summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitattributes4
-rw-r--r--.gitignore20
-rw-r--r--.travis.yml58
-rw-r--r--Doxyfile2432
-rw-r--r--LICENSE.md2
-rw-r--r--README.md7
-rw-r--r--SConstruct107
-rw-r--r--bin/tests/SCsub2
-rw-r--r--bin/tests/test_containers.cpp2
-rw-r--r--bin/tests/test_containers.h2
-rw-r--r--bin/tests/test_detailer.cpp2
-rw-r--r--bin/tests/test_detailer.h2
-rw-r--r--bin/tests/test_gdscript.cpp2
-rw-r--r--bin/tests/test_gdscript.h2
-rw-r--r--bin/tests/test_gui.cpp2
-rw-r--r--bin/tests/test_gui.h2
-rw-r--r--bin/tests/test_image.cpp2
-rw-r--r--bin/tests/test_image.h2
-rw-r--r--bin/tests/test_io.cpp2
-rw-r--r--bin/tests/test_io.h2
-rw-r--r--bin/tests/test_main.cpp3
-rw-r--r--bin/tests/test_main.h2
-rw-r--r--bin/tests/test_math.cpp2
-rw-r--r--bin/tests/test_math.h2
-rw-r--r--bin/tests/test_misc.cpp2
-rw-r--r--bin/tests/test_misc.h2
-rw-r--r--bin/tests/test_particles.cpp2
-rw-r--r--bin/tests/test_particles.h2
-rw-r--r--bin/tests/test_physics.cpp2
-rw-r--r--bin/tests/test_physics.h2
-rw-r--r--bin/tests/test_physics_2d.cpp2
-rw-r--r--bin/tests/test_physics_2d.h2
-rw-r--r--bin/tests/test_python.cpp2
-rw-r--r--bin/tests/test_python.h2
-rw-r--r--bin/tests/test_render.cpp2
-rw-r--r--bin/tests/test_render.h2
-rw-r--r--bin/tests/test_shader_lang.cpp2
-rw-r--r--bin/tests/test_shader_lang.h2
-rw-r--r--bin/tests/test_sound.cpp2
-rw-r--r--bin/tests/test_sound.h2
-rw-r--r--bin/tests/test_string.cpp24
-rw-r--r--bin/tests/test_string.h2
-rw-r--r--core/SCsub2
-rw-r--r--core/allocators.h2
-rw-r--r--core/array.cpp20
-rw-r--r--core/array.h8
-rw-r--r--core/balloon_allocator.h2
-rw-r--r--core/bind/SCsub2
-rw-r--r--core/bind/core_bind.cpp158
-rw-r--r--core/bind/core_bind.h31
-rw-r--r--core/color.cpp2
-rw-r--r--core/color.h2
-rw-r--r--core/command_queue_mt.cpp2
-rw-r--r--core/command_queue_mt.h4
-rw-r--r--core/compressed_translation.cpp10
-rw-r--r--core/compressed_translation.h2
-rw-r--r--core/core_string_names.cpp2
-rw-r--r--core/core_string_names.h2
-rw-r--r--core/dictionary.cpp17
-rw-r--r--core/dictionary.h2
-rw-r--r--core/dvector.cpp2
-rw-r--r--core/dvector.h2
-rw-r--r--core/error_list.h3
-rw-r--r--core/error_macros.cpp2
-rw-r--r--core/error_macros.h25
-rw-r--r--core/event_queue.cpp2
-rw-r--r--core/event_queue.h2
-rw-r--r--core/fpstr.cpp2
-rw-r--r--core/fpstr.h2
-rw-r--r--core/func_ref.cpp3
-rw-r--r--core/global_constants.cpp6
-rw-r--r--core/global_constants.h2
-rw-r--r--core/globals.cpp74
-rw-r--r--core/globals.h13
-rw-r--r--core/hash_map.h2
-rw-r--r--core/hashfuncs.h2
-rw-r--r--core/image.cpp152
-rw-r--r--core/image.h6
-rw-r--r--core/image_quantize.cpp2
-rw-r--r--core/input_map.cpp60
-rw-r--r--core/input_map.h3
-rw-r--r--core/int_types.h2
-rw-r--r--core/io/SCsub2
-rw-r--r--core/io/aes256.cpp758
-rw-r--r--core/io/aes256.h92
-rw-r--r--core/io/compression.cpp6
-rw-r--r--core/io/compression.h2
-rw-r--r--core/io/config_file.cpp603
-rw-r--r--core/io/config_file.h4
-rw-r--r--core/io/file_access_buffered.cpp2
-rw-r--r--core/io/file_access_buffered.h2
-rw-r--r--core/io/file_access_buffered_fa.h2
-rw-r--r--core/io/file_access_compressed.cpp2
-rw-r--r--core/io/file_access_compressed.h2
-rw-r--r--core/io/file_access_encrypted.cpp4
-rw-r--r--core/io/file_access_memory.cpp2
-rw-r--r--core/io/file_access_memory.h2
-rw-r--r--core/io/file_access_network.cpp2
-rw-r--r--core/io/file_access_network.h2
-rw-r--r--core/io/file_access_pack.cpp2
-rw-r--r--core/io/file_access_pack.h2
-rw-r--r--core/io/file_access_zip.cpp2
-rw-r--r--core/io/file_access_zip.h2
-rw-r--r--core/io/http_client.cpp30
-rw-r--r--core/io/http_client.h4
-rw-r--r--core/io/image_loader.cpp13
-rw-r--r--core/io/image_loader.h2
-rw-r--r--core/io/ioapi.h1
-rw-r--r--core/io/ip.cpp2
-rw-r--r--core/io/ip.h2
-rw-r--r--core/io/ip_address.cpp4
-rw-r--r--core/io/ip_address.h2
-rw-r--r--core/io/json.cpp20
-rw-r--r--core/io/json.h2
-rw-r--r--core/io/marshalls.cpp10
-rw-r--r--core/io/marshalls.h2
-rw-r--r--core/io/packet_peer.cpp7
-rw-r--r--core/io/packet_peer.h2
-rw-r--r--core/io/resource_format_binary.cpp352
-rw-r--r--core/io/resource_format_binary.h16
-rw-r--r--core/io/resource_format_xml.cpp408
-rw-r--r--core/io/resource_format_xml.h27
-rw-r--r--core/io/resource_loader.cpp69
-rw-r--r--core/io/resource_loader.h24
-rw-r--r--core/io/resource_saver.cpp2
-rw-r--r--core/io/resource_saver.h4
-rw-r--r--core/io/stream_peer.cpp301
-rw-r--r--core/io/stream_peer.h40
-rw-r--r--core/io/stream_peer_tcp.cpp2
-rw-r--r--core/io/stream_peer_tcp.h2
-rw-r--r--core/io/tcp_server.cpp2
-rw-r--r--core/io/tcp_server.h2
-rw-r--r--core/io/translation_loader_po.cpp11
-rw-r--r--core/io/translation_loader_po.h4
-rw-r--r--core/io/unzip.c2
-rw-r--r--core/io/xml_parser.cpp14
-rw-r--r--core/io/xml_parser.h2
-rw-r--r--core/io/zip.c4
-rw-r--r--core/io/zip.h2
-rw-r--r--core/io/zip_io.h3
-rw-r--r--core/list.h12
-rw-r--r--core/map.h2
-rw-r--r--core/math/SCsub2
-rw-r--r--core/math/aabb.cpp2
-rw-r--r--core/math/aabb.h2
-rw-r--r--core/math/bezier_curve.cpp2
-rw-r--r--core/math/bezier_curve.h2
-rw-r--r--core/math/bsp_tree.cpp2
-rw-r--r--core/math/bsp_tree.h2
-rw-r--r--core/math/camera_matrix.cpp2
-rw-r--r--core/math/camera_matrix.h2
-rw-r--r--core/math/face3.cpp2
-rw-r--r--core/math/face3.h2
-rw-r--r--core/math/geometry.cpp2
-rw-r--r--core/math/geometry.h33
-rw-r--r--core/math/math_2d.cpp7
-rw-r--r--core/math/math_2d.h4
-rw-r--r--core/math/math_defs.cpp2
-rw-r--r--core/math/math_defs.h2
-rw-r--r--core/math/math_funcs.cpp12
-rw-r--r--core/math/math_funcs.h6
-rw-r--r--core/math/matrix3.cpp2
-rw-r--r--core/math/matrix3.h2
-rw-r--r--core/math/octree.h2
-rw-r--r--core/math/plane.cpp2
-rw-r--r--core/math/plane.h2
-rw-r--r--core/math/quat.cpp2
-rw-r--r--core/math/quat.h4
-rw-r--r--core/math/quick_hull.cpp2
-rw-r--r--core/math/quick_hull.h2
-rw-r--r--core/math/transform.cpp2
-rw-r--r--core/math/transform.h2
-rw-r--r--core/math/triangle_mesh.cpp2
-rw-r--r--core/math/triangle_mesh.h2
-rw-r--r--core/math/triangulate.cpp2
-rw-r--r--core/math/triangulate.h2
-rw-r--r--core/math/vector3.cpp2
-rw-r--r--core/math/vector3.h32
-rw-r--r--core/message_queue.cpp106
-rw-r--r--core/message_queue.h9
-rw-r--r--core/method_bind.cpp6
-rw-r--r--core/method_bind.h2
-rw-r--r--core/multi_bucket_array.h2
-rw-r--r--core/object.cpp240
-rw-r--r--core/object.h96
-rw-r--r--core/object_type_db.cpp82
-rw-r--r--core/object_type_db.h24
-rw-r--r--core/os/SCsub2
-rw-r--r--core/os/copymem.cpp2
-rw-r--r--core/os/copymem.h2
-rw-r--r--core/os/dir_access.cpp2
-rw-r--r--core/os/dir_access.h2
-rw-r--r--core/os/file_access.cpp2
-rw-r--r--core/os/file_access.h3
-rw-r--r--core/os/input.cpp274
-rw-r--r--core/os/input.h79
-rw-r--r--core/os/input_event.cpp3
-rw-r--r--core/os/input_event.h5
-rw-r--r--core/os/keyboard.cpp2
-rw-r--r--core/os/keyboard.h2
-rw-r--r--core/os/main_loop.cpp5
-rw-r--r--core/os/main_loop.h4
-rw-r--r--core/os/memory.cpp2
-rw-r--r--core/os/memory.h2
-rw-r--r--core/os/memory_pool_dynamic.cpp2
-rw-r--r--core/os/memory_pool_dynamic.h2
-rw-r--r--core/os/memory_pool_dynamic_prealloc.cpp2
-rw-r--r--core/os/memory_pool_dynamic_prealloc.h2
-rw-r--r--core/os/memory_pool_dynamic_static.cpp2
-rw-r--r--core/os/memory_pool_dynamic_static.h2
-rw-r--r--core/os/memory_pool_static.cpp2
-rw-r--r--core/os/memory_pool_static.h2
-rw-r--r--core/os/mutex.cpp2
-rw-r--r--core/os/mutex.h2
-rw-r--r--core/os/os.cpp38
-rw-r--r--core/os/os.h16
-rw-r--r--core/os/pc_joystick_map.h2
-rw-r--r--core/os/semaphore.cpp2
-rw-r--r--core/os/semaphore.h2
-rw-r--r--core/os/shell.cpp2
-rw-r--r--core/os/shell.h2
-rw-r--r--core/os/thread.cpp7
-rw-r--r--core/os/thread.h6
-rw-r--r--core/os/thread_dummy.cpp2
-rw-r--r--core/os/thread_dummy.h2
-rw-r--r--core/os/thread_safe.cpp2
-rw-r--r--core/os/thread_safe.h2
-rw-r--r--core/packed_data_container.cpp2
-rw-r--r--core/packed_data_container.h2
-rw-r--r--core/pair.cpp2
-rw-r--r--core/pair.h2
-rw-r--r--core/path_db.cpp33
-rw-r--r--core/path_db.h7
-rw-r--r--core/path_remap.cpp2
-rw-r--r--core/path_remap.h2
-rw-r--r--core/pool_allocator.cpp2
-rw-r--r--core/pool_allocator.h2
-rw-r--r--core/print_string.cpp5
-rw-r--r--core/print_string.h3
-rw-r--r--core/ref_ptr.cpp2
-rw-r--r--core/ref_ptr.h2
-rw-r--r--core/reference.cpp2
-rw-r--r--core/reference.h2
-rw-r--r--core/register_core_types.cpp4
-rw-r--r--core/register_core_types.h2
-rw-r--r--core/res_ptr.cpp2
-rw-r--r--core/res_ptr.h2
-rw-r--r--core/resource.cpp4
-rw-r--r--core/resource.h6
-rw-r--r--core/rid.cpp2
-rw-r--r--core/rid.h2
-rw-r--r--core/ring_buffer.h16
-rw-r--r--core/safe_refcount.cpp2
-rw-r--r--core/safe_refcount.h2
-rw-r--r--core/script_debugger_debugger.cpp2
-rw-r--r--core/script_debugger_local.cpp18
-rw-r--r--core/script_debugger_local.h2
-rw-r--r--core/script_debugger_remote.cpp299
-rw-r--r--core/script_debugger_remote.h51
-rw-r--r--core/script_language.cpp24
-rw-r--r--core/script_language.h56
-rw-r--r--core/self_list.h2
-rw-r--r--core/set.h2
-rw-r--r--core/simple_type.h2
-rw-r--r--core/sort.h2
-rw-r--r--core/string_db.cpp6
-rw-r--r--core/string_db.h14
-rw-r--r--core/translation.cpp10
-rw-r--r--core/translation.h2
-rw-r--r--core/typedefs.h18
-rw-r--r--core/undo_redo.cpp33
-rw-r--r--core/undo_redo.h13
-rw-r--r--core/ustring.cpp183
-rw-r--r--core/ustring.h9
-rw-r--r--core/variant.cpp228
-rw-r--r--core/variant.h11
-rw-r--r--core/variant_call.cpp53
-rw-r--r--core/variant_call_bind.h2
-rw-r--r--core/variant_op.cpp62
-rw-r--r--core/variant_parser.cpp2211
-rw-r--r--core/variant_parser.h139
-rw-r--r--core/vector.h48
-rw-r--r--core/vmap.cpp2
-rw-r--r--core/vmap.h2
-rw-r--r--core/vset.cpp2
-rw-r--r--core/vset.h2
-rw-r--r--demos/2d/area_input/engine.cfg1
-rw-r--r--demos/2d/area_input/icon.pngbin0 -> 3416 bytes
-rw-r--r--demos/2d/area_input/input.gd17
-rw-r--r--demos/2d/area_input/input.scnbin2886 -> 3118 bytes
-rw-r--r--demos/2d/dynamic_collision_shapes/ball.gd17
-rw-r--r--demos/2d/dynamic_collision_shapes/ball.pngbin0 -> 321 bytes
-rw-r--r--demos/2d/dynamic_collision_shapes/ball.scnbin0 -> 1857 bytes
-rw-r--r--demos/2d/dynamic_collision_shapes/box.pngbin0 -> 253 bytes
-rw-r--r--demos/2d/dynamic_collision_shapes/circle.pngbin0 -> 889 bytes
-rw-r--r--demos/2d/dynamic_collision_shapes/dynamic_colobjs.gd19
-rw-r--r--demos/2d/dynamic_collision_shapes/dynamic_colobjs.scnbin0 -> 4399 bytes
-rw-r--r--demos/2d/dynamic_collision_shapes/engine.cfg5
-rw-r--r--demos/2d/dynamic_collision_shapes/icon.pngbin0 -> 1563 bytes
-rw-r--r--demos/2d/dynamic_collision_shapes/poly.pngbin0 -> 1638 bytes
-rw-r--r--demos/2d/fog_of_war/engine.cfg2
-rw-r--r--demos/2d/fog_of_war/fog.gd92
-rw-r--r--demos/2d/fog_of_war/fog.scnbin3714 -> 4159 bytes
-rw-r--r--demos/2d/fog_of_war/icon.png.flags1
-rw-r--r--demos/2d/fog_of_war/tile_edit.scnbin1443 -> 1570 bytes
-rw-r--r--demos/2d/fog_of_war/troll.gd33
-rw-r--r--demos/2d/fog_of_war/troll.scnbin1839 -> 1979 bytes
-rw-r--r--demos/2d/hdr/beach_cave.gd29
-rw-r--r--demos/2d/hdr/beach_cave.scnbin2972 -> 4834 bytes
-rw-r--r--demos/2d/hdr/engine.cfg1
-rw-r--r--demos/2d/hdr/icon.pngbin0 -> 3962 bytes
-rw-r--r--demos/2d/hexamap/map.scnbin2644 -> 3517 bytes
-rw-r--r--demos/2d/hexamap/tiles.scnbin2091 -> 2217 bytes
-rw-r--r--demos/2d/hexamap/troll.gd31
-rw-r--r--demos/2d/hexamap/troll.scnbin1839 -> 1983 bytes
-rw-r--r--demos/2d/isometric/dungeon.scnbin2841 -> 4708 bytes
-rw-r--r--demos/2d/isometric/tileset.scnbin2565 -> 4476 bytes
-rw-r--r--demos/2d/isometric/troll.gd31
-rw-r--r--demos/2d/isometric/troll.scnbin2100 -> 2116 bytes
-rw-r--r--demos/2d/isometric_light/column.scnbin1909 -> 2026 bytes
-rw-r--r--demos/2d/isometric_light/cubio.gd117
-rw-r--r--demos/2d/isometric_light/cubio.scnbin7006 -> 6952 bytes
-rw-r--r--demos/2d/isometric_light/engine.cfg1
-rw-r--r--demos/2d/isometric_light/icon.pngbin0 -> 7675 bytes
-rw-r--r--demos/2d/isometric_light/map.gd15
-rw-r--r--demos/2d/isometric_light/map.scnbin8661 -> 9352 bytes
-rw-r--r--demos/2d/isometric_light/shoot.gd20
-rw-r--r--demos/2d/isometric_light/shoot.scnbin4561 -> 4111 bytes
-rw-r--r--demos/2d/isometric_light/tileset_scene.scnbin4812 -> 5339 bytes
-rw-r--r--demos/2d/isometric_light/torch.scnbin4416 -> 3861 bytes
-rw-r--r--demos/2d/kinematic_char/colworld.gd16
-rw-r--r--demos/2d/kinematic_char/colworld.scnbin7459 -> 7366 bytes
-rw-r--r--demos/2d/kinematic_char/engine.cfg2
-rw-r--r--demos/2d/kinematic_char/player.gd168
-rw-r--r--demos/2d/kinematic_char/player.scnbin1728 -> 1703 bytes
-rw-r--r--demos/2d/kinematic_col/colworld.scnbin2941 -> 4073 bytes
-rw-r--r--demos/2d/kinematic_col/player.gd23
-rw-r--r--demos/2d/kinematic_col/player.scnbin1495 -> 1625 bytes
-rw-r--r--demos/2d/light_mask/engine.cfg1
-rw-r--r--demos/2d/light_mask/icon.pngbin0 -> 6285 bytes
-rw-r--r--demos/2d/light_mask/lightmask.scnbin2916 -> 3829 bytes
-rw-r--r--demos/2d/lights_shadows/engine.cfg1
-rw-r--r--demos/2d/lights_shadows/icon.pngbin0 -> 3988 bytes
-rw-r--r--demos/2d/lights_shadows/light_shadows.scnbin4293 -> 4978 bytes
-rw-r--r--demos/2d/lookat/engine.cfg1
-rw-r--r--demos/2d/lookat/icon.pngbin0 -> 1495 bytes
-rw-r--r--demos/2d/lookat/lookat.gd38
-rw-r--r--demos/2d/lookat/lookat.scnbin1622 -> 1640 bytes
-rw-r--r--demos/2d/motion/engine.cfg1
-rw-r--r--demos/2d/motion/icon.pngbin0 -> 2621 bytes
-rw-r--r--demos/2d/motion/motion.gd35
-rw-r--r--demos/2d/motion/motion.scnbin2845 -> 2738 bytes
-rw-r--r--demos/2d/navpoly/engine.cfg1
-rw-r--r--demos/2d/navpoly/icon.pngbin0 -> 3642 bytes
-rw-r--r--demos/2d/navpoly/navigation.gd64
-rw-r--r--demos/2d/navpoly/navigation.scnbin3456 -> 5128 bytes
-rw-r--r--demos/2d/navpoly/navigation2.scnbin3564 -> 0 bytes
-rw-r--r--demos/2d/normalmaps/engine.cfg1
-rw-r--r--demos/2d/normalmaps/icon.pngbin0 -> 10402 bytes
-rw-r--r--demos/2d/normalmaps/normalmap.scnbin2450 -> 3168 bytes
-rw-r--r--demos/2d/particles/particles.xml265
-rw-r--r--demos/2d/platformer/bullet.gd13
-rw-r--r--demos/2d/platformer/bullet.xml273
-rw-r--r--demos/2d/platformer/coin.gd17
-rw-r--r--demos/2d/platformer/coin.xml293
-rw-r--r--demos/2d/platformer/enemy.gd91
-rw-r--r--demos/2d/platformer/enemy.xml317
-rw-r--r--demos/2d/platformer/engine.cfg6
-rw-r--r--demos/2d/platformer/moving_platform.gd21
-rw-r--r--demos/2d/platformer/moving_platform.xml214
-rw-r--r--demos/2d/platformer/one_way_platform.xml67
-rw-r--r--demos/2d/platformer/parallax_bg.xml258
-rw-r--r--demos/2d/platformer/player.gd237
-rw-r--r--demos/2d/platformer/player.xml411
-rw-r--r--demos/2d/platformer/seesaw.xml207
-rw-r--r--demos/2d/platformer/stage.xml881
-rw-r--r--demos/2d/platformer/tiles_demo.png.flags1
-rw-r--r--demos/2d/platformer/tileset_edit.xml213
-rw-r--r--demos/2d/polygon_path_finder_demo/engine.cfg5
-rw-r--r--demos/2d/polygon_path_finder_demo/icon.pngbin3639 -> 0 bytes
-rw-r--r--demos/2d/polygon_path_finder_demo/icon.png.flags1
-rw-r--r--demos/2d/polygon_path_finder_demo/new_scene_poly_with_holes.scnbin2609 -> 0 bytes
-rw-r--r--demos/2d/polygon_path_finder_demo/polygonpathfinder.gd80
-rw-r--r--demos/2d/pong/pong.gd82
-rw-r--r--demos/2d/pong/pong.xml206
-rw-r--r--demos/2d/rubegoldberg/ball.xml210
-rw-r--r--demos/2d/rubegoldberg/box.xml242
-rw-r--r--demos/2d/rubegoldberg/domino.xml244
-rw-r--r--demos/2d/rubegoldberg/pendulum.xml210
-rw-r--r--demos/2d/rubegoldberg/platform.xml188
-rw-r--r--demos/2d/rubegoldberg/rubegoldberg.xml181
-rw-r--r--demos/2d/rubegoldberg/seesaw.xml266
-rw-r--r--demos/2d/screen_space_shaders/engine.cfg1
-rw-r--r--demos/2d/screen_space_shaders/icon.pngbin0 -> 7479 bytes
-rw-r--r--demos/2d/screen_space_shaders/screen_shaders.gd19
-rw-r--r--demos/2d/screen_space_shaders/screen_shaders.scnbin5936 -> 7562 bytes
-rw-r--r--demos/2d/sdf_font/engine.cfg1
-rw-r--r--demos/2d/sdf_font/icon.pngbin0 -> 3560 bytes
-rw-r--r--demos/2d/sdf_font/sdf.scnbin2415 -> 2820 bytes
-rw-r--r--demos/2d/shower_of_bullets/bullets.gd59
-rw-r--r--demos/2d/shower_of_bullets/shower.gd29
-rw-r--r--demos/2d/shower_of_bullets/shower.scnbin1836 -> 1909 bytes
-rw-r--r--demos/2d/space_shooter/asteroid.gd42
-rw-r--r--demos/2d/space_shooter/asteroid.scnbin4516 -> 3548 bytes
-rw-r--r--demos/2d/space_shooter/enemy1.gd29
-rw-r--r--demos/2d/space_shooter/enemy1.scnbin3759 -> 3369 bytes
-rw-r--r--demos/2d/space_shooter/enemy2.gd51
-rw-r--r--demos/2d/space_shooter/enemy2.scnbin3801 -> 3253 bytes
-rw-r--r--demos/2d/space_shooter/enemy_shot.gd19
-rw-r--r--demos/2d/space_shooter/enemy_shot.scnbin3944 -> 3218 bytes
-rw-r--r--demos/2d/space_shooter/explosion.scnbin1497 -> 1756 bytes
-rw-r--r--demos/2d/space_shooter/game_state.gd20
-rw-r--r--demos/2d/space_shooter/level.scnbin9185 -> 6496 bytes
-rw-r--r--demos/2d/space_shooter/level_tiles.scnbin2168 -> 1825 bytes
-rw-r--r--demos/2d/space_shooter/main_menu.gd13
-rw-r--r--demos/2d/space_shooter/main_menu.scnbin2402 -> 1903 bytes
-rw-r--r--demos/2d/space_shooter/parallax.scnbin3307 -> 2814 bytes
-rw-r--r--demos/2d/space_shooter/rail.gd19
-rw-r--r--demos/2d/space_shooter/ship.gd65
-rw-r--r--demos/2d/space_shooter/ship.scnbin6752 -> 4965 bytes
-rw-r--r--demos/2d/space_shooter/shot.gd34
-rw-r--r--demos/2d/space_shooter/shot.scnbin4079 -> 3315 bytes
-rw-r--r--demos/2d/splash/engine.cfg1
-rw-r--r--demos/2d/splash/icon.pngbin0 -> 7041 bytes
-rw-r--r--demos/2d/splash/splash.xml338
-rw-r--r--demos/2d/sprite_shaders/engine.cfg1
-rw-r--r--demos/2d/sprite_shaders/icon.pngbin0 -> 8209 bytes
-rw-r--r--demos/2d/sprite_shaders/sprite_shaders.scnbin4079 -> 5477 bytes
-rw-r--r--demos/2d/tetris/grid.gd219
-rw-r--r--demos/2d/tetris/grid.xml252
-rw-r--r--demos/2d/tetris/tetris.xml252
-rw-r--r--demos/2d/texscreen/bubbles.gd10
-rw-r--r--demos/2d/texscreen/bubbles.scnbin1551 -> 2626 bytes
-rw-r--r--demos/2d/texscreen/engine.cfg1
-rw-r--r--demos/2d/texscreen/icon.pngbin0 -> 9245 bytes
-rw-r--r--demos/2d/texscreen/lens.gd45
-rw-r--r--demos/2d/texscreen/lens.scnbin1805 -> 1850 bytes
-rw-r--r--demos/3d/fixed_materials/fixed_materials.scnbin6071 -> 8271 bytes
-rw-r--r--demos/3d/kinematic_char/cubio.gd91
-rw-r--r--demos/3d/kinematic_char/follow_camera.gd62
-rw-r--r--demos/3d/kinematic_char/level.scnbin15523 -> 18847 bytes
-rw-r--r--demos/3d/kinematic_char/purplecube.scnbin9808 -> 7927 bytes
-rw-r--r--demos/3d/mousepick_test/mousepick.gd22
-rw-r--r--demos/3d/mousepick_test/mousepick.scnbin38194 -> 40434 bytes
-rw-r--r--demos/3d/navmesh/icon.pngbin0 -> 4902 bytes
-rw-r--r--demos/3d/navmesh/navmesh.gd103
-rw-r--r--demos/3d/navmesh/navmesh.scnbin38129 -> 40827 bytes
-rw-r--r--demos/3d/platformer/bullet.gd13
-rw-r--r--demos/3d/platformer/bullet.scnbin6157 -> 7303 bytes
-rw-r--r--demos/3d/platformer/coin.gd18
-rw-r--r--demos/3d/platformer/coin.scnbin6791 -> 7785 bytes
-rw-r--r--demos/3d/platformer/enemy.gd60
-rw-r--r--demos/3d/platformer/enemy.scnbin37784 -> 39181 bytes
-rw-r--r--demos/3d/platformer/engine.cfg4
-rw-r--r--demos/3d/platformer/follow_camera.gd89
-rw-r--r--demos/3d/platformer/player.gd212
-rw-r--r--demos/3d/platformer/player.scnbin0 -> 107922 bytes
-rw-r--r--demos/3d/platformer/player.xml1762
-rw-r--r--demos/3d/platformer/robotrigged.scnbin107962 -> 110973 bytes
-rw-r--r--demos/3d/platformer/stage.scnbin0 -> 17714 bytes
-rw-r--r--demos/3d/platformer/stage.xml697
-rw-r--r--demos/3d/platformer/tiles.scnbin47723 -> 23305 bytes
-rw-r--r--demos/3d/polygon_path_finder/engine.cfg5
-rw-r--r--demos/3d/polygon_path_finder/icon.pngbin0 -> 712 bytes
-rw-r--r--demos/3d/polygon_path_finder/poly_with_holes.scnbin0 -> 2974 bytes
-rw-r--r--demos/3d/polygon_path_finder/polygonpathfinder.gd77
-rw-r--r--demos/3d/sat_test/box.scnbin23739 -> 27363 bytes
-rw-r--r--demos/3d/sat_test/capsule.scnbin21133 -> 22718 bytes
-rw-r--r--demos/3d/sat_test/convex.scnbin22828 -> 25617 bytes
-rw-r--r--demos/3d/sat_test/engine.cfg3
-rw-r--r--demos/3d/sat_test/icon.pngbin0 -> 4628 bytes
-rw-r--r--demos/3d/sat_test/sat_test.scnbin0 -> 3430 bytes
-rw-r--r--demos/3d/sat_test/sat_test.xml179
-rw-r--r--demos/3d/sat_test/shapes.scnbin23064 -> 25887 bytes
-rw-r--r--demos/3d/sat_test/sphere.scnbin38627 -> 41375 bytes
-rw-r--r--demos/3d/shader_materials/shader_materials.scnbin6382 -> 9892 bytes
-rw-r--r--demos/3d/truck_town/car_base.scnbin11573 -> 13459 bytes
-rw-r--r--demos/3d/truck_town/car_select.gd20
-rw-r--r--demos/3d/truck_town/car_select.scnbin1702 -> 1968 bytes
-rw-r--r--demos/3d/truck_town/crane.scnbin24164 -> 26350 bytes
-rw-r--r--demos/3d/truck_town/engine.cfg1
-rw-r--r--demos/3d/truck_town/follow_camera.gd58
-rw-r--r--demos/3d/truck_town/icon.pngbin0 -> 6878 bytes
-rw-r--r--demos/3d/truck_town/trailer_truck.scnbin19934 -> 22400 bytes
-rw-r--r--demos/3d/truck_town/truck_scene.scnbin1873575 -> 1889480 bytes
-rw-r--r--demos/3d/truck_town/trucktown.scnbin161749 -> 165689 bytes
-rw-r--r--demos/3d/truck_town/vehicle.gd43
-rw-r--r--demos/gui/drag_and_drop/drag_and_drop.scnbin2594 -> 2947 bytes
-rw-r--r--demos/gui/drag_and_drop/drag_drop_script.gd18
-rw-r--r--demos/gui/drag_and_drop/engine.cfg1
-rw-r--r--demos/gui/drag_and_drop/icon.pngbin0 -> 806 bytes
-rw-r--r--demos/gui/input_mapping/controls.gd9
-rw-r--r--demos/gui/input_mapping/controls.scnbin2686 -> 2698 bytes
-rw-r--r--demos/gui/input_mapping/engine.cfg2
-rw-r--r--demos/gui/input_mapping/icon.pngbin0 -> 1503 bytes
-rw-r--r--demos/gui/rich_text_bbcode/engine.cfg1
-rw-r--r--demos/gui/rich_text_bbcode/icon.pngbin0 -> 4304 bytes
-rw-r--r--demos/gui/rich_text_bbcode/rich_text_bbcode.gd13
-rw-r--r--demos/gui/rich_text_bbcode/rich_text_bbcode.scnbin2373 -> 3217 bytes
-rw-r--r--demos/gui/translation/controls.gd11
-rw-r--r--demos/gui/translation/controls.scnbin2349 -> 2272 bytes
-rw-r--r--demos/gui/translation/engine.cfg1
-rw-r--r--demos/gui/translation/icon.pngbin0 -> 2557 bytes
-rw-r--r--demos/gui/translation/main.gd18
-rw-r--r--demos/gui/translation/main.scnbin2671 -> 2939 bytes
-rw-r--r--demos/misc/autoload/global.gd41
-rw-r--r--demos/misc/autoload/scene_a.gd12
-rw-r--r--demos/misc/autoload/scene_a.scnbin1459 -> 1660 bytes
-rw-r--r--demos/misc/autoload/scene_b.gd12
-rw-r--r--demos/misc/autoload/scene_b.scnbin1448 -> 1639 bytes
-rw-r--r--demos/misc/instancing/ball.scnbin1563 -> 1885 bytes
-rw-r--r--demos/misc/instancing/container.scnbin2312 -> 3137 bytes
-rw-r--r--demos/misc/instancing/engine.cfg1
-rw-r--r--demos/misc/instancing/icon.pngbin0 -> 3396 bytes
-rw-r--r--demos/misc/joysticks/diagram.pngbin0 -> 171519 bytes
-rw-r--r--demos/misc/joysticks/engine.cfg2
-rw-r--r--demos/misc/joysticks/indicators.pngbin0 -> 1069 bytes
-rw-r--r--demos/misc/joysticks/joysticks.gd49
-rw-r--r--demos/misc/joysticks/joysticks.scnbin3809 -> 4356 bytes
-rw-r--r--demos/misc/joysticks/jsdiagram.xscn115
-rw-r--r--demos/misc/pause/spinpause.gd2
-rw-r--r--demos/misc/pause/spinpause.scnbin3331 -> 5399 bytes
-rw-r--r--demos/misc/regex/engine.cfg5
-rw-r--r--demos/misc/regex/icon.pngbin0 -> 2215 bytes
-rw-r--r--demos/misc/regex/regex.gd28
-rw-r--r--demos/misc/regex/regex.scnbin0 -> 1775 bytes
-rw-r--r--demos/misc/scene_changer/scene_a.gd7
-rw-r--r--demos/misc/scene_changer/scene_a.scnbin1459 -> 1660 bytes
-rw-r--r--demos/misc/scene_changer/scene_b.gd7
-rw-r--r--demos/misc/scene_changer/scene_b.scnbin1448 -> 1639 bytes
-rw-r--r--demos/misc/threads/thread.gd26
-rw-r--r--demos/misc/threads/thread.scnbin1638 -> 1586 bytes
-rw-r--r--demos/misc/tween/engine.cfg4
-rw-r--r--demos/misc/tween/icon.pngbin3621 -> 2831 bytes
-rw-r--r--demos/misc/tween/main.gd53
-rw-r--r--demos/misc/tween/main.scnbin0 -> 5216 bytes
-rw-r--r--demos/misc/tween/main.xml367
-rw-r--r--demos/misc/udp_chat/chat.gd46
-rw-r--r--demos/misc/udp_chat/chat.scnbin3198 -> 3359 bytes
-rw-r--r--demos/misc/window_management/control.gd85
-rw-r--r--demos/misc/window_management/engine.cfg2
-rw-r--r--demos/misc/window_management/icon.pngbin3639 -> 4210 bytes
-rw-r--r--demos/misc/window_management/icon.png.flags1
-rw-r--r--demos/misc/window_management/observer/observer.gd31
-rw-r--r--demos/misc/window_management/observer/observer.scnbin1786 -> 3824 bytes
-rw-r--r--demos/misc/window_management/window_management.scnbin5132 -> 4384 bytes
-rw-r--r--demos/viewport/2d_in_3d/pong.gd81
-rw-r--r--demos/viewport/2d_in_3d/pong.scnbin0 -> 1417 bytes
-rw-r--r--demos/viewport/2d_in_3d/pong.xml183
-rw-r--r--demos/viewport/2d_in_3d/pong3d.gd9
-rw-r--r--demos/viewport/2d_in_3d/pong3d.scnbin3412 -> 5236 bytes
-rw-r--r--demos/viewport/3d_in_2d/engine.cfg1
-rw-r--r--demos/viewport/3d_in_2d/icon.pngbin0 -> 3758 bytes
-rw-r--r--demos/viewport/3d_in_2d/main.scnbin1438 -> 1685 bytes
-rw-r--r--demos/viewport/3d_in_2d/player.scnbin105180 -> 107246 bytes
-rw-r--r--demos/viewport/3d_in_2d/player.xml1736
-rw-r--r--demos/viewport/3d_in_2d/player_2d.scnbin1576 -> 1834 bytes
-rw-r--r--demos/viewport/3d_in_2d/player_3d.scnbin1448 -> 1688 bytes
-rw-r--r--demos/viewport/gui_in_3d/engine.cfg1
-rw-r--r--demos/viewport/gui_in_3d/gui.scnbin2270 -> 2579 bytes
-rw-r--r--demos/viewport/gui_in_3d/gui_3d.gd70
-rw-r--r--demos/viewport/gui_in_3d/gui_3d.scnbin4668 -> 6137 bytes
-rw-r--r--demos/viewport/gui_in_3d/icon.pngbin0 -> 3770 bytes
-rw-r--r--demos/viewport/screen_capture/engine.cfg1
-rw-r--r--demos/viewport/screen_capture/icon.pngbin0 -> 7350 bytes
-rw-r--r--demos/viewport/screen_capture/screen_capture.gd23
-rw-r--r--demos/viewport/screen_capture/screen_capture.scnbin1977 -> 3482 bytes
-rw-r--r--doc/Doxyfile2432
-rw-r--r--doc/Makefile47
-rw-r--r--doc/base/classes.xml15751
-rw-r--r--doc/core_classes.xml2654
-rw-r--r--doc/deferred_format.txt33
-rw-r--r--doc/demos.txt40
-rw-r--r--doc/engine_classes.xml17936
-rw-r--r--doc/examples/physics/script/test_base.sq295
-rw-r--r--doc/examples/physics/script/test_fall.sq42
-rw-r--r--doc/gdscript.lyx2531
-rw-r--r--doc/godot_splash.pngbin9801 -> 0 bytes
-rw-r--r--doc/header.txt12
-rw-r--r--doc/html/@GDScript.html93
-rw-r--r--doc/html/@Global Scope.html459
-rw-r--r--doc/html/@Squirrel.html2
-rw-r--r--doc/html/tutorial01/0_home_red_coding_godot_doc_math_position.pngbin1679 -> 0 bytes
-rw-r--r--doc/html/tutorial01/1_home_red_coding_godot_doc_math_direction.pngbin3600 -> 0 bytes
-rw-r--r--doc/html/tutorial01/2_home_red_coding_godot_doc_math_normals.pngbin2452 -> 0 bytes
-rw-r--r--doc/html/tutorial01/tutorial.css128
-rw-r--r--doc/html/tutorial01/tutorial.html902
-rw-r--r--doc/html/tutorial01/tutorial0x.pngbin2056 -> 0 bytes
-rw-r--r--doc/html/tutorial01/tutorial1x.pngbin4122 -> 0 bytes
-rw-r--r--doc/html/tutorial01/tutorial2x.pngbin618 -> 0 bytes
-rw-r--r--doc/html/tutorial01/tutorial3x.pngbin754 -> 0 bytes
-rw-r--r--doc/html/tutorial01/tutorial4x.pngbin2961 -> 0 bytes
-rw-r--r--doc/make_doc.sh17
-rw-r--r--doc/notes.txt20
-rw-r--r--doc/phys_engine.pngbin29177 -> 0 bytes
-rw-r--r--doc/squirrel.lyx984
-rw-r--r--doc/todo.txt39
-rw-r--r--doc/tools/doc_merge.py211
-rw-r--r--doc/tools/locales/es/LC_MESSAGES/makedocs.mobin0 -> 2321 bytes
-rw-r--r--doc/tools/locales/es/LC_MESSAGES/makedocs.po142
-rw-r--r--doc/tools/main.css (renamed from doc/html/main.css)0
-rw-r--r--doc/tools/makedocs.pot108
-rw-r--r--doc/tools/makedocs.py382
-rw-r--r--doc/tools/makedoku.py514
-rw-r--r--doc/tools/makehtml.py720
-rw-r--r--doc/tools/makemd.py346
-rw-r--r--doc/tutorial/01 Getting Started.lyx557
-rw-r--r--doc/tutorial/editor.pngbin81238 -> 0 bytes
-rw-r--r--doc/tutorial/pm.pngbin36586 -> 0 bytes
-rw-r--r--doc/tutorial/pmc.pngbin22446 -> 0 bytes
-rw-r--r--doc/tutorial/tute1_1.pngbin8719 -> 0 bytes
-rw-r--r--doc/tutorial/tute1_2.pngbin12907 -> 0 bytes
-rw-r--r--doc/tutorial/tute1_2b.pngbin3154 -> 0 bytes
-rw-r--r--doc/tutorial/tute1_3a.pngbin6660 -> 0 bytes
-rw-r--r--doc/tutorial/tute1_3b.pngbin27956 -> 0 bytes
-rw-r--r--doc/tutorial/tute1_3c.pngbin3785 -> 0 bytes
-rw-r--r--doc/tutorial/tute1_4a.pngbin17321 -> 0 bytes
-rw-r--r--doc/tutorial/tute1_4b.pngbin5421 -> 0 bytes
-rw-r--r--doc/tutorial/tute1_5a.pngbin25190 -> 0 bytes
-rw-r--r--doc/tutorial/tute1_5b.pngbin47382 -> 0 bytes
-rw-r--r--doc/tutorial/tute1_6.pngbin2555 -> 0 bytes
-rw-r--r--doc/tutorial/tute1_7.pngbin1445 -> 0 bytes
-rw-r--r--doc/undoredoapi.txt25
-rw-r--r--drivers/SCsub70
-rw-r--r--drivers/alsa/SCsub2
-rw-r--r--drivers/alsa/audio_driver_alsa.cpp2
-rw-r--r--drivers/alsa/audio_driver_alsa.h2
-rw-r--r--drivers/builtin_openssl2/e_os.h6
-rw-r--r--drivers/builtin_zlib/SCsub2
-rw-r--r--drivers/chibi/SCsub2
-rw-r--r--drivers/chibi/cp_config.h2
-rw-r--r--drivers/chibi/cp_envelope.cpp2
-rw-r--r--drivers/chibi/cp_envelope.h2
-rw-r--r--drivers/chibi/cp_file_access_wrapper.cpp2
-rw-r--r--drivers/chibi/cp_file_access_wrapper.h2
-rw-r--r--drivers/chibi/cp_instrument.cpp2
-rw-r--r--drivers/chibi/cp_instrument.h2
-rw-r--r--drivers/chibi/cp_loader.h2
-rw-r--r--drivers/chibi/cp_loader_it.cpp2
-rw-r--r--drivers/chibi/cp_loader_it.h2
-rw-r--r--drivers/chibi/cp_loader_it_info.cpp2
-rw-r--r--drivers/chibi/cp_loader_it_instruments.cpp2
-rw-r--r--drivers/chibi/cp_loader_it_patterns.cpp2
-rw-r--r--drivers/chibi/cp_loader_it_samples.cpp2
-rw-r--r--drivers/chibi/cp_loader_mod.cpp11
-rw-r--r--drivers/chibi/cp_loader_mod.h2
-rw-r--r--drivers/chibi/cp_loader_s3m.cpp22
-rw-r--r--drivers/chibi/cp_loader_s3m.h2
-rw-r--r--drivers/chibi/cp_loader_xm.cpp18
-rw-r--r--drivers/chibi/cp_loader_xm.h2
-rw-r--r--drivers/chibi/cp_mixer.h2
-rw-r--r--drivers/chibi/cp_note.h2
-rw-r--r--drivers/chibi/cp_order.h2
-rw-r--r--drivers/chibi/cp_pattern.cpp2
-rw-r--r--drivers/chibi/cp_pattern.h2
-rw-r--r--drivers/chibi/cp_player_data.cpp2
-rw-r--r--drivers/chibi/cp_player_data.h2
-rw-r--r--drivers/chibi/cp_player_data_control.cpp2
-rw-r--r--drivers/chibi/cp_player_data_effects.cpp2
-rw-r--r--drivers/chibi/cp_player_data_envelopes.cpp2
-rw-r--r--drivers/chibi/cp_player_data_events.cpp2
-rw-r--r--drivers/chibi/cp_player_data_filter.cpp2
-rw-r--r--drivers/chibi/cp_player_data_nna.cpp2
-rw-r--r--drivers/chibi/cp_player_data_notes.cpp2
-rw-r--r--drivers/chibi/cp_player_data_reserved.cpp2
-rw-r--r--drivers/chibi/cp_player_data_utils.cpp2
-rw-r--r--drivers/chibi/cp_sample.cpp2
-rw-r--r--drivers/chibi/cp_sample.h2
-rw-r--r--drivers/chibi/cp_sample_defs.h2
-rw-r--r--drivers/chibi/cp_sample_manager.cpp2
-rw-r--r--drivers/chibi/cp_sample_manager.h2
-rw-r--r--drivers/chibi/cp_song.cpp2
-rw-r--r--drivers/chibi/cp_song.h2
-rw-r--r--drivers/chibi/cp_tables.cpp2
-rw-r--r--drivers/chibi/cp_tables.h2
-rw-r--r--drivers/chibi/event_stream_chibi.cpp15
-rw-r--r--drivers/chibi/event_stream_chibi.h4
-rw-r--r--drivers/convex_decomp/b2Glue.h3
-rw-r--r--drivers/convex_decomp/b2Polygon.cpp8
-rw-r--r--drivers/convex_decomp/b2Polygon.h2
-rw-r--r--drivers/dds/SCsub1
-rw-r--r--drivers/dds/texture_loader_dds.cpp10
-rw-r--r--drivers/dds/texture_loader_dds.h2
-rw-r--r--drivers/etc1/SCsub1
-rw-r--r--drivers/etc1/rg_etc1.cpp4908
-rw-r--r--drivers/etc1/rg_etc1.h152
-rw-r--r--drivers/gl_context/SCsub1
-rw-r--r--drivers/gl_context/context_gl.cpp2
-rw-r--r--drivers/gl_context/context_gl.h2
-rw-r--r--drivers/gl_context/glew.c4
-rw-r--r--drivers/gles2/rasterizer_gles2.cpp326
-rw-r--r--drivers/gles2/rasterizer_gles2.h21
-rw-r--r--drivers/gles2/rasterizer_instance_gles2.cpp2
-rw-r--r--drivers/gles2/rasterizer_instance_gles2.h2
-rw-r--r--drivers/gles2/shader_compiler_gles2.cpp268
-rw-r--r--drivers/gles2/shader_compiler_gles2.h7
-rw-r--r--drivers/gles2/shader_gles2.cpp6
-rw-r--r--drivers/gles2/shader_gles2.h7
-rw-r--r--drivers/gles2/shaders/SCsub2
-rw-r--r--drivers/gles2/shaders/canvas.glsl29
-rw-r--r--drivers/gles2/shaders/material.glsl8
-rw-r--r--drivers/jpegd/SCsub11
-rw-r--r--drivers/jpegd/image_loader_jpegd.cpp108
-rw-r--r--drivers/jpegd/image_loader_jpegd.h32
-rw-r--r--drivers/jpegd/jpgd.cpp3172
-rw-r--r--drivers/jpegd/jpgd.h319
-rw-r--r--drivers/jpg/SCsub13
-rw-r--r--drivers/jpg/image_loader_jpg.cpp93
-rw-r--r--drivers/jpg/image_loader_jpg.h32
-rw-r--r--drivers/jpg/jidctflt.c286
-rw-r--r--drivers/jpg/loadjpeg.c341
-rw-r--r--drivers/jpg/tinyjpeg-internal.h162
-rw-r--r--drivers/jpg/tinyjpeg.c2202
-rw-r--r--drivers/jpg/tinyjpeg.h74
-rw-r--r--drivers/mpc/SCsub1
-rw-r--r--drivers/mpc/audio_stream_mpc.cpp133
-rw-r--r--drivers/mpc/audio_stream_mpc.h47
-rw-r--r--drivers/nedmalloc/SCsub1
-rw-r--r--drivers/nedmalloc/malloc.c.h11628
-rw-r--r--drivers/nedmalloc/memory_pool_static_nedmalloc.cpp2
-rw-r--r--drivers/nedmalloc/memory_pool_static_nedmalloc.h2
-rw-r--r--drivers/nedmalloc/nedmalloc.cpp2934
-rw-r--r--drivers/nedmalloc/nedmalloc.h604
-rw-r--r--drivers/nrex/README.md61
-rw-r--r--drivers/nrex/SCsub7
-rw-r--r--drivers/nrex/nrex.cpp1435
-rw-r--r--drivers/nrex/nrex.hpp175
-rw-r--r--drivers/nrex/nrex_config.h12
-rw-r--r--drivers/nrex/regex.cpp116
-rw-r--r--drivers/nrex/regex.h47
-rw-r--r--drivers/ogg/SCsub4
-rw-r--r--drivers/openssl/SCsub2
-rw-r--r--drivers/openssl/register_openssl.cpp38
-rw-r--r--drivers/openssl/register_openssl.h22
-rw-r--r--drivers/openssl/stream_peer_openssl.cpp7
-rw-r--r--drivers/openssl/stream_peer_openssl.h2
-rw-r--r--drivers/opus/SCsub195
-rw-r--r--drivers/opus/analysis.c645
-rw-r--r--drivers/opus/analysis.h90
-rw-r--r--drivers/opus/audio_stream_opus.cpp376
-rw-r--r--drivers/opus/audio_stream_opus.h141
-rw-r--r--drivers/opus/celt/_kiss_fft_guts.h183
-rw-r--r--drivers/opus/celt/arch.h214
-rwxr-xr-xdrivers/opus/celt/arm/arm2gnu.pl316
-rw-r--r--drivers/opus/celt/arm/arm_celt_map.c49
-rw-r--r--drivers/opus/celt/arm/armcpu.c174
-rw-r--r--drivers/opus/celt/arm/armcpu.h71
-rw-r--r--drivers/opus/celt/arm/armopts.s37
-rw-r--r--drivers/opus/celt/arm/armopts.s.in37
-rw-r--r--drivers/opus/celt/arm/celt_pitch_xcorr_arm.s545
-rw-r--r--drivers/opus/celt/arm/fixed_armv4.h76
-rw-r--r--drivers/opus/celt/arm/fixed_armv5e.h116
-rw-r--r--drivers/opus/celt/arm/kiss_fft_armv4.h121
-rw-r--r--drivers/opus/celt/arm/kiss_fft_armv5e.h118
-rw-r--r--drivers/opus/celt/arm/pitch_arm.h57
-rw-r--r--drivers/opus/celt/bands.c1518
-rw-r--r--drivers/opus/celt/bands.h114
-rw-r--r--drivers/opus/celt/celt.c223
-rw-r--r--drivers/opus/celt/celt.h218
-rw-r--r--drivers/opus/celt/celt_decoder.c1195
-rw-r--r--drivers/opus/celt/celt_encoder.c2353
-rw-r--r--drivers/opus/celt/celt_lpc.c309
-rw-r--r--drivers/opus/celt/celt_lpc.h54
-rw-r--r--drivers/opus/celt/cpu_support.h54
-rw-r--r--drivers/opus/celt/cwrs.c697
-rw-r--r--drivers/opus/celt/cwrs.h48
-rw-r--r--drivers/opus/celt/ecintrin.h87
-rw-r--r--drivers/opus/celt/entcode.c93
-rw-r--r--drivers/opus/celt/entcode.h117
-rw-r--r--drivers/opus/celt/entdec.c245
-rw-r--r--drivers/opus/celt/entdec.h100
-rw-r--r--drivers/opus/celt/entenc.c294
-rw-r--r--drivers/opus/celt/entenc.h110
-rw-r--r--drivers/opus/celt/fixed_debug.h773
-rw-r--r--drivers/opus/celt/fixed_generic.h134
-rw-r--r--drivers/opus/celt/float_cast.h140
-rw-r--r--drivers/opus/celt/kiss_fft.c719
-rw-r--r--drivers/opus/celt/kiss_fft.h139
-rw-r--r--drivers/opus/celt/laplace.c134
-rw-r--r--drivers/opus/celt/laplace.h48
-rw-r--r--drivers/opus/celt/mathops.c208
-rw-r--r--drivers/opus/celt/mathops.h258
-rw-r--r--drivers/opus/celt/mdct.c311
-rw-r--r--drivers/opus/celt/mdct.h70
-rw-r--r--drivers/opus/celt/mfrngcod.h48
-rw-r--r--drivers/opus/celt/modes.c438
-rw-r--r--drivers/opus/celt/opus_custom_demo.c210
-rw-r--r--drivers/opus/celt/opus_modes.h83
-rw-r--r--drivers/opus/celt/os_support.h92
-rw-r--r--drivers/opus/celt/pitch.c537
-rw-r--r--drivers/opus/celt/pitch.h173
-rw-r--r--drivers/opus/celt/quant_bands.c556
-rw-r--r--drivers/opus/celt/quant_bands.h66
-rw-r--r--drivers/opus/celt/rate.c638
-rw-r--r--drivers/opus/celt/rate.h101
-rw-r--r--drivers/opus/celt/stack_alloc.h182
-rw-r--r--drivers/opus/celt/static_modes_fixed.h595
-rw-r--r--drivers/opus/celt/static_modes_float.h599
-rw-r--r--drivers/opus/celt/tests/test_unit_cwrs32.c161
-rw-r--r--drivers/opus/celt/tests/test_unit_dft.c164
-rw-r--r--drivers/opus/celt/tests/test_unit_entropy.c382
-rw-r--r--drivers/opus/celt/tests/test_unit_laplace.c92
-rw-r--r--drivers/opus/celt/tests/test_unit_mathops.c275
-rw-r--r--drivers/opus/celt/tests/test_unit_mdct.c210
-rw-r--r--drivers/opus/celt/tests/test_unit_rotation.c90
-rw-r--r--drivers/opus/celt/tests/test_unit_types.c50
-rw-r--r--drivers/opus/celt/vq.c415
-rw-r--r--drivers/opus/celt/vq.h70
-rw-r--r--drivers/opus/celt/x86/pitch_sse.h156
-rw-r--r--drivers/opus/http.c3391
-rw-r--r--drivers/opus/info.c687
-rw-r--r--drivers/opus/internal.c42
-rw-r--r--drivers/opus/internal.h249
-rw-r--r--drivers/opus/mlp.c140
-rw-r--r--drivers/opus/mlp.h41
-rw-r--r--drivers/opus/mlp_data.c105
-rw-r--r--drivers/opus/opus.c329
-rw-r--r--drivers/opus/opus.h978
-rw-r--r--drivers/opus/opus_compare.c379
-rw-r--r--drivers/opus/opus_config.h129
-rw-r--r--drivers/opus/opus_custom.h342
-rw-r--r--drivers/opus/opus_decoder.c970
-rw-r--r--drivers/opus/opus_defines.h726
-rw-r--r--drivers/opus/opus_demo.c885
-rw-r--r--drivers/opus/opus_encoder.c2488
-rw-r--r--drivers/opus/opus_multistream.c92
-rw-r--r--drivers/opus/opus_multistream.h660
-rw-r--r--drivers/opus/opus_multistream_decoder.c537
-rw-r--r--drivers/opus/opus_multistream_encoder.c1174
-rw-r--r--drivers/opus/opus_private.h129
-rw-r--r--drivers/opus/opus_types.h159
-rw-r--r--drivers/opus/opusfile.c3158
-rw-r--r--drivers/opus/opusfile.h2102
-rw-r--r--drivers/opus/repacketizer.c345
-rw-r--r--drivers/opus/repacketizer_demo.c217
-rw-r--r--drivers/opus/silk/A2NLSF.c252
-rw-r--r--drivers/opus/silk/API.h133
-rw-r--r--drivers/opus/silk/CNG.c172
-rw-r--r--drivers/opus/silk/HP_variable_cutoff.c77
-rw-r--r--drivers/opus/silk/Inlines.h188
-rw-r--r--drivers/opus/silk/LPC_analysis_filter.c106
-rw-r--r--drivers/opus/silk/LPC_inv_pred_gain.c154
-rw-r--r--drivers/opus/silk/LP_variable_cutoff.c135
-rw-r--r--drivers/opus/silk/MacroCount.h718
-rw-r--r--drivers/opus/silk/MacroDebug.h952
-rw-r--r--drivers/opus/silk/NLSF2A.c178
-rw-r--r--drivers/opus/silk/NLSF_VQ.c68
-rw-r--r--drivers/opus/silk/NLSF_VQ_weights_laroia.c80
-rw-r--r--drivers/opus/silk/NLSF_decode.c101
-rw-r--r--drivers/opus/silk/NLSF_del_dec_quant.c207
-rw-r--r--drivers/opus/silk/NLSF_encode.c136
-rw-r--r--drivers/opus/silk/NLSF_stabilize.c142
-rw-r--r--drivers/opus/silk/NLSF_unpack.c55
-rw-r--r--drivers/opus/silk/NSQ.c446
-rw-r--r--drivers/opus/silk/NSQ_del_dec.c719
-rw-r--r--drivers/opus/silk/PLC.c423
-rw-r--r--drivers/opus/silk/PLC.h61
-rw-r--r--drivers/opus/silk/SigProc_FIX.h594
-rw-r--r--drivers/opus/silk/VAD.c357
-rw-r--r--drivers/opus/silk/VQ_WMat_EC.c120
-rw-r--r--drivers/opus/silk/ana_filt_bank_1.c74
-rw-r--r--drivers/opus/silk/arm/SigProc_FIX_armv4.h47
-rw-r--r--drivers/opus/silk/arm/SigProc_FIX_armv5e.h61
-rw-r--r--drivers/opus/silk/arm/macros_armv4.h103
-rw-r--r--drivers/opus/silk/arm/macros_armv5e.h213
-rw-r--r--drivers/opus/silk/biquad_alt.c78
-rw-r--r--drivers/opus/silk/bwexpander.c51
-rw-r--r--drivers/opus/silk/bwexpander_32.c50
-rw-r--r--drivers/opus/silk/check_control_input.c106
-rw-r--r--drivers/opus/silk/code_signs.c115
-rw-r--r--drivers/opus/silk/control.h142
-rw-r--r--drivers/opus/silk/control_SNR.c81
-rw-r--r--drivers/opus/silk/control_audio_bandwidth.c126
-rw-r--r--drivers/opus/silk/control_codec.c422
-rw-r--r--drivers/opus/silk/debug.c170
-rw-r--r--drivers/opus/silk/debug.h279
-rw-r--r--drivers/opus/silk/dec_API.c397
-rw-r--r--drivers/opus/silk/decode_core.c238
-rw-r--r--drivers/opus/silk/decode_frame.c128
-rw-r--r--drivers/opus/silk/decode_indices.c151
-rw-r--r--drivers/opus/silk/decode_parameters.c115
-rw-r--r--drivers/opus/silk/decode_pitch.c77
-rw-r--r--drivers/opus/silk/decode_pulses.c115
-rw-r--r--drivers/opus/silk/decoder_set_fs.c108
-rw-r--r--drivers/opus/silk/define.h235
-rw-r--r--drivers/opus/silk/enc_API.c556
-rw-r--r--drivers/opus/silk/encode_indices.c181
-rw-r--r--drivers/opus/silk/encode_pulses.c206
-rw-r--r--drivers/opus/silk/errors.h98
-rw-r--r--drivers/opus/silk/fixed/LTP_analysis_filter_FIX.c85
-rw-r--r--drivers/opus/silk/fixed/LTP_scale_ctrl_FIX.c53
-rw-r--r--drivers/opus/silk/fixed/apply_sine_window_FIX.c101
-rw-r--r--drivers/opus/silk/fixed/autocorr_FIX.c48
-rw-r--r--drivers/opus/silk/fixed/burg_modified_FIX.c279
-rw-r--r--drivers/opus/silk/fixed/corrMatrix_FIX.c156
-rw-r--r--drivers/opus/silk/fixed/encode_frame_FIX.c385
-rw-r--r--drivers/opus/silk/fixed/find_LPC_FIX.c151
-rw-r--r--drivers/opus/silk/fixed/find_LTP_FIX.c244
-rw-r--r--drivers/opus/silk/fixed/find_pitch_lags_FIX.c145
-rw-r--r--drivers/opus/silk/fixed/find_pred_coefs_FIX.c147
-rw-r--r--drivers/opus/silk/fixed/k2a_FIX.c53
-rw-r--r--drivers/opus/silk/fixed/k2a_Q16_FIX.c53
-rw-r--r--drivers/opus/silk/fixed/main_FIX.h257
-rw-r--r--drivers/opus/silk/fixed/noise_shape_analysis_FIX.c445
-rw-r--r--drivers/opus/silk/fixed/pitch_analysis_core_FIX.c744
-rw-r--r--drivers/opus/silk/fixed/prefilter_FIX.c209
-rw-r--r--drivers/opus/silk/fixed/process_gains_FIX.c117
-rw-r--r--drivers/opus/silk/fixed/regularize_correlations_FIX.c47
-rw-r--r--drivers/opus/silk/fixed/residual_energy16_FIX.c103
-rw-r--r--drivers/opus/silk/fixed/residual_energy_FIX.c97
-rw-r--r--drivers/opus/silk/fixed/schur64_FIX.c92
-rw-r--r--drivers/opus/silk/fixed/schur_FIX.c106
-rw-r--r--drivers/opus/silk/fixed/solve_LS_FIX.c249
-rw-r--r--drivers/opus/silk/fixed/structs_FIX.h133
-rw-r--r--drivers/opus/silk/fixed/vector_ops_FIX.c96
-rw-r--r--drivers/opus/silk/fixed/warped_autocorrelation_FIX.c88
-rw-r--r--drivers/opus/silk/float/LPC_analysis_filter_FLP.c249
-rw-r--r--drivers/opus/silk/float/LPC_inv_pred_gain_FLP.c76
-rw-r--r--drivers/opus/silk/float/LTP_analysis_filter_FLP.c75
-rw-r--r--drivers/opus/silk/float/LTP_scale_ctrl_FLP.c52
-rw-r--r--drivers/opus/silk/float/SigProc_FLP.h204
-rw-r--r--drivers/opus/silk/float/apply_sine_window_FLP.c81
-rw-r--r--drivers/opus/silk/float/autocorrelation_FLP.c52
-rw-r--r--drivers/opus/silk/float/burg_modified_FLP.c186
-rw-r--r--drivers/opus/silk/float/bwexpander_FLP.c49
-rw-r--r--drivers/opus/silk/float/corrMatrix_FLP.c93
-rw-r--r--drivers/opus/silk/float/encode_frame_FLP.c372
-rw-r--r--drivers/opus/silk/float/energy_FLP.c60
-rw-r--r--drivers/opus/silk/float/find_LPC_FLP.c104
-rw-r--r--drivers/opus/silk/float/find_LTP_FLP.c132
-rw-r--r--drivers/opus/silk/float/find_pitch_lags_FLP.c132
-rw-r--r--drivers/opus/silk/float/find_pred_coefs_FLP.c117
-rw-r--r--drivers/opus/silk/float/inner_product_FLP.c60
-rw-r--r--drivers/opus/silk/float/k2a_FLP.c53
-rw-r--r--drivers/opus/silk/float/levinsondurbin_FLP.c81
-rw-r--r--drivers/opus/silk/float/main_FLP.h312
-rw-r--r--drivers/opus/silk/float/noise_shape_analysis_FLP.c365
-rw-r--r--drivers/opus/silk/float/pitch_analysis_core_FLP.c630
-rw-r--r--drivers/opus/silk/float/prefilter_FLP.c206
-rw-r--r--drivers/opus/silk/float/process_gains_FLP.c103
-rw-r--r--drivers/opus/silk/float/regularize_correlations_FLP.c48
-rw-r--r--drivers/opus/silk/float/residual_energy_FLP.c117
-rw-r--r--drivers/opus/silk/float/scale_copy_vector_FLP.c57
-rw-r--r--drivers/opus/silk/float/scale_vector_FLP.c56
-rw-r--r--drivers/opus/silk/float/schur_FLP.c70
-rw-r--r--drivers/opus/silk/float/solve_LS_FLP.c207
-rw-r--r--drivers/opus/silk/float/sort_FLP.c83
-rw-r--r--drivers/opus/silk/float/structs_FLP.h131
-rw-r--r--drivers/opus/silk/float/warped_autocorrelation_FLP.c73
-rw-r--r--drivers/opus/silk/float/wrappers_FLP.c201
-rw-r--r--drivers/opus/silk/gain_quant.c141
-rw-r--r--drivers/opus/silk/init_decoder.c56
-rw-r--r--drivers/opus/silk/init_encoder.c64
-rw-r--r--drivers/opus/silk/inner_prod_aligned.c47
-rw-r--r--drivers/opus/silk/interpolate.c51
-rw-r--r--drivers/opus/silk/lin2log.c46
-rw-r--r--drivers/opus/silk/log2lin.c58
-rw-r--r--drivers/opus/silk/macros.h113
-rw-r--r--drivers/opus/silk/pitch_est_defines.h88
-rw-r--r--drivers/opus/silk/pitch_est_tables.c99
-rw-r--r--drivers/opus/silk/process_NLSFs.c105
-rw-r--r--drivers/opus/silk/quant_LTP_gains.c128
-rw-r--r--drivers/opus/silk/resampler.c215
-rw-r--r--drivers/opus/silk/resampler_down2.c74
-rw-r--r--drivers/opus/silk/resampler_down2_3.c103
-rw-r--r--drivers/opus/silk/resampler_private.h88
-rw-r--r--drivers/opus/silk/resampler_private_AR2.c55
-rw-r--r--drivers/opus/silk/resampler_private_IIR_FIR.c107
-rw-r--r--drivers/opus/silk/resampler_private_down_FIR.c194
-rw-r--r--drivers/opus/silk/resampler_private_up2_HQ.c113
-rw-r--r--drivers/opus/silk/resampler_rom.c96
-rw-r--r--drivers/opus/silk/resampler_rom.h68
-rw-r--r--drivers/opus/silk/resampler_structs.h60
-rw-r--r--drivers/opus/silk/shell_coder.c151
-rw-r--r--drivers/opus/silk/sigm_Q15.c76
-rw-r--r--drivers/opus/silk/silk_main.h438
-rw-r--r--drivers/opus/silk/sort.c154
-rw-r--r--drivers/opus/silk/stereo_LR_to_MS.c229
-rw-r--r--drivers/opus/silk/stereo_MS_to_LR.c85
-rw-r--r--drivers/opus/silk/stereo_decode_pred.c73
-rw-r--r--drivers/opus/silk/stereo_encode_pred.c62
-rw-r--r--drivers/opus/silk/stereo_find_predictor.c79
-rw-r--r--drivers/opus/silk/stereo_quant_pred.c73
-rw-r--r--drivers/opus/silk/structs.h327
-rw-r--r--drivers/opus/silk/sum_sqr_shift.c85
-rw-r--r--drivers/opus/silk/table_LSF_cos.c70
-rw-r--r--drivers/opus/silk/tables.h122
-rw-r--r--drivers/opus/silk/tables_LTP.c296
-rw-r--r--drivers/opus/silk/tables_NLSF_CB_NB_MB.c159
-rw-r--r--drivers/opus/silk/tables_NLSF_CB_WB.c198
-rw-r--r--drivers/opus/silk/tables_gain.c63
-rw-r--r--drivers/opus/silk/tables_other.c138
-rw-r--r--drivers/opus/silk/tables_pitch_lag.c69
-rw-r--r--drivers/opus/silk/tables_pulses_per_block.c264
-rw-r--r--drivers/opus/silk/tuning_parameters.h171
-rw-r--r--drivers/opus/silk/typedef.h78
-rw-r--r--drivers/opus/stream.c366
-rw-r--r--drivers/opus/tansig_table.h45
-rw-r--r--drivers/opus/wincerts.c171
-rw-r--r--drivers/opus/winerrno.h90
-rw-r--r--drivers/png/SCsub13
-rw-r--r--drivers/png/arm/arm_init.c232
-rw-r--r--drivers/png/arm/filter_neon.S235
-rw-r--r--drivers/png/example.c85
-rw-r--r--drivers/png/filter_neon.S225
-rw-r--r--drivers/png/image_loader_png.cpp2
-rw-r--r--drivers/png/image_loader_png.h2
-rw-r--r--drivers/png/png.c398
-rw-r--r--drivers/png/png.h490
-rw-r--r--drivers/png/pngconf.h72
-rw-r--r--drivers/png/pngdebug.h22
-rw-r--r--drivers/png/pngerror.c80
-rw-r--r--drivers/png/pngget.c64
-rw-r--r--drivers/png/pnginfo.h7
-rw-r--r--drivers/png/pnglibconf.h164
-rw-r--r--drivers/png/pngmem.c12
-rw-r--r--drivers/png/pngpread.c695
-rw-r--r--drivers/png/pngpriv.h236
-rw-r--r--drivers/png/pngread.c50
-rw-r--r--drivers/png/pngrio.c4
-rw-r--r--drivers/png/pngrtran.c228
-rw-r--r--drivers/png/pngrutil.c245
-rw-r--r--drivers/png/pngset.c283
-rw-r--r--drivers/png/pngstruct.h39
-rw-r--r--drivers/png/pngtrans.c115
-rw-r--r--drivers/png/pngwio.c6
-rw-r--r--drivers/png/pngwrite.c427
-rw-r--r--drivers/png/pngwtran.c20
-rw-r--r--drivers/png/pngwutil.c620
-rw-r--r--drivers/png/resource_saver_png.cpp6
-rw-r--r--drivers/pnm/SCsub10
-rw-r--r--drivers/pnm/bitmap_loader_pnm.cpp235
-rw-r--r--drivers/pnm/bitmap_loader_pnm.h33
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.cpp15
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.h7
-rw-r--r--drivers/pvr/texture_loader_pvr.cpp9
-rw-r--r--drivers/pvr/texture_loader_pvr.h2
-rw-r--r--drivers/register_driver_types.cpp56
-rw-r--r--drivers/register_driver_types.h2
-rw-r--r--drivers/rtaudio/RtAudio.cpp20466
-rw-r--r--drivers/rtaudio/audio_driver_rtaudio.cpp2
-rw-r--r--drivers/rtaudio/audio_driver_rtaudio.h2
-rw-r--r--drivers/speex/audio_stream_speex.cpp183
-rw-r--r--drivers/speex/audio_stream_speex.h58
-rw-r--r--drivers/speex/config.h104
-rw-r--r--drivers/speex/lsp.h128
-rw-r--r--drivers/speex/speex_bind.cpp128
-rw-r--r--drivers/speex/speex_bind.h96
-rw-r--r--drivers/squish/SCsub1
-rw-r--r--drivers/theora/SCsub35
-rw-r--r--drivers/theora/decode.c46
-rw-r--r--drivers/theora/encint.h1
-rw-r--r--drivers/theora/video_stream_theora.cpp601
-rw-r--r--drivers/theora/video_stream_theora.h86
-rw-r--r--drivers/theoraplayer/SCsub106
-rw-r--r--drivers/theoraplayer/include/theoraplayer/TheoraAsync.h51
-rw-r--r--drivers/theoraplayer/include/theoraplayer/TheoraAudioInterface.h51
-rw-r--r--drivers/theoraplayer/include/theoraplayer/TheoraAudioPacketQueue.h48
-rw-r--r--drivers/theoraplayer/include/theoraplayer/TheoraDataSource.h89
-rw-r--r--drivers/theoraplayer/include/theoraplayer/TheoraException.h46
-rw-r--r--drivers/theoraplayer/include/theoraplayer/TheoraExport.h38
-rw-r--r--drivers/theoraplayer/include/theoraplayer/TheoraFrameQueue.h95
-rw-r--r--drivers/theoraplayer/include/theoraplayer/TheoraPixelTransform.h18
-rw-r--r--drivers/theoraplayer/include/theoraplayer/TheoraPlayer.h17
-rw-r--r--drivers/theoraplayer/include/theoraplayer/TheoraTimer.h69
-rw-r--r--drivers/theoraplayer/include/theoraplayer/TheoraUtil.h32
-rw-r--r--drivers/theoraplayer/include/theoraplayer/TheoraVideoClip.h282
-rw-r--r--drivers/theoraplayer/include/theoraplayer/TheoraVideoFrame.h56
-rw-r--r--drivers/theoraplayer/include/theoraplayer/TheoraVideoManager.h110
-rw-r--r--drivers/theoraplayer/include/theoraplayer/TheoraWorkerThread.h32
-rw-r--r--drivers/theoraplayer/src/AVFoundation/TheoraVideoClip_AVFoundation.h47
-rw-r--r--drivers/theoraplayer/src/AVFoundation/TheoraVideoClip_AVFoundation.mm457
-rw-r--r--drivers/theoraplayer/src/FFmpeg/TheoraVideoClip_FFmpeg.cpp439
-rw-r--r--drivers/theoraplayer/src/FFmpeg/TheoraVideoClip_FFmpeg.h53
-rw-r--r--drivers/theoraplayer/src/Theora/TheoraVideoClip_Theora.cpp703
-rw-r--r--drivers/theoraplayer/src/Theora/TheoraVideoClip_Theora.h64
-rw-r--r--drivers/theoraplayer/src/TheoraAsync.cpp253
-rw-r--r--drivers/theoraplayer/src/TheoraAudioInterface.cpp21
-rw-r--r--drivers/theoraplayer/src/TheoraAudioPacketQueue.cpp126
-rw-r--r--drivers/theoraplayer/src/TheoraDataSource.cpp128
-rw-r--r--drivers/theoraplayer/src/TheoraException.cpp37
-rw-r--r--drivers/theoraplayer/src/TheoraFrameQueue.cpp174
-rw-r--r--drivers/theoraplayer/src/TheoraTimer.cpp70
-rw-r--r--drivers/theoraplayer/src/TheoraUtil.cpp59
-rw-r--r--drivers/theoraplayer/src/TheoraVideoClip.cpp496
-rw-r--r--drivers/theoraplayer/src/TheoraVideoFrame.cpp159
-rw-r--r--drivers/theoraplayer/src/TheoraVideoManager.cpp485
-rw-r--r--drivers/theoraplayer/src/TheoraWorkerThread.cpp49
-rw-r--r--drivers/theoraplayer/src/YUV/C/yuv420_grey_c.c56
-rw-r--r--drivers/theoraplayer/src/YUV/C/yuv420_rgb_c.c358
-rw-r--r--drivers/theoraplayer/src/YUV/C/yuv420_yuv_c.c86
-rw-r--r--drivers/theoraplayer/src/YUV/android/cpu-features.c1095
-rw-r--r--drivers/theoraplayer/src/YUV/android/cpu-features.h212
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/LICENSE29
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/LICENSE_THIRD_PARTY8
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/include/libyuv.h33
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/include/libyuv/basic_types.h118
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/include/libyuv/compare.h73
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/include/libyuv/convert.h254
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/include/libyuv/convert_argb.h225
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/include/libyuv/convert_from.h173
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/include/libyuv/convert_from_argb.h168
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/include/libyuv/cpu_id.h81
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/include/libyuv/format_conversion.h168
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/include/libyuv/mjpeg_decoder.h201
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/include/libyuv/planar_functions.h434
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/include/libyuv/rotate.h117
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/include/libyuv/rotate_argb.h33
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/include/libyuv/row.h1694
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/include/libyuv/scale.h85
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/include/libyuv/scale_argb.h57
-rw-r--r--drivers/theoraplayer/src/YUV/libyuv/include/libyuv/scale_row.h301
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/include/libyuv/version.h16
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/include/libyuv/video_common.h182
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/libtheoraplayer-readme.txt15
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/compare.cc325
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/compare_common.cc42
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/compare_neon.cc64
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/compare_posix.cc158
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/compare_win.cc232
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/convert.cc1491
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/convert_argb.cc901
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/convert_from.cc1196
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/convert_from_argb.cc1096
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/convert_jpeg.cc392
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/convert_to_argb.cc327
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/convert_to_i420.cc383
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/cpu_id.cc300
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/format_conversion.cc552
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/mjpeg_decoder.cc558
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/mjpeg_validate.cc47
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/planar_functions.cc2238
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/rotate.cc1301
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/rotate_argb.cc209
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/rotate_mips.cc486
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/rotate_neon.cc412
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/row_any.cc542
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/row_common.cc2247
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/row_mips.cc991
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/row_neon.cc2847
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/row_posix.cc6443
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/row_win.cc7284
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/row_x86.asm146
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/scale.cc926
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/scale_argb.cc809
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/scale_argb_neon.cc145
-rw-r--r--drivers/theoraplayer/src/YUV/libyuv/src/scale_common.cc772
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/scale_mips.cc653
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/scale_neon.cc699
-rw-r--r--drivers/theoraplayer/src/YUV/libyuv/src/scale_posix.cc1315
-rw-r--r--drivers/theoraplayer/src/YUV/libyuv/src/scale_win.cc1320
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/video_common.cc64
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/src/x86inc.asm1136
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/yuv_libyuv.c72
-rwxr-xr-xdrivers/theoraplayer/src/YUV/libyuv/yuv_libyuv.h14
-rw-r--r--drivers/theoraplayer/src/YUV/yuv_util.c39
-rw-r--r--drivers/theoraplayer/src/YUV/yuv_util.h17
-rw-r--r--drivers/theoraplayer/theoraplayer.xcodeproj/project.pbxproj2606
-rw-r--r--drivers/theoraplayer/video_stream_theoraplayer.cpp554
-rw-r--r--drivers/theoraplayer/video_stream_theoraplayer.h66
-rw-r--r--drivers/trex/SCsub10
-rw-r--r--drivers/trex/TRexpp.h75
-rw-r--r--drivers/trex/history.txt15
-rw-r--r--drivers/trex/readme.txt171
-rw-r--r--drivers/trex/regex.cpp163
-rw-r--r--drivers/trex/regex.h50
-rw-r--r--drivers/trex/test.c41
-rw-r--r--drivers/trex/trex.c643
-rw-r--r--drivers/trex/trex.h70
-rw-r--r--drivers/unix/SCsub12
-rw-r--r--drivers/unix/dir_access_unix.cpp2
-rw-r--r--drivers/unix/dir_access_unix.h2
-rw-r--r--drivers/unix/file_access_unix.cpp10
-rw-r--r--drivers/unix/file_access_unix.h11
-rw-r--r--drivers/unix/ip_unix.cpp2
-rw-r--r--drivers/unix/ip_unix.h2
-rw-r--r--drivers/unix/memory_pool_static_malloc.cpp2
-rw-r--r--drivers/unix/memory_pool_static_malloc.h2
-rw-r--r--drivers/unix/mutex_posix.cpp2
-rw-r--r--drivers/unix/mutex_posix.h2
-rw-r--r--drivers/unix/os_unix.cpp53
-rw-r--r--drivers/unix/os_unix.h6
-rw-r--r--drivers/unix/packet_peer_udp_posix.cpp10
-rw-r--r--drivers/unix/semaphore_posix.cpp4
-rw-r--r--drivers/unix/semaphore_posix.h2
-rw-r--r--drivers/unix/stream_peer_tcp_posix.cpp17
-rw-r--r--drivers/unix/stream_peer_tcp_posix.h4
-rw-r--r--drivers/unix/tcp_server_posix.cpp8
-rw-r--r--drivers/unix/tcp_server_posix.h2
-rw-r--r--drivers/unix/thread_posix.cpp44
-rw-r--r--drivers/unix/thread_posix.h3
-rw-r--r--drivers/vorbis/SCsub6
-rw-r--r--drivers/vorbis/audio_stream_ogg_vorbis.cpp215
-rw-r--r--drivers/vorbis/audio_stream_ogg_vorbis.h55
-rw-r--r--drivers/webp/SCsub157
-rw-r--r--drivers/webp/config.h145
-rw-r--r--drivers/webp/dec/alpha.c205
-rw-r--r--drivers/webp/dec/alphai.h55
-rw-r--r--drivers/webp/dec/buffer.c99
-rw-r--r--drivers/webp/dec/common.h54
-rw-r--r--drivers/webp/dec/decode_vp8.h17
-rw-r--r--drivers/webp/dec/frame.c665
-rw-r--r--drivers/webp/dec/idec.c307
-rw-r--r--drivers/webp/dec/io.c269
-rw-r--r--drivers/webp/dec/quant.c17
-rw-r--r--drivers/webp/dec/tree.c182
-rw-r--r--drivers/webp/dec/vp8.c493
-rw-r--r--drivers/webp/dec/vp8i.h218
-rw-r--r--drivers/webp/dec/vp8l.c1095
-rw-r--r--drivers/webp/dec/vp8li.h53
-rw-r--r--drivers/webp/dec/webp.c220
-rw-r--r--drivers/webp/dec/webpi.h35
-rw-r--r--drivers/webp/decode.h164
-rw-r--r--drivers/webp/demux.h364
-rw-r--r--drivers/webp/demux/anim_decode.c442
-rw-r--r--drivers/webp/demux/demux.c957
-rw-r--r--drivers/webp/dsp/alpha_processing.c383
-rw-r--r--drivers/webp/dsp/alpha_processing_mips_dsp_r2.c141
-rw-r--r--drivers/webp/dsp/alpha_processing_sse2.c298
-rw-r--r--drivers/webp/dsp/alpha_processing_sse41.c92
-rw-r--r--drivers/webp/dsp/argb.c68
-rw-r--r--drivers/webp/dsp/argb_mips_dsp_r2.c110
-rw-r--r--drivers/webp/dsp/argb_sse2.c67
-rw-r--r--drivers/webp/dsp/cost.c412
-rw-r--r--drivers/webp/dsp/cost_mips32.c154
-rw-r--r--drivers/webp/dsp/cost_mips_dsp_r2.c107
-rw-r--r--drivers/webp/dsp/cost_sse2.c119
-rw-r--r--drivers/webp/dsp/cpu.c95
-rw-r--r--drivers/webp/dsp/dec.c338
-rw-r--r--drivers/webp/dsp/dec_clip_tables.c366
-rw-r--r--drivers/webp/dsp/dec_mips32.c587
-rw-r--r--drivers/webp/dsp/dec_mips_dsp_r2.c994
-rw-r--r--drivers/webp/dsp/dec_neon.c1478
-rw-r--r--drivers/webp/dsp/dec_sse2.c1056
-rw-r--r--drivers/webp/dsp/dec_sse41.c45
-rw-r--r--drivers/webp/dsp/dsp.h366
-rw-r--r--drivers/webp/dsp/enc.c347
-rw-r--r--drivers/webp/dsp/enc_avx2.c21
-rw-r--r--drivers/webp/dsp/enc_mips32.c672
-rw-r--r--drivers/webp/dsp/enc_mips_dsp_r2.c1512
-rw-r--r--drivers/webp/dsp/enc_neon.c934
-rw-r--r--drivers/webp/dsp/enc_sse2.c1364
-rw-r--r--drivers/webp/dsp/enc_sse41.c375
-rw-r--r--drivers/webp/dsp/filters.c240
-rw-r--r--drivers/webp/dsp/filters_mips_dsp_r2.c405
-rw-r--r--drivers/webp/dsp/filters_sse2.c352
-rw-r--r--drivers/webp/dsp/lossless.c1013
-rw-r--r--drivers/webp/dsp/lossless.h292
-rw-r--r--drivers/webp/dsp/lossless_enc.c1305
-rw-r--r--drivers/webp/dsp/lossless_enc_mips32.c417
-rw-r--r--drivers/webp/dsp/lossless_enc_mips_dsp_r2.c275
-rw-r--r--drivers/webp/dsp/lossless_enc_neon.c143
-rw-r--r--drivers/webp/dsp/lossless_enc_sse2.c270
-rw-r--r--drivers/webp/dsp/lossless_enc_sse41.c51
-rw-r--r--drivers/webp/dsp/lossless_mips_dsp_r2.c680
-rw-r--r--drivers/webp/dsp/lossless_neon.c269
-rw-r--r--drivers/webp/dsp/lossless_sse2.c372
-rw-r--r--drivers/webp/dsp/mips_macro.h200
-rw-r--r--drivers/webp/dsp/neon.h82
-rw-r--r--drivers/webp/dsp/rescaler.c238
-rw-r--r--drivers/webp/dsp/rescaler_mips32.c291
-rw-r--r--drivers/webp/dsp/rescaler_mips_dsp_r2.c314
-rw-r--r--drivers/webp/dsp/rescaler_neon.c186
-rw-r--r--drivers/webp/dsp/rescaler_sse2.c373
-rw-r--r--drivers/webp/dsp/upsampling.c259
-rw-r--r--drivers/webp/dsp/upsampling_mips_dsp_r2.c282
-rw-r--r--drivers/webp/dsp/upsampling_neon.c261
-rw-r--r--drivers/webp/dsp/upsampling_sse2.c196
-rw-r--r--drivers/webp/dsp/yuv.c264
-rw-r--r--drivers/webp/dsp/yuv.h287
-rw-r--r--drivers/webp/dsp/yuv_mips32.c103
-rw-r--r--drivers/webp/dsp/yuv_mips_dsp_r2.c134
-rw-r--r--drivers/webp/dsp/yuv_sse2.c606
-rw-r--r--drivers/webp/dsp/yuv_tables_sse2.h536
-rw-r--r--drivers/webp/enc/alpha.c417
-rw-r--r--drivers/webp/enc/analysis.c361
-rw-r--r--drivers/webp/enc/backward_references.c1253
-rw-r--r--drivers/webp/enc/backward_references.h188
-rw-r--r--drivers/webp/enc/config.c69
-rw-r--r--drivers/webp/enc/cost.c672
-rw-r--r--drivers/webp/enc/cost.h36
-rw-r--r--drivers/webp/enc/delta_palettization.c455
-rw-r--r--drivers/webp/enc/delta_palettization.h25
-rw-r--r--drivers/webp/enc/filter.c332
-rw-r--r--drivers/webp/enc/frame.c987
-rw-r--r--drivers/webp/enc/histogram.c980
-rw-r--r--drivers/webp/enc/histogram.h87
-rw-r--r--drivers/webp/enc/iterator.c214
-rw-r--r--drivers/webp/enc/near_lossless.c160
-rw-r--r--drivers/webp/enc/picture.c1001
-rw-r--r--drivers/webp/enc/picture_csp.c1156
-rw-r--r--drivers/webp/enc/picture_psnr.c175
-rw-r--r--drivers/webp/enc/picture_rescale.c264
-rw-r--r--drivers/webp/enc/picture_tools.c206
-rw-r--r--drivers/webp/enc/quant.c811
-rw-r--r--drivers/webp/enc/syntax.c134
-rw-r--r--drivers/webp/enc/token.c285
-rw-r--r--drivers/webp/enc/tree.c30
-rw-r--r--drivers/webp/enc/vp8enci.h437
-rw-r--r--drivers/webp/enc/vp8l.c1367
-rw-r--r--drivers/webp/enc/vp8li.h23
-rw-r--r--drivers/webp/enc/webpenc.c266
-rw-r--r--drivers/webp/encode.h174
-rw-r--r--drivers/webp/extras.h51
-rw-r--r--drivers/webp/format_constants.h34
-rw-r--r--drivers/webp/image_loader_webp.cpp2
-rw-r--r--drivers/webp/image_loader_webp.h2
-rw-r--r--drivers/webp/mux.h760
-rw-r--r--drivers/webp/mux/anim_encode.c1404
-rw-r--r--drivers/webp/mux/muxedit.c740
-rw-r--r--drivers/webp/mux/muxi.h167
-rw-r--r--drivers/webp/mux/muxinternal.c331
-rw-r--r--drivers/webp/mux/muxread.c449
-rw-r--r--drivers/webp/mux_types.h97
-rw-r--r--drivers/webp/types.h21
-rw-r--r--drivers/webp/utils/bit_reader.c251
-rw-r--r--drivers/webp/utils/bit_reader.h238
-rw-r--r--drivers/webp/utils/bit_reader_inl.h172
-rw-r--r--drivers/webp/utils/bit_writer.c183
-rw-r--r--drivers/webp/utils/bit_writer.h106
-rw-r--r--drivers/webp/utils/color_cache.c25
-rw-r--r--drivers/webp/utils/color_cache.h30
-rw-r--r--drivers/webp/utils/endian_inl.h100
-rw-r--r--drivers/webp/utils/filters.c187
-rw-r--r--drivers/webp/utils/filters.h44
-rw-r--r--drivers/webp/utils/huffman.c337
-rw-r--r--drivers/webp/utils/huffman.h108
-rw-r--r--drivers/webp/utils/huffman_encode.c102
-rw-r--r--drivers/webp/utils/huffman_encode.h29
-rw-r--r--drivers/webp/utils/quant_levels.c24
-rw-r--r--drivers/webp/utils/quant_levels.h19
-rw-r--r--drivers/webp/utils/quant_levels_dec.c279
-rw-r--r--drivers/webp/utils/quant_levels_dec.h35
-rw-r--r--drivers/webp/utils/random.c43
-rw-r--r--drivers/webp/utils/random.h63
-rw-r--r--drivers/webp/utils/rescaler.c176
-rw-r--r--drivers/webp/utils/rescaler.h87
-rw-r--r--drivers/webp/utils/thread.c233
-rw-r--r--drivers/webp/utils/thread.h97
-rw-r--r--drivers/webp/utils/utils.c223
-rw-r--r--drivers/webp/utils/utils.h116
-rw-r--r--drivers/webpold/SCsub63
-rw-r--r--drivers/webpold/dec/alpha.c140
-rw-r--r--drivers/webpold/dec/buffer.c215
-rw-r--r--drivers/webpold/dec/decode_vp8.h182
-rw-r--r--drivers/webpold/dec/frame.c679
-rw-r--r--drivers/webpold/dec/idec.c785
-rw-r--r--drivers/webpold/dec/io.c633
-rw-r--r--drivers/webpold/dec/layer.c (renamed from drivers/webp/dec/layer.c)0
-rw-r--r--drivers/webpold/dec/quant.c113
-rw-r--r--drivers/webpold/dec/tree.c589
-rw-r--r--drivers/webpold/dec/vp8.c787
-rw-r--r--drivers/webpold/dec/vp8i.h335
-rw-r--r--drivers/webpold/dec/vp8l.c1200
-rw-r--r--drivers/webpold/dec/vp8li.h121
-rw-r--r--drivers/webpold/dec/webp.c771
-rw-r--r--drivers/webpold/dec/webpi.h114
-rw-r--r--drivers/webpold/decode.h454
-rw-r--r--drivers/webpold/dsp/cpu.c85
-rw-r--r--drivers/webpold/dsp/dec.c732
-rw-r--r--drivers/webpold/dsp/dec_neon.c329
-rw-r--r--drivers/webpold/dsp/dec_sse2.c903
-rw-r--r--drivers/webpold/dsp/dsp.h210
-rw-r--r--drivers/webpold/dsp/enc.c743
-rw-r--r--drivers/webpold/dsp/enc_sse2.c837
-rw-r--r--drivers/webpold/dsp/lossless.c1138
-rw-r--r--drivers/webpold/dsp/lossless.h82
-rw-r--r--drivers/webpold/dsp/upsampling.c357
-rw-r--r--drivers/webpold/dsp/upsampling_sse2.c209
-rw-r--r--drivers/webpold/dsp/yuv.c52
-rw-r--r--drivers/webpold/dsp/yuv.h128
-rw-r--r--drivers/webpold/enc/alpha.c330
-rw-r--r--drivers/webpold/enc/analysis.c364
-rw-r--r--drivers/webpold/enc/backward_references.c874
-rw-r--r--drivers/webpold/enc/backward_references.h212
-rw-r--r--drivers/webpold/enc/config.c132
-rw-r--r--drivers/webpold/enc/cost.c494
-rw-r--r--drivers/webpold/enc/cost.h48
-rw-r--r--drivers/webpold/enc/filter.c409
-rw-r--r--drivers/webpold/enc/frame.c939
-rw-r--r--drivers/webpold/enc/histogram.c406
-rw-r--r--drivers/webpold/enc/histogram.h115
-rw-r--r--drivers/webpold/enc/iterator.c422
-rw-r--r--drivers/webpold/enc/layer.c (renamed from drivers/webp/enc/layer.c)0
-rw-r--r--drivers/webpold/enc/picture.c1041
-rw-r--r--drivers/webpold/enc/quant.c930
-rw-r--r--drivers/webpold/enc/syntax.c437
-rw-r--r--drivers/webpold/enc/tree.c510
-rw-r--r--drivers/webpold/enc/vp8enci.h525
-rw-r--r--drivers/webpold/enc/vp8l.c1150
-rw-r--r--drivers/webpold/enc/vp8li.h68
-rw-r--r--drivers/webpold/enc/webpenc.c389
-rw-r--r--drivers/webpold/encode.h463
-rw-r--r--drivers/webpold/format_constants.h90
-rw-r--r--drivers/webpold/image_loader_webp.cpp165
-rw-r--r--drivers/webpold/image_loader_webp.h32
-rw-r--r--drivers/webpold/mux.h604
-rw-r--r--drivers/webpold/mux/demux.c (renamed from drivers/webp/mux/demux.c)0
-rw-r--r--drivers/webpold/mux/muxedit.c712
-rw-r--r--drivers/webpold/mux/muxi.h271
-rw-r--r--drivers/webpold/mux/muxinternal.c576
-rw-r--r--drivers/webpold/mux/muxread.c411
-rw-r--r--drivers/webpold/types.h45
-rw-r--r--drivers/webpold/utils/bit_reader.c229
-rw-r--r--drivers/webpold/utils/bit_reader.h198
-rw-r--r--drivers/webpold/utils/bit_writer.c284
-rw-r--r--drivers/webpold/utils/bit_writer.h123
-rw-r--r--drivers/webpold/utils/color_cache.c44
-rw-r--r--drivers/webpold/utils/color_cache.h68
-rw-r--r--drivers/webpold/utils/filters.c229
-rw-r--r--drivers/webpold/utils/filters.h54
-rw-r--r--drivers/webpold/utils/huffman.c238
-rw-r--r--drivers/webpold/utils/huffman.h78
-rw-r--r--drivers/webpold/utils/huffman_encode.c439
-rw-r--r--drivers/webpold/utils/huffman_encode.h47
-rw-r--r--drivers/webpold/utils/quant_levels.c154
-rw-r--r--drivers/webpold/utils/quant_levels.h39
-rw-r--r--drivers/webpold/utils/rescaler.c152
-rw-r--r--drivers/webpold/utils/rescaler.h76
-rw-r--r--drivers/webpold/utils/thread.c247
-rw-r--r--drivers/webpold/utils/thread.h86
-rw-r--r--drivers/webpold/utils/utils.c44
-rw-r--r--drivers/webpold/utils/utils.h44
-rw-r--r--drivers/windows/SCsub2
-rw-r--r--drivers/windows/dir_access_windows.cpp2
-rw-r--r--drivers/windows/dir_access_windows.h2
-rw-r--r--drivers/windows/file_access_windows.cpp4
-rw-r--r--drivers/windows/file_access_windows.h2
-rw-r--r--drivers/windows/mutex_windows.cpp2
-rw-r--r--drivers/windows/mutex_windows.h2
-rw-r--r--drivers/windows/semaphore_windows.cpp2
-rw-r--r--drivers/windows/semaphore_windows.h2
-rw-r--r--drivers/windows/shell_windows.cpp2
-rw-r--r--drivers/windows/shell_windows.h2
-rw-r--r--drivers/windows/thread_windows.cpp2
-rw-r--r--drivers/windows/thread_windows.h2
-rw-r--r--godot_icon.pngbin0 -> 12574 bytes
-rw-r--r--godot_icon.svg133
-rw-r--r--logo_small.pngbin2025 -> 0 bytes
-rw-r--r--main/SCsub2
-rw-r--r--main/input_default.cpp829
-rw-r--r--main/input_default.h176
-rw-r--r--main/main.cpp332
-rw-r--r--main/main.h2
-rw-r--r--main/performance.cpp2
-rw-r--r--main/performance.h2
-rw-r--r--main/splash.h4
-rw-r--r--makerel.bat1
-rwxr-xr-xmethods.py39
-rw-r--r--modules/SCsub2
-rw-r--r--modules/gdscript/SCsub2
-rw-r--r--modules/gdscript/gd_compiler.cpp42
-rw-r--r--modules/gdscript/gd_compiler.h4
-rw-r--r--modules/gdscript/gd_editor.cpp697
-rw-r--r--modules/gdscript/gd_functions.cpp138
-rw-r--r--modules/gdscript/gd_functions.h5
-rw-r--r--modules/gdscript/gd_parser.cpp352
-rw-r--r--modules/gdscript/gd_parser.h14
-rw-r--r--modules/gdscript/gd_pretty_print.cpp2
-rw-r--r--modules/gdscript/gd_pretty_print.h2
-rw-r--r--modules/gdscript/gd_script.cpp126
-rw-r--r--modules/gdscript/gd_script.h28
-rw-r--r--modules/gdscript/gd_tokenizer.cpp57
-rw-r--r--modules/gdscript/gd_tokenizer.h5
-rw-r--r--modules/gdscript/register_types.cpp2
-rw-r--r--modules/gdscript/register_types.h2
-rw-r--r--modules/gridmap/SCsub3
-rw-r--r--modules/gridmap/grid_map.cpp83
-rw-r--r--modules/gridmap/grid_map.h4
-rw-r--r--modules/gridmap/grid_map_editor_plugin.cpp26
-rw-r--r--modules/gridmap/grid_map_editor_plugin.h9
-rw-r--r--modules/gridmap/register_types.cpp2
-rw-r--r--modules/gridmap/register_types.h2
-rw-r--r--platform/android/AndroidManifest.xml.template8
-rw-r--r--platform/android/SCsub63
-rw-r--r--platform/android/android_native_app_glue.h2
-rw-r--r--platform/android/audio_driver_jandroid.cpp6
-rw-r--r--platform/android/audio_driver_jandroid.h2
-rw-r--r--platform/android/audio_driver_opensl.cpp5
-rw-r--r--platform/android/audio_driver_opensl.h2
-rw-r--r--platform/android/build.gradle.template70
-rw-r--r--platform/android/cpu-features.c2
-rw-r--r--platform/android/detect.py146
-rw-r--r--platform/android/dir_access_android.cpp2
-rw-r--r--platform/android/dir_access_android.h2
-rw-r--r--platform/android/dir_access_jandroid.cpp6
-rw-r--r--platform/android/dir_access_jandroid.h2
-rw-r--r--platform/android/export/export.cpp72
-rw-r--r--platform/android/file_access_android.cpp21
-rw-r--r--platform/android/file_access_android.h12
-rw-r--r--platform/android/file_access_jandroid.cpp6
-rw-r--r--platform/android/file_access_jandroid.h2
-rw-r--r--platform/android/godot_android.cpp24
-rw-r--r--platform/android/java/aidl/com/android/vending/billing/IInAppBillingService.aidl144
-rw-r--r--platform/android/java/ant.properties17
-rw-r--r--platform/android/java/build.properties17
-rw-r--r--platform/android/java/build.xml92
-rw-r--r--platform/android/java/default.properties11
-rw-r--r--platform/android/java/gradle/wrapper/gradle-wrapper.jarbin0 -> 49896 bytes
-rw-r--r--platform/android/java/gradle/wrapper/gradle-wrapper.properties6
-rwxr-xr-xplatform/android/java/gradlew164
-rw-r--r--platform/android/java/gradlew.bat90
-rw-r--r--platform/android/java/my-release-key.keystorebin2218 -> 0 bytes
-rw-r--r--platform/android/java/proguard-project.txt20
-rw-r--r--platform/android/java/proguard.cfg36
-rw-r--r--platform/android/java/res/drawable-hdpi/notify_panel_notification_icon_bg.png (renamed from platform/android/libs/apk_expansion/res/drawable-hdpi/notify_panel_notification_icon_bg.png)bin1027 -> 1027 bytes
-rw-r--r--platform/android/java/res/drawable-mdpi/notify_panel_notification_icon_bg.png (renamed from platform/android/libs/apk_expansion/res/drawable-mdpi/notify_panel_notification_icon_bg.png)bin1125 -> 1125 bytes
-rw-r--r--platform/android/java/res/drawable/icon.pngbin17135 -> 12574 bytes
-rw-r--r--platform/android/java/res/layout/status_bar_ongoing_event_progress_bar.xml (renamed from platform/android/libs/apk_expansion/res/layout/status_bar_ongoing_event_progress_bar.xml)0
-rw-r--r--platform/android/java/res/values-fa/strings.xml16
-rw-r--r--platform/android/java/res/values-v11/styles.xml (renamed from platform/android/libs/apk_expansion/res/values-v11/styles.xml)0
-rw-r--r--platform/android/java/res/values-v9/styles.xml (renamed from platform/android/libs/apk_expansion/res/values-v9/styles.xml)0
-rw-r--r--platform/android/java/res/values/strings.xml42
-rw-r--r--platform/android/java/res/values/styles.xml (renamed from platform/android/libs/apk_expansion/res/values/styles.xml)0
-rw-r--r--platform/android/java/src/com/android/godot/Dictionary.java80
-rw-r--r--platform/android/java/src/com/android/godot/Godot.java925
-rw-r--r--platform/android/java/src/com/android/godot/GodotDownloaderAlarmReceiver.java30
-rw-r--r--platform/android/java/src/com/android/godot/GodotDownloaderService.java56
-rw-r--r--platform/android/java/src/com/android/godot/GodotIO.java672
-rw-r--r--platform/android/java/src/com/android/godot/GodotLib.java66
-rw-r--r--platform/android/java/src/com/android/godot/GodotPaymentV3.java128
-rw-r--r--platform/android/java/src/com/android/godot/GodotView.java641
-rw-r--r--platform/android/java/src/com/android/godot/input/GodotEditText.java133
-rw-r--r--platform/android/java/src/com/android/godot/input/GodotTextInputWrapper.java154
-rw-r--r--platform/android/java/src/com/android/godot/payments/ConsumeTask.java71
-rw-r--r--platform/android/java/src/com/android/godot/payments/GenericConsumeTask.java53
-rw-r--r--platform/android/java/src/com/android/godot/payments/HandlePurchaseTask.java82
-rw-r--r--platform/android/java/src/com/android/godot/payments/PaymentsCache.java45
-rw-r--r--platform/android/java/src/com/android/godot/payments/PaymentsManager.java201
-rw-r--r--platform/android/java/src/com/android/godot/payments/PurchaseTask.java97
-rw-r--r--platform/android/java/src/com/android/godot/payments/ReleaseAllConsumablesTask.java87
-rw-r--r--platform/android/java/src/com/android/godot/payments/ValidateTask.java97
-rw-r--r--platform/android/java/src/com/android/godot/utils/Crypt.java39
-rw-r--r--platform/android/java/src/com/android/godot/utils/CustomSSLSocketFactory.java54
-rw-r--r--platform/android/java/src/com/android/godot/utils/HttpRequester.java206
-rw-r--r--platform/android/java/src/com/android/godot/utils/RequestParams.java58
-rw-r--r--platform/android/java/src/com/android/vending/licensing/AESObfuscator.java (renamed from platform/android/libs/play_licensing/src/com/google/android/vending/licensing/AESObfuscator.java)0
-rw-r--r--platform/android/java/src/com/android/vending/licensing/APKExpansionPolicy.java (renamed from platform/android/libs/play_licensing/src/com/google/android/vending/licensing/APKExpansionPolicy.java)0
-rw-r--r--platform/android/java/src/com/android/vending/licensing/DeviceLimiter.java (renamed from platform/android/libs/play_licensing/src/com/google/android/vending/licensing/DeviceLimiter.java)0
-rw-r--r--platform/android/java/src/com/android/vending/licensing/ILicenseResultListener.aidl (renamed from platform/android/libs/play_licensing/aidl/ILicenseResultListener.aidl)0
-rw-r--r--platform/android/java/src/com/android/vending/licensing/ILicenseResultListener.java (renamed from platform/android/libs/play_licensing/src/com/google/android/vending/licensing/ILicenseResultListener.java)0
-rw-r--r--platform/android/java/src/com/android/vending/licensing/ILicensingService.aidl (renamed from platform/android/libs/play_licensing/aidl/ILicensingService.aidl)0
-rw-r--r--platform/android/java/src/com/android/vending/licensing/ILicensingService.java (renamed from platform/android/libs/play_licensing/src/com/google/android/vending/licensing/ILicensingService.java)0
-rw-r--r--platform/android/java/src/com/android/vending/licensing/LicenseChecker.java351
-rw-r--r--platform/android/java/src/com/android/vending/licensing/LicenseCheckerCallback.java (renamed from platform/android/libs/play_licensing/src/com/google/android/vending/licensing/LicenseCheckerCallback.java)0
-rw-r--r--platform/android/java/src/com/android/vending/licensing/LicenseValidator.java (renamed from platform/android/libs/play_licensing/src/com/google/android/vending/licensing/LicenseValidator.java)0
-rw-r--r--platform/android/java/src/com/android/vending/licensing/NullDeviceLimiter.java (renamed from platform/android/libs/play_licensing/src/com/google/android/vending/licensing/NullDeviceLimiter.java)0
-rw-r--r--platform/android/java/src/com/android/vending/licensing/Obfuscator.java (renamed from platform/android/libs/play_licensing/src/com/google/android/vending/licensing/Obfuscator.java)0
-rw-r--r--platform/android/java/src/com/android/vending/licensing/Policy.java (renamed from platform/android/libs/play_licensing/src/com/google/android/vending/licensing/Policy.java)0
-rw-r--r--platform/android/java/src/com/android/vending/licensing/PreferenceObfuscator.java (renamed from platform/android/libs/play_licensing/src/com/google/android/vending/licensing/PreferenceObfuscator.java)0
-rw-r--r--platform/android/java/src/com/android/vending/licensing/ResponseData.java (renamed from platform/android/libs/play_licensing/src/com/google/android/vending/licensing/ResponseData.java)0
-rw-r--r--platform/android/java/src/com/android/vending/licensing/ServerManagedPolicy.java (renamed from platform/android/libs/play_licensing/src/com/google/android/vending/licensing/ServerManagedPolicy.java)0
-rw-r--r--platform/android/java/src/com/android/vending/licensing/StrictPolicy.java (renamed from platform/android/libs/play_licensing/src/com/google/android/vending/licensing/StrictPolicy.java)0
-rw-r--r--platform/android/java/src/com/android/vending/licensing/ValidationException.java (renamed from platform/android/libs/play_licensing/src/com/google/android/vending/licensing/ValidationException.java)0
-rw-r--r--platform/android/java/src/com/android/vending/licensing/util/Base64.java (renamed from platform/android/libs/play_licensing/src/com/google/android/vending/licensing/util/Base64.java)0
-rw-r--r--platform/android/java/src/com/android/vending/licensing/util/Base64DecoderException.java (renamed from platform/android/libs/play_licensing/src/com/google/android/vending/licensing/util/Base64DecoderException.java)0
-rw-r--r--platform/android/java/src/com/google/android/vending/expansion/downloader/Constants.java (renamed from platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/Constants.java)0
-rw-r--r--platform/android/java/src/com/google/android/vending/expansion/downloader/DownloadProgressInfo.java (renamed from platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/DownloadProgressInfo.java)0
-rw-r--r--platform/android/java/src/com/google/android/vending/expansion/downloader/DownloaderClientMarshaller.java (renamed from platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/DownloaderClientMarshaller.java)0
-rw-r--r--platform/android/java/src/com/google/android/vending/expansion/downloader/DownloaderServiceMarshaller.java (renamed from platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/DownloaderServiceMarshaller.java)0
-rw-r--r--platform/android/java/src/com/google/android/vending/expansion/downloader/Helpers.java306
-rw-r--r--platform/android/java/src/com/google/android/vending/expansion/downloader/IDownloaderClient.java (renamed from platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/IDownloaderClient.java)0
-rw-r--r--platform/android/java/src/com/google/android/vending/expansion/downloader/IDownloaderService.java (renamed from platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/IDownloaderService.java)0
-rw-r--r--platform/android/java/src/com/google/android/vending/expansion/downloader/IStub.java (renamed from platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/IStub.java)0
-rw-r--r--platform/android/java/src/com/google/android/vending/expansion/downloader/SystemFacade.java (renamed from platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/SystemFacade.java)0
-rw-r--r--platform/android/java/src/com/google/android/vending/expansion/downloader/impl/AndroidHttpClient.java (renamed from platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/AndroidHttpClient.java)0
-rwxr-xr-xplatform/android/java/src/com/google/android/vending/expansion/downloader/impl/CustomIntentService.java (renamed from platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/CustomIntentService.java)0
-rw-r--r--platform/android/java/src/com/google/android/vending/expansion/downloader/impl/CustomNotificationFactory.java (renamed from platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/CustomNotificationFactory.java)0
-rw-r--r--platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadInfo.java (renamed from platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/DownloadInfo.java)0
-rw-r--r--platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java231
-rw-r--r--platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadThread.java (renamed from platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/DownloadThread.java)0
-rw-r--r--platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloaderService.java (renamed from platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/DownloaderService.java)0
-rwxr-xr-xplatform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadsDB.java (renamed from platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/DownloadsDB.java)0
-rw-r--r--platform/android/java/src/com/google/android/vending/expansion/downloader/impl/HttpDateTime.java (renamed from platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/HttpDateTime.java)0
-rw-r--r--platform/android/java/src/com/google/android/vending/expansion/downloader/impl/V14CustomNotification.java101
-rw-r--r--platform/android/java/src/com/google/android/vending/expansion/downloader/impl/V3CustomNotification.java116
-rw-r--r--platform/android/java/src/org/godotengine/godot/Dictionary.java80
-rw-r--r--platform/android/java/src/org/godotengine/godot/Godot.java938
-rw-r--r--platform/android/java/src/org/godotengine/godot/GodotDownloaderAlarmReceiver.java30
-rw-r--r--platform/android/java/src/org/godotengine/godot/GodotDownloaderService.java56
-rw-r--r--platform/android/java/src/org/godotengine/godot/GodotIO.java673
-rw-r--r--platform/android/java/src/org/godotengine/godot/GodotLib.java66
-rw-r--r--platform/android/java/src/org/godotengine/godot/GodotPaymentV3.java154
-rw-r--r--platform/android/java/src/org/godotengine/godot/GodotView.java661
-rw-r--r--platform/android/java/src/org/godotengine/godot/input/GodotEditText.java133
-rw-r--r--platform/android/java/src/org/godotengine/godot/input/GodotTextInputWrapper.java154
-rw-r--r--platform/android/java/src/org/godotengine/godot/payments/ConsumeTask.java71
-rw-r--r--platform/android/java/src/org/godotengine/godot/payments/GenericConsumeTask.java53
-rw-r--r--platform/android/java/src/org/godotengine/godot/payments/HandlePurchaseTask.java82
-rw-r--r--platform/android/java/src/org/godotengine/godot/payments/PaymentsCache.java45
-rw-r--r--platform/android/java/src/org/godotengine/godot/payments/PaymentsManager.java282
-rw-r--r--platform/android/java/src/org/godotengine/godot/payments/PurchaseTask.java101
-rw-r--r--platform/android/java/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java87
-rw-r--r--platform/android/java/src/org/godotengine/godot/payments/ValidateTask.java97
-rw-r--r--platform/android/java/src/org/godotengine/godot/utils/Crypt.java39
-rw-r--r--platform/android/java/src/org/godotengine/godot/utils/CustomSSLSocketFactory.java54
-rw-r--r--platform/android/java/src/org/godotengine/godot/utils/HttpRequester.java206
-rw-r--r--platform/android/java/src/org/godotengine/godot/utils/RequestParams.java58
-rw-r--r--platform/android/java_class_wrapper.cpp2
-rw-r--r--platform/android/java_glue.cpp84
-rw-r--r--platform/android/java_glue.h38
-rw-r--r--platform/android/libs/apk_expansion/AndroidManifest.xml9
-rw-r--r--platform/android/libs/apk_expansion/build.xml92
-rw-r--r--platform/android/libs/apk_expansion/proguard-project.txt20
-rw-r--r--platform/android/libs/apk_expansion/project.properties13
-rw-r--r--platform/android/libs/apk_expansion/res/values/strings.xml41
-rw-r--r--platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/Helpers.java306
-rw-r--r--platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java231
-rw-r--r--platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/V14CustomNotification.java101
-rw-r--r--platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/V3CustomNotification.java116
-rw-r--r--platform/android/libs/downloader_library/.classpath9
-rw-r--r--platform/android/libs/downloader_library/.settings/org.eclipse.jdt.core.prefs4
-rw-r--r--platform/android/libs/downloader_library/AndroidManifest.xml9
-rw-r--r--platform/android/libs/downloader_library/build.xml92
-rw-r--r--platform/android/libs/downloader_library/gen/com/android/vending/expansion/downloader/BuildConfig.java6
-rw-r--r--platform/android/libs/downloader_library/gen/com/android/vending/expansion/downloader/R.java73
-rw-r--r--platform/android/libs/downloader_library/proguard-project.txt20
-rw-r--r--platform/android/libs/downloader_library/project.properties13
-rw-r--r--platform/android/libs/downloader_library/res/drawable-hdpi/notify_panel_notification_icon_bg.pngbin1027 -> 0 bytes
-rw-r--r--platform/android/libs/downloader_library/res/drawable-mdpi/notify_panel_notification_icon_bg.pngbin1125 -> 0 bytes
-rw-r--r--platform/android/libs/downloader_library/res/layout/status_bar_ongoing_event_progress_bar.xml104
-rw-r--r--platform/android/libs/downloader_library/res/values-v11/styles.xml6
-rw-r--r--platform/android/libs/downloader_library/res/values-v9/styles.xml5
-rw-r--r--platform/android/libs/downloader_library/res/values/strings.xml41
-rw-r--r--platform/android/libs/downloader_library/res/values/styles.xml25
-rw-r--r--platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/Constants.java236
-rw-r--r--platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/DownloadProgressInfo.java80
-rw-r--r--platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/DownloaderClientMarshaller.java277
-rw-r--r--platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/DownloaderServiceMarshaller.java181
-rw-r--r--platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/Helpers.java306
-rw-r--r--platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/IDownloaderClient.java126
-rw-r--r--platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/IDownloaderService.java83
-rw-r--r--platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/IStub.java41
-rw-r--r--platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/SystemFacade.java123
-rw-r--r--platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/AndroidHttpClient.java536
-rwxr-xr-xplatform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/CustomIntentService.java112
-rw-r--r--platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/CustomNotificationFactory.java30
-rw-r--r--platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/DownloadInfo.java92
-rw-r--r--platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java231
-rw-r--r--platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/DownloadThread.java963
-rw-r--r--platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/DownloaderService.java1341
-rwxr-xr-xplatform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/DownloadsDB.java510
-rw-r--r--platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/HttpDateTime.java200
-rw-r--r--platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/V14CustomNotification.java101
-rw-r--r--platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/V3CustomNotification.java116
-rw-r--r--platform/android/libs/google_play_services/.classpath9
-rw-r--r--platform/android/libs/google_play_services/AndroidManifest.xml9
-rw-r--r--platform/android/libs/google_play_services/README.txt17
-rw-r--r--platform/android/libs/google_play_services/build.xml92
-rw-r--r--platform/android/libs/google_play_services/libs/google-play-services.jarbin1881748 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/libs/google-play-services.jar.properties1
-rw-r--r--platform/android/libs/google_play_services/proguard-project.txt20
-rw-r--r--platform/android/libs/google_play_services/proguard.txt20
-rw-r--r--platform/android/libs/google_play_services/project.properties15
-rw-r--r--platform/android/libs/google_play_services/res/color/common_signin_btn_text_dark.xml18
-rw-r--r--platform/android/libs/google_play_services/res/color/common_signin_btn_text_light.xml18
-rw-r--r--platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_disabled_dark.9.pngbin1811 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_disabled_focus_dark.9.pngbin1846 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_disabled_focus_light.9.pngbin1846 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_disabled_light.9.pngbin1811 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_focus_dark.9.pngbin2100 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_focus_light.9.pngbin2075 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_normal_dark.9.pngbin2050 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_normal_light.9.pngbin2049 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_pressed_dark.9.pngbin2224 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_pressed_light.9.pngbin2331 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_disabled_dark.9.pngbin1927 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_disabled_focus_dark.9.pngbin1957 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_disabled_focus_light.9.pngbin1957 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_disabled_light.9.pngbin1927 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_focus_dark.9.pngbin2206 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_focus_light.9.pngbin2182 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_normal_dark.9.pngbin2185 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_normal_light.9.pngbin2158 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_pressed_dark.9.pngbin2374 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_pressed_light.9.pngbin2483 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-hdpi/ic_plusone_medium_off_client.pngbin1187 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-hdpi/ic_plusone_small_off_client.pngbin841 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-hdpi/ic_plusone_standard_off_client.pngbin1498 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-hdpi/ic_plusone_tall_off_client.pngbin1140 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_disabled_dark.9.pngbin1202 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_disabled_focus_dark.9.pngbin1236 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_disabled_focus_light.9.pngbin1236 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_disabled_light.9.pngbin1202 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_focus_dark.9.pngbin1389 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_focus_light.9.pngbin1362 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_normal_dark.9.pngbin1369 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_normal_light.9.pngbin1345 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_pressed_dark.9.pngbin1465 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_pressed_light.9.pngbin1521 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_disabled_dark.9.pngbin1309 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_disabled_focus_dark.9.pngbin1316 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_disabled_focus_light.9.pngbin1316 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_disabled_light.9.pngbin1309 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_focus_dark.9.pngbin1461 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_focus_light.9.pngbin1463 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_normal_dark.9.pngbin1463 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_normal_light.9.pngbin1455 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_pressed_dark.9.pngbin1556 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_pressed_light.9.pngbin1623 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-mdpi/ic_plusone_medium_off_client.pngbin751 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-mdpi/ic_plusone_small_off_client.pngbin581 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-mdpi/ic_plusone_standard_off_client.pngbin996 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-mdpi/ic_plusone_tall_off_client.pngbin789 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_disabled_dark.9.pngbin2438 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_disabled_focus_dark.9.pngbin2457 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_disabled_focus_light.9.pngbin2457 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_disabled_light.9.pngbin2438 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_focus_dark.9.pngbin2886 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_focus_light.9.pngbin2908 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_normal_dark.9.pngbin2847 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_normal_light.9.pngbin2888 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_pressed_dark.9.pngbin3133 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_pressed_light.9.pngbin3301 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_disabled_dark.9.pngbin2569 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_disabled_focus_dark.9.pngbin2571 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_disabled_focus_light.9.pngbin2571 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_disabled_light.9.pngbin2569 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_focus_dark.9.pngbin2939 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_focus_light.9.pngbin2947 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_normal_dark.9.pngbin2931 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_normal_light.9.pngbin2944 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_pressed_dark.9.pngbin3255 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_pressed_light.9.pngbin3384 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xhdpi/ic_plusone_medium_off_client.pngbin1598 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xhdpi/ic_plusone_small_off_client.pngbin1205 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xhdpi/ic_plusone_standard_off_client.pngbin2074 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xhdpi/ic_plusone_tall_off_client.pngbin1741 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_disabled_dark.9.pngbin4988 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_disabled_focus_dark.9.pngbin5092 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_disabled_focus_light.9.pngbin5092 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_disabled_light.9.pngbin4988 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_focus_dark.9.pngbin6558 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_focus_light.9.pngbin6216 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_normal_dark.9.pngbin6530 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_normal_light.9.pngbin6234 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_pressed_dark.9.pngbin7015 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_pressed_light.9.pngbin7352 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_disabled_dark.9.pngbin5637 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_disabled_focus_dark.9.pngbin5572 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_disabled_focus_light.9.pngbin5572 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_disabled_light.9.pngbin5637 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_focus_dark.9.pngbin6958 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_focus_light.9.pngbin6647 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_normal_dark.9.pngbin6975 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_normal_light.9.pngbin6713 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_pressed_dark.9.pngbin7569 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_pressed_light.9.pngbin7944 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xxhdpi/ic_plusone_medium_off_client.pngbin5828 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xxhdpi/ic_plusone_small_off_client.pngbin4279 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xxhdpi/ic_plusone_standard_off_client.pngbin7439 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable-xxhdpi/ic_plusone_tall_off_client.pngbin6204 -> 0 bytes
-rw-r--r--platform/android/libs/google_play_services/res/drawable/common_signin_btn_icon_dark.xml18
-rw-r--r--platform/android/libs/google_play_services/res/drawable/common_signin_btn_icon_light.xml18
-rw-r--r--platform/android/libs/google_play_services/res/drawable/common_signin_btn_text_dark.xml18
-rw-r--r--platform/android/libs/google_play_services/res/drawable/common_signin_btn_text_light.xml18
-rw-r--r--platform/android/libs/google_play_services/res/values-af/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-am/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-ar/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-be/strings.xml36
-rw-r--r--platform/android/libs/google_play_services/res/values-bg/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-ca/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-cs/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-da/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-de/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-el/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-en-rGB/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-en-rIN/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-es-rUS/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-es/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-et-rEE/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-fa/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-fi/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-fr-rCA/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-fr/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-hi/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-hr/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-hu/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-hy-rAM/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-in/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-it/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-iw/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-ja/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-ka-rGE/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-km-rKH/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-ko/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-lo-rLA/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-lt/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-lv/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-mn-rMN/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-ms-rMY/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-nb/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-nl/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-pl/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-pt-rBR/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-pt-rPT/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-pt/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-ro/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-ru/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-sk/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-sl/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-sr/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-sv/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-sw/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-th/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-tl/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-tr/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-uk/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-vi/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-zh-rCN/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-zh-rHK/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-zh-rTW/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values-zu/strings.xml31
-rw-r--r--platform/android/libs/google_play_services/res/values/ads_attrs.xml22
-rw-r--r--platform/android/libs/google_play_services/res/values/colors.xml14
-rw-r--r--platform/android/libs/google_play_services/res/values/maps_attrs.xml26
-rw-r--r--platform/android/libs/google_play_services/res/values/strings.xml111
-rw-r--r--platform/android/libs/google_play_services/res/values/version.xml4
-rw-r--r--platform/android/libs/google_play_services/src/android/UnusedStub.java21
-rw-r--r--platform/android/libs/play_licensing/AndroidManifest.xml24
-rw-r--r--platform/android/libs/play_licensing/build.xml92
-rw-r--r--platform/android/libs/play_licensing/proguard-project.txt20
-rw-r--r--platform/android/libs/play_licensing/project.properties12
-rw-r--r--platform/android/libs/play_licensing/src/com/google/android/vending/licensing/LicenseChecker.java351
-rw-r--r--platform/android/os_android.cpp32
-rw-r--r--platform/android/os_android.h16
-rw-r--r--platform/android/platform_config.h2
-rw-r--r--platform/android/project.properties.template15
-rw-r--r--platform/android/thread_jandroid.cpp2
-rw-r--r--platform/android/thread_jandroid.h2
-rw-r--r--platform/bb10/SCsub1
-rw-r--r--platform/bb10/audio_driver_bb10.cpp3
-rw-r--r--platform/bb10/audio_driver_bb10.h2
-rw-r--r--platform/bb10/bbutil.h2
-rw-r--r--platform/bb10/export/export.cpp26
-rw-r--r--platform/bb10/godot_bb10.cpp2
-rw-r--r--platform/bb10/os_bb10.cpp5
-rw-r--r--platform/bb10/os_bb10.h2
-rw-r--r--platform/bb10/payment_service.cpp2
-rw-r--r--platform/bb10/payment_service.h2
-rw-r--r--platform/bb10/platform_config.h2
-rw-r--r--platform/flash/SCsub2
-rw-r--r--platform/flash/detect.py3
-rw-r--r--platform/flash/dir_access_flash.cpp2
-rw-r--r--platform/flash/dir_access_flash.h2
-rw-r--r--platform/flash/os_flash.h175
-rw-r--r--platform/flash/rasterizer_flash.cpp2
-rw-r--r--platform/flash/rasterizer_flash.h4
-rw-r--r--platform/haiku/SCsub25
-rw-r--r--platform/haiku/audio_driver_media_kit.cpp142
-rw-r--r--platform/haiku/audio_driver_media_kit.h72
-rw-r--r--platform/haiku/context_gl_haiku.cpp43
-rw-r--r--platform/haiku/context_gl_haiku.h29
-rw-r--r--platform/haiku/detect.py62
-rw-r--r--platform/haiku/godot.rdef60
-rw-r--r--platform/haiku/godot_haiku.cpp19
-rw-r--r--platform/haiku/haiku_application.cpp7
-rw-r--r--platform/haiku/haiku_application.h13
-rw-r--r--platform/haiku/haiku_direct_window.cpp342
-rw-r--r--platform/haiku/haiku_direct_window.h60
-rw-r--r--platform/haiku/haiku_gl_view.cpp18
-rw-r--r--platform/haiku/haiku_gl_view.h15
-rw-r--r--platform/haiku/key_mapping_haiku.cpp193
-rw-r--r--platform/haiku/key_mapping_haiku.h13
-rw-r--r--platform/haiku/logo.pngbin0 -> 1361 bytes
-rw-r--r--platform/haiku/os_haiku.cpp321
-rw-r--r--platform/haiku/os_haiku.h99
-rw-r--r--platform/haiku/platform_config.h6
-rw-r--r--platform/iphone/Appirater.h2
-rw-r--r--platform/iphone/SCsub3
-rw-r--r--platform/iphone/app_delegate.h2
-rw-r--r--platform/iphone/app_delegate.mm80
-rw-r--r--platform/iphone/audio_driver_iphone.cpp2
-rw-r--r--platform/iphone/audio_driver_iphone.h2
-rw-r--r--platform/iphone/detect.py39
-rw-r--r--platform/iphone/game_center.h2
-rw-r--r--platform/iphone/game_center.mm12
-rwxr-xr-xplatform/iphone/gl_view.h11
-rwxr-xr-xplatform/iphone/gl_view.mm89
-rwxr-xr-x[-rw-r--r--]platform/iphone/globals/global_defaults.cpp1
-rw-r--r--platform/iphone/godot_iphone.cpp4
-rw-r--r--platform/iphone/icloud.h66
-rw-r--r--platform/iphone/icloud.mm385
-rw-r--r--platform/iphone/in_app_store.h2
-rw-r--r--platform/iphone/in_app_store.mm11
-rw-r--r--platform/iphone/os_iphone.cpp19
-rw-r--r--platform/iphone/os_iphone.h10
-rw-r--r--platform/iphone/platform_config.h4
-rw-r--r--platform/iphone/rasterizer_iphone.cpp2
-rw-r--r--platform/iphone/rasterizer_iphone.h2
-rw-r--r--platform/iphone/sem_iphone.cpp7
-rw-r--r--platform/iphone/sem_iphone.h2
-rw-r--r--platform/iphone/view_controller.h2
-rw-r--r--platform/iphone/view_controller.mm7
-rw-r--r--platform/isim/detect.py15
-rw-r--r--platform/javascript/SCsub5
-rw-r--r--platform/javascript/audio_driver_javascript.cpp2
-rw-r--r--platform/javascript/audio_driver_javascript.h2
-rw-r--r--platform/javascript/audio_server_javascript.cpp805
-rw-r--r--platform/javascript/audio_server_javascript.h198
-rw-r--r--platform/javascript/detect.py13
-rw-r--r--platform/javascript/export/export.cpp65
-rw-r--r--platform/javascript/export/export.h2
-rw-r--r--platform/javascript/javascript_main.cpp59
-rw-r--r--platform/javascript/os_javascript.cpp55
-rw-r--r--platform/javascript/os_javascript.h16
-rw-r--r--platform/javascript/platform_config.h2
-rw-r--r--platform/nacl/audio_driver_nacl.cpp2
-rw-r--r--platform/nacl/audio_driver_nacl.h2
-rw-r--r--platform/nacl/context_gl_nacl.cpp2
-rw-r--r--platform/nacl/context_gl_nacl.h2
-rw-r--r--platform/nacl/geturl_handler.cpp2
-rw-r--r--platform/nacl/geturl_handler.h2
-rw-r--r--platform/nacl/godot_module.cpp2
-rw-r--r--platform/nacl/godot_nacl.cpp2
-rw-r--r--platform/nacl/html/icon_128.pngbin2255 -> 11146 bytes
-rw-r--r--platform/nacl/html/icon_16.pngbin850 -> 828 bytes
-rw-r--r--platform/nacl/nacl_keycodes.h2
-rw-r--r--platform/nacl/opengl_context.cpp2
-rw-r--r--platform/nacl/opengl_context.h2
-rw-r--r--platform/nacl/os_nacl.cpp5
-rw-r--r--platform/nacl/os_nacl.h2
-rw-r--r--platform/nacl/pepper_main.cpp2
-rw-r--r--platform/nacl/platform_config.h2
-rw-r--r--platform/osx/SCsub1
-rw-r--r--platform/osx/audio_driver_osx.cpp2
-rw-r--r--platform/osx/audio_driver_osx.h2
-rw-r--r--platform/osx/context_gl_osx.cpp2
-rw-r--r--platform/osx/context_gl_osx.h2
-rw-r--r--platform/osx/detect.py39
-rw-r--r--platform/osx/dir_access_osx.h92
-rw-r--r--platform/osx/dir_access_osx.mm350
-rw-r--r--platform/osx/export/export.cpp31
-rw-r--r--platform/osx/godot_main_osx.mm2
-rw-r--r--platform/osx/godot_osx.h2
-rw-r--r--platform/osx/godot_osx.mm2
-rw-r--r--platform/osx/os_osx.h8
-rw-r--r--platform/osx/os_osx.mm58
-rw-r--r--platform/osx/platform_config.h3
-rw-r--r--platform/osx/sem_osx.cpp2
-rw-r--r--platform/osx/sem_osx.h2
-rw-r--r--platform/server/godot_server.cpp2
-rw-r--r--platform/server/os_server.cpp5
-rw-r--r--platform/server/os_server.h4
-rw-r--r--platform/server/platform_config.h2
-rw-r--r--platform/windows/SCsub11
-rw-r--r--platform/windows/context_gl_win.cpp2
-rw-r--r--platform/windows/context_gl_win.h2
-rw-r--r--platform/windows/ctxgl_procaddr.cpp2
-rw-r--r--platform/windows/ctxgl_procaddr.h2
-rw-r--r--platform/windows/detect.py779
-rw-r--r--platform/windows/export/export.cpp343
-rw-r--r--platform/windows/export/export.h34
-rw-r--r--platform/windows/godot.icobin0 -> 370070 bytes
-rw-r--r--platform/windows/godot_res.rc33
-rw-r--r--platform/windows/godot_win.cpp2
-rw-r--r--platform/windows/joystick.cpp536
-rw-r--r--platform/windows/joystick.h142
-rw-r--r--platform/windows/key_mapping_win.cpp2
-rw-r--r--platform/windows/key_mapping_win.h2
-rw-r--r--platform/windows/lang_table.h2
-rw-r--r--platform/windows/os_windows.cpp412
-rw-r--r--platform/windows/os_windows.h50
-rw-r--r--platform/windows/packet_peer_udp_winsock.cpp21
-rw-r--r--platform/windows/platform_config.h2
-rw-r--r--platform/windows/stream_peer_winsock.cpp10
-rw-r--r--platform/windows/stream_peer_winsock.h4
-rw-r--r--platform/windows/tcp_server_winsock.cpp9
-rw-r--r--platform/windows/tcp_server_winsock.h2
-rw-r--r--platform/winrt/app.cpp770
-rw-r--r--platform/winrt/app.h122
-rw-r--r--platform/winrt/detect.py312
-rw-r--r--platform/winrt/include/EGL/egl.h596
-rw-r--r--platform/winrt/include/EGL/eglext.h1532
-rw-r--r--platform/winrt/include/EGL/eglplatform.h262
-rw-r--r--platform/winrt/include/GLES2/gl2.h1240
-rw-r--r--platform/winrt/include/GLES2/gl2ext.h4026
-rw-r--r--platform/winrt/include/GLES2/gl2platform.h60
-rw-r--r--platform/winrt/include/GLES3/gl3.h2122
-rw-r--r--platform/winrt/include/GLES3/gl3ext.h48
-rw-r--r--platform/winrt/include/GLES3/gl3platform.h60
-rw-r--r--platform/winrt/include/GLSLANG/ShaderLang.h822
-rw-r--r--platform/winrt/include/GLSLANG/ShaderVars.h370
-rw-r--r--platform/winrt/include/KHR/khrplatform.h564
-rw-r--r--platform/winrt/include/angle_gl.h46
-rw-r--r--platform/winrt/include/angle_windowsstore.h74
-rw-r--r--platform/winrt/os_winrt.cpp36
-rw-r--r--platform/winrt/os_winrt.h4
-rw-r--r--platform/x11/SCsub1
-rw-r--r--platform/x11/context_gl_x11.cpp12
-rw-r--r--platform/x11/context_gl_x11.h2
-rw-r--r--platform/x11/detect.py56
-rw-r--r--platform/x11/godot_x11.cpp2
-rw-r--r--platform/x11/joystick_linux.cpp416
-rw-r--r--platform/x11/joystick_linux.h92
-rw-r--r--platform/x11/key_mapping_x11.cpp2
-rw-r--r--platform/x11/key_mapping_x11.h2
-rw-r--r--platform/x11/os_x11.cpp397
-rw-r--r--platform/x11/os_x11.h43
-rw-r--r--platform/x11/platform_config.h5
-rw-r--r--scene/2d/SCsub2
-rw-r--r--scene/2d/animated_sprite.cpp18
-rw-r--r--scene/2d/animated_sprite.h2
-rw-r--r--scene/2d/area_2d.cpp35
-rw-r--r--scene/2d/area_2d.h6
-rw-r--r--scene/2d/back_buffer_copy.cpp4
-rw-r--r--scene/2d/back_buffer_copy.h2
-rw-r--r--scene/2d/camera_2d.cpp45
-rw-r--r--scene/2d/camera_2d.h8
-rw-r--r--scene/2d/canvas_item.cpp50
-rw-r--r--scene/2d/canvas_item.h14
-rw-r--r--scene/2d/canvas_modulate.cpp13
-rw-r--r--scene/2d/collision_object_2d.cpp60
-rw-r--r--scene/2d/collision_object_2d.h2
-rw-r--r--scene/2d/collision_polygon_2d.cpp164
-rw-r--r--scene/2d/collision_polygon_2d.h15
-rw-r--r--scene/2d/collision_shape_2d.cpp171
-rw-r--r--scene/2d/collision_shape_2d.h10
-rw-r--r--scene/2d/joints_2d.cpp104
-rw-r--r--scene/2d/joints_2d.h13
-rw-r--r--scene/2d/light_2d.cpp36
-rw-r--r--scene/2d/light_2d.h7
-rw-r--r--scene/2d/light_occluder_2d.cpp5
-rw-r--r--scene/2d/navigation2d.cpp45
-rw-r--r--scene/2d/navigation_polygon.cpp18
-rw-r--r--scene/2d/node_2d.cpp23
-rw-r--r--scene/2d/node_2d.h4
-rw-r--r--scene/2d/node_2d_singleton.cpp2
-rw-r--r--scene/2d/node_2d_singleton.h2
-rw-r--r--scene/2d/parallax_background.cpp22
-rw-r--r--scene/2d/parallax_background.h6
-rw-r--r--scene/2d/parallax_layer.cpp2
-rw-r--r--scene/2d/parallax_layer.h2
-rw-r--r--scene/2d/particles_2d.cpp52
-rw-r--r--scene/2d/particles_2d.h3
-rw-r--r--scene/2d/path_2d.cpp12
-rw-r--r--scene/2d/path_2d.h2
-rw-r--r--scene/2d/physics_body_2d.cpp27
-rw-r--r--scene/2d/physics_body_2d.h4
-rw-r--r--scene/2d/position_2d.cpp2
-rw-r--r--scene/2d/position_2d.h2
-rw-r--r--scene/2d/ray_cast_2d.cpp29
-rw-r--r--scene/2d/ray_cast_2d.h6
-rw-r--r--scene/2d/remote_transform_2d.cpp2
-rw-r--r--scene/2d/remote_transform_2d.h2
-rw-r--r--scene/2d/sample_player_2d.cpp4
-rw-r--r--scene/2d/sample_player_2d.h2
-rw-r--r--scene/2d/screen_button.cpp10
-rw-r--r--scene/2d/screen_button.h2
-rw-r--r--scene/2d/sound_player_2d.cpp2
-rw-r--r--scene/2d/sound_player_2d.h2
-rw-r--r--scene/2d/sprite.cpp44
-rw-r--r--scene/2d/sprite.h2
-rw-r--r--scene/2d/tile_map.cpp111
-rw-r--r--scene/2d/tile_map.h12
-rw-r--r--scene/2d/visibility_notifier_2d.cpp2
-rw-r--r--scene/2d/visibility_notifier_2d.h2
-rw-r--r--scene/3d/SCsub4
-rw-r--r--scene/3d/area.cpp41
-rw-r--r--scene/3d/area.h16
-rw-r--r--scene/3d/baked_light_instance.cpp2
-rw-r--r--scene/3d/body_shape.cpp112
-rw-r--r--scene/3d/body_shape.h20
-rw-r--r--scene/3d/bone_attachment.cpp2
-rw-r--r--scene/3d/bone_attachment.h2
-rw-r--r--scene/3d/camera.cpp113
-rw-r--r--scene/3d/camera.h7
-rw-r--r--scene/3d/character_camera.cpp2
-rw-r--r--scene/3d/character_camera.h2
-rw-r--r--scene/3d/collision_object.cpp10
-rw-r--r--scene/3d/collision_object.h2
-rw-r--r--scene/3d/collision_polygon.cpp106
-rw-r--r--scene/3d/collision_polygon.h12
-rw-r--r--scene/3d/interpolated_camera.cpp2
-rw-r--r--scene/3d/interpolated_camera.h2
-rw-r--r--scene/3d/light.cpp6
-rw-r--r--scene/3d/light.h2
-rw-r--r--scene/3d/mesh_instance.cpp2
-rw-r--r--scene/3d/mesh_instance.h2
-rw-r--r--scene/3d/multimesh_instance.cpp2
-rw-r--r--scene/3d/multimesh_instance.h2
-rw-r--r--scene/3d/navigation.cpp2
-rw-r--r--scene/3d/navigation_mesh.cpp124
-rw-r--r--scene/3d/navigation_mesh.h17
-rw-r--r--scene/3d/optimized_spatial_scene.cpp2
-rw-r--r--scene/3d/optimized_spatial_scene.h2
-rw-r--r--scene/3d/particles.cpp6
-rw-r--r--scene/3d/particles.h2
-rw-r--r--scene/3d/path.cpp2
-rw-r--r--scene/3d/path.h2
-rw-r--r--scene/3d/physics_body.cpp96
-rw-r--r--scene/3d/physics_body.h20
-rw-r--r--scene/3d/physics_joint.cpp35
-rw-r--r--scene/3d/physics_joint.h6
-rw-r--r--scene/3d/portal.cpp2
-rw-r--r--scene/3d/portal.h2
-rw-r--r--scene/3d/position_3d.cpp2
-rw-r--r--scene/3d/position_3d.h2
-rw-r--r--scene/3d/proximity_group.cpp2
-rw-r--r--scene/3d/proximity_group.h2
-rw-r--r--scene/3d/quad.cpp2
-rw-r--r--scene/3d/quad.h2
-rw-r--r--scene/3d/ray_cast.cpp2
-rw-r--r--scene/3d/ray_cast.h2
-rw-r--r--scene/3d/room_instance.cpp2
-rw-r--r--scene/3d/room_instance.h2
-rw-r--r--scene/3d/scenario_fx.cpp2
-rw-r--r--scene/3d/scenario_fx.h2
-rw-r--r--scene/3d/skeleton.cpp111
-rw-r--r--scene/3d/skeleton.h10
-rw-r--r--scene/3d/spatial.cpp39
-rw-r--r--scene/3d/spatial.h8
-rw-r--r--scene/3d/spatial_indexer.cpp2
-rw-r--r--scene/3d/spatial_indexer.h2
-rw-r--r--scene/3d/spatial_player.cpp2
-rw-r--r--scene/3d/spatial_player.h2
-rw-r--r--scene/3d/spatial_sample_player.cpp2
-rw-r--r--scene/3d/spatial_sample_player.h2
-rw-r--r--scene/3d/spatial_stream_player.cpp293
-rw-r--r--scene/3d/spatial_stream_player.h58
-rw-r--r--scene/3d/sprite_3d.cpp4
-rw-r--r--scene/3d/test_cube.cpp2
-rw-r--r--scene/3d/test_cube.h2
-rw-r--r--scene/3d/visibility_notifier.cpp2
-rw-r--r--scene/3d/visibility_notifier.h2
-rw-r--r--scene/3d/visual_instance.cpp2
-rw-r--r--scene/3d/visual_instance.h2
-rw-r--r--scene/SCsub2
-rw-r--r--scene/animation/SCsub2
-rw-r--r--scene/animation/animation_cache.cpp2
-rw-r--r--scene/animation/animation_cache.h2
-rw-r--r--scene/animation/animation_player.cpp116
-rw-r--r--scene/animation/animation_player.h5
-rw-r--r--scene/animation/animation_tree_player.cpp167
-rw-r--r--scene/animation/animation_tree_player.h23
-rw-r--r--scene/animation/transitioner.cpp2
-rw-r--r--scene/animation/transitioner.h2
-rw-r--r--scene/animation/tween.cpp2
-rw-r--r--scene/animation/tween.h2
-rw-r--r--scene/animation/tween_interpolaters.cpp2
-rw-r--r--scene/audio/SCsub2
-rw-r--r--scene/audio/event_player.cpp12
-rw-r--r--scene/audio/event_player.h2
-rw-r--r--scene/audio/sample_player.cpp42
-rw-r--r--scene/audio/sample_player.h10
-rw-r--r--scene/audio/sound_room_params.cpp2
-rw-r--r--scene/audio/sound_room_params.h2
-rw-r--r--scene/audio/stream_player.cpp188
-rw-r--r--scene/audio/stream_player.h36
-rw-r--r--scene/gui/SCsub2
-rw-r--r--scene/gui/base_button.cpp18
-rw-r--r--scene/gui/base_button.h2
-rw-r--r--scene/gui/box_container.cpp38
-rw-r--r--scene/gui/box_container.h19
-rw-r--r--scene/gui/button.cpp14
-rw-r--r--scene/gui/button.h2
-rw-r--r--scene/gui/button_array.cpp10
-rw-r--r--scene/gui/button_array.h2
-rw-r--r--scene/gui/button_group.cpp4
-rw-r--r--scene/gui/button_group.h8
-rw-r--r--scene/gui/center_container.cpp2
-rw-r--r--scene/gui/center_container.h2
-rw-r--r--scene/gui/check_box.cpp2
-rw-r--r--scene/gui/check_box.h2
-rw-r--r--scene/gui/check_button.cpp2
-rw-r--r--scene/gui/check_button.h2
-rw-r--r--scene/gui/color_picker.cpp474
-rw-r--r--scene/gui/color_picker.h55
-rw-r--r--scene/gui/container.cpp12
-rw-r--r--scene/gui/container.h3
-rw-r--r--scene/gui/control.cpp1228
-rw-r--r--scene/gui/control.h84
-rw-r--r--scene/gui/custom_button.cpp2
-rw-r--r--scene/gui/custom_button.h2
-rw-r--r--scene/gui/dialogs.cpp8
-rw-r--r--scene/gui/dialogs.h2
-rw-r--r--scene/gui/file_dialog.cpp60
-rw-r--r--scene/gui/file_dialog.h7
-rw-r--r--scene/gui/graph_edit.cpp206
-rw-r--r--scene/gui/graph_edit.h15
-rw-r--r--scene/gui/graph_node.cpp62
-rw-r--r--scene/gui/graph_node.h11
-rw-r--r--scene/gui/grid_container.cpp2
-rw-r--r--scene/gui/grid_container.h2
-rw-r--r--scene/gui/item_list.cpp70
-rw-r--r--scene/gui/item_list.h3
-rw-r--r--scene/gui/label.cpp287
-rw-r--r--scene/gui/label.h42
-rw-r--r--scene/gui/line_edit.cpp228
-rw-r--r--scene/gui/line_edit.h25
-rw-r--r--scene/gui/margin_container.cpp2
-rw-r--r--scene/gui/margin_container.h2
-rw-r--r--scene/gui/menu_button.cpp6
-rw-r--r--scene/gui/menu_button.h2
-rw-r--r--scene/gui/option_button.cpp13
-rw-r--r--scene/gui/option_button.h2
-rw-r--r--scene/gui/panel.cpp2
-rw-r--r--scene/gui/panel.h2
-rw-r--r--scene/gui/panel_container.cpp2
-rw-r--r--scene/gui/panel_container.h2
-rw-r--r--scene/gui/patch_9_frame.cpp132
-rw-r--r--scene/gui/patch_9_frame.h40
-rw-r--r--scene/gui/popup.cpp24
-rw-r--r--scene/gui/popup.h2
-rw-r--r--scene/gui/popup_menu.cpp54
-rw-r--r--scene/gui/popup_menu.h3
-rw-r--r--scene/gui/progress_bar.cpp2
-rw-r--r--scene/gui/progress_bar.h2
-rw-r--r--scene/gui/range.cpp50
-rw-r--r--scene/gui/range.h15
-rw-r--r--scene/gui/reference_frame.cpp2
-rw-r--r--scene/gui/reference_frame.h2
-rw-r--r--scene/gui/rich_text_label.cpp559
-rw-r--r--scene/gui/rich_text_label.h92
-rw-r--r--scene/gui/scroll_bar.cpp2
-rw-r--r--scene/gui/scroll_bar.h2
-rw-r--r--scene/gui/scroll_container.cpp12
-rw-r--r--scene/gui/scroll_container.h2
-rw-r--r--scene/gui/separator.cpp2
-rw-r--r--scene/gui/separator.h2
-rw-r--r--scene/gui/slider.cpp6
-rw-r--r--scene/gui/slider.h2
-rw-r--r--scene/gui/spin_box.cpp87
-rw-r--r--scene/gui/spin_box.h18
-rw-r--r--scene/gui/split_container.cpp38
-rw-r--r--scene/gui/split_container.h17
-rw-r--r--scene/gui/tab_container.cpp91
-rw-r--r--scene/gui/tab_container.h2
-rw-r--r--scene/gui/tabs.cpp422
-rw-r--r--scene/gui/tabs.h39
-rw-r--r--scene/gui/text_edit.cpp452
-rw-r--r--scene/gui/text_edit.h15
-rw-r--r--scene/gui/texture_button.cpp34
-rw-r--r--scene/gui/texture_button.h6
-rw-r--r--scene/gui/texture_frame.cpp8
-rw-r--r--scene/gui/texture_frame.h2
-rw-r--r--scene/gui/texture_progress.cpp184
-rw-r--r--scene/gui/texture_progress.h33
-rw-r--r--scene/gui/tool_button.cpp2
-rw-r--r--scene/gui/tool_button.h2
-rw-r--r--scene/gui/tree.cpp557
-rw-r--r--scene/gui/tree.h28
-rw-r--r--scene/gui/video_player.cpp212
-rw-r--r--scene/gui/video_player.h38
-rw-r--r--scene/io/SCsub2
-rw-r--r--scene/io/resource_format_image.cpp20
-rw-r--r--scene/io/resource_format_image.h4
-rw-r--r--scene/io/resource_format_wav.cpp13
-rw-r--r--scene/io/resource_format_wav.h4
-rw-r--r--scene/main/SCsub2
-rw-r--r--scene/main/canvas_layer.cpp2
-rw-r--r--scene/main/canvas_layer.h2
-rw-r--r--scene/main/instance_placeholder.cpp75
-rw-r--r--scene/main/instance_placeholder.h37
-rw-r--r--scene/main/misc.cpp2
-rw-r--r--scene/main/misc.h2
-rw-r--r--scene/main/node.cpp229
-rw-r--r--scene/main/node.h48
-rw-r--r--scene/main/resource_preloader.cpp2
-rw-r--r--scene/main/resource_preloader.h2
-rw-r--r--scene/main/scene_main_loop.cpp603
-rw-r--r--scene/main/scene_main_loop.h100
-rw-r--r--scene/main/scene_singleton.cpp2
-rw-r--r--scene/main/scene_singleton.h2
-rw-r--r--scene/main/timer.cpp7
-rw-r--r--scene/main/timer.h2
-rw-r--r--scene/main/viewport.cpp1073
-rw-r--r--scene/main/viewport.h101
-rw-r--r--scene/register_scene_types.cpp42
-rw-r--r--scene/register_scene_types.h2
-rw-r--r--scene/resources/SCsub1
-rw-r--r--scene/resources/animation.cpp26
-rw-r--r--scene/resources/animation.h4
-rw-r--r--scene/resources/audio_stream.cpp72
-rw-r--r--scene/resources/audio_stream.h71
-rw-r--r--scene/resources/audio_stream_resampled.cpp6
-rw-r--r--scene/resources/audio_stream_resampled.h5
-rw-r--r--scene/resources/baked_light.cpp8
-rw-r--r--scene/resources/bit_mask.cpp51
-rw-r--r--scene/resources/bit_mask.h13
-rw-r--r--scene/resources/bounds.cpp2
-rw-r--r--scene/resources/bounds.h2
-rw-r--r--scene/resources/box_shape.cpp21
-rw-r--r--scene/resources/box_shape.h3
-rw-r--r--scene/resources/canvas.cpp2
-rw-r--r--scene/resources/canvas.h2
-rw-r--r--scene/resources/capsule_shape.cpp43
-rw-r--r--scene/resources/capsule_shape.h4
-rw-r--r--scene/resources/capsule_shape_2d.cpp29
-rw-r--r--scene/resources/capsule_shape_2d.h5
-rw-r--r--scene/resources/circle_shape_2d.cpp25
-rw-r--r--scene/resources/circle_shape_2d.h6
-rw-r--r--scene/resources/color_ramp.cpp34
-rw-r--r--scene/resources/color_ramp.h3
-rw-r--r--scene/resources/concave_polygon_shape.cpp36
-rw-r--r--scene/resources/concave_polygon_shape.h24
-rw-r--r--scene/resources/concave_polygon_shape_2d.cpp42
-rw-r--r--scene/resources/concave_polygon_shape_2d.h5
-rw-r--r--scene/resources/convex_polygon_shape.cpp29
-rw-r--r--scene/resources/convex_polygon_shape.h3
-rw-r--r--scene/resources/convex_polygon_shape_2d.cpp34
-rw-r--r--scene/resources/convex_polygon_shape_2d.h5
-rw-r--r--scene/resources/curve.cpp2
-rw-r--r--scene/resources/curve.h2
-rw-r--r--scene/resources/default_theme/SCsub2
-rw-r--r--scene/resources/default_theme/button_disabled.pngbin333 -> 3048 bytes
-rw-r--r--scene/resources/default_theme/button_focus.pngbin0 -> 2931 bytes
-rw-r--r--scene/resources/default_theme/button_hover.pngbin338 -> 3072 bytes
-rw-r--r--scene/resources/default_theme/button_normal.pngbin333 -> 3070 bytes
-rw-r--r--scene/resources/default_theme/button_pressed.pngbin351 -> 3078 bytes
-rw-r--r--scene/resources/default_theme/checked.pngbin597 -> 601 bytes
-rw-r--r--scene/resources/default_theme/default_theme.cpp239
-rw-r--r--scene/resources/default_theme/default_theme.h2
-rw-r--r--scene/resources/default_theme/focus.pngbin459 -> 2905 bytes
-rw-r--r--scene/resources/default_theme/frame_focus.pngbin0 -> 301 bytes
-rw-r--r--scene/resources/default_theme/graph_node_default.pngbin0 -> 289 bytes
-rw-r--r--scene/resources/default_theme/graph_node_default_focus.pngbin0 -> 408 bytes
-rw-r--r--scene/resources/default_theme/graph_node_selected.pngbin0 -> 738 bytes
-rw-r--r--scene/resources/default_theme/hslider_bg.pngbin229 -> 479 bytes
-rw-r--r--scene/resources/default_theme/hslider_grabber.pngbin483 -> 582 bytes
-rw-r--r--scene/resources/default_theme/hslider_grabber_hl.pngbin456 -> 611 bytes
-rw-r--r--scene/resources/default_theme/icon_add.pngbin0 -> 351 bytes
-rw-r--r--scene/resources/default_theme/icon_color_pick.pngbin0 -> 646 bytes
-rw-r--r--scene/resources/default_theme/icon_reload.pngbin0 -> 519 bytes
-rw-r--r--scene/resources/default_theme/line_edit.pngbin338 -> 309 bytes
-rw-r--r--scene/resources/default_theme/line_edit_disabled.pngbin336 -> 294 bytes
-rw-r--r--scene/resources/default_theme/make_header.py72
-rw-r--r--scene/resources/default_theme/make_png_header.py41
-rw-r--r--scene/resources/default_theme/option_button_disabled.pngbin353 -> 3198 bytes
-rw-r--r--scene/resources/default_theme/option_button_hover.pngbin368 -> 3209 bytes
-rw-r--r--scene/resources/default_theme/option_button_normal.pngbin365 -> 3223 bytes
-rw-r--r--scene/resources/default_theme/option_button_pressed.pngbin362 -> 3231 bytes
-rw-r--r--scene/resources/default_theme/panel_bg.pngbin173 -> 174 bytes
-rw-r--r--scene/resources/default_theme/popup_bg.pngbin308 -> 3078 bytes
-rw-r--r--scene/resources/default_theme/popup_window.pngbin508 -> 1050 bytes
-rw-r--r--scene/resources/default_theme/scroll_bg.pngbin215 -> 468 bytes
-rw-r--r--scene/resources/default_theme/scroll_grabber.pngbin266 -> 364 bytes
-rw-r--r--scene/resources/default_theme/scroll_grabber_hl.pngbin286 -> 411 bytes
-rw-r--r--scene/resources/default_theme/tab_behind.pngbin298 -> 394 bytes
-rw-r--r--scene/resources/default_theme/tab_close.pngbin0 -> 398 bytes
-rw-r--r--scene/resources/default_theme/tab_container_bg.pngbin301 -> 3070 bytes
-rw-r--r--scene/resources/default_theme/tab_current.pngbin294 -> 3055 bytes
-rw-r--r--scene/resources/default_theme/theme_data.h146
-rw-r--r--scene/resources/default_theme/toggle_off.pngbin733 -> 1613 bytes
-rw-r--r--scene/resources/default_theme/toggle_on.pngbin831 -> 1618 bytes
-rw-r--r--scene/resources/default_theme/tree_bg.pngbin341 -> 309 bytes
-rw-r--r--scene/resources/default_theme/unchecked.pngbin394 -> 385 bytes
-rw-r--r--scene/resources/default_theme/uv_editor.gsl19
-rw-r--r--scene/resources/default_theme/vslider_bg.pngbin229 -> 543 bytes
-rw-r--r--scene/resources/default_theme/vslider_grabber.pngbin572 -> 533 bytes
-rw-r--r--scene/resources/default_theme/vslider_grabber_hl.pngbin456 -> 555 bytes
-rw-r--r--scene/resources/default_theme/w_editor.gsl11
-rw-r--r--scene/resources/environment.cpp2
-rw-r--r--scene/resources/environment.h2
-rw-r--r--scene/resources/event_stream.cpp2
-rw-r--r--scene/resources/event_stream.h2
-rw-r--r--scene/resources/font.cpp47
-rw-r--r--scene/resources/font.h14
-rw-r--r--scene/resources/gibberish_stream.cpp5
-rw-r--r--scene/resources/gibberish_stream.h6
-rw-r--r--scene/resources/height_map_shape.cpp2
-rw-r--r--scene/resources/height_map_shape.h2
-rw-r--r--scene/resources/material.cpp14
-rw-r--r--scene/resources/material.h2
-rw-r--r--scene/resources/mesh.cpp14
-rw-r--r--scene/resources/mesh.h2
-rw-r--r--scene/resources/mesh_data_tool.cpp2
-rw-r--r--scene/resources/mesh_data_tool.h2
-rw-r--r--scene/resources/mesh_library.cpp10
-rw-r--r--scene/resources/mesh_library.h2
-rw-r--r--scene/resources/multimesh.cpp14
-rw-r--r--scene/resources/multimesh.h2
-rw-r--r--scene/resources/packed_scene.cpp1260
-rw-r--r--scene/resources/packed_scene.h134
-rw-r--r--scene/resources/plane_shape.cpp31
-rw-r--r--scene/resources/plane_shape.h4
-rw-r--r--scene/resources/ray_shape.cpp9
-rw-r--r--scene/resources/ray_shape.h4
-rw-r--r--scene/resources/rectangle_shape_2d.cpp17
-rw-r--r--scene/resources/rectangle_shape_2d.h5
-rw-r--r--scene/resources/rich_text.cpp2
-rw-r--r--scene/resources/rich_text.h2
-rw-r--r--scene/resources/room.cpp2
-rw-r--r--scene/resources/room.h2
-rw-r--r--scene/resources/sample.cpp8
-rw-r--r--scene/resources/sample.h2
-rw-r--r--scene/resources/sample_library.cpp6
-rw-r--r--scene/resources/sample_library.h2
-rw-r--r--scene/resources/scene_format_text.cpp1438
-rw-r--r--scene/resources/scene_format_text.h142
-rw-r--r--scene/resources/scene_preloader.cpp2
-rw-r--r--scene/resources/scene_preloader.h2
-rw-r--r--scene/resources/segment_shape_2d.cpp51
-rw-r--r--scene/resources/segment_shape_2d.h7
-rw-r--r--scene/resources/shader.cpp31
-rw-r--r--scene/resources/shader.h4
-rw-r--r--scene/resources/shader_graph.cpp333
-rw-r--r--scene/resources/shader_graph.h17
-rw-r--r--scene/resources/shape.cpp61
-rw-r--r--scene/resources/shape.h12
-rw-r--r--scene/resources/shape_2d.cpp6
-rw-r--r--scene/resources/shape_2d.h4
-rw-r--r--scene/resources/shape_line_2d.cpp31
-rw-r--r--scene/resources/shape_line_2d.h5
-rw-r--r--scene/resources/space_2d.cpp2
-rw-r--r--scene/resources/space_2d.h2
-rw-r--r--scene/resources/sphere_shape.cpp26
-rw-r--r--scene/resources/sphere_shape.h4
-rw-r--r--scene/resources/style_box.cpp10
-rw-r--r--scene/resources/style_box.h2
-rw-r--r--scene/resources/surface_tool.cpp2
-rw-r--r--scene/resources/surface_tool.h2
-rw-r--r--scene/resources/texture.cpp44
-rw-r--r--scene/resources/texture.h9
-rw-r--r--scene/resources/theme.cpp80
-rw-r--r--scene/resources/theme.h14
-rw-r--r--scene/resources/tile_set.cpp2
-rw-r--r--scene/resources/tile_set.h2
-rw-r--r--scene/resources/video_stream.cpp10
-rw-r--r--scene/resources/video_stream.h38
-rw-r--r--scene/resources/volume.cpp2
-rw-r--r--scene/resources/volume.h2
-rw-r--r--scene/resources/world.cpp2
-rw-r--r--scene/resources/world.h2
-rw-r--r--scene/resources/world_2d.cpp4
-rw-r--r--scene/resources/world_2d.h2
-rw-r--r--scene/scene_string_names.cpp11
-rw-r--r--scene/scene_string_names.h14
-rw-r--r--servers/SCsub2
-rw-r--r--servers/audio/SCsub2
-rw-r--r--servers/audio/audio_driver_dummy.cpp2
-rw-r--r--servers/audio/audio_driver_dummy.h2
-rw-r--r--servers/audio/audio_filter_sw.cpp2
-rw-r--r--servers/audio/audio_filter_sw.h2
-rw-r--r--servers/audio/audio_mixer_sw.cpp131
-rw-r--r--servers/audio/audio_mixer_sw.h4
-rw-r--r--servers/audio/audio_rb_resampler.cpp356
-rw-r--r--servers/audio/audio_rb_resampler.h138
-rw-r--r--servers/audio/audio_server_sw.cpp24
-rw-r--r--servers/audio/audio_server_sw.h8
-rw-r--r--servers/audio/reverb_buffers_sw.cpp2
-rw-r--r--servers/audio/reverb_buffers_sw.h2
-rw-r--r--servers/audio/reverb_sw.cpp2
-rw-r--r--servers/audio/reverb_sw.h2
-rw-r--r--servers/audio/sample_manager_sw.cpp10
-rw-r--r--servers/audio/sample_manager_sw.h2
-rw-r--r--servers/audio/voice_rb_sw.cpp2
-rw-r--r--servers/audio/voice_rb_sw.h2
-rw-r--r--servers/audio_server.cpp7
-rw-r--r--servers/audio_server.h6
-rw-r--r--servers/physics/SCsub2
-rw-r--r--servers/physics/area_pair_sw.cpp2
-rw-r--r--servers/physics/area_pair_sw.h2
-rw-r--r--servers/physics/area_sw.cpp19
-rw-r--r--servers/physics/area_sw.h13
-rw-r--r--servers/physics/body_pair_sw.cpp13
-rw-r--r--servers/physics/body_pair_sw.h2
-rw-r--r--servers/physics/body_sw.cpp99
-rw-r--r--servers/physics/body_sw.h21
-rw-r--r--servers/physics/broad_phase_basic.cpp2
-rw-r--r--servers/physics/broad_phase_basic.h2
-rw-r--r--servers/physics/broad_phase_octree.cpp2
-rw-r--r--servers/physics/broad_phase_octree.h2
-rw-r--r--servers/physics/broad_phase_sw.cpp2
-rw-r--r--servers/physics/broad_phase_sw.h2
-rw-r--r--servers/physics/collision_object_sw.cpp2
-rw-r--r--servers/physics/collision_object_sw.h2
-rw-r--r--servers/physics/collision_solver_sat.cpp2
-rw-r--r--servers/physics/collision_solver_sat.h2
-rw-r--r--servers/physics/collision_solver_sw.cpp2
-rw-r--r--servers/physics/collision_solver_sw.h2
-rw-r--r--servers/physics/constraint_sw.cpp2
-rw-r--r--servers/physics/constraint_sw.h2
-rw-r--r--servers/physics/gjk_epa.cpp2
-rw-r--r--servers/physics/gjk_epa.h2
-rw-r--r--servers/physics/joints/SCsub3
-rw-r--r--servers/physics/joints_sw.cpp2
-rw-r--r--servers/physics/joints_sw.h2
-rw-r--r--servers/physics/physics_server_sw.cpp28
-rw-r--r--servers/physics/physics_server_sw.h7
-rw-r--r--servers/physics/shape_sw.cpp6
-rw-r--r--servers/physics/shape_sw.h2
-rw-r--r--servers/physics/space_sw.cpp1492
-rw-r--r--servers/physics/space_sw.h366
-rw-r--r--servers/physics/step_sw.cpp2
-rw-r--r--servers/physics/step_sw.h2
-rw-r--r--servers/physics_2d/SCsub1
-rw-r--r--servers/physics_2d/area_2d_sw.cpp10
-rw-r--r--servers/physics_2d/area_2d_sw.h2
-rw-r--r--servers/physics_2d/area_pair_2d_sw.cpp2
-rw-r--r--servers/physics_2d/area_pair_2d_sw.h2
-rw-r--r--servers/physics_2d/body_2d_sw.cpp86
-rw-r--r--servers/physics_2d/body_2d_sw.h13
-rw-r--r--servers/physics_2d/body_pair_2d_sw.cpp15
-rw-r--r--servers/physics_2d/body_pair_2d_sw.h2
-rw-r--r--servers/physics_2d/broad_phase_2d_basic.cpp2
-rw-r--r--servers/physics_2d/broad_phase_2d_basic.h2
-rw-r--r--servers/physics_2d/broad_phase_2d_hash_grid.cpp2
-rw-r--r--servers/physics_2d/broad_phase_2d_hash_grid.h2
-rw-r--r--servers/physics_2d/broad_phase_2d_sw.cpp2
-rw-r--r--servers/physics_2d/broad_phase_2d_sw.h2
-rw-r--r--servers/physics_2d/collision_object_2d_sw.cpp2
-rw-r--r--servers/physics_2d/collision_object_2d_sw.h2
-rw-r--r--servers/physics_2d/collision_solver_2d_sat.cpp2
-rw-r--r--servers/physics_2d/collision_solver_2d_sat.h2
-rw-r--r--servers/physics_2d/collision_solver_2d_sw.cpp2
-rw-r--r--servers/physics_2d/collision_solver_2d_sw.h2
-rw-r--r--servers/physics_2d/constraint_2d_sw.cpp2
-rw-r--r--servers/physics_2d/constraint_2d_sw.h2
-rw-r--r--servers/physics_2d/joints_2d_sw.cpp14
-rw-r--r--servers/physics_2d/joints_2d_sw.h4
-rw-r--r--servers/physics_2d/physics_2d_server_sw.cpp48
-rw-r--r--servers/physics_2d/physics_2d_server_sw.h12
-rw-r--r--servers/physics_2d/physics_2d_server_wrap_mt.h19
-rw-r--r--servers/physics_2d/shape_2d_sw.cpp2
-rw-r--r--servers/physics_2d/shape_2d_sw.h2
-rw-r--r--servers/physics_2d/space_2d_sw.cpp25
-rw-r--r--servers/physics_2d/space_2d_sw.h13
-rw-r--r--servers/physics_2d/step_2d_sw.cpp54
-rw-r--r--servers/physics_2d/step_2d_sw.h4
-rw-r--r--servers/physics_2d_server.cpp22
-rw-r--r--servers/physics_2d_server.h14
-rw-r--r--servers/physics_server.cpp34
-rw-r--r--servers/physics_server.h24
-rw-r--r--servers/register_server_types.cpp22
-rw-r--r--servers/register_server_types.h2
-rw-r--r--servers/spatial_sound/SCsub2
-rw-r--r--servers/spatial_sound/spatial_sound_server_sw.cpp2
-rw-r--r--servers/spatial_sound/spatial_sound_server_sw.h2
-rw-r--r--servers/spatial_sound_2d/SCsub2
-rw-r--r--servers/spatial_sound_2d/spatial_sound_2d_server_sw.cpp2
-rw-r--r--servers/spatial_sound_2d/spatial_sound_2d_server_sw.h2
-rw-r--r--servers/spatial_sound_2d_server.cpp2
-rw-r--r--servers/spatial_sound_2d_server.h2
-rw-r--r--servers/spatial_sound_server.cpp2
-rw-r--r--servers/spatial_sound_server.h2
-rw-r--r--servers/visual/SCsub2
-rw-r--r--servers/visual/particle_system_sw.cpp2
-rw-r--r--servers/visual/particle_system_sw.h2
-rw-r--r--servers/visual/rasterizer.cpp2
-rw-r--r--servers/visual/rasterizer.h21
-rw-r--r--servers/visual/rasterizer_dummy.cpp5
-rw-r--r--servers/visual/rasterizer_dummy.h11
-rw-r--r--servers/visual/shader_compiler.cpp2
-rw-r--r--servers/visual/shader_compiler.h2
-rw-r--r--servers/visual/shader_graph.cpp2
-rw-r--r--servers/visual/shader_graph.h2
-rw-r--r--servers/visual/shader_language.cpp22
-rw-r--r--servers/visual/shader_language.h2
-rw-r--r--servers/visual/visual_server_raster.cpp109
-rw-r--r--servers/visual/visual_server_raster.h14
-rw-r--r--servers/visual/visual_server_wrap_mt.cpp2
-rw-r--r--servers/visual/visual_server_wrap_mt.h14
-rw-r--r--servers/visual_server.cpp3
-rw-r--r--servers/visual_server.h19
-rwxr-xr-xtools/Godot.app/Contents/Info.plist8
-rw-r--r--tools/Godot.app/Contents/Resources/Godot.icnsbin294521 -> 260598 bytes
-rw-r--r--tools/SCsub3
-rw-r--r--tools/addheader/addheader.py2
-rw-r--r--tools/addheader/header.txt2
-rw-r--r--tools/collada/SCsub2
-rw-r--r--tools/collada/collada.cpp12
-rw-r--r--tools/collada/collada.h2
-rw-r--r--tools/doc/SCsub2
-rw-r--r--tools/doc/doc_data.cpp27
-rw-r--r--tools/doc/doc_data.h2
-rw-r--r--tools/docdump/SCsub2
-rw-r--r--tools/docdump/class_list.xml13625
-rw-r--r--tools/docdump/doc_dump.cpp6
-rw-r--r--tools/docdump/doc_dump.h2
-rw-r--r--tools/docdump/doc_merge.py208
-rw-r--r--tools/docdump/main.css146
-rw-r--r--tools/docdump/makedoku.py511
-rw-r--r--tools/docdump/makehtml.py704
-rw-r--r--tools/docdump/makemd.py345
-rw-r--r--tools/editor/SCsub11
-rw-r--r--tools/editor/animation_editor.cpp315
-rw-r--r--tools/editor/animation_editor.h28
-rw-r--r--tools/editor/array_property_edit.cpp250
-rw-r--r--tools/editor/array_property_edit.h38
-rw-r--r--tools/editor/call_dialog.cpp2
-rw-r--r--tools/editor/call_dialog.h2
-rw-r--r--tools/editor/code_editor.cpp8
-rw-r--r--tools/editor/code_editor.h2
-rw-r--r--tools/editor/connections_dialog.cpp25
-rw-r--r--tools/editor/connections_dialog.h4
-rw-r--r--tools/editor/console.cpp386
-rw-r--r--tools/editor/console.h116
-rw-r--r--tools/editor/create_dialog.cpp6
-rw-r--r--tools/editor/create_dialog.h2
-rw-r--r--tools/editor/default_saver.cpp2
-rw-r--r--tools/editor/default_saver.h2
-rw-r--r--tools/editor/dependency_editor.cpp693
-rw-r--r--tools/editor/dependency_editor.h119
-rw-r--r--tools/editor/doc_code_font.h2
-rw-r--r--tools/editor/doc_font.h2
-rw-r--r--tools/editor/doc_title_font.h2
-rw-r--r--tools/editor/editor_data.cpp170
-rw-r--r--tools/editor/editor_data.h20
-rw-r--r--tools/editor/editor_dir_dialog.cpp19
-rw-r--r--tools/editor/editor_dir_dialog.h2
-rw-r--r--tools/editor/editor_file_dialog.cpp95
-rw-r--r--tools/editor/editor_file_dialog.h7
-rw-r--r--tools/editor/editor_file_system.cpp988
-rw-r--r--tools/editor/editor_file_system.h96
-rw-r--r--tools/editor/editor_fonts.cpp2
-rw-r--r--tools/editor/editor_fonts.h2
-rw-r--r--tools/editor/editor_help.cpp630
-rw-r--r--tools/editor/editor_help.h96
-rw-r--r--tools/editor/editor_icons.h2
-rw-r--r--tools/editor/editor_import_export.cpp398
-rw-r--r--tools/editor/editor_import_export.h73
-rw-r--r--tools/editor/editor_log.cpp69
-rw-r--r--tools/editor/editor_log.h16
-rw-r--r--tools/editor/editor_name_dialog.cpp89
-rw-r--r--tools/editor/editor_name_dialog.h57
-rw-r--r--tools/editor/editor_node.cpp1832
-rw-r--r--tools/editor/editor_node.h151
-rw-r--r--tools/editor/editor_path.cpp8
-rw-r--r--tools/editor/editor_path.h2
-rw-r--r--tools/editor/editor_plugin.cpp3
-rw-r--r--tools/editor/editor_plugin.h3
-rw-r--r--tools/editor/editor_reimport_dialog.cpp2
-rw-r--r--tools/editor/editor_reimport_dialog.h2
-rw-r--r--tools/editor/editor_run.cpp99
-rw-r--r--tools/editor/editor_run.h12
-rw-r--r--tools/editor/editor_run_native.cpp53
-rw-r--r--tools/editor/editor_run_native.h15
-rw-r--r--tools/editor/editor_selection.cpp2
-rw-r--r--tools/editor/editor_selection.h2
-rw-r--r--tools/editor/editor_settings.cpp48
-rw-r--r--tools/editor/editor_settings.h4
-rw-r--r--tools/editor/editor_sub_scene.cpp14
-rw-r--r--tools/editor/editor_sub_scene.h2
-rw-r--r--tools/editor/editor_vu.cpp2
-rw-r--r--tools/editor/editor_vu.h2
-rw-r--r--tools/editor/file_type_cache.cpp2
-rw-r--r--tools/editor/file_type_cache.h2
-rw-r--r--tools/editor/fileserver/SCsub4
-rw-r--r--tools/editor/fileserver/editor_file_server.cpp20
-rw-r--r--tools/editor/groups_editor.cpp167
-rw-r--r--tools/editor/groups_editor.h38
-rw-r--r--tools/editor/icons/SCsub19
-rw-r--r--tools/editor/icons/icon_add_track.pngbin446 -> 165 bytes
-rw-r--r--tools/editor/icons/icon_anchor.pngbin0 -> 428 bytes
-rw-r--r--tools/editor/icons/icon_audio_stream_opus.pngbin0 -> 559 bytes
-rw-r--r--tools/editor/icons/icon_back.pngbin206 -> 180 bytes
-rw-r--r--tools/editor/icons/icon_class_list.pngbin0 -> 241 bytes
-rw-r--r--tools/editor/icons/icon_console.pngbin0 -> 640 bytes
-rw-r--r--tools/editor/icons/icon_control_align_bottom_center.pngbin0 -> 174 bytes
-rw-r--r--tools/editor/icons/icon_control_align_bottom_left.pngbin0 -> 172 bytes
-rw-r--r--tools/editor/icons/icon_control_align_bottom_right.pngbin0 -> 174 bytes
-rw-r--r--tools/editor/icons/icon_control_align_bottom_wide.pngbin0 -> 174 bytes
-rw-r--r--tools/editor/icons/icon_control_align_center.pngbin0 -> 181 bytes
-rw-r--r--tools/editor/icons/icon_control_align_center_left.pngbin0 -> 172 bytes
-rw-r--r--tools/editor/icons/icon_control_align_center_right.pngbin0 -> 171 bytes
-rw-r--r--tools/editor/icons/icon_control_align_left_center.pngbin0 -> 183 bytes
-rw-r--r--tools/editor/icons/icon_control_align_left_wide.pngbin0 -> 166 bytes
-rw-r--r--tools/editor/icons/icon_control_align_right_center.pngbin0 -> 181 bytes
-rw-r--r--tools/editor/icons/icon_control_align_right_wide.pngbin0 -> 167 bytes
-rw-r--r--tools/editor/icons/icon_control_align_top_center.pngbin0 -> 181 bytes
-rw-r--r--tools/editor/icons/icon_control_align_top_left.pngbin0 -> 176 bytes
-rw-r--r--tools/editor/icons/icon_control_align_top_right.pngbin0 -> 183 bytes
-rw-r--r--tools/editor/icons/icon_control_align_top_wide.pngbin0 -> 179 bytes
-rw-r--r--tools/editor/icons/icon_control_align_wide.pngbin0 -> 165 bytes
-rw-r--r--tools/editor/icons/icon_control_hcenter_wide.pngbin0 -> 182 bytes
-rw-r--r--tools/editor/icons/icon_control_vcenter_wide.pngbin0 -> 171 bytes
-rw-r--r--tools/editor/icons/icon_create_new_scene_from.pngbin0 -> 588 bytes
-rw-r--r--tools/editor/icons/icon_debug.pngbin0 -> 659 bytes
-rw-r--r--tools/editor/icons/icon_edit_pivot.pngbin0 -> 407 bytes
-rw-r--r--tools/editor/icons/icon_file_list.pngbin260 -> 288 bytes
-rw-r--r--tools/editor/icons/icon_filesystem.pngbin0 -> 241 bytes
-rw-r--r--tools/editor/icons/icon_forward.pngbin199 -> 191 bytes
-rw-r--r--tools/editor/icons/icon_godot.pngbin0 -> 671 bytes
-rw-r--r--tools/editor/icons/icon_grid.pngbin0 -> 354 bytes
-rw-r--r--tools/editor/icons/icon_help.pngbin822 -> 841 bytes
-rw-r--r--tools/editor/icons/icon_history.pngbin0 -> 572 bytes
-rw-r--r--tools/editor/icons/icon_key_invalid.pngbin0 -> 239 bytes
-rw-r--r--tools/editor/icons/icon_key_invalid_hover.pngbin0 -> 239 bytes
-rw-r--r--tools/editor/icons/icon_list_select.pngbin0 -> 470 bytes
-rw-r--r--tools/editor/icons/icon_live_debug.pngbin0 -> 583 bytes
-rw-r--r--tools/editor/icons/icon_multi_edit.pngbin0 -> 576 bytes
-rw-r--r--tools/editor/icons/icon_multi_node_edit.pngbin0 -> 576 bytes
-rw-r--r--tools/editor/icons/icon_non_favorite.pngbin0 -> 469 bytes
-rw-r--r--tools/editor/icons/icon_patch_9_frame.pngbin0 -> 431 bytes
-rw-r--r--tools/editor/icons/icon_pin.pngbin381 -> 428 bytes
-rw-r--r--tools/editor/icons/icon_region_edit.pngbin0 -> 171 bytes
-rw-r--r--tools/editor/icons/icon_remote.pngbin0 -> 707 bytes
-rw-r--r--tools/editor/icons/icon_script_list.pngbin0 -> 213 bytes
-rw-r--r--tools/editor/import_settings.cpp2
-rw-r--r--tools/editor/import_settings.h2
-rw-r--r--tools/editor/inspector_dock.cpp22
-rw-r--r--tools/editor/inspector_dock.h35
-rw-r--r--tools/editor/io_plugins/SCsub4
-rw-r--r--tools/editor/io_plugins/editor_atlas.cpp14
-rw-r--r--tools/editor/io_plugins/editor_atlas.h2
-rw-r--r--tools/editor/io_plugins/editor_export_scene.cpp112
-rw-r--r--tools/editor/io_plugins/editor_export_scene.h16
-rw-r--r--tools/editor/io_plugins/editor_font_import_plugin.cpp28
-rw-r--r--tools/editor/io_plugins/editor_font_import_plugin.h2
-rw-r--r--tools/editor/io_plugins/editor_import_collada.cpp290
-rw-r--r--tools/editor/io_plugins/editor_import_collada.h2
-rw-r--r--tools/editor/io_plugins/editor_mesh_import_plugin.cpp39
-rw-r--r--tools/editor/io_plugins/editor_sample_import_plugin.cpp97
-rw-r--r--tools/editor/io_plugins/editor_sample_import_plugin.h16
-rw-r--r--tools/editor/io_plugins/editor_scene_import_plugin.cpp6
-rw-r--r--tools/editor/io_plugins/editor_scene_import_plugin.h2
-rw-r--r--tools/editor/io_plugins/editor_texture_import_plugin.cpp113
-rw-r--r--tools/editor/io_plugins/editor_texture_import_plugin.h5
-rw-r--r--tools/editor/io_plugins/editor_translation_import_plugin.cpp2
-rw-r--r--tools/editor/io_plugins/editor_translation_import_plugin.h2
-rw-r--r--tools/editor/multi_node_edit.cpp118
-rw-r--r--tools/editor/multi_node_edit.h32
-rw-r--r--tools/editor/optimized_save_dialog.cpp2
-rw-r--r--tools/editor/optimized_save_dialog.h2
-rw-r--r--tools/editor/output_strings.cpp2
-rw-r--r--tools/editor/output_strings.h2
-rw-r--r--tools/editor/pane_drag.cpp2
-rw-r--r--tools/editor/pane_drag.h2
-rw-r--r--tools/editor/plugins/SCsub4
-rw-r--r--tools/editor/plugins/animation_data_editor_plugin.cpp2
-rw-r--r--tools/editor/plugins/animation_data_editor_plugin.h2
-rw-r--r--tools/editor/plugins/animation_player_editor_plugin.cpp515
-rw-r--r--tools/editor/plugins/animation_player_editor_plugin.h50
-rw-r--r--tools/editor/plugins/animation_tree_editor_plugin.cpp25
-rw-r--r--tools/editor/plugins/animation_tree_editor_plugin.h3
-rw-r--r--tools/editor/plugins/camera_editor_plugin.cpp2
-rw-r--r--tools/editor/plugins/camera_editor_plugin.h2
-rw-r--r--tools/editor/plugins/canvas_item_editor_plugin.cpp709
-rw-r--r--tools/editor/plugins/canvas_item_editor_plugin.h52
-rw-r--r--tools/editor/plugins/collision_polygon_editor_plugin.cpp7
-rw-r--r--tools/editor/plugins/collision_polygon_editor_plugin.h2
-rw-r--r--tools/editor/plugins/collision_shape_2d_editor_plugin.cpp40
-rw-r--r--tools/editor/plugins/color_ramp_editor_plugin.cpp17
-rw-r--r--tools/editor/plugins/color_ramp_editor_plugin.h3
-rw-r--r--tools/editor/plugins/control_editor_plugin.cpp2
-rw-r--r--tools/editor/plugins/control_editor_plugin.h2
-rw-r--r--tools/editor/plugins/cube_grid_theme_editor_plugin.cpp2
-rw-r--r--tools/editor/plugins/cube_grid_theme_editor_plugin.h2
-rw-r--r--tools/editor/plugins/editor_preview_plugins.cpp105
-rw-r--r--tools/editor/plugins/editor_preview_plugins.h11
-rw-r--r--tools/editor/plugins/item_list_editor_plugin.cpp367
-rw-r--r--tools/editor/plugins/item_list_editor_plugin.h140
-rw-r--r--tools/editor/plugins/mesh_editor_plugin.cpp151
-rw-r--r--tools/editor/plugins/mesh_editor_plugin.h13
-rw-r--r--tools/editor/plugins/multimesh_editor_plugin.cpp24
-rw-r--r--tools/editor/plugins/multimesh_editor_plugin.h10
-rw-r--r--tools/editor/plugins/particles_2d_editor_plugin.cpp3
-rw-r--r--tools/editor/plugins/particles_2d_editor_plugin.h2
-rw-r--r--tools/editor/plugins/particles_editor_plugin.cpp3
-rw-r--r--tools/editor/plugins/particles_editor_plugin.h2
-rw-r--r--tools/editor/plugins/path_2d_editor_plugin.cpp4
-rw-r--r--tools/editor/plugins/path_2d_editor_plugin.h2
-rw-r--r--tools/editor/plugins/path_editor_plugin.cpp1194
-rw-r--r--tools/editor/plugins/path_editor_plugin.h2
-rw-r--r--tools/editor/plugins/polygon_2d_editor_plugin.cpp171
-rw-r--r--tools/editor/plugins/polygon_2d_editor_plugin.h17
-rw-r--r--tools/editor/plugins/resource_preloader_editor_plugin.cpp20
-rw-r--r--tools/editor/plugins/resource_preloader_editor_plugin.h3
-rw-r--r--tools/editor/plugins/rich_text_editor_plugin.cpp2
-rw-r--r--tools/editor/plugins/rich_text_editor_plugin.h2
-rw-r--r--tools/editor/plugins/sample_editor_plugin.cpp10
-rw-r--r--tools/editor/plugins/sample_editor_plugin.h2
-rw-r--r--tools/editor/plugins/sample_library_editor_plugin.cpp26
-rw-r--r--tools/editor/plugins/sample_library_editor_plugin.h3
-rw-r--r--tools/editor/plugins/sample_player_editor_plugin.cpp2
-rw-r--r--tools/editor/plugins/sample_player_editor_plugin.h2
-rw-r--r--tools/editor/plugins/script_editor_plugin.cpp1633
-rw-r--r--tools/editor/plugins/script_editor_plugin.h75
-rw-r--r--tools/editor/plugins/shader_editor_plugin.cpp12
-rw-r--r--tools/editor/plugins/shader_editor_plugin.h2
-rw-r--r--tools/editor/plugins/shader_graph_editor_plugin.cpp2039
-rw-r--r--tools/editor/plugins/shader_graph_editor_plugin.h19
-rw-r--r--tools/editor/plugins/spatial_editor_plugin.cpp373
-rw-r--r--tools/editor/plugins/spatial_editor_plugin.h25
-rw-r--r--tools/editor/plugins/sprite_frames_editor_plugin.cpp21
-rw-r--r--tools/editor/plugins/sprite_frames_editor_plugin.h3
-rw-r--r--tools/editor/plugins/sprite_region_editor_plugin.cpp608
-rw-r--r--tools/editor/plugins/sprite_region_editor_plugin.h133
-rw-r--r--tools/editor/plugins/stream_editor_plugin.cpp2
-rw-r--r--tools/editor/plugins/stream_editor_plugin.h2
-rw-r--r--tools/editor/plugins/style_box_editor_plugin.cpp21
-rw-r--r--tools/editor/plugins/style_box_editor_plugin.h3
-rw-r--r--tools/editor/plugins/theme_editor_plugin.cpp55
-rw-r--r--tools/editor/plugins/theme_editor_plugin.h3
-rw-r--r--tools/editor/plugins/tile_map_editor_plugin.cpp63
-rw-r--r--tools/editor/plugins/tile_map_editor_plugin.h2
-rw-r--r--tools/editor/plugins/tile_set_editor_plugin.cpp61
-rw-r--r--tools/editor/plugins/tile_set_editor_plugin.h9
-rw-r--r--tools/editor/progress_dialog.cpp14
-rw-r--r--tools/editor/progress_dialog.h5
-rw-r--r--tools/editor/project_export.cpp110
-rw-r--r--tools/editor/project_export.h12
-rw-r--r--tools/editor/project_manager.cpp77
-rw-r--r--tools/editor/project_manager.h3
-rw-r--r--tools/editor/project_settings.cpp413
-rw-r--r--tools/editor/project_settings.h10
-rw-r--r--tools/editor/property_editor.cpp1528
-rw-r--r--tools/editor/property_editor.h101
-rw-r--r--tools/editor/pvrtc_compress.cpp2
-rw-r--r--tools/editor/pvrtc_compress.h2
-rw-r--r--tools/editor/quick_open.cpp114
-rw-r--r--tools/editor/quick_open.h15
-rw-r--r--tools/editor/register_exporters.h2
-rw-r--r--tools/editor/reparent_dialog.cpp30
-rw-r--r--tools/editor/reparent_dialog.h9
-rw-r--r--tools/editor/resources_dock.cpp2
-rw-r--r--tools/editor/resources_dock.h2
-rw-r--r--tools/editor/run_settings_dialog.cpp2
-rw-r--r--tools/editor/run_settings_dialog.h2
-rw-r--r--tools/editor/scene_tree_dock.cpp316
-rw-r--r--tools/editor/scene_tree_dock.h10
-rw-r--r--tools/editor/scene_tree_editor.cpp155
-rw-r--r--tools/editor/scene_tree_editor.h10
-rw-r--r--tools/editor/scenes.cpp2
-rw-r--r--tools/editor/scenes.h2
-rw-r--r--tools/editor/scenes_dock.cpp1198
-rw-r--r--tools/editor/scenes_dock.h133
-rw-r--r--tools/editor/script_create_dialog.cpp10
-rw-r--r--tools/editor/script_create_dialog.h2
-rw-r--r--tools/editor/script_editor_debugger.cpp639
-rw-r--r--tools/editor/script_editor_debugger.h66
-rw-r--r--tools/editor/settings_config_dialog.cpp15
-rw-r--r--tools/editor/settings_config_dialog.h6
-rw-r--r--tools/editor/spatial_editor_gizmos.cpp6384
-rw-r--r--tools/editor/spatial_editor_gizmos.h978
-rw-r--r--tools/export/blender25/godot_export_manager.py946
-rw-r--r--tools/export/blender25/io_scene_dae/__init__.py5
-rw-r--r--tools/export/blender25/io_scene_dae/export_dae.py6
-rw-r--r--tools/freetype/SCsub4
-rw-r--r--tools/html_fs/godot.html1317
-rw-r--r--tools/html_fs/godotfs.js (renamed from tools/html_fs/filesystem.js)0
-rw-r--r--tools/ios_xcode_template/godot_ios.xcodeproj/project.pbxproj2
-rw-r--r--tools/ios_xcode_template/godot_ios/godot_ios-Info.plist2
-rw-r--r--tools/ios_xcode_template/godot_ios/main.m35
-rw-r--r--tools/ios_xcode_template/godot_iosTests/godot_iosTests-Info.plist2
-rw-r--r--tools/ios_xcode_template/godot_iosTests/godot_iosTests.m35
-rw-r--r--tools/osx_template.app/Contents/Resources/icon.icnsbin294521 -> 260598 bytes
-rw-r--r--tools/pck/SCsub1
-rw-r--r--tools/pck/pck_packer.cpp2
-rw-r--r--tools/pe_bliss/README84
-rw-r--r--tools/pe_bliss/SCsub5
-rw-r--r--tools/pe_bliss/entropy.cpp111
-rw-r--r--tools/pe_bliss/entropy.h51
-rw-r--r--tools/pe_bliss/file_version_info.cpp440
-rw-r--r--tools/pe_bliss/file_version_info.h199
-rw-r--r--tools/pe_bliss/message_table.cpp81
-rw-r--r--tools/pe_bliss/message_table.h56
-rw-r--r--tools/pe_bliss/pe_base.cpp1680
-rw-r--r--tools/pe_bliss/pe_base.h544
-rw-r--r--tools/pe_bliss/pe_bliss.h39
-rw-r--r--tools/pe_bliss/pe_bliss_godot.cpp118
-rw-r--r--tools/pe_bliss/pe_bliss_godot.h7
-rw-r--r--tools/pe_bliss/pe_bliss_resources.h36
-rw-r--r--tools/pe_bliss/pe_bound_import.cpp311
-rw-r--r--tools/pe_bliss/pe_bound_import.h108
-rw-r--r--tools/pe_bliss/pe_checksum.cpp103
-rw-r--r--tools/pe_bliss/pe_checksum.h30
-rw-r--r--tools/pe_bliss/pe_debug.cpp865
-rw-r--r--tools/pe_bliss/pe_debug.h324
-rw-r--r--tools/pe_bliss/pe_directory.cpp59
-rw-r--r--tools/pe_bliss/pe_directory.h50
-rw-r--r--tools/pe_bliss/pe_dotnet.cpp186
-rw-r--r--tools/pe_bliss/pe_dotnet.h97
-rw-r--r--tools/pe_bliss/pe_exception.cpp40
-rw-r--r--tools/pe_bliss/pe_exception.h130
-rw-r--r--tools/pe_bliss/pe_exception_directory.cpp177
-rw-r--r--tools/pe_bliss/pe_exception_directory.h88
-rw-r--r--tools/pe_bliss/pe_exports.cpp700
-rw-r--r--tools/pe_bliss/pe_exports.h184
-rw-r--r--tools/pe_bliss/pe_factory.cpp43
-rw-r--r--tools/pe_bliss/pe_factory.h39
-rw-r--r--tools/pe_bliss/pe_imports.cpp777
-rw-r--r--tools/pe_bliss/pe_imports.h208
-rw-r--r--tools/pe_bliss/pe_load_config.cpp557
-rw-r--r--tools/pe_bliss/pe_load_config.h184
-rw-r--r--tools/pe_bliss/pe_properties.cpp41
-rw-r--r--tools/pe_bliss/pe_properties.h236
-rw-r--r--tools/pe_bliss/pe_properties_generic.cpp645
-rw-r--r--tools/pe_bliss/pe_properties_generic.h277
-rw-r--r--tools/pe_bliss/pe_rebuilder.cpp214
-rw-r--r--tools/pe_bliss/pe_rebuilder.h40
-rw-r--r--tools/pe_bliss/pe_relocations.cpp320
-rw-r--r--tools/pe_bliss/pe_relocations.h122
-rw-r--r--tools/pe_bliss/pe_resource_manager.cpp286
-rw-r--r--tools/pe_bliss/pe_resource_manager.h113
-rw-r--r--tools/pe_bliss/pe_resource_viewer.cpp382
-rw-r--r--tools/pe_bliss/pe_resource_viewer.h153
-rw-r--r--tools/pe_bliss/pe_resources.cpp726
-rw-r--r--tools/pe_bliss/pe_resources.h245
-rw-r--r--tools/pe_bliss/pe_rich_data.cpp152
-rw-r--r--tools/pe_bliss/pe_rich_data.h58
-rw-r--r--tools/pe_bliss/pe_section.cpp303
-rw-r--r--tools/pe_bliss/pe_section.h158
-rw-r--r--tools/pe_bliss/pe_structures.h1028
-rw-r--r--tools/pe_bliss/pe_tls.cpp396
-rw-r--r--tools/pe_bliss/pe_tls.h122
-rw-r--r--tools/pe_bliss/resource_bitmap_reader.cpp86
-rw-r--r--tools/pe_bliss/resource_bitmap_reader.h50
-rw-r--r--tools/pe_bliss/resource_bitmap_writer.cpp75
-rw-r--r--tools/pe_bliss/resource_bitmap_writer.h47
-rw-r--r--tools/pe_bliss/resource_cursor_icon_reader.cpp521
-rw-r--r--tools/pe_bliss/resource_cursor_icon_reader.h84
-rw-r--r--tools/pe_bliss/resource_cursor_icon_writer.cpp447
-rw-r--r--tools/pe_bliss/resource_cursor_icon_writer.h94
-rw-r--r--tools/pe_bliss/resource_data_info.cpp48
-rw-r--r--tools/pe_bliss/resource_data_info.h48
-rw-r--r--tools/pe_bliss/resource_internal.h34
-rw-r--r--tools/pe_bliss/resource_message_list_reader.cpp131
-rw-r--r--tools/pe_bliss/resource_message_list_reader.h49
-rw-r--r--tools/pe_bliss/resource_string_table_reader.cpp109
-rw-r--r--tools/pe_bliss/resource_string_table_reader.h57
-rw-r--r--tools/pe_bliss/resource_version_info_reader.cpp311
-rw-r--r--tools/pe_bliss/resource_version_info_reader.h67
-rw-r--r--tools/pe_bliss/resource_version_info_writer.cpp283
-rw-r--r--tools/pe_bliss/resource_version_info_writer.h52
-rw-r--r--tools/pe_bliss/stdint_defs.h45
-rw-r--r--tools/pe_bliss/utils.cpp85
-rw-r--r--tools/pe_bliss/utils.h105
-rw-r--r--tools/pe_bliss/version_info_editor.cpp184
-rw-r--r--tools/pe_bliss/version_info_editor.h79
-rw-r--r--tools/pe_bliss/version_info_types.h38
-rw-r--r--tools/pe_bliss/version_info_viewer.cpp180
-rw-r--r--tools/pe_bliss/version_info_viewer.h89
-rwxr-xr-xtools/scripts/file-hex-array.py52
-rw-r--r--version.py7
2926 files changed, 270503 insertions, 195109 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000000..f1e99ee8ca
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,4 @@
+*.cpp eol=lf
+*.h eol=lf
+*.py eol=lf
+*.hpp eol=lf
diff --git a/.gitignore b/.gitignore
index 613eff442a..a6d5a2d412 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,6 +15,7 @@ core/method_bind.inc
core/method_bind_ext.inc
core/script_encryption_key.cpp
core/global_defaults.cpp
+drivers/unix/os_unix_global_settings_path.cpp
tools/editor/register_exporters.cpp
tools/editor/doc_data_compressed.h
tools/editor/editor_icons.cpp
@@ -23,6 +24,9 @@ tools/editor/editor_icons.cpp
make.bat
log.txt
+# Documentation generated by doxygen or from classes.xml
+doc/_build/
+
# Javascript specific
*.bc
@@ -50,6 +54,14 @@ platform/android/libs/play_licensing/gen/*
*.d
*.so
*.os
+*.Plo
+*.lo
+*.Po
+
+# Libs generated files
+.deps/*
+.dirstamp
+
# QT project files
*.config
@@ -73,6 +85,8 @@ platform/android/libs/play_licensing/gen/*
*.suo
*.user
*.sln.docstates
+*.sln
+*.vcxproj*
# Build results
[Dd]ebug/
@@ -175,9 +189,6 @@ AutoTest.Net/
# Installshield output folder
[Ee]xpress/
-# dumpdoc generated files
-doc/html/class_list
-
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
@@ -282,4 +293,5 @@ cscope.in.out
cscope.po.out
godot.creator.*
-projects/ \ No newline at end of file
+projects/
+platform/windows/godot_res.res
diff --git a/.travis.yml b/.travis.yml
index 6dd21dae0b..13f91b99e8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,14 +1,48 @@
language: cpp
-compiler:
+
+sudo: required
+dist: trusty
+
+compiler:
- gcc
-before_install:
-
-
-before_script:
- - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
- - sudo apt-get update -qq
- - sudo apt-get install -qq scons pkg-config libx11-dev libxcursor-dev build-essential libasound2-dev libfreetype6-dev libgl1-mesa-dev libglu-dev
- - if [ "$CXX" = "g++" ]; then sudo apt-get install -qq g++-4.8; fi
- - if [ "$CXX" = "g++" ]; then export CXX="g++-4.8" CC="gcc-4.8"; fi
-
-script: scons platform=x11
+ - clang
+
+os:
+ - linux
+ - osx
+
+env:
+ - GODOT_TARGET=iphone
+ - GODOT_TARGET=osx
+ - GODOT_TARGET=x11
+ - GODOT_TARGET=android
+ - GODOT_TARGET=windows
+
+matrix:
+ exclude:
+ - os: linux
+ env: GODOT_TARGET=iphone
+ - os: linux
+ env: GODOT_TARGET=osx
+ - os: linux
+ env: GODOT_TARGET=android
+ - os: osx
+ env: GODOT_TARGET=x11
+ - os: osx
+ env: GODOT_TARGET=windows
+ - compiler: gcc
+ env: GODOT_TARGET=iphone
+ - compiler: clang
+ env: GODOT_TARGET=android
+ - compiler: clang
+ env: GODOT_TARGET=windows
+
+
+before_script:
+ - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get update -qq; sudo apt-get install -y scons pkg-config libx11-dev libxcursor-dev build-essential libasound2-dev libfreetype6-dev libgl1-mesa-dev libglu-dev libssl-dev libxinerama-dev libevdev-dev libudev-dev; fi
+ - if [ "$TRAVIS_OS_NAME" = "linux" ] && [ "$GODOT_TARGET" = "windows" ]; then sudo apt-get update -qq; sudo apt-get install -y mingw32 mingw-w64; fi
+ - if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update; brew install scons; fi
+ - if [ "$TRAVIS_OS_NAME" = "osx" ] && [ "$GODOT_TARGET" = "android" ]; then brew update; brew install android-sdk android-ndk; export ANDROID_HOME=/usr/local/opt/android-sdk; export ANDROID_NDK_ROOT=/usr/local/opt/android-ndk; fi
+
+script:
+ - scons platform=$GODOT_TARGET CXX=$CXX
diff --git a/Doxyfile b/Doxyfile
deleted file mode 100644
index c32a1bf195..0000000000
--- a/Doxyfile
+++ /dev/null
@@ -1,2432 +0,0 @@
-# Doxyfile 1.8.9.1
-
-# This file describes the settings to be used by the documentation system
-# doxygen (www.doxygen.org) for a project.
-#
-# All text after a double hash (##) is considered a comment and is placed in
-# front of the TAG it is preceding.
-#
-# All text after a single hash (#) is considered a comment and will be ignored.
-# The format is:
-# TAG = value [value, ...]
-# For lists, items can also be appended using:
-# TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (\" \").
-
-#---------------------------------------------------------------------------
-# Project related configuration options
-#---------------------------------------------------------------------------
-
-# This tag specifies the encoding used for all characters in the config file
-# that follow. The default is UTF-8 which is also the encoding used for all text
-# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
-# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
-# for the list of possible encodings.
-# The default value is: UTF-8.
-
-DOXYFILE_ENCODING = UTF-8
-
-# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
-# double-quotes, unless you are using Doxywizard) that should identify the
-# project for which the documentation is generated. This name is used in the
-# title of most generated pages and in a few other places.
-# The default value is: My Project.
-
-PROJECT_NAME = Godot
-
-# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
-# could be handy for archiving the generated documentation or if some version
-# control system is used.
-
-PROJECT_NUMBER =
-
-# Using the PROJECT_BRIEF tag one can provide an optional one line description
-# for a project that appears at the top of each page and should give viewer a
-# quick idea about the purpose of the project. Keep the description short.
-
-PROJECT_BRIEF = "Game Engine MIT"
-
-# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
-# in the documentation. The maximum height of the logo should not exceed 55
-# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
-# the logo to the output directory.
-
-PROJECT_LOGO = E:/development/godot/logo_small.png
-
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
-# into which the generated documentation will be written. If a relative path is
-# entered, it will be relative to the location where doxygen was started. If
-# left blank the current directory will be used.
-
-OUTPUT_DIRECTORY = E:/development/godot/doxygen
-
-# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
-# directories (in 2 levels) under the output directory of each output format and
-# will distribute the generated files over these directories. Enabling this
-# option can be useful when feeding doxygen a huge amount of source files, where
-# putting all generated files in the same directory would otherwise causes
-# performance problems for the file system.
-# The default value is: NO.
-
-CREATE_SUBDIRS = NO
-
-# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
-# characters to appear in the names of generated files. If set to NO, non-ASCII
-# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
-# U+3044.
-# The default value is: NO.
-
-ALLOW_UNICODE_NAMES = NO
-
-# The OUTPUT_LANGUAGE tag is used to specify the language in which all
-# documentation generated by doxygen is written. Doxygen will use this
-# information to generate all constant output in the proper language.
-# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
-# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
-# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
-# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
-# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
-# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
-# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
-# Ukrainian and Vietnamese.
-# The default value is: English.
-
-OUTPUT_LANGUAGE = English
-
-# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
-# descriptions after the members that are listed in the file and class
-# documentation (similar to Javadoc). Set to NO to disable this.
-# The default value is: YES.
-
-BRIEF_MEMBER_DESC = YES
-
-# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
-# description of a member or function before the detailed description
-#
-# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
-# brief descriptions will be completely suppressed.
-# The default value is: YES.
-
-REPEAT_BRIEF = YES
-
-# This tag implements a quasi-intelligent brief description abbreviator that is
-# used to form the text in various listings. Each string in this list, if found
-# as the leading text of the brief description, will be stripped from the text
-# and the result, after processing the whole list, is used as the annotated
-# text. Otherwise, the brief description is used as-is. If left blank, the
-# following values are used ($name is automatically replaced with the name of
-# the entity):The $name class, The $name widget, The $name file, is, provides,
-# specifies, contains, represents, a, an and the.
-
-ABBREVIATE_BRIEF = "The $name class" \
- "The $name widget" \
- "The $name file" \
- is \
- provides \
- specifies \
- contains \
- represents \
- a \
- an \
- the
-
-# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# doxygen will generate a detailed section even if there is only a brief
-# description.
-# The default value is: NO.
-
-ALWAYS_DETAILED_SEC = NO
-
-# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
-# inherited members of a class in the documentation of that class as if those
-# members were ordinary class members. Constructors, destructors and assignment
-# operators of the base classes will not be shown.
-# The default value is: NO.
-
-INLINE_INHERITED_MEMB = NO
-
-# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
-# before files name in the file list and in the header files. If set to NO the
-# shortest path that makes the file name unique will be used
-# The default value is: YES.
-
-FULL_PATH_NAMES = YES
-
-# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
-# Stripping is only done if one of the specified strings matches the left-hand
-# part of the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the path to
-# strip.
-#
-# Note that you can specify absolute paths here, but also relative paths, which
-# will be relative from the directory where doxygen is started.
-# This tag requires that the tag FULL_PATH_NAMES is set to YES.
-
-STRIP_FROM_PATH =
-
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
-# path mentioned in the documentation of a class, which tells the reader which
-# header file to include in order to use a class. If left blank only the name of
-# the header file containing the class definition is used. Otherwise one should
-# specify the list of include paths that are normally passed to the compiler
-# using the -I flag.
-
-STRIP_FROM_INC_PATH =
-
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
-# less readable) file names. This can be useful is your file systems doesn't
-# support long names like on DOS, Mac, or CD-ROM.
-# The default value is: NO.
-
-SHORT_NAMES = NO
-
-# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
-# first line (until the first dot) of a Javadoc-style comment as the brief
-# description. If set to NO, the Javadoc-style will behave just like regular Qt-
-# style comments (thus requiring an explicit @brief command for a brief
-# description.)
-# The default value is: NO.
-
-JAVADOC_AUTOBRIEF = NO
-
-# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
-# line (until the first dot) of a Qt-style comment as the brief description. If
-# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
-# requiring an explicit \brief command for a brief description.)
-# The default value is: NO.
-
-QT_AUTOBRIEF = NO
-
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
-# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
-# a brief description. This used to be the default behavior. The new default is
-# to treat a multi-line C++ comment block as a detailed description. Set this
-# tag to YES if you prefer the old behavior instead.
-#
-# Note that setting this tag to YES also means that rational rose comments are
-# not recognized any more.
-# The default value is: NO.
-
-MULTILINE_CPP_IS_BRIEF = NO
-
-# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
-# documentation from any documented member that it re-implements.
-# The default value is: YES.
-
-INHERIT_DOCS = YES
-
-# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
-# page for each member. If set to NO, the documentation of a member will be part
-# of the file/class/namespace that contains it.
-# The default value is: NO.
-
-SEPARATE_MEMBER_PAGES = NO
-
-# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
-# uses this value to replace tabs by spaces in code fragments.
-# Minimum value: 1, maximum value: 16, default value: 4.
-
-TAB_SIZE = 4
-
-# This tag can be used to specify a number of aliases that act as commands in
-# the documentation. An alias has the form:
-# name=value
-# For example adding
-# "sideeffect=@par Side Effects:\n"
-# will allow you to put the command \sideeffect (or @sideeffect) in the
-# documentation, which will result in a user-defined paragraph with heading
-# "Side Effects:". You can put \n's in the value part of an alias to insert
-# newlines.
-
-ALIASES =
-
-# This tag can be used to specify a number of word-keyword mappings (TCL only).
-# A mapping has the form "name=value". For example adding "class=itcl::class"
-# will allow you to use the command class in the itcl::class meaning.
-
-TCL_SUBST =
-
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
-# only. Doxygen will then generate output that is more tailored for C. For
-# instance, some of the names that are used will be different. The list of all
-# members will be omitted, etc.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_FOR_C = NO
-
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
-# Python sources only. Doxygen will then generate output that is more tailored
-# for that language. For instance, namespaces will be presented as packages,
-# qualified scopes will look different, etc.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_JAVA = NO
-
-# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
-# sources. Doxygen will then generate output that is tailored for Fortran.
-# The default value is: NO.
-
-OPTIMIZE_FOR_FORTRAN = NO
-
-# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
-# sources. Doxygen will then generate output that is tailored for VHDL.
-# The default value is: NO.
-
-OPTIMIZE_OUTPUT_VHDL = NO
-
-# Doxygen selects the parser to use depending on the extension of the files it
-# parses. With this tag you can assign which parser to use for a given
-# extension. Doxygen has a built-in mapping, but you can override or extend it
-# using this tag. The format is ext=language, where ext is a file extension, and
-# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
-# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
-# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
-# Fortran. In the later case the parser tries to guess whether the code is fixed
-# or free formatted code, this is the default for Fortran type files), VHDL. For
-# instance to make doxygen treat .inc files as Fortran files (default is PHP),
-# and .f files as C (default is Fortran), use: inc=Fortran f=C.
-#
-# Note: For files without extension you can use no_extension as a placeholder.
-#
-# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
-# the files are not read by doxygen.
-
-EXTENSION_MAPPING =
-
-# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
-# according to the Markdown format, which allows for more readable
-# documentation. See http://daringfireball.net/projects/markdown/ for details.
-# The output of markdown processing is further processed by doxygen, so you can
-# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
-# case of backward compatibilities issues.
-# The default value is: YES.
-
-MARKDOWN_SUPPORT = YES
-
-# When enabled doxygen tries to link words that correspond to documented
-# classes, or namespaces to their corresponding documentation. Such a link can
-# be prevented in individual cases by putting a % sign in front of the word or
-# globally by setting AUTOLINK_SUPPORT to NO.
-# The default value is: YES.
-
-AUTOLINK_SUPPORT = YES
-
-# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
-# to include (a tag file for) the STL sources as input, then you should set this
-# tag to YES in order to let doxygen match functions declarations and
-# definitions whose arguments contain STL classes (e.g. func(std::string);
-# versus func(std::string) {}). This also make the inheritance and collaboration
-# diagrams that involve STL classes more complete and accurate.
-# The default value is: NO.
-
-BUILTIN_STL_SUPPORT = NO
-
-# If you use Microsoft's C++/CLI language, you should set this option to YES to
-# enable parsing support.
-# The default value is: NO.
-
-CPP_CLI_SUPPORT = NO
-
-# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
-# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
-# will parse them like normal C++ but will assume all classes use public instead
-# of private inheritance when no explicit protection keyword is present.
-# The default value is: NO.
-
-SIP_SUPPORT = NO
-
-# For Microsoft's IDL there are propget and propput attributes to indicate
-# getter and setter methods for a property. Setting this option to YES will make
-# doxygen to replace the get and set methods by a property in the documentation.
-# This will only work if the methods are indeed getting or setting a simple
-# type. If this is not the case, or you want to show the methods anyway, you
-# should set this option to NO.
-# The default value is: YES.
-
-IDL_PROPERTY_SUPPORT = YES
-
-# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
-# tag is set to YES then doxygen will reuse the documentation of the first
-# member in the group (if any) for the other members of the group. By default
-# all members of a group must be documented explicitly.
-# The default value is: NO.
-
-DISTRIBUTE_GROUP_DOC = NO
-
-# Set the SUBGROUPING tag to YES to allow class member groups of the same type
-# (for instance a group of public functions) to be put as a subgroup of that
-# type (e.g. under the Public Functions section). Set it to NO to prevent
-# subgrouping. Alternatively, this can be done per class using the
-# \nosubgrouping command.
-# The default value is: YES.
-
-SUBGROUPING = YES
-
-# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
-# are shown inside the group in which they are included (e.g. using \ingroup)
-# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
-# and RTF).
-#
-# Note that this feature does not work in combination with
-# SEPARATE_MEMBER_PAGES.
-# The default value is: NO.
-
-INLINE_GROUPED_CLASSES = NO
-
-# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
-# with only public data fields or simple typedef fields will be shown inline in
-# the documentation of the scope in which they are defined (i.e. file,
-# namespace, or group documentation), provided this scope is documented. If set
-# to NO, structs, classes, and unions are shown on a separate page (for HTML and
-# Man pages) or section (for LaTeX and RTF).
-# The default value is: NO.
-
-INLINE_SIMPLE_STRUCTS = NO
-
-# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
-# enum is documented as struct, union, or enum with the name of the typedef. So
-# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
-# with name TypeT. When disabled the typedef will appear as a member of a file,
-# namespace, or class. And the struct will be named TypeS. This can typically be
-# useful for C code in case the coding convention dictates that all compound
-# types are typedef'ed and only the typedef is referenced, never the tag name.
-# The default value is: NO.
-
-TYPEDEF_HIDES_STRUCT = NO
-
-# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
-# cache is used to resolve symbols given their name and scope. Since this can be
-# an expensive process and often the same symbol appears multiple times in the
-# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
-# doxygen will become slower. If the cache is too large, memory is wasted. The
-# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
-# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
-# symbols. At the end of a run doxygen will report the cache usage and suggest
-# the optimal cache size from a speed point of view.
-# Minimum value: 0, maximum value: 9, default value: 0.
-
-LOOKUP_CACHE_SIZE = 0
-
-#---------------------------------------------------------------------------
-# Build related configuration options
-#---------------------------------------------------------------------------
-
-# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
-# documentation are documented, even if no documentation was available. Private
-# class members and static file members will be hidden unless the
-# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
-# Note: This will also disable the warnings about undocumented members that are
-# normally produced when WARNINGS is set to YES.
-# The default value is: NO.
-
-EXTRACT_ALL = NO
-
-# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
-# be included in the documentation.
-# The default value is: NO.
-
-EXTRACT_PRIVATE = NO
-
-# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
-# scope will be included in the documentation.
-# The default value is: NO.
-
-EXTRACT_PACKAGE = NO
-
-# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
-# included in the documentation.
-# The default value is: NO.
-
-EXTRACT_STATIC = NO
-
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
-# locally in source files will be included in the documentation. If set to NO,
-# only classes defined in header files are included. Does not have any effect
-# for Java sources.
-# The default value is: YES.
-
-EXTRACT_LOCAL_CLASSES = YES
-
-# This flag is only useful for Objective-C code. If set to YES, local methods,
-# which are defined in the implementation section but not in the interface are
-# included in the documentation. If set to NO, only methods in the interface are
-# included.
-# The default value is: NO.
-
-EXTRACT_LOCAL_METHODS = NO
-
-# If this flag is set to YES, the members of anonymous namespaces will be
-# extracted and appear in the documentation as a namespace called
-# 'anonymous_namespace{file}', where file will be replaced with the base name of
-# the file that contains the anonymous namespace. By default anonymous namespace
-# are hidden.
-# The default value is: NO.
-
-EXTRACT_ANON_NSPACES = NO
-
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
-# undocumented members inside documented classes or files. If set to NO these
-# members will be included in the various overviews, but no documentation
-# section is generated. This option has no effect if EXTRACT_ALL is enabled.
-# The default value is: NO.
-
-HIDE_UNDOC_MEMBERS = NO
-
-# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy. If set
-# to NO, these classes will be included in the various overviews. This option
-# has no effect if EXTRACT_ALL is enabled.
-# The default value is: NO.
-
-HIDE_UNDOC_CLASSES = NO
-
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
-# (class|struct|union) declarations. If set to NO, these declarations will be
-# included in the documentation.
-# The default value is: NO.
-
-HIDE_FRIEND_COMPOUNDS = NO
-
-# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
-# documentation blocks found inside the body of a function. If set to NO, these
-# blocks will be appended to the function's detailed documentation block.
-# The default value is: NO.
-
-HIDE_IN_BODY_DOCS = NO
-
-# The INTERNAL_DOCS tag determines if documentation that is typed after a
-# \internal command is included. If the tag is set to NO then the documentation
-# will be excluded. Set it to YES to include the internal documentation.
-# The default value is: NO.
-
-INTERNAL_DOCS = NO
-
-# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
-# names in lower-case letters. If set to YES, upper-case letters are also
-# allowed. This is useful if you have classes or files whose names only differ
-# in case and if your file system supports case sensitive file names. Windows
-# and Mac users are advised to set this option to NO.
-# The default value is: system dependent.
-
-CASE_SENSE_NAMES = NO
-
-# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
-# their full class and namespace scopes in the documentation. If set to YES, the
-# scope will be hidden.
-# The default value is: NO.
-
-HIDE_SCOPE_NAMES = NO
-
-# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
-# append additional text to a page's title, such as Class Reference. If set to
-# YES the compound reference will be hidden.
-# The default value is: NO.
-
-HIDE_COMPOUND_REFERENCE= NO
-
-# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
-# the files that are included by a file in the documentation of that file.
-# The default value is: YES.
-
-SHOW_INCLUDE_FILES = YES
-
-# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
-# grouped member an include statement to the documentation, telling the reader
-# which file to include in order to use the member.
-# The default value is: NO.
-
-SHOW_GROUPED_MEMB_INC = NO
-
-# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
-# files with double quotes in the documentation rather than with sharp brackets.
-# The default value is: NO.
-
-FORCE_LOCAL_INCLUDES = NO
-
-# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
-# documentation for inline members.
-# The default value is: YES.
-
-INLINE_INFO = YES
-
-# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
-# (detailed) documentation of file and class members alphabetically by member
-# name. If set to NO, the members will appear in declaration order.
-# The default value is: YES.
-
-SORT_MEMBER_DOCS = YES
-
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
-# descriptions of file, namespace and class members alphabetically by member
-# name. If set to NO, the members will appear in declaration order. Note that
-# this will also influence the order of the classes in the class list.
-# The default value is: NO.
-
-SORT_BRIEF_DOCS = NO
-
-# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
-# (brief and detailed) documentation of class members so that constructors and
-# destructors are listed first. If set to NO the constructors will appear in the
-# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
-# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
-# member documentation.
-# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
-# detailed member documentation.
-# The default value is: NO.
-
-SORT_MEMBERS_CTORS_1ST = NO
-
-# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
-# of group names into alphabetical order. If set to NO the group names will
-# appear in their defined order.
-# The default value is: NO.
-
-SORT_GROUP_NAMES = NO
-
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
-# fully-qualified names, including namespaces. If set to NO, the class list will
-# be sorted only by class name, not including the namespace part.
-# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the alphabetical
-# list.
-# The default value is: NO.
-
-SORT_BY_SCOPE_NAME = NO
-
-# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
-# type resolution of all parameters of a function it will reject a match between
-# the prototype and the implementation of a member function even if there is
-# only one candidate or it is obvious which candidate to choose by doing a
-# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
-# accept a match between prototype and implementation in such cases.
-# The default value is: NO.
-
-STRICT_PROTO_MATCHING = NO
-
-# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
-# list. This list is created by putting \todo commands in the documentation.
-# The default value is: YES.
-
-GENERATE_TODOLIST = YES
-
-# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
-# list. This list is created by putting \test commands in the documentation.
-# The default value is: YES.
-
-GENERATE_TESTLIST = YES
-
-# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
-# list. This list is created by putting \bug commands in the documentation.
-# The default value is: YES.
-
-GENERATE_BUGLIST = YES
-
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
-# the deprecated list. This list is created by putting \deprecated commands in
-# the documentation.
-# The default value is: YES.
-
-GENERATE_DEPRECATEDLIST= YES
-
-# The ENABLED_SECTIONS tag can be used to enable conditional documentation
-# sections, marked by \if <section_label> ... \endif and \cond <section_label>
-# ... \endcond blocks.
-
-ENABLED_SECTIONS =
-
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
-# initial value of a variable or macro / define can have for it to appear in the
-# documentation. If the initializer consists of more lines than specified here
-# it will be hidden. Use a value of 0 to hide initializers completely. The
-# appearance of the value of individual variables and macros / defines can be
-# controlled using \showinitializer or \hideinitializer command in the
-# documentation regardless of this setting.
-# Minimum value: 0, maximum value: 10000, default value: 30.
-
-MAX_INITIALIZER_LINES = 30
-
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
-# the bottom of the documentation of classes and structs. If set to YES, the
-# list will mention the files that were used to generate the documentation.
-# The default value is: YES.
-
-SHOW_USED_FILES = YES
-
-# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
-# will remove the Files entry from the Quick Index and from the Folder Tree View
-# (if specified).
-# The default value is: YES.
-
-SHOW_FILES = YES
-
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
-# page. This will remove the Namespaces entry from the Quick Index and from the
-# Folder Tree View (if specified).
-# The default value is: YES.
-
-SHOW_NAMESPACES = YES
-
-# The FILE_VERSION_FILTER tag can be used to specify a program or script that
-# doxygen should invoke to get the current version for each file (typically from
-# the version control system). Doxygen will invoke the program by executing (via
-# popen()) the command command input-file, where command is the value of the
-# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
-# by doxygen. Whatever the program writes to standard output is used as the file
-# version. For an example see the documentation.
-
-FILE_VERSION_FILTER =
-
-# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
-# by doxygen. The layout file controls the global structure of the generated
-# output files in an output format independent way. To create the layout file
-# that represents doxygen's defaults, run doxygen with the -l option. You can
-# optionally specify a file name after the option, if omitted DoxygenLayout.xml
-# will be used as the name of the layout file.
-#
-# Note that if you run doxygen from a directory containing a file called
-# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
-# tag is left empty.
-
-LAYOUT_FILE =
-
-# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
-# the reference definitions. This must be a list of .bib files. The .bib
-# extension is automatically appended if omitted. This requires the bibtex tool
-# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
-# For LaTeX the style of the bibliography can be controlled using
-# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
-# search path. See also \cite for info how to create references.
-
-CITE_BIB_FILES =
-
-#---------------------------------------------------------------------------
-# Configuration options related to warning and progress messages
-#---------------------------------------------------------------------------
-
-# The QUIET tag can be used to turn on/off the messages that are generated to
-# standard output by doxygen. If QUIET is set to YES this implies that the
-# messages are off.
-# The default value is: NO.
-
-QUIET = NO
-
-# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
-# this implies that the warnings are on.
-#
-# Tip: Turn warnings on while writing the documentation.
-# The default value is: YES.
-
-WARNINGS = YES
-
-# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
-# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
-# will automatically be disabled.
-# The default value is: YES.
-
-WARN_IF_UNDOCUMENTED = YES
-
-# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some parameters
-# in a documented function, or documenting parameters that don't exist or using
-# markup commands wrongly.
-# The default value is: YES.
-
-WARN_IF_DOC_ERROR = YES
-
-# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
-# are documented, but have no documentation for their parameters or return
-# value. If set to NO, doxygen will only warn about wrong or incomplete
-# parameter documentation, but not about the absence of documentation.
-# The default value is: NO.
-
-WARN_NO_PARAMDOC = NO
-
-# The WARN_FORMAT tag determines the format of the warning messages that doxygen
-# can produce. The string should contain the $file, $line, and $text tags, which
-# will be replaced by the file and line number from which the warning originated
-# and the warning text. Optionally the format may contain $version, which will
-# be replaced by the version of the file (if it could be obtained via
-# FILE_VERSION_FILTER)
-# The default value is: $file:$line: $text.
-
-WARN_FORMAT = "$file:$line: $text"
-
-# The WARN_LOGFILE tag can be used to specify a file to which warning and error
-# messages should be written. If left blank the output is written to standard
-# error (stderr).
-
-WARN_LOGFILE =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the input files
-#---------------------------------------------------------------------------
-
-# The INPUT tag is used to specify the files and/or directories that contain
-# documented source files. You may enter file names like myfile.cpp or
-# directories like /usr/src/myproject. Separate the files or directories with
-# spaces.
-# Note: If this tag is empty the current directory is searched.
-
-INPUT = E:/development/godot
-
-# This tag can be used to specify the character encoding of the source files
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
-# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
-# documentation (see: http://www.gnu.org/software/libiconv) for the list of
-# possible encodings.
-# The default value is: UTF-8.
-
-INPUT_ENCODING = UTF-8
-
-# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
-# *.h) to filter out the source-files in the directories. If left blank the
-# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
-# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
-# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
-# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
-# *.qsf, *.as and *.js.
-
-FILE_PATTERNS = *.c \
- *.cc \
- *.cxx \
- *.cpp \
- *.c++ \
- *.java \
- *.ii \
- *.ixx \
- *.ipp \
- *.i++ \
- *.inl \
- *.idl \
- *.ddl \
- *.odl \
- *.h \
- *.hh \
- *.hxx \
- *.hpp \
- *.h++ \
- *.cs \
- *.d \
- *.php \
- *.php4 \
- *.php5 \
- *.phtml \
- *.inc \
- *.m \
- *.markdown \
- *.md \
- *.mm \
- *.dox \
- *.py \
- *.f90 \
- *.f \
- *.for \
- *.tcl \
- *.vhd \
- *.vhdl \
- *.ucf \
- *.qsf \
- *.as \
- *.js
-
-# The RECURSIVE tag can be used to specify whether or not subdirectories should
-# be searched for input files as well.
-# The default value is: NO.
-
-RECURSIVE = YES
-
-# The EXCLUDE tag can be used to specify files and/or directories that should be
-# excluded from the INPUT source files. This way you can easily exclude a
-# subdirectory from a directory tree whose root is specified with the INPUT tag.
-#
-# Note that relative paths are relative to the directory from which doxygen is
-# run.
-
-EXCLUDE =
-
-# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
-# directories that are symbolic links (a Unix file system feature) are excluded
-# from the input.
-# The default value is: NO.
-
-EXCLUDE_SYMLINKS = NO
-
-# If the value of the INPUT tag contains directories, you can use the
-# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories.
-#
-# Note that the wildcards are matched against the file with absolute path, so to
-# exclude all test directories for example use the pattern */test/*
-
-EXCLUDE_PATTERNS =
-
-# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
-# (namespaces, classes, functions, etc.) that should be excluded from the
-# output. The symbol name can be a fully qualified name, a word, or if the
-# wildcard * is used, a substring. Examples: ANamespace, AClass,
-# AClass::ANamespace, ANamespace::*Test
-#
-# Note that the wildcards are matched against the file with absolute path, so to
-# exclude all test directories use the pattern */test/*
-
-EXCLUDE_SYMBOLS =
-
-# The EXAMPLE_PATH tag can be used to specify one or more files or directories
-# that contain example code fragments that are included (see the \include
-# command).
-
-EXAMPLE_PATH =
-
-# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
-# *.h) to filter out the source-files in the directories. If left blank all
-# files are included.
-
-EXAMPLE_PATTERNS = *
-
-# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude commands
-# irrespective of the value of the RECURSIVE tag.
-# The default value is: NO.
-
-EXAMPLE_RECURSIVE = NO
-
-# The IMAGE_PATH tag can be used to specify one or more files or directories
-# that contain images that are to be included in the documentation (see the
-# \image command).
-
-IMAGE_PATH =
-
-# The INPUT_FILTER tag can be used to specify a program that doxygen should
-# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command:
-#
-# <filter> <input-file>
-#
-# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
-# name of an input file. Doxygen will then use the output that the filter
-# program writes to standard output. If FILTER_PATTERNS is specified, this tag
-# will be ignored.
-#
-# Note that the filter must not add or remove lines; it is applied before the
-# code is scanned, but not when the output code is generated. If lines are added
-# or removed, the anchors will not be placed correctly.
-
-INPUT_FILTER =
-
-# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
-# basis. Doxygen will compare the file name with each pattern and apply the
-# filter if there is a match. The filters are a list of the form: pattern=filter
-# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
-# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
-# patterns match the file name, INPUT_FILTER is applied.
-
-FILTER_PATTERNS =
-
-# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER) will also be used to filter the input files that are used for
-# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
-# The default value is: NO.
-
-FILTER_SOURCE_FILES = NO
-
-# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
-# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
-# it is also possible to disable source filtering for a specific pattern using
-# *.ext= (so without naming a filter).
-# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
-
-FILTER_SOURCE_PATTERNS =
-
-# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
-# is part of the input, its contents will be placed on the main page
-# (index.html). This can be useful if you have a project on for instance GitHub
-# and want to reuse the introduction page also for the doxygen output.
-
-USE_MDFILE_AS_MAINPAGE = README.md
-
-#---------------------------------------------------------------------------
-# Configuration options related to source browsing
-#---------------------------------------------------------------------------
-
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
-# generated. Documented entities will be cross-referenced with these sources.
-#
-# Note: To get rid of all source code in the generated output, make sure that
-# also VERBATIM_HEADERS is set to NO.
-# The default value is: NO.
-
-SOURCE_BROWSER = NO
-
-# Setting the INLINE_SOURCES tag to YES will include the body of functions,
-# classes and enums directly into the documentation.
-# The default value is: NO.
-
-INLINE_SOURCES = NO
-
-# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
-# special comment blocks from generated source code fragments. Normal C, C++ and
-# Fortran comments will always remain visible.
-# The default value is: YES.
-
-STRIP_CODE_COMMENTS = YES
-
-# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
-# function all documented functions referencing it will be listed.
-# The default value is: NO.
-
-REFERENCED_BY_RELATION = NO
-
-# If the REFERENCES_RELATION tag is set to YES then for each documented function
-# all documented entities called/used by that function will be listed.
-# The default value is: NO.
-
-REFERENCES_RELATION = NO
-
-# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
-# to YES then the hyperlinks from functions in REFERENCES_RELATION and
-# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
-# link to the documentation.
-# The default value is: YES.
-
-REFERENCES_LINK_SOURCE = YES
-
-# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
-# source code will show a tooltip with additional information such as prototype,
-# brief description and links to the definition and documentation. Since this
-# will make the HTML file larger and loading of large files a bit slower, you
-# can opt to disable this feature.
-# The default value is: YES.
-# This tag requires that the tag SOURCE_BROWSER is set to YES.
-
-SOURCE_TOOLTIPS = YES
-
-# If the USE_HTAGS tag is set to YES then the references to source code will
-# point to the HTML generated by the htags(1) tool instead of doxygen built-in
-# source browser. The htags tool is part of GNU's global source tagging system
-# (see http://www.gnu.org/software/global/global.html). You will need version
-# 4.8.6 or higher.
-#
-# To use it do the following:
-# - Install the latest version of global
-# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
-# - Make sure the INPUT points to the root of the source tree
-# - Run doxygen as normal
-#
-# Doxygen will invoke htags (and that will in turn invoke gtags), so these
-# tools must be available from the command line (i.e. in the search path).
-#
-# The result: instead of the source browser generated by doxygen, the links to
-# source code will now point to the output of htags.
-# The default value is: NO.
-# This tag requires that the tag SOURCE_BROWSER is set to YES.
-
-USE_HTAGS = NO
-
-# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
-# verbatim copy of the header file for each class for which an include is
-# specified. Set to NO to disable this.
-# See also: Section \class.
-# The default value is: YES.
-
-VERBATIM_HEADERS = YES
-
-# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
-# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
-# cost of reduced performance. This can be particularly helpful with template
-# rich C++ code for which doxygen's built-in parser lacks the necessary type
-# information.
-# Note: The availability of this option depends on whether or not doxygen was
-# compiled with the --with-libclang option.
-# The default value is: NO.
-
-CLANG_ASSISTED_PARSING = NO
-
-# If clang assisted parsing is enabled you can provide the compiler with command
-# line options that you would normally use when invoking the compiler. Note that
-# the include paths will already be set by doxygen for the files and directories
-# specified with INPUT and INCLUDE_PATH.
-# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
-
-CLANG_OPTIONS =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the alphabetical class index
-#---------------------------------------------------------------------------
-
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
-# compounds will be generated. Enable this if the project contains a lot of
-# classes, structs, unions or interfaces.
-# The default value is: YES.
-
-ALPHABETICAL_INDEX = YES
-
-# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
-# which the alphabetical index list will be split.
-# Minimum value: 1, maximum value: 20, default value: 5.
-# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
-
-COLS_IN_ALPHA_INDEX = 5
-
-# In case all classes in a project start with a common prefix, all classes will
-# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
-# can be used to specify a prefix (or a list of prefixes) that should be ignored
-# while generating the index headers.
-# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
-
-IGNORE_PREFIX =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the HTML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
-# The default value is: YES.
-
-GENERATE_HTML = YES
-
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: html.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_OUTPUT = html
-
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
-# generated HTML page (for example: .htm, .php, .asp).
-# The default value is: .html.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_FILE_EXTENSION = .html
-
-# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
-# each generated HTML page. If the tag is left blank doxygen will generate a
-# standard header.
-#
-# To get valid HTML the header file that includes any scripts and style sheets
-# that doxygen needs, which is dependent on the configuration options used (e.g.
-# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
-# default header using
-# doxygen -w html new_header.html new_footer.html new_stylesheet.css
-# YourConfigFile
-# and then modify the file new_header.html. See also section "Doxygen usage"
-# for information on how to generate the default header that doxygen normally
-# uses.
-# Note: The header is subject to change so you typically have to regenerate the
-# default header when upgrading to a newer version of doxygen. For a description
-# of the possible markers and block names see the documentation.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_HEADER =
-
-# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
-# generated HTML page. If the tag is left blank doxygen will generate a standard
-# footer. See HTML_HEADER for more information on how to generate a default
-# footer and what special commands can be used inside the footer. See also
-# section "Doxygen usage" for information on how to generate the default footer
-# that doxygen normally uses.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_FOOTER =
-
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
-# sheet that is used by each HTML page. It can be used to fine-tune the look of
-# the HTML output. If left blank doxygen will generate a default style sheet.
-# See also section "Doxygen usage" for information on how to generate the style
-# sheet that doxygen normally uses.
-# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
-# it is more robust and this tag (HTML_STYLESHEET) will in the future become
-# obsolete.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_STYLESHEET =
-
-# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
-# cascading style sheets that are included after the standard style sheets
-# created by doxygen. Using this option one can overrule certain style aspects.
-# This is preferred over using HTML_STYLESHEET since it does not replace the
-# standard style sheet and is therefore more robust against future updates.
-# Doxygen will copy the style sheet files to the output directory.
-# Note: The order of the extra style sheet files is of importance (e.g. the last
-# style sheet in the list overrules the setting of the previous ones in the
-# list). For an example see the documentation.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_EXTRA_STYLESHEET =
-
-# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
-# other source files which should be copied to the HTML output directory. Note
-# that these files will be copied to the base HTML output directory. Use the
-# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
-# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
-# files will be copied as-is; there are no commands or markers available.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_EXTRA_FILES =
-
-# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
-# will adjust the colors in the style sheet and background images according to
-# this color. Hue is specified as an angle on a colorwheel, see
-# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
-# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
-# purple, and 360 is red again.
-# Minimum value: 0, maximum value: 359, default value: 220.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_HUE = 220
-
-# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
-# in the HTML output. For a value of 0 the output will use grayscales only. A
-# value of 255 will produce the most vivid colors.
-# Minimum value: 0, maximum value: 255, default value: 100.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_SAT = 100
-
-# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
-# luminance component of the colors in the HTML output. Values below 100
-# gradually make the output lighter, whereas values above 100 make the output
-# darker. The value divided by 100 is the actual gamma applied, so 80 represents
-# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
-# change the gamma.
-# Minimum value: 40, maximum value: 240, default value: 80.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_COLORSTYLE_GAMMA = 80
-
-# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
-# page will contain the date and time when the page was generated. Setting this
-# to NO can help when comparing the output of multiple runs.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_TIMESTAMP = YES
-
-# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
-# documentation will contain sections that can be hidden and shown after the
-# page has loaded.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_DYNAMIC_SECTIONS = NO
-
-# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
-# shown in the various tree structured indices initially; the user can expand
-# and collapse entries dynamically later on. Doxygen will expand the tree to
-# such a level that at most the specified number of entries are visible (unless
-# a fully collapsed tree already exceeds this amount). So setting the number of
-# entries 1 will produce a full collapsed tree by default. 0 is a special value
-# representing an infinite number of entries and will result in a full expanded
-# tree by default.
-# Minimum value: 0, maximum value: 9999, default value: 100.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-HTML_INDEX_NUM_ENTRIES = 100
-
-# If the GENERATE_DOCSET tag is set to YES, additional index files will be
-# generated that can be used as input for Apple's Xcode 3 integrated development
-# environment (see: http://developer.apple.com/tools/xcode/), introduced with
-# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
-# Makefile in the HTML output directory. Running make will produce the docset in
-# that directory and running make install will install the docset in
-# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
-# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
-# for more information.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_DOCSET = NO
-
-# This tag determines the name of the docset feed. A documentation feed provides
-# an umbrella under which multiple documentation sets from a single provider
-# (such as a company or product suite) can be grouped.
-# The default value is: Doxygen generated docs.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_FEEDNAME = "Doxygen generated docs"
-
-# This tag specifies a string that should uniquely identify the documentation
-# set bundle. This should be a reverse domain-name style string, e.g.
-# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_BUNDLE_ID = org.doxygen.Project
-
-# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
-# the documentation publisher. This should be a reverse domain-name style
-# string, e.g. com.mycompany.MyDocSet.documentation.
-# The default value is: org.doxygen.Publisher.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_PUBLISHER_ID = org.doxygen.Publisher
-
-# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
-# The default value is: Publisher.
-# This tag requires that the tag GENERATE_DOCSET is set to YES.
-
-DOCSET_PUBLISHER_NAME = Publisher
-
-# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
-# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
-# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
-# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
-# Windows.
-#
-# The HTML Help Workshop contains a compiler that can convert all HTML output
-# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
-# files are now used as the Windows 98 help format, and will replace the old
-# Windows help format (.hlp) on all Windows platforms in the future. Compressed
-# HTML files also contain an index, a table of contents, and you can search for
-# words in the documentation. The HTML workshop also contains a viewer for
-# compressed HTML files.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_HTMLHELP = NO
-
-# The CHM_FILE tag can be used to specify the file name of the resulting .chm
-# file. You can add a path in front of the file if the result should not be
-# written to the html output directory.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-CHM_FILE =
-
-# The HHC_LOCATION tag can be used to specify the location (absolute path
-# including file name) of the HTML help compiler (hhc.exe). If non-empty,
-# doxygen will try to run the HTML help compiler on the generated index.hhp.
-# The file has to be specified with full path.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-HHC_LOCATION =
-
-# The GENERATE_CHI flag controls if a separate .chi index file is generated
-# (YES) or that it should be included in the master .chm file (NO).
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-GENERATE_CHI = NO
-
-# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
-# and project file content.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-CHM_INDEX_ENCODING =
-
-# The BINARY_TOC flag controls whether a binary table of contents is generated
-# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
-# enables the Previous and Next buttons.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-BINARY_TOC = NO
-
-# The TOC_EXPAND flag can be set to YES to add extra items for group members to
-# the table of contents of the HTML help documentation and to the tree view.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
-
-TOC_EXPAND = NO
-
-# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
-# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
-# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
-# (.qch) of the generated HTML documentation.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_QHP = NO
-
-# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
-# the file name of the resulting .qch file. The path specified is relative to
-# the HTML output folder.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QCH_FILE =
-
-# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
-# Project output. For more information please see Qt Help Project / Namespace
-# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_NAMESPACE = org.doxygen.Project
-
-# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
-# Help Project output. For more information please see Qt Help Project / Virtual
-# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
-# folders).
-# The default value is: doc.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_VIRTUAL_FOLDER = doc
-
-# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
-# filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
-# filters).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_CUST_FILTER_NAME =
-
-# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
-# custom filter to add. For more information please see Qt Help Project / Custom
-# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
-# filters).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_CUST_FILTER_ATTRS =
-
-# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
-# project's filter section matches. Qt Help Project / Filter Attributes (see:
-# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHP_SECT_FILTER_ATTRS =
-
-# The QHG_LOCATION tag can be used to specify the location of Qt's
-# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
-# generated .qhp file.
-# This tag requires that the tag GENERATE_QHP is set to YES.
-
-QHG_LOCATION =
-
-# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
-# generated, together with the HTML files, they form an Eclipse help plugin. To
-# install this plugin and make it available under the help contents menu in
-# Eclipse, the contents of the directory containing the HTML and XML files needs
-# to be copied into the plugins directory of eclipse. The name of the directory
-# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
-# After copying Eclipse needs to be restarted before the help appears.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_ECLIPSEHELP = NO
-
-# A unique identifier for the Eclipse help plugin. When installing the plugin
-# the directory name containing the HTML and XML files should also have this
-# name. Each documentation set should have its own identifier.
-# The default value is: org.doxygen.Project.
-# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
-
-ECLIPSE_DOC_ID = org.doxygen.Project
-
-# If you want full control over the layout of the generated HTML pages it might
-# be necessary to disable the index and replace it with your own. The
-# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
-# of each HTML page. A value of NO enables the index and the value YES disables
-# it. Since the tabs in the index contain the same information as the navigation
-# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-DISABLE_INDEX = NO
-
-# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
-# structure should be generated to display hierarchical information. If the tag
-# value is set to YES, a side panel will be generated containing a tree-like
-# index structure (just like the one that is generated for HTML Help). For this
-# to work a browser that supports JavaScript, DHTML, CSS and frames is required
-# (i.e. any modern browser). Windows users are probably better off using the
-# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
-# further fine-tune the look of the index. As an example, the default style
-# sheet generated by doxygen has an example that shows how to put an image at
-# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
-# the same information as the tab index, you could consider setting
-# DISABLE_INDEX to YES when enabling this option.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-GENERATE_TREEVIEW = NO
-
-# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
-# doxygen will group on one line in the generated HTML documentation.
-#
-# Note that a value of 0 will completely suppress the enum values from appearing
-# in the overview section.
-# Minimum value: 0, maximum value: 20, default value: 4.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-ENUM_VALUES_PER_LINE = 4
-
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
-# to set the initial width (in pixels) of the frame in which the tree is shown.
-# Minimum value: 0, maximum value: 1500, default value: 250.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-TREEVIEW_WIDTH = 250
-
-# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
-# external symbols imported via tag files in a separate window.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-EXT_LINKS_IN_WINDOW = NO
-
-# Use this tag to change the font size of LaTeX formulas included as images in
-# the HTML documentation. When you change the font size after a successful
-# doxygen run you need to manually remove any form_*.png images from the HTML
-# output directory to force them to be regenerated.
-# Minimum value: 8, maximum value: 50, default value: 10.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-FORMULA_FONTSIZE = 10
-
-# Use the FORMULA_TRANPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are not
-# supported properly for IE 6.0, but are supported on all modern browsers.
-#
-# Note that when changing this option you need to delete any form_*.png files in
-# the HTML output directory before the changes have effect.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-FORMULA_TRANSPARENT = YES
-
-# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
-# http://www.mathjax.org) which uses client side Javascript for the rendering
-# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
-# installed or if you want to formulas look prettier in the HTML output. When
-# enabled you may also need to install MathJax separately and configure the path
-# to it using the MATHJAX_RELPATH option.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-USE_MATHJAX = NO
-
-# When MathJax is enabled you can set the default output format to be used for
-# the MathJax output. See the MathJax site (see:
-# http://docs.mathjax.org/en/latest/output.html) for more details.
-# Possible values are: HTML-CSS (which is slower, but has the best
-# compatibility), NativeMML (i.e. MathML) and SVG.
-# The default value is: HTML-CSS.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_FORMAT = HTML-CSS
-
-# When MathJax is enabled you need to specify the location relative to the HTML
-# output directory using the MATHJAX_RELPATH option. The destination directory
-# should contain the MathJax.js script. For instance, if the mathjax directory
-# is located at the same level as the HTML output directory, then
-# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
-# Content Delivery Network so you can quickly see the result without installing
-# MathJax. However, it is strongly recommended to install a local copy of
-# MathJax from http://www.mathjax.org before deployment.
-# The default value is: http://cdn.mathjax.org/mathjax/latest.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
-
-# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
-# extension names that should be enabled during MathJax rendering. For example
-# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_EXTENSIONS =
-
-# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
-# of code that will be used on startup of the MathJax code. See the MathJax site
-# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
-# example see the documentation.
-# This tag requires that the tag USE_MATHJAX is set to YES.
-
-MATHJAX_CODEFILE =
-
-# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
-# the HTML output. The underlying search engine uses javascript and DHTML and
-# should work on any modern browser. Note that when using HTML help
-# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
-# there is already a search function so this one should typically be disabled.
-# For large projects the javascript based search engine can be slow, then
-# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
-# search using the keyboard; to jump to the search box use <access key> + S
-# (what the <access key> is depends on the OS and browser, but it is typically
-# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
-# key> to jump into the search results window, the results can be navigated
-# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
-# the search. The filter options can be selected when the cursor is inside the
-# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
-# to select a filter and <Enter> or <escape> to activate or cancel the filter
-# option.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_HTML is set to YES.
-
-SEARCHENGINE = YES
-
-# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a web server instead of a web client using Javascript. There
-# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
-# setting. When disabled, doxygen will generate a PHP script for searching and
-# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
-# and searching needs to be provided by external tools. See the section
-# "External Indexing and Searching" for details.
-# The default value is: NO.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SERVER_BASED_SEARCH = NO
-
-# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
-# script for searching. Instead the search results are written to an XML file
-# which needs to be processed by an external indexer. Doxygen will invoke an
-# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
-# search results.
-#
-# Doxygen ships with an example indexer (doxyindexer) and search engine
-# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: http://xapian.org/).
-#
-# See the section "External Indexing and Searching" for details.
-# The default value is: NO.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTERNAL_SEARCH = NO
-
-# The SEARCHENGINE_URL should point to a search engine hosted by a web server
-# which will return the search results when EXTERNAL_SEARCH is enabled.
-#
-# Doxygen ships with an example indexer (doxyindexer) and search engine
-# (doxysearch.cgi) which are based on the open source search engine library
-# Xapian (see: http://xapian.org/). See the section "External Indexing and
-# Searching" for details.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SEARCHENGINE_URL =
-
-# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
-# search data is written to a file for indexing by an external tool. With the
-# SEARCHDATA_FILE tag the name of this file can be specified.
-# The default file is: searchdata.xml.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-SEARCHDATA_FILE = searchdata.xml
-
-# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
-# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
-# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
-# projects and redirect the results back to the right project.
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTERNAL_SEARCH_ID =
-
-# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
-# projects other than the one defined by this configuration file, but that are
-# all added to the same external search index. Each project needs to have a
-# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
-# to a relative location where the documentation can be found. The format is:
-# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
-# This tag requires that the tag SEARCHENGINE is set to YES.
-
-EXTRA_SEARCH_MAPPINGS =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the LaTeX output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
-# The default value is: YES.
-
-GENERATE_LATEX = NO
-
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: latex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_OUTPUT = latex
-
-# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked.
-#
-# Note that when enabling USE_PDFLATEX this option is only used for generating
-# bitmaps for formulas in the HTML output, but not in the Makefile that is
-# written to the output directory.
-# The default file is: latex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_CMD_NAME = latex
-
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
-# index for LaTeX.
-# The default file is: makeindex.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-MAKEINDEX_CMD_NAME = makeindex
-
-# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
-# documents. This may be useful for small projects and may help to save some
-# trees in general.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-COMPACT_LATEX = NO
-
-# The PAPER_TYPE tag can be used to set the paper type that is used by the
-# printer.
-# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
-# 14 inches) and executive (7.25 x 10.5 inches).
-# The default value is: a4.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-PAPER_TYPE = a4
-
-# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
-# that should be included in the LaTeX output. To get the times font for
-# instance you can specify
-# EXTRA_PACKAGES=times
-# If left blank no extra packages will be included.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-EXTRA_PACKAGES =
-
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
-# generated LaTeX document. The header should contain everything until the first
-# chapter. If it is left blank doxygen will generate a standard header. See
-# section "Doxygen usage" for information on how to let doxygen write the
-# default header to a separate file.
-#
-# Note: Only use a user-defined header if you know what you are doing! The
-# following commands have a special meaning inside the header: $title,
-# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
-# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
-# string, for the replacement values of the other commands the user is referred
-# to HTML_HEADER.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_HEADER =
-
-# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
-# generated LaTeX document. The footer should contain everything after the last
-# chapter. If it is left blank doxygen will generate a standard footer. See
-# LATEX_HEADER for more information on how to generate a default footer and what
-# special commands can be used inside the footer.
-#
-# Note: Only use a user-defined footer if you know what you are doing!
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_FOOTER =
-
-# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
-# LaTeX style sheets that are included after the standard style sheets created
-# by doxygen. Using this option one can overrule certain style aspects. Doxygen
-# will copy the style sheet files to the output directory.
-# Note: The order of the extra style sheet files is of importance (e.g. the last
-# style sheet in the list overrules the setting of the previous ones in the
-# list).
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_EXTRA_STYLESHEET =
-
-# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
-# other source files which should be copied to the LATEX_OUTPUT output
-# directory. Note that the files will be copied as-is; there are no commands or
-# markers available.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_EXTRA_FILES =
-
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
-# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
-# contain links (just like the HTML output) instead of page references. This
-# makes the output suitable for online browsing using a PDF viewer.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-PDF_HYPERLINKS = YES
-
-# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
-# the PDF file directly from the LaTeX files. Set this option to YES, to get a
-# higher quality PDF documentation.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-USE_PDFLATEX = YES
-
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
-# command to the generated LaTeX files. This will instruct LaTeX to keep running
-# if errors occur, instead of asking the user for help. This option is also used
-# when generating formulas in HTML.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_BATCHMODE = NO
-
-# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
-# index chapters (such as File Index, Compound Index, etc.) in the output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_HIDE_INDICES = NO
-
-# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
-# code with syntax highlighting in the LaTeX output.
-#
-# Note that which sources are shown also depends on other settings such as
-# SOURCE_BROWSER.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_SOURCE_CODE = NO
-
-# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
-# bibliography, e.g. plainnat, or ieeetr. See
-# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
-# The default value is: plain.
-# This tag requires that the tag GENERATE_LATEX is set to YES.
-
-LATEX_BIB_STYLE = plain
-
-#---------------------------------------------------------------------------
-# Configuration options related to the RTF output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
-# RTF output is optimized for Word 97 and may not look too pretty with other RTF
-# readers/editors.
-# The default value is: NO.
-
-GENERATE_RTF = NO
-
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: rtf.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_OUTPUT = rtf
-
-# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
-# documents. This may be useful for small projects and may help to save some
-# trees in general.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-COMPACT_RTF = NO
-
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
-# contain hyperlink fields. The RTF file will contain links (just like the HTML
-# output) instead of page references. This makes the output suitable for online
-# browsing using Word or some other Word compatible readers that support those
-# fields.
-#
-# Note: WordPad (write) and others do not support links.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_HYPERLINKS = NO
-
-# Load stylesheet definitions from file. Syntax is similar to doxygen's config
-# file, i.e. a series of assignments. You only have to provide replacements,
-# missing definitions are set to their default value.
-#
-# See also section "Doxygen usage" for information on how to generate the
-# default style sheet that doxygen normally uses.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_STYLESHEET_FILE =
-
-# Set optional variables used in the generation of an RTF document. Syntax is
-# similar to doxygen's config file. A template extensions file can be generated
-# using doxygen -e rtf extensionFile.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_EXTENSIONS_FILE =
-
-# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
-# with syntax highlighting in the RTF output.
-#
-# Note that which sources are shown also depends on other settings such as
-# SOURCE_BROWSER.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_RTF is set to YES.
-
-RTF_SOURCE_CODE = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the man page output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
-# classes and files.
-# The default value is: NO.
-
-GENERATE_MAN = NO
-
-# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it. A directory man3 will be created inside the directory specified by
-# MAN_OUTPUT.
-# The default directory is: man.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_OUTPUT = man
-
-# The MAN_EXTENSION tag determines the extension that is added to the generated
-# man pages. In case the manual section does not start with a number, the number
-# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
-# optional.
-# The default value is: .3.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_EXTENSION = .3
-
-# The MAN_SUBDIR tag determines the name of the directory created within
-# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
-# MAN_EXTENSION with the initial . removed.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_SUBDIR =
-
-# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
-# will generate one additional man file for each entity documented in the real
-# man page(s). These additional files only source the real man page, but without
-# them the man command would be unable to find the correct page.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_MAN is set to YES.
-
-MAN_LINKS = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the XML output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
-# captures the structure of the code including all documentation.
-# The default value is: NO.
-
-GENERATE_XML = NO
-
-# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
-# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
-# it.
-# The default directory is: xml.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_OUTPUT = xml
-
-# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
-# listings (including syntax highlighting and cross-referencing information) to
-# the XML output. Note that enabling this will significantly increase the size
-# of the XML output.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_XML is set to YES.
-
-XML_PROGRAMLISTING = YES
-
-#---------------------------------------------------------------------------
-# Configuration options related to the DOCBOOK output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
-# that can be used to generate PDF.
-# The default value is: NO.
-
-GENERATE_DOCBOOK = NO
-
-# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
-# front of it.
-# The default directory is: docbook.
-# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
-
-DOCBOOK_OUTPUT = docbook
-
-# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
-# program listings (including syntax highlighting and cross-referencing
-# information) to the DOCBOOK output. Note that enabling this will significantly
-# increase the size of the DOCBOOK output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
-
-DOCBOOK_PROGRAMLISTING = NO
-
-#---------------------------------------------------------------------------
-# Configuration options for the AutoGen Definitions output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
-# AutoGen Definitions (see http://autogen.sf.net) file that captures the
-# structure of the code including all documentation. Note that this feature is
-# still experimental and incomplete at the moment.
-# The default value is: NO.
-
-GENERATE_AUTOGEN_DEF = NO
-
-#---------------------------------------------------------------------------
-# Configuration options related to the Perl module output
-#---------------------------------------------------------------------------
-
-# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
-# file that captures the structure of the code including all documentation.
-#
-# Note that this feature is still experimental and incomplete at the moment.
-# The default value is: NO.
-
-GENERATE_PERLMOD = NO
-
-# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
-# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
-# output from the Perl module output.
-# The default value is: NO.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_LATEX = NO
-
-# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
-# formatted so it can be parsed by a human reader. This is useful if you want to
-# understand what is going on. On the other hand, if this tag is set to NO, the
-# size of the Perl module output will be much smaller and Perl will parse it
-# just the same.
-# The default value is: YES.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_PRETTY = YES
-
-# The names of the make variables in the generated doxyrules.make file are
-# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
-# so different doxyrules.make files included by the same Makefile don't
-# overwrite each other's variables.
-# This tag requires that the tag GENERATE_PERLMOD is set to YES.
-
-PERLMOD_MAKEVAR_PREFIX =
-
-#---------------------------------------------------------------------------
-# Configuration options related to the preprocessor
-#---------------------------------------------------------------------------
-
-# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
-# C-preprocessor directives found in the sources and include files.
-# The default value is: YES.
-
-ENABLE_PREPROCESSING = YES
-
-# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
-# in the source code. If set to NO, only conditional compilation will be
-# performed. Macro expansion can be done in a controlled way by setting
-# EXPAND_ONLY_PREDEF to YES.
-# The default value is: NO.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-MACRO_EXPANSION = NO
-
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
-# the macro expansion is limited to the macros specified with the PREDEFINED and
-# EXPAND_AS_DEFINED tags.
-# The default value is: NO.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-EXPAND_ONLY_PREDEF = NO
-
-# If the SEARCH_INCLUDES tag is set to YES, the include files in the
-# INCLUDE_PATH will be searched if a #include is found.
-# The default value is: YES.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-SEARCH_INCLUDES = YES
-
-# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by the
-# preprocessor.
-# This tag requires that the tag SEARCH_INCLUDES is set to YES.
-
-INCLUDE_PATH =
-
-# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
-# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will be
-# used.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-INCLUDE_FILE_PATTERNS =
-
-# The PREDEFINED tag can be used to specify one or more macro names that are
-# defined before the preprocessor is started (similar to the -D option of e.g.
-# gcc). The argument of the tag is a list of macros of the form: name or
-# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
-# is assumed. To prevent a macro definition from being undefined via #undef or
-# recursively expanded use the := operator instead of the = operator.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-PREDEFINED =
-
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
-# tag can be used to specify a list of macro names that should be expanded. The
-# macro definition that is found in the sources will be used. Use the PREDEFINED
-# tag if you want to use a different macro definition that overrules the
-# definition found in the source code.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-EXPAND_AS_DEFINED =
-
-# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
-# remove all references to function-like macros that are alone on a line, have
-# an all uppercase name, and do not end with a semicolon. Such function macros
-# are typically used for boiler-plate code, and will confuse the parser if not
-# removed.
-# The default value is: YES.
-# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
-
-SKIP_FUNCTION_MACROS = YES
-
-#---------------------------------------------------------------------------
-# Configuration options related to external references
-#---------------------------------------------------------------------------
-
-# The TAGFILES tag can be used to specify one or more tag files. For each tag
-# file the location of the external documentation should be added. The format of
-# a tag file without this location is as follows:
-# TAGFILES = file1 file2 ...
-# Adding location for the tag files is done as follows:
-# TAGFILES = file1=loc1 "file2 = loc2" ...
-# where loc1 and loc2 can be relative or absolute paths or URLs. See the
-# section "Linking to external documentation" for more information about the use
-# of tag files.
-# Note: Each tag file must have a unique name (where the name does NOT include
-# the path). If a tag file is not located in the directory in which doxygen is
-# run, you must also specify the path to the tagfile here.
-
-TAGFILES =
-
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
-# tag file that is based on the input files it reads. See section "Linking to
-# external documentation" for more information about the usage of tag files.
-
-GENERATE_TAGFILE =
-
-# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
-# the class index. If set to NO, only the inherited external classes will be
-# listed.
-# The default value is: NO.
-
-ALLEXTERNALS = NO
-
-# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
-# in the modules index. If set to NO, only the current project's groups will be
-# listed.
-# The default value is: YES.
-
-EXTERNAL_GROUPS = YES
-
-# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
-# the related pages index. If set to NO, only the current project's pages will
-# be listed.
-# The default value is: YES.
-
-EXTERNAL_PAGES = YES
-
-# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of 'which perl').
-# The default file (with absolute path) is: /usr/bin/perl.
-
-PERL_PATH = /usr/bin/perl
-
-#---------------------------------------------------------------------------
-# Configuration options related to the dot tool
-#---------------------------------------------------------------------------
-
-# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
-# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
-# NO turns the diagrams off. Note that this option also works with HAVE_DOT
-# disabled, but it is recommended to install and use dot, since it yields more
-# powerful graphs.
-# The default value is: YES.
-
-CLASS_DIAGRAMS = YES
-
-# You can define message sequence charts within doxygen comments using the \msc
-# command. Doxygen will then run the mscgen tool (see:
-# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
-# documentation. The MSCGEN_PATH tag allows you to specify the directory where
-# the mscgen tool resides. If left empty the tool is assumed to be found in the
-# default search path.
-
-MSCGEN_PATH =
-
-# You can include diagrams made with dia in doxygen documentation. Doxygen will
-# then run dia to produce the diagram and insert it in the documentation. The
-# DIA_PATH tag allows you to specify the directory where the dia binary resides.
-# If left empty dia is assumed to be found in the default search path.
-
-DIA_PATH =
-
-# If set to YES the inheritance and collaboration graphs will hide inheritance
-# and usage relations if the target is undocumented or is not a class.
-# The default value is: YES.
-
-HIDE_UNDOC_RELATIONS = YES
-
-# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz (see:
-# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
-# Bell Labs. The other options in this section have no effect if this option is
-# set to NO
-# The default value is: NO.
-
-HAVE_DOT = NO
-
-# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
-# to run in parallel. When set to 0 doxygen will base this on the number of
-# processors available in the system. You can set it explicitly to a value
-# larger than 0 to get control over the balance between CPU load and processing
-# speed.
-# Minimum value: 0, maximum value: 32, default value: 0.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_NUM_THREADS = 0
-
-# When you want a differently looking font in the dot files that doxygen
-# generates you can specify the font name using DOT_FONTNAME. You need to make
-# sure dot is able to find the font, which can be done by putting it in a
-# standard location or by setting the DOTFONTPATH environment variable or by
-# setting DOT_FONTPATH to the directory containing the font.
-# The default value is: Helvetica.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTNAME = Helvetica
-
-# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
-# dot graphs.
-# Minimum value: 4, maximum value: 24, default value: 10.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTSIZE = 10
-
-# By default doxygen will tell dot to use the default font as specified with
-# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
-# the path where dot can find it using this tag.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_FONTPATH =
-
-# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
-# each documented class showing the direct and indirect inheritance relations.
-# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CLASS_GRAPH = YES
-
-# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
-# graph for each documented class showing the direct and indirect implementation
-# dependencies (inheritance, containment, and class references variables) of the
-# class with other documented classes.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-COLLABORATION_GRAPH = YES
-
-# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
-# groups, showing the direct groups dependencies.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GROUP_GRAPHS = YES
-
-# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
-# collaboration diagrams in a style similar to the OMG's Unified Modeling
-# Language.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-UML_LOOK = NO
-
-# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
-# class node. If there are many fields or methods and many nodes the graph may
-# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
-# number of items for each type to make the size more manageable. Set this to 0
-# for no limit. Note that the threshold may be exceeded by 50% before the limit
-# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
-# but if the number exceeds 15, the total amount of fields shown is limited to
-# 10.
-# Minimum value: 0, maximum value: 100, default value: 10.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-UML_LIMIT_NUM_FIELDS = 10
-
-# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
-# collaboration graphs will show the relations between templates and their
-# instances.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-TEMPLATE_RELATIONS = NO
-
-# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
-# YES then doxygen will generate a graph for each documented file showing the
-# direct and indirect include dependencies of the file with other documented
-# files.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INCLUDE_GRAPH = YES
-
-# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
-# set to YES then doxygen will generate a graph for each documented file showing
-# the direct and indirect include dependencies of the file with other documented
-# files.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INCLUDED_BY_GRAPH = YES
-
-# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
-# dependency graph for every global function or class method.
-#
-# Note that enabling this option will significantly increase the time of a run.
-# So in most cases it will be better to enable call graphs for selected
-# functions only using the \callgraph command.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CALL_GRAPH = NO
-
-# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
-# dependency graph for every global function or class method.
-#
-# Note that enabling this option will significantly increase the time of a run.
-# So in most cases it will be better to enable caller graphs for selected
-# functions only using the \callergraph command.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-CALLER_GRAPH = NO
-
-# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
-# hierarchy of all classes instead of a textual one.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GRAPHICAL_HIERARCHY = YES
-
-# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
-# dependencies a directory has on other directories in a graphical way. The
-# dependency relations are determined by the #include relations between the
-# files in the directories.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DIRECTORY_GRAPH = YES
-
-# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot.
-# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
-# to make the SVG files visible in IE 9+ (other browsers do not have this
-# requirement).
-# Possible values are: png, jpg, gif and svg.
-# The default value is: png.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_IMAGE_FORMAT = png
-
-# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
-# enable generation of interactive SVG images that allow zooming and panning.
-#
-# Note that this requires a modern browser other than Internet Explorer. Tested
-# and working are Firefox, Chrome, Safari, and Opera.
-# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
-# the SVG files visible. Older versions of IE do not have SVG support.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-INTERACTIVE_SVG = NO
-
-# The DOT_PATH tag can be used to specify the path where the dot tool can be
-# found. If left blank, it is assumed the dot tool can be found in the path.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_PATH =
-
-# The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the \dotfile
-# command).
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOTFILE_DIRS =
-
-# The MSCFILE_DIRS tag can be used to specify one or more directories that
-# contain msc files that are included in the documentation (see the \mscfile
-# command).
-
-MSCFILE_DIRS =
-
-# The DIAFILE_DIRS tag can be used to specify one or more directories that
-# contain dia files that are included in the documentation (see the \diafile
-# command).
-
-DIAFILE_DIRS =
-
-# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
-# path where java can find the plantuml.jar file. If left blank, it is assumed
-# PlantUML is not used or called during a preprocessing step. Doxygen will
-# generate a warning when it encounters a \startuml command in this case and
-# will not generate output for the diagram.
-
-PLANTUML_JAR_PATH =
-
-# When using plantuml, the specified paths are searched for files specified by
-# the !include statement in a plantuml block.
-
-PLANTUML_INCLUDE_PATH =
-
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
-# that will be shown in the graph. If the number of nodes in a graph becomes
-# larger than this value, doxygen will truncate the graph, which is visualized
-# by representing a node as a red box. Note that doxygen if the number of direct
-# children of the root node in a graph is already larger than
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
-# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
-# Minimum value: 0, maximum value: 10000, default value: 50.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_GRAPH_MAX_NODES = 50
-
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
-# generated by dot. A depth value of 3 means that only nodes reachable from the
-# root by following a path via at most 3 edges will be shown. Nodes that lay
-# further from the root node will be omitted. Note that setting this option to 1
-# or 2 may greatly reduce the computation time needed for large code bases. Also
-# note that the size of a graph can be further restricted by
-# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
-# Minimum value: 0, maximum value: 1000, default value: 0.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-MAX_DOT_GRAPH_DEPTH = 0
-
-# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not seem
-# to support this out of the box.
-#
-# Warning: Depending on the platform used, enabling this option may lead to
-# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
-# read).
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_TRANSPARENT = NO
-
-# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
-# files in one run (i.e. multiple -o and -T options on the command line). This
-# makes dot run faster, but since only newer versions of dot (>1.8.10) support
-# this, this feature is disabled by default.
-# The default value is: NO.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_MULTI_TARGETS = NO
-
-# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
-# explaining the meaning of the various boxes and arrows in the dot generated
-# graphs.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-GENERATE_LEGEND = YES
-
-# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
-# files that are used to generate the various graphs.
-# The default value is: YES.
-# This tag requires that the tag HAVE_DOT is set to YES.
-
-DOT_CLEANUP = YES
diff --git a/LICENSE.md b/LICENSE.md
index ca0a9702f7..2f78f0e37d 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -1,7 +1,7 @@
GODOT ENGINE
http://www.godotengine.org
**********************************************************************
- Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.
+ Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
diff --git a/README.md b/README.md
index 3456290f74..d5dadb93a7 100644
--- a/README.md
+++ b/README.md
@@ -7,12 +7,11 @@ The editor, language and APIs are feature rich, yet simple to learn, allowing yo
### About
-Godot has been developed by Juan Linietsky and Ariel Manzur for several years, and was born as an in-house engine, used to publish several work-for-hire titles.
-Development is sponsored by OKAM Studio (http://www.okamstudio.com).
+Godot has been developed by Juan Linietsky and Ariel Manzur for several years, and was born as an in-house engine, used to publish several work-for-hire titles. Godot is a member project of the [Software Freedom Conservancy](https://sfconservancy.org)
### Documentation
-Documentation has been moved to the [GitHub Wiki](https://github.com/okamstudio/godot/wiki).
+Documentation has been moved to the [OpenProject Wiki](http://godotengine.org/projects/godot-engine/wiki/Documentation).
### Binary Downloads, Community, etc.
@@ -23,4 +22,4 @@ http://www.godotengine.org
### Compiling from Source
Compilation instructions for every platform can be found in the Wiki:
-https://github.com/okamstudio/godot/wiki/advanced
+http://godotengine.org/projects/godot-engine/wiki/Advanced_topics
diff --git a/SConstruct b/SConstruct
index a1a3238305..b047e961f2 100644
--- a/SConstruct
+++ b/SConstruct
@@ -54,33 +54,47 @@ methods.save_active_platforms(active_platforms,active_platform_ids)
custom_tools=['default']
+platform_arg = ARGUMENTS.get("platform", False)
+
if (os.name=="posix"):
pass
elif (os.name=="nt"):
- if (os.getenv("VSINSTALLDIR")==None):
- custom_tools=['mingw']
+ if (os.getenv("VSINSTALLDIR")==None or platform_arg=="android"):
+ custom_tools=['mingw']
env_base=Environment(tools=custom_tools,ENV = {'PATH' : os.environ['PATH']});
+
#env_base=Environment(tools=custom_tools);
env_base.global_defaults=global_defaults
-env_base.android_source_modules=[]
-env_base.android_source_files=[]
-env_base.android_module_libraries=[]
+env_base.android_maven_repos=[]
+env_base.android_dependencies=[]
+env_base.android_java_dirs=[]
+env_base.android_res_dirs=[]
+env_base.android_aidl_dirs=[]
+env_base.android_jni_dirs=[]
env_base.android_manifest_chunk=""
env_base.android_permission_chunk=""
env_base.android_appattributes_chunk=""
env_base.disabled_modules=[]
-env_base.__class__.android_module_source = methods.android_module_source
-env_base.__class__.android_module_library = methods.android_module_library
-env_base.__class__.android_module_file = methods.android_module_file
-env_base.__class__.android_module_manifest = methods.android_module_manifest
-env_base.__class__.android_module_permission = methods.android_module_permission
-env_base.__class__.android_module_attribute = methods.android_module_attribute
+
+env_base.__class__.android_add_maven_repository=methods.android_add_maven_repository
+env_base.__class__.android_add_dependency=methods.android_add_dependency
+env_base.__class__.android_add_java_dir=methods.android_add_java_dir
+env_base.__class__.android_add_res_dir=methods.android_add_res_dir
+env_base.__class__.android_add_aidl_dir=methods.android_add_aidl_dir
+env_base.__class__.android_add_jni_dir=methods.android_add_jni_dir
+env_base.__class__.android_add_to_manifest = methods.android_add_to_manifest
+env_base.__class__.android_add_to_permissions = methods.android_add_to_permissions
+env_base.__class__.android_add_to_attributes = methods.android_add_to_attributes
env_base.__class__.disable_module = methods.disable_module
env_base.__class__.add_source_files = methods.add_source_files
+env_base["x86_opt_gcc"]=False
+env_base["x86_opt_vc"]=False
+env_base["armv7_opt_gcc"]=False
+
customs = ['custom.py']
profile = ARGUMENTS.get("profile", False)
@@ -99,10 +113,11 @@ opts.Add('p','Platform (same as platform=).',"")
opts.Add('tools','Build Tools (Including Editor): (yes/no)','yes')
opts.Add('gdscript','Build GDSCript support: (yes/no)','yes')
opts.Add('vorbis','Build Ogg Vorbis Support: (yes/no)','yes')
+opts.Add('opus','Build Opus Audio Format Support: (yes/no)','yes')
opts.Add('minizip','Build Minizip Archive Support: (yes/no)','yes')
opts.Add('squish','Squish BC Texture Compression in editor (yes/no)','yes')
opts.Add('theora','Theora Video (yes/no)','yes')
-opts.Add('use_theoraplayer_binary', "Use precompiled binaries from libtheoraplayer for ogg/theora/vorbis (yes/no)", "no")
+opts.Add('theoralib','Theora Video (yes/no)','no')
opts.Add('freetype','Freetype support in editor','yes')
opts.Add('speex','Speex Audio (yes/no)','yes')
opts.Add('xml','XML Save/Load support (yes/no)','yes')
@@ -119,6 +134,7 @@ opts.Add("CXX", "Compiler");
opts.Add("CCFLAGS", "Custom flags for the C++ compiler");
opts.Add("CFLAGS", "Custom flags for the C compiler");
opts.Add("LINKFLAGS", "Custom flags for the linker");
+opts.Add('unix_global_settings_path', 'unix-specific path to system-wide settings. Currently only used by templates.','')
opts.Add('disable_3d', 'Disable 3D nodes for smaller executable (yes/no)', "no")
opts.Add('disable_advanced_gui', 'Disable advance 3D gui nodes and behaviors (yes/no)', "no")
opts.Add('colored', 'Enable colored output for the compilation (yes/no)', 'no')
@@ -181,7 +197,7 @@ if selected_platform in platform_list:
if env['vsproj']=="yes":
env.vs_incs = []
env.vs_srcs = []
-
+
def AddToVSProject( sources ):
for x in sources:
if type(x) == type(""):
@@ -193,12 +209,12 @@ if selected_platform in platform_list:
basename = pieces[0]
basename = basename.replace('\\\\','/')
env.vs_srcs = env.vs_srcs + [basename + ".cpp"]
- env.vs_incs = env.vs_incs + [basename + ".h"]
- #print basename
- env.AddToVSProject = AddToVSProject
-
+ env.vs_incs = env.vs_incs + [basename + ".h"]
+ #print basename
+ env.AddToVSProject = AddToVSProject
+
env.extra_suffix=""
-
+
if env["extra_suffix"] != '' :
env.extra_suffix += '.'+env["extra_suffix"]
@@ -217,15 +233,15 @@ if selected_platform in platform_list:
env.Append(LINKFLAGS=string.split(str(LINKFLAGS)))
- detect.configure(env)
-
-
flag_list = platform_flags[selected_platform]
for f in flag_list:
if not (f[0] in ARGUMENTS): # allow command line to override platform flags
env[f[0]] = f[1]
- #env['platform_libsuffix'] = env['LIBSUFFIX']
+ #must happen after the flags, so when flags are used by configure, stuff happens (ie, ssl on x11)
+ detect.configure(env)
+
+ #env['platform_libsuffix'] = env['LIBSUFFIX']
suffix="."+selected_platform
@@ -280,10 +296,11 @@ if selected_platform in platform_list:
if (env['musepack']=='yes'):
env.Append(CPPFLAGS=['-DMUSEPACK_ENABLED']);
- if (env['openssl']!='no'):
- env.Append(CPPFLAGS=['-DOPENSSL_ENABLED']);
- if (env['openssl']=="builtin"):
- env.Append(CPPPATH=['#drivers/builtin_openssl2'])
+
+ if (env['openssl']!='no'):
+ env.Append(CPPFLAGS=['-DOPENSSL_ENABLED']);
+ if (env['openssl']=="builtin"):
+ env.Append(CPPPATH=['#drivers/builtin_openssl2'])
if (env["builtin_zlib"]=='yes'):
env.Append(CPPPATH=['#drivers/builtin_zlib/zlib'])
@@ -296,9 +313,15 @@ if selected_platform in platform_list:
if (env['vorbis']=='yes'):
env.Append(CPPFLAGS=['-DVORBIS_ENABLED']);
+ if (env['opus']=='yes'):
+ env.Append(CPPFLAGS=['-DOPUS_ENABLED']);
+
if (env['theora']=='yes'):
- env.Append(CPPFLAGS=['-DTHEORA_ENABLED']);
+ env['theoralib']='yes'
+ env.Append(CPPFLAGS=['-DTHEORA_ENABLED']);
+ if (env['theoralib']=='yes'):
+ env.Append(CPPFLAGS=['-DTHEORALIB_ENABLED']);
if (env['png']=='yes'):
env.Append(CPPFLAGS=['-DPNG_ENABLED']);
@@ -331,7 +354,7 @@ if selected_platform in platform_list:
if (env['colored']=='yes'):
methods.colored(sys,env)
-
+
if (env['etc1']=='yes'):
env.Append(CPPFLAGS=['-DETC1_ENABLED'])
@@ -350,22 +373,22 @@ if selected_platform in platform_list:
SConscript("main/SCsub")
SConscript("platform/"+selected_platform+"/SCsub"); # build selected platform
-
- # Microsoft Visual Studio Project Generation
- if (env['vsproj'])=="yes":
-
+
+ # Microsoft Visual Studio Project Generation
+ if (env['vsproj'])=="yes":
+
AddToVSProject(env.core_sources)
AddToVSProject(env.main_sources)
- AddToVSProject(env.modules_sources)
+ AddToVSProject(env.modules_sources)
AddToVSProject(env.scene_sources)
AddToVSProject(env.servers_sources)
AddToVSProject(env.tool_sources)
-
+
#env['MSVS_VERSION']='9.0'
env['MSVSBUILDCOM'] = "scons platform=" + selected_platform + " target=" + env["target"] + " bits=" + env["bits"] + " tools=yes"
- env['MSVSREBUILDCOM'] = "scons platform=" + selected_platform + " target=" + env["target"] + " bits=" + env["bits"] + " tools=yes"
- env['MSVSCLEANCOM'] = "scons platform=" + selected_platform + " target=" + env["target"] + " bits=" + env["bits"] + " tools=yes"
-
+ env['MSVSREBUILDCOM'] = "scons platform=" + selected_platform + " target=" + env["target"] + " bits=" + env["bits"] + " tools=yes vsproj=true"
+ env['MSVSCLEANCOM'] = "scons --clean platform=" + selected_platform + " target=" + env["target"] + " bits=" + env["bits"] + " tools=yes"
+
debug_variants = ['Debug|Win32']+['Debug|x64']
release_variants = ['Release|Win32']+['Release|x64']
release_debug_variants = ['Release_Debug|Win32']+['Release_Debug|x64']
@@ -376,11 +399,11 @@ if selected_platform in platform_list:
targets = debug_targets + release_targets + release_debug_targets
msvproj = env.MSVSProject(target = ['#godot' + env['MSVSPROJECTSUFFIX'] ],
incs = env.vs_incs,
- srcs = env.vs_srcs,
- runfile = targets,
- buildtarget = targets,
- auto_build_solution=1,
- variant = variants)
+ srcs = env.vs_srcs,
+ runfile = targets,
+ buildtarget = targets,
+ auto_build_solution=1,
+ variant = variants)
else:
diff --git a/bin/tests/SCsub b/bin/tests/SCsub
index 6613df9c05..57c9bc63b2 100644
--- a/bin/tests/SCsub
+++ b/bin/tests/SCsub
@@ -10,5 +10,3 @@ Export('env')
lib = env.Library("tests",env.tests_sources)
env.Prepend(LIBS=[lib])
-
-
diff --git a/bin/tests/test_containers.cpp b/bin/tests/test_containers.cpp
index db877fcc1c..f8cc8ccd41 100644
--- a/bin/tests/test_containers.cpp
+++ b/bin/tests/test_containers.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_containers.h b/bin/tests/test_containers.h
index 3bfdef301b..72d5c0ff7a 100644
--- a/bin/tests/test_containers.h
+++ b/bin/tests/test_containers.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_detailer.cpp b/bin/tests/test_detailer.cpp
index ce318632dd..616356077e 100644
--- a/bin/tests/test_detailer.cpp
+++ b/bin/tests/test_detailer.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_detailer.h b/bin/tests/test_detailer.h
index a410f6a67a..597e088caf 100644
--- a/bin/tests/test_detailer.h
+++ b/bin/tests/test_detailer.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_gdscript.cpp b/bin/tests/test_gdscript.cpp
index 68209ecb54..683191fba2 100644
--- a/bin/tests/test_gdscript.cpp
+++ b/bin/tests/test_gdscript.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_gdscript.h b/bin/tests/test_gdscript.h
index f599b9c9e1..225654e2a8 100644
--- a/bin/tests/test_gdscript.h
+++ b/bin/tests/test_gdscript.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_gui.cpp b/bin/tests/test_gui.cpp
index c404623872..cba488a3da 100644
--- a/bin/tests/test_gui.cpp
+++ b/bin/tests/test_gui.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_gui.h b/bin/tests/test_gui.h
index 556b45462a..5526320b0c 100644
--- a/bin/tests/test_gui.h
+++ b/bin/tests/test_gui.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_image.cpp b/bin/tests/test_image.cpp
index b378755dfe..bf9851cf01 100644
--- a/bin/tests/test_image.cpp
+++ b/bin/tests/test_image.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_image.h b/bin/tests/test_image.h
index 8812658464..09b33e799e 100644
--- a/bin/tests/test_image.h
+++ b/bin/tests/test_image.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_io.cpp b/bin/tests/test_io.cpp
index 4c211a1b0d..a1eb2be19b 100644
--- a/bin/tests/test_io.cpp
+++ b/bin/tests/test_io.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_io.h b/bin/tests/test_io.h
index 27a5118cf0..c839590ab9 100644
--- a/bin/tests/test_io.h
+++ b/bin/tests/test_io.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_main.cpp b/bin/tests/test_main.cpp
index 3dba347e39..8143a95d66 100644
--- a/bin/tests/test_main.cpp
+++ b/bin/tests/test_main.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -61,6 +61,7 @@ const char ** tests_get_names() {
"gui",
"io",
"shaderlang",
+ "physics",
NULL
};
diff --git a/bin/tests/test_main.h b/bin/tests/test_main.h
index d1898387eb..c8d571a7dd 100644
--- a/bin/tests/test_main.h
+++ b/bin/tests/test_main.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_math.cpp b/bin/tests/test_math.cpp
index d340515c65..b5041b265f 100644
--- a/bin/tests/test_math.cpp
+++ b/bin/tests/test_math.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_math.h b/bin/tests/test_math.h
index 3209ebcef6..492c3a1837 100644
--- a/bin/tests/test_math.h
+++ b/bin/tests/test_math.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_misc.cpp b/bin/tests/test_misc.cpp
index d6ea193853..68564c62b0 100644
--- a/bin/tests/test_misc.cpp
+++ b/bin/tests/test_misc.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_misc.h b/bin/tests/test_misc.h
index ac751e5cc9..55608f6a0e 100644
--- a/bin/tests/test_misc.h
+++ b/bin/tests/test_misc.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_particles.cpp b/bin/tests/test_particles.cpp
index 18b52444d8..bafd78eda0 100644
--- a/bin/tests/test_particles.cpp
+++ b/bin/tests/test_particles.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_particles.h b/bin/tests/test_particles.h
index e5e3cfab15..e95637a4e6 100644
--- a/bin/tests/test_particles.h
+++ b/bin/tests/test_particles.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_physics.cpp b/bin/tests/test_physics.cpp
index e3fd96ff9d..ce96f37f3f 100644
--- a/bin/tests/test_physics.cpp
+++ b/bin/tests/test_physics.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_physics.h b/bin/tests/test_physics.h
index f62806bf5e..5b6a54f2d4 100644
--- a/bin/tests/test_physics.h
+++ b/bin/tests/test_physics.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_physics_2d.cpp b/bin/tests/test_physics_2d.cpp
index 70a7d868be..c5fb734999 100644
--- a/bin/tests/test_physics_2d.cpp
+++ b/bin/tests/test_physics_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_physics_2d.h b/bin/tests/test_physics_2d.h
index eadd5ebcb4..e2eb1f4023 100644
--- a/bin/tests/test_physics_2d.h
+++ b/bin/tests/test_physics_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_python.cpp b/bin/tests/test_python.cpp
index a89e4a7eee..575caf2513 100644
--- a/bin/tests/test_python.cpp
+++ b/bin/tests/test_python.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_python.h b/bin/tests/test_python.h
index 9dafbd545d..77e9603fe2 100644
--- a/bin/tests/test_python.h
+++ b/bin/tests/test_python.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_render.cpp b/bin/tests/test_render.cpp
index 97a52b16c1..568699e5e6 100644
--- a/bin/tests/test_render.cpp
+++ b/bin/tests/test_render.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_render.h b/bin/tests/test_render.h
index dc71a32978..6993e75b9f 100644
--- a/bin/tests/test_render.h
+++ b/bin/tests/test_render.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_shader_lang.cpp b/bin/tests/test_shader_lang.cpp
index df826e489d..e55ad3074f 100644
--- a/bin/tests/test_shader_lang.cpp
+++ b/bin/tests/test_shader_lang.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_shader_lang.h b/bin/tests/test_shader_lang.h
index 85d379bc43..f129fb224a 100644
--- a/bin/tests/test_shader_lang.h
+++ b/bin/tests/test_shader_lang.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_sound.cpp b/bin/tests/test_sound.cpp
index 63c6edd9c9..44cc117e02 100644
--- a/bin/tests/test_sound.cpp
+++ b/bin/tests/test_sound.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_sound.h b/bin/tests/test_sound.h
index 32b66c8bba..91b87a2261 100644
--- a/bin/tests/test_sound.h
+++ b/bin/tests/test_sound.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/bin/tests/test_string.cpp b/bin/tests/test_string.cpp
index 3c8d0f7d86..fe7bf4d9cf 100644
--- a/bin/tests/test_string.cpp
+++ b/bin/tests/test_string.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,7 +31,7 @@
//#include "math_funcs.h"
#include <stdio.h>
#include "os/os.h"
-#include "drivers/trex/regex.h"
+#include "drivers/nrex/regex.h"
#include "test_string.h"
@@ -463,20 +463,16 @@ bool test_26() {
OS::get_singleton()->print("\n\nTest 26: RegEx\n");
RegEx regexp("(.*):(.*)");
- List<String> captures;
- bool match = regexp.match("name:password", &captures);
- printf("\tmatch: %s\n", match?"true":"false");
+ int res = regexp.find("name:password");
+ printf("\tmatch: %s\n", (res>=0)?"true":"false");
- printf("\t%i captures:\n", captures.size());
- List<String>::Element *I = captures.front();
- while (I) {
-
- printf("%ls\n", I->get().c_str());
-
- I = I->next();
- };
- return captures.size();
+ printf("\t%i captures:\n", regexp.get_capture_count());
+ for (int i = 0; i<regexp.get_capture_count(); i++)
+ {
+ printf("%ls\n", regexp.get_capture(i).c_str());
+ }
+ return res;
};
struct test_27_data {
diff --git a/bin/tests/test_string.h b/bin/tests/test_string.h
index b04eccb005..7b3cd9a019 100644
--- a/bin/tests/test_string.h
+++ b/bin/tests/test_string.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/SCsub b/core/SCsub
index d04041141c..4ce91c794f 100644
--- a/core/SCsub
+++ b/core/SCsub
@@ -63,5 +63,3 @@ SConscript('bind/SCsub');
lib = env.Library("core",env.core_sources)
env.Prepend(LIBS=[lib])
-
-
diff --git a/core/allocators.h b/core/allocators.h
index 16e516e87b..4a5fd7a119 100644
--- a/core/allocators.h
+++ b/core/allocators.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/array.cpp b/core/array.cpp
index ab9f19d6a0..fef0fcbb40 100644
--- a/core/array.cpp
+++ b/core/array.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -222,6 +222,24 @@ void Array::invert(){
}
+void Array::push_front(const Variant& p_value) {
+
+ _p->array.insert(0,p_value);
+}
+
+void Array::pop_back(){
+
+ if (!_p->array.empty())
+ _p->array.resize( _p->array.size() -1 );
+
+}
+void Array::pop_front(){
+
+ if (!_p->array.empty())
+ _p->array.remove(0);
+
+}
+
Array::Array(const Array& p_from) {
diff --git a/core/array.h b/core/array.h
index 904309b257..ecb91b69dc 100644
--- a/core/array.h
+++ b/core/array.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -53,7 +53,7 @@ public:
bool empty() const;
void clear();
- bool is_shared() const;
+ bool is_shared() const;
bool operator==(const Array& p_array) const;
@@ -75,6 +75,10 @@ public:
void erase(const Variant& p_value);
+ void push_front(const Variant& p_value);
+ void pop_back();
+ void pop_front();
+
Array(const Array& p_from);
Array(bool p_shared=false);
~Array();
diff --git a/core/balloon_allocator.h b/core/balloon_allocator.h
index 177c744669..eb6632bb37 100644
--- a/core/balloon_allocator.h
+++ b/core/balloon_allocator.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/bind/SCsub b/core/bind/SCsub
index c6ba1fa537..7b4a6acbc0 100644
--- a/core/bind/SCsub
+++ b/core/bind/SCsub
@@ -3,5 +3,3 @@ Import('env')
env.add_source_files(env.core_sources,"*.cpp")
Export('env')
-
-
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp
index 26b1dac6f1..94d9e22a1e 100644
--- a/core/bind/core_bind.cpp
+++ b/core/bind/core_bind.cpp
@@ -62,8 +62,8 @@ void _ResourceLoader::_bind_methods() {
ObjectTypeDB::bind_method(_MD("load:Resource","path","type_hint", "p_no_cache"),&_ResourceLoader::load,DEFVAL(""), DEFVAL(false));
ObjectTypeDB::bind_method(_MD("get_recognized_extensions_for_type","type"),&_ResourceLoader::get_recognized_extensions_for_type);
ObjectTypeDB::bind_method(_MD("set_abort_on_missing_resources","abort"),&_ResourceLoader::set_abort_on_missing_resources);
- ObjectTypeDB::bind_method(_MD("get_dependencies"),&_ResourceLoader::get_dependencies);
- ObjectTypeDB::bind_method(_MD("has"),&_ResourceLoader::has);
+ ObjectTypeDB::bind_method(_MD("get_dependencies","path"),&_ResourceLoader::get_dependencies);
+ ObjectTypeDB::bind_method(_MD("has","path"),&_ResourceLoader::has);
}
_ResourceLoader::_ResourceLoader() {
@@ -96,7 +96,7 @@ _ResourceSaver *_ResourceSaver::singleton=NULL;
void _ResourceSaver::_bind_methods() {
- ObjectTypeDB::bind_method(_MD("save","path","resource:Resource"),&_ResourceSaver::save, DEFVAL(0));
+ ObjectTypeDB::bind_method(_MD("save","path","resource:Resource","flags"),&_ResourceSaver::save,DEFVAL(0));
ObjectTypeDB::bind_method(_MD("get_recognized_extensions","type"),&_ResourceSaver::get_recognized_extensions);
BIND_CONSTANT(FLAG_RELATIVE_PATHS);
@@ -494,6 +494,10 @@ uint64_t _OS::get_unix_time() const {
return OS::get_singleton()->get_unix_time();
};
+uint64_t _OS::get_system_time_secs() const {
+ return OS::get_singleton()->get_system_time_secs();
+}
+
void _OS::delay_usec(uint32_t p_usec) const {
OS::get_singleton()->delay_usec(p_usec);
@@ -694,6 +698,26 @@ bool _OS::is_debug_build() const {
}
+void _OS::set_screen_orientation(ScreenOrientation p_orientation) {
+
+ OS::get_singleton()->set_screen_orientation(OS::ScreenOrientation(p_orientation));
+}
+
+_OS::ScreenOrientation _OS::get_screen_orientation() const {
+
+ return ScreenOrientation(OS::get_singleton()->get_screen_orientation());
+}
+
+void _OS::set_keep_screen_on(bool p_enabled) {
+
+ OS::get_singleton()->set_keep_screen_on(p_enabled);
+}
+
+bool _OS::is_keep_screen_on() const {
+
+ return OS::get_singleton()->is_keep_screen_on();
+}
+
String _OS::get_system_dir(SystemDir p_dir) const {
return OS::get_singleton()->get_system_dir(OS::SystemDir(p_dir));
@@ -717,6 +741,11 @@ int _OS::find_scancode_from_string(const String& p_code) const {
return find_keycode(p_code);
}
+void _OS::alert(const String& p_alert,const String& p_title) {
+
+ OS::get_singleton()->alert(p_alert,p_title);
+}
+
_OS *_OS::singleton=NULL;
void _OS::_bind_methods() {
@@ -752,6 +781,11 @@ void _OS::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_window_maximized", "enabled"),&_OS::set_window_maximized);
ObjectTypeDB::bind_method(_MD("is_window_maximized"),&_OS::is_window_maximized);
+ ObjectTypeDB::bind_method(_MD("set_screen_orientation","orientation"),&_OS::set_screen_orientation);
+ ObjectTypeDB::bind_method(_MD("get_screen_orientation"),&_OS::get_screen_orientation);
+
+ ObjectTypeDB::bind_method(_MD("set_keep_screen_on","enabled"),&_OS::set_keep_screen_on);
+ ObjectTypeDB::bind_method(_MD("is_keep_screen_on"),&_OS::is_keep_screen_on);
ObjectTypeDB::bind_method(_MD("set_iterations_per_second","iterations_per_second"),&_OS::set_iterations_per_second);
ObjectTypeDB::bind_method(_MD("get_iterations_per_second"),&_OS::get_iterations_per_second);
@@ -787,8 +821,9 @@ void _OS::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_time","utc"),&_OS::get_time,DEFVAL(false));
ObjectTypeDB::bind_method(_MD("get_time_zone_info"),&_OS::get_time_zone_info);
ObjectTypeDB::bind_method(_MD("get_unix_time"),&_OS::get_unix_time);
+ ObjectTypeDB::bind_method(_MD("get_system_time_secs"), &_OS::get_system_time_secs);
- ObjectTypeDB::bind_method(_MD("set_icon"),&_OS::set_icon);
+ ObjectTypeDB::bind_method(_MD("set_icon","icon"),&_OS::set_icon);
ObjectTypeDB::bind_method(_MD("delay_usec","usec"),&_OS::delay_usec);
ObjectTypeDB::bind_method(_MD("delay_msec","msec"),&_OS::delay_msec);
@@ -827,9 +862,9 @@ void _OS::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_frames_per_second"),&_OS::get_frames_per_second);
ObjectTypeDB::bind_method(_MD("print_all_textures_by_size"),&_OS::print_all_textures_by_size);
- ObjectTypeDB::bind_method(_MD("print_resources_by_type"),&_OS::print_resources_by_type);
+ ObjectTypeDB::bind_method(_MD("print_resources_by_type","types"),&_OS::print_resources_by_type);
- ObjectTypeDB::bind_method(_MD("native_video_play"),&_OS::native_video_play);
+ ObjectTypeDB::bind_method(_MD("native_video_play","path","volume","audio_track","subtitle_track"),&_OS::native_video_play);
ObjectTypeDB::bind_method(_MD("native_video_is_playing"),&_OS::native_video_is_playing);
ObjectTypeDB::bind_method(_MD("native_video_stop"),&_OS::native_video_stop);
ObjectTypeDB::bind_method(_MD("native_video_pause"),&_OS::native_video_pause);
@@ -840,6 +875,7 @@ void _OS::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_use_file_access_save_and_swap","enabled"),&_OS::set_use_file_access_save_and_swap);
+ ObjectTypeDB::bind_method(_MD("alert","text","title"),&_OS::alert,DEFVAL("Alert!"));
BIND_CONSTANT( DAY_SUNDAY );
@@ -863,6 +899,14 @@ void _OS::_bind_methods() {
BIND_CONSTANT( MONTH_NOVEMBER );
BIND_CONSTANT( MONTH_DECEMBER );
+ BIND_CONSTANT( SCREEN_ORIENTATION_LANDSCAPE );
+ BIND_CONSTANT( SCREEN_ORIENTATION_PORTRAIT );
+ BIND_CONSTANT( SCREEN_ORIENTATION_REVERSE_LANDSCAPE );
+ BIND_CONSTANT( SCREEN_ORIENTATION_REVERSE_PORTRAIT );
+ BIND_CONSTANT( SCREEN_ORIENTATION_SENSOR_LANDSCAPE );
+ BIND_CONSTANT( SCREEN_ORIENTATION_SENSOR_PORTRAIT );
+ BIND_CONSTANT( SCREEN_ORIENTATION_SENSOR );
+
BIND_CONSTANT( SYSTEM_DIR_DESKTOP);
BIND_CONSTANT( SYSTEM_DIR_DCIM );
BIND_CONSTANT( SYSTEM_DIR_DOCUMENTS );
@@ -1476,6 +1520,7 @@ void _File::_bind_methods() {
BIND_CONSTANT( READ );
BIND_CONSTANT( WRITE );
BIND_CONSTANT( READ_WRITE );
+ BIND_CONSTANT( WRITE_READ );
}
_File::_File(){
@@ -1678,12 +1723,89 @@ Variant _Marshalls::base64_to_variant(const String& p_str) {
return v;
};
+String _Marshalls::raw_to_base64(const DVector<uint8_t> &p_arr) {
+
+ int len = p_arr.size();
+ DVector<uint8_t>::Read r = p_arr.read();
+
+ int b64len = len / 3 * 4 + 4 + 1;
+ DVector<uint8_t> b64buff;
+ b64buff.resize(b64len);
+ DVector<uint8_t>::Write w64 = b64buff.write();
+
+ int strlen = base64_encode((char*)(&w64[0]), (char*)(&r[0]), len);
+ w64[strlen] = 0;
+ String ret = (char*)&w64[0];
+
+ return ret;
+};
+
+DVector<uint8_t> _Marshalls::base64_to_raw(const String &p_str) {
+
+ int strlen = p_str.length();
+ CharString cstr = p_str.ascii();
+
+ int arr_len;
+ DVector<uint8_t> buf;
+ {
+ buf.resize(strlen / 4 * 3 + 1);
+ DVector<uint8_t>::Write w = buf.write();
+
+ arr_len = base64_decode((char*)(&w[0]), (char*)cstr.get_data(), strlen);
+ };
+ buf.resize(arr_len);
+
+ // conversion from DVector<uint8_t> to raw array?
+ return buf;
+};
+
+String _Marshalls::utf8_to_base64(const String& p_str) {
+
+ CharString cstr = p_str.utf8();
+ int len = cstr.length();
+
+ int b64len = len / 3 * 4 + 4 + 1;
+ DVector<uint8_t> b64buff;
+ b64buff.resize(b64len);
+ DVector<uint8_t>::Write w64 = b64buff.write();
+
+ int strlen = base64_encode((char*)(&w64[0]), (char*)cstr.get_data(), len);
+
+ w64[strlen] = 0;
+ String ret = (char*)&w64[0];
+
+ return ret;
+};
+
+String _Marshalls::base64_to_utf8(const String& p_str) {
+
+ int strlen = p_str.length();
+ CharString cstr = p_str.ascii();
+
+ DVector<uint8_t> buf;
+ buf.resize(strlen / 4 * 3 + 1 + 1);
+ DVector<uint8_t>::Write w = buf.write();
+
+ int len = base64_decode((char*)(&w[0]), (char*)cstr.get_data(), strlen);
+
+ w[len] = 0;
+ String ret = String::utf8((char*)&w[0]);
+
+ return ret;
+};
+
void _Marshalls::_bind_methods() {
ObjectTypeDB::bind_method(_MD("variant_to_base64:String","variant"),&_Marshalls::variant_to_base64);
ObjectTypeDB::bind_method(_MD("base64_to_variant:Variant","base64_str"),&_Marshalls::base64_to_variant);
+ ObjectTypeDB::bind_method(_MD("raw_to_base64:String","array"),&_Marshalls::raw_to_base64);
+ ObjectTypeDB::bind_method(_MD("base64_to_raw:RawArray","base64_str"),&_Marshalls::base64_to_raw);
+
+ ObjectTypeDB::bind_method(_MD("utf8_to_base64:String","utf8_str"),&_Marshalls::utf8_to_base64);
+ ObjectTypeDB::bind_method(_MD("base64_to_utf8:String","base64_str"),&_Marshalls::base64_to_utf8);
+
};
@@ -1772,6 +1894,15 @@ void _Thread::_start_func(void *ud) {
memdelete(tud);
Variant::CallError ce;
const Variant* arg[1]={&t->userdata};
+
+ // we don't know our thread pointer yet :(
+ if (t->name == "") {
+ // come up with a better name using maybe the filename on the Script?
+ //t->thread->set_name(t->target_method);
+ } else {
+ //t->thread->set_name(t->name);
+ };
+
t->ret=t->target_instance->call(t->target_method,arg,1,ce);
if (ce.error!=Variant::CallError::CALL_OK) {
@@ -1796,6 +1927,7 @@ void _Thread::_start_func(void *ud) {
default: {}
}
+
ERR_EXPLAIN("Could not call function '"+t->target_method.operator String()+"'' starting thread ID: "+t->get_id()+" Reason: "+reason);
ERR_FAIL();
}
@@ -1860,12 +1992,24 @@ Variant _Thread::wait_to_finish() {
return r;
}
+Error _Thread::set_name(const String &p_name) {
+
+ name = p_name;
+
+ if (thread) {
+ return thread->set_name(p_name);
+ };
+
+ return OK;
+};
+
void _Thread::_bind_methods() {
ObjectTypeDB::bind_method(_MD("start:Error","instance","method","userdata","priority"),&_Thread::start,DEFVAL(Variant()),DEFVAL(PRIORITY_NORMAL));
ObjectTypeDB::bind_method(_MD("get_id"),&_Thread::get_id);
ObjectTypeDB::bind_method(_MD("is_active"),&_Thread::is_active);
- ObjectTypeDB::bind_method(_MD("wait_to_finish:var"),&_Thread::wait_to_finish);
+ ObjectTypeDB::bind_method(_MD("wait_to_finish:Variant"),&_Thread::wait_to_finish);
+ ObjectTypeDB::bind_method(_MD("set_name:Error", "name"),&_Thread::set_name);
BIND_CONSTANT( PRIORITY_LOW );
BIND_CONSTANT( PRIORITY_NORMAL );
diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h
index 74f29c23e8..e03657f3a0 100644
--- a/core/bind/core_bind.h
+++ b/core/bind/core_bind.h
@@ -208,6 +208,7 @@ public:
Dictionary get_time(bool utc) const;
Dictionary get_time_zone_info() const;
uint64_t get_unix_time() const;
+ uint64_t get_system_time_secs() const;
int get_static_memory_usage() const;
int get_static_memory_peak_usage() const;
@@ -239,11 +240,31 @@ public:
SYSTEM_DIR_RINGTONES,
};
+ enum ScreenOrientation {
+
+ SCREEN_ORIENTATION_LANDSCAPE,
+ SCREEN_ORIENTATION_PORTRAIT,
+ SCREEN_ORIENTATION_REVERSE_LANDSCAPE,
+ SCREEN_ORIENTATION_REVERSE_PORTRAIT,
+ SCREEN_ORIENTATION_SENSOR_LANDSCAPE,
+ SCREEN_ORIENTATION_SENSOR_PORTRAIT,
+ SCREEN_ORIENTATION_SENSOR,
+ };
+
String get_system_dir(SystemDir p_dir) const;
String get_data_dir() const;
+ void alert(const String& p_alert,const String& p_title="ALERT!");
+
+
+ void set_screen_orientation(ScreenOrientation p_orientation);
+ ScreenOrientation get_screen_orientation() const;
+
+ void set_keep_screen_on(bool p_enabled);
+ bool is_keep_screen_on() const;
+
void set_time_scale(float p_scale);
float get_time_scale();
@@ -255,6 +276,7 @@ public:
};
VARIANT_ENUM_CAST(_OS::SystemDir);
+VARIANT_ENUM_CAST(_OS::ScreenOrientation);
class _Geometry : public Object {
@@ -310,6 +332,7 @@ public:
READ=1,
WRITE=2,
READ_WRITE=3,
+ WRITE_READ=7,
};
Error open_encrypted(const String& p_path, int p_mode_flags,const Vector<uint8_t>& p_key);
@@ -436,6 +459,12 @@ public:
String variant_to_base64(const Variant& p_var);
Variant base64_to_variant(const String& p_str);
+ String raw_to_base64(const DVector<uint8_t>& p_arr);
+ DVector<uint8_t> base64_to_raw(const String& p_str);
+
+ String utf8_to_base64(const String& p_str);
+ String base64_to_utf8(const String& p_str);
+
_Marshalls() {};
};
@@ -483,6 +512,7 @@ protected:
Object *target_instance;
StringName target_method;
Thread *thread;
+ String name;
static void _bind_methods();
static void _start_func(void *ud);
public:
@@ -498,6 +528,7 @@ public:
String get_id() const;
bool is_active() const;
Variant wait_to_finish();
+ Error set_name(const String& p_name);
_Thread();
~_Thread();
diff --git a/core/color.cpp b/core/color.cpp
index 32f3df6d4b..c53de360bc 100644
--- a/core/color.cpp
+++ b/core/color.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/color.h b/core/color.h
index d5d5a4ea09..d0a1e8835c 100644
--- a/core/color.h
+++ b/core/color.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/command_queue_mt.cpp b/core/command_queue_mt.cpp
index f28617b33c..a2507b1378 100644
--- a/core/command_queue_mt.cpp
+++ b/core/command_queue_mt.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/command_queue_mt.h b/core/command_queue_mt.h
index 113199869b..4fd33e3a55 100644
--- a/core/command_queue_mt.h
+++ b/core/command_queue_mt.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -983,7 +983,7 @@ public:
void flush_all() {
- ERR_FAIL_COND(sync);
+ //ERR_FAIL_COND(sync);
lock();
while (true) {
bool exit = !flush_one();
diff --git a/core/compressed_translation.cpp b/core/compressed_translation.cpp
index 45fd4b5080..b104b8062a 100644
--- a/core/compressed_translation.cpp
+++ b/core/compressed_translation.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -410,15 +410,15 @@ bool PHashTranslation::_set(const StringName& p_name, const Variant& p_value) {
String name = p_name.operator String();
if (name=="hash_table") {
hash_table=p_value;
- print_line("translation: loaded hash table of size: "+itos(hash_table.size()));
+ //print_line("translation: loaded hash table of size: "+itos(hash_table.size()));
} else if (name=="bucket_table") {
bucket_table=p_value;
- print_line("translation: loaded bucket table of size: "+itos(bucket_table.size()));
+ //print_line("translation: loaded bucket table of size: "+itos(bucket_table.size()));
} else if (name=="strings") {
strings=p_value;
- print_line("translation: loaded string table of size: "+itos(strings.size()));
+ //print_line("translation: loaded string table of size: "+itos(strings.size()));
} else if (name=="load_from") {
- print_line("generating");
+ //print_line("generating");
generate(p_value);
} else
return false;
diff --git a/core/compressed_translation.h b/core/compressed_translation.h
index c41e2afb53..a1406ce1b2 100644
--- a/core/compressed_translation.h
+++ b/core/compressed_translation.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/core_string_names.cpp b/core/core_string_names.cpp
index d0cd19768f..8605b9131b 100644
--- a/core/core_string_names.cpp
+++ b/core/core_string_names.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/core_string_names.h b/core/core_string_names.h
index 8bda1f3f79..ef9e846c47 100644
--- a/core/core_string_names.h
+++ b/core/core_string_names.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/dictionary.cpp b/core/dictionary.cpp
index b2d31f230d..a013c21b29 100644
--- a/core/dictionary.cpp
+++ b/core/dictionary.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -160,7 +160,20 @@ void Dictionary::_unref() const {
}
uint32_t Dictionary::hash() const {
- return hash_djb2_one_64(make_uint64_t(_p));
+ uint32_t h=hash_djb2_one_32(Variant::DICTIONARY);
+
+ List<Variant> keys;
+ get_key_list(&keys);
+
+ for (List<Variant>::Element *E=keys.front();E;E=E->next()) {
+
+ h = hash_djb2_one_32( E->get().hash(), h);
+ h = hash_djb2_one_32( operator[](E->get()).hash(), h);
+
+ }
+
+
+ return h;
}
Array Dictionary::keys() const {
diff --git a/core/dictionary.h b/core/dictionary.h
index 8cbabfc65d..145e7e5c84 100644
--- a/core/dictionary.h
+++ b/core/dictionary.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/dvector.cpp b/core/dvector.cpp
index 60aa2e079f..fa06399139 100644
--- a/core/dvector.cpp
+++ b/core/dvector.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/dvector.h b/core/dvector.h
index 2c75bbf9eb..17431b33a6 100644
--- a/core/dvector.h
+++ b/core/dvector.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/error_list.h b/core/error_list.h
index 124027172e..cb531f527f 100644
--- a/core/error_list.h
+++ b/core/error_list.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -54,6 +54,7 @@ enum Error {
ERR_FILE_CANT_READ,
ERR_FILE_UNRECOGNIZED, // (15)
ERR_FILE_CORRUPT,
+ ERR_FILE_MISSING_DEPENDENCIES,
ERR_FILE_EOF,
ERR_CANT_OPEN, ///< Can't open a resource/socket/file
ERR_CANT_CREATE,
diff --git a/core/error_macros.cpp b/core/error_macros.cpp
index 53bce56626..03e5ba37da 100644
--- a/core/error_macros.cpp
+++ b/core/error_macros.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/error_macros.h b/core/error_macros.h
index 18b08d8e0e..cafbf0c16e 100644
--- a/core/error_macros.h
+++ b/core/error_macros.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -104,7 +104,7 @@ extern bool _err_error_exists;
#define ERR_FAIL_INDEX(m_index,m_size) \
do {if ((m_index)<0 || (m_index)>=(m_size)) { \
- _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Index "_STR(m_index)" out of size ("_STR(m_size)")."); \
+ _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Index " _STR(m_index)" out of size (" _STR(m_size)")."); \
return; \
} else _err_error_exists=false; } while(0); \
@@ -115,7 +115,7 @@ extern bool _err_error_exists;
#define ERR_FAIL_INDEX_V(m_index,m_size,m_retval) \
do {if ((m_index)<0 || (m_index)>=(m_size)) { \
- _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Index "_STR(m_index)" out of size ("_STR(m_size)")."); \
+ _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Index " _STR(m_index)" out of size (" _STR(m_size)")."); \
return m_retval; \
} else _err_error_exists=false;} while (0);
@@ -125,14 +125,14 @@ extern bool _err_error_exists;
#define ERR_FAIL_NULL(m_param) \
{ if ( !m_param ) { \
- _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Parameter ' "_STR(m_param)" ' is null."); \
+ _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Parameter ' " _STR(m_param)" ' is null."); \
return; \
}else _err_error_exists=false; } \
#define ERR_FAIL_NULL_V(m_param,m_retval) \
{ if ( !m_param ) { \
- _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Parameter ' "_STR(m_param)" ' is null."); \
+ _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Parameter ' " _STR(m_param)" ' is null."); \
return m_retval; \
}else _err_error_exists=false; } \
@@ -142,7 +142,7 @@ extern bool _err_error_exists;
#define ERR_FAIL_COND(m_cond) \
{ if ( m_cond ) { \
- _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Condition ' "_STR(m_cond)" ' is true."); \
+ _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Condition ' " _STR(m_cond)" ' is true."); \
return; \
}else _err_error_exists=false; } \
@@ -154,7 +154,7 @@ extern bool _err_error_exists;
#define ERR_FAIL_COND_V(m_cond,m_retval) \
{ if ( m_cond ) { \
- _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Condition ' "_STR(m_cond)" ' is true. returned: "_STR(m_retval)); \
+ _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Condition ' " _STR(m_cond)" ' is true. returned: " _STR(m_retval)); \
return m_retval; \
}else _err_error_exists=false; } \
@@ -164,7 +164,7 @@ extern bool _err_error_exists;
#define ERR_CONTINUE(m_cond) \
{ if ( m_cond ) { \
- _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Condition ' "_STR(m_cond)" ' is true. Continuing..:"); \
+ _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Condition ' " _STR(m_cond)" ' is true. Continuing..:"); \
continue;\
} else _err_error_exists=false;} \
@@ -174,7 +174,7 @@ extern bool _err_error_exists;
#define ERR_BREAK(m_cond) \
{ if ( m_cond ) { \
- _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Condition ' "_STR(m_cond)" ' is true. Breaking..:"); \
+ _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Condition ' " _STR(m_cond)" ' is true. Breaking..:"); \
break;\
} else _err_error_exists=false;} \
@@ -193,7 +193,7 @@ extern bool _err_error_exists;
#define ERR_FAIL_V(m_value) \
{ \
- _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Method/Function Failed, returning: "__STR(m_value)); \
+ _err_print_error(FUNCTION_STR,__FILE__,__LINE__,"Method/Function Failed, returning: " __STR(m_value)); \
_err_error_exists=false; \
return m_value;\
} \
@@ -207,6 +207,11 @@ extern bool _err_error_exists;
_err_error_exists=false;\
} \
+#define ERR_PRINTS(m_string) \
+ { \
+ _err_print_error(FUNCTION_STR,__FILE__,__LINE__,String(m_string).utf8().get_data()); \
+ _err_error_exists=false;\
+ } \
/** Print a warning string.
*/
diff --git a/core/event_queue.cpp b/core/event_queue.cpp
index 1afd686f86..088e80b266 100644
--- a/core/event_queue.cpp
+++ b/core/event_queue.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/event_queue.h b/core/event_queue.h
index 51ed7373eb..af0a4df2b8 100644
--- a/core/event_queue.h
+++ b/core/event_queue.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/fpstr.cpp b/core/fpstr.cpp
index 20b527d88b..76046d0b99 100644
--- a/core/fpstr.cpp
+++ b/core/fpstr.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/fpstr.h b/core/fpstr.h
index c8ff80806e..d3d02733b3 100644
--- a/core/fpstr.h
+++ b/core/fpstr.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/func_ref.cpp b/core/func_ref.cpp
index 0e43112de8..66962710bd 100644
--- a/core/func_ref.cpp
+++ b/core/func_ref.cpp
@@ -31,8 +31,7 @@ void FuncRef::_bind_methods() {
{
MethodInfo mi;
- mi.name="call";
- mi.arguments.push_back( PropertyInfo( Variant::STRING, "method"));
+ mi.name="call_func";
Vector<Variant> defargs;
for(int i=0;i<10;i++) {
mi.arguments.push_back( PropertyInfo( Variant::NIL, "arg"+itos(i)));
diff --git a/core/global_constants.cpp b/core/global_constants.cpp
index b8d113f67c..92e50a8b96 100644
--- a/core/global_constants.cpp
+++ b/core/global_constants.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -402,6 +402,9 @@ static _GlobalConstant _global_constants[]={
BIND_GLOBAL_CONSTANT( JOY_ANALOG_2_X ),
BIND_GLOBAL_CONSTANT( JOY_ANALOG_2_Y ),
+ BIND_GLOBAL_CONSTANT( JOY_ANALOG_L2 ),
+ BIND_GLOBAL_CONSTANT( JOY_ANALOG_R2 ),
+
// error list
@@ -422,6 +425,7 @@ static _GlobalConstant _global_constants[]={
BIND_GLOBAL_CONSTANT( ERR_FILE_CANT_READ ),
BIND_GLOBAL_CONSTANT( ERR_FILE_UNRECOGNIZED ),
BIND_GLOBAL_CONSTANT( ERR_FILE_CORRUPT ),
+ BIND_GLOBAL_CONSTANT( ERR_FILE_MISSING_DEPENDENCIES),
BIND_GLOBAL_CONSTANT( ERR_FILE_EOF ),
BIND_GLOBAL_CONSTANT( ERR_CANT_OPEN ), ///< Can't open a resource/socket/file
BIND_GLOBAL_CONSTANT( ERR_CANT_CREATE ),
diff --git a/core/global_constants.h b/core/global_constants.h
index 77cd3724c6..f7f6677482 100644
--- a/core/global_constants.h
+++ b/core/global_constants.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/globals.cpp b/core/globals.cpp
index 8a7d66b68a..1e60854f28 100644
--- a/core/globals.cpp
+++ b/core/globals.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -54,7 +54,7 @@ String Globals::localize_path(const String& p_path) const {
if (resource_path=="")
return p_path; //not initialied yet
- if (p_path.begins_with("res://"))
+ if (p_path.find(":/") != -1)
return p_path.simplify_path();
@@ -132,8 +132,12 @@ bool Globals::_set(const StringName& p_name, const Variant& p_value) {
if (props.has(p_name)) {
if (!props[p_name].overrided)
props[p_name].variant=p_value;
+
+ if (props[p_name].order>=NO_ORDER_BASE && registering_order) {
+ props[p_name].order=last_order++;
+ }
} else {
- props[p_name]=VariantContainer(p_value,last_order++);
+ props[p_name]=VariantContainer(p_value,last_order++ + (registering_order?0:NO_ORDER_BASE));
}
}
@@ -300,6 +304,7 @@ Error Globals::setup(const String& p_path,const String & p_main_pack) {
return OK;
}
+
if (OS::get_singleton()->get_resource_dir()!="") {
//OS will call Globals->get_resource_path which will be empty if not overriden!
//if the OS would rather use somewhere else, then it will not be empty.
@@ -309,7 +314,7 @@ Error Globals::setup(const String& p_path,const String & p_main_pack) {
print_line("has res dir: "+resource_path);
if (!_load_resource_pack("res://data.pck"))
- _load_resource_pack("res://data.pcz");
+ _load_resource_pack("res://data.zip");
// make sure this is load from the resource path
print_line("exists engine cfg? "+itos(FileAccess::exists("/engine.cfg")));
if (_load_settings("res://engine.cfg")==OK || _load_settings_binary("res://engine.cfb")==OK) {
@@ -332,6 +337,7 @@ Error Globals::setup(const String& p_path,const String & p_main_pack) {
String candidate = d->get_current_dir();
String current_dir = d->get_current_dir();
+ String exec_name = OS::get_singleton()->get_executable_path().get_file().basename();
bool found = false;
bool first_time=true;
@@ -339,7 +345,16 @@ Error Globals::setup(const String& p_path,const String & p_main_pack) {
//try to load settings in ascending through dirs shape!
//tries to open pack, but only first time
- if (first_time && (_load_resource_pack(current_dir+"/data.pck") || _load_resource_pack(current_dir+"/data.pcz") )) {
+ if (first_time && (_load_resource_pack(current_dir+"/"+exec_name+".pck") || _load_resource_pack(current_dir+"/"+exec_name+".zip") )) {
+ if (_load_settings("res://engine.cfg")==OK || _load_settings_binary("res://engine.cfb")==OK) {
+
+ _load_settings("res://override.cfg");
+ found=true;
+
+
+ }
+ break;
+ } else if (first_time && (_load_resource_pack(current_dir+"/data.pck") || _load_resource_pack(current_dir+"/data.zip") )) {
if (_load_settings("res://engine.cfg")==OK || _load_settings_binary("res://engine.cfb")==OK) {
_load_settings("res://override.cfg");
@@ -623,7 +638,9 @@ static Variant _decode_variant(const String& p_string) {
InputEvent ie;
ie.type=InputEvent::JOYSTICK_MOTION;
ie.device=params[0].to_int();
- ie.joy_motion.axis=params[1].to_int();
+ int axis = params[1].to_int();;
+ ie.joy_motion.axis=axis>>1;
+ ie.joy_motion.axis_value=axis&1?1:-1;
return ie;
}
@@ -731,6 +748,10 @@ static Variant _decode_variant(const String& p_string) {
return Variant();
}
+void Globals::set_registering_order(bool p_enable) {
+
+ registering_order=p_enable;
+}
Error Globals::_load_settings_binary(const String p_path) {
@@ -750,6 +771,8 @@ Error Globals::_load_settings_binary(const String p_path) {
ERR_FAIL_V(ERR_FILE_CORRUPT;)
}
+ set_registering_order(false);
+
uint32_t count=f->get_32();
for(int i=0;i<count;i++) {
@@ -774,6 +797,9 @@ Error Globals::_load_settings_binary(const String p_path) {
set_persisting(key,true);
}
+ set_registering_order(true);
+
+
return OK;
}
Error Globals::_load_settings(const String p_path) {
@@ -792,6 +818,8 @@ Error Globals::_load_settings(const String p_path) {
String section;
String subpath;
+ set_registering_order(false);
+
int line_count = 0;
while(!f->eof_reached()) {
@@ -867,6 +895,7 @@ Error Globals::_load_settings(const String p_path) {
memdelete(f);
+ set_registering_order(true);
return OK;
}
@@ -1002,7 +1031,7 @@ static String _encode_variant(const Variant& p_variant) {
} break;
case InputEvent::JOYSTICK_MOTION: {
- return "jaxis("+itos(ev.device)+", "+itos(ev.joy_motion.axis)+")";
+ return "jaxis("+itos(ev.device)+", "+itos(ev.joy_motion.axis * 2 + (ev.joy_motion.axis_value<0?0:1))+")";
} break;
default: {
@@ -1149,6 +1178,12 @@ Error Globals::_save_settings_text(const String& p_file,const Map<String,List<St
return OK;
}
+
+Error Globals::_save_custom_bnd(const String &p_file) { // add other params as dictionary and array?
+
+ return save_custom(p_file);
+};
+
Error Globals::save_custom(const String& p_path,const CustomMap& p_custom,const Set<String>& p_ignore_masks) {
ERR_FAIL_COND_V(p_path=="",ERR_INVALID_PARAMETER);
@@ -1321,7 +1356,7 @@ Vector<String> Globals::get_optimizer_presets() const {
if (!E->get().name.begins_with("optimizer_presets/"))
continue;
- names.push_back(E->get().name.get_slice("/",1));
+ names.push_back(E->get().name.get_slicec('/',1));
}
names.sort();
@@ -1358,9 +1393,12 @@ void Globals::_bind_methods() {
ObjectTypeDB::bind_method(_MD("localize_path","path"),&Globals::localize_path);
ObjectTypeDB::bind_method(_MD("globalize_path","path"),&Globals::globalize_path);
ObjectTypeDB::bind_method(_MD("save"),&Globals::save);
- ObjectTypeDB::bind_method(_MD("has_singleton"),&Globals::has_singleton);
- ObjectTypeDB::bind_method(_MD("get_singleton"),&Globals::get_singleton_object);
- ObjectTypeDB::bind_method(_MD("load_resource_pack"),&Globals::_load_resource_pack);
+ ObjectTypeDB::bind_method(_MD("has_singleton","name"),&Globals::has_singleton);
+ ObjectTypeDB::bind_method(_MD("get_singleton","name"),&Globals::get_singleton_object);
+ ObjectTypeDB::bind_method(_MD("load_resource_pack","pack"),&Globals::_load_resource_pack);
+
+ ObjectTypeDB::bind_method(_MD("save_custom","file"),&Globals::_save_custom_bnd);
+
}
Globals::Globals() {
@@ -1369,7 +1407,7 @@ Globals::Globals() {
singleton=this;
last_order=0;
disable_platform_override=false;
-
+ registering_order=true;
Array va;
@@ -1395,6 +1433,7 @@ Globals::Globals() {
joyb.joy_button.button_index=JOY_BUTTON_0;
va.push_back(joyb);
set("input/ui_accept",va);
+ input_presets.push_back("input/ui_accept");
va=Array();
key.key.scancode=KEY_SPACE;
@@ -1402,6 +1441,7 @@ Globals::Globals() {
joyb.joy_button.button_index=JOY_BUTTON_3;
va.push_back(joyb);
set("input/ui_select",va);
+ input_presets.push_back("input/ui_select");
va=Array();
key.key.scancode=KEY_ESCAPE;
@@ -1409,17 +1449,20 @@ Globals::Globals() {
joyb.joy_button.button_index=JOY_BUTTON_1;
va.push_back(joyb);
set("input/ui_cancel",va);
+ input_presets.push_back("input/ui_cancel");
va=Array();
key.key.scancode=KEY_TAB;
va.push_back(key);
set("input/ui_focus_next",va);
+ input_presets.push_back("input/ui_focus_next");
va=Array();
key.key.scancode=KEY_TAB;
key.key.mod.shift=true;
va.push_back(key);
set("input/ui_focus_prev",va);
+ input_presets.push_back("input/ui_focus_prev");
key.key.mod.shift=false;
va=Array();
@@ -1428,6 +1471,7 @@ Globals::Globals() {
joyb.joy_button.button_index=JOY_DPAD_LEFT;
va.push_back(joyb);
set("input/ui_left",va);
+ input_presets.push_back("input/ui_left");
va=Array();
key.key.scancode=KEY_RIGHT;
@@ -1435,6 +1479,7 @@ Globals::Globals() {
joyb.joy_button.button_index=JOY_DPAD_RIGHT;
va.push_back(joyb);
set("input/ui_right",va);
+ input_presets.push_back("input/ui_right");
va=Array();
key.key.scancode=KEY_UP;
@@ -1442,6 +1487,7 @@ Globals::Globals() {
joyb.joy_button.button_index=JOY_DPAD_UP;
va.push_back(joyb);
set("input/ui_up",va);
+ input_presets.push_back("input/ui_up");
va=Array();
key.key.scancode=KEY_DOWN;
@@ -1449,17 +1495,20 @@ Globals::Globals() {
joyb.joy_button.button_index=JOY_DPAD_DOWN;
va.push_back(joyb);
set("input/ui_down",va);
+ input_presets.push_back("input/ui_down");
va=Array();
key.key.scancode=KEY_PAGEUP;
va.push_back(key);
set("input/ui_page_up",va);
+ input_presets.push_back("input/ui_page_up");
va=Array();
key.key.scancode=KEY_PAGEDOWN;
va.push_back(key);
set("input/ui_page_down",va);
+ input_presets.push_back("input/ui_page_down");
// set("display/orientation", "landscape");
@@ -1468,7 +1517,6 @@ Globals::Globals() {
custom_prop_info["render/mipmap_policy"]=PropertyInfo(Variant::INT,"render/mipmap_policy",PROPERTY_HINT_ENUM,"Allow,Allow For Po2,Disallow");
custom_prop_info["render/thread_model"]=PropertyInfo(Variant::INT,"render/thread_model",PROPERTY_HINT_ENUM,"Single-Unsafe,Single-Safe,Multi-Threaded");
custom_prop_info["physics_2d/thread_model"]=PropertyInfo(Variant::INT,"physics_2d/thread_model",PROPERTY_HINT_ENUM,"Single-Unsafe,Single-Safe,Multi-Threaded");
- set("display/emulate_touchscreen",false);
using_datapack=false;
}
diff --git a/core/globals.h b/core/globals.h
index f739bcfb90..8951f5fbd2 100644
--- a/core/globals.h
+++ b/core/globals.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -54,6 +54,10 @@ public:
protected:
+ enum {
+ NO_ORDER_BASE=1<<18
+ };
+
struct VariantContainer {
int order;
bool persist;
@@ -64,12 +68,14 @@ protected:
VariantContainer(const Variant& p_variant, int p_order, bool p_persist=false) { variant=p_variant; order=p_order; hide_from_editor=false; persist=p_persist; overrided=false; }
};
+ bool registering_order;
int last_order;
Map<StringName,VariantContainer> props;
String resource_path;
Map<StringName,PropertyInfo> custom_prop_info;
bool disable_platform_override;
bool using_datapack;
+ List<String> input_presets;
bool _set(const StringName& p_name, const Variant& p_value);
@@ -86,6 +92,7 @@ protected:
List<Singleton> singletons;
+ Error _save_custom_bnd(const String& p_file);
bool _load_resource_pack(const String& p_pack);
@@ -123,6 +130,8 @@ public:
Vector<String> get_optimizer_presets() const;
+ List<String> get_input_presets() const { return input_presets; }
+
void set_disable_platform_override(bool p_disable);
Object* get_singleton_object(const String& p_name) const;
@@ -130,6 +139,8 @@ public:
bool is_using_datapack() const;
+ void set_registering_order(bool p_registering);
+
Globals();
~Globals();
diff --git a/core/hash_map.h b/core/hash_map.h
index eea6d1a153..33eb25652c 100644
--- a/core/hash_map.h
+++ b/core/hash_map.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/hashfuncs.h b/core/hashfuncs.h
index b12950f160..c2ed5bd679 100644
--- a/core/hashfuncs.h
+++ b/core/hashfuncs.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/image.cpp b/core/image.cpp
index 037018519e..798fc41f40 100644
--- a/core/image.cpp
+++ b/core/image.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,6 +34,33 @@
#include "print_string.h"
#include <stdio.h>
+
+const char* Image::format_names[Image::FORMAT_MAX]={
+ "Grayscale",
+ "Intensity",
+ "GrayscaleAlpha",
+ "RGB",
+ "RGBA",
+ "Indexed",
+ "IndexedAlpha",
+ "YUV422",
+ "YUV444",
+ "BC1",
+ "BC2",
+ "BC3",
+ "BC4",
+ "BC5",
+ "PVRTC2",
+ "PVRTC2Alpha",
+ "PVRTC4",
+ "PVRTC4Alpha",
+ "ETC",
+ "ATC",
+ "ATCAlphaExp",
+ "ATCAlphaInterp",
+
+};
+
SavePNGFunc Image::save_png_func = NULL;
void Image::_put_pixel(int p_x,int p_y, const BColor& p_color, unsigned char *p_data) {
@@ -295,7 +322,7 @@ void Image::set_pallete(const DVector<uint8_t>& p_data) {
DVector<uint8_t>::Write wp = data.write();
unsigned char *dst=wp.ptr() + pal_ofs;
- DVector<uint8_t>::Read r = data.read();
+ DVector<uint8_t>::Read r = p_data.read();
const unsigned char *src=r.ptr();
copymem(dst, src, len);
@@ -400,6 +427,102 @@ Image::Format Image::get_format() const{
return format;
}
+static double _bicubic_interp_kernel( double x ) {
+
+ x = ABS(x);
+
+ double bc = 0;
+
+ if ( x <= 1 )
+ bc = ( 1.5 * x - 2.5 ) * x * x + 1;
+ else if ( x < 2 )
+ bc = ( ( -0.5 * x + 2.5 ) * x - 4 ) * x + 2;
+
+
+ return bc;
+}
+
+template<int CC>
+static void _scale_cubic(const uint8_t* p_src, uint8_t* p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) {
+
+
+ // get source image size
+ int width = p_src_width;
+ int height = p_src_height;
+ double xfac = (double) width / p_dst_width;
+ double yfac = (double) height / p_dst_height;
+ // coordinates of source points and cooefficiens
+ double ox, oy, dx, dy, k1, k2;
+ int ox1, oy1, ox2, oy2;
+ // destination pixel values
+ // width and height decreased by 1
+ int ymax = height - 1;
+ int xmax = width - 1;
+ // temporary pointer
+
+ for ( int y = 0; y < p_dst_height; y++ ) {
+ // Y coordinates
+ oy = (double) y * yfac - 0.5f;
+ oy1 = (int) oy;
+ dy = oy - (double) oy1;
+
+ for ( int x = 0; x < p_dst_width; x++ ) {
+ // X coordinates
+ ox = (double) x * xfac - 0.5f;
+ ox1 = (int) ox;
+ dx = ox - (double) ox1;
+
+ // initial pixel value
+
+ uint8_t *dst=p_dst + (y*p_dst_width+x)*CC;
+
+ double color[CC];
+ for(int i=0;i<CC;i++) {
+ color[i]=0;
+ }
+
+
+
+ for ( int n = -1; n < 3; n++ ) {
+ // get Y cooefficient
+ k1 = _bicubic_interp_kernel( dy - (double) n );
+
+ oy2 = oy1 + n;
+ if ( oy2 < 0 )
+ oy2 = 0;
+ if ( oy2 > ymax )
+ oy2 = ymax;
+
+ for ( int m = -1; m < 3; m++ ) {
+ // get X cooefficient
+ k2 = k1 * _bicubic_interp_kernel( (double) m - dx );
+
+ ox2 = ox1 + m;
+ if ( ox2 < 0 )
+ ox2 = 0;
+ if ( ox2 > xmax )
+ ox2 = xmax;
+
+ // get pixel of original image
+ const uint8_t *p = p_src + (oy2 * p_src_width + ox2)*CC;
+
+ for(int i=0;i<CC;i++) {
+
+ color[i]+=p[i]*k2;
+ }
+ }
+ }
+
+ for(int i=0;i<CC;i++) {
+ dst[i]=CLAMP(Math::fast_ftoi(color[i]),0,255);
+ }
+ }
+ }
+}
+
+
+
+
template<int CC>
static void _scale_bilinear(const uint8_t* p_src, uint8_t* p_dst, uint32_t p_src_width, uint32_t p_src_height, uint32_t p_dst_width, uint32_t p_dst_height) {
@@ -559,6 +682,17 @@ void Image::resize( int p_width, int p_height, Interpolation p_interpolation ) {
}
} break;
+ case INTERPOLATE_CUBIC: {
+
+ switch(get_format_pixel_size(format)) {
+ case 1: _scale_cubic<1>(r_ptr,w_ptr,width,height,p_width,p_height); break;
+ case 2: _scale_cubic<2>(r_ptr,w_ptr,width,height,p_width,p_height); break;
+ case 3: _scale_cubic<3>(r_ptr,w_ptr,width,height,p_width,p_height); break;
+ case 4: _scale_cubic<4>(r_ptr,w_ptr,width,height,p_width,p_height); break;
+ }
+
+ } break;
+
}
@@ -1016,10 +1150,10 @@ void Image::create( const char ** p_xpm ) {
String line_str=line_ptr;
line_str.replace("\t"," ");
- size_width=line_str.get_slice(" ",0).to_int();
- size_height=line_str.get_slice(" ",1).to_int();
- colormap_size=line_str.get_slice(" ",2).to_int();
- pixelchars=line_str.get_slice(" ",3).to_int();
+ size_width=line_str.get_slicec(' ',0).to_int();
+ size_height=line_str.get_slicec(' ',1).to_int();
+ colormap_size=line_str.get_slicec(' ',2).to_int();
+ pixelchars=line_str.get_slicec(' ',3).to_int();
ERR_FAIL_COND(colormap_size > 32766);
ERR_FAIL_COND(pixelchars > 5);
ERR_FAIL_COND(size_width > 32767);
@@ -2248,6 +2382,12 @@ void Image::fix_alpha_edges() {
}
+String Image::get_format_name(Format p_format) {
+
+ ERR_FAIL_INDEX_V(p_format,FORMAT_MAX,String());
+ return format_names[p_format];
+}
+
Image::Image(const uint8_t* p_png,int p_len) {
width=0;
diff --git a/core/image.h b/core/image.h
index 8ce4f22dc1..aea5dc6438 100644
--- a/core/image.h
+++ b/core/image.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -87,10 +87,12 @@ public:
FORMAT_MAX
};
+ static const char* format_names[FORMAT_MAX];
enum Interpolation {
INTERPOLATE_NEAREST,
INTERPOLATE_BILINEAR,
+ INTERPOLATE_CUBIC,
/* INTERPOLATE GAUSS */
};
@@ -351,6 +353,8 @@ public:
Image get_rect(const Rect2& p_area) const;
static void set_compress_bc_func(void (*p_compress_func)(Image *));
+ static String get_format_name(Format p_format);
+
Image(const uint8_t* p_mem_png, int p_len=-1);
Image(const char **p_xpm);
~Image();
diff --git a/core/image_quantize.cpp b/core/image_quantize.cpp
index a14e0ab72e..b8d4658fda 100644
--- a/core/image_quantize.cpp
+++ b/core/image_quantize.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/input_map.cpp b/core/input_map.cpp
index 24151c59c9..d4560a1e1b 100644
--- a/core/input_map.cpp
+++ b/core/input_map.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -204,6 +204,64 @@ bool InputMap::event_is_action(const InputEvent& p_event, const StringName& p_ac
return _find_event(E->get().inputs,p_event)!=NULL;
}
+bool InputMap::event_is_joy_motion_action_pressed(const InputEvent& p_event) const {
+
+ ERR_FAIL_COND_V(p_event.type!=InputEvent::JOYSTICK_MOTION,false);
+ bool pressed=false;
+
+ //this could be optimized by having a separate list of joymotions?
+
+ for (Map<StringName, Action>::Element *A=input_map.front();A;A=A->next()) {
+
+ for (List<InputEvent>::Element *E=A->get().inputs.front();E;E=E->next()) {
+
+ const InputEvent& e=E->get();
+ if(e.type!=p_event.type)
+ continue;
+ if (e.type!=InputEvent::KEY && e.device!=p_event.device)
+ continue;
+
+ switch(p_event.type) {
+
+ case InputEvent::KEY: {
+
+ if (e.key.scancode==p_event.key.scancode && e.key.mod == p_event.key.mod)
+ return e.key.pressed;
+
+ } break;
+ case InputEvent::JOYSTICK_BUTTON: {
+
+ if (e.joy_button.button_index==p_event.joy_button.button_index) {
+ return e.joy_button.pressed;
+ }
+
+ } break;
+ case InputEvent::MOUSE_BUTTON: {
+
+ if (e.mouse_button.button_index==p_event.mouse_button.button_index) {
+ return e.mouse_button.pressed;
+ }
+
+ } break;
+ case InputEvent::JOYSTICK_MOTION: {
+
+ if (e.joy_motion.axis==p_event.joy_motion.axis) {
+ if (
+ (e.joy_motion.axis_value * p_event.joy_motion.axis_value >0) && //same axis
+ ABS(e.joy_motion.axis_value)>0.5 && ABS(p_event.joy_motion.axis_value)>0.5 )
+ pressed=true;
+ }
+
+ } break;
+ }
+
+ }
+ }
+
+ return pressed;
+
+}
+
void InputMap::load_from_globals() {
input_map.clear();;
diff --git a/core/input_map.h b/core/input_map.h
index c5b21b1457..5cd1e41922 100644
--- a/core/input_map.h
+++ b/core/input_map.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -68,6 +68,7 @@ public:
const List<InputEvent> *get_action_list(const StringName& p_action);
bool event_is_action(const InputEvent& p_event, const StringName& p_action) const;
+ bool event_is_joy_motion_action_pressed(const InputEvent& p_event) const;
void load_from_globals();
diff --git a/core/int_types.h b/core/int_types.h
index 231196b808..7d7c4b16b0 100644
--- a/core/int_types.h
+++ b/core/int_types.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/SCsub b/core/io/SCsub
index 5aecb4b915..3ff9b355a4 100644
--- a/core/io/SCsub
+++ b/core/io/SCsub
@@ -5,5 +5,3 @@ env.add_source_files(env.core_sources,"*.c")
#env.core_sources.append("io/fastlz.c")
Export('env')
-
-
diff --git a/core/io/aes256.cpp b/core/io/aes256.cpp
index 69a5091f1d..cfdac0214d 100644
--- a/core/io/aes256.cpp
+++ b/core/io/aes256.cpp
@@ -1,359 +1,399 @@
-/*
-* Byte-oriented AES-256 implementation.
-* All lookup tables replaced with 'on the fly' calculations.
-*
-* Copyright (c) 2007-2009 Ilya O. Levin, http://www.literatecode.com
-* Other contributors: Hal Finney
-*
-* Permission to use, copy, modify, and distribute this software for any
-* purpose with or without fee is hereby granted, provided that the above
-* copyright notice and this permission notice appear in all copies.
-*
-* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-*/
-#include "aes256.h"
-
-#define F(x) (((x)<<1) ^ ((((x)>>7) & 1) * 0x1b))
-#define FD(x) (((x) >> 1) ^ (((x) & 1) ? 0x8d : 0))
-
-// #define BACK_TO_TABLES
-#ifdef BACK_TO_TABLES
-
-const uint8_t sbox[256] = {
- 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
- 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
- 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
- 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
- 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
- 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
- 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
- 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
- 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
- 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
- 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
- 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
- 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
- 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
- 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
- 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
- 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
- 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
- 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
- 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
- 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
- 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
- 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
- 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
- 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
- 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
- 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
- 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
- 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
- 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
- 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
- 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
-};
-const uint8_t sboxinv[256] = {
- 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38,
- 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
- 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
- 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
- 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d,
- 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
- 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2,
- 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
- 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
- 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
- 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda,
- 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
- 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a,
- 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
- 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
- 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
- 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea,
- 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
- 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85,
- 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
- 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
- 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
- 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20,
- 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
- 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31,
- 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
- 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
- 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
- 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0,
- 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
- 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26,
- 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
-};
-
-#define rj_sbox(x) sbox[(x)]
-#define rj_sbox_inv(x) sboxinv[(x)]
-
-#else /* tableless subroutines */
-
-/* -------------------------------------------------------------------------- */
-uint8_t gf_alog(uint8_t x) // calculate anti-logarithm gen 3
-{
- uint8_t atb = 1, z;
-
- while (x--) {z = atb; atb <<= 1; if (z & 0x80) atb^= 0x1b; atb ^= z;}
-
- return atb;
-} /* gf_alog */
-
-/* -------------------------------------------------------------------------- */
-uint8_t gf_log(uint8_t x) // calculate logarithm gen 3
-{
- uint8_t atb = 1, i = 0, z;
-
- do {
- if (atb == x) break;
- z = atb; atb <<= 1; if (z & 0x80) atb^= 0x1b; atb ^= z;
- } while (++i > 0);
-
- return i;
-} /* gf_log */
-
-
-/* -------------------------------------------------------------------------- */
-uint8_t gf_mulinv(uint8_t x) // calculate multiplicative inverse
-{
- return (x) ? gf_alog(255 - gf_log(x)) : 0;
-} /* gf_mulinv */
-
-/* -------------------------------------------------------------------------- */
-uint8_t rj_sbox(uint8_t x)
-{
- uint8_t y, sb;
-
- sb = y = gf_mulinv(x);
- y = (y<<1)|(y>>7); sb ^= y; y = (y<<1)|(y>>7); sb ^= y;
- y = (y<<1)|(y>>7); sb ^= y; y = (y<<1)|(y>>7); sb ^= y;
-
- return (sb ^ 0x63);
-} /* rj_sbox */
-
-/* -------------------------------------------------------------------------- */
-uint8_t rj_sbox_inv(uint8_t x)
-{
- uint8_t y, sb;
-
- y = x ^ 0x63;
- sb = y = (y<<1)|(y>>7);
- y = (y<<2)|(y>>6); sb ^= y; y = (y<<3)|(y>>5); sb ^= y;
-
- return gf_mulinv(sb);
-} /* rj_sbox_inv */
-
-#endif
-
-/* -------------------------------------------------------------------------- */
-uint8_t rj_xtime(uint8_t x)
-{
- return (x & 0x80) ? ((x << 1) ^ 0x1b) : (x << 1);
-} /* rj_xtime */
-
-/* -------------------------------------------------------------------------- */
-void aes_subBytes(uint8_t *buf)
-{
- register uint8_t i = 16;
-
- while (i--) buf[i] = rj_sbox(buf[i]);
-} /* aes_subBytes */
-
-/* -------------------------------------------------------------------------- */
-void aes_subBytes_inv(uint8_t *buf)
-{
- register uint8_t i = 16;
-
- while (i--) buf[i] = rj_sbox_inv(buf[i]);
-} /* aes_subBytes_inv */
-
-/* -------------------------------------------------------------------------- */
-void aes_addRoundKey(uint8_t *buf, uint8_t *key)
-{
- register uint8_t i = 16;
-
- while (i--) buf[i] ^= key[i];
-} /* aes_addRoundKey */
-
-/* -------------------------------------------------------------------------- */
-void aes_addRoundKey_cpy(uint8_t *buf, uint8_t *key, uint8_t *cpk)
-{
- register uint8_t i = 16;
-
- while (i--) buf[i] ^= (cpk[i] = key[i]), cpk[16+i] = key[16 + i];
-} /* aes_addRoundKey_cpy */
-
-
-/* -------------------------------------------------------------------------- */
-void aes_shiftRows(uint8_t *buf)
-{
- register uint8_t i, j; /* to make it potentially parallelable :) */
-
- i = buf[1]; buf[1] = buf[5]; buf[5] = buf[9]; buf[9] = buf[13]; buf[13] = i;
- i = buf[10]; buf[10] = buf[2]; buf[2] = i;
- j = buf[3]; buf[3] = buf[15]; buf[15] = buf[11]; buf[11] = buf[7]; buf[7] = j;
- j = buf[14]; buf[14] = buf[6]; buf[6] = j;
-
-} /* aes_shiftRows */
-
-/* -------------------------------------------------------------------------- */
-void aes_shiftRows_inv(uint8_t *buf)
-{
- register uint8_t i, j; /* same as above :) */
-
- i = buf[1]; buf[1] = buf[13]; buf[13] = buf[9]; buf[9] = buf[5]; buf[5] = i;
- i = buf[2]; buf[2] = buf[10]; buf[10] = i;
- j = buf[3]; buf[3] = buf[7]; buf[7] = buf[11]; buf[11] = buf[15]; buf[15] = j;
- j = buf[6]; buf[6] = buf[14]; buf[14] = j;
-
-} /* aes_shiftRows_inv */
-
-/* -------------------------------------------------------------------------- */
-void aes_mixColumns(uint8_t *buf)
-{
- register uint8_t i, a, b, c, d, e;
-
- for (i = 0; i < 16; i += 4)
- {
- a = buf[i]; b = buf[i + 1]; c = buf[i + 2]; d = buf[i + 3];
- e = a ^ b ^ c ^ d;
- buf[i] ^= e ^ rj_xtime(a^b); buf[i+1] ^= e ^ rj_xtime(b^c);
- buf[i+2] ^= e ^ rj_xtime(c^d); buf[i+3] ^= e ^ rj_xtime(d^a);
- }
-} /* aes_mixColumns */
-
-/* -------------------------------------------------------------------------- */
-void aes_mixColumns_inv(uint8_t *buf)
-{
- register uint8_t i, a, b, c, d, e, x, y, z;
-
- for (i = 0; i < 16; i += 4)
- {
- a = buf[i]; b = buf[i + 1]; c = buf[i + 2]; d = buf[i + 3];
- e = a ^ b ^ c ^ d;
- z = rj_xtime(e);
- x = e ^ rj_xtime(rj_xtime(z^a^c)); y = e ^ rj_xtime(rj_xtime(z^b^d));
- buf[i] ^= x ^ rj_xtime(a^b); buf[i+1] ^= y ^ rj_xtime(b^c);
- buf[i+2] ^= x ^ rj_xtime(c^d); buf[i+3] ^= y ^ rj_xtime(d^a);
- }
-} /* aes_mixColumns_inv */
-
-/* -------------------------------------------------------------------------- */
-void aes_expandEncKey(uint8_t *k, uint8_t *rc)
-{
- register uint8_t i;
-
- k[0] ^= rj_sbox(k[29]) ^ (*rc);
- k[1] ^= rj_sbox(k[30]);
- k[2] ^= rj_sbox(k[31]);
- k[3] ^= rj_sbox(k[28]);
- *rc = F( *rc);
-
- for(i = 4; i < 16; i += 4) k[i] ^= k[i-4], k[i+1] ^= k[i-3],
- k[i+2] ^= k[i-2], k[i+3] ^= k[i-1];
- k[16] ^= rj_sbox(k[12]);
- k[17] ^= rj_sbox(k[13]);
- k[18] ^= rj_sbox(k[14]);
- k[19] ^= rj_sbox(k[15]);
-
- for(i = 20; i < 32; i += 4) k[i] ^= k[i-4], k[i+1] ^= k[i-3],
- k[i+2] ^= k[i-2], k[i+3] ^= k[i-1];
-
-} /* aes_expandEncKey */
-
-/* -------------------------------------------------------------------------- */
-void aes_expandDecKey(uint8_t *k, uint8_t *rc)
-{
- uint8_t i;
-
- for(i = 28; i > 16; i -= 4) k[i+0] ^= k[i-4], k[i+1] ^= k[i-3],
- k[i+2] ^= k[i-2], k[i+3] ^= k[i-1];
-
- k[16] ^= rj_sbox(k[12]);
- k[17] ^= rj_sbox(k[13]);
- k[18] ^= rj_sbox(k[14]);
- k[19] ^= rj_sbox(k[15]);
-
- for(i = 12; i > 0; i -= 4) k[i+0] ^= k[i-4], k[i+1] ^= k[i-3],
- k[i+2] ^= k[i-2], k[i+3] ^= k[i-1];
-
- *rc = FD(*rc);
- k[0] ^= rj_sbox(k[29]) ^ (*rc);
- k[1] ^= rj_sbox(k[30]);
- k[2] ^= rj_sbox(k[31]);
- k[3] ^= rj_sbox(k[28]);
-} /* aes_expandDecKey */
-
-
-/* -------------------------------------------------------------------------- */
-void aes256_init(aes256_context *ctx, uint8_t *k)
-{
- uint8_t rcon = 1;
- register uint8_t i;
-
- for (i = 0; i < sizeof(ctx->key); i++) ctx->enckey[i] = ctx->deckey[i] = k[i];
- for (i = 8;--i;) aes_expandEncKey(ctx->deckey, &rcon);
-} /* aes256_init */
-
-/* -------------------------------------------------------------------------- */
-void aes256_done(aes256_context *ctx)
-{
- register uint8_t i;
-
- for (i = 0; i < sizeof(ctx->key); i++)
- ctx->key[i] = ctx->enckey[i] = ctx->deckey[i] = 0;
-} /* aes256_done */
-
-/* -------------------------------------------------------------------------- */
-void aes256_encrypt_ecb(aes256_context *ctx, uint8_t *buf)
-{
- uint8_t i, rcon;
-
- aes_addRoundKey_cpy(buf, ctx->enckey, ctx->key);
- for(i = 1, rcon = 1; i < 14; ++i)
- {
- aes_subBytes(buf);
- aes_shiftRows(buf);
- aes_mixColumns(buf);
- if( i & 1 ) aes_addRoundKey( buf, &ctx->key[16]);
- else aes_expandEncKey(ctx->key, &rcon), aes_addRoundKey(buf, ctx->key);
- }
- aes_subBytes(buf);
- aes_shiftRows(buf);
- aes_expandEncKey(ctx->key, &rcon);
- aes_addRoundKey(buf, ctx->key);
-} /* aes256_encrypt */
-
-/* -------------------------------------------------------------------------- */
-void aes256_decrypt_ecb(aes256_context *ctx, uint8_t *buf)
-{
- uint8_t i, rcon;
-
- aes_addRoundKey_cpy(buf, ctx->deckey, ctx->key);
- aes_shiftRows_inv(buf);
- aes_subBytes_inv(buf);
-
- for (i = 14, rcon = 0x80; --i;)
- {
- if( ( i & 1 ) )
- {
- aes_expandDecKey(ctx->key, &rcon);
- aes_addRoundKey(buf, &ctx->key[16]);
- }
- else aes_addRoundKey(buf, ctx->key);
- aes_mixColumns_inv(buf);
- aes_shiftRows_inv(buf);
- aes_subBytes_inv(buf);
- }
- aes_addRoundKey( buf, ctx->key);
-} /* aes256_decrypt */
+/*
+* Byte-oriented AES-256 implementation.
+* All lookup tables replaced with 'on the fly' calculations.
+*
+* Copyright (c) 2007-2011 Ilya O. Levin, http://www.literatecode.com
+* Other contributors: Hal Finney
+*
+* Permission to use, copy, modify, and distribute this software for any
+* purpose with or without fee is hereby granted, provided that the above
+* copyright notice and this permission notice appear in all copies.
+*
+* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+#include "aes256.h"
+
+#define FD(x) (((x) >> 1) ^ (((x) & 1) ? 0x8d : 0))
+
+#define BACK_TO_TABLES
+
+static uint8_t rj_xtime(uint8_t);
+static void aes_subBytes(uint8_t *);
+static void aes_subBytes_inv(uint8_t *);
+static void aes_addRoundKey(uint8_t *, uint8_t *);
+static void aes_addRoundKey_cpy(uint8_t *, uint8_t *, uint8_t *);
+static void aes_shiftRows(uint8_t *);
+static void aes_shiftRows_inv(uint8_t *);
+static void aes_mixColumns(uint8_t *);
+static void aes_mixColumns_inv(uint8_t *);
+static void aes_expandEncKey(uint8_t *, uint8_t *);
+static void aes_expandDecKey(uint8_t *, uint8_t *);
+#ifndef BACK_TO_TABLES
+static uint8_t gf_alog(uint8_t);
+static uint8_t gf_log(uint8_t);
+static uint8_t gf_mulinv(uint8_t);
+static uint8_t rj_sbox(uint8_t);
+static uint8_t rj_sbox_inv(uint8_t);
+#endif
+
+#ifdef BACK_TO_TABLES
+
+static const uint8_t sbox[256] =
+{
+ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
+ 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
+ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
+ 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
+ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
+ 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
+ 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
+ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
+ 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
+ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
+ 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
+ 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
+ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
+ 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
+ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
+ 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
+ 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
+ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
+ 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
+ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
+ 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
+ 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
+ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
+ 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
+ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
+ 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
+ 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
+};
+static const uint8_t sboxinv[256] =
+{
+ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38,
+ 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
+ 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87,
+ 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
+ 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d,
+ 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
+ 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2,
+ 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
+ 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16,
+ 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
+ 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda,
+ 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
+ 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a,
+ 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
+ 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02,
+ 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
+ 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea,
+ 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
+ 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85,
+ 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
+ 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89,
+ 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
+ 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20,
+ 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
+ 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31,
+ 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
+ 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d,
+ 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
+ 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0,
+ 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
+ 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26,
+ 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
+};
+
+#define rj_sbox(x) sbox[(x)]
+#define rj_sbox_inv(x) sboxinv[(x)]
+
+#else /* tableless subroutines */
+
+/* -------------------------------------------------------------------------- */
+static uint8_t gf_alog(uint8_t x) // calculate anti-logarithm gen 3
+{
+ uint8_t y = 1, i;
+
+ for (i = 0; i < x; i++) y ^= rj_xtime(y);
+
+ return y;
+} /* gf_alog */
+
+/* -------------------------------------------------------------------------- */
+static uint8_t gf_log(uint8_t x) // calculate logarithm gen 3
+{
+ uint8_t y, i = 0;
+
+ if (x)
+ for (i = 1, y = 1; i > 0; i++ )
+ {
+ y ^= rj_xtime(y);
+ if (y == x) break;
+ }
+
+ return i;
+} /* gf_log */
+
+
+/* -------------------------------------------------------------------------- */
+static uint8_t gf_mulinv(uint8_t x) // calculate multiplicative inverse
+{
+ return (x) ? gf_alog(255 - gf_log(x)) : 0;
+} /* gf_mulinv */
+
+/* -------------------------------------------------------------------------- */
+static uint8_t rj_sbox(uint8_t x)
+{
+ uint8_t y, sb;
+
+ sb = y = gf_mulinv(x);
+ y = (uint8_t)(y << 1) | (y >> 7), sb ^= y;
+ y = (uint8_t)(y << 1) | (y >> 7), sb ^= y;
+ y = (uint8_t)(y << 1) | (y >> 7), sb ^= y;
+ y = (uint8_t)(y << 1) | (y >> 7), sb ^= y;
+
+ return (sb ^ 0x63);
+} /* rj_sbox */
+
+/* -------------------------------------------------------------------------- */
+static uint8_t rj_sbox_inv(uint8_t x)
+{
+ uint8_t y, sb;
+
+ y = x ^ 0x63;
+ sb = y = (uint8_t)(y << 1) | (y >> 7);
+ y = (uint8_t)(y << 2) | (y >> 6);
+ sb ^= y;
+ y = (uint8_t)(y << 3) | (y >> 5);
+ sb ^= y;
+
+ return gf_mulinv(sb);
+} /* rj_sbox_inv */
+
+#endif
+
+/* -------------------------------------------------------------------------- */
+static uint8_t rj_xtime(uint8_t x)
+{
+ uint8_t y = (uint8_t)(x << 1);
+ return (x & 0x80) ? (y ^ 0x1b) : y;
+} /* rj_xtime */
+
+/* -------------------------------------------------------------------------- */
+static void aes_subBytes(uint8_t *buf)
+{
+ register uint8_t i = 16;
+
+ while (i--) buf[i] = rj_sbox(buf[i]);
+} /* aes_subBytes */
+
+/* -------------------------------------------------------------------------- */
+static void aes_subBytes_inv(uint8_t *buf)
+{
+ register uint8_t i = 16;
+
+ while (i--) buf[i] = rj_sbox_inv(buf[i]);
+} /* aes_subBytes_inv */
+
+/* -------------------------------------------------------------------------- */
+static void aes_addRoundKey(uint8_t *buf, uint8_t *key)
+{
+ register uint8_t i = 16;
+
+ while (i--) buf[i] ^= key[i];
+} /* aes_addRoundKey */
+
+/* -------------------------------------------------------------------------- */
+static void aes_addRoundKey_cpy(uint8_t *buf, uint8_t *key, uint8_t *cpk)
+{
+ register uint8_t i = 16;
+
+ while (i--) buf[i] ^= (cpk[i] = key[i]), cpk[16 + i] = key[16 + i];
+} /* aes_addRoundKey_cpy */
+
+
+/* -------------------------------------------------------------------------- */
+static void aes_shiftRows(uint8_t *buf)
+{
+ register uint8_t i, j; /* to make it potentially parallelable :) */
+
+ i = buf[1], buf[1] = buf[5], buf[5] = buf[9], buf[9] = buf[13], buf[13] = i;
+ i = buf[10], buf[10] = buf[2], buf[2] = i;
+ j = buf[3], buf[3] = buf[15], buf[15] = buf[11], buf[11] = buf[7], buf[7] = j;
+ j = buf[14], buf[14] = buf[6], buf[6] = j;
+
+} /* aes_shiftRows */
+
+/* -------------------------------------------------------------------------- */
+static void aes_shiftRows_inv(uint8_t *buf)
+{
+ register uint8_t i, j; /* same as above :) */
+
+ i = buf[1], buf[1] = buf[13], buf[13] = buf[9], buf[9] = buf[5], buf[5] = i;
+ i = buf[2], buf[2] = buf[10], buf[10] = i;
+ j = buf[3], buf[3] = buf[7], buf[7] = buf[11], buf[11] = buf[15], buf[15] = j;
+ j = buf[6], buf[6] = buf[14], buf[14] = j;
+
+} /* aes_shiftRows_inv */
+
+/* -------------------------------------------------------------------------- */
+static void aes_mixColumns(uint8_t *buf)
+{
+ register uint8_t i, a, b, c, d, e;
+
+ for (i = 0; i < 16; i += 4)
+ {
+ a = buf[i];
+ b = buf[i + 1];
+ c = buf[i + 2];
+ d = buf[i + 3];
+ e = a ^ b ^ c ^ d;
+ buf[i] ^= e ^ rj_xtime(a ^ b);
+ buf[i + 1] ^= e ^ rj_xtime(b ^ c);
+ buf[i + 2] ^= e ^ rj_xtime(c ^ d);
+ buf[i + 3] ^= e ^ rj_xtime(d ^ a);
+ }
+} /* aes_mixColumns */
+
+/* -------------------------------------------------------------------------- */
+void aes_mixColumns_inv(uint8_t *buf)
+{
+ register uint8_t i, a, b, c, d, e, x, y, z;
+
+ for (i = 0; i < 16; i += 4)
+ {
+ a = buf[i];
+ b = buf[i + 1];
+ c = buf[i + 2];
+ d = buf[i + 3];
+ e = a ^ b ^ c ^ d;
+ z = rj_xtime(e);
+ x = e ^ rj_xtime(rj_xtime(z ^ a ^ c));
+ y = e ^ rj_xtime(rj_xtime(z ^ b ^ d));
+ buf[i] ^= x ^ rj_xtime(a ^ b);
+ buf[i + 1] ^= y ^ rj_xtime(b ^ c);
+ buf[i + 2] ^= x ^ rj_xtime(c ^ d);
+ buf[i + 3] ^= y ^ rj_xtime(d ^ a);
+ }
+} /* aes_mixColumns_inv */
+
+/* -------------------------------------------------------------------------- */
+static void aes_expandEncKey(uint8_t *k, uint8_t *rc)
+{
+ register uint8_t i;
+
+ k[0] ^= rj_sbox(k[29]) ^ (*rc);
+ k[1] ^= rj_sbox(k[30]);
+ k[2] ^= rj_sbox(k[31]);
+ k[3] ^= rj_sbox(k[28]);
+ *rc = rj_xtime( *rc);
+
+ for(i = 4; i < 16; i += 4) k[i] ^= k[i - 4], k[i + 1] ^= k[i - 3],
+ k[i + 2] ^= k[i - 2], k[i + 3] ^= k[i - 1];
+ k[16] ^= rj_sbox(k[12]);
+ k[17] ^= rj_sbox(k[13]);
+ k[18] ^= rj_sbox(k[14]);
+ k[19] ^= rj_sbox(k[15]);
+
+ for(i = 20; i < 32; i += 4) k[i] ^= k[i - 4], k[i + 1] ^= k[i - 3],
+ k[i + 2] ^= k[i - 2], k[i + 3] ^= k[i - 1];
+
+} /* aes_expandEncKey */
+
+/* -------------------------------------------------------------------------- */
+void aes_expandDecKey(uint8_t *k, uint8_t *rc)
+{
+ uint8_t i;
+
+ for(i = 28; i > 16; i -= 4) k[i + 0] ^= k[i - 4], k[i + 1] ^= k[i - 3],
+ k[i + 2] ^= k[i - 2], k[i + 3] ^= k[i - 1];
+
+ k[16] ^= rj_sbox(k[12]);
+ k[17] ^= rj_sbox(k[13]);
+ k[18] ^= rj_sbox(k[14]);
+ k[19] ^= rj_sbox(k[15]);
+
+ for(i = 12; i > 0; i -= 4) k[i + 0] ^= k[i - 4], k[i + 1] ^= k[i - 3],
+ k[i + 2] ^= k[i - 2], k[i + 3] ^= k[i - 1];
+
+ *rc = FD(*rc);
+ k[0] ^= rj_sbox(k[29]) ^ (*rc);
+ k[1] ^= rj_sbox(k[30]);
+ k[2] ^= rj_sbox(k[31]);
+ k[3] ^= rj_sbox(k[28]);
+} /* aes_expandDecKey */
+
+
+/* -------------------------------------------------------------------------- */
+void aes256_init(aes256_context *ctx, uint8_t *k)
+{
+ uint8_t rcon = 1;
+ register uint8_t i;
+
+ for (i = 0; i < sizeof(ctx->key); i++) ctx->enckey[i] = ctx->deckey[i] = k[i];
+ for (i = 8; --i;) aes_expandEncKey(ctx->deckey, &rcon);
+} /* aes256_init */
+
+/* -------------------------------------------------------------------------- */
+void aes256_done(aes256_context *ctx)
+{
+ register uint8_t i;
+
+ for (i = 0; i < sizeof(ctx->key); i++)
+ ctx->key[i] = ctx->enckey[i] = ctx->deckey[i] = 0;
+} /* aes256_done */
+
+/* -------------------------------------------------------------------------- */
+void aes256_encrypt_ecb(aes256_context *ctx, uint8_t *buf)
+{
+ uint8_t i, rcon;
+
+ aes_addRoundKey_cpy(buf, ctx->enckey, ctx->key);
+ for(i = 1, rcon = 1; i < 14; ++i)
+ {
+ aes_subBytes(buf);
+ aes_shiftRows(buf);
+ aes_mixColumns(buf);
+ if( i & 1 ) aes_addRoundKey( buf, &ctx->key[16]);
+ else aes_expandEncKey(ctx->key, &rcon), aes_addRoundKey(buf, ctx->key);
+ }
+ aes_subBytes(buf);
+ aes_shiftRows(buf);
+ aes_expandEncKey(ctx->key, &rcon);
+ aes_addRoundKey(buf, ctx->key);
+} /* aes256_encrypt */
+
+/* -------------------------------------------------------------------------- */
+void aes256_decrypt_ecb(aes256_context *ctx, uint8_t *buf)
+{
+ uint8_t i, rcon;
+
+ aes_addRoundKey_cpy(buf, ctx->deckey, ctx->key);
+ aes_shiftRows_inv(buf);
+ aes_subBytes_inv(buf);
+
+ for (i = 14, rcon = 0x80; --i;)
+ {
+ if( ( i & 1 ) )
+ {
+ aes_expandDecKey(ctx->key, &rcon);
+ aes_addRoundKey(buf, &ctx->key[16]);
+ }
+ else aes_addRoundKey(buf, ctx->key);
+ aes_mixColumns_inv(buf);
+ aes_shiftRows_inv(buf);
+ aes_subBytes_inv(buf);
+ }
+ aes_addRoundKey( buf, ctx->key);
+} /* aes256_decrypt */
diff --git a/core/io/aes256.h b/core/io/aes256.h
index 180352e970..fabbcf1968 100644
--- a/core/io/aes256.h
+++ b/core/io/aes256.h
@@ -1,46 +1,46 @@
-/*
-* Byte-oriented AES-256 implementation.
-* All lookup tables replaced with 'on the fly' calculations.
-*
-* Copyright (c) 2007-2009 Ilya O. Levin, http://www.literatecode.com
-* Other contributors: Hal Finney
-*
-* Permission to use, copy, modify, and distribute this software for any
-* purpose with or without fee is hereby granted, provided that the above
-* copyright notice and this permission notice appear in all copies.
-*
-* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-*/
-
-#ifndef AES_256_H
-#define AES_256_H
-
-#include "typedefs.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
- typedef struct {
- uint8_t key[32];
- uint8_t enckey[32];
- uint8_t deckey[32];
- } aes256_context;
-
-
- void aes256_init(aes256_context *, uint8_t * /* key */);
- void aes256_done(aes256_context *);
- void aes256_encrypt_ecb(aes256_context *, uint8_t * /* plaintext */);
- void aes256_decrypt_ecb(aes256_context *, uint8_t * /* cipertext */);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
+/*
+* Byte-oriented AES-256 implementation.
+* All lookup tables replaced with 'on the fly' calculations.
+*
+* Copyright (c) 2007-2009 Ilya O. Levin, http://www.literatecode.com
+* Other contributors: Hal Finney
+*
+* Permission to use, copy, modify, and distribute this software for any
+* purpose with or without fee is hereby granted, provided that the above
+* copyright notice and this permission notice appear in all copies.
+*
+* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#ifndef AES_256_H
+#define AES_256_H
+
+#include "typedefs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ typedef struct {
+ uint8_t key[32];
+ uint8_t enckey[32];
+ uint8_t deckey[32];
+ } aes256_context;
+
+
+ void aes256_init(aes256_context *, uint8_t * /* key */);
+ void aes256_done(aes256_context *);
+ void aes256_encrypt_ecb(aes256_context *, uint8_t * /* plaintext */);
+ void aes256_decrypt_ecb(aes256_context *, uint8_t * /* cipertext */);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/core/io/compression.cpp b/core/io/compression.cpp
index 0bc006b41e..a17e358cbb 100644
--- a/core/io/compression.cpp
+++ b/core/io/compression.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -26,12 +26,12 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#include "zlib.h"
+#include "os/copymem.h"
#include "compression.h"
#include "fastlz.h"
-#include "zlib.h"
#include "zip_io.h"
-#include "os/copymem.h"
int Compression::compress(uint8_t *p_dst, const uint8_t *p_src, int p_src_size,Mode p_mode) {
diff --git a/core/io/compression.h b/core/io/compression.h
index 106a3f0201..07a293c940 100644
--- a/core/io/compression.h
+++ b/core/io/compression.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/config_file.cpp b/core/io/config_file.cpp
index 75388f514a..fd20ec9404 100644
--- a/core/io/config_file.cpp
+++ b/core/io/config_file.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,6 +29,7 @@
#include "config_file.h"
#include "os/keyboard.h"
#include "os/file_access.h"
+#include "variant_parser.h"
StringArray ConfigFile::_get_sections() const {
@@ -83,10 +84,10 @@ void ConfigFile::set_value(const String& p_section, const String& p_key, const V
}
}
-Variant ConfigFile::get_value(const String& p_section, const String& p_key) const{
+Variant ConfigFile::get_value(const String& p_section, const String& p_key, Variant p_default) const {
- ERR_FAIL_COND_V(!values.has(p_section),Variant());
- ERR_FAIL_COND_V(!values[p_section].has(p_key),Variant());
+ ERR_FAIL_COND_V(!values.has(p_section),p_default);
+ ERR_FAIL_COND_V(!values[p_section].has(p_key),p_default);
return values[p_section][p_key];
}
@@ -118,151 +119,6 @@ void ConfigFile::get_section_keys(const String& p_section,List<String> *r_keys)
}
-static String _encode_variant(const Variant& p_variant) {
-
- switch(p_variant.get_type()) {
-
- case Variant::BOOL: {
- bool val = p_variant;
- return (val?"true":"false");
- } break;
- case Variant::INT: {
- int val = p_variant;
- return itos(val);
- } break;
- case Variant::REAL: {
- float val = p_variant;
- return rtos(val)+(val==int(val)?".0":"");
- } break;
- case Variant::STRING: {
- String val = p_variant;
- return "\""+val.xml_escape()+"\"";
- } break;
- case Variant::COLOR: {
-
- Color val = p_variant;
- return "#"+val.to_html();
- } break;
- case Variant::STRING_ARRAY:
- case Variant::INT_ARRAY:
- case Variant::REAL_ARRAY:
- case Variant::ARRAY: {
- Array arr = p_variant;
- String str="[";
- for(int i=0;i<arr.size();i++) {
-
- if (i>0)
- str+=", ";
- str+=_encode_variant(arr[i]);
- }
- str+="]";
- return str;
- } break;
- case Variant::DICTIONARY: {
- Dictionary d = p_variant;
- String str="{";
- List<Variant> keys;
- d.get_key_list(&keys);
- for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
-
- if (E!=keys.front())
- str+=", ";
- str+=_encode_variant(E->get());
- str+=":";
- str+=_encode_variant(d[E->get()]);
-
- }
- str+="}";
- return str;
- } break;
- case Variant::IMAGE: {
- String str="img(";
-
- Image img=p_variant;
- if (!img.empty()) {
-
- String format;
- switch(img.get_format()) {
-
- case Image::FORMAT_GRAYSCALE: format="grayscale"; break;
- case Image::FORMAT_INTENSITY: format="intensity"; break;
- case Image::FORMAT_GRAYSCALE_ALPHA: format="grayscale_alpha"; break;
- case Image::FORMAT_RGB: format="rgb"; break;
- case Image::FORMAT_RGBA: format="rgba"; break;
- case Image::FORMAT_INDEXED : format="indexed"; break;
- case Image::FORMAT_INDEXED_ALPHA: format="indexed_alpha"; break;
- case Image::FORMAT_BC1: format="bc1"; break;
- case Image::FORMAT_BC2: format="bc2"; break;
- case Image::FORMAT_BC3: format="bc3"; break;
- case Image::FORMAT_BC4: format="bc4"; break;
- case Image::FORMAT_BC5: format="bc5"; break;
- case Image::FORMAT_CUSTOM: format="custom custom_size="+itos(img.get_data().size())+""; break;
- default: {}
- }
-
- str+=format+", ";
- str+=itos(img.get_mipmaps())+", ";
- str+=itos(img.get_width())+", ";
- str+=itos(img.get_height())+", ";
- DVector<uint8_t> data = img.get_data();
- int ds=data.size();
- DVector<uint8_t>::Read r = data.read();
- for(int i=0;i<ds;i++) {
- uint8_t byte = r[i];
- const char hex[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
- char bstr[3]={ hex[byte>>4], hex[byte&0xF], 0};
- str+=bstr;
- }
- }
- str+=")";
- return str;
- } break;
- case Variant::INPUT_EVENT: {
-
- InputEvent ev = p_variant;
-
- switch(ev.type) {
-
- case InputEvent::KEY: {
-
- String mods;
- if (ev.key.mod.control)
- mods+="C";
- if (ev.key.mod.shift)
- mods+="S";
- if (ev.key.mod.alt)
- mods+="A";
- if (ev.key.mod.meta)
- mods+="M";
- if (mods!="")
- mods=", "+mods;
-
- return "key("+keycode_get_string(ev.key.scancode)+mods+")";
- } break;
- case InputEvent::MOUSE_BUTTON: {
-
- return "mbutton("+itos(ev.device)+", "+itos(ev.mouse_button.button_index)+")";
- } break;
- case InputEvent::JOYSTICK_BUTTON: {
-
- return "jbutton("+itos(ev.device)+", "+itos(ev.joy_button.button_index)+")";
- } break;
- case InputEvent::JOYSTICK_MOTION: {
-
- return "jaxis("+itos(ev.device)+", "+itos(ev.joy_motion.axis)+")";
- } break;
- default: {
-
- return "nil";
- } break;
-
- }
- } break;
- default: {}
- }
-
- return "nil"; //don't know wha to do with this
-}
Error ConfigFile::save(const String& p_path){
@@ -271,6 +127,8 @@ Error ConfigFile::save(const String& p_path){
FileAccess *file = FileAccess::open(p_path,FileAccess::WRITE,&err);
if (err) {
+ if (file)
+ memdelete(file);
return err;
}
@@ -283,7 +141,9 @@ Error ConfigFile::save(const String& p_path){
for(Map<String, Variant>::Element *F=E->get().front();F;F=F->next()) {
- file->store_string(F->key()+"="+_encode_variant(F->get())+"\n");
+ String vstr;
+ VariantWriter::write_to_string(F->get(),vstr);
+ file->store_string(F->key()+"="+vstr+"\n");
}
}
@@ -292,432 +152,49 @@ Error ConfigFile::save(const String& p_path){
return OK;
}
-static Vector<String> _decode_params(const String& p_string) {
-
- int begin=p_string.find("(");
- ERR_FAIL_COND_V(begin==-1,Vector<String>());
- begin++;
- int end=p_string.find(")");
- ERR_FAIL_COND_V(end<begin,Vector<String>());
- return p_string.substr(begin,end-begin).split(",");
-}
-
-static String _get_chunk(const String& str,int &pos, int close_pos) {
-
-
- enum {
- MIN_COMMA,
- MIN_COLON,
- MIN_CLOSE,
- MIN_QUOTE,
- MIN_PARENTHESIS,
- MIN_CURLY_OPEN,
- MIN_OPEN
- };
-
- int min_pos=close_pos;
- int min_what=MIN_CLOSE;
-
-#define TEST_MIN(m_how,m_what) \
-{\
-int res = str.find(m_how,pos);\
-if (res!=-1 && res < min_pos) {\
- min_pos=res;\
- min_what=m_what;\
-}\
-}\
-
-
- TEST_MIN(",",MIN_COMMA);
- TEST_MIN("[",MIN_OPEN);
- TEST_MIN("{",MIN_CURLY_OPEN);
- TEST_MIN("(",MIN_PARENTHESIS);
- TEST_MIN("\"",MIN_QUOTE);
-
- int end=min_pos;
-
-
- switch(min_what) {
-
- case MIN_COMMA: {
- } break;
- case MIN_CLOSE: {
- //end because it's done
- } break;
- case MIN_QUOTE: {
- end=str.find("\"",min_pos+1)+1;
- ERR_FAIL_COND_V(end==-1,Variant());
-
- } break;
- case MIN_PARENTHESIS: {
-
- end=str.find(")",min_pos+1)+1;
- ERR_FAIL_COND_V(end==-1,Variant());
-
- } break;
- case MIN_OPEN: {
- int level=1;
- end++;
- while(end<close_pos) {
-
- if (str[end]=='[')
- level++;
- if (str[end]==']') {
- level--;
- if (level==0)
- break;
- }
- end++;
- }
- ERR_FAIL_COND_V(level!=0,Variant());
- end++;
- } break;
- case MIN_CURLY_OPEN: {
- int level=1;
- end++;
- while(end<close_pos) {
-
- if (str[end]=='{')
- level++;
- if (str[end]=='}') {
- level--;
- if (level==0)
- break;
- }
- end++;
- }
- ERR_FAIL_COND_V(level!=0,Variant());
- end++;
- } break;
-
- }
-
- String ret = str.substr(pos,end-pos);
-
- pos=end;
- while(pos<close_pos) {
- if (str[pos]!=',' && str[pos]!=' ' && str[pos]!=':')
- break;
- pos++;
- }
-
- return ret;
-
-}
-
-
-static Variant _decode_variant(const String& p_string) {
-
-
- String str = p_string.strip_edges();
-
- if (str.nocasecmp_to("true")==0)
- return Variant(true);
- if (str.nocasecmp_to("false")==0)
- return Variant(false);
- if (str.nocasecmp_to("nil")==0)
- return Variant();
- if (str.is_valid_float()) {
- if (str.find(".")==-1)
- return str.to_int();
- else
- return str.to_double();
-
- }
- if (str.begins_with("#")) { //string
- return Color::html(str);
- }
- if (str.begins_with("\"")) { //string
- int end = str.find_last("\"");
- ERR_FAIL_COND_V(end==0,Variant());
- return str.substr(1,end-1).xml_unescape();
-
- }
-
- if (str.begins_with("[")) { //array
-
- int close_pos = str.find_last("]");
- ERR_FAIL_COND_V(close_pos==-1,Variant());
- Array array;
-
- int pos=1;
-
- while(pos<close_pos) {
-
- String s = _get_chunk(str,pos,close_pos);
- array.push_back(_decode_variant(s));
- }
- return array;
-
- }
-
- if (str.begins_with("{")) { //array
-
- int close_pos = str.find_last("}");
- ERR_FAIL_COND_V(close_pos==-1,Variant());
- Dictionary d;
-
- int pos=1;
-
- while(pos<close_pos) {
-
- String key = _get_chunk(str,pos,close_pos);
- String data = _get_chunk(str,pos,close_pos);
- d[_decode_variant(key)]=_decode_variant(data);
- }
- return d;
-
- }
- if (str.begins_with("key")) {
- Vector<String> params = _decode_params(p_string);
- ERR_FAIL_COND_V(params.size()!=1 && params.size()!=2,Variant());
- int scode=0;
-
- if (params[0].is_numeric()) {
- scode=params[0].to_int();
- if (scode < 10) {
- scode=KEY_0+scode;
- }
- } else
- scode=find_keycode(params[0]);
-
- InputEvent ie;
- ie.type=InputEvent::KEY;
- ie.key.scancode=scode;
-
- if (params.size()==2) {
- String mods=params[1];
- if (mods.findn("C")!=-1)
- ie.key.mod.control=true;
- if (mods.findn("A")!=-1)
- ie.key.mod.alt=true;
- if (mods.findn("S")!=-1)
- ie.key.mod.shift=true;
- if (mods.findn("M")!=-1)
- ie.key.mod.meta=true;
- }
- return ie;
-
- }
-
- if (str.begins_with("mbutton")) {
- Vector<String> params = _decode_params(p_string);
- ERR_FAIL_COND_V(params.size()!=2,Variant());
-
- InputEvent ie;
- ie.type=InputEvent::MOUSE_BUTTON;
- ie.device=params[0].to_int();
- ie.mouse_button.button_index=params[1].to_int();
-
- return ie;
- }
-
- if (str.begins_with("jbutton")) {
- Vector<String> params = _decode_params(p_string);
- ERR_FAIL_COND_V(params.size()!=2,Variant());
-
- InputEvent ie;
- ie.type=InputEvent::JOYSTICK_BUTTON;
- ie.device=params[0].to_int();
- ie.joy_button.button_index=params[1].to_int();
-
- return ie;
- }
-
- if (str.begins_with("jaxis")) {
- Vector<String> params = _decode_params(p_string);
- ERR_FAIL_COND_V(params.size()!=2,Variant());
-
- InputEvent ie;
- ie.type=InputEvent::JOYSTICK_MOTION;
- ie.device=params[0].to_int();
- ie.joy_motion.axis=params[1].to_int();
-
- return ie;
- }
- if (str.begins_with("img")) {
- Vector<String> params = _decode_params(p_string);
- if (params.size()==0) {
- return Image();
- }
-
- ERR_FAIL_COND_V(params.size()!=5,Image());
-
- String format=params[0].strip_edges();
-
- Image::Format imgformat;
-
- if (format=="grayscale") {
- imgformat=Image::FORMAT_GRAYSCALE;
- } else if (format=="intensity") {
- imgformat=Image::FORMAT_INTENSITY;
- } else if (format=="grayscale_alpha") {
- imgformat=Image::FORMAT_GRAYSCALE_ALPHA;
- } else if (format=="rgb") {
- imgformat=Image::FORMAT_RGB;
- } else if (format=="rgba") {
- imgformat=Image::FORMAT_RGBA;
- } else if (format=="indexed") {
- imgformat=Image::FORMAT_INDEXED;
- } else if (format=="indexed_alpha") {
- imgformat=Image::FORMAT_INDEXED_ALPHA;
- } else if (format=="bc1") {
- imgformat=Image::FORMAT_BC1;
- } else if (format=="bc2") {
- imgformat=Image::FORMAT_BC2;
- } else if (format=="bc3") {
- imgformat=Image::FORMAT_BC3;
- } else if (format=="bc4") {
- imgformat=Image::FORMAT_BC4;
- } else if (format=="bc5") {
- imgformat=Image::FORMAT_BC5;
- } else if (format=="custom") {
- imgformat=Image::FORMAT_CUSTOM;
- } else {
-
- ERR_FAIL_V( Image() );
- }
-
- int mipmaps=params[1].to_int();
- int w=params[2].to_int();
- int h=params[3].to_int();
-
- if (w == 0 && h == 0) {
- //r_v = Image(w, h, imgformat);
- return Image();
- };
-
-
- String data=params[4];
- int datasize=data.length()/2;
- DVector<uint8_t> pixels;
- pixels.resize(datasize);
- DVector<uint8_t>::Write wb = pixels.write();
- const CharType *cptr=data.c_str();
-
- int idx=0;
- uint8_t byte;
- while( idx<datasize*2) {
-
- CharType c=*(cptr++);
-
- ERR_FAIL_COND_V(c=='<',ERR_FILE_CORRUPT);
-
- if ( (c>='0' && c<='9') || (c>='A' && c<='F') || (c>='a' && c<='f') ) {
-
- if (idx&1) {
-
- byte|=HEX2CHR(c);
- wb[idx>>1]=byte;
- } else {
-
- byte=HEX2CHR(c)<<4;
- }
-
- idx++;
- }
-
- }
-
- wb = DVector<uint8_t>::Write();
-
- return Image(w,h,mipmaps,imgformat,pixels);
- }
-
- if (str.find(",")!=-1) { //vector2 or vector3
- Vector<float> farr = str.split_floats(",",true);
- if (farr.size()==2) {
- return Point2(farr[0],farr[1]);
- }
- if (farr.size()==3) {
- return Vector3(farr[0],farr[1],farr[2]);
- }
- ERR_FAIL_V(Variant());
- }
-
-
- return Variant();
-}
Error ConfigFile::load(const String& p_path) {
Error err;
FileAccess *f= FileAccess::open(p_path,FileAccess::READ,&err);
- if (err!=OK) {
-
- return err;
- }
-
-
- String line;
- String section;
- String subpath;
-
- int line_count = 0;
-
- while(!f->eof_reached()) {
-
- String line = f->get_line().strip_edges();
- line_count++;
-
- if (line=="")
- continue;
-
- // find comments
-
- {
+ if (!f)
+ return ERR_CANT_OPEN;
- int pos=0;
- while (true) {
- int ret = line.find(";",pos);
- if (ret==-1)
- break;
+ VariantParser::StreamFile stream;
+ stream.f=f;
- int qc=0;
- for(int i=0;i<ret;i++) {
+ String assign;
+ Variant value;
+ VariantParser::Tag next_tag;
- if (line[i]=='"')
- qc++;
- }
+ int lines=0;
+ String error_text;
- if ( !(qc&1) ) {
- //not inside string, real comment
- line=line.substr(0,ret);
- break;
-
- }
+ String section;
- pos=ret+1;
+ while(true) {
+ assign=Variant();
+ next_tag.fields.clear();
+ next_tag.name=String();
- }
+ err = VariantParser::parse_tag_assign_eof(&stream,lines,error_text,next_tag,assign,value,NULL,true);
+ if (err==ERR_FILE_EOF) {
+ memdelete(f);
+ return OK;
+ }
+ else if (err!=OK) {
+ ERR_PRINTS("ConfgFile::load - "+p_path+":"+itos(lines)+" error: "+error_text);
+ memdelete(f);
+ return err;
}
- if (line.begins_with("[")) {
-
- int end = line.find_last("]");
- ERR_CONTINUE(end!=line.length()-1);
-
- section=line.substr(1,line.length()-2);
-
- } else if (line.find("=")!=-1) {
-
-
- int eqpos = line.find("=");
- String var=line.substr(0,eqpos).strip_edges();
- String value=line.substr(eqpos+1,line.length()).strip_edges();
-
- Variant val = _decode_variant(value);
-
- set_value(section,var,val);
-
- } else {
-
- if (line.length() > 0) {
- ERR_PRINT(String("Syntax error on line "+itos(line_count)+" of file "+p_path).ascii().get_data());
- };
- };
+ if (assign!=String()) {
+ set_value(section,assign,value);
+ } else if (next_tag.name!=String()) {
+ section=next_tag.name;
+ }
}
memdelete(f);
@@ -730,13 +207,13 @@ Error ConfigFile::load(const String& p_path) {
void ConfigFile::_bind_methods(){
ObjectTypeDB::bind_method(_MD("set_value","section","key","value"),&ConfigFile::set_value);
- ObjectTypeDB::bind_method(_MD("get_value","section","key"),&ConfigFile::get_value);
+ ObjectTypeDB::bind_method(_MD("get_value","section","key","default"),&ConfigFile::get_value,DEFVAL(Variant()));
ObjectTypeDB::bind_method(_MD("has_section","section"),&ConfigFile::has_section);
ObjectTypeDB::bind_method(_MD("has_section_key","section","key"),&ConfigFile::has_section_key);
ObjectTypeDB::bind_method(_MD("get_sections"),&ConfigFile::_get_sections);
- ObjectTypeDB::bind_method(_MD("get_section_keys"),&ConfigFile::_get_section_keys);
+ ObjectTypeDB::bind_method(_MD("get_section_keys","section"),&ConfigFile::_get_section_keys);
ObjectTypeDB::bind_method(_MD("load:Error","path"),&ConfigFile::load);
ObjectTypeDB::bind_method(_MD("save:Error","path"),&ConfigFile::save);
diff --git a/core/io/config_file.h b/core/io/config_file.h
index 608f143fb1..4708fefeaa 100644
--- a/core/io/config_file.h
+++ b/core/io/config_file.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -46,7 +46,7 @@ protected:
public:
void set_value(const String& p_section, const String& p_key, const Variant& p_value);
- Variant get_value(const String& p_section, const String& p_key) const;
+ Variant get_value(const String& p_section, const String& p_key, Variant p_default=Variant()) const;
bool has_section(const String& p_section) const;
bool has_section_key(const String& p_section,const String& p_key) const;
diff --git a/core/io/file_access_buffered.cpp b/core/io/file_access_buffered.cpp
index ab17cb8118..b38fda3686 100644
--- a/core/io/file_access_buffered.cpp
+++ b/core/io/file_access_buffered.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/file_access_buffered.h b/core/io/file_access_buffered.h
index e6de203cda..9d405e15f7 100644
--- a/core/io/file_access_buffered.h
+++ b/core/io/file_access_buffered.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/file_access_buffered_fa.h b/core/io/file_access_buffered_fa.h
index d36c4843e4..afa79db06f 100644
--- a/core/io/file_access_buffered_fa.h
+++ b/core/io/file_access_buffered_fa.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp
index 1d06dc8c4b..2547d2d065 100644
--- a/core/io/file_access_compressed.cpp
+++ b/core/io/file_access_compressed.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h
index 69a03fa14f..f9e7cd98bd 100644
--- a/core/io/file_access_compressed.h
+++ b/core/io/file_access_compressed.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp
index 29f27dcbda..65b1ca5207 100644
--- a/core/io/file_access_encrypted.cpp
+++ b/core/io/file_access_encrypted.cpp
@@ -5,10 +5,12 @@
#include "print_string.h"
#define COMP_MAGIC 0x43454447
+#include "core/variant.h"
+#include <stdio.h>
Error FileAccessEncrypted::open_and_parse(FileAccess *p_base,const Vector<uint8_t>& p_key,Mode p_mode) {
- print_line("open and parse!");
+ //print_line("open and parse!");
ERR_FAIL_COND_V(file!=NULL,ERR_ALREADY_IN_USE);
ERR_FAIL_COND_V(p_key.size()!=32,ERR_INVALID_PARAMETER);
diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp
index 83da55fc61..2cc52a9e2d 100644
--- a/core/io/file_access_memory.cpp
+++ b/core/io/file_access_memory.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h
index 8c58a8a8ce..287f3dfe04 100644
--- a/core/io/file_access_memory.h
+++ b/core/io/file_access_memory.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/file_access_network.cpp b/core/io/file_access_network.cpp
index 850e055129..10667a4187 100644
--- a/core/io/file_access_network.cpp
+++ b/core/io/file_access_network.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/file_access_network.h b/core/io/file_access_network.h
index 2190cdb0ea..0073209ab8 100644
--- a/core/io/file_access_network.h
+++ b/core/io/file_access_network.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp
index 339a6d0528..5c8c741f28 100644
--- a/core/io/file_access_pack.cpp
+++ b/core/io/file_access_pack.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h
index 5bf5ad012c..f5dae6d51d 100644
--- a/core/io/file_access_pack.h
+++ b/core/io/file_access_pack.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp
index ab2eb3b3f2..41f43bf54d 100644
--- a/core/io/file_access_zip.cpp
+++ b/core/io/file_access_zip.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h
index 88272e6cfc..0a927b72f2 100644
--- a/core/io/file_access_zip.h
+++ b/core/io/file_access_zip.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/http_client.cpp b/core/io/http_client.cpp
index dbd009e319..19a7286dcf 100644
--- a/core/io/http_client.cpp
+++ b/core/io/http_client.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -248,7 +248,7 @@ Error HTTPClient::poll(){
status=STATUS_SSL_HANDSHAKE_ERROR;
return ERR_CANT_CONNECT;
}
- print_line("SSL! TURNED ON!");
+ //print_line("SSL! TURNED ON!");
connection=ssl;
}
status=STATUS_CONNECTED;
@@ -295,7 +295,7 @@ Error HTTPClient::poll(){
response_str.push_back(0);
String response;
response.parse_utf8((const char*)response_str.ptr());
- print_line("END OF RESPONSE? :\n"+response+"\n------");
+ //print_line("END OF RESPONSE? :\n"+response+"\n------");
Vector<String> responses = response.split("\n");
body_size=0;
chunked=false;
@@ -307,16 +307,17 @@ Error HTTPClient::poll(){
for(int i=0;i<responses.size();i++) {
String s = responses[i].strip_edges();
+ s = s.to_lower();
if (s.length()==0)
continue;
- if (s.begins_with("Content-Length:")) {
+ if (s.begins_with("content-length:")) {
body_size = s.substr(s.find(":")+1,s.length()).strip_edges().to_int();
body_left=body_size;
}
- if (s.begins_with("Transfer-Encoding:")) {
+ if (s.begins_with("transfer-encoding:")) {
String encoding = s.substr(s.find(":")+1,s.length()).strip_edges();
- print_line("TRANSFER ENCODING: "+encoding);
+ //print_line("TRANSFER ENCODING: "+encoding);
if (encoding=="chunked") {
chunked=true;
}
@@ -325,7 +326,7 @@ Error HTTPClient::poll(){
if (i==0 && responses[i].begins_with("HTTP")) {
- String num = responses[i].get_slice(" ",1);
+ String num = responses[i].get_slicec(' ',1);
response_num=num.to_int();
} else {
@@ -579,7 +580,7 @@ Error HTTPClient::_get_http_data(uint8_t* p_buffer, int p_bytes,int &r_received)
void HTTPClient::_bind_methods() {
- ObjectTypeDB::bind_method(_MD("connect:Error","host","port","use_ssl"),&HTTPClient::connect,DEFVAL(false),DEFVAL(true));
+ ObjectTypeDB::bind_method(_MD("connect:Error","host","port","use_ssl","verify_host"),&HTTPClient::connect,DEFVAL(false),DEFVAL(true));
ObjectTypeDB::bind_method(_MD("set_connection","connection:StreamPeer"),&HTTPClient::set_connection);
ObjectTypeDB::bind_method(_MD("request","method","url","headers","body"),&HTTPClient::request,DEFVAL(String()));
ObjectTypeDB::bind_method(_MD("send_body_text","body"),&HTTPClient::send_body_text);
@@ -601,6 +602,8 @@ void HTTPClient::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_status"),&HTTPClient::get_status);
ObjectTypeDB::bind_method(_MD("poll:Error"),&HTTPClient::poll);
+ ObjectTypeDB::bind_method(_MD("query_string_from_dict:String","fields"),&HTTPClient::query_string_from_dict);
+
BIND_CONSTANT( METHOD_GET );
BIND_CONSTANT( METHOD_HEAD );
@@ -689,6 +692,16 @@ void HTTPClient::set_read_chunk_size(int p_size) {
read_chunk_size=p_size;
}
+String HTTPClient::query_string_from_dict(const Dictionary& p_dict) {
+ String query = "";
+ Array keys = p_dict.keys();
+ for (int i = 0; i < keys.size(); ++i) {
+ query += "&" + String(keys[i]).http_escape() + "=" + String(p_dict[keys[i]]).http_escape();
+ }
+ query.erase(0, 1);
+ return query;
+}
+
HTTPClient::HTTPClient(){
tcp_connection = StreamPeerTCP::create_ref();
@@ -710,4 +723,3 @@ HTTPClient::~HTTPClient(){
}
-
diff --git a/core/io/http_client.h b/core/io/http_client.h
index 21281f38c5..e138681396 100644
--- a/core/io/http_client.h
+++ b/core/io/http_client.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -192,6 +192,8 @@ public:
Error poll();
+ String query_string_from_dict(const Dictionary& p_dict);
+
HTTPClient();
~HTTPClient();
};
diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp
index d3390ae199..aa641f00b4 100644
--- a/core/io/image_loader.cpp
+++ b/core/io/image_loader.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -50,8 +50,10 @@ Error ImageLoader::load_image(String p_file,Image *p_image, FileAccess *p_custom
if (!f) {
Error err;
f=FileAccess::open(p_file,FileAccess::READ,&err);
- if (!f)
+ if (!f) {
+ print_line("ERROR OPENING FILE: "+p_file);
return err;
+ }
}
String extension = p_file.extension();
@@ -62,15 +64,20 @@ Error ImageLoader::load_image(String p_file,Image *p_image, FileAccess *p_custom
if (!loader[i]->recognize(extension))
continue;
Error err = loader[i]->load_image(p_image,f);
+
if (err!=ERR_FILE_UNRECOGNIZED) {
+
+
if (!p_custom)
memdelete(f);
+
return err;
}
}
-
+ print_line("NO LOADER?");
+
if (!p_custom)
memdelete(f);
diff --git a/core/io/image_loader.h b/core/io/image_loader.h
index ff972696ea..3cc6c6cf43 100644
--- a/core/io/image_loader.h
+++ b/core/io/image_loader.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/ioapi.h b/core/io/ioapi.h
index a13d7ba621..24bf612617 100644
--- a/core/io/ioapi.h
+++ b/core/io/ioapi.h
@@ -40,7 +40,6 @@
#endif
#include <stdio.h>
-#include <stdlib.h>
#include "zlib.h"
#if defined(USE_FILE32API)
diff --git a/core/io/ip.cpp b/core/io/ip.cpp
index 523f9f472b..b8bd00c2fb 100644
--- a/core/io/ip.cpp
+++ b/core/io/ip.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/ip.h b/core/io/ip.h
index 6f50a190e6..38c86e7ba3 100644
--- a/core/io/ip.h
+++ b/core/io/ip.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/ip_address.cpp b/core/io/ip_address.cpp
index c5506f1a74..7a51bce7c6 100644
--- a/core/io/ip_address.cpp
+++ b/core/io/ip_address.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -47,7 +47,7 @@ IP_Address::IP_Address(const String& p_string) {
}
for(int i=0;i<4;i++) {
- field[i]=p_string.get_slice(".",i).to_int();
+ field[i]=p_string.get_slicec('.',i).to_int();
}
}
diff --git a/core/io/ip_address.h b/core/io/ip_address.h
index e55f45a2d7..1292311729 100644
--- a/core/io/ip_address.h
+++ b/core/io/ip_address.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/json.cpp b/core/io/json.cpp
index 14890abd26..f9a8638d06 100644
--- a/core/io/json.cpp
+++ b/core/io/json.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -86,7 +86,7 @@ String JSON::_print_var(const Variant& p_var) {
s+="}";
return s;
};
- default: return "\""+String(p_var).c_escape()+"\"";
+ default: return "\""+String(p_var).json_escape()+"\"";
}
@@ -177,9 +177,6 @@ Error JSON::_get_token(const CharType *p_str, int &idx, int p_len, Token& r_toke
case 'n': res=10; break;
case 'f': res=12; break;
case 'r': res=13; break;
- case '\"': res='\"'; break;
- case '\\': res='\\'; break;
- case '/': res='/'; break; //wtf
case 'u': {
//hexnumbarh - oct is deprecated
@@ -218,10 +215,13 @@ Error JSON::_get_token(const CharType *p_str, int &idx, int p_len, Token& r_toke
} break;
+ //case '\"': res='\"'; break;
+ //case '\\': res='\\'; break;
+ //case '/': res='/'; break;
default: {
-
- r_err_str="Invalid escape sequence";
- return ERR_PARSE_ERROR;
+ res = next;
+ //r_err_str="Invalid escape sequence";
+ //return ERR_PARSE_ERROR;
} break;
}
@@ -288,7 +288,7 @@ Error JSON::_parse_value(Variant &value,Token& token,const CharType *p_str,int &
if (token.type==TK_CURLY_BRACKET_OPEN) {
- Dictionary d;
+ Dictionary d(true);
Error err = _parse_object(d,p_str,index,p_len,line,r_err_str);
if (err)
return err;
@@ -296,7 +296,7 @@ Error JSON::_parse_value(Variant &value,Token& token,const CharType *p_str,int &
return OK;
} else if (token.type==TK_BRACKET_OPEN) {
- Array a;
+ Array a(true);
Error err = _parse_array(a,p_str,index,p_len,line,r_err_str);
if (err)
return err;
diff --git a/core/io/json.h b/core/io/json.h
index 78b6303451..a2803269cb 100644
--- a/core/io/json.h
+++ b/core/io/json.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp
index b0d24abfe3..4dccf21d2d 100644
--- a/core/io/marshalls.cpp
+++ b/core/io/marshalls.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -36,7 +36,10 @@ Error decode_variant(Variant& r_variant,const uint8_t *p_buffer, int p_len,int *
const uint8_t * buf=p_buffer;
int len=p_len;
- ERR_FAIL_COND_V(len<4,ERR_INVALID_DATA);
+ if (len<4) {
+
+ ERR_FAIL_COND_V(len<4,ERR_INVALID_DATA);
+ }
uint32_t type=decode_uint32(buf);
@@ -299,10 +302,8 @@ Error decode_variant(Variant& r_variant,const uint8_t *p_buffer, int p_len,int *
ERR_FAIL_COND_V(len<12,ERR_INVALID_DATA);
Vector<StringName> names;
Vector<StringName> subnames;
- bool absolute;
StringName prop;
- int i=0;
uint32_t namecount=strlen&=0x7FFFFFFF;
uint32_t subnamecount = decode_uint32(buf+4);
uint32_t flags = decode_uint32(buf+8);
@@ -391,7 +392,6 @@ Error decode_variant(Variant& r_variant,const uint8_t *p_buffer, int p_len,int *
ie.type=decode_uint32(&buf[0]);
ie.device=decode_uint32(&buf[4]);
- uint32_t len = decode_uint32(&buf[8])-12;
if (r_len)
(*r_len)+=12;
diff --git a/core/io/marshalls.h b/core/io/marshalls.h
index df673debf5..7a5b16e8af 100644
--- a/core/io/marshalls.h
+++ b/core/io/marshalls.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/packet_peer.cpp b/core/io/packet_peer.cpp
index 875cace368..6cb3daa7ac 100644
--- a/core/io/packet_peer.cpp
+++ b/core/io/packet_peer.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -127,7 +127,7 @@ Error PacketPeer::_get_packet_error() const {
void PacketPeer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_var"),&PacketPeer::_bnd_get_var);
- ObjectTypeDB::bind_method(_MD("put_var", "var:var"),&PacketPeer::put_var);
+ ObjectTypeDB::bind_method(_MD("put_var", "var:Variant"),&PacketPeer::put_var);
ObjectTypeDB::bind_method(_MD("get_packet"),&PacketPeer::_get_packet);
ObjectTypeDB::bind_method(_MD("put_packet:Error", "buffer"),&PacketPeer::_put_packet);
ObjectTypeDB::bind_method(_MD("get_packet_error:Error"),&PacketPeer::_get_packet_error);
@@ -156,7 +156,6 @@ Error PacketPeerStream::_poll_buffer() const {
Error err = peer->get_partial_data(&temp_buffer[0], ring_buffer.space_left(), read);
if (err)
return err;
-
if (read==0)
return OK;
@@ -202,7 +201,7 @@ Error PacketPeerStream::get_packet(const uint8_t **r_buffer,int &r_buffer_size)
uint8_t lbuf[4];
ring_buffer.copy(lbuf,0,4);
remaining-=4;
- uint32_t len = decode_uint32(lbuf);
+ uint32_t len = decode_uint32(lbuf);
ERR_FAIL_COND_V(remaining<(int)len,ERR_UNAVAILABLE);
ring_buffer.read(lbuf,4); //get rid of first 4 bytes
diff --git a/core/io/packet_peer.h b/core/io/packet_peer.h
index 76d1eb22b5..b29fc22af0 100644
--- a/core/io/packet_peer.h
+++ b/core/io/packet_peer.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index 0f6f8a74b1..c008c3f9a4 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,6 +31,7 @@
#include "globals.h"
#include "io/file_access_compressed.h"
#include "io/marshalls.h"
+#include "os/dir_access.h"
//#define print_bl(m_what) print_line(m_what)
#define print_bl(m_what)
@@ -99,7 +100,9 @@ enum {
OBJECT_EMPTY=0,
OBJECT_EXTERNAL_RESOURCE=1,
OBJECT_INTERNAL_RESOURCE=2,
- FORMAT_VERSION=0
+ OBJECT_EXTERNAL_RESOURCE_INDEX=3,
+ FORMAT_VERSION=1,
+ FORMAT_VERSION_CAN_RENAME_DEPS=1
};
@@ -375,7 +378,7 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant& r_v) {
} break;
case OBJECT_INTERNAL_RESOURCE: {
uint32_t index=f->get_32();
- String path = res_path+"::"+itos(index);
+ String path = res_path+"::"+itos(index);
RES res = ResourceLoader::load(path);
if (res.is_null()) {
WARN_PRINT(String("Couldn't load resource: "+path).utf8().get_data());
@@ -384,6 +387,7 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant& r_v) {
} break;
case OBJECT_EXTERNAL_RESOURCE: {
+ //old file format, still around for compatibility
String type = get_unicode_string();
String path = get_unicode_string();
@@ -394,6 +398,10 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant& r_v) {
}
+ if (remaps.find(path)) {
+ path=remaps[path];
+ }
+
RES res=ResourceLoader::load(path,type);
if (res.is_null()) {
@@ -402,6 +410,34 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant& r_v) {
r_v=res;
} break;
+ case OBJECT_EXTERNAL_RESOURCE_INDEX: {
+ //new file format, just refers to an index in the external list
+ uint32_t erindex = f->get_32();
+
+ if (erindex>=external_resources.size()) {
+ WARN_PRINT("Broken external resource! (index out of size");
+ r_v=Variant();
+ } else {
+
+ String type = external_resources[erindex].type;
+ String path = external_resources[erindex].path;
+
+ if (path.find("://")==-1 && path.is_rel_path()) {
+ // path is relative to file being loaded, so convert to a resource path
+ path=Globals::get_singleton()->localize_path(res_path.get_base_dir().plus_file(path));
+
+ }
+
+ RES res=ResourceLoader::load(path,type);
+
+ if (res.is_null()) {
+ WARN_PRINT(String("Couldn't load resource: "+path).utf8().get_data());
+ }
+ r_v=res;
+ }
+
+
+ } break;
default: {
ERR_FAIL_V(ERR_FILE_CORRUPT);
@@ -628,17 +664,20 @@ Error ResourceInteractiveLoaderBinary::poll(){
if (s<external_resources.size()) {
- RES res = ResourceLoader::load(external_resources[s].path,external_resources[s].type);
+ String path = external_resources[s].path;
+ if (remaps.has(path)) {
+ path=remaps[path];
+ }
+ RES res = ResourceLoader::load(path,external_resources[s].type);
if (res.is_null()) {
if (!ResourceLoader::get_abort_on_missing_resources()) {
- ResourceLoader::notify_load_error("Resource Not Found: "+external_resources[s].path);
+ ResourceLoader::notify_dependency_error(local_path,path,external_resources[s].type);
} else {
-
- error=ERR_FILE_CORRUPT;
- ERR_EXPLAIN("Can't load dependency: "+external_resources[s].path);
+ error=ERR_FILE_MISSING_DEPENDENCIES;
+ ERR_EXPLAIN("Can't load dependency: "+path);
ERR_FAIL_V(error);
}
@@ -686,7 +725,8 @@ Error ResourceInteractiveLoaderBinary::poll(){
}
} else {
- path=res_path;
+ if (!ResourceCache::has(res_path))
+ path=res_path;
}
uint64_t offset = internal_resources[s].offset;
@@ -787,12 +827,35 @@ int ResourceInteractiveLoaderBinary::get_stage_count() const {
return external_resources.size()+internal_resources.size();
}
+
+static void save_ustring(FileAccess* f,const String& p_string) {
+
+
+ CharString utf8 = p_string.utf8();
+ f->store_32(utf8.length()+1);
+ f->store_buffer((const uint8_t*)utf8.get_data(),utf8.length()+1);
+}
+
+
+static String get_ustring(FileAccess *f) {
+
+ int len = f->get_32();
+ Vector<char> str_buf;
+ str_buf.resize(len);
+ f->get_buffer((uint8_t*)&str_buf[0],len);
+ String s;
+ s.parse_utf8(&str_buf[0]);
+ return s;
+}
+
String ResourceInteractiveLoaderBinary::get_unicode_string() {
int len = f->get_32();
if (len>str_buf.size()) {
str_buf.resize(len);
}
+ if (len==0)
+ return String();
f->get_buffer((uint8_t*)&str_buf[0],len);
String s;
s.parse_utf8(&str_buf[0]);
@@ -801,7 +864,7 @@ String ResourceInteractiveLoaderBinary::get_unicode_string() {
-void ResourceInteractiveLoaderBinary::get_dependencies(FileAccess *p_f,List<String> *p_dependencies) {
+void ResourceInteractiveLoaderBinary::get_dependencies(FileAccess *p_f,List<String> *p_dependencies,bool p_add_types) {
open(p_f);
if (error)
@@ -814,6 +877,10 @@ void ResourceInteractiveLoaderBinary::get_dependencies(FileAccess *p_f,List<Stri
dep=ResourceLoader::guess_full_filename(dep,external_resources[i].type);
}
+ if (p_add_types && external_resources[i].type!=String()) {
+ dep+="::"+external_resources[i].type;
+ }
+
p_dependencies->push_back(dep);
}
@@ -841,7 +908,7 @@ void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) {
error=ERR_FILE_UNRECOGNIZED;
ERR_EXPLAIN("Unrecognized binary resource file: "+local_path);
- ERR_FAIL_V();
+ ERR_FAIL();
}
bool big_endian = f->get_32();
@@ -866,7 +933,7 @@ void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) {
print_bl("minor: "+itos(ver_minor));
print_bl("format: "+itos(ver_format));
- if (ver_format<FORMAT_VERSION || ver_major>VERSION_MAJOR) {
+ if (ver_format>FORMAT_VERSION || ver_major>VERSION_MAJOR) {
f->close();
ERR_EXPLAIN("File Format '"+itos(FORMAT_VERSION)+"."+itos(ver_major)+"."+itos(ver_minor)+"' is too new! Please upgrade to a a new engine version: "+local_path);
@@ -903,6 +970,7 @@ void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) {
}
//see if the exporter has different set of external resources for more efficient loading
+ /*
String preload_depts = "deps/"+res_path.md5_text();
if (Globals::get_singleton()->has(preload_depts)) {
external_resources.clear();
@@ -913,7 +981,7 @@ void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) {
external_resources[i].path=depts.get_name(i);
}
print_line(res_path+" - EXTERNAL RESOURCES: "+itos(external_resources.size()));
- }
+ }*/
print_bl("ext resources: "+itos(ext_resources_size));
uint32_t int_resources_size=f->get_32();
@@ -973,7 +1041,7 @@ String ResourceInteractiveLoaderBinary::recognize(FileAccess *p_f) {
uint32_t ver_minor=f->get_32();
uint32_t ver_format=f->get_32();
- if (ver_format<FORMAT_VERSION || ver_major>VERSION_MAJOR) {
+ if (ver_format>FORMAT_VERSION || ver_major>VERSION_MAJOR) {
f->close();
return "";
@@ -1000,8 +1068,10 @@ ResourceInteractiveLoaderBinary::~ResourceInteractiveLoaderBinary() {
}
-Ref<ResourceInteractiveLoader> ResourceFormatLoaderBinary::load_interactive(const String &p_path) {
+Ref<ResourceInteractiveLoader> ResourceFormatLoaderBinary::load_interactive(const String &p_path, Error *r_error) {
+ if (r_error)
+ *r_error=ERR_FILE_CANT_OPEN;
Error err;
FileAccess *f = FileAccess::open(p_path,FileAccess::READ,&err);
@@ -1114,7 +1184,7 @@ Error ResourceFormatLoaderBinary::load_import_metadata(const String &p_path, Ref
}
-void ResourceFormatLoaderBinary::get_dependencies(const String& p_path,List<String> *p_dependencies) {
+void ResourceFormatLoaderBinary::get_dependencies(const String& p_path,List<String> *p_dependencies,bool p_add_types) {
FileAccess *f = FileAccess::open(p_path,FileAccess::READ);
ERR_FAIL_COND(!f);
@@ -1123,7 +1193,217 @@ void ResourceFormatLoaderBinary::get_dependencies(const String& p_path,List<Stri
ria->local_path=Globals::get_singleton()->localize_path(p_path);
ria->res_path=ria->local_path;
// ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
- ria->get_dependencies(f,p_dependencies);
+ ria->get_dependencies(f,p_dependencies,p_add_types);
+}
+
+Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path,const Map<String,String>& p_map) {
+
+
+// Error error=OK;
+
+
+ FileAccess *f=FileAccess::open(p_path,FileAccess::READ);
+ ERR_FAIL_COND_V(!f,ERR_CANT_OPEN);
+
+ FileAccess* fw=NULL;//=FileAccess::open(p_path+".depren");
+
+ String local_path=p_path.get_base_dir();
+
+ uint8_t header[4];
+ f->get_buffer(header,4);
+ if (header[0]=='R' && header[1]=='S' && header[2]=='C' && header[3]=='C') {
+ //compressed
+ FileAccessCompressed *fac = memnew( FileAccessCompressed );
+ fac->open_after_magic(f);
+ f=fac;
+
+ FileAccessCompressed *facw = memnew( FileAccessCompressed );
+ facw->configure("RSCC");
+ Error err = facw->_open(p_path+".depren",FileAccess::WRITE);
+ if (err) {
+ memdelete(fac);
+ memdelete(facw);
+ ERR_FAIL_COND_V(err,ERR_FILE_CORRUPT);
+ }
+
+ fw=facw;
+
+
+ } else if (header[0]!='R' || header[1]!='S' || header[2]!='R' || header[3]!='C') {
+ //not normal
+
+ //error=ERR_FILE_UNRECOGNIZED;
+ memdelete(f);
+ ERR_EXPLAIN("Unrecognized binary resource file: "+local_path);
+ ERR_FAIL_V(ERR_FILE_UNRECOGNIZED);
+ } else {
+ fw = FileAccess::open(p_path+".depren",FileAccess::WRITE);
+ if (!fw) {
+ memdelete(f);
+ }
+ ERR_FAIL_COND_V(!fw,ERR_CANT_CREATE);
+ }
+
+ bool big_endian = f->get_32();
+#ifdef BIG_ENDIAN_ENABLED
+ endian_swap = !big_endian;
+#else
+ bool endian_swap = big_endian;
+#endif
+
+ bool use_real64 = f->get_32();
+
+ f->set_endian_swap(big_endian!=0); //read big endian if saved as big endian
+ fw->store_32(endian_swap);
+ fw->set_endian_swap(big_endian!=0);
+ fw->store_32(use_real64); //use real64
+
+ uint32_t ver_major=f->get_32();
+ uint32_t ver_minor=f->get_32();
+ uint32_t ver_format=f->get_32();
+
+ if (ver_format<FORMAT_VERSION_CAN_RENAME_DEPS) {
+
+ memdelete(f);
+ memdelete(fw);
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ da->remove(p_path+".depren");
+ memdelete(da);
+ //fuck it, use the old approach;
+
+ WARN_PRINT(("This file is old, so it can't refactor dependencies, opening and resaving: "+p_path).utf8().get_data());
+
+ Error err;
+ f = FileAccess::open(p_path,FileAccess::READ,&err);
+ if (err!=OK) {
+ ERR_FAIL_COND_V(err!=OK,ERR_FILE_CANT_OPEN);
+ }
+
+ Ref<ResourceInteractiveLoaderBinary> ria = memnew( ResourceInteractiveLoaderBinary );
+ ria->local_path=Globals::get_singleton()->localize_path(p_path);
+ ria->res_path=ria->local_path;
+ ria->remaps=p_map;
+ // ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
+ ria->open(f);
+
+ err = ria->poll();
+
+ while(err==OK) {
+ err=ria->poll();
+ }
+
+ ERR_FAIL_COND_V(err!=ERR_FILE_EOF,ERR_FILE_CORRUPT);
+ RES res = ria->get_resource();
+ ERR_FAIL_COND_V(!res.is_valid(),ERR_FILE_CORRUPT);
+
+ return ResourceFormatSaverBinary::singleton->save(p_path,res);
+ }
+
+ if (ver_format>FORMAT_VERSION || ver_major>VERSION_MAJOR) {
+
+ memdelete(f);
+ memdelete(fw);
+ ERR_EXPLAIN("File Format '"+itos(FORMAT_VERSION)+"."+itos(ver_major)+"."+itos(ver_minor)+"' is too new! Please upgrade to a a new engine version: "+local_path);
+ ERR_FAIL_V(ERR_FILE_UNRECOGNIZED);
+
+ }
+
+ fw->store_32( VERSION_MAJOR ); //current version
+ fw->store_32( VERSION_MINOR );
+ fw->store_32( FORMAT_VERSION );
+
+ save_ustring(fw,get_ustring(f)); //type
+
+
+ size_t md_ofs = f->get_pos();
+ size_t importmd_ofs = f->get_64();
+ fw->store_64(0); //metadata offset
+
+ for(int i=0;i<14;i++) {
+ fw->store_32(0);
+ f->get_32();
+ }
+
+ //string table
+ uint32_t string_table_size=f->get_32();
+
+ fw->store_32(string_table_size);
+
+ for(uint32_t i=0;i<string_table_size;i++) {
+
+ String s = get_ustring(f);
+ save_ustring(fw,s);
+ }
+
+ //external resources
+ uint32_t ext_resources_size=f->get_32();
+ fw->store_32(ext_resources_size);
+ for(uint32_t i=0;i<ext_resources_size;i++) {
+
+ String type = get_ustring(f);
+ String path = get_ustring(f);
+
+ bool relative=false;
+ if (!path.begins_with("res://")) {
+ path=local_path.plus_file(path).simplify_path();
+ relative=true;
+ }
+
+
+ if (p_map.has(path)) {
+ String np=p_map[path];
+ path=np;
+ }
+
+ if (relative) {
+ //restore relative
+ path=local_path.path_to_file(path);
+ }
+
+ save_ustring(fw,type);
+ save_ustring(fw,path);
+ }
+
+ int64_t size_diff = (int64_t)fw->get_pos() - (int64_t)f->get_pos();
+
+ //internal resources
+ uint32_t int_resources_size=f->get_32();
+ fw->store_32(int_resources_size);
+
+ for(uint32_t i=0;i<int_resources_size;i++) {
+
+
+ String path=get_ustring(f);
+ uint64_t offset=f->get_64();
+ save_ustring(fw,path);
+ fw->store_64(offset+size_diff);
+ }
+
+ //rest of file
+ uint8_t b = f->get_8();
+ while(!f->eof_reached()) {
+ fw->store_8(b);
+ b = f->get_8();
+ }
+
+ bool all_ok = fw->get_error()==OK;
+
+ fw->seek(md_ofs);
+ fw->store_64(importmd_ofs+size_diff);
+
+
+ memdelete(f);
+ memdelete(fw);
+
+ if (!all_ok) {
+ return ERR_CANT_CREATE;
+ }
+
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ da->remove(p_path);
+ da->rename(p_path+".depren",p_path);
+ memdelete(da);
+ return OK;
}
@@ -1433,10 +1713,8 @@ void ResourceFormatSaverBinaryInstance::write_variant(const Variant& p_property,
}
if (res->get_path().length() && res->get_path().find("::")==-1) {
- f->store_32(OBJECT_EXTERNAL_RESOURCE);
- save_unicode_string(res->get_save_type());
- String path=relative_paths?local_path.path_to_file(res->get_path()):res->get_path();
- save_unicode_string(path);
+ f->store_32(OBJECT_EXTERNAL_RESOURCE_INDEX);
+ f->store_32(external_resources[res]);
} else {
if (!resource_set.has(res)) {
@@ -1594,11 +1872,12 @@ void ResourceFormatSaverBinaryInstance::_find_resources(const Variant& p_variant
RES res = p_variant.operator RefPtr();
- if (res.is_null())
+ if (res.is_null() || external_resources.has(res))
return;
if (!p_main && (!bundle_resources ) && res->get_path().length() && res->get_path().find("::") == -1 ) {
- external_resources.insert(res);
+ int idx = external_resources.size();
+ external_resources[res]=idx;
return;
}
@@ -1819,7 +2098,7 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path,const RES& p_
Property p;
p.name_idx=get_string_index(F->get().name);
p.value=E->get()->get(F->get().name);
- if (F->get().usage&PROPERTY_USAGE_STORE_IF_NONZERO && p.value.is_zero())
+ if ((F->get().usage&PROPERTY_USAGE_STORE_IF_NONZERO && p.value.is_zero())||(F->get().usage&PROPERTY_USAGE_STORE_IF_NONONE && p.value.is_one()) )
continue;
p.pi=F->get();
@@ -1842,10 +2121,18 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path,const RES& p_
// save external resource table
f->store_32(external_resources.size()); //amount of external resources
- for(Set<RES>::Element *E=external_resources.front();E;E=E->next()) {
+ Vector<RES> save_order;
+ save_order.resize(external_resources.size());
+
+ for(Map<RES,int>::Element *E=external_resources.front();E;E=E->next()) {
+ save_order[E->get()]=E->key();
+ }
- save_unicode_string(E->get()->get_save_type());
- String path = E->get()->get_path();
+ for(int i=0;i<save_order.size();i++) {
+
+ save_unicode_string(save_order[i]->get_save_type());
+ String path = save_order[i]->get_path();
+ path=relative_paths?local_path.path_to_file(path):path;
save_unicode_string(path);
}
// save internal resource table
@@ -1888,10 +2175,11 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path,const RES& p_
save_unicode_string("local://"+itos(r->get_subindex()));
if (takeover_paths) {
- r->set_path(p_path+"::"+itos(ofs_pos.size()),true);
+ r->set_path(p_path+"::"+itos(r->get_subindex()),true);
}
- } else
+ } else {
save_unicode_string(r->get_path()); //actual external
+ }
ofs_pos.push_back(f->get_pos());
f->store_64(0); //offset in 64 bits
}
@@ -1995,3 +2283,9 @@ void ResourceFormatSaverBinary::get_recognized_extensions(const RES& p_resource,
}
+ResourceFormatSaverBinary* ResourceFormatSaverBinary::singleton=NULL;
+
+ResourceFormatSaverBinary::ResourceFormatSaverBinary() {
+
+ singleton=this;
+}
diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h
index da415d97a5..b8be3080b8 100644
--- a/core/io/resource_format_binary.h
+++ b/core/io/resource_format_binary.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -71,6 +71,7 @@ class ResourceInteractiveLoaderBinary : public ResourceInteractiveLoader {
String get_unicode_string();
void _advance_padding(uint32_t p_len);
+ Map<String,String> remaps;
Error error;
int stage;
@@ -88,9 +89,10 @@ public:
virtual int get_stage() const;
virtual int get_stage_count() const;
+ void set_remaps(const Map<String,String>& p_remaps) { remaps=p_remaps; }
void open(FileAccess *p_f);
String recognize(FileAccess *p_f);
- void get_dependencies(FileAccess *p_f,List<String> *p_dependencies);
+ void get_dependencies(FileAccess *p_f, List<String> *p_dependencies, bool p_add_types);
ResourceInteractiveLoaderBinary();
@@ -101,13 +103,14 @@ public:
class ResourceFormatLoaderBinary : public ResourceFormatLoader {
public:
- virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path);
+ virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path,Error *r_error=NULL);
virtual void get_recognized_extensions_for_type(const String& p_type,List<String> *p_extensions) const;
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String& p_type) const;
virtual String get_resource_type(const String &p_path) const;
- virtual void get_dependencies(const String& p_path,List<String> *p_dependencies);
+ virtual void get_dependencies(const String& p_path, List<String> *p_dependencies, bool p_add_types=false);
virtual Error load_import_metadata(const String &p_path, Ref<ResourceImportMetadata>& r_var) const;
+ virtual Error rename_dependencies(const String &p_path,const Map<String,String>& p_map);
@@ -134,7 +137,7 @@ class ResourceFormatSaverBinaryInstance {
Vector<StringName> strings;
- Set<RES> external_resources;
+ Map<RES,int> external_resources;
List<RES> saved_resources;
@@ -174,11 +177,12 @@ class ResourceFormatSaverBinary : public ResourceFormatSaver {
public:
+ static ResourceFormatSaverBinary* singleton;
virtual Error save(const String &p_path,const RES& p_resource,uint32_t p_flags=0);
virtual bool recognize(const RES& p_resource) const;
virtual void get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) const;
-
+ ResourceFormatSaverBinary();
};
diff --git a/core/io/resource_format_xml.cpp b/core/io/resource_format_xml.cpp
index 36746a4111..8c8d79948a 100644
--- a/core/io/resource_format_xml.cpp
+++ b/core/io/resource_format_xml.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,10 +29,10 @@
#include "resource_format_xml.h"
#include "globals.h"
#include "version.h"
+#include "os/dir_access.h"
-
-ResourceInteractiveLoaderXML::Tag* ResourceInteractiveLoaderXML::parse_tag(bool *r_exit,bool p_printerr) {
+ResourceInteractiveLoaderXML::Tag* ResourceInteractiveLoaderXML::parse_tag(bool *r_exit, bool p_printerr, List<String> *r_order) {
while(get_char()!='<' && !f->eof_reached()) {}
@@ -107,7 +107,11 @@ ResourceInteractiveLoaderXML::Tag* ResourceInteractiveLoaderXML::parse_tag(bool
if (r_value.size()) {
r_value.push_back(0);
- tag.args[name].parse_utf8(r_value.get_data());
+ String str;
+ str.parse_utf8(r_value.get_data());
+ tag.args[name]=str;
+ if (r_order)
+ r_order->push_back(name);
}
break;
@@ -119,7 +123,11 @@ ResourceInteractiveLoaderXML::Tag* ResourceInteractiveLoaderXML::parse_tag(bool
} else if (reading_value && r_value.size()) {
r_value.push_back(0);
- tag.args[name].parse_utf8(r_value.get_data());
+ String str;
+ str.parse_utf8(r_value.get_data());
+ tag.args[name]=str;
+ if (r_order)
+ r_order->push_back(name);
name="";
r_value.clear();
reading_value=false;
@@ -463,6 +471,10 @@ Error ResourceInteractiveLoaderXML::parse_property(Variant& r_v, String &r_name)
}
+ if (remaps.has(path)) {
+ path=remaps[path];
+ }
+
//take advantage of the resource loader cache. The resource is cached on it, even if
RES res=ResourceLoader::load(path,hint);
@@ -473,10 +485,31 @@ Error ResourceInteractiveLoaderXML::parse_property(Variant& r_v, String &r_name)
}
r_v=res.get_ref_ptr();
+ } else if (tag->args.has("external")) {
+
+ int index = tag->args["external"].to_int();
+ if (ext_resources.has(index)) {
+ String path=ext_resources[index].path;
+ String type=ext_resources[index].type;
+
+ //take advantage of the resource loader cache. The resource is cached on it, even if
+ RES res=ResourceLoader::load(path,type);
+
+ if (res.is_null()) {
+
+ WARN_PRINT(String("Couldn't load externalresource: "+path).ascii().get_data());
+ }
+
+ r_v=res.get_ref_ptr();
+ } else {
+ WARN_PRINT(String("Invalid external resource index: "+itos(index)).ascii().get_data());
+
+ }
}
+
Error err=goto_end_of_tag();
if (err) {
ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Error closing <resource> tag.");
@@ -1207,47 +1240,47 @@ Error ResourceInteractiveLoaderXML::parse_property(Variant& r_v, String &r_name)
r_v=Vector3(
- data.get_slice(",",0).to_double(),
- data.get_slice(",",1).to_double(),
- data.get_slice(",",2).to_double()
+ data.get_slicec(',',0).to_double(),
+ data.get_slicec(',',1).to_double(),
+ data.get_slicec(',',2).to_double()
);
} else if (type=="vector2") {
r_v=Vector2(
- data.get_slice(",",0).to_double(),
- data.get_slice(",",1).to_double()
+ data.get_slicec(',',0).to_double(),
+ data.get_slicec(',',1).to_double()
);
} else if (type=="plane") {
r_v=Plane(
- data.get_slice(",",0).to_double(),
- data.get_slice(",",1).to_double(),
- data.get_slice(",",2).to_double(),
- data.get_slice(",",3).to_double()
+ data.get_slicec(',',0).to_double(),
+ data.get_slicec(',',1).to_double(),
+ data.get_slicec(',',2).to_double(),
+ data.get_slicec(',',3).to_double()
);
} else if (type=="quaternion") {
r_v=Quat(
- data.get_slice(",",0).to_double(),
- data.get_slice(",",1).to_double(),
- data.get_slice(",",2).to_double(),
- data.get_slice(",",3).to_double()
+ data.get_slicec(',',0).to_double(),
+ data.get_slicec(',',1).to_double(),
+ data.get_slicec(',',2).to_double(),
+ data.get_slicec(',',3).to_double()
);
} else if (type=="rect2") {
r_v=Rect2(
Vector2(
- data.get_slice(",",0).to_double(),
- data.get_slice(",",1).to_double()
+ data.get_slicec(',',0).to_double(),
+ data.get_slicec(',',1).to_double()
),
Vector2(
- data.get_slice(",",2).to_double(),
- data.get_slice(",",3).to_double()
+ data.get_slicec(',',2).to_double(),
+ data.get_slicec(',',3).to_double()
)
);
@@ -1256,14 +1289,14 @@ Error ResourceInteractiveLoaderXML::parse_property(Variant& r_v, String &r_name)
r_v=AABB(
Vector3(
- data.get_slice(",",0).to_double(),
- data.get_slice(",",1).to_double(),
- data.get_slice(",",2).to_double()
+ data.get_slicec(',',0).to_double(),
+ data.get_slicec(',',1).to_double(),
+ data.get_slicec(',',2).to_double()
),
Vector3(
- data.get_slice(",",3).to_double(),
- data.get_slice(",",4).to_double(),
- data.get_slice(",",5).to_double()
+ data.get_slicec(',',3).to_double(),
+ data.get_slicec(',',4).to_double(),
+ data.get_slicec(',',5).to_double()
)
);
@@ -1272,7 +1305,7 @@ Error ResourceInteractiveLoaderXML::parse_property(Variant& r_v, String &r_name)
Matrix32 m3;
for (int i=0;i<3;i++) {
for (int j=0;j<2;j++) {
- m3.elements[i][j]=data.get_slice(",",i*2+j).to_double();
+ m3.elements[i][j]=data.get_slicec(',',i*2+j).to_double();
}
}
r_v=m3;
@@ -1282,7 +1315,7 @@ Error ResourceInteractiveLoaderXML::parse_property(Variant& r_v, String &r_name)
Matrix3 m3;
for (int i=0;i<3;i++) {
for (int j=0;j<3;j++) {
- m3.elements[i][j]=data.get_slice(",",i*3+j).to_double();
+ m3.elements[i][j]=data.get_slicec(',',i*3+j).to_double();
}
}
r_v=m3;
@@ -1292,24 +1325,24 @@ Error ResourceInteractiveLoaderXML::parse_property(Variant& r_v, String &r_name)
Transform tr;
for (int i=0;i<3;i++) {
for (int j=0;j<3;j++) {
- tr.basis.elements[i][j]=data.get_slice(",",i*3+j).to_double();
+ tr.basis.elements[i][j]=data.get_slicec(',',i*3+j).to_double();
}
}
tr.origin=Vector3(
- data.get_slice(",",9).to_double(),
- data.get_slice(",",10).to_double(),
- data.get_slice(",",11).to_double()
+ data.get_slicec(',',9).to_double(),
+ data.get_slicec(',',10).to_double(),
+ data.get_slicec(',',11).to_double()
);
r_v=tr;
} else if (type=="color") {
r_v=Color(
- data.get_slice(",",0).to_double(),
- data.get_slice(",",1).to_double(),
- data.get_slice(",",2).to_double(),
- data.get_slice(",",3).to_double()
+ data.get_slicec(',',0).to_double(),
+ data.get_slicec(',',1).to_double(),
+ data.get_slicec(',',2).to_double(),
+ data.get_slicec(',',3).to_double()
);
} else if (type=="node_path") {
@@ -1364,32 +1397,6 @@ Error ResourceInteractiveLoaderXML::poll() {
if (error!=OK)
return error;
- if (ext_resources.size()) {
-
- error=ERR_FILE_CORRUPT;
- String path=ext_resources.front()->get();
-
- RES res = ResourceLoader::load(path);
-
- if (res.is_null()) {
-
- if (ResourceLoader::get_abort_on_missing_resources()) {
- ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": editor exported nonexistent resource at: "+path);
- ERR_FAIL_V(error);
- } else {
- ResourceLoader::notify_load_error("Resource Not Found: "+path);
- }
- } else {
-
- resource_cache.push_back(res);
- }
-
- error=OK;
- ext_resources.pop_front();
- resource_current++;
- return error;
- }
-
bool exit;
Tag *tag = parse_tag(&exit);
@@ -1413,12 +1420,13 @@ Error ResourceInteractiveLoaderXML::poll() {
ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": <ext_resource> missing 'path' field.");
ERR_FAIL_COND_V(!tag->args.has("path"),ERR_FILE_CORRUPT);
- String type;
+ String type="Resource";
if (tag->args.has("type"))
type=tag->args["type"];
String path = tag->args["path"];
+
ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": <ext_resource> can't use a local path, this is a bug?.");
ERR_FAIL_COND_V(path.begins_with("local://"),ERR_FILE_CORRUPT);
@@ -1427,6 +1435,9 @@ Error ResourceInteractiveLoaderXML::poll() {
path=Globals::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path));
}
+ if (remaps.has(path)) {
+ path=remaps[path];
+ }
RES res = ResourceLoader::load(path,type);
@@ -1436,13 +1447,21 @@ Error ResourceInteractiveLoaderXML::poll() {
ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": <ext_resource> referenced nonexistent resource at: "+path);
ERR_FAIL_V(error);
} else {
- ResourceLoader::notify_load_error("Resource Not Found: "+path);
+ ResourceLoader::notify_dependency_error(local_path,path,type);
}
} else {
resource_cache.push_back(res);
}
+ if (tag->args.has("index")) {
+ ExtResource er;
+ er.path=path;
+ er.type=type;
+ ext_resources[tag->args["index"].to_int()]=er;
+ }
+
+
Error err = close_tag("ext_resource");
if (err)
return error;
@@ -1551,7 +1570,9 @@ Error ResourceInteractiveLoaderXML::poll() {
if (main) {
f->close();
resource=res;
- resource->set_path(res_path);
+ if (!ResourceCache::has(res_path)) {
+ resource->set_path(res_path);
+ }
error=ERR_FILE_EOF;
return error;
@@ -1566,7 +1587,7 @@ int ResourceInteractiveLoaderXML::get_stage() const {
}
int ResourceInteractiveLoaderXML::get_stage_count() const {
- return resources_total+ext_resources.size();
+ return resources_total;//+ext_resources;
}
ResourceInteractiveLoaderXML::~ResourceInteractiveLoaderXML() {
@@ -1574,7 +1595,7 @@ ResourceInteractiveLoaderXML::~ResourceInteractiveLoaderXML() {
memdelete(f);
}
-void ResourceInteractiveLoaderXML::get_dependencies(FileAccess *f,List<String> *p_dependencies) {
+void ResourceInteractiveLoaderXML::get_dependencies(FileAccess *f,List<String> *p_dependencies,bool p_add_types) {
open(f);
@@ -1617,6 +1638,10 @@ void ResourceInteractiveLoaderXML::get_dependencies(FileAccess *f,List<String> *
path = ResourceLoader::guess_full_filename(path,type);
}
+ if (p_add_types && tag->args.has("type")) {
+ path+="::"+tag->args["type"];
+ }
+
p_dependencies->push_back(path);
Error err = close_tag("ext_resource");
@@ -1628,6 +1653,167 @@ void ResourceInteractiveLoaderXML::get_dependencies(FileAccess *f,List<String> *
}
+Error ResourceInteractiveLoaderXML::rename_dependencies(FileAccess *p_f, const String &p_path,const Map<String,String>& p_map) {
+
+ open(p_f);
+ ERR_FAIL_COND_V(error!=OK,error);
+
+ //FileAccess
+
+ bool old_format=false;
+
+ FileAccess *fw = NULL;
+
+ String base_path=local_path.get_base_dir();
+
+ while(true) {
+ bool exit;
+ List<String> order;
+
+ Tag *tag = parse_tag(&exit,true,&order);
+
+ bool done=false;
+
+ if (!tag) {
+ if (fw) {
+ memdelete(fw);
+ }
+ error=ERR_FILE_CORRUPT;
+ ERR_FAIL_COND_V(!exit,error);
+ error=ERR_FILE_EOF;
+
+ return error;
+ }
+
+ if (tag->name=="ext_resource") {
+
+ if (!tag->args.has("index") || !tag->args.has("path") || !tag->args.has("type")) {
+ old_format=true;
+ break;
+ }
+
+ if (!fw) {
+
+ fw=FileAccess::open(p_path+".depren",FileAccess::WRITE);
+ fw->store_line("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"); //no escape
+ fw->store_line("<resource_file type=\""+resource_type+"\" subresource_count=\""+itos(resources_total)+"\" version=\""+itos(VERSION_MAJOR)+"."+itos(VERSION_MINOR)+"\" version_name=\""+VERSION_FULL_NAME+"\">");
+
+ }
+
+ String path = tag->args["path"];
+ String index = tag->args["index"];
+ String type = tag->args["type"];
+
+
+ bool relative=false;
+ if (!path.begins_with("res://")) {
+ path=base_path.plus_file(path).simplify_path();
+ relative=true;
+ }
+
+
+ if (p_map.has(path)) {
+ String np=p_map[path];
+ path=np;
+ }
+
+ if (relative) {
+ //restore relative
+ path=base_path.path_to_file(path);
+ }
+
+ tag->args["path"]=path;
+ tag->args["index"]=index;
+ tag->args["type"]=type;
+
+ } else {
+
+ done=true;
+ }
+
+ String tagt="\t<";
+ if (exit)
+ tagt+="/";
+ tagt+=tag->name;
+
+ for(List<String>::Element *E=order.front();E;E=E->next()) {
+ tagt+=" "+E->get()+"=\""+tag->args[E->get()]+"\"";
+ }
+ tagt+=">";
+ fw->store_line(tagt);
+ if (done)
+ break;
+ close_tag("ext_resource");
+ fw->store_line("\t</ext_resource>");
+
+ }
+
+
+ if (old_format) {
+ if (fw)
+ memdelete(fw);
+
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ da->remove(p_path+".depren");
+ memdelete(da);
+ //fuck it, use the old approach;
+
+ WARN_PRINT(("This file is old, so it can't refactor dependencies, opening and resaving: "+p_path).utf8().get_data());
+
+ Error err;
+ FileAccess *f2 = FileAccess::open(p_path,FileAccess::READ,&err);
+ if (err!=OK) {
+ ERR_FAIL_COND_V(err!=OK,ERR_FILE_CANT_OPEN);
+ }
+
+ Ref<ResourceInteractiveLoaderXML> ria = memnew( ResourceInteractiveLoaderXML );
+ ria->local_path=Globals::get_singleton()->localize_path(p_path);
+ ria->res_path=ria->local_path;
+ ria->remaps=p_map;
+ // ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
+ ria->open(f2);
+
+ err = ria->poll();
+
+ while(err==OK) {
+ err=ria->poll();
+ }
+
+ ERR_FAIL_COND_V(err!=ERR_FILE_EOF,ERR_FILE_CORRUPT);
+ RES res = ria->get_resource();
+ ERR_FAIL_COND_V(!res.is_valid(),ERR_FILE_CORRUPT);
+
+ return ResourceFormatSaverXML::singleton->save(p_path,res);
+ }
+
+ if (!fw) {
+
+ return OK; //nothing to rename, do nothing
+ }
+
+ uint8_t c=f->get_8();
+ while(!f->eof_reached()) {
+ fw->store_8(c);
+ c=f->get_8();
+ }
+
+ bool all_ok = fw->get_error()==OK;
+
+ memdelete(fw);
+
+ if (!all_ok) {
+ return ERR_CANT_CREATE;
+ }
+
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ da->remove(p_path);
+ da->rename(p_path+".depren",p_path);
+ memdelete(da);
+
+ return OK;
+
+}
+
void ResourceInteractiveLoaderXML::open(FileAccess *p_f) {
@@ -1674,8 +1860,8 @@ void ResourceInteractiveLoaderXML::open(FileAccess *p_f) {
ERR_FAIL();
}
- int major = version.get_slice(".",0).to_int();
- int minor = version.get_slice(".",1).to_int();
+ int major = version.get_slicec('.',0).to_int();
+ int minor = version.get_slicec('.',1).to_int();
if (major>VERSION_MAJOR) {
@@ -1686,6 +1872,7 @@ void ResourceInteractiveLoaderXML::open(FileAccess *p_f) {
}
+ /*
String preload_depts = "deps/"+local_path.md5_text();
if (Globals::get_singleton()->has(preload_depts)) {
ext_resources.clear();
@@ -1697,7 +1884,7 @@ void ResourceInteractiveLoaderXML::open(FileAccess *p_f) {
}
print_line(local_path+" - EXTERNAL RESOURCES: "+itos(ext_resources.size()));
}
-
+*/
}
@@ -1730,7 +1917,10 @@ String ResourceInteractiveLoaderXML::recognize(FileAccess *p_f) {
/////////////////////
-Ref<ResourceInteractiveLoader> ResourceFormatLoaderXML::load_interactive(const String &p_path) {
+Ref<ResourceInteractiveLoader> ResourceFormatLoaderXML::load_interactive(const String &p_path, Error *r_error) {
+
+ if (r_error)
+ *r_error=ERR_CANT_OPEN;
Error err;
FileAccess *f = FileAccess::open(p_path,FileAccess::READ,&err);
@@ -1767,7 +1957,6 @@ void ResourceFormatLoaderXML::get_recognized_extensions_for_type(const String& p
if (ext=="res")
continue;
p_extensions->push_back("x"+ext);
- p_extensions->push_back(ext);
}
p_extensions->push_back("xml");
@@ -1816,7 +2005,7 @@ String ResourceFormatLoaderXML::get_resource_type(const String &p_path) const{
}
-void ResourceFormatLoaderXML::get_dependencies(const String& p_path,List<String> *p_dependencies) {
+void ResourceFormatLoaderXML::get_dependencies(const String& p_path,List<String> *p_dependencies,bool p_add_types) {
FileAccess *f = FileAccess::open(p_path,FileAccess::READ);
if (!f) {
@@ -1828,11 +2017,27 @@ void ResourceFormatLoaderXML::get_dependencies(const String& p_path,List<String>
ria->local_path=Globals::get_singleton()->localize_path(p_path);
ria->res_path=ria->local_path;
// ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
- ria->get_dependencies(f,p_dependencies);
+ ria->get_dependencies(f,p_dependencies,p_add_types);
}
+Error ResourceFormatLoaderXML::rename_dependencies(const String &p_path,const Map<String,String>& p_map) {
+
+ FileAccess *f = FileAccess::open(p_path,FileAccess::READ);
+ if (!f) {
+
+ ERR_FAIL_V(ERR_CANT_OPEN);
+ }
+
+ Ref<ResourceInteractiveLoaderXML> ria = memnew( ResourceInteractiveLoaderXML );
+ ria->local_path=Globals::get_singleton()->localize_path(p_path);
+ ria->res_path=ria->local_path;
+// ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
+ return ria->rename_dependencies(f,p_path,p_map);
+}
+
+
/****************************************************************************************/
/****************************************************************************************/
/****************************************************************************************/
@@ -1852,8 +2057,8 @@ void ResourceFormatLoaderXML::get_dependencies(const String& p_path,List<String>
void ResourceFormatSaverXMLInstance::escape(String& p_str) {
p_str=p_str.replace("&","&amp;");
- p_str=p_str.replace("<","&gt;");
- p_str=p_str.replace(">","&lt;");
+ p_str=p_str.replace("<","&lt;");
+ p_str=p_str.replace(">","&gt;");
p_str=p_str.replace("'","&apos;");
p_str=p_str.replace("\"","&quot;");
for (char i=1;i<32;i++) {
@@ -2024,20 +2229,26 @@ void ResourceFormatSaverXMLInstance::write_property(const String& p_name,const V
return; // don't save it
}
- params="resource_type=\""+res->get_save_type()+"\"";
+ if (external_resources.has(res)) {
- if (res->get_path().length() && res->get_path().find("::")==-1) {
- //external resource
- String path=relative_paths?local_path.path_to_file(res->get_path()):res->get_path();
- escape(path);
- params+=" path=\""+path+"\"";
+ params="external=\""+itos(external_resources[res])+"\"";
} else {
+ params="resource_type=\""+res->get_save_type()+"\"";
- //internal resource
- ERR_EXPLAIN("Resource was not pre cached for the resource section, bug?");
- ERR_FAIL_COND(!resource_set.has(res));
- params+=" path=\"local://"+itos(res->get_subindex())+"\"";
+ if (res->get_path().length() && res->get_path().find("::")==-1) {
+ //external resource
+ String path=relative_paths?local_path.path_to_file(res->get_path()):res->get_path();
+ escape(path);
+ params+=" path=\""+path+"\"";
+ } else {
+
+ //internal resource
+ ERR_EXPLAIN("Resource was not pre cached for the resource section, bug?");
+ ERR_FAIL_COND(!resource_set.has(res));
+
+ params+=" path=\"local://"+itos(res->get_subindex())+"\"";
+ }
}
} break;
@@ -2441,11 +2652,12 @@ void ResourceFormatSaverXMLInstance::_find_resources(const Variant& p_variant,bo
RES res = p_variant.operator RefPtr();
- if (res.is_null())
+ if (res.is_null() || external_resources.has(res))
return;
if (!p_main && (!bundle_resources ) && res->get_path().length() && res->get_path().find("::") == -1 ) {
- external_resources.push_back(res);
+ int index = external_resources.size();
+ external_resources[res]=index;
return;
}
@@ -2533,12 +2745,12 @@ Error ResourceFormatSaverXMLInstance::save(const String &p_path,const RES& p_res
enter_tag("resource_file","type=\""+p_resource->get_type()+"\" subresource_count=\""+itos(saved_resources.size()+external_resources.size())+"\" version=\""+itos(VERSION_MAJOR)+"."+itos(VERSION_MINOR)+"\" version_name=\""+VERSION_FULL_NAME+"\"");
write_string("\n",false);
- for(List<RES>::Element *E=external_resources.front();E;E=E->next()) {
+ for(Map<RES,int>::Element *E=external_resources.front();E;E=E->next()) {
write_tabs();
- String p = E->get()->get_path();
+ String p = E->key()->get_path();
- enter_tag("ext_resource","path=\""+p+"\" type=\""+E->get()->get_save_type()+"\""); //bundled
+ enter_tag("ext_resource","path=\""+p+"\" type=\""+E->key()->get_save_type()+"\" index=\""+itos(E->get())+"\""); //bundled
exit_tag("ext_resource"); //bundled
write_string("\n",false);
}
@@ -2607,9 +2819,12 @@ Error ResourceFormatSaverXMLInstance::save(const String &p_path,const RES& p_res
String name = PE->get().name;
Variant value = res->get(name);
- if (PE->get().usage&PROPERTY_USAGE_STORE_IF_NONZERO && value.is_zero())
+
+
+ if ((PE->get().usage&PROPERTY_USAGE_STORE_IF_NONZERO && value.is_zero())||(PE->get().usage&PROPERTY_USAGE_STORE_IF_NONONE && value.is_one()) )
continue;
+
write_property(name,value);
}
@@ -2664,3 +2879,8 @@ void ResourceFormatSaverXML::get_recognized_extensions(const RES& p_resource,Lis
}
}
+
+ResourceFormatSaverXML* ResourceFormatSaverXML::singleton=NULL;
+ResourceFormatSaverXML::ResourceFormatSaverXML() {
+ singleton=this;
+}
diff --git a/core/io/resource_format_xml.h b/core/io/resource_format_xml.h
index d5ba9eb800..94c81a4111 100644
--- a/core/io/resource_format_xml.h
+++ b/core/io/resource_format_xml.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -46,13 +46,21 @@ class ResourceInteractiveLoaderXML : public ResourceInteractiveLoader {
String name;
HashMap<String,String> args;
+
};
_FORCE_INLINE_ Error _parse_array_element(Vector<char> &buff,bool p_number_only,FileAccess *f,bool *end);
+ struct ExtResource {
+ String path;
+ String type;
+ };
+
- List<StringName> ext_resources;
+ Map<String,String> remaps;
+
+ Map<int,ExtResource> ext_resources;
int resources_total;
int resource_current;
@@ -66,7 +74,7 @@ friend class ResourceFormatLoaderXML;
List<Tag> tag_stack;
List<RES> resource_cache;
- Tag* parse_tag(bool* r_exit=NULL,bool p_printerr=true);
+ Tag* parse_tag(bool* r_exit=NULL,bool p_printerr=true,List<String> *r_order=NULL);
Error close_tag(const String& p_name);
_FORCE_INLINE_ void unquote(String& p_str);
Error goto_end_of_tag();
@@ -87,7 +95,8 @@ public:
void open(FileAccess *p_f);
String recognize(FileAccess *p_f);
- void get_dependencies(FileAccess *p_f,List<String> *p_dependencies);
+ void get_dependencies(FileAccess *p_f, List<String> *p_dependencies, bool p_add_types);
+ Error rename_dependencies(FileAccess *p_f, const String &p_path,const Map<String,String>& p_map);
~ResourceInteractiveLoaderXML();
@@ -97,12 +106,13 @@ public:
class ResourceFormatLoaderXML : public ResourceFormatLoader {
public:
- virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path);
+ virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path,Error *r_error=NULL);
virtual void get_recognized_extensions_for_type(const String& p_type,List<String> *p_extensions) const;
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String& p_type) const;
virtual String get_resource_type(const String &p_path) const;
- virtual void get_dependencies(const String& p_path,List<String> *p_dependencies);
+ virtual void get_dependencies(const String& p_path, List<String> *p_dependencies, bool p_add_types=false);
+ virtual Error rename_dependencies(const String &p_path,const Map<String,String>& p_map);
};
@@ -125,7 +135,7 @@ class ResourceFormatSaverXMLInstance {
int depth;
Set<RES> resource_set;
List<RES> saved_resources;
- List<RES> external_resources;
+ Map<RES,int> external_resources;
void enter_tag(const char* p_tag,const String& p_args=String());
void exit_tag(const char* p_tag);
@@ -148,11 +158,12 @@ public:
class ResourceFormatSaverXML : public ResourceFormatSaver {
public:
+ static ResourceFormatSaverXML* singleton;
virtual Error save(const String &p_path,const RES& p_resource,uint32_t p_flags=0);
virtual bool recognize(const RES& p_resource) const;
virtual void get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) const;
-
+ ResourceFormatSaverXML();
};
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index 22d89840ae..67208b5960 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -103,10 +103,10 @@ public:
-Ref<ResourceInteractiveLoader> ResourceFormatLoader::load_interactive(const String &p_path) {
+Ref<ResourceInteractiveLoader> ResourceFormatLoader::load_interactive(const String &p_path, Error *r_error) {
//either this
- Ref<Resource> res = load(p_path);
+ Ref<Resource> res = load(p_path,p_path,r_error);
if (res.is_null())
return Ref<ResourceInteractiveLoader>();
@@ -115,12 +115,13 @@ Ref<ResourceInteractiveLoader> ResourceFormatLoader::load_interactive(const Stri
return ril;
}
-RES ResourceFormatLoader::load(const String &p_path,const String& p_original_path) {
+RES ResourceFormatLoader::load(const String &p_path, const String& p_original_path, Error *r_error) {
+
String path=p_path;
//or this must be implemented
- Ref<ResourceInteractiveLoader> ril = load_interactive(p_path);
+ Ref<ResourceInteractiveLoader> ril = load_interactive(p_path,r_error);
if (!ril.is_valid())
return RES();
ril->set_local_path(p_original_path);
@@ -130,9 +131,14 @@ RES ResourceFormatLoader::load(const String &p_path,const String& p_original_pat
Error err = ril->poll();
if (err==ERR_FILE_EOF) {
+ if (r_error)
+ *r_error=OK;
return ril->get_resource();
}
+ if (r_error)
+ *r_error=err;
+
ERR_FAIL_COND_V(err!=OK,RES());
}
@@ -140,7 +146,7 @@ RES ResourceFormatLoader::load(const String &p_path,const String& p_original_pat
}
-void ResourceFormatLoader::get_dependencies(const String& p_path,List<String> *p_dependencies) {
+void ResourceFormatLoader::get_dependencies(const String& p_path, List<String> *p_dependencies, bool p_add_types) {
//do nothing by default
}
@@ -149,7 +155,10 @@ void ResourceFormatLoader::get_dependencies(const String& p_path,List<String> *p
///////////////////////////////////
-RES ResourceLoader::load(const String &p_path,const String& p_type_hint,bool p_no_cache) {
+RES ResourceLoader::load(const String &p_path, const String& p_type_hint, bool p_no_cache, Error *r_error) {
+
+ if (r_error)
+ *r_error=ERR_CANT_OPEN;
String local_path;
if (p_path.is_rel_path())
@@ -183,7 +192,7 @@ RES ResourceLoader::load(const String &p_path,const String& p_type_hint,bool p_n
if (p_type_hint!="" && !loader[i]->handles_type(p_type_hint))
continue;
found=true;
- RES res = loader[i]->load(remapped_path,local_path);
+ RES res = loader[i]->load(remapped_path,local_path,r_error);
if (res.is_null())
continue;
if (!p_no_cache)
@@ -222,14 +231,12 @@ Ref<ResourceImportMetadata> ResourceLoader::load_import_metadata(const String &p
local_path = Globals::get_singleton()->localize_path(p_path);
String extension=p_path.extension();
- bool found=false;
Ref<ResourceImportMetadata> ret;
for (int i=0;i<loader_count;i++) {
if (!loader[i]->recognize(extension))
continue;
- found=true;
Error err = loader[i]->load_import_metadata(local_path,ret);
if (err==OK)
@@ -289,9 +296,11 @@ String ResourceLoader::find_complete_path(const String& p_path,const String& p_t
return local_path;
}
-Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_path,const String& p_type_hint,bool p_no_cache) {
+Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_path,const String& p_type_hint,bool p_no_cache,Error *r_error) {
+ if (r_error)
+ *r_error=ERR_CANT_OPEN;
String local_path;
if (p_path.is_rel_path())
@@ -327,7 +336,7 @@ Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_
if (p_type_hint!="" && !loader[i]->handles_type(p_type_hint))
continue;
found=true;
- Ref<ResourceInteractiveLoader> ril = loader[i]->load_interactive(remapped_path);
+ Ref<ResourceInteractiveLoader> ril = loader[i]->load_interactive(remapped_path,r_error);
if (ril.is_null())
continue;
if (!p_no_cache)
@@ -352,7 +361,32 @@ void ResourceLoader::add_resource_format_loader(ResourceFormatLoader *p_format_l
loader[loader_count++]=p_format_loader;
}
-void ResourceLoader::get_dependencies(const String& p_path,List<String> *p_dependencies) {
+void ResourceLoader::get_dependencies(const String& p_path, List<String> *p_dependencies, bool p_add_types) {
+
+
+ String local_path;
+ if (p_path.is_rel_path())
+ local_path="res://"+p_path;
+ else
+ local_path = Globals::get_singleton()->localize_path(p_path);
+
+ String remapped_path = PathRemap::get_singleton()->get_remap(local_path);
+
+ String extension=remapped_path.extension();
+
+ for (int i=0;i<loader_count;i++) {
+
+ if (!loader[i]->recognize(extension))
+ continue;
+ //if (p_type_hint!="" && !loader[i]->handles_type(p_type_hint))
+ // continue;
+
+ loader[i]->get_dependencies(remapped_path,p_dependencies,p_add_types);
+
+ }
+}
+
+Error ResourceLoader::rename_dependencies(const String &p_path,const Map<String,String>& p_map) {
String local_path;
@@ -372,11 +406,15 @@ void ResourceLoader::get_dependencies(const String& p_path,List<String> *p_depen
//if (p_type_hint!="" && !loader[i]->handles_type(p_type_hint))
// continue;
- loader[i]->get_dependencies(remapped_path,p_dependencies);
+ return loader[i]->rename_dependencies(p_path,p_map);
}
+
+ return OK; // ??
+
}
+
String ResourceLoader::guess_full_filename(const String &p_path,const String& p_type) {
String local_path;
@@ -414,6 +452,9 @@ String ResourceLoader::get_resource_type(const String &p_path) {
ResourceLoadErrorNotify ResourceLoader::err_notify=NULL;
void *ResourceLoader::err_notify_ud=NULL;
+DependencyErrorNotify ResourceLoader::dep_err_notify=NULL;
+void *ResourceLoader::dep_err_notify_ud=NULL;
+
bool ResourceLoader::abort_on_missing_resource=true;
bool ResourceLoader::timestamp_on_load=false;
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index d25727f19f..fe58303066 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -57,21 +57,23 @@ public:
class ResourceFormatLoader {
public:
- virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path);
- virtual RES load(const String &p_path,const String& p_original_path="");
+ virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path,Error *r_error=NULL);
+ virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL);
virtual void get_recognized_extensions(List<String> *p_extensions) const=0;
virtual void get_recognized_extensions_for_type(const String& p_type,List<String> *p_extensions) const;
bool recognize(const String& p_extension) const;
virtual bool handles_type(const String& p_type) const=0;
virtual String get_resource_type(const String &p_path) const=0;
- virtual void get_dependencies(const String& p_path,List<String> *p_dependencies);
+ virtual void get_dependencies(const String& p_path,List<String> *p_dependencies,bool p_add_types=false);
virtual Error load_import_metadata(const String &p_path, Ref<ResourceImportMetadata>& r_var) const { return ERR_UNAVAILABLE; }
+ virtual Error rename_dependencies(const String &p_path,const Map<String,String>& p_map) { return OK; }
virtual ~ResourceFormatLoader() {}
};
typedef void (*ResourceLoadErrorNotify)(void *p_ud,const String& p_text);
+typedef void (*DependencyErrorNotify)(void *p_ud,const String& p_loading,const String& p_which,const String& p_type);
class ResourceLoader {
@@ -86,6 +88,8 @@ class ResourceLoader {
static void* err_notify_ud;
static ResourceLoadErrorNotify err_notify;
+ static void* dep_err_notify_ud;
+ static DependencyErrorNotify dep_err_notify;
static bool abort_on_missing_resource;
static String find_complete_path(const String& p_path,const String& p_type);
@@ -93,14 +97,15 @@ public:
- static Ref<ResourceInteractiveLoader> load_interactive(const String &p_path,const String& p_type_hint="",bool p_no_cache=false);
- static RES load(const String &p_path,const String& p_type_hint="",bool p_no_cache=false);
+ static Ref<ResourceInteractiveLoader> load_interactive(const String &p_path,const String& p_type_hint="",bool p_no_cache=false,Error *r_error=NULL);
+ static RES load(const String &p_path,const String& p_type_hint="",bool p_no_cache=false,Error *r_error=NULL);
static Ref<ResourceImportMetadata> load_import_metadata(const String &p_path);
static void get_recognized_extensions_for_type(const String& p_type,List<String> *p_extensions);
static void add_resource_format_loader(ResourceFormatLoader *p_format_loader);
static String get_resource_type(const String &p_path);
- static void get_dependencies(const String& p_path,List<String> *p_dependencies);
+ static void get_dependencies(const String& p_path,List<String> *p_dependencies,bool p_add_types=false);
+ static Error rename_dependencies(const String &p_path,const Map<String,String>& p_map);
static String guess_full_filename(const String &p_path,const String& p_type);
@@ -108,6 +113,11 @@ public:
static void notify_load_error(const String& p_err) { if (err_notify) err_notify(err_notify_ud,p_err); }
static void set_error_notify_func(void* p_ud,ResourceLoadErrorNotify p_err_notify) { err_notify=p_err_notify; err_notify_ud=p_ud;}
+
+ static void notify_dependency_error(const String& p_path,const String& p_dependency,const String& p_type) { if (dep_err_notify) dep_err_notify(dep_err_notify_ud,p_path,p_dependency,p_type); }
+ static void set_dependency_error_notify_func(void* p_ud,DependencyErrorNotify p_err_notify) { dep_err_notify=p_err_notify; dep_err_notify_ud=p_ud;}
+
+
static void set_abort_on_missing_resources(bool p_abort) { abort_on_missing_resource=p_abort; }
static bool get_abort_on_missing_resources() { return abort_on_missing_resource; }
};
diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp
index fdb9a53f0d..51020a0285 100644
--- a/core/io/resource_saver.cpp
+++ b/core/io/resource_saver.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/resource_saver.h b/core/io/resource_saver.h
index 05cbe7f98e..7bc96c1087 100644
--- a/core/io/resource_saver.h
+++ b/core/io/resource_saver.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -46,7 +46,7 @@ public:
virtual Error save(const String &p_path,const RES& p_resource,uint32_t p_flags=0)=0;
virtual bool recognize(const RES& p_resource) const=0;
virtual void get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) const=0;
-
+
virtual ~ResourceFormatSaver() {}
};
diff --git a/core/io/stream_peer.cpp b/core/io/stream_peer.cpp
index b00b462eb6..2a9dff86f8 100644
--- a/core/io/stream_peer.cpp
+++ b/core/io/stream_peer.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,7 +27,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "stream_peer.h"
-
+#include "io/marshalls.h"
Error StreamPeer::_put_data(const DVector<uint8_t>& p_data) {
@@ -115,6 +115,271 @@ Array StreamPeer::_get_partial_data(int p_bytes) {
}
+void StreamPeer::set_big_endian(bool p_enable) {
+
+ big_endian=p_enable;
+}
+
+bool StreamPeer::is_big_endian_enabled() const {
+
+ return big_endian;
+}
+
+
+void StreamPeer::put_u8(uint8_t p_val) {
+ put_data((const uint8_t*)&p_val,1);
+
+}
+
+void StreamPeer::put_8(int8_t p_val){
+
+ put_data((const uint8_t*)&p_val,1);
+}
+void StreamPeer::put_u16(uint16_t p_val){
+
+ if (big_endian) {
+ p_val=BSWAP16(p_val);
+ }
+ uint8_t buf[2];
+ encode_uint16(p_val,buf);
+ put_data(buf,2);
+
+}
+void StreamPeer::put_16(int16_t p_val){
+
+ if (big_endian) {
+ p_val=BSWAP16(p_val);
+ }
+ uint8_t buf[2];
+ encode_uint16(p_val,buf);
+ put_data(buf,2);
+
+}
+void StreamPeer::put_u32(uint32_t p_val){
+
+ if (big_endian) {
+ p_val=BSWAP32(p_val);
+ }
+ uint8_t buf[4];
+ encode_uint32(p_val,buf);
+ put_data(buf,4);
+
+}
+void StreamPeer::put_32(int32_t p_val){
+
+ if (big_endian) {
+ p_val=BSWAP32(p_val);
+ }
+ uint8_t buf[4];
+ encode_uint32(p_val,buf);
+ put_data(buf,4);
+
+}
+void StreamPeer::put_u64(uint64_t p_val){
+
+ if (big_endian) {
+ p_val=BSWAP64(p_val);
+ }
+ uint8_t buf[8];
+ encode_uint64(p_val,buf);
+ put_data(buf,8);
+
+}
+void StreamPeer::put_64(int64_t p_val){
+
+ if (big_endian) {
+ p_val=BSWAP64(p_val);
+ }
+ uint8_t buf[8];
+ encode_uint64(p_val,buf);
+ put_data(buf,8);
+
+}
+void StreamPeer::put_float(float p_val){
+
+ uint8_t buf[4];
+
+ encode_float(p_val,buf);
+ if (big_endian) {
+ uint32_t *p32=(uint32_t *)buf;
+ *p32=BSWAP32(*p32);
+ }
+
+ put_data(buf,4);
+
+}
+void StreamPeer::put_double(double p_val){
+
+ uint8_t buf[8];
+ encode_double(p_val,buf);
+ if (big_endian) {
+ uint64_t *p64=(uint64_t *)buf;
+ *p64=BSWAP64(*p64);
+ }
+ put_data(buf,8);
+
+}
+void StreamPeer::put_utf8_string(const String& p_string) {
+
+ CharString cs=p_string.utf8();
+ put_data((const uint8_t*)cs.get_data(),cs.length());
+
+}
+void StreamPeer::put_var(const Variant& p_variant){
+
+ int len=0;
+ Vector<uint8_t> buf;
+ encode_variant(p_variant,NULL,len);
+ buf.resize(len);
+ put_32(len);
+ encode_variant(p_variant,buf.ptr(),len);
+ put_data(buf.ptr(),buf.size());
+
+
+}
+
+uint8_t StreamPeer::get_u8(){
+
+ uint8_t buf[1];
+ get_data(buf,1);
+ return buf[0];
+}
+int8_t StreamPeer::get_8(){
+
+ uint8_t buf[1];
+ get_data(buf,1);
+ return buf[0];
+
+}
+uint16_t StreamPeer::get_u16(){
+
+ uint8_t buf[2];
+ get_data(buf,2);
+ uint16_t r = decode_uint16(buf);
+ if (big_endian) {
+ r=BSWAP16(r);
+ }
+ return r;
+
+}
+int16_t StreamPeer::get_16(){
+
+ uint8_t buf[2];
+ get_data(buf,2);
+ uint16_t r = decode_uint16(buf);
+ if (big_endian) {
+ r=BSWAP16(r);
+ }
+ return r;
+
+}
+uint32_t StreamPeer::get_u32(){
+
+ uint8_t buf[4];
+ get_data(buf,4);
+ uint32_t r = decode_uint32(buf);
+ if (big_endian) {
+ r=BSWAP32(r);
+ }
+ return r;
+
+}
+int32_t StreamPeer::get_32(){
+
+ uint8_t buf[4];
+ get_data(buf,4);
+ uint32_t r = decode_uint32(buf);
+ if (big_endian) {
+ r=BSWAP32(r);
+ }
+ return r;
+
+}
+uint64_t StreamPeer::get_u64(){
+
+ uint8_t buf[8];
+ get_data(buf,8);
+ uint64_t r = decode_uint64(buf);
+ if (big_endian) {
+ r=BSWAP64(r);
+ }
+ return r;
+
+}
+int64_t StreamPeer::get_64(){
+
+ uint8_t buf[8];
+ get_data(buf,8);
+ uint64_t r = decode_uint64(buf);
+ if (big_endian) {
+ r=BSWAP64(r);
+ }
+ return r;
+
+}
+float StreamPeer::get_float(){
+
+ uint8_t buf[4];
+ get_data(buf,4);
+
+ if (big_endian) {
+ uint32_t *p32=(uint32_t *)buf;
+ *p32=BSWAP32(*p32);
+ }
+
+ return decode_float(buf);
+}
+
+float StreamPeer::get_double(){
+
+ uint8_t buf[8];
+ get_data(buf,8);
+
+ if (big_endian) {
+ uint64_t *p64=(uint64_t *)buf;
+ *p64=BSWAP64(*p64);
+ }
+
+ return decode_double(buf);
+
+}
+String StreamPeer::get_string(int p_bytes){
+
+ ERR_FAIL_COND_V(p_bytes<0,String());
+
+ Vector<char> buf;
+ buf.resize(p_bytes+1);
+ get_data((uint8_t*)&buf[0],p_bytes);
+ buf[p_bytes]=0;
+ return buf.ptr();
+
+}
+String StreamPeer::get_utf8_string(int p_bytes){
+
+ ERR_FAIL_COND_V(p_bytes<0,String());
+ ERR_FAIL_COND_V(p_bytes<0,String());
+
+ Vector<uint8_t> buf;
+ buf.resize(p_bytes);
+ get_data(buf.ptr(),p_bytes);
+
+ String ret;
+ ret.parse_utf8((const char*)buf.ptr(),buf.size());
+ return ret;
+
+}
+Variant StreamPeer::get_var(){
+
+ int len = get_32();
+ Vector<uint8_t> var;
+ var.resize(len);
+ get_data(var.ptr(),len);
+
+ Variant ret;
+ decode_variant(ret,var.ptr(),len);
+ return ret;
+}
+
void StreamPeer::_bind_methods() {
@@ -123,4 +388,36 @@ void StreamPeer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_data","bytes"),&StreamPeer::_get_data);
ObjectTypeDB::bind_method(_MD("get_partial_data","bytes"),&StreamPeer::_get_partial_data);
+
+ ObjectTypeDB::bind_method(_MD("get_available_bytes"),&StreamPeer::get_available_bytes);
+
+ ObjectTypeDB::bind_method(_MD("set_big_endian","enable"),&StreamPeer::set_big_endian);
+ ObjectTypeDB::bind_method(_MD("is_big_endian_enabled"),&StreamPeer::is_big_endian_enabled);
+
+ ObjectTypeDB::bind_method(_MD("put_8","val"),&StreamPeer::put_8);
+ ObjectTypeDB::bind_method(_MD("put_u8","val"),&StreamPeer::put_u8);
+ ObjectTypeDB::bind_method(_MD("put_16","val"),&StreamPeer::put_16);
+ ObjectTypeDB::bind_method(_MD("put_u16","val"),&StreamPeer::put_u16);
+ ObjectTypeDB::bind_method(_MD("put_32","val"),&StreamPeer::put_32);
+ ObjectTypeDB::bind_method(_MD("put_u32","val"),&StreamPeer::put_u32);
+ ObjectTypeDB::bind_method(_MD("put_64","val"),&StreamPeer::put_64);
+ ObjectTypeDB::bind_method(_MD("put_u64","val"),&StreamPeer::put_u64);
+ ObjectTypeDB::bind_method(_MD("put_float","val"),&StreamPeer::put_float);
+ ObjectTypeDB::bind_method(_MD("put_double","val"),&StreamPeer::put_double);
+ ObjectTypeDB::bind_method(_MD("put_utf8_string","val"),&StreamPeer::put_utf8_string);
+ ObjectTypeDB::bind_method(_MD("put_var","val:Variant"),&StreamPeer::put_var);
+
+ ObjectTypeDB::bind_method(_MD("get_8"),&StreamPeer::get_8);
+ ObjectTypeDB::bind_method(_MD("get_u8"),&StreamPeer::get_u8);
+ ObjectTypeDB::bind_method(_MD("get_16"),&StreamPeer::get_16);
+ ObjectTypeDB::bind_method(_MD("get_u16"),&StreamPeer::get_u16);
+ ObjectTypeDB::bind_method(_MD("get_32"),&StreamPeer::get_32);
+ ObjectTypeDB::bind_method(_MD("get_u32"),&StreamPeer::get_u32);
+ ObjectTypeDB::bind_method(_MD("get_64"),&StreamPeer::get_64);
+ ObjectTypeDB::bind_method(_MD("get_u64"),&StreamPeer::get_u64);
+ ObjectTypeDB::bind_method(_MD("get_float"),&StreamPeer::get_float);
+ ObjectTypeDB::bind_method(_MD("get_double"),&StreamPeer::get_double);
+ ObjectTypeDB::bind_method(_MD("get_string","bytes"),&StreamPeer::get_string);
+ ObjectTypeDB::bind_method(_MD("get_utf8_string","bytes"),&StreamPeer::get_utf8_string);
+ ObjectTypeDB::bind_method(_MD("get_var:Variant"),&StreamPeer::get_var);
}
diff --git a/core/io/stream_peer.h b/core/io/stream_peer.h
index e83fc71b93..970e6695a5 100644
--- a/core/io/stream_peer.h
+++ b/core/io/stream_peer.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -44,6 +44,8 @@ protected:
Array _get_data(int p_bytes);
Array _get_partial_data(int p_bytes);
+ bool big_endian;
+
public:
virtual Error put_data(const uint8_t* p_data,int p_bytes)=0; ///< put a whole chunk of data, blocking until it sent
@@ -52,7 +54,41 @@ public:
virtual Error get_data(uint8_t* p_buffer, int p_bytes)=0; ///< read p_bytes of data, if p_bytes > available, it will block
virtual Error get_partial_data(uint8_t* p_buffer, int p_bytes,int &r_received)=0; ///< read as much data as p_bytes into buffer, if less was read, return in r_received
- StreamPeer() {}
+ virtual int get_available_bytes() const=0;
+
+ void set_big_endian(bool p_enable);
+ bool is_big_endian_enabled() const;
+
+ void put_8(int8_t p_val);
+ void put_u8(uint8_t p_val);
+ void put_16(int16_t p_val);
+ void put_u16(uint16_t p_val);
+ void put_32(int32_t p_val);
+ void put_u32(uint32_t p_val);
+ void put_64(int64_t p_val);
+ void put_u64(uint64_t p_val);
+ void put_float(float p_val);
+ void put_double(double p_val);
+ void put_utf8_string(const String& p_string);
+ void put_var(const Variant& p_variant);
+
+ uint8_t get_u8();
+ int8_t get_8();
+ uint16_t get_u16();
+ int16_t get_16();
+ uint32_t get_u32();
+ int32_t get_32();
+ uint64_t get_u64();
+ int64_t get_64();
+ float get_float();
+ float get_double();
+ String get_string(int p_bytes);
+ String get_utf8_string(int p_bytes);
+ Variant get_var();
+
+
+
+ StreamPeer() { big_endian=false; }
};
#endif // STREAM_PEER_H
diff --git a/core/io/stream_peer_tcp.cpp b/core/io/stream_peer_tcp.cpp
index c2343790ea..fbb0c69cb7 100644
--- a/core/io/stream_peer_tcp.cpp
+++ b/core/io/stream_peer_tcp.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/stream_peer_tcp.h b/core/io/stream_peer_tcp.h
index 0e37303516..4c58e7e149 100644
--- a/core/io/stream_peer_tcp.h
+++ b/core/io/stream_peer_tcp.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/tcp_server.cpp b/core/io/tcp_server.cpp
index 803df87086..274d20a48a 100644
--- a/core/io/tcp_server.cpp
+++ b/core/io/tcp_server.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/tcp_server.h b/core/io/tcp_server.h
index b59f3293d7..512a7e640a 100644
--- a/core/io/tcp_server.h
+++ b/core/io/tcp_server.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp
index c32b25c407..fe101a8676 100644
--- a/core/io/translation_loader_po.cpp
+++ b/core/io/translation_loader_po.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,7 +30,10 @@
#include "os/file_access.h"
#include "translation.h"
-RES TranslationLoaderPO::load(const String &p_path,const String& p_original_path) {
+RES TranslationLoaderPO::load(const String &p_path, const String& p_original_path, Error *r_error) {
+
+ if (r_error)
+ *r_error=ERR_CANT_OPEN;
FileAccess *f=FileAccess::open(p_path,FileAccess::READ);
ERR_FAIL_COND_V(!f,RES());
@@ -49,6 +52,8 @@ RES TranslationLoaderPO::load(const String &p_path,const String& p_original_path
String msg_id;
String msg_str;
String config;
+ if (r_error)
+ *r_error=ERR_FILE_CORRUPT;
Ref<Translation> translation = Ref<Translation>( memnew( Translation ));
int line = 1;
@@ -174,6 +179,8 @@ RES TranslationLoaderPO::load(const String &p_path,const String& p_original_path
}
}
+ if (r_error)
+ *r_error=OK;
return translation;
diff --git a/core/io/translation_loader_po.h b/core/io/translation_loader_po.h
index 9d8ad97a29..a569674d80 100644
--- a/core/io/translation_loader_po.h
+++ b/core/io/translation_loader_po.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,7 +34,7 @@
class TranslationLoaderPO : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path,const String& p_original_path="");
+ virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String& p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/core/io/unzip.c b/core/io/unzip.c
index 0cd975211e..b438021ad7 100644
--- a/core/io/unzip.c
+++ b/core/io/unzip.c
@@ -1788,7 +1788,7 @@ extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len)
return UNZ_PARAMERROR;
- if ((pfile_in_zip_read_info->read_buffer == NULL))
+ if (pfile_in_zip_read_info->read_buffer==NULL)
return UNZ_END_OF_LIST_OF_FILE;
if (len==0)
return 0;
diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp
index 1ff458f325..e6a90412c1 100644
--- a/core/io/xml_parser.cpp
+++ b/core/io/xml_parser.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -385,15 +385,15 @@ void XMLParser::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_node_data"),&XMLParser::get_node_data);
ObjectTypeDB::bind_method(_MD("get_node_offset"),&XMLParser::get_node_offset);
ObjectTypeDB::bind_method(_MD("get_attribute_count"),&XMLParser::get_attribute_count);
- ObjectTypeDB::bind_method(_MD("get_attribute_name"),&XMLParser::get_attribute_name);
- ObjectTypeDB::bind_method(_MD("get_attribute_value"),(String (XMLParser::*)(int) const) &XMLParser::get_attribute_value);
- ObjectTypeDB::bind_method(_MD("has_attribute"),&XMLParser::has_attribute);
- ObjectTypeDB::bind_method(_MD("get_named_attribute_value"), (String (XMLParser::*)(const String&) const) &XMLParser::get_attribute_value);
- ObjectTypeDB::bind_method(_MD("get_named_attribute_value_safe"), &XMLParser::get_attribute_value_safe);
+ ObjectTypeDB::bind_method(_MD("get_attribute_name","idx"),&XMLParser::get_attribute_name);
+ ObjectTypeDB::bind_method(_MD("get_attribute_value","idx"),(String (XMLParser::*)(int) const) &XMLParser::get_attribute_value);
+ ObjectTypeDB::bind_method(_MD("has_attribute","name"),&XMLParser::has_attribute);
+ ObjectTypeDB::bind_method(_MD("get_named_attribute_value","name"), (String (XMLParser::*)(const String&) const) &XMLParser::get_attribute_value);
+ ObjectTypeDB::bind_method(_MD("get_named_attribute_value_safe","name"), &XMLParser::get_attribute_value_safe);
ObjectTypeDB::bind_method(_MD("is_empty"),&XMLParser::is_empty);
ObjectTypeDB::bind_method(_MD("get_current_line"),&XMLParser::get_current_line);
ObjectTypeDB::bind_method(_MD("skip_section"),&XMLParser::skip_section);
- ObjectTypeDB::bind_method(_MD("seek"),&XMLParser::seek);
+ ObjectTypeDB::bind_method(_MD("seek","pos"),&XMLParser::seek);
ObjectTypeDB::bind_method(_MD("open","file"),&XMLParser::open);
ObjectTypeDB::bind_method(_MD("open_buffer","buffer"),&XMLParser::open_buffer);
diff --git a/core/io/xml_parser.h b/core/io/xml_parser.h
index 418a8efa70..e0ec3ec770 100644
--- a/core/io/xml_parser.h
+++ b/core/io/xml_parser.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/io/zip.c b/core/io/zip.c
index 8f6aeb922f..c4ab93ab81 100644
--- a/core/io/zip.c
+++ b/core/io/zip.c
@@ -1114,9 +1114,9 @@ extern int ZEXPORT zipOpenNewFileInZip4_64 (zipFile file, const char* filename,
zi->ci.flag = flagBase;
if ((level==8) || (level==9))
zi->ci.flag |= 2;
- if ((level==2))
+ if (level==2)
zi->ci.flag |= 4;
- if ((level==1))
+ if (level==1)
zi->ci.flag |= 6;
if (password != NULL)
zi->ci.flag |= 1;
diff --git a/core/io/zip.h b/core/io/zip.h
index cca06c2ee8..85f93568c9 100644
--- a/core/io/zip.h
+++ b/core/io/zip.h
@@ -39,6 +39,8 @@
#ifndef _zip12_H
#define _zip12_H
+#include <stdlib.h>
+
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/core/io/zip_io.h b/core/io/zip_io.h
index c4b4d6b34d..355003d947 100644
--- a/core/io/zip_io.h
+++ b/core/io/zip_io.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,6 +34,7 @@
#include "os/file_access.h"
#include "os/copymem.h"
+
static void* zipio_open(void* data, const char* p_fname, int mode) {
FileAccess *&f = *(FileAccess**)data;
diff --git a/core/list.h b/core/list.h
index 6deb150ef6..fbeb653da4 100644
--- a/core/list.h
+++ b/core/list.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -518,10 +518,16 @@ public:
if (value->prev_ptr) {
value->prev_ptr->next_ptr = value->next_ptr;
- };
+ }
+ else {
+ _data->first = value->next_ptr;
+ }
if (value->next_ptr) {
value->next_ptr->prev_ptr = value->prev_ptr;
- };
+ }
+ else {
+ _data->last = value->prev_ptr;
+ }
value->next_ptr = where;
if (!where) {
diff --git a/core/map.h b/core/map.h
index e45c833bcb..35dc73df48 100644
--- a/core/map.h
+++ b/core/map.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/SCsub b/core/math/SCsub
index c6ba1fa537..7b4a6acbc0 100644
--- a/core/math/SCsub
+++ b/core/math/SCsub
@@ -3,5 +3,3 @@ Import('env')
env.add_source_files(env.core_sources,"*.cpp")
Export('env')
-
-
diff --git a/core/math/aabb.cpp b/core/math/aabb.cpp
index 435df66aab..6d8a5a72f0 100644
--- a/core/math/aabb.cpp
+++ b/core/math/aabb.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/aabb.h b/core/math/aabb.h
index 4781e5c263..7c9c3081ac 100644
--- a/core/math/aabb.h
+++ b/core/math/aabb.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/bezier_curve.cpp b/core/math/bezier_curve.cpp
index c9467a77e4..37cf16504c 100644
--- a/core/math/bezier_curve.cpp
+++ b/core/math/bezier_curve.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/bezier_curve.h b/core/math/bezier_curve.h
index de14d68987..25df9dfda8 100644
--- a/core/math/bezier_curve.h
+++ b/core/math/bezier_curve.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/bsp_tree.cpp b/core/math/bsp_tree.cpp
index d71b7551d9..0c07b733f0 100644
--- a/core/math/bsp_tree.cpp
+++ b/core/math/bsp_tree.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/bsp_tree.h b/core/math/bsp_tree.h
index b980d9590b..a7145f9ff1 100644
--- a/core/math/bsp_tree.h
+++ b/core/math/bsp_tree.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp
index f1afa33a4b..61c8b78e0a 100644
--- a/core/math/camera_matrix.cpp
+++ b/core/math/camera_matrix.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/camera_matrix.h b/core/math/camera_matrix.h
index 52b84f4870..27500a545e 100644
--- a/core/math/camera_matrix.h
+++ b/core/math/camera_matrix.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/face3.cpp b/core/math/face3.cpp
index 354372df74..e1af91f28e 100644
--- a/core/math/face3.cpp
+++ b/core/math/face3.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/face3.h b/core/math/face3.h
index eccbc78122..c36fdd1332 100644
--- a/core/math/face3.h
+++ b/core/math/face3.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/geometry.cpp b/core/math/geometry.cpp
index 14adde74e7..2905d26fe5 100644
--- a/core/math/geometry.cpp
+++ b/core/math/geometry.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/geometry.h b/core/math/geometry.h
index b438b41d61..8370990d6e 100644
--- a/core/math/geometry.h
+++ b/core/math/geometry.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -886,7 +886,38 @@ public:
}
+ static double vec2_cross(const Point2 &O, const Point2 &A, const Point2 &B)
+ {
+ return (double)(A.x - O.x) * (B.y - O.y) - (double)(A.y - O.y) * (B.x - O.x);
+ }
+
+ // Returns a list of points on the convex hull in counter-clockwise order.
+ // Note: the last point in the returned list is the same as the first one.
+ static Vector<Point2> convex_hull_2d(Vector<Point2> P)
+ {
+ int n = P.size(), k = 0;
+ Vector<Point2> H;
+ H.resize(2*n);
+
+ // Sort points lexicographically
+ P.sort();
+
+ // Build lower hull
+ for (int i = 0; i < n; ++i) {
+ while (k >= 2 && vec2_cross(H[k-2], H[k-1], P[i]) <= 0) k--;
+ H[k++] = P[i];
+ }
+
+ // Build upper hull
+ for (int i = n-2, t = k+1; i >= 0; i--) {
+ while (k >= t && vec2_cross(H[k-2], H[k-1], P[i]) <= 0) k--;
+ H[k++] = P[i];
+ }
+
+ H.resize(k);
+ return H;
+ }
static MeshData build_convex_mesh(const DVector<Plane> &p_planes);
static DVector<Plane> build_sphere_planes(float p_radius, int p_lats, int p_lons, Vector3::Axis p_axis=Vector3::AXIS_Z);
diff --git a/core/math/math_2d.cpp b/core/math/math_2d.cpp
index 88717723ce..a485125cb4 100644
--- a/core/math/math_2d.cpp
+++ b/core/math/math_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,7 +29,7 @@
#include "math_2d.h"
-real_t Vector2::atan2() const {
+real_t Vector2::angle() const {
return Math::atan2(x,y);
}
@@ -165,7 +165,7 @@ Vector2 Vector2::floor() const {
Vector2 Vector2::rotated(float p_by) const {
Vector2 v;
- v.set_rotation(atan2()+p_by);
+ v.set_rotation(angle()+p_by);
v*=length();
return v;
}
@@ -187,7 +187,6 @@ Vector2 Vector2::snapped(const Vector2& p_by) const {
Vector2 Vector2::clamped(real_t p_len) const {
- return *this;
real_t l = length();
Vector2 v = *this;
if (l>0 && p_len<l) {
diff --git a/core/math/math_2d.h b/core/math/math_2d.h
index 5e6cefd114..1171364671 100644
--- a/core/math/math_2d.h
+++ b/core/math/math_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -133,7 +133,7 @@ struct Vector2 {
bool operator<(const Vector2& p_vec2) const { return (x==p_vec2.x)?(y<p_vec2.y):(x<p_vec2.x); }
bool operator<=(const Vector2& p_vec2) const { return (x==p_vec2.x)?(y<=p_vec2.y):(x<=p_vec2.x); }
- real_t atan2() const;
+ real_t angle() const;
void set_rotation(float p_radians) {
diff --git a/core/math/math_defs.cpp b/core/math/math_defs.cpp
index 51aaa6800e..70963bd71d 100644
--- a/core/math/math_defs.cpp
+++ b/core/math/math_defs.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/math_defs.h b/core/math/math_defs.h
index 7cb6c7f499..eb85039ca3 100644
--- a/core/math/math_defs.h
+++ b/core/math/math_defs.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/math_funcs.cpp b/core/math/math_funcs.cpp
index 3c94ac5bc7..20d9db3375 100644
--- a/core/math/math_funcs.cpp
+++ b/core/math/math_funcs.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -207,9 +207,15 @@ double Math::ceil(double p_x) {
int Math::decimals(double p_step) {
int max=4;
+ double llimit = Math::pow(0.1,max);
+ double ulimit = 1.0-llimit;
int i=0;
- while( (p_step - Math::floor(p_step)) != 0.0 && max) {
-
+ while( max) {
+
+ float d = absf(p_step) - Math::floor(absf(p_step));
+
+ if (d<llimit || d>ulimit)
+ break;
p_step*=10.0;
max--;
i++;
diff --git a/core/math/math_funcs.h b/core/math/math_funcs.h
index 33175ed2fc..62890b0371 100644
--- a/core/math/math_funcs.h
+++ b/core/math/math_funcs.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -79,9 +79,9 @@ public:
return Math::log( p_linear ) * 8.6858896380650365530225783783321;
}
- static inline double db2linear(double p_linear) {
+ static inline double db2linear(double p_db) {
- return Math::exp( p_linear * 0.11512925464970228420089957273422 );
+ return Math::exp( p_db * 0.11512925464970228420089957273422 );
}
static bool is_nan(double p_val);
diff --git a/core/math/matrix3.cpp b/core/math/matrix3.cpp
index 10f1461fdc..f51da80a83 100644
--- a/core/math/matrix3.cpp
+++ b/core/math/matrix3.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/matrix3.h b/core/math/matrix3.h
index 98feb2dbbd..291934b8eb 100644
--- a/core/math/matrix3.h
+++ b/core/math/matrix3.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/octree.h b/core/math/octree.h
index 84de388178..b51c4bcba7 100644
--- a/core/math/octree.h
+++ b/core/math/octree.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/plane.cpp b/core/math/plane.cpp
index f9395a002a..d17ce01bec 100644
--- a/core/math/plane.cpp
+++ b/core/math/plane.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/plane.h b/core/math/plane.h
index 604b880266..d20e63dc47 100644
--- a/core/math/plane.h
+++ b/core/math/plane.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/quat.cpp b/core/math/quat.cpp
index e0c4b0793c..ebc5ec4e65 100644
--- a/core/math/quat.cpp
+++ b/core/math/quat.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/quat.h b/core/math/quat.h
index de4aedaeec..738b6946c7 100644
--- a/core/math/quat.h
+++ b/core/math/quat.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -73,7 +73,7 @@ public:
-x * v.x - y * v.y - z * v.z);
}
- _FORCE_INLINE_ Vector3 xform(const Vector3& v) {
+ _FORCE_INLINE_ Vector3 xform(const Vector3& v) const {
Quat q = *this * v;
q *= this->inverse();
diff --git a/core/math/quick_hull.cpp b/core/math/quick_hull.cpp
index 80ae0f04e1..956824d3d0 100644
--- a/core/math/quick_hull.cpp
+++ b/core/math/quick_hull.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/quick_hull.h b/core/math/quick_hull.h
index cb486a0b6f..8c009b907d 100644
--- a/core/math/quick_hull.h
+++ b/core/math/quick_hull.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/transform.cpp b/core/math/transform.cpp
index a6f4f626cc..8371f7e34b 100644
--- a/core/math/transform.cpp
+++ b/core/math/transform.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/transform.h b/core/math/transform.h
index a992843d70..bd1247084d 100644
--- a/core/math/transform.h
+++ b/core/math/transform.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/triangle_mesh.cpp b/core/math/triangle_mesh.cpp
index 70cb639fc2..adb9861092 100644
--- a/core/math/triangle_mesh.cpp
+++ b/core/math/triangle_mesh.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/triangle_mesh.h b/core/math/triangle_mesh.h
index 87d8ce8e6c..b5e8f79cde 100644
--- a/core/math/triangle_mesh.h
+++ b/core/math/triangle_mesh.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/triangulate.cpp b/core/math/triangulate.cpp
index b13e13c47d..27b7c86675 100644
--- a/core/math/triangulate.cpp
+++ b/core/math/triangulate.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/triangulate.h b/core/math/triangulate.h
index 927b7efb8d..7dcc91b2fd 100644
--- a/core/math/triangulate.h
+++ b/core/math/triangulate.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/vector3.cpp b/core/math/vector3.cpp
index a3877eb9ff..8afd73f482 100644
--- a/core/math/vector3.cpp
+++ b/core/math/vector3.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/math/vector3.h b/core/math/vector3.h
index d27b611379..528c4d37b3 100644
--- a/core/math/vector3.h
+++ b/core/math/vector3.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -40,11 +40,11 @@ struct Vector3 {
enum Axis {
AXIS_X,
AXIS_Y,
- AXIS_Z,
+ AXIS_Z,
};
union {
-
+
#ifdef USE_QUAD_VECTORS
struct {
@@ -52,7 +52,7 @@ struct Vector3 {
real_t y;
real_t z;
real_t _unused;
- };
+ };
real_t coord[4];
#else
@@ -61,18 +61,18 @@ struct Vector3 {
real_t y;
real_t z;
};
-
+
real_t coord[3];
#endif
};
_FORCE_INLINE_ const real_t& operator[](int p_axis) const {
-
+
return coord[p_axis];
}
_FORCE_INLINE_ real_t& operator[](int p_axis) {
-
+
return coord[p_axis];
}
@@ -84,7 +84,7 @@ struct Vector3 {
_FORCE_INLINE_ real_t length() const;
_FORCE_INLINE_ real_t length_squared() const;
-
+
_FORCE_INLINE_ void normalize();
_FORCE_INLINE_ Vector3 normalized() const;
_FORCE_INLINE_ Vector3 inverse() const;
@@ -107,6 +107,8 @@ struct Vector3 {
_FORCE_INLINE_ real_t dot(const Vector3& p_b) const;
_FORCE_INLINE_ Vector3 abs() const;
+ _FORCE_INLINE_ Vector3 floor() const;
+ _FORCE_INLINE_ Vector3 ceil() const;
_FORCE_INLINE_ real_t distance_to(const Vector3& p_b) const;
_FORCE_INLINE_ real_t distance_squared_to(const Vector3& p_b) const;
@@ -172,7 +174,17 @@ real_t Vector3::dot(const Vector3& p_b) const {
Vector3 Vector3::abs() const {
return Vector3( Math::abs(x), Math::abs(y), Math::abs(z) );
-}
+}
+
+Vector3 Vector3::floor() const {
+
+ return Vector3( Math::floor(x), Math::floor(y), Math::floor(z) );
+}
+
+Vector3 Vector3::ceil() const {
+
+ return Vector3( Math::ceil(x), Math::ceil(y), Math::ceil(z) );
+}
Vector3 Vector3::linear_interpolate(const Vector3& p_b,float p_t) const {
@@ -301,7 +313,7 @@ bool Vector3::operator<(const Vector3& p_v) const {
return y<p_v.y;
} else
return x<p_v.x;
-
+
}
bool Vector3::operator<=(const Vector3& p_v) const {
diff --git a/core/message_queue.cpp b/core/message_queue.cpp
index 489939ee65..c69021f4f0 100644
--- a/core/message_queue.cpp
+++ b/core/message_queue.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -28,7 +28,7 @@
/*************************************************************************/
#include "message_queue.h"
#include "globals.h"
-
+#include "script_language.h"
MessageQueue *MessageQueue::singleton=NULL;
MessageQueue *MessageQueue::get_singleton() {
@@ -36,26 +36,11 @@ MessageQueue *MessageQueue::get_singleton() {
return singleton;
}
-Error MessageQueue::push_call(ObjectID p_id, const StringName& p_method, VARIANT_ARG_DECLARE) {
+Error MessageQueue::push_call(ObjectID p_id,const StringName& p_method,const Variant** p_args,int p_argcount,bool p_show_error) {
_THREAD_SAFE_METHOD_
- uint8_t room_needed=sizeof(Message);
- int args=0;
- if (p_arg5.get_type()!=Variant::NIL)
- args=5;
- else if (p_arg4.get_type()!=Variant::NIL)
- args=4;
- else if (p_arg3.get_type()!=Variant::NIL)
- args=3;
- else if (p_arg2.get_type()!=Variant::NIL)
- args=2;
- else if (p_arg1.get_type()!=Variant::NIL)
- args=1;
- else
- args=0;
-
- room_needed+=sizeof(Variant)*args;
+ int room_needed=sizeof(Message)+sizeof(Variant)*p_argcount;
if ((buffer_end+room_needed) >= buffer_size) {
String type;
@@ -65,53 +50,43 @@ Error MessageQueue::push_call(ObjectID p_id, const StringName& p_method, VARIANT
statistics();
}
+
ERR_FAIL_COND_V( (buffer_end+room_needed) >= buffer_size , ERR_OUT_OF_MEMORY );
Message * msg = memnew_placement( &buffer[ buffer_end ], Message );
- msg->args=args;
+ msg->args=p_argcount;
msg->instance_ID=p_id;
msg->target=p_method;
msg->type=TYPE_CALL;
- buffer_end+=sizeof(Message);
+ if (p_show_error)
+ msg->type|=FLAG_SHOW_ERROR;
+ buffer_end+=sizeof(Message);
- if (args>=1) {
+ for(int i=0;i<p_argcount;i++) {
Variant * v = memnew_placement( &buffer[ buffer_end ], Variant );
buffer_end+=sizeof(Variant);
- *v=p_arg1;
- }
-
- if (args>=2) {
+ *v=*p_args[i];
- Variant * v = memnew_placement( &buffer[ buffer_end ], Variant );
- buffer_end+=sizeof(Variant);
- *v=p_arg2;
}
- if (args>=3) {
+ return OK;
+}
- Variant * v = memnew_placement( &buffer[ buffer_end ], Variant );
- buffer_end+=sizeof(Variant);
- *v=p_arg3;
+Error MessageQueue::push_call(ObjectID p_id, const StringName& p_method, VARIANT_ARG_DECLARE) {
- }
+ VARIANT_ARGPTRS;
- if (args>=4) {
+ int argc=0;
- Variant * v = memnew_placement( &buffer[ buffer_end ], Variant );
- buffer_end+=sizeof(Variant);
- *v=p_arg4;
+ for(int i=0;i<VARIANT_ARG_MAX;i++) {
+ if (argptr[i]->get_type()==Variant::NIL)
+ break;
+ argc++;
}
- if (args>=5) {
+ return push_call(p_id,p_method,argptr,argc,false);
- Variant * v = memnew_placement( &buffer[ buffer_end ], Variant );
- buffer_end+=sizeof(Variant);
- *v=p_arg5;
- }
-
-
- return OK;
}
Error MessageQueue::push_set(ObjectID p_id, const StringName& p_prop, const Variant& p_value) {
@@ -212,7 +187,7 @@ void MessageQueue::statistics() {
if (target!=NULL) {
- switch(message->type) {
+ switch(message->type&FLAG_MASK) {
case TYPE_CALL: {
@@ -251,7 +226,7 @@ void MessageQueue::statistics() {
read_pos+=sizeof(Message);
- if (message->type!=TYPE_NOTIFICATION)
+ if ((message->type&FLAG_MASK)!=TYPE_NOTIFICATION)
read_pos+=sizeof(Variant)*message->args;
}
@@ -322,6 +297,26 @@ int MessageQueue::get_max_buffer_usage() const {
return buffer_max_used;
}
+
+void MessageQueue::_call_function(Object* p_target, const StringName& p_func, const Variant *p_args, int p_argcount,bool p_show_error) {
+
+ const Variant **argptrs=NULL;
+ if (p_argcount) {
+ argptrs = (const Variant**)alloca(sizeof(Variant*)*p_argcount);
+ for(int i=0;i<p_argcount;i++) {
+ argptrs[i]=&p_args[i];
+ }
+ }
+
+ Variant::CallError ce;
+ p_target->call(p_func,argptrs,p_argcount,ce);
+ if (p_show_error && ce.error!=Variant::CallError::CALL_OK) {
+
+ ERR_PRINTS("Error calling deferred method: "+Variant::get_call_error_text(p_target,p_func,argptrs,p_argcount,ce));
+
+ }
+}
+
void MessageQueue::flush() {
@@ -347,7 +342,7 @@ void MessageQueue::flush() {
if (target!=NULL) {
- switch(message->type) {
+ switch(message->type&FLAG_MASK) {
case TYPE_CALL: {
Variant *args= (Variant*)(message+1);
@@ -355,12 +350,7 @@ void MessageQueue::flush() {
// messages don't expect a return value
- target->call( message->target,
- (message->args>=1) ? args[0] : Variant(),
- (message->args>=2) ? args[1] : Variant(),
- (message->args>=3) ? args[2] : Variant(),
- (message->args>=4) ? args[3] : Variant(),
- (message->args>=5) ? args[4] : Variant() );
+ _call_function(target,message->target,args,message->args,message->type&FLAG_SHOW_ERROR);
for(int i=0;i<message->args;i++) {
args[i].~Variant();
@@ -386,7 +376,7 @@ void MessageQueue::flush() {
}
uint32_t advance = sizeof(Message);
- if (message->type!=TYPE_NOTIFICATION)
+ if ((message->type&FLAG_MASK)!=TYPE_NOTIFICATION)
advance+=sizeof(Variant)*message->args;
message->~Message();
@@ -423,14 +413,14 @@ MessageQueue::~MessageQueue() {
Message *message = (Message*)&buffer[ read_pos ];
Variant *args= (Variant*)(message+1);
int argc = message->args;
- if (message->type!=TYPE_NOTIFICATION) {
+ if ((message->type&FLAG_MASK)!=TYPE_NOTIFICATION) {
for (int i=0;i<argc;i++)
args[i].~Variant();
}
message->~Message();
read_pos+=sizeof(Message);
- if (message->type!=TYPE_NOTIFICATION)
+ if ((message->type&FLAG_MASK)!=TYPE_NOTIFICATION)
read_pos+=sizeof(Variant)*message->args;
}
diff --git a/core/message_queue.h b/core/message_queue.h
index 5cee21847b..6a3ec79732 100644
--- a/core/message_queue.h
+++ b/core/message_queue.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -46,7 +46,10 @@ class MessageQueue {
enum {
TYPE_CALL,
TYPE_NOTIFICATION,
- TYPE_SET
+ TYPE_SET,
+ FLAG_SHOW_ERROR=1<<14,
+ FLAG_MASK=FLAG_SHOW_ERROR-1
+
};
struct Message {
@@ -65,12 +68,14 @@ class MessageQueue {
uint32_t buffer_max_used;
uint32_t buffer_size;
+ void _call_function(Object* p_target,const StringName& p_func,const Variant *p_args,int p_argcount,bool p_show_error);
static MessageQueue *singleton;
public:
static MessageQueue *get_singleton();
+ Error push_call(ObjectID p_id,const StringName& p_method,const Variant** p_args,int p_argcount,bool p_show_error=false);
Error push_call(ObjectID p_id, const StringName& p_method, VARIANT_ARG_LIST);
Error push_notification(ObjectID p_id, int p_notification);
Error push_set(ObjectID p_id, const StringName& p_prop, const Variant& p_value);
diff --git a/core/method_bind.cpp b/core/method_bind.cpp
index 3429e5f0af..b41fa33887 100644
--- a/core/method_bind.cpp
+++ b/core/method_bind.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -40,8 +40,8 @@ PropertyInfo MethodBind::get_argument_info(int p_argument) const {
PropertyInfo pi( get_argument_type(p_argument), name );
if ((pi.type==Variant::OBJECT) && name.find(":")!=-1) {
pi.hint=PROPERTY_HINT_RESOURCE_TYPE;
- pi.hint_string=name.get_slice(":",1);
- pi.name=name.get_slice(":",0);
+ pi.hint_string=name.get_slicec(':',1);
+ pi.name=name.get_slicec(':',0);
}
return pi;
diff --git a/core/method_bind.h b/core/method_bind.h
index 85c1084f80..4c2598e50c 100644
--- a/core/method_bind.h
+++ b/core/method_bind.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/multi_bucket_array.h b/core/multi_bucket_array.h
index d85c9de583..98033e40f6 100644
--- a/core/multi_bucket_array.h
+++ b/core/multi_bucket_array.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/object.cpp b/core/object.cpp
index 6bb7973cef..c92fc35b24 100644
--- a/core/object.cpp
+++ b/core/object.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -258,12 +258,15 @@ bool Object::_predelete() {
_predelete_ok=1;
notification(NOTIFICATION_PREDELETE,true);
+ if (_predelete_ok) {
+ _type_ptr=NULL; //must restore so destructors can access type ptr correctly
+ }
return _predelete_ok;
}
void Object::_postinitialize() {
-
+ _type_ptr=_get_type_namev();
_initialize_typev();
notification(NOTIFICATION_POSTINITIALIZE);
@@ -311,6 +314,7 @@ void Object::set(const StringName& p_name, const Variant& p_value, bool *r_valid
_edited=true;
#endif
+
if (script_instance) {
if (script_instance->set(p_name,p_value)) {
@@ -323,9 +327,9 @@ void Object::set(const StringName& p_name, const Variant& p_value, bool *r_valid
//try built-in setgetter
{
- if (ObjectTypeDB::set_property(this,p_name,p_value)) {
- if (r_valid)
- *r_valid=true;
+ if (ObjectTypeDB::set_property(this,p_name,p_value,r_valid)) {
+ //if (r_valid)
+ // *r_valid=true;
return;
}
}
@@ -508,17 +512,10 @@ Variant Object::_call_deferred_bind(const Variant** p_args, int p_argcount, Vari
r_error.error=Variant::CallError::CALL_OK;
- StringName signal = *p_args[0];
-
- Variant v[VARIANT_ARG_MAX];
-
-
- for(int i=0;i<MIN(5,p_argcount-1);i++) {
+ StringName method = *p_args[0];
- v[i]=*p_args[i+1];
- }
+ MessageQueue::get_singleton()->push_call(get_instance_ID(),method,&p_args[1],p_argcount-1);
- call_deferred(signal,v[0],v[1],v[2],v[3],v[4]);
return Variant();
}
@@ -835,6 +832,8 @@ void Object::call_multilevel(const StringName& p_name, VARIANT_ARG_DECLARE) {
Variant Object::call(const StringName& p_method,const Variant** p_args,int p_argcount,Variant::CallError &r_error) {
+ r_error.error=Variant::CallError::CALL_OK;
+
if (p_method==CoreStringNames::get_singleton()->_free) {
//free must be here, before anything, always ready
#ifdef DEBUG_ENABLED
@@ -967,7 +966,10 @@ void Object::set_script_instance(ScriptInstance *p_instance) {
script_instance=p_instance;
- script=p_instance->get_script().get_ref_ptr();
+ if (p_instance)
+ script=p_instance->get_script().get_ref_ptr();
+ else
+ script=RefPtr();
}
RefPtr Object::get_script() const {
@@ -1004,6 +1006,27 @@ Array Object::_get_property_list_bind() const {
return convert_property_list(&lpi);
}
+
+static Dictionary _get_dict_from_method(const MethodInfo &mi) {
+
+ Dictionary d;
+ d["name"]=mi.name;
+ d["args"]=convert_property_list(&mi.arguments);
+ Array da;
+ for(int i=0;i<mi.default_arguments.size();i++)
+ da.push_back(mi.default_arguments[i]);
+ d["default_args"]=da;
+ d["flags"]=mi.flags;
+ d["id"]=mi.id;
+ Dictionary r;
+ r["type"]=mi.return_val.type;
+ r["hint"]=mi.return_val.hint;
+ r["hint_string"]=mi.return_val.hint_string;
+ d["return_type"]=r;
+ return d;
+
+}
+
Array Object::_get_method_list_bind() const {
List<MethodInfo> ml;
@@ -1012,20 +1035,7 @@ Array Object::_get_method_list_bind() const {
for(List<MethodInfo>::Element *E=ml.front();E;E=E->next()) {
- Dictionary d;
- d["name"]=E->get().name;
- d["args"]=convert_property_list(&E->get().arguments);
- Array da;
- for(int i=0;i<E->get().default_arguments.size();i++)
- da.push_back(E->get().default_arguments[i]);
- d["default_args"]=da;
- d["flags"]=E->get().flags;
- d["id"]=E->get().id;
- Dictionary r;
- r["type"]=E->get().return_val.type;
- r["hint"]=E->get().return_val.hint;
- r["hint_string"]=E->get().return_val.hint_string;
- d["return_type"]=r;
+ Dictionary d = _get_dict_from_method(E->get());
//va.push_back(d);
ret.push_back(d);
}
@@ -1115,21 +1125,22 @@ Variant Object::_emit_signal(const Variant** p_args, int p_argcount, Variant::Ca
StringName signal = *p_args[0];
- Variant v[VARIANT_ARG_MAX];
+ const Variant**args=NULL;
- for(int i=0;i<MIN(5,p_argcount-1);i++) {
-
- v[i]=*p_args[i+1];
+ int argc=p_argcount-1;
+ if (argc) {
+ args=&p_args[1];
}
- emit_signal(signal,v[0],v[1],v[2],v[3],v[4]);
+ emit_signal(signal,args,argc);
+
return Variant();
-}
+}
-void Object::emit_signal(const StringName& p_name,VARIANT_ARG_DECLARE) {
+void Object::emit_signal(const StringName& p_name,const Variant** p_args,int p_argcount) {
if (_block_signals)
return; //no emit, signals blocked
@@ -1152,10 +1163,12 @@ void Object::emit_signal(const StringName& p_name,VARIANT_ARG_DECLARE) {
OBJ_DEBUG_LOCK
+ Vector<const Variant*> bind_mem;
+
+
for(int i=0;i<ssize;i++) {
const Connection &c = slot_map.getv(i).conn;
- VARIANT_ARGPTRS
Object *target;
#ifdef DEBUG_ENABLED
@@ -1166,21 +1179,37 @@ void Object::emit_signal(const StringName& p_name,VARIANT_ARG_DECLARE) {
#endif
- int bind_count=c.binds.size();
- int bind=0;
+ const Variant **args=p_args;
+ int argc=p_argcount;
- for(int i=0;bind < bind_count && i<VARIANT_ARG_MAX;i++) {
+ if (c.binds.size()) {
+ //handle binds
+ bind_mem.resize(p_argcount+c.binds.size());
- if (argptr[i]->get_type()==Variant::NIL) {
- argptr[i]=&c.binds[bind];
- bind++;
+ for(int j=0;j<p_argcount;j++) {
+ bind_mem[j]=p_args[j];
+ }
+ for(int j=0;j<c.binds.size();j++) {
+ bind_mem[p_argcount+j]=&c.binds[j];
}
+
+ args=bind_mem.ptr();
+ argc=bind_mem.size();
}
if (c.flags&CONNECT_DEFERRED) {
- MessageQueue::get_singleton()->push_call(target->get_instance_ID(),c.method,VARIANT_ARGPTRS_PASS);
+ MessageQueue::get_singleton()->push_call(target->get_instance_ID(),c.method,args,argc,true);
} else {
- target->call( c.method, VARIANT_ARGPTRS_PASS );
+ Variant::CallError ce;
+ target->call( c.method, args, argc,ce );
+ if (ce.error!=Variant::CallError::CALL_OK) {
+
+ if (ce.error==Variant::CallError::CALL_ERROR_INVALID_METHOD && !ObjectTypeDB::type_exists( target->get_type_name() ) ) {
+ //most likely object is not initialized yet, do not throw error.
+ } else {
+ ERR_PRINTS("Error calling method from signal '"+String(p_name)+"': "+Variant::get_call_error_text(target,c.method,args,argc,ce));
+ }
+ }
}
if (c.flags&CONNECT_ONESHOT) {
@@ -1193,57 +1222,29 @@ void Object::emit_signal(const StringName& p_name,VARIANT_ARG_DECLARE) {
}
-#if 0
-
- //old (deprecated and dangerous code)
- s->lock++;
- for( Map<Signal::Target,Signal::Slot>::Element *E = s->slot_map.front();E;E=E->next() ) {
- const Signal::Target& t = E->key();
- const Signal::Slot& s = E->get();
- const Connection &c = s.cE->get();
-
- VARIANT_ARGPTRS
+ while (!disconnect_data.empty()) {
- int bind_count=c.binds.size();
- int bind=0;
+ const _ObjectSignalDisconnectData &dd = disconnect_data.front()->get();
+ disconnect(dd.signal,dd.target,dd.method);
+ disconnect_data.pop_front();
+ }
- for(int i=0;bind < bind_count && i<VARIANT_ARG_MAX;i++) {
+}
- if (argptr[i]->get_type()==Variant::NIL) {
- argptr[i]=&c.binds[bind];
- bind++;
- }
- }
+void Object::emit_signal(const StringName& p_name,VARIANT_ARG_DECLARE) {
- if (c.flags&CONNECT_DEFERRED) {
- MessageQueue::get_singleton()->push_call(t._id,t.method,VARIANT_ARGPTRS_PASS);
- } else {
- Object *obj = ObjectDB::get_instance(t._id);
- ERR_CONTINUE(!obj); //yeah this should always be here
- obj->call( t.method, VARIANT_ARGPTRS_PASS );
- }
+ VARIANT_ARGPTRS;
- if (c.flags&CONNECT_ONESHOT) {
- _ObjectSignalDisconnectData dd;
- dd.signal=p_name;
- dd.target=ObjectDB::get_instance(t._id);
- dd.method=t.method;
- disconnect_data.push_back(dd);
- }
+ int argc=0;
+ for(int i=0;i<VARIANT_ARG_MAX;i++) {
+ if (argptr[i]->get_type()==Variant::NIL)
+ break;
+ argc++;
}
-
-
- s->lock--;
-#endif
- while (!disconnect_data.empty()) {
-
- const _ObjectSignalDisconnectData &dd = disconnect_data.front()->get();
- disconnect(dd.signal,dd.target,dd.method);
- disconnect_data.pop_front();
- }
+ emit_signal(p_name,argptr,argc);
}
@@ -1292,11 +1293,39 @@ void Object::_emit_signal(const StringName& p_name,const Array& p_pargs){
#endif
Array Object::_get_signal_list() const{
- return Array();
+ List<MethodInfo> signal_list;
+ get_signal_list(&signal_list);
+
+ Array ret;
+ for (List<MethodInfo>::Element *E=signal_list.front();E;E=E->next()) {
+
+ ret.push_back(_get_dict_from_method(E->get()));
+ }
+
+ return ret;
}
Array Object::_get_signal_connection_list(const String& p_signal) const{
- return Array();
+ List<Connection> conns;
+ get_all_signal_connections(&conns);
+
+ Array ret;
+
+ for (List<Connection>::Element *E=conns.front();E;E=E->next()) {
+
+ Connection &c=E->get();
+ Dictionary rc;
+ rc["signal"]=c.signal;
+ rc["method"]=c.method;
+ rc["source"]=c.source;
+ rc["target"]=c.target;
+ rc["binds"]=c.binds;
+ rc["flags"]=c.flags;
+ ret.push_back(rc);
+ }
+
+ return ret;
+
}
@@ -1398,6 +1427,10 @@ bool Object::is_connected(const StringName& p_signal, Object *p_to_object, const
bool signal_is_valid = ObjectTypeDB::has_signal(get_type_name(),p_signal);
if (signal_is_valid)
return false;
+
+ if (!script.is_null() && Ref<Script>(script)->has_script_signal(p_signal))
+ return false;
+
ERR_EXPLAIN("Nonexistent signal: "+p_signal);
ERR_FAIL_COND_V(!s,false);
}
@@ -1539,7 +1572,7 @@ void Object::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get","property"),&Object::_get_bind);
ObjectTypeDB::bind_method(_MD("get_property_list"),&Object::_get_property_list_bind);
ObjectTypeDB::bind_method(_MD("get_method_list"),&Object::_get_method_list_bind);
- ObjectTypeDB::bind_method(_MD("notification","what"),&Object::notification,DEFVAL(false));
+ ObjectTypeDB::bind_method(_MD("notification","what","reversed"),&Object::notification,DEFVAL(false));
ObjectTypeDB::bind_method(_MD("get_instance_ID"),&Object::get_instance_ID);
ObjectTypeDB::bind_method(_MD("set_script","script:Script"),&Object::set_script);
@@ -1602,11 +1635,12 @@ void Object::_bind_methods() {
ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"call_deferred",&Object::_call_deferred_bind,mi,defargs);
}
- ObjectTypeDB::bind_method(_MD("callv:var","method","arg_array"),&Object::callv);
+ ObjectTypeDB::bind_method(_MD("callv:Variant","method","arg_array"),&Object::callv);
- ObjectTypeDB::bind_method(_MD("has_method"),&Object::has_method);
+ ObjectTypeDB::bind_method(_MD("has_method","method"),&Object::has_method);
ObjectTypeDB::bind_method(_MD("get_signal_list"),&Object::_get_signal_list);
+ ObjectTypeDB::bind_method(_MD("get_signal_connection_list","signal"),&Object::_get_signal_connection_list);
ObjectTypeDB::bind_method(_MD("connect","signal","target:Object","method","binds","flags"),&Object::connect,DEFVAL(Array()),DEFVAL(0));
ObjectTypeDB::bind_method(_MD("disconnect","signal","target:Object","method"),&Object::disconnect);
@@ -1688,6 +1722,26 @@ void Object::get_translatable_strings(List<String> *p_strings) const {
}
+Variant::Type Object::get_static_property_type(const StringName& p_property, bool *r_valid) const {
+
+ bool valid;
+ Variant::Type t = ObjectTypeDB::get_property_type(get_type_name(),p_property,&valid);
+ if (valid) {
+ if (r_valid)
+ *r_valid=true;
+ return t;
+ }
+
+ if (get_script_instance()) {
+ return get_script_instance()->get_property_type(p_property,r_valid);
+ }
+ if (r_valid)
+ *r_valid=false;
+
+ return Variant::NIL;
+
+}
+
bool Object::is_queued_for_deletion() const {
return _is_queued_for_deletion;
}
@@ -1707,7 +1761,7 @@ bool Object::is_edited() const {
Object::Object() {
-
+ _type_ptr=NULL;
_block_signals=false;
_predelete_ok=0;
_instance_ID=0;
diff --git a/core/object.h b/core/object.h
index 9680af924a..dcebf9b2a2 100644
--- a/core/object.h
+++ b/core/object.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -49,7 +49,7 @@
enum PropertyHint {
PROPERTY_HINT_NONE, ///< no hint provided.
- PROPERTY_HINT_RANGE, ///< hint_text = "min,max,step"
+ PROPERTY_HINT_RANGE, ///< hint_text = "min,max,step,slider; //slider is optional"
PROPERTY_HINT_EXP_RANGE, ///< hint_text = "min,max,step", exponential edit
PROPERTY_HINT_ENUM, ///< hint_text= "val1,val2,val3,etc"
PROPERTY_HINT_EXP_EASING, /// exponential easing funciton (Math::ease)
@@ -58,12 +58,12 @@ enum PropertyHint {
PROPERTY_HINT_KEY_ACCEL, ///< hint_text= "length" (as integer)
PROPERTY_HINT_FLAGS, ///< hint_text= "flag1,flag2,etc" (as bit flags)
PROPERTY_HINT_ALL_FLAGS,
- PROPERTY_HINT_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,"
+ PROPERTY_HINT_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,"
PROPERTY_HINT_DIR, ///< a directort path must be passed
PROPERTY_HINT_GLOBAL_FILE, ///< a file path must be passed, hint_text (optionally) is a filter "*.png,*.wav,*.doc,"
PROPERTY_HINT_GLOBAL_DIR, ///< a directort path must be passed
PROPERTY_HINT_RESOURCE_TYPE, ///< a resource object type
- PROPERTY_HINT_MULTILINE_TEXT, ///< used for string properties that can contain multiple lines
+ PROPERTY_HINT_MULTILINE_TEXT, ///< used for string properties that can contain multiple lines
PROPERTY_HINT_COLOR_NO_ALPHA, ///< used for ignoring alpha component when editing a color
PROPERTY_HINT_IMAGE_COMPRESS_LOSSY,
PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS,
@@ -71,7 +71,7 @@ enum PropertyHint {
};
enum PropertyUsageFlags {
-
+
PROPERTY_USAGE_STORAGE=1,
PROPERTY_USAGE_EDITOR=2,
PROPERTY_USAGE_NETWORK=4,
@@ -82,7 +82,8 @@ enum PropertyUsageFlags {
PROPERTY_USAGE_BUNDLE=128, //used for optimized bundles
PROPERTY_USAGE_CATEGORY=256,
PROPERTY_USAGE_STORE_IF_NONZERO=512, //only store if nonzero
- PROPERTY_USAGE_NO_INSTANCE_STATE=1024,
+ PROPERTY_USAGE_STORE_IF_NONONE=1024, //only store if false
+ PROPERTY_USAGE_NO_INSTANCE_STATE=2048,
PROPERTY_USAGE_DEFAULT=PROPERTY_USAGE_STORAGE|PROPERTY_USAGE_EDITOR|PROPERTY_USAGE_NETWORK,
PROPERTY_USAGE_DEFAULT_INTL=PROPERTY_USAGE_STORAGE|PROPERTY_USAGE_EDITOR|PROPERTY_USAGE_NETWORK|PROPERTY_USAGE_INTERNATIONALIZED,
@@ -97,17 +98,19 @@ enum PropertyUsageFlags {
#define ADD_PROPERTYI( m_property, m_setter, m_getter, m_index ) ObjectTypeDB::add_property( get_type_static(), m_property, m_setter, m_getter, m_index )
#define ADD_PROPERTYNZ( m_property, m_setter, m_getter ) ObjectTypeDB::add_property( get_type_static(), (m_property).added_usage(PROPERTY_USAGE_STORE_IF_NONZERO), m_setter, m_getter )
#define ADD_PROPERTYINZ( m_property, m_setter, m_getter, m_index ) ObjectTypeDB::add_property( get_type_static(), (m_property).added_usage(PROPERTY_USAGE_STORE_IF_NONZERO), m_setter, m_getter, m_index )
+#define ADD_PROPERTYNO( m_property, m_setter, m_getter ) ObjectTypeDB::add_property( get_type_static(), (m_property).added_usage(PROPERTY_USAGE_STORE_IF_NONONE), m_setter, m_getter )
+#define ADD_PROPERTYINO( m_property, m_setter, m_getter, m_index ) ObjectTypeDB::add_property( get_type_static(), (m_property).added_usage(PROPERTY_USAGE_STORE_IF_NONONE), m_setter, m_getter, m_index )
struct PropertyInfo {
-
- Variant::Type type;
+
+ Variant::Type type;
String name;
PropertyHint hint;
- String hint_string;
+ String hint_string;
uint32_t usage;
_FORCE_INLINE_ PropertyInfo added_usage(int p_fl) const { PropertyInfo pi=*this; pi.usage|=p_fl; return pi; }
-
+
PropertyInfo() { type=Variant::NIL; hint=PROPERTY_HINT_NONE; usage = PROPERTY_USAGE_DEFAULT; }
PropertyInfo( Variant::Type p_type, const String p_name, PropertyHint p_hint=PROPERTY_HINT_NONE, const String& p_hint_string="",uint32_t p_usage=PROPERTY_USAGE_DEFAULT) {
type=p_type; name=p_name; hint=p_hint; hint_string=p_hint_string; usage=p_usage;
@@ -122,23 +125,23 @@ struct PropertyInfo {
Array convert_property_list(const List<PropertyInfo> * p_list);
struct MethodInfo {
-
+
String name;
List<PropertyInfo> arguments;
Vector<Variant> default_arguments;
PropertyInfo return_val;
uint32_t flags;
int id;
-
+
inline bool operator<(const MethodInfo& p_method) const { return id==p_method.id?(name < p_method.name):(id<p_method.id); }
-
+
MethodInfo();
MethodInfo(const String& p_name);
MethodInfo(const String& p_name, const PropertyInfo& p_param1);
MethodInfo(const String& p_name, const PropertyInfo& p_param1,const PropertyInfo& p_param2);
MethodInfo(const String& p_name, const PropertyInfo& p_param1,const PropertyInfo& p_param2,const PropertyInfo& p_param3);
MethodInfo(const String& p_name, const PropertyInfo& p_param1,const PropertyInfo& p_param2,const PropertyInfo& p_param3,const PropertyInfo& p_param4);
- MethodInfo(const String& p_name, const PropertyInfo& p_param1,const PropertyInfo& p_param2,const PropertyInfo& p_param3,const PropertyInfo& p_param4,const PropertyInfo& p_param5);
+ MethodInfo(const String& p_name, const PropertyInfo& p_param1,const PropertyInfo& p_param2,const PropertyInfo& p_param3,const PropertyInfo& p_param4,const PropertyInfo& p_param5);
MethodInfo(Variant::Type ret);
MethodInfo(Variant::Type ret,const String& p_name);
MethodInfo(Variant::Type ret,const String& p_name, const PropertyInfo& p_param1);
@@ -155,7 +158,7 @@ struct MethodInfo {
//return NULL;
/*
- the following is an uncomprehensible blob of hacks and workarounds to compensate for many of the fallencies in C++. As a plus, this macro pretty much alone defines the object model.
+ the following is an uncomprehensible blob of hacks and workarounds to compensate for many of the fallencies in C++. As a plus, this macro pretty much alone defines the object model.
*/
#define REVERSE_GET_PROPERTY_LIST \
@@ -179,10 +182,10 @@ public:\
virtual String get_type() const { \
return String(#m_type);\
}\
-virtual StringName get_type_name() const { \
+virtual const StringName* _get_type_namev() const { \
if (!_type_name)\
_type_name=get_type_static();\
- return _type_name;\
+ return &_type_name;\
}\
static _FORCE_INLINE_ void* get_type_ptr_static() { \
static int ptr;\
@@ -311,7 +314,7 @@ private:
class ScriptInstance;
typedef uint32_t ObjectID;
-class Object {
+class Object {
public:
enum ConnectFlags {
@@ -388,6 +391,8 @@ friend void postinitialize_handler(Object*);
ScriptInstance *script_instance;
RefPtr script;
Dictionary metadata;
+ mutable StringName _type_name;
+ mutable const StringName* _type_ptr;
void _add_user_signal(const String& p_name, const Array& p_pargs=Array());
bool _has_user_signal(const StringName& p_name) const;
@@ -399,7 +404,7 @@ friend void postinitialize_handler(Object*);
void property_list_changed_notify();
-protected:
+protected:
virtual bool _use_builtin_script() const { return false; }
virtual void _initialize_typev() { initialize_type(); }
@@ -407,14 +412,14 @@ protected:
virtual bool _getv(const StringName& p_name,Variant &r_property) const { return false; };
virtual void _get_property_listv(List<PropertyInfo> *p_list,bool p_reversed) const {};
virtual void _notificationv(int p_notification,bool p_reversed) {};
-
+
static String _get_category() { return ""; }
static void _bind_methods();
bool _set(const StringName& p_name,const Variant &p_property) { return false; };
bool _get(const StringName& p_name,Variant &r_property) const { return false; };
void _get_property_list(List<PropertyInfo> *p_list) const {};
void _notification(int p_notification) {};
-
+
_FORCE_INLINE_ static void (*_get_bind_methods())() {
return &Object::_bind_methods;
}
@@ -426,13 +431,13 @@ protected:
}
_FORCE_INLINE_ void (Object::* (_get_get_property_list() const))(List<PropertyInfo> *p_list) const{
return &Object::_get_property_list;
- }
+ }
_FORCE_INLINE_ void (Object::* (_get_notification() const))(int){
return &Object::_notification;
- }
+ }
static void get_valid_parents_static(List<String> *p_parents);
static void _get_valid_parents_static(List<String> *p_parents);
-
+
void cancel_delete();
@@ -445,7 +450,11 @@ protected:
Variant _call_deferred_bind(const Variant** p_args, int p_argcount, Variant::CallError& r_error);
-
+ virtual const StringName* _get_type_namev() const {
+ if (!_type_name)
+ _type_name=get_type_static();
+ return &_type_name;
+ }
DVector<String> _get_meta_list_bind() const;
Array _get_property_list_bind() const;
@@ -476,7 +485,7 @@ public:
void add_change_receptor( Object *p_receptor );
void remove_change_receptor( Object *p_receptor );
-
+
template<class T>
T *cast_to() {
@@ -491,7 +500,7 @@ public:
return NULL;
#endif
}
-
+
template<class T>
const T *cast_to() const {
@@ -508,11 +517,11 @@ public:
}
enum {
-
+
NOTIFICATION_POSTINITIALIZE=0,
NOTIFICATION_PREDELETE=1
};
-
+
/* TYPE API */
static void get_inheritance_list_static(List<String>* p_inheritance_list) { p_inheritance_list->push_back("Object"); }
@@ -523,12 +532,20 @@ public:
virtual String get_type() const { return "Object"; }
virtual String get_save_type() const { return get_type(); } //type stored when saving
- virtual StringName get_type_name() const { return StringName("Object"); }
+
+
+
virtual bool is_type(const String& p_type) const { return (p_type=="Object"); }
virtual bool is_type_ptr(void *p_ptr) const { return get_type_ptr_static()==p_ptr; }
+ _FORCE_INLINE_ const StringName& get_type_name() const {
+ if (!_type_ptr) {
+ return *_get_type_namev();
+ } else {
+ return *_type_ptr;
+ }
+ }
-
/* IAPI */
// void set(const String& p_name, const Variant& p_value);
// Variant get(const String& p_name) const;
@@ -537,7 +554,7 @@ public:
Variant get(const StringName& p_name, bool *r_valid=NULL) const;
void get_property_list(List<PropertyInfo> *p_list,bool p_reversed=false) const;
-
+
bool has_method(const StringName& p_method) const;
void get_method_list(List<MethodInfo> *p_list) const;
Variant callv(const StringName& p_method,const Array& p_args);
@@ -547,14 +564,14 @@ public:
Variant call(const StringName& p_name, VARIANT_ARG_LIST); // C++ helper
void call_multilevel(const StringName& p_name, VARIANT_ARG_LIST); // C++ helper
- void notification(int p_notification,bool p_reversed=false);
+ void notification(int p_notification,bool p_reversed=false);
//used mainly by script, get and set all INCLUDING string
virtual Variant getvar(const Variant& p_key, bool *r_valid=NULL) const;
virtual void setvar(const Variant& p_key, const Variant& p_value,bool *r_valid=NULL);
/* SCRIPT */
-
+
void set_script(const RefPtr& p_script);
RefPtr get_script() const;
@@ -576,6 +593,7 @@ public:
void add_user_signal(const MethodInfo& p_signal);
void emit_signal(const StringName& p_name,VARIANT_ARG_LIST);
+ void emit_signal(const StringName& p_name, const Variant** p_args, int p_argcount);
void get_signal_list(List<MethodInfo> *p_signals ) const;
void get_signal_connection_list(const StringName& p_signal,List<Connection> *p_connections) const;
void get_all_signal_connections(List<Connection> *p_connections) const;
@@ -589,6 +607,8 @@ public:
void set_block_signals(bool p_block);
bool is_blocking_signals() const;
+ Variant::Type get_static_property_type(const StringName& p_property,bool *r_valid=NULL) const;
+
virtual void get_translatable_strings(List<String> *p_strings) const;
virtual void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const;
@@ -597,14 +617,14 @@ public:
StringName tr(const StringName& p_message) const; //translate message (alternative)
bool _is_queued_for_deletion; // set to true by SceneTree::queue_delete()
- bool is_queued_for_deletion() const;
+ bool is_queued_for_deletion() const;
_FORCE_INLINE_ void set_message_translation(bool p_enable) { _can_translate=p_enable; }
_FORCE_INLINE_ bool can_translate_messages() const { return _can_translate; }
void clear_internal_resource_paths();
- Object();
+ Object();
virtual ~Object();
};
@@ -632,13 +652,13 @@ class ObjectDB {
static HashMap<Object*,ObjectID,ObjectPtrHash> instance_checks;
static uint32_t instance_counter;
-friend class Object;
+friend class Object;
friend void unregister_core_types();
static void cleanup();
static uint32_t add_instance(Object *p_object);
static void remove_instance(Object *p_object);
-public:
+public:
typedef void (*DebugFunc)(Object *p_obj);
diff --git a/core/object_type_db.cpp b/core/object_type_db.cpp
index a2cae50940..dd9304f1f9 100644
--- a/core/object_type_db.cpp
+++ b/core/object_type_db.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -205,7 +205,7 @@ ObjectTypeDB::TypeInfo::~TypeInfo() {
}
-bool ObjectTypeDB::is_type(const String &p_type,const String& p_inherits) {
+bool ObjectTypeDB::is_type(const StringName &p_type,const StringName& p_inherits) {
OBJTYPE_LOCK;
@@ -220,7 +220,7 @@ bool ObjectTypeDB::is_type(const String &p_type,const String& p_inherits) {
return false;
}
-void ObjectTypeDB::get_type_list( List<String> *p_types) {
+void ObjectTypeDB::get_type_list( List<StringName> *p_types) {
OBJTYPE_LOCK;
@@ -235,7 +235,7 @@ void ObjectTypeDB::get_type_list( List<String> *p_types) {
}
-void ObjectTypeDB::get_inheriters_from( const String& p_type,List<String> *p_types) {
+void ObjectTypeDB::get_inheriters_from( const StringName& p_type,List<StringName> *p_types) {
OBJTYPE_LOCK;
@@ -249,7 +249,7 @@ void ObjectTypeDB::get_inheriters_from( const String& p_type,List<String> *p_typ
}
-String ObjectTypeDB::type_inherits_from(const String& p_type) {
+StringName ObjectTypeDB::type_inherits_from(const StringName& p_type) {
OBJTYPE_LOCK;
@@ -258,7 +258,7 @@ String ObjectTypeDB::type_inherits_from(const String& p_type) {
return ti->inherits;
}
-bool ObjectTypeDB::type_exists(const String &p_type) {
+bool ObjectTypeDB::type_exists(const StringName &p_type) {
OBJTYPE_LOCK;
return types.has(p_type);
@@ -269,7 +269,7 @@ void ObjectTypeDB::add_compatibility_type(const StringName& p_type,const StringN
compat_types[p_type]=p_fallback;
}
-Object *ObjectTypeDB::instance(const String &p_type) {
+Object *ObjectTypeDB::instance(const StringName &p_type) {
TypeInfo *ti;
{
@@ -287,7 +287,7 @@ Object *ObjectTypeDB::instance(const String &p_type) {
return ti->creation_func();
}
-bool ObjectTypeDB::can_instance(const String &p_type) {
+bool ObjectTypeDB::can_instance(const StringName &p_type) {
OBJTYPE_LOCK;
@@ -612,6 +612,7 @@ void ObjectTypeDB::add_property(StringName p_type,const PropertyInfo& p_pinfo, c
psg._setptr=mb_set;
psg._getptr=mb_get;
psg.index=p_index;
+ psg.type=p_pinfo.type;
type->property_setget[p_pinfo.name]=psg;
@@ -634,7 +635,7 @@ void ObjectTypeDB::get_property_list(StringName p_type,List<PropertyInfo> *p_lis
}
}
-bool ObjectTypeDB::set_property(Object* p_object,const StringName& p_property, const Variant& p_value) {
+bool ObjectTypeDB::set_property(Object* p_object,const StringName& p_property, const Variant& p_value,bool *r_valid) {
TypeInfo *type=types.getptr(p_object->get_type_name());
@@ -643,24 +644,37 @@ bool ObjectTypeDB::set_property(Object* p_object,const StringName& p_property, c
const PropertySetGet *psg = check->property_setget.getptr(p_property);
if (psg) {
- if (!psg->setter)
+ if (!psg->setter) {
+ if (r_valid)
+ *r_valid=false;
return true; //return true but do nothing
+ }
+
+ Variant::CallError ce;
if (psg->index>=0) {
Variant index=psg->index;
const Variant* arg[2]={&index,&p_value};
- Variant::CallError ce;
- p_object->call(psg->setter,arg,2,ce);
+// p_object->call(psg->setter,arg,2,ce);
+ if (psg->_setptr) {
+ psg->_setptr->call(p_object,arg,2,ce);
+ } else {
+ p_object->call(psg->setter,arg,2,ce);
+ }
+
} else {
const Variant* arg[1]={&p_value};
- Variant::CallError ce;
if (psg->_setptr) {
psg->_setptr->call(p_object,arg,1,ce);
} else {
p_object->call(psg->setter,arg,1,ce);
}
}
+
+ if (r_valid)
+ *r_valid=ce.error==Variant::CallError::CALL_OK;
+
return true;
}
@@ -712,6 +726,29 @@ bool ObjectTypeDB::get_property(Object* p_object,const StringName& p_property, V
return false;
}
+Variant::Type ObjectTypeDB::get_property_type(const StringName& p_type, const StringName& p_property,bool *r_is_valid) {
+
+ TypeInfo *type=types.getptr(p_type);
+ TypeInfo *check=type;
+ while(check) {
+ const PropertySetGet *psg = check->property_setget.getptr(p_property);
+ if (psg) {
+
+ if (r_is_valid)
+ *r_is_valid=true;
+
+ return psg->type;
+ }
+
+ check=check->inherits_ptr;
+ }
+ if (r_is_valid)
+ *r_is_valid=false;
+
+ return Variant::NIL;
+
+}
+
void ObjectTypeDB::set_method_flags(StringName p_type,StringName p_method,int p_flags) {
@@ -740,6 +777,25 @@ bool ObjectTypeDB::has_method(StringName p_type,StringName p_method,bool p_no_in
}
+bool ObjectTypeDB::get_setter_and_type_for_property(const StringName& p_class, const StringName& p_prop, StringName& r_class, StringName& r_setter) {
+
+ TypeInfo *type=types.getptr(p_class);
+ TypeInfo *check=type;
+ while(check) {
+
+ if (check->property_setget.has(p_prop)) {
+ r_class=check->name;
+ r_setter=check->property_setget[p_prop].setter;
+ return true;
+ }
+
+ check=check->inherits_ptr;
+ }
+
+ return false;
+
+}
+
#ifdef DEBUG_METHODS_ENABLED
MethodBind* ObjectTypeDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind , const MethodDefinition &method_name, const Variant **p_defs, int p_defcount) {
StringName mdname=method_name.name;
diff --git a/core/object_type_db.h b/core/object_type_db.h
index 27c1506960..f6caf14be5 100644
--- a/core/object_type_db.h
+++ b/core/object_type_db.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -117,6 +117,7 @@ class ObjectTypeDB {
StringName getter;
MethodBind *_setptr;
MethodBind *_getptr;
+ Variant::Type type;
};
struct TypeInfo {
@@ -228,13 +229,13 @@ public:
T::register_custom_data_to_otdb();
}
- static void get_type_list( List<String> *p_types);
- static void get_inheriters_from( const String& p_type,List<String> *p_types);
- static String type_inherits_from(const String& p_type);
- static bool type_exists(const String &p_type);
- static bool is_type(const String &p_type,const String& p_inherits);
- static bool can_instance(const String &p_type);
- static Object *instance(const String &p_type);
+ static void get_type_list( List<StringName> *p_types);
+ static void get_inheriters_from( const StringName& p_type,List<StringName> *p_types);
+ static StringName type_inherits_from(const StringName& p_type);
+ static bool type_exists(const StringName &p_type);
+ static bool is_type(const StringName &p_type,const StringName& p_inherits);
+ static bool can_instance(const StringName &p_type);
+ static Object *instance(const StringName &p_type);
#if 0
template<class N, class M>
@@ -456,8 +457,9 @@ public:
static void add_property(StringName p_type,const PropertyInfo& p_pinfo, const StringName& p_setter, const StringName& p_getter, int p_index=-1);
static void get_property_list(StringName p_type,List<PropertyInfo> *p_list,bool p_no_inheritance=false);
- static bool set_property(Object* p_object,const StringName& p_property, const Variant& p_value);
+ static bool set_property(Object* p_object, const StringName& p_property, const Variant& p_value, bool *r_valid=NULL);
static bool get_property(Object* p_object,const StringName& p_property, Variant& r_value);
+ static Variant::Type get_property_type(const StringName& p_type, const StringName& p_property,bool *r_is_valid=NULL);
@@ -475,7 +477,9 @@ public:
static void get_integer_constant_list(const StringName& p_type, List<String> *p_constants, bool p_no_inheritance=false);
static int get_integer_constant(const StringName& p_type, const StringName &p_name, bool *p_success=NULL);
static StringName get_category(const StringName& p_node);
-
+
+ static bool get_setter_and_type_for_property(const StringName& p_class, const StringName& p_prop, StringName& r_class, StringName& r_setter);
+
static void set_type_enabled(StringName p_type,bool p_enable);
static bool is_type_enabled(StringName p_type);
diff --git a/core/os/SCsub b/core/os/SCsub
index c6ba1fa537..7b4a6acbc0 100644
--- a/core/os/SCsub
+++ b/core/os/SCsub
@@ -3,5 +3,3 @@ Import('env')
env.add_source_files(env.core_sources,"*.cpp")
Export('env')
-
-
diff --git a/core/os/copymem.cpp b/core/os/copymem.cpp
index 54baf1e232..234ca50b45 100644
--- a/core/os/copymem.cpp
+++ b/core/os/copymem.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/os/copymem.h b/core/os/copymem.h
index a5d640edbf..d7fc46aae4 100644
--- a/core/os/copymem.h
+++ b/core/os/copymem.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/os/dir_access.cpp b/core/os/dir_access.cpp
index d0baae5872..32d66a7408 100644
--- a/core/os/dir_access.cpp
+++ b/core/os/dir_access.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/os/dir_access.h b/core/os/dir_access.h
index 8bacc96c60..e97a065998 100644
--- a/core/os/dir_access.h
+++ b/core/os/dir_access.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/os/file_access.cpp b/core/os/file_access.cpp
index ef7efd27e1..d82d0b63c5 100644
--- a/core/os/file_access.cpp
+++ b/core/os/file_access.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/os/file_access.h b/core/os/file_access.h
index 8e34013796..51cf839117 100644
--- a/core/os/file_access.h
+++ b/core/os/file_access.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -78,6 +78,7 @@ public:
READ=1,
WRITE=2,
READ_WRITE=3,
+ WRITE_READ=7,
};
virtual void close()=0; ///< close a file
diff --git a/core/os/input.cpp b/core/os/input.cpp
index 2b939ede46..6e1e618d9a 100644
--- a/core/os/input.cpp
+++ b/core/os/input.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -53,8 +53,12 @@ void Input::_bind_methods() {
ObjectTypeDB::bind_method(_MD("is_mouse_button_pressed","button"),&Input::is_mouse_button_pressed);
ObjectTypeDB::bind_method(_MD("is_joy_button_pressed","device","button"),&Input::is_joy_button_pressed);
ObjectTypeDB::bind_method(_MD("is_action_pressed","action"),&Input::is_action_pressed);
+ ObjectTypeDB::bind_method(_MD("add_joy_mapping","mapping", "update_existing"),&Input::add_joy_mapping, DEFVAL(false));
+ ObjectTypeDB::bind_method(_MD("remove_joy_mapping","guid"),&Input::remove_joy_mapping);
+ ObjectTypeDB::bind_method(_MD("is_joy_known","device"),&Input::is_joy_known);
ObjectTypeDB::bind_method(_MD("get_joy_axis","device","axis"),&Input::get_joy_axis);
ObjectTypeDB::bind_method(_MD("get_joy_name","device"),&Input::get_joy_name);
+ ObjectTypeDB::bind_method(_MD("get_joy_guid","device"),&Input::get_joy_guid);
ObjectTypeDB::bind_method(_MD("get_accelerometer"),&Input::get_accelerometer);
//ObjectTypeDB::bind_method(_MD("get_mouse_pos"),&Input::get_mouse_pos); - this is not the function you want
ObjectTypeDB::bind_method(_MD("get_mouse_speed"),&Input::get_mouse_speed);
@@ -62,8 +66,9 @@ void Input::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_mouse_mode","mode"),&Input::set_mouse_mode);
ObjectTypeDB::bind_method(_MD("get_mouse_mode"),&Input::get_mouse_mode);
ObjectTypeDB::bind_method(_MD("warp_mouse_pos","to"),&Input::warp_mouse_pos);
- ObjectTypeDB::bind_method(_MD("action_press"),&Input::action_press);
- ObjectTypeDB::bind_method(_MD("action_release"),&Input::action_release);
+ ObjectTypeDB::bind_method(_MD("action_press","action"),&Input::action_press);
+ ObjectTypeDB::bind_method(_MD("action_release","action"),&Input::action_release);
+ ObjectTypeDB::bind_method(_MD("set_custom_mouse_cursor","image:Texture","hotspot"),&Input::set_custom_mouse_cursor,DEFVAL(Vector2()));
BIND_CONSTANT( MOUSE_MODE_VISIBLE );
BIND_CONSTANT( MOUSE_MODE_HIDDEN );
@@ -104,266 +109,3 @@ Input::Input() {
//////////////////////////////////////////////////////////
-
-void InputDefault::SpeedTrack::update(const Vector2& p_delta_p) {
-
- uint64_t tick = OS::get_singleton()->get_ticks_usec();
- uint32_t tdiff = tick-last_tick;
- float delta_t = tdiff / 1000000.0;
- last_tick=tick;
-
-
- accum+=p_delta_p;
- accum_t+=delta_t;
-
- if (accum_t>max_ref_frame*10)
- accum_t=max_ref_frame*10;
-
- while( accum_t>=min_ref_frame ) {
-
- float slice_t = min_ref_frame / accum_t;
- Vector2 slice = accum*slice_t;
- accum=accum-slice;
- accum_t-=min_ref_frame;
-
- speed=(slice/min_ref_frame).linear_interpolate(speed,min_ref_frame/max_ref_frame);
- }
-
-
-
-}
-
-void InputDefault::SpeedTrack::reset() {
- last_tick = OS::get_singleton()->get_ticks_usec();
- speed=Vector2();
- accum_t=0;
-}
-
-InputDefault::SpeedTrack::SpeedTrack() {
-
- min_ref_frame=0.1;
- max_ref_frame=0.3;
- reset();
-}
-
-bool InputDefault::is_key_pressed(int p_scancode) {
-
- _THREAD_SAFE_METHOD_
- return keys_pressed.has(p_scancode);
-}
-
-bool InputDefault::is_mouse_button_pressed(int p_button) {
-
- _THREAD_SAFE_METHOD_
- return (mouse_button_mask&(1<<p_button))!=0;
-}
-
-
-static int _combine_device(int p_value,int p_device) {
-
- return p_value|(p_device<<20);
-}
-
-bool InputDefault::is_joy_button_pressed(int p_device, int p_button) {
-
- _THREAD_SAFE_METHOD_
- return joy_buttons_pressed.has(_combine_device(p_button,p_device));
-}
-
-bool InputDefault::is_action_pressed(const StringName& p_action) {
-
- if (custom_action_press.has(p_action))
- return true; //simpler
-
- const List<InputEvent> *alist = InputMap::get_singleton()->get_action_list(p_action);
- if (!alist)
- return NULL;
-
-
- for (const List<InputEvent>::Element *E=alist->front();E;E=E->next()) {
-
-
- int device=E->get().device;
-
- switch(E->get().type) {
-
- case InputEvent::KEY: {
-
- const InputEventKey &iek=E->get().key;
- if ((keys_pressed.has(iek.scancode)))
- return true;
- } break;
- case InputEvent::MOUSE_BUTTON: {
-
- const InputEventMouseButton &iemb=E->get().mouse_button;
- if(mouse_button_mask&(1<<iemb.button_index))
- return true;
- } break;
- case InputEvent::JOYSTICK_BUTTON: {
-
- const InputEventJoystickButton &iejb=E->get().joy_button;
- int c = _combine_device(iejb.button_index,device);
- if (joy_buttons_pressed.has(c))
- return true;
- } break;
- }
- }
-
- return false;
-}
-
-float InputDefault::get_joy_axis(int p_device,int p_axis) {
-
- _THREAD_SAFE_METHOD_
- int c = _combine_device(p_axis,p_device);
- if (joy_axis.has(c)) {
- return joy_axis[c];
- } else {
- return 0;
- }
-}
-
-String InputDefault::get_joy_name(int p_idx) {
-
- _THREAD_SAFE_METHOD_
- return joy_names[p_idx];
-};
-
-void InputDefault::joy_connection_changed(int p_idx, bool p_connected, String p_name) {
-
- _THREAD_SAFE_METHOD_
- joy_names[p_idx] = p_connected ? p_name : "";
-
- emit_signal("joy_connection_changed", p_idx, p_connected);
-};
-
-Vector3 InputDefault::get_accelerometer() {
-
- _THREAD_SAFE_METHOD_
- return accelerometer;
-}
-
-void InputDefault::parse_input_event(const InputEvent& p_event) {
-
- _THREAD_SAFE_METHOD_
- switch(p_event.type) {
-
- case InputEvent::KEY: {
-
- if (p_event.key.echo)
- break;
- if (p_event.key.scancode==0)
- break;
-
- // print_line(p_event);
-
- if (p_event.key.pressed)
- keys_pressed.insert(p_event.key.scancode);
- else
- keys_pressed.erase(p_event.key.scancode);
- } break;
- case InputEvent::MOUSE_BUTTON: {
-
- if (p_event.mouse_button.doubleclick)
- break;
-
- if (p_event.mouse_button.pressed)
- mouse_button_mask|=(1<<p_event.mouse_button.button_index);
- else
- mouse_button_mask&=~(1<<p_event.mouse_button.button_index);
- } break;
- case InputEvent::JOYSTICK_BUTTON: {
-
- int c = _combine_device(p_event.joy_button.button_index,p_event.device);
-
- if (p_event.joy_button.pressed)
- joy_buttons_pressed.insert(c);
- else
- joy_buttons_pressed.erase(c);
- } break;
- case InputEvent::JOYSTICK_MOTION: {
- set_joy_axis(p_event.device, p_event.joy_motion.axis, p_event.joy_motion.axis_value);
- } break;
-
- }
-
- if (main_loop)
- main_loop->input_event(p_event);
-
-}
-
-void InputDefault::set_joy_axis(int p_device,int p_axis,float p_value) {
-
- _THREAD_SAFE_METHOD_
- int c = _combine_device(p_axis,p_device);
- joy_axis[c]=p_value;
-}
-
-void InputDefault::set_accelerometer(const Vector3& p_accel) {
-
- _THREAD_SAFE_METHOD_
-
- accelerometer=p_accel;
-
-}
-
-void InputDefault::set_main_loop(MainLoop *p_main_loop) {
- main_loop=p_main_loop;
-
-}
-
-void InputDefault::set_mouse_pos(const Point2& p_posf) {
-
- mouse_speed_track.update(p_posf-mouse_pos);
- mouse_pos=p_posf;
-}
-
-Point2 InputDefault::get_mouse_pos() const {
-
- return mouse_pos;
-}
-Point2 InputDefault::get_mouse_speed() const {
-
- return mouse_speed_track.speed;
-}
-
-int InputDefault::get_mouse_button_mask() const {
-
- return OS::get_singleton()->get_mouse_button_state();
-}
-
-void InputDefault::warp_mouse_pos(const Vector2& p_to) {
-
- OS::get_singleton()->warp_mouse_pos(p_to);
-}
-
-
-void InputDefault::iteration(float p_step) {
-
-
-}
-
-void InputDefault::action_press(const StringName& p_action) {
-
- if (custom_action_press.has(p_action)) {
-
- custom_action_press[p_action]++;
- } else {
- custom_action_press[p_action]=1;
- }
-}
-
-void InputDefault::action_release(const StringName& p_action){
-
- ERR_FAIL_COND(!custom_action_press.has(p_action));
- custom_action_press[p_action]--;
- if (custom_action_press[p_action]==0) {
- custom_action_press.erase(p_action);
- }
-}
-
-InputDefault::InputDefault() {
-
- mouse_button_mask=0;
- main_loop=NULL;
-}
diff --git a/core/os/input.h b/core/os/input.h
index ce14c2166e..2dd4496f26 100644
--- a/core/os/input.h
+++ b/core/os/input.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -62,8 +62,11 @@ public:
virtual float get_joy_axis(int p_device,int p_axis)=0;
virtual String get_joy_name(int p_idx)=0;
- virtual void joy_connection_changed(int p_idx, bool p_connected, String p_name)=0;
-
+ virtual void joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid)=0;
+ virtual void add_joy_mapping(String p_mapping, bool p_update_existing=false)=0;
+ virtual void remove_joy_mapping(String p_guid)=0;
+ virtual bool is_joy_known(int p_device)=0;
+ virtual String get_joy_guid(int p_device) const=0;
virtual Point2 get_mouse_pos() const=0;
virtual Point2 get_mouse_speed() const=0;
@@ -78,77 +81,15 @@ public:
void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const;
+ virtual bool is_emulating_touchscreen() const=0;
+
+ virtual void set_custom_mouse_cursor(const RES& p_cursor,const Vector2& p_hotspot=Vector2())=0;
+ virtual void set_mouse_in_window(bool p_in_window)=0;
Input();
};
VARIANT_ENUM_CAST(Input::MouseMode);
-class InputDefault : public Input {
-
- OBJ_TYPE( InputDefault, Input );
- _THREAD_SAFE_CLASS_
-
- int mouse_button_mask;
- Set<int> keys_pressed;
- Set<int> joy_buttons_pressed;
- Map<int,float> joy_axis;
- Map<StringName,int> custom_action_press;
- Map<int, String> joy_names;
- Vector3 accelerometer;
- Vector2 mouse_pos;
- MainLoop *main_loop;
-
- struct SpeedTrack {
-
- uint64_t last_tick;
- Vector2 speed;
- Vector2 accum;
- float accum_t;
- float min_ref_frame;
- float max_ref_frame;
-
- void update(const Vector2& p_delta_p);
- void reset();
- SpeedTrack();
- };
-
- SpeedTrack mouse_speed_track;
-
-public:
-
- virtual bool is_key_pressed(int p_scancode);
- virtual bool is_mouse_button_pressed(int p_button);
- virtual bool is_joy_button_pressed(int p_device, int p_button);
- virtual bool is_action_pressed(const StringName& p_action);
-
- virtual float get_joy_axis(int p_device,int p_axis);
- String get_joy_name(int p_idx);
- void joy_connection_changed(int p_idx, bool p_connected, String p_name);
-
- virtual Vector3 get_accelerometer();
-
- virtual Point2 get_mouse_pos() const;
- virtual Point2 get_mouse_speed() const;
- virtual int get_mouse_button_mask() const;
-
- virtual void warp_mouse_pos(const Vector2& p_to);
-
-
- void parse_input_event(const InputEvent& p_event);
- void set_accelerometer(const Vector3& p_accel);
- void set_joy_axis(int p_device,int p_axis,float p_value);
-
- void set_main_loop(MainLoop *main_loop);
- void set_mouse_pos(const Point2& p_posf);
-
- void action_press(const StringName& p_action);
- void action_release(const StringName& p_action);
-
- void iteration(float p_step);
-
- InputDefault();
-
-};
#endif // INPUT_H
diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp
index 2bd62927b0..2f39567a7e 100644
--- a/core/os/input_event.cpp
+++ b/core/os/input_event.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -156,6 +156,7 @@ bool InputEvent::is_pressed() const {
case MOUSE_BUTTON: return mouse_button.pressed;
case JOYSTICK_BUTTON: return joy_button.pressed;
case SCREEN_TOUCH: return screen_touch.pressed;
+ case JOYSTICK_MOTION: return InputMap::get_singleton()->event_is_joy_motion_action_pressed(*this);
case ACTION: return action.pressed;
default: {}
}
diff --git a/core/os/input_event.h b/core/os/input_event.h
index 4bb122ebc1..b601adc875 100644
--- a/core/os/input_event.h
+++ b/core/os/input_event.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -143,6 +143,9 @@ enum {
JOY_ANALOG_2_X = JOY_AXIS_4,
JOY_ANALOG_2_Y = JOY_AXIS_5,
+
+ JOY_ANALOG_L2 = JOY_AXIS_6,
+ JOY_ANALOG_R2 = JOY_AXIS_7,
};
diff --git a/core/os/keyboard.cpp b/core/os/keyboard.cpp
index 10e64c3961..633aa06a9a 100644
--- a/core/os/keyboard.cpp
+++ b/core/os/keyboard.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/os/keyboard.h b/core/os/keyboard.h
index eaf656dd4d..69e74d1252 100644
--- a/core/os/keyboard.h
+++ b/core/os/keyboard.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/os/main_loop.cpp b/core/os/main_loop.cpp
index b4c02ddbce..310bbaa3b8 100644
--- a/core/os/main_loop.cpp
+++ b/core/os/main_loop.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -45,7 +45,8 @@ void MainLoop::_bind_methods() {
BIND_VMETHOD( MethodInfo("_idle",PropertyInfo(Variant::REAL,"delta")) );
BIND_VMETHOD( MethodInfo("_finalize") );
-
+ BIND_CONSTANT(NOTIFICATION_WM_MOUSE_ENTER);
+ BIND_CONSTANT(NOTIFICATION_WM_MOUSE_EXIT);
BIND_CONSTANT(NOTIFICATION_WM_FOCUS_IN);
BIND_CONSTANT(NOTIFICATION_WM_FOCUS_OUT);
BIND_CONSTANT(NOTIFICATION_WM_QUIT_REQUEST);
diff --git a/core/os/main_loop.h b/core/os/main_loop.h
index bf9fe83a43..059624dbe4 100644
--- a/core/os/main_loop.h
+++ b/core/os/main_loop.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -47,6 +47,8 @@ protected:
public:
enum {
+ NOTIFICATION_WM_MOUSE_ENTER = 3,
+ NOTIFICATION_WM_MOUSE_EXIT = 4,
NOTIFICATION_WM_FOCUS_IN = 5,
NOTIFICATION_WM_FOCUS_OUT = 6,
NOTIFICATION_WM_QUIT_REQUEST = 7,
diff --git a/core/os/memory.cpp b/core/os/memory.cpp
index 1d9ac4e302..f7f8fef2b7 100644
--- a/core/os/memory.cpp
+++ b/core/os/memory.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/os/memory.h b/core/os/memory.h
index 0a35c93fdb..98b973bc06 100644
--- a/core/os/memory.h
+++ b/core/os/memory.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/os/memory_pool_dynamic.cpp b/core/os/memory_pool_dynamic.cpp
index d1c41aff84..6be8d0a36d 100644
--- a/core/os/memory_pool_dynamic.cpp
+++ b/core/os/memory_pool_dynamic.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/os/memory_pool_dynamic.h b/core/os/memory_pool_dynamic.h
index 00999ee24d..82149bcf5d 100644
--- a/core/os/memory_pool_dynamic.h
+++ b/core/os/memory_pool_dynamic.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/os/memory_pool_dynamic_prealloc.cpp b/core/os/memory_pool_dynamic_prealloc.cpp
index c7c25f32d1..f76c2a12b4 100644
--- a/core/os/memory_pool_dynamic_prealloc.cpp
+++ b/core/os/memory_pool_dynamic_prealloc.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/os/memory_pool_dynamic_prealloc.h b/core/os/memory_pool_dynamic_prealloc.h
index 3523079bac..d2256c0c98 100644
--- a/core/os/memory_pool_dynamic_prealloc.h
+++ b/core/os/memory_pool_dynamic_prealloc.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/os/memory_pool_dynamic_static.cpp b/core/os/memory_pool_dynamic_static.cpp
index 029ef450cd..894066708e 100644
--- a/core/os/memory_pool_dynamic_static.cpp
+++ b/core/os/memory_pool_dynamic_static.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/os/memory_pool_dynamic_static.h b/core/os/memory_pool_dynamic_static.h
index a870f3070c..6177c78de7 100644
--- a/core/os/memory_pool_dynamic_static.h
+++ b/core/os/memory_pool_dynamic_static.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/os/memory_pool_static.cpp b/core/os/memory_pool_static.cpp
index d3617eac73..321f4d989e 100644
--- a/core/os/memory_pool_static.cpp
+++ b/core/os/memory_pool_static.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/os/memory_pool_static.h b/core/os/memory_pool_static.h
index 40bd1aaf0e..2e11b7ded4 100644
--- a/core/os/memory_pool_static.h
+++ b/core/os/memory_pool_static.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/os/mutex.cpp b/core/os/mutex.cpp
index be984c080b..9b379009b9 100644
--- a/core/os/mutex.cpp
+++ b/core/os/mutex.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/os/mutex.h b/core/os/mutex.h
index ac6d36d635..f16375aa26 100644
--- a/core/os/mutex.h
+++ b/core/os/mutex.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/os/os.cpp b/core/os/os.cpp
index f292456079..e93038f854 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,7 +31,7 @@
#include <stdarg.h>
#include "dir_access.h"
#include "globals.h"
-
+#include "input.h"
OS* OS::singleton=NULL;
@@ -50,7 +50,9 @@ uint64_t OS::get_unix_time() const {
return 0;
};
-
+uint64_t OS::get_system_time_secs() const {
+ return 0;
+}
void OS::debug_break() {
// something
@@ -59,9 +61,16 @@ void OS::debug_break() {
void OS::print_error(const char* p_function,const char* p_file,int p_line,const char *p_code,const char*p_rationale,ErrorType p_type) {
+ const char* err_type;
+ switch(p_type) {
+ case ERR_ERROR: err_type="**ERROR**"; break;
+ case ERR_WARNING: err_type="**WARNING**"; break;
+ case ERR_SCRIPT: err_type="**SCRIPT ERROR**"; break;
+ }
+
if (p_rationale && *p_rationale)
- print("**ERROR**: %s\n ",p_rationale);
- print("**ERROR**: At: %s:%i:%s() - %s\n",p_file,p_line,p_function,p_code);
+ print("%s: %s\n ",err_type,p_rationale);
+ print("%s: At: %s:%i:%s() - %s\n",err_type,p_file,p_line,p_function,p_code);
}
void OS::print(const char* p_format, ...) {
@@ -103,6 +112,14 @@ float OS::get_target_fps() const {
return _target_fps;
}
+void OS::set_keep_screen_on(bool p_enabled) {
+ _keep_screen_on=p_enabled;
+}
+
+bool OS::is_keep_screen_on() const {
+ return _keep_screen_on;
+}
+
void OS::set_low_processor_usage_mode(bool p_enabled) {
low_processor_usage_mode=p_enabled;
@@ -361,7 +378,7 @@ Error OS::set_cwd(const String& p_cwd) {
bool OS::has_touchscreen_ui_hint() const {
//return false;
- return GLOBAL_DEF("display/emulate_touchscreen",false);
+ return Input::get_singleton() && Input::get_singleton()->is_emulating_touchscreen();
}
int OS::get_free_static_memory() const {
@@ -498,12 +515,20 @@ float OS::get_time_scale() const {
return _time_scale;
}
+bool OS::is_joy_known(int p_device) {
+ return true;
+}
+
+String OS::get_joy_guid(int p_device) const {
+ return "Default Joystick";
+}
OS::OS() {
last_error=NULL;
frames_drawn=0;
singleton=this;
ips=60;
+ _keep_screen_on=true; // set default value to true, because this had been true before godot 2.0.
low_processor_usage_mode=false;
_verbose_stdout=false;
_frame_delay=0;
@@ -514,6 +539,7 @@ OS::OS() {
_target_fps=0;
_render_thread_mode=RENDER_THREAD_SAFE;
_time_scale=1.0;
+ _pixel_snap=false;
Math::seed(1234567);
}
diff --git a/core/os/os.h b/core/os/os.h
index 0230a75ca0..bc3fad302a 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -46,6 +46,7 @@ class OS {
String _custom_level;
List<String> _cmdline;
int ips;
+ bool _keep_screen_on;
bool low_processor_usage_mode;
bool _verbose_stdout;
String _local_clipboard;
@@ -58,6 +59,7 @@ class OS {
float _fps;
int _target_fps;
float _time_scale;
+ bool _pixel_snap;
char *last_error;
@@ -74,7 +76,7 @@ public:
bool fullscreen;
bool resizable;
float get_aspect() const { return (float)width/(float)height; }
- VideoMode(int p_width=640,int p_height=480,bool p_fullscreen=false, bool p_resizable = true) {width=p_width; height=p_height; fullscreen=p_fullscreen; resizable = p_resizable; }
+ VideoMode(int p_width=1280,int p_height=720,bool p_fullscreen=false, bool p_resizable = true) {width=p_width; height=p_height; fullscreen=p_fullscreen; resizable = p_resizable; }
};
protected:
friend class Main;
@@ -155,7 +157,7 @@ public:
virtual int get_screen_count() const{ return 1; }
virtual int get_current_screen() const { return 0; }
virtual void set_current_screen(int p_screen) { }
- virtual Point2 get_screen_position(int p_screen=0) { return Point2(); }
+ virtual Point2 get_screen_position(int p_screen=0) const { return Point2(); }
virtual Size2 get_screen_size(int p_screen=0) const { return get_window_size(); }
virtual Point2 get_window_position() const { return Vector2(); }
virtual void set_window_position(const Point2& p_position) {}
@@ -179,10 +181,12 @@ public:
virtual float get_frames_per_second() const { return _fps; };
-
+ virtual void set_keep_screen_on(bool p_enabled);
+ virtual bool is_keep_screen_on() const;
virtual void set_low_processor_usage_mode(bool p_enabled);
virtual bool is_in_low_processor_usage_mode() const;
+ virtual String get_installed_templates_path() const { return ""; };
virtual String get_executable_path() const;
virtual Error execute(const String& p_path, const List<String>& p_arguments,bool p_blocking,ProcessID *r_child_id=NULL,String* r_pipe=NULL,int *r_exitcode=NULL)=0;
virtual Error kill(const ProcessID& p_pid)=0;
@@ -254,6 +258,7 @@ public:
virtual Time get_time(bool local=false) const=0;
virtual TimeZoneInfo get_time_zone_info() const=0;
virtual uint64_t get_unix_time() const;
+ virtual uint64_t get_system_time_secs() const;
virtual void delay_usec(uint32_t p_usec) const=0;
virtual uint64_t get_ticks_usec() const=0;
@@ -392,7 +397,10 @@ public:
void set_time_scale(float p_scale);
float get_time_scale() const;
+ _FORCE_INLINE_ bool get_use_pixel_snap() const { return _pixel_snap; }
+ virtual bool is_joy_known(int p_device);
+ virtual String get_joy_guid(int p_device)const;
OS();
virtual ~OS();
diff --git a/core/os/pc_joystick_map.h b/core/os/pc_joystick_map.h
index 111dc9b3a8..df123c5c1b 100644
--- a/core/os/pc_joystick_map.h
+++ b/core/os/pc_joystick_map.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/os/semaphore.cpp b/core/os/semaphore.cpp
index 8cb431d2cc..5fa2d339dc 100644
--- a/core/os/semaphore.cpp
+++ b/core/os/semaphore.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/os/semaphore.h b/core/os/semaphore.h
index e8ad9d3c3a..b65542ce35 100644
--- a/core/os/semaphore.h
+++ b/core/os/semaphore.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/os/shell.cpp b/core/os/shell.cpp
index 3746dc6804..8737d97fa0 100644
--- a/core/os/shell.cpp
+++ b/core/os/shell.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/os/shell.h b/core/os/shell.h
index 7ef5abbdef..805dd70301 100644
--- a/core/os/shell.h
+++ b/core/os/shell.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/os/thread.cpp b/core/os/thread.cpp
index 96b0f561ca..7fb1e969d4 100644
--- a/core/os/thread.cpp
+++ b/core/os/thread.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -58,6 +58,11 @@ void Thread::wait_to_finish(Thread *p_thread) {
}
+Error Thread::set_name(const String &p_name) {
+
+ return ERR_UNAVAILABLE;
+};
+
Thread::Thread()
{
}
diff --git a/core/os/thread.h b/core/os/thread.h
index 590fee1fc6..5711561809 100644
--- a/core/os/thread.h
+++ b/core/os/thread.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,6 +35,7 @@
@author Juan Linietsky <reduzio@gmail.com>
*/
+#include "ustring.h"
typedef void (*ThreadCreateCallback)(void *p_userdata);
@@ -71,7 +72,8 @@ protected:
Thread();
public:
-
+
+ virtual Error set_name(const String& p_name);
virtual ID get_ID() const=0;
diff --git a/core/os/thread_dummy.cpp b/core/os/thread_dummy.cpp
index 4e139f6379..30a0e2696c 100644
--- a/core/os/thread_dummy.cpp
+++ b/core/os/thread_dummy.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/os/thread_dummy.h b/core/os/thread_dummy.h
index a83e42ff98..800eef9ef9 100644
--- a/core/os/thread_dummy.h
+++ b/core/os/thread_dummy.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/os/thread_safe.cpp b/core/os/thread_safe.cpp
index 9a20db6a9d..f252190504 100644
--- a/core/os/thread_safe.cpp
+++ b/core/os/thread_safe.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/os/thread_safe.h b/core/os/thread_safe.h
index 62d2181279..793dd88543 100644
--- a/core/os/thread_safe.h
+++ b/core/os/thread_safe.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/packed_data_container.cpp b/core/packed_data_container.cpp
index fa17e93aa8..dd736502a3 100644
--- a/core/packed_data_container.cpp
+++ b/core/packed_data_container.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/packed_data_container.h b/core/packed_data_container.h
index f4152bbb4d..9183dcb90e 100644
--- a/core/packed_data_container.h
+++ b/core/packed_data_container.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/pair.cpp b/core/pair.cpp
index 17076bb379..14bb2d7775 100644
--- a/core/pair.cpp
+++ b/core/pair.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/pair.h b/core/pair.h
index 83fc837fff..9bffc37f49 100644
--- a/core/pair.h
+++ b/core/pair.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/path_db.cpp b/core/path_db.cpp
index d3dc3aceb8..d3521fcb23 100644
--- a/core/path_db.cpp
+++ b/core/path_db.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -286,6 +286,37 @@ NodePath::NodePath(const Vector<StringName>& p_path,const Vector<StringName>& p_
data->property=p_property;
}
+
+void NodePath::simplify() {
+
+ if (!data)
+ return;
+ for(int i=0;i<data->path.size();i++) {
+ if (data->path.size()==1)
+ break;
+ if (data->path[i].operator String()==".") {
+ data->path.remove(i);
+ i--;
+ } else if (data->path[i].operator String()==".." && i>0 && data->path[i-1].operator String()!="." && data->path[i-1].operator String()!="..") {
+ //remove both
+ data->path.remove(i-1);
+ data->path.remove(i-1);
+ i-=2;
+ if (data->path.size()==0) {
+ data->path.push_back(".");
+ break;
+ }
+ }
+ }
+}
+
+NodePath NodePath::simplified() const {
+
+ NodePath np=*this;
+ np.simplify();
+ return np;
+}
+
NodePath::NodePath(const String& p_path) {
data=NULL;
diff --git a/core/path_db.h b/core/path_db.h
index b4f13d50be..9c9be65d28 100644
--- a/core/path_db.h
+++ b/core/path_db.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -84,7 +84,10 @@ public:
bool operator==(const NodePath& p_path) const;
bool operator!=(const NodePath& p_path) const;
void operator=(const NodePath& p_path);
-
+
+ void simplify();
+ NodePath simplified() const;
+
NodePath(const Vector<StringName>& p_path,bool p_absolute,const String& p_property="");
NodePath(const Vector<StringName>& p_path,const Vector<StringName>& p_subpath,bool p_absolute,const String& p_property="");
NodePath(const NodePath& p_path);
diff --git a/core/path_remap.cpp b/core/path_remap.cpp
index 2ef39470a0..d4cb883f41 100644
--- a/core/path_remap.cpp
+++ b/core/path_remap.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/path_remap.h b/core/path_remap.h
index cb2a045668..66ebe7987b 100644
--- a/core/path_remap.h
+++ b/core/path_remap.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/pool_allocator.cpp b/core/pool_allocator.cpp
index d7dca45836..23be650fda 100644
--- a/core/pool_allocator.cpp
+++ b/core/pool_allocator.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/pool_allocator.h b/core/pool_allocator.h
index 4b0f931eb3..2c5920149b 100644
--- a/core/pool_allocator.h
+++ b/core/pool_allocator.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/print_string.cpp b/core/print_string.cpp
index a06d4de237..e364388b7b 100644
--- a/core/print_string.cpp
+++ b/core/print_string.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,6 +32,7 @@
static PrintHandlerList *print_handler_list=NULL;
bool _print_line_enabled=true;
+bool _print_error_enabled = true;
void add_print_handler(PrintHandlerList *p_handler) {
@@ -65,7 +66,7 @@ void remove_print_handler(PrintHandlerList *p_handler) {
l=l->next;
}
- OS::get_singleton()->print("print hanlder list is %p\n",print_handler_list);
+ OS::get_singleton()->print("print handler list is %p\n",print_handler_list);
ERR_FAIL_COND(l==NULL);
_global_unlock();
diff --git a/core/print_string.h b/core/print_string.h
index 854f8ec2e5..0aa5b4c8e9 100644
--- a/core/print_string.h
+++ b/core/print_string.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -52,6 +52,7 @@ void add_print_handler(PrintHandlerList *p_handler);
void remove_print_handler(PrintHandlerList *p_handler);
extern bool _print_line_enabled;
+extern bool _print_error_enabled;
extern void print_line(String p_string);
#endif
diff --git a/core/ref_ptr.cpp b/core/ref_ptr.cpp
index ddb8054e3b..dee2b9a164 100644
--- a/core/ref_ptr.cpp
+++ b/core/ref_ptr.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/ref_ptr.h b/core/ref_ptr.h
index d1ee6a3a7d..68788b73cd 100644
--- a/core/ref_ptr.h
+++ b/core/ref_ptr.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/reference.cpp b/core/reference.cpp
index 509e132b5a..90bafd0a9c 100644
--- a/core/reference.cpp
+++ b/core/reference.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/reference.h b/core/reference.h
index 65f31f78f3..8bfbf19ab6 100644
--- a/core/reference.h
+++ b/core/reference.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/register_core_types.cpp b/core/register_core_types.cpp
index 8754946bb1..d977ea3e18 100644
--- a/core/register_core_types.cpp
+++ b/core/register_core_types.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -101,10 +101,12 @@ void register_core_types() {
resource_loader_binary = memnew( ResourceFormatLoaderBinary );
ResourceLoader::add_resource_format_loader(resource_loader_binary);
+#ifdef XML_ENABLED
resource_saver_xml = memnew( ResourceFormatSaverXML );
ResourceSaver::add_resource_format_saver(resource_saver_xml);
resource_loader_xml = memnew( ResourceFormatLoaderXML );
ResourceLoader::add_resource_format_loader(resource_loader_xml);
+#endif
ObjectTypeDB::register_type<Object>();
diff --git a/core/register_core_types.h b/core/register_core_types.h
index a84849c969..239d67f1ec 100644
--- a/core/register_core_types.h
+++ b/core/register_core_types.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/res_ptr.cpp b/core/res_ptr.cpp
index fcff285e8f..11312b8021 100644
--- a/core/res_ptr.cpp
+++ b/core/res_ptr.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/res_ptr.h b/core/res_ptr.h
index 21f7fb6a2c..e1dc66b290 100644
--- a/core/res_ptr.h
+++ b/core/res_ptr.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/resource.cpp b/core/resource.cpp
index 6967599f96..e0706cf541 100644
--- a/core/resource.cpp
+++ b/core/resource.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -278,7 +278,7 @@ void Resource::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_import_metadata","metadata"),&Resource::set_import_metadata);
ObjectTypeDB::bind_method(_MD("get_import_metadata"),&Resource::get_import_metadata);
- ObjectTypeDB::bind_method(_MD("duplicate"),&Resource::duplicate,DEFVAL(false));
+ ObjectTypeDB::bind_method(_MD("duplicate","subresources"),&Resource::duplicate,DEFVAL(false));
ADD_SIGNAL( MethodInfo("changed") );
ADD_PROPERTY( PropertyInfo(Variant::STRING,"resource/path",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_EDITOR ), _SCS("set_path"),_SCS("get_path"));
ADD_PROPERTYNZ( PropertyInfo(Variant::STRING,"resource/name"), _SCS("set_name"),_SCS("get_name"));
diff --git a/core/resource.h b/core/resource.h
index 9d9c445e1d..f0c86631cc 100644
--- a/core/resource.h
+++ b/core/resource.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -130,7 +130,7 @@ public:
void set_name(const String& p_name);
String get_name() const;
- void set_path(const String& p_path,bool p_take_over=false);
+ virtual void set_path(const String& p_path,bool p_take_over=false);
String get_path() const;
void set_subindex(int p_sub_index);
@@ -144,7 +144,7 @@ public:
#ifdef TOOLS_ENABLED
- void set_last_modified_time(uint64_t p_time) { last_modified_time=p_time; }
+ virtual void set_last_modified_time(uint64_t p_time) { last_modified_time=p_time; }
uint64_t get_last_modified_time() const { return last_modified_time; }
#endif
diff --git a/core/rid.cpp b/core/rid.cpp
index 0870e6ab2d..219c2f0e69 100644
--- a/core/rid.cpp
+++ b/core/rid.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/rid.h b/core/rid.h
index e6582757ee..85ae1b15d3 100644
--- a/core/rid.h
+++ b/core/rid.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/ring_buffer.h b/core/ring_buffer.h
index de33de0c76..4658ec5e51 100644
--- a/core/ring_buffer.h
+++ b/core/ring_buffer.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -141,20 +141,26 @@ public:
inline int space_left() {
int left = read_pos - write_pos;
if (left < 0) {
- return size() + left;
+ return size() + left - 1;
};
if (left == 0) {
- return size();
+ return size()-1;
};
- return left;
+ return left -1;
};
inline int data_left() {
- return size() - space_left();
+ return size() - space_left() - 1;
};
inline int size() {
return data.size();
};
+
+ inline void clear() {
+ read_pos = 0;
+ write_pos = 0;
+
+ }
void resize(int p_power) {
int old_size = size();
diff --git a/core/safe_refcount.cpp b/core/safe_refcount.cpp
index afe2a4eb33..7718e466f2 100644
--- a/core/safe_refcount.cpp
+++ b/core/safe_refcount.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/safe_refcount.h b/core/safe_refcount.h
index 481b9fa7e9..e5dc854c23 100644
--- a/core/safe_refcount.h
+++ b/core/safe_refcount.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/script_debugger_debugger.cpp b/core/script_debugger_debugger.cpp
index 5c592a130c..71ad33f5ed 100644
--- a/core/script_debugger_debugger.cpp
+++ b/core/script_debugger_debugger.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/script_debugger_local.cpp b/core/script_debugger_local.cpp
index 2266b05f6d..3e442f7f59 100644
--- a/core/script_debugger_local.cpp
+++ b/core/script_debugger_local.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -60,7 +60,7 @@ void ScriptDebuggerLocal::debug(ScriptLanguage *p_script,bool p_can_continue) {
if (line.get_slice_count(" ")==1) {
print_line("*Frame "+itos(current_frame)+" - "+p_script->debug_get_stack_level_source(current_frame)+":"+itos(p_script->debug_get_stack_level_line(current_frame))+" in function '"+p_script->debug_get_stack_level_function(current_frame)+"'");
} else {
- int frame = line.get_slice(" ",1).to_int();
+ int frame = line.get_slicec(' ',1).to_int();
if (frame<0 || frame >=total_frames) {
print_line("Error: Invalid frame.");
} else {
@@ -108,7 +108,7 @@ void ScriptDebuggerLocal::debug(ScriptLanguage *p_script,bool p_can_continue) {
print_line("Usage: print <expre>");
} else {
- String expr = line.get_slice(" ",2);
+ String expr = line.get_slicec(' ',2);
String res = p_script->debug_parse_stack_level_expression(current_frame,expr);
print_line(res);
}
@@ -130,9 +130,9 @@ void ScriptDebuggerLocal::debug(ScriptLanguage *p_script,bool p_can_continue) {
} else {
- String bppos=line.get_slice(" ",1);
- String source=bppos.get_slice(":",0).strip_edges();
- int line=bppos.get_slice(":",1).strip_edges().to_int();
+ String bppos=line.get_slicec(' ',1);
+ String source=bppos.get_slicec(':',0).strip_edges();
+ int line=bppos.get_slicec(':',1).strip_edges().to_int();
source = breakpoint_find_source(source);
@@ -147,9 +147,9 @@ void ScriptDebuggerLocal::debug(ScriptLanguage *p_script,bool p_can_continue) {
clear_breakpoints();
} else {
- String bppos=line.get_slice(" ",1);
- String source=bppos.get_slice(":",0).strip_edges();
- int line=bppos.get_slice(":",1).strip_edges().to_int();
+ String bppos=line.get_slicec(' ',1);
+ String source=bppos.get_slicec(':',0).strip_edges();
+ int line=bppos.get_slicec(':',1).strip_edges().to_int();
source = breakpoint_find_source(source);
diff --git a/core/script_debugger_local.h b/core/script_debugger_local.h
index 45ff1d4466..4abacfc519 100644
--- a/core/script_debugger_local.h
+++ b/core/script_debugger_local.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp
index 33e9dc0fd9..b56ff4c0e1 100644
--- a/core/script_debugger_remote.cpp
+++ b/core/script_debugger_remote.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,11 +30,37 @@
#include "os/os.h"
#include "io/ip.h"
#include "globals.h"
+#include "os/input.h"
+void ScriptDebuggerRemote::_send_video_memory() {
+
+ List<ResourceUsage> usage;
+ if (resource_usage_func)
+ resource_usage_func(&usage);
+
+ usage.sort();
+
+ packet_peer_stream->put_var("message:video_mem");
+ packet_peer_stream->put_var(usage.size()*4);
+
+
+ for(List<ResourceUsage>::Element *E=usage.front();E;E=E->next()) {
+
+ packet_peer_stream->put_var(E->get().path);
+ packet_peer_stream->put_var(E->get().type);
+ packet_peer_stream->put_var(E->get().format);
+ packet_peer_stream->put_var(E->get().vram);
+ }
+
+}
Error ScriptDebuggerRemote::connect_to_host(const String& p_host,uint16_t p_port) {
- IP_Address ip = IP::get_singleton()->resolve_hostname(p_host);
+ IP_Address ip;
+ if (p_host.is_valid_ip_address())
+ ip=p_host;
+ else
+ ip = IP::get_singleton()->resolve_hostname(p_host);
int port = p_port;
@@ -109,6 +135,10 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script,bool p_can_continue) {
packet_peer_stream->put_var(p_can_continue);
packet_peer_stream->put_var(p_script->debug_get_error());
+ Input::MouseMode mouse_mode=Input::get_singleton()->get_mouse_mode();
+ if (mouse_mode!=Input::MOUSE_MODE_VISIBLE)
+ Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
+
while(true) {
@@ -127,7 +157,7 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script,bool p_can_continue) {
ERR_CONTINUE( cmd[0].get_type()!=Variant::STRING );
String command = cmd[0];
- cmd.remove(0);
+
if (command=="get_stack_dump") {
@@ -150,7 +180,7 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script,bool p_can_continue) {
} else if (command=="get_stack_frame_vars") {
-
+ cmd.remove(0);
ERR_CONTINUE( cmd.size()!=1 );
int lv = cmd[0];
@@ -243,6 +273,20 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script,bool p_can_continue) {
if (request_scene_tree)
request_scene_tree(request_scene_tree_ud);
+
+ } else if (command=="request_video_mem") {
+
+ _send_video_memory();
+ } else if (command=="breakpoint") {
+
+ bool set = cmd[3];
+ if (set)
+ insert_breakpoint(cmd[2],cmd[1]);
+ else
+ remove_breakpoint(cmd[2],cmd[1]);
+
+ } else {
+ _parse_live_edit(cmd);
}
@@ -256,6 +300,9 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script,bool p_can_continue) {
packet_peer_stream->put_var("debug_exit");
packet_peer_stream->put_var(0);
+ if (mouse_mode!=Input::MOUSE_MODE_VISIBLE)
+ Input::get_singleton()->set_mouse_mode(mouse_mode);
+
}
@@ -287,6 +334,37 @@ void ScriptDebuggerRemote::_get_output() {
messages.pop_front();
locking=false;
}
+
+ while (errors.size()) {
+ locking=true;
+ packet_peer_stream->put_var("error");
+ OutputError oe = errors.front()->get();
+
+ packet_peer_stream->put_var(oe.callstack.size()+2);
+
+ Array error_data;
+
+ error_data.push_back(oe.hr);
+ error_data.push_back(oe.min);
+ error_data.push_back(oe.sec);
+ error_data.push_back(oe.msec);
+ error_data.push_back(oe.source_func);
+ error_data.push_back(oe.source_file);
+ error_data.push_back(oe.source_line);
+ error_data.push_back(oe.error);
+ error_data.push_back(oe.error_descr);
+ error_data.push_back(oe.warning);
+ packet_peer_stream->put_var(error_data);
+ packet_peer_stream->put_var(oe.callstack.size());
+ for(int i=0;i<oe.callstack.size();i++) {
+ packet_peer_stream->put_var(oe.callstack[i]);
+
+ }
+
+ errors.pop_front();
+ locking=false;
+
+ }
mutex->unlock();
}
@@ -301,6 +379,160 @@ void ScriptDebuggerRemote::line_poll() {
}
+void ScriptDebuggerRemote::_err_handler(void* ud,const char* p_func,const char*p_file,int p_line,const char *p_err, const char * p_descr,ErrorHandlerType p_type) {
+
+ if (p_type==ERR_HANDLER_SCRIPT)
+ return; //ignore script errors, those go through debugger
+
+ ScriptDebuggerRemote *sdr = (ScriptDebuggerRemote*)ud;
+
+ OutputError oe;
+ oe.error=p_err;
+ oe.error_descr=p_descr;
+ oe.source_file=p_file;
+ oe.source_line=p_line;
+ oe.source_func=p_func;
+ oe.warning=p_type==ERR_HANDLER_WARNING;
+ uint64_t time = OS::get_singleton()->get_ticks_msec();
+ oe.hr=time/3600000;
+ oe.min=(time/60000)%60;
+ oe.sec=(time/1000)%60;
+ oe.msec=time%1000;
+ Array cstack;
+
+ Vector<ScriptLanguage::StackInfo> si;
+
+ for(int i=0;i<ScriptServer::get_language_count();i++) {
+ si=ScriptServer::get_language(i)->debug_get_current_stack_info();
+ if (si.size())
+ break;
+ }
+
+ cstack.resize(si.size()*2);
+ for(int i=0;i<si.size();i++) {
+ String path;
+ int line=0;
+ if (si[i].script.is_valid()) {
+ path=si[i].script->get_path();
+ line=si[i].line;
+ }
+ cstack[i*2+0]=path;
+ cstack[i*2+1]=line;
+ }
+
+ oe.callstack=cstack;
+
+
+ sdr->mutex->lock();
+
+ if (!sdr->locking && sdr->tcp_client->is_connected()) {
+
+ sdr->errors.push_back(oe);
+ }
+
+ sdr->mutex->unlock();
+}
+
+
+bool ScriptDebuggerRemote::_parse_live_edit(const Array& cmd) {
+
+ String cmdstr = cmd[0];
+ if (!live_edit_funcs || !cmdstr.begins_with("live_"))
+ return false;
+
+
+ //print_line(Variant(cmd).get_construct_string());
+ if (cmdstr=="live_set_root") {
+
+ if (!live_edit_funcs->root_func)
+ return true;
+ //print_line("root: "+Variant(cmd).get_construct_string());
+ live_edit_funcs->root_func(live_edit_funcs->udata,cmd[1],cmd[2]);
+
+ } else if (cmdstr=="live_node_path") {
+
+ if (!live_edit_funcs->node_path_func)
+ return true;
+ //print_line("path: "+Variant(cmd).get_construct_string());
+
+ live_edit_funcs->node_path_func(live_edit_funcs->udata,cmd[1],cmd[2]);
+
+ } else if (cmdstr=="live_res_path") {
+
+ if (!live_edit_funcs->res_path_func)
+ return true;
+ live_edit_funcs->res_path_func(live_edit_funcs->udata,cmd[1],cmd[2]);
+
+ } else if (cmdstr=="live_node_prop_res") {
+ if (!live_edit_funcs->node_set_res_func)
+ return true;
+
+ live_edit_funcs->node_set_res_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]);
+
+ } else if (cmdstr=="live_node_prop") {
+
+ if (!live_edit_funcs->node_set_func)
+ return true;
+ live_edit_funcs->node_set_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]);
+
+ } else if (cmdstr=="live_res_prop_res") {
+
+ if (!live_edit_funcs->res_set_res_func)
+ return true;
+ live_edit_funcs->res_set_res_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]);
+
+ } else if (cmdstr=="live_res_prop") {
+
+ if (!live_edit_funcs->res_set_func)
+ return true;
+ live_edit_funcs->res_set_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]);
+
+ } else if (cmdstr=="live_node_call") {
+
+ if (!live_edit_funcs->node_call_func)
+ return true;
+ live_edit_funcs->node_call_func(live_edit_funcs->udata,cmd[1],cmd[2], cmd[3],cmd[4],cmd[5],cmd[6],cmd[7]);
+
+ } else if (cmdstr=="live_res_call") {
+
+ if (!live_edit_funcs->res_call_func)
+ return true;
+ live_edit_funcs->res_call_func(live_edit_funcs->udata,cmd[1],cmd[2], cmd[3],cmd[4],cmd[5],cmd[6],cmd[7]);
+
+ } else if (cmdstr=="live_create_node") {
+
+ live_edit_funcs->tree_create_node_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]);
+
+ } else if (cmdstr=="live_instance_node") {
+
+ live_edit_funcs->tree_instance_node_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]);
+
+ } else if (cmdstr=="live_remove_node") {
+
+ live_edit_funcs->tree_remove_node_func(live_edit_funcs->udata,cmd[1]);
+
+ } else if (cmdstr=="live_remove_and_keep_node") {
+
+ live_edit_funcs->tree_remove_and_keep_node_func(live_edit_funcs->udata,cmd[1],cmd[2]);
+ } else if (cmdstr=="live_restore_node") {
+
+ live_edit_funcs->tree_restore_node_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3]);
+
+ } else if (cmdstr=="live_duplicate_node") {
+
+ live_edit_funcs->tree_duplicate_node_func(live_edit_funcs->udata,cmd[1],cmd[2]);
+ } else if (cmdstr=="live_reparent_node") {
+
+ live_edit_funcs->tree_reparent_node_func(live_edit_funcs->udata,cmd[1],cmd[2],cmd[3],cmd[4]);
+
+ } else {
+
+ return false;
+ }
+
+ return true;
+}
+
void ScriptDebuggerRemote::_poll_events() {
while(packet_peer_stream->get_available_packet_count()>0) {
@@ -321,7 +553,7 @@ void ScriptDebuggerRemote::_poll_events() {
ERR_CONTINUE( cmd[0].get_type()!=Variant::STRING );
String command = cmd[0];
- cmd.remove(0);
+ //cmd.remove(0);
if (command=="break") {
@@ -331,6 +563,18 @@ void ScriptDebuggerRemote::_poll_events() {
if (request_scene_tree)
request_scene_tree(request_scene_tree_ud);
+ } else if (command=="request_video_mem") {
+
+ _send_video_memory();
+ } else if (command=="breakpoint") {
+
+ bool set = cmd[3];
+ if (set)
+ insert_breakpoint(cmd[2],cmd[1]);
+ else
+ remove_breakpoint(cmd[2],cmd[1]);
+ } else {
+ _parse_live_edit(cmd);
}
}
@@ -394,10 +638,35 @@ void ScriptDebuggerRemote::_print_handler(void *p_this,const String& p_string) {
ScriptDebuggerRemote *sdr = (ScriptDebuggerRemote*)p_this;
+ uint64_t ticks = OS::get_singleton()->get_ticks_usec()/1000;
+ sdr->msec_count+=ticks-sdr->last_msec;
+ sdr->last_msec=ticks;
+
+ if (sdr->msec_count>1000) {
+ sdr->char_count=0;
+ sdr->msec_count=0;
+ }
+
+ String s = p_string;
+ int allowed_chars = MIN(MAX(sdr->max_cps - sdr->char_count,0), s.length());
+
+ if (allowed_chars==0)
+ return;
+
+ if (allowed_chars<s.length()) {
+ s=s.substr(0,allowed_chars);
+ }
+
+ sdr->char_count+=allowed_chars;
+
+ if (sdr->char_count>=sdr->max_cps) {
+ s+="\n[output overflow, print less text!]\n";
+ }
+
sdr->mutex->lock();
if (!sdr->locking && sdr->tcp_client->is_connected()) {
- sdr->output_strings .push_back(p_string);
+ sdr->output_strings.push_back(s);
}
sdr->mutex->unlock();
}
@@ -413,6 +682,13 @@ void ScriptDebuggerRemote::set_request_scene_tree_message_func(RequestSceneTreeM
request_scene_tree_ud=p_udata;
}
+void ScriptDebuggerRemote::set_live_edit_funcs(LiveEditFuncs *p_funcs) {
+
+ live_edit_funcs=p_funcs;
+}
+
+ScriptDebuggerRemote::ResourceUsageFunc ScriptDebuggerRemote::resource_usage_func=NULL;
+
ScriptDebuggerRemote::ScriptDebuggerRemote() {
tcp_client = StreamPeerTCP::create_ref();
@@ -429,13 +705,22 @@ ScriptDebuggerRemote::ScriptDebuggerRemote() {
last_perf_time=0;
poll_every=0;
request_scene_tree=NULL;
+ live_edit_funcs=NULL;
+ max_cps = GLOBAL_DEF("debug/max_remote_stdout_chars_per_second",2048);
+ char_count=0;
+ msec_count=0;
+ last_msec=0;
+
+ eh.errfunc=_err_handler;
+ eh.userdata=this;
+ add_error_handler(&eh);
}
ScriptDebuggerRemote::~ScriptDebuggerRemote() {
remove_print_handler(&phl);
+ remove_error_handler(&eh);
memdelete(mutex);
-
}
diff --git a/core/script_debugger_remote.h b/core/script_debugger_remote.h
index 89b9947c4b..f18e212236 100644
--- a/core/script_debugger_remote.h
+++ b/core/script_debugger_remote.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,6 +34,7 @@
#include "io/stream_peer_tcp.h"
#include "io/packet_peer.h"
#include "list.h"
+
class ScriptDebuggerRemote : public ScriptDebugger {
struct Message {
@@ -42,6 +43,8 @@ class ScriptDebuggerRemote : public ScriptDebugger {
Array data;
};
+
+
Ref<StreamPeerTCP> tcp_client;
Ref<PacketPeerStream> packet_peer_stream;
@@ -49,8 +52,31 @@ class ScriptDebuggerRemote : public ScriptDebugger {
Object *performance;
bool requested_quit;
Mutex *mutex;
+
+ struct OutputError {
+
+ int hr;
+ int min;
+ int sec;
+ int msec;
+ String source_file;
+ String source_func;
+ int source_line;
+ String error;
+ String error_descr;
+ bool warning;
+ Array callstack;
+
+ };
+
List<String> output_strings;
List<Message> messages;
+ List<OutputError> errors;
+
+ int max_cps;
+ int char_count;
+ uint64_t last_msec;
+ uint64_t msec_count;
bool locking; //hack to avoid a deadloop
static void _print_handler(void *p_this,const String& p_string);
@@ -62,12 +88,34 @@ class ScriptDebuggerRemote : public ScriptDebugger {
uint32_t poll_every;
+ bool _parse_live_edit(const Array &p_command);
+
RequestSceneTreeMessageFunc request_scene_tree;
void *request_scene_tree_ud;
+ void _send_video_memory();
+ LiveEditFuncs *live_edit_funcs;
+
+ ErrorHandlerList eh;
+ static void _err_handler(void*,const char*,const char*,int p_line,const char *, const char *,ErrorHandlerType p_type);
+
public:
+ struct ResourceUsage {
+
+ String path;
+ String format;
+ String type;
+ RID id;
+ int vram;
+ bool operator<(const ResourceUsage& p_img) const { return vram==p_img.vram ? id<p_img.id : vram > p_img.vram; }
+ };
+
+ typedef void (*ResourceUsageFunc)(List<ResourceUsage>*);
+
+ static ResourceUsageFunc resource_usage_func;
+
Error connect_to_host(const String& p_host,uint16_t p_port);
virtual void debug(ScriptLanguage *p_script,bool p_can_continue=true);
virtual void idle_poll();
@@ -79,6 +127,7 @@ public:
virtual void send_message(const String& p_message, const Array& p_args);
virtual void set_request_scene_tree_message_func(RequestSceneTreeMessageFunc p_func, void *p_udata);
+ virtual void set_live_edit_funcs(LiveEditFuncs *p_funcs);
ScriptDebuggerRemote();
~ScriptDebuggerRemote();
diff --git a/core/script_language.cpp b/core/script_language.cpp
index 68ac7d0ae7..2ce3844ba3 100644
--- a/core/script_language.cpp
+++ b/core/script_language.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -136,6 +136,14 @@ ScriptInstance::~ScriptInstance() {
}
+
+ScriptCodeCompletionCache *ScriptCodeCompletionCache::singleton=NULL;
+ScriptCodeCompletionCache::ScriptCodeCompletionCache() {
+ singleton=this;
+}
+
+
+
void ScriptLanguage::frame() {
@@ -259,6 +267,20 @@ void PlaceHolderScriptInstance::get_property_list(List<PropertyInfo> *p_properti
}
}
+Variant::Type PlaceHolderScriptInstance::get_property_type(const StringName& p_name,bool *r_is_valid) const {
+
+ if (values.has(p_name)) {
+ if (r_is_valid)
+ *r_is_valid=true;
+ return values[p_name].get_type();
+ }
+ if (r_is_valid)
+ *r_is_valid=false;
+
+ return Variant::NIL;
+}
+
+
void PlaceHolderScriptInstance::update(const List<PropertyInfo> &p_properties,const Map<StringName,Variant>& p_values) {
diff --git a/core/script_language.h b/core/script_language.h
index c1b906e251..3138c88e8e 100644
--- a/core/script_language.h
+++ b/core/script_language.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -82,6 +82,7 @@ public:
virtual StringName get_instance_base_type() const=0; // this may not work in all scripts, will return empty if so
virtual ScriptInstance* instance_create(Object *p_this)=0;
virtual bool instance_has(const Object *p_this) const=0;
+
virtual bool has_source_code() const=0;
virtual String get_source_code() const=0;
@@ -97,6 +98,7 @@ public:
virtual bool has_script_signal(const StringName& p_signal) const=0;
virtual void get_script_signal_list(List<MethodInfo> *r_signals) const=0;
+ virtual bool get_property_default_value(const StringName& p_property,Variant& r_value) const=0;
virtual void update_exports() {} //editor tool
@@ -109,6 +111,7 @@ public:
virtual bool set(const StringName& p_name, const Variant& p_value)=0;
virtual bool get(const StringName& p_name, Variant &r_ret) const=0;
virtual void get_property_list(List<PropertyInfo> *p_properties) const=0;
+ virtual Variant::Type get_property_type(const StringName& p_name,bool *r_is_valid=NULL) const=0;
virtual void get_method_list(List<MethodInfo> *p_list) const=0;
virtual bool has_method(const StringName& p_method) const=0;
@@ -126,6 +129,19 @@ public:
virtual ~ScriptInstance();
};
+class ScriptCodeCompletionCache {
+
+ static ScriptCodeCompletionCache *singleton;
+public:
+
+ virtual RES get_cached_resource(const String& p_path)=0;
+
+ static ScriptCodeCompletionCache* get_sigleton() { return singleton; }
+
+ ScriptCodeCompletionCache();
+
+};
+
class ScriptLanguage {
public:
@@ -150,6 +166,7 @@ public:
virtual String make_function(const String& p_class,const String& p_name,const StringArray& p_args) const=0;
virtual Error complete_code(const String& p_code, const String& p_base_path, Object*p_owner,List<String>* r_options,String& r_call_hint) { return ERR_UNAVAILABLE; }
virtual void auto_indent_code(String& p_code,int p_from_line,int p_to_line) const=0;
+ virtual void add_global_constant(const StringName& p_variable,const Variant& p_value)=0;
/* DEBUGGER FUNCTIONS */
@@ -163,6 +180,13 @@ public:
virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems=-1,int p_max_depth=-1)=0;
virtual String debug_parse_stack_level_expression(int p_level,const String& p_expression,int p_max_subitems=-1,int p_max_depth=-1)=0;
+ struct StackInfo {
+ Ref<Script> script;
+ int line;
+ };
+
+ virtual Vector<StackInfo> debug_get_current_stack_info() { return Vector<StackInfo>(); }
+
/* LOADER FUNCTIONS */
virtual void get_recognized_extensions(List<String> *p_extensions) const=0;
@@ -188,6 +212,7 @@ public:
virtual bool set(const StringName& p_name, const Variant& p_value);
virtual bool get(const StringName& p_name, Variant &r_ret) const;
virtual void get_property_list(List<PropertyInfo> *p_properties) const;
+ virtual Variant::Type get_property_type(const StringName& p_name,bool *r_is_valid=NULL) const;
virtual void get_method_list(List<MethodInfo> *p_list) const {}
virtual bool has_method(const StringName& p_method) const { return false; }
@@ -225,6 +250,32 @@ public:
typedef void (*RequestSceneTreeMessageFunc)(void *);
+ struct LiveEditFuncs {
+
+ void *udata;
+ void (*node_path_func)(void *,const NodePath &p_path,int p_id);
+ void (*res_path_func)(void *,const String &p_path,int p_id);
+
+ void (*node_set_func)(void *,int p_id,const StringName& p_prop,const Variant& p_value);
+ void (*node_set_res_func)(void *,int p_id,const StringName& p_prop,const String& p_value);
+ void (*node_call_func)(void *,int p_id,const StringName& p_method,VARIANT_ARG_DECLARE);
+ void (*res_set_func)(void *,int p_id,const StringName& p_prop,const Variant& p_value);
+ void (*res_set_res_func)(void *,int p_id,const StringName& p_prop,const String& p_value);
+ void (*res_call_func)(void *,int p_id,const StringName& p_method,VARIANT_ARG_DECLARE);
+ void (*root_func)(void*, const NodePath& p_scene_path,const String& p_scene_from);
+
+ void (*tree_create_node_func)(void*,const NodePath& p_parent,const String& p_type,const String& p_name);
+ void (*tree_instance_node_func)(void*,const NodePath& p_parent,const String& p_path,const String& p_name);
+ void (*tree_remove_node_func)(void*,const NodePath& p_at);
+ void (*tree_remove_and_keep_node_func)(void*,const NodePath& p_at,ObjectID p_keep_id);
+ void (*tree_restore_node_func)(void*,ObjectID p_id,const NodePath& p_at,int p_at_pos);
+ void (*tree_duplicate_node_func)(void*,const NodePath& p_at,const String& p_new_name);
+ void (*tree_reparent_node_func)(void*,const NodePath& p_at,const NodePath& p_new_place,const String& p_new_name,int p_at_pos);
+
+ };
+
+
+
_FORCE_INLINE_ static ScriptDebugger * get_singleton() { return singleton; }
void set_lines_left(int p_left);
int get_lines_left() const;
@@ -239,10 +290,12 @@ public:
bool is_breakpoint_line(int p_line) const;
void clear_breakpoints();
+
virtual void debug(ScriptLanguage *p_script,bool p_can_continue=true)=0;
virtual void idle_poll();
virtual void line_poll();
+
void set_break_language(ScriptLanguage *p_lang);
ScriptLanguage* get_break_language() const;
@@ -252,6 +305,7 @@ public:
virtual void request_quit() {}
virtual void set_request_scene_tree_message_func(RequestSceneTreeMessageFunc p_func, void *p_udata) {}
+ virtual void set_live_edit_funcs(LiveEditFuncs *p_funcs) {}
ScriptDebugger();
virtual ~ScriptDebugger() {singleton=NULL;}
diff --git a/core/self_list.h b/core/self_list.h
index b414baaba6..bfdcfbfbc2 100644
--- a/core/self_list.h
+++ b/core/self_list.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/set.h b/core/set.h
index 91c4e3f9c4..808ffe5b36 100644
--- a/core/set.h
+++ b/core/set.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/simple_type.h b/core/simple_type.h
index 84e08bf0b4..1cc597146e 100644
--- a/core/simple_type.h
+++ b/core/simple_type.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/sort.h b/core/sort.h
index 65664d0ed8..bd61921c8a 100644
--- a/core/sort.h
+++ b/core/sort.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/string_db.cpp b/core/string_db.cpp
index 57fdd6e70f..0e953cc326 100644
--- a/core/string_db.cpp
+++ b/core/string_db.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -158,7 +158,7 @@ void StringName::operator=(const StringName& p_name) {
_data = p_name._data;
}
}
-
+/* was inlined
StringName::operator String() const {
if (_data)
@@ -166,7 +166,7 @@ StringName::operator String() const {
return "";
}
-
+*/
StringName::StringName(const StringName& p_name) {
ERR_FAIL_COND(!configured);
diff --git a/core/string_db.h b/core/string_db.h
index 912d7513ad..f6c6ecefec 100644
--- a/core/string_db.h
+++ b/core/string_db.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -114,7 +114,17 @@ public:
}
bool operator!=(const StringName& p_name) const;
- operator String() const;
+ _FORCE_INLINE_ operator String() const {
+
+ if (_data) {
+ if (_data->cname )
+ return String(_data->cname);
+ else
+ return _data->name;
+ }
+
+ return String();
+ }
static StringName search(const char *p_name);
static StringName search(const CharType *p_name);
diff --git a/core/translation.cpp b/core/translation.cpp
index 8247cd1201..e4dad8d8de 100644
--- a/core/translation.cpp
+++ b/core/translation.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -626,7 +626,7 @@ bool TranslationServer::_load_translations(const String& p_from) {
for(int i=0;i<tcount;i++) {
- print_line( "Loading translation from " + r[i] );
+ //print_line( "Loading translation from " + r[i] );
Ref<Translation> tr = ResourceLoader::load(r[i]);
if (tr.is_valid())
add_translation(tr);
@@ -670,10 +670,10 @@ void TranslationServer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_locale","locale"),&TranslationServer::set_locale);
ObjectTypeDB::bind_method(_MD("get_locale"),&TranslationServer::get_locale);
- ObjectTypeDB::bind_method(_MD("translate"),&TranslationServer::translate);
+ ObjectTypeDB::bind_method(_MD("translate","message"),&TranslationServer::translate);
- ObjectTypeDB::bind_method(_MD("add_translation"),&TranslationServer::add_translation);
- ObjectTypeDB::bind_method(_MD("remove_translation"),&TranslationServer::remove_translation);
+ ObjectTypeDB::bind_method(_MD("add_translation","translation:Translation"),&TranslationServer::add_translation);
+ ObjectTypeDB::bind_method(_MD("remove_translation","translation:Translation"),&TranslationServer::remove_translation);
ObjectTypeDB::bind_method(_MD("clear"),&TranslationServer::clear);
diff --git a/core/translation.h b/core/translation.h
index 54118cd3b5..5be6b8913a 100644
--- a/core/translation.h
+++ b/core/translation.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/typedefs.h b/core/typedefs.h
index ae1eb1f5e7..1ca7a4f66d 100644
--- a/core/typedefs.h
+++ b/core/typedefs.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -41,8 +41,8 @@
#define _MKSTR(m_x) _STR(m_x)
#endif
// have to include version.h for this to work, include it in the .cpp not the .h
-#define VERSION_MKSTRING _MKSTR(VERSION_MAJOR)"."_MKSTR(VERSION_MINOR)"."_MKSTR(VERSION_STATUS)"."_MKSTR(VERSION_REVISION)
-#define VERSION_FULL_NAME _MKSTR(VERSION_NAME)" v"VERSION_MKSTRING
+#define VERSION_MKSTRING _MKSTR(VERSION_MAJOR)"." _MKSTR(VERSION_MINOR)"." _MKSTR(VERSION_STATUS)"." _MKSTR(VERSION_REVISION)
+#define VERSION_FULL_NAME _MKSTR(VERSION_NAME)" v" VERSION_MKSTRING
#ifndef _ALWAYS_INLINE_
@@ -197,10 +197,22 @@ static inline int get_shift_from_power_of_2( unsigned int p_pixel ) {
return -1;
}
+/** Swap 16 bits value for endianness */
+static inline uint16_t BSWAP16(uint16_t x) {
+ return (x>>8)|(x<<8);
+}
/** Swap 32 bits value for endianness */
static inline uint32_t BSWAP32(uint32_t x) {
return((x<<24)|((x<<8)&0x00FF0000)|((x>>8)&0x0000FF00)|(x>>24));
}
+/** Swap 64 bits value for endianness */
+
+static inline uint64_t BSWAP64(uint64_t x) {
+ x = (x & 0x00000000FFFFFFFF) << 32 | (x & 0xFFFFFFFF00000000) >> 32;
+ x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16;
+ x = (x & 0x00FF00FF00FF00FF) << 8 | (x & 0xFF00FF00FF00FF00) >> 8;
+ return x;
+}
/** When compiling with RTTI, we can add an "extra"
* layer of safeness in many operations, so dynamic_cast
diff --git a/core/undo_redo.cpp b/core/undo_redo.cpp
index f565070216..ecbda1d3fd 100644
--- a/core/undo_redo.cpp
+++ b/core/undo_redo.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -244,7 +244,12 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) {
Resource* res = obj->cast_to<Resource>();
if (res)
res->set_edited(true);
+
#endif
+
+ if (method_callback) {
+ method_callback(method_callbck_ud,obj,op.name,VARIANT_ARGS_FROM_ARRAY(op.args));
+ }
} break;
case Operation::TYPE_PROPERTY: {
@@ -254,6 +259,9 @@ void UndoRedo::_process_operation_list(List<Operation>::Element *E) {
if (res)
res->set_edited(true);
#endif
+ if (property_callback) {
+ property_callback(prop_callback_ud,obj,op.name,op.args[0]);
+ }
} break;
case Operation::TYPE_REFERENCE: {
//do nothing
@@ -325,6 +333,19 @@ void UndoRedo::set_commit_notify_callback(CommitNotifyCallback p_callback,void*
callback_ud=p_ud;
}
+void UndoRedo::set_method_notify_callback(MethodNotifyCallback p_method_callback,void* p_ud) {
+
+ method_callback=p_method_callback;
+ method_callbck_ud=p_ud;
+}
+
+void UndoRedo::set_property_notify_callback(PropertyNotifyCallback p_property_callback,void* p_ud){
+
+ property_callback=p_property_callback;
+ prop_callback_ud=p_ud;
+}
+
+
UndoRedo::UndoRedo() {
version=1;
@@ -334,6 +355,12 @@ UndoRedo::UndoRedo() {
merging=true;
callback=NULL;
callback_ud=NULL;
+
+ method_callbck_ud=NULL;
+ prop_callback_ud=NULL;
+ method_callback=NULL;
+ property_callback=NULL;
+
}
UndoRedo::~UndoRedo() {
@@ -455,8 +482,8 @@ void UndoRedo::_bind_methods() {
ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"add_undo_method",&UndoRedo::_add_undo_method,mi,defargs);
}
- ObjectTypeDB::bind_method(_MD("add_do_property","object", "property", "value:var"),&UndoRedo::add_do_property);
- ObjectTypeDB::bind_method(_MD("add_undo_property","object", "property", "value:var"),&UndoRedo::add_undo_property);
+ ObjectTypeDB::bind_method(_MD("add_do_property","object", "property", "value:Variant"),&UndoRedo::add_do_property);
+ ObjectTypeDB::bind_method(_MD("add_undo_property","object", "property", "value:Variant"),&UndoRedo::add_undo_property);
ObjectTypeDB::bind_method(_MD("add_do_reference","object"),&UndoRedo::add_do_reference);
ObjectTypeDB::bind_method(_MD("add_undo_reference","object"),&UndoRedo::add_undo_reference);
ObjectTypeDB::bind_method(_MD("clear_history"),&UndoRedo::clear_history);
diff --git a/core/undo_redo.h b/core/undo_redo.h
index a9187534c1..7f63ba9ed6 100644
--- a/core/undo_redo.h
+++ b/core/undo_redo.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -45,6 +45,9 @@ public:
Variant _add_do_method(const Variant** p_args, int p_argcount, Variant::CallError& r_error);
Variant _add_undo_method(const Variant** p_args, int p_argcount, Variant::CallError& r_error);
+ typedef void (*MethodNotifyCallback)(void *p_ud,Object*p_base,const StringName& p_name,VARIANT_ARG_DECLARE);
+ typedef void (*PropertyNotifyCallback)(void *p_ud,Object*p_base,const StringName& p_property,const Variant& p_value);
+
private:
struct Operation {
@@ -83,6 +86,11 @@ private:
CommitNotifyCallback callback;
void* callback_ud;
+ void* method_callbck_ud;
+ void* prop_callback_ud;
+
+ MethodNotifyCallback method_callback;
+ PropertyNotifyCallback property_callback;
protected:
@@ -113,6 +121,9 @@ public:
void set_commit_notify_callback(CommitNotifyCallback p_callback,void* p_ud);
+ void set_method_notify_callback(MethodNotifyCallback p_method_callback,void* p_ud);
+ void set_property_notify_callback(PropertyNotifyCallback p_property_callback,void* p_ud);
+
UndoRedo();
~UndoRedo();
};
diff --git a/core/ustring.cpp b/core/ustring.cpp
index 5df95ac4c2..ee750c39e5 100644
--- a/core/ustring.cpp
+++ b/core/ustring.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -44,6 +44,11 @@
#include <stdlib.h>
#include <stdio.h>
#endif
+
+#if defined(MINGW_ENABLED) || defined(_MSC_VER)
+#define snprintf _snprintf
+#endif
+
/** STRING **/
const char *CharString::get_data() const {
@@ -67,11 +72,14 @@ void String::copy_from(const char *p_cstr) {
return;
}
+
resize(len+1); // include 0
- for(int i=0;i<len+1;i++) {
-
- set(i,p_cstr[i]);
+ CharType *dst = this->ptr();
+
+ for (int i=0;i<len+1;i++) {
+
+ dst[i]=p_cstr[i];
}
}
@@ -486,7 +494,7 @@ String String::capitalize() const {
String cap;
for (int i=0;i<aux.get_slice_count(" ");i++) {
- String slice=aux.get_slice(" ",i);
+ String slice=aux.get_slicec(' ',i);
if (slice.length()>0) {
slice[0]=_find_upper(slice[0]);
@@ -577,6 +585,41 @@ String String::get_slice(String p_splitter, int p_slice) const {
}
+String String::get_slicec(CharType p_splitter, int p_slice) const {
+
+ if (empty())
+ return String();
+
+ if (p_slice<0)
+ return String();
+
+ const CharType *c=this->ptr();
+ int i=0;
+ int prev=0;
+ int count=0;
+ while(true) {
+
+
+ if (c[i]==0 || c[i]==p_splitter) {
+
+ if (p_slice==count) {
+
+ return substr(prev,i-prev);
+ } else {
+ count++;
+ prev=i+1;
+ }
+
+ }
+
+ i++;
+
+ }
+
+ return String(); //no find!
+
+}
+
Vector<String> String::split_spaces() const {
@@ -854,17 +897,8 @@ String String::num(double p_num,int p_decimals) {
}
char buf[256];
-#if defined(__GNUC__)
-#ifdef MINGW_ENABLED
- //snprintf is inexplicably broken in mingw
- //sprintf(buf,fmt,p_num);
- _snprintf(buf,256,fmt,p_num);
-#else
+#if defined(__GNUC__) || defined(_MSC_VER)
snprintf(buf,256,fmt,p_num);
-#endif
-
-#elif defined(_MSC_VER)
- _snprintf(buf,256,fmt,p_num);
#else
sprintf(buf,fmt,p_num);
#endif
@@ -1135,10 +1169,7 @@ String String::num_scientific(double p_num) {
char buf[256];
-#if defined(_MSC_VER) || defined(MINGW_ENABLED)
-
- _snprintf(buf,256,"%lg",p_num);
-#elif defined(__GNUC__)
+#if defined(__GNUC__) || defined(_MSC_VER)
snprintf(buf,256,"%lg",p_num);
#else
sprintf(buf,"%.16lg",p_num);
@@ -1605,12 +1636,16 @@ int64_t String::to_int64() const {
return integer*sign;
}
-int String::to_int(const char* p_str) {
+int String::to_int(const char* p_str,int p_len) {
int to=0;
- while(p_str[to]!=0 && p_str[to]!='.')
- to++;
+ if (p_len>=0)
+ to=p_len;
+ else {
+ while(p_str[to]!=0 && p_str[to]!='.')
+ to++;
+ }
int integer=0;
@@ -3010,6 +3045,83 @@ bool String::is_valid_identifier() const {
//kind of poor should be rewritten properly
+String String::world_wrap(int p_chars_per_line) const {
+
+ int from=0;
+ int last_space=0;
+ String ret;
+ for(int i=0;i<length();i++) {
+ if (i-from>=p_chars_per_line) {
+ if (last_space==-1) {
+ ret+=substr(from,i-from+1)+"\n";
+ } else {
+ ret+=substr(from,last_space-from)+"\n";
+ i=last_space; //rewind
+ }
+ from=i+1;
+ last_space=-1;
+ } else if (operator[](i)==' ' || operator[](i)=='\t') {
+ last_space=i;
+ } else if (operator[](i)=='\n') {
+ ret+=substr(from,i-from)+"\n";
+ from=i+1;
+ last_space=-1;
+ }
+ }
+
+ if (from<length()) {
+ ret+=substr(from,length());
+ }
+
+ return ret;
+}
+
+String String::http_escape() const {
+ const CharString temp = utf8();
+ String res;
+ for (int i = 0; i < length(); ++i) {
+ CharType ord = temp[i];
+ if (ord == '.' || ord == '-' || ord == '_' || ord == '~' ||
+ (ord >= 'a' && ord <= 'z') ||
+ (ord >= 'A' && ord <= 'Z') ||
+ (ord >= '0' && ord <= '9')) {
+ res += ord;
+ } else {
+ char h_Val[3];
+#if defined(__GNUC__) || defined(_MSC_VER)
+ snprintf(h_Val, 3, "%.2X", ord);
+#else
+ sprintf(h_Val, "%.2X", ord);
+#endif
+ res += "%";
+ res += h_Val;
+ }
+ }
+ return res;
+}
+
+String String::http_unescape() const {
+ String res;
+ for (int i = 0; i < length(); ++i) {
+ if (ord_at(i) == '%' && i+2 < length()) {
+ CharType ord1 = ord_at(i+1);
+ if ((ord1 >= '0' && ord1 <= '9') || (ord1 >= 'A' && ord1 <= 'Z')) {
+ CharType ord2 = ord_at(i+2);
+ if ((ord2 >= '0' && ord2 <= '9') || (ord2 >= 'A' && ord2 <= 'Z')) {
+ char bytes[2] = {ord1, ord2};
+ res += (char)strtol(bytes, NULL, 16);
+ i+=2;
+ }
+ } else {
+ res += ord_at(i);
+ }
+ } else {
+ res += ord_at(i);
+ }
+ }
+ return String::utf8(res.ascii());
+}
+
String String::c_unescape() const {
String escaped=*this;
@@ -3046,12 +3158,27 @@ String String::c_escape() const {
return escaped;
}
+String String::json_escape() const {
+
+ String escaped=*this;
+ escaped=escaped.replace("\\","\\\\");
+ escaped=escaped.replace("\b","\\b");
+ escaped=escaped.replace("\f","\\f");
+ escaped=escaped.replace("\n","\\n");
+ escaped=escaped.replace("\r","\\r");
+ escaped=escaped.replace("\t","\\t");
+ escaped=escaped.replace("\v","\\v");
+ escaped=escaped.replace("\"","\\\"");
+
+ return escaped;
+}
+
String String::xml_escape(bool p_escape_quotes) const {
String str=*this;
str=str.replace("&","&amp;");
- str=str.replace("<","&gt;");
- str=str.replace(">","&lt;");
+ str=str.replace("<","&lt;");
+ str=str.replace(">","&gt;");
if (p_escape_quotes) {
str=str.replace("'","&apos;");
str=str.replace("\"","&quot;");
@@ -3103,12 +3230,12 @@ static _FORCE_INLINE_ int _xml_unescape(const CharType *p_src,int p_src_len,Char
} else if (p_src_len>=4 && p_src[1]=='g' && p_src[2]=='t' && p_src[3]==';') {
if (p_dst)
- *p_dst='<';
+ *p_dst='>';
eat=4;
} else if (p_src_len>=4 && p_src[1]=='l' && p_src[2]=='t' && p_src[3]==';') {
if (p_dst)
- *p_dst='>';
+ *p_dst='<';
eat=4;
} else if (p_src_len>=5 && p_src[1]=='a' && p_src[2]=='m' && p_src[3]=='p' && p_src[4]==';') {
@@ -3333,8 +3460,8 @@ String String::path_to(const String& p_path) const {
//nothing
} else {
//dos style
- String src_begin=src.get_slice("/",0);
- String dst_begin=dst.get_slice("/",0);
+ String src_begin=src.get_slicec('/',0);
+ String dst_begin=dst.get_slicec('/',0);
if (src_begin!=dst_begin)
return p_path; //impossible to do this
diff --git a/core/ustring.h b/core/ustring.h
index 53ed319862..9276afa0f7 100644
--- a/core/ustring.h
+++ b/core/ustring.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -144,7 +144,7 @@ public:
int to_int() const;
int64_t to_int64() const;
- static int to_int(const char* p_str);
+ static int to_int(const char* p_str, int p_len=-1);
static double to_double(const char* p_str);
static double to_double(const CharType* p_str, const CharType **r_end=NULL);
static int64_t to_int(const CharType* p_str,int p_len=-1);
@@ -153,6 +153,7 @@ public:
int get_slice_count(String p_splitter) const;
String get_slice(String p_splitter,int p_slice) const;
+ String get_slicec(CharType splitter,int p_slice) const;
Vector<String> split(const String &p_splitter,bool p_allow_empty=true) const;
Vector<String> split_spaces() const;
@@ -206,8 +207,12 @@ public:
String xml_escape(bool p_escape_quotes=false) const;
String xml_unescape() const;
+ String http_escape() const;
+ String http_unescape() const;
String c_escape() const;
String c_unescape() const;
+ String json_escape() const;
+ String world_wrap(int p_chars_per_line) const;
String percent_encode() const;
String percent_decode() const;
diff --git a/core/variant.cpp b/core/variant.cpp
index 034dc2b4fc..3bd8d80528 100644
--- a/core/variant.cpp
+++ b/core/variant.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,7 +33,7 @@
#include "scene/gui/control.h"
#include "io/marshalls.h"
#include "core_string_names.h"
-
+#include "variant_parser.h"
String Variant::get_type_name(Variant::Type p_type) {
@@ -706,6 +706,17 @@ bool Variant::operator==(const Variant& p_variant) const {
}
+bool Variant::operator!=(const Variant& p_variant) const {
+
+ if (type!=p_variant.type) //evaluation of operator== needs to be more strict
+ return true;
+ bool v;
+ Variant r;
+ evaluate(OP_NOT_EQUAL,*this,p_variant,r,v);
+ return r;
+
+}
+
bool Variant::operator<(const Variant& p_variant) const {
if (type!=p_variant.type) //if types differ, then order by type first
return type<p_variant.type;
@@ -878,6 +889,63 @@ bool Variant::is_zero() const {
return false;
}
+
+bool Variant::is_one() const {
+
+ switch( type ) {
+ case NIL: {
+
+ return true;
+ } break;
+
+ // atomic types
+ case BOOL: {
+
+ return _data._bool==true;
+ } break;
+ case INT: {
+
+ return _data._int==1;
+
+ } break;
+ case REAL: {
+
+ return _data._real==1;
+
+ } break;
+ case VECTOR2: {
+
+ return *reinterpret_cast<const Vector2*>(_data._mem)==Vector2(1,1);
+
+ } break;
+ case RECT2: {
+
+ return *reinterpret_cast<const Rect2*>(_data._mem)==Rect2(1,1,1,1);
+
+ } break;
+ case VECTOR3: {
+
+ return *reinterpret_cast<const Vector3*>(_data._mem)==Vector3(1,1,1);
+
+ } break;
+ case PLANE: {
+
+ return *reinterpret_cast<const Plane*>(_data._mem)==Plane(1,1,1,1);
+
+ } break;
+ case COLOR: {
+
+ return *reinterpret_cast<const Color*>(_data._mem)==Color(1,1,1,1);
+
+ } break;
+
+ default: { return !is_zero(); }
+ }
+
+ return false;
+}
+
+
void Variant::reference(const Variant& p_variant) {
@@ -1535,9 +1603,17 @@ Variant::operator String() const {
} break;
case OBJECT: {
- if (_get_obj().obj)
+ if (_get_obj().obj) {
+ #ifdef DEBUG_ENABLED
+ if (ScriptDebugger::get_singleton() && _get_obj().ref.is_null()) {
+ //only if debugging!
+ if (!ObjectDB::instance_validate(_get_obj().obj)) {
+ return "[Deleted Object]";
+ };
+ };
+ #endif
return "["+_get_obj().obj->get_type()+":"+itos(_get_obj().obj->get_instance_ID())+"]";
- else
+ } else
return "[Object:null]";
} break;
@@ -2908,132 +2984,40 @@ void Variant::construct_from_string(const String& p_string,Variant& r_value,Obje
}
-String Variant::get_construct_string(ObjectDeConstruct p_obj_deconstruct,void *p_deconstruct_ud) const {
-
- switch( type ) {
-
- case NIL: return "null";
- case BOOL: return _data._bool ? "true" : "false";
- case INT: return String::num(_data._int);
- case REAL: return String::num(_data._real);
- case STRING: return "\""+reinterpret_cast<const String*>(_data._mem)->c_escape()+"\"";
- case VECTOR2: return "Vector2("+operator Vector2()+")";
- case RECT2: return "Rect2("+operator Rect2()+")";
- case MATRIX32: return "Matrix32("+operator Matrix32()+")";
- case VECTOR3: return "Vector3("+operator Vector3()+")";
- case PLANE: return "Plane("+operator Plane()+")";
- //case QUAT:
- case _AABB: return "AABB("+operator AABB()+")";
- case QUAT: return "Quat("+operator Quat()+")";
- case MATRIX3: return "Matrix3("+operator Matrix3()+")";
- case TRANSFORM: return "Transform("+operator Transform()+")";
- case NODE_PATH: return "@\""+String(operator NodePath()).c_escape()+"\"";
- case INPUT_EVENT: return "InputEvent()";
- case COLOR: return "Color("+String::num( operator Color().r)+","+String::num( operator Color().g)+","+String::num( operator Color().b)+","+String::num( operator Color().a)+")" ;
- case DICTIONARY: {
-
- const Dictionary &d =*reinterpret_cast<const Dictionary*>(_data._mem);
- //const String *K=NULL;
- String str="{";
- List<Variant> keys;
- d.get_key_list(&keys);
-
- Vector<_VariantStrPair> pairs;
-
- for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
-
- _VariantStrPair sp;
- sp.key=E->get().get_construct_string(p_obj_deconstruct,p_deconstruct_ud);
- sp.value=d[E->get()].get_construct_string(p_obj_deconstruct,p_deconstruct_ud);
- pairs.push_back(sp);
- }
-
- pairs.sort();
-
- for(int i=0;i<pairs.size();i++) {
- if (i>0)
- str+=", ";
- str+="("+pairs[i].key+":"+pairs[i].value+")";
- }
- str+="}";
+String Variant::get_construct_string() const {
- return str;
- } break;
- case VECTOR3_ARRAY: {
-
- DVector<Vector3> vec = operator DVector<Vector3>();
- String str="Vector3Array([";
- for(int i=0;i<vec.size();i++) {
-
- if (i>0)
- str+=", ";
- str+=Variant( vec[i] ).get_construct_string();
- }
- return str+"])";
- } break;
- case STRING_ARRAY: {
-
- DVector<String> vec = operator DVector<String>();
- String str="StringArray([";
- for(int i=0;i<vec.size();i++) {
-
- if (i>0)
- str+=", ";
- str=str+=Variant( vec[i] ).get_construct_string();
- }
- return str+"])";
- } break;
- case INT_ARRAY: {
+ String vars;
+ VariantWriter::write_to_string(*this,vars);
- DVector<int> vec = operator DVector<int>();
- String str="IntArray([";
- for(int i=0;i<vec.size();i++) {
+ return vars;
- if (i>0)
- str+=", ";
- str=str+itos(vec[i]);
- }
- return str+"])";
- } break;
- case REAL_ARRAY: {
+}
- DVector<real_t> vec = operator DVector<real_t>();
- String str="FloatArray([";
- for(int i=0;i<vec.size();i++) {
+String Variant::get_call_error_text(Object* p_base, const StringName& p_method,const Variant** p_argptrs,int p_argcount,const Variant::CallError &ce) {
- if (i>0)
- str+=", ";
- str=str+rtos(vec[i]);
- }
- return str+"])";
- } break;
- case ARRAY: {
- Array arr = operator Array();
- String str="[";
- for (int i=0; i<arr.size(); i++) {
- if (i)
- str+=", ";
- str += arr[i].get_construct_string(p_obj_deconstruct,p_deconstruct_ud);
- };
- return str+"]";
+ String err_text;
- } break;
- case OBJECT: {
+ if (ce.error==Variant::CallError::CALL_ERROR_INVALID_ARGUMENT) {
+ int errorarg=ce.argument;
+ err_text="Cannot convert argument "+itos(errorarg+1)+" from "+Variant::get_type_name(p_argptrs[errorarg]->get_type())+" to "+Variant::get_type_name(ce.expected)+".";
+ } else if (ce.error==Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) {
+ err_text="Expected "+itos(ce.argument)+" arguments.";
+ } else if (ce.error==Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) {
+ err_text="Expected "+itos(ce.argument)+" arguments.";
+ } else if (ce.error==Variant::CallError::CALL_ERROR_INVALID_METHOD) {
+ err_text="Method not found.";
+ } else if (ce.error==Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
+ err_text="Instance is null";
+ } else if (ce.error==Variant::CallError::CALL_OK){
+ return "Call OK";
+ }
- if (_get_obj().obj) {
- if (p_obj_deconstruct) {
- return "Object(\""+p_obj_deconstruct(Variant(*this),p_deconstruct_ud).c_escape()+")";
- } else {
- return _get_obj().obj->get_type()+".new()";
- }
- } else
- return "null";
+ String class_name = p_base->get_type();
+ Ref<Script> script = p_base->get_script();
+ if (script.is_valid() && script->get_path().is_resource_file()) {
- } break;
- default: {
- return "["+get_type_name(type)+"]";
- }
+ class_name+="("+script->get_path().get_file()+")";
}
-
+ return "'"+class_name+"::"+String(p_method)+"': "+err_text;
}
diff --git a/core/variant.h b/core/variant.h
index 5f338ef667..b58c781bdd 100644
--- a/core/variant.h
+++ b/core/variant.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -185,6 +185,7 @@ public:
_FORCE_INLINE_ bool is_array() const { return type>=ARRAY; };
bool is_shared() const;
bool is_zero() const;
+ bool is_one() const;
operator bool() const;
operator signed int() const;
@@ -389,7 +390,10 @@ public:
Variant call(const StringName& p_method,const Variant** p_args,int p_argcount,CallError &r_error);
Variant call(const StringName& p_method,const Variant& p_arg1=Variant(),const Variant& p_arg2=Variant(),const Variant& p_arg3=Variant(),const Variant& p_arg4=Variant(),const Variant& p_arg5=Variant());
- static Variant construct(const Variant::Type,const Variant** p_args,int p_argcount,CallError &r_error);
+
+ static String get_call_error_text(Object* p_base, const StringName& p_method,const Variant** p_argptrs,int p_argcount,const Variant::CallError &ce);
+
+ static Variant construct(const Variant::Type,const Variant** p_args,int p_argcount,CallError &r_error,bool p_strict=true);
void get_method_list(List<MethodInfo> *p_list) const;
bool has_method(const StringName& p_method) const;
@@ -410,6 +414,7 @@ public:
//argsVariant call()
bool operator==(const Variant& p_variant) const;
+ bool operator!=(const Variant& p_variant) const;
bool operator<(const Variant& p_variant) const;
uint32_t hash() const;
@@ -424,7 +429,7 @@ public:
typedef String (*ObjectDeConstruct)(const Variant& p_object,void *ud);
typedef void (*ObjectConstruct)(const String& p_text,void *ud,Variant& r_value);
- String get_construct_string(ObjectDeConstruct p_obj_deconstruct=NULL,void *p_deconstruct_ud=NULL) const;
+ String get_construct_string() const;
static void construct_from_string(const String& p_string,Variant& r_value,ObjectConstruct p_obj_construct=NULL,void *p_construct_ud=NULL);
void operator=(const Variant& p_variant); // only this is enough for all the other types
diff --git a/core/variant_call.cpp b/core/variant_call.cpp
index 4cca3420a1..90f868c866 100644
--- a/core/variant_call.cpp
+++ b/core/variant_call.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -272,6 +272,9 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
VCALL_LOCALMEM0R(String,get_file);
VCALL_LOCALMEM0R(String,xml_escape);
VCALL_LOCALMEM0R(String,xml_unescape);
+ VCALL_LOCALMEM0R(String,c_escape);
+ VCALL_LOCALMEM0R(String,c_unescape);
+ VCALL_LOCALMEM0R(String,json_escape);
VCALL_LOCALMEM0R(String,percent_encode);
VCALL_LOCALMEM0R(String,percent_decode);
VCALL_LOCALMEM0R(String,is_valid_identifier);
@@ -333,7 +336,7 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
VCALL_LOCALMEM1R(Vector2,dot);
VCALL_LOCALMEM1R(Vector2,slide);
VCALL_LOCALMEM1R(Vector2,reflect);
- VCALL_LOCALMEM0R(Vector2,atan2);
+ VCALL_LOCALMEM0R(Vector2,angle);
// VCALL_LOCALMEM1R(Vector2,cross);
VCALL_LOCALMEM0R(Rect2,get_area);
@@ -359,6 +362,8 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
VCALL_LOCALMEM1R(Vector3, dot);
VCALL_LOCALMEM1R(Vector3, cross);
VCALL_LOCALMEM0R(Vector3, abs);
+ VCALL_LOCALMEM0R(Vector3, floor);
+ VCALL_LOCALMEM0R(Vector3, ceil);
VCALL_LOCALMEM1R(Vector3, distance_to);
VCALL_LOCALMEM1R(Vector3, distance_squared_to);
VCALL_LOCALMEM1R(Vector3, slide);
@@ -407,6 +412,7 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
VCALL_LOCALMEM0R(Quat,normalized);
VCALL_LOCALMEM0R(Quat,inverse);
VCALL_LOCALMEM1R(Quat,dot);
+ VCALL_LOCALMEM1R(Quat,xform);
VCALL_LOCALMEM2R(Quat,slerp);
VCALL_LOCALMEM2R(Quat,slerpni);
VCALL_LOCALMEM4R(Quat,cubic_slerp);
@@ -447,6 +453,9 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
VCALL_LOCALMEM0(Array,clear);
VCALL_LOCALMEM0R(Array,hash);
VCALL_LOCALMEM1(Array,push_back);
+ VCALL_LOCALMEM1(Array,push_front);
+ VCALL_LOCALMEM0(Array,pop_back);
+ VCALL_LOCALMEM0(Array,pop_front);
VCALL_LOCALMEM1(Array,append);
VCALL_LOCALMEM1(Array,resize);
VCALL_LOCALMEM2(Array,insert);
@@ -753,7 +762,7 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
}
static void Matrix32_init2(Variant& r_ret,const Variant** p_args) {
-
+
Matrix32 m(*p_args[0], *p_args[1]);
r_ret=m;
}
@@ -855,6 +864,11 @@ static void _call_##m_type##_##m_method(Variant& r_ret,Variant& p_self,const Var
r_ret=Transform(p_args[0]->operator Matrix3(),p_args[1]->operator Vector3());
}
+ static void Image_init1(Variant& r_ret, const Variant** p_args) {
+
+ r_ret=Image(*p_args[0],*p_args[1],*p_args[2],Image::Format(p_args[3]->operator int()));
+ }
+
static void add_constructor(VariantConstructFunc p_func,const Variant::Type p_type,
const String& p_name1="", const Variant::Type p_type1=Variant::NIL,
const String& p_name2="", const Variant::Type p_type2=Variant::NIL,
@@ -956,7 +970,7 @@ Variant Variant::call(const StringName& p_method,const Variant** p_args,int p_ar
#define VCALL(m_type,m_method) _VariantCall::_call_##m_type##_##m_method
-Variant Variant::construct(const Variant::Type p_type,const Variant** p_args,int p_argcount,CallError &r_error) {
+Variant Variant::construct(const Variant::Type p_type, const Variant** p_args, int p_argcount, CallError &r_error, bool p_strict) {
r_error.error=Variant::CallError::CALL_ERROR_INVALID_METHOD;
ERR_FAIL_INDEX_V(p_type,VARIANT_MAX,Variant());
@@ -1032,7 +1046,7 @@ Variant Variant::construct(const Variant::Type p_type,const Variant** p_args,int
} else if (p_argcount==1 && p_args[0]->type==p_type) {
return *p_args[0]; //copy construct
- } else if (p_argcount==1 && Variant::can_convert(p_args[0]->type,p_type)) {
+ } else if (p_argcount==1 && (!p_strict || Variant::can_convert(p_args[0]->type,p_type))) {
//near match construct
switch(p_type) {
@@ -1133,7 +1147,7 @@ void Variant::get_method_list(List<MethodInfo> *p_list) const {
if (fd.returns)
ret.name="ret";
mi.return_val=ret;
-#endif
+#endif
p_list->push_back(mi);
}
@@ -1275,6 +1289,9 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl
ADDFUNC0(STRING,STRING,String,get_file,varray());
ADDFUNC0(STRING,STRING,String,xml_escape,varray());
ADDFUNC0(STRING,STRING,String,xml_unescape,varray());
+ ADDFUNC0(STRING,STRING,String,c_escape,varray());
+ ADDFUNC0(STRING,STRING,String,c_unescape,varray());
+ ADDFUNC0(STRING,STRING,String,json_escape,varray());
ADDFUNC0(STRING,STRING,String,percent_encode,varray());
ADDFUNC0(STRING,STRING,String,percent_decode,varray());
ADDFUNC0(STRING,BOOL,String,is_valid_identifier,varray());
@@ -1288,13 +1305,13 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl
ADDFUNC1(STRING,STRING,String,pad_decimals,INT,"digits",varray());
ADDFUNC1(STRING,STRING,String,pad_zeros,INT,"digits",varray());
- ADDFUNC0(STRING,STRING,String,to_ascii,varray());
- ADDFUNC0(STRING,STRING,String,to_utf8,varray());
+ ADDFUNC0(STRING,RAW_ARRAY,String,to_ascii,varray());
+ ADDFUNC0(STRING,RAW_ARRAY,String,to_utf8,varray());
ADDFUNC0(VECTOR2,VECTOR2,Vector2,normalized,varray());
ADDFUNC0(VECTOR2,REAL,Vector2,length,varray());
- ADDFUNC0(VECTOR2,REAL,Vector2,atan2,varray());
+ ADDFUNC0(VECTOR2,REAL,Vector2,angle,varray());
ADDFUNC0(VECTOR2,REAL,Vector2,length_squared,varray());
ADDFUNC1(VECTOR2,REAL,Vector2,distance_to,VECTOR2,"to",varray());
ADDFUNC1(VECTOR2,REAL,Vector2,distance_squared_to,VECTOR2,"to",varray());
@@ -1336,6 +1353,8 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl
ADDFUNC1(VECTOR3,REAL,Vector3,dot,VECTOR3,"b",varray());
ADDFUNC1(VECTOR3,VECTOR3,Vector3,cross,VECTOR3,"b",varray());
ADDFUNC0(VECTOR3,VECTOR3,Vector3,abs,varray());
+ ADDFUNC0(VECTOR3,VECTOR3,Vector3,floor,varray());
+ ADDFUNC0(VECTOR3,VECTOR3,Vector3,ceil,varray());
ADDFUNC1(VECTOR3,REAL,Vector3,distance_to,VECTOR3,"b",varray());
ADDFUNC1(VECTOR3,REAL,Vector3,distance_squared_to,VECTOR3,"b",varray());
ADDFUNC1(VECTOR3,VECTOR3,Vector3,slide,VECTOR3,"by",varray());
@@ -1357,6 +1376,7 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl
ADDFUNC0(QUAT,QUAT,Quat,normalized,varray());
ADDFUNC0(QUAT,QUAT,Quat,inverse,varray());
ADDFUNC1(QUAT,REAL,Quat,dot,QUAT,"b",varray());
+ ADDFUNC1(QUAT,VECTOR3,Quat,xform,VECTOR3,"v",varray());
ADDFUNC2(QUAT,QUAT,Quat,slerp,QUAT,"b",REAL,"t",varray());
ADDFUNC2(QUAT,QUAT,Quat,slerpni,QUAT,"b",REAL,"t",varray());
ADDFUNC4(QUAT,QUAT,Quat,cubic_slerp,QUAT,"b",QUAT,"pre_a",QUAT,"post_b",REAL,"t",varray());
@@ -1415,12 +1435,15 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl
ADDFUNC0(ARRAY,NIL,Array,clear,varray());
ADDFUNC0(ARRAY,INT,Array,hash,varray());
ADDFUNC1(ARRAY,NIL,Array,push_back,NIL,"value",varray());
+ ADDFUNC1(ARRAY,NIL,Array,push_front,NIL,"value",varray());
ADDFUNC1(ARRAY,NIL,Array,append,NIL,"value",varray());
ADDFUNC1(ARRAY,NIL,Array,resize,INT,"pos",varray());
ADDFUNC2(ARRAY,NIL,Array,insert,INT,"pos",NIL,"value",varray());
ADDFUNC1(ARRAY,NIL,Array,remove,INT,"pos",varray());
ADDFUNC1(ARRAY,NIL,Array,erase,NIL,"value",varray());
ADDFUNC1(ARRAY,INT,Array,find,NIL,"value",varray());
+ ADDFUNC0(ARRAY,NIL,Array,pop_back,varray());
+ ADDFUNC0(ARRAY,NIL,Array,pop_front,varray());
ADDFUNC0(ARRAY,NIL,Array,sort,varray());
ADDFUNC2(ARRAY,NIL,Array,sort_custom,OBJECT,"obj",STRING,"func",varray());
ADDFUNC0(ARRAY,NIL,Array,invert,varray());
@@ -1535,10 +1558,10 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl
ADDFUNC1(TRANSFORM,NIL,Transform,xform,NIL,"v",varray());
ADDFUNC1(TRANSFORM,NIL,Transform,xform_inv,NIL,"v",varray());
-#ifdef DEBUG_ENABLED
+#ifdef DEBUG_ENABLED
_VariantCall::type_funcs[Variant::TRANSFORM].functions["xform"].returns=true;
_VariantCall::type_funcs[Variant::TRANSFORM].functions["xform_inv"].returns=true;
-#endif
+#endif
ADDFUNC0(INPUT_EVENT,BOOL,InputEvent,is_pressed,varray());
ADDFUNC1(INPUT_EVENT,BOOL,InputEvent,is_action,STRING,"action",varray());
@@ -1577,6 +1600,8 @@ _VariantCall::addfunc(Variant::m_vtype,Variant::m_ret,_SCS(#m_method),VCALL(m_cl
_VariantCall::add_constructor(_VariantCall::Transform_init1,Variant::TRANSFORM,"x_axis",Variant::VECTOR3,"y_axis",Variant::VECTOR3,"z_axis",Variant::VECTOR3,"origin",Variant::VECTOR3);
_VariantCall::add_constructor(_VariantCall::Transform_init2,Variant::TRANSFORM,"basis",Variant::MATRIX3,"origin",Variant::VECTOR3);
+ _VariantCall::add_constructor(_VariantCall::Image_init1,Variant::IMAGE,"width",Variant::INT,"height",Variant::INT,"mipmaps",Variant::BOOL,"format",Variant::INT);
+
/* REGISTER CONSTANTS */
_VariantCall::constant_data[Variant::VECTOR3].value["AXIS_X"]=Vector3::AXIS_X;
@@ -1635,9 +1660,3 @@ void unregister_variant_methods() {
}
-
-
-
-
-
-
diff --git a/core/variant_call_bind.h b/core/variant_call_bind.h
index 613669203d..54954540b0 100644
--- a/core/variant_call_bind.h
+++ b/core/variant_call_bind.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/variant_op.cpp b/core/variant_op.cpp
index 1cdf6d7319..204a00e1d5 100644
--- a/core/variant_op.cpp
+++ b/core/variant_op.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -586,7 +586,21 @@ void Variant::evaluate(const Operator& p_op, const Variant& p_a, const Variant&
} break;
DEFAULT_OP_LOCALMEM_NUM(*,VECTOR3,Vector3);
DEFAULT_OP_FAIL(PLANE);
- DEFAULT_OP_FAIL(QUAT);
+ case QUAT: {
+
+ switch(p_b.type) {
+ case VECTOR3: {
+
+ _RETURN( reinterpret_cast<const Quat*>(p_a._data._mem)->xform( *(const Vector3*)p_b._data._mem) );
+ } break;
+ case QUAT: {
+
+ _RETURN( *reinterpret_cast<const Quat*>(p_a._data._mem) * *reinterpret_cast<const Quat*>(p_b._data._mem) );
+ } break;
+ };
+ r_valid=false;
+ return;
+ } break;
DEFAULT_OP_FAIL(_AABB);
case MATRIX3: {
@@ -989,7 +1003,7 @@ void Variant::set(const Variant& p_index, const Variant& p_value, bool *r_valid)
return;
}
- *str = str->substr(0,idx-1)+chr+str->substr(idx+1,str->length());
+ *str = str->substr(0,idx)+chr+str->substr(idx+1,str->length());
valid=true;
return;
@@ -1338,6 +1352,22 @@ void Variant::set(const Variant& p_index, const Variant& p_value, bool *r_valid)
valid=true;
v->set_hsv(v->get_h(),v->get_s(),p_value);
return;
+ } else if (*str=="r8" ) {
+ valid=true;
+ v->g=float(p_value)/255.0;
+ return;
+ } else if (*str=="g8" ) {
+ valid=true;
+ v->g=float(p_value)/255.0;
+ return;
+ } else if (*str=="b8" ) {
+ valid=true;
+ v->b=float(p_value)/255.0;
+ return;
+ } else if (*str=="a8" ) {\
+ valid=true;
+ v->a=float(p_value)/255.0;
+ return;
}
} else if (p_index.get_type()==Variant::INT) {
@@ -2181,6 +2211,18 @@ Variant Variant::get(const Variant& p_index, bool *r_valid) const {
} else if (*str=="v" ) {
valid=true;
return v->get_v();
+ } else if (*str=="r8") {
+ valid=true;
+ return v->r*255.0;
+ } else if (*str=="g8" ) {
+ valid=true;
+ return v->g*255.0;
+ } else if (*str=="b8" ) {
+ valid=true;
+ return v->b*255.0;
+ } else if (*str=="a8" ) {
+ valid=true;
+ return v->a*255.0;
}
} else if (p_index.get_type()==Variant::INT) {
@@ -2573,7 +2615,7 @@ bool Variant::in(const Variant& p_index, bool *r_valid) const {
String idx=p_index;
const String *str=reinterpret_cast<const String*>(_data._mem);
- return str->find("idx")!=-1;
+ return str->find(idx)!=-1;
}
} break;
@@ -2621,7 +2663,7 @@ bool Variant::in(const Variant& p_index, bool *r_valid) const {
if (l) {
for(int i=0;i<l;i++) {
- if ((*arr)[i]==p_index)
+ if (evaluate(OP_EQUAL,(*arr)[i],p_index))
return true;
}
@@ -2804,9 +2846,9 @@ void Variant::get_property_list(List<PropertyInfo> *p_list) const {
} break;
case MATRIX32: {
- p_list->push_back( PropertyInfo(Variant::REAL,"x"));
- p_list->push_back( PropertyInfo(Variant::REAL,"y"));
- p_list->push_back( PropertyInfo(Variant::REAL,"o"));
+ p_list->push_back( PropertyInfo(Variant::VECTOR2,"x"));
+ p_list->push_back( PropertyInfo(Variant::VECTOR2,"y"));
+ p_list->push_back( PropertyInfo(Variant::VECTOR2,"o"));
} break;
case PLANE: {
@@ -2852,6 +2894,10 @@ void Variant::get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back( PropertyInfo(Variant::REAL,"h"));
p_list->push_back( PropertyInfo(Variant::REAL,"s"));
p_list->push_back( PropertyInfo(Variant::REAL,"v"));
+ p_list->push_back( PropertyInfo(Variant::INT,"r8"));
+ p_list->push_back( PropertyInfo(Variant::INT,"g8"));
+ p_list->push_back( PropertyInfo(Variant::INT,"b8"));
+ p_list->push_back( PropertyInfo(Variant::INT,"a8"));
} break;
case IMAGE: { } break;
diff --git a/core/variant_parser.cpp b/core/variant_parser.cpp
new file mode 100644
index 0000000000..3efa87de80
--- /dev/null
+++ b/core/variant_parser.cpp
@@ -0,0 +1,2211 @@
+#include "variant_parser.h"
+#include "io/resource_loader.h"
+#include "os/keyboard.h"
+
+
+
+CharType VariantParser::StreamFile::get_char() {
+
+ return f->get_8();
+}
+
+bool VariantParser::StreamFile::is_utf8() const {
+
+ return true;
+}
+bool VariantParser::StreamFile::is_eof() const {
+
+ return f->eof_reached();
+}
+
+
+CharType VariantParser::StreamString::get_char() {
+
+ if (pos>=s.length())
+ return 0;
+ else
+ return s[pos++];
+}
+
+bool VariantParser::StreamString::is_utf8() const {
+ return false;
+}
+bool VariantParser::StreamString::is_eof() const {
+ return pos>s.length();
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+
+const char * VariantParser::tk_name[TK_MAX] = {
+ "'{'",
+ "'}'",
+ "'['",
+ "']'",
+ "'('",
+ "')'",
+ "identifier",
+ "string",
+ "number",
+ "color",
+ "':'",
+ "','",
+ "'.'",
+ "'='",
+ "EOF",
+ "ERROR"
+};
+
+
+
+Error VariantParser::get_token(Stream *p_stream, Token& r_token, int &line, String &r_err_str) {
+
+ while (true) {
+
+ CharType cchar;
+ if (p_stream->saved) {
+ cchar=p_stream->saved;
+ p_stream->saved=0;
+ } else {
+ cchar=p_stream->get_char();
+ if (p_stream->is_eof()) {
+ r_token.type=TK_EOF;
+ return OK;
+ }
+ }
+
+ switch(cchar) {
+
+ case '\n': {
+
+ line++;
+ break;
+ };
+ case 0: {
+ r_token.type=TK_EOF;
+ return OK;
+ } break;
+ case '{': {
+
+ r_token.type=TK_CURLY_BRACKET_OPEN;
+ return OK;
+ };
+ case '}': {
+
+ r_token.type=TK_CURLY_BRACKET_CLOSE;
+ return OK;
+ };
+ case '[': {
+
+ r_token.type=TK_BRACKET_OPEN;
+ return OK;
+ };
+ case ']': {
+
+ r_token.type=TK_BRACKET_CLOSE;
+ return OK;
+ };
+ case '(': {
+
+ r_token.type=TK_PARENTHESIS_OPEN;
+ return OK;
+ };
+ case ')': {
+
+ r_token.type=TK_PARENTHESIS_CLOSE;
+ return OK;
+ };
+ case ':': {
+
+ r_token.type=TK_COLON;
+ return OK;
+ };
+ case ';': {
+
+ while(true) {
+ CharType ch=p_stream->get_char();
+ if (p_stream->is_eof()) {
+ r_token.type=TK_EOF;
+ return OK;
+ }
+ if (ch=='\n')
+ break;
+ }
+
+ break;
+ };
+ case ',': {
+
+ r_token.type=TK_COMMA;
+ return OK;
+ };
+ case '.': {
+
+ r_token.type=TK_PERIOD;
+ return OK;
+ };
+ case '=': {
+
+ r_token.type=TK_EQUAL;
+ return OK;
+ };
+ case '#': {
+
+
+ String color_str="#";
+ while(true) {
+ CharType ch=p_stream->get_char();
+ if (p_stream->is_eof()) {
+ r_token.type=TK_EOF;
+ return OK;
+ } else if ( (ch>='0' && ch<='9') || (ch>='a' && ch<='f') || (ch>='A' && ch<='F') ) {
+ color_str+=String::chr(ch);
+
+ } else {
+ p_stream->saved=ch;
+ break;
+ }
+ }
+
+ r_token.value=Color::html(color_str);
+ r_token.type=TK_COLOR;
+ return OK;
+
+ };
+ case '"': {
+
+
+ String str;
+ while(true) {
+
+ CharType ch=p_stream->get_char();
+
+ if (ch==0) {
+ r_err_str="Unterminated String";
+ r_token.type=TK_ERROR;
+ return ERR_PARSE_ERROR;
+ } else if (ch=='"') {
+ break;
+ } else if (ch=='\\') {
+ //escaped characters...
+ CharType next = p_stream->get_char();
+ if (next==0) {
+ r_err_str="Unterminated String";
+ r_token.type=TK_ERROR;
+ return ERR_PARSE_ERROR;
+ }
+ CharType res=0;
+
+ switch(next) {
+
+ case 'b': res=8; break;
+ case 't': res=9; break;
+ case 'n': res=10; break;
+ case 'f': res=12; break;
+ case 'r': res=13; break;
+ case 'u': {
+ //hexnumbarh - oct is deprecated
+
+
+ for(int j=0;j<4;j++) {
+ CharType c = p_stream->get_char();
+ if (c==0) {
+ r_err_str="Unterminated String";
+ r_token.type=TK_ERROR;
+ return ERR_PARSE_ERROR;
+ }
+ if (!((c>='0' && c<='9') || (c>='a' && c<='f') || (c>='A' && c<='F'))) {
+
+ r_err_str="Malformed hex constant in string";
+ r_token.type=TK_ERROR;
+ return ERR_PARSE_ERROR;
+ }
+ CharType v;
+ if (c>='0' && c<='9') {
+ v=c-'0';
+ } else if (c>='a' && c<='f') {
+ v=c-'a';
+ v+=10;
+ } else if (c>='A' && c<='F') {
+ v=c-'A';
+ v+=10;
+ } else {
+ ERR_PRINT("BUG");
+ v=0;
+ }
+
+ res<<=4;
+ res|=v;
+
+
+ }
+
+
+
+ } break;
+ //case '\"': res='\"'; break;
+ //case '\\': res='\\'; break;
+ //case '/': res='/'; break;
+ default: {
+ res = next;
+ //r_err_str="Invalid escape sequence";
+ //return ERR_PARSE_ERROR;
+ } break;
+ }
+
+ str+=res;
+
+ } else {
+ if (ch=='\n')
+ line++;
+ str+=ch;
+ }
+ }
+
+ if (p_stream->is_utf8()) {
+ str.parse_utf8( str.ascii(true).get_data() );
+ }
+ r_token.type=TK_STRING;
+ r_token.value=str;
+ return OK;
+
+ } break;
+ default: {
+
+ if (cchar<=32) {
+ break;
+ }
+
+ if (cchar=='-' || (cchar>='0' && cchar<='9')) {
+ //a number
+
+
+ String num;
+#define READING_SIGN 0
+#define READING_INT 1
+#define READING_DEC 2
+#define READING_EXP 3
+#define READING_DONE 4
+ int reading=READING_INT;
+
+ if (cchar=='-') {
+ num+='-';
+ cchar=p_stream->get_char();
+
+ }
+
+
+
+ CharType c = cchar;
+ bool exp_sign=false;
+ bool exp_beg=false;
+ bool is_float=false;
+
+ while(true) {
+
+ switch(reading) {
+ case READING_INT: {
+
+ if (c>='0' && c<='9') {
+ //pass
+ } else if (c=='.') {
+ reading=READING_DEC;
+ is_float=true;
+ } else if (c=='e') {
+ reading=READING_EXP;
+ } else {
+ reading=READING_DONE;
+ }
+
+ } break;
+ case READING_DEC: {
+
+ if (c>='0' && c<='9') {
+
+ } else if (c=='e') {
+ reading=READING_EXP;
+
+ } else {
+ reading=READING_DONE;
+ }
+
+ } break;
+ case READING_EXP: {
+
+ if (c>='0' && c<='9') {
+ exp_beg=true;
+
+ } else if ((c=='-' || c=='+') && !exp_sign && !exp_beg) {
+ exp_sign=true;
+
+ } else {
+ reading=READING_DONE;
+ }
+ } break;
+ }
+
+ if (reading==READING_DONE)
+ break;
+ num+=String::chr(c);
+ c = p_stream->get_char();
+
+
+ }
+
+ p_stream->saved=c;
+
+
+ r_token.type=TK_NUMBER;
+ if (is_float)
+ r_token.value=num.to_double();
+ else
+ r_token.value=num.to_int();
+ return OK;
+
+ } else if ((cchar>='A' && cchar<='Z') || (cchar>='a' && cchar<='z') || cchar=='_') {
+
+ String id;
+ bool first=true;
+
+ while((cchar>='A' && cchar<='Z') || (cchar>='a' && cchar<='z') || cchar=='_' || (!first && cchar>='0' && cchar<='9')) {
+
+ id+=String::chr(cchar);
+ cchar=p_stream->get_char();
+ first=false;
+ }
+
+ p_stream->saved=cchar;
+
+ r_token.type=TK_IDENTIFIER;
+ r_token.value=id;
+ return OK;
+ } else {
+ r_err_str="Unexpected character.";
+ r_token.type=TK_ERROR;
+ return ERR_PARSE_ERROR;
+ }
+ }
+ }
+ }
+
+ r_token.type=TK_ERROR;
+ return ERR_PARSE_ERROR;
+}
+
+Error VariantParser::_parse_enginecfg(Stream *p_stream, Vector<String>& strings, int &line, String &r_err_str) {
+
+ Token token;
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_PARENTHESIS_OPEN) {
+ r_err_str="Expected '(' in old-style engine.cfg construct";
+ return ERR_PARSE_ERROR;
+ }
+
+
+ String accum;
+
+ while(true) {
+
+ CharType c=p_stream->get_char();
+
+ if (p_stream->is_eof()) {
+ r_err_str="Unexpected EOF while parsing old-style engine.cfg construct";
+ return ERR_PARSE_ERROR;
+ }
+
+ if (c==',') {
+ strings.push_back(accum.strip_edges());
+ accum=String();
+ } else if (c==')') {
+ strings.push_back(accum.strip_edges());
+ return OK;
+ } else if (c=='\n') {
+ line++;
+ }
+
+ }
+
+ return OK;
+}
+
+template<class T>
+Error VariantParser::_parse_construct(Stream *p_stream,Vector<T>& r_construct,int &line,String &r_err_str) {
+
+
+ Token token;
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_PARENTHESIS_OPEN) {
+ r_err_str="Expected '(' in constructor";
+ return ERR_PARSE_ERROR;
+ }
+
+
+ bool first=true;
+ while(true) {
+
+ if (!first) {
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type==TK_COMMA) {
+ //do none
+ } else if (token.type==TK_PARENTHESIS_CLOSE) {
+ break;
+ } else {
+ r_err_str="Expected ',' or ')' in constructor";
+ return ERR_PARSE_ERROR;
+
+ }
+ }
+ get_token(p_stream,token,line,r_err_str);
+
+ if (first && token.type==TK_PARENTHESIS_CLOSE) {
+ break;
+ } else if (token.type!=TK_NUMBER) {
+ r_err_str="Expected float in constructor";
+ return ERR_PARSE_ERROR;
+ }
+
+
+ r_construct.push_back(token.value);
+ first=false;
+ }
+
+ return OK;
+
+}
+
+Error VariantParser::parse_value(Token& token,Variant &value,Stream *p_stream,int &line,String &r_err_str,ResourceParser *p_res_parser) {
+
+
+
+/* {
+ Error err = get_token(p_stream,token,line,r_err_str);
+ if (err)
+ return err;
+ }*/
+
+
+ if (token.type==TK_CURLY_BRACKET_OPEN) {
+
+ Dictionary d;
+ Error err = _parse_dictionary(d,p_stream,line,r_err_str,p_res_parser);
+ if (err)
+ return err;
+ value=d;
+ return OK;
+ } else if (token.type==TK_BRACKET_OPEN) {
+
+ Array a;
+ Error err = _parse_array(a,p_stream,line,r_err_str,p_res_parser);
+ if (err)
+ return err;
+ value=a;
+ return OK;
+
+ } else if (token.type==TK_IDENTIFIER) {
+/*
+ VECTOR2, // 5
+ RECT2,
+ VECTOR3,
+ MATRIX32,
+ PLANE,
+ QUAT, // 10
+ _AABB, //sorry naming convention fail :( not like it's used often
+ MATRIX3,
+ TRANSFORM,
+
+ // misc types
+ COLOR,
+ IMAGE, // 15
+ NODE_PATH,
+ _RID,
+ OBJECT,
+ INPUT_EVENT,
+ DICTIONARY, // 20
+ ARRAY,
+
+ // arrays
+ RAW_ARRAY,
+ INT_ARRAY,
+ REAL_ARRAY,
+ STRING_ARRAY, // 25
+ VECTOR2_ARRAY,
+ VECTOR3_ARRAY,
+ COLOR_ARRAY,
+
+ VARIANT_MAX
+
+*/
+ String id = token.value;
+ if (id=="true")
+ value=true;
+ else if (id=="false")
+ value=false;
+ else if (id=="null")
+ value=Variant();
+ else if (id=="Vector2"){
+
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream,args,line,r_err_str);
+ if (err)
+ return err;
+
+ if (args.size()!=2) {
+ r_err_str="Expected 2 arguments for constructor";
+ }
+
+ value=Vector2(args[0],args[1]);
+ return OK;
+ } else if (id=="Rect2"){
+
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream,args,line,r_err_str);
+ if (err)
+ return err;
+
+ if (args.size()!=4) {
+ r_err_str="Expected 4 arguments for constructor";
+ }
+
+ value=Rect2(args[0],args[1],args[2],args[3]);
+ return OK;
+ } else if (id=="Vector3"){
+
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream,args,line,r_err_str);
+ if (err)
+ return err;
+
+ if (args.size()!=3) {
+ r_err_str="Expected 3 arguments for constructor";
+ }
+
+ value=Vector3(args[0],args[1],args[2]);
+ return OK;
+ } else if (id=="Matrix32"){
+
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream,args,line,r_err_str);
+ if (err)
+ return err;
+
+ if (args.size()!=6) {
+ r_err_str="Expected 6 arguments for constructor";
+ }
+ Matrix32 m;
+ m[0]=Vector2(args[0],args[1]);
+ m[1]=Vector2(args[2],args[3]);
+ m[2]=Vector2(args[4],args[5]);
+ value=m;
+ return OK;
+ } else if (id=="Plane") {
+
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream,args,line,r_err_str);
+ if (err)
+ return err;
+
+ if (args.size()!=4) {
+ r_err_str="Expected 4 arguments for constructor";
+ }
+
+ value=Plane(args[0],args[1],args[2],args[3]);
+ return OK;
+ } else if (id=="Quat") {
+
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream,args,line,r_err_str);
+ if (err)
+ return err;
+
+ if (args.size()!=4) {
+ r_err_str="Expected 4 arguments for constructor";
+ }
+
+ value=Quat(args[0],args[1],args[2],args[3]);
+ return OK;
+
+ } else if (id=="AABB"){
+
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream,args,line,r_err_str);
+ if (err)
+ return err;
+
+ if (args.size()!=6) {
+ r_err_str="Expected 6 arguments for constructor";
+ }
+
+ value=AABB(Vector3(args[0],args[1],args[2]),Vector3(args[3],args[4],args[5]));
+ return OK;
+
+ } else if (id=="Matrix3"){
+
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream,args,line,r_err_str);
+ if (err)
+ return err;
+
+ if (args.size()!=9) {
+ r_err_str="Expected 9 arguments for constructor";
+ }
+
+ value=Matrix3(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]);
+ return OK;
+ } else if (id=="Transform"){
+
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream,args,line,r_err_str);
+ if (err)
+ return err;
+
+ if (args.size()!=12) {
+ r_err_str="Expected 12 arguments for constructor";
+ }
+
+ value=Transform(Matrix3(args[0],args[1],args[2],args[3],args[4],args[5],args[6],args[7],args[8]),Vector3(args[9],args[10],args[11]));
+ return OK;
+
+ } else if (id=="Color") {
+
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream,args,line,r_err_str);
+ if (err)
+ return err;
+
+ if (args.size()!=4) {
+ r_err_str="Expected 4 arguments for constructor";
+ }
+
+ value=Color(args[0],args[1],args[2],args[3]);
+ return OK;
+
+ } else if (id=="Image") {
+
+ //:|
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_PARENTHESIS_OPEN) {
+ r_err_str="Expected '('";
+ return ERR_PARSE_ERROR;
+ }
+
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type==TK_PARENTHESIS_CLOSE) {
+ value=Image(); // just an Image()
+ return OK;
+ } else if (token.type!=TK_NUMBER) {
+ r_err_str="Expected number (width)";
+ return ERR_PARSE_ERROR;
+ }
+
+ get_token(p_stream,token,line,r_err_str);
+
+ int width=token.value;
+ if (token.type!=TK_COMMA) {
+ r_err_str="Expected ','";
+ return ERR_PARSE_ERROR;
+ }
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_NUMBER) {
+ r_err_str="Expected number (height)";
+ return ERR_PARSE_ERROR;
+ }
+
+ int height=token.value;
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_COMMA) {
+ r_err_str="Expected ','";
+ return ERR_PARSE_ERROR;
+ }
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_NUMBER) {
+ r_err_str="Expected number (mipmaps)";
+ return ERR_PARSE_ERROR;
+ }
+
+ int mipmaps=token.value;
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_COMMA) {
+ r_err_str="Expected ','";
+ return ERR_PARSE_ERROR;
+ }
+
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_IDENTIFIER) {
+ r_err_str="Expected identifier (format)";
+ return ERR_PARSE_ERROR;
+ }
+
+
+ String sformat=token.value;
+
+ Image::Format format;
+
+ if (sformat=="GRAYSCALE") format=Image::FORMAT_GRAYSCALE;
+ else if (sformat=="INTENSITY") format=Image::FORMAT_INTENSITY;
+ else if (sformat=="GRAYSCALE_ALPHA") format=Image::FORMAT_GRAYSCALE_ALPHA;
+ else if (sformat=="RGB") format=Image::FORMAT_RGB;
+ else if (sformat=="RGBA") format=Image::FORMAT_RGBA;
+ else if (sformat=="INDEXED") format=Image::FORMAT_INDEXED;
+ else if (sformat=="INDEXED_ALPHA") format=Image::FORMAT_INDEXED_ALPHA;
+ else if (sformat=="BC1") format=Image::FORMAT_BC1;
+ else if (sformat=="BC2") format=Image::FORMAT_BC2;
+ else if (sformat=="BC3") format=Image::FORMAT_BC3;
+ else if (sformat=="BC4") format=Image::FORMAT_BC4;
+ else if (sformat=="BC5") format=Image::FORMAT_BC5;
+ else if (sformat=="PVRTC2") format=Image::FORMAT_PVRTC2;
+ else if (sformat=="PVRTC2_ALPHA") format=Image::FORMAT_PVRTC2_ALPHA;
+ else if (sformat=="PVRTC4") format=Image::FORMAT_PVRTC4;
+ else if (sformat=="PVRTC4_ALPHA") format=Image::FORMAT_PVRTC4_ALPHA;
+ else if (sformat=="ATC") format=Image::FORMAT_ATC;
+ else if (sformat=="ATC_ALPHA_EXPLICIT") format=Image::FORMAT_ATC_ALPHA_EXPLICIT;
+ else if (sformat=="ATC_ALPHA_INTERPOLATED") format=Image::FORMAT_ATC_ALPHA_INTERPOLATED;
+ else if (sformat=="CUSTOM") format=Image::FORMAT_CUSTOM;
+ else {
+ r_err_str="Invalid image format: '"+sformat+"'";
+ return ERR_PARSE_ERROR;
+ };
+
+ int len = Image::get_image_data_size(width,height,format,mipmaps);
+
+ DVector<uint8_t> buffer;
+ buffer.resize(len);
+
+ if (buffer.size()!=len) {
+ r_err_str="Couldn't allocate image buffer of size: "+itos(len);
+ }
+
+ {
+ DVector<uint8_t>::Write w=buffer.write();
+
+ for(int i=0;i<len;i++) {
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_COMMA) {
+ r_err_str="Expected ','";
+ return ERR_PARSE_ERROR;
+ }
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_NUMBER) {
+ r_err_str="Expected number";
+ return ERR_PARSE_ERROR;
+ }
+
+ w[i]=int(token.value);
+
+ }
+ }
+
+
+ Image img(width,height,mipmaps,format,buffer);
+
+ value=img;
+
+ return OK;
+
+
+ } else if (id=="NodePath") {
+
+
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_PARENTHESIS_OPEN) {
+ r_err_str="Expected '('";
+ return ERR_PARSE_ERROR;
+ }
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_STRING) {
+ r_err_str="Expected string as argument for NodePath()";
+ return ERR_PARSE_ERROR;
+ }
+
+ value=NodePath(String(token.value));
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_PARENTHESIS_CLOSE) {
+ r_err_str="Expected ')'";
+ return ERR_PARSE_ERROR;
+ }
+
+ } else if (id=="RID") {
+
+
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_PARENTHESIS_OPEN) {
+ r_err_str="Expected '('";
+ return ERR_PARSE_ERROR;
+ }
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_NUMBER) {
+ r_err_str="Expected number as argument";
+ return ERR_PARSE_ERROR;
+ }
+
+ value=token.value;
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_PARENTHESIS_CLOSE) {
+ r_err_str="Expected ')'";
+ return ERR_PARSE_ERROR;
+ }
+
+
+ return OK;
+
+ } else if (id=="Resource" || id=="SubResource" || id=="ExtResource") {
+
+
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_PARENTHESIS_OPEN) {
+ r_err_str="Expected '('";
+ return ERR_PARSE_ERROR;
+ }
+
+
+ if (p_res_parser && id=="Resource" && p_res_parser->func){
+
+ RES res;
+ Error err = p_res_parser->func(p_res_parser->userdata,p_stream,res,line,r_err_str);
+ if (err)
+ return err;
+
+ value=res;
+
+ return OK;
+ } else if (p_res_parser && id=="ExtResource" && p_res_parser->ext_func){
+
+ RES res;
+ Error err = p_res_parser->ext_func(p_res_parser->userdata,p_stream,res,line,r_err_str);
+ if (err)
+ return err;
+
+ value=res;
+
+ return OK;
+ } else if (p_res_parser && id=="SubResource" && p_res_parser->sub_func){
+
+ RES res;
+ Error err = p_res_parser->sub_func(p_res_parser->userdata,p_stream,res,line,r_err_str);
+ if (err)
+ return err;
+
+ value=res;
+
+ return OK;
+ } else {
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type==TK_STRING) {
+ String path=token.value;
+ RES res = ResourceLoader::load(path);
+ if (res.is_null()) {
+ r_err_str="Can't load resource at path: '"+path+"'.";
+ return ERR_PARSE_ERROR;
+ }
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_PARENTHESIS_CLOSE) {
+ r_err_str="Expected ')'";
+ return ERR_PARSE_ERROR;
+ }
+
+ value=res;
+ return OK;
+
+ } else {
+ r_err_str="Expected string as argument for Resource().";
+ return ERR_PARSE_ERROR;
+ }
+ }
+
+ return OK;
+
+
+ } else if (id=="InputEvent") {
+
+
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_PARENTHESIS_OPEN) {
+ r_err_str="Expected '('";
+ return ERR_PARSE_ERROR;
+ }
+
+ get_token(p_stream,token,line,r_err_str);
+
+ if (token.type!=TK_IDENTIFIER) {
+ r_err_str="Expected identifier";
+ return ERR_PARSE_ERROR;
+ }
+
+
+ String id = token.value;
+
+ InputEvent ie;
+
+ if (id=="KEY") {
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_COMMA) {
+ r_err_str="Expected ','";
+ return ERR_PARSE_ERROR;
+ }
+
+ ie.type=InputEvent::KEY;
+
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type==TK_IDENTIFIER) {
+ String name=token.value;
+ ie.key.scancode=find_keycode(name);
+ } else if (token.type==TK_NUMBER) {
+
+ ie.key.scancode=token.value;
+ } else {
+
+ r_err_str="Expected string or integer for keycode";
+ return ERR_PARSE_ERROR;
+ }
+
+ get_token(p_stream,token,line,r_err_str);
+
+ if (token.type==TK_COMMA) {
+
+ get_token(p_stream,token,line,r_err_str);
+
+ if (token.type!=TK_IDENTIFIER) {
+ r_err_str="Expected identifier with modifier flas";
+ return ERR_PARSE_ERROR;
+ }
+
+ String mods=token.value;
+
+ if (mods.findn("C")!=-1)
+ ie.key.mod.control=true;
+ if (mods.findn("A")!=-1)
+ ie.key.mod.alt=true;
+ if (mods.findn("S")!=-1)
+ ie.key.mod.shift=true;
+ if (mods.findn("M")!=-1)
+ ie.key.mod.meta=true;
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_PARENTHESIS_CLOSE) {
+ r_err_str="Expected ')'";
+ return ERR_PARSE_ERROR;
+ }
+
+ } else if (token.type!=TK_PARENTHESIS_CLOSE) {
+
+ r_err_str="Expected ')' or modifier flags.";
+ return ERR_PARSE_ERROR;
+ }
+
+
+ } else if (id=="MBUTTON") {
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_COMMA) {
+ r_err_str="Expected ','";
+ return ERR_PARSE_ERROR;
+ }
+
+ ie.type=InputEvent::MOUSE_BUTTON;
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_NUMBER) {
+ r_err_str="Expected button index";
+ return ERR_PARSE_ERROR;
+ }
+
+ ie.mouse_button.button_index = token.value;
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_PARENTHESIS_CLOSE) {
+ r_err_str="Expected ')'";
+ return ERR_PARSE_ERROR;
+ }
+
+ } else if (id=="JBUTTON") {
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_COMMA) {
+ r_err_str="Expected ','";
+ return ERR_PARSE_ERROR;
+ }
+
+ ie.type=InputEvent::JOYSTICK_BUTTON;
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_NUMBER) {
+ r_err_str="Expected button index";
+ return ERR_PARSE_ERROR;
+ }
+
+ ie.joy_button.button_index = token.value;
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_PARENTHESIS_CLOSE) {
+ r_err_str="Expected ')'";
+ return ERR_PARSE_ERROR;
+ }
+
+ } else if (id=="JAXIS") {
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_COMMA) {
+ r_err_str="Expected ','";
+ return ERR_PARSE_ERROR;
+ }
+
+ ie.type=InputEvent::JOYSTICK_MOTION;
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_NUMBER) {
+ r_err_str="Expected axis index";
+ return ERR_PARSE_ERROR;
+ }
+
+ ie.joy_motion.axis = token.value;
+
+ get_token(p_stream,token,line,r_err_str);
+
+ if (token.type!=TK_COMMA) {
+ r_err_str="Expected ',' after axis index";
+ return ERR_PARSE_ERROR;
+ }
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_NUMBER) {
+ r_err_str="Expected axis sign";
+ return ERR_PARSE_ERROR;
+ }
+
+ ie.joy_motion.axis_value = token.value;
+
+ get_token(p_stream,token,line,r_err_str);
+
+ if (token.type!=TK_PARENTHESIS_CLOSE) {
+ r_err_str="Expected ')' for jaxis";
+ return ERR_PARSE_ERROR;
+ }
+
+ } else {
+
+ r_err_str="Invalid input event type.";
+ return ERR_PARSE_ERROR;
+ }
+
+ value=ie;
+
+ return OK;
+
+ } else if (id=="ByteArray") {
+
+ Vector<uint8_t> args;
+ Error err = _parse_construct<uint8_t>(p_stream,args,line,r_err_str);
+ if (err)
+ return err;
+
+ DVector<uint8_t> arr;
+ {
+ int len=args.size();
+ arr.resize(len);
+ DVector<uint8_t>::Write w = arr.write();
+ for(int i=0;i<len;i++) {
+ w[i]=args[i];
+ }
+ }
+
+ value=arr;
+
+ return OK;
+
+ } else if (id=="IntArray") {
+
+ Vector<int32_t> args;
+ Error err = _parse_construct<int32_t>(p_stream,args,line,r_err_str);
+ if (err)
+ return err;
+
+ DVector<int32_t> arr;
+ {
+ int len=args.size();
+ arr.resize(len);
+ DVector<int32_t>::Write w = arr.write();
+ for(int i=0;i<len;i++) {
+ w[i]=int(args[i]);
+ }
+ }
+
+ value=arr;
+
+ return OK;
+
+ } else if (id=="FloatArray") {
+
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream,args,line,r_err_str);
+ if (err)
+ return err;
+
+ DVector<float> arr;
+ {
+ int len=args.size();
+ arr.resize(len);
+ DVector<float>::Write w = arr.write();
+ for(int i=0;i<len;i++) {
+ w[i]=args[i];
+ }
+ }
+
+ value=arr;
+
+ return OK;
+ } else if (id=="StringArray") {
+
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_PARENTHESIS_OPEN) {
+ r_err_str="Expected '('";
+ return ERR_PARSE_ERROR;
+ }
+
+ Vector<String> cs;
+
+ bool first=true;
+ while(true) {
+
+ if (!first) {
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type==TK_COMMA) {
+ //do none
+ } else if (token.type==TK_PARENTHESIS_CLOSE) {
+ break;
+ } else {
+ r_err_str="Expected ',' or ')'";
+ return ERR_PARSE_ERROR;
+
+ }
+ }
+ get_token(p_stream,token,line,r_err_str);
+
+ if (token.type!=TK_STRING) {
+ r_err_str="Expected string";
+ return ERR_PARSE_ERROR;
+ }
+
+ first=false;
+ cs.push_back(token.value);
+ }
+
+
+ DVector<String> arr;
+ {
+ int len=cs.size();
+ arr.resize(len);
+ DVector<String>::Write w = arr.write();
+ for(int i=0;i<len;i++) {
+ w[i]=cs[i];
+ }
+ }
+
+ value=arr;
+
+ return OK;
+
+
+ } else if (id=="Vector2Array") {
+
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream,args,line,r_err_str);
+ if (err)
+ return err;
+
+ DVector<Vector2> arr;
+ {
+ int len=args.size()/2;
+ arr.resize(len);
+ DVector<Vector2>::Write w = arr.write();
+ for(int i=0;i<len;i++) {
+ w[i]=Vector2(args[i*2+0],args[i*2+1]);
+ }
+ }
+
+ value=arr;
+
+ return OK;
+
+ } else if (id=="Vector3Array") {
+
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream,args,line,r_err_str);
+ if (err)
+ return err;
+
+ DVector<Vector3> arr;
+ {
+ int len=args.size()/3;
+ arr.resize(len);
+ DVector<Vector3>::Write w = arr.write();
+ for(int i=0;i<len;i++) {
+ w[i]=Vector3(args[i*3+0],args[i*3+1],args[i*3+2]);
+ }
+ }
+
+ value=arr;
+
+ return OK;
+
+ } else if (id=="ColorArray") {
+
+ Vector<float> args;
+ Error err = _parse_construct<float>(p_stream,args,line,r_err_str);
+ if (err)
+ return err;
+
+ DVector<Color> arr;
+ {
+ int len=args.size()/4;
+ arr.resize(len);
+ DVector<Color>::Write w = arr.write();
+ for(int i=0;i<len;i++) {
+ w[i]=Color(args[i*3+0],args[i*3+1],args[i*3+2],args[i*3+3]);
+ }
+ }
+
+ value=arr;
+
+ return OK;
+ } else if (id=="key") { // compatibility with engine.cfg
+
+ Vector<String> params;
+ Error err = _parse_enginecfg(p_stream,params,line,r_err_str);
+ if (err)
+ return err;
+ ERR_FAIL_COND_V(params.size()!=1 && params.size()!=2,ERR_PARSE_ERROR);
+
+ int scode=0;
+
+ if (params[0].is_numeric()) {
+ scode=params[0].to_int();
+ if (scode < 10) {
+ scode=KEY_0+scode;
+ }
+ } else
+ scode=find_keycode(params[0]);
+
+ InputEvent ie;
+ ie.type=InputEvent::KEY;
+ ie.key.scancode=scode;
+
+ if (params.size()==2) {
+ String mods=params[1];
+ if (mods.findn("C")!=-1)
+ ie.key.mod.control=true;
+ if (mods.findn("A")!=-1)
+ ie.key.mod.alt=true;
+ if (mods.findn("S")!=-1)
+ ie.key.mod.shift=true;
+ if (mods.findn("M")!=-1)
+ ie.key.mod.meta=true;
+ }
+ value=ie;
+ return OK;
+
+ } else if (id=="mbutton") { // compatibility with engine.cfg
+
+ Vector<String> params;
+ Error err = _parse_enginecfg(p_stream,params,line,r_err_str);
+ if (err)
+ return err;
+ ERR_FAIL_COND_V(params.size()!=2,ERR_PARSE_ERROR);
+
+ InputEvent ie;
+ ie.type=InputEvent::MOUSE_BUTTON;
+ ie.device=params[0].to_int();
+ ie.mouse_button.button_index=params[1].to_int();
+
+ value=ie;
+ return OK;
+ } else if (id=="jbutton") { // compatibility with engine.cfg
+
+ Vector<String> params;
+ Error err = _parse_enginecfg(p_stream,params,line,r_err_str);
+ if (err)
+ return err;
+ ERR_FAIL_COND_V(params.size()!=2,ERR_PARSE_ERROR);
+ InputEvent ie;
+ ie.type=InputEvent::JOYSTICK_BUTTON;
+ ie.device=params[0].to_int();
+ ie.joy_button.button_index=params[1].to_int();
+
+ value=ie;
+
+ return OK;
+ } else if (id=="jaxis") { // compatibility with engine.cfg
+
+ Vector<String> params;
+ Error err = _parse_enginecfg(p_stream,params,line,r_err_str);
+ if (err)
+ return err;
+ ERR_FAIL_COND_V(params.size()!=2,ERR_PARSE_ERROR);
+
+ InputEvent ie;
+ ie.type=InputEvent::JOYSTICK_MOTION;
+ ie.device=params[0].to_int();
+ int axis=params[1].to_int();
+ ie.joy_motion.axis=axis>>1;
+ ie.joy_motion.axis_value=axis&1?1:-1;
+
+ value= ie;
+
+ return OK;
+ } else if (id=="img") { // compatibility with engine.cfg
+
+ Token token;
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_PARENTHESIS_OPEN) {
+ r_err_str="Expected '(' in old-style engine.cfg construct";
+ return ERR_PARSE_ERROR;
+ }
+
+ while(true) {
+ CharType c = p_stream->get_char();
+ if (p_stream->is_eof()) {
+ r_err_str="Unexpected EOF in old style engine.cfg img()";
+ return ERR_PARSE_ERROR;
+ }
+ if (c==')')
+ break;
+ }
+
+ value=Image();
+
+ return OK;
+
+ } else {
+ r_err_str="Unexpected identifier: '"+id+"'.";
+ return ERR_PARSE_ERROR;
+ }
+
+
+ /*
+ VECTOR2, // 5
+ RECT2,
+ VECTOR3,
+ MATRIX32,
+ PLANE,
+ QUAT, // 10
+ _AABB, //sorry naming convention fail :( not like it's used often
+ MATRIX3,
+ TRANSFORM,
+
+ // misc types
+ COLOR,
+ IMAGE, // 15
+ NODE_PATH,
+ _RID,
+ OBJECT,
+ INPUT_EVENT,
+ DICTIONARY, // 20
+ ARRAY,
+
+ // arrays
+ RAW_ARRAY,
+ INT_ARRAY,
+ REAL_ARRAY,
+ STRING_ARRAY, // 25
+ VECTOR2_ARRAY,
+ VECTOR3_ARRAY,
+ COLOR_ARRAY,
+
+ VARIANT_MAX
+
+ */
+
+ return OK;
+
+ } else if (token.type==TK_NUMBER) {
+
+ value=token.value;
+ return OK;
+ } else if (token.type==TK_STRING) {
+
+ value=token.value;
+ return OK;
+ } else if (token.type==TK_COLOR) {
+
+ value=token.value;
+ return OK;
+ } else {
+ r_err_str="Expected value, got "+String(tk_name[token.type])+".";
+ return ERR_PARSE_ERROR;
+ }
+
+ return ERR_PARSE_ERROR;
+}
+
+
+Error VariantParser::_parse_array(Array &array, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser) {
+
+ Token token;
+ bool need_comma=false;
+
+
+ while(true) {
+
+ if (p_stream->is_eof()) {
+ r_err_str="Unexpected End of File while parsing array";
+ return ERR_FILE_CORRUPT;
+ }
+
+ Error err = get_token(p_stream,token,line,r_err_str);
+ if (err!=OK)
+ return err;
+
+ if (token.type==TK_BRACKET_CLOSE) {
+
+ return OK;
+ }
+
+ if (need_comma) {
+
+ if (token.type!=TK_COMMA) {
+
+ r_err_str="Expected ','";
+ return ERR_PARSE_ERROR;
+ } else {
+ need_comma=false;
+ continue;
+ }
+ }
+
+ Variant v;
+ err = parse_value(token,v,p_stream,line,r_err_str,p_res_parser);
+ if (err)
+ return err;
+
+ array.push_back(v);
+ need_comma=true;
+
+ }
+
+ return OK;
+
+}
+
+Error VariantParser::_parse_dictionary(Dictionary &object, Stream *p_stream, int &line, String &r_err_str, ResourceParser *p_res_parser) {
+
+ bool at_key=true;
+ Variant key;
+ Token token;
+ bool need_comma=false;
+
+
+ while(true) {
+
+
+ if (p_stream->is_eof()) {
+ r_err_str="Unexpected End of File while parsing dictionary";
+ return ERR_FILE_CORRUPT;
+ }
+
+ if (at_key) {
+
+ Error err = get_token(p_stream,token,line,r_err_str);
+ if (err!=OK)
+ return err;
+
+ if (token.type==TK_CURLY_BRACKET_CLOSE) {
+
+ return OK;
+ }
+
+ if (need_comma) {
+
+ if (token.type!=TK_COMMA) {
+
+ r_err_str="Expected '}' or ','";
+ return ERR_PARSE_ERROR;
+ } else {
+ need_comma=false;
+ continue;
+ }
+ }
+
+
+
+
+ err = parse_value(token,key,p_stream,line,r_err_str,p_res_parser);
+
+ if (err)
+ return err;
+
+ err = get_token(p_stream,token,line,r_err_str);
+
+ if (err!=OK)
+ return err;
+ if (token.type!=TK_COLON) {
+
+ r_err_str="Expected ':'";
+ return ERR_PARSE_ERROR;
+ }
+ at_key=false;
+ } else {
+
+
+ Error err = get_token(p_stream,token,line,r_err_str);
+ if (err!=OK)
+ return err;
+
+ Variant v;
+ err = parse_value(token,v,p_stream,line,r_err_str,p_res_parser);
+ if (err)
+ return err;
+ object[key]=v;
+ need_comma=true;
+ at_key=true;
+ }
+ }
+
+ return OK;
+}
+
+
+Error VariantParser::_parse_tag(Token& token, Stream *p_stream, int &line, String &r_err_str, Tag& r_tag, ResourceParser *p_res_parser,bool p_simple_tag) {
+
+ r_tag.fields.clear();
+
+ if (token.type!=TK_BRACKET_OPEN) {
+ r_err_str="Expected '['";
+ return ERR_PARSE_ERROR;
+ }
+
+
+ if (p_simple_tag) {
+
+ r_tag.name="";
+ r_tag.fields.clear();
+
+ while(true) {
+
+ CharType c = p_stream->get_char();
+ if (p_stream->is_eof()) {
+ r_err_str="Unexpected EOF while parsing simple tag";
+ return ERR_PARSE_ERROR;
+ }
+ if (c==']')
+ break;
+ r_tag.name+=String::chr(c);
+ }
+
+ r_tag.name = r_tag.name.strip_edges();
+
+ return OK;
+
+ }
+
+ get_token(p_stream,token,line,r_err_str);
+
+
+ if (token.type!=TK_IDENTIFIER) {
+ r_err_str="Expected identifier (tag name)";
+ return ERR_PARSE_ERROR;
+ }
+
+ r_tag.name=token.value;
+ bool parsing_tag=true;
+
+ while(true) {
+
+ if (p_stream->is_eof()) {
+ r_err_str="Unexpected End of File while parsing tag: "+r_tag.name;
+ return ERR_FILE_CORRUPT;
+ }
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type==TK_BRACKET_CLOSE)
+ break;
+
+ if (parsing_tag && token.type==TK_PERIOD) {
+ r_tag.name+="."; //support tags such as [someprop.Anroid] for specific platforms
+ get_token(p_stream,token,line,r_err_str);
+ } else if (parsing_tag && token.type==TK_COLON) {
+ r_tag.name+=":"; //support tags such as [someprop.Anroid] for specific platforms
+ get_token(p_stream,token,line,r_err_str);
+ } else {
+ parsing_tag=false;
+ }
+
+ if (token.type!=TK_IDENTIFIER) {
+ r_err_str="Expected Identifier";
+ return ERR_PARSE_ERROR;
+ }
+
+ String id=token.value;
+
+ if (parsing_tag) {
+ r_tag.name+=id;
+ continue;
+ }
+
+ get_token(p_stream,token,line,r_err_str);
+ if (token.type!=TK_EQUAL) {
+ return ERR_PARSE_ERROR;
+ }
+
+ get_token(p_stream,token,line,r_err_str);
+ Variant value;
+ Error err = parse_value(token,value,p_stream,line,r_err_str,p_res_parser);
+ if (err)
+ return err;
+
+ r_tag.fields[id]=value;
+
+ }
+
+
+ return OK;
+
+}
+
+Error VariantParser::parse_tag(Stream *p_stream, int &line, String &r_err_str, Tag& r_tag, ResourceParser *p_res_parser, bool p_simple_tag) {
+
+ Token token;
+ get_token(p_stream,token,line,r_err_str);
+
+ if (token.type==TK_EOF) {
+ return ERR_FILE_EOF;
+ }
+
+ if (token.type!=TK_BRACKET_OPEN) {
+ r_err_str="Expected '['";
+ return ERR_PARSE_ERROR;
+ }
+
+ return _parse_tag(token,p_stream,line,r_err_str,r_tag,p_res_parser,p_simple_tag);
+
+}
+
+Error VariantParser::parse_tag_assign_eof(Stream *p_stream, int &line, String &r_err_str, Tag& r_tag, String &r_assign, Variant &r_value, ResourceParser *p_res_parser, bool p_simple_tag) {
+
+
+ //assign..
+ r_assign="";
+ String what;
+
+ while(true) {
+
+
+ CharType c;
+ if (p_stream->saved) {
+ c=p_stream->saved;
+ p_stream->saved=0;
+
+ } else {
+ c=p_stream->get_char();
+ }
+
+ if (p_stream->is_eof())
+ return ERR_FILE_EOF;
+
+ if (c==';') { //comment
+ while(true) {
+ CharType ch=p_stream->get_char();
+ if (p_stream->is_eof()) {
+ return ERR_FILE_EOF;
+ }
+ if (ch=='\n')
+ break;
+ }
+ continue;
+ }
+
+ if (c=='[' && what.length()==0) {
+ //it's a tag!
+ p_stream->saved='['; //go back one
+
+ Error err = parse_tag(p_stream,line,r_err_str,r_tag,p_res_parser,p_simple_tag);
+
+ return err;
+ }
+
+ if (c>32) {
+ if (c!='=') {
+ what+=String::chr(c);
+ } else {
+ r_assign=what;
+ Token token;
+ get_token(p_stream,token,line,r_err_str);
+ Error err = parse_value(token,r_value,p_stream,line,r_err_str,p_res_parser);
+ if (err) {
+
+ }
+ return err;
+ }
+ } else if (c=='\n') {
+ line++;
+ }
+ }
+
+ return OK;
+}
+
+Error VariantParser::parse(Stream *p_stream, Variant& r_ret, String &r_err_str, int &r_err_line, ResourceParser *p_res_parser) {
+
+
+ Token token;
+ Error err = get_token(p_stream,token,r_err_line,r_err_str);
+ if (err)
+ return err;
+
+ if (token.type==TK_EOF) {
+ return ERR_FILE_EOF;
+ }
+
+ return parse_value(token,r_ret,p_stream,r_err_line,r_err_str,p_res_parser);
+
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+
+Error VariantWriter::write(const Variant& p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud,EncodeResourceFunc p_encode_res_func,void* p_encode_res_ud) {
+
+ switch( p_variant.get_type() ) {
+
+ case Variant::NIL: {
+ p_store_string_func(p_store_string_ud,"null");
+ } break;
+ case Variant::BOOL: {
+
+ p_store_string_func(p_store_string_ud,p_variant.operator bool() ? "true":"false" );
+ } break;
+ case Variant::INT: {
+
+ p_store_string_func(p_store_string_ud, itos(p_variant.operator int()) );
+ } break;
+ case Variant::REAL: {
+
+ String s = rtoss(p_variant.operator real_t());
+ if (s.find(".")==-1 && s.find("e")==-1)
+ s+=".0";
+ p_store_string_func(p_store_string_ud, s );
+ } break;
+ case Variant::STRING: {
+
+ String str=p_variant;
+
+ str="\""+str.c_escape()+"\"";
+ p_store_string_func(p_store_string_ud, str );
+ } break;
+ case Variant::VECTOR2: {
+
+ Vector2 v = p_variant;
+ p_store_string_func(p_store_string_ud,"Vector2( "+rtoss(v.x) +", "+rtoss(v.y)+" )" );
+ } break;
+ case Variant::RECT2: {
+
+ Rect2 aabb = p_variant;
+ p_store_string_func(p_store_string_ud,"Rect2( "+rtoss(aabb.pos.x) +", "+rtoss(aabb.pos.y) +", "+rtoss(aabb.size.x) +", "+rtoss(aabb.size.y)+" )" );
+
+ } break;
+ case Variant::VECTOR3: {
+
+ Vector3 v = p_variant;
+ p_store_string_func(p_store_string_ud,"Vector3( "+rtoss(v.x) +", "+rtoss(v.y)+", "+rtoss(v.z)+" )");
+ } break;
+ case Variant::PLANE: {
+
+ Plane p = p_variant;
+ p_store_string_func(p_store_string_ud,"Plane( "+rtoss(p.normal.x) +", "+rtoss(p.normal.y)+", "+rtoss(p.normal.z)+", "+rtoss(p.d)+" )" );
+
+ } break;
+ case Variant::_AABB: {
+
+ AABB aabb = p_variant;
+ p_store_string_func(p_store_string_ud,"AABB( "+rtoss(aabb.pos.x) +", "+rtoss(aabb.pos.y) +", "+rtoss(aabb.pos.z) +", "+rtoss(aabb.size.x) +", "+rtoss(aabb.size.y) +", "+rtoss(aabb.size.z)+" )" );
+
+ } break;
+ case Variant::QUAT: {
+
+ Quat quat = p_variant;
+ p_store_string_func(p_store_string_ud,"Quat( "+rtoss(quat.x)+", "+rtoss(quat.y)+", "+rtoss(quat.z)+", "+rtoss(quat.w)+" )");
+
+ } break;
+ case Variant::MATRIX32: {
+
+ String s="Matrix32( ";
+ Matrix32 m3 = p_variant;
+ for (int i=0;i<3;i++) {
+ for (int j=0;j<2;j++) {
+
+ if (i!=0 || j!=0)
+ s+=", ";
+ s+=rtoss( m3.elements[i][j] );
+ }
+ }
+
+ p_store_string_func(p_store_string_ud,s+" )");
+
+ } break;
+ case Variant::MATRIX3: {
+
+ String s="Matrix3( ";
+ Matrix3 m3 = p_variant;
+ for (int i=0;i<3;i++) {
+ for (int j=0;j<3;j++) {
+
+ if (i!=0 || j!=0)
+ s+=", ";
+ s+=rtoss( m3.elements[i][j] );
+ }
+ }
+
+ p_store_string_func(p_store_string_ud,s+" )");
+
+ } break;
+ case Variant::TRANSFORM: {
+
+ String s="Transform( ";
+ Transform t = p_variant;
+ Matrix3 &m3 = t.basis;
+ for (int i=0;i<3;i++) {
+ for (int j=0;j<3;j++) {
+
+ if (i!=0 || j!=0)
+ s+=", ";
+ s+=rtoss( m3.elements[i][j] );
+ }
+ }
+
+ s=s+", "+rtoss(t.origin.x) +", "+rtoss(t.origin.y)+", "+rtoss(t.origin.z);
+
+ p_store_string_func(p_store_string_ud,s+" )");
+ } break;
+
+ // misc types
+ case Variant::COLOR: {
+
+ Color c = p_variant;
+ p_store_string_func(p_store_string_ud,"Color( "+rtoss(c.r) +", "+rtoss(c.g)+", "+rtoss(c.b)+", "+rtoss(c.a)+" )");
+
+ } break;
+ case Variant::IMAGE: {
+
+
+ Image img=p_variant;
+
+ if (img.empty()) {
+ p_store_string_func(p_store_string_ud,"Image()");
+ break;
+ }
+
+ String imgstr="Image( ";
+ imgstr+=itos(img.get_width());
+ imgstr+=", "+itos(img.get_height());
+ imgstr+=", "+itos(img.get_mipmaps());
+ imgstr+=", ";
+
+ switch(img.get_format()) {
+
+ case Image::FORMAT_GRAYSCALE: imgstr+="GRAYSCALE"; break;
+ case Image::FORMAT_INTENSITY: imgstr+="INTENSITY"; break;
+ case Image::FORMAT_GRAYSCALE_ALPHA: imgstr+="GRAYSCALE_ALPHA"; break;
+ case Image::FORMAT_RGB: imgstr+="RGB"; break;
+ case Image::FORMAT_RGBA: imgstr+="RGBA"; break;
+ case Image::FORMAT_INDEXED : imgstr+="INDEXED"; break;
+ case Image::FORMAT_INDEXED_ALPHA: imgstr+="INDEXED_ALPHA"; break;
+ case Image::FORMAT_BC1: imgstr+="BC1"; break;
+ case Image::FORMAT_BC2: imgstr+="BC2"; break;
+ case Image::FORMAT_BC3: imgstr+="BC3"; break;
+ case Image::FORMAT_BC4: imgstr+="BC4"; break;
+ case Image::FORMAT_BC5: imgstr+="BC5"; break;
+ case Image::FORMAT_PVRTC2: imgstr+="PVRTC2"; break;
+ case Image::FORMAT_PVRTC2_ALPHA: imgstr+="PVRTC2_ALPHA"; break;
+ case Image::FORMAT_PVRTC4: imgstr+="PVRTC4"; break;
+ case Image::FORMAT_PVRTC4_ALPHA: imgstr+="PVRTC4_ALPHA"; break;
+ case Image::FORMAT_ETC: imgstr+="ETC"; break;
+ case Image::FORMAT_ATC: imgstr+="ATC"; break;
+ case Image::FORMAT_ATC_ALPHA_EXPLICIT: imgstr+="ATC_ALPHA_EXPLICIT"; break;
+ case Image::FORMAT_ATC_ALPHA_INTERPOLATED: imgstr+="ATC_ALPHA_INTERPOLATED"; break;
+ case Image::FORMAT_CUSTOM: imgstr+="CUSTOM"; break;
+ default: {}
+ }
+
+
+ String s;
+
+ DVector<uint8_t> data = img.get_data();
+ int len = data.size();
+ DVector<uint8_t>::Read r = data.read();
+ const uint8_t *ptr=r.ptr();;
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ s+=", ";
+ s+=itos(ptr[i]);
+ }
+
+ imgstr+=", ";
+ p_store_string_func(p_store_string_ud,imgstr);
+ p_store_string_func(p_store_string_ud,s);
+ p_store_string_func(p_store_string_ud," )");
+ } break;
+ case Variant::NODE_PATH: {
+
+ String str=p_variant;
+
+ str="NodePath(\""+str.c_escape()+"\")";
+ p_store_string_func(p_store_string_ud,str);
+
+ } break;
+
+ case Variant::OBJECT: {
+
+ RES res = p_variant;
+ if (res.is_null()) {
+ p_store_string_func(p_store_string_ud,"null");
+ break; // don't save it
+ }
+
+ String res_text;
+
+ if (p_encode_res_func) {
+
+ res_text=p_encode_res_func(p_encode_res_ud,res);
+ }
+
+ if (res_text==String() && res->get_path().is_resource_file()) {
+
+ //external resource
+ String path=res->get_path();
+ res_text="Resource( \""+path+"\")";
+ }
+
+ if (res_text==String())
+ res_text="null";
+
+ p_store_string_func(p_store_string_ud,res_text);
+
+ } break;
+ case Variant::INPUT_EVENT: {
+
+ p_store_string_func(p_store_string_ud,"InputEvent()"); //will be added later
+ } break;
+ case Variant::DICTIONARY: {
+
+ Dictionary dict = p_variant;
+
+ List<Variant> keys;
+ dict.get_key_list(&keys);
+ keys.sort();
+
+ p_store_string_func(p_store_string_ud,"{ ");
+ for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
+
+ //if (!_check_type(dict[E->get()]))
+ // continue;
+ write(E->get(),p_store_string_func,p_store_string_ud,p_encode_res_func,p_encode_res_ud);
+ p_store_string_func(p_store_string_ud,":");
+ write(dict[E->get()],p_store_string_func,p_store_string_ud,p_encode_res_func,p_encode_res_ud);
+ if (E->next())
+ p_store_string_func(p_store_string_ud,", ");
+ }
+
+
+ p_store_string_func(p_store_string_ud," }");
+
+
+ } break;
+ case Variant::ARRAY: {
+
+ p_store_string_func(p_store_string_ud,"[ ");
+ Array array = p_variant;
+ int len=array.size();
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ p_store_string_func(p_store_string_ud,", ");
+ write(array[i],p_store_string_func,p_store_string_ud,p_encode_res_func,p_encode_res_ud);
+
+ }
+ p_store_string_func(p_store_string_ud," ]");
+
+ } break;
+
+ case Variant::RAW_ARRAY: {
+
+ p_store_string_func(p_store_string_ud,"ByteArray( ");
+ String s;
+ DVector<uint8_t> data = p_variant;
+ int len = data.size();
+ DVector<uint8_t>::Read r = data.read();
+ const uint8_t *ptr=r.ptr();;
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ p_store_string_func(p_store_string_ud,", ");
+
+ p_store_string_func(p_store_string_ud,itos(ptr[i]));
+
+ }
+
+ p_store_string_func(p_store_string_ud," )");
+
+ } break;
+ case Variant::INT_ARRAY: {
+
+ p_store_string_func(p_store_string_ud,"IntArray( ");
+ DVector<int> data = p_variant;
+ int len = data.size();
+ DVector<int>::Read r = data.read();
+ const int *ptr=r.ptr();;
+
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ p_store_string_func(p_store_string_ud,", ");
+
+ p_store_string_func(p_store_string_ud,itos(ptr[i]));
+ }
+
+
+ p_store_string_func(p_store_string_ud," )");
+
+ } break;
+ case Variant::REAL_ARRAY: {
+
+ p_store_string_func(p_store_string_ud,"FloatArray( ");
+ DVector<real_t> data = p_variant;
+ int len = data.size();
+ DVector<real_t>::Read r = data.read();
+ const real_t *ptr=r.ptr();;
+
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ p_store_string_func(p_store_string_ud,", ");
+ p_store_string_func(p_store_string_ud,rtoss(ptr[i]));
+ }
+
+ p_store_string_func(p_store_string_ud," )");
+
+ } break;
+ case Variant::STRING_ARRAY: {
+
+ p_store_string_func(p_store_string_ud,"StringArray( ");
+ DVector<String> data = p_variant;
+ int len = data.size();
+ DVector<String>::Read r = data.read();
+ const String *ptr=r.ptr();;
+ String s;
+ //write_string("\n");
+
+
+
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ p_store_string_func(p_store_string_ud,", ");
+ String str=ptr[i];
+ p_store_string_func(p_store_string_ud,"\""+str.c_escape()+"\"");
+ }
+
+ p_store_string_func(p_store_string_ud," )");
+
+ } break;
+ case Variant::VECTOR2_ARRAY: {
+
+ p_store_string_func(p_store_string_ud,"Vector2Array( ");
+ DVector<Vector2> data = p_variant;
+ int len = data.size();
+ DVector<Vector2>::Read r = data.read();
+ const Vector2 *ptr=r.ptr();;
+
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ p_store_string_func(p_store_string_ud,", ");
+ p_store_string_func(p_store_string_ud,rtoss(ptr[i].x)+", "+rtoss(ptr[i].y) );
+ }
+
+ p_store_string_func(p_store_string_ud," )");
+
+ } break;
+ case Variant::VECTOR3_ARRAY: {
+
+ p_store_string_func(p_store_string_ud,"Vector3Array( ");
+ DVector<Vector3> data = p_variant;
+ int len = data.size();
+ DVector<Vector3>::Read r = data.read();
+ const Vector3 *ptr=r.ptr();;
+
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ p_store_string_func(p_store_string_ud,", ");
+ p_store_string_func(p_store_string_ud,rtoss(ptr[i].x)+", "+rtoss(ptr[i].y)+", "+rtoss(ptr[i].z) );
+ }
+
+ p_store_string_func(p_store_string_ud," )");
+
+ } break;
+ case Variant::COLOR_ARRAY: {
+
+ p_store_string_func(p_store_string_ud,"ColorArray( ");
+
+ DVector<Color> data = p_variant;
+ int len = data.size();
+ DVector<Color>::Read r = data.read();
+ const Color *ptr=r.ptr();;
+
+ for (int i=0;i<len;i++) {
+
+ if (i>0)
+ p_store_string_func(p_store_string_ud,", ");
+
+ p_store_string_func(p_store_string_ud,rtoss(ptr[i].r)+", "+rtoss(ptr[i].g)+", "+rtoss(ptr[i].b)+", "+rtoss(ptr[i].a) );
+
+ }
+ p_store_string_func(p_store_string_ud," )");
+
+ } break;
+ default: {}
+
+ }
+
+ return OK;
+}
+
+static Error _write_to_str(void *ud,const String& p_string) {
+
+ String *str=(String*)ud;
+ (*str)+=p_string;
+ return OK;
+}
+
+Error VariantWriter::write_to_string(const Variant& p_variant, String& r_string, EncodeResourceFunc p_encode_res_func, void *p_encode_res_ud) {
+
+ r_string=String();
+
+ return write(p_variant,_write_to_str,&r_string,p_encode_res_func,p_encode_res_ud);
+
+}
diff --git a/core/variant_parser.h b/core/variant_parser.h
new file mode 100644
index 0000000000..00f6910b29
--- /dev/null
+++ b/core/variant_parser.h
@@ -0,0 +1,139 @@
+#ifndef VARIANT_PARSER_H
+#define VARIANT_PARSER_H
+
+#include "variant.h"
+#include "os/file_access.h"
+#include "resource.h"
+
+class VariantParser {
+public:
+
+ struct Stream {
+
+ virtual CharType get_char()=0;
+ virtual bool is_utf8() const=0;
+ virtual bool is_eof() const=0;
+
+ CharType saved;
+
+ Stream() { saved=0; }
+ virtual ~Stream() {}
+ };
+
+ struct StreamFile : public Stream {
+
+ FileAccess *f;
+
+ virtual CharType get_char();
+ virtual bool is_utf8() const;
+ virtual bool is_eof() const;
+
+ StreamFile() { f=NULL; }
+
+ };
+
+ struct StreamString : public Stream {
+
+ String s;
+ int pos;
+
+ virtual CharType get_char();
+ virtual bool is_utf8() const;
+ virtual bool is_eof() const;
+
+ StreamString() { pos=0; }
+
+ };
+
+ typedef Error (*ParseResourceFunc)(void* p_self, Stream* p_stream,Ref<Resource>& r_res,int &line,String &r_err_str);
+
+ struct ResourceParser {
+
+ void *userdata;
+ ParseResourceFunc func;
+ ParseResourceFunc ext_func;
+ ParseResourceFunc sub_func;
+
+ };
+
+ enum TokenType {
+ TK_CURLY_BRACKET_OPEN,
+ TK_CURLY_BRACKET_CLOSE,
+ TK_BRACKET_OPEN,
+ TK_BRACKET_CLOSE,
+ TK_PARENTHESIS_OPEN,
+ TK_PARENTHESIS_CLOSE,
+ TK_IDENTIFIER,
+ TK_STRING,
+ TK_NUMBER,
+ TK_COLOR,
+ TK_COLON,
+ TK_COMMA,
+ TK_PERIOD,
+ TK_EQUAL,
+ TK_EOF,
+ TK_ERROR,
+ TK_MAX
+ };
+
+ enum Expecting {
+
+ EXPECT_OBJECT,
+ EXPECT_OBJECT_KEY,
+ EXPECT_COLON,
+ EXPECT_OBJECT_VALUE,
+ };
+
+ struct Token {
+
+ TokenType type;
+ Variant value;
+ };
+
+ struct Tag {
+
+ String name;
+ Map<String,Variant> fields;
+ };
+
+private:
+ static const char * tk_name[TK_MAX];
+
+ template<class T>
+ static Error _parse_construct(Stream *p_stream, Vector<T>& r_construct, int &line, String &r_err_str);
+ static Error _parse_enginecfg(Stream *p_stream, Vector<String>& strings, int &line, String &r_err_str);
+ static Error _parse_dictionary(Dictionary &object, Stream *p_stream, int &line, String &r_err_str,ResourceParser *p_res_parser=NULL);
+ static Error _parse_array(Array &array, Stream *p_stream, int &line, String &r_err_str,ResourceParser *p_res_parser=NULL);
+ static Error _parse_tag(Token& token,Stream *p_stream, int &line, String &r_err_str,Tag& r_tag,ResourceParser *p_res_parser=NULL,bool p_simple_tag=false);
+
+public:
+
+ static Error parse_tag(Stream *p_stream, int &line, String &r_err_str,Tag& r_tag,ResourceParser *p_res_parser=NULL,bool p_simple_tag=false);
+ static Error parse_tag_assign_eof(Stream *p_stream, int &line, String &r_err_str, Tag& r_tag, String &r_assign, Variant &r_value,ResourceParser *p_res_parser=NULL,bool p_simple_tag=false);
+
+ static Error parse_value(Token& token,Variant &value, Stream *p_stream, int &line, String &r_err_str,ResourceParser *p_res_parser=NULL);
+ static Error get_token(Stream *p_stream,Token& r_token,int &line,String &r_err_str);
+ static Error parse(Stream *p_stream, Variant &r_ret, String &r_err_str, int &r_err_line,ResourceParser *p_res_parser=NULL);
+};
+
+
+
+
+class VariantWriter {
+public:
+
+ typedef Error (*StoreStringFunc)(void *ud,const String& p_string);
+ typedef String (*EncodeResourceFunc)(void *ud,const RES& p_resource);
+
+ static Error write(const Variant& p_variant, StoreStringFunc p_store_string_func, void *p_store_string_ud,EncodeResourceFunc p_encode_res_func,void* p_encode_res_ud);
+ static Error write_to_string(const Variant& p_variant, String& r_string, EncodeResourceFunc p_encode_res_func=NULL,void* p_encode_res_ud=NULL);
+
+
+};
+
+
+
+
+
+
+#endif // VARIANT_PARSER_H
diff --git a/core/vector.h b/core/vector.h
index b93d9a0dea..641721f401 100644
--- a/core/vector.h
+++ b/core/vector.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -42,7 +42,7 @@
template<class T>
class Vector {
- mutable void* _ptr;
+ mutable T* _ptr;
// internal helpers
@@ -51,21 +51,21 @@ class Vector {
if (!_ptr)
return NULL;
- return reinterpret_cast<SafeRefCount*>(_ptr);
+ return reinterpret_cast<SafeRefCount*>((uint8_t*)_ptr-sizeof(int)-sizeof(SafeRefCount));
}
_FORCE_INLINE_ int* _get_size() const {
if (!_ptr)
return NULL;
- return reinterpret_cast<int*>(((uint8_t*)(_ptr))+sizeof(SafeRefCount));
+ return reinterpret_cast<int*>((uint8_t*)_ptr-sizeof(int));
}
_FORCE_INLINE_ T* _get_data() const {
if (!_ptr)
return NULL;
- return reinterpret_cast<T*>(((uint8_t*)(_ptr))+sizeof(SafeRefCount)+sizeof(int));
+ return reinterpret_cast<T*>(_ptr);
}
@@ -88,11 +88,11 @@ public:
_FORCE_INLINE_ void clear() { resize(0); }
_FORCE_INLINE_ int size() const {
-
- if (!_ptr)
- return 0;
+ int* size = _get_size();
+ if (size)
+ return *size;
else
- return *reinterpret_cast<int*>(((uint8_t*)(_ptr))+sizeof(SafeRefCount));
+ return 0;
}
_FORCE_INLINE_ bool empty() const { return _ptr == 0; }
Error resize(int p_size);
@@ -174,7 +174,7 @@ void Vector<T>::_unref(void *p_data) {
if (!p_data)
return;
- SafeRefCount *src = reinterpret_cast<SafeRefCount*>(p_data);
+ SafeRefCount *src = reinterpret_cast<SafeRefCount*>((uint8_t*)p_data-sizeof(int)-sizeof(SafeRefCount));
if (!src->unref())
return; // still in use
@@ -189,7 +189,7 @@ void Vector<T>::_unref(void *p_data) {
}
// free mem
- memfree(p_data);
+ memfree((uint8_t*)p_data-sizeof(int)-sizeof(SafeRefCount));
}
@@ -201,7 +201,8 @@ void Vector<T>::_copy_on_write() {
if (_get_refcount()->get() > 1 ) {
/* in use by more than me */
- SafeRefCount *src_new=(SafeRefCount *)memalloc(_get_alloc_size(*_get_size()));
+ void* mem_new = memalloc(_get_alloc_size(*_get_size()));
+ SafeRefCount *src_new=(SafeRefCount *)mem_new;
src_new->init();
int * _size = (int*)(src_new+1);
*_size=*_get_size();
@@ -215,7 +216,7 @@ void Vector<T>::_copy_on_write() {
}
_unref(_ptr);
- _ptr=src_new;
+ _ptr=_data;
}
}
@@ -260,16 +261,17 @@ Error Vector<T>::resize(int p_size) {
if (size()==0) {
// alloc from scratch
- _ptr = (T*)memalloc(_get_alloc_size(p_size));
- ERR_FAIL_COND_V( !_ptr ,ERR_OUT_OF_MEMORY);
+ void* ptr=memalloc(_get_alloc_size(p_size));
+ ERR_FAIL_COND_V( !ptr ,ERR_OUT_OF_MEMORY);
+ _ptr=(T*)((uint8_t*)ptr+sizeof(int)+sizeof(SafeRefCount));
_get_refcount()->init(); // init refcount
*_get_size()=0; // init size (currently, none)
} else {
- void *_ptrnew = (T*)memrealloc(_ptr,_get_alloc_size(p_size));
+ void *_ptrnew = (T*)memrealloc((uint8_t*)_ptr-sizeof(int)-sizeof(SafeRefCount),_get_alloc_size(p_size));
ERR_FAIL_COND_V( !_ptrnew ,ERR_OUT_OF_MEMORY);
- _ptr=_ptrnew;
+ _ptr=(T*)((uint8_t*)_ptrnew+sizeof(int)+sizeof(SafeRefCount));
}
// construct the newly created elements
@@ -291,10 +293,10 @@ Error Vector<T>::resize(int p_size) {
t->~T();
}
- void *_ptrnew = (T*)memrealloc(_ptr,_get_alloc_size(p_size));
+ void *_ptrnew = (T*)memrealloc((uint8_t*)_ptr-sizeof(int)-sizeof(SafeRefCount),_get_alloc_size(p_size));
ERR_FAIL_COND_V( !_ptrnew ,ERR_OUT_OF_MEMORY);
- _ptr=_ptrnew;
+ _ptr=(T*)((uint8_t*)_ptrnew+sizeof(int)+sizeof(SafeRefCount));
*_get_size()=p_size;
@@ -340,12 +342,14 @@ template<class T>
void Vector<T>::remove(int p_index) {
ERR_FAIL_INDEX(p_index, size());
- for (int i=p_index; i<size()-1; i++) {
+ T*p=ptr();
+ int len=size();
+ for (int i=p_index; i<len-1; i++) {
- set(i, get(i+1));
+ p[i]=p[i+1];
};
- resize(size()-1);
+ resize(len-1);
};
template<class T>
diff --git a/core/vmap.cpp b/core/vmap.cpp
index 32481eb9eb..e94198257a 100644
--- a/core/vmap.cpp
+++ b/core/vmap.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/vmap.h b/core/vmap.h
index 5ff8f73978..6880abf260 100644
--- a/core/vmap.h
+++ b/core/vmap.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/vset.cpp b/core/vset.cpp
index c849bf3367..cefafeb073 100644
--- a/core/vset.cpp
+++ b/core/vset.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/core/vset.h b/core/vset.h
index e1e02ab435..cafcb0bb2f 100644
--- a/core/vset.h
+++ b/core/vset.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/demos/2d/area_input/engine.cfg b/demos/2d/area_input/engine.cfg
index 3227e9278f..8fa2e15beb 100644
--- a/demos/2d/area_input/engine.cfg
+++ b/demos/2d/area_input/engine.cfg
@@ -2,3 +2,4 @@
name="Area 2D Input Events"
main_scene="res://input.scn"
+icon="res://icon.png"
diff --git a/demos/2d/area_input/icon.png b/demos/2d/area_input/icon.png
new file mode 100644
index 0000000000..2f412ecf68
--- /dev/null
+++ b/demos/2d/area_input/icon.png
Binary files differ
diff --git a/demos/2d/area_input/input.gd b/demos/2d/area_input/input.gd
index 3f719fc853..e9cc9f3c1d 100644
--- a/demos/2d/area_input/input.gd
+++ b/demos/2d/area_input/input.gd
@@ -1,16 +1,15 @@
extends Area2D
-#virtual from CollisionObject2D (also available as signal)
+
+# Virtual from CollisionObject2D (also available as signal)
func _input_event(viewport, event, shape_idx):
- #convert event to local coordinates
- if (event.type==InputEvent.MOUSE_MOTION):
- event = make_input_local( event )
+ # Convert event to local coordinates
+ if (event.type == InputEvent.MOUSE_MOTION):
+ event = make_input_local(event)
get_node("label").set_text(str(event.pos))
-
-#virtual from CollisionObject2D (also available as signal)
-func _mouse_exit():
- get_node("label").set_text("")
-
+# Virtual from CollisionObject2D (also available as signal)
+func _mouse_exit():
+ get_node("label").set_text("")
diff --git a/demos/2d/area_input/input.scn b/demos/2d/area_input/input.scn
index 1a2dcbc5f4..f3a19f64da 100644
--- a/demos/2d/area_input/input.scn
+++ b/demos/2d/area_input/input.scn
Binary files differ
diff --git a/demos/2d/dynamic_collision_shapes/ball.gd b/demos/2d/dynamic_collision_shapes/ball.gd
new file mode 100644
index 0000000000..169079ea46
--- /dev/null
+++ b/demos/2d/dynamic_collision_shapes/ball.gd
@@ -0,0 +1,17 @@
+
+extends RigidBody2D
+
+# Member variables
+var timeout = 5
+
+
+func _process(delta):
+ timeout -= delta
+ if (timeout < 1):
+ set_opacity(timeout)
+ if (timeout < 0):
+ queue_free()
+
+
+func _ready():
+ set_process(true)
diff --git a/demos/2d/dynamic_collision_shapes/ball.png b/demos/2d/dynamic_collision_shapes/ball.png
new file mode 100644
index 0000000000..b7cf71da29
--- /dev/null
+++ b/demos/2d/dynamic_collision_shapes/ball.png
Binary files differ
diff --git a/demos/2d/dynamic_collision_shapes/ball.scn b/demos/2d/dynamic_collision_shapes/ball.scn
new file mode 100644
index 0000000000..51a91d5bc0
--- /dev/null
+++ b/demos/2d/dynamic_collision_shapes/ball.scn
Binary files differ
diff --git a/demos/2d/dynamic_collision_shapes/box.png b/demos/2d/dynamic_collision_shapes/box.png
new file mode 100644
index 0000000000..f29b83ce38
--- /dev/null
+++ b/demos/2d/dynamic_collision_shapes/box.png
Binary files differ
diff --git a/demos/2d/dynamic_collision_shapes/circle.png b/demos/2d/dynamic_collision_shapes/circle.png
new file mode 100644
index 0000000000..9fdfa550b1
--- /dev/null
+++ b/demos/2d/dynamic_collision_shapes/circle.png
Binary files differ
diff --git a/demos/2d/dynamic_collision_shapes/dynamic_colobjs.gd b/demos/2d/dynamic_collision_shapes/dynamic_colobjs.gd
new file mode 100644
index 0000000000..25db51642b
--- /dev/null
+++ b/demos/2d/dynamic_collision_shapes/dynamic_colobjs.gd
@@ -0,0 +1,19 @@
+
+extends Node2D
+
+# Member variables
+const EMIT_INTERVAL = 0.1
+var timeout = EMIT_INTERVAL
+
+
+func _process(delta):
+ timeout -= delta
+ if (timeout < 0):
+ timeout = EMIT_INTERVAL
+ var ball = preload("res://ball.scn").instance()
+ ball.set_pos(Vector2(randf()*get_viewport_rect().size.x, 0))
+ add_child(ball)
+
+
+func _ready():
+ set_process(true)
diff --git a/demos/2d/dynamic_collision_shapes/dynamic_colobjs.scn b/demos/2d/dynamic_collision_shapes/dynamic_colobjs.scn
new file mode 100644
index 0000000000..6d17e2209f
--- /dev/null
+++ b/demos/2d/dynamic_collision_shapes/dynamic_colobjs.scn
Binary files differ
diff --git a/demos/2d/dynamic_collision_shapes/engine.cfg b/demos/2d/dynamic_collision_shapes/engine.cfg
new file mode 100644
index 0000000000..76a074f346
--- /dev/null
+++ b/demos/2d/dynamic_collision_shapes/engine.cfg
@@ -0,0 +1,5 @@
+[application]
+
+name="Run-Time CollisionShape"
+main_scene="res://dynamic_colobjs.scn"
+icon="res://icon.png"
diff --git a/demos/2d/dynamic_collision_shapes/icon.png b/demos/2d/dynamic_collision_shapes/icon.png
new file mode 100644
index 0000000000..b47506d7c8
--- /dev/null
+++ b/demos/2d/dynamic_collision_shapes/icon.png
Binary files differ
diff --git a/demos/2d/dynamic_collision_shapes/poly.png b/demos/2d/dynamic_collision_shapes/poly.png
new file mode 100644
index 0000000000..49ed55cc7d
--- /dev/null
+++ b/demos/2d/dynamic_collision_shapes/poly.png
Binary files differ
diff --git a/demos/2d/fog_of_war/engine.cfg b/demos/2d/fog_of_war/engine.cfg
index 5c4307b5bc..1f56851c58 100644
--- a/demos/2d/fog_of_war/engine.cfg
+++ b/demos/2d/fog_of_war/engine.cfg
@@ -2,7 +2,7 @@
name="Fog of War"
main_scene="res://fog.scn"
-icon="icon.png"
+icon="res://icon.png"
[input]
diff --git a/demos/2d/fog_of_war/fog.gd b/demos/2d/fog_of_war/fog.gd
index 9da5680e4d..3ac8df0e17 100644
--- a/demos/2d/fog_of_war/fog.gd
+++ b/demos/2d/fog_of_war/fog.gd
@@ -1,86 +1,78 @@
extends TileMap
-# member variables here, example:
-# var a=2
-# var b="textvar"
+# Member variables
-# boundarys for the fog rectangle
-var x_min = -20 # left start tile
-var x_max = 20 # right end tile
-var y_min = -20 # top start tile
-var y_max = 20 # bottom end tile
+# Boundaries for the fog rectangle
+var x_min = -20 # Left start tile
+var x_max = 20 # Right end tile
+var y_min = -20 # Top start tile
+var y_max = 20 # Bottom end tile
-var position # players position
+var position # Player's position
-# iteration variables
+# Iteration variables
var x
var y
-# variable to check if player moved
+# Variables to check if the player moved
var x_old
var y_old
-# array to build up the visible area like a square
-# first value determines the width/height of the tip
-# here it would be 2*2 + 1 = 5 tiles wide/high
-# second value determines the total squares size
-# here it would be 5*2 + 1 = 10 tiles wide/high
-var l = range(2,5)
+# Array to build up the visible area like a square.
+# First value determines the width/height of the tip.
+# Here it would be 2*2 + 1 = 5 tiles wide/high.
+# Second value determines the total squares size.
+# Here it would be 5*2 + 1 = 10 tiles wide/high.
+var l = range(2, 5)
-# process that runs in realtime
+
+# Process that runs in realtime
func _fixed_process(delta):
position = get_node("../troll").get_pos()
- # calculate the corresponding tile
+ # Calculate the corresponding tile
# from the players position
x = int(position.x/get_cell_size().x)
- # switching from positive to negative tile positions
+ # Switching from positive to negative tile positions
# causes problems because of rounding problems
if position.x < 0:
- x -= 1 # correct negative values
+ x -= 1 # Correct negative values
y = int(position.y/get_cell_size().y)
- if position.y < 0:
+ if (position.y < 0):
y -= 1
-
- # check if the player moved one tile further
- if (x_old != x) or (y_old != y):
-
- # create the transparent part (visited area)
- var end = l.size()-1
+
+ # Check if the player moved one tile further
+ if ((x_old != x) or (y_old != y)):
+ # Create the transparent part (visited area)
+ var end = l.size() - 1
var start = 0
for steps in range(l.size()):
- for m in range(x-l[end]-1,x+l[end]+2):
- for n in range(y-l[start]-1,y+l[start]+2):
- if get_cell(m,n) != 0:
- set_cell(m,n,1,0,0)
+ for m in range(x - l[end] - 1, x + l[end] + 2):
+ for n in range(y - l[start] - 1, y + l[start] + 2):
+ if (get_cell(m, n) != 0):
+ set_cell(m, n, 1, 0, 0)
end -= 1
start += 1
-
- # create the actual and active visible part
- var end = l.size()-1
+
+ # Create the actual and active visible part
+ var end = l.size() - 1
var start = 0
for steps in range(l.size()):
- for m in range(x-l[end],x+l[end]+1):
- for n in range(y-l[start],y+l[start]+1):
- set_cell(m,n,-1)
+ for m in range(x - l[end], x + l[end] + 1):
+ for n in range(y - l[start], y + l[start] + 1):
+ set_cell(m, n, -1)
end -= 1
start += 1
-
+
x_old = x
y_old = y
-
- pass
+
func _ready():
- # Initalization here
-
- # create a square filled with the 100% opaque fog
- for x in range(x_min,x_max):
- for y in range(y_min,y_max):
- set_cell(x,y,0,0,0)
+ # Create a square filled with the 100% opaque fog
+ for x in range(x_min, x_max):
+ for y in range(y_min, y_max):
+ set_cell(x, y, 0, 0, 0)
set_fixed_process(true)
- pass
-
-
diff --git a/demos/2d/fog_of_war/fog.scn b/demos/2d/fog_of_war/fog.scn
index 4987f1ead5..cf19601567 100644
--- a/demos/2d/fog_of_war/fog.scn
+++ b/demos/2d/fog_of_war/fog.scn
Binary files differ
diff --git a/demos/2d/fog_of_war/icon.png.flags b/demos/2d/fog_of_war/icon.png.flags
deleted file mode 100644
index dbef2209e8..0000000000
--- a/demos/2d/fog_of_war/icon.png.flags
+++ /dev/null
@@ -1 +0,0 @@
-gen_mipmaps=true
diff --git a/demos/2d/fog_of_war/tile_edit.scn b/demos/2d/fog_of_war/tile_edit.scn
index aaca19d370..3eddf38e48 100644
--- a/demos/2d/fog_of_war/tile_edit.scn
+++ b/demos/2d/fog_of_war/tile_edit.scn
Binary files differ
diff --git a/demos/2d/fog_of_war/troll.gd b/demos/2d/fog_of_war/troll.gd
index d118d3a2ba..6f40072e84 100644
--- a/demos/2d/fog_of_war/troll.gd
+++ b/demos/2d/fog_of_war/troll.gd
@@ -2,42 +2,37 @@
extends KinematicBody2D
# This is a simple collision demo showing how
-# the kinematic cotroller works.
+# the kinematic controller works.
# move() will allow to move the node, and will
-# always move it to a non-colliding spot,
+# always move it to a non-colliding spot,
# as long as it starts from a non-colliding spot too.
+# Member variables
+const MOTION_SPEED = 160 # Pixels/second
-#pixels / second
-const MOTION_SPEED=160
func _fixed_process(delta):
-
var motion = Vector2()
if (Input.is_action_pressed("move_up")):
- motion+=Vector2(0,-1)
+ motion += Vector2(0, -1)
if (Input.is_action_pressed("move_bottom")):
- motion+=Vector2(0,1)
+ motion += Vector2(0, 1)
if (Input.is_action_pressed("move_left")):
- motion+=Vector2(-1,0)
+ motion += Vector2(-1, 0)
if (Input.is_action_pressed("move_right")):
- motion+=Vector2(1,0)
+ motion += Vector2(1, 0)
- motion = motion.normalized() * MOTION_SPEED * delta
+ motion = motion.normalized()*MOTION_SPEED*delta
motion = move(motion)
- #make character slide nicely through the world
+ # Make character slide nicely through the world
var slide_attempts = 4
- while(is_colliding() and slide_attempts>0):
+ while(is_colliding() and slide_attempts > 0):
motion = get_collision_normal().slide(motion)
- motion=move(motion)
- slide_attempts-=1
-
+ motion = move(motion)
+ slide_attempts -= 1
+
func _ready():
- # Initalization here
set_fixed_process(true)
- pass
-
-
diff --git a/demos/2d/fog_of_war/troll.scn b/demos/2d/fog_of_war/troll.scn
index f5d87c3631..ab9af17221 100644
--- a/demos/2d/fog_of_war/troll.scn
+++ b/demos/2d/fog_of_war/troll.scn
Binary files differ
diff --git a/demos/2d/hdr/beach_cave.gd b/demos/2d/hdr/beach_cave.gd
index 9dffbc4662..fcc878e565 100644
--- a/demos/2d/hdr/beach_cave.gd
+++ b/demos/2d/hdr/beach_cave.gd
@@ -1,26 +1,21 @@
extends Node2D
-# member variables here, example:
-# var a=2
-# var b="textvar"
-const CAVE_LIMIT=1000
+# Member variables
+const CAVE_LIMIT = 1000
-func _input(ev):
- if (ev.type==InputEvent.MOUSE_MOTION and ev.button_mask&1):
- var rel_x = ev.relative_x
+
+func _input(event):
+ if (event.type == InputEvent.MOUSE_MOTION and event.button_mask&1):
+ var rel_x = event.relative_x
var cavepos = get_node("cave").get_pos()
- cavepos.x+=rel_x
- if (cavepos.x<-CAVE_LIMIT):
- cavepos.x=-CAVE_LIMIT
- elif (cavepos.x>0):
- cavepos.x=0
+ cavepos.x += rel_x
+ if (cavepos.x < -CAVE_LIMIT):
+ cavepos.x = -CAVE_LIMIT
+ elif (cavepos.x > 0):
+ cavepos.x = 0
get_node("cave").set_pos(cavepos)
-
+
func _ready():
set_process_input(true)
- # Initialization here
- pass
-
-
diff --git a/demos/2d/hdr/beach_cave.scn b/demos/2d/hdr/beach_cave.scn
index 4147a130ad..6a4108e7a5 100644
--- a/demos/2d/hdr/beach_cave.scn
+++ b/demos/2d/hdr/beach_cave.scn
Binary files differ
diff --git a/demos/2d/hdr/engine.cfg b/demos/2d/hdr/engine.cfg
index 3d8b4222d5..ab53a022f0 100644
--- a/demos/2d/hdr/engine.cfg
+++ b/demos/2d/hdr/engine.cfg
@@ -2,6 +2,7 @@
name="HDR for 2D"
main_scene="res://beach_cave.scn"
+icon="res://icon.png"
[display]
diff --git a/demos/2d/hdr/icon.png b/demos/2d/hdr/icon.png
new file mode 100644
index 0000000000..461cd4638a
--- /dev/null
+++ b/demos/2d/hdr/icon.png
Binary files differ
diff --git a/demos/2d/hexamap/map.scn b/demos/2d/hexamap/map.scn
index 5798aab850..de49527003 100644
--- a/demos/2d/hexamap/map.scn
+++ b/demos/2d/hexamap/map.scn
Binary files differ
diff --git a/demos/2d/hexamap/tiles.scn b/demos/2d/hexamap/tiles.scn
index 265aedac2b..a019bbb92d 100644
--- a/demos/2d/hexamap/tiles.scn
+++ b/demos/2d/hexamap/tiles.scn
Binary files differ
diff --git a/demos/2d/hexamap/troll.gd b/demos/2d/hexamap/troll.gd
index d118d3a2ba..82938fdf10 100644
--- a/demos/2d/hexamap/troll.gd
+++ b/demos/2d/hexamap/troll.gd
@@ -2,42 +2,37 @@
extends KinematicBody2D
# This is a simple collision demo showing how
-# the kinematic cotroller works.
+# the kinematic controller works.
# move() will allow to move the node, and will
# always move it to a non-colliding spot,
# as long as it starts from a non-colliding spot too.
+# Member variables
+const MOTION_SPEED = 160 # Pixels/second
-#pixels / second
-const MOTION_SPEED=160
func _fixed_process(delta):
-
var motion = Vector2()
if (Input.is_action_pressed("move_up")):
- motion+=Vector2(0,-1)
+ motion += Vector2(0, -1)
if (Input.is_action_pressed("move_bottom")):
- motion+=Vector2(0,1)
+ motion += Vector2(0, 1)
if (Input.is_action_pressed("move_left")):
- motion+=Vector2(-1,0)
+ motion += Vector2(-1, 0)
if (Input.is_action_pressed("move_right")):
- motion+=Vector2(1,0)
+ motion += Vector2(1, 0)
- motion = motion.normalized() * MOTION_SPEED * delta
+ motion = motion.normalized()*MOTION_SPEED*delta
motion = move(motion)
- #make character slide nicely through the world
+ # Make character slide nicely through the world
var slide_attempts = 4
- while(is_colliding() and slide_attempts>0):
+ while(is_colliding() and slide_attempts > 0):
motion = get_collision_normal().slide(motion)
- motion=move(motion)
- slide_attempts-=1
-
+ motion = move(motion)
+ slide_attempts -= 1
+
func _ready():
- # Initalization here
set_fixed_process(true)
- pass
-
-
diff --git a/demos/2d/hexamap/troll.scn b/demos/2d/hexamap/troll.scn
index f5d87c3631..1f33dabf8e 100644
--- a/demos/2d/hexamap/troll.scn
+++ b/demos/2d/hexamap/troll.scn
Binary files differ
diff --git a/demos/2d/isometric/dungeon.scn b/demos/2d/isometric/dungeon.scn
index 64efc257c0..8f0f316d73 100644
--- a/demos/2d/isometric/dungeon.scn
+++ b/demos/2d/isometric/dungeon.scn
Binary files differ
diff --git a/demos/2d/isometric/tileset.scn b/demos/2d/isometric/tileset.scn
index c04ea5382c..e487285f83 100644
--- a/demos/2d/isometric/tileset.scn
+++ b/demos/2d/isometric/tileset.scn
Binary files differ
diff --git a/demos/2d/isometric/troll.gd b/demos/2d/isometric/troll.gd
index d118d3a2ba..d8d4880df1 100644
--- a/demos/2d/isometric/troll.gd
+++ b/demos/2d/isometric/troll.gd
@@ -2,42 +2,37 @@
extends KinematicBody2D
# This is a simple collision demo showing how
-# the kinematic cotroller works.
+# the kinematic controller works.
# move() will allow to move the node, and will
# always move it to a non-colliding spot,
# as long as it starts from a non-colliding spot too.
+# Member variables
+const MOTION_SPEED = 160 # Pixels/seconds
-#pixels / second
-const MOTION_SPEED=160
func _fixed_process(delta):
-
var motion = Vector2()
if (Input.is_action_pressed("move_up")):
- motion+=Vector2(0,-1)
+ motion += Vector2(0, -1)
if (Input.is_action_pressed("move_bottom")):
- motion+=Vector2(0,1)
+ motion += Vector2(0, 1)
if (Input.is_action_pressed("move_left")):
- motion+=Vector2(-1,0)
+ motion += Vector2(-1, 0)
if (Input.is_action_pressed("move_right")):
- motion+=Vector2(1,0)
+ motion += Vector2(1, 0)
- motion = motion.normalized() * MOTION_SPEED * delta
+ motion = motion.normalized()*MOTION_SPEED*delta
motion = move(motion)
- #make character slide nicely through the world
+ # Make character slide nicely through the world
var slide_attempts = 4
- while(is_colliding() and slide_attempts>0):
+ while(is_colliding() and slide_attempts > 0):
motion = get_collision_normal().slide(motion)
- motion=move(motion)
- slide_attempts-=1
-
+ motion = move(motion)
+ slide_attempts -= 1
+
func _ready():
- # Initalization here
set_fixed_process(true)
- pass
-
-
diff --git a/demos/2d/isometric/troll.scn b/demos/2d/isometric/troll.scn
index 19b566fe05..d53aac4fbf 100644
--- a/demos/2d/isometric/troll.scn
+++ b/demos/2d/isometric/troll.scn
Binary files differ
diff --git a/demos/2d/isometric_light/column.scn b/demos/2d/isometric_light/column.scn
index f0b7683885..03f3c2c976 100644
--- a/demos/2d/isometric_light/column.scn
+++ b/demos/2d/isometric_light/column.scn
Binary files differ
diff --git a/demos/2d/isometric_light/cubio.gd b/demos/2d/isometric_light/cubio.gd
index 30c766936c..508cd3728c 100644
--- a/demos/2d/isometric_light/cubio.gd
+++ b/demos/2d/isometric_light/cubio.gd
@@ -1,96 +1,85 @@
extends KinematicBody2D
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
+# Member variables
const MAX_SPEED = 300.0
const IDLE_SPEED = 10.0
-const ACCEL=5.0
-const VSCALE=0.5
-const SHOOT_INTERVAL=0.3
+const ACCEL = 5.0
+const VSCALE = 0.5
+const SHOOT_INTERVAL = 0.3
+
+var speed = Vector2()
+var current_anim = ""
+var current_mirror = false
-var speed=Vector2()
-var current_anim=""
-var current_mirror=false
+var shoot_countdown = 0
-var shoot_countdown=0
-func _input(ev):
- if (ev.type==InputEvent.MOUSE_BUTTON and ev.button_index==1 and ev.pressed and shoot_countdown<=0):
- var pos = get_canvas_transform().affine_inverse() * ev.pos
- var dir = (pos-get_global_pos()).normalized()
+func _input(event):
+ if (event.type == InputEvent.MOUSE_BUTTON and event.button_index == 1 and event.pressed and shoot_countdown <= 0):
+ var pos = get_canvas_transform().affine_inverse()*event.pos
+ var dir = (pos - get_global_pos()).normalized()
var bullet = preload("res://shoot.scn").instance()
- bullet.advance_dir=dir
- bullet.set_pos( get_global_pos() + dir * 60 )
+ bullet.advance_dir = dir
+ bullet.set_pos(get_global_pos() + dir*60)
get_parent().add_child(bullet)
- shoot_countdown=SHOOT_INTERVAL
-
-
-
+ shoot_countdown = SHOOT_INTERVAL
+
func _fixed_process(delta):
-
- shoot_countdown-=delta
+ shoot_countdown -= delta
var dir = Vector2()
if (Input.is_action_pressed("up")):
- dir+=Vector2(0,-1)
+ dir += Vector2(0, -1)
if (Input.is_action_pressed("down")):
- dir+=Vector2(0,1)
+ dir += Vector2(0, 1)
if (Input.is_action_pressed("left")):
- dir+=Vector2(-1,0)
+ dir += Vector2(-1, 0)
if (Input.is_action_pressed("right")):
- dir+=Vector2(1,0)
-
- if (dir!=Vector2()):
- dir=dir.normalized()
- speed = speed.linear_interpolate(dir*MAX_SPEED,delta*ACCEL)
- var motion = speed * delta
- motion.y*=VSCALE
- motion=move(motion)
+ dir += Vector2(1, 0)
+
+ if (dir != Vector2()):
+ dir = dir.normalized()
+ speed = speed.linear_interpolate(dir*MAX_SPEED, delta*ACCEL)
+ var motion = speed*delta
+ motion.y *= VSCALE
+ motion = move(motion)
if (is_colliding()):
var n = get_collision_normal()
- motion=n.slide(motion)
+ motion = n.slide(motion)
move(motion)
- var next_anim=""
- var next_mirror=false
+ var next_anim = ""
+ var next_mirror = false
- if (dir==Vector2() and speed.length()<IDLE_SPEED):
- next_anim="idle"
- next_mirror=false
- elif (speed.length()>IDLE_SPEED*0.1):
- var angle = atan2(abs(speed.x),speed.y)
+ if (dir == Vector2() and speed.length() < IDLE_SPEED):
+ next_anim = "idle"
+ next_mirror = false
+ elif (speed.length() > IDLE_SPEED*0.1):
+ var angle = atan2(abs(speed.x), speed.y)
- next_mirror = speed.x>0
- if (angle<PI/8):
- next_anim="bottom"
- next_mirror=false
- elif (angle<PI/4+PI/8):
- next_anim="bottom_left"
- elif (angle<PI*2/4+PI/8):
- next_anim="left"
- elif (angle<PI*3/4+PI/8):
- next_anim="top_left"
+ next_mirror = speed.x > 0
+ if (angle < PI/8):
+ next_anim = "bottom"
+ next_mirror = false
+ elif (angle < PI/4 + PI/8):
+ next_anim = "bottom_left"
+ elif (angle < PI*2/4 + PI/8):
+ next_anim = "left"
+ elif (angle < PI*3/4 + PI/8):
+ next_anim = "top_left"
else:
- next_anim="top"
- next_mirror=false
-
-
- if (next_anim!=current_anim or next_mirror!=current_mirror):
+ next_anim = "top"
+ next_mirror = false
+
+ if (next_anim != current_anim or next_mirror != current_mirror):
get_node("frames").set_flip_h(next_mirror)
get_node("anim").play(next_anim)
- current_anim=next_anim
- current_mirror=next_mirror
-
+ current_anim = next_anim
+ current_mirror = next_mirror
func _ready():
- # Initialization here
set_fixed_process(true)
set_process_input(true)
- pass
-
-
diff --git a/demos/2d/isometric_light/cubio.scn b/demos/2d/isometric_light/cubio.scn
index fc931b0c8d..55e2185247 100644
--- a/demos/2d/isometric_light/cubio.scn
+++ b/demos/2d/isometric_light/cubio.scn
Binary files differ
diff --git a/demos/2d/isometric_light/engine.cfg b/demos/2d/isometric_light/engine.cfg
index 08393f1724..a5b053aa95 100644
--- a/demos/2d/isometric_light/engine.cfg
+++ b/demos/2d/isometric_light/engine.cfg
@@ -2,6 +2,7 @@
name="Isometric 2D + Lighting"
main_scene="res://map.scn"
+icon="res://icon.png"
[input]
diff --git a/demos/2d/isometric_light/icon.png b/demos/2d/isometric_light/icon.png
new file mode 100644
index 0000000000..0801f78ea5
--- /dev/null
+++ b/demos/2d/isometric_light/icon.png
Binary files differ
diff --git a/demos/2d/isometric_light/map.gd b/demos/2d/isometric_light/map.gd
index f712aeeaec..6b790ddf1c 100644
--- a/demos/2d/isometric_light/map.gd
+++ b/demos/2d/isometric_light/map.gd
@@ -1,18 +1,7 @@
extends Node2D
-# member variables here, example:
-# var a=2
-# var b="textvar"
-func _ready():
- # Initialization here
- pass
-
-
-
-
-func _on_prince_area_body_enter( body ):
- if (body.get_name()=="cubio"):
+func _on_prince_area_body_enter(body):
+ if (body.get_name() == "cubio"):
get_node("message").show()
- pass # replace with function body
diff --git a/demos/2d/isometric_light/map.scn b/demos/2d/isometric_light/map.scn
index 89002f991f..da3fc5654f 100644
--- a/demos/2d/isometric_light/map.scn
+++ b/demos/2d/isometric_light/map.scn
Binary files differ
diff --git a/demos/2d/isometric_light/shoot.gd b/demos/2d/isometric_light/shoot.gd
index 0486bbb658..b48d4ad34b 100644
--- a/demos/2d/isometric_light/shoot.gd
+++ b/demos/2d/isometric_light/shoot.gd
@@ -1,27 +1,21 @@
extends KinematicBody2D
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
-var advance_dir=Vector2(1,0)
+# Member variables
const ADVANCE_SPEED = 500.0
-var hit=false
+var advance_dir = Vector2(1, 0)
+var hit = false
+
func _fixed_process(delta):
-
if (hit):
return
- move(advance_dir*delta*ADVANCE_SPEED)
+ move(advance_dir*delta*ADVANCE_SPEED)
if (is_colliding()):
get_node("anim").play("explode")
- hit=true
+ hit = true
+
func _ready():
- # Initialization here
set_fixed_process(true)
- pass
-
-
diff --git a/demos/2d/isometric_light/shoot.scn b/demos/2d/isometric_light/shoot.scn
index 672608810f..6909ae0c71 100644
--- a/demos/2d/isometric_light/shoot.scn
+++ b/demos/2d/isometric_light/shoot.scn
Binary files differ
diff --git a/demos/2d/isometric_light/tileset_scene.scn b/demos/2d/isometric_light/tileset_scene.scn
index 3d0773c9c5..4841cc18a7 100644
--- a/demos/2d/isometric_light/tileset_scene.scn
+++ b/demos/2d/isometric_light/tileset_scene.scn
Binary files differ
diff --git a/demos/2d/isometric_light/torch.scn b/demos/2d/isometric_light/torch.scn
index 3f08b33311..9d6a8e2eae 100644
--- a/demos/2d/isometric_light/torch.scn
+++ b/demos/2d/isometric_light/torch.scn
Binary files differ
diff --git a/demos/2d/kinematic_char/colworld.gd b/demos/2d/kinematic_char/colworld.gd
index fe2dc30bb6..7926ef9d54 100644
--- a/demos/2d/kinematic_char/colworld.gd
+++ b/demos/2d/kinematic_char/colworld.gd
@@ -1,18 +1,8 @@
extends Node2D
-#member variables here, example:
-#var a=2
-#var b="textvar"
-func _ready():
- #Initalization here
- pass
-
-
-
-
-func _on_princess_body_enter( body ):
- #the name of this editor-generated callback is unfortunate
- if (body.get_name()=="player"):
+func _on_princess_body_enter(body):
+ # The name of this editor-generated callback is unfortunate
+ if (body.get_name() == "player"):
get_node("youwin").show()
diff --git a/demos/2d/kinematic_char/colworld.scn b/demos/2d/kinematic_char/colworld.scn
index e66705368d..ff10826563 100644
--- a/demos/2d/kinematic_char/colworld.scn
+++ b/demos/2d/kinematic_char/colworld.scn
Binary files differ
diff --git a/demos/2d/kinematic_char/engine.cfg b/demos/2d/kinematic_char/engine.cfg
index 4ce8f836ae..8bdd5e2fc5 100644
--- a/demos/2d/kinematic_char/engine.cfg
+++ b/demos/2d/kinematic_char/engine.cfg
@@ -1,6 +1,6 @@
[application]
-name="Kinematic Collision"
+name="Kinematic Character"
main_scene="res://colworld.scn"
icon="res://icon.png"
diff --git a/demos/2d/kinematic_char/player.gd b/demos/2d/kinematic_char/player.gd
index 329382408b..2890cc2ce3 100644
--- a/demos/2d/kinematic_char/player.gd
+++ b/demos/2d/kinematic_char/player.gd
@@ -1,137 +1,123 @@
extends KinematicBody2D
-#This is a simple collision demo showing how
-#the kinematic cotroller works.
-#move() will allow to move the node, and will
-#always move it to a non-colliding spot,
-#as long as it starts from a non-colliding spot too.
+# This is a simple collision demo showing how
+# the kinematic controller works.
+# move() will allow to move the node, and will
+# always move it to a non-colliding spot,
+# as long as it starts from a non-colliding spot too.
+# Member variables
+const GRAVITY = 500.0 # Pixels/second
-#pixels / second
-const GRAVITY = 500.0
-
-#Angle in degrees towards either side that the player can
-#consider "floor".
+# Angle in degrees towards either side that the player can consider "floor"
const FLOOR_ANGLE_TOLERANCE = 40
const WALK_FORCE = 600
-const WALK_MIN_SPEED=10
+const WALK_MIN_SPEED = 10
const WALK_MAX_SPEED = 200
const STOP_FORCE = 1300
const JUMP_SPEED = 200
-const JUMP_MAX_AIRBORNE_TIME=0.2
+const JUMP_MAX_AIRBORNE_TIME = 0.2
-const SLIDE_STOP_VELOCITY=1.0 #one pixel per second
-const SLIDE_STOP_MIN_TRAVEL=1.0 #one pixel
+const SLIDE_STOP_VELOCITY = 1.0 # One pixel per second
+const SLIDE_STOP_MIN_TRAVEL = 1.0 # One pixel
var velocity = Vector2()
-var on_air_time=100
-var jumping=false
+var on_air_time = 100
+var jumping = false
-var prev_jump_pressed=false
+var prev_jump_pressed = false
-func _fixed_process(delta):
- #create forces
- var force = Vector2(0,GRAVITY)
+func _fixed_process(delta):
+ # Create forces
+ var force = Vector2(0, GRAVITY)
var walk_left = Input.is_action_pressed("move_left")
var walk_right = Input.is_action_pressed("move_right")
var jump = Input.is_action_pressed("jump")
-
- var stop=true
+
+ var stop = true
if (walk_left):
- if (velocity.x<=WALK_MIN_SPEED and velocity.x > -WALK_MAX_SPEED):
- force.x-=WALK_FORCE
- stop=false
-
+ if (velocity.x <= WALK_MIN_SPEED and velocity.x > -WALK_MAX_SPEED):
+ force.x -= WALK_FORCE
+ stop = false
elif (walk_right):
- if (velocity.x>=-WALK_MIN_SPEED and velocity.x < WALK_MAX_SPEED):
- force.x+=WALK_FORCE
- stop=false
+ if (velocity.x >= -WALK_MIN_SPEED and velocity.x < WALK_MAX_SPEED):
+ force.x += WALK_FORCE
+ stop = false
if (stop):
var vsign = sign(velocity.x)
var vlen = abs(velocity.x)
- vlen -= STOP_FORCE * delta
- if (vlen<0):
- vlen=0
-
- velocity.x=vlen*vsign
+ vlen -= STOP_FORCE*delta
+ if (vlen < 0):
+ vlen = 0
-
-
- #integrate forces to velocity
- velocity += force * delta
+ velocity.x = vlen*vsign
- #integrate velocity into motion and move
- var motion = velocity * delta
-
- #move and consume motion
+ # Integrate forces to velocity
+ velocity += force*delta
+
+ # Integrate velocity into motion and move
+ var motion = velocity*delta
+
+ # Move and consume motion
motion = move(motion)
-
-
- var floor_velocity=Vector2()
-
+
+ var floor_velocity = Vector2()
+
if (is_colliding()):
- # you can check which tile was collision against with this
+ # You can check which tile was collision against with this
# print(get_collider_metadata())
-
- #ran against something, is it the floor? get normal
+
+ # Ran against something, is it the floor? Get normal
var n = get_collision_normal()
-
- if ( rad2deg(acos(n.dot( Vector2(0,-1)))) < FLOOR_ANGLE_TOLERANCE ):
- #if angle to the "up" vectors is < angle tolerance
- #char is on floor
- on_air_time=0
- floor_velocity=get_collider_velocity()
-
-
- if (on_air_time==0 and force.x==0 and get_travel().length() < SLIDE_STOP_MIN_TRAVEL and abs(velocity.x) < SLIDE_STOP_VELOCITY and get_collider_velocity()==Vector2()):
- #Since this formula will always slide the character around,
- #a special case must be considered to to stop it from moving
- #if standing on an inclined floor. Conditions are:
- # 1) Standing on floor (on_air_time==0)
+
+ if (rad2deg(acos(n.dot(Vector2(0, -1)))) < FLOOR_ANGLE_TOLERANCE):
+ # If angle to the "up" vectors is < angle tolerance
+ # char is on floor
+ on_air_time = 0
+ floor_velocity = get_collider_velocity()
+
+ if (on_air_time == 0 and force.x == 0 and get_travel().length() < SLIDE_STOP_MIN_TRAVEL and abs(velocity.x) < SLIDE_STOP_VELOCITY and get_collider_velocity() == Vector2()):
+ # Since this formula will always slide the character around,
+ # a special case must be considered to to stop it from moving
+ # if standing on an inclined floor. Conditions are:
+ # 1) Standing on floor (on_air_time == 0)
# 2) Did not move more than one pixel (get_travel().length() < SLIDE_STOP_MIN_TRAVEL)
# 3) Not moving horizontally (abs(velocity.x) < SLIDE_STOP_VELOCITY)
# 4) Collider is not moving
-
+
revert_motion()
- velocity.y=0.0
-
+ velocity.y = 0.0
else:
- #For every other case of motion,our motion was interrupted.
- #Try to complete the motion by "sliding"
- #by the normal
-
+ # For every other case of motion, our motion was interrupted.
+ # Try to complete the motion by "sliding" by the normal
motion = n.slide(motion)
- velocity = n.slide(velocity)
- #then move again
+ velocity = n.slide(velocity)
+ # Then move again
move(motion)
-
- if (floor_velocity!=Vector2()):
- #if floor moves, move with floor
+
+ if (floor_velocity != Vector2()):
+ # If floor moves, move with floor
move(floor_velocity*delta)
-
- if (jumping and velocity.y>0):
- #if falling, no longer jumping
- jumping=false
-
- if (on_air_time<JUMP_MAX_AIRBORNE_TIME and jump and not prev_jump_pressed and not jumping):
- # Jump must also be allowed to happen if the
- # character left the floor a little bit ago.
+
+ if (jumping and velocity.y > 0):
+ # If falling, no longer jumping
+ jumping = false
+
+ if (on_air_time < JUMP_MAX_AIRBORNE_TIME and jump and not prev_jump_pressed and not jumping):
+ # Jump must also be allowed to happen if the character left the floor a little bit ago.
# Makes controls more snappy.
- velocity.y=-JUMP_SPEED
- jumping=true
-
- on_air_time+=delta
- prev_jump_pressed=jump
+ velocity.y = -JUMP_SPEED
+ jumping = true
+
+ on_air_time += delta
+ prev_jump_pressed = jump
+
func _ready():
- #Initalization here
set_fixed_process(true)
- pass
-
-
diff --git a/demos/2d/kinematic_char/player.scn b/demos/2d/kinematic_char/player.scn
index 5809c0e98a..5ee86ce85d 100644
--- a/demos/2d/kinematic_char/player.scn
+++ b/demos/2d/kinematic_char/player.scn
Binary files differ
diff --git a/demos/2d/kinematic_col/colworld.scn b/demos/2d/kinematic_col/colworld.scn
index 064ff12075..06607b7efd 100644
--- a/demos/2d/kinematic_col/colworld.scn
+++ b/demos/2d/kinematic_col/colworld.scn
Binary files differ
diff --git a/demos/2d/kinematic_col/player.gd b/demos/2d/kinematic_col/player.gd
index 36784a9d9f..ce09e1509e 100644
--- a/demos/2d/kinematic_col/player.gd
+++ b/demos/2d/kinematic_col/player.gd
@@ -2,35 +2,30 @@
extends KinematicBody2D
# This is a simple collision demo showing how
-# the kinematic cotroller works.
+# the kinematic controller works.
# move() will allow to move the node, and will
# always move it to a non-colliding spot,
# as long as it starts from a non-colliding spot too.
+# Member variables
+const MOTION_SPEED = 160 # Pixels/second
-#pixels / second
-const MOTION_SPEED=160
func _fixed_process(delta):
-
var motion = Vector2()
if (Input.is_action_pressed("move_up")):
- motion+=Vector2(0,-1)
+ motion += Vector2(0, -1)
if (Input.is_action_pressed("move_bottom")):
- motion+=Vector2(0,1)
+ motion += Vector2(0, 1)
if (Input.is_action_pressed("move_left")):
- motion+=Vector2(-1,0)
+ motion += Vector2(-1, 0)
if (Input.is_action_pressed("move_right")):
- motion+=Vector2(1,0)
+ motion += Vector2(1, 0)
- motion = motion.normalized() * MOTION_SPEED * delta
+ motion = motion.normalized()*MOTION_SPEED*delta
move(motion)
-
+
func _ready():
- # Initalization here
set_fixed_process(true)
- pass
-
-
diff --git a/demos/2d/kinematic_col/player.scn b/demos/2d/kinematic_col/player.scn
index e558bffe8e..28ad204472 100644
--- a/demos/2d/kinematic_col/player.scn
+++ b/demos/2d/kinematic_col/player.scn
Binary files differ
diff --git a/demos/2d/light_mask/engine.cfg b/demos/2d/light_mask/engine.cfg
index 8b0ae6f61d..39608669ab 100644
--- a/demos/2d/light_mask/engine.cfg
+++ b/demos/2d/light_mask/engine.cfg
@@ -2,6 +2,7 @@
name="Using Lights As Mask"
main_scene="res://lightmask.scn"
+icon="res://icon.png"
[rasterizer]
diff --git a/demos/2d/light_mask/icon.png b/demos/2d/light_mask/icon.png
new file mode 100644
index 0000000000..34a6b709f6
--- /dev/null
+++ b/demos/2d/light_mask/icon.png
Binary files differ
diff --git a/demos/2d/light_mask/lightmask.scn b/demos/2d/light_mask/lightmask.scn
index 08805f44c6..fcf56b5b84 100644
--- a/demos/2d/light_mask/lightmask.scn
+++ b/demos/2d/light_mask/lightmask.scn
Binary files differ
diff --git a/demos/2d/lights_shadows/engine.cfg b/demos/2d/lights_shadows/engine.cfg
index 771288c209..80142633d3 100644
--- a/demos/2d/lights_shadows/engine.cfg
+++ b/demos/2d/lights_shadows/engine.cfg
@@ -2,6 +2,7 @@
name="2D Lighting"
main_scene="res://light_shadows.scn"
+icon="res://icon.png"
[display]
diff --git a/demos/2d/lights_shadows/icon.png b/demos/2d/lights_shadows/icon.png
new file mode 100644
index 0000000000..554f01bb46
--- /dev/null
+++ b/demos/2d/lights_shadows/icon.png
Binary files differ
diff --git a/demos/2d/lights_shadows/light_shadows.scn b/demos/2d/lights_shadows/light_shadows.scn
index a13e31376e..24ccd1e0be 100644
--- a/demos/2d/lights_shadows/light_shadows.scn
+++ b/demos/2d/lights_shadows/light_shadows.scn
Binary files differ
diff --git a/demos/2d/lookat/engine.cfg b/demos/2d/lookat/engine.cfg
index 56917a39ec..81df107f0e 100644
--- a/demos/2d/lookat/engine.cfg
+++ b/demos/2d/lookat/engine.cfg
@@ -2,3 +2,4 @@
name="Look At Pointer"
main_scene="res://lookat.scn"
+icon="res://icon.png"
diff --git a/demos/2d/lookat/icon.png b/demos/2d/lookat/icon.png
new file mode 100644
index 0000000000..442cc1799f
--- /dev/null
+++ b/demos/2d/lookat/icon.png
Binary files differ
diff --git a/demos/2d/lookat/lookat.gd b/demos/2d/lookat/lookat.gd
index 742c5b0671..c45c3ad622 100644
--- a/demos/2d/lookat/lookat.gd
+++ b/demos/2d/lookat/lookat.gd
@@ -1,43 +1,33 @@
extends Sprite
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
-const MODE_DIRECT=0
-const MODE_CONSTANT=1
-const MODE_SMOOTH=2
+# Member variables
+const MODE_DIRECT = 0
+const MODE_CONSTANT = 1
+const MODE_SMOOTH = 2
const ROTATION_SPEED = 1
const SMOOTH_SPEED = 2.0
-export(int,"Direct","Constant","Smooth") var mode=MODE_DIRECT
+export(int, "Direct", "Constant", "Smooth") var mode = MODE_DIRECT
+
func _process(delta):
var mpos = get_viewport().get_mouse_pos()
- if (mode==MODE_DIRECT):
-
+ if (mode == MODE_DIRECT):
look_at(mpos)
-
- elif (mode==MODE_CONSTANT):
-
+ elif (mode == MODE_CONSTANT):
var ang = get_angle_to(mpos)
var s = sign(ang)
- ang=abs(ang)
-
- rotate( min(ang,ROTATION_SPEED*delta)*s )
+ ang = abs(ang)
- elif (mode==MODE_SMOOTH):
-
- var ang = get_angle_to(mpos)
+ rotate(min(ang, ROTATION_SPEED*delta)*s)
+ elif (mode == MODE_SMOOTH):
+ var ang = get_angle_to(mpos)
- rotate( ang*delta*SMOOTH_SPEED )
+ rotate(ang*delta*SMOOTH_SPEED)
+
func _ready():
- # Initialization here
set_process(true)
- pass
-
-
diff --git a/demos/2d/lookat/lookat.scn b/demos/2d/lookat/lookat.scn
index 880070b4c7..66be060c06 100644
--- a/demos/2d/lookat/lookat.scn
+++ b/demos/2d/lookat/lookat.scn
Binary files differ
diff --git a/demos/2d/motion/engine.cfg b/demos/2d/motion/engine.cfg
index 261111904c..6e660572d6 100644
--- a/demos/2d/motion/engine.cfg
+++ b/demos/2d/motion/engine.cfg
@@ -2,6 +2,7 @@
name="Motion Test"
main_scene="res://motion.scn"
+icon="res://icon.png"
[display]
diff --git a/demos/2d/motion/icon.png b/demos/2d/motion/icon.png
new file mode 100644
index 0000000000..9e64961d3c
--- /dev/null
+++ b/demos/2d/motion/icon.png
Binary files differ
diff --git a/demos/2d/motion/motion.gd b/demos/2d/motion/motion.gd
index 8f8f56a889..f9bbd6f90d 100644
--- a/demos/2d/motion/motion.gd
+++ b/demos/2d/motion/motion.gd
@@ -1,38 +1,33 @@
extends Sprite
-
-export var use_idle=true
-
-# member variables here, example:
-# var a=2
-# var b="textvar"
+# Member variables
const BEGIN = -113
const END = 907
-const TIME = 5.0 # seconds
-const SPEED = (END-BEGIN)/TIME
+const TIME = 5.0 # Seconds
+const SPEED = (END - BEGIN)/TIME
+
+export var use_idle = true
+
func _process(delta):
var ofs = get_pos()
- ofs.x+=delta*SPEED
- if (ofs.x>END):
- ofs.x=BEGIN
+ ofs.x += delta*SPEED
+ if (ofs.x > END):
+ ofs.x = BEGIN
set_pos(ofs)
-
+
+
func _fixed_process(delta):
var ofs = get_pos()
- ofs.x+=delta*SPEED
- if (ofs.x>END):
- ofs.x=BEGIN
+ ofs.x += delta*SPEED
+ if (ofs.x > END):
+ ofs.x = BEGIN
set_pos(ofs)
-
+
func _ready():
- # Initialization here
if (use_idle):
set_process(true)
else:
set_fixed_process(true)
- pass
-
-
diff --git a/demos/2d/motion/motion.scn b/demos/2d/motion/motion.scn
index 6c5b5307ac..6e19356674 100644
--- a/demos/2d/motion/motion.scn
+++ b/demos/2d/motion/motion.scn
Binary files differ
diff --git a/demos/2d/navpoly/engine.cfg b/demos/2d/navpoly/engine.cfg
index 40515dd3d2..b750419915 100644
--- a/demos/2d/navpoly/engine.cfg
+++ b/demos/2d/navpoly/engine.cfg
@@ -2,6 +2,7 @@
name="Navigation Polygon (2D)"
main_scene="res://navigation.scn"
+icon="res://icon.png"
[display]
diff --git a/demos/2d/navpoly/icon.png b/demos/2d/navpoly/icon.png
new file mode 100644
index 0000000000..7a28a367c6
--- /dev/null
+++ b/demos/2d/navpoly/icon.png
Binary files differ
diff --git a/demos/2d/navpoly/navigation.gd b/demos/2d/navpoly/navigation.gd
index 9c3dc2921d..4cfa2ad733 100644
--- a/demos/2d/navpoly/navigation.gd
+++ b/demos/2d/navpoly/navigation.gd
@@ -1,63 +1,53 @@
extends Navigation2D
-# member variables here, example:
-# var a=2
-# var b="textvar"
-var begin=Vector2()
-var end=Vector2()
-var path=[]
+# Member variables
+const SPEED = 200.0
-const SPEED=200.0
-
-func _process(delta):
+var begin = Vector2()
+var end = Vector2()
+var path = []
- if (path.size()>1):
-
+func _process(delta):
+ if (path.size() > 1):
var to_walk = delta*SPEED
- while(to_walk>0 and path.size()>=2):
- var pfrom = path[path.size()-1]
- var pto = path[path.size()-2]
+ while(to_walk > 0 and path.size() >= 2):
+ var pfrom = path[path.size() - 1]
+ var pto = path[path.size() - 2]
var d = pfrom.distance_to(pto)
- if (d<=to_walk):
- path.remove(path.size()-1)
- to_walk-=d
+ if (d <= to_walk):
+ path.remove(path.size() - 1)
+ to_walk -= d
else:
- path[path.size()-1] = pfrom.linear_interpolate(pto,to_walk/d)
- to_walk=0
-
- var atpos = path[path.size()-1]
+ path[path.size() - 1] = pfrom.linear_interpolate(pto, to_walk/d)
+ to_walk = 0
+
+ var atpos = path[path.size() - 1]
get_node("agent").set_pos(atpos)
- if (path.size()<2):
- path=[]
+ if (path.size() < 2):
+ path = []
set_process(false)
-
else:
set_process(false)
-
func _update_path():
-
- var p = get_simple_path(begin,end,true)
- path=Array(p) # Vector2array to complex to use, convert to regular array
+ var p = get_simple_path(begin, end, true)
+ path = Array(p) # Vector2array too complex to use, convert to regular array
path.invert()
set_process(true)
-func _input(ev):
- if (ev.type==InputEvent.MOUSE_BUTTON and ev.pressed and ev.button_index==1):
- begin=get_node("agent").get_pos()
- #mouse to local navigatio cooards
- end=ev.pos - get_pos()
+func _input(event):
+ if (event.type == InputEvent.MOUSE_BUTTON and event.pressed and event.button_index == 1):
+ begin = get_node("agent").get_pos()
+ # Mouse to local navigation coordinates
+ end = event.pos - get_pos()
_update_path()
+
func _ready():
- # Initialization here
set_process_input(true)
- pass
-
-
diff --git a/demos/2d/navpoly/navigation.scn b/demos/2d/navpoly/navigation.scn
index 1bb7de391b..c56270bfd3 100644
--- a/demos/2d/navpoly/navigation.scn
+++ b/demos/2d/navpoly/navigation.scn
Binary files differ
diff --git a/demos/2d/navpoly/navigation2.scn b/demos/2d/navpoly/navigation2.scn
deleted file mode 100644
index 224aed73f5..0000000000
--- a/demos/2d/navpoly/navigation2.scn
+++ /dev/null
Binary files differ
diff --git a/demos/2d/normalmaps/engine.cfg b/demos/2d/normalmaps/engine.cfg
index f0002dc2b8..4f9f4f67f0 100644
--- a/demos/2d/normalmaps/engine.cfg
+++ b/demos/2d/normalmaps/engine.cfg
@@ -2,6 +2,7 @@
name="2D Normal Mapping"
main_scene="res://normalmap.scn"
+icon="res://icon.png"
[display]
diff --git a/demos/2d/normalmaps/icon.png b/demos/2d/normalmaps/icon.png
new file mode 100644
index 0000000000..11ff5de829
--- /dev/null
+++ b/demos/2d/normalmaps/icon.png
Binary files differ
diff --git a/demos/2d/normalmaps/normalmap.scn b/demos/2d/normalmaps/normalmap.scn
index ab737e83f3..cf5fc05ce1 100644
--- a/demos/2d/normalmaps/normalmap.scn
+++ b/demos/2d/normalmaps/normalmap.scn
Binary files differ
diff --git a/demos/2d/particles/particles.xml b/demos/2d/particles/particles.xml
index c8f7596b86..c21ccb1f55 100644
--- a/demos/2d/particles/particles.xml
+++ b/demos/2d/particles/particles.xml
@@ -1,37 +1,49 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="4" version="1.0" version_name="Godot Engine v1.0.3917-beta1">
- <ext_resource path="res://fire_particle.png" type="Texture"></ext_resource>
- <ext_resource path="res://smoke_particle.png" type="Texture"></ext_resource>
- <ext_resource path="res://spark_particle2.png" type="Texture"></ext_resource>
+<resource_file type="PackedScene" subresource_count="8" version="2.0" version_name="Godot Engine v2.0.alpha.custom_build">
+ <ext_resource path="res://fire_particle.png" type="Texture" index="0"></ext_resource>
+ <ext_resource path="res://smoke_particle.png" type="Texture" index="1"></ext_resource>
+ <ext_resource path="res://spark_particle2.png" type="Texture" index="2"></ext_resource>
+ <resource type="ColorRamp" path="local://1">
+ <real_array name="offsets" len="3"> 0, 0.1, 1 </real_array>
+ <color_array name="colors" len="3"> 1, 1, 1, 0, 0.886275, 0.371681, 0, 1, 1, 0.99115, 1, 0 </color_array>
+
+ </resource>
+ <resource type="ColorRamp" path="local://2">
+ <real_array name="offsets" len="3"> 0, 0.2, 1 </real_array>
+ <color_array name="colors" len="3"> 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0 </color_array>
+
+ </resource>
+ <resource type="ColorRamp" path="local://3">
+ <real_array name="offsets" len="4"> 0, 0.1, 0.5, 1 </real_array>
+ <color_array name="colors" len="4"> 1, 1, 1, 0.870518, 1, 0.47451, 0.6, 1, 0.529412, 0.74902, 1, 1, 0, 1, 0.698039, 0 </color_array>
+
+ </resource>
+ <resource type="ColorRamp" path="local://4">
+ <real_array name="offsets" len="4"> 0, 0.1, 0.7, 1 </real_array>
+ <color_array name="colors" len="4"> 1, 1, 1, 0, 0.886275, 0.401015, 0, 1, 1, 0.679866, 0.432123, 0.12654, 0, 0, 0, 0 </color_array>
+
+ </resource>
<main_resource>
<dictionary name="_bundled" shared="false">
+ <string> "conn_count" </string>
+ <int> 0 </int>
+ <string> "conns" </string>
+ <int_array len="0"> </int_array>
+ <string> "editable_instances" </string>
+ <array len="0" shared="false">
+ </array>
<string> "names" </string>
- <string_array len="68">
+ <string_array len="41">
<string> "Node" </string>
- <string> "_import_path" </string>
<string> "__meta__" </string>
<string> "Fire" </string>
- <string> "Particles2D" </string>
- <string> "visibility/visible" </string>
- <string> "visibility/opacity" </string>
- <string> "visibility/self_opacity" </string>
- <string> "visibility/behind_parent" </string>
<string> "visibility/blend_mode" </string>
<string> "transform/pos" </string>
<string> "transform/rot" </string>
- <string> "transform/scale" </string>
<string> "config/amount" </string>
<string> "config/lifetime" </string>
- <string> "config/time_scale" </string>
- <string> "config/preprocess" </string>
- <string> "config/emit_timeout" </string>
- <string> "config/emitting" </string>
- <string> "config/offset" </string>
<string> "config/half_extents" </string>
<string> "config/local_space" </string>
- <string> "config/explosiveness" </string>
- <string> "config/flip_h" </string>
- <string> "config/flip_v" </string>
<string> "config/texture" </string>
<string> "params/direction" </string>
<string> "params/spread" </string>
@@ -47,136 +59,159 @@
<string> "params/initial_size" </string>
<string> "params/final_size" </string>
<string> "params/hue_variation" </string>
- <string> "randomness/direction" </string>
- <string> "randomness/spread" </string>
- <string> "randomness/linear_velocity" </string>
- <string> "randomness/spin_velocity" </string>
- <string> "randomness/orbit_velocity" </string>
- <string> "randomness/gravity_direction" </string>
- <string> "randomness/gravity_strength" </string>
- <string> "randomness/radial_accel" </string>
- <string> "randomness/tangential_accel" </string>
- <string> "randomness/damping" </string>
+ <string> "params/anim_speed_scale" </string>
+ <string> "params/anim_initial_pos" </string>
<string> "randomness/initial_angle" </string>
- <string> "randomness/initial_size" </string>
- <string> "randomness/final_size" </string>
- <string> "randomness/hue_variation" </string>
- <string> "color_phases/count" </string>
- <string> "phase_0/pos" </string>
- <string> "phase_0/color" </string>
- <string> "phase_1/pos" </string>
- <string> "phase_1/color" </string>
- <string> "phase_2/pos" </string>
- <string> "phase_2/color" </string>
- <string> "phase_3/pos" </string>
- <string> "phase_3/color" </string>
- <string> "emission_points" </string>
+ <string> "color/color_ramp" </string>
+ <string> "Particles2D" </string>
<string> "Smoke" </string>
+ <string> "randomness/spin_velocity" </string>
<string> "Magic" </string>
+ <string> "randomness/orbit_velocity" </string>
<string> "Explosion" </string>
+ <string> "visibility/behind_parent" </string>
+ <string> "config/time_scale" </string>
+ <string> "config/explosiveness" </string>
<string> "Mask" </string>
+ <string> "color/color" </string>
+ <string> "emission_points" </string>
</string_array>
- <string> "version" </string>
- <int> 1 </int>
- <string> "conn_count" </string>
- <int> 0 </int>
<string> "node_count" </string>
<int> 6 </int>
+ <string> "node_paths" </string>
+ <array len="0" shared="false">
+ </array>
+ <string> "nodes" </string>
+ <int_array len="304"> -1, -1, 0, 0, -1, 1, 1, 0, 0, 0, 0, 29, 2, -1, 26, 3, 1, 4, 2, 5, 3, 6, 4, 7, 5, 8, 6, 9, 7, 10, 8, 11, 9, 12, 9, 13, 10, 14, 9, 15, 9, 16, 11, 17, 12, 18, 9, 19, 9, 20, 9, 21, 11, 22, 13, 23, 14, 24, 9, 25, 5, 26, 9, 27, 15, 28, 16, 0, 0, 0, 29, 30, -1, 25, 4, 17, 5, 18, 6, 4, 7, 19, 9, 7, 10, 20, 11, 9, 12, 21, 13, 22, 14, 5, 15, 9, 16, 9, 17, 9, 18, 9, 19, 9, 20, 9, 21, 11, 22, 5, 23, 23, 24, 9, 25, 5, 26, 9, 31, 5, 27, 5, 28, 24, 0, 0, 0, 29, 32, -1, 26, 4, 25, 6, 4, 7, 15, 8, 26, 9, 7, 10, 27, 11, 9, 12, 11, 13, 10, 14, 14, 15, 28, 16, 9, 17, 29, 18, 9, 19, 30, 20, 9, 21, 31, 22, 23, 23, 5, 24, 9, 25, 5, 26, 9, 31, 5, 33, 32, 27, 5, 28, 33, 0, 0, 0, 29, 34, -1, 28, 35, 34, 3, 1, 4, 35, 5, 3, 6, 4, 7, 15, 36, 15, 8, 6, 9, 7, 37, 36, 10, 20, 11, 9, 12, 11, 13, 37, 14, 9, 15, 9, 16, 11, 17, 12, 18, 9, 19, 9, 20, 38, 21, 5, 22, 13, 23, 23, 24, 9, 25, 5, 26, 9, 28, 39, 0, 0, 0, 29, 38, -1, 25, 4, 40, 6, 41, 7, 42, 8, 43, 9, 7, 10, 27, 11, 9, 12, 11, 13, 9, 14, 15, 15, 9, 16, 9, 17, 9, 18, 9, 19, 9, 20, 9, 21, 5, 22, 5, 23, 5, 24, 9, 25, 5, 26, 9, 31, 5, 39, 44, 40, 45, 0 </int_array>
<string> "variants" </string>
- <array len="65" shared="false">
- <node_path> "" </node_path>
+ <array len="46" shared="false">
<dictionary shared="false">
+ <string> "__editor_plugin_screen__" </string>
+ <string> "2D" </string>
<string> "__editor_plugin_states__" </string>
<dictionary shared="false">
<string> "2D" </string>
<dictionary shared="false">
- <string> "pixel_snap" </string>
+ <string> "ofs" </string>
+ <vector2> -193.367, -465.428 </vector2>
+ <string> "snap_grid" </string>
+ <bool> False </bool>
+ <string> "snap_offset" </string>
+ <vector2> 0, 0 </vector2>
+ <string> "snap_pixel" </string>
<bool> False </bool>
+ <string> "snap_relative" </string>
+ <bool> False </bool>
+ <string> "snap_rotation" </string>
+ <bool> False </bool>
+ <string> "snap_rotation_offset" </string>
+ <real> 0 </real>
+ <string> "snap_rotation_step" </string>
+ <real> 0.261799 </real>
+ <string> "snap_show_grid" </string>
+ <bool> False </bool>
+ <string> "snap_step" </string>
+ <vector2> 10, 10 </vector2>
<string> "zoom" </string>
<real> 0.440127 </real>
- <string> "use_snap" </string>
- <bool> False </bool>
- <string> "ofs" </string>
- <vector2> -193.367, -173.288 </vector2>
- <string> "snap" </string>
- <int> 10 </int>
</dictionary>
<string> "3D" </string>
<dictionary shared="false">
- <string> "zfar" </string>
- <real> 500 </real>
+ <string> "ambient_light_color" </string>
+ <color> 0.15, 0.15, 0.15, 1 </color>
+ <string> "default_light" </string>
+ <bool> True </bool>
+ <string> "default_srgb" </string>
+ <bool> False </bool>
+ <string> "deflight_rot_x" </string>
+ <real> 0.942478 </real>
+ <string> "deflight_rot_y" </string>
+ <real> 0.628319 </real>
<string> "fov" </string>
<real> 45 </real>
+ <string> "show_grid" </string>
+ <bool> True </bool>
+ <string> "show_origin" </string>
+ <bool> True </bool>
+ <string> "viewport_mode" </string>
+ <int> 1 </int>
<string> "viewports" </string>
<array len="4" shared="false">
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> True </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
</array>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
+ <string> "zfar" </string>
+ <real> 500 </real>
<string> "znear" </string>
<real> 0.1 </real>
</dictionary>
+ <string> "Anim" </string>
+ <dictionary shared="false">
+ <string> "visible" </string>
+ <bool> False </bool>
+ </dictionary>
</dictionary>
<string> "__editor_run_settings__" </string>
<dictionary shared="false">
@@ -185,77 +220,55 @@
<string> "run_mode" </string>
<int> 0 </int>
</dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "2D" </string>
</dictionary>
- <bool> True </bool>
- <real> 1 </real>
- <bool> False </bool>
<int> 1 </int>
<vector2> 165.787, 527.801 </vector2>
<real> -179.790649 </real>
- <vector2> 1, 1 </vector2>
<int> 32 </int>
- <real> 0 </real>
- <vector2> 0, 0 </vector2>
+ <real> 1 </real>
<vector2> 15, 15 </vector2>
- <resource resource_type="Texture" path="res://fire_particle.png"> </resource>
+ <bool> False </bool>
+ <resource external="0"> </resource>
+ <real> 0 </real>
<real> 20 </real>
<real> 180 </real>
<real> 80 </real>
<real> 0.7 </real>
<real> 0.3 </real>
<real> 2 </real>
- <int> 3 </int>
- <color> 1, 1, 1, 0 </color>
- <real> 0.1 </real>
- <color> 0.886275, 0.371681, 0, 1 </color>
- <color> 1, 0.99115, 1, 0 </color>
- <color> 0, 0, 0, 1 </color>
- <vector2_array len="0"> </vector2_array>
+ <resource resource_type="ColorRamp" path="local://1"> </resource>
<vector2> 377.396, 543.147 </vector2>
<real> 176.575912 </real>
<real> 4 </real>
- <resource resource_type="Texture" path="res://smoke_particle.png"> </resource>
+ <resource external="1"> </resource>
<real> 20.907272 </real>
<real> 47.151516 </real>
<real> 3 </real>
- <real> 0.2 </real>
- <color> 1, 1, 1, 1 </color>
- <color> 0, 0, 0, 0 </color>
+ <resource resource_type="ColorRamp" path="local://2"> </resource>
<vector2> 593.848, 531.064 </vector2>
<vector2> 40, 40 </vector2>
- <resource resource_type="Texture" path="res://spark_particle2.png"> </resource>
+ <resource external="2"> </resource>
<real> 0.01 </real>
<real> 9.8 </real>
<real> 15.515152 </real>
<real> 45 </real>
<real> 100 </real>
- <int> 4 </int>
- <color> 1, 1, 1, 0.870518 </color>
- <color> 1, 0.47451, 0.6, 1 </color>
- <real> 0.5 </real>
- <color> 0.529412, 0.74902, 1, 1 </color>
- <color> 0, 1, 0.698039, 0 </color>
+ <resource resource_type="ColorRamp" path="local://3"> </resource>
+ <bool> True </bool>
<vector2> 613.467, 182.62 </vector2>
<real> 0.05 </real>
<real> 184.546997 </real>
<real> 366.300415 </real>
- <color> 0.886275, 0.401015, 0, 1 </color>
- <color> 1, 0.679866, 0.432123, 0.12654 </color>
+ <resource resource_type="ColorRamp" path="local://4"> </resource>
<vector2> 192.975, 141.598 </vector2>
<int> 170 </int>
+ <real> 0.1 </real>
<vector2> 128, 128 </vector2>
- <int> 0 </int>
<color> 1, 0.477876, 0.60177, 1 </color>
- <color> 0.533333, 0.752212, 1, 1 </color>
- <color> 0, 1, 0.699115, 0 </color>
<vector2_array len="512"> -0.125, -0.03125, 0.65625, -0.148438, 0.609375, 0.0234375, -0.757812, 0.375, 0.265625, 0.078125, 0.632812, 0.382812, 0.671875, 0.414062, 0.367188, -0.226562, 0.75, -0.125, 0.4375, 0.421875, 0.335938, -0.148438, -0.125, 0.257812, -0.171875, 0.359375, -0.601562, -0.265625, 0.375, 0.382812, -0.296875, 0.09375, -0.664062, -0.21875, -0.554688, -0.226562, -0.320312, 0.367188, -0.320312, -0.257812, 0, -0.257812, 0.578125, -0.25, -0.164062, 0.109375, -0.578125, -0.015625, -0.445312, 0, 0.273438, 0.101562, 0.320312, 0.03125, -0.125, 0.0703125, -0.570312, 0.289062, 0.257812, -0.09375, -0.585938, 0.179688, -0.664062, 0.0234375, -0.25, -0.0859375, 0.6875, -0.109375, 0.234375, 0, -0.5, -0.265625, 0.710938, 0.335938, 0.609375, -0.046875, 0.664062, -0.210938, -0.242188, -0.21875, -0.484375, -0.257812, -0.453125, 0.414062, 0.609375, -0.203125, 0.289062, 0.132812, -0.03125, -0.257812, -0.492188, -0.1875, 0.5625, -0.140625, -0.5625, 0.148438, -0.257812, -0.234375, -0.140625, 0.15625, -0.5625, 0.109375, 0.132812, 0.398438, -0.640625, -0.25, -0.585938, 0.304688, -0.328125, -0.257812, 0.226562, 0.148438, -0.546875, 0.210938, 0.625, 0.179688, 0.648438, -0.0078125, 0.367188, 0.328125, 0.265625, 0.0546875, -0.59375, -0.273438, -0.203125, 0.21875, 0.570312, -0.21875, -0.695312, 0.078125, -0.375, 0.03125, -0.164062, 0.0390625, 0.265625, 0.226562, -0.625, -0.109375, 0.203125, -0.132812, -0.671875, 0.328125, 0.625, -0.179688, -0.640625, 0.0859375, 0.65625, 0, -0.242188, 0.414062, 0.242188, 0.25, -0.148438, -0.0625, 0.390625, -0.25, 0.664062, 0.351562, 0.320312, 0.203125, -0.546875, 0.335938, 0.328125, -0.148438, 0.609375, -0.0625, -0.171875, 0.046875, -0.578125, 0.0546875, -0.304688, -0.28125, 0.734375, -0.0546875, 0.679688, 0.390625, -0.460938, 0.0859375, -0.703125, 0.101562, -0.140625, 0.234375, -0.507812, 0.078125, -0.25, 0.304688, -0.046875, 0.359375, 0.1875, 0.0703125, -0.570312, 0.242188, 0.65625, 0.0859375, -0.203125, -0.265625, -0.164062, -0.179688, 0.367188, -0.1875, -0.601562, -0.101562, -0.117188, -0.210938, -0.546875, 0.109375, -0.585938, -0.28125, -0.59375, -0.03125, 0.3125, -0.179688, 0.414062, 0.429688, -0.476562, -0.195312, -0.0703125, -0.21875, -0.5625, 0.304688, -0.609375, 0.226562, 0.429688, 0.429688, 0.203125, 0.242188, 0.078125, 0.367188, 0.242188, 0.03125, 0.601562, -0.0390625, 0.328125, 0.03125, -0.53125, -0.195312, -0.53125, -0.210938, 0.3125, -0.257812, 0.445312, -0.273438, 0.273438, -0.273438, -0.695312, -0.179688, 0.234375, -0.15625, -0.546875, -0.242188, -0.234375, -0.125, 0.734375, -0.226562, 0.367188, -0.234375, -0.15625, 0.046875, -0.445312, -0.226562, 0.625, 0.03125, -0.0859375, 0.210938, -0.648438, 0.296875, 0.335938, -0.109375, 0.625, -0.078125, 0.601562, 0.351562, 0.242188, 0.140625, 0.0234375, -0.273438, -0.679688, -0.109375, 0.640625, 0.15625, 0.171875, 0.0859375, -0.273438, -0.273438, -0.242188, 0.34375, 0.179688, 0.15625, -0.179688, -0.117188, 0.671875, 0.03125, -0.640625, 0.304688, 0.109375, -0.242188, -0.210938, 0.382812, -0.0859375, 0.0078125, -0.695312, 0.078125, 0.296875, 0.320312, 0.304688, -0.226562, 0.257812, -0.0234375, -0.203125, -0.015625, -0.648438, 0.335938, -0.703125, -0.132812, -0.273438, -0.210938, -0.15625, -0.273438, -0.0390625, 0.335938, 0.617188, 0.179688, 0.34375, 0.390625, -0.210938, -0.132812, -0.226562, -0.117188, 0.617188, -0.289062, 0.125, -0.21875, 0.71875, -0.164062, -0.570312, 0.1875, -0.1875, 0.382812, 0.640625, -0.296875, -0.125, 0.109375, 0.671875, 0.289062, -0.515625, 0.382812, 0.359375, -0.179688, 0.726562, -0.226562, 0.25, 0.320312, -0.328125, 0, -0.117188, -0.234375, -0.210938, -0.148438, -0.546875, -0.117188, 0.359375, 0.429688, -0.15625, -0.226562, 0.632812, -0.257812, -0.28125, -0.273438, 0.265625, 0.015625, -0.765625, 0.351562, 0.703125, 0.421875, -0.585938, 0.0078125, 0.28125, 0.109375, 0.304688, 0.171875, 0.65625, 0.421875, 0.078125, 0.382812, 0.179688, 0.25, -0.382812, 0.0703125, 0.585938, -0.140625, -0.109375, 0.382812, -0.59375, -0.09375, 0.4375, 0.398438, -0.132812, 0.0234375, -0.625, 0.0078125, -0.210938, -0.21875, -0.25, 0.257812, 0.257812, 0.398438, 0.625, 0.195312, 0.148438, -0.234375, -0.476562, 0.398438, -0.210938, 0.046875, 0.695312, -0.101562, 0.695312, 0.140625, -0.492188, -0.1875, 0.25, -0.09375, -0.195312, -0.195312, -0.328125, 0.0703125, -0.242188, -0.0625, 0.296875, 0.34375, -0.632812, 0.0078125, -0.265625, 0.09375, 0.421875, -0.203125, 0.171875, 0.03125, -0.09375, -0.0703125, 0.289062, 0.0859375, -0.609375, 0.390625, -0.554688, 0.257812, -0.6875, 0.0078125, 0.304688, 0.414062, 0.226562, 0.390625, -0.21875, -0.28125, 0.265625, 0.320312, -0.671875, 0.234375, -0.210938, 0.03125, 0.679688, -0.0234375, 0.359375, -0.203125, 0.3125, 0.289062, 0.671875, 0.140625, -0.78125, 0.414062, -0.546875, 0.40625, 0.625, 0.367188, 0.0859375, 0.421875, 0.1875, -0.09375, 0.617188, 0.40625, -0.078125, -0.0390625, 0.695312, 0.0859375, -0.6875, -0.265625, 0.421875, -0.265625, 0.601562, -0.0234375, -0.3125, -0.265625, -0.078125, 0.046875, 0.617188, 0.164062, 0.273438, -0.03125, -0.695312, -0.015625, -0.5625, 0.164062, -0.578125, 0.265625, -0.726562, 0.421875, -0.078125, -0.25, -0.171875, 0.171875, -0.234375, -0.0390625, 0.257812, 0.429688, -0.179688, -0.117188, 0.351562, -0.03125, -0.78125, -0.234375, -0.546875, -0.171875, -0.460938, -0.234375, -0.164062, 0.09375, -0.65625, 0.398438, -0.445312, 0.0859375, -0.71875, -0.226562, 0.671875, 0.101562, -0.46875, -0.195312, -0.71875, -0.265625, 0.617188, 0.125, -0.78125, -0.21875, -0.226562, -0.15625, 0.21875, 0.0234375, 0.289062, 0.101562, 0.648438, -0.171875, 0.390625, -0.273438, -0.257812, 0.078125, -0.21875, 0, 0.65625, -0.203125, -0.679688, 0.171875, -0.1875, 0.328125, -0.46875, -0.28125, 0.273438, 0, 0.664062, 0.296875, -0.140625, 0.335938, -0.625, 0.382812, -0.34375, -0.21875, -0.171875, -0.25, -0.546875, -0.117188, -0.117188, -0.203125, -0.1875, 0.351562, -0.585938, -0.109375, -0.203125, -0.0625, -0.570312, 0.03125, -0.5625, -0.109375, 0.601562, -0.195312, 0.3125, 0.140625, -0.101562, 0.25, 0.25, 0.3125, 0.125, -0.203125, -0.09375, -0.140625, -0.242188, 0.414062, 0.664062, -0.0625, -0.21875, -0.078125, 0.6875, -0.210938, -0.140625, 0.015625, -0.632812, -0.25, -0.109375, 0.234375, -0.695312, 0.015625, -0.3125, -0.28125, 0.296875, -0.0234375, 0.296875, 0.203125, -0.125, 0.234375, 0.570312, 0.390625, -0.554688, 0.203125, -0.5625, 0.351562, -0.15625, 0.21875, -0.375, 0.0390625, -0.226562, -0.140625, 0.695312, 0.164062, 0.632812, 0.367188, -0.328125, -0.210938, -0.59375, 0.34375, 0.304688, -0.242188, -0.34375, 0.0703125, -0.679688, -0.179688, 0.664062, 0.101562, 0.34375, 0.171875, -0.695312, -0.078125, -0.242188, -0.0546875, 0.304688, -0.234375, -0.0078125, -0.21875, -0.632812, 0.203125, 0.625, 0.03125, -0.414062, 0.015625, 0.273438, -0.078125, 0.695312, 0.28125, 0.34375, 0.101562, -0.164062, 0.289062, -0.1875, 0.273438, -0.203125, 0.0703125, 0.734375, -0.171875, -0.59375, 0.34375, -0.15625, 0.210938, 0.429688, 0.375, -0.234375, 0.34375, 0.617188, 0.101562, 0.703125, 0, -0.578125, 0.148438, 0.21875, -0.171875, -0.304688, 0.375, -0.65625, -0.09375, -0.101562, 0.25, -0.4375, 0.03125, -0.242188, 0.421875, -0.546875, 0.0625, -0.632812, -0.148438, -0.125, 0.179688, 0.179688, 0.304688, -0.265625, 0.078125, -0.289062, 0.421875, -0.585938, 0.1875, -0.289062, 0.34375, 0.273438, 0.367188, -0.109375, 0.117188, 0.34375, 0.046875, -0.0625, 0.320312, 0.6875, -0.234375, -0.523438, 0.320312, -0.09375, -0.242188, -0.65625, 0.25, -0.609375, -0.117188, -0.140625, 0.140625, 0.28125, -0.09375, -0.625, -0.28125, 0.34375, 0.328125, 0.265625, 0.109375, -0.609375, 0.0078125, -0.078125, -0.234375, -0.289062, -0.203125, 0.289062, 0.289062, -0.0859375, 0.0078125, -0.101562, -0.28125, -0.625, -0.101562, -0.546875, 0.382812, -0.539062, -0.195312, -0.210938, 0.046875, -0.492188, 0.390625, -0.664062, -0.0703125, 0.71875, -0.101562, -0.140625, -0.046875, 0.695312, 0.289062, -0.710938, 0.429688, -0.703125, 0.3125, -0.203125, 0.109375, 0.421875, -0.273438, 0.304688, 0.21875, 0.328125, 0.257812, -0.632812, -0.0703125, 0.320312, -0.140625, 0.265625, -0.203125, -0.109375, -0.179688, 0.25, -0.210938, 0.65625, 0.109375, -0.648438, -0.0625, -0.0859375, 0.375, -0.429688, 0.398438, 0.320312, 0.3125, -0.0703125, 0.265625, 0.648438, 0.0078125, 0.320312, 0.335938, 0.398438, 0.421875, -0.101562, -0.0625, -0.296875, 0.40625, 0.695312, -0.0390625, 0.335938, 0.21875, -0.546875, 0.117188, -0.476562, 0.390625, -0.648438, 0.117188, -0.078125, -0.28125, 0.328125, 0.289062, -0.226562, 0.179688, 0.226562, 0.375, -0.429688, 0.382812, -0.0546875, 0.34375, 0.59375, -0.125, 0.632812, 0.265625, 0.226562, 0.3125, -0.523438, -0.140625, -0.546875, 0.046875, 0.242188, -0.148438, -0.648438, 0.0234375, -0.289062, 0, -0.546875, 0.101562, -0.125, -0.0625, -0.492188, 0.367188, 0.328125, 0.15625, -0.351562, 0.0546875, -0.609375, 0.414062, -0.296875, 0.09375, 0.671875, -0.203125, -0.257812, -0.273438, -0.335938, 0.414062, 0.65625, -0.195312, -0.601562, -0.101562, -0.203125, -0.078125, 0.210938, 0.242188, 0.296875, 0.335938, -0.578125, 0.40625, -0.664062, -0.078125, -0.0859375, 0.390625, 0.171875, 0.304688, -0.6875, 0.390625, -0.554688, 0.0078125, -0.570312, -0.179688, -0.210938, -0.09375, 0.726562, -0.03125, -0.546875, -0.0859375, -0.265625, -0.171875, -0.65625, 0.179688, -0.171875, 0.257812, -0.164062, -0.171875, 0.203125, 0.335938, -0.640625, 0.21875, 0.390625, 0.375, 0.6875, -0.234375, 0.742188, 0.34375, -0.0546875, 0.351562, -0.632812, 0.195312, 0.671875, -0.21875, 0.195312, 0.015625, 0.226562, 0.117188, -0.507812, 0.078125, -0.140625, -0.15625, 0.703125, -0.28125, 0.226562, -0.140625, 0.328125, 0.421875, 0.3125, 0.1875, 0.703125, 0.078125, 0.351562, 0.289062, 0.21875, -0.242188, -0.328125, 0, 0.171875, 0.101562, -0.304688, -0.242188, -0.210938, 0.078125, 0.625, -0.0078125, 0.25, 0.242188, -0.664062, 0.117188, 0.203125, -0.140625, 0.226562, 0.429688, 0.328125, -0.203125, -0.679688, 0.0703125, -0.195312, -0.148438, -0.523438, 0.328125, 0.382812, -0.257812, 0.578125, -0.171875, 0.65625, 0.320312, -0.632812, -0.148438, 0.703125, 0.0703125, -0.53125, 0.398438, -0.414062, 0.03125, -0.0859375, 0.0546875, -0.53125, 0.335938, 0.304688, 0.429688, -0.234375, -0.148438, -0.375, 0.046875, -0.148438, 0.289062, -0.0390625, 0.421875, 0.226562, -0.125, -0.570312, 0.398438, -0.0703125, -0.0234375, 0.257812, -0.132812 </vector2_array>
</array>
- <string> "nodes" </string>
- <int_array len="640"> -1, -1, 0, 0, -1, 2, 1, 0, 2, 1, 0, 0, 0, 4, 3, -1, 60, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 8, 13, 9, 14, 3, 15, 3, 16, 10, 17, 10, 18, 2, 19, 11, 20, 12, 21, 4, 22, 3, 23, 4, 24, 4, 25, 13, 26, 10, 27, 10, 28, 14, 29, 10, 30, 10, 31, 15, 32, 16, 33, 10, 34, 10, 35, 10, 36, 15, 37, 17, 38, 18, 39, 10, 40, 10, 41, 10, 42, 10, 43, 10, 44, 10, 45, 10, 46, 10, 47, 10, 48, 10, 49, 10, 50, 19, 51, 10, 52, 10, 53, 10, 54, 20, 55, 10, 56, 21, 57, 22, 58, 23, 59, 3, 60, 24, 61, 3, 62, 25, 63, 26, 0, 0, 0, 4, 64, -1, 59, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 10, 27, 11, 28, 12, 8, 13, 9, 14, 29, 15, 3, 16, 10, 17, 10, 18, 2, 19, 11, 20, 11, 21, 4, 22, 3, 23, 4, 24, 4, 25, 30, 26, 10, 27, 31, 28, 32, 29, 3, 30, 10, 31, 10, 32, 10, 33, 10, 34, 10, 35, 10, 36, 15, 37, 3, 38, 33, 39, 10, 40, 10, 41, 10, 42, 10, 43, 3, 44, 10, 45, 10, 46, 10, 47, 10, 48, 10, 49, 10, 50, 3, 51, 10, 52, 10, 53, 10, 54, 20, 55, 10, 56, 21, 57, 34, 58, 35, 59, 3, 60, 36, 61, 3, 62, 25, 63, 26, 0, 0, 0, 4, 65, -1, 59, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 10, 37, 11, 10, 12, 8, 13, 9, 14, 19, 15, 3, 16, 10, 17, 10, 18, 2, 19, 11, 20, 38, 21, 4, 22, 3, 23, 4, 24, 4, 25, 39, 26, 10, 27, 15, 28, 14, 29, 18, 30, 40, 31, 10, 32, 41, 33, 10, 34, 42, 35, 10, 36, 43, 37, 33, 38, 3, 39, 10, 40, 10, 41, 10, 42, 10, 43, 3, 44, 44, 45, 10, 46, 10, 47, 10, 48, 10, 49, 10, 50, 3, 51, 10, 52, 10, 53, 10, 54, 45, 55, 10, 56, 46, 57, 22, 58, 47, 59, 48, 60, 49, 61, 3, 62, 50, 63, 26, 0, 0, 0, 4, 66, -1, 60, 1, 0, 5, 2, 6, 3, 7, 3, 8, 2, 9, 5, 10, 51, 11, 7, 12, 8, 13, 9, 14, 19, 15, 19, 16, 10, 17, 10, 18, 2, 19, 11, 20, 12, 21, 4, 22, 52, 23, 4, 24, 4, 25, 30, 26, 10, 27, 15, 28, 53, 29, 10, 30, 10, 31, 15, 32, 16, 33, 10, 34, 10, 35, 54, 36, 3, 37, 17, 38, 33, 39, 10, 40, 10, 41, 10, 42, 10, 43, 10, 44, 10, 45, 10, 46, 10, 47, 10, 48, 10, 49, 10, 50, 10, 51, 10, 52, 10, 53, 10, 54, 45, 55, 10, 56, 21, 57, 22, 58, 55, 59, 17, 60, 56, 61, 3, 62, 36, 63, 26, 0, 0, 0, 4, 67, -1, 59, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 10, 57, 11, 10, 12, 8, 13, 58, 14, 22, 15, 3, 16, 10, 17, 10, 18, 2, 19, 11, 20, 59, 21, 4, 22, 3, 23, 4, 24, 4, 25, 39, 26, 10, 27, 15, 28, 10, 29, 19, 30, 10, 31, 10, 32, 10, 33, 10, 34, 10, 35, 10, 36, 3, 37, 3, 38, 3, 39, 10, 40, 10, 41, 10, 42, 10, 43, 3, 44, 10, 45, 10, 46, 10, 47, 10, 48, 10, 49, 10, 50, 10, 51, 10, 52, 10, 53, 10, 54, 60, 55, 10, 56, 61, 57, 48, 58, 62, 59, 3, 60, 63, 61, 3, 62, 25, 63, 64, 0 </int_array>
- <string> "conns" </string>
- <int_array len="0"> </int_array>
+ <string> "version" </string>
+ <int> 2 </int>
</dictionary>
</main_resource>
diff --git a/demos/2d/platformer/bullet.gd b/demos/2d/platformer/bullet.gd
index 9aacc9809d..3aee69714e 100644
--- a/demos/2d/platformer/bullet.gd
+++ b/demos/2d/platformer/bullet.gd
@@ -1,21 +1,16 @@
extends RigidBody2D
-# member variables here, example:
-# var a=2
-# var b="textvar"
+# Member variables
+var disabled = false
-var disabled=false
func disable():
if (disabled):
return
get_node("anim").play("shutdown")
- disabled=true
+ disabled = true
+
func _ready():
- # Initalization here
get_node("Timer").start()
- pass
-
-
diff --git a/demos/2d/platformer/bullet.xml b/demos/2d/platformer/bullet.xml
index 84c903803f..63938581ad 100644
--- a/demos/2d/platformer/bullet.xml
+++ b/demos/2d/platformer/bullet.xml
@@ -1,12 +1,17 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="5" version="1.0" version_name="Godot Engine v1.0.3917-beta1">
- <ext_resource path="res://bullet.*" type="Texture"></ext_resource>
- <ext_resource path="res://bullet.*" type="Script"></ext_resource>
+<resource_file type="PackedScene" subresource_count="6" version="2.0" version_name="Godot Engine v2.0.alpha.custom_build">
+ <ext_resource path="res://bullet.png" type="Texture" index="1"></ext_resource>
+ <ext_resource path="res://bullet.gd" type="Script" index="0"></ext_resource>
<resource type="CircleShape2D" path="local://1">
<real name="custom_solver_bias"> 0 </real>
<real name="radius"> 10 </real>
</resource>
+ <resource type="ColorRamp" path="local://3">
+ <real_array name="offsets" len="2"> 0, 1 </real_array>
+ <color_array name="colors" len="2"> 1, 1, 1, 1, 1, 0, 0, 0 </color_array>
+
+ </resource>
<resource type="Animation" path="local://2">
<string name="resource/name"> "shutdown" </string>
<real name="length"> 1.5 </real>
@@ -18,14 +23,14 @@
<dictionary name="tracks/0/keys" shared="false">
<string> "cont" </string>
<bool> False </bool>
+ <string> "times" </string>
+ <real_array len="1"> 0 </real_array>
<string> "transitions" </string>
<real_array len="1"> 1 </real_array>
<string> "values" </string>
<array len="1" shared="false">
<bool> False </bool>
</array>
- <string> "times" </string>
- <real_array len="1"> 0 </real_array>
</dictionary>
<string name="tracks/1/type"> "value" </string>
<node_path name="tracks/1/path"> "sprite:visibility/self_opacity" </node_path>
@@ -33,6 +38,8 @@
<dictionary name="tracks/1/keys" shared="false">
<string> "cont" </string>
<bool> True </bool>
+ <string> "times" </string>
+ <real_array len="2"> 0, 1.00394 </real_array>
<string> "transitions" </string>
<real_array len="2"> 1, 1 </real_array>
<string> "values" </string>
@@ -40,13 +47,13 @@
<real> 1 </real>
<real> 0 </real>
</array>
- <string> "times" </string>
- <real_array len="2"> 0, 1.00394 </real_array>
</dictionary>
<string name="tracks/2/type"> "method" </string>
<node_path name="tracks/2/path"> "." </node_path>
<int name="tracks/2/interp"> 1 </int>
<dictionary name="tracks/2/keys" shared="false">
+ <string> "times" </string>
+ <real_array len="1"> 1.31 </real_array>
<string> "transitions" </string>
<real_array len="1"> 1 </real_array>
<string> "values" </string>
@@ -59,57 +66,51 @@
<string> "queue_free" </string>
</dictionary>
</array>
- <string> "times" </string>
- <real_array len="1"> 1.31 </real_array>
</dictionary>
</resource>
<main_resource>
<dictionary name="_bundled" shared="false">
+ <string> "conn_count" </string>
+ <int> 1 </int>
+ <string> "conns" </string>
+ <int_array len="6"> 4, 0, 73, 72, 2, 0 </int_array>
+ <string> "editable_instances" </string>
+ <array len="0" shared="false">
+ </array>
<string> "names" </string>
- <string_array len="111">
+ <string_array len="74">
<string> "bullet" </string>
- <string> "RigidBody2D" </string>
- <string> "visibility/visible" </string>
- <string> "visibility/opacity" </string>
- <string> "visibility/self_opacity" </string>
- <string> "visibility/on_top" </string>
- <string> "transform/pos" </string>
- <string> "transform/rot" </string>
- <string> "transform/scale" </string>
- <string> "shape_count" </string>
+ <string> "input/pickable" </string>
<string> "shapes/0/shape" </string>
<string> "shapes/0/transform" </string>
<string> "shapes/0/trigger" </string>
+ <string> "collision/layers" </string>
+ <string> "collision/mask" </string>
<string> "mode" </string>
<string> "mass" </string>
<string> "friction" </string>
<string> "bounce" </string>
+ <string> "gravity_scale" </string>
<string> "custom_integrator" </string>
<string> "continuous_cd" </string>
<string> "contacts_reported" </string>
<string> "contact_monitor" </string>
- <string> "active" </string>
+ <string> "sleeping" </string>
<string> "can_sleep" </string>
<string> "velocity/linear" </string>
<string> "velocity/angular" </string>
+ <string> "damp_override/linear" </string>
+ <string> "damp_override/angular" </string>
<string> "script/script" </string>
<string> "__meta__" </string>
+ <string> "RigidBody2D" </string>
<string> "particles" </string>
- <string> "Particles2D" </string>
+ <string> "visibility/opacity" </string>
<string> "visibility/blend_mode" </string>
<string> "config/amount" </string>
<string> "config/lifetime" </string>
- <string> "config/time_scale" </string>
- <string> "config/preprocess" </string>
- <string> "config/emit_timeout" </string>
- <string> "config/emitting" </string>
- <string> "config/offset" </string>
- <string> "config/half_extents" </string>
<string> "config/local_space" </string>
- <string> "config/explosiveness" </string>
- <string> "config/flip_h" </string>
- <string> "config/flip_v" </string>
<string> "config/texture" </string>
<string> "params/direction" </string>
<string> "params/spread" </string>
@@ -121,54 +122,27 @@
<string> "params/radial_accel" </string>
<string> "params/tangential_accel" </string>
<string> "params/damping" </string>
+ <string> "params/initial_angle" </string>
<string> "params/initial_size" </string>
<string> "params/final_size" </string>
<string> "params/hue_variation" </string>
- <string> "randomness/direction" </string>
- <string> "randomness/spread" </string>
- <string> "randomness/linear_velocity" </string>
- <string> "randomness/spin_velocity" </string>
- <string> "randomness/orbit_velocity" </string>
- <string> "randomness/gravity_direction" </string>
- <string> "randomness/gravity_strength" </string>
- <string> "randomness/radial_accel" </string>
- <string> "randomness/tangential_accel" </string>
- <string> "randomness/damping" </string>
- <string> "randomness/initial_size" </string>
- <string> "randomness/final_size" </string>
- <string> "randomness/hue_variation" </string>
- <string> "color_phases/count" </string>
- <string> "phase_0/pos" </string>
- <string> "phase_0/color" </string>
- <string> "phase_1/pos" </string>
- <string> "phase_1/color" </string>
- <string> "phase_2/pos" </string>
- <string> "phase_2/color" </string>
- <string> "phase_3/pos" </string>
- <string> "phase_3/color" </string>
- <string> "emission_points" </string>
+ <string> "params/anim_speed_scale" </string>
+ <string> "params/anim_initial_pos" </string>
+ <string> "color/color_ramp" </string>
+ <string> "Particles2D" </string>
<string> "sprite" </string>
- <string> "Sprite" </string>
<string> "texture" </string>
- <string> "centered" </string>
- <string> "offset" </string>
- <string> "flip_h" </string>
- <string> "flip_v" </string>
- <string> "vframes" </string>
- <string> "hframes" </string>
- <string> "frame" </string>
- <string> "modulate" </string>
- <string> "region" </string>
- <string> "region_rect" </string>
+ <string> "Sprite" </string>
<string> "CollisionShape2D" </string>
<string> "shape" </string>
<string> "trigger" </string>
+ <string> "_update_shape_index" </string>
<string> "Timer" </string>
+ <string> "process_mode" </string>
<string> "wait_time" </string>
<string> "one_shot" </string>
<string> "autostart" </string>
<string> "anim" </string>
- <string> "AnimationPlayer" </string>
<string> "playback/process_mode" </string>
<string> "playback/default_blend_time" </string>
<string> "root/root" </string>
@@ -177,128 +151,158 @@
<string> "playback/speed" </string>
<string> "blend_times" </string>
<string> "autoplay" </string>
+ <string> "AnimationPlayer" </string>
<string> "disable" </string>
<string> "timeout" </string>
</string_array>
- <string> "version" </string>
- <int> 1 </int>
- <string> "conn_count" </string>
- <int> 1 </int>
<string> "node_count" </string>
<int> 6 </int>
+ <string> "node_paths" </string>
+ <array len="0" shared="false">
+ </array>
+ <string> "nodes" </string>
+ <int_array len="166"> -1, -1, 24, 0, -1, 23, 1, 0, 2, 1, 3, 2, 4, 0, 5, 3, 6, 3, 7, 4, 8, 5, 9, 5, 10, 6, 11, 5, 12, 0, 13, 7, 14, 4, 15, 0, 16, 0, 17, 8, 18, 9, 19, 6, 20, 10, 21, 10, 22, 11, 23, 12, 0, 0, 0, 49, 25, -1, 23, 26, 13, 27, 3, 28, 14, 29, 15, 30, 0, 31, 16, 32, 6, 33, 17, 34, 6, 35, 6, 36, 6, 37, 6, 38, 6, 39, 6, 40, 6, 41, 6, 42, 6, 43, 5, 44, 6, 45, 6, 46, 5, 47, 6, 48, 18, 0, 0, 0, 52, 50, -1, 1, 51, 16, 0, 0, 0, 53, 53, -1, 3, 54, 1, 55, 0, 56, 19, 0, 0, 0, 57, 57, -1, 4, 58, 3, 59, 5, 60, 8, 61, 0, 0, 0, 0, 71, 62, -1, 8, 63, 3, 64, 6, 65, 20, 66, 21, 67, 8, 68, 5, 69, 22, 70, 23, 0 </int_array>
<string> "variants" </string>
- <array len="27" shared="false">
- <bool> True </bool>
- <real> 1 </real>
- <vector2> 0, 0 </vector2>
- <real> 0 </real>
- <vector2> 1, 1 </vector2>
- <int> 1 </int>
+ <array len="24" shared="false">
+ <bool> False </bool>
<resource resource_type="Shape2D" path="local://1"> </resource>
<matrix32> 1, 0, 0, 1, 0, 0 </matrix32>
- <bool> False </bool>
+ <int> 1 </int>
<int> 0 </int>
+ <real> 1 </real>
+ <real> 0 </real>
<int> 2 </int>
- <resource resource_type="Script" path="res://bullet.*"> </resource>
+ <bool> True </bool>
+ <vector2> 0, 0 </vector2>
+ <real> -1 </real>
+ <resource external="0"> </resource>
<dictionary shared="false">
+ <string> "__editor_plugin_screen__" </string>
+ <string> "2D" </string>
<string> "__editor_plugin_states__" </string>
<dictionary shared="false">
- <string> "Script" </string>
- <dictionary shared="false">
- <string> "current" </string>
- <int> 2 </int>
- <string> "sources" </string>
- <array len="3" shared="false">
- <string> "res://enemy.gd" </string>
- <string> "res://player.gd" </string>
- <string> "res://bullet.gd" </string>
- </array>
- </dictionary>
<string> "2D" </string>
<dictionary shared="false">
- <string> "pixel_snap" </string>
+ <string> "ofs" </string>
+ <vector2> -74.7573, -35.9676 </vector2>
+ <string> "snap_grid" </string>
<bool> False </bool>
+ <string> "snap_offset" </string>
+ <vector2> 0, 0 </vector2>
+ <string> "snap_pixel" </string>
+ <bool> False </bool>
+ <string> "snap_relative" </string>
+ <bool> False </bool>
+ <string> "snap_rotation" </string>
+ <bool> False </bool>
+ <string> "snap_rotation_offset" </string>
+ <real> 0 </real>
+ <string> "snap_rotation_step" </string>
+ <real> 0.261799 </real>
+ <string> "snap_show_grid" </string>
+ <bool> False </bool>
+ <string> "snap_step" </string>
+ <vector2> 10, 10 </vector2>
<string> "zoom" </string>
<real> 3.424785 </real>
- <string> "ofs" </string>
- <vector2> -74.7573, -35.9676 </vector2>
</dictionary>
<string> "3D" </string>
<dictionary shared="false">
- <string> "zfar" </string>
- <real> 500 </real>
+ <string> "ambient_light_color" </string>
+ <color> 0.15, 0.15, 0.15, 1 </color>
+ <string> "default_light" </string>
+ <bool> True </bool>
+ <string> "default_srgb" </string>
+ <bool> False </bool>
+ <string> "deflight_rot_x" </string>
+ <real> 0.942478 </real>
+ <string> "deflight_rot_y" </string>
+ <real> 0.628319 </real>
<string> "fov" </string>
<real> 45 </real>
+ <string> "show_grid" </string>
+ <bool> True </bool>
+ <string> "show_origin" </string>
+ <bool> True </bool>
+ <string> "viewport_mode" </string>
+ <int> 1 </int>
<string> "viewports" </string>
<array len="4" shared="false">
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> True </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
</array>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
+ <string> "zfar" </string>
+ <real> 500 </real>
<string> "znear" </string>
<real> 0.1 </real>
</dictionary>
+ <string> "Anim" </string>
+ <dictionary shared="false">
+ <string> "visible" </string>
+ <bool> False </bool>
+ </dictionary>
</dictionary>
<string> "__editor_run_settings__" </string>
<dictionary shared="false">
@@ -307,29 +311,22 @@
<string> "run_mode" </string>
<int> 0 </int>
</dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "2D" </string>
</dictionary>
<real> 0.559322 </real>
<int> 24 </int>
<real> 0.1 </real>
- <resource resource_type="Texture" path="res://bullet.*"> </resource>
+ <resource external="1"> </resource>
<real> 10 </real>
- <color> 1, 1, 1, 1 </color>
- <color> 1, 0, 0, 0 </color>
- <color> 0, 0, 0, 1 </color>
- <vector2_array len="0"> </vector2_array>
- <rect2> 0, 0, 0, 0 </rect2>
+ <resource resource_type="ColorRamp" path="local://3"> </resource>
+ <int> -1 </int>
<node_path> ".." </node_path>
<resource resource_type="Animation" path="local://2"> </resource>
<array len="0" shared="false">
</array>
<string> "" </string>
</array>
- <string> "nodes" </string>
- <int_array len="282"> -1, -1, 1, 0, -1, 25, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 8, 13, 9, 14, 1, 15, 1, 16, 3, 17, 8, 18, 10, 19, 9, 20, 8, 21, 0, 22, 0, 23, 2, 24, 3, 25, 11, 26, 12, 0, 0, 0, 28, 27, -1, 57, 2, 0, 3, 13, 4, 1, 5, 0, 29, 5, 6, 2, 7, 3, 8, 4, 30, 14, 31, 15, 32, 1, 33, 3, 34, 3, 35, 0, 36, 2, 37, 2, 38, 8, 39, 1, 40, 8, 41, 8, 42, 16, 43, 3, 44, 17, 45, 3, 46, 3, 47, 3, 48, 3, 49, 3, 50, 3, 51, 3, 52, 3, 53, 1, 54, 3, 55, 3, 56, 3, 57, 3, 58, 3, 59, 3, 60, 3, 61, 3, 62, 3, 63, 3, 64, 3, 65, 3, 66, 3, 67, 3, 68, 3, 69, 10, 70, 3, 71, 18, 72, 1, 73, 19, 74, 1, 75, 20, 76, 1, 77, 20, 78, 21, 0, 0, 0, 80, 79, -1, 18, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 81, 16, 82, 0, 83, 2, 84, 8, 85, 8, 86, 5, 87, 5, 88, 9, 89, 18, 90, 8, 91, 22, 0, 0, 0, 92, 92, -1, 9, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 93, 6, 94, 8, 0, 0, 0, 95, 95, -1, 3, 96, 1, 97, 0, 98, 8, 0, 0, 0, 100, 99, -1, 8, 101, 5, 102, 3, 103, 23, 104, 24, 105, 0, 106, 1, 107, 25, 108, 26, 0 </int_array>
- <string> "conns" </string>
- <int_array len="6"> 4, 0, 110, 109, 2, 0 </int_array>
+ <string> "version" </string>
+ <int> 2 </int>
</dictionary>
</main_resource>
diff --git a/demos/2d/platformer/coin.gd b/demos/2d/platformer/coin.gd
index 3e31a395ae..1118732707 100644
--- a/demos/2d/platformer/coin.gd
+++ b/demos/2d/platformer/coin.gd
@@ -1,20 +1,19 @@
extends Area2D
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
-var taken=false
+# Member variables
+var taken = false
func _on_body_enter( body ):
if (not taken and body extends preload("res://player.gd")):
get_node("anim").play("taken")
- taken=true
+ taken = true
+
+func _on_coin_area_enter(area):
+ pass # replace with function body
-func _ready():
- # Initalization here
- pass
+func _on_coin_area_enter_shape(area_id, area, area_shape, area_shape):
+ pass # replace with function body
diff --git a/demos/2d/platformer/coin.xml b/demos/2d/platformer/coin.xml
index 194ea711b0..f33a63bd57 100644
--- a/demos/2d/platformer/coin.xml
+++ b/demos/2d/platformer/coin.xml
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="9" version="1.0" version_name="Godot Engine v1.0.3917-beta1">
- <ext_resource path="res://bullet.*" type="Texture"></ext_resource>
- <ext_resource path="res://coin.*" type="Texture"></ext_resource>
- <ext_resource path="res://sound_coin.*" type="Sample"></ext_resource>
- <ext_resource path="res://coin.*" type="Script"></ext_resource>
+<resource_file type="PackedScene" subresource_count="10" version="2.0" version_name="Godot Engine v2.0.alpha.custom_build">
+ <ext_resource path="res://bullet.png" type="Texture" index="3"></ext_resource>
+ <ext_resource path="res://coin.png" type="Texture" index="1"></ext_resource>
+ <ext_resource path="res://sound_coin.wav" type="Sample" index="2"></ext_resource>
+ <ext_resource path="res://coin.gd" type="Script" index="0"></ext_resource>
<resource type="CircleShape2D" path="local://1">
<real name="custom_solver_bias"> 0 </real>
<real name="radius"> 10 </real>
@@ -20,14 +20,14 @@
<dictionary name="tracks/0/keys" shared="false">
<string> "cont" </string>
<bool> True </bool>
+ <string> "times" </string>
+ <real_array len="1"> 0 </real_array>
<string> "transitions" </string>
<real_array len="1"> 1 </real_array>
<string> "values" </string>
<array len="1" shared="false">
<int> 0 </int>
</array>
- <string> "times" </string>
- <real_array len="1"> 0 </real_array>
</dictionary>
<string name="tracks/1/type"> "value" </string>
<node_path name="tracks/1/path"> "sound:play/play" </node_path>
@@ -35,14 +35,14 @@
<dictionary name="tracks/1/keys" shared="false">
<string> "cont" </string>
<bool> False </bool>
+ <string> "times" </string>
+ <real_array len="1"> 0 </real_array>
<string> "transitions" </string>
<real_array len="1"> 1 </real_array>
<string> "values" </string>
<array len="1" shared="false">
<string> "coin" </string>
</array>
- <string> "times" </string>
- <real_array len="1"> 0 </real_array>
</dictionary>
<string name="tracks/2/type"> "value" </string>
<node_path name="tracks/2/path"> "particles:visibility/self_opacity" </node_path>
@@ -50,6 +50,8 @@
<dictionary name="tracks/2/keys" shared="false">
<string> "cont" </string>
<bool> True </bool>
+ <string> "times" </string>
+ <real_array len="2"> 0, 1.66 </real_array>
<string> "transitions" </string>
<real_array len="2"> 1, 1 </real_array>
<string> "values" </string>
@@ -57,8 +59,6 @@
<real> 1 </real>
<real> 0 </real>
</array>
- <string> "times" </string>
- <real_array len="2"> 0, 1.66 </real_array>
</dictionary>
<string name="tracks/3/type"> "value" </string>
<node_path name="tracks/3/path"> "sprite:visibility/self_opacity" </node_path>
@@ -66,6 +66,8 @@
<dictionary name="tracks/3/keys" shared="false">
<string> "cont" </string>
<bool> True </bool>
+ <string> "times" </string>
+ <real_array len="2"> 0, 0.4 </real_array>
<string> "transitions" </string>
<real_array len="2"> 1, 1 </real_array>
<string> "values" </string>
@@ -73,8 +75,6 @@
<real> 1 </real>
<real> 0 </real>
</array>
- <string> "times" </string>
- <real_array len="2"> 0, 0.4 </real_array>
</dictionary>
<string name="tracks/4/type"> "value" </string>
<node_path name="tracks/4/path"> "particles:config/emitting" </node_path>
@@ -82,19 +82,21 @@
<dictionary name="tracks/4/keys" shared="false">
<string> "cont" </string>
<bool> False </bool>
+ <string> "times" </string>
+ <real_array len="1"> 0 </real_array>
<string> "transitions" </string>
<real_array len="1"> 1 </real_array>
<string> "values" </string>
<array len="1" shared="false">
<bool> True </bool>
</array>
- <string> "times" </string>
- <real_array len="1"> 0 </real_array>
</dictionary>
<string name="tracks/5/type"> "method" </string>
<node_path name="tracks/5/path"> "." </node_path>
<int name="tracks/5/interp"> 1 </int>
<dictionary name="tracks/5/keys" shared="false">
+ <string> "times" </string>
+ <real_array len="1"> 2.7 </real_array>
<string> "transitions" </string>
<real_array len="1"> 1 </real_array>
<string> "values" </string>
@@ -107,8 +109,6 @@
<string> "queue_free" </string>
</dictionary>
</array>
- <string> "times" </string>
- <real_array len="1"> 2.7 </real_array>
</dictionary>
</resource>
@@ -123,6 +123,8 @@
<dictionary name="tracks/0/keys" shared="false">
<string> "cont" </string>
<bool> False </bool>
+ <string> "times" </string>
+ <real_array len="7"> 0, 0.25, 0.5, 0.75, 1, 1.25, 1.5 </real_array>
<string> "transitions" </string>
<real_array len="7"> 1, 1, 1, 1, 1, 1, 1 </real_array>
<string> "values" </string>
@@ -135,8 +137,6 @@
<int> 1 </int>
<int> 0 </int>
</array>
- <string> "times" </string>
- <real_array len="7"> 0, 0.25, 0.5, 0.75, 1, 1.25, 1.5 </real_array>
</dictionary>
</resource>
@@ -147,49 +147,43 @@
<string> "pitch" </string>
<real> 1 </real>
<string> "sample" </string>
- <resource resource_type="Sample" path="res://sound_coin.*"> </resource>
+ <resource external="2"> </resource>
</dictionary>
</resource>
+ <resource type="ColorRamp" path="local://5">
+ <real_array name="offsets" len="2"> 0, 1 </real_array>
+ <color_array name="colors" len="2"> 1, 1, 1, 1, 0, 0, 0, 1 </color_array>
+
+ </resource>
<main_resource>
<dictionary name="_bundled" shared="false">
+ <string> "conn_count" </string>
+ <int> 1 </int>
+ <string> "conns" </string>
+ <int_array len="6"> 0, 0, 76, 75, 2, 0 </int_array>
+ <string> "editable_instances" </string>
+ <array len="0" shared="false">
+ </array>
<string> "names" </string>
- <string_array len="115">
+ <string_array len="77">
<string> "coin" </string>
- <string> "Area2D" </string>
- <string> "visibility/visible" </string>
- <string> "visibility/opacity" </string>
- <string> "visibility/self_opacity" </string>
- <string> "visibility/on_top" </string>
- <string> "transform/pos" </string>
- <string> "transform/rot" </string>
- <string> "transform/scale" </string>
- <string> "shape_count" </string>
+ <string> "input/pickable" </string>
<string> "shapes/0/shape" </string>
<string> "shapes/0/transform" </string>
<string> "shapes/0/trigger" </string>
- <string> "gravity_point" </string>
<string> "gravity_vec" </string>
<string> "gravity" </string>
- <string> "density" </string>
- <string> "monitoring" </string>
+ <string> "linear_damp" </string>
+ <string> "angular_damp" </string>
<string> "script/script" </string>
<string> "__meta__" </string>
+ <string> "Area2D" </string>
<string> "sprite" </string>
- <string> "Sprite" </string>
<string> "texture" </string>
- <string> "centered" </string>
- <string> "offset" </string>
- <string> "flip_h" </string>
- <string> "flip_v" </string>
- <string> "vframes" </string>
<string> "hframes" </string>
- <string> "frame" </string>
- <string> "modulate" </string>
- <string> "region" </string>
- <string> "region_rect" </string>
+ <string> "Sprite" </string>
<string> "anim" </string>
- <string> "AnimationPlayer" </string>
<string> "playback/process_mode" </string>
<string> "playback/default_blend_time" </string>
<string> "root/root" </string>
@@ -199,12 +193,13 @@
<string> "playback/speed" </string>
<string> "blend_times" </string>
<string> "autoplay" </string>
+ <string> "AnimationPlayer" </string>
<string> "collision" </string>
- <string> "CollisionShape2D" </string>
<string> "shape" </string>
<string> "trigger" </string>
+ <string> "_update_shape_index" </string>
+ <string> "CollisionShape2D" </string>
<string> "sound" </string>
- <string> "SamplePlayer2D" </string>
<string> "params/volume_db" </string>
<string> "params/pitch_scale" </string>
<string> "params/attenuation/min_distance" </string>
@@ -213,19 +208,13 @@
<string> "config/polyphony" </string>
<string> "config/samples" </string>
<string> "config/pitch_random" </string>
+ <string> "SamplePlayer2D" </string>
<string> "particles" </string>
- <string> "Particles2D" </string>
<string> "visibility/blend_mode" </string>
<string> "config/amount" </string>
<string> "config/lifetime" </string>
- <string> "config/time_scale" </string>
- <string> "config/preprocess" </string>
- <string> "config/emit_timeout" </string>
<string> "config/emitting" </string>
- <string> "config/offset" </string>
<string> "config/half_extents" </string>
- <string> "config/local_space" </string>
- <string> "config/explosiveness" </string>
<string> "config/texture" </string>
<string> "params/direction" </string>
<string> "params/spread" </string>
@@ -237,160 +226,170 @@
<string> "params/radial_accel" </string>
<string> "params/tangential_accel" </string>
<string> "params/damping" </string>
+ <string> "params/initial_angle" </string>
<string> "params/initial_size" </string>
<string> "params/final_size" </string>
<string> "params/hue_variation" </string>
- <string> "randomness/direction" </string>
- <string> "randomness/spread" </string>
- <string> "randomness/linear_velocity" </string>
- <string> "randomness/spin_velocity" </string>
- <string> "randomness/orbit_velocity" </string>
- <string> "randomness/gravity_direction" </string>
- <string> "randomness/gravity_strength" </string>
- <string> "randomness/radial_accel" </string>
- <string> "randomness/tangential_accel" </string>
- <string> "randomness/damping" </string>
- <string> "randomness/initial_size" </string>
- <string> "randomness/final_size" </string>
- <string> "randomness/hue_variation" </string>
- <string> "color_phases/count" </string>
- <string> "phase_0/pos" </string>
- <string> "phase_0/color" </string>
- <string> "phase_1/pos" </string>
- <string> "phase_1/color" </string>
- <string> "phase_2/pos" </string>
- <string> "phase_2/color" </string>
- <string> "phase_3/pos" </string>
- <string> "phase_3/color" </string>
- <string> "emission_points" </string>
+ <string> "params/anim_speed_scale" </string>
+ <string> "params/anim_initial_pos" </string>
+ <string> "color/color_ramp" </string>
+ <string> "Particles2D" </string>
<string> "enabler" </string>
- <string> "VisibilityEnabler2D" </string>
<string> "rect" </string>
<string> "enabler/pause_animations" </string>
<string> "enabler/freeze_bodies" </string>
+ <string> "enabler/pause_particles" </string>
+ <string> "enabler/process_parent" </string>
+ <string> "enabler/fixed_process_parent" </string>
+ <string> "VisibilityEnabler2D" </string>
<string> "_on_body_enter" </string>
<string> "body_enter" </string>
</string_array>
- <string> "version" </string>
- <int> 1 </int>
- <string> "conn_count" </string>
- <int> 1 </int>
<string> "node_count" </string>
<int> 7 </int>
+ <string> "node_paths" </string>
+ <array len="0" shared="false">
+ </array>
+ <string> "nodes" </string>
+ <int_array len="171"> -1, -1, 11, 0, -1, 10, 1, 0, 2, 1, 3, 2, 4, 3, 5, 4, 6, 5, 7, 6, 8, 7, 9, 8, 10, 9, 0, 0, 0, 15, 12, -1, 2, 13, 10, 14, 11, 0, 0, 0, 26, 16, -1, 9, 17, 12, 18, 13, 19, 14, 20, 15, 21, 16, 22, 0, 23, 17, 24, 18, 25, 19, 0, 0, 0, 31, 27, -1, 3, 28, 1, 29, 3, 30, 20, 0, 0, 0, 41, 32, -1, 8, 33, 13, 34, 7, 35, 7, 36, 21, 37, 7, 38, 12, 39, 22, 40, 13, 0, 0, 0, 66, 42, -1, 23, 43, 12, 44, 23, 45, 24, 46, 3, 47, 25, 48, 26, 49, 13, 50, 27, 51, 13, 52, 13, 53, 13, 54, 13, 55, 13, 56, 13, 57, 13, 58, 13, 59, 13, 60, 28, 61, 28, 62, 13, 63, 7, 64, 13, 65, 29, 0, 0, 0, 74, 67, -1, 6, 68, 30, 69, 0, 70, 0, 71, 0, 72, 3, 73, 3, 0 </int_array>
<string> "variants" </string>
- <array len="37" shared="false">
+ <array len="31" shared="false">
<bool> True </bool>
- <real> 1 </real>
- <vector2> 0, 0 </vector2>
- <real> 0 </real>
- <vector2> 1, 1 </vector2>
- <int> 1 </int>
<resource resource_type="Shape2D" path="local://1"> </resource>
<matrix32> 1, 0, 0, 1, 0, 0 </matrix32>
<bool> False </bool>
<vector2> 0, 1 </vector2>
<real> 98 </real>
<real> 0.1 </real>
- <resource resource_type="Script" path="res://coin.*"> </resource>
+ <real> 1 </real>
+ <resource external="0"> </resource>
<dictionary shared="false">
+ <string> "__editor_plugin_screen__" </string>
+ <string> "2D" </string>
<string> "__editor_plugin_states__" </string>
<dictionary shared="false">
- <string> "Script" </string>
- <dictionary shared="false">
- <string> "current" </string>
- <int> 2 </int>
- <string> "sources" </string>
- <array len="3" shared="false">
- <string> "res://enemy.gd" </string>
- <string> "res://player.gd" </string>
- <string> "res://coin.gd" </string>
- </array>
- </dictionary>
<string> "2D" </string>
<dictionary shared="false">
- <string> "pixel_snap" </string>
+ <string> "ofs" </string>
+ <vector2> -34.3697, -21.6562 </vector2>
+ <string> "snap_grid" </string>
+ <bool> False </bool>
+ <string> "snap_offset" </string>
+ <vector2> 0, 0 </vector2>
+ <string> "snap_pixel" </string>
+ <bool> False </bool>
+ <string> "snap_relative" </string>
+ <bool> False </bool>
+ <string> "snap_rotation" </string>
+ <bool> False </bool>
+ <string> "snap_rotation_offset" </string>
+ <real> 0 </real>
+ <string> "snap_rotation_step" </string>
+ <real> 0.261799 </real>
+ <string> "snap_show_grid" </string>
<bool> False </bool>
+ <string> "snap_step" </string>
+ <vector2> 10, 10 </vector2>
<string> "zoom" </string>
<real> 3.794776 </real>
- <string> "ofs" </string>
- <vector2> -34.3697, -21.6562 </vector2>
</dictionary>
<string> "3D" </string>
<dictionary shared="false">
- <string> "zfar" </string>
- <real> 500 </real>
+ <string> "ambient_light_color" </string>
+ <color> 0.15, 0.15, 0.15, 1 </color>
+ <string> "default_light" </string>
+ <bool> True </bool>
+ <string> "default_srgb" </string>
+ <bool> False </bool>
+ <string> "deflight_rot_x" </string>
+ <real> 0.942478 </real>
+ <string> "deflight_rot_y" </string>
+ <real> 0.628319 </real>
<string> "fov" </string>
<real> 45 </real>
+ <string> "show_grid" </string>
+ <bool> True </bool>
+ <string> "show_origin" </string>
+ <bool> True </bool>
+ <string> "viewport_mode" </string>
+ <int> 1 </int>
<string> "viewports" </string>
<array len="4" shared="false">
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> True </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
</array>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
+ <string> "zfar" </string>
+ <real> 500 </real>
<string> "znear" </string>
<real> 0.1 </real>
</dictionary>
+ <string> "Anim" </string>
+ <dictionary shared="false">
+ <string> "visible" </string>
+ <bool> False </bool>
+ </dictionary>
</dictionary>
<string> "__editor_run_settings__" </string>
<dictionary shared="false">
@@ -399,14 +398,11 @@
<string> "run_mode" </string>
<int> 0 </int>
</dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "2D" </string>
</dictionary>
- <resource resource_type="Texture" path="res://coin.*"> </resource>
+ <resource external="1"> </resource>
<int> 4 </int>
- <int> 0 </int>
- <color> 1, 1, 1, 1 </color>
- <rect2> 0, 0, 0, 0 </rect2>
+ <int> 1 </int>
+ <real> 0 </real>
<node_path> ".." </node_path>
<resource resource_type="Animation" path="local://2"> </resource>
<resource resource_type="Animation" path="local://3"> </resource>
@@ -414,23 +410,20 @@
<array len="0" shared="false">
</array>
<string> "spin" </string>
+ <int> -1 </int>
<real> 2048 </real>
<resource resource_type="SampleLibrary" path="local://4"> </resource>
<int> 8 </int>
<real> 0.4 </real>
<vector2> 5, 5 </vector2>
- <resource resource_type="Texture" path="res://bullet.*"> </resource>
+ <resource external="3"> </resource>
<real> 10 </real>
<real> 0.2 </real>
- <int> 2 </int>
- <color> 0, 0, 0, 1 </color>
- <vector2_array len="0"> </vector2_array>
+ <resource resource_type="ColorRamp" path="local://5"> </resource>
<rect2> -10, -10, 20, 20 </rect2>
</array>
- <string> "nodes" </string>
- <int_array len="317"> -1, -1, 1, 0, -1, 18, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 8, 13, 8, 14, 9, 15, 10, 16, 11, 17, 0, 18, 12, 19, 13, 0, 0, 0, 21, 20, -1, 18, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 22, 14, 23, 0, 24, 2, 25, 8, 26, 8, 27, 5, 28, 15, 29, 16, 30, 17, 31, 8, 32, 18, 0, 0, 0, 34, 33, -1, 9, 35, 5, 36, 3, 37, 19, 38, 20, 39, 21, 40, 0, 41, 22, 42, 23, 43, 24, 0, 0, 0, 45, 44, -1, 9, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 46, 6, 47, 8, 0, 0, 0, 49, 48, -1, 15, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 50, 3, 51, 1, 52, 1, 53, 25, 54, 1, 55, 5, 56, 26, 57, 3, 0, 0, 0, 59, 58, -1, 55, 2, 0, 3, 1, 4, 1, 5, 0, 60, 5, 6, 2, 7, 3, 8, 4, 61, 27, 62, 28, 63, 1, 64, 3, 65, 3, 66, 8, 67, 2, 68, 29, 69, 0, 70, 1, 71, 30, 72, 3, 73, 31, 74, 3, 75, 3, 76, 3, 77, 3, 78, 3, 79, 3, 80, 3, 81, 3, 82, 32, 83, 32, 84, 3, 85, 3, 86, 3, 87, 3, 88, 3, 89, 3, 90, 3, 91, 3, 92, 3, 93, 3, 94, 3, 95, 3, 96, 3, 97, 3, 98, 33, 99, 3, 100, 17, 101, 1, 102, 34, 103, 1, 104, 34, 105, 1, 106, 34, 107, 35, 0, 0, 0, 109, 108, -1, 10, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 110, 36, 111, 0, 112, 0, 0 </int_array>
- <string> "conns" </string>
- <int_array len="6"> 0, 0, 114, 113, 2, 0 </int_array>
+ <string> "version" </string>
+ <int> 2 </int>
</dictionary>
</main_resource>
diff --git a/demos/2d/platformer/enemy.gd b/demos/2d/platformer/enemy.gd
index a264cd0cff..5a4d8af579 100644
--- a/demos/2d/platformer/enemy.gd
+++ b/demos/2d/platformer/enemy.gd
@@ -1,98 +1,83 @@
extends RigidBody2D
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
+# Member variables
const STATE_WALKING = 0
const STATE_DYING = 1
-
var state = STATE_WALKING
-
var direction = -1
-var anim=""
+var anim = ""
-var rc_left=null
-var rc_right=null
+var rc_left = null
+var rc_right = null
var WALK_SPEED = 50
var bullet_class = preload("res://bullet.gd")
+
func _die():
queue_free()
+
func _pre_explode():
- #stay there
+ # Stay there
clear_shapes()
set_mode(MODE_STATIC)
get_node("sound").play("explode")
-
-func _integrate_forces(s):
+func _integrate_forces(s):
var lv = s.get_linear_velocity()
- var new_anim=anim
+ var new_anim = anim
- if (state==STATE_DYING):
- new_anim="explode"
- elif (state==STATE_WALKING):
-
- new_anim="walk"
+ if (state == STATE_DYING):
+ new_anim = "explode"
+ elif (state == STATE_WALKING):
+ new_anim = "walk"
- var wall_side=0.0
+ var wall_side = 0.0
for i in range(s.get_contact_count()):
var cc = s.get_contact_collider_object(i)
var dp = s.get_contact_local_normal(i)
if (cc):
-
-
if (cc extends bullet_class and not cc.disabled):
set_mode(MODE_RIGID)
- state=STATE_DYING
- #lv=s.get_contact_local_normal(i)*400
+ state = STATE_DYING
+ #lv = s.get_contact_local_normal(i)*400
s.set_angular_velocity(sign(dp.x)*33.0)
set_friction(1)
cc.disable()
get_node("sound").play("hit")
-
break
-
-
- if (dp.x>0.9):
- wall_side=1.0
- elif (dp.x<-0.9):
- wall_side=-1.0
-
- if (wall_side!=0 and wall_side!=direction):
-
- direction=-direction
- get_node("sprite").set_scale( Vector2(-direction,1) )
- if (direction<0 and not rc_left.is_colliding() and rc_right.is_colliding()):
- direction=-direction
- get_node("sprite").set_scale( Vector2(-direction,1) )
- elif (direction>0 and not rc_right.is_colliding() and rc_left.is_colliding()):
- direction=-direction
- get_node("sprite").set_scale( Vector2(-direction,1) )
-
-
- lv.x = direction * WALK_SPEED
- if( anim!=new_anim ):
- anim=new_anim
+ if (dp.x > 0.9):
+ wall_side = 1.0
+ elif (dp.x < -0.9):
+ wall_side = -1.0
+
+ if (wall_side != 0 and wall_side != direction):
+ direction = -direction
+ get_node("sprite").set_scale(Vector2(-direction, 1))
+ if (direction < 0 and not rc_left.is_colliding() and rc_right.is_colliding()):
+ direction = -direction
+ get_node("sprite").set_scale(Vector2(-direction, 1))
+ elif (direction > 0 and not rc_right.is_colliding() and rc_left.is_colliding()):
+ direction = -direction
+ get_node("sprite").set_scale(Vector2(-direction, 1))
+
+ lv.x = direction*WALK_SPEED
+
+ if(anim != new_anim):
+ anim = new_anim
get_node("anim").play(anim)
-
+
s.set_linear_velocity(lv)
func _ready():
- # Initalization here
- rc_left=get_node("raycast_left")
- rc_right=get_node("raycast_right")
-
-
-
+ rc_left = get_node("raycast_left")
+ rc_right = get_node("raycast_right")
diff --git a/demos/2d/platformer/enemy.xml b/demos/2d/platformer/enemy.xml
index 470797db46..72d2ff068e 100644
--- a/demos/2d/platformer/enemy.xml
+++ b/demos/2d/platformer/enemy.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="11" version="1.0" version_name="Godot Engine v1.0.3917-beta1">
- <ext_resource path="res://sound_explode.*" type="Sample"></ext_resource>
- <ext_resource path="res://enemy.*" type="Texture"></ext_resource>
- <ext_resource path="res://enemy.*" type="Script"></ext_resource>
- <ext_resource path="res://sound_hit.*" type="Sample"></ext_resource>
- <ext_resource path="res://bullet.*" type="Texture"></ext_resource>
+<resource_file type="PackedScene" subresource_count="12" version="2.0" version_name="Godot Engine v2.0.alpha.custom_build">
+ <ext_resource path="res://bullet.png" type="Texture" index="2"></ext_resource>
+ <ext_resource path="res://enemy.gd" type="Script" index="0"></ext_resource>
+ <ext_resource path="res://sound_explode.wav" type="Sample" index="3"></ext_resource>
+ <ext_resource path="res://sound_hit.wav" type="Sample" index="4"></ext_resource>
+ <ext_resource path="res://enemy.png" type="Texture" index="1"></ext_resource>
<resource type="CircleShape2D" path="local://1">
<real name="custom_solver_bias"> 0 </real>
<real name="radius"> 14 </real>
@@ -21,6 +21,8 @@
<dictionary name="tracks/0/keys" shared="false">
<string> "cont" </string>
<bool> False </bool>
+ <string> "times" </string>
+ <real_array len="10"> 0, 0.75, 1.5, 2.25, 3, 3.75, 4.5, 5.25, 6, 6.75 </real_array>
<string> "transitions" </string>
<real_array len="10"> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 </real_array>
<string> "values" </string>
@@ -36,8 +38,6 @@
<int> 7 </int>
<int> 5 </int>
</array>
- <string> "times" </string>
- <real_array len="10"> 0, 0.75, 1.5, 2.25, 3, 3.75, 4.5, 5.25, 6, 6.75 </real_array>
</dictionary>
</resource>
@@ -52,6 +52,8 @@
<dictionary name="tracks/0/keys" shared="false">
<string> "cont" </string>
<bool> True </bool>
+ <string> "times" </string>
+ <real_array len="2"> 3.58422, 4.33851 </real_array>
<string> "transitions" </string>
<real_array len="2"> 1, 1 </real_array>
<string> "values" </string>
@@ -59,8 +61,6 @@
<real> 1 </real>
<real> 0 </real>
</array>
- <string> "times" </string>
- <real_array len="2"> 3.58422, 4.33851 </real_array>
</dictionary>
<string name="tracks/1/type"> "value" </string>
<node_path name="tracks/1/path"> "sprite:frame" </node_path>
@@ -68,14 +68,14 @@
<dictionary name="tracks/1/keys" shared="false">
<string> "cont" </string>
<bool> True </bool>
+ <string> "times" </string>
+ <real_array len="1"> 0 </real_array>
<string> "transitions" </string>
<real_array len="1"> 1 </real_array>
<string> "values" </string>
<array len="1" shared="false">
<int> 4 </int>
</array>
- <string> "times" </string>
- <real_array len="1"> 0 </real_array>
</dictionary>
<string name="tracks/2/type"> "value" </string>
<node_path name="tracks/2/path"> "Particles2D:config/emitting" </node_path>
@@ -83,19 +83,21 @@
<dictionary name="tracks/2/keys" shared="false">
<string> "cont" </string>
<bool> False </bool>
+ <string> "times" </string>
+ <real_array len="1"> 3.47394 </real_array>
<string> "transitions" </string>
<real_array len="1"> 1 </real_array>
<string> "values" </string>
<array len="1" shared="false">
<bool> True </bool>
</array>
- <string> "times" </string>
- <real_array len="1"> 3.47394 </real_array>
</dictionary>
<string name="tracks/3/type"> "method" </string>
<node_path name="tracks/3/path"> "." </node_path>
<int name="tracks/3/interp"> 1 </int>
<dictionary name="tracks/3/keys" shared="false">
+ <string> "times" </string>
+ <real_array len="2"> 3.20357, 5.07305 </real_array>
<string> "transitions" </string>
<real_array len="2"> 1, 1 </real_array>
<string> "values" </string>
@@ -115,8 +117,6 @@
<string> "_die" </string>
</dictionary>
</array>
- <string> "times" </string>
- <real_array len="2"> 3.20357, 5.07305 </real_array>
</dictionary>
</resource>
@@ -131,6 +131,8 @@
<dictionary name="tracks/0/keys" shared="false">
<string> "cont" </string>
<bool> False </bool>
+ <string> "times" </string>
+ <real_array len="6"> 0, 0.25, 0.5, 0.75, 1, 1.25 </real_array>
<string> "transitions" </string>
<real_array len="6"> 1, 1, 1, 1, 1, 1 </real_array>
<string> "values" </string>
@@ -142,44 +144,46 @@
<int> 4 </int>
<int> 0 </int>
</array>
- <string> "times" </string>
- <real_array len="6"> 0, 0.25, 0.5, 0.75, 1, 1.25 </real_array>
</dictionary>
</resource>
+ <resource type="ColorRamp" path="local://6">
+ <real_array name="offsets" len="2"> 0, 1 </real_array>
+ <color_array name="colors" len="2"> 1, 0.884956, 0.823009, 1, 0.768627, 0.389381, 0, 0 </color_array>
+
+ </resource>
<resource type="SampleLibrary" path="local://5">
- <dictionary name="samples/explode" shared="false">
+ <dictionary name="samples/hit" shared="false">
<string> "db" </string>
<real> 0 </real>
<string> "pitch" </string>
<real> 1 </real>
<string> "sample" </string>
- <resource resource_type="Sample" path="res://sound_explode.*"> </resource>
+ <resource external="4"> </resource>
</dictionary>
- <dictionary name="samples/hit" shared="false">
+ <dictionary name="samples/explode" shared="false">
<string> "db" </string>
<real> 0 </real>
<string> "pitch" </string>
<real> 1 </real>
<string> "sample" </string>
- <resource resource_type="Sample" path="res://sound_hit.*"> </resource>
+ <resource external="3"> </resource>
</dictionary>
</resource>
<main_resource>
<dictionary name="_bundled" shared="false">
+ <string> "conn_count" </string>
+ <int> 0 </int>
+ <string> "conns" </string>
+ <int_array len="0"> </int_array>
+ <string> "editable_instances" </string>
+ <array len="0" shared="false">
+ </array>
<string> "names" </string>
- <string_array len="132">
+ <string_array len="108">
<string> "enemy" </string>
- <string> "RigidBody2D" </string>
- <string> "visibility/visible" </string>
- <string> "visibility/opacity" </string>
- <string> "visibility/self_opacity" </string>
- <string> "visibility/on_top" </string>
- <string> "transform/pos" </string>
- <string> "transform/rot" </string>
- <string> "transform/scale" </string>
- <string> "shape_count" </string>
+ <string> "input/pickable" </string>
<string> "shapes/0/shape" </string>
<string> "shapes/0/transform" </string>
<string> "shapes/0/trigger" </string>
@@ -189,27 +193,37 @@
<string> "shapes/2/shape" </string>
<string> "shapes/2/transform" </string>
<string> "shapes/2/trigger" </string>
+ <string> "collision/layers" </string>
+ <string> "collision/mask" </string>
<string> "mode" </string>
<string> "mass" </string>
<string> "friction" </string>
<string> "bounce" </string>
+ <string> "gravity_scale" </string>
<string> "custom_integrator" </string>
<string> "continuous_cd" </string>
<string> "contacts_reported" </string>
<string> "contact_monitor" </string>
- <string> "active" </string>
+ <string> "sleeping" </string>
<string> "can_sleep" </string>
<string> "velocity/linear" </string>
<string> "velocity/angular" </string>
+ <string> "damp_override/linear" </string>
+ <string> "damp_override/angular" </string>
<string> "script/script" </string>
<string> "__meta__" </string>
+ <string> "RigidBody2D" </string>
<string> "enabler" </string>
- <string> "VisibilityEnabler2D" </string>
+ <string> "transform/pos" </string>
+ <string> "transform/scale" </string>
<string> "rect" </string>
<string> "enabler/pause_animations" </string>
<string> "enabler/freeze_bodies" </string>
+ <string> "enabler/pause_particles" </string>
+ <string> "enabler/process_parent" </string>
+ <string> "enabler/fixed_process_parent" </string>
+ <string> "VisibilityEnabler2D" </string>
<string> "anim" </string>
- <string> "AnimationPlayer" </string>
<string> "playback/process_mode" </string>
<string> "playback/default_blend_time" </string>
<string> "root/root" </string>
@@ -220,40 +234,32 @@
<string> "playback/speed" </string>
<string> "blend_times" </string>
<string> "autoplay" </string>
+ <string> "AnimationPlayer" </string>
+ <string> "sprite" </string>
+ <string> "texture" </string>
+ <string> "hframes" </string>
+ <string> "frame" </string>
+ <string> "Sprite" </string>
<string> "CollisionShape2D" </string>
<string> "shape" </string>
<string> "trigger" </string>
+ <string> "_update_shape_index" </string>
<string> "CollisionShape2D 2" </string>
<string> "CollisionShape2D 3" </string>
- <string> "sprite" </string>
- <string> "Sprite" </string>
- <string> "texture" </string>
- <string> "centered" </string>
- <string> "offset" </string>
- <string> "flip_h" </string>
- <string> "flip_v" </string>
- <string> "vframes" </string>
- <string> "hframes" </string>
- <string> "frame" </string>
- <string> "modulate" </string>
- <string> "region" </string>
- <string> "region_rect" </string>
<string> "raycast_left" </string>
- <string> "RayCast2D" </string>
<string> "enabled" </string>
<string> "cast_to" </string>
+ <string> "layer_mask" </string>
+ <string> "type_mask" </string>
+ <string> "RayCast2D" </string>
<string> "raycast_right" </string>
<string> "Particles2D" </string>
+ <string> "visibility/self_opacity" </string>
<string> "visibility/blend_mode" </string>
<string> "config/amount" </string>
<string> "config/lifetime" </string>
- <string> "config/time_scale" </string>
- <string> "config/preprocess" </string>
<string> "config/emit_timeout" </string>
<string> "config/emitting" </string>
- <string> "config/offset" </string>
- <string> "config/half_extents" </string>
- <string> "config/local_space" </string>
<string> "config/explosiveness" </string>
<string> "config/texture" </string>
<string> "params/direction" </string>
@@ -266,34 +272,15 @@
<string> "params/radial_accel" </string>
<string> "params/tangential_accel" </string>
<string> "params/damping" </string>
+ <string> "params/initial_angle" </string>
<string> "params/initial_size" </string>
<string> "params/final_size" </string>
<string> "params/hue_variation" </string>
- <string> "randomness/direction" </string>
- <string> "randomness/spread" </string>
- <string> "randomness/linear_velocity" </string>
+ <string> "params/anim_speed_scale" </string>
+ <string> "params/anim_initial_pos" </string>
<string> "randomness/spin_velocity" </string>
- <string> "randomness/orbit_velocity" </string>
- <string> "randomness/gravity_direction" </string>
- <string> "randomness/gravity_strength" </string>
- <string> "randomness/radial_accel" </string>
- <string> "randomness/tangential_accel" </string>
- <string> "randomness/damping" </string>
- <string> "randomness/initial_size" </string>
- <string> "randomness/final_size" </string>
- <string> "randomness/hue_variation" </string>
- <string> "color_phases/count" </string>
- <string> "phase_0/pos" </string>
- <string> "phase_0/color" </string>
- <string> "phase_1/pos" </string>
- <string> "phase_1/color" </string>
- <string> "phase_2/pos" </string>
- <string> "phase_2/color" </string>
- <string> "phase_3/pos" </string>
- <string> "phase_3/color" </string>
- <string> "emission_points" </string>
+ <string> "color/color_ramp" </string>
<string> "sound" </string>
- <string> "SamplePlayer2D" </string>
<string> "params/volume_db" </string>
<string> "params/pitch_scale" </string>
<string> "params/attenuation/min_distance" </string>
@@ -302,126 +289,159 @@
<string> "config/polyphony" </string>
<string> "config/samples" </string>
<string> "config/pitch_random" </string>
+ <string> "SamplePlayer2D" </string>
</string_array>
- <string> "version" </string>
- <int> 1 </int>
- <string> "conn_count" </string>
- <int> 0 </int>
<string> "node_count" </string>
<int> 11 </int>
+ <string> "node_paths" </string>
+ <array len="0" shared="false">
+ </array>
+ <string> "nodes" </string>
+ <int_array len="289"> -1, -1, 30, 0, -1, 29, 1, 0, 2, 1, 3, 2, 4, 0, 5, 1, 6, 3, 7, 0, 8, 1, 9, 4, 10, 0, 11, 5, 12, 5, 13, 6, 14, 7, 15, 8, 16, 8, 17, 7, 18, 0, 19, 9, 20, 10, 21, 0, 22, 0, 23, 11, 24, 12, 25, 8, 26, 13, 27, 13, 28, 14, 29, 15, 0, 0, 0, 40, 31, -1, 8, 32, 16, 33, 17, 34, 18, 35, 11, 36, 11, 37, 11, 38, 0, 39, 0, 0, 0, 0, 52, 41, -1, 10, 42, 5, 43, 8, 44, 19, 45, 20, 46, 21, 47, 22, 48, 11, 49, 23, 50, 24, 51, 25, 0, 0, 0, 57, 53, -1, 3, 54, 26, 55, 27, 56, 10, 0, 0, 0, 58, 58, -1, 4, 32, 28, 59, 1, 60, 0, 61, 29, 0, 0, 0, 58, 62, -1, 4, 32, 30, 59, 1, 60, 0, 61, 29, 0, 0, 0, 58, 63, -1, 4, 32, 31, 59, 1, 60, 0, 61, 29, 0, 0, 0, 69, 64, -1, 5, 32, 32, 65, 11, 66, 33, 67, 5, 68, 34, 0, 0, 0, 69, 70, -1, 5, 32, 35, 65, 11, 66, 33, 67, 5, 68, 34, 0, 0, 0, 71, 71, -1, 26, 72, 36, 73, 5, 74, 37, 75, 38, 76, 38, 77, 0, 78, 39, 79, 40, 80, 8, 81, 41, 82, 42, 83, 43, 84, 8, 85, 8, 86, 44, 87, 8, 88, 8, 89, 8, 90, 8, 91, 43, 92, 23, 93, 8, 94, 7, 95, 8, 96, 7, 97, 45, 0, 0, 0, 107, 98, -1, 8, 99, 8, 100, 7, 101, 7, 102, 46, 103, 7, 104, 47, 105, 48, 106, 8, 0 </int_array>
<string> "variants" </string>
- <array len="51" shared="false">
- <bool> True </bool>
- <real> 1 </real>
- <vector2> 0, 0 </vector2>
- <real> 0 </real>
- <vector2> 1, 1 </vector2>
- <int> 3 </int>
+ <array len="49" shared="false">
+ <bool> False </bool>
<resource resource_type="Shape2D" path="local://1"> </resource>
<matrix32> 1, -0, 0, 1, -1.08072, -2.16144 </matrix32>
- <bool> False </bool>
<matrix32> 1, -0, 0, 1, 6.48431, 3.24216 </matrix32>
<matrix32> 1, -0, 0, 1, -12.495, 3.53415 </matrix32>
+ <int> 1 </int>
<int> 2 </int>
+ <real> 1 </real>
+ <real> 0 </real>
+ <int> 0 </int>
<int> 4 </int>
- <resource resource_type="Script" path="res://enemy.*"> </resource>
+ <bool> True </bool>
+ <vector2> 0, 0 </vector2>
+ <real> -1 </real>
+ <resource external="0"> </resource>
<dictionary shared="false">
+ <string> "__editor_plugin_screen__" </string>
+ <string> "2D" </string>
<string> "__editor_plugin_states__" </string>
<dictionary shared="false">
- <string> "Script" </string>
- <dictionary shared="false">
- <string> "current" </string>
- <int> 0 </int>
- <string> "sources" </string>
- <array len="1" shared="false">
- <string> "res://enemy.gd" </string>
- </array>
- </dictionary>
<string> "2D" </string>
<dictionary shared="false">
- <string> "pixel_snap" </string>
+ <string> "ofs" </string>
+ <vector2> -227.625, -197.9 </vector2>
+ <string> "snap_grid" </string>
+ <bool> False </bool>
+ <string> "snap_offset" </string>
+ <vector2> 0, 0 </vector2>
+ <string> "snap_pixel" </string>
+ <bool> False </bool>
+ <string> "snap_relative" </string>
+ <bool> False </bool>
+ <string> "snap_rotation" </string>
<bool> False </bool>
+ <string> "snap_rotation_offset" </string>
+ <real> 0 </real>
+ <string> "snap_rotation_step" </string>
+ <real> 0.261799 </real>
+ <string> "snap_show_grid" </string>
+ <bool> False </bool>
+ <string> "snap_step" </string>
+ <vector2> 10, 10 </vector2>
<string> "zoom" </string>
<real> 1.108033 </real>
- <string> "ofs" </string>
- <vector2> -227.625, -197.9 </vector2>
</dictionary>
<string> "3D" </string>
<dictionary shared="false">
- <string> "zfar" </string>
- <real> 500 </real>
+ <string> "ambient_light_color" </string>
+ <color> 0.15, 0.15, 0.15, 1 </color>
+ <string> "default_light" </string>
+ <bool> True </bool>
+ <string> "default_srgb" </string>
+ <bool> False </bool>
+ <string> "deflight_rot_x" </string>
+ <real> 0.942478 </real>
+ <string> "deflight_rot_y" </string>
+ <real> 0.628319 </real>
<string> "fov" </string>
<real> 45 </real>
+ <string> "show_grid" </string>
+ <bool> True </bool>
+ <string> "show_origin" </string>
+ <bool> True </bool>
+ <string> "viewport_mode" </string>
+ <int> 1 </int>
<string> "viewports" </string>
<array len="4" shared="false">
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> True </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
</array>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
+ <string> "zfar" </string>
+ <real> 500 </real>
<string> "znear" </string>
<real> 0.1 </real>
</dictionary>
+ <string> "Anim" </string>
+ <dictionary shared="false">
+ <string> "visible" </string>
+ <bool> False </bool>
+ </dictionary>
</dictionary>
<string> "__editor_run_settings__" </string>
<dictionary shared="false">
@@ -430,13 +450,10 @@
<string> "run_mode" </string>
<int> 0 </int>
</dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "2D" </string>
</dictionary>
<vector2> 16.2569, 11.0034 </vector2>
<vector2> 23.5056, 10.8629 </vector2>
<rect2> -10, -10, 20, 20 </rect2>
- <int> 1 </int>
<node_path> ".." </node_path>
<resource resource_type="Animation" path="local://2"> </resource>
<resource resource_type="Animation" path="local://3"> </resource>
@@ -445,36 +462,32 @@
<array len="0" shared="false">
</array>
<string> "" </string>
+ <resource external="1"> </resource>
+ <int> 8 </int>
<vector2> -1.08072, -2.16144 </vector2>
+ <int> -1 </int>
<vector2> 6.48431, 3.24216 </vector2>
<vector2> -12.495, 3.53415 </vector2>
- <resource resource_type="Texture" path="res://enemy.*"> </resource>
- <int> 8 </int>
- <color> 1, 1, 1, 1 </color>
- <rect2> 0, 0, 0, 0 </rect2>
<vector2> -33.2868, -9.34363 </vector2>
<vector2> 0, 45 </vector2>
+ <int> 15 </int>
<vector2> 29.1987, -9.34363 </vector2>
<real> 0.121212 </real>
<int> 32 </int>
<real> 0.5 </real>
<real> 0.1 </real>
- <resource resource_type="Texture" path="res://bullet.*"> </resource>
+ <resource external="2"> </resource>
<real> 180 </real>
<real> 90 </real>
<real> 2 </real>
<real> 9.8 </real>
- <color> 1, 0.884956, 0.823009, 1 </color>
- <color> 0.768627, 0.389381, 0, 0 </color>
- <color> 0, 0, 0, 1 </color>
- <vector2_array len="0"> </vector2_array>
+ <resource resource_type="ColorRamp" path="local://6"> </resource>
<real> 2048 </real>
+ <int> 3 </int>
<resource resource_type="SampleLibrary" path="local://5"> </resource>
</array>
- <string> "nodes" </string>
- <int_array len="445"> -1, -1, 1, 0, -1, 31, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 8, 13, 6, 14, 9, 15, 8, 16, 6, 17, 10, 18, 8, 19, 11, 20, 1, 21, 3, 22, 3, 23, 8, 24, 8, 25, 12, 26, 8, 27, 0, 28, 0, 29, 2, 30, 3, 31, 13, 32, 14, 0, 0, 0, 34, 33, -1, 10, 2, 0, 3, 1, 4, 1, 5, 0, 6, 15, 7, 3, 8, 16, 35, 17, 36, 0, 37, 0, 0, 0, 0, 39, 38, -1, 10, 40, 18, 41, 3, 42, 19, 43, 20, 44, 21, 45, 22, 46, 0, 47, 23, 48, 24, 49, 25, 0, 0, 0, 50, 50, -1, 9, 2, 0, 3, 1, 4, 1, 5, 0, 6, 26, 7, 3, 8, 4, 51, 6, 52, 8, 0, 0, 0, 50, 53, -1, 9, 2, 0, 3, 1, 4, 1, 5, 0, 6, 27, 7, 3, 8, 4, 51, 6, 52, 8, 0, 0, 0, 50, 54, -1, 9, 2, 0, 3, 1, 4, 1, 5, 0, 6, 28, 7, 3, 8, 4, 51, 6, 52, 8, 0, 0, 0, 56, 55, -1, 18, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 57, 29, 58, 0, 59, 2, 60, 8, 61, 8, 62, 18, 63, 30, 64, 12, 65, 31, 66, 8, 67, 32, 0, 0, 0, 69, 68, -1, 9, 2, 0, 3, 1, 4, 1, 5, 0, 6, 33, 7, 3, 8, 4, 70, 0, 71, 34, 0, 0, 0, 69, 72, -1, 9, 2, 0, 3, 1, 4, 1, 5, 0, 6, 35, 7, 3, 8, 4, 70, 0, 71, 34, 0, 0, 0, 73, 73, -1, 55, 2, 0, 3, 1, 4, 36, 5, 0, 74, 18, 6, 2, 7, 3, 8, 4, 75, 37, 76, 38, 77, 1, 78, 3, 79, 38, 80, 8, 81, 2, 82, 2, 83, 0, 84, 39, 85, 40, 86, 3, 87, 41, 88, 42, 89, 43, 90, 3, 91, 3, 92, 44, 93, 3, 94, 3, 95, 3, 96, 43, 97, 23, 98, 3, 99, 3, 100, 3, 101, 3, 102, 1, 103, 3, 104, 3, 105, 3, 106, 3, 107, 3, 108, 3, 109, 3, 110, 3, 111, 3, 112, 11, 113, 3, 114, 45, 115, 1, 116, 46, 117, 1, 118, 47, 119, 1, 120, 47, 121, 48, 0, 0, 0, 123, 122, -1, 15, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 124, 3, 125, 1, 126, 1, 127, 49, 128, 1, 129, 5, 130, 50, 131, 3, 0 </int_array>
- <string> "conns" </string>
- <int_array len="0"> </int_array>
+ <string> "version" </string>
+ <int> 2 </int>
</dictionary>
</main_resource>
diff --git a/demos/2d/platformer/engine.cfg b/demos/2d/platformer/engine.cfg
index 50b6b862e9..044d661e3e 100644
--- a/demos/2d/platformer/engine.cfg
+++ b/demos/2d/platformer/engine.cfg
@@ -4,14 +4,14 @@ name="Platformer"
main_scene="res://stage.xml"
icon="res://icon.png"
name_es="Plataformero"
+target_fps="60"
[display]
width=800
height=480
-stretch_2d=false
-stretch_mode="viewport"
-stretch_aspect="keep"
+stretch_mode="2d"
+stretch_aspect="keep_height"
[image_loader]
diff --git a/demos/2d/platformer/moving_platform.gd b/demos/2d/platformer/moving_platform.gd
index 719d9e460e..21c312d5c3 100644
--- a/demos/2d/platformer/moving_platform.gd
+++ b/demos/2d/platformer/moving_platform.gd
@@ -1,27 +1,20 @@
extends Node2D
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
+# Member variables
export var motion = Vector2()
export var cycle = 1.0
-var accum=0.0
+var accum = 0.0
-func _fixed_process(delta):
- accum += delta * (1.0/cycle) * PI * 2.0
- accum = fmod(accum,PI*2.0)
+func _fixed_process(delta):
+ accum += delta*(1.0/cycle)*PI*2.0
+ accum = fmod(accum, PI*2.0)
var d = sin(accum)
var xf = Matrix32()
- xf[2]= motion * d
+ xf[2]= motion*d
get_node("platform").set_transform(xf)
-
+
func _ready():
- # Initalization here
set_fixed_process(true)
- pass
-
-
diff --git a/demos/2d/platformer/moving_platform.xml b/demos/2d/platformer/moving_platform.xml
index 4d54d6d11c..4b94a7af48 100644
--- a/demos/2d/platformer/moving_platform.xml
+++ b/demos/2d/platformer/moving_platform.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="4" version="1.0" version_name="Godot Engine v1.0.3917-beta1">
- <ext_resource path="res://moving_platform.*" type="Texture"></ext_resource>
- <ext_resource path="res://moving_platform.*" type="Script"></ext_resource>
+<resource_file type="PackedScene" subresource_count="4" version="2.0" version_name="Godot Engine v2.0.alpha.custom_build">
+ <ext_resource path="res://moving_platform.png" type="Texture" index="1"></ext_resource>
+ <ext_resource path="res://moving_platform.gd" type="Script" index="0"></ext_resource>
<resource type="ConvexPolygonShape2D" path="local://1">
<real name="custom_solver_bias"> 0 </real>
<vector2_array name="points" len="4"> -88, 24, -88, -24, 88, -24, 88, 24 </vector2_array>
@@ -9,169 +9,189 @@
</resource>
<main_resource>
<dictionary name="_bundled" shared="false">
+ <string> "conn_count" </string>
+ <int> 0 </int>
+ <string> "conns" </string>
+ <int_array len="0"> </int_array>
+ <string> "editable_instances" </string>
+ <array len="0" shared="false">
+ </array>
<string> "names" </string>
- <string_array len="46">
+ <string_array len="36">
<string> "moving_platform" </string>
- <string> "Node2D" </string>
- <string> "visibility/visible" </string>
- <string> "visibility/opacity" </string>
- <string> "visibility/self_opacity" </string>
- <string> "visibility/on_top" </string>
- <string> "transform/pos" </string>
- <string> "transform/rot" </string>
- <string> "transform/scale" </string>
<string> "script/script" </string>
<string> "__meta__" </string>
<string> "motion" </string>
<string> "cycle" </string>
+ <string> "Node2D" </string>
<string> "platform" </string>
- <string> "RigidBody2D" </string>
- <string> "shape_count" </string>
+ <string> "input/pickable" </string>
<string> "shapes/0/shape" </string>
<string> "shapes/0/transform" </string>
<string> "shapes/0/trigger" </string>
+ <string> "collision/layers" </string>
+ <string> "collision/mask" </string>
<string> "mode" </string>
<string> "mass" </string>
<string> "friction" </string>
<string> "bounce" </string>
+ <string> "gravity_scale" </string>
<string> "custom_integrator" </string>
<string> "continuous_cd" </string>
<string> "contacts_reported" </string>
<string> "contact_monitor" </string>
- <string> "active" </string>
+ <string> "sleeping" </string>
<string> "can_sleep" </string>
<string> "velocity/linear" </string>
<string> "velocity/angular" </string>
+ <string> "damp_override/linear" </string>
+ <string> "damp_override/angular" </string>
+ <string> "RigidBody2D" </string>
<string> "Sprite" </string>
<string> "texture" </string>
- <string> "centered" </string>
- <string> "offset" </string>
- <string> "flip_h" </string>
- <string> "flip_v" </string>
- <string> "vframes" </string>
- <string> "hframes" </string>
- <string> "frame" </string>
- <string> "modulate" </string>
- <string> "region" </string>
- <string> "region_rect" </string>
<string> "CollisionPolygon2D" </string>
<string> "build_mode" </string>
<string> "polygon" </string>
+ <string> "shape_range" </string>
+ <string> "trigger" </string>
</string_array>
- <string> "version" </string>
- <int> 1 </int>
- <string> "conn_count" </string>
- <int> 0 </int>
<string> "node_count" </string>
<int> 4 </int>
+ <string> "node_paths" </string>
+ <array len="0" shared="false">
+ </array>
+ <string> "nodes" </string>
+ <int_array len="88"> -1, -1, 5, 0, -1, 4, 1, 0, 2, 1, 3, 2, 4, 3, 0, 0, 0, 28, 6, -1, 21, 7, 4, 8, 5, 9, 6, 10, 4, 11, 7, 12, 7, 13, 8, 14, 3, 15, 3, 16, 9, 17, 3, 18, 4, 19, 10, 20, 10, 21, 4, 22, 4, 23, 11, 24, 2, 25, 9, 26, 12, 27, 12, 0, 1, 0, 29, 29, -1, 1, 30, 13, 0, 1, 0, 31, 31, -1, 4, 32, 10, 33, 14, 34, 15, 35, 4, 0 </int_array>
<string> "variants" </string>
- <array len="17" shared="false">
- <bool> True </bool>
- <real> 1 </real>
- <vector2> 0, 0 </vector2>
- <real> 0 </real>
- <vector2> 1, 1 </vector2>
- <resource resource_type="Script" path="res://moving_platform.*"> </resource>
+ <array len="16" shared="false">
+ <resource external="0"> </resource>
<dictionary shared="false">
+ <string> "__editor_plugin_screen__" </string>
+ <string> "2D" </string>
<string> "__editor_plugin_states__" </string>
<dictionary shared="false">
- <string> "Script" </string>
- <dictionary shared="false">
- <string> "current" </string>
- <int> 0 </int>
- <string> "sources" </string>
- <array len="4" shared="false">
- <string> "res://moving_platform.gd" </string>
- <string> "res://enemy.gd" </string>
- <string> "res://player.gd" </string>
- <string> "res://coin.gd" </string>
- </array>
- </dictionary>
<string> "2D" </string>
<dictionary shared="false">
- <string> "pixel_snap" </string>
+ <string> "ofs" </string>
+ <vector2> -210.652, -172.81 </vector2>
+ <string> "snap_grid" </string>
+ <bool> False </bool>
+ <string> "snap_offset" </string>
+ <vector2> 0, 0 </vector2>
+ <string> "snap_pixel" </string>
+ <bool> False </bool>
+ <string> "snap_relative" </string>
<bool> False </bool>
+ <string> "snap_rotation" </string>
+ <bool> False </bool>
+ <string> "snap_rotation_offset" </string>
+ <real> 0 </real>
+ <string> "snap_rotation_step" </string>
+ <real> 0.261799 </real>
+ <string> "snap_show_grid" </string>
+ <bool> False </bool>
+ <string> "snap_step" </string>
+ <vector2> 10, 10 </vector2>
<string> "zoom" </string>
<real> 1.360373 </real>
- <string> "ofs" </string>
- <vector2> -210.652, -172.81 </vector2>
</dictionary>
<string> "3D" </string>
<dictionary shared="false">
- <string> "zfar" </string>
- <real> 500 </real>
+ <string> "ambient_light_color" </string>
+ <color> 0.15, 0.15, 0.15, 1 </color>
+ <string> "default_light" </string>
+ <bool> True </bool>
+ <string> "default_srgb" </string>
+ <bool> False </bool>
+ <string> "deflight_rot_x" </string>
+ <real> 0.942478 </real>
+ <string> "deflight_rot_y" </string>
+ <real> 0.628319 </real>
<string> "fov" </string>
- <real> 400 </real>
+ <real> 179 </real>
+ <string> "show_grid" </string>
+ <bool> True </bool>
+ <string> "show_origin" </string>
+ <bool> True </bool>
+ <string> "viewport_mode" </string>
+ <int> 1 </int>
<string> "viewports" </string>
<array len="4" shared="false">
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> True </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
</array>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
+ <string> "zfar" </string>
+ <real> 500 </real>
<string> "znear" </string>
<real> 0.1 </real>
</dictionary>
+ <string> "Anim" </string>
+ <dictionary shared="false">
+ <string> "visible" </string>
+ <bool> False </bool>
+ </dictionary>
</dictionary>
<string> "__editor_run_settings__" </string>
<dictionary shared="false">
@@ -180,24 +200,24 @@
<string> "run_mode" </string>
<int> 0 </int>
</dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "2D" </string>
</dictionary>
- <int> 1 </int>
+ <vector2> 0, 0 </vector2>
+ <real> 1 </real>
+ <bool> False </bool>
<resource resource_type="Shape2D" path="local://1"> </resource>
<matrix32> 1, -0, 0, 1, 0, 0 </matrix32>
- <bool> False </bool>
+ <int> 1 </int>
<int> 3 </int>
+ <real> 0 </real>
<int> 0 </int>
- <resource resource_type="Texture" path="res://moving_platform.*"> </resource>
- <color> 1, 1, 1, 1 </color>
- <rect2> 0, 0, 0, 0 </rect2>
+ <bool> True </bool>
+ <real> -1 </real>
+ <resource external="1"> </resource>
<vector2_array len="4"> -88, -24, 88, -24, 88, 24, -88, 24 </vector2_array>
+ <vector2> -1, -1 </vector2>
</array>
- <string> "nodes" </string>
- <int_array len="150"> -1, -1, 1, 0, -1, 11, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 11, 2, 12, 1, 0, 0, 0, 14, 13, -1, 23, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 15, 7, 16, 8, 17, 9, 18, 10, 19, 11, 20, 1, 21, 1, 22, 3, 23, 10, 24, 10, 25, 12, 26, 10, 27, 0, 28, 0, 29, 2, 30, 3, 0, 1, 0, 31, 31, -1, 18, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 32, 13, 33, 0, 34, 2, 35, 10, 36, 10, 37, 7, 38, 7, 39, 12, 40, 14, 41, 10, 42, 15, 0, 1, 0, 43, 43, -1, 9, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 44, 12, 45, 16, 0 </int_array>
- <string> "conns" </string>
- <int_array len="0"> </int_array>
+ <string> "version" </string>
+ <int> 2 </int>
</dictionary>
</main_resource>
diff --git a/demos/2d/platformer/one_way_platform.xml b/demos/2d/platformer/one_way_platform.xml
index 491dd32b17..85b2322711 100644
--- a/demos/2d/platformer/one_way_platform.xml
+++ b/demos/2d/platformer/one_way_platform.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="3" version="1.1" version_name="Godot Engine v1.1.rc1.custom_build">
- <ext_resource path="res://one_way_platform.png" type="Texture"></ext_resource>
+<resource_file type="PackedScene" subresource_count="3" version="2.0" version_name="Godot Engine v2.0.alpha.custom_build">
+ <ext_resource path="res://one_way_platform.png" type="Texture" index="0"></ext_resource>
<resource type="RectangleShape2D" path="local://1">
<real name="custom_solver_bias"> 0 </real>
<vector2 name="extents"> 100, 10 </vector2>
@@ -12,22 +12,13 @@
<int> 0 </int>
<string> "conns" </string>
<int_array len="0"> </int_array>
+ <string> "editable_instances" </string>
+ <array len="0" shared="false">
+ </array>
<string> "names" </string>
- <string_array len="42">
+ <string_array len="23">
<string> "one_way_platform" </string>
- <string> "StaticBody2D" </string>
- <string> "_import_path" </string>
- <string> "visibility/visible" </string>
- <string> "visibility/opacity" </string>
- <string> "visibility/self_opacity" </string>
- <string> "visibility/light_mask" </string>
- <string> "transform/pos" </string>
- <string> "transform/rot" </string>
- <string> "transform/scale" </string>
- <string> "z/z" </string>
- <string> "z/relative" </string>
<string> "input/pickable" </string>
- <string> "shape_count" </string>
<string> "shapes/0/shape" </string>
<string> "shapes/0/transform" </string>
<string> "shapes/0/trigger" </string>
@@ -40,42 +31,34 @@
<string> "friction" </string>
<string> "bounce" </string>
<string> "__meta__" </string>
+ <string> "StaticBody2D" </string>
<string> "sprite" </string>
- <string> "Sprite" </string>
<string> "texture" </string>
- <string> "centered" </string>
- <string> "offset" </string>
- <string> "flip_h" </string>
- <string> "flip_v" </string>
- <string> "vframes" </string>
- <string> "hframes" </string>
- <string> "frame" </string>
- <string> "modulate" </string>
- <string> "region" </string>
- <string> "region_rect" </string>
+ <string> "Sprite" </string>
<string> "CollisionShape2D" </string>
+ <string> "transform/pos" </string>
<string> "shape" </string>
<string> "trigger" </string>
+ <string> "_update_shape_index" </string>
</string_array>
<string> "node_count" </string>
<int> 3 </int>
+ <string> "node_paths" </string>
+ <array len="0" shared="false">
+ </array>
<string> "nodes" </string>
- <int_array len="135"> -1, -1, 1, 0, -1, 24, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 10, 7, 11, 1, 12, 8, 13, 3, 14, 9, 15, 10, 16, 8, 17, 3, 18, 3, 19, 11, 20, 12, 21, 4, 22, 5, 23, 2, 24, 5, 25, 13, 0, 0, 0, 27, 26, -1, 21, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 10, 7, 11, 1, 28, 14, 29, 1, 30, 4, 31, 8, 32, 8, 33, 3, 34, 3, 35, 7, 36, 15, 37, 8, 38, 16, 0, 0, 0, 39, 39, -1, 12, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 17, 8, 5, 9, 6, 10, 7, 11, 1, 40, 9, 41, 8, 0 </int_array>
+ <int_array len="57"> -1, -1, 14, 0, -1, 13, 1, 0, 2, 1, 3, 2, 4, 0, 5, 3, 6, 3, 7, 4, 8, 5, 9, 6, 10, 7, 11, 8, 12, 7, 13, 9, 0, 0, 0, 17, 15, -1, 1, 16, 10, 0, 0, 0, 18, 18, -1, 4, 19, 11, 20, 1, 21, 0, 22, 12, 0 </int_array>
<string> "variants" </string>
- <array len="18" shared="false">
- <node_path> "" </node_path>
- <bool> True </bool>
- <real> 1 </real>
- <int> 1 </int>
- <vector2> 0, 0 </vector2>
- <real> 0 </real>
- <vector2> 1, 1 </vector2>
- <int> 0 </int>
+ <array len="13" shared="false">
<bool> False </bool>
<resource resource_type="Shape2D" path="local://1"> </resource>
<matrix32> 1, -0, 0, 1, 1.46304, -13.1672 </matrix32>
+ <int> 1 </int>
<vector2> 0, 1 </vector2>
<real> 20 </real>
+ <vector2> 0, 0 </vector2>
+ <real> 0 </real>
+ <real> 1 </real>
<dictionary shared="false">
<string> "__editor_plugin_screen__" </string>
<string> "2D" </string>
@@ -198,6 +181,11 @@
<string> "znear" </string>
<real> 0.1 </real>
</dictionary>
+ <string> "Anim" </string>
+ <dictionary shared="false">
+ <string> "visible" </string>
+ <bool> False </bool>
+ </dictionary>
</dictionary>
<string> "__editor_run_settings__" </string>
<dictionary shared="false">
@@ -207,13 +195,12 @@
<int> 0 </int>
</dictionary>
</dictionary>
- <resource resource_type="Texture" path="res://one_way_platform.png"> </resource>
- <color> 1, 1, 1, 1 </color>
- <rect2> 0, 0, 0, 0 </rect2>
+ <resource external="0"> </resource>
<vector2> 1.46304, -13.1672 </vector2>
+ <int> -1 </int>
</array>
<string> "version" </string>
- <int> 1 </int>
+ <int> 2 </int>
</dictionary>
</main_resource>
diff --git a/demos/2d/platformer/parallax_bg.xml b/demos/2d/platformer/parallax_bg.xml
index cc8cfe5de0..3b306aecab 100644
--- a/demos/2d/platformer/parallax_bg.xml
+++ b/demos/2d/platformer/parallax_bg.xml
@@ -1,23 +1,23 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="7" version="0.99" version_name="Godot Engine v0.99.3046-pre-beta">
- <ext_resource path="res://scroll_bg_sky.png" type="Texture"></ext_resource>
- <ext_resource path="res://scroll_bg_cloud_1.png" type="Texture"></ext_resource>
- <ext_resource path="res://scroll_bg_cloud_3.png" type="Texture"></ext_resource>
- <ext_resource path="res://scroll_bg_cloud_2.png" type="Texture"></ext_resource>
- <ext_resource path="res://scroll_bg_fg_1.png" type="Texture"></ext_resource>
- <ext_resource path="res://scroll_bg_fg_2.png" type="Texture"></ext_resource>
+<resource_file type="PackedScene" subresource_count="7" version="2.0" version_name="Godot Engine v2.0.alpha.custom_build">
+ <ext_resource path="res://scroll_bg_cloud_1.png" type="Texture" index="1"></ext_resource>
+ <ext_resource path="res://scroll_bg_sky.png" type="Texture" index="0"></ext_resource>
+ <ext_resource path="res://scroll_bg_fg_2.png" type="Texture" index="4"></ext_resource>
+ <ext_resource path="res://scroll_bg_cloud_3.png" type="Texture" index="3"></ext_resource>
+ <ext_resource path="res://scroll_bg_cloud_2.png" type="Texture" index="2"></ext_resource>
+ <ext_resource path="res://scroll_bg_fg_1.png" type="Texture" index="5"></ext_resource>
<main_resource>
- <string name="resource/name"> "" </string>
- <dictionary name="_bundled">
+ <dictionary name="_bundled" shared="false">
+ <string> "conn_count" </string>
+ <int> 0 </int>
+ <string> "conns" </string>
+ <int_array len="0"> </int_array>
+ <string> "editable_instances" </string>
+ <array len="0" shared="false">
+ </array>
<string> "names" </string>
- <string_array len="51">
+ <string_array len="32">
<string> "parallax_bg" </string>
- <string> "ParallaxBackground" </string>
- <string> "process/process" </string>
- <string> "process/fixed_process" </string>
- <string> "process/input" </string>
- <string> "process/unhandled_input" </string>
- <string> "process/mode" </string>
<string> "layer" </string>
<string> "offset" </string>
<string> "rotation" </string>
@@ -27,148 +27,204 @@
<string> "scroll/base_scale" </string>
<string> "scroll/limit_begin" </string>
<string> "scroll/limit_end" </string>
- <string> "script/script" </string>
+ <string> "scroll/ignore_camera_zoom" </string>
<string> "__meta__" </string>
+ <string> "ParallaxBackground" </string>
<string> "sky" </string>
- <string> "ParallaxLayer" </string>
- <string> "visibility/visible" </string>
- <string> "visibility/toplevel" </string>
- <string> "visibility/opacity" </string>
- <string> "visibility/self_opacity" </string>
- <string> "visibility/on_top" </string>
- <string> "visibility/blend_mode" </string>
- <string> "transform/notify" </string>
- <string> "transform/pos" </string>
- <string> "transform/rot" </string>
- <string> "transform/scale" </string>
<string> "motion/scale" </string>
<string> "motion/mirroring" </string>
+ <string> "ParallaxLayer" </string>
<string> "Sprite" </string>
+ <string> "transform/scale" </string>
<string> "texture" </string>
<string> "centered" </string>
- <string> "flip_h" </string>
- <string> "flip_v" </string>
- <string> "vframes" </string>
- <string> "hframes" </string>
- <string> "frame" </string>
- <string> "modulate" </string>
- <string> "region" </string>
- <string> "region_rect" </string>
<string> "clouds" </string>
+ <string> "transform/pos" </string>
<string> "Sprite 2" </string>
<string> "Sprite 3" </string>
<string> "Sprite 4" </string>
<string> "Sprite 5" </string>
<string> "Sprite 6" </string>
<string> "mount_ 2" </string>
+ <string> "region" </string>
+ <string> "region_rect" </string>
<string> "mount_1" </string>
</string_array>
- <string> "version" </string>
- <int> 1 </int>
- <string> "conn_count" </string>
- <int> 0 </int>
<string> "node_count" </string>
<int> 14 </int>
+ <string> "node_paths" </string>
+ <array len="0" shared="false">
+ </array>
+ <string> "nodes" </string>
+ <int_array len="198"> -1, -1, 12, 0, -1, 11, 1, 0, 2, 1, 3, 2, 4, 3, 5, 1, 6, 1, 7, 4, 8, 1, 9, 1, 10, 5, 11, 6, 0, 0, 0, 16, 13, -1, 2, 14, 3, 15, 7, 0, 1, 0, 17, 17, -1, 3, 18, 8, 19, 9, 20, 5, 0, 0, 0, 16, 21, -1, 2, 14, 10, 15, 7, 0, 3, 0, 17, 17, -1, 3, 22, 11, 19, 12, 20, 5, 0, 3, 0, 17, 23, -1, 3, 22, 13, 19, 12, 20, 5, 0, 3, 0, 17, 24, -1, 3, 22, 14, 19, 15, 20, 5, 0, 3, 0, 17, 25, -1, 3, 22, 16, 19, 15, 20, 5, 0, 3, 0, 17, 26, -1, 3, 22, 17, 19, 18, 20, 5, 0, 3, 0, 17, 27, -1, 3, 22, 19, 19, 18, 20, 5, 0, 0, 0, 16, 28, -1, 2, 14, 20, 15, 7, 0, 10, 0, 17, 17, -1, 5, 22, 21, 19, 22, 20, 5, 29, 23, 30, 24, 0, 0, 0, 16, 31, -1, 2, 14, 25, 15, 7, 0, 12, 0, 17, 17, -1, 5, 22, 21, 19, 26, 20, 5, 29, 23, 30, 24, 0 </int_array>
<string> "variants" </string>
- <array len="33">
- <bool> False </bool>
- <int> 0 </int>
+ <array len="27" shared="false">
<int> -1 </int>
<vector2> 0, 0 </vector2>
<real> 0 </real>
<vector2> 1, 1 </vector2>
<vector2> 0.7, 0 </vector2>
- <resource name=""></resource> <dictionary>
+ <bool> False </bool>
+ <dictionary shared="false">
+ <string> "__editor_plugin_screen__" </string>
+ <string> "2D" </string>
<string> "__editor_plugin_states__" </string>
- <dictionary>
- <string> "Script" </string>
- <dictionary>
- <string> "current" </string>
- <int> 0 </int>
- <string> "sources" </string>
- <array len="4">
- <string> "res://moving_platform.gd" </string>
- <string> "res://enemy.gd" </string>
- <string> "res://player.gd" </string>
- <string> "res://coin.gd" </string>
- </array>
- </dictionary>
+ <dictionary shared="false">
<string> "2D" </string>
- <dictionary>
- <string> "zoom" </string>
- <real> 1 </real>
+ <dictionary shared="false">
<string> "ofs" </string>
<vector2> -5, -25 </vector2>
+ <string> "snap_grid" </string>
+ <bool> False </bool>
+ <string> "snap_offset" </string>
+ <vector2> 0, 0 </vector2>
+ <string> "snap_pixel" </string>
+ <bool> False </bool>
+ <string> "snap_relative" </string>
+ <bool> False </bool>
+ <string> "snap_rotation" </string>
+ <bool> False </bool>
+ <string> "snap_rotation_offset" </string>
+ <real> 0 </real>
+ <string> "snap_rotation_step" </string>
+ <real> 0.261799 </real>
+ <string> "snap_show_grid" </string>
+ <bool> False </bool>
+ <string> "snap_step" </string>
+ <vector2> 10, 10 </vector2>
+ <string> "zoom" </string>
+ <real> 1 </real>
</dictionary>
<string> "3D" </string>
- <dictionary>
- <string> "zfar" </string>
- <real> 500 </real>
+ <dictionary shared="false">
+ <string> "ambient_light_color" </string>
+ <color> 0.15, 0.15, 0.15, 1 </color>
+ <string> "default_light" </string>
+ <bool> True </bool>
+ <string> "default_srgb" </string>
+ <bool> False </bool>
+ <string> "deflight_rot_x" </string>
+ <real> 0.942478 </real>
+ <string> "deflight_rot_y" </string>
+ <real> 0.628319 </real>
<string> "fov" </string>
<real> 45 </real>
- <string> "window_mode" </string>
- <int> 0 </int>
- <string> "window_0" </string>
- <dictionary>
- <string> "distance" </string>
- <real> 4 </real>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "x_rot" </string>
- <real> 0.337 </real>
- <string> "y_rot" </string>
- <real> -0.575 </real>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
+ <string> "show_grid" </string>
+ <bool> True </bool>
+ <string> "show_origin" </string>
+ <bool> True </bool>
+ <string> "viewport_mode" </string>
+ <int> 1 </int>
+ <string> "viewports" </string>
+ <array len="4" shared="false">
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
+ <string> "listener" </string>
+ <bool> True </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
+ <string> "x_rot" </string>
+ <real> 0 </real>
+ <string> "y_rot" </string>
+ <real> 0 </real>
+ </dictionary>
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
+ <string> "x_rot" </string>
+ <real> 0 </real>
+ <string> "y_rot" </string>
+ <real> 0 </real>
+ </dictionary>
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
+ <string> "x_rot" </string>
+ <real> 0 </real>
+ <string> "y_rot" </string>
+ <real> 0 </real>
+ </dictionary>
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
+ <string> "x_rot" </string>
+ <real> 0 </real>
+ <string> "y_rot" </string>
+ <real> 0 </real>
+ </dictionary>
+ </array>
+ <string> "zfar" </string>
+ <real> 500 </real>
<string> "znear" </string>
<real> 0.1 </real>
</dictionary>
+ <string> "Anim" </string>
+ <dictionary shared="false">
+ <string> "visible" </string>
+ <bool> False </bool>
+ </dictionary>
</dictionary>
<string> "__editor_run_settings__" </string>
- <dictionary>
+ <dictionary shared="false">
<string> "custom_args" </string>
<string> "-l $scene" </string>
<string> "run_mode" </string>
<int> 0 </int>
</dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "2D" </string>
</dictionary>
- <bool> True </bool>
- <real> 1 </real>
<vector2> 800, 0 </vector2>
<vector2> 32, 0.94 </vector2>
- <resource resource_type="Texture" path="res://scroll_bg_sky.png"> </resource>
- <int> 1 </int>
- <color> 1, 1, 1, 1 </color>
- <rect2> 0, 0, 0, 0 </rect2>
+ <resource external="0"> </resource>
<vector2> 0.1, 1 </vector2>
<vector2> 28, 127 </vector2>
- <resource resource_type="Texture" path="res://scroll_bg_cloud_1.png"> </resource>
+ <resource external="1"> </resource>
<vector2> 404, 24 </vector2>
<vector2> 154, 46 </vector2>
- <resource resource_type="Texture" path="res://scroll_bg_cloud_2.png"> </resource>
+ <resource external="2"> </resource>
<vector2> 525, 130 </vector2>
<vector2> 255, 158 </vector2>
- <resource resource_type="Texture" path="res://scroll_bg_cloud_3.png"> </resource>
+ <resource external="3"> </resource>
<vector2> 674, 70 </vector2>
<vector2> 0.2, 1 </vector2>
<vector2> 0, 225 </vector2>
- <resource resource_type="Texture" path="res://scroll_bg_fg_2.png"> </resource>
+ <resource external="4"> </resource>
+ <bool> True </bool>
<rect2> 0, 0, 800, 256 </rect2>
<vector2> 0.4, 1 </vector2>
- <resource resource_type="Texture" path="res://scroll_bg_fg_1.png"> </resource>
+ <resource external="5"> </resource>
</array>
- <string> "nodes" </string>
- <int_array len="760"> -1, -1, 1, 0, -1, 16, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 7, 2, 8, 3, 9, 4, 10, 5, 11, 3, 12, 3, 13, 6, 14, 3, 15, 3, 16, 7, 17, 8, 0, 0, 0, 19, 18, -1, 18, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 20, 9, 21, 0, 22, 10, 23, 10, 24, 9, 25, 1, 26, 0, 27, 3, 28, 4, 29, 5, 30, 5, 31, 11, 16, 7, 0, 1, 0, 32, 32, -1, 27, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 20, 9, 21, 0, 22, 10, 23, 10, 24, 9, 25, 1, 26, 0, 27, 3, 28, 4, 29, 12, 33, 13, 34, 0, 8, 3, 35, 0, 36, 0, 37, 14, 38, 14, 39, 1, 40, 15, 41, 0, 42, 16, 16, 7, 0, 0, 0, 19, 43, -1, 18, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 20, 9, 21, 0, 22, 10, 23, 10, 24, 9, 25, 1, 26, 0, 27, 3, 28, 4, 29, 5, 30, 17, 31, 11, 16, 7, 0, 3, 0, 32, 32, -1, 27, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 20, 9, 21, 0, 22, 10, 23, 10, 24, 9, 25, 1, 26, 0, 27, 18, 28, 4, 29, 5, 33, 19, 34, 0, 8, 3, 35, 0, 36, 0, 37, 14, 38, 14, 39, 1, 40, 15, 41, 0, 42, 16, 16, 7, 0, 3, 0, 32, 44, -1, 27, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 20, 9, 21, 0, 22, 10, 23, 10, 24, 9, 25, 1, 26, 0, 27, 20, 28, 4, 29, 5, 33, 19, 34, 0, 8, 3, 35, 0, 36, 0, 37, 14, 38, 14, 39, 1, 40, 15, 41, 0, 42, 16, 16, 7, 0, 3, 0, 32, 45, -1, 27, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 20, 9, 21, 0, 22, 10, 23, 10, 24, 9, 25, 1, 26, 0, 27, 21, 28, 4, 29, 5, 33, 22, 34, 0, 8, 3, 35, 0, 36, 0, 37, 14, 38, 14, 39, 1, 40, 15, 41, 0, 42, 16, 16, 7, 0, 3, 0, 32, 46, -1, 27, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 20, 9, 21, 0, 22, 10, 23, 10, 24, 9, 25, 1, 26, 0, 27, 23, 28, 4, 29, 5, 33, 22, 34, 0, 8, 3, 35, 0, 36, 0, 37, 14, 38, 14, 39, 1, 40, 15, 41, 0, 42, 16, 16, 7, 0, 3, 0, 32, 47, -1, 27, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 20, 9, 21, 0, 22, 10, 23, 10, 24, 9, 25, 1, 26, 0, 27, 24, 28, 4, 29, 5, 33, 25, 34, 0, 8, 3, 35, 0, 36, 0, 37, 14, 38, 14, 39, 1, 40, 15, 41, 0, 42, 16, 16, 7, 0, 3, 0, 32, 48, -1, 27, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 20, 9, 21, 0, 22, 10, 23, 10, 24, 9, 25, 1, 26, 0, 27, 26, 28, 4, 29, 5, 33, 25, 34, 0, 8, 3, 35, 0, 36, 0, 37, 14, 38, 14, 39, 1, 40, 15, 41, 0, 42, 16, 16, 7, 0, 0, 0, 19, 49, -1, 18, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 20, 9, 21, 0, 22, 10, 23, 10, 24, 9, 25, 1, 26, 0, 27, 3, 28, 4, 29, 5, 30, 27, 31, 11, 16, 7, 0, 10, 0, 32, 32, -1, 27, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 20, 9, 21, 0, 22, 10, 23, 10, 24, 9, 25, 1, 26, 0, 27, 28, 28, 4, 29, 5, 33, 29, 34, 0, 8, 3, 35, 0, 36, 0, 37, 14, 38, 14, 39, 1, 40, 15, 41, 9, 42, 30, 16, 7, 0, 0, 0, 19, 50, -1, 18, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 20, 9, 21, 0, 22, 10, 23, 10, 24, 9, 25, 1, 26, 0, 27, 3, 28, 4, 29, 5, 30, 31, 31, 11, 16, 7, 0, 12, 0, 32, 32, -1, 27, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 20, 9, 21, 0, 22, 10, 23, 10, 24, 9, 25, 1, 26, 0, 27, 28, 28, 4, 29, 5, 33, 32, 34, 0, 8, 3, 35, 0, 36, 0, 37, 14, 38, 14, 39, 1, 40, 15, 41, 9, 42, 30, 16, 7, 0 </int_array>
- <string> "conns" </string>
- <int_array len="0"> </int_array>
+ <string> "version" </string>
+ <int> 2 </int>
</dictionary>
- <resource name="script/script"></resource>
+
</main_resource>
</resource_file> \ No newline at end of file
diff --git a/demos/2d/platformer/player.gd b/demos/2d/platformer/player.gd
index 9ee189df21..7ed99df9bd 100644
--- a/demos/2d/platformer/player.gd
+++ b/demos/2d/platformer/player.gd
@@ -1,3 +1,4 @@
+
extends RigidBody2D
# Character Demo, written by Juan Linietsky.
@@ -24,42 +25,40 @@ extends RigidBody2D
# -Friction cant be used, so floor velocity must be considered
# for moving platforms.
-var anim=""
-var siding_left=false
-var jumping=false
-var stopping_jump=false
-var shooting=false
+# Member variables
+var anim = ""
+var siding_left = false
+var jumping = false
+var stopping_jump = false
+var shooting = false
var WALK_ACCEL = 800.0
-var WALK_DEACCEL= 800.0
-var WALK_MAX_VELOCITY= 200.0
+var WALK_DEACCEL = 800.0
+var WALK_MAX_VELOCITY = 200.0
var AIR_ACCEL = 200.0
-var AIR_DEACCEL= 200.0
-var JUMP_VELOCITY=460
-var STOP_JUMP_FORCE=900.0
+var AIR_DEACCEL = 200.0
+var JUMP_VELOCITY = 460
+var STOP_JUMP_FORCE = 900.0
var MAX_FLOOR_AIRBORNE_TIME = 0.15
-var airborne_time=1e20
-var shoot_time=1e20
+var airborne_time = 1e20
+var shoot_time = 1e20
var MAX_SHOOT_POSE_TIME = 0.3
var bullet = preload("res://bullet.xml")
-var floor_h_velocity=0.0
+var floor_h_velocity = 0.0
var enemy
-func _integrate_forces(s):
-
-
+func _integrate_forces(s):
var lv = s.get_linear_velocity()
var step = s.get_step()
- var new_anim=anim
- var new_siding_left=siding_left
-
+ var new_anim = anim
+ var new_siding_left = siding_left
# Get the controls
var move_left = Input.is_action_pressed("move_left")
@@ -74,188 +73,160 @@ func _integrate_forces(s):
p.y = p.y - 100
e.set_pos(p)
get_parent().add_child(e)
-
-
- #deapply prev floor velocity
- lv.x-=floor_h_velocity
- floor_h_velocity=0.0
+ # Deapply prev floor velocity
+ lv.x -= floor_h_velocity
+ floor_h_velocity = 0.0
# Find the floor (a contact with upwards facing collision normal)
- var found_floor=false
- var floor_index=-1
+ var found_floor = false
+ var floor_index = -1
for x in range(s.get_contact_count()):
-
var ci = s.get_contact_local_normal(x)
- if (ci.dot(Vector2(0,-1))>0.6):
- found_floor=true
- floor_index=x
+ if (ci.dot(Vector2(0, -1)) > 0.6):
+ found_floor = true
+ floor_index = x
# A good idea when impementing characters of all kinds,
- # Compensates for physics imprecission, as well as human
- # reaction delay.
-
+ # compensates for physics imprecission, as well as human reaction delay.
if (shoot and not shooting):
- shoot_time=0
+ shoot_time = 0
var bi = bullet.instance()
var ss
if (siding_left):
- ss=-1.0
+ ss = -1.0
else:
- ss=1.0
- var pos = get_pos() + get_node("bullet_shoot").get_pos()*Vector2(ss,1.0)
-
+ ss = 1.0
+ var pos = get_pos() + get_node("bullet_shoot").get_pos()*Vector2(ss, 1.0)
+
bi.set_pos(pos)
get_parent().add_child(bi)
-
- bi.set_linear_velocity( Vector2(800.0*ss,-80) )
- get_node("sprite/smoke").set_emitting(true)
+
+ bi.set_linear_velocity(Vector2(800.0*ss, -80))
+ get_node("sprite/smoke").set_emitting(true)
get_node("sound").play("shoot")
- PS2D.body_add_collision_exception(bi.get_rid(),get_rid()) # make bullet and this not collide
-
-
+ PS2D.body_add_collision_exception(bi.get_rid(), get_rid()) # Make bullet and this not collide
else:
- shoot_time+=step
-
+ shoot_time += step
if (found_floor):
- airborne_time=0.0
+ airborne_time = 0.0
else:
- airborne_time+=step #time it spent in the air
-
+ airborne_time += step # Time it spent in the air
+
var on_floor = airborne_time < MAX_FLOOR_AIRBORNE_TIME
- # Process jump
+ # Process jump
if (jumping):
- if (lv.y>0):
- #set off the jumping flag if going down
- jumping=false
+ if (lv.y > 0):
+ # Set off the jumping flag if going down
+ jumping = false
elif (not jump):
- stopping_jump=true
-
- if (stopping_jump):
- lv.y+=STOP_JUMP_FORCE*step
+ stopping_jump = true
+ if (stopping_jump):
+ lv.y += STOP_JUMP_FORCE*step
+
if (on_floor):
-
# Process logic when character is on floor
-
if (move_left and not move_right):
if (lv.x > -WALK_MAX_VELOCITY):
- lv.x-=WALK_ACCEL*step
+ lv.x -= WALK_ACCEL*step
elif (move_right and not move_left):
if (lv.x < WALK_MAX_VELOCITY):
- lv.x+=WALK_ACCEL*step
+ lv.x += WALK_ACCEL*step
else:
var xv = abs(lv.x)
- xv-=WALK_DEACCEL*step
- if (xv<0):
- xv=0
- lv.x=sign(lv.x)*xv
-
- #Check jump
+ xv -= WALK_DEACCEL*step
+ if (xv < 0):
+ xv = 0
+ lv.x = sign(lv.x)*xv
+
+ # Check jump
if (not jumping and jump):
- lv.y=-JUMP_VELOCITY
- jumping=true
- stopping_jump=false
+ lv.y = -JUMP_VELOCITY
+ jumping = true
+ stopping_jump = false
get_node("sound").play("jump")
-
- #check siding
+ # Check siding
if (lv.x < 0 and move_left):
- new_siding_left=true
+ new_siding_left = true
elif (lv.x > 0 and move_right):
- new_siding_left=false
+ new_siding_left = false
if (jumping):
- new_anim="jumping"
- elif (abs(lv.x)<0.1):
- if (shoot_time<MAX_SHOOT_POSE_TIME):
- new_anim="idle_weapon"
+ new_anim = "jumping"
+ elif (abs(lv.x) < 0.1):
+ if (shoot_time < MAX_SHOOT_POSE_TIME):
+ new_anim = "idle_weapon"
else:
- new_anim="idle"
+ new_anim = "idle"
else:
- if (shoot_time<MAX_SHOOT_POSE_TIME):
- new_anim="run_weapon"
+ if (shoot_time < MAX_SHOOT_POSE_TIME):
+ new_anim = "run_weapon"
else:
- new_anim="run"
+ new_anim = "run"
else:
-
# Process logic when the character is in the air
-
if (move_left and not move_right):
if (lv.x > -WALK_MAX_VELOCITY):
- lv.x-=AIR_ACCEL*step
+ lv.x -= AIR_ACCEL*step
elif (move_right and not move_left):
if (lv.x < WALK_MAX_VELOCITY):
- lv.x+=AIR_ACCEL*step
+ lv.x += AIR_ACCEL*step
else:
var xv = abs(lv.x)
- xv-=AIR_DEACCEL*step
- if (xv<0):
- xv=0
- lv.x=sign(lv.x)*xv
-
- if (lv.y<0):
- if (shoot_time<MAX_SHOOT_POSE_TIME):
- new_anim="jumping_weapon"
+ xv -= AIR_DEACCEL*step
+ if (xv < 0):
+ xv = 0
+ lv.x = sign(lv.x)*xv
+
+ if (lv.y < 0):
+ if (shoot_time < MAX_SHOOT_POSE_TIME):
+ new_anim = "jumping_weapon"
else:
- new_anim="jumping"
+ new_anim = "jumping"
else:
- if (shoot_time<MAX_SHOOT_POSE_TIME):
- new_anim="falling_weapon"
+ if (shoot_time < MAX_SHOOT_POSE_TIME):
+ new_anim = "falling_weapon"
else:
- new_anim="falling"
-
-
- #Update siding
+ new_anim = "falling"
- if (new_siding_left!=siding_left):
+ # Update siding
+ if (new_siding_left != siding_left):
if (new_siding_left):
- get_node("sprite").set_scale( Vector2(-1,1) )
+ get_node("sprite").set_scale(Vector2(-1, 1))
else:
- get_node("sprite").set_scale( Vector2(1,1) )
-
- siding_left=new_siding_left
-
- #Change animation
- if (new_anim!=anim):
- anim=new_anim
- get_node("anim").play(anim)
-
- shooting=shoot
-
- # Apply floor velocity
- if (found_floor):
- floor_h_velocity=s.get_contact_collider_velocity_at_pos(floor_index).x
- lv.x+=floor_h_velocity
+ get_node("sprite").set_scale(Vector2(1, 1))
+ siding_left = new_siding_left
-
-
- #Finally, apply gravity and set back the linear velocity
- lv+=s.get_total_gravity()*step
- s.set_linear_velocity(lv)
-
+ # Change animation
+ if (new_anim != anim):
+ anim = new_anim
+ get_node("anim").play(anim)
-
+ shooting = shoot
+ # Apply floor velocity
+ if (found_floor):
+ floor_h_velocity = s.get_contact_collider_velocity_at_pos(floor_index).x
+ lv.x += floor_h_velocity
+ # Finally, apply gravity and set back the linear velocity
+ lv += s.get_total_gravity()*step
+ s.set_linear_velocity(lv)
func _ready():
- # Initalization here
-
+ enemy = ResourceLoader.load("res://enemy.xml")
+
# if !Globals.has_singleton("Facebook"):
-# return
+# return
# var Facebook = Globals.get_singleton("Facebook")
# var link = Globals.get("facebook/link")
# var icon = Globals.get("facebook/icon")
# var msg = "I just sneezed on your wall! Beat my score and Stop the Running nose!"
# var title = "I just sneezed on your wall!"
# Facebook.post("feed", msg, title, link, icon)
- enemy = ResourceLoader.load("res://enemy.xml")
- pass
-
-
-
diff --git a/demos/2d/platformer/player.xml b/demos/2d/platformer/player.xml
index 196881dee4..493279672f 100644
--- a/demos/2d/platformer/player.xml
+++ b/demos/2d/platformer/player.xml
@@ -1,15 +1,15 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="24" version="1.0" version_name="Godot Engine v1.0.rc2.custom_build">
- <ext_resource path="res://osb_jump.png" type="Texture"></ext_resource>
- <ext_resource path="res://bullet.png" type="Texture"></ext_resource>
- <ext_resource path="res://osb_right.png" type="Texture"></ext_resource>
- <ext_resource path="res://sound_coin.wav" type="Sample"></ext_resource>
- <ext_resource path="res://osb_fire.png" type="Texture"></ext_resource>
- <ext_resource path="res://sound_shoot.wav" type="Sample"></ext_resource>
- <ext_resource path="res://osb_left.png" type="Texture"></ext_resource>
- <ext_resource path="res://robot_demo.png" type="Texture"></ext_resource>
- <ext_resource path="res://player.gd" type="Script"></ext_resource>
- <ext_resource path="res://sound_jump.wav" type="Sample"></ext_resource>
+<resource_file type="PackedScene" subresource_count="25" version="2.0" version_name="Godot Engine v2.0.alpha.custom_build">
+ <ext_resource path="res://bullet.png" type="Texture" index="2"></ext_resource>
+ <ext_resource path="res://sound_coin.wav" type="Sample" index="3"></ext_resource>
+ <ext_resource path="res://player.gd" type="Script" index="0"></ext_resource>
+ <ext_resource path="res://robot_demo.png" type="Texture" index="1"></ext_resource>
+ <ext_resource path="res://sound_shoot.wav" type="Sample" index="5"></ext_resource>
+ <ext_resource path="res://sound_jump.wav" type="Sample" index="4"></ext_resource>
+ <ext_resource path="res://osb_left.png" type="Texture" index="6"></ext_resource>
+ <ext_resource path="res://osb_right.png" type="Texture" index="7"></ext_resource>
+ <ext_resource path="res://osb_jump.png" type="Texture" index="8"></ext_resource>
+ <ext_resource path="res://osb_fire.png" type="Texture" index="9"></ext_resource>
<resource type="RayShape2D" path="local://1">
<real name="custom_solver_bias"> 0.5 </real>
<real name="length"> 20 </real>
@@ -20,6 +20,11 @@
<vector2_array name="points" len="3"> -19.902, -24.8691, 19.3625, -24.6056, -0.138023, 16.5036 </vector2_array>
</resource>
+ <resource type="ColorRamp" path="local://14">
+ <real_array name="offsets" len="2"> 0, 1 </real_array>
+ <color_array name="colors" len="2"> 1, 1, 1, 1, 0, 0, 0, 0.0442478 </color_array>
+
+ </resource>
<resource type="Animation" path="local://3">
<string name="resource/name"> "idle" </string>
<real name="length"> 7 </real>
@@ -31,6 +36,8 @@
<dictionary name="tracks/0/keys" shared="false">
<string> "cont" </string>
<bool> False </bool>
+ <string> "times" </string>
+ <real_array len="8"> 0, 1.25, 1.5, 2, 4.5, 4.75, 5, 5.25 </real_array>
<string> "transitions" </string>
<real_array len="8"> 1, 1, 1, 1, 1, 1, 1, 1 </real_array>
<string> "values" </string>
@@ -44,8 +51,6 @@
<int> 19 </int>
<int> 16 </int>
</array>
- <string> "times" </string>
- <real_array len="8"> 0, 1.25, 1.5, 2, 4.5, 4.75, 5, 5.25 </real_array>
</dictionary>
</resource>
@@ -60,6 +65,8 @@
<dictionary name="tracks/0/keys" shared="false">
<string> "cont" </string>
<bool> False </bool>
+ <string> "times" </string>
+ <real_array len="3"> 0, 0.25, 0.5 </real_array>
<string> "transitions" </string>
<real_array len="3"> 1, 1, 1 </real_array>
<string> "values" </string>
@@ -68,13 +75,11 @@
<int> 24 </int>
<int> 23 </int>
</array>
- <string> "times" </string>
- <real_array len="3"> 0, 0.25, 0.5 </real_array>
</dictionary>
</resource>
- <resource type="Animation" path="local://5">
- <string name="resource/name"> "idle_weapon" </string>
+ <resource type="Animation" path="local://10">
+ <string name="resource/name"> "falling_weapon" </string>
<real name="length"> 0.5 </real>
<bool name="loop"> True </bool>
<real name="step"> 0.25 </real>
@@ -84,19 +89,20 @@
<dictionary name="tracks/0/keys" shared="false">
<string> "cont" </string>
<bool> False </bool>
+ <string> "times" </string>
+ <real_array len="1"> 0 </real_array>
<string> "transitions" </string>
<real_array len="1"> 1 </real_array>
<string> "values" </string>
<array len="1" shared="false">
- <int> 25 </int>
+ <int> 26 </int>
</array>
- <string> "times" </string>
- <real_array len="1"> 0 </real_array>
</dictionary>
</resource>
- <resource type="Animation" path="local://6">
- <real name="length"> 1.25 </real>
+ <resource type="Animation" path="local://5">
+ <string name="resource/name"> "idle_weapon" </string>
+ <real name="length"> 0.5 </real>
<bool name="loop"> True </bool>
<real name="step"> 0.25 </real>
<string name="tracks/0/type"> "value" </string>
@@ -105,19 +111,14 @@
<dictionary name="tracks/0/keys" shared="false">
<string> "cont" </string>
<bool> False </bool>
+ <string> "times" </string>
+ <real_array len="1"> 0 </real_array>
<string> "transitions" </string>
- <real_array len="6"> 1, 1, 1, 1, 1, 1 </real_array>
+ <real_array len="1"> 1 </real_array>
<string> "values" </string>
- <array len="6" shared="false">
- <int> 0 </int>
- <int> 1 </int>
- <int> 2 </int>
- <int> 3 </int>
- <int> 4 </int>
- <int> 0 </int>
+ <array len="1" shared="false">
+ <int> 25 </int>
</array>
- <string> "times" </string>
- <real_array len="6"> 0, 0.25, 0.5, 0.75, 1, 1.25 </real_array>
</dictionary>
</resource>
@@ -132,14 +133,14 @@
<dictionary name="tracks/0/keys" shared="false">
<string> "cont" </string>
<bool> False </bool>
+ <string> "times" </string>
+ <real_array len="1"> 0 </real_array>
<string> "transitions" </string>
<real_array len="1"> 1 </real_array>
<string> "values" </string>
<array len="1" shared="false">
<int> 22 </int>
</array>
- <string> "times" </string>
- <real_array len="1"> 0 </real_array>
</dictionary>
</resource>
@@ -154,14 +155,14 @@
<dictionary name="tracks/0/keys" shared="false">
<string> "cont" </string>
<bool> False </bool>
+ <string> "times" </string>
+ <real_array len="1"> 0 </real_array>
<string> "transitions" </string>
<real_array len="1"> 1 </real_array>
<string> "values" </string>
<array len="1" shared="false">
<int> 21 </int>
</array>
- <string> "times" </string>
- <real_array len="1"> 0 </real_array>
</dictionary>
</resource>
@@ -175,6 +176,8 @@
<dictionary name="tracks/0/keys" shared="false">
<string> "cont" </string>
<bool> False </bool>
+ <string> "times" </string>
+ <real_array len="6"> 0, 0.25, 0.5, 0.75, 1, 1.25 </real_array>
<string> "transitions" </string>
<real_array len="6"> 1, 1, 1, 1, 1, 1 </real_array>
<string> "values" </string>
@@ -186,13 +189,10 @@
<int> 14 </int>
<int> 5 </int>
</array>
- <string> "times" </string>
- <real_array len="6"> 0, 0.25, 0.5, 0.75, 1, 1.25 </real_array>
</dictionary>
</resource>
- <resource type="Animation" path="local://10">
- <string name="resource/name"> "falling_weapon" </string>
+ <resource type="Animation" path="local://12">
<real name="length"> 0.5 </real>
<bool name="loop"> True </bool>
<real name="step"> 0.25 </real>
@@ -202,18 +202,18 @@
<dictionary name="tracks/0/keys" shared="false">
<string> "cont" </string>
<bool> False </bool>
+ <string> "times" </string>
+ <real_array len="1"> 0 </real_array>
<string> "transitions" </string>
<real_array len="1"> 1 </real_array>
<string> "values" </string>
<array len="1" shared="false">
<int> 26 </int>
</array>
- <string> "times" </string>
- <real_array len="1"> 0 </real_array>
</dictionary>
</resource>
- <resource type="Animation" path="local://11">
+ <resource type="Animation" path="local://6">
<real name="length"> 1.25 </real>
<bool name="loop"> True </bool>
<real name="step"> 0.25 </real>
@@ -223,24 +223,24 @@
<dictionary name="tracks/0/keys" shared="false">
<string> "cont" </string>
<bool> False </bool>
+ <string> "times" </string>
+ <real_array len="6"> 0, 0.25, 0.5, 0.75, 1, 1.25 </real_array>
<string> "transitions" </string>
<real_array len="6"> 1, 1, 1, 1, 1, 1 </real_array>
<string> "values" </string>
<array len="6" shared="false">
- <int> 5 </int>
- <int> 6 </int>
- <int> 7 </int>
- <int> 8 </int>
- <int> 9 </int>
- <int> 5 </int>
+ <int> 0 </int>
+ <int> 1 </int>
+ <int> 2 </int>
+ <int> 3 </int>
+ <int> 4 </int>
+ <int> 0 </int>
</array>
- <string> "times" </string>
- <real_array len="6"> 0, 0.25, 0.5, 0.75, 1, 1.25 </real_array>
</dictionary>
</resource>
- <resource type="Animation" path="local://12">
- <real name="length"> 0.5 </real>
+ <resource type="Animation" path="local://11">
+ <real name="length"> 1.25 </real>
<bool name="loop"> True </bool>
<real name="step"> 0.25 </real>
<string name="tracks/0/type"> "value" </string>
@@ -249,14 +249,19 @@
<dictionary name="tracks/0/keys" shared="false">
<string> "cont" </string>
<bool> False </bool>
+ <string> "times" </string>
+ <real_array len="6"> 0, 0.25, 0.5, 0.75, 1, 1.25 </real_array>
<string> "transitions" </string>
- <real_array len="1"> 1 </real_array>
+ <real_array len="6"> 1, 1, 1, 1, 1, 1 </real_array>
<string> "values" </string>
- <array len="1" shared="false">
- <int> 26 </int>
+ <array len="6" shared="false">
+ <int> 5 </int>
+ <int> 6 </int>
+ <int> 7 </int>
+ <int> 8 </int>
+ <int> 9 </int>
+ <int> 5 </int>
</array>
- <string> "times" </string>
- <real_array len="1"> 0 </real_array>
</dictionary>
</resource>
@@ -267,7 +272,7 @@
<string> "pitch" </string>
<real> 1 </real>
<string> "sample" </string>
- <resource resource_type="Sample" path="res://sound_jump.wav"> </resource>
+ <resource external="4"> </resource>
</dictionary>
<dictionary name="samples/shoot" shared="false">
<string> "db" </string>
@@ -275,7 +280,7 @@
<string> "pitch" </string>
<real> 1 </real>
<string> "sample" </string>
- <resource resource_type="Sample" path="res://sound_shoot.wav"> </resource>
+ <resource external="5"> </resource>
</dictionary>
<dictionary name="samples/coin" shared="false">
<string> "db" </string>
@@ -283,36 +288,36 @@
<string> "pitch" </string>
<real> 1 </real>
<string> "sample" </string>
- <resource resource_type="Sample" path="res://sound_coin.wav"> </resource>
+ <resource external="3"> </resource>
</dictionary>
</resource>
<main_resource>
<dictionary name="_bundled" shared="false">
+ <string> "conn_count" </string>
+ <int> 0 </int>
+ <string> "conns" </string>
+ <int_array len="0"> </int_array>
+ <string> "editable_instances" </string>
+ <array len="0" shared="false">
+ </array>
<string> "names" </string>
- <string_array len="180">
+ <string_array len="144">
<string> "player" </string>
- <string> "RigidBody2D" </string>
- <string> "_import_path" </string>
- <string> "visibility/visible" </string>
- <string> "visibility/opacity" </string>
- <string> "visibility/self_opacity" </string>
- <string> "visibility/behind_parent" </string>
- <string> "transform/pos" </string>
- <string> "transform/rot" </string>
- <string> "transform/scale" </string>
- <string> "shape_count" </string>
+ <string> "input/pickable" </string>
<string> "shapes/0/shape" </string>
<string> "shapes/0/transform" </string>
<string> "shapes/0/trigger" </string>
<string> "shapes/1/shape" </string>
<string> "shapes/1/transform" </string>
<string> "shapes/1/trigger" </string>
- <string> "layers" </string>
+ <string> "collision/layers" </string>
+ <string> "collision/mask" </string>
<string> "mode" </string>
<string> "mass" </string>
<string> "friction" </string>
<string> "bounce" </string>
+ <string> "gravity_scale" </string>
<string> "custom_integrator" </string>
<string> "continuous_cd" </string>
<string> "contacts_reported" </string>
@@ -321,39 +326,28 @@
<string> "can_sleep" </string>
<string> "velocity/linear" </string>
<string> "velocity/angular" </string>
+ <string> "damp_override/linear" </string>
+ <string> "damp_override/angular" </string>
<string> "script/script" </string>
<string> "__meta__" </string>
+ <string> "RigidBody2D" </string>
<string> "sprite" </string>
- <string> "Sprite" </string>
<string> "texture" </string>
- <string> "centered" </string>
- <string> "offset" </string>
- <string> "flip_h" </string>
- <string> "flip_v" </string>
<string> "vframes" </string>
<string> "hframes" </string>
- <string> "frame" </string>
- <string> "modulate" </string>
- <string> "region" </string>
- <string> "region_rect" </string>
+ <string> "Sprite" </string>
<string> "smoke" </string>
- <string> "Particles2D" </string>
+ <string> "visibility/self_opacity" </string>
<string> "visibility/blend_mode" </string>
+ <string> "transform/pos" </string>
+ <string> "transform/rot" </string>
<string> "config/amount" </string>
<string> "config/lifetime" </string>
- <string> "config/time_scale" </string>
- <string> "config/preprocess" </string>
<string> "config/emit_timeout" </string>
<string> "config/emitting" </string>
- <string> "config/offset" </string>
- <string> "config/half_extents" </string>
<string> "config/local_space" </string>
<string> "config/explosiveness" </string>
- <string> "config/flip_h" </string>
- <string> "config/flip_v" </string>
<string> "config/texture" </string>
- <string> "config/h_frames" </string>
- <string> "config/v_frames" </string>
<string> "params/direction" </string>
<string> "params/spread" </string>
<string> "params/linear_velocity" </string>
@@ -370,53 +364,30 @@
<string> "params/hue_variation" </string>
<string> "params/anim_speed_scale" </string>
<string> "params/anim_initial_pos" </string>
- <string> "randomness/direction" </string>
- <string> "randomness/spread" </string>
- <string> "randomness/linear_velocity" </string>
<string> "randomness/spin_velocity" </string>
- <string> "randomness/orbit_velocity" </string>
- <string> "randomness/gravity_direction" </string>
- <string> "randomness/gravity_strength" </string>
- <string> "randomness/radial_accel" </string>
- <string> "randomness/tangential_accel" </string>
- <string> "randomness/damping" </string>
- <string> "randomness/initial_angle" </string>
- <string> "randomness/initial_size" </string>
- <string> "randomness/final_size" </string>
- <string> "randomness/hue_variation" </string>
- <string> "randomness/anim_speed_scale" </string>
- <string> "randomness/anim_initial_pos" </string>
- <string> "color_phases/count" </string>
- <string> "phase_0/pos" </string>
- <string> "phase_0/color" </string>
- <string> "phase_1/pos" </string>
- <string> "phase_1/color" </string>
- <string> "phase_2/pos" </string>
- <string> "phase_2/color" </string>
- <string> "phase_3/pos" </string>
- <string> "phase_3/color" </string>
- <string> "emission_points" </string>
+ <string> "color/color_ramp" </string>
+ <string> "Particles2D" </string>
<string> "anim" </string>
- <string> "AnimationPlayer" </string>
<string> "playback/process_mode" </string>
<string> "playback/default_blend_time" </string>
<string> "root/root" </string>
<string> "anims/idle" </string>
<string> "anims/jumping" </string>
+ <string> "anims/falling_weapon" </string>
<string> "anims/idle_weapon" </string>
- <string> "anims/run" </string>
<string> "anims/crouch" </string>
<string> "anims/falling" </string>
<string> "anims/standing_weapon_ready" </string>
- <string> "anims/falling_weapon" </string>
- <string> "anims/run_weapon" </string>
<string> "anims/jumping_weapon" </string>
+ <string> "anims/run" </string>
+ <string> "anims/run_weapon" </string>
<string> "playback/active" </string>
<string> "playback/speed" </string>
<string> "blend_times" </string>
<string> "autoplay" </string>
+ <string> "AnimationPlayer" </string>
<string> "camera" </string>
- <string> "Camera2D" </string>
+ <string> "anchor_mode" </string>
<string> "rotating" </string>
<string> "current" </string>
<string> "smoothing" </string>
@@ -431,14 +402,16 @@
<string> "drag_margin/top" </string>
<string> "drag_margin/right" </string>
<string> "drag_margin/bottom" </string>
+ <string> "Camera2D" </string>
<string> "bullet_shoot" </string>
<string> "Position2D" </string>
<string> "CollisionShape2D" </string>
+ <string> "transform/scale" </string>
<string> "shape" </string>
<string> "trigger" </string>
+ <string> "_update_shape_index" </string>
<string> "sound" </string>
- <string> "SamplePlayer" </string>
- <string> "config/voices" </string>
+ <string> "config/polyphony" </string>
<string> "config/samples" </string>
<string> "default/volume_db" </string>
<string> "default/pitch_scale" </string>
@@ -452,167 +425,180 @@
<string> "default/reverb_room" </string>
<string> "default/reverb_send" </string>
<string> "default/chorus_send" </string>
+ <string> "SamplePlayer" </string>
<string> "CollisionPolygon2D" </string>
<string> "build_mode" </string>
<string> "polygon" </string>
+ <string> "shape_range" </string>
<string> "ui" </string>
- <string> "CanvasLayer" </string>
<string> "layer" </string>
+ <string> "offset" </string>
<string> "rotation" </string>
<string> "scale" </string>
+ <string> "CanvasLayer" </string>
<string> "left" </string>
- <string> "TouchScreenButton" </string>
<string> "normal" </string>
<string> "pressed" </string>
<string> "bitmask" </string>
<string> "passby_press" </string>
<string> "action" </string>
<string> "visibility_mode" </string>
+ <string> "TouchScreenButton" </string>
<string> "right" </string>
<string> "jump" </string>
<string> "fire" </string>
</string_array>
- <string> "version" </string>
- <int> 1 </int>
- <string> "conn_count" </string>
- <int> 0 </int>
<string> "node_count" </string>
<int> 14 </int>
+ <string> "node_paths" </string>
+ <array len="0" shared="false">
+ </array>
+ <string> "nodes" </string>
+ <int_array len="398"> -1, -1, 27, 0, -1, 26, 1, 0, 2, 1, 3, 2, 4, 0, 5, 3, 6, 4, 7, 0, 8, 5, 9, 5, 10, 6, 11, 7, 12, 8, 13, 8, 14, 9, 15, 10, 16, 11, 17, 12, 18, 0, 19, 0, 20, 10, 21, 13, 22, 8, 23, 14, 24, 14, 25, 15, 26, 16, 0, 0, 0, 32, 28, -1, 3, 29, 17, 30, 6, 31, 18, 0, 1, 0, 63, 33, -1, 29, 34, 19, 35, 5, 36, 20, 37, 21, 38, 22, 39, 23, 40, 23, 41, 0, 42, 0, 43, 24, 44, 25, 45, 8, 46, 26, 47, 27, 48, 9, 49, 8, 50, 8, 51, 28, 52, 8, 53, 8, 54, 8, 55, 8, 56, 29, 57, 29, 58, 8, 59, 9, 60, 8, 61, 29, 62, 30, 0, 0, 0, 82, 64, -1, 17, 65, 5, 66, 8, 67, 31, 68, 32, 69, 33, 70, 34, 71, 35, 72, 36, 73, 37, 74, 38, 75, 39, 76, 40, 77, 41, 78, 10, 79, 29, 80, 42, 81, 43, 0, 0, 0, 99, 83, -1, 15, 84, 5, 85, 0, 86, 10, 87, 8, 88, 44, 89, 11, 90, 11, 91, 45, 92, 45, 93, 10, 94, 10, 95, 46, 96, 46, 97, 46, 98, 46, 0, 0, 0, 101, 100, -1, 1, 36, 47, 0, 0, 0, 102, 102, -1, 5, 36, 48, 103, 49, 104, 1, 105, 0, 106, 50, 0, 0, 0, 122, 107, -1, 14, 108, 5, 109, 51, 110, 8, 111, 9, 112, 8, 113, 8, 114, 8, 115, 11, 116, 8, 117, 8, 118, 8, 119, 6, 120, 8, 121, 8, 0, 0, 0, 123, 123, -1, 4, 124, 11, 125, 52, 126, 53, 105, 0, 0, 0, 0, 132, 127, -1, 4, 128, 11, 129, 13, 130, 8, 131, 44, 0, 9, 0, 140, 133, -1, 8, 36, 54, 103, 55, 134, 56, 135, 57, 136, 57, 137, 10, 138, 58, 139, 5, 0, 9, 0, 140, 141, -1, 8, 36, 59, 103, 55, 134, 60, 135, 57, 136, 57, 137, 10, 138, 61, 139, 5, 0, 9, 0, 140, 142, -1, 8, 36, 62, 103, 55, 134, 63, 135, 57, 136, 57, 137, 0, 138, 64, 139, 5, 0, 9, 0, 140, 143, -1, 8, 36, 65, 103, 55, 134, 66, 135, 57, 136, 57, 137, 0, 138, 67, 139, 5, 0 </int_array>
<string> "variants" </string>
- <array len="72" shared="false">
- <node_path> "" </node_path>
- <bool> True </bool>
- <real> 1 </real>
+ <array len="68" shared="false">
<bool> False </bool>
- <vector2> 0, 0 </vector2>
- <real> 0 </real>
- <vector2> 1, 1 </vector2>
- <int> 2 </int>
<resource resource_type="Shape2D" path="local://1"> </resource>
<matrix32> 1, -0, 0, 1.76469, 0.291992, -12.1587 </matrix32>
<resource resource_type="Shape2D" path="local://2"> </resource>
<matrix32> 1, -0, 0, 1, 0, 0 </matrix32>
<int> 1 </int>
+ <int> 2 </int>
<real> 3 </real>
+ <real> 0 </real>
+ <real> 1 </real>
+ <bool> True </bool>
<int> 0 </int>
<int> 3 </int>
- <resource resource_type="Script" path="res://player.gd"> </resource>
+ <vector2> 0, 0 </vector2>
+ <real> -1 </real>
+ <resource external="0"> </resource>
<dictionary shared="false">
+ <string> "__editor_plugin_screen__" </string>
+ <string> "2D" </string>
<string> "__editor_plugin_states__" </string>
<dictionary shared="false">
- <string> "Script" </string>
- <dictionary shared="false">
- <string> "current" </string>
- <int> 0 </int>
- <string> "sources" </string>
- <array len="1" shared="false">
- <string> "res://player.gd" </string>
- </array>
- </dictionary>
<string> "2D" </string>
<dictionary shared="false">
- <string> "pixel_snap" </string>
+ <string> "ofs" </string>
+ <vector2> -110.795, -101.2 </vector2>
+ <string> "snap_grid" </string>
<bool> False </bool>
- <string> "zoom" </string>
- <real> 2.272073 </real>
- <string> "use_snap" </string>
+ <string> "snap_offset" </string>
+ <vector2> 0, 0 </vector2>
+ <string> "snap_pixel" </string>
<bool> False </bool>
- <string> "ofs" </string>
- <vector2> -181.946, -86.2812 </vector2>
- <string> "snap" </string>
- <int> 10 </int>
+ <string> "snap_relative" </string>
+ <bool> False </bool>
+ <string> "snap_rotation" </string>
+ <bool> False </bool>
+ <string> "snap_rotation_offset" </string>
+ <real> 0 </real>
+ <string> "snap_rotation_step" </string>
+ <real> 0.261799 </real>
+ <string> "snap_show_grid" </string>
+ <bool> False </bool>
+ <string> "snap_step" </string>
+ <vector2> 10, 10 </vector2>
+ <string> "zoom" </string>
+ <real> 2.050546 </real>
</dictionary>
<string> "3D" </string>
<dictionary shared="false">
+ <string> "ambient_light_color" </string>
+ <color> 0.15, 0.15, 0.15, 1 </color>
+ <string> "default_light" </string>
+ <bool> True </bool>
+ <string> "default_srgb" </string>
+ <bool> False </bool>
+ <string> "deflight_rot_x" </string>
+ <real> 0.942478 </real>
<string> "deflight_rot_y" </string>
<real> 0.628319 </real>
- <string> "zfar" </string>
- <real> 500 </real>
<string> "fov" </string>
<real> 45 </real>
+ <string> "show_grid" </string>
+ <bool> True </bool>
+ <string> "show_origin" </string>
+ <bool> True </bool>
+ <string> "viewport_mode" </string>
+ <int> 1 </int>
<string> "viewports" </string>
<array len="4" shared="false">
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
<string> "listener" </string>
<bool> True </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
<string> "use_environment" </string>
<bool> False </bool>
<string> "use_orthogonal" </string>
<bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
+ </dictionary>
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
<string> "listener" </string>
<bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
<string> "use_environment" </string>
<bool> False </bool>
<string> "use_orthogonal" </string>
<bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
+ </dictionary>
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
<string> "listener" </string>
<bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
<string> "use_environment" </string>
<bool> False </bool>
<string> "use_orthogonal" </string>
<bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
+ </dictionary>
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
<string> "listener" </string>
<bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
<string> "use_environment" </string>
<bool> False </bool>
<string> "use_orthogonal" </string>
<bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
+ <string> "x_rot" </string>
+ <real> 0 </real>
+ <string> "y_rot" </string>
+ <real> 0 </real>
</dictionary>
</array>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "ambient_light_color" </string>
- <color> 0.15, 0.15, 0.15, 1 </color>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
+ <string> "zfar" </string>
+ <real> 500 </real>
<string> "znear" </string>
<real> 0.1 </real>
- <string> "default_srgb" </string>
+ </dictionary>
+ <string> "Anim" </string>
+ <dictionary shared="false">
+ <string> "visible" </string>
<bool> False </bool>
- <string> "deflight_rot_x" </string>
- <real> 0.942478 </real>
</dictionary>
</dictionary>
<string> "__editor_run_settings__" </string>
@@ -622,68 +608,61 @@
<string> "run_mode" </string>
<int> 0 </int>
</dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "Script" </string>
</dictionary>
- <resource resource_type="Texture" path="res://robot_demo.png"> </resource>
+ <resource external="1"> </resource>
<int> 16 </int>
- <color> 1, 1, 1, 1 </color>
- <rect2> 0, 0, 0, 0 </rect2>
<real> 0.363636 </real>
<vector2> 20.7312, 3.21187 </vector2>
<real> 83.450417 </real>
<int> 4 </int>
<real> 0.3 </real>
<real> 0.1 </real>
- <resource resource_type="Texture" path="res://bullet.png"> </resource>
+ <resource external="2"> </resource>
<real> 180 </real>
<real> 20 </real>
<real> 9.8 </real>
<real> 2 </real>
- <color> 0, 0, 0, 0.0442478 </color>
- <color> 1, 0, 0, 1 </color>
- <color> 0, 0, 0, 1 </color>
- <vector2_array len="0"> </vector2_array>
+ <resource resource_type="ColorRamp" path="local://14"> </resource>
<node_path> ".." </node_path>
<resource resource_type="Animation" path="local://3"> </resource>
<resource resource_type="Animation" path="local://4"> </resource>
+ <resource resource_type="Animation" path="local://10"> </resource>
<resource resource_type="Animation" path="local://5"> </resource>
- <resource resource_type="Animation" path="local://6"> </resource>
<resource resource_type="Animation" path="local://7"> </resource>
<resource resource_type="Animation" path="local://8"> </resource>
<resource resource_type="Animation" path="local://9"> </resource>
- <resource resource_type="Animation" path="local://10"> </resource>
- <resource resource_type="Animation" path="local://11"> </resource>
<resource resource_type="Animation" path="local://12"> </resource>
+ <resource resource_type="Animation" path="local://6"> </resource>
+ <resource resource_type="Animation" path="local://11"> </resource>
<array len="0" shared="false">
</array>
<string> "" </string>
+ <vector2> 1, 1 </vector2>
<int> 10000000 </int>
<real> 0.2 </real>
<vector2> 31.2428, 4.08784 </vector2>
<vector2> 0.291992, -12.1587 </vector2>
<vector2> 1, 1.76469 </vector2>
+ <int> -1 </int>
<resource resource_type="SampleLibrary" path="local://13"> </resource>
- <nil> </nil>
<vector2_array len="3"> -0.138023, 16.5036, -19.902, -24.8691, 19.3625, -24.6056 </vector2_array>
+ <vector2> -1, -1 </vector2>
<vector2> 27.7593, 360.87 </vector2>
<vector2> 1.49157, 1.46265 </vector2>
- <resource resource_type="Texture" path="res://osb_left.png"> </resource>
+ <resource external="6"> </resource>
<resource name=""></resource> <string> "move_left" </string>
<vector2> 121.542, 361.415 </vector2>
- <resource resource_type="Texture" path="res://osb_right.png"> </resource>
+ <resource external="7"> </resource>
<string> "move_right" </string>
<vector2> 666.224, 359.02 </vector2>
- <resource resource_type="Texture" path="res://osb_jump.png"> </resource>
+ <resource external="8"> </resource>
<string> "jump" </string>
<vector2> 668.073, 262.788 </vector2>
- <resource resource_type="Texture" path="res://osb_fire.png"> </resource>
+ <resource external="9"> </resource>
<string> "shoot" </string>
</array>
- <string> "nodes" </string>
- <int_array len="618"> -1, -1, 1, 0, -1, 30, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 10, 7, 11, 8, 12, 9, 13, 3, 14, 10, 15, 11, 16, 3, 17, 12, 18, 7, 19, 13, 20, 5, 21, 5, 22, 1, 23, 14, 24, 15, 25, 3, 26, 3, 27, 1, 28, 4, 29, 5, 30, 16, 31, 17, 0, 0, 0, 33, 32, -1, 19, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 34, 18, 35, 1, 36, 4, 37, 3, 38, 3, 39, 7, 40, 19, 41, 14, 42, 20, 43, 3, 44, 21, 0, 1, 0, 46, 45, -1, 66, 2, 0, 3, 1, 4, 2, 5, 22, 6, 3, 47, 12, 7, 23, 8, 24, 9, 6, 48, 25, 49, 26, 50, 2, 51, 5, 52, 26, 53, 3, 54, 4, 55, 4, 56, 3, 57, 27, 58, 3, 59, 3, 60, 28, 61, 12, 62, 12, 63, 5, 64, 29, 65, 30, 66, 2, 67, 5, 68, 5, 69, 31, 70, 5, 71, 5, 72, 5, 73, 5, 74, 32, 75, 32, 76, 5, 77, 2, 78, 5, 79, 5, 80, 5, 81, 5, 82, 32, 83, 5, 84, 5, 85, 5, 86, 5, 87, 5, 88, 5, 89, 5, 90, 5, 91, 5, 92, 5, 93, 5, 94, 5, 95, 7, 96, 5, 97, 20, 98, 2, 99, 33, 100, 2, 101, 34, 102, 2, 103, 35, 104, 36, 0, 0, 0, 106, 105, -1, 18, 2, 0, 107, 12, 108, 5, 109, 37, 110, 38, 111, 39, 112, 40, 113, 41, 114, 42, 115, 43, 116, 44, 117, 45, 118, 46, 119, 47, 120, 1, 121, 32, 122, 48, 123, 49, 0, 0, 0, 125, 124, -1, 23, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 35, 1, 126, 3, 127, 1, 128, 5, 129, 6, 130, 14, 131, 14, 132, 50, 133, 50, 134, 1, 135, 1, 136, 51, 137, 51, 138, 51, 139, 51, 0, 0, 0, 141, 140, -1, 8, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 52, 8, 5, 9, 6, 0, 0, 0, 142, 142, -1, 10, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 53, 8, 5, 9, 54, 143, 8, 144, 3, 0, 0, 0, 146, 145, -1, 15, 2, 0, 147, 15, 148, 55, 149, 5, 150, 2, 151, 5, 152, 5, 153, 5, 154, 56, 155, 56, 156, 56, 157, 56, 158, 7, 159, 5, 160, 5, 0, 0, 0, 161, 161, -1, 10, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 162, 14, 163, 57, 0, 0, 0, 165, 164, -1, 5, 2, 0, 166, 14, 36, 4, 167, 5, 168, 6, 0, 9, 0, 170, 169, -1, 14, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 58, 8, 5, 9, 59, 171, 60, 172, 61, 173, 61, 174, 1, 175, 62, 176, 12, 0, 9, 0, 170, 177, -1, 14, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 63, 8, 5, 9, 59, 171, 64, 172, 61, 173, 61, 174, 1, 175, 65, 176, 12, 0, 9, 0, 170, 178, -1, 14, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 66, 8, 5, 9, 59, 171, 67, 172, 61, 173, 61, 174, 3, 175, 68, 176, 12, 0, 9, 0, 170, 179, -1, 14, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 69, 8, 5, 9, 59, 171, 70, 172, 61, 173, 61, 174, 3, 175, 71, 176, 12, 0 </int_array>
- <string> "conns" </string>
- <int_array len="0"> </int_array>
+ <string> "version" </string>
+ <int> 2 </int>
</dictionary>
</main_resource>
diff --git a/demos/2d/platformer/seesaw.xml b/demos/2d/platformer/seesaw.xml
index ed879a9319..760423167f 100644
--- a/demos/2d/platformer/seesaw.xml
+++ b/demos/2d/platformer/seesaw.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="4" version="1.0" version_name="Godot Engine v1.0.3917-beta1">
- <ext_resource path="res://plank.*" type="Texture"></ext_resource>
- <ext_resource path="res://plankpin.*" type="Texture"></ext_resource>
+<resource_file type="PackedScene" subresource_count="4" version="2.0" version_name="Godot Engine v2.0.alpha.custom_build">
+ <ext_resource path="res://plank.png" type="Texture" index="0"></ext_resource>
+ <ext_resource path="res://plankpin.png" type="Texture" index="1"></ext_resource>
<resource type="RectangleShape2D" path="local://1">
<real name="custom_solver_bias"> 0 </real>
<vector2 name="extents"> 128, 8 </vector2>
@@ -9,159 +9,192 @@
</resource>
<main_resource>
<dictionary name="_bundled" shared="false">
+ <string> "conn_count" </string>
+ <int> 0 </int>
+ <string> "conns" </string>
+ <int_array len="0"> </int_array>
+ <string> "editable_instances" </string>
+ <array len="0" shared="false">
+ </array>
<string> "names" </string>
- <string_array len="49">
+ <string_array len="40">
<string> "seesaw" </string>
- <string> "Node2D" </string>
- <string> "visibility/visible" </string>
- <string> "visibility/opacity" </string>
- <string> "visibility/self_opacity" </string>
- <string> "visibility/on_top" </string>
- <string> "transform/pos" </string>
- <string> "transform/rot" </string>
- <string> "transform/scale" </string>
<string> "__meta__" </string>
+ <string> "Node2D" </string>
<string> "plank" </string>
- <string> "RigidBody2D" </string>
- <string> "shape_count" </string>
+ <string> "input/pickable" </string>
<string> "shapes/0/shape" </string>
<string> "shapes/0/transform" </string>
<string> "shapes/0/trigger" </string>
+ <string> "collision/layers" </string>
+ <string> "collision/mask" </string>
<string> "mode" </string>
<string> "mass" </string>
<string> "friction" </string>
<string> "bounce" </string>
+ <string> "gravity_scale" </string>
<string> "custom_integrator" </string>
<string> "continuous_cd" </string>
<string> "contacts_reported" </string>
<string> "contact_monitor" </string>
- <string> "active" </string>
+ <string> "sleeping" </string>
<string> "can_sleep" </string>
<string> "velocity/linear" </string>
<string> "velocity/angular" </string>
+ <string> "damp_override/linear" </string>
+ <string> "damp_override/angular" </string>
+ <string> "RigidBody2D" </string>
<string> "sprite" </string>
- <string> "Sprite" </string>
<string> "texture" </string>
- <string> "centered" </string>
- <string> "offset" </string>
- <string> "flip_h" </string>
- <string> "flip_v" </string>
- <string> "vframes" </string>
- <string> "hframes" </string>
- <string> "frame" </string>
- <string> "modulate" </string>
- <string> "region" </string>
- <string> "region_rect" </string>
+ <string> "Sprite" </string>
<string> "CollisionShape2D" </string>
<string> "shape" </string>
<string> "trigger" </string>
+ <string> "_update_shape_index" </string>
<string> "pin" </string>
- <string> "PinJoint2D" </string>
<string> "node_a" </string>
<string> "node_b" </string>
<string> "bias/bias" </string>
+ <string> "softness" </string>
+ <string> "PinJoint2D" </string>
+ <string> "transform/pos" </string>
</string_array>
- <string> "version" </string>
- <int> 1 </int>
- <string> "conn_count" </string>
- <int> 0 </int>
<string> "node_count" </string>
<int> 6 </int>
+ <string> "node_paths" </string>
+ <array len="0" shared="false">
+ </array>
+ <string> "nodes" </string>
+ <int_array len="106"> -1, -1, 2, 0, -1, 1, 1, 0, 0, 0, 0, 25, 3, -1, 21, 4, 1, 5, 2, 6, 3, 7, 1, 8, 4, 9, 4, 10, 5, 11, 6, 12, 7, 13, 8, 14, 7, 15, 1, 16, 5, 17, 5, 18, 1, 19, 1, 20, 9, 21, 10, 22, 8, 23, 11, 24, 11, 0, 1, 0, 28, 26, -1, 1, 27, 12, 0, 1, 0, 29, 29, -1, 3, 30, 2, 31, 1, 32, 13, 0, 0, 0, 38, 33, -1, 4, 34, 14, 35, 15, 36, 8, 37, 8, 0, 0, 0, 28, 28, -1, 2, 39, 16, 27, 17, 0 </int_array>
<string> "variants" </string>
- <array len="19" shared="false">
- <bool> True </bool>
- <real> 1 </real>
- <vector2> 0, 0 </vector2>
- <real> 0 </real>
- <vector2> 1, 1 </vector2>
+ <array len="18" shared="false">
<dictionary shared="false">
+ <string> "__editor_plugin_screen__" </string>
+ <string> "2D" </string>
<string> "__editor_plugin_states__" </string>
<dictionary shared="false">
<string> "2D" </string>
<dictionary shared="false">
- <string> "pixel_snap" </string>
+ <string> "ofs" </string>
+ <vector2> -116.979, -109.897 </vector2>
+ <string> "snap_grid" </string>
+ <bool> False </bool>
+ <string> "snap_offset" </string>
+ <vector2> 0, 0 </vector2>
+ <string> "snap_pixel" </string>
+ <bool> False </bool>
+ <string> "snap_relative" </string>
+ <bool> False </bool>
+ <string> "snap_rotation" </string>
<bool> False </bool>
+ <string> "snap_rotation_offset" </string>
+ <real> 0 </real>
+ <string> "snap_rotation_step" </string>
+ <real> 0.261799 </real>
+ <string> "snap_show_grid" </string>
+ <bool> False </bool>
+ <string> "snap_step" </string>
+ <vector2> 10, 10 </vector2>
<string> "zoom" </string>
<real> 2.050547 </real>
- <string> "ofs" </string>
- <vector2> -116.979, -109.897 </vector2>
</dictionary>
<string> "3D" </string>
<dictionary shared="false">
- <string> "zfar" </string>
- <real> 500 </real>
+ <string> "ambient_light_color" </string>
+ <color> 0.15, 0.15, 0.15, 1 </color>
+ <string> "default_light" </string>
+ <bool> True </bool>
+ <string> "default_srgb" </string>
+ <bool> False </bool>
+ <string> "deflight_rot_x" </string>
+ <real> 0.942478 </real>
+ <string> "deflight_rot_y" </string>
+ <real> 0.628319 </real>
<string> "fov" </string>
- <real> 400 </real>
+ <real> 179 </real>
+ <string> "show_grid" </string>
+ <bool> True </bool>
+ <string> "show_origin" </string>
+ <bool> True </bool>
+ <string> "viewport_mode" </string>
+ <int> 1 </int>
<string> "viewports" </string>
<array len="4" shared="false">
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> True </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
</array>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
+ <string> "zfar" </string>
+ <real> 500 </real>
<string> "znear" </string>
<real> 0.1 </real>
</dictionary>
+ <string> "Anim" </string>
+ <dictionary shared="false">
+ <string> "visible" </string>
+ <bool> False </bool>
+ </dictionary>
</dictionary>
<string> "__editor_run_settings__" </string>
<dictionary shared="false">
@@ -170,27 +203,27 @@
<string> "run_mode" </string>
<int> 0 </int>
</dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "2D" </string>
</dictionary>
- <int> 1 </int>
+ <bool> False </bool>
<resource resource_type="Shape2D" path="local://1"> </resource>
<matrix32> 1, 0, 0, 1, 0, 0 </matrix32>
- <bool> False </bool>
+ <int> 1 </int>
<int> 0 </int>
<real> 5.102041 </real>
- <resource resource_type="Texture" path="res://plank.*"> </resource>
- <color> 1, 1, 1, 1 </color>
- <rect2> 0, 0, 0, 0 </rect2>
+ <real> 1 </real>
+ <real> 0 </real>
+ <bool> True </bool>
+ <vector2> 0, 0 </vector2>
+ <real> -1 </real>
+ <resource external="0"> </resource>
+ <int> -1 </int>
<node_path> "../plank" </node_path>
<node_path> "" </node_path>
<vector2> -0.290825, 20.2425 </vector2>
- <resource resource_type="Texture" path="res://plankpin.*"> </resource>
+ <resource external="1"> </resource>
</array>
- <string> "nodes" </string>
- <int_array len="214"> -1, -1, 1, 0, -1, 8, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 9, 5, 0, 0, 0, 11, 10, -1, 23, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 12, 6, 13, 7, 14, 8, 15, 9, 16, 10, 17, 11, 18, 1, 19, 3, 20, 9, 21, 9, 22, 10, 23, 9, 24, 0, 25, 0, 26, 2, 27, 3, 0, 1, 0, 29, 28, -1, 18, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 30, 12, 31, 0, 32, 2, 33, 9, 34, 9, 35, 6, 36, 6, 37, 10, 38, 13, 39, 9, 40, 14, 0, 1, 0, 41, 41, -1, 9, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 42, 7, 43, 9, 0, 0, 0, 45, 44, -1, 10, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 46, 15, 47, 16, 48, 3, 0, 0, 0, 29, 29, -1, 18, 2, 0, 3, 1, 4, 1, 5, 0, 6, 17, 7, 3, 8, 4, 30, 18, 31, 0, 32, 2, 33, 9, 34, 9, 35, 6, 36, 6, 37, 10, 38, 13, 39, 9, 40, 14, 0 </int_array>
- <string> "conns" </string>
- <int_array len="0"> </int_array>
+ <string> "version" </string>
+ <int> 2 </int>
</dictionary>
</main_resource>
diff --git a/demos/2d/platformer/stage.xml b/demos/2d/platformer/stage.xml
index 4d6083adf6..3b5d281551 100644
--- a/demos/2d/platformer/stage.xml
+++ b/demos/2d/platformer/stage.xml
@@ -1,37 +1,29 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="10" version="1.1" version_name="Godot Engine v1.1.rc1.custom_build">
- <ext_resource path="res://tileset.xml" type="TileSet"></ext_resource>
- <ext_resource path="res://coin.xml" type="PackedScene"></ext_resource>
- <ext_resource path="res://moving_platform.xml" type="PackedScene"></ext_resource>
- <ext_resource path="res://seesaw.xml" type="PackedScene"></ext_resource>
- <ext_resource path="res://one_way_platform.xml" type="PackedScene"></ext_resource>
- <ext_resource path="res://player.xml" type="PackedScene"></ext_resource>
- <ext_resource path="res://music.ogg" type="AudioStream"></ext_resource>
- <ext_resource path="res://enemy.xml" type="PackedScene"></ext_resource>
- <ext_resource path="res://parallax_bg.xml" type="PackedScene"></ext_resource>
+<resource_file type="PackedScene" subresource_count="10" version="2.0" version_name="Godot Engine v2.0.alpha.custom_build">
+ <ext_resource path="res://tileset.xml" type="TileSet" index="0"></ext_resource>
+ <ext_resource path="res://music.ogg" type="AudioStream" index="6"></ext_resource>
+ <ext_resource path="res://coin.xml" type="PackedScene" index="1"></ext_resource>
+ <ext_resource path="res://one_way_platform.xml" type="PackedScene" index="4"></ext_resource>
+ <ext_resource path="res://moving_platform.xml" type="PackedScene" index="2"></ext_resource>
+ <ext_resource path="res://enemy.xml" type="PackedScene" index="7"></ext_resource>
+ <ext_resource path="res://seesaw.xml" type="PackedScene" index="3"></ext_resource>
+ <ext_resource path="res://player.xml" type="PackedScene" index="5"></ext_resource>
+ <ext_resource path="res://parallax_bg.xml" type="PackedScene" index="8"></ext_resource>
<main_resource>
<dictionary name="_bundled" shared="false">
<string> "conn_count" </string>
<int> 0 </int>
<string> "conns" </string>
<int_array len="0"> </int_array>
+ <string> "editable_instances" </string>
+ <array len="0" shared="false">
+ </array>
<string> "names" </string>
- <string_array len="133">
+ <string_array len="112">
<string> "stage" </string>
- <string> "Node" </string>
- <string> "_import_path" </string>
<string> "__meta__" </string>
+ <string> "Node" </string>
<string> "tile_map" </string>
- <string> "TileMap" </string>
- <string> "visibility/visible" </string>
- <string> "visibility/opacity" </string>
- <string> "visibility/self_opacity" </string>
- <string> "visibility/light_mask" </string>
- <string> "transform/pos" </string>
- <string> "transform/rot" </string>
- <string> "transform/scale" </string>
- <string> "z/z" </string>
- <string> "z/relative" </string>
<string> "mode" </string>
<string> "tile_set" </string>
<string> "cell/size" </string>
@@ -46,9 +38,13 @@
<string> "collision/layers" </string>
<string> "collision/mask" </string>
<string> "tile_data" </string>
+ <string> "TileMap" </string>
<string> "coins" </string>
<string> "coin" </string>
- <string> "Area2D" </string>
+ <string> "transform/pos" </string>
+ <string> "input/pickable" </string>
+ <string> "linear_damp" </string>
+ <string> "angular_damp" </string>
<string> "coin 2" </string>
<string> "coin 3" </string>
<string> "coin 4" </string>
@@ -92,24 +88,23 @@
<string> "coin 31 7 5" </string>
<string> "props" </string>
<string> "moving_platform" </string>
- <string> "Node2D" </string>
<string> "motion" </string>
<string> "cycle" </string>
<string> "moving_platform 2" </string>
<string> "moving_platform 3" </string>
<string> "seesaw" </string>
<string> "one_way_platform" </string>
- <string> "StaticBody2D" </string>
<string> "player" </string>
- <string> "RigidBody2D" </string>
<string> "music" </string>
- <string> "StreamPlayer" </string>
<string> "stream/stream" </string>
<string> "stream/play" </string>
<string> "stream/loop" </string>
<string> "stream/volume_db" </string>
<string> "stream/autoplay" </string>
<string> "stream/paused" </string>
+ <string> "stream/loop_restart_time" </string>
+ <string> "stream/buffering_ms" </string>
+ <string> "StreamPlayer" </string>
<string> "enemies" </string>
<string> "enemy 5" </string>
<string> "enemy 6" </string>
@@ -123,50 +118,39 @@
<string> "enemy 14" </string>
<string> "enemy 15" </string>
<string> "parallax_bg" </string>
- <string> "ParallaxBackground" </string>
+ <string> "scroll/ignore_camera_zoom" </string>
<string> "Label" </string>
<string> "margin/left" </string>
<string> "margin/top" </string>
<string> "margin/right" </string>
<string> "margin/bottom" </string>
- <string> "focus_neighbour/left" </string>
- <string> "focus_neighbour/top" </string>
- <string> "focus_neighbour/right" </string>
- <string> "focus_neighbour/bottom" </string>
<string> "focus/ignore_mouse" </string>
<string> "focus/stop_mouse" </string>
<string> "size_flags/horizontal" </string>
- <string> "size_flags/stretch_ratio" </string>
- <string> "range/min" </string>
- <string> "range/max" </string>
- <string> "range/step" </string>
- <string> "range/page" </string>
- <string> "range/value" </string>
- <string> "range/exp_edit" </string>
- <string> "rounded_values" </string>
<string> "text" </string>
- <string> "align" </string>
- <string> "valign" </string>
<string> "autowrap" </string>
- <string> "uppercase" </string>
<string> "percent_visible" </string>
+ <string> "lines_skipped" </string>
+ <string> "max_lines_visible" </string>
</string_array>
<string> "node_count" </string>
<int> 67 </int>
+ <string> "node_paths" </string>
+ <array len="0" shared="false">
+ </array>
<string> "nodes" </string>
- <int_array len="973"> -1, -1, 1, 0, -1, 2, 2, 0, 3, 1, 0, 0, 0, 5, 4, -1, 25, 2, 0, 6, 2, 7, 3, 8, 3, 9, 4, 10, 5, 11, 6, 12, 7, 13, 8, 14, 2, 15, 8, 16, 9, 17, 10, 18, 11, 19, 12, 20, 13, 21, 8, 22, 14, 23, 14, 24, 3, 25, 6, 26, 4, 27, 4, 28, 15, 3, 16, 0, 0, 0, 1, 29, -1, 1, 2, 0, 0, 2, 0, 31, 30, 17, 3, 2, 0, 10, 18, 3, 19, 0, 2, 0, 31, 32, 17, 3, 2, 0, 10, 20, 3, 19, 0, 2, 0, 31, 33, 17, 3, 2, 0, 10, 21, 3, 19, 0, 2, 0, 31, 34, 17, 3, 2, 0, 10, 22, 3, 19, 0, 2, 0, 31, 35, 17, 3, 2, 0, 10, 23, 3, 19, 0, 2, 0, 31, 36, 17, 3, 2, 0, 10, 24, 3, 19, 0, 2, 0, 31, 37, 17, 3, 2, 0, 10, 25, 3, 19, 0, 2, 0, 31, 38, 17, 3, 2, 0, 10, 26, 3, 19, 0, 2, 0, 31, 39, 17, 3, 2, 0, 10, 27, 3, 19, 0, 2, 0, 31, 40, 17, 3, 2, 0, 10, 28, 3, 19, 0, 2, 0, 31, 41, 17, 3, 2, 0, 10, 29, 3, 19, 0, 2, 0, 31, 42, 17, 3, 2, 0, 10, 30, 3, 19, 0, 2, 0, 31, 43, 17, 3, 2, 0, 10, 31, 3, 19, 0, 2, 0, 31, 44, 17, 3, 2, 0, 10, 32, 3, 19, 0, 2, 0, 31, 45, 17, 3, 2, 0, 10, 33, 3, 19, 0, 2, 0, 31, 46, 17, 3, 2, 0, 10, 34, 3, 19, 0, 2, 0, 31, 47, 17, 3, 2, 0, 10, 35, 3, 19, 0, 2, 0, 31, 48, 17, 3, 2, 0, 10, 36, 3, 19, 0, 2, 0, 31, 49, 17, 3, 2, 0, 10, 37, 3, 19, 0, 2, 0, 31, 50, 17, 3, 2, 0, 10, 38, 3, 19, 0, 2, 0, 31, 51, 17, 3, 2, 0, 10, 39, 3, 19, 0, 2, 0, 31, 52, 17, 3, 2, 0, 10, 40, 3, 19, 0, 2, 0, 31, 53, 17, 3, 2, 0, 10, 41, 3, 19, 0, 2, 0, 31, 54, 17, 3, 2, 0, 10, 42, 3, 19, 0, 2, 0, 31, 55, 17, 3, 2, 0, 10, 43, 3, 19, 0, 2, 0, 31, 56, 17, 3, 2, 0, 10, 44, 3, 19, 0, 2, 0, 31, 57, 17, 3, 2, 0, 10, 45, 3, 19, 0, 2, 0, 31, 58, 17, 3, 2, 0, 10, 46, 3, 19, 0, 2, 0, 31, 59, 17, 3, 2, 0, 10, 47, 3, 19, 0, 2, 0, 31, 60, 17, 3, 2, 0, 10, 48, 3, 19, 0, 2, 0, 31, 61, 17, 3, 2, 0, 10, 49, 3, 19, 0, 2, 0, 31, 62, 17, 3, 2, 0, 10, 50, 3, 19, 0, 2, 0, 31, 63, 17, 3, 2, 0, 10, 51, 3, 19, 0, 2, 0, 31, 64, 17, 3, 2, 0, 10, 52, 3, 19, 0, 2, 0, 31, 65, 17, 3, 2, 0, 10, 53, 3, 19, 0, 2, 0, 31, 66, 17, 3, 2, 0, 10, 54, 3, 19, 0, 2, 0, 31, 67, 17, 3, 2, 0, 10, 55, 3, 19, 0, 2, 0, 31, 68, 17, 3, 2, 0, 10, 56, 3, 19, 0, 2, 0, 31, 69, 17, 3, 2, 0, 10, 57, 3, 19, 0, 2, 0, 31, 70, 17, 3, 2, 0, 10, 58, 3, 19, 0, 2, 0, 31, 71, 17, 3, 2, 0, 10, 59, 3, 19, 0, 2, 0, 31, 72, 17, 3, 2, 0, 10, 60, 3, 19, 0, 0, 0, 1, 73, -1, 1, 2, 0, 0, 45, 0, 75, 74, 61, 5, 2, 0, 10, 62, 3, 63, 76, 64, 77, 65, 0, 45, 0, 75, 78, 61, 5, 2, 0, 10, 66, 3, 63, 76, 67, 77, 68, 0, 45, 0, 75, 79, 61, 5, 2, 0, 10, 69, 3, 63, 76, 70, 77, 68, 0, 45, 0, 75, 80, 71, 3, 2, 0, 10, 72, 3, 73, 0, 45, 0, 82, 81, 74, 3, 2, 0, 10, 75, 3, 76, 0, 0, 0, 84, 83, 77, 3, 2, 0, 10, 78, 3, 79, 0, 0, 0, 86, 85, -1, 7, 2, 0, 87, 80, 88, 14, 89, 2, 90, 81, 91, 2, 92, 14, 0, 0, 0, 1, 93, -1, 1, 2, 0, 0, 53, 0, 84, 94, 82, 3, 2, 0, 10, 83, 3, 84, 0, 53, 0, 84, 95, 82, 3, 2, 0, 10, 85, 3, 84, 0, 53, 0, 84, 96, 82, 3, 2, 0, 10, 86, 3, 84, 0, 53, 0, 84, 97, 82, 3, 2, 0, 10, 87, 3, 84, 0, 53, 0, 84, 98, 82, 3, 2, 0, 10, 88, 3, 84, 0, 53, 0, 84, 99, 82, 3, 2, 0, 10, 89, 3, 84, 0, 53, 0, 84, 100, 82, 3, 2, 0, 10, 90, 3, 84, 0, 53, 0, 84, 101, 82, 3, 2, 0, 10, 91, 3, 84, 0, 53, 0, 84, 102, 82, 3, 2, 0, 10, 92, 3, 84, 0, 53, 0, 84, 103, 82, 3, 2, 0, 10, 93, 3, 84, 0, 53, 0, 84, 104, 82, 3, 2, 0, 10, 94, 3, 84, 0, 0, 0, 106, 105, 95, 2, 2, 0, 3, 96, 0, 0, 0, 107, 107, -1, 30, 2, 0, 6, 2, 7, 3, 8, 3, 9, 4, 108, 97, 109, 98, 110, 99, 111, 100, 112, 0, 113, 0, 114, 0, 115, 0, 116, 2, 117, 2, 118, 13, 119, 3, 120, 6, 121, 101, 122, 3, 123, 102, 124, 6, 125, 14, 126, 14, 127, 103, 128, 8, 129, 8, 130, 2, 131, 14, 132, 104, 0 </int_array>
+ <int_array len="925"> -1, -1, 2, 0, -1, 1, 1, 0, 0, 0, 0, 18, 3, -1, 15, 4, 1, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 10, 1, 11, 7, 12, 7, 13, 8, 14, 9, 15, 10, 16, 10, 17, 11, 1, 12, 0, 0, 0, 2, 19, -1, 0, 0, 2, 0, 2147483647, 20, 13, 4, 21, 14, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 25, 13, 4, 21, 17, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 26, 13, 4, 21, 18, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 27, 13, 4, 21, 19, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 28, 13, 4, 21, 20, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 29, 13, 4, 21, 21, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 30, 13, 4, 21, 22, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 31, 13, 4, 21, 23, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 32, 13, 4, 21, 24, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 33, 13, 4, 21, 25, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 34, 13, 4, 21, 26, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 35, 13, 4, 21, 27, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 36, 13, 4, 21, 28, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 37, 13, 4, 21, 29, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 38, 13, 4, 21, 30, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 39, 13, 4, 21, 31, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 40, 13, 4, 21, 32, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 41, 13, 4, 21, 33, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 42, 13, 4, 21, 34, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 43, 13, 4, 21, 35, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 44, 13, 4, 21, 36, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 45, 13, 4, 21, 37, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 46, 13, 4, 21, 38, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 47, 13, 4, 21, 39, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 48, 13, 4, 21, 40, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 49, 13, 4, 21, 41, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 50, 13, 4, 21, 42, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 51, 13, 4, 21, 43, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 52, 13, 4, 21, 44, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 53, 13, 4, 21, 45, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 54, 13, 4, 21, 46, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 55, 13, 4, 21, 47, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 56, 13, 4, 21, 48, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 57, 13, 4, 21, 49, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 58, 13, 4, 21, 50, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 59, 13, 4, 21, 51, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 60, 13, 4, 21, 52, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 61, 13, 4, 21, 53, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 62, 13, 4, 21, 54, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 63, 13, 4, 21, 55, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 64, 13, 4, 21, 56, 22, 15, 23, 16, 24, 8, 0, 2, 0, 2147483647, 65, 13, 4, 21, 57, 22, 15, 23, 16, 24, 8, 0, 0, 0, 2, 66, -1, 0, 0, 45, 0, 2147483647, 67, 58, 3, 21, 59, 68, 60, 69, 61, 0, 45, 0, 2147483647, 70, 58, 3, 21, 62, 68, 63, 69, 64, 0, 45, 0, 2147483647, 71, 58, 3, 21, 65, 68, 66, 69, 64, 0, 45, 0, 2147483647, 72, 67, 1, 21, 68, 0, 45, 0, 2147483647, 73, 69, 1, 21, 70, 0, 0, 0, 2147483647, 74, 71, 1, 21, 72, 0, 0, 0, 84, 75, -1, 8, 76, 73, 77, 7, 78, 15, 79, 74, 80, 15, 81, 7, 82, 9, 83, 75, 0, 0, 0, 2, 85, -1, 0, 0, 53, 0, 2147483647, 86, 76, 1, 21, 77, 0, 53, 0, 2147483647, 87, 76, 1, 21, 78, 0, 53, 0, 2147483647, 88, 76, 1, 21, 79, 0, 53, 0, 2147483647, 89, 76, 1, 21, 80, 0, 53, 0, 2147483647, 90, 76, 1, 21, 81, 0, 53, 0, 2147483647, 91, 76, 1, 21, 82, 0, 53, 0, 2147483647, 92, 76, 1, 21, 83, 0, 53, 0, 2147483647, 93, 76, 1, 21, 84, 0, 53, 0, 2147483647, 94, 76, 1, 21, 85, 0, 53, 0, 2147483647, 95, 76, 1, 21, 86, 0, 53, 0, 2147483647, 96, 76, 1, 21, 87, 0, 0, 0, 2147483647, 97, 88, 1, 98, 7, 0, 0, 0, 99, 99, -1, 12, 100, 89, 101, 90, 102, 91, 103, 92, 104, 15, 105, 15, 106, 6, 107, 93, 108, 15, 109, 8, 110, 1, 111, 94, 0 </int_array>
<string> "variants" </string>
- <array len="105" shared="false">
- <node_path> "" </node_path>
+ <array len="95" shared="false">
<dictionary shared="false">
<string> "__editor_plugin_screen__" </string>
- <string> "2D" </string>
+ <string> "Script" </string>
<string> "__editor_plugin_states__" </string>
<dictionary shared="false">
<string> "2D" </string>
<dictionary shared="false">
<string> "ofs" </string>
- <vector2> 328.379, 822.226 </vector2>
+ <vector2> -70.6559, 735.599 </vector2>
<string> "snap_grid" </string>
<bool> False </bool>
<string> "snap_offset" </string>
@@ -186,7 +170,7 @@
<string> "snap_step" </string>
<vector2> 10, 10 </vector2>
<string> "zoom" </string>
- <real> 1.108032 </real>
+ <real> 0.663419 </real>
</dictionary>
<string> "3D" </string>
<dictionary shared="false">
@@ -280,17 +264,10 @@
<string> "znear" </string>
<real> 0.1 </real>
</dictionary>
- <string> "Script" </string>
+ <string> "Anim" </string>
<dictionary shared="false">
- <string> "current" </string>
- <int> 0 </int>
- <string> "sources" </string>
- <array len="4" shared="false">
- <string> "res://moving_platform.gd" </string>
- <string> "res://enemy.gd" </string>
- <string> "res://player.gd" </string>
- <string> "res://coin.gd" </string>
- </array>
+ <string> "visible" </string>
+ <bool> False </bool>
</dictionary>
</dictionary>
<string> "__editor_run_settings__" </string>
@@ -301,136 +278,25 @@
<int> 0 </int>
</dictionary>
</dictionary>
- <bool> True </bool>
- <real> 1 </real>
- <int> 1 </int>
- <vector2> 0, 0 </vector2>
- <real> 0 </real>
- <vector2> 1, 1 </vector2>
<int> 0 </int>
- <resource resource_type="TileSet" path="res://tileset.xml"> </resource>
+ <resource external="0"> </resource>
<vector2> 64, 64 </vector2>
<int> 8 </int>
<matrix32> 1, 0, 0, 1, 0, 0 </matrix32>
<int> 2 </int>
<bool> False </bool>
+ <real> 1 </real>
+ <real> 0 </real>
+ <int> 1 </int>
<int_array len="2008"> 0, 2, 70, 536870914, 71, 10, 72, 10, 73, 10, 74, 10, 75, 10, 76, 10, 77, 10, 78, 10, 65536, 2, 65606, 536870914, 65607, 10, 65608, 10, 65609, 10, 65610, 10, 65611, 10, 65612, 10, 65613, 10, 65614, 10, 131072, 2, 131142, 536870914, 131143, 10, 131144, 10, 131145, 10, 131146, 10, 131147, 10, 131148, 10, 131149, 10, 131150, 10, 196608, 2, 196626, 9, 196678, 536870914, 196679, 10, 196680, 10, 196681, 10, 196682, 10, 196683, 10, 196684, 10, 196685, 10, 196686, 10, 262144, 2, 262162, 8, 262214, 536870914, 262215, 10, 262216, 10, 262217, 10, 262218, 10, 262219, 10, 262220, 10, 262221, 10, 262222, 10, 327680, 2, 327697, 536870921, 327698, 7, 327733, 9, 327750, 536870914, 327751, 10, 327752, 10, 327753, 10, 327754, 10, 327755, 10, 327756, 10, 327757, 10, 327758, 10, 393216, 2, 393233, 536870920, 393234, 7, 393257, 9, 393269, 7, 393286, 536870914, 393287, 10, 393288, 10, 393289, 10, 393290, 10, 393291, 10, 393292, 10, 393293, 10, 393294, 10, 458752, 2, 458769, 7, 458770, 8, 458790, 9, 458793, 8, 458805, 8, 458822, 536870914, 458823, 10, 458824, 10, 458825, 10, 458826, 10, 458827, 10, 458828, 10, 458829, 10, 458830, 10, 524288, 4, 524289, 1, 524304, 536870913, 524305, 536870918, 524306, 6, 524307, 5, 524308, 1, 524326, 8, 524329, 7, 524341, 7, 524358, 536870914, 524359, 10, 524360, 10, 524361, 10, 524362, 10, 524363, 10, 524364, 10, 524365, 10, 524366, 10, 589824, 10, 589825, 13, 589840, 536870914, 589841, 10, 589842, 10, 589843, 10, 589844, 2, 589862, 7, 589865, 7, 589876, 536870913, 589877, 6, 589878, 1, 589894, 536870914, 589895, 10, 589896, 10, 589897, 10, 589898, 10, 589899, 10, 589900, 10, 589901, 10, 589902, 10, 655360, 2, 655376, 536870914, 655377, 10, 655378, 10, 655379, 10, 655380, 2, 655398, 7, 655401, 8, 655412, 536870925, 655413, 11, 655414, 13, 655430, 536870914, 655431, 10, 655432, 10, 655433, 10, 655434, 10, 655435, 10, 655436, 10, 655437, 10, 655438, 10, 720896, 2, 720912, 536870914, 720913, 10, 720914, 10, 720915, 10, 720916, 2, 720934, 8, 720937, 7, 720958, 536870913, 720959, 5, 720960, 536870917, 720961, 5, 720962, 5, 720963, 536870917, 720964, 5, 720965, 0, 720966, 536870916, 720967, 10, 720968, 10, 720969, 10, 720970, 10, 720971, 10, 720972, 10, 720973, 10, 720974, 10, 786432, 2, 786437, 9, 786448, 536870914, 786449, 10, 786450, 10, 786451, 10, 786452, 2, 786464, 536870913, 786465, 1, 786470, 7, 786473, 7, 786474, 536870924, 786475, 1, 786494, 536870914, 786495, 10, 786496, 10, 786497, 10, 786498, 10, 786499, 10, 786500, 10, 786501, 10, 786502, 10, 786503, 10, 786504, 10, 786505, 10, 786506, 10, 786507, 10, 786508, 10, 786509, 10, 851968, 2, 851973, 7, 851984, 536870914, 851985, 10, 851986, 10, 851987, 10, 851988, 2, 851996, 536870913, 851997, 1, 852000, 536870914, 852001, 3, 852006, 7, 852009, 536870913, 852011, 2, 852030, 536870914, 852031, 10, 852032, 10, 852033, 10, 852034, 10, 852035, 10, 852036, 10, 852037, 10, 852038, 10, 852039, 10, 852040, 10, 852041, 10, 852042, 10, 852043, 10, 852044, 10, 852045, 10, 917504, 2, 917506, 9, 917509, 7, 917512, 536870921, 917520, 536870925, 917521, 11, 917522, 11, 917523, 11, 917524, 13, 917532, 536870925, 917533, 13, 917536, 536870914, 917537, 4, 917538, 1, 917540, 536870913, 917541, 0, 917542, 1, 917545, 536870914, 917546, 10, 917547, 4, 917548, 1, 917566, 536870914, 917567, 10, 917568, 10, 917569, 10, 917570, 10, 917571, 10, 917572, 10, 917573, 10, 917574, 10, 917575, 10, 917576, 10, 917577, 10, 917578, 10, 917579, 10, 917580, 10, 917581, 10, 983040, 2, 983042, 7, 983045, 7, 983048, 536870920, 983050, 536870913, 983051, 0, 983052, 1, 983064, 536870913, 983065, 1, 983072, 536870914, 983073, 10, 983074, 4, 983075, 0, 983076, 536870916, 983077, 10, 983078, 4, 983079, 536870912, 983080, 536870912, 983081, 536870916, 983082, 10, 983083, 10, 983084, 2, 983095, 9, 983102, 536870914, 983103, 10, 983104, 10, 983105, 10, 983106, 10, 983107, 10, 983108, 10, 983109, 10, 983110, 10, 983111, 10, 983112, 10, 983113, 10, 983114, 10, 983115, 10, 983116, 10, 983117, 10, 1048576, 2, 1048578, 8, 1048581, 8, 1048584, 536870919, 1048586, 536870914, 1048587, 536870922, 1048588, 2, 1048600, 536870925, 1048601, 13, 1048604, 9, 1048608, 536870925, 1048609, 536870923, 1048610, 536870923, 1048611, 536870923, 1048612, 10, 1048613, 10, 1048614, 10, 1048615, 10, 1048616, 10, 1048617, 10, 1048618, 10, 1048619, 10, 1048620, 4, 1048621, 1, 1048630, 536870921, 1048631, 8, 1048638, 536870914, 1048639, 10, 1048640, 10, 1048641, 10, 1048642, 10, 1048643, 10, 1048644, 10, 1048645, 10, 1048646, 10, 1048647, 10, 1048648, 10, 1048649, 10, 1048650, 10, 1048651, 10, 1048652, 10, 1048653, 10, 1114112, 4, 1114113, 0, 1114114, 6, 1114115, 0, 1114116, 0, 1114117, 6, 1114118, 1, 1114120, 536870920, 1114122, 536870925, 1114123, 11, 1114124, 13, 1114128, 536870913, 1114129, 5, 1114130, 536870917, 1114131, 5, 1114132, 0, 1114133, 1, 1114140, 7, 1114141, 536870921, 1114148, 536870914, 1114149, 10, 1114150, 10, 1114151, 10, 1114152, 10, 1114153, 10, 1114154, 10, 1114155, 10, 1114156, 10, 1114157, 2, 1114166, 536870920, 1114167, 8, 1114174, 536870914, 1114175, 10, 1114176, 10, 1114177, 10, 1114178, 10, 1114179, 10, 1114180, 10, 1114181, 10, 1114182, 10, 1114183, 10, 1114184, 10, 1114185, 10, 1114186, 10, 1114187, 10, 1114188, 10, 1179648, 10, 1179649, 10, 1179650, 10, 1179651, 10, 1179652, 10, 1179653, 10, 1179654, 2, 1179656, 536870919, 1179663, 536870915, 1179665, 10, 1179666, 10, 1179667, 10, 1179668, 10, 1179669, 4, 1179670, 12, 1179675, 9, 1179676, 8, 1179677, 8, 1179684, 536870914, 1179685, 10, 1179686, 10, 1179687, 10, 1179688, 10, 1179689, 10, 1179690, 10, 1179691, 10, 1179692, 10, 1179693, 4, 1179694, 1, 1179701, 9, 1179702, 536870919, 1179703, 7, 1179710, 536870914, 1179711, 10, 1179712, 10, 1179713, 10, 1179714, 10, 1179715, 10, 1179716, 10, 1179717, 10, 1179718, 10, 1179719, 10, 1179720, 10, 1179721, 10, 1179722, 10, 1245184, 10, 1245185, 10, 1245186, 10, 1245187, 10, 1245188, 10, 1245189, 10, 1245190, 2, 1245192, 536870919, 1245199, 536870913, 1245200, 536870916, 1245201, 10, 1245202, 10, 1245203, 10, 1245204, 10, 1245205, 10, 1245207, 1, 1245211, 7, 1245212, 7, 1245213, 536870920, 1245220, 536870914, 1245221, 10, 1245222, 10, 1245223, 10, 1245224, 10, 1245225, 10, 1245226, 10, 1245227, 10, 1245228, 10, 1245229, 10, 1245230, 2, 1245237, 8, 1245238, 536870919, 1245239, 8, 1245240, 536870921, 1245246, 536870914, 1245247, 10, 1245248, 10, 1245249, 10, 1245250, 10, 1245251, 10, 1245252, 10, 1245253, 10, 1245254, 10, 1245255, 10, 1245256, 10, 1245257, 10, 1245258, 10, 1310720, 10, 1310721, 10, 1310722, 10, 1310723, 10, 1310724, 10, 1310725, 10, 1310726, 2, 1310728, 536870920, 1310730, 536870913, 1310731, 1, 1310734, 536870913, 1310735, 536870916, 1310736, 10, 1310737, 10, 1310738, 10, 1310739, 10, 1310740, 10, 1310741, 10, 1310742, 10, 1310743, 4, 1310744, 1, 1310747, 8, 1310748, 7, 1310749, 536870919, 1310756, 536870914, 1310757, 10, 1310758, 10, 1310759, 10, 1310760, 10, 1310761, 10, 1310762, 10, 1310763, 10, 1310764, 10, 1310765, 10, 1310766, 4, 1310767, 5, 1310768, 12, 1310773, 7, 1310774, 536870919, 1310775, 7, 1310776, 536870919, 1310782, 536870914, 1310783, 10, 1310784, 10, 1310785, 10, 1310786, 10, 1310787, 10, 1310788, 10, 1310789, 10, 1310790, 10, 1310791, 10, 1310792, 10, 1310793, 10, 1376256, 10, 1376257, 10, 1376258, 10, 1376259, 10, 1376260, 10, 1376261, 10, 1376262, 4, 1376263, 0, 1376264, 0, 1376265, 0, 1376266, 536870916, 1376267, 4, 1376268, 0, 1376269, 0, 1376270, 536870916, 1376271, 10, 1376272, 10, 1376273, 10, 1376274, 10, 1376275, 10, 1376276, 10, 1376277, 10, 1376278, 10, 1376279, 10, 1376280, 4, 1376281, 12, 1376283, 8, 1376284, 8, 1376285, 536870920, 1376287, 536870924, 1376288, 0, 1376289, 5, 1376290, 536870917, 1376291, 0, 1376292, 536870916, 1376293, 10, 1376294, 10, 1376295, 10, 1376296, 10, 1376297, 10, 1376298, 10, 1376299, 10, 1376300, 10, 1376301, 10, 1376302, 10, 1376303, 10, 1376305, 12, 1376309, 7, 1376310, 536870920, 1376311, 7, 1376312, 536870920, 1376318, 536870914, 1376319, 10, 1376320, 10, 1376321, 10, 1376322, 10, 1376323, 10, 1376324, 10, 1376325, 10, 1376326, 10, 1376327, 10, 1376328, 10, 1441792, 10, 1441793, 10, 1441794, 10, 1441795, 10, 1441796, 10, 1441797, 10, 1441798, 10, 1441799, 10, 1441800, 10, 1441801, 10, 1441802, 10, 1441803, 10, 1441804, 10, 1441805, 10, 1441806, 10, 1441807, 10, 1441808, 10, 1441809, 10, 1441810, 10, 1441811, 10, 1441812, 10, 1441813, 10, 1441814, 10, 1441815, 10, 1441816, 10, 1441818, 0, 1441819, 6, 1441820, 6, 1441821, 536870918, 1441822, 5, 1441824, 10, 1441825, 10, 1441826, 10, 1441827, 10, 1441828, 10, 1441829, 10, 1441830, 10, 1441831, 10, 1441832, 10, 1441833, 10, 1441834, 10, 1441835, 10, 1441836, 10, 1441837, 10, 1441838, 10, 1441839, 10, 1441840, 10, 1441842, 0, 1441843, 0, 1441844, 0, 1441845, 6, 1441846, 536870918, 1441847, 6, 1441848, 536870918, 1441849, 0, 1441850, 5, 1441851, 536870917, 1441852, 5, 1441853, 0, 1441854, 536870916, 1441855, 10, 1441856, 10, 1441857, 10, 1441858, 10, 1441859, 10, 1441860, 10, 1441861, 10, 1441862, 10, 1441863, 10, 1507328, 10, 1507329, 10, 1507330, 10, 1507331, 10, 1507332, 10, 1507333, 10, 1507334, 10, 1507335, 10, 1507336, 10, 1507337, 10, 1507338, 10, 1507339, 10, 1507340, 10, 1507341, 10, 1507342, 10, 1507343, 10, 1507344, 10, 1507345, 10, 1507346, 10, 1507347, 10, 1507348, 10, 1507349, 10, 1507350, 10, 1507351, 10, 1507352, 10, 1507353, 10, 1507354, 10, 1507355, 10, 1507356, 10, 1507357, 10, 1507358, 10, 1507359, 10, 1507360, 10, 1507361, 10, 1507362, 10, 1507363, 10, 1507364, 10, 1507365, 10, 1507366, 10, 1507367, 10, 1507368, 10, 1507369, 10, 1507370, 10, 1507371, 10, 1507372, 10, 1507373, 10, 1507374, 10, 1507375, 10, 1507376, 10, 1507377, 10, 1507378, 10, 1507379, 10, 1507380, 10, 1507381, 10, 1507382, 10, 1507383, 10, 1507384, 10, 1507385, 10, 1507386, 10, 1507387, 10, 1507388, 10, 1507389, 10, 1507390, 10, 1507391, 10, 1507392, 10, 1507393, 10, 1507394, 10, 1507395, 10, 1507396, 10, 1507397, 10, 1507398, 10, 1507399, 10, 1572864, 10, 1572865, 10, 1572866, 10, 1572867, 10, 1572868, 10, 1572869, 10, 1572870, 10, 1572871, 10, 1572872, 10, 1572873, 10, 1572874, 10, 1572875, 10, 1572876, 10, 1572877, 10, 1572878, 10, 1572879, 10, 1572880, 10, 1572881, 10, 1572882, 10, 1572883, 10, 1572884, 10, 1572885, 10, 1572886, 10, 1572887, 10, 1572888, 10, 1572889, 10, 1572890, 10, 1572891, 10, 1572892, 10, 1572893, 10, 1572894, 10, 1572895, 10, 1572896, 10, 1572897, 10, 1572898, 10, 1572899, 10, 1572900, 10, 1572901, 10, 1572902, 10, 1572903, 10, 1572904, 10, 1572905, 10, 1572906, 10, 1572907, 10, 1572908, 10, 1572909, 10, 1572910, 10, 1572911, 10, 1572912, 10, 1572913, 10, 1572914, 10, 1572915, 10, 1572916, 10, 1572917, 10, 1572918, 10, 1572919, 10, 1572920, 10, 1572921, 10, 1572922, 10, 1572923, 10, 1572924, 10, 1572925, 10, 1572926, 10, 1572927, 10, 1572928, 10, 1572929, 10, 1572930, 10, 1572931, 10, 1572932, 10, 1572933, 10, 1572934, 10, 1572935, 10, 1638400, 10, 1638401, 10, 1638402, 10, 1638403, 10, 1638404, 10, 1638405, 10, 1638406, 10, 1638407, 10, 1638408, 10, 1638409, 10, 1638410, 10, 1638411, 10, 1638412, 10, 1638413, 10, 1638414, 10, 1638415, 10, 1638416, 10, 1638417, 10, 1638418, 10, 1638419, 10, 1638420, 10, 1638421, 10, 1638422, 10, 1638423, 10, 1638424, 10, 1638425, 10, 1638426, 10, 1638427, 10, 1638428, 10, 1638429, 10, 1638430, 10, 1638431, 10, 1638432, 10, 1638433, 10, 1638434, 10, 1638435, 10, 1638436, 10, 1638437, 10, 1638438, 10, 1638439, 10, 1638440, 10, 1638441, 10, 1638442, 10, 1638443, 10, 1638444, 10, 1638445, 10, 1638446, 10, 1638447, 10, 1638448, 10, 1638449, 10, 1638450, 10, 1638451, 10, 1638452, 10, 1638453, 10, 1638454, 10, 1638455, 10, 1638456, 10, 1638457, 10, 1638458, 10, 1638459, 10, 1638460, 10, 1638461, 10, 1638462, 10, 1638463, 10, 1638464, 10, 1638465, 10, 1638466, 10, 1638467, 10, 1638468, 10, 1638469, 10, 1638470, 10, 1638471, 10, 1703952, 10, 1703953, 10, 1703954, 10, 1703955, 10, 1703956, 10, 1703957, 10, 1703958, 10, 1703959, 10, 1703960, 10, 1703961, 10, 1703962, 10, 1703963, 10, 1703964, 10, 1703965, 10, 1703966, 10, 1703967, 10, 1703968, 10, 1703969, 10, 1703970, 10, 1703971, 10, 1703972, 10, 1703973, 10, 1703974, 10, 1703975, 10, 1703976, 10, 1703977, 10, 1703978, 10, 1703979, 10, 1703980, 10, 1703981, 10, 1703982, 10, 1703983, 10, 1703984, 10, 1703985, 10, 1703986, 10, 1703987, 10, 1703988, 10, 1703989, 10, 1703990, 10, 1703991, 10, 1703992, 10, 1703993, 10, 1703994, 10, 1703995, 10, 1703996, 10, 1703997, 10, 1703998, 10, 1703999, 10, 1704000, 10, 1704001, 10, 1704002, 10, 1704003, 10, 1704004, 10, 1704005, 10, 1704006, 10, 1704007, 10, 1769488, 10, 1769489, 10, 1769490, 10, 1769491, 10, 1769492, 10, 1769493, 10, 1769494, 10, 1769495, 10, 1769496, 10, 1769497, 10, 1769498, 10, 1769499, 10, 1769500, 10, 1769501, 10, 1769502, 10, 1769503, 10, 1769504, 10, 1769505, 10, 1769506, 10, 1769507, 10, 1769508, 10, 1769509, 10, 1769510, 10, 1769511, 10, 1769512, 10, 1769513, 10, 1769514, 10, 1769515, 10, 1769516, 10, 1769517, 10, 1769518, 10, 1769519, 10, 1769520, 10, 1769521, 10, 1769522, 10, 1769523, 10, 1769524, 10, 1769525, 10, 1769526, 10, 1769527, 10, 1769528, 10, 1769529, 10, 1769530, 10, 1769531, 10, 1769532, 10, 1769533, 10, 1769534, 10, 1769535, 10, 1769536, 10, 1769537, 10, 1769538, 10, 1769539, 10, 1769540, 10, 1769541, 10 </int_array>
<dictionary shared="false">
<string> "_edit_lock_" </string>
<bool> True </bool>
</dictionary>
- <resource resource_type="PackedScene" path="res://coin.xml"> </resource>
+ <resource external="1"> </resource>
<vector2> 672, 1179 </vector2>
- <dictionary shared="false">
- <string> "__editor_plugin_screen__" </string>
- <string> "2D" </string>
- <string> "__editor_plugin_states__" </string>
- <dictionary shared="false">
- <string> "2D" </string>
- <dictionary shared="false">
- <string> "ofs" </string>
- <vector2> -34.3697, -21.6562 </vector2>
- <string> "pixel_snap" </string>
- <bool> False </bool>
- <string> "zoom" </string>
- <real> 3.794776 </real>
- </dictionary>
- <string> "3D" </string>
- <dictionary shared="false">
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "fov" </string>
- <real> 45 </real>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "viewports" </string>
- <array len="4" shared="false">
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- </dictionary>
- </array>
- <string> "zfar" </string>
- <real> 500 </real>
- <string> "znear" </string>
- <real> 0.1 </real>
- </dictionary>
- <string> "Script" </string>
- <dictionary shared="false">
- <string> "current" </string>
- <int> 2 </int>
- <string> "sources" </string>
- <array len="3" shared="false">
- <string> "res://enemy.gd" </string>
- <string> "res://player.gd" </string>
- <string> "res://coin.gd" </string>
- </array>
- </dictionary>
- </dictionary>
- <string> "__editor_run_settings__" </string>
- <dictionary shared="false">
- <string> "custom_args" </string>
- <string> "-l $scene" </string>
- <string> "run_mode" </string>
- <int> 0 </int>
- </dictionary>
- </dictionary>
+ <bool> True </bool>
+ <real> 0.1 </real>
<vector2> 704, 1179 </vector2>
<vector2> 736, 1179 </vector2>
<vector2> 1120, 992 </vector2>
@@ -472,119 +338,8 @@
<vector2> 4300.75, 541.058 </vector2>
<vector2> 4236.75, 541.058 </vector2>
<vector2> 4172.75, 541.058 </vector2>
- <resource resource_type="PackedScene" path="res://moving_platform.xml"> </resource>
+ <resource external="2"> </resource>
<vector2> 1451.86, 742.969 </vector2>
- <dictionary shared="false">
- <string> "__editor_plugin_screen__" </string>
- <string> "2D" </string>
- <string> "__editor_plugin_states__" </string>
- <dictionary shared="false">
- <string> "2D" </string>
- <dictionary shared="false">
- <string> "ofs" </string>
- <vector2> -210.652, -172.81 </vector2>
- <string> "pixel_snap" </string>
- <bool> False </bool>
- <string> "zoom" </string>
- <real> 1.360373 </real>
- </dictionary>
- <string> "3D" </string>
- <dictionary shared="false">
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "fov" </string>
- <real> 400 </real>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "viewports" </string>
- <array len="4" shared="false">
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- </dictionary>
- </array>
- <string> "zfar" </string>
- <real> 500 </real>
- <string> "znear" </string>
- <real> 0.1 </real>
- </dictionary>
- <string> "Script" </string>
- <dictionary shared="false">
- <string> "current" </string>
- <int> 0 </int>
- <string> "sources" </string>
- <array len="4" shared="false">
- <string> "res://moving_platform.gd" </string>
- <string> "res://enemy.gd" </string>
- <string> "res://player.gd" </string>
- <string> "res://coin.gd" </string>
- </array>
- </dictionary>
- </dictionary>
- <string> "__editor_run_settings__" </string>
- <dictionary shared="false">
- <string> "custom_args" </string>
- <string> "-l $scene" </string>
- <string> "run_mode" </string>
- <int> 0 </int>
- </dictionary>
- </dictionary>
<vector2> 0, 140 </vector2>
<real> 5 </real>
<vector2> 624.824, 545.544 </vector2>
@@ -592,482 +347,17 @@
<real> 10 </real>
<vector2> 3419.86, 739.662 </vector2>
<vector2> 450, 0 </vector2>
- <resource resource_type="PackedScene" path="res://seesaw.xml"> </resource>
+ <resource external="3"> </resource>
<vector2> 2402.79, 849.52 </vector2>
- <dictionary shared="false">
- <string> "__editor_plugin_screen__" </string>
- <string> "2D" </string>
- <string> "__editor_plugin_states__" </string>
- <dictionary shared="false">
- <string> "2D" </string>
- <dictionary shared="false">
- <string> "ofs" </string>
- <vector2> -116.979, -109.897 </vector2>
- <string> "pixel_snap" </string>
- <bool> False </bool>
- <string> "zoom" </string>
- <real> 2.050547 </real>
- </dictionary>
- <string> "3D" </string>
- <dictionary shared="false">
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "fov" </string>
- <real> 400 </real>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "viewports" </string>
- <array len="4" shared="false">
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- </dictionary>
- </array>
- <string> "zfar" </string>
- <real> 500 </real>
- <string> "znear" </string>
- <real> 0.1 </real>
- </dictionary>
- </dictionary>
- <string> "__editor_run_settings__" </string>
- <dictionary shared="false">
- <string> "custom_args" </string>
- <string> "-l $scene" </string>
- <string> "run_mode" </string>
- <int> 0 </int>
- </dictionary>
- </dictionary>
- <resource resource_type="PackedScene" path="res://one_way_platform.xml"> </resource>
+ <resource external="4"> </resource>
<vector2> 927.698, 1120.81 </vector2>
- <dictionary shared="false">
- <string> "__editor_plugin_screen__" </string>
- <string> "2D" </string>
- <string> "__editor_plugin_states__" </string>
- <dictionary shared="false">
- <string> "2D" </string>
- <dictionary shared="false">
- <string> "ofs" </string>
- <vector2> -133.699, -110.553 </vector2>
- <string> "snap_grid" </string>
- <bool> False </bool>
- <string> "snap_offset" </string>
- <vector2> 0, 0 </vector2>
- <string> "snap_pixel" </string>
- <bool> False </bool>
- <string> "snap_relative" </string>
- <bool> False </bool>
- <string> "snap_rotation" </string>
- <bool> False </bool>
- <string> "snap_rotation_offset" </string>
- <real> 0 </real>
- <string> "snap_rotation_step" </string>
- <real> 0.261799 </real>
- <string> "snap_show_grid" </string>
- <bool> False </bool>
- <string> "snap_step" </string>
- <vector2> 10, 10 </vector2>
- <string> "zoom" </string>
- <real> 2.050546 </real>
- </dictionary>
- <string> "3D" </string>
- <dictionary shared="false">
- <string> "ambient_light_color" </string>
- <color> 0.15, 0.15, 0.15, 1 </color>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "default_srgb" </string>
- <bool> False </bool>
- <string> "deflight_rot_x" </string>
- <real> 0.942478 </real>
- <string> "deflight_rot_y" </string>
- <real> 0.628319 </real>
- <string> "fov" </string>
- <real> 45 </real>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "viewports" </string>
- <array len="4" shared="false">
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "listener" </string>
- <bool> True </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "listener" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "listener" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "listener" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- </dictionary>
- </array>
- <string> "zfar" </string>
- <real> 500 </real>
- <string> "znear" </string>
- <real> 0.1 </real>
- </dictionary>
- </dictionary>
- <string> "__editor_run_settings__" </string>
- <dictionary shared="false">
- <string> "custom_args" </string>
- <string> "-l $scene" </string>
- <string> "run_mode" </string>
- <int> 0 </int>
- </dictionary>
- </dictionary>
- <resource resource_type="PackedScene" path="res://player.xml"> </resource>
+ <resource external="5"> </resource>
<vector2> 251.684, 1045.6 </vector2>
- <dictionary shared="false">
- <string> "__editor_plugin_screen__" </string>
- <string> "Script" </string>
- <string> "__editor_plugin_states__" </string>
- <dictionary shared="false">
- <string> "2D" </string>
- <dictionary shared="false">
- <string> "ofs" </string>
- <vector2> -181.946, -86.2812 </vector2>
- <string> "pixel_snap" </string>
- <bool> False </bool>
- <string> "snap" </string>
- <int> 10 </int>
- <string> "use_snap" </string>
- <bool> False </bool>
- <string> "zoom" </string>
- <real> 2.272073 </real>
- </dictionary>
- <string> "3D" </string>
- <dictionary shared="false">
- <string> "ambient_light_color" </string>
- <color> 0.15, 0.15, 0.15, 1 </color>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "default_srgb" </string>
- <bool> False </bool>
- <string> "deflight_rot_x" </string>
- <real> 0.942478 </real>
- <string> "deflight_rot_y" </string>
- <real> 0.628319 </real>
- <string> "fov" </string>
- <real> 45 </real>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "viewports" </string>
- <array len="4" shared="false">
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "listener" </string>
- <bool> True </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "listener" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "listener" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "listener" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- </dictionary>
- </array>
- <string> "zfar" </string>
- <real> 500 </real>
- <string> "znear" </string>
- <real> 0.1 </real>
- </dictionary>
- <string> "Script" </string>
- <dictionary shared="false">
- <string> "current" </string>
- <int> 0 </int>
- <string> "sources" </string>
- <array len="1" shared="false">
- <string> "res://player.gd" </string>
- </array>
- </dictionary>
- </dictionary>
- <string> "__editor_run_settings__" </string>
- <dictionary shared="false">
- <string> "custom_args" </string>
- <string> "-l $scene" </string>
- <string> "run_mode" </string>
- <int> 0 </int>
- </dictionary>
- </dictionary>
- <resource resource_type="AudioStream" path="res://music.ogg"> </resource>
+ <resource external="6"> </resource>
<real> 2 </real>
- <resource resource_type="PackedScene" path="res://enemy.xml"> </resource>
+ <int> 500 </int>
+ <resource external="7"> </resource>
<vector2> 834.664, 1309.6 </vector2>
- <dictionary shared="false">
- <string> "__editor_plugin_screen__" </string>
- <string> "2D" </string>
- <string> "__editor_plugin_states__" </string>
- <dictionary shared="false">
- <string> "2D" </string>
- <dictionary shared="false">
- <string> "ofs" </string>
- <vector2> -227.625, -197.9 </vector2>
- <string> "pixel_snap" </string>
- <bool> False </bool>
- <string> "zoom" </string>
- <real> 1.108033 </real>
- </dictionary>
- <string> "3D" </string>
- <dictionary shared="false">
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "fov" </string>
- <real> 45 </real>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "viewports" </string>
- <array len="4" shared="false">
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- </dictionary>
- </array>
- <string> "zfar" </string>
- <real> 500 </real>
- <string> "znear" </string>
- <real> 0.1 </real>
- </dictionary>
- <string> "Script" </string>
- <dictionary shared="false">
- <string> "current" </string>
- <int> 0 </int>
- <string> "sources" </string>
- <array len="1" shared="false">
- <string> "res://enemy.gd" </string>
- </array>
- </dictionary>
- </dictionary>
- <string> "__editor_run_settings__" </string>
- <dictionary shared="false">
- <string> "custom_args" </string>
- <string> "-l $scene" </string>
- <string> "run_mode" </string>
- <int> 0 </int>
- </dictionary>
- </dictionary>
<vector2> 707.665, 1225.05 </vector2>
<vector2> 1125.21, 1053.06 </vector2>
<vector2> 1292.11, 1059.24 </vector2>
@@ -1078,79 +368,16 @@
<vector2> 3429.73, 540.865 </vector2>
<vector2> 3546.2, 1356.19 </vector2>
<vector2> 2406.63, 815.115 </vector2>
- <resource resource_type="PackedScene" path="res://parallax_bg.xml"> </resource>
- <dictionary shared="false">
- <string> "__editor_plugin_screen__" </string>
- <string> "2D" </string>
- <string> "__editor_plugin_states__" </string>
- <dictionary shared="false">
- <string> "2D" </string>
- <dictionary shared="false">
- <string> "ofs" </string>
- <vector2> -5, -25 </vector2>
- <string> "zoom" </string>
- <real> 1 </real>
- </dictionary>
- <string> "3D" </string>
- <dictionary shared="false">
- <string> "fov" </string>
- <real> 45 </real>
- <string> "window_0" </string>
- <dictionary shared="false">
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "distance" </string>
- <real> 4 </real>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
- <string> "x_rot" </string>
- <real> 0.337 </real>
- <string> "y_rot" </string>
- <real> -0.575 </real>
- </dictionary>
- <string> "window_mode" </string>
- <int> 0 </int>
- <string> "zfar" </string>
- <real> 500 </real>
- <string> "znear" </string>
- <real> 0.1 </real>
- </dictionary>
- <string> "Script" </string>
- <dictionary shared="false">
- <string> "current" </string>
- <int> 0 </int>
- <string> "sources" </string>
- <array len="4" shared="false">
- <string> "res://moving_platform.gd" </string>
- <string> "res://enemy.gd" </string>
- <string> "res://player.gd" </string>
- <string> "res://coin.gd" </string>
- </array>
- </dictionary>
- </dictionary>
- <string> "__editor_run_settings__" </string>
- <dictionary shared="false">
- <string> "custom_args" </string>
- <string> "-l $scene" </string>
- <string> "run_mode" </string>
- <int> 0 </int>
- </dictionary>
- </dictionary>
+ <resource external="8"> </resource>
<real> 12 </real>
<real> -202 </real>
<real> 358 </real>
<real> -10 </real>
- <real> 7 </real>
- <real> 14.769231 </real>
<string> "This is a simple demo on how to make a platformer game with Godot.&quot;This version uses physics and the 2D physics engine for motion and collision.&quot;&quot;The demo also shows the benefits of using the scene system, where coins,&quot;enemies and the player are edited separatedly and instanced in the stage.&quot;&quot;To edit the base tiles for the tileset, open the tileset_edit.xml file and follow &quot;instructions.&quot;" </string>
- <real> -1 </real>
+ <int> -1 </int>
</array>
<string> "version" </string>
- <int> 1 </int>
+ <int> 2 </int>
</dictionary>
</main_resource>
diff --git a/demos/2d/platformer/tiles_demo.png.flags b/demos/2d/platformer/tiles_demo.png.flags
new file mode 100644
index 0000000000..efb2b8ce5f
--- /dev/null
+++ b/demos/2d/platformer/tiles_demo.png.flags
@@ -0,0 +1 @@
+filter=false
diff --git a/demos/2d/platformer/tileset_edit.xml b/demos/2d/platformer/tileset_edit.xml
index db289433ab..3ae9f1bd2a 100644
--- a/demos/2d/platformer/tileset_edit.xml
+++ b/demos/2d/platformer/tileset_edit.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="14" version="1.0" version_name="Godot Engine v1.0.stable.custom_build">
- <ext_resource path="res://tiles_demo.png" type="Texture"></ext_resource>
+<resource_file type="PackedScene" subresource_count="14" version="2.0" version_name="Godot Engine v2.0.alpha.custom_build">
+ <ext_resource path="res://tiles_demo.png" type="Texture" index="0"></ext_resource>
<resource type="ConvexPolygonShape2D" path="local://1">
<real name="custom_solver_bias"> 0 </real>
<vector2_array name="points" len="4"> -32, -24, 32, -24, 32, 32, -32, 32 </vector2_array>
@@ -63,48 +63,41 @@
</resource>
<main_resource>
<dictionary name="_bundled" shared="false">
+ <string> "conn_count" </string>
+ <int> 0 </int>
+ <string> "conns" </string>
+ <int_array len="0"> </int_array>
+ <string> "editable_instances" </string>
+ <array len="0" shared="false">
+ </array>
<string> "names" </string>
- <string_array len="77">
+ <string_array len="49">
<string> "Node" </string>
- <string> "_import_path" </string>
<string> "__meta__" </string>
<string> "floor" </string>
- <string> "Sprite" </string>
- <string> "visibility/visible" </string>
- <string> "visibility/opacity" </string>
- <string> "visibility/self_opacity" </string>
- <string> "transform/pos" </string>
- <string> "transform/rot" </string>
- <string> "transform/scale" </string>
- <string> "z/z" </string>
- <string> "z/relative" </string>
<string> "texture" </string>
- <string> "centered" </string>
- <string> "offset" </string>
- <string> "flip_h" </string>
- <string> "flip_v" </string>
- <string> "vframes" </string>
- <string> "hframes" </string>
- <string> "frame" </string>
- <string> "modulate" </string>
<string> "region" </string>
<string> "region_rect" </string>
+ <string> "Sprite" </string>
<string> "collision" </string>
- <string> "StaticBody2D" </string>
- <string> "shape_count" </string>
+ <string> "input/pickable" </string>
<string> "shapes/0/shape" </string>
<string> "shapes/0/transform" </string>
<string> "shapes/0/trigger" </string>
- <string> "layers" </string>
+ <string> "collision/layers" </string>
+ <string> "collision/mask" </string>
<string> "constant_linear_velocity" </string>
<string> "constant_angular_velocity" </string>
<string> "friction" </string>
<string> "bounce" </string>
+ <string> "StaticBody2D" </string>
<string> "CollisionPolygon2D" </string>
<string> "build_mode" </string>
<string> "polygon" </string>
+ <string> "shape_range" </string>
<string> "trigger" </string>
<string> "edge" </string>
+ <string> "transform/pos" </string>
<string> "wall" </string>
<string> "wall_deco" </string>
<string> "corner" </string>
@@ -118,147 +111,152 @@
<string> "ramp" </string>
<string> "ceiling2wall" </string>
<string> "help" </string>
- <string> "Label" </string>
- <string> "focus_neighbour/left" </string>
- <string> "focus_neighbour/top" </string>
- <string> "focus_neighbour/right" </string>
- <string> "focus_neighbour/bottom" </string>
<string> "focus/ignore_mouse" </string>
<string> "focus/stop_mouse" </string>
<string> "size_flags/horizontal" </string>
- <string> "size_flags/stretch_ratio" </string>
- <string> "range/min" </string>
- <string> "range/max" </string>
- <string> "range/step" </string>
- <string> "range/page" </string>
- <string> "range/value" </string>
- <string> "range/exp_edit" </string>
- <string> "rounded_values" </string>
<string> "text" </string>
- <string> "align" </string>
- <string> "valign" </string>
- <string> "autowrap" </string>
- <string> "uppercase" </string>
<string> "percent_visible" </string>
+ <string> "lines_skipped" </string>
+ <string> "max_lines_visible" </string>
+ <string> "Label" </string>
<string> "platform_floor" </string>
<string> "platform_edge" </string>
</string_array>
- <string> "version" </string>
- <int> 1 </int>
- <string> "conn_count" </string>
- <int> 0 </int>
<string> "node_count" </string>
<int> 42 </int>
+ <string> "node_paths" </string>
+ <array len="0" shared="false">
+ </array>
+ <string> "nodes" </string>
+ <int_array len="772"> -1, -1, 0, 0, -1, 1, 1, 0, 0, 0, 0, 6, 2, -1, 3, 3, 1, 4, 2, 5, 3, 0, 1, 0, 18, 7, -1, 10, 8, 4, 9, 5, 10, 6, 11, 4, 12, 7, 13, 7, 14, 8, 15, 9, 16, 10, 17, 9, 0, 2, 0, 19, 19, -1, 4, 20, 11, 21, 12, 22, 13, 23, 4, 0, 0, 0, 6, 24, -1, 4, 25, 14, 3, 1, 4, 2, 5, 15, 0, 4, 0, 18, 7, -1, 10, 8, 4, 9, 16, 10, 6, 11, 4, 12, 7, 13, 7, 14, 8, 15, 9, 16, 10, 17, 9, 0, 5, 0, 19, 19, -1, 4, 20, 11, 21, 17, 22, 13, 23, 4, 0, 0, 0, 6, 26, -1, 4, 25, 18, 3, 1, 4, 2, 5, 19, 0, 7, 0, 18, 7, -1, 10, 8, 4, 9, 20, 10, 6, 11, 4, 12, 7, 13, 7, 14, 8, 15, 9, 16, 10, 17, 9, 0, 8, 0, 19, 19, -1, 4, 20, 11, 21, 21, 22, 13, 23, 4, 0, 0, 0, 6, 27, -1, 4, 25, 22, 3, 1, 4, 2, 5, 23, 0, 10, 0, 18, 7, -1, 10, 8, 4, 9, 24, 10, 6, 11, 4, 12, 7, 13, 7, 14, 8, 15, 9, 16, 10, 17, 9, 0, 11, 0, 19, 19, -1, 4, 20, 11, 21, 25, 22, 13, 23, 4, 0, 0, 0, 6, 28, -1, 4, 25, 26, 3, 1, 4, 2, 5, 27, 0, 13, 0, 18, 7, -1, 10, 8, 4, 9, 28, 10, 6, 11, 4, 12, 7, 13, 7, 14, 8, 15, 9, 16, 10, 17, 9, 0, 14, 0, 19, 19, -1, 4, 20, 11, 21, 29, 22, 13, 23, 4, 0, 0, 0, 6, 29, -1, 4, 25, 30, 3, 1, 4, 2, 5, 31, 0, 16, 0, 18, 7, -1, 10, 8, 4, 9, 32, 10, 6, 11, 4, 12, 7, 13, 7, 14, 8, 15, 9, 16, 10, 17, 9, 0, 17, 0, 19, 19, -1, 4, 20, 11, 21, 33, 22, 13, 23, 4, 0, 0, 0, 6, 30, -1, 4, 25, 34, 3, 1, 4, 2, 5, 35, 0, 19, 0, 18, 7, -1, 10, 8, 4, 9, 36, 10, 6, 11, 4, 12, 7, 13, 7, 14, 8, 15, 9, 16, 10, 17, 9, 0, 20, 0, 19, 19, -1, 4, 20, 11, 21, 33, 22, 13, 23, 4, 0, 0, 0, 6, 31, -1, 4, 25, 37, 3, 1, 4, 2, 5, 38, 0, 0, 0, 6, 32, -1, 4, 25, 39, 3, 1, 4, 2, 5, 40, 0, 0, 0, 6, 33, -1, 4, 25, 41, 3, 1, 4, 2, 5, 42, 0, 0, 0, 6, 34, -1, 4, 25, 43, 3, 1, 4, 2, 5, 44, 0, 0, 0, 6, 35, -1, 4, 25, 45, 3, 1, 4, 2, 5, 46, 0, 26, 0, 18, 7, -1, 10, 8, 4, 9, 47, 10, 6, 11, 4, 12, 7, 13, 7, 14, 8, 15, 9, 16, 10, 17, 9, 0, 27, 0, 19, 19, -1, 4, 20, 11, 21, 48, 22, 13, 23, 4, 0, 0, 0, 6, 36, -1, 4, 25, 49, 3, 1, 4, 2, 5, 50, 0, 29, 0, 18, 7, -1, 10, 8, 4, 9, 51, 10, 6, 11, 4, 12, 7, 13, 7, 14, 8, 15, 9, 16, 10, 17, 9, 0, 30, 0, 19, 19, -1, 4, 20, 11, 21, 52, 22, 13, 23, 4, 0, 0, 0, 6, 37, -1, 4, 25, 53, 3, 1, 4, 2, 5, 54, 0, 32, 0, 18, 7, -1, 10, 8, 4, 9, 55, 10, 6, 11, 4, 12, 7, 13, 7, 14, 8, 15, 9, 16, 10, 17, 9, 0, 33, 0, 19, 19, -1, 4, 20, 11, 21, 21, 22, 13, 23, 4, 0, 0, 0, 46, 38, -1, 7, 39, 2, 40, 2, 41, 56, 42, 57, 43, 10, 44, 11, 45, 58, 0, 0, 0, 6, 47, -1, 4, 25, 59, 3, 1, 4, 2, 5, 60, 0, 36, 0, 18, 7, -1, 10, 8, 4, 9, 61, 10, 6, 11, 4, 12, 7, 13, 7, 14, 8, 15, 9, 16, 10, 17, 9, 0, 37, 0, 19, 19, -1, 4, 20, 11, 21, 62, 22, 13, 23, 4, 0, 0, 0, 6, 48, -1, 4, 25, 63, 3, 1, 4, 2, 5, 64, 0, 39, 0, 18, 7, -1, 10, 8, 4, 9, 65, 10, 6, 11, 4, 12, 7, 13, 7, 14, 8, 15, 9, 16, 10, 17, 9, 0, 40, 0, 19, 19, -1, 4, 20, 11, 21, 66, 22, 13, 23, 4, 0 </int_array>
<string> "variants" </string>
- <array len="69" shared="false">
- <node_path> "" </node_path>
+ <array len="67" shared="false">
<dictionary shared="false">
+ <string> "__editor_plugin_screen__" </string>
+ <string> "Script" </string>
<string> "__editor_plugin_states__" </string>
<dictionary shared="false">
<string> "2D" </string>
<dictionary shared="false">
- <string> "pixel_snap" </string>
- <bool> True </bool>
- <string> "zoom" </string>
- <real> 1.670183 </real>
- <string> "use_snap" </string>
- <bool> True </bool>
<string> "ofs" </string>
<vector2> -446.534, -87.6905 </vector2>
- <string> "snap" </string>
- <int> 8 </int>
+ <string> "snap_grid" </string>
+ <bool> False </bool>
+ <string> "snap_offset" </string>
+ <vector2> 0, 0 </vector2>
+ <string> "snap_pixel" </string>
+ <bool> False </bool>
+ <string> "snap_relative" </string>
+ <bool> False </bool>
+ <string> "snap_rotation" </string>
+ <bool> False </bool>
+ <string> "snap_rotation_offset" </string>
+ <real> 0 </real>
+ <string> "snap_rotation_step" </string>
+ <real> 0.261799 </real>
+ <string> "snap_show_grid" </string>
+ <bool> False </bool>
+ <string> "snap_step" </string>
+ <vector2> 10, 10 </vector2>
+ <string> "zoom" </string>
+ <real> 1.670183 </real>
</dictionary>
<string> "3D" </string>
<dictionary shared="false">
+ <string> "ambient_light_color" </string>
+ <color> 0.15, 0.15, 0.15, 1 </color>
+ <string> "default_light" </string>
+ <bool> True </bool>
+ <string> "default_srgb" </string>
+ <bool> False </bool>
+ <string> "deflight_rot_x" </string>
+ <real> 0.942478 </real>
<string> "deflight_rot_y" </string>
<real> 0.628319 </real>
- <string> "zfar" </string>
- <real> 500 </real>
<string> "fov" </string>
<real> 45 </real>
+ <string> "show_grid" </string>
+ <bool> True </bool>
+ <string> "show_origin" </string>
+ <bool> True </bool>
+ <string> "viewport_mode" </string>
+ <int> 1 </int>
<string> "viewports" </string>
<array len="4" shared="false">
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
<string> "listener" </string>
<bool> True </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
<string> "use_environment" </string>
<bool> False </bool>
<string> "use_orthogonal" </string>
<bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
+ </dictionary>
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
<string> "listener" </string>
<bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
<string> "use_environment" </string>
<bool> False </bool>
<string> "use_orthogonal" </string>
<bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
+ </dictionary>
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
<string> "listener" </string>
<bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
<string> "use_environment" </string>
<bool> False </bool>
<string> "use_orthogonal" </string>
<bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
+ </dictionary>
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
<string> "listener" </string>
<bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
<string> "use_environment" </string>
<bool> False </bool>
<string> "use_orthogonal" </string>
<bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
+ <string> "x_rot" </string>
+ <real> 0 </real>
+ <string> "y_rot" </string>
+ <real> 0 </real>
</dictionary>
</array>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "ambient_light_color" </string>
- <color> 0.15, 0.15, 0.15, 1 </color>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
+ <string> "zfar" </string>
+ <real> 500 </real>
<string> "znear" </string>
<real> 0.1 </real>
- <string> "default_srgb" </string>
+ </dictionary>
+ <string> "Anim" </string>
+ <dictionary shared="false">
+ <string> "visible" </string>
<bool> False </bool>
- <string> "deflight_rot_x" </string>
- <real> 0.942478 </real>
</dictionary>
</dictionary>
<string> "__editor_run_settings__" </string>
@@ -268,23 +266,20 @@
<string> "run_mode" </string>
<int> 0 </int>
</dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "2D" </string>
</dictionary>
+ <resource external="0"> </resource>
<bool> True </bool>
- <real> 1 </real>
- <vector2> 0, 0 </vector2>
- <real> 0 </real>
- <vector2> 1, 1 </vector2>
- <int> 0 </int>
- <resource resource_type="Texture" path="res://tiles_demo.png"> </resource>
- <bool> False </bool>
- <int> 1 </int>
- <color> 1, 1, 1, 1 </color>
<rect2> 0, 0, 64, 64 </rect2>
+ <bool> False </bool>
<resource resource_type="Shape2D" path="local://1"> </resource>
<matrix32> 1, -0, 0, 1, 0, 0 </matrix32>
+ <int> 1 </int>
+ <vector2> 0, 0 </vector2>
+ <real> 0 </real>
+ <real> 1 </real>
+ <int> 0 </int>
<vector2_array len="4"> 32, -24, 32, 32, -32, 32, -32, -24 </vector2_array>
+ <vector2> -1, -1 </vector2>
<vector2> 64, 0 </vector2>
<rect2> 64, 0, 64, 64 </rect2>
<resource resource_type="Shape2D" path="local://2"> </resource>
@@ -329,7 +324,7 @@
<resource resource_type="Shape2D" path="local://10"> </resource>
<int> 2 </int>
<string> "This scene serves as a tool for editing the tileset.&#0010;Nodes (sprites) and their respective collisions&#0010;are edited here. &#0010;&#0010;To create a tileset from this, a &quot;TileSet&quot; resoucre &#0010;must be created. Use the helper in:&#0010;&#0010; Scene -&lt; Convert To -&lt; TileSet&#0010;&#0010;This will save a tileset. Saving over it will merge your changes.&#0010;&#0010;Finally, the saved tileset resource (tileset.xml in this&#0010; case), can be opened to be used into a TileMap node&#0010; for editing a tile map.&#0010;" </string>
- <real> -1 </real>
+ <int> -1 </int>
<vector2> 0, 256 </vector2>
<rect2> 128, 0, 64, 64 </rect2>
<resource resource_type="Shape2D" path="local://11"> </resource>
@@ -339,10 +334,8 @@
<resource resource_type="Shape2D" path="local://12"> </resource>
<vector2_array len="4"> 24, -24, 24, 24, -32, 24, -32, -24 </vector2_array>
</array>
- <string> "nodes" </string>
- <int_array len="1708"> -1, -1, 0, 0, -1, 2, 1, 0, 2, 1, 0, 0, 0, 4, 3, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 12, 0, 1, 0, 25, 24, -1, 18, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 26, 10, 27, 13, 28, 14, 29, 9, 30, 10, 31, 4, 32, 5, 33, 3, 34, 5, 0, 2, 0, 35, 35, -1, 12, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 36, 7, 37, 15, 38, 9, 0, 0, 0, 4, 39, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 16, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 17, 0, 4, 0, 25, 24, -1, 18, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 26, 10, 27, 18, 28, 14, 29, 9, 30, 10, 31, 4, 32, 5, 33, 3, 34, 5, 0, 5, 0, 35, 35, -1, 12, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 36, 7, 37, 19, 38, 9, 0, 0, 0, 4, 40, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 20, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 21, 0, 7, 0, 25, 24, -1, 18, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 26, 10, 27, 22, 28, 14, 29, 9, 30, 10, 31, 4, 32, 5, 33, 3, 34, 5, 0, 8, 0, 35, 35, -1, 12, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 36, 7, 37, 23, 38, 9, 0, 0, 0, 4, 41, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 24, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 25, 0, 10, 0, 25, 24, -1, 18, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 26, 10, 27, 26, 28, 14, 29, 9, 30, 10, 31, 4, 32, 5, 33, 3, 34, 5, 0, 11, 0, 35, 35, -1, 12, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 36, 7, 37, 27, 38, 9, 0, 0, 0, 4, 42, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 28, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 29, 0, 13, 0, 25, 24, -1, 18, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 26, 10, 27, 30, 28, 14, 29, 9, 30, 10, 31, 4, 32, 5, 33, 3, 34, 5, 0, 14, 0, 35, 35, -1, 12, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 36, 7, 37, 31, 38, 9, 0, 0, 0, 4, 43, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 32, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 33, 0, 16, 0, 25, 24, -1, 18, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 26, 10, 27, 34, 28, 14, 29, 9, 30, 10, 31, 4, 32, 5, 33, 3, 34, 5, 0, 17, 0, 35, 35, -1, 12, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 36, 7, 37, 35, 38, 9, 0, 0, 0, 4, 44, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 36, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 37, 0, 19, 0, 25, 24, -1, 18, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 26, 10, 27, 38, 28, 14, 29, 9, 30, 10, 31, 4, 32, 5, 33, 3, 34, 5, 0, 20, 0, 35, 35, -1, 12, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 36, 7, 37, 35, 38, 9, 0, 0, 0, 4, 45, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 39, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 40, 0, 0, 0, 4, 46, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 41, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 42, 0, 0, 0, 4, 47, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 43, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 44, 0, 0, 0, 4, 48, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 45, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 46, 0, 0, 0, 4, 49, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 47, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 48, 0, 26, 0, 25, 24, -1, 18, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 26, 10, 27, 49, 28, 14, 29, 9, 30, 10, 31, 4, 32, 5, 33, 3, 34, 5, 0, 27, 0, 35, 35, -1, 12, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 36, 7, 37, 50, 38, 9, 0, 0, 0, 4, 50, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 51, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 52, 0, 29, 0, 25, 24, -1, 18, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 26, 10, 27, 53, 28, 14, 29, 9, 30, 10, 31, 4, 32, 5, 33, 3, 34, 5, 0, 30, 0, 35, 35, -1, 12, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 36, 7, 37, 54, 38, 9, 0, 0, 0, 4, 51, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 55, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 56, 0, 32, 0, 25, 24, -1, 18, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 26, 10, 27, 57, 28, 14, 29, 9, 30, 10, 31, 4, 32, 5, 33, 3, 34, 5, 0, 33, 0, 35, 35, -1, 12, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 36, 7, 37, 23, 38, 9, 0, 0, 0, 53, 52, -1, 25, 1, 0, 5, 2, 6, 3, 7, 3, 54, 0, 55, 0, 56, 0, 57, 0, 58, 2, 59, 2, 60, 58, 61, 3, 62, 5, 63, 3, 64, 3, 65, 3, 66, 5, 67, 9, 68, 9, 69, 59, 70, 7, 71, 7, 72, 9, 73, 9, 74, 60, 0, 0, 0, 4, 75, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 61, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 62, 0, 36, 0, 25, 24, -1, 18, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 26, 10, 27, 63, 28, 14, 29, 9, 30, 10, 31, 4, 32, 5, 33, 3, 34, 5, 0, 37, 0, 35, 35, -1, 12, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 36, 7, 37, 64, 38, 9, 0, 0, 0, 4, 76, -1, 20, 1, 0, 5, 2, 6, 3, 7, 3, 8, 65, 9, 5, 10, 6, 11, 7, 12, 2, 13, 8, 14, 2, 15, 4, 16, 9, 17, 9, 18, 10, 19, 10, 20, 7, 21, 11, 22, 2, 23, 66, 0, 39, 0, 25, 24, -1, 18, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 26, 10, 27, 67, 28, 14, 29, 9, 30, 10, 31, 4, 32, 5, 33, 3, 34, 5, 0, 40, 0, 35, 35, -1, 12, 1, 0, 5, 2, 6, 3, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 2, 36, 7, 37, 68, 38, 9, 0 </int_array>
- <string> "conns" </string>
- <int_array len="0"> </int_array>
+ <string> "version" </string>
+ <int> 2 </int>
</dictionary>
</main_resource>
diff --git a/demos/2d/polygon_path_finder_demo/engine.cfg b/demos/2d/polygon_path_finder_demo/engine.cfg
deleted file mode 100644
index 41c4adf701..0000000000
--- a/demos/2d/polygon_path_finder_demo/engine.cfg
+++ /dev/null
@@ -1,5 +0,0 @@
-[application]
-
-name="polygon_path_finder_demo"
-main_scene="res://new_scene_poly_with_holes.scn"
-icon="icon.png"
diff --git a/demos/2d/polygon_path_finder_demo/icon.png b/demos/2d/polygon_path_finder_demo/icon.png
deleted file mode 100644
index 0c422e37b0..0000000000
--- a/demos/2d/polygon_path_finder_demo/icon.png
+++ /dev/null
Binary files differ
diff --git a/demos/2d/polygon_path_finder_demo/icon.png.flags b/demos/2d/polygon_path_finder_demo/icon.png.flags
deleted file mode 100644
index dbef2209e8..0000000000
--- a/demos/2d/polygon_path_finder_demo/icon.png.flags
+++ /dev/null
@@ -1 +0,0 @@
-gen_mipmaps=true
diff --git a/demos/2d/polygon_path_finder_demo/new_scene_poly_with_holes.scn b/demos/2d/polygon_path_finder_demo/new_scene_poly_with_holes.scn
deleted file mode 100644
index 07838be41e..0000000000
--- a/demos/2d/polygon_path_finder_demo/new_scene_poly_with_holes.scn
+++ /dev/null
Binary files differ
diff --git a/demos/2d/polygon_path_finder_demo/polygonpathfinder.gd b/demos/2d/polygon_path_finder_demo/polygonpathfinder.gd
deleted file mode 100644
index a0e71dd127..0000000000
--- a/demos/2d/polygon_path_finder_demo/polygonpathfinder.gd
+++ /dev/null
@@ -1,80 +0,0 @@
-
-extends Spatial
-
-func _ready():
- var pf = PolygonPathFinder.new()
-
- var points = Vector2Array()
- var connections = IntArray()
-
- # poly 1
- points.push_back(Vector2(0, 0)) #0
- points.push_back(Vector2(10, 0)) #1
- points.push_back(Vector2(10, 10)) #2
- points.push_back(Vector2(0, 10)) #3
-
- connections.push_back(0) # connect vertex 0 ...
- connections.push_back(1) # ... to 1
- drawLine(points[0], points[1], get_node("/root/Spatial/Polys"))
- connections.push_back(1) # connect vertex 1 ...
- connections.push_back(2) # ... to 2
- drawLine(points[1], points[2], get_node("/root/Spatial/Polys"))
- connections.push_back(2) # etc.
- connections.push_back(3)
- drawLine(points[2], points[3], get_node("/root/Spatial/Polys"))
- connections.push_back(3) # connect vertex 3 ...
- connections.push_back(0) # back to vertex 0, to close the polygon
- drawLine(points[3], points[0], get_node("/root/Spatial/Polys"))
-
- # poly 2, as obstacle inside poly 1
- points.push_back(Vector2(2, 0.5)) #4
- points.push_back(Vector2(4, 0.5)) #5
- points.push_back(Vector2(4, 9.5)) #6
- points.push_back(Vector2(2, 9.5)) #7
-
- connections.push_back(4)
- connections.push_back(5)
- drawLine(points[4], points[5], get_node("/root/Spatial/Polys"))
- connections.push_back(5)
- connections.push_back(6)
- drawLine(points[5], points[6], get_node("/root/Spatial/Polys"))
- connections.push_back(6)
- connections.push_back(7)
- drawLine(points[6], points[7], get_node("/root/Spatial/Polys"))
- connections.push_back(7)
- connections.push_back(4)
- drawLine(points[7], points[4], get_node("/root/Spatial/Polys"))
-
-
- print("points: ",points)
- print("connections: ",connections)
-
- pf.setup(points, connections)
-
- var path = pf.find_path(Vector2(1, 5), Vector2(8, 5))
-
- var lastStep = null
- print("path: ",path)
- for step in path:
- print("step: ",step)
- if (lastStep != null):
- var currPathSegment = Vector2Array()
- drawLine(lastStep, step, get_node("/root/Spatial/Path"))
- lastStep = step
-
-
-
-func drawLine(pointA, pointB, immediateGeo):
- var drawPosY = 0.1
- var im = immediateGeo
-
- im.begin(Mesh.PRIMITIVE_POINTS, null)
- im.add_vertex(Vector3(pointA.x, drawPosY, pointA.y))
- im.add_vertex(Vector3(pointB.x, drawPosY, pointB.y))
- im.end()
- im.begin(Mesh.PRIMITIVE_LINE_STRIP, null)
- im.add_vertex(Vector3(pointA.x, drawPosY, pointA.y))
- im.add_vertex(Vector3(pointB.x, drawPosY, pointB.y))
- im.end()
-
-
diff --git a/demos/2d/pong/pong.gd b/demos/2d/pong/pong.gd
index cf6003c659..81afbd9961 100644
--- a/demos/2d/pong/pong.gd
+++ b/demos/2d/pong/pong.gd
@@ -1,73 +1,67 @@
extends Node2D
-#member variables here, example:
-#var a=2
-#var b="textvar"
+# Member variables
const INITIAL_BALL_SPEED = 80
var ball_speed = INITIAL_BALL_SPEED
-var screen_size = Vector2(640,400)
-#default ball direction
-var direction = Vector2(-1,0)
-var pad_size = Vector2(8,32)
+var screen_size = Vector2(640, 400)
+
+# Default ball direction
+var direction = Vector2(-1, 0)
+var pad_size = Vector2(8, 32)
const PAD_SPEED = 150
func _process(delta):
-
-
- #get ball position and pad rectangles
+ # Get ball position and pad rectangles
var ball_pos = get_node("ball").get_pos()
- var left_rect = Rect2( get_node("left").get_pos() - pad_size*0.5, pad_size )
- var right_rect = Rect2( get_node("right").get_pos() - pad_size*0.5, pad_size )
+ var left_rect = Rect2(get_node("left").get_pos() - pad_size*0.5, pad_size)
+ var right_rect = Rect2(get_node("right").get_pos() - pad_size*0.5, pad_size)
- #integrate new ball postion
- ball_pos+=direction*ball_speed*delta
+ # Integrate new ball postion
+ ball_pos += direction*ball_speed*delta
- #flip when touching roof or floor
- if ( (ball_pos.y<0 and direction.y <0) or (ball_pos.y>screen_size.y and direction.y>0)):
+ # Flip when touching roof or floor
+ if ((ball_pos.y < 0 and direction.y < 0) or (ball_pos.y > screen_size.y and direction.y > 0)):
direction.y = -direction.y
-
- #flip, change direction and increase speed when touching pads
- if ( (left_rect.has_point(ball_pos) and direction.x < 0) or (right_rect.has_point(ball_pos) and direction.x > 0)):
- direction.x=-direction.x
- ball_speed*=1.1
- direction.y=randf()*2.0-1
+
+ # Flip, change direction and increase speed when touching pads
+ if ((left_rect.has_point(ball_pos) and direction.x < 0) or (right_rect.has_point(ball_pos) and direction.x > 0)):
+ direction.x = -direction.x
+ ball_speed *= 1.1
+ direction.y = randf()*2.0 - 1
direction = direction.normalized()
-
- #check gameover
- if (ball_pos.x<0 or ball_pos.x>screen_size.x):
- ball_pos=screen_size*0.5
- ball_speed=INITIAL_BALL_SPEED
- direction=Vector2(-1,0)
-
-
+
+ # Check gameover
+ if (ball_pos.x < 0 or ball_pos.x > screen_size.x):
+ ball_pos = screen_size*0.5
+ ball_speed = INITIAL_BALL_SPEED
+ direction = Vector2(-1, 0)
+
get_node("ball").set_pos(ball_pos)
-
- #move left pad
+
+ # Move left pad
var left_pos = get_node("left").get_pos()
if (left_pos.y > 0 and Input.is_action_pressed("left_move_up")):
- left_pos.y+=-PAD_SPEED*delta
+ left_pos.y += -PAD_SPEED*delta
if (left_pos.y < screen_size.y and Input.is_action_pressed("left_move_down")):
- left_pos.y+=PAD_SPEED*delta
-
+ left_pos.y += PAD_SPEED*delta
+
get_node("left").set_pos(left_pos)
-
- #move right pad
+
+ # Move right pad
var right_pos = get_node("right").get_pos()
if (right_pos.y > 0 and Input.is_action_pressed("right_move_up")):
- right_pos.y+=-PAD_SPEED*delta
+ right_pos.y += -PAD_SPEED*delta
if (right_pos.y < screen_size.y and Input.is_action_pressed("right_move_down")):
- right_pos.y+=PAD_SPEED*delta
-
- get_node("right").set_pos(right_pos)
+ right_pos.y += PAD_SPEED*delta
-
+ get_node("right").set_pos(right_pos)
+
func _ready():
- screen_size = get_viewport_rect().size #get actual size
+ screen_size = get_viewport_rect().size # Get actual size
pad_size = get_node("left").get_texture().get_size()
set_process(true)
-
diff --git a/demos/2d/pong/pong.xml b/demos/2d/pong/pong.xml
index cf47a8db9f..2189be7c62 100644
--- a/demos/2d/pong/pong.xml
+++ b/demos/2d/pong/pong.xml
@@ -1,153 +1,170 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="6" version="0.99" version_name="Godot Engine v0.99.3735-pre-beta">
- <ext_resource path="res://pong.*" type="GDScript"></ext_resource>
- <ext_resource path="res://separator.*" type="ImageTexture"></ext_resource>
- <ext_resource path="res://left_pallete.*" type="ImageTexture"></ext_resource>
- <ext_resource path="res://right_pallete.*" type="ImageTexture"></ext_resource>
- <ext_resource path="res://ball.*" type="ImageTexture"></ext_resource>
+<resource_file type="PackedScene" subresource_count="6" version="2.0" version_name="Godot Engine v2.0.alpha.custom_build">
+ <ext_resource path="res://pong.gd" type="Script" index="0"></ext_resource>
+ <ext_resource path="res://left_pallete.png" type="Texture" index="1"></ext_resource>
+ <ext_resource path="res://separator.png" type="Texture" index="3"></ext_resource>
+ <ext_resource path="res://right_pallete.png" type="Texture" index="2"></ext_resource>
+ <ext_resource path="res://ball.png" type="Texture" index="4"></ext_resource>
<main_resource>
<dictionary name="_bundled" shared="false">
+ <string> "conn_count" </string>
+ <int> 0 </int>
+ <string> "conns" </string>
+ <int_array len="0"> </int_array>
+ <string> "editable_instances" </string>
+ <array len="0" shared="false">
+ </array>
<string> "names" </string>
- <string_array len="27">
+ <string_array len="11">
<string> "game" </string>
- <string> "Node2D" </string>
- <string> "visibility/visible" </string>
- <string> "visibility/opacity" </string>
- <string> "visibility/self_opacity" </string>
- <string> "visibility/on_top" </string>
- <string> "transform/pos" </string>
- <string> "transform/rot" </string>
- <string> "transform/scale" </string>
<string> "script/script" </string>
<string> "__meta__" </string>
+ <string> "Node2D" </string>
<string> "left" </string>
- <string> "Sprite" </string>
+ <string> "transform/pos" </string>
<string> "texture" </string>
- <string> "centered" </string>
- <string> "offset" </string>
- <string> "flip_h" </string>
- <string> "flip_v" </string>
- <string> "vframes" </string>
- <string> "hframes" </string>
- <string> "frame" </string>
- <string> "modulate" </string>
- <string> "region" </string>
- <string> "region_rect" </string>
+ <string> "Sprite" </string>
<string> "right" </string>
<string> "separator" </string>
<string> "ball" </string>
</string_array>
- <string> "version" </string>
- <int> 1 </int>
- <string> "conn_count" </string>
- <int> 0 </int>
<string> "node_count" </string>
<int> 5 </int>
+ <string> "node_paths" </string>
+ <array len="0" shared="false">
+ </array>
+ <string> "nodes" </string>
+ <int_array len="55"> -1, -1, 3, 0, -1, 2, 1, 0, 2, 1, 0, 0, 0, 7, 4, -1, 2, 5, 2, 6, 3, 0, 0, 0, 7, 8, -1, 2, 5, 4, 6, 5, 0, 0, 0, 7, 9, -1, 2, 5, 6, 6, 7, 0, 0, 0, 7, 10, -1, 2, 5, 8, 6, 9, 0 </int_array>
<string> "variants" </string>
- <array len="20" shared="false">
- <bool> True </bool>
- <real> 1 </real>
- <vector2> 0, 0 </vector2>
- <real> 0 </real>
- <vector2> 1, 1 </vector2>
- <resource resource_type="GDScript" path="res://pong.*"> </resource>
+ <array len="10" shared="false">
+ <resource external="0"> </resource>
<dictionary shared="false">
+ <string> "__editor_plugin_screen__" </string>
+ <string> "Script" </string>
<string> "__editor_plugin_states__" </string>
<dictionary shared="false">
- <string> "Script" </string>
- <dictionary shared="false">
- <string> "current" </string>
- <int> 0 </int>
- <string> "sources" </string>
- <array len="1" shared="false">
- <string> "res://pong.gd" </string>
- </array>
- </dictionary>
<string> "2D" </string>
<dictionary shared="false">
- <string> "pixel_snap" </string>
- <bool> True </bool>
- <string> "zoom" </string>
- <real> 1.108033 </real>
<string> "ofs" </string>
<vector2> -54.59, -36.0052 </vector2>
+ <string> "snap_grid" </string>
+ <bool> False </bool>
+ <string> "snap_offset" </string>
+ <vector2> 0, 0 </vector2>
+ <string> "snap_pixel" </string>
+ <bool> False </bool>
+ <string> "snap_relative" </string>
+ <bool> False </bool>
+ <string> "snap_rotation" </string>
+ <bool> False </bool>
+ <string> "snap_rotation_offset" </string>
+ <real> 0 </real>
+ <string> "snap_rotation_step" </string>
+ <real> 0.261799 </real>
+ <string> "snap_show_grid" </string>
+ <bool> False </bool>
+ <string> "snap_step" </string>
+ <vector2> 10, 10 </vector2>
+ <string> "zoom" </string>
+ <real> 1.108033 </real>
</dictionary>
<string> "3D" </string>
<dictionary shared="false">
- <string> "zfar" </string>
- <real> 500 </real>
+ <string> "ambient_light_color" </string>
+ <color> 0.15, 0.15, 0.15, 1 </color>
+ <string> "default_light" </string>
+ <bool> True </bool>
+ <string> "default_srgb" </string>
+ <bool> False </bool>
+ <string> "deflight_rot_x" </string>
+ <real> 0.942478 </real>
+ <string> "deflight_rot_y" </string>
+ <real> 0.628319 </real>
<string> "fov" </string>
<real> 45 </real>
+ <string> "show_grid" </string>
+ <bool> True </bool>
+ <string> "show_origin" </string>
+ <bool> True </bool>
+ <string> "viewport_mode" </string>
+ <int> 1 </int>
<string> "viewports" </string>
<array len="4" shared="false">
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> True </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
</array>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
+ <string> "zfar" </string>
+ <real> 500 </real>
<string> "znear" </string>
<real> 0.1 </real>
</dictionary>
+ <string> "Anim" </string>
+ <dictionary shared="false">
+ <string> "visible" </string>
+ <bool> False </bool>
+ </dictionary>
</dictionary>
<string> "__editor_run_settings__" </string>
<dictionary shared="false">
@@ -156,27 +173,18 @@
<string> "run_mode" </string>
<int> 0 </int>
</dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "Script" </string>
</dictionary>
<vector2> 67.6875, 183.208 </vector2>
- <resource resource_type="ImageTexture" path="res://left_pallete.*"> </resource>
- <bool> False </bool>
- <int> 1 </int>
- <int> 0 </int>
- <color> 1, 1, 1, 1 </color>
- <rect2> 0, 0, 0, 0 </rect2>
+ <resource external="1"> </resource>
<vector2> 577, 187 </vector2>
- <resource resource_type="ImageTexture" path="res://right_pallete.*"> </resource>
+ <resource external="2"> </resource>
<vector2> 320, 200 </vector2>
- <resource resource_type="ImageTexture" path="res://separator.*"> </resource>
+ <resource external="3"> </resource>
<vector2> 320.283, 188 </vector2>
- <resource resource_type="ImageTexture" path="res://ball.*"> </resource>
+ <resource external="4"> </resource>
</array>
- <string> "nodes" </string>
- <int_array len="197"> -1, -1, 1, 0, -1, 9, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 0, 0, 0, 12, 11, -1, 18, 2, 0, 3, 1, 4, 1, 5, 0, 6, 7, 7, 3, 8, 4, 13, 8, 14, 0, 15, 2, 16, 9, 17, 9, 18, 10, 19, 10, 20, 11, 21, 12, 22, 9, 23, 13, 0, 0, 0, 12, 24, -1, 18, 2, 0, 3, 1, 4, 1, 5, 0, 6, 14, 7, 3, 8, 4, 13, 15, 14, 0, 15, 2, 16, 9, 17, 9, 18, 10, 19, 10, 20, 11, 21, 12, 22, 9, 23, 13, 0, 0, 0, 12, 25, -1, 18, 2, 0, 3, 1, 4, 1, 5, 0, 6, 16, 7, 3, 8, 4, 13, 17, 14, 0, 15, 2, 16, 9, 17, 9, 18, 10, 19, 10, 20, 11, 21, 12, 22, 9, 23, 13, 0, 0, 0, 12, 26, -1, 18, 2, 0, 3, 1, 4, 1, 5, 0, 6, 18, 7, 3, 8, 4, 13, 19, 14, 0, 15, 2, 16, 9, 17, 9, 18, 10, 19, 10, 20, 11, 21, 12, 22, 9, 23, 13, 0 </int_array>
- <string> "conns" </string>
- <int_array len="0"> </int_array>
+ <string> "version" </string>
+ <int> 2 </int>
</dictionary>
</main_resource>
diff --git a/demos/2d/rubegoldberg/ball.xml b/demos/2d/rubegoldberg/ball.xml
index 625438eb75..73b699514c 100644
--- a/demos/2d/rubegoldberg/ball.xml
+++ b/demos/2d/rubegoldberg/ball.xml
@@ -1,171 +1,200 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="3" version="0.99" version_name="Godot Engine v0.99.3656-pre-beta">
- <ext_resource path="res://art/bowling_ball.*" type="ImageTexture"></ext_resource>
+<resource_file type="PackedScene" subresource_count="3" version="2.0" version_name="Godot Engine v2.0.alpha.custom_build">
+ <ext_resource path="res://art/bowling_ball.png" type="Texture" index="0"></ext_resource>
<resource type="CircleShape2D" path="local://1">
- <string name="resource/name"> "" </string>
<real name="custom_solver_bias"> 0 </real>
<real name="radius"> 32 </real>
- <resource name="script/script"></resource>
+
</resource>
<main_resource>
- <string name="resource/name"> "" </string>
<dictionary name="_bundled" shared="false">
+ <string> "conn_count" </string>
+ <int> 0 </int>
+ <string> "conns" </string>
+ <int_array len="0"> </int_array>
+ <string> "editable_instances" </string>
+ <array len="0" shared="false">
+ </array>
<string> "names" </string>
- <string_array len="48">
+ <string_array len="30">
<string> "Ball" </string>
- <string> "RigidBody2D" </string>
- <string> "process/process" </string>
- <string> "process/fixed_process" </string>
- <string> "process/input" </string>
- <string> "process/unhandled_input" </string>
- <string> "process/pause_mode" </string>
- <string> "visibility/visible" </string>
- <string> "visibility/opacity" </string>
- <string> "visibility/self_opacity" </string>
- <string> "visibility/on_top" </string>
- <string> "visibility/blend_mode" </string>
- <string> "transform/pos" </string>
- <string> "transform/rot" </string>
- <string> "transform/scale" </string>
- <string> "shape_count" </string>
+ <string> "input/pickable" </string>
<string> "shapes/0/shape" </string>
<string> "shapes/0/transform" </string>
<string> "shapes/0/trigger" </string>
+ <string> "collision/layers" </string>
+ <string> "collision/mask" </string>
<string> "mode" </string>
<string> "mass" </string>
<string> "friction" </string>
<string> "bounce" </string>
+ <string> "gravity_scale" </string>
<string> "custom_integrator" </string>
<string> "continuous_cd" </string>
<string> "contacts_reported" </string>
<string> "contact_monitor" </string>
- <string> "active" </string>
+ <string> "sleeping" </string>
<string> "can_sleep" </string>
<string> "velocity/linear" </string>
<string> "velocity/angular" </string>
- <string> "script/script" </string>
+ <string> "damp_override/linear" </string>
+ <string> "damp_override/angular" </string>
<string> "__meta__" </string>
+ <string> "RigidBody2D" </string>
<string> "Sprite" </string>
<string> "texture" </string>
- <string> "centered" </string>
- <string> "offset" </string>
- <string> "flip_h" </string>
- <string> "flip_v" </string>
- <string> "vframes" </string>
- <string> "hframes" </string>
- <string> "frame" </string>
- <string> "modulate" </string>
- <string> "region" </string>
- <string> "region_rect" </string>
<string> "CollisionShape2D" </string>
<string> "shape" </string>
<string> "trigger" </string>
+ <string> "_update_shape_index" </string>
</string_array>
- <string> "version" </string>
- <int> 1 </int>
- <string> "conn_count" </string>
- <int> 0 </int>
<string> "node_count" </string>
<int> 3 </int>
+ <string> "node_paths" </string>
+ <array len="0" shared="false">
+ </array>
+ <string> "nodes" </string>
+ <int_array len="73"> -1, -1, 23, 0, -1, 22, 1, 0, 2, 1, 3, 2, 4, 0, 5, 3, 6, 3, 7, 4, 8, 5, 9, 6, 10, 7, 11, 6, 12, 0, 13, 4, 14, 4, 15, 0, 16, 0, 17, 8, 18, 9, 19, 7, 20, 10, 21, 10, 22, 11, 0, 0, 0, 24, 24, -1, 1, 25, 12, 0, 0, 0, 26, 26, -1, 3, 27, 1, 28, 0, 29, 13, 0 </int_array>
<string> "variants" </string>
- <array len="16" shared="true">
+ <array len="14" shared="false">
<bool> False </bool>
+ <resource resource_type="Shape2D" path="local://1"> </resource>
+ <matrix32> 1, 0, 0, 1, 0, 0 </matrix32>
+ <int> 1 </int>
<int> 0 </int>
- <bool> True </bool>
+ <real> 3 </real>
<real> 1 </real>
- <vector2> 0, 0 </vector2>
<real> 0 </real>
- <vector2> 1, 1 </vector2>
- <int> 1 </int>
- <resource resource_type="CircleShape2D" path="local://1"> </resource>
- <matrix32> 1, 0, 0, 1, 0, 0 </matrix32>
- <real> 3 </real>
- <resource name=""></resource> <dictionary shared="false">
+ <bool> True </bool>
+ <vector2> 0, 0 </vector2>
+ <real> -1 </real>
+ <dictionary shared="false">
+ <string> "__editor_plugin_screen__" </string>
+ <string> "2D" </string>
<string> "__editor_plugin_states__" </string>
<dictionary shared="false">
<string> "2D" </string>
<dictionary shared="false">
- <string> "zoom" </string>
- <real> 1.50734 </real>
<string> "ofs" </string>
<vector2> -80.5995, -149.825 </vector2>
+ <string> "snap_grid" </string>
+ <bool> False </bool>
+ <string> "snap_offset" </string>
+ <vector2> 0, 0 </vector2>
+ <string> "snap_pixel" </string>
+ <bool> False </bool>
+ <string> "snap_relative" </string>
+ <bool> False </bool>
+ <string> "snap_rotation" </string>
+ <bool> False </bool>
+ <string> "snap_rotation_offset" </string>
+ <real> 0 </real>
+ <string> "snap_rotation_step" </string>
+ <real> 0.261799 </real>
+ <string> "snap_show_grid" </string>
+ <bool> False </bool>
+ <string> "snap_step" </string>
+ <vector2> 10, 10 </vector2>
+ <string> "zoom" </string>
+ <real> 1.50734 </real>
</dictionary>
<string> "3D" </string>
<dictionary shared="false">
- <string> "zfar" </string>
- <real> 500 </real>
+ <string> "ambient_light_color" </string>
+ <color> 0.15, 0.15, 0.15, 1 </color>
+ <string> "default_light" </string>
+ <bool> True </bool>
+ <string> "default_srgb" </string>
+ <bool> False </bool>
+ <string> "deflight_rot_x" </string>
+ <real> 0.942478 </real>
+ <string> "deflight_rot_y" </string>
+ <real> 0.628319 </real>
<string> "fov" </string>
<real> 45 </real>
+ <string> "show_grid" </string>
+ <bool> True </bool>
+ <string> "show_origin" </string>
+ <bool> True </bool>
+ <string> "viewport_mode" </string>
+ <int> 1 </int>
<string> "viewports" </string>
- <array len="4" shared="true">
+ <array len="4" shared="false">
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> True </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
</array>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
+ <string> "zfar" </string>
+ <real> 500 </real>
<string> "znear" </string>
<real> 0.1 </real>
</dictionary>
+ <string> "Anim" </string>
+ <dictionary shared="false">
+ <string> "visible" </string>
+ <bool> False </bool>
+ </dictionary>
</dictionary>
<string> "__editor_run_settings__" </string>
<dictionary shared="false">
@@ -174,18 +203,13 @@
<string> "run_mode" </string>
<int> 0 </int>
</dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "Script" </string>
</dictionary>
- <resource resource_type="ImageTexture" path="res://art/bowling_ball.*"> </resource>
- <color> 1, 1, 1, 1 </color>
- <rect2> 0, 0, 0, 0 </rect2>
+ <resource external="0"> </resource>
+ <int> -1 </int>
</array>
- <string> "nodes" </string>
- <int_array len="165"> -1, -1, 1, 0, -1, 31, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 7, 2, 8, 3, 9, 3, 10, 2, 11, 1, 12, 4, 13, 5, 14, 6, 15, 7, 16, 8, 17, 9, 18, 0, 19, 1, 20, 10, 21, 3, 22, 5, 23, 0, 24, 0, 25, 1, 26, 0, 27, 2, 28, 2, 29, 4, 30, 5, 31, 11, 32, 12, 0, 0, 0, 33, 33, -1, 25, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 7, 2, 8, 3, 9, 3, 10, 2, 11, 1, 12, 4, 13, 5, 14, 6, 34, 13, 35, 2, 36, 4, 37, 0, 38, 0, 39, 7, 40, 7, 41, 1, 42, 14, 43, 0, 44, 15, 31, 11, 0, 0, 0, 45, 45, -1, 16, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 7, 2, 8, 3, 9, 3, 10, 2, 11, 1, 12, 4, 13, 5, 14, 6, 46, 8, 47, 0, 31, 11, 0 </int_array>
- <string> "conns" </string>
- <int_array len="0"> </int_array>
+ <string> "version" </string>
+ <int> 2 </int>
</dictionary>
- <resource name="script/script"></resource>
+
</main_resource>
</resource_file> \ No newline at end of file
diff --git a/demos/2d/rubegoldberg/box.xml b/demos/2d/rubegoldberg/box.xml
index c715326ae0..c30d30e9f9 100644
--- a/demos/2d/rubegoldberg/box.xml
+++ b/demos/2d/rubegoldberg/box.xml
@@ -1,142 +1,214 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="3" version="0.99" version_name="Godot Engine v0.99.2864-pre-beta">
- <ext_resource path="res://art/box.png" type="Texture"></ext_resource>
+<resource_file type="PackedScene" subresource_count="3" version="2.0" version_name="Godot Engine v2.0.alpha.custom_build">
+ <ext_resource path="res://art/box.png" type="Texture" index="0"></ext_resource>
<resource type="RectangleShape2D" path="local://1">
- <string name="resource/name"> "" </string>
<real name="custom_solver_bias"> 0 </real>
<vector2 name="extents"> 32, 32 </vector2>
- <resource name="script/script"></resource>
+
</resource>
<main_resource>
- <string name="resource/name"> "" </string>
- <dictionary name="_bundled">
+ <dictionary name="_bundled" shared="false">
+ <string> "conn_count" </string>
+ <int> 0 </int>
+ <string> "conns" </string>
+ <int_array len="0"> </int_array>
+ <string> "editable_instances" </string>
+ <array len="0" shared="false">
+ </array>
<string> "names" </string>
- <string_array len="48">
+ <string_array len="30">
<string> "box" </string>
- <string> "RigidBody2D" </string>
- <string> "process/process" </string>
- <string> "process/fixed_process" </string>
- <string> "process/input" </string>
- <string> "process/unhandled_input" </string>
- <string> "process/mode" </string>
- <string> "visibility/visible" </string>
- <string> "visibility/toplevel" </string>
- <string> "visibility/opacity" </string>
- <string> "visibility/self_opacity" </string>
- <string> "visibility/on_top" </string>
- <string> "visibility/blend_mode" </string>
- <string> "transform/notify" </string>
- <string> "transform/pos" </string>
- <string> "transform/rot" </string>
- <string> "transform/scale" </string>
- <string> "shape_count" </string>
+ <string> "input/pickable" </string>
<string> "shapes/0/shape" </string>
<string> "shapes/0/transform" </string>
+ <string> "shapes/0/trigger" </string>
+ <string> "collision/layers" </string>
+ <string> "collision/mask" </string>
<string> "mode" </string>
<string> "mass" </string>
<string> "friction" </string>
<string> "bounce" </string>
+ <string> "gravity_scale" </string>
<string> "custom_integrator" </string>
<string> "continuous_cd" </string>
<string> "contacts_reported" </string>
<string> "contact_monitor" </string>
- <string> "active" </string>
+ <string> "sleeping" </string>
<string> "can_sleep" </string>
<string> "velocity/linear" </string>
<string> "velocity/angular" </string>
- <string> "script/script" </string>
+ <string> "damp_override/linear" </string>
+ <string> "damp_override/angular" </string>
<string> "__meta__" </string>
+ <string> "RigidBody2D" </string>
<string> "Sprite" </string>
<string> "texture" </string>
- <string> "centered" </string>
- <string> "offset" </string>
- <string> "flip_h" </string>
- <string> "flip_v" </string>
- <string> "vframes" </string>
- <string> "hframes" </string>
- <string> "frame" </string>
- <string> "modulate" </string>
- <string> "region" </string>
- <string> "region_rect" </string>
<string> "CollisionShape2D" </string>
<string> "shape" </string>
+ <string> "trigger" </string>
+ <string> "_update_shape_index" </string>
</string_array>
- <string> "version" </string>
- <int> 1 </int>
- <string> "conn_count" </string>
- <int> 0 </int>
<string> "node_count" </string>
<int> 3 </int>
+ <string> "node_paths" </string>
+ <array len="0" shared="false">
+ </array>
+ <string> "nodes" </string>
+ <int_array len="73"> -1, -1, 23, 0, -1, 22, 1, 0, 2, 1, 3, 2, 4, 0, 5, 3, 6, 3, 7, 4, 8, 5, 9, 5, 10, 6, 11, 5, 12, 0, 13, 4, 14, 4, 15, 0, 16, 0, 17, 7, 18, 8, 19, 6, 20, 9, 21, 9, 22, 10, 0, 0, 0, 24, 24, -1, 1, 25, 11, 0, 0, 0, 26, 26, -1, 3, 27, 1, 28, 0, 29, 12, 0 </int_array>
<string> "variants" </string>
- <array len="15">
+ <array len="13" shared="false">
<bool> False </bool>
+ <resource resource_type="Shape2D" path="local://1"> </resource>
+ <matrix32> 1, 0, 0, 1, 0, 0 </matrix32>
+ <int> 1 </int>
<int> 0 </int>
- <bool> True </bool>
<real> 1 </real>
- <vector2> 0, 0 </vector2>
<real> 0 </real>
- <vector2> 1, 1 </vector2>
- <int> 1 </int>
- <resource resource_type="RectangleShape2D" path="local://1"> </resource>
- <matrix32> 1, 0, 0, 1, 0, 0 </matrix32>
- <resource name=""></resource> <dictionary>
+ <bool> True </bool>
+ <vector2> 0, 0 </vector2>
+ <real> -1 </real>
+ <dictionary shared="false">
+ <string> "__editor_plugin_screen__" </string>
+ <string> "2D" </string>
<string> "__editor_plugin_states__" </string>
- <dictionary>
+ <dictionary shared="false">
<string> "2D" </string>
- <dictionary>
- <string> "zoom" </string>
- <real> 1 </real>
+ <dictionary shared="false">
<string> "ofs" </string>
<vector2> -125, -163 </vector2>
+ <string> "snap_grid" </string>
+ <bool> False </bool>
+ <string> "snap_offset" </string>
+ <vector2> 0, 0 </vector2>
+ <string> "snap_pixel" </string>
+ <bool> False </bool>
+ <string> "snap_relative" </string>
+ <bool> False </bool>
+ <string> "snap_rotation" </string>
+ <bool> False </bool>
+ <string> "snap_rotation_offset" </string>
+ <real> 0 </real>
+ <string> "snap_rotation_step" </string>
+ <real> 0.261799 </real>
+ <string> "snap_show_grid" </string>
+ <bool> False </bool>
+ <string> "snap_step" </string>
+ <vector2> 10, 10 </vector2>
+ <string> "zoom" </string>
+ <real> 1 </real>
</dictionary>
<string> "3D" </string>
- <dictionary>
- <string> "zfar" </string>
- <real> 500 </real>
+ <dictionary shared="false">
+ <string> "ambient_light_color" </string>
+ <color> 0.15, 0.15, 0.15, 1 </color>
+ <string> "default_light" </string>
+ <bool> True </bool>
+ <string> "default_srgb" </string>
+ <bool> False </bool>
+ <string> "deflight_rot_x" </string>
+ <real> 0.942478 </real>
+ <string> "deflight_rot_y" </string>
+ <real> 0.628319 </real>
<string> "fov" </string>
<real> 45 </real>
- <string> "window_mode" </string>
- <int> 0 </int>
- <string> "window_0" </string>
- <dictionary>
- <string> "distance" </string>
- <real> 4 </real>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "x_rot" </string>
- <real> 0.337 </real>
- <string> "y_rot" </string>
- <real> -0.575 </real>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
+ <string> "show_grid" </string>
+ <bool> True </bool>
+ <string> "show_origin" </string>
+ <bool> True </bool>
+ <string> "viewport_mode" </string>
+ <int> 1 </int>
+ <string> "viewports" </string>
+ <array len="4" shared="false">
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
+ <string> "listener" </string>
+ <bool> True </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
+ <string> "x_rot" </string>
+ <real> 0 </real>
+ <string> "y_rot" </string>
+ <real> 0 </real>
+ </dictionary>
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
+ <string> "x_rot" </string>
+ <real> 0 </real>
+ <string> "y_rot" </string>
+ <real> 0 </real>
+ </dictionary>
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
+ <string> "x_rot" </string>
+ <real> 0 </real>
+ <string> "y_rot" </string>
+ <real> 0 </real>
+ </dictionary>
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
+ <string> "x_rot" </string>
+ <real> 0 </real>
+ <string> "y_rot" </string>
+ <real> 0 </real>
+ </dictionary>
+ </array>
+ <string> "zfar" </string>
+ <real> 500 </real>
<string> "znear" </string>
<real> 0.1 </real>
</dictionary>
+ <string> "Anim" </string>
+ <dictionary shared="false">
+ <string> "visible" </string>
+ <bool> False </bool>
+ </dictionary>
</dictionary>
<string> "__editor_run_settings__" </string>
- <dictionary>
+ <dictionary shared="false">
<string> "custom_args" </string>
<string> "-l $scene" </string>
<string> "run_mode" </string>
<int> 0 </int>
</dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "2D" </string>
</dictionary>
- <resource resource_type="Texture" path="res://art/box.png"> </resource>
- <color> 1, 1, 1, 1 </color>
- <rect2> 0, 0, 0, 0 </rect2>
+ <resource external="0"> </resource>
+ <int> -1 </int>
</array>
- <string> "nodes" </string>
- <int_array len="173"> -1, -1, 1, 0, -1, 32, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 7, 2, 8, 0, 9, 3, 10, 3, 11, 2, 12, 1, 13, 2, 14, 4, 15, 5, 16, 6, 17, 7, 18, 8, 19, 9, 20, 1, 21, 3, 22, 3, 23, 5, 24, 0, 25, 0, 26, 1, 27, 0, 28, 2, 29, 2, 30, 4, 31, 5, 32, 10, 33, 11, 0, 0, 0, 34, 34, -1, 27, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 7, 2, 8, 0, 9, 3, 10, 3, 11, 2, 12, 1, 13, 0, 14, 4, 15, 5, 16, 6, 35, 12, 36, 2, 37, 4, 38, 0, 39, 0, 40, 7, 41, 7, 42, 1, 43, 13, 44, 0, 45, 14, 32, 10, 0, 0, 0, 46, 46, -1, 17, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 7, 2, 8, 0, 9, 3, 10, 3, 11, 2, 12, 1, 13, 2, 14, 4, 15, 5, 16, 6, 47, 8, 32, 10, 0 </int_array>
- <string> "conns" </string>
- <int_array len="0"> </int_array>
+ <string> "version" </string>
+ <int> 2 </int>
</dictionary>
- <resource name="script/script"></resource>
+
</main_resource>
</resource_file> \ No newline at end of file
diff --git a/demos/2d/rubegoldberg/domino.xml b/demos/2d/rubegoldberg/domino.xml
index 324bf57e66..ec86c833df 100644
--- a/demos/2d/rubegoldberg/domino.xml
+++ b/demos/2d/rubegoldberg/domino.xml
@@ -1,143 +1,215 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="3" version="0.99" version_name="Godot Engine v0.99.2864-pre-beta">
- <ext_resource path="res://art/domino.png" type="Texture"></ext_resource>
+<resource_file type="PackedScene" subresource_count="3" version="2.0" version_name="Godot Engine v2.0.alpha.custom_build">
+ <ext_resource path="res://art/domino.png" type="Texture" index="0"></ext_resource>
<resource type="RectangleShape2D" path="local://1">
- <string name="resource/name"> "" </string>
<real name="custom_solver_bias"> 0 </real>
<vector2 name="extents"> 16, 64 </vector2>
- <resource name="script/script"></resource>
+
</resource>
<main_resource>
- <string name="resource/name"> "" </string>
- <dictionary name="_bundled">
+ <dictionary name="_bundled" shared="false">
+ <string> "conn_count" </string>
+ <int> 0 </int>
+ <string> "conns" </string>
+ <int_array len="0"> </int_array>
+ <string> "editable_instances" </string>
+ <array len="0" shared="false">
+ </array>
<string> "names" </string>
- <string_array len="48">
+ <string_array len="30">
<string> "domino" </string>
- <string> "RigidBody2D" </string>
- <string> "process/process" </string>
- <string> "process/fixed_process" </string>
- <string> "process/input" </string>
- <string> "process/unhandled_input" </string>
- <string> "process/mode" </string>
- <string> "visibility/visible" </string>
- <string> "visibility/toplevel" </string>
- <string> "visibility/opacity" </string>
- <string> "visibility/self_opacity" </string>
- <string> "visibility/on_top" </string>
- <string> "visibility/blend_mode" </string>
- <string> "transform/notify" </string>
- <string> "transform/pos" </string>
- <string> "transform/rot" </string>
- <string> "transform/scale" </string>
- <string> "shape_count" </string>
+ <string> "input/pickable" </string>
<string> "shapes/0/shape" </string>
<string> "shapes/0/transform" </string>
+ <string> "shapes/0/trigger" </string>
+ <string> "collision/layers" </string>
+ <string> "collision/mask" </string>
<string> "mode" </string>
<string> "mass" </string>
<string> "friction" </string>
<string> "bounce" </string>
+ <string> "gravity_scale" </string>
<string> "custom_integrator" </string>
<string> "continuous_cd" </string>
<string> "contacts_reported" </string>
<string> "contact_monitor" </string>
- <string> "active" </string>
+ <string> "sleeping" </string>
<string> "can_sleep" </string>
<string> "velocity/linear" </string>
<string> "velocity/angular" </string>
- <string> "script/script" </string>
+ <string> "damp_override/linear" </string>
+ <string> "damp_override/angular" </string>
<string> "__meta__" </string>
+ <string> "RigidBody2D" </string>
<string> "Sprite" </string>
<string> "texture" </string>
- <string> "centered" </string>
- <string> "offset" </string>
- <string> "flip_h" </string>
- <string> "flip_v" </string>
- <string> "vframes" </string>
- <string> "hframes" </string>
- <string> "frame" </string>
- <string> "modulate" </string>
- <string> "region" </string>
- <string> "region_rect" </string>
<string> "CollisionShape2D" </string>
<string> "shape" </string>
+ <string> "trigger" </string>
+ <string> "_update_shape_index" </string>
</string_array>
- <string> "version" </string>
- <int> 1 </int>
- <string> "conn_count" </string>
- <int> 0 </int>
<string> "node_count" </string>
<int> 3 </int>
+ <string> "node_paths" </string>
+ <array len="0" shared="false">
+ </array>
+ <string> "nodes" </string>
+ <int_array len="73"> -1, -1, 23, 0, -1, 22, 1, 0, 2, 1, 3, 2, 4, 0, 5, 3, 6, 3, 7, 4, 8, 5, 9, 6, 10, 7, 11, 5, 12, 0, 13, 4, 14, 4, 15, 0, 16, 0, 17, 8, 18, 9, 19, 7, 20, 10, 21, 10, 22, 11, 0, 0, 0, 24, 24, -1, 1, 25, 12, 0, 0, 0, 26, 26, -1, 3, 27, 1, 28, 0, 29, 13, 0 </int_array>
<string> "variants" </string>
- <array len="16">
+ <array len="14" shared="false">
<bool> False </bool>
+ <resource resource_type="Shape2D" path="local://1"> </resource>
+ <matrix32> 1, 0, 0, 1, 0, 0 </matrix32>
+ <int> 1 </int>
<int> 0 </int>
- <bool> True </bool>
<real> 1 </real>
- <vector2> 0, 0 </vector2>
- <real> 0 </real>
- <vector2> 1, 1 </vector2>
- <int> 1 </int>
- <resource resource_type="RectangleShape2D" path="local://1"> </resource>
- <matrix32> 1, 0, 0, 1, 0, 0 </matrix32>
<real> 0.5 </real>
- <resource name=""></resource> <dictionary>
+ <real> 0 </real>
+ <bool> True </bool>
+ <vector2> 0, 0 </vector2>
+ <real> -1 </real>
+ <dictionary shared="false">
+ <string> "__editor_plugin_screen__" </string>
+ <string> "2D" </string>
<string> "__editor_plugin_states__" </string>
- <dictionary>
+ <dictionary shared="false">
<string> "2D" </string>
- <dictionary>
- <string> "zoom" </string>
- <real> 1 </real>
+ <dictionary shared="false">
<string> "ofs" </string>
<vector2> -135, -114 </vector2>
+ <string> "snap_grid" </string>
+ <bool> False </bool>
+ <string> "snap_offset" </string>
+ <vector2> 0, 0 </vector2>
+ <string> "snap_pixel" </string>
+ <bool> False </bool>
+ <string> "snap_relative" </string>
+ <bool> False </bool>
+ <string> "snap_rotation" </string>
+ <bool> False </bool>
+ <string> "snap_rotation_offset" </string>
+ <real> 0 </real>
+ <string> "snap_rotation_step" </string>
+ <real> 0.261799 </real>
+ <string> "snap_show_grid" </string>
+ <bool> False </bool>
+ <string> "snap_step" </string>
+ <vector2> 10, 10 </vector2>
+ <string> "zoom" </string>
+ <real> 1 </real>
</dictionary>
<string> "3D" </string>
- <dictionary>
- <string> "zfar" </string>
- <real> 500 </real>
+ <dictionary shared="false">
+ <string> "ambient_light_color" </string>
+ <color> 0.15, 0.15, 0.15, 1 </color>
+ <string> "default_light" </string>
+ <bool> True </bool>
+ <string> "default_srgb" </string>
+ <bool> False </bool>
+ <string> "deflight_rot_x" </string>
+ <real> 0.942478 </real>
+ <string> "deflight_rot_y" </string>
+ <real> 0.628319 </real>
<string> "fov" </string>
<real> 45 </real>
- <string> "window_mode" </string>
- <int> 0 </int>
- <string> "window_0" </string>
- <dictionary>
- <string> "distance" </string>
- <real> 4 </real>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "x_rot" </string>
- <real> 0.337 </real>
- <string> "y_rot" </string>
- <real> -0.575 </real>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
+ <string> "show_grid" </string>
+ <bool> True </bool>
+ <string> "show_origin" </string>
+ <bool> True </bool>
+ <string> "viewport_mode" </string>
+ <int> 1 </int>
+ <string> "viewports" </string>
+ <array len="4" shared="false">
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
+ <string> "listener" </string>
+ <bool> True </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
+ <string> "x_rot" </string>
+ <real> 0 </real>
+ <string> "y_rot" </string>
+ <real> 0 </real>
+ </dictionary>
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
+ <string> "x_rot" </string>
+ <real> 0 </real>
+ <string> "y_rot" </string>
+ <real> 0 </real>
+ </dictionary>
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
+ <string> "x_rot" </string>
+ <real> 0 </real>
+ <string> "y_rot" </string>
+ <real> 0 </real>
+ </dictionary>
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
+ <string> "x_rot" </string>
+ <real> 0 </real>
+ <string> "y_rot" </string>
+ <real> 0 </real>
+ </dictionary>
+ </array>
+ <string> "zfar" </string>
+ <real> 500 </real>
<string> "znear" </string>
<real> 0.1 </real>
</dictionary>
+ <string> "Anim" </string>
+ <dictionary shared="false">
+ <string> "visible" </string>
+ <bool> False </bool>
+ </dictionary>
</dictionary>
<string> "__editor_run_settings__" </string>
- <dictionary>
+ <dictionary shared="false">
<string> "custom_args" </string>
<string> "-l $scene" </string>
<string> "run_mode" </string>
<int> 0 </int>
</dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "2D" </string>
</dictionary>
- <resource resource_type="Texture" path="res://art/domino.png"> </resource>
- <color> 1, 1, 1, 1 </color>
- <rect2> 0, 0, 0, 0 </rect2>
+ <resource external="0"> </resource>
+ <int> -1 </int>
</array>
- <string> "nodes" </string>
- <int_array len="173"> -1, -1, 1, 0, -1, 32, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 7, 2, 8, 0, 9, 3, 10, 3, 11, 2, 12, 1, 13, 2, 14, 4, 15, 5, 16, 6, 17, 7, 18, 8, 19, 9, 20, 1, 21, 3, 22, 10, 23, 5, 24, 0, 25, 0, 26, 1, 27, 0, 28, 2, 29, 2, 30, 4, 31, 5, 32, 11, 33, 12, 0, 0, 0, 34, 34, -1, 27, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 7, 2, 8, 0, 9, 3, 10, 3, 11, 2, 12, 1, 13, 0, 14, 4, 15, 5, 16, 6, 35, 13, 36, 2, 37, 4, 38, 0, 39, 0, 40, 7, 41, 7, 42, 1, 43, 14, 44, 0, 45, 15, 32, 11, 0, 0, 0, 46, 46, -1, 17, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 7, 2, 8, 0, 9, 3, 10, 3, 11, 2, 12, 1, 13, 2, 14, 4, 15, 5, 16, 6, 47, 8, 32, 11, 0 </int_array>
- <string> "conns" </string>
- <int_array len="0"> </int_array>
+ <string> "version" </string>
+ <int> 2 </int>
</dictionary>
- <resource name="script/script"></resource>
+
</main_resource>
</resource_file> \ No newline at end of file
diff --git a/demos/2d/rubegoldberg/pendulum.xml b/demos/2d/rubegoldberg/pendulum.xml
index 2a5378ff2f..90ad45f287 100644
--- a/demos/2d/rubegoldberg/pendulum.xml
+++ b/demos/2d/rubegoldberg/pendulum.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="5" version="0.99" version_name="Godot Engine v0.99.3735-pre-beta">
- <ext_resource path="res://art/bowling_ball.*" type="ImageTexture"></ext_resource>
- <ext_resource path="res://art/box.*" type="ImageTexture"></ext_resource>
+<resource_file type="PackedScene" subresource_count="5" version="2.0" version_name="Godot Engine v2.0.alpha.custom_build">
+ <ext_resource path="res://art/bowling_ball.png" type="Texture" index="1"></ext_resource>
+ <ext_resource path="res://art/box.png" type="Texture" index="0"></ext_resource>
<resource type="RectangleShape2D" path="local://1">
<real name="custom_solver_bias"> 0 </real>
<vector2 name="extents"> 3, 12 </vector2>
@@ -14,165 +14,201 @@
</resource>
<main_resource>
<dictionary name="_bundled" shared="false">
+ <string> "conn_count" </string>
+ <int> 0 </int>
+ <string> "conns" </string>
+ <int_array len="0"> </int_array>
+ <string> "editable_instances" </string>
+ <array len="0" shared="false">
+ </array>
<string> "names" </string>
- <string_array len="57">
+ <string_array len="49">
<string> "pendulum" </string>
- <string> "Node2D" </string>
- <string> "visibility/visible" </string>
- <string> "visibility/opacity" </string>
- <string> "visibility/self_opacity" </string>
- <string> "visibility/on_top" </string>
- <string> "transform/pos" </string>
- <string> "transform/rot" </string>
- <string> "transform/scale" </string>
<string> "__meta__" </string>
+ <string> "Node2D" </string>
<string> "union_0" </string>
- <string> "RigidBody2D" </string>
- <string> "shape_count" </string>
+ <string> "input/pickable" </string>
<string> "shapes/0/shape" </string>
<string> "shapes/0/transform" </string>
<string> "shapes/0/trigger" </string>
+ <string> "collision/layers" </string>
+ <string> "collision/mask" </string>
<string> "mode" </string>
<string> "mass" </string>
<string> "friction" </string>
<string> "bounce" </string>
+ <string> "gravity_scale" </string>
<string> "custom_integrator" </string>
<string> "continuous_cd" </string>
<string> "contacts_reported" </string>
<string> "contact_monitor" </string>
- <string> "active" </string>
+ <string> "sleeping" </string>
<string> "can_sleep" </string>
<string> "velocity/linear" </string>
<string> "velocity/angular" </string>
+ <string> "damp_override/linear" </string>
+ <string> "damp_override/angular" </string>
+ <string> "RigidBody2D" </string>
<string> "Sprite" </string>
+ <string> "transform/scale" </string>
<string> "texture" </string>
- <string> "centered" </string>
- <string> "offset" </string>
- <string> "flip_h" </string>
- <string> "flip_v" </string>
- <string> "vframes" </string>
- <string> "hframes" </string>
- <string> "frame" </string>
- <string> "modulate" </string>
- <string> "region" </string>
- <string> "region_rect" </string>
<string> "collision" </string>
- <string> "CollisionShape2D" </string>
<string> "shape" </string>
<string> "trigger" </string>
+ <string> "_update_shape_index" </string>
+ <string> "CollisionShape2D" </string>
<string> "union_ 2" </string>
+ <string> "transform/pos" </string>
<string> "union_ 3" </string>
<string> "union_ 4" </string>
<string> "joint1" </string>
- <string> "PinJoint2D" </string>
<string> "node_a" </string>
<string> "node_b" </string>
<string> "bias/bias" </string>
+ <string> "softness" </string>
+ <string> "PinJoint2D" </string>
<string> "joint 2_3" </string>
<string> "joint 3_4" </string>
<string> "ball" </string>
<string> "joint 4_ball" </string>
<string> "joint wall" </string>
</string_array>
- <string> "version" </string>
- <int> 1 </int>
- <string> "conn_count" </string>
- <int> 0 </int>
<string> "node_count" </string>
<int> 21 </int>
+ <string> "node_paths" </string>
+ <array len="0" shared="false">
+ </array>
+ <string> "nodes" </string>
+ <int_array len="479"> -1, -1, 2, 0, -1, 1, 1, 0, 0, 0, 0, 25, 3, -1, 22, 4, 1, 5, 2, 6, 3, 7, 1, 8, 4, 9, 4, 10, 5, 11, 6, 12, 7, 13, 8, 14, 7, 15, 1, 16, 5, 17, 5, 18, 1, 19, 1, 20, 9, 21, 10, 22, 8, 23, 11, 24, 11, 1, 12, 0, 1, 0, 26, 26, -1, 2, 27, 13, 28, 14, 0, 1, 0, 33, 29, -1, 3, 30, 2, 31, 1, 32, 15, 0, 0, 0, 25, 34, -1, 23, 35, 16, 4, 1, 5, 2, 6, 17, 7, 1, 8, 4, 9, 4, 10, 5, 11, 6, 12, 7, 13, 8, 14, 7, 15, 1, 16, 5, 17, 5, 18, 1, 19, 1, 20, 9, 21, 10, 22, 8, 23, 11, 24, 11, 1, 18, 0, 4, 0, 26, 26, -1, 2, 27, 13, 28, 14, 0, 4, 0, 33, 29, -1, 3, 30, 2, 31, 1, 32, 15, 0, 0, 0, 25, 36, -1, 23, 35, 19, 4, 1, 5, 2, 6, 17, 7, 1, 8, 4, 9, 4, 10, 5, 11, 6, 12, 7, 13, 8, 14, 7, 15, 1, 16, 5, 17, 5, 18, 1, 19, 1, 20, 9, 21, 10, 22, 8, 23, 11, 24, 11, 1, 18, 0, 7, 0, 26, 26, -1, 2, 27, 13, 28, 14, 0, 7, 0, 33, 29, -1, 3, 30, 2, 31, 1, 32, 15, 0, 0, 0, 25, 37, -1, 23, 35, 20, 4, 1, 5, 2, 6, 17, 7, 1, 8, 4, 9, 4, 10, 5, 11, 6, 12, 7, 13, 8, 14, 7, 15, 1, 16, 5, 17, 5, 18, 1, 19, 1, 20, 9, 21, 10, 22, 8, 23, 11, 24, 11, 1, 18, 0, 10, 0, 26, 26, -1, 2, 27, 13, 28, 14, 0, 10, 0, 33, 29, -1, 3, 30, 2, 31, 1, 32, 15, 0, 0, 0, 43, 38, -1, 5, 35, 21, 39, 22, 40, 23, 41, 8, 42, 8, 0, 0, 0, 43, 44, -1, 5, 35, 24, 39, 23, 40, 25, 41, 8, 42, 8, 0, 0, 0, 43, 45, -1, 5, 35, 26, 39, 25, 40, 27, 41, 6, 42, 8, 0, 0, 0, 25, 46, -1, 24, 35, 28, 27, 29, 4, 1, 5, 30, 6, 17, 7, 1, 8, 4, 9, 4, 10, 5, 11, 6, 12, 7, 13, 8, 14, 7, 15, 1, 16, 5, 17, 5, 18, 1, 19, 1, 20, 9, 21, 10, 22, 8, 23, 11, 24, 11, 1, 18, 0, 16, 0, 26, 26, -1, 2, 27, 31, 28, 32, 0, 16, 0, 33, 29, -1, 3, 30, 30, 31, 1, 32, 15, 0, 0, 0, 43, 47, -1, 5, 35, 33, 39, 27, 40, 34, 41, 8, 42, 8, 0, 0, 0, 43, 48, -1, 5, 35, 35, 39, 22, 40, 36, 41, 8, 42, 8, 0 </int_array>
<string> "variants" </string>
- <array len="38" shared="false">
- <bool> True </bool>
- <real> 1 </real>
- <vector2> 0, 0 </vector2>
- <real> 0 </real>
- <vector2> 1, 1 </vector2>
+ <array len="37" shared="false">
<dictionary shared="false">
+ <string> "__editor_plugin_screen__" </string>
+ <string> "2D" </string>
<string> "__editor_plugin_states__" </string>
<dictionary shared="false">
<string> "2D" </string>
<dictionary shared="false">
- <string> "zoom" </string>
- <real> 2.78951 </real>
<string> "ofs" </string>
<vector2> -121.028, 0.923909 </vector2>
+ <string> "snap_grid" </string>
+ <bool> False </bool>
+ <string> "snap_offset" </string>
+ <vector2> 0, 0 </vector2>
+ <string> "snap_pixel" </string>
+ <bool> False </bool>
+ <string> "snap_relative" </string>
+ <bool> False </bool>
+ <string> "snap_rotation" </string>
+ <bool> False </bool>
+ <string> "snap_rotation_offset" </string>
+ <real> 0 </real>
+ <string> "snap_rotation_step" </string>
+ <real> 0.261799 </real>
+ <string> "snap_show_grid" </string>
+ <bool> False </bool>
+ <string> "snap_step" </string>
+ <vector2> 10, 10 </vector2>
+ <string> "zoom" </string>
+ <real> 2.78951 </real>
</dictionary>
<string> "3D" </string>
<dictionary shared="false">
- <string> "zfar" </string>
- <real> 500 </real>
+ <string> "ambient_light_color" </string>
+ <color> 0.15, 0.15, 0.15, 1 </color>
+ <string> "default_light" </string>
+ <bool> True </bool>
+ <string> "default_srgb" </string>
+ <bool> False </bool>
+ <string> "deflight_rot_x" </string>
+ <real> 0.942478 </real>
+ <string> "deflight_rot_y" </string>
+ <real> 0.628319 </real>
<string> "fov" </string>
<real> 45 </real>
+ <string> "show_grid" </string>
+ <bool> True </bool>
+ <string> "show_origin" </string>
+ <bool> True </bool>
+ <string> "viewport_mode" </string>
+ <int> 1 </int>
<string> "viewports" </string>
<array len="4" shared="false">
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> True </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
</array>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
+ <string> "zfar" </string>
+ <real> 500 </real>
<string> "znear" </string>
<real> 0.1 </real>
</dictionary>
+ <string> "Anim" </string>
+ <dictionary shared="false">
+ <string> "visible" </string>
+ <bool> False </bool>
+ </dictionary>
</dictionary>
<string> "__editor_run_settings__" </string>
<dictionary shared="false">
@@ -181,23 +217,25 @@
<string> "run_mode" </string>
<int> 0 </int>
</dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "2D" </string>
</dictionary>
- <int> 1 </int>
- <resource resource_type="RectangleShape2D" path="local://1"> </resource>
- <matrix32> 1, 0, 0, 1, 0, 0 </matrix32>
<bool> False </bool>
+ <resource resource_type="Shape2D" path="local://1"> </resource>
+ <matrix32> 1, 0, 0, 1, 0, 0 </matrix32>
+ <int> 1 </int>
<int> 0 </int>
<real> 0.2 </real>
+ <real> 1 </real>
+ <real> 0 </real>
+ <bool> True </bool>
+ <vector2> 0, 0 </vector2>
+ <real> -1 </real>
<dictionary shared="false">
<string> "_edit_group_" </string>
<bool> True </bool>
</dictionary>
<vector2> 0.1, 0.4 </vector2>
- <resource resource_type="ImageTexture" path="res://art/box.*"> </resource>
- <color> 1, 1, 1, 1 </color>
- <rect2> 0, 0, 0, 0 </rect2>
+ <resource external="0"> </resource>
+ <int> -1 </int>
<vector2> 0, 26.9432 </vector2>
<matrix32> 1, -0, 0, 1, 0, 0 </matrix32>
<dictionary shared="false">
@@ -215,18 +253,16 @@
<node_path> "../union_ 4" </node_path>
<vector2> 0, 106.787 </vector2>
<vector2> 0.98476, 1 </vector2>
- <resource resource_type="CircleShape2D" path="local://2"> </resource>
+ <resource resource_type="Shape2D" path="local://2"> </resource>
<vector2> 0.5, 0.5 </vector2>
- <resource resource_type="ImageTexture" path="res://art/bowling_ball.*"> </resource>
+ <resource external="1"> </resource>
<vector2> 0, 92.5287 </vector2>
<node_path> "../ball" </node_path>
<vector2> 0, -12.1024 </vector2>
<node_path> "" </node_path>
</array>
- <string> "nodes" </string>
- <int_array len="773"> -1, -1, 1, 0, -1, 8, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 9, 5, 0, 0, 0, 11, 10, -1, 24, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 12, 6, 13, 7, 14, 8, 15, 9, 16, 10, 17, 11, 18, 1, 19, 3, 20, 9, 21, 9, 22, 10, 23, 9, 24, 0, 25, 0, 26, 2, 27, 3, 9, 12, 0, 1, 0, 28, 28, -1, 18, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 13, 29, 14, 30, 0, 31, 2, 32, 9, 33, 9, 34, 6, 35, 6, 36, 10, 37, 15, 38, 9, 39, 16, 0, 1, 0, 41, 40, -1, 9, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 42, 7, 43, 9, 0, 0, 0, 11, 44, -1, 24, 2, 0, 3, 1, 4, 1, 5, 0, 6, 17, 7, 3, 8, 4, 12, 6, 13, 7, 14, 18, 15, 9, 16, 10, 17, 11, 18, 1, 19, 3, 20, 9, 21, 9, 22, 10, 23, 9, 24, 0, 25, 0, 26, 2, 27, 3, 9, 19, 0, 4, 0, 28, 28, -1, 18, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 13, 29, 14, 30, 0, 31, 2, 32, 9, 33, 9, 34, 6, 35, 6, 36, 10, 37, 15, 38, 9, 39, 16, 0, 4, 0, 41, 40, -1, 9, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 42, 7, 43, 9, 0, 0, 0, 11, 45, -1, 24, 2, 0, 3, 1, 4, 1, 5, 0, 6, 20, 7, 3, 8, 4, 12, 6, 13, 7, 14, 18, 15, 9, 16, 10, 17, 11, 18, 1, 19, 3, 20, 9, 21, 9, 22, 10, 23, 9, 24, 0, 25, 0, 26, 2, 27, 3, 9, 19, 0, 7, 0, 28, 28, -1, 18, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 13, 29, 14, 30, 0, 31, 2, 32, 9, 33, 9, 34, 6, 35, 6, 36, 10, 37, 15, 38, 9, 39, 16, 0, 7, 0, 41, 40, -1, 9, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 42, 7, 43, 9, 0, 0, 0, 11, 46, -1, 24, 2, 0, 3, 1, 4, 1, 5, 0, 6, 21, 7, 3, 8, 4, 12, 6, 13, 7, 14, 18, 15, 9, 16, 10, 17, 11, 18, 1, 19, 3, 20, 9, 21, 9, 22, 10, 23, 9, 24, 0, 25, 0, 26, 2, 27, 3, 9, 19, 0, 10, 0, 28, 28, -1, 18, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 13, 29, 14, 30, 0, 31, 2, 32, 9, 33, 9, 34, 6, 35, 6, 36, 10, 37, 15, 38, 9, 39, 16, 0, 10, 0, 41, 40, -1, 9, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 42, 7, 43, 9, 0, 0, 0, 48, 47, -1, 10, 2, 0, 3, 1, 4, 1, 5, 0, 6, 22, 7, 3, 8, 4, 49, 23, 50, 24, 51, 3, 0, 0, 0, 48, 52, -1, 10, 2, 0, 3, 1, 4, 1, 5, 0, 6, 25, 7, 3, 8, 4, 49, 24, 50, 26, 51, 3, 0, 0, 0, 48, 53, -1, 10, 2, 0, 3, 1, 4, 1, 5, 0, 6, 27, 7, 3, 8, 4, 49, 26, 50, 28, 51, 11, 0, 0, 0, 11, 54, -1, 24, 2, 0, 3, 1, 4, 1, 5, 0, 6, 29, 7, 3, 8, 30, 12, 6, 13, 31, 14, 18, 15, 9, 16, 10, 17, 11, 18, 1, 19, 3, 20, 9, 21, 9, 22, 10, 23, 9, 24, 0, 25, 0, 26, 2, 27, 3, 9, 19, 0, 16, 0, 28, 28, -1, 18, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 32, 29, 33, 30, 0, 31, 2, 32, 9, 33, 9, 34, 6, 35, 6, 36, 10, 37, 15, 38, 9, 39, 16, 0, 16, 0, 41, 40, -1, 9, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 42, 31, 43, 9, 0, 0, 0, 48, 55, -1, 10, 2, 0, 3, 1, 4, 1, 5, 0, 6, 34, 7, 3, 8, 4, 49, 28, 50, 35, 51, 3, 0, 0, 0, 48, 56, -1, 10, 2, 0, 3, 1, 4, 1, 5, 0, 6, 36, 7, 3, 8, 4, 49, 23, 50, 37, 51, 3, 0 </int_array>
- <string> "conns" </string>
- <int_array len="0"> </int_array>
+ <string> "version" </string>
+ <int> 2 </int>
</dictionary>
</main_resource>
diff --git a/demos/2d/rubegoldberg/platform.xml b/demos/2d/rubegoldberg/platform.xml
index 0cc8f4b137..09cd0fdda6 100644
--- a/demos/2d/rubegoldberg/platform.xml
+++ b/demos/2d/rubegoldberg/platform.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="3" version="0.99" version_name="Godot Engine v0.99.3735-pre-beta">
- <ext_resource path="res://art/platform.*" type="ImageTexture"></ext_resource>
+<resource_file type="PackedScene" subresource_count="3" version="2.0" version_name="Godot Engine v2.0.alpha.custom_build">
+ <ext_resource path="res://art/platform.png" type="Texture" index="0"></ext_resource>
<resource type="RectangleShape2D" path="local://1">
<real name="custom_solver_bias"> 0 </real>
<vector2 name="extents"> 128, 16 </vector2>
@@ -8,148 +8,178 @@
</resource>
<main_resource>
<dictionary name="_bundled" shared="false">
+ <string> "conn_count" </string>
+ <int> 0 </int>
+ <string> "conns" </string>
+ <int_array len="0"> </int_array>
+ <string> "editable_instances" </string>
+ <array len="0" shared="false">
+ </array>
<string> "names" </string>
- <string_array len="34">
+ <string_array len="19">
<string> "platform" </string>
- <string> "StaticBody2D" </string>
- <string> "visibility/visible" </string>
- <string> "visibility/opacity" </string>
- <string> "visibility/self_opacity" </string>
- <string> "visibility/on_top" </string>
- <string> "transform/pos" </string>
- <string> "transform/rot" </string>
- <string> "transform/scale" </string>
- <string> "shape_count" </string>
+ <string> "input/pickable" </string>
<string> "shapes/0/shape" </string>
<string> "shapes/0/transform" </string>
<string> "shapes/0/trigger" </string>
- <string> "simulate_motion" </string>
+ <string> "collision/layers" </string>
+ <string> "collision/mask" </string>
<string> "constant_linear_velocity" </string>
<string> "constant_angular_velocity" </string>
<string> "friction" </string>
<string> "bounce" </string>
<string> "__meta__" </string>
+ <string> "StaticBody2D" </string>
<string> "Sprite" </string>
<string> "texture" </string>
- <string> "centered" </string>
- <string> "offset" </string>
- <string> "flip_h" </string>
- <string> "flip_v" </string>
- <string> "vframes" </string>
- <string> "hframes" </string>
- <string> "frame" </string>
- <string> "modulate" </string>
- <string> "region" </string>
- <string> "region_rect" </string>
<string> "CollisionShape2D" </string>
<string> "shape" </string>
<string> "trigger" </string>
+ <string> "_update_shape_index" </string>
</string_array>
- <string> "version" </string>
- <int> 1 </int>
- <string> "conn_count" </string>
- <int> 0 </int>
<string> "node_count" </string>
<int> 3 </int>
+ <string> "node_paths" </string>
+ <array len="0" shared="false">
+ </array>
+ <string> "nodes" </string>
+ <int_array len="51"> -1, -1, 12, 0, -1, 11, 1, 0, 2, 1, 3, 2, 4, 0, 5, 3, 6, 3, 7, 4, 8, 5, 9, 6, 10, 5, 11, 7, 0, 0, 0, 13, 13, -1, 1, 14, 8, 0, 0, 0, 15, 15, -1, 3, 16, 1, 17, 0, 18, 9, 0 </int_array>
<string> "variants" </string>
- <array len="14" shared="false">
- <bool> True </bool>
- <real> 1 </real>
+ <array len="10" shared="false">
+ <bool> False </bool>
+ <resource resource_type="Shape2D" path="local://1"> </resource>
+ <matrix32> 1, 0, 0, 1, 0, 0 </matrix32>
+ <int> 1 </int>
<vector2> 0, 0 </vector2>
<real> 0 </real>
- <vector2> 1, 1 </vector2>
- <int> 1 </int>
- <resource resource_type="RectangleShape2D" path="local://1"> </resource>
- <matrix32> 1, 0, 0, 1, 0, 0 </matrix32>
- <bool> False </bool>
+ <real> 1 </real>
<dictionary shared="false">
+ <string> "__editor_plugin_screen__" </string>
+ <string> "2D" </string>
<string> "__editor_plugin_states__" </string>
<dictionary shared="false">
<string> "2D" </string>
<dictionary shared="false">
- <string> "pixel_snap" </string>
+ <string> "ofs" </string>
+ <vector2> -135, -114 </vector2>
+ <string> "snap_grid" </string>
+ <bool> False </bool>
+ <string> "snap_offset" </string>
+ <vector2> 0, 0 </vector2>
+ <string> "snap_pixel" </string>
+ <bool> False </bool>
+ <string> "snap_relative" </string>
+ <bool> False </bool>
+ <string> "snap_rotation" </string>
+ <bool> False </bool>
+ <string> "snap_rotation_offset" </string>
+ <real> 0 </real>
+ <string> "snap_rotation_step" </string>
+ <real> 0.261799 </real>
+ <string> "snap_show_grid" </string>
<bool> False </bool>
+ <string> "snap_step" </string>
+ <vector2> 10, 10 </vector2>
<string> "zoom" </string>
<real> 1 </real>
- <string> "ofs" </string>
- <vector2> -135, -114 </vector2>
</dictionary>
<string> "3D" </string>
<dictionary shared="false">
- <string> "zfar" </string>
- <real> 500 </real>
+ <string> "ambient_light_color" </string>
+ <color> 0.15, 0.15, 0.15, 1 </color>
+ <string> "default_light" </string>
+ <bool> True </bool>
+ <string> "default_srgb" </string>
+ <bool> False </bool>
+ <string> "deflight_rot_x" </string>
+ <real> 0.942478 </real>
+ <string> "deflight_rot_y" </string>
+ <real> 0.628319 </real>
<string> "fov" </string>
<real> 45 </real>
+ <string> "show_grid" </string>
+ <bool> True </bool>
+ <string> "show_origin" </string>
+ <bool> True </bool>
+ <string> "viewport_mode" </string>
+ <int> 1 </int>
<string> "viewports" </string>
<array len="4" shared="false">
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> True </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
</array>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
+ <string> "zfar" </string>
+ <real> 500 </real>
<string> "znear" </string>
<real> 0.1 </real>
</dictionary>
+ <string> "Anim" </string>
+ <dictionary shared="false">
+ <string> "visible" </string>
+ <bool> False </bool>
+ </dictionary>
</dictionary>
<string> "__editor_run_settings__" </string>
<dictionary shared="false">
@@ -158,18 +188,12 @@
<string> "run_mode" </string>
<int> 0 </int>
</dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "2D" </string>
</dictionary>
- <resource resource_type="ImageTexture" path="res://art/platform.*"> </resource>
- <int> 0 </int>
- <color> 1, 1, 1, 1 </color>
- <rect2> 0, 0, 0, 0 </rect2>
+ <resource external="0"> </resource>
+ <int> -1 </int>
</array>
- <string> "nodes" </string>
- <int_array len="109"> -1, -1, 1, 0, -1, 17, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 11, 7, 12, 8, 13, 8, 14, 2, 15, 3, 16, 1, 17, 3, 18, 9, 0, 0, 0, 19, 19, -1, 18, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 20, 10, 21, 0, 22, 2, 23, 8, 24, 8, 25, 5, 26, 5, 27, 11, 28, 12, 29, 8, 30, 13, 0, 0, 0, 31, 31, -1, 9, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 32, 6, 33, 8, 0 </int_array>
- <string> "conns" </string>
- <int_array len="0"> </int_array>
+ <string> "version" </string>
+ <int> 2 </int>
</dictionary>
</main_resource>
diff --git a/demos/2d/rubegoldberg/rubegoldberg.xml b/demos/2d/rubegoldberg/rubegoldberg.xml
index edb6dda0e1..490b0f9d34 100644
--- a/demos/2d/rubegoldberg/rubegoldberg.xml
+++ b/demos/2d/rubegoldberg/rubegoldberg.xml
@@ -1,25 +1,37 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="7" version="0.99" version_name="Godot Engine v0.99.3735-pre-beta">
- <ext_resource path="res://platform.*" type="PackedScene"></ext_resource>
- <ext_resource path="res://ball.*" type="PackedScene"></ext_resource>
- <ext_resource path="res://domino.*" type="PackedScene"></ext_resource>
- <ext_resource path="res://seesaw.*" type="PackedScene"></ext_resource>
- <ext_resource path="res://box.*" type="PackedScene"></ext_resource>
- <ext_resource path="res://pendulum.*" type="PackedScene"></ext_resource>
+<resource_file type="PackedScene" subresource_count="7" version="2.0" version_name="Godot Engine v2.0.alpha.custom_build">
+ <ext_resource path="res://platform.xml" type="PackedScene" index="0"></ext_resource>
+ <ext_resource path="res://seesaw.xml" type="PackedScene" index="3"></ext_resource>
+ <ext_resource path="res://pendulum.xml" type="PackedScene" index="5"></ext_resource>
+ <ext_resource path="res://box.xml" type="PackedScene" index="4"></ext_resource>
+ <ext_resource path="res://ball.xml" type="PackedScene" index="1"></ext_resource>
+ <ext_resource path="res://domino.xml" type="PackedScene" index="2"></ext_resource>
<main_resource>
<dictionary name="_bundled" shared="false">
+ <string> "conn_count" </string>
+ <int> 0 </int>
+ <string> "conns" </string>
+ <int_array len="0"> </int_array>
+ <string> "editable_instances" </string>
+ <array len="0" shared="false">
+ </array>
<string> "names" </string>
- <string_array len="29">
+ <string_array len="33">
<string> "Node" </string>
<string> "__meta__" </string>
<string> "platform" </string>
- <string> "StaticBody2D" </string>
<string> "transform/pos" </string>
<string> "transform/rot" </string>
+ <string> "input/pickable" </string>
+ <string> "collision/layers" </string>
+ <string> "collision/mask" </string>
<string> "platform 2" </string>
<string> "platform 3" </string>
<string> "Ball" </string>
- <string> "RigidBody2D" </string>
+ <string> "gravity_scale" </string>
+ <string> "sleeping" </string>
+ <string> "damp_override/linear" </string>
+ <string> "damp_override/angular" </string>
<string> "domino" </string>
<string> "domino 2" </string>
<string> "domino 4" </string>
@@ -31,7 +43,6 @@
<string> "platform 7" </string>
<string> "platform 8" </string>
<string> "SeeSaw" </string>
- <string> "Node2D" </string>
<string> "box" </string>
<string> "pendulum" </string>
<string> "pendulum 2" </string>
@@ -40,102 +51,142 @@
<string> "Ball 5" </string>
<string> "velocity/linear" </string>
</string_array>
- <string> "version" </string>
- <int> 1 </int>
- <string> "conn_count" </string>
- <int> 0 </int>
<string> "node_count" </string>
<int> 21 </int>
+ <string> "node_paths" </string>
+ <array len="0" shared="false">
+ </array>
+ <string> "nodes" </string>
+ <int_array len="347"> -1, -1, 0, 0, -1, 1, 1, 0, 0, 0, 0, 2147483647, 2, 1, 5, 3, 2, 4, 3, 5, 4, 6, 5, 7, 5, 0, 0, 0, 2147483647, 8, 1, 4, 3, 6, 5, 4, 6, 5, 7, 5, 0, 0, 0, 2147483647, 9, 1, 4, 3, 7, 5, 4, 6, 5, 7, 5, 0, 0, 0, 2147483647, 10, 8, 8, 3, 9, 5, 4, 6, 5, 7, 5, 11, 10, 12, 4, 13, 11, 14, 11, 0, 0, 0, 2147483647, 15, 12, 8, 3, 13, 5, 4, 6, 5, 7, 5, 11, 10, 12, 4, 13, 11, 14, 11, 0, 0, 0, 2147483647, 16, 12, 8, 3, 14, 5, 4, 6, 5, 7, 5, 11, 10, 12, 4, 13, 11, 14, 11, 0, 0, 0, 2147483647, 17, 12, 8, 3, 15, 5, 4, 6, 5, 7, 5, 11, 10, 12, 4, 13, 11, 14, 11, 0, 0, 0, 2147483647, 18, 1, 5, 3, 16, 4, 17, 5, 4, 6, 5, 7, 5, 0, 0, 0, 2147483647, 19, 1, 6, 3, 18, 4, 19, 20, 20, 5, 4, 6, 5, 7, 5, 0, 0, 0, 2147483647, 21, 8, 8, 3, 21, 5, 4, 6, 5, 7, 5, 11, 10, 12, 4, 13, 11, 14, 11, 0, 0, 0, 2147483647, 22, 1, 4, 3, 22, 5, 4, 6, 5, 7, 5, 0, 0, 0, 2147483647, 23, 1, 4, 3, 23, 5, 4, 6, 5, 7, 5, 0, 0, 0, 2147483647, 24, 1, 4, 3, 24, 5, 4, 6, 5, 7, 5, 0, 0, 0, 2147483647, 25, 25, 1, 3, 26, 0, 0, 0, 2147483647, 26, 27, 9, 3, 28, 4, 29, 5, 4, 6, 5, 7, 5, 11, 10, 12, 4, 13, 11, 14, 11, 0, 0, 0, 2147483647, 27, 30, 1, 3, 31, 0, 0, 0, 2147483647, 28, 30, 1, 3, 32, 0, 0, 0, 2147483647, 29, 30, 1, 3, 33, 0, 0, 0, 2147483647, 30, 30, 1, 3, 34, 0, 0, 0, 2147483647, 31, 8, 9, 3, 35, 5, 4, 6, 5, 7, 5, 11, 10, 12, 4, 32, 36, 13, 11, 14, 11, 0 </int_array>
<string> "variants" </string>
- <array len="33" shared="false">
+ <array len="37" shared="false">
<dictionary shared="false">
+ <string> "__editor_plugin_screen__" </string>
+ <string> "2D" </string>
<string> "__editor_plugin_states__" </string>
<dictionary shared="false">
<string> "2D" </string>
<dictionary shared="false">
- <string> "pixel_snap" </string>
+ <string> "ofs" </string>
+ <vector2> -717.096, -249.162 </vector2>
+ <string> "snap_grid" </string>
<bool> False </bool>
+ <string> "snap_offset" </string>
+ <vector2> 0, 0 </vector2>
+ <string> "snap_pixel" </string>
+ <bool> False </bool>
+ <string> "snap_relative" </string>
+ <bool> False </bool>
+ <string> "snap_rotation" </string>
+ <bool> False </bool>
+ <string> "snap_rotation_offset" </string>
+ <real> 0 </real>
+ <string> "snap_rotation_step" </string>
+ <real> 0.261799 </real>
+ <string> "snap_show_grid" </string>
+ <bool> False </bool>
+ <string> "snap_step" </string>
+ <vector2> 10, 10 </vector2>
<string> "zoom" </string>
<real> 0.598737 </real>
- <string> "ofs" </string>
- <vector2> -15.4883, -75.0379 </vector2>
</dictionary>
<string> "3D" </string>
<dictionary shared="false">
- <string> "zfar" </string>
- <real> 500 </real>
+ <string> "ambient_light_color" </string>
+ <color> 0.15, 0.15, 0.15, 1 </color>
+ <string> "default_light" </string>
+ <bool> True </bool>
+ <string> "default_srgb" </string>
+ <bool> False </bool>
+ <string> "deflight_rot_x" </string>
+ <real> 0.942478 </real>
+ <string> "deflight_rot_y" </string>
+ <real> 0.628319 </real>
<string> "fov" </string>
<real> 45 </real>
+ <string> "show_grid" </string>
+ <bool> True </bool>
+ <string> "show_origin" </string>
+ <bool> True </bool>
+ <string> "viewport_mode" </string>
+ <int> 1 </int>
<string> "viewports" </string>
<array len="4" shared="false">
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> True </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
</array>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
+ <string> "zfar" </string>
+ <real> 500 </real>
<string> "znear" </string>
<real> 0.1 </real>
</dictionary>
+ <string> "Anim" </string>
+ <dictionary shared="false">
+ <string> "visible" </string>
+ <bool> False </bool>
+ </dictionary>
</dictionary>
<string> "__editor_run_settings__" </string>
<dictionary shared="false">
@@ -144,17 +195,19 @@
<string> "run_mode" </string>
<int> 0 </int>
</dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "2D" </string>
</dictionary>
- <resource resource_type="PackedScene" path="res://platform.*"> </resource>
+ <resource external="0"> </resource>
<vector2> 116.881, 145.589 </vector2>
<real> -20.87962 </real>
+ <bool> False </bool>
+ <int> 1 </int>
<vector2> 336.29, 264.52 </vector2>
<vector2> 526.99, 264.52 </vector2>
- <resource resource_type="PackedScene" path="res://ball.*"> </resource>
+ <resource external="1"> </resource>
<vector2> 76.0801, 67.2141 </vector2>
- <resource resource_type="PackedScene" path="res://domino.*"> </resource>
+ <real> 1 </real>
+ <real> -1 </real>
+ <resource external="2"> </resource>
<vector2> 262.764, 182.008 </vector2>
<vector2> 356.951, 182.008 </vector2>
<vector2> 448.834, 179.291 </vector2>
@@ -167,12 +220,12 @@
<vector2> 679.231, 588.598 </vector2>
<vector2> 424.491, 588.598 </vector2>
<vector2> 185.655, 588.598 </vector2>
- <resource resource_type="PackedScene" path="res://seesaw.*"> </resource>
+ <resource external="3"> </resource>
<vector2> 602.935, 554.501 </vector2>
- <resource resource_type="PackedScene" path="res://box.*"> </resource>
+ <resource external="4"> </resource>
<vector2> 476.002, 509.406 </vector2>
<real> 21.737282 </real>
- <resource resource_type="PackedScene" path="res://pendulum.*"> </resource>
+ <resource external="5"> </resource>
<vector2> 391.607, 305.444 </vector2>
<vector2> 343.172, 303.774 </vector2>
<vector2> 288.056, 303.774 </vector2>
@@ -180,10 +233,8 @@
<vector2> 116.165, 526.515 </vector2>
<vector2> 0, -200 </vector2>
</array>
- <string> "nodes" </string>
- <int_array len="201"> -1, -1, 0, 0, -1, 1, 1, 0, 0, 0, 0, 3, 2, 1, 2, 4, 2, 5, 3, 0, 0, 0, 3, 6, 1, 1, 4, 4, 0, 0, 0, 3, 7, 1, 1, 4, 5, 0, 0, 0, 9, 8, 6, 1, 4, 7, 0, 0, 0, 9, 10, 8, 1, 4, 9, 0, 0, 0, 9, 11, 8, 1, 4, 10, 0, 0, 0, 9, 12, 8, 1, 4, 11, 0, 0, 0, 3, 13, 1, 2, 4, 12, 5, 13, 0, 0, 0, 3, 14, 1, 3, 4, 14, 5, 15, 15, 16, 0, 0, 0, 9, 16, 6, 1, 4, 17, 0, 0, 0, 3, 17, 1, 1, 4, 18, 0, 0, 0, 3, 18, 1, 1, 4, 19, 0, 0, 0, 3, 19, 1, 1, 4, 20, 0, 0, 0, 21, 20, 21, 1, 4, 22, 0, 0, 0, 9, 22, 23, 2, 4, 24, 5, 25, 0, 0, 0, 21, 23, 26, 1, 4, 27, 0, 0, 0, 21, 24, 26, 1, 4, 28, 0, 0, 0, 21, 25, 26, 1, 4, 29, 0, 0, 0, 21, 26, 26, 1, 4, 30, 0, 0, 0, 9, 27, 6, 2, 4, 31, 28, 32, 0 </int_array>
- <string> "conns" </string>
- <int_array len="0"> </int_array>
+ <string> "version" </string>
+ <int> 2 </int>
</dictionary>
</main_resource>
diff --git a/demos/2d/rubegoldberg/seesaw.xml b/demos/2d/rubegoldberg/seesaw.xml
index 30edbe9162..281e4e7c0d 100644
--- a/demos/2d/rubegoldberg/seesaw.xml
+++ b/demos/2d/rubegoldberg/seesaw.xml
@@ -1,169 +1,243 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="5" version="0.99" version_name="Godot Engine v0.99.2864-pre-beta">
- <ext_resource path="res://art/seesaw_top.png" type="Texture"></ext_resource>
- <ext_resource path="res://art/seesaw_base.png" type="Texture"></ext_resource>
+<resource_file type="PackedScene" subresource_count="5" version="2.0" version_name="Godot Engine v2.0.alpha.custom_build">
+ <ext_resource path="res://art/seesaw_top.png" type="Texture" index="1"></ext_resource>
+ <ext_resource path="res://art/seesaw_base.png" type="Texture" index="0"></ext_resource>
<resource type="ConcavePolygonShape2D" path="local://1">
- <string name="resource/name"> "" </string>
<real name="custom_solver_bias"> 0 </real>
<vector2_array name="segments" len="6"> -32.6231, 32.0838, -1.28218, -31.1383, -1.28218, -31.1383, 33.8412, 33.1645, 33.8412, 33.1645, -32.6231, 32.0838 </vector2_array>
- <resource name="script/script"></resource>
+
</resource>
<resource type="ConvexPolygonShape2D" path="local://2">
- <string name="resource/name"> "" </string>
<real name="custom_solver_bias"> 0 </real>
<vector2_array name="points" len="4"> -99.0874, 7.76759, -125.025, -8.98358, 125.162, -8.44321, 99.2248, 7.22723 </vector2_array>
- <resource name="script/script"></resource>
+
</resource>
<main_resource>
- <string name="resource/name"> "" </string>
- <dictionary name="_bundled">
+ <dictionary name="_bundled" shared="false">
+ <string> "conn_count" </string>
+ <int> 0 </int>
+ <string> "conns" </string>
+ <int_array len="0"> </int_array>
+ <string> "editable_instances" </string>
+ <array len="0" shared="false">
+ </array>
<string> "names" </string>
- <string_array len="58">
+ <string_array len="43">
<string> "SeeSaw" </string>
- <string> "Node2D" </string>
- <string> "process/process" </string>
- <string> "process/fixed_process" </string>
- <string> "process/input" </string>
- <string> "process/unhandled_input" </string>
- <string> "process/mode" </string>
- <string> "visibility/visible" </string>
- <string> "visibility/toplevel" </string>
- <string> "visibility/opacity" </string>
- <string> "visibility/self_opacity" </string>
- <string> "visibility/on_top" </string>
- <string> "visibility/blend_mode" </string>
- <string> "transform/notify" </string>
- <string> "transform/pos" </string>
- <string> "transform/rot" </string>
- <string> "transform/scale" </string>
- <string> "script/script" </string>
<string> "__meta__" </string>
+ <string> "Node2D" </string>
<string> "Sprite" </string>
<string> "texture" </string>
- <string> "centered" </string>
- <string> "offset" </string>
- <string> "flip_h" </string>
- <string> "flip_v" </string>
- <string> "vframes" </string>
- <string> "hframes" </string>
- <string> "frame" </string>
- <string> "modulate" </string>
- <string> "region" </string>
- <string> "region_rect" </string>
<string> "StaticBody2D" </string>
- <string> "shape_count" </string>
+ <string> "input/pickable" </string>
<string> "shapes/0/shape" </string>
<string> "shapes/0/transform" </string>
- <string> "simulate_motion" </string>
+ <string> "shapes/0/trigger" </string>
+ <string> "collision/layers" </string>
+ <string> "collision/mask" </string>
<string> "constant_linear_velocity" </string>
<string> "constant_angular_velocity" </string>
+ <string> "friction" </string>
+ <string> "bounce" </string>
<string> "CollisionPolygon2D" </string>
<string> "build_mode" </string>
<string> "polygon" </string>
+ <string> "shape_range" </string>
+ <string> "trigger" </string>
<string> "RigidBody2D" </string>
+ <string> "transform/pos" </string>
+ <string> "transform/rot" </string>
<string> "mode" </string>
<string> "mass" </string>
- <string> "friction" </string>
- <string> "bounce" </string>
+ <string> "gravity_scale" </string>
<string> "custom_integrator" </string>
<string> "continuous_cd" </string>
<string> "contacts_reported" </string>
<string> "contact_monitor" </string>
- <string> "active" </string>
+ <string> "sleeping" </string>
<string> "can_sleep" </string>
<string> "velocity/linear" </string>
<string> "velocity/angular" </string>
+ <string> "damp_override/linear" </string>
+ <string> "damp_override/angular" </string>
+ <string> "transform/scale" </string>
<string> "PinJoint2D" </string>
<string> "node_a" </string>
<string> "node_b" </string>
<string> "bias/bias" </string>
+ <string> "softness" </string>
</string_array>
- <string> "version" </string>
- <int> 1 </int>
- <string> "conn_count" </string>
- <int> 0 </int>
<string> "node_count" </string>
<int> 8 </int>
+ <string> "node_paths" </string>
+ <array len="0" shared="false">
+ </array>
+ <string> "nodes" </string>
+ <int_array len="156"> -1, -1, 2, 0, -1, 1, 1, 0, 0, 0, 0, 3, 3, -1, 1, 4, 1, 0, 1, 0, 5, 5, -1, 10, 6, 2, 7, 3, 8, 4, 9, 2, 10, 5, 11, 5, 12, 6, 13, 7, 14, 8, 15, 7, 0, 2, 0, 16, 16, -1, 4, 17, 9, 18, 10, 19, 11, 20, 2, 0, 0, 0, 21, 21, -1, 23, 22, 12, 23, 13, 6, 2, 7, 14, 8, 4, 9, 2, 10, 5, 11, 5, 24, 9, 25, 8, 14, 8, 15, 7, 26, 8, 27, 2, 28, 9, 29, 9, 30, 2, 31, 2, 32, 15, 33, 6, 34, 7, 35, 16, 36, 16, 0, 4, 0, 3, 3, -1, 2, 37, 17, 4, 18, 0, 4, 0, 16, 16, -1, 4, 17, 9, 18, 19, 19, 11, 20, 2, 0, 0, 0, 38, 38, -1, 5, 22, 20, 39, 21, 40, 22, 41, 7, 42, 7, 0 </int_array>
<string> "variants" </string>
- <array len="25">
- <bool> False </bool>
- <int> 0 </int>
- <bool> True </bool>
- <real> 1 </real>
- <vector2> 0, 0 </vector2>
- <real> 0 </real>
- <vector2> 1, 1 </vector2>
- <resource name=""></resource> <dictionary>
+ <array len="23" shared="false">
+ <dictionary shared="false">
+ <string> "__editor_plugin_screen__" </string>
+ <string> "2D" </string>
<string> "__editor_plugin_states__" </string>
- <dictionary>
+ <dictionary shared="false">
<string> "2D" </string>
- <dictionary>
- <string> "zoom" </string>
- <real> 1.670183 </real>
+ <dictionary shared="false">
<string> "ofs" </string>
<vector2> -277.779, -292.484 </vector2>
+ <string> "snap_grid" </string>
+ <bool> False </bool>
+ <string> "snap_offset" </string>
+ <vector2> 0, 0 </vector2>
+ <string> "snap_pixel" </string>
+ <bool> False </bool>
+ <string> "snap_relative" </string>
+ <bool> False </bool>
+ <string> "snap_rotation" </string>
+ <bool> False </bool>
+ <string> "snap_rotation_offset" </string>
+ <real> 0 </real>
+ <string> "snap_rotation_step" </string>
+ <real> 0.261799 </real>
+ <string> "snap_show_grid" </string>
+ <bool> False </bool>
+ <string> "snap_step" </string>
+ <vector2> 10, 10 </vector2>
+ <string> "zoom" </string>
+ <real> 1.670183 </real>
</dictionary>
<string> "3D" </string>
- <dictionary>
- <string> "zfar" </string>
- <real> 500 </real>
+ <dictionary shared="false">
+ <string> "ambient_light_color" </string>
+ <color> 0.15, 0.15, 0.15, 1 </color>
+ <string> "default_light" </string>
+ <bool> True </bool>
+ <string> "default_srgb" </string>
+ <bool> False </bool>
+ <string> "deflight_rot_x" </string>
+ <real> 0.942478 </real>
+ <string> "deflight_rot_y" </string>
+ <real> 0.628319 </real>
<string> "fov" </string>
<real> 45 </real>
- <string> "window_mode" </string>
- <int> 0 </int>
- <string> "window_0" </string>
- <dictionary>
- <string> "distance" </string>
- <real> 4 </real>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "x_rot" </string>
- <real> 0.337 </real>
- <string> "y_rot" </string>
- <real> -0.575 </real>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
+ <string> "show_grid" </string>
+ <bool> True </bool>
+ <string> "show_origin" </string>
+ <bool> True </bool>
+ <string> "viewport_mode" </string>
+ <int> 1 </int>
+ <string> "viewports" </string>
+ <array len="4" shared="false">
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
+ <string> "listener" </string>
+ <bool> True </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
+ <string> "x_rot" </string>
+ <real> 0 </real>
+ <string> "y_rot" </string>
+ <real> 0 </real>
+ </dictionary>
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
+ <string> "x_rot" </string>
+ <real> 0 </real>
+ <string> "y_rot" </string>
+ <real> 0 </real>
+ </dictionary>
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
+ <string> "x_rot" </string>
+ <real> 0 </real>
+ <string> "y_rot" </string>
+ <real> 0 </real>
+ </dictionary>
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
+ <string> "x_rot" </string>
+ <real> 0 </real>
+ <string> "y_rot" </string>
+ <real> 0 </real>
+ </dictionary>
+ </array>
+ <string> "zfar" </string>
+ <real> 500 </real>
<string> "znear" </string>
<real> 0.1 </real>
</dictionary>
+ <string> "Anim" </string>
+ <dictionary shared="false">
+ <string> "visible" </string>
+ <bool> False </bool>
+ </dictionary>
</dictionary>
<string> "__editor_run_settings__" </string>
- <dictionary>
+ <dictionary shared="false">
<string> "custom_args" </string>
<string> "-l $scene" </string>
<string> "run_mode" </string>
<int> 0 </int>
</dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "2D" </string>
</dictionary>
- <resource resource_type="Texture" path="res://art/seesaw_base.png"> </resource>
- <int> 1 </int>
- <color> 1, 1, 1, 1 </color>
- <rect2> 0, 0, 0, 0 </rect2>
- <resource resource_type="ConcavePolygonShape2D" path="local://1"> </resource>
+ <resource external="0"> </resource>
+ <bool> False </bool>
+ <resource resource_type="Shape2D" path="local://1"> </resource>
<matrix32> 1, 0, 0, 1, 0, 0 </matrix32>
+ <int> 1 </int>
+ <vector2> 0, 0 </vector2>
+ <real> 0 </real>
+ <real> 1 </real>
+ <int> 0 </int>
<vector2_array len="3"> -32.6231, 32.0838, -1.28218, -31.1383, 33.8412, 33.1645 </vector2_array>
+ <vector2> -1, -1 </vector2>
<vector2> 1.19748, -29.9368 </vector2>
<real> 16.223282 </real>
- <resource resource_type="ConvexPolygonShape2D" path="local://2"> </resource>
+ <resource resource_type="Shape2D" path="local://2"> </resource>
+ <bool> True </bool>
+ <real> -1 </real>
<vector2> 1, 0.5 </vector2>
- <resource resource_type="Texture" path="res://art/seesaw_top.png"> </resource>
+ <resource external="1"> </resource>
<vector2_array len="4"> -125.025, -8.98358, 125.162, -8.44321, 99.2248, 7.22723, -99.0874, 7.76759 </vector2_array>
<vector2> 0, -31.1343 </vector2>
<node_path> "../RigidBody2D" </node_path>
<node_path> "../Sprite/StaticBody2D" </node_path>
</array>
- <string> "nodes" </string>
- <int_array len="414"> -1, -1, 1, 0, -1, 17, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 7, 2, 8, 0, 9, 3, 10, 3, 11, 2, 12, 1, 13, 0, 14, 4, 15, 5, 16, 6, 17, 7, 18, 8, 0, 0, 0, 19, 19, -1, 27, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 7, 2, 8, 0, 9, 3, 10, 3, 11, 2, 12, 1, 13, 0, 14, 4, 15, 5, 16, 6, 20, 9, 21, 2, 22, 4, 23, 0, 24, 0, 25, 10, 26, 10, 27, 1, 28, 11, 29, 0, 30, 12, 17, 7, 0, 1, 0, 31, 31, -1, 22, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 7, 2, 8, 0, 9, 3, 10, 3, 11, 2, 12, 1, 13, 2, 14, 4, 15, 5, 16, 6, 32, 10, 33, 13, 34, 14, 35, 0, 36, 4, 37, 5, 17, 7, 0, 2, 0, 38, 38, -1, 18, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 7, 2, 8, 0, 9, 3, 10, 3, 11, 2, 12, 1, 13, 2, 14, 4, 15, 5, 16, 6, 39, 1, 40, 15, 17, 7, 0, 0, 0, 41, 41, -1, 31, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 7, 2, 8, 0, 9, 3, 10, 3, 11, 2, 12, 1, 13, 2, 14, 16, 15, 17, 16, 6, 32, 10, 33, 18, 34, 14, 42, 1, 43, 3, 44, 3, 45, 5, 46, 0, 47, 0, 48, 1, 49, 0, 50, 2, 51, 2, 52, 4, 53, 5, 17, 7, 0, 4, 0, 19, 19, -1, 27, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 7, 2, 8, 0, 9, 3, 10, 3, 11, 2, 12, 1, 13, 0, 14, 4, 15, 5, 16, 19, 20, 20, 21, 2, 22, 4, 23, 0, 24, 0, 25, 10, 26, 10, 27, 1, 28, 11, 29, 0, 30, 12, 17, 7, 0, 4, 0, 38, 38, -1, 18, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 7, 2, 8, 0, 9, 3, 10, 3, 11, 2, 12, 1, 13, 2, 14, 4, 15, 5, 16, 6, 39, 1, 40, 21, 17, 7, 0, 0, 0, 54, 54, -1, 19, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 7, 2, 8, 0, 9, 3, 10, 3, 11, 2, 12, 1, 13, 0, 14, 22, 15, 5, 16, 6, 55, 23, 56, 24, 57, 5, 17, 7, 0 </int_array>
- <string> "conns" </string>
- <int_array len="0"> </int_array>
+ <string> "version" </string>
+ <int> 2 </int>
</dictionary>
- <resource name="script/script"></resource>
+
</main_resource>
</resource_file> \ No newline at end of file
diff --git a/demos/2d/screen_space_shaders/engine.cfg b/demos/2d/screen_space_shaders/engine.cfg
index 527e2f8f0a..383ca7bf11 100644
--- a/demos/2d/screen_space_shaders/engine.cfg
+++ b/demos/2d/screen_space_shaders/engine.cfg
@@ -2,6 +2,7 @@
name="Screen-Space Shaders"
main_scene="res://screen_shaders.scn"
+icon="res://icon.png"
[display]
diff --git a/demos/2d/screen_space_shaders/icon.png b/demos/2d/screen_space_shaders/icon.png
new file mode 100644
index 0000000000..e3cc049081
--- /dev/null
+++ b/demos/2d/screen_space_shaders/icon.png
Binary files differ
diff --git a/demos/2d/screen_space_shaders/screen_shaders.gd b/demos/2d/screen_space_shaders/screen_shaders.gd
index 4e8a548539..b847a9c923 100644
--- a/demos/2d/screen_space_shaders/screen_shaders.gd
+++ b/demos/2d/screen_space_shaders/screen_shaders.gd
@@ -1,32 +1,25 @@
extends Control
-# member variables here, example:
-# var a=2
-# var b="textvar"
func _ready():
- # Initialization here
for c in get_node("pictures").get_children():
- get_node("picture").add_item("PIC: "+c.get_name())
+ get_node("picture").add_item("PIC: " + c.get_name())
for c in get_node("effects").get_children():
- get_node("effect").add_item("FX: "+c.get_name())
- pass
+ get_node("effect").add_item("FX: " + c.get_name())
-
-
-func _on_picture_item_selected( ID ):
+func _on_picture_item_selected(ID):
for c in range(get_node("pictures").get_child_count()):
- if (ID==c):
+ if (ID == c):
get_node("pictures").get_child(c).show()
else:
get_node("pictures").get_child(c).hide()
-func _on_effect_item_selected( ID ):
+func _on_effect_item_selected(ID):
for c in range(get_node("effects").get_child_count()):
- if (ID==c):
+ if (ID == c):
get_node("effects").get_child(c).show()
else:
get_node("effects").get_child(c).hide()
diff --git a/demos/2d/screen_space_shaders/screen_shaders.scn b/demos/2d/screen_space_shaders/screen_shaders.scn
index fc2be96fc9..be12cef02d 100644
--- a/demos/2d/screen_space_shaders/screen_shaders.scn
+++ b/demos/2d/screen_space_shaders/screen_shaders.scn
Binary files differ
diff --git a/demos/2d/sdf_font/engine.cfg b/demos/2d/sdf_font/engine.cfg
index bdf26ce741..bf983041fa 100644
--- a/demos/2d/sdf_font/engine.cfg
+++ b/demos/2d/sdf_font/engine.cfg
@@ -2,3 +2,4 @@
name="Signed Distance Field Font"
main_scene="res://sdf.scn"
+icon="res://icon.png"
diff --git a/demos/2d/sdf_font/icon.png b/demos/2d/sdf_font/icon.png
new file mode 100644
index 0000000000..0c700ad77c
--- /dev/null
+++ b/demos/2d/sdf_font/icon.png
Binary files differ
diff --git a/demos/2d/sdf_font/sdf.scn b/demos/2d/sdf_font/sdf.scn
index 89d6245bf0..4880500d6d 100644
--- a/demos/2d/sdf_font/sdf.scn
+++ b/demos/2d/sdf_font/sdf.scn
Binary files differ
diff --git a/demos/2d/shower_of_bullets/bullets.gd b/demos/2d/shower_of_bullets/bullets.gd
index 79f4faaae6..e0eba2682a 100644
--- a/demos/2d/shower_of_bullets/bullets.gd
+++ b/demos/2d/shower_of_bullets/bullets.gd
@@ -4,73 +4,68 @@ extends Node2D
# This demo is an example of controling a high number of 2D objects with logic and collision without using scene nodes.
# This technique is a lot more efficient than using instancing and nodes, but requires more programming and is less visual
+# Member variables
const BULLET_COUNT = 500
const SPEED_MIN = 20
const SPEED_MAX = 50
-var bullets=[]
+var bullets = []
var shape
+
+# Inner classes
class Bullet:
var pos = Vector2()
var speed = 1.0
var body = RID()
-
-func _draw():
+func _draw():
var t = preload("res://bullet.png")
var tofs = -t.get_size()*0.5
for b in bullets:
- draw_texture(t,b.pos+tofs)
-
-
+ draw_texture(t, b.pos + tofs)
+
+
func _process(delta):
var width = get_viewport_rect().size.x*2.0
var mat = Matrix32()
for b in bullets:
- b.pos.x-=b.speed*delta
+ b.pos.x -= b.speed*delta
if (b.pos.x < -30):
- b.pos.x+=width
- mat.o=b.pos
-
- Physics2DServer.body_set_state(b.body,Physics2DServer.BODY_STATE_TRANSFORM,mat)
+ b.pos.x += width
+ mat.o = b.pos
+ Physics2DServer.body_set_state(b.body, Physics2DServer.BODY_STATE_TRANSFORM, mat)
+
update()
-
-
-func _ready():
- shape = Physics2DServer.shape_create(Physics2DServer.SHAPE_CIRCLE)
- Physics2DServer.shape_set_data(shape,8) #radius
+func _ready():
+ shape = Physics2DServer.shape_create(Physics2DServer.SHAPE_CIRCLE)
+ Physics2DServer.shape_set_data(shape, 8) # Radius
+
for i in range(BULLET_COUNT):
var b = Bullet.new()
- b.speed=rand_range(SPEED_MIN,SPEED_MAX)
+ b.speed = rand_range(SPEED_MIN, SPEED_MAX)
b.body = Physics2DServer.body_create(Physics2DServer.BODY_MODE_KINEMATIC)
- Physics2DServer.body_set_space(b.body,get_world_2d().get_space())
- Physics2DServer.body_add_shape(b.body,shape)
+ Physics2DServer.body_set_space(b.body, get_world_2d().get_space())
+ Physics2DServer.body_add_shape(b.body, shape)
- b.pos = Vector2( get_viewport_rect().size * Vector2(randf()*2.0,randf()) ) #twice as long
- b.pos.x += get_viewport_rect().size.x # start outside
+ b.pos = Vector2(get_viewport_rect().size * Vector2(randf()*2.0, randf())) # Twice as long
+ b.pos.x += get_viewport_rect().size.x # Start outside
var mat = Matrix32()
- mat.o=b.pos
- Physics2DServer.body_set_state(b.body,Physics2DServer.BODY_STATE_TRANSFORM,mat)
+ mat.o = b.pos
+ Physics2DServer.body_set_state(b.body, Physics2DServer.BODY_STATE_TRANSFORM, mat)
bullets.append(b)
-
-
- set_process(true)
-
+ set_process(true)
+
+
func _exit_tree():
for b in bullets:
Physics2DServer.free_rid(b.body)
Physics2DServer.free_rid(shape)
- # Initalization here
bullets.clear()
-
- pass
-
-
diff --git a/demos/2d/shower_of_bullets/shower.gd b/demos/2d/shower_of_bullets/shower.gd
index bba8431764..50c1109489 100644
--- a/demos/2d/shower_of_bullets/shower.gd
+++ b/demos/2d/shower_of_bullets/shower.gd
@@ -1,32 +1,25 @@
extends Node2D
-# member variables here, example:
-# var a=2
-# var b="textvar"
+# Member variables
+var touching = 0
-var touching=0
+func _input(event):
+ if (event.type == InputEvent.MOUSE_MOTION):
+ get_node("player").set_pos(event.pos - Vector2(0, 16))
-func _input(ev):
- if (ev.type==InputEvent.MOUSE_MOTION):
- get_node("player").set_pos(ev.pos-Vector2(0,16))
-
-
-func _on_player_body_enter_shape( body_id, body, body_shape, area_shape ):
-
- touching+=1
- if (touching==1):
+func _on_player_body_enter_shape(body_id, body, body_shape, area_shape):
+ touching += 1
+ if (touching == 1):
get_node("player/sprite").set_frame(1)
-func _on_player_body_exit_shape( body_id, body, body_shape, area_shape ):
-
- touching-=1
- if (touching==0):
+func _on_player_body_exit_shape(body_id, body, body_shape, area_shape):
+ touching -= 1
+ if (touching == 0):
get_node("player/sprite").set_frame(0)
func _ready():
set_process_input(true)
- pass
diff --git a/demos/2d/shower_of_bullets/shower.scn b/demos/2d/shower_of_bullets/shower.scn
index 648888d099..9e2181e9c6 100644
--- a/demos/2d/shower_of_bullets/shower.scn
+++ b/demos/2d/shower_of_bullets/shower.scn
Binary files differ
diff --git a/demos/2d/space_shooter/asteroid.gd b/demos/2d/space_shooter/asteroid.gd
index f21b9777bb..9f6734e122 100644
--- a/demos/2d/space_shooter/asteroid.gd
+++ b/demos/2d/space_shooter/asteroid.gd
@@ -1,49 +1,43 @@
extends Area2D
-# member variables here, example:
-# var a=2
-# var b="textvar"
+# Member variables
+const SPEED = -200
+const Y_RANDOM = 10
-const SPEED=-200
-const Y_RANDOM=10
+var points = 1
+var speed_y = 0.0
+var destroyed = false
-var points=1
-
-
-var speed_y=0.0
func _process(delta):
+ translate(Vector2(SPEED, speed_y)*delta)
- translate( Vector2(SPEED,speed_y) * delta )
func _ready():
- # Initialization here
- speed_y=rand_range(-Y_RANDOM,Y_RANDOM)
- pass
+ speed_y = rand_range(-Y_RANDOM, Y_RANDOM)
-var destroyed=false
func destroy():
if (destroyed):
- return
- destroyed=true
+ return
+ destroyed = true
get_node("anim").play("explode")
set_process(false)
get_node("sfx").play("sound_explode")
- #accum points
- get_node("/root/game_state").points+=1
-
+ # Accumulate points
+ get_node("/root/game_state").points += 1
+
+
func is_enemy():
- return not destroyed
-
+ return not destroyed
+
func _on_visibility_enter_screen():
set_process(true)
- #make it spin!
+ # Make it spin!
get_node("anim").play("spin")
-
+
func _on_visibility_exit_screen():
queue_free()
- pass # replace with function body
diff --git a/demos/2d/space_shooter/asteroid.scn b/demos/2d/space_shooter/asteroid.scn
index b881725ea4..6bca98cd30 100644
--- a/demos/2d/space_shooter/asteroid.scn
+++ b/demos/2d/space_shooter/asteroid.scn
Binary files differ
diff --git a/demos/2d/space_shooter/enemy1.gd b/demos/2d/space_shooter/enemy1.gd
index 051798742a..204995c05d 100644
--- a/demos/2d/space_shooter/enemy1.gd
+++ b/demos/2d/space_shooter/enemy1.gd
@@ -1,17 +1,15 @@
extends Area2D
-# member variables here, example:
-# var a=2
-# var b="textvar"
+# Member variables
+const SPEED = -200
+
+var destroyed=false
-const SPEED=-200
func _process(delta):
- get_parent().translate(Vector2(SPEED*delta,0))
+ get_parent().translate(Vector2(SPEED*delta, 0))
-
-var destroyed=false
func is_enemy():
return not destroyed
@@ -19,19 +17,20 @@ func is_enemy():
func destroy():
if (destroyed):
- return
- destroyed=true
+ return
+ destroyed = true
get_node("anim").play("explode")
- set_process(false)
+ set_process(false)
get_node("sfx").play("sound_explode")
- #accum points
- get_node("/root/game_state").points+=5
+ # Accumulate points
+ get_node("/root/game_state").points += 5
+
func _on_visibility_enter_screen():
set_process(true)
- get_node("anim").play("zigzag")
- get_node("anim").seek(randf()*2.0) #make it start from any pos
+ get_node("anim").play("zigzag")
+ get_node("anim").seek(randf()*2.0) # Make it start from any pos
+
func _on_visibility_exit_screen():
queue_free()
-
diff --git a/demos/2d/space_shooter/enemy1.scn b/demos/2d/space_shooter/enemy1.scn
index 14298f0a59..805071b772 100644
--- a/demos/2d/space_shooter/enemy1.scn
+++ b/demos/2d/space_shooter/enemy1.scn
Binary files differ
diff --git a/demos/2d/space_shooter/enemy2.gd b/demos/2d/space_shooter/enemy2.gd
index 4f632a053d..bfdb743103 100644
--- a/demos/2d/space_shooter/enemy2.gd
+++ b/demos/2d/space_shooter/enemy2.gd
@@ -1,56 +1,51 @@
extends Area2D
-# member variables here, example:
-# var a=2
-# var b="textvar"
-const SPEED=-220
-const SHOOT_INTERVAL=1
-var shoot_timeout=0
+# Member variables
+const SPEED = -220
+const SHOOT_INTERVAL = 1
+
+var shoot_timeout = 0
+var destroyed=false
+
func _process(delta):
- translate( Vector2(SPEED*delta,0) )
- shoot_timeout-=delta
+ translate(Vector2(SPEED*delta, 0))
+ shoot_timeout -= delta
- if (shoot_timeout<0):
-
- shoot_timeout=SHOOT_INTERVAL
+ if (shoot_timeout < 0):
+ shoot_timeout = SHOOT_INTERVAL
- #instance a shot
+ # Instance a shot
var shot = preload("res://enemy_shot.scn").instance()
- #set pos as "shoot_from" Position2D node
- shot.set_pos( get_node("shoot_from").get_global_pos() )
- #add it to parent, so it has world coordinates
+ # Set pos as "shoot_from" Position2D node
+ shot.set_pos(get_node("shoot_from").get_global_pos())
+ # Add it to parent, so it has world coordinates
get_parent().add_child(shot)
-
-var destroyed=false
+
func is_enemy():
return not destroyed
+
func destroy():
if (destroyed):
- return
- destroyed=true
+ return
+ destroyed = true
get_node("anim").play("explode")
- set_process(false)
+ set_process(false)
get_node("sfx").play("sound_explode")
- #accum points
- get_node("/root/game_state").points+=10
+ # Accumulate points
+ get_node("/root/game_state").points += 10
+
func _ready():
set_fixed_process(true)
- # Initialization here
- pass
-
-
func _on_visibility_enter_screen():
set_process(true)
- pass # replace with function body
func _on_visibility_exit_screen():
queue_free()
- pass # replace with function body
diff --git a/demos/2d/space_shooter/enemy2.scn b/demos/2d/space_shooter/enemy2.scn
index 1d31f9c30e..644add77aa 100644
--- a/demos/2d/space_shooter/enemy2.scn
+++ b/demos/2d/space_shooter/enemy2.scn
Binary files differ
diff --git a/demos/2d/space_shooter/enemy_shot.gd b/demos/2d/space_shooter/enemy_shot.gd
index 238d24e4a2..6c782b69f1 100644
--- a/demos/2d/space_shooter/enemy_shot.gd
+++ b/demos/2d/space_shooter/enemy_shot.gd
@@ -1,32 +1,31 @@
extends Area2D
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
+# Member variables
const SPEED = -800
+var hit = false
+
+
func _process(delta):
- translate(Vector2(delta*SPEED,0))
+ translate(Vector2(delta*SPEED, 0))
+
func _ready():
- # Initialization here
set_process(true)
-var hit=false
-
func is_enemy():
return true
+
func _hit_something():
if (hit):
return
- hit=true
+ hit = true
set_process(false)
get_node("anim").play("splash")
+
func _on_visibility_exit_screen():
queue_free()
-
diff --git a/demos/2d/space_shooter/enemy_shot.scn b/demos/2d/space_shooter/enemy_shot.scn
index 13f5ae89e5..353c9058f7 100644
--- a/demos/2d/space_shooter/enemy_shot.scn
+++ b/demos/2d/space_shooter/enemy_shot.scn
Binary files differ
diff --git a/demos/2d/space_shooter/explosion.scn b/demos/2d/space_shooter/explosion.scn
index 4edcf709cb..6fc105fac3 100644
--- a/demos/2d/space_shooter/explosion.scn
+++ b/demos/2d/space_shooter/explosion.scn
Binary files differ
diff --git a/demos/2d/space_shooter/game_state.gd b/demos/2d/space_shooter/game_state.gd
index 26ef086f14..0aa5e1f42b 100644
--- a/demos/2d/space_shooter/game_state.gd
+++ b/demos/2d/space_shooter/game_state.gd
@@ -1,24 +1,22 @@
-extends Node
+extends Node
+# Member variables
var points = 0
var max_points = 0
func _ready():
var f = File.new()
- #load high score
- if (f.open("user://highscore",File.READ)==OK):
-
- max_points=f.get_var()
-
+ # Load high score
+ if (f.open("user://highscore", File.READ) == OK):
+ max_points = f.get_var()
func game_over():
- if (points>max_points):
- max_points=points
- #save high score
+ if (points > max_points):
+ max_points = points
+ # Save high score
var f = File.new()
- f.open("user://highscore",File.WRITE)
+ f.open("user://highscore", File.WRITE)
f.store_var(max_points)
- \ No newline at end of file
diff --git a/demos/2d/space_shooter/level.scn b/demos/2d/space_shooter/level.scn
index 12a679f8b6..6d5f8005f5 100644
--- a/demos/2d/space_shooter/level.scn
+++ b/demos/2d/space_shooter/level.scn
Binary files differ
diff --git a/demos/2d/space_shooter/level_tiles.scn b/demos/2d/space_shooter/level_tiles.scn
index 4d1feea70f..932be39a29 100644
--- a/demos/2d/space_shooter/level_tiles.scn
+++ b/demos/2d/space_shooter/level_tiles.scn
Binary files differ
diff --git a/demos/2d/space_shooter/main_menu.gd b/demos/2d/space_shooter/main_menu.gd
index 52221aba1b..a7f242da7b 100644
--- a/demos/2d/space_shooter/main_menu.gd
+++ b/demos/2d/space_shooter/main_menu.gd
@@ -1,20 +1,11 @@
extends Control
-# member variables here, example:
-# var a=2
-# var b="textvar"
func _ready():
-
- get_node("score").set_text( "HIGH SCORE: "+str( get_node("/root/game_state").max_points ) )
- # Initialization here
- pass
-
-
+ get_node("score").set_text("HIGH SCORE: " + str(get_node("/root/game_state").max_points))
func _on_play_pressed():
- get_node("/root/game_state").points=0
+ get_node("/root/game_state").points = 0
get_tree().change_scene("res://level.scn")
- pass # replace with function body
diff --git a/demos/2d/space_shooter/main_menu.scn b/demos/2d/space_shooter/main_menu.scn
index b87cc5d3a8..91b0b37b14 100644
--- a/demos/2d/space_shooter/main_menu.scn
+++ b/demos/2d/space_shooter/main_menu.scn
Binary files differ
diff --git a/demos/2d/space_shooter/parallax.scn b/demos/2d/space_shooter/parallax.scn
index f67277dc01..2753d16e84 100644
--- a/demos/2d/space_shooter/parallax.scn
+++ b/demos/2d/space_shooter/parallax.scn
Binary files differ
diff --git a/demos/2d/space_shooter/rail.gd b/demos/2d/space_shooter/rail.gd
index 803a09fe84..7362dff97d 100644
--- a/demos/2d/space_shooter/rail.gd
+++ b/demos/2d/space_shooter/rail.gd
@@ -1,26 +1,19 @@
extends Node2D
+# Member variables
+const SPEED = 200
+var offset = 0
-const SPEED=200
-# member variables here, example:
-# var a=2
-# var b="textvar"
func stop():
set_process(false)
-var offset=0
-
func _process(delta):
-
- offset+=delta*SPEED
- set_pos(Vector2(offset,0))
+ offset += delta*SPEED
+ set_pos(Vector2(offset, 0))
+
func _ready():
set_process(true)
- # Initialization here
-
-
-
diff --git a/demos/2d/space_shooter/ship.gd b/demos/2d/space_shooter/ship.gd
index fa444868a4..b6c1200632 100644
--- a/demos/2d/space_shooter/ship.gd
+++ b/demos/2d/space_shooter/ship.gd
@@ -1,71 +1,65 @@
extends Area2D
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
+# Member variables
const SPEED = 200
var screen_size
+var prev_shooting = false
+var killed = false
-var prev_shooting=false
func _process(delta):
-
var motion = Vector2()
if Input.is_action_pressed("move_up"):
- motion+=Vector2(0,-1)
+ motion += Vector2(0, -1)
if Input.is_action_pressed("move_down"):
- motion+=Vector2(0,1)
+ motion += Vector2(0, 1)
if Input.is_action_pressed("move_left"):
- motion+=Vector2(-1,0)
+ motion += Vector2(-1, 0)
if Input.is_action_pressed("move_right"):
- motion+=Vector2(1,0)
+ motion += Vector2(1, 0)
var shooting = Input.is_action_pressed("shoot")
-
+
var pos = get_pos()
- pos+=motion*delta*SPEED
- if (pos.x<0):
- pos.x=0
- if (pos.x>screen_size.x):
- pos.x=screen_size.x
- if (pos.y<0):
- pos.y=0
- if (pos.y>screen_size.y):
- pos.y=screen_size.y
-
+ pos += motion*delta*SPEED
+ if (pos.x < 0):
+ pos.x = 0
+ if (pos.x > screen_size.x):
+ pos.x = screen_size.x
+ if (pos.y < 0):
+ pos.y = 0
+ if (pos.y > screen_size.y):
+ pos.y = screen_size.y
+
set_pos(pos)
if (shooting and not prev_shooting):
- # just pressed
+ # Just pressed
var shot = preload("res://shot.scn").instance()
- #use the position3d as reference
- shot.set_pos( get_node("shootfrom").get_global_pos() )
- #put it two parents above, so it is not moved by us
+ # Use the Position2D as reference
+ shot.set_pos(get_node("shootfrom").get_global_pos())
+ # Put it two parents above, so it is not moved by us
get_node("../..").add_child(shot)
- #play sound
+ # Play sound
get_node("sfx").play("shoot")
-
prev_shooting = shooting
+
+ # Update points counter
+ get_node("../hud/score_points").set_text(str(get_node("/root/game_state").points))
- #update points counter
- get_node("../hud/score_points").set_text( str(get_node("/root/game_state").points) )
func _ready():
- # Initialization here
screen_size = get_viewport().get_rect().size
set_process(true)
- pass
-var killed=false
func _hit_something():
if (killed):
return
- killed=true
+ killed = true
get_node("anim").play("explode")
get_node("sfx").play("sound_explode")
get_node("../hud/game_over").show()
@@ -74,15 +68,14 @@ func _hit_something():
set_process(false)
-func _on_ship_body_enter( body ):
+func _on_ship_body_enter(body):
_hit_something()
-func _on_ship_area_enter( area ):
+func _on_ship_area_enter(area):
if (area.has_method("is_enemy") and area.is_enemy()):
_hit_something()
func _on_back_to_menu_pressed():
get_tree().change_scene("res://main_menu.scn")
- pass # replace with function body
diff --git a/demos/2d/space_shooter/ship.scn b/demos/2d/space_shooter/ship.scn
index 82c710eda7..c60e2e3e3b 100644
--- a/demos/2d/space_shooter/ship.scn
+++ b/demos/2d/space_shooter/ship.scn
Binary files differ
diff --git a/demos/2d/space_shooter/shot.gd b/demos/2d/space_shooter/shot.gd
index 28b67bd26d..936dde73d1 100644
--- a/demos/2d/space_shooter/shot.gd
+++ b/demos/2d/space_shooter/shot.gd
@@ -1,48 +1,40 @@
extends Area2D
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
+# Member variables
const SPEED = 800
+var hit = false
+
+
func _process(delta):
- translate(Vector2(delta*SPEED,0))
+ translate(Vector2(delta*SPEED, 0))
+
func _ready():
- # Initialization here
set_process(true)
- pass
-var hit=false
func _hit_something():
if (hit):
return
- hit=true
+ hit = true
set_process(false)
get_node("anim").play("splash")
+
func _on_visibility_exit_screen():
queue_free()
- pass # replace with function body
-
-func _on_shot_area_enter( area ):
- #hit an enemy or asteroid
+func _on_shot_area_enter(area):
+ # Hit an enemy or asteroid
if (area.has_method("destroy")):
- #duck typing at it's best
+ # Duck typing at it's best
area.destroy()
_hit_something()
-
-
- pass
-func _on_shot_body_enter( body ):
- #hit the tilemap
+func _on_shot_body_enter(body):
+ # Hit the tilemap
_hit_something()
- pass # replace with function body
-
diff --git a/demos/2d/space_shooter/shot.scn b/demos/2d/space_shooter/shot.scn
index 86a20ffa47..9daf4ebe82 100644
--- a/demos/2d/space_shooter/shot.scn
+++ b/demos/2d/space_shooter/shot.scn
Binary files differ
diff --git a/demos/2d/splash/engine.cfg b/demos/2d/splash/engine.cfg
index cb50c7b1be..e461426305 100644
--- a/demos/2d/splash/engine.cfg
+++ b/demos/2d/splash/engine.cfg
@@ -2,6 +2,7 @@
name="Splash Screen"
main_scene="res://splash.xml"
+icon="res://icon.png"
[display]
diff --git a/demos/2d/splash/icon.png b/demos/2d/splash/icon.png
new file mode 100644
index 0000000000..b8e24f209e
--- /dev/null
+++ b/demos/2d/splash/icon.png
Binary files differ
diff --git a/demos/2d/splash/splash.xml b/demos/2d/splash/splash.xml
index ecfcb0f5b5..4a36619b09 100644
--- a/demos/2d/splash/splash.xml
+++ b/demos/2d/splash/splash.xml
@@ -1,20 +1,20 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="20" version="0.99" version_name="Godot Engine v0.99.3735-pre-beta">
- <ext_resource path="res://splash_01.*" type="ImageTexture"></ext_resource>
- <ext_resource path="res://splash_02.*" type="ImageTexture"></ext_resource>
- <ext_resource path="res://splash_03.*" type="ImageTexture"></ext_resource>
- <ext_resource path="res://splash_04.*" type="ImageTexture"></ext_resource>
- <ext_resource path="res://splash_05.*" type="ImageTexture"></ext_resource>
- <ext_resource path="res://splash_06.*" type="ImageTexture"></ext_resource>
- <ext_resource path="res://splash_07.*" type="ImageTexture"></ext_resource>
- <ext_resource path="res://splash_08.*" type="ImageTexture"></ext_resource>
- <ext_resource path="res://splash_09.*" type="ImageTexture"></ext_resource>
- <ext_resource path="res://bg.*" type="ImageTexture"></ext_resource>
- <ext_resource path="res://bg_layer_2.*" type="ImageTexture"></ext_resource>
- <ext_resource path="res://bg_layer_1.*" type="ImageTexture"></ext_resource>
- <ext_resource path="res://button_pressed.*" type="ImageTexture"></ext_resource>
- <ext_resource path="res://freesans.*" type="Font"></ext_resource>
- <ext_resource path="res://button.*" type="ImageTexture"></ext_resource>
+<resource_file type="PackedScene" subresource_count="20" version="2.0" version_name="Godot Engine v2.0.alpha.custom_build">
+ <ext_resource path="res://splash_02.png" type="Texture" index="4"></ext_resource>
+ <ext_resource path="res://splash_01.png" type="Texture" index="3"></ext_resource>
+ <ext_resource path="res://splash_05.png" type="Texture" index="7"></ext_resource>
+ <ext_resource path="res://splash_06.png" type="Texture" index="8"></ext_resource>
+ <ext_resource path="res://splash_03.png" type="Texture" index="5"></ext_resource>
+ <ext_resource path="res://splash_04.png" type="Texture" index="6"></ext_resource>
+ <ext_resource path="res://splash_07.png" type="Texture" index="9"></ext_resource>
+ <ext_resource path="res://splash_08.png" type="Texture" index="10"></ext_resource>
+ <ext_resource path="res://splash_09.png" type="Texture" index="11"></ext_resource>
+ <ext_resource path="res://bg.png" type="Texture" index="0"></ext_resource>
+ <ext_resource path="res://bg_layer_2.png" type="Texture" index="1"></ext_resource>
+ <ext_resource path="res://bg_layer_1.png" type="Texture" index="2"></ext_resource>
+ <ext_resource path="res://button_pressed.png" type="Texture" index="13"></ext_resource>
+ <ext_resource path="res://button.png" type="Texture" index="12"></ext_resource>
+ <ext_resource path="res://freesans.fnt" type="Font" index="14"></ext_resource>
<resource type="Animation" path="local://1">
<string name="resource/name"> "scroll" </string>
<real name="length"> 1 </real>
@@ -26,6 +26,8 @@
<dictionary name="tracks/0/keys" shared="false">
<string> "cont" </string>
<bool> True </bool>
+ <string> "times" </string>
+ <real_array len="2"> 0, 1 </real_array>
<string> "transitions" </string>
<real_array len="2"> 1, 1 </real_array>
<string> "values" </string>
@@ -33,48 +35,23 @@
<vector2> 0, 0 </vector2>
<vector2> -800, 0 </vector2>
</array>
- <string> "times" </string>
- <real_array len="2"> 0, 1 </real_array>
</dictionary>
</resource>
<resource type="SpriteFrames" path="local://2">
<array name="frames" len="9" shared="false">
- <resource resource_type="ImageTexture" path="res://splash_01.*"> </resource>
- <resource resource_type="ImageTexture" path="res://splash_02.*"> </resource>
- <resource resource_type="ImageTexture" path="res://splash_03.*"> </resource>
- <resource resource_type="ImageTexture" path="res://splash_04.*"> </resource>
- <resource resource_type="ImageTexture" path="res://splash_05.*"> </resource>
- <resource resource_type="ImageTexture" path="res://splash_06.*"> </resource>
- <resource resource_type="ImageTexture" path="res://splash_07.*"> </resource>
- <resource resource_type="ImageTexture" path="res://splash_08.*"> </resource>
- <resource resource_type="ImageTexture" path="res://splash_09.*"> </resource>
+ <resource external="3"> </resource>
+ <resource external="4"> </resource>
+ <resource external="5"> </resource>
+ <resource external="6"> </resource>
+ <resource external="7"> </resource>
+ <resource external="8"> </resource>
+ <resource external="9"> </resource>
+ <resource external="10"> </resource>
+ <resource external="11"> </resource>
</array>
</resource>
- <resource type="Animation" path="local://3">
- <string name="resource/name"> "loop" </string>
- <real name="length"> 0.6 </real>
- <bool name="loop"> True </bool>
- <real name="step"> 0.1 </real>
- <string name="tracks/0/type"> "value" </string>
- <node_path name="tracks/0/path"> "logo:frame" </node_path>
- <int name="tracks/0/interp"> 1 </int>
- <dictionary name="tracks/0/keys" shared="false">
- <string> "cont" </string>
- <bool> False </bool>
- <string> "transitions" </string>
- <real_array len="2"> 1, 1 </real_array>
- <string> "values" </string>
- <array len="2" shared="false">
- <int> 8 </int>
- <int> 7 </int>
- </array>
- <string> "times" </string>
- <real_array len="2"> 0, 0.3 </real_array>
- </dictionary>
-
- </resource>
<resource type="Animation" path="local://4">
<string name="resource/name"> "intro" </string>
<real name="length"> 3 </real>
@@ -86,6 +63,8 @@
<dictionary name="tracks/0/keys" shared="false">
<string> "cont" </string>
<bool> True </bool>
+ <string> "times" </string>
+ <real_array len="2"> 1, 1.5 </real_array>
<string> "transitions" </string>
<real_array len="2"> 2, 1 </real_array>
<string> "values" </string>
@@ -93,8 +72,6 @@
<vector2> 412, -212.981 </vector2>
<vector2> 412, 171 </vector2>
</array>
- <string> "times" </string>
- <real_array len="2"> 1, 1.5 </real_array>
</dictionary>
<string name="tracks/1/type"> "value" </string>
<node_path name="tracks/1/path"> "logo:frame" </node_path>
@@ -102,6 +79,8 @@
<dictionary name="tracks/1/keys" shared="false">
<string> "cont" </string>
<bool> False </bool>
+ <string> "times" </string>
+ <real_array len="10"> 0, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3 </real_array>
<string> "transitions" </string>
<real_array len="10"> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 </real_array>
<string> "values" </string>
@@ -117,8 +96,6 @@
<int> 7 </int>
<int> 8 </int>
</array>
- <string> "times" </string>
- <real_array len="10"> 0, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3 </real_array>
</dictionary>
<string name="tracks/2/type"> "value" </string>
<node_path name="tracks/2/path"> "start:visibility/opacity" </node_path>
@@ -126,6 +103,8 @@
<dictionary name="tracks/2/keys" shared="false">
<string> "cont" </string>
<bool> True </bool>
+ <string> "times" </string>
+ <real_array len="2"> 2.5, 2.8 </real_array>
<string> "transitions" </string>
<real_array len="2"> 1, 1 </real_array>
<string> "values" </string>
@@ -133,8 +112,6 @@
<real> 0 </real>
<real> 1 </real>
</array>
- <string> "times" </string>
- <real_array len="2"> 2.5, 2.8 </real_array>
</dictionary>
<string name="tracks/3/type"> "value" </string>
<node_path name="tracks/3/path"> "start:visibility/visible" </node_path>
@@ -142,6 +119,8 @@
<dictionary name="tracks/3/keys" shared="false">
<string> "cont" </string>
<bool> False </bool>
+ <string> "times" </string>
+ <real_array len="2"> 0, 2.5 </real_array>
<string> "transitions" </string>
<real_array len="2"> 1, 1 </real_array>
<string> "values" </string>
@@ -149,8 +128,6 @@
<bool> False </bool>
<bool> True </bool>
</array>
- <string> "times" </string>
- <real_array len="2"> 0, 2.5 </real_array>
</dictionary>
<string name="tracks/4/type"> "value" </string>
<node_path name="tracks/4/path"> "copyright:visibility/visible" </node_path>
@@ -158,6 +135,8 @@
<dictionary name="tracks/4/keys" shared="false">
<string> "cont" </string>
<bool> False </bool>
+ <string> "times" </string>
+ <real_array len="2"> 0, 2.5 </real_array>
<string> "transitions" </string>
<real_array len="2"> 1, 1 </real_array>
<string> "values" </string>
@@ -165,8 +144,6 @@
<bool> False </bool>
<bool> True </bool>
</array>
- <string> "times" </string>
- <real_array len="2"> 0, 2.5 </real_array>
</dictionary>
<string name="tracks/5/type"> "value" </string>
<node_path name="tracks/5/path"> "copyright:visibility/opacity" </node_path>
@@ -174,6 +151,8 @@
<dictionary name="tracks/5/keys" shared="false">
<string> "cont" </string>
<bool> True </bool>
+ <string> "times" </string>
+ <real_array len="2"> 2.5, 2.8 </real_array>
<string> "transitions" </string>
<real_array len="2"> 1, 1 </real_array>
<string> "values" </string>
@@ -181,45 +160,61 @@
<real> 0 </real>
<real> 1 </real>
</array>
+ </dictionary>
+
+ </resource>
+ <resource type="Animation" path="local://3">
+ <string name="resource/name"> "loop" </string>
+ <real name="length"> 0.6 </real>
+ <bool name="loop"> True </bool>
+ <real name="step"> 0.1 </real>
+ <string name="tracks/0/type"> "value" </string>
+ <node_path name="tracks/0/path"> "logo:frame" </node_path>
+ <int name="tracks/0/interp"> 1 </int>
+ <dictionary name="tracks/0/keys" shared="false">
+ <string> "cont" </string>
+ <bool> False </bool>
<string> "times" </string>
- <real_array len="2"> 2.5, 2.8 </real_array>
+ <real_array len="2"> 0, 0.3 </real_array>
+ <string> "transitions" </string>
+ <real_array len="2"> 1, 1 </real_array>
+ <string> "values" </string>
+ <array len="2" shared="false">
+ <int> 8 </int>
+ <int> 7 </int>
+ </array>
</dictionary>
</resource>
<main_resource>
<dictionary name="_bundled" shared="false">
+ <string> "conn_count" </string>
+ <int> 0 </int>
+ <string> "conns" </string>
+ <int_array len="0"> </int_array>
+ <string> "editable_instances" </string>
+ <array len="0" shared="false">
+ </array>
<string> "names" </string>
- <string_array len="81">
+ <string_array len="51">
<string> "splash" </string>
- <string> "Control" </string>
- <string> "visibility/visible" </string>
- <string> "visibility/opacity" </string>
- <string> "visibility/self_opacity" </string>
- <string> "visibility/on_top" </string>
<string> "anchor/right" </string>
<string> "anchor/bottom" </string>
- <string> "focus_neighbour/left" </string>
- <string> "focus_neighbour/top" </string>
- <string> "focus_neighbour/right" </string>
- <string> "focus_neighbour/bottom" </string>
<string> "focus/ignore_mouse" </string>
<string> "focus/stop_mouse" </string>
<string> "size_flags/horizontal" </string>
<string> "size_flags/vertical" </string>
- <string> "size_flags/stretch_ratio" </string>
<string> "__meta__" </string>
+ <string> "Control" </string>
<string> "bg" </string>
<string> "margin/right" </string>
<string> "margin/bottom" </string>
<string> "1" </string>
- <string> "TextureFrame" </string>
<string> "texture" </string>
- <string> "modulate" </string>
- <string> "expand" </string>
+ <string> "TextureFrame" </string>
<string> "2" </string>
<string> "margin/left" </string>
<string> "scroll" </string>
- <string> "AnimationPlayer" </string>
<string> "playback/process_mode" </string>
<string> "playback/default_blend_time" </string>
<string> "root/root" </string>
@@ -228,152 +223,172 @@
<string> "playback/speed" </string>
<string> "blend_times" </string>
<string> "autoplay" </string>
+ <string> "AnimationPlayer" </string>
<string> "layer2" </string>
<string> "margin/top" </string>
<string> "layer1" </string>
<string> "logo" </string>
- <string> "AnimatedSprite" </string>
<string> "transform/pos" </string>
- <string> "transform/rot" </string>
- <string> "transform/scale" </string>
<string> "frames" </string>
<string> "frame" </string>
- <string> "centered" </string>
- <string> "flip_h" </string>
- <string> "flip_v" </string>
+ <string> "AnimatedSprite" </string>
<string> "start" </string>
- <string> "TextureButton" </string>
- <string> "disabled" </string>
<string> "toggle_mode" </string>
- <string> "click_on_press" </string>
<string> "textures/normal" </string>
<string> "textures/pressed" </string>
- <string> "textures/hover" </string>
- <string> "textures/disabled" </string>
- <string> "textures/focused" </string>
- <string> "textures/click_mask" </string>
+ <string> "TextureButton" </string>
<string> "copyright" </string>
- <string> "Label" </string>
<string> "custom_fonts/font" </string>
- <string> "range/min" </string>
- <string> "range/max" </string>
- <string> "range/step" </string>
- <string> "range/page" </string>
- <string> "range/value" </string>
- <string> "range/exp_edit" </string>
- <string> "rounded_values" </string>
<string> "text" </string>
- <string> "align" </string>
- <string> "valign" </string>
- <string> "autowrap" </string>
<string> "percent_visible" </string>
+ <string> "lines_skipped" </string>
+ <string> "max_lines_visible" </string>
+ <string> "Label" </string>
<string> "intro" </string>
- <string> "anims/loop" </string>
<string> "anims/intro" </string>
<string> "next/intro" </string>
+ <string> "anims/loop" </string>
</string_array>
- <string> "version" </string>
- <int> 1 </int>
- <string> "conn_count" </string>
- <int> 0 </int>
<string> "node_count" </string>
<int> 17 </int>
+ <string> "node_paths" </string>
+ <array len="0" shared="false">
+ </array>
+ <string> "nodes" </string>
+ <int_array len="387"> -1, -1, 8, 0, -1, 7, 1, 0, 2, 0, 3, 1, 4, 2, 5, 3, 6, 3, 7, 4, 0, 0, 0, 8, 9, -1, 6, 10, 5, 11, 5, 3, 1, 4, 2, 5, 3, 6, 3, 0, 1, 0, 14, 12, -1, 7, 10, 5, 11, 5, 3, 2, 4, 2, 5, 3, 6, 3, 13, 6, 0, 1, 0, 14, 15, -1, 8, 16, 7, 10, 8, 11, 9, 3, 2, 4, 2, 5, 3, 6, 3, 13, 6, 0, 1, 0, 26, 17, -1, 8, 18, 0, 19, 10, 20, 11, 21, 12, 22, 2, 23, 13, 24, 14, 25, 15, 0, 0, 0, 8, 27, -1, 6, 10, 5, 11, 5, 3, 1, 4, 2, 5, 3, 6, 3, 0, 5, 0, 14, 12, -1, 8, 28, 16, 10, 7, 11, 17, 3, 2, 4, 2, 5, 3, 6, 3, 13, 18, 0, 5, 0, 14, 15, -1, 9, 16, 7, 28, 16, 10, 8, 11, 17, 3, 2, 4, 2, 5, 3, 6, 3, 13, 18, 0, 5, 0, 26, 17, -1, 8, 18, 0, 19, 10, 20, 11, 21, 12, 22, 2, 23, 19, 24, 14, 25, 15, 0, 0, 0, 8, 29, -1, 6, 10, 5, 11, 5, 3, 1, 4, 2, 5, 3, 6, 3, 0, 9, 0, 14, 12, -1, 8, 28, 20, 10, 7, 11, 17, 3, 2, 4, 2, 5, 3, 6, 3, 13, 21, 0, 9, 0, 14, 15, -1, 9, 16, 7, 28, 20, 10, 8, 11, 17, 3, 2, 4, 2, 5, 3, 6, 3, 13, 21, 0, 9, 0, 26, 17, -1, 8, 18, 0, 19, 10, 20, 11, 21, 12, 22, 2, 23, 22, 24, 14, 25, 15, 0, 0, 0, 34, 30, -1, 3, 31, 23, 32, 24, 33, 25, 0, 0, 0, 39, 35, -1, 11, 16, 26, 28, 27, 10, 28, 11, 29, 3, 1, 4, 2, 5, 3, 6, 3, 36, 1, 37, 30, 38, 31, 0, 0, 0, 46, 40, -1, 12, 16, 32, 28, 33, 10, 34, 11, 35, 3, 2, 4, 2, 5, 3, 41, 36, 42, 37, 43, 38, 44, 39, 45, 40, 0, 0, 0, 26, 47, -1, 10, 18, 0, 19, 10, 20, 11, 48, 41, 49, 42, 50, 43, 22, 2, 23, 38, 24, 14, 25, 44, 0 </int_array>
<string> "variants" </string>
- <array len="49" shared="false">
- <bool> True </bool>
- <real> 1 </real>
+ <array len="45" shared="false">
<int> 1 </int>
- <node_path> "" </node_path>
<bool> False </bool>
+ <bool> True </bool>
<int> 2 </int>
<dictionary shared="false">
+ <string> "__editor_plugin_screen__" </string>
+ <string> "2D" </string>
<string> "__editor_plugin_states__" </string>
<dictionary shared="false">
<string> "2D" </string>
<dictionary shared="false">
- <string> "pixel_snap" </string>
- <bool> True </bool>
+ <string> "ofs" </string>
+ <vector2> -301.424, -450.503 </vector2>
+ <string> "snap_grid" </string>
+ <bool> False </bool>
+ <string> "snap_offset" </string>
+ <vector2> 0, 0 </vector2>
+ <string> "snap_pixel" </string>
+ <bool> False </bool>
+ <string> "snap_relative" </string>
+ <bool> False </bool>
+ <string> "snap_rotation" </string>
+ <bool> False </bool>
+ <string> "snap_rotation_offset" </string>
+ <real> 0 </real>
+ <string> "snap_rotation_step" </string>
+ <real> 0.261799 </real>
+ <string> "snap_show_grid" </string>
+ <bool> False </bool>
+ <string> "snap_step" </string>
+ <vector2> 10, 10 </vector2>
<string> "zoom" </string>
<real> 0.54036 </real>
- <string> "ofs" </string>
- <vector2> -301.424, 3.30361 </vector2>
</dictionary>
<string> "3D" </string>
<dictionary shared="false">
- <string> "zfar" </string>
- <real> 500 </real>
+ <string> "ambient_light_color" </string>
+ <color> 0.15, 0.15, 0.15, 1 </color>
+ <string> "default_light" </string>
+ <bool> True </bool>
+ <string> "default_srgb" </string>
+ <bool> False </bool>
+ <string> "deflight_rot_x" </string>
+ <real> 0.942478 </real>
+ <string> "deflight_rot_y" </string>
+ <real> 0.628319 </real>
<string> "fov" </string>
<real> 45 </real>
+ <string> "show_grid" </string>
+ <bool> True </bool>
+ <string> "show_origin" </string>
+ <bool> True </bool>
+ <string> "viewport_mode" </string>
+ <int> 1 </int>
<string> "viewports" </string>
<array len="4" shared="false">
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> True </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
<dictionary shared="false">
<string> "distance" </string>
<real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
<string> "x_rot" </string>
<real> 0 </real>
<string> "y_rot" </string>
<real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
</dictionary>
</array>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
+ <string> "zfar" </string>
+ <real> 500 </real>
<string> "znear" </string>
<real> 0.1 </real>
</dictionary>
+ <string> "Anim" </string>
+ <dictionary shared="false">
+ <string> "visible" </string>
+ <bool> False </bool>
+ </dictionary>
</dictionary>
<string> "__editor_run_settings__" </string>
<dictionary shared="false">
@@ -382,12 +397,9 @@
<string> "run_mode" </string>
<int> 0 </int>
</dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "2D" </string>
</dictionary>
<real> 40 </real>
- <resource resource_type="ImageTexture" path="res://bg.*"> </resource>
- <color> 1, 1, 1, 1 </color>
+ <resource external="0"> </resource>
<real> 800 </real>
<real> 1600 </real>
<real> 450 </real>
@@ -400,38 +412,36 @@
<string> "scroll" </string>
<real> 194 </real>
<real> 456 </real>
- <resource resource_type="ImageTexture" path="res://bg_layer_2.*"> </resource>
+ <resource external="1"> </resource>
<real> 0.1 </real>
<real> 212 </real>
- <resource resource_type="ImageTexture" path="res://bg_layer_1.*"> </resource>
+ <resource external="2"> </resource>
<real> 0.2 </real>
<vector2> 412, 171 </vector2>
- <vector2> 1, 1 </vector2>
<resource resource_type="SpriteFrames" path="local://2"> </resource>
<int> 8 </int>
<real> 345 </real>
<real> 369 </real>
<real> 494 </real>
<real> 443 </real>
- <resource resource_type="ImageTexture" path="res://button.*"> </resource>
- <resource resource_type="ImageTexture" path="res://button_pressed.*"> </resource>
- <resource name=""></resource> <real> 658 </real>
+ <resource external="12"> </resource>
+ <resource external="13"> </resource>
+ <real> 658 </real>
<real> 417 </real>
<real> 776 </real>
<real> 434 </real>
- <resource resource_type="Font" path="res://freesans.*"> </resource>
+ <resource external="14"> </resource>
<string> "(c) 1994 SOGA" </string>
+ <real> 1 </real>
<int> 0 </int>
- <real> -1 </real>
- <resource resource_type="Animation" path="local://3"> </resource>
+ <int> -1 </int>
<resource resource_type="Animation" path="local://4"> </resource>
<string> "loop" </string>
+ <resource resource_type="Animation" path="local://3"> </resource>
<string> "intro" </string>
</array>
- <string> "nodes" </string>
- <int_array len="675"> -1, -1, 1, 0, -1, 16, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 2, 8, 3, 9, 3, 10, 3, 11, 3, 12, 4, 13, 0, 14, 5, 15, 5, 16, 1, 17, 6, 0, 0, 0, 1, 18, -1, 15, 2, 0, 3, 1, 4, 1, 5, 0, 19, 7, 20, 7, 8, 3, 9, 3, 10, 3, 11, 3, 12, 4, 13, 0, 14, 5, 15, 5, 16, 1, 0, 1, 0, 22, 21, -1, 18, 2, 0, 3, 1, 4, 1, 5, 0, 19, 7, 20, 7, 8, 3, 9, 3, 10, 3, 11, 3, 12, 0, 13, 0, 14, 5, 15, 5, 16, 1, 23, 8, 24, 9, 25, 4, 0, 1, 0, 22, 26, -1, 19, 2, 0, 3, 1, 4, 1, 5, 0, 27, 10, 19, 11, 20, 12, 8, 3, 9, 3, 10, 3, 11, 3, 12, 0, 13, 0, 14, 5, 15, 5, 16, 1, 23, 8, 24, 9, 25, 4, 0, 1, 0, 29, 28, -1, 8, 30, 2, 31, 13, 32, 14, 33, 15, 34, 0, 35, 16, 36, 17, 37, 18, 0, 0, 0, 1, 38, -1, 15, 2, 0, 3, 1, 4, 1, 5, 0, 19, 7, 20, 7, 8, 3, 9, 3, 10, 3, 11, 3, 12, 4, 13, 0, 14, 5, 15, 5, 16, 1, 0, 5, 0, 22, 21, -1, 19, 2, 0, 3, 1, 4, 1, 5, 0, 39, 19, 19, 10, 20, 20, 8, 3, 9, 3, 10, 3, 11, 3, 12, 0, 13, 0, 14, 5, 15, 5, 16, 1, 23, 21, 24, 9, 25, 4, 0, 5, 0, 22, 26, -1, 20, 2, 0, 3, 1, 4, 1, 5, 0, 27, 10, 39, 19, 19, 11, 20, 20, 8, 3, 9, 3, 10, 3, 11, 3, 12, 0, 13, 0, 14, 5, 15, 5, 16, 1, 23, 21, 24, 9, 25, 4, 0, 5, 0, 29, 28, -1, 8, 30, 2, 31, 13, 32, 14, 33, 15, 34, 0, 35, 22, 36, 17, 37, 18, 0, 0, 0, 1, 40, -1, 15, 2, 0, 3, 1, 4, 1, 5, 0, 19, 7, 20, 7, 8, 3, 9, 3, 10, 3, 11, 3, 12, 4, 13, 0, 14, 5, 15, 5, 16, 1, 0, 9, 0, 22, 21, -1, 19, 2, 0, 3, 1, 4, 1, 5, 0, 39, 23, 19, 10, 20, 20, 8, 3, 9, 3, 10, 3, 11, 3, 12, 0, 13, 0, 14, 5, 15, 5, 16, 1, 23, 24, 24, 9, 25, 4, 0, 9, 0, 22, 26, -1, 20, 2, 0, 3, 1, 4, 1, 5, 0, 27, 10, 39, 23, 19, 11, 20, 20, 8, 3, 9, 3, 10, 3, 11, 3, 12, 0, 13, 0, 14, 5, 15, 5, 16, 1, 23, 24, 24, 9, 25, 4, 0, 9, 0, 29, 28, -1, 8, 30, 2, 31, 13, 32, 14, 33, 15, 34, 0, 35, 25, 36, 17, 37, 18, 0, 0, 0, 42, 41, -1, 13, 2, 0, 3, 1, 4, 1, 5, 0, 43, 26, 44, 13, 45, 27, 46, 28, 47, 29, 48, 0, 49, 4, 50, 4, 24, 9, 0, 0, 0, 52, 51, -1, 26, 2, 0, 3, 1, 4, 1, 5, 0, 27, 30, 39, 31, 19, 32, 20, 33, 8, 3, 9, 3, 10, 3, 11, 3, 12, 4, 13, 0, 14, 5, 15, 5, 16, 1, 53, 4, 54, 4, 55, 4, 56, 34, 57, 35, 58, 36, 59, 36, 60, 36, 61, 36, 0, 0, 0, 63, 62, -1, 29, 2, 0, 3, 1, 4, 1, 5, 0, 27, 37, 39, 38, 19, 39, 20, 40, 8, 3, 9, 3, 10, 3, 11, 3, 12, 0, 13, 0, 14, 5, 16, 1, 64, 41, 65, 13, 66, 1, 67, 1, 68, 1, 69, 13, 70, 4, 71, 4, 72, 42, 73, 43, 74, 43, 75, 4, 76, 44, 0, 0, 0, 29, 77, -1, 10, 30, 2, 31, 13, 32, 14, 78, 45, 79, 46, 80, 47, 34, 0, 35, 1, 36, 17, 37, 48, 0 </int_array>
- <string> "conns" </string>
- <int_array len="0"> </int_array>
+ <string> "version" </string>
+ <int> 2 </int>
</dictionary>
</main_resource>
diff --git a/demos/2d/sprite_shaders/engine.cfg b/demos/2d/sprite_shaders/engine.cfg
index 09f9a59566..17bdada188 100644
--- a/demos/2d/sprite_shaders/engine.cfg
+++ b/demos/2d/sprite_shaders/engine.cfg
@@ -2,3 +2,4 @@
name="2D Shaders for Sprites"
main_scene="res://sprite_shaders.scn"
+icon="res://icon.png"
diff --git a/demos/2d/sprite_shaders/icon.png b/demos/2d/sprite_shaders/icon.png
new file mode 100644
index 0000000000..8b13ef6bb4
--- /dev/null
+++ b/demos/2d/sprite_shaders/icon.png
Binary files differ
diff --git a/demos/2d/sprite_shaders/sprite_shaders.scn b/demos/2d/sprite_shaders/sprite_shaders.scn
index 7c36f2137c..b6060f8eaa 100644
--- a/demos/2d/sprite_shaders/sprite_shaders.scn
+++ b/demos/2d/sprite_shaders/sprite_shaders.scn
Binary files differ
diff --git a/demos/2d/tetris/grid.gd b/demos/2d/tetris/grid.gd
index 8708d168e4..75fabb4210 100644
--- a/demos/2d/tetris/grid.gd
+++ b/demos/2d/tetris/grid.gd
@@ -1,82 +1,76 @@
-
extends Control
# Simple Tetris-like demo, (c) 2012 Juan Linietsky
# Implemented by using a regular Control and drawing on it during the _draw() callback.
# The drawing surface is updated only when changes happen (by calling update())
-
+# Member variables
var score = 0
-var score_label=null
+var score_label = null
const MAX_SHAPES = 7
var block = preload("block.png")
-var block_colors=[
- Color(1,0.5,0.5),
- Color(0.5,1,0.5),
- Color(0.5,0.5,1),
- Color(0.8,0.4,0.8),
- Color(0.8,0.8,0.4),
- Color(0.4,0.8,0.8),
- Color(0.7,0.7,0.7)]
-
-var block_shapes=[
- [ Vector2(0,-1),Vector2(0,0),Vector2(0,1),Vector2(0,2) ], # I
- [ Vector2(0,0),Vector2(1,0),Vector2(1,1),Vector2(0,1) ], # O
- [ Vector2(-1,1),Vector2(0,1),Vector2(0,0),Vector2(1,0) ], # S
- [ Vector2(1,1),Vector2(0,1),Vector2(0,0),Vector2(-1,0) ], # Z
- [ Vector2(-1,1),Vector2(-1,0),Vector2(0,0),Vector2(1,0) ], # L
- [ Vector2(1,1),Vector2(1,0),Vector2(0,0),Vector2(-1,0) ], # J
- [ Vector2(0,1),Vector2(1,0),Vector2(0,0),Vector2(-1,0) ]] # T
-
+var block_colors = [
+ Color(1, 0.5, 0.5),
+ Color(0.5, 1, 0.5),
+ Color(0.5, 0.5, 1),
+ Color(0.8, 0.4, 0.8),
+ Color(0.8, 0.8, 0.4),
+ Color(0.4, 0.8, 0.8),
+ Color(0.7, 0.7, 0.7)]
-var block_rotations=[
- Matrix32( Vector2(1,0),Vector2(0,1), Vector2() ),
- Matrix32( Vector2(0,1),Vector2(-1,0), Vector2() ),
- Matrix32( Vector2(-1,0),Vector2(0,-1), Vector2() ),
- Matrix32( Vector2(0,-1),Vector2(1,0), Vector2() )
-]
-
+var block_shapes = [
+ [ Vector2(0, -1), Vector2(0, 0), Vector2(0, 1), Vector2(0, 2) ], # I
+ [ Vector2(0, 0), Vector2(1, 0), Vector2(1, 1), Vector2(0, 1) ], # O
+ [ Vector2(-1, 1), Vector2(0, 1), Vector2(0, 0), Vector2(1, 0) ], # S
+ [ Vector2(1, 1), Vector2(0, 1), Vector2(0, 0), Vector2(-1, 0) ], # Z
+ [ Vector2(-1, 1), Vector2(-1, 0), Vector2(0, 0), Vector2(1, 0) ], # L
+ [ Vector2(1, 1), Vector2(1, 0), Vector2(0, 0), Vector2(-1, 0) ], # J
+ [ Vector2(0, 1), Vector2(1, 0), Vector2(0, 0), Vector2(-1, 0) ]] # T
-var width=0
-var height=0
+var block_rotations = [
+ Matrix32(Vector2(1, 0), Vector2(0, 1), Vector2()),
+ Matrix32(Vector2(0, 1), Vector2(-1, 0), Vector2()),
+ Matrix32(Vector2(-1, 0), Vector2(0, -1), Vector2()),
+ Matrix32(Vector2(0, -1), Vector2(1, 0), Vector2())]
-var cells={}
+var width = 0
+var height = 0
-var piece_active=false
-var piece_shape=0
-var piece_pos=Vector2()
-var piece_rot=0
+var cells = {}
+var piece_active = false
+var piece_shape = 0
+var piece_pos = Vector2()
+var piece_rot = 0
-func piece_cell_xform(p,er=0):
- var r = (4+er+piece_rot)%4
- return piece_pos+block_rotations[r].xform(p)
-func _draw():
+func piece_cell_xform(p, er = 0):
+ var r = (4 + er + piece_rot) % 4
+ return piece_pos + block_rotations[r].xform(p)
+
- var sb = get_stylebox("bg","Tree") # use line edit bg
- draw_style_box(sb,Rect2(Vector2(),get_size()).grow(3))
+func _draw():
+ var sb = get_stylebox("bg", "Tree") # Use line edit bg
+ draw_style_box(sb, Rect2(Vector2(), get_size()).grow(3))
var bs = block.get_size()
for y in range(height):
for x in range(width):
- if (Vector2(x,y) in cells):
- draw_texture_rect(block,Rect2(Vector2(x,y)*bs,bs),false,block_colors[cells[Vector2(x,y)]])
-
+ if (Vector2(x, y) in cells):
+ draw_texture_rect(block, Rect2(Vector2(x, y)*bs, bs), false, block_colors[cells[Vector2(x, y)]])
+
if (piece_active):
-
for c in block_shapes[piece_shape]:
- draw_texture_rect(block,Rect2(piece_cell_xform(c)*bs,bs),false,block_colors[piece_shape])
-
+ draw_texture_rect(block, Rect2(piece_cell_xform(c)*bs, bs), false, block_colors[piece_shape])
-func piece_check_fit(ofs,er=0):
+func piece_check_fit(ofs, er = 0):
for c in block_shapes[piece_shape]:
- var pos = piece_cell_xform(c,er)+ofs
+ var pos = piece_cell_xform(c, er) + ofs
if (pos.x < 0):
return false
if (pos.y < 0):
@@ -88,130 +82,113 @@ func piece_check_fit(ofs,er=0):
if (pos in cells):
return false
- return true
+ return true
-func new_piece():
- piece_shape = randi() % MAX_SHAPES
- piece_pos = Vector2(width/2,0)
- piece_active=true
- piece_rot=0
- if (piece_shape==0):
- piece_pos.y+=1
-
+func new_piece():
+ piece_shape = randi() % MAX_SHAPES
+ piece_pos = Vector2(width/2, 0)
+ piece_active = true
+ piece_rot = 0
+ if (piece_shape == 0):
+ piece_pos.y += 1
+
if (not piece_check_fit(Vector2())):
- #game over
- #print("GAME OVER!")
+ # Game over
game_over()
-
- update()
-
+ update()
+
+
func test_collapse_rows():
- var accum_down=0
+ var accum_down = 0
for i in range(height):
var y = height - i - 1
var collapse = true
for x in range(width):
- if (Vector2(x,y) in cells):
+ if (Vector2(x, y) in cells):
if (accum_down):
- cells[ Vector2(x,y+accum_down) ] = cells[Vector2(x,y)]
+ cells[Vector2(x, y + accum_down)] = cells[Vector2(x, y)]
else:
- collapse=false
+ collapse = false
if (accum_down):
- cells.erase( Vector2(x,y+accum_down) )
-
- if (collapse):
- accum_down+=1
+ cells.erase(Vector2(x, y + accum_down))
-
- score+=accum_down*100
+ if (collapse):
+ accum_down += 1
+
+ score += accum_down*100
score_label.set_text(str(score))
-
-
+
+
func game_over():
+ piece_active = false
+ get_node("gameover").set_text("Game over!")
+ update()
+
- piece_active=false
- get_node("gameover").set_text("Game Over")
- update()
-
-
func restart_pressed():
+ score = 0
+ score_label.set_text("0")
+ cells.clear()
+ get_node("gameover").set_text("")
+ piece_active = true
+ get_node("../restart").release_focus()
+ update()
- score=0
- score_label.set_text("0")
- cells.clear()
- get_node("gameover").set_text("")
- piece_active=true
- get_node("../restart").release_focus()
- update()
-
-
func piece_move_down():
-
if (!piece_active):
return
- if (piece_check_fit(Vector2(0,1))):
- piece_pos.y+=1
- update()
+ if (piece_check_fit(Vector2(0, 1))):
+ piece_pos.y += 1
+ update()
else:
-
for c in block_shapes[piece_shape]:
var pos = piece_cell_xform(c)
- cells[pos]=piece_shape
+ cells[pos] = piece_shape
test_collapse_rows()
new_piece()
-
-func piece_rotate():
+func piece_rotate():
var adv = 1
- if (not piece_check_fit(Vector2(),1)):
+ if (not piece_check_fit(Vector2(), 1)):
return
piece_rot = (piece_rot + adv) % 4
update()
-
-
-
-func _input(ie):
+func _input(ie):
if (not piece_active):
return
if (!ie.is_pressed()):
return
if (ie.is_action("move_left")):
- if (piece_check_fit(Vector2(-1,0))):
- piece_pos.x-=1
+ if (piece_check_fit(Vector2(-1, 0))):
+ piece_pos.x -= 1
update()
elif (ie.is_action("move_right")):
- if (piece_check_fit(Vector2(1,0))):
- piece_pos.x+=1
+ if (piece_check_fit(Vector2(1, 0))):
+ piece_pos.x += 1
update()
elif (ie.is_action("move_down")):
piece_move_down()
elif (ie.is_action("rotate")):
piece_rotate()
-
-
-func setup(w,h):
- width=w
- height=h
- set_size( Vector2(w,h)*block.get_size() )
+
+
+func setup(w, h):
+ width = w
+ height = h
+ set_size(Vector2(w, h)*block.get_size())
new_piece()
get_node("timer").start()
-
-func _ready():
- # Initalization here
- setup(10,20)
+func _ready():
+ setup(10, 20)
score_label = get_node("../score")
-
+
set_process_input(true)
-
-
-
-
diff --git a/demos/2d/tetris/grid.xml b/demos/2d/tetris/grid.xml
index 072ffb5e75..49ad4ccc41 100644
--- a/demos/2d/tetris/grid.xml
+++ b/demos/2d/tetris/grid.xml
@@ -1,153 +1,209 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="2" version="0.99" version_name="Godot Engine v0.99.3037-pre-beta">
- <ext_resource path="res://grid.gd" type="GDScript"></ext_resource>
+<resource_file type="PackedScene" subresource_count="2" version="2.0" version_name="Godot Engine v2.0.alpha.custom_build">
+ <ext_resource path="res://grid.gd" type="Script" index="0"></ext_resource>
<main_resource>
- <string name="resource/name"> "" </string>
- <dictionary name="_bundled">
+ <dictionary name="_bundled" shared="false">
+ <string> "conn_count" </string>
+ <int> 1 </int>
+ <string> "conns" </string>
+ <int_array len="6"> 1, 0, 30, 29, 2, 0 </int_array>
+ <string> "editable_instances" </string>
+ <array len="0" shared="false">
+ </array>
<string> "names" </string>
- <string_array len="57">
+ <string_array len="31">
<string> "Grid" </string>
- <string> "Control" </string>
- <string> "process/process" </string>
- <string> "process/fixed_process" </string>
- <string> "process/input" </string>
- <string> "process/unhandled_input" </string>
- <string> "process/mode" </string>
- <string> "visibility/visible" </string>
- <string> "visibility/toplevel" </string>
- <string> "visibility/opacity" </string>
- <string> "visibility/self_opacity" </string>
- <string> "visibility/on_top" </string>
- <string> "visibility/blend_mode" </string>
- <string> "transform/notify" </string>
- <string> "anchor/left" </string>
- <string> "anchor/top" </string>
- <string> "anchor/right" </string>
- <string> "anchor/bottom" </string>
- <string> "margin/left" </string>
- <string> "margin/top" </string>
<string> "margin/right" </string>
<string> "margin/bottom" </string>
- <string> "hint/tooltip" </string>
- <string> "focus_neighbour/left" </string>
- <string> "focus_neighbour/top" </string>
- <string> "focus_neighbour/right" </string>
- <string> "focus_neighbour/bottom" </string>
<string> "focus/ignore_mouse" </string>
<string> "focus/stop_mouse" </string>
<string> "size_flags/horizontal" </string>
<string> "size_flags/vertical" </string>
- <string> "size_flags/stretch_ratio" </string>
<string> "script/script" </string>
<string> "__meta__" </string>
+ <string> "Control" </string>
<string> "timer" </string>
- <string> "Timer" </string>
+ <string> "process_mode" </string>
<string> "wait_time" </string>
<string> "one_shot" </string>
<string> "autostart" </string>
+ <string> "Timer" </string>
<string> "gameover" </string>
- <string> "Label" </string>
+ <string> "anchor/right" </string>
+ <string> "anchor/bottom" </string>
<string> "custom_colors/font_color" </string>
+ <string> "custom_colors/font_color_shadow" </string>
<string> "custom_constants/shadow_offset_x" </string>
<string> "custom_constants/shadow_offset_y" </string>
- <string> "range/min" </string>
- <string> "range/max" </string>
- <string> "range/step" </string>
- <string> "range/page" </string>
- <string> "range/value" </string>
- <string> "range/exp_edit" </string>
- <string> "rounded_values" </string>
- <string> "text" </string>
<string> "align" </string>
<string> "valign" </string>
- <string> "autowrap" </string>
+ <string> "percent_visible" </string>
+ <string> "lines_skipped" </string>
+ <string> "max_lines_visible" </string>
+ <string> "Label" </string>
<string> "piece_move_down" </string>
<string> "timeout" </string>
</string_array>
- <string> "version" </string>
- <int> 1 </int>
- <string> "conn_count" </string>
- <int> 1 </int>
<string> "node_count" </string>
<int> 3 </int>
+ <string> "node_paths" </string>
+ <array len="0" shared="false">
+ </array>
+ <string> "nodes" </string>
+ <int_array len="73"> -1, -1, 9, 0, -1, 8, 1, 0, 2, 0, 3, 1, 4, 2, 5, 3, 6, 3, 7, 4, 8, 5, 0, 0, 0, 15, 10, -1, 4, 11, 6, 12, 7, 13, 1, 14, 1, 0, 0, 0, 28, 16, -1, 14, 17, 6, 18, 6, 3, 2, 4, 2, 5, 3, 19, 8, 20, 9, 21, 6, 22, 6, 23, 6, 24, 6, 25, 7, 26, 10, 27, 11, 0 </int_array>
<string> "variants" </string>
- <array len="14">
+ <array len="12" shared="false">
+ <real> 40 </real>
<bool> False </bool>
- <int> 0 </int>
<bool> True </bool>
- <real> 1 </real>
- <real> 0 </real>
- <real> 40 </real>
- <string> "" </string>
- <node_path> "" </node_path>
<int> 2 </int>
- <resource resource_type="GDScript" path="res://grid.gd"> </resource>
- <dictionary>
+ <resource external="0"> </resource>
+ <dictionary shared="false">
+ <string> "__editor_plugin_screen__" </string>
+ <string> "2D" </string>
<string> "__editor_plugin_states__" </string>
- <dictionary>
- <string> "Script" </string>
- <dictionary>
- <string> "current" </string>
- <int> 0 </int>
- <string> "sources" </string>
- <array len="1">
- <string> "res://grid.gd" </string>
- </array>
- </dictionary>
+ <dictionary shared="false">
<string> "2D" </string>
- <dictionary>
+ <dictionary shared="false">
+ <string> "ofs" </string>
+ <vector2> -229.129, -80 </vector2>
+ <string> "snap_grid" </string>
+ <bool> False </bool>
+ <string> "snap_offset" </string>
+ <vector2> 0, 0 </vector2>
+ <string> "snap_pixel" </string>
+ <bool> False </bool>
+ <string> "snap_relative" </string>
+ <bool> False </bool>
+ <string> "snap_rotation" </string>
+ <bool> False </bool>
+ <string> "snap_rotation_offset" </string>
+ <real> 0 </real>
+ <string> "snap_rotation_step" </string>
+ <real> 0.261799 </real>
+ <string> "snap_show_grid" </string>
+ <bool> False </bool>
+ <string> "snap_step" </string>
+ <vector2> 10, 10 </vector2>
<string> "zoom" </string>
<real> 1 </real>
- <string> "ofs" </string>
- <vector2> -69, -22 </vector2>
</dictionary>
<string> "3D" </string>
- <dictionary>
- <string> "zfar" </string>
- <real> 500 </real>
+ <dictionary shared="false">
+ <string> "ambient_light_color" </string>
+ <color> 0.15, 0.15, 0.15, 1 </color>
+ <string> "default_light" </string>
+ <bool> True </bool>
+ <string> "default_srgb" </string>
+ <bool> False </bool>
+ <string> "deflight_rot_x" </string>
+ <real> 0.942478 </real>
+ <string> "deflight_rot_y" </string>
+ <real> 0.628319 </real>
<string> "fov" </string>
<real> 45 </real>
- <string> "window_mode" </string>
- <int> 0 </int>
- <string> "window_0" </string>
- <dictionary>
- <string> "distance" </string>
- <real> 4 </real>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "x_rot" </string>
- <real> 0.337 </real>
- <string> "y_rot" </string>
- <real> -0.575 </real>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
+ <string> "show_grid" </string>
+ <bool> True </bool>
+ <string> "show_origin" </string>
+ <bool> True </bool>
+ <string> "viewport_mode" </string>
+ <int> 1 </int>
+ <string> "viewports" </string>
+ <array len="4" shared="false">
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
+ <string> "listener" </string>
+ <bool> True </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
+ <string> "x_rot" </string>
+ <real> 0 </real>
+ <string> "y_rot" </string>
+ <real> 0 </real>
+ </dictionary>
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
+ <string> "x_rot" </string>
+ <real> 0 </real>
+ <string> "y_rot" </string>
+ <real> 0 </real>
+ </dictionary>
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
+ <string> "x_rot" </string>
+ <real> 0 </real>
+ <string> "y_rot" </string>
+ <real> 0 </real>
+ </dictionary>
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
+ <string> "x_rot" </string>
+ <real> 0 </real>
+ <string> "y_rot" </string>
+ <real> 0 </real>
+ </dictionary>
+ </array>
+ <string> "zfar" </string>
+ <real> 500 </real>
<string> "znear" </string>
<real> 0.1 </real>
</dictionary>
+ <string> "Anim" </string>
+ <dictionary shared="false">
+ <string> "visible" </string>
+ <bool> False </bool>
+ </dictionary>
</dictionary>
<string> "__editor_run_settings__" </string>
- <dictionary>
+ <dictionary shared="false">
<string> "custom_args" </string>
<string> "-l $scene" </string>
<string> "run_mode" </string>
<int> 0 </int>
</dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "Script" </string>
</dictionary>
- <resource name=""></resource> <int> 1 </int>
+ <int> 1 </int>
+ <real> 1 </real>
+ <color> 1, 1, 1, 1 </color>
<color> 0, 0, 0, 1 </color>
+ <int> 0 </int>
+ <int> -1 </int>
</array>
- <string> "nodes" </string>
- <int_array len="193"> -1, -1, 1, 0, -1, 32, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 7, 2, 8, 0, 9, 3, 10, 3, 11, 2, 12, 1, 13, 0, 14, 1, 15, 1, 16, 1, 17, 1, 18, 4, 19, 4, 20, 5, 21, 5, 22, 6, 23, 7, 24, 7, 25, 7, 26, 7, 27, 0, 28, 2, 29, 8, 30, 8, 31, 3, 32, 9, 33, 10, 0, 0, 0, 35, 34, -1, 9, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 36, 3, 37, 0, 38, 0, 32, 11, 0, 0, 0, 40, 39, -1, 45, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 7, 2, 8, 0, 9, 3, 10, 3, 11, 2, 12, 1, 13, 0, 14, 1, 15, 1, 16, 12, 17, 12, 18, 4, 19, 4, 20, 4, 21, 4, 22, 6, 23, 7, 24, 7, 25, 7, 26, 7, 27, 2, 28, 2, 29, 8, 30, 1, 31, 3, 41, 13, 42, 12, 43, 12, 44, 4, 45, 3, 46, 3, 47, 3, 48, 4, 49, 0, 50, 0, 51, 6, 52, 12, 53, 12, 54, 0, 32, 11, 0 </int_array>
- <string> "conns" </string>
- <int_array len="6"> 1, 0, 56, 55, 2, 0 </int_array>
+ <string> "version" </string>
+ <int> 2 </int>
</dictionary>
- <resource name="script/script"></resource>
+
</main_resource>
</resource_file> \ No newline at end of file
diff --git a/demos/2d/tetris/tetris.xml b/demos/2d/tetris/tetris.xml
index 1b5e5afeb0..a8e47a8ae4 100644
--- a/demos/2d/tetris/tetris.xml
+++ b/demos/2d/tetris/tetris.xml
@@ -1,147 +1,192 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="2" version="0.99" version_name="Godot Engine v0.99.3037-pre-beta">
- <ext_resource path="res://grid.xml" type="PackedScene"></ext_resource>
+<resource_file type="PackedScene" subresource_count="2" version="2.0" version_name="Godot Engine v2.0.alpha.custom_build">
+ <ext_resource path="res://grid.xml" type="PackedScene" index="0"></ext_resource>
<main_resource>
- <string name="resource/name"> "" </string>
- <dictionary name="_bundled">
+ <dictionary name="_bundled" shared="false">
+ <string> "conn_count" </string>
+ <int> 1 </int>
+ <string> "conns" </string>
+ <int_array len="6"> 4, 1, 23, 22, 2, 0 </int_array>
+ <string> "editable_instances" </string>
+ <array len="0" shared="false">
+ </array>
<string> "names" </string>
- <string_array len="59">
+ <string_array len="24">
<string> "Tetris" </string>
- <string> "Panel" </string>
- <string> "process/process" </string>
- <string> "process/fixed_process" </string>
- <string> "process/input" </string>
- <string> "process/unhandled_input" </string>
- <string> "process/mode" </string>
- <string> "visibility/visible" </string>
- <string> "visibility/toplevel" </string>
- <string> "visibility/opacity" </string>
- <string> "visibility/self_opacity" </string>
- <string> "visibility/on_top" </string>
- <string> "visibility/blend_mode" </string>
- <string> "transform/notify" </string>
- <string> "anchor/left" </string>
- <string> "anchor/top" </string>
- <string> "anchor/right" </string>
- <string> "anchor/bottom" </string>
- <string> "margin/left" </string>
- <string> "margin/top" </string>
<string> "margin/right" </string>
<string> "margin/bottom" </string>
- <string> "hint/tooltip" </string>
- <string> "focus_neighbour/left" </string>
- <string> "focus_neighbour/top" </string>
- <string> "focus_neighbour/right" </string>
- <string> "focus_neighbour/bottom" </string>
<string> "focus/ignore_mouse" </string>
<string> "focus/stop_mouse" </string>
<string> "size_flags/horizontal" </string>
<string> "size_flags/vertical" </string>
- <string> "size_flags/stretch_ratio" </string>
- <string> "script/script" </string>
<string> "__meta__" </string>
+ <string> "Panel" </string>
<string> "Grid" </string>
- <string> "Control" </string>
+ <string> "margin/left" </string>
+ <string> "margin/top" </string>
<string> "Label" </string>
- <string> "range/min" </string>
- <string> "range/max" </string>
- <string> "range/step" </string>
- <string> "range/page" </string>
- <string> "range/value" </string>
- <string> "range/exp_edit" </string>
- <string> "rounded_values" </string>
<string> "text" </string>
- <string> "align" </string>
- <string> "valign" </string>
- <string> "autowrap" </string>
+ <string> "percent_visible" </string>
+ <string> "lines_skipped" </string>
+ <string> "max_lines_visible" </string>
<string> "score" </string>
<string> "restart" </string>
- <string> "Button" </string>
- <string> "disabled" </string>
<string> "toggle_mode" </string>
- <string> "click_on_press" </string>
- <string> "icon" </string>
<string> "flat" </string>
- <string> "clip_text" </string>
+ <string> "Button" </string>
<string> "restart_pressed" </string>
<string> "pressed" </string>
</string_array>
- <string> "version" </string>
- <int> 1 </int>
- <string> "conn_count" </string>
- <int> 1 </int>
<string> "node_count" </string>
<int> 5 </int>
+ <string> "node_paths" </string>
+ <array len="0" shared="false">
+ </array>
+ <string> "nodes" </string>
+ <int_array len="123"> -1, -1, 8, 0, -1, 7, 1, 0, 2, 0, 3, 1, 4, 2, 5, 3, 6, 3, 7, 4, 0, 0, 0, 2147483647, 9, 5, 4, 10, 6, 11, 7, 1, 8, 2, 9, 0, 0, 0, 12, 12, -1, 11, 10, 10, 11, 11, 1, 12, 2, 13, 3, 2, 4, 2, 5, 3, 13, 14, 14, 15, 15, 16, 16, 17, 0, 0, 0, 12, 17, -1, 11, 10, 18, 11, 19, 1, 20, 2, 21, 3, 2, 4, 2, 5, 3, 13, 22, 14, 15, 15, 16, 16, 17, 0, 0, 0, 21, 18, -1, 11, 10, 10, 11, 23, 1, 24, 2, 25, 3, 1, 4, 2, 5, 3, 6, 3, 19, 1, 13, 26, 20, 1, 0 </int_array>
<string> "variants" </string>
- <array len="30">
+ <array len="27" shared="false">
+ <real> 400 </real>
<bool> False </bool>
- <int> 0 </int>
<bool> True </bool>
- <real> 1 </real>
- <real> 0 </real>
- <real> 400 </real>
- <string> "" </string>
- <node_path> "" </node_path>
<int> 2 </int>
- <resource name=""></resource> <dictionary>
+ <dictionary shared="false">
+ <string> "__editor_plugin_screen__" </string>
+ <string> "2D" </string>
<string> "__editor_plugin_states__" </string>
- <dictionary>
- <string> "Script" </string>
- <dictionary>
- <string> "current" </string>
- <int> 0 </int>
- <string> "sources" </string>
- <array len="1">
- <string> "res://grid.gd" </string>
- </array>
- </dictionary>
+ <dictionary shared="false">
<string> "2D" </string>
- <dictionary>
+ <dictionary shared="false">
+ <string> "ofs" </string>
+ <vector2> -229.129, -54.344 </vector2>
+ <string> "snap_grid" </string>
+ <bool> False </bool>
+ <string> "snap_offset" </string>
+ <vector2> 0, 0 </vector2>
+ <string> "snap_pixel" </string>
+ <bool> False </bool>
+ <string> "snap_relative" </string>
+ <bool> False </bool>
+ <string> "snap_rotation" </string>
+ <bool> False </bool>
+ <string> "snap_rotation_offset" </string>
+ <real> 0 </real>
+ <string> "snap_rotation_step" </string>
+ <real> 0.261799 </real>
+ <string> "snap_show_grid" </string>
+ <bool> False </bool>
+ <string> "snap_step" </string>
+ <vector2> 10, 10 </vector2>
<string> "zoom" </string>
<real> 1.360374 </real>
- <string> "ofs" </string>
- <vector2> -44.5757, -54.344 </vector2>
</dictionary>
<string> "3D" </string>
- <dictionary>
- <string> "zfar" </string>
- <real> 500 </real>
+ <dictionary shared="false">
+ <string> "ambient_light_color" </string>
+ <color> 0.15, 0.15, 0.15, 1 </color>
+ <string> "default_light" </string>
+ <bool> True </bool>
+ <string> "default_srgb" </string>
+ <bool> False </bool>
+ <string> "deflight_rot_x" </string>
+ <real> 0.942478 </real>
+ <string> "deflight_rot_y" </string>
+ <real> 0.628319 </real>
<string> "fov" </string>
<real> 45 </real>
- <string> "window_mode" </string>
- <int> 0 </int>
- <string> "window_0" </string>
- <dictionary>
- <string> "distance" </string>
- <real> 4 </real>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "x_rot" </string>
- <real> 0.337 </real>
- <string> "y_rot" </string>
- <real> -0.575 </real>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
+ <string> "show_grid" </string>
+ <bool> True </bool>
+ <string> "show_origin" </string>
+ <bool> True </bool>
+ <string> "viewport_mode" </string>
+ <int> 1 </int>
+ <string> "viewports" </string>
+ <array len="4" shared="false">
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
+ <string> "listener" </string>
+ <bool> True </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
+ <string> "x_rot" </string>
+ <real> 0 </real>
+ <string> "y_rot" </string>
+ <real> 0 </real>
+ </dictionary>
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
+ <string> "x_rot" </string>
+ <real> 0 </real>
+ <string> "y_rot" </string>
+ <real> 0 </real>
+ </dictionary>
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
+ <string> "x_rot" </string>
+ <real> 0 </real>
+ <string> "y_rot" </string>
+ <real> 0 </real>
+ </dictionary>
+ <dictionary shared="false">
+ <string> "distance" </string>
+ <real> 4 </real>
+ <string> "listener" </string>
+ <bool> False </bool>
+ <string> "pos" </string>
+ <vector3> 0, 0, 0 </vector3>
+ <string> "use_environment" </string>
+ <bool> False </bool>
+ <string> "use_orthogonal" </string>
+ <bool> False </bool>
+ <string> "x_rot" </string>
+ <real> 0 </real>
+ <string> "y_rot" </string>
+ <real> 0 </real>
+ </dictionary>
+ </array>
+ <string> "zfar" </string>
+ <real> 500 </real>
<string> "znear" </string>
<real> 0.1 </real>
</dictionary>
+ <string> "Anim" </string>
+ <dictionary shared="false">
+ <string> "visible" </string>
+ <bool> False </bool>
+ </dictionary>
</dictionary>
<string> "__editor_run_settings__" </string>
- <dictionary>
+ <dictionary shared="false">
<string> "custom_args" </string>
<string> "-l $scene" </string>
<string> "run_mode" </string>
<int> 0 </int>
</dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "2D" </string>
</dictionary>
- <resource resource_type="PackedScene" path="res://grid.xml"> </resource>
+ <resource external="0"> </resource>
<real> 40 </real>
<real> 35 </real>
<real> 80 </real>
@@ -151,6 +196,9 @@
<real> 283 </real>
<real> 49 </real>
<string> "Score:" </string>
+ <real> 1 </real>
+ <int> 0 </int>
+ <int> -1 </int>
<real> 252 </real>
<real> 55 </real>
<real> 293 </real>
@@ -161,11 +209,9 @@
<real> 311 </real>
<string> "Restart" </string>
</array>
- <string> "nodes" </string>
- <int_array len="351"> -1, -1, 1, 0, -1, 32, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 7, 2, 8, 0, 9, 3, 10, 3, 11, 2, 12, 1, 13, 0, 14, 1, 15, 1, 16, 1, 17, 1, 18, 4, 19, 4, 20, 5, 21, 5, 22, 6, 23, 7, 24, 7, 25, 7, 26, 7, 27, 0, 28, 2, 29, 8, 30, 8, 31, 3, 32, 9, 33, 10, 0, 0, 0, 35, 34, 11, 4, 18, 12, 19, 13, 20, 14, 21, 15, 0, 0, 0, 36, 36, -1, 42, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 7, 2, 8, 0, 9, 3, 10, 3, 11, 2, 12, 1, 13, 0, 14, 1, 15, 1, 16, 1, 17, 1, 18, 16, 19, 17, 20, 18, 21, 19, 22, 6, 23, 7, 24, 7, 25, 7, 26, 7, 27, 2, 28, 2, 29, 8, 30, 1, 31, 3, 37, 4, 38, 3, 39, 3, 40, 3, 41, 4, 42, 0, 43, 0, 44, 20, 45, 1, 46, 1, 47, 0, 32, 9, 0, 0, 0, 36, 48, -1, 42, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 7, 2, 8, 0, 9, 3, 10, 3, 11, 2, 12, 1, 13, 0, 14, 1, 15, 1, 16, 1, 17, 1, 18, 21, 19, 22, 20, 23, 21, 24, 22, 6, 23, 7, 24, 7, 25, 7, 26, 7, 27, 2, 28, 2, 29, 8, 30, 1, 31, 3, 37, 4, 38, 3, 39, 3, 40, 3, 41, 4, 42, 0, 43, 0, 44, 25, 45, 1, 46, 1, 47, 0, 32, 9, 0, 0, 0, 50, 49, -1, 38, 2, 0, 3, 0, 4, 0, 5, 0, 6, 1, 7, 2, 8, 0, 9, 3, 10, 3, 11, 2, 12, 1, 13, 0, 14, 1, 15, 1, 16, 1, 17, 1, 18, 16, 19, 26, 20, 27, 21, 28, 22, 6, 23, 7, 24, 7, 25, 7, 26, 7, 27, 0, 28, 2, 29, 8, 30, 8, 31, 3, 51, 0, 52, 0, 53, 0, 44, 29, 54, 9, 55, 0, 56, 0, 32, 9, 0 </int_array>
- <string> "conns" </string>
- <int_array len="6"> 4, 1, 58, 57, 2, 0 </int_array>
+ <string> "version" </string>
+ <int> 2 </int>
</dictionary>
- <resource name="script/script"></resource>
+
</main_resource>
</resource_file> \ No newline at end of file
diff --git a/demos/2d/texscreen/bubbles.gd b/demos/2d/texscreen/bubbles.gd
index 2ee227a928..400da1a205 100644
--- a/demos/2d/texscreen/bubbles.gd
+++ b/demos/2d/texscreen/bubbles.gd
@@ -1,17 +1,11 @@
extends Control
-# member variables here, example:
-# var a=2
-# var b="textvar"
+# Member variables
+const MAX_BUBBLES = 10
-const MAX_BUBBLES=10
func _ready():
- # Initialization here
for i in range(MAX_BUBBLES):
var bubble = preload("res://lens.scn").instance()
add_child(bubble)
- pass
-
-
diff --git a/demos/2d/texscreen/bubbles.scn b/demos/2d/texscreen/bubbles.scn
index 41026aceed..8509b3811c 100644
--- a/demos/2d/texscreen/bubbles.scn
+++ b/demos/2d/texscreen/bubbles.scn
Binary files differ
diff --git a/demos/2d/texscreen/engine.cfg b/demos/2d/texscreen/engine.cfg
index fb683dfc1d..92d0e98d5b 100644
--- a/demos/2d/texscreen/engine.cfg
+++ b/demos/2d/texscreen/engine.cfg
@@ -2,6 +2,7 @@
name="Glass Bubbles (Texscreen)"
main_scene="res://bubbles.scn"
+icon="res://icon.png"
[display]
diff --git a/demos/2d/texscreen/icon.png b/demos/2d/texscreen/icon.png
new file mode 100644
index 0000000000..d74d025ced
--- /dev/null
+++ b/demos/2d/texscreen/icon.png
Binary files differ
diff --git a/demos/2d/texscreen/lens.gd b/demos/2d/texscreen/lens.gd
index 2ccbfba497..d1007553b0 100644
--- a/demos/2d/texscreen/lens.gd
+++ b/demos/2d/texscreen/lens.gd
@@ -1,37 +1,32 @@
extends BackBufferCopy
-# member variables here, example:
-# var a=2
-# var b="textvar"
-const MOTION_SPEED=150
+# Member variables
+const MOTION_SPEED = 150
+
+var vsize
+var dir
-var vsize;
-var dir;
func _process(delta):
- var pos = get_pos() + dir * delta * MOTION_SPEED
+ var pos = get_pos() + dir*delta*MOTION_SPEED
+
+ if (pos.x < 0):
+ dir.x = abs(dir.x)
+ elif (pos.x > vsize.x):
+ dir.x = -abs(dir.x)
+
+ if (pos.y < 0):
+ dir.y = abs(dir.y)
+ elif (pos.y > vsize.y):
+ dir.y = -abs(dir.y)
- if (pos.x<0):
- dir.x=abs(dir.x)
- elif (pos.x>vsize.x):
- dir.x=-abs(dir.x)
-
- if (pos.y<0):
- dir.y=abs(dir.y)
- elif (pos.y>vsize.y):
- dir.y=-abs(dir.y)
-
set_pos(pos)
+
func _ready():
vsize = get_viewport_rect().size
- var pos = vsize * Vector2(randf(),randf());
- set_pos(pos);
- dir = Vector2(randf()*2.0-1,randf()*2.0-1).normalized()
+ var pos = vsize*Vector2(randf(), randf())
+ set_pos(pos)
+ dir = Vector2(randf()*2.0 - 1, randf()*2.0 - 1).normalized()
set_process(true)
-
- # Initialization here
- pass
-
-
diff --git a/demos/2d/texscreen/lens.scn b/demos/2d/texscreen/lens.scn
index 5c6f8b7af8..530a0b1eb0 100644
--- a/demos/2d/texscreen/lens.scn
+++ b/demos/2d/texscreen/lens.scn
Binary files differ
diff --git a/demos/3d/fixed_materials/fixed_materials.scn b/demos/3d/fixed_materials/fixed_materials.scn
index de14ccdb15..94809b9a5e 100644
--- a/demos/3d/fixed_materials/fixed_materials.scn
+++ b/demos/3d/fixed_materials/fixed_materials.scn
Binary files differ
diff --git a/demos/3d/kinematic_char/cubio.gd b/demos/3d/kinematic_char/cubio.gd
index 058b919d05..769ada3bca 100644
--- a/demos/3d/kinematic_char/cubio.gd
+++ b/demos/3d/kinematic_char/cubio.gd
@@ -1,10 +1,7 @@
extends KinematicBody
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
+# Member variables
var g = -9.8
var vel = Vector3()
const MAX_SPEED = 5
@@ -13,83 +10,77 @@ const ACCEL= 2
const DEACCEL= 4
const MAX_SLOPE_ANGLE = 30
-func _fixed_process(delta):
- var dir = Vector3() #where does the player intend to walk to
+func _fixed_process(delta):
+ var dir = Vector3() # Where does the player intend to walk to
var cam_xform = get_node("target/camera").get_global_transform()
if (Input.is_action_pressed("move_forward")):
- dir+=-cam_xform.basis[2]
+ dir += -cam_xform.basis[2]
if (Input.is_action_pressed("move_backwards")):
- dir+=cam_xform.basis[2]
+ dir += cam_xform.basis[2]
if (Input.is_action_pressed("move_left")):
- dir+=-cam_xform.basis[0]
+ dir += -cam_xform.basis[0]
if (Input.is_action_pressed("move_right")):
- dir+=cam_xform.basis[0]
-
- dir.y=0
- dir=dir.normalized()
-
- vel.y+=delta*g
+ dir += cam_xform.basis[0]
+
+ dir.y = 0
+ dir = dir.normalized()
+
+ vel.y += delta*g
var hvel = vel
- hvel.y=0
+ hvel.y = 0
var target = dir*MAX_SPEED
var accel
- if (dir.dot(hvel) >0):
- accel=ACCEL
+ if (dir.dot(hvel) > 0):
+ accel = ACCEL
else:
- accel=DEACCEL
-
- hvel = hvel.linear_interpolate(target,accel*delta)
+ accel = DEACCEL
+
+ hvel = hvel.linear_interpolate(target, accel*delta)
+
+ vel.x = hvel.x
+ vel.z = hvel.z
- vel.x=hvel.x;
- vel.z=hvel.z
-
var motion = move(vel*delta)
-
+
var on_floor = false
var original_vel = vel
-
-
- var floor_velocity=Vector3()
-
- var attempts=4
+ var floor_velocity = Vector3()
+ var attempts = 4
while(is_colliding() and attempts):
- var n=get_collision_normal()
-
- if ( rad2deg(acos(n.dot( Vector3(0,1,0)))) < MAX_SLOPE_ANGLE ):
- #if angle to the "up" vectors is < angle tolerance
- #char is on floor
- floor_velocity=get_collider_velocity()
- on_floor=true
+ var n = get_collision_normal()
+
+ if (rad2deg(acos(n.dot(Vector3(0, 1, 0)))) < MAX_SLOPE_ANGLE):
+ # If angle to the "up" vectors is < angle tolerance,
+ # char is on floor
+ floor_velocity = get_collider_velocity()
+ on_floor = true
motion = n.slide(motion)
vel = n.slide(vel)
if (original_vel.dot(vel) > 0):
- #do not allow to slide towads the opposite direction we were coming from
+ # Do not allow to slide towads the opposite direction we were coming from
motion=move(motion)
- if (motion.length()<0.001):
+ if (motion.length() < 0.001):
break
- attempts-=1
-
- if (on_floor and floor_velocity!=Vector3()):
- move(floor_velocity*delta)
+ attempts -= 1
+
+ if (on_floor and floor_velocity != Vector3()):
+ move(floor_velocity*delta)
if (on_floor and Input.is_action_pressed("jump")):
- vel.y=JUMP_SPEED
-
+ vel.y = JUMP_SPEED
+
var crid = get_node("../elevator1").get_rid()
-# print(crid," : ",PS.body_get_state(crid,PS.BODY_STATE_TRANSFORM))
+
func _ready():
- # Initalization here
set_fixed_process(true)
- pass
-func _on_tcube_body_enter( body ):
+func _on_tcube_body_enter(body):
get_node("../ty").show()
- pass # replace with function body
diff --git a/demos/3d/kinematic_char/follow_camera.gd b/demos/3d/kinematic_char/follow_camera.gd
index cf7172d7bb..37a1402053 100644
--- a/demos/3d/kinematic_char/follow_camera.gd
+++ b/demos/3d/kinematic_char/follow_camera.gd
@@ -1,69 +1,57 @@
extends Camera
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
-var collision_exception=[]
-export var min_distance=0.5
-export var max_distance=4.0
-export var angle_v_adjust=0.0
-export var autoturn_ray_aperture=25
-export var autoturn_speed=50
+# Member variables
+var collision_exception = []
+export var min_distance = 0.5
+export var max_distance = 4.0
+export var angle_v_adjust = 0.0
+export var autoturn_ray_aperture = 25
+export var autoturn_speed = 50
var max_height = 2.0
var min_height = 0
+
func _fixed_process(dt):
- var target = get_parent().get_global_transform().origin
+ var target = get_parent().get_global_transform().origin
var pos = get_global_transform().origin
- var up = Vector3(0,1,0)
+ var up = Vector3(0, 1, 0)
var delta = pos - target
- #regular delta follow
+ # Regular delta follow
- #check ranges
-
+ # Check ranges
if (delta.length() < min_distance):
- delta = delta.normalized() * min_distance
+ delta = delta.normalized()*min_distance
elif (delta.length() > max_distance):
- delta = delta.normalized() * max_distance
+ delta = delta.normalized()*max_distance
- #check upper and lower height
- if ( delta.y > max_height):
+ # Check upper and lower height
+ if (delta.y > max_height):
delta.y = max_height
- if ( delta.y < min_height):
+ if (delta.y < min_height):
delta.y = min_height
-
+
pos = target + delta
- look_at_from_pos(pos,target,up)
+ look_at_from_pos(pos, target, up)
- #turn a little up or down
+ # Turn a little up or down
var t = get_transform()
- t.basis = Matrix3(t.basis[0],deg2rad(angle_v_adjust)) * t.basis
+ t.basis = Matrix3(t.basis[0], deg2rad(angle_v_adjust))*t.basis
set_transform(t)
-
-
-func _ready():
-#find collision exceptions for ray
+func _ready():
+ # Find collision exceptions for ray
var node = self
while(node):
if (node extends RigidBody):
collision_exception.append(node.get_rid())
break
else:
- node=node.get_parent()
- # Initalization here
+ node = node.get_parent()
set_fixed_process(true)
- #this detaches the camera transform from the parent spatial node
+ # This detaches the camera transform from the parent spatial node
set_as_toplevel(true)
-
-
-
-
-
-
diff --git a/demos/3d/kinematic_char/level.scn b/demos/3d/kinematic_char/level.scn
index 8be64c61c0..0082f55f43 100644
--- a/demos/3d/kinematic_char/level.scn
+++ b/demos/3d/kinematic_char/level.scn
Binary files differ
diff --git a/demos/3d/kinematic_char/purplecube.scn b/demos/3d/kinematic_char/purplecube.scn
index ab758366fd..e3ed1bf84b 100644
--- a/demos/3d/kinematic_char/purplecube.scn
+++ b/demos/3d/kinematic_char/purplecube.scn
Binary files differ
diff --git a/demos/3d/mousepick_test/mousepick.gd b/demos/3d/mousepick_test/mousepick.gd
index c96091b650..674ec7ff6f 100644
--- a/demos/3d/mousepick_test/mousepick.gd
+++ b/demos/3d/mousepick_test/mousepick.gd
@@ -1,15 +1,12 @@
extends RigidBody
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
+# Member variables
var gray_mat = FixedMaterial.new()
+var selected = false
-var selected=false
-func _input_event(camera,event,pos,normal,shape):
+func _input_event(camera, event, pos, normal, shape):
if (event.type==InputEvent.MOUSE_BUTTON and event.pressed):
if (not selected):
get_node("mesh").set_material_override(gray_mat)
@@ -17,16 +14,11 @@ func _input_event(camera,event,pos,normal,shape):
get_node("mesh").set_material_override(null)
selected = not selected
-
-func _mouse_enter():
- get_node("mesh").set_scale( Vector3(1.1,1.1,1.1) )
-func _mouse_exit():
- get_node("mesh").set_scale( Vector3(1,1,1) )
-
-func _ready():
- # Initalization here
- pass
+func _mouse_enter():
+ get_node("mesh").set_scale(Vector3(1.1, 1.1, 1.1))
+func _mouse_exit():
+ get_node("mesh").set_scale(Vector3(1, 1, 1))
diff --git a/demos/3d/mousepick_test/mousepick.scn b/demos/3d/mousepick_test/mousepick.scn
index 7ecac46a86..0b6c33c119 100644
--- a/demos/3d/mousepick_test/mousepick.scn
+++ b/demos/3d/mousepick_test/mousepick.scn
Binary files differ
diff --git a/demos/3d/navmesh/icon.png b/demos/3d/navmesh/icon.png
new file mode 100644
index 0000000000..51fef7b2df
--- /dev/null
+++ b/demos/3d/navmesh/icon.png
Binary files differ
diff --git a/demos/3d/navmesh/navmesh.gd b/demos/3d/navmesh/navmesh.gd
index b5dc488ec3..30b8cfb32a 100644
--- a/demos/3d/navmesh/navmesh.gd
+++ b/demos/3d/navmesh/navmesh.gd
@@ -1,61 +1,54 @@
extends Navigation
-# member variables here, example:
-# var a=2
-# var b="textvar"
+# Member variables
+const SPEED = 4.0
-const SPEED=4.0
+var camrot = 0.0
-var camrot=0.0
-
-var begin=Vector3()
-var end=Vector3()
+var begin = Vector3()
+var end = Vector3()
var m = FixedMaterial.new()
-var path=[]
-
-func _process(delta):
+var path = []
+var draw_path = false
- if (path.size()>1):
-
+func _process(delta):
+ if (path.size() > 1):
var to_walk = delta*SPEED
- var to_watch = Vector3(0,1,0)
- while(to_walk>0 and path.size()>=2):
- var pfrom = path[path.size()-1]
- var pto = path[path.size()-2]
+ var to_watch = Vector3(0, 1, 0)
+ while(to_walk > 0 and path.size() >= 2):
+ var pfrom = path[path.size() - 1]
+ var pto = path[path.size() - 2]
to_watch = (pto - pfrom).normalized()
var d = pfrom.distance_to(pto)
- if (d<=to_walk):
- path.remove(path.size()-1)
- to_walk-=d
+ if (d <= to_walk):
+ path.remove(path.size() - 1)
+ to_walk -= d
else:
- path[path.size()-1] = pfrom.linear_interpolate(pto,to_walk/d)
- to_walk=0
-
- var atpos = path[path.size()-1]
+ path[path.size() - 1] = pfrom.linear_interpolate(pto, to_walk/d)
+ to_walk = 0
+
+ var atpos = path[path.size() - 1]
var atdir = to_watch
- atdir.y=0
+ atdir.y = 0
var t = Transform()
- t.origin=atpos
- t=t.looking_at(atpos+atdir,Vector3(0,1,0))
+ t.origin = atpos
+ t=t.looking_at(atpos + atdir, Vector3(0, 1, 0))
get_node("robot_base").set_transform(t)
- if (path.size()<2):
- path=[]
+ if (path.size() < 2):
+ path = []
set_process(false)
-
else:
set_process(false)
-var draw_path=false
func _update_path():
-
- var p = get_simple_path(begin,end,true)
- path=Array(p) # Vector3array to complex to use, convert to regular array
+ var p = get_simple_path(begin, end, true)
+ path = Array(p) # Vector3array too complex to use, convert to regular array
path.invert()
set_process(true)
@@ -63,48 +56,40 @@ func _update_path():
var im = get_node("draw")
im.set_material_override(m)
im.clear()
- im.begin(Mesh.PRIMITIVE_POINTS,null)
+ im.begin(Mesh.PRIMITIVE_POINTS, null)
im.add_vertex(begin)
im.add_vertex(end)
im.end()
- im.begin(Mesh.PRIMITIVE_LINE_STRIP,null)
+ im.begin(Mesh.PRIMITIVE_LINE_STRIP, null)
for x in p:
im.add_vertex(x)
im.end()
-func _input(ev):
- if (ev.type==InputEvent.MOUSE_BUTTON and ev.button_index==BUTTON_LEFT and ev.pressed):
-
- var from = get_node("cambase/Camera").project_ray_origin(ev.pos)
- var to = from+get_node("cambase/Camera").project_ray_normal(ev.pos)*100
- var p = get_closest_point_to_segment(from,to)
-
- begin=get_closest_point(get_node("robot_base").get_translation())
- end=p
+func _input(event):
+ if (event.type == InputEvent.MOUSE_BUTTON and event.button_index == BUTTON_LEFT and event.pressed):
+ var from = get_node("cambase/Camera").project_ray_origin(event.pos)
+ var to = from + get_node("cambase/Camera").project_ray_normal(event.pos)*100
+ var p = get_closest_point_to_segment(from, to)
+
+ begin = get_closest_point(get_node("robot_base").get_translation())
+ end = p
_update_path()
-
- if (ev.type==InputEvent.MOUSE_MOTION):
- if (ev.button_mask&BUTTON_MASK_MIDDLE):
-
- camrot+=ev.relative_x*0.005
- get_node("cambase").set_rotation(Vector3(0,camrot,0))
+
+ if (event.type == InputEvent.MOUSE_MOTION):
+ if (event.button_mask&BUTTON_MASK_MIDDLE):
+ camrot += event.relative_x*0.005
+ get_node("cambase").set_rotation(Vector3(0, camrot, 0))
print("camrot ", camrot)
-
func _ready():
- # Initalization here
set_process_input(true)
m.set_line_width(3)
m.set_point_size(3)
- m.set_fixed_flag(FixedMaterial.FLAG_USE_POINT_SIZE,true)
- m.set_flag(Material.FLAG_UNSHADED,true)
+ m.set_fixed_flag(FixedMaterial.FLAG_USE_POINT_SIZE, true)
+ m.set_flag(Material.FLAG_UNSHADED, true)
#begin = get_closest_point(get_node("start").get_translation())
#end = get_closest_point(get_node("end").get_translation())
#call_deferred("_update_path")
-
- pass
-
-
diff --git a/demos/3d/navmesh/navmesh.scn b/demos/3d/navmesh/navmesh.scn
index 1202985dec..33183781ad 100644
--- a/demos/3d/navmesh/navmesh.scn
+++ b/demos/3d/navmesh/navmesh.scn
Binary files differ
diff --git a/demos/3d/platformer/bullet.gd b/demos/3d/platformer/bullet.gd
index 842e6874e9..29219403bd 100644
--- a/demos/3d/platformer/bullet.gd
+++ b/demos/3d/platformer/bullet.gd
@@ -1,14 +1,5 @@
extends RigidBody
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
-var disabled=false
-
-func _ready():
- # Initalization here
- pass
-
-
+# Member variables
+var disabled = false
diff --git a/demos/3d/platformer/bullet.scn b/demos/3d/platformer/bullet.scn
index da90dba1a5..54ceb50488 100644
--- a/demos/3d/platformer/bullet.scn
+++ b/demos/3d/platformer/bullet.scn
Binary files differ
diff --git a/demos/3d/platformer/coin.gd b/demos/3d/platformer/coin.gd
index 8bf1a3460d..bd2eea81e2 100644
--- a/demos/3d/platformer/coin.gd
+++ b/demos/3d/platformer/coin.gd
@@ -1,23 +1,11 @@
extends Area
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
-
+# Member variables
var taken = false
-func _on_coin_body_enter( body ):
+func _on_coin_body_enter(body):
if (not taken and body extends preload("res://player.gd")):
get_node("anim").play("take")
- taken=true
-
-
-func _ready():
- # Initalization here
- pass
-
-
-
+ taken = true
diff --git a/demos/3d/platformer/coin.scn b/demos/3d/platformer/coin.scn
index a4148b4060..238150788b 100644
--- a/demos/3d/platformer/coin.scn
+++ b/demos/3d/platformer/coin.scn
Binary files differ
diff --git a/demos/3d/platformer/enemy.gd b/demos/3d/platformer/enemy.gd
index cbbb2fe725..55c79e4858 100644
--- a/demos/3d/platformer/enemy.gd
+++ b/demos/3d/platformer/enemy.gd
@@ -1,14 +1,10 @@
extends RigidBody
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
+# Member variables
const STATE_WALKING = 0
const STATE_DYING = 1
-
var prev_advance = false
var deaccel = 20.0
var accel = 5
@@ -16,79 +12,67 @@ var max_speed = 2
var rot_dir = 4
var rot_speed = 1
-var dying=false
-
-func _integrate_forces(state):
+var dying = false
-
+func _integrate_forces(state):
var delta = state.get_step()
var lv = state.get_linear_velocity()
var g = state.get_total_gravity()
- lv += g * delta #apply gravity
+ lv += g*delta # Apply gravity
var up = -g.normalized()
-
+
if (dying):
state.set_linear_velocity(lv)
return
-
+
for i in range(state.get_contact_count()):
var cc = state.get_contact_collider_object(i)
var dp = state.get_contact_local_normal(i)
-
+
if (cc):
if (cc extends preload("res://bullet.gd") and not cc.disabled):
set_mode(MODE_RIGID)
- dying=true
- #lv=s.get_contact_local_normal(i)*400
- state.set_angular_velocity( -dp.cross(up).normalized() *33.0)
+ dying = true
+ #lv = s.get_contact_local_normal(i)*400
+ state.set_angular_velocity(-dp.cross(up).normalized()*33.0)
get_node("AnimationPlayer").play("impact")
get_node("AnimationPlayer").queue("explode")
set_friction(1)
- cc.disabled=true
+ cc.disabled = true
get_node("sound").play("hit")
return
-
-
-
-
var col_floor = get_node("Armature/ray_floor").is_colliding()
var col_wall = get_node("Armature/ray_wall").is_colliding()
var advance = not col_wall and col_floor
var dir = get_node("Armature").get_transform().basis[2].normalized()
-
-
var deaccel_dir = dir
if (advance):
if (dir.dot(lv) < max_speed):
- lv+=dir * accel * delta
+ lv += dir*accel*delta
deaccel_dir = dir.cross(g).normalized()
else:
if (prev_advance):
- rot_dir = 1 #randf() * 2.0 -1.0
-
- dir = Matrix3(up,rot_dir * rot_speed * delta).xform(dir)
- get_node("Armature").set_transform( Transform().looking_at(-dir,up) )
-
+ rot_dir = 1 # randf()*2.0 - 1.0
+ dir = Matrix3(up, rot_dir*rot_speed*delta).xform(dir)
+ get_node("Armature").set_transform(Transform().looking_at(-dir, up))
+
var dspeed = deaccel_dir.dot(lv)
- dspeed -= deaccel * delta
- if (dspeed<0):
- dspeed=0
+ dspeed -= deaccel*delta
+ if (dspeed < 0):
+ dspeed = 0
lv = lv - deaccel_dir*deaccel_dir.dot(lv) + deaccel_dir*dspeed
-
state.set_linear_velocity(lv)
- prev_advance=advance
-
-func _ready():
- # Initalization here
- pass
+ prev_advance = advance
+func _die():
+ queue_free()
diff --git a/demos/3d/platformer/enemy.scn b/demos/3d/platformer/enemy.scn
index 06d725061d..dd62692b7f 100644
--- a/demos/3d/platformer/enemy.scn
+++ b/demos/3d/platformer/enemy.scn
Binary files differ
diff --git a/demos/3d/platformer/engine.cfg b/demos/3d/platformer/engine.cfg
index 793ac36364..84a7e8f597 100644
--- a/demos/3d/platformer/engine.cfg
+++ b/demos/3d/platformer/engine.cfg
@@ -1,12 +1,12 @@
[application]
name="Platformer 3D"
-main_scene="res://stage.xml"
+main_scene="res://stage.scn"
icon="res://icon.png"
[display]
-height=450
+height=720
stretch_2d=true
[input]
diff --git a/demos/3d/platformer/follow_camera.gd b/demos/3d/platformer/follow_camera.gd
index 3d18327df0..d0d531b9a5 100644
--- a/demos/3d/platformer/follow_camera.gd
+++ b/demos/3d/platformer/follow_camera.gd
@@ -1,95 +1,80 @@
extends Camera
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
-var collision_exception=[]
-export var min_distance=0.5
-export var max_distance=4.0
-export var angle_v_adjust=0.0
-export var autoturn_ray_aperture=25
-export var autoturn_speed=50
+# Member variables
+var collision_exception = []
+export var min_distance = 0.5
+export var max_distance = 4.0
+export var angle_v_adjust = 0.0
+export var autoturn_ray_aperture = 25
+export var autoturn_speed = 50
var max_height = 2.0
var min_height = 0
func _fixed_process(dt):
- var target = get_parent().get_global_transform().origin
+ var target = get_parent().get_global_transform().origin
var pos = get_global_transform().origin
- var up = Vector3(0,1,0)
+ var up = Vector3(0, 1, 0)
var delta = pos - target
- #regular delta follow
-
- #check ranges
+ # Regular delta follow
+ # Check ranges
if (delta.length() < min_distance):
- delta = delta.normalized() * min_distance
+ delta = delta.normalized()*min_distance
elif (delta.length() > max_distance):
- delta = delta.normalized() * max_distance
+ delta = delta.normalized()*max_distance
- #check upper and lower height
- if ( delta.y > max_height):
+ # Check upper and lower height
+ if (delta.y > max_height):
delta.y = max_height
- if ( delta.y < min_height):
+ if (delta.y < min_height):
delta.y = min_height
- #check autoturn
-
- var ds = PhysicsServer.space_get_direct_state( get_world().get_space() )
-
+ # Check autoturn
+ var ds = PhysicsServer.space_get_direct_state(get_world().get_space())
- var col_left = ds.intersect_ray(target,target+Matrix3(up,deg2rad(autoturn_ray_aperture)).xform(delta),collision_exception)
- var col = ds.intersect_ray(target,target+delta,collision_exception)
- var col_right = ds.intersect_ray(target,target+Matrix3(up,deg2rad(-autoturn_ray_aperture)).xform(delta),collision_exception)
+ var col_left = ds.intersect_ray(target, target + Matrix3(up, deg2rad(autoturn_ray_aperture)).xform(delta), collision_exception)
+ var col = ds.intersect_ray(target, target + delta, collision_exception)
+ var col_right = ds.intersect_ray(target, target + Matrix3(up, deg2rad(-autoturn_ray_aperture)).xform(delta), collision_exception)
if (!col.empty()):
- #if main ray was occluded, get camera closer, this is the worst case scenario
+ # If main ray was occluded, get camera closer, this is the worst case scenario
delta = col.position - target
elif (!col_left.empty() and col_right.empty()):
- #if only left ray is occluded, turn the camera around to the right
- delta = Matrix3(up,deg2rad(-dt*autoturn_speed)).xform(delta)
+ # If only left ray is occluded, turn the camera around to the right
+ delta = Matrix3(up, deg2rad(-dt*autoturn_speed)).xform(delta)
elif (col_left.empty() and !col_right.empty()):
- #if only right ray is occluded, turn the camera around to the left
- delta = Matrix3(up,deg2rad(dt*autoturn_speed)).xform(delta)
+ # If only right ray is occluded, turn the camera around to the left
+ delta = Matrix3(up, deg2rad(dt*autoturn_speed)).xform(delta)
else:
- #do nothing otherwise, left and right are occluded but center is not, so do not autoturn
+ # Do nothing otherwise, left and right are occluded but center is not, so do not autoturn
pass
- #apply lookat
- if (delta==Vector3()):
- delta = (pos - target).normalized() * 0.0001
+ # Apply lookat
+ if (delta == Vector3()):
+ delta = (pos - target).normalized()*0.0001
pos = target + delta
- look_at_from_pos(pos,target,up)
+ look_at_from_pos(pos, target, up)
- #turn a little up or down
+ # Turn a little up or down
var t = get_transform()
- t.basis = Matrix3(t.basis[0],deg2rad(angle_v_adjust)) * t.basis
+ t.basis = Matrix3(t.basis[0], deg2rad(angle_v_adjust))*t.basis
set_transform(t)
-
-
-func _ready():
-#find collision exceptions for ray
+func _ready():
+ # Find collision exceptions for ray
var node = self
while(node):
if (node extends RigidBody):
collision_exception.append(node.get_rid())
break
else:
- node=node.get_parent()
- # Initalization here
+ node = node.get_parent()
set_fixed_process(true)
- #this detaches the camera transform from the parent spatial node
+ # This detaches the camera transform from the parent spatial node
set_as_toplevel(true)
-
-
-
-
-
-
diff --git a/demos/3d/platformer/player.gd b/demos/3d/platformer/player.gd
index 4eeb12e23b..7471460538 100644
--- a/demos/3d/platformer/player.gd
+++ b/demos/3d/platformer/player.gd
@@ -1,12 +1,7 @@
extends RigidBody
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
-#var dir=Vector3()
-
+# Member variables
const ANIM_FLOOR = 0
const ANIM_AIR_UP = 1
const ANIM_AIR_DOWN = 2
@@ -14,21 +9,21 @@ const ANIM_AIR_DOWN = 2
const SHOOT_TIME = 1.5
const SHOOT_SCALE = 2
-const CHAR_SCALE = Vector3(0.3,0.3,0.3)
+const CHAR_SCALE = Vector3(0.3, 0.3, 0.3)
var facing_dir = Vector3(1, 0, 0)
var movement_dir = Vector3()
-var jumping=false
+var jumping = false
-var turn_speed=40
+var turn_speed = 40
var keep_jump_inertia = true
var air_idle_deaccel = false
-var accel=19.0
-var deaccel=14.0
-var sharp_turn_threshhold = 140
+var accel = 19.0
+var deaccel = 14.0
+var sharp_turn_threshold = 140
-var max_speed=3.1
+var max_speed = 3.1
var on_floor = false
var prev_shoot = false
@@ -37,9 +32,9 @@ var last_floor_velocity = Vector3()
var shoot_blend = 0
-func adjust_facing(p_facing, p_target,p_step, p_adjust_rate,current_gn):
- var n = p_target # normal
+func adjust_facing(p_facing, p_target, p_step, p_adjust_rate, current_gn):
+ var n = p_target # Normal
var t = n.cross(current_gn).normalized()
var x = n.dot(p_facing)
@@ -47,47 +42,43 @@ func adjust_facing(p_facing, p_target,p_step, p_adjust_rate,current_gn):
var ang = atan2(y,x)
- if (abs(ang)<0.001): # too small
+ if (abs(ang) < 0.001): # Too small
return p_facing
var s = sign(ang)
- ang = ang * s
- var turn = ang * p_adjust_rate * p_step
+ ang = ang*s
+ var turn = ang*p_adjust_rate*p_step
var a
- if (ang<turn):
- a=ang
+ if (ang < turn):
+ a = ang
else:
- a=turn
- ang = (ang - a) * s
+ a = turn
+ ang = (ang - a)*s
- return ((n * cos(ang)) + (t * sin(ang))) * p_facing.length()
-
-
+ return (n*cos(ang) + t*sin(ang))*p_facing.length()
-func _integrate_forces( state ):
- var lv = state.get_linear_velocity() # linear velocity
+func _integrate_forces(state):
+ var lv = state.get_linear_velocity() # Linear velocity
var g = state.get_total_gravity()
var delta = state.get_step()
- var d = 1.0 - delta*state.get_total_density()
- if (d<0):
- d=0
- lv += g * delta #apply gravity
-
+# var d = 1.0 - delta*state.get_total_density()
+# if (d < 0):
+# d = 0
+ lv += g*delta # Apply gravity
+
var anim = ANIM_FLOOR
-
+
var up = -g.normalized() # (up is against gravity)
- var vv = up.dot(lv) # vertical velocity
- var hv = lv - (up*vv) # horizontal velocity
-
-
-
- var hdir = hv.normalized() # horizontal direction
- var hspeed = hv.length() #horizontal speed
-
+ var vv = up.dot(lv) # Vertical velocity
+ var hv = lv - up*vv # Horizontal velocity
+
+ var hdir = hv.normalized() # Horizontal direction
+ var hspeed = hv.length() # Horizontal speed
+
var floor_velocity
var onfloor = false
-
+
if (state.get_contact_count() == 0):
floor_velocity = last_floor_velocity
else:
@@ -98,104 +89,89 @@ func _integrate_forces( state ):
onfloor = true
floor_velocity = state.get_contact_collider_velocity_at_pos(i)
break
-
-
- var dir = Vector3() #where does the player intend to walk to
+
+ var dir = Vector3() # Where does the player intend to walk to
var cam_xform = get_node("target/camera").get_global_transform()
if (Input.is_action_pressed("move_forward")):
- dir+=-cam_xform.basis[2]
+ dir += -cam_xform.basis[2]
if (Input.is_action_pressed("move_backwards")):
- dir+=cam_xform.basis[2]
+ dir += cam_xform.basis[2]
if (Input.is_action_pressed("move_left")):
- dir+=-cam_xform.basis[0]
+ dir += -cam_xform.basis[0]
if (Input.is_action_pressed("move_right")):
- dir+=cam_xform.basis[0]
-
+ dir += cam_xform.basis[0]
+
var jump_attempt = Input.is_action_pressed("jump")
var shoot_attempt = Input.is_action_pressed("shoot")
-
+
var target_dir = (dir - up*dir.dot(up)).normalized()
if (onfloor):
-
- var sharp_turn = hspeed > 0.1 and rad2deg(acos(target_dir.dot(hdir))) > sharp_turn_threshhold
-
- if (dir.length()>0.1 and !sharp_turn) :
- if (hspeed > 0.001) :
-
+ var sharp_turn = hspeed > 0.1 and rad2deg(acos(target_dir.dot(hdir))) > sharp_turn_threshold
+
+ if (dir.length() > 0.1 and !sharp_turn):
+ if (hspeed > 0.001):
#linear_dir = linear_h_velocity/linear_vel
- #if (linear_vel > brake_velocity_limit and linear_dir.dot(ctarget_dir)<-cos(Math::deg2rad(brake_angular_limit)))
- # brake=true
+ #if (linear_vel > brake_velocity_limit and linear_dir.dot(ctarget_dir) < -cos(Math::deg2rad(brake_angular_limit)))
+ # brake = true
#else
- hdir = adjust_facing(hdir,target_dir,delta,1.0/hspeed*turn_speed,up)
+ hdir = adjust_facing(hdir, target_dir, delta, 1.0/hspeed*turn_speed, up)
facing_dir = hdir
else:
-
hdir = target_dir
- if (hspeed<max_speed):
- hspeed+=accel*delta
-
+ if (hspeed < max_speed):
+ hspeed += accel*delta
else:
- hspeed-=deaccel*delta
- if (hspeed<0):
- hspeed=0
+ hspeed -= deaccel*delta
+ if (hspeed < 0):
+ hspeed = 0
hv = hdir*hspeed
- var mesh_xform = get_node("Armature").get_transform()
- var facing_mesh=-mesh_xform.basis[0].normalized()
+ var mesh_xform = get_node("Armature").get_transform()
+ var facing_mesh = -mesh_xform.basis[0].normalized()
facing_mesh = (facing_mesh - up*facing_mesh.dot(up)).normalized()
- facing_mesh = adjust_facing(facing_mesh,target_dir,delta,1.0/hspeed*turn_speed,up)
- var m3 = Matrix3(-facing_mesh,up,-facing_mesh.cross(up).normalized()).scaled( CHAR_SCALE )
+ facing_mesh = adjust_facing(facing_mesh, target_dir, delta, 1.0/hspeed*turn_speed, up)
+ var m3 = Matrix3(-facing_mesh, up, -facing_mesh.cross(up).normalized()).scaled(CHAR_SCALE)
+
+ get_node("Armature").set_transform(Transform(m3, mesh_xform.origin))
- get_node("Armature").set_transform(Transform(m3,mesh_xform.origin))
-
if (not jumping and jump_attempt):
vv = 7.0
- jumping = true
+ jumping = true
get_node("sfx").play("jump")
else:
-
- if (vv>0):
- anim=ANIM_AIR_UP
+ if (vv > 0):
+ anim = ANIM_AIR_UP
else:
- anim=ANIM_AIR_DOWN
-
+ anim = ANIM_AIR_DOWN
+
var hs
- if (dir.length()>0.1):
-
- hv += target_dir * (accel * 0.2) * delta
+ if (dir.length() > 0.1):
+ hv += target_dir*(accel*0.2)*delta
if (hv.length() > max_speed):
- hv = hv.normalized() * max_speed
-
+ hv = hv.normalized()*max_speed
else:
-
if (air_idle_deaccel):
- hspeed = hspeed - (deaccel * 0.2) * delta
- if (hspeed<0):
- hspeed=0
-
+ hspeed = hspeed - (deaccel*0.2)*delta
+ if (hspeed < 0):
+ hspeed = 0
+
hv = hdir*hspeed
-
-
+
if (jumping and vv < 0):
- jumping=false
-
- lv = hv+up*vv
+ jumping = false
+ lv = hv + up*vv
-
if (onfloor):
-
movement_dir = lv
#lv += floor_velocity
last_floor_velocity = floor_velocity
else:
-
- if (on_floor) :
-
+ if (on_floor):
#if (keep_jump_inertia):
# lv += last_floor_velocity
pass
@@ -204,40 +180,32 @@ func _integrate_forces( state ):
movement_dir = lv
on_floor = onfloor
-
+
state.set_linear_velocity(lv)
- if (shoot_blend>0):
- shoot_blend -= delta * SHOOT_SCALE
- if (shoot_blend<0):
- shoot_blend=0
+ if (shoot_blend > 0):
+ shoot_blend -= delta*SHOOT_SCALE
+ if (shoot_blend < 0):
+ shoot_blend = 0
if (shoot_attempt and not prev_shoot):
- shoot_blend = SHOOT_TIME
+ shoot_blend = SHOOT_TIME
var bullet = preload("res://bullet.scn").instance()
- bullet.set_transform( get_node("Armature/bullet").get_global_transform().orthonormalized() )
- get_parent().add_child( bullet )
- bullet.set_linear_velocity( get_node("Armature/bullet").get_global_transform().basis[2].normalized() * 20 )
- PS.body_add_collision_exception( bullet.get_rid(), get_rid() ) #add it to bullet
+ bullet.set_transform(get_node("Armature/bullet").get_global_transform().orthonormalized())
+ get_parent().add_child(bullet)
+ bullet.set_linear_velocity(get_node("Armature/bullet").get_global_transform().basis[2].normalized()*20)
+ PS.body_add_collision_exception(bullet.get_rid(), get_rid()) # Add it to bullet
get_node("sfx").play("shoot")
-
+
prev_shoot = shoot_attempt
if (onfloor):
- get_node("AnimationTreePlayer").blend2_node_set_amount("walk",hspeed / max_speed)
-
- get_node("AnimationTreePlayer").transition_node_set_current("state",anim)
- get_node("AnimationTreePlayer").blend2_node_set_amount("gun",min(shoot_blend,1.0))
-# state.set_angular_velocity(Vector3())
-
+ get_node("AnimationTreePlayer").blend2_node_set_amount("walk", hspeed/max_speed)
+ get_node("AnimationTreePlayer").transition_node_set_current("state", anim)
+ get_node("AnimationTreePlayer").blend2_node_set_amount("gun", min(shoot_blend, 1.0))
+# state.set_angular_velocity(Vector3())
func _ready():
-
-
- # Initalization here
get_node("AnimationTreePlayer").set_active(true)
- pass
-
-
diff --git a/demos/3d/platformer/player.scn b/demos/3d/platformer/player.scn
new file mode 100644
index 0000000000..3b24da94ec
--- /dev/null
+++ b/demos/3d/platformer/player.scn
Binary files differ
diff --git a/demos/3d/platformer/player.xml b/demos/3d/platformer/player.xml
deleted file mode 100644
index c008d21675..0000000000
--- a/demos/3d/platformer/player.xml
+++ /dev/null
@@ -1,1762 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="23" version="1.0" version_name="Godot Engine v1.0.3917-beta1">
- <ext_resource path="res://osb_left.png" type="Texture"></ext_resource>
- <ext_resource path="res://osb_up.png" type="Texture"></ext_resource>
- <ext_resource path="res://player.gd" type="Script"></ext_resource>
- <ext_resource path="res://sound_jump.wav" type="Sample"></ext_resource>
- <ext_resource path="res://follow_camera.gd" type="Script"></ext_resource>
- <ext_resource path="res://osb_down.png" type="Texture"></ext_resource>
- <ext_resource path="res://osb_right.png" type="Texture"></ext_resource>
- <ext_resource path="res://sound_shoot.wav" type="Sample"></ext_resource>
- <resource type="CapsuleShape" path="local://1">
- <real name="radius"> 0.4 </real>
- <real name="height"> 0.4 </real>
-
- </resource>
- <resource type="RayShape" path="local://2">
- <real name="length"> 1 </real>
-
- </resource>
- <resource type="FixedMaterial" path="local://3">
- <bool name="flags/visible"> True </bool>
- <bool name="flags/double_sided"> True </bool>
- <bool name="flags/invert_faces"> False </bool>
- <bool name="flags/unshaded"> False </bool>
- <bool name="flags/on_top"> False </bool>
- <bool name="flags/wireframe"> False </bool>
- <bool name="flags/billboard_sw"> False </bool>
- <bool name="hints/decal"> False </bool>
- <bool name="hints/opaque_pre_zpass"> False </bool>
- <bool name="hints/no_shadow"> False </bool>
- <bool name="hints/no_depth_draw"> False </bool>
- <int name="params/blend_mode"> 0 </int>
- <real name="params/line_width"> 0 </real>
- <bool name="fixed_flags/use_alpha"> False </bool>
- <bool name="fixed_flags/use_color_array"> False </bool>
- <bool name="fixed_flags/use_point_size"> False </bool>
- <color name="params/diffuse"> 0.702475, 0.707942, 0.727015, 1 </color>
- <color name="params/specular"> 0.351321, 0.35466, 0.377071, 1 </color>
- <color name="params/emission"> 0, 0, 0, 1 </color>
- <real name="params/specular_exp"> 34.20256 </real>
- <int name="params/detail_blend"> 0 </int>
- <real name="params/detail_mix"> 1 </real>
- <int name="params/normal_depth"> 1 </int>
- <real name="params/shade_param"> 0.5 </real>
- <int name="params/glow"> 0 </int>
- <real name="params/point_size"> 1 </real>
- <transform name="uv_xform"> 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 </transform>
- <resource name="textures/diffuse"></resource> <int name="textures/diffuse_tc"> 0 </int>
- <resource name="textures/detail"></resource> <int name="textures/detail_tc"> 0 </int>
- <resource name="textures/specular"></resource> <int name="textures/specular_tc"> 0 </int>
- <resource name="textures/emission"></resource> <int name="textures/emission_tc"> 0 </int>
- <resource name="textures/specular_exp"></resource> <int name="textures/specular_exp_tc"> 0 </int>
- <resource name="textures/glow"></resource> <int name="textures/glow_tc"> 0 </int>
- <resource name="textures/normal"></resource> <int name="textures/normal_tc"> 0 </int>
- <resource name="textures/shade_param"></resource> <int name="textures/shade_param_tc"> 0 </int>
-
- </resource>
- <resource type="FixedMaterial" path="local://4">
- <bool name="flags/visible"> True </bool>
- <bool name="flags/double_sided"> True </bool>
- <bool name="flags/invert_faces"> False </bool>
- <bool name="flags/unshaded"> False </bool>
- <bool name="flags/on_top"> False </bool>
- <bool name="flags/wireframe"> False </bool>
- <bool name="flags/billboard_sw"> False </bool>
- <bool name="hints/decal"> False </bool>
- <bool name="hints/opaque_pre_zpass"> False </bool>
- <bool name="hints/no_shadow"> False </bool>
- <bool name="hints/no_depth_draw"> False </bool>
- <int name="params/blend_mode"> 0 </int>
- <real name="params/line_width"> 0 </real>
- <bool name="fixed_flags/use_alpha"> False </bool>
- <bool name="fixed_flags/use_color_array"> False </bool>
- <bool name="fixed_flags/use_point_size"> False </bool>
- <color name="params/diffuse"> 0.0616188, 0.431354, 0.64, 1 </color>
- <color name="params/specular"> 0.5, 0.5, 0.5, 1 </color>
- <color name="params/emission"> 0.0196078, 0.235675, 0.675973, 1 </color>
- <real name="params/specular_exp"> 50 </real>
- <int name="params/detail_blend"> 0 </int>
- <real name="params/detail_mix"> 1 </real>
- <int name="params/normal_depth"> 1 </int>
- <real name="params/shade_param"> 0.5 </real>
- <real name="params/glow"> 0.4 </real>
- <real name="params/point_size"> 1 </real>
- <transform name="uv_xform"> 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 </transform>
- <resource name="textures/diffuse"></resource> <int name="textures/diffuse_tc"> 0 </int>
- <resource name="textures/detail"></resource> <int name="textures/detail_tc"> 0 </int>
- <resource name="textures/specular"></resource> <int name="textures/specular_tc"> 0 </int>
- <resource name="textures/emission"></resource> <int name="textures/emission_tc"> 0 </int>
- <resource name="textures/specular_exp"></resource> <int name="textures/specular_exp_tc"> 0 </int>
- <resource name="textures/glow"></resource> <int name="textures/glow_tc"> 0 </int>
- <resource name="textures/normal"></resource> <int name="textures/normal_tc"> 0 </int>
- <resource name="textures/shade_param"></resource> <int name="textures/shade_param_tc"> 0 </int>
-
- </resource>
- <resource type="Mesh" path="local://5">
- <string name="resource/name"> "Cube.002" </string>
- <dictionary name="surfaces/0" shared="false">
- <string> "alphasort" </string>
- <bool> False </bool>
- <string> "material" </string>
- <resource resource_type="Material" path="local://3"> </resource>
- <string> "morph_arrays" </string>
- <array len="0" shared="false">
- </array>
- <string> "primitive" </string>
- <int> 4 </int>
- <string> "arrays" </string>
- <array len="9" shared="false">
- <vector3_array len="679"> 0.2607, 6.45948, 0.980779, 0.852531, 6.83043, 0.609826, 0.852531, 6.93043, 0.609826, 0.2607, 6.55948, 0.980779, 0, 7.06621, 0.103096, 0.955654, 7.06621, 0.103096, 0.852531, 6.93043, -0.403642, 0, 6.93043, -0.403642, 0, 6.45948, -0.774594, 0, 6.55948, -0.774594, 0.2607, 6.55948, -0.774594, 0.2607, 6.45948, -0.774594, 0, 6.45948, 0.980779, 0, 6.55948, 0.980779, 0.852531, 6.83043, -0.403642, 0.955654, 6.96621, 0.103096, 0, 6.93043, 0.609826, 1.70474, 3.5573, -0.353999, 1.71449, 3.62366, -0.198996, 1.77916, 3.62988, -0.16353, 1.76754, 3.55083, -0.34818, 1.71511, 3.58298, -0.0127468, 1.70308, 3.74367, 0.0692484, 1.80667, 3.81951, -0.174607, 1.52592, 3.24162, -0.0839551, 1.50573, 3.18374, -0.268539, 1.36446, 3.09798, -0.344433, 1.38154, 3.17921, -0.0161709, 2.44682, 3.07552, 0.376618, 2.28993, 2.80163, 0.457827, 2.52299, 2.59433, 0.553631, 2.69474, 2.85281, 0.479075, 2.53359, 3.02984, -0.15501, 2.55604, 3.1449, 0.136694, 2.79433, 2.92572, 0.24463, 2.78064, 2.80757, -0.0472709, 2.39441, 2.7167, -0.284614, 2.64285, 2.49755, -0.175588, 2.70938, 2.79639, 0.46437, 2.79808, 2.86134, 0.255559, 2.78589, 2.75611, -0.00442547, 2.66316, 2.47998, -0.118712, 2.38561, 2.31013, 0.396952, 2.36919, 2.23204, 0.0813577, 2.41942, 2.2435, 0.110139, 2.43405, 2.31306, 0.391226, 2.55641, 2.56618, 0.530774, 2.47334, 2.30784, -0.0772789, 2.51219, 2.31101, -0.0311523, 2.38859, 2.74151, 0.0599679, 2.38864, 2.7416, 0.0600288, 2.12663, 2.44425, -0.0282163, 2.22321, 2.52508, -0.185319, 2.13459, 2.5274, 0.293671, 0.173831, 0.925795, -0.251959, 0.323615, 0.972996, -0.416293, 0.50934, 0.00104547, -0.453384, 0.175987, 0.00104547, -0.331706, 0.916812, 0.888823, 0.214332, 0.549239, 0.836962, 0.37006, 0.552121, 0.665123, 0.401021, 0.944465, 0.443271, 0.182901, 0.631626, 1.83578, -0.105239, 0.721202, 1.70631, 0.188726, 0.913722, 0.95431, -0.169976, 0.478232, 1.53675, 0.317272, 0.454208, 1.69171, -0.268756, 0.63543, 0.987243, -0.370343, 0.262225, 1.39447, 0.162709, 0.170564, 0.859014, 0.160279, 0.255551, 1.52426, -0.294896, 0.126803, 1.32882, -0.0395796, 0.0660405, 0.880691, -0.102965, 0.19102, 1.40531, -0.162224, 0.256767, 1.56023, -0.0958005, 0.300707, 1.62315, -0.168503, 0.292542, 1.58081, -0.213789, 0.245079, 1.4957, -0.123593, 0.426543, 1.69115, -0.196413, 0.547313, 1.79071, -0.0844079, 0.586182, 1.83924, -0.0975873, 0.434509, 1.71208, -0.231916, 0.212253, 1.44274, -0.0415312, 0.220281, 1.46968, -0.143048, 0.175617, 1.41154, -0.0437374, 0.543306, 0.573346, 0.523815, 0.207486, 0.384965, 0.351051, 0.269976, 0.320526, 0.743389, 0.53325, 0.468211, 0.783185, 0.792721, 0.321493, 0.73458, 0.514523, 0.271138, 0.956088, 0.631719, 0.163855, 0.92639, 0.386424, 0.163401, 0.930524, 0.486595, 0.00104547, 1.08874, 0.326299, 0.00104547, 0.904533, 0.668445, 1.73174, 0.152757, 0.462058, 1.58268, 0.259184, 0.290415, 1.46398, 0.121989, 1.57608, 3.45117, -0.0476083, 1.50191, 3.29774, -0.132197, 1.61428, 3.4244, 0.016813, 1.66072, 3.58429, -0.072422, 1.62434, 3.38222, -0.419987, 1.67177, 3.34226, -0.426789, 1.48496, 3.24915, -0.287145, 1.54119, 3.29007, -0.372791, 1.57272, 3.23249, -0.370566, 1.79243, 3.69662, -0.478226, 1.47279, 3.17682, -0.509438, 1.6491, 3.37415, -0.611694, 1.52444, 3.47482, 0.146797, 1.97806, 2.60303, -0.0912834, 1.98619, 2.68696, 0.233771, 2.07568, 2.68462, -0.249978, 2.24859, 2.87814, -0.35026, 2.14291, 2.96404, 0.3995, 2.30152, 3.24052, 0.317542, 2.38915, 3.19439, -0.219368, 2.41174, 3.31063, 0.0752657, 0.0964089, 0.00104547, -0.196812, 0.154027, 0.441809, 0.19622, 0.835003, 0.00104547, -0.205403, 0.55748, 1.72198, 0.0964474, 0.425773, 1.62639, 0.166544, 0.447702, 1.58483, 0.201877, 0.611101, 1.70343, 0.114914, 0.506064, 1.79234, -0.0642154, 0.311982, 1.54621, 0.0812291, 0.30653, 1.48536, 0.0960338, 0.408718, 1.71209, -0.154497, 0.23599, 1.51185, -0.0296548, 0.272186, 1.57784, -0.251696, 0.0508581, 0.00104547, 0.0402964, 0.14499, 0.00104547, 0.619324, 0.916171, 0.00104547, 0.0302318, 0.874277, 0.386199, 0.339815, 0.82337, 0.00104547, 0.611434, 0.644625, 0.00104547, 0.90083, 0.19633, 0.00104547, -0.176104, 0.736495, 0.00104547, -0.182387, 0.85902, 0.00104547, 0.0313234, 0.108829, 0.00104547, 0.040049, 1.86783, 5.49219, -0.536097, 1.99626, 5.62831, -0.300326, 1.99626, 5.45781, -0.129823, 1.86783, 5.22204, -0.265945, 1.86783, 6.50041, -0.265945, 1.99626, 6.26464, -0.129823, 1.99626, 6.09414, -0.300326, 1.86783, 6.23026, -0.536097, 1.99626, 5.86123, -0.362734, 1.86783, 5.86123, -0.63498, 1.7, 6.62333, -0.336911, 1.7, 6.30123, -0.659013, 1.7, 5.42123, -0.659013, 1.7, 5.09912, -0.336911, 1.7, 5.86123, -0.776911, 1.6, 6.62333, 0.543096, 1.6, 6.30123, 0.865198, 1.7, 6.30123, 0.865198, 1.7, 6.62333, 0.543096, 1.6, 5.86123, 0.983096, 1.7, 5.86123, 0.983096, 1.6, 5.42123, 0.865198, 1.7, 5.42123, 0.865198, 1.6, 5.42123, -0.659013, 1.6, 5.09912, -0.336911, 1.6, 5.09913, 0.543096, 1.7, 5.09913, 0.543096, 1.6, 5.86123, -0.776911, 1.6, 4.98123, 0.103096, 1.7, 4.98123, 0.103096, 1.6, 6.30123, -0.659013, 1.6, 6.62333, -0.336911, 1.6, 6.74123, 0.103096, 1.7, 6.74123, 0.103096, 1.86783, 5.86123, 0.841165, 1.86783, 6.23026, 0.742282, 1.86783, 5.49219, 0.742282, 1.86783, 5.22204, 0.47213, 1.86783, 5.12316, 0.103096, 1.86783, 6.50041, 0.47213, 1.86783, 6.5993, 0.103096, 1.99626, 5.3954, 0.103096, 1.99626, 5.45781, 0.336007, 1.99626, 5.62832, 0.50651, 1.99626, 5.86123, 0.568919, 1.99626, 6.09414, 0.50651, 1.99626, 6.26464, 0.336007, 1.99626, 6.32705, 0.103096, 0.102832, 2.48009, 0.176006, 5.00021e-06, 2.4738, 0.177211, 5.00021e-06, 2.42055, 0.19141, 0.0988953, 2.42787, 0.190009, 0.149215, 2.70638, -0.125392, 0.228589, 2.63923, -0.0490058, 0.245228, 2.61305, -0.0718189, 0.152867, 2.69118, -0.160703, 5.00021e-06, 2.7271, -0.192857, 0.200279, 2.72863, -0.178996, 5.00021e-06, 2.77269, -0.218433, 0.254515, 2.5228, 0.0532499, 0.177509, 2.46933, 0.131427, 0.230502, 2.45653, 0.179303, 0.32495, 2.52211, 0.0834183, 0.31356, 2.6328, -0.0699792, 5.00021e-06, 2.38434, 0.263172, 0.134082, 2.39331, 0.261453, 4.89224e-06, 2.18251, 0.500372, 0.225093, 2.1995, 0.49518, 0.391925, 2.2292, 0.34273, 0.272307, 2.12215, 0.166987, 0.273286, 2.15284, 0.145033, 0.377566, 2.23301, 0.230347, 0.509219, 2.60277, -0.0602789, 0.306467, 2.75371, -0.22827, 0.384471, 2.30721, 0.355435, 5.53206e-06, 2.7678, -0.324424, 0.340915, 2.69228, -0.257391, 0.141881, 2.21642, -0.246023, 5.00021e-06, 2.24749, -0.273838, 0.226149, 2.1204, 0.482878, 5.00021e-06, 2.10499, 0.484715, 5.00021e-06, 1.97359, 0.0658354, 0.0951926, 1.97992, 0.0646229, 0.536694, 2.41886, 0.193185, 0.163197, 2.02451, 0.00668271, 5.00021e-06, 2.80311, -0.262553, 0.221777, 2.14883, -0.169134, 5.0058e-06, 2.08031, -0.179583, 4.99835e-06, 2.12243, -0.227502, 5.00021e-06, 1.97109, -0.0331461, 4.99835e-06, 1.97504, -0.0339018, 0.229811, 2.07077, -0.0609438, 5.0058e-06, 2.03165, -0.112157, 4.99835e-06, 2.00283, -0.0700111, 5.00021e-06, 2.14179, -0.244837, 0.549486, 2.33903, 0.185763, 0.532141, 2.52821, -0.0726373, 0.367385, 2.32682, -0.123862, 0.198102, 4.44663, -0.00271145, 0.535945, 4.16951, 0.521097, 0.681184, 4.27477, 0.307467, 0.0960235, 4.4178, 0.0939296, 0, 4.41627, 0.145479, 0, 4.10504, 0.75232, 0.295152, 4.11437, 0.707528, 0, 4.62654, -0.650476, 0.75197, 4.49872, -0.484507, 0.568386, 3.97815, -0.416848, 0, 4.0743, -0.542347, 0.453404, 3.62952, 1.15385, 0, 3.62251, 1.22471, 0, 3.3304, 0.897974, 0.354866, 3.3434, 0.864531, 0.713601, 4.46674, -0.124363, 1.03995, 4.04518, 0.442157, 1.12602, 4.3213, -0.0494407, 0, 4.73174, -0.547059, 0.464921, 4.64317, -0.424668, 0.716219, 4.58287, -0.480226, 0, 4.71901, -0.593658, 0.850048, 3.71295, 0.879328, 0.649196, 3.42772, 0.674737, 0.84841, 3.80937, 0.873472, 0.451539, 3.72707, 1.15037, 0.155937, 3.05577, 0.331006, 0.258719, 3.09481, 0.245674, 0.822291, 3.77674, 0.0641416, 0.359401, 3.14451, 0.132252, 0.226502, 3.30884, -0.183514, 0, 3.34718, -0.233548, 0, 3.04671, 0.334585, 1.1403, 4.19005, 0.0860849, 1.11025, 4.20631, -0.0820755, 0, 3.71833, 1.2227, 1.07207, 4.04817, 0.195228, 0.177538, 3.25078, -0.147598, 0, 3.28068, -0.186631, 0.249187, 2.13753, -0.031997, 0.20137, 2.11848, 0.0341487, 0.497933, 2.32861, 0.160251, 0.252884, 2.22978, -0.1047, 0.438171, 2.39896, -0.000411894, 0.941862, 3.86072, 0.194563, 0.997836, 4.10049, -0.213272, 0.87372, 3.89175, -0.186777, 0.347259, 3.23006, -0.0503454, 0.821813, 3.80214, -0.0657451, 0.908494, 3.91354, 0.153681, 1.01577, 4.06798, 0.154229, 1.07199, 4.18489, 0.0643051, 1.04723, 4.19828, -0.0742428, 2.0359, 6.20719, -0.0966551, 2.0359, 6.06097, -0.242878, 2.0359, 5.66148, -0.242878, 2.0359, 5.51526, -0.0966551, 2.0359, 5.86123, -0.296399, 2.0359, 5.86123, 0.502584, 2.0359, 6.06097, 0.449063, 2.0359, 5.66148, 0.449063, 2.0359, 5.51526, 0.30284, 2.0359, 5.46174, 0.103096, 2.0359, 6.20719, 0.30284, 2.0359, 6.26072, 0.103096, 0, 5.86123, 1.1031, 0, 5.47658, 1.00003, 0.329213, 5.47658, 1.00003, 0, 5.20179, 0.809688, 0, 4.9952, 0.603096, 0.329213, 5.20344, 0.811334, 1.15486, 6.36123, 0.969121, 1.2072, 6.11123, 1.03611, 1.39648, 6.36123, 0.969121, 0, 5.86123, -0.896911, 1.39648, 5.86123, -0.896911, 1.39648, 5.36123, -0.762936, 0, 5.36123, -0.762936, 1.39648, 4.9952, -0.396911, 0, 4.9952, -0.396911, 0.329213, 5.36123, 0.969121, 0.257147, 5.40641, 0.875976, 0.257146, 5.2834, 0.752961, 0, 5.49634, 0.900073, 0.257147, 5.49634, 0.900073, 0, 5.28211, 0.751677, 0.685695, 5.86123, 1.1031, 0.633352, 6.11123, 1.03611, 1.39648, 5.36123, 0.969121, 1.39648, 5.86123, 1.1031, 1.15486, 5.86123, 1.1031, 1.39648, 4.9952, 0.603096, 0.23657, 2.56168, 0.0584772, 0.170392, 2.51572, 0.125662, 5.00021e-06, 2.73725, -0.153025, 0.350345, 2.31871, -0.0906937, 0, 4.66231, -0.410127, 0.153299, 4.61636, -0.336561, 0.252264, 4.53307, -0.191655, 0.271744, 3.18932, -0.0437093, 0.122488, 3.05335, 0.253795, 0.202672, 3.0838, 0.187225, 0.281216, 3.12258, 0.0987407, 0, 3.04628, 0.256587, 0.954611, 4.1111, -0.182336, 0.85235, 3.93911, -0.160509, 0.809584, 3.86528, -0.0607897, 0.809978, 3.84435, 0.0462258, 0, 4.97587, -0.315884, 1.39648, 4.86123, 0.103096, 0.18642, 4.95573, -0.248219, 0.269727, 4.92174, -0.116503, 0.212301, 4.88556, 0.0356146, 0, 4.86123, 0.103096, 0.942888, 6.86123, 0.103096, 1.39648, 6.86123, 0.103096, 1.39648, 6.72725, -0.396911, 0.841135, 6.72725, -0.396911, 1.39648, 6.36123, -0.762936, 0.257165, 6.36123, -0.762936, 0.841135, 6.72725, 0.603096, 1.39648, 6.72725, 0.603096, 0, 6.36123, -0.762936, 0.257165, 6.36123, 0.969121, 0.685695, 6.36123, 0.969121, 0, 6.36123, 0.969121, -0.2607, 6.45948, 0.980779, -0.2607, 6.55948, 0.980779, -0.852531, 6.93043, 0.609826, -0.852531, 6.83043, 0.609826, -0.852531, 6.93043, -0.403642, -0.955654, 7.06621, 0.103096, -0.2607, 6.45948, -0.774594, -0.2607, 6.55948, -0.774594, -0.852531, 6.83043, -0.403642, -0.955654, 6.96621, 0.103096, -1.70474, 3.5573, -0.353999, -1.76754, 3.55083, -0.34818, -1.77916, 3.62988, -0.16353, -1.71449, 3.62366, -0.198996, -1.80667, 3.81951, -0.174607, -1.70308, 3.74367, 0.0692484, -1.71511, 3.58298, -0.0127468, -1.52592, 3.24162, -0.0839551, -1.38154, 3.17921, -0.0161709, -1.36446, 3.09798, -0.344433, -1.50573, 3.18374, -0.268539, -2.44682, 3.07552, 0.376618, -2.69474, 2.85281, 0.479075, -2.52299, 2.59433, 0.553631, -2.28993, 2.80163, 0.457827, -2.53359, 3.02984, -0.15501, -2.78064, 2.80757, -0.0472709, -2.79433, 2.92572, 0.24463, -2.55604, 3.1449, 0.136694, -2.39441, 2.7167, -0.284614, -2.64285, 2.49755, -0.175588, -2.79808, 2.86134, 0.255559, -2.70938, 2.79639, 0.46437, -2.66316, 2.47998, -0.118712, -2.78589, 2.75611, -0.00442547, -2.38561, 2.31013, 0.396952, -2.43405, 2.31306, 0.391226, -2.41942, 2.2435, 0.110139, -2.36919, 2.23204, 0.0813577, -2.55641, 2.56618, 0.530774, -2.51219, 2.31101, -0.0311523, -2.47334, 2.30784, -0.0772789, -2.38859, 2.74151, 0.0599679, -2.38864, 2.7416, 0.0600288, -2.12663, 2.44425, -0.0282163, -2.22321, 2.52508, -0.185319, -2.13459, 2.5274, 0.293671, -0.173831, 0.925795, -0.251959, -0.175987, 0.00104547, -0.331706, -0.50934, 0.00104547, -0.453384, -0.323615, 0.972996, -0.416293, -0.916812, 0.888823, 0.214332, -0.944465, 0.443271, 0.182901, -0.552121, 0.665123, 0.401021, -0.549239, 0.836962, 0.37006, -0.631626, 1.83578, -0.105239, -0.913722, 0.95431, -0.169976, -0.721202, 1.70631, 0.188726, -0.478232, 1.53675, 0.317272, -0.454208, 1.69171, -0.268756, -0.63543, 0.987243, -0.370343, -0.170564, 0.859014, 0.160279, -0.262225, 1.39447, 0.162709, -0.255551, 1.52426, -0.294896, -0.0660405, 0.880691, -0.102965, -0.126803, 1.32882, -0.0395796, -0.19102, 1.40531, -0.162224, -0.256767, 1.56023, -0.0958005, -0.245079, 1.4957, -0.123593, -0.292542, 1.58081, -0.213789, -0.300707, 1.62315, -0.168503, -0.426543, 1.69115, -0.196413, -0.434509, 1.71208, -0.231916, -0.586182, 1.83924, -0.0975873, -0.547313, 1.79071, -0.0844079, -0.212253, 1.44274, -0.0415312, -0.175617, 1.41154, -0.0437374, -0.220281, 1.46968, -0.143048, -0.543306, 0.573346, 0.523815, -0.53325, 0.468211, 0.783185, -0.269976, 0.320526, 0.743389, -0.207486, 0.384965, 0.351051, -0.792721, 0.321493, 0.73458, -0.631719, 0.163855, 0.92639, -0.514523, 0.271138, 0.956088, -0.386424, 0.163401, 0.930524, -0.486595, 0.00104547, 1.08874, -0.326299, 0.00104547, 0.904533, -0.462058, 1.58268, 0.259184, -0.668445, 1.73174, 0.152757, -0.290415, 1.46398, 0.121989, -1.57608, 3.45117, -0.0476083, -1.61428, 3.4244, 0.016813, -1.50191, 3.29774, -0.132197, -1.66072, 3.58429, -0.072422, -1.62434, 3.38222, -0.419987, -1.67177, 3.34226, -0.426789, -1.48496, 3.24915, -0.287145, -1.57272, 3.23249, -0.370566, -1.54119, 3.29007, -0.372791, -1.79243, 3.69662, -0.478226, -1.47279, 3.17682, -0.509438, -1.6491, 3.37415, -0.611694, -1.52444, 3.47482, 0.146797, -1.98619, 2.68696, 0.233771, -1.97806, 2.60303, -0.0912834, -2.07568, 2.68462, -0.249978, -2.24859, 2.87814, -0.35026, -2.14291, 2.96404, 0.3995, -2.30152, 3.24052, 0.317542, -2.38915, 3.19439, -0.219368, -2.41174, 3.31063, 0.0752657, -0.0964089, 0.00104547, -0.196812, -0.154027, 0.441809, 0.19622, -0.835003, 0.00104547, -0.205403, -0.55748, 1.72198, 0.0964474, -0.611101, 1.70343, 0.114914, -0.447702, 1.58483, 0.201877, -0.425773, 1.62639, 0.166544, -0.506064, 1.79234, -0.0642154, -0.30653, 1.48536, 0.0960338, -0.311982, 1.54621, 0.0812291, -0.408718, 1.71209, -0.154497, -0.23599, 1.51185, -0.0296548, -0.272186, 1.57784, -0.251696, -0.14499, 0.00104547, 0.619324, -0.0508581, 0.00104547, 0.0402964, -0.916171, 0.00104547, 0.0302318, -0.82337, 0.00104547, 0.611434, -0.874277, 0.386199, 0.339815, -0.644625, 0.00104547, 0.90083, -0.19633, 0.00104547, -0.176104, -0.108829, 0.00104547, 0.040049, -0.85902, 0.00104547, 0.0313234, -0.736495, 0.00104547, -0.182387, -1.86783, 5.49219, -0.536097, -1.86783, 5.22204, -0.265945, -1.99626, 5.45781, -0.129823, -1.99626, 5.62831, -0.300326, -1.86783, 6.50041, -0.265945, -1.86783, 6.23026, -0.536097, -1.99626, 6.09414, -0.300326, -1.99626, 6.26464, -0.129823, -1.86783, 5.86123, -0.63498, -1.99626, 5.86123, -0.362734, -1.7, 6.62333, -0.336911, -1.7, 6.30123, -0.659013, -1.7, 5.42123, -0.659013, -1.7, 5.09912, -0.336911, -1.7, 5.86123, -0.776911, -1.6, 6.62333, 0.543096, -1.7, 6.62333, 0.543096, -1.7, 6.30123, 0.865198, -1.6, 6.30123, 0.865198, -1.7, 5.86123, 0.983096, -1.6, 5.86123, 0.983096, -1.7, 5.42123, 0.865198, -1.6, 5.42123, 0.865198, -1.6, 5.42123, -0.659013, -1.6, 5.09912, -0.336911, -1.7, 5.09913, 0.543096, -1.6, 5.09913, 0.543096, -1.6, 5.86123, -0.776911, -1.7, 4.98123, 0.103096, -1.6, 4.98123, 0.103096, -1.6, 6.30123, -0.659013, -1.6, 6.62333, -0.336911, -1.6, 6.74123, 0.103096, -1.7, 6.74123, 0.103096, -1.86783, 6.23026, 0.742282, -1.86783, 5.86123, 0.841165, -1.86783, 5.49219, 0.742282, -1.86783, 5.22204, 0.47213, -1.86783, 5.12316, 0.103096, -1.86783, 6.5993, 0.103096, -1.86783, 6.50041, 0.47213, -1.99626, 5.45781, 0.336007, -1.99626, 5.3954, 0.103096, -1.99626, 5.86123, 0.568919, -1.99626, 5.62832, 0.50651, -1.99626, 6.09414, 0.50651, -1.99626, 6.26464, 0.336007, -1.99626, 6.32705, 0.103096, -0.102832, 2.48009, 0.176006, -0.0988953, 2.42787, 0.190009, -0.149215, 2.70638, -0.125392, -0.152867, 2.69118, -0.160703, -0.245228, 2.61305, -0.0718189, -0.228589, 2.63923, -0.0490058, -0.200279, 2.72863, -0.178996, -0.254515, 2.5228, 0.0532499, -0.32495, 2.52211, 0.0834183, -0.230502, 2.45653, 0.179303, -0.177509, 2.46933, 0.131427, -0.31356, 2.6328, -0.0699792, -0.134082, 2.39331, 0.261453, -0.225093, 2.1995, 0.49518, -0.391925, 2.2292, 0.34273, -0.377566, 2.23301, 0.230347, -0.273286, 2.15284, 0.145033, -0.272307, 2.12215, 0.166987, -0.306467, 2.75371, -0.22827, -0.509219, 2.60277, -0.0602789, -0.384471, 2.30721, 0.355435, -0.141881, 2.21642, -0.246023, -0.340915, 2.69228, -0.257391, -0.226149, 2.1204, 0.482878, -0.0951926, 1.97992, 0.0646229, -0.536694, 2.41886, 0.193185, -0.163197, 2.02451, 0.00668271, -0.221777, 2.14883, -0.169134, -0.229811, 2.07077, -0.0609438, -0.549486, 2.33903, 0.185763, -0.532141, 2.52821, -0.0726373, -0.367385, 2.32682, -0.123862, -0.198102, 4.44663, -0.00271145, -0.681184, 4.27477, 0.307467, -0.535945, 4.16951, 0.521097, -0.0960235, 4.4178, 0.0939296, -0.295152, 4.11437, 0.707528, -0.568386, 3.97815, -0.416848, -0.75197, 4.49872, -0.484507, -0.453404, 3.62952, 1.15385, -0.354866, 3.3434, 0.864531, -0.713601, 4.46674, -0.124363, -1.12602, 4.3213, -0.0494407, -1.03995, 4.04518, 0.442157, -0.716219, 4.58287, -0.480226, -0.464921, 4.64317, -0.424668, -0.850048, 3.71295, 0.879328, -0.649196, 3.42772, 0.674737, -0.84841, 3.80937, 0.873472, -0.451539, 3.72707, 1.15037, -0.258719, 3.09481, 0.245674, -0.155937, 3.05577, 0.331006, -0.822291, 3.77674, 0.0641416, -0.359401, 3.14451, 0.132252, -0.226502, 3.30884, -0.183514, -1.1403, 4.19005, 0.0860849, -1.11025, 4.20631, -0.0820755, -1.07207, 4.04817, 0.195228, -0.177538, 3.25078, -0.147598, -0.20137, 2.11848, 0.0341487, -0.249187, 2.13753, -0.031997, -0.497933, 2.32861, 0.160251, -0.252884, 2.22978, -0.1047, -0.438171, 2.39896, -0.000411894, -0.941862, 3.86072, 0.194563, -0.997836, 4.10049, -0.213272, -0.87372, 3.89175, -0.186777, -0.347259, 3.23006, -0.0503454, -0.821813, 3.80214, -0.0657451, -1.01577, 4.06798, 0.154229, -0.908494, 3.91354, 0.153681, -1.04723, 4.19828, -0.0742428, -1.07199, 4.18489, 0.0643051, -2.0359, 6.06097, -0.242878, -2.0359, 6.20719, -0.0966551, -2.0359, 5.51526, -0.0966551, -2.0359, 5.66148, -0.242878, -2.0359, 5.86123, -0.296399, -2.0359, 6.06097, 0.449063, -2.0359, 5.86123, 0.502584, -2.0359, 5.66148, 0.449063, -2.0359, 5.51526, 0.30284, -2.0359, 5.46174, 0.103096, -2.0359, 6.26072, 0.103096, -2.0359, 6.20719, 0.30284, -0.329213, 5.47658, 1.00003, -0.329213, 5.20344, 0.811334, -1.15486, 6.36123, 0.969121, -1.39648, 6.36123, 0.969121, -1.2072, 6.11123, 1.03611, -1.39648, 5.36123, -0.762936, -1.39648, 5.86123, -0.896911, -1.39648, 4.9952, -0.396911, -0.257146, 5.2834, 0.752961, -0.257147, 5.40641, 0.875976, -0.329213, 5.36123, 0.969121, -0.257147, 5.49634, 0.900073, -0.685695, 5.86123, 1.1031, -0.633352, 6.11123, 1.03611, -1.39648, 5.36123, 0.969121, -1.15486, 5.86123, 1.1031, -1.39648, 5.86123, 1.1031, -1.39648, 4.9952, 0.603096, -0.23657, 2.56168, 0.0584772, -0.170392, 2.51572, 0.125662, -0.350345, 2.31871, -0.0906937, -0.153299, 4.61636, -0.336561, -0.252264, 4.53307, -0.191655, -0.271744, 3.18932, -0.0437093, -0.202672, 3.0838, 0.187225, -0.122488, 3.05335, 0.253795, -0.281216, 3.12258, 0.0987407, -0.85235, 3.93911, -0.160509, -0.954611, 4.1111, -0.182336, -0.809584, 3.86528, -0.0607897, -0.809978, 3.84435, 0.0462258, -1.39648, 4.86123, 0.103096, -0.18642, 4.95573, -0.248219, -0.269727, 4.92174, -0.116503, -0.212301, 4.88556, 0.0356146, -0.942888, 6.86123, 0.103096, -0.841135, 6.72725, -0.396911, -1.39648, 6.72725, -0.396911, -1.39648, 6.86123, 0.103096, -0.257165, 6.36123, -0.762936, -1.39648, 6.36123, -0.762936, -1.39648, 6.72725, 0.603096, -0.841135, 6.72725, 0.603096, -0.257165, 6.36123, 0.969121, -0.685695, 6.36123, 0.969121 </vector3_array>
- <vector3_array len="679"> 0.323483, -0.753124, 0.572855, 0.771126, -0.534781, 0.345505, 0.599478, 0.562448, 0.569454, 0.202252, 0.315394, 0.927157, 0, 1, -0, 0.696021, 0.718022, -0, 0.599136, 0.562128, -0.57013, 0, 0.866019, -0.500011, 0, -0.789191, -0.614148, 0, 0.382911, -0.923785, 0.202065, 0.315101, -0.927298, 0.323297, -0.752692, -0.573527, 0, -0.789675, 0.613525, 0, 0.383265, 0.923638, 0.770859, -0.534596, -0.346386, 0.868674, -0.495384, 0, 0, 0.866452, 0.49926, 0.167052, 0.584181, -0.794246, 0.308094, 0.942288, -0.13104, -0.783538, 0.601413, -0.156107, -0.724538, 0.614456, -0.312232, -0.831821, 0.51651, -0.203201, -0.468553, 0.81396, 0.343405, -0.207013, 0.970059, -0.127008, -0.839933, 0.527586, -0.127141, -0.839469, 0.51929, -0.16009, -0.952083, -0.0830945, -0.294335, -0.969325, 0.0600821, 0.238326, -0.242219, 0.80573, 0.54049, -0.618771, 0.285356, 0.731912, -0.00900884, -0.126124, 0.991974, 0.500138, 0.3651, 0.785216, 0.0490036, 0.723054, -0.689051, 0.0889861, 0.993844, -0.0659897, 0.858321, 0.492184, 0.145054, 0.845097, 0.209024, -0.492057, -0.210106, 0.16008, -0.964484, 0.529219, -0.36215, -0.767317, 0.835061, -0.3935, 0.384488, 0.882867, -0.432425, 0.18318, 0.857612, -0.49035, 0.155111, 0.828872, -0.533561, 0.168177, -0.311554, -0.724288, 0.615094, -0.251244, -0.959933, -0.124121, 0.661603, -0.73467, 0.150137, 0.642912, -0.678963, 0.354503, 0.72766, -0.516469, 0.45141, 0.115162, -0.7841, -0.609856, 0.772162, -0.611128, 0.174036, 0.773373, -0.45522, 0.441213, 0.537341, -0.81952, 0.199126, -0.891041, -0.346405, -0.293343, -0.609658, -0.17619, -0.772835, -0.901333, -0.16224, 0.401594, -0.77153, 0.0690475, -0.632435, -0.315127, 0.0940378, -0.944379, 0.055046, -0.627524, -0.776649, -0.536581, -0.621673, -0.570617, 0.861095, 0.107012, 0.497055, -0.0380375, 0.0810799, 0.995982, -0.00700771, -0.117129, 0.993092, 0.797008, -0.304385, 0.521659, 0.524884, 0.803823, -0.279938, 0.595044, 0.585044, 0.551041, 0.871559, 0.129934, -0.472761, -0.200267, 0.367489, 0.90821, 0.0669956, 0.520966, -0.850944, 0.382844, 0.129947, -0.914628, -0.739262, 0.276472, 0.614048, -0.776468, 0.0611156, 0.627186, -0.58619, 0.359116, -0.726235, -0.959877, 0.277253, 0.0420384, -0.992667, 0.0720484, -0.0970652, -0.896641, 0.277198, -0.345247, -0.943047, 0.164182, -0.289321, -0.728454, 0.359224, -0.583363, -0.765447, 0.642375, 0.0380222, -0.855938, 0.516566, 0.0230252, -0.610501, 0.786645, -0.0920755, -0.477172, 0.854307, 0.206074, -0.309014, 0.951044, 0.00500023, -0.513202, 0.81332, -0.274108, -0.781621, 0.597475, 0.179142, -0.831231, 0.554821, 0.0350519, -0.80571, 0.57851, 0.127112, 0.0110026, 0.996233, -0.0860201, -0.616626, 0.733745, -0.28529, -0.740791, 0.504539, 0.443474, 0.0110097, 0.826727, 0.562495, 0.798668, 0.375314, 0.470393, 0.00700849, 0.548665, 0.836013, 0.68171, 0.189197, 0.706736, -0.65479, 0.336406, 0.676817, -0.0310549, -0.441781, 0.896585, -0.617121, -0.634152, 0.465846, -0.16707, 0.870366, 0.463195, -0.5063, 0.725429, 0.466276, -0.711913, 0.614788, 0.339435, -0.409744, 0.0530964, 0.910654, -0.764085, -0.38755, 0.515732, -0.847732, 0.508439, -0.15113, 0.0380266, 0.718502, 0.694485, -0.160029, 0.076014, -0.984181, -0.759497, 0.484317, -0.434284, -0.812045, -0.505651, -0.291375, -0.511638, -0.289361, -0.809009, -0.820559, 0.421287, -0.386263, -0.223103, 0.739342, -0.635294, -0.724353, 0.0750365, -0.685334, -0.43004, 0.304028, -0.850078, -0.80007, 0.434581, 0.413553, -0.0460378, -0.996819, -0.0650535, -0.0350519, -0.808196, 0.58787, 0.267172, -0.820528, -0.505325, 0.6294, -0.428272, -0.648412, 0.297403, -0.309419, 0.903223, 0.622553, 0.221196, 0.750666, 0.897953, 0.117994, -0.423978, 0.920375, 0.351143, 0.17207, -0.753305, -0.654134, 0.0681181, -0.674119, -0.252419, 0.694153, 0.713493, -0.691478, -0.113078, 0.455352, 0.602466, 0.655507, -0.318438, 0.223307, 0.921266, -0.564392, 0.704489, 0.430299, -0.398344, 0.805696, 0.438379, 0.565223, 0.681269, -0.465184, -0.74958, 0.0670519, 0.658509, -0.747893, 0.534638, 0.39347, -0.0789773, 0.541844, -0.83676, -0.969378, 0.150213, 0.194276, -0.723252, 0.667233, -0.178062, -0.702756, -0.294317, -0.647697, -0.77343, -0.576065, 0.264489, 0.64207, -0.336037, -0.689075, 0.714816, 0.636836, -0.288926, 0.692559, -0.68055, 0.239193, 0.560659, -0.716842, 0.414487, -0.216317, -0.957402, 0.19128, 0.194204, -0.972021, 0.132139, 0.711943, 0.135989, -0.688945, -0.686439, 0.302193, -0.661423, 0.776432, -0.314175, -0.546304, 0.886017, -0.231005, -0.402008, 0.886168, -0.401076, -0.232044, 0.776611, -0.545429, -0.315248, 0.776187, 0.546132, -0.315076, 0.885812, 0.401915, -0.231951, 0.885812, 0.231951, -0.401915, 0.776187, 0.315076, -0.546132, 0.885871, 0, -0.463932, 0.776359, 0, -0.630291, 0.327036, 0.818089, -0.473052, 0.327036, 0.473052, -0.818089, 0.32719, -0.472275, -0.818476, 0.327303, -0.817758, -0.473439, 0.327008, 0, -0.945022, -0.652547, 0.65655, 0.378317, -0.652728, 0.379423, 0.655732, 0.327303, 0.473439, 0.817758, 0.32719, 0.818476, 0.472275, -0.653098, 0, 0.757273, 0.327317, 0, 0.944915, -0.652976, -0.378566, 0.65598, 0.327458, -0.472662, 0.818145, -0.652547, -0.378317, -0.65655, -0.652728, -0.655732, -0.379423, -0.652976, -0.65598, 0.378566, 0.327458, -0.818145, 0.472662, -0.652603, 0, -0.7577, -0.653098, -0.757273, 0, 0.327317, -0.944915, 0, -0.6523, 0.379174, -0.656302, -0.6523, 0.656302, -0.379174, -0.652603, 0.7577, 0, 0.327008, 0.945022, -0, 0.776848, 0, 0.629688, 0.776611, 0.315248, 0.545429, 0.776856, -0.314346, 0.545601, 0.776856, -0.545601, 0.314346, 0.776848, -0.629688, 0, 0.776432, 0.546304, 0.314175, 0.776359, 0.630291, -0, 0.886281, -0.463147, 0, 0.886373, -0.401169, 0.231097, 0.886373, -0.231097, 0.401169, 0.886281, 0, 0.463147, 0.886168, 0.232044, 0.401076, 0.886017, 0.402008, 0.231005, 0.885871, 0.463932, -0, 0.320359, 0.0650729, 0.945059, 0, 0.0700382, 0.997544, 0, 0.642347, 0.766414, 0.0170187, 0.688755, 0.724794, 0.609974, 0.430981, -0.664971, 0.947519, 0.264145, -0.180099, 0.303207, 0.801547, 0.515352, 0.183115, 0.866546, 0.464292, 0, 0.882519, 0.470277, -0.0130118, 0.73066, 0.682617, 0, 0.706106, 0.708106, 0.225998, 0.736995, 0.636996, 0.221247, 0.645722, 0.730817, -0.0530284, 0.84045, 0.539289, -0.0270074, 0.825227, 0.564155, -0.0350336, 0.777746, 0.627602, 0, 0.830353, 0.557237, -0.0410178, 0.818354, 0.573248, 0, 0.314425, 0.949282, 0.27534, 0.29136, 0.916132, 0.778752, -0.489473, 0.392379, 0.746544, -0.651475, -0.135099, 0.272405, -0.803194, 0.529788, 0.652602, -0.667616, 0.35833, 0.671414, 0.730451, 0.125077, 0.357959, 0.928893, -0.0949891, 0.443473, 0.436465, 0.782835, 0, 0.377932, -0.925833, 0.555211, 0.240091, -0.796302, 0.325138, -0.340145, -0.882376, 0, -0.203036, -0.979171, 0.405354, -0.612535, 0.678593, 0, -0.671726, 0.7408, 0, -0.989545, 0.144225, 0.324316, -0.945923, 0.00700683, 0.678459, 0.508344, 0.530359, 0.581287, -0.797393, -0.16208, 0, 0.993246, -0.116029, 0.624575, -0.536494, -0.567522, 0, -0.741749, -0.670677, 0, -0.556084, -0.831126, 0, -0.999902, -0.0140126, 0, -0.966632, -0.256168, 0.738289, -0.658258, -0.147058, 0, -0.851521, -0.524321, 0, -0.900741, -0.434357, 0, -0.346076, -0.938206, 0.897164, -0.425078, 0.120022, 0.916025, -0.0850023, -0.392011, 0.746835, -0.537601, -0.391438, 0.24712, 0.836407, 0.489238, 0.187033, 0.840147, 0.509089, 0.180007, 0.858032, 0.481018, 0.245128, 0.817427, 0.521272, 0, 0.768221, 0.640184, 0, 0.834352, 0.551232, 0.143113, 0.833656, 0.53342, 0, 0.114054, -0.993474, 0.536767, 0.0429814, -0.842635, 0.34218, -0.328173, -0.880463, 0, -0.278155, -0.960536, 0.372421, -0.379429, 0.846957, 0, -0.377424, 0.926041, 0, -0.819843, 0.572589, 0.295296, -0.813817, 0.500502, 0.195064, 0.900294, 0.389127, 0.804875, 0.356387, 0.474516, 0.808731, 0.587804, -0.020993, 0, 0.994988, 0.0999987, 0.169127, 0.969729, 0.176132, 0.451126, 0.771215, -0.449125, 0, 0.777245, -0.629198, 0.78993, -0.410483, 0.455536, 0.657391, -0.729434, 0.189112, 0.705632, 0.319286, 0.632566, 0.308272, 0.411363, 0.857758, 0.231245, -0.951006, 0.205217, 0.47266, -0.881231, 0.00500699, 0.887311, -0.393138, -0.241085, 0.618412, -0.762508, -0.190127, 0.259028, -0.529057, -0.808087, 0, -0.471055, -0.882104, 0, -0.97194, 0.235228, 0.972719, -0.231933, -0.00499856, 0.748485, -0.564366, -0.348226, 0, 0.419376, 0.907813, 0.793691, -0.521454, -0.313273, 0.307062, -0.405082, -0.861174, 0, -0.36621, -0.930532, -0.256367, -0.749072, -0.610874, 0.241336, -0.969348, -0.0460641, 0.800238, -0.563168, -0.206061, 0.679395, -0.526306, -0.511297, 0.794806, -0.441448, -0.416422, 0.78099, -0.430994, -0.451994, 0.727309, -0.686292, 0.00500213, 0.915343, -0.34713, -0.204077, 0.535473, -0.673595, -0.50945, 0.971477, -0.237116, 0.00300147, 0.731118, -0.68011, -0.0540087, 0.849093, -0.528058, -0.0140015, 0.83344, -0.540285, -0.116061, 0.864591, -0.499341, -0.0560383, 0.984291, 0.153045, -0.088026, 0.984291, 0.088026, -0.153045, 0.984377, -0.0870333, -0.153059, 0.984441, -0.152068, -0.0880395, 0.984378, 0, -0.176068, 0.984551, 0, 0.175098, 0.984441, 0.0880395, 0.152068, 0.984527, -0.0870466, 0.152081, 0.984527, -0.152081, 0.0870466, 0.984551, -0.175098, 0, 0.984377, 0.153059, 0.0870333, 0.984378, 0.176068, -0, 0, 0, 1, 0, -0.848897, 0.528558, -0.210351, -0.405676, 0.889483, 0, -0.0810577, 0.996709, 0, -0.92105, 0.389444, -0.197353, -0.573024, 0.795421, -0.167145, 0.336293, 0.926806, -0.401672, 0.237397, 0.884479, 0.653302, 0.379175, 0.655303, 0, 0, -1, 0.653177, 0, -0.757205, 0.653121, -0.37807, -0.656122, 0, -0.49926, -0.866452, 0.671631, -0.686645, -0.278262, 0, -0.926881, -0.375357, -0.433934, -0.447965, 0.781683, -0.4965, -0.437441, 0.749755, -0.353503, -0.137195, 0.925318, 0, -0.848897, 0.528558, -0.359502, -0.75906, 0.542758, 0, -0.0770792, 0.997025, 0.168109, 0.172111, 0.970627, 0.402511, 0.237301, 0.884123, 0.65355, -0.378318, 0.655551, 0.653672, 0, 0.756778, -0.167136, 0.17214, 0.97079, 0.668803, -0.684822, 0.289347, 0.880048, 0.129007, 0.457025, 0.644507, 0.0390307, 0.763601, 0, 0.542878, -0.839811, 0.823173, -0.419088, -0.383081, 0, 0.941447, 0.33716, 0.175995, 0.932972, 0.31399, 0.269002, 0.885006, 0.380003, 0.644374, -0.493286, -0.584339, 0.355385, -0.786851, 0.504546, 0.641692, -0.681736, 0.351379, 0.758512, -0.647437, -0.07405, 0, -0.746027, 0.665916, 0.905274, -0.411124, -0.107032, 0.759428, -0.614346, -0.214121, 0.64053, -0.74862, -0.171142, 0.712784, -0.693763, -0.103113, 0, -0.812786, -0.582563, 0.707572, -0.706571, 0.0100081, 0.463983, -0.666975, -0.582978, 0.721736, -0.682696, -0.114116, 0.557506, -0.667605, 0.493448, 0, -0.762778, 0.64666, -0.001, 1, 0, 0.653177, 0.757205, -0, 0.652874, 0.655873, -0.378927, -0.0379873, 0.86471, -0.500832, 0.652874, 0.378927, -0.655873, -0.0350082, 0.578135, -0.81519, -0.0380063, 0.865143, 0.500083, 0.653121, 0.656122, 0.37807, 0, 0.610194, -0.792252, -0.0350367, 0.578606, 0.814854, 0.168118, 0.336236, 0.926651, 0, 0.610678, 0.791879, -0.322586, -0.753368, 0.57304, -0.201292, 0.315457, 0.927345, -0.598836, 0.562786, 0.569796, -0.77072, -0.535194, 0.345772, -0.598495, 0.562465, -0.570471, -0.695505, 0.718521, 0, -0.322401, -0.752935, -0.573713, -0.201105, 0.315165, -0.927485, -0.770452, -0.535009, -0.346654, -0.868428, -0.495815, 0, -0.166079, 0.584278, -0.794378, 0.725013, 0.614011, -0.312005, 0.783924, 0.600942, -0.155985, -0.307188, 0.942578, -0.13108, 0.20797, 0.969858, -0.126981, 0.469334, 0.813578, 0.343244, 0.832129, 0.51608, -0.203032, 0.840228, 0.527143, -0.127034, 0.969385, 0.0600239, 0.238095, 0.952177, -0.0830154, -0.294055, 0.839764, 0.518854, -0.159955, 0.243161, 0.805534, 0.540358, -0.499387, 0.365283, 0.785609, 0.0100097, -0.126123, 0.991964, 0.619388, 0.285179, 0.731458, -0.0480059, 0.723089, -0.689085, -0.844811, 0.209201, -0.492473, -0.858057, 0.492607, 0.145179, -0.087994, 0.993932, -0.0659955, 0.211062, 0.160047, -0.964281, -0.528498, -0.362341, -0.767723, -0.882646, -0.432807, 0.183342, -0.834757, -0.393829, 0.38481, -0.828558, -0.534004, 0.168317, -0.857347, -0.490771, 0.155244, 0.312458, -0.724062, 0.614902, -0.642324, -0.679401, 0.354731, -0.66104, -0.735157, 0.150236, 0.252182, -0.959691, -0.124089, -0.727189, -0.516845, 0.451739, -0.771757, -0.6116, 0.174171, -0.114173, -0.784191, -0.609926, -0.772971, -0.455572, 0.441554, -0.536629, -0.819961, 0.199233, 0.891247, -0.346096, -0.293081, 0.610287, -0.176083, -0.772363, 0.90152, -0.162094, 0.401232, 0.771935, 0.0689942, -0.631947, 0.537293, -0.621339, -0.570311, -0.0540481, -0.627558, -0.776691, 0.316027, 0.0940081, -0.944081, -0.860836, 0.107104, 0.497483, -0.796642, -0.304628, 0.522076, 0.00800875, -0.117128, 0.993085, 0.039037, 0.0810768, 0.995943, -0.524159, 0.804245, -0.280085, -0.871318, 0.130047, -0.473173, -0.594398, 0.585392, 0.551369, 0.201228, 0.367416, 0.908027, -0.0660001, 0.521001, -0.851001, -0.381991, 0.129997, -0.914978, 0.776865, 0.061068, 0.626698, 0.739716, 0.276267, 0.613594, 0.586846, 0.358906, -0.725809, 0.992681, 0.0719769, -0.0969689, 0.959955, 0.276987, 0.0419981, 0.896837, 0.27695, -0.344937, 0.943158, 0.164027, -0.289048, 0.856205, 0.516124, 0.0230055, 0.765861, 0.641883, 0.0379931, 0.728923, 0.358962, -0.582938, 0.611128, 0.786165, -0.0920193, 0.513938, 0.812902, -0.273967, 0.309918, 0.95075, 0.00499869, 0.477944, 0.853899, 0.205976, 0.78201, 0.597008, 0.179002, 0.806061, 0.578044, 0.12701, 0.83154, 0.55436, 0.0350227, -0.0100024, 0.996243, -0.086021, -0.0100089, 0.826736, 0.562501, 0.741242, 0.504165, 0.443145, 0.617246, 0.733292, -0.285114, -0.798305, 0.375614, 0.470769, -0.681174, 0.189326, 0.707219, -0.00600732, 0.548668, 0.836019, 0.655362, 0.336185, 0.676373, 0.0320557, -0.441767, 0.896557, 0.617741, -0.63376, 0.465558, 0.507043, 0.725062, 0.46604, 0.168043, 0.870221, 0.463117, 0.712406, 0.61435, 0.339193, 0.410577, 0.0530746, 0.91028, 0.848013, 0.508008, -0.151002, 0.764501, -0.387254, 0.515338, -0.0370272, 0.718529, 0.694511, 0.161004, 0.0760018, -0.984023, 0.75992, 0.483949, -0.433954, 0.812386, -0.50524, -0.291138, 0.820886, 0.420942, -0.385946, 0.512377, -0.289213, -0.808595, 0.224054, 0.739177, -0.635152, 0.724828, 0.0749822, -0.684837, 0.430854, 0.303897, -0.849712, 0.80043, 0.434233, 0.413222, 0.0360521, -0.808167, 0.587849, 0.0470365, -0.996773, -0.0650504, -0.266242, -0.820747, -0.50546, -0.628795, -0.428542, -0.648821, -0.296489, -0.309511, 0.903492, -0.621939, 0.221334, 0.751134, -0.897759, 0.1181, -0.424359, -0.920222, 0.351467, 0.172229, 0.753738, -0.65364, 0.0680667, 0.674665, -0.252249, 0.693684, -0.713001, -0.691972, -0.113159, -0.454558, 0.60274, 0.655806, 0.399186, 0.805375, 0.438204, 0.565073, 0.704091, 0.430056, 0.319337, 0.223236, 0.920972, -0.564542, 0.681654, -0.465447, 0.748334, 0.534238, 0.393175, 0.750018, 0.0670016, 0.658015, 0.0799707, 0.541802, -0.836693, 0.969438, 0.150068, 0.194088, 0.723729, 0.66675, -0.177933, 0.773832, -0.575619, 0.264284, 0.703262, -0.29411, -0.647241, -0.641482, -0.336253, -0.689518, -0.692038, -0.681022, 0.239359, -0.714327, 0.637291, -0.289132, -0.559972, -0.717244, 0.41472, 0.217271, -0.957194, 0.191239, 0.686968, 0.301986, -0.660969, -0.711449, 0.136086, -0.689435, -0.19324, -0.972209, 0.132164, -0.776034, -0.314419, -0.546728, -0.776214, -0.545854, -0.315493, -0.885953, -0.401432, -0.23225, -0.885802, -0.231209, -0.402364, -0.775789, 0.546556, -0.315321, -0.775789, 0.315321, -0.546556, -0.885597, 0.232156, -0.402271, -0.885597, 0.402271, -0.232156, -0.775961, 0, -0.630781, -0.885655, 0, -0.464344, -0.326142, 0.818357, -0.473206, -0.326142, 0.473206, -0.818357, -0.326296, -0.472429, -0.818744, -0.326409, -0.818026, -0.473594, -0.326114, 0, -0.94533, 0.653121, 0.656122, 0.37807, -0.326296, 0.818744, 0.472429, -0.326409, 0.473594, 0.818026, 0.653302, 0.379175, 0.655303, -0.326423, 0, 0.945224, 0.653672, 0, 0.756778, -0.326564, -0.472817, 0.818413, 0.65355, -0.378318, 0.655551, 0.653121, -0.37807, -0.656122, 0.653302, -0.655303, -0.379175, -0.326564, -0.818413, 0.472817, 0.65355, -0.655551, 0.378318, 0.653177, 0, -0.757205, -0.326423, -0.945224, 0, 0.653672, -0.756778, 0, 0.652874, 0.378927, -0.655873, 0.652874, 0.655873, -0.378927, 0.653177, 0.757205, -0, -0.326114, 0.94533, 0, -0.776214, 0.315493, 0.545854, -0.776451, 0, 0.630178, -0.776459, -0.314591, 0.546026, -0.776459, -0.546026, 0.314591, -0.776451, -0.630178, 0, -0.775961, 0.630781, 0, -0.776034, 0.546728, 0.314419, -0.886159, -0.401525, 0.231302, -0.886067, -0.463558, 0, -0.886067, 0, 0.463558, -0.886159, -0.231302, 0.401525, -0.885953, 0.23225, 0.401432, -0.885802, 0.402364, 0.231209, -0.885655, 0.464344, 0, -0.31946, 0.0650937, 0.945361, -0.0160178, 0.688766, 0.724806, -0.609345, 0.431244, -0.665377, -0.182148, 0.866704, 0.464377, -0.302298, 0.80179, 0.515508, -0.947416, 0.264395, -0.18027, 0.0140125, 0.730651, 0.682608, -0.225049, 0.737161, 0.637139, 0.0280069, 0.825204, 0.56414, 0.054026, 0.840405, 0.53926, -0.220295, 0.645864, 0.730978, 0.0360333, 0.777718, 0.62758, 0.0420165, 0.81832, 0.573224, -0.274414, 0.29144, 0.916384, -0.778358, -0.489855, 0.392685, -0.652026, -0.668052, 0.358564, -0.271477, -0.803413, 0.529932, -0.746101, -0.651962, -0.135199, -0.357087, 0.929225, -0.095023, -0.670864, 0.730942, 0.125161, -0.442668, 0.436659, 0.783182, -0.324243, -0.340255, -0.882662, -0.554518, 0.240224, -0.796745, -0.404517, -0.612784, 0.678868, -0.323422, -0.946236, 0.00600785, -0.677918, 0.508689, 0.530719, -0.580624, -0.797857, -0.162174, -0.623964, -0.536829, -0.567877, -0.737833, -0.658744, -0.147166, -0.896969, -0.42546, 0.12013, -0.915864, -0.0850803, -0.39237, -0.746391, -0.538003, -0.39173, -0.246181, 0.836614, 0.489359, -0.179039, 0.858186, 0.481104, -0.186067, 0.840304, 0.509184, -0.244187, 0.817627, 0.5214, -0.142132, 0.833775, 0.533496, -0.341296, -0.328285, -0.880764, -0.536055, 0.0430044, -0.843087, -0.371558, -0.37957, 0.847273, -0.294382, -0.814057, 0.50065, -0.194101, 0.90047, 0.389203, -0.808384, 0.58828, -0.02101, -0.804522, 0.356675, 0.474898, -0.450328, 0.771563, -0.449328, -0.168155, 0.969892, 0.176162, -0.789553, -0.410808, 0.455897, -0.656822, -0.729914, 0.189237, -0.705129, 0.319511, 0.633013, -0.307366, 0.41149, 0.858022, -0.471882, -0.881648, 0.00500936, -0.230297, -0.951225, 0.205264, -0.887098, -0.393487, -0.241299, -0.617794, -0.76298, -0.190244, -0.258094, -0.529194, -0.808295, -0.972665, -0.232159, -0.00500342, -0.748045, -0.564789, -0.348487, -0.79332, -0.521869, -0.313522, -0.306156, -0.405206, -0.861439, -0.240392, -0.969582, -0.0460752, 0.257302, -0.748879, -0.610717, -0.799878, -0.563619, -0.206226, -0.678856, -0.526664, -0.511645, -0.794437, -0.441799, -0.416754, -0.780599, -0.431331, -0.452347, -0.726837, -0.686791, 0.00500577, -0.915181, -0.347448, -0.204264, -0.534758, -0.673956, -0.509723, -0.97142, -0.237347, 0.00300439, -0.848814, -0.528507, -0.0140134, -0.730652, -0.680607, -0.0540482, -0.864338, -0.499774, -0.0560868, -0.833134, -0.540736, -0.116158, -0.98426, 0.0881128, -0.153196, -0.98426, 0.153196, -0.0881128, -0.98441, -0.152218, -0.0881262, -0.984346, -0.0871191, -0.15321, -0.984347, 0, -0.176241, -0.98441, 0.0881262, 0.152218, -0.98452, 0, 0.175271, -0.984497, -0.0871325, 0.152231, -0.984497, -0.152231, 0.0871325, -0.98452, -0.175271, 0, -0.984347, 0.176241, 0, -0.984346, 0.15321, 0.0871191, 0.211308, -0.405591, 0.889295, 0.198315, -0.572911, 0.795264, 0.168118, 0.336236, 0.926651, -0.652728, 0.379423, 0.655732, 0.402511, 0.237301, 0.884123, -0.652547, -0.378317, -0.65655, -0.652603, 0, -0.7577, -0.671081, -0.687107, -0.278449, 0.354379, -0.137147, 0.92499, 0.497254, -0.437223, 0.749383, 0.434747, -0.44777, 0.781343, 0.360374, -0.758786, 0.542562, -0.167136, 0.17214, 0.97079, -0.401672, 0.237397, 0.884479, -0.652976, -0.378566, 0.65598, 0.168109, 0.172111, 0.970627, -0.653098, 0, 0.757273, -0.668249, -0.685281, 0.289541, -0.879823, 0.129121, 0.457428, -0.643922, 0.0390559, 0.764094, -0.82285, -0.419434, -0.383396, -0.175025, 0.933135, 0.314046, -0.268074, 0.885244, 0.380105, -0.643788, -0.493604, -0.584716, -0.641103, -0.682174, 0.351605, -0.354509, -0.787131, 0.504725, -0.758087, -0.647929, -0.0741063, -0.759004, -0.614813, -0.214283, -0.905093, -0.411497, -0.107129, -0.639939, -0.7491, -0.171251, -0.712291, -0.694258, -0.103187, -0.707071, -0.707071, 0.0100152, -0.463198, -0.667285, -0.583249, -0.721256, -0.68319, -0.114199, -0.556815, -0.667978, 0.493723, 0.002, 0.999998, -0, 0.0389854, 0.864677, -0.500813, -0.6523, 0.656302, -0.379174, -0.652603, 0.7577, 0, 0.0360071, 0.578114, -0.815161, -0.6523, 0.379174, -0.656302, -0.652547, 0.65655, 0.378317, 0.039005, 0.86511, 0.500063, 0.0360365, 0.578586, 0.814825, -0.167145, 0.336293, 0.926806 </vector3_array>
- <nil> </nil>
- <nil> </nil>
- <nil> </nil>
- <nil> </nil>
- <real_array len="2716"> 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 9, 8, 0, 0, 8, 9, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 12, 13, 0, 0, 12, 13, 0, 0, 13, 12, 0, 0, 13, 12, 0, 0, 13, 12, 0, 0, 13, 12, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 12, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 9, 8, 0, 0, 8, 9, 0, 0, 9, 0, 0, 0, 8, 9, 0, 0, 9, 8, 0, 0, 9, 0, 0, 0, 8, 9, 0, 0, 8, 9, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 12, 13, 0, 0, 12, 13, 0, 0, 13, 12, 0, 0, 13, 12, 0, 0, 12, 13, 0, 0, 12, 13, 0, 0, 13, 12, 0, 0, 12, 13, 0, 0, 12, 13, 0, 0, 13, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 12, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 7, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 11, 10, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 10, 11, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 15, 16, 0, 0, 16, 15, 0, 0, 16, 15, 0, 0, 15, 16, 0, 0, 16, 15, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 15, 0, 0, 16, 15, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 11, 10, 0, 0, 11, 0, 0, 0, 10, 11, 0, 0, 10, 11, 0, 0, 11, 10, 0, 0, 11, 0, 0, 0, 10, 11, 0, 0, 11, 0, 0, 0, 10, 11, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 15, 16, 0, 0, 16, 15, 0, 0, 16, 15, 0, 0, 15, 16, 0, 0, 15, 16, 0, 0, 16, 15, 0, 0, 15, 16, 0, 0, 15, 16, 0, 0, 15, 16, 0, 0, 16, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 16, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 16, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 15, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0 </real_array>
- <real_array len="2716"> 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.5, 0.5, 0, 0, 0.503159, 0.496841, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.700171, 0.299829, 0, 0, 0.66474, 0.33526, 0, 0, 0.704636, 0.295364, 0, 0, 0.664742, 0.335258, 0, 0, 0.719812, 0.280188, 0, 0, 0.682575, 0.317425, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.664813, 0.335187, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.533212, 0.466788, 0, 0, 0.538228, 0.461772, 0, 0, 1, 0, 0, 0, 0.500006, 0.499994, 0, 0, 0.525218, 0.474782, 0, 0, 1, 0, 0, 0, 0.563768, 0.436232, 0, 0, 0.523139, 0.476861, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.665519, 0.334481, 0, 0, 0.664658, 0.335342, 0, 0, 0.676033, 0.323967, 0, 0, 0.667711, 0.332289, 0, 0, 0.668675, 0.331325, 0, 0, 0.673479, 0.326521, 0, 0, 0.667424, 0.332576, 0, 0, 0.6672, 0.3328, 0, 0, 0.664792, 0.335208, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.500004, 0.499996, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.997415, 0.00258508, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.5, 0.5, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.503159, 0.496841, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.700171, 0.299829, 0, 0, 0.664742, 0.335258, 0, 0, 0.704636, 0.295364, 0, 0, 0.66474, 0.33526, 0, 0, 0.719812, 0.280188, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.682575, 0.317425, 0, 0, 0.664813, 0.335187, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.533212, 0.466788, 0, 0, 1, 0, 0, 0, 0.538228, 0.461772, 0, 0, 0.500006, 0.499994, 0, 0, 0.525218, 0.474782, 0, 0, 1, 0, 0, 0, 0.563768, 0.436232, 0, 0, 1, 0, 0, 0, 0.523139, 0.476861, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.665519, 0.334481, 0, 0, 0.667711, 0.332289, 0, 0, 0.676033, 0.323967, 0, 0, 0.664658, 0.335342, 0, 0, 0.668675, 0.331325, 0, 0, 0.667424, 0.332576, 0, 0, 0.673479, 0.326521, 0, 0, 0.6672, 0.3328, 0, 0, 0.664792, 0.335208, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.500004, 0.499996, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 </real_array>
- <int_array len="3246"> 0, 2, 1, 0, 3, 2, 4, 6, 5, 4, 7, 6, 8, 10, 9, 8, 11, 10, 12, 3, 0, 12, 13, 3, 11, 6, 10, 11, 14, 6, 14, 5, 6, 14, 15, 5, 1, 5, 15, 1, 2, 5, 4, 2, 16, 4, 5, 2, 16, 3, 13, 16, 2, 3, 7, 10, 6, 7, 9, 10, 17, 19, 18, 17, 20, 19, 19, 22, 21, 19, 23, 22, 24, 26, 25, 24, 27, 26, 28, 30, 29, 28, 31, 30, 32, 34, 33, 32, 35, 34, 33, 31, 28, 33, 34, 31, 36, 35, 32, 36, 37, 35, 34, 38, 31, 34, 39, 38, 37, 40, 35, 37, 41, 40, 42, 44, 43, 42, 45, 44, 31, 46, 30, 31, 38, 46, 35, 39, 34, 35, 40, 39, 43, 48, 47, 43, 44, 48, 47, 41, 37, 47, 48, 41, 30, 45, 42, 30, 46, 45, 44, 49, 48, 48, 49, 41, 46, 49, 45, 39, 50, 38, 41, 50, 40, 41, 49, 50, 45, 49, 44, 38, 49, 46, 38, 50, 49, 40, 50, 39, 51, 47, 52, 51, 43, 47, 52, 37, 36, 52, 47, 37, 53, 43, 51, 53, 42, 43, 29, 42, 53, 29, 30, 42, 54, 56, 55, 54, 57, 56, 58, 60, 59, 58, 61, 60, 62, 58, 63, 62, 64, 58, 63, 59, 65, 63, 58, 59, 66, 64, 62, 66, 67, 64, 65, 69, 68, 65, 59, 69, 70, 67, 66, 70, 55, 67, 68, 72, 71, 68, 69, 72, 73, 55, 70, 73, 54, 55, 74, 76, 75, 74, 77, 76, 78, 80, 79, 78, 81, 80, 82, 83, 77, 82, 84, 83, 85, 87, 86, 85, 88, 87, 89, 90, 88, 89, 91, 90, 88, 92, 87, 88, 90, 92, 91, 93, 90, 90, 93, 92, 92, 93, 94, 55, 56, 67, 65, 95, 63, 65, 96, 95, 68, 96, 65, 68, 97, 96, 71, 54, 73, 71, 72, 54, 98, 24, 99, 98, 100, 24, 18, 21, 101, 18, 19, 21, 102, 20, 17, 102, 103, 20, 99, 25, 104, 99, 24, 25, 101, 100, 98, 101, 21, 100, 104, 106, 105, 104, 25, 106, 105, 103, 102, 105, 106, 103, 20, 23, 19, 20, 107, 23, 25, 108, 106, 25, 26, 108, 106, 109, 103, 106, 108, 109, 100, 27, 24, 100, 110, 27, 103, 107, 20, 103, 109, 107, 21, 110, 100, 21, 22, 110, 27, 111, 26, 27, 112, 111, 26, 113, 108, 26, 111, 113, 108, 114, 109, 108, 113, 114, 110, 112, 27, 110, 115, 112, 22, 115, 110, 22, 116, 115, 109, 117, 107, 109, 114, 117, 107, 118, 23, 107, 117, 118, 23, 116, 22, 23, 118, 116, 72, 57, 54, 72, 119, 57, 59, 120, 69, 59, 60, 120, 64, 61, 58, 64, 121, 61, 69, 119, 72, 69, 120, 119, 122, 124, 123, 122, 125, 124, 126, 125, 122, 126, 79, 125, 123, 128, 127, 123, 124, 128, 129, 79, 126, 129, 78, 79, 130, 77, 74, 130, 82, 77, 75, 78, 129, 75, 76, 78, 127, 82, 130, 127, 128, 82, 124, 97, 128, 124, 96, 97, 79, 95, 125, 79, 80, 95, 128, 84, 82, 128, 97, 84, 76, 81, 78, 76, 131, 81, 77, 131, 76, 77, 83, 131, 125, 96, 124, 125, 95, 96, 86, 133, 132, 86, 87, 133, 134, 89, 135, 134, 136, 89, 135, 88, 85, 135, 89, 88, 136, 91, 89, 136, 137, 91, 87, 94, 133, 87, 92, 94, 137, 93, 91, 67, 121, 64, 67, 56, 121, 83, 70, 131, 83, 73, 70, 73, 84, 71, 73, 83, 84, 63, 80, 62, 63, 95, 80, 66, 131, 70, 66, 81, 131, 97, 71, 84, 97, 68, 71, 81, 62, 80, 81, 66, 62, 138, 140, 139, 138, 141, 140, 57, 139, 56, 138, 139, 119, 119, 139, 57, 56, 139, 121, 132, 136, 134, 132, 133, 136, 137, 133, 94, 137, 136, 133, 94, 93, 137, 142, 144, 143, 142, 145, 144, 146, 148, 147, 146, 149, 148, 149, 150, 148, 149, 151, 150, 151, 143, 150, 151, 142, 143, 152, 149, 146, 152, 153, 149, 154, 145, 142, 154, 155, 145, 156, 142, 151, 156, 154, 142, 153, 151, 149, 153, 156, 151, 157, 159, 158, 157, 160, 159, 158, 162, 161, 158, 159, 162, 161, 164, 163, 161, 162, 164, 165, 155, 154, 165, 166, 155, 163, 168, 167, 163, 164, 168, 169, 154, 156, 169, 165, 154, 167, 171, 170, 167, 168, 171, 172, 156, 153, 172, 169, 156, 173, 153, 152, 173, 172, 153, 174, 160, 157, 174, 175, 160, 159, 176, 162, 159, 177, 176, 162, 178, 164, 162, 176, 178, 164, 179, 168, 164, 178, 179, 168, 180, 171, 168, 179, 180, 175, 181, 160, 175, 182, 181, 160, 177, 159, 160, 181, 177, 179, 183, 180, 179, 184, 183, 176, 185, 178, 176, 186, 185, 177, 186, 176, 177, 187, 186, 181, 187, 177, 181, 188, 187, 178, 184, 179, 178, 185, 184, 182, 188, 181, 182, 189, 188, 182, 147, 189, 182, 146, 147, 145, 183, 144, 145, 180, 183, 175, 146, 182, 175, 152, 146, 155, 180, 145, 155, 171, 180, 174, 152, 175, 174, 173, 152, 166, 171, 155, 166, 170, 171, 190, 192, 191, 190, 193, 192, 194, 196, 195, 194, 197, 196, 198, 199, 197, 198, 200, 199, 201, 203, 202, 201, 204, 203, 197, 205, 196, 197, 199, 205, 193, 206, 192, 193, 207, 206, 196, 204, 201, 196, 205, 204, 202, 207, 193, 202, 203, 207, 207, 208, 206, 207, 209, 208, 210, 212, 211, 210, 213, 212, 199, 214, 205, 199, 215, 214, 203, 209, 207, 203, 216, 209, 217, 219, 218, 217, 220, 219, 221, 223, 222, 221, 224, 223, 205, 225, 204, 205, 214, 225, 204, 216, 203, 204, 225, 216, 224, 211, 226, 221, 211, 224, 210, 211, 221, 200, 215, 199, 200, 227, 215, 219, 229, 228, 219, 230, 229, 224, 231, 223, 224, 232, 231, 228, 234, 233, 228, 229, 234, 226, 232, 224, 226, 235, 232, 220, 230, 219, 220, 236, 230, 233, 235, 226, 233, 234, 235, 237, 214, 238, 237, 225, 214, 215, 238, 214, 215, 218, 238, 218, 227, 217, 218, 215, 227, 221, 216, 210, 221, 209, 216, 209, 222, 208, 209, 221, 222, 225, 210, 216, 225, 237, 210, 218, 219, 238, 238, 219, 239, 239, 219, 228, 240, 242, 241, 243, 245, 244, 243, 246, 245, 247, 249, 248, 247, 250, 249, 251, 253, 252, 251, 254, 253, 255, 256, 242, 255, 257, 256, 258, 260, 259, 258, 261, 260, 262, 254, 251, 262, 263, 254, 242, 264, 241, 242, 256, 264, 240, 246, 243, 240, 241, 246, 241, 265, 246, 241, 264, 265, 259, 257, 255, 259, 260, 257, 263, 266, 254, 263, 267, 266, 268, 267, 263, 268, 269, 267, 250, 270, 249, 250, 271, 270, 254, 272, 253, 254, 266, 272, 251, 264, 262, 251, 265, 264, 248, 261, 247, 248, 260, 261, 257, 273, 256, 260, 274, 257, 260, 248, 274, 265, 252, 275, 265, 251, 252, 256, 262, 264, 256, 276, 262, 246, 275, 245, 246, 265, 275, 271, 277, 270, 271, 278, 277, 226, 279, 233, 226, 280, 279, 211, 280, 226, 211, 212, 280, 237, 213, 210, 237, 281, 213, 233, 282, 228, 233, 279, 282, 238, 281, 237, 238, 283, 281, 276, 284, 262, 262, 284, 268, 262, 268, 263, 248, 249, 274, 274, 249, 285, 285, 249, 286, 249, 287, 286, 249, 270, 287, 286, 287, 288, 288, 287, 268, 268, 287, 269, 276, 289, 284, 276, 290, 289, 274, 291, 273, 274, 292, 291, 273, 290, 276, 273, 291, 290, 273, 257, 274, 256, 273, 276, 147, 294, 293, 147, 148, 294, 143, 296, 295, 143, 144, 296, 150, 295, 297, 150, 143, 295, 148, 297, 294, 148, 150, 297, 187, 298, 186, 187, 299, 298, 186, 300, 185, 186, 298, 300, 185, 301, 184, 185, 300, 301, 184, 302, 183, 184, 301, 302, 189, 303, 188, 189, 304, 303, 188, 299, 187, 188, 303, 299, 305, 307, 306, 308, 310, 309, 311, 313, 312, 189, 293, 304, 189, 147, 293, 144, 302, 296, 144, 183, 302, 314, 316, 315, 314, 317, 316, 317, 318, 316, 317, 319, 318, 310, 321, 320, 310, 322, 321, 307, 323, 306, 307, 324, 323, 320, 324, 307, 320, 321, 324, 308, 322, 310, 308, 325, 322, 326, 305, 327, 328, 330, 329, 328, 326, 330, 326, 320, 307, 320, 326, 328, 328, 310, 320, 326, 307, 305, 309, 310, 331, 331, 310, 328, 312, 329, 330, 313, 329, 312, 195, 201, 332, 195, 196, 201, 333, 193, 190, 333, 202, 193, 334, 197, 194, 334, 198, 197, 332, 202, 333, 332, 201, 202, 239, 283, 238, 239, 335, 283, 336, 259, 337, 336, 258, 259, 337, 255, 338, 337, 259, 255, 338, 242, 240, 338, 255, 242, 270, 339, 287, 270, 277, 339, 267, 340, 266, 267, 341, 340, 287, 342, 269, 287, 339, 342, 269, 341, 267, 269, 342, 341, 266, 343, 272, 266, 340, 343, 286, 344, 285, 286, 345, 344, 228, 335, 239, 228, 282, 335, 288, 345, 286, 288, 346, 345, 268, 346, 288, 268, 347, 346, 284, 347, 268, 284, 289, 347, 285, 292, 274, 285, 344, 292, 348, 318, 319, 348, 349, 318, 350, 349, 348, 351, 349, 350, 352, 349, 351, 353, 349, 352, 309, 349, 353, 309, 331, 349, 354, 356, 355, 354, 357, 356, 357, 358, 356, 357, 359, 358, 354, 361, 360, 354, 355, 361, 362, 314, 359, 359, 314, 358, 358, 314, 315, 360, 361, 363, 363, 361, 313, 363, 313, 364, 364, 313, 311, 365, 363, 305, 364, 327, 363, 327, 305, 363, 366, 368, 367, 366, 369, 368, 4, 370, 7, 4, 371, 370, 8, 373, 372, 8, 9, 373, 12, 367, 13, 12, 366, 367, 372, 370, 374, 372, 373, 370, 374, 371, 375, 374, 370, 371, 369, 371, 368, 369, 375, 371, 4, 368, 371, 4, 16, 368, 16, 367, 368, 16, 13, 367, 7, 373, 9, 7, 370, 373, 376, 378, 377, 376, 379, 378, 378, 381, 380, 378, 382, 381, 383, 385, 384, 383, 386, 385, 387, 389, 388, 387, 390, 389, 391, 393, 392, 391, 394, 393, 394, 388, 393, 394, 387, 388, 395, 392, 396, 395, 391, 392, 393, 398, 397, 393, 388, 398, 396, 400, 399, 396, 392, 400, 401, 403, 402, 401, 404, 403, 388, 405, 398, 388, 389, 405, 392, 397, 400, 392, 393, 397, 404, 406, 403, 404, 407, 406, 407, 399, 406, 407, 396, 399, 389, 402, 405, 389, 401, 402, 403, 406, 408, 406, 399, 408, 405, 402, 408, 397, 398, 409, 399, 409, 408, 399, 400, 409, 402, 403, 408, 398, 408, 409, 398, 405, 408, 400, 397, 409, 410, 407, 404, 410, 411, 407, 411, 396, 407, 411, 395, 396, 412, 404, 401, 412, 410, 404, 390, 401, 389, 390, 412, 401, 413, 415, 414, 413, 416, 415, 417, 419, 418, 417, 420, 419, 421, 417, 422, 421, 423, 417, 423, 420, 417, 423, 424, 420, 425, 422, 426, 425, 421, 422, 424, 427, 420, 424, 428, 427, 429, 426, 416, 429, 425, 426, 428, 430, 427, 428, 431, 430, 432, 416, 413, 432, 429, 416, 433, 435, 434, 433, 436, 435, 437, 439, 438, 437, 440, 439, 441, 443, 442, 441, 434, 443, 444, 446, 445, 444, 447, 446, 448, 450, 449, 448, 445, 450, 445, 451, 450, 445, 446, 451, 449, 450, 452, 450, 451, 452, 451, 453, 452, 416, 426, 415, 424, 455, 454, 424, 423, 455, 428, 454, 456, 428, 424, 454, 431, 413, 430, 431, 432, 413, 457, 383, 458, 457, 459, 383, 379, 382, 378, 379, 460, 382, 461, 377, 462, 461, 376, 377, 459, 386, 383, 459, 463, 386, 460, 458, 382, 460, 457, 458, 463, 464, 386, 463, 465, 464, 465, 462, 464, 465, 461, 462, 377, 380, 466, 377, 378, 380, 386, 467, 385, 386, 464, 467, 464, 468, 467, 464, 462, 468, 458, 384, 469, 458, 383, 384, 462, 466, 468, 462, 377, 466, 382, 469, 381, 382, 458, 469, 384, 471, 470, 384, 385, 471, 385, 472, 471, 385, 467, 472, 467, 473, 472, 467, 468, 473, 469, 470, 474, 469, 384, 470, 381, 474, 475, 381, 469, 474, 468, 476, 473, 468, 466, 476, 466, 477, 476, 466, 380, 477, 380, 475, 477, 380, 381, 475, 430, 414, 478, 430, 413, 414, 420, 479, 419, 420, 427, 479, 422, 418, 480, 422, 417, 418, 427, 478, 479, 427, 430, 478, 481, 483, 482, 481, 484, 483, 485, 482, 440, 485, 481, 482, 484, 486, 483, 484, 487, 486, 488, 440, 437, 488, 485, 440, 489, 434, 441, 489, 433, 434, 436, 437, 435, 436, 488, 437, 487, 441, 486, 487, 489, 441, 483, 456, 454, 483, 486, 456, 440, 455, 439, 440, 482, 455, 486, 442, 456, 486, 441, 442, 435, 438, 490, 435, 437, 438, 434, 490, 443, 434, 435, 490, 482, 454, 455, 482, 483, 454, 447, 491, 446, 447, 492, 491, 493, 448, 494, 493, 495, 448, 495, 445, 448, 495, 444, 445, 494, 449, 496, 494, 448, 449, 446, 453, 451, 446, 491, 453, 496, 449, 452, 426, 480, 415, 426, 422, 480, 443, 429, 432, 443, 490, 429, 432, 442, 443, 432, 431, 442, 423, 439, 455, 423, 421, 439, 425, 490, 438, 425, 429, 490, 456, 431, 428, 456, 442, 431, 438, 421, 425, 438, 439, 421, 497, 499, 498, 497, 500, 499, 414, 415, 500, 497, 478, 500, 478, 414, 500, 415, 480, 500, 492, 494, 491, 492, 493, 494, 496, 491, 494, 496, 453, 491, 453, 496, 452, 501, 503, 502, 501, 504, 503, 505, 507, 506, 505, 508, 507, 506, 510, 509, 506, 507, 510, 509, 504, 501, 509, 510, 504, 511, 506, 512, 511, 505, 506, 513, 502, 514, 513, 501, 502, 515, 501, 513, 515, 509, 501, 512, 509, 515, 512, 506, 509, 516, 518, 517, 516, 519, 518, 519, 520, 518, 519, 521, 520, 521, 522, 520, 521, 523, 522, 524, 514, 525, 524, 513, 514, 523, 526, 522, 523, 527, 526, 528, 513, 524, 528, 515, 513, 527, 529, 526, 527, 530, 529, 531, 515, 528, 531, 512, 515, 532, 512, 531, 532, 511, 512, 533, 517, 534, 533, 516, 517, 518, 536, 535, 518, 520, 536, 520, 537, 536, 520, 522, 537, 522, 538, 537, 522, 526, 538, 526, 539, 538, 526, 529, 539, 534, 541, 540, 534, 517, 541, 517, 535, 541, 517, 518, 535, 538, 543, 542, 538, 539, 543, 536, 545, 544, 536, 537, 545, 535, 544, 546, 535, 536, 544, 541, 546, 547, 541, 535, 546, 537, 542, 545, 537, 538, 542, 540, 547, 548, 540, 541, 547, 540, 508, 505, 540, 548, 508, 502, 543, 539, 502, 503, 543, 534, 505, 511, 534, 540, 505, 514, 539, 529, 514, 502, 539, 533, 511, 532, 533, 534, 511, 525, 529, 530, 525, 514, 529, 549, 192, 550, 549, 191, 192, 551, 553, 552, 551, 554, 553, 198, 555, 200, 198, 552, 555, 556, 558, 557, 556, 559, 558, 552, 560, 555, 552, 553, 560, 550, 206, 561, 550, 192, 206, 553, 557, 560, 553, 556, 557, 559, 561, 558, 559, 550, 561, 561, 208, 562, 561, 206, 208, 563, 565, 564, 563, 566, 565, 555, 568, 567, 555, 560, 568, 558, 562, 569, 558, 561, 562, 217, 570, 220, 217, 571, 570, 572, 223, 573, 572, 222, 223, 560, 574, 568, 560, 557, 574, 557, 569, 574, 557, 558, 569, 566, 573, 575, 566, 572, 573, 563, 572, 566, 200, 567, 227, 200, 555, 567, 570, 229, 230, 570, 576, 229, 573, 231, 232, 573, 223, 231, 576, 234, 229, 576, 577, 234, 575, 232, 235, 575, 573, 232, 220, 230, 236, 220, 570, 230, 577, 235, 234, 577, 575, 235, 578, 568, 574, 578, 579, 568, 567, 579, 571, 567, 568, 579, 571, 227, 567, 571, 217, 227, 572, 569, 562, 572, 563, 569, 562, 222, 572, 562, 208, 222, 574, 563, 578, 574, 569, 563, 571, 579, 570, 570, 579, 580, 570, 580, 576, 581, 583, 582, 584, 245, 585, 584, 244, 245, 247, 586, 250, 247, 587, 586, 588, 253, 589, 588, 252, 253, 590, 592, 591, 590, 582, 592, 258, 593, 261, 258, 594, 593, 595, 589, 596, 595, 588, 589, 582, 597, 592, 582, 583, 597, 581, 585, 583, 581, 584, 585, 583, 598, 597, 583, 585, 598, 594, 591, 593, 594, 590, 591, 596, 600, 599, 596, 589, 600, 601, 599, 602, 601, 596, 599, 250, 603, 271, 250, 586, 603, 589, 272, 600, 589, 253, 272, 588, 597, 598, 588, 595, 597, 587, 261, 593, 587, 247, 261, 591, 592, 604, 593, 605, 587, 593, 591, 605, 598, 252, 588, 598, 275, 252, 592, 595, 606, 592, 597, 595, 585, 275, 598, 585, 245, 275, 271, 607, 278, 271, 603, 607, 575, 609, 608, 575, 577, 609, 566, 608, 565, 566, 575, 608, 578, 564, 610, 578, 563, 564, 577, 611, 609, 577, 576, 611, 579, 610, 612, 579, 578, 610, 606, 595, 613, 613, 595, 601, 601, 595, 596, 587, 605, 586, 586, 605, 614, 586, 614, 615, 586, 616, 603, 586, 615, 616, 615, 617, 616, 616, 617, 601, 616, 601, 602, 606, 619, 618, 606, 613, 619, 605, 621, 620, 605, 604, 621, 604, 618, 621, 604, 606, 618, 604, 605, 591, 592, 606, 604, 508, 622, 507, 508, 623, 622, 504, 624, 503, 504, 625, 624, 510, 625, 504, 510, 626, 625, 507, 626, 510, 507, 622, 626, 546, 628, 627, 546, 544, 628, 544, 629, 628, 544, 545, 629, 545, 630, 629, 545, 542, 630, 542, 631, 630, 542, 543, 631, 548, 633, 632, 548, 547, 633, 547, 627, 633, 547, 546, 627, 305, 306, 634, 308, 309, 635, 636, 638, 637, 548, 623, 508, 548, 632, 623, 503, 631, 543, 503, 624, 631, 314, 639, 317, 314, 640, 639, 317, 641, 319, 317, 639, 641, 635, 643, 642, 635, 644, 643, 634, 323, 645, 634, 306, 323, 644, 645, 643, 644, 634, 645, 308, 642, 325, 308, 635, 642, 646, 647, 305, 648, 650, 649, 648, 649, 646, 646, 634, 644, 644, 648, 646, 648, 644, 635, 646, 305, 634, 309, 651, 635, 651, 648, 635, 638, 649, 650, 637, 638, 650, 554, 556, 553, 554, 652, 556, 653, 550, 559, 653, 549, 550, 334, 552, 198, 334, 551, 552, 652, 559, 556, 652, 653, 559, 580, 612, 654, 580, 579, 612, 336, 594, 258, 336, 655, 594, 655, 590, 594, 655, 656, 590, 656, 582, 590, 656, 581, 582, 603, 657, 607, 603, 616, 657, 599, 659, 658, 599, 600, 659, 616, 660, 657, 616, 602, 660, 602, 658, 660, 602, 599, 658, 600, 343, 659, 600, 272, 343, 615, 662, 661, 615, 614, 662, 576, 654, 611, 576, 580, 654, 617, 661, 663, 617, 615, 661, 601, 663, 664, 601, 617, 663, 613, 664, 619, 613, 601, 664, 614, 620, 662, 614, 605, 620, 665, 319, 641, 665, 348, 319, 665, 666, 348, 665, 667, 666, 665, 668, 667, 665, 353, 668, 651, 353, 665, 309, 353, 651, 669, 671, 670, 669, 672, 671, 670, 674, 673, 670, 671, 674, 669, 675, 672, 669, 676, 675, 640, 673, 674, 362, 673, 640, 362, 640, 314, 676, 637, 675, 676, 677, 637, 637, 677, 636, 636, 677, 678, 365, 305, 677, 678, 677, 647, 647, 677, 305 </int_array>
- </array>
- </dictionary>
- <dictionary name="surfaces/1" shared="false">
- <string> "alphasort" </string>
- <bool> False </bool>
- <string> "material" </string>
- <resource resource_type="Material" path="local://4"> </resource>
- <string> "morph_arrays" </string>
- <array len="0" shared="false">
- </array>
- <string> "primitive" </string>
- <int> 4 </int>
- <string> "arrays" </string>
- <array len="9" shared="false">
- <vector3_array len="625"> 0.23068, 6.41266, 0.879344, 0.754113, 6.74074, 0.551263, 0.754113, 6.81344, 0.551263, 0.23068, 6.48536, 0.879344, 0.845318, 6.86083, 0.103095, 0.845318, 6.93353, 0.103095, 0.754113, 6.74074, -0.345078, 0.754113, 6.81344, -0.345078, 0, 6.36123, 0.969121, 0.257165, 6.36123, 0.969121, 0, 6.41266, 0.879344, 0, 6.36123, -0.762936, 0, 6.41266, -0.673159, 0.23068, 6.41266, -0.673159, 0.257165, 6.36123, -0.762936, 0.23068, 6.48536, -0.673159, 0.2607, 6.45948, -0.774594, 0.852531, 6.83043, -0.403642, 0, 6.48536, -0.673159, 0, 6.48536, 0.879344, 0.955654, 6.96621, 0.103096, 0.852531, 6.83043, 0.609826, 0.2607, 6.45948, 0.980779, 0, 6.45948, -0.774594, 0, 6.45948, 0.980779, 0.144337, 4.62833, -0.267808, 0.227645, 4.56054, -0.149869, 0.230474, 4.54553, -0.1645, 0.145367, 4.61509, -0.285537, 0, 4.66573, -0.327684, 0, 4.65348, -0.346986, 0.16781, 4.49143, -0.0124773, 0.169802, 4.47494, -0.0244043, 2.39441, 2.7167, -0.284614, 2.22321, 2.52508, -0.185319, 2.22875, 2.57563, -0.151192, 2.37464, 2.73891, -0.235805, 0.829811, 0.39491, 0.192334, 0.539954, 0.53255, 0.320534, 0.53677, 0.505704, 0.45924, 0.823707, 0.343455, 0.299719, 0.251731, 0.393841, 0.202075, 0.245627, 0.342385, 0.30946, 2.37016, 3.14596, -0.180206, 2.39069, 3.24439, 0.0703977, 2.51365, 3.10316, 0.122743, 2.49324, 3.00574, -0.125365, 2.02679, 2.71357, 0.205928, 2.02114, 2.64141, -0.071524, 2.14773, 2.50612, -0.0177825, 2.15324, 2.5776, 0.25697, 0.197471, 4.75418, 0.019584, 0.212301, 4.88556, 0.0356146, 0, 4.86123, 0.103096, 0, 4.72999, 0.114516, 2.55604, 3.1449, 0.136694, 2.53359, 3.02984, -0.15501, 2.38915, 3.19439, -0.219368, 2.41174, 3.31063, 0.0752657, 2.13459, 2.5274, 0.293671, 2.28993, 2.80163, 0.457827, 2.27149, 2.82221, 0.391821, 2.44682, 3.07552, 0.376618, 2.41931, 3.04467, 0.327652, 1.98619, 2.68696, 0.233771, 1.97806, 2.60303, -0.0912834, 2.12663, 2.44425, -0.0282163, 2.24859, 2.87814, -0.35026, 2.25039, 2.87648, -0.291744, 2.07568, 2.68462, -0.249978, 2.10304, 2.71157, -0.20629, 2.30152, 3.24052, 0.317542, 2.29549, 3.18528, 0.277312, 2.14291, 2.96404, 0.3995, 2.1462, 2.9606, 0.342119, 1.31621, 3.39795, -0.203802, 1.35829, 3.43387, -0.29479, 1.54119, 3.29007, -0.372791, 1.48496, 3.24915, -0.287145, 0.552121, 0.665123, 0.401021, 0.154027, 0.441809, 0.19622, 0.944465, 0.443271, 0.182901, 0.0964089, 0.00104547, -0.196812, 0.19633, 0.00104547, -0.176104, 0.835003, 0.00104547, -0.205403, 0.736495, 0.00104547, -0.182387, 0.108829, 0.00104547, 0.040049, 0.85902, 0.00104547, 0.0313234, 0.0508581, 0.00104547, 0.0402964, 0.207486, 0.384965, 0.351051, 0.874277, 0.386199, 0.339815, 0.916171, 0.00104547, 0.0302318, 0.543306, 0.573346, 0.523815, 0.158656, 2.88784, -0.132794, 0.242974, 2.8226, -0.0472403, 0.228589, 2.63923, -0.0490058, 0.149215, 2.70638, -0.125392, 0.241672, 4.68094, -0.138747, 0.158365, 4.73746, -0.261278, 0, 4.76911, -0.32375, 0.18264, 4.62281, 0.00355331, 0, 4.46751, 0.137356, 0, 4.44976, 0.12846, 1.6, 5.86123, 0.903096, 1.6, 5.46123, 0.795916, 1.6, 5.42123, 0.865198, 1.6, 5.86123, 0.983096, 1.6, 5.16841, 0.503096, 1.6, 5.09913, 0.543096, 1.6, 5.06123, 0.103096, 1.6, 4.98123, 0.103096, 1.6, 5.46123, -0.589731, 1.6, 5.42123, -0.659013, 1.6, 5.09912, -0.336911, 1.6, 5.16841, -0.296911, 1.6, 5.86123, -0.696911, 1.6, 5.86123, -0.776911, 1.6, 6.26123, -0.589731, 1.6, 6.30123, -0.659013, 1.6, 6.55405, -0.296911, 1.6, 6.62333, -0.336911, 1.15486, 6.36123, 0.969121, 0.685695, 6.36123, 0.969121, 0.765488, 6.24202, 0.864397, 1.07507, 6.24202, 0.864397, 1.2072, 6.11123, 1.03611, 1.10961, 6.07706, 0.908599, 2.0359, 5.66148, 0.449063, 2.0359, 5.51526, 0.30284, 1.90356, 5.8612, 0.10311, 2.0359, 5.46174, 0.103096, 2.0359, 6.20719, 0.30284, 2.0359, 6.06097, 0.449063, 2.0359, 5.51526, -0.0966551, 2.0359, 5.66148, -0.242878, 2.0359, 5.86123, -0.296399, 0, 5.40641, 0.875976, 0, 5.28211, 0.751677, 0.257146, 5.2834, 0.752961, 0.257147, 5.40641, 0.875976, 1.39648, 4.9952, 0.603096, 1.39648, 4.86123, 0.103096, 1.39648, 5.06123, 0.103096, 1.39648, 5.16841, 0.503096, 1.39648, 6.86123, 0.103096, 1.39648, 6.72725, 0.603096, 1.39648, 6.55405, 0.503096, 1.39648, 6.66123, 0.103096, 1.39648, 6.36123, 0.969121, 1.39648, 6.26123, 0.795916, 1.39648, 5.86123, 1.1031, 1.39648, 5.86123, 0.903096, 1.39648, 5.36123, 0.969121, 1.39648, 5.46123, 0.795916, 1.6, 6.66123, 0.103096, 1.6, 6.55405, 0.503096, 1.6, 6.62333, 0.543096, 1.6, 6.74123, 0.103096, 1.6, 6.26123, 0.795916, 1.6, 6.30123, 0.865198, 1.39648, 5.36123, -0.762936, 1.39648, 5.46123, -0.589731, 1.39648, 5.16841, -0.296911, 1.39648, 4.9952, -0.396911, 1.39648, 5.86123, -0.896911, 1.39648, 5.86123, -0.696911, 1.39648, 6.36123, -0.762936, 1.39648, 6.26123, -0.589731, 1.39648, 6.72725, -0.396911, 1.39648, 6.55405, -0.296911, 0.73095, 6.07706, 0.908599, 0.765488, 5.9121, 0.9528, 1.07507, 5.9121, 0.9528, 1.10961, 6.07706, 0.908599, 0.765488, 6.24202, 0.864397, 1.07507, 6.24202, 0.864397, 0.685695, 5.86123, 1.1031, 1.15486, 5.86123, 1.1031, 1.07507, 5.9121, 0.9528, 0.765488, 5.9121, 0.9528, 0.633352, 6.11123, 1.03611, 0.73095, 6.07706, 0.908599, 1.39648, 6.66123, 0.103096, 1.39648, 6.55405, 0.503096, 1.6, 6.55405, 0.503096, 1.6, 6.66123, 0.103096, 1.39648, 6.26123, 0.795916, 1.6, 6.26123, 0.795916, 1.39648, 5.86123, 0.903096, 1.6, 5.86123, 0.903096, 1.39648, 5.46123, 0.795916, 1.6, 5.46123, 0.795916, 1.39648, 5.16841, 0.503096, 1.6, 5.16841, 0.503096, 1.39648, 5.06123, 0.103096, 1.6, 5.06123, 0.103096, 1.39648, 5.46123, -0.589731, 1.6, 5.46123, -0.589731, 1.6, 5.16841, -0.296911, 1.39648, 5.16841, -0.296911, 1.39648, 5.86123, -0.696911, 1.6, 5.86123, -0.696911, 1.39648, 6.26123, -0.589731, 1.6, 6.26123, -0.589731, 1.39648, 6.55405, -0.296911, 1.6, 6.55405, -0.296911, 2.0359, 5.86123, 0.502584, 2.0359, 6.26072, 0.103096, 2.0359, 6.06097, -0.242878, 2.0359, 6.20719, -0.0966551, 0, 5.49634, 0.900073, 0.257147, 5.49634, 0.900073, 0.252264, 4.53307, -0.191655, 0.153299, 4.61636, -0.336561, 0, 4.66231, -0.410127, 0.198102, 4.44663, -0.00271145, 0, 2.66463, 0.20367, 5.00021e-06, 2.4738, 0.177211, 0.102832, 2.48009, 0.176006, 0.109384, 2.67117, 0.201936, 0.251452, 2.74864, 0.0718984, 0.23657, 2.56168, 0.0584772, 0.181152, 2.70508, 0.146183, 0.170392, 2.51572, 0.125662, 0, 2.91839, -0.164227, 5.00021e-06, 2.73725, -0.153025, 1.35355, 3.45169, -0.0607277, 1.50191, 3.29774, -0.132197, 0.413722, 1.77804, 0.182495, 0.302308, 1.69787, 0.09718, 0.311982, 1.54621, 0.0812291, 0.425773, 1.62639, 0.166544, 0.489091, 1.94399, -0.0482645, 0.542593, 1.87364, 0.112398, 0.55748, 1.72198, 0.0964474, 0.506064, 1.79234, -0.0642154, 0.394125, 1.86374, -0.138546, 0.408718, 1.71209, -0.154497, 0.227335, 1.66351, -0.0137039, 0.23599, 1.51185, -0.0296548, 0.0960235, 4.4178, 0.0939296, 1.5172, 3.69575, -0.311084, 1.54768, 3.76732, -0.167808, 1.71449, 3.62366, -0.198996, 1.70474, 3.5573, -0.353999, 1.43134, 3.52144, -0.355117, 1.62434, 3.38222, -0.419987, 1.436, 3.60537, 0.00285106, 1.57608, 3.45117, -0.0476083, 1.51354, 3.73444, -0.0382403, 1.66072, 3.58429, -0.072422, 0.254872, 1.70456, -0.0798497, 0.256767, 1.56023, -0.0958005, 0.288751, 1.77481, -0.152552, 0.300707, 1.62315, -0.168503, 0, 4.41627, 0.145479, 0.841135, 6.72725, 0.603096, 0.841135, 6.72725, -0.396911, 0.942888, 6.86123, 0.103096, -0.23068, 6.41266, 0.879344, -0.23068, 6.48536, 0.879344, -0.754113, 6.81344, 0.551263, -0.754113, 6.74074, 0.551263, -0.845318, 6.93353, 0.103095, -0.845318, 6.86083, 0.103095, -0.754113, 6.74074, -0.345078, -0.754113, 6.81344, -0.345078, -0.257165, 6.36123, 0.969121, -0.257165, 6.36123, -0.762936, -0.23068, 6.41266, -0.673159, -0.23068, 6.48536, -0.673159, -0.852531, 6.83043, -0.403642, -0.2607, 6.45948, -0.774594, -0.852531, 6.83043, 0.609826, -0.955654, 6.96621, 0.103096, -0.2607, 6.45948, 0.980779, -0.144337, 4.62833, -0.267808, -0.145367, 4.61509, -0.285537, -0.230474, 4.54553, -0.1645, -0.227645, 4.56054, -0.149869, -0.169802, 4.47494, -0.0244043, -0.16781, 4.49143, -0.0124773, -2.39441, 2.7167, -0.284614, -2.37464, 2.73891, -0.235805, -2.22875, 2.57563, -0.151192, -2.22321, 2.52508, -0.185319, -0.829811, 0.39491, 0.192334, -0.823707, 0.343455, 0.299719, -0.53677, 0.505704, 0.45924, -0.539954, 0.53255, 0.320534, -0.245627, 0.342385, 0.30946, -0.251731, 0.393841, 0.202075, -2.37016, 3.14596, -0.180206, -2.49324, 3.00574, -0.125365, -2.51365, 3.10316, 0.122743, -2.39069, 3.24439, 0.0703977, -2.02679, 2.71357, 0.205928, -2.15324, 2.5776, 0.25697, -2.14773, 2.50612, -0.0177825, -2.02114, 2.64141, -0.071524, -0.197471, 4.75418, 0.019584, -0.212301, 4.88556, 0.0356146, -2.55604, 3.1449, 0.136694, -2.53359, 3.02984, -0.15501, -2.38915, 3.19439, -0.219368, -2.41174, 3.31063, 0.0752657, -2.13459, 2.5274, 0.293671, -2.27149, 2.82221, 0.391821, -2.28993, 2.80163, 0.457827, -2.44682, 3.07552, 0.376618, -2.41931, 3.04467, 0.327652, -1.98619, 2.68696, 0.233771, -1.97806, 2.60303, -0.0912834, -2.12663, 2.44425, -0.0282163, -2.24859, 2.87814, -0.35026, -2.25039, 2.87648, -0.291744, -2.07568, 2.68462, -0.249978, -2.10304, 2.71157, -0.20629, -2.29549, 3.18528, 0.277312, -2.30152, 3.24052, 0.317542, -2.1462, 2.9606, 0.342119, -2.14291, 2.96404, 0.3995, -1.31621, 3.39795, -0.203802, -1.48496, 3.24915, -0.287145, -1.54119, 3.29007, -0.372791, -1.35829, 3.43387, -0.29479, -0.552121, 0.665123, 0.401021, -0.154027, 0.441809, 0.19622, -0.944465, 0.443271, 0.182901, -0.19633, 0.00104547, -0.176104, -0.0964089, 0.00104547, -0.196812, -0.835003, 0.00104547, -0.205403, -0.736495, 0.00104547, -0.182387, -0.108829, 0.00104547, 0.040049, -0.85902, 0.00104547, 0.0313234, -0.207486, 0.384965, 0.351051, -0.0508581, 0.00104547, 0.0402964, -0.916171, 0.00104547, 0.0302318, -0.874277, 0.386199, 0.339815, -0.543306, 0.573346, 0.523815, -0.158656, 2.88784, -0.132794, -0.149215, 2.70638, -0.125392, -0.228589, 2.63923, -0.0490058, -0.242974, 2.8226, -0.0472403, -0.241672, 4.68094, -0.138747, -0.158365, 4.73746, -0.261278, -0.18264, 4.62281, 0.00355331, -1.6, 5.86123, 0.903096, -1.6, 5.86123, 0.983096, -1.6, 5.42123, 0.865198, -1.6, 5.46123, 0.795916, -1.6, 5.09913, 0.543096, -1.6, 5.16841, 0.503096, -1.6, 4.98123, 0.103096, -1.6, 5.06123, 0.103096, -1.6, 5.46123, -0.589731, -1.6, 5.16841, -0.296911, -1.6, 5.09912, -0.336911, -1.6, 5.42123, -0.659013, -1.6, 5.86123, -0.696911, -1.6, 5.86123, -0.776911, -1.6, 6.26123, -0.589731, -1.6, 6.30123, -0.659013, -1.6, 6.55405, -0.296911, -1.6, 6.62333, -0.336911, -1.15486, 6.36123, 0.969121, -1.07507, 6.24202, 0.864397, -0.765488, 6.24202, 0.864397, -0.685695, 6.36123, 0.969121, -1.2072, 6.11123, 1.03611, -1.10961, 6.07706, 0.908599, -2.0359, 5.66148, 0.449063, -1.90356, 5.8612, 0.10311, -2.0359, 5.51526, 0.30284, -2.0359, 5.46174, 0.103096, -2.0359, 6.20719, 0.30284, -2.0359, 6.06097, 0.449063, -2.0359, 5.51526, -0.0966551, -2.0359, 5.66148, -0.242878, -2.0359, 5.86123, -0.296399, -0.257147, 5.40641, 0.875976, -0.257146, 5.2834, 0.752961, -1.39648, 4.9952, 0.603096, -1.39648, 5.16841, 0.503096, -1.39648, 5.06123, 0.103096, -1.39648, 4.86123, 0.103096, -1.39648, 6.86123, 0.103096, -1.39648, 6.66123, 0.103096, -1.39648, 6.55405, 0.503096, -1.39648, 6.72725, 0.603096, -1.39648, 6.26123, 0.795916, -1.39648, 6.36123, 0.969121, -1.39648, 5.86123, 0.903096, -1.39648, 5.86123, 1.1031, -1.39648, 5.46123, 0.795916, -1.39648, 5.36123, 0.969121, -1.6, 6.66123, 0.103096, -1.6, 6.74123, 0.103096, -1.6, 6.62333, 0.543096, -1.6, 6.55405, 0.503096, -1.6, 6.30123, 0.865198, -1.6, 6.26123, 0.795916, -1.39648, 5.36123, -0.762936, -1.39648, 4.9952, -0.396911, -1.39648, 5.16841, -0.296911, -1.39648, 5.46123, -0.589731, -1.39648, 5.86123, -0.896911, -1.39648, 5.86123, -0.696911, -1.39648, 6.36123, -0.762936, -1.39648, 6.26123, -0.589731, -1.39648, 6.72725, -0.396911, -1.39648, 6.55405, -0.296911, -0.73095, 6.07706, 0.908599, -1.10961, 6.07706, 0.908599, -1.07507, 5.9121, 0.9528, -0.765488, 5.9121, 0.9528, -0.765488, 6.24202, 0.864397, -1.07507, 6.24202, 0.864397, -0.685695, 5.86123, 1.1031, -0.765488, 5.9121, 0.9528, -1.07507, 5.9121, 0.9528, -1.15486, 5.86123, 1.1031, -0.633352, 6.11123, 1.03611, -0.73095, 6.07706, 0.908599, -1.39648, 6.66123, 0.103096, -1.6, 6.66123, 0.103096, -1.6, 6.55405, 0.503096, -1.39648, 6.55405, 0.503096, -1.6, 6.26123, 0.795916, -1.39648, 6.26123, 0.795916, -1.6, 5.86123, 0.903096, -1.39648, 5.86123, 0.903096, -1.6, 5.46123, 0.795916, -1.39648, 5.46123, 0.795916, -1.6, 5.16841, 0.503096, -1.39648, 5.16841, 0.503096, -1.6, 5.06123, 0.103096, -1.39648, 5.06123, 0.103096, -1.39648, 5.46123, -0.589731, -1.39648, 5.16841, -0.296911, -1.6, 5.16841, -0.296911, -1.6, 5.46123, -0.589731, -1.39648, 5.86123, -0.696911, -1.6, 5.86123, -0.696911, -1.39648, 6.26123, -0.589731, -1.6, 6.26123, -0.589731, -1.39648, 6.55405, -0.296911, -1.6, 6.55405, -0.296911, -2.0359, 5.86123, 0.502584, -2.0359, 6.26072, 0.103096, -2.0359, 6.06097, -0.242878, -2.0359, 6.20719, -0.0966551, -0.257147, 5.49634, 0.900073, -0.153299, 4.61636, -0.336561, -0.252264, 4.53307, -0.191655, -0.198102, 4.44663, -0.00271145, -0.109384, 2.67117, 0.201936, -0.102832, 2.48009, 0.176006, -0.251452, 2.74864, 0.0718984, -0.23657, 2.56168, 0.0584772, -0.181152, 2.70508, 0.146183, -0.170392, 2.51572, 0.125662, -1.35355, 3.45169, -0.0607277, -1.50191, 3.29774, -0.132197, -0.413722, 1.77804, 0.182495, -0.425773, 1.62639, 0.166544, -0.311982, 1.54621, 0.0812291, -0.302308, 1.69787, 0.09718, -0.489091, 1.94399, -0.0482645, -0.506064, 1.79234, -0.0642154, -0.55748, 1.72198, 0.0964474, -0.542593, 1.87364, 0.112398, -0.394125, 1.86374, -0.138546, -0.408718, 1.71209, -0.154497, -0.23599, 1.51185, -0.0296548, -0.227335, 1.66351, -0.0137039, -0.0960235, 4.4178, 0.0939296, -1.5172, 3.69575, -0.311084, -1.70474, 3.5573, -0.353999, -1.71449, 3.62366, -0.198996, -1.54768, 3.76732, -0.167808, -1.62434, 3.38222, -0.419987, -1.43134, 3.52144, -0.355117, -1.436, 3.60537, 0.00285106, -1.57608, 3.45117, -0.0476083, -1.66072, 3.58429, -0.072422, -1.51354, 3.73444, -0.0382403, -0.256767, 1.56023, -0.0958005, -0.254872, 1.70456, -0.0798497, -0.288751, 1.77481, -0.152552, -0.300707, 1.62315, -0.168503, -0.841135, 6.72725, 0.603096, -0.841135, 6.72725, -0.396911, -0.942888, 6.86123, 0.103096, 0.177538, 3.25078, -0.147598, 0.271744, 3.18932, -0.0437093, 0.257359, 3.00596, -0.0454748, 0.168097, 3.06931, -0.140196, 0, 3.04628, 0.256587, 0, 2.85545, 0.230128, 0.115936, 2.86226, 0.227866, 0.122488, 3.05335, 0.253795, 0.281216, 3.12258, 0.0987407, 0.266334, 2.93561, 0.0853195, 0.202672, 3.0838, 0.187225, 0.191912, 2.89444, 0.166704, 0, 3.28068, -0.186631, 0, 3.09954, -0.175429, -0.177538, 3.25078, -0.147598, -0.168097, 3.06931, -0.140196, -0.257359, 3.00596, -0.0454748, -0.271744, 3.18932, -0.0437093, -0.122488, 3.05335, 0.253795, -0.115936, 2.86226, 0.227866, -0.281216, 3.12258, 0.0987407, -0.266334, 2.93561, 0.0853195, -0.202672, 3.0838, 0.187225, -0.191912, 2.89444, 0.166704, 0, 4.59875, 0.125936, 0.269727, 4.92174, -0.116503, 0.2557, 4.80134, -0.127625, 0.172392, 4.8466, -0.254748, 0.18642, 4.95573, -0.248219, 0, 4.87249, -0.319817, 0, 4.97587, -0.315884, -0.269727, 4.92174, -0.116503, -0.18642, 4.95573, -0.248219, -0.172392, 4.8466, -0.254748, -0.2557, 4.80134, -0.127625, -0.809978, 3.84435, 0.0462258, -0.978723, 3.69555, -0.0371168, -0.992485, 3.72148, -0.13879, -0.809584, 3.86528, -0.0607897, -1.14747, 3.54675, -0.120459, -1.17539, 3.57767, -0.21679, -0.908494, 3.91354, 0.153681, -1.05685, 3.75959, 0.0822117, -1.2052, 3.60564, 0.010742, -0.954611, 4.1111, -0.182336, -1.14214, 3.97265, -0.225252, -1.21405, 4.05463, -0.105431, -1.04723, 4.19828, -0.0742428, -1.32967, 3.8342, -0.268168, -1.38086, 3.91097, -0.136619, -1.04535, 3.79989, -0.225379, -0.85235, 3.93911, -0.160509, -1.23834, 3.66066, -0.290248, -1.01577, 4.06798, 0.154229, -1.15585, 3.91378, 0.10377, -1.29593, 3.75958, 0.0533104, -1.21917, 4.03474, 0.0301233, -1.07199, 4.18489, 0.0643051, -1.36635, 3.88459, -0.00405846, 0.809978, 3.84435, 0.0462258, 0.809584, 3.86528, -0.0607897, 0.992485, 3.72148, -0.13879, 0.978723, 3.69555, -0.0371168, 1.17539, 3.57767, -0.21679, 1.14747, 3.54675, -0.120459, 0.908494, 3.91354, 0.153681, 1.05685, 3.75959, 0.0822117, 1.2052, 3.60564, 0.010742, 0.954611, 4.1111, -0.182336, 1.04723, 4.19828, -0.0742428, 1.21405, 4.05463, -0.105431, 1.14214, 3.97265, -0.225252, 1.38086, 3.91097, -0.136619, 1.32967, 3.8342, -0.268168, 0.85235, 3.93911, -0.160509, 1.04535, 3.79989, -0.225379, 1.23834, 3.66066, -0.290248, 1.01577, 4.06798, 0.154229, 1.15585, 3.91378, 0.10377, 1.29593, 3.75958, 0.0533104, 1.07199, 4.18489, 0.0643051, 1.21917, 4.03474, 0.0301233, 1.36635, 3.88459, -0.00405846, 0.377566, 2.23301, 0.230347, 0.273286, 2.15284, 0.145033, 0.28296, 2.00118, 0.129082, 0.389618, 2.08136, 0.214396, 0.292634, 1.84952, 0.113131, 0.40167, 1.9297, 0.198445, 0.438171, 2.39896, -0.000411894, 0.497933, 2.32861, 0.160251, 0.51282, 2.17695, 0.1443, 0.455144, 2.24731, -0.0163628, 0.527707, 2.02529, 0.128349, 0.472118, 2.09565, -0.0323137, 0.350345, 2.31871, -0.0906937, 0.364938, 2.16706, -0.106645, 0.379531, 2.0154, -0.122595, 0.20137, 2.11848, 0.0341487, 0.210025, 1.96682, 0.0181978, 0.21868, 1.81516, 0.00224695, 0.249187, 2.13753, -0.031997, 0.251082, 1.9932, -0.0479479, 0.252977, 1.84888, -0.0638988, 0.252884, 2.22978, -0.1047, 0.26484, 2.07812, -0.12065, 0.276796, 1.92646, -0.136601, -0.377566, 2.23301, 0.230347, -0.389618, 2.08136, 0.214396, -0.28296, 2.00118, 0.129082, -0.273286, 2.15284, 0.145033, -0.40167, 1.9297, 0.198445, -0.292634, 1.84952, 0.113131, -0.438171, 2.39896, -0.000411894, -0.455144, 2.24731, -0.0163628, -0.51282, 2.17695, 0.1443, -0.497933, 2.32861, 0.160251, -0.472118, 2.09565, -0.0323137, -0.527707, 2.02529, 0.128349, -0.350345, 2.31871, -0.0906937, -0.364938, 2.16706, -0.106645, -0.379531, 2.0154, -0.122595, -0.210025, 1.96682, 0.0181978, -0.20137, 2.11848, 0.0341487, -0.21868, 1.81516, 0.00224695, -0.251082, 1.9932, -0.0479479, -0.249187, 2.13753, -0.031997, -0.252977, 1.84888, -0.0638988, -0.252884, 2.22978, -0.1047, -0.26484, 2.07812, -0.12065, -0.276796, 1.92646, -0.136601 </vector3_array>
- <vector3_array len="625"> 0.0360096, 0.589157, 0.807216, 0.379162, 0.648277, 0.660282, 0.710781, -0.701771, 0.0480528, 0.391591, -0.775171, 0.495749, 0.722924, 0.690928, -0, 0.722446, -0.691427, 0, 0.378912, 0.647849, -0.660846, 0.710746, -0.701737, -0.0490515, 0, 0.610678, 0.791879, -0.0350367, 0.578606, 0.814854, 0, 0.501628, 0.865083, 0, 0.610194, -0.792252, 0, 0.501194, -0.865335, 0.0359806, 0.588682, -0.807564, -0.0350082, 0.578135, -0.81519, 0.391397, -0.774786, -0.496503, 0.323297, -0.752692, -0.573527, 0.770859, -0.534596, -0.346386, 0, -0.789191, -0.614148, 0, -0.789675, 0.613525, 0.868674, -0.495384, 0, 0.771126, -0.534781, 0.345505, 0.323483, -0.753124, 0.572855, 0, -0.789191, -0.614148, 0, -0.789675, 0.613525, 0.705688, 0.318859, -0.63272, 0.999838, 0.00999838, 0.0149976, 0.799697, 0.565786, 0.200924, 0.540954, 0.82793, -0.147987, 0, 0.473026, -0.881048, 0, 0.986122, -0.166021, 0.790431, -0.193105, 0.581317, 0.744403, 0.310168, 0.59132, -0.210106, 0.16008, -0.964484, -0.609658, -0.17619, -0.772835, -0.695748, -0.0600646, -0.71577, -0.418461, 0.236261, -0.876967, 0.72763, -0.205178, 0.654566, 0.0120115, 0.213204, 0.976934, -0.0129987, 0.889909, -0.455953, 0.408168, 0.754311, -0.514212, -0.717691, -0.0310299, 0.69567, -0.403281, 0.782544, -0.47433, 0.962114, -0.068008, -0.264031, 0.98219, 0.109021, 0.15303, -0.0740053, 0.995071, -0.0660047, -0.0730215, 0.709209, -0.701207, 0.120177, -0.831221, 0.542797, 0.130096, -0.988732, -0.0740548, -0.9642, -0.11214, -0.240299, -0.953245, 0.0220288, 0.301394, 0.741648, -0.0980857, 0.66358, 0.557506, -0.667605, 0.493448, 0, -0.762778, 0.64666, 0, -0.0440454, 0.99903, 0.0889861, 0.993844, -0.0659897, 0.0490036, 0.723054, -0.689051, 0.897953, 0.117994, -0.423978, 0.920375, 0.351143, 0.17207, -0.901333, -0.16224, 0.401594, -0.618771, 0.285356, 0.731912, -0.721733, 0.300305, 0.623633, -0.242219, 0.80573, 0.54049, -0.400552, 0.758045, 0.514709, -0.0350519, -0.808196, 0.58787, -0.0460378, -0.996819, -0.0650535, -0.891041, -0.346405, -0.293343, 0.6294, -0.428272, -0.648412, 0.728593, -0.433353, -0.530432, 0.267172, -0.820528, -0.505325, 0.35736, -0.806813, -0.470474, 0.622553, 0.221196, 0.750666, 0.819836, -0.00400408, 0.572584, 0.297403, -0.309419, 0.903223, 0.487706, -0.344499, 0.802162, -0.679917, -0.730986, -0.0580783, -0.592431, -0.368268, -0.716522, -0.511638, -0.289361, -0.809009, -0.812045, -0.505651, -0.291375, -0.00700771, -0.117129, 0.993092, -0.674119, -0.252419, 0.694153, 0.797008, -0.304385, 0.521659, -0.753305, -0.654134, 0.0681181, -0.216317, -0.957402, 0.19128, 0.713493, -0.691478, -0.113078, 0.194204, -0.972021, 0.132139, -0.686439, 0.302193, -0.661423, 0.711943, 0.135989, -0.688945, -0.702756, -0.294317, -0.647697, -0.616626, 0.733745, -0.28529, 0.714816, 0.636836, -0.288926, 0.64207, -0.336037, -0.689075, 0.0110026, 0.996233, -0.0860201, 0.456853, -0.0569817, -0.887715, 0.891957, -0.0679967, -0.446978, 0.947519, 0.264145, -0.180099, 0.609974, 0.430981, -0.664971, 0.983744, -0.109971, -0.141963, 0.618615, -0.0169894, -0.785511, 0, 0.0229939, -0.999736, 0.785814, -0.0981016, 0.610633, 0, -0.271413, 0.962463, 0, 0.126129, 0.992014, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -0.167145, 0.336293, 0.926806, 0.168118, 0.336236, 0.926651, 0.327528, -0.185299, 0.926493, -0.326633, -0.185359, 0.926797, -0.401672, 0.237397, 0.884479, -0.493594, 0.225271, 0.840011, 0.984527, -0.0870466, 0.152081, 0.984527, -0.152081, 0.0870466, 1, 0, -0, 0.984551, -0.175098, 0, 0.984377, 0.153059, 0.0870333, 0.984441, 0.0880395, 0.152068, 0.984441, -0.152068, -0.0880395, 0.984377, -0.0870333, -0.153059, 0.984378, 0, -0.176068, 0, -0.499694, 0.866202, 0, -0.0770792, 0.997025, -0.353503, -0.137195, 0.925318, -0.4965, -0.437441, 0.749755, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 0, 0.25922, 0.965818, 0, 0.25922, 0.965818, 0, 0.25922, 0.965818, 0, 0.25922, 0.965818, 0, 0.25922, 0.965818, 0, 0.25922, 0.965818, 0.168109, 0.172111, 0.970627, -0.167136, 0.17214, 0.97079, -0.326504, 0.624964, 0.709094, 0.327398, 0.62476, 0.708862, 0.402511, 0.237301, 0.884123, 0.494351, 0.22516, 0.839595, 0.770022, 0.638018, -0, 0.77049, 0.552351, 0.318202, -0.770083, 0.552777, 0.318448, -0.769614, 0.638509, 0, 0.77067, 0.319278, 0.551479, -0.770263, 0.319524, 0.551905, 0.770513, 0, 0.637424, -0.770106, 0, 0.637916, 0.770916, -0.318378, 0.551655, -0.770509, -0.318624, 0.552081, 0.770916, -0.551655, 0.318378, -0.770509, -0.552081, 0.318624, 0.770513, -0.637424, 0, -0.770106, -0.637916, 0, 0.77049, -0.318202, -0.552351, -0.770083, -0.318448, -0.552777, -0.770263, -0.551905, -0.319524, 0.77067, -0.551479, -0.319278, 0.770022, 0, -0.638018, -0.769614, 0, -0.638509, 0.770245, 0.319101, -0.552175, -0.769837, 0.319347, -0.552601, 0.770245, 0.552175, -0.319101, -0.769837, 0.552601, -0.319347, 0.984551, 0, 0.175098, 0.984378, 0.176068, -0, 0.984291, 0.088026, -0.153045, 0.984291, 0.153045, -0.088026, 0, -0.848897, 0.528558, -0.359502, -0.75906, 0.542758, 0.269002, 0.885006, 0.380003, 0.175995, 0.932972, 0.31399, 0, 0.941447, 0.33716, 0.24712, 0.836407, 0.489238, 0, -0.135113, 0.99083, 0, 0.0700382, 0.997544, 0.320359, 0.0650729, 0.945059, 0.353552, -0.136213, 0.925444, 0.952453, -0.0990471, 0.288137, 0.880048, 0.129007, 0.457025, 0.701409, -0.115067, 0.70341, 0.644507, 0.0390307, 0.763601, 0, -0.0550267, -0.998485, 0, 0.542878, -0.839811, -0.285466, -0.616005, 0.734198, -0.764085, -0.38755, 0.515732, -0.0240167, -0.100069, 0.994691, -0.686889, -0.119154, 0.716928, -0.74958, 0.0670519, 0.658509, -0.318438, 0.223307, 0.921266, 0.825985, 0.143997, -0.54499, 0.923944, 0.0519969, 0.378977, 0.455352, 0.602466, 0.655507, 0.565223, 0.681269, -0.465184, 0.342959, 0.132984, -0.929889, -0.0789773, 0.541844, -0.83676, -0.991178, -0.058069, 0.119142, -0.969378, 0.150213, 0.194276, 0.245128, 0.817427, 0.521272, 0.232988, 0.56297, -0.792958, 0.642155, 0.763184, -0.0720174, 0.308094, 0.942288, -0.13104, 0.167052, 0.584181, -0.794246, -0.281137, 0.0480233, -0.958465, -0.160029, 0.076014, -0.984181, 0.184197, -0.152163, 0.97104, -0.409744, 0.0530964, 0.910654, 0.581446, 0.410315, 0.702539, 0.0380266, 0.718502, 0.694485, -0.910035, 0.00700797, -0.414472, -0.943047, 0.164182, -0.289321, -0.529471, 0.0660587, -0.845752, -0.728454, 0.359224, -0.583363, 0, 0.768221, 0.640184, -0.0380063, 0.865143, 0.500083, -0.0379873, 0.86471, -0.500832, -0.001, 1, 0, -0.0350106, 0.589178, 0.807244, -0.390743, -0.775474, 0.495943, -0.710285, -0.70227, 0.048087, -0.378305, 0.648523, 0.660533, -0.721967, -0.691927, 0, -0.722446, 0.691427, 0, -0.378055, 0.648094, -0.661096, -0.71025, -0.702236, -0.0490864, 0.0360365, 0.578586, 0.814825, 0.0360071, 0.578114, -0.815161, -0.0349823, 0.588703, -0.807592, -0.390549, -0.775089, -0.496698, -0.770452, -0.535009, -0.346654, -0.322401, -0.752935, -0.573713, -0.77072, -0.535194, 0.345772, -0.868428, -0.495815, 0, -0.322586, -0.753368, 0.57304, -0.705185, 0.319084, -0.633166, -0.540246, 0.828378, -0.148068, -0.799337, 0.566238, 0.201085, -0.999837, 0.0100084, 0.0150126, -0.743957, 0.310399, 0.591761, -0.790055, -0.193258, 0.581777, 0.211062, 0.160047, -0.964281, 0.419287, 0.236161, -0.876599, 0.696264, -0.0600228, -0.715271, 0.610287, -0.176083, -0.772363, -0.727158, -0.205327, 0.655043, -0.407334, 0.754619, -0.514422, 0.0139984, 0.889897, -0.455947, -0.0110107, 0.213206, 0.976945, 0.404118, 0.782228, -0.474138, 0.718176, -0.0310076, 0.69517, -0.962039, -0.0680735, -0.264285, 0.0740164, 0.709157, -0.701155, 0.0749998, 0.994997, -0.0659998, -0.982154, 0.109128, 0.15318, -0.119189, -0.831321, 0.542862, 0.953337, 0.0220078, 0.301106, 0.96427, -0.112031, -0.240067, -0.129112, -0.98886, -0.0740644, -0.741197, -0.0981585, 0.664072, -0.556815, -0.667978, 0.493723, -0.087994, 0.993932, -0.0659955, -0.0480059, 0.723089, -0.689085, -0.897759, 0.1181, -0.424359, -0.920222, 0.351467, 0.172229, 0.90152, -0.162094, 0.401232, 0.722212, 0.300088, 0.623183, 0.619388, 0.285179, 0.731458, 0.243161, 0.805534, 0.540358, 0.401392, 0.757741, 0.514503, 0.0360521, -0.808167, 0.587849, 0.0470365, -0.996773, -0.0650504, 0.891247, -0.346096, -0.293081, -0.628795, -0.428542, -0.648821, -0.728123, -0.433669, -0.530819, -0.266242, -0.820747, -0.50546, -0.356487, -0.807102, -0.470642, -0.819508, -0.00400737, 0.573054, -0.621939, 0.221334, 0.751134, -0.486942, -0.344667, 0.802553, -0.296489, -0.309511, 0.903492, 0.680455, -0.730488, -0.0580388, 0.812386, -0.50524, -0.291138, 0.512377, -0.289213, -0.808595, 0.59308, -0.36805, -0.716097, 0.00800875, -0.117128, 0.993085, 0.674665, -0.252249, 0.693684, -0.796642, -0.304628, 0.522076, 0.217271, -0.957194, 0.191239, 0.753738, -0.65364, 0.0680667, -0.713001, -0.691972, -0.113159, -0.19324, -0.972209, 0.132164, 0.686968, 0.301986, -0.660969, -0.711449, 0.136086, -0.689435, 0.617246, 0.733292, -0.285114, 0.703262, -0.29411, -0.647241, -0.641482, -0.336253, -0.689518, -0.714327, 0.637291, -0.289132, -0.0100024, 0.996243, -0.086021, -0.456062, -0.0570077, -0.88812, -0.609345, 0.431244, -0.665377, -0.947416, 0.264395, -0.18027, -0.891752, -0.0680574, -0.447377, -0.983712, -0.11008, -0.142103, -0.617997, -0.0169999, -0.785996, -0.785431, -0.0981788, 0.611113, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 0.168118, 0.336236, 0.926651, 0.327528, -0.185299, 0.926493, -0.326633, -0.185359, 0.926797, -0.167145, 0.336293, 0.926806, 0.402511, 0.237301, 0.884123, 0.494351, 0.22516, 0.839595, -0.984497, -0.0871325, 0.152231, -1, 0, 0, -0.984497, -0.152231, 0.0871325, -0.98452, -0.175271, 0, -0.984346, 0.15321, 0.0871191, -0.98441, 0.0881262, 0.152218, -0.98441, -0.152218, -0.0881262, -0.984346, -0.0871191, -0.15321, -0.984347, 0, -0.176241, 0.497254, -0.437223, 0.749383, 0.354379, -0.137147, 0.92499, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, 0.25922, 0.965818, 0, 0.25922, 0.965818, 0, 0.25922, 0.965818, 0, 0.25922, 0.965818, 0, 0.25922, 0.965818, 0, 0.25922, 0.965818, -0.167136, 0.17214, 0.97079, -0.326504, 0.624964, 0.709094, 0.327398, 0.62476, 0.708862, 0.168109, 0.172111, 0.970627, -0.401672, 0.237397, 0.884479, -0.493594, 0.225271, 0.840011, -0.769614, 0.638509, 0, 0.770022, 0.638018, -0, 0.77049, 0.552351, 0.318202, -0.770083, 0.552777, 0.318448, 0.77067, 0.319278, 0.551479, -0.770263, 0.319524, 0.551905, 0.770513, 0, 0.637424, -0.770106, 0, 0.637916, 0.770916, -0.318378, 0.551655, -0.770509, -0.318624, 0.552081, 0.770916, -0.551655, 0.318378, -0.770509, -0.552081, 0.318624, 0.770513, -0.637424, 0, -0.770106, -0.637916, 0, -0.770083, -0.318448, -0.552777, -0.770263, -0.551905, -0.319524, 0.77067, -0.551479, -0.319278, 0.77049, -0.318202, -0.552351, -0.769614, 0, -0.638509, 0.770022, 0, -0.638018, -0.769837, 0.319347, -0.552601, 0.770245, 0.319101, -0.552175, -0.769837, 0.552601, -0.319347, 0.770245, 0.552175, -0.319101, -0.98452, 0, 0.175271, -0.984347, 0.176241, 0, -0.98426, 0.0881128, -0.153196, -0.98426, 0.153196, -0.0881128, 0.360374, -0.758786, 0.542562, -0.175025, 0.933135, 0.314046, -0.268074, 0.885244, 0.380105, -0.246181, 0.836614, 0.489359, -0.352675, -0.136261, 0.925772, -0.31946, 0.0650937, 0.945361, -0.95236, -0.0991416, 0.288412, -0.879823, 0.129121, 0.457428, -0.7009, -0.115148, 0.703904, -0.643922, 0.0390559, 0.764094, 0.286385, -0.615829, 0.733988, 0.764501, -0.387254, 0.515338, 0.0250168, -0.100067, 0.994666, 0.319337, 0.223236, 0.920972, 0.750018, 0.0670016, 0.658015, 0.687417, -0.119072, 0.716435, -0.825667, 0.144116, -0.54544, -0.564542, 0.681654, -0.465447, -0.454558, 0.60274, 0.655806, -0.923798, 0.0520449, 0.379327, -0.342076, 0.13303, -0.930208, 0.0799707, 0.541802, -0.836693, 0.969438, 0.150068, 0.194088, 0.991195, -0.0580114, 0.119023, -0.244187, 0.817627, 0.5214, -0.232042, 0.563101, -0.793142, -0.166079, 0.584278, -0.794378, -0.307188, 0.942578, -0.13108, -0.641567, 0.763675, -0.0720637, 0.161004, 0.0760018, -0.984023, 0.282058, 0.0480098, -0.958196, -0.18323, -0.152191, 0.971218, 0.410577, 0.0530746, 0.91028, -0.0370272, 0.718529, 0.694511, -0.580783, 0.410554, 0.702948, 0.943158, 0.164027, -0.289048, 0.910207, 0.00700159, -0.414094, 0.530191, 0.0660237, -0.845304, 0.728923, 0.358962, -0.582938, 0.039005, 0.86511, 0.500063, 0.0389854, 0.864677, -0.500813, 0.002, 0.999998, -0, 0.307062, -0.405082, -0.861174, 0.644374, -0.493286, -0.584339, 0.899636, -0.0680481, -0.431305, 0.473063, -0.0580077, -0.879117, 0, -0.746027, 0.665916, 0, -0.135113, 0.99083, 0.361199, -0.136075, 0.922507, 0.355385, -0.786851, 0.504546, 0.758512, -0.647437, -0.07405, 0.952727, -0.0990756, 0.287219, 0.641692, -0.681736, 0.351379, 0.709379, -0.115062, 0.695372, 0, -0.36621, -0.930532, 0, -0.0550267, -0.998485, -0.306156, -0.405206, -0.861439, -0.472286, -0.0580352, -0.879533, -0.899445, -0.0681094, -0.431694, -0.643788, -0.493604, -0.584716, -0.354509, -0.787131, 0.504725, -0.360328, -0.136124, 0.92284, -0.758087, -0.647929, -0.0741063, -0.952635, -0.0991702, 0.287493, -0.641103, -0.682174, 0.351605, -0.708882, -0.115143, 0.695866, 0, -0.0550817, 0.998482, 0.721736, -0.682696, -0.114116, 0.984884, -0.110987, -0.132984, 0.620192, -0.0180056, -0.784243, 0.463983, -0.666975, -0.582978, 0, 0.0239931, -0.999712, 0, -0.812786, -0.582563, -0.721256, -0.68319, -0.114199, -0.463198, -0.667285, -0.583249, -0.619576, -0.0180168, -0.78473, -0.984854, -0.111096, -0.133115, -0.712291, -0.694258, -0.103187, 0.595443, -0.778579, 0.198147, 0.653726, -0.55762, -0.511568, -0.639939, -0.7491, -0.171251, 0.643677, -0.761801, 0.0730768, 0.630288, -0.468214, -0.619283, -0.730652, -0.680607, -0.0540482, 0.116169, -0.506735, 0.854239, 0.201265, -0.563742, 0.801054, -0.905093, -0.411497, -0.107129, -0.0970155, 0.416066, -0.904144, -0.581217, 0.747279, -0.32212, -0.864338, -0.499774, -0.0560868, -0.164974, 0.491923, -0.854866, -0.616439, 0.761542, -0.200142, 0.407071, -0.149026, -0.901157, -0.759004, -0.614813, -0.214283, 0.347173, -0.0500249, -0.936466, -0.848814, -0.528507, -0.0140134, -0.344309, 0.00500449, 0.938843, -0.266308, -0.0730846, 0.961113, -0.669545, 0.542441, 0.507413, -0.833134, -0.540736, -0.116158, -0.62997, 0.48074, 0.609939, 0.712784, -0.693763, -0.103113, 0.64053, -0.74862, -0.171142, -0.653152, -0.557985, -0.511903, -0.594796, -0.779043, 0.198265, -0.629685, -0.46851, -0.619674, -0.64309, -0.762292, 0.0731239, 0.731118, -0.68011, -0.0540087, -0.11518, -0.506794, 0.854338, -0.200304, -0.563855, 0.801215, 0.905274, -0.411124, -0.107032, 0.864591, -0.499341, -0.0560383, 0.581879, 0.746844, -0.321933, 0.0980061, 0.416026, -0.904056, 0.617059, 0.761072, -0.200019, 0.165946, 0.491841, -0.854724, 0.759428, -0.614346, -0.214121, -0.406236, -0.149087, -0.901524, -0.346292, -0.0500423, -0.936791, 0.849093, -0.528058, -0.0140015, 0.345191, 0.00500277, 0.938519, 0.267238, -0.0730651, 0.960857, 0.83344, -0.540285, -0.116061, 0.670096, 0.542078, 0.507073, 0.630574, 0.480437, 0.609555, 0.652602, -0.667616, 0.35833, 0.272405, -0.803194, 0.529788, -0.69805, -0.119179, 0.706062, -0.0250168, -0.100067, 0.994666, -0.692476, -0.119254, 0.711516, -0.0250168, -0.100067, 0.994666, 0.794806, -0.441448, -0.416422, 0.800238, -0.563168, -0.206061, 0.931286, 0.0550169, 0.360111, 0.825985, 0.143997, -0.54499, 0.927789, 0.0530451, 0.369314, 0.825985, 0.143997, -0.54499, 0.823173, -0.419088, -0.383081, 0.35507, 0.134026, -0.925182, 0.348836, 0.133937, -0.927564, 0.241336, -0.969348, -0.0460641, -0.998282, -0.049063, 0.0320411, -0.995768, -0.0530409, 0.0750579, -0.256367, -0.749072, -0.610874, -0.92242, 0.00300137, -0.386176, -0.915525, 0.00500287, -0.402231, 0.679395, -0.526306, -0.511297, -0.621461, 0.0540401, -0.781579, -0.575446, 0.0600465, -0.815632, -0.652026, -0.668052, 0.358564, 0.0260168, -0.100064, 0.994641, 0.698563, -0.119096, 0.705568, -0.271477, -0.803413, 0.529932, 0.0260168, -0.100064, 0.994641, 0.692997, -0.119171, 0.711023, -0.794437, -0.441799, -0.416754, -0.825667, 0.144116, -0.54544, -0.931153, 0.0550682, 0.360446, -0.799878, -0.563619, -0.206226, -0.825667, 0.144116, -0.54544, -0.92765, 0.0530944, 0.369657, -0.82285, -0.419434, -0.383396, -0.354195, 0.134074, -0.925511, -0.347958, 0.133984, -0.927887, 0.998285, -0.049014, 0.0320091, -0.240392, -0.969582, -0.0460752, 0.995776, -0.0529881, 0.0749831, 0.922569, 0.0029986, -0.38582, 0.257302, -0.748879, -0.610717, 0.915686, 0.00499829, -0.401862, -0.678856, -0.526664, -0.511645, 0.622074, 0.0540065, -0.781093, 0.576115, 0.060012, -0.815163 </vector3_array>
- <nil> </nil>
- <nil> </nil>
- <nil> </nil>
- <nil> </nil>
- <real_array len="2500"> 6, 7, 0, 0, 6, 7, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 6, 7, 0, 0, 7, 0, 0, 0, 7, 6, 0, 0, 7, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 7, 0, 0, 6, 7, 0, 0, 6, 7, 0, 0, 6, 7, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 13, 0, 0, 0, 14, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 6, 3, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 3, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 8, 9, 3, 0, 8, 9, 3, 0, 8, 9, 0, 0, 8, 9, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 1, 3, 0, 0, 1, 3, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 3, 6, 0, 0, 3, 6, 0, 0, 3, 6, 0, 0, 3, 6, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 1, 3, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 3, 0, 0, 1, 3, 0, 0, 1, 0, 0, 0, 1, 3, 0, 0, 1, 0, 0, 0, 1, 3, 0, 0, 1, 0, 0, 0, 8, 9, 3, 0, 8, 9, 0, 0, 12, 13, 1, 0, 12, 13, 1, 0, 12, 13, 0, 0, 12, 13, 0, 0, 12, 13, 1, 0, 12, 13, 1, 0, 12, 13, 0, 0, 12, 13, 0, 0, 12, 13, 1, 0, 12, 13, 0, 0, 12, 13, 1, 0, 12, 13, 0, 0, 3, 0, 0, 0, 8, 9, 3, 0, 8, 9, 3, 0, 8, 9, 0, 0, 9, 8, 0, 0, 9, 8, 3, 0, 9, 8, 0, 0, 9, 8, 3, 0, 9, 8, 0, 0, 8, 9, 3, 0, 8, 9, 0, 0, 12, 13, 1, 0, 12, 13, 0, 0, 12, 13, 1, 0, 12, 13, 0, 0, 3, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 7, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 6, 7, 0, 0, 7, 0, 0, 0, 6, 7, 0, 0, 7, 6, 0, 0, 7, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 7, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 16, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 16, 0, 0, 0, 17, 0, 0, 0, 16, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 6, 3, 0, 0, 6, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 10, 11, 3, 0, 10, 11, 0, 0, 10, 11, 0, 0, 10, 11, 3, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 1, 3, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 3, 0, 0, 3, 6, 0, 0, 3, 6, 0, 0, 3, 6, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 1, 3, 0, 0, 1, 0, 0, 0, 1, 3, 0, 0, 1, 0, 0, 0, 1, 3, 0, 0, 1, 0, 0, 0, 10, 11, 3, 0, 10, 11, 0, 0, 15, 16, 1, 0, 15, 16, 0, 0, 15, 16, 0, 0, 15, 16, 1, 0, 15, 16, 1, 0, 15, 16, 0, 0, 15, 16, 0, 0, 15, 16, 1, 0, 15, 16, 1, 0, 15, 16, 0, 0, 15, 16, 0, 0, 15, 16, 1, 0, 3, 0, 0, 0, 10, 11, 3, 0, 11, 10, 0, 0, 10, 11, 0, 0, 10, 11, 3, 0, 11, 10, 0, 0, 11, 10, 3, 0, 11, 10, 3, 0, 11, 10, 0, 0, 10, 11, 0, 0, 10, 11, 3, 0, 15, 16, 0, 0, 15, 16, 1, 0, 15, 16, 1, 0, 15, 16, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 1, 0, 0, 3, 1, 0, 0, 3, 0, 0, 0, 3, 1, 0, 0, 3, 1, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 1, 0, 0, 3, 0, 0, 0, 3, 1, 0, 0, 3, 0, 0, 0, 3, 1, 0, 0, 3, 0, 0, 0, 3, 1, 0, 0, 3, 1, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 1, 0, 0, 3, 0, 0, 0, 3, 1, 0, 0, 3, 0, 0, 0, 3, 1, 0, 0, 3, 6, 0, 0, 6, 0, 0, 0, 6, 3, 0, 0, 6, 3, 0, 0, 6, 0, 0, 0, 6, 3, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 3, 0, 0, 6, 3, 0, 0, 3, 0, 0, 0, 3, 10, 11, 0, 3, 10, 11, 0, 3, 0, 0, 0, 3, 10, 11, 0, 3, 10, 11, 0, 3, 0, 0, 0, 3, 10, 11, 0, 3, 10, 11, 0, 3, 0, 0, 0, 3, 10, 11, 0, 3, 10, 11, 0, 3, 0, 0, 0, 3, 11, 10, 0, 3, 10, 11, 0, 3, 11, 10, 0, 3, 0, 0, 0, 3, 11, 10, 0, 3, 0, 0, 0, 3, 11, 10, 0, 3, 11, 10, 0, 3, 10, 11, 0, 3, 0, 0, 0, 3, 10, 11, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 8, 9, 0, 3, 8, 9, 0, 3, 8, 9, 0, 3, 8, 9, 0, 3, 0, 0, 0, 3, 8, 9, 0, 3, 8, 9, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 8, 9, 0, 3, 8, 9, 0, 3, 8, 9, 0, 3, 9, 8, 0, 3, 0, 0, 0, 3, 9, 8, 0, 3, 9, 8, 0, 3, 0, 0, 0, 3, 9, 8, 0, 3, 9, 8, 0, 3, 0, 0, 0, 3, 8, 9, 0, 3, 8, 9, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 12, 13, 0, 1, 12, 13, 0, 1, 12, 13, 0, 1, 12, 13, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 12, 13, 0, 1, 12, 13, 0, 1, 12, 13, 0, 1, 12, 13, 0, 1, 12, 0, 0, 12, 1, 13, 0, 12, 1, 13, 0, 1, 0, 0, 0, 1, 12, 13, 0, 1, 12, 13, 0, 1, 0, 0, 0, 1, 12, 13, 0, 1, 12, 13, 0, 1, 0, 0, 0, 1, 12, 13, 0, 1, 12, 13, 0, 1, 0, 0, 0, 1, 15, 16, 0, 1, 15, 16, 0, 1, 0, 0, 0, 1, 15, 16, 0, 1, 15, 16, 0, 1, 0, 0, 0, 1, 15, 16, 0, 1, 15, 16, 0, 1, 0, 0, 0, 1, 15, 16, 0, 1, 15, 16, 0, 1, 15, 0, 0, 15, 1, 16, 0, 15, 1, 16, 0, 1, 15, 16, 0, 1, 0, 0, 0, 1, 15, 16, 0, 1, 15, 16, 0, 1, 0, 0, 0, 1, 15, 16, 0, 1, 0, 0, 0, 1, 15, 16, 0, 1, 15, 16, 0 </real_array>
- <real_array len="2500"> 0.500006, 0.499994, 0, 0, 0.500036, 0.499964, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.508359, 0.491641, 0, 0, 1, 0, 0, 0, 0.500012, 0.499988, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.500137, 0.499863, 0, 0, 0.997415, 0.00258508, 0, 0, 0.5, 0.5, 0, 0, 0.502778, 0.497222, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.439327, 0.339942, 0.220731, 0, 0.397775, 0.362587, 0.239639, 0, 0.523139, 0.476861, 0, 0, 0.563768, 0.436232, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 0.66667, 0.33333, 0, 0, 1, 0, 0, 0, 0.412375, 0.353797, 0.233829, 0, 0.538228, 0.461772, 0, 0, 0.544073, 0.274503, 0.181424, 0, 0.550005, 0.266658, 0.183337, 0, 0.673479, 0.326521, 0, 0, 0.664658, 0.335342, 0, 0, 0.546797, 0.270935, 0.182268, 0, 0.544673, 0.273746, 0.181581, 0, 0.665519, 0.334481, 0, 0, 0.668675, 0.331325, 0, 0, 0.615652, 0.230199, 0.154149, 0, 0.6672, 0.3328, 0, 0, 0.544198, 0.2744, 0.181402, 0, 0.664792, 0.335208, 0, 0, 1, 0, 0, 0, 0.37581, 0.37581, 0.24838, 0, 0.378779, 0.374023, 0.247199, 0, 0.503159, 0.496841, 0, 0, 0.5, 0.5, 0, 0, 0.399773, 0.361383, 0.238845, 0, 0.525218, 0.474782, 0, 0, 0.409739, 0.358697, 0.231565, 0, 0.533212, 0.466788, 0, 0, 0.375815, 0.375807, 0.248378, 0, 0.500006, 0.499994, 0, 0, 0.56732, 0.24294, 0.18974, 0, 0.700171, 0.299829, 0, 0, 0.544164, 0.274448, 0.181388, 0, 0.66474, 0.33526, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.500006, 0.499994, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.500036, 0.499964, 0, 0, 1, 0, 0, 0, 0.508359, 0.491641, 0, 0, 0.500012, 0.499988, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.502778, 0.497222, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.439327, 0.339942, 0.220731, 0, 0.563768, 0.436232, 0, 0, 0.523139, 0.476861, 0, 0, 0.397775, 0.362587, 0.239639, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 0.412375, 0.353797, 0.233829, 0, 0.538228, 0.461772, 0, 0, 0.544073, 0.274503, 0.181424, 0, 0.664658, 0.335342, 0, 0, 0.673479, 0.326521, 0, 0, 0.550005, 0.266658, 0.183337, 0, 0.546797, 0.270935, 0.182268, 0, 0.668675, 0.331325, 0, 0, 0.665519, 0.334481, 0, 0, 0.544673, 0.273746, 0.181581, 0, 0.615652, 0.230199, 0.154149, 0, 0.6672, 0.3328, 0, 0, 0.664792, 0.335208, 0, 0, 0.544198, 0.2744, 0.181402, 0, 1, 0, 0, 0, 0.37581, 0.37581, 0.24838, 0, 0.5, 0.5, 0, 0, 0.503159, 0.496841, 0, 0, 0.378779, 0.374023, 0.247199, 0, 0.525218, 0.474782, 0, 0, 0.399773, 0.361383, 0.238845, 0, 0.409739, 0.358697, 0.231565, 0, 0.533212, 0.466788, 0, 0, 0.500006, 0.499994, 0, 0, 0.375815, 0.375807, 0.248378, 0, 0.700171, 0.299829, 0, 0, 0.56732, 0.24294, 0.18974, 0, 0.544164, 0.274448, 0.181388, 0, 0.66474, 0.33526, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 0.666663, 0.333337, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 0.718253, 0.15884, 0.122907, 0, 0.739344, 0.136359, 0.124296, 0, 1, 0, 0, 0, 0.45939, 0.304779, 0.235832, 0, 0.485992, 0.268898, 0.245111, 0, 1, 0, 0, 0, 0.7331, 0.143653, 0.123247, 0, 0.477963, 0.280975, 0.241062, 0, 1, 0, 0, 0, 0.748373, 0.125813, 0.125813, 0, 0.747178, 0.12721, 0.125612, 0, 1, 0, 0, 0, 0.497836, 0.251082, 0.251082, 0, 0.496251, 0.253466, 0.250283, 0, 0.738503, 0.137343, 0.124154, 0, 1, 0, 0, 0, 0.484902, 0.270539, 0.244559, 0, 1, 0, 0, 0, 0.730612, 0.143641, 0.125747, 0, 0.4748, 0.280042, 0.245157, 0, 0.748371, 0.125816, 0.125813, 0, 1, 0, 0, 0, 0.497833, 0.251086, 0.251081, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.739344, 0.136359, 0.124296, 0, 0.718253, 0.15884, 0.122907, 0, 0.485992, 0.268898, 0.245111, 0, 0.45939, 0.304779, 0.235832, 0, 1, 0, 0, 0, 0.7331, 0.143653, 0.123247, 0, 0.477963, 0.280975, 0.241062, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.747178, 0.12721, 0.125612, 0, 0.748373, 0.125813, 0.125813, 0, 0.496251, 0.253466, 0.250283, 0, 0.497836, 0.251082, 0.251082, 0, 1, 0, 0, 0, 0.738503, 0.137343, 0.124154, 0, 0.484902, 0.270539, 0.244559, 0, 1, 0, 0, 0, 0.730612, 0.143641, 0.125747, 0, 0.4748, 0.280042, 0.245157, 0, 1, 0, 0, 0, 0.748371, 0.125816, 0.125813, 0, 0.497833, 0.251086, 0.251081, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.668925, 0.222972, 0.108103, 0, 0.666077, 0.221944, 0.111978, 0, 0.402445, 0.40244, 0.195114, 0, 0.399364, 0.399217, 0.201418, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666312, 0.222075, 0.111612, 0, 0.667337, 0.222443, 0.110219, 0, 0.399617, 0.399566, 0.200817, 0, 0.400725, 0.40072, 0.198555, 0, 0.500004, 0.499996, 0, 0, 0.533361, 0.40023, 0.0664093, 0, 0.571539, 0.286063, 0.142398, 0, 1, 0, 0, 0, 0.666044, 0.222012, 0.111945, 0, 0.399328, 0.399322, 0.20135, 0, 1, 0, 0, 0, 0.678203, 0.225313, 0.0964842, 0, 0.412634, 0.411257, 0.176109, 0, 1, 0, 0, 0, 0.666023, 0.222008, 0.111969, 0, 0.399306, 0.399306, 0.201389, 0, 1, 0, 0, 0, 0.666077, 0.221944, 0.111978, 0, 0.668925, 0.222972, 0.108103, 0, 1, 0, 0, 0, 0.399364, 0.399217, 0.201418, 0, 0.402445, 0.40244, 0.195114, 0, 1, 0, 0, 0, 0.667337, 0.222443, 0.110219, 0, 0.666312, 0.222075, 0.111612, 0, 1, 0, 0, 0, 0.400725, 0.40072, 0.198555, 0, 0.399617, 0.399566, 0.200817, 0, 0.500004, 0.499996, 0, 0, 0.533361, 0.40023, 0.0664093, 0, 0.571539, 0.286063, 0.142398, 0, 0.666044, 0.222012, 0.111945, 0, 1, 0, 0, 0, 0.399328, 0.399322, 0.20135, 0, 0.678203, 0.225313, 0.0964842, 0, 1, 0, 0, 0, 0.412634, 0.411257, 0.176109, 0, 1, 0, 0, 0, 0.666023, 0.222008, 0.111969, 0, 0.399306, 0.399306, 0.201389, 0 </real_array>
- <int_array len="2502"> 0, 2, 1, 0, 3, 2, 1, 5, 4, 1, 2, 5, 6, 5, 7, 6, 4, 5, 8, 0, 9, 8, 10, 0, 11, 13, 12, 11, 14, 13, 15, 17, 16, 15, 7, 17, 12, 15, 18, 12, 13, 15, 10, 3, 0, 10, 19, 3, 13, 7, 15, 13, 6, 7, 2, 20, 5, 2, 21, 20, 7, 20, 17, 7, 5, 20, 21, 3, 22, 21, 2, 3, 18, 16, 23, 18, 15, 16, 22, 19, 24, 22, 3, 19, 25, 27, 26, 25, 28, 27, 29, 28, 25, 29, 30, 28, 26, 32, 31, 26, 27, 32, 33, 35, 34, 33, 36, 35, 37, 39, 38, 37, 40, 39, 38, 42, 41, 38, 39, 42, 43, 45, 44, 43, 46, 45, 47, 49, 48, 47, 50, 49, 51, 53, 52, 51, 54, 53, 55, 46, 56, 55, 45, 46, 57, 44, 58, 57, 43, 44, 59, 61, 60, 59, 50, 61, 62, 45, 55, 62, 63, 45, 64, 48, 65, 64, 47, 48, 66, 50, 59, 66, 49, 50, 67, 43, 57, 67, 68, 43, 69, 68, 67, 69, 70, 68, 34, 49, 66, 34, 35, 49, 65, 70, 69, 65, 48, 70, 58, 72, 71, 58, 44, 72, 56, 36, 33, 56, 46, 36, 71, 74, 73, 71, 72, 74, 60, 63, 62, 60, 61, 63, 73, 47, 64, 73, 74, 47, 75, 77, 76, 75, 78, 77, 79, 41, 80, 79, 38, 41, 81, 38, 79, 81, 37, 38, 80, 83, 82, 80, 41, 83, 84, 37, 81, 84, 85, 37, 41, 86, 83, 41, 42, 86, 85, 40, 37, 85, 87, 40, 42, 88, 86, 42, 89, 88, 87, 90, 40, 87, 91, 90, 40, 92, 39, 40, 90, 92, 39, 89, 42, 39, 92, 89, 48, 35, 70, 48, 49, 35, 74, 50, 47, 74, 61, 50, 70, 36, 68, 70, 35, 36, 44, 63, 72, 44, 45, 63, 68, 46, 43, 68, 36, 46, 72, 61, 74, 72, 63, 61, 93, 95, 94, 93, 96, 95, 97, 25, 26, 97, 98, 25, 98, 29, 25, 98, 99, 29, 100, 26, 31, 100, 97, 26, 31, 102, 101, 31, 32, 102, 103, 105, 104, 103, 106, 105, 104, 108, 107, 104, 105, 108, 107, 110, 109, 107, 108, 110, 111, 113, 112, 111, 114, 113, 115, 112, 116, 115, 111, 112, 117, 116, 118, 117, 115, 116, 119, 118, 120, 119, 117, 118, 114, 110, 113, 114, 109, 110, 121, 123, 122, 121, 124, 123, 125, 124, 121, 125, 126, 124, 127, 129, 128, 128, 129, 130, 131, 129, 132, 133, 130, 129, 134, 133, 129, 135, 134, 129, 136, 138, 137, 136, 139, 138, 140, 142, 141, 140, 143, 142, 144, 146, 145, 144, 147, 146, 145, 149, 148, 145, 146, 149, 148, 151, 150, 148, 149, 151, 150, 153, 152, 150, 151, 153, 152, 143, 140, 152, 153, 143, 154, 156, 155, 154, 157, 156, 155, 159, 158, 155, 156, 159, 158, 106, 103, 158, 159, 106, 160, 162, 161, 160, 163, 162, 164, 161, 165, 164, 160, 161, 166, 165, 167, 166, 164, 165, 168, 167, 169, 168, 166, 167, 154, 120, 157, 154, 119, 120, 144, 169, 147, 144, 168, 169, 163, 142, 162, 163, 141, 142, 170, 172, 171, 170, 173, 172, 174, 173, 170, 174, 175, 173, 176, 178, 177, 176, 179, 178, 177, 126, 125, 177, 178, 126, 180, 179, 176, 180, 181, 179, 122, 181, 180, 122, 123, 181, 182, 184, 183, 182, 185, 184, 183, 187, 186, 183, 184, 187, 186, 189, 188, 186, 187, 189, 188, 191, 190, 188, 189, 191, 190, 193, 192, 190, 191, 193, 192, 195, 194, 192, 193, 195, 196, 198, 197, 196, 199, 198, 200, 197, 201, 200, 196, 197, 202, 201, 203, 202, 200, 201, 204, 203, 205, 204, 202, 203, 199, 195, 198, 199, 194, 195, 182, 205, 185, 182, 204, 205, 206, 129, 127, 207, 129, 131, 132, 129, 206, 208, 135, 129, 209, 208, 129, 207, 209, 129, 210, 139, 136, 210, 211, 139, 28, 212, 27, 28, 213, 212, 30, 213, 28, 30, 214, 213, 27, 215, 32, 27, 212, 215, 216, 218, 217, 216, 219, 218, 220, 95, 221, 220, 94, 95, 222, 218, 219, 222, 223, 218, 224, 96, 93, 224, 225, 96, 220, 223, 222, 220, 221, 223, 226, 78, 75, 226, 227, 78, 228, 230, 229, 228, 231, 230, 232, 234, 233, 232, 235, 234, 236, 235, 232, 236, 237, 235, 229, 239, 238, 229, 230, 239, 233, 231, 228, 233, 234, 231, 32, 240, 102, 32, 215, 240, 241, 243, 242, 241, 244, 243, 76, 246, 245, 76, 77, 246, 247, 227, 226, 247, 248, 227, 242, 250, 249, 242, 243, 250, 245, 244, 241, 245, 246, 244, 249, 248, 247, 249, 250, 248, 238, 252, 251, 238, 239, 252, 253, 237, 236, 253, 254, 237, 251, 254, 253, 251, 252, 254, 102, 240, 255, 9, 1, 256, 9, 0, 1, 14, 6, 13, 14, 257, 6, 256, 4, 258, 256, 1, 4, 257, 4, 6, 257, 258, 4, 259, 261, 260, 259, 262, 261, 262, 263, 261, 262, 264, 263, 265, 263, 264, 265, 266, 263, 8, 259, 10, 8, 267, 259, 11, 269, 268, 11, 12, 269, 270, 271, 266, 270, 272, 271, 12, 270, 269, 12, 18, 270, 10, 260, 19, 10, 259, 260, 269, 266, 265, 269, 270, 266, 261, 274, 273, 261, 263, 274, 266, 274, 263, 266, 271, 274, 260, 273, 275, 260, 261, 273, 18, 272, 270, 18, 23, 272, 19, 275, 24, 19, 260, 275, 276, 278, 277, 276, 279, 278, 29, 277, 30, 29, 276, 277, 279, 280, 278, 279, 281, 280, 282, 284, 283, 282, 285, 284, 286, 288, 287, 286, 289, 288, 289, 290, 288, 289, 291, 290, 292, 294, 293, 292, 295, 294, 296, 298, 297, 296, 299, 298, 300, 53, 54, 300, 301, 53, 302, 293, 294, 302, 303, 293, 304, 295, 292, 304, 305, 295, 306, 307, 297, 306, 308, 307, 309, 294, 310, 309, 302, 294, 311, 299, 296, 311, 312, 299, 313, 297, 298, 313, 306, 297, 314, 292, 315, 314, 304, 292, 316, 315, 317, 316, 314, 315, 285, 298, 284, 285, 313, 298, 312, 317, 299, 312, 316, 317, 305, 318, 295, 305, 319, 318, 303, 283, 293, 303, 282, 283, 319, 320, 318, 319, 321, 320, 308, 310, 307, 308, 309, 310, 321, 296, 320, 321, 311, 296, 322, 324, 323, 322, 325, 324, 326, 291, 289, 326, 327, 291, 328, 289, 286, 328, 326, 289, 327, 329, 291, 327, 330, 329, 331, 286, 332, 331, 328, 286, 291, 333, 290, 291, 329, 333, 332, 287, 334, 332, 286, 287, 290, 336, 335, 290, 333, 336, 334, 338, 337, 334, 287, 338, 287, 339, 338, 287, 288, 339, 288, 335, 339, 288, 290, 335, 299, 284, 298, 299, 317, 284, 320, 297, 307, 320, 296, 297, 317, 283, 284, 317, 315, 283, 295, 310, 294, 295, 318, 310, 315, 293, 283, 315, 292, 293, 318, 307, 310, 318, 320, 307, 340, 342, 341, 340, 343, 342, 344, 276, 345, 344, 279, 276, 345, 29, 99, 345, 276, 29, 346, 279, 344, 346, 281, 279, 281, 102, 280, 281, 101, 102, 347, 349, 348, 347, 350, 349, 350, 351, 349, 350, 352, 351, 352, 353, 351, 352, 354, 353, 355, 357, 356, 355, 358, 357, 359, 358, 355, 359, 360, 358, 361, 360, 359, 361, 362, 360, 363, 362, 361, 363, 364, 362, 356, 353, 354, 356, 357, 353, 365, 367, 366, 365, 368, 367, 369, 366, 370, 369, 365, 366, 371, 373, 372, 373, 374, 372, 375, 376, 372, 377, 372, 374, 378, 372, 377, 379, 372, 378, 136, 381, 380, 136, 137, 381, 382, 384, 383, 382, 385, 384, 386, 388, 387, 386, 389, 388, 389, 390, 388, 389, 391, 390, 391, 392, 390, 391, 393, 392, 393, 394, 392, 393, 395, 394, 395, 383, 394, 395, 382, 383, 396, 398, 397, 396, 399, 398, 399, 400, 398, 399, 401, 400, 401, 348, 400, 401, 347, 348, 402, 404, 403, 402, 405, 404, 406, 405, 402, 406, 407, 405, 408, 407, 406, 408, 409, 407, 410, 409, 408, 410, 411, 409, 396, 364, 363, 396, 397, 364, 386, 411, 410, 386, 387, 411, 403, 384, 385, 403, 404, 384, 412, 414, 413, 412, 415, 414, 416, 413, 417, 416, 412, 413, 418, 420, 419, 418, 421, 420, 421, 370, 420, 421, 369, 370, 422, 419, 423, 422, 418, 419, 368, 423, 367, 368, 422, 423, 424, 426, 425, 424, 427, 426, 427, 428, 426, 427, 429, 428, 429, 430, 428, 429, 431, 430, 431, 432, 430, 431, 433, 432, 433, 434, 432, 433, 435, 434, 435, 436, 434, 435, 437, 436, 438, 440, 439, 438, 441, 440, 442, 441, 438, 442, 443, 441, 444, 443, 442, 444, 445, 443, 446, 445, 444, 446, 447, 445, 439, 436, 437, 439, 440, 436, 424, 447, 446, 424, 425, 447, 448, 371, 372, 449, 375, 372, 376, 448, 372, 450, 372, 379, 451, 372, 450, 449, 372, 451, 210, 380, 452, 210, 136, 380, 277, 454, 453, 277, 278, 454, 30, 453, 214, 30, 277, 453, 278, 455, 454, 278, 280, 455, 216, 457, 456, 216, 217, 457, 458, 342, 343, 458, 459, 342, 460, 457, 461, 460, 456, 457, 224, 341, 225, 224, 340, 341, 458, 461, 459, 458, 460, 461, 462, 323, 463, 462, 322, 323, 464, 466, 465, 464, 467, 466, 468, 470, 469, 468, 471, 470, 472, 469, 473, 472, 468, 469, 467, 474, 466, 467, 475, 474, 471, 465, 470, 471, 464, 465, 280, 476, 455, 280, 102, 476, 477, 479, 478, 477, 480, 479, 325, 481, 324, 325, 482, 481, 483, 463, 484, 483, 462, 463, 480, 485, 479, 480, 486, 485, 482, 478, 481, 482, 477, 478, 486, 484, 485, 486, 483, 484, 475, 487, 474, 475, 488, 487, 489, 473, 490, 489, 472, 473, 488, 490, 487, 488, 489, 490, 102, 255, 476, 267, 262, 259, 267, 491, 262, 268, 265, 492, 268, 269, 265, 491, 264, 262, 491, 493, 264, 492, 264, 493, 492, 265, 264, 494, 496, 495, 494, 497, 496, 497, 94, 496, 497, 93, 94, 498, 500, 499, 498, 501, 500, 499, 219, 216, 499, 500, 219, 502, 496, 503, 502, 495, 496, 503, 94, 220, 503, 496, 94, 504, 500, 501, 504, 505, 500, 505, 219, 500, 505, 222, 219, 506, 497, 494, 506, 507, 497, 507, 93, 497, 507, 224, 93, 502, 505, 504, 502, 503, 505, 503, 222, 505, 503, 220, 222, 508, 510, 509, 508, 511, 510, 509, 343, 340, 509, 510, 343, 498, 513, 512, 498, 499, 513, 499, 456, 513, 499, 216, 456, 514, 510, 511, 514, 515, 510, 515, 343, 510, 515, 458, 343, 516, 513, 517, 516, 512, 513, 517, 456, 460, 517, 513, 456, 506, 509, 507, 506, 508, 509, 507, 340, 224, 507, 509, 340, 514, 517, 515, 514, 516, 517, 515, 460, 458, 515, 517, 460, 31, 518, 100, 31, 101, 518, 100, 54, 51, 100, 518, 54, 519, 521, 520, 519, 522, 521, 520, 98, 97, 520, 521, 98, 522, 523, 521, 522, 524, 523, 521, 99, 98, 521, 523, 99, 52, 520, 51, 52, 519, 520, 51, 97, 100, 51, 520, 97, 281, 518, 101, 281, 346, 518, 346, 54, 518, 346, 300, 54, 525, 527, 526, 525, 528, 527, 528, 345, 527, 528, 344, 345, 526, 523, 524, 526, 527, 523, 527, 99, 523, 527, 345, 99, 301, 528, 525, 301, 300, 528, 300, 344, 528, 300, 346, 344, 529, 531, 530, 529, 532, 531, 530, 534, 533, 530, 531, 534, 533, 325, 322, 533, 534, 325, 535, 530, 536, 535, 529, 530, 536, 533, 537, 536, 530, 533, 537, 322, 462, 537, 533, 322, 538, 540, 539, 538, 541, 540, 539, 543, 542, 539, 540, 543, 542, 480, 477, 542, 543, 480, 532, 544, 531, 532, 545, 544, 531, 546, 534, 531, 544, 546, 534, 482, 325, 534, 546, 482, 547, 536, 548, 547, 535, 536, 548, 537, 549, 548, 536, 537, 549, 462, 483, 549, 537, 462, 541, 550, 540, 541, 551, 550, 540, 552, 543, 540, 550, 552, 543, 486, 480, 543, 552, 486, 545, 539, 544, 545, 538, 539, 544, 542, 546, 544, 539, 542, 546, 477, 482, 546, 542, 477, 551, 548, 550, 551, 547, 548, 550, 549, 552, 550, 548, 549, 552, 483, 486, 552, 549, 483, 553, 555, 554, 553, 556, 555, 556, 557, 555, 556, 558, 557, 558, 76, 557, 558, 75, 76, 559, 556, 553, 559, 560, 556, 560, 558, 556, 560, 561, 558, 561, 75, 558, 561, 226, 75, 562, 564, 563, 562, 565, 564, 565, 566, 564, 565, 567, 566, 567, 242, 566, 567, 241, 242, 554, 569, 568, 554, 555, 569, 555, 570, 569, 555, 557, 570, 557, 245, 570, 557, 76, 245, 571, 560, 559, 571, 572, 560, 572, 561, 560, 572, 573, 561, 573, 226, 561, 573, 247, 226, 563, 575, 574, 563, 564, 575, 564, 576, 575, 564, 566, 576, 566, 249, 576, 566, 242, 249, 568, 565, 562, 568, 569, 565, 569, 567, 565, 569, 570, 567, 570, 241, 567, 570, 245, 241, 574, 572, 571, 574, 575, 572, 575, 573, 572, 575, 576, 573, 576, 247, 573, 576, 249, 247, 577, 579, 578, 577, 580, 579, 580, 581, 579, 580, 582, 581, 582, 229, 581, 582, 228, 229, 583, 585, 584, 583, 586, 585, 586, 587, 585, 586, 588, 587, 588, 233, 587, 588, 232, 233, 589, 586, 583, 589, 590, 586, 590, 588, 586, 590, 591, 588, 591, 232, 588, 591, 236, 232, 578, 593, 592, 578, 579, 593, 579, 594, 593, 579, 581, 594, 581, 238, 594, 581, 229, 238, 584, 580, 577, 584, 585, 580, 585, 582, 580, 585, 587, 582, 587, 228, 582, 587, 233, 228, 592, 596, 595, 592, 593, 596, 593, 597, 596, 593, 594, 597, 594, 251, 597, 594, 238, 251, 598, 590, 589, 598, 599, 590, 599, 591, 590, 599, 600, 591, 600, 236, 591, 600, 253, 236, 595, 599, 598, 595, 596, 599, 596, 600, 599, 596, 597, 600, 597, 253, 600, 597, 251, 253, 601, 603, 602, 601, 604, 603, 602, 606, 605, 602, 603, 606, 605, 467, 464, 605, 606, 467, 607, 609, 608, 607, 610, 609, 608, 612, 611, 608, 609, 612, 611, 471, 468, 611, 612, 471, 613, 608, 614, 613, 607, 608, 614, 611, 615, 614, 608, 611, 615, 468, 472, 615, 611, 468, 604, 616, 603, 604, 617, 616, 603, 618, 606, 603, 616, 618, 606, 475, 467, 606, 618, 475, 610, 602, 609, 610, 601, 602, 609, 605, 612, 609, 602, 605, 612, 464, 471, 612, 605, 464, 617, 619, 616, 617, 620, 619, 616, 621, 618, 616, 619, 621, 618, 488, 475, 618, 621, 488, 622, 614, 623, 622, 613, 614, 623, 615, 624, 623, 614, 615, 624, 472, 489, 624, 615, 472, 620, 623, 619, 620, 622, 623, 619, 624, 621, 619, 623, 624, 621, 489, 488, 621, 624, 489 </int_array>
- </array>
- </dictionary>
-
- </resource>
- <resource type="SampleLibrary" path="local://6">
- <dictionary name="samples/jump" shared="false">
- <string> "db" </string>
- <real> 0 </real>
- <string> "pitch" </string>
- <real> 1 </real>
- <string> "sample" </string>
- <resource resource_type="Sample" path="res://sound_jump.wav"> </resource>
- </dictionary>
- <dictionary name="samples/shoot" shared="false">
- <string> "db" </string>
- <real> 0 </real>
- <string> "pitch" </string>
- <real> 1 </real>
- <string> "sample" </string>
- <resource resource_type="Sample" path="res://sound_shoot.wav"> </resource>
- </dictionary>
-
- </resource>
- <resource type="Animation" path="local://7">
- <string name="resource/name"> "idle" </string>
- <real name="length"> 1.25 </real>
- <bool name="loop"> True </bool>
- <real name="step"> 0.1 </real>
- <string name="tracks/0/type"> "transform" </string>
- <node_path name="tracks/0/path"> "Armature/Skeleton:r-arm" </node_path>
- <int name="tracks/0/interp"> 1 </int>
- <real_array name="tracks/0/keys" len="180"> 0, 1, 1.01328e-06, -8.34465e-07, 1.07288e-06, -0.0255728, 0.138077, -0.259039, 0.955604, 1, 1, 1, 0.05, 1, 5.96046e-07, -2.38419e-07, 3.8743e-07, -0.0264725, 0.139277, -0.25962, 0.955248, 1, 1, 1, 0.1, 1, 5.36442e-07, -2.38419e-07, 3.8743e-07, -0.028916, 0.142508, -0.261183, 0.954274, 1, 1, 1, 0.15, 1, 1.19209e-07, 1.19209e-07, 5.96046e-08, -0.0326835, 0.14736, -0.26354, 0.952766, 1, 1, 1, 0.25, 1, 5.96046e-08, 1.19209e-07, 0, -0.0433083, 0.158072, -0.268982, 0.949098, 1, 1, 1, 0.3, 1, 8.9407e-07, -3.57628e-07, 5.96046e-07, -0.0481632, 0.16058, -0.27034, 0.948056, 1, 1, 1, 0.35, 1, 7.15256e-07, -3.57628e-07, 5.36442e-07, -0.0515519, 0.159894, -0.270034, 0.948081, 1, 1, 1, 0.4, 1, 6.25849e-07, -3.57628e-07, 5.06639e-07, -0.0529994, 0.155917, -0.267946, 0.949256, 1, 1, 1, 0.85, 1, 8.04663e-07, -5.96046e-07, 8.34465e-07, -0.01551, 0.114246, -0.235933, 0.964906, 1, 1, 1, 0.9, 1, 7.15256e-07, -4.76837e-07, 7.15256e-07, -0.0133439, 0.115591, -0.236366, 0.964672, 1, 1, 1, 0.95, 1, 5.06639e-07, -3.57628e-07, 4.76837e-07, -0.0142794, 0.118993, -0.239276, 0.963527, 1, 1, 1, 1.1, 1, 6.55651e-07, -3.57628e-07, 5.36442e-07, -0.0224776, 0.132362, -0.25315, 0.958066, 1, 1, 1, 1.15, 1, 7.45058e-07, -2.38419e-07, 4.17233e-07, -0.0241962, 0.135447, -0.25637, 0.956736, 1, 1, 1, 1.2, 1, 7.15256e-07, -2.38419e-07, 5.06639e-07, -0.0252313, 0.137384, -0.258343, 0.955902, 1, 1, 1, 1.25, 1, 1.01328e-06, -8.34465e-07, 1.07288e-06, -0.0255726, 0.138077, -0.259039, 0.955604, 1, 1, 1 </real_array>
- <string name="tracks/1/type"> "transform" </string>
- <node_path name="tracks/1/path"> "Armature/Skeleton:r-forearm" </node_path>
- <int name="tracks/1/interp"> 1 </int>
- <real_array name="tracks/1/keys" len="204"> 0, 1, 2.38419e-07, -8.34465e-07, -4.76837e-07, -0.218168, -0.120735, -0.0116329, 0.968344, 1, 1, 1, 0.05, 1, 2.98023e-08, -5.96046e-07, -2.38419e-07, -0.218633, -0.120967, -0.0119311, 0.968207, 1, 1, 1, 0.1, 1, 1.78814e-07, -7.7486e-07, -4.76837e-07, -0.219848, -0.121646, -0.0127373, 0.967836, 1, 1, 1, 0.15, 1, -5.96046e-08, -6.25849e-07, -4.76837e-07, -0.221585, -0.122891, -0.0139574, 0.967266, 1, 1, 1, 0.2, 1, -2.98023e-08, -9.83477e-07, -1.78814e-07, -0.223801, -0.125062, -0.0151597, 0.966459, 1, 1, 1, 0.25, 1, 1.49012e-07, -5.66244e-07, -2.38419e-07, -0.225991, -0.128733, -0.0159408, 0.965454, 1, 1, 1, 0.3, 1, 0, -1.04308e-06, -2.38419e-07, -0.227229, -0.134329, -0.0159913, 0.9644, 1, 0.999999, 1, 0.55, 1, 2.98023e-08, -5.66244e-07, -3.57628e-07, -0.218159, -0.170756, -0.00658222, 0.960836, 1, 1, 1, 0.6, 1, 1.49012e-07, -5.36442e-07, -2.98023e-07, -0.214746, -0.174272, -0.00460497, 0.960985, 1, 1, 1, 0.65, 1, 2.38419e-07, -2.08616e-07, -3.57628e-07, -0.21128, -0.17607, -0.0030008, 0.961432, 1, 1, 1, 0.7, 1, 1.49012e-07, -4.47035e-07, -2.38419e-07, -0.207961, -0.17612, -0.00179697, 0.962149, 1, 1, 1, 0.75, 1, -2.38419e-07, -6.55651e-07, -3.57628e-07, -0.204984, -0.174339, -0.000935222, 0.963113, 1, 1, 1, 0.8, 1, 8.9407e-08, -2.98023e-08, -1.19209e-07, -0.202542, -0.170485, -0.000499965, 0.964319, 1, 0.999999, 1, 0.85, 1, 8.9407e-08, -8.64267e-07, -4.17233e-07, -0.200954, -0.164989, -0.000498206, 0.965607, 1, 0.999999, 1, 1.15, 1, 1.19209e-07, -6.85453e-07, -2.98023e-07, -0.216378, -0.124725, -0.0104075, 0.968254, 1, 1, 1, 1.2, 1, -2.98023e-08, 2.98023e-08, -1.78814e-07, -0.217708, -0.121801, -0.0113103, 0.968318, 1, 1, 1, 1.25, 1, 2.38419e-07, -8.34465e-07, -4.76837e-07, -0.218168, -0.120734, -0.0116329, 0.968344, 1, 1, 1 </real_array>
- <string name="tracks/2/type"> "transform" </string>
- <node_path name="tracks/2/path"> "Armature/Skeleton:l-arm" </node_path>
- <int name="tracks/2/interp"> 1 </int>
- <real_array name="tracks/2/keys" len="180"> 0, 1, -1.01328e-06, -8.34465e-07, 1.07288e-06, -0.0255728, -0.138077, 0.25904, 0.955604, 1, 1, 1, 0.05, 1, -5.96046e-07, -2.38419e-07, 3.8743e-07, -0.0264725, -0.139277, 0.25962, 0.955248, 1, 1, 1, 0.1, 1, -5.36442e-07, -2.38419e-07, 3.8743e-07, -0.028916, -0.142508, 0.261183, 0.954274, 1, 1, 1, 0.15, 1, -1.19209e-07, 1.19209e-07, 5.96046e-08, -0.0326835, -0.14736, 0.26354, 0.952766, 1, 1, 1, 0.25, 1, -5.96046e-08, 1.19209e-07, 0, -0.0433083, -0.158072, 0.268982, 0.949098, 1, 1, 1, 0.3, 1, -8.9407e-07, -3.57628e-07, 5.96046e-07, -0.0481632, -0.16058, 0.27034, 0.948056, 1, 1, 1, 0.35, 1, -7.15256e-07, -3.57628e-07, 5.36442e-07, -0.0515519, -0.159894, 0.270034, 0.948081, 1, 1, 1, 0.4, 1, -6.25849e-07, -3.57628e-07, 5.06639e-07, -0.0529994, -0.155917, 0.267946, 0.949256, 1, 1, 1, 0.85, 1, -8.04663e-07, -5.96046e-07, 8.34465e-07, -0.01551, -0.114246, 0.235933, 0.964906, 1, 1, 1, 0.9, 1, -7.15256e-07, -4.76837e-07, 7.15256e-07, -0.0133439, -0.115591, 0.236367, 0.964672, 1, 1, 1, 0.95, 1, -5.06639e-07, -3.57628e-07, 4.76837e-07, -0.0142794, -0.118993, 0.239276, 0.963527, 1, 1, 1, 1.1, 1, -6.55651e-07, -3.57628e-07, 5.36442e-07, -0.0224776, -0.132362, 0.25315, 0.958066, 1, 1, 1, 1.15, 1, -7.45058e-07, -2.38419e-07, 4.17233e-07, -0.0241962, -0.135447, 0.25637, 0.956736, 1, 1, 1, 1.2, 1, -7.15256e-07, -2.38419e-07, 5.06639e-07, -0.0252313, -0.137384, 0.258343, 0.955902, 1, 1, 1, 1.25, 1, -1.01328e-06, -8.34465e-07, 1.07288e-06, -0.0255726, -0.138077, 0.259039, 0.955604, 1, 1, 1 </real_array>
- <string name="tracks/3/type"> "transform" </string>
- <node_path name="tracks/3/path"> "Armature/Skeleton:l-forearm" </node_path>
- <int name="tracks/3/interp"> 1 </int>
- <real_array name="tracks/3/keys" len="204"> 0, 1, -2.38419e-07, -8.34465e-07, -4.76837e-07, -0.218168, 0.120735, 0.0116329, 0.968344, 1, 1, 1, 0.05, 1, -5.96046e-08, -8.04663e-07, -3.57628e-07, -0.218633, 0.120966, 0.0119311, 0.968207, 1, 1, 1, 0.1, 1, -3.57628e-07, -7.45058e-07, -4.17233e-07, -0.219848, 0.121646, 0.0127373, 0.967836, 1, 1, 1, 0.15, 1, -1.49012e-07, -6.25849e-07, -3.57628e-07, -0.221585, 0.122891, 0.0139575, 0.967266, 1, 1, 1, 0.2, 1, 0, -9.53674e-07, -1.19209e-07, -0.223801, 0.125062, 0.0151597, 0.966459, 1, 1, 1, 0.25, 1, -1.49012e-07, -5.66244e-07, -2.38419e-07, -0.225991, 0.128733, 0.0159408, 0.965454, 1, 1, 1, 0.3, 1, 0, -1.04308e-06, -2.38419e-07, -0.227229, 0.134329, 0.0159913, 0.9644, 1, 0.999999, 1, 0.55, 1, -2.98023e-08, -5.66244e-07, -3.57628e-07, -0.218159, 0.170756, 0.00658222, 0.960836, 1, 1, 1, 0.6, 1, -1.49012e-07, -5.36442e-07, -2.98023e-07, -0.214746, 0.174272, 0.00460497, 0.960985, 1, 1, 1, 0.65, 1, -2.38419e-07, -2.08616e-07, -3.57628e-07, -0.21128, 0.17607, 0.0030008, 0.961432, 1, 1, 1, 0.7, 1, -1.49012e-07, -4.47035e-07, -2.38419e-07, -0.207961, 0.17612, 0.00179697, 0.962149, 1, 1, 1, 0.75, 1, 2.38419e-07, -6.55651e-07, -3.57628e-07, -0.204984, 0.174339, 0.000935222, 0.963113, 1, 1, 1, 0.8, 1, -2.98023e-08, 0, -1.19209e-07, -0.202542, 0.170485, 0.000499968, 0.964319, 1, 1, 1, 0.85, 1, 1.49012e-07, -8.34465e-07, -4.17233e-07, -0.200954, 0.164989, 0.000498198, 0.965606, 1, 1, 1, 1.15, 1, -2.38419e-07, -8.04663e-07, -6.55651e-07, -0.216378, 0.124725, 0.0104075, 0.968254, 1, 1, 1, 1.2, 1, -2.08616e-07, 2.08616e-07, -2.98023e-07, -0.217708, 0.121801, 0.0113103, 0.968318, 1, 1, 1, 1.25, 1, -2.38419e-07, -8.34465e-07, -4.76837e-07, -0.218168, 0.120734, 0.0116329, 0.968344, 1, 1, 1 </real_array>
- <string name="tracks/4/type"> "transform" </string>
- <node_path name="tracks/4/path"> "Armature/Skeleton:r-thigh" </node_path>
- <int name="tracks/4/interp"> 1 </int>
- <real_array name="tracks/4/keys" len="180"> 0, 1, 0, 5.21541e-08, -3.42727e-07, -0.0539951, -0.0696263, 0.0213632, 0.995882, 1, 1, 1, 0.05, 1, 0, 5.21541e-08, -3.42727e-07, -0.0567764, -0.0700338, 0.0212387, 0.995701, 1, 1, 1, 0.1, 1, 0, 3.72529e-08, -3.42727e-07, -0.06411, -0.0711033, 0.0209058, 0.995187, 1, 1, 1, 0.15, 1, 0, 9.68575e-08, -3.42727e-07, -0.0751103, -0.0727354, 0.0204167, 0.994309, 1, 1, 1, 0.45, 1, 0, 1.41561e-07, -1.3411e-07, -0.154319, -0.0862804, 0.0175296, 0.984091, 1, 1, 1, 0.5, 1, 2.98023e-08, 7.45058e-09, 2.5332e-07, -0.162001, -0.0877685, 0.017297, 0.982728, 1, 1, 1, 0.55, 1, 0, 3.72529e-08, -3.42727e-07, -0.166842, -0.0887317, 0.0171579, 0.981833, 1, 1, 1, 0.6, 1, 0, 2.98023e-08, -1.49012e-07, -0.169226, -0.0892111, 0.0170905, 0.981383, 1, 1, 1, 0.65, 1, 0, 2.98023e-08, -1.49012e-07, -0.169226, -0.0892111, 0.0170905, 0.981383, 1, 1, 1, 0.7, 1, 0, 3.72529e-08, -3.42727e-07, -0.166842, -0.0887317, 0.0171579, 0.981833, 1, 1, 1, 0.75, 1, 2.98023e-08, 7.45058e-09, 2.5332e-07, -0.162001, -0.0877685, 0.017297, 0.982728, 1, 1, 1, 0.8, 1, 0, 1.41561e-07, -1.3411e-07, -0.154319, -0.0862804, 0.0175296, 0.984091, 1, 1, 1, 1.15, 1, 0, 3.72529e-08, -3.42727e-07, -0.06411, -0.0711033, 0.0209058, 0.995187, 1, 1, 1, 1.2, 1, 0, 5.21541e-08, -3.42727e-07, -0.0567764, -0.0700338, 0.0212387, 0.995701, 1, 1, 1, 1.25, 1, 0, 5.21541e-08, -3.42727e-07, -0.0539951, -0.0696263, 0.0213632, 0.995882, 1, 1, 1 </real_array>
- <string name="tracks/5/type"> "transform" </string>
- <node_path name="tracks/5/path"> "Armature/Skeleton:r-leg" </node_path>
- <int name="tracks/5/interp"> 1 </int>
- <real_array name="tracks/5/keys" len="192"> 0, 1, 1.42842e-07, 1.93715e-07, 2.98023e-07, -0.0965851, -0.0177476, 0.000627753, 0.995166, 1, 1, 1, 0.05, 1, 4.62169e-08, -6.70552e-08, 6.55651e-07, -0.100604, -0.0182764, 0.000608928, 0.994758, 1, 1, 1, 0.1, 1, 8.12579e-08, 5.96046e-08, 5.36442e-07, -0.111195, -0.0196529, 0.000562433, 0.993604, 1, 1, 1, 0.15, 1, 3.0268e-08, -2.98023e-08, 5.96046e-07, -0.127055, -0.0217242, 0.000494295, 0.991658, 1, 1, 1, 0.45, 1, 1.55647e-07, 1.49012e-07, 4.76837e-07, -0.240017, -0.0376881, -3.78875e-05, 0.970037, 1, 1, 1, 0.5, 1, -1.23866e-07, 3.57628e-07, 7.7486e-07, -0.250826, -0.0393224, -9.00224e-05, 0.967233, 1, 1, 1, 0.55, 1, 5.34346e-08, 3.72529e-08, 5.96046e-07, -0.25762, -0.040368, -0.000123774, 0.965403, 1, 1, 1, 0.6, 1, 1.08266e-08, 5.96046e-08, 7.15256e-07, -0.260963, -0.0408854, -0.000140397, 0.964483, 1, 1, 1, 0.65, 1, 1.08266e-08, 5.96046e-08, 7.15256e-07, -0.260963, -0.0408854, -0.000140397, 0.964483, 1, 1, 1, 0.7, 1, 5.34346e-08, 3.72529e-08, 5.96046e-07, -0.25762, -0.040368, -0.000123775, 0.965403, 1, 1, 1, 0.75, 1, -1.23866e-07, 3.57628e-07, 7.7486e-07, -0.250826, -0.0393224, -9.00224e-05, 0.967233, 1, 1, 1, 0.8, 1, 1.55647e-07, 1.49012e-07, 4.76837e-07, -0.240017, -0.0376881, -3.78871e-05, 0.970037, 1, 1, 1, 0.9, 1, -4.8778e-08, -1.3411e-07, 7.15256e-07, -0.208519, -0.0330444, 0.00011266, 0.97746, 1, 1, 1, 1.15, 1, 8.12579e-08, 5.96046e-08, 5.36442e-07, -0.111195, -0.0196529, 0.000562432, 0.993604, 1, 1, 1, 1.2, 1, 4.62169e-08, -6.70552e-08, 6.55651e-07, -0.100605, -0.0182764, 0.000608928, 0.994758, 1, 1, 1, 1.25, 1, 1.42842e-07, 1.93715e-07, 2.98023e-07, -0.0965852, -0.0177476, 0.000627753, 0.995166, 1, 1, 1 </real_array>
- <string name="tracks/6/type"> "transform" </string>
- <node_path name="tracks/6/path"> "Armature/Skeleton:r-foot" </node_path>
- <int name="tracks/6/interp"> 1 </int>
- <real_array name="tracks/6/keys" len="180"> 0, 1, 8.9407e-08, 2.38419e-07, -2.23517e-08, 0.0349931, -0.0301778, 0.0362945, 0.998272, 1, 1, 1, 0.05, 1, 7.45058e-08, 2.38419e-07, 6.33299e-08, 0.0358993, -0.0301376, 0.0363473, 0.998239, 1, 1, 1, 0.1, 1, 5.21541e-08, 1.19209e-07, 2.98023e-08, 0.0384013, -0.0300263, 0.0364927, 0.998144, 1, 1, 1, 0.15, 1, 4.47035e-08, 1.19209e-07, -1.11759e-08, 0.0424549, -0.0298457, 0.0367279, 0.997977, 1, 1, 1, 0.5, 1, 5.21541e-08, 1.19209e-07, 7.45058e-09, 0.0873535, -0.0278095, 0.0392948, 0.995014, 1, 1, 1, 0.55, 1, -7.45058e-09, 0, -5.21541e-08, 0.0905253, -0.0276632, 0.0394735, 0.994727, 1, 1, 1, 0.6, 1, 2.98023e-08, 0, 2.23517e-08, 0.0921114, -0.0275899, 0.0395627, 0.99458, 1, 1, 1, 0.65, 1, 2.98023e-08, 0, 2.23517e-08, 0.0921114, -0.0275899, 0.0395627, 0.99458, 1, 1, 1, 0.7, 1, -7.45058e-09, 0, -5.21541e-08, 0.0905253, -0.0276632, 0.0394735, 0.994727, 1, 1, 1, 0.75, 1, 5.21541e-08, 1.19209e-07, 7.45058e-09, 0.0873535, -0.0278095, 0.0392948, 0.995014, 1, 1, 1, 0.8, 1, 1.04308e-07, 2.38419e-07, -1.49012e-08, 0.0824784, -0.0280337, 0.0390195, 0.995434, 1, 1, 1, 1.1, 1, 4.47035e-08, 1.19209e-07, -1.11759e-08, 0.0424549, -0.0298457, 0.0367279, 0.997977, 1, 1, 1, 1.15, 1, 5.21541e-08, 1.19209e-07, 2.98023e-08, 0.0384013, -0.0300263, 0.0364927, 0.998144, 1, 1, 1, 1.2, 1, 7.45058e-08, 2.38419e-07, 6.33299e-08, 0.0358993, -0.0301376, 0.0363473, 0.998239, 1, 1, 1, 1.25, 1, 8.9407e-08, 2.38419e-07, -2.23517e-08, 0.0349931, -0.0301778, 0.0362945, 0.998272, 1, 1, 1 </real_array>
- <string name="tracks/7/type"> "transform" </string>
- <node_path name="tracks/7/path"> "Armature/Skeleton:l-thigh" </node_path>
- <int name="tracks/7/interp"> 1 </int>
- <real_array name="tracks/7/keys" len="180"> 0, 1, 0, 6.70552e-08, -1.04308e-07, -0.0539995, 0.0696269, -0.0213643, 0.995881, 1, 0.999999, 1, 0.05, 1, 0, 6.70552e-08, -1.04308e-07, -0.05678, 0.0700343, -0.0212398, 0.995701, 1, 0.999999, 1, 0.1, 1, 0, 2.23517e-08, -1.04308e-07, -0.0641135, 0.0711039, -0.0209069, 0.995187, 1, 0.999999, 1, 0.15, 1, 0, 8.19564e-08, -1.04308e-07, -0.075114, 0.072736, -0.0204178, 0.994309, 1, 0.999999, 1, 0.45, 1, -2.98023e-08, 1.04308e-07, 1.04308e-07, -0.15432, 0.0862808, -0.0175308, 0.98409, 1, 0.999999, 1, 0.5, 1, -5.96046e-08, 2.98023e-08, 4.91738e-07, -0.162002, 0.0877689, -0.0172983, 0.982727, 1, 0.999999, 1, 0.55, 1, 0, 5.21541e-08, -1.04308e-07, -0.166843, 0.0887321, -0.0171591, 0.981833, 1, 0.999999, 1, 0.6, 1, -2.98023e-08, 4.47035e-08, 8.9407e-08, -0.169228, 0.0892116, -0.0170917, 0.981382, 1, 0.999999, 1, 0.65, 1, -2.98023e-08, 4.47035e-08, 8.9407e-08, -0.169228, 0.0892116, -0.0170917, 0.981382, 1, 0.999999, 1, 0.7, 1, 0, 5.21541e-08, -1.04308e-07, -0.166843, 0.0887321, -0.0171591, 0.981833, 1, 0.999999, 1, 0.75, 1, -5.96046e-08, 2.98023e-08, 4.91738e-07, -0.162002, 0.0877689, -0.0172983, 0.982727, 1, 0.999999, 1, 0.8, 1, -2.98023e-08, 1.04308e-07, 1.04308e-07, -0.15432, 0.0862808, -0.0175308, 0.98409, 1, 0.999999, 1, 1.15, 1, 0, 2.23517e-08, -1.04308e-07, -0.0641135, 0.0711039, -0.020907, 0.995187, 1, 0.999999, 1, 1.2, 1, 0, 6.70552e-08, -1.04308e-07, -0.05678, 0.0700343, -0.0212398, 0.995701, 1, 0.999999, 1, 1.25, 1, 0, 6.70552e-08, -1.04308e-07, -0.0539992, 0.0696269, -0.0213643, 0.995881, 1, 0.999999, 1 </real_array>
- <string name="tracks/8/type"> "transform" </string>
- <node_path name="tracks/8/path"> "Armature/Skeleton:l-leg" </node_path>
- <int name="tracks/8/interp"> 1 </int>
- <real_array name="tracks/8/keys" len="192"> 0, 1, 9.06875e-08, -8.19564e-08, 3.57628e-07, -0.0965913, 0.0177484, -0.00062776, 0.995166, 1, 1, 1, 0.05, 1, 3.44589e-08, -1.93715e-07, 2.98023e-07, -0.10061, 0.0182771, -0.000608941, 0.994758, 1, 1, 1, 0.1, 1, 2.52621e-08, -1.86265e-07, 5.96046e-08, -0.1112, 0.0196536, -0.000562456, 0.993604, 1, 1, 1, 0.15, 1, 9.02219e-08, -1.19209e-07, 1.19209e-07, -0.127061, 0.021725, -0.000494313, 0.991657, 1, 1, 1, 0.45, 1, 7.13626e-08, -5.21541e-08, 1.19209e-07, -0.24002, 0.0376883, 3.78708e-05, 0.970036, 1, 1, 1, 0.5, 1, -2.84053e-08, -1.78814e-07, -1.78814e-07, -0.250828, 0.0393224, 9.00085e-05, 0.967233, 1, 1, 1, 0.55, 1, 1.234e-08, 2.01166e-07, 1.78814e-07, -0.257623, 0.0403681, 0.000123756, 0.965402, 1, 1, 1, 0.6, 1, -9.97679e-08, 5.21541e-08, -5.96046e-08, -0.260966, 0.0408856, 0.000140381, 0.964482, 1, 1, 1, 0.65, 1, -9.97679e-08, 5.21541e-08, -5.96046e-08, -0.260966, 0.0408856, 0.000140381, 0.964482, 1, 1, 1, 0.7, 1, 1.234e-08, 2.01166e-07, 1.78814e-07, -0.257623, 0.0403681, 0.000123754, 0.965402, 1, 1, 1, 0.75, 1, -2.84053e-08, -1.78814e-07, -1.78814e-07, -0.250828, 0.0393224, 9.00085e-05, 0.967233, 1, 1, 1, 0.8, 1, 7.13626e-08, -5.21541e-08, 1.19209e-07, -0.24002, 0.0376883, 3.78693e-05, 0.970036, 1, 1, 1, 0.9, 1, 3.73693e-08, -5.21541e-08, 2.38419e-07, -0.208521, 0.0330446, -0.000112648, 0.977459, 1, 1, 1, 1.15, 1, 2.52621e-08, -1.86265e-07, 5.96046e-08, -0.1112, 0.0196536, -0.000562457, 0.993604, 1, 1, 1, 1.2, 1, 3.44589e-08, -1.93715e-07, 2.98023e-07, -0.10061, 0.0182771, -0.000608943, 0.994758, 1, 1, 1, 1.25, 1, 9.06875e-08, -8.19564e-08, 3.57628e-07, -0.0965911, 0.0177484, -0.000627765, 0.995166, 1, 1, 1 </real_array>
- <string name="tracks/9/type"> "transform" </string>
- <node_path name="tracks/9/path"> "Armature/Skeleton:l-foot" </node_path>
- <int name="tracks/9/interp"> 1 </int>
- <real_array name="tracks/9/keys" len="180"> 0, 1, -6.70552e-08, 0, -3.72529e-09, 0.0349931, 0.0301778, -0.0362945, 0.998272, 1, 1, 1, 0.05, 1, -1.49012e-08, 1.19209e-07, -7.45058e-09, 0.0358993, 0.0301376, -0.0363473, 0.998239, 1, 1, 1, 0.1, 1, 1.49012e-08, -1.19209e-07, 1.49012e-08, 0.0384013, 0.0300263, -0.0364927, 0.998144, 1, 1, 1, 0.15, 1, -4.47035e-08, 0, -3.72529e-09, 0.0424549, 0.0298457, -0.0367279, 0.997977, 1, 1, 1, 0.5, 1, 5.21541e-08, 0, -1.11759e-08, 0.0873535, 0.0278095, -0.0392948, 0.995014, 1, 1, 1, 0.55, 1, 4.47035e-08, 0, -2.98023e-08, 0.0905253, 0.0276632, -0.0394736, 0.994727, 1, 1, 1, 0.6, 1, 1.49012e-08, 0, -1.86265e-08, 0.0921114, 0.02759, -0.0395628, 0.99458, 1, 1, 1, 0.65, 1, 1.49012e-08, 0, -1.86265e-08, 0.0921114, 0.02759, -0.0395628, 0.99458, 1, 1, 1, 0.7, 1, 4.47035e-08, 0, -2.98023e-08, 0.0905253, 0.0276633, -0.0394736, 0.994727, 1, 1, 1, 0.75, 1, 5.21541e-08, 0, -1.11759e-08, 0.0873535, 0.0278095, -0.0392948, 0.995014, 1, 1, 1, 0.8, 1, -3.72529e-08, 1.19209e-07, -1.11759e-08, 0.0824784, 0.0280338, -0.0390195, 0.995434, 1, 1, 1, 1.1, 1, -4.47035e-08, 0, -3.72529e-09, 0.0424549, 0.0298457, -0.0367279, 0.997977, 1, 1, 1, 1.15, 1, 1.49012e-08, -1.19209e-07, 1.49012e-08, 0.0384013, 0.0300263, -0.0364927, 0.998144, 1, 1, 1, 1.2, 1, -1.49012e-08, 1.19209e-07, -7.45058e-09, 0.0358992, 0.0301376, -0.0363473, 0.998239, 1, 1, 1, 1.25, 1, -6.70552e-08, 0, -3.72529e-09, 0.0349931, 0.0301778, -0.0362945, 0.998272, 1, 1, 1 </real_array>
- <string name="tracks/10/type"> "transform" </string>
- <node_path name="tracks/10/path"> "Armature/Skeleton:MASTER" </node_path>
- <int name="tracks/10/interp"> 1 </int>
- <real_array name="tracks/10/keys" len="24"> 0, 1, 0, -0.322829, 2.42144e-08, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0, -0.322829, 2.42144e-08, 5.1658e-08, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/11/type"> "transform" </string>
- <node_path name="tracks/11/path"> "Armature/Skeleton:HEAD" </node_path>
- <int name="tracks/11/interp"> 1 </int>
- <real_array name="tracks/11/keys" len="24"> 0, 1, -5.68434e-14, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -5.68434e-14, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/12/type"> "transform" </string>
- <node_path name="tracks/12/path"> "Armature/Skeleton:r-LEGCONTROL" </node_path>
- <int name="tracks/12/interp"> 1 </int>
- <real_array name="tracks/12/keys" len="24"> 0, 1, 0.220288, -4.0302e-11, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.220288, -4.0302e-11, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/13/type"> "transform" </string>
- <node_path name="tracks/13/path"> "Armature/Skeleton:l-LEGCONTROL" </node_path>
- <int name="tracks/13/interp"> 1 </int>
- <real_array name="tracks/13/keys" len="24"> 0, 1, -0.220288, -4.0302e-11, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.220288, -4.0302e-11, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/14/type"> "transform" </string>
- <node_path name="tracks/14/path"> "Armature/Skeleton:r-LEGORIENT" </node_path>
- <int name="tracks/14/interp"> 1 </int>
- <real_array name="tracks/14/keys" len="24"> 0, 1, -0.183564, 0.0305941, 5.96046e-08, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.183564, 0.0305941, 5.96046e-08, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1 </real_array>
- <string name="tracks/15/type"> "transform" </string>
- <node_path name="tracks/15/path"> "Armature/Skeleton:l-LEGORIENT" </node_path>
- <int name="tracks/15/interp"> 1 </int>
- <real_array name="tracks/15/keys" len="24"> 0, 1, 0.183564, 0.030594, 5.96046e-08, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.183564, 0.030594, 5.96046e-08, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1 </real_array>
- <string name="tracks/16/type"> "transform" </string>
- <node_path name="tracks/16/path"> "Armature/Skeleton:r-ARMCONTROL" </node_path>
- <int name="tracks/16/interp"> 1 </int>
- <real_array name="tracks/16/keys" len="168"> 0, 1, -1.15243, -0.687477, 0.0713858, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -1.15504, -0.689394, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, -1.16214, -0.694617, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.15, 1, -1.17317, -0.702725, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.3, 1, -1.21295, -0.731968, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.35, 1, -1.22128, -0.738092, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, -1.2252, -0.740971, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, -1.22553, -0.741211, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.5, 1, -1.22422, -0.740253, 0.0713858, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, -1.22161, -0.73833, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.6, 1, -1.21787, -0.735585, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1.15, 1, -1.15488, -0.689275, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1.2, 1, -1.15308, -0.687955, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1.25, 1, -1.15243, -0.687477, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/17/type"> "transform" </string>
- <node_path name="tracks/17/path"> "Armature/Skeleton:l-ARMCONTROL" </node_path>
- <int name="tracks/17/interp"> 1 </int>
- <real_array name="tracks/17/keys" len="168"> 0, 1, 1.15243, -0.687477, 0.0713859, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 1.15504, -0.689394, 0.0713859, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, 1.16214, -0.694617, 0.0713859, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.15, 1, 1.17317, -0.702725, 0.0713859, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.3, 1, 1.21295, -0.731968, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.35, 1, 1.22128, -0.738092, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, 1.2252, -0.740971, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, 1.22553, -0.741211, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.5, 1, 1.22422, -0.740253, 0.0713858, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, 1.22161, -0.73833, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.6, 1, 1.21787, -0.735585, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1.15, 1, 1.15488, -0.689275, 0.0713859, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1.2, 1, 1.15308, -0.687955, 0.0713859, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1.25, 1, 1.15243, -0.687477, 0.0713859, -5.1658e-08, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/18/type"> "transform" </string>
- <node_path name="tracks/18/path"> "Armature/Skeleton:r-ARMORIENT" </node_path>
- <int name="tracks/18/interp"> 1 </int>
- <real_array name="tracks/18/keys" len="156"> 0, 1, 0.849557, -0.741664, 4.9468, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 0.849557, -0.741664, 4.93101, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, 0.849557, -0.741664, 4.88735, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.15, 1, 0.849557, -0.741664, 4.81599, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.2, 1, 0.849557, -0.741664, 4.71797, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.75, 1, 0.849557, -0.741664, 3.21234, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, 0.849557, -0.741664, 3.18081, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.85, 1, 0.849557, -0.741664, 3.18869, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.9, 1, 0.849557, -0.741664, 3.28296, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.95, 1, 0.849557, -0.741664, 3.48291, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1.15, 1, 0.849557, -0.741664, 4.70777, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1.2, 1, 0.849557, -0.741664, 4.88227, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.849557, -0.741664, 4.9468, -5.1658e-08, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/19/type"> "transform" </string>
- <node_path name="tracks/19/path"> "Armature/Skeleton:l-ARMORIENT" </node_path>
- <int name="tracks/19/interp"> 1 </int>
- <real_array name="tracks/19/keys" len="156"> 0, 1, -0.849557, -0.741664, 4.9468, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -0.849557, -0.741664, 4.93101, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, -0.849557, -0.741664, 4.88735, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.15, 1, -0.849557, -0.741664, 4.81599, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.2, 1, -0.849557, -0.741664, 4.71797, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.75, 1, -0.849557, -0.741664, 3.21234, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, -0.849557, -0.741664, 3.18081, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.85, 1, -0.849557, -0.741664, 3.18869, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.9, 1, -0.849557, -0.741664, 3.28296, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.95, 1, -0.849557, -0.741664, 3.48291, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1.15, 1, -0.849557, -0.741664, 4.70777, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1.2, 1, -0.849557, -0.741664, 4.88227, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.849557, -0.741664, 4.9468, -5.1658e-08, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/20/type"> "transform" </string>
- <node_path name="tracks/20/path"> "Armature/Skeleton:hip" </node_path>
- <int name="tracks/20/interp"> 1 </int>
- <real_array name="tracks/20/keys" len="180"> 0, 1, 1.11759e-08, 0.0713859, 0.0510914, 0, 0, 1.44945e-21, 1, 1, 1, 1, 0.05, 1, 1.11759e-08, 0.0713859, 0.0522077, -4.26326e-14, 4.23516e-22, 1.44945e-21, 1, 1, 1, 1, 0.1, 1, 1.11759e-08, 0.0713859, 0.05529, -5.68434e-14, 2.11758e-21, 1.44945e-21, 1, 1, 1, 1, 0.15, 1, 1.11759e-08, 0.0713859, 0.0602832, -4.26326e-14, 4.23516e-22, 1.44945e-21, 1, 1, 1, 1, 0.5, 1, 1.11759e-08, 0.0713859, 0.115648, 0, 0, 1.44945e-21, 1, 1, 1, 1, 0.55, 1, 1.11759e-08, 0.0713859, 0.119568, -4.26326e-14, 4.23516e-22, 1.44945e-21, 1, 1, 1, 1, 0.6, 1, 1.11759e-08, 0.0713859, 0.121528, -4.26326e-14, 4.23516e-22, 1.44945e-21, 1, 1, 1, 1, 0.65, 1, 1.11759e-08, 0.0713859, 0.121528, -4.26326e-14, 4.23516e-22, 1.44945e-21, 1, 1, 1, 1, 0.7, 1, 1.11759e-08, 0.0713859, 0.119568, -5.68434e-14, 2.11758e-21, 1.44945e-21, 1, 1, 1, 1, 0.75, 1, 1.11759e-08, 0.0713859, 0.115648, 0, 0, 1.44945e-21, 1, 1, 1, 1, 0.8, 1, 1.11759e-08, 0.0713859, 0.109626, -5.68434e-14, 2.11758e-21, 1.44945e-21, 1, 1, 1, 1, 1.1, 1, 1.11759e-08, 0.0713859, 0.0602832, -5.68434e-14, 2.11758e-21, 1.44945e-21, 1, 1, 1, 1, 1.15, 1, 1.11759e-08, 0.0713859, 0.05529, -4.26326e-14, 4.23516e-22, 1.44945e-21, 1, 1, 1, 1, 1.2, 1, 1.11759e-08, 0.0713859, 0.0522077, -2.84217e-14, -4.23516e-22, 1.44945e-21, 1, 1, 1, 1, 1.25, 1, 1.11759e-08, 0.0713859, 0.0510914, -4.26326e-14, 4.23516e-22, 1.44945e-21, 1, 1, 1, 1 </real_array>
- <string name="tracks/21/type"> "transform" </string>
- <node_path name="tracks/21/path"> "Armature/Skeleton:waist" </node_path>
- <int name="tracks/21/interp"> 1 </int>
- <real_array name="tracks/21/keys" len="168"> 0, 1, 5.71157e-15, -1.62345e-08, 8.9407e-08, 0, 0, 2.44616e-35, 1, 1, 1, 1, 0.05, 1, 5.75176e-15, -1.64873e-08, 8.9407e-08, 0.000214909, 1.42979e-18, -2.11758e-22, 1, 1, 1, 1, 0.1, 1, 4.06271e-15, -5.26452e-09, 8.9407e-08, 0.000808293, -3.04932e-19, 2.465e-22, 1, 1, 1, 1, 0.15, 1, 1.54246e-15, 1.14859e-08, 8.9407e-08, 0.00176961, 6.63395e-18, -1.17394e-20, 0.999998, 1, 1, 1, 0.5, 1, 4.42376e-15, -1.05373e-09, -2.98023e-08, 0.0124283, 2.20213e-20, -2.77954e-22, 0.999923, 1, 1, 1, 0.55, 1, 4.56489e-15, -1.94163e-09, 8.9407e-08, 0.0131829, 1.00996e-17, -7.10618e-15, 0.999913, 1, 1, 1, 0.65, 1, 1.79332e-15, -2.38573e-09, 8.9407e-08, 0.0135603, 1.03769e-16, -1.40726e-18, 0.999908, 1, 1, 1, 0.7, 1, 4.56489e-15, -1.94163e-09, 8.9407e-08, 0.0131829, -1.18256e-16, 1.5591e-18, 0.999913, 1, 1, 1, 0.75, 1, 4.42376e-15, -1.05373e-09, -2.98023e-08, 0.0124282, 2.20246e-20, -2.77954e-22, 0.999923, 1, 1, 1, 0.8, 1, 4.20699e-15, 3.1009e-10, -2.98023e-08, 0.011269, -6.2751e-17, 7.07106e-19, 0.999937, 1, 1, 1, 1.1, 1, 1.54246e-15, 1.14859e-08, 8.9407e-08, 0.00176961, 7.93788e-18, -7.10545e-15, 0.999998, 1, 1, 1, 1.15, 1, 4.06271e-15, -5.26452e-09, 8.9407e-08, 0.000808293, -3.04932e-19, 2.465e-22, 1, 1, 1, 1, 1.2, 1, 5.75176e-15, -1.64874e-08, 8.9407e-08, 0.00021491, -2.03966e-18, 4.23517e-22, 1, 1, 1, 1, 1.25, 1, 5.71157e-15, -1.62345e-08, 8.9407e-08, 3.83187e-10, 0, 1.22308e-35, 1, 1, 1, 1 </real_array>
- <string name="tracks/22/type"> "transform" </string>
- <node_path name="tracks/22/path"> "Armature/Skeleton:chest" </node_path>
- <int name="tracks/22/interp"> 1 </int>
- <real_array name="tracks/22/keys" len="156"> 0, 1, 7.24544e-18, 1.86265e-08, 5.96046e-08, 0, 0, -1.33383e-23, 1, 1, 1, 1, 0.05, 1, -3.76414e-18, 3.72529e-09, 0, 0.00110099, -2.41201e-19, -1.97577e-17, 0.999999, 1, 1, 1, 0.1, 1, 9.18675e-18, 1.49012e-08, -1.19209e-07, 0.00410119, -8.96205e-19, -7.35977e-17, 0.999992, 1, 1, 1, 0.15, 1, 1.76552e-17, 7.45058e-09, -5.96046e-08, 0.00875896, -1.91283e-18, -1.57184e-16, 0.999962, 1, 1, 1, 0.3, 1, 1.31081e-17, -1.11759e-08, 0, 0.0255569, -5.58266e-18, -4.58633e-16, 0.999673, 1, 1, 1, 0.35, 1, 1.99653e-17, -1.49012e-08, -5.96046e-08, 0.0290738, -6.35135e-18, -5.21745e-16, 0.999577, 1, 1, 1, 0.4, 1, 1.92772e-17, 1.11759e-08, 1.19209e-07, 0.0307265, -6.71273e-18, -5.51404e-16, 0.999528, 1, 1, 1, 0.5, 1, 4.47552e-17, 1.11759e-08, 5.96046e-08, 0.0303143, -6.6203e-18, -5.44008e-16, 0.99954, 1, 1, 1, 0.55, 1, 1.08083e-17, 2.23517e-08, -5.96046e-08, 0.0292103, -6.38065e-18, -5.24195e-16, 0.999573, 1, 1, 1, 0.6, 1, -3.34373e-18, -1.11759e-08, -2.98023e-07, 0.0276344, -6.03606e-18, -4.95914e-16, 0.999618, 1, 1, 1, 1.15, 1, 9.18674e-18, 1.49012e-08, -1.19209e-07, 0.0010327, -2.26125e-19, -1.85323e-17, 0.999999, 1, 1, 1, 1.2, 1, -3.7641e-18, 0, 0, 0.000274137, -6.02241e-20, -4.91966e-18, 1, 1, 1, 1, 1.25, 1, 7.24539e-18, 1.86265e-08, 5.96046e-08, 0, 0, 1.31315e-23, 1, 1, 1, 1 </real_array>
- <string name="tracks/23/type"> "transform" </string>
- <node_path name="tracks/23/path"> "Armature/Skeleton:neck" </node_path>
- <int name="tracks/23/interp"> 1 </int>
- <real_array name="tracks/23/keys" len="24"> 0, 1, -1.13687e-13, -1.49012e-08, -3.57628e-07, 1.17383e-27, 2.13163e-14, 5.50671e-14, 1, 1, 1, 1, 1.25, 1, -1.13687e-13, -1.49012e-08, -3.57628e-07, -2.46125e-27, 2.13163e-14, -1.77636e-15, 1, 1, 1, 1 </real_array>
- <string name="tracks/24/type"> "transform" </string>
- <node_path name="tracks/24/path"> "Armature/Skeleton:headtracker" </node_path>
- <int name="tracks/24/interp"> 1 </int>
- <real_array name="tracks/24/keys" len="180"> 0, 1, -2.16716e-13, 2.38419e-07, -1.20141e-07, 0.00540576, -3.97061e-09, 4.73012e-08, 0.999985, 1, 1, 1, 0.05, 1, 1.42109e-14, -6.85453e-07, -5.96046e-08, 0.00687155, -3.90174e-09, 4.73059e-08, 0.999976, 1, 1, 1, 0.1, 1, -1.06581e-13, -3.57628e-07, 4.65661e-09, 0.0108835, -3.7136e-09, 4.73184e-08, 0.999941, 1, 1, 1, 0.15, 1, 2.4869e-14, -7.15256e-07, -2.79397e-09, 0.0171898, -3.41769e-09, 4.73365e-08, 0.999852, 1, 1, 1, 0.35, 1, 5.68434e-14, -4.76837e-07, -2.16532e-08, 0.0482761, -1.95634e-09, 4.7399e-08, 0.998834, 1, 1, 1, 0.4, 1, 1.3145e-13, -4.76837e-07, 1.39698e-08, 0.0525864, -1.75345e-09, 4.74044e-08, 0.998616, 1, 1, 1, 0.45, 1, -7.10543e-15, -2.98023e-07, -2.23517e-08, 0.0549628, -1.64161e-09, 4.74072e-08, 0.998488, 1, 1, 1, 0.5, 1, 8.88178e-14, -4.47035e-07, -5.75092e-08, 0.056151, -1.58539e-09, 4.74086e-08, 0.998422, 1, 1, 1, 0.55, 1, -1.06581e-14, -7.15256e-07, -1.09896e-07, 0.0561279, -1.58659e-09, 4.74089e-08, 0.998424, 1, 1, 1, 0.6, 1, 1.49214e-13, -5.36442e-07, 8.3819e-09, 0.0550227, -1.63855e-09, 4.74081e-08, 0.998485, 1, 1, 1, 0.65, 1, 1.42109e-13, -5.66244e-07, -2.72412e-08, 0.0528693, -1.73995e-09, 4.74061e-08, 0.998601, 1, 1, 1, 0.7, 1, 1.27898e-13, -9.83477e-07, 2.23517e-08, 0.0497256, -1.88791e-09, 4.74026e-08, 0.998763, 1, 1, 1, 1.15, 1, 4.61853e-14, -2.68221e-07, -1.44821e-07, 0.00768525, -3.86364e-09, 4.73087e-08, 0.99997, 1, 1, 1, 1.2, 1, -4.61853e-14, -2.38419e-07, -9.12696e-08, 0.00601107, -3.94226e-09, 4.73032e-08, 0.999982, 1, 1, 1, 1.25, 1, -2.16716e-13, 2.38419e-07, -1.20141e-07, 0.00540581, -3.97061e-09, 4.73011e-08, 0.999985, 1, 1, 1 </real_array>
- <string name="tracks/25/type"> "transform" </string>
- <node_path name="tracks/25/path"> "Armature/Skeleton:head" </node_path>
- <int name="tracks/25/interp"> 1 </int>
- <real_array name="tracks/25/keys" len="156"> 0, 1, -1.11494e-13, -1.15717e-07, -2.08616e-07, 7.45058e-09, 8.88178e-15, 0, 1, 1, 1, 1, 0.05, 1, 1.80868e-10, 1.36495e-05, 0.000901487, 1.49012e-08, 1.77636e-14, -2.13163e-14, 1, 1, 1, 1, 0.1, 1, 6.8149e-10, 5.12244e-05, 0.00339634, 7.45058e-09, 1.77636e-15, -2.13163e-14, 1, 1, 1, 1, 0.15, 1, 1.5005e-09, 0.00011289, 0.00747763, 7.45058e-09, 7.10543e-15, -7.10543e-15, 1, 1, 1, 1, 0.2, 1, 2.6273e-09, 0.000197746, 0.0130927, 7.45058e-09, -5.32907e-15, 7.10543e-15, 1, 1, 1, 1, 0.75, 1, 2.00072e-08, 0.00150619, 0.0996987, 7.45058e-09, 3.55271e-15, -1.42109e-14, 1, 1, 1, 1, 0.8, 1, 2.03706e-08, 0.00153358, 0.10151, 1.49012e-08, 3.55271e-15, -1.42109e-14, 1, 1, 1, 1, 0.85, 1, 2.02794e-08, 0.00152671, 0.101055, 1.49012e-08, -5.32907e-15, 7.10543e-15, 1, 1, 1, 1, 0.9, 1, 1.91881e-08, 0.00144463, 0.0956172, 7.45058e-09, -7.10543e-15, 0, 1, 1, 1, 1, 0.95, 1, 1.68664e-08, 0.00126975, 0.084048, 1.49012e-08, 1.77636e-15, -2.13163e-14, 1, 1, 1, 1, 1.15, 1, 2.70661e-09, 0.000203704, 0.0134885, 7.45058e-09, -5.32907e-15, 7.10543e-15, 1, 1, 1, 1, 1.2, 1, 7.26606e-10, 5.46668e-05, 0.00362133, 7.45058e-09, 2.13163e-14, -1.42109e-14, 1, 1, 1, 1, 1.25, 1, -1.10217e-13, -1.15717e-07, -2.02097e-07, 7.45058e-09, -5.32907e-15, 7.10543e-15, 1, 1, 1, 1 </real_array>
- <string name="tracks/26/type"> "transform" </string>
- <node_path name="tracks/26/path"> "Armature/Skeleton:vent" </node_path>
- <int name="tracks/26/interp"> 1 </int>
- <real_array name="tracks/26/keys" len="24"> 0, 1, 4.48581e-08, 0.00292328, 0.204329, 1.04774e-09, -4.44089e-15, 5.58928e-15, 1, 1, 1, 1, 1.25, 1, 4.48581e-08, 0.00292328, 0.204329, 1.74623e-09, -6.21725e-15, 3.40058e-14, 1, 1, 1, 1 </real_array>
-
- </resource>
- <resource type="Animation" path="local://8">
- <string name="resource/name"> "shooting" </string>
- <real name="length"> 0.416667 </real>
- <bool name="loop"> False </bool>
- <real name="step"> 0.1 </real>
- <string name="tracks/0/type"> "transform" </string>
- <node_path name="tracks/0/path"> "Armature/Skeleton:r-arm" </node_path>
- <int name="tracks/0/interp"> 1 </int>
- <real_array name="tracks/0/keys" len="108"> 0, 1, 2.98023e-07, 3.57628e-07, 2.38419e-07, 0.177354, -0.316176, -0.0334956, 0.931373, 1, 1, 1, 0.05, 1, 5.36442e-07, -1.19209e-07, 5.06639e-07, 0.188185, -0.332103, -0.0311768, 0.923754, 1, 1, 1, 0.1, 1, 7.15256e-07, -3.57628e-07, 5.66244e-07, 0.204001, -0.354515, -0.0276657, 0.912106, 1, 1, 1, 0.15, 1, 6.25849e-07, -1.19209e-07, 4.76837e-07, 0.207621, -0.359465, -0.0268362, 0.909372, 1, 1, 1, 0.2, 1, 4.47035e-07, -1.19209e-07, 4.76837e-07, 0.203765, -0.354216, -0.0277227, 0.912273, 1, 1, 1, 0.35, 1, 6.85453e-07, -3.57628e-07, 5.36442e-07, 0.181322, -0.322103, -0.0326568, 0.928604, 1, 1, 1, 0.4, 1, 5.36442e-07, -1.19209e-07, 4.76837e-07, 0.177926, -0.317037, -0.0333752, 0.930976, 1, 1, 1, 0.45, 1, 2.98023e-07, 3.57628e-07, 2.38419e-07, 0.177354, -0.316176, -0.0334956, 0.931373, 1, 1, 1, 1.25, 1, 2.98023e-07, 3.57628e-07, 2.38419e-07, 0.177354, -0.316176, -0.0334956, 0.931373, 1, 1, 1 </real_array>
- <string name="tracks/1/type"> "transform" </string>
- <node_path name="tracks/1/path"> "Armature/Skeleton:r-forearm" </node_path>
- <int name="tracks/1/interp"> 1 </int>
- <real_array name="tracks/1/keys" len="108"> 0, 1, -4.47035e-07, -2.98023e-07, 0, 0.00444313, -0.215306, 0.0125622, 0.976456, 1, 1, 1, 0.05, 1, -2.08616e-07, -4.17233e-07, -2.98023e-07, 0.00305205, -0.21031, 0.0121764, 0.977554, 1, 1, 1, 0.1, 1, 2.08616e-07, -3.57628e-07, -3.57628e-07, 0.000634907, -0.201765, 0.0115128, 0.979366, 1, 0.999999, 1, 0.15, 1, 1.19209e-07, -1.19209e-07, -4.17233e-07, 2.2336e-05, -0.199561, 0.0113313, 0.97982, 1, 1, 1, 0.2, 1, 2.98023e-07, -8.9407e-08, -4.17233e-07, 0.000688273, -0.201948, 0.0115275, 0.979328, 1, 1, 1, 0.3, 1, -1.78814e-07, -2.68221e-07, -5.96046e-08, 0.00309916, -0.210458, 0.0121876, 0.977522, 1, 1, 1, 0.35, 1, 2.98023e-07, -5.96046e-07, -4.17233e-07, 0.00397812, -0.213611, 0.0124303, 0.976832, 1, 1, 1, 0.4, 1, -2.68221e-07, -4.47035e-07, -1.78814e-07, 0.00437828, -0.215068, 0.0125436, 0.976509, 1, 1, 1, 1.25, 1, -4.47035e-07, -2.98023e-07, 0, 0.00444313, -0.215306, 0.0125622, 0.976456, 1, 1, 1 </real_array>
- <string name="tracks/2/type"> "transform" </string>
- <node_path name="tracks/2/path"> "Armature/Skeleton:l-arm" </node_path>
- <int name="tracks/2/interp"> 1 </int>
- <real_array name="tracks/2/keys" len="108"> 0, 1, -5.66244e-07, 0, 2.68221e-07, -0.666114, -0.365882, 0.129948, 0.636817, 1, 1, 1, 0.05, 1, -5.96046e-07, -4.76837e-07, 4.76837e-07, -0.656623, -0.392941, 0.132853, 0.629916, 1, 1, 0.999999, 0.1, 1, -1.04308e-06, -5.96046e-07, 7.45058e-07, -0.641339, -0.431274, 0.137762, 0.619442, 1, 1, 1, 0.15, 1, -1.04308e-06, -7.15256e-07, 8.9407e-07, -0.637616, -0.439805, 0.139013, 0.617003, 1, 1, 0.999999, 0.2, 1, 2.98023e-08, 0, 3.27826e-07, -0.641587, -0.430741, 0.137654, 0.61958, 1, 1, 0.999999, 0.35, 1, -2.38419e-07, -3.57628e-07, 1.49012e-07, -0.662747, -0.375915, 0.130927, 0.634281, 1, 1, 0.999999, 0.4, 1, -5.66244e-07, -1.19209e-07, 3.57628e-07, -0.665636, -0.367338, 0.130084, 0.636451, 1, 1, 1, 0.45, 1, -5.66244e-07, 0, 2.68221e-07, -0.666114, -0.365882, 0.129948, 0.636817, 1, 1, 1, 1.25, 1, -5.66244e-07, 0, 2.68221e-07, -0.666114, -0.365882, 0.129948, 0.636817, 1, 1, 1 </real_array>
- <string name="tracks/3/type"> "transform" </string>
- <node_path name="tracks/3/path"> "Armature/Skeleton:l-forearm" </node_path>
- <int name="tracks/3/interp"> 1 </int>
- <real_array name="tracks/3/keys" len="108"> 0, 1, 2.98023e-08, -5.96046e-07, -4.17233e-07, -0.130784, -0.271804, -0.0853016, 0.949601, 1.3, 1.3, 1.3, 0.05, 1, 1.49012e-07, -6.55651e-07, -5.96046e-07, -0.133062, -0.270527, -0.0774246, 0.950324, 1.3, 1.3, 1.3, 0.1, 1, 2.68221e-07, -5.96046e-07, -2.38419e-07, -0.136329, -0.26867, -0.0661281, 0.95124, 1.3, 1.3, 1.3, 0.15, 1, -8.9407e-08, -8.04663e-07, -7.15256e-07, -0.137063, -0.26825, -0.0635932, 0.951426, 1.3, 1.3, 1.3, 0.2, 1, -8.9407e-08, -6.85453e-07, -7.15256e-07, -0.136283, -0.268695, -0.0662837, 0.951229, 1.3, 1.3, 1.3, 0.35, 1, -1.78814e-07, -5.66244e-07, -4.76837e-07, -0.131626, -0.271333, -0.0823877, 0.949876, 1.3, 1.3, 1.3, 0.4, 1, 5.96046e-08, -5.96046e-07, -3.57628e-07, -0.130906, -0.271736, -0.0848797, 0.949641, 1.3, 1.3, 1.3, 0.45, 1, 2.98023e-08, -5.96046e-07, -4.17233e-07, -0.130784, -0.271804, -0.0853016, 0.949601, 1.3, 1.3, 1.3, 1.25, 1, 2.98023e-08, -5.96046e-07, -4.17233e-07, -0.130784, -0.271804, -0.0853016, 0.949601, 1.3, 1.3, 1.3 </real_array>
- <string name="tracks/4/type"> "transform" </string>
- <node_path name="tracks/4/path"> "Armature/Skeleton:r-thigh" </node_path>
- <int name="tracks/4/interp"> 1 </int>
- <real_array name="tracks/4/keys" len="24"> 0, 1, 0, 1.63913e-07, 1.93715e-07, -0.283345, 0.0300071, -0.0426225, 0.957601, 1, 1, 1, 1.25, 1, 0, 1.63913e-07, 1.93715e-07, -0.283345, 0.0300071, -0.0426225, 0.957601, 1, 1, 1 </real_array>
- <string name="tracks/5/type"> "transform" </string>
- <node_path name="tracks/5/path"> "Armature/Skeleton:r-leg" </node_path>
- <int name="tracks/5/interp"> 1 </int>
- <real_array name="tracks/5/keys" len="24"> 0, 1, 2.29338e-08, 8.9407e-08, 5.36442e-07, -0.369097, -0.0505305, 0.00260278, 0.928013, 1, 1, 1, 1.25, 1, 2.29338e-08, 8.9407e-08, 5.36442e-07, -0.369097, -0.0505305, 0.00260278, 0.928013, 1, 1, 1 </real_array>
- <string name="tracks/6/type"> "transform" </string>
- <node_path name="tracks/6/path"> "Armature/Skeleton:r-foot" </node_path>
- <int name="tracks/6/interp"> 1 </int>
- <real_array name="tracks/6/keys" len="24"> 0, 1, 1.49012e-08, 0, -5.21541e-08, 0.163945, 0.140221, -0.046324, 0.975354, 1, 1, 1, 1.25, 1, 1.49012e-08, 0, -5.21541e-08, 0.163945, 0.140221, -0.046324, 0.975354, 1, 1, 1 </real_array>
- <string name="tracks/7/type"> "transform" </string>
- <node_path name="tracks/7/path"> "Armature/Skeleton:l-thigh" </node_path>
- <int name="tracks/7/interp"> 1 </int>
- <real_array name="tracks/7/keys" len="24"> 0, 1, 0, 2.08616e-07, 1.49012e-08, 0.284249, 0.0874448, 0.000525696, 0.954754, 1, 1, 1, 1.25, 1, 0, 2.08616e-07, 1.49012e-08, 0.284249, 0.0874448, 0.000525696, 0.954754, 1, 1, 1 </real_array>
- <string name="tracks/8/type"> "transform" </string>
- <node_path name="tracks/8/path"> "Armature/Skeleton:l-leg" </node_path>
- <int name="tracks/8/interp"> 1 </int>
- <real_array name="tracks/8/keys" len="24"> 0, 1, -6.98492e-10, -2.98023e-08, 4.76837e-07, -0.32359, -0.0556479, 0.000232734, 0.94456, 1, 1, 1, 1.25, 1, -6.98492e-10, -2.98023e-08, 4.76837e-07, -0.32359, -0.0556479, 0.000232734, 0.94456, 1, 1, 1 </real_array>
- <string name="tracks/9/type"> "transform" </string>
- <node_path name="tracks/9/path"> "Armature/Skeleton:l-foot" </node_path>
- <int name="tracks/9/interp"> 1 </int>
- <real_array name="tracks/9/keys" len="24"> 0, 1, 2.23517e-08, 1.19209e-07, 7.45058e-09, -0.260411, 0.0677016, 0.0123204, 0.963042, 1, 1, 1, 1.25, 1, 2.23517e-08, 1.19209e-07, 7.45058e-09, -0.260411, 0.0677016, 0.0123204, 0.963042, 1, 1, 1 </real_array>
- <string name="tracks/10/type"> "transform" </string>
- <node_path name="tracks/10/path"> "Armature/Skeleton:MASTER" </node_path>
- <int name="tracks/10/interp"> 1 </int>
- <real_array name="tracks/10/keys" len="24"> 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/11/type"> "transform" </string>
- <node_path name="tracks/11/path"> "Armature/Skeleton:HEAD" </node_path>
- <int name="tracks/11/interp"> 1 </int>
- <real_array name="tracks/11/keys" len="24"> 0, 1, -5.68434e-14, 0, 0.994808, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -5.68434e-14, 0, 0.994808, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/12/type"> "transform" </string>
- <node_path name="tracks/12/path"> "Armature/Skeleton:r-LEGCONTROL" </node_path>
- <int name="tracks/12/interp"> 1 </int>
- <real_array name="tracks/12/keys" len="24"> 0, 1, -0.142338, -0.593751, 0.041427, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.142338, -0.593751, 0.041427, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/13/type"> "transform" </string>
- <node_path name="tracks/13/path"> "Armature/Skeleton:l-LEGCONTROL" </node_path>
- <int name="tracks/13/interp"> 1 </int>
- <real_array name="tracks/13/keys" len="24"> 0, 1, 0.133965, 1.12742, 1.35169, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.133965, 1.12742, 1.35169, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/14/type"> "transform" </string>
- <node_path name="tracks/14/path"> "Armature/Skeleton:r-LEGORIENT" </node_path>
- <int name="tracks/14/interp"> 1 </int>
- <real_array name="tracks/14/keys" len="24"> 0, 1, 0.100474, 0.669825, -0.778672, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.100474, 0.669825, -0.778672, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/15/type"> "transform" </string>
- <node_path name="tracks/15/path"> "Armature/Skeleton:l-LEGORIENT" </node_path>
- <int name="tracks/15/interp"> 1 </int>
- <real_array name="tracks/15/keys" len="24"> 0, 1, -0.0204011, -0.122407, 5.96046e-08, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.0204011, -0.122407, 5.96046e-08, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/16/type"> "transform" </string>
- <node_path name="tracks/16/path"> "Armature/Skeleton:r-ARMCONTROL" </node_path>
- <int name="tracks/16/interp"> 1 </int>
- <real_array name="tracks/16/keys" len="24"> 0, 1, -0.868295, 0.288818, -0.834593, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.868295, 0.288818, -0.834593, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/17/type"> "transform" </string>
- <node_path name="tracks/17/path"> "Armature/Skeleton:l-ARMCONTROL" </node_path>
- <int name="tracks/17/interp"> 1 </int>
- <real_array name="tracks/17/keys" len="24"> 0, 1, 1.73339, 0.895247, 5.13844, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 1.73339, 0.895247, 5.13844, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/18/type"> "transform" </string>
- <node_path name="tracks/18/path"> "Armature/Skeleton:r-ARMORIENT" </node_path>
- <int name="tracks/18/interp"> 1 </int>
- <real_array name="tracks/18/keys" len="24"> 0, 1, 0.405204, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.405204, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/19/type"> "transform" </string>
- <node_path name="tracks/19/path"> "Armature/Skeleton:l-ARMORIENT" </node_path>
- <int name="tracks/19/interp"> 1 </int>
- <real_array name="tracks/19/keys" len="24"> 0, 1, -1.5774, 0.0723579, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -1.5774, 0.0723579, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/20/type"> "transform" </string>
- <node_path name="tracks/20/path"> "Armature/Skeleton:hip" </node_path>
- <int name="tracks/20/interp"> 1 </int>
- <real_array name="tracks/20/keys" len="24"> 0, 1, 0.050238, 0.697428, 0.108012, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1, 1.25, 1, 0.050238, 0.697428, 0.108012, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1 </real_array>
- <string name="tracks/21/type"> "transform" </string>
- <node_path name="tracks/21/path"> "Armature/Skeleton:waist" </node_path>
- <int name="tracks/21/interp"> 1 </int>
- <real_array name="tracks/21/keys" len="24"> 0, 1, 7.45059e-09, -5.21541e-08, 2.38419e-07, 0.0550011, -0.00481196, -0.0870228, 0.994675, 1, 1, 1, 1.25, 1, 7.45059e-09, -5.21541e-08, 2.38419e-07, 0.0550011, -0.00481196, -0.0870228, 0.994675, 1, 1, 1 </real_array>
- <string name="tracks/22/type"> "transform" </string>
- <node_path name="tracks/22/path"> "Armature/Skeleton:chest" </node_path>
- <int name="tracks/22/interp"> 1 </int>
- <real_array name="tracks/22/keys" len="108"> 0, 1, -1.93979e-09, 3.72529e-08, -1.78814e-07, 4.95597e-09, 0.00666624, -0.163159, 0.986577, 1, 1, 1, 0.05, 1, -1.93979e-09, 3.72529e-08, -1.78814e-07, -0.00988221, 0.00482982, -0.145309, 0.989325, 1, 1, 1, 0.1, 1, -1.93979e-09, 3.72529e-08, -1.78814e-07, -0.0244913, 0.00210965, -0.118794, 0.992615, 1, 1, 1, 0.15, 1, -1.93979e-09, 3.72529e-08, -1.78814e-07, -0.0278586, 0.00148179, -0.112662, 0.993242, 1, 1, 1, 0.2, 1, -1.93979e-09, 3.72529e-08, -1.78814e-07, -0.0242687, 0.00215113, -0.1192, 0.992571, 1, 1, 1, 0.35, 1, -1.93979e-09, 3.72529e-08, -1.78814e-07, -0.00360581, 0.00599648, -0.156654, 0.987629, 1, 1, 1, 0.4, 1, -1.93979e-09, 3.72529e-08, -1.78814e-07, -0.000519651, 0.00656974, -0.162222, 0.986732, 1, 1, 1, 0.45, 1, -1.93979e-09, 3.72529e-08, -1.78814e-07, 4.95597e-09, 0.00666624, -0.163159, 0.986577, 1, 1, 1, 1.25, 1, -1.93979e-09, 3.72529e-08, -1.78814e-07, 4.95597e-09, 0.00666624, -0.163159, 0.986577, 1, 1, 1 </real_array>
- <string name="tracks/23/type"> "transform" </string>
- <node_path name="tracks/23/path"> "Armature/Skeleton:neck" </node_path>
- <int name="tracks/23/interp"> 1 </int>
- <real_array name="tracks/23/keys" len="24"> 0, 1, -2.91038e-08, -1.78814e-07, -9.53674e-07, -7.45058e-09, 2.57076e-09, -2.87348e-09, 1, 1, 1, 1, 1.25, 1, -2.91038e-08, -1.78814e-07, -9.53674e-07, -7.45058e-09, 2.57076e-09, -2.87348e-09, 1, 1, 1, 1 </real_array>
- <string name="tracks/24/type"> "transform" </string>
- <node_path name="tracks/24/path"> "Armature/Skeleton:headtracker" </node_path>
- <int name="tracks/24/interp"> 1 </int>
- <real_array name="tracks/24/keys" len="108"> 0, 1, 1.05648e-08, -8.34465e-07, 8.61473e-09, 0.067043, -0.15676, 0.0458898, 0.984289, 1, 1, 1, 0.05, 1, -2.68221e-08, -7.7486e-07, -7.12462e-08, 0.0563978, -0.14039, 0.0396845, 0.987692, 1, 1, 1, 0.1, 1, 2.66356e-08, -1.78814e-07, -1.87429e-07, 0.0407343, -0.116242, 0.0305639, 0.991915, 1, 1, 1, 0.15, 1, -1.30386e-08, -3.57628e-07, -7.72998e-08, 0.0371396, -0.110688, 0.0284725, 0.992753, 1, 1, 1, 0.2, 1, 2.57045e-08, -5.96046e-07, -9.05711e-08, 0.0409678, -0.116604, 0.0306994, 0.991858, 1, 1, 1, 0.35, 1, 4.0076e-08, -1.78814e-07, -5.26197e-08, 0.0631478, -0.150775, 0.0436179, 0.985584, 1, 1, 1, 0.4, 1, 3.32831e-08, -5.36442e-07, 3.95812e-09, 0.0664811, -0.155897, 0.045562, 0.98448, 1, 1, 1, 0.45, 1, 1.05648e-08, -8.34465e-07, 8.61473e-09, 0.067043, -0.15676, 0.0458898, 0.984289, 1, 1, 1, 1.25, 1, 1.05648e-08, -8.34465e-07, 8.61473e-09, 0.067043, -0.15676, 0.0458898, 0.984289, 1, 1, 1 </real_array>
- <string name="tracks/25/type"> "transform" </string>
- <node_path name="tracks/25/path"> "Armature/Skeleton:head" </node_path>
- <int name="tracks/25/interp"> 1 </int>
- <real_array name="tracks/25/keys" len="24"> 0, 1, -7.38021e-13, 4.70318e-08, 9.16189e-08, -1.036e-25, -3.37508e-14, -8.17124e-13, 1, 1, 1, 1, 1.25, 1, -7.38021e-13, 4.70318e-08, 9.16189e-08, -1.036e-25, -3.37508e-14, -8.17124e-13, 1, 1, 1, 1 </real_array>
- <string name="tracks/26/type"> "transform" </string>
- <node_path name="tracks/26/path"> "Armature/Skeleton:vent" </node_path>
- <int name="tracks/26/interp"> 1 </int>
- <real_array name="tracks/26/keys" len="24"> 0, 1, 4.48982e-08, 0.00292331, 0.204329, 8.84756e-09, -3.8014e-13, 5.94471e-12, 1, 1, 1, 1, 1.25, 1, 4.48982e-08, 0.00292331, 0.204329, 8.84756e-09, -3.8014e-13, 5.94471e-12, 1, 1, 1, 1 </real_array>
-
- </resource>
- <resource type="Animation" path="local://9">
- <string name="resource/name"> "falling-cycle" </string>
- <real name="length"> 0.416667 </real>
- <bool name="loop"> True </bool>
- <real name="step"> 0.1 </real>
- <string name="tracks/0/type"> "transform" </string>
- <node_path name="tracks/0/path"> "Armature/Skeleton:r-arm" </node_path>
- <int name="tracks/0/interp"> 1 </int>
- <real_array name="tracks/0/keys" len="132"> 0, 1, 2.98023e-08, 1.19209e-07, -2.98023e-08, -0.336022, 0.262721, 0.175267, 0.887326, 1, 1, 1, 0.05, 1, 7.45058e-07, -3.57628e-07, 5.36442e-07, -0.336851, 0.262046, 0.173695, 0.887521, 1, 1, 1, 0.1, 1, 8.34465e-07, -5.96046e-07, 7.15256e-07, -0.33853, 0.260365, 0.16952, 0.888184, 1, 1, 1, 0.15, 1, 8.9407e-07, -3.57628e-07, 8.9407e-07, -0.338209, 0.258327, 0.163568, 0.890015, 1, 1, 1, 0.2, 1, 5.96046e-07, -3.57628e-07, 7.45058e-07, -0.333363, 0.256341, 0.157703, 0.89347, 1, 1, 1, 0.25, 1, 1.43051e-06, -8.34465e-07, 1.3113e-06, -0.339001, 0.253177, 0.158008, 0.892196, 1, 1, 0.999999, 0.3, 1, 5.96046e-07, -1.19209e-07, 2.98023e-07, -0.348081, 0.252511, 0.164449, 0.887713, 1, 1, 1, 0.35, 1, 1.07288e-06, -5.96046e-07, 7.45058e-07, -0.343056, 0.25799, 0.170697, 0.886914, 1, 1, 1, 0.4, 1, 3.27826e-07, 0, 2.38419e-07, -0.337258, 0.26196, 0.174599, 0.887214, 1, 1, 1, 0.45, 1, 2.98023e-08, 1.19209e-07, -2.98023e-08, -0.336022, 0.262721, 0.175267, 0.887326, 1, 1, 1, 1.25, 1, 2.98023e-08, 1.19209e-07, -2.98023e-08, -0.336022, 0.262721, 0.175267, 0.887326, 1, 1, 1 </real_array>
- <string name="tracks/1/type"> "transform" </string>
- <node_path name="tracks/1/path"> "Armature/Skeleton:r-forearm" </node_path>
- <int name="tracks/1/interp"> 1 </int>
- <real_array name="tracks/1/keys" len="120"> 0, 1, 3.27826e-07, -6.55651e-07, -4.17233e-07, 0.46904, -0.387773, 0.0221851, 0.793184, 1, 1, 1, 0.05, 1, -1.49012e-07, -8.34465e-07, -5.36442e-07, 0.467449, -0.38757, 0.0209387, 0.794256, 1, 0.999999, 1, 0.15, 1, 8.9407e-08, -8.34465e-07, -2.38419e-07, 0.457674, -0.38779, 0.0142454, 0.799969, 1, 1, 1, 0.2, 1, -1.19209e-07, -9.53674e-07, -5.96046e-07, 0.453414, -0.391376, 0.0115749, 0.800692, 1, 1, 1, 0.25, 1, -2.98023e-08, -8.64267e-07, -5.96046e-07, 0.455951, -0.392917, 0.0127032, 0.798476, 1, 1, 1, 0.3, 1, -2.68221e-07, -5.96046e-07, -3.57628e-07, 0.461696, -0.389009, 0.0167183, 0.797013, 1, 1, 1, 0.35, 1, 5.96046e-08, -9.23872e-07, -5.96046e-07, 0.465445, -0.38698, 0.0198743, 0.795747, 1, 1, 1, 0.4, 1, 2.68221e-07, -8.64267e-07, -6.55651e-07, 0.4685, -0.387548, 0.0218417, 0.793623, 1, 1, 1, 0.45, 1, 3.27826e-07, -6.55651e-07, -4.17233e-07, 0.46904, -0.387773, 0.0221851, 0.793184, 1, 1, 1, 1.25, 1, 3.27826e-07, -6.55651e-07, -4.17233e-07, 0.46904, -0.387773, 0.0221851, 0.793184, 1, 1, 1 </real_array>
- <string name="tracks/2/type"> "transform" </string>
- <node_path name="tracks/2/path"> "Armature/Skeleton:l-arm" </node_path>
- <int name="tracks/2/interp"> 1 </int>
- <real_array name="tracks/2/keys" len="132"> 0, 1, -2.98023e-08, 1.19209e-07, -2.98023e-08, -0.326141, -0.23441, -0.185472, 0.896819, 1, 1, 1, 0.05, 1, -9.53674e-07, -4.76837e-07, 5.66244e-07, -0.309655, -0.239675, -0.179325, 0.902503, 1, 1, 1, 0.1, 1, -8.64267e-07, -4.76837e-07, 7.15256e-07, -0.27681, -0.251556, -0.166111, 0.912416, 1, 1, 1, 0.15, 1, -8.64267e-07, -3.57628e-07, 8.04663e-07, -0.254018, -0.264552, -0.15679, 0.917008, 1, 1, 1, 0.2, 1, -4.76837e-07, -3.57628e-07, 4.47035e-07, -0.251196, -0.272504, -0.156931, 0.915431, 1, 1, 1, 0.25, 1, -1.13249e-06, -7.15256e-07, 8.9407e-07, -0.279016, -0.258742, -0.169921, 0.909027, 1, 1, 1, 0.3, 1, -7.15256e-07, 1.19209e-07, 5.06639e-07, -0.316679, -0.238757, -0.183476, 0.89947, 1, 1, 1, 0.35, 1, -6.25849e-07, -1.19209e-07, 3.57628e-07, -0.327726, -0.235686, -0.18601, 0.895795, 1, 1, 1, 0.4, 1, -2.68221e-07, 0, 1.49012e-07, -0.326797, -0.234512, -0.185665, 0.896514, 1, 1, 1, 0.45, 1, -2.98023e-08, 1.19209e-07, -2.98023e-08, -0.326141, -0.23441, -0.185472, 0.896819, 1, 1, 1, 1.25, 1, -2.98023e-08, 1.19209e-07, -2.98023e-08, -0.326141, -0.23441, -0.185472, 0.896819, 1, 1, 1 </real_array>
- <string name="tracks/3/type"> "transform" </string>
- <node_path name="tracks/3/path"> "Armature/Skeleton:l-forearm" </node_path>
- <int name="tracks/3/interp"> 1 </int>
- <real_array name="tracks/3/keys" len="120"> 0, 1, -2.08616e-07, -1.54972e-06, -1.19209e-07, 0.47174, 0.366267, -0.0198596, 0.80182, 1, 1, 1, 0.05, 1, -2.98023e-08, -6.25849e-07, 0, 0.468656, 0.375596, -0.0166676, 0.799382, 1, 1, 1, 0.1, 1, -8.9407e-08, -2.68221e-07, -5.96046e-08, 0.459943, 0.392089, -0.0107327, 0.79662, 1, 1, 1, 0.15, 1, -2.08616e-07, -2.08616e-07, -2.38419e-07, 0.451048, 0.400355, -0.00696642, 0.797636, 1, 1, 1, 0.2, 1, -2.38419e-07, -7.7486e-07, 0, 0.448637, 0.398723, -0.00658308, 0.799813, 1, 1, 1, 0.3, 1, -5.96046e-08, -2.98023e-07, -4.17233e-07, 0.465357, 0.361793, -0.0151844, 0.807662, 1, 1, 1, 0.35, 1, -1.49012e-07, -5.36442e-07, -3.57628e-07, 0.468536, 0.360417, -0.0183993, 0.806372, 1, 1, 1, 0.4, 1, -5.96046e-08, -8.64267e-07, -1.78814e-07, 0.471244, 0.365087, -0.0196777, 0.802654, 1, 1, 1, 0.45, 1, -2.08616e-07, -1.54972e-06, -1.19209e-07, 0.47174, 0.366267, -0.0198596, 0.80182, 1, 1, 1, 1.25, 1, -2.08616e-07, -1.54972e-06, -1.19209e-07, 0.47174, 0.366267, -0.0198596, 0.80182, 1, 1, 1 </real_array>
- <string name="tracks/4/type"> "transform" </string>
- <node_path name="tracks/4/path"> "Armature/Skeleton:r-thigh" </node_path>
- <int name="tracks/4/interp"> 1 </int>
- <real_array name="tracks/4/keys" len="132"> 0, 1, 0, 7.45058e-09, -1.3411e-07, -0.0625169, 0.00920125, -0.00328561, 0.997996, 1, 1, 1, 0.05, 1, 5.96046e-08, 8.9407e-08, -6.10948e-07, -0.0877092, 0.00901381, -0.00306586, 0.996101, 1, 1, 1, 0.1, 1, 5.96046e-08, -2.23517e-08, -1.19209e-07, -0.138998, 0.00794913, -0.00288258, 0.990257, 1, 1, 1, 0.15, 1, 5.96046e-08, 1.49012e-08, -4.02331e-07, -0.178155, 0.00579277, -0.00296187, 0.983981, 1, 1, 1, 0.2, 1, 8.9407e-08, 0, 1.78814e-07, -0.18648, 0.0038127, -0.0029159, 0.982447, 1, 1, 1, 0.25, 1, 5.96046e-08, 5.21541e-08, -1.93715e-07, -0.189861, 0.00940162, -0.00299906, 0.981761, 1, 1, 1, 0.3, 1, 5.96046e-08, -5.96046e-08, 2.83122e-07, -0.170763, 0.015059, -0.00307746, 0.985192, 1, 1, 1, 0.35, 1, 0, -7.45058e-09, -1.3411e-07, -0.115285, 0.0123617, -0.00312517, 0.993251, 1, 1, 1, 0.4, 1, 0, 7.45058e-09, -1.3411e-07, -0.0713277, 0.00977016, -0.00325209, 0.9974, 1, 1, 1, 0.45, 1, 0, 7.45058e-09, -1.3411e-07, -0.0625169, 0.00920125, -0.00328561, 0.997996, 1, 1, 1, 1.25, 1, 0, 7.45058e-09, -1.3411e-07, -0.0625169, 0.00920125, -0.00328561, 0.997996, 1, 1, 1 </real_array>
- <string name="tracks/5/type"> "transform" </string>
- <node_path name="tracks/5/path"> "Armature/Skeleton:r-leg" </node_path>
- <int name="tracks/5/interp"> 1 </int>
- <real_array name="tracks/5/keys" len="120"> 0, 1, 4.42378e-08, -8.19564e-08, 1.78814e-07, -0.407694, 0.0277893, 0.000765211, 0.912696, 1, 1, 1, 0.05, 1, 1.89757e-08, -5.21541e-08, 6.55651e-07, -0.435809, 0.0297697, 0.000893482, 0.899546, 1, 1, 1, 0.1, 1, 1.42027e-08, 6.70552e-08, 7.15256e-07, -0.489147, 0.0339313, 0.00115069, 0.871541, 1, 1, 1, 0.15, 1, 1.13854e-07, 0, 5.96046e-07, -0.523927, 0.0370339, 0.00133512, 0.850957, 1, 1, 1, 0.2, 1, 1.29221e-07, -3.72529e-08, 4.17233e-07, -0.526448, 0.0372296, 0.00134975, 0.849391, 1, 1, 1, 0.25, 1, 1.6077e-07, -2.68221e-07, 4.76837e-07, -0.538369, 0.0372441, 0.00135905, 0.841885, 1, 1, 1, 0.3, 1, 6.17001e-09, -1.04308e-07, 7.15256e-07, -0.530237, 0.0358611, 0.00127618, 0.84709, 1, 1, 1, 0.4, 1, 2.08383e-08, -2.23517e-08, 4.17233e-07, -0.418447, 0.0284447, 0.00080823, 0.907795, 1, 1, 1, 0.45, 1, 4.42378e-08, -8.19564e-08, 1.78814e-07, -0.407694, 0.0277893, 0.000765211, 0.912696, 1, 1, 1, 1.25, 1, 4.42378e-08, -8.19564e-08, 1.78814e-07, -0.407694, 0.0277893, 0.000765211, 0.912696, 1, 1, 1 </real_array>
- <string name="tracks/6/type"> "transform" </string>
- <node_path name="tracks/6/path"> "Armature/Skeleton:r-foot" </node_path>
- <int name="tracks/6/interp"> 1 </int>
- <real_array name="tracks/6/keys" len="24"> 0, 1, 1.04308e-07, -1.19209e-07, 6.70552e-08, -1.11759e-08, 1.16415e-09, 7.45058e-09, 1, 1, 1, 1, 1.25, 1, 1.04308e-07, -1.19209e-07, 6.70552e-08, -1.11759e-08, 1.16415e-09, 7.45058e-09, 1, 1, 1, 1 </real_array>
- <string name="tracks/7/type"> "transform" </string>
- <node_path name="tracks/7/path"> "Armature/Skeleton:l-thigh" </node_path>
- <int name="tracks/7/interp"> 1 </int>
- <real_array name="tracks/7/keys" len="120"> 0, 1, -2.98023e-08, 1.49012e-08, 1.19209e-07, -0.630421, -0.0882657, 0.00990556, 0.771155, 1, 1, 1, 0.05, 1, 8.9407e-08, 9.68575e-08, -2.38419e-07, -0.641086, -0.0918399, 0.00914405, 0.7619, 1, 1, 1, 0.15, 1, 5.96046e-08, 2.23517e-08, -1.3411e-07, -0.695929, -0.109196, 0.0054072, 0.70974, 1, 1, 1, 0.2, 1, 0, 7.45058e-09, 4.61936e-07, -0.716484, -0.115048, 0.00471066, 0.688035, 0.999999, 1, 1, 0.25, 1, 2.98023e-08, 5.21541e-08, 7.45058e-08, -0.742062, -0.116709, 0.0109015, 0.660003, 1, 1, 1, 0.3, 1, -5.96046e-08, -6.70552e-08, 5.51343e-07, -0.738131, -0.110711, 0.0165993, 0.665304, 0.999999, 1, 1, 0.35, 1, -2.98023e-08, -1.49012e-08, 1.19209e-07, -0.683291, -0.098194, 0.0131016, 0.723395, 1, 1, 1, 0.4, 1, -2.98023e-08, 1.49012e-08, 1.19209e-07, -0.638973, -0.0897534, 0.0103931, 0.763904, 1, 1, 1, 0.45, 1, -2.98023e-08, 1.49012e-08, 1.19209e-07, -0.630421, -0.0882657, 0.00990556, 0.771155, 1, 1, 1, 1.25, 1, -2.98023e-08, 1.49012e-08, 1.19209e-07, -0.630421, -0.0882657, 0.00990556, 0.771155, 1, 1, 1 </real_array>
- <string name="tracks/8/type"> "transform" </string>
- <node_path name="tracks/8/path"> "Armature/Skeleton:l-leg" </node_path>
- <int name="tracks/8/interp"> 1 </int>
- <real_array name="tracks/8/keys" len="120"> 0, 1, 4.48199e-08, -1.11759e-07, 1.78814e-07, -0.822993, -0.106344, -0.00540277, 0.557982, 1, 1, 1, 0.05, 1, 4.30737e-09, -2.08616e-07, -1.19209e-07, -0.827005, -0.107477, -0.00546779, 0.551799, 1, 1, 1, 0.1, 1, 8.84756e-09, -1.19209e-07, 1.19209e-07, -0.836608, -0.110063, -0.00562015, 0.536601, 1, 1, 1, 0.2, 1, -2.91038e-08, 1.19209e-07, 0, -0.857806, -0.115929, -0.00596456, 0.500693, 1, 1, 1, 0.25, 1, 7.33417e-09, 0, 5.96046e-08, 0.876669, 0.123709, 0.00633999, -0.464874, 1, 1, 1, 0.3, 1, -4.38886e-08, -1.3411e-07, -1.19209e-07, 0.881066, 0.125876, 0.00641456, -0.455891, 1, 1, 1, 0.35, 1, 9.66247e-09, 0, -5.96046e-08, -0.853515, -0.11545, -0.00587343, 0.508083, 1, 1, 1, 0.4, 1, 2.17697e-08, -3.72529e-08, 5.96046e-08, -0.828218, -0.107764, -0.00547631, 0.549921, 1, 1, 1, 0.45, 1, 4.48199e-08, -1.11759e-07, 1.78814e-07, -0.822993, -0.106344, -0.00540277, 0.557982, 1, 1, 1, 1.25, 1, 4.48199e-08, -1.11759e-07, 1.78814e-07, -0.822993, -0.106344, -0.00540277, 0.557982, 1, 1, 1 </real_array>
- <string name="tracks/9/type"> "transform" </string>
- <node_path name="tracks/9/path"> "Armature/Skeleton:l-foot" </node_path>
- <int name="tracks/9/interp"> 1 </int>
- <real_array name="tracks/9/keys" len="24"> 0, 1, 7.45058e-09, -2.38419e-07, -8.19564e-08, -1.86265e-08, -1.28057e-09, 3.72529e-09, 1, 1, 1, 1, 1.25, 1, 7.45058e-09, -2.38419e-07, -8.19564e-08, -1.86265e-08, -1.28057e-09, 3.72529e-09, 1, 1, 1, 1 </real_array>
- <string name="tracks/10/type"> "transform" </string>
- <node_path name="tracks/10/path"> "Armature/Skeleton:MASTER" </node_path>
- <int name="tracks/10/interp"> 1 </int>
- <real_array name="tracks/10/keys" len="24"> 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/11/type"> "transform" </string>
- <node_path name="tracks/11/path"> "Armature/Skeleton:HEAD" </node_path>
- <int name="tracks/11/interp"> 1 </int>
- <real_array name="tracks/11/keys" len="108"> 0, 1, -5.68434e-14, 0, 2.81136, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -5.68434e-14, 0, 2.88275, 0, 0, 0, 1, 1, 1, 1, 0.15, 1, 5.68434e-14, 4.76837e-07, 3.22584, 0, 0, 0, 1, 1, 1, 1, 0.2, 1, 5.68434e-14, 4.76837e-07, 3.31311, 0, 0, -7.10543e-15, 1, 1, 1, 1, 0.25, 1, 5.68434e-14, 4.76837e-07, 3.27685, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, -5.68434e-14, 0, 2.93405, 0, 0, -7.10543e-15, 1, 1, 1, 1, 0.4, 1, -5.68434e-14, 0, 2.82965, 0, 0, 0, 1, 1, 1, 1, 0.45, 1, -5.68434e-14, 0, 2.81136, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -5.68434e-14, 0, 2.81136, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/12/type"> "transform" </string>
- <node_path name="tracks/12/path"> "Armature/Skeleton:r-LEGCONTROL" </node_path>
- <int name="tracks/12/interp"> 1 </int>
- <real_array name="tracks/12/keys" len="120"> 0, 1, -5.96046e-08, 0.623878, 0.831837, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -5.96046e-08, 0.623878, 0.85661, 0, 0, 0, 1, 1, 1, 1, 0.1, 1, -5.96046e-08, 0.623878, 0.907642, 0, 0, 0, 1, 1, 1, 1, 0.15, 1, -5.96046e-08, 0.623878, 0.942906, 0, 0, 0, 1, 1, 1, 1, 0.2, 1, -5.96046e-08, 0.623878, 0.943599, 0, 0, 0, 1, 1, 1, 1, 0.25, 1, -5.96046e-08, 0.623878, 0.921011, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, -5.96046e-08, 0.623878, 0.851786, 0, 0, 0, 1, 1, 1, 1, 0.4, 1, -5.96046e-08, 0.623878, 0.834743, 0, 0, 0, 1, 1, 1, 1, 0.45, 1, -5.96046e-08, 0.623878, 0.831837, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -5.96046e-08, 0.623878, 0.831837, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/13/type"> "transform" </string>
- <node_path name="tracks/13/path"> "Armature/Skeleton:l-LEGCONTROL" </node_path>
- <int name="tracks/13/interp"> 1 </int>
- <real_array name="tracks/13/keys" len="132"> 0, 1, -1.19209e-07, 1.00668e-07, 1.33339, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -1.19209e-07, 1.01535e-07, 1.34488, 0, 0, 0, 1, 1, 1, 1, 0.1, 1, -1.19209e-07, 1.0373e-07, 1.37395, 0, 0, 0, 1, 1, 1, 1, 0.15, 1, -1.19209e-07, 1.06482e-07, 1.41041, 0, 0, 0, 1, 1, 1, 1, 0.2, 1, -1.19209e-07, 1.08677e-07, 1.43947, 0, 0, 0, 1, 1, 1, 1, 0.25, 1, -1.19209e-07, 1.09544e-07, 1.45096, 0, 0, 0, 1, 1, 1, 1, 0.3, 1, -1.19209e-07, 1.07675e-07, 1.4262, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, -1.19209e-07, 1.03822e-07, 1.37517, 0, 0, 0, 1, 1, 1, 1, 0.4, 1, -1.19209e-07, 1.01159e-07, 1.33989, 0, 0, 0, 1, 1, 1, 1, 0.45, 1, -1.19209e-07, 1.00668e-07, 1.33339, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -1.19209e-07, 1.00668e-07, 1.33339, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/14/type"> "transform" </string>
- <node_path name="tracks/14/path"> "Armature/Skeleton:r-LEGORIENT" </node_path>
- <int name="tracks/14/interp"> 1 </int>
- <real_array name="tracks/14/keys" len="24"> 0, 1, -2.98023e-08, 1.19209e-07, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -2.98023e-08, 1.19209e-07, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/15/type"> "transform" </string>
- <node_path name="tracks/15/path"> "Armature/Skeleton:l-LEGORIENT" </node_path>
- <int name="tracks/15/interp"> 1 </int>
- <real_array name="tracks/15/keys" len="24"> 0, 1, 2.98023e-08, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 2.98023e-08, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/16/type"> "transform" </string>
- <node_path name="tracks/16/path"> "Armature/Skeleton:r-ARMCONTROL" </node_path>
- <int name="tracks/16/interp"> 1 </int>
- <real_array name="tracks/16/keys" len="132"> 0, 1, -1.39671, 2.72686, 1.19541, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -1.39671, 2.70532, 1.19971, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, -1.39671, 2.65088, 1.2106, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.15, 1, -1.39671, 2.5826, 1.22425, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.2, 1, -1.39671, 2.52819, 1.23514, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.25, 1, -1.39671, 2.50668, 1.23944, 0, 0, 0, 1, 1, 1, 1, 0.3, 1, -1.39671, 2.55303, 1.23017, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.35, 1, -1.39671, 2.64856, 1.21105, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, -1.39671, 2.71466, 1.19784, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, -1.39671, 2.72686, 1.19541, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -1.39671, 2.72686, 1.19541, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/17/type"> "transform" </string>
- <node_path name="tracks/17/path"> "Armature/Skeleton:l-ARMCONTROL" </node_path>
- <int name="tracks/17/interp"> 1 </int>
- <real_array name="tracks/17/keys" len="120"> 0, 1, 1.27388, 2.72686, 1.19541, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 1.27388, 2.68042, 1.20468, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, 1.27388, 2.58486, 1.2238, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.15, 1, 1.27388, 2.51885, 1.23701, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.2, 1, 1.27388, 2.51756, 1.23727, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.25, 1, 1.27388, 2.55985, 1.22881, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, 1.27388, 2.68948, 1.20288, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, 1.27388, 2.72141, 1.19649, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, 1.27388, 2.72686, 1.19541, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 1.27388, 2.72686, 1.19541, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/18/type"> "transform" </string>
- <node_path name="tracks/18/path"> "Armature/Skeleton:r-ARMORIENT" </node_path>
- <int name="tracks/18/interp"> 1 </int>
- <real_array name="tracks/18/keys" len="24"> 0, 1, 0.59069, -0.00390959, 0.736489, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.59069, -0.00390959, 0.736489, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/19/type"> "transform" </string>
- <node_path name="tracks/19/path"> "Armature/Skeleton:l-ARMORIENT" </node_path>
- <int name="tracks/19/interp"> 1 </int>
- <real_array name="tracks/19/keys" len="24"> 0, 1, -0.59069, -0.00390959, 0.736489, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.59069, -0.00390959, 0.736489, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/20/type"> "transform" </string>
- <node_path name="tracks/20/path"> "Armature/Skeleton:hip" </node_path>
- <int name="tracks/20/interp"> 1 </int>
- <real_array name="tracks/20/keys" len="120"> 0, 1, -9.25123e-16, 1.16368e-07, -0.513782, -0.068257, 1.03065e-08, 8.40178e-15, 0.997668, 1, 1, 1, 0.05, 1, -0.00604435, -0.0171726, -0.516875, -0.068257, 1.03065e-08, 1.59689e-14, 0.997668, 1, 1, 1, 0.15, 1, -0.0352723, -0.100186, -0.531832, -0.068257, 1.03065e-08, 8.79127e-15, 0.997668, 1, 1, 1, 0.2, 1, -0.0427212, -0.121339, -0.535645, -0.068257, 1.03065e-08, 1.59689e-14, 0.997668, 1, 1, 1, 0.25, 1, -0.0251165, -0.102747, -0.494262, -0.068257, 1.03065e-08, 8.40178e-15, 0.997668, 1, 1, 1, 0.3, 1, -0.00387635, -0.0612733, -0.455449, -0.068257, 1.03065e-08, 8.79127e-15, 0.997668, 1, 1, 1, 0.35, 1, -0.000906605, -0.0266833, -0.479965, -0.068257, 1.03065e-08, 1.59689e-14, 0.997668, 1, 1, 1, 0.4, 1, -5.88306e-05, -0.00401501, -0.507859, -0.068257, 1.03065e-08, 8.79127e-15, 0.997668, 1, 1, 1, 0.45, 1, -9.25123e-16, 1.16368e-07, -0.513782, -0.068257, 1.03065e-08, 8.40178e-15, 0.997668, 1, 1, 1, 1.25, 1, -9.25123e-16, 1.16368e-07, -0.513782, -0.068257, 1.03065e-08, 8.40178e-15, 0.997668, 1, 1, 1 </real_array>
- <string name="tracks/21/type"> "transform" </string>
- <node_path name="tracks/21/path"> "Armature/Skeleton:waist" </node_path>
- <int name="tracks/21/interp"> 1 </int>
- <real_array name="tracks/21/keys" len="108"> 0, 1, -5.25618e-15, 1.49011e-08, -1.49012e-07, 0.0904093, -6.07213e-16, 7.18977e-15, 0.995905, 1, 1, 1, 0.05, 1, -2.67973e-10, 2.32644e-08, -5.96046e-08, 0.0920949, -3.47794e-16, 7.16792e-15, 0.99575, 1, 1, 1, 0.15, 1, 2.52298e-09, 2.61876e-08, -2.98023e-08, 0.100243, -1.17281e-15, 7.25956e-15, 0.994963, 1, 1, 1, 0.2, 1, -5.62989e-10, 3.32728e-08, -1.49012e-07, 0.102318, -1.15767e-15, 7.26199e-15, 0.994752, 1, 1, 1, 0.25, 1, -1.24048e-09, 3.35948e-08, -8.9407e-08, 0.101456, -6.3375e-16, 7.20691e-15, 0.99484, 1, 1, 1, 0.35, 1, 8.229e-13, 2.99392e-08, -1.49012e-07, 0.0933096, -3.39049e-16, 7.16834e-15, 0.995637, 1, 1, 1, 0.4, 1, -3.31995e-12, 2.53408e-08, -1.49012e-07, 0.0908406, -1.44454e-15, 1.31767e-16, 0.995865, 1, 1, 1, 0.45, 1, -5.25618e-15, 1.49011e-08, -1.49012e-07, 0.0904093, -6.07213e-16, 7.18977e-15, 0.995905, 1, 1, 1, 1.25, 1, -5.25618e-15, 1.49011e-08, -1.49012e-07, 0.0904093, -6.07213e-16, 7.18977e-15, 0.995905, 1, 1, 1 </real_array>
- <string name="tracks/22/type"> "transform" </string>
- <node_path name="tracks/22/path"> "Armature/Skeleton:chest" </node_path>
- <int name="tracks/22/interp"> 1 </int>
- <real_array name="tracks/22/keys" len="108"> 0, 1, -1.31025e-21, 7.45058e-09, -1.78814e-07, 0.0570428, -7.52314e-16, -1.03276e-15, 0.998372, 1, 1, 1, 0.05, 1, -6.93196e-14, 7.45058e-09, 0, 0.0590419, -0.00284152, 0.000283556, 0.998251, 1, 1, 1, 0.15, 1, 7.44988e-10, -3.72529e-09, 0, 0.0686997, -0.0165823, 0.00165476, 0.997498, 1, 1, 1, 0.2, 1, -7.04617e-14, -7.45058e-09, -5.96046e-08, 0.0711578, -0.0200834, 0.00200414, 0.997261, 1, 1, 1, 0.25, 1, -6.96491e-14, -3.72529e-09, -5.96046e-08, 0.0701373, -0.0186297, 0.00185908, 0.997362, 1, 1, 1, 0.35, 1, 6.97804e-11, 7.45058e-09, -1.78814e-07, 0.0604823, -0.00488944, 0.000487919, 0.998157, 1, 1, 1, 0.4, 1, -2.75782e-14, 1.11759e-08, -2.38419e-07, 0.0575543, -0.000727023, 7.25494e-05, 0.998342, 1, 1, 1, 0.45, 1, -1.31025e-21, 7.45058e-09, -1.78814e-07, 0.0570428, -7.52314e-16, -1.03276e-15, 0.998372, 1, 1, 1, 1.25, 1, -1.31025e-21, 7.45058e-09, -1.78814e-07, 0.0570428, -7.52314e-16, -1.03276e-15, 0.998372, 1, 1, 1 </real_array>
- <string name="tracks/23/type"> "transform" </string>
- <node_path name="tracks/23/path"> "Armature/Skeleton:neck" </node_path>
- <int name="tracks/23/interp"> 1 </int>
- <real_array name="tracks/23/keys" len="24"> 0, 1, -8.52651e-14, -4.47035e-08, -4.76837e-07, -7.45058e-09, 2.13163e-14, -1.77636e-15, 1, 1, 1, 1, 1.25, 1, -8.52651e-14, -4.47035e-08, -4.76837e-07, -7.45058e-09, 2.13163e-14, -1.77636e-15, 1, 1, 1, 1 </real_array>
- <string name="tracks/24/type"> "transform" </string>
- <node_path name="tracks/24/path"> "Armature/Skeleton:headtracker" </node_path>
- <int name="tracks/24/interp"> 1 </int>
- <real_array name="tracks/24/keys" len="120"> 0, 1, 1.77636e-14, -4.17233e-07, -3.53903e-08, -0.197724, -1.34662e-08, 4.54456e-08, 0.980258, 1, 1, 1, 0.05, 1, -1.95943e-09, -5.06639e-07, -6.40284e-08, -0.199636, 0.000196518, -0.00285815, 0.979866, 1, 1, 1, 0.15, 1, -2.19083e-08, -2.38419e-07, -5.75092e-08, -0.207914, 0.00144056, -0.0167025, 0.978003, 1, 1, 1, 0.2, 1, 6.08469e-09, -3.8743e-07, -6.33299e-08, -0.209803, 0.00183038, -0.0202351, 0.977533, 1, 1, 1, 0.25, 1, -4.45088e-08, -8.64267e-07, -5.21541e-08, -0.20649, 0.000358444, -0.0190238, 0.978264, 1, 1, 1, 0.3, 1, 7.56265e-09, -8.34465e-07, -4.84288e-08, -0.200537, -0.000986884, -0.0126263, 0.979604, 1, 1, 1, 0.35, 1, 3.42126e-11, -4.17233e-07, -2.37487e-08, -0.198104, -0.000490507, -0.00505109, 0.980168, 1, 1, 1, 0.4, 1, 3.9655e-10, -3.57628e-07, -3.05008e-08, -0.197722, -8.26043e-05, -0.000750033, 0.980258, 1, 1, 1, 0.45, 1, 1.77636e-14, -4.17233e-07, -3.53903e-08, -0.197724, -1.34662e-08, 4.54456e-08, 0.980258, 1, 1, 1, 1.25, 1, 1.77636e-14, -4.17233e-07, -3.53903e-08, -0.197724, -1.34662e-08, 4.54456e-08, 0.980258, 1, 1, 1 </real_array>
- <string name="tracks/25/type"> "transform" </string>
- <node_path name="tracks/25/path"> "Armature/Skeleton:head" </node_path>
- <int name="tracks/25/interp"> 1 </int>
- <real_array name="tracks/25/keys" len="24"> 0, 1, 2.81164e-14, 2.468e-08, 3.32249e-07, 2.23517e-08, -5.32907e-15, 7.10543e-15, 1, 1, 1, 1, 1.25, 1, 2.81164e-14, 2.468e-08, 3.32249e-07, 2.23517e-08, -5.32907e-15, 7.10543e-15, 1, 1, 1, 1 </real_array>
- <string name="tracks/26/type"> "transform" </string>
- <node_path name="tracks/26/path"> "Armature/Skeleton:vent" </node_path>
- <int name="tracks/26/interp"> 1 </int>
- <real_array name="tracks/26/keys" len="24"> 0, 1, 7.99361e-14, 1.49012e-07, -8.34465e-07, 2.43308e-08, 6.21725e-15, -8.59209e-15, 1, 1, 1, 1, 1.25, 1, 7.99361e-14, 1.49012e-07, -8.34465e-07, 2.43308e-08, 6.21725e-15, -8.59209e-15, 1, 1, 1, 1 </real_array>
-
- </resource>
- <resource type="Animation" path="local://10">
- <string name="resource/name"> "default" </string>
- <real name="length"> 1.25 </real>
- <bool name="loop"> False </bool>
- <real name="step"> 0.1 </real>
- <string name="tracks/0/type"> "transform" </string>
- <node_path name="tracks/0/path"> "Armature/Skeleton:r-arm" </node_path>
- <int name="tracks/0/interp"> 1 </int>
- <real_array name="tracks/0/keys" len="12"> 0, 1, 5.06639e-07, -1.19209e-07, 3.57628e-07, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/1/type"> "transform" </string>
- <node_path name="tracks/1/path"> "Armature/Skeleton:r-forearm" </node_path>
- <int name="tracks/1/interp"> 1 </int>
- <real_array name="tracks/1/keys" len="12"> 0, 1, 1.19209e-07, -8.9407e-07, -1.19209e-07, -3.72529e-08, -1.49012e-08, 2.23517e-08, 1, 1, 1, 1 </real_array>
- <string name="tracks/2/type"> "transform" </string>
- <node_path name="tracks/2/path"> "Armature/Skeleton:l-arm" </node_path>
- <int name="tracks/2/interp"> 1 </int>
- <real_array name="tracks/2/keys" len="12"> 0, 1, -5.06639e-07, -1.19209e-07, 3.57628e-07, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/3/type"> "transform" </string>
- <node_path name="tracks/3/path"> "Armature/Skeleton:l-forearm" </node_path>
- <int name="tracks/3/interp"> 1 </int>
- <real_array name="tracks/3/keys" len="12"> 0, 1, -1.19209e-07, -8.9407e-07, -1.19209e-07, -3.72529e-08, 1.49012e-08, -2.23517e-08, 1, 1, 1, 1 </real_array>
- <string name="tracks/4/type"> "transform" </string>
- <node_path name="tracks/4/path"> "Armature/Skeleton:r-thigh" </node_path>
- <int name="tracks/4/interp"> 1 </int>
- <real_array name="tracks/4/keys" len="12"> 0, 1, 0, 2.98023e-08, -2.5332e-07, 0, 5.20417e-18, -2.79397e-09, 1, 1, 1, 1 </real_array>
- <string name="tracks/5/type"> "transform" </string>
- <node_path name="tracks/5/path"> "Armature/Skeleton:r-leg" </node_path>
- <int name="tracks/5/interp"> 1 </int>
- <real_array name="tracks/5/keys" len="12"> 0, 1, 2.10712e-08, -7.45058e-09, 5.96046e-07, 7.45058e-09, 3.60887e-09, 3.91446e-09, 1, 1, 1, 1 </real_array>
- <string name="tracks/6/type"> "transform" </string>
- <node_path name="tracks/6/path"> "Armature/Skeleton:r-foot" </node_path>
- <int name="tracks/6/interp"> 1 </int>
- <real_array name="tracks/6/keys" len="12"> 0, 1, 6.70552e-08, 1.19209e-07, 0, 3.72529e-09, 1.16415e-09, 3.72529e-09, 1, 1, 1, 1 </real_array>
- <string name="tracks/7/type"> "transform" </string>
- <node_path name="tracks/7/path"> "Armature/Skeleton:l-thigh" </node_path>
- <int name="tracks/7/interp"> 1 </int>
- <real_array name="tracks/7/keys" len="12"> 0, 1, 0, 2.98023e-08, -1.49012e-08, 1.86265e-09, 7.45058e-09, 2.09548e-09, 1, 1, 1, 1 </real_array>
- <string name="tracks/8/type"> "transform" </string>
- <node_path name="tracks/8/path"> "Armature/Skeleton:l-leg" </node_path>
- <int name="tracks/8/interp"> 1 </int>
- <real_array name="tracks/8/keys" len="12"> 0, 1, 1.74623e-08, -2.98023e-08, 2.98023e-07, 3.72529e-09, 7.45058e-09, -1.17143e-09, 1, 1, 1, 1 </real_array>
- <string name="tracks/9/type"> "transform" </string>
- <node_path name="tracks/9/path"> "Armature/Skeleton:l-foot" </node_path>
- <int name="tracks/9/interp"> 1 </int>
- <real_array name="tracks/9/keys" len="12"> 0, 1, 1.49012e-08, 0, 0, 0, -1.39698e-09, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/10/type"> "transform" </string>
- <node_path name="tracks/10/path"> "Armature/Skeleton:MASTER" </node_path>
- <int name="tracks/10/interp"> 1 </int>
- <real_array name="tracks/10/keys" len="12"> 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/11/type"> "transform" </string>
- <node_path name="tracks/11/path"> "Armature/Skeleton:HEAD" </node_path>
- <int name="tracks/11/interp"> 1 </int>
- <real_array name="tracks/11/keys" len="12"> 0, 1, -5.68434e-14, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/12/type"> "transform" </string>
- <node_path name="tracks/12/path"> "Armature/Skeleton:r-LEGCONTROL" </node_path>
- <int name="tracks/12/interp"> 1 </int>
- <real_array name="tracks/12/keys" len="12"> 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/13/type"> "transform" </string>
- <node_path name="tracks/13/path"> "Armature/Skeleton:l-LEGCONTROL" </node_path>
- <int name="tracks/13/interp"> 1 </int>
- <real_array name="tracks/13/keys" len="12"> 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/14/type"> "transform" </string>
- <node_path name="tracks/14/path"> "Armature/Skeleton:r-LEGORIENT" </node_path>
- <int name="tracks/14/interp"> 1 </int>
- <real_array name="tracks/14/keys" len="12"> 0, 1, -2.98023e-08, 1.19209e-07, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/15/type"> "transform" </string>
- <node_path name="tracks/15/path"> "Armature/Skeleton:l-LEGORIENT" </node_path>
- <int name="tracks/15/interp"> 1 </int>
- <real_array name="tracks/15/keys" len="12"> 0, 1, 2.98023e-08, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/16/type"> "transform" </string>
- <node_path name="tracks/16/path"> "Armature/Skeleton:r-ARMCONTROL" </node_path>
- <int name="tracks/16/interp"> 1 </int>
- <real_array name="tracks/16/keys" len="12"> 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/17/type"> "transform" </string>
- <node_path name="tracks/17/path"> "Armature/Skeleton:l-ARMCONTROL" </node_path>
- <int name="tracks/17/interp"> 1 </int>
- <real_array name="tracks/17/keys" len="12"> 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/18/type"> "transform" </string>
- <node_path name="tracks/18/path"> "Armature/Skeleton:r-ARMORIENT" </node_path>
- <int name="tracks/18/interp"> 1 </int>
- <real_array name="tracks/18/keys" len="12"> 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/19/type"> "transform" </string>
- <node_path name="tracks/19/path"> "Armature/Skeleton:l-ARMORIENT" </node_path>
- <int name="tracks/19/interp"> 1 </int>
- <real_array name="tracks/19/keys" len="12"> 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/20/type"> "transform" </string>
- <node_path name="tracks/20/path"> "Armature/Skeleton:hip" </node_path>
- <int name="tracks/20/interp"> 1 </int>
- <real_array name="tracks/20/keys" len="12"> 0, 1, 0, -2.84217e-14, 0, 0, 0, 1.44945e-21, 1, 1, 1, 1 </real_array>
- <string name="tracks/21/type"> "transform" </string>
- <node_path name="tracks/21/path"> "Armature/Skeleton:waist" </node_path>
- <int name="tracks/21/interp"> 1 </int>
- <real_array name="tracks/21/keys" len="12"> 0, 1, -6.35275e-21, 2.84217e-14, 0, 0, 0, 2.44616e-35, 1, 1, 1, 1 </real_array>
- <string name="tracks/22/type"> "transform" </string>
- <node_path name="tracks/22/path"> "Armature/Skeleton:chest" </node_path>
- <int name="tracks/22/interp"> 1 </int>
- <real_array name="tracks/22/keys" len="12"> 0, 1, -3.38813e-21, 0, 0, 0, 0, -1.33383e-23, 1, 1, 1, 1 </real_array>
- <string name="tracks/23/type"> "transform" </string>
- <node_path name="tracks/23/path"> "Armature/Skeleton:neck" </node_path>
- <int name="tracks/23/interp"> 1 </int>
- <real_array name="tracks/23/keys" len="12"> 0, 1, -8.52651e-14, -5.96046e-08, -7.15256e-07, 1.17383e-27, 2.13163e-14, 5.50671e-14, 1, 1, 1, 1 </real_array>
- <string name="tracks/24/type"> "transform" </string>
- <node_path name="tracks/24/path"> "Armature/Skeleton:headtracker" </node_path>
- <int name="tracks/24/interp"> 1 </int>
- <real_array name="tracks/24/keys" len="12"> 0, 1, -1.77636e-13, 5.96046e-08, -5.98375e-08, 7.45058e-09, 1.04639e-13, -2.13163e-14, 1, 1, 1, 1 </real_array>
- <string name="tracks/25/type"> "transform" </string>
- <node_path name="tracks/25/path"> "Armature/Skeleton:head" </node_path>
- <int name="tracks/25/interp"> 1 </int>
- <real_array name="tracks/25/keys" len="12"> 0, 1, -2.30926e-14, -1.22469e-07, 2.39583e-07, -2.52436e-28, 7.10543e-15, -7.10543e-15, 1, 1, 1, 1 </real_array>
- <string name="tracks/26/type"> "transform" </string>
- <node_path name="tracks/26/path"> "Armature/Skeleton:vent" </node_path>
- <int name="tracks/26/interp"> 1 </int>
- <real_array name="tracks/26/keys" len="12"> 0, 1, 3.55271e-15, 5.96046e-08, -7.15256e-07, 1.97906e-09, -2.66454e-15, 5.59448e-15, 1, 1, 1, 1 </real_array>
-
- </resource>
- <resource type="Animation" path="local://11">
- <string name="resource/name"> "run-cycle" </string>
- <real name="length"> 0.833333 </real>
- <bool name="loop"> True </bool>
- <real name="step"> 0.1 </real>
- <string name="tracks/0/type"> "transform" </string>
- <node_path name="tracks/0/path"> "Armature/Skeleton:r-arm" </node_path>
- <int name="tracks/0/interp"> 1 </int>
- <real_array name="tracks/0/keys" len="192"> 0, 1, 9.23872e-07, -3.57628e-07, 5.66244e-07, 0.222344, -0.226466, -0.0274315, 0.947905, 1, 1, 1, 0.05, 1, 6.55651e-07, -1.19209e-07, 2.98023e-07, 0.251975, -0.208305, -0.0408158, 0.944167, 1, 1, 1, 0.15, 1, 1.07288e-06, -3.57628e-07, 5.36442e-07, 0.379887, -0.057225, -0.102903, 0.917509, 1, 1, 1, 0.2, 1, 6.25849e-07, -3.57628e-07, 7.45058e-07, 0.418674, -0.00696497, -0.113328, 0.901011, 1, 1, 1, 0.25, 1, 8.64267e-07, -3.57628e-07, 3.8743e-07, 0.413182, 0.0386478, -0.0801881, 0.906287, 1, 1, 1, 0.3, 1, 9.53674e-07, -4.76837e-07, 5.96046e-07, 0.315261, 0.124735, -0.0152523, 0.940648, 1, 1, 1, 0.4, 1, 6.25849e-07, -3.57628e-07, 4.17233e-07, -0.151881, 0.360683, -0.0357324, 0.919545, 1, 1, 0.999999, 0.45, 1, 6.25849e-07, -3.57628e-07, 7.45058e-07, -0.172392, 0.343529, -0.046079, 0.922034, 1, 1, 0.999999, 0.55, 1, 6.55651e-07, -3.57628e-07, 5.36442e-07, 0.168352, 0.0191591, -0.0776353, 0.982478, 1, 1, 1, 0.6, 1, 9.53674e-07, -3.57628e-07, 3.27826e-07, 0.182793, -0.0233152, -0.109476, 0.976759, 1, 1, 1, 0.65, 1, 4.17233e-07, 0, 1.78814e-07, 0.138039, -0.0157468, -0.121765, 0.982787, 1, 1, 1, 0.7, 1, 6.25849e-07, -2.38419e-07, 1.78814e-07, 0.121673, -0.0809579, -0.109793, 0.983152, 1, 1, 1, 0.75, 1, 9.23872e-07, -3.57628e-07, 7.45058e-07, 0.131274, -0.176942, -0.0767055, 0.972407, 1, 1, 1, 0.8, 1, 5.66244e-07, -1.19209e-07, 5.96046e-07, 0.13073, -0.218021, -0.0501677, 0.965847, 1, 1, 1, 0.85, 1, 2.98023e-08, 0, -5.96046e-08, 0.129118, -0.224691, -0.0428281, 0.964888, 1, 1, 1, 1.25, 1, 2.98023e-08, 0, -5.96046e-08, 0.129118, -0.224691, -0.0428281, 0.964888, 1, 1, 1 </real_array>
- <string name="tracks/1/type"> "transform" </string>
- <node_path name="tracks/1/path"> "Armature/Skeleton:r-forearm" </node_path>
- <int name="tracks/1/interp"> 1 </int>
- <real_array name="tracks/1/keys" len="180"> 0, 1, 0, -4.17233e-07, -3.57628e-07, -0.0379169, -0.0715942, 0.00193508, 0.996711, 1, 1, 1, 0.05, 1, -1.78814e-07, -5.96046e-07, -4.17233e-07, -0.000241383, -0.109076, 0.00379063, 0.994026, 1, 1, 1, 0.1, 1, 8.9407e-08, -6.55651e-07, -6.55651e-07, 0.0679255, -0.167209, 0.00334064, 0.983573, 1, 0.999999, 1, 0.25, 1, -1.19209e-07, -3.8743e-07, 0, 0.158727, -0.350464, 0.00627285, 0.923007, 1, 1, 1, 0.3, 1, -3.27826e-07, -6.85453e-07, 1.78814e-07, 0.146536, -0.393807, 0.00119701, 0.907437, 1, 1, 1, 0.35, 1, -8.9407e-08, -6.55651e-07, -3.57628e-07, 0.153485, -0.416977, -0.0128296, 0.895772, 1, 1, 1, 0.4, 1, 8.9407e-08, -9.83477e-07, -5.36442e-07, 0.172873, -0.368078, -0.014432, 0.913469, 1, 0.999999, 1, 0.45, 1, 0, -9.83477e-07, -1.19209e-07, 0.191151, -0.391536, -0.0140892, 0.899979, 1, 1, 1, 0.5, 1, 8.9407e-08, -5.96046e-07, -6.55651e-07, 0.210133, -0.527231, -0.0202225, 0.823081, 1, 1, 1, 0.55, 1, 2.68221e-07, -6.25849e-07, -4.17233e-07, 0.159334, -0.589231, -0.00909611, 0.792046, 1, 1, 1, 0.65, 1, -1.19209e-07, -6.85453e-07, -7.15256e-07, 0.0168538, -0.43832, 0.0104639, 0.8986, 1, 1, 1, 0.7, 1, 1.78814e-07, -5.36442e-07, -1.78814e-07, -0.00524541, -0.376783, 0.0174757, 0.926122, 1, 1, 1, 0.8, 1, -5.96046e-08, -7.15256e-07, -5.36442e-07, 0.00762745, -0.243737, 0.014512, 0.969703, 1, 1, 1, 0.85, 1, 1.19209e-07, -6.85453e-07, -7.7486e-07, 0.00858928, -0.221202, 0.0126834, 0.975108, 1, 1, 1, 1.25, 1, 1.19209e-07, -6.85453e-07, -7.7486e-07, 0.00858928, -0.221202, 0.0126834, 0.975108, 1, 1, 1 </real_array>
- <string name="tracks/2/type"> "transform" </string>
- <node_path name="tracks/2/path"> "Armature/Skeleton:l-arm" </node_path>
- <int name="tracks/2/interp"> 1 </int>
- <real_array name="tracks/2/keys" len="228"> 0, 1, -9.53674e-07, -5.96046e-07, 4.76837e-07, -0.211109, -0.378307, 0.04716, 0.900052, 1, 1, 1, 0.05, 1, -9.53674e-07, 1.19209e-07, 3.57628e-07, -0.122361, -0.307485, 0.0444022, 0.942608, 1, 1, 1, 0.1, 1, -6.85453e-07, -2.38419e-07, 5.96046e-07, 0.0655243, -0.124344, 0.0558387, 0.988497, 1, 1, 1, 0.15, 1, -7.7486e-07, -1.19209e-07, 5.66244e-07, 0.17223, 0.0168325, 0.088774, 0.980904, 1, 1, 1, 0.2, 1, -5.36442e-07, -3.57628e-07, 5.36442e-07, 0.151153, 0.0193605, 0.111763, 0.981981, 1, 1, 1, 0.25, 1, -6.25849e-07, -3.57628e-07, 5.96046e-07, 0.105831, 0.0199286, 0.119921, 0.986925, 1, 1, 1, 0.3, 1, -1.19209e-06, -5.96046e-07, 6.25849e-07, 0.11, 0.117841, 0.0973986, 0.982103, 1, 1, 1, 0.35, 1, -5.36442e-07, -1.19209e-07, 4.47035e-07, 0.163427, 0.213955, 0.0590648, 0.961263, 1, 1, 1, 0.4, 1, -6.85453e-07, -3.57628e-07, 5.06639e-07, 0.212517, 0.23167, 0.0327435, 0.948733, 1, 1, 1, 0.45, 1, -8.04663e-07, -2.38419e-07, 5.66244e-07, 0.240572, 0.207043, 0.0320326, 0.947751, 1, 1, 1, 0.5, 1, -9.23872e-07, 0, 8.04663e-07, 0.292283, 0.151342, 0.0529747, 0.942794, 1, 1, 1, 0.55, 1, -6.85453e-07, -3.57628e-07, 3.57628e-07, 0.354424, 0.0696654, 0.0852169, 0.928584, 1, 1, 1, 0.6, 1, -5.66244e-07, -2.38419e-07, 2.98023e-07, 0.397207, 0.0175472, 0.104303, 0.911614, 1, 1, 1, 0.65, 1, -8.34465e-07, -2.38419e-07, 4.47035e-07, 0.407225, -0.0166533, 0.0875941, 0.908965, 1, 1, 1, 0.7, 1, -1.2517e-06, -1.19209e-07, 6.55651e-07, 0.349327, -0.0813931, 0.0308211, 0.93295, 1, 1, 1, 0.75, 1, -1.19209e-07, 1.19209e-07, 2.08616e-07, 0.214708, -0.14004, -0.012317, 0.966508, 1, 1, 1, 0.8, 1, -6.55651e-07, -1.19209e-07, 2.98023e-07, -0.00140518, -0.171137, -0.0177305, 0.985087, 1, 1, 1, 0.85, 1, -4.76837e-07, -3.57628e-07, 3.8743e-07, -0.0925096, -0.171599, -0.011185, 0.98075, 1, 1, 1, 1.25, 1, -4.76837e-07, -3.57628e-07, 3.8743e-07, -0.0925096, -0.171599, -0.011185, 0.98075, 1, 1, 1 </real_array>
- <string name="tracks/3/type"> "transform" </string>
- <node_path name="tracks/3/path"> "Armature/Skeleton:l-forearm" </node_path>
- <int name="tracks/3/interp"> 1 </int>
- <real_array name="tracks/3/keys" len="180"> 0, 1, 2.08616e-07, -2.98023e-08, -5.96046e-07, 0.176871, 0.346752, 0.0115369, 0.921058, 1, 1, 1, 0.05, 1, -1.49012e-07, -4.76837e-07, -2.38419e-07, 0.1969, 0.431458, 0.0161118, 0.880236, 1, 1, 1, 0.1, 1, -3.57628e-07, -8.04663e-07, -4.76837e-07, 0.196923, 0.556224, 0.0152519, 0.80722, 1, 1, 1, 0.15, 1, -2.68221e-07, -4.17233e-07, -2.98023e-07, 0.134905, 0.568169, 0.00154346, 0.811777, 1, 1, 1, 0.2, 1, -1.49012e-07, -6.25849e-07, -4.17233e-07, 0.0562878, 0.484209, -0.00707307, 0.873111, 1, 1, 1, 0.25, 1, -2.98023e-08, -8.04663e-07, -3.57628e-07, 0.0047636, 0.406038, -0.0121859, 0.913763, 1, 1, 1, 0.3, 1, 5.96046e-08, -7.7486e-07, -1.78814e-07, -0.011494, 0.345751, -0.0179636, 0.938084, 1, 0.999999, 1, 0.4, 1, 5.36442e-07, -5.36442e-07, -1.19209e-07, -0.0325058, 0.107107, -0.00429871, 0.993707, 1, 0.999999, 1, 0.45, 1, 2.08616e-07, -8.34465e-07, -1.78814e-07, -0.0177273, 0.0767786, -0.00241131, 0.996888, 1, 1, 1, 0.65, 1, -5.96046e-08, -6.55651e-07, -1.07288e-06, 0.154364, 0.318848, -0.0046877, 0.935139, 1, 1, 1, 0.7, 1, 5.96046e-08, -9.23872e-07, -1.01328e-06, 0.155566, 0.376204, -0.00401138, 0.913375, 1, 1, 1, 0.75, 1, 0, -8.9407e-07, -4.17233e-07, 0.173064, 0.444685, 0.00561718, 0.87879, 1, 1, 1, 0.8, 1, 3.27826e-07, -6.55651e-07, -4.17233e-07, 0.251551, 0.464674, 0.00544377, 0.848982, 1, 1, 1, 0.85, 1, 8.9407e-08, -7.15256e-07, -9.53674e-07, 0.280639, 0.447823, -0.00246765, 0.848935, 1, 1, 1, 1.25, 1, 8.9407e-08, -7.15256e-07, -9.53674e-07, 0.280639, 0.447823, -0.00246765, 0.848935, 1, 1, 1 </real_array>
- <string name="tracks/4/type"> "transform" </string>
- <node_path name="tracks/4/path"> "Armature/Skeleton:r-thigh" </node_path>
- <int name="tracks/4/interp"> 1 </int>
- <real_array name="tracks/4/keys" len="192"> 0, 1, 0, 1.63913e-07, 1.93715e-07, -0.283345, 0.0300071, -0.0426225, 0.957601, 1, 1, 1, 0.05, 1, 8.9407e-08, 1.93715e-07, -5.06639e-07, -0.221388, 0.0587497, -0.0627932, 0.971387, 1, 1, 1, 0.15, 1, 5.96046e-08, 6.70552e-08, -1.3411e-07, 0.127996, 0.137739, -0.113256, 0.975612, 1, 1, 1, 0.2, 1, -5.96046e-08, -7.45058e-09, -7.45058e-07, 0.264976, 0.121823, -0.100248, 0.951261, 1, 1, 1, 0.25, 1, 2.98023e-08, -2.01166e-07, -4.91738e-07, 0.314522, 0.0998354, -0.077727, 0.94078, 1, 1, 1, 0.3, 1, 1.49012e-07, 1.3411e-07, 1.3411e-07, 0.306548, 0.0507913, -0.0454783, 0.949411, 1, 1, 1, 0.35, 1, 8.9407e-08, 7.45058e-09, -2.83122e-07, 0.297828, -0.0187708, -0.0207563, 0.954209, 1, 1, 1, 0.4, 1, 8.9407e-08, 4.47035e-08, -2.98023e-07, 0.287784, -0.0733564, -0.00467344, 0.95487, 1, 1, 1, 0.45, 1, 2.98023e-08, 2.23517e-08, -2.5332e-07, 0.170166, -0.0854042, 0.00266015, 0.981704, 1, 1, 1, 0.6, 1, 0, 1.04308e-07, 0, -0.531982, -0.0722138, 0.0220251, 0.843383, 1, 1, 1, 0.65, 1, 0, 1.3411e-07, -3.12924e-07, -0.652152, -0.0747176, 0.0102306, 0.754328, 1, 1, 1, 0.7, 1, -2.98023e-08, 0, 1.49012e-07, -0.686637, -0.0649825, 0.00231536, 0.724087, 1, 1, 1, 0.75, 1, 2.98023e-08, -1.56462e-07, -2.38419e-07, -0.638385, -0.0394346, -0.00259775, 0.768702, 1, 1, 1, 0.8, 1, 1.49012e-07, -8.9407e-08, -1.93715e-07, -0.432358, 0.00843852, -0.0248422, 0.90132, 1, 1, 1, 0.85, 1, 0, 1.63913e-07, 1.93715e-07, -0.283345, 0.0300071, -0.0426225, 0.957601, 1, 1, 1, 1.25, 1, 0, 1.63913e-07, 1.93715e-07, -0.283345, 0.0300071, -0.0426225, 0.957601, 1, 1, 1 </real_array>
- <string name="tracks/5/type"> "transform" </string>
- <node_path name="tracks/5/path"> "Armature/Skeleton:r-leg" </node_path>
- <int name="tracks/5/interp"> 1 </int>
- <real_array name="tracks/5/keys" len="216"> 0, 1, 2.29338e-08, 8.9407e-08, 5.36442e-07, -0.369097, -0.0505305, 0.00260278, 0.928013, 1, 1, 1, 0.05, 1, 8.26549e-08, 1.93715e-07, 4.76837e-07, -0.32656, -0.0387365, 0.00230976, 0.94438, 1, 1, 1, 0.15, 1, 4.78467e-08, -7.45058e-09, 7.7486e-07, -0.04833, 0.013837, -0.00331139, 0.99873, 1, 1, 1, 0.2, 1, 1.44588e-07, 0, 7.15256e-07, 0.0174433, 0.00914093, -0.00369525, 0.999799, 1, 1, 1, 0.25, 1, 4.49363e-08, 1.63913e-07, 2.38419e-07, -0.0309752, 0.0174032, -0.00233819, 0.999366, 1, 1, 1, 0.3, 1, 6.06524e-08, -7.45058e-08, 6.55651e-07, -0.161344, 0.031869, -0.00095907, 0.986383, 1, 1, 1, 0.35, 1, 6.23986e-08, 1.11759e-07, 5.36442e-07, -0.258604, 0.043227, -0.000463765, 0.965016, 1, 1, 1, 0.4, 1, 2.66591e-08, 1.11759e-07, 5.96046e-07, -0.311843, 0.0531668, -0.000274837, 0.948645, 1, 1, 1, 0.45, 1, -0.000736501, 0.00352155, -0.0507002, -0.471618, 0.0737067, 0.000546333, 0.878717, 1, 1, 1, 0.5, 1, -0.00351399, 0.0168005, -0.241486, -0.74573, 0.0999092, 7.49679e-05, 0.658714, 1, 1, 1, 0.55, 1, -0.00736267, 0.0352004, -0.505227, 0.896291, -0.0831834, 0.00513814, -0.435565, 1, 1, 1, 0.6, 1, -0.0098056, 0.0468799, -0.672563, 0.946677, -0.0409485, 0.00588309, -0.319519, 1, 1, 1, 0.65, 1, -0.0098056, 0.0468801, -0.672652, 0.947809, 0.0057637, 0.00256107, -0.318776, 1, 1, 1, 0.7, 1, -0.00736268, 0.0352004, -0.505962, 0.888767, 0.0669386, 0.000245982, -0.453445, 1, 1, 1, 0.75, 1, -0.003514, 0.016801, -0.242868, -0.757574, -0.0924392, -0.000540428, 0.64617, 1, 1, 1, 0.8, 1, -0.000736581, 0.0035219, -0.0512407, -0.527405, -0.0678553, 0.00109702, 0.846899, 1, 1, 1, 0.85, 1, 2.29338e-08, 8.9407e-08, 5.36442e-07, -0.369097, -0.0505305, 0.00260278, 0.928013, 1, 1, 1, 1.25, 1, 2.29338e-08, 8.9407e-08, 5.36442e-07, -0.369097, -0.0505305, 0.00260278, 0.928013, 1, 1, 1 </real_array>
- <string name="tracks/6/type"> "transform" </string>
- <node_path name="tracks/6/path"> "Armature/Skeleton:r-foot" </node_path>
- <int name="tracks/6/interp"> 1 </int>
- <real_array name="tracks/6/keys" len="216"> 0, 1, 1.49012e-08, 0, -5.21541e-08, 0.163945, 0.140221, -0.046324, 0.975354, 1, 1, 1, 0.05, 1, 9.68575e-08, 0, 7.82311e-08, 0.163142, 0.147087, -0.0386578, 0.974811, 1, 1, 1, 0.1, 1, 7.45058e-08, 0, 1.11759e-08, 0.154504, 0.157524, -0.0272069, 0.974974, 1, 1, 1, 0.15, 1, 8.9407e-08, 0, 3.72529e-08, 0.106593, 0.145246, -0.0455539, 0.982581, 1, 1, 1, 0.2, 1, 3.72529e-08, 0, 0, 0.00306457, 0.0975244, -0.0887594, 0.991263, 1, 1, 1, 0.3, 1, 4.47035e-08, 1.19209e-07, -1.60187e-07, -0.165764, -0.00244496, -0.0619073, 0.984217, 1, 1, 1, 0.35, 1, 3.72529e-08, -1.19209e-07, -1.2666e-07, -0.225564, -0.0444232, -0.0320188, 0.972688, 1, 1, 1, 0.4, 1, -2.98023e-08, -1.19209e-07, 1.3411e-07, -0.254966, -0.0644888, -0.0152293, 0.964677, 1, 1, 1, 0.45, 1, 5.96046e-08, 1.19209e-07, -3.72529e-09, -0.263415, -0.0674915, -0.0129876, 0.962231, 1, 1, 1, 0.5, 1, 7.45058e-08, 0, -2.98023e-08, -0.26682, -0.065605, -0.0157537, 0.961382, 1, 1, 1, 0.55, 1, 5.96046e-08, 0, 3.35276e-08, -0.268414, -0.0578826, -0.0205736, 0.961343, 1, 1, 1, 0.6, 1, 2.23517e-08, -1.19209e-07, 1.49012e-07, -0.268984, -0.0431783, -0.0254932, 0.961839, 1, 1, 1, 0.65, 1, 3.72529e-08, 0, -1.11759e-08, -0.205247, -0.0144598, -0.0301062, 0.97814, 1, 1, 1, 0.7, 1, 7.45058e-08, -1.19209e-07, -5.58794e-08, 0.0302446, 0.0427142, -0.0345553, 0.998031, 1, 1, 1, 0.75, 1, 8.9407e-08, 0, -1.11759e-07, 0.187052, 0.0967062, -0.0379775, 0.97684, 1, 1, 1, 0.8, 1, 8.19564e-08, -1.19209e-07, 2.23517e-08, 0.173053, 0.130372, -0.0438442, 0.975261, 1, 1, 1, 0.85, 1, 1.49012e-08, 0, -5.21541e-08, 0.163945, 0.140221, -0.046324, 0.975354, 1, 1, 1, 1.25, 1, 1.49012e-08, 0, -5.21541e-08, 0.163945, 0.140221, -0.046324, 0.975354, 1, 1, 1 </real_array>
- <string name="tracks/7/type"> "transform" </string>
- <node_path name="tracks/7/path"> "Armature/Skeleton:l-thigh" </node_path>
- <int name="tracks/7/interp"> 1 </int>
- <real_array name="tracks/7/keys" len="204"> 0, 1, 0, 2.08616e-07, 1.49012e-08, 0.284249, 0.0874448, 0.000525696, 0.954754, 1, 1, 1, 0.05, 1, 0, 1.11759e-07, -1.63913e-07, 0.0840381, 0.068345, -0.00156289, 0.994115, 1, 1, 1, 0.15, 1, 0, -9.68575e-08, -1.19209e-07, -0.428198, 0.103089, -0.0309307, 0.897253, 1, 1, 1, 0.2, 1, 2.98023e-08, 0, -2.5332e-07, -0.585268, 0.121806, -0.0264258, 0.801203, 1, 1, 1, 0.25, 1, -5.96046e-08, -2.68221e-07, -1.93715e-07, -0.68271, 0.117151, -0.00691618, 0.721203, 1, 1, 1, 0.3, 1, 5.96046e-08, 5.21541e-08, 3.57628e-07, -0.675843, 0.0951763, -0.00368054, 0.730865, 1, 1, 1, 0.35, 1, -5.96046e-08, -8.9407e-08, -1.04308e-07, -0.577504, 0.0522321, 0.00297164, 0.81471, 1, 1, 1, 0.4, 1, 0, 7.45058e-09, 1.63913e-07, -0.36481, -0.00958558, 0.0300626, 0.930547, 1, 1, 1, 0.45, 1, -1.19209e-07, 7.45058e-08, 1.49012e-07, -0.214962, -0.0628985, 0.0719756, 0.971933, 1, 1, 1, 0.5, 1, 0, 7.45058e-09, -7.15256e-07, -0.0924244, -0.113076, 0.110988, 0.983033, 1, 1, 1, 0.6, 1, 2.98023e-08, 3.72529e-08, 7.30157e-07, 0.212199, -0.104928, 0.0711089, 0.968971, 1, 1, 1, 0.65, 1, 8.9407e-08, 1.49012e-08, -1.63913e-07, 0.280374, -0.0786743, 0.0551762, 0.955069, 1, 1, 1, 0.7, 1, 0, 1.11759e-07, 2.5332e-07, 0.288443, -0.0349057, 0.033278, 0.956282, 1, 1, 1, 0.75, 1, -2.98023e-08, -1.3411e-07, -6.85453e-07, 0.285487, 0.0289713, 0.0136411, 0.957847, 1, 1, 1, 0.8, 1, -5.96046e-08, 8.9407e-08, -3.27826e-07, 0.284867, 0.0752772, 0.00313844, 0.955602, 1, 1, 1, 0.85, 1, 0, 2.08616e-07, 1.49012e-08, 0.284249, 0.0874448, 0.000525696, 0.954754, 1, 1, 1, 1.25, 1, 0, 2.08616e-07, 1.49012e-08, 0.284249, 0.0874448, 0.000525696, 0.954754, 1, 1, 1 </real_array>
- <string name="tracks/8/type"> "transform" </string>
- <node_path name="tracks/8/path"> "Armature/Skeleton:l-leg" </node_path>
- <int name="tracks/8/interp"> 1 </int>
- <real_array name="tracks/8/keys" len="216"> 0, 1, -6.98492e-10, -2.98023e-08, 4.76837e-07, -0.32359, -0.0556479, 0.000232734, 0.94456, 1, 1, 1, 0.05, 1, 0.0014394, 0.00688202, -0.0998148, -0.562955, -0.0817876, -0.000658042, 0.82243, 1, 1, 1, 0.1, 1, 0.00484604, 0.0231691, -0.333955, -0.80836, -0.0993527, 0.00161956, 0.580241, 1, 1, 1, 0.15, 1, 0.00839999, 0.04016, -0.576718, 0.916395, 0.0904963, -0.00581601, -0.389867, 1, 1, 1, 0.2, 1, 0.010174, 0.048641, -0.697832, 0.949699, 0.0597103, -0.00558806, -0.307368, 1, 1, 1, 0.25, 1, 0.00943748, 0.0451194, -0.647324, 0.940565, -0.00539416, -0.00131091, -0.339569, 1, 1, 1, 0.3, 1, 0.00617793, 0.0295368, -0.424059, -0.852217, 0.0810981, 0.000142268, 0.516865, 1, 1, 1, 0.35, 1, 0.00247674, 0.0118409, -0.170242, -0.686673, 0.0913182, 0.000156236, 0.721208, 1, 1, 1, 0.4, 1, 0.000368256, 0.00176083, -0.02535, -0.450712, 0.0617424, -0.0017981, 0.89053, 1, 1, 1, 0.45, 1, -3.27127e-08, -2.23517e-08, 0, -0.320919, 0.0402711, -0.00287403, 0.946246, 1, 1, 1, 0.5, 1, -3.65544e-08, 2.6077e-07, 0, -0.222093, 0.0121194, -0.000893378, 0.97495, 1, 1, 1, 0.55, 1, -7.85803e-08, -5.21541e-08, 5.96046e-08, -0.085227, -0.0121138, 0.00211304, 0.996286, 1, 1, 1, 0.6, 1, -9.66247e-09, -1.93715e-07, -5.96046e-08, -0.0204391, -0.0111085, 0.00211107, 0.999727, 1, 1, 1, 0.65, 1, -1.47847e-08, -7.45058e-09, 1.19209e-07, -0.0461144, -0.0137229, 0.00155832, 0.998841, 1, 1, 1, 0.75, 1, 9.77889e-08, -8.9407e-08, 0, -0.259445, -0.0379664, 0.000355786, 0.965011, 1, 1, 1, 0.8, 1, -3.06172e-08, -1.19209e-07, 1.19209e-07, -0.311223, -0.0514541, 0.000257438, 0.948943, 1, 1, 1, 0.85, 1, -6.98492e-10, -2.98023e-08, 4.76837e-07, -0.32359, -0.0556479, 0.000232734, 0.94456, 1, 1, 1, 1.25, 1, -6.98492e-10, -2.98023e-08, 4.76837e-07, -0.32359, -0.0556479, 0.000232734, 0.94456, 1, 1, 1 </real_array>
- <string name="tracks/9/type"> "transform" </string>
- <node_path name="tracks/9/path"> "Armature/Skeleton:l-foot" </node_path>
- <int name="tracks/9/interp"> 1 </int>
- <real_array name="tracks/9/keys" len="204"> 0, 1, 2.23517e-08, 1.19209e-07, 7.45058e-09, -0.260411, 0.0677016, 0.0123204, 0.963042, 1, 1, 1, 0.05, 1, 1.49012e-08, 1.19209e-07, -6.33299e-08, -0.261291, 0.0586691, 0.0123934, 0.963396, 1, 1, 1, 0.1, 1, 1.49012e-08, 1.19209e-07, 3.35276e-08, -0.262834, 0.0342669, 0.0126709, 0.964149, 1, 1, 1, 0.2, 1, 1.49012e-08, 0, 1.86265e-08, -0.260355, -0.0293857, 0.0140367, 0.964964, 1, 1, 1, 0.25, 1, -6.70552e-08, 0, -2.49594e-07, -0.153196, -0.0556389, 0.0191204, 0.986443, 1, 1, 1, 0.3, 1, 7.45058e-09, 2.38419e-07, 3.35276e-08, 0.102501, -0.0807205, 0.0313849, 0.990956, 1, 1, 1, 0.35, 1, -1.49012e-08, 1.19209e-07, -1.11759e-08, 0.182765, -0.105332, 0.0403985, 0.976663, 1, 1, 1, 0.4, 1, 0, 2.38419e-07, 2.98023e-08, 0.1689, -0.131443, 0.0454069, 0.975773, 1, 1, 1, 0.45, 1, -2.23517e-08, 1.19209e-07, 1.11759e-08, 0.162548, -0.163949, 0.0367097, 0.972292, 1, 1, 1, 0.5, 1, -7.45058e-09, 1.19209e-07, -6.70552e-08, 0.160675, -0.186181, 0.0223394, 0.969031, 1, 1, 1, 0.55, 1, 0, 2.38419e-07, -4.09782e-08, 0.121712, -0.123055, 0.0340729, 0.984318, 1, 1, 1, 0.65, 1, -2.23517e-08, 2.38419e-07, -4.84288e-08, -0.0909908, -0.00331438, 0.030867, 0.995368, 1, 1, 1, 0.7, 1, -2.98023e-08, 0, -1.86265e-08, -0.167009, 0.0327264, 0.0253347, 0.985086, 1, 1, 1, 0.75, 1, -1.49012e-08, 2.38419e-07, -9.31323e-08, -0.225897, 0.0565391, 0.0182554, 0.972338, 1, 1, 1, 0.8, 1, 7.45058e-09, 0, 1.41561e-07, -0.254123, 0.0658906, 0.0135391, 0.96483, 1, 1, 1, 0.85, 1, 2.23517e-08, 1.19209e-07, 7.45058e-09, -0.260411, 0.0677016, 0.0123204, 0.963042, 1, 1, 1, 1.25, 1, 2.23517e-08, 1.19209e-07, 7.45058e-09, -0.260411, 0.0677016, 0.0123204, 0.963042, 1, 1, 1 </real_array>
- <string name="tracks/10/type"> "transform" </string>
- <node_path name="tracks/10/path"> "Armature/Skeleton:MASTER" </node_path>
- <int name="tracks/10/interp"> 1 </int>
- <real_array name="tracks/10/keys" len="24"> 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/11/type"> "transform" </string>
- <node_path name="tracks/11/path"> "Armature/Skeleton:HEAD" </node_path>
- <int name="tracks/11/interp"> 1 </int>
- <real_array name="tracks/11/keys" len="192"> 0, 1, -5.68434e-14, 0, 0.994808, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -5.68434e-14, 0, 0.908378, 0, 0, 0, 1, 1, 1, 1, 0.1, 1, -5.68434e-14, 0, 0.865919, 0, 0, 7.10543e-15, 1, 1, 1, 1, 0.15, 1, -5.68434e-14, 0, 0.952043, 0, 0, 0, 1, 1, 1, 1, 0.25, 1, -5.68434e-14, 0, 1.23636, 0, 0, 0, 1, 1, 1, 1, 0.3, 1, -5.68434e-14, 0, 1.26452, 0, 0, 7.10543e-15, 1, 1, 1, 1, 0.35, 1, -5.68434e-14, 0, 1.17812, 0, 0, -7.10543e-15, 1, 1, 1, 1, 0.45, 1, -5.68434e-14, 0, 0.917901, 0, 0, 0, 1, 1, 1, 1, 0.5, 1, -5.68434e-14, 0, 0.850875, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, -5.68434e-14, 0, 0.90967, 0, 0, 0, 1, 1, 1, 1, 0.65, 1, -5.68434e-14, 0, 1.19399, 0, 0, 0, 1, 1, 1, 1, 0.7, 1, -5.68434e-14, 0, 1.26645, 0, 0, 7.10543e-15, 1, 1, 1, 1, 0.75, 1, -5.68434e-14, 0, 1.20667, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, -5.68434e-14, 0, 1.04898, 0, 0, 7.10543e-15, 1, 1, 1, 1, 0.85, 1, -5.68434e-14, 0, 0.994808, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -5.68434e-14, 0, 0.994808, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/12/type"> "transform" </string>
- <node_path name="tracks/12/path"> "Armature/Skeleton:r-LEGCONTROL" </node_path>
- <int name="tracks/12/interp"> 1 </int>
- <real_array name="tracks/12/keys" len="192"> 0, 1, -0.142338, -0.593751, 0.041427, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -0.141891, -0.466314, 0.0666584, 0, 0, 0, 1, 1, 1, 1, 0.1, 1, -0.140854, -0.18721, 0.16679, 0, 0, 0, 1, 1, 1, 1, 0.3, 1, -0.135712, 0.882052, 1.08263, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, -0.134593, 1.04285, 1.23903, 0, 0, 0, 1, 1, 1, 1, 0.4, 1, -0.134052, 1.11594, 1.33052, 0, 0, 0, 1, 1, 1, 1, 0.45, 1, -0.134139, 1.01025, 1.37488, 0, 0, 0, 1, 1, 1, 1, 0.5, 1, -0.134864, 0.561422, 1.40083, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, -0.136154, -0.107091, 1.41207, 0, 0, 0, 1, 1, 1, 1, 0.6, 1, -0.137517, -0.627938, 1.41499, 0, 0, 0, 1, 1, 1, 1, 0.65, 1, -0.138802, -0.880369, 1.32217, 0, 0, 0, 1, 1, 1, 1, 0.7, 1, -0.140187, -0.97361, 0.946171, 0, 0, 0, 1, 1, 1, 1, 0.75, 1, -0.141374, -0.990009, 0.507478, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, -0.142135, -0.753522, 0.166703, 0, 0, 0, 1, 1, 1, 1, 0.85, 1, -0.142338, -0.593751, 0.041427, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.142338, -0.593751, 0.041427, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/13/type"> "transform" </string>
- <node_path name="tracks/13/path"> "Armature/Skeleton:l-LEGCONTROL" </node_path>
- <int name="tracks/13/interp"> 1 </int>
- <real_array name="tracks/13/keys" len="192"> 0, 1, 0.133965, 1.12742, 1.35169, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 0.134319, 0.88137, 1.36048, 0, 0, 0, 1, 1, 1, 1, 0.15, 1, 0.136624, -0.318866, 1.4031, 0, 0, 0, 1, 1, 1, 1, 0.2, 1, 0.13794, -0.745207, 1.41408, 0, 0, 0, 1, 1, 1, 1, 0.25, 1, 0.139237, -0.932173, 1.26013, 0, 0, 0, 1, 1, 1, 1, 0.3, 1, 0.140615, -0.985177, 0.795642, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, 0.141658, -0.933265, 0.382912, 0, 0, 0, 1, 1, 1, 1, 0.4, 1, 0.142236, -0.69551, 0.103281, 0, 0, 0, 1, 1, 1, 1, 0.45, 1, 0.142112, -0.449542, 0.0515677, 0, 0, 0, 1, 1, 1, 1, 0.5, 1, 0.141234, -0.239295, 0.11699, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, 0.140074, 0.0127278, 0.285218, 0, 0, 0, 1, 1, 1, 1, 0.7, 1, 0.136158, 0.812955, 1.03336, 0, 0, 0, 1, 1, 1, 1, 0.75, 1, 0.134866, 1.00553, 1.22614, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, 0.13414, 1.10444, 1.32777, 0, 0, 0, 1, 1, 1, 1, 0.85, 1, 0.133965, 1.12742, 1.35169, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.133965, 1.12742, 1.35169, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/14/type"> "transform" </string>
- <node_path name="tracks/14/path"> "Armature/Skeleton:r-LEGORIENT" </node_path>
- <int name="tracks/14/interp"> 1 </int>
- <real_array name="tracks/14/keys" len="180"> 0, 1, 0.100474, 0.669825, -0.778672, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 0.0953997, 0.642052, -0.742965, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 0.1, 1, 0.0823101, 0.56581, -0.648221, 4.1297e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.35, 1, 0.0243976, -0.0441461, -0.063019, 4.1297e-08, 2.53394e-15, -7.10543e-15, 1, 1, 1, 1, 0.4, 1, 0.020945, -0.11126, -0.00892317, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 0.45, 1, 0.0214889, -0.0993756, -0.1204, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.5, 1, 0.0261557, -0.00703263, -0.571036, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, 0.0350212, 0.144668, -1.19143, 7.10993e-08, 6.08666e-15, -4.32757e-22, 1, 1, 1, 1, 0.6, 1, 0.0452013, 0.286137, -1.58564, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.65, 1, 0.056361, 0.396596, -1.62736, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.7, 1, 0.0713525, 0.504199, -1.41721, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 0.75, 1, 0.0877976, 0.602767, -1.08603, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, 0.097935, 0.656912, -0.843801, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 0.85, 1, 0.100474, 0.669825, -0.778672, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.100474, 0.669825, -0.778672, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/15/type"> "transform" </string>
- <node_path name="tracks/15/path"> "Armature/Skeleton:l-LEGORIENT" </node_path>
- <int name="tracks/15/interp"> 1 </int>
- <real_array name="tracks/15/keys" len="180"> 0, 1, -0.0204011, -0.122407, 5.96046e-08, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -0.0226399, -0.0760723, -0.246171, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 0.15, 1, -0.0384328, 0.195889, -1.36473, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.2, 1, -0.0485586, 0.325533, -1.64571, 7.10993e-08, 9.63937e-15, -6.85353e-22, 1, 1, 1, 1, 0.25, 1, -0.0604436, 0.430887, -1.61593, 0, 0, 0, 1, 1, 1, 1, 0.3, 1, -0.0768237, 0.538687, -1.39129, 7.10993e-08, 2.53394e-15, -2.11758e-22, 1, 1, 1, 1, 0.35, 1, -0.0915991, 0.623227, -1.09587, 4.1297e-08, 2.53394e-15, -7.10543e-15, 1, 1, 1, 1, 0.4, 1, -0.0992045, 0.663389, -0.847581, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 0.45, 1, -0.0979352, 0.656214, -0.687419, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.5, 1, -0.0877979, 0.599371, -0.580202, 0, 0, 0, 1, 1, 1, 1, 0.65, 1, -0.0452008, 0.276356, -0.334939, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.75, 1, -0.0261556, -0.010167, -0.0897738, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, -0.0214889, -0.0999783, -0.0177123, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 0.85, 1, -0.0204011, -0.122407, 5.96046e-08, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.0204011, -0.122407, 5.96046e-08, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/16/type"> "transform" </string>
- <node_path name="tracks/16/path"> "Armature/Skeleton:r-ARMCONTROL" </node_path>
- <int name="tracks/16/interp"> 1 </int>
- <real_array name="tracks/16/keys" len="168"> 0, 1, -0.868295, 0.288818, -0.834593, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -0.920336, 0.223441, -0.675278, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, -1.0611, 0.0535004, -0.268795, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.3, 1, -1.81549, -0.572945, 1.93497, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.35, 1, -1.97521, -0.260334, 2.42549, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, -2.07242, 0.0952058, 2.72719, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, -2.06152, 0.134094, 2.70055, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.5, 1, -1.94935, -0.00418663, 2.38214, 0, 0, 0, 1, 1, 1, 1, 0.6, 1, -1.5659, -0.316463, 1.27531, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.65, 1, -1.39564, -0.31023, 0.768786, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.75, 1, -1.01032, 0.0728607, -0.380929, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, -0.896442, 0.243316, -0.739858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.85, 1, -0.868295, 0.288818, -0.834593, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.868295, 0.288818, -0.834593, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/17/type"> "transform" </string>
- <node_path name="tracks/17/path"> "Armature/Skeleton:l-ARMCONTROL" </node_path>
- <int name="tracks/17/interp"> 1 </int>
- <real_array name="tracks/17/keys" len="168"> 0, 1, 2.08906, 0.170859, 2.78004, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 2.03311, 0.0989122, 2.61048, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, 1.88529, -0.0705678, 2.18507, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.2, 1, 1.50915, -0.334755, 1.10648, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.25, 1, 1.33866, -0.287646, 0.593788, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, 0.966909, 0.137533, -0.532556, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, 0.882217, 0.266322, -0.791318, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, 0.89374, 0.256562, -0.760212, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.5, 1, 0.999084, 0.126561, -0.459517, 0, 0, 0, 1, 1, 1, 1, 0.7, 1, 1.75712, -0.595706, 1.75783, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.75, 1, 1.92686, -0.424236, 2.27222, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, 2.0556, 0.0151663, 2.66931, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.85, 1, 2.08906, 0.170859, 2.78004, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 2.08906, 0.170859, 2.78004, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/18/type"> "transform" </string>
- <node_path name="tracks/18/path"> "Armature/Skeleton:r-ARMORIENT" </node_path>
- <int name="tracks/18/interp"> 1 </int>
- <real_array name="tracks/18/keys" len="156"> 0, 1, 0.405204, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 0.341349, -0.264663, 0.0556155, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.15, 1, 0.0336542, -1.45692, 0.323532, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.2, 1, -0.0452293, -1.75482, 0.391734, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.25, 1, 0.0926713, -1.62165, 0.363375, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, 1.18685, -0.378264, 0.0954279, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, 1.51909, 0.00473738, 0.0141962, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, 1.55064, 0.0706801, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.5, 1, 1.44211, 0.0639179, 0, 0, 0, 0, 1, 1, 1, 1, 0.75, 1, 0.54098, 0.00832748, 0, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, 0.432091, 0.00163841, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.85, 1, 0.405204, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.405204, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/19/type"> "transform" </string>
- <node_path name="tracks/19/path"> "Armature/Skeleton:l-ARMORIENT" </node_path>
- <int name="tracks/19/interp"> 1 </int>
- <real_array name="tracks/19/keys" len="168"> 0, 1, -1.5774, 0.0723579, 0, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -1.5235, 0.0690539, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, -1.38104, 0.0602572, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, -0.448482, 0.0061903, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, -0.312683, -0.140136, 0.0283925, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.5, 1, -0.161211, -0.627825, 0.135386, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, -0.030728, -1.28144, 0.283529, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.6, 1, 0.0389389, -1.69292, 0.377552, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.65, 1, -0.0330012, -1.68882, 0.377568, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.7, 1, -0.409697, -1.26443, 0.283661, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.75, 1, -1.00503, -0.588506, 0.135634, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, -1.45325, -0.0721812, 0.0284887, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.85, 1, -1.5774, 0.0723579, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -1.5774, 0.0723579, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/20/type"> "transform" </string>
- <node_path name="tracks/20/path"> "Armature/Skeleton:hip" </node_path>
- <int name="tracks/20/interp"> 1 </int>
- <real_array name="tracks/20/keys" len="216"> 0, 1, 0.050238, 0.697428, 0.108012, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1, 0.05, 1, 0.0669454, 0.729981, 0.0847113, 0.0751978, 0.000902196, 0.0773167, 0.994166, 1, 1, 1, 0.15, 1, 0.147711, 0.887191, -0.02789, 0.103321, 0.0347243, 0.0196114, 0.993848, 1, 1, 1, 0.2, 1, 0.168294, 0.927241, -0.0565808, 0.110419, 0.0433374, -0.00845134, 0.992904, 1, 1, 1, 0.25, 1, 0.154709, 0.910602, -0.0446639, 0.107418, 0.0422538, -0.0318613, 0.992804, 1, 1, 1, 0.3, 1, 0.0960078, 0.836978, 0.00806546, 0.0942701, 0.034167, -0.0564973, 0.993355, 1, 1, 1, 0.35, 1, 0.021745, 0.753374, 0.0679436, 0.0793445, 0.0222103, -0.0760792, 0.993692, 1, 1, 1, 0.4, 1, -0.035471, 0.705747, 0.102054, 0.07085, 0.00995431, -0.0854402, 0.993771, 1, 1, 1, 0.45, 1, -0.0674228, 0.714066, 0.0960958, 0.0723594, -0.00257329, -0.0821245, 0.993989, 1, 1, 1, 0.5, 1, -0.0866932, 0.776805, 0.0511615, 0.0836199, -0.0185098, -0.0626717, 0.994353, 1, 1, 1, 0.55, 1, -0.0950061, 0.863738, -0.0110998, 0.0991637, -0.0338542, -0.0304325, 0.994029, 1, 1, 1, 0.6, 1, -0.0971422, 0.918921, -0.0506222, 0.108957, -0.0424157, -6.6921e-05, 0.993141, 1, 1, 1, 0.65, 1, -0.0894483, 0.918925, -0.0506237, 0.108927, -0.0421963, 0.0241723, 0.99286, 1, 1, 1, 0.7, 1, -0.0546535, 0.863773, -0.0111129, 0.0990954, -0.0332032, 0.0485143, 0.99334, 1, 1, 1, 0.75, 1, 0.000162542, 0.776872, 0.051137, 0.0835711, -0.0190219, 0.071275, 0.993768, 1, 1, 1, 0.8, 1, 0.0397389, 0.714092, 0.0960863, 0.072346, -0.00878352, 0.08392, 0.993804, 1, 1, 1, 0.85, 1, 0.050238, 0.697428, 0.108012, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1, 1.25, 1, 0.050238, 0.697428, 0.108012, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1 </real_array>
- <string name="tracks/21/type"> "transform" </string>
- <node_path name="tracks/21/path"> "Armature/Skeleton:waist" </node_path>
- <int name="tracks/21/interp"> 1 </int>
- <real_array name="tracks/21/keys" len="180"> 0, 1, 7.45059e-09, -5.21541e-08, 2.38419e-07, 0.0550011, -0.00481196, -0.0870228, 0.994675, 1, 1, 1, 0.05, 1, -2.16067e-08, -1.49015e-09, 1.19209e-07, 0.0607085, -0.00428583, -0.0791363, 0.995004, 1, 1, 1, 0.1, 1, -2.23518e-09, 4.61936e-08, 1.49012e-07, 0.0742298, -0.00290666, -0.0580589, 0.995545, 1, 1, 1, 0.2, 1, -1.22934e-08, -7.00588e-08, 1.49012e-07, 0.0953622, 0.000412438, -0.00409159, 0.995434, 1, 1, 1, 0.25, 1, -1.86265e-08, 1.39698e-08, -1.49012e-07, 0.0924473, 0.00171257, 0.0202586, 0.99551, 1, 1, 1, 0.35, 1, -1.56462e-08, 3.1013e-08, 0, 0.0648424, 0.00419923, 0.0731356, 0.995203, 1, 1, 1, 0.4, 1, 2.23523e-09, -2.84985e-08, 1.19209e-07, 0.0564666, 0.00472734, 0.0850757, 0.994762, 1, 1, 1, 0.45, 1, -4.47039e-09, 2.23518e-08, -8.9407e-08, 0.0579181, 0.00454757, 0.0830774, 0.994848, 1, 1, 1, 0.5, 1, 8.43755e-15, -5.58794e-08, 8.9407e-08, 0.0689504, 0.00348495, 0.0670145, 0.995361, 1, 1, 1, 0.6, 1, 5.5879e-09, -7.60309e-08, -2.98023e-08, 0.0939097, 5.69107e-05, 0.0121633, 0.995506, 1, 1, 1, 0.65, 1, 1.78815e-08, -2.31898e-08, 3.27826e-07, 0.0939129, -0.00128467, -0.0120988, 0.995506, 1, 1, 1, 0.75, 1, -1.86265e-09, 3.11993e-08, -2.98023e-08, 0.0689717, -0.00392611, -0.0670089, 0.995358, 1, 1, 1, 0.8, 1, 1.49013e-09, 4.80559e-08, 0, 0.0579302, -0.00464071, -0.0830884, 0.994846, 1, 1, 1, 0.85, 1, 7.45059e-09, -5.21541e-08, 2.38419e-07, 0.0550011, -0.00481196, -0.0870228, 0.994675, 1, 1, 1, 1.25, 1, 7.45059e-09, -5.21541e-08, 2.38419e-07, 0.0550011, -0.00481196, -0.0870228, 0.994675, 1, 1, 1 </real_array>
- <string name="tracks/22/type"> "transform" </string>
- <node_path name="tracks/22/path"> "Armature/Skeleton:chest" </node_path>
- <int name="tracks/22/interp"> 1 </int>
- <real_array name="tracks/22/keys" len="168"> 0, 1, -1.93979e-09, 3.72529e-08, -1.78814e-07, 0.0947232, -0.00739035, -0.0868418, 0.991681, 1, 1, 1, 0.05, 1, 9.31322e-10, 7.07805e-08, 5.96046e-08, 0.0947233, -0.00739035, -0.0868419, 0.991681, 1, 1, 1, 0.1, 1, 6.51926e-10, 7.07805e-08, 5.96046e-08, 0.0949443, -0.00694628, -0.0757376, 0.992573, 1, 1, 1, 0.15, 1, 3.7253e-10, -2.6077e-08, -2.38419e-07, 0.0959905, -0.00433497, -0.0114678, 0.995307, 1, 1, 1, 0.25, 1, 1.86265e-08, 2.23517e-08, 1.19209e-07, 0.0965992, 0.00494126, 0.201269, 0.974749, 1, 1, 1, 0.3, 1, -7.68343e-10, 7.45058e-09, 1.78814e-07, 0.0963173, 0.00675391, 0.221794, 0.970301, 1, 1, 1, 0.4, 1, -1.56574e-10, 7.82311e-08, -1.78814e-07, 0.0949654, 0.0073896, 0.100605, 0.990356, 1, 1, 1, 0.45, 1, 3.30057e-09, 1.08033e-07, -5.96046e-08, 0.0947232, 0.00739035, 0.0868418, 0.991681, 1, 1, 1, 0.5, 1, -3.25963e-09, -9.31323e-08, 5.96046e-08, 0.0947232, 0.00739035, 0.0868418, 0.991681, 1, 1, 1, 0.55, 1, -2.10027e-08, 7.45058e-08, -1.78814e-07, 0.0955253, 0.00546829, 0.0431828, 0.994475, 1, 1, 1, 0.65, 1, 1.26195e-08, -4.84288e-08, -2.38419e-07, 0.0967914, -0.0040173, -0.170015, 0.980668, 1, 1, 1, 0.7, 1, 1.23865e-08, -8.19564e-08, -5.96046e-08, 0.0964064, -0.00640121, -0.223121, 0.969991, 1, 1, 1, 0.75, 1, 1.86265e-09, -7.07805e-08, -2.98023e-07, 0.0963505, -0.00664593, -0.228565, 0.968726, 1, 1, 1, 1.25, 1, -1.93979e-09, 3.72529e-08, -1.78814e-07, 0.0963505, -0.00664594, -0.228565, 0.968726, 1, 1, 1 </real_array>
- <string name="tracks/23/type"> "transform" </string>
- <node_path name="tracks/23/path"> "Armature/Skeleton:neck" </node_path>
- <int name="tracks/23/interp"> 1 </int>
- <real_array name="tracks/23/keys" len="24"> 0, 1, -1.95579e-08, -1.49012e-08, -9.53674e-07, -7.45058e-09, -2.48375e-09, 8.87174e-09, 1, 1, 1, 1, 1.25, 1, -6.51927e-08, -7.45058e-08, -9.53674e-07, 6.80667e-18, 2.71908e-09, -1.56593e-08, 1, 1, 1, 1 </real_array>
- <string name="tracks/24/type"> "transform" </string>
- <node_path name="tracks/24/path"> "Armature/Skeleton:headtracker" </node_path>
- <int name="tracks/24/interp"> 1 </int>
- <real_array name="tracks/24/keys" len="204"> 0, 1, 2.79375e-09, -5.96046e-07, -2.50526e-07, 0.174741, -0.0963796, 0.0144345, 0.97978, 1, 1, 1, 0.05, 1, -3.7254e-09, -2.08616e-07, -1.22236e-07, 0.195715, -0.0950264, 0.0238173, 0.975755, 1, 1, 1, 0.1, 1, 4.54485e-08, -7.15256e-07, -7.68341e-08, 0.229373, -0.0816785, 0.0404464, 0.969062, 1, 1, 1, 0.15, 1, -1.49012e-08, -6.85453e-07, -8.59145e-08, 0.25499, -0.0176933, 0.0391946, 0.965987, 1, 1, 1, 0.25, 1, 1.4901e-08, -1.49012e-07, -1.78115e-07, 0.23692, 0.192561, -0.0167461, 0.952108, 1, 1, 1, 0.3, 1, -4.61937e-08, -4.47035e-07, -1.46218e-07, 0.20349, 0.220566, -0.0253329, 0.953573, 1, 1, 1, 0.35, 1, 8.94071e-09, -2.68221e-07, -1.97906e-08, 0.179164, 0.172369, -0.0185073, 0.968425, 1, 1, 1, 0.4, 1, 2.23509e-09, -3.57628e-07, -9.56934e-08, 0.17384, 0.110352, -0.0138213, 0.978474, 1, 1, 1, 0.45, 1, -2.75671e-08, -7.45058e-07, 2.63099e-08, 0.188123, 0.0930304, -0.0247279, 0.977417, 1, 1, 1, 0.5, 1, -9.31436e-10, 4.47035e-07, -6.37956e-08, 0.217624, 0.0872372, -0.0441829, 0.971122, 1, 1, 1, 0.55, 1, 1.04306e-08, -2.38419e-07, -1.33412e-07, 0.247766, 0.0401273, -0.0490683, 0.966744, 1, 1, 1, 0.65, 1, 3.27827e-08, -4.47035e-07, -6.26314e-08, 0.245106, -0.170404, 0.00637661, 0.954382, 1, 1, 1, 0.7, 1, 3.27823e-08, -1.49012e-07, -6.70552e-08, 0.212986, -0.224596, 0.0272969, 0.950499, 1, 1, 1, 0.75, 1, -7.45057e-08, 0, 6.33299e-08, 0.183845, -0.233119, 0.0392625, 0.954104, 1, 1, 1, 0.8, 1, -6.7055e-08, -5.96046e-07, -5.00586e-08, 0.175853, -0.235075, 0.0484733, 0.954707, 1, 1, 1, 0.85, 1, 7.45066e-09, -6.55651e-07, 6.75209e-09, 0.174943, -0.235515, 0.051072, 0.95463, 1, 1, 1, 1.25, 1, 7.45066e-09, -6.55651e-07, 6.75209e-09, 0.174943, -0.235515, 0.051072, 0.95463, 1, 1, 1 </real_array>
- <string name="tracks/25/type"> "transform" </string>
- <node_path name="tracks/25/path"> "Armature/Skeleton:head" </node_path>
- <int name="tracks/25/interp"> 1 </int>
- <real_array name="tracks/25/keys" len="24"> 0, 1, -1.25867e-08, -4.23752e-08, -2.57976e-07, 2.23517e-08, 3.7017e-10, 7.60394e-10, 1, 1, 1, 1, 1.25, 1, 1.23749e-08, -2.09548e-09, 2.43308e-07, 2.23517e-08, -2.79233e-10, -7.29088e-11, 1, 1, 1, 1 </real_array>
- <string name="tracks/26/type"> "transform" </string>
- <node_path name="tracks/26/path"> "Armature/Skeleton:vent" </node_path>
- <int name="tracks/26/interp"> 1 </int>
- <real_array name="tracks/26/keys" len="24"> 0, 1, 5.20962e-08, 0.00292337, 0.204329, -7.21775e-09, 1.1358e-11, -7.03732e-10, 1, 1, 1, 1, 1.25, 1, 4.12186e-08, 0.00292328, 0.20433, -8.14907e-09, 9.21561e-11, 1.63806e-10, 1, 1, 1, 1 </real_array>
-
- </resource>
- <resource type="Animation" path="local://12">
- <string name="resource/name"> "walk-cycle" </string>
- <real name="length"> 1.041667 </real>
- <bool name="loop"> True </bool>
- <real name="step"> 0.1 </real>
- <string name="tracks/0/type"> "transform" </string>
- <node_path name="tracks/0/path"> "Armature/Skeleton:r-arm" </node_path>
- <int name="tracks/0/interp"> 1 </int>
- <real_array name="tracks/0/keys" len="228"> 0, 1, 7.7486e-07, -3.57628e-07, 5.66244e-07, 0.132777, -0.115851, -0.0857195, 0.980613, 1, 1, 1, 0.05, 1, 4.17233e-07, 1.19209e-07, 3.27826e-07, 0.136218, -0.113975, -0.0877542, 0.980181, 1, 1, 1, 0.1, 1, 5.06639e-07, -2.38419e-07, 2.98023e-07, 0.144837, -0.108331, -0.0933223, 0.97907, 1, 1, 1, 0.15, 1, 5.36442e-07, -3.57628e-07, 3.57628e-07, 0.15539, -0.0990044, -0.102617, 0.977508, 1, 0.999999, 1, 0.2, 1, 7.15256e-07, -3.57628e-07, 4.47035e-07, 0.162073, -0.0835771, -0.115431, 0.976434, 1, 1, 1, 0.25, 1, 6.25849e-07, -3.57628e-07, 4.17233e-07, 0.160674, -0.0537521, -0.128708, 0.977102, 1, 1, 1, 0.3, 1, 6.85453e-07, -3.57628e-07, 2.98023e-07, 0.144844, 0.00232148, -0.137246, 0.979887, 1, 1, 1, 0.45, 1, 9.53674e-07, -7.15256e-07, 6.85453e-07, 0.0267683, 0.215793, -0.138386, 0.966212, 1, 1, 1, 0.5, 1, 7.7486e-07, -3.57628e-07, 4.17233e-07, -0.00441569, 0.255036, -0.137846, 0.957045, 1, 1, 1, 0.55, 1, 8.34465e-07, -5.96046e-07, 5.36442e-07, -0.00986276, 0.263176, -0.137756, 0.954811, 1, 1, 1, 0.6, 1, 4.76837e-07, 0, 3.8743e-07, 0.0174093, 0.245944, -0.13741, 0.959337, 1, 1, 1, 0.7, 1, 3.27826e-07, -1.19209e-07, 2.68221e-07, 0.12402, 0.181155, -0.127036, 0.967297, 1, 1, 1, 0.75, 1, 7.45058e-07, 0, 4.47035e-07, 0.157369, 0.166922, -0.11544, 0.96646, 1, 1, 1, 0.8, 1, 8.34465e-07, -1.19209e-07, 4.47035e-07, 0.166665, 0.143487, -0.108193, 0.969499, 1, 1, 1, 0.85, 1, 2.98023e-07, 0, 1.49012e-07, 0.164004, 0.0866041, -0.105149, 0.977009, 1, 0.999999, 1, 0.95, 1, 4.76837e-07, 0, 2.38419e-07, 0.144168, -0.0621538, -0.0938402, 0.983131, 1, 1, 1, 1, 1, 8.64267e-07, -4.76837e-07, 6.85453e-07, 0.135099, -0.105557, -0.0876091, 0.98129, 1, 1, 1, 1.05, 1, 7.7486e-07, -3.57628e-07, 5.66244e-07, 0.132777, -0.115851, -0.0857195, 0.980613, 1, 1, 1, 1.25, 1, 7.7486e-07, -3.57628e-07, 5.66244e-07, 0.132777, -0.115851, -0.0857195, 0.980613, 1, 1, 1 </real_array>
- <string name="tracks/1/type"> "transform" </string>
- <node_path name="tracks/1/path"> "Armature/Skeleton:r-forearm" </node_path>
- <int name="tracks/1/interp"> 1 </int>
- <real_array name="tracks/1/keys" len="228"> 0, 1, 7.45058e-07, -8.04663e-07, -8.34465e-07, -0.0607703, -0.240987, 0.00892511, 0.968583, 1, 1, 1, 0.05, 1, -2.98023e-07, -3.57628e-07, 1.78814e-07, -0.0608664, -0.247441, 0.00903588, 0.966947, 1, 0.999999, 1, 0.1, 1, -1.78814e-07, -7.45058e-07, -1.19209e-07, -0.0607357, -0.265635, 0.00908754, 0.962116, 1, 1, 1, 0.15, 1, 4.17233e-07, -8.64267e-07, -4.17233e-07, -0.0586521, -0.298966, 0.00880687, 0.952419, 1, 1, 1, 0.25, 1, 3.8743e-07, -5.96046e-07, -2.98023e-07, -0.0404347, -0.402042, 0.00443354, 0.914717, 1, 1, 1, 0.3, 1, -2.98023e-08, -6.85453e-07, -2.38419e-07, -0.0222657, -0.438743, -0.00390802, 0.898328, 1, 1, 1, 0.35, 1, -3.27826e-07, -2.68221e-07, -1.78814e-07, -0.001747, -0.450439, -0.0151044, 0.892678, 1, 0.999999, 1, 0.4, 1, -2.98023e-08, -3.57628e-07, -4.76837e-07, 0.0165229, -0.440184, -0.0247739, 0.897414, 1, 1, 1, 0.5, 1, 2.98023e-08, -3.27826e-07, 0, 0.0357718, -0.396841, -0.0343986, 0.916545, 1, 1, 1, 0.55, 1, 1.49012e-07, -6.25849e-07, -1.78814e-07, 0.0355214, -0.39013, -0.0350975, 0.919405, 1, 1, 1, 0.6, 1, 1.78814e-07, -5.06639e-07, -5.36442e-07, 0.01977, -0.384514, -0.0345495, 0.92226, 1, 1, 1, 0.65, 1, -1.19209e-07, -4.17233e-07, -2.38419e-07, -0.0162325, -0.357154, -0.033198, 0.933314, 1, 0.999999, 1, 0.75, 1, -2.98023e-08, -3.57628e-07, -2.98023e-07, -0.0986698, -0.203446, -0.0321126, 0.973572, 1, 0.999999, 1, 0.8, 1, 5.96046e-08, -7.45058e-07, -2.38419e-07, -0.110421, -0.161891, -0.0281555, 0.980207, 1, 1, 1, 0.85, 1, 4.76837e-07, -8.04663e-07, -8.34465e-07, -0.104832, -0.172931, -0.0183971, 0.979166, 1, 0.999999, 1, 0.95, 1, 0, -6.55651e-07, -5.96046e-07, -0.0743493, -0.227469, 0.00271093, 0.970939, 1, 1, 1, 1, 1, -2.98023e-08, -3.57628e-07, -2.38419e-07, -0.0636988, -0.238854, 0.00790001, 0.968932, 1, 1, 1, 1.05, 1, 7.45058e-07, -8.04663e-07, -8.34465e-07, -0.0607703, -0.240987, 0.00892511, 0.968583, 1, 1, 1, 1.25, 1, 7.45058e-07, -8.04663e-07, -8.34465e-07, -0.0607703, -0.240987, 0.00892511, 0.968583, 1, 1, 1 </real_array>
- <string name="tracks/2/type"> "transform" </string>
- <node_path name="tracks/2/path"> "Armature/Skeleton:l-arm" </node_path>
- <int name="tracks/2/interp"> 1 </int>
- <real_array name="tracks/2/keys" len="216"> 0, 1, -7.45058e-07, -4.76837e-07, 4.47035e-07, -0.0127337, -0.264935, 0.137763, 0.954289, 1, 1, 1, 0.05, 1, -3.8743e-07, 0, 2.38419e-07, 0.0104992, -0.248758, 0.137429, 0.958709, 1, 1, 1, 0.15, 1, -5.66244e-07, -1.19209e-07, 4.47035e-07, 0.119317, -0.176495, 0.127478, 0.968691, 1, 1, 1, 0.2, 1, -5.06639e-07, -1.19209e-07, 3.27826e-07, 0.156208, -0.160784, 0.115735, 0.967653, 1, 1, 1, 0.25, 1, -4.17233e-07, -1.19209e-07, 2.68221e-07, 0.170588, -0.146234, 0.10696, 0.968543, 1, 0.999999, 1, 0.3, 1, -8.34465e-07, -3.57628e-07, 8.9407e-07, 0.16899, -0.106962, 0.104274, 0.974232, 1, 1, 1, 0.45, 1, -9.23872e-07, -5.96046e-07, 7.7486e-07, 0.141826, 0.058077, 0.0901382, 0.984067, 1, 1, 1, 0.5, 1, -7.7486e-07, -5.96046e-07, 2.98023e-07, 0.134623, 0.0959315, 0.0862667, 0.982462, 1, 1, 1, 0.55, 1, -7.45058e-07, -3.57628e-07, 6.25849e-07, 0.133233, 0.11842, 0.0861958, 0.980202, 1, 1, 1, 0.6, 1, -4.76837e-07, 0, 4.47035e-07, 0.137596, 0.131505, 0.0903706, 0.977551, 1, 1, 1, 0.65, 1, -6.55651e-07, -3.57628e-07, 5.36442e-07, 0.146837, 0.135484, 0.0990691, 0.974817, 1, 1, 1, 0.7, 1, -5.96046e-07, -3.57628e-07, 6.25849e-07, 0.15676, 0.127354, 0.111789, 0.972991, 1, 1, 1, 0.75, 1, -4.17233e-07, 0, 3.8743e-07, 0.161767, 0.101349, 0.126219, 0.973462, 1, 1, 1, 0.8, 1, -6.85453e-07, -3.57628e-07, 5.06639e-07, 0.154473, 0.0449621, 0.136756, 0.977453, 1, 1, 1, 0.95, 1, -6.55651e-07, -2.38419e-07, 4.76837e-07, 0.0363447, -0.203514, 0.138296, 0.968574, 1, 1, 1, 1, 1, -5.96046e-07, -3.57628e-07, 3.57628e-07, -0.00218869, -0.252498, 0.137778, 0.957735, 1, 1, 1, 1.05, 1, -7.45058e-07, -4.76837e-07, 4.47035e-07, -0.0127337, -0.264935, 0.137763, 0.954289, 1, 1, 1, 1.25, 1, -7.45058e-07, -4.76837e-07, 4.47035e-07, -0.0127337, -0.264935, 0.137763, 0.954289, 1, 1, 1 </real_array>
- <string name="tracks/3/type"> "transform" </string>
- <node_path name="tracks/3/path"> "Armature/Skeleton:l-forearm" </node_path>
- <int name="tracks/3/interp"> 1 </int>
- <real_array name="tracks/3/keys" len="192"> 0, 1, 3.57628e-07, -5.96046e-07, -3.57628e-07, 0.0370915, 0.39046, 0.0351404, 0.919201, 1, 1, 1, 0.05, 1, -1.49012e-07, -5.96046e-07, -2.38419e-07, 0.0247868, 0.388139, 0.0345456, 0.92062, 1, 1, 1, 0.1, 1, -3.57628e-07, -5.66244e-07, -4.76837e-07, -0.00839952, 0.367653, 0.0329431, 0.929342, 1, 1, 1, 0.15, 1, -1.78814e-07, -5.66244e-07, -7.7486e-07, -0.0538019, 0.307417, 0.0309853, 0.949547, 1, 1, 1, 0.2, 1, 0, -3.8743e-07, -4.17233e-07, -0.0934157, 0.21941, 0.0316565, 0.970634, 1, 1, 1, 0.25, 1, -1.49012e-07, -7.7486e-07, -3.57628e-07, -0.112029, 0.160435, 0.0303507, 0.980198, 1, 1, 1, 0.3, 1, 1.19209e-07, -7.15256e-07, -2.38419e-07, -0.111906, 0.1565, 0.0231637, 0.981045, 1, 1, 1, 0.35, 1, 2.68221e-07, -5.06639e-07, -2.38419e-07, -0.104709, 0.167819, 0.0144275, 0.980135, 1, 1, 1, 0.6, 1, 2.38419e-07, -3.57628e-07, -2.98023e-07, -0.0540049, 0.274564, -0.0119163, 0.959977, 1, 1, 1, 0.65, 1, 2.68221e-07, -2.68221e-07, 5.96046e-08, -0.0496356, 0.312827, -0.0136146, 0.948415, 1, 1, 1, 0.8, 1, 1.78814e-07, -3.8743e-07, -2.38419e-07, -0.0228587, 0.449632, -0.00310725, 0.892916, 1, 1, 1, 0.85, 1, -2.08616e-07, -6.25849e-07, -5.36442e-07, -0.00418434, 0.463526, 0.00969348, 0.886021, 1, 1, 1, 0.9, 1, -2.68221e-07, -6.85453e-07, -1.19209e-07, 0.0143603, 0.452468, 0.0218435, 0.891397, 1, 1, 1, 1, 1, 8.9407e-08, -5.96046e-07, -5.36442e-07, 0.0356796, 0.398885, 0.0342096, 0.915668, 1, 1, 1, 1.05, 1, 3.57628e-07, -5.96046e-07, -3.57628e-07, 0.0370915, 0.39046, 0.0351404, 0.919201, 1, 1, 1, 1.25, 1, 3.57628e-07, -5.96046e-07, -3.57628e-07, 0.0370915, 0.39046, 0.0351404, 0.919201, 1, 1, 1 </real_array>
- <string name="tracks/4/type"> "transform" </string>
- <node_path name="tracks/4/path"> "Armature/Skeleton:r-thigh" </node_path>
- <int name="tracks/4/interp"> 1 </int>
- <real_array name="tracks/4/keys" len="180"> 0, 1, -5.96046e-08, 7.45058e-09, -1.3411e-07, -0.47466, -0.0131527, -0.012987, 0.879975, 1, 1, 1, 0.05, 1, 2.98023e-08, 2.23517e-08, -2.23517e-07, -0.410091, -0.00379406, -0.0158917, 0.911898, 1, 1, 1, 0.25, 1, -1.19209e-07, 1.11759e-07, -5.21541e-07, 0.0997313, 0.0337367, -0.0261638, 0.994098, 1, 1, 1, 0.3, 1, 8.9407e-08, 4.47035e-08, -4.02331e-07, 0.122513, 0.0214196, -0.0200121, 0.992034, 1, 1, 1, 0.45, 1, 1.19209e-07, 7.45058e-09, -3.27826e-07, 0.229705, -0.0511077, 0.00301582, 0.971913, 1, 1, 1, 0.5, 1, 0, 3.72529e-08, -3.72529e-07, 0.236488, -0.0697987, 0.00859063, 0.969086, 1, 1, 1, 0.55, 1, 0, 2.98023e-08, -2.5332e-07, 0.206064, -0.0732532, 0.0100766, 0.975741, 1, 1, 1, 0.6, 1, -2.98023e-08, 4.47035e-08, -2.68221e-07, 0.118009, -0.0599028, 0.00750554, 0.991176, 1, 1, 1, 0.65, 1, -8.9407e-08, 2.23517e-08, -2.83122e-07, -0.0368129, -0.031384, 0.00214083, 0.998827, 1, 1, 1, 0.8, 1, -5.96046e-08, 2.23517e-08, -3.42727e-07, -0.634332, 0.0354032, -0.00990766, 0.772186, 1, 1, 1, 0.85, 1, 0, 2.23517e-08, -5.51343e-07, -0.746229, 0.0185993, -0.00698883, 0.665393, 1, 1, 1, 0.9, 1, 2.98023e-08, 1.49012e-08, -3.72529e-07, -0.740985, -0.00577112, -0.000829951, 0.671497, 1, 1, 1, 1, 1, 0, 2.98023e-08, -2.68221e-07, -0.523042, -0.0161244, -0.00986391, 0.852097, 1, 1, 1, 1.05, 1, -5.96046e-08, 7.45058e-09, -1.3411e-07, -0.47466, -0.0131527, -0.012987, 0.879975, 1, 1, 1, 1.25, 1, -5.96046e-08, 7.45058e-09, -1.3411e-07, -0.47466, -0.0131527, -0.012987, 0.879975, 1, 1, 1 </real_array>
- <string name="tracks/5/type"> "transform" </string>
- <node_path name="tracks/5/path"> "Armature/Skeleton:r-leg" </node_path>
- <int name="tracks/5/interp"> 1 </int>
- <real_array name="tracks/5/keys" len="216"> 0, 1, 9.0804e-08, -5.21541e-08, 5.36442e-07, -0.373219, -0.0555838, 8.64882e-05, 0.926077, 1, 1, 1, 0.05, 1, 2.50293e-08, 1.3411e-07, 5.96046e-07, -0.322099, -0.0481091, 0.000521386, 0.945483, 1, 1, 1, 0.1, 1, 1.20257e-07, -1.49012e-07, 7.15256e-07, -0.224139, -0.0330777, 0.00125387, 0.973995, 1, 1, 1, 0.15, 1, 3.94648e-08, -1.3411e-07, 6.55651e-07, -0.165692, -0.0218823, 0.00143977, 0.985934, 1, 1, 1, 0.2, 1, 1.33412e-07, -1.56462e-07, 5.36442e-07, -0.09297, -0.0104596, 0.00125276, 0.995613, 1, 1, 1, 0.25, 1, 3.55067e-08, 4.47035e-08, 1.78814e-07, -0.0411288, -0.0028586, 0.000542978, 0.99915, 1, 1, 1, 0.35, 1, 9.26666e-08, 5.96046e-08, 6.55651e-07, -0.159491, 0.00874812, -0.00126692, 0.98716, 1, 1, 1, 0.45, 1, 3.87663e-08, 0, 4.76837e-07, -0.233894, 0.0318884, -0.00310529, 0.971734, 1, 1, 1, 0.5, 1, -3.53903e-08, -7.45058e-08, 5.96046e-07, -0.280896, 0.0453351, -0.00364749, 0.95866, 1, 1, 1, 0.55, 1, 1.59489e-08, 4.47035e-08, 5.96046e-07, -0.352331, 0.0592861, -0.00363569, 0.933989, 1, 1, 1, 0.6, 1, 2.16532e-08, 1.3411e-07, 6.55651e-07, -0.469209, 0.0766892, -0.00261066, 0.879747, 1, 1, 1, 0.75, 1, 9.51113e-08, -2.01166e-07, 7.15256e-07, -0.846575, 0.0999882, 0.00219129, 0.522789, 1, 1, 1, 0.8, 1, 3.77186e-08, -1.49012e-07, 6.55651e-07, 0.900504, -0.0754152, -0.00223886, -0.428252, 1, 1, 1, 0.85, 1, 4.92437e-08, 1.49012e-07, 6.55651e-07, 0.906482, -0.0264902, -0.00126108, -0.42141, 1, 1, 1, 0.9, 1, -2.71248e-08, 1.63913e-07, 5.36442e-07, -0.830638, -0.0316768, -0.000334372, 0.555911, 1, 1, 1, 1, 1, 2.87546e-08, 4.84288e-07, 7.7486e-07, -0.453335, -0.0623349, -0.000381388, 0.889158, 1, 1, 1, 1.05, 1, 9.0804e-08, -5.21541e-08, 5.36442e-07, -0.373219, -0.0555838, 8.64882e-05, 0.926077, 1, 1, 1, 1.25, 1, 9.0804e-08, -5.21541e-08, 5.36442e-07, -0.373219, -0.0555838, 8.64882e-05, 0.926077, 1, 1, 1 </real_array>
- <string name="tracks/6/type"> "transform" </string>
- <node_path name="tracks/6/path"> "Armature/Skeleton:r-foot" </node_path>
- <int name="tracks/6/interp"> 1 </int>
- <real_array name="tracks/6/keys" len="168"> 0, 1, 5.21541e-08, -1.19209e-07, 9.31323e-08, 0.00219921, 0.118787, -0.0237834, 0.992633, 1, 1, 1, 0.05, 1, 5.96046e-08, 0, -5.58794e-08, 0.00569734, 0.111426, -0.0235639, 0.993477, 1, 1, 1, 0.1, 1, 4.47035e-08, -1.19209e-07, 3.35276e-08, 0.015864, 0.0910374, -0.022104, 0.995476, 1, 1, 1, 0.25, 1, 2.98023e-08, 1.19209e-07, -5.58794e-08, 0.0701794, 0.000367211, 0.000696922, 0.997534, 1, 1, 1, 0.35, 1, 8.19564e-08, -1.19209e-07, -1.11759e-08, 0.121501, -0.050768, 0.0840024, 0.987727, 1, 1, 1, 0.4, 1, 7.45058e-08, 1.19209e-07, 1.04308e-07, 0.115586, -0.0703619, 0.0928345, 0.986444, 1, 1, 1, 0.45, 1, 7.45058e-08, 1.19209e-07, 3.72529e-08, 0.0659214, -0.0866695, 0.0774413, 0.991033, 1, 1, 1, 0.5, 1, -5.96046e-08, 1.19209e-07, -1.11759e-07, 0.0031081, -0.0968864, 0.054063, 0.993821, 1, 1, 1, 0.55, 1, 5.96046e-08, 0, -6.70552e-08, -0.0166663, -0.0982007, 0.0374834, 0.994321, 1, 1, 1, 0.6, 1, 5.96046e-08, 1.19209e-07, -4.84288e-08, -0.0148445, -0.0906634, 0.0264974, 0.995418, 1, 1, 1, 0.65, 1, 0, 0, 4.09782e-08, -0.0108355, -0.0727448, 0.0177847, 0.997133, 1, 1, 1, 1, 1, 6.70552e-08, 0, 7.07805e-08, 0.00219189, 0.11394, -0.0230367, 0.993218, 1, 1, 1, 1.05, 1, 5.21541e-08, -1.19209e-07, 9.31323e-08, 0.00219921, 0.118787, -0.0237834, 0.992633, 1, 1, 1, 1.25, 1, 5.21541e-08, -1.19209e-07, 9.31323e-08, 0.00219921, 0.118787, -0.0237834, 0.992633, 1, 1, 1 </real_array>
- <string name="tracks/7/type"> "transform" </string>
- <node_path name="tracks/7/path"> "Armature/Skeleton:l-thigh" </node_path>
- <int name="tracks/7/interp"> 1 </int>
- <real_array name="tracks/7/keys" len="144"> 0, 1, 2.98023e-08, 2.98023e-08, 1.04308e-07, 0.217295, 0.0746597, -0.0103365, 0.973192, 1, 0.999999, 1, 0.05, 1, -8.9407e-08, 1.49012e-08, 1.49012e-08, 0.151772, 0.0624666, -0.00777083, 0.986409, 1, 1, 1, 0.1, 1, -2.98023e-08, 2.98023e-08, -8.9407e-08, -0.00391929, 0.0335048, -0.00214722, 0.999429, 1, 0.999999, 1, 0.3, 1, 0, 3.72529e-08, -1.49012e-07, -0.748933, -0.0405244, 0.0112371, 0.66131, 1, 1, 1, 0.35, 1, 5.96046e-08, 7.45058e-09, -3.12924e-07, -0.802758, -0.0149771, 0.00481471, 0.596097, 1, 1, 1, 0.4, 1, 0, 7.45058e-09, -1.78814e-07, -0.770121, 0.00992629, -0.000335305, 0.63782, 1, 1, 1, 0.8, 1, -5.96046e-08, 5.21541e-08, -1.04308e-07, 0.0878935, -0.0301616, 0.023494, 0.995396, 1, 1, 1, 0.85, 1, 2.98023e-08, 5.21541e-08, -2.98023e-07, 0.0819817, -0.0162162, 0.0156585, 0.996379, 1, 0.999999, 1, 0.9, 1, -5.96046e-08, 7.45058e-09, -1.3411e-07, 0.0980511, 0.00664153, 0.00756362, 0.99513, 1, 0.999999, 1, 1, 1, -5.96046e-08, 2.98023e-08, -2.98023e-08, 0.201153, 0.0660118, -0.00800331, 0.9773, 1, 0.999999, 1, 1.05, 1, 2.98023e-08, 2.98023e-08, 1.04308e-07, 0.217295, 0.0746597, -0.0103365, 0.973192, 1, 0.999999, 1, 1.25, 1, 2.98023e-08, 2.98023e-08, 1.04308e-07, 0.217295, 0.0746597, -0.0103365, 0.973192, 1, 0.999999, 1 </real_array>
- <string name="tracks/8/type"> "transform" </string>
- <node_path name="tracks/8/path"> "Armature/Skeleton:l-leg" </node_path>
- <int name="tracks/8/interp"> 1 </int>
- <real_array name="tracks/8/keys" len="228"> 0, 1, 4.19095e-08, 1.41561e-07, 2.98023e-07, -0.33502, -0.0565195, 0.00376308, 0.940507, 1, 1, 1, 0.05, 1, 2.82889e-08, 1.86265e-07, 0, -0.412041, -0.0666523, 0.00293558, 0.908719, 1, 1, 1, 0.2, 1, -7.12462e-08, -1.2666e-07, 5.96046e-08, -0.831864, -0.10996, -0.00255585, 0.543972, 1, 1, 1, 0.25, 1, 2.32831e-09, -1.04308e-07, 5.96046e-08, 0.89602, 0.0970023, 0.00298318, -0.433277, 1, 1, 1, 0.3, 1, 1.9907e-08, 3.65078e-07, 2.98023e-07, 0.921569, 0.0590099, 0.00230107, -0.383696, 1, 1, 1, 0.35, 1, -8.28877e-08, -1.93715e-07, 2.38419e-07, 0.901128, 0.00554219, 0.000798309, -0.433517, 1, 1, 1, 0.4, 1, -7.53207e-08, 5.21541e-08, 1.19209e-07, -0.81758, 0.0439972, 0.000730356, 0.574132, 1, 1, 1, 0.5, 1, -2.91038e-09, 1.41561e-07, 2.38419e-07, -0.503688, 0.068707, 0.00074972, 0.861149, 1, 1, 1, 0.55, 1, 6.1933e-08, 8.19564e-08, 5.96046e-08, -0.352333, 0.0527461, -0.000239235, 0.934387, 1, 1, 1, 0.6, 1, -2.95695e-08, 1.04308e-07, 1.78814e-07, -0.244271, 0.03738, -0.00103017, 0.968986, 1, 1, 1, 0.65, 1, 9.54606e-09, 3.50177e-07, 1.78814e-07, -0.200824, 0.0283491, -0.00130918, 0.979216, 1, 1, 1, 0.7, 1, 2.01399e-08, 2.23517e-08, 0, -0.167963, 0.0193272, -0.0011918, 0.985603, 1, 1, 1, 0.75, 1, -2.47965e-08, -2.23517e-07, 1.19209e-07, -0.0847999, 0.00700657, -0.000838314, 0.996373, 1, 1, 1, 0.8, 1, -4.88944e-08, -7.45058e-09, 0, -0.073705, 0.000793342, 3.27131e-05, 0.99728, 1, 1, 1, 0.9, 1, -5.50644e-08, 0, 1.19209e-07, -0.297998, -0.0240387, 0.0012853, 0.954263, 1, 1, 1, 0.95, 1, -1.08266e-08, -2.98023e-08, 1.19209e-07, -0.340478, -0.0423349, 0.0021981, 0.939296, 1, 1, 1, 1, 1, 5.07571e-08, -1.63913e-07, 0, -0.339784, -0.0539663, 0.00332048, 0.938948, 1, 1, 1, 1.05, 1, 4.19095e-08, 1.41561e-07, 2.98023e-07, -0.33502, -0.0565195, 0.00376308, 0.940507, 1, 1, 1, 1.25, 1, 4.19095e-08, 1.41561e-07, 2.98023e-07, -0.33502, -0.0565195, 0.00376308, 0.940507, 1, 1, 1 </real_array>
- <string name="tracks/9/type"> "transform" </string>
- <node_path name="tracks/9/path"> "Armature/Skeleton:l-foot" </node_path>
- <int name="tracks/9/interp"> 1 </int>
- <real_array name="tracks/9/keys" len="192"> 0, 1, -3.72529e-08, 0, 8.19564e-08, -0.0168517, 0.0989445, -0.0394225, 0.994169, 1, 1, 1, 0.05, 1, 6.70552e-08, 1.19209e-07, -4.47035e-08, -0.0168456, 0.0944203, -0.0381151, 0.99466, 1, 1, 1, 0.1, 1, 1.49012e-08, 1.19209e-07, -3.35276e-08, -0.0167772, 0.0819293, -0.034504, 0.995899, 1, 1, 1, 0.15, 1, -7.45058e-09, 1.19209e-07, -1.3411e-07, -0.0165494, 0.0617975, -0.0286797, 0.997539, 1, 1, 1, 0.4, 1, -2.23517e-08, 0, 2.6077e-08, -0.00864448, -0.0855905, 0.0141105, 0.996193, 1, 1, 1, 0.45, 1, 7.45058e-09, 2.38419e-07, -7.45058e-08, -0.00528641, -0.10464, 0.0196597, 0.994302, 1, 1, 1, 0.5, 1, -1.49012e-08, 1.19209e-07, 7.45058e-09, -0.00140908, -0.115976, 0.0229639, 0.992986, 1, 1, 1, 0.55, 1, 1.49012e-08, 2.38419e-07, 3.72529e-08, 0.00315788, -0.117918, 0.023482, 0.992741, 1, 1, 1, 0.6, 1, -2.98023e-08, 1.19209e-07, -1.49012e-08, 0.00993965, -0.108994, 0.0205203, 0.993781, 1, 1, 1, 0.65, 1, 1.49012e-08, 0, 1.86265e-08, 0.0206495, -0.0875135, 0.0140912, 0.99585, 1, 1, 1, 0.8, 1, -2.23517e-08, 1.19209e-07, -3.72529e-09, 0.0751354, 0.00445886, 0.00173853, 0.997162, 1, 1, 1, 0.9, 1, 0, 0, -2.98023e-08, 0.131833, 0.0617586, 0.0448617, 0.988329, 1, 1, 1, 0.95, 1, 3.72529e-08, 0, -6.70552e-08, 0.10712, 0.0825392, 0.0325464, 0.99028, 1, 1, 1, 1, 1, 1.49012e-08, 2.38419e-07, -4.84288e-08, 0.0202877, 0.0962194, -0.0179372, 0.994992, 1, 1, 1, 1.05, 1, -3.72529e-08, 0, 8.19564e-08, -0.0168517, 0.0989445, -0.0394225, 0.994169, 1, 1, 1, 1.25, 1, -3.72529e-08, 0, 8.19564e-08, -0.0168517, 0.0989445, -0.0394225, 0.994169, 1, 1, 1 </real_array>
- <string name="tracks/10/type"> "transform" </string>
- <node_path name="tracks/10/path"> "Armature/Skeleton:MASTER" </node_path>
- <int name="tracks/10/interp"> 1 </int>
- <real_array name="tracks/10/keys" len="24"> 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/11/type"> "transform" </string>
- <node_path name="tracks/11/path"> "Armature/Skeleton:HEAD" </node_path>
- <int name="tracks/11/interp"> 1 </int>
- <real_array name="tracks/11/keys" len="216"> 0, 1, -5.68434e-14, 0, 0.850875, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -5.68434e-14, 0, 0.888268, 0, 0, 0, 1, 1, 1, 1, 0.1, 1, -5.68434e-14, 0, 0.982704, 0, 0, 7.10543e-15, 1, 1, 1, 1, 0.15, 1, -5.68434e-14, 0, 1.10101, 0, 0, 0, 1, 1, 1, 1, 0.2, 1, -5.68434e-14, 0, 1.19526, 0, 0, -7.10543e-15, 1, 1, 1, 1, 0.25, 1, -5.68434e-14, 0, 1.23253, 0, 0, 0, 1, 1, 1, 1, 0.3, 1, -5.68434e-14, 0, 1.20497, 0, 0, 7.10543e-15, 1, 1, 1, 1, 0.35, 1, -5.68434e-14, 0, 1.13278, 0, 0, -7.10543e-15, 1, 1, 1, 1, 0.45, 1, -5.68434e-14, 0, 0.935015, 0, 0, 0, 1, 1, 1, 1, 0.5, 1, -5.68434e-14, 0, 0.868188, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, -5.68434e-14, 0, 0.85559, 0, 0, 0, 1, 1, 1, 1, 0.6, 1, -5.68434e-14, 0, 0.901897, 0, 0, 0, 1, 1, 1, 1, 0.75, 1, -5.68434e-14, 0, 1.20896, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, -5.68434e-14, 0, 1.22782, 0, 0, 7.10543e-15, 1, 1, 1, 1, 0.85, 1, -5.68434e-14, 0, 1.18155, 0, 0, 0, 1, 1, 1, 1, 1, 1, -5.68434e-14, 0, 0.874524, 0, 0, 0, 1, 1, 1, 1, 1.05, 1, -5.68434e-14, 0, 0.850875, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -5.68434e-14, 0, 0.850875, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/12/type"> "transform" </string>
- <node_path name="tracks/12/path"> "Armature/Skeleton:r-LEGCONTROL" </node_path>
- <int name="tracks/12/interp"> 1 </int>
- <real_array name="tracks/12/keys" len="180"> 0, 1, -0.142338, -0.946415, 0.217759, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -0.142333, -0.853172, 0.14976, 0, 0, 0, 1, 1, 1, 1, 0.1, 1, -0.142326, -0.626394, 0.0493819, 0, 0, 0, 1, 1, 1, 1, 0.25, 1, -0.142324, 0.323052, 0.113333, 0, 0, 0, 1, 1, 1, 1, 0.45, 1, -0.139402, 1.42157, 0.666575, 0, 0, 0, 1, 1, 1, 1, 0.5, 1, -0.136793, 1.55206, 0.805069, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, -0.131841, 1.57295, 0.911952, 0, 0, 0, 1, 1, 1, 1, 0.6, 1, -0.113377, 1.47151, 1.00452, 0, 0, 0, 1, 1, 1, 1, 0.65, 1, -0.077946, 1.23249, 1.08549, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, -0.0017584, 0.265596, 1.17195, 0, 0, 0, 1, 1, 1, 1, 0.85, 1, -0.0190262, -0.03908, 1.05516, 0, 0, 0, 1, 1, 1, 1, 0.95, 1, -0.100589, -0.692012, 0.50379, 0, 0, 0, 1, 1, 1, 1, 1, 1, -0.133542, -0.895383, 0.278588, 0, 0, 0, 1, 1, 1, 1, 1.05, 1, -0.142338, -0.946415, 0.217759, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.142338, -0.946415, 0.217759, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/13/type"> "transform" </string>
- <node_path name="tracks/13/path"> "Armature/Skeleton:l-LEGCONTROL" </node_path>
- <int name="tracks/13/interp"> 1 </int>
- <real_array name="tracks/13/keys" len="192"> 0, 1, 0.133965, 1.58294, 0.896163, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 0.120869, 1.49689, 0.924311, 0, 0, 0, 1, 1, 1, 1, 0.1, 1, 0.0877482, 1.26696, 0.995435, 0, 0, 0, 1, 1, 1, 1, 0.25, 1, 0, 0.313476, 1.18387, 0, 0, 0, 1, 1, 1, 1, 0.3, 1, 0.0102771, 0.0502403, 1.13241, 0, 0, 0, 1, 1, 1, 1, 0.4, 1, 0.0744684, -0.535892, 0.782828, 0, 0, 0, 1, 1, 1, 1, 0.45, 1, 0.110957, -0.769809, 0.54983, 0, 0, 0, 1, 1, 1, 1, 0.5, 1, 0.13588, -0.912113, 0.342608, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, 0.142337, -0.934969, 0.197995, 0, 0, 0, 1, 1, 1, 1, 0.6, 1, 0.142331, -0.819832, 0.0904105, 0, 0, 0, 1, 1, 1, 1, 0.65, 1, 0.142325, -0.584709, 0.0345853, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, 0.14222, 0.375652, 0.134472, 0, 0, 0, 1, 1, 1, 1, 0.95, 1, 0.136416, 1.34572, 0.707882, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0.134481, 1.53602, 0.857536, 0, 0, 0, 1, 1, 1, 1, 1.05, 1, 0.133965, 1.58294, 0.896163, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.133965, 1.58294, 0.896163, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/14/type"> "transform" </string>
- <node_path name="tracks/14/path"> "Armature/Skeleton:r-LEGORIENT" </node_path>
- <int name="tracks/14/interp"> 1 </int>
- <real_array name="tracks/14/keys" len="192"> 0, 1, 0.100474, 0.669825, -0.778672, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 0.098364, 0.655731, -0.762274, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 0.1, 1, 0.092555, 0.616937, -0.717148, 4.1297e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.15, 1, 0.0832335, 0.55472, -0.644792, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.4, 1, 0.0154476, 0.102931, -0.119635, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 0.45, 1, 0.00660282, 0.0440027, -0.051146, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.5, 1, 0.00131494, 0.00876498, -0.0101888, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, 0.000308841, 0.00205886, -0.00239307, 7.10993e-08, 6.08666e-15, -4.32757e-22, 1, 1, 1, 1, 0.6, 1, 0.00340915, 0.0227199, -0.0264083, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.65, 1, 0.0108188, 0.0720865, -0.0837842, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.7, 1, 0.0221942, 0.14786, -0.171845, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 0.9, 1, 0.0824287, 0.549322, -0.638501, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.95, 1, 0.0927294, 0.618084, -0.718475, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 1, 1, 0.0989292, 0.659501, -0.766658, 0, 0, 0, 1, 1, 1, 1, 1.05, 1, 0.100474, 0.669825, -0.778672, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.100474, 0.669825, -0.778672, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/15/type"> "transform" </string>
- <node_path name="tracks/15/path"> "Armature/Skeleton:l-LEGORIENT" </node_path>
- <int name="tracks/15/interp"> 1 </int>
- <real_array name="tracks/15/keys" len="192"> 0, 1, 2.98023e-08, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -0.00210956, 0.0140947, -0.0163979, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 0.1, 1, -0.00791863, 0.0528884, -0.0615235, 4.1297e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.15, 1, -0.0172402, 0.115105, -0.13388, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.4, 1, -0.085026, 0.566894, -0.659037, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 0.45, 1, -0.0938708, 0.625823, -0.727526, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.5, 1, -0.0991587, 0.66106, -0.768483, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, -0.100165, 0.667766, -0.776279, 7.10993e-08, 6.08666e-15, -4.32757e-22, 1, 1, 1, 1, 0.6, 1, -0.0970645, 0.647105, -0.752263, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.65, 1, -0.0896548, 0.597739, -0.694888, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.7, 1, -0.0782794, 0.521965, -0.606827, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 0.9, 1, -0.0180449, 0.120504, -0.14017, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.95, 1, -0.00774428, 0.0517416, -0.0601966, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 1, 1, -0.00154439, 0.0103241, -0.0120134, 0, 0, 0, 1, 1, 1, 1, 1.05, 1, 2.98023e-08, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 2.98023e-08, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/16/type"> "transform" </string>
- <node_path name="tracks/16/path"> "Armature/Skeleton:r-ARMCONTROL" </node_path>
- <int name="tracks/16/interp"> 1 </int>
- <real_array name="tracks/16/keys" len="180"> 0, 1, -0.868295, -0.434147, -0.728793, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -0.894115, -0.429589, -0.685758, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, -0.965105, -0.417039, -0.56775, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.15, 1, -1.07881, -0.396902, -0.379345, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, -1.9017, -0.250463, 0.973224, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, -2.00893, -0.231348, 1.14912, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.5, 1, -2.07309, -0.219917, 1.25447, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, -2.08428, -0.222594, 1.27283, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.6, 1, -2.0356, -0.276793, 1.19246, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.65, 1, -1.92036, -0.39421, 1.00266, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.75, 1, -1.5939, -0.636021, 0.464508, 0, 0, 0, 1, 1, 1, 1, 0.95, 1, -0.989962, -0.50147, -0.527541, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1, 1, -0.8923, -0.448337, -0.688738, 0, 0, 0, 1, 1, 1, 1, 1.05, 1, -0.868295, -0.434147, -0.728793, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.868295, -0.434147, -0.728793, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/17/type"> "transform" </string>
- <node_path name="tracks/17/path"> "Armature/Skeleton:l-ARMCONTROL" </node_path>
- <int name="tracks/17/interp"> 1 </int>
- <real_array name="tracks/17/keys" len="180"> 0, 1, 2.08906, -0.217074, 1.28073, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 2.04863, -0.260861, 1.21323, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, 1.93875, -0.371377, 1.03141, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.25, 1, 1.47813, -0.663608, 0.273554, 0, 0, 0, 1, 1, 1, 1, 0.45, 1, 0.953814, -0.514624, -0.588262, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.5, 1, 0.884829, -0.464922, -0.701557, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, 0.872045, -0.428974, -0.722627, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.6, 1, 0.909668, -0.39768, -0.660821, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.65, 1, 0.999508, -0.365756, -0.513451, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.7, 1, 1.13734, -0.334072, -0.287612, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.9, 1, 1.86856, -0.237138, 0.914287, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.95, 1, 1.99427, -0.225258, 1.12276, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1, 1, 2.07012, -0.218627, 1.24908, 0, 0, 0, 1, 1, 1, 1, 1.05, 1, 2.08906, -0.217074, 1.28073, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 2.08906, -0.217074, 1.28073, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/18/type"> "transform" </string>
- <node_path name="tracks/18/path"> "Armature/Skeleton:r-ARMORIENT" </node_path>
- <int name="tracks/18/interp"> 1 </int>
- <real_array name="tracks/18/keys" len="192"> 0, 1, 0.405204, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 0.429983, 0.0015192, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, 0.498118, 0.0057025, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.15, 1, 0.607264, 0.0124156, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, 1.39747, 0.061233, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, 1.50046, 0.0676029, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.5, 1, 1.56207, 0.0714109, 0, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, 1.5738, 0.0721354, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.6, 1, 1.53767, 0.0699027, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.65, 1, 1.45139, 0.0645664, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.7, 1, 1.31902, 0.0563741, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.9, 1, 0.616836, 0.0129952, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.95, 1, 0.496168, 0.00557709, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1, 1, 0.423375, 0.00111222, 0, 0, 0, 0, 1, 1, 1, 1, 1.05, 1, 0.405204, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.405204, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/19/type"> "transform" </string>
- <node_path name="tracks/19/path"> "Armature/Skeleton:l-ARMORIENT" </node_path>
- <int name="tracks/19/interp"> 1 </int>
- <real_array name="tracks/19/keys" len="192"> 0, 1, -1.5774, 0.0723579, 0, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -1.55262, 0.0708387, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, -1.48449, 0.0666554, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.15, 1, -1.37534, 0.0599422, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, -0.585136, 0.0111248, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, -0.482148, 0.00475502, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.5, 1, -0.420538, 0.000946999, 0, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, -0.408805, 0.000222445, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.6, 1, -0.444934, 0.00245523, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.65, 1, -0.531212, 0.00779152, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.7, 1, -0.663587, 0.0159838, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.9, 1, -1.36577, 0.0593629, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.95, 1, -1.48644, 0.0667808, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1, 1, -1.55923, 0.0712457, 0, 0, 0, 0, 1, 1, 1, 1, 1.05, 1, -1.5774, 0.0723579, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -1.5774, 0.0723579, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/20/type"> "transform" </string>
- <node_path name="tracks/20/path"> "Armature/Skeleton:hip" </node_path>
- <int name="tracks/20/interp"> 1 </int>
- <real_array name="tracks/20/keys" len="276"> 0, 1, 0.0502379, 0.036174, 0.108012, 7.74552e-15, -1.97402e-08, 0.0871557, 0.996195, 1, 1, 1, 0.05, 1, 0.0469382, 0.0509099, 0.094259, -3.35906e-14, -1.89171e-08, 0.0835209, 0.996506, 1, 1, 1, 0.1, 1, 0.0379226, 0.088175, 0.0594788, -4.57539e-14, -1.66467e-08, 0.0734954, 0.997296, 1, 1, 1, 0.15, 1, 0.0249111, 0.134917, 0.0158529, -3.14989e-14, -1.29934e-08, 0.0573644, 0.998353, 1, 1, 1, 0.2, 1, 0.0112907, 0.17217, -0.0189178, -1.3373e-14, -8.15547e-09, 0.0360035, 0.999352, 1, 1, 1, 0.25, 1, 2.27588e-08, 0.186899, -0.0326645, -1.50375e-14, -2.49281e-09, 0.0110021, 0.99994, 1, 1, 1, 0.3, 1, -0.0104418, 0.176016, -0.0225072, -7.05369e-14, 3.45387e-09, -0.0152525, 0.999884, 1, 1, 1, 0.35, 1, -0.0222285, 0.147506, 0.00410175, -3.23609e-14, 9.01354e-09, -0.039798, 0.999208, 1, 1, 1, 0.4, 1, -0.0338161, 0.108041, 0.0409362, -3.84007e-14, 1.36964e-08, -0.0604725, 0.99817, 1, 1, 1, 0.45, 1, -0.043192, 0.0694027, 0.0769985, -3.85801e-14, 1.71613e-08, -0.0757699, 0.997125, 1, 1, 1, 0.5, 1, -0.0488776, 0.0430113, 0.10163, -7.13117e-15, 1.92273e-08, -0.084891, 0.99639, 1, 1, 1, 0.55, 1, -0.049846, 0.0380361, 0.106274, -6.66418e-14, 1.96198e-08, -0.0866238, 0.996241, 1, 1, 1, 0.6, 1, -0.0458462, 0.0563236, 0.0892055, -1.43694e-14, 1.84095e-08, -0.0812805, 0.996691, 1, 1, 1, 0.65, 1, -0.0363638, 0.0959547, 0.0522163, -5.40282e-14, 1.5511e-08, -0.0684838, 0.997652, 1, 1, 1, 0.7, 1, -0.0231681, 0.1427, 0.0085876, -3.25683e-14, 1.10473e-08, -0.0487772, 0.99881, 1, 1, 1, 0.75, 1, -0.00951665, 0.177588, -0.0239747, 1.83932e-15, 5.34013e-09, -0.0235807, 0.999722, 1, 1, 1, 0.8, 1, 0.00190332, 0.185037, -0.0309267, -4.07805e-14, -1.06814e-09, 0.00471147, 0.999989, 1, 1, 1, 0.85, 1, 0.0140465, 0.166752, -0.0138602, -8.20187e-14, -7.29738e-09, 0.0322142, 0.999481, 1, 1, 1, 0.9, 1, 0.0278208, 0.127127, 0.0231235, -3.37482e-14, -1.26773e-08, 0.0559684, 0.998433, 1, 1, 1, 0.95, 1, 0.0402532, 0.080384, 0.0667505, -4.05783e-14, -1.67149e-08, 0.0737966, 0.997273, 1, 1, 1, 1, 1, 0.0482781, 0.0454891, 0.0993183, 1.00279e-15, -1.91378e-08, 0.0844954, 0.996424, 1, 1, 1, 1.05, 1, 0.0502379, 0.036174, 0.108012, 7.74552e-15, -1.97402e-08, 0.0871557, 0.996195, 1, 1, 1, 1.25, 1, 0.0502379, 0.036174, 0.108012, 7.74552e-15, -1.97402e-08, 0.0871557, 0.996195, 1, 1, 1 </real_array>
- <string name="tracks/21/type"> "transform" </string>
- <node_path name="tracks/21/path"> "Armature/Skeleton:waist" </node_path>
- <int name="tracks/21/interp"> 1 </int>
- <real_array name="tracks/21/keys" len="192"> 0, 1, 4.1909e-09, -2.55596e-10, -3.57628e-07, 0.0550011, -0.00481196, -0.0870228, 0.994675, 1, 1, 1, 0.05, 1, 3.53838e-09, 6.53649e-11, -5.96046e-08, 0.0550183, -0.0046113, -0.0833935, 0.994986, 1, 1, 1, 0.1, 1, -5.60775e-10, -7.51698e-09, -2.98023e-08, 0.0550619, -0.00405785, -0.0733833, 0.995774, 1, 1, 1, 0.15, 1, -2.23866e-09, -1.11867e-08, -1.49012e-07, 0.0551203, -0.00316731, -0.0572769, 0.996831, 1, 1, 1, 0.4, 1, -2.04997e-09, -2.75862e-09, 1.78814e-07, 0.0551102, 0.00333869, 0.0603803, 0.996647, 1, 1, 1, 0.45, 1, 2.0486e-09, 4.35754e-10, 5.96046e-08, 0.0550525, 0.00418331, 0.0756543, 0.995605, 1, 1, 1, 0.5, 1, -5.1223e-09, 2.12108e-09, 1.19209e-07, 0.0550119, 0.00468692, 0.0847616, 0.994871, 1, 1, 1, 0.55, 1, 9.31448e-11, -6.0701e-10, 0, 0.0550037, 0.00478259, 0.0864917, 0.994722, 1, 1, 1, 0.6, 1, -8.38328e-10, -2.70165e-09, 0, 0.0550285, 0.00448757, 0.0811565, 0.995171, 1, 1, 1, 0.65, 1, -5.5956e-10, 2.044e-09, 2.98023e-08, 0.0550816, 0.00378102, 0.0683793, 0.996131, 1, 1, 1, 0.7, 1, -1.88318e-10, -1.00538e-08, -1.49012e-07, 0.0551455, 0.00269294, 0.0487028, 0.997286, 1, 1, 1, 0.9, 1, -2.42557e-09, -9.9462e-09, 1.19209e-07, 0.0551247, -0.00309027, -0.055883, 0.99691, 1, 1, 1, 0.95, 1, 2.79174e-09, -8.13951e-09, 0, 0.0550607, -0.00407449, -0.073684, 0.995752, 1, 1, 1, 1, 1, -4.66262e-10, 1.71346e-09, 0, 0.0550138, -0.0046651, -0.0843665, 0.994904, 1, 1, 1, 1.05, 1, 4.1909e-09, -2.55596e-10, -3.57628e-07, 0.0550011, -0.00481196, -0.0870228, 0.994675, 1, 1, 1, 1.25, 1, 4.1909e-09, -2.55596e-10, -3.57628e-07, 0.0550011, -0.00481196, -0.0870228, 0.994675, 1, 1, 1 </real_array>
- <string name="tracks/22/type"> "transform" </string>
- <node_path name="tracks/22/path"> "Armature/Skeleton:chest" </node_path>
- <int name="tracks/22/interp"> 1 </int>
- <real_array name="tracks/22/keys" len="192"> 0, 1, 4.20218e-09, -1.49012e-08, 0, 0.0550026, -0.0108562, -0.086477, 0.994675, 1, 1, 1, 0.05, 1, 6.60681e-10, -7.45058e-09, -5.96046e-08, 0.0550197, -0.0104035, -0.0828704, 0.994986, 1, 1, 1, 0.1, 1, 1.42138e-09, -7.45058e-09, 1.19209e-07, 0.0550633, -0.00915483, -0.072923, 0.995774, 1, 1, 1, 0.15, 1, -1.4402e-10, -1.86265e-08, -5.96046e-08, 0.0551217, -0.00714571, -0.0569177, 0.99683, 1, 1, 1, 0.4, 1, -2.54046e-09, 7.45058e-09, -1.78814e-07, 0.0551116, 0.00753235, 0.0600015, 0.996647, 1, 1, 1, 0.45, 1, -2.31643e-09, 1.86265e-08, -1.78814e-07, 0.0550539, 0.00943788, 0.0751797, 0.995604, 1, 1, 1, 0.5, 1, -3.16026e-09, 1.49012e-08, 5.96046e-08, 0.0550134, 0.0105741, 0.0842299, 0.99487, 1, 1, 1, 0.55, 1, -4.35034e-09, 2.23517e-08, -1.78814e-07, 0.0550051, 0.0107899, 0.0859492, 0.994722, 1, 1, 1, 0.6, 1, -1.53961e-09, -7.45058e-09, 5.96046e-08, 0.05503, 0.0101243, 0.0806475, 0.995171, 1, 1, 1, 0.65, 1, -1.47879e-09, -1.86265e-08, -5.96046e-08, 0.055083, 0.00853027, 0.0679504, 0.996131, 1, 1, 1, 0.7, 1, -2.07954e-09, 2.6077e-08, -2.38419e-07, 0.0551469, 0.00607548, 0.0483973, 0.997286, 1, 1, 1, 0.9, 1, -1.29246e-09, -2.6077e-08, 5.96046e-08, 0.0551261, -0.00697189, -0.0555325, 0.99691, 1, 1, 1, 0.95, 1, 2.48766e-09, -7.45058e-09, 5.96046e-08, 0.0550621, -0.00919238, -0.0732219, 0.995752, 1, 1, 1, 1, 1, -1.94411e-09, -7.45058e-09, -1.19209e-07, 0.0550152, -0.0105248, -0.0838373, 0.994904, 1, 1, 1, 1.05, 1, 4.20218e-09, -1.49012e-08, 0, 0.0550026, -0.0108562, -0.086477, 0.994675, 1, 1, 1, 1.25, 1, 4.20218e-09, -1.49012e-08, 0, 0.0550026, -0.0108562, -0.086477, 0.994675, 1, 1, 1 </real_array>
- <string name="tracks/23/type"> "transform" </string>
- <node_path name="tracks/23/path"> "Armature/Skeleton:neck" </node_path>
- <int name="tracks/23/interp"> 1 </int>
- <real_array name="tracks/23/keys" len="24"> 0, 1, 1.58195e-10, -1.19209e-07, -8.34465e-07, -1.49012e-08, 2.17021e-10, 8.15234e-10, 1, 1, 1, 1, 1.25, 1, 1.58195e-10, -1.19209e-07, -8.34465e-07, -1.49012e-08, 2.17021e-10, 8.15234e-10, 1, 1, 1, 1 </real_array>
- <string name="tracks/24/type"> "transform" </string>
- <node_path name="tracks/24/path"> "Armature/Skeleton:headtracker" </node_path>
- <int name="tracks/24/interp"> 1 </int>
- <real_array name="tracks/24/keys" len="144"> 0, 1, 8.86136e-10, -2.38419e-07, -4.91273e-08, 0.0549542, -0.0952446, 0.00487296, 0.993924, 1, 1, 1, 0.05, 1, 2.18506e-09, -1.78814e-07, -5.65778e-08, 0.0504772, -0.0912067, 0.0042631, 0.994543, 1, 1, 1, 0.1, 1, 5.53928e-10, -4.17233e-07, -3.67872e-08, 0.0390059, -0.0800384, 0.00284171, 0.996024, 1, 1, 1, 0.45, 1, -5.1797e-09, -8.04663e-07, -5.82077e-08, 0.0448447, 0.08285, -0.00340957, 0.995547, 1, 1, 1, 0.5, 1, 3.73723e-09, 3.57628e-07, -5.28526e-08, 0.052893, 0.0927872, -0.00455309, 0.99427, 1, 1, 1, 0.55, 1, 3.81474e-09, -2.98023e-08, -4.30737e-08, 0.0543919, 0.0946615, -0.00479041, 0.994011, 1, 1, 1, 0.6, 1, 5.97727e-09, -1.01328e-06, -7.35745e-08, 0.0488359, 0.0887913, -0.00401032, 0.994844, 1, 1, 1, 0.65, 1, -3.89822e-10, -6.25849e-07, -7.96281e-08, 0.0366099, 0.0746935, -0.00247956, 0.996531, 1, 1, 1, 0.95, 1, -4.46247e-09, 1.19209e-07, -6.96164e-08, 0.0414353, -0.080551, 0.00304791, 0.995884, 1, 1, 1, 1, 1, 2.64143e-09, -5.96046e-07, -7.72998e-08, 0.052136, -0.0923283, 0.0044599, 0.994353, 1, 1, 1, 1.05, 1, 8.86136e-10, -2.38419e-07, -4.91273e-08, 0.0549542, -0.0952446, 0.00487296, 0.993924, 1, 1, 1, 1.25, 1, 8.86136e-10, -2.38419e-07, -4.91273e-08, 0.0549542, -0.0952446, 0.00487296, 0.993924, 1, 1, 1 </real_array>
- <string name="tracks/25/type"> "transform" </string>
- <node_path name="tracks/25/path"> "Armature/Skeleton:head" </node_path>
- <int name="tracks/25/interp"> 1 </int>
- <real_array name="tracks/25/keys" len="24"> 0, 1, -3.08853e-09, 1.69966e-08, 3.98955e-07, 4.70848e-20, -1.3217e-10, -5.67425e-10, 1, 1, 1, 1, 1.25, 1, -3.08853e-09, 1.69966e-08, 3.98955e-07, 4.70848e-20, -1.3217e-10, -5.67425e-10, 1, 1, 1, 1 </real_array>
- <string name="tracks/26/type"> "transform" </string>
- <node_path name="tracks/26/path"> "Armature/Skeleton:vent" </node_path>
- <int name="tracks/26/interp"> 1 </int>
- <real_array name="tracks/26/keys" len="24"> 0, 1, 5.17831e-08, 0.00292331, 0.204329, 3.25963e-09, -2.17324e-11, 3.00563e-10, 1, 1, 1, 1, 1.25, 1, 5.17831e-08, 0.00292331, 0.204329, 3.25963e-09, -2.17324e-11, 3.00563e-10, 1, 1, 1, 1 </real_array>
-
- </resource>
- <resource type="Animation" path="local://13">
- <string name="resource/name"> "shooting_standing" </string>
- <real name="length"> 0.416667 </real>
- <bool name="loop"> False </bool>
- <real name="step"> 0.1 </real>
- <string name="tracks/0/type"> "transform" </string>
- <node_path name="tracks/0/path"> "Armature/Skeleton:r-arm" </node_path>
- <int name="tracks/0/interp"> 1 </int>
- <real_array name="tracks/0/keys" len="132"> 0, 1, 5.96046e-07, -1.19209e-07, 4.47035e-07, -0.206314, 0.709894, -0.150643, 0.656348, 1, 1, 1, 0.05, 1, 1.07288e-06, -4.76837e-07, 8.34465e-07, -0.199825, 0.723236, -0.14911, 0.644023, 1, 1, 1, 0.1, 1, 4.47035e-07, -1.19209e-07, 3.27826e-07, -0.186028, 0.74616, -0.147051, 0.622106, 1, 1, 1, 0.15, 1, 4.47035e-07, -1.19209e-07, 1.49012e-07, -0.168011, 0.761016, -0.149525, 0.608497, 1, 1, 1, 0.2, 1, 2.38419e-07, 1.19209e-07, -1.19209e-07, -0.141127, 0.777642, -0.158168, 0.591895, 1, 1, 1, 0.25, 1, 7.15256e-07, -2.38419e-07, 2.68221e-07, -0.129783, 0.779527, -0.165304, 0.590059, 1, 1, 1, 0.3, 1, 6.25849e-07, -1.19209e-07, 2.08616e-07, -0.152097, 0.757922, -0.164122, 0.612768, 1, 1, 1, 0.35, 1, 8.9407e-07, -4.76837e-07, 8.34465e-07, -0.183836, 0.730436, -0.157254, 0.638701, 1, 1, 1, 0.4, 1, 7.45058e-07, -3.57628e-07, 5.66244e-07, -0.202964, 0.713054, -0.151716, 0.653714, 1, 1, 1, 0.45, 1, 5.96046e-07, -1.19209e-07, 4.47035e-07, -0.206314, 0.709894, -0.150643, 0.656348, 1, 1, 1, 1.25, 1, 5.96046e-07, -1.19209e-07, 4.47035e-07, -0.206314, 0.709894, -0.150643, 0.656348, 1, 1, 1 </real_array>
- <string name="tracks/1/type"> "transform" </string>
- <node_path name="tracks/1/path"> "Armature/Skeleton:r-forearm" </node_path>
- <int name="tracks/1/interp"> 1 </int>
- <real_array name="tracks/1/keys" len="120"> 0, 1, 0, -4.76837e-07, -7.7486e-07, 0.0490264, -0.364254, 0.0100564, 0.929954, 1, 1, 1, 0.05, 1, 1.19209e-07, -4.47035e-07, -4.76837e-07, 0.0346734, -0.325178, 0.00768963, 0.944986, 1, 1, 1, 0.1, 1, 1.19209e-07, -5.06639e-07, -3.57628e-07, 0.00822793, -0.255634, 0.00344931, 0.966732, 1, 1, 1, 0.15, 1, 2.98023e-08, -7.15256e-07, -5.96046e-07, -0.00893206, -0.219161, 0.00118009, 0.975647, 1, 1, 1, 0.2, 1, 1.49012e-07, -4.47035e-07, -5.96046e-07, -0.0220165, -0.204408, 0.000203021, 0.978638, 1, 1, 1, 0.25, 1, 4.17233e-07, -4.76837e-07, -5.36442e-07, -0.0204464, -0.223283, 0.00158917, 0.974538, 1, 1, 1, 0.35, 1, 1.19209e-07, -6.85453e-07, -2.98023e-07, 0.0295549, -0.331584, 0.00842644, 0.942925, 1, 1, 1, 0.4, 1, 0, -6.55651e-07, -6.55651e-07, 0.0460614, -0.359518, 0.00983853, 0.931949, 1, 1, 1, 0.45, 1, 0, -4.76837e-07, -7.7486e-07, 0.0490264, -0.364254, 0.0100564, 0.929954, 1, 1, 1, 1.25, 1, 0, -4.76837e-07, -7.7486e-07, 0.0490264, -0.364254, 0.0100564, 0.929954, 1, 1, 1 </real_array>
- <string name="tracks/2/type"> "transform" </string>
- <node_path name="tracks/2/path"> "Armature/Skeleton:l-arm" </node_path>
- <int name="tracks/2/interp"> 1 </int>
- <real_array name="tracks/2/keys" len="132"> 0, 1, -4.17233e-07, -3.57628e-07, 4.47035e-07, -0.474516, -0.584521, 0.0340579, 0.657274, 1, 1, 1, 0.05, 1, -7.45058e-07, -3.57628e-07, 5.36442e-07, -0.46761, -0.58693, 0.0339523, 0.660076, 1, 1, 1, 0.1, 1, -4.76837e-07, -2.38419e-07, 2.98023e-07, -0.452786, -0.591715, 0.0339493, 0.666112, 1, 1, 1, 0.15, 1, -6.55651e-07, -3.57628e-07, 2.98023e-07, -0.443727, -0.588057, 0.0337848, 0.675392, 1, 1, 1, 0.2, 1, 2.98023e-08, 1.19209e-07, -3.27826e-07, -0.450408, -0.563251, 0.0324613, 0.691973, 1, 1, 1, 0.25, 1, -5.96046e-07, -3.57628e-07, 2.98023e-07, -0.461281, -0.543778, 0.0314456, 0.700383, 1, 1, 1, 0.3, 1, -4.17233e-07, 0, 1.78814e-07, -0.469244, -0.550688, 0.0318109, 0.689595, 1, 1, 1, 0.35, 1, -7.7486e-07, -2.38419e-07, 4.76837e-07, -0.473462, -0.569016, 0.0329517, 0.671542, 1, 1, 1, 0.4, 1, -6.25849e-07, -3.57628e-07, 5.96046e-07, -0.474439, -0.5821, 0.0338759, 0.659485, 1, 1, 1, 0.45, 1, -4.17233e-07, -3.57628e-07, 4.47035e-07, -0.474516, -0.584521, 0.0340579, 0.657274, 1, 1, 1, 1.25, 1, -4.17233e-07, -3.57628e-07, 4.47035e-07, -0.474516, -0.584521, 0.0340579, 0.657274, 1, 1, 1 </real_array>
- <string name="tracks/3/type"> "transform" </string>
- <node_path name="tracks/3/path"> "Armature/Skeleton:l-forearm" </node_path>
- <int name="tracks/3/interp"> 1 </int>
- <real_array name="tracks/3/keys" len="96"> 0, 1, 1.78814e-07, 2.98023e-08, -3.57628e-07, -0.156054, -0.257929, 9.29801e-05, 0.953478, 1.3, 1.3, 1.3, 0.05, 1, -8.9407e-08, -9.23872e-07, -2.98023e-07, -0.156186, -0.25785, 0.000491834, 0.953477, 1.3, 1.3, 1.3, 0.1, 1, 0, -5.06639e-07, -2.98023e-07, -0.156442, -0.257682, 0.00128265, 0.95348, 1.3, 1.3, 1.3, 0.15, 1, -2.08616e-07, -5.36442e-07, -5.96046e-08, -0.156528, -0.257623, 0.00155313, 0.953481, 1.3, 1.3, 1.3, 0.25, 1, 2.98023e-08, -5.36442e-07, -3.57628e-07, -0.155874, -0.258131, -0.000583909, 0.953452, 1.3, 1.3, 1.3, 0.35, 1, 2.98023e-08, -4.76837e-07, -3.57628e-07, -0.15592, -0.258051, -0.000371468, 0.953467, 1.3, 1.3, 1.3, 0.4, 1, 1.49012e-07, -2.68221e-07, -2.98023e-07, -0.156032, -0.257949, 1.56283e-05, 0.953476, 1.3, 1.3, 1.3, 1.25, 1, 1.78814e-07, 2.98023e-08, -3.57628e-07, -0.156054, -0.257929, 9.29801e-05, 0.953478, 1.3, 1.3, 1.3 </real_array>
- <string name="tracks/4/type"> "transform" </string>
- <node_path name="tracks/4/path"> "Armature/Skeleton:r-thigh" </node_path>
- <int name="tracks/4/interp"> 1 </int>
- <real_array name="tracks/4/keys" len="120"> 0, 1, 5.96046e-08, 2.23517e-08, -1.3411e-07, 0.301601, -0.0701581, -0.00864293, 0.95081, 1, 1, 1, 0.05, 1, 5.96046e-08, 2.98023e-08, -1.04308e-07, 0.248345, -0.0620849, -0.00736271, 0.966652, 1, 1, 1, 0.1, 1, 8.9407e-08, 6.70552e-08, -1.04308e-07, 0.175365, -0.0511626, -0.00552639, 0.983158, 1, 1, 1, 0.15, 1, 8.9407e-08, 4.47035e-08, -1.04308e-07, 0.153891, -0.0497144, -0.00660778, 0.986814, 1, 1, 1, 0.2, 1, 5.96046e-08, -2.98023e-08, -1.49012e-08, 0.151238, -0.0561188, -0.0117034, 0.986834, 1, 1, 1, 0.25, 1, 2.98023e-08, -1.49012e-08, -1.04308e-07, 0.168743, -0.0655087, -0.0152581, 0.983362, 1, 1, 1, 0.35, 1, 2.98023e-08, 2.23517e-08, -1.63913e-07, 0.26593, -0.072486, -0.0117415, 0.961192, 1, 1, 1, 0.4, 1, 5.96046e-08, 7.45058e-09, -1.78814e-07, 0.296131, -0.070636, -0.00916634, 0.952488, 1, 1, 1, 0.45, 1, 5.96046e-08, 2.23517e-08, -1.3411e-07, 0.301601, -0.0701581, -0.00864293, 0.95081, 1, 1, 1, 1.25, 1, 5.96046e-08, 2.23517e-08, -1.3411e-07, 0.301601, -0.0701581, -0.00864293, 0.95081, 1, 1, 1 </real_array>
- <string name="tracks/5/type"> "transform" </string>
- <node_path name="tracks/5/path"> "Armature/Skeleton:r-leg" </node_path>
- <int name="tracks/5/interp"> 1 </int>
- <real_array name="tracks/5/keys" len="120"> 0, 1, -4.31901e-08, -7.45058e-08, 7.7486e-07, -0.33852, 0.053398, -0.0152903, 0.939319, 1, 1, 1, 0.05, 1, 5.6345e-08, -2.23517e-08, 6.55651e-07, -0.403989, 0.0628472, -0.0146608, 0.912484, 1, 1, 1, 0.1, 1, 5.02914e-08, -1.49012e-08, 5.36442e-07, -0.486228, 0.0751824, -0.0137902, 0.870483, 1, 1, 1, 0.15, 1, 1.11642e-07, 5.96046e-08, 5.96046e-07, -0.506485, 0.0840018, -0.0142775, 0.858028, 1, 1, 1, 0.2, 1, 1.23633e-07, 8.19564e-08, 5.36442e-07, -0.500531, 0.103313, -0.0168649, 0.859367, 1, 1, 1, 0.25, 1, 9.58098e-08, 1.49012e-08, 6.55651e-07, -0.475505, 0.111896, -0.0189746, 0.872361, 1, 1, 1, 0.35, 1, 7.84639e-08, 9.68575e-08, 5.96046e-07, -0.376662, 0.0699087, -0.0169347, 0.923554, 1, 1, 1, 0.4, 1, -1.16415e-09, -7.45058e-09, 7.15256e-07, -0.344524, 0.0558207, -0.0155573, 0.936987, 1, 1, 1, 0.45, 1, -4.31901e-08, -7.45058e-08, 7.7486e-07, -0.33852, 0.053398, -0.0152903, 0.939319, 1, 1, 1, 1.25, 1, -4.31901e-08, -7.45058e-08, 7.7486e-07, -0.33852, 0.053398, -0.0152903, 0.939319, 1, 1, 1 </real_array>
- <string name="tracks/6/type"> "transform" </string>
- <node_path name="tracks/6/path"> "Armature/Skeleton:r-foot" </node_path>
- <int name="tracks/6/interp"> 1 </int>
- <real_array name="tracks/6/keys" len="108"> 0, 1, 1.19209e-07, 0, 1.82539e-07, -0.218034, -0.0651501, 0.015764, 0.973637, 1, 1, 1, 0.05, 1, 5.21541e-08, 0, -9.31323e-08, -0.206333, -0.0662009, 0.0171463, 0.976089, 1, 1, 1, 0.1, 1, 2.98023e-08, -1.19209e-07, -7.45058e-08, -0.188973, -0.0677374, 0.0191861, 0.979455, 1, 1, 1, 0.15, 1, 0, 0, -4.84288e-08, -0.184958, -0.0680889, 0.0196559, 0.980188, 1, 1, 1, 0.2, 1, 5.96046e-08, 0, -1.19209e-07, -0.189238, -0.0677142, 0.019155, 0.979406, 1, 1, 1, 0.35, 1, 8.19564e-08, 1.19209e-07, 3.72529e-08, -0.213767, -0.0655347, 0.0162687, 0.974548, 1, 1, 1, 0.4, 1, 1.04308e-07, 0, 5.21541e-08, -0.217419, -0.0652056, 0.0158368, 0.973769, 1, 1, 1, 0.45, 1, 1.19209e-07, 0, 1.82539e-07, -0.218034, -0.0651501, 0.015764, 0.973637, 1, 1, 1, 1.25, 1, 1.19209e-07, 0, 1.82539e-07, -0.218034, -0.0651501, 0.015764, 0.973637, 1, 1, 1 </real_array>
- <string name="tracks/7/type"> "transform" </string>
- <node_path name="tracks/7/path"> "Armature/Skeleton:l-thigh" </node_path>
- <int name="tracks/7/interp"> 1 </int>
- <real_array name="tracks/7/keys" len="132"> 0, 1, -5.96046e-08, -1.2666e-07, 1.04308e-07, -0.633392, 0.109953, 0.00349885, 0.765972, 1, 1, 1, 0.05, 1, 0, -4.47035e-08, 1.3411e-07, -0.628866, 0.106487, 0.00414994, 0.770176, 1, 1, 1, 0.1, 1, -2.98023e-08, 4.47035e-08, 1.49012e-07, -0.619935, 0.101098, 0.00522767, 0.778095, 1, 1, 1, 0.15, 1, -2.98023e-08, 5.96046e-08, 1.49012e-07, -0.616185, 0.108634, 0.00550208, 0.780054, 1, 1, 1, 0.2, 1, 5.96046e-08, 4.47035e-08, 2.5332e-07, -0.613177, 0.141231, 0.00523592, 0.7772, 1, 1, 1, 0.25, 1, 0, 0, 1.49012e-07, -0.612177, 0.164991, 0.00476259, 0.773301, 1, 1, 1, 0.3, 1, 5.96046e-08, -7.45058e-09, 1.3411e-07, -0.619021, 0.155086, 0.00421746, 0.769898, 1, 1, 1, 0.35, 1, 2.98023e-08, 7.45058e-09, 7.45058e-08, -0.627679, 0.130628, 0.00377015, 0.767425, 1, 1, 1, 0.4, 1, -2.98023e-08, -1.3411e-07, 7.45058e-08, -0.632568, 0.11319, 0.0035387, 0.766181, 1, 1, 1, 0.45, 1, -5.96046e-08, -1.2666e-07, 1.04308e-07, -0.633392, 0.109953, 0.00349885, 0.765972, 1, 1, 1, 1.25, 1, -5.96046e-08, -1.2666e-07, 1.04308e-07, -0.633392, 0.109953, 0.00349885, 0.765972, 1, 1, 1 </real_array>
- <string name="tracks/8/type"> "transform" </string>
- <node_path name="tracks/8/path"> "Armature/Skeleton:l-leg" </node_path>
- <int name="tracks/8/interp"> 1 </int>
- <real_array name="tracks/8/keys" len="120"> 0, 1, -4.07454e-08, -1.11759e-07, 0, -0.55604, 0.155102, 0.00378888, 0.816547, 1, 1, 1, 0.05, 1, 7.60192e-08, -8.9407e-08, 1.19209e-07, -0.534898, 0.148998, 0.00358481, 0.831668, 1, 1, 1, 0.1, 1, -1.0326e-07, -1.49012e-08, 2.38419e-07, -0.500235, 0.139173, 0.00323174, 0.854626, 1, 1, 1, 0.15, 1, 6.41448e-08, 4.47035e-08, 1.78814e-07, -0.492131, 0.143377, 0.00332103, 0.858626, 1, 1, 1, 0.25, 1, -6.58911e-08, -8.19564e-08, 1.78814e-07, -0.517192, 0.191548, 0.00473312, 0.834146, 1, 1, 1, 0.3, 1, 3.0268e-08, 1.49012e-08, 1.19209e-07, -0.534465, 0.187415, 0.00465677, 0.824136, 1, 1, 1, 0.35, 1, 3.11993e-08, -5.21541e-08, 2.38419e-07, -0.548296, 0.170437, 0.0042049, 0.818722, 1, 1, 1, 0.4, 1, 2.51457e-08, -9.68575e-08, 1.19209e-07, -0.554953, 0.157536, 0.00385503, 0.81682, 1, 1, 1, 0.45, 1, -4.07454e-08, -1.11759e-07, 0, -0.55604, 0.155102, 0.00378888, 0.816547, 1, 1, 1, 1.25, 1, -4.07454e-08, -1.11759e-07, 0, -0.55604, 0.155102, 0.00378888, 0.816547, 1, 1, 1 </real_array>
- <string name="tracks/9/type"> "transform" </string>
- <node_path name="tracks/9/path"> "Armature/Skeleton:l-foot" </node_path>
- <int name="tracks/9/interp"> 1 </int>
- <real_array name="tracks/9/keys" len="108"> 0, 1, 7.45058e-08, 1.19209e-07, 3.72529e-09, -0.143967, -0.0951747, 0.00523759, 0.984981, 1, 1, 1, 0.05, 1, 7.45058e-09, 2.38419e-07, 3.35276e-08, -0.157581, -0.0952617, 0.00367365, 0.982894, 1, 1, 1, 0.1, 1, -2.23517e-08, 1.19209e-07, -1.11759e-08, -0.17766, -0.0953568, 0.00135921, 0.97946, 1, 1, 1, 0.15, 1, -3.72529e-08, 1.19209e-07, 4.84288e-08, -0.182282, -0.0953731, 0.000825106, 0.97861, 1, 1, 1, 0.2, 1, 1.49012e-08, 1.19209e-07, -5.21541e-08, -0.177354, -0.0953557, 0.00139453, 0.979516, 1, 1, 1, 0.35, 1, 4.47035e-08, 0, 5.96046e-08, -0.148938, -0.0952085, 0.00466699, 0.984241, 1, 1, 1, 0.4, 1, 5.21541e-08, 1.19209e-07, -4.09782e-08, -0.144684, -0.0951797, 0.00515536, 0.984876, 1, 1, 1, 0.45, 1, 7.45058e-08, 1.19209e-07, 3.72529e-09, -0.143967, -0.0951747, 0.00523759, 0.984981, 1, 1, 1, 1.25, 1, 7.45058e-08, 1.19209e-07, 3.72529e-09, -0.143967, -0.0951747, 0.00523759, 0.984981, 1, 1, 1 </real_array>
- <string name="tracks/10/type"> "transform" </string>
- <node_path name="tracks/10/path"> "Armature/Skeleton:MASTER" </node_path>
- <int name="tracks/10/interp"> 1 </int>
- <real_array name="tracks/10/keys" len="24"> 0, 1, 0, 1.36988, -1.03377e-07, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0, 1.36988, -1.03377e-07, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/11/type"> "transform" </string>
- <node_path name="tracks/11/path"> "Armature/Skeleton:HEAD" </node_path>
- <int name="tracks/11/interp"> 1 </int>
- <real_array name="tracks/11/keys" len="108"> 0, 1, 8.64522e-08, 0.572547, -4.76837e-07, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 8.64522e-08, 0.572548, 0.471507, 0, 0, 0, 1, 1, 1, 1, 0.1, 1, 8.64522e-08, 0.572548, 1.12029, 0, 0, 7.10543e-15, 1, 1, 1, 1, 0.15, 1, 8.64522e-08, 0.572548, 1.26782, 0, 0, 0, 1, 1, 1, 1, 0.2, 1, 8.64522e-08, 0.572548, 1.10411, 0, 0, -7.10543e-15, 1, 1, 1, 1, 0.35, 1, 8.64522e-08, 0.572548, 0.166984, 0, 0, -7.10543e-15, 1, 1, 1, 1, 0.4, 1, 8.64522e-08, 0.572547, 0.024261, 0, 0, 0, 1, 1, 1, 1, 0.45, 1, 8.64522e-08, 0.572547, -4.76837e-07, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 8.64522e-08, 0.572547, -4.76837e-07, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/12/type"> "transform" </string>
- <node_path name="tracks/12/path"> "Armature/Skeleton:r-LEGCONTROL" </node_path>
- <int name="tracks/12/interp"> 1 </int>
- <real_array name="tracks/12/keys" len="108"> 0, 1, -0.0366479, -0.0811065, 0.809552, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -0.0366479, -0.0811065, 0.816585, 0, 0, 0, 1, 1, 1, 1, 0.1, 1, -0.0366479, -0.0811065, 0.826986, 0, 0, 0, 1, 1, 1, 1, 0.15, 1, -0.0366479, -0.0811065, 0.829386, 0, 0, 0, 1, 1, 1, 1, 0.2, 1, -0.0366479, -0.0811065, 0.826827, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, -0.0366479, -0.0811065, 0.812119, 0, 0, 0, 1, 1, 1, 1, 0.4, 1, -0.0366479, -0.0811065, 0.809922, 0, 0, 0, 1, 1, 1, 1, 0.45, 1, -0.0366479, -0.0811065, 0.809552, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.0366479, -0.0811065, 0.809552, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/13/type"> "transform" </string>
- <node_path name="tracks/13/path"> "Armature/Skeleton:l-LEGCONTROL" </node_path>
- <int name="tracks/13/interp"> 1 </int>
- <real_array name="tracks/13/keys" len="24"> 0, 1, 0.0611181, -2.75446, 0.0815672, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.0611181, -2.75446, 0.0815672, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/14/type"> "transform" </string>
- <node_path name="tracks/14/path"> "Armature/Skeleton:r-LEGORIENT" </node_path>
- <int name="tracks/14/interp"> 1 </int>
- <real_array name="tracks/14/keys" len="24"> 0, 1, 0.0798243, -0.0543702, -2.95838, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.0798243, -0.0543702, -2.95838, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/15/type"> "transform" </string>
- <node_path name="tracks/15/path"> "Armature/Skeleton:l-LEGORIENT" </node_path>
- <int name="tracks/15/interp"> 1 </int>
- <real_array name="tracks/15/keys" len="24"> 0, 1, 0.183564, 0.0305935, -3.02205, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.183564, 0.0305935, -3.02205, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/16/type"> "transform" </string>
- <node_path name="tracks/16/path"> "Armature/Skeleton:r-ARMCONTROL" </node_path>
- <int name="tracks/16/interp"> 1 </int>
- <real_array name="tracks/16/keys" len="24"> 0, 1, -2.74884, 1.12805, 3.06242, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -2.74884, 1.12805, 3.06242, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/17/type"> "transform" </string>
- <node_path name="tracks/17/path"> "Armature/Skeleton:l-ARMCONTROL" </node_path>
- <int name="tracks/17/interp"> 1 </int>
- <real_array name="tracks/17/keys" len="24"> 0, 1, 1.73339, 0.895247, 5.13844, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 1.73339, 0.895247, 5.13844, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/18/type"> "transform" </string>
- <node_path name="tracks/18/path"> "Armature/Skeleton:r-ARMORIENT" </node_path>
- <int name="tracks/18/interp"> 1 </int>
- <real_array name="tracks/18/keys" len="24"> 0, 1, 0.101768, -0.813356, 5.76642, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.101768, -0.813356, 5.76642, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/19/type"> "transform" </string>
- <node_path name="tracks/19/path"> "Armature/Skeleton:l-ARMORIENT" </node_path>
- <int name="tracks/19/interp"> 1 </int>
- <real_array name="tracks/19/keys" len="24"> 0, 1, -0.849557, -0.741664, 5.51935, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.849557, -0.741664, 5.51935, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/20/type"> "transform" </string>
- <node_path name="tracks/20/path"> "Armature/Skeleton:hip" </node_path>
- <int name="tracks/20/interp"> 1 </int>
- <real_array name="tracks/20/keys" len="132"> 0, 1, 2.65402e-07, 1.83685, 0.489514, -5.25643e-15, 1.43922e-08, -0.0635436, 0.997979, 1, 1, 1, 0.05, 1, 2.56992e-07, 1.7811, 0.489514, -1.96073e-14, 1.43922e-08, -0.0635436, 0.997979, 1, 1, 1, 0.1, 1, 2.44553e-07, 1.69876, 0.489514, -1.94961e-14, 1.43922e-08, -0.0635436, 0.997979, 1, 1, 1, 0.15, 1, 2.41683e-07, 1.67977, 0.489514, -4.43536e-14, 1.60316e-08, -0.070782, 0.997492, 1, 1, 1, 0.2, 1, 2.44743e-07, 1.70003, 0.489514, -3.42428e-14, 2.17962e-08, -0.0962332, 0.995359, 1, 1, 1, 0.25, 1, 2.50383e-07, 1.73738, 0.489514, -5.58716e-16, 2.56855e-08, -0.113405, 0.993549, 1, 1, 1, 0.3, 1, 2.57035e-07, 1.78143, 0.489514, -6.36206e-15, 2.33115e-08, -0.102924, 0.994689, 1, 1, 1, 0.35, 1, 2.62333e-07, 1.81652, 0.489514, -1.06935e-14, 1.84103e-08, -0.0812848, 0.996691, 1, 1, 1, 0.4, 1, 2.6496e-07, 1.83392, 0.489514, -2.45344e-14, 1.50179e-08, -0.0663065, 0.997799, 1, 1, 1, 0.45, 1, 2.65402e-07, 1.83685, 0.489514, -5.25643e-15, 1.43922e-08, -0.0635436, 0.997979, 1, 1, 1, 1.25, 1, 2.65402e-07, 1.83685, 0.489514, -5.25643e-15, 1.43922e-08, -0.0635436, 0.997979, 1, 1, 1 </real_array>
- <string name="tracks/21/type"> "transform" </string>
- <node_path name="tracks/21/path"> "Armature/Skeleton:waist" </node_path>
- <int name="tracks/21/interp"> 1 </int>
- <real_array name="tracks/21/keys" len="120"> 0, 1, -4.65684e-10, 7.57313e-10, 0, -8.93894e-16, 2.55708e-08, -0.112898, 0.993607, 1, 1, 1, 0.05, 1, -4.18389e-09, 6.71868e-09, -2.98023e-08, -0.00385828, -0.000945429, -0.112898, 0.993599, 1, 1, 1, 0.1, 1, -2.6989e-09, 6.71803e-09, -2.98023e-08, -0.0118093, -0.00289381, -0.11289, 0.993533, 1, 1, 1, 0.15, 1, -1.65698e-09, 6.19854e-09, -1.19209e-07, -0.0173041, -0.00424031, -0.112881, 0.993449, 1, 1, 1, 0.2, 1, 6.17568e-09, 2.79554e-08, -1.78814e-07, -0.0174121, -0.00426678, -0.11288, 0.993447, 1, 1, 1, 0.25, 1, -9.69976e-10, -3.44268e-09, -2.98023e-08, -0.013893, -0.00340444, -0.112887, 0.993505, 1, 1, 1, 0.35, 1, 8.55826e-09, 2.92274e-08, -2.98023e-08, -0.00310744, -0.000761444, -0.112898, 0.993601, 1, 1, 1, 0.4, 1, 2.05826e-09, 1.24848e-08, 0, -0.000452603, -0.000110883, -0.112898, 0.993606, 1, 1, 1, 0.45, 1, -4.65684e-10, 7.57313e-10, 0, -8.93894e-16, 2.55708e-08, -0.112898, 0.993607, 1, 1, 1, 1.25, 1, -4.65684e-10, 7.57313e-10, 0, -8.93894e-16, 2.55708e-08, -0.112898, 0.993607, 1, 1, 1 </real_array>
- <string name="tracks/22/type"> "transform" </string>
- <node_path name="tracks/22/path"> "Armature/Skeleton:chest" </node_path>
- <int name="tracks/22/interp"> 1 </int>
- <real_array name="tracks/22/keys" len="108"> 0, 1, -7.51303e-09, 2.23517e-08, -2.38419e-07, 2.43554e-09, -0.00270918, 0.0663084, 0.997796, 1, 1, 1, 0.05, 1, -5.41336e-11, 3.72529e-09, -2.38419e-07, -0.00158657, -0.00317713, 0.0662892, 0.997794, 1, 1, 1, 0.15, 1, -3.26683e-10, 0, 5.96046e-08, -0.00925885, -0.00543992, 0.0661937, 0.997749, 1, 1, 1, 0.2, 1, -2.06055e-09, 1.49012e-08, -2.38419e-07, -0.0112141, -0.00601653, 0.0661687, 0.997727, 1, 1, 1, 0.25, 1, 1.76951e-08, -3.72529e-09, -1.78814e-07, -0.0104022, -0.00577711, 0.0661791, 0.997737, 1, 1, 1, 0.35, 1, 7.20902e-09, 7.45058e-09, -1.19209e-07, -0.00273, -0.00351437, 0.0662752, 0.997791, 1, 1, 1, 0.4, 1, 4.13622e-10, 3.72529e-09, -1.78814e-07, -0.000405934, -0.00282891, 0.0663035, 0.997795, 1, 1, 1, 0.45, 1, -7.51303e-09, 2.23517e-08, -2.38419e-07, 2.43554e-09, -0.00270918, 0.0663084, 0.997796, 1, 1, 1, 1.25, 1, -7.51303e-09, 2.23517e-08, -2.38419e-07, 2.43554e-09, -0.00270918, 0.0663084, 0.997796, 1, 1, 1 </real_array>
- <string name="tracks/23/type"> "transform" </string>
- <node_path name="tracks/23/path"> "Armature/Skeleton:neck" </node_path>
- <int name="tracks/23/interp"> 1 </int>
- <real_array name="tracks/23/keys" len="24"> 0, 1, 4.48992e-09, -1.3411e-07, -1.07288e-06, -1.49012e-08, 7.81341e-10, 2.3736e-09, 1, 1, 1, 1, 1.25, 1, 4.48992e-09, -1.3411e-07, -1.07288e-06, -1.49012e-08, 7.81341e-10, 2.3736e-09, 1, 1, 1, 1 </real_array>
- <string name="tracks/24/type"> "transform" </string>
- <node_path name="tracks/24/path"> "Armature/Skeleton:headtracker" </node_path>
- <int name="tracks/24/interp"> 1 </int>
- <real_array name="tracks/24/keys" len="120"> 0, 1, -1.54592e-09, -2.38419e-07, -3.32948e-08, 0.0746069, -0.101992, 0.0306522, 0.99151, 1, 1, 1, 0.05, 1, -1.11768e-09, -1.19209e-07, -9.73232e-08, 0.0219469, -0.103542, 0.0251775, 0.994064, 1, 1, 1, 0.1, 1, 3.72477e-10, -2.98023e-07, -7.61356e-08, -0.0560921, -0.105311, 0.0169133, 0.992712, 1, 1, 1, 0.15, 1, 1.49005e-09, -3.8743e-07, -9.8953e-08, -0.0807068, -0.112423, 0.0155536, 0.990255, 1, 1, 1, 0.2, 1, 9.68555e-09, -1.78814e-07, -2.06754e-07, -0.0663987, -0.135548, 0.0221852, 0.988294, 1, 1, 1, 0.25, 1, 1.86265e-08, -2.68221e-07, -1.18744e-08, -0.0319373, -0.150579, 0.0303761, 0.987615, 1, 1, 1, 0.35, 1, 7.26442e-09, -6.85453e-07, 3.81842e-08, 0.0516026, -0.119052, 0.0329235, 0.990999, 1, 1, 1, 0.4, 1, -1.48637e-09, -2.38419e-07, -5.07571e-08, 0.0712567, -0.10465, 0.03106, 0.991467, 1, 1, 1, 0.45, 1, -1.54592e-09, -2.38419e-07, -3.32948e-08, 0.0746069, -0.101992, 0.0306522, 0.99151, 1, 1, 1, 1.25, 1, -1.54592e-09, -2.38419e-07, -3.32948e-08, 0.0746069, -0.101992, 0.0306522, 0.99151, 1, 1, 1 </real_array>
- <string name="tracks/25/type"> "transform" </string>
- <node_path name="tracks/25/path"> "Armature/Skeleton:head" </node_path>
- <int name="tracks/25/interp"> 1 </int>
- <real_array name="tracks/25/keys" len="24"> 0, 1, 3.53794e-09, -1.25496e-07, -8.33534e-08, 2.23517e-08, 1.01485e-10, -1.43572e-10, 1, 1, 1, 1, 1.25, 1, 3.53794e-09, -1.25496e-07, -8.33534e-08, 2.23517e-08, 1.01485e-10, -1.43572e-10, 1, 1, 1, 1 </real_array>
- <string name="tracks/26/type"> "transform" </string>
- <node_path name="tracks/26/path"> "Armature/Skeleton:vent" </node_path>
- <int name="tracks/26/interp"> 1 </int>
- <real_array name="tracks/26/keys" len="24"> 0, 1, 1.23685e-09, 2.38419e-07, -5.96046e-07, -2.32831e-09, -1.31362e-12, 1.19249e-11, 1, 1, 1, 1, 1.25, 1, 1.23685e-09, 2.38419e-07, -5.96046e-07, -2.32831e-09, -1.31362e-12, 1.19249e-11, 1, 1, 1, 1 </real_array>
-
- </resource>
- <resource type="Animation" path="local://14">
- <string name="resource/name"> "jump-up-cycle" </string>
- <real name="length"> 0.416667 </real>
- <bool name="loop"> True </bool>
- <real name="step"> 0.1 </real>
- <string name="tracks/0/type"> "transform" </string>
- <node_path name="tracks/0/path"> "Armature/Skeleton:r-arm" </node_path>
- <int name="tracks/0/interp"> 1 </int>
- <real_array name="tracks/0/keys" len="120"> 0, 1, 6.55651e-07, -3.57628e-07, 5.66244e-07, 0.208387, -0.176945, -0.0164982, 0.961766, 1, 1, 1, 0.05, 1, 6.85453e-07, -2.38419e-07, 4.17233e-07, 0.211256, -0.175803, -0.0179009, 0.961324, 1, 1, 1, 0.1, 1, 6.55651e-07, -2.38419e-07, 3.27826e-07, 0.216682, -0.174684, -0.0207438, 0.960263, 1, 1, 1, 0.15, 1, 6.25849e-07, -3.57628e-07, 6.25849e-07, 0.219812, -0.176984, -0.0232576, 0.959072, 1, 1, 1, 0.25, 1, 1.3113e-06, -9.53674e-07, 9.23872e-07, 0.223631, -0.219998, -0.0262768, 0.949157, 1, 1, 1, 0.3, 1, 8.9407e-07, -4.76837e-07, 6.85453e-07, 0.220416, -0.21329, -0.0232336, 0.951517, 1, 1, 1, 0.35, 1, 8.34465e-07, -3.57628e-07, 6.25849e-07, 0.214429, -0.195082, -0.0193009, 0.956865, 1, 1, 1, 0.4, 1, 8.34465e-07, -3.57628e-07, 6.25849e-07, 0.209436, -0.180062, -0.0169379, 0.960951, 1, 1, 1, 0.45, 1, 6.55651e-07, -3.57628e-07, 5.66244e-07, 0.208387, -0.176945, -0.0164982, 0.961766, 1, 1, 1, 1.25, 1, 6.55651e-07, -3.57628e-07, 5.66244e-07, 0.208387, -0.176945, -0.0164982, 0.961766, 1, 1, 1 </real_array>
- <string name="tracks/1/type"> "transform" </string>
- <node_path name="tracks/1/path"> "Armature/Skeleton:r-forearm" </node_path>
- <int name="tracks/1/interp"> 1 </int>
- <real_array name="tracks/1/keys" len="108"> 0, 1, 5.06639e-07, -8.64267e-07, -8.9407e-07, -0.0797867, 0.0313898, -0.00372185, 0.996311, 1, 1, 1, 0.05, 1, -5.96046e-08, -4.76837e-07, -3.57628e-07, -0.0735466, 0.0175489, -0.00298843, 0.997133, 1, 1, 1, 0.2, 1, 2.98023e-07, -9.83477e-07, -5.36442e-07, -0.0401349, -0.0767179, 0.000985969, 0.996244, 1, 1, 1, 0.25, 1, -2.98023e-08, -6.25849e-07, -4.17233e-07, -0.0324823, -0.0976145, 0.00230383, 0.994691, 1, 1, 1, 0.3, 1, 2.08616e-07, -9.53674e-07, -6.55651e-07, -0.0445163, -0.0629722, 0.000635031, 0.997022, 1, 0.999999, 1, 0.35, 1, -1.49012e-07, -8.34465e-07, -4.17233e-07, -0.0633553, -0.0111982, -0.0018671, 0.997926, 1, 1, 1, 0.4, 1, 2.38419e-07, -8.64267e-07, -7.7486e-07, -0.0770585, 0.0244395, -0.00342743, 0.996721, 1, 1, 1, 0.45, 1, 5.06639e-07, -8.64267e-07, -8.9407e-07, -0.0797867, 0.0313898, -0.00372185, 0.996311, 1, 1, 1, 1.25, 1, 5.06639e-07, -8.64267e-07, -8.9407e-07, -0.0797867, 0.0313898, -0.00372185, 0.996311, 1, 1, 1 </real_array>
- <string name="tracks/2/type"> "transform" </string>
- <node_path name="tracks/2/path"> "Armature/Skeleton:l-arm" </node_path>
- <int name="tracks/2/interp"> 1 </int>
- <real_array name="tracks/2/keys" len="132"> 0, 1, -1.19209e-07, -5.96046e-07, 5.36442e-07, -0.488489, -0.631801, -0.249807, 0.547542, 1, 1, 1, 0.05, 1, -1.49012e-07, -7.15256e-07, 5.96046e-07, -0.474017, -0.625071, -0.244485, 0.569931, 1, 1, 0.999999, 0.1, 1, -5.96046e-07, -3.57628e-07, 6.25849e-07, -0.454842, -0.607865, -0.232791, 0.607805, 1, 1, 0.999999, 0.15, 1, -6.25849e-07, -4.76837e-07, 6.85453e-07, -0.465321, -0.582319, -0.222366, 0.628437, 1, 1, 1, 0.2, 1, -3.8743e-07, -5.96046e-07, 6.25849e-07, -0.510621, -0.547625, -0.217789, 0.626052, 1, 1, 1, 0.25, 1, -5.96046e-07, -7.15256e-07, 2.98023e-07, -0.546434, -0.526096, -0.217482, 0.614275, 1, 1, 1, 0.3, 1, -3.57628e-07, -5.96046e-07, 6.85453e-07, -0.543207, -0.547611, -0.225218, 0.595252, 1, 1, 0.999999, 0.35, 1, -5.06639e-07, -5.96046e-07, 7.7486e-07, -0.516521, -0.594071, -0.238908, 0.568514, 1, 1, 1, 0.4, 1, -3.27826e-07, -5.96046e-07, 7.15256e-07, -0.493183, -0.625944, -0.248106, 0.550825, 1, 1, 1, 0.45, 1, -1.19209e-07, -5.96046e-07, 5.36442e-07, -0.488489, -0.631801, -0.249807, 0.547542, 1, 1, 1, 1.25, 1, -1.19209e-07, -5.96046e-07, 5.36442e-07, -0.488489, -0.631801, -0.249807, 0.547542, 1, 1, 1 </real_array>
- <string name="tracks/3/type"> "transform" </string>
- <node_path name="tracks/3/path"> "Armature/Skeleton:l-forearm" </node_path>
- <int name="tracks/3/interp"> 1 </int>
- <real_array name="tracks/3/keys" len="132"> 0, 1, -8.9407e-08, -5.96046e-07, -2.38419e-07, 0.170167, 0.120493, -0.091473, 0.973734, 1, 1, 1, 0.05, 1, -5.96046e-08, -5.36442e-07, -2.98023e-07, 0.191507, 0.15179, -0.0881411, 0.965669, 1, 1, 1, 0.1, 1, -2.98023e-08, -5.06639e-07, -1.19209e-07, 0.225056, 0.198248, -0.0838434, 0.950273, 1, 1, 1, 0.15, 1, -1.78814e-07, -6.85453e-07, -2.38419e-07, 0.242609, 0.209269, -0.0881917, 0.94317, 1, 1, 1, 0.2, 1, -3.27826e-07, -5.36442e-07, -1.19209e-07, 0.246276, 0.185328, -0.105902, 0.945403, 1, 1, 1, 0.25, 1, -4.76837e-07, -5.06639e-07, -7.7486e-07, 0.240434, 0.157542, -0.120519, 0.950183, 1, 1, 1, 0.3, 1, -8.9407e-08, -6.85453e-07, -2.98023e-07, 0.22081, 0.140399, -0.117544, 0.957974, 1, 0.999999, 1, 0.35, 1, -1.19209e-07, -7.7486e-07, -2.98023e-07, 0.191979, 0.127301, -0.104336, 0.967498, 1, 1, 1, 0.4, 1, -8.9407e-08, -6.55651e-07, -2.98023e-07, 0.173508, 0.121415, -0.0935976, 0.972827, 1, 1, 1, 0.45, 1, -8.9407e-08, -5.96046e-07, -2.38419e-07, 0.170167, 0.120493, -0.091473, 0.973734, 1, 1, 1, 1.25, 1, -8.9407e-08, -5.96046e-07, -2.38419e-07, 0.170167, 0.120493, -0.091473, 0.973734, 1, 1, 1 </real_array>
- <string name="tracks/4/type"> "transform" </string>
- <node_path name="tracks/4/path"> "Armature/Skeleton:r-thigh" </node_path>
- <int name="tracks/4/interp"> 1 </int>
- <real_array name="tracks/4/keys" len="120"> 0, 1, 0, 1.63913e-07, 1.93715e-07, -0.731646, -0.0455606, -0.00930311, 0.680097, 1, 1, 1, 0.05, 1, -8.9407e-08, 5.96046e-08, -3.57628e-07, -0.699019, -0.0340935, -0.0129449, 0.714172, 1, 1, 1, 0.1, 1, -8.9407e-08, 1.41561e-07, -2.83122e-07, -0.643626, -0.015991, -0.0189581, 0.764938, 1, 1, 1, 0.15, 1, -8.9407e-08, 3.72529e-08, -5.06639e-07, -0.617849, -0.00879986, -0.0226563, 0.785921, 1, 1, 1, 0.2, 1, -5.96046e-08, 9.68575e-08, 7.45058e-08, -0.628974, -0.00984708, -0.0265256, 0.776912, 1, 1, 1, 0.25, 1, -5.96046e-08, 9.68575e-08, -4.47035e-07, -0.653197, -0.0153019, -0.02661, 0.756565, 1, 1, 1, 0.35, 1, -2.98023e-08, 2.98023e-08, 2.98023e-07, -0.712225, -0.0376632, -0.0133416, 0.700813, 1, 1, 1, 0.4, 1, -2.98023e-08, 1.04308e-07, 1.63913e-07, -0.728798, -0.0444052, -0.00986262, 0.683216, 1, 1, 1, 0.45, 1, 0, 1.63913e-07, 1.93715e-07, -0.731646, -0.0455606, -0.00930311, 0.680097, 1, 1, 1, 1.25, 1, 0, 1.63913e-07, 1.93715e-07, -0.731646, -0.0455606, -0.00930311, 0.680097, 1, 1, 1 </real_array>
- <string name="tracks/5/type"> "transform" </string>
- <node_path name="tracks/5/path"> "Armature/Skeleton:r-leg" </node_path>
- <int name="tracks/5/interp"> 1 </int>
- <real_array name="tracks/5/keys" len="120"> 0, 1, -0.0436297, 0.0381679, -0.243318, 0.903835, 0.221183, 0.00392365, -0.366258, 1, 1, 1, 0.05, 1, -0.0436298, 0.0381678, -0.243318, 0.894017, 0.213358, 0.00409072, -0.393949, 1, 1, 1, 0.1, 1, -0.0436297, 0.0381675, -0.243318, 0.873591, 0.198684, 0.00402625, -0.444239, 1, 1, 1, 0.15, 1, -0.0436297, 0.0381679, -0.243318, 0.86099, 0.194348, 0.00472605, -0.470004, 1, 1, 1, 0.2, 1, -0.0436298, 0.038168, -0.243318, 0.866453, 0.209209, 0.00740134, -0.453251, 1, 1, 1, 0.25, 1, -0.0436297, 0.0381682, -0.243318, 0.877278, 0.223532, 0.00901692, -0.42466, 1, 1, 1, 0.35, 1, -0.0436297, 0.0381675, -0.243318, 0.89824, 0.222872, 0.00544398, -0.378765, 1, 1, 1, 0.4, 1, -0.0436297, 0.0381677, -0.243318, 0.90306, 0.22143, 0.0041485, -0.368015, 1, 1, 1, 0.45, 1, -0.0436297, 0.0381679, -0.243318, 0.903835, 0.221183, 0.00392365, -0.366258, 1, 1, 1, 1.25, 1, -0.0436297, 0.0381679, -0.243318, 0.903835, 0.221183, 0.00392365, -0.366258, 1, 1, 1 </real_array>
- <string name="tracks/6/type"> "transform" </string>
- <node_path name="tracks/6/path"> "Armature/Skeleton:r-foot" </node_path>
- <int name="tracks/6/interp"> 1 </int>
- <real_array name="tracks/6/keys" len="108"> 0, 1, 7.45058e-08, 1.19209e-07, -3.72529e-09, -0.278586, 0.162913, 0.049835, 0.94518, 1, 1, 1, 0.05, 1, 5.21541e-08, -1.19209e-07, 4.47035e-08, -0.263884, 0.163221, 0.0462377, 0.949519, 1, 1, 1, 0.15, 1, 3.72529e-08, 0, 2.98023e-08, -0.191844, 0.164134, 0.02867, 0.967178, 1, 1, 1, 0.2, 1, 9.68575e-08, 0, -7.45058e-09, -0.173312, 0.164214, 0.0241673, 0.970779, 1, 1, 1, 0.25, 1, 8.9407e-08, -3.57628e-07, 2.6077e-08, -0.181008, 0.164188, 0.0260364, 0.96933, 1, 1, 1, 0.35, 1, 7.45058e-08, 3.57628e-07, 7.45058e-09, -0.253238, 0.163417, 0.0436354, 0.952503, 1, 1, 1, 0.4, 1, 8.19564e-08, 2.38419e-07, 2.6077e-08, -0.274832, 0.162996, 0.0489163, 0.946312, 1, 1, 1, 0.45, 1, 7.45058e-08, 1.19209e-07, -3.72529e-09, -0.278586, 0.162913, 0.049835, 0.94518, 1, 1, 1, 1.25, 1, 7.45058e-08, 1.19209e-07, -3.72529e-09, -0.278586, 0.162913, 0.049835, 0.94518, 1, 1, 1 </real_array>
- <string name="tracks/7/type"> "transform" </string>
- <node_path name="tracks/7/path"> "Armature/Skeleton:l-thigh" </node_path>
- <int name="tracks/7/interp"> 1 </int>
- <real_array name="tracks/7/keys" len="120"> 0, 1, 0, 2.08616e-07, 1.49012e-08, 0.318341, 0.0708015, -0.00441775, 0.945318, 1, 1, 1, 0.05, 1, 0, 1.93715e-07, 3.42727e-07, 0.307147, 0.068999, -0.0035256, 0.949151, 1, 1, 1, 0.1, 1, 2.98023e-08, 2.01166e-07, 4.47035e-08, 0.292292, 0.0665824, -0.00232838, 0.954006, 1, 1, 1, 0.15, 1, 5.96046e-08, 1.04308e-07, -1.93715e-07, 0.272221, 0.0650766, -0.00188312, 0.96003, 1, 1, 1, 0.2, 1, 2.98023e-08, 2.23517e-08, -1.78814e-07, 0.232486, 0.0650023, -0.00182597, 0.970424, 1, 1, 1, 0.25, 1, 5.96046e-08, -1.49012e-08, -1.04308e-07, 0.226129, 0.0676028, -0.00263455, 0.971745, 1, 1, 1, 0.35, 1, -2.98023e-08, 5.21541e-08, 1.63913e-07, 0.288667, 0.069411, -0.00418897, 0.954901, 1, 1, 1, 0.4, 1, -2.98023e-08, 1.41561e-07, 1.93715e-07, 0.312853, 0.0704368, -0.0043685, 0.947176, 1, 1, 1, 0.45, 1, 0, 2.08616e-07, 1.49012e-08, 0.318341, 0.0708015, -0.00441775, 0.945318, 1, 1, 1, 1.25, 1, 0, 2.08616e-07, 1.49012e-08, 0.318341, 0.0708015, -0.00441775, 0.945318, 1, 1, 1 </real_array>
- <string name="tracks/8/type"> "transform" </string>
- <node_path name="tracks/8/path"> "Armature/Skeleton:l-leg" </node_path>
- <int name="tracks/8/interp"> 1 </int>
- <real_array name="tracks/8/keys" len="108"> 0, 1, 5.78584e-08, 5.96046e-08, 2.38419e-07, -0.0511448, -0.0112637, 0.00107338, 0.998627, 1, 1, 1, 0.05, 1, -2.94531e-08, -8.19564e-08, 1.78814e-07, -0.0669256, -0.012717, 0.000882011, 0.997677, 1, 1, 1, 0.1, 1, -3.07336e-08, -2.98023e-08, 3.57628e-07, -0.0875047, -0.0145704, 0.000627808, 0.996057, 1, 1, 1, 0.15, 1, 1.66474e-08, -8.9407e-08, 2.38419e-07, -0.12177, -0.0175352, 0.000386084, 0.992403, 1, 1, 1, 0.2, 1, 1.28057e-08, -1.49012e-08, 1.19209e-07, -0.196391, -0.0229446, -2.58925e-05, 0.980257, 1, 1, 1, 0.25, 1, -7.91624e-08, 8.9407e-08, 0, -0.21572, -0.0236374, -9.3472e-05, 0.976169, 1, 1, 1, 0.4, 1, 2.95695e-08, 6.70552e-08, 1.19209e-07, -0.060964, -0.012162, 0.00100229, 0.998065, 1, 1, 1, 0.45, 1, 5.78584e-08, 5.96046e-08, 2.38419e-07, -0.0511448, -0.0112637, 0.00107338, 0.998627, 1, 1, 1, 1.25, 1, 5.78584e-08, 5.96046e-08, 2.38419e-07, -0.0511448, -0.0112637, 0.00107338, 0.998627, 1, 1, 1 </real_array>
- <string name="tracks/9/type"> "transform" </string>
- <node_path name="tracks/9/path"> "Armature/Skeleton:l-foot" </node_path>
- <int name="tracks/9/interp"> 1 </int>
- <real_array name="tracks/9/keys" len="108"> 0, 1, 5.21541e-08, 1.19209e-07, -1.9744e-07, -0.285587, 0.0658082, 0.0159816, 0.955957, 1, 1, 1, 0.05, 1, 7.45058e-09, 1.19209e-07, -1.08033e-07, -0.295281, 0.0650349, 0.017475, 0.953034, 1, 1, 1, 0.15, 1, -2.23517e-08, 1.19209e-07, 2.98023e-08, -0.341727, 0.0611981, 0.0246725, 0.93748, 1, 1, 1, 0.2, 1, 5.21541e-08, 1.19209e-07, -1.19209e-07, -0.353427, 0.0601963, 0.0264969, 0.933147, 1, 1, 1, 0.25, 1, -1.49012e-08, 2.38419e-07, -4.84288e-08, -0.348577, 0.0606133, 0.0257401, 0.934964, 1, 1, 1, 0.35, 1, -7.45058e-09, 1.19209e-07, -7.45058e-09, -0.302251, 0.0644732, 0.0185506, 0.950865, 1, 1, 1, 0.4, 1, 5.21541e-08, 1.19209e-07, -8.19564e-08, -0.28807, 0.065611, 0.0163638, 0.955219, 1, 1, 1, 0.45, 1, 5.21541e-08, 1.19209e-07, -1.9744e-07, -0.285587, 0.0658082, 0.0159816, 0.955957, 1, 1, 1, 1.25, 1, 5.21541e-08, 1.19209e-07, -1.9744e-07, -0.285587, 0.0658082, 0.0159816, 0.955957, 1, 1, 1 </real_array>
- <string name="tracks/10/type"> "transform" </string>
- <node_path name="tracks/10/path"> "Armature/Skeleton:MASTER" </node_path>
- <int name="tracks/10/interp"> 1 </int>
- <real_array name="tracks/10/keys" len="24"> 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/11/type"> "transform" </string>
- <node_path name="tracks/11/path"> "Armature/Skeleton:HEAD" </node_path>
- <int name="tracks/11/interp"> 1 </int>
- <real_array name="tracks/11/keys" len="108"> 0, 1, 1.37965e-08, 0.0913706, -0.0102687, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 1.37965e-08, 0.0913706, 0.0826712, 0, 0, 0, 1, 1, 1, 1, 0.15, 1, 1.37965e-08, 0.0913706, 0.527418, 0, 0, 0, 1, 1, 1, 1, 0.2, 1, 1.37965e-08, 0.0913706, 0.640416, 0, 0, -7.10543e-15, 1, 1, 1, 1, 0.25, 1, 1.37965e-08, 0.0913706, 0.59344, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, 1.37965e-08, 0.0913706, 0.149321, 0, 0, -7.10543e-15, 1, 1, 1, 1, 0.4, 1, 1.37965e-08, 0.0913706, 0.0135775, 0, 0, 0, 1, 1, 1, 1, 0.45, 1, 1.37965e-08, 0.0913706, -0.0102687, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 1.37965e-08, 0.0913706, -0.0102687, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/12/type"> "transform" </string>
- <node_path name="tracks/12/path"> "Armature/Skeleton:r-LEGCONTROL" </node_path>
- <int name="tracks/12/interp"> 1 </int>
- <real_array name="tracks/12/keys" len="108"> 0, 1, -0.142338, -0.579062, 1.09897, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -0.142338, -0.574357, 1.07628, 0, 0, 0, 1, 1, 1, 1, 0.15, 1, -0.142338, -0.551601, 0.966619, 0, 0, 0, 1, 1, 1, 1, 0.2, 1, -0.142338, -0.545802, 0.938678, 0, 0, 0, 1, 1, 1, 1, 0.25, 1, -0.142338, -0.54821, 0.950281, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, -0.142338, -0.570965, 1.05993, 0, 0, 0, 1, 1, 1, 1, 0.4, 1, -0.142338, -0.577858, 1.09316, 0, 0, 0, 1, 1, 1, 1, 0.45, 1, -0.142338, -0.579062, 1.09897, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.142338, -0.579062, 1.09897, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/13/type"> "transform" </string>
- <node_path name="tracks/13/path"> "Armature/Skeleton:l-LEGCONTROL" </node_path>
- <int name="tracks/13/interp"> 1 </int>
- <real_array name="tracks/13/keys" len="108"> 0, 1, 0.133965, 0.921787, 0.705414, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 0.133965, 0.88632, 0.724279, 0, 0, 0, 1, 1, 1, 1, 0.1, 1, 0.133965, 0.833892, 0.752174, 0, 0, 0, 1, 1, 1, 1, 0.15, 1, 0.133965, 0.821796, 0.758611, 0, 0, 0, 1, 1, 1, 1, 0.2, 1, 0.133965, 0.834697, 0.751748, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, 0.133965, 0.908846, 0.712298, 0, 0, 0, 1, 1, 1, 1, 0.4, 1, 0.133965, 0.919922, 0.706406, 0, 0, 0, 1, 1, 1, 1, 0.45, 1, 0.133965, 0.921787, 0.705414, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.133965, 0.921787, 0.705414, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/14/type"> "transform" </string>
- <node_path name="tracks/14/path"> "Armature/Skeleton:r-LEGORIENT" </node_path>
- <int name="tracks/14/interp"> 1 </int>
- <real_array name="tracks/14/keys" len="24"> 0, 1, 0.100474, 0.669825, -0.778672, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.100474, 0.669825, -0.778672, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/15/type"> "transform" </string>
- <node_path name="tracks/15/path"> "Armature/Skeleton:l-LEGORIENT" </node_path>
- <int name="tracks/15/interp"> 1 </int>
- <real_array name="tracks/15/keys" len="24"> 0, 1, -0.0204011, -0.122407, 5.96046e-08, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.0204011, -0.122407, 5.96046e-08, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/16/type"> "transform" </string>
- <node_path name="tracks/16/path"> "Armature/Skeleton:r-ARMCONTROL" </node_path>
- <int name="tracks/16/interp"> 1 </int>
- <real_array name="tracks/16/keys" len="120"> 0, 1, -0.868295, 0.267668, -0.820401, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -0.868295, 0.253357, -0.761204, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, -0.868295, 0.216179, -0.653431, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.15, 1, -0.868295, 0.157463, -0.585229, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.2, 1, -0.868295, 0.102061, -0.562116, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.25, 1, -0.868295, 0.10969, -0.583242, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, -0.868295, 0.226187, -0.758093, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, -0.868295, 0.261497, -0.811129, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, -0.868295, 0.267668, -0.820401, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.868295, 0.267668, -0.820401, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/17/type"> "transform" </string>
- <node_path name="tracks/17/path"> "Armature/Skeleton:l-ARMCONTROL" </node_path>
- <int name="tracks/17/interp"> 1 </int>
- <real_array name="tracks/17/keys" len="108"> 0, 1, 2.08906, 2.18272, 3.23967, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 2.08906, 2.16545, 3.23967, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.15, 1, 2.08906, 2.08198, 3.23967, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.2, 1, 2.08906, 2.06071, 3.23967, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.25, 1, 2.08906, 2.06954, 3.23967, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, 2.08906, 2.15301, 3.23967, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, 2.08906, 2.1783, 3.23967, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, 2.08906, 2.18272, 3.23967, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 2.08906, 2.18272, 3.23967, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/18/type"> "transform" </string>
- <node_path name="tracks/18/path"> "Armature/Skeleton:r-ARMORIENT" </node_path>
- <int name="tracks/18/interp"> 1 </int>
- <real_array name="tracks/18/keys" len="24"> 0, 1, 0.405204, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.405204, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/19/type"> "transform" </string>
- <node_path name="tracks/19/path"> "Armature/Skeleton:l-ARMORIENT" </node_path>
- <int name="tracks/19/interp"> 1 </int>
- <real_array name="tracks/19/keys" len="132"> 0, 1, -0.495073, -1.94554, 0.375148, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -0.529633, -1.94554, 0.375148, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, -0.616933, -1.94554, 0.375148, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.15, 1, -0.726325, -1.94554, 0.375148, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.2, 1, -0.813485, -1.94554, 0.375148, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.25, 1, -0.847955, -1.94554, 0.375148, 0, 0, 0, 1, 1, 1, 1, 0.3, 1, -0.773744, -1.94554, 0.375148, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.35, 1, -0.620743, -1.94554, 0.375148, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, -0.514687, -1.94554, 0.375148, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, -0.495073, -1.94554, 0.375148, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.495073, -1.94554, 0.375148, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/20/type"> "transform" </string>
- <node_path name="tracks/20/path"> "Armature/Skeleton:hip" </node_path>
- <int name="tracks/20/interp"> 1 </int>
- <real_array name="tracks/20/keys" len="132"> 0, 1, 0.050238, 0.697428, 0.108012, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1, 0.05, 1, 0.050238, 0.727833, 0.0877454, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1, 0.1, 1, 0.050238, 0.772783, 0.0577767, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1, 0.15, 1, 0.050238, 0.78451, 0.0674334, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1, 0.2, 1, 0.050238, 0.778496, 0.13139, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1, 0.25, 1, 0.050238, 0.766398, 0.174636, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1, 0.3, 1, 0.050238, 0.744412, 0.160603, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1, 0.35, 1, 0.050238, 0.716858, 0.131686, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1, 0.4, 1, 0.050238, 0.700317, 0.111698, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1, 0.45, 1, 0.050238, 0.697428, 0.108012, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1, 1.25, 1, 0.050238, 0.697428, 0.108012, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1 </real_array>
- <string name="tracks/21/type"> "transform" </string>
- <node_path name="tracks/21/path"> "Armature/Skeleton:waist" </node_path>
- <int name="tracks/21/interp"> 1 </int>
- <real_array name="tracks/21/keys" len="24"> 0, 1, 7.45059e-09, -5.21541e-08, 2.38419e-07, 0.126301, -0.0110499, -0.0864524, 0.988156, 1, 1, 1, 1.25, 1, 7.45059e-09, -5.21541e-08, 2.38419e-07, 0.126301, -0.0110499, -0.0864524, 0.988156, 1, 1, 1 </real_array>
- <string name="tracks/22/type"> "transform" </string>
- <node_path name="tracks/22/path"> "Armature/Skeleton:chest" </node_path>
- <int name="tracks/22/interp"> 1 </int>
- <real_array name="tracks/22/keys" len="24"> 0, 1, -2.26918e-09, 5.21541e-08, -1.78814e-07, 0.0237758, -0.0135633, -0.0860939, 0.995911, 1, 1, 1, 1.25, 1, -2.26918e-09, 5.21541e-08, -1.78814e-07, 0.0237758, -0.0135633, -0.0860939, 0.995911, 1, 1, 1 </real_array>
- <string name="tracks/23/type"> "transform" </string>
- <node_path name="tracks/23/path"> "Armature/Skeleton:neck" </node_path>
- <int name="tracks/23/interp"> 1 </int>
- <real_array name="tracks/23/keys" len="24"> 0, 1, -1.11758e-08, -2.23517e-07, -1.43051e-06, -7.45058e-09, -4.4605e-10, 4.26538e-09, 1, 1, 1, 1, 1.25, 1, -1.11758e-08, -2.23517e-07, -1.43051e-06, -7.45058e-09, -4.4605e-10, 4.26538e-09, 1, 1, 1, 1 </real_array>
- <string name="tracks/24/type"> "transform" </string>
- <node_path name="tracks/24/path"> "Armature/Skeleton:headtracker" </node_path>
- <int name="tracks/24/interp"> 1 </int>
- <real_array name="tracks/24/keys" len="108"> 0, 1, 1.02445e-08, -4.47035e-07, -1.05007e-07, 0.287287, -0.0941088, 0.0255168, 0.952869, 1, 1, 1, 0.05, 1, -2.68222e-08, -2.98023e-08, -7.10133e-08, 0.277009, -0.0944548, 0.024506, 0.9559, 1, 1, 1, 0.15, 1, -2.42144e-08, -3.57628e-07, -3.39933e-08, 0.229614, -0.0956923, 0.0198279, 0.968363, 1, 1, 1, 0.2, 1, -1.22934e-08, -1.78814e-07, 1.30385e-08, 0.224057, -0.0957887, 0.0192787, 0.969665, 1, 1, 1, 0.25, 1, -3.91156e-08, 1.19209e-07, -4.79631e-08, 0.233664, -0.0955615, 0.0202274, 0.967399, 1, 1, 1, 0.35, 1, -3.35279e-09, -3.27826e-07, -4.61005e-08, 0.274341, -0.0944949, 0.024241, 0.956671, 1, 1, 1, 0.4, 1, -1.67641e-09, -2.68221e-07, -8.21892e-08, 0.285395, -0.0941665, 0.0253304, 0.953436, 1, 1, 1, 0.45, 1, 1.02445e-08, -4.47035e-07, -1.05007e-07, 0.287287, -0.0941088, 0.0255168, 0.952869, 1, 1, 1, 1.25, 1, 1.02445e-08, -4.47035e-07, -1.05007e-07, 0.287287, -0.0941088, 0.0255168, 0.952869, 1, 1, 1 </real_array>
- <string name="tracks/25/type"> "transform" </string>
- <node_path name="tracks/25/path"> "Armature/Skeleton:head" </node_path>
- <int name="tracks/25/interp"> 1 </int>
- <real_array name="tracks/25/keys" len="24"> 0, 1, -7.74519e-09, -9.56934e-08, 3.16533e-07, 7.45058e-09, 3.37575e-10, -1.99442e-09, 1, 1, 1, 1, 1.25, 1, -7.74519e-09, -9.56934e-08, 3.16533e-07, 7.45058e-09, 3.37575e-10, -1.99442e-09, 1, 1, 1, 1 </real_array>
- <string name="tracks/26/type"> "transform" </string>
- <node_path name="tracks/26/path"> "Armature/Skeleton:vent" </node_path>
- <int name="tracks/26/interp"> 1 </int>
- <real_array name="tracks/26/keys" len="24"> 0, 1, 3.38022e-08, 0.00292349, 0.20433, 6.98492e-10, 2.45226e-11, 6.71222e-11, 1, 1, 1, 1, 1.25, 1, 3.38022e-08, 0.00292349, 0.20433, 6.98492e-10, 2.45226e-11, 6.71222e-11, 1, 1, 1, 1 </real_array>
-
- </resource>
- <main_resource>
- <dictionary name="_bundled" shared="false">
- <string> "names" </string>
- <string_array len="248">
- <string> "player" </string>
- <string> "RigidBody" </string>
- <string> "shape_count" </string>
- <string> "shapes/0/shape" </string>
- <string> "shapes/0/transform" </string>
- <string> "shapes/0/trigger" </string>
- <string> "shapes/1/shape" </string>
- <string> "shapes/1/transform" </string>
- <string> "shapes/1/trigger" </string>
- <string> "mode" </string>
- <string> "mass" </string>
- <string> "friction" </string>
- <string> "bounce" </string>
- <string> "custom_integrator" </string>
- <string> "continuous_cd" </string>
- <string> "contacts_reported" </string>
- <string> "contact_monitor" </string>
- <string> "active" </string>
- <string> "can_sleep" </string>
- <string> "velocity/linear" </string>
- <string> "velocity/angular" </string>
- <string> "script/script" </string>
- <string> "__meta__" </string>
- <string> "collision_capsule" </string>
- <string> "CollisionShape" </string>
- <string> "transform/local" </string>
- <string> "shape" </string>
- <string> "trigger" </string>
- <string> "collision_ray" </string>
- <string> "target" </string>
- <string> "Spatial" </string>
- <string> "camera" </string>
- <string> "Camera" </string>
- <string> "projection" </string>
- <string> "fov" </string>
- <string> "near" </string>
- <string> "far" </string>
- <string> "vaspect" </string>
- <string> "current" </string>
- <string> "visible_layers" </string>
- <string> "environment" </string>
- <string> "min_distance" </string>
- <string> "max_distance" </string>
- <string> "angle_v_adjust" </string>
- <string> "autoturn_ray_aperture" </string>
- <string> "autoturn_speed" </string>
- <string> "Armature" </string>
- <string> "Skeleton" </string>
- <string> "bones/0/name" </string>
- <string> "bones/0/parent" </string>
- <string> "bones/0/rest" </string>
- <string> "bones/0/enabled" </string>
- <string> "bones/0/bound_childs" </string>
- <string> "bones/1/name" </string>
- <string> "bones/1/parent" </string>
- <string> "bones/1/rest" </string>
- <string> "bones/1/enabled" </string>
- <string> "bones/1/bound_childs" </string>
- <string> "bones/2/name" </string>
- <string> "bones/2/parent" </string>
- <string> "bones/2/rest" </string>
- <string> "bones/2/enabled" </string>
- <string> "bones/2/bound_childs" </string>
- <string> "bones/3/name" </string>
- <string> "bones/3/parent" </string>
- <string> "bones/3/rest" </string>
- <string> "bones/3/enabled" </string>
- <string> "bones/3/bound_childs" </string>
- <string> "bones/4/name" </string>
- <string> "bones/4/parent" </string>
- <string> "bones/4/rest" </string>
- <string> "bones/4/enabled" </string>
- <string> "bones/4/bound_childs" </string>
- <string> "bones/5/name" </string>
- <string> "bones/5/parent" </string>
- <string> "bones/5/rest" </string>
- <string> "bones/5/enabled" </string>
- <string> "bones/5/bound_childs" </string>
- <string> "bones/6/name" </string>
- <string> "bones/6/parent" </string>
- <string> "bones/6/rest" </string>
- <string> "bones/6/enabled" </string>
- <string> "bones/6/bound_childs" </string>
- <string> "bones/7/name" </string>
- <string> "bones/7/parent" </string>
- <string> "bones/7/rest" </string>
- <string> "bones/7/enabled" </string>
- <string> "bones/7/bound_childs" </string>
- <string> "bones/8/name" </string>
- <string> "bones/8/parent" </string>
- <string> "bones/8/rest" </string>
- <string> "bones/8/enabled" </string>
- <string> "bones/8/bound_childs" </string>
- <string> "bones/9/name" </string>
- <string> "bones/9/parent" </string>
- <string> "bones/9/rest" </string>
- <string> "bones/9/enabled" </string>
- <string> "bones/9/bound_childs" </string>
- <string> "bones/10/name" </string>
- <string> "bones/10/parent" </string>
- <string> "bones/10/rest" </string>
- <string> "bones/10/enabled" </string>
- <string> "bones/10/bound_childs" </string>
- <string> "bones/11/name" </string>
- <string> "bones/11/parent" </string>
- <string> "bones/11/rest" </string>
- <string> "bones/11/enabled" </string>
- <string> "bones/11/bound_childs" </string>
- <string> "bones/12/name" </string>
- <string> "bones/12/parent" </string>
- <string> "bones/12/rest" </string>
- <string> "bones/12/enabled" </string>
- <string> "bones/12/bound_childs" </string>
- <string> "bones/13/name" </string>
- <string> "bones/13/parent" </string>
- <string> "bones/13/rest" </string>
- <string> "bones/13/enabled" </string>
- <string> "bones/13/bound_childs" </string>
- <string> "bones/14/name" </string>
- <string> "bones/14/parent" </string>
- <string> "bones/14/rest" </string>
- <string> "bones/14/enabled" </string>
- <string> "bones/14/bound_childs" </string>
- <string> "bones/15/name" </string>
- <string> "bones/15/parent" </string>
- <string> "bones/15/rest" </string>
- <string> "bones/15/enabled" </string>
- <string> "bones/15/bound_childs" </string>
- <string> "bones/16/name" </string>
- <string> "bones/16/parent" </string>
- <string> "bones/16/rest" </string>
- <string> "bones/16/enabled" </string>
- <string> "bones/16/bound_childs" </string>
- <string> "bones/17/name" </string>
- <string> "bones/17/parent" </string>
- <string> "bones/17/rest" </string>
- <string> "bones/17/enabled" </string>
- <string> "bones/17/bound_childs" </string>
- <string> "bones/18/name" </string>
- <string> "bones/18/parent" </string>
- <string> "bones/18/rest" </string>
- <string> "bones/18/enabled" </string>
- <string> "bones/18/bound_childs" </string>
- <string> "bones/19/name" </string>
- <string> "bones/19/parent" </string>
- <string> "bones/19/rest" </string>
- <string> "bones/19/enabled" </string>
- <string> "bones/19/bound_childs" </string>
- <string> "bones/20/name" </string>
- <string> "bones/20/parent" </string>
- <string> "bones/20/rest" </string>
- <string> "bones/20/enabled" </string>
- <string> "bones/20/bound_childs" </string>
- <string> "bones/21/name" </string>
- <string> "bones/21/parent" </string>
- <string> "bones/21/rest" </string>
- <string> "bones/21/enabled" </string>
- <string> "bones/21/bound_childs" </string>
- <string> "bones/22/name" </string>
- <string> "bones/22/parent" </string>
- <string> "bones/22/rest" </string>
- <string> "bones/22/enabled" </string>
- <string> "bones/22/bound_childs" </string>
- <string> "bones/23/name" </string>
- <string> "bones/23/parent" </string>
- <string> "bones/23/rest" </string>
- <string> "bones/23/enabled" </string>
- <string> "bones/23/bound_childs" </string>
- <string> "bones/24/name" </string>
- <string> "bones/24/parent" </string>
- <string> "bones/24/rest" </string>
- <string> "bones/24/enabled" </string>
- <string> "bones/24/bound_childs" </string>
- <string> "bones/25/name" </string>
- <string> "bones/25/parent" </string>
- <string> "bones/25/rest" </string>
- <string> "bones/25/enabled" </string>
- <string> "bones/25/bound_childs" </string>
- <string> "bones/26/name" </string>
- <string> "bones/26/parent" </string>
- <string> "bones/26/rest" </string>
- <string> "bones/26/enabled" </string>
- <string> "bones/26/bound_childs" </string>
- <string> "robot" </string>
- <string> "MeshInstance" </string>
- <string> "layers" </string>
- <string> "geometry/visible" </string>
- <string> "geometry/material_override" </string>
- <string> "geometry/cast_shadow" </string>
- <string> "geometry/receive_shadows" </string>
- <string> "geometry/range_begin" </string>
- <string> "geometry/range_end" </string>
- <string> "geometry/billboard" </string>
- <string> "geometry/billboard_y" </string>
- <string> "geometry/depth_scale" </string>
- <string> "geometry/visible_in_all_rooms" </string>
- <string> "mesh/mesh" </string>
- <string> "bullet" </string>
- <string> "Position3D" </string>
- <string> "sfx" </string>
- <string> "SpatialSamplePlayer" </string>
- <string> "params/volume_db" </string>
- <string> "params/pitch_scale" </string>
- <string> "params/attenuation/min_distance" </string>
- <string> "params/attenuation/max_distance" </string>
- <string> "params/attenuation/distance_exp" </string>
- <string> "params/emission_cone/degrees" </string>
- <string> "params/emission_cone/attenuation_db" </string>
- <string> "config/polyphony" </string>
- <string> "config/samples" </string>
- <string> "AnimationPlayer" </string>
- <string> "playback/process_mode" </string>
- <string> "playback/default_blend_time" </string>
- <string> "root/root" </string>
- <string> "anims/idle" </string>
- <string> "anims/shooting" </string>
- <string> "anims/falling-cycle" </string>
- <string> "anims/default" </string>
- <string> "anims/run-cycle" </string>
- <string> "anims/walk-cycle" </string>
- <string> "anims/shooting_standing" </string>
- <string> "anims/jump-up-cycle" </string>
- <string> "playback/active" </string>
- <string> "playback/speed" </string>
- <string> "blend_times" </string>
- <string> "autoplay" </string>
- <string> "AnimationTreePlayer" </string>
- <string> "base_path" </string>
- <string> "master_player" </string>
- <string> "data" </string>
- <string> "fwd" </string>
- <string> "TouchScreenButton" </string>
- <string> "visibility/visible" </string>
- <string> "visibility/opacity" </string>
- <string> "visibility/self_opacity" </string>
- <string> "visibility/behind_parent" </string>
- <string> "transform/pos" </string>
- <string> "transform/rot" </string>
- <string> "transform/scale" </string>
- <string> "normal" </string>
- <string> "pressed" </string>
- <string> "bitmask" </string>
- <string> "passby_press" </string>
- <string> "action" </string>
- <string> "visibility_mode" </string>
- <string> "bwd" </string>
- <string> "left" </string>
- <string> "right" </string>
- </string_array>
- <string> "version" </string>
- <int> 1 </int>
- <string> "conn_count" </string>
- <int> 0 </int>
- <string> "node_count" </string>
- <int> 16 </int>
- <string> "variants" </string>
- <array len="121" shared="false">
- <int> 2 </int>
- <resource resource_type="Shape" path="local://1"> </resource>
- <transform> 1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0.954765, 0 </transform>
- <bool> False </bool>
- <resource resource_type="Shape" path="local://2"> </resource>
- <transform> 1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 1.01236, 0 </transform>
- <real> 1 </real>
- <real> 0 </real>
- <bool> True </bool>
- <int> 3 </int>
- <vector3> 0, 0, 0 </vector3>
- <resource resource_type="Script" path="res://player.gd"> </resource>
- <dictionary shared="false">
- <string> "__editor_plugin_states__" </string>
- <dictionary shared="false">
- <string> "Script" </string>
- <dictionary shared="false">
- <string> "current" </string>
- <int> 1 </int>
- <string> "sources" </string>
- <array len="2" shared="false">
- <string> "res://follow_camera.gd" </string>
- <string> "res://player.gd" </string>
- </array>
- </dictionary>
- <string> "2D" </string>
- <dictionary shared="false">
- <string> "pixel_snap" </string>
- <bool> False </bool>
- <string> "zoom" </string>
- <real> 1 </real>
- <string> "ofs" </string>
- <vector2> -241, -19 </vector2>
- </dictionary>
- <string> "3D" </string>
- <dictionary shared="false">
- <string> "zfar" </string>
- <real> 500 </real>
- <string> "fov" </string>
- <real> 400 </real>
- <string> "viewports" </string>
- <array len="4" shared="false">
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 2.161076 </real>
- <string> "x_rot" </string>
- <real> 0.520797 </real>
- <string> "y_rot" </string>
- <real> 26.741669 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> -0.415811, 0.486899, 0.089334 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- </array>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
- <string> "znear" </string>
- <real> 0.1 </real>
- </dictionary>
- </dictionary>
- <string> "__editor_run_settings__" </string>
- <dictionary shared="false">
- <string> "custom_args" </string>
- <string> "-l $scene" </string>
- <string> "run_mode" </string>
- <int> 0 </int>
- </dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "3D" </string>
- </dictionary>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.95244, 0 </transform>
- <transform> 1, 0, 0, 0, 0.871263, 0.490817, 0, -0.490817, 0.871263, 0, 2.59805, 1.25672 </transform>
- <int> 0 </int>
- <real> 70 </real>
- <real> 0.1 </real>
- <real> 100 </real>
- <int> -1 </int>
- <resource name=""></resource> <resource resource_type="Script" path="res://follow_camera.gd"> </resource>
- <real> 3 </real>
- <int> 25 </int>
- <int> 50 </int>
- <transform> 0.3, 0, 0, 0, 0.3, 0, 0, 0, 0.3, 0, 0, 0 </transform>
- <string> "MASTER" </string>
- <transform> 1, 0, -0, 0, 7.54979e-08, 1, -0, -1, 7.54979e-08, 0, -0.011277, -0 </transform>
- <array len="0" shared="false">
- </array>
- <string> "hip" </string>
- <transform> 1, -1.50996e-07, -3.60002e-14, -1.50996e-07, -1, -3.01992e-07, 9.59926e-15, 3.01992e-07, -1, -3.38813e-21, 2.58363e-07, 2.10612 </transform>
- <string> "waist" </string>
- <int> 1 </int>
- <transform> 1, 1.50996e-07, 1.80001e-14, -1.50996e-07, 1, 0, -1.80001e-14, 0, 1, 3.38813e-21, 2.84217e-14, -0.384614 </transform>
- <string> "chest" </string>
- <transform> 1, -7.31455e-16, 4.86029e-17, 7.28861e-16, 0.999166, 0.040823, -7.84198e-17, -0.040823, 0.999166, 0, 4.84022e-11, -0.8217 </transform>
- <string> "neck" </string>
- <transform> -1, -1.10548e-06, -9.37766e-09, 1.08766e-06, -0.985328, 0.170671, -1.97913e-07, 0.170671, 0.985328, -1.64727e-13, 5.96046e-08, -1.24906 </transform>
- <string> "headtracker" </string>
- <int> 4 </int>
- <transform> 1, 9.87793e-08, -1.09789e-06, 1.09743e-06, 0.00449866, 0.99999, 1.03717e-07, -0.99999, 0.00449866, 0, 5.96046e-08, -0.491774 </transform>
- <string> "head" </string>
- <int> 5 </int>
- <transform> -1, 2.36978e-07, 1.97097e-07, -2.5035e-07, -0.25144, -0.967873, -1.79807e-07, -0.967873, 0.25144, -2.94648e-10, 4.76837e-07, 0.00400549 </transform>
- <string> "vent" </string>
- <int> 6 </int>
- <transform> 1, -2.54965e-07, -1.4699e-08, 2.55005e-07, 0.999996, 0.00282324, 1.39791e-08, -0.00282325, 0.999996, -7.04808e-08, 0.270992, -1.2429 </transform>
- <string> "r-arm" </string>
- <transform> 0.11477, -0.699489, -0.705367, -0.802661, -0.483653, 0.349021, -0.585289, 0.526113, -0.616961, 0.940786, 0.107144, -0.773564 </transform>
- <string> "r-forearm" </string>
- <int> 8 </int>
- <transform> -0.859542, 0.0564943, 0.507934, 0.107631, -0.951571, 0.287973, 0.499604, 0.302194, 0.811834, 2.38419e-07, -4.76837e-07, -0.935513 </transform>
- <string> "l-arm" </string>
- <transform> 0.11477, 0.699489, 0.705367, 0.802661, -0.483653, 0.349021, 0.585289, 0.526113, -0.616961, -0.940786, 0.107144, -0.773564 </transform>
- <string> "l-forearm" </string>
- <int> 10 </int>
- <transform> -0.859542, -0.0564943, -0.507934, -0.107631, -0.951571, 0.287973, -0.499604, 0.302194, 0.811834, -2.38419e-07, -4.76837e-07, -0.935513 </transform>
- <string> "r-thigh" </string>
- <transform> 0.994883, -0.0545632, -0.085028, -0.0580629, -0.997541, -0.0392442, -0.0826777, 0.0439804, -0.995605, 0.349652, 0.0628238, -0.163877 </transform>
- <string> "r-leg" </string>
- <int> 12 </int>
- <transform> -0.999508, -0.031366, -0.000870243, 0.0312939, -0.994411, -0.100835, 0.00229738, -0.100812, 0.994903, 5.96046e-08, 5.96046e-08, -0.644636 </transform>
- <string> "r-foot" </string>
- <int> 13 </int>
- <transform> 0.996208, -0.0766666, -0.0411273, -0.0442384, -0.0393329, -0.998246, 0.0749145, 0.996281, -0.0425754, -5.96046e-08, 4.19095e-09, -1.43073 </transform>
- <string> "l-thigh" </string>
- <transform> 0.994883, 0.0545632, 0.085028, 0.0580633, -0.997541, -0.0392452, 0.0826776, 0.0439813, -0.995606, -0.349652, 0.0628238, -0.163877 </transform>
- <string> "l-leg" </string>
- <int> 15 </int>
- <transform> -0.999508, 0.0313662, 0.000870456, -0.0312941, -0.994411, -0.100836, -0.00229725, -0.100814, 0.994903, 0, 1.49012e-08, -0.644636 </transform>
- <string> "l-foot" </string>
- <int> 16 </int>
- <transform> 0.996208, 0.0766668, 0.0411275, 0.0442386, -0.0393327, -0.998246, -0.0749147, 0.996281, -0.0425752, 0, -8.3819e-09, -1.43073 </transform>
- <string> "HEAD" </string>
- <transform> 1, -1.50996e-07, -0, -1.50996e-07, -1, 0, 0, 0, -1, 5.68434e-14, -5.79659, 6.35228 </transform>
- <string> "r-LEGCONTROL" </string>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 0.518863, 3.72276e-07, 0.204768 </transform>
- <string> "l-LEGCONTROL" </string>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, -0.518863, 3.72276e-07, 0.204768 </transform>
- <string> "r-LEGORIENT" </string>
- <transform> -1, -1.50996e-07, -5.03577e-15, -3.75647e-14, 2.15429e-07, 1, -1.50996e-07, 1, -2.15429e-07, 0.411677, -0.66395, 1.62881 </transform>
- <string> "l-LEGORIENT" </string>
- <transform> -1, -1.50996e-07, -5.03577e-15, -3.75647e-14, 2.15429e-07, 1, -1.50996e-07, 1, -2.15429e-07, -0.411677, -0.66395, 1.62881 </transform>
- <string> "r-ARMCONTROL" </string>
- <transform> 1, 0, 0, 0, 7.54979e-08, -1, 0, 1, 7.54979e-08, 2.62535, -0.186879, 2.59016 </transform>
- <string> "l-ARMCONTROL" </string>
- <transform> 1, 0, 0, 0, 7.54979e-08, -1, 0, 1, 7.54979e-08, -2.62535, -0.186879, 2.59016 </transform>
- <string> "r-ARMORIENT" </string>
- <transform> 1, 0, 0, 0, 7.54979e-08, -1, 0, 1, 7.54979e-08, 1.57185, 0.510255, 3.44768 </transform>
- <string> "l-ARMORIENT" </string>
- <transform> 1, 0, 0, 0, 7.54979e-08, -1, 0, 1, 7.54979e-08, -1.57185, 0.510255, 3.44768 </transform>
- <resource resource_type="Mesh" path="local://5"> </resource>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, -1.94071, 3.64079, 3.3802 </transform>
- <real> 180 </real>
- <real> -6 </real>
- <resource resource_type="SampleLibrary" path="local://6"> </resource>
- <node_path> ".." </node_path>
- <resource resource_type="Animation" path="local://7"> </resource>
- <resource resource_type="Animation" path="local://8"> </resource>
- <resource resource_type="Animation" path="local://9"> </resource>
- <resource resource_type="Animation" path="local://10"> </resource>
- <resource resource_type="Animation" path="local://11"> </resource>
- <resource resource_type="Animation" path="local://12"> </resource>
- <resource resource_type="Animation" path="local://13"> </resource>
- <resource resource_type="Animation" path="local://14"> </resource>
- <string> "" </string>
- <node_path> "../AnimationPlayer" </node_path>
- <dictionary shared="false">
- <string> "connections" </string>
- <array len="27" shared="false">
- <string> "walk" </string>
- <string> "scale" </string>
- <int> 0 </int>
- <string> "scale" </string>
- <string> "state" </string>
- <int> 0 </int>
- <string> "anim 3" </string>
- <string> "state" </string>
- <int> 1 </int>
- <string> "anim 4" </string>
- <string> "state" </string>
- <int> 2 </int>
- <string> "gun" </string>
- <string> "out" </string>
- <int> 0 </int>
- <string> "state" </string>
- <string> "gun" </string>
- <int> 0 </int>
- <string> "anim 5" </string>
- <string> "gun" </string>
- <int> 1 </int>
- <string> "anim" </string>
- <string> "walk" </string>
- <int> 0 </int>
- <string> "anim 2" </string>
- <string> "walk" </string>
- <int> 1 </int>
- </array>
- <string> "master" </string>
- <node_path> "../AnimationPlayer" </node_path>
- <string> "active" </string>
- <bool> True </bool>
- <string> "nodes" </string>
- <array len="10" shared="false">
- <dictionary shared="false">
- <string> "id" </string>
- <string> "scale" </string>
- <string> "scale" </string>
- <real> 1.2 </real>
- <string> "pos" </string>
- <vector2> 247, 68 </vector2>
- <string> "type" </string>
- <string> "timescale" </string>
- </dictionary>
- <dictionary shared="false">
- <string> "id" </string>
- <string> "state" </string>
- <string> "transitions" </string>
- <array len="3" shared="false">
- <dictionary shared="false">
- <string> "auto_advance" </string>
- <bool> False </bool>
- </dictionary>
- <dictionary shared="false">
- <string> "auto_advance" </string>
- <bool> False </bool>
- </dictionary>
- <dictionary shared="false">
- <string> "auto_advance" </string>
- <bool> False </bool>
- </dictionary>
- </array>
- <string> "xfade" </string>
- <real> 0.1 </real>
- <string> "type" </string>
- <string> "transition" </string>
- <string> "pos" </string>
- <vector2> 359, 132 </vector2>
- </dictionary>
- <dictionary shared="false">
- <string> "from" </string>
- <string> "idle" </string>
- <string> "id" </string>
- <string> "anim" </string>
- <string> "pos" </string>
- <vector2> 7, 70 </vector2>
- <string> "type" </string>
- <string> "animation" </string>
- </dictionary>
- <dictionary shared="false">
- <string> "id" </string>
- <string> "out" </string>
- <string> "type" </string>
- <string> "output" </string>
- <string> "pos" </string>
- <vector2> 579, 114 </vector2>
- </dictionary>
- <dictionary shared="false">
- <string> "from" </string>
- <string> "shooting_standing" </string>
- <string> "id" </string>
- <string> "anim 5" </string>
- <string> "pos" </string>
- <vector2> 331, 242 </vector2>
- <string> "type" </string>
- <string> "animation" </string>
- </dictionary>
- <dictionary shared="false">
- <string> "from" </string>
- <string> "jump-up-cycle" </string>
- <string> "id" </string>
- <string> "anim 3" </string>
- <string> "pos" </string>
- <vector2> 143, 144 </vector2>
- <string> "type" </string>
- <string> "animation" </string>
- </dictionary>
- <dictionary shared="false">
- <string> "from" </string>
- <string> "walk-cycle" </string>
- <string> "id" </string>
- <string> "anim 2" </string>
- <string> "pos" </string>
- <vector2> 7, 152 </vector2>
- <string> "type" </string>
- <string> "animation" </string>
- </dictionary>
- <dictionary shared="false">
- <string> "id" </string>
- <string> "gun" </string>
- <string> "blend" </string>
- <real> 1 </real>
- <string> "filter" </string>
- <array len="22" shared="false">
- <node_path> "Armature/Skeleton:MASTER" </node_path>
- <node_path> "Armature/Skeleton:l-thigh" </node_path>
- <node_path> "Armature/Skeleton:headtracker" </node_path>
- <node_path> "Armature/Skeleton:r-foot" </node_path>
- <node_path> "Armature/Skeleton:r-leg" </node_path>
- <node_path> "Armature/Skeleton:waist" </node_path>
- <node_path> "Armature/Skeleton:r-ARMCONTROL" </node_path>
- <node_path> "Armature/Skeleton:r-ARMORIENT" </node_path>
- <node_path> "Armature/Skeleton:r-LEGCONTROL" </node_path>
- <node_path> "Armature/Skeleton:r-LEGORIENT" </node_path>
- <node_path> "Armature/Skeleton:hip" </node_path>
- <node_path> "Armature/Skeleton:l-foot" </node_path>
- <node_path> "Armature/Skeleton:l-leg" </node_path>
- <node_path> "Armature/Skeleton:neck" </node_path>
- <node_path> "Armature" </node_path>
- <node_path> "Armature/Skeleton:l-ARMCONTROL" </node_path>
- <node_path> "Armature/Skeleton:l-ARMORIENT" </node_path>
- <node_path> "Armature/Skeleton:l-LEGCONTROL" </node_path>
- <node_path> "Armature/Skeleton:l-LEGORIENT" </node_path>
- <node_path> "Armature/Skeleton:HEAD" </node_path>
- <node_path> "Armature/Skeleton:head" </node_path>
- <node_path> "Armature/Skeleton:r-thigh" </node_path>
- </array>
- <string> "type" </string>
- <string> "blend2" </string>
- <string> "pos" </string>
- <vector2> 469, 127 </vector2>
- </dictionary>
- <dictionary shared="false">
- <string> "from" </string>
- <string> "falling-cycle" </string>
- <string> "id" </string>
- <string> "anim 4" </string>
- <string> "pos" </string>
- <vector2> 141, 230 </vector2>
- <string> "type" </string>
- <string> "animation" </string>
- </dictionary>
- <dictionary shared="false">
- <string> "id" </string>
- <string> "walk" </string>
- <string> "blend" </string>
- <real> 1 </real>
- <string> "filter" </string>
- <array len="0" shared="false">
- </array>
- <string> "type" </string>
- <string> "blend2" </string>
- <string> "pos" </string>
- <vector2> 148, 46 </vector2>
- </dictionary>
- </array>
- </dictionary>
- <vector2> 72, 301 </vector2>
- <vector2> 1, 1 </vector2>
- <resource resource_type="Texture" path="res://osb_up.png"> </resource>
- <string> "move_forward" </string>
- <vector2> 72, 365 </vector2>
- <resource resource_type="Texture" path="res://osb_down.png"> </resource>
- <string> "move_backwards" </string>
- <vector2> 29, 332 </vector2>
- <resource resource_type="Texture" path="res://osb_left.png"> </resource>
- <string> "move_left" </string>
- <vector2> 108, 327 </vector2>
- <resource resource_type="Texture" path="res://osb_right.png"> </resource>
- <string> "move_right" </string>
- </array>
- <string> "nodes" </string>
- <int_array len="654"> -1, -1, 1, 0, -1, 21, 2, 0, 3, 1, 4, 2, 5, 3, 6, 4, 7, 5, 8, 3, 9, 0, 10, 6, 11, 7, 12, 7, 13, 8, 14, 3, 15, 9, 16, 8, 17, 8, 18, 8, 19, 10, 20, 10, 21, 11, 22, 12, 0, 0, 0, 24, 23, -1, 3, 25, 2, 26, 1, 27, 3, 0, 0, 0, 24, 28, -1, 3, 25, 5, 26, 4, 27, 3, 0, 0, 0, 30, 29, -1, 1, 25, 13, 0, 3, 0, 32, 31, -1, 15, 25, 14, 33, 15, 34, 16, 35, 17, 36, 18, 37, 3, 38, 3, 39, 19, 40, 20, 21, 21, 41, 6, 42, 22, 43, 7, 44, 23, 45, 24, 0, 0, 0, 30, 46, -1, 1, 25, 25, 0, 5, 0, 47, 47, -1, 135, 48, 26, 49, 19, 50, 27, 51, 8, 52, 28, 53, 29, 54, 15, 55, 30, 56, 8, 57, 28, 58, 31, 59, 32, 60, 33, 61, 8, 62, 28, 63, 34, 64, 0, 65, 35, 66, 8, 67, 28, 68, 36, 69, 9, 70, 37, 71, 8, 72, 28, 73, 38, 74, 39, 75, 40, 76, 8, 77, 28, 78, 41, 79, 42, 80, 43, 81, 8, 82, 28, 83, 44, 84, 45, 85, 46, 86, 8, 87, 28, 88, 47, 89, 9, 90, 48, 91, 8, 92, 28, 93, 49, 94, 50, 95, 51, 96, 8, 97, 28, 98, 52, 99, 9, 100, 53, 101, 8, 102, 28, 103, 54, 104, 55, 105, 56, 106, 8, 107, 28, 108, 57, 109, 32, 110, 58, 111, 8, 112, 28, 113, 59, 114, 60, 115, 61, 116, 8, 117, 28, 118, 62, 119, 63, 120, 64, 121, 8, 122, 28, 123, 65, 124, 32, 125, 66, 126, 8, 127, 28, 128, 67, 129, 68, 130, 69, 131, 8, 132, 28, 133, 70, 134, 71, 135, 72, 136, 8, 137, 28, 138, 73, 139, 15, 140, 74, 141, 8, 142, 28, 143, 75, 144, 15, 145, 76, 146, 8, 147, 28, 148, 77, 149, 15, 150, 78, 151, 8, 152, 28, 153, 79, 154, 15, 155, 80, 156, 8, 157, 28, 158, 81, 159, 15, 160, 82, 161, 8, 162, 28, 163, 83, 164, 15, 165, 84, 166, 8, 167, 28, 168, 85, 169, 15, 170, 86, 171, 8, 172, 28, 173, 87, 174, 15, 175, 88, 176, 8, 177, 28, 178, 89, 179, 15, 180, 90, 181, 8, 182, 28, 0, 6, 0, 184, 183, -1, 12, 185, 32, 186, 8, 187, 20, 188, 8, 189, 8, 190, 7, 191, 7, 192, 3, 193, 3, 194, 3, 195, 3, 196, 91, 0, 5, 0, 198, 197, -1, 1, 25, 92, 0, 0, 0, 200, 199, -1, 9, 201, 7, 202, 6, 203, 6, 204, 18, 205, 6, 206, 93, 207, 94, 208, 32, 209, 95, 0, 0, 0, 210, 210, -1, 15, 211, 32, 212, 7, 213, 96, 214, 97, 215, 98, 216, 99, 217, 100, 218, 101, 219, 102, 220, 103, 221, 104, 222, 8, 223, 6, 224, 28, 225, 105, 0, 0, 0, 226, 226, -1, 3, 227, 96, 228, 106, 229, 107, 0, 0, 0, 231, 230, -1, 13, 232, 8, 233, 6, 234, 6, 235, 3, 236, 108, 237, 7, 238, 109, 239, 110, 240, 20, 241, 20, 242, 8, 243, 111, 244, 32, 0, 0, 0, 231, 245, -1, 13, 232, 8, 233, 6, 234, 6, 235, 3, 236, 112, 237, 7, 238, 109, 239, 113, 240, 20, 241, 20, 242, 8, 243, 114, 244, 32, 0, 0, 0, 231, 246, -1, 13, 232, 8, 233, 6, 234, 6, 235, 3, 236, 115, 237, 7, 238, 109, 239, 116, 240, 20, 241, 20, 242, 8, 243, 117, 244, 32, 0, 0, 0, 231, 247, -1, 13, 232, 8, 233, 6, 234, 6, 235, 3, 236, 118, 237, 7, 238, 109, 239, 119, 240, 20, 241, 20, 242, 8, 243, 120, 244, 32, 0 </int_array>
- <string> "conns" </string>
- <int_array len="0"> </int_array>
- </dictionary>
-
- </main_resource>
-</resource_file> \ No newline at end of file
diff --git a/demos/3d/platformer/robotrigged.scn b/demos/3d/platformer/robotrigged.scn
index e54125a07e..68af0cfe47 100644
--- a/demos/3d/platformer/robotrigged.scn
+++ b/demos/3d/platformer/robotrigged.scn
Binary files differ
diff --git a/demos/3d/platformer/stage.scn b/demos/3d/platformer/stage.scn
new file mode 100644
index 0000000000..7eafda5888
--- /dev/null
+++ b/demos/3d/platformer/stage.scn
Binary files differ
diff --git a/demos/3d/platformer/stage.xml b/demos/3d/platformer/stage.xml
deleted file mode 100644
index 37a11068c9..0000000000
--- a/demos/3d/platformer/stage.xml
+++ /dev/null
@@ -1,697 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="7" version="1.0" version_name="Godot Engine v1.0.stable.custom_build">
- <ext_resource path="res://sb.cube" type="CubeMap"></ext_resource>
- <ext_resource path="res://tiles.res" type="MeshLibrary"></ext_resource>
- <ext_resource path="res://enemy.scn" type="PackedScene"></ext_resource>
- <ext_resource path="res://player.xml" type="PackedScene"></ext_resource>
- <ext_resource path="res://coin.scn" type="PackedScene"></ext_resource>
- <resource type="Environment" path="local://1">
- <bool name="ambient_light/enabled"> True </bool>
- <color name="ambient_light/color"> 0, 0.409429, 0.596681, 1 </color>
- <real name="ambient_light/energy"> 1 </real>
- <bool name="fxaa/enabled"> False </bool>
- <int name="background/mode"> 4 </int>
- <color name="background/color"> 0, 0, 0, 1 </color>
- <nil name="background/texture"> </nil>
- <resource name="background/cubemap" resource_type="CubeMap" path="res://sb.cube"> </resource>
- <real name="background/energy"> 1 </real>
- <real name="background/scale"> 1 </real>
- <real name="background/glow"> 0.6 </real>
- <bool name="glow/enabled"> True </bool>
- <int name="glow/blur_passes"> 2 </int>
- <real name="glow/blur_scale"> 1.3 </real>
- <real name="glow/blur_strength"> 1.2 </real>
- <int name="glow/blur_blend_mode"> 1 </int>
- <real name="glow/bloom"> 0 </real>
- <real name="glow/bloom_treshold"> 0.5 </real>
- <bool name="dof_blur/enabled"> False </bool>
- <int name="dof_blur/blur_passes"> 1 </int>
- <real name="dof_blur/begin"> 100 </real>
- <real name="dof_blur/range"> 10 </real>
- <bool name="hdr/enabled"> True </bool>
- <int name="hdr/tonemapper"> 0 </int>
- <real name="hdr/exposure"> 0.4 </real>
- <real name="hdr/white"> 1 </real>
- <real name="hdr/glow_treshold"> 0.9 </real>
- <real name="hdr/glow_scale"> 0.5 </real>
- <real name="hdr/min_luminance"> 0.4 </real>
- <real name="hdr/max_luminance"> 8 </real>
- <real name="hdr/exposure_adj_speed"> 2 </real>
- <bool name="fog/enabled"> True </bool>
- <real name="fog/begin"> 10 </real>
- <color name="fog/begin_color"> 0, 0.773632, 0.985852, 1 </color>
- <color name="fog/end_color"> 0, 0, 0, 1 </color>
- <real name="fog/attenuation"> 0.965936 </real>
- <bool name="fog/bg"> True </bool>
- <bool name="bcs/enabled"> False </bool>
- <real name="bcs/brightness"> 1 </real>
- <real name="bcs/contrast"> 1 </real>
- <real name="bcs/saturation"> 1.608 </real>
- <bool name="srgb/enabled"> False </bool>
-
- </resource>
- <main_resource>
- <dictionary name="_bundled" shared="false">
- <string> "names" </string>
- <string_array len="94">
- <string> "world" </string>
- <string> "Spatial" </string>
- <string> "_import_path" </string>
- <string> "_import_transform" </string>
- <string> "visibility/visible" </string>
- <string> "__meta__" </string>
- <string> "GridMap" </string>
- <string> "theme/theme" </string>
- <string> "theme/bake" </string>
- <string> "lighting/bake" </string>
- <string> "cell/size" </string>
- <string> "cell/octant_size" </string>
- <string> "cell/center_x" </string>
- <string> "cell/center_y" </string>
- <string> "cell/center_z" </string>
- <string> "cell/scale" </string>
- <string> "data" </string>
- <string> "DirectionalLight" </string>
- <string> "transform/local" </string>
- <string> "layers" </string>
- <string> "params/enabled" </string>
- <string> "params/editor_only" </string>
- <string> "params/bake_mode" </string>
- <string> "params/energy" </string>
- <string> "colors/diffuse" </string>
- <string> "colors/specular" </string>
- <string> "shadow/shadow" </string>
- <string> "shadow/darkening" </string>
- <string> "shadow/z_offset" </string>
- <string> "shadow/z_slope_scale" </string>
- <string> "shadow/esm_multiplier" </string>
- <string> "shadow/blur_passes" </string>
- <string> "projector" </string>
- <string> "operator" </string>
- <string> "shadow/mode" </string>
- <string> "shadow/max_distance" </string>
- <string> "shadow/split_weight" </string>
- <string> "shadow/zoffset_scale" </string>
- <string> "environment" </string>
- <string> "WorldEnvironment" </string>
- <string> "coins" </string>
- <string> "Node" </string>
- <string> "coin" </string>
- <string> "Area" </string>
- <string> "coin 2" </string>
- <string> "coin 3" </string>
- <string> "coin 3 2" </string>
- <string> "coin 4" </string>
- <string> "coin 4 2" </string>
- <string> "coin 4 3" </string>
- <string> "coin 3 3" </string>
- <string> "coin 5" </string>
- <string> "coin 4 4" </string>
- <string> "coin 3 4" </string>
- <string> "coin 4 4 2" </string>
- <string> "coin 6" </string>
- <string> "coin 4 5" </string>
- <string> "coin 3 5" </string>
- <string> "coin 4 5 2" </string>
- <string> "coin 4 4 3" </string>
- <string> "coin 3 5 2" </string>
- <string> "coin 6 2" </string>
- <string> "coin 4 5 3" </string>
- <string> "coin 7" </string>
- <string> "coin 4 6" </string>
- <string> "coin 6 3" </string>
- <string> "coin 3 5 3" </string>
- <string> "coin 4 4 4" </string>
- <string> "coin 3 6" </string>
- <string> "coin 4 5 4" </string>
- <string> "coin 4 5 4 2" </string>
- <string> "coin 8" </string>
- <string> "coin 4 4 5" </string>
- <string> "coin 4 7" </string>
- <string> "coin 6 4" </string>
- <string> "coin 3 5 4" </string>
- <string> "coin 4 5 5" </string>
- <string> "coin 3 7" </string>
- <string> "coin 4 5 4 3" </string>
- <string> "coin 9" </string>
- <string> "coin 4 4 6" </string>
- <string> "coin 4 8" </string>
- <string> "coin 4 5 6" </string>
- <string> "coin 3 5 5" </string>
- <string> "coin 6 5" </string>
- <string> "coin 3 8" </string>
- <string> "coin 4 5 4 4" </string>
- <string> "enemies" </string>
- <string> "enemy" </string>
- <string> "RigidBody" </string>
- <string> "enemy 2" </string>
- <string> "enemy 3" </string>
- <string> "enemy 4" </string>
- <string> "player" </string>
- </string_array>
- <string> "version" </string>
- <int> 1 </int>
- <string> "conn_count" </string>
- <int> 0 </int>
- <string> "node_count" </string>
- <int> 55 </int>
- <string> "variants" </string>
- <array len="82" shared="false">
- <node_path> "" </node_path>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 </transform>
- <bool> True </bool>
- <dictionary shared="false">
- <string> "__editor_plugin_states__" </string>
- <dictionary shared="false">
- <string> "2D" </string>
- <dictionary shared="false">
- <string> "pixel_snap" </string>
- <bool> False </bool>
- <string> "zoom" </string>
- <real> 1 </real>
- <string> "use_snap" </string>
- <bool> False </bool>
- <string> "ofs" </string>
- <vector2> 1, 1 </vector2>
- <string> "snap" </string>
- <int> 10 </int>
- </dictionary>
- <string> "3D" </string>
- <dictionary shared="false">
- <string> "deflight_rot_y" </string>
- <real> 0.628319 </real>
- <string> "zfar" </string>
- <real> 500 </real>
- <string> "fov" </string>
- <real> 179 </real>
- <string> "viewports" </string>
- <array len="4" shared="false">
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 9.009935 </real>
- <string> "x_rot" </string>
- <real> 0.458294 </real>
- <string> "y_rot" </string>
- <real> -1.2 </real>
- <string> "listener" </string>
- <bool> True </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 13.4535, 5.75047, 13.8175 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "listener" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "listener" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "listener" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- </array>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "default_light" </string>
- <bool> False </bool>
- <string> "ambient_light_color" </string>
- <color> 0.15, 0.15, 0.15, 1 </color>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
- <string> "znear" </string>
- <real> 0.1 </real>
- <string> "default_srgb" </string>
- <bool> False </bool>
- <string> "deflight_rot_x" </string>
- <real> 0.942478 </real>
- </dictionary>
- </dictionary>
- <string> "__editor_run_settings__" </string>
- <dictionary shared="false">
- <string> "custom_args" </string>
- <string> "-l $scene" </string>
- <string> "run_mode" </string>
- <int> 0 </int>
- </dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "3D" </string>
- </dictionary>
- <resource resource_type="MeshLibrary" path="res://tiles.res"> </resource>
- <bool> False </bool>
- <real> 2 </real>
- <int> 4 </int>
- <real> 1.001 </real>
- <dictionary shared="false">
- <string> "cells" </string>
- <int_array len="5133"> 3, 0, 1048584, 12, 0, 1441800, 65539, 0, 1048584, 65548, 0, 1441800, 131075, 0, 1048578, 131084, 0, 1441800, 196611, 0, 1048578, 196620, 0, 1441800, 262147, 0, 1048578, 262156, 0, 1441800, 327683, 0, 1048584, 327692, 0, 1441794, 393219, 0, 1048584, 393228, 0, 1441794, 458752, 0, 655367, 458753, 0, 655367, 458754, 0, 655367, 458755, 0, 655367, 458764, 0, 1441794, 524286, 0, 655367, 524287, 0, 655367, 524300, 0, 1441798, -65533, 0, 1048579, -65532, 0, 1441799, -65531, 0, 1441799, -65530, 0, 1441799, -65529, 0, 1441799, -65528, 0, 1441799, -65527, 0, 1441799, -65526, 0, 1441799, -65525, 0, 1441799, -65524, 0, 1441800, 3, 1, 1048584, 12, 1, 1441800, 29, 1, 8, 30, 1, 8, 31, 1, 8, 65539, 1, 1048584, 65548, 1, 1441800, 65560, 1, 655366, 65561, 1, 655366, 65562, 1, 655366, 65563, 1, 655366, 65564, 1, 655365, 65565, 1, 6, 65566, 1, 6, 65567, 1, 6, 65568, 1, 655366, 65569, 1, 655365, 131075, 1, 1048578, 131084, 1, 1441800, 196611, 1, 1048578, 196620, 1, 1441800, 262147, 1, 1048578, 262156, 1, 1441800, 327683, 1, 1048584, 327692, 1, 1441794, 393219, 1, 1048584, 393228, 1, 1441794, 458752, 1, 655367, 458753, 1, 655367, 458754, 1, 655367, 458755, 1, 655367, 458764, 1, 1441794, 524285, 1, 655367, 524286, 1, 655367, 524287, 1, 655367, 524300, 1, 1441798, -65533, 1, 1048579, -65532, 1, 1441799, -65531, 1, 1441799, -65530, 1, 1441799, -65529, 1, 1441799, -65528, 1, 1441799, -65527, 1, 1441799, -65526, 1, 1441799, -65525, 1, 1441799, -65524, 1, 1441800, -65507, 1, 3, -65506, 1, 3, -65505, 1, 3, 3, 2, 1048584, 5, 2, 1441797, 6, 2, 655365, 8, 2, 1441801, 9, 2, 655368, 10, 2, 655368, 11, 2, 655368, 12, 2, 1441800, 28, 2, 1048584, 32, 2, 9, 65539, 2, 1048584, 65544, 2, 1441797, 65545, 2, 655366, 65546, 2, 655366, 65547, 2, 655366, 65548, 2, 1441800, 65564, 2, 655369, 65568, 2, 5, 65569, 2, 1048583, 65570, 2, 655365, 131075, 2, 1048578, 131084, 2, 1441800, 131100, 2, 655369, 196611, 2, 1048578, 196620, 2, 1441800, 196632, 2, 655366, 196633, 2, 655366, 196634, 2, 655366, 196635, 2, 655366, 196636, 2, 655365, 262147, 2, 1048578, 262156, 2, 1441800, 327683, 2, 1048584, 327692, 2, 1441794, 393219, 2, 1048584, 393228, 2, 1441794, 458752, 2, 655367, 458753, 2, 655367, 458754, 2, 655367, 458755, 2, 655367, 458764, 2, 1441794, 524285, 2, 655367, 524286, 2, 655367, 524287, 2, 655367, 524300, 2, 1441798, -65533, 2, 1048579, -65532, 2, 1048583, -65531, 2, 1441796, -65530, 2, 655364, -65529, 2, 1441799, -65528, 2, 1441796, -65527, 2, 655363, -65526, 2, 655363, -65525, 2, 655363, -65524, 2, 1441800, -65508, 2, 1048579, -65507, 2, 1441799, -65506, 2, 1441799, -65505, 2, 1441799, -65504, 2, 4, 3, 3, 1048584, 5, 3, 5, 6, 3, 1048581, 8, 3, 9, 9, 3, 8, 10, 3, 8, 11, 3, 8, 12, 3, 1441800, 28, 3, 1048585, 33, 3, 9, 65539, 3, 1048584, 65544, 3, 5, 65545, 3, 6, 65546, 3, 6, 65547, 3, 6, 65548, 3, 1441800, 65564, 3, 1048585, 65569, 3, 5, 65570, 3, 1048583, 65571, 3, 655365, 131075, 3, 1048578, 131084, 3, 1441800, 131100, 3, 1048585, 196611, 3, 1048578, 196620, 3, 1441800, 196632, 3, 655363, 196633, 3, 655363, 196634, 3, 655363, 196635, 3, 655364, 196636, 3, 1048581, 262147, 3, 1048578, 262156, 3, 1441800, 262168, 3, 655366, 262169, 3, 655366, 262170, 3, 655366, 262171, 3, 655365, 327683, 3, 1048584, 327692, 3, 1441794, 393219, 3, 1048584, 393228, 3, 1441794, 458752, 3, 655367, 458753, 3, 655366, 458754, 3, 655366, 458755, 3, 655367, 458764, 3, 1441794, 458771, 3, 1048578, 524284, 3, 655367, 524285, 3, 655367, 524286, 3, 655367, 524287, 3, 655367, 524300, 3, 1441798, -65533, 3, 1048579, -65532, 3, 1048583, -65531, 3, 4, -65530, 3, 1048580, -65529, 3, 1441799, -65528, 3, 4, -65527, 3, 3, -65526, 3, 3, -65525, 3, 3, -65524, 3, 1441800, -65508, 3, 1048580, -65507, 3, 1441799, -65506, 3, 1441799, -65505, 3, 1441799, -65504, 3, 1441799, -65503, 3, 4, 3, 4, 1048584, 12, 4, 1441800, 27, 4, 1048584, 34, 4, 1441800, 65539, 4, 1048584, 65548, 4, 1441800, 65563, 4, 1048584, 65570, 4, 1048583, 65571, 4, 1048582, 131075, 4, 1048578, 131084, 4, 9, 131085, 4, 3, 131086, 4, 3, 131087, 4, 3, 131088, 4, 3, 131089, 4, 3, 131090, 4, 3, 131099, 4, 1048584, 196611, 4, 1048578, 196620, 4, 9, 196621, 4, 8, 196622, 4, 8, 196623, 4, 8, 196624, 4, 8, 196625, 4, 8, 196626, 4, 8, 196635, 4, 1048584, 262147, 4, 1048578, 262156, 4, 1441800, 262168, 4, 655363, 262169, 4, 655363, 262170, 4, 655364, 262171, 4, 1048582, 327680, 4, 8, 327681, 4, 8, 327682, 4, 8, 327683, 4, 1048580, 327691, 4, 1441808, 327692, 4, 9, 327693, 4, 3, 327694, 4, 3, 327695, 4, 3, 327696, 4, 3, 327697, 4, 3, 393216, 4, 8, 393217, 4, 8, 393218, 4, 8, 393219, 4, 1048585, 393228, 4, 9, 393229, 4, 2, 393230, 4, 2, 393231, 4, 2, 393232, 4, 2, 393233, 4, 2, 458752, 4, 6, 458753, 4, 6, 458754, 4, 6, 458755, 4, 1048581, 458764, 4, 1441800, 458771, 4, 1048578, 458774, 4, 1048583, 458775, 4, 1048583, 458776, 4, 1048583, 458777, 4, 1048583, 458778, 4, 1048582, 524284, 4, 655367, 524285, 4, 655367, 524286, 4, 655367, 524287, 4, 1048583, 524300, 4, 1441798, 524307, 4, 1048582, -65533, 4, 1048579, -65532, 4, 7, -65531, 4, 7, -65530, 4, 7, -65529, 4, 7, -65528, 4, 1441799, -65527, 4, 1441799, -65526, 4, 1441799, -65525, 4, 1441799, -65524, 4, 1441800, -65509, 4, 1048579, -65508, 4, 1441799, -65507, 4, 1441799, -65506, 4, 1441799, -65505, 4, 1441799, -65504, 4, 1441799, -65503, 4, 1441799, -65502, 4, 1441795, 3, 5, 1048584, 11, 5, 1441801, 27, 5, 1048584, 34, 5, 9, 65538, 5, 3, 65539, 5, 1048580, 65547, 5, 1441801, 65563, 5, 1048584, 65570, 5, 5, 65571, 5, 1048582, 131074, 5, 2, 131075, 5, 1048585, 131083, 5, 1441797, 131084, 5, 7, 131085, 5, 7, 131086, 5, 7, 131087, 5, 7, 131088, 5, 7, 131089, 5, 7, 131090, 5, 7, 131091, 5, 1441795, 131099, 5, 1048584, 196610, 5, 2, 196611, 5, 1048585, 196627, 5, 1441800, 196635, 5, 1048584, 262146, 5, 2, 262147, 5, 1048585, 262156, 5, 1441806, 262157, 5, 1, 262158, 5, 1, 262159, 5, 1, 262160, 5, 1, 262161, 5, 655361, 262162, 5, 655361, 262170, 5, 1048584, 262171, 5, 1048582, 327680, 5, 655366, 327681, 5, 1441798, 327682, 5, 6, 327683, 5, 1048581, 327692, 5, 1441798, 327693, 5, 7, 327694, 5, 7, 327695, 5, 7, 327696, 5, 7, 327697, 5, 1048583, 327698, 5, 1441795, 393215, 5, 1048584, 393234, 5, 1441794, 458751, 5, 1048584, 458764, 5, 1441806, 458765, 5, 655361, 458766, 5, 655361, 458767, 5, 655361, 458768, 5, 655361, 458769, 5, 655361, 458771, 5, 1048578, 458773, 5, 1048583, 458774, 5, 1048583, 458775, 5, 1048583, 458776, 5, 1048583, 458777, 5, 1048583, 458778, 5, 1048582, 524283, 5, 655367, 524284, 5, 655367, 524285, 5, 655367, 524286, 5, 655367, 524287, 5, 1048582, 524300, 5, 1441798, 524301, 5, 1441799, 524302, 5, 1441799, 524303, 5, 1441799, 524304, 5, 1441799, 524305, 5, 1441799, 524306, 5, 1441799, 524307, 5, 1048582, -65533, 5, 1048579, -65532, 5, 7, -65531, 5, 7, -65530, 5, 7, -65529, 5, 1048583, -65528, 5, 1441799, -65527, 5, 1441799, -65526, 5, 1441799, -65525, 5, 1441801, -65509, 5, 1048579, -65508, 5, 1441799, -65507, 5, 1441799, -65506, 5, 1441799, -65505, 5, 1441799, -65504, 5, 1441799, -65503, 5, 1441799, -65502, 5, 4, 2, 6, 655368, 3, 6, 655368, 4, 6, 655369, 11, 6, 1441794, 27, 6, 1048584, 35, 6, 1441800, 65537, 6, 1048579, 65538, 6, 655366, 65539, 6, 655366, 65540, 6, 655365, 65547, 6, 1441794, 65563, 6, 1048584, 65571, 6, 1441798, 131073, 6, 1048584, 131083, 6, 1441798, 131084, 6, 7, 131085, 6, 7, 131086, 6, 7, 131087, 6, 7, 131088, 6, 7, 131089, 6, 7, 131090, 6, 7, 131091, 6, 1441795, 131099, 6, 1048584, 196609, 6, 1048584, 196627, 6, 1441800, 196635, 6, 1048584, 262145, 6, 1048584, 262156, 6, 1441806, 262157, 6, 1, 262158, 6, 1, 262159, 6, 1, 262160, 6, 1, 262161, 6, 655361, 262162, 6, 655361, 262170, 6, 1048584, 262171, 6, 1048582, 327680, 6, 1441799, 327681, 6, 1048582, 327692, 6, 1441798, 327693, 6, 7, 327694, 6, 7, 327695, 6, 7, 327696, 6, 7, 327697, 6, 1048583, 327698, 6, 1441795, 393215, 6, 1048584, 393234, 6, 1441794, 458751, 6, 1048584, 458764, 6, 1441806, 458765, 6, 655361, 458766, 6, 655361, 458767, 6, 655361, 458768, 6, 655361, 458769, 6, 655361, 458771, 6, 1048578, 458773, 6, 1048583, 458774, 6, 1048583, 458775, 6, 1048583, 458776, 6, 1048583, 458777, 6, 1048583, 458778, 6, 1048582, 524283, 6, 655367, 524284, 6, 655367, 524285, 6, 655367, 524286, 6, 655367, 524287, 6, 1048582, 524300, 6, 1441798, 524301, 6, 1441799, 524302, 6, 1441799, 524303, 6, 1441799, 524304, 6, 1441799, 524305, 6, 1441799, 524306, 6, 1441799, 524307, 6, 1048582, -65534, 6, 655363, -65533, 6, 655363, -65532, 6, 655364, -65531, 6, 655367, -65530, 6, 655367, -65529, 6, 1048583, -65528, 6, 7, -65527, 6, 1441799, -65526, 6, 1441799, -65525, 6, 1441795, -65509, 6, 1048579, -65508, 6, 1441799, -65507, 6, 1441799, -65506, 6, 1441799, -65505, 6, 1441799, -65504, 6, 1441799, -65503, 6, 1441799, -65502, 6, 1441799, -65501, 6, 1441800, 4, 7, 1048584, 6, 7, 11, 11, 7, 9, 27, 7, 1048584, 35, 7, 1441800, 65537, 7, 1048579, 65538, 7, 1441799, 65539, 7, 1441799, 65540, 7, 1048582, 65542, 7, 12, 65547, 7, 9, 65563, 7, 1048584, 65571, 7, 1441798, 131073, 7, 1048584, 131078, 7, 1441804, 131083, 7, 5, 131084, 7, 7, 131085, 7, 1441796, 131086, 7, 655363, 131087, 7, 655363, 131088, 7, 655364, 131089, 7, 7, 131090, 7, 7, 131091, 7, 1441795, 131099, 7, 1048584, 196609, 7, 1048584, 196614, 7, 13, 196621, 7, 1441801, 196622, 7, 655362, 196623, 7, 655362, 196624, 7, 655369, 196627, 7, 1441800, 196635, 7, 1048584, 262145, 7, 1048584, 262156, 7, 1441806, 262157, 7, 1441806, 262158, 7, 1, 262159, 7, 1, 262160, 7, 1, 262161, 7, 655361, 262162, 7, 655361, 262170, 7, 1048584, 262171, 7, 1048582, 327680, 7, 1441799, 327681, 7, 1048582, 327691, 7, 1441809, 327692, 7, 1441801, 327693, 7, 655363, 327694, 7, 655363, 327695, 7, 655363, 327696, 7, 655364, 327697, 7, 1048583, 327698, 7, 1441795, 393215, 7, 1048584, 393228, 7, 1441801, 393229, 7, 655368, 393230, 7, 655368, 393231, 7, 655368, 393232, 7, 655369, 393234, 7, 1441794, 458751, 7, 1048584, 458764, 7, 1441800, 458768, 7, 655361, 458769, 7, 655361, 458771, 7, 1048578, 458774, 7, 1048583, 458775, 7, 1048583, 458776, 7, 1048583, 458777, 7, 1048583, 458778, 7, 1048582, 524282, 7, 655367, 524283, 7, 655367, 524284, 7, 655367, 524285, 7, 655367, 524286, 7, 655367, 524287, 7, 1048582, 524300, 7, 1441798, 524301, 7, 1441799, 524302, 7, 1441799, 524303, 7, 1441799, 524304, 7, 1441799, 524305, 7, 1441799, 524306, 7, 1441799, 524307, 7, 1048582, -65532, 7, 1048579, -65531, 7, 1048583, -65530, 7, 10, -65529, 7, 1441799, -65528, 7, 1441799, -65527, 7, 1441799, -65526, 7, 1441799, -65525, 7, 4, -65509, 7, 1048579, -65508, 7, 1441799, -65507, 7, 1441799, -65506, 7, 1441799, -65505, 7, 1441799, -65504, 7, 1441799, -65503, 7, 1441799, -65502, 7, 1441799, -65501, 7, 1441800, 2, 8, 3, 3, 8, 3, 4, 8, 1048585, 12, 8, 1441800, 27, 8, 1048584, 35, 8, 1441800, 65537, 8, 1048579, 65538, 8, 6, 65539, 8, 6, 65540, 8, 1048581, 65548, 8, 1441800, 65563, 8, 1048584, 65571, 8, 1441798, 65572, 8, 655366, 65573, 8, 655366, 65574, 8, 655366, 65575, 8, 655366, 65576, 8, 655366, 65577, 8, 655365, 131073, 8, 1048584, 131084, 8, 1441796, 131088, 8, 1048579, 131089, 8, 7, 131090, 8, 7, 131091, 8, 1441795, 131099, 8, 1048584, 196609, 8, 1048584, 196620, 8, 1441801, 196624, 8, 1048584, 196627, 8, 1441800, 196635, 8, 1048584, 262145, 8, 1048584, 262156, 8, 1441800, 262161, 8, 655361, 262162, 8, 655361, 262170, 8, 1048584, 262171, 8, 1048582, 327680, 8, 1441799, 327681, 8, 1048581, 327692, 8, 1441800, 327695, 8, 3, 327696, 8, 1048580, 327697, 8, 1048583, 327698, 8, 1441795, 393215, 8, 1048584, 393228, 8, 1441800, 393231, 8, 8, 393232, 8, 1048585, 393234, 8, 1441794, 458751, 8, 1048584, 458764, 8, 9, 458769, 8, 655361, 458771, 8, 1048578, 458774, 8, 1048583, 458775, 8, 1048583, 458776, 8, 1048583, 458777, 8, 1048583, 458778, 8, 1048582, 524282, 8, 655367, 524283, 8, 655367, 524284, 8, 655367, 524285, 8, 655367, 524286, 8, 655367, 524287, 8, 1048582, 524300, 8, 5, 524301, 8, 1441799, 524302, 8, 1441799, 524303, 8, 1441799, 524304, 8, 1441799, 524305, 8, 1441799, 524306, 8, 1441799, 524307, 8, 1048582, -65534, 8, 3, -65533, 8, 3, -65532, 8, 1048580, -65531, 8, 655367, -65530, 8, 655367, -65529, 8, 655367, -65528, 8, 1441799, -65527, 8, 1441799, -65526, 8, 1441799, -65525, 8, 655367, -65524, 8, 1441800, -65509, 8, 1048579, -65508, 8, 1441799, -65507, 8, 1441799, -65506, 8, 1441799, -65505, 8, 1441799, -65504, 8, 1441799, -65503, 8, 1441799, -65502, 8, 1441799, -65501, 8, 1441800, 1, 9, 1048578, 2, 9, 5, 3, 9, 1048581, 8, 9, 11, 12, 9, 1441800, 27, 9, 1048584, 35, 9, 1441800, 65537, 9, 1048578, 65544, 9, 12, 65548, 9, 1441800, 65563, 9, 1048584, 65570, 9, 1441809, 65571, 9, 1441801, 65572, 9, 655363, 65573, 9, 655363, 65574, 9, 655363, 65575, 9, 655363, 65576, 9, 655363, 131073, 9, 1048578, 131080, 9, 1048588, 131084, 9, 1441800, 131088, 9, 1048579, 131089, 9, 7, 131090, 9, 7, 131091, 9, 1441795, 131099, 9, 1048584, 131107, 9, 1441797, 131108, 9, 655366, 131109, 9, 655366, 131110, 9, 655366, 131111, 9, 655366, 131112, 9, 655366, 131113, 9, 655365, 196609, 9, 1048578, 196616, 9, 1048588, 196620, 9, 1441800, 196624, 9, 1048584, 196627, 9, 1441800, 196635, 9, 1048584, 262145, 9, 1048578, 262152, 9, 1048589, 262156, 9, 1441800, 262161, 9, 655361, 262162, 9, 655361, 262169, 9, 3, 262170, 9, 1048580, 262171, 9, 1048582, 327680, 9, 655368, 327681, 9, 655369, 327682, 9, 1048592, 327692, 9, 1441800, 327694, 9, 1048579, 327695, 9, 1441799, 327696, 9, 1441799, 327697, 9, 1441799, 327698, 9, 1441795, 327705, 9, 8, 327706, 9, 1048585, 393216, 9, 655368, 393217, 9, 655369, 393228, 9, 1441800, 393230, 9, 1048584, 393234, 9, 1441794, 393241, 9, 8, 393242, 9, 1048585, 458752, 9, 655366, 458753, 9, 655365, 458764, 9, 1441798, 458765, 9, 1441795, 458767, 9, 655361, 458768, 9, 655361, 458769, 9, 655361, 458771, 9, 1048578, 458774, 9, 1048583, 458775, 9, 1048583, 458776, 9, 1048583, 458777, 9, 6, 458778, 9, 1048581, 524282, 9, 655367, 524283, 9, 655367, 524284, 9, 655367, 524285, 9, 655367, 524286, 9, 655367, 524287, 9, 655367, 524301, 9, 1441798, 524302, 9, 1441799, 524303, 9, 1441799, 524304, 9, 1441799, 524305, 9, 1441799, 524306, 9, 1441799, 524307, 9, 1048582, -65535, 9, 1048584, -65534, 9, 4, -65533, 9, 1048580, -65532, 9, 7, -65531, 9, 7, -65530, 9, 7, -65529, 9, 7, -65528, 9, 10, -65527, 9, 1441799, -65526, 9, 1441799, -65525, 9, 655367, -65524, 9, 1441800, -65509, 9, 1048579, -65508, 9, 1441799, -65507, 9, 1441799, -65506, 9, 1441799, -65505, 9, 1441799, -65504, 9, 1441799, -65503, 9, 1441799, -65502, 9, 1441799, -65501, 9, 1441800, 1, 10, 1048578, 12, 10, 1441800, 26, 10, 8, 27, 10, 1048585, 35, 10, 1441800, 65537, 10, 1048578, 65548, 10, 1441800, 65561, 10, 3, 65562, 10, 3, 65563, 10, 1048585, 65571, 10, 1441800, 131073, 10, 1048578, 131084, 10, 1441800, 131088, 10, 1048580, 131089, 10, 1048583, 131090, 10, 1048583, 131091, 10, 4, 131097, 10, 8, 131098, 10, 8, 131099, 10, 1048585, 131106, 10, 1441809, 131107, 10, 1441801, 131108, 10, 655363, 131109, 10, 655363, 131110, 10, 655363, 131111, 10, 655363, 131112, 10, 655364, 131113, 10, 1048582, 196609, 10, 1048578, 196620, 10, 1441800, 196624, 10, 1048585, 196627, 10, 9, 196633, 10, 8, 196634, 10, 8, 196635, 10, 1048585, 196643, 10, 1441797, 196644, 10, 655366, 196645, 10, 655366, 196646, 10, 655366, 196647, 10, 655366, 196648, 10, 655366, 196649, 10, 655365, 262145, 10, 1048578, 262156, 10, 1441800, 262161, 10, 1, 262162, 10, 1, 262168, 10, 1048579, 262169, 10, 6, 262170, 10, 6, 262171, 10, 1048581, 327681, 10, 1048578, 327685, 10, 655377, 327689, 10, 655376, 327692, 10, 1441800, 327694, 10, 1048579, 327695, 10, 1441799, 327696, 10, 1441796, 327697, 10, 655363, 327704, 10, 1048584, 393217, 10, 1048584, 393228, 10, 1441800, 393230, 10, 1048584, 393232, 10, 1441801, 393233, 10, 655362, 393240, 10, 1048584, 458752, 10, 6, 458753, 10, 1048582, 458764, 10, 1441798, 458765, 10, 4, 458766, 10, 3, 458767, 10, 14, 458768, 10, 3, 458769, 10, 8, 458770, 10, 8, 458771, 10, 1048585, 458774, 10, 1048583, 458775, 10, 1048583, 458776, 10, 1048582, 524282, 10, 655367, 524283, 10, 655367, 524284, 10, 655367, 524285, 10, 655367, 524286, 10, 655367, 524287, 10, 655367, 524301, 10, 5, 524302, 10, 6, 524303, 10, 6, 524304, 10, 6, 524305, 10, 6, 524306, 10, 6, 524307, 10, 1048581, -65535, 10, 1048584, -65534, 10, 1048583, -65533, 10, 7, -65532, 10, 7, -65531, 10, 7, -65530, 10, 7, -65529, 10, 7, -65528, 10, 655367, -65527, 10, 655367, -65526, 10, 655367, -65525, 10, 655367, -65524, 10, 1441800, -65511, 10, 3, -65510, 10, 3, -65509, 10, 1048580, -65508, 10, 7, -65507, 10, 7, -65506, 10, 7, -65505, 10, 7, -65504, 10, 7, -65503, 10, 7, -65502, 10, 1441799, -65501, 10, 1441795, 2, 11, 655368, 3, 11, 655368, 4, 11, 655368, 5, 11, 655368, 6, 11, 655368, 7, 11, 655368, 8, 11, 655368, 9, 11, 655368, 10, 11, 655368, 11, 11, 655368, 21, 11, 8, 22, 11, 8, 23, 11, 8, 24, 11, 1048585, 25, 11, 1441801, 26, 11, 655369, 35, 11, 1441800, 65538, 11, 655368, 65539, 11, 655368, 65540, 11, 655368, 65541, 11, 655368, 65542, 11, 655368, 65543, 11, 655368, 65544, 11, 655368, 65545, 11, 655368, 65546, 11, 655368, 65547, 11, 655368, 65549, 11, 8, 65550, 11, 8, 65551, 11, 8, 65552, 11, 8, 65553, 11, 8, 65554, 11, 8, 65555, 11, 8, 65556, 11, 8, 65557, 11, 8, 65558, 11, 8, 65559, 11, 8, 65560, 11, 1048585, 65561, 11, 1441797, 65562, 11, 655365, 65571, 11, 1441800, 131074, 11, 655368, 131075, 11, 655368, 131076, 11, 655368, 131077, 11, 655368, 131078, 11, 655368, 131079, 11, 655368, 131080, 11, 655368, 131081, 11, 655368, 131082, 11, 655368, 131083, 11, 655368, 131085, 11, 8, 131086, 11, 8, 131087, 11, 1048585, 131088, 11, 6, 131089, 11, 6, 131090, 11, 6, 131091, 11, 6, 131092, 11, 9, 131093, 11, 8, 131094, 11, 8, 131095, 11, 8, 131096, 11, 1048585, 131107, 11, 1441800, 196610, 11, 655368, 196611, 11, 655368, 196612, 11, 655368, 196613, 11, 655368, 196614, 11, 655368, 196615, 11, 655368, 196616, 11, 655368, 196617, 11, 655368, 196618, 11, 655368, 196619, 11, 655368, 196621, 11, 8, 196622, 11, 8, 196623, 11, 1048585, 196628, 11, 9, 196629, 11, 8, 196630, 11, 8, 196631, 11, 8, 196632, 11, 1048585, 196642, 11, 1441809, 196643, 11, 1441801, 196644, 11, 655363, 196645, 11, 655363, 196646, 11, 655363, 196647, 11, 655363, 196648, 11, 655364, 196649, 11, 1048582, 262146, 11, 655368, 262147, 11, 655368, 262148, 11, 655368, 262149, 11, 655368, 262150, 11, 655368, 262151, 11, 655368, 262152, 11, 655368, 262153, 11, 655368, 262154, 11, 655368, 262155, 11, 655368, 262157, 11, 8, 262158, 11, 8, 262159, 11, 8, 262160, 11, 14, 262161, 11, 14, 262162, 11, 14, 262163, 11, 14, 262164, 11, 8, 262165, 11, 8, 262166, 11, 8, 262167, 11, 8, 262168, 11, 1048585, 262179, 11, 1441797, 262180, 11, 655366, 262181, 11, 655366, 262182, 11, 655366, 262183, 11, 655366, 262184, 11, 655366, 262185, 11, 655365, 327682, 11, 655362, 327683, 11, 655362, 327684, 11, 655362, 327685, 11, 655369, 327686, 11, 655366, 327687, 11, 655366, 327688, 11, 655366, 327689, 11, 1441801, 327690, 11, 655368, 327691, 11, 655368, 327693, 11, 8, 327694, 11, 1048585, 327695, 11, 6, 327696, 11, 9, 327697, 11, 8, 327698, 11, 8, 327699, 11, 8, 327700, 11, 8, 327701, 11, 8, 327702, 11, 8, 327703, 11, 8, 327704, 11, 1048585, 393218, 11, 655362, 393219, 11, 655362, 393220, 11, 655362, 393221, 11, 655369, 393225, 11, 1441801, 393226, 11, 655368, 393227, 11, 655368, 393229, 11, 8, 393230, 11, 1048585, 393232, 11, 9, 393233, 11, 2, 393234, 11, 2, 393235, 11, 2, 393236, 11, 2, 393237, 11, 8, 393238, 11, 8, 393239, 11, 8, 393240, 11, 1048585, 458752, 11, 655367, 458753, 11, 655367, 458754, 11, 655366, 458755, 11, 655366, 458756, 11, 655366, 458757, 11, 655366, 458761, 11, 1441797, 458762, 11, 655366, 458763, 11, 655366, 458764, 11, 1441799, 458765, 11, 6, 458766, 11, 1048581, 458768, 11, 5, 458769, 11, 6, 458770, 11, 6, 458771, 11, 6, 458772, 11, 6, 458773, 11, 6, 458774, 11, 6, 458775, 11, 6, 458776, 11, 1048581, 524282, 11, 655367, 524283, 11, 655367, 524284, 11, 655367, 524285, 11, 655367, 524286, 11, 655367, 524287, 11, 655367, -65534, 11, 655363, -65533, 11, 655363, -65532, 11, 655363, -65531, 11, 655363, -65530, 11, 655363, -65529, 11, 655363, -65528, 11, 655363, -65527, 11, 655363, -65526, 11, 655363, -65525, 11, 655363, -65512, 11, 1048580, -65511, 11, 1441796, -65510, 11, 655364, -65509, 11, 7, -65508, 11, 7, -65507, 11, 7, -65506, 11, 7, -65505, 11, 7, -65504, 11, 7, -65503, 11, 7, -65502, 11, 7, -65501, 11, 1441795, 21, 12, 15, 23, 12, 1048582, 25, 12, 9, 26, 12, 1048585, 35, 12, 1441800, 65548, 12, 1048584, 65549, 12, 1048583, 65550, 12, 1048583, 65551, 12, 1048583, 65552, 12, 1048583, 65553, 12, 1048583, 65554, 12, 1048583, 65555, 12, 1048583, 65556, 12, 1048583, 65561, 12, 5, 65562, 12, 1048581, 65571, 12, 1441800, 131084, 12, 1048584, 131087, 12, 16, 131092, 12, 17, 131107, 12, 1441800, 196620, 12, 1048584, 196643, 12, 1441800, 262156, 12, 1048584, 262178, 12, 1441809, 262179, 12, 1441801, 262180, 12, 655363, 262181, 12, 655363, 262182, 12, 655363, 262183, 12, 655363, 262184, 12, 655364, 262185, 12, 1048582, 327686, 12, 655363, 327687, 12, 655363, 327688, 12, 655363, 327692, 12, 1048584, 327694, 12, 16, 327696, 12, 17, 327715, 12, 1441797, 327716, 12, 655366, 327717, 12, 655366, 327718, 12, 655366, 327719, 12, 655366, 327720, 12, 655365, 393222, 12, 655368, 393223, 12, 655368, 393224, 12, 655368, 393228, 12, 1048584, 458752, 12, 655367, 458753, 12, 655367, 458754, 12, 655367, 458755, 12, 655367, 458756, 12, 655367, 458757, 12, 655367, 458758, 12, 655366, 458759, 12, 655366, 458760, 12, 655366, 458761, 12, 1441799, 458762, 12, 1441799, 458763, 12, 1441799, 458764, 12, 655366, 524282, 12, 655367, 524283, 12, 655367, 524284, 12, 655367, 524285, 12, 655367, 524286, 12, 655367, 524287, 12, 655367, -65513, 12, 1048579, -65512, 12, 7, -65511, 12, 4, -65510, 12, 1048580, -65509, 12, 7, -65508, 12, 7, -65507, 12, 7, -65506, 12, 7, -65505, 12, 7, -65504, 12, 7, -65503, 12, 7, -65502, 12, 7, -65501, 12, 1441795, 21, 13, 15, 23, 13, 1048582, 28, 13, 1441801, 29, 13, 655369, 35, 13, 1441800, 65548, 13, 1048584, 65549, 13, 1048583, 65550, 13, 1048583, 65551, 13, 1048583, 65552, 13, 1048583, 65553, 13, 1048583, 65554, 13, 1048583, 65555, 13, 1048583, 65556, 13, 1048583, 65564, 13, 1441801, 65565, 13, 655369, 65571, 13, 1441800, 131084, 13, 1048584, 131100, 13, 1441797, 131101, 13, 655365, 131107, 13, 1441800, 196620, 13, 1048584, 196643, 13, 1441800, 262156, 13, 1048584, 262179, 13, 1441800, 327692, 13, 1048584, 327715, 13, 1441798, 393228, 13, 1048584, 458752, 13, 655367, 458753, 13, 655367, 458754, 13, 655367, 458755, 13, 655367, 458756, 13, 655367, 458757, 13, 655367, 458758, 13, 655367, 458759, 13, 655367, 458760, 13, 655367, 458761, 13, 655367, 458762, 13, 1441799, 458763, 13, 1441799, 458764, 13, 655366, 524282, 13, 655367, 524283, 13, 655367, 524284, 13, 655367, 524285, 13, 655367, 524286, 13, 655367, 524287, 13, 655367, -65513, 13, 1048579, -65512, 13, 7, -65511, 13, 7, -65510, 13, 7, -65509, 13, 7, -65508, 13, 1441796, -65507, 13, 655364, -65506, 13, 7, -65505, 13, 7, -65504, 13, 7, -65503, 13, 7, -65502, 13, 7, -65501, 13, 1441795, 21, 14, 15, 23, 14, 1048582, 28, 14, 9, 29, 14, 1048585, 35, 14, 1441800, 65548, 14, 1048584, 65549, 14, 1048583, 65550, 14, 1048583, 65551, 14, 1048583, 65552, 14, 1048583, 65553, 14, 655373, 65554, 14, 655373, 65555, 14, 1048583, 65556, 14, 1048583, 65564, 14, 9, 65565, 14, 1048585, 65571, 14, 1441800, 131084, 14, 1048584, 131090, 14, 655373, 131100, 14, 5, 131101, 14, 1048581, 131107, 14, 1441800, 196620, 14, 1048584, 196643, 14, 1441800, 262156, 14, 1048584, 262179, 14, 1441800, 327692, 14, 1048584, 327715, 14, 1441798, 393228, 14, 1048584, 458752, 14, 655367, 458753, 14, 655367, 458754, 14, 655367, 458755, 14, 655367, 458756, 14, 655367, 458757, 14, 655367, 458758, 14, 655367, 458759, 14, 655367, 458760, 14, 655367, 458761, 14, 655367, 458762, 14, 1441799, 458763, 14, 1441799, 458764, 14, 655366, 524282, 14, 655367, 524283, 14, 655367, 524284, 14, 655367, 524285, 14, 655367, 524286, 14, 655367, 524287, 14, 655367, -65513, 14, 1048579, -65512, 14, 7, -65511, 14, 7, -65510, 14, 7, -65509, 14, 7, -65508, 14, 4, -65507, 14, 1048580, -65506, 14, 7, -65505, 14, 7, -65504, 14, 7, -65503, 14, 7, -65502, 14, 7, -65501, 14, 1441795, 21, 15, 655368, 22, 15, 655368, 23, 15, 655368, 24, 15, 655369, 31, 15, 1441801, 32, 15, 655369, 35, 15, 1441800, 65548, 15, 1048584, 65549, 15, 655368, 65550, 15, 655368, 65551, 15, 655368, 65552, 15, 655368, 65553, 15, 655368, 65554, 15, 655368, 65555, 15, 655368, 65556, 15, 655368, 65557, 15, 655368, 65558, 15, 655368, 65559, 15, 655368, 65560, 15, 655369, 65567, 15, 1441801, 65568, 15, 655369, 65571, 15, 1441800, 131084, 15, 1048584, 131085, 15, 655368, 131086, 15, 655368, 131087, 15, 655368, 131088, 15, 655368, 131089, 15, 655368, 131090, 15, 655368, 131091, 15, 655368, 131092, 15, 655368, 131093, 15, 655368, 131094, 15, 655368, 131095, 15, 655368, 131096, 15, 655369, 131103, 15, 1441801, 131104, 15, 655369, 131107, 15, 1441800, 196620, 15, 1048584, 196621, 15, 655368, 196622, 15, 655368, 196623, 15, 655368, 196624, 15, 655368, 196625, 15, 655368, 196626, 15, 655368, 196627, 15, 655368, 196628, 15, 655368, 196629, 15, 655368, 196630, 15, 655368, 196631, 15, 655368, 196632, 15, 655369, 196639, 15, 1441797, 196640, 15, 655365, 196643, 15, 1441800, 262156, 15, 1048584, 262158, 15, 655368, 262159, 15, 655368, 262160, 15, 655368, 262161, 15, 655368, 262162, 15, 655368, 262163, 15, 655368, 262164, 15, 655368, 262165, 15, 655368, 262166, 15, 655368, 262167, 15, 655368, 262168, 15, 655369, 262179, 15, 1441800, 327692, 15, 1048584, 327693, 15, 655368, 327694, 15, 655368, 327695, 15, 655368, 327696, 15, 655368, 327697, 15, 655368, 327698, 15, 655368, 327699, 15, 655368, 327700, 15, 655366, 327701, 15, 655366, 327702, 15, 655366, 327703, 15, 655366, 327704, 15, 655365, 327715, 15, 1441798, 393228, 15, 1048584, 393229, 15, 655368, 393230, 15, 655368, 393231, 15, 655368, 393232, 15, 655368, 393233, 15, 655368, 393234, 15, 655368, 393235, 15, 655368, 458752, 15, 655367, 458753, 15, 655367, 458754, 15, 655367, 458755, 15, 655367, 458756, 15, 655367, 458757, 15, 655367, 458758, 15, 655367, 458759, 15, 655367, 458760, 15, 655367, 458761, 15, 655367, 458762, 15, 1441799, 458763, 15, 1441799, 458764, 15, 655366, 458765, 15, 655366, 458766, 15, 655366, 458767, 15, 655366, 458768, 15, 655366, 458769, 15, 655366, 458770, 15, 655366, 458771, 15, 655366, 524282, 15, 655367, 524284, 15, 655367, 524285, 15, 655367, 524286, 15, 655367, 524287, 15, 655367, -65512, 15, 655364, -65511, 15, 7, -65510, 15, 7, -65509, 15, 7, -65508, 15, 7, -65507, 15, 7, -65506, 15, 7, -65505, 15, 1441796, -65504, 15, 655364, -65503, 15, 7, -65502, 15, 7, -65501, 15, 1441795, 25, 16, 655369, 31, 16, 9, 32, 16, 1048585, 34, 16, 1441801, 65548, 16, 1048584, 65561, 16, 655369, 65567, 16, 9, 65568, 16, 1048585, 65570, 16, 1441801, 131084, 16, 1048584, 131097, 16, 655369, 131103, 16, 9, 131104, 16, 1048585, 131106, 16, 1441801, 196620, 16, 1048584, 196633, 16, 655369, 196639, 16, 5, 196640, 16, 1048581, 196642, 16, 1441801, 262156, 16, 1048584, 262169, 16, 655369, 262178, 16, 1441801, 327692, 16, 1048584, 327705, 16, 655365, 327714, 16, 1441797, 393228, 16, 1048584, 458752, 16, 655367, 458753, 16, 655367, 458754, 16, 655367, 458755, 16, 655367, 458756, 16, 655367, 458757, 16, 655367, 458758, 16, 655367, 458759, 16, 655367, 458760, 16, 655367, 458761, 16, 655367, 458762, 16, 1441799, 458763, 16, 1441799, 458764, 16, 655366, 524282, 16, 655367, 524284, 16, 655367, 524285, 16, 655367, 524286, 16, 655367, 524287, 16, 655367, -65511, 16, 655364, -65510, 16, 7, -65509, 16, 7, -65508, 16, 7, -65507, 16, 7, -65506, 16, 7, -65505, 16, 4, -65504, 16, 1048580, -65503, 16, 7, -65502, 16, 1441796, 25, 17, 1048584, 34, 17, 1441800, 65548, 17, 1048584, 65561, 17, 1048584, 65570, 17, 1441800, 131084, 17, 1048584, 131097, 17, 1048584, 131106, 17, 1441800, 196633, 17, 1048584, 196642, 17, 1441800, 262169, 17, 1048584, 262174, 17, 655377, 262177, 17, 655376, 262178, 17, 1441800, 327705, 17, 1048582, 327714, 17, 1441798, 458752, 17, 655367, 458753, 17, 655367, 458754, 17, 655367, 458755, 17, 655367, 458756, 17, 655367, 458757, 17, 655367, 458758, 17, 655367, 458759, 17, 655367, 458760, 17, 655367, 458761, 17, 655367, 458762, 17, 1441799, 458763, 17, 1441799, 458764, 17, 1441799, 524282, 17, 655367, 524283, 17, 655367, 524284, 17, 655367, 524285, 17, 655367, 524286, 17, 655367, 524287, 17, 655367, -65511, 17, 1048579, -65510, 17, 7, -65509, 17, 7, -65508, 17, 7, -65507, 17, 7, -65506, 17, 7, -65505, 17, 7, -65504, 17, 7, -65503, 17, 7, -65502, 17, 1441795, 26, 18, 655368, 27, 18, 655368, 28, 18, 655368, 29, 18, 655368, 30, 18, 655368, 31, 18, 655368, 32, 18, 655368, 33, 18, 655368, 65562, 18, 655368, 65563, 18, 655368, 65564, 18, 655368, 65565, 18, 655368, 65566, 18, 655368, 65567, 18, 655368, 65568, 18, 655368, 65569, 18, 655368, 131098, 18, 655368, 131099, 18, 655368, 131100, 18, 655368, 131101, 18, 655368, 131102, 18, 655368, 131103, 18, 655368, 131104, 18, 655368, 131105, 18, 655368, 196634, 18, 655368, 196635, 18, 655368, 196636, 18, 655368, 196637, 18, 655368, 196638, 18, 655368, 196639, 18, 655368, 196640, 18, 655368, 196641, 18, 655368, 262170, 18, 655368, 262171, 18, 655368, 262172, 18, 655368, 262173, 18, 655368, 262174, 18, 655369, 262175, 18, 655366, 262176, 18, 655366, 262177, 18, 1441801, 327706, 18, 655366, 327707, 18, 655366, 327708, 18, 655366, 327709, 18, 655366, 327710, 18, 655366, 327713, 18, 1441797, 458752, 18, 655367, 458753, 18, 655367, 458754, 18, 655367, 458755, 18, 655367, 458756, 18, 655367, 458757, 18, 655367, 458758, 18, 655367, 458759, 18, 655367, 458760, 18, 655367, 458762, 18, 1441799, 458763, 18, 1441799, 458764, 18, 1441799, 524283, 18, 655367, 524284, 18, 655367, 524285, 18, 655367, 524286, 18, 655367, 524287, 18, 655367, -65510, 18, 655363, -65509, 18, 655363, -65508, 18, 655363, -65507, 18, 655363, -65506, 18, 655363, -65505, 18, 655363, -65504, 18, 655363, -65503, 18, 655363, 524287, 19, 655367, 65540, 65533, 3, 131076, 65533, 2, 131077, 65533, 3, 196611, 65533, 1048579, 196612, 65533, 6, 196613, 65533, 6, 196614, 65533, 655366, 196615, 65533, 655366, 196616, 65533, 655366, 196617, 65533, 655366, 196618, 65533, 7, 196619, 65533, 655366, 196620, 65533, 1441801, 262147, 65533, 1048578, 262156, 65533, 1441801, 327683, 65533, 1048584, 327692, 65533, 1441801, 393219, 65533, 1048584, 393228, 65533, 1441801, 458764, 65533, 1441801, 524300, 65533, 1441797, 65539, 65534, 1048579, 65540, 65534, 1048583, 65541, 65534, 4, 131075, 65534, 1048578, 131077, 65534, 5, 131078, 65534, 4, 196611, 65534, 1048578, 196614, 65534, 5, 196615, 65534, 7, 196616, 65534, 655370, 196617, 65534, 7, 196618, 65534, 7, 196619, 65534, 7, 196620, 65534, 1441800, 262147, 65534, 1048578, 262152, 65534, 655372, 262156, 65534, 1441800, 327683, 65534, 1048584, 327688, 65534, 655373, 327692, 65534, 1441794, 393219, 65534, 1048584, 393228, 65534, 1441794, 458753, 65534, 655367, 458754, 65534, 655367, 458764, 65534, 1441794, 524300, 65534, 1441798, 4, 65535, 2, 5, 65535, 2, 6, 65535, 2, 7, 65535, 2, 8, 65535, 2, 9, 65535, 2, 10, 65535, 2, 11, 65535, 2, 65539, 65535, 1048579, 65540, 65535, 5, 65541, 65535, 1048581, 65542, 65535, 4, 65543, 65535, 2, 65544, 65535, 2, 65545, 65535, 2, 65546, 65535, 2, 65547, 65535, 2, 131075, 65535, 1048578, 131078, 65535, 5, 131079, 65535, 9, 131080, 65535, 2, 131081, 65535, 2, 131082, 65535, 2, 131083, 65535, 2, 196611, 65535, 1048578, 196615, 65535, 5, 196616, 65535, 6, 196617, 65535, 6, 196618, 65535, 6, 196619, 65535, 6, 196620, 65535, 1441800, 262147, 65535, 1048578, 262156, 65535, 1441800, 327683, 65535, 1048584, 327692, 65535, 1441794, 393219, 65535, 1048584, 393228, 65535, 1441794, 458752, 65535, 655367, 458753, 65535, 655367, 458754, 65535, 655367, 458755, 65535, 655367, 458764, 65535, 1441794, 524287, 65535, 655367, 524300, 65535, 1441798, -65532, 65535, 2, -65531, 65535, 2, -65530, 65535, 2, -65529, 65535, 2, -65528, 65535, 2, -65527, 65535, 2, -65526, 65535, 2, -65525, 65535, 2 </int_array>
- </dictionary>
- <dictionary shared="false">
- <string> "_editor_clip_" </string>
- <int> 0 </int>
- <string> "_editor_floor_" </string>
- <vector3> 0, 2, 0 </vector3>
- </dictionary>
- <transform> 0.522923, 0.663002, -0.535706, -0.24539, 0.718971, 0.650281, 0.816294, -0.20859, 0.53866, 0, 0, 0 </transform>
- <int> 1 </int>
- <int> 0 </int>
- <real> 1.5 </real>
- <color> 1, 1, 1, 1 </color>
- <real> 0 </real>
- <real> 0.08 </real>
- <real> 0.5 </real>
- <real> 60 </real>
- <real> 1 </real>
- <resource name=""></resource> <int> 2 </int>
- <real> 40 </real>
- <real> 0.410558 </real>
- <resource resource_type="Environment" path="local://1"> </resource>
- <dictionary shared="false">
- <string> "_editor_collapsed" </string>
- <bool> True </bool>
- </dictionary>
- <resource resource_type="PackedScene" path="res://coin.scn"> </resource>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 18.5311, 2.85075, 5.24675 </transform>
- <dictionary shared="false">
- <string> "__editor_plugin_states__" </string>
- <dictionary shared="false">
- <string> "Script" </string>
- <dictionary shared="false">
- <string> "current" </string>
- <int> 0 </int>
- <string> "sources" </string>
- <array len="1" shared="false">
- <string> "res://coin.gd" </string>
- </array>
- </dictionary>
- <string> "2D" </string>
- <dictionary shared="false">
- <string> "zoom" </string>
- <real> 1 </real>
- <string> "ofs" </string>
- <vector2> 1, 1 </vector2>
- </dictionary>
- <string> "3D" </string>
- <dictionary shared="false">
- <string> "fov" </string>
- <real> 400 </real>
- <string> "zfar" </string>
- <real> 500 </real>
- <string> "viewports" </string>
- <array len="4" shared="false">
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 1.361845 </real>
- <string> "x_rot" </string>
- <real> 0.0125 </real>
- <string> "y_rot" </string>
- <real> 12.050008 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> -0.00892573, 0.51052, -0.216081 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- </array>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "znear" </string>
- <real> 0.1 </real>
- <string> "show_origin" </string>
- <bool> True </bool>
- </dictionary>
- </dictionary>
- <string> "__editor_run_settings__" </string>
- <dictionary shared="false">
- <string> "custom_args" </string>
- <string> "-l $scene" </string>
- <string> "run_mode" </string>
- <int> 0 </int>
- </dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "3D" </string>
- </dictionary>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 18.5311, 2.85075, 7.24675 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 20.5311, 2.85075, 5.24675 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 20.5311, 2.85075, 7.24675 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 1.61344, 11.28, 11.0239 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 1.61344, 11.28, 13.0239 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 3.61344, 11.28, 11.0239 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 3.61344, 11.28, 13.0239 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 1.61344, 12.9027, 11.03 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 1.61344, 12.9027, 13.03 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 3.61344, 12.9027, 13.03 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 3.61344, 12.9027, 11.03 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 1.61344, 11.28, 15.0922 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 1.61344, 11.28, 17.0922 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 3.61344, 11.28, 17.0922 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 3.61344, 11.28, 15.0922 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 3.61344, 12.9027, 15.0983 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 3.61344, 12.9027, 17.0983 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 1.61344, 12.9027, 15.0983 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 1.61344, 12.9027, 17.0983 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 57.057, 4.14271, 26.9338 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 57.057, 4.14271, 28.9338 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 57.057, 5.76534, 26.9399 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 59.057, 5.76534, 28.9399 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 59.057, 5.76534, 26.9399 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 59.057, 4.14271, 28.9338 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 59.057, 4.14271, 26.9338 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 57.057, 5.76534, 28.9399 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 62.9108, 6.16547, 31.0899 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 64.9108, 7.7881, 31.096 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 62.9108, 6.16547, 33.0899 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 62.9108, 7.7881, 31.096 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 64.9108, 7.7881, 33.096 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 64.9108, 6.16547, 31.0899 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 64.9108, 6.16547, 33.0899 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 62.9108, 7.7881, 33.096 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 51.5614, 2.98252, 23.1775 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 53.5614, 4.60515, 23.1836 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 51.5614, 2.98252, 25.1775 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 53.5614, 2.98252, 23.1775 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 53.5614, 4.60515, 25.1836 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 51.5614, 4.60515, 23.1836 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 53.5614, 2.98252, 25.1775 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 51.5614, 4.60515, 25.1836 </transform>
- <resource resource_type="PackedScene" path="res://enemy.scn"> </resource>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 18.3062, 5.40827, 5.96938 </transform>
- <dictionary shared="false">
- <string> "__editor_plugin_states__" </string>
- <dictionary shared="false">
- <string> "Script" </string>
- <dictionary shared="false">
- <string> "current" </string>
- <int> 0 </int>
- <string> "sources" </string>
- <array len="2" shared="false">
- <string> "res://enemy.gd" </string>
- <string> "res://player.gd" </string>
- </array>
- </dictionary>
- <string> "2D" </string>
- <dictionary shared="false">
- <string> "zoom" </string>
- <real> 1 </real>
- <string> "ofs" </string>
- <vector2> 1, 1 </vector2>
- </dictionary>
- <string> "3D" </string>
- <dictionary shared="false">
- <string> "fov" </string>
- <real> 400 </real>
- <string> "zfar" </string>
- <real> 500 </real>
- <string> "viewports" </string>
- <array len="4" shared="false">
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 7.403724 </real>
- <string> "x_rot" </string>
- <real> 0.25 </real>
- <string> "y_rot" </string>
- <real> 3.312502 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0.898236, 0.953557, 0.742913 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- </array>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "znear" </string>
- <real> 0.1 </real>
- <string> "show_origin" </string>
- <bool> True </bool>
- </dictionary>
- </dictionary>
- <string> "__editor_run_settings__" </string>
- <dictionary shared="false">
- <string> "custom_args" </string>
- <string> "-l $scene" </string>
- <string> "run_mode" </string>
- <int> 0 </int>
- </dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "Script" </string>
- </dictionary>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 64.1292, 5.40827, 17.1396 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 64.1292, 5.40827, 32.6128 </transform>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 55.5702, 5.40827, 32.6128 </transform>
- <resource resource_type="PackedScene" path="res://player.xml"> </resource>
- <transform> 0.0160676, 0, -0.999871, 0, 1, 0, 0.999871, 0, 0.0160676, 8.50167, 4.15811, 15.9334 </transform>
- <dictionary shared="false">
- <string> "__editor_plugin_states__" </string>
- <dictionary shared="false">
- <string> "Script" </string>
- <dictionary shared="false">
- <string> "current" </string>
- <int> 1 </int>
- <string> "sources" </string>
- <array len="2" shared="false">
- <string> "res://follow_camera.gd" </string>
- <string> "res://player.gd" </string>
- </array>
- </dictionary>
- <string> "2D" </string>
- <dictionary shared="false">
- <string> "pixel_snap" </string>
- <bool> False </bool>
- <string> "zoom" </string>
- <real> 1 </real>
- <string> "ofs" </string>
- <vector2> -241, -19 </vector2>
- </dictionary>
- <string> "3D" </string>
- <dictionary shared="false">
- <string> "fov" </string>
- <real> 400 </real>
- <string> "zfar" </string>
- <real> 500 </real>
- <string> "viewports" </string>
- <array len="4" shared="false">
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 2.161076 </real>
- <string> "x_rot" </string>
- <real> 0.520797 </real>
- <string> "y_rot" </string>
- <real> 26.741669 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> -0.415811, 0.486899, 0.089334 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- </array>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "znear" </string>
- <real> 0.1 </real>
- <string> "show_origin" </string>
- <bool> True </bool>
- </dictionary>
- </dictionary>
- <string> "__editor_run_settings__" </string>
- <dictionary shared="false">
- <string> "custom_args" </string>
- <string> "-l $scene" </string>
- <string> "run_mode" </string>
- <int> 0 </int>
- </dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "3D" </string>
- </dictionary>
- </array>
- <string> "nodes" </string>
- <int_array len="873"> -1, -1, 1, 0, -1, 4, 2, 0, 3, 1, 4, 2, 5, 3, 0, 0, 0, 6, 6, -1, 14, 2, 0, 3, 1, 4, 2, 7, 4, 8, 5, 9, 5, 10, 6, 11, 7, 12, 2, 13, 2, 14, 2, 15, 8, 16, 9, 5, 10, 0, 0, 0, 17, 17, -1, 23, 2, 0, 3, 1, 18, 11, 4, 2, 19, 12, 20, 2, 21, 5, 22, 13, 23, 14, 24, 15, 25, 15, 26, 2, 27, 16, 28, 17, 29, 18, 30, 19, 31, 20, 32, 21, 33, 13, 34, 22, 35, 23, 36, 24, 37, 6, 0, 0, 0, 39, 38, -1, 4, 2, 0, 3, 1, 4, 2, 38, 25, 0, 0, 0, 41, 40, -1, 2, 2, 0, 5, 26, 0, 4, 0, 43, 42, 27, 4, 2, 0, 3, 1, 18, 28, 5, 29, 0, 4, 0, 43, 44, 27, 4, 2, 0, 3, 1, 18, 30, 5, 29, 0, 4, 0, 43, 45, 27, 4, 2, 0, 3, 1, 18, 31, 5, 29, 0, 4, 0, 43, 46, 27, 4, 2, 0, 3, 1, 18, 32, 5, 29, 0, 4, 0, 43, 47, 27, 4, 2, 0, 3, 1, 18, 33, 5, 29, 0, 4, 0, 43, 48, 27, 4, 2, 0, 3, 1, 18, 34, 5, 29, 0, 4, 0, 43, 49, 27, 4, 2, 0, 3, 1, 18, 35, 5, 29, 0, 4, 0, 43, 50, 27, 4, 2, 0, 3, 1, 18, 36, 5, 29, 0, 4, 0, 43, 51, 27, 4, 2, 0, 3, 1, 18, 37, 5, 29, 0, 4, 0, 43, 52, 27, 4, 2, 0, 3, 1, 18, 38, 5, 29, 0, 4, 0, 43, 53, 27, 4, 2, 0, 3, 1, 18, 39, 5, 29, 0, 4, 0, 43, 54, 27, 4, 2, 0, 3, 1, 18, 40, 5, 29, 0, 4, 0, 43, 55, 27, 4, 2, 0, 3, 1, 18, 41, 5, 29, 0, 4, 0, 43, 56, 27, 4, 2, 0, 3, 1, 18, 42, 5, 29, 0, 4, 0, 43, 57, 27, 4, 2, 0, 3, 1, 18, 43, 5, 29, 0, 4, 0, 43, 58, 27, 4, 2, 0, 3, 1, 18, 44, 5, 29, 0, 4, 0, 43, 59, 27, 4, 2, 0, 3, 1, 18, 45, 5, 29, 0, 4, 0, 43, 60, 27, 4, 2, 0, 3, 1, 18, 46, 5, 29, 0, 4, 0, 43, 61, 27, 4, 2, 0, 3, 1, 18, 47, 5, 29, 0, 4, 0, 43, 62, 27, 4, 2, 0, 3, 1, 18, 48, 5, 29, 0, 4, 0, 43, 63, 27, 4, 2, 0, 3, 1, 18, 49, 5, 29, 0, 4, 0, 43, 64, 27, 4, 2, 0, 3, 1, 18, 50, 5, 29, 0, 4, 0, 43, 65, 27, 4, 2, 0, 3, 1, 18, 51, 5, 29, 0, 4, 0, 43, 66, 27, 4, 2, 0, 3, 1, 18, 52, 5, 29, 0, 4, 0, 43, 67, 27, 4, 2, 0, 3, 1, 18, 53, 5, 29, 0, 4, 0, 43, 68, 27, 4, 2, 0, 3, 1, 18, 54, 5, 29, 0, 4, 0, 43, 69, 27, 4, 2, 0, 3, 1, 18, 55, 5, 29, 0, 4, 0, 43, 70, 27, 4, 2, 0, 3, 1, 18, 56, 5, 29, 0, 4, 0, 43, 71, 27, 4, 2, 0, 3, 1, 18, 57, 5, 29, 0, 4, 0, 43, 72, 27, 4, 2, 0, 3, 1, 18, 58, 5, 29, 0, 4, 0, 43, 73, 27, 4, 2, 0, 3, 1, 18, 59, 5, 29, 0, 4, 0, 43, 74, 27, 4, 2, 0, 3, 1, 18, 60, 5, 29, 0, 4, 0, 43, 75, 27, 4, 2, 0, 3, 1, 18, 61, 5, 29, 0, 4, 0, 43, 76, 27, 4, 2, 0, 3, 1, 18, 62, 5, 29, 0, 4, 0, 43, 77, 27, 4, 2, 0, 3, 1, 18, 63, 5, 29, 0, 4, 0, 43, 78, 27, 4, 2, 0, 3, 1, 18, 64, 5, 29, 0, 4, 0, 43, 79, 27, 4, 2, 0, 3, 1, 18, 65, 5, 29, 0, 4, 0, 43, 80, 27, 4, 2, 0, 3, 1, 18, 66, 5, 29, 0, 4, 0, 43, 81, 27, 4, 2, 0, 3, 1, 18, 67, 5, 29, 0, 4, 0, 43, 82, 27, 4, 2, 0, 3, 1, 18, 68, 5, 29, 0, 4, 0, 43, 83, 27, 4, 2, 0, 3, 1, 18, 69, 5, 29, 0, 4, 0, 43, 84, 27, 4, 2, 0, 3, 1, 18, 70, 5, 29, 0, 4, 0, 43, 85, 27, 4, 2, 0, 3, 1, 18, 71, 5, 29, 0, 4, 0, 43, 86, 27, 4, 2, 0, 3, 1, 18, 72, 5, 29, 0, 0, 0, 41, 87, -1, 1, 2, 0, 0, 49, 0, 89, 88, 73, 4, 2, 0, 3, 1, 18, 74, 5, 75, 0, 49, 0, 89, 90, 73, 4, 2, 0, 3, 1, 18, 76, 5, 75, 0, 49, 0, 89, 91, 73, 4, 2, 0, 3, 1, 18, 77, 5, 75, 0, 49, 0, 89, 92, 73, 4, 2, 0, 3, 1, 18, 78, 5, 75, 0, 0, 0, 89, 93, 79, 4, 2, 0, 3, 1, 18, 80, 5, 81, 0 </int_array>
- <string> "conns" </string>
- <int_array len="0"> </int_array>
- </dictionary>
-
- </main_resource>
-</resource_file> \ No newline at end of file
diff --git a/demos/3d/platformer/tiles.scn b/demos/3d/platformer/tiles.scn
index ca804d2d09..4c3442dbeb 100644
--- a/demos/3d/platformer/tiles.scn
+++ b/demos/3d/platformer/tiles.scn
Binary files differ
diff --git a/demos/3d/polygon_path_finder/engine.cfg b/demos/3d/polygon_path_finder/engine.cfg
new file mode 100644
index 0000000000..47450408af
--- /dev/null
+++ b/demos/3d/polygon_path_finder/engine.cfg
@@ -0,0 +1,5 @@
+[application]
+
+name="Polygon Pathfinder"
+main_scene="res://poly_with_holes.scn"
+icon="res://icon.png"
diff --git a/demos/3d/polygon_path_finder/icon.png b/demos/3d/polygon_path_finder/icon.png
new file mode 100644
index 0000000000..643f5595ee
--- /dev/null
+++ b/demos/3d/polygon_path_finder/icon.png
Binary files differ
diff --git a/demos/3d/polygon_path_finder/poly_with_holes.scn b/demos/3d/polygon_path_finder/poly_with_holes.scn
new file mode 100644
index 0000000000..6b340377b7
--- /dev/null
+++ b/demos/3d/polygon_path_finder/poly_with_holes.scn
Binary files differ
diff --git a/demos/3d/polygon_path_finder/polygonpathfinder.gd b/demos/3d/polygon_path_finder/polygonpathfinder.gd
new file mode 100644
index 0000000000..1e843043da
--- /dev/null
+++ b/demos/3d/polygon_path_finder/polygonpathfinder.gd
@@ -0,0 +1,77 @@
+
+extends Spatial
+
+
+func _ready():
+ var pf = PolygonPathFinder.new()
+
+ var points = Vector2Array()
+ var connections = IntArray()
+
+ # Poly 1
+ points.push_back(Vector2(0, 0)) # 0
+ points.push_back(Vector2(10, 0)) # 1
+ points.push_back(Vector2(10, 10)) # 2
+ points.push_back(Vector2(0, 10)) # 3
+
+ connections.push_back(0) # Connect vertex 0...
+ connections.push_back(1) # ... to 1
+ drawLine(points[0], points[1], get_node("/root/Spatial/Polys"))
+ connections.push_back(1) # Connect vertex 1...
+ connections.push_back(2) # ... to 2
+ drawLine(points[1], points[2], get_node("/root/Spatial/Polys"))
+ connections.push_back(2) # Etc.
+ connections.push_back(3)
+ drawLine(points[2], points[3], get_node("/root/Spatial/Polys"))
+ connections.push_back(3) # Connect vertex 3...
+ connections.push_back(0) # ... back to vertex 0, to close the polygon
+ drawLine(points[3], points[0], get_node("/root/Spatial/Polys"))
+
+ # Poly 2, as obstacle inside poly 1
+ points.push_back(Vector2(2, 0.5)) # 4
+ points.push_back(Vector2(4, 0.5)) # 5
+ points.push_back(Vector2(4, 9.5)) # 6
+ points.push_back(Vector2(2, 9.5)) # 7
+
+ connections.push_back(4)
+ connections.push_back(5)
+ drawLine(points[4], points[5], get_node("/root/Spatial/Polys"))
+ connections.push_back(5)
+ connections.push_back(6)
+ drawLine(points[5], points[6], get_node("/root/Spatial/Polys"))
+ connections.push_back(6)
+ connections.push_back(7)
+ drawLine(points[6], points[7], get_node("/root/Spatial/Polys"))
+ connections.push_back(7)
+ connections.push_back(4)
+ drawLine(points[7], points[4], get_node("/root/Spatial/Polys"))
+
+ print("points: ", points)
+ print("connections: ", connections)
+
+ pf.setup(points, connections)
+
+ var path = pf.find_path(Vector2(1, 5), Vector2(8, 5))
+
+ var lastStep = null
+ print("path: ", path)
+ for step in path:
+ print("step: ", step)
+ if (lastStep != null):
+ var currPathSegment = Vector2Array()
+ drawLine(lastStep, step, get_node("/root/Spatial/Path"))
+ lastStep = step
+
+
+func drawLine(pointA, pointB, immediateGeo):
+ var drawPosY = 0.1
+ var im = immediateGeo
+
+ im.begin(Mesh.PRIMITIVE_POINTS, null)
+ im.add_vertex(Vector3(pointA.x, drawPosY, pointA.y))
+ im.add_vertex(Vector3(pointB.x, drawPosY, pointB.y))
+ im.end()
+ im.begin(Mesh.PRIMITIVE_LINE_STRIP, null)
+ im.add_vertex(Vector3(pointA.x, drawPosY, pointA.y))
+ im.add_vertex(Vector3(pointB.x, drawPosY, pointB.y))
+ im.end()
diff --git a/demos/3d/sat_test/box.scn b/demos/3d/sat_test/box.scn
index 8b02826ea7..f9c15839a2 100644
--- a/demos/3d/sat_test/box.scn
+++ b/demos/3d/sat_test/box.scn
Binary files differ
diff --git a/demos/3d/sat_test/capsule.scn b/demos/3d/sat_test/capsule.scn
index a4fe2b2b3f..db8ff43116 100644
--- a/demos/3d/sat_test/capsule.scn
+++ b/demos/3d/sat_test/capsule.scn
Binary files differ
diff --git a/demos/3d/sat_test/convex.scn b/demos/3d/sat_test/convex.scn
index 5f62beccaf..93e05338eb 100644
--- a/demos/3d/sat_test/convex.scn
+++ b/demos/3d/sat_test/convex.scn
Binary files differ
diff --git a/demos/3d/sat_test/engine.cfg b/demos/3d/sat_test/engine.cfg
index cc215c83e8..e21c9b1eff 100644
--- a/demos/3d/sat_test/engine.cfg
+++ b/demos/3d/sat_test/engine.cfg
@@ -1,4 +1,5 @@
[application]
name="SAT Collision Test"
-main_scene="res://sat_test.xml"
+main_scene="res://sat_test.scn"
+icon="res://icon.png"
diff --git a/demos/3d/sat_test/icon.png b/demos/3d/sat_test/icon.png
new file mode 100644
index 0000000000..194456e10f
--- /dev/null
+++ b/demos/3d/sat_test/icon.png
Binary files differ
diff --git a/demos/3d/sat_test/sat_test.scn b/demos/3d/sat_test/sat_test.scn
new file mode 100644
index 0000000000..0b25431202
--- /dev/null
+++ b/demos/3d/sat_test/sat_test.scn
Binary files differ
diff --git a/demos/3d/sat_test/sat_test.xml b/demos/3d/sat_test/sat_test.xml
deleted file mode 100644
index f11dec3292..0000000000
--- a/demos/3d/sat_test/sat_test.xml
+++ /dev/null
@@ -1,179 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="5" version="0.99" version_name="Godot Engine v0.99.3735-pre-beta">
- <ext_resource path="res://box.*" type="PackedScene"></ext_resource>
- <ext_resource path="res://sphere.*" type="PackedScene"></ext_resource>
- <ext_resource path="res://capsule.*" type="PackedScene"></ext_resource>
- <ext_resource path="res://convex.*" type="PackedScene"></ext_resource>
- <main_resource>
- <dictionary name="_bundled" shared="false">
- <string> "names" </string>
- <string_array len="30">
- <string> "Node" </string>
- <string> "__meta__" </string>
- <string> "sphere" </string>
- <string> "Spatial" </string>
- <string> "transform/local" </string>
- <string> "box" </string>
- <string> "convex" </string>
- <string> "Camera" </string>
- <string> "projection" </string>
- <string> "fov" </string>
- <string> "near" </string>
- <string> "far" </string>
- <string> "vaspect" </string>
- <string> "current" </string>
- <string> "visible_layers" </string>
- <string> "environment" </string>
- <string> "OmniLight" </string>
- <string> "layers" </string>
- <string> "params/energy" </string>
- <string> "colors/ambient" </string>
- <string> "colors/diffuse" </string>
- <string> "colors/specular" </string>
- <string> "shadow/shadow" </string>
- <string> "shadow/darkening" </string>
- <string> "shadow/z_offset" </string>
- <string> "shadow/z_slope_scale" </string>
- <string> "projector" </string>
- <string> "operator" </string>
- <string> "params/radius" </string>
- <string> "params/attenuation" </string>
- </string_array>
- <string> "version" </string>
- <int> 1 </int>
- <string> "conn_count" </string>
- <int> 0 </int>
- <string> "node_count" </string>
- <int> 7 </int>
- <string> "variants" </string>
- <array len="26" shared="false">
- <dictionary shared="false">
- <string> "__editor_plugin_states__" </string>
- <dictionary shared="false">
- <string> "2D" </string>
- <dictionary shared="false">
- <string> "zoom" </string>
- <real> 1 </real>
- <string> "ofs" </string>
- <vector2> 1, 1 </vector2>
- </dictionary>
- <string> "3D" </string>
- <dictionary shared="false">
- <string> "zfar" </string>
- <real> 500 </real>
- <string> "fov" </string>
- <real> 400 </real>
- <string> "viewports" </string>
- <array len="4" shared="false">
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 34.508423 </real>
- <string> "x_rot" </string>
- <real> 0.7 </real>
- <string> "y_rot" </string>
- <real> 1.262503 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 13.3659, 3.22136, 2.27417 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- </array>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "default_light" </string>
- <bool> False </bool>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
- <string> "znear" </string>
- <real> 0.1 </real>
- </dictionary>
- </dictionary>
- <string> "__editor_run_settings__" </string>
- <dictionary shared="false">
- <string> "custom_args" </string>
- <string> "-l $scene" </string>
- <string> "run_mode" </string>
- <int> 0 </int>
- </dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "3D" </string>
- </dictionary>
- <resource resource_type="PackedScene" path="res://sphere.*"> </resource>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -2.93877 </transform>
- <resource resource_type="PackedScene" path="res://box.*"> </resource>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 13.5356, 0, -3.40082 </transform>
- <resource resource_type="PackedScene" path="res://convex.*"> </resource>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 22.8626, 0, -2.50073 </transform>
- <resource resource_type="PackedScene" path="res://capsule.*"> </resource>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 28.4061, 0, -2.76809 </transform>
- <transform> 1, 0, 0, 0, 0.819152, 0.573576, 0, -0.573576, 0.819152, 14.482, 11.1225, 20.5858 </transform>
- <int> 0 </int>
- <real> 60 </real>
- <real> 0.1 </real>
- <real> 100 </real>
- <bool> False </bool>
- <int> -1 </int>
- <resource name=""></resource> <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 66.4797, 0, 10.4696 </transform>
- <int> 1 </int>
- <real> 1.5 </real>
- <color> 0.355828, 0.346354, 0.329995, 1 </color>
- <color> 1, 1, 1, 1 </color>
- <real> 0 </real>
- <real> 0.05 </real>
- <real> 500 </real>
- <real> 0.535887 </real>
- </array>
- <string> "nodes" </string>
- <int_array len="105"> -1, -1, 0, 0, -1, 1, 1, 0, 0, 0, 0, 3, 2, 1, 1, 4, 2, 0, 0, 0, 3, 5, 3, 1, 4, 4, 0, 0, 0, 3, 6, 5, 1, 4, 6, 0, 0, 0, 3, 3, 7, 1, 4, 8, 0, 0, 0, 7, 7, -1, 9, 4, 9, 8, 10, 9, 11, 10, 12, 11, 13, 12, 14, 13, 14, 14, 15, 15, 16, 0, 0, 0, 16, 16, -1, 14, 4, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 21, 22, 14, 23, 22, 24, 23, 25, 22, 26, 16, 27, 10, 28, 24, 29, 25, 0 </int_array>
- <string> "conns" </string>
- <int_array len="0"> </int_array>
- </dictionary>
-
- </main_resource>
-</resource_file> \ No newline at end of file
diff --git a/demos/3d/sat_test/shapes.scn b/demos/3d/sat_test/shapes.scn
index 584237b89d..bf10be0a59 100644
--- a/demos/3d/sat_test/shapes.scn
+++ b/demos/3d/sat_test/shapes.scn
Binary files differ
diff --git a/demos/3d/sat_test/sphere.scn b/demos/3d/sat_test/sphere.scn
index dd49c914b3..e40c3bd42d 100644
--- a/demos/3d/sat_test/sphere.scn
+++ b/demos/3d/sat_test/sphere.scn
Binary files differ
diff --git a/demos/3d/shader_materials/shader_materials.scn b/demos/3d/shader_materials/shader_materials.scn
index 243c6c8f06..7eb43cda0d 100644
--- a/demos/3d/shader_materials/shader_materials.scn
+++ b/demos/3d/shader_materials/shader_materials.scn
Binary files differ
diff --git a/demos/3d/truck_town/car_base.scn b/demos/3d/truck_town/car_base.scn
index d62c8dcb29..acfbfae162 100644
--- a/demos/3d/truck_town/car_base.scn
+++ b/demos/3d/truck_town/car_base.scn
Binary files differ
diff --git a/demos/3d/truck_town/car_select.gd b/demos/3d/truck_town/car_select.gd
index 00b4d853b8..4efcf63426 100644
--- a/demos/3d/truck_town/car_select.gd
+++ b/demos/3d/truck_town/car_select.gd
@@ -1,40 +1,30 @@
extends Control
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
-func _ready():
- # Initalization here
- pass
-
-var town=null
+# Member variables
+var town = null
func _back():
-
town.queue_free()
show()
-
-func _load_scene(car):
+func _load_scene(car):
var tt = load(car).instance()
tt.set_name("car")
town = load("res://truck_scene.scn").instance()
town.get_node("instance_pos").add_child(tt)
- town.get_node("back").connect("pressed",self,"_back")
+ town.get_node("back").connect("pressed", self, "_back")
get_parent().add_child(town)
hide()
-func _on_van_1_pressed():
+func _on_van_1_pressed():
_load_scene("res://car_base.scn")
func _on_van_2_pressed():
-
_load_scene("res://trailer_truck.scn")
diff --git a/demos/3d/truck_town/car_select.scn b/demos/3d/truck_town/car_select.scn
index 024adf1423..d838e995b2 100644
--- a/demos/3d/truck_town/car_select.scn
+++ b/demos/3d/truck_town/car_select.scn
Binary files differ
diff --git a/demos/3d/truck_town/crane.scn b/demos/3d/truck_town/crane.scn
index 2c4645af69..dfddd97882 100644
--- a/demos/3d/truck_town/crane.scn
+++ b/demos/3d/truck_town/crane.scn
Binary files differ
diff --git a/demos/3d/truck_town/engine.cfg b/demos/3d/truck_town/engine.cfg
index 3c340e6dcd..b2a463e1e2 100644
--- a/demos/3d/truck_town/engine.cfg
+++ b/demos/3d/truck_town/engine.cfg
@@ -2,6 +2,7 @@
name="Truck Town"
main_scene="res://car_select.scn"
+icon="res://icon.png"
[display]
diff --git a/demos/3d/truck_town/follow_camera.gd b/demos/3d/truck_town/follow_camera.gd
index cf7172d7bb..7c6a0a2ba6 100644
--- a/demos/3d/truck_town/follow_camera.gd
+++ b/demos/3d/truck_town/follow_camera.gd
@@ -1,69 +1,57 @@
extends Camera
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
-var collision_exception=[]
-export var min_distance=0.5
-export var max_distance=4.0
-export var angle_v_adjust=0.0
-export var autoturn_ray_aperture=25
-export var autoturn_speed=50
+# Member variables
+var collision_exception = []
+export var min_distance = 0.5
+export var max_distance = 4.0
+export var angle_v_adjust = 0.0
+export var autoturn_ray_aperture = 25
+export var autoturn_speed = 50
var max_height = 2.0
var min_height = 0
+
func _fixed_process(dt):
- var target = get_parent().get_global_transform().origin
+ var target = get_parent().get_global_transform().origin
var pos = get_global_transform().origin
- var up = Vector3(0,1,0)
+ var up = Vector3(0, 1, 0)
var delta = pos - target
- #regular delta follow
+ # Regular delta follow
- #check ranges
-
+ # Check ranges
if (delta.length() < min_distance):
- delta = delta.normalized() * min_distance
+ delta = delta.normalized()*min_distance
elif (delta.length() > max_distance):
- delta = delta.normalized() * max_distance
+ delta = delta.normalized()*max_distance
- #check upper and lower height
+ # Check upper and lower height
if ( delta.y > max_height):
delta.y = max_height
if ( delta.y < min_height):
delta.y = min_height
-
+
pos = target + delta
- look_at_from_pos(pos,target,up)
+ look_at_from_pos(pos, target, up)
- #turn a little up or down
+ # Turn a little up or down
var t = get_transform()
- t.basis = Matrix3(t.basis[0],deg2rad(angle_v_adjust)) * t.basis
+ t.basis = Matrix3(t.basis[0], deg2rad(angle_v_adjust))*t.basis
set_transform(t)
-
-
-func _ready():
-#find collision exceptions for ray
+func _ready():
+ # Find collision exceptions for ray
var node = self
while(node):
if (node extends RigidBody):
collision_exception.append(node.get_rid())
break
else:
- node=node.get_parent()
- # Initalization here
+ node = node.get_parent()
set_fixed_process(true)
- #this detaches the camera transform from the parent spatial node
+ # This detaches the camera transform from the parent spatial node
set_as_toplevel(true)
-
-
-
-
-
-
diff --git a/demos/3d/truck_town/icon.png b/demos/3d/truck_town/icon.png
new file mode 100644
index 0000000000..7d7bd42116
--- /dev/null
+++ b/demos/3d/truck_town/icon.png
Binary files differ
diff --git a/demos/3d/truck_town/trailer_truck.scn b/demos/3d/truck_town/trailer_truck.scn
index 0131e9e3a2..6fcf83e270 100644
--- a/demos/3d/truck_town/trailer_truck.scn
+++ b/demos/3d/truck_town/trailer_truck.scn
Binary files differ
diff --git a/demos/3d/truck_town/truck_scene.scn b/demos/3d/truck_town/truck_scene.scn
index a02ce259c1..0c1be13ce2 100644
--- a/demos/3d/truck_town/truck_scene.scn
+++ b/demos/3d/truck_town/truck_scene.scn
Binary files differ
diff --git a/demos/3d/truck_town/trucktown.scn b/demos/3d/truck_town/trucktown.scn
index 57a84315ee..4a8f7e7e52 100644
--- a/demos/3d/truck_town/trucktown.scn
+++ b/demos/3d/truck_town/trucktown.scn
Binary files differ
diff --git a/demos/3d/truck_town/vehicle.gd b/demos/3d/truck_town/vehicle.gd
index 1aa7f0faa2..c4224577c6 100644
--- a/demos/3d/truck_town/vehicle.gd
+++ b/demos/3d/truck_town/vehicle.gd
@@ -1,54 +1,45 @@
extends VehicleBody
-# member variables here, example:
-# var a=2
-# var b="textvar"
+# Member variables
+const STEER_SPEED = 1
+const STEER_LIMIT = 0.4
+var steer_angle = 0
+var steer_target = 0
-const STEER_SPEED=1
-const STEER_LIMIT=0.4
+export var engine_force = 40
-var steer_angle=0
-var steer_target=0
-
-
-export var engine_force=40
func _fixed_process(delta):
-
-
if (Input.is_action_pressed("ui_left")):
- steer_target=-STEER_LIMIT
+ steer_target = -STEER_LIMIT
elif (Input.is_action_pressed("ui_right")):
- steer_target=STEER_LIMIT
+ steer_target = STEER_LIMIT
else:
- steer_target=0
-
+ steer_target = 0
+
if (Input.is_action_pressed("ui_up")):
set_engine_force(engine_force)
else:
set_engine_force(0)
-
+
if (Input.is_action_pressed("ui_down")):
set_brake(1)
else:
set_brake(0.0)
-
-
+
if (steer_target < steer_angle):
steer_angle -= STEER_SPEED*delta
if (steer_target > steer_angle):
- steer_angle=steer_target
+ steer_angle = steer_target
elif (steer_target > steer_angle):
steer_angle += STEER_SPEED*delta
if (steer_target < steer_angle):
- steer_angle=steer_target
-
+ steer_angle = steer_target
+
set_steering(steer_angle)
-func _ready():
- # Initalization here
- set_fixed_process(true)
- pass
+func _ready():
+ set_fixed_process(true)
diff --git a/demos/gui/drag_and_drop/drag_and_drop.scn b/demos/gui/drag_and_drop/drag_and_drop.scn
index 94a25cc53e..9dec254ef7 100644
--- a/demos/gui/drag_and_drop/drag_and_drop.scn
+++ b/demos/gui/drag_and_drop/drag_and_drop.scn
Binary files differ
diff --git a/demos/gui/drag_and_drop/drag_drop_script.gd b/demos/gui/drag_and_drop/drag_drop_script.gd
index 21a737ce1a..719c42fe8f 100644
--- a/demos/gui/drag_and_drop/drag_drop_script.gd
+++ b/demos/gui/drag_and_drop/drag_drop_script.gd
@@ -2,23 +2,19 @@
extends ColorPickerButton
-#virtual function
func get_drag_data(pos):
-
- #use another colorpicker as drag preview
+ # Use another colorpicker as drag preview
var cpb = ColorPickerButton.new()
- cpb.set_color( get_color() )
- cpb.set_size(Vector2(50,50))
+ cpb.set_color(get_color())
+ cpb.set_size(Vector2(50, 50))
set_drag_preview(cpb)
- #return color as drag data
+ # Return color as drag data
return get_color()
-#virtual function
+
func can_drop_data(pos, data):
- return typeof(data)==TYPE_COLOR
+ return typeof(data) == TYPE_COLOR
+
-#virtual function
func drop_data(pos, data):
set_color(data)
-
-
diff --git a/demos/gui/drag_and_drop/engine.cfg b/demos/gui/drag_and_drop/engine.cfg
index 448939c61d..49b9b93512 100644
--- a/demos/gui/drag_and_drop/engine.cfg
+++ b/demos/gui/drag_and_drop/engine.cfg
@@ -2,3 +2,4 @@
name="Drag &amp; Drop (GUI)"
main_scene="res://drag_and_drop.scn"
+icon="res://icon.png"
diff --git a/demos/gui/drag_and_drop/icon.png b/demos/gui/drag_and_drop/icon.png
new file mode 100644
index 0000000000..f900d8d4a3
--- /dev/null
+++ b/demos/gui/drag_and_drop/icon.png
Binary files differ
diff --git a/demos/gui/input_mapping/controls.gd b/demos/gui/input_mapping/controls.gd
index 6ca059c812..3cee6e6871 100644
--- a/demos/gui/input_mapping/controls.gd
+++ b/demos/gui/input_mapping/controls.gd
@@ -1,3 +1,6 @@
+
+extends Control
+
# Note for the reader:
#
# This demo conveniently uses the same names for actions and for the container nodes
@@ -9,12 +12,12 @@
# action and the node, e.g.:
# button.connect("pressed", self, "wait_for_input", [ button, action ])
-extends Control
-
+# Member variables
var player_actions = [ "move_up", "move_down", "move_left", "move_right", "jump" ]
var action # To register the action the UI is currently handling
var button # Button node corresponding to the above action
+
func wait_for_input(action_bind):
action = action_bind
# See note at the beginning of the script
@@ -22,6 +25,7 @@ func wait_for_input(action_bind):
get_node("contextual_help").set_text("Press a key to assign to the '" + action + "' action.")
set_process_input(true)
+
func _input(event):
# Handle the first pressed key
if (event.type == InputEvent.KEY):
@@ -39,6 +43,7 @@ func _input(event):
# Add the new key binding
InputMap.action_add_event(action, event)
+
func _ready():
# Initialise each button with the default key binding from InputMap
var input_event
diff --git a/demos/gui/input_mapping/controls.scn b/demos/gui/input_mapping/controls.scn
index 276712ba22..98cbbca464 100644
--- a/demos/gui/input_mapping/controls.scn
+++ b/demos/gui/input_mapping/controls.scn
Binary files differ
diff --git a/demos/gui/input_mapping/engine.cfg b/demos/gui/input_mapping/engine.cfg
index 959c0ac7d5..811635ce25 100644
--- a/demos/gui/input_mapping/engine.cfg
+++ b/demos/gui/input_mapping/engine.cfg
@@ -2,7 +2,7 @@
name="Input Mapping GUI"
main_scene="res://controls.scn"
-icon="icon.png"
+icon="res://icon.png"
[display]
diff --git a/demos/gui/input_mapping/icon.png b/demos/gui/input_mapping/icon.png
new file mode 100644
index 0000000000..5a1abf4f58
--- /dev/null
+++ b/demos/gui/input_mapping/icon.png
Binary files differ
diff --git a/demos/gui/rich_text_bbcode/engine.cfg b/demos/gui/rich_text_bbcode/engine.cfg
index e0ea296f6d..5f68b6a0e6 100644
--- a/demos/gui/rich_text_bbcode/engine.cfg
+++ b/demos/gui/rich_text_bbcode/engine.cfg
@@ -2,3 +2,4 @@
name="Rich Text Label (BBCode)"
main_scene="res://rich_text_bbcode.scn"
+icon="res://icon.png"
diff --git a/demos/gui/rich_text_bbcode/icon.png b/demos/gui/rich_text_bbcode/icon.png
new file mode 100644
index 0000000000..6db48a3a9b
--- /dev/null
+++ b/demos/gui/rich_text_bbcode/icon.png
Binary files differ
diff --git a/demos/gui/rich_text_bbcode/rich_text_bbcode.gd b/demos/gui/rich_text_bbcode/rich_text_bbcode.gd
index 30fac1f729..79a08c1303 100644
--- a/demos/gui/rich_text_bbcode/rich_text_bbcode.gd
+++ b/demos/gui/rich_text_bbcode/rich_text_bbcode.gd
@@ -1,17 +1,6 @@
extends Panel
-# member variables here, example:
-# var a=2
-# var b="textvar"
-func _ready():
- # Initialization here
- pass
-
-
-
-
-func _on_RichTextLabel_meta_clicked( meta ):
+func _on_RichTextLabel_meta_clicked(meta):
OS.shell_open(meta)
- pass # replace with function body
diff --git a/demos/gui/rich_text_bbcode/rich_text_bbcode.scn b/demos/gui/rich_text_bbcode/rich_text_bbcode.scn
index ca02044bb8..c908d44dc3 100644
--- a/demos/gui/rich_text_bbcode/rich_text_bbcode.scn
+++ b/demos/gui/rich_text_bbcode/rich_text_bbcode.scn
Binary files differ
diff --git a/demos/gui/translation/controls.gd b/demos/gui/translation/controls.gd
index f8403f49a7..ae2e26362b 100644
--- a/demos/gui/translation/controls.gd
+++ b/demos/gui/translation/controls.gd
@@ -1,20 +1,9 @@
extends Panel
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
-func _ready():
- # Initialization here
- pass
-
-
-
func _on_back_pressed():
var s = load("res://main.scn")
var si = s.instance()
get_parent().add_child(si)
queue_free()
- pass # replace with function body
diff --git a/demos/gui/translation/controls.scn b/demos/gui/translation/controls.scn
index 66e6d47702..055ac90b9b 100644
--- a/demos/gui/translation/controls.scn
+++ b/demos/gui/translation/controls.scn
Binary files differ
diff --git a/demos/gui/translation/engine.cfg b/demos/gui/translation/engine.cfg
index 169b65e154..dcd3d1983d 100644
--- a/demos/gui/translation/engine.cfg
+++ b/demos/gui/translation/engine.cfg
@@ -2,6 +2,7 @@
name="Translation Demo"
main_scene="res://main.scn"
+icon="res://icon.png"
[locale]
diff --git a/demos/gui/translation/icon.png b/demos/gui/translation/icon.png
new file mode 100644
index 0000000000..4be5ac1127
--- /dev/null
+++ b/demos/gui/translation/icon.png
Binary files differ
diff --git a/demos/gui/translation/main.gd b/demos/gui/translation/main.gd
index bf3c0c0840..c3e788f82b 100644
--- a/demos/gui/translation/main.gd
+++ b/demos/gui/translation/main.gd
@@ -1,31 +1,21 @@
extends Panel
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
-func _ready():
- # Initialization here
- pass
-
-
func _goto_scene():
var s = load("res://controls.scn")
var si = s.instance()
get_parent().add_child(si)
queue_free()
- pass
func _on_system_pressed():
- #will autodetect based on system, then fall back
- #to english if not found
+ # Will autodetect based on system, then fall back
+ # to english if not found
_goto_scene()
-#NOTE: Changling locale will not change the text in the controls,
-# The scene must be reloaded for changes to take effect.
+# NOTE: Changing locale will not change the text in the controls,
+# The scene must be reloaded for changes to take effect.
func _on_english_pressed():
TranslationServer.set_locale("en")
diff --git a/demos/gui/translation/main.scn b/demos/gui/translation/main.scn
index 76c9ba7b45..8fc0b4ffb2 100644
--- a/demos/gui/translation/main.scn
+++ b/demos/gui/translation/main.scn
Binary files differ
diff --git a/demos/misc/autoload/global.gd b/demos/misc/autoload/global.gd
index d1bd45461f..735995e806 100644
--- a/demos/misc/autoload/global.gd
+++ b/demos/misc/autoload/global.gd
@@ -1,43 +1,36 @@
extends Node
-var current_scene = null
+# Changing scenes is most easily done using the functions `change_scene`
+# and `change_scene_to` of the SceneTree. This script demonstrates how to
+# change scenes without those helpers.
func goto_scene(path):
-
# This function will usually be called from a signal callback,
# or some other function from the running scene.
# Deleting the current scene at this point might be
# a bad idea, because it may be inside of a callback or function of it.
# The worst case will be a crash or unexpected behavior.
-
+
# The way around this is deferring the load to a later time, when
# it is ensured that no code from the current scene is running:
-
+
call_deferred("_deferred_goto_scene",path)
func _deferred_goto_scene(path):
-
- # Immediately free the current scene,
- # there is no risk here.
- current_scene.free()
-
+ # Immediately free the current scene, there is no risk here.
+ get_tree().get_current_scene().free()
+
# Load new scene
- var s = ResourceLoader.load(path)
-
+ var packed_scene = ResourceLoader.load(path)
+
# Instance the new scene
- current_scene = s.instance()
-
- # Add it to the active scene, as child of root
- get_tree().get_root().add_child(current_scene)
-
-
-func _ready():
- # Get the current scene, the first time.
- # it is always the last child of root,
- # after the autoloaded nodes.
-
- var root = get_tree().get_root()
- current_scene = root.get_child( root.get_child_count() -1 )
+ var instanced_scene = packed_scene.instance()
+
+ # Add it to the scene tree, as direct child of root
+ get_tree().get_root().add_child(instanced_scene)
+
+ # Set it as the current scene, only after it has been added to the tree
+ get_tree().set_current_scene(instanced_scene)
diff --git a/demos/misc/autoload/scene_a.gd b/demos/misc/autoload/scene_a.gd
index 21a6a84eb9..03da86d9a0 100644
--- a/demos/misc/autoload/scene_a.gd
+++ b/demos/misc/autoload/scene_a.gd
@@ -1,17 +1,5 @@
-
extends Panel
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
-func _ready():
- # Initalization here
- pass
-
-
-
func _on_goto_scene_pressed():
get_node("/root/global").goto_scene("res://scene_b.scn")
- pass # replace with function body
diff --git a/demos/misc/autoload/scene_a.scn b/demos/misc/autoload/scene_a.scn
index 61727a57ba..eff314e29d 100644
--- a/demos/misc/autoload/scene_a.scn
+++ b/demos/misc/autoload/scene_a.scn
Binary files differ
diff --git a/demos/misc/autoload/scene_b.gd b/demos/misc/autoload/scene_b.gd
index 4a88fddda9..dea8c4623f 100644
--- a/demos/misc/autoload/scene_b.gd
+++ b/demos/misc/autoload/scene_b.gd
@@ -1,17 +1,5 @@
-
extends Panel
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
-func _ready():
- # Initalization here
- pass
-
-
-
func _on_goto_scene_pressed():
get_node("/root/global").goto_scene("res://scene_a.scn")
- pass # replace with function body
diff --git a/demos/misc/autoload/scene_b.scn b/demos/misc/autoload/scene_b.scn
index ae09eeff88..4cdb03e90e 100644
--- a/demos/misc/autoload/scene_b.scn
+++ b/demos/misc/autoload/scene_b.scn
Binary files differ
diff --git a/demos/misc/instancing/ball.scn b/demos/misc/instancing/ball.scn
index 81c222a306..4d6367885e 100644
--- a/demos/misc/instancing/ball.scn
+++ b/demos/misc/instancing/ball.scn
Binary files differ
diff --git a/demos/misc/instancing/container.scn b/demos/misc/instancing/container.scn
index 9a365ac494..0f65daa2ca 100644
--- a/demos/misc/instancing/container.scn
+++ b/demos/misc/instancing/container.scn
Binary files differ
diff --git a/demos/misc/instancing/engine.cfg b/demos/misc/instancing/engine.cfg
index 52a28a3fce..76b0c97721 100644
--- a/demos/misc/instancing/engine.cfg
+++ b/demos/misc/instancing/engine.cfg
@@ -2,6 +2,7 @@
name="Scene Instancing Demo"
main_scene="res://container.scn"
+icon="res://icon.png"
[physics_2d]
diff --git a/demos/misc/instancing/icon.png b/demos/misc/instancing/icon.png
new file mode 100644
index 0000000000..79a4283de7
--- /dev/null
+++ b/demos/misc/instancing/icon.png
Binary files differ
diff --git a/demos/misc/joysticks/diagram.png b/demos/misc/joysticks/diagram.png
new file mode 100644
index 0000000000..3f8ba1f973
--- /dev/null
+++ b/demos/misc/joysticks/diagram.png
Binary files differ
diff --git a/demos/misc/joysticks/engine.cfg b/demos/misc/joysticks/engine.cfg
index 71ac91000e..79cda1eeb4 100644
--- a/demos/misc/joysticks/engine.cfg
+++ b/demos/misc/joysticks/engine.cfg
@@ -6,5 +6,5 @@ icon="res://icon.png"
[display]
-width=260
+width=550
height=300
diff --git a/demos/misc/joysticks/indicators.png b/demos/misc/joysticks/indicators.png
new file mode 100644
index 0000000000..90fee48498
--- /dev/null
+++ b/demos/misc/joysticks/indicators.png
Binary files differ
diff --git a/demos/misc/joysticks/joysticks.gd b/demos/misc/joysticks/joysticks.gd
index d359e993e6..f5bc1bddad 100644
--- a/demos/misc/joysticks/joysticks.gd
+++ b/demos/misc/joysticks/joysticks.gd
@@ -8,33 +8,46 @@ extends Node2D
#
# Licensed under the MIT license
+# Member variables
var joy_num
var cur_joy
var axis_value
var btn_state
-func _ready():
- set_process_input(true)
+const DEADZONE = 0.2
-func _input(ev):
- # get the joystick device number from the spinbox
+func _fixed_process(delta):
+ # Get the joystick device number from the spinbox
joy_num = get_node("joy_num").get_value()
-
- # display the name of the joystick if we haven't already
+
+ # Display the name of the joystick if we haven't already
if joy_num != cur_joy:
cur_joy = joy_num
- get_node("joy_name").set_text( Input.get_joy_name(joy_num) )
-
- # loop through the axes and show their current values
- for axis in range(0,8):
- axis_value = Input.get_joy_axis(joy_num,axis)
- get_node("axis_prog"+str(axis)).set_value(100*axis_value)
- get_node("axis_val"+str(axis)).set_text(str(axis_value))
-
- # loop through the buttons and highlight the ones that are pressed
- for btn in range(0,17):
+ get_node("joy_name").set_text(Input.get_joy_name(joy_num))
+
+ # Loop through the axes and show their current values
+ for axis in range(0, 8):
+ axis_value = Input.get_joy_axis(joy_num, axis)
+ get_node("axis_prog" + str(axis)).set_value(100*axis_value)
+ get_node("axis_val" + str(axis)).set_text(str(axis_value))
+ if (axis < 4):
+ if (abs(axis_value) < DEADZONE):
+ get_node("diagram/axes/" + str(axis) + "+").hide()
+ get_node("diagram/axes/" + str(axis) + "-").hide()
+ elif (axis_value > 0):
+ get_node("diagram/axes/" + str(axis) + "+").show()
+ else:
+ get_node("diagram/axes/" + str(axis) + "-").show()
+
+ # Loop through the buttons and highlight the ones that are pressed
+ for btn in range(0, 16):
btn_state = 1
if (Input.is_joy_button_pressed(joy_num, btn)):
- get_node("btn"+str(btn)).add_color_override("font_color",Color(1,1,1,1))
+ get_node("btn" + str(btn)).add_color_override("font_color", Color(1, 1, 1, 1))
+ get_node("diagram/buttons/" + str(btn)).show()
else:
- get_node("btn"+str(btn)).add_color_override("font_color",Color(0.2,0.1,0.3,1))
+ get_node("btn" + str(btn)).add_color_override("font_color", Color(0.2, 0.1, 0.3, 1))
+ get_node("diagram/buttons/" + str(btn)).hide()
+
+func _ready():
+ set_fixed_process(true)
diff --git a/demos/misc/joysticks/joysticks.scn b/demos/misc/joysticks/joysticks.scn
index 5dbd7f49bf..3e0f326a0d 100644
--- a/demos/misc/joysticks/joysticks.scn
+++ b/demos/misc/joysticks/joysticks.scn
Binary files differ
diff --git a/demos/misc/joysticks/jsdiagram.xscn b/demos/misc/joysticks/jsdiagram.xscn
new file mode 100644
index 0000000000..537ad30278
--- /dev/null
+++ b/demos/misc/joysticks/jsdiagram.xscn
@@ -0,0 +1,115 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<resource_file type="PackedScene" subresource_count="3" version="2.0" version_name="Godot Engine v2.0.alpha.custom_build">
+ <ext_resource path="res://indicators.png" type="Texture" index="1"></ext_resource>
+ <ext_resource path="res://diagram.png" type="Texture" index="0"></ext_resource>
+ <main_resource>
+ <dictionary name="_bundled" shared="false">
+ <string> "conn_count" </string>
+ <int> 0 </int>
+ <string> "conns" </string>
+ <int_array len="0"> </int_array>
+ <string> "editable_instances" </string>
+ <array len="0" shared="false">
+ </array>
+ <string> "names" </string>
+ <string_array len="37">
+ <string> "diagram" </string>
+ <string> "transform/pos" </string>
+ <string> "transform/scale" </string>
+ <string> "texture" </string>
+ <string> "__meta__" </string>
+ <string> "Sprite" </string>
+ <string> "buttons" </string>
+ <string> "Node2D" </string>
+ <string> "0" </string>
+ <string> "region" </string>
+ <string> "region_rect" </string>
+ <string> "1" </string>
+ <string> "2" </string>
+ <string> "3" </string>
+ <string> "4" </string>
+ <string> "5" </string>
+ <string> "6" </string>
+ <string> "flip_h" </string>
+ <string> "7" </string>
+ <string> "8" </string>
+ <string> "9" </string>
+ <string> "10" </string>
+ <string> "11" </string>
+ <string> "12" </string>
+ <string> "13" </string>
+ <string> "flip_v" </string>
+ <string> "14" </string>
+ <string> "15" </string>
+ <string> "axes" </string>
+ <string> "0-" </string>
+ <string> "0+" </string>
+ <string> "1-" </string>
+ <string> "1+" </string>
+ <string> "3-" </string>
+ <string> "3+" </string>
+ <string> "2-" </string>
+ <string> "2+" </string>
+ </string_array>
+ <string> "node_count" </string>
+ <int> 27 </int>
+ <string> "node_paths" </string>
+ <array len="0" shared="false">
+ </array>
+ <string> "nodes" </string>
+ <int_array len="453"> -1, -1, 5, 0, -1, 4, 1, 0, 2, 1, 3, 2, 4, 3, 0, 0, 0, 7, 6, -1, 1, 4, 4, 0, 1, 0, 5, 8, -1, 5, 1, 5, 2, 6, 3, 7, 9, 8, 10, 9, 0, 1, 0, 5, 11, -1, 5, 1, 10, 2, 6, 3, 7, 9, 8, 10, 9, 0, 1, 0, 5, 12, -1, 5, 1, 11, 2, 6, 3, 7, 9, 8, 10, 9, 0, 1, 0, 5, 13, -1, 5, 1, 12, 2, 6, 3, 7, 9, 8, 10, 9, 0, 1, 0, 5, 14, -1, 5, 1, 13, 2, 14, 3, 7, 9, 8, 10, 15, 0, 1, 0, 5, 15, -1, 5, 1, 16, 2, 14, 3, 7, 9, 8, 10, 15, 0, 1, 0, 5, 16, -1, 6, 1, 17, 2, 18, 3, 7, 17, 8, 9, 8, 10, 19, 0, 1, 0, 5, 18, -1, 5, 1, 20, 2, 18, 3, 7, 9, 8, 10, 19, 0, 1, 0, 5, 19, -1, 5, 1, 21, 2, 6, 3, 7, 9, 8, 10, 9, 0, 1, 0, 5, 20, -1, 5, 1, 22, 2, 6, 3, 7, 9, 8, 10, 9, 0, 1, 0, 5, 21, -1, 5, 1, 23, 2, 24, 3, 7, 9, 8, 10, 9, 0, 1, 0, 5, 22, -1, 5, 1, 25, 2, 24, 3, 7, 9, 8, 10, 9, 0, 1, 0, 5, 23, -1, 5, 1, 26, 2, 6, 3, 7, 9, 8, 10, 27, 0, 1, 0, 5, 24, -1, 6, 1, 28, 2, 6, 3, 7, 25, 8, 9, 8, 10, 27, 0, 1, 0, 5, 26, -1, 5, 1, 29, 2, 6, 3, 7, 9, 8, 10, 30, 0, 1, 0, 5, 27, -1, 6, 1, 31, 2, 6, 3, 7, 17, 8, 9, 8, 10, 30, 0, 0, 0, 7, 28, -1, 0, 0, 18, 0, 5, 29, -1, 5, 1, 32, 2, 6, 3, 7, 9, 8, 10, 30, 0, 18, 0, 5, 30, -1, 6, 1, 33, 2, 6, 3, 7, 17, 8, 9, 8, 10, 30, 0, 18, 0, 5, 31, -1, 5, 1, 34, 2, 6, 3, 7, 9, 8, 10, 27, 0, 18, 0, 5, 32, -1, 6, 1, 35, 2, 6, 3, 7, 25, 8, 9, 8, 10, 27, 0, 18, 0, 5, 33, -1, 5, 1, 36, 2, 6, 3, 7, 9, 8, 10, 27, 0, 18, 0, 5, 34, -1, 6, 1, 37, 2, 6, 3, 7, 25, 8, 9, 8, 10, 27, 0, 18, 0, 5, 35, -1, 5, 1, 38, 2, 6, 3, 7, 9, 8, 10, 30, 0, 18, 0, 5, 36, -1, 6, 1, 39, 2, 6, 3, 7, 17, 8, 9, 8, 10, 30, 0 </int_array>
+ <string> "variants" </string>
+ <array len="40" shared="false">
+ <vector2> 368.635, 155.289 </vector2>
+ <vector2> 0.432859, 0.446287 </vector2>
+ <resource external="0"> </resource>
+ <dictionary shared="false">
+ <string> "__editor_plugin_screen__" </string>
+ <string> "2D" </string>
+ </dictionary>
+ <dictionary shared="false">
+ <string> "_editor_collapsed" </string>
+ <bool> True </bool>
+ </dictionary>
+ <vector2> 147.73, 120.925 </vector2>
+ <vector2> 0.9, 0.9 </vector2>
+ <resource external="1"> </resource>
+ <bool> True </bool>
+ <rect2> 0, 0, 45, 45 </rect2>
+ <vector2> 185.769, 82.4874 </vector2>
+ <vector2> 112.377, 82.4874 </vector2>
+ <vector2> 149.073, 47.3293 </vector2>
+ <vector2> -161.038, -158.037 </vector2>
+ <vector2> 5.3348, 3.35512 </vector2>
+ <rect2> 10, 10, 10, 10 </rect2>
+ <vector2> 159.362, -156.977 </vector2>
+ <vector2> -159.349, -221.878 </vector2>
+ <vector2> 1.0458, 2.16952 </vector2>
+ <rect2> 0, 0, 45, 22 </rect2>
+ <vector2> 156.677, -220.11 </vector2>
+ <vector2> -67.5308, 164.422 </vector2>
+ <vector2> 75.8825, 167.363 </vector2>
+ <vector2> -46.6707, 52.702 </vector2>
+ <vector2> 0.810497, 0.57205 </vector2>
+ <vector2> 56.2581, 54.4382 </vector2>
+ <vector2> -139.402, 46.8295 </vector2>
+ <rect2> 50, 0, 54, 14 </rect2>
+ <vector2> -139.838, 115.789 </vector2>
+ <vector2> -172.262, 81.8793 </vector2>
+ <rect2> 50, 0, 14, 54 </rect2>
+ <vector2> -105.085, 81.0326 </vector2>
+ <vector2> -94.4295, 164.932 </vector2>
+ <vector2> -40.3475, 164.509 </vector2>
+ <vector2> -67.6802, 137.926 </vector2>
+ <vector2> -67.4618, 192.915 </vector2>
+ <vector2> 76.6557, 140.986 </vector2>
+ <vector2> 76.0009, 195.339 </vector2>
+ <vector2> 48.8152, 167.145 </vector2>
+ <vector2> 102.899, 167.857 </vector2>
+ </array>
+ <string> "version" </string>
+ <int> 2 </int>
+ </dictionary>
+
+ </main_resource>
+</resource_file> \ No newline at end of file
diff --git a/demos/misc/pause/spinpause.gd b/demos/misc/pause/spinpause.gd
index 1b8f8388f0..ea5617c06f 100644
--- a/demos/misc/pause/spinpause.gd
+++ b/demos/misc/pause/spinpause.gd
@@ -11,5 +11,3 @@ func _on_pause_pressed():
func _on_unpause_pressed():
get_node("pause_popup").hide()
get_tree().set_pause(false)
-
-
diff --git a/demos/misc/pause/spinpause.scn b/demos/misc/pause/spinpause.scn
index a3835c4374..2cbe85ec9a 100644
--- a/demos/misc/pause/spinpause.scn
+++ b/demos/misc/pause/spinpause.scn
Binary files differ
diff --git a/demos/misc/regex/engine.cfg b/demos/misc/regex/engine.cfg
new file mode 100644
index 0000000000..ef5483e096
--- /dev/null
+++ b/demos/misc/regex/engine.cfg
@@ -0,0 +1,5 @@
+[application]
+
+name="RegEx"
+main_scene="res://regex.scn"
+icon="res://icon.png"
diff --git a/demos/misc/regex/icon.png b/demos/misc/regex/icon.png
new file mode 100644
index 0000000000..7a5232ec4b
--- /dev/null
+++ b/demos/misc/regex/icon.png
Binary files differ
diff --git a/demos/misc/regex/regex.gd b/demos/misc/regex/regex.gd
new file mode 100644
index 0000000000..98e5ca8828
--- /dev/null
+++ b/demos/misc/regex/regex.gd
@@ -0,0 +1,28 @@
+
+extends VBoxContainer
+
+# Member variables
+var regex = RegEx.new()
+
+
+func update_expression(text):
+ regex.compile(text)
+ update_text()
+
+
+func update_text():
+ var text = get_node("Text").get_text()
+ var list = get_node("List")
+ for child in list.get_children():
+ child.queue_free()
+ if regex.is_valid():
+ regex.find(text)
+ for res in regex.get_captures():
+ var label = Label.new()
+ label.set_text(res)
+ list.add_child(label)
+
+
+func _ready():
+ get_node("Text").set_text("They asked me \"What's going on \\\"in the manor\\\"?\"")
+ update_expression(get_node("Expression").get_text())
diff --git a/demos/misc/regex/regex.scn b/demos/misc/regex/regex.scn
new file mode 100644
index 0000000000..debd55504f
--- /dev/null
+++ b/demos/misc/regex/regex.scn
Binary files differ
diff --git a/demos/misc/scene_changer/scene_a.gd b/demos/misc/scene_changer/scene_a.gd
index 956878b0f7..0e80395e84 100644
--- a/demos/misc/scene_changer/scene_a.gd
+++ b/demos/misc/scene_changer/scene_a.gd
@@ -1,17 +1,16 @@
extends Panel
-# member variables here, example:
+# Member variables here, example:
# var a=2
# var b="textvar"
+
func _ready():
# Initalization here
pass
-
-
func _on_goto_scene_pressed():
get_tree().change_scene("res://scene_b.scn")
- pass # replace with function body
+ pass # Replace with function body
diff --git a/demos/misc/scene_changer/scene_a.scn b/demos/misc/scene_changer/scene_a.scn
index 61727a57ba..9a4b6434be 100644
--- a/demos/misc/scene_changer/scene_a.scn
+++ b/demos/misc/scene_changer/scene_a.scn
Binary files differ
diff --git a/demos/misc/scene_changer/scene_b.gd b/demos/misc/scene_changer/scene_b.gd
index 4f94d6bb8f..9ed13cf26b 100644
--- a/demos/misc/scene_changer/scene_b.gd
+++ b/demos/misc/scene_changer/scene_b.gd
@@ -1,17 +1,16 @@
extends Panel
-# member variables here, example:
+# Member variables here, example:
# var a=2
# var b="textvar"
+
func _ready():
# Initalization here
pass
-
-
func _on_goto_scene_pressed():
get_tree().change_scene("res://scene_a.scn")
- pass # replace with function body
+ pass # Replace with function body
diff --git a/demos/misc/scene_changer/scene_b.scn b/demos/misc/scene_changer/scene_b.scn
index ae09eeff88..4cdb03e90e 100644
--- a/demos/misc/scene_changer/scene_b.scn
+++ b/demos/misc/scene_changer/scene_b.scn
Binary files differ
diff --git a/demos/misc/threads/thread.gd b/demos/misc/threads/thread.gd
index 7d8aabd1b7..1ef67e403c 100644
--- a/demos/misc/threads/thread.gd
+++ b/demos/misc/threads/thread.gd
@@ -1,31 +1,31 @@
extends Node2D
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
+# Member variables
var thread = Thread.new()
-#this function runs in a thread!
-#threads always take one userdata argument
+
+# This function runs in a thread!
+# Threads always take one userdata argument
func _bg_load(path):
print("THREAD FUNC!")
- #load the resource
+ # Load the resource
var tex = ResourceLoader.load(path)
- #call _bg_load_done on main thread
+ # Call _bg_load_done on main thread
call_deferred("_bg_load_done")
- return tex #return it
+ return tex # return it
+
func _bg_load_done():
- #wait for the thread to complete, get the returned value
+ # Wait for the thread to complete, get the returned value
var tex = thread.wait_to_finish()
- #set to the sprite
+ # Set to the sprite
get_node("sprite").set_texture(tex)
+
func _on_load_pressed():
if (thread.is_active()):
- #already working
+ # Already working
return
print("START THREAD!")
- thread.start(self,"_bg_load","res://mona.png")
+ thread.start(self, "_bg_load", "res://mona.png")
diff --git a/demos/misc/threads/thread.scn b/demos/misc/threads/thread.scn
index 349127529a..eea93615c7 100644
--- a/demos/misc/threads/thread.scn
+++ b/demos/misc/threads/thread.scn
Binary files differ
diff --git a/demos/misc/tween/engine.cfg b/demos/misc/tween/engine.cfg
index f97e540dbd..1d87303015 100644
--- a/demos/misc/tween/engine.cfg
+++ b/demos/misc/tween/engine.cfg
@@ -1,8 +1,8 @@
[application]
name="Tween Demo"
-main_scene="res://main.xml"
-icon="icon.png"
+main_scene="res://main.scn"
+icon="res://icon.png"
target_fps=60
[display]
diff --git a/demos/misc/tween/icon.png b/demos/misc/tween/icon.png
index 3e991fcc29..ed55c24140 100644
--- a/demos/misc/tween/icon.png
+++ b/demos/misc/tween/icon.png
Binary files differ
diff --git a/demos/misc/tween/main.gd b/demos/misc/tween/main.gd
index a0106a7682..512271311e 100644
--- a/demos/misc/tween/main.gd
+++ b/demos/misc/tween/main.gd
@@ -1,10 +1,7 @@
extends Control
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
+# Member variables
var trans = ["linear", "sine", "quint", "quart", "quad", "expo", "elastic", "cubic", "circ", "bounce", "back"]
var eases = ["in", "out", "in_out", "out_in"]
var modes = ["move", "color", "scale", "rotate", "callback", "follow", "repeat", "pause"]
@@ -14,6 +11,7 @@ var state = {
eases = Tween.EASE_IN,
}
+
func _ready():
for index in range(trans.size()):
var name = trans[index]
@@ -39,9 +37,7 @@ func _ready():
get_node("modes/repeat").set_pressed(true)
reset_tween()
-
- # Initalization here
- pass
+
func on_trans_changed(name, index):
for index in range(trans.size()):
@@ -53,7 +49,8 @@ func on_trans_changed(name, index):
state.trans = index
reset_tween()
-
+
+
func on_eases_changed(name, index):
for index in range(eases.size()):
var pressed = eases[index] == name
@@ -64,7 +61,8 @@ func on_eases_changed(name, index):
state.eases = index
reset_tween()
-
+
+
func on_modes_changed(name):
var tween = get_node("tween")
if name == "pause":
@@ -76,10 +74,12 @@ func on_modes_changed(name):
get_node("timeline").set_ignore_mouse(true)
else:
reset_tween()
-
+
+
func on_color_changed(color):
reset_tween()
-
+
+
func reset_tween():
var tween = get_node("tween")
var pos = tween.tell()
@@ -92,20 +92,20 @@ func reset_tween():
var size = get_node("tween/area").get_size()
if get_node("modes/move").is_pressed():
- tween.interpolate_method(sprite, "set_pos", Vector2(0,0), Vector2(size.width, size.height), 2, state.trans, state.eases)
- tween.interpolate_property(sprite, "transform/pos", Vector2(size.width,size.height), Vector2(0, 0), 2, state.trans, state.eases, 2)
+ tween.interpolate_method(sprite, "set_pos", Vector2(0, 0), Vector2(size.width, size.height), 2, state.trans, state.eases)
+ tween.interpolate_property(sprite, "transform/pos", Vector2(size.width, size.height), Vector2(0, 0), 2, state.trans, state.eases, 2)
if get_node("modes/color").is_pressed():
tween.interpolate_method(sprite, "set_modulate", get_node("color/color_from").get_color(), get_node("color/color_to").get_color(), 2, state.trans, state.eases)
tween.interpolate_property(sprite, "modulate", get_node("color/color_to").get_color(), get_node("color/color_from").get_color(), 2, state.trans, state.eases, 2)
else:
- sprite.set_modulate(Color(1, 1, 1, 1))
+ sprite.set_modulate(Color(1,1,1,1))
if get_node("modes/scale").is_pressed():
- tween.interpolate_method(sprite, "set_scale", Vector2(0.5,0.5), Vector2(1.5, 1.5), 2, state.trans, state.eases)
- tween.interpolate_property(sprite, "transform/scale", Vector2(1.5,1.5), Vector2(0.5, 0.5), 2, state.trans, state.eases, 2)
+ tween.interpolate_method(sprite, "set_scale", Vector2(0.5, 0.5), Vector2(1.5, 1.5), 2, state.trans, state.eases)
+ tween.interpolate_property(sprite, "transform/scale", Vector2(1.5, 1.5), Vector2(0.5, 0.5), 2, state.trans, state.eases, 2)
else:
- sprite.set_scale(Vector2(1, 1))
+ sprite.set_scale(Vector2(1,1))
if get_node("modes/rotate").is_pressed():
tween.interpolate_method(sprite, "_set_rotd", 0, 360, 2, state.trans, state.eases)
@@ -139,26 +139,27 @@ func reset_tween():
else:
tween.resume_all()
get_node("timeline").set_ignore_mouse(true)
-
-func _on_tween_step( object, key, elapsed, value ):
- var timeline = get_node("timeline")
+func _on_tween_step(object, key, elapsed, value):
+ var timeline = get_node("timeline")
+
var tween = get_node("tween")
var runtime = tween.get_runtime()
-
- var ratio = 100 * (elapsed / runtime)
- timeline.set_value(ratio)
+ var ratio = 100*(elapsed/runtime)
+ timeline.set_value(ratio)
+
-func _on_timeline_value_changed( value ):
+func _on_timeline_value_changed(value):
if !get_node("modes/pause").is_pressed():
return
var tween = get_node("tween")
var runtime = tween.get_runtime()
- tween.seek(runtime * value / 100)
-
+ tween.seek(runtime*value/100)
+
+
func on_callback(arg):
var label = get_node("tween/area/label")
label.add_text("on_callback -> " + arg + "\n")
diff --git a/demos/misc/tween/main.scn b/demos/misc/tween/main.scn
new file mode 100644
index 0000000000..3f25bfd75c
--- /dev/null
+++ b/demos/misc/tween/main.scn
Binary files differ
diff --git a/demos/misc/tween/main.xml b/demos/misc/tween/main.xml
deleted file mode 100644
index 6580ba04da..0000000000
--- a/demos/misc/tween/main.xml
+++ /dev/null
@@ -1,367 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="3" version="1.0" version_name="Godot Engine v1.0.3917-beta1">
- <ext_resource path="res://icon.png" type="Texture"></ext_resource>
- <ext_resource path="res://main.gd" type="Script"></ext_resource>
- <main_resource>
- <dictionary name="_bundled" shared="false">
- <string> "names" </string>
- <string_array len="115">
- <string> "main" </string>
- <string> "Control" </string>
- <string> "_import_path" </string>
- <string> "visibility/visible" </string>
- <string> "visibility/opacity" </string>
- <string> "visibility/self_opacity" </string>
- <string> "visibility/behind_parent" </string>
- <string> "margin/right" </string>
- <string> "margin/bottom" </string>
- <string> "transform/rot" </string>
- <string> "transform/scale" </string>
- <string> "focus_neighbour/left" </string>
- <string> "focus_neighbour/top" </string>
- <string> "focus_neighbour/right" </string>
- <string> "focus_neighbour/bottom" </string>
- <string> "focus/ignore_mouse" </string>
- <string> "focus/stop_mouse" </string>
- <string> "size_flags/horizontal" </string>
- <string> "size_flags/vertical" </string>
- <string> "size_flags/stretch_ratio" </string>
- <string> "script/script" </string>
- <string> "__meta__" </string>
- <string> "trans" </string>
- <string> "VBoxContainer" </string>
- <string> "margin/left" </string>
- <string> "margin/top" </string>
- <string> "linear" </string>
- <string> "Button" </string>
- <string> "disabled" </string>
- <string> "pressed" </string>
- <string> "toggle_mode" </string>
- <string> "click_on_press" </string>
- <string> "text" </string>
- <string> "icon" </string>
- <string> "flat" </string>
- <string> "clip_text" </string>
- <string> "align" </string>
- <string> "sine" </string>
- <string> "quint" </string>
- <string> "quart" </string>
- <string> "quad" </string>
- <string> "expo" </string>
- <string> "elastic" </string>
- <string> "cubic" </string>
- <string> "circ" </string>
- <string> "bounce" </string>
- <string> "back" </string>
- <string> "eases" </string>
- <string> "in" </string>
- <string> "out" </string>
- <string> "in_out" </string>
- <string> "out_in" </string>
- <string> "modes" </string>
- <string> "move" </string>
- <string> "color" </string>
- <string> "scale" </string>
- <string> "rotate" </string>
- <string> "callback" </string>
- <string> "follow" </string>
- <string> "repeat" </string>
- <string> "pause" </string>
- <string> "label_1" </string>
- <string> "Label" </string>
- <string> "range/min" </string>
- <string> "range/max" </string>
- <string> "range/step" </string>
- <string> "range/page" </string>
- <string> "range/value" </string>
- <string> "range/exp_edit" </string>
- <string> "rounded_values" </string>
- <string> "valign" </string>
- <string> "autowrap" </string>
- <string> "uppercase" </string>
- <string> "percent_visible" </string>
- <string> "color_from" </string>
- <string> "ColorPicker" </string>
- <string> "label_2" </string>
- <string> "color_to" </string>
- <string> "tween" </string>
- <string> "Tween" </string>
- <string> "playback/process_mode" </string>
- <string> "playback/active" </string>
- <string> "playback/repeat" </string>
- <string> "playback/speed" </string>
- <string> "area" </string>
- <string> "Panel" </string>
- <string> "label" </string>
- <string> "RichTextLabel" </string>
- <string> "scroll_active" </string>
- <string> "scroll_follow" </string>
- <string> "tab_size" </string>
- <string> "selection_enabled" </string>
- <string> "sprite" </string>
- <string> "Sprite" </string>
- <string> "transform/pos" </string>
- <string> "texture" </string>
- <string> "centered" </string>
- <string> "offset" </string>
- <string> "flip_h" </string>
- <string> "flip_v" </string>
- <string> "vframes" </string>
- <string> "hframes" </string>
- <string> "frame" </string>
- <string> "modulate" </string>
- <string> "region" </string>
- <string> "region_rect" </string>
- <string> "follow_2" </string>
- <string> "timeline" </string>
- <string> "HSlider" </string>
- <string> "tick_count" </string>
- <string> "ticks_on_borders" </string>
- <string> "_on_tween_step" </string>
- <string> "tween_step" </string>
- <string> "_on_timeline_value_changed" </string>
- <string> "value_changed" </string>
- </string_array>
- <string> "version" </string>
- <int> 1 </int>
- <string> "conn_count" </string>
- <int> 2 </int>
- <string> "node_count" </string>
- <int> 39 </int>
- <string> "variants" </string>
- <array len="104" shared="false">
- <node_path> "" </node_path>
- <bool> True </bool>
- <real> 1 </real>
- <bool> False </bool>
- <real> 800 </real>
- <real> 600 </real>
- <real> 0 </real>
- <vector2> 1, 1 </vector2>
- <int> 2 </int>
- <resource resource_type="Script" path="res://main.gd"> </resource>
- <dictionary shared="false">
- <string> "__editor_plugin_states__" </string>
- <dictionary shared="false">
- <string> "Script" </string>
- <dictionary shared="false">
- <string> "current" </string>
- <int> 0 </int>
- <string> "sources" </string>
- <array len="1" shared="false">
- <string> "res://main.gd" </string>
- </array>
- </dictionary>
- <string> "2D" </string>
- <dictionary shared="false">
- <string> "pixel_snap" </string>
- <bool> False </bool>
- <string> "zoom" </string>
- <real> 1.360374 </real>
- <string> "use_snap" </string>
- <bool> True </bool>
- <string> "ofs" </string>
- <vector2> -215.073, -20.8125 </vector2>
- <string> "snap" </string>
- <int> 8 </int>
- </dictionary>
- <string> "3D" </string>
- <dictionary shared="false">
- <string> "zfar" </string>
- <real> 500 </real>
- <string> "fov" </string>
- <real> 45 </real>
- <string> "viewports" </string>
- <array len="4" shared="false">
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- </array>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
- <string> "znear" </string>
- <real> 0.1 </real>
- </dictionary>
- </dictionary>
- <string> "__editor_run_settings__" </string>
- <dictionary shared="false">
- <string> "custom_args" </string>
- <string> "-l $scene" </string>
- <string> "run_mode" </string>
- <int> 0 </int>
- </dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "Script" </string>
- </dictionary>
- <real> 56 </real>
- <real> 256 </real>
- <real> 129 </real>
- <real> 582 </real>
- <dictionary shared="false">
- <string> "_editor_collapsed" </string>
- <bool> True </bool>
- </dictionary>
- <real> 73 </real>
- <real> 26 </real>
- <string> "linear" </string>
- <resource name=""></resource> <int> 1 </int>
- <real> 30 </real>
- <string> "sine" </string>
- <real> 60 </real>
- <real> 86 </real>
- <string> "quint" </string>
- <real> 90 </real>
- <real> 116 </real>
- <string> "quart" </string>
- <real> 120 </real>
- <real> 146 </real>
- <string> "quad" </string>
- <real> 150 </real>
- <real> 176 </real>
- <string> "expo" </string>
- <real> 180 </real>
- <real> 206 </real>
- <string> "elastic" </string>
- <real> 210 </real>
- <real> 236 </real>
- <string> "cubic" </string>
- <real> 240 </real>
- <real> 266 </real>
- <string> "circ" </string>
- <real> 270 </real>
- <real> 296 </real>
- <string> "bounce" </string>
- <real> 300 </real>
- <real> 326 </real>
- <string> "back" </string>
- <real> 152 </real>
- <real> 215 </real>
- <real> 372 </real>
- <dictionary shared="false">
- <string> "_editor_collapsed" </string>
- <bool> True </bool>
- </dictionary>
- <real> 63 </real>
- <string> "in" </string>
- <string> "out" </string>
- <string> "in_out" </string>
- <string> "out_in" </string>
- <real> 317 </real>
- <real> 492 </real>
- <dictionary shared="false">
- <string> "_editor_collapsed" </string>
- <bool> True </bool>
- </dictionary>
- <real> 77 </real>
- <string> "move" </string>
- <string> "color" </string>
- <string> "scale" </string>
- <string> "rotate" </string>
- <string> "callback" </string>
- <string> "follow" </string>
- <string> "repeat" </string>
- <string> "pause" </string>
- <real> 384 </real>
- <real> 760 </real>
- <real> 592 </real>
- <dictionary shared="false">
- <string> "_editor_collapsed" </string>
- <bool> True </bool>
- </dictionary>
- <real> 376 </real>
- <real> 19 </real>
- <string> "Color From:" </string>
- <int> 0 </int>
- <real> -1 </real>
- <real> 23 </real>
- <real> 174 </real>
- <real> 178 </real>
- <real> 197 </real>
- <string> "Color To:" </string>
- <real> 201 </real>
- <real> 352 </real>
- <real> 32 </real>
- <real> 768 </real>
- <real> 216 </real>
- <real> 24 </real>
- <real> 552 </real>
- <real> 160 </real>
- <string> "" </string>
- <int> 4 </int>
- <vector2> 0, 0 </vector2>
- <resource resource_type="Texture" path="res://icon.png"> </resource>
- <color> 1, 1, 1, 1 </color>
- <rect2> 0, 0, 0, 0 </rect2>
- <vector2> 0, 184 </vector2>
- <vector2> 736, 0 </vector2>
- <real> 40 </real>
- <real> 224 </real>
- <real> 100 </real>
- </array>
- <string> "nodes" </string>
- <int_array len="2229"> -1, -1, 1, 0, -1, 20, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 4, 8, 5, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 1, 17, 8, 18, 8, 19, 2, 20, 9, 21, 10, 0, 0, 0, 23, 22, -1, 21, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 24, 11, 25, 12, 7, 13, 8, 14, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 3, 17, 8, 18, 8, 19, 2, 21, 15, 0, 1, 0, 27, 26, -1, 27, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 16, 8, 17, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 1, 17, 8, 18, 8, 19, 2, 28, 3, 29, 3, 30, 1, 31, 3, 32, 18, 33, 19, 34, 3, 35, 3, 36, 20, 0, 1, 0, 27, 37, -1, 28, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 25, 21, 7, 16, 8, 11, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 1, 17, 8, 18, 8, 19, 2, 28, 3, 29, 3, 30, 1, 31, 3, 32, 22, 33, 19, 34, 3, 35, 3, 36, 20, 0, 1, 0, 27, 38, -1, 28, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 25, 23, 7, 16, 8, 24, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 1, 17, 8, 18, 8, 19, 2, 28, 3, 29, 3, 30, 1, 31, 3, 32, 25, 33, 19, 34, 3, 35, 3, 36, 20, 0, 1, 0, 27, 39, -1, 28, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 25, 26, 7, 16, 8, 27, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 1, 17, 8, 18, 8, 19, 2, 28, 3, 29, 3, 30, 1, 31, 3, 32, 28, 33, 19, 34, 3, 35, 3, 36, 20, 0, 1, 0, 27, 40, -1, 28, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 25, 29, 7, 16, 8, 30, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 1, 17, 8, 18, 8, 19, 2, 28, 3, 29, 3, 30, 1, 31, 3, 32, 31, 33, 19, 34, 3, 35, 3, 36, 20, 0, 1, 0, 27, 41, -1, 28, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 25, 32, 7, 16, 8, 33, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 1, 17, 8, 18, 8, 19, 2, 28, 3, 29, 3, 30, 1, 31, 3, 32, 34, 33, 19, 34, 3, 35, 3, 36, 20, 0, 1, 0, 27, 42, -1, 28, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 25, 35, 7, 16, 8, 36, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 1, 17, 8, 18, 8, 19, 2, 28, 3, 29, 3, 30, 1, 31, 3, 32, 37, 33, 19, 34, 3, 35, 3, 36, 20, 0, 1, 0, 27, 43, -1, 28, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 25, 38, 7, 16, 8, 39, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 1, 17, 8, 18, 8, 19, 2, 28, 3, 29, 3, 30, 1, 31, 3, 32, 40, 33, 19, 34, 3, 35, 3, 36, 20, 0, 1, 0, 27, 44, -1, 28, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 25, 41, 7, 16, 8, 42, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 1, 17, 8, 18, 8, 19, 2, 28, 3, 29, 3, 30, 1, 31, 3, 32, 43, 33, 19, 34, 3, 35, 3, 36, 20, 0, 1, 0, 27, 45, -1, 28, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 25, 44, 7, 16, 8, 45, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 1, 17, 8, 18, 8, 19, 2, 28, 3, 29, 3, 30, 1, 31, 3, 32, 46, 33, 19, 34, 3, 35, 3, 36, 20, 0, 1, 0, 27, 46, -1, 28, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 25, 47, 7, 16, 8, 48, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 1, 17, 8, 18, 8, 19, 2, 28, 3, 29, 3, 30, 1, 31, 3, 32, 49, 33, 19, 34, 3, 35, 3, 36, 20, 0, 0, 0, 23, 47, -1, 21, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 24, 50, 25, 12, 7, 51, 8, 52, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 3, 17, 8, 18, 8, 19, 2, 21, 53, 0, 13, 0, 27, 48, -1, 27, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 54, 8, 17, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 1, 17, 8, 18, 8, 19, 2, 28, 3, 29, 3, 30, 1, 31, 3, 32, 55, 33, 19, 34, 3, 35, 3, 36, 20, 0, 13, 0, 27, 49, -1, 28, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 25, 21, 7, 54, 8, 11, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 1, 17, 8, 18, 8, 19, 2, 28, 3, 29, 3, 30, 1, 31, 3, 32, 56, 33, 19, 34, 3, 35, 3, 36, 20, 0, 13, 0, 27, 50, -1, 28, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 25, 23, 7, 54, 8, 24, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 1, 17, 8, 18, 8, 19, 2, 28, 3, 29, 3, 30, 1, 31, 3, 32, 57, 33, 19, 34, 3, 35, 3, 36, 20, 0, 13, 0, 27, 51, -1, 28, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 25, 26, 7, 54, 8, 27, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 1, 17, 8, 18, 8, 19, 2, 28, 3, 29, 3, 30, 1, 31, 3, 32, 58, 33, 19, 34, 3, 35, 3, 36, 20, 0, 0, 0, 23, 52, -1, 21, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 24, 41, 25, 12, 7, 59, 8, 60, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 3, 17, 8, 18, 8, 19, 2, 21, 61, 0, 18, 0, 27, 53, -1, 27, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 62, 8, 17, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 1, 17, 8, 18, 8, 19, 2, 28, 3, 29, 3, 30, 1, 31, 3, 32, 63, 33, 19, 34, 3, 35, 3, 36, 20, 0, 18, 0, 27, 54, -1, 28, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 25, 21, 7, 62, 8, 11, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 1, 17, 8, 18, 8, 19, 2, 28, 3, 29, 3, 30, 1, 31, 3, 32, 64, 33, 19, 34, 3, 35, 3, 36, 20, 0, 18, 0, 27, 55, -1, 28, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 25, 23, 7, 62, 8, 24, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 1, 17, 8, 18, 8, 19, 2, 28, 3, 29, 3, 30, 1, 31, 3, 32, 65, 33, 19, 34, 3, 35, 3, 36, 20, 0, 18, 0, 27, 56, -1, 28, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 25, 26, 7, 62, 8, 27, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 1, 17, 8, 18, 8, 19, 2, 28, 3, 29, 3, 30, 1, 31, 3, 32, 66, 33, 19, 34, 3, 35, 3, 36, 20, 0, 18, 0, 27, 57, -1, 28, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 25, 29, 7, 62, 8, 30, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 1, 17, 8, 18, 8, 19, 2, 28, 3, 29, 3, 30, 1, 31, 3, 32, 67, 33, 19, 34, 3, 35, 3, 36, 20, 0, 18, 0, 27, 58, -1, 28, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 25, 32, 7, 62, 8, 33, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 1, 17, 8, 18, 8, 19, 2, 28, 3, 29, 3, 30, 1, 31, 3, 32, 68, 33, 19, 34, 3, 35, 3, 36, 20, 0, 18, 0, 27, 59, -1, 28, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 25, 35, 7, 62, 8, 36, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 1, 17, 8, 18, 8, 19, 2, 28, 3, 29, 3, 30, 1, 31, 3, 32, 69, 33, 19, 34, 3, 35, 3, 36, 20, 0, 18, 0, 27, 60, -1, 28, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 25, 38, 7, 62, 8, 39, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 1, 17, 8, 18, 8, 19, 2, 28, 3, 29, 3, 30, 1, 31, 3, 32, 70, 33, 19, 34, 3, 35, 3, 36, 20, 0, 0, 0, 23, 54, -1, 21, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 24, 71, 25, 41, 7, 72, 8, 73, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 3, 17, 8, 18, 8, 19, 2, 21, 74, 0, 27, 0, 62, 61, -1, 30, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 7, 75, 8, 76, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 1, 16, 1, 17, 8, 19, 2, 63, 6, 64, 2, 65, 2, 66, 2, 67, 6, 68, 3, 69, 3, 32, 77, 36, 78, 70, 78, 71, 3, 72, 3, 73, 79, 0, 27, 0, 75, 74, -1, 19, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 25, 80, 7, 75, 8, 81, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 3, 17, 8, 18, 8, 19, 2, 0, 27, 0, 62, 76, -1, 31, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 25, 82, 7, 75, 8, 83, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 1, 16, 1, 17, 8, 19, 2, 63, 6, 64, 2, 65, 2, 66, 2, 67, 6, 68, 3, 69, 3, 32, 84, 36, 78, 70, 78, 71, 3, 72, 3, 73, 79, 0, 27, 0, 75, 77, -1, 19, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 25, 85, 7, 75, 8, 86, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 3, 17, 8, 18, 8, 19, 2, 0, 0, 0, 79, 78, -1, 5, 2, 0, 80, 20, 81, 1, 82, 1, 83, 2, 0, 32, 0, 85, 84, -1, 20, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 24, 87, 25, 87, 7, 88, 8, 89, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 1, 17, 8, 18, 8, 19, 2, 0, 33, 0, 87, 86, -1, 24, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 24, 33, 25, 90, 7, 91, 8, 92, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 1, 17, 8, 19, 2, 32, 93, 88, 1, 89, 1, 90, 94, 91, 3, 0, 33, 0, 93, 92, -1, 19, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 94, 95, 9, 6, 10, 7, 95, 96, 96, 1, 97, 95, 98, 3, 99, 3, 100, 20, 101, 20, 102, 78, 103, 97, 104, 3, 105, 98, 0, 33, 0, 93, 58, -1, 19, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 94, 99, 9, 6, 10, 7, 95, 96, 96, 1, 97, 95, 98, 3, 99, 3, 100, 20, 101, 20, 102, 78, 103, 97, 104, 3, 105, 98, 0, 33, 0, 93, 106, -1, 19, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 94, 100, 9, 6, 10, 7, 95, 96, 96, 1, 97, 95, 98, 3, 99, 3, 100, 20, 101, 20, 102, 78, 103, 97, 104, 3, 105, 98, 0, 0, 0, 108, 107, -1, 28, 2, 0, 3, 1, 4, 2, 5, 2, 6, 3, 24, 101, 25, 102, 7, 72, 8, 41, 9, 6, 10, 7, 11, 0, 12, 0, 13, 0, 14, 0, 15, 3, 16, 1, 17, 8, 19, 2, 63, 6, 64, 103, 65, 2, 66, 6, 67, 2, 68, 3, 69, 3, 109, 78, 110, 3, 0 </int_array>
- <string> "conns" </string>
- <int_array len="12"> 32, 0, 112, 111, 2, 0, 38, 0, 114, 113, 2, 0 </int_array>
- </dictionary>
-
- </main_resource>
-</resource_file>
diff --git a/demos/misc/udp_chat/chat.gd b/demos/misc/udp_chat/chat.gd
index 3270eebbfe..b60afa9ded 100644
--- a/demos/misc/udp_chat/chat.gd
+++ b/demos/misc/udp_chat/chat.gd
@@ -1,72 +1,66 @@
extends Panel
-# Really simple UDP chat client, not intended as a chat example!!
+# Really simple UDP chat client, not intended as a comprehensive chat implementation.
# (UDP can lose packets and you won't normally find out, so don't do a chat this way)
# This is just a demo that shows how to use the UDP class.
+# Member variables
var udp = PacketPeerUDP.new()
-func _process(delta):
+func _process(delta):
if (not udp.is_listening()):
return
-
- while(udp.get_available_packet_count()>0):
+
+ while(udp.get_available_packet_count() > 0):
var packet = udp.get_var()
- if (typeof(packet)==TYPE_STRING):
+ if (typeof(packet) == TYPE_STRING):
var host = udp.get_packet_ip()
var port = udp.get_packet_port()
- get_node("chat/text").add_text("("+host+":"+str(port)+":) "+packet)
+ get_node("chat/text").add_text("(" + host + ":" + str(port) + ":) " + packet)
get_node("chat/text").newline()
-
-
+
func _ready():
- # Initalization here
- get_node("chat").add_style_override("panel",get_stylebox("bg","Tree"))
+ get_node("chat").add_style_override("panel", get_stylebox("bg", "Tree"))
set_process(true)
-
func send_message(text):
if (udp.is_listening()):
udp.put_var(text)
-
-
-func _on_connect_toggled( pressed ):
+func _on_connect_toggled(pressed):
if (pressed):
- var err = udp.listen( get_node("listen_port").get_val() )
- if (err!=OK):
- get_node("status").set_text("Error:\nCan't Listen.")
+ var err = udp.listen(get_node("listen_port").get_val())
+ if (err != OK):
+ get_node("status").set_text("Error:\nCan't listen.")
get_node("connect").set_pressed(false)
else:
get_node("status").set_text("Connected.")
get_node("connect").set_text("Disconnect")
err = udp.set_send_address(get_node("remote_host").get_text(),get_node("remote_port").get_val())
- if (err!=OK):
- get_node("status").set_text("Error:\nCan't Resolve.")
+ if (err != OK):
+ get_node("status").set_text("Error:\nCan't resolve.")
get_node("connect").set_pressed(false)
else:
- send_message("* "+get_node("user_name").get_text()+" entered chat.")
+ send_message("* " + get_node("user_name").get_text() + " entered chat.")
else:
-
udp.close()
get_node("status").set_text("Disconnected.")
get_node("connect").set_text("Connect")
-
+func _on_entry_line_text_entered(text):
+ _on_entry_button_pressed()
-func _on_entry_line_text_entered( text ):
- _on_entry_button_pressed();
func _on_entry_button_pressed():
var msg = get_node("entry_line").get_text()
- if (msg==""):
+ if (msg == ""):
return
- send_message(get_node("user_name").get_text()+"> "+msg)
+ send_message(get_node("user_name").get_text() + "> " + msg)
get_node("entry_line").set_text("")
diff --git a/demos/misc/udp_chat/chat.scn b/demos/misc/udp_chat/chat.scn
index efa4b799a0..fe38e9da72 100644
--- a/demos/misc/udp_chat/chat.scn
+++ b/demos/misc/udp_chat/chat.scn
Binary files differ
diff --git a/demos/misc/window_management/control.gd b/demos/misc/window_management/control.gd
index 1609dda699..cd8e0e185b 100644
--- a/demos/misc/window_management/control.gd
+++ b/demos/misc/window_management/control.gd
@@ -1,17 +1,18 @@
extends Control
+# Member variables
var mousepos
-func _fixed_process(delta):
+func _fixed_process(delta):
var modetext = "Mode:\n"
if(OS.is_window_fullscreen()):
modetext += "Fullscreen\n"
else:
modetext += "Windowed\n"
-
+
if(!OS.is_window_resizable()):
modetext += "FixedSize\n"
@@ -29,119 +30,119 @@ func _fixed_process(delta):
get_node("Label_Mode").set_text(modetext)
- get_node("Label_Position").set_text( str("Position:\n", OS.get_window_position() ) )
+ get_node("Label_Position").set_text(str("Position:\n", OS.get_window_position()))
- get_node("Label_Size").set_text(str("Size:\n", OS.get_window_size() ) )
+ get_node("Label_Size").set_text(str("Size:\n", OS.get_window_size()))
- get_node("Label_MousePosition").set_text(str("Mouse Position:\n", mousepos ) )
+ get_node("Label_MousePosition").set_text(str("Mouse Position:\n", mousepos))
- get_node("Label_Screen_Count").set_text( str("Screen_Count:\n", OS.get_screen_count() ) )
+ get_node("Label_Screen_Count").set_text(str("Screen_Count:\n", OS.get_screen_count()))
- get_node("Label_Screen_Current").set_text( str("Screen:\n", OS.get_current_screen() ) )
+ get_node("Label_Screen_Current").set_text(str("Screen:\n", OS.get_current_screen()))
- get_node("Label_Screen0_Resolution").set_text( str("Screen0 Resolution:\n", OS.get_screen_size() ) )
+ get_node("Label_Screen0_Resolution").set_text(str("Screen0 Resolution:\n", OS.get_screen_size()))
- get_node("Label_Screen0_Position").set_text(str("Screen0 Position:\n",OS.get_screen_position() ) )
+ get_node("Label_Screen0_Position").set_text(str("Screen0 Position:\n", OS.get_screen_position()))
if(OS.get_screen_count() > 1):
get_node("Button_Screen0").show()
get_node("Button_Screen1").show()
get_node("Label_Screen1_Resolution").show()
get_node("Label_Screen1_Position").show()
- get_node("Label_Screen1_Resolution").set_text( str("Screen1 Resolution:\n", OS.get_screen_size(1) ) )
- get_node("Label_Screen1_Position").set_text( str("Screen1 Position:\n", OS.get_screen_position(1) ) )
+ get_node("Label_Screen1_Resolution").set_text(str("Screen1 Resolution:\n", OS.get_screen_size(1)))
+ get_node("Label_Screen1_Position").set_text(str("Screen1 Position:\n", OS.get_screen_position(1)))
else:
get_node("Button_Screen0").hide()
get_node("Button_Screen1").hide()
get_node("Label_Screen1_Resolution").hide()
get_node("Label_Screen1_Position").hide()
-
- get_node("Button_Fullscreen").set_pressed( OS.is_window_fullscreen() )
- get_node("Button_FixedSize").set_pressed( !OS.is_window_resizable() )
- get_node("Button_Minimized").set_pressed( OS.is_window_minimized() )
- get_node("Button_Maximized").set_pressed( OS.is_window_maximized() )
- get_node("Button_Mouse_Grab").set_pressed( Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED )
+
+ get_node("Button_Fullscreen").set_pressed(OS.is_window_fullscreen())
+ get_node("Button_FixedSize").set_pressed(!OS.is_window_resizable())
+ get_node("Button_Minimized").set_pressed(OS.is_window_minimized())
+ get_node("Button_Maximized").set_pressed(OS.is_window_maximized())
+ get_node("Button_Mouse_Grab").set_pressed(Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED)
func check_wm_api():
var s = ""
- if( !OS.has_method("get_screen_count") ):
+ if(!OS.has_method("get_screen_count")):
s += " - get_screen_count()\n"
- if( !OS.has_method("get_current_screen") ):
+ if(!OS.has_method("get_current_screen")):
s += " - get_current_screen()\n"
- if( !OS.has_method("set_current_screen") ):
+ if(!OS.has_method("set_current_screen")):
s += " - set_current_screen()\n"
- if( !OS.has_method("get_screen_position") ):
+ if(!OS.has_method("get_screen_position")):
s += " - get_screen_position()\n"
- if( !OS.has_method("get_screen_size") ):
+ if(!OS.has_method("get_screen_size")):
s += " - get_screen_size()\n"
- if( !OS.has_method("get_window_position") ):
+ if(!OS.has_method("get_window_position")):
s += " - get_window_position()\n"
- if( !OS.has_method("set_window_position") ):
+ if(!OS.has_method("set_window_position")):
s += " - set_window_position()\n"
- if( !OS.has_method("get_window_size") ):
+ if(!OS.has_method("get_window_size")):
s += " - get_window_size()\n"
- if( !OS.has_method("set_window_size") ):
+ if(!OS.has_method("set_window_size")):
s += " - set_window_size()\n"
- if( !OS.has_method("set_window_fullscreen") ):
+ if(!OS.has_method("set_window_fullscreen")):
s += " - set_window_fullscreen()\n"
- if( !OS.has_method("is_window_fullscreen") ):
+ if(!OS.has_method("is_window_fullscreen")):
s += " - is_window_fullscreen()\n"
- if( !OS.has_method("set_window_resizable") ):
+ if(!OS.has_method("set_window_resizable")):
s += " - set_window_resizable()\n"
- if( !OS.has_method("is_window_resizable") ):
+ if(!OS.has_method("is_window_resizable")):
s += " - is_window_resizable()\n"
- if( !OS.has_method("set_window_minimized") ):
+ if(!OS.has_method("set_window_minimized")):
s += " - set_window_minimized()\n"
- if( !OS.has_method("is_window_minimized") ):
+ if(!OS.has_method("is_window_minimized")):
s += " - is_window_minimized()\n"
- if( !OS.has_method("set_window_maximized") ):
+ if(!OS.has_method("set_window_maximized")):
s += " - set_window_maximized()\n"
- if( !OS.has_method("is_window_maximized") ):
+ if(!OS.has_method("is_window_maximized")):
s += " - is_window_maximized()\n"
- if( s.length() == 0 ):
+ if(s.length() == 0):
return true
else:
var text = get_node("ImplementationDialog/Text").get_text()
- get_node("ImplementationDialog/Text").set_text( text + s )
+ get_node("ImplementationDialog/Text").set_text(text + s)
get_node("ImplementationDialog").show()
return false
func _ready():
- if( check_wm_api() ):
+ if(check_wm_api()):
set_fixed_process(true)
set_process_input(true)
-func _input(ev):
- if (ev.type==InputEvent.MOUSE_MOTION):
- mousepos = ev.pos
+func _input(event):
+ if (event.type == InputEvent.MOUSE_MOTION):
+ mousepos = event.pos
func _on_Button_MoveTo_pressed():
- OS.set_window_position( Vector2(100,100) )
+ OS.set_window_position(Vector2(100, 100))
func _on_Button_Resize_pressed():
- OS.set_window_size( Vector2(1024,768) )
+ OS.set_window_size(Vector2(1024, 768))
func _on_Button_Screen0_pressed():
diff --git a/demos/misc/window_management/engine.cfg b/demos/misc/window_management/engine.cfg
index 0a34231673..911d3fd4a1 100644
--- a/demos/misc/window_management/engine.cfg
+++ b/demos/misc/window_management/engine.cfg
@@ -2,7 +2,7 @@
name="Window Management"
main_scene="res://window_management.scn"
-icon="icon.png"
+icon="res://icon.png"
[display]
diff --git a/demos/misc/window_management/icon.png b/demos/misc/window_management/icon.png
index 0c422e37b0..ec5c7891f9 100644
--- a/demos/misc/window_management/icon.png
+++ b/demos/misc/window_management/icon.png
Binary files differ
diff --git a/demos/misc/window_management/icon.png.flags b/demos/misc/window_management/icon.png.flags
deleted file mode 100644
index 5130fd1aab..0000000000
--- a/demos/misc/window_management/icon.png.flags
+++ /dev/null
@@ -1 +0,0 @@
-gen_mipmaps=false
diff --git a/demos/misc/window_management/observer/observer.gd b/demos/misc/window_management/observer/observer.gd
index d27912a670..f100811859 100644
--- a/demos/misc/window_management/observer/observer.gd
+++ b/demos/misc/window_management/observer/observer.gd
@@ -1,16 +1,17 @@
extends Spatial
+# Member variables
var r_pos = Vector2()
var state
-const STATE_MENU=0
-const STATE_GRAB=1
+const STATE_MENU = 0
+const STATE_GRAB = 1
+
func direction(vector):
- var v = get_node("Camera").get_global_transform().basis * vector
+ var v = get_node("Camera").get_global_transform().basis*vector
v = v.normalized()
-
return v
@@ -22,43 +23,42 @@ func impulse(event, action):
func _fixed_process(delta):
-
if(state != STATE_GRAB):
return
if(Input.get_mouse_mode() != Input.MOUSE_MODE_CAPTURED):
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
- var dir = Vector3()
+ var dir = Vector3()
var cam = get_global_transform()
var org = get_translation()
if (Input.is_action_pressed("move_forward")):
- dir += direction(Vector3(0,0,-1))
+ dir += direction(Vector3(0, 0, -1))
if (Input.is_action_pressed("move_backwards")):
- dir += direction(Vector3(0,0,1))
+ dir += direction(Vector3(0, 0, 1))
if (Input.is_action_pressed("move_left")):
- dir += direction(Vector3(-1,0,0))
+ dir += direction(Vector3(-1, 0, 0))
if (Input.is_action_pressed("move_right")):
- dir += direction(Vector3(1,0,0))
+ dir += direction(Vector3(1, 0, 0))
dir = dir.normalized()
- move(dir * 10 * delta)
- var d = delta * 0.1
+ move(dir*10*delta)
+ var d = delta*0.1
- var yaw = get_transform().rotated(Vector3(0,1,0), d * r_pos.x)
+ var yaw = get_transform().rotated(Vector3(0, 1, 0), d*r_pos.x)
set_transform(yaw)
var cam = get_node("Camera")
- var pitch = cam.get_transform().rotated(Vector3(1,0,0), d * r_pos.y)
+ var pitch = cam.get_transform().rotated(Vector3(1, 0, 0), d*r_pos.y)
cam.set_transform(pitch)
r_pos.x = 0.0
r_pos.y = 0.0
-func _input( event ):
+func _input(event):
if(event.type == InputEvent.MOUSE_MOTION):
r_pos = event.relative_pos
@@ -76,4 +76,3 @@ func _ready():
set_process_input(true)
state = STATE_MENU
-
diff --git a/demos/misc/window_management/observer/observer.scn b/demos/misc/window_management/observer/observer.scn
index da29ad62b8..813d7d4587 100644
--- a/demos/misc/window_management/observer/observer.scn
+++ b/demos/misc/window_management/observer/observer.scn
Binary files differ
diff --git a/demos/misc/window_management/window_management.scn b/demos/misc/window_management/window_management.scn
index 8db43b6638..35662871f1 100644
--- a/demos/misc/window_management/window_management.scn
+++ b/demos/misc/window_management/window_management.scn
Binary files differ
diff --git a/demos/viewport/2d_in_3d/pong.gd b/demos/viewport/2d_in_3d/pong.gd
index bfffdcf0d8..ac3457453b 100644
--- a/demos/viewport/2d_in_3d/pong.gd
+++ b/demos/viewport/2d_in_3d/pong.gd
@@ -1,73 +1,66 @@
extends Node2D
-# member variables here, example:
-# var a=2
-# var b="textvar"
+# Member variables
const INITIAL_BALL_SPEED = 80
var ball_speed = INITIAL_BALL_SPEED
-var screen_size = Vector2(640,400)
-#default ball direction
-var direction = Vector2(-1,0)
-var pad_size = Vector2(8,32)
+var screen_size = Vector2(640, 400)
+# Default ball direction
+var direction = Vector2(-1, 0)
+var pad_size = Vector2(8, 32)
const PAD_SPEED = 150
func _process(delta):
-
-
- # get ball positio and pad rectangles
+ # Get ball position and pad rectangles
var ball_pos = get_node("ball").get_pos()
- var left_rect = Rect2( get_node("left").get_pos() - pad_size*0.5, pad_size )
- var right_rect = Rect2( get_node("right").get_pos() - pad_size*0.5, pad_size )
+ var left_rect = Rect2(get_node("left").get_pos() - pad_size*0.5, pad_size)
+ var right_rect = Rect2(get_node("right").get_pos() - pad_size*0.5, pad_size)
- #integrate new ball postion
- ball_pos+=direction*ball_speed*delta
+ # Integrate new ball postion
+ ball_pos += direction*ball_speed*delta
- #flip when touching roof or floor
- if ( (ball_pos.y<0 and direction.y <0) or (ball_pos.y>screen_size.y and direction.y>0)):
+ # Flip when touching roof or floor
+ if ((ball_pos.y < 0 and direction.y < 0) or (ball_pos.y > screen_size.y and direction.y > 0)):
direction.y = -direction.y
-
- #flip, change direction and increase speed when touching pads
- if ( (left_rect.has_point(ball_pos) and direction.x < 0) or (right_rect.has_point(ball_pos) and direction.x > 0)):
- direction.x=-direction.x
- ball_speed*=1.1
- direction.y=randf()*2.0-1
+
+ # Flip, change direction and increase speed when touching pads
+ if ((left_rect.has_point(ball_pos) and direction.x < 0) or (right_rect.has_point(ball_pos) and direction.x > 0)):
+ direction.x = -direction.x
+ ball_speed *= 1.1
+ direction.y = randf()*2.0 - 1
direction = direction.normalized()
-
- #check gameover
- if (ball_pos.x<0 or ball_pos.x>screen_size.x):
- ball_pos=screen_size*0.5
- ball_speed=INITIAL_BALL_SPEED
- direction=Vector2(-1,0)
-
-
+
+ # Check gameover
+ if (ball_pos.x < 0 or ball_pos.x > screen_size.x):
+ ball_pos = screen_size*0.5
+ ball_speed = INITIAL_BALL_SPEED
+ direction = Vector2(-1, 0)
+
get_node("ball").set_pos(ball_pos)
-
- #move left pad
+
+ # Move left pad
var left_pos = get_node("left").get_pos()
if (left_pos.y > 0 and Input.is_action_pressed("left_move_up")):
- left_pos.y+=-PAD_SPEED*delta
+ left_pos.y += -PAD_SPEED*delta
if (left_pos.y < screen_size.y and Input.is_action_pressed("left_move_down")):
- left_pos.y+=PAD_SPEED*delta
-
+ left_pos.y += PAD_SPEED*delta
+
get_node("left").set_pos(left_pos)
-
- #move right pad
+
+ # Move right pad
var right_pos = get_node("right").get_pos()
if (right_pos.y > 0 and Input.is_action_pressed("right_move_up")):
- right_pos.y+=-PAD_SPEED*delta
+ right_pos.y += -PAD_SPEED*delta
if (right_pos.y < screen_size.y and Input.is_action_pressed("right_move_down")):
- right_pos.y+=PAD_SPEED*delta
-
- get_node("right").set_pos(right_pos)
+ right_pos.y += PAD_SPEED*delta
-
+ get_node("right").set_pos(right_pos)
+
func _ready():
- screen_size = get_viewport_rect().size # get actual size
+ screen_size = get_viewport_rect().size # Get actual size
pad_size = get_node("left").get_texture().get_size()
set_process(true)
-
diff --git a/demos/viewport/2d_in_3d/pong.scn b/demos/viewport/2d_in_3d/pong.scn
new file mode 100644
index 0000000000..559e2f96bc
--- /dev/null
+++ b/demos/viewport/2d_in_3d/pong.scn
Binary files differ
diff --git a/demos/viewport/2d_in_3d/pong.xml b/demos/viewport/2d_in_3d/pong.xml
deleted file mode 100644
index cf47a8db9f..0000000000
--- a/demos/viewport/2d_in_3d/pong.xml
+++ /dev/null
@@ -1,183 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" subresource_count="6" version="0.99" version_name="Godot Engine v0.99.3735-pre-beta">
- <ext_resource path="res://pong.*" type="GDScript"></ext_resource>
- <ext_resource path="res://separator.*" type="ImageTexture"></ext_resource>
- <ext_resource path="res://left_pallete.*" type="ImageTexture"></ext_resource>
- <ext_resource path="res://right_pallete.*" type="ImageTexture"></ext_resource>
- <ext_resource path="res://ball.*" type="ImageTexture"></ext_resource>
- <main_resource>
- <dictionary name="_bundled" shared="false">
- <string> "names" </string>
- <string_array len="27">
- <string> "game" </string>
- <string> "Node2D" </string>
- <string> "visibility/visible" </string>
- <string> "visibility/opacity" </string>
- <string> "visibility/self_opacity" </string>
- <string> "visibility/on_top" </string>
- <string> "transform/pos" </string>
- <string> "transform/rot" </string>
- <string> "transform/scale" </string>
- <string> "script/script" </string>
- <string> "__meta__" </string>
- <string> "left" </string>
- <string> "Sprite" </string>
- <string> "texture" </string>
- <string> "centered" </string>
- <string> "offset" </string>
- <string> "flip_h" </string>
- <string> "flip_v" </string>
- <string> "vframes" </string>
- <string> "hframes" </string>
- <string> "frame" </string>
- <string> "modulate" </string>
- <string> "region" </string>
- <string> "region_rect" </string>
- <string> "right" </string>
- <string> "separator" </string>
- <string> "ball" </string>
- </string_array>
- <string> "version" </string>
- <int> 1 </int>
- <string> "conn_count" </string>
- <int> 0 </int>
- <string> "node_count" </string>
- <int> 5 </int>
- <string> "variants" </string>
- <array len="20" shared="false">
- <bool> True </bool>
- <real> 1 </real>
- <vector2> 0, 0 </vector2>
- <real> 0 </real>
- <vector2> 1, 1 </vector2>
- <resource resource_type="GDScript" path="res://pong.*"> </resource>
- <dictionary shared="false">
- <string> "__editor_plugin_states__" </string>
- <dictionary shared="false">
- <string> "Script" </string>
- <dictionary shared="false">
- <string> "current" </string>
- <int> 0 </int>
- <string> "sources" </string>
- <array len="1" shared="false">
- <string> "res://pong.gd" </string>
- </array>
- </dictionary>
- <string> "2D" </string>
- <dictionary shared="false">
- <string> "pixel_snap" </string>
- <bool> True </bool>
- <string> "zoom" </string>
- <real> 1.108033 </real>
- <string> "ofs" </string>
- <vector2> -54.59, -36.0052 </vector2>
- </dictionary>
- <string> "3D" </string>
- <dictionary shared="false">
- <string> "zfar" </string>
- <real> 500 </real>
- <string> "fov" </string>
- <real> 45 </real>
- <string> "viewports" </string>
- <array len="4" shared="false">
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- </array>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
- <string> "znear" </string>
- <real> 0.1 </real>
- </dictionary>
- </dictionary>
- <string> "__editor_run_settings__" </string>
- <dictionary shared="false">
- <string> "custom_args" </string>
- <string> "-l $scene" </string>
- <string> "run_mode" </string>
- <int> 0 </int>
- </dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "Script" </string>
- </dictionary>
- <vector2> 67.6875, 183.208 </vector2>
- <resource resource_type="ImageTexture" path="res://left_pallete.*"> </resource>
- <bool> False </bool>
- <int> 1 </int>
- <int> 0 </int>
- <color> 1, 1, 1, 1 </color>
- <rect2> 0, 0, 0, 0 </rect2>
- <vector2> 577, 187 </vector2>
- <resource resource_type="ImageTexture" path="res://right_pallete.*"> </resource>
- <vector2> 320, 200 </vector2>
- <resource resource_type="ImageTexture" path="res://separator.*"> </resource>
- <vector2> 320.283, 188 </vector2>
- <resource resource_type="ImageTexture" path="res://ball.*"> </resource>
- </array>
- <string> "nodes" </string>
- <int_array len="197"> -1, -1, 1, 0, -1, 9, 2, 0, 3, 1, 4, 1, 5, 0, 6, 2, 7, 3, 8, 4, 9, 5, 10, 6, 0, 0, 0, 12, 11, -1, 18, 2, 0, 3, 1, 4, 1, 5, 0, 6, 7, 7, 3, 8, 4, 13, 8, 14, 0, 15, 2, 16, 9, 17, 9, 18, 10, 19, 10, 20, 11, 21, 12, 22, 9, 23, 13, 0, 0, 0, 12, 24, -1, 18, 2, 0, 3, 1, 4, 1, 5, 0, 6, 14, 7, 3, 8, 4, 13, 15, 14, 0, 15, 2, 16, 9, 17, 9, 18, 10, 19, 10, 20, 11, 21, 12, 22, 9, 23, 13, 0, 0, 0, 12, 25, -1, 18, 2, 0, 3, 1, 4, 1, 5, 0, 6, 16, 7, 3, 8, 4, 13, 17, 14, 0, 15, 2, 16, 9, 17, 9, 18, 10, 19, 10, 20, 11, 21, 12, 22, 9, 23, 13, 0, 0, 0, 12, 26, -1, 18, 2, 0, 3, 1, 4, 1, 5, 0, 6, 18, 7, 3, 8, 4, 13, 19, 14, 0, 15, 2, 16, 9, 17, 9, 18, 10, 19, 10, 20, 11, 21, 12, 22, 9, 23, 13, 0 </int_array>
- <string> "conns" </string>
- <int_array len="0"> </int_array>
- </dictionary>
-
- </main_resource>
-</resource_file> \ No newline at end of file
diff --git a/demos/viewport/2d_in_3d/pong3d.gd b/demos/viewport/2d_in_3d/pong3d.gd
index 046d4dd859..79a7a36801 100644
--- a/demos/viewport/2d_in_3d/pong3d.gd
+++ b/demos/viewport/2d_in_3d/pong3d.gd
@@ -1,14 +1,7 @@
extends Spatial
-# member variables here, example:
-# var a=2
-# var b="textvar"
func _ready():
- # Initalization here
var tex = get_node("Viewport").get_render_target_texture()
- get_node("Quad").get_material_override().set_texture(FixedMaterial.PARAM_DIFFUSE,tex)
- pass
-
-
+ get_node("Quad").get_material_override().set_texture(FixedMaterial.PARAM_DIFFUSE, tex)
diff --git a/demos/viewport/2d_in_3d/pong3d.scn b/demos/viewport/2d_in_3d/pong3d.scn
index 58fd1513c0..2e60764a88 100644
--- a/demos/viewport/2d_in_3d/pong3d.scn
+++ b/demos/viewport/2d_in_3d/pong3d.scn
Binary files differ
diff --git a/demos/viewport/3d_in_2d/engine.cfg b/demos/viewport/3d_in_2d/engine.cfg
index cc893361b5..6d456d7bd4 100644
--- a/demos/viewport/3d_in_2d/engine.cfg
+++ b/demos/viewport/3d_in_2d/engine.cfg
@@ -2,3 +2,4 @@
name="3D in 2D"
main_scene="res://main.scn"
+icon="res://icon.png"
diff --git a/demos/viewport/3d_in_2d/icon.png b/demos/viewport/3d_in_2d/icon.png
new file mode 100644
index 0000000000..d8a332c18f
--- /dev/null
+++ b/demos/viewport/3d_in_2d/icon.png
Binary files differ
diff --git a/demos/viewport/3d_in_2d/main.scn b/demos/viewport/3d_in_2d/main.scn
index ad371b4417..d6c4deea42 100644
--- a/demos/viewport/3d_in_2d/main.scn
+++ b/demos/viewport/3d_in_2d/main.scn
Binary files differ
diff --git a/demos/viewport/3d_in_2d/player.scn b/demos/viewport/3d_in_2d/player.scn
index d6e6ddc461..7f490237fb 100644
--- a/demos/viewport/3d_in_2d/player.scn
+++ b/demos/viewport/3d_in_2d/player.scn
Binary files differ
diff --git a/demos/viewport/3d_in_2d/player.xml b/demos/viewport/3d_in_2d/player.xml
deleted file mode 100644
index 5730336107..0000000000
--- a/demos/viewport/3d_in_2d/player.xml
+++ /dev/null
@@ -1,1736 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<resource_file type="PackedScene" version="0.99" version_name="Godot Engine v0.99.3735-pre-beta">
- <resource type="CapsuleShape" path="local://1">
- <real name="radius"> 0.4 </real>
- <real name="height"> 0.4 </real>
-
- </resource>
- <resource type="RayShape" path="local://2">
- <real name="length"> 1 </real>
-
- </resource>
- <resource type="FixedMaterial" path="local://3">
- <bool name="flags/visible"> True </bool>
- <bool name="flags/double_sided"> True </bool>
- <bool name="flags/invert_faces"> False </bool>
- <bool name="flags/unshaded"> False </bool>
- <bool name="flags/on_top"> False </bool>
- <bool name="flags/wireframe"> False </bool>
- <bool name="flags/billboard_sw"> False </bool>
- <bool name="hints/decal"> False </bool>
- <bool name="hints/opaque_pre_zpass"> False </bool>
- <bool name="hints/no_shadow"> False </bool>
- <bool name="hints/no_depth_draw"> False </bool>
- <int name="params/blend_mode"> 0 </int>
- <real name="params/line_width"> 0 </real>
- <bool name="fixed_flags/use_alpha"> False </bool>
- <bool name="fixed_flags/use_color_array"> False </bool>
- <bool name="fixed_flags/use_point_size"> False </bool>
- <color name="params/diffuse"> 0.702475, 0.707942, 0.727015, 1 </color>
- <color name="params/specular"> 0.351321, 0.35466, 0.377071, 1 </color>
- <color name="params/emission"> 0, 0, 0, 1 </color>
- <real name="params/specular_exp"> 34.20256 </real>
- <int name="params/detail_blend"> 0 </int>
- <real name="params/detail_mix"> 1 </real>
- <int name="params/normal_depth"> 1 </int>
- <real name="params/shade_param"> 0.5 </real>
- <int name="params/glow"> 0 </int>
- <real name="params/point_size"> 1 </real>
- <transform name="uv_xform"> 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 </transform>
- <resource name="textures/diffuse"></resource> <int name="textures/diffuse_tc"> 0 </int>
- <resource name="textures/detail"></resource> <int name="textures/detail_tc"> 0 </int>
- <resource name="textures/specular"></resource> <int name="textures/specular_tc"> 0 </int>
- <resource name="textures/emission"></resource> <int name="textures/emission_tc"> 0 </int>
- <resource name="textures/specular_exp"></resource> <int name="textures/specular_exp_tc"> 0 </int>
- <resource name="textures/glow"></resource> <int name="textures/glow_tc"> 0 </int>
- <resource name="textures/normal"></resource> <int name="textures/normal_tc"> 0 </int>
- <resource name="textures/shade_param"></resource> <int name="textures/shade_param_tc"> 0 </int>
-
- </resource>
- <resource type="FixedMaterial" path="local://4">
- <bool name="flags/visible"> True </bool>
- <bool name="flags/double_sided"> True </bool>
- <bool name="flags/invert_faces"> False </bool>
- <bool name="flags/unshaded"> False </bool>
- <bool name="flags/on_top"> False </bool>
- <bool name="flags/wireframe"> False </bool>
- <bool name="flags/billboard_sw"> False </bool>
- <bool name="hints/decal"> False </bool>
- <bool name="hints/opaque_pre_zpass"> False </bool>
- <bool name="hints/no_shadow"> False </bool>
- <bool name="hints/no_depth_draw"> False </bool>
- <int name="params/blend_mode"> 0 </int>
- <real name="params/line_width"> 0 </real>
- <bool name="fixed_flags/use_alpha"> False </bool>
- <bool name="fixed_flags/use_color_array"> False </bool>
- <bool name="fixed_flags/use_point_size"> False </bool>
- <color name="params/diffuse"> 0.0616188, 0.431354, 0.64, 1 </color>
- <color name="params/specular"> 0.5, 0.5, 0.5, 1 </color>
- <color name="params/emission"> 0.0196078, 0.235675, 0.675973, 1 </color>
- <real name="params/specular_exp"> 50 </real>
- <int name="params/detail_blend"> 0 </int>
- <real name="params/detail_mix"> 1 </real>
- <int name="params/normal_depth"> 1 </int>
- <real name="params/shade_param"> 0.5 </real>
- <real name="params/glow"> 0.4 </real>
- <real name="params/point_size"> 1 </real>
- <transform name="uv_xform"> 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 </transform>
- <resource name="textures/diffuse"></resource> <int name="textures/diffuse_tc"> 0 </int>
- <resource name="textures/detail"></resource> <int name="textures/detail_tc"> 0 </int>
- <resource name="textures/specular"></resource> <int name="textures/specular_tc"> 0 </int>
- <resource name="textures/emission"></resource> <int name="textures/emission_tc"> 0 </int>
- <resource name="textures/specular_exp"></resource> <int name="textures/specular_exp_tc"> 0 </int>
- <resource name="textures/glow"></resource> <int name="textures/glow_tc"> 0 </int>
- <resource name="textures/normal"></resource> <int name="textures/normal_tc"> 0 </int>
- <resource name="textures/shade_param"></resource> <int name="textures/shade_param_tc"> 0 </int>
-
- </resource>
- <resource type="Mesh" path="local://5">
- <string name="resource/name"> "Cube.002" </string>
- <dictionary name="surfaces/0" shared="false">
- <string> "alphasort" </string>
- <bool> False </bool>
- <string> "material" </string>
- <resource resource_type="FixedMaterial" path="local://3"> </resource>
- <string> "morph_arrays" </string>
- <array len="0" shared="false">
- </array>
- <string> "primitive" </string>
- <int> 4 </int>
- <string> "arrays" </string>
- <array len="9" shared="false">
- <vector3_array len="679"> 0.2607, 6.45948, 0.980779, 0.852531, 6.83043, 0.609826, 0.852531, 6.93043, 0.609826, 0.2607, 6.55948, 0.980779, 0, 7.06621, 0.103096, 0.955654, 7.06621, 0.103096, 0.852531, 6.93043, -0.403642, 0, 6.93043, -0.403642, 0, 6.45948, -0.774594, 0, 6.55948, -0.774594, 0.2607, 6.55948, -0.774594, 0.2607, 6.45948, -0.774594, 0, 6.45948, 0.980779, 0, 6.55948, 0.980779, 0.852531, 6.83043, -0.403642, 0.955654, 6.96621, 0.103096, 0, 6.93043, 0.609826, 1.70474, 3.5573, -0.353999, 1.71449, 3.62366, -0.198996, 1.77916, 3.62988, -0.16353, 1.76754, 3.55083, -0.34818, 1.71511, 3.58298, -0.0127468, 1.70308, 3.74367, 0.0692484, 1.80667, 3.81951, -0.174607, 1.52592, 3.24162, -0.0839551, 1.50573, 3.18374, -0.268539, 1.36446, 3.09798, -0.344433, 1.38154, 3.17921, -0.0161709, 2.44682, 3.07552, 0.376618, 2.28993, 2.80163, 0.457827, 2.52299, 2.59433, 0.553631, 2.69474, 2.85281, 0.479075, 2.53359, 3.02984, -0.15501, 2.55604, 3.1449, 0.136694, 2.79433, 2.92572, 0.24463, 2.78064, 2.80757, -0.0472709, 2.39441, 2.7167, -0.284614, 2.64285, 2.49755, -0.175588, 2.70938, 2.79639, 0.46437, 2.79808, 2.86134, 0.255559, 2.78589, 2.75611, -0.00442547, 2.66316, 2.47998, -0.118712, 2.38561, 2.31013, 0.396952, 2.36919, 2.23204, 0.0813577, 2.41942, 2.2435, 0.110139, 2.43405, 2.31306, 0.391226, 2.55641, 2.56618, 0.530774, 2.47334, 2.30784, -0.0772789, 2.51219, 2.31101, -0.0311523, 2.38859, 2.74151, 0.0599679, 2.38864, 2.7416, 0.0600288, 2.12663, 2.44425, -0.0282163, 2.22321, 2.52508, -0.185319, 2.13459, 2.5274, 0.293671, 0.173831, 0.925795, -0.251959, 0.323615, 0.972996, -0.416293, 0.50934, 0.00104547, -0.453384, 0.175987, 0.00104547, -0.331706, 0.916812, 0.888823, 0.214332, 0.549239, 0.836962, 0.37006, 0.552121, 0.665123, 0.401021, 0.944465, 0.443271, 0.182901, 0.631626, 1.83578, -0.105239, 0.721202, 1.70631, 0.188726, 0.913722, 0.95431, -0.169976, 0.478232, 1.53675, 0.317272, 0.454208, 1.69171, -0.268756, 0.63543, 0.987243, -0.370343, 0.262225, 1.39447, 0.162709, 0.170564, 0.859014, 0.160279, 0.255551, 1.52426, -0.294896, 0.126803, 1.32882, -0.0395796, 0.0660405, 0.880691, -0.102965, 0.19102, 1.40531, -0.162224, 0.256767, 1.56023, -0.0958005, 0.300707, 1.62315, -0.168503, 0.292542, 1.58081, -0.213789, 0.245079, 1.4957, -0.123593, 0.426543, 1.69115, -0.196413, 0.547313, 1.79071, -0.0844079, 0.586182, 1.83924, -0.0975873, 0.434509, 1.71208, -0.231916, 0.212253, 1.44274, -0.0415312, 0.220281, 1.46968, -0.143048, 0.175617, 1.41154, -0.0437374, 0.543306, 0.573346, 0.523815, 0.207486, 0.384965, 0.351051, 0.269976, 0.320526, 0.743389, 0.53325, 0.468211, 0.783185, 0.792721, 0.321493, 0.73458, 0.514523, 0.271138, 0.956088, 0.631719, 0.163855, 0.92639, 0.386424, 0.163401, 0.930524, 0.486595, 0.00104547, 1.08874, 0.326299, 0.00104547, 0.904533, 0.668445, 1.73174, 0.152757, 0.462058, 1.58268, 0.259184, 0.290415, 1.46398, 0.121989, 1.57608, 3.45117, -0.0476083, 1.50191, 3.29774, -0.132197, 1.61428, 3.4244, 0.016813, 1.66072, 3.58429, -0.072422, 1.62434, 3.38222, -0.419987, 1.67177, 3.34226, -0.426789, 1.48496, 3.24915, -0.287145, 1.54119, 3.29007, -0.372791, 1.57272, 3.23249, -0.370566, 1.79243, 3.69662, -0.478226, 1.47279, 3.17682, -0.509438, 1.6491, 3.37415, -0.611694, 1.52444, 3.47482, 0.146797, 1.97806, 2.60303, -0.0912834, 1.98619, 2.68696, 0.233771, 2.07568, 2.68462, -0.249978, 2.24859, 2.87814, -0.35026, 2.14291, 2.96404, 0.3995, 2.30152, 3.24052, 0.317542, 2.38915, 3.19439, -0.219368, 2.41174, 3.31063, 0.0752657, 0.0964089, 0.00104547, -0.196812, 0.154027, 0.441809, 0.19622, 0.835003, 0.00104547, -0.205403, 0.55748, 1.72198, 0.0964474, 0.425773, 1.62639, 0.166544, 0.447702, 1.58483, 0.201877, 0.611101, 1.70343, 0.114914, 0.506064, 1.79234, -0.0642154, 0.311982, 1.54621, 0.0812291, 0.30653, 1.48536, 0.0960338, 0.408718, 1.71209, -0.154497, 0.23599, 1.51185, -0.0296548, 0.272186, 1.57784, -0.251696, 0.0508581, 0.00104547, 0.0402964, 0.14499, 0.00104547, 0.619324, 0.916171, 0.00104547, 0.0302318, 0.874277, 0.386199, 0.339815, 0.82337, 0.00104547, 0.611434, 0.644625, 0.00104547, 0.90083, 0.19633, 0.00104547, -0.176104, 0.736495, 0.00104547, -0.182387, 0.85902, 0.00104547, 0.0313234, 0.108829, 0.00104547, 0.040049, 1.86783, 5.49219, -0.536097, 1.99626, 5.62831, -0.300326, 1.99626, 5.45781, -0.129823, 1.86783, 5.22204, -0.265945, 1.86783, 6.50041, -0.265945, 1.99626, 6.26464, -0.129823, 1.99626, 6.09414, -0.300326, 1.86783, 6.23026, -0.536097, 1.99626, 5.86123, -0.362734, 1.86783, 5.86123, -0.63498, 1.7, 6.62333, -0.336911, 1.7, 6.30123, -0.659013, 1.7, 5.42123, -0.659013, 1.7, 5.09912, -0.336911, 1.7, 5.86123, -0.776911, 1.6, 6.62333, 0.543096, 1.6, 6.30123, 0.865198, 1.7, 6.30123, 0.865198, 1.7, 6.62333, 0.543096, 1.6, 5.86123, 0.983096, 1.7, 5.86123, 0.983096, 1.6, 5.42123, 0.865198, 1.7, 5.42123, 0.865198, 1.6, 5.42123, -0.659013, 1.6, 5.09912, -0.336911, 1.6, 5.09913, 0.543096, 1.7, 5.09913, 0.543096, 1.6, 5.86123, -0.776911, 1.6, 4.98123, 0.103096, 1.7, 4.98123, 0.103096, 1.6, 6.30123, -0.659013, 1.6, 6.62333, -0.336911, 1.6, 6.74123, 0.103096, 1.7, 6.74123, 0.103096, 1.86783, 5.86123, 0.841165, 1.86783, 6.23026, 0.742282, 1.86783, 5.49219, 0.742282, 1.86783, 5.22204, 0.47213, 1.86783, 5.12316, 0.103096, 1.86783, 6.50041, 0.47213, 1.86783, 6.5993, 0.103096, 1.99626, 5.3954, 0.103096, 1.99626, 5.45781, 0.336007, 1.99626, 5.62832, 0.50651, 1.99626, 5.86123, 0.568919, 1.99626, 6.09414, 0.50651, 1.99626, 6.26464, 0.336007, 1.99626, 6.32705, 0.103096, 0.102832, 2.48009, 0.176006, 5.00021e-06, 2.4738, 0.177211, 5.00021e-06, 2.42055, 0.19141, 0.0988953, 2.42787, 0.190009, 0.149215, 2.70638, -0.125392, 0.228589, 2.63923, -0.0490058, 0.245228, 2.61305, -0.0718189, 0.152867, 2.69118, -0.160703, 5.00021e-06, 2.7271, -0.192857, 0.200279, 2.72863, -0.178996, 5.00021e-06, 2.77269, -0.218433, 0.254515, 2.5228, 0.0532499, 0.177509, 2.46933, 0.131427, 0.230502, 2.45653, 0.179303, 0.32495, 2.52211, 0.0834183, 0.31356, 2.6328, -0.0699792, 5.00021e-06, 2.38434, 0.263172, 0.134082, 2.39331, 0.261453, 4.89224e-06, 2.18251, 0.500372, 0.225093, 2.1995, 0.49518, 0.391925, 2.2292, 0.34273, 0.272307, 2.12215, 0.166987, 0.273286, 2.15284, 0.145033, 0.377566, 2.23301, 0.230347, 0.509219, 2.60277, -0.0602789, 0.306467, 2.75371, -0.22827, 0.384471, 2.30721, 0.355435, 5.53206e-06, 2.7678, -0.324424, 0.340915, 2.69228, -0.257391, 0.141881, 2.21642, -0.246023, 5.00021e-06, 2.24749, -0.273838, 0.226149, 2.1204, 0.482878, 5.00021e-06, 2.10499, 0.484715, 5.00021e-06, 1.97359, 0.0658354, 0.0951926, 1.97992, 0.0646229, 0.536694, 2.41886, 0.193185, 0.163197, 2.02451, 0.00668271, 5.00021e-06, 2.80311, -0.262553, 0.221777, 2.14883, -0.169134, 5.0058e-06, 2.08031, -0.179583, 4.99835e-06, 2.12243, -0.227502, 5.00021e-06, 1.97109, -0.0331461, 4.99835e-06, 1.97504, -0.0339018, 0.229811, 2.07077, -0.0609438, 5.0058e-06, 2.03165, -0.112157, 4.99835e-06, 2.00283, -0.0700111, 5.00021e-06, 2.14179, -0.244837, 0.549486, 2.33903, 0.185763, 0.532141, 2.52821, -0.0726373, 0.367385, 2.32682, -0.123862, 0.198102, 4.44663, -0.00271145, 0.535945, 4.16951, 0.521097, 0.681184, 4.27477, 0.307467, 0.0960235, 4.4178, 0.0939296, 0, 4.41627, 0.145479, 0, 4.10504, 0.75232, 0.295152, 4.11437, 0.707528, 0, 4.62654, -0.650476, 0.75197, 4.49872, -0.484507, 0.568386, 3.97815, -0.416848, 0, 4.0743, -0.542347, 0.453404, 3.62952, 1.15385, 0, 3.62251, 1.22471, 0, 3.3304, 0.897974, 0.354866, 3.3434, 0.864531, 0.713601, 4.46674, -0.124363, 1.03995, 4.04518, 0.442157, 1.12602, 4.3213, -0.0494407, 0, 4.73174, -0.547059, 0.464921, 4.64317, -0.424668, 0.716219, 4.58287, -0.480226, 0, 4.71901, -0.593658, 0.850048, 3.71295, 0.879328, 0.649196, 3.42772, 0.674737, 0.84841, 3.80937, 0.873472, 0.451539, 3.72707, 1.15037, 0.155937, 3.05577, 0.331006, 0.258719, 3.09481, 0.245674, 0.822291, 3.77674, 0.0641416, 0.359401, 3.14451, 0.132252, 0.226502, 3.30884, -0.183514, 0, 3.34718, -0.233548, 0, 3.04671, 0.334585, 1.1403, 4.19005, 0.0860849, 1.11025, 4.20631, -0.0820755, 0, 3.71833, 1.2227, 1.07207, 4.04817, 0.195228, 0.177538, 3.25078, -0.147598, 0, 3.28068, -0.186631, 0.249187, 2.13753, -0.031997, 0.20137, 2.11848, 0.0341487, 0.497933, 2.32861, 0.160251, 0.252884, 2.22978, -0.1047, 0.438171, 2.39896, -0.000411894, 0.941862, 3.86072, 0.194563, 0.997836, 4.10049, -0.213272, 0.87372, 3.89175, -0.186777, 0.347259, 3.23006, -0.0503454, 0.821813, 3.80214, -0.0657451, 0.908494, 3.91354, 0.153681, 1.01577, 4.06798, 0.154229, 1.07199, 4.18489, 0.0643051, 1.04723, 4.19828, -0.0742428, 2.0359, 6.20719, -0.0966551, 2.0359, 6.06097, -0.242878, 2.0359, 5.66148, -0.242878, 2.0359, 5.51526, -0.0966551, 2.0359, 5.86123, -0.296399, 2.0359, 5.86123, 0.502584, 2.0359, 6.06097, 0.449063, 2.0359, 5.66148, 0.449063, 2.0359, 5.51526, 0.30284, 2.0359, 5.46174, 0.103096, 2.0359, 6.20719, 0.30284, 2.0359, 6.26072, 0.103096, 0, 5.86123, 1.1031, 0, 5.47658, 1.00003, 0.329213, 5.47658, 1.00003, 0, 5.20179, 0.809688, 0, 4.9952, 0.603096, 0.329213, 5.20344, 0.811334, 1.15486, 6.36123, 0.969121, 1.2072, 6.11123, 1.03611, 1.39648, 6.36123, 0.969121, 0, 5.86123, -0.896911, 1.39648, 5.86123, -0.896911, 1.39648, 5.36123, -0.762936, 0, 5.36123, -0.762936, 1.39648, 4.9952, -0.396911, 0, 4.9952, -0.396911, 0.329213, 5.36123, 0.969121, 0.257147, 5.40641, 0.875976, 0.257146, 5.2834, 0.752961, 0, 5.49634, 0.900073, 0.257147, 5.49634, 0.900073, 0, 5.28211, 0.751677, 0.685695, 5.86123, 1.1031, 0.633352, 6.11123, 1.03611, 1.39648, 5.36123, 0.969121, 1.39648, 5.86123, 1.1031, 1.15486, 5.86123, 1.1031, 1.39648, 4.9952, 0.603096, 0.23657, 2.56168, 0.0584772, 0.170392, 2.51572, 0.125662, 5.00021e-06, 2.73725, -0.153025, 0.350345, 2.31871, -0.0906937, 0, 4.66231, -0.410127, 0.153299, 4.61636, -0.336561, 0.252264, 4.53307, -0.191655, 0.271744, 3.18932, -0.0437093, 0.122488, 3.05335, 0.253795, 0.202672, 3.0838, 0.187225, 0.281216, 3.12258, 0.0987407, 0, 3.04628, 0.256587, 0.954611, 4.1111, -0.182336, 0.85235, 3.93911, -0.160509, 0.809584, 3.86528, -0.0607897, 0.809978, 3.84435, 0.0462258, 0, 4.97587, -0.315884, 1.39648, 4.86123, 0.103096, 0.18642, 4.95573, -0.248219, 0.269727, 4.92174, -0.116503, 0.212301, 4.88556, 0.0356146, 0, 4.86123, 0.103096, 0.942888, 6.86123, 0.103096, 1.39648, 6.86123, 0.103096, 1.39648, 6.72725, -0.396911, 0.841135, 6.72725, -0.396911, 1.39648, 6.36123, -0.762936, 0.257165, 6.36123, -0.762936, 0.841135, 6.72725, 0.603096, 1.39648, 6.72725, 0.603096, 0, 6.36123, -0.762936, 0.257165, 6.36123, 0.969121, 0.685695, 6.36123, 0.969121, 0, 6.36123, 0.969121, -0.2607, 6.45948, 0.980779, -0.2607, 6.55948, 0.980779, -0.852531, 6.93043, 0.609826, -0.852531, 6.83043, 0.609826, -0.852531, 6.93043, -0.403642, -0.955654, 7.06621, 0.103096, -0.2607, 6.45948, -0.774594, -0.2607, 6.55948, -0.774594, -0.852531, 6.83043, -0.403642, -0.955654, 6.96621, 0.103096, -1.70474, 3.5573, -0.353999, -1.76754, 3.55083, -0.34818, -1.77916, 3.62988, -0.16353, -1.71449, 3.62366, -0.198996, -1.80667, 3.81951, -0.174607, -1.70308, 3.74367, 0.0692484, -1.71511, 3.58298, -0.0127468, -1.52592, 3.24162, -0.0839551, -1.38154, 3.17921, -0.0161709, -1.36446, 3.09798, -0.344433, -1.50573, 3.18374, -0.268539, -2.44682, 3.07552, 0.376618, -2.69474, 2.85281, 0.479075, -2.52299, 2.59433, 0.553631, -2.28993, 2.80163, 0.457827, -2.53359, 3.02984, -0.15501, -2.78064, 2.80757, -0.0472709, -2.79433, 2.92572, 0.24463, -2.55604, 3.1449, 0.136694, -2.39441, 2.7167, -0.284614, -2.64285, 2.49755, -0.175588, -2.79808, 2.86134, 0.255559, -2.70938, 2.79639, 0.46437, -2.66316, 2.47998, -0.118712, -2.78589, 2.75611, -0.00442547, -2.38561, 2.31013, 0.396952, -2.43405, 2.31306, 0.391226, -2.41942, 2.2435, 0.110139, -2.36919, 2.23204, 0.0813577, -2.55641, 2.56618, 0.530774, -2.51219, 2.31101, -0.0311523, -2.47334, 2.30784, -0.0772789, -2.38859, 2.74151, 0.0599679, -2.38864, 2.7416, 0.0600288, -2.12663, 2.44425, -0.0282163, -2.22321, 2.52508, -0.185319, -2.13459, 2.5274, 0.293671, -0.173831, 0.925795, -0.251959, -0.175987, 0.00104547, -0.331706, -0.50934, 0.00104547, -0.453384, -0.323615, 0.972996, -0.416293, -0.916812, 0.888823, 0.214332, -0.944465, 0.443271, 0.182901, -0.552121, 0.665123, 0.401021, -0.549239, 0.836962, 0.37006, -0.631626, 1.83578, -0.105239, -0.913722, 0.95431, -0.169976, -0.721202, 1.70631, 0.188726, -0.478232, 1.53675, 0.317272, -0.454208, 1.69171, -0.268756, -0.63543, 0.987243, -0.370343, -0.170564, 0.859014, 0.160279, -0.262225, 1.39447, 0.162709, -0.255551, 1.52426, -0.294896, -0.0660405, 0.880691, -0.102965, -0.126803, 1.32882, -0.0395796, -0.19102, 1.40531, -0.162224, -0.256767, 1.56023, -0.0958005, -0.245079, 1.4957, -0.123593, -0.292542, 1.58081, -0.213789, -0.300707, 1.62315, -0.168503, -0.426543, 1.69115, -0.196413, -0.434509, 1.71208, -0.231916, -0.586182, 1.83924, -0.0975873, -0.547313, 1.79071, -0.0844079, -0.212253, 1.44274, -0.0415312, -0.175617, 1.41154, -0.0437374, -0.220281, 1.46968, -0.143048, -0.543306, 0.573346, 0.523815, -0.53325, 0.468211, 0.783185, -0.269976, 0.320526, 0.743389, -0.207486, 0.384965, 0.351051, -0.792721, 0.321493, 0.73458, -0.631719, 0.163855, 0.92639, -0.514523, 0.271138, 0.956088, -0.386424, 0.163401, 0.930524, -0.486595, 0.00104547, 1.08874, -0.326299, 0.00104547, 0.904533, -0.462058, 1.58268, 0.259184, -0.668445, 1.73174, 0.152757, -0.290415, 1.46398, 0.121989, -1.57608, 3.45117, -0.0476083, -1.61428, 3.4244, 0.016813, -1.50191, 3.29774, -0.132197, -1.66072, 3.58429, -0.072422, -1.62434, 3.38222, -0.419987, -1.67177, 3.34226, -0.426789, -1.48496, 3.24915, -0.287145, -1.57272, 3.23249, -0.370566, -1.54119, 3.29007, -0.372791, -1.79243, 3.69662, -0.478226, -1.47279, 3.17682, -0.509438, -1.6491, 3.37415, -0.611694, -1.52444, 3.47482, 0.146797, -1.98619, 2.68696, 0.233771, -1.97806, 2.60303, -0.0912834, -2.07568, 2.68462, -0.249978, -2.24859, 2.87814, -0.35026, -2.14291, 2.96404, 0.3995, -2.30152, 3.24052, 0.317542, -2.38915, 3.19439, -0.219368, -2.41174, 3.31063, 0.0752657, -0.0964089, 0.00104547, -0.196812, -0.154027, 0.441809, 0.19622, -0.835003, 0.00104547, -0.205403, -0.55748, 1.72198, 0.0964474, -0.611101, 1.70343, 0.114914, -0.447702, 1.58483, 0.201877, -0.425773, 1.62639, 0.166544, -0.506064, 1.79234, -0.0642154, -0.30653, 1.48536, 0.0960338, -0.311982, 1.54621, 0.0812291, -0.408718, 1.71209, -0.154497, -0.23599, 1.51185, -0.0296548, -0.272186, 1.57784, -0.251696, -0.14499, 0.00104547, 0.619324, -0.0508581, 0.00104547, 0.0402964, -0.916171, 0.00104547, 0.0302318, -0.82337, 0.00104547, 0.611434, -0.874277, 0.386199, 0.339815, -0.644625, 0.00104547, 0.90083, -0.19633, 0.00104547, -0.176104, -0.108829, 0.00104547, 0.040049, -0.85902, 0.00104547, 0.0313234, -0.736495, 0.00104547, -0.182387, -1.86783, 5.49219, -0.536097, -1.86783, 5.22204, -0.265945, -1.99626, 5.45781, -0.129823, -1.99626, 5.62831, -0.300326, -1.86783, 6.50041, -0.265945, -1.86783, 6.23026, -0.536097, -1.99626, 6.09414, -0.300326, -1.99626, 6.26464, -0.129823, -1.86783, 5.86123, -0.63498, -1.99626, 5.86123, -0.362734, -1.7, 6.62333, -0.336911, -1.7, 6.30123, -0.659013, -1.7, 5.42123, -0.659013, -1.7, 5.09912, -0.336911, -1.7, 5.86123, -0.776911, -1.6, 6.62333, 0.543096, -1.7, 6.62333, 0.543096, -1.7, 6.30123, 0.865198, -1.6, 6.30123, 0.865198, -1.7, 5.86123, 0.983096, -1.6, 5.86123, 0.983096, -1.7, 5.42123, 0.865198, -1.6, 5.42123, 0.865198, -1.6, 5.42123, -0.659013, -1.6, 5.09912, -0.336911, -1.7, 5.09913, 0.543096, -1.6, 5.09913, 0.543096, -1.6, 5.86123, -0.776911, -1.7, 4.98123, 0.103096, -1.6, 4.98123, 0.103096, -1.6, 6.30123, -0.659013, -1.6, 6.62333, -0.336911, -1.6, 6.74123, 0.103096, -1.7, 6.74123, 0.103096, -1.86783, 6.23026, 0.742282, -1.86783, 5.86123, 0.841165, -1.86783, 5.49219, 0.742282, -1.86783, 5.22204, 0.47213, -1.86783, 5.12316, 0.103096, -1.86783, 6.5993, 0.103096, -1.86783, 6.50041, 0.47213, -1.99626, 5.45781, 0.336007, -1.99626, 5.3954, 0.103096, -1.99626, 5.86123, 0.568919, -1.99626, 5.62832, 0.50651, -1.99626, 6.09414, 0.50651, -1.99626, 6.26464, 0.336007, -1.99626, 6.32705, 0.103096, -0.102832, 2.48009, 0.176006, -0.0988953, 2.42787, 0.190009, -0.149215, 2.70638, -0.125392, -0.152867, 2.69118, -0.160703, -0.245228, 2.61305, -0.0718189, -0.228589, 2.63923, -0.0490058, -0.200279, 2.72863, -0.178996, -0.254515, 2.5228, 0.0532499, -0.32495, 2.52211, 0.0834183, -0.230502, 2.45653, 0.179303, -0.177509, 2.46933, 0.131427, -0.31356, 2.6328, -0.0699792, -0.134082, 2.39331, 0.261453, -0.225093, 2.1995, 0.49518, -0.391925, 2.2292, 0.34273, -0.377566, 2.23301, 0.230347, -0.273286, 2.15284, 0.145033, -0.272307, 2.12215, 0.166987, -0.306467, 2.75371, -0.22827, -0.509219, 2.60277, -0.0602789, -0.384471, 2.30721, 0.355435, -0.141881, 2.21642, -0.246023, -0.340915, 2.69228, -0.257391, -0.226149, 2.1204, 0.482878, -0.0951926, 1.97992, 0.0646229, -0.536694, 2.41886, 0.193185, -0.163197, 2.02451, 0.00668271, -0.221777, 2.14883, -0.169134, -0.229811, 2.07077, -0.0609438, -0.549486, 2.33903, 0.185763, -0.532141, 2.52821, -0.0726373, -0.367385, 2.32682, -0.123862, -0.198102, 4.44663, -0.00271145, -0.681184, 4.27477, 0.307467, -0.535945, 4.16951, 0.521097, -0.0960235, 4.4178, 0.0939296, -0.295152, 4.11437, 0.707528, -0.568386, 3.97815, -0.416848, -0.75197, 4.49872, -0.484507, -0.453404, 3.62952, 1.15385, -0.354866, 3.3434, 0.864531, -0.713601, 4.46674, -0.124363, -1.12602, 4.3213, -0.0494407, -1.03995, 4.04518, 0.442157, -0.716219, 4.58287, -0.480226, -0.464921, 4.64317, -0.424668, -0.850048, 3.71295, 0.879328, -0.649196, 3.42772, 0.674737, -0.84841, 3.80937, 0.873472, -0.451539, 3.72707, 1.15037, -0.258719, 3.09481, 0.245674, -0.155937, 3.05577, 0.331006, -0.822291, 3.77674, 0.0641416, -0.359401, 3.14451, 0.132252, -0.226502, 3.30884, -0.183514, -1.1403, 4.19005, 0.0860849, -1.11025, 4.20631, -0.0820755, -1.07207, 4.04817, 0.195228, -0.177538, 3.25078, -0.147598, -0.20137, 2.11848, 0.0341487, -0.249187, 2.13753, -0.031997, -0.497933, 2.32861, 0.160251, -0.252884, 2.22978, -0.1047, -0.438171, 2.39896, -0.000411894, -0.941862, 3.86072, 0.194563, -0.997836, 4.10049, -0.213272, -0.87372, 3.89175, -0.186777, -0.347259, 3.23006, -0.0503454, -0.821813, 3.80214, -0.0657451, -1.01577, 4.06798, 0.154229, -0.908494, 3.91354, 0.153681, -1.04723, 4.19828, -0.0742428, -1.07199, 4.18489, 0.0643051, -2.0359, 6.06097, -0.242878, -2.0359, 6.20719, -0.0966551, -2.0359, 5.51526, -0.0966551, -2.0359, 5.66148, -0.242878, -2.0359, 5.86123, -0.296399, -2.0359, 6.06097, 0.449063, -2.0359, 5.86123, 0.502584, -2.0359, 5.66148, 0.449063, -2.0359, 5.51526, 0.30284, -2.0359, 5.46174, 0.103096, -2.0359, 6.26072, 0.103096, -2.0359, 6.20719, 0.30284, -0.329213, 5.47658, 1.00003, -0.329213, 5.20344, 0.811334, -1.15486, 6.36123, 0.969121, -1.39648, 6.36123, 0.969121, -1.2072, 6.11123, 1.03611, -1.39648, 5.36123, -0.762936, -1.39648, 5.86123, -0.896911, -1.39648, 4.9952, -0.396911, -0.257146, 5.2834, 0.752961, -0.257147, 5.40641, 0.875976, -0.329213, 5.36123, 0.969121, -0.257147, 5.49634, 0.900073, -0.685695, 5.86123, 1.1031, -0.633352, 6.11123, 1.03611, -1.39648, 5.36123, 0.969121, -1.15486, 5.86123, 1.1031, -1.39648, 5.86123, 1.1031, -1.39648, 4.9952, 0.603096, -0.23657, 2.56168, 0.0584772, -0.170392, 2.51572, 0.125662, -0.350345, 2.31871, -0.0906937, -0.153299, 4.61636, -0.336561, -0.252264, 4.53307, -0.191655, -0.271744, 3.18932, -0.0437093, -0.202672, 3.0838, 0.187225, -0.122488, 3.05335, 0.253795, -0.281216, 3.12258, 0.0987407, -0.85235, 3.93911, -0.160509, -0.954611, 4.1111, -0.182336, -0.809584, 3.86528, -0.0607897, -0.809978, 3.84435, 0.0462258, -1.39648, 4.86123, 0.103096, -0.18642, 4.95573, -0.248219, -0.269727, 4.92174, -0.116503, -0.212301, 4.88556, 0.0356146, -0.942888, 6.86123, 0.103096, -0.841135, 6.72725, -0.396911, -1.39648, 6.72725, -0.396911, -1.39648, 6.86123, 0.103096, -0.257165, 6.36123, -0.762936, -1.39648, 6.36123, -0.762936, -1.39648, 6.72725, 0.603096, -0.841135, 6.72725, 0.603096, -0.257165, 6.36123, 0.969121, -0.685695, 6.36123, 0.969121 </vector3_array>
- <vector3_array len="679"> 0.323483, -0.753124, 0.572855, 0.771126, -0.534781, 0.345505, 0.599478, 0.562448, 0.569454, 0.202252, 0.315394, 0.927157, 0, 1, -0, 0.696021, 0.718022, -0, 0.599136, 0.562128, -0.57013, 0, 0.866019, -0.500011, 0, -0.789191, -0.614148, 0, 0.382911, -0.923785, 0.202065, 0.315101, -0.927298, 0.323297, -0.752692, -0.573527, 0, -0.789675, 0.613525, 0, 0.383265, 0.923638, 0.770859, -0.534596, -0.346386, 0.868674, -0.495384, 0, 0, 0.866452, 0.49926, 0.167052, 0.584181, -0.794246, 0.308094, 0.942288, -0.13104, -0.783538, 0.601413, -0.156107, -0.724538, 0.614456, -0.312232, -0.831821, 0.51651, -0.203201, -0.468553, 0.81396, 0.343405, -0.207013, 0.970059, -0.127008, -0.839933, 0.527586, -0.127141, -0.839469, 0.51929, -0.16009, -0.952083, -0.0830945, -0.294335, -0.969325, 0.0600821, 0.238326, -0.242219, 0.80573, 0.54049, -0.618771, 0.285356, 0.731912, -0.00900884, -0.126124, 0.991974, 0.500138, 0.3651, 0.785216, 0.0490036, 0.723054, -0.689051, 0.0889861, 0.993844, -0.0659897, 0.858321, 0.492184, 0.145054, 0.845097, 0.209024, -0.492057, -0.210106, 0.16008, -0.964484, 0.529219, -0.36215, -0.767317, 0.835061, -0.3935, 0.384488, 0.882867, -0.432425, 0.18318, 0.857612, -0.49035, 0.155111, 0.828872, -0.533561, 0.168177, -0.311554, -0.724288, 0.615094, -0.251244, -0.959933, -0.124121, 0.661603, -0.73467, 0.150137, 0.642912, -0.678963, 0.354503, 0.72766, -0.516469, 0.45141, 0.115162, -0.7841, -0.609856, 0.772162, -0.611128, 0.174036, 0.773373, -0.45522, 0.441213, 0.537341, -0.81952, 0.199126, -0.891041, -0.346405, -0.293343, -0.609658, -0.17619, -0.772835, -0.901333, -0.16224, 0.401594, -0.77153, 0.0690475, -0.632435, -0.315127, 0.0940378, -0.944379, 0.055046, -0.627524, -0.776649, -0.536581, -0.621673, -0.570617, 0.861095, 0.107012, 0.497055, -0.0380375, 0.0810799, 0.995982, -0.00700771, -0.117129, 0.993092, 0.797008, -0.304385, 0.521659, 0.524884, 0.803823, -0.279938, 0.595044, 0.585044, 0.551041, 0.871559, 0.129934, -0.472761, -0.200267, 0.367489, 0.90821, 0.0669956, 0.520966, -0.850944, 0.382844, 0.129947, -0.914628, -0.739262, 0.276472, 0.614048, -0.776468, 0.0611156, 0.627186, -0.58619, 0.359116, -0.726235, -0.959877, 0.277253, 0.0420384, -0.992667, 0.0720484, -0.0970652, -0.896641, 0.277198, -0.345247, -0.943047, 0.164182, -0.289321, -0.728454, 0.359224, -0.583363, -0.765447, 0.642375, 0.0380222, -0.855938, 0.516566, 0.0230252, -0.610501, 0.786645, -0.0920755, -0.477172, 0.854307, 0.206074, -0.309014, 0.951044, 0.00500023, -0.513202, 0.81332, -0.274108, -0.781621, 0.597475, 0.179142, -0.831231, 0.554821, 0.0350519, -0.80571, 0.57851, 0.127112, 0.0110026, 0.996233, -0.0860201, -0.616626, 0.733745, -0.28529, -0.740791, 0.504539, 0.443474, 0.0110097, 0.826727, 0.562495, 0.798668, 0.375314, 0.470393, 0.00700849, 0.548665, 0.836013, 0.68171, 0.189197, 0.706736, -0.65479, 0.336406, 0.676817, -0.0310549, -0.441781, 0.896585, -0.617121, -0.634152, 0.465846, -0.16707, 0.870366, 0.463195, -0.5063, 0.725429, 0.466276, -0.711913, 0.614788, 0.339435, -0.409744, 0.0530964, 0.910654, -0.764085, -0.38755, 0.515732, -0.847732, 0.508439, -0.15113, 0.0380266, 0.718502, 0.694485, -0.160029, 0.076014, -0.984181, -0.759497, 0.484317, -0.434284, -0.812045, -0.505651, -0.291375, -0.511638, -0.289361, -0.809009, -0.820559, 0.421287, -0.386263, -0.223103, 0.739342, -0.635294, -0.724353, 0.0750365, -0.685334, -0.43004, 0.304028, -0.850078, -0.80007, 0.434581, 0.413553, -0.0460378, -0.996819, -0.0650535, -0.0350519, -0.808196, 0.58787, 0.267172, -0.820528, -0.505325, 0.6294, -0.428272, -0.648412, 0.297403, -0.309419, 0.903223, 0.622553, 0.221196, 0.750666, 0.897953, 0.117994, -0.423978, 0.920375, 0.351143, 0.17207, -0.753305, -0.654134, 0.0681181, -0.674119, -0.252419, 0.694153, 0.713493, -0.691478, -0.113078, 0.455352, 0.602466, 0.655507, -0.318438, 0.223307, 0.921266, -0.564392, 0.704489, 0.430299, -0.398344, 0.805696, 0.438379, 0.565223, 0.681269, -0.465184, -0.74958, 0.0670519, 0.658509, -0.747893, 0.534638, 0.39347, -0.0789773, 0.541844, -0.83676, -0.969378, 0.150213, 0.194276, -0.723252, 0.667233, -0.178062, -0.702756, -0.294317, -0.647697, -0.77343, -0.576065, 0.264489, 0.64207, -0.336037, -0.689075, 0.714816, 0.636836, -0.288926, 0.692559, -0.68055, 0.239193, 0.560659, -0.716842, 0.414487, -0.216317, -0.957402, 0.19128, 0.194204, -0.972021, 0.132139, 0.711943, 0.135989, -0.688945, -0.686439, 0.302193, -0.661423, 0.776432, -0.314175, -0.546304, 0.886017, -0.231005, -0.402008, 0.886168, -0.401076, -0.232044, 0.776611, -0.545429, -0.315248, 0.776187, 0.546132, -0.315076, 0.885812, 0.401915, -0.231951, 0.885812, 0.231951, -0.401915, 0.776187, 0.315076, -0.546132, 0.885871, 0, -0.463932, 0.776359, 0, -0.630291, 0.327036, 0.818089, -0.473052, 0.327036, 0.473052, -0.818089, 0.32719, -0.472275, -0.818476, 0.327303, -0.817758, -0.473439, 0.327008, 0, -0.945022, -0.652547, 0.65655, 0.378317, -0.652728, 0.379423, 0.655732, 0.327303, 0.473439, 0.817758, 0.32719, 0.818476, 0.472275, -0.653098, 0, 0.757273, 0.327317, 0, 0.944915, -0.652976, -0.378566, 0.65598, 0.327458, -0.472662, 0.818145, -0.652547, -0.378317, -0.65655, -0.652728, -0.655732, -0.379423, -0.652976, -0.65598, 0.378566, 0.327458, -0.818145, 0.472662, -0.652603, 0, -0.7577, -0.653098, -0.757273, 0, 0.327317, -0.944915, 0, -0.6523, 0.379174, -0.656302, -0.6523, 0.656302, -0.379174, -0.652603, 0.7577, 0, 0.327008, 0.945022, -0, 0.776848, 0, 0.629688, 0.776611, 0.315248, 0.545429, 0.776856, -0.314346, 0.545601, 0.776856, -0.545601, 0.314346, 0.776848, -0.629688, 0, 0.776432, 0.546304, 0.314175, 0.776359, 0.630291, -0, 0.886281, -0.463147, 0, 0.886373, -0.401169, 0.231097, 0.886373, -0.231097, 0.401169, 0.886281, 0, 0.463147, 0.886168, 0.232044, 0.401076, 0.886017, 0.402008, 0.231005, 0.885871, 0.463932, -0, 0.320359, 0.0650729, 0.945059, 0, 0.0700382, 0.997544, 0, 0.642347, 0.766414, 0.0170187, 0.688755, 0.724794, 0.609974, 0.430981, -0.664971, 0.947519, 0.264145, -0.180099, 0.303207, 0.801547, 0.515352, 0.183115, 0.866546, 0.464292, 0, 0.882519, 0.470277, -0.0130118, 0.73066, 0.682617, 0, 0.706106, 0.708106, 0.225998, 0.736995, 0.636996, 0.221247, 0.645722, 0.730817, -0.0530284, 0.84045, 0.539289, -0.0270074, 0.825227, 0.564155, -0.0350336, 0.777746, 0.627602, 0, 0.830353, 0.557237, -0.0410178, 0.818354, 0.573248, 0, 0.314425, 0.949282, 0.27534, 0.29136, 0.916132, 0.778752, -0.489473, 0.392379, 0.746544, -0.651475, -0.135099, 0.272405, -0.803194, 0.529788, 0.652602, -0.667616, 0.35833, 0.671414, 0.730451, 0.125077, 0.357959, 0.928893, -0.0949891, 0.443473, 0.436465, 0.782835, 0, 0.377932, -0.925833, 0.555211, 0.240091, -0.796302, 0.325138, -0.340145, -0.882376, 0, -0.203036, -0.979171, 0.405354, -0.612535, 0.678593, 0, -0.671726, 0.7408, 0, -0.989545, 0.144225, 0.324316, -0.945923, 0.00700683, 0.678459, 0.508344, 0.530359, 0.581287, -0.797393, -0.16208, 0, 0.993246, -0.116029, 0.624575, -0.536494, -0.567522, 0, -0.741749, -0.670677, 0, -0.556084, -0.831126, 0, -0.999902, -0.0140126, 0, -0.966632, -0.256168, 0.738289, -0.658258, -0.147058, 0, -0.851521, -0.524321, 0, -0.900741, -0.434357, 0, -0.346076, -0.938206, 0.897164, -0.425078, 0.120022, 0.916025, -0.0850023, -0.392011, 0.746835, -0.537601, -0.391438, 0.24712, 0.836407, 0.489238, 0.187033, 0.840147, 0.509089, 0.180007, 0.858032, 0.481018, 0.245128, 0.817427, 0.521272, 0, 0.768221, 0.640184, 0, 0.834352, 0.551232, 0.143113, 0.833656, 0.53342, 0, 0.114054, -0.993474, 0.536767, 0.0429814, -0.842635, 0.34218, -0.328173, -0.880463, 0, -0.278155, -0.960536, 0.372421, -0.379429, 0.846957, 0, -0.377424, 0.926041, 0, -0.819843, 0.572589, 0.295296, -0.813817, 0.500502, 0.195064, 0.900294, 0.389127, 0.804875, 0.356387, 0.474516, 0.808731, 0.587804, -0.020993, 0, 0.994988, 0.0999987, 0.169127, 0.969729, 0.176132, 0.451126, 0.771215, -0.449125, 0, 0.777245, -0.629198, 0.78993, -0.410483, 0.455536, 0.657391, -0.729434, 0.189112, 0.705632, 0.319286, 0.632566, 0.308272, 0.411363, 0.857758, 0.231245, -0.951006, 0.205217, 0.47266, -0.881231, 0.00500699, 0.887311, -0.393138, -0.241085, 0.618412, -0.762508, -0.190127, 0.259028, -0.529057, -0.808087, 0, -0.471055, -0.882104, 0, -0.97194, 0.235228, 0.972719, -0.231933, -0.00499856, 0.748485, -0.564366, -0.348226, 0, 0.419376, 0.907813, 0.793691, -0.521454, -0.313273, 0.307062, -0.405082, -0.861174, 0, -0.36621, -0.930532, -0.256367, -0.749072, -0.610874, 0.241336, -0.969348, -0.0460641, 0.800238, -0.563168, -0.206061, 0.679395, -0.526306, -0.511297, 0.794806, -0.441448, -0.416422, 0.78099, -0.430994, -0.451994, 0.727309, -0.686292, 0.00500213, 0.915343, -0.34713, -0.204077, 0.535473, -0.673595, -0.50945, 0.971477, -0.237116, 0.00300147, 0.731118, -0.68011, -0.0540087, 0.849093, -0.528058, -0.0140015, 0.83344, -0.540285, -0.116061, 0.864591, -0.499341, -0.0560383, 0.984291, 0.153045, -0.088026, 0.984291, 0.088026, -0.153045, 0.984377, -0.0870333, -0.153059, 0.984441, -0.152068, -0.0880395, 0.984378, 0, -0.176068, 0.984551, 0, 0.175098, 0.984441, 0.0880395, 0.152068, 0.984527, -0.0870466, 0.152081, 0.984527, -0.152081, 0.0870466, 0.984551, -0.175098, 0, 0.984377, 0.153059, 0.0870333, 0.984378, 0.176068, -0, 0, 0, 1, 0, -0.848897, 0.528558, -0.210351, -0.405676, 0.889483, 0, -0.0810577, 0.996709, 0, -0.92105, 0.389444, -0.197353, -0.573024, 0.795421, -0.167145, 0.336293, 0.926806, -0.401672, 0.237397, 0.884479, 0.653302, 0.379175, 0.655303, 0, 0, -1, 0.653177, 0, -0.757205, 0.653121, -0.37807, -0.656122, 0, -0.49926, -0.866452, 0.671631, -0.686645, -0.278262, 0, -0.926881, -0.375357, -0.433934, -0.447965, 0.781683, -0.4965, -0.437441, 0.749755, -0.353503, -0.137195, 0.925318, 0, -0.848897, 0.528558, -0.359502, -0.75906, 0.542758, 0, -0.0770792, 0.997025, 0.168109, 0.172111, 0.970627, 0.402511, 0.237301, 0.884123, 0.65355, -0.378318, 0.655551, 0.653672, 0, 0.756778, -0.167136, 0.17214, 0.97079, 0.668803, -0.684822, 0.289347, 0.880048, 0.129007, 0.457025, 0.644507, 0.0390307, 0.763601, 0, 0.542878, -0.839811, 0.823173, -0.419088, -0.383081, 0, 0.941447, 0.33716, 0.175995, 0.932972, 0.31399, 0.269002, 0.885006, 0.380003, 0.644374, -0.493286, -0.584339, 0.355385, -0.786851, 0.504546, 0.641692, -0.681736, 0.351379, 0.758512, -0.647437, -0.07405, 0, -0.746027, 0.665916, 0.905274, -0.411124, -0.107032, 0.759428, -0.614346, -0.214121, 0.64053, -0.74862, -0.171142, 0.712784, -0.693763, -0.103113, 0, -0.812786, -0.582563, 0.707572, -0.706571, 0.0100081, 0.463983, -0.666975, -0.582978, 0.721736, -0.682696, -0.114116, 0.557506, -0.667605, 0.493448, 0, -0.762778, 0.64666, -0.001, 1, 0, 0.653177, 0.757205, -0, 0.652874, 0.655873, -0.378927, -0.0379873, 0.86471, -0.500832, 0.652874, 0.378927, -0.655873, -0.0350082, 0.578135, -0.81519, -0.0380063, 0.865143, 0.500083, 0.653121, 0.656122, 0.37807, 0, 0.610194, -0.792252, -0.0350367, 0.578606, 0.814854, 0.168118, 0.336236, 0.926651, 0, 0.610678, 0.791879, -0.322586, -0.753368, 0.57304, -0.201292, 0.315457, 0.927345, -0.598836, 0.562786, 0.569796, -0.77072, -0.535194, 0.345772, -0.598495, 0.562465, -0.570471, -0.695505, 0.718521, 0, -0.322401, -0.752935, -0.573713, -0.201105, 0.315165, -0.927485, -0.770452, -0.535009, -0.346654, -0.868428, -0.495815, 0, -0.166079, 0.584278, -0.794378, 0.725013, 0.614011, -0.312005, 0.783924, 0.600942, -0.155985, -0.307188, 0.942578, -0.13108, 0.20797, 0.969858, -0.126981, 0.469334, 0.813578, 0.343244, 0.832129, 0.51608, -0.203032, 0.840228, 0.527143, -0.127034, 0.969385, 0.0600239, 0.238095, 0.952177, -0.0830154, -0.294055, 0.839764, 0.518854, -0.159955, 0.243161, 0.805534, 0.540358, -0.499387, 0.365283, 0.785609, 0.0100097, -0.126123, 0.991964, 0.619388, 0.285179, 0.731458, -0.0480059, 0.723089, -0.689085, -0.844811, 0.209201, -0.492473, -0.858057, 0.492607, 0.145179, -0.087994, 0.993932, -0.0659955, 0.211062, 0.160047, -0.964281, -0.528498, -0.362341, -0.767723, -0.882646, -0.432807, 0.183342, -0.834757, -0.393829, 0.38481, -0.828558, -0.534004, 0.168317, -0.857347, -0.490771, 0.155244, 0.312458, -0.724062, 0.614902, -0.642324, -0.679401, 0.354731, -0.66104, -0.735157, 0.150236, 0.252182, -0.959691, -0.124089, -0.727189, -0.516845, 0.451739, -0.771757, -0.6116, 0.174171, -0.114173, -0.784191, -0.609926, -0.772971, -0.455572, 0.441554, -0.536629, -0.819961, 0.199233, 0.891247, -0.346096, -0.293081, 0.610287, -0.176083, -0.772363, 0.90152, -0.162094, 0.401232, 0.771935, 0.0689942, -0.631947, 0.537293, -0.621339, -0.570311, -0.0540481, -0.627558, -0.776691, 0.316027, 0.0940081, -0.944081, -0.860836, 0.107104, 0.497483, -0.796642, -0.304628, 0.522076, 0.00800875, -0.117128, 0.993085, 0.039037, 0.0810768, 0.995943, -0.524159, 0.804245, -0.280085, -0.871318, 0.130047, -0.473173, -0.594398, 0.585392, 0.551369, 0.201228, 0.367416, 0.908027, -0.0660001, 0.521001, -0.851001, -0.381991, 0.129997, -0.914978, 0.776865, 0.061068, 0.626698, 0.739716, 0.276267, 0.613594, 0.586846, 0.358906, -0.725809, 0.992681, 0.0719769, -0.0969689, 0.959955, 0.276987, 0.0419981, 0.896837, 0.27695, -0.344937, 0.943158, 0.164027, -0.289048, 0.856205, 0.516124, 0.0230055, 0.765861, 0.641883, 0.0379931, 0.728923, 0.358962, -0.582938, 0.611128, 0.786165, -0.0920193, 0.513938, 0.812902, -0.273967, 0.309918, 0.95075, 0.00499869, 0.477944, 0.853899, 0.205976, 0.78201, 0.597008, 0.179002, 0.806061, 0.578044, 0.12701, 0.83154, 0.55436, 0.0350227, -0.0100024, 0.996243, -0.086021, -0.0100089, 0.826736, 0.562501, 0.741242, 0.504165, 0.443145, 0.617246, 0.733292, -0.285114, -0.798305, 0.375614, 0.470769, -0.681174, 0.189326, 0.707219, -0.00600732, 0.548668, 0.836019, 0.655362, 0.336185, 0.676373, 0.0320557, -0.441767, 0.896557, 0.617741, -0.63376, 0.465558, 0.507043, 0.725062, 0.46604, 0.168043, 0.870221, 0.463117, 0.712406, 0.61435, 0.339193, 0.410577, 0.0530746, 0.91028, 0.848013, 0.508008, -0.151002, 0.764501, -0.387254, 0.515338, -0.0370272, 0.718529, 0.694511, 0.161004, 0.0760018, -0.984023, 0.75992, 0.483949, -0.433954, 0.812386, -0.50524, -0.291138, 0.820886, 0.420942, -0.385946, 0.512377, -0.289213, -0.808595, 0.224054, 0.739177, -0.635152, 0.724828, 0.0749822, -0.684837, 0.430854, 0.303897, -0.849712, 0.80043, 0.434233, 0.413222, 0.0360521, -0.808167, 0.587849, 0.0470365, -0.996773, -0.0650504, -0.266242, -0.820747, -0.50546, -0.628795, -0.428542, -0.648821, -0.296489, -0.309511, 0.903492, -0.621939, 0.221334, 0.751134, -0.897759, 0.1181, -0.424359, -0.920222, 0.351467, 0.172229, 0.753738, -0.65364, 0.0680667, 0.674665, -0.252249, 0.693684, -0.713001, -0.691972, -0.113159, -0.454558, 0.60274, 0.655806, 0.399186, 0.805375, 0.438204, 0.565073, 0.704091, 0.430056, 0.319337, 0.223236, 0.920972, -0.564542, 0.681654, -0.465447, 0.748334, 0.534238, 0.393175, 0.750018, 0.0670016, 0.658015, 0.0799707, 0.541802, -0.836693, 0.969438, 0.150068, 0.194088, 0.723729, 0.66675, -0.177933, 0.773832, -0.575619, 0.264284, 0.703262, -0.29411, -0.647241, -0.641482, -0.336253, -0.689518, -0.692038, -0.681022, 0.239359, -0.714327, 0.637291, -0.289132, -0.559972, -0.717244, 0.41472, 0.217271, -0.957194, 0.191239, 0.686968, 0.301986, -0.660969, -0.711449, 0.136086, -0.689435, -0.19324, -0.972209, 0.132164, -0.776034, -0.314419, -0.546728, -0.776214, -0.545854, -0.315493, -0.885953, -0.401432, -0.23225, -0.885802, -0.231209, -0.402364, -0.775789, 0.546556, -0.315321, -0.775789, 0.315321, -0.546556, -0.885597, 0.232156, -0.402271, -0.885597, 0.402271, -0.232156, -0.775961, 0, -0.630781, -0.885655, 0, -0.464344, -0.326142, 0.818357, -0.473206, -0.326142, 0.473206, -0.818357, -0.326296, -0.472429, -0.818744, -0.326409, -0.818026, -0.473594, -0.326114, 0, -0.94533, 0.653121, 0.656122, 0.37807, -0.326296, 0.818744, 0.472429, -0.326409, 0.473594, 0.818026, 0.653302, 0.379175, 0.655303, -0.326423, 0, 0.945224, 0.653672, 0, 0.756778, -0.326564, -0.472817, 0.818413, 0.65355, -0.378318, 0.655551, 0.653121, -0.37807, -0.656122, 0.653302, -0.655303, -0.379175, -0.326564, -0.818413, 0.472817, 0.65355, -0.655551, 0.378318, 0.653177, 0, -0.757205, -0.326423, -0.945224, 0, 0.653672, -0.756778, 0, 0.652874, 0.378927, -0.655873, 0.652874, 0.655873, -0.378927, 0.653177, 0.757205, -0, -0.326114, 0.94533, 0, -0.776214, 0.315493, 0.545854, -0.776451, 0, 0.630178, -0.776459, -0.314591, 0.546026, -0.776459, -0.546026, 0.314591, -0.776451, -0.630178, 0, -0.775961, 0.630781, 0, -0.776034, 0.546728, 0.314419, -0.886159, -0.401525, 0.231302, -0.886067, -0.463558, 0, -0.886067, 0, 0.463558, -0.886159, -0.231302, 0.401525, -0.885953, 0.23225, 0.401432, -0.885802, 0.402364, 0.231209, -0.885655, 0.464344, 0, -0.31946, 0.0650937, 0.945361, -0.0160178, 0.688766, 0.724806, -0.609345, 0.431244, -0.665377, -0.182148, 0.866704, 0.464377, -0.302298, 0.80179, 0.515508, -0.947416, 0.264395, -0.18027, 0.0140125, 0.730651, 0.682608, -0.225049, 0.737161, 0.637139, 0.0280069, 0.825204, 0.56414, 0.054026, 0.840405, 0.53926, -0.220295, 0.645864, 0.730978, 0.0360333, 0.777718, 0.62758, 0.0420165, 0.81832, 0.573224, -0.274414, 0.29144, 0.916384, -0.778358, -0.489855, 0.392685, -0.652026, -0.668052, 0.358564, -0.271477, -0.803413, 0.529932, -0.746101, -0.651962, -0.135199, -0.357087, 0.929225, -0.095023, -0.670864, 0.730942, 0.125161, -0.442668, 0.436659, 0.783182, -0.324243, -0.340255, -0.882662, -0.554518, 0.240224, -0.796745, -0.404517, -0.612784, 0.678868, -0.323422, -0.946236, 0.00600785, -0.677918, 0.508689, 0.530719, -0.580624, -0.797857, -0.162174, -0.623964, -0.536829, -0.567877, -0.737833, -0.658744, -0.147166, -0.896969, -0.42546, 0.12013, -0.915864, -0.0850803, -0.39237, -0.746391, -0.538003, -0.39173, -0.246181, 0.836614, 0.489359, -0.179039, 0.858186, 0.481104, -0.186067, 0.840304, 0.509184, -0.244187, 0.817627, 0.5214, -0.142132, 0.833775, 0.533496, -0.341296, -0.328285, -0.880764, -0.536055, 0.0430044, -0.843087, -0.371558, -0.37957, 0.847273, -0.294382, -0.814057, 0.50065, -0.194101, 0.90047, 0.389203, -0.808384, 0.58828, -0.02101, -0.804522, 0.356675, 0.474898, -0.450328, 0.771563, -0.449328, -0.168155, 0.969892, 0.176162, -0.789553, -0.410808, 0.455897, -0.656822, -0.729914, 0.189237, -0.705129, 0.319511, 0.633013, -0.307366, 0.41149, 0.858022, -0.471882, -0.881648, 0.00500936, -0.230297, -0.951225, 0.205264, -0.887098, -0.393487, -0.241299, -0.617794, -0.76298, -0.190244, -0.258094, -0.529194, -0.808295, -0.972665, -0.232159, -0.00500342, -0.748045, -0.564789, -0.348487, -0.79332, -0.521869, -0.313522, -0.306156, -0.405206, -0.861439, -0.240392, -0.969582, -0.0460752, 0.257302, -0.748879, -0.610717, -0.799878, -0.563619, -0.206226, -0.678856, -0.526664, -0.511645, -0.794437, -0.441799, -0.416754, -0.780599, -0.431331, -0.452347, -0.726837, -0.686791, 0.00500577, -0.915181, -0.347448, -0.204264, -0.534758, -0.673956, -0.509723, -0.97142, -0.237347, 0.00300439, -0.848814, -0.528507, -0.0140134, -0.730652, -0.680607, -0.0540482, -0.864338, -0.499774, -0.0560868, -0.833134, -0.540736, -0.116158, -0.98426, 0.0881128, -0.153196, -0.98426, 0.153196, -0.0881128, -0.98441, -0.152218, -0.0881262, -0.984346, -0.0871191, -0.15321, -0.984347, 0, -0.176241, -0.98441, 0.0881262, 0.152218, -0.98452, 0, 0.175271, -0.984497, -0.0871325, 0.152231, -0.984497, -0.152231, 0.0871325, -0.98452, -0.175271, 0, -0.984347, 0.176241, 0, -0.984346, 0.15321, 0.0871191, 0.211308, -0.405591, 0.889295, 0.198315, -0.572911, 0.795264, 0.168118, 0.336236, 0.926651, -0.652728, 0.379423, 0.655732, 0.402511, 0.237301, 0.884123, -0.652547, -0.378317, -0.65655, -0.652603, 0, -0.7577, -0.671081, -0.687107, -0.278449, 0.354379, -0.137147, 0.92499, 0.497254, -0.437223, 0.749383, 0.434747, -0.44777, 0.781343, 0.360374, -0.758786, 0.542562, -0.167136, 0.17214, 0.97079, -0.401672, 0.237397, 0.884479, -0.652976, -0.378566, 0.65598, 0.168109, 0.172111, 0.970627, -0.653098, 0, 0.757273, -0.668249, -0.685281, 0.289541, -0.879823, 0.129121, 0.457428, -0.643922, 0.0390559, 0.764094, -0.82285, -0.419434, -0.383396, -0.175025, 0.933135, 0.314046, -0.268074, 0.885244, 0.380105, -0.643788, -0.493604, -0.584716, -0.641103, -0.682174, 0.351605, -0.354509, -0.787131, 0.504725, -0.758087, -0.647929, -0.0741063, -0.759004, -0.614813, -0.214283, -0.905093, -0.411497, -0.107129, -0.639939, -0.7491, -0.171251, -0.712291, -0.694258, -0.103187, -0.707071, -0.707071, 0.0100152, -0.463198, -0.667285, -0.583249, -0.721256, -0.68319, -0.114199, -0.556815, -0.667978, 0.493723, 0.002, 0.999998, -0, 0.0389854, 0.864677, -0.500813, -0.6523, 0.656302, -0.379174, -0.652603, 0.7577, 0, 0.0360071, 0.578114, -0.815161, -0.6523, 0.379174, -0.656302, -0.652547, 0.65655, 0.378317, 0.039005, 0.86511, 0.500063, 0.0360365, 0.578586, 0.814825, -0.167145, 0.336293, 0.926806 </vector3_array>
- <nil> </nil>
- <nil> </nil>
- <nil> </nil>
- <nil> </nil>
- <real_array len="2716"> 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 9, 8, 0, 0, 8, 9, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 12, 13, 0, 0, 12, 13, 0, 0, 13, 12, 0, 0, 13, 12, 0, 0, 13, 12, 0, 0, 13, 12, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 12, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 9, 8, 0, 0, 8, 9, 0, 0, 9, 0, 0, 0, 8, 9, 0, 0, 9, 8, 0, 0, 9, 0, 0, 0, 8, 9, 0, 0, 8, 9, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 12, 13, 0, 0, 12, 13, 0, 0, 13, 12, 0, 0, 13, 12, 0, 0, 12, 13, 0, 0, 12, 13, 0, 0, 13, 12, 0, 0, 12, 13, 0, 0, 12, 13, 0, 0, 13, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 12, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 7, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 11, 10, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 10, 11, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 15, 16, 0, 0, 16, 15, 0, 0, 16, 15, 0, 0, 15, 16, 0, 0, 16, 15, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 15, 0, 0, 16, 15, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 11, 10, 0, 0, 11, 0, 0, 0, 10, 11, 0, 0, 10, 11, 0, 0, 11, 10, 0, 0, 11, 0, 0, 0, 10, 11, 0, 0, 11, 0, 0, 0, 10, 11, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 15, 16, 0, 0, 16, 15, 0, 0, 16, 15, 0, 0, 15, 16, 0, 0, 15, 16, 0, 0, 16, 15, 0, 0, 15, 16, 0, 0, 15, 16, 0, 0, 15, 16, 0, 0, 16, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 16, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 16, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 15, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0 </real_array>
- <real_array len="2716"> 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.5, 0.5, 0, 0, 0.503159, 0.496841, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.700171, 0.299829, 0, 0, 0.66474, 0.33526, 0, 0, 0.704636, 0.295364, 0, 0, 0.664742, 0.335258, 0, 0, 0.719812, 0.280188, 0, 0, 0.682575, 0.317425, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.664813, 0.335187, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.533212, 0.466788, 0, 0, 0.538228, 0.461772, 0, 0, 1, 0, 0, 0, 0.500006, 0.499994, 0, 0, 0.525218, 0.474782, 0, 0, 1, 0, 0, 0, 0.563768, 0.436232, 0, 0, 0.523139, 0.476861, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.665519, 0.334481, 0, 0, 0.664658, 0.335342, 0, 0, 0.676033, 0.323967, 0, 0, 0.667711, 0.332289, 0, 0, 0.668675, 0.331325, 0, 0, 0.673479, 0.326521, 0, 0, 0.667424, 0.332576, 0, 0, 0.6672, 0.3328, 0, 0, 0.664792, 0.335208, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.500004, 0.499996, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.997415, 0.00258508, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.5, 0.5, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.503159, 0.496841, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.700171, 0.299829, 0, 0, 0.664742, 0.335258, 0, 0, 0.704636, 0.295364, 0, 0, 0.66474, 0.33526, 0, 0, 0.719812, 0.280188, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.682575, 0.317425, 0, 0, 0.664813, 0.335187, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.533212, 0.466788, 0, 0, 1, 0, 0, 0, 0.538228, 0.461772, 0, 0, 0.500006, 0.499994, 0, 0, 0.525218, 0.474782, 0, 0, 1, 0, 0, 0, 0.563768, 0.436232, 0, 0, 1, 0, 0, 0, 0.523139, 0.476861, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.665519, 0.334481, 0, 0, 0.667711, 0.332289, 0, 0, 0.676033, 0.323967, 0, 0, 0.664658, 0.335342, 0, 0, 0.668675, 0.331325, 0, 0, 0.667424, 0.332576, 0, 0, 0.673479, 0.326521, 0, 0, 0.6672, 0.3328, 0, 0, 0.664792, 0.335208, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.500004, 0.499996, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 </real_array>
- <int_array len="3246"> 0, 2, 1, 0, 3, 2, 4, 6, 5, 4, 7, 6, 8, 10, 9, 8, 11, 10, 12, 3, 0, 12, 13, 3, 11, 6, 10, 11, 14, 6, 14, 5, 6, 14, 15, 5, 1, 5, 15, 1, 2, 5, 4, 2, 16, 4, 5, 2, 16, 3, 13, 16, 2, 3, 7, 10, 6, 7, 9, 10, 17, 19, 18, 17, 20, 19, 19, 22, 21, 19, 23, 22, 24, 26, 25, 24, 27, 26, 28, 30, 29, 28, 31, 30, 32, 34, 33, 32, 35, 34, 33, 31, 28, 33, 34, 31, 36, 35, 32, 36, 37, 35, 34, 38, 31, 34, 39, 38, 37, 40, 35, 37, 41, 40, 42, 44, 43, 42, 45, 44, 31, 46, 30, 31, 38, 46, 35, 39, 34, 35, 40, 39, 43, 48, 47, 43, 44, 48, 47, 41, 37, 47, 48, 41, 30, 45, 42, 30, 46, 45, 44, 49, 48, 48, 49, 41, 46, 49, 45, 39, 50, 38, 41, 50, 40, 41, 49, 50, 45, 49, 44, 38, 49, 46, 38, 50, 49, 40, 50, 39, 51, 47, 52, 51, 43, 47, 52, 37, 36, 52, 47, 37, 53, 43, 51, 53, 42, 43, 29, 42, 53, 29, 30, 42, 54, 56, 55, 54, 57, 56, 58, 60, 59, 58, 61, 60, 62, 58, 63, 62, 64, 58, 63, 59, 65, 63, 58, 59, 66, 64, 62, 66, 67, 64, 65, 69, 68, 65, 59, 69, 70, 67, 66, 70, 55, 67, 68, 72, 71, 68, 69, 72, 73, 55, 70, 73, 54, 55, 74, 76, 75, 74, 77, 76, 78, 80, 79, 78, 81, 80, 82, 83, 77, 82, 84, 83, 85, 87, 86, 85, 88, 87, 89, 90, 88, 89, 91, 90, 88, 92, 87, 88, 90, 92, 91, 93, 90, 90, 93, 92, 92, 93, 94, 55, 56, 67, 65, 95, 63, 65, 96, 95, 68, 96, 65, 68, 97, 96, 71, 54, 73, 71, 72, 54, 98, 24, 99, 98, 100, 24, 18, 21, 101, 18, 19, 21, 102, 20, 17, 102, 103, 20, 99, 25, 104, 99, 24, 25, 101, 100, 98, 101, 21, 100, 104, 106, 105, 104, 25, 106, 105, 103, 102, 105, 106, 103, 20, 23, 19, 20, 107, 23, 25, 108, 106, 25, 26, 108, 106, 109, 103, 106, 108, 109, 100, 27, 24, 100, 110, 27, 103, 107, 20, 103, 109, 107, 21, 110, 100, 21, 22, 110, 27, 111, 26, 27, 112, 111, 26, 113, 108, 26, 111, 113, 108, 114, 109, 108, 113, 114, 110, 112, 27, 110, 115, 112, 22, 115, 110, 22, 116, 115, 109, 117, 107, 109, 114, 117, 107, 118, 23, 107, 117, 118, 23, 116, 22, 23, 118, 116, 72, 57, 54, 72, 119, 57, 59, 120, 69, 59, 60, 120, 64, 61, 58, 64, 121, 61, 69, 119, 72, 69, 120, 119, 122, 124, 123, 122, 125, 124, 126, 125, 122, 126, 79, 125, 123, 128, 127, 123, 124, 128, 129, 79, 126, 129, 78, 79, 130, 77, 74, 130, 82, 77, 75, 78, 129, 75, 76, 78, 127, 82, 130, 127, 128, 82, 124, 97, 128, 124, 96, 97, 79, 95, 125, 79, 80, 95, 128, 84, 82, 128, 97, 84, 76, 81, 78, 76, 131, 81, 77, 131, 76, 77, 83, 131, 125, 96, 124, 125, 95, 96, 86, 133, 132, 86, 87, 133, 134, 89, 135, 134, 136, 89, 135, 88, 85, 135, 89, 88, 136, 91, 89, 136, 137, 91, 87, 94, 133, 87, 92, 94, 137, 93, 91, 67, 121, 64, 67, 56, 121, 83, 70, 131, 83, 73, 70, 73, 84, 71, 73, 83, 84, 63, 80, 62, 63, 95, 80, 66, 131, 70, 66, 81, 131, 97, 71, 84, 97, 68, 71, 81, 62, 80, 81, 66, 62, 138, 140, 139, 138, 141, 140, 57, 139, 56, 138, 139, 119, 119, 139, 57, 56, 139, 121, 132, 136, 134, 132, 133, 136, 137, 133, 94, 137, 136, 133, 94, 93, 137, 142, 144, 143, 142, 145, 144, 146, 148, 147, 146, 149, 148, 149, 150, 148, 149, 151, 150, 151, 143, 150, 151, 142, 143, 152, 149, 146, 152, 153, 149, 154, 145, 142, 154, 155, 145, 156, 142, 151, 156, 154, 142, 153, 151, 149, 153, 156, 151, 157, 159, 158, 157, 160, 159, 158, 162, 161, 158, 159, 162, 161, 164, 163, 161, 162, 164, 165, 155, 154, 165, 166, 155, 163, 168, 167, 163, 164, 168, 169, 154, 156, 169, 165, 154, 167, 171, 170, 167, 168, 171, 172, 156, 153, 172, 169, 156, 173, 153, 152, 173, 172, 153, 174, 160, 157, 174, 175, 160, 159, 176, 162, 159, 177, 176, 162, 178, 164, 162, 176, 178, 164, 179, 168, 164, 178, 179, 168, 180, 171, 168, 179, 180, 175, 181, 160, 175, 182, 181, 160, 177, 159, 160, 181, 177, 179, 183, 180, 179, 184, 183, 176, 185, 178, 176, 186, 185, 177, 186, 176, 177, 187, 186, 181, 187, 177, 181, 188, 187, 178, 184, 179, 178, 185, 184, 182, 188, 181, 182, 189, 188, 182, 147, 189, 182, 146, 147, 145, 183, 144, 145, 180, 183, 175, 146, 182, 175, 152, 146, 155, 180, 145, 155, 171, 180, 174, 152, 175, 174, 173, 152, 166, 171, 155, 166, 170, 171, 190, 192, 191, 190, 193, 192, 194, 196, 195, 194, 197, 196, 198, 199, 197, 198, 200, 199, 201, 203, 202, 201, 204, 203, 197, 205, 196, 197, 199, 205, 193, 206, 192, 193, 207, 206, 196, 204, 201, 196, 205, 204, 202, 207, 193, 202, 203, 207, 207, 208, 206, 207, 209, 208, 210, 212, 211, 210, 213, 212, 199, 214, 205, 199, 215, 214, 203, 209, 207, 203, 216, 209, 217, 219, 218, 217, 220, 219, 221, 223, 222, 221, 224, 223, 205, 225, 204, 205, 214, 225, 204, 216, 203, 204, 225, 216, 224, 211, 226, 221, 211, 224, 210, 211, 221, 200, 215, 199, 200, 227, 215, 219, 229, 228, 219, 230, 229, 224, 231, 223, 224, 232, 231, 228, 234, 233, 228, 229, 234, 226, 232, 224, 226, 235, 232, 220, 230, 219, 220, 236, 230, 233, 235, 226, 233, 234, 235, 237, 214, 238, 237, 225, 214, 215, 238, 214, 215, 218, 238, 218, 227, 217, 218, 215, 227, 221, 216, 210, 221, 209, 216, 209, 222, 208, 209, 221, 222, 225, 210, 216, 225, 237, 210, 218, 219, 238, 238, 219, 239, 239, 219, 228, 240, 242, 241, 243, 245, 244, 243, 246, 245, 247, 249, 248, 247, 250, 249, 251, 253, 252, 251, 254, 253, 255, 256, 242, 255, 257, 256, 258, 260, 259, 258, 261, 260, 262, 254, 251, 262, 263, 254, 242, 264, 241, 242, 256, 264, 240, 246, 243, 240, 241, 246, 241, 265, 246, 241, 264, 265, 259, 257, 255, 259, 260, 257, 263, 266, 254, 263, 267, 266, 268, 267, 263, 268, 269, 267, 250, 270, 249, 250, 271, 270, 254, 272, 253, 254, 266, 272, 251, 264, 262, 251, 265, 264, 248, 261, 247, 248, 260, 261, 257, 273, 256, 260, 274, 257, 260, 248, 274, 265, 252, 275, 265, 251, 252, 256, 262, 264, 256, 276, 262, 246, 275, 245, 246, 265, 275, 271, 277, 270, 271, 278, 277, 226, 279, 233, 226, 280, 279, 211, 280, 226, 211, 212, 280, 237, 213, 210, 237, 281, 213, 233, 282, 228, 233, 279, 282, 238, 281, 237, 238, 283, 281, 276, 284, 262, 262, 284, 268, 262, 268, 263, 248, 249, 274, 274, 249, 285, 285, 249, 286, 249, 287, 286, 249, 270, 287, 286, 287, 288, 288, 287, 268, 268, 287, 269, 276, 289, 284, 276, 290, 289, 274, 291, 273, 274, 292, 291, 273, 290, 276, 273, 291, 290, 273, 257, 274, 256, 273, 276, 147, 294, 293, 147, 148, 294, 143, 296, 295, 143, 144, 296, 150, 295, 297, 150, 143, 295, 148, 297, 294, 148, 150, 297, 187, 298, 186, 187, 299, 298, 186, 300, 185, 186, 298, 300, 185, 301, 184, 185, 300, 301, 184, 302, 183, 184, 301, 302, 189, 303, 188, 189, 304, 303, 188, 299, 187, 188, 303, 299, 305, 307, 306, 308, 310, 309, 311, 313, 312, 189, 293, 304, 189, 147, 293, 144, 302, 296, 144, 183, 302, 314, 316, 315, 314, 317, 316, 317, 318, 316, 317, 319, 318, 310, 321, 320, 310, 322, 321, 307, 323, 306, 307, 324, 323, 320, 324, 307, 320, 321, 324, 308, 322, 310, 308, 325, 322, 326, 305, 327, 328, 330, 329, 328, 326, 330, 326, 320, 307, 320, 326, 328, 328, 310, 320, 326, 307, 305, 309, 310, 331, 331, 310, 328, 312, 329, 330, 313, 329, 312, 195, 201, 332, 195, 196, 201, 333, 193, 190, 333, 202, 193, 334, 197, 194, 334, 198, 197, 332, 202, 333, 332, 201, 202, 239, 283, 238, 239, 335, 283, 336, 259, 337, 336, 258, 259, 337, 255, 338, 337, 259, 255, 338, 242, 240, 338, 255, 242, 270, 339, 287, 270, 277, 339, 267, 340, 266, 267, 341, 340, 287, 342, 269, 287, 339, 342, 269, 341, 267, 269, 342, 341, 266, 343, 272, 266, 340, 343, 286, 344, 285, 286, 345, 344, 228, 335, 239, 228, 282, 335, 288, 345, 286, 288, 346, 345, 268, 346, 288, 268, 347, 346, 284, 347, 268, 284, 289, 347, 285, 292, 274, 285, 344, 292, 348, 318, 319, 348, 349, 318, 350, 349, 348, 351, 349, 350, 352, 349, 351, 353, 349, 352, 309, 349, 353, 309, 331, 349, 354, 356, 355, 354, 357, 356, 357, 358, 356, 357, 359, 358, 354, 361, 360, 354, 355, 361, 362, 314, 359, 359, 314, 358, 358, 314, 315, 360, 361, 363, 363, 361, 313, 363, 313, 364, 364, 313, 311, 365, 363, 305, 364, 327, 363, 327, 305, 363, 366, 368, 367, 366, 369, 368, 4, 370, 7, 4, 371, 370, 8, 373, 372, 8, 9, 373, 12, 367, 13, 12, 366, 367, 372, 370, 374, 372, 373, 370, 374, 371, 375, 374, 370, 371, 369, 371, 368, 369, 375, 371, 4, 368, 371, 4, 16, 368, 16, 367, 368, 16, 13, 367, 7, 373, 9, 7, 370, 373, 376, 378, 377, 376, 379, 378, 378, 381, 380, 378, 382, 381, 383, 385, 384, 383, 386, 385, 387, 389, 388, 387, 390, 389, 391, 393, 392, 391, 394, 393, 394, 388, 393, 394, 387, 388, 395, 392, 396, 395, 391, 392, 393, 398, 397, 393, 388, 398, 396, 400, 399, 396, 392, 400, 401, 403, 402, 401, 404, 403, 388, 405, 398, 388, 389, 405, 392, 397, 400, 392, 393, 397, 404, 406, 403, 404, 407, 406, 407, 399, 406, 407, 396, 399, 389, 402, 405, 389, 401, 402, 403, 406, 408, 406, 399, 408, 405, 402, 408, 397, 398, 409, 399, 409, 408, 399, 400, 409, 402, 403, 408, 398, 408, 409, 398, 405, 408, 400, 397, 409, 410, 407, 404, 410, 411, 407, 411, 396, 407, 411, 395, 396, 412, 404, 401, 412, 410, 404, 390, 401, 389, 390, 412, 401, 413, 415, 414, 413, 416, 415, 417, 419, 418, 417, 420, 419, 421, 417, 422, 421, 423, 417, 423, 420, 417, 423, 424, 420, 425, 422, 426, 425, 421, 422, 424, 427, 420, 424, 428, 427, 429, 426, 416, 429, 425, 426, 428, 430, 427, 428, 431, 430, 432, 416, 413, 432, 429, 416, 433, 435, 434, 433, 436, 435, 437, 439, 438, 437, 440, 439, 441, 443, 442, 441, 434, 443, 444, 446, 445, 444, 447, 446, 448, 450, 449, 448, 445, 450, 445, 451, 450, 445, 446, 451, 449, 450, 452, 450, 451, 452, 451, 453, 452, 416, 426, 415, 424, 455, 454, 424, 423, 455, 428, 454, 456, 428, 424, 454, 431, 413, 430, 431, 432, 413, 457, 383, 458, 457, 459, 383, 379, 382, 378, 379, 460, 382, 461, 377, 462, 461, 376, 377, 459, 386, 383, 459, 463, 386, 460, 458, 382, 460, 457, 458, 463, 464, 386, 463, 465, 464, 465, 462, 464, 465, 461, 462, 377, 380, 466, 377, 378, 380, 386, 467, 385, 386, 464, 467, 464, 468, 467, 464, 462, 468, 458, 384, 469, 458, 383, 384, 462, 466, 468, 462, 377, 466, 382, 469, 381, 382, 458, 469, 384, 471, 470, 384, 385, 471, 385, 472, 471, 385, 467, 472, 467, 473, 472, 467, 468, 473, 469, 470, 474, 469, 384, 470, 381, 474, 475, 381, 469, 474, 468, 476, 473, 468, 466, 476, 466, 477, 476, 466, 380, 477, 380, 475, 477, 380, 381, 475, 430, 414, 478, 430, 413, 414, 420, 479, 419, 420, 427, 479, 422, 418, 480, 422, 417, 418, 427, 478, 479, 427, 430, 478, 481, 483, 482, 481, 484, 483, 485, 482, 440, 485, 481, 482, 484, 486, 483, 484, 487, 486, 488, 440, 437, 488, 485, 440, 489, 434, 441, 489, 433, 434, 436, 437, 435, 436, 488, 437, 487, 441, 486, 487, 489, 441, 483, 456, 454, 483, 486, 456, 440, 455, 439, 440, 482, 455, 486, 442, 456, 486, 441, 442, 435, 438, 490, 435, 437, 438, 434, 490, 443, 434, 435, 490, 482, 454, 455, 482, 483, 454, 447, 491, 446, 447, 492, 491, 493, 448, 494, 493, 495, 448, 495, 445, 448, 495, 444, 445, 494, 449, 496, 494, 448, 449, 446, 453, 451, 446, 491, 453, 496, 449, 452, 426, 480, 415, 426, 422, 480, 443, 429, 432, 443, 490, 429, 432, 442, 443, 432, 431, 442, 423, 439, 455, 423, 421, 439, 425, 490, 438, 425, 429, 490, 456, 431, 428, 456, 442, 431, 438, 421, 425, 438, 439, 421, 497, 499, 498, 497, 500, 499, 414, 415, 500, 497, 478, 500, 478, 414, 500, 415, 480, 500, 492, 494, 491, 492, 493, 494, 496, 491, 494, 496, 453, 491, 453, 496, 452, 501, 503, 502, 501, 504, 503, 505, 507, 506, 505, 508, 507, 506, 510, 509, 506, 507, 510, 509, 504, 501, 509, 510, 504, 511, 506, 512, 511, 505, 506, 513, 502, 514, 513, 501, 502, 515, 501, 513, 515, 509, 501, 512, 509, 515, 512, 506, 509, 516, 518, 517, 516, 519, 518, 519, 520, 518, 519, 521, 520, 521, 522, 520, 521, 523, 522, 524, 514, 525, 524, 513, 514, 523, 526, 522, 523, 527, 526, 528, 513, 524, 528, 515, 513, 527, 529, 526, 527, 530, 529, 531, 515, 528, 531, 512, 515, 532, 512, 531, 532, 511, 512, 533, 517, 534, 533, 516, 517, 518, 536, 535, 518, 520, 536, 520, 537, 536, 520, 522, 537, 522, 538, 537, 522, 526, 538, 526, 539, 538, 526, 529, 539, 534, 541, 540, 534, 517, 541, 517, 535, 541, 517, 518, 535, 538, 543, 542, 538, 539, 543, 536, 545, 544, 536, 537, 545, 535, 544, 546, 535, 536, 544, 541, 546, 547, 541, 535, 546, 537, 542, 545, 537, 538, 542, 540, 547, 548, 540, 541, 547, 540, 508, 505, 540, 548, 508, 502, 543, 539, 502, 503, 543, 534, 505, 511, 534, 540, 505, 514, 539, 529, 514, 502, 539, 533, 511, 532, 533, 534, 511, 525, 529, 530, 525, 514, 529, 549, 192, 550, 549, 191, 192, 551, 553, 552, 551, 554, 553, 198, 555, 200, 198, 552, 555, 556, 558, 557, 556, 559, 558, 552, 560, 555, 552, 553, 560, 550, 206, 561, 550, 192, 206, 553, 557, 560, 553, 556, 557, 559, 561, 558, 559, 550, 561, 561, 208, 562, 561, 206, 208, 563, 565, 564, 563, 566, 565, 555, 568, 567, 555, 560, 568, 558, 562, 569, 558, 561, 562, 217, 570, 220, 217, 571, 570, 572, 223, 573, 572, 222, 223, 560, 574, 568, 560, 557, 574, 557, 569, 574, 557, 558, 569, 566, 573, 575, 566, 572, 573, 563, 572, 566, 200, 567, 227, 200, 555, 567, 570, 229, 230, 570, 576, 229, 573, 231, 232, 573, 223, 231, 576, 234, 229, 576, 577, 234, 575, 232, 235, 575, 573, 232, 220, 230, 236, 220, 570, 230, 577, 235, 234, 577, 575, 235, 578, 568, 574, 578, 579, 568, 567, 579, 571, 567, 568, 579, 571, 227, 567, 571, 217, 227, 572, 569, 562, 572, 563, 569, 562, 222, 572, 562, 208, 222, 574, 563, 578, 574, 569, 563, 571, 579, 570, 570, 579, 580, 570, 580, 576, 581, 583, 582, 584, 245, 585, 584, 244, 245, 247, 586, 250, 247, 587, 586, 588, 253, 589, 588, 252, 253, 590, 592, 591, 590, 582, 592, 258, 593, 261, 258, 594, 593, 595, 589, 596, 595, 588, 589, 582, 597, 592, 582, 583, 597, 581, 585, 583, 581, 584, 585, 583, 598, 597, 583, 585, 598, 594, 591, 593, 594, 590, 591, 596, 600, 599, 596, 589, 600, 601, 599, 602, 601, 596, 599, 250, 603, 271, 250, 586, 603, 589, 272, 600, 589, 253, 272, 588, 597, 598, 588, 595, 597, 587, 261, 593, 587, 247, 261, 591, 592, 604, 593, 605, 587, 593, 591, 605, 598, 252, 588, 598, 275, 252, 592, 595, 606, 592, 597, 595, 585, 275, 598, 585, 245, 275, 271, 607, 278, 271, 603, 607, 575, 609, 608, 575, 577, 609, 566, 608, 565, 566, 575, 608, 578, 564, 610, 578, 563, 564, 577, 611, 609, 577, 576, 611, 579, 610, 612, 579, 578, 610, 606, 595, 613, 613, 595, 601, 601, 595, 596, 587, 605, 586, 586, 605, 614, 586, 614, 615, 586, 616, 603, 586, 615, 616, 615, 617, 616, 616, 617, 601, 616, 601, 602, 606, 619, 618, 606, 613, 619, 605, 621, 620, 605, 604, 621, 604, 618, 621, 604, 606, 618, 604, 605, 591, 592, 606, 604, 508, 622, 507, 508, 623, 622, 504, 624, 503, 504, 625, 624, 510, 625, 504, 510, 626, 625, 507, 626, 510, 507, 622, 626, 546, 628, 627, 546, 544, 628, 544, 629, 628, 544, 545, 629, 545, 630, 629, 545, 542, 630, 542, 631, 630, 542, 543, 631, 548, 633, 632, 548, 547, 633, 547, 627, 633, 547, 546, 627, 305, 306, 634, 308, 309, 635, 636, 638, 637, 548, 623, 508, 548, 632, 623, 503, 631, 543, 503, 624, 631, 314, 639, 317, 314, 640, 639, 317, 641, 319, 317, 639, 641, 635, 643, 642, 635, 644, 643, 634, 323, 645, 634, 306, 323, 644, 645, 643, 644, 634, 645, 308, 642, 325, 308, 635, 642, 646, 647, 305, 648, 650, 649, 648, 649, 646, 646, 634, 644, 644, 648, 646, 648, 644, 635, 646, 305, 634, 309, 651, 635, 651, 648, 635, 638, 649, 650, 637, 638, 650, 554, 556, 553, 554, 652, 556, 653, 550, 559, 653, 549, 550, 334, 552, 198, 334, 551, 552, 652, 559, 556, 652, 653, 559, 580, 612, 654, 580, 579, 612, 336, 594, 258, 336, 655, 594, 655, 590, 594, 655, 656, 590, 656, 582, 590, 656, 581, 582, 603, 657, 607, 603, 616, 657, 599, 659, 658, 599, 600, 659, 616, 660, 657, 616, 602, 660, 602, 658, 660, 602, 599, 658, 600, 343, 659, 600, 272, 343, 615, 662, 661, 615, 614, 662, 576, 654, 611, 576, 580, 654, 617, 661, 663, 617, 615, 661, 601, 663, 664, 601, 617, 663, 613, 664, 619, 613, 601, 664, 614, 620, 662, 614, 605, 620, 665, 319, 641, 665, 348, 319, 665, 666, 348, 665, 667, 666, 665, 668, 667, 665, 353, 668, 651, 353, 665, 309, 353, 651, 669, 671, 670, 669, 672, 671, 670, 674, 673, 670, 671, 674, 669, 675, 672, 669, 676, 675, 640, 673, 674, 362, 673, 640, 362, 640, 314, 676, 637, 675, 676, 677, 637, 637, 677, 636, 636, 677, 678, 365, 305, 677, 678, 677, 647, 647, 677, 305 </int_array>
- </array>
- </dictionary>
- <dictionary name="surfaces/1" shared="false">
- <string> "alphasort" </string>
- <bool> False </bool>
- <string> "material" </string>
- <resource resource_type="FixedMaterial" path="local://4"> </resource>
- <string> "morph_arrays" </string>
- <array len="0" shared="false">
- </array>
- <string> "primitive" </string>
- <int> 4 </int>
- <string> "arrays" </string>
- <array len="9" shared="false">
- <vector3_array len="625"> 0.23068, 6.41266, 0.879344, 0.754113, 6.74074, 0.551263, 0.754113, 6.81344, 0.551263, 0.23068, 6.48536, 0.879344, 0.845318, 6.86083, 0.103095, 0.845318, 6.93353, 0.103095, 0.754113, 6.74074, -0.345078, 0.754113, 6.81344, -0.345078, 0, 6.36123, 0.969121, 0.257165, 6.36123, 0.969121, 0, 6.41266, 0.879344, 0, 6.36123, -0.762936, 0, 6.41266, -0.673159, 0.23068, 6.41266, -0.673159, 0.257165, 6.36123, -0.762936, 0.23068, 6.48536, -0.673159, 0.2607, 6.45948, -0.774594, 0.852531, 6.83043, -0.403642, 0, 6.48536, -0.673159, 0, 6.48536, 0.879344, 0.955654, 6.96621, 0.103096, 0.852531, 6.83043, 0.609826, 0.2607, 6.45948, 0.980779, 0, 6.45948, -0.774594, 0, 6.45948, 0.980779, 0.144337, 4.62833, -0.267808, 0.227645, 4.56054, -0.149869, 0.230474, 4.54553, -0.1645, 0.145367, 4.61509, -0.285537, 0, 4.66573, -0.327684, 0, 4.65348, -0.346986, 0.16781, 4.49143, -0.0124773, 0.169802, 4.47494, -0.0244043, 2.39441, 2.7167, -0.284614, 2.22321, 2.52508, -0.185319, 2.22875, 2.57563, -0.151192, 2.37464, 2.73891, -0.235805, 0.829811, 0.39491, 0.192334, 0.539954, 0.53255, 0.320534, 0.53677, 0.505704, 0.45924, 0.823707, 0.343455, 0.299719, 0.251731, 0.393841, 0.202075, 0.245627, 0.342385, 0.30946, 2.37016, 3.14596, -0.180206, 2.39069, 3.24439, 0.0703977, 2.51365, 3.10316, 0.122743, 2.49324, 3.00574, -0.125365, 2.02679, 2.71357, 0.205928, 2.02114, 2.64141, -0.071524, 2.14773, 2.50612, -0.0177825, 2.15324, 2.5776, 0.25697, 0.197471, 4.75418, 0.019584, 0.212301, 4.88556, 0.0356146, 0, 4.86123, 0.103096, 0, 4.72999, 0.114516, 2.55604, 3.1449, 0.136694, 2.53359, 3.02984, -0.15501, 2.38915, 3.19439, -0.219368, 2.41174, 3.31063, 0.0752657, 2.13459, 2.5274, 0.293671, 2.28993, 2.80163, 0.457827, 2.27149, 2.82221, 0.391821, 2.44682, 3.07552, 0.376618, 2.41931, 3.04467, 0.327652, 1.98619, 2.68696, 0.233771, 1.97806, 2.60303, -0.0912834, 2.12663, 2.44425, -0.0282163, 2.24859, 2.87814, -0.35026, 2.25039, 2.87648, -0.291744, 2.07568, 2.68462, -0.249978, 2.10304, 2.71157, -0.20629, 2.30152, 3.24052, 0.317542, 2.29549, 3.18528, 0.277312, 2.14291, 2.96404, 0.3995, 2.1462, 2.9606, 0.342119, 1.31621, 3.39795, -0.203802, 1.35829, 3.43387, -0.29479, 1.54119, 3.29007, -0.372791, 1.48496, 3.24915, -0.287145, 0.552121, 0.665123, 0.401021, 0.154027, 0.441809, 0.19622, 0.944465, 0.443271, 0.182901, 0.0964089, 0.00104547, -0.196812, 0.19633, 0.00104547, -0.176104, 0.835003, 0.00104547, -0.205403, 0.736495, 0.00104547, -0.182387, 0.108829, 0.00104547, 0.040049, 0.85902, 0.00104547, 0.0313234, 0.0508581, 0.00104547, 0.0402964, 0.207486, 0.384965, 0.351051, 0.874277, 0.386199, 0.339815, 0.916171, 0.00104547, 0.0302318, 0.543306, 0.573346, 0.523815, 0.158656, 2.88784, -0.132794, 0.242974, 2.8226, -0.0472403, 0.228589, 2.63923, -0.0490058, 0.149215, 2.70638, -0.125392, 0.241672, 4.68094, -0.138747, 0.158365, 4.73746, -0.261278, 0, 4.76911, -0.32375, 0.18264, 4.62281, 0.00355331, 0, 4.46751, 0.137356, 0, 4.44976, 0.12846, 1.6, 5.86123, 0.903096, 1.6, 5.46123, 0.795916, 1.6, 5.42123, 0.865198, 1.6, 5.86123, 0.983096, 1.6, 5.16841, 0.503096, 1.6, 5.09913, 0.543096, 1.6, 5.06123, 0.103096, 1.6, 4.98123, 0.103096, 1.6, 5.46123, -0.589731, 1.6, 5.42123, -0.659013, 1.6, 5.09912, -0.336911, 1.6, 5.16841, -0.296911, 1.6, 5.86123, -0.696911, 1.6, 5.86123, -0.776911, 1.6, 6.26123, -0.589731, 1.6, 6.30123, -0.659013, 1.6, 6.55405, -0.296911, 1.6, 6.62333, -0.336911, 1.15486, 6.36123, 0.969121, 0.685695, 6.36123, 0.969121, 0.765488, 6.24202, 0.864397, 1.07507, 6.24202, 0.864397, 1.2072, 6.11123, 1.03611, 1.10961, 6.07706, 0.908599, 2.0359, 5.66148, 0.449063, 2.0359, 5.51526, 0.30284, 1.90356, 5.8612, 0.10311, 2.0359, 5.46174, 0.103096, 2.0359, 6.20719, 0.30284, 2.0359, 6.06097, 0.449063, 2.0359, 5.51526, -0.0966551, 2.0359, 5.66148, -0.242878, 2.0359, 5.86123, -0.296399, 0, 5.40641, 0.875976, 0, 5.28211, 0.751677, 0.257146, 5.2834, 0.752961, 0.257147, 5.40641, 0.875976, 1.39648, 4.9952, 0.603096, 1.39648, 4.86123, 0.103096, 1.39648, 5.06123, 0.103096, 1.39648, 5.16841, 0.503096, 1.39648, 6.86123, 0.103096, 1.39648, 6.72725, 0.603096, 1.39648, 6.55405, 0.503096, 1.39648, 6.66123, 0.103096, 1.39648, 6.36123, 0.969121, 1.39648, 6.26123, 0.795916, 1.39648, 5.86123, 1.1031, 1.39648, 5.86123, 0.903096, 1.39648, 5.36123, 0.969121, 1.39648, 5.46123, 0.795916, 1.6, 6.66123, 0.103096, 1.6, 6.55405, 0.503096, 1.6, 6.62333, 0.543096, 1.6, 6.74123, 0.103096, 1.6, 6.26123, 0.795916, 1.6, 6.30123, 0.865198, 1.39648, 5.36123, -0.762936, 1.39648, 5.46123, -0.589731, 1.39648, 5.16841, -0.296911, 1.39648, 4.9952, -0.396911, 1.39648, 5.86123, -0.896911, 1.39648, 5.86123, -0.696911, 1.39648, 6.36123, -0.762936, 1.39648, 6.26123, -0.589731, 1.39648, 6.72725, -0.396911, 1.39648, 6.55405, -0.296911, 0.73095, 6.07706, 0.908599, 0.765488, 5.9121, 0.9528, 1.07507, 5.9121, 0.9528, 1.10961, 6.07706, 0.908599, 0.765488, 6.24202, 0.864397, 1.07507, 6.24202, 0.864397, 0.685695, 5.86123, 1.1031, 1.15486, 5.86123, 1.1031, 1.07507, 5.9121, 0.9528, 0.765488, 5.9121, 0.9528, 0.633352, 6.11123, 1.03611, 0.73095, 6.07706, 0.908599, 1.39648, 6.66123, 0.103096, 1.39648, 6.55405, 0.503096, 1.6, 6.55405, 0.503096, 1.6, 6.66123, 0.103096, 1.39648, 6.26123, 0.795916, 1.6, 6.26123, 0.795916, 1.39648, 5.86123, 0.903096, 1.6, 5.86123, 0.903096, 1.39648, 5.46123, 0.795916, 1.6, 5.46123, 0.795916, 1.39648, 5.16841, 0.503096, 1.6, 5.16841, 0.503096, 1.39648, 5.06123, 0.103096, 1.6, 5.06123, 0.103096, 1.39648, 5.46123, -0.589731, 1.6, 5.46123, -0.589731, 1.6, 5.16841, -0.296911, 1.39648, 5.16841, -0.296911, 1.39648, 5.86123, -0.696911, 1.6, 5.86123, -0.696911, 1.39648, 6.26123, -0.589731, 1.6, 6.26123, -0.589731, 1.39648, 6.55405, -0.296911, 1.6, 6.55405, -0.296911, 2.0359, 5.86123, 0.502584, 2.0359, 6.26072, 0.103096, 2.0359, 6.06097, -0.242878, 2.0359, 6.20719, -0.0966551, 0, 5.49634, 0.900073, 0.257147, 5.49634, 0.900073, 0.252264, 4.53307, -0.191655, 0.153299, 4.61636, -0.336561, 0, 4.66231, -0.410127, 0.198102, 4.44663, -0.00271145, 0, 2.66463, 0.20367, 5.00021e-06, 2.4738, 0.177211, 0.102832, 2.48009, 0.176006, 0.109384, 2.67117, 0.201936, 0.251452, 2.74864, 0.0718984, 0.23657, 2.56168, 0.0584772, 0.181152, 2.70508, 0.146183, 0.170392, 2.51572, 0.125662, 0, 2.91839, -0.164227, 5.00021e-06, 2.73725, -0.153025, 1.35355, 3.45169, -0.0607277, 1.50191, 3.29774, -0.132197, 0.413722, 1.77804, 0.182495, 0.302308, 1.69787, 0.09718, 0.311982, 1.54621, 0.0812291, 0.425773, 1.62639, 0.166544, 0.489091, 1.94399, -0.0482645, 0.542593, 1.87364, 0.112398, 0.55748, 1.72198, 0.0964474, 0.506064, 1.79234, -0.0642154, 0.394125, 1.86374, -0.138546, 0.408718, 1.71209, -0.154497, 0.227335, 1.66351, -0.0137039, 0.23599, 1.51185, -0.0296548, 0.0960235, 4.4178, 0.0939296, 1.5172, 3.69575, -0.311084, 1.54768, 3.76732, -0.167808, 1.71449, 3.62366, -0.198996, 1.70474, 3.5573, -0.353999, 1.43134, 3.52144, -0.355117, 1.62434, 3.38222, -0.419987, 1.436, 3.60537, 0.00285106, 1.57608, 3.45117, -0.0476083, 1.51354, 3.73444, -0.0382403, 1.66072, 3.58429, -0.072422, 0.254872, 1.70456, -0.0798497, 0.256767, 1.56023, -0.0958005, 0.288751, 1.77481, -0.152552, 0.300707, 1.62315, -0.168503, 0, 4.41627, 0.145479, 0.841135, 6.72725, 0.603096, 0.841135, 6.72725, -0.396911, 0.942888, 6.86123, 0.103096, -0.23068, 6.41266, 0.879344, -0.23068, 6.48536, 0.879344, -0.754113, 6.81344, 0.551263, -0.754113, 6.74074, 0.551263, -0.845318, 6.93353, 0.103095, -0.845318, 6.86083, 0.103095, -0.754113, 6.74074, -0.345078, -0.754113, 6.81344, -0.345078, -0.257165, 6.36123, 0.969121, -0.257165, 6.36123, -0.762936, -0.23068, 6.41266, -0.673159, -0.23068, 6.48536, -0.673159, -0.852531, 6.83043, -0.403642, -0.2607, 6.45948, -0.774594, -0.852531, 6.83043, 0.609826, -0.955654, 6.96621, 0.103096, -0.2607, 6.45948, 0.980779, -0.144337, 4.62833, -0.267808, -0.145367, 4.61509, -0.285537, -0.230474, 4.54553, -0.1645, -0.227645, 4.56054, -0.149869, -0.169802, 4.47494, -0.0244043, -0.16781, 4.49143, -0.0124773, -2.39441, 2.7167, -0.284614, -2.37464, 2.73891, -0.235805, -2.22875, 2.57563, -0.151192, -2.22321, 2.52508, -0.185319, -0.829811, 0.39491, 0.192334, -0.823707, 0.343455, 0.299719, -0.53677, 0.505704, 0.45924, -0.539954, 0.53255, 0.320534, -0.245627, 0.342385, 0.30946, -0.251731, 0.393841, 0.202075, -2.37016, 3.14596, -0.180206, -2.49324, 3.00574, -0.125365, -2.51365, 3.10316, 0.122743, -2.39069, 3.24439, 0.0703977, -2.02679, 2.71357, 0.205928, -2.15324, 2.5776, 0.25697, -2.14773, 2.50612, -0.0177825, -2.02114, 2.64141, -0.071524, -0.197471, 4.75418, 0.019584, -0.212301, 4.88556, 0.0356146, -2.55604, 3.1449, 0.136694, -2.53359, 3.02984, -0.15501, -2.38915, 3.19439, -0.219368, -2.41174, 3.31063, 0.0752657, -2.13459, 2.5274, 0.293671, -2.27149, 2.82221, 0.391821, -2.28993, 2.80163, 0.457827, -2.44682, 3.07552, 0.376618, -2.41931, 3.04467, 0.327652, -1.98619, 2.68696, 0.233771, -1.97806, 2.60303, -0.0912834, -2.12663, 2.44425, -0.0282163, -2.24859, 2.87814, -0.35026, -2.25039, 2.87648, -0.291744, -2.07568, 2.68462, -0.249978, -2.10304, 2.71157, -0.20629, -2.29549, 3.18528, 0.277312, -2.30152, 3.24052, 0.317542, -2.1462, 2.9606, 0.342119, -2.14291, 2.96404, 0.3995, -1.31621, 3.39795, -0.203802, -1.48496, 3.24915, -0.287145, -1.54119, 3.29007, -0.372791, -1.35829, 3.43387, -0.29479, -0.552121, 0.665123, 0.401021, -0.154027, 0.441809, 0.19622, -0.944465, 0.443271, 0.182901, -0.19633, 0.00104547, -0.176104, -0.0964089, 0.00104547, -0.196812, -0.835003, 0.00104547, -0.205403, -0.736495, 0.00104547, -0.182387, -0.108829, 0.00104547, 0.040049, -0.85902, 0.00104547, 0.0313234, -0.207486, 0.384965, 0.351051, -0.0508581, 0.00104547, 0.0402964, -0.916171, 0.00104547, 0.0302318, -0.874277, 0.386199, 0.339815, -0.543306, 0.573346, 0.523815, -0.158656, 2.88784, -0.132794, -0.149215, 2.70638, -0.125392, -0.228589, 2.63923, -0.0490058, -0.242974, 2.8226, -0.0472403, -0.241672, 4.68094, -0.138747, -0.158365, 4.73746, -0.261278, -0.18264, 4.62281, 0.00355331, -1.6, 5.86123, 0.903096, -1.6, 5.86123, 0.983096, -1.6, 5.42123, 0.865198, -1.6, 5.46123, 0.795916, -1.6, 5.09913, 0.543096, -1.6, 5.16841, 0.503096, -1.6, 4.98123, 0.103096, -1.6, 5.06123, 0.103096, -1.6, 5.46123, -0.589731, -1.6, 5.16841, -0.296911, -1.6, 5.09912, -0.336911, -1.6, 5.42123, -0.659013, -1.6, 5.86123, -0.696911, -1.6, 5.86123, -0.776911, -1.6, 6.26123, -0.589731, -1.6, 6.30123, -0.659013, -1.6, 6.55405, -0.296911, -1.6, 6.62333, -0.336911, -1.15486, 6.36123, 0.969121, -1.07507, 6.24202, 0.864397, -0.765488, 6.24202, 0.864397, -0.685695, 6.36123, 0.969121, -1.2072, 6.11123, 1.03611, -1.10961, 6.07706, 0.908599, -2.0359, 5.66148, 0.449063, -1.90356, 5.8612, 0.10311, -2.0359, 5.51526, 0.30284, -2.0359, 5.46174, 0.103096, -2.0359, 6.20719, 0.30284, -2.0359, 6.06097, 0.449063, -2.0359, 5.51526, -0.0966551, -2.0359, 5.66148, -0.242878, -2.0359, 5.86123, -0.296399, -0.257147, 5.40641, 0.875976, -0.257146, 5.2834, 0.752961, -1.39648, 4.9952, 0.603096, -1.39648, 5.16841, 0.503096, -1.39648, 5.06123, 0.103096, -1.39648, 4.86123, 0.103096, -1.39648, 6.86123, 0.103096, -1.39648, 6.66123, 0.103096, -1.39648, 6.55405, 0.503096, -1.39648, 6.72725, 0.603096, -1.39648, 6.26123, 0.795916, -1.39648, 6.36123, 0.969121, -1.39648, 5.86123, 0.903096, -1.39648, 5.86123, 1.1031, -1.39648, 5.46123, 0.795916, -1.39648, 5.36123, 0.969121, -1.6, 6.66123, 0.103096, -1.6, 6.74123, 0.103096, -1.6, 6.62333, 0.543096, -1.6, 6.55405, 0.503096, -1.6, 6.30123, 0.865198, -1.6, 6.26123, 0.795916, -1.39648, 5.36123, -0.762936, -1.39648, 4.9952, -0.396911, -1.39648, 5.16841, -0.296911, -1.39648, 5.46123, -0.589731, -1.39648, 5.86123, -0.896911, -1.39648, 5.86123, -0.696911, -1.39648, 6.36123, -0.762936, -1.39648, 6.26123, -0.589731, -1.39648, 6.72725, -0.396911, -1.39648, 6.55405, -0.296911, -0.73095, 6.07706, 0.908599, -1.10961, 6.07706, 0.908599, -1.07507, 5.9121, 0.9528, -0.765488, 5.9121, 0.9528, -0.765488, 6.24202, 0.864397, -1.07507, 6.24202, 0.864397, -0.685695, 5.86123, 1.1031, -0.765488, 5.9121, 0.9528, -1.07507, 5.9121, 0.9528, -1.15486, 5.86123, 1.1031, -0.633352, 6.11123, 1.03611, -0.73095, 6.07706, 0.908599, -1.39648, 6.66123, 0.103096, -1.6, 6.66123, 0.103096, -1.6, 6.55405, 0.503096, -1.39648, 6.55405, 0.503096, -1.6, 6.26123, 0.795916, -1.39648, 6.26123, 0.795916, -1.6, 5.86123, 0.903096, -1.39648, 5.86123, 0.903096, -1.6, 5.46123, 0.795916, -1.39648, 5.46123, 0.795916, -1.6, 5.16841, 0.503096, -1.39648, 5.16841, 0.503096, -1.6, 5.06123, 0.103096, -1.39648, 5.06123, 0.103096, -1.39648, 5.46123, -0.589731, -1.39648, 5.16841, -0.296911, -1.6, 5.16841, -0.296911, -1.6, 5.46123, -0.589731, -1.39648, 5.86123, -0.696911, -1.6, 5.86123, -0.696911, -1.39648, 6.26123, -0.589731, -1.6, 6.26123, -0.589731, -1.39648, 6.55405, -0.296911, -1.6, 6.55405, -0.296911, -2.0359, 5.86123, 0.502584, -2.0359, 6.26072, 0.103096, -2.0359, 6.06097, -0.242878, -2.0359, 6.20719, -0.0966551, -0.257147, 5.49634, 0.900073, -0.153299, 4.61636, -0.336561, -0.252264, 4.53307, -0.191655, -0.198102, 4.44663, -0.00271145, -0.109384, 2.67117, 0.201936, -0.102832, 2.48009, 0.176006, -0.251452, 2.74864, 0.0718984, -0.23657, 2.56168, 0.0584772, -0.181152, 2.70508, 0.146183, -0.170392, 2.51572, 0.125662, -1.35355, 3.45169, -0.0607277, -1.50191, 3.29774, -0.132197, -0.413722, 1.77804, 0.182495, -0.425773, 1.62639, 0.166544, -0.311982, 1.54621, 0.0812291, -0.302308, 1.69787, 0.09718, -0.489091, 1.94399, -0.0482645, -0.506064, 1.79234, -0.0642154, -0.55748, 1.72198, 0.0964474, -0.542593, 1.87364, 0.112398, -0.394125, 1.86374, -0.138546, -0.408718, 1.71209, -0.154497, -0.23599, 1.51185, -0.0296548, -0.227335, 1.66351, -0.0137039, -0.0960235, 4.4178, 0.0939296, -1.5172, 3.69575, -0.311084, -1.70474, 3.5573, -0.353999, -1.71449, 3.62366, -0.198996, -1.54768, 3.76732, -0.167808, -1.62434, 3.38222, -0.419987, -1.43134, 3.52144, -0.355117, -1.436, 3.60537, 0.00285106, -1.57608, 3.45117, -0.0476083, -1.66072, 3.58429, -0.072422, -1.51354, 3.73444, -0.0382403, -0.256767, 1.56023, -0.0958005, -0.254872, 1.70456, -0.0798497, -0.288751, 1.77481, -0.152552, -0.300707, 1.62315, -0.168503, -0.841135, 6.72725, 0.603096, -0.841135, 6.72725, -0.396911, -0.942888, 6.86123, 0.103096, 0.177538, 3.25078, -0.147598, 0.271744, 3.18932, -0.0437093, 0.257359, 3.00596, -0.0454748, 0.168097, 3.06931, -0.140196, 0, 3.04628, 0.256587, 0, 2.85545, 0.230128, 0.115936, 2.86226, 0.227866, 0.122488, 3.05335, 0.253795, 0.281216, 3.12258, 0.0987407, 0.266334, 2.93561, 0.0853195, 0.202672, 3.0838, 0.187225, 0.191912, 2.89444, 0.166704, 0, 3.28068, -0.186631, 0, 3.09954, -0.175429, -0.177538, 3.25078, -0.147598, -0.168097, 3.06931, -0.140196, -0.257359, 3.00596, -0.0454748, -0.271744, 3.18932, -0.0437093, -0.122488, 3.05335, 0.253795, -0.115936, 2.86226, 0.227866, -0.281216, 3.12258, 0.0987407, -0.266334, 2.93561, 0.0853195, -0.202672, 3.0838, 0.187225, -0.191912, 2.89444, 0.166704, 0, 4.59875, 0.125936, 0.269727, 4.92174, -0.116503, 0.2557, 4.80134, -0.127625, 0.172392, 4.8466, -0.254748, 0.18642, 4.95573, -0.248219, 0, 4.87249, -0.319817, 0, 4.97587, -0.315884, -0.269727, 4.92174, -0.116503, -0.18642, 4.95573, -0.248219, -0.172392, 4.8466, -0.254748, -0.2557, 4.80134, -0.127625, -0.809978, 3.84435, 0.0462258, -0.978723, 3.69555, -0.0371168, -0.992485, 3.72148, -0.13879, -0.809584, 3.86528, -0.0607897, -1.14747, 3.54675, -0.120459, -1.17539, 3.57767, -0.21679, -0.908494, 3.91354, 0.153681, -1.05685, 3.75959, 0.0822117, -1.2052, 3.60564, 0.010742, -0.954611, 4.1111, -0.182336, -1.14214, 3.97265, -0.225252, -1.21405, 4.05463, -0.105431, -1.04723, 4.19828, -0.0742428, -1.32967, 3.8342, -0.268168, -1.38086, 3.91097, -0.136619, -1.04535, 3.79989, -0.225379, -0.85235, 3.93911, -0.160509, -1.23834, 3.66066, -0.290248, -1.01577, 4.06798, 0.154229, -1.15585, 3.91378, 0.10377, -1.29593, 3.75958, 0.0533104, -1.21917, 4.03474, 0.0301233, -1.07199, 4.18489, 0.0643051, -1.36635, 3.88459, -0.00405846, 0.809978, 3.84435, 0.0462258, 0.809584, 3.86528, -0.0607897, 0.992485, 3.72148, -0.13879, 0.978723, 3.69555, -0.0371168, 1.17539, 3.57767, -0.21679, 1.14747, 3.54675, -0.120459, 0.908494, 3.91354, 0.153681, 1.05685, 3.75959, 0.0822117, 1.2052, 3.60564, 0.010742, 0.954611, 4.1111, -0.182336, 1.04723, 4.19828, -0.0742428, 1.21405, 4.05463, -0.105431, 1.14214, 3.97265, -0.225252, 1.38086, 3.91097, -0.136619, 1.32967, 3.8342, -0.268168, 0.85235, 3.93911, -0.160509, 1.04535, 3.79989, -0.225379, 1.23834, 3.66066, -0.290248, 1.01577, 4.06798, 0.154229, 1.15585, 3.91378, 0.10377, 1.29593, 3.75958, 0.0533104, 1.07199, 4.18489, 0.0643051, 1.21917, 4.03474, 0.0301233, 1.36635, 3.88459, -0.00405846, 0.377566, 2.23301, 0.230347, 0.273286, 2.15284, 0.145033, 0.28296, 2.00118, 0.129082, 0.389618, 2.08136, 0.214396, 0.292634, 1.84952, 0.113131, 0.40167, 1.9297, 0.198445, 0.438171, 2.39896, -0.000411894, 0.497933, 2.32861, 0.160251, 0.51282, 2.17695, 0.1443, 0.455144, 2.24731, -0.0163628, 0.527707, 2.02529, 0.128349, 0.472118, 2.09565, -0.0323137, 0.350345, 2.31871, -0.0906937, 0.364938, 2.16706, -0.106645, 0.379531, 2.0154, -0.122595, 0.20137, 2.11848, 0.0341487, 0.210025, 1.96682, 0.0181978, 0.21868, 1.81516, 0.00224695, 0.249187, 2.13753, -0.031997, 0.251082, 1.9932, -0.0479479, 0.252977, 1.84888, -0.0638988, 0.252884, 2.22978, -0.1047, 0.26484, 2.07812, -0.12065, 0.276796, 1.92646, -0.136601, -0.377566, 2.23301, 0.230347, -0.389618, 2.08136, 0.214396, -0.28296, 2.00118, 0.129082, -0.273286, 2.15284, 0.145033, -0.40167, 1.9297, 0.198445, -0.292634, 1.84952, 0.113131, -0.438171, 2.39896, -0.000411894, -0.455144, 2.24731, -0.0163628, -0.51282, 2.17695, 0.1443, -0.497933, 2.32861, 0.160251, -0.472118, 2.09565, -0.0323137, -0.527707, 2.02529, 0.128349, -0.350345, 2.31871, -0.0906937, -0.364938, 2.16706, -0.106645, -0.379531, 2.0154, -0.122595, -0.210025, 1.96682, 0.0181978, -0.20137, 2.11848, 0.0341487, -0.21868, 1.81516, 0.00224695, -0.251082, 1.9932, -0.0479479, -0.249187, 2.13753, -0.031997, -0.252977, 1.84888, -0.0638988, -0.252884, 2.22978, -0.1047, -0.26484, 2.07812, -0.12065, -0.276796, 1.92646, -0.136601 </vector3_array>
- <vector3_array len="625"> 0.0360096, 0.589157, 0.807216, 0.379162, 0.648277, 0.660282, 0.710781, -0.701771, 0.0480528, 0.391591, -0.775171, 0.495749, 0.722924, 0.690928, -0, 0.722446, -0.691427, 0, 0.378912, 0.647849, -0.660846, 0.710746, -0.701737, -0.0490515, 0, 0.610678, 0.791879, -0.0350367, 0.578606, 0.814854, 0, 0.501628, 0.865083, 0, 0.610194, -0.792252, 0, 0.501194, -0.865335, 0.0359806, 0.588682, -0.807564, -0.0350082, 0.578135, -0.81519, 0.391397, -0.774786, -0.496503, 0.323297, -0.752692, -0.573527, 0.770859, -0.534596, -0.346386, 0, -0.789191, -0.614148, 0, -0.789675, 0.613525, 0.868674, -0.495384, 0, 0.771126, -0.534781, 0.345505, 0.323483, -0.753124, 0.572855, 0, -0.789191, -0.614148, 0, -0.789675, 0.613525, 0.705688, 0.318859, -0.63272, 0.999838, 0.00999838, 0.0149976, 0.799697, 0.565786, 0.200924, 0.540954, 0.82793, -0.147987, 0, 0.473026, -0.881048, 0, 0.986122, -0.166021, 0.790431, -0.193105, 0.581317, 0.744403, 0.310168, 0.59132, -0.210106, 0.16008, -0.964484, -0.609658, -0.17619, -0.772835, -0.695748, -0.0600646, -0.71577, -0.418461, 0.236261, -0.876967, 0.72763, -0.205178, 0.654566, 0.0120115, 0.213204, 0.976934, -0.0129987, 0.889909, -0.455953, 0.408168, 0.754311, -0.514212, -0.717691, -0.0310299, 0.69567, -0.403281, 0.782544, -0.47433, 0.962114, -0.068008, -0.264031, 0.98219, 0.109021, 0.15303, -0.0740053, 0.995071, -0.0660047, -0.0730215, 0.709209, -0.701207, 0.120177, -0.831221, 0.542797, 0.130096, -0.988732, -0.0740548, -0.9642, -0.11214, -0.240299, -0.953245, 0.0220288, 0.301394, 0.741648, -0.0980857, 0.66358, 0.557506, -0.667605, 0.493448, 0, -0.762778, 0.64666, 0, -0.0440454, 0.99903, 0.0889861, 0.993844, -0.0659897, 0.0490036, 0.723054, -0.689051, 0.897953, 0.117994, -0.423978, 0.920375, 0.351143, 0.17207, -0.901333, -0.16224, 0.401594, -0.618771, 0.285356, 0.731912, -0.721733, 0.300305, 0.623633, -0.242219, 0.80573, 0.54049, -0.400552, 0.758045, 0.514709, -0.0350519, -0.808196, 0.58787, -0.0460378, -0.996819, -0.0650535, -0.891041, -0.346405, -0.293343, 0.6294, -0.428272, -0.648412, 0.728593, -0.433353, -0.530432, 0.267172, -0.820528, -0.505325, 0.35736, -0.806813, -0.470474, 0.622553, 0.221196, 0.750666, 0.819836, -0.00400408, 0.572584, 0.297403, -0.309419, 0.903223, 0.487706, -0.344499, 0.802162, -0.679917, -0.730986, -0.0580783, -0.592431, -0.368268, -0.716522, -0.511638, -0.289361, -0.809009, -0.812045, -0.505651, -0.291375, -0.00700771, -0.117129, 0.993092, -0.674119, -0.252419, 0.694153, 0.797008, -0.304385, 0.521659, -0.753305, -0.654134, 0.0681181, -0.216317, -0.957402, 0.19128, 0.713493, -0.691478, -0.113078, 0.194204, -0.972021, 0.132139, -0.686439, 0.302193, -0.661423, 0.711943, 0.135989, -0.688945, -0.702756, -0.294317, -0.647697, -0.616626, 0.733745, -0.28529, 0.714816, 0.636836, -0.288926, 0.64207, -0.336037, -0.689075, 0.0110026, 0.996233, -0.0860201, 0.456853, -0.0569817, -0.887715, 0.891957, -0.0679967, -0.446978, 0.947519, 0.264145, -0.180099, 0.609974, 0.430981, -0.664971, 0.983744, -0.109971, -0.141963, 0.618615, -0.0169894, -0.785511, 0, 0.0229939, -0.999736, 0.785814, -0.0981016, 0.610633, 0, -0.271413, 0.962463, 0, 0.126129, 0.992014, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -0.167145, 0.336293, 0.926806, 0.168118, 0.336236, 0.926651, 0.327528, -0.185299, 0.926493, -0.326633, -0.185359, 0.926797, -0.401672, 0.237397, 0.884479, -0.493594, 0.225271, 0.840011, 0.984527, -0.0870466, 0.152081, 0.984527, -0.152081, 0.0870466, 1, 0, -0, 0.984551, -0.175098, 0, 0.984377, 0.153059, 0.0870333, 0.984441, 0.0880395, 0.152068, 0.984441, -0.152068, -0.0880395, 0.984377, -0.0870333, -0.153059, 0.984378, 0, -0.176068, 0, -0.499694, 0.866202, 0, -0.0770792, 0.997025, -0.353503, -0.137195, 0.925318, -0.4965, -0.437441, 0.749755, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 0, 0.25922, 0.965818, 0, 0.25922, 0.965818, 0, 0.25922, 0.965818, 0, 0.25922, 0.965818, 0, 0.25922, 0.965818, 0, 0.25922, 0.965818, 0.168109, 0.172111, 0.970627, -0.167136, 0.17214, 0.97079, -0.326504, 0.624964, 0.709094, 0.327398, 0.62476, 0.708862, 0.402511, 0.237301, 0.884123, 0.494351, 0.22516, 0.839595, 0.770022, 0.638018, -0, 0.77049, 0.552351, 0.318202, -0.770083, 0.552777, 0.318448, -0.769614, 0.638509, 0, 0.77067, 0.319278, 0.551479, -0.770263, 0.319524, 0.551905, 0.770513, 0, 0.637424, -0.770106, 0, 0.637916, 0.770916, -0.318378, 0.551655, -0.770509, -0.318624, 0.552081, 0.770916, -0.551655, 0.318378, -0.770509, -0.552081, 0.318624, 0.770513, -0.637424, 0, -0.770106, -0.637916, 0, 0.77049, -0.318202, -0.552351, -0.770083, -0.318448, -0.552777, -0.770263, -0.551905, -0.319524, 0.77067, -0.551479, -0.319278, 0.770022, 0, -0.638018, -0.769614, 0, -0.638509, 0.770245, 0.319101, -0.552175, -0.769837, 0.319347, -0.552601, 0.770245, 0.552175, -0.319101, -0.769837, 0.552601, -0.319347, 0.984551, 0, 0.175098, 0.984378, 0.176068, -0, 0.984291, 0.088026, -0.153045, 0.984291, 0.153045, -0.088026, 0, -0.848897, 0.528558, -0.359502, -0.75906, 0.542758, 0.269002, 0.885006, 0.380003, 0.175995, 0.932972, 0.31399, 0, 0.941447, 0.33716, 0.24712, 0.836407, 0.489238, 0, -0.135113, 0.99083, 0, 0.0700382, 0.997544, 0.320359, 0.0650729, 0.945059, 0.353552, -0.136213, 0.925444, 0.952453, -0.0990471, 0.288137, 0.880048, 0.129007, 0.457025, 0.701409, -0.115067, 0.70341, 0.644507, 0.0390307, 0.763601, 0, -0.0550267, -0.998485, 0, 0.542878, -0.839811, -0.285466, -0.616005, 0.734198, -0.764085, -0.38755, 0.515732, -0.0240167, -0.100069, 0.994691, -0.686889, -0.119154, 0.716928, -0.74958, 0.0670519, 0.658509, -0.318438, 0.223307, 0.921266, 0.825985, 0.143997, -0.54499, 0.923944, 0.0519969, 0.378977, 0.455352, 0.602466, 0.655507, 0.565223, 0.681269, -0.465184, 0.342959, 0.132984, -0.929889, -0.0789773, 0.541844, -0.83676, -0.991178, -0.058069, 0.119142, -0.969378, 0.150213, 0.194276, 0.245128, 0.817427, 0.521272, 0.232988, 0.56297, -0.792958, 0.642155, 0.763184, -0.0720174, 0.308094, 0.942288, -0.13104, 0.167052, 0.584181, -0.794246, -0.281137, 0.0480233, -0.958465, -0.160029, 0.076014, -0.984181, 0.184197, -0.152163, 0.97104, -0.409744, 0.0530964, 0.910654, 0.581446, 0.410315, 0.702539, 0.0380266, 0.718502, 0.694485, -0.910035, 0.00700797, -0.414472, -0.943047, 0.164182, -0.289321, -0.529471, 0.0660587, -0.845752, -0.728454, 0.359224, -0.583363, 0, 0.768221, 0.640184, -0.0380063, 0.865143, 0.500083, -0.0379873, 0.86471, -0.500832, -0.001, 1, 0, -0.0350106, 0.589178, 0.807244, -0.390743, -0.775474, 0.495943, -0.710285, -0.70227, 0.048087, -0.378305, 0.648523, 0.660533, -0.721967, -0.691927, 0, -0.722446, 0.691427, 0, -0.378055, 0.648094, -0.661096, -0.71025, -0.702236, -0.0490864, 0.0360365, 0.578586, 0.814825, 0.0360071, 0.578114, -0.815161, -0.0349823, 0.588703, -0.807592, -0.390549, -0.775089, -0.496698, -0.770452, -0.535009, -0.346654, -0.322401, -0.752935, -0.573713, -0.77072, -0.535194, 0.345772, -0.868428, -0.495815, 0, -0.322586, -0.753368, 0.57304, -0.705185, 0.319084, -0.633166, -0.540246, 0.828378, -0.148068, -0.799337, 0.566238, 0.201085, -0.999837, 0.0100084, 0.0150126, -0.743957, 0.310399, 0.591761, -0.790055, -0.193258, 0.581777, 0.211062, 0.160047, -0.964281, 0.419287, 0.236161, -0.876599, 0.696264, -0.0600228, -0.715271, 0.610287, -0.176083, -0.772363, -0.727158, -0.205327, 0.655043, -0.407334, 0.754619, -0.514422, 0.0139984, 0.889897, -0.455947, -0.0110107, 0.213206, 0.976945, 0.404118, 0.782228, -0.474138, 0.718176, -0.0310076, 0.69517, -0.962039, -0.0680735, -0.264285, 0.0740164, 0.709157, -0.701155, 0.0749998, 0.994997, -0.0659998, -0.982154, 0.109128, 0.15318, -0.119189, -0.831321, 0.542862, 0.953337, 0.0220078, 0.301106, 0.96427, -0.112031, -0.240067, -0.129112, -0.98886, -0.0740644, -0.741197, -0.0981585, 0.664072, -0.556815, -0.667978, 0.493723, -0.087994, 0.993932, -0.0659955, -0.0480059, 0.723089, -0.689085, -0.897759, 0.1181, -0.424359, -0.920222, 0.351467, 0.172229, 0.90152, -0.162094, 0.401232, 0.722212, 0.300088, 0.623183, 0.619388, 0.285179, 0.731458, 0.243161, 0.805534, 0.540358, 0.401392, 0.757741, 0.514503, 0.0360521, -0.808167, 0.587849, 0.0470365, -0.996773, -0.0650504, 0.891247, -0.346096, -0.293081, -0.628795, -0.428542, -0.648821, -0.728123, -0.433669, -0.530819, -0.266242, -0.820747, -0.50546, -0.356487, -0.807102, -0.470642, -0.819508, -0.00400737, 0.573054, -0.621939, 0.221334, 0.751134, -0.486942, -0.344667, 0.802553, -0.296489, -0.309511, 0.903492, 0.680455, -0.730488, -0.0580388, 0.812386, -0.50524, -0.291138, 0.512377, -0.289213, -0.808595, 0.59308, -0.36805, -0.716097, 0.00800875, -0.117128, 0.993085, 0.674665, -0.252249, 0.693684, -0.796642, -0.304628, 0.522076, 0.217271, -0.957194, 0.191239, 0.753738, -0.65364, 0.0680667, -0.713001, -0.691972, -0.113159, -0.19324, -0.972209, 0.132164, 0.686968, 0.301986, -0.660969, -0.711449, 0.136086, -0.689435, 0.617246, 0.733292, -0.285114, 0.703262, -0.29411, -0.647241, -0.641482, -0.336253, -0.689518, -0.714327, 0.637291, -0.289132, -0.0100024, 0.996243, -0.086021, -0.456062, -0.0570077, -0.88812, -0.609345, 0.431244, -0.665377, -0.947416, 0.264395, -0.18027, -0.891752, -0.0680574, -0.447377, -0.983712, -0.11008, -0.142103, -0.617997, -0.0169999, -0.785996, -0.785431, -0.0981788, 0.611113, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 0.168118, 0.336236, 0.926651, 0.327528, -0.185299, 0.926493, -0.326633, -0.185359, 0.926797, -0.167145, 0.336293, 0.926806, 0.402511, 0.237301, 0.884123, 0.494351, 0.22516, 0.839595, -0.984497, -0.0871325, 0.152231, -1, 0, 0, -0.984497, -0.152231, 0.0871325, -0.98452, -0.175271, 0, -0.984346, 0.15321, 0.0871191, -0.98441, 0.0881262, 0.152218, -0.98441, -0.152218, -0.0881262, -0.984346, -0.0871191, -0.15321, -0.984347, 0, -0.176241, 0.497254, -0.437223, 0.749383, 0.354379, -0.137147, 0.92499, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, 1, 0, -0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, 0, 0.25922, 0.965818, 0, 0.25922, 0.965818, 0, 0.25922, 0.965818, 0, 0.25922, 0.965818, 0, 0.25922, 0.965818, 0, 0.25922, 0.965818, -0.167136, 0.17214, 0.97079, -0.326504, 0.624964, 0.709094, 0.327398, 0.62476, 0.708862, 0.168109, 0.172111, 0.970627, -0.401672, 0.237397, 0.884479, -0.493594, 0.225271, 0.840011, -0.769614, 0.638509, 0, 0.770022, 0.638018, -0, 0.77049, 0.552351, 0.318202, -0.770083, 0.552777, 0.318448, 0.77067, 0.319278, 0.551479, -0.770263, 0.319524, 0.551905, 0.770513, 0, 0.637424, -0.770106, 0, 0.637916, 0.770916, -0.318378, 0.551655, -0.770509, -0.318624, 0.552081, 0.770916, -0.551655, 0.318378, -0.770509, -0.552081, 0.318624, 0.770513, -0.637424, 0, -0.770106, -0.637916, 0, -0.770083, -0.318448, -0.552777, -0.770263, -0.551905, -0.319524, 0.77067, -0.551479, -0.319278, 0.77049, -0.318202, -0.552351, -0.769614, 0, -0.638509, 0.770022, 0, -0.638018, -0.769837, 0.319347, -0.552601, 0.770245, 0.319101, -0.552175, -0.769837, 0.552601, -0.319347, 0.770245, 0.552175, -0.319101, -0.98452, 0, 0.175271, -0.984347, 0.176241, 0, -0.98426, 0.0881128, -0.153196, -0.98426, 0.153196, -0.0881128, 0.360374, -0.758786, 0.542562, -0.175025, 0.933135, 0.314046, -0.268074, 0.885244, 0.380105, -0.246181, 0.836614, 0.489359, -0.352675, -0.136261, 0.925772, -0.31946, 0.0650937, 0.945361, -0.95236, -0.0991416, 0.288412, -0.879823, 0.129121, 0.457428, -0.7009, -0.115148, 0.703904, -0.643922, 0.0390559, 0.764094, 0.286385, -0.615829, 0.733988, 0.764501, -0.387254, 0.515338, 0.0250168, -0.100067, 0.994666, 0.319337, 0.223236, 0.920972, 0.750018, 0.0670016, 0.658015, 0.687417, -0.119072, 0.716435, -0.825667, 0.144116, -0.54544, -0.564542, 0.681654, -0.465447, -0.454558, 0.60274, 0.655806, -0.923798, 0.0520449, 0.379327, -0.342076, 0.13303, -0.930208, 0.0799707, 0.541802, -0.836693, 0.969438, 0.150068, 0.194088, 0.991195, -0.0580114, 0.119023, -0.244187, 0.817627, 0.5214, -0.232042, 0.563101, -0.793142, -0.166079, 0.584278, -0.794378, -0.307188, 0.942578, -0.13108, -0.641567, 0.763675, -0.0720637, 0.161004, 0.0760018, -0.984023, 0.282058, 0.0480098, -0.958196, -0.18323, -0.152191, 0.971218, 0.410577, 0.0530746, 0.91028, -0.0370272, 0.718529, 0.694511, -0.580783, 0.410554, 0.702948, 0.943158, 0.164027, -0.289048, 0.910207, 0.00700159, -0.414094, 0.530191, 0.0660237, -0.845304, 0.728923, 0.358962, -0.582938, 0.039005, 0.86511, 0.500063, 0.0389854, 0.864677, -0.500813, 0.002, 0.999998, -0, 0.307062, -0.405082, -0.861174, 0.644374, -0.493286, -0.584339, 0.899636, -0.0680481, -0.431305, 0.473063, -0.0580077, -0.879117, 0, -0.746027, 0.665916, 0, -0.135113, 0.99083, 0.361199, -0.136075, 0.922507, 0.355385, -0.786851, 0.504546, 0.758512, -0.647437, -0.07405, 0.952727, -0.0990756, 0.287219, 0.641692, -0.681736, 0.351379, 0.709379, -0.115062, 0.695372, 0, -0.36621, -0.930532, 0, -0.0550267, -0.998485, -0.306156, -0.405206, -0.861439, -0.472286, -0.0580352, -0.879533, -0.899445, -0.0681094, -0.431694, -0.643788, -0.493604, -0.584716, -0.354509, -0.787131, 0.504725, -0.360328, -0.136124, 0.92284, -0.758087, -0.647929, -0.0741063, -0.952635, -0.0991702, 0.287493, -0.641103, -0.682174, 0.351605, -0.708882, -0.115143, 0.695866, 0, -0.0550817, 0.998482, 0.721736, -0.682696, -0.114116, 0.984884, -0.110987, -0.132984, 0.620192, -0.0180056, -0.784243, 0.463983, -0.666975, -0.582978, 0, 0.0239931, -0.999712, 0, -0.812786, -0.582563, -0.721256, -0.68319, -0.114199, -0.463198, -0.667285, -0.583249, -0.619576, -0.0180168, -0.78473, -0.984854, -0.111096, -0.133115, -0.712291, -0.694258, -0.103187, 0.595443, -0.778579, 0.198147, 0.653726, -0.55762, -0.511568, -0.639939, -0.7491, -0.171251, 0.643677, -0.761801, 0.0730768, 0.630288, -0.468214, -0.619283, -0.730652, -0.680607, -0.0540482, 0.116169, -0.506735, 0.854239, 0.201265, -0.563742, 0.801054, -0.905093, -0.411497, -0.107129, -0.0970155, 0.416066, -0.904144, -0.581217, 0.747279, -0.32212, -0.864338, -0.499774, -0.0560868, -0.164974, 0.491923, -0.854866, -0.616439, 0.761542, -0.200142, 0.407071, -0.149026, -0.901157, -0.759004, -0.614813, -0.214283, 0.347173, -0.0500249, -0.936466, -0.848814, -0.528507, -0.0140134, -0.344309, 0.00500449, 0.938843, -0.266308, -0.0730846, 0.961113, -0.669545, 0.542441, 0.507413, -0.833134, -0.540736, -0.116158, -0.62997, 0.48074, 0.609939, 0.712784, -0.693763, -0.103113, 0.64053, -0.74862, -0.171142, -0.653152, -0.557985, -0.511903, -0.594796, -0.779043, 0.198265, -0.629685, -0.46851, -0.619674, -0.64309, -0.762292, 0.0731239, 0.731118, -0.68011, -0.0540087, -0.11518, -0.506794, 0.854338, -0.200304, -0.563855, 0.801215, 0.905274, -0.411124, -0.107032, 0.864591, -0.499341, -0.0560383, 0.581879, 0.746844, -0.321933, 0.0980061, 0.416026, -0.904056, 0.617059, 0.761072, -0.200019, 0.165946, 0.491841, -0.854724, 0.759428, -0.614346, -0.214121, -0.406236, -0.149087, -0.901524, -0.346292, -0.0500423, -0.936791, 0.849093, -0.528058, -0.0140015, 0.345191, 0.00500277, 0.938519, 0.267238, -0.0730651, 0.960857, 0.83344, -0.540285, -0.116061, 0.670096, 0.542078, 0.507073, 0.630574, 0.480437, 0.609555, 0.652602, -0.667616, 0.35833, 0.272405, -0.803194, 0.529788, -0.69805, -0.119179, 0.706062, -0.0250168, -0.100067, 0.994666, -0.692476, -0.119254, 0.711516, -0.0250168, -0.100067, 0.994666, 0.794806, -0.441448, -0.416422, 0.800238, -0.563168, -0.206061, 0.931286, 0.0550169, 0.360111, 0.825985, 0.143997, -0.54499, 0.927789, 0.0530451, 0.369314, 0.825985, 0.143997, -0.54499, 0.823173, -0.419088, -0.383081, 0.35507, 0.134026, -0.925182, 0.348836, 0.133937, -0.927564, 0.241336, -0.969348, -0.0460641, -0.998282, -0.049063, 0.0320411, -0.995768, -0.0530409, 0.0750579, -0.256367, -0.749072, -0.610874, -0.92242, 0.00300137, -0.386176, -0.915525, 0.00500287, -0.402231, 0.679395, -0.526306, -0.511297, -0.621461, 0.0540401, -0.781579, -0.575446, 0.0600465, -0.815632, -0.652026, -0.668052, 0.358564, 0.0260168, -0.100064, 0.994641, 0.698563, -0.119096, 0.705568, -0.271477, -0.803413, 0.529932, 0.0260168, -0.100064, 0.994641, 0.692997, -0.119171, 0.711023, -0.794437, -0.441799, -0.416754, -0.825667, 0.144116, -0.54544, -0.931153, 0.0550682, 0.360446, -0.799878, -0.563619, -0.206226, -0.825667, 0.144116, -0.54544, -0.92765, 0.0530944, 0.369657, -0.82285, -0.419434, -0.383396, -0.354195, 0.134074, -0.925511, -0.347958, 0.133984, -0.927887, 0.998285, -0.049014, 0.0320091, -0.240392, -0.969582, -0.0460752, 0.995776, -0.0529881, 0.0749831, 0.922569, 0.0029986, -0.38582, 0.257302, -0.748879, -0.610717, 0.915686, 0.00499829, -0.401862, -0.678856, -0.526664, -0.511645, 0.622074, 0.0540065, -0.781093, 0.576115, 0.060012, -0.815163 </vector3_array>
- <nil> </nil>
- <nil> </nil>
- <nil> </nil>
- <nil> </nil>
- <real_array len="2500"> 6, 7, 0, 0, 6, 7, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 6, 7, 0, 0, 7, 0, 0, 0, 7, 6, 0, 0, 7, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 7, 0, 0, 6, 7, 0, 0, 6, 7, 0, 0, 6, 7, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 13, 0, 0, 0, 14, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 6, 3, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 3, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 9, 0, 0, 0, 8, 9, 3, 0, 8, 9, 3, 0, 8, 9, 0, 0, 8, 9, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 13, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 14, 0, 0, 0, 1, 3, 0, 0, 1, 3, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 3, 6, 0, 0, 3, 6, 0, 0, 3, 6, 0, 0, 3, 6, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 1, 3, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 3, 0, 0, 1, 3, 0, 0, 1, 0, 0, 0, 1, 3, 0, 0, 1, 0, 0, 0, 1, 3, 0, 0, 1, 0, 0, 0, 8, 9, 3, 0, 8, 9, 0, 0, 12, 13, 1, 0, 12, 13, 1, 0, 12, 13, 0, 0, 12, 13, 0, 0, 12, 13, 1, 0, 12, 13, 1, 0, 12, 13, 0, 0, 12, 13, 0, 0, 12, 13, 1, 0, 12, 13, 0, 0, 12, 13, 1, 0, 12, 13, 0, 0, 3, 0, 0, 0, 8, 9, 3, 0, 8, 9, 3, 0, 8, 9, 0, 0, 9, 8, 0, 0, 9, 8, 3, 0, 9, 8, 0, 0, 9, 8, 3, 0, 9, 8, 0, 0, 8, 9, 3, 0, 8, 9, 0, 0, 12, 13, 1, 0, 12, 13, 0, 0, 12, 13, 1, 0, 12, 13, 0, 0, 3, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 7, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 6, 7, 0, 0, 7, 0, 0, 0, 6, 7, 0, 0, 7, 6, 0, 0, 7, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 7, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 7, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 16, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 16, 0, 0, 0, 17, 0, 0, 0, 16, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 6, 3, 0, 0, 6, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 11, 0, 0, 0, 10, 11, 3, 0, 10, 11, 0, 0, 10, 11, 0, 0, 10, 11, 3, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 16, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 17, 0, 0, 0, 1, 3, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 3, 0, 0, 3, 6, 0, 0, 3, 6, 0, 0, 3, 6, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 1, 3, 0, 0, 1, 0, 0, 0, 1, 3, 0, 0, 1, 0, 0, 0, 1, 3, 0, 0, 1, 0, 0, 0, 10, 11, 3, 0, 10, 11, 0, 0, 15, 16, 1, 0, 15, 16, 0, 0, 15, 16, 0, 0, 15, 16, 1, 0, 15, 16, 1, 0, 15, 16, 0, 0, 15, 16, 0, 0, 15, 16, 1, 0, 15, 16, 1, 0, 15, 16, 0, 0, 15, 16, 0, 0, 15, 16, 1, 0, 3, 0, 0, 0, 10, 11, 3, 0, 11, 10, 0, 0, 10, 11, 0, 0, 10, 11, 3, 0, 11, 10, 0, 0, 11, 10, 3, 0, 11, 10, 3, 0, 11, 10, 0, 0, 10, 11, 0, 0, 10, 11, 3, 0, 15, 16, 0, 0, 15, 16, 1, 0, 15, 16, 1, 0, 15, 16, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 1, 0, 0, 3, 1, 0, 0, 3, 0, 0, 0, 3, 1, 0, 0, 3, 1, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 1, 0, 0, 3, 0, 0, 0, 3, 1, 0, 0, 3, 0, 0, 0, 3, 1, 0, 0, 3, 0, 0, 0, 3, 1, 0, 0, 3, 1, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 1, 0, 0, 3, 0, 0, 0, 3, 1, 0, 0, 3, 0, 0, 0, 3, 1, 0, 0, 3, 6, 0, 0, 6, 0, 0, 0, 6, 3, 0, 0, 6, 3, 0, 0, 6, 0, 0, 0, 6, 3, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 0, 0, 0, 6, 3, 0, 0, 6, 3, 0, 0, 3, 0, 0, 0, 3, 10, 11, 0, 3, 10, 11, 0, 3, 0, 0, 0, 3, 10, 11, 0, 3, 10, 11, 0, 3, 0, 0, 0, 3, 10, 11, 0, 3, 10, 11, 0, 3, 0, 0, 0, 3, 10, 11, 0, 3, 10, 11, 0, 3, 0, 0, 0, 3, 11, 10, 0, 3, 10, 11, 0, 3, 11, 10, 0, 3, 0, 0, 0, 3, 11, 10, 0, 3, 0, 0, 0, 3, 11, 10, 0, 3, 11, 10, 0, 3, 10, 11, 0, 3, 0, 0, 0, 3, 10, 11, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 8, 9, 0, 3, 8, 9, 0, 3, 8, 9, 0, 3, 8, 9, 0, 3, 0, 0, 0, 3, 8, 9, 0, 3, 8, 9, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 8, 9, 0, 3, 8, 9, 0, 3, 8, 9, 0, 3, 9, 8, 0, 3, 0, 0, 0, 3, 9, 8, 0, 3, 9, 8, 0, 3, 0, 0, 0, 3, 9, 8, 0, 3, 9, 8, 0, 3, 0, 0, 0, 3, 8, 9, 0, 3, 8, 9, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 12, 13, 0, 1, 12, 13, 0, 1, 12, 13, 0, 1, 12, 13, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 12, 13, 0, 1, 12, 13, 0, 1, 12, 13, 0, 1, 12, 13, 0, 1, 12, 0, 0, 12, 1, 13, 0, 12, 1, 13, 0, 1, 0, 0, 0, 1, 12, 13, 0, 1, 12, 13, 0, 1, 0, 0, 0, 1, 12, 13, 0, 1, 12, 13, 0, 1, 0, 0, 0, 1, 12, 13, 0, 1, 12, 13, 0, 1, 0, 0, 0, 1, 15, 16, 0, 1, 15, 16, 0, 1, 0, 0, 0, 1, 15, 16, 0, 1, 15, 16, 0, 1, 0, 0, 0, 1, 15, 16, 0, 1, 15, 16, 0, 1, 0, 0, 0, 1, 15, 16, 0, 1, 15, 16, 0, 1, 15, 0, 0, 15, 1, 16, 0, 15, 1, 16, 0, 1, 15, 16, 0, 1, 0, 0, 0, 1, 15, 16, 0, 1, 15, 16, 0, 1, 0, 0, 0, 1, 15, 16, 0, 1, 0, 0, 0, 1, 15, 16, 0, 1, 15, 16, 0 </real_array>
- <real_array len="2500"> 0.500006, 0.499994, 0, 0, 0.500036, 0.499964, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.508359, 0.491641, 0, 0, 1, 0, 0, 0, 0.500012, 0.499988, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.500137, 0.499863, 0, 0, 0.997415, 0.00258508, 0, 0, 0.5, 0.5, 0, 0, 0.502778, 0.497222, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.439327, 0.339942, 0.220731, 0, 0.397775, 0.362587, 0.239639, 0, 0.523139, 0.476861, 0, 0, 0.563768, 0.436232, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 0.66667, 0.33333, 0, 0, 1, 0, 0, 0, 0.412375, 0.353797, 0.233829, 0, 0.538228, 0.461772, 0, 0, 0.544073, 0.274503, 0.181424, 0, 0.550005, 0.266658, 0.183337, 0, 0.673479, 0.326521, 0, 0, 0.664658, 0.335342, 0, 0, 0.546797, 0.270935, 0.182268, 0, 0.544673, 0.273746, 0.181581, 0, 0.665519, 0.334481, 0, 0, 0.668675, 0.331325, 0, 0, 0.615652, 0.230199, 0.154149, 0, 0.6672, 0.3328, 0, 0, 0.544198, 0.2744, 0.181402, 0, 0.664792, 0.335208, 0, 0, 1, 0, 0, 0, 0.37581, 0.37581, 0.24838, 0, 0.378779, 0.374023, 0.247199, 0, 0.503159, 0.496841, 0, 0, 0.5, 0.5, 0, 0, 0.399773, 0.361383, 0.238845, 0, 0.525218, 0.474782, 0, 0, 0.409739, 0.358697, 0.231565, 0, 0.533212, 0.466788, 0, 0, 0.375815, 0.375807, 0.248378, 0, 0.500006, 0.499994, 0, 0, 0.56732, 0.24294, 0.18974, 0, 0.700171, 0.299829, 0, 0, 0.544164, 0.274448, 0.181388, 0, 0.66474, 0.33526, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.500006, 0.499994, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.500036, 0.499964, 0, 0, 1, 0, 0, 0, 0.508359, 0.491641, 0, 0, 0.500012, 0.499988, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.502778, 0.497222, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.439327, 0.339942, 0.220731, 0, 0.563768, 0.436232, 0, 0, 0.523139, 0.476861, 0, 0, 0.397775, 0.362587, 0.239639, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 0.412375, 0.353797, 0.233829, 0, 0.538228, 0.461772, 0, 0, 0.544073, 0.274503, 0.181424, 0, 0.664658, 0.335342, 0, 0, 0.673479, 0.326521, 0, 0, 0.550005, 0.266658, 0.183337, 0, 0.546797, 0.270935, 0.182268, 0, 0.668675, 0.331325, 0, 0, 0.665519, 0.334481, 0, 0, 0.544673, 0.273746, 0.181581, 0, 0.615652, 0.230199, 0.154149, 0, 0.6672, 0.3328, 0, 0, 0.664792, 0.335208, 0, 0, 0.544198, 0.2744, 0.181402, 0, 1, 0, 0, 0, 0.37581, 0.37581, 0.24838, 0, 0.5, 0.5, 0, 0, 0.503159, 0.496841, 0, 0, 0.378779, 0.374023, 0.247199, 0, 0.525218, 0.474782, 0, 0, 0.399773, 0.361383, 0.238845, 0, 0.409739, 0.358697, 0.231565, 0, 0.533212, 0.466788, 0, 0, 0.500006, 0.499994, 0, 0, 0.375815, 0.375807, 0.248378, 0, 0.700171, 0.299829, 0, 0, 0.56732, 0.24294, 0.18974, 0, 0.544164, 0.274448, 0.181388, 0, 0.66474, 0.33526, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 0.666663, 0.333337, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666667, 0.333333, 0, 0, 0.666667, 0.333333, 0, 0, 1, 0, 0, 0, 0.718253, 0.15884, 0.122907, 0, 0.739344, 0.136359, 0.124296, 0, 1, 0, 0, 0, 0.45939, 0.304779, 0.235832, 0, 0.485992, 0.268898, 0.245111, 0, 1, 0, 0, 0, 0.7331, 0.143653, 0.123247, 0, 0.477963, 0.280975, 0.241062, 0, 1, 0, 0, 0, 0.748373, 0.125813, 0.125813, 0, 0.747178, 0.12721, 0.125612, 0, 1, 0, 0, 0, 0.497836, 0.251082, 0.251082, 0, 0.496251, 0.253466, 0.250283, 0, 0.738503, 0.137343, 0.124154, 0, 1, 0, 0, 0, 0.484902, 0.270539, 0.244559, 0, 1, 0, 0, 0, 0.730612, 0.143641, 0.125747, 0, 0.4748, 0.280042, 0.245157, 0, 0.748371, 0.125816, 0.125813, 0, 1, 0, 0, 0, 0.497833, 0.251086, 0.251081, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.739344, 0.136359, 0.124296, 0, 0.718253, 0.15884, 0.122907, 0, 0.485992, 0.268898, 0.245111, 0, 0.45939, 0.304779, 0.235832, 0, 1, 0, 0, 0, 0.7331, 0.143653, 0.123247, 0, 0.477963, 0.280975, 0.241062, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.747178, 0.12721, 0.125612, 0, 0.748373, 0.125813, 0.125813, 0, 0.496251, 0.253466, 0.250283, 0, 0.497836, 0.251082, 0.251082, 0, 1, 0, 0, 0, 0.738503, 0.137343, 0.124154, 0, 0.484902, 0.270539, 0.244559, 0, 1, 0, 0, 0, 0.730612, 0.143641, 0.125747, 0, 0.4748, 0.280042, 0.245157, 0, 1, 0, 0, 0, 0.748371, 0.125816, 0.125813, 0, 0.497833, 0.251086, 0.251081, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.668925, 0.222972, 0.108103, 0, 0.666077, 0.221944, 0.111978, 0, 0.402445, 0.40244, 0.195114, 0, 0.399364, 0.399217, 0.201418, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0.666312, 0.222075, 0.111612, 0, 0.667337, 0.222443, 0.110219, 0, 0.399617, 0.399566, 0.200817, 0, 0.400725, 0.40072, 0.198555, 0, 0.500004, 0.499996, 0, 0, 0.533361, 0.40023, 0.0664093, 0, 0.571539, 0.286063, 0.142398, 0, 1, 0, 0, 0, 0.666044, 0.222012, 0.111945, 0, 0.399328, 0.399322, 0.20135, 0, 1, 0, 0, 0, 0.678203, 0.225313, 0.0964842, 0, 0.412634, 0.411257, 0.176109, 0, 1, 0, 0, 0, 0.666023, 0.222008, 0.111969, 0, 0.399306, 0.399306, 0.201389, 0, 1, 0, 0, 0, 0.666077, 0.221944, 0.111978, 0, 0.668925, 0.222972, 0.108103, 0, 1, 0, 0, 0, 0.399364, 0.399217, 0.201418, 0, 0.402445, 0.40244, 0.195114, 0, 1, 0, 0, 0, 0.667337, 0.222443, 0.110219, 0, 0.666312, 0.222075, 0.111612, 0, 1, 0, 0, 0, 0.400725, 0.40072, 0.198555, 0, 0.399617, 0.399566, 0.200817, 0, 0.500004, 0.499996, 0, 0, 0.533361, 0.40023, 0.0664093, 0, 0.571539, 0.286063, 0.142398, 0, 0.666044, 0.222012, 0.111945, 0, 1, 0, 0, 0, 0.399328, 0.399322, 0.20135, 0, 0.678203, 0.225313, 0.0964842, 0, 1, 0, 0, 0, 0.412634, 0.411257, 0.176109, 0, 1, 0, 0, 0, 0.666023, 0.222008, 0.111969, 0, 0.399306, 0.399306, 0.201389, 0 </real_array>
- <int_array len="2502"> 0, 2, 1, 0, 3, 2, 1, 5, 4, 1, 2, 5, 6, 5, 7, 6, 4, 5, 8, 0, 9, 8, 10, 0, 11, 13, 12, 11, 14, 13, 15, 17, 16, 15, 7, 17, 12, 15, 18, 12, 13, 15, 10, 3, 0, 10, 19, 3, 13, 7, 15, 13, 6, 7, 2, 20, 5, 2, 21, 20, 7, 20, 17, 7, 5, 20, 21, 3, 22, 21, 2, 3, 18, 16, 23, 18, 15, 16, 22, 19, 24, 22, 3, 19, 25, 27, 26, 25, 28, 27, 29, 28, 25, 29, 30, 28, 26, 32, 31, 26, 27, 32, 33, 35, 34, 33, 36, 35, 37, 39, 38, 37, 40, 39, 38, 42, 41, 38, 39, 42, 43, 45, 44, 43, 46, 45, 47, 49, 48, 47, 50, 49, 51, 53, 52, 51, 54, 53, 55, 46, 56, 55, 45, 46, 57, 44, 58, 57, 43, 44, 59, 61, 60, 59, 50, 61, 62, 45, 55, 62, 63, 45, 64, 48, 65, 64, 47, 48, 66, 50, 59, 66, 49, 50, 67, 43, 57, 67, 68, 43, 69, 68, 67, 69, 70, 68, 34, 49, 66, 34, 35, 49, 65, 70, 69, 65, 48, 70, 58, 72, 71, 58, 44, 72, 56, 36, 33, 56, 46, 36, 71, 74, 73, 71, 72, 74, 60, 63, 62, 60, 61, 63, 73, 47, 64, 73, 74, 47, 75, 77, 76, 75, 78, 77, 79, 41, 80, 79, 38, 41, 81, 38, 79, 81, 37, 38, 80, 83, 82, 80, 41, 83, 84, 37, 81, 84, 85, 37, 41, 86, 83, 41, 42, 86, 85, 40, 37, 85, 87, 40, 42, 88, 86, 42, 89, 88, 87, 90, 40, 87, 91, 90, 40, 92, 39, 40, 90, 92, 39, 89, 42, 39, 92, 89, 48, 35, 70, 48, 49, 35, 74, 50, 47, 74, 61, 50, 70, 36, 68, 70, 35, 36, 44, 63, 72, 44, 45, 63, 68, 46, 43, 68, 36, 46, 72, 61, 74, 72, 63, 61, 93, 95, 94, 93, 96, 95, 97, 25, 26, 97, 98, 25, 98, 29, 25, 98, 99, 29, 100, 26, 31, 100, 97, 26, 31, 102, 101, 31, 32, 102, 103, 105, 104, 103, 106, 105, 104, 108, 107, 104, 105, 108, 107, 110, 109, 107, 108, 110, 111, 113, 112, 111, 114, 113, 115, 112, 116, 115, 111, 112, 117, 116, 118, 117, 115, 116, 119, 118, 120, 119, 117, 118, 114, 110, 113, 114, 109, 110, 121, 123, 122, 121, 124, 123, 125, 124, 121, 125, 126, 124, 127, 129, 128, 128, 129, 130, 131, 129, 132, 133, 130, 129, 134, 133, 129, 135, 134, 129, 136, 138, 137, 136, 139, 138, 140, 142, 141, 140, 143, 142, 144, 146, 145, 144, 147, 146, 145, 149, 148, 145, 146, 149, 148, 151, 150, 148, 149, 151, 150, 153, 152, 150, 151, 153, 152, 143, 140, 152, 153, 143, 154, 156, 155, 154, 157, 156, 155, 159, 158, 155, 156, 159, 158, 106, 103, 158, 159, 106, 160, 162, 161, 160, 163, 162, 164, 161, 165, 164, 160, 161, 166, 165, 167, 166, 164, 165, 168, 167, 169, 168, 166, 167, 154, 120, 157, 154, 119, 120, 144, 169, 147, 144, 168, 169, 163, 142, 162, 163, 141, 142, 170, 172, 171, 170, 173, 172, 174, 173, 170, 174, 175, 173, 176, 178, 177, 176, 179, 178, 177, 126, 125, 177, 178, 126, 180, 179, 176, 180, 181, 179, 122, 181, 180, 122, 123, 181, 182, 184, 183, 182, 185, 184, 183, 187, 186, 183, 184, 187, 186, 189, 188, 186, 187, 189, 188, 191, 190, 188, 189, 191, 190, 193, 192, 190, 191, 193, 192, 195, 194, 192, 193, 195, 196, 198, 197, 196, 199, 198, 200, 197, 201, 200, 196, 197, 202, 201, 203, 202, 200, 201, 204, 203, 205, 204, 202, 203, 199, 195, 198, 199, 194, 195, 182, 205, 185, 182, 204, 205, 206, 129, 127, 207, 129, 131, 132, 129, 206, 208, 135, 129, 209, 208, 129, 207, 209, 129, 210, 139, 136, 210, 211, 139, 28, 212, 27, 28, 213, 212, 30, 213, 28, 30, 214, 213, 27, 215, 32, 27, 212, 215, 216, 218, 217, 216, 219, 218, 220, 95, 221, 220, 94, 95, 222, 218, 219, 222, 223, 218, 224, 96, 93, 224, 225, 96, 220, 223, 222, 220, 221, 223, 226, 78, 75, 226, 227, 78, 228, 230, 229, 228, 231, 230, 232, 234, 233, 232, 235, 234, 236, 235, 232, 236, 237, 235, 229, 239, 238, 229, 230, 239, 233, 231, 228, 233, 234, 231, 32, 240, 102, 32, 215, 240, 241, 243, 242, 241, 244, 243, 76, 246, 245, 76, 77, 246, 247, 227, 226, 247, 248, 227, 242, 250, 249, 242, 243, 250, 245, 244, 241, 245, 246, 244, 249, 248, 247, 249, 250, 248, 238, 252, 251, 238, 239, 252, 253, 237, 236, 253, 254, 237, 251, 254, 253, 251, 252, 254, 102, 240, 255, 9, 1, 256, 9, 0, 1, 14, 6, 13, 14, 257, 6, 256, 4, 258, 256, 1, 4, 257, 4, 6, 257, 258, 4, 259, 261, 260, 259, 262, 261, 262, 263, 261, 262, 264, 263, 265, 263, 264, 265, 266, 263, 8, 259, 10, 8, 267, 259, 11, 269, 268, 11, 12, 269, 270, 271, 266, 270, 272, 271, 12, 270, 269, 12, 18, 270, 10, 260, 19, 10, 259, 260, 269, 266, 265, 269, 270, 266, 261, 274, 273, 261, 263, 274, 266, 274, 263, 266, 271, 274, 260, 273, 275, 260, 261, 273, 18, 272, 270, 18, 23, 272, 19, 275, 24, 19, 260, 275, 276, 278, 277, 276, 279, 278, 29, 277, 30, 29, 276, 277, 279, 280, 278, 279, 281, 280, 282, 284, 283, 282, 285, 284, 286, 288, 287, 286, 289, 288, 289, 290, 288, 289, 291, 290, 292, 294, 293, 292, 295, 294, 296, 298, 297, 296, 299, 298, 300, 53, 54, 300, 301, 53, 302, 293, 294, 302, 303, 293, 304, 295, 292, 304, 305, 295, 306, 307, 297, 306, 308, 307, 309, 294, 310, 309, 302, 294, 311, 299, 296, 311, 312, 299, 313, 297, 298, 313, 306, 297, 314, 292, 315, 314, 304, 292, 316, 315, 317, 316, 314, 315, 285, 298, 284, 285, 313, 298, 312, 317, 299, 312, 316, 317, 305, 318, 295, 305, 319, 318, 303, 283, 293, 303, 282, 283, 319, 320, 318, 319, 321, 320, 308, 310, 307, 308, 309, 310, 321, 296, 320, 321, 311, 296, 322, 324, 323, 322, 325, 324, 326, 291, 289, 326, 327, 291, 328, 289, 286, 328, 326, 289, 327, 329, 291, 327, 330, 329, 331, 286, 332, 331, 328, 286, 291, 333, 290, 291, 329, 333, 332, 287, 334, 332, 286, 287, 290, 336, 335, 290, 333, 336, 334, 338, 337, 334, 287, 338, 287, 339, 338, 287, 288, 339, 288, 335, 339, 288, 290, 335, 299, 284, 298, 299, 317, 284, 320, 297, 307, 320, 296, 297, 317, 283, 284, 317, 315, 283, 295, 310, 294, 295, 318, 310, 315, 293, 283, 315, 292, 293, 318, 307, 310, 318, 320, 307, 340, 342, 341, 340, 343, 342, 344, 276, 345, 344, 279, 276, 345, 29, 99, 345, 276, 29, 346, 279, 344, 346, 281, 279, 281, 102, 280, 281, 101, 102, 347, 349, 348, 347, 350, 349, 350, 351, 349, 350, 352, 351, 352, 353, 351, 352, 354, 353, 355, 357, 356, 355, 358, 357, 359, 358, 355, 359, 360, 358, 361, 360, 359, 361, 362, 360, 363, 362, 361, 363, 364, 362, 356, 353, 354, 356, 357, 353, 365, 367, 366, 365, 368, 367, 369, 366, 370, 369, 365, 366, 371, 373, 372, 373, 374, 372, 375, 376, 372, 377, 372, 374, 378, 372, 377, 379, 372, 378, 136, 381, 380, 136, 137, 381, 382, 384, 383, 382, 385, 384, 386, 388, 387, 386, 389, 388, 389, 390, 388, 389, 391, 390, 391, 392, 390, 391, 393, 392, 393, 394, 392, 393, 395, 394, 395, 383, 394, 395, 382, 383, 396, 398, 397, 396, 399, 398, 399, 400, 398, 399, 401, 400, 401, 348, 400, 401, 347, 348, 402, 404, 403, 402, 405, 404, 406, 405, 402, 406, 407, 405, 408, 407, 406, 408, 409, 407, 410, 409, 408, 410, 411, 409, 396, 364, 363, 396, 397, 364, 386, 411, 410, 386, 387, 411, 403, 384, 385, 403, 404, 384, 412, 414, 413, 412, 415, 414, 416, 413, 417, 416, 412, 413, 418, 420, 419, 418, 421, 420, 421, 370, 420, 421, 369, 370, 422, 419, 423, 422, 418, 419, 368, 423, 367, 368, 422, 423, 424, 426, 425, 424, 427, 426, 427, 428, 426, 427, 429, 428, 429, 430, 428, 429, 431, 430, 431, 432, 430, 431, 433, 432, 433, 434, 432, 433, 435, 434, 435, 436, 434, 435, 437, 436, 438, 440, 439, 438, 441, 440, 442, 441, 438, 442, 443, 441, 444, 443, 442, 444, 445, 443, 446, 445, 444, 446, 447, 445, 439, 436, 437, 439, 440, 436, 424, 447, 446, 424, 425, 447, 448, 371, 372, 449, 375, 372, 376, 448, 372, 450, 372, 379, 451, 372, 450, 449, 372, 451, 210, 380, 452, 210, 136, 380, 277, 454, 453, 277, 278, 454, 30, 453, 214, 30, 277, 453, 278, 455, 454, 278, 280, 455, 216, 457, 456, 216, 217, 457, 458, 342, 343, 458, 459, 342, 460, 457, 461, 460, 456, 457, 224, 341, 225, 224, 340, 341, 458, 461, 459, 458, 460, 461, 462, 323, 463, 462, 322, 323, 464, 466, 465, 464, 467, 466, 468, 470, 469, 468, 471, 470, 472, 469, 473, 472, 468, 469, 467, 474, 466, 467, 475, 474, 471, 465, 470, 471, 464, 465, 280, 476, 455, 280, 102, 476, 477, 479, 478, 477, 480, 479, 325, 481, 324, 325, 482, 481, 483, 463, 484, 483, 462, 463, 480, 485, 479, 480, 486, 485, 482, 478, 481, 482, 477, 478, 486, 484, 485, 486, 483, 484, 475, 487, 474, 475, 488, 487, 489, 473, 490, 489, 472, 473, 488, 490, 487, 488, 489, 490, 102, 255, 476, 267, 262, 259, 267, 491, 262, 268, 265, 492, 268, 269, 265, 491, 264, 262, 491, 493, 264, 492, 264, 493, 492, 265, 264, 494, 496, 495, 494, 497, 496, 497, 94, 496, 497, 93, 94, 498, 500, 499, 498, 501, 500, 499, 219, 216, 499, 500, 219, 502, 496, 503, 502, 495, 496, 503, 94, 220, 503, 496, 94, 504, 500, 501, 504, 505, 500, 505, 219, 500, 505, 222, 219, 506, 497, 494, 506, 507, 497, 507, 93, 497, 507, 224, 93, 502, 505, 504, 502, 503, 505, 503, 222, 505, 503, 220, 222, 508, 510, 509, 508, 511, 510, 509, 343, 340, 509, 510, 343, 498, 513, 512, 498, 499, 513, 499, 456, 513, 499, 216, 456, 514, 510, 511, 514, 515, 510, 515, 343, 510, 515, 458, 343, 516, 513, 517, 516, 512, 513, 517, 456, 460, 517, 513, 456, 506, 509, 507, 506, 508, 509, 507, 340, 224, 507, 509, 340, 514, 517, 515, 514, 516, 517, 515, 460, 458, 515, 517, 460, 31, 518, 100, 31, 101, 518, 100, 54, 51, 100, 518, 54, 519, 521, 520, 519, 522, 521, 520, 98, 97, 520, 521, 98, 522, 523, 521, 522, 524, 523, 521, 99, 98, 521, 523, 99, 52, 520, 51, 52, 519, 520, 51, 97, 100, 51, 520, 97, 281, 518, 101, 281, 346, 518, 346, 54, 518, 346, 300, 54, 525, 527, 526, 525, 528, 527, 528, 345, 527, 528, 344, 345, 526, 523, 524, 526, 527, 523, 527, 99, 523, 527, 345, 99, 301, 528, 525, 301, 300, 528, 300, 344, 528, 300, 346, 344, 529, 531, 530, 529, 532, 531, 530, 534, 533, 530, 531, 534, 533, 325, 322, 533, 534, 325, 535, 530, 536, 535, 529, 530, 536, 533, 537, 536, 530, 533, 537, 322, 462, 537, 533, 322, 538, 540, 539, 538, 541, 540, 539, 543, 542, 539, 540, 543, 542, 480, 477, 542, 543, 480, 532, 544, 531, 532, 545, 544, 531, 546, 534, 531, 544, 546, 534, 482, 325, 534, 546, 482, 547, 536, 548, 547, 535, 536, 548, 537, 549, 548, 536, 537, 549, 462, 483, 549, 537, 462, 541, 550, 540, 541, 551, 550, 540, 552, 543, 540, 550, 552, 543, 486, 480, 543, 552, 486, 545, 539, 544, 545, 538, 539, 544, 542, 546, 544, 539, 542, 546, 477, 482, 546, 542, 477, 551, 548, 550, 551, 547, 548, 550, 549, 552, 550, 548, 549, 552, 483, 486, 552, 549, 483, 553, 555, 554, 553, 556, 555, 556, 557, 555, 556, 558, 557, 558, 76, 557, 558, 75, 76, 559, 556, 553, 559, 560, 556, 560, 558, 556, 560, 561, 558, 561, 75, 558, 561, 226, 75, 562, 564, 563, 562, 565, 564, 565, 566, 564, 565, 567, 566, 567, 242, 566, 567, 241, 242, 554, 569, 568, 554, 555, 569, 555, 570, 569, 555, 557, 570, 557, 245, 570, 557, 76, 245, 571, 560, 559, 571, 572, 560, 572, 561, 560, 572, 573, 561, 573, 226, 561, 573, 247, 226, 563, 575, 574, 563, 564, 575, 564, 576, 575, 564, 566, 576, 566, 249, 576, 566, 242, 249, 568, 565, 562, 568, 569, 565, 569, 567, 565, 569, 570, 567, 570, 241, 567, 570, 245, 241, 574, 572, 571, 574, 575, 572, 575, 573, 572, 575, 576, 573, 576, 247, 573, 576, 249, 247, 577, 579, 578, 577, 580, 579, 580, 581, 579, 580, 582, 581, 582, 229, 581, 582, 228, 229, 583, 585, 584, 583, 586, 585, 586, 587, 585, 586, 588, 587, 588, 233, 587, 588, 232, 233, 589, 586, 583, 589, 590, 586, 590, 588, 586, 590, 591, 588, 591, 232, 588, 591, 236, 232, 578, 593, 592, 578, 579, 593, 579, 594, 593, 579, 581, 594, 581, 238, 594, 581, 229, 238, 584, 580, 577, 584, 585, 580, 585, 582, 580, 585, 587, 582, 587, 228, 582, 587, 233, 228, 592, 596, 595, 592, 593, 596, 593, 597, 596, 593, 594, 597, 594, 251, 597, 594, 238, 251, 598, 590, 589, 598, 599, 590, 599, 591, 590, 599, 600, 591, 600, 236, 591, 600, 253, 236, 595, 599, 598, 595, 596, 599, 596, 600, 599, 596, 597, 600, 597, 253, 600, 597, 251, 253, 601, 603, 602, 601, 604, 603, 602, 606, 605, 602, 603, 606, 605, 467, 464, 605, 606, 467, 607, 609, 608, 607, 610, 609, 608, 612, 611, 608, 609, 612, 611, 471, 468, 611, 612, 471, 613, 608, 614, 613, 607, 608, 614, 611, 615, 614, 608, 611, 615, 468, 472, 615, 611, 468, 604, 616, 603, 604, 617, 616, 603, 618, 606, 603, 616, 618, 606, 475, 467, 606, 618, 475, 610, 602, 609, 610, 601, 602, 609, 605, 612, 609, 602, 605, 612, 464, 471, 612, 605, 464, 617, 619, 616, 617, 620, 619, 616, 621, 618, 616, 619, 621, 618, 488, 475, 618, 621, 488, 622, 614, 623, 622, 613, 614, 623, 615, 624, 623, 614, 615, 624, 472, 489, 624, 615, 472, 620, 623, 619, 620, 622, 623, 619, 624, 621, 619, 623, 624, 621, 489, 488, 621, 624, 489 </int_array>
- </array>
- </dictionary>
-
- </resource>
- <resource type="SampleLibrary" path="local://6">
- </resource>
- <resource type="Animation" path="local://7">
- <string name="resource/name"> "idle" </string>
- <real name="length"> 1.25 </real>
- <bool name="loop"> True </bool>
- <real name="step"> 0.1 </real>
- <string name="tracks/0/type"> "transform" </string>
- <node_path name="tracks/0/path"> "Armature/Skeleton:r-arm" </node_path>
- <int name="tracks/0/interp"> 1 </int>
- <real_array name="tracks/0/keys" len="180"> 0, 1, 1.01328e-06, -8.34465e-07, 1.07288e-06, -0.0255728, 0.138077, -0.259039, 0.955604, 1, 1, 1, 0.05, 1, 5.96046e-07, -2.38419e-07, 3.8743e-07, -0.0264725, 0.139277, -0.25962, 0.955248, 1, 1, 1, 0.1, 1, 5.36442e-07, -2.38419e-07, 3.8743e-07, -0.028916, 0.142508, -0.261183, 0.954274, 1, 1, 1, 0.15, 1, 1.19209e-07, 1.19209e-07, 5.96046e-08, -0.0326835, 0.14736, -0.26354, 0.952766, 1, 1, 1, 0.25, 1, 5.96046e-08, 1.19209e-07, 0, -0.0433083, 0.158072, -0.268982, 0.949098, 1, 1, 1, 0.3, 1, 8.9407e-07, -3.57628e-07, 5.96046e-07, -0.0481632, 0.16058, -0.27034, 0.948056, 1, 1, 1, 0.35, 1, 7.15256e-07, -3.57628e-07, 5.36442e-07, -0.0515519, 0.159894, -0.270034, 0.948081, 1, 1, 1, 0.4, 1, 6.25849e-07, -3.57628e-07, 5.06639e-07, -0.0529994, 0.155917, -0.267946, 0.949256, 1, 1, 1, 0.85, 1, 8.04663e-07, -5.96046e-07, 8.34465e-07, -0.01551, 0.114246, -0.235933, 0.964906, 1, 1, 1, 0.9, 1, 7.15256e-07, -4.76837e-07, 7.15256e-07, -0.0133439, 0.115591, -0.236366, 0.964672, 1, 1, 1, 0.95, 1, 5.06639e-07, -3.57628e-07, 4.76837e-07, -0.0142794, 0.118993, -0.239276, 0.963527, 1, 1, 1, 1.1, 1, 6.55651e-07, -3.57628e-07, 5.36442e-07, -0.0224776, 0.132362, -0.25315, 0.958066, 1, 1, 1, 1.15, 1, 7.45058e-07, -2.38419e-07, 4.17233e-07, -0.0241962, 0.135447, -0.25637, 0.956736, 1, 1, 1, 1.2, 1, 7.15256e-07, -2.38419e-07, 5.06639e-07, -0.0252313, 0.137384, -0.258343, 0.955902, 1, 1, 1, 1.25, 1, 1.01328e-06, -8.34465e-07, 1.07288e-06, -0.0255726, 0.138077, -0.259039, 0.955604, 1, 1, 1 </real_array>
- <string name="tracks/1/type"> "transform" </string>
- <node_path name="tracks/1/path"> "Armature/Skeleton:r-forearm" </node_path>
- <int name="tracks/1/interp"> 1 </int>
- <real_array name="tracks/1/keys" len="204"> 0, 1, 2.38419e-07, -8.34465e-07, -4.76837e-07, -0.218168, -0.120735, -0.0116329, 0.968344, 1, 1, 1, 0.05, 1, 2.98023e-08, -5.96046e-07, -2.38419e-07, -0.218633, -0.120967, -0.0119311, 0.968207, 1, 1, 1, 0.1, 1, 1.78814e-07, -7.7486e-07, -4.76837e-07, -0.219848, -0.121646, -0.0127373, 0.967836, 1, 1, 1, 0.15, 1, -5.96046e-08, -6.25849e-07, -4.76837e-07, -0.221585, -0.122891, -0.0139574, 0.967266, 1, 1, 1, 0.2, 1, -2.98023e-08, -9.83477e-07, -1.78814e-07, -0.223801, -0.125062, -0.0151597, 0.966459, 1, 1, 1, 0.25, 1, 1.49012e-07, -5.66244e-07, -2.38419e-07, -0.225991, -0.128733, -0.0159408, 0.965454, 1, 1, 1, 0.3, 1, 0, -1.04308e-06, -2.38419e-07, -0.227229, -0.134329, -0.0159913, 0.9644, 1, 0.999999, 1, 0.55, 1, 2.98023e-08, -5.66244e-07, -3.57628e-07, -0.218159, -0.170756, -0.00658222, 0.960836, 1, 1, 1, 0.6, 1, 1.49012e-07, -5.36442e-07, -2.98023e-07, -0.214746, -0.174272, -0.00460497, 0.960985, 1, 1, 1, 0.65, 1, 2.38419e-07, -2.08616e-07, -3.57628e-07, -0.21128, -0.17607, -0.0030008, 0.961432, 1, 1, 1, 0.7, 1, 1.49012e-07, -4.47035e-07, -2.38419e-07, -0.207961, -0.17612, -0.00179697, 0.962149, 1, 1, 1, 0.75, 1, -2.38419e-07, -6.55651e-07, -3.57628e-07, -0.204984, -0.174339, -0.000935222, 0.963113, 1, 1, 1, 0.8, 1, 8.9407e-08, -2.98023e-08, -1.19209e-07, -0.202542, -0.170485, -0.000499965, 0.964319, 1, 0.999999, 1, 0.85, 1, 8.9407e-08, -8.64267e-07, -4.17233e-07, -0.200954, -0.164989, -0.000498206, 0.965607, 1, 0.999999, 1, 1.15, 1, 1.19209e-07, -6.85453e-07, -2.98023e-07, -0.216378, -0.124725, -0.0104075, 0.968254, 1, 1, 1, 1.2, 1, -2.98023e-08, 2.98023e-08, -1.78814e-07, -0.217708, -0.121801, -0.0113103, 0.968318, 1, 1, 1, 1.25, 1, 2.38419e-07, -8.34465e-07, -4.76837e-07, -0.218168, -0.120734, -0.0116329, 0.968344, 1, 1, 1 </real_array>
- <string name="tracks/2/type"> "transform" </string>
- <node_path name="tracks/2/path"> "Armature/Skeleton:l-arm" </node_path>
- <int name="tracks/2/interp"> 1 </int>
- <real_array name="tracks/2/keys" len="180"> 0, 1, -1.01328e-06, -8.34465e-07, 1.07288e-06, -0.0255728, -0.138077, 0.25904, 0.955604, 1, 1, 1, 0.05, 1, -5.96046e-07, -2.38419e-07, 3.8743e-07, -0.0264725, -0.139277, 0.25962, 0.955248, 1, 1, 1, 0.1, 1, -5.36442e-07, -2.38419e-07, 3.8743e-07, -0.028916, -0.142508, 0.261183, 0.954274, 1, 1, 1, 0.15, 1, -1.19209e-07, 1.19209e-07, 5.96046e-08, -0.0326835, -0.14736, 0.26354, 0.952766, 1, 1, 1, 0.25, 1, -5.96046e-08, 1.19209e-07, 0, -0.0433083, -0.158072, 0.268982, 0.949098, 1, 1, 1, 0.3, 1, -8.9407e-07, -3.57628e-07, 5.96046e-07, -0.0481632, -0.16058, 0.27034, 0.948056, 1, 1, 1, 0.35, 1, -7.15256e-07, -3.57628e-07, 5.36442e-07, -0.0515519, -0.159894, 0.270034, 0.948081, 1, 1, 1, 0.4, 1, -6.25849e-07, -3.57628e-07, 5.06639e-07, -0.0529994, -0.155917, 0.267946, 0.949256, 1, 1, 1, 0.85, 1, -8.04663e-07, -5.96046e-07, 8.34465e-07, -0.01551, -0.114246, 0.235933, 0.964906, 1, 1, 1, 0.9, 1, -7.15256e-07, -4.76837e-07, 7.15256e-07, -0.0133439, -0.115591, 0.236367, 0.964672, 1, 1, 1, 0.95, 1, -5.06639e-07, -3.57628e-07, 4.76837e-07, -0.0142794, -0.118993, 0.239276, 0.963527, 1, 1, 1, 1.1, 1, -6.55651e-07, -3.57628e-07, 5.36442e-07, -0.0224776, -0.132362, 0.25315, 0.958066, 1, 1, 1, 1.15, 1, -7.45058e-07, -2.38419e-07, 4.17233e-07, -0.0241962, -0.135447, 0.25637, 0.956736, 1, 1, 1, 1.2, 1, -7.15256e-07, -2.38419e-07, 5.06639e-07, -0.0252313, -0.137384, 0.258343, 0.955902, 1, 1, 1, 1.25, 1, -1.01328e-06, -8.34465e-07, 1.07288e-06, -0.0255726, -0.138077, 0.259039, 0.955604, 1, 1, 1 </real_array>
- <string name="tracks/3/type"> "transform" </string>
- <node_path name="tracks/3/path"> "Armature/Skeleton:l-forearm" </node_path>
- <int name="tracks/3/interp"> 1 </int>
- <real_array name="tracks/3/keys" len="204"> 0, 1, -2.38419e-07, -8.34465e-07, -4.76837e-07, -0.218168, 0.120735, 0.0116329, 0.968344, 1, 1, 1, 0.05, 1, -5.96046e-08, -8.04663e-07, -3.57628e-07, -0.218633, 0.120966, 0.0119311, 0.968207, 1, 1, 1, 0.1, 1, -3.57628e-07, -7.45058e-07, -4.17233e-07, -0.219848, 0.121646, 0.0127373, 0.967836, 1, 1, 1, 0.15, 1, -1.49012e-07, -6.25849e-07, -3.57628e-07, -0.221585, 0.122891, 0.0139575, 0.967266, 1, 1, 1, 0.2, 1, 0, -9.53674e-07, -1.19209e-07, -0.223801, 0.125062, 0.0151597, 0.966459, 1, 1, 1, 0.25, 1, -1.49012e-07, -5.66244e-07, -2.38419e-07, -0.225991, 0.128733, 0.0159408, 0.965454, 1, 1, 1, 0.3, 1, 0, -1.04308e-06, -2.38419e-07, -0.227229, 0.134329, 0.0159913, 0.9644, 1, 0.999999, 1, 0.55, 1, -2.98023e-08, -5.66244e-07, -3.57628e-07, -0.218159, 0.170756, 0.00658222, 0.960836, 1, 1, 1, 0.6, 1, -1.49012e-07, -5.36442e-07, -2.98023e-07, -0.214746, 0.174272, 0.00460497, 0.960985, 1, 1, 1, 0.65, 1, -2.38419e-07, -2.08616e-07, -3.57628e-07, -0.21128, 0.17607, 0.0030008, 0.961432, 1, 1, 1, 0.7, 1, -1.49012e-07, -4.47035e-07, -2.38419e-07, -0.207961, 0.17612, 0.00179697, 0.962149, 1, 1, 1, 0.75, 1, 2.38419e-07, -6.55651e-07, -3.57628e-07, -0.204984, 0.174339, 0.000935222, 0.963113, 1, 1, 1, 0.8, 1, -2.98023e-08, 0, -1.19209e-07, -0.202542, 0.170485, 0.000499968, 0.964319, 1, 1, 1, 0.85, 1, 1.49012e-07, -8.34465e-07, -4.17233e-07, -0.200954, 0.164989, 0.000498198, 0.965606, 1, 1, 1, 1.15, 1, -2.38419e-07, -8.04663e-07, -6.55651e-07, -0.216378, 0.124725, 0.0104075, 0.968254, 1, 1, 1, 1.2, 1, -2.08616e-07, 2.08616e-07, -2.98023e-07, -0.217708, 0.121801, 0.0113103, 0.968318, 1, 1, 1, 1.25, 1, -2.38419e-07, -8.34465e-07, -4.76837e-07, -0.218168, 0.120734, 0.0116329, 0.968344, 1, 1, 1 </real_array>
- <string name="tracks/4/type"> "transform" </string>
- <node_path name="tracks/4/path"> "Armature/Skeleton:r-thigh" </node_path>
- <int name="tracks/4/interp"> 1 </int>
- <real_array name="tracks/4/keys" len="180"> 0, 1, 0, 5.21541e-08, -3.42727e-07, -0.0539951, -0.0696263, 0.0213632, 0.995882, 1, 1, 1, 0.05, 1, 0, 5.21541e-08, -3.42727e-07, -0.0567764, -0.0700338, 0.0212387, 0.995701, 1, 1, 1, 0.1, 1, 0, 3.72529e-08, -3.42727e-07, -0.06411, -0.0711033, 0.0209058, 0.995187, 1, 1, 1, 0.15, 1, 0, 9.68575e-08, -3.42727e-07, -0.0751103, -0.0727354, 0.0204167, 0.994309, 1, 1, 1, 0.45, 1, 0, 1.41561e-07, -1.3411e-07, -0.154319, -0.0862804, 0.0175296, 0.984091, 1, 1, 1, 0.5, 1, 2.98023e-08, 7.45058e-09, 2.5332e-07, -0.162001, -0.0877685, 0.017297, 0.982728, 1, 1, 1, 0.55, 1, 0, 3.72529e-08, -3.42727e-07, -0.166842, -0.0887317, 0.0171579, 0.981833, 1, 1, 1, 0.6, 1, 0, 2.98023e-08, -1.49012e-07, -0.169226, -0.0892111, 0.0170905, 0.981383, 1, 1, 1, 0.65, 1, 0, 2.98023e-08, -1.49012e-07, -0.169226, -0.0892111, 0.0170905, 0.981383, 1, 1, 1, 0.7, 1, 0, 3.72529e-08, -3.42727e-07, -0.166842, -0.0887317, 0.0171579, 0.981833, 1, 1, 1, 0.75, 1, 2.98023e-08, 7.45058e-09, 2.5332e-07, -0.162001, -0.0877685, 0.017297, 0.982728, 1, 1, 1, 0.8, 1, 0, 1.41561e-07, -1.3411e-07, -0.154319, -0.0862804, 0.0175296, 0.984091, 1, 1, 1, 1.15, 1, 0, 3.72529e-08, -3.42727e-07, -0.06411, -0.0711033, 0.0209058, 0.995187, 1, 1, 1, 1.2, 1, 0, 5.21541e-08, -3.42727e-07, -0.0567764, -0.0700338, 0.0212387, 0.995701, 1, 1, 1, 1.25, 1, 0, 5.21541e-08, -3.42727e-07, -0.0539951, -0.0696263, 0.0213632, 0.995882, 1, 1, 1 </real_array>
- <string name="tracks/5/type"> "transform" </string>
- <node_path name="tracks/5/path"> "Armature/Skeleton:r-leg" </node_path>
- <int name="tracks/5/interp"> 1 </int>
- <real_array name="tracks/5/keys" len="192"> 0, 1, 1.42842e-07, 1.93715e-07, 2.98023e-07, -0.0965851, -0.0177476, 0.000627753, 0.995166, 1, 1, 1, 0.05, 1, 4.62169e-08, -6.70552e-08, 6.55651e-07, -0.100604, -0.0182764, 0.000608928, 0.994758, 1, 1, 1, 0.1, 1, 8.12579e-08, 5.96046e-08, 5.36442e-07, -0.111195, -0.0196529, 0.000562433, 0.993604, 1, 1, 1, 0.15, 1, 3.0268e-08, -2.98023e-08, 5.96046e-07, -0.127055, -0.0217242, 0.000494295, 0.991658, 1, 1, 1, 0.45, 1, 1.55647e-07, 1.49012e-07, 4.76837e-07, -0.240017, -0.0376881, -3.78875e-05, 0.970037, 1, 1, 1, 0.5, 1, -1.23866e-07, 3.57628e-07, 7.7486e-07, -0.250826, -0.0393224, -9.00224e-05, 0.967233, 1, 1, 1, 0.55, 1, 5.34346e-08, 3.72529e-08, 5.96046e-07, -0.25762, -0.040368, -0.000123774, 0.965403, 1, 1, 1, 0.6, 1, 1.08266e-08, 5.96046e-08, 7.15256e-07, -0.260963, -0.0408854, -0.000140397, 0.964483, 1, 1, 1, 0.65, 1, 1.08266e-08, 5.96046e-08, 7.15256e-07, -0.260963, -0.0408854, -0.000140397, 0.964483, 1, 1, 1, 0.7, 1, 5.34346e-08, 3.72529e-08, 5.96046e-07, -0.25762, -0.040368, -0.000123775, 0.965403, 1, 1, 1, 0.75, 1, -1.23866e-07, 3.57628e-07, 7.7486e-07, -0.250826, -0.0393224, -9.00224e-05, 0.967233, 1, 1, 1, 0.8, 1, 1.55647e-07, 1.49012e-07, 4.76837e-07, -0.240017, -0.0376881, -3.78871e-05, 0.970037, 1, 1, 1, 0.9, 1, -4.8778e-08, -1.3411e-07, 7.15256e-07, -0.208519, -0.0330444, 0.00011266, 0.97746, 1, 1, 1, 1.15, 1, 8.12579e-08, 5.96046e-08, 5.36442e-07, -0.111195, -0.0196529, 0.000562432, 0.993604, 1, 1, 1, 1.2, 1, 4.62169e-08, -6.70552e-08, 6.55651e-07, -0.100605, -0.0182764, 0.000608928, 0.994758, 1, 1, 1, 1.25, 1, 1.42842e-07, 1.93715e-07, 2.98023e-07, -0.0965852, -0.0177476, 0.000627753, 0.995166, 1, 1, 1 </real_array>
- <string name="tracks/6/type"> "transform" </string>
- <node_path name="tracks/6/path"> "Armature/Skeleton:r-foot" </node_path>
- <int name="tracks/6/interp"> 1 </int>
- <real_array name="tracks/6/keys" len="180"> 0, 1, 8.9407e-08, 2.38419e-07, -2.23517e-08, 0.0349931, -0.0301778, 0.0362945, 0.998272, 1, 1, 1, 0.05, 1, 7.45058e-08, 2.38419e-07, 6.33299e-08, 0.0358993, -0.0301376, 0.0363473, 0.998239, 1, 1, 1, 0.1, 1, 5.21541e-08, 1.19209e-07, 2.98023e-08, 0.0384013, -0.0300263, 0.0364927, 0.998144, 1, 1, 1, 0.15, 1, 4.47035e-08, 1.19209e-07, -1.11759e-08, 0.0424549, -0.0298457, 0.0367279, 0.997977, 1, 1, 1, 0.5, 1, 5.21541e-08, 1.19209e-07, 7.45058e-09, 0.0873535, -0.0278095, 0.0392948, 0.995014, 1, 1, 1, 0.55, 1, -7.45058e-09, 0, -5.21541e-08, 0.0905253, -0.0276632, 0.0394735, 0.994727, 1, 1, 1, 0.6, 1, 2.98023e-08, 0, 2.23517e-08, 0.0921114, -0.0275899, 0.0395627, 0.99458, 1, 1, 1, 0.65, 1, 2.98023e-08, 0, 2.23517e-08, 0.0921114, -0.0275899, 0.0395627, 0.99458, 1, 1, 1, 0.7, 1, -7.45058e-09, 0, -5.21541e-08, 0.0905253, -0.0276632, 0.0394735, 0.994727, 1, 1, 1, 0.75, 1, 5.21541e-08, 1.19209e-07, 7.45058e-09, 0.0873535, -0.0278095, 0.0392948, 0.995014, 1, 1, 1, 0.8, 1, 1.04308e-07, 2.38419e-07, -1.49012e-08, 0.0824784, -0.0280337, 0.0390195, 0.995434, 1, 1, 1, 1.1, 1, 4.47035e-08, 1.19209e-07, -1.11759e-08, 0.0424549, -0.0298457, 0.0367279, 0.997977, 1, 1, 1, 1.15, 1, 5.21541e-08, 1.19209e-07, 2.98023e-08, 0.0384013, -0.0300263, 0.0364927, 0.998144, 1, 1, 1, 1.2, 1, 7.45058e-08, 2.38419e-07, 6.33299e-08, 0.0358993, -0.0301376, 0.0363473, 0.998239, 1, 1, 1, 1.25, 1, 8.9407e-08, 2.38419e-07, -2.23517e-08, 0.0349931, -0.0301778, 0.0362945, 0.998272, 1, 1, 1 </real_array>
- <string name="tracks/7/type"> "transform" </string>
- <node_path name="tracks/7/path"> "Armature/Skeleton:l-thigh" </node_path>
- <int name="tracks/7/interp"> 1 </int>
- <real_array name="tracks/7/keys" len="180"> 0, 1, 0, 6.70552e-08, -1.04308e-07, -0.0539995, 0.0696269, -0.0213643, 0.995881, 1, 0.999999, 1, 0.05, 1, 0, 6.70552e-08, -1.04308e-07, -0.05678, 0.0700343, -0.0212398, 0.995701, 1, 0.999999, 1, 0.1, 1, 0, 2.23517e-08, -1.04308e-07, -0.0641135, 0.0711039, -0.0209069, 0.995187, 1, 0.999999, 1, 0.15, 1, 0, 8.19564e-08, -1.04308e-07, -0.075114, 0.072736, -0.0204178, 0.994309, 1, 0.999999, 1, 0.45, 1, -2.98023e-08, 1.04308e-07, 1.04308e-07, -0.15432, 0.0862808, -0.0175308, 0.98409, 1, 0.999999, 1, 0.5, 1, -5.96046e-08, 2.98023e-08, 4.91738e-07, -0.162002, 0.0877689, -0.0172983, 0.982727, 1, 0.999999, 1, 0.55, 1, 0, 5.21541e-08, -1.04308e-07, -0.166843, 0.0887321, -0.0171591, 0.981833, 1, 0.999999, 1, 0.6, 1, -2.98023e-08, 4.47035e-08, 8.9407e-08, -0.169228, 0.0892116, -0.0170917, 0.981382, 1, 0.999999, 1, 0.65, 1, -2.98023e-08, 4.47035e-08, 8.9407e-08, -0.169228, 0.0892116, -0.0170917, 0.981382, 1, 0.999999, 1, 0.7, 1, 0, 5.21541e-08, -1.04308e-07, -0.166843, 0.0887321, -0.0171591, 0.981833, 1, 0.999999, 1, 0.75, 1, -5.96046e-08, 2.98023e-08, 4.91738e-07, -0.162002, 0.0877689, -0.0172983, 0.982727, 1, 0.999999, 1, 0.8, 1, -2.98023e-08, 1.04308e-07, 1.04308e-07, -0.15432, 0.0862808, -0.0175308, 0.98409, 1, 0.999999, 1, 1.15, 1, 0, 2.23517e-08, -1.04308e-07, -0.0641135, 0.0711039, -0.020907, 0.995187, 1, 0.999999, 1, 1.2, 1, 0, 6.70552e-08, -1.04308e-07, -0.05678, 0.0700343, -0.0212398, 0.995701, 1, 0.999999, 1, 1.25, 1, 0, 6.70552e-08, -1.04308e-07, -0.0539992, 0.0696269, -0.0213643, 0.995881, 1, 0.999999, 1 </real_array>
- <string name="tracks/8/type"> "transform" </string>
- <node_path name="tracks/8/path"> "Armature/Skeleton:l-leg" </node_path>
- <int name="tracks/8/interp"> 1 </int>
- <real_array name="tracks/8/keys" len="192"> 0, 1, 9.06875e-08, -8.19564e-08, 3.57628e-07, -0.0965913, 0.0177484, -0.00062776, 0.995166, 1, 1, 1, 0.05, 1, 3.44589e-08, -1.93715e-07, 2.98023e-07, -0.10061, 0.0182771, -0.000608941, 0.994758, 1, 1, 1, 0.1, 1, 2.52621e-08, -1.86265e-07, 5.96046e-08, -0.1112, 0.0196536, -0.000562456, 0.993604, 1, 1, 1, 0.15, 1, 9.02219e-08, -1.19209e-07, 1.19209e-07, -0.127061, 0.021725, -0.000494313, 0.991657, 1, 1, 1, 0.45, 1, 7.13626e-08, -5.21541e-08, 1.19209e-07, -0.24002, 0.0376883, 3.78708e-05, 0.970036, 1, 1, 1, 0.5, 1, -2.84053e-08, -1.78814e-07, -1.78814e-07, -0.250828, 0.0393224, 9.00085e-05, 0.967233, 1, 1, 1, 0.55, 1, 1.234e-08, 2.01166e-07, 1.78814e-07, -0.257623, 0.0403681, 0.000123756, 0.965402, 1, 1, 1, 0.6, 1, -9.97679e-08, 5.21541e-08, -5.96046e-08, -0.260966, 0.0408856, 0.000140381, 0.964482, 1, 1, 1, 0.65, 1, -9.97679e-08, 5.21541e-08, -5.96046e-08, -0.260966, 0.0408856, 0.000140381, 0.964482, 1, 1, 1, 0.7, 1, 1.234e-08, 2.01166e-07, 1.78814e-07, -0.257623, 0.0403681, 0.000123754, 0.965402, 1, 1, 1, 0.75, 1, -2.84053e-08, -1.78814e-07, -1.78814e-07, -0.250828, 0.0393224, 9.00085e-05, 0.967233, 1, 1, 1, 0.8, 1, 7.13626e-08, -5.21541e-08, 1.19209e-07, -0.24002, 0.0376883, 3.78693e-05, 0.970036, 1, 1, 1, 0.9, 1, 3.73693e-08, -5.21541e-08, 2.38419e-07, -0.208521, 0.0330446, -0.000112648, 0.977459, 1, 1, 1, 1.15, 1, 2.52621e-08, -1.86265e-07, 5.96046e-08, -0.1112, 0.0196536, -0.000562457, 0.993604, 1, 1, 1, 1.2, 1, 3.44589e-08, -1.93715e-07, 2.98023e-07, -0.10061, 0.0182771, -0.000608943, 0.994758, 1, 1, 1, 1.25, 1, 9.06875e-08, -8.19564e-08, 3.57628e-07, -0.0965911, 0.0177484, -0.000627765, 0.995166, 1, 1, 1 </real_array>
- <string name="tracks/9/type"> "transform" </string>
- <node_path name="tracks/9/path"> "Armature/Skeleton:l-foot" </node_path>
- <int name="tracks/9/interp"> 1 </int>
- <real_array name="tracks/9/keys" len="180"> 0, 1, -6.70552e-08, 0, -3.72529e-09, 0.0349931, 0.0301778, -0.0362945, 0.998272, 1, 1, 1, 0.05, 1, -1.49012e-08, 1.19209e-07, -7.45058e-09, 0.0358993, 0.0301376, -0.0363473, 0.998239, 1, 1, 1, 0.1, 1, 1.49012e-08, -1.19209e-07, 1.49012e-08, 0.0384013, 0.0300263, -0.0364927, 0.998144, 1, 1, 1, 0.15, 1, -4.47035e-08, 0, -3.72529e-09, 0.0424549, 0.0298457, -0.0367279, 0.997977, 1, 1, 1, 0.5, 1, 5.21541e-08, 0, -1.11759e-08, 0.0873535, 0.0278095, -0.0392948, 0.995014, 1, 1, 1, 0.55, 1, 4.47035e-08, 0, -2.98023e-08, 0.0905253, 0.0276632, -0.0394736, 0.994727, 1, 1, 1, 0.6, 1, 1.49012e-08, 0, -1.86265e-08, 0.0921114, 0.02759, -0.0395628, 0.99458, 1, 1, 1, 0.65, 1, 1.49012e-08, 0, -1.86265e-08, 0.0921114, 0.02759, -0.0395628, 0.99458, 1, 1, 1, 0.7, 1, 4.47035e-08, 0, -2.98023e-08, 0.0905253, 0.0276633, -0.0394736, 0.994727, 1, 1, 1, 0.75, 1, 5.21541e-08, 0, -1.11759e-08, 0.0873535, 0.0278095, -0.0392948, 0.995014, 1, 1, 1, 0.8, 1, -3.72529e-08, 1.19209e-07, -1.11759e-08, 0.0824784, 0.0280338, -0.0390195, 0.995434, 1, 1, 1, 1.1, 1, -4.47035e-08, 0, -3.72529e-09, 0.0424549, 0.0298457, -0.0367279, 0.997977, 1, 1, 1, 1.15, 1, 1.49012e-08, -1.19209e-07, 1.49012e-08, 0.0384013, 0.0300263, -0.0364927, 0.998144, 1, 1, 1, 1.2, 1, -1.49012e-08, 1.19209e-07, -7.45058e-09, 0.0358992, 0.0301376, -0.0363473, 0.998239, 1, 1, 1, 1.25, 1, -6.70552e-08, 0, -3.72529e-09, 0.0349931, 0.0301778, -0.0362945, 0.998272, 1, 1, 1 </real_array>
- <string name="tracks/10/type"> "transform" </string>
- <node_path name="tracks/10/path"> "Armature/Skeleton:MASTER" </node_path>
- <int name="tracks/10/interp"> 1 </int>
- <real_array name="tracks/10/keys" len="24"> 0, 1, 0, -0.322829, 2.42144e-08, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0, -0.322829, 2.42144e-08, 5.1658e-08, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/11/type"> "transform" </string>
- <node_path name="tracks/11/path"> "Armature/Skeleton:HEAD" </node_path>
- <int name="tracks/11/interp"> 1 </int>
- <real_array name="tracks/11/keys" len="24"> 0, 1, -5.68434e-14, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -5.68434e-14, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/12/type"> "transform" </string>
- <node_path name="tracks/12/path"> "Armature/Skeleton:r-LEGCONTROL" </node_path>
- <int name="tracks/12/interp"> 1 </int>
- <real_array name="tracks/12/keys" len="24"> 0, 1, 0.220288, -4.0302e-11, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.220288, -4.0302e-11, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/13/type"> "transform" </string>
- <node_path name="tracks/13/path"> "Armature/Skeleton:l-LEGCONTROL" </node_path>
- <int name="tracks/13/interp"> 1 </int>
- <real_array name="tracks/13/keys" len="24"> 0, 1, -0.220288, -4.0302e-11, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.220288, -4.0302e-11, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/14/type"> "transform" </string>
- <node_path name="tracks/14/path"> "Armature/Skeleton:r-LEGORIENT" </node_path>
- <int name="tracks/14/interp"> 1 </int>
- <real_array name="tracks/14/keys" len="24"> 0, 1, -0.183564, 0.0305941, 5.96046e-08, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.183564, 0.0305941, 5.96046e-08, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1 </real_array>
- <string name="tracks/15/type"> "transform" </string>
- <node_path name="tracks/15/path"> "Armature/Skeleton:l-LEGORIENT" </node_path>
- <int name="tracks/15/interp"> 1 </int>
- <real_array name="tracks/15/keys" len="24"> 0, 1, 0.183564, 0.030594, 5.96046e-08, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.183564, 0.030594, 5.96046e-08, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1 </real_array>
- <string name="tracks/16/type"> "transform" </string>
- <node_path name="tracks/16/path"> "Armature/Skeleton:r-ARMCONTROL" </node_path>
- <int name="tracks/16/interp"> 1 </int>
- <real_array name="tracks/16/keys" len="168"> 0, 1, -1.15243, -0.687477, 0.0713858, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -1.15504, -0.689394, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, -1.16214, -0.694617, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.15, 1, -1.17317, -0.702725, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.3, 1, -1.21295, -0.731968, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.35, 1, -1.22128, -0.738092, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, -1.2252, -0.740971, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, -1.22553, -0.741211, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.5, 1, -1.22422, -0.740253, 0.0713858, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, -1.22161, -0.73833, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.6, 1, -1.21787, -0.735585, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1.15, 1, -1.15488, -0.689275, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1.2, 1, -1.15308, -0.687955, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1.25, 1, -1.15243, -0.687477, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/17/type"> "transform" </string>
- <node_path name="tracks/17/path"> "Armature/Skeleton:l-ARMCONTROL" </node_path>
- <int name="tracks/17/interp"> 1 </int>
- <real_array name="tracks/17/keys" len="168"> 0, 1, 1.15243, -0.687477, 0.0713859, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 1.15504, -0.689394, 0.0713859, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, 1.16214, -0.694617, 0.0713859, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.15, 1, 1.17317, -0.702725, 0.0713859, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.3, 1, 1.21295, -0.731968, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.35, 1, 1.22128, -0.738092, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, 1.2252, -0.740971, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, 1.22553, -0.741211, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.5, 1, 1.22422, -0.740253, 0.0713858, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, 1.22161, -0.73833, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.6, 1, 1.21787, -0.735585, 0.0713858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1.15, 1, 1.15488, -0.689275, 0.0713859, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1.2, 1, 1.15308, -0.687955, 0.0713859, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1.25, 1, 1.15243, -0.687477, 0.0713859, -5.1658e-08, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/18/type"> "transform" </string>
- <node_path name="tracks/18/path"> "Armature/Skeleton:r-ARMORIENT" </node_path>
- <int name="tracks/18/interp"> 1 </int>
- <real_array name="tracks/18/keys" len="156"> 0, 1, 0.849557, -0.741664, 4.9468, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 0.849557, -0.741664, 4.93101, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, 0.849557, -0.741664, 4.88735, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.15, 1, 0.849557, -0.741664, 4.81599, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.2, 1, 0.849557, -0.741664, 4.71797, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.75, 1, 0.849557, -0.741664, 3.21234, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, 0.849557, -0.741664, 3.18081, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.85, 1, 0.849557, -0.741664, 3.18869, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.9, 1, 0.849557, -0.741664, 3.28296, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.95, 1, 0.849557, -0.741664, 3.48291, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1.15, 1, 0.849557, -0.741664, 4.70777, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1.2, 1, 0.849557, -0.741664, 4.88227, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.849557, -0.741664, 4.9468, -5.1658e-08, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/19/type"> "transform" </string>
- <node_path name="tracks/19/path"> "Armature/Skeleton:l-ARMORIENT" </node_path>
- <int name="tracks/19/interp"> 1 </int>
- <real_array name="tracks/19/keys" len="156"> 0, 1, -0.849557, -0.741664, 4.9468, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -0.849557, -0.741664, 4.93101, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, -0.849557, -0.741664, 4.88735, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.15, 1, -0.849557, -0.741664, 4.81599, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.2, 1, -0.849557, -0.741664, 4.71797, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.75, 1, -0.849557, -0.741664, 3.21234, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, -0.849557, -0.741664, 3.18081, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.85, 1, -0.849557, -0.741664, 3.18869, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.9, 1, -0.849557, -0.741664, 3.28296, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.95, 1, -0.849557, -0.741664, 3.48291, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1.15, 1, -0.849557, -0.741664, 4.70777, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1.2, 1, -0.849557, -0.741664, 4.88227, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.849557, -0.741664, 4.9468, -5.1658e-08, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/20/type"> "transform" </string>
- <node_path name="tracks/20/path"> "Armature/Skeleton:hip" </node_path>
- <int name="tracks/20/interp"> 1 </int>
- <real_array name="tracks/20/keys" len="180"> 0, 1, 1.11759e-08, 0.0713859, 0.0510914, 0, 0, 1.44945e-21, 1, 1, 1, 1, 0.05, 1, 1.11759e-08, 0.0713859, 0.0522077, -4.26326e-14, 4.23516e-22, 1.44945e-21, 1, 1, 1, 1, 0.1, 1, 1.11759e-08, 0.0713859, 0.05529, -5.68434e-14, 2.11758e-21, 1.44945e-21, 1, 1, 1, 1, 0.15, 1, 1.11759e-08, 0.0713859, 0.0602832, -4.26326e-14, 4.23516e-22, 1.44945e-21, 1, 1, 1, 1, 0.5, 1, 1.11759e-08, 0.0713859, 0.115648, 0, 0, 1.44945e-21, 1, 1, 1, 1, 0.55, 1, 1.11759e-08, 0.0713859, 0.119568, -4.26326e-14, 4.23516e-22, 1.44945e-21, 1, 1, 1, 1, 0.6, 1, 1.11759e-08, 0.0713859, 0.121528, -4.26326e-14, 4.23516e-22, 1.44945e-21, 1, 1, 1, 1, 0.65, 1, 1.11759e-08, 0.0713859, 0.121528, -4.26326e-14, 4.23516e-22, 1.44945e-21, 1, 1, 1, 1, 0.7, 1, 1.11759e-08, 0.0713859, 0.119568, -5.68434e-14, 2.11758e-21, 1.44945e-21, 1, 1, 1, 1, 0.75, 1, 1.11759e-08, 0.0713859, 0.115648, 0, 0, 1.44945e-21, 1, 1, 1, 1, 0.8, 1, 1.11759e-08, 0.0713859, 0.109626, -5.68434e-14, 2.11758e-21, 1.44945e-21, 1, 1, 1, 1, 1.1, 1, 1.11759e-08, 0.0713859, 0.0602832, -5.68434e-14, 2.11758e-21, 1.44945e-21, 1, 1, 1, 1, 1.15, 1, 1.11759e-08, 0.0713859, 0.05529, -4.26326e-14, 4.23516e-22, 1.44945e-21, 1, 1, 1, 1, 1.2, 1, 1.11759e-08, 0.0713859, 0.0522077, -2.84217e-14, -4.23516e-22, 1.44945e-21, 1, 1, 1, 1, 1.25, 1, 1.11759e-08, 0.0713859, 0.0510914, -4.26326e-14, 4.23516e-22, 1.44945e-21, 1, 1, 1, 1 </real_array>
- <string name="tracks/21/type"> "transform" </string>
- <node_path name="tracks/21/path"> "Armature/Skeleton:waist" </node_path>
- <int name="tracks/21/interp"> 1 </int>
- <real_array name="tracks/21/keys" len="168"> 0, 1, 5.71157e-15, -1.62345e-08, 8.9407e-08, 0, 0, 2.44616e-35, 1, 1, 1, 1, 0.05, 1, 5.75176e-15, -1.64873e-08, 8.9407e-08, 0.000214909, 1.42979e-18, -2.11758e-22, 1, 1, 1, 1, 0.1, 1, 4.06271e-15, -5.26452e-09, 8.9407e-08, 0.000808293, -3.04932e-19, 2.465e-22, 1, 1, 1, 1, 0.15, 1, 1.54246e-15, 1.14859e-08, 8.9407e-08, 0.00176961, 6.63395e-18, -1.17394e-20, 0.999998, 1, 1, 1, 0.5, 1, 4.42376e-15, -1.05373e-09, -2.98023e-08, 0.0124283, 2.20213e-20, -2.77954e-22, 0.999923, 1, 1, 1, 0.55, 1, 4.56489e-15, -1.94163e-09, 8.9407e-08, 0.0131829, 1.00996e-17, -7.10618e-15, 0.999913, 1, 1, 1, 0.65, 1, 1.79332e-15, -2.38573e-09, 8.9407e-08, 0.0135603, 1.03769e-16, -1.40726e-18, 0.999908, 1, 1, 1, 0.7, 1, 4.56489e-15, -1.94163e-09, 8.9407e-08, 0.0131829, -1.18256e-16, 1.5591e-18, 0.999913, 1, 1, 1, 0.75, 1, 4.42376e-15, -1.05373e-09, -2.98023e-08, 0.0124282, 2.20246e-20, -2.77954e-22, 0.999923, 1, 1, 1, 0.8, 1, 4.20699e-15, 3.1009e-10, -2.98023e-08, 0.011269, -6.2751e-17, 7.07106e-19, 0.999937, 1, 1, 1, 1.1, 1, 1.54246e-15, 1.14859e-08, 8.9407e-08, 0.00176961, 7.93788e-18, -7.10545e-15, 0.999998, 1, 1, 1, 1.15, 1, 4.06271e-15, -5.26452e-09, 8.9407e-08, 0.000808293, -3.04932e-19, 2.465e-22, 1, 1, 1, 1, 1.2, 1, 5.75176e-15, -1.64874e-08, 8.9407e-08, 0.00021491, -2.03966e-18, 4.23517e-22, 1, 1, 1, 1, 1.25, 1, 5.71157e-15, -1.62345e-08, 8.9407e-08, 3.83187e-10, 0, 1.22308e-35, 1, 1, 1, 1 </real_array>
- <string name="tracks/22/type"> "transform" </string>
- <node_path name="tracks/22/path"> "Armature/Skeleton:chest" </node_path>
- <int name="tracks/22/interp"> 1 </int>
- <real_array name="tracks/22/keys" len="156"> 0, 1, 7.24544e-18, 1.86265e-08, 5.96046e-08, 0, 0, -1.33383e-23, 1, 1, 1, 1, 0.05, 1, -3.76414e-18, 3.72529e-09, 0, 0.00110099, -2.41201e-19, -1.97577e-17, 0.999999, 1, 1, 1, 0.1, 1, 9.18675e-18, 1.49012e-08, -1.19209e-07, 0.00410119, -8.96205e-19, -7.35977e-17, 0.999992, 1, 1, 1, 0.15, 1, 1.76552e-17, 7.45058e-09, -5.96046e-08, 0.00875896, -1.91283e-18, -1.57184e-16, 0.999962, 1, 1, 1, 0.3, 1, 1.31081e-17, -1.11759e-08, 0, 0.0255569, -5.58266e-18, -4.58633e-16, 0.999673, 1, 1, 1, 0.35, 1, 1.99653e-17, -1.49012e-08, -5.96046e-08, 0.0290738, -6.35135e-18, -5.21745e-16, 0.999577, 1, 1, 1, 0.4, 1, 1.92772e-17, 1.11759e-08, 1.19209e-07, 0.0307265, -6.71273e-18, -5.51404e-16, 0.999528, 1, 1, 1, 0.5, 1, 4.47552e-17, 1.11759e-08, 5.96046e-08, 0.0303143, -6.6203e-18, -5.44008e-16, 0.99954, 1, 1, 1, 0.55, 1, 1.08083e-17, 2.23517e-08, -5.96046e-08, 0.0292103, -6.38065e-18, -5.24195e-16, 0.999573, 1, 1, 1, 0.6, 1, -3.34373e-18, -1.11759e-08, -2.98023e-07, 0.0276344, -6.03606e-18, -4.95914e-16, 0.999618, 1, 1, 1, 1.15, 1, 9.18674e-18, 1.49012e-08, -1.19209e-07, 0.0010327, -2.26125e-19, -1.85323e-17, 0.999999, 1, 1, 1, 1.2, 1, -3.7641e-18, 0, 0, 0.000274137, -6.02241e-20, -4.91966e-18, 1, 1, 1, 1, 1.25, 1, 7.24539e-18, 1.86265e-08, 5.96046e-08, 0, 0, 1.31315e-23, 1, 1, 1, 1 </real_array>
- <string name="tracks/23/type"> "transform" </string>
- <node_path name="tracks/23/path"> "Armature/Skeleton:neck" </node_path>
- <int name="tracks/23/interp"> 1 </int>
- <real_array name="tracks/23/keys" len="24"> 0, 1, -1.13687e-13, -1.49012e-08, -3.57628e-07, 1.17383e-27, 2.13163e-14, 5.50671e-14, 1, 1, 1, 1, 1.25, 1, -1.13687e-13, -1.49012e-08, -3.57628e-07, -2.46125e-27, 2.13163e-14, -1.77636e-15, 1, 1, 1, 1 </real_array>
- <string name="tracks/24/type"> "transform" </string>
- <node_path name="tracks/24/path"> "Armature/Skeleton:headtracker" </node_path>
- <int name="tracks/24/interp"> 1 </int>
- <real_array name="tracks/24/keys" len="180"> 0, 1, -2.16716e-13, 2.38419e-07, -1.20141e-07, 0.00540576, -3.97061e-09, 4.73012e-08, 0.999985, 1, 1, 1, 0.05, 1, 1.42109e-14, -6.85453e-07, -5.96046e-08, 0.00687155, -3.90174e-09, 4.73059e-08, 0.999976, 1, 1, 1, 0.1, 1, -1.06581e-13, -3.57628e-07, 4.65661e-09, 0.0108835, -3.7136e-09, 4.73184e-08, 0.999941, 1, 1, 1, 0.15, 1, 2.4869e-14, -7.15256e-07, -2.79397e-09, 0.0171898, -3.41769e-09, 4.73365e-08, 0.999852, 1, 1, 1, 0.35, 1, 5.68434e-14, -4.76837e-07, -2.16532e-08, 0.0482761, -1.95634e-09, 4.7399e-08, 0.998834, 1, 1, 1, 0.4, 1, 1.3145e-13, -4.76837e-07, 1.39698e-08, 0.0525864, -1.75345e-09, 4.74044e-08, 0.998616, 1, 1, 1, 0.45, 1, -7.10543e-15, -2.98023e-07, -2.23517e-08, 0.0549628, -1.64161e-09, 4.74072e-08, 0.998488, 1, 1, 1, 0.5, 1, 8.88178e-14, -4.47035e-07, -5.75092e-08, 0.056151, -1.58539e-09, 4.74086e-08, 0.998422, 1, 1, 1, 0.55, 1, -1.06581e-14, -7.15256e-07, -1.09896e-07, 0.0561279, -1.58659e-09, 4.74089e-08, 0.998424, 1, 1, 1, 0.6, 1, 1.49214e-13, -5.36442e-07, 8.3819e-09, 0.0550227, -1.63855e-09, 4.74081e-08, 0.998485, 1, 1, 1, 0.65, 1, 1.42109e-13, -5.66244e-07, -2.72412e-08, 0.0528693, -1.73995e-09, 4.74061e-08, 0.998601, 1, 1, 1, 0.7, 1, 1.27898e-13, -9.83477e-07, 2.23517e-08, 0.0497256, -1.88791e-09, 4.74026e-08, 0.998763, 1, 1, 1, 1.15, 1, 4.61853e-14, -2.68221e-07, -1.44821e-07, 0.00768525, -3.86364e-09, 4.73087e-08, 0.99997, 1, 1, 1, 1.2, 1, -4.61853e-14, -2.38419e-07, -9.12696e-08, 0.00601107, -3.94226e-09, 4.73032e-08, 0.999982, 1, 1, 1, 1.25, 1, -2.16716e-13, 2.38419e-07, -1.20141e-07, 0.00540581, -3.97061e-09, 4.73011e-08, 0.999985, 1, 1, 1 </real_array>
- <string name="tracks/25/type"> "transform" </string>
- <node_path name="tracks/25/path"> "Armature/Skeleton:head" </node_path>
- <int name="tracks/25/interp"> 1 </int>
- <real_array name="tracks/25/keys" len="156"> 0, 1, -1.11494e-13, -1.15717e-07, -2.08616e-07, 7.45058e-09, 8.88178e-15, 0, 1, 1, 1, 1, 0.05, 1, 1.80868e-10, 1.36495e-05, 0.000901487, 1.49012e-08, 1.77636e-14, -2.13163e-14, 1, 1, 1, 1, 0.1, 1, 6.8149e-10, 5.12244e-05, 0.00339634, 7.45058e-09, 1.77636e-15, -2.13163e-14, 1, 1, 1, 1, 0.15, 1, 1.5005e-09, 0.00011289, 0.00747763, 7.45058e-09, 7.10543e-15, -7.10543e-15, 1, 1, 1, 1, 0.2, 1, 2.6273e-09, 0.000197746, 0.0130927, 7.45058e-09, -5.32907e-15, 7.10543e-15, 1, 1, 1, 1, 0.75, 1, 2.00072e-08, 0.00150619, 0.0996987, 7.45058e-09, 3.55271e-15, -1.42109e-14, 1, 1, 1, 1, 0.8, 1, 2.03706e-08, 0.00153358, 0.10151, 1.49012e-08, 3.55271e-15, -1.42109e-14, 1, 1, 1, 1, 0.85, 1, 2.02794e-08, 0.00152671, 0.101055, 1.49012e-08, -5.32907e-15, 7.10543e-15, 1, 1, 1, 1, 0.9, 1, 1.91881e-08, 0.00144463, 0.0956172, 7.45058e-09, -7.10543e-15, 0, 1, 1, 1, 1, 0.95, 1, 1.68664e-08, 0.00126975, 0.084048, 1.49012e-08, 1.77636e-15, -2.13163e-14, 1, 1, 1, 1, 1.15, 1, 2.70661e-09, 0.000203704, 0.0134885, 7.45058e-09, -5.32907e-15, 7.10543e-15, 1, 1, 1, 1, 1.2, 1, 7.26606e-10, 5.46668e-05, 0.00362133, 7.45058e-09, 2.13163e-14, -1.42109e-14, 1, 1, 1, 1, 1.25, 1, -1.10217e-13, -1.15717e-07, -2.02097e-07, 7.45058e-09, -5.32907e-15, 7.10543e-15, 1, 1, 1, 1 </real_array>
- <string name="tracks/26/type"> "transform" </string>
- <node_path name="tracks/26/path"> "Armature/Skeleton:vent" </node_path>
- <int name="tracks/26/interp"> 1 </int>
- <real_array name="tracks/26/keys" len="24"> 0, 1, 4.48581e-08, 0.00292328, 0.204329, 1.04774e-09, -4.44089e-15, 5.58928e-15, 1, 1, 1, 1, 1.25, 1, 4.48581e-08, 0.00292328, 0.204329, 1.74623e-09, -6.21725e-15, 3.40058e-14, 1, 1, 1, 1 </real_array>
-
- </resource>
- <resource type="Animation" path="local://8">
- <string name="resource/name"> "shooting" </string>
- <real name="length"> 0.416667 </real>
- <bool name="loop"> False </bool>
- <real name="step"> 0.1 </real>
- <string name="tracks/0/type"> "transform" </string>
- <node_path name="tracks/0/path"> "Armature/Skeleton:r-arm" </node_path>
- <int name="tracks/0/interp"> 1 </int>
- <real_array name="tracks/0/keys" len="108"> 0, 1, 2.98023e-07, 3.57628e-07, 2.38419e-07, 0.177354, -0.316176, -0.0334956, 0.931373, 1, 1, 1, 0.05, 1, 5.36442e-07, -1.19209e-07, 5.06639e-07, 0.188185, -0.332103, -0.0311768, 0.923754, 1, 1, 1, 0.1, 1, 7.15256e-07, -3.57628e-07, 5.66244e-07, 0.204001, -0.354515, -0.0276657, 0.912106, 1, 1, 1, 0.15, 1, 6.25849e-07, -1.19209e-07, 4.76837e-07, 0.207621, -0.359465, -0.0268362, 0.909372, 1, 1, 1, 0.2, 1, 4.47035e-07, -1.19209e-07, 4.76837e-07, 0.203765, -0.354216, -0.0277227, 0.912273, 1, 1, 1, 0.35, 1, 6.85453e-07, -3.57628e-07, 5.36442e-07, 0.181322, -0.322103, -0.0326568, 0.928604, 1, 1, 1, 0.4, 1, 5.36442e-07, -1.19209e-07, 4.76837e-07, 0.177926, -0.317037, -0.0333752, 0.930976, 1, 1, 1, 0.45, 1, 2.98023e-07, 3.57628e-07, 2.38419e-07, 0.177354, -0.316176, -0.0334956, 0.931373, 1, 1, 1, 1.25, 1, 2.98023e-07, 3.57628e-07, 2.38419e-07, 0.177354, -0.316176, -0.0334956, 0.931373, 1, 1, 1 </real_array>
- <string name="tracks/1/type"> "transform" </string>
- <node_path name="tracks/1/path"> "Armature/Skeleton:r-forearm" </node_path>
- <int name="tracks/1/interp"> 1 </int>
- <real_array name="tracks/1/keys" len="108"> 0, 1, -4.47035e-07, -2.98023e-07, 0, 0.00444313, -0.215306, 0.0125622, 0.976456, 1, 1, 1, 0.05, 1, -2.08616e-07, -4.17233e-07, -2.98023e-07, 0.00305205, -0.21031, 0.0121764, 0.977554, 1, 1, 1, 0.1, 1, 2.08616e-07, -3.57628e-07, -3.57628e-07, 0.000634907, -0.201765, 0.0115128, 0.979366, 1, 0.999999, 1, 0.15, 1, 1.19209e-07, -1.19209e-07, -4.17233e-07, 2.2336e-05, -0.199561, 0.0113313, 0.97982, 1, 1, 1, 0.2, 1, 2.98023e-07, -8.9407e-08, -4.17233e-07, 0.000688273, -0.201948, 0.0115275, 0.979328, 1, 1, 1, 0.3, 1, -1.78814e-07, -2.68221e-07, -5.96046e-08, 0.00309916, -0.210458, 0.0121876, 0.977522, 1, 1, 1, 0.35, 1, 2.98023e-07, -5.96046e-07, -4.17233e-07, 0.00397812, -0.213611, 0.0124303, 0.976832, 1, 1, 1, 0.4, 1, -2.68221e-07, -4.47035e-07, -1.78814e-07, 0.00437828, -0.215068, 0.0125436, 0.976509, 1, 1, 1, 1.25, 1, -4.47035e-07, -2.98023e-07, 0, 0.00444313, -0.215306, 0.0125622, 0.976456, 1, 1, 1 </real_array>
- <string name="tracks/2/type"> "transform" </string>
- <node_path name="tracks/2/path"> "Armature/Skeleton:l-arm" </node_path>
- <int name="tracks/2/interp"> 1 </int>
- <real_array name="tracks/2/keys" len="108"> 0, 1, -5.66244e-07, 0, 2.68221e-07, -0.666114, -0.365882, 0.129948, 0.636817, 1, 1, 1, 0.05, 1, -5.96046e-07, -4.76837e-07, 4.76837e-07, -0.656623, -0.392941, 0.132853, 0.629916, 1, 1, 0.999999, 0.1, 1, -1.04308e-06, -5.96046e-07, 7.45058e-07, -0.641339, -0.431274, 0.137762, 0.619442, 1, 1, 1, 0.15, 1, -1.04308e-06, -7.15256e-07, 8.9407e-07, -0.637616, -0.439805, 0.139013, 0.617003, 1, 1, 0.999999, 0.2, 1, 2.98023e-08, 0, 3.27826e-07, -0.641587, -0.430741, 0.137654, 0.61958, 1, 1, 0.999999, 0.35, 1, -2.38419e-07, -3.57628e-07, 1.49012e-07, -0.662747, -0.375915, 0.130927, 0.634281, 1, 1, 0.999999, 0.4, 1, -5.66244e-07, -1.19209e-07, 3.57628e-07, -0.665636, -0.367338, 0.130084, 0.636451, 1, 1, 1, 0.45, 1, -5.66244e-07, 0, 2.68221e-07, -0.666114, -0.365882, 0.129948, 0.636817, 1, 1, 1, 1.25, 1, -5.66244e-07, 0, 2.68221e-07, -0.666114, -0.365882, 0.129948, 0.636817, 1, 1, 1 </real_array>
- <string name="tracks/3/type"> "transform" </string>
- <node_path name="tracks/3/path"> "Armature/Skeleton:l-forearm" </node_path>
- <int name="tracks/3/interp"> 1 </int>
- <real_array name="tracks/3/keys" len="108"> 0, 1, 2.98023e-08, -5.96046e-07, -4.17233e-07, -0.130784, -0.271804, -0.0853016, 0.949601, 1.3, 1.3, 1.3, 0.05, 1, 1.49012e-07, -6.55651e-07, -5.96046e-07, -0.133062, -0.270527, -0.0774246, 0.950324, 1.3, 1.3, 1.3, 0.1, 1, 2.68221e-07, -5.96046e-07, -2.38419e-07, -0.136329, -0.26867, -0.0661281, 0.95124, 1.3, 1.3, 1.3, 0.15, 1, -8.9407e-08, -8.04663e-07, -7.15256e-07, -0.137063, -0.26825, -0.0635932, 0.951426, 1.3, 1.3, 1.3, 0.2, 1, -8.9407e-08, -6.85453e-07, -7.15256e-07, -0.136283, -0.268695, -0.0662837, 0.951229, 1.3, 1.3, 1.3, 0.35, 1, -1.78814e-07, -5.66244e-07, -4.76837e-07, -0.131626, -0.271333, -0.0823877, 0.949876, 1.3, 1.3, 1.3, 0.4, 1, 5.96046e-08, -5.96046e-07, -3.57628e-07, -0.130906, -0.271736, -0.0848797, 0.949641, 1.3, 1.3, 1.3, 0.45, 1, 2.98023e-08, -5.96046e-07, -4.17233e-07, -0.130784, -0.271804, -0.0853016, 0.949601, 1.3, 1.3, 1.3, 1.25, 1, 2.98023e-08, -5.96046e-07, -4.17233e-07, -0.130784, -0.271804, -0.0853016, 0.949601, 1.3, 1.3, 1.3 </real_array>
- <string name="tracks/4/type"> "transform" </string>
- <node_path name="tracks/4/path"> "Armature/Skeleton:r-thigh" </node_path>
- <int name="tracks/4/interp"> 1 </int>
- <real_array name="tracks/4/keys" len="24"> 0, 1, 0, 1.63913e-07, 1.93715e-07, -0.283345, 0.0300071, -0.0426225, 0.957601, 1, 1, 1, 1.25, 1, 0, 1.63913e-07, 1.93715e-07, -0.283345, 0.0300071, -0.0426225, 0.957601, 1, 1, 1 </real_array>
- <string name="tracks/5/type"> "transform" </string>
- <node_path name="tracks/5/path"> "Armature/Skeleton:r-leg" </node_path>
- <int name="tracks/5/interp"> 1 </int>
- <real_array name="tracks/5/keys" len="24"> 0, 1, 2.29338e-08, 8.9407e-08, 5.36442e-07, -0.369097, -0.0505305, 0.00260278, 0.928013, 1, 1, 1, 1.25, 1, 2.29338e-08, 8.9407e-08, 5.36442e-07, -0.369097, -0.0505305, 0.00260278, 0.928013, 1, 1, 1 </real_array>
- <string name="tracks/6/type"> "transform" </string>
- <node_path name="tracks/6/path"> "Armature/Skeleton:r-foot" </node_path>
- <int name="tracks/6/interp"> 1 </int>
- <real_array name="tracks/6/keys" len="24"> 0, 1, 1.49012e-08, 0, -5.21541e-08, 0.163945, 0.140221, -0.046324, 0.975354, 1, 1, 1, 1.25, 1, 1.49012e-08, 0, -5.21541e-08, 0.163945, 0.140221, -0.046324, 0.975354, 1, 1, 1 </real_array>
- <string name="tracks/7/type"> "transform" </string>
- <node_path name="tracks/7/path"> "Armature/Skeleton:l-thigh" </node_path>
- <int name="tracks/7/interp"> 1 </int>
- <real_array name="tracks/7/keys" len="24"> 0, 1, 0, 2.08616e-07, 1.49012e-08, 0.284249, 0.0874448, 0.000525696, 0.954754, 1, 1, 1, 1.25, 1, 0, 2.08616e-07, 1.49012e-08, 0.284249, 0.0874448, 0.000525696, 0.954754, 1, 1, 1 </real_array>
- <string name="tracks/8/type"> "transform" </string>
- <node_path name="tracks/8/path"> "Armature/Skeleton:l-leg" </node_path>
- <int name="tracks/8/interp"> 1 </int>
- <real_array name="tracks/8/keys" len="24"> 0, 1, -6.98492e-10, -2.98023e-08, 4.76837e-07, -0.32359, -0.0556479, 0.000232734, 0.94456, 1, 1, 1, 1.25, 1, -6.98492e-10, -2.98023e-08, 4.76837e-07, -0.32359, -0.0556479, 0.000232734, 0.94456, 1, 1, 1 </real_array>
- <string name="tracks/9/type"> "transform" </string>
- <node_path name="tracks/9/path"> "Armature/Skeleton:l-foot" </node_path>
- <int name="tracks/9/interp"> 1 </int>
- <real_array name="tracks/9/keys" len="24"> 0, 1, 2.23517e-08, 1.19209e-07, 7.45058e-09, -0.260411, 0.0677016, 0.0123204, 0.963042, 1, 1, 1, 1.25, 1, 2.23517e-08, 1.19209e-07, 7.45058e-09, -0.260411, 0.0677016, 0.0123204, 0.963042, 1, 1, 1 </real_array>
- <string name="tracks/10/type"> "transform" </string>
- <node_path name="tracks/10/path"> "Armature/Skeleton:MASTER" </node_path>
- <int name="tracks/10/interp"> 1 </int>
- <real_array name="tracks/10/keys" len="24"> 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/11/type"> "transform" </string>
- <node_path name="tracks/11/path"> "Armature/Skeleton:HEAD" </node_path>
- <int name="tracks/11/interp"> 1 </int>
- <real_array name="tracks/11/keys" len="24"> 0, 1, -5.68434e-14, 0, 0.994808, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -5.68434e-14, 0, 0.994808, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/12/type"> "transform" </string>
- <node_path name="tracks/12/path"> "Armature/Skeleton:r-LEGCONTROL" </node_path>
- <int name="tracks/12/interp"> 1 </int>
- <real_array name="tracks/12/keys" len="24"> 0, 1, -0.142338, -0.593751, 0.041427, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.142338, -0.593751, 0.041427, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/13/type"> "transform" </string>
- <node_path name="tracks/13/path"> "Armature/Skeleton:l-LEGCONTROL" </node_path>
- <int name="tracks/13/interp"> 1 </int>
- <real_array name="tracks/13/keys" len="24"> 0, 1, 0.133965, 1.12742, 1.35169, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.133965, 1.12742, 1.35169, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/14/type"> "transform" </string>
- <node_path name="tracks/14/path"> "Armature/Skeleton:r-LEGORIENT" </node_path>
- <int name="tracks/14/interp"> 1 </int>
- <real_array name="tracks/14/keys" len="24"> 0, 1, 0.100474, 0.669825, -0.778672, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.100474, 0.669825, -0.778672, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/15/type"> "transform" </string>
- <node_path name="tracks/15/path"> "Armature/Skeleton:l-LEGORIENT" </node_path>
- <int name="tracks/15/interp"> 1 </int>
- <real_array name="tracks/15/keys" len="24"> 0, 1, -0.0204011, -0.122407, 5.96046e-08, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.0204011, -0.122407, 5.96046e-08, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/16/type"> "transform" </string>
- <node_path name="tracks/16/path"> "Armature/Skeleton:r-ARMCONTROL" </node_path>
- <int name="tracks/16/interp"> 1 </int>
- <real_array name="tracks/16/keys" len="24"> 0, 1, -0.868295, 0.288818, -0.834593, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.868295, 0.288818, -0.834593, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/17/type"> "transform" </string>
- <node_path name="tracks/17/path"> "Armature/Skeleton:l-ARMCONTROL" </node_path>
- <int name="tracks/17/interp"> 1 </int>
- <real_array name="tracks/17/keys" len="24"> 0, 1, 1.73339, 0.895247, 5.13844, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 1.73339, 0.895247, 5.13844, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/18/type"> "transform" </string>
- <node_path name="tracks/18/path"> "Armature/Skeleton:r-ARMORIENT" </node_path>
- <int name="tracks/18/interp"> 1 </int>
- <real_array name="tracks/18/keys" len="24"> 0, 1, 0.405204, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.405204, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/19/type"> "transform" </string>
- <node_path name="tracks/19/path"> "Armature/Skeleton:l-ARMORIENT" </node_path>
- <int name="tracks/19/interp"> 1 </int>
- <real_array name="tracks/19/keys" len="24"> 0, 1, -1.5774, 0.0723579, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -1.5774, 0.0723579, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/20/type"> "transform" </string>
- <node_path name="tracks/20/path"> "Armature/Skeleton:hip" </node_path>
- <int name="tracks/20/interp"> 1 </int>
- <real_array name="tracks/20/keys" len="24"> 0, 1, 0.050238, 0.697428, 0.108012, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1, 1.25, 1, 0.050238, 0.697428, 0.108012, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1 </real_array>
- <string name="tracks/21/type"> "transform" </string>
- <node_path name="tracks/21/path"> "Armature/Skeleton:waist" </node_path>
- <int name="tracks/21/interp"> 1 </int>
- <real_array name="tracks/21/keys" len="24"> 0, 1, 7.45059e-09, -5.21541e-08, 2.38419e-07, 0.0550011, -0.00481196, -0.0870228, 0.994675, 1, 1, 1, 1.25, 1, 7.45059e-09, -5.21541e-08, 2.38419e-07, 0.0550011, -0.00481196, -0.0870228, 0.994675, 1, 1, 1 </real_array>
- <string name="tracks/22/type"> "transform" </string>
- <node_path name="tracks/22/path"> "Armature/Skeleton:chest" </node_path>
- <int name="tracks/22/interp"> 1 </int>
- <real_array name="tracks/22/keys" len="108"> 0, 1, -1.93979e-09, 3.72529e-08, -1.78814e-07, 4.95597e-09, 0.00666624, -0.163159, 0.986577, 1, 1, 1, 0.05, 1, -1.93979e-09, 3.72529e-08, -1.78814e-07, -0.00988221, 0.00482982, -0.145309, 0.989325, 1, 1, 1, 0.1, 1, -1.93979e-09, 3.72529e-08, -1.78814e-07, -0.0244913, 0.00210965, -0.118794, 0.992615, 1, 1, 1, 0.15, 1, -1.93979e-09, 3.72529e-08, -1.78814e-07, -0.0278586, 0.00148179, -0.112662, 0.993242, 1, 1, 1, 0.2, 1, -1.93979e-09, 3.72529e-08, -1.78814e-07, -0.0242687, 0.00215113, -0.1192, 0.992571, 1, 1, 1, 0.35, 1, -1.93979e-09, 3.72529e-08, -1.78814e-07, -0.00360581, 0.00599648, -0.156654, 0.987629, 1, 1, 1, 0.4, 1, -1.93979e-09, 3.72529e-08, -1.78814e-07, -0.000519651, 0.00656974, -0.162222, 0.986732, 1, 1, 1, 0.45, 1, -1.93979e-09, 3.72529e-08, -1.78814e-07, 4.95597e-09, 0.00666624, -0.163159, 0.986577, 1, 1, 1, 1.25, 1, -1.93979e-09, 3.72529e-08, -1.78814e-07, 4.95597e-09, 0.00666624, -0.163159, 0.986577, 1, 1, 1 </real_array>
- <string name="tracks/23/type"> "transform" </string>
- <node_path name="tracks/23/path"> "Armature/Skeleton:neck" </node_path>
- <int name="tracks/23/interp"> 1 </int>
- <real_array name="tracks/23/keys" len="24"> 0, 1, -2.91038e-08, -1.78814e-07, -9.53674e-07, -7.45058e-09, 2.57076e-09, -2.87348e-09, 1, 1, 1, 1, 1.25, 1, -2.91038e-08, -1.78814e-07, -9.53674e-07, -7.45058e-09, 2.57076e-09, -2.87348e-09, 1, 1, 1, 1 </real_array>
- <string name="tracks/24/type"> "transform" </string>
- <node_path name="tracks/24/path"> "Armature/Skeleton:headtracker" </node_path>
- <int name="tracks/24/interp"> 1 </int>
- <real_array name="tracks/24/keys" len="108"> 0, 1, 1.05648e-08, -8.34465e-07, 8.61473e-09, 0.067043, -0.15676, 0.0458898, 0.984289, 1, 1, 1, 0.05, 1, -2.68221e-08, -7.7486e-07, -7.12462e-08, 0.0563978, -0.14039, 0.0396845, 0.987692, 1, 1, 1, 0.1, 1, 2.66356e-08, -1.78814e-07, -1.87429e-07, 0.0407343, -0.116242, 0.0305639, 0.991915, 1, 1, 1, 0.15, 1, -1.30386e-08, -3.57628e-07, -7.72998e-08, 0.0371396, -0.110688, 0.0284725, 0.992753, 1, 1, 1, 0.2, 1, 2.57045e-08, -5.96046e-07, -9.05711e-08, 0.0409678, -0.116604, 0.0306994, 0.991858, 1, 1, 1, 0.35, 1, 4.0076e-08, -1.78814e-07, -5.26197e-08, 0.0631478, -0.150775, 0.0436179, 0.985584, 1, 1, 1, 0.4, 1, 3.32831e-08, -5.36442e-07, 3.95812e-09, 0.0664811, -0.155897, 0.045562, 0.98448, 1, 1, 1, 0.45, 1, 1.05648e-08, -8.34465e-07, 8.61473e-09, 0.067043, -0.15676, 0.0458898, 0.984289, 1, 1, 1, 1.25, 1, 1.05648e-08, -8.34465e-07, 8.61473e-09, 0.067043, -0.15676, 0.0458898, 0.984289, 1, 1, 1 </real_array>
- <string name="tracks/25/type"> "transform" </string>
- <node_path name="tracks/25/path"> "Armature/Skeleton:head" </node_path>
- <int name="tracks/25/interp"> 1 </int>
- <real_array name="tracks/25/keys" len="24"> 0, 1, -7.38021e-13, 4.70318e-08, 9.16189e-08, -1.036e-25, -3.37508e-14, -8.17124e-13, 1, 1, 1, 1, 1.25, 1, -7.38021e-13, 4.70318e-08, 9.16189e-08, -1.036e-25, -3.37508e-14, -8.17124e-13, 1, 1, 1, 1 </real_array>
- <string name="tracks/26/type"> "transform" </string>
- <node_path name="tracks/26/path"> "Armature/Skeleton:vent" </node_path>
- <int name="tracks/26/interp"> 1 </int>
- <real_array name="tracks/26/keys" len="24"> 0, 1, 4.48982e-08, 0.00292331, 0.204329, 8.84756e-09, -3.8014e-13, 5.94471e-12, 1, 1, 1, 1, 1.25, 1, 4.48982e-08, 0.00292331, 0.204329, 8.84756e-09, -3.8014e-13, 5.94471e-12, 1, 1, 1, 1 </real_array>
-
- </resource>
- <resource type="Animation" path="local://9">
- <string name="resource/name"> "jump-up-cycle" </string>
- <real name="length"> 0.416667 </real>
- <bool name="loop"> True </bool>
- <real name="step"> 0.1 </real>
- <string name="tracks/0/type"> "transform" </string>
- <node_path name="tracks/0/path"> "Armature/Skeleton:r-arm" </node_path>
- <int name="tracks/0/interp"> 1 </int>
- <real_array name="tracks/0/keys" len="120"> 0, 1, 6.55651e-07, -3.57628e-07, 5.66244e-07, 0.208387, -0.176945, -0.0164982, 0.961766, 1, 1, 1, 0.05, 1, 6.85453e-07, -2.38419e-07, 4.17233e-07, 0.211256, -0.175803, -0.0179009, 0.961324, 1, 1, 1, 0.1, 1, 6.55651e-07, -2.38419e-07, 3.27826e-07, 0.216682, -0.174684, -0.0207438, 0.960263, 1, 1, 1, 0.15, 1, 6.25849e-07, -3.57628e-07, 6.25849e-07, 0.219812, -0.176984, -0.0232576, 0.959072, 1, 1, 1, 0.25, 1, 1.3113e-06, -9.53674e-07, 9.23872e-07, 0.223631, -0.219998, -0.0262768, 0.949157, 1, 1, 1, 0.3, 1, 8.9407e-07, -4.76837e-07, 6.85453e-07, 0.220416, -0.21329, -0.0232336, 0.951517, 1, 1, 1, 0.35, 1, 8.34465e-07, -3.57628e-07, 6.25849e-07, 0.214429, -0.195082, -0.0193009, 0.956865, 1, 1, 1, 0.4, 1, 8.34465e-07, -3.57628e-07, 6.25849e-07, 0.209436, -0.180062, -0.0169379, 0.960951, 1, 1, 1, 0.45, 1, 6.55651e-07, -3.57628e-07, 5.66244e-07, 0.208387, -0.176945, -0.0164982, 0.961766, 1, 1, 1, 1.25, 1, 6.55651e-07, -3.57628e-07, 5.66244e-07, 0.208387, -0.176945, -0.0164982, 0.961766, 1, 1, 1 </real_array>
- <string name="tracks/1/type"> "transform" </string>
- <node_path name="tracks/1/path"> "Armature/Skeleton:r-forearm" </node_path>
- <int name="tracks/1/interp"> 1 </int>
- <real_array name="tracks/1/keys" len="108"> 0, 1, 5.06639e-07, -8.64267e-07, -8.9407e-07, -0.0797867, 0.0313898, -0.00372185, 0.996311, 1, 1, 1, 0.05, 1, -5.96046e-08, -4.76837e-07, -3.57628e-07, -0.0735466, 0.0175489, -0.00298843, 0.997133, 1, 1, 1, 0.2, 1, 2.98023e-07, -9.83477e-07, -5.36442e-07, -0.0401349, -0.0767179, 0.000985969, 0.996244, 1, 1, 1, 0.25, 1, -2.98023e-08, -6.25849e-07, -4.17233e-07, -0.0324823, -0.0976145, 0.00230383, 0.994691, 1, 1, 1, 0.3, 1, 2.08616e-07, -9.53674e-07, -6.55651e-07, -0.0445163, -0.0629722, 0.000635031, 0.997022, 1, 0.999999, 1, 0.35, 1, -1.49012e-07, -8.34465e-07, -4.17233e-07, -0.0633553, -0.0111982, -0.0018671, 0.997926, 1, 1, 1, 0.4, 1, 2.38419e-07, -8.64267e-07, -7.7486e-07, -0.0770585, 0.0244395, -0.00342743, 0.996721, 1, 1, 1, 0.45, 1, 5.06639e-07, -8.64267e-07, -8.9407e-07, -0.0797867, 0.0313898, -0.00372185, 0.996311, 1, 1, 1, 1.25, 1, 5.06639e-07, -8.64267e-07, -8.9407e-07, -0.0797867, 0.0313898, -0.00372185, 0.996311, 1, 1, 1 </real_array>
- <string name="tracks/2/type"> "transform" </string>
- <node_path name="tracks/2/path"> "Armature/Skeleton:l-arm" </node_path>
- <int name="tracks/2/interp"> 1 </int>
- <real_array name="tracks/2/keys" len="132"> 0, 1, -1.19209e-07, -5.96046e-07, 5.36442e-07, -0.488489, -0.631801, -0.249807, 0.547542, 1, 1, 1, 0.05, 1, -1.49012e-07, -7.15256e-07, 5.96046e-07, -0.474017, -0.625071, -0.244485, 0.569931, 1, 1, 0.999999, 0.1, 1, -5.96046e-07, -3.57628e-07, 6.25849e-07, -0.454842, -0.607865, -0.232791, 0.607805, 1, 1, 0.999999, 0.15, 1, -6.25849e-07, -4.76837e-07, 6.85453e-07, -0.465321, -0.582319, -0.222366, 0.628437, 1, 1, 1, 0.2, 1, -3.8743e-07, -5.96046e-07, 6.25849e-07, -0.510621, -0.547625, -0.217789, 0.626052, 1, 1, 1, 0.25, 1, -5.96046e-07, -7.15256e-07, 2.98023e-07, -0.546434, -0.526096, -0.217482, 0.614275, 1, 1, 1, 0.3, 1, -3.57628e-07, -5.96046e-07, 6.85453e-07, -0.543207, -0.547611, -0.225218, 0.595252, 1, 1, 0.999999, 0.35, 1, -5.06639e-07, -5.96046e-07, 7.7486e-07, -0.516521, -0.594071, -0.238908, 0.568514, 1, 1, 1, 0.4, 1, -3.27826e-07, -5.96046e-07, 7.15256e-07, -0.493183, -0.625944, -0.248106, 0.550825, 1, 1, 1, 0.45, 1, -1.19209e-07, -5.96046e-07, 5.36442e-07, -0.488489, -0.631801, -0.249807, 0.547542, 1, 1, 1, 1.25, 1, -1.19209e-07, -5.96046e-07, 5.36442e-07, -0.488489, -0.631801, -0.249807, 0.547542, 1, 1, 1 </real_array>
- <string name="tracks/3/type"> "transform" </string>
- <node_path name="tracks/3/path"> "Armature/Skeleton:l-forearm" </node_path>
- <int name="tracks/3/interp"> 1 </int>
- <real_array name="tracks/3/keys" len="132"> 0, 1, -8.9407e-08, -5.96046e-07, -2.38419e-07, 0.170167, 0.120493, -0.091473, 0.973734, 1, 1, 1, 0.05, 1, -5.96046e-08, -5.36442e-07, -2.98023e-07, 0.191507, 0.15179, -0.0881411, 0.965669, 1, 1, 1, 0.1, 1, -2.98023e-08, -5.06639e-07, -1.19209e-07, 0.225056, 0.198248, -0.0838434, 0.950273, 1, 1, 1, 0.15, 1, -1.78814e-07, -6.85453e-07, -2.38419e-07, 0.242609, 0.209269, -0.0881917, 0.94317, 1, 1, 1, 0.2, 1, -3.27826e-07, -5.36442e-07, -1.19209e-07, 0.246276, 0.185328, -0.105902, 0.945403, 1, 1, 1, 0.25, 1, -4.76837e-07, -5.06639e-07, -7.7486e-07, 0.240434, 0.157542, -0.120519, 0.950183, 1, 1, 1, 0.3, 1, -8.9407e-08, -6.85453e-07, -2.98023e-07, 0.22081, 0.140399, -0.117544, 0.957974, 1, 0.999999, 1, 0.35, 1, -1.19209e-07, -7.7486e-07, -2.98023e-07, 0.191979, 0.127301, -0.104336, 0.967498, 1, 1, 1, 0.4, 1, -8.9407e-08, -6.55651e-07, -2.98023e-07, 0.173508, 0.121415, -0.0935976, 0.972827, 1, 1, 1, 0.45, 1, -8.9407e-08, -5.96046e-07, -2.38419e-07, 0.170167, 0.120493, -0.091473, 0.973734, 1, 1, 1, 1.25, 1, -8.9407e-08, -5.96046e-07, -2.38419e-07, 0.170167, 0.120493, -0.091473, 0.973734, 1, 1, 1 </real_array>
- <string name="tracks/4/type"> "transform" </string>
- <node_path name="tracks/4/path"> "Armature/Skeleton:r-thigh" </node_path>
- <int name="tracks/4/interp"> 1 </int>
- <real_array name="tracks/4/keys" len="120"> 0, 1, 0, 1.63913e-07, 1.93715e-07, -0.731646, -0.0455606, -0.00930311, 0.680097, 1, 1, 1, 0.05, 1, -8.9407e-08, 5.96046e-08, -3.57628e-07, -0.699019, -0.0340935, -0.0129449, 0.714172, 1, 1, 1, 0.1, 1, -8.9407e-08, 1.41561e-07, -2.83122e-07, -0.643626, -0.015991, -0.0189581, 0.764938, 1, 1, 1, 0.15, 1, -8.9407e-08, 3.72529e-08, -5.06639e-07, -0.617849, -0.00879986, -0.0226563, 0.785921, 1, 1, 1, 0.2, 1, -5.96046e-08, 9.68575e-08, 7.45058e-08, -0.628974, -0.00984708, -0.0265256, 0.776912, 1, 1, 1, 0.25, 1, -5.96046e-08, 9.68575e-08, -4.47035e-07, -0.653197, -0.0153019, -0.02661, 0.756565, 1, 1, 1, 0.35, 1, -2.98023e-08, 2.98023e-08, 2.98023e-07, -0.712225, -0.0376632, -0.0133416, 0.700813, 1, 1, 1, 0.4, 1, -2.98023e-08, 1.04308e-07, 1.63913e-07, -0.728798, -0.0444052, -0.00986262, 0.683216, 1, 1, 1, 0.45, 1, 0, 1.63913e-07, 1.93715e-07, -0.731646, -0.0455606, -0.00930311, 0.680097, 1, 1, 1, 1.25, 1, 0, 1.63913e-07, 1.93715e-07, -0.731646, -0.0455606, -0.00930311, 0.680097, 1, 1, 1 </real_array>
- <string name="tracks/5/type"> "transform" </string>
- <node_path name="tracks/5/path"> "Armature/Skeleton:r-leg" </node_path>
- <int name="tracks/5/interp"> 1 </int>
- <real_array name="tracks/5/keys" len="120"> 0, 1, -0.0436297, 0.0381679, -0.243318, 0.903835, 0.221183, 0.00392365, -0.366258, 1, 1, 1, 0.05, 1, -0.0436298, 0.0381678, -0.243318, 0.894017, 0.213358, 0.00409072, -0.393949, 1, 1, 1, 0.1, 1, -0.0436297, 0.0381675, -0.243318, 0.873591, 0.198684, 0.00402625, -0.444239, 1, 1, 1, 0.15, 1, -0.0436297, 0.0381679, -0.243318, 0.86099, 0.194348, 0.00472605, -0.470004, 1, 1, 1, 0.2, 1, -0.0436298, 0.038168, -0.243318, 0.866453, 0.209209, 0.00740134, -0.453251, 1, 1, 1, 0.25, 1, -0.0436297, 0.0381682, -0.243318, 0.877278, 0.223532, 0.00901692, -0.42466, 1, 1, 1, 0.35, 1, -0.0436297, 0.0381675, -0.243318, 0.89824, 0.222872, 0.00544398, -0.378765, 1, 1, 1, 0.4, 1, -0.0436297, 0.0381677, -0.243318, 0.90306, 0.22143, 0.0041485, -0.368015, 1, 1, 1, 0.45, 1, -0.0436297, 0.0381679, -0.243318, 0.903835, 0.221183, 0.00392365, -0.366258, 1, 1, 1, 1.25, 1, -0.0436297, 0.0381679, -0.243318, 0.903835, 0.221183, 0.00392365, -0.366258, 1, 1, 1 </real_array>
- <string name="tracks/6/type"> "transform" </string>
- <node_path name="tracks/6/path"> "Armature/Skeleton:r-foot" </node_path>
- <int name="tracks/6/interp"> 1 </int>
- <real_array name="tracks/6/keys" len="108"> 0, 1, 7.45058e-08, 1.19209e-07, -3.72529e-09, -0.278586, 0.162913, 0.049835, 0.94518, 1, 1, 1, 0.05, 1, 5.21541e-08, -1.19209e-07, 4.47035e-08, -0.263884, 0.163221, 0.0462377, 0.949519, 1, 1, 1, 0.15, 1, 3.72529e-08, 0, 2.98023e-08, -0.191844, 0.164134, 0.02867, 0.967178, 1, 1, 1, 0.2, 1, 9.68575e-08, 0, -7.45058e-09, -0.173312, 0.164214, 0.0241673, 0.970779, 1, 1, 1, 0.25, 1, 8.9407e-08, -3.57628e-07, 2.6077e-08, -0.181008, 0.164188, 0.0260364, 0.96933, 1, 1, 1, 0.35, 1, 7.45058e-08, 3.57628e-07, 7.45058e-09, -0.253238, 0.163417, 0.0436354, 0.952503, 1, 1, 1, 0.4, 1, 8.19564e-08, 2.38419e-07, 2.6077e-08, -0.274832, 0.162996, 0.0489163, 0.946312, 1, 1, 1, 0.45, 1, 7.45058e-08, 1.19209e-07, -3.72529e-09, -0.278586, 0.162913, 0.049835, 0.94518, 1, 1, 1, 1.25, 1, 7.45058e-08, 1.19209e-07, -3.72529e-09, -0.278586, 0.162913, 0.049835, 0.94518, 1, 1, 1 </real_array>
- <string name="tracks/7/type"> "transform" </string>
- <node_path name="tracks/7/path"> "Armature/Skeleton:l-thigh" </node_path>
- <int name="tracks/7/interp"> 1 </int>
- <real_array name="tracks/7/keys" len="120"> 0, 1, 0, 2.08616e-07, 1.49012e-08, 0.318341, 0.0708015, -0.00441775, 0.945318, 1, 1, 1, 0.05, 1, 0, 1.93715e-07, 3.42727e-07, 0.307147, 0.068999, -0.0035256, 0.949151, 1, 1, 1, 0.1, 1, 2.98023e-08, 2.01166e-07, 4.47035e-08, 0.292292, 0.0665824, -0.00232838, 0.954006, 1, 1, 1, 0.15, 1, 5.96046e-08, 1.04308e-07, -1.93715e-07, 0.272221, 0.0650766, -0.00188312, 0.96003, 1, 1, 1, 0.2, 1, 2.98023e-08, 2.23517e-08, -1.78814e-07, 0.232486, 0.0650023, -0.00182597, 0.970424, 1, 1, 1, 0.25, 1, 5.96046e-08, -1.49012e-08, -1.04308e-07, 0.226129, 0.0676028, -0.00263455, 0.971745, 1, 1, 1, 0.35, 1, -2.98023e-08, 5.21541e-08, 1.63913e-07, 0.288667, 0.069411, -0.00418897, 0.954901, 1, 1, 1, 0.4, 1, -2.98023e-08, 1.41561e-07, 1.93715e-07, 0.312853, 0.0704368, -0.0043685, 0.947176, 1, 1, 1, 0.45, 1, 0, 2.08616e-07, 1.49012e-08, 0.318341, 0.0708015, -0.00441775, 0.945318, 1, 1, 1, 1.25, 1, 0, 2.08616e-07, 1.49012e-08, 0.318341, 0.0708015, -0.00441775, 0.945318, 1, 1, 1 </real_array>
- <string name="tracks/8/type"> "transform" </string>
- <node_path name="tracks/8/path"> "Armature/Skeleton:l-leg" </node_path>
- <int name="tracks/8/interp"> 1 </int>
- <real_array name="tracks/8/keys" len="108"> 0, 1, 5.78584e-08, 5.96046e-08, 2.38419e-07, -0.0511448, -0.0112637, 0.00107338, 0.998627, 1, 1, 1, 0.05, 1, -2.94531e-08, -8.19564e-08, 1.78814e-07, -0.0669256, -0.012717, 0.000882011, 0.997677, 1, 1, 1, 0.1, 1, -3.07336e-08, -2.98023e-08, 3.57628e-07, -0.0875047, -0.0145704, 0.000627808, 0.996057, 1, 1, 1, 0.15, 1, 1.66474e-08, -8.9407e-08, 2.38419e-07, -0.12177, -0.0175352, 0.000386084, 0.992403, 1, 1, 1, 0.2, 1, 1.28057e-08, -1.49012e-08, 1.19209e-07, -0.196391, -0.0229446, -2.58925e-05, 0.980257, 1, 1, 1, 0.25, 1, -7.91624e-08, 8.9407e-08, 0, -0.21572, -0.0236374, -9.3472e-05, 0.976169, 1, 1, 1, 0.4, 1, 2.95695e-08, 6.70552e-08, 1.19209e-07, -0.060964, -0.012162, 0.00100229, 0.998065, 1, 1, 1, 0.45, 1, 5.78584e-08, 5.96046e-08, 2.38419e-07, -0.0511448, -0.0112637, 0.00107338, 0.998627, 1, 1, 1, 1.25, 1, 5.78584e-08, 5.96046e-08, 2.38419e-07, -0.0511448, -0.0112637, 0.00107338, 0.998627, 1, 1, 1 </real_array>
- <string name="tracks/9/type"> "transform" </string>
- <node_path name="tracks/9/path"> "Armature/Skeleton:l-foot" </node_path>
- <int name="tracks/9/interp"> 1 </int>
- <real_array name="tracks/9/keys" len="108"> 0, 1, 5.21541e-08, 1.19209e-07, -1.9744e-07, -0.285587, 0.0658082, 0.0159816, 0.955957, 1, 1, 1, 0.05, 1, 7.45058e-09, 1.19209e-07, -1.08033e-07, -0.295281, 0.0650349, 0.017475, 0.953034, 1, 1, 1, 0.15, 1, -2.23517e-08, 1.19209e-07, 2.98023e-08, -0.341727, 0.0611981, 0.0246725, 0.93748, 1, 1, 1, 0.2, 1, 5.21541e-08, 1.19209e-07, -1.19209e-07, -0.353427, 0.0601963, 0.0264969, 0.933147, 1, 1, 1, 0.25, 1, -1.49012e-08, 2.38419e-07, -4.84288e-08, -0.348577, 0.0606133, 0.0257401, 0.934964, 1, 1, 1, 0.35, 1, -7.45058e-09, 1.19209e-07, -7.45058e-09, -0.302251, 0.0644732, 0.0185506, 0.950865, 1, 1, 1, 0.4, 1, 5.21541e-08, 1.19209e-07, -8.19564e-08, -0.28807, 0.065611, 0.0163638, 0.955219, 1, 1, 1, 0.45, 1, 5.21541e-08, 1.19209e-07, -1.9744e-07, -0.285587, 0.0658082, 0.0159816, 0.955957, 1, 1, 1, 1.25, 1, 5.21541e-08, 1.19209e-07, -1.9744e-07, -0.285587, 0.0658082, 0.0159816, 0.955957, 1, 1, 1 </real_array>
- <string name="tracks/10/type"> "transform" </string>
- <node_path name="tracks/10/path"> "Armature/Skeleton:MASTER" </node_path>
- <int name="tracks/10/interp"> 1 </int>
- <real_array name="tracks/10/keys" len="24"> 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/11/type"> "transform" </string>
- <node_path name="tracks/11/path"> "Armature/Skeleton:HEAD" </node_path>
- <int name="tracks/11/interp"> 1 </int>
- <real_array name="tracks/11/keys" len="108"> 0, 1, 1.37965e-08, 0.0913706, -0.0102687, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 1.37965e-08, 0.0913706, 0.0826712, 0, 0, 0, 1, 1, 1, 1, 0.15, 1, 1.37965e-08, 0.0913706, 0.527418, 0, 0, 0, 1, 1, 1, 1, 0.2, 1, 1.37965e-08, 0.0913706, 0.640416, 0, 0, -7.10543e-15, 1, 1, 1, 1, 0.25, 1, 1.37965e-08, 0.0913706, 0.59344, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, 1.37965e-08, 0.0913706, 0.149321, 0, 0, -7.10543e-15, 1, 1, 1, 1, 0.4, 1, 1.37965e-08, 0.0913706, 0.0135775, 0, 0, 0, 1, 1, 1, 1, 0.45, 1, 1.37965e-08, 0.0913706, -0.0102687, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 1.37965e-08, 0.0913706, -0.0102687, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/12/type"> "transform" </string>
- <node_path name="tracks/12/path"> "Armature/Skeleton:r-LEGCONTROL" </node_path>
- <int name="tracks/12/interp"> 1 </int>
- <real_array name="tracks/12/keys" len="108"> 0, 1, -0.142338, -0.579062, 1.09897, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -0.142338, -0.574357, 1.07628, 0, 0, 0, 1, 1, 1, 1, 0.15, 1, -0.142338, -0.551601, 0.966619, 0, 0, 0, 1, 1, 1, 1, 0.2, 1, -0.142338, -0.545802, 0.938678, 0, 0, 0, 1, 1, 1, 1, 0.25, 1, -0.142338, -0.54821, 0.950281, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, -0.142338, -0.570965, 1.05993, 0, 0, 0, 1, 1, 1, 1, 0.4, 1, -0.142338, -0.577858, 1.09316, 0, 0, 0, 1, 1, 1, 1, 0.45, 1, -0.142338, -0.579062, 1.09897, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.142338, -0.579062, 1.09897, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/13/type"> "transform" </string>
- <node_path name="tracks/13/path"> "Armature/Skeleton:l-LEGCONTROL" </node_path>
- <int name="tracks/13/interp"> 1 </int>
- <real_array name="tracks/13/keys" len="108"> 0, 1, 0.133965, 0.921787, 0.705414, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 0.133965, 0.88632, 0.724279, 0, 0, 0, 1, 1, 1, 1, 0.1, 1, 0.133965, 0.833892, 0.752174, 0, 0, 0, 1, 1, 1, 1, 0.15, 1, 0.133965, 0.821796, 0.758611, 0, 0, 0, 1, 1, 1, 1, 0.2, 1, 0.133965, 0.834697, 0.751748, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, 0.133965, 0.908846, 0.712298, 0, 0, 0, 1, 1, 1, 1, 0.4, 1, 0.133965, 0.919922, 0.706406, 0, 0, 0, 1, 1, 1, 1, 0.45, 1, 0.133965, 0.921787, 0.705414, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.133965, 0.921787, 0.705414, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/14/type"> "transform" </string>
- <node_path name="tracks/14/path"> "Armature/Skeleton:r-LEGORIENT" </node_path>
- <int name="tracks/14/interp"> 1 </int>
- <real_array name="tracks/14/keys" len="24"> 0, 1, 0.100474, 0.669825, -0.778672, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.100474, 0.669825, -0.778672, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/15/type"> "transform" </string>
- <node_path name="tracks/15/path"> "Armature/Skeleton:l-LEGORIENT" </node_path>
- <int name="tracks/15/interp"> 1 </int>
- <real_array name="tracks/15/keys" len="24"> 0, 1, -0.0204011, -0.122407, 5.96046e-08, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.0204011, -0.122407, 5.96046e-08, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/16/type"> "transform" </string>
- <node_path name="tracks/16/path"> "Armature/Skeleton:r-ARMCONTROL" </node_path>
- <int name="tracks/16/interp"> 1 </int>
- <real_array name="tracks/16/keys" len="120"> 0, 1, -0.868295, 0.267668, -0.820401, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -0.868295, 0.253357, -0.761204, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, -0.868295, 0.216179, -0.653431, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.15, 1, -0.868295, 0.157463, -0.585229, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.2, 1, -0.868295, 0.102061, -0.562116, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.25, 1, -0.868295, 0.10969, -0.583242, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, -0.868295, 0.226187, -0.758093, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, -0.868295, 0.261497, -0.811129, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, -0.868295, 0.267668, -0.820401, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.868295, 0.267668, -0.820401, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/17/type"> "transform" </string>
- <node_path name="tracks/17/path"> "Armature/Skeleton:l-ARMCONTROL" </node_path>
- <int name="tracks/17/interp"> 1 </int>
- <real_array name="tracks/17/keys" len="108"> 0, 1, 2.08906, 2.18272, 3.23967, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 2.08906, 2.16545, 3.23967, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.15, 1, 2.08906, 2.08198, 3.23967, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.2, 1, 2.08906, 2.06071, 3.23967, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.25, 1, 2.08906, 2.06954, 3.23967, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, 2.08906, 2.15301, 3.23967, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, 2.08906, 2.1783, 3.23967, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, 2.08906, 2.18272, 3.23967, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 2.08906, 2.18272, 3.23967, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/18/type"> "transform" </string>
- <node_path name="tracks/18/path"> "Armature/Skeleton:r-ARMORIENT" </node_path>
- <int name="tracks/18/interp"> 1 </int>
- <real_array name="tracks/18/keys" len="24"> 0, 1, 0.405204, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.405204, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/19/type"> "transform" </string>
- <node_path name="tracks/19/path"> "Armature/Skeleton:l-ARMORIENT" </node_path>
- <int name="tracks/19/interp"> 1 </int>
- <real_array name="tracks/19/keys" len="132"> 0, 1, -0.495073, -1.94554, 0.375148, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -0.529633, -1.94554, 0.375148, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, -0.616933, -1.94554, 0.375148, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.15, 1, -0.726325, -1.94554, 0.375148, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.2, 1, -0.813485, -1.94554, 0.375148, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.25, 1, -0.847955, -1.94554, 0.375148, 0, 0, 0, 1, 1, 1, 1, 0.3, 1, -0.773744, -1.94554, 0.375148, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.35, 1, -0.620743, -1.94554, 0.375148, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, -0.514687, -1.94554, 0.375148, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, -0.495073, -1.94554, 0.375148, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.495073, -1.94554, 0.375148, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/20/type"> "transform" </string>
- <node_path name="tracks/20/path"> "Armature/Skeleton:hip" </node_path>
- <int name="tracks/20/interp"> 1 </int>
- <real_array name="tracks/20/keys" len="132"> 0, 1, 0.050238, 0.697428, 0.108012, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1, 0.05, 1, 0.050238, 0.727833, 0.0877454, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1, 0.1, 1, 0.050238, 0.772783, 0.0577767, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1, 0.15, 1, 0.050238, 0.78451, 0.0674334, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1, 0.2, 1, 0.050238, 0.778496, 0.13139, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1, 0.25, 1, 0.050238, 0.766398, 0.174636, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1, 0.3, 1, 0.050238, 0.744412, 0.160603, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1, 0.35, 1, 0.050238, 0.716858, 0.131686, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1, 0.4, 1, 0.050238, 0.700317, 0.111698, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1, 0.45, 1, 0.050238, 0.697428, 0.108012, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1, 1.25, 1, 0.050238, 0.697428, 0.108012, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1 </real_array>
- <string name="tracks/21/type"> "transform" </string>
- <node_path name="tracks/21/path"> "Armature/Skeleton:waist" </node_path>
- <int name="tracks/21/interp"> 1 </int>
- <real_array name="tracks/21/keys" len="24"> 0, 1, 7.45059e-09, -5.21541e-08, 2.38419e-07, 0.126301, -0.0110499, -0.0864524, 0.988156, 1, 1, 1, 1.25, 1, 7.45059e-09, -5.21541e-08, 2.38419e-07, 0.126301, -0.0110499, -0.0864524, 0.988156, 1, 1, 1 </real_array>
- <string name="tracks/22/type"> "transform" </string>
- <node_path name="tracks/22/path"> "Armature/Skeleton:chest" </node_path>
- <int name="tracks/22/interp"> 1 </int>
- <real_array name="tracks/22/keys" len="24"> 0, 1, -2.26918e-09, 5.21541e-08, -1.78814e-07, 0.0237758, -0.0135633, -0.0860939, 0.995911, 1, 1, 1, 1.25, 1, -2.26918e-09, 5.21541e-08, -1.78814e-07, 0.0237758, -0.0135633, -0.0860939, 0.995911, 1, 1, 1 </real_array>
- <string name="tracks/23/type"> "transform" </string>
- <node_path name="tracks/23/path"> "Armature/Skeleton:neck" </node_path>
- <int name="tracks/23/interp"> 1 </int>
- <real_array name="tracks/23/keys" len="24"> 0, 1, -1.11758e-08, -2.23517e-07, -1.43051e-06, -7.45058e-09, -4.4605e-10, 4.26538e-09, 1, 1, 1, 1, 1.25, 1, -1.11758e-08, -2.23517e-07, -1.43051e-06, -7.45058e-09, -4.4605e-10, 4.26538e-09, 1, 1, 1, 1 </real_array>
- <string name="tracks/24/type"> "transform" </string>
- <node_path name="tracks/24/path"> "Armature/Skeleton:headtracker" </node_path>
- <int name="tracks/24/interp"> 1 </int>
- <real_array name="tracks/24/keys" len="108"> 0, 1, 1.02445e-08, -4.47035e-07, -1.05007e-07, 0.287287, -0.0941088, 0.0255168, 0.952869, 1, 1, 1, 0.05, 1, -2.68222e-08, -2.98023e-08, -7.10133e-08, 0.277009, -0.0944548, 0.024506, 0.9559, 1, 1, 1, 0.15, 1, -2.42144e-08, -3.57628e-07, -3.39933e-08, 0.229614, -0.0956923, 0.0198279, 0.968363, 1, 1, 1, 0.2, 1, -1.22934e-08, -1.78814e-07, 1.30385e-08, 0.224057, -0.0957887, 0.0192787, 0.969665, 1, 1, 1, 0.25, 1, -3.91156e-08, 1.19209e-07, -4.79631e-08, 0.233664, -0.0955615, 0.0202274, 0.967399, 1, 1, 1, 0.35, 1, -3.35279e-09, -3.27826e-07, -4.61005e-08, 0.274341, -0.0944949, 0.024241, 0.956671, 1, 1, 1, 0.4, 1, -1.67641e-09, -2.68221e-07, -8.21892e-08, 0.285395, -0.0941665, 0.0253304, 0.953436, 1, 1, 1, 0.45, 1, 1.02445e-08, -4.47035e-07, -1.05007e-07, 0.287287, -0.0941088, 0.0255168, 0.952869, 1, 1, 1, 1.25, 1, 1.02445e-08, -4.47035e-07, -1.05007e-07, 0.287287, -0.0941088, 0.0255168, 0.952869, 1, 1, 1 </real_array>
- <string name="tracks/25/type"> "transform" </string>
- <node_path name="tracks/25/path"> "Armature/Skeleton:head" </node_path>
- <int name="tracks/25/interp"> 1 </int>
- <real_array name="tracks/25/keys" len="24"> 0, 1, -7.74519e-09, -9.56934e-08, 3.16533e-07, 7.45058e-09, 3.37575e-10, -1.99442e-09, 1, 1, 1, 1, 1.25, 1, -7.74519e-09, -9.56934e-08, 3.16533e-07, 7.45058e-09, 3.37575e-10, -1.99442e-09, 1, 1, 1, 1 </real_array>
- <string name="tracks/26/type"> "transform" </string>
- <node_path name="tracks/26/path"> "Armature/Skeleton:vent" </node_path>
- <int name="tracks/26/interp"> 1 </int>
- <real_array name="tracks/26/keys" len="24"> 0, 1, 3.38022e-08, 0.00292349, 0.20433, 6.98492e-10, 2.45226e-11, 6.71222e-11, 1, 1, 1, 1, 1.25, 1, 3.38022e-08, 0.00292349, 0.20433, 6.98492e-10, 2.45226e-11, 6.71222e-11, 1, 1, 1, 1 </real_array>
-
- </resource>
- <resource type="Animation" path="local://10">
- <string name="resource/name"> "shooting_standing" </string>
- <real name="length"> 0.416667 </real>
- <bool name="loop"> False </bool>
- <real name="step"> 0.1 </real>
- <string name="tracks/0/type"> "transform" </string>
- <node_path name="tracks/0/path"> "Armature/Skeleton:r-arm" </node_path>
- <int name="tracks/0/interp"> 1 </int>
- <real_array name="tracks/0/keys" len="132"> 0, 1, 5.96046e-07, -1.19209e-07, 4.47035e-07, -0.206314, 0.709894, -0.150643, 0.656348, 1, 1, 1, 0.05, 1, 1.07288e-06, -4.76837e-07, 8.34465e-07, -0.199825, 0.723236, -0.14911, 0.644023, 1, 1, 1, 0.1, 1, 4.47035e-07, -1.19209e-07, 3.27826e-07, -0.186028, 0.74616, -0.147051, 0.622106, 1, 1, 1, 0.15, 1, 4.47035e-07, -1.19209e-07, 1.49012e-07, -0.168011, 0.761016, -0.149525, 0.608497, 1, 1, 1, 0.2, 1, 2.38419e-07, 1.19209e-07, -1.19209e-07, -0.141127, 0.777642, -0.158168, 0.591895, 1, 1, 1, 0.25, 1, 7.15256e-07, -2.38419e-07, 2.68221e-07, -0.129783, 0.779527, -0.165304, 0.590059, 1, 1, 1, 0.3, 1, 6.25849e-07, -1.19209e-07, 2.08616e-07, -0.152097, 0.757922, -0.164122, 0.612768, 1, 1, 1, 0.35, 1, 8.9407e-07, -4.76837e-07, 8.34465e-07, -0.183836, 0.730436, -0.157254, 0.638701, 1, 1, 1, 0.4, 1, 7.45058e-07, -3.57628e-07, 5.66244e-07, -0.202964, 0.713054, -0.151716, 0.653714, 1, 1, 1, 0.45, 1, 5.96046e-07, -1.19209e-07, 4.47035e-07, -0.206314, 0.709894, -0.150643, 0.656348, 1, 1, 1, 1.25, 1, 5.96046e-07, -1.19209e-07, 4.47035e-07, -0.206314, 0.709894, -0.150643, 0.656348, 1, 1, 1 </real_array>
- <string name="tracks/1/type"> "transform" </string>
- <node_path name="tracks/1/path"> "Armature/Skeleton:r-forearm" </node_path>
- <int name="tracks/1/interp"> 1 </int>
- <real_array name="tracks/1/keys" len="120"> 0, 1, 0, -4.76837e-07, -7.7486e-07, 0.0490264, -0.364254, 0.0100564, 0.929954, 1, 1, 1, 0.05, 1, 1.19209e-07, -4.47035e-07, -4.76837e-07, 0.0346734, -0.325178, 0.00768963, 0.944986, 1, 1, 1, 0.1, 1, 1.19209e-07, -5.06639e-07, -3.57628e-07, 0.00822793, -0.255634, 0.00344931, 0.966732, 1, 1, 1, 0.15, 1, 2.98023e-08, -7.15256e-07, -5.96046e-07, -0.00893206, -0.219161, 0.00118009, 0.975647, 1, 1, 1, 0.2, 1, 1.49012e-07, -4.47035e-07, -5.96046e-07, -0.0220165, -0.204408, 0.000203021, 0.978638, 1, 1, 1, 0.25, 1, 4.17233e-07, -4.76837e-07, -5.36442e-07, -0.0204464, -0.223283, 0.00158917, 0.974538, 1, 1, 1, 0.35, 1, 1.19209e-07, -6.85453e-07, -2.98023e-07, 0.0295549, -0.331584, 0.00842644, 0.942925, 1, 1, 1, 0.4, 1, 0, -6.55651e-07, -6.55651e-07, 0.0460614, -0.359518, 0.00983853, 0.931949, 1, 1, 1, 0.45, 1, 0, -4.76837e-07, -7.7486e-07, 0.0490264, -0.364254, 0.0100564, 0.929954, 1, 1, 1, 1.25, 1, 0, -4.76837e-07, -7.7486e-07, 0.0490264, -0.364254, 0.0100564, 0.929954, 1, 1, 1 </real_array>
- <string name="tracks/2/type"> "transform" </string>
- <node_path name="tracks/2/path"> "Armature/Skeleton:l-arm" </node_path>
- <int name="tracks/2/interp"> 1 </int>
- <real_array name="tracks/2/keys" len="132"> 0, 1, -4.17233e-07, -3.57628e-07, 4.47035e-07, -0.474516, -0.584521, 0.0340579, 0.657274, 1, 1, 1, 0.05, 1, -7.45058e-07, -3.57628e-07, 5.36442e-07, -0.46761, -0.58693, 0.0339523, 0.660076, 1, 1, 1, 0.1, 1, -4.76837e-07, -2.38419e-07, 2.98023e-07, -0.452786, -0.591715, 0.0339493, 0.666112, 1, 1, 1, 0.15, 1, -6.55651e-07, -3.57628e-07, 2.98023e-07, -0.443727, -0.588057, 0.0337848, 0.675392, 1, 1, 1, 0.2, 1, 2.98023e-08, 1.19209e-07, -3.27826e-07, -0.450408, -0.563251, 0.0324613, 0.691973, 1, 1, 1, 0.25, 1, -5.96046e-07, -3.57628e-07, 2.98023e-07, -0.461281, -0.543778, 0.0314456, 0.700383, 1, 1, 1, 0.3, 1, -4.17233e-07, 0, 1.78814e-07, -0.469244, -0.550688, 0.0318109, 0.689595, 1, 1, 1, 0.35, 1, -7.7486e-07, -2.38419e-07, 4.76837e-07, -0.473462, -0.569016, 0.0329517, 0.671542, 1, 1, 1, 0.4, 1, -6.25849e-07, -3.57628e-07, 5.96046e-07, -0.474439, -0.5821, 0.0338759, 0.659485, 1, 1, 1, 0.45, 1, -4.17233e-07, -3.57628e-07, 4.47035e-07, -0.474516, -0.584521, 0.0340579, 0.657274, 1, 1, 1, 1.25, 1, -4.17233e-07, -3.57628e-07, 4.47035e-07, -0.474516, -0.584521, 0.0340579, 0.657274, 1, 1, 1 </real_array>
- <string name="tracks/3/type"> "transform" </string>
- <node_path name="tracks/3/path"> "Armature/Skeleton:l-forearm" </node_path>
- <int name="tracks/3/interp"> 1 </int>
- <real_array name="tracks/3/keys" len="96"> 0, 1, 1.78814e-07, 2.98023e-08, -3.57628e-07, -0.156054, -0.257929, 9.29801e-05, 0.953478, 1.3, 1.3, 1.3, 0.05, 1, -8.9407e-08, -9.23872e-07, -2.98023e-07, -0.156186, -0.25785, 0.000491834, 0.953477, 1.3, 1.3, 1.3, 0.1, 1, 0, -5.06639e-07, -2.98023e-07, -0.156442, -0.257682, 0.00128265, 0.95348, 1.3, 1.3, 1.3, 0.15, 1, -2.08616e-07, -5.36442e-07, -5.96046e-08, -0.156528, -0.257623, 0.00155313, 0.953481, 1.3, 1.3, 1.3, 0.25, 1, 2.98023e-08, -5.36442e-07, -3.57628e-07, -0.155874, -0.258131, -0.000583909, 0.953452, 1.3, 1.3, 1.3, 0.35, 1, 2.98023e-08, -4.76837e-07, -3.57628e-07, -0.15592, -0.258051, -0.000371468, 0.953467, 1.3, 1.3, 1.3, 0.4, 1, 1.49012e-07, -2.68221e-07, -2.98023e-07, -0.156032, -0.257949, 1.56283e-05, 0.953476, 1.3, 1.3, 1.3, 1.25, 1, 1.78814e-07, 2.98023e-08, -3.57628e-07, -0.156054, -0.257929, 9.29801e-05, 0.953478, 1.3, 1.3, 1.3 </real_array>
- <string name="tracks/4/type"> "transform" </string>
- <node_path name="tracks/4/path"> "Armature/Skeleton:r-thigh" </node_path>
- <int name="tracks/4/interp"> 1 </int>
- <real_array name="tracks/4/keys" len="120"> 0, 1, 5.96046e-08, 2.23517e-08, -1.3411e-07, 0.301601, -0.0701581, -0.00864293, 0.95081, 1, 1, 1, 0.05, 1, 5.96046e-08, 2.98023e-08, -1.04308e-07, 0.248345, -0.0620849, -0.00736271, 0.966652, 1, 1, 1, 0.1, 1, 8.9407e-08, 6.70552e-08, -1.04308e-07, 0.175365, -0.0511626, -0.00552639, 0.983158, 1, 1, 1, 0.15, 1, 8.9407e-08, 4.47035e-08, -1.04308e-07, 0.153891, -0.0497144, -0.00660778, 0.986814, 1, 1, 1, 0.2, 1, 5.96046e-08, -2.98023e-08, -1.49012e-08, 0.151238, -0.0561188, -0.0117034, 0.986834, 1, 1, 1, 0.25, 1, 2.98023e-08, -1.49012e-08, -1.04308e-07, 0.168743, -0.0655087, -0.0152581, 0.983362, 1, 1, 1, 0.35, 1, 2.98023e-08, 2.23517e-08, -1.63913e-07, 0.26593, -0.072486, -0.0117415, 0.961192, 1, 1, 1, 0.4, 1, 5.96046e-08, 7.45058e-09, -1.78814e-07, 0.296131, -0.070636, -0.00916634, 0.952488, 1, 1, 1, 0.45, 1, 5.96046e-08, 2.23517e-08, -1.3411e-07, 0.301601, -0.0701581, -0.00864293, 0.95081, 1, 1, 1, 1.25, 1, 5.96046e-08, 2.23517e-08, -1.3411e-07, 0.301601, -0.0701581, -0.00864293, 0.95081, 1, 1, 1 </real_array>
- <string name="tracks/5/type"> "transform" </string>
- <node_path name="tracks/5/path"> "Armature/Skeleton:r-leg" </node_path>
- <int name="tracks/5/interp"> 1 </int>
- <real_array name="tracks/5/keys" len="120"> 0, 1, -4.31901e-08, -7.45058e-08, 7.7486e-07, -0.33852, 0.053398, -0.0152903, 0.939319, 1, 1, 1, 0.05, 1, 5.6345e-08, -2.23517e-08, 6.55651e-07, -0.403989, 0.0628472, -0.0146608, 0.912484, 1, 1, 1, 0.1, 1, 5.02914e-08, -1.49012e-08, 5.36442e-07, -0.486228, 0.0751824, -0.0137902, 0.870483, 1, 1, 1, 0.15, 1, 1.11642e-07, 5.96046e-08, 5.96046e-07, -0.506485, 0.0840018, -0.0142775, 0.858028, 1, 1, 1, 0.2, 1, 1.23633e-07, 8.19564e-08, 5.36442e-07, -0.500531, 0.103313, -0.0168649, 0.859367, 1, 1, 1, 0.25, 1, 9.58098e-08, 1.49012e-08, 6.55651e-07, -0.475505, 0.111896, -0.0189746, 0.872361, 1, 1, 1, 0.35, 1, 7.84639e-08, 9.68575e-08, 5.96046e-07, -0.376662, 0.0699087, -0.0169347, 0.923554, 1, 1, 1, 0.4, 1, -1.16415e-09, -7.45058e-09, 7.15256e-07, -0.344524, 0.0558207, -0.0155573, 0.936987, 1, 1, 1, 0.45, 1, -4.31901e-08, -7.45058e-08, 7.7486e-07, -0.33852, 0.053398, -0.0152903, 0.939319, 1, 1, 1, 1.25, 1, -4.31901e-08, -7.45058e-08, 7.7486e-07, -0.33852, 0.053398, -0.0152903, 0.939319, 1, 1, 1 </real_array>
- <string name="tracks/6/type"> "transform" </string>
- <node_path name="tracks/6/path"> "Armature/Skeleton:r-foot" </node_path>
- <int name="tracks/6/interp"> 1 </int>
- <real_array name="tracks/6/keys" len="108"> 0, 1, 1.19209e-07, 0, 1.82539e-07, -0.218034, -0.0651501, 0.015764, 0.973637, 1, 1, 1, 0.05, 1, 5.21541e-08, 0, -9.31323e-08, -0.206333, -0.0662009, 0.0171463, 0.976089, 1, 1, 1, 0.1, 1, 2.98023e-08, -1.19209e-07, -7.45058e-08, -0.188973, -0.0677374, 0.0191861, 0.979455, 1, 1, 1, 0.15, 1, 0, 0, -4.84288e-08, -0.184958, -0.0680889, 0.0196559, 0.980188, 1, 1, 1, 0.2, 1, 5.96046e-08, 0, -1.19209e-07, -0.189238, -0.0677142, 0.019155, 0.979406, 1, 1, 1, 0.35, 1, 8.19564e-08, 1.19209e-07, 3.72529e-08, -0.213767, -0.0655347, 0.0162687, 0.974548, 1, 1, 1, 0.4, 1, 1.04308e-07, 0, 5.21541e-08, -0.217419, -0.0652056, 0.0158368, 0.973769, 1, 1, 1, 0.45, 1, 1.19209e-07, 0, 1.82539e-07, -0.218034, -0.0651501, 0.015764, 0.973637, 1, 1, 1, 1.25, 1, 1.19209e-07, 0, 1.82539e-07, -0.218034, -0.0651501, 0.015764, 0.973637, 1, 1, 1 </real_array>
- <string name="tracks/7/type"> "transform" </string>
- <node_path name="tracks/7/path"> "Armature/Skeleton:l-thigh" </node_path>
- <int name="tracks/7/interp"> 1 </int>
- <real_array name="tracks/7/keys" len="132"> 0, 1, -5.96046e-08, -1.2666e-07, 1.04308e-07, -0.633392, 0.109953, 0.00349885, 0.765972, 1, 1, 1, 0.05, 1, 0, -4.47035e-08, 1.3411e-07, -0.628866, 0.106487, 0.00414994, 0.770176, 1, 1, 1, 0.1, 1, -2.98023e-08, 4.47035e-08, 1.49012e-07, -0.619935, 0.101098, 0.00522767, 0.778095, 1, 1, 1, 0.15, 1, -2.98023e-08, 5.96046e-08, 1.49012e-07, -0.616185, 0.108634, 0.00550208, 0.780054, 1, 1, 1, 0.2, 1, 5.96046e-08, 4.47035e-08, 2.5332e-07, -0.613177, 0.141231, 0.00523592, 0.7772, 1, 1, 1, 0.25, 1, 0, 0, 1.49012e-07, -0.612177, 0.164991, 0.00476259, 0.773301, 1, 1, 1, 0.3, 1, 5.96046e-08, -7.45058e-09, 1.3411e-07, -0.619021, 0.155086, 0.00421746, 0.769898, 1, 1, 1, 0.35, 1, 2.98023e-08, 7.45058e-09, 7.45058e-08, -0.627679, 0.130628, 0.00377015, 0.767425, 1, 1, 1, 0.4, 1, -2.98023e-08, -1.3411e-07, 7.45058e-08, -0.632568, 0.11319, 0.0035387, 0.766181, 1, 1, 1, 0.45, 1, -5.96046e-08, -1.2666e-07, 1.04308e-07, -0.633392, 0.109953, 0.00349885, 0.765972, 1, 1, 1, 1.25, 1, -5.96046e-08, -1.2666e-07, 1.04308e-07, -0.633392, 0.109953, 0.00349885, 0.765972, 1, 1, 1 </real_array>
- <string name="tracks/8/type"> "transform" </string>
- <node_path name="tracks/8/path"> "Armature/Skeleton:l-leg" </node_path>
- <int name="tracks/8/interp"> 1 </int>
- <real_array name="tracks/8/keys" len="120"> 0, 1, -4.07454e-08, -1.11759e-07, 0, -0.55604, 0.155102, 0.00378888, 0.816547, 1, 1, 1, 0.05, 1, 7.60192e-08, -8.9407e-08, 1.19209e-07, -0.534898, 0.148998, 0.00358481, 0.831668, 1, 1, 1, 0.1, 1, -1.0326e-07, -1.49012e-08, 2.38419e-07, -0.500235, 0.139173, 0.00323174, 0.854626, 1, 1, 1, 0.15, 1, 6.41448e-08, 4.47035e-08, 1.78814e-07, -0.492131, 0.143377, 0.00332103, 0.858626, 1, 1, 1, 0.25, 1, -6.58911e-08, -8.19564e-08, 1.78814e-07, -0.517192, 0.191548, 0.00473312, 0.834146, 1, 1, 1, 0.3, 1, 3.0268e-08, 1.49012e-08, 1.19209e-07, -0.534465, 0.187415, 0.00465677, 0.824136, 1, 1, 1, 0.35, 1, 3.11993e-08, -5.21541e-08, 2.38419e-07, -0.548296, 0.170437, 0.0042049, 0.818722, 1, 1, 1, 0.4, 1, 2.51457e-08, -9.68575e-08, 1.19209e-07, -0.554953, 0.157536, 0.00385503, 0.81682, 1, 1, 1, 0.45, 1, -4.07454e-08, -1.11759e-07, 0, -0.55604, 0.155102, 0.00378888, 0.816547, 1, 1, 1, 1.25, 1, -4.07454e-08, -1.11759e-07, 0, -0.55604, 0.155102, 0.00378888, 0.816547, 1, 1, 1 </real_array>
- <string name="tracks/9/type"> "transform" </string>
- <node_path name="tracks/9/path"> "Armature/Skeleton:l-foot" </node_path>
- <int name="tracks/9/interp"> 1 </int>
- <real_array name="tracks/9/keys" len="108"> 0, 1, 7.45058e-08, 1.19209e-07, 3.72529e-09, -0.143967, -0.0951747, 0.00523759, 0.984981, 1, 1, 1, 0.05, 1, 7.45058e-09, 2.38419e-07, 3.35276e-08, -0.157581, -0.0952617, 0.00367365, 0.982894, 1, 1, 1, 0.1, 1, -2.23517e-08, 1.19209e-07, -1.11759e-08, -0.17766, -0.0953568, 0.00135921, 0.97946, 1, 1, 1, 0.15, 1, -3.72529e-08, 1.19209e-07, 4.84288e-08, -0.182282, -0.0953731, 0.000825106, 0.97861, 1, 1, 1, 0.2, 1, 1.49012e-08, 1.19209e-07, -5.21541e-08, -0.177354, -0.0953557, 0.00139453, 0.979516, 1, 1, 1, 0.35, 1, 4.47035e-08, 0, 5.96046e-08, -0.148938, -0.0952085, 0.00466699, 0.984241, 1, 1, 1, 0.4, 1, 5.21541e-08, 1.19209e-07, -4.09782e-08, -0.144684, -0.0951797, 0.00515536, 0.984876, 1, 1, 1, 0.45, 1, 7.45058e-08, 1.19209e-07, 3.72529e-09, -0.143967, -0.0951747, 0.00523759, 0.984981, 1, 1, 1, 1.25, 1, 7.45058e-08, 1.19209e-07, 3.72529e-09, -0.143967, -0.0951747, 0.00523759, 0.984981, 1, 1, 1 </real_array>
- <string name="tracks/10/type"> "transform" </string>
- <node_path name="tracks/10/path"> "Armature/Skeleton:MASTER" </node_path>
- <int name="tracks/10/interp"> 1 </int>
- <real_array name="tracks/10/keys" len="24"> 0, 1, 0, 1.36988, -1.03377e-07, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0, 1.36988, -1.03377e-07, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/11/type"> "transform" </string>
- <node_path name="tracks/11/path"> "Armature/Skeleton:HEAD" </node_path>
- <int name="tracks/11/interp"> 1 </int>
- <real_array name="tracks/11/keys" len="108"> 0, 1, 8.64522e-08, 0.572547, -4.76837e-07, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 8.64522e-08, 0.572548, 0.471507, 0, 0, 0, 1, 1, 1, 1, 0.1, 1, 8.64522e-08, 0.572548, 1.12029, 0, 0, 7.10543e-15, 1, 1, 1, 1, 0.15, 1, 8.64522e-08, 0.572548, 1.26782, 0, 0, 0, 1, 1, 1, 1, 0.2, 1, 8.64522e-08, 0.572548, 1.10411, 0, 0, -7.10543e-15, 1, 1, 1, 1, 0.35, 1, 8.64522e-08, 0.572548, 0.166984, 0, 0, -7.10543e-15, 1, 1, 1, 1, 0.4, 1, 8.64522e-08, 0.572547, 0.024261, 0, 0, 0, 1, 1, 1, 1, 0.45, 1, 8.64522e-08, 0.572547, -4.76837e-07, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 8.64522e-08, 0.572547, -4.76837e-07, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/12/type"> "transform" </string>
- <node_path name="tracks/12/path"> "Armature/Skeleton:r-LEGCONTROL" </node_path>
- <int name="tracks/12/interp"> 1 </int>
- <real_array name="tracks/12/keys" len="108"> 0, 1, -0.0366479, -0.0811065, 0.809552, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -0.0366479, -0.0811065, 0.816585, 0, 0, 0, 1, 1, 1, 1, 0.1, 1, -0.0366479, -0.0811065, 0.826986, 0, 0, 0, 1, 1, 1, 1, 0.15, 1, -0.0366479, -0.0811065, 0.829386, 0, 0, 0, 1, 1, 1, 1, 0.2, 1, -0.0366479, -0.0811065, 0.826827, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, -0.0366479, -0.0811065, 0.812119, 0, 0, 0, 1, 1, 1, 1, 0.4, 1, -0.0366479, -0.0811065, 0.809922, 0, 0, 0, 1, 1, 1, 1, 0.45, 1, -0.0366479, -0.0811065, 0.809552, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.0366479, -0.0811065, 0.809552, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/13/type"> "transform" </string>
- <node_path name="tracks/13/path"> "Armature/Skeleton:l-LEGCONTROL" </node_path>
- <int name="tracks/13/interp"> 1 </int>
- <real_array name="tracks/13/keys" len="24"> 0, 1, 0.0611181, -2.75446, 0.0815672, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.0611181, -2.75446, 0.0815672, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/14/type"> "transform" </string>
- <node_path name="tracks/14/path"> "Armature/Skeleton:r-LEGORIENT" </node_path>
- <int name="tracks/14/interp"> 1 </int>
- <real_array name="tracks/14/keys" len="24"> 0, 1, 0.0798243, -0.0543702, -2.95838, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.0798243, -0.0543702, -2.95838, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/15/type"> "transform" </string>
- <node_path name="tracks/15/path"> "Armature/Skeleton:l-LEGORIENT" </node_path>
- <int name="tracks/15/interp"> 1 </int>
- <real_array name="tracks/15/keys" len="24"> 0, 1, 0.183564, 0.0305935, -3.02205, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.183564, 0.0305935, -3.02205, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/16/type"> "transform" </string>
- <node_path name="tracks/16/path"> "Armature/Skeleton:r-ARMCONTROL" </node_path>
- <int name="tracks/16/interp"> 1 </int>
- <real_array name="tracks/16/keys" len="24"> 0, 1, -2.74884, 1.12805, 3.06242, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -2.74884, 1.12805, 3.06242, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/17/type"> "transform" </string>
- <node_path name="tracks/17/path"> "Armature/Skeleton:l-ARMCONTROL" </node_path>
- <int name="tracks/17/interp"> 1 </int>
- <real_array name="tracks/17/keys" len="24"> 0, 1, 1.73339, 0.895247, 5.13844, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 1.73339, 0.895247, 5.13844, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/18/type"> "transform" </string>
- <node_path name="tracks/18/path"> "Armature/Skeleton:r-ARMORIENT" </node_path>
- <int name="tracks/18/interp"> 1 </int>
- <real_array name="tracks/18/keys" len="24"> 0, 1, 0.101768, -0.813356, 5.76642, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.101768, -0.813356, 5.76642, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/19/type"> "transform" </string>
- <node_path name="tracks/19/path"> "Armature/Skeleton:l-ARMORIENT" </node_path>
- <int name="tracks/19/interp"> 1 </int>
- <real_array name="tracks/19/keys" len="24"> 0, 1, -0.849557, -0.741664, 5.51935, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.849557, -0.741664, 5.51935, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/20/type"> "transform" </string>
- <node_path name="tracks/20/path"> "Armature/Skeleton:hip" </node_path>
- <int name="tracks/20/interp"> 1 </int>
- <real_array name="tracks/20/keys" len="132"> 0, 1, 2.65402e-07, 1.83685, 0.489514, -5.25643e-15, 1.43922e-08, -0.0635436, 0.997979, 1, 1, 1, 0.05, 1, 2.56992e-07, 1.7811, 0.489514, -1.96073e-14, 1.43922e-08, -0.0635436, 0.997979, 1, 1, 1, 0.1, 1, 2.44553e-07, 1.69876, 0.489514, -1.94961e-14, 1.43922e-08, -0.0635436, 0.997979, 1, 1, 1, 0.15, 1, 2.41683e-07, 1.67977, 0.489514, -4.43536e-14, 1.60316e-08, -0.070782, 0.997492, 1, 1, 1, 0.2, 1, 2.44743e-07, 1.70003, 0.489514, -3.42428e-14, 2.17962e-08, -0.0962332, 0.995359, 1, 1, 1, 0.25, 1, 2.50383e-07, 1.73738, 0.489514, -5.58716e-16, 2.56855e-08, -0.113405, 0.993549, 1, 1, 1, 0.3, 1, 2.57035e-07, 1.78143, 0.489514, -6.36206e-15, 2.33115e-08, -0.102924, 0.994689, 1, 1, 1, 0.35, 1, 2.62333e-07, 1.81652, 0.489514, -1.06935e-14, 1.84103e-08, -0.0812848, 0.996691, 1, 1, 1, 0.4, 1, 2.6496e-07, 1.83392, 0.489514, -2.45344e-14, 1.50179e-08, -0.0663065, 0.997799, 1, 1, 1, 0.45, 1, 2.65402e-07, 1.83685, 0.489514, -5.25643e-15, 1.43922e-08, -0.0635436, 0.997979, 1, 1, 1, 1.25, 1, 2.65402e-07, 1.83685, 0.489514, -5.25643e-15, 1.43922e-08, -0.0635436, 0.997979, 1, 1, 1 </real_array>
- <string name="tracks/21/type"> "transform" </string>
- <node_path name="tracks/21/path"> "Armature/Skeleton:waist" </node_path>
- <int name="tracks/21/interp"> 1 </int>
- <real_array name="tracks/21/keys" len="120"> 0, 1, -4.65684e-10, 7.57313e-10, 0, -8.93894e-16, 2.55708e-08, -0.112898, 0.993607, 1, 1, 1, 0.05, 1, -4.18389e-09, 6.71868e-09, -2.98023e-08, -0.00385828, -0.000945429, -0.112898, 0.993599, 1, 1, 1, 0.1, 1, -2.6989e-09, 6.71803e-09, -2.98023e-08, -0.0118093, -0.00289381, -0.11289, 0.993533, 1, 1, 1, 0.15, 1, -1.65698e-09, 6.19854e-09, -1.19209e-07, -0.0173041, -0.00424031, -0.112881, 0.993449, 1, 1, 1, 0.2, 1, 6.17568e-09, 2.79554e-08, -1.78814e-07, -0.0174121, -0.00426678, -0.11288, 0.993447, 1, 1, 1, 0.25, 1, -9.69976e-10, -3.44268e-09, -2.98023e-08, -0.013893, -0.00340444, -0.112887, 0.993505, 1, 1, 1, 0.35, 1, 8.55826e-09, 2.92274e-08, -2.98023e-08, -0.00310744, -0.000761444, -0.112898, 0.993601, 1, 1, 1, 0.4, 1, 2.05826e-09, 1.24848e-08, 0, -0.000452603, -0.000110883, -0.112898, 0.993606, 1, 1, 1, 0.45, 1, -4.65684e-10, 7.57313e-10, 0, -8.93894e-16, 2.55708e-08, -0.112898, 0.993607, 1, 1, 1, 1.25, 1, -4.65684e-10, 7.57313e-10, 0, -8.93894e-16, 2.55708e-08, -0.112898, 0.993607, 1, 1, 1 </real_array>
- <string name="tracks/22/type"> "transform" </string>
- <node_path name="tracks/22/path"> "Armature/Skeleton:chest" </node_path>
- <int name="tracks/22/interp"> 1 </int>
- <real_array name="tracks/22/keys" len="108"> 0, 1, -7.51303e-09, 2.23517e-08, -2.38419e-07, 2.43554e-09, -0.00270918, 0.0663084, 0.997796, 1, 1, 1, 0.05, 1, -5.41336e-11, 3.72529e-09, -2.38419e-07, -0.00158657, -0.00317713, 0.0662892, 0.997794, 1, 1, 1, 0.15, 1, -3.26683e-10, 0, 5.96046e-08, -0.00925885, -0.00543992, 0.0661937, 0.997749, 1, 1, 1, 0.2, 1, -2.06055e-09, 1.49012e-08, -2.38419e-07, -0.0112141, -0.00601653, 0.0661687, 0.997727, 1, 1, 1, 0.25, 1, 1.76951e-08, -3.72529e-09, -1.78814e-07, -0.0104022, -0.00577711, 0.0661791, 0.997737, 1, 1, 1, 0.35, 1, 7.20902e-09, 7.45058e-09, -1.19209e-07, -0.00273, -0.00351437, 0.0662752, 0.997791, 1, 1, 1, 0.4, 1, 4.13622e-10, 3.72529e-09, -1.78814e-07, -0.000405934, -0.00282891, 0.0663035, 0.997795, 1, 1, 1, 0.45, 1, -7.51303e-09, 2.23517e-08, -2.38419e-07, 2.43554e-09, -0.00270918, 0.0663084, 0.997796, 1, 1, 1, 1.25, 1, -7.51303e-09, 2.23517e-08, -2.38419e-07, 2.43554e-09, -0.00270918, 0.0663084, 0.997796, 1, 1, 1 </real_array>
- <string name="tracks/23/type"> "transform" </string>
- <node_path name="tracks/23/path"> "Armature/Skeleton:neck" </node_path>
- <int name="tracks/23/interp"> 1 </int>
- <real_array name="tracks/23/keys" len="24"> 0, 1, 4.48992e-09, -1.3411e-07, -1.07288e-06, -1.49012e-08, 7.81341e-10, 2.3736e-09, 1, 1, 1, 1, 1.25, 1, 4.48992e-09, -1.3411e-07, -1.07288e-06, -1.49012e-08, 7.81341e-10, 2.3736e-09, 1, 1, 1, 1 </real_array>
- <string name="tracks/24/type"> "transform" </string>
- <node_path name="tracks/24/path"> "Armature/Skeleton:headtracker" </node_path>
- <int name="tracks/24/interp"> 1 </int>
- <real_array name="tracks/24/keys" len="120"> 0, 1, -1.54592e-09, -2.38419e-07, -3.32948e-08, 0.0746069, -0.101992, 0.0306522, 0.99151, 1, 1, 1, 0.05, 1, -1.11768e-09, -1.19209e-07, -9.73232e-08, 0.0219469, -0.103542, 0.0251775, 0.994064, 1, 1, 1, 0.1, 1, 3.72477e-10, -2.98023e-07, -7.61356e-08, -0.0560921, -0.105311, 0.0169133, 0.992712, 1, 1, 1, 0.15, 1, 1.49005e-09, -3.8743e-07, -9.8953e-08, -0.0807068, -0.112423, 0.0155536, 0.990255, 1, 1, 1, 0.2, 1, 9.68555e-09, -1.78814e-07, -2.06754e-07, -0.0663987, -0.135548, 0.0221852, 0.988294, 1, 1, 1, 0.25, 1, 1.86265e-08, -2.68221e-07, -1.18744e-08, -0.0319373, -0.150579, 0.0303761, 0.987615, 1, 1, 1, 0.35, 1, 7.26442e-09, -6.85453e-07, 3.81842e-08, 0.0516026, -0.119052, 0.0329235, 0.990999, 1, 1, 1, 0.4, 1, -1.48637e-09, -2.38419e-07, -5.07571e-08, 0.0712567, -0.10465, 0.03106, 0.991467, 1, 1, 1, 0.45, 1, -1.54592e-09, -2.38419e-07, -3.32948e-08, 0.0746069, -0.101992, 0.0306522, 0.99151, 1, 1, 1, 1.25, 1, -1.54592e-09, -2.38419e-07, -3.32948e-08, 0.0746069, -0.101992, 0.0306522, 0.99151, 1, 1, 1 </real_array>
- <string name="tracks/25/type"> "transform" </string>
- <node_path name="tracks/25/path"> "Armature/Skeleton:head" </node_path>
- <int name="tracks/25/interp"> 1 </int>
- <real_array name="tracks/25/keys" len="24"> 0, 1, 3.53794e-09, -1.25496e-07, -8.33534e-08, 2.23517e-08, 1.01485e-10, -1.43572e-10, 1, 1, 1, 1, 1.25, 1, 3.53794e-09, -1.25496e-07, -8.33534e-08, 2.23517e-08, 1.01485e-10, -1.43572e-10, 1, 1, 1, 1 </real_array>
- <string name="tracks/26/type"> "transform" </string>
- <node_path name="tracks/26/path"> "Armature/Skeleton:vent" </node_path>
- <int name="tracks/26/interp"> 1 </int>
- <real_array name="tracks/26/keys" len="24"> 0, 1, 1.23685e-09, 2.38419e-07, -5.96046e-07, -2.32831e-09, -1.31362e-12, 1.19249e-11, 1, 1, 1, 1, 1.25, 1, 1.23685e-09, 2.38419e-07, -5.96046e-07, -2.32831e-09, -1.31362e-12, 1.19249e-11, 1, 1, 1, 1 </real_array>
-
- </resource>
- <resource type="Animation" path="local://11">
- <string name="resource/name"> "falling-cycle" </string>
- <real name="length"> 0.416667 </real>
- <bool name="loop"> True </bool>
- <real name="step"> 0.1 </real>
- <string name="tracks/0/type"> "transform" </string>
- <node_path name="tracks/0/path"> "Armature/Skeleton:r-arm" </node_path>
- <int name="tracks/0/interp"> 1 </int>
- <real_array name="tracks/0/keys" len="132"> 0, 1, 2.98023e-08, 1.19209e-07, -2.98023e-08, -0.336022, 0.262721, 0.175267, 0.887326, 1, 1, 1, 0.05, 1, 7.45058e-07, -3.57628e-07, 5.36442e-07, -0.336851, 0.262046, 0.173695, 0.887521, 1, 1, 1, 0.1, 1, 8.34465e-07, -5.96046e-07, 7.15256e-07, -0.33853, 0.260365, 0.16952, 0.888184, 1, 1, 1, 0.15, 1, 8.9407e-07, -3.57628e-07, 8.9407e-07, -0.338209, 0.258327, 0.163568, 0.890015, 1, 1, 1, 0.2, 1, 5.96046e-07, -3.57628e-07, 7.45058e-07, -0.333363, 0.256341, 0.157703, 0.89347, 1, 1, 1, 0.25, 1, 1.43051e-06, -8.34465e-07, 1.3113e-06, -0.339001, 0.253177, 0.158008, 0.892196, 1, 1, 0.999999, 0.3, 1, 5.96046e-07, -1.19209e-07, 2.98023e-07, -0.348081, 0.252511, 0.164449, 0.887713, 1, 1, 1, 0.35, 1, 1.07288e-06, -5.96046e-07, 7.45058e-07, -0.343056, 0.25799, 0.170697, 0.886914, 1, 1, 1, 0.4, 1, 3.27826e-07, 0, 2.38419e-07, -0.337258, 0.26196, 0.174599, 0.887214, 1, 1, 1, 0.45, 1, 2.98023e-08, 1.19209e-07, -2.98023e-08, -0.336022, 0.262721, 0.175267, 0.887326, 1, 1, 1, 1.25, 1, 2.98023e-08, 1.19209e-07, -2.98023e-08, -0.336022, 0.262721, 0.175267, 0.887326, 1, 1, 1 </real_array>
- <string name="tracks/1/type"> "transform" </string>
- <node_path name="tracks/1/path"> "Armature/Skeleton:r-forearm" </node_path>
- <int name="tracks/1/interp"> 1 </int>
- <real_array name="tracks/1/keys" len="120"> 0, 1, 3.27826e-07, -6.55651e-07, -4.17233e-07, 0.46904, -0.387773, 0.0221851, 0.793184, 1, 1, 1, 0.05, 1, -1.49012e-07, -8.34465e-07, -5.36442e-07, 0.467449, -0.38757, 0.0209387, 0.794256, 1, 0.999999, 1, 0.15, 1, 8.9407e-08, -8.34465e-07, -2.38419e-07, 0.457674, -0.38779, 0.0142454, 0.799969, 1, 1, 1, 0.2, 1, -1.19209e-07, -9.53674e-07, -5.96046e-07, 0.453414, -0.391376, 0.0115749, 0.800692, 1, 1, 1, 0.25, 1, -2.98023e-08, -8.64267e-07, -5.96046e-07, 0.455951, -0.392917, 0.0127032, 0.798476, 1, 1, 1, 0.3, 1, -2.68221e-07, -5.96046e-07, -3.57628e-07, 0.461696, -0.389009, 0.0167183, 0.797013, 1, 1, 1, 0.35, 1, 5.96046e-08, -9.23872e-07, -5.96046e-07, 0.465445, -0.38698, 0.0198743, 0.795747, 1, 1, 1, 0.4, 1, 2.68221e-07, -8.64267e-07, -6.55651e-07, 0.4685, -0.387548, 0.0218417, 0.793623, 1, 1, 1, 0.45, 1, 3.27826e-07, -6.55651e-07, -4.17233e-07, 0.46904, -0.387773, 0.0221851, 0.793184, 1, 1, 1, 1.25, 1, 3.27826e-07, -6.55651e-07, -4.17233e-07, 0.46904, -0.387773, 0.0221851, 0.793184, 1, 1, 1 </real_array>
- <string name="tracks/2/type"> "transform" </string>
- <node_path name="tracks/2/path"> "Armature/Skeleton:l-arm" </node_path>
- <int name="tracks/2/interp"> 1 </int>
- <real_array name="tracks/2/keys" len="132"> 0, 1, -2.98023e-08, 1.19209e-07, -2.98023e-08, -0.326141, -0.23441, -0.185472, 0.896819, 1, 1, 1, 0.05, 1, -9.53674e-07, -4.76837e-07, 5.66244e-07, -0.309655, -0.239675, -0.179325, 0.902503, 1, 1, 1, 0.1, 1, -8.64267e-07, -4.76837e-07, 7.15256e-07, -0.27681, -0.251556, -0.166111, 0.912416, 1, 1, 1, 0.15, 1, -8.64267e-07, -3.57628e-07, 8.04663e-07, -0.254018, -0.264552, -0.15679, 0.917008, 1, 1, 1, 0.2, 1, -4.76837e-07, -3.57628e-07, 4.47035e-07, -0.251196, -0.272504, -0.156931, 0.915431, 1, 1, 1, 0.25, 1, -1.13249e-06, -7.15256e-07, 8.9407e-07, -0.279016, -0.258742, -0.169921, 0.909027, 1, 1, 1, 0.3, 1, -7.15256e-07, 1.19209e-07, 5.06639e-07, -0.316679, -0.238757, -0.183476, 0.89947, 1, 1, 1, 0.35, 1, -6.25849e-07, -1.19209e-07, 3.57628e-07, -0.327726, -0.235686, -0.18601, 0.895795, 1, 1, 1, 0.4, 1, -2.68221e-07, 0, 1.49012e-07, -0.326797, -0.234512, -0.185665, 0.896514, 1, 1, 1, 0.45, 1, -2.98023e-08, 1.19209e-07, -2.98023e-08, -0.326141, -0.23441, -0.185472, 0.896819, 1, 1, 1, 1.25, 1, -2.98023e-08, 1.19209e-07, -2.98023e-08, -0.326141, -0.23441, -0.185472, 0.896819, 1, 1, 1 </real_array>
- <string name="tracks/3/type"> "transform" </string>
- <node_path name="tracks/3/path"> "Armature/Skeleton:l-forearm" </node_path>
- <int name="tracks/3/interp"> 1 </int>
- <real_array name="tracks/3/keys" len="120"> 0, 1, -2.08616e-07, -1.54972e-06, -1.19209e-07, 0.47174, 0.366267, -0.0198596, 0.80182, 1, 1, 1, 0.05, 1, -2.98023e-08, -6.25849e-07, 0, 0.468656, 0.375596, -0.0166676, 0.799382, 1, 1, 1, 0.1, 1, -8.9407e-08, -2.68221e-07, -5.96046e-08, 0.459943, 0.392089, -0.0107327, 0.79662, 1, 1, 1, 0.15, 1, -2.08616e-07, -2.08616e-07, -2.38419e-07, 0.451048, 0.400355, -0.00696642, 0.797636, 1, 1, 1, 0.2, 1, -2.38419e-07, -7.7486e-07, 0, 0.448637, 0.398723, -0.00658308, 0.799813, 1, 1, 1, 0.3, 1, -5.96046e-08, -2.98023e-07, -4.17233e-07, 0.465357, 0.361793, -0.0151844, 0.807662, 1, 1, 1, 0.35, 1, -1.49012e-07, -5.36442e-07, -3.57628e-07, 0.468536, 0.360417, -0.0183993, 0.806372, 1, 1, 1, 0.4, 1, -5.96046e-08, -8.64267e-07, -1.78814e-07, 0.471244, 0.365087, -0.0196777, 0.802654, 1, 1, 1, 0.45, 1, -2.08616e-07, -1.54972e-06, -1.19209e-07, 0.47174, 0.366267, -0.0198596, 0.80182, 1, 1, 1, 1.25, 1, -2.08616e-07, -1.54972e-06, -1.19209e-07, 0.47174, 0.366267, -0.0198596, 0.80182, 1, 1, 1 </real_array>
- <string name="tracks/4/type"> "transform" </string>
- <node_path name="tracks/4/path"> "Armature/Skeleton:r-thigh" </node_path>
- <int name="tracks/4/interp"> 1 </int>
- <real_array name="tracks/4/keys" len="132"> 0, 1, 0, 7.45058e-09, -1.3411e-07, -0.0625169, 0.00920125, -0.00328561, 0.997996, 1, 1, 1, 0.05, 1, 5.96046e-08, 8.9407e-08, -6.10948e-07, -0.0877092, 0.00901381, -0.00306586, 0.996101, 1, 1, 1, 0.1, 1, 5.96046e-08, -2.23517e-08, -1.19209e-07, -0.138998, 0.00794913, -0.00288258, 0.990257, 1, 1, 1, 0.15, 1, 5.96046e-08, 1.49012e-08, -4.02331e-07, -0.178155, 0.00579277, -0.00296187, 0.983981, 1, 1, 1, 0.2, 1, 8.9407e-08, 0, 1.78814e-07, -0.18648, 0.0038127, -0.0029159, 0.982447, 1, 1, 1, 0.25, 1, 5.96046e-08, 5.21541e-08, -1.93715e-07, -0.189861, 0.00940162, -0.00299906, 0.981761, 1, 1, 1, 0.3, 1, 5.96046e-08, -5.96046e-08, 2.83122e-07, -0.170763, 0.015059, -0.00307746, 0.985192, 1, 1, 1, 0.35, 1, 0, -7.45058e-09, -1.3411e-07, -0.115285, 0.0123617, -0.00312517, 0.993251, 1, 1, 1, 0.4, 1, 0, 7.45058e-09, -1.3411e-07, -0.0713277, 0.00977016, -0.00325209, 0.9974, 1, 1, 1, 0.45, 1, 0, 7.45058e-09, -1.3411e-07, -0.0625169, 0.00920125, -0.00328561, 0.997996, 1, 1, 1, 1.25, 1, 0, 7.45058e-09, -1.3411e-07, -0.0625169, 0.00920125, -0.00328561, 0.997996, 1, 1, 1 </real_array>
- <string name="tracks/5/type"> "transform" </string>
- <node_path name="tracks/5/path"> "Armature/Skeleton:r-leg" </node_path>
- <int name="tracks/5/interp"> 1 </int>
- <real_array name="tracks/5/keys" len="120"> 0, 1, 4.42378e-08, -8.19564e-08, 1.78814e-07, -0.407694, 0.0277893, 0.000765211, 0.912696, 1, 1, 1, 0.05, 1, 1.89757e-08, -5.21541e-08, 6.55651e-07, -0.435809, 0.0297697, 0.000893482, 0.899546, 1, 1, 1, 0.1, 1, 1.42027e-08, 6.70552e-08, 7.15256e-07, -0.489147, 0.0339313, 0.00115069, 0.871541, 1, 1, 1, 0.15, 1, 1.13854e-07, 0, 5.96046e-07, -0.523927, 0.0370339, 0.00133512, 0.850957, 1, 1, 1, 0.2, 1, 1.29221e-07, -3.72529e-08, 4.17233e-07, -0.526448, 0.0372296, 0.00134975, 0.849391, 1, 1, 1, 0.25, 1, 1.6077e-07, -2.68221e-07, 4.76837e-07, -0.538369, 0.0372441, 0.00135905, 0.841885, 1, 1, 1, 0.3, 1, 6.17001e-09, -1.04308e-07, 7.15256e-07, -0.530237, 0.0358611, 0.00127618, 0.84709, 1, 1, 1, 0.4, 1, 2.08383e-08, -2.23517e-08, 4.17233e-07, -0.418447, 0.0284447, 0.00080823, 0.907795, 1, 1, 1, 0.45, 1, 4.42378e-08, -8.19564e-08, 1.78814e-07, -0.407694, 0.0277893, 0.000765211, 0.912696, 1, 1, 1, 1.25, 1, 4.42378e-08, -8.19564e-08, 1.78814e-07, -0.407694, 0.0277893, 0.000765211, 0.912696, 1, 1, 1 </real_array>
- <string name="tracks/6/type"> "transform" </string>
- <node_path name="tracks/6/path"> "Armature/Skeleton:r-foot" </node_path>
- <int name="tracks/6/interp"> 1 </int>
- <real_array name="tracks/6/keys" len="24"> 0, 1, 1.04308e-07, -1.19209e-07, 6.70552e-08, -1.11759e-08, 1.16415e-09, 7.45058e-09, 1, 1, 1, 1, 1.25, 1, 1.04308e-07, -1.19209e-07, 6.70552e-08, -1.11759e-08, 1.16415e-09, 7.45058e-09, 1, 1, 1, 1 </real_array>
- <string name="tracks/7/type"> "transform" </string>
- <node_path name="tracks/7/path"> "Armature/Skeleton:l-thigh" </node_path>
- <int name="tracks/7/interp"> 1 </int>
- <real_array name="tracks/7/keys" len="120"> 0, 1, -2.98023e-08, 1.49012e-08, 1.19209e-07, -0.630421, -0.0882657, 0.00990556, 0.771155, 1, 1, 1, 0.05, 1, 8.9407e-08, 9.68575e-08, -2.38419e-07, -0.641086, -0.0918399, 0.00914405, 0.7619, 1, 1, 1, 0.15, 1, 5.96046e-08, 2.23517e-08, -1.3411e-07, -0.695929, -0.109196, 0.0054072, 0.70974, 1, 1, 1, 0.2, 1, 0, 7.45058e-09, 4.61936e-07, -0.716484, -0.115048, 0.00471066, 0.688035, 0.999999, 1, 1, 0.25, 1, 2.98023e-08, 5.21541e-08, 7.45058e-08, -0.742062, -0.116709, 0.0109015, 0.660003, 1, 1, 1, 0.3, 1, -5.96046e-08, -6.70552e-08, 5.51343e-07, -0.738131, -0.110711, 0.0165993, 0.665304, 0.999999, 1, 1, 0.35, 1, -2.98023e-08, -1.49012e-08, 1.19209e-07, -0.683291, -0.098194, 0.0131016, 0.723395, 1, 1, 1, 0.4, 1, -2.98023e-08, 1.49012e-08, 1.19209e-07, -0.638973, -0.0897534, 0.0103931, 0.763904, 1, 1, 1, 0.45, 1, -2.98023e-08, 1.49012e-08, 1.19209e-07, -0.630421, -0.0882657, 0.00990556, 0.771155, 1, 1, 1, 1.25, 1, -2.98023e-08, 1.49012e-08, 1.19209e-07, -0.630421, -0.0882657, 0.00990556, 0.771155, 1, 1, 1 </real_array>
- <string name="tracks/8/type"> "transform" </string>
- <node_path name="tracks/8/path"> "Armature/Skeleton:l-leg" </node_path>
- <int name="tracks/8/interp"> 1 </int>
- <real_array name="tracks/8/keys" len="120"> 0, 1, 4.48199e-08, -1.11759e-07, 1.78814e-07, -0.822993, -0.106344, -0.00540277, 0.557982, 1, 1, 1, 0.05, 1, 4.30737e-09, -2.08616e-07, -1.19209e-07, -0.827005, -0.107477, -0.00546779, 0.551799, 1, 1, 1, 0.1, 1, 8.84756e-09, -1.19209e-07, 1.19209e-07, -0.836608, -0.110063, -0.00562015, 0.536601, 1, 1, 1, 0.2, 1, -2.91038e-08, 1.19209e-07, 0, -0.857806, -0.115929, -0.00596456, 0.500693, 1, 1, 1, 0.25, 1, 7.33417e-09, 0, 5.96046e-08, 0.876669, 0.123709, 0.00633999, -0.464874, 1, 1, 1, 0.3, 1, -4.38886e-08, -1.3411e-07, -1.19209e-07, 0.881066, 0.125876, 0.00641456, -0.455891, 1, 1, 1, 0.35, 1, 9.66247e-09, 0, -5.96046e-08, -0.853515, -0.11545, -0.00587343, 0.508083, 1, 1, 1, 0.4, 1, 2.17697e-08, -3.72529e-08, 5.96046e-08, -0.828218, -0.107764, -0.00547631, 0.549921, 1, 1, 1, 0.45, 1, 4.48199e-08, -1.11759e-07, 1.78814e-07, -0.822993, -0.106344, -0.00540277, 0.557982, 1, 1, 1, 1.25, 1, 4.48199e-08, -1.11759e-07, 1.78814e-07, -0.822993, -0.106344, -0.00540277, 0.557982, 1, 1, 1 </real_array>
- <string name="tracks/9/type"> "transform" </string>
- <node_path name="tracks/9/path"> "Armature/Skeleton:l-foot" </node_path>
- <int name="tracks/9/interp"> 1 </int>
- <real_array name="tracks/9/keys" len="24"> 0, 1, 7.45058e-09, -2.38419e-07, -8.19564e-08, -1.86265e-08, -1.28057e-09, 3.72529e-09, 1, 1, 1, 1, 1.25, 1, 7.45058e-09, -2.38419e-07, -8.19564e-08, -1.86265e-08, -1.28057e-09, 3.72529e-09, 1, 1, 1, 1 </real_array>
- <string name="tracks/10/type"> "transform" </string>
- <node_path name="tracks/10/path"> "Armature/Skeleton:MASTER" </node_path>
- <int name="tracks/10/interp"> 1 </int>
- <real_array name="tracks/10/keys" len="24"> 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/11/type"> "transform" </string>
- <node_path name="tracks/11/path"> "Armature/Skeleton:HEAD" </node_path>
- <int name="tracks/11/interp"> 1 </int>
- <real_array name="tracks/11/keys" len="108"> 0, 1, -5.68434e-14, 0, 2.81136, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -5.68434e-14, 0, 2.88275, 0, 0, 0, 1, 1, 1, 1, 0.15, 1, 5.68434e-14, 4.76837e-07, 3.22584, 0, 0, 0, 1, 1, 1, 1, 0.2, 1, 5.68434e-14, 4.76837e-07, 3.31311, 0, 0, -7.10543e-15, 1, 1, 1, 1, 0.25, 1, 5.68434e-14, 4.76837e-07, 3.27685, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, -5.68434e-14, 0, 2.93405, 0, 0, -7.10543e-15, 1, 1, 1, 1, 0.4, 1, -5.68434e-14, 0, 2.82965, 0, 0, 0, 1, 1, 1, 1, 0.45, 1, -5.68434e-14, 0, 2.81136, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -5.68434e-14, 0, 2.81136, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/12/type"> "transform" </string>
- <node_path name="tracks/12/path"> "Armature/Skeleton:r-LEGCONTROL" </node_path>
- <int name="tracks/12/interp"> 1 </int>
- <real_array name="tracks/12/keys" len="120"> 0, 1, -5.96046e-08, 0.623878, 0.831837, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -5.96046e-08, 0.623878, 0.85661, 0, 0, 0, 1, 1, 1, 1, 0.1, 1, -5.96046e-08, 0.623878, 0.907642, 0, 0, 0, 1, 1, 1, 1, 0.15, 1, -5.96046e-08, 0.623878, 0.942906, 0, 0, 0, 1, 1, 1, 1, 0.2, 1, -5.96046e-08, 0.623878, 0.943599, 0, 0, 0, 1, 1, 1, 1, 0.25, 1, -5.96046e-08, 0.623878, 0.921011, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, -5.96046e-08, 0.623878, 0.851786, 0, 0, 0, 1, 1, 1, 1, 0.4, 1, -5.96046e-08, 0.623878, 0.834743, 0, 0, 0, 1, 1, 1, 1, 0.45, 1, -5.96046e-08, 0.623878, 0.831837, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -5.96046e-08, 0.623878, 0.831837, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/13/type"> "transform" </string>
- <node_path name="tracks/13/path"> "Armature/Skeleton:l-LEGCONTROL" </node_path>
- <int name="tracks/13/interp"> 1 </int>
- <real_array name="tracks/13/keys" len="132"> 0, 1, -1.19209e-07, 1.00668e-07, 1.33339, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -1.19209e-07, 1.01535e-07, 1.34488, 0, 0, 0, 1, 1, 1, 1, 0.1, 1, -1.19209e-07, 1.0373e-07, 1.37395, 0, 0, 0, 1, 1, 1, 1, 0.15, 1, -1.19209e-07, 1.06482e-07, 1.41041, 0, 0, 0, 1, 1, 1, 1, 0.2, 1, -1.19209e-07, 1.08677e-07, 1.43947, 0, 0, 0, 1, 1, 1, 1, 0.25, 1, -1.19209e-07, 1.09544e-07, 1.45096, 0, 0, 0, 1, 1, 1, 1, 0.3, 1, -1.19209e-07, 1.07675e-07, 1.4262, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, -1.19209e-07, 1.03822e-07, 1.37517, 0, 0, 0, 1, 1, 1, 1, 0.4, 1, -1.19209e-07, 1.01159e-07, 1.33989, 0, 0, 0, 1, 1, 1, 1, 0.45, 1, -1.19209e-07, 1.00668e-07, 1.33339, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -1.19209e-07, 1.00668e-07, 1.33339, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/14/type"> "transform" </string>
- <node_path name="tracks/14/path"> "Armature/Skeleton:r-LEGORIENT" </node_path>
- <int name="tracks/14/interp"> 1 </int>
- <real_array name="tracks/14/keys" len="24"> 0, 1, -2.98023e-08, 1.19209e-07, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -2.98023e-08, 1.19209e-07, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/15/type"> "transform" </string>
- <node_path name="tracks/15/path"> "Armature/Skeleton:l-LEGORIENT" </node_path>
- <int name="tracks/15/interp"> 1 </int>
- <real_array name="tracks/15/keys" len="24"> 0, 1, 2.98023e-08, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 2.98023e-08, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/16/type"> "transform" </string>
- <node_path name="tracks/16/path"> "Armature/Skeleton:r-ARMCONTROL" </node_path>
- <int name="tracks/16/interp"> 1 </int>
- <real_array name="tracks/16/keys" len="132"> 0, 1, -1.39671, 2.72686, 1.19541, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -1.39671, 2.70532, 1.19971, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, -1.39671, 2.65088, 1.2106, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.15, 1, -1.39671, 2.5826, 1.22425, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.2, 1, -1.39671, 2.52819, 1.23514, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.25, 1, -1.39671, 2.50668, 1.23944, 0, 0, 0, 1, 1, 1, 1, 0.3, 1, -1.39671, 2.55303, 1.23017, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.35, 1, -1.39671, 2.64856, 1.21105, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, -1.39671, 2.71466, 1.19784, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, -1.39671, 2.72686, 1.19541, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -1.39671, 2.72686, 1.19541, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/17/type"> "transform" </string>
- <node_path name="tracks/17/path"> "Armature/Skeleton:l-ARMCONTROL" </node_path>
- <int name="tracks/17/interp"> 1 </int>
- <real_array name="tracks/17/keys" len="120"> 0, 1, 1.27388, 2.72686, 1.19541, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 1.27388, 2.68042, 1.20468, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, 1.27388, 2.58486, 1.2238, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.15, 1, 1.27388, 2.51885, 1.23701, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.2, 1, 1.27388, 2.51756, 1.23727, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.25, 1, 1.27388, 2.55985, 1.22881, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, 1.27388, 2.68948, 1.20288, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, 1.27388, 2.72141, 1.19649, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, 1.27388, 2.72686, 1.19541, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 1.27388, 2.72686, 1.19541, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/18/type"> "transform" </string>
- <node_path name="tracks/18/path"> "Armature/Skeleton:r-ARMORIENT" </node_path>
- <int name="tracks/18/interp"> 1 </int>
- <real_array name="tracks/18/keys" len="24"> 0, 1, 0.59069, -0.00390959, 0.736489, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.59069, -0.00390959, 0.736489, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/19/type"> "transform" </string>
- <node_path name="tracks/19/path"> "Armature/Skeleton:l-ARMORIENT" </node_path>
- <int name="tracks/19/interp"> 1 </int>
- <real_array name="tracks/19/keys" len="24"> 0, 1, -0.59069, -0.00390959, 0.736489, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.59069, -0.00390959, 0.736489, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/20/type"> "transform" </string>
- <node_path name="tracks/20/path"> "Armature/Skeleton:hip" </node_path>
- <int name="tracks/20/interp"> 1 </int>
- <real_array name="tracks/20/keys" len="120"> 0, 1, -9.25123e-16, 1.16368e-07, -0.513782, -0.068257, 1.03065e-08, 8.40178e-15, 0.997668, 1, 1, 1, 0.05, 1, -0.00604435, -0.0171726, -0.516875, -0.068257, 1.03065e-08, 1.59689e-14, 0.997668, 1, 1, 1, 0.15, 1, -0.0352723, -0.100186, -0.531832, -0.068257, 1.03065e-08, 8.79127e-15, 0.997668, 1, 1, 1, 0.2, 1, -0.0427212, -0.121339, -0.535645, -0.068257, 1.03065e-08, 1.59689e-14, 0.997668, 1, 1, 1, 0.25, 1, -0.0251165, -0.102747, -0.494262, -0.068257, 1.03065e-08, 8.40178e-15, 0.997668, 1, 1, 1, 0.3, 1, -0.00387635, -0.0612733, -0.455449, -0.068257, 1.03065e-08, 8.79127e-15, 0.997668, 1, 1, 1, 0.35, 1, -0.000906605, -0.0266833, -0.479965, -0.068257, 1.03065e-08, 1.59689e-14, 0.997668, 1, 1, 1, 0.4, 1, -5.88306e-05, -0.00401501, -0.507859, -0.068257, 1.03065e-08, 8.79127e-15, 0.997668, 1, 1, 1, 0.45, 1, -9.25123e-16, 1.16368e-07, -0.513782, -0.068257, 1.03065e-08, 8.40178e-15, 0.997668, 1, 1, 1, 1.25, 1, -9.25123e-16, 1.16368e-07, -0.513782, -0.068257, 1.03065e-08, 8.40178e-15, 0.997668, 1, 1, 1 </real_array>
- <string name="tracks/21/type"> "transform" </string>
- <node_path name="tracks/21/path"> "Armature/Skeleton:waist" </node_path>
- <int name="tracks/21/interp"> 1 </int>
- <real_array name="tracks/21/keys" len="108"> 0, 1, -5.25618e-15, 1.49011e-08, -1.49012e-07, 0.0904093, -6.07213e-16, 7.18977e-15, 0.995905, 1, 1, 1, 0.05, 1, -2.67973e-10, 2.32644e-08, -5.96046e-08, 0.0920949, -3.47794e-16, 7.16792e-15, 0.99575, 1, 1, 1, 0.15, 1, 2.52298e-09, 2.61876e-08, -2.98023e-08, 0.100243, -1.17281e-15, 7.25956e-15, 0.994963, 1, 1, 1, 0.2, 1, -5.62989e-10, 3.32728e-08, -1.49012e-07, 0.102318, -1.15767e-15, 7.26199e-15, 0.994752, 1, 1, 1, 0.25, 1, -1.24048e-09, 3.35948e-08, -8.9407e-08, 0.101456, -6.3375e-16, 7.20691e-15, 0.99484, 1, 1, 1, 0.35, 1, 8.229e-13, 2.99392e-08, -1.49012e-07, 0.0933096, -3.39049e-16, 7.16834e-15, 0.995637, 1, 1, 1, 0.4, 1, -3.31995e-12, 2.53408e-08, -1.49012e-07, 0.0908406, -1.44454e-15, 1.31767e-16, 0.995865, 1, 1, 1, 0.45, 1, -5.25618e-15, 1.49011e-08, -1.49012e-07, 0.0904093, -6.07213e-16, 7.18977e-15, 0.995905, 1, 1, 1, 1.25, 1, -5.25618e-15, 1.49011e-08, -1.49012e-07, 0.0904093, -6.07213e-16, 7.18977e-15, 0.995905, 1, 1, 1 </real_array>
- <string name="tracks/22/type"> "transform" </string>
- <node_path name="tracks/22/path"> "Armature/Skeleton:chest" </node_path>
- <int name="tracks/22/interp"> 1 </int>
- <real_array name="tracks/22/keys" len="108"> 0, 1, -1.31025e-21, 7.45058e-09, -1.78814e-07, 0.0570428, -7.52314e-16, -1.03276e-15, 0.998372, 1, 1, 1, 0.05, 1, -6.93196e-14, 7.45058e-09, 0, 0.0590419, -0.00284152, 0.000283556, 0.998251, 1, 1, 1, 0.15, 1, 7.44988e-10, -3.72529e-09, 0, 0.0686997, -0.0165823, 0.00165476, 0.997498, 1, 1, 1, 0.2, 1, -7.04617e-14, -7.45058e-09, -5.96046e-08, 0.0711578, -0.0200834, 0.00200414, 0.997261, 1, 1, 1, 0.25, 1, -6.96491e-14, -3.72529e-09, -5.96046e-08, 0.0701373, -0.0186297, 0.00185908, 0.997362, 1, 1, 1, 0.35, 1, 6.97804e-11, 7.45058e-09, -1.78814e-07, 0.0604823, -0.00488944, 0.000487919, 0.998157, 1, 1, 1, 0.4, 1, -2.75782e-14, 1.11759e-08, -2.38419e-07, 0.0575543, -0.000727023, 7.25494e-05, 0.998342, 1, 1, 1, 0.45, 1, -1.31025e-21, 7.45058e-09, -1.78814e-07, 0.0570428, -7.52314e-16, -1.03276e-15, 0.998372, 1, 1, 1, 1.25, 1, -1.31025e-21, 7.45058e-09, -1.78814e-07, 0.0570428, -7.52314e-16, -1.03276e-15, 0.998372, 1, 1, 1 </real_array>
- <string name="tracks/23/type"> "transform" </string>
- <node_path name="tracks/23/path"> "Armature/Skeleton:neck" </node_path>
- <int name="tracks/23/interp"> 1 </int>
- <real_array name="tracks/23/keys" len="24"> 0, 1, -8.52651e-14, -4.47035e-08, -4.76837e-07, -7.45058e-09, 2.13163e-14, -1.77636e-15, 1, 1, 1, 1, 1.25, 1, -8.52651e-14, -4.47035e-08, -4.76837e-07, -7.45058e-09, 2.13163e-14, -1.77636e-15, 1, 1, 1, 1 </real_array>
- <string name="tracks/24/type"> "transform" </string>
- <node_path name="tracks/24/path"> "Armature/Skeleton:headtracker" </node_path>
- <int name="tracks/24/interp"> 1 </int>
- <real_array name="tracks/24/keys" len="120"> 0, 1, 1.77636e-14, -4.17233e-07, -3.53903e-08, -0.197724, -1.34662e-08, 4.54456e-08, 0.980258, 1, 1, 1, 0.05, 1, -1.95943e-09, -5.06639e-07, -6.40284e-08, -0.199636, 0.000196518, -0.00285815, 0.979866, 1, 1, 1, 0.15, 1, -2.19083e-08, -2.38419e-07, -5.75092e-08, -0.207914, 0.00144056, -0.0167025, 0.978003, 1, 1, 1, 0.2, 1, 6.08469e-09, -3.8743e-07, -6.33299e-08, -0.209803, 0.00183038, -0.0202351, 0.977533, 1, 1, 1, 0.25, 1, -4.45088e-08, -8.64267e-07, -5.21541e-08, -0.20649, 0.000358444, -0.0190238, 0.978264, 1, 1, 1, 0.3, 1, 7.56265e-09, -8.34465e-07, -4.84288e-08, -0.200537, -0.000986884, -0.0126263, 0.979604, 1, 1, 1, 0.35, 1, 3.42126e-11, -4.17233e-07, -2.37487e-08, -0.198104, -0.000490507, -0.00505109, 0.980168, 1, 1, 1, 0.4, 1, 3.9655e-10, -3.57628e-07, -3.05008e-08, -0.197722, -8.26043e-05, -0.000750033, 0.980258, 1, 1, 1, 0.45, 1, 1.77636e-14, -4.17233e-07, -3.53903e-08, -0.197724, -1.34662e-08, 4.54456e-08, 0.980258, 1, 1, 1, 1.25, 1, 1.77636e-14, -4.17233e-07, -3.53903e-08, -0.197724, -1.34662e-08, 4.54456e-08, 0.980258, 1, 1, 1 </real_array>
- <string name="tracks/25/type"> "transform" </string>
- <node_path name="tracks/25/path"> "Armature/Skeleton:head" </node_path>
- <int name="tracks/25/interp"> 1 </int>
- <real_array name="tracks/25/keys" len="24"> 0, 1, 2.81164e-14, 2.468e-08, 3.32249e-07, 2.23517e-08, -5.32907e-15, 7.10543e-15, 1, 1, 1, 1, 1.25, 1, 2.81164e-14, 2.468e-08, 3.32249e-07, 2.23517e-08, -5.32907e-15, 7.10543e-15, 1, 1, 1, 1 </real_array>
- <string name="tracks/26/type"> "transform" </string>
- <node_path name="tracks/26/path"> "Armature/Skeleton:vent" </node_path>
- <int name="tracks/26/interp"> 1 </int>
- <real_array name="tracks/26/keys" len="24"> 0, 1, 7.99361e-14, 1.49012e-07, -8.34465e-07, 2.43308e-08, 6.21725e-15, -8.59209e-15, 1, 1, 1, 1, 1.25, 1, 7.99361e-14, 1.49012e-07, -8.34465e-07, 2.43308e-08, 6.21725e-15, -8.59209e-15, 1, 1, 1, 1 </real_array>
-
- </resource>
- <resource type="Animation" path="local://12">
- <string name="resource/name"> "walk-cycle" </string>
- <real name="length"> 1.041667 </real>
- <bool name="loop"> True </bool>
- <real name="step"> 0.1 </real>
- <string name="tracks/0/type"> "transform" </string>
- <node_path name="tracks/0/path"> "Armature/Skeleton:r-arm" </node_path>
- <int name="tracks/0/interp"> 1 </int>
- <real_array name="tracks/0/keys" len="228"> 0, 1, 7.7486e-07, -3.57628e-07, 5.66244e-07, 0.132777, -0.115851, -0.0857195, 0.980613, 1, 1, 1, 0.05, 1, 4.17233e-07, 1.19209e-07, 3.27826e-07, 0.136218, -0.113975, -0.0877542, 0.980181, 1, 1, 1, 0.1, 1, 5.06639e-07, -2.38419e-07, 2.98023e-07, 0.144837, -0.108331, -0.0933223, 0.97907, 1, 1, 1, 0.15, 1, 5.36442e-07, -3.57628e-07, 3.57628e-07, 0.15539, -0.0990044, -0.102617, 0.977508, 1, 0.999999, 1, 0.2, 1, 7.15256e-07, -3.57628e-07, 4.47035e-07, 0.162073, -0.0835771, -0.115431, 0.976434, 1, 1, 1, 0.25, 1, 6.25849e-07, -3.57628e-07, 4.17233e-07, 0.160674, -0.0537521, -0.128708, 0.977102, 1, 1, 1, 0.3, 1, 6.85453e-07, -3.57628e-07, 2.98023e-07, 0.144844, 0.00232148, -0.137246, 0.979887, 1, 1, 1, 0.45, 1, 9.53674e-07, -7.15256e-07, 6.85453e-07, 0.0267683, 0.215793, -0.138386, 0.966212, 1, 1, 1, 0.5, 1, 7.7486e-07, -3.57628e-07, 4.17233e-07, -0.00441569, 0.255036, -0.137846, 0.957045, 1, 1, 1, 0.55, 1, 8.34465e-07, -5.96046e-07, 5.36442e-07, -0.00986276, 0.263176, -0.137756, 0.954811, 1, 1, 1, 0.6, 1, 4.76837e-07, 0, 3.8743e-07, 0.0174093, 0.245944, -0.13741, 0.959337, 1, 1, 1, 0.7, 1, 3.27826e-07, -1.19209e-07, 2.68221e-07, 0.12402, 0.181155, -0.127036, 0.967297, 1, 1, 1, 0.75, 1, 7.45058e-07, 0, 4.47035e-07, 0.157369, 0.166922, -0.11544, 0.96646, 1, 1, 1, 0.8, 1, 8.34465e-07, -1.19209e-07, 4.47035e-07, 0.166665, 0.143487, -0.108193, 0.969499, 1, 1, 1, 0.85, 1, 2.98023e-07, 0, 1.49012e-07, 0.164004, 0.0866041, -0.105149, 0.977009, 1, 0.999999, 1, 0.95, 1, 4.76837e-07, 0, 2.38419e-07, 0.144168, -0.0621538, -0.0938402, 0.983131, 1, 1, 1, 1, 1, 8.64267e-07, -4.76837e-07, 6.85453e-07, 0.135099, -0.105557, -0.0876091, 0.98129, 1, 1, 1, 1.05, 1, 7.7486e-07, -3.57628e-07, 5.66244e-07, 0.132777, -0.115851, -0.0857195, 0.980613, 1, 1, 1, 1.25, 1, 7.7486e-07, -3.57628e-07, 5.66244e-07, 0.132777, -0.115851, -0.0857195, 0.980613, 1, 1, 1 </real_array>
- <string name="tracks/1/type"> "transform" </string>
- <node_path name="tracks/1/path"> "Armature/Skeleton:r-forearm" </node_path>
- <int name="tracks/1/interp"> 1 </int>
- <real_array name="tracks/1/keys" len="228"> 0, 1, 7.45058e-07, -8.04663e-07, -8.34465e-07, -0.0607703, -0.240987, 0.00892511, 0.968583, 1, 1, 1, 0.05, 1, -2.98023e-07, -3.57628e-07, 1.78814e-07, -0.0608664, -0.247441, 0.00903588, 0.966947, 1, 0.999999, 1, 0.1, 1, -1.78814e-07, -7.45058e-07, -1.19209e-07, -0.0607357, -0.265635, 0.00908754, 0.962116, 1, 1, 1, 0.15, 1, 4.17233e-07, -8.64267e-07, -4.17233e-07, -0.0586521, -0.298966, 0.00880687, 0.952419, 1, 1, 1, 0.25, 1, 3.8743e-07, -5.96046e-07, -2.98023e-07, -0.0404347, -0.402042, 0.00443354, 0.914717, 1, 1, 1, 0.3, 1, -2.98023e-08, -6.85453e-07, -2.38419e-07, -0.0222657, -0.438743, -0.00390802, 0.898328, 1, 1, 1, 0.35, 1, -3.27826e-07, -2.68221e-07, -1.78814e-07, -0.001747, -0.450439, -0.0151044, 0.892678, 1, 0.999999, 1, 0.4, 1, -2.98023e-08, -3.57628e-07, -4.76837e-07, 0.0165229, -0.440184, -0.0247739, 0.897414, 1, 1, 1, 0.5, 1, 2.98023e-08, -3.27826e-07, 0, 0.0357718, -0.396841, -0.0343986, 0.916545, 1, 1, 1, 0.55, 1, 1.49012e-07, -6.25849e-07, -1.78814e-07, 0.0355214, -0.39013, -0.0350975, 0.919405, 1, 1, 1, 0.6, 1, 1.78814e-07, -5.06639e-07, -5.36442e-07, 0.01977, -0.384514, -0.0345495, 0.92226, 1, 1, 1, 0.65, 1, -1.19209e-07, -4.17233e-07, -2.38419e-07, -0.0162325, -0.357154, -0.033198, 0.933314, 1, 0.999999, 1, 0.75, 1, -2.98023e-08, -3.57628e-07, -2.98023e-07, -0.0986698, -0.203446, -0.0321126, 0.973572, 1, 0.999999, 1, 0.8, 1, 5.96046e-08, -7.45058e-07, -2.38419e-07, -0.110421, -0.161891, -0.0281555, 0.980207, 1, 1, 1, 0.85, 1, 4.76837e-07, -8.04663e-07, -8.34465e-07, -0.104832, -0.172931, -0.0183971, 0.979166, 1, 0.999999, 1, 0.95, 1, 0, -6.55651e-07, -5.96046e-07, -0.0743493, -0.227469, 0.00271093, 0.970939, 1, 1, 1, 1, 1, -2.98023e-08, -3.57628e-07, -2.38419e-07, -0.0636988, -0.238854, 0.00790001, 0.968932, 1, 1, 1, 1.05, 1, 7.45058e-07, -8.04663e-07, -8.34465e-07, -0.0607703, -0.240987, 0.00892511, 0.968583, 1, 1, 1, 1.25, 1, 7.45058e-07, -8.04663e-07, -8.34465e-07, -0.0607703, -0.240987, 0.00892511, 0.968583, 1, 1, 1 </real_array>
- <string name="tracks/2/type"> "transform" </string>
- <node_path name="tracks/2/path"> "Armature/Skeleton:l-arm" </node_path>
- <int name="tracks/2/interp"> 1 </int>
- <real_array name="tracks/2/keys" len="216"> 0, 1, -7.45058e-07, -4.76837e-07, 4.47035e-07, -0.0127337, -0.264935, 0.137763, 0.954289, 1, 1, 1, 0.05, 1, -3.8743e-07, 0, 2.38419e-07, 0.0104992, -0.248758, 0.137429, 0.958709, 1, 1, 1, 0.15, 1, -5.66244e-07, -1.19209e-07, 4.47035e-07, 0.119317, -0.176495, 0.127478, 0.968691, 1, 1, 1, 0.2, 1, -5.06639e-07, -1.19209e-07, 3.27826e-07, 0.156208, -0.160784, 0.115735, 0.967653, 1, 1, 1, 0.25, 1, -4.17233e-07, -1.19209e-07, 2.68221e-07, 0.170588, -0.146234, 0.10696, 0.968543, 1, 0.999999, 1, 0.3, 1, -8.34465e-07, -3.57628e-07, 8.9407e-07, 0.16899, -0.106962, 0.104274, 0.974232, 1, 1, 1, 0.45, 1, -9.23872e-07, -5.96046e-07, 7.7486e-07, 0.141826, 0.058077, 0.0901382, 0.984067, 1, 1, 1, 0.5, 1, -7.7486e-07, -5.96046e-07, 2.98023e-07, 0.134623, 0.0959315, 0.0862667, 0.982462, 1, 1, 1, 0.55, 1, -7.45058e-07, -3.57628e-07, 6.25849e-07, 0.133233, 0.11842, 0.0861958, 0.980202, 1, 1, 1, 0.6, 1, -4.76837e-07, 0, 4.47035e-07, 0.137596, 0.131505, 0.0903706, 0.977551, 1, 1, 1, 0.65, 1, -6.55651e-07, -3.57628e-07, 5.36442e-07, 0.146837, 0.135484, 0.0990691, 0.974817, 1, 1, 1, 0.7, 1, -5.96046e-07, -3.57628e-07, 6.25849e-07, 0.15676, 0.127354, 0.111789, 0.972991, 1, 1, 1, 0.75, 1, -4.17233e-07, 0, 3.8743e-07, 0.161767, 0.101349, 0.126219, 0.973462, 1, 1, 1, 0.8, 1, -6.85453e-07, -3.57628e-07, 5.06639e-07, 0.154473, 0.0449621, 0.136756, 0.977453, 1, 1, 1, 0.95, 1, -6.55651e-07, -2.38419e-07, 4.76837e-07, 0.0363447, -0.203514, 0.138296, 0.968574, 1, 1, 1, 1, 1, -5.96046e-07, -3.57628e-07, 3.57628e-07, -0.00218869, -0.252498, 0.137778, 0.957735, 1, 1, 1, 1.05, 1, -7.45058e-07, -4.76837e-07, 4.47035e-07, -0.0127337, -0.264935, 0.137763, 0.954289, 1, 1, 1, 1.25, 1, -7.45058e-07, -4.76837e-07, 4.47035e-07, -0.0127337, -0.264935, 0.137763, 0.954289, 1, 1, 1 </real_array>
- <string name="tracks/3/type"> "transform" </string>
- <node_path name="tracks/3/path"> "Armature/Skeleton:l-forearm" </node_path>
- <int name="tracks/3/interp"> 1 </int>
- <real_array name="tracks/3/keys" len="192"> 0, 1, 3.57628e-07, -5.96046e-07, -3.57628e-07, 0.0370915, 0.39046, 0.0351404, 0.919201, 1, 1, 1, 0.05, 1, -1.49012e-07, -5.96046e-07, -2.38419e-07, 0.0247868, 0.388139, 0.0345456, 0.92062, 1, 1, 1, 0.1, 1, -3.57628e-07, -5.66244e-07, -4.76837e-07, -0.00839952, 0.367653, 0.0329431, 0.929342, 1, 1, 1, 0.15, 1, -1.78814e-07, -5.66244e-07, -7.7486e-07, -0.0538019, 0.307417, 0.0309853, 0.949547, 1, 1, 1, 0.2, 1, 0, -3.8743e-07, -4.17233e-07, -0.0934157, 0.21941, 0.0316565, 0.970634, 1, 1, 1, 0.25, 1, -1.49012e-07, -7.7486e-07, -3.57628e-07, -0.112029, 0.160435, 0.0303507, 0.980198, 1, 1, 1, 0.3, 1, 1.19209e-07, -7.15256e-07, -2.38419e-07, -0.111906, 0.1565, 0.0231637, 0.981045, 1, 1, 1, 0.35, 1, 2.68221e-07, -5.06639e-07, -2.38419e-07, -0.104709, 0.167819, 0.0144275, 0.980135, 1, 1, 1, 0.6, 1, 2.38419e-07, -3.57628e-07, -2.98023e-07, -0.0540049, 0.274564, -0.0119163, 0.959977, 1, 1, 1, 0.65, 1, 2.68221e-07, -2.68221e-07, 5.96046e-08, -0.0496356, 0.312827, -0.0136146, 0.948415, 1, 1, 1, 0.8, 1, 1.78814e-07, -3.8743e-07, -2.38419e-07, -0.0228587, 0.449632, -0.00310725, 0.892916, 1, 1, 1, 0.85, 1, -2.08616e-07, -6.25849e-07, -5.36442e-07, -0.00418434, 0.463526, 0.00969348, 0.886021, 1, 1, 1, 0.9, 1, -2.68221e-07, -6.85453e-07, -1.19209e-07, 0.0143603, 0.452468, 0.0218435, 0.891397, 1, 1, 1, 1, 1, 8.9407e-08, -5.96046e-07, -5.36442e-07, 0.0356796, 0.398885, 0.0342096, 0.915668, 1, 1, 1, 1.05, 1, 3.57628e-07, -5.96046e-07, -3.57628e-07, 0.0370915, 0.39046, 0.0351404, 0.919201, 1, 1, 1, 1.25, 1, 3.57628e-07, -5.96046e-07, -3.57628e-07, 0.0370915, 0.39046, 0.0351404, 0.919201, 1, 1, 1 </real_array>
- <string name="tracks/4/type"> "transform" </string>
- <node_path name="tracks/4/path"> "Armature/Skeleton:r-thigh" </node_path>
- <int name="tracks/4/interp"> 1 </int>
- <real_array name="tracks/4/keys" len="180"> 0, 1, -5.96046e-08, 7.45058e-09, -1.3411e-07, -0.47466, -0.0131527, -0.012987, 0.879975, 1, 1, 1, 0.05, 1, 2.98023e-08, 2.23517e-08, -2.23517e-07, -0.410091, -0.00379406, -0.0158917, 0.911898, 1, 1, 1, 0.25, 1, -1.19209e-07, 1.11759e-07, -5.21541e-07, 0.0997313, 0.0337367, -0.0261638, 0.994098, 1, 1, 1, 0.3, 1, 8.9407e-08, 4.47035e-08, -4.02331e-07, 0.122513, 0.0214196, -0.0200121, 0.992034, 1, 1, 1, 0.45, 1, 1.19209e-07, 7.45058e-09, -3.27826e-07, 0.229705, -0.0511077, 0.00301582, 0.971913, 1, 1, 1, 0.5, 1, 0, 3.72529e-08, -3.72529e-07, 0.236488, -0.0697987, 0.00859063, 0.969086, 1, 1, 1, 0.55, 1, 0, 2.98023e-08, -2.5332e-07, 0.206064, -0.0732532, 0.0100766, 0.975741, 1, 1, 1, 0.6, 1, -2.98023e-08, 4.47035e-08, -2.68221e-07, 0.118009, -0.0599028, 0.00750554, 0.991176, 1, 1, 1, 0.65, 1, -8.9407e-08, 2.23517e-08, -2.83122e-07, -0.0368129, -0.031384, 0.00214083, 0.998827, 1, 1, 1, 0.8, 1, -5.96046e-08, 2.23517e-08, -3.42727e-07, -0.634332, 0.0354032, -0.00990766, 0.772186, 1, 1, 1, 0.85, 1, 0, 2.23517e-08, -5.51343e-07, -0.746229, 0.0185993, -0.00698883, 0.665393, 1, 1, 1, 0.9, 1, 2.98023e-08, 1.49012e-08, -3.72529e-07, -0.740985, -0.00577112, -0.000829951, 0.671497, 1, 1, 1, 1, 1, 0, 2.98023e-08, -2.68221e-07, -0.523042, -0.0161244, -0.00986391, 0.852097, 1, 1, 1, 1.05, 1, -5.96046e-08, 7.45058e-09, -1.3411e-07, -0.47466, -0.0131527, -0.012987, 0.879975, 1, 1, 1, 1.25, 1, -5.96046e-08, 7.45058e-09, -1.3411e-07, -0.47466, -0.0131527, -0.012987, 0.879975, 1, 1, 1 </real_array>
- <string name="tracks/5/type"> "transform" </string>
- <node_path name="tracks/5/path"> "Armature/Skeleton:r-leg" </node_path>
- <int name="tracks/5/interp"> 1 </int>
- <real_array name="tracks/5/keys" len="216"> 0, 1, 9.0804e-08, -5.21541e-08, 5.36442e-07, -0.373219, -0.0555838, 8.64882e-05, 0.926077, 1, 1, 1, 0.05, 1, 2.50293e-08, 1.3411e-07, 5.96046e-07, -0.322099, -0.0481091, 0.000521386, 0.945483, 1, 1, 1, 0.1, 1, 1.20257e-07, -1.49012e-07, 7.15256e-07, -0.224139, -0.0330777, 0.00125387, 0.973995, 1, 1, 1, 0.15, 1, 3.94648e-08, -1.3411e-07, 6.55651e-07, -0.165692, -0.0218823, 0.00143977, 0.985934, 1, 1, 1, 0.2, 1, 1.33412e-07, -1.56462e-07, 5.36442e-07, -0.09297, -0.0104596, 0.00125276, 0.995613, 1, 1, 1, 0.25, 1, 3.55067e-08, 4.47035e-08, 1.78814e-07, -0.0411288, -0.0028586, 0.000542978, 0.99915, 1, 1, 1, 0.35, 1, 9.26666e-08, 5.96046e-08, 6.55651e-07, -0.159491, 0.00874812, -0.00126692, 0.98716, 1, 1, 1, 0.45, 1, 3.87663e-08, 0, 4.76837e-07, -0.233894, 0.0318884, -0.00310529, 0.971734, 1, 1, 1, 0.5, 1, -3.53903e-08, -7.45058e-08, 5.96046e-07, -0.280896, 0.0453351, -0.00364749, 0.95866, 1, 1, 1, 0.55, 1, 1.59489e-08, 4.47035e-08, 5.96046e-07, -0.352331, 0.0592861, -0.00363569, 0.933989, 1, 1, 1, 0.6, 1, 2.16532e-08, 1.3411e-07, 6.55651e-07, -0.469209, 0.0766892, -0.00261066, 0.879747, 1, 1, 1, 0.75, 1, 9.51113e-08, -2.01166e-07, 7.15256e-07, -0.846575, 0.0999882, 0.00219129, 0.522789, 1, 1, 1, 0.8, 1, 3.77186e-08, -1.49012e-07, 6.55651e-07, 0.900504, -0.0754152, -0.00223886, -0.428252, 1, 1, 1, 0.85, 1, 4.92437e-08, 1.49012e-07, 6.55651e-07, 0.906482, -0.0264902, -0.00126108, -0.42141, 1, 1, 1, 0.9, 1, -2.71248e-08, 1.63913e-07, 5.36442e-07, -0.830638, -0.0316768, -0.000334372, 0.555911, 1, 1, 1, 1, 1, 2.87546e-08, 4.84288e-07, 7.7486e-07, -0.453335, -0.0623349, -0.000381388, 0.889158, 1, 1, 1, 1.05, 1, 9.0804e-08, -5.21541e-08, 5.36442e-07, -0.373219, -0.0555838, 8.64882e-05, 0.926077, 1, 1, 1, 1.25, 1, 9.0804e-08, -5.21541e-08, 5.36442e-07, -0.373219, -0.0555838, 8.64882e-05, 0.926077, 1, 1, 1 </real_array>
- <string name="tracks/6/type"> "transform" </string>
- <node_path name="tracks/6/path"> "Armature/Skeleton:r-foot" </node_path>
- <int name="tracks/6/interp"> 1 </int>
- <real_array name="tracks/6/keys" len="168"> 0, 1, 5.21541e-08, -1.19209e-07, 9.31323e-08, 0.00219921, 0.118787, -0.0237834, 0.992633, 1, 1, 1, 0.05, 1, 5.96046e-08, 0, -5.58794e-08, 0.00569734, 0.111426, -0.0235639, 0.993477, 1, 1, 1, 0.1, 1, 4.47035e-08, -1.19209e-07, 3.35276e-08, 0.015864, 0.0910374, -0.022104, 0.995476, 1, 1, 1, 0.25, 1, 2.98023e-08, 1.19209e-07, -5.58794e-08, 0.0701794, 0.000367211, 0.000696922, 0.997534, 1, 1, 1, 0.35, 1, 8.19564e-08, -1.19209e-07, -1.11759e-08, 0.121501, -0.050768, 0.0840024, 0.987727, 1, 1, 1, 0.4, 1, 7.45058e-08, 1.19209e-07, 1.04308e-07, 0.115586, -0.0703619, 0.0928345, 0.986444, 1, 1, 1, 0.45, 1, 7.45058e-08, 1.19209e-07, 3.72529e-08, 0.0659214, -0.0866695, 0.0774413, 0.991033, 1, 1, 1, 0.5, 1, -5.96046e-08, 1.19209e-07, -1.11759e-07, 0.0031081, -0.0968864, 0.054063, 0.993821, 1, 1, 1, 0.55, 1, 5.96046e-08, 0, -6.70552e-08, -0.0166663, -0.0982007, 0.0374834, 0.994321, 1, 1, 1, 0.6, 1, 5.96046e-08, 1.19209e-07, -4.84288e-08, -0.0148445, -0.0906634, 0.0264974, 0.995418, 1, 1, 1, 0.65, 1, 0, 0, 4.09782e-08, -0.0108355, -0.0727448, 0.0177847, 0.997133, 1, 1, 1, 1, 1, 6.70552e-08, 0, 7.07805e-08, 0.00219189, 0.11394, -0.0230367, 0.993218, 1, 1, 1, 1.05, 1, 5.21541e-08, -1.19209e-07, 9.31323e-08, 0.00219921, 0.118787, -0.0237834, 0.992633, 1, 1, 1, 1.25, 1, 5.21541e-08, -1.19209e-07, 9.31323e-08, 0.00219921, 0.118787, -0.0237834, 0.992633, 1, 1, 1 </real_array>
- <string name="tracks/7/type"> "transform" </string>
- <node_path name="tracks/7/path"> "Armature/Skeleton:l-thigh" </node_path>
- <int name="tracks/7/interp"> 1 </int>
- <real_array name="tracks/7/keys" len="144"> 0, 1, 2.98023e-08, 2.98023e-08, 1.04308e-07, 0.217295, 0.0746597, -0.0103365, 0.973192, 1, 0.999999, 1, 0.05, 1, -8.9407e-08, 1.49012e-08, 1.49012e-08, 0.151772, 0.0624666, -0.00777083, 0.986409, 1, 1, 1, 0.1, 1, -2.98023e-08, 2.98023e-08, -8.9407e-08, -0.00391929, 0.0335048, -0.00214722, 0.999429, 1, 0.999999, 1, 0.3, 1, 0, 3.72529e-08, -1.49012e-07, -0.748933, -0.0405244, 0.0112371, 0.66131, 1, 1, 1, 0.35, 1, 5.96046e-08, 7.45058e-09, -3.12924e-07, -0.802758, -0.0149771, 0.00481471, 0.596097, 1, 1, 1, 0.4, 1, 0, 7.45058e-09, -1.78814e-07, -0.770121, 0.00992629, -0.000335305, 0.63782, 1, 1, 1, 0.8, 1, -5.96046e-08, 5.21541e-08, -1.04308e-07, 0.0878935, -0.0301616, 0.023494, 0.995396, 1, 1, 1, 0.85, 1, 2.98023e-08, 5.21541e-08, -2.98023e-07, 0.0819817, -0.0162162, 0.0156585, 0.996379, 1, 0.999999, 1, 0.9, 1, -5.96046e-08, 7.45058e-09, -1.3411e-07, 0.0980511, 0.00664153, 0.00756362, 0.99513, 1, 0.999999, 1, 1, 1, -5.96046e-08, 2.98023e-08, -2.98023e-08, 0.201153, 0.0660118, -0.00800331, 0.9773, 1, 0.999999, 1, 1.05, 1, 2.98023e-08, 2.98023e-08, 1.04308e-07, 0.217295, 0.0746597, -0.0103365, 0.973192, 1, 0.999999, 1, 1.25, 1, 2.98023e-08, 2.98023e-08, 1.04308e-07, 0.217295, 0.0746597, -0.0103365, 0.973192, 1, 0.999999, 1 </real_array>
- <string name="tracks/8/type"> "transform" </string>
- <node_path name="tracks/8/path"> "Armature/Skeleton:l-leg" </node_path>
- <int name="tracks/8/interp"> 1 </int>
- <real_array name="tracks/8/keys" len="228"> 0, 1, 4.19095e-08, 1.41561e-07, 2.98023e-07, -0.33502, -0.0565195, 0.00376308, 0.940507, 1, 1, 1, 0.05, 1, 2.82889e-08, 1.86265e-07, 0, -0.412041, -0.0666523, 0.00293558, 0.908719, 1, 1, 1, 0.2, 1, -7.12462e-08, -1.2666e-07, 5.96046e-08, -0.831864, -0.10996, -0.00255585, 0.543972, 1, 1, 1, 0.25, 1, 2.32831e-09, -1.04308e-07, 5.96046e-08, 0.89602, 0.0970023, 0.00298318, -0.433277, 1, 1, 1, 0.3, 1, 1.9907e-08, 3.65078e-07, 2.98023e-07, 0.921569, 0.0590099, 0.00230107, -0.383696, 1, 1, 1, 0.35, 1, -8.28877e-08, -1.93715e-07, 2.38419e-07, 0.901128, 0.00554219, 0.000798309, -0.433517, 1, 1, 1, 0.4, 1, -7.53207e-08, 5.21541e-08, 1.19209e-07, -0.81758, 0.0439972, 0.000730356, 0.574132, 1, 1, 1, 0.5, 1, -2.91038e-09, 1.41561e-07, 2.38419e-07, -0.503688, 0.068707, 0.00074972, 0.861149, 1, 1, 1, 0.55, 1, 6.1933e-08, 8.19564e-08, 5.96046e-08, -0.352333, 0.0527461, -0.000239235, 0.934387, 1, 1, 1, 0.6, 1, -2.95695e-08, 1.04308e-07, 1.78814e-07, -0.244271, 0.03738, -0.00103017, 0.968986, 1, 1, 1, 0.65, 1, 9.54606e-09, 3.50177e-07, 1.78814e-07, -0.200824, 0.0283491, -0.00130918, 0.979216, 1, 1, 1, 0.7, 1, 2.01399e-08, 2.23517e-08, 0, -0.167963, 0.0193272, -0.0011918, 0.985603, 1, 1, 1, 0.75, 1, -2.47965e-08, -2.23517e-07, 1.19209e-07, -0.0847999, 0.00700657, -0.000838314, 0.996373, 1, 1, 1, 0.8, 1, -4.88944e-08, -7.45058e-09, 0, -0.073705, 0.000793342, 3.27131e-05, 0.99728, 1, 1, 1, 0.9, 1, -5.50644e-08, 0, 1.19209e-07, -0.297998, -0.0240387, 0.0012853, 0.954263, 1, 1, 1, 0.95, 1, -1.08266e-08, -2.98023e-08, 1.19209e-07, -0.340478, -0.0423349, 0.0021981, 0.939296, 1, 1, 1, 1, 1, 5.07571e-08, -1.63913e-07, 0, -0.339784, -0.0539663, 0.00332048, 0.938948, 1, 1, 1, 1.05, 1, 4.19095e-08, 1.41561e-07, 2.98023e-07, -0.33502, -0.0565195, 0.00376308, 0.940507, 1, 1, 1, 1.25, 1, 4.19095e-08, 1.41561e-07, 2.98023e-07, -0.33502, -0.0565195, 0.00376308, 0.940507, 1, 1, 1 </real_array>
- <string name="tracks/9/type"> "transform" </string>
- <node_path name="tracks/9/path"> "Armature/Skeleton:l-foot" </node_path>
- <int name="tracks/9/interp"> 1 </int>
- <real_array name="tracks/9/keys" len="192"> 0, 1, -3.72529e-08, 0, 8.19564e-08, -0.0168517, 0.0989445, -0.0394225, 0.994169, 1, 1, 1, 0.05, 1, 6.70552e-08, 1.19209e-07, -4.47035e-08, -0.0168456, 0.0944203, -0.0381151, 0.99466, 1, 1, 1, 0.1, 1, 1.49012e-08, 1.19209e-07, -3.35276e-08, -0.0167772, 0.0819293, -0.034504, 0.995899, 1, 1, 1, 0.15, 1, -7.45058e-09, 1.19209e-07, -1.3411e-07, -0.0165494, 0.0617975, -0.0286797, 0.997539, 1, 1, 1, 0.4, 1, -2.23517e-08, 0, 2.6077e-08, -0.00864448, -0.0855905, 0.0141105, 0.996193, 1, 1, 1, 0.45, 1, 7.45058e-09, 2.38419e-07, -7.45058e-08, -0.00528641, -0.10464, 0.0196597, 0.994302, 1, 1, 1, 0.5, 1, -1.49012e-08, 1.19209e-07, 7.45058e-09, -0.00140908, -0.115976, 0.0229639, 0.992986, 1, 1, 1, 0.55, 1, 1.49012e-08, 2.38419e-07, 3.72529e-08, 0.00315788, -0.117918, 0.023482, 0.992741, 1, 1, 1, 0.6, 1, -2.98023e-08, 1.19209e-07, -1.49012e-08, 0.00993965, -0.108994, 0.0205203, 0.993781, 1, 1, 1, 0.65, 1, 1.49012e-08, 0, 1.86265e-08, 0.0206495, -0.0875135, 0.0140912, 0.99585, 1, 1, 1, 0.8, 1, -2.23517e-08, 1.19209e-07, -3.72529e-09, 0.0751354, 0.00445886, 0.00173853, 0.997162, 1, 1, 1, 0.9, 1, 0, 0, -2.98023e-08, 0.131833, 0.0617586, 0.0448617, 0.988329, 1, 1, 1, 0.95, 1, 3.72529e-08, 0, -6.70552e-08, 0.10712, 0.0825392, 0.0325464, 0.99028, 1, 1, 1, 1, 1, 1.49012e-08, 2.38419e-07, -4.84288e-08, 0.0202877, 0.0962194, -0.0179372, 0.994992, 1, 1, 1, 1.05, 1, -3.72529e-08, 0, 8.19564e-08, -0.0168517, 0.0989445, -0.0394225, 0.994169, 1, 1, 1, 1.25, 1, -3.72529e-08, 0, 8.19564e-08, -0.0168517, 0.0989445, -0.0394225, 0.994169, 1, 1, 1 </real_array>
- <string name="tracks/10/type"> "transform" </string>
- <node_path name="tracks/10/path"> "Armature/Skeleton:MASTER" </node_path>
- <int name="tracks/10/interp"> 1 </int>
- <real_array name="tracks/10/keys" len="24"> 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/11/type"> "transform" </string>
- <node_path name="tracks/11/path"> "Armature/Skeleton:HEAD" </node_path>
- <int name="tracks/11/interp"> 1 </int>
- <real_array name="tracks/11/keys" len="216"> 0, 1, -5.68434e-14, 0, 0.850875, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -5.68434e-14, 0, 0.888268, 0, 0, 0, 1, 1, 1, 1, 0.1, 1, -5.68434e-14, 0, 0.982704, 0, 0, 7.10543e-15, 1, 1, 1, 1, 0.15, 1, -5.68434e-14, 0, 1.10101, 0, 0, 0, 1, 1, 1, 1, 0.2, 1, -5.68434e-14, 0, 1.19526, 0, 0, -7.10543e-15, 1, 1, 1, 1, 0.25, 1, -5.68434e-14, 0, 1.23253, 0, 0, 0, 1, 1, 1, 1, 0.3, 1, -5.68434e-14, 0, 1.20497, 0, 0, 7.10543e-15, 1, 1, 1, 1, 0.35, 1, -5.68434e-14, 0, 1.13278, 0, 0, -7.10543e-15, 1, 1, 1, 1, 0.45, 1, -5.68434e-14, 0, 0.935015, 0, 0, 0, 1, 1, 1, 1, 0.5, 1, -5.68434e-14, 0, 0.868188, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, -5.68434e-14, 0, 0.85559, 0, 0, 0, 1, 1, 1, 1, 0.6, 1, -5.68434e-14, 0, 0.901897, 0, 0, 0, 1, 1, 1, 1, 0.75, 1, -5.68434e-14, 0, 1.20896, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, -5.68434e-14, 0, 1.22782, 0, 0, 7.10543e-15, 1, 1, 1, 1, 0.85, 1, -5.68434e-14, 0, 1.18155, 0, 0, 0, 1, 1, 1, 1, 1, 1, -5.68434e-14, 0, 0.874524, 0, 0, 0, 1, 1, 1, 1, 1.05, 1, -5.68434e-14, 0, 0.850875, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -5.68434e-14, 0, 0.850875, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/12/type"> "transform" </string>
- <node_path name="tracks/12/path"> "Armature/Skeleton:r-LEGCONTROL" </node_path>
- <int name="tracks/12/interp"> 1 </int>
- <real_array name="tracks/12/keys" len="180"> 0, 1, -0.142338, -0.946415, 0.217759, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -0.142333, -0.853172, 0.14976, 0, 0, 0, 1, 1, 1, 1, 0.1, 1, -0.142326, -0.626394, 0.0493819, 0, 0, 0, 1, 1, 1, 1, 0.25, 1, -0.142324, 0.323052, 0.113333, 0, 0, 0, 1, 1, 1, 1, 0.45, 1, -0.139402, 1.42157, 0.666575, 0, 0, 0, 1, 1, 1, 1, 0.5, 1, -0.136793, 1.55206, 0.805069, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, -0.131841, 1.57295, 0.911952, 0, 0, 0, 1, 1, 1, 1, 0.6, 1, -0.113377, 1.47151, 1.00452, 0, 0, 0, 1, 1, 1, 1, 0.65, 1, -0.077946, 1.23249, 1.08549, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, -0.0017584, 0.265596, 1.17195, 0, 0, 0, 1, 1, 1, 1, 0.85, 1, -0.0190262, -0.03908, 1.05516, 0, 0, 0, 1, 1, 1, 1, 0.95, 1, -0.100589, -0.692012, 0.50379, 0, 0, 0, 1, 1, 1, 1, 1, 1, -0.133542, -0.895383, 0.278588, 0, 0, 0, 1, 1, 1, 1, 1.05, 1, -0.142338, -0.946415, 0.217759, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.142338, -0.946415, 0.217759, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/13/type"> "transform" </string>
- <node_path name="tracks/13/path"> "Armature/Skeleton:l-LEGCONTROL" </node_path>
- <int name="tracks/13/interp"> 1 </int>
- <real_array name="tracks/13/keys" len="192"> 0, 1, 0.133965, 1.58294, 0.896163, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 0.120869, 1.49689, 0.924311, 0, 0, 0, 1, 1, 1, 1, 0.1, 1, 0.0877482, 1.26696, 0.995435, 0, 0, 0, 1, 1, 1, 1, 0.25, 1, 0, 0.313476, 1.18387, 0, 0, 0, 1, 1, 1, 1, 0.3, 1, 0.0102771, 0.0502403, 1.13241, 0, 0, 0, 1, 1, 1, 1, 0.4, 1, 0.0744684, -0.535892, 0.782828, 0, 0, 0, 1, 1, 1, 1, 0.45, 1, 0.110957, -0.769809, 0.54983, 0, 0, 0, 1, 1, 1, 1, 0.5, 1, 0.13588, -0.912113, 0.342608, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, 0.142337, -0.934969, 0.197995, 0, 0, 0, 1, 1, 1, 1, 0.6, 1, 0.142331, -0.819832, 0.0904105, 0, 0, 0, 1, 1, 1, 1, 0.65, 1, 0.142325, -0.584709, 0.0345853, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, 0.14222, 0.375652, 0.134472, 0, 0, 0, 1, 1, 1, 1, 0.95, 1, 0.136416, 1.34572, 0.707882, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0.134481, 1.53602, 0.857536, 0, 0, 0, 1, 1, 1, 1, 1.05, 1, 0.133965, 1.58294, 0.896163, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.133965, 1.58294, 0.896163, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/14/type"> "transform" </string>
- <node_path name="tracks/14/path"> "Armature/Skeleton:r-LEGORIENT" </node_path>
- <int name="tracks/14/interp"> 1 </int>
- <real_array name="tracks/14/keys" len="192"> 0, 1, 0.100474, 0.669825, -0.778672, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 0.098364, 0.655731, -0.762274, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 0.1, 1, 0.092555, 0.616937, -0.717148, 4.1297e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.15, 1, 0.0832335, 0.55472, -0.644792, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.4, 1, 0.0154476, 0.102931, -0.119635, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 0.45, 1, 0.00660282, 0.0440027, -0.051146, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.5, 1, 0.00131494, 0.00876498, -0.0101888, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, 0.000308841, 0.00205886, -0.00239307, 7.10993e-08, 6.08666e-15, -4.32757e-22, 1, 1, 1, 1, 0.6, 1, 0.00340915, 0.0227199, -0.0264083, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.65, 1, 0.0108188, 0.0720865, -0.0837842, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.7, 1, 0.0221942, 0.14786, -0.171845, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 0.9, 1, 0.0824287, 0.549322, -0.638501, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.95, 1, 0.0927294, 0.618084, -0.718475, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 1, 1, 0.0989292, 0.659501, -0.766658, 0, 0, 0, 1, 1, 1, 1, 1.05, 1, 0.100474, 0.669825, -0.778672, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.100474, 0.669825, -0.778672, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/15/type"> "transform" </string>
- <node_path name="tracks/15/path"> "Armature/Skeleton:l-LEGORIENT" </node_path>
- <int name="tracks/15/interp"> 1 </int>
- <real_array name="tracks/15/keys" len="192"> 0, 1, 2.98023e-08, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -0.00210956, 0.0140947, -0.0163979, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 0.1, 1, -0.00791863, 0.0528884, -0.0615235, 4.1297e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.15, 1, -0.0172402, 0.115105, -0.13388, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.4, 1, -0.085026, 0.566894, -0.659037, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 0.45, 1, -0.0938708, 0.625823, -0.727526, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.5, 1, -0.0991587, 0.66106, -0.768483, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, -0.100165, 0.667766, -0.776279, 7.10993e-08, 6.08666e-15, -4.32757e-22, 1, 1, 1, 1, 0.6, 1, -0.0970645, 0.647105, -0.752263, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.65, 1, -0.0896548, 0.597739, -0.694888, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.7, 1, -0.0782794, 0.521965, -0.606827, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 0.9, 1, -0.0180449, 0.120504, -0.14017, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.95, 1, -0.00774428, 0.0517416, -0.0601966, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 1, 1, -0.00154439, 0.0103241, -0.0120134, 0, 0, 0, 1, 1, 1, 1, 1.05, 1, 2.98023e-08, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 2.98023e-08, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/16/type"> "transform" </string>
- <node_path name="tracks/16/path"> "Armature/Skeleton:r-ARMCONTROL" </node_path>
- <int name="tracks/16/interp"> 1 </int>
- <real_array name="tracks/16/keys" len="180"> 0, 1, -0.868295, -0.434147, -0.728793, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -0.894115, -0.429589, -0.685758, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, -0.965105, -0.417039, -0.56775, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.15, 1, -1.07881, -0.396902, -0.379345, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, -1.9017, -0.250463, 0.973224, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, -2.00893, -0.231348, 1.14912, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.5, 1, -2.07309, -0.219917, 1.25447, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, -2.08428, -0.222594, 1.27283, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.6, 1, -2.0356, -0.276793, 1.19246, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.65, 1, -1.92036, -0.39421, 1.00266, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.75, 1, -1.5939, -0.636021, 0.464508, 0, 0, 0, 1, 1, 1, 1, 0.95, 1, -0.989962, -0.50147, -0.527541, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1, 1, -0.8923, -0.448337, -0.688738, 0, 0, 0, 1, 1, 1, 1, 1.05, 1, -0.868295, -0.434147, -0.728793, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.868295, -0.434147, -0.728793, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/17/type"> "transform" </string>
- <node_path name="tracks/17/path"> "Armature/Skeleton:l-ARMCONTROL" </node_path>
- <int name="tracks/17/interp"> 1 </int>
- <real_array name="tracks/17/keys" len="180"> 0, 1, 2.08906, -0.217074, 1.28073, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 2.04863, -0.260861, 1.21323, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, 1.93875, -0.371377, 1.03141, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.25, 1, 1.47813, -0.663608, 0.273554, 0, 0, 0, 1, 1, 1, 1, 0.45, 1, 0.953814, -0.514624, -0.588262, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.5, 1, 0.884829, -0.464922, -0.701557, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, 0.872045, -0.428974, -0.722627, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.6, 1, 0.909668, -0.39768, -0.660821, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.65, 1, 0.999508, -0.365756, -0.513451, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.7, 1, 1.13734, -0.334072, -0.287612, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.9, 1, 1.86856, -0.237138, 0.914287, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.95, 1, 1.99427, -0.225258, 1.12276, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1, 1, 2.07012, -0.218627, 1.24908, 0, 0, 0, 1, 1, 1, 1, 1.05, 1, 2.08906, -0.217074, 1.28073, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 2.08906, -0.217074, 1.28073, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/18/type"> "transform" </string>
- <node_path name="tracks/18/path"> "Armature/Skeleton:r-ARMORIENT" </node_path>
- <int name="tracks/18/interp"> 1 </int>
- <real_array name="tracks/18/keys" len="192"> 0, 1, 0.405204, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 0.429983, 0.0015192, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, 0.498118, 0.0057025, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.15, 1, 0.607264, 0.0124156, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, 1.39747, 0.061233, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, 1.50046, 0.0676029, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.5, 1, 1.56207, 0.0714109, 0, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, 1.5738, 0.0721354, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.6, 1, 1.53767, 0.0699027, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.65, 1, 1.45139, 0.0645664, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.7, 1, 1.31902, 0.0563741, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.9, 1, 0.616836, 0.0129952, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.95, 1, 0.496168, 0.00557709, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1, 1, 0.423375, 0.00111222, 0, 0, 0, 0, 1, 1, 1, 1, 1.05, 1, 0.405204, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.405204, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/19/type"> "transform" </string>
- <node_path name="tracks/19/path"> "Armature/Skeleton:l-ARMORIENT" </node_path>
- <int name="tracks/19/interp"> 1 </int>
- <real_array name="tracks/19/keys" len="192"> 0, 1, -1.5774, 0.0723579, 0, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -1.55262, 0.0708387, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, -1.48449, 0.0666554, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.15, 1, -1.37534, 0.0599422, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, -0.585136, 0.0111248, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, -0.482148, 0.00475502, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.5, 1, -0.420538, 0.000946999, 0, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, -0.408805, 0.000222445, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.6, 1, -0.444934, 0.00245523, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.65, 1, -0.531212, 0.00779152, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.7, 1, -0.663587, 0.0159838, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.9, 1, -1.36577, 0.0593629, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.95, 1, -1.48644, 0.0667808, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 1, 1, -1.55923, 0.0712457, 0, 0, 0, 0, 1, 1, 1, 1, 1.05, 1, -1.5774, 0.0723579, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -1.5774, 0.0723579, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/20/type"> "transform" </string>
- <node_path name="tracks/20/path"> "Armature/Skeleton:hip" </node_path>
- <int name="tracks/20/interp"> 1 </int>
- <real_array name="tracks/20/keys" len="276"> 0, 1, 0.0502379, 0.036174, 0.108012, 7.74552e-15, -1.97402e-08, 0.0871557, 0.996195, 1, 1, 1, 0.05, 1, 0.0469382, 0.0509099, 0.094259, -3.35906e-14, -1.89171e-08, 0.0835209, 0.996506, 1, 1, 1, 0.1, 1, 0.0379226, 0.088175, 0.0594788, -4.57539e-14, -1.66467e-08, 0.0734954, 0.997296, 1, 1, 1, 0.15, 1, 0.0249111, 0.134917, 0.0158529, -3.14989e-14, -1.29934e-08, 0.0573644, 0.998353, 1, 1, 1, 0.2, 1, 0.0112907, 0.17217, -0.0189178, -1.3373e-14, -8.15547e-09, 0.0360035, 0.999352, 1, 1, 1, 0.25, 1, 2.27588e-08, 0.186899, -0.0326645, -1.50375e-14, -2.49281e-09, 0.0110021, 0.99994, 1, 1, 1, 0.3, 1, -0.0104418, 0.176016, -0.0225072, -7.05369e-14, 3.45387e-09, -0.0152525, 0.999884, 1, 1, 1, 0.35, 1, -0.0222285, 0.147506, 0.00410175, -3.23609e-14, 9.01354e-09, -0.039798, 0.999208, 1, 1, 1, 0.4, 1, -0.0338161, 0.108041, 0.0409362, -3.84007e-14, 1.36964e-08, -0.0604725, 0.99817, 1, 1, 1, 0.45, 1, -0.043192, 0.0694027, 0.0769985, -3.85801e-14, 1.71613e-08, -0.0757699, 0.997125, 1, 1, 1, 0.5, 1, -0.0488776, 0.0430113, 0.10163, -7.13117e-15, 1.92273e-08, -0.084891, 0.99639, 1, 1, 1, 0.55, 1, -0.049846, 0.0380361, 0.106274, -6.66418e-14, 1.96198e-08, -0.0866238, 0.996241, 1, 1, 1, 0.6, 1, -0.0458462, 0.0563236, 0.0892055, -1.43694e-14, 1.84095e-08, -0.0812805, 0.996691, 1, 1, 1, 0.65, 1, -0.0363638, 0.0959547, 0.0522163, -5.40282e-14, 1.5511e-08, -0.0684838, 0.997652, 1, 1, 1, 0.7, 1, -0.0231681, 0.1427, 0.0085876, -3.25683e-14, 1.10473e-08, -0.0487772, 0.99881, 1, 1, 1, 0.75, 1, -0.00951665, 0.177588, -0.0239747, 1.83932e-15, 5.34013e-09, -0.0235807, 0.999722, 1, 1, 1, 0.8, 1, 0.00190332, 0.185037, -0.0309267, -4.07805e-14, -1.06814e-09, 0.00471147, 0.999989, 1, 1, 1, 0.85, 1, 0.0140465, 0.166752, -0.0138602, -8.20187e-14, -7.29738e-09, 0.0322142, 0.999481, 1, 1, 1, 0.9, 1, 0.0278208, 0.127127, 0.0231235, -3.37482e-14, -1.26773e-08, 0.0559684, 0.998433, 1, 1, 1, 0.95, 1, 0.0402532, 0.080384, 0.0667505, -4.05783e-14, -1.67149e-08, 0.0737966, 0.997273, 1, 1, 1, 1, 1, 0.0482781, 0.0454891, 0.0993183, 1.00279e-15, -1.91378e-08, 0.0844954, 0.996424, 1, 1, 1, 1.05, 1, 0.0502379, 0.036174, 0.108012, 7.74552e-15, -1.97402e-08, 0.0871557, 0.996195, 1, 1, 1, 1.25, 1, 0.0502379, 0.036174, 0.108012, 7.74552e-15, -1.97402e-08, 0.0871557, 0.996195, 1, 1, 1 </real_array>
- <string name="tracks/21/type"> "transform" </string>
- <node_path name="tracks/21/path"> "Armature/Skeleton:waist" </node_path>
- <int name="tracks/21/interp"> 1 </int>
- <real_array name="tracks/21/keys" len="192"> 0, 1, 4.1909e-09, -2.55596e-10, -3.57628e-07, 0.0550011, -0.00481196, -0.0870228, 0.994675, 1, 1, 1, 0.05, 1, 3.53838e-09, 6.53649e-11, -5.96046e-08, 0.0550183, -0.0046113, -0.0833935, 0.994986, 1, 1, 1, 0.1, 1, -5.60775e-10, -7.51698e-09, -2.98023e-08, 0.0550619, -0.00405785, -0.0733833, 0.995774, 1, 1, 1, 0.15, 1, -2.23866e-09, -1.11867e-08, -1.49012e-07, 0.0551203, -0.00316731, -0.0572769, 0.996831, 1, 1, 1, 0.4, 1, -2.04997e-09, -2.75862e-09, 1.78814e-07, 0.0551102, 0.00333869, 0.0603803, 0.996647, 1, 1, 1, 0.45, 1, 2.0486e-09, 4.35754e-10, 5.96046e-08, 0.0550525, 0.00418331, 0.0756543, 0.995605, 1, 1, 1, 0.5, 1, -5.1223e-09, 2.12108e-09, 1.19209e-07, 0.0550119, 0.00468692, 0.0847616, 0.994871, 1, 1, 1, 0.55, 1, 9.31448e-11, -6.0701e-10, 0, 0.0550037, 0.00478259, 0.0864917, 0.994722, 1, 1, 1, 0.6, 1, -8.38328e-10, -2.70165e-09, 0, 0.0550285, 0.00448757, 0.0811565, 0.995171, 1, 1, 1, 0.65, 1, -5.5956e-10, 2.044e-09, 2.98023e-08, 0.0550816, 0.00378102, 0.0683793, 0.996131, 1, 1, 1, 0.7, 1, -1.88318e-10, -1.00538e-08, -1.49012e-07, 0.0551455, 0.00269294, 0.0487028, 0.997286, 1, 1, 1, 0.9, 1, -2.42557e-09, -9.9462e-09, 1.19209e-07, 0.0551247, -0.00309027, -0.055883, 0.99691, 1, 1, 1, 0.95, 1, 2.79174e-09, -8.13951e-09, 0, 0.0550607, -0.00407449, -0.073684, 0.995752, 1, 1, 1, 1, 1, -4.66262e-10, 1.71346e-09, 0, 0.0550138, -0.0046651, -0.0843665, 0.994904, 1, 1, 1, 1.05, 1, 4.1909e-09, -2.55596e-10, -3.57628e-07, 0.0550011, -0.00481196, -0.0870228, 0.994675, 1, 1, 1, 1.25, 1, 4.1909e-09, -2.55596e-10, -3.57628e-07, 0.0550011, -0.00481196, -0.0870228, 0.994675, 1, 1, 1 </real_array>
- <string name="tracks/22/type"> "transform" </string>
- <node_path name="tracks/22/path"> "Armature/Skeleton:chest" </node_path>
- <int name="tracks/22/interp"> 1 </int>
- <real_array name="tracks/22/keys" len="192"> 0, 1, 4.20218e-09, -1.49012e-08, 0, 0.0550026, -0.0108562, -0.086477, 0.994675, 1, 1, 1, 0.05, 1, 6.60681e-10, -7.45058e-09, -5.96046e-08, 0.0550197, -0.0104035, -0.0828704, 0.994986, 1, 1, 1, 0.1, 1, 1.42138e-09, -7.45058e-09, 1.19209e-07, 0.0550633, -0.00915483, -0.072923, 0.995774, 1, 1, 1, 0.15, 1, -1.4402e-10, -1.86265e-08, -5.96046e-08, 0.0551217, -0.00714571, -0.0569177, 0.99683, 1, 1, 1, 0.4, 1, -2.54046e-09, 7.45058e-09, -1.78814e-07, 0.0551116, 0.00753235, 0.0600015, 0.996647, 1, 1, 1, 0.45, 1, -2.31643e-09, 1.86265e-08, -1.78814e-07, 0.0550539, 0.00943788, 0.0751797, 0.995604, 1, 1, 1, 0.5, 1, -3.16026e-09, 1.49012e-08, 5.96046e-08, 0.0550134, 0.0105741, 0.0842299, 0.99487, 1, 1, 1, 0.55, 1, -4.35034e-09, 2.23517e-08, -1.78814e-07, 0.0550051, 0.0107899, 0.0859492, 0.994722, 1, 1, 1, 0.6, 1, -1.53961e-09, -7.45058e-09, 5.96046e-08, 0.05503, 0.0101243, 0.0806475, 0.995171, 1, 1, 1, 0.65, 1, -1.47879e-09, -1.86265e-08, -5.96046e-08, 0.055083, 0.00853027, 0.0679504, 0.996131, 1, 1, 1, 0.7, 1, -2.07954e-09, 2.6077e-08, -2.38419e-07, 0.0551469, 0.00607548, 0.0483973, 0.997286, 1, 1, 1, 0.9, 1, -1.29246e-09, -2.6077e-08, 5.96046e-08, 0.0551261, -0.00697189, -0.0555325, 0.99691, 1, 1, 1, 0.95, 1, 2.48766e-09, -7.45058e-09, 5.96046e-08, 0.0550621, -0.00919238, -0.0732219, 0.995752, 1, 1, 1, 1, 1, -1.94411e-09, -7.45058e-09, -1.19209e-07, 0.0550152, -0.0105248, -0.0838373, 0.994904, 1, 1, 1, 1.05, 1, 4.20218e-09, -1.49012e-08, 0, 0.0550026, -0.0108562, -0.086477, 0.994675, 1, 1, 1, 1.25, 1, 4.20218e-09, -1.49012e-08, 0, 0.0550026, -0.0108562, -0.086477, 0.994675, 1, 1, 1 </real_array>
- <string name="tracks/23/type"> "transform" </string>
- <node_path name="tracks/23/path"> "Armature/Skeleton:neck" </node_path>
- <int name="tracks/23/interp"> 1 </int>
- <real_array name="tracks/23/keys" len="24"> 0, 1, 1.58195e-10, -1.19209e-07, -8.34465e-07, -1.49012e-08, 2.17021e-10, 8.15234e-10, 1, 1, 1, 1, 1.25, 1, 1.58195e-10, -1.19209e-07, -8.34465e-07, -1.49012e-08, 2.17021e-10, 8.15234e-10, 1, 1, 1, 1 </real_array>
- <string name="tracks/24/type"> "transform" </string>
- <node_path name="tracks/24/path"> "Armature/Skeleton:headtracker" </node_path>
- <int name="tracks/24/interp"> 1 </int>
- <real_array name="tracks/24/keys" len="144"> 0, 1, 8.86136e-10, -2.38419e-07, -4.91273e-08, 0.0549542, -0.0952446, 0.00487296, 0.993924, 1, 1, 1, 0.05, 1, 2.18506e-09, -1.78814e-07, -5.65778e-08, 0.0504772, -0.0912067, 0.0042631, 0.994543, 1, 1, 1, 0.1, 1, 5.53928e-10, -4.17233e-07, -3.67872e-08, 0.0390059, -0.0800384, 0.00284171, 0.996024, 1, 1, 1, 0.45, 1, -5.1797e-09, -8.04663e-07, -5.82077e-08, 0.0448447, 0.08285, -0.00340957, 0.995547, 1, 1, 1, 0.5, 1, 3.73723e-09, 3.57628e-07, -5.28526e-08, 0.052893, 0.0927872, -0.00455309, 0.99427, 1, 1, 1, 0.55, 1, 3.81474e-09, -2.98023e-08, -4.30737e-08, 0.0543919, 0.0946615, -0.00479041, 0.994011, 1, 1, 1, 0.6, 1, 5.97727e-09, -1.01328e-06, -7.35745e-08, 0.0488359, 0.0887913, -0.00401032, 0.994844, 1, 1, 1, 0.65, 1, -3.89822e-10, -6.25849e-07, -7.96281e-08, 0.0366099, 0.0746935, -0.00247956, 0.996531, 1, 1, 1, 0.95, 1, -4.46247e-09, 1.19209e-07, -6.96164e-08, 0.0414353, -0.080551, 0.00304791, 0.995884, 1, 1, 1, 1, 1, 2.64143e-09, -5.96046e-07, -7.72998e-08, 0.052136, -0.0923283, 0.0044599, 0.994353, 1, 1, 1, 1.05, 1, 8.86136e-10, -2.38419e-07, -4.91273e-08, 0.0549542, -0.0952446, 0.00487296, 0.993924, 1, 1, 1, 1.25, 1, 8.86136e-10, -2.38419e-07, -4.91273e-08, 0.0549542, -0.0952446, 0.00487296, 0.993924, 1, 1, 1 </real_array>
- <string name="tracks/25/type"> "transform" </string>
- <node_path name="tracks/25/path"> "Armature/Skeleton:head" </node_path>
- <int name="tracks/25/interp"> 1 </int>
- <real_array name="tracks/25/keys" len="24"> 0, 1, -3.08853e-09, 1.69966e-08, 3.98955e-07, 4.70848e-20, -1.3217e-10, -5.67425e-10, 1, 1, 1, 1, 1.25, 1, -3.08853e-09, 1.69966e-08, 3.98955e-07, 4.70848e-20, -1.3217e-10, -5.67425e-10, 1, 1, 1, 1 </real_array>
- <string name="tracks/26/type"> "transform" </string>
- <node_path name="tracks/26/path"> "Armature/Skeleton:vent" </node_path>
- <int name="tracks/26/interp"> 1 </int>
- <real_array name="tracks/26/keys" len="24"> 0, 1, 5.17831e-08, 0.00292331, 0.204329, 3.25963e-09, -2.17324e-11, 3.00563e-10, 1, 1, 1, 1, 1.25, 1, 5.17831e-08, 0.00292331, 0.204329, 3.25963e-09, -2.17324e-11, 3.00563e-10, 1, 1, 1, 1 </real_array>
-
- </resource>
- <resource type="Animation" path="local://13">
- <string name="resource/name"> "run-cycle" </string>
- <real name="length"> 0.833333 </real>
- <bool name="loop"> True </bool>
- <real name="step"> 0.1 </real>
- <string name="tracks/0/type"> "transform" </string>
- <node_path name="tracks/0/path"> "Armature/Skeleton:r-arm" </node_path>
- <int name="tracks/0/interp"> 1 </int>
- <real_array name="tracks/0/keys" len="192"> 0, 1, 9.23872e-07, -3.57628e-07, 5.66244e-07, 0.222344, -0.226466, -0.0274315, 0.947905, 1, 1, 1, 0.05, 1, 6.55651e-07, -1.19209e-07, 2.98023e-07, 0.251975, -0.208305, -0.0408158, 0.944167, 1, 1, 1, 0.15, 1, 1.07288e-06, -3.57628e-07, 5.36442e-07, 0.379887, -0.057225, -0.102903, 0.917509, 1, 1, 1, 0.2, 1, 6.25849e-07, -3.57628e-07, 7.45058e-07, 0.418674, -0.00696497, -0.113328, 0.901011, 1, 1, 1, 0.25, 1, 8.64267e-07, -3.57628e-07, 3.8743e-07, 0.413182, 0.0386478, -0.0801881, 0.906287, 1, 1, 1, 0.3, 1, 9.53674e-07, -4.76837e-07, 5.96046e-07, 0.315261, 0.124735, -0.0152523, 0.940648, 1, 1, 1, 0.4, 1, 6.25849e-07, -3.57628e-07, 4.17233e-07, -0.151881, 0.360683, -0.0357324, 0.919545, 1, 1, 0.999999, 0.45, 1, 6.25849e-07, -3.57628e-07, 7.45058e-07, -0.172392, 0.343529, -0.046079, 0.922034, 1, 1, 0.999999, 0.55, 1, 6.55651e-07, -3.57628e-07, 5.36442e-07, 0.168352, 0.0191591, -0.0776353, 0.982478, 1, 1, 1, 0.6, 1, 9.53674e-07, -3.57628e-07, 3.27826e-07, 0.182793, -0.0233152, -0.109476, 0.976759, 1, 1, 1, 0.65, 1, 4.17233e-07, 0, 1.78814e-07, 0.138039, -0.0157468, -0.121765, 0.982787, 1, 1, 1, 0.7, 1, 6.25849e-07, -2.38419e-07, 1.78814e-07, 0.121673, -0.0809579, -0.109793, 0.983152, 1, 1, 1, 0.75, 1, 9.23872e-07, -3.57628e-07, 7.45058e-07, 0.131274, -0.176942, -0.0767055, 0.972407, 1, 1, 1, 0.8, 1, 5.66244e-07, -1.19209e-07, 5.96046e-07, 0.13073, -0.218021, -0.0501677, 0.965847, 1, 1, 1, 0.85, 1, 2.98023e-08, 0, -5.96046e-08, 0.129118, -0.224691, -0.0428281, 0.964888, 1, 1, 1, 1.25, 1, 2.98023e-08, 0, -5.96046e-08, 0.129118, -0.224691, -0.0428281, 0.964888, 1, 1, 1 </real_array>
- <string name="tracks/1/type"> "transform" </string>
- <node_path name="tracks/1/path"> "Armature/Skeleton:r-forearm" </node_path>
- <int name="tracks/1/interp"> 1 </int>
- <real_array name="tracks/1/keys" len="180"> 0, 1, 0, -4.17233e-07, -3.57628e-07, -0.0379169, -0.0715942, 0.00193508, 0.996711, 1, 1, 1, 0.05, 1, -1.78814e-07, -5.96046e-07, -4.17233e-07, -0.000241383, -0.109076, 0.00379063, 0.994026, 1, 1, 1, 0.1, 1, 8.9407e-08, -6.55651e-07, -6.55651e-07, 0.0679255, -0.167209, 0.00334064, 0.983573, 1, 0.999999, 1, 0.25, 1, -1.19209e-07, -3.8743e-07, 0, 0.158727, -0.350464, 0.00627285, 0.923007, 1, 1, 1, 0.3, 1, -3.27826e-07, -6.85453e-07, 1.78814e-07, 0.146536, -0.393807, 0.00119701, 0.907437, 1, 1, 1, 0.35, 1, -8.9407e-08, -6.55651e-07, -3.57628e-07, 0.153485, -0.416977, -0.0128296, 0.895772, 1, 1, 1, 0.4, 1, 8.9407e-08, -9.83477e-07, -5.36442e-07, 0.172873, -0.368078, -0.014432, 0.913469, 1, 0.999999, 1, 0.45, 1, 0, -9.83477e-07, -1.19209e-07, 0.191151, -0.391536, -0.0140892, 0.899979, 1, 1, 1, 0.5, 1, 8.9407e-08, -5.96046e-07, -6.55651e-07, 0.210133, -0.527231, -0.0202225, 0.823081, 1, 1, 1, 0.55, 1, 2.68221e-07, -6.25849e-07, -4.17233e-07, 0.159334, -0.589231, -0.00909611, 0.792046, 1, 1, 1, 0.65, 1, -1.19209e-07, -6.85453e-07, -7.15256e-07, 0.0168538, -0.43832, 0.0104639, 0.8986, 1, 1, 1, 0.7, 1, 1.78814e-07, -5.36442e-07, -1.78814e-07, -0.00524541, -0.376783, 0.0174757, 0.926122, 1, 1, 1, 0.8, 1, -5.96046e-08, -7.15256e-07, -5.36442e-07, 0.00762745, -0.243737, 0.014512, 0.969703, 1, 1, 1, 0.85, 1, 1.19209e-07, -6.85453e-07, -7.7486e-07, 0.00858928, -0.221202, 0.0126834, 0.975108, 1, 1, 1, 1.25, 1, 1.19209e-07, -6.85453e-07, -7.7486e-07, 0.00858928, -0.221202, 0.0126834, 0.975108, 1, 1, 1 </real_array>
- <string name="tracks/2/type"> "transform" </string>
- <node_path name="tracks/2/path"> "Armature/Skeleton:l-arm" </node_path>
- <int name="tracks/2/interp"> 1 </int>
- <real_array name="tracks/2/keys" len="228"> 0, 1, -9.53674e-07, -5.96046e-07, 4.76837e-07, -0.211109, -0.378307, 0.04716, 0.900052, 1, 1, 1, 0.05, 1, -9.53674e-07, 1.19209e-07, 3.57628e-07, -0.122361, -0.307485, 0.0444022, 0.942608, 1, 1, 1, 0.1, 1, -6.85453e-07, -2.38419e-07, 5.96046e-07, 0.0655243, -0.124344, 0.0558387, 0.988497, 1, 1, 1, 0.15, 1, -7.7486e-07, -1.19209e-07, 5.66244e-07, 0.17223, 0.0168325, 0.088774, 0.980904, 1, 1, 1, 0.2, 1, -5.36442e-07, -3.57628e-07, 5.36442e-07, 0.151153, 0.0193605, 0.111763, 0.981981, 1, 1, 1, 0.25, 1, -6.25849e-07, -3.57628e-07, 5.96046e-07, 0.105831, 0.0199286, 0.119921, 0.986925, 1, 1, 1, 0.3, 1, -1.19209e-06, -5.96046e-07, 6.25849e-07, 0.11, 0.117841, 0.0973986, 0.982103, 1, 1, 1, 0.35, 1, -5.36442e-07, -1.19209e-07, 4.47035e-07, 0.163427, 0.213955, 0.0590648, 0.961263, 1, 1, 1, 0.4, 1, -6.85453e-07, -3.57628e-07, 5.06639e-07, 0.212517, 0.23167, 0.0327435, 0.948733, 1, 1, 1, 0.45, 1, -8.04663e-07, -2.38419e-07, 5.66244e-07, 0.240572, 0.207043, 0.0320326, 0.947751, 1, 1, 1, 0.5, 1, -9.23872e-07, 0, 8.04663e-07, 0.292283, 0.151342, 0.0529747, 0.942794, 1, 1, 1, 0.55, 1, -6.85453e-07, -3.57628e-07, 3.57628e-07, 0.354424, 0.0696654, 0.0852169, 0.928584, 1, 1, 1, 0.6, 1, -5.66244e-07, -2.38419e-07, 2.98023e-07, 0.397207, 0.0175472, 0.104303, 0.911614, 1, 1, 1, 0.65, 1, -8.34465e-07, -2.38419e-07, 4.47035e-07, 0.407225, -0.0166533, 0.0875941, 0.908965, 1, 1, 1, 0.7, 1, -1.2517e-06, -1.19209e-07, 6.55651e-07, 0.349327, -0.0813931, 0.0308211, 0.93295, 1, 1, 1, 0.75, 1, -1.19209e-07, 1.19209e-07, 2.08616e-07, 0.214708, -0.14004, -0.012317, 0.966508, 1, 1, 1, 0.8, 1, -6.55651e-07, -1.19209e-07, 2.98023e-07, -0.00140518, -0.171137, -0.0177305, 0.985087, 1, 1, 1, 0.85, 1, -4.76837e-07, -3.57628e-07, 3.8743e-07, -0.0925096, -0.171599, -0.011185, 0.98075, 1, 1, 1, 1.25, 1, -4.76837e-07, -3.57628e-07, 3.8743e-07, -0.0925096, -0.171599, -0.011185, 0.98075, 1, 1, 1 </real_array>
- <string name="tracks/3/type"> "transform" </string>
- <node_path name="tracks/3/path"> "Armature/Skeleton:l-forearm" </node_path>
- <int name="tracks/3/interp"> 1 </int>
- <real_array name="tracks/3/keys" len="180"> 0, 1, 2.08616e-07, -2.98023e-08, -5.96046e-07, 0.176871, 0.346752, 0.0115369, 0.921058, 1, 1, 1, 0.05, 1, -1.49012e-07, -4.76837e-07, -2.38419e-07, 0.1969, 0.431458, 0.0161118, 0.880236, 1, 1, 1, 0.1, 1, -3.57628e-07, -8.04663e-07, -4.76837e-07, 0.196923, 0.556224, 0.0152519, 0.80722, 1, 1, 1, 0.15, 1, -2.68221e-07, -4.17233e-07, -2.98023e-07, 0.134905, 0.568169, 0.00154346, 0.811777, 1, 1, 1, 0.2, 1, -1.49012e-07, -6.25849e-07, -4.17233e-07, 0.0562878, 0.484209, -0.00707307, 0.873111, 1, 1, 1, 0.25, 1, -2.98023e-08, -8.04663e-07, -3.57628e-07, 0.0047636, 0.406038, -0.0121859, 0.913763, 1, 1, 1, 0.3, 1, 5.96046e-08, -7.7486e-07, -1.78814e-07, -0.011494, 0.345751, -0.0179636, 0.938084, 1, 0.999999, 1, 0.4, 1, 5.36442e-07, -5.36442e-07, -1.19209e-07, -0.0325058, 0.107107, -0.00429871, 0.993707, 1, 0.999999, 1, 0.45, 1, 2.08616e-07, -8.34465e-07, -1.78814e-07, -0.0177273, 0.0767786, -0.00241131, 0.996888, 1, 1, 1, 0.65, 1, -5.96046e-08, -6.55651e-07, -1.07288e-06, 0.154364, 0.318848, -0.0046877, 0.935139, 1, 1, 1, 0.7, 1, 5.96046e-08, -9.23872e-07, -1.01328e-06, 0.155566, 0.376204, -0.00401138, 0.913375, 1, 1, 1, 0.75, 1, 0, -8.9407e-07, -4.17233e-07, 0.173064, 0.444685, 0.00561718, 0.87879, 1, 1, 1, 0.8, 1, 3.27826e-07, -6.55651e-07, -4.17233e-07, 0.251551, 0.464674, 0.00544377, 0.848982, 1, 1, 1, 0.85, 1, 8.9407e-08, -7.15256e-07, -9.53674e-07, 0.280639, 0.447823, -0.00246765, 0.848935, 1, 1, 1, 1.25, 1, 8.9407e-08, -7.15256e-07, -9.53674e-07, 0.280639, 0.447823, -0.00246765, 0.848935, 1, 1, 1 </real_array>
- <string name="tracks/4/type"> "transform" </string>
- <node_path name="tracks/4/path"> "Armature/Skeleton:r-thigh" </node_path>
- <int name="tracks/4/interp"> 1 </int>
- <real_array name="tracks/4/keys" len="192"> 0, 1, 0, 1.63913e-07, 1.93715e-07, -0.283345, 0.0300071, -0.0426225, 0.957601, 1, 1, 1, 0.05, 1, 8.9407e-08, 1.93715e-07, -5.06639e-07, -0.221388, 0.0587497, -0.0627932, 0.971387, 1, 1, 1, 0.15, 1, 5.96046e-08, 6.70552e-08, -1.3411e-07, 0.127996, 0.137739, -0.113256, 0.975612, 1, 1, 1, 0.2, 1, -5.96046e-08, -7.45058e-09, -7.45058e-07, 0.264976, 0.121823, -0.100248, 0.951261, 1, 1, 1, 0.25, 1, 2.98023e-08, -2.01166e-07, -4.91738e-07, 0.314522, 0.0998354, -0.077727, 0.94078, 1, 1, 1, 0.3, 1, 1.49012e-07, 1.3411e-07, 1.3411e-07, 0.306548, 0.0507913, -0.0454783, 0.949411, 1, 1, 1, 0.35, 1, 8.9407e-08, 7.45058e-09, -2.83122e-07, 0.297828, -0.0187708, -0.0207563, 0.954209, 1, 1, 1, 0.4, 1, 8.9407e-08, 4.47035e-08, -2.98023e-07, 0.287784, -0.0733564, -0.00467344, 0.95487, 1, 1, 1, 0.45, 1, 2.98023e-08, 2.23517e-08, -2.5332e-07, 0.170166, -0.0854042, 0.00266015, 0.981704, 1, 1, 1, 0.6, 1, 0, 1.04308e-07, 0, -0.531982, -0.0722138, 0.0220251, 0.843383, 1, 1, 1, 0.65, 1, 0, 1.3411e-07, -3.12924e-07, -0.652152, -0.0747176, 0.0102306, 0.754328, 1, 1, 1, 0.7, 1, -2.98023e-08, 0, 1.49012e-07, -0.686637, -0.0649825, 0.00231536, 0.724087, 1, 1, 1, 0.75, 1, 2.98023e-08, -1.56462e-07, -2.38419e-07, -0.638385, -0.0394346, -0.00259775, 0.768702, 1, 1, 1, 0.8, 1, 1.49012e-07, -8.9407e-08, -1.93715e-07, -0.432358, 0.00843852, -0.0248422, 0.90132, 1, 1, 1, 0.85, 1, 0, 1.63913e-07, 1.93715e-07, -0.283345, 0.0300071, -0.0426225, 0.957601, 1, 1, 1, 1.25, 1, 0, 1.63913e-07, 1.93715e-07, -0.283345, 0.0300071, -0.0426225, 0.957601, 1, 1, 1 </real_array>
- <string name="tracks/5/type"> "transform" </string>
- <node_path name="tracks/5/path"> "Armature/Skeleton:r-leg" </node_path>
- <int name="tracks/5/interp"> 1 </int>
- <real_array name="tracks/5/keys" len="216"> 0, 1, 2.29338e-08, 8.9407e-08, 5.36442e-07, -0.369097, -0.0505305, 0.00260278, 0.928013, 1, 1, 1, 0.05, 1, 8.26549e-08, 1.93715e-07, 4.76837e-07, -0.32656, -0.0387365, 0.00230976, 0.94438, 1, 1, 1, 0.15, 1, 4.78467e-08, -7.45058e-09, 7.7486e-07, -0.04833, 0.013837, -0.00331139, 0.99873, 1, 1, 1, 0.2, 1, 1.44588e-07, 0, 7.15256e-07, 0.0174433, 0.00914093, -0.00369525, 0.999799, 1, 1, 1, 0.25, 1, 4.49363e-08, 1.63913e-07, 2.38419e-07, -0.0309752, 0.0174032, -0.00233819, 0.999366, 1, 1, 1, 0.3, 1, 6.06524e-08, -7.45058e-08, 6.55651e-07, -0.161344, 0.031869, -0.00095907, 0.986383, 1, 1, 1, 0.35, 1, 6.23986e-08, 1.11759e-07, 5.36442e-07, -0.258604, 0.043227, -0.000463765, 0.965016, 1, 1, 1, 0.4, 1, 2.66591e-08, 1.11759e-07, 5.96046e-07, -0.311843, 0.0531668, -0.000274837, 0.948645, 1, 1, 1, 0.45, 1, -0.000736501, 0.00352155, -0.0507002, -0.471618, 0.0737067, 0.000546333, 0.878717, 1, 1, 1, 0.5, 1, -0.00351399, 0.0168005, -0.241486, -0.74573, 0.0999092, 7.49679e-05, 0.658714, 1, 1, 1, 0.55, 1, -0.00736267, 0.0352004, -0.505227, 0.896291, -0.0831834, 0.00513814, -0.435565, 1, 1, 1, 0.6, 1, -0.0098056, 0.0468799, -0.672563, 0.946677, -0.0409485, 0.00588309, -0.319519, 1, 1, 1, 0.65, 1, -0.0098056, 0.0468801, -0.672652, 0.947809, 0.0057637, 0.00256107, -0.318776, 1, 1, 1, 0.7, 1, -0.00736268, 0.0352004, -0.505962, 0.888767, 0.0669386, 0.000245982, -0.453445, 1, 1, 1, 0.75, 1, -0.003514, 0.016801, -0.242868, -0.757574, -0.0924392, -0.000540428, 0.64617, 1, 1, 1, 0.8, 1, -0.000736581, 0.0035219, -0.0512407, -0.527405, -0.0678553, 0.00109702, 0.846899, 1, 1, 1, 0.85, 1, 2.29338e-08, 8.9407e-08, 5.36442e-07, -0.369097, -0.0505305, 0.00260278, 0.928013, 1, 1, 1, 1.25, 1, 2.29338e-08, 8.9407e-08, 5.36442e-07, -0.369097, -0.0505305, 0.00260278, 0.928013, 1, 1, 1 </real_array>
- <string name="tracks/6/type"> "transform" </string>
- <node_path name="tracks/6/path"> "Armature/Skeleton:r-foot" </node_path>
- <int name="tracks/6/interp"> 1 </int>
- <real_array name="tracks/6/keys" len="216"> 0, 1, 1.49012e-08, 0, -5.21541e-08, 0.163945, 0.140221, -0.046324, 0.975354, 1, 1, 1, 0.05, 1, 9.68575e-08, 0, 7.82311e-08, 0.163142, 0.147087, -0.0386578, 0.974811, 1, 1, 1, 0.1, 1, 7.45058e-08, 0, 1.11759e-08, 0.154504, 0.157524, -0.0272069, 0.974974, 1, 1, 1, 0.15, 1, 8.9407e-08, 0, 3.72529e-08, 0.106593, 0.145246, -0.0455539, 0.982581, 1, 1, 1, 0.2, 1, 3.72529e-08, 0, 0, 0.00306457, 0.0975244, -0.0887594, 0.991263, 1, 1, 1, 0.3, 1, 4.47035e-08, 1.19209e-07, -1.60187e-07, -0.165764, -0.00244496, -0.0619073, 0.984217, 1, 1, 1, 0.35, 1, 3.72529e-08, -1.19209e-07, -1.2666e-07, -0.225564, -0.0444232, -0.0320188, 0.972688, 1, 1, 1, 0.4, 1, -2.98023e-08, -1.19209e-07, 1.3411e-07, -0.254966, -0.0644888, -0.0152293, 0.964677, 1, 1, 1, 0.45, 1, 5.96046e-08, 1.19209e-07, -3.72529e-09, -0.263415, -0.0674915, -0.0129876, 0.962231, 1, 1, 1, 0.5, 1, 7.45058e-08, 0, -2.98023e-08, -0.26682, -0.065605, -0.0157537, 0.961382, 1, 1, 1, 0.55, 1, 5.96046e-08, 0, 3.35276e-08, -0.268414, -0.0578826, -0.0205736, 0.961343, 1, 1, 1, 0.6, 1, 2.23517e-08, -1.19209e-07, 1.49012e-07, -0.268984, -0.0431783, -0.0254932, 0.961839, 1, 1, 1, 0.65, 1, 3.72529e-08, 0, -1.11759e-08, -0.205247, -0.0144598, -0.0301062, 0.97814, 1, 1, 1, 0.7, 1, 7.45058e-08, -1.19209e-07, -5.58794e-08, 0.0302446, 0.0427142, -0.0345553, 0.998031, 1, 1, 1, 0.75, 1, 8.9407e-08, 0, -1.11759e-07, 0.187052, 0.0967062, -0.0379775, 0.97684, 1, 1, 1, 0.8, 1, 8.19564e-08, -1.19209e-07, 2.23517e-08, 0.173053, 0.130372, -0.0438442, 0.975261, 1, 1, 1, 0.85, 1, 1.49012e-08, 0, -5.21541e-08, 0.163945, 0.140221, -0.046324, 0.975354, 1, 1, 1, 1.25, 1, 1.49012e-08, 0, -5.21541e-08, 0.163945, 0.140221, -0.046324, 0.975354, 1, 1, 1 </real_array>
- <string name="tracks/7/type"> "transform" </string>
- <node_path name="tracks/7/path"> "Armature/Skeleton:l-thigh" </node_path>
- <int name="tracks/7/interp"> 1 </int>
- <real_array name="tracks/7/keys" len="204"> 0, 1, 0, 2.08616e-07, 1.49012e-08, 0.284249, 0.0874448, 0.000525696, 0.954754, 1, 1, 1, 0.05, 1, 0, 1.11759e-07, -1.63913e-07, 0.0840381, 0.068345, -0.00156289, 0.994115, 1, 1, 1, 0.15, 1, 0, -9.68575e-08, -1.19209e-07, -0.428198, 0.103089, -0.0309307, 0.897253, 1, 1, 1, 0.2, 1, 2.98023e-08, 0, -2.5332e-07, -0.585268, 0.121806, -0.0264258, 0.801203, 1, 1, 1, 0.25, 1, -5.96046e-08, -2.68221e-07, -1.93715e-07, -0.68271, 0.117151, -0.00691618, 0.721203, 1, 1, 1, 0.3, 1, 5.96046e-08, 5.21541e-08, 3.57628e-07, -0.675843, 0.0951763, -0.00368054, 0.730865, 1, 1, 1, 0.35, 1, -5.96046e-08, -8.9407e-08, -1.04308e-07, -0.577504, 0.0522321, 0.00297164, 0.81471, 1, 1, 1, 0.4, 1, 0, 7.45058e-09, 1.63913e-07, -0.36481, -0.00958558, 0.0300626, 0.930547, 1, 1, 1, 0.45, 1, -1.19209e-07, 7.45058e-08, 1.49012e-07, -0.214962, -0.0628985, 0.0719756, 0.971933, 1, 1, 1, 0.5, 1, 0, 7.45058e-09, -7.15256e-07, -0.0924244, -0.113076, 0.110988, 0.983033, 1, 1, 1, 0.6, 1, 2.98023e-08, 3.72529e-08, 7.30157e-07, 0.212199, -0.104928, 0.0711089, 0.968971, 1, 1, 1, 0.65, 1, 8.9407e-08, 1.49012e-08, -1.63913e-07, 0.280374, -0.0786743, 0.0551762, 0.955069, 1, 1, 1, 0.7, 1, 0, 1.11759e-07, 2.5332e-07, 0.288443, -0.0349057, 0.033278, 0.956282, 1, 1, 1, 0.75, 1, -2.98023e-08, -1.3411e-07, -6.85453e-07, 0.285487, 0.0289713, 0.0136411, 0.957847, 1, 1, 1, 0.8, 1, -5.96046e-08, 8.9407e-08, -3.27826e-07, 0.284867, 0.0752772, 0.00313844, 0.955602, 1, 1, 1, 0.85, 1, 0, 2.08616e-07, 1.49012e-08, 0.284249, 0.0874448, 0.000525696, 0.954754, 1, 1, 1, 1.25, 1, 0, 2.08616e-07, 1.49012e-08, 0.284249, 0.0874448, 0.000525696, 0.954754, 1, 1, 1 </real_array>
- <string name="tracks/8/type"> "transform" </string>
- <node_path name="tracks/8/path"> "Armature/Skeleton:l-leg" </node_path>
- <int name="tracks/8/interp"> 1 </int>
- <real_array name="tracks/8/keys" len="216"> 0, 1, -6.98492e-10, -2.98023e-08, 4.76837e-07, -0.32359, -0.0556479, 0.000232734, 0.94456, 1, 1, 1, 0.05, 1, 0.0014394, 0.00688202, -0.0998148, -0.562955, -0.0817876, -0.000658042, 0.82243, 1, 1, 1, 0.1, 1, 0.00484604, 0.0231691, -0.333955, -0.80836, -0.0993527, 0.00161956, 0.580241, 1, 1, 1, 0.15, 1, 0.00839999, 0.04016, -0.576718, 0.916395, 0.0904963, -0.00581601, -0.389867, 1, 1, 1, 0.2, 1, 0.010174, 0.048641, -0.697832, 0.949699, 0.0597103, -0.00558806, -0.307368, 1, 1, 1, 0.25, 1, 0.00943748, 0.0451194, -0.647324, 0.940565, -0.00539416, -0.00131091, -0.339569, 1, 1, 1, 0.3, 1, 0.00617793, 0.0295368, -0.424059, -0.852217, 0.0810981, 0.000142268, 0.516865, 1, 1, 1, 0.35, 1, 0.00247674, 0.0118409, -0.170242, -0.686673, 0.0913182, 0.000156236, 0.721208, 1, 1, 1, 0.4, 1, 0.000368256, 0.00176083, -0.02535, -0.450712, 0.0617424, -0.0017981, 0.89053, 1, 1, 1, 0.45, 1, -3.27127e-08, -2.23517e-08, 0, -0.320919, 0.0402711, -0.00287403, 0.946246, 1, 1, 1, 0.5, 1, -3.65544e-08, 2.6077e-07, 0, -0.222093, 0.0121194, -0.000893378, 0.97495, 1, 1, 1, 0.55, 1, -7.85803e-08, -5.21541e-08, 5.96046e-08, -0.085227, -0.0121138, 0.00211304, 0.996286, 1, 1, 1, 0.6, 1, -9.66247e-09, -1.93715e-07, -5.96046e-08, -0.0204391, -0.0111085, 0.00211107, 0.999727, 1, 1, 1, 0.65, 1, -1.47847e-08, -7.45058e-09, 1.19209e-07, -0.0461144, -0.0137229, 0.00155832, 0.998841, 1, 1, 1, 0.75, 1, 9.77889e-08, -8.9407e-08, 0, -0.259445, -0.0379664, 0.000355786, 0.965011, 1, 1, 1, 0.8, 1, -3.06172e-08, -1.19209e-07, 1.19209e-07, -0.311223, -0.0514541, 0.000257438, 0.948943, 1, 1, 1, 0.85, 1, -6.98492e-10, -2.98023e-08, 4.76837e-07, -0.32359, -0.0556479, 0.000232734, 0.94456, 1, 1, 1, 1.25, 1, -6.98492e-10, -2.98023e-08, 4.76837e-07, -0.32359, -0.0556479, 0.000232734, 0.94456, 1, 1, 1 </real_array>
- <string name="tracks/9/type"> "transform" </string>
- <node_path name="tracks/9/path"> "Armature/Skeleton:l-foot" </node_path>
- <int name="tracks/9/interp"> 1 </int>
- <real_array name="tracks/9/keys" len="204"> 0, 1, 2.23517e-08, 1.19209e-07, 7.45058e-09, -0.260411, 0.0677016, 0.0123204, 0.963042, 1, 1, 1, 0.05, 1, 1.49012e-08, 1.19209e-07, -6.33299e-08, -0.261291, 0.0586691, 0.0123934, 0.963396, 1, 1, 1, 0.1, 1, 1.49012e-08, 1.19209e-07, 3.35276e-08, -0.262834, 0.0342669, 0.0126709, 0.964149, 1, 1, 1, 0.2, 1, 1.49012e-08, 0, 1.86265e-08, -0.260355, -0.0293857, 0.0140367, 0.964964, 1, 1, 1, 0.25, 1, -6.70552e-08, 0, -2.49594e-07, -0.153196, -0.0556389, 0.0191204, 0.986443, 1, 1, 1, 0.3, 1, 7.45058e-09, 2.38419e-07, 3.35276e-08, 0.102501, -0.0807205, 0.0313849, 0.990956, 1, 1, 1, 0.35, 1, -1.49012e-08, 1.19209e-07, -1.11759e-08, 0.182765, -0.105332, 0.0403985, 0.976663, 1, 1, 1, 0.4, 1, 0, 2.38419e-07, 2.98023e-08, 0.1689, -0.131443, 0.0454069, 0.975773, 1, 1, 1, 0.45, 1, -2.23517e-08, 1.19209e-07, 1.11759e-08, 0.162548, -0.163949, 0.0367097, 0.972292, 1, 1, 1, 0.5, 1, -7.45058e-09, 1.19209e-07, -6.70552e-08, 0.160675, -0.186181, 0.0223394, 0.969031, 1, 1, 1, 0.55, 1, 0, 2.38419e-07, -4.09782e-08, 0.121712, -0.123055, 0.0340729, 0.984318, 1, 1, 1, 0.65, 1, -2.23517e-08, 2.38419e-07, -4.84288e-08, -0.0909908, -0.00331438, 0.030867, 0.995368, 1, 1, 1, 0.7, 1, -2.98023e-08, 0, -1.86265e-08, -0.167009, 0.0327264, 0.0253347, 0.985086, 1, 1, 1, 0.75, 1, -1.49012e-08, 2.38419e-07, -9.31323e-08, -0.225897, 0.0565391, 0.0182554, 0.972338, 1, 1, 1, 0.8, 1, 7.45058e-09, 0, 1.41561e-07, -0.254123, 0.0658906, 0.0135391, 0.96483, 1, 1, 1, 0.85, 1, 2.23517e-08, 1.19209e-07, 7.45058e-09, -0.260411, 0.0677016, 0.0123204, 0.963042, 1, 1, 1, 1.25, 1, 2.23517e-08, 1.19209e-07, 7.45058e-09, -0.260411, 0.0677016, 0.0123204, 0.963042, 1, 1, 1 </real_array>
- <string name="tracks/10/type"> "transform" </string>
- <node_path name="tracks/10/path"> "Armature/Skeleton:MASTER" </node_path>
- <int name="tracks/10/interp"> 1 </int>
- <real_array name="tracks/10/keys" len="24"> 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/11/type"> "transform" </string>
- <node_path name="tracks/11/path"> "Armature/Skeleton:HEAD" </node_path>
- <int name="tracks/11/interp"> 1 </int>
- <real_array name="tracks/11/keys" len="192"> 0, 1, -5.68434e-14, 0, 0.994808, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -5.68434e-14, 0, 0.908378, 0, 0, 0, 1, 1, 1, 1, 0.1, 1, -5.68434e-14, 0, 0.865919, 0, 0, 7.10543e-15, 1, 1, 1, 1, 0.15, 1, -5.68434e-14, 0, 0.952043, 0, 0, 0, 1, 1, 1, 1, 0.25, 1, -5.68434e-14, 0, 1.23636, 0, 0, 0, 1, 1, 1, 1, 0.3, 1, -5.68434e-14, 0, 1.26452, 0, 0, 7.10543e-15, 1, 1, 1, 1, 0.35, 1, -5.68434e-14, 0, 1.17812, 0, 0, -7.10543e-15, 1, 1, 1, 1, 0.45, 1, -5.68434e-14, 0, 0.917901, 0, 0, 0, 1, 1, 1, 1, 0.5, 1, -5.68434e-14, 0, 0.850875, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, -5.68434e-14, 0, 0.90967, 0, 0, 0, 1, 1, 1, 1, 0.65, 1, -5.68434e-14, 0, 1.19399, 0, 0, 0, 1, 1, 1, 1, 0.7, 1, -5.68434e-14, 0, 1.26645, 0, 0, 7.10543e-15, 1, 1, 1, 1, 0.75, 1, -5.68434e-14, 0, 1.20667, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, -5.68434e-14, 0, 1.04898, 0, 0, 7.10543e-15, 1, 1, 1, 1, 0.85, 1, -5.68434e-14, 0, 0.994808, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -5.68434e-14, 0, 0.994808, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/12/type"> "transform" </string>
- <node_path name="tracks/12/path"> "Armature/Skeleton:r-LEGCONTROL" </node_path>
- <int name="tracks/12/interp"> 1 </int>
- <real_array name="tracks/12/keys" len="192"> 0, 1, -0.142338, -0.593751, 0.041427, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -0.141891, -0.466314, 0.0666584, 0, 0, 0, 1, 1, 1, 1, 0.1, 1, -0.140854, -0.18721, 0.16679, 0, 0, 0, 1, 1, 1, 1, 0.3, 1, -0.135712, 0.882052, 1.08263, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, -0.134593, 1.04285, 1.23903, 0, 0, 0, 1, 1, 1, 1, 0.4, 1, -0.134052, 1.11594, 1.33052, 0, 0, 0, 1, 1, 1, 1, 0.45, 1, -0.134139, 1.01025, 1.37488, 0, 0, 0, 1, 1, 1, 1, 0.5, 1, -0.134864, 0.561422, 1.40083, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, -0.136154, -0.107091, 1.41207, 0, 0, 0, 1, 1, 1, 1, 0.6, 1, -0.137517, -0.627938, 1.41499, 0, 0, 0, 1, 1, 1, 1, 0.65, 1, -0.138802, -0.880369, 1.32217, 0, 0, 0, 1, 1, 1, 1, 0.7, 1, -0.140187, -0.97361, 0.946171, 0, 0, 0, 1, 1, 1, 1, 0.75, 1, -0.141374, -0.990009, 0.507478, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, -0.142135, -0.753522, 0.166703, 0, 0, 0, 1, 1, 1, 1, 0.85, 1, -0.142338, -0.593751, 0.041427, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.142338, -0.593751, 0.041427, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/13/type"> "transform" </string>
- <node_path name="tracks/13/path"> "Armature/Skeleton:l-LEGCONTROL" </node_path>
- <int name="tracks/13/interp"> 1 </int>
- <real_array name="tracks/13/keys" len="192"> 0, 1, 0.133965, 1.12742, 1.35169, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 0.134319, 0.88137, 1.36048, 0, 0, 0, 1, 1, 1, 1, 0.15, 1, 0.136624, -0.318866, 1.4031, 0, 0, 0, 1, 1, 1, 1, 0.2, 1, 0.13794, -0.745207, 1.41408, 0, 0, 0, 1, 1, 1, 1, 0.25, 1, 0.139237, -0.932173, 1.26013, 0, 0, 0, 1, 1, 1, 1, 0.3, 1, 0.140615, -0.985177, 0.795642, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, 0.141658, -0.933265, 0.382912, 0, 0, 0, 1, 1, 1, 1, 0.4, 1, 0.142236, -0.69551, 0.103281, 0, 0, 0, 1, 1, 1, 1, 0.45, 1, 0.142112, -0.449542, 0.0515677, 0, 0, 0, 1, 1, 1, 1, 0.5, 1, 0.141234, -0.239295, 0.11699, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, 0.140074, 0.0127278, 0.285218, 0, 0, 0, 1, 1, 1, 1, 0.7, 1, 0.136158, 0.812955, 1.03336, 0, 0, 0, 1, 1, 1, 1, 0.75, 1, 0.134866, 1.00553, 1.22614, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, 0.13414, 1.10444, 1.32777, 0, 0, 0, 1, 1, 1, 1, 0.85, 1, 0.133965, 1.12742, 1.35169, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.133965, 1.12742, 1.35169, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/14/type"> "transform" </string>
- <node_path name="tracks/14/path"> "Armature/Skeleton:r-LEGORIENT" </node_path>
- <int name="tracks/14/interp"> 1 </int>
- <real_array name="tracks/14/keys" len="180"> 0, 1, 0.100474, 0.669825, -0.778672, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 0.0953997, 0.642052, -0.742965, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 0.1, 1, 0.0823101, 0.56581, -0.648221, 4.1297e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.35, 1, 0.0243976, -0.0441461, -0.063019, 4.1297e-08, 2.53394e-15, -7.10543e-15, 1, 1, 1, 1, 0.4, 1, 0.020945, -0.11126, -0.00892317, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 0.45, 1, 0.0214889, -0.0993756, -0.1204, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.5, 1, 0.0261557, -0.00703263, -0.571036, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, 0.0350212, 0.144668, -1.19143, 7.10993e-08, 6.08666e-15, -4.32757e-22, 1, 1, 1, 1, 0.6, 1, 0.0452013, 0.286137, -1.58564, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.65, 1, 0.056361, 0.396596, -1.62736, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.7, 1, 0.0713525, 0.504199, -1.41721, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 0.75, 1, 0.0877976, 0.602767, -1.08603, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, 0.097935, 0.656912, -0.843801, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 0.85, 1, 0.100474, 0.669825, -0.778672, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.100474, 0.669825, -0.778672, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/15/type"> "transform" </string>
- <node_path name="tracks/15/path"> "Armature/Skeleton:l-LEGORIENT" </node_path>
- <int name="tracks/15/interp"> 1 </int>
- <real_array name="tracks/15/keys" len="180"> 0, 1, -0.0204011, -0.122407, 5.96046e-08, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -0.0226399, -0.0760723, -0.246171, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 0.15, 1, -0.0384328, 0.195889, -1.36473, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.2, 1, -0.0485586, 0.325533, -1.64571, 7.10993e-08, 9.63937e-15, -6.85353e-22, 1, 1, 1, 1, 0.25, 1, -0.0604436, 0.430887, -1.61593, 0, 0, 0, 1, 1, 1, 1, 0.3, 1, -0.0768237, 0.538687, -1.39129, 7.10993e-08, 2.53394e-15, -2.11758e-22, 1, 1, 1, 1, 0.35, 1, -0.0915991, 0.623227, -1.09587, 4.1297e-08, 2.53394e-15, -7.10543e-15, 1, 1, 1, 1, 0.4, 1, -0.0992045, 0.663389, -0.847581, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 0.45, 1, -0.0979352, 0.656214, -0.687419, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.5, 1, -0.0877979, 0.599371, -0.580202, 0, 0, 0, 1, 1, 1, 1, 0.65, 1, -0.0452008, 0.276356, -0.334939, 7.10993e-08, 2.53395e-15, 7.10543e-15, 1, 1, 1, 1, 0.75, 1, -0.0261556, -0.010167, -0.0897738, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, -0.0214889, -0.0999783, -0.0177123, 7.10993e-08, 6.08666e-15, 7.10543e-15, 1, 1, 1, 1, 0.85, 1, -0.0204011, -0.122407, 5.96046e-08, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.0204011, -0.122407, 5.96046e-08, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/16/type"> "transform" </string>
- <node_path name="tracks/16/path"> "Armature/Skeleton:r-ARMCONTROL" </node_path>
- <int name="tracks/16/interp"> 1 </int>
- <real_array name="tracks/16/keys" len="168"> 0, 1, -0.868295, 0.288818, -0.834593, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -0.920336, 0.223441, -0.675278, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, -1.0611, 0.0535004, -0.268795, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.3, 1, -1.81549, -0.572945, 1.93497, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.35, 1, -1.97521, -0.260334, 2.42549, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, -2.07242, 0.0952058, 2.72719, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, -2.06152, 0.134094, 2.70055, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.5, 1, -1.94935, -0.00418663, 2.38214, 0, 0, 0, 1, 1, 1, 1, 0.6, 1, -1.5659, -0.316463, 1.27531, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.65, 1, -1.39564, -0.31023, 0.768786, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.75, 1, -1.01032, 0.0728607, -0.380929, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, -0.896442, 0.243316, -0.739858, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.85, 1, -0.868295, 0.288818, -0.834593, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -0.868295, 0.288818, -0.834593, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/17/type"> "transform" </string>
- <node_path name="tracks/17/path"> "Armature/Skeleton:l-ARMCONTROL" </node_path>
- <int name="tracks/17/interp"> 1 </int>
- <real_array name="tracks/17/keys" len="168"> 0, 1, 2.08906, 0.170859, 2.78004, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 2.03311, 0.0989122, 2.61048, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, 1.88529, -0.0705678, 2.18507, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.2, 1, 1.50915, -0.334755, 1.10648, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.25, 1, 1.33866, -0.287646, 0.593788, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, 0.966909, 0.137533, -0.532556, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, 0.882217, 0.266322, -0.791318, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, 0.89374, 0.256562, -0.760212, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.5, 1, 0.999084, 0.126561, -0.459517, 0, 0, 0, 1, 1, 1, 1, 0.7, 1, 1.75712, -0.595706, 1.75783, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.75, 1, 1.92686, -0.424236, 2.27222, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, 2.0556, 0.0151663, 2.66931, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.85, 1, 2.08906, 0.170859, 2.78004, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 2.08906, 0.170859, 2.78004, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/18/type"> "transform" </string>
- <node_path name="tracks/18/path"> "Armature/Skeleton:r-ARMORIENT" </node_path>
- <int name="tracks/18/interp"> 1 </int>
- <real_array name="tracks/18/keys" len="156"> 0, 1, 0.405204, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, 0.341349, -0.264663, 0.0556155, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.15, 1, 0.0336542, -1.45692, 0.323532, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.2, 1, -0.0452293, -1.75482, 0.391734, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.25, 1, 0.0926713, -1.62165, 0.363375, 0, 0, 0, 1, 1, 1, 1, 0.35, 1, 1.18685, -0.378264, 0.0954279, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, 1.51909, 0.00473738, 0.0141962, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, 1.55064, 0.0706801, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.5, 1, 1.44211, 0.0639179, 0, 0, 0, 0, 1, 1, 1, 1, 0.75, 1, 0.54098, 0.00832748, 0, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, 0.432091, 0.00163841, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.85, 1, 0.405204, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, 0.405204, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/19/type"> "transform" </string>
- <node_path name="tracks/19/path"> "Armature/Skeleton:l-ARMORIENT" </node_path>
- <int name="tracks/19/interp"> 1 </int>
- <real_array name="tracks/19/keys" len="168"> 0, 1, -1.5774, 0.0723579, 0, 0, 0, 0, 1, 1, 1, 1, 0.05, 1, -1.5235, 0.0690539, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.1, 1, -1.38104, 0.0602572, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.4, 1, -0.448482, 0.0061903, 0, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.45, 1, -0.312683, -0.140136, 0.0283925, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.5, 1, -0.161211, -0.627825, 0.135386, 0, 0, 0, 1, 1, 1, 1, 0.55, 1, -0.030728, -1.28144, 0.283529, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.6, 1, 0.0389389, -1.69292, 0.377552, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.65, 1, -0.0330012, -1.68882, 0.377568, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.7, 1, -0.409697, -1.26443, 0.283661, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.75, 1, -1.00503, -0.588506, 0.135634, 0, 0, 0, 1, 1, 1, 1, 0.8, 1, -1.45325, -0.0721812, 0.0284887, -5.1658e-08, 0, 0, 1, 1, 1, 1, 0.85, 1, -1.5774, 0.0723579, 0, 0, 0, 0, 1, 1, 1, 1, 1.25, 1, -1.5774, 0.0723579, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/20/type"> "transform" </string>
- <node_path name="tracks/20/path"> "Armature/Skeleton:hip" </node_path>
- <int name="tracks/20/interp"> 1 </int>
- <real_array name="tracks/20/keys" len="216"> 0, 1, 0.050238, 0.697428, 0.108012, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1, 0.05, 1, 0.0669454, 0.729981, 0.0847113, 0.0751978, 0.000902196, 0.0773167, 0.994166, 1, 1, 1, 0.15, 1, 0.147711, 0.887191, -0.02789, 0.103321, 0.0347243, 0.0196114, 0.993848, 1, 1, 1, 0.2, 1, 0.168294, 0.927241, -0.0565808, 0.110419, 0.0433374, -0.00845134, 0.992904, 1, 1, 1, 0.25, 1, 0.154709, 0.910602, -0.0446639, 0.107418, 0.0422538, -0.0318613, 0.992804, 1, 1, 1, 0.3, 1, 0.0960078, 0.836978, 0.00806546, 0.0942701, 0.034167, -0.0564973, 0.993355, 1, 1, 1, 0.35, 1, 0.021745, 0.753374, 0.0679436, 0.0793445, 0.0222103, -0.0760792, 0.993692, 1, 1, 1, 0.4, 1, -0.035471, 0.705747, 0.102054, 0.07085, 0.00995431, -0.0854402, 0.993771, 1, 1, 1, 0.45, 1, -0.0674228, 0.714066, 0.0960958, 0.0723594, -0.00257329, -0.0821245, 0.993989, 1, 1, 1, 0.5, 1, -0.0866932, 0.776805, 0.0511615, 0.0836199, -0.0185098, -0.0626717, 0.994353, 1, 1, 1, 0.55, 1, -0.0950061, 0.863738, -0.0110998, 0.0991637, -0.0338542, -0.0304325, 0.994029, 1, 1, 1, 0.6, 1, -0.0971422, 0.918921, -0.0506222, 0.108957, -0.0424157, -6.6921e-05, 0.993141, 1, 1, 1, 0.65, 1, -0.0894483, 0.918925, -0.0506237, 0.108927, -0.0421963, 0.0241723, 0.99286, 1, 1, 1, 0.7, 1, -0.0546535, 0.863773, -0.0111129, 0.0990954, -0.0332032, 0.0485143, 0.99334, 1, 1, 1, 0.75, 1, 0.000162542, 0.776872, 0.051137, 0.0835711, -0.0190219, 0.071275, 0.993768, 1, 1, 1, 0.8, 1, 0.0397389, 0.714092, 0.0960863, 0.072346, -0.00878352, 0.08392, 0.993804, 1, 1, 1, 0.85, 1, 0.050238, 0.697428, 0.108012, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1, 1.25, 1, 0.050238, 0.697428, 0.108012, 0.0693673, -0.00606888, 0.0869442, 0.993777, 1, 1, 1 </real_array>
- <string name="tracks/21/type"> "transform" </string>
- <node_path name="tracks/21/path"> "Armature/Skeleton:waist" </node_path>
- <int name="tracks/21/interp"> 1 </int>
- <real_array name="tracks/21/keys" len="180"> 0, 1, 7.45059e-09, -5.21541e-08, 2.38419e-07, 0.0550011, -0.00481196, -0.0870228, 0.994675, 1, 1, 1, 0.05, 1, -2.16067e-08, -1.49015e-09, 1.19209e-07, 0.0607085, -0.00428583, -0.0791363, 0.995004, 1, 1, 1, 0.1, 1, -2.23518e-09, 4.61936e-08, 1.49012e-07, 0.0742298, -0.00290666, -0.0580589, 0.995545, 1, 1, 1, 0.2, 1, -1.22934e-08, -7.00588e-08, 1.49012e-07, 0.0953622, 0.000412438, -0.00409159, 0.995434, 1, 1, 1, 0.25, 1, -1.86265e-08, 1.39698e-08, -1.49012e-07, 0.0924473, 0.00171257, 0.0202586, 0.99551, 1, 1, 1, 0.35, 1, -1.56462e-08, 3.1013e-08, 0, 0.0648424, 0.00419923, 0.0731356, 0.995203, 1, 1, 1, 0.4, 1, 2.23523e-09, -2.84985e-08, 1.19209e-07, 0.0564666, 0.00472734, 0.0850757, 0.994762, 1, 1, 1, 0.45, 1, -4.47039e-09, 2.23518e-08, -8.9407e-08, 0.0579181, 0.00454757, 0.0830774, 0.994848, 1, 1, 1, 0.5, 1, 8.43755e-15, -5.58794e-08, 8.9407e-08, 0.0689504, 0.00348495, 0.0670145, 0.995361, 1, 1, 1, 0.6, 1, 5.5879e-09, -7.60309e-08, -2.98023e-08, 0.0939097, 5.69107e-05, 0.0121633, 0.995506, 1, 1, 1, 0.65, 1, 1.78815e-08, -2.31898e-08, 3.27826e-07, 0.0939129, -0.00128467, -0.0120988, 0.995506, 1, 1, 1, 0.75, 1, -1.86265e-09, 3.11993e-08, -2.98023e-08, 0.0689717, -0.00392611, -0.0670089, 0.995358, 1, 1, 1, 0.8, 1, 1.49013e-09, 4.80559e-08, 0, 0.0579302, -0.00464071, -0.0830884, 0.994846, 1, 1, 1, 0.85, 1, 7.45059e-09, -5.21541e-08, 2.38419e-07, 0.0550011, -0.00481196, -0.0870228, 0.994675, 1, 1, 1, 1.25, 1, 7.45059e-09, -5.21541e-08, 2.38419e-07, 0.0550011, -0.00481196, -0.0870228, 0.994675, 1, 1, 1 </real_array>
- <string name="tracks/22/type"> "transform" </string>
- <node_path name="tracks/22/path"> "Armature/Skeleton:chest" </node_path>
- <int name="tracks/22/interp"> 1 </int>
- <real_array name="tracks/22/keys" len="168"> 0, 1, -1.93979e-09, 3.72529e-08, -1.78814e-07, 0.0947232, -0.00739035, -0.0868418, 0.991681, 1, 1, 1, 0.05, 1, 9.31322e-10, 7.07805e-08, 5.96046e-08, 0.0947233, -0.00739035, -0.0868419, 0.991681, 1, 1, 1, 0.1, 1, 6.51926e-10, 7.07805e-08, 5.96046e-08, 0.0949443, -0.00694628, -0.0757376, 0.992573, 1, 1, 1, 0.15, 1, 3.7253e-10, -2.6077e-08, -2.38419e-07, 0.0959905, -0.00433497, -0.0114678, 0.995307, 1, 1, 1, 0.25, 1, 1.86265e-08, 2.23517e-08, 1.19209e-07, 0.0965992, 0.00494126, 0.201269, 0.974749, 1, 1, 1, 0.3, 1, -7.68343e-10, 7.45058e-09, 1.78814e-07, 0.0963173, 0.00675391, 0.221794, 0.970301, 1, 1, 1, 0.4, 1, -1.56574e-10, 7.82311e-08, -1.78814e-07, 0.0949654, 0.0073896, 0.100605, 0.990356, 1, 1, 1, 0.45, 1, 3.30057e-09, 1.08033e-07, -5.96046e-08, 0.0947232, 0.00739035, 0.0868418, 0.991681, 1, 1, 1, 0.5, 1, -3.25963e-09, -9.31323e-08, 5.96046e-08, 0.0947232, 0.00739035, 0.0868418, 0.991681, 1, 1, 1, 0.55, 1, -2.10027e-08, 7.45058e-08, -1.78814e-07, 0.0955253, 0.00546829, 0.0431828, 0.994475, 1, 1, 1, 0.65, 1, 1.26195e-08, -4.84288e-08, -2.38419e-07, 0.0967914, -0.0040173, -0.170015, 0.980668, 1, 1, 1, 0.7, 1, 1.23865e-08, -8.19564e-08, -5.96046e-08, 0.0964064, -0.00640121, -0.223121, 0.969991, 1, 1, 1, 0.75, 1, 1.86265e-09, -7.07805e-08, -2.98023e-07, 0.0963505, -0.00664593, -0.228565, 0.968726, 1, 1, 1, 1.25, 1, -1.93979e-09, 3.72529e-08, -1.78814e-07, 0.0963505, -0.00664594, -0.228565, 0.968726, 1, 1, 1 </real_array>
- <string name="tracks/23/type"> "transform" </string>
- <node_path name="tracks/23/path"> "Armature/Skeleton:neck" </node_path>
- <int name="tracks/23/interp"> 1 </int>
- <real_array name="tracks/23/keys" len="24"> 0, 1, -1.95579e-08, -1.49012e-08, -9.53674e-07, -7.45058e-09, -2.48375e-09, 8.87174e-09, 1, 1, 1, 1, 1.25, 1, -6.51927e-08, -7.45058e-08, -9.53674e-07, 6.80667e-18, 2.71908e-09, -1.56593e-08, 1, 1, 1, 1 </real_array>
- <string name="tracks/24/type"> "transform" </string>
- <node_path name="tracks/24/path"> "Armature/Skeleton:headtracker" </node_path>
- <int name="tracks/24/interp"> 1 </int>
- <real_array name="tracks/24/keys" len="204"> 0, 1, 2.79375e-09, -5.96046e-07, -2.50526e-07, 0.174741, -0.0963796, 0.0144345, 0.97978, 1, 1, 1, 0.05, 1, -3.7254e-09, -2.08616e-07, -1.22236e-07, 0.195715, -0.0950264, 0.0238173, 0.975755, 1, 1, 1, 0.1, 1, 4.54485e-08, -7.15256e-07, -7.68341e-08, 0.229373, -0.0816785, 0.0404464, 0.969062, 1, 1, 1, 0.15, 1, -1.49012e-08, -6.85453e-07, -8.59145e-08, 0.25499, -0.0176933, 0.0391946, 0.965987, 1, 1, 1, 0.25, 1, 1.4901e-08, -1.49012e-07, -1.78115e-07, 0.23692, 0.192561, -0.0167461, 0.952108, 1, 1, 1, 0.3, 1, -4.61937e-08, -4.47035e-07, -1.46218e-07, 0.20349, 0.220566, -0.0253329, 0.953573, 1, 1, 1, 0.35, 1, 8.94071e-09, -2.68221e-07, -1.97906e-08, 0.179164, 0.172369, -0.0185073, 0.968425, 1, 1, 1, 0.4, 1, 2.23509e-09, -3.57628e-07, -9.56934e-08, 0.17384, 0.110352, -0.0138213, 0.978474, 1, 1, 1, 0.45, 1, -2.75671e-08, -7.45058e-07, 2.63099e-08, 0.188123, 0.0930304, -0.0247279, 0.977417, 1, 1, 1, 0.5, 1, -9.31436e-10, 4.47035e-07, -6.37956e-08, 0.217624, 0.0872372, -0.0441829, 0.971122, 1, 1, 1, 0.55, 1, 1.04306e-08, -2.38419e-07, -1.33412e-07, 0.247766, 0.0401273, -0.0490683, 0.966744, 1, 1, 1, 0.65, 1, 3.27827e-08, -4.47035e-07, -6.26314e-08, 0.245106, -0.170404, 0.00637661, 0.954382, 1, 1, 1, 0.7, 1, 3.27823e-08, -1.49012e-07, -6.70552e-08, 0.212986, -0.224596, 0.0272969, 0.950499, 1, 1, 1, 0.75, 1, -7.45057e-08, 0, 6.33299e-08, 0.183845, -0.233119, 0.0392625, 0.954104, 1, 1, 1, 0.8, 1, -6.7055e-08, -5.96046e-07, -5.00586e-08, 0.175853, -0.235075, 0.0484733, 0.954707, 1, 1, 1, 0.85, 1, 7.45066e-09, -6.55651e-07, 6.75209e-09, 0.174943, -0.235515, 0.051072, 0.95463, 1, 1, 1, 1.25, 1, 7.45066e-09, -6.55651e-07, 6.75209e-09, 0.174943, -0.235515, 0.051072, 0.95463, 1, 1, 1 </real_array>
- <string name="tracks/25/type"> "transform" </string>
- <node_path name="tracks/25/path"> "Armature/Skeleton:head" </node_path>
- <int name="tracks/25/interp"> 1 </int>
- <real_array name="tracks/25/keys" len="24"> 0, 1, -1.25867e-08, -4.23752e-08, -2.57976e-07, 2.23517e-08, 3.7017e-10, 7.60394e-10, 1, 1, 1, 1, 1.25, 1, 1.23749e-08, -2.09548e-09, 2.43308e-07, 2.23517e-08, -2.79233e-10, -7.29088e-11, 1, 1, 1, 1 </real_array>
- <string name="tracks/26/type"> "transform" </string>
- <node_path name="tracks/26/path"> "Armature/Skeleton:vent" </node_path>
- <int name="tracks/26/interp"> 1 </int>
- <real_array name="tracks/26/keys" len="24"> 0, 1, 5.20962e-08, 0.00292337, 0.204329, -7.21775e-09, 1.1358e-11, -7.03732e-10, 1, 1, 1, 1, 1.25, 1, 4.12186e-08, 0.00292328, 0.20433, -8.14907e-09, 9.21561e-11, 1.63806e-10, 1, 1, 1, 1 </real_array>
-
- </resource>
- <resource type="Animation" path="local://14">
- <string name="resource/name"> "default" </string>
- <real name="length"> 1.25 </real>
- <bool name="loop"> False </bool>
- <real name="step"> 0.1 </real>
- <string name="tracks/0/type"> "transform" </string>
- <node_path name="tracks/0/path"> "Armature/Skeleton:r-arm" </node_path>
- <int name="tracks/0/interp"> 1 </int>
- <real_array name="tracks/0/keys" len="12"> 0, 1, 5.06639e-07, -1.19209e-07, 3.57628e-07, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/1/type"> "transform" </string>
- <node_path name="tracks/1/path"> "Armature/Skeleton:r-forearm" </node_path>
- <int name="tracks/1/interp"> 1 </int>
- <real_array name="tracks/1/keys" len="12"> 0, 1, 1.19209e-07, -8.9407e-07, -1.19209e-07, -3.72529e-08, -1.49012e-08, 2.23517e-08, 1, 1, 1, 1 </real_array>
- <string name="tracks/2/type"> "transform" </string>
- <node_path name="tracks/2/path"> "Armature/Skeleton:l-arm" </node_path>
- <int name="tracks/2/interp"> 1 </int>
- <real_array name="tracks/2/keys" len="12"> 0, 1, -5.06639e-07, -1.19209e-07, 3.57628e-07, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/3/type"> "transform" </string>
- <node_path name="tracks/3/path"> "Armature/Skeleton:l-forearm" </node_path>
- <int name="tracks/3/interp"> 1 </int>
- <real_array name="tracks/3/keys" len="12"> 0, 1, -1.19209e-07, -8.9407e-07, -1.19209e-07, -3.72529e-08, 1.49012e-08, -2.23517e-08, 1, 1, 1, 1 </real_array>
- <string name="tracks/4/type"> "transform" </string>
- <node_path name="tracks/4/path"> "Armature/Skeleton:r-thigh" </node_path>
- <int name="tracks/4/interp"> 1 </int>
- <real_array name="tracks/4/keys" len="12"> 0, 1, 0, 2.98023e-08, -2.5332e-07, 0, 5.20417e-18, -2.79397e-09, 1, 1, 1, 1 </real_array>
- <string name="tracks/5/type"> "transform" </string>
- <node_path name="tracks/5/path"> "Armature/Skeleton:r-leg" </node_path>
- <int name="tracks/5/interp"> 1 </int>
- <real_array name="tracks/5/keys" len="12"> 0, 1, 2.10712e-08, -7.45058e-09, 5.96046e-07, 7.45058e-09, 3.60887e-09, 3.91446e-09, 1, 1, 1, 1 </real_array>
- <string name="tracks/6/type"> "transform" </string>
- <node_path name="tracks/6/path"> "Armature/Skeleton:r-foot" </node_path>
- <int name="tracks/6/interp"> 1 </int>
- <real_array name="tracks/6/keys" len="12"> 0, 1, 6.70552e-08, 1.19209e-07, 0, 3.72529e-09, 1.16415e-09, 3.72529e-09, 1, 1, 1, 1 </real_array>
- <string name="tracks/7/type"> "transform" </string>
- <node_path name="tracks/7/path"> "Armature/Skeleton:l-thigh" </node_path>
- <int name="tracks/7/interp"> 1 </int>
- <real_array name="tracks/7/keys" len="12"> 0, 1, 0, 2.98023e-08, -1.49012e-08, 1.86265e-09, 7.45058e-09, 2.09548e-09, 1, 1, 1, 1 </real_array>
- <string name="tracks/8/type"> "transform" </string>
- <node_path name="tracks/8/path"> "Armature/Skeleton:l-leg" </node_path>
- <int name="tracks/8/interp"> 1 </int>
- <real_array name="tracks/8/keys" len="12"> 0, 1, 1.74623e-08, -2.98023e-08, 2.98023e-07, 3.72529e-09, 7.45058e-09, -1.17143e-09, 1, 1, 1, 1 </real_array>
- <string name="tracks/9/type"> "transform" </string>
- <node_path name="tracks/9/path"> "Armature/Skeleton:l-foot" </node_path>
- <int name="tracks/9/interp"> 1 </int>
- <real_array name="tracks/9/keys" len="12"> 0, 1, 1.49012e-08, 0, 0, 0, -1.39698e-09, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/10/type"> "transform" </string>
- <node_path name="tracks/10/path"> "Armature/Skeleton:MASTER" </node_path>
- <int name="tracks/10/interp"> 1 </int>
- <real_array name="tracks/10/keys" len="12"> 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/11/type"> "transform" </string>
- <node_path name="tracks/11/path"> "Armature/Skeleton:HEAD" </node_path>
- <int name="tracks/11/interp"> 1 </int>
- <real_array name="tracks/11/keys" len="12"> 0, 1, -5.68434e-14, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/12/type"> "transform" </string>
- <node_path name="tracks/12/path"> "Armature/Skeleton:r-LEGCONTROL" </node_path>
- <int name="tracks/12/interp"> 1 </int>
- <real_array name="tracks/12/keys" len="12"> 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/13/type"> "transform" </string>
- <node_path name="tracks/13/path"> "Armature/Skeleton:l-LEGCONTROL" </node_path>
- <int name="tracks/13/interp"> 1 </int>
- <real_array name="tracks/13/keys" len="12"> 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/14/type"> "transform" </string>
- <node_path name="tracks/14/path"> "Armature/Skeleton:r-LEGORIENT" </node_path>
- <int name="tracks/14/interp"> 1 </int>
- <real_array name="tracks/14/keys" len="12"> 0, 1, -2.98023e-08, 1.19209e-07, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/15/type"> "transform" </string>
- <node_path name="tracks/15/path"> "Armature/Skeleton:l-LEGORIENT" </node_path>
- <int name="tracks/15/interp"> 1 </int>
- <real_array name="tracks/15/keys" len="12"> 0, 1, 2.98023e-08, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/16/type"> "transform" </string>
- <node_path name="tracks/16/path"> "Armature/Skeleton:r-ARMCONTROL" </node_path>
- <int name="tracks/16/interp"> 1 </int>
- <real_array name="tracks/16/keys" len="12"> 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/17/type"> "transform" </string>
- <node_path name="tracks/17/path"> "Armature/Skeleton:l-ARMCONTROL" </node_path>
- <int name="tracks/17/interp"> 1 </int>
- <real_array name="tracks/17/keys" len="12"> 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/18/type"> "transform" </string>
- <node_path name="tracks/18/path"> "Armature/Skeleton:r-ARMORIENT" </node_path>
- <int name="tracks/18/interp"> 1 </int>
- <real_array name="tracks/18/keys" len="12"> 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/19/type"> "transform" </string>
- <node_path name="tracks/19/path"> "Armature/Skeleton:l-ARMORIENT" </node_path>
- <int name="tracks/19/interp"> 1 </int>
- <real_array name="tracks/19/keys" len="12"> 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1 </real_array>
- <string name="tracks/20/type"> "transform" </string>
- <node_path name="tracks/20/path"> "Armature/Skeleton:hip" </node_path>
- <int name="tracks/20/interp"> 1 </int>
- <real_array name="tracks/20/keys" len="12"> 0, 1, 0, -2.84217e-14, 0, 0, 0, 1.44945e-21, 1, 1, 1, 1 </real_array>
- <string name="tracks/21/type"> "transform" </string>
- <node_path name="tracks/21/path"> "Armature/Skeleton:waist" </node_path>
- <int name="tracks/21/interp"> 1 </int>
- <real_array name="tracks/21/keys" len="12"> 0, 1, -6.35275e-21, 2.84217e-14, 0, 0, 0, 2.44616e-35, 1, 1, 1, 1 </real_array>
- <string name="tracks/22/type"> "transform" </string>
- <node_path name="tracks/22/path"> "Armature/Skeleton:chest" </node_path>
- <int name="tracks/22/interp"> 1 </int>
- <real_array name="tracks/22/keys" len="12"> 0, 1, -3.38813e-21, 0, 0, 0, 0, -1.33383e-23, 1, 1, 1, 1 </real_array>
- <string name="tracks/23/type"> "transform" </string>
- <node_path name="tracks/23/path"> "Armature/Skeleton:neck" </node_path>
- <int name="tracks/23/interp"> 1 </int>
- <real_array name="tracks/23/keys" len="12"> 0, 1, -8.52651e-14, -5.96046e-08, -7.15256e-07, 1.17383e-27, 2.13163e-14, 5.50671e-14, 1, 1, 1, 1 </real_array>
- <string name="tracks/24/type"> "transform" </string>
- <node_path name="tracks/24/path"> "Armature/Skeleton:headtracker" </node_path>
- <int name="tracks/24/interp"> 1 </int>
- <real_array name="tracks/24/keys" len="12"> 0, 1, -1.77636e-13, 5.96046e-08, -5.98375e-08, 7.45058e-09, 1.04639e-13, -2.13163e-14, 1, 1, 1, 1 </real_array>
- <string name="tracks/25/type"> "transform" </string>
- <node_path name="tracks/25/path"> "Armature/Skeleton:head" </node_path>
- <int name="tracks/25/interp"> 1 </int>
- <real_array name="tracks/25/keys" len="12"> 0, 1, -2.30926e-14, -1.22469e-07, 2.39583e-07, -2.52436e-28, 7.10543e-15, -7.10543e-15, 1, 1, 1, 1 </real_array>
- <string name="tracks/26/type"> "transform" </string>
- <node_path name="tracks/26/path"> "Armature/Skeleton:vent" </node_path>
- <int name="tracks/26/interp"> 1 </int>
- <real_array name="tracks/26/keys" len="12"> 0, 1, 3.55271e-15, 5.96046e-08, -7.15256e-07, 1.97906e-09, -2.66454e-15, 5.59448e-15, 1, 1, 1, 1 </real_array>
-
- </resource>
- <main_resource>
- <dictionary name="_bundled" shared="false">
- <string> "names" </string>
- <string_array len="249">
- <string> "player" </string>
- <string> "RigidBody" </string>
- <string> "shape_count" </string>
- <string> "shapes/0/shape" </string>
- <string> "shapes/0/transform" </string>
- <string> "shapes/0/trigger" </string>
- <string> "shapes/1/shape" </string>
- <string> "shapes/1/transform" </string>
- <string> "shapes/1/trigger" </string>
- <string> "mode" </string>
- <string> "mass" </string>
- <string> "friction" </string>
- <string> "bounce" </string>
- <string> "custom_integrator" </string>
- <string> "continuous_cd" </string>
- <string> "contacts_reported" </string>
- <string> "contact_monitor" </string>
- <string> "active" </string>
- <string> "can_sleep" </string>
- <string> "velocity/linear" </string>
- <string> "velocity/angular" </string>
- <string> "script/script" </string>
- <string> "__meta__" </string>
- <string> "collision_capsule" </string>
- <string> "CollisionShape" </string>
- <string> "transform/local" </string>
- <string> "shape" </string>
- <string> "trigger" </string>
- <string> "collision_ray" </string>
- <string> "target" </string>
- <string> "Spatial" </string>
- <string> "camera" </string>
- <string> "Camera" </string>
- <string> "projection" </string>
- <string> "fov" </string>
- <string> "near" </string>
- <string> "far" </string>
- <string> "vaspect" </string>
- <string> "current" </string>
- <string> "visible_layers" </string>
- <string> "environment" </string>
- <string> "min_distance" </string>
- <string> "max_distance" </string>
- <string> "angle_v_adjust" </string>
- <string> "autoturn_ray_aperture" </string>
- <string> "autoturn_speed" </string>
- <string> "Armature" </string>
- <string> "Skeleton" </string>
- <string> "bones/0/name" </string>
- <string> "bones/0/parent" </string>
- <string> "bones/0/rest" </string>
- <string> "bones/0/enabled" </string>
- <string> "bones/0/bound_childs" </string>
- <string> "bones/1/name" </string>
- <string> "bones/1/parent" </string>
- <string> "bones/1/rest" </string>
- <string> "bones/1/enabled" </string>
- <string> "bones/1/bound_childs" </string>
- <string> "bones/2/name" </string>
- <string> "bones/2/parent" </string>
- <string> "bones/2/rest" </string>
- <string> "bones/2/enabled" </string>
- <string> "bones/2/bound_childs" </string>
- <string> "bones/3/name" </string>
- <string> "bones/3/parent" </string>
- <string> "bones/3/rest" </string>
- <string> "bones/3/enabled" </string>
- <string> "bones/3/bound_childs" </string>
- <string> "bones/4/name" </string>
- <string> "bones/4/parent" </string>
- <string> "bones/4/rest" </string>
- <string> "bones/4/enabled" </string>
- <string> "bones/4/bound_childs" </string>
- <string> "bones/5/name" </string>
- <string> "bones/5/parent" </string>
- <string> "bones/5/rest" </string>
- <string> "bones/5/enabled" </string>
- <string> "bones/5/bound_childs" </string>
- <string> "bones/6/name" </string>
- <string> "bones/6/parent" </string>
- <string> "bones/6/rest" </string>
- <string> "bones/6/enabled" </string>
- <string> "bones/6/bound_childs" </string>
- <string> "bones/7/name" </string>
- <string> "bones/7/parent" </string>
- <string> "bones/7/rest" </string>
- <string> "bones/7/enabled" </string>
- <string> "bones/7/bound_childs" </string>
- <string> "bones/8/name" </string>
- <string> "bones/8/parent" </string>
- <string> "bones/8/rest" </string>
- <string> "bones/8/enabled" </string>
- <string> "bones/8/bound_childs" </string>
- <string> "bones/9/name" </string>
- <string> "bones/9/parent" </string>
- <string> "bones/9/rest" </string>
- <string> "bones/9/enabled" </string>
- <string> "bones/9/bound_childs" </string>
- <string> "bones/10/name" </string>
- <string> "bones/10/parent" </string>
- <string> "bones/10/rest" </string>
- <string> "bones/10/enabled" </string>
- <string> "bones/10/bound_childs" </string>
- <string> "bones/11/name" </string>
- <string> "bones/11/parent" </string>
- <string> "bones/11/rest" </string>
- <string> "bones/11/enabled" </string>
- <string> "bones/11/bound_childs" </string>
- <string> "bones/12/name" </string>
- <string> "bones/12/parent" </string>
- <string> "bones/12/rest" </string>
- <string> "bones/12/enabled" </string>
- <string> "bones/12/bound_childs" </string>
- <string> "bones/13/name" </string>
- <string> "bones/13/parent" </string>
- <string> "bones/13/rest" </string>
- <string> "bones/13/enabled" </string>
- <string> "bones/13/bound_childs" </string>
- <string> "bones/14/name" </string>
- <string> "bones/14/parent" </string>
- <string> "bones/14/rest" </string>
- <string> "bones/14/enabled" </string>
- <string> "bones/14/bound_childs" </string>
- <string> "bones/15/name" </string>
- <string> "bones/15/parent" </string>
- <string> "bones/15/rest" </string>
- <string> "bones/15/enabled" </string>
- <string> "bones/15/bound_childs" </string>
- <string> "bones/16/name" </string>
- <string> "bones/16/parent" </string>
- <string> "bones/16/rest" </string>
- <string> "bones/16/enabled" </string>
- <string> "bones/16/bound_childs" </string>
- <string> "bones/17/name" </string>
- <string> "bones/17/parent" </string>
- <string> "bones/17/rest" </string>
- <string> "bones/17/enabled" </string>
- <string> "bones/17/bound_childs" </string>
- <string> "bones/18/name" </string>
- <string> "bones/18/parent" </string>
- <string> "bones/18/rest" </string>
- <string> "bones/18/enabled" </string>
- <string> "bones/18/bound_childs" </string>
- <string> "bones/19/name" </string>
- <string> "bones/19/parent" </string>
- <string> "bones/19/rest" </string>
- <string> "bones/19/enabled" </string>
- <string> "bones/19/bound_childs" </string>
- <string> "bones/20/name" </string>
- <string> "bones/20/parent" </string>
- <string> "bones/20/rest" </string>
- <string> "bones/20/enabled" </string>
- <string> "bones/20/bound_childs" </string>
- <string> "bones/21/name" </string>
- <string> "bones/21/parent" </string>
- <string> "bones/21/rest" </string>
- <string> "bones/21/enabled" </string>
- <string> "bones/21/bound_childs" </string>
- <string> "bones/22/name" </string>
- <string> "bones/22/parent" </string>
- <string> "bones/22/rest" </string>
- <string> "bones/22/enabled" </string>
- <string> "bones/22/bound_childs" </string>
- <string> "bones/23/name" </string>
- <string> "bones/23/parent" </string>
- <string> "bones/23/rest" </string>
- <string> "bones/23/enabled" </string>
- <string> "bones/23/bound_childs" </string>
- <string> "bones/24/name" </string>
- <string> "bones/24/parent" </string>
- <string> "bones/24/rest" </string>
- <string> "bones/24/enabled" </string>
- <string> "bones/24/bound_childs" </string>
- <string> "bones/25/name" </string>
- <string> "bones/25/parent" </string>
- <string> "bones/25/rest" </string>
- <string> "bones/25/enabled" </string>
- <string> "bones/25/bound_childs" </string>
- <string> "bones/26/name" </string>
- <string> "bones/26/parent" </string>
- <string> "bones/26/rest" </string>
- <string> "bones/26/enabled" </string>
- <string> "bones/26/bound_childs" </string>
- <string> "robot" </string>
- <string> "MeshInstance" </string>
- <string> "layers" </string>
- <string> "geometry/visible" </string>
- <string> "geometry/material_override" </string>
- <string> "geometry/cast_shadow" </string>
- <string> "geometry/receive_shadows" </string>
- <string> "geometry/range_begin" </string>
- <string> "geometry/range_end" </string>
- <string> "geometry/billboard" </string>
- <string> "geometry/billboard_y" </string>
- <string> "geometry/depth_scale" </string>
- <string> "geometry/visible_in_all_rooms" </string>
- <string> "mesh/mesh" </string>
- <string> "bullet" </string>
- <string> "Position3D" </string>
- <string> "sfx" </string>
- <string> "SpatialSamplePlayer" </string>
- <string> "params/volume_db" </string>
- <string> "params/pitch_scale" </string>
- <string> "params/attenuation/min_distance" </string>
- <string> "params/attenuation/max_distance" </string>
- <string> "params/attenuation/distance_exp" </string>
- <string> "params/emission_cone/degrees" </string>
- <string> "params/emission_cone/attenuation_db" </string>
- <string> "config/polyphony" </string>
- <string> "config/samples" </string>
- <string> "AnimationPlayer" </string>
- <string> "playback/process_mode" </string>
- <string> "playback/default_blend_time" </string>
- <string> "root/root" </string>
- <string> "speed" </string>
- <string> "anims/idle" </string>
- <string> "anims/shooting" </string>
- <string> "anims/jump-up-cycle" </string>
- <string> "anims/shooting_standing" </string>
- <string> "anims/falling-cycle" </string>
- <string> "anims/walk-cycle" </string>
- <string> "anims/run-cycle" </string>
- <string> "anims/default" </string>
- <string> "blend_times" </string>
- <string> "autoplay" </string>
- <string> "AnimationTreePlayer" </string>
- <string> "process/process" </string>
- <string> "base_path" </string>
- <string> "master_player" </string>
- <string> "data" </string>
- <string> "fwd" </string>
- <string> "TouchScreenButton" </string>
- <string> "process/input" </string>
- <string> "visibility/visible" </string>
- <string> "visibility/opacity" </string>
- <string> "visibility/self_opacity" </string>
- <string> "visibility/on_top" </string>
- <string> "transform/pos" </string>
- <string> "transform/rot" </string>
- <string> "transform/scale" </string>
- <string> "normal" </string>
- <string> "pressed" </string>
- <string> "bitmask" </string>
- <string> "passby_press" </string>
- <string> "action" </string>
- <string> "visibility_mode" </string>
- <string> "bwd" </string>
- <string> "left" </string>
- <string> "right" </string>
- </string_array>
- <string> "version" </string>
- <int> 1 </int>
- <string> "conn_count" </string>
- <int> 0 </int>
- <string> "node_count" </string>
- <int> 16 </int>
- <string> "variants" </string>
- <array len="121" shared="false">
- <int> 2 </int>
- <resource resource_type="CapsuleShape" path="local://1"> </resource>
- <transform> 1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0.954765, 0 </transform>
- <bool> False </bool>
- <resource resource_type="RayShape" path="local://2"> </resource>
- <transform> 1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 1.01236, 0 </transform>
- <real> 1 </real>
- <real> 0 </real>
- <bool> True </bool>
- <int> 3 </int>
- <vector3> 0, 0, 0 </vector3>
- <resource resource_type="GDScript" path="res://player.*"> </resource>
- <dictionary shared="false">
- <string> "__editor_plugin_states__" </string>
- <dictionary shared="false">
- <string> "Script" </string>
- <dictionary shared="false">
- <string> "current" </string>
- <int> 1 </int>
- <string> "sources" </string>
- <array len="2" shared="false">
- <string> "res://follow_camera.gd" </string>
- <string> "res://player.gd" </string>
- </array>
- </dictionary>
- <string> "2D" </string>
- <dictionary shared="false">
- <string> "zoom" </string>
- <real> 1 </real>
- <string> "ofs" </string>
- <vector2> -241, -19 </vector2>
- </dictionary>
- <string> "3D" </string>
- <dictionary shared="false">
- <string> "zfar" </string>
- <real> 500 </real>
- <string> "fov" </string>
- <real> 400 </real>
- <string> "viewports" </string>
- <array len="4" shared="false">
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 2.161076 </real>
- <string> "x_rot" </string>
- <real> 0.520797 </real>
- <string> "y_rot" </string>
- <real> 26.741669 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> -0.415811, 0.486899, 0.089334 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- <dictionary shared="false">
- <string> "distance" </string>
- <real> 4 </real>
- <string> "x_rot" </string>
- <real> 0 </real>
- <string> "y_rot" </string>
- <real> 0 </real>
- <string> "use_orthogonal" </string>
- <bool> False </bool>
- <string> "use_environment" </string>
- <bool> False </bool>
- <string> "pos" </string>
- <vector3> 0, 0, 0 </vector3>
- </dictionary>
- </array>
- <string> "viewport_mode" </string>
- <int> 1 </int>
- <string> "default_light" </string>
- <bool> True </bool>
- <string> "show_grid" </string>
- <bool> True </bool>
- <string> "show_origin" </string>
- <bool> True </bool>
- <string> "znear" </string>
- <real> 0.1 </real>
- </dictionary>
- </dictionary>
- <string> "__editor_run_settings__" </string>
- <dictionary shared="false">
- <string> "custom_args" </string>
- <string> "-l $scene" </string>
- <string> "run_mode" </string>
- <int> 0 </int>
- </dictionary>
- <string> "__editor_plugin_screen__" </string>
- <string> "Script" </string>
- </dictionary>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.95244, 0 </transform>
- <transform> 1, 0, 0, 0, 0.871263, 0.490817, 0, -0.490817, 0.871263, 0, 2.59805, 1.25672 </transform>
- <int> 0 </int>
- <real> 70 </real>
- <real> 0.1 </real>
- <real> 100 </real>
- <int> -1 </int>
- <resource name=""></resource> <resource resource_type="GDScript" path="res://follow_camera.*"> </resource>
- <real> 3 </real>
- <int> 25 </int>
- <int> 50 </int>
- <transform> 0.3, 0, 0, 0, 0.3, 0, 0, 0, 0.3, 0, 0, 0 </transform>
- <string> "MASTER" </string>
- <transform> 1, 0, -0, 0, 7.54979e-08, 1, -0, -1, 7.54979e-08, 0, -0.011277, -0 </transform>
- <array len="0" shared="false">
- </array>
- <string> "hip" </string>
- <transform> 1, -1.50996e-07, -3.60002e-14, -1.50996e-07, -1, -3.01992e-07, 9.59926e-15, 3.01992e-07, -1, -3.38813e-21, 2.58363e-07, 2.10612 </transform>
- <string> "waist" </string>
- <int> 1 </int>
- <transform> 1, 1.50996e-07, 1.80001e-14, -1.50996e-07, 1, 0, -1.80001e-14, 0, 1, 3.38813e-21, 2.84217e-14, -0.384614 </transform>
- <string> "chest" </string>
- <transform> 1, -7.31455e-16, 4.86029e-17, 7.28861e-16, 0.999166, 0.040823, -7.84198e-17, -0.040823, 0.999166, 0, 4.84022e-11, -0.8217 </transform>
- <string> "neck" </string>
- <transform> -1, -1.10548e-06, -9.37766e-09, 1.08766e-06, -0.985328, 0.170671, -1.97913e-07, 0.170671, 0.985328, -1.64727e-13, 5.96046e-08, -1.24906 </transform>
- <string> "headtracker" </string>
- <int> 4 </int>
- <transform> 1, 9.87793e-08, -1.09789e-06, 1.09743e-06, 0.00449866, 0.99999, 1.03717e-07, -0.99999, 0.00449866, 0, 5.96046e-08, -0.491774 </transform>
- <string> "head" </string>
- <int> 5 </int>
- <transform> -1, 2.36978e-07, 1.97097e-07, -2.5035e-07, -0.25144, -0.967873, -1.79807e-07, -0.967873, 0.25144, -2.94648e-10, 4.76837e-07, 0.00400549 </transform>
- <string> "vent" </string>
- <int> 6 </int>
- <transform> 1, -2.54965e-07, -1.4699e-08, 2.55005e-07, 0.999996, 0.00282324, 1.39791e-08, -0.00282325, 0.999996, -7.04808e-08, 0.270992, -1.2429 </transform>
- <string> "r-arm" </string>
- <transform> 0.11477, -0.699489, -0.705367, -0.802661, -0.483653, 0.349021, -0.585289, 0.526113, -0.616961, 0.940786, 0.107144, -0.773564 </transform>
- <string> "r-forearm" </string>
- <int> 8 </int>
- <transform> -0.859542, 0.0564943, 0.507934, 0.107631, -0.951571, 0.287973, 0.499604, 0.302194, 0.811834, 2.38419e-07, -4.76837e-07, -0.935513 </transform>
- <string> "l-arm" </string>
- <transform> 0.11477, 0.699489, 0.705367, 0.802661, -0.483653, 0.349021, 0.585289, 0.526113, -0.616961, -0.940786, 0.107144, -0.773564 </transform>
- <string> "l-forearm" </string>
- <int> 10 </int>
- <transform> -0.859542, -0.0564943, -0.507934, -0.107631, -0.951571, 0.287973, -0.499604, 0.302194, 0.811834, -2.38419e-07, -4.76837e-07, -0.935513 </transform>
- <string> "r-thigh" </string>
- <transform> 0.994883, -0.0545632, -0.085028, -0.0580629, -0.997541, -0.0392442, -0.0826777, 0.0439804, -0.995605, 0.349652, 0.0628238, -0.163877 </transform>
- <string> "r-leg" </string>
- <int> 12 </int>
- <transform> -0.999508, -0.031366, -0.000870243, 0.0312939, -0.994411, -0.100835, 0.00229738, -0.100812, 0.994903, 5.96046e-08, 5.96046e-08, -0.644636 </transform>
- <string> "r-foot" </string>
- <int> 13 </int>
- <transform> 0.996208, -0.0766666, -0.0411273, -0.0442384, -0.0393329, -0.998246, 0.0749145, 0.996281, -0.0425754, -5.96046e-08, 4.19095e-09, -1.43073 </transform>
- <string> "l-thigh" </string>
- <transform> 0.994883, 0.0545632, 0.085028, 0.0580633, -0.997541, -0.0392452, 0.0826776, 0.0439813, -0.995606, -0.349652, 0.0628238, -0.163877 </transform>
- <string> "l-leg" </string>
- <int> 15 </int>
- <transform> -0.999508, 0.0313662, 0.000870456, -0.0312941, -0.994411, -0.100836, -0.00229725, -0.100814, 0.994903, 0, 1.49012e-08, -0.644636 </transform>
- <string> "l-foot" </string>
- <int> 16 </int>
- <transform> 0.996208, 0.0766668, 0.0411275, 0.0442386, -0.0393327, -0.998246, -0.0749147, 0.996281, -0.0425752, 0, -8.3819e-09, -1.43073 </transform>
- <string> "HEAD" </string>
- <transform> 1, -1.50996e-07, -0, -1.50996e-07, -1, 0, 0, 0, -1, 5.68434e-14, -5.79659, 6.35228 </transform>
- <string> "r-LEGCONTROL" </string>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, 0.518863, 3.72276e-07, 0.204768 </transform>
- <string> "l-LEGCONTROL" </string>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, -0.518863, 3.72276e-07, 0.204768 </transform>
- <string> "r-LEGORIENT" </string>
- <transform> -1, -1.50996e-07, -5.03577e-15, -3.75647e-14, 2.15429e-07, 1, -1.50996e-07, 1, -2.15429e-07, 0.411677, -0.66395, 1.62881 </transform>
- <string> "l-LEGORIENT" </string>
- <transform> -1, -1.50996e-07, -5.03577e-15, -3.75647e-14, 2.15429e-07, 1, -1.50996e-07, 1, -2.15429e-07, -0.411677, -0.66395, 1.62881 </transform>
- <string> "r-ARMCONTROL" </string>
- <transform> 1, 0, 0, 0, 7.54979e-08, -1, 0, 1, 7.54979e-08, 2.62535, -0.186879, 2.59016 </transform>
- <string> "l-ARMCONTROL" </string>
- <transform> 1, 0, 0, 0, 7.54979e-08, -1, 0, 1, 7.54979e-08, -2.62535, -0.186879, 2.59016 </transform>
- <string> "r-ARMORIENT" </string>
- <transform> 1, 0, 0, 0, 7.54979e-08, -1, 0, 1, 7.54979e-08, 1.57185, 0.510255, 3.44768 </transform>
- <string> "l-ARMORIENT" </string>
- <transform> 1, 0, 0, 0, 7.54979e-08, -1, 0, 1, 7.54979e-08, -1.57185, 0.510255, 3.44768 </transform>
- <resource resource_type="Mesh" path="local://5"> </resource>
- <transform> 1, 0, 0, 0, 1, 0, 0, 0, 1, -1.94071, 3.64079, 3.3802 </transform>
- <real> 180 </real>
- <real> -6 </real>
- <resource resource_type="SampleLibrary" path="local://6"> </resource>
- <node_path> ".." </node_path>
- <resource resource_type="Animation" path="local://7"> </resource>
- <resource resource_type="Animation" path="local://8"> </resource>
- <resource resource_type="Animation" path="local://9"> </resource>
- <resource resource_type="Animation" path="local://10"> </resource>
- <resource resource_type="Animation" path="local://11"> </resource>
- <resource resource_type="Animation" path="local://12"> </resource>
- <resource resource_type="Animation" path="local://13"> </resource>
- <resource resource_type="Animation" path="local://14"> </resource>
- <string> "" </string>
- <node_path> "../AnimationPlayer" </node_path>
- <dictionary shared="false">
- <string> "connections" </string>
- <array len="27" shared="false">
- <string> "walk" </string>
- <string> "scale" </string>
- <int> 0 </int>
- <string> "scale" </string>
- <string> "state" </string>
- <int> 0 </int>
- <string> "anim 3" </string>
- <string> "state" </string>
- <int> 1 </int>
- <string> "anim 4" </string>
- <string> "state" </string>
- <int> 2 </int>
- <string> "gun" </string>
- <string> "out" </string>
- <int> 0 </int>
- <string> "state" </string>
- <string> "gun" </string>
- <int> 0 </int>
- <string> "anim 5" </string>
- <string> "gun" </string>
- <int> 1 </int>
- <string> "anim" </string>
- <string> "walk" </string>
- <int> 0 </int>
- <string> "anim 2" </string>
- <string> "walk" </string>
- <int> 1 </int>
- </array>
- <string> "master" </string>
- <node_path> "../AnimationPlayer" </node_path>
- <string> "active" </string>
- <bool> True </bool>
- <string> "nodes" </string>
- <array len="10" shared="false">
- <dictionary shared="false">
- <string> "id" </string>
- <string> "scale" </string>
- <string> "scale" </string>
- <real> 1.2 </real>
- <string> "pos" </string>
- <vector2> 247, 68 </vector2>
- <string> "type" </string>
- <string> "timescale" </string>
- </dictionary>
- <dictionary shared="false">
- <string> "id" </string>
- <string> "state" </string>
- <string> "transitions" </string>
- <array len="3" shared="false">
- <dictionary shared="false">
- <string> "auto_advance" </string>
- <bool> False </bool>
- </dictionary>
- <dictionary shared="false">
- <string> "auto_advance" </string>
- <bool> False </bool>
- </dictionary>
- <dictionary shared="false">
- <string> "auto_advance" </string>
- <bool> False </bool>
- </dictionary>
- </array>
- <string> "xfade" </string>
- <real> 0.1 </real>
- <string> "type" </string>
- <string> "transition" </string>
- <string> "pos" </string>
- <vector2> 359, 132 </vector2>
- </dictionary>
- <dictionary shared="false">
- <string> "from" </string>
- <string> "idle" </string>
- <string> "id" </string>
- <string> "anim" </string>
- <string> "pos" </string>
- <vector2> 7, 70 </vector2>
- <string> "type" </string>
- <string> "animation" </string>
- </dictionary>
- <dictionary shared="false">
- <string> "id" </string>
- <string> "out" </string>
- <string> "type" </string>
- <string> "output" </string>
- <string> "pos" </string>
- <vector2> 579, 114 </vector2>
- </dictionary>
- <dictionary shared="false">
- <string> "from" </string>
- <string> "jump-up-cycle" </string>
- <string> "id" </string>
- <string> "anim 3" </string>
- <string> "pos" </string>
- <vector2> 143, 144 </vector2>
- <string> "type" </string>
- <string> "animation" </string>
- </dictionary>
- <dictionary shared="false">
- <string> "from" </string>
- <string> "shooting_standing" </string>
- <string> "id" </string>
- <string> "anim 5" </string>
- <string> "pos" </string>
- <vector2> 331, 242 </vector2>
- <string> "type" </string>
- <string> "animation" </string>
- </dictionary>
- <dictionary shared="false">
- <string> "from" </string>
- <string> "walk-cycle" </string>
- <string> "id" </string>
- <string> "anim 2" </string>
- <string> "pos" </string>
- <vector2> 7, 152 </vector2>
- <string> "type" </string>
- <string> "animation" </string>
- </dictionary>
- <dictionary shared="false">
- <string> "id" </string>
- <string> "gun" </string>
- <string> "blend" </string>
- <real> 1 </real>
- <string> "filter" </string>
- <array len="22" shared="false">
- <node_path> "Armature/Skeleton:MASTER" </node_path>
- <node_path> "Armature/Skeleton:l-thigh" </node_path>
- <node_path> "Armature/Skeleton:headtracker" </node_path>
- <node_path> "Armature/Skeleton:r-leg" </node_path>
- <node_path> "Armature/Skeleton:r-foot" </node_path>
- <node_path> "Armature/Skeleton:r-LEGORIENT" </node_path>
- <node_path> "Armature/Skeleton:r-LEGCONTROL" </node_path>
- <node_path> "Armature/Skeleton:r-ARMORIENT" </node_path>
- <node_path> "Armature/Skeleton:r-ARMCONTROL" </node_path>
- <node_path> "Armature/Skeleton:waist" </node_path>
- <node_path> "Armature/Skeleton:neck" </node_path>
- <node_path> "Armature/Skeleton:l-leg" </node_path>
- <node_path> "Armature/Skeleton:l-foot" </node_path>
- <node_path> "Armature/Skeleton:hip" </node_path>
- <node_path> "Armature/Skeleton:head" </node_path>
- <node_path> "Armature/Skeleton:HEAD" </node_path>
- <node_path> "Armature/Skeleton:l-LEGORIENT" </node_path>
- <node_path> "Armature/Skeleton:l-LEGCONTROL" </node_path>
- <node_path> "Armature/Skeleton:l-ARMORIENT" </node_path>
- <node_path> "Armature/Skeleton:l-ARMCONTROL" </node_path>
- <node_path> "Armature" </node_path>
- <node_path> "Armature/Skeleton:r-thigh" </node_path>
- </array>
- <string> "type" </string>
- <string> "blend2" </string>
- <string> "pos" </string>
- <vector2> 469, 127 </vector2>
- </dictionary>
- <dictionary shared="false">
- <string> "from" </string>
- <string> "falling-cycle" </string>
- <string> "id" </string>
- <string> "anim 4" </string>
- <string> "pos" </string>
- <vector2> 141, 230 </vector2>
- <string> "type" </string>
- <string> "animation" </string>
- </dictionary>
- <dictionary shared="false">
- <string> "id" </string>
- <string> "walk" </string>
- <string> "blend" </string>
- <real> 1 </real>
- <string> "filter" </string>
- <array len="0" shared="false">
- </array>
- <string> "type" </string>
- <string> "blend2" </string>
- <string> "pos" </string>
- <vector2> 148, 46 </vector2>
- </dictionary>
- </array>
- </dictionary>
- <vector2> 72, 301 </vector2>
- <vector2> 1, 1 </vector2>
- <resource resource_type="ImageTexture" path="res://osb_up.*"> </resource>
- <string> "move_forward" </string>
- <vector2> 72, 365 </vector2>
- <resource resource_type="ImageTexture" path="res://osb_down.*"> </resource>
- <string> "move_backwards" </string>
- <vector2> 29, 332 </vector2>
- <resource resource_type="ImageTexture" path="res://osb_left.*"> </resource>
- <string> "move_left" </string>
- <vector2> 108, 327 </vector2>
- <resource resource_type="ImageTexture" path="res://osb_right.*"> </resource>
- <string> "move_right" </string>
- </array>
- <string> "nodes" </string>
- <int_array len="662"> -1, -1, 1, 0, -1, 21, 2, 0, 3, 1, 4, 2, 5, 3, 6, 4, 7, 5, 8, 3, 9, 0, 10, 6, 11, 7, 12, 7, 13, 8, 14, 3, 15, 9, 16, 8, 17, 8, 18, 8, 19, 10, 20, 10, 21, 11, 22, 12, 0, 0, 0, 24, 23, -1, 3, 25, 2, 26, 1, 27, 3, 0, 0, 0, 24, 28, -1, 3, 25, 5, 26, 4, 27, 3, 0, 0, 0, 30, 29, -1, 1, 25, 13, 0, 3, 0, 32, 31, -1, 15, 25, 14, 33, 15, 34, 16, 35, 17, 36, 18, 37, 3, 38, 3, 39, 19, 40, 20, 21, 21, 41, 6, 42, 22, 43, 7, 44, 23, 45, 24, 0, 0, 0, 30, 46, -1, 1, 25, 25, 0, 5, 0, 47, 47, -1, 135, 48, 26, 49, 19, 50, 27, 51, 8, 52, 28, 53, 29, 54, 15, 55, 30, 56, 8, 57, 28, 58, 31, 59, 32, 60, 33, 61, 8, 62, 28, 63, 34, 64, 0, 65, 35, 66, 8, 67, 28, 68, 36, 69, 9, 70, 37, 71, 8, 72, 28, 73, 38, 74, 39, 75, 40, 76, 8, 77, 28, 78, 41, 79, 42, 80, 43, 81, 8, 82, 28, 83, 44, 84, 45, 85, 46, 86, 8, 87, 28, 88, 47, 89, 9, 90, 48, 91, 8, 92, 28, 93, 49, 94, 50, 95, 51, 96, 8, 97, 28, 98, 52, 99, 9, 100, 53, 101, 8, 102, 28, 103, 54, 104, 55, 105, 56, 106, 8, 107, 28, 108, 57, 109, 32, 110, 58, 111, 8, 112, 28, 113, 59, 114, 60, 115, 61, 116, 8, 117, 28, 118, 62, 119, 63, 120, 64, 121, 8, 122, 28, 123, 65, 124, 32, 125, 66, 126, 8, 127, 28, 128, 67, 129, 68, 130, 69, 131, 8, 132, 28, 133, 70, 134, 71, 135, 72, 136, 8, 137, 28, 138, 73, 139, 15, 140, 74, 141, 8, 142, 28, 143, 75, 144, 15, 145, 76, 146, 8, 147, 28, 148, 77, 149, 15, 150, 78, 151, 8, 152, 28, 153, 79, 154, 15, 155, 80, 156, 8, 157, 28, 158, 81, 159, 15, 160, 82, 161, 8, 162, 28, 163, 83, 164, 15, 165, 84, 166, 8, 167, 28, 168, 85, 169, 15, 170, 86, 171, 8, 172, 28, 173, 87, 174, 15, 175, 88, 176, 8, 177, 28, 178, 89, 179, 15, 180, 90, 181, 8, 182, 28, 0, 6, 0, 184, 183, -1, 12, 185, 32, 186, 8, 187, 20, 188, 8, 189, 8, 190, 7, 191, 7, 192, 3, 193, 3, 194, 3, 195, 3, 196, 91, 0, 5, 0, 198, 197, -1, 1, 25, 92, 0, 0, 0, 200, 199, -1, 9, 201, 7, 202, 6, 203, 6, 204, 18, 205, 6, 206, 93, 207, 94, 208, 32, 209, 95, 0, 0, 0, 210, 210, -1, 14, 211, 32, 212, 7, 213, 96, 214, 6, 215, 97, 216, 98, 217, 99, 218, 100, 219, 101, 220, 102, 221, 103, 222, 104, 223, 28, 224, 105, 0, 0, 0, 225, 225, -1, 4, 226, 8, 227, 96, 228, 106, 229, 107, 0, 0, 0, 231, 230, -1, 14, 232, 8, 233, 8, 234, 6, 235, 6, 236, 8, 237, 108, 238, 7, 239, 109, 240, 110, 241, 20, 242, 20, 243, 8, 244, 111, 245, 32, 0, 0, 0, 231, 246, -1, 14, 232, 8, 233, 8, 234, 6, 235, 6, 236, 8, 237, 112, 238, 7, 239, 109, 240, 113, 241, 20, 242, 20, 243, 8, 244, 114, 245, 32, 0, 0, 0, 231, 247, -1, 14, 232, 8, 233, 8, 234, 6, 235, 6, 236, 8, 237, 115, 238, 7, 239, 109, 240, 116, 241, 20, 242, 20, 243, 8, 244, 117, 245, 32, 0, 0, 0, 231, 248, -1, 14, 232, 8, 233, 8, 234, 6, 235, 6, 236, 8, 237, 118, 238, 7, 239, 109, 240, 119, 241, 20, 242, 20, 243, 8, 244, 120, 245, 32, 0 </int_array>
- <string> "conns" </string>
- <int_array len="0"> </int_array>
- </dictionary>
-
- </main_resource>
-</resource_file> \ No newline at end of file
diff --git a/demos/viewport/3d_in_2d/player_2d.scn b/demos/viewport/3d_in_2d/player_2d.scn
index eb6a09ae82..edb6c080c1 100644
--- a/demos/viewport/3d_in_2d/player_2d.scn
+++ b/demos/viewport/3d_in_2d/player_2d.scn
Binary files differ
diff --git a/demos/viewport/3d_in_2d/player_3d.scn b/demos/viewport/3d_in_2d/player_3d.scn
index 1dfd35adf4..c8bba5e460 100644
--- a/demos/viewport/3d_in_2d/player_3d.scn
+++ b/demos/viewport/3d_in_2d/player_3d.scn
Binary files differ
diff --git a/demos/viewport/gui_in_3d/engine.cfg b/demos/viewport/gui_in_3d/engine.cfg
index 25a6636132..252e53ca33 100644
--- a/demos/viewport/gui_in_3d/engine.cfg
+++ b/demos/viewport/gui_in_3d/engine.cfg
@@ -2,3 +2,4 @@
name="GUI in 3D"
main_scene="res://gui_3d.scn"
+icon="res://icon.png"
diff --git a/demos/viewport/gui_in_3d/gui.scn b/demos/viewport/gui_in_3d/gui.scn
index 4d665226b7..d7daa30340 100644
--- a/demos/viewport/gui_in_3d/gui.scn
+++ b/demos/viewport/gui_in_3d/gui.scn
Binary files differ
diff --git a/demos/viewport/gui_in_3d/gui_3d.gd b/demos/viewport/gui_in_3d/gui_3d.gd
index c2a9df0069..b93c17521d 100644
--- a/demos/viewport/gui_in_3d/gui_3d.gd
+++ b/demos/viewport/gui_in_3d/gui_3d.gd
@@ -1,45 +1,37 @@
extends Spatial
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
-var prev_pos=null
-
-
-func _input( ev ):
- #all other (non-mouse) events
- if (not ev.type in [InputEvent.MOUSE_BUTTON,InputEvent.MOUSE_MOTION,InputEvent.SCREEN_DRAG,InputEvent.SCREEN_TOUCH]):
- get_node("viewport").input(ev)
-
-
-#mouse events for area
-func _on_area_input_event( camera, ev, click_pos, click_normal, shape_idx ):
-
- #use click pos (click in 3d space, convert to area space
- var pos = get_node("area").get_global_transform().affine_inverse() * click_pos
- #convert to 2D
- pos = Vector2(pos.x,pos.y)
- #convert to viewport coordinate system
- pos.x=(pos.x+1.5)*100
- pos.y=(-pos.y+0.75)*100
- #set to event
- ev.pos=pos
- ev.global_pos=pos
- if (prev_pos==null):
- prev_pos=pos
- if (ev.type==InputEvent.MOUSE_MOTION):
- ev.relative_pos=pos-prev_pos
- prev_pos=pos
-
- get_node("viewport").input(ev)
-
-
+# Member variables
+var prev_pos = null
+
+
+func _input(event):
+ # All other (non-mouse) events
+ if (not event.type in [InputEvent.MOUSE_BUTTON, InputEvent.MOUSE_MOTION, InputEvent.SCREEN_DRAG, InputEvent.SCREEN_TOUCH]):
+ get_node("viewport").input(event)
+
+
+# Mouse events for Area
+func _on_area_input_event(camera, event, click_pos, click_normal, shape_idx):
+ # Use click pos (click in 3d space, convert to area space)
+ var pos = get_node("area").get_global_transform().affine_inverse()*click_pos
+ # Convert to 2D
+ pos = Vector2(pos.x, pos.y)
+ # Convert to viewport coordinate system
+ pos.x = (pos.x + 1.5)*100
+ pos.y = (-pos.y + 0.75)*100
+ # Set to event
+ event.pos = pos
+ event.global_pos = pos
+ if (prev_pos == null):
+ prev_pos = pos
+ if (event.type == InputEvent.MOUSE_MOTION):
+ event.relative_pos = pos - prev_pos
+ prev_pos = pos
+ # Send the event to the viewport
+ get_node("viewport").input(event)
+
func _ready():
- # Initalization here
- get_node("area/quad").get_material_override().set_texture(FixedMaterial.PARAM_DIFFUSE, get_node("viewport").get_render_target_texture() )
+ get_node("area/quad").get_material_override().set_texture(FixedMaterial.PARAM_DIFFUSE, get_node("viewport").get_render_target_texture())
set_process_input(true)
- pass
-
diff --git a/demos/viewport/gui_in_3d/gui_3d.scn b/demos/viewport/gui_in_3d/gui_3d.scn
index c69d4dc73f..0541e7b142 100644
--- a/demos/viewport/gui_in_3d/gui_3d.scn
+++ b/demos/viewport/gui_in_3d/gui_3d.scn
Binary files differ
diff --git a/demos/viewport/gui_in_3d/icon.png b/demos/viewport/gui_in_3d/icon.png
new file mode 100644
index 0000000000..22bdd791bb
--- /dev/null
+++ b/demos/viewport/gui_in_3d/icon.png
Binary files differ
diff --git a/demos/viewport/screen_capture/engine.cfg b/demos/viewport/screen_capture/engine.cfg
index b25ed8258e..a843242720 100644
--- a/demos/viewport/screen_capture/engine.cfg
+++ b/demos/viewport/screen_capture/engine.cfg
@@ -2,6 +2,7 @@
name="Screen Capturing"
main_scene="res://screen_capture.scn"
+icon="res://icon.png"
[display]
diff --git a/demos/viewport/screen_capture/icon.png b/demos/viewport/screen_capture/icon.png
new file mode 100644
index 0000000000..a696824775
--- /dev/null
+++ b/demos/viewport/screen_capture/icon.png
Binary files differ
diff --git a/demos/viewport/screen_capture/screen_capture.gd b/demos/viewport/screen_capture/screen_capture.gd
index 69f16fa498..9867d95452 100644
--- a/demos/viewport/screen_capture/screen_capture.gd
+++ b/demos/viewport/screen_capture/screen_capture.gd
@@ -1,27 +1,16 @@
extends Control
-# member variables here, example:
-# var a=2
-# var b="textvar"
-
-func _ready():
- # Initialization here
- pass
-
-
-
func _on_button_pressed():
get_viewport().queue_screen_capture()
- #let two frames pass to make sure the screen was aptured
- yield(get_tree(),"idle_frame")
- yield(get_tree(),"idle_frame")
- #retrieve the captured image
+ # Let two frames pass to make sure the screen was captured
+ yield(get_tree(), "idle_frame")
+ yield(get_tree(), "idle_frame")
+ # Retrieve the captured image
var img = get_viewport().get_screen_capture()
- #create a texture for it
+ # Create a texture for it
var tex = ImageTexture.new()
tex.create_from_image(img)
- #set it to the capture node
+ # Set it to the capture node
get_node("capture").set_texture(tex)
- pass # replace with function body
diff --git a/demos/viewport/screen_capture/screen_capture.scn b/demos/viewport/screen_capture/screen_capture.scn
index d204e3b67e..ee847fbe62 100644
--- a/demos/viewport/screen_capture/screen_capture.scn
+++ b/demos/viewport/screen_capture/screen_capture.scn
Binary files differ
diff --git a/doc/Doxyfile b/doc/Doxyfile
new file mode 100644
index 0000000000..c1904f17c9
--- /dev/null
+++ b/doc/Doxyfile
@@ -0,0 +1,2432 @@
+# Doxyfile 1.8.9.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = Godot
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF = "Game Engine MIT"
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO = ../logo.png
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = ./_build/doxygen/
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 4
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = ../core/ ../main/ ../scene/
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.idl \
+ *.ddl \
+ *.odl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.cs \
+ *.d \
+ *.php \
+ *.php4 \
+ *.php5 \
+ *.phtml \
+ *.inc \
+ *.m \
+ *.markdown \
+ *.md \
+ *.mm \
+ *.dox \
+ *.py \
+ *.f90 \
+ *.f \
+ *.for \
+ *.tcl \
+ *.vhd \
+ *.vhdl \
+ *.ucf \
+ *.qsf \
+ *.as \
+ *.js
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE = README.md
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# compiled with the --with-libclang option.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644
index 0000000000..286a5162af
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,47 @@
+BASEDIR = $(CURDIR)
+CLASSES = $(BASEDIR)/base/classes.xml
+OUTPUTDIR = $(BASEDIR)/_build
+TOOLSDIR = $(BASEDIR)/tools
+
+.ONESHELL:
+
+clean:
+ rm -rf $(OUTPUTDIR)
+
+doku:
+ rm -rf $(OUTPUTDIR)/doku
+ mkdir -p $(OUTPUTDIR)/doku
+ pushd $(OUTPUTDIR)/doku
+ python2 $(TOOLSDIR)/makedoku.py $(CLASSES)
+ popd
+
+doxygen:
+ rm -rf $(OUTPUTDIR)/doxygen
+ mkdir -p $(OUTPUTDIR)/doxygen
+ doxygen Doxyfile
+
+html:
+ rm -rf $(OUTPUTDIR)/html
+ mkdir -p $(OUTPUTDIR)/html
+ pushd $(OUTPUTDIR)/html
+ python2 $(TOOLSDIR)/makehtml.py -multipage $(CLASSES)
+ popd
+
+markdown:
+ rm -rf $(OUTPUTDIR)/markdown
+ mkdir -p $(OUTPUTDIR)/markdown
+ pushd $(OUTPUTDIR)/markdown
+ python2 $(TOOLSDIR)/makemd.py $(CLASSES)
+ popd
+
+rst:
+ rm -rf $(OUTPUTDIR)/rst
+ mkdir -p $(OUTPUTDIR)/rst
+ pushd $(OUTPUTDIR)/rst
+ echo "TODO"
+ popd
+
+textile:
+ rm -rf $(OUTPUTDIR)/textile
+ mkdir -p $(OUTPUTDIR)/textile
+ python3 $(TOOLSDIR)/makedocs.py --input $(CLASSES) --output $(OUTPUTDIR)/textile
diff --git a/doc/base/classes.xml b/doc/base/classes.xml
index 41721647e2..4c8e57eca7 100644
--- a/doc/base/classes.xml
+++ b/doc/base/classes.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<doc version="1.0.3917-beta1" name="Engine Types">
+<doc version="2.0.alpha.custom_build" name="Engine Types">
<class name="@GDScript" category="Core">
<brief_description>
Built-in GDScript functions.
@@ -8,7 +8,7 @@
This contains the list of built-in gdscript functions. Mostly math functions and other utilities. Everything else is expanded by objects.
</description>
<methods>
- <method name="sin" >
+ <method name="sin">
<return type="float">
</return>
<argument index="0" name="s" type="float">
@@ -17,7 +17,7 @@
Standard sine function.
</description>
</method>
- <method name="cos" >
+ <method name="cos">
<return type="float">
</return>
<argument index="0" name="s" type="float">
@@ -26,7 +26,7 @@
Standard cosine function.
</description>
</method>
- <method name="tan" >
+ <method name="tan">
<return type="float">
</return>
<argument index="0" name="s" type="float">
@@ -35,7 +35,7 @@
Standard tangent function.
</description>
</method>
- <method name="sinh" >
+ <method name="sinh">
<return type="float">
</return>
<argument index="0" name="s" type="float">
@@ -44,7 +44,7 @@
Hyperbolic sine.
</description>
</method>
- <method name="cosh" >
+ <method name="cosh">
<return type="float">
</return>
<argument index="0" name="s" type="float">
@@ -53,7 +53,7 @@
Hyperbolic cosine.
</description>
</method>
- <method name="tanh" >
+ <method name="tanh">
<return type="float">
</return>
<argument index="0" name="s" type="float">
@@ -62,7 +62,7 @@
Hyperbolic tangent.
</description>
</method>
- <method name="asin" >
+ <method name="asin">
<return type="float">
</return>
<argument index="0" name="s" type="float">
@@ -71,7 +71,7 @@
Arc-sine.
</description>
</method>
- <method name="acos" >
+ <method name="acos">
<return type="float">
</return>
<argument index="0" name="s" type="float">
@@ -80,7 +80,7 @@
Arc-cosine.
</description>
</method>
- <method name="atan" >
+ <method name="atan">
<return type="float">
</return>
<argument index="0" name="s" type="float">
@@ -89,7 +89,7 @@
Arc-tangent.
</description>
</method>
- <method name="atan2" >
+ <method name="atan2">
<return type="float">
</return>
<argument index="0" name="x" type="float">
@@ -100,7 +100,7 @@
Arc-tangent that takes a 2D vector as argument, retuns the full -pi to +pi range.
</description>
</method>
- <method name="sqrt" >
+ <method name="sqrt">
<return type="float">
</return>
<argument index="0" name="s" type="float">
@@ -109,7 +109,7 @@
Square root.
</description>
</method>
- <method name="fmod" >
+ <method name="fmod">
<return type="float">
</return>
<argument index="0" name="x" type="float">
@@ -120,7 +120,7 @@
Module (remainder of x/y).
</description>
</method>
- <method name="fposmod" >
+ <method name="fposmod">
<return type="float">
</return>
<argument index="0" name="x" type="float">
@@ -131,7 +131,7 @@
Module (remainder of x/y) that wraps equally in positive and negative.
</description>
</method>
- <method name="floor" >
+ <method name="floor">
<return type="float">
</return>
<argument index="0" name="s" type="float">
@@ -140,7 +140,7 @@
Floor (rounds down to nearest integer).
</description>
</method>
- <method name="ceil" >
+ <method name="ceil">
<return type="float">
</return>
<argument index="0" name="s" type="float">
@@ -149,7 +149,7 @@
Ceiling (rounds up to nearest integer).
</description>
</method>
- <method name="round" >
+ <method name="round">
<return type="float">
</return>
<argument index="0" name="s" type="float">
@@ -158,16 +158,16 @@
Round to nearest integer.
</description>
</method>
- <method name="abs" >
+ <method name="abs">
<return type="float">
</return>
<argument index="0" name="s" type="float">
</argument>
<description>
- Remove sign (works for integer and float).
+ Remove sign (works for integer and float).
</description>
</method>
- <method name="sign" >
+ <method name="sign">
<return type="float">
</return>
<argument index="0" name="s" type="float">
@@ -176,7 +176,7 @@
Return sign (-1 or +1).
</description>
</method>
- <method name="pow" >
+ <method name="pow">
<return type="float">
</return>
<argument index="0" name="x" type="float">
@@ -187,7 +187,7 @@
Power function, x elevate to y.
</description>
</method>
- <method name="log" >
+ <method name="log">
<return type="float">
</return>
<argument index="0" name="s" type="float">
@@ -196,7 +196,7 @@
Natural logarithm.
</description>
</method>
- <method name="exp" >
+ <method name="exp">
<return type="float">
</return>
<argument index="0" name="s" type="float">
@@ -205,7 +205,7 @@
Exponential logarithm.
</description>
</method>
- <method name="isnan" >
+ <method name="isnan">
<return type="float">
</return>
<argument index="0" name="s" type="float">
@@ -214,7 +214,7 @@
Return true if the float is not a number.
</description>
</method>
- <method name="isinf" >
+ <method name="isinf">
<return type="float">
</return>
<argument index="0" name="s" type="float">
@@ -223,7 +223,7 @@
Return true if the float is infinite.
</description>
</method>
- <method name="ease" >
+ <method name="ease">
<return type="float">
</return>
<argument index="0" name="s" type="float">
@@ -234,7 +234,7 @@
Easing function, based on exponent. 0 is constant, 1 is linear, 0 to 1 is ease-in, 1+ is ease out. Negative values are in-out/out in.
</description>
</method>
- <method name="decimals" >
+ <method name="decimals">
<return type="float">
</return>
<argument index="0" name="step" type="float">
@@ -243,7 +243,7 @@
Return the amount of decimals in the floating point value.
</description>
</method>
- <method name="stepify" >
+ <method name="stepify">
<return type="float">
</return>
<argument index="0" name="s" type="float">
@@ -254,7 +254,7 @@
Snap float value to a given step.
</description>
</method>
- <method name="lerp" >
+ <method name="lerp">
<return type="float">
</return>
<argument index="0" name="from" type="float">
@@ -267,7 +267,7 @@
Linear interpolates between two values by a normalized value.
</description>
</method>
- <method name="dectime" >
+ <method name="dectime">
<return type="float">
</return>
<argument index="0" name="value" type="float">
@@ -280,32 +280,28 @@
Decreases time by a specified amount.
</description>
</method>
- <method name="randomize" >
+ <method name="randomize">
<return type="Nil">
</return>
<description>
- Reset the seed of the random number generator with a
- new, different one.
+ Reset the seed of the random number generator with a new, different one.
</description>
</method>
- <method name="randi" >
+ <method name="randi">
<return type="int">
</return>
<description>
- Random 32 bits value (integer). To obtain a value
- from 0 to N, you can use remainder, like (for random
- from 0 to 19): randi() %
- 20.
+ Random 32 bits value (integer). To obtain a value from 0 to N, you can use remainder, like (for random from 0 to 19): randi() % 20.
</description>
</method>
- <method name="randf" >
+ <method name="randf">
<return type="float">
</return>
<description>
Random value (0 to 1 float).
</description>
</method>
- <method name="rand_range" >
+ <method name="rand_range">
<return type="float">
</return>
<argument index="0" name="from" type="float">
@@ -313,11 +309,18 @@
<argument index="1" name="to" type="float">
</argument>
<description>
- Random range, any floating point value between
- 'from' and 'to'
+ Random range, any floating point value between 'from' and 'to'
</description>
</method>
- <method name="rand_seed" >
+ <method name="seed">
+ <return type="Nil">
+ </return>
+ <argument index="0" name="seed" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="rand_seed">
<return type="Array">
</return>
<argument index="0" name="seed" type="float">
@@ -326,7 +329,7 @@
Random from seed, pass a seed and an array with both number and new seed is returned.
</description>
</method>
- <method name="deg2rad" >
+ <method name="deg2rad">
<return type="float">
</return>
<argument index="0" name="deg" type="float">
@@ -335,7 +338,7 @@
Convert from degrees to radians.
</description>
</method>
- <method name="rad2deg" >
+ <method name="rad2deg">
<return type="float">
</return>
<argument index="0" name="rad" type="float">
@@ -344,7 +347,7 @@
Convert from radias to degrees.
</description>
</method>
- <method name="linear2db" >
+ <method name="linear2db">
<return type="float">
</return>
<argument index="0" name="nrg" type="float">
@@ -353,7 +356,7 @@
Convert from linear energy to decibels (audio).
</description>
</method>
- <method name="db2linear" >
+ <method name="db2linear">
<return type="float">
</return>
<argument index="0" name="db" type="float">
@@ -362,7 +365,7 @@
Convert from decibels to linear energy (audio).
</description>
</method>
- <method name="max" >
+ <method name="max">
<return type="float">
</return>
<argument index="0" name="a" type="float">
@@ -373,7 +376,7 @@
Return the maximum of two values.
</description>
</method>
- <method name="min" >
+ <method name="min">
<return type="float">
</return>
<argument index="0" name="a" type="float">
@@ -384,7 +387,7 @@
Return the minimum of two values.
</description>
</method>
- <method name="clamp" >
+ <method name="clamp">
<return type="float">
</return>
<argument index="0" name="val" type="float">
@@ -397,7 +400,7 @@
Clamp both values to a range.
</description>
</method>
- <method name="nearest_po2" >
+ <method name="nearest_po2">
<return type="int">
</return>
<argument index="0" name="val" type="int">
@@ -406,8 +409,8 @@
Return the nearest larger power of 2 for an integer.
</description>
</method>
- <method name="weakref" >
- <return type="Object">
+ <method name="weakref">
+ <return type="WeakRef">
</return>
<argument index="0" name="obj" type="Object">
</argument>
@@ -415,8 +418,8 @@
Return a weak reference to an object.
</description>
</method>
- <method name="funcref" >
- <return type="Object">
+ <method name="funcref">
+ <return type="FuncRef">
</return>
<argument index="0" name="instance" type="Object">
</argument>
@@ -426,10 +429,10 @@
Returns a reference to the specified function
</description>
</method>
- <method name="convert" >
+ <method name="convert">
<return type="Object">
</return>
- <argument index="0" name="what" type="var">
+ <argument index="0" name="what" type="Variant">
</argument>
<argument index="1" name="type" type="int">
</argument>
@@ -437,151 +440,193 @@
Convert from a type to another in the best way possible. The "type" parameter uses the enum TYPE_* in Global Scope.
</description>
</method>
- <method name="str" >
+ <method name="str">
<return type="String">
</return>
- <argument index="0" name="what" type="var">
+ <argument index="0" name="what" type="Variant">
</argument>
- <argument index="1" name="..." type="var">
+ <argument index="1" name="..." type="Variant">
</argument>
<description>
Convert one or more arguments to strings in the best way possible.
</description>
</method>
- <method name="str" >
+ <method name="str">
<return type="String">
</return>
- <argument index="0" name="what" type="var">
+ <argument index="0" name="what" type="Variant">
</argument>
- <argument index="1" name="..." type="var">
+ <argument index="1" name="..." type="Variant">
</argument>
<description>
Convert one or more arguments to strings in the best way possible.
</description>
</method>
- <method name="print" >
+ <method name="print">
<return type="Nil">
</return>
- <argument index="0" name="what" type="var">
+ <argument index="0" name="what" type="Variant">
</argument>
- <argument index="1" name="..." type="var">
+ <argument index="1" name="..." type="Variant">
</argument>
<description>
Print one or more arguments to strings in the best way possible to a console line.
</description>
</method>
- <method name="printt" >
+ <method name="printt">
<return type="Nil">
</return>
- <argument index="0" name="what" type="var">
+ <argument index="0" name="what" type="Variant">
</argument>
- <argument index="1" name="..." type="var">
+ <argument index="1" name="..." type="Variant">
</argument>
<description>
Print one or more arguments to the console with a tab between each argument.
</description>
</method>
- <method name="printerr" >
+ <method name="prints">
<return type="Nil">
</return>
- <argument index="0" name="what" type="var">
+ <argument index="0" name="what" type="Variant">
</argument>
- <argument index="1" name="..." type="var">
+ <argument index="1" name="..." type="Variant">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="printerr">
+ <return type="Nil">
+ </return>
+ <argument index="0" name="what" type="Variant">
+ </argument>
+ <argument index="1" name="..." type="Variant">
</argument>
<description>
Print one or more arguments to strings in the best way possible to standard error line.
</description>
</method>
- <method name="printraw" >
+ <method name="printraw">
<return type="Nil">
</return>
- <argument index="0" name="what" type="var">
+ <argument index="0" name="what" type="Variant">
</argument>
- <argument index="1" name="..." type="var">
+ <argument index="1" name="..." type="Variant">
</argument>
<description>
Print one or more arguments to strings in the best way possible to console. No newline is added at the end.
</description>
</method>
- <method name="var2str" >
+ <method name="var2str">
<return type="String">
</return>
- <argument index="0" name="var" type="var">
+ <argument index="0" name="var" type="Variant">
</argument>
<description>
Converts the value of a variable to a String.
</description>
</method>
- <method name="str2var:var" >
- <return type="String">
+ <method name="str2var">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="string" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="var2bytes">
+ <return type="RawArray">
</return>
- <argument index="0" name="str" type="String">
+ <argument index="0" name="var" type="Variant">
</argument>
<description>
- Converts the value of a String to a variable.
</description>
</method>
- <method name="range" >
+ <method name="bytes2var">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="bytes" type="RawArray">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="range">
<return type="Array">
</return>
- <argument index="0" name="..." type="var">
+ <argument index="0" name="..." type="Variant">
</argument>
<description>
Return an array with the given range. Range can be 1 argument N (0 to N-1), two arguments (initial, final-1) or three arguments (initial,final-1,increment).
</description>
</method>
- <method name="load" >
- <return type="Object">
+ <method name="load">
+ <return type="Resource">
</return>
<argument index="0" name="path" type="String">
</argument>
<description>
- Load a resource from the filesystem, pass a valid
- path as argument.
+ Load a resource from the filesystem, pass a valid path as argument.
</description>
</method>
- <method name="inst2dict" >
+ <method name="inst2dict">
<return type="Dictionary">
</return>
<argument index="0" name="inst" type="Object">
</argument>
<description>
- Convert a script class instance to a dictionary
- (useful for serializing).
+ Convert a script class instance to a dictionary (useful for serializing).
</description>
</method>
- <method name="dict2inst" >
+ <method name="dict2inst">
<return type="Object">
</return>
<argument index="0" name="dict" type="Dictionary">
</argument>
<description>
- Convert a previously converted instances to dictionary
- back into an instance. Useful for deserializing.
+ Convert a previously converted instances to dictionary back into an instance. Useful for deserializing.
</description>
</method>
- <method name="hash" >
+ <method name="hash">
<return type="int">
</return>
- <argument index="0" name="var:var" type="var">
+ <argument index="0" name="var:Variant" type="Variant">
</argument>
<description>
Hashes the variable passed and returns an integer.
</description>
</method>
- <method name="print_stack" >
+ <method name="Color8">
+ <return type="Color">
+ </return>
+ <argument index="0" name="r8" type="int">
+ </argument>
+ <argument index="1" name="g8" type="int">
+ </argument>
+ <argument index="2" name="b8" type="int">
+ </argument>
+ <argument index="3" name="a8" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="print_stack">
<return type="Nil">
</return>
<description>
- Print a stack track at code location, only works when
- running with debugger turned on.
+ Print a stack track at code location, only works when running with debugger turned on.
+ </description>
+ </method>
+ <method name="instance_from_id">
+ <return type="Object">
+ </return>
+ <argument index="0" name="instance_id" type="int">
+ </argument>
+ <description>
</description>
</method>
</methods>
<constants>
<constant name="PI" value="3.141593">
- Constant that represents how many times the diameter of a
- circumference fits around it's perimeter.
+ Constant that represents how many times the diameter of a circumference fits around it's perimeter.
</constant>
</constants>
</class>
@@ -591,7 +636,7 @@
</brief_description>
<description>
Global scope constants and variables. This is all that resides in the globals, constants regarding error codes, scancodes, property hints, etc. It's not much.
- Singletons are also documented here, since they can be accessed from anywhere.
+ Singletons are also documented here, since they can be accessed from anywhere.
</description>
<methods>
</methods>
@@ -1188,6 +1233,8 @@
</constant>
<constant name="KEY_MASK_CTRL" value="268435456">
</constant>
+ <constant name="KEY_MASK_CMD" value="268435456">
+ </constant>
<constant name="KEY_MASK_KPAD" value="536870912">
</constant>
<constant name="KEY_MASK_GROUP_SWITCH" value="1073741824">
@@ -1353,11 +1400,15 @@
</constant>
<constant name="JOY_ANALOG_2_Y" value="5">
</constant>
+ <constant name="JOY_ANALOG_L2" value="6">
+ </constant>
+ <constant name="JOY_ANALOG_R2" value="7">
+ </constant>
<constant name="OK" value="0">
Functions that return [Error] return OK when everything went ok. Most functions don't return error anyway and/or just print errors to stdout.
</constant>
<constant name="FAILED" value="1">
- Generic fail return error;
+ Generic fail return error.
</constant>
<constant name="ERR_UNAVAILABLE" value="2">
</constant>
@@ -1389,95 +1440,98 @@
</constant>
<constant name="ERR_FILE_CORRUPT" value="16">
</constant>
- <constant name="ERR_FILE_EOF" value="17">
+ <constant name="ERR_FILE_MISSING_DEPENDENCIES" value="17">
+ </constant>
+ <constant name="ERR_FILE_EOF" value="18">
</constant>
- <constant name="ERR_CANT_OPEN" value="18">
+ <constant name="ERR_CANT_OPEN" value="19">
</constant>
- <constant name="ERR_CANT_CREATE" value="19">
+ <constant name="ERR_CANT_CREATE" value="20">
</constant>
- <constant name="ERROR_QUERY_FAILED" value="20">
+ <constant name="ERROR_QUERY_FAILED" value="21">
</constant>
- <constant name="ERR_ALREADY_IN_USE" value="21">
+ <constant name="ERR_ALREADY_IN_USE" value="22">
</constant>
- <constant name="ERR_LOCKED" value="22">
+ <constant name="ERR_LOCKED" value="23">
</constant>
- <constant name="ERR_TIMEOUT" value="23">
+ <constant name="ERR_TIMEOUT" value="24">
</constant>
- <constant name="ERR_CANT_AQUIRE_RESOURCE" value="27">
+ <constant name="ERR_CANT_AQUIRE_RESOURCE" value="28">
</constant>
- <constant name="ERR_INVALID_DATA" value="29">
+ <constant name="ERR_INVALID_DATA" value="30">
</constant>
- <constant name="ERR_INVALID_PARAMETER" value="30">
+ <constant name="ERR_INVALID_PARAMETER" value="31">
</constant>
- <constant name="ERR_ALREADY_EXISTS" value="31">
+ <constant name="ERR_ALREADY_EXISTS" value="32">
</constant>
- <constant name="ERR_DOES_NOT_EXIST" value="32">
+ <constant name="ERR_DOES_NOT_EXIST" value="33">
</constant>
- <constant name="ERR_DATABASE_CANT_READ" value="33">
+ <constant name="ERR_DATABASE_CANT_READ" value="34">
</constant>
- <constant name="ERR_DATABASE_CANT_WRITE" value="34">
+ <constant name="ERR_DATABASE_CANT_WRITE" value="35">
</constant>
- <constant name="ERR_COMPILATION_FAILED" value="35">
+ <constant name="ERR_COMPILATION_FAILED" value="36">
</constant>
- <constant name="ERR_METHOD_NOT_FOUND" value="36">
+ <constant name="ERR_METHOD_NOT_FOUND" value="37">
</constant>
- <constant name="ERR_LINK_FAILED" value="37">
+ <constant name="ERR_LINK_FAILED" value="38">
</constant>
- <constant name="ERR_SCRIPT_FAILED" value="38">
+ <constant name="ERR_SCRIPT_FAILED" value="39">
</constant>
- <constant name="ERR_CYCLIC_LINK" value="39">
+ <constant name="ERR_CYCLIC_LINK" value="40">
</constant>
- <constant name="ERR_BUSY" value="43">
+ <constant name="ERR_BUSY" value="44">
</constant>
- <constant name="ERR_HELP" value="45">
+ <constant name="ERR_HELP" value="46">
</constant>
- <constant name="ERR_BUG" value="46">
+ <constant name="ERR_BUG" value="47">
</constant>
- <constant name="ERR_WTF" value="48">
+ <constant name="ERR_WTF" value="49">
</constant>
<constant name="PROPERTY_HINT_NONE" value="0">
No hint for edited property.
</constant>
<constant name="PROPERTY_HINT_RANGE" value="1">
- Hint string is a range, defined as "min,max" or "min,max,step". This is valid for integers and floats.
+ Hints that the string is a range, defined as "min,max" or "min,max,step". This is valid for integers and floats.
</constant>
<constant name="PROPERTY_HINT_EXP_RANGE" value="2">
- Hint string is an exponential range, defined as "min,max" or "min,max,step". This is valid for integers and floats.
+ Hints that the string is an exponential range, defined as "min,max" or "min,max,step". This is valid for integers and floats.
</constant>
<constant name="PROPERTY_HINT_ENUM" value="3">
- Property hint is an enumerated value, like "Hello,Something,Else". This is valid for integers, floats and strings properties.
+ Property hint for an enumerated value, like "Hello,Something,Else". This is valid for integer, float and string properties.
</constant>
<constant name="PROPERTY_HINT_EXP_EASING" value="4">
</constant>
<constant name="PROPERTY_HINT_LENGTH" value="5">
</constant>
- <constant name="PROPERTY_HINT_KEY_ACCEL" value="6">
+ <constant name="PROPERTY_HINT_KEY_ACCEL" value="7">
</constant>
- <constant name="PROPERTY_HINT_FLAGS" value="7">
- Property hint is a bitmask description, for bits 0,1,2,3 abd 5 the hint would be like "Bit0,Bit1,Bit2,Bit3,,Bit5". Valid only for integers.
+ <constant name="PROPERTY_HINT_FLAGS" value="8">
+ Property hint for a bitmask description, for bits 0,1,2,3 and 5 the hint would be like "Bit0,Bit1,Bit2,Bit3,,Bit5". Valid only for integers.
</constant>
- <constant name="PROPERTY_HINT_ALL_FLAGS" value="8">
+ <constant name="PROPERTY_HINT_ALL_FLAGS" value="9">
+ Property hint for a bitmask description that covers all 32 bits. Valid only for integers.
</constant>
- <constant name="PROPERTY_HINT_FILE" value="9">
+ <constant name="PROPERTY_HINT_FILE" value="10">
String property is a file (so pop up a file dialog when edited). Hint string can be a set of wildcards like "*.doc".
</constant>
- <constant name="PROPERTY_HINT_DIR" value="10">
+ <constant name="PROPERTY_HINT_DIR" value="11">
String property is a directory (so pop up a file dialog when edited).
</constant>
- <constant name="PROPERTY_HINT_GLOBAL_FILE" value="11">
+ <constant name="PROPERTY_HINT_GLOBAL_FILE" value="12">
</constant>
- <constant name="PROPERTY_HINT_GLOBAL_DIR" value="12">
+ <constant name="PROPERTY_HINT_GLOBAL_DIR" value="13">
</constant>
- <constant name="PROPERTY_HINT_RESOURCE_TYPE" value="13">
+ <constant name="PROPERTY_HINT_RESOURCE_TYPE" value="14">
String property is a resource, so open the resource popup menu when edited.
</constant>
- <constant name="PROPERTY_HINT_MULTILINE_TEXT" value="14">
+ <constant name="PROPERTY_HINT_MULTILINE_TEXT" value="15">
</constant>
- <constant name="PROPERTY_HINT_COLOR_NO_ALPHA" value="15">
+ <constant name="PROPERTY_HINT_COLOR_NO_ALPHA" value="16">
</constant>
- <constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSY" value="16">
+ <constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSY" value="17">
</constant>
- <constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS" value="17">
+ <constant name="PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS" value="18">
</constant>
<constant name="PROPERTY_USAGE_STORAGE" value="1">
Property will be used as storage (default).
@@ -1582,39 +1636,35 @@
Axis-Aligned Bounding Box.
</brief_description>
<description>
- AABB provides an 3D Axis-Aligned Bounding Box. It consists of a
- position and a size, and several utility functions. It is typically
- used for simple (fast) overlap tests.
+ AABB provides an 3D Axis-Aligned Bounding Box. It consists of a position, a size, and several utility functions. It is typically used for simple (fast) overlap tests.
</description>
<methods>
- <method name="encloses" >
+ <method name="encloses">
<return type="bool">
</return>
<argument index="0" name="with" type="AABB">
</argument>
<description>
- Return true if this [AABB] completely encloses another
- one.
+ Return true if this [AABB] completely encloses another one.
</description>
</method>
- <method name="expand" >
+ <method name="expand">
<return type="AABB">
</return>
<argument index="0" name="to_point" type="Vector3">
</argument>
<description>
- Return this [AABB] expanded to include a given
- point.
+ Return this [AABB] expanded to include a given point.
</description>
</method>
- <method name="get_area" >
+ <method name="get_area">
<return type="float">
</return>
<description>
- Get the area inside the [AABB]
+ Get the area of the [AABB].
</description>
</method>
- <method name="get_endpoint" >
+ <method name="get_endpoint">
<return type="Vector3">
</return>
<argument index="0" name="idx" type="int">
@@ -1623,87 +1673,81 @@
Get the position of the 8 endpoints of the [AABB] in space.
</description>
</method>
- <method name="get_longest_axis" >
+ <method name="get_longest_axis">
<return type="Vector3">
</return>
<description>
- Return the normalized longest axis of the [AABB]
+ Return the normalized longest axis of the [AABB].
</description>
</method>
- <method name="get_longest_axis_index" >
+ <method name="get_longest_axis_index">
<return type="int">
</return>
<description>
- Return the index of the longest axis of the [AABB]
- (according to [Vector3]::AXIS* enum).
+ Return the index of the longest axis of the [AABB] (according to [Vector3]::AXIS* enum).
</description>
</method>
- <method name="get_longest_axis_size" >
+ <method name="get_longest_axis_size">
<return type="float">
</return>
<description>
- Return the scalar length of the longest axis of the
- [AABB].
+ Return the scalar length of the longest axis of the [AABB].
</description>
</method>
- <method name="get_shortest_axis" >
+ <method name="get_shortest_axis">
<return type="Vector3">
</return>
<description>
- Return the normalized shortest axis of the [AABB]
+ Return the normalized shortest axis of the [AABB].
</description>
</method>
- <method name="get_shortest_axis_index" >
+ <method name="get_shortest_axis_index">
<return type="int">
</return>
<description>
- Return the index of the shortest axis of the [AABB]
- (according to [Vector3]::AXIS* enum).
+ Return the index of the shortest axis of the [AABB] (according to [Vector3]::AXIS* enum).
</description>
</method>
- <method name="get_shortest_axis_size" >
+ <method name="get_shortest_axis_size">
<return type="float">
</return>
<description>
- Return the scalar length of the shortest axis of the
- [AABB].
+ Return the scalar length of the shortest axis of the [AABB].
</description>
</method>
- <method name="get_support" >
+ <method name="get_support">
<return type="Vector3">
</return>
<argument index="0" name="dir" type="Vector3">
</argument>
<description>
- Return the support point in a given direction. This
- is useful for collision detection algorithms.
+ Return the support point in a given direction. This is useful for collision detection algorithms.
</description>
</method>
- <method name="grow" >
+ <method name="grow">
<return type="AABB">
</return>
<argument index="0" name="by" type="float">
</argument>
<description>
- Return a copy of the AABB grown a given a mount of
- units towards all the sides.
+ Return a copy of the [AABB] grown a given amount of units towards all the sides.
</description>
</method>
- <method name="has_no_area" >
+ <method name="has_no_area">
<return type="bool">
</return>
<description>
Return true if the [AABB] is flat or empty.
</description>
</method>
- <method name="has_no_surface" >
+ <method name="has_no_surface">
<return type="bool">
</return>
<description>
Return true if the [AABB] is empty.
</description>
</method>
- <method name="has_point" >
+ <method name="has_point">
<return type="bool">
</return>
<argument index="0" name="point" type="Vector3">
@@ -1712,17 +1756,16 @@
Return true if the [AABB] contains a point.
</description>
</method>
- <method name="intersection" >
+ <method name="intersection">
<return type="AABB">
</return>
<argument index="0" name="with" type="AABB">
</argument>
<description>
- Return the intersection between two [AABB]s. An
- empty AABB (size 0,0,0) is returned on failure.
+ Return the intersection between two [AABB]s. An empty AABB (size 0,0,0) is returned on failure.
</description>
</method>
- <method name="intersects" >
+ <method name="intersects">
<return type="bool">
</return>
<argument index="0" name="with" type="AABB">
@@ -1731,16 +1774,16 @@
Return true if the [AABB] overlaps with another.
</description>
</method>
- <method name="intersects_plane" >
+ <method name="intersects_plane">
<return type="bool">
</return>
<argument index="0" name="plane" type="Plane">
</argument>
<description>
- Return true if the AABB is at both sides of a plane.
+ Return true if the [AABB] is at both sides of a plane.
</description>
</method>
- <method name="intersects_segment" >
+ <method name="intersects_segment">
<return type="bool">
</return>
<argument index="0" name="from" type="Vector3">
@@ -1750,17 +1793,18 @@
<description>
</description>
</method>
- <method name="merge" >
+ <method name="merge">
<return type="AABB">
</return>
<argument index="0" name="with" type="AABB">
</argument>
<description>
- Combine this [AABB] with another one, a larger one
- is returned that contains both.
+ Combine this [AABB] with another, a larger one is returned that contains both.
</description>
</method>
- <method name="AABB" >
+ <method name="AABB">
+ <return type="AABB">
+ </return>
<argument index="0" name="pos" type="Vector3">
</argument>
<argument index="1" name="size" type="Vector3">
@@ -1786,41 +1830,38 @@
Base dialog for user notification.
</brief_description>
<description>
- This dialog is useful for small notifications to the user about an
- event. It can only be accepted or closed, with the same result.
+ This dialog is useful for small notifications to the user about an event. It can only be accepted or closed, with the same result.
</description>
<methods>
- <method name="get_ok" >
+ <method name="get_ok">
<return type="Object">
</return>
<description>
Return the OK Button.
</description>
</method>
- <method name="get_label" >
+ <method name="get_label">
<return type="Object">
</return>
<description>
Return the label used for built-in text.
</description>
</method>
- <method name="set_hide_on_ok" >
+ <method name="set_hide_on_ok">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
- Set whether the dialog is hidden when accepted
- (default true).
+ Set whether the dialog is hidden when accepted (default true).
</description>
</method>
- <method name="get_hide_on_ok" qualifiers="const" >
+ <method name="get_hide_on_ok" qualifiers="const">
<return type="bool">
</return>
<description>
- Return true if the dialog will be hidden when
- accepted (default true).
+ Return true if the dialog will be hidden when accepted (default true).
</description>
</method>
- <method name="add_button" >
+ <method name="add_button">
<return type="Button">
</return>
<argument index="0" name="text" type="String">
@@ -1832,7 +1873,7 @@
<description>
</description>
</method>
- <method name="add_cancel" >
+ <method name="add_cancel">
<return type="Button">
</return>
<argument index="0" name="name" type="String">
@@ -1840,22 +1881,23 @@
<description>
</description>
</method>
- <method name="register_text_enter" >
+ <method name="register_text_enter">
+ <return type="LineEdit">
+ </return>
<argument index="0" name="line_edit" type="Object">
</argument>
<description>
- Register a [LineEdit] in the dialog. When the enter
- key is pressed, the dialog will be accepted.
+ Register a [LineEdit] in the dialog. When the enter key is pressed, the dialog will be accepted.
</description>
</method>
- <method name="set_text" >
+ <method name="set_text">
<argument index="0" name="text" type="String">
</argument>
<description>
Set the built-in label text.
</description>
</method>
- <method name="get_text" qualifiers="const" >
+ <method name="get_text" qualifiers="const">
<return type="String">
</return>
<description>
@@ -1888,104 +1930,98 @@
Sprite node that can use multiple textures for animation.
</description>
<methods>
- <method name="set_sprite_frames" >
+ <method name="set_sprite_frames">
<argument index="0" name="sprite_frames" type="SpriteFrames">
</argument>
<description>
- Set the [SpriteFrames] resource, which contains all
- frames.
+ Set the [SpriteFrames] resource, which contains all frames.
</description>
</method>
- <method name="get_sprite_frames" qualifiers="const" >
+ <method name="get_sprite_frames" qualifiers="const">
<return type="SpriteFrames">
</return>
<description>
- Get the [SpriteFrames] resource, which contains all
- frames.
+ Get the [SpriteFrames] resource, which contains all frames.
</description>
</method>
- <method name="set_centered" >
+ <method name="set_centered">
<argument index="0" name="centered" type="bool">
</argument>
<description>
- When turned on, offset at (0,0) is the center of the
- sprite, when off, the top-left corner is.
+ When turned on, offset at (0,0) is the center of the sprite, when off, the top-left corner is.
</description>
</method>
- <method name="is_centered" qualifiers="const" >
+ <method name="is_centered" qualifiers="const">
<return type="bool">
</return>
<description>
Return true when centered. See [set_centered].
</description>
</method>
- <method name="set_offset" >
+ <method name="set_offset">
<argument index="0" name="offset" type="Vector2">
</argument>
<description>
- Set the offset of the sprite in the node origin.
- Position varies depending on whether it is centered
- or not.
+ Set the offset of the sprite in the node origin. Position varies depending on whether it is centered or not.
</description>
</method>
- <method name="get_offset" qualifiers="const" >
+ <method name="get_offset" qualifiers="const">
<return type="Vector2">
</return>
<description>
Return the offset of the sprite in the node origin.
</description>
</method>
- <method name="set_flip_h" >
+ <method name="set_flip_h">
<argument index="0" name="flip_h" type="bool">
</argument>
<description>
If true, sprite is flipped horizontally.
</description>
</method>
- <method name="is_flipped_h" qualifiers="const" >
+ <method name="is_flipped_h" qualifiers="const">
<return type="bool">
</return>
<description>
Return true if sprite is flipped horizontally.
</description>
</method>
- <method name="set_flip_v" >
+ <method name="set_flip_v">
<argument index="0" name="flip_v" type="bool">
</argument>
<description>
If true, sprite is flipped vertically.
</description>
</method>
- <method name="is_flipped_v" qualifiers="const" >
+ <method name="is_flipped_v" qualifiers="const">
<return type="bool">
</return>
<description>
Return true if sprite is flipped vertically.
</description>
</method>
- <method name="set_frame" >
+ <method name="set_frame">
<argument index="0" name="frame" type="int">
</argument>
<description>
- Set the visible sprite frame index (from the list of
- frames inside the [SpriteFrames] resource).
+ Set the visible sprite frame index (from the list of frames inside the [SpriteFrames] resource).
</description>
</method>
- <method name="get_frame" qualifiers="const" >
+ <method name="get_frame" qualifiers="const">
<return type="int">
</return>
<description>
Return the visible frame index.
</description>
</method>
- <method name="set_modulate" >
+ <method name="set_modulate">
<argument index="0" name="modulate" type="Color">
</argument>
<description>
Change the color modulation (multiplication) for this sprite.
</description>
</method>
- <method name="get_modulate" qualifiers="const" >
+ <method name="get_modulate" qualifiers="const">
<return type="Color">
</return>
<description>
@@ -1993,6 +2029,12 @@
</description>
</method>
</methods>
+ <signals>
+ <signal name="frame_changed">
+ <description>
+ </description>
+ </signal>
+ </signals>
<constants>
</constants>
</class>
@@ -2002,31 +2044,37 @@
<description>
</description>
<methods>
- <method name="set_sprite_frames" >
+ <method name="set_sprite_frames">
<argument index="0" name="sprite_frames" type="SpriteFrames">
</argument>
<description>
</description>
</method>
- <method name="get_sprite_frames" qualifiers="const" >
+ <method name="get_sprite_frames" qualifiers="const">
<return type="Texture">
</return>
<description>
</description>
</method>
- <method name="set_frame" >
+ <method name="set_frame">
<argument index="0" name="frame" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_frame" qualifiers="const" >
+ <method name="get_frame" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
</methods>
+ <signals>
+ <signal name="frame_changed">
+ <description>
+ </description>
+ </signal>
+ </signals>
<constants>
</constants>
</class>
@@ -2038,7 +2086,7 @@
An Animation resource contains data used to animate everything in the engine. Animations are divided into tracks, and each track must be linked to a node. The state of that node can be changed through time, by adding timed keys (events) to the track. [br] Animations are just data containers, and must be added to odes such as an [AnimationPlayer] or [AnimationTreePlayer] to be played back.
</description>
<methods>
- <method name="add_track" >
+ <method name="add_track">
<return type="int">
</return>
<argument index="0" name="type" type="int">
@@ -2049,21 +2097,21 @@
Add a track to the Animation. The track type must be specified as any of the values in te TYPE_* enumeration.
</description>
</method>
- <method name="remove_track" >
+ <method name="remove_track">
<argument index="0" name="idx" type="int">
</argument>
<description>
Remove a track by specifying the track index.
</description>
</method>
- <method name="get_track_count" qualifiers="const" >
+ <method name="get_track_count" qualifiers="const">
<return type="int">
</return>
<description>
Return the amount of tracks in the animation.
</description>
</method>
- <method name="track_get_type" qualifiers="const" >
+ <method name="track_get_type" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="idx" type="int">
@@ -2072,7 +2120,7 @@
Get the type of a track.
</description>
</method>
- <method name="track_get_path" qualifiers="const" >
+ <method name="track_get_path" qualifiers="const">
<return type="NodePath">
</return>
<argument index="0" name="idx" type="int">
@@ -2081,16 +2129,16 @@
Get the path of a track. for more information on the path format, see [method track_set_path]
</description>
</method>
- <method name="track_set_path" >
+ <method name="track_set_path">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="path" type="NodePath">
</argument>
<description>
- Set the path of a track. Paths must be valid scene-tree paths to a node, and must be specified starting from the parent node of the node that will reproduce the animation. Tracks that control properties or bones must append their name after the path, separated by ":". Example: "character/skeleton:ankle" or "character/mesh:transform/local"
+ Set the path of a track. Paths must be valid scene-tree paths to a node, and must be specified starting from the parent node of the node that will reproduce the animation. Tracks that control properties or bones must append their name after the path, separated by ":". Example: "character/skeleton:ankle" or "character/mesh:transform/local"
</description>
</method>
- <method name="find_track" qualifiers="const" >
+ <method name="find_track" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="path" type="NodePath">
@@ -2098,21 +2146,21 @@
<description>
</description>
</method>
- <method name="track_move_up" >
+ <method name="track_move_up">
<argument index="0" name="idx" type="int">
</argument>
<description>
Move a track up.
</description>
</method>
- <method name="track_move_down" >
+ <method name="track_move_down">
<argument index="0" name="idx" type="int">
</argument>
<description>
Nove a track down.
</description>
</method>
- <method name="transform_track_insert_key" >
+ <method name="transform_track_insert_key">
<return type="int">
</return>
<argument index="0" name="idx" type="int">
@@ -2129,7 +2177,7 @@
Insert a transform key for a transform track.
</description>
</method>
- <method name="track_insert_key" >
+ <method name="track_insert_key">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="time" type="float">
@@ -2142,7 +2190,7 @@
Insert a generic key in a given track.
</description>
</method>
- <method name="track_remove_key" >
+ <method name="track_remove_key">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="key_idx" type="int">
@@ -2151,7 +2199,7 @@
Remove a key by index in a given track.
</description>
</method>
- <method name="track_remove_key_at_pos" >
+ <method name="track_remove_key_at_pos">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="pos" type="float">
@@ -2160,7 +2208,7 @@
Remove a key by position (seconds) in a given track.
</description>
</method>
- <method name="track_set_key_value" >
+ <method name="track_set_key_value">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="key" type="int">
@@ -2171,7 +2219,7 @@
Set the value of an existing key.
</description>
</method>
- <method name="track_set_key_transition" >
+ <method name="track_set_key_transition">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="key_idx" type="int">
@@ -2179,11 +2227,10 @@
<argument index="2" name="transition" type="float">
</argument>
<description>
- Set the transition curve (easing) for a specific key (see built-in
- math function "ease").
+ Set the transition curve (easing) for a specific key (see built-in math function "ease").
</description>
</method>
- <method name="track_get_key_transition" qualifiers="const" >
+ <method name="track_get_key_transition" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="idx" type="int">
@@ -2191,11 +2238,10 @@
<argument index="1" name="key_idx" type="int">
</argument>
<description>
- Return the transition curve (easing) for a specific key (see built-in
- math function "ease").
+ Return the transition curve (easing) for a specific key (see built-in math function "ease").
</description>
</method>
- <method name="track_get_key_count" qualifiers="const" >
+ <method name="track_get_key_count" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="idx" type="int">
@@ -2204,7 +2250,7 @@
Return the amount of keys in a given track.
</description>
</method>
- <method name="track_get_key_value" qualifiers="const" >
+ <method name="track_get_key_value" qualifiers="const">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="key_idx" type="int">
@@ -2213,7 +2259,7 @@
Return the value of a given key in a given track.
</description>
</method>
- <method name="track_get_key_time" qualifiers="const" >
+ <method name="track_get_key_time" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="idx" type="int">
@@ -2224,7 +2270,7 @@
Return the time at which the key is located.
</description>
</method>
- <method name="track_find_key" qualifiers="const" >
+ <method name="track_find_key" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="idx" type="int">
@@ -2237,7 +2283,7 @@
Find the key index by time in a given track. Optionally, only find it if the exact time is given.
</description>
</method>
- <method name="track_set_interpolation_type" >
+ <method name="track_set_interpolation_type">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="interpolation" type="int">
@@ -2246,7 +2292,7 @@
Set the interpolation type of a given track, from the INTERPOLATION_* enum.
</description>
</method>
- <method name="track_get_interpolation_type" qualifiers="const" >
+ <method name="track_get_interpolation_type" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="idx" type="int">
@@ -2255,7 +2301,7 @@
Return the interpolation type of a given track, from the INTERPOLATION_* enum.
</description>
</method>
- <method name="transform_track_interpolate" qualifiers="const" >
+ <method name="transform_track_interpolate" qualifiers="const">
<return type="Array">
</return>
<argument index="0" name="idx" type="int">
@@ -2266,7 +2312,7 @@
Return the interpolated value of a transform track at a given time (in seconds). An array consisting of 3 elements: position ([Vector3]), rotation ([Quat]) and scale ([Vector3]).
</description>
</method>
- <method name="value_track_set_continuous" >
+ <method name="value_track_set_continuous">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="continuous" type="bool">
@@ -2275,7 +2321,7 @@
Enable or disable interpolation for a whole track. By default tracks are interpolated.
</description>
</method>
- <method name="value_track_is_continuous" qualifiers="const" >
+ <method name="value_track_is_continuous" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="idx" type="int">
@@ -2284,7 +2330,7 @@
Return wether interpolation is enabled or disabled for a whole track. By default tracks are interpolated.
</description>
</method>
- <method name="value_track_get_key_indices" qualifiers="const" >
+ <method name="value_track_get_key_indices" qualifiers="const">
<return type="IntArray">
</return>
<argument index="0" name="idx" type="int">
@@ -2297,7 +2343,7 @@
Return all the key indices of a value track, given a position and delta time.
</description>
</method>
- <method name="method_track_get_key_indices" qualifiers="const" >
+ <method name="method_track_get_key_indices" qualifiers="const">
<return type="IntArray">
</return>
<argument index="0" name="idx" type="int">
@@ -2310,7 +2356,7 @@
Return all the key indices of a method track, given a position and delta time.
</description>
</method>
- <method name="method_track_get_name" qualifiers="const" >
+ <method name="method_track_get_name" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="idx" type="int">
@@ -2321,7 +2367,7 @@
Return the method name of a method track.
</description>
</method>
- <method name="method_track_get_params" qualifiers="const" >
+ <method name="method_track_get_params" qualifiers="const">
<return type="Array">
</return>
<argument index="0" name="idx" type="int">
@@ -2332,47 +2378,47 @@
Return the arguments values to be called on a method track for a given key in a given track.
</description>
</method>
- <method name="set_length" >
+ <method name="set_length">
<argument index="0" name="time_sec" type="float">
</argument>
<description>
Set the total length of the animation (in seconds). Note that length is not delimited by the last key, as this one may be before or after the end to ensure correct interpolation and looping.
</description>
</method>
- <method name="get_length" qualifiers="const" >
+ <method name="get_length" qualifiers="const">
<return type="float">
</return>
<description>
Return the total length of the animation (in seconds).
</description>
</method>
- <method name="set_loop" >
+ <method name="set_loop">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
Set a flag indicating that the animation must loop. This is uses for correct interpolation of animation cycles, and for hinting the player that it must restart the animation.
</description>
</method>
- <method name="has_loop" qualifiers="const" >
+ <method name="has_loop" qualifiers="const">
<return type="bool">
</return>
<description>
Return wether the animation has the loop flag set.
</description>
</method>
- <method name="set_step" >
+ <method name="set_step">
<argument index="0" name="size_sec" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_step" qualifiers="const" >
+ <method name="get_step" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="clear" >
+ <method name="clear">
<description>
Clear the animation (clear all tracks and reset all).
</description>
@@ -2401,13 +2447,13 @@
</class>
<class name="AnimationPlayer" inherits="Node" category="Core">
<brief_description>
- Container and player of [Animaton] resources.
+ Container and player of [Animation] resources.
</brief_description>
<description>
An animation player is used for general purpose playback of [Animation] resources. It contains a dictionary of animations (referenced by name) and custom blend times between their transitions. Additionally, animations can be played and blended in diferent channels.
</description>
<methods>
- <method name="add_animation" >
+ <method name="add_animation">
<return type="int">
</return>
<argument index="0" name="name" type="String">
@@ -2418,14 +2464,14 @@
Add an animation resource to the player, which will be later referenced by the "name" argument.
</description>
</method>
- <method name="remove_animation" >
+ <method name="remove_animation">
<argument index="0" name="name" type="String">
</argument>
<description>
Remove an animation from the player (by supplying the same name used to add it).
</description>
</method>
- <method name="rename_animation" >
+ <method name="rename_animation">
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="newname" type="String">
@@ -2434,7 +2480,7 @@
Rename an existing animation.
</description>
</method>
- <method name="has_animation" qualifiers="const" >
+ <method name="has_animation" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="name" type="String">
@@ -2443,7 +2489,7 @@
Request wether an [Animation] name exist within the player.
</description>
</method>
- <method name="get_animation" qualifiers="const" >
+ <method name="get_animation" qualifiers="const">
<return type="Animation">
</return>
<argument index="0" name="name" type="String">
@@ -2452,14 +2498,14 @@
Get an [Animation] resource by requesting a name.
</description>
</method>
- <method name="get_animation_list" qualifiers="const" >
+ <method name="get_animation_list" qualifiers="const">
<return type="StringArray">
</return>
<description>
Get the list of names of the animations stored in the player.
</description>
</method>
- <method name="set_blend_time" >
+ <method name="set_blend_time">
<argument index="0" name="anim_from" type="String">
</argument>
<argument index="1" name="anim_to" type="String">
@@ -2470,7 +2516,7 @@
Specify a blend time (in seconds) between two animations, referemced by their names.
</description>
</method>
- <method name="get_blend_time" qualifiers="const" >
+ <method name="get_blend_time" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="anim_from" type="String">
@@ -2481,21 +2527,21 @@
Get the blend time between two animations, referemced by their names.
</description>
</method>
- <method name="set_default_blend_time" >
+ <method name="set_default_blend_time">
<argument index="0" name="sec" type="float">
</argument>
<description>
Set the default blend time between animations.
</description>
</method>
- <method name="get_default_blend_time" qualifiers="const" >
+ <method name="get_default_blend_time" qualifiers="const">
<return type="float">
</return>
<description>
Return the default blend time between animations.
</description>
</method>
- <method name="play" >
+ <method name="play">
<argument index="0" name="name" type="String" default="&quot;&quot;">
</argument>
<argument index="1" name="custom_blend" type="float" default="-1">
@@ -2505,56 +2551,62 @@
<argument index="3" name="from_end" type="bool" default="false">
</argument>
<description>
- Play a given animation by the animation name. Custom
- speed and blend times can be set. If custom speed is
- negative (-1), 'from_end' being true can play the
- animation backwards.
+ Play a given animation by the animation name. Custom speed and blend times can be set. If custom speed is negative (-1), 'from_end' being true can play the animation backwards.
</description>
</method>
- <method name="stop" >
+ <method name="play_backwards">
+ <argument index="0" name="name" type="String" default="&quot;&quot;">
+ </argument>
+ <argument index="1" name="custom_blend" type="float" default="-1">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="stop">
+ <argument index="0" name="reset" type="bool" default="true">
+ </argument>
<description>
- Stop the currently played animation.
</description>
</method>
- <method name="stop_all" >
+ <method name="stop_all">
<description>
Stop playback of animations (deprecated).
</description>
</method>
- <method name="is_playing" qualifiers="const" >
+ <method name="is_playing" qualifiers="const">
<return type="bool">
</return>
<description>
Return wether an animation is playing.
</description>
</method>
- <method name="set_current_animation" >
+ <method name="set_current_animation">
<argument index="0" name="anim" type="String">
</argument>
<description>
- Set the current animation (even if no playback occurs). Using set_current_animation() and set_active() are similar to claling play().
+ Set the current animation (even if no playback occurs). Using set_current_animation() and set_active() are similar to calling play().
</description>
</method>
- <method name="get_current_animation" qualifiers="const" >
+ <method name="get_current_animation" qualifiers="const">
<return type="String">
</return>
<description>
Return the name of the animation being played.
</description>
</method>
- <method name="queue" >
+ <method name="queue">
<argument index="0" name="name" type="String">
</argument>
<description>
Queue an animation for playback once the current one is done.
</description>
</method>
- <method name="clear_queue" >
+ <method name="clear_queue">
<description>
If animations are queued to play, clear them.
</description>
</method>
- <method name="set_active" >
+ <method name="set_active">
<argument index="0" name="active" type="bool">
</argument>
<description>
@@ -2562,77 +2614,72 @@
will do nothing.
</description>
</method>
- <method name="is_active" qualifiers="const" >
+ <method name="is_active" qualifiers="const">
<return type="bool">
</return>
<description>
Return true if the player is active.
</description>
</method>
- <method name="set_speed" >
+ <method name="set_speed">
<argument index="0" name="speed" type="float">
</argument>
<description>
Set a speed scaling ratio in a given animation channel (or channel 0 if none is provided). Default ratio is [i]1[/i] (no scaling).
</description>
</method>
- <method name="get_speed" qualifiers="const" >
+ <method name="get_speed" qualifiers="const">
<return type="float">
</return>
<description>
Get the speed scaling ratio in a given animation channel (or channel 0 if none is provided). Default ratio is [i]1[/i] (no scaling).
</description>
</method>
- <method name="set_autoplay" >
+ <method name="set_autoplay">
<argument index="0" name="name" type="String">
</argument>
<description>
Set the name of the animation that will be automatically played when the scene is loaded.
</description>
</method>
- <method name="get_autoplay" qualifiers="const" >
+ <method name="get_autoplay" qualifiers="const">
<return type="String">
</return>
<description>
Return the name of the animation that will be automatically played when the scene is loaded.
</description>
</method>
- <method name="set_root" >
+ <method name="set_root">
<argument index="0" name="path" type="NodePath">
</argument>
<description>
- AnimationPlayer resolves animation track paths from
- this node (which is relative to itself), by
- default root is "..", but it can be changed..
+ AnimationPlayer resolves animation track paths from this node (which is relative to itself), by default root is "..", but it can be changed.
</description>
</method>
- <method name="get_root" qualifiers="const" >
+ <method name="get_root" qualifiers="const">
<return type="NodePath">
</return>
<description>
Return path to root node (see [set_root]).
</description>
</method>
- <method name="seek" >
+ <method name="seek">
<argument index="0" name="pos_sec" type="float">
</argument>
<argument index="1" name="update" type="bool" default="false">
</argument>
<description>
- Seek the animation to a given position in time (in
- seconds). If 'update'
- is true, the animation will be updated too,
- otherwise it will be updated at process time.
+ Seek the animation to a given position in time (in seconds). If 'update' is true, the animation will be updated too, otherwise it will be updated at process time.
</description>
</method>
- <method name="get_pos" qualifiers="const" >
+ <method name="get_pos" qualifiers="const">
<return type="float">
</return>
<description>
- Return the playback position (in seconds) in an animation channel (or channel 0 if none is provided)
+ Return the playback position (in seconds) in an animation channel (or channel 0 if none is provided).
</description>
</method>
- <method name="find_animation" qualifiers="const" >
+ <method name="find_animation" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="animation" type="Animation">
@@ -2641,42 +2688,40 @@
Find an animation name by resource.
</description>
</method>
- <method name="clear_caches" >
+ <method name="clear_caches">
<description>
The animation player creates caches for faster access to the nodes it will animate. However, if a specific node is removed, it may not notice it, so clear_caches will force the player to search for the nodes again.
</description>
</method>
- <method name="set_animation_process_mode" >
+ <method name="set_animation_process_mode">
<argument index="0" name="mode" type="int">
</argument>
<description>
Set the mode in which the animation player processes. By default, it processes on idle time (framerate dependent), but using fixed time works well for animating static collision bodies in 2D and 3D. See enum ANIMATION_PROCESS_*.
</description>
</method>
- <method name="get_animation_process_mode" qualifiers="const" >
+ <method name="get_animation_process_mode" qualifiers="const">
<return type="int">
</return>
<description>
Return the mode in which the animation player processes. See [method set_animation_process_mode].
</description>
</method>
- <method name="get_current_animation_pos" qualifiers="const" >
+ <method name="get_current_animation_pos" qualifiers="const">
<return type="float">
</return>
<description>
- Get the position (in seconds) of the currently being
- played animation.
+ Get the position (in seconds) of the currently being played animation.
</description>
</method>
- <method name="get_current_animation_length" qualifiers="const" >
+ <method name="get_current_animation_length" qualifiers="const">
<return type="float">
</return>
<description>
- Get the length (in seconds) of the currently being
- played animation.
+ Get the length (in seconds) of the currently being played animation.
</description>
</method>
- <method name="advance" >
+ <method name="advance">
<argument index="0" name="delta" type="float">
</argument>
<description>
@@ -2690,8 +2735,7 @@
<argument index="1" name="new_name" type="String">
</argument>
<description>
- If the currently being played animation changes,
- this signal will notify of such change.
+ If the currently being played animation changes, this signal will notify of such change.
</description>
</signal>
<signal name="finished">
@@ -2702,8 +2746,7 @@
</signals>
<constants>
<constant name="ANIMATION_PROCESS_FIXED" value="0">
- Process animation on fixed process. This is specially useful
- when animating kinematic bodies.
+ Process animation on fixed process. This is specially useful when animating kinematic bodies.
</constant>
<constant name="ANIMATION_PROCESS_IDLE" value="1">
Process animation on idle process.
@@ -2715,23 +2758,19 @@
Animation Player that uses a node graph for the blending.
</brief_description>
<description>
- Animation Player that uses a node graph for the blending. This kind
- of player is very useful when animating character or other skeleton
- based rigs, because it can combine several animations to form a
- desired pose.
+ Animation Player that uses a node graph for the blending. This kind of player is very useful when animating character or other skeleton based rigs, because it can combine several animations to form a desired pose.
</description>
<methods>
- <method name="add_node" >
+ <method name="add_node">
<argument index="0" name="type" type="int">
</argument>
<argument index="1" name="id" type="String">
</argument>
<description>
- Add a node of a given type in the graph with given
- id.
+ Add a node of a given type in the graph with given id.
</description>
</method>
- <method name="node_exists" qualifiers="const" >
+ <method name="node_exists" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="node" type="String">
@@ -2740,7 +2779,7 @@
Check if a node exists (by name).
</description>
</method>
- <method name="node_rename" >
+ <method name="node_rename">
<return type="int">
</return>
<argument index="0" name="node" type="String">
@@ -2751,7 +2790,7 @@
Rename a node in the graph.
</description>
</method>
- <method name="node_get_type" qualifiers="const" >
+ <method name="node_get_type" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="id" type="String">
@@ -2760,17 +2799,16 @@
Get the node type, will return from NODE_* enum.
</description>
</method>
- <method name="node_get_input_count" qualifiers="const" >
+ <method name="node_get_input_count" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="id" type="String">
</argument>
<description>
- Return the input count for a given node. Different
- types of nodes have different amount of inputs.
+ Return the input count for a given node. Different types of nodes have different amount of inputs.
</description>
</method>
- <method name="node_get_input_source" qualifiers="const" >
+ <method name="node_get_input_source" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="id" type="String">
@@ -2781,7 +2819,7 @@
Return the input source for a given node input.
</description>
</method>
- <method name="animation_node_set_animation" >
+ <method name="animation_node_set_animation">
<argument index="0" name="id" type="String">
</argument>
<argument index="1" name="animation" type="Animation">
@@ -2790,7 +2828,7 @@
Set the animation for an animation node.
</description>
</method>
- <method name="animation_node_get_animation" qualifiers="const" >
+ <method name="animation_node_get_animation" qualifiers="const">
<return type="Animation">
</return>
<argument index="0" name="id" type="String">
@@ -2798,7 +2836,7 @@
<description>
</description>
</method>
- <method name="animation_node_set_master_animation" >
+ <method name="animation_node_set_master_animation">
<argument index="0" name="id" type="String">
</argument>
<argument index="1" name="source" type="String">
@@ -2806,7 +2844,7 @@
<description>
</description>
</method>
- <method name="animation_node_get_master_animation" qualifiers="const" >
+ <method name="animation_node_get_master_animation" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="id" type="String">
@@ -2814,7 +2852,7 @@
<description>
</description>
</method>
- <method name="oneshot_node_set_fadein_time" >
+ <method name="oneshot_node_set_fadein_time">
<argument index="0" name="id" type="String">
</argument>
<argument index="1" name="time_sec" type="float">
@@ -2822,7 +2860,7 @@
<description>
</description>
</method>
- <method name="oneshot_node_get_fadein_time" qualifiers="const" >
+ <method name="oneshot_node_get_fadein_time" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="id" type="String">
@@ -2830,7 +2868,7 @@
<description>
</description>
</method>
- <method name="oneshot_node_set_fadeout_time" >
+ <method name="oneshot_node_set_fadeout_time">
<argument index="0" name="id" type="String">
</argument>
<argument index="1" name="time_sec" type="float">
@@ -2838,7 +2876,7 @@
<description>
</description>
</method>
- <method name="oneshot_node_get_fadeout_time" qualifiers="const" >
+ <method name="oneshot_node_get_fadeout_time" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="id" type="String">
@@ -2846,7 +2884,7 @@
<description>
</description>
</method>
- <method name="oneshot_node_set_autorestart" >
+ <method name="oneshot_node_set_autorestart">
<argument index="0" name="id" type="String">
</argument>
<argument index="1" name="enable" type="bool">
@@ -2854,7 +2892,7 @@
<description>
</description>
</method>
- <method name="oneshot_node_set_autorestart_delay" >
+ <method name="oneshot_node_set_autorestart_delay">
<argument index="0" name="id" type="String">
</argument>
<argument index="1" name="delay_sec" type="float">
@@ -2862,7 +2900,7 @@
<description>
</description>
</method>
- <method name="oneshot_node_set_autorestart_random_delay" >
+ <method name="oneshot_node_set_autorestart_random_delay">
<argument index="0" name="id" type="String">
</argument>
<argument index="1" name="rand_sec" type="float">
@@ -2870,7 +2908,7 @@
<description>
</description>
</method>
- <method name="oneshot_node_has_autorestart" qualifiers="const" >
+ <method name="oneshot_node_has_autorestart" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="id" type="String">
@@ -2878,7 +2916,7 @@
<description>
</description>
</method>
- <method name="oneshot_node_get_autorestart_delay" qualifiers="const" >
+ <method name="oneshot_node_get_autorestart_delay" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="id" type="String">
@@ -2886,7 +2924,7 @@
<description>
</description>
</method>
- <method name="oneshot_node_get_autorestart_random_delay" qualifiers="const" >
+ <method name="oneshot_node_get_autorestart_random_delay" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="id" type="String">
@@ -2894,19 +2932,19 @@
<description>
</description>
</method>
- <method name="oneshot_node_start" >
+ <method name="oneshot_node_start">
<argument index="0" name="id" type="String">
</argument>
<description>
</description>
</method>
- <method name="oneshot_node_stop" >
+ <method name="oneshot_node_stop">
<argument index="0" name="id" type="String">
</argument>
<description>
</description>
</method>
- <method name="oneshot_node_is_active" qualifiers="const" >
+ <method name="oneshot_node_is_active" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="id" type="String">
@@ -2914,7 +2952,7 @@
<description>
</description>
</method>
- <method name="oneshot_node_set_filter_path" >
+ <method name="oneshot_node_set_filter_path">
<argument index="0" name="id" type="String">
</argument>
<argument index="1" name="path" type="NodePath">
@@ -2924,7 +2962,7 @@
<description>
</description>
</method>
- <method name="mix_node_set_amount" >
+ <method name="mix_node_set_amount">
<argument index="0" name="id" type="String">
</argument>
<argument index="1" name="ratio" type="float">
@@ -2932,7 +2970,7 @@
<description>
</description>
</method>
- <method name="mix_node_get_amount" qualifiers="const" >
+ <method name="mix_node_get_amount" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="id" type="String">
@@ -2940,7 +2978,7 @@
<description>
</description>
</method>
- <method name="blend2_node_set_amount" >
+ <method name="blend2_node_set_amount">
<argument index="0" name="id" type="String">
</argument>
<argument index="1" name="blend" type="float">
@@ -2948,7 +2986,7 @@
<description>
</description>
</method>
- <method name="blend2_node_get_amount" qualifiers="const" >
+ <method name="blend2_node_get_amount" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="id" type="String">
@@ -2956,7 +2994,7 @@
<description>
</description>
</method>
- <method name="blend2_node_set_filter_path" >
+ <method name="blend2_node_set_filter_path">
<argument index="0" name="id" type="String">
</argument>
<argument index="1" name="path" type="NodePath">
@@ -2966,7 +3004,7 @@
<description>
</description>
</method>
- <method name="blend3_node_set_amount" >
+ <method name="blend3_node_set_amount">
<argument index="0" name="id" type="String">
</argument>
<argument index="1" name="blend" type="float">
@@ -2974,7 +3012,7 @@
<description>
</description>
</method>
- <method name="blend3_node_get_amount" qualifiers="const" >
+ <method name="blend3_node_get_amount" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="id" type="String">
@@ -2982,7 +3020,7 @@
<description>
</description>
</method>
- <method name="blend4_node_set_amount" >
+ <method name="blend4_node_set_amount">
<argument index="0" name="id" type="String">
</argument>
<argument index="1" name="blend" type="Vector2">
@@ -2990,7 +3028,7 @@
<description>
</description>
</method>
- <method name="blend4_node_get_amount" qualifiers="const" >
+ <method name="blend4_node_get_amount" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="id" type="String">
@@ -2998,7 +3036,7 @@
<description>
</description>
</method>
- <method name="timescale_node_set_scale" >
+ <method name="timescale_node_set_scale">
<argument index="0" name="id" type="String">
</argument>
<argument index="1" name="scale" type="float">
@@ -3006,7 +3044,7 @@
<description>
</description>
</method>
- <method name="timescale_node_get_scale" qualifiers="const" >
+ <method name="timescale_node_get_scale" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="id" type="String">
@@ -3014,7 +3052,7 @@
<description>
</description>
</method>
- <method name="timeseek_node_seek" >
+ <method name="timeseek_node_seek">
<argument index="0" name="id" type="String">
</argument>
<argument index="1" name="pos_sec" type="float">
@@ -3022,7 +3060,7 @@
<description>
</description>
</method>
- <method name="transition_node_set_input_count" >
+ <method name="transition_node_set_input_count">
<argument index="0" name="id" type="String">
</argument>
<argument index="1" name="count" type="int">
@@ -3030,7 +3068,7 @@
<description>
</description>
</method>
- <method name="transition_node_get_input_count" qualifiers="const" >
+ <method name="transition_node_get_input_count" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="id" type="String">
@@ -3038,7 +3076,7 @@
<description>
</description>
</method>
- <method name="transition_node_delete_input" >
+ <method name="transition_node_delete_input">
<argument index="0" name="id" type="String">
</argument>
<argument index="1" name="input_idx" type="int">
@@ -3046,7 +3084,7 @@
<description>
</description>
</method>
- <method name="transition_node_set_input_auto_advance" >
+ <method name="transition_node_set_input_auto_advance">
<argument index="0" name="id" type="String">
</argument>
<argument index="1" name="input_idx" type="int">
@@ -3056,7 +3094,7 @@
<description>
</description>
</method>
- <method name="transition_node_has_input_auto_advance" qualifiers="const" >
+ <method name="transition_node_has_input_auto_advance" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="id" type="String">
@@ -3066,7 +3104,7 @@
<description>
</description>
</method>
- <method name="transition_node_set_xfade_time" >
+ <method name="transition_node_set_xfade_time">
<argument index="0" name="id" type="String">
</argument>
<argument index="1" name="time_sec" type="float">
@@ -3074,7 +3112,7 @@
<description>
</description>
</method>
- <method name="transition_node_get_xfade_time" qualifiers="const" >
+ <method name="transition_node_get_xfade_time" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="id" type="String">
@@ -3082,7 +3120,7 @@
<description>
</description>
</method>
- <method name="transition_node_set_current" >
+ <method name="transition_node_set_current">
<argument index="0" name="id" type="String">
</argument>
<argument index="1" name="input_idx" type="int">
@@ -3090,7 +3128,7 @@
<description>
</description>
</method>
- <method name="transition_node_get_current" qualifiers="const" >
+ <method name="transition_node_get_current" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="id" type="String">
@@ -3098,7 +3136,7 @@
<description>
</description>
</method>
- <method name="node_set_pos" >
+ <method name="node_set_pos">
<argument index="0" name="id" type="String">
</argument>
<argument index="1" name="screen_pos" type="Vector2">
@@ -3106,7 +3144,7 @@
<description>
</description>
</method>
- <method name="node_get_pos" qualifiers="const" >
+ <method name="node_get_pos" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="id" type="String">
@@ -3114,13 +3152,13 @@
<description>
</description>
</method>
- <method name="remove_node" >
+ <method name="remove_node">
<argument index="0" name="id" type="String">
</argument>
<description>
</description>
</method>
- <method name="connect" >
+ <method name="connect">
<return type="int">
</return>
<argument index="0" name="id" type="String">
@@ -3132,7 +3170,7 @@
<description>
</description>
</method>
- <method name="is_connected" qualifiers="const" >
+ <method name="is_connected" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="id" type="String">
@@ -3144,7 +3182,7 @@
<description>
</description>
</method>
- <method name="disconnect" >
+ <method name="disconnect">
<argument index="0" name="id" type="String">
</argument>
<argument index="1" name="dst_input_idx" type="int">
@@ -3152,41 +3190,71 @@
<description>
</description>
</method>
- <method name="set_active" >
+ <method name="set_active">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_active" qualifiers="const" >
+ <method name="is_active" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_base_path" >
+ <method name="set_base_path">
<argument index="0" name="path" type="NodePath">
</argument>
<description>
</description>
</method>
- <method name="get_base_path" qualifiers="const" >
+ <method name="get_base_path" qualifiers="const">
+ <return type="NodePath">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_master_player">
+ <argument index="0" name="nodepath" type="NodePath">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_master_player" qualifiers="const">
<return type="NodePath">
</return>
<description>
</description>
</method>
- <method name="get_node_list" >
+ <method name="get_node_list">
<return type="StringArray">
</return>
<description>
</description>
</method>
- <method name="reset" >
+ <method name="set_animation_process_mode">
+ <argument index="0" name="mode" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_animation_process_mode" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="advance">
+ <argument index="0" name="delta" type="float">
+ </argument>
<description>
</description>
</method>
- <method name="recompute_caches" >
+ <method name="reset">
+ <description>
+ </description>
+ </method>
+ <method name="recompute_caches">
<description>
</description>
</method>
@@ -3220,96 +3288,160 @@
<description>
</description>
<methods>
- <method name="set_space_override_mode" >
+ <method name="set_space_override_mode">
<argument index="0" name="enable" type="int">
</argument>
<description>
+ Set the space override mode. This mode controls how an area affects gravity and damp.
+ AREA_SPACE_OVERRIDE_DISABLED: This area does not affect gravity/damp. These are generally areas that exist only to detect collisions, and objects entering or exiting them.
+ AREA_SPACE_OVERRIDE_COMBINE: This area adds its gravity/damp values to whatever has been calculated so far. This way, many overlapping areas can combine their physics to make interesting effects.
+ AREA_SPACE_OVERRIDE_COMBINE_REPLACE: This area adds its gravity/damp values to whatever has been calculated so far. Then stops taking into account the rest of the areas, even the default one.
+ AREA_SPACE_OVERRIDE_REPLACE: This area replaces any gravity/damp, even the default one, and stops taking into account the rest of the areas.
+ AREA_SPACE_OVERRIDE_REPLACE_COMBINE: This area replaces any gravity/damp calculated so far, but keeps calculating the rest of the areas, down to the default one.
</description>
</method>
- <method name="get_space_override_mode" qualifiers="const" >
+ <method name="get_space_override_mode" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_gravity_is_point" >
+ <method name="set_gravity_is_point">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_gravity_a_point" qualifiers="const" >
+ <method name="is_gravity_a_point" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_gravity_vector" >
+ <method name="set_gravity_distance_scale">
+ <argument index="0" name="distance_scale" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_gravity_distance_scale" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_gravity_vector">
<argument index="0" name="vector" type="Vector3">
</argument>
<description>
</description>
</method>
- <method name="get_gravity_vector" qualifiers="const" >
+ <method name="get_gravity_vector" qualifiers="const">
<return type="Vector3">
</return>
<description>
</description>
</method>
- <method name="set_gravity" >
+ <method name="set_gravity">
<argument index="0" name="gravity" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_gravity" qualifiers="const" >
+ <method name="get_gravity" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_density" >
- <argument index="0" name="density" type="float">
+ <method name="set_angular_damp">
+ <argument index="0" name="angular_damp" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_density" qualifiers="const" >
+ <method name="get_angular_damp" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_priority" >
+ <method name="set_linear_damp">
+ <argument index="0" name="linear_damp" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_linear_damp" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_priority">
<argument index="0" name="priority" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_priority" qualifiers="const" >
+ <method name="get_priority" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_enable_monitoring" >
+ <method name="set_monitorable">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_monitoring_enabled" qualifiers="const" >
+ <method name="is_monitorable" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="get_overlapping_bodies" qualifiers="const" >
+ <method name="set_enable_monitoring">
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_monitoring_enabled" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_overlapping_bodies" qualifiers="const">
<return type="Array">
</return>
<description>
</description>
</method>
+ <method name="get_overlapping_areas" qualifiers="const">
+ <return type="Array">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="overlaps_body" qualifiers="const">
+ <return type="PhysicsBody">
+ </return>
+ <argument index="0" name="body" type="Object">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="overlaps_area" qualifiers="const">
+ <return type="Area">
+ </return>
+ <argument index="0" name="area" type="Object">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<signals>
<signal name="body_enter">
@@ -3330,6 +3462,24 @@
<description>
</description>
</signal>
+ <signal name="area_enter">
+ <argument index="0" name="area" type="Object">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ <signal name="area_enter_shape">
+ <argument index="0" name="area_id" type="int">
+ </argument>
+ <argument index="1" name="area" type="Object">
+ </argument>
+ <argument index="2" name="area_shape" type="int">
+ </argument>
+ <argument index="3" name="area_shape" type="int">
+ </argument>
+ <description>
+ </description>
+ </signal>
<signal name="body_exit">
<argument index="0" name="body" type="Object">
</argument>
@@ -3348,109 +3498,282 @@
<description>
</description>
</signal>
+ <signal name="area_exit">
+ <argument index="0" name="area" type="Object">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ <signal name="area_exit_shape">
+ <argument index="0" name="area_id" type="int">
+ </argument>
+ <argument index="1" name="area" type="Object">
+ </argument>
+ <argument index="2" name="area_shape" type="int">
+ </argument>
+ <argument index="3" name="area_shape" type="int">
+ </argument>
+ <description>
+ </description>
+ </signal>
</signals>
<constants>
</constants>
</class>
<class name="Area2D" inherits="CollisionObject2D" category="Core">
<brief_description>
- General purpose area detection and influence for 2D Phisics.
+ General purpose area detection and influence for 2D physics.
</brief_description>
<description>
- General purpose area detection for 2D Phisics. Areas can be used for detection of objects that enter/exit them, as well as overriding space parameters (changing gravity, damping, etc). An Area2D can be set as a children to a RigidBody2D to generate a custom gravity field. For this, use SPACE_OVERRIDE_COMBINE and point gravity at the center of mass.
+ General purpose area detection for 2D physics. Areas can be used for detection of objects that enter/exit them, as well as overriding space parameters (changing gravity, damping, etc). For this, use any space override different from AREA_SPACE_OVERRIDE_DISABLE and point gravity at the center of mass.
</description>
<methods>
- <method name="set_space_override_mode" >
+ <method name="set_space_override_mode">
<argument index="0" name="enable" type="int">
</argument>
<description>
+ Set the space override mode. This mode controls how an area affects gravity and damp.
+ AREA_SPACE_OVERRIDE_DISABLED: This area does not affect gravity/damp. These are generally areas that exist only to detect collisions, and objects entering or exiting them.
+ AREA_SPACE_OVERRIDE_COMBINE: This area adds its gravity/damp values to whatever has been calculated so far. This way, many overlapping areas can combine their physics to make interesting effects.
+ AREA_SPACE_OVERRIDE_COMBINE_REPLACE: This area adds its gravity/damp values to whatever has been calculated so far. Then stops taking into account the rest of the areas, even the default one.
+ AREA_SPACE_OVERRIDE_REPLACE: This area replaces any gravity/damp, even the default one, and stops taking into account the rest of the areas.
+ AREA_SPACE_OVERRIDE_REPLACE_COMBINE: This area replaces any gravity/damp calculated so far, but keeps calculating the rest of the areas, down to the default one.
</description>
</method>
- <method name="get_space_override_mode" qualifiers="const" >
+ <method name="get_space_override_mode" qualifiers="const">
<return type="int">
</return>
<description>
+ Return the space override mode.
</description>
</method>
- <method name="set_gravity_is_point" >
+ <method name="set_gravity_is_point">
<argument index="0" name="enable" type="bool">
</argument>
<description>
- When overriding space parameters, areas can have a center of gravity as a point.
+ When overriding space parameters, this method sets whether this area has a center of gravity. To set/get the location of the center of gravity, use [method set_gravity_vector]/[method get_gravity_vector].
</description>
</method>
- <method name="is_gravity_a_point" qualifiers="const" >
+ <method name="is_gravity_a_point" qualifiers="const">
<return type="bool">
</return>
<description>
- Return if gravity is a point. When overriding space parameters, areas can have a center of gravity as a point.
+ Return whether gravity is a point. A point gravity will attract objects towards it, as opposed to a gravity vector, which moves them in a given direction.
+ </description>
+ </method>
+ <method name="set_gravity_distance_scale">
+ <argument index="0" name="distance_scale" type="float">
+ </argument>
+ <description>
+ Set the falloff factor for point gravity. The greater this value is, the faster the strength of gravity decreases with the square of distance.
+ </description>
+ </method>
+ <method name="get_gravity_distance_scale" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ Return the falloff factor for point gravity.
</description>
</method>
- <method name="set_gravity_vector" >
+ <method name="set_gravity_vector">
<argument index="0" name="vector" type="Vector2">
</argument>
<description>
- Set gravity vector. If gravity is a point, this will be the attraction center
+ Set the gravity vector. This vector does not have to be normalized.
+ If gravity is a point (see [method is_gravity_a_point]), this will be the attraction center.
</description>
</method>
- <method name="get_gravity_vector" qualifiers="const" >
+ <method name="get_gravity_vector" qualifiers="const">
<return type="Vector2">
</return>
<description>
+ Return the gravity vector. If gravity is a point (see [method is_gravity_a_point]), this will be the attraction center.
</description>
</method>
- <method name="set_gravity" >
+ <method name="set_gravity">
<argument index="0" name="gravity" type="float">
</argument>
<description>
+ Set the gravity intensity. This is useful to alter the force of gravity without altering its direction.
+ This value multiplies the gravity vector, whether it is the given vector ([method set_gravity_vector]), or a calculated one (when using a center of gravity).
</description>
</method>
- <method name="get_gravity" qualifiers="const" >
+ <method name="get_gravity" qualifiers="const">
<return type="float">
</return>
<description>
+ Return the gravity intensity.
</description>
</method>
- <method name="set_density" >
- <argument index="0" name="density" type="float">
+ <method name="set_linear_damp">
+ <argument index="0" name="linear_damp" type="float">
</argument>
<description>
+ Set the rate at which objects stop moving in this area, if there are not any other forces moving it. The value is a fraction of its current speed, lost per second. Thus, a value of 1.0 should mean stopping immediately, and 0.0 means the object never stops.
+ In practice, as the fraction of speed lost gets smaller with each frame, a value of 1.0 does not mean the object will stop in exactly one second. Only when the physics calculations are done at 1 frame per second, it does stop in a second.
</description>
</method>
- <method name="get_density" qualifiers="const" >
+ <method name="get_linear_damp" qualifiers="const">
<return type="float">
</return>
<description>
+ Return the linear damp rate.
</description>
</method>
- <method name="set_priority" >
+ <method name="set_angular_damp">
+ <argument index="0" name="angular_damp" type="float">
+ </argument>
+ <description>
+ Set the rate at which objects stop spinning in this area, if there are not any other forces making it spin. The value is a fraction of its current speed, lost per second. Thus, a value of 1.0 should mean stopping immediately, and 0.0 means the object never stops.
+ In practice, as the fraction of speed lost gets smaller with each frame, a value of 1.0 does not mean the object will stop in exactly one second. Only when the physics calculations are done at 1 frame per second, it does stop in a second.
+ </description>
+ </method>
+ <method name="get_angular_damp" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ Return the angular damp rate.
+ </description>
+ </method>
+ <method name="set_priority">
<argument index="0" name="priority" type="float">
</argument>
<description>
+ Set the order in which the area is processed. Greater values mean the area gets processed first. This is useful for areas which have an space override different from AREA_SPACE_OVERRIDE_DISABLED or AREA_SPACE_OVERRIDE_COMBINE, as they replace values, and are thus order-dependent.
+ Areas with the same priority value get evaluated in an unpredictable order, and should be differentiated if evaluation order is to be important.
</description>
</method>
- <method name="get_priority" qualifiers="const" >
+ <method name="get_priority" qualifiers="const">
<return type="float">
</return>
<description>
+ Return the processing order of this area.
+ </description>
+ </method>
+ <method name="set_collision_mask">
+ <argument index="0" name="collision_mask" type="int">
+ </argument>
+ <description>
+ Set the physics layers this area can scan for collisions.
+ </description>
+ </method>
+ <method name="get_collision_mask" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Return the physics layers this area can scan for collisions.
</description>
</method>
- <method name="set_enable_monitoring" >
+ <method name="set_layer_mask">
+ <argument index="0" name="layer_mask" type="int">
+ </argument>
+ <description>
+ Set the physics layers this area is in.
+ Collidable objects can exist in any of 32 different layers. These layers are not visual, but more of a tagging system instead. A collidable can use these layers/tags to select with which objects it can collide, using [method set_collision_mask].
+ A contact is detected if object A is in any of the layers that object B scans, or object B is in any layer scanned by object A.
+ </description>
+ </method>
+ <method name="get_layer_mask" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Return the physics layer this area is in.
+ </description>
+ </method>
+ <method name="set_collision_mask_bit">
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <argument index="1" name="value" type="bool">
+ </argument>
+ <description>
+ Set/clear individual bits on the collision mask. This makes selecting the areas scanned easier.
+ </description>
+ </method>
+ <method name="get_collision_mask_bit" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <description>
+ Return an individual bit on the collision mask.
+ </description>
+ </method>
+ <method name="set_layer_mask_bit">
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <argument index="1" name="value" type="bool">
+ </argument>
+ <description>
+ Set/clear individual bits on the layer mask. This makes getting an area in/out of only one layer easier.
+ </description>
+ </method>
+ <method name="get_layer_mask_bit" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <description>
+ Return an individual bit on the layer mask.
+ </description>
+ </method>
+ <method name="set_enable_monitoring">
<argument index="0" name="enable" type="bool">
</argument>
<description>
+ Set whether this area can detect bodies/areas entering/exiting it.
</description>
</method>
- <method name="is_monitoring_enabled" qualifiers="const" >
+ <method name="is_monitoring_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
+ Return whether this area detects bodies/areas entering/exiting it.
+ </description>
+ </method>
+ <method name="set_monitorable">
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ Set whether this area can be detected by other, monitoring, areas. Only areas need to be marked as monitorable. Bodies are always so.
</description>
</method>
- <method name="get_overlapping_bodies" qualifiers="const" >
+ <method name="is_monitorable" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Set whether this area can be detected by other, monitoring, areas.
+ </description>
+ </method>
+ <method name="get_overlapping_bodies" qualifiers="const">
+ <return type="Array">
+ </return>
+ <description>
+ Return a list of the bodies ([PhysicsBody2D]) that are totally or partially inside this area.
+ </description>
+ </method>
+ <method name="get_overlapping_areas" qualifiers="const">
<return type="Array">
</return>
<description>
+ Return a list of the areas that are totally or partially inside this area.
+ </description>
+ </method>
+ <method name="overlaps_body" qualifiers="const">
+ <return type="PhysicsBody2D">
+ </return>
+ <argument index="0" name="body" type="Object">
+ </argument>
+ <description>
+ Return whether the body passed is totally or partially inside this area.
+ </description>
+ </method>
+ <method name="overlaps_area" qualifiers="const">
+ <return type="Area2D">
+ </return>
+ <argument index="0" name="area" type="Object">
+ </argument>
+ <description>
+ Return whether the area passed is totally or partially inside this area.
</description>
</method>
</methods>
@@ -3459,6 +3782,7 @@
<argument index="0" name="body" type="Object">
</argument>
<description>
+ This signal is triggered only once when a body enters this area. The only parameter passed is the body that entered this area.
</description>
</signal>
<signal name="body_enter_shape">
@@ -3471,12 +3795,34 @@
<argument index="3" name="area_shape" type="int">
</argument>
<description>
+ This signal triggers only once when a body enters this area. The first parameter is the body's [RID]. The second one is the body as an object. The third one is the index of the shape of the body that entered this area, and the fourth one is the index of the shape in this area that repored the entering.
+ </description>
+ </signal>
+ <signal name="area_enter">
+ <argument index="0" name="area" type="Object">
+ </argument>
+ <description>
+ This signal is triggered only once when an area enters this area. The only parameter passed is the area that entered this area.
+ </description>
+ </signal>
+ <signal name="area_enter_shape">
+ <argument index="0" name="area_id" type="int">
+ </argument>
+ <argument index="1" name="area" type="Object">
+ </argument>
+ <argument index="2" name="area_shape" type="int">
+ </argument>
+ <argument index="3" name="area_shape" type="int">
+ </argument>
+ <description>
+ This signal triggers only once when an area enters this area. The first parameter is the area's [RID]. The second one is the area as an object. The third one is the index of the shape entering this area, and the fourth one is the index of the shape in this area that reported the entering.
</description>
</signal>
<signal name="body_exit">
<argument index="0" name="body" type="Object">
</argument>
<description>
+ This signal is triggered only once when a body exits this area. The only parameter passed is the body that exited this area.
</description>
</signal>
<signal name="body_exit_shape">
@@ -3489,6 +3835,27 @@
<argument index="3" name="area_shape" type="int">
</argument>
<description>
+ This signal triggers only once when a body exits this area. The first parameter is the body's [RID]. The second one is the body as an object. The third one is the index of the shape exiting this area, and the fourth one is the index of the shape in this area that reported the exit.
+ </description>
+ </signal>
+ <signal name="area_exit">
+ <argument index="0" name="area" type="Object">
+ </argument>
+ <description>
+ This signal is triggered only once when an area exits this area. The only parameter passed is the area that exited this area.
+ </description>
+ </signal>
+ <signal name="area_exit_shape">
+ <argument index="0" name="area_id" type="int">
+ </argument>
+ <argument index="1" name="area" type="Object">
+ </argument>
+ <argument index="2" name="area_shape" type="int">
+ </argument>
+ <argument index="3" name="area_shape" type="int">
+ </argument>
+ <description>
+ This signal triggers only once when an area exits this area. The first parameter is the area's [RID]. The second one is the area as an object. The third one is the index of the shape entering this area, and the fourth one is the index of the shape in this area that reported the entering.
</description>
</signal>
</signals>
@@ -3503,46 +3870,49 @@
Generic array, contains several elements of any type, accessible by numerical index starting at 0. Arrays are always passed by reference.
</description>
<methods>
- <method name="append" >
+ <method name="append">
<argument index="0" name="value" type="var">
</argument>
<description>
+ Append an element at the end of the array (alias of [method push_back]).
</description>
</method>
- <method name="clear" >
+ <method name="clear">
<description>
Clear the array (resize to 0).
</description>
</method>
- <method name="empty" >
+ <method name="empty">
<return type="bool">
</return>
<description>
Return true if the array is empty (size==0).
</description>
</method>
- <method name="erase" >
+ <method name="erase">
<argument index="0" name="value" type="var">
</argument>
<description>
+ Remove the first occurence of a value from the array.
</description>
</method>
- <method name="find" >
+ <method name="find">
<return type="int">
</return>
<argument index="0" name="value" type="var">
</argument>
<description>
+ Searches the array for a value and returns its index or -1 if not found.
</description>
</method>
- <method name="hash" >
+ <method name="hash">
<return type="int">
</return>
<description>
Return a hashed integer value representing the array contents.
</description>
</method>
- <method name="insert" >
+ <method name="insert">
<argument index="0" name="pos" type="int">
</argument>
<argument index="1" name="value" type="var">
@@ -3551,93 +3921,131 @@
Insert a new element at a given position in the array. The position must be valid, or at the end of the array (pos==size()).
</description>
</method>
- <method name="invert" >
+ <method name="invert">
<description>
+ Reverse the order of the elements in the array (so first element will now be the last).
</description>
</method>
- <method name="push_back" >
+ <method name="is_shared">
+ <return type="bool">
+ </return>
+ <description>
+ Get whether this is a shared array instance.
+ </description>
+ </method>
+ <method name="pop_back">
+ <description>
+ </description>
+ </method>
+ <method name="pop_front">
+ <description>
+ </description>
+ </method>
+ <method name="push_back">
<argument index="0" name="value" type="var">
</argument>
<description>
Append an element at the end of the array.
</description>
</method>
- <method name="remove" >
+ <method name="push_front">
+ <argument index="0" name="value" type="var">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="remove">
<argument index="0" name="pos" type="int">
</argument>
<description>
Remove an element from the array by index.
</description>
</method>
- <method name="resize" >
+ <method name="resize">
<argument index="0" name="pos" type="int">
</argument>
<description>
Resize the array to contain a different number of elements. If the array size is smaller, elements are cleared, if bigger, new elements are Null.
</description>
</method>
- <method name="size" >
+ <method name="size">
<return type="int">
</return>
<description>
Return the amount of elements in the array.
</description>
</method>
- <method name="sort" >
+ <method name="sort">
<description>
+ Sort the array using natural order.
</description>
</method>
- <method name="sort_custom" >
+ <method name="sort_custom">
<argument index="0" name="obj" type="Object">
</argument>
<argument index="1" name="func" type="String">
</argument>
<description>
+ Sort the array using a custom method. The arguments are an object that holds the method and the name of such method. The custom method receives two arguments (a pair of elements from the array) and must return true if the first argument is less than the second, and return false otherwise.
</description>
</method>
- <method name="Array" >
+ <method name="Array">
+ <return type="Array">
+ </return>
<argument index="0" name="from" type="RawArray">
</argument>
<description>
Construct an array from a [RawArray].
</description>
</method>
- <method name="Array" >
+ <method name="Array">
+ <return type="Array">
+ </return>
<argument index="0" name="from" type="IntArray">
</argument>
<description>
Construct an array from a [RawArray].
</description>
</method>
- <method name="Array" >
+ <method name="Array">
+ <return type="Array">
+ </return>
<argument index="0" name="from" type="RealArray">
</argument>
<description>
Construct an array from a [RawArray].
</description>
</method>
- <method name="Array" >
+ <method name="Array">
+ <return type="Array">
+ </return>
<argument index="0" name="from" type="StringArray">
</argument>
<description>
Construct an array from a [RawArray].
</description>
</method>
- <method name="Array" >
+ <method name="Array">
+ <return type="Array">
+ </return>
<argument index="0" name="from" type="Vector2Array">
</argument>
<description>
Construct an array from a [RawArray].
</description>
</method>
- <method name="Array" >
+ <method name="Array">
+ <return type="Array">
+ </return>
<argument index="0" name="from" type="Vector3Array">
</argument>
<description>
Construct an array from a [RawArray].
</description>
</method>
- <method name="Array" >
+ <method name="Array">
+ <return type="Array">
+ </return>
<argument index="0" name="from" type="ColorArray">
</argument>
<description>
@@ -3654,37 +4062,37 @@
<description>
</description>
<methods>
- <method name="set_atlas" >
+ <method name="set_atlas">
<argument index="0" name="atlas" type="Texture">
</argument>
<description>
</description>
</method>
- <method name="get_atlas" qualifiers="const" >
+ <method name="get_atlas" qualifiers="const">
<return type="Texture">
</return>
<description>
</description>
</method>
- <method name="set_region" >
+ <method name="set_region">
<argument index="0" name="region" type="Rect2">
</argument>
<description>
</description>
</method>
- <method name="get_region" qualifiers="const" >
+ <method name="get_region" qualifiers="const">
<return type="Rect2">
</return>
<description>
</description>
</method>
- <method name="set_margin" >
+ <method name="set_margin">
<argument index="0" name="margin" type="Rect2">
</argument>
<description>
</description>
</method>
- <method name="get_margin" qualifiers="const" >
+ <method name="get_margin" qualifiers="const">
<return type="Rect2">
</return>
<description>
@@ -3699,10 +4107,10 @@
Server interface for low level audio access.
</brief_description>
<description>
- AudioServer is a low level server interface for audio access. It is"#10;"#9;in charge of creating sample data (playable audio) as well as it's"#10;"#9;playback via a voice interface.
+ AudioServer is a low level server interface for audio access. It is in charge of creating sample data (playable audio) as well as its playback via a voice interface.
</description>
<methods>
- <method name="sample_create" >
+ <method name="sample_create">
<return type="RID">
</return>
<argument index="0" name="format" type="int">
@@ -3712,39 +4120,37 @@
<argument index="2" name="length" type="int">
</argument>
<description>
- Create an audio sample, return a [RID] referencing"#10;"#9;"#9;"#9;it. The sample will be created with a given format"#10;"#9;"#9;"#9;(from the SAMPLE_FORMAT_* enum), a total length (in"#10;"#9;"#9;"#9;frames, not samples or bytes), in either stereo or"#10;"#9;"#9;"#9;mono.
+ Create an audio sample, return a [RID] referencing it. The sample will be created with a given format (from the SAMPLE_FORMAT_* enum), a total length (in frames, not samples or bytes), in either stereo or mono.
</description>
</method>
- <method name="sample_set_description" >
+ <method name="sample_set_description">
<argument index="0" name="sample" type="RID">
</argument>
<argument index="1" name="description" type="String">
</argument>
<description>
- Set the description of an audio sample. Mainly used"#10;"#9;"#9;"#9;for organization.
+ Set the description of an audio sample. Mainly used for organization.
</description>
</method>
- <method name="sample_get_description" qualifiers="const" >
+ <method name="sample_get_description" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="sample" type="RID">
</argument>
- <argument index="1" name="arg1" type="String">
- </argument>
<description>
- Return the description of an audio sample. Mainly"#10;"#9;"#9;"#9;used for organization.
+ Return the description of an audio sample. Mainly used for organization.
</description>
</method>
- <method name="sample_get_format" qualifiers="const" >
+ <method name="sample_get_format" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="sample" type="RID">
</argument>
<description>
- Return the format of the audio sample, in the form"#10;"#9;"#9;"#9;of the SAMPLE_FORMAT_* enum.
+ Return the format of the audio sample, in the form of the SAMPLE_FORMAT_* enum.
</description>
</method>
- <method name="sample_is_stereo" qualifiers="const" >
+ <method name="sample_is_stereo" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="sample" type="RID">
@@ -3753,43 +4159,43 @@
Return wether the sample is stereo (2 channels)
</description>
</method>
- <method name="sample_get_length" qualifiers="const" >
+ <method name="sample_get_length" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="sample" type="RID">
</argument>
<description>
- Return the length in frames of the audio sample (not"#10;"#9;"#9;"#9;samples or bytes).
+ Return the length in frames of the audio sample (not samples or bytes).
</description>
</method>
- <method name="sample_set_signed_data" >
+ <method name="sample_set_signed_data">
<argument index="0" name="sample" type="RID">
</argument>
<argument index="1" name="data" type="RealArray">
</argument>
<description>
- Set the sample data for a given sample as an array"#10;"#9;"#9;"#9;of floats. The length must be equal to the sample"#10;"#9;"#9;"#9;lenght or an error will be produced.
+ Set the sample data for a given sample as an array of floats. The length must be equal to the sample lenght or an error will be produced.
</description>
</method>
- <method name="sample_set_data" >
+ <method name="sample_set_data">
<argument index="0" name="sample" type="RID">
</argument>
- <argument index="1" name="arg1" type="RawArray">
+ <argument index="1" name="data" type="RawArray">
</argument>
<description>
- Set the sample data for a given sample as an array"#10;"#9;"#9;"#9;of bytes. The length must be equal to the sample"#10;"#9;"#9;"#9;lenght expected in bytes or an error will be produced.
+ Set the sample data for a given sample as an array of bytes. The length must be equal to the sample lenght expected in bytes or an error will be produced.
</description>
</method>
- <method name="sample_get_data" qualifiers="const" >
+ <method name="sample_get_data" qualifiers="const">
<return type="RawArray">
</return>
<argument index="0" name="sample" type="RID">
</argument>
<description>
- Return the sample data as an array of bytes. The"#10;"#9;"#9;"#9;length will be the expected length in bytes.
+ Return the sample data as an array of bytes. The length will be the expected length in bytes.
</description>
</method>
- <method name="sample_set_mix_rate" >
+ <method name="sample_set_mix_rate">
<argument index="0" name="sample" type="RID">
</argument>
<argument index="1" name="mix_rate" type="int">
@@ -3798,7 +4204,7 @@
Change the default mix rate of a given sample.
</description>
</method>
- <method name="sample_get_mix_rate" qualifiers="const" >
+ <method name="sample_get_mix_rate" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="sample" type="RID">
@@ -3807,86 +4213,86 @@
Return the mix rate of the given sample.
</description>
</method>
- <method name="sample_set_loop_format" >
+ <method name="sample_set_loop_format">
<argument index="0" name="sample" type="RID">
</argument>
<argument index="1" name="loop_format" type="int">
</argument>
<description>
- Set the loop format for a sample from the"#10;"#9;"#9;"#9;SAMPLE_LOOP_* enum. As a warning, Ping Pong loops"#10;"#9;"#9;"#9;may not be available on some hardware-mixing"#10;"#9;"#9;"#9;platforms.
+ Set the loop format for a sample from the SAMPLE_LOOP_* enum. As a warning, Ping Pong loops may not be available on some hardware-mixing platforms.
</description>
</method>
- <method name="sample_get_loop_format" qualifiers="const" >
+ <method name="sample_get_loop_format" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="sample" type="RID">
</argument>
<description>
- Return the loop format for a sample, as a value from"#10;"#9;"#9;"#9;the SAMPLE_LOOP_* enum.
+ Return the loop format for a sample, as a value from the SAMPLE_LOOP_* enum.
</description>
</method>
- <method name="sample_set_loop_begin" >
+ <method name="sample_set_loop_begin">
<argument index="0" name="sample" type="RID">
</argument>
<argument index="1" name="pos" type="int">
</argument>
<description>
- Set the initial loop point of a sample. Only has"#10;"#9;"#9;"#9;effect if sample loop is enabled. See [method sample_set_loop_format].
+ Set the initial loop point of a sample. Only has effect if sample loop is enabled. See [method sample_set_loop_format].
</description>
</method>
- <method name="sample_get_loop_begin" qualifiers="const" >
+ <method name="sample_get_loop_begin" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="sample" type="RID">
</argument>
<description>
- Return the initial loop point of a sample. Only has"#10;"#9;"#9;"#9;effect if sample loop is enabled. See [method sample_set_loop_format].
+ Return the initial loop point of a sample. Only has effect if sample loop is enabled. See [method sample_set_loop_format].
</description>
</method>
- <method name="sample_set_loop_end" >
+ <method name="sample_set_loop_end">
<argument index="0" name="sample" type="RID">
</argument>
<argument index="1" name="pos" type="int">
</argument>
<description>
- Set the final loop point of a sample. Only has"#10;"#9;"#9;"#9;effect if sample loop is enabled. See [method sample_set_loop_format].
+ Set the final loop point of a sample. Only has effect if sample loop is enabled. See [method sample_set_loop_format].
</description>
</method>
- <method name="sample_get_loop_end" qualifiers="const" >
+ <method name="sample_get_loop_end" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="sample" type="RID">
</argument>
<description>
- Return the final loop point of a sample. Only has"#10;"#9;"#9;"#9;effect if sample loop is enabled. See [method sample_set_loop_format].
+ Return the final loop point of a sample. Only has effect if sample loop is enabled. See [method sample_set_loop_format].
</description>
</method>
- <method name="voice_create" >
+ <method name="voice_create">
<return type="RID">
</return>
<description>
- Allocate a voice for playback. Voices are"#10;"#9;"#9;"#9;persistent. A voice can play a single sample at the"#10;"#9;"#9;"#9;same time. See [method sample_create].
+ Allocate a voice for playback. Voices are persistent. A voice can play a single sample at the same time. See [method sample_create].
</description>
</method>
- <method name="voice_play" >
+ <method name="voice_play">
<argument index="0" name="voice" type="RID">
</argument>
<argument index="1" name="sample" type="RID">
</argument>
<description>
- Start playback of a given voice using a given"#10;"#9;"#9;"#9;sample. If the voice was already playing it will be"#10;"#9;"#9;"#9;restarted.
+ Start playback of a given voice using a given sample. If the voice was already playing it will be restarted.
</description>
</method>
- <method name="voice_set_volume" >
+ <method name="voice_set_volume">
<argument index="0" name="voice" type="RID">
</argument>
<argument index="1" name="volume" type="float">
</argument>
<description>
- Change the volume of a currently playing voice."#10;"#9;"#9;"#9;Volume is expressed as linear gain where 0.0 is mute"#10;"#9;"#9;"#9;and 1.0 is default.
+ Change the volume of a currently playing voice. Volume is expressed as linear gain where 0.0 is mute and 1.0 is default.
</description>
</method>
- <method name="voice_set_pan" >
+ <method name="voice_set_pan">
<argument index="0" name="voice" type="RID">
</argument>
<argument index="1" name="pan" type="float">
@@ -3896,10 +4302,10 @@
<argument index="3" name="height" type="float" default="0">
</argument>
<description>
- Change the pan of a currently playing voice and,"#10;"#9;"#9;"#9;optionally, the depth and height for a positional/3D"#10;"#9;"#9;"#9;sound. Panning values are expressed within the -1 to"#10;"#9;"#9;"#9;+1 range.
+ Change the pan of a currently playing voice and, optionally, the depth and height for a positional/3D sound. Panning values are expressed within the -1 to +1 range.
</description>
</method>
- <method name="voice_set_filter" >
+ <method name="voice_set_filter">
<argument index="0" name="voice" type="RID">
</argument>
<argument index="1" name="type" type="int">
@@ -3911,19 +4317,19 @@
<argument index="4" name="gain" type="float" default="0">
</argument>
<description>
- Set a resonant filter post processing for the voice."#10;"#9;"#9;"#9;Filter type is a value from the FILTER_* enum.
+ Set a resonant filter post processing for the voice. Filter type is a value from the FILTER_* enum.
</description>
</method>
- <method name="voice_set_chorus" >
+ <method name="voice_set_chorus">
<argument index="0" name="voice" type="RID">
</argument>
<argument index="1" name="chorus" type="float">
</argument>
<description>
- Set chorus send post processing for the voice (from"#10;"#9;"#9;"#9;0 to 1).
+ Set chorus send post processing for the voice (from 0 to 1).
</description>
</method>
- <method name="voice_set_reverb" >
+ <method name="voice_set_reverb">
<argument index="0" name="voice" type="RID">
</argument>
<argument index="1" name="room" type="int">
@@ -3931,28 +4337,28 @@
<argument index="2" name="reverb" type="float">
</argument>
<description>
- Set the reverb send post processing for the voice (from"#10;"#9;"#9;"#9;0 to 1) and the reverb type, from the REVERB_* enum.
+ Set the reverb send post processing for the voice (from 0 to 1) and the reverb type, from the REVERB_* enum.
</description>
</method>
- <method name="voice_set_mix_rate" >
+ <method name="voice_set_mix_rate">
<argument index="0" name="voice" type="RID">
</argument>
<argument index="1" name="rate" type="int">
</argument>
<description>
- Set a different playback mix rate for the given"#10;"#9;"#9;"#9;voice.
+ Set a different playback mix rate for the given voice.
</description>
</method>
- <method name="voice_set_positional" >
+ <method name="voice_set_positional">
<argument index="0" name="voice" type="RID">
</argument>
<argument index="1" name="enabled" type="bool">
</argument>
<description>
- Set wether a given voice is positional. This is only"#10;"#9;"#9;"#9;interpreted as a hint and used for backends that may"#10;"#9;"#9;"#9;support binaural encoding.
+ Set wether a given voice is positional. This is only interpreted as a hint and used for backends that may support binaural encoding.
</description>
</method>
- <method name="voice_get_volume" qualifiers="const" >
+ <method name="voice_get_volume" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="voice" type="RID">
@@ -3961,88 +4367,88 @@
Return the current volume for a given voice.
</description>
</method>
- <method name="voice_get_pan" qualifiers="const" >
+ <method name="voice_get_pan" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="voice" type="RID">
</argument>
<description>
- Return the current pan for a given voice (-1 to +1"#10;"#9;"#9;"#9;range).
+ Return the current pan for a given voice (-1 to +1 range).
</description>
</method>
- <method name="voice_get_pan_height" qualifiers="const" >
+ <method name="voice_get_pan_height" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="voice" type="RID">
</argument>
<description>
- Return the current pan height for a given voice (-1 to +1"#10;"#9;"#9;"#9;range).
+ Return the current pan height for a given voice (-1 to +1 range).
</description>
</method>
- <method name="voice_get_pan_depth" qualifiers="const" >
+ <method name="voice_get_pan_depth" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="voice" type="RID">
</argument>
<description>
- Return the current pan depth for a given voice (-1 to +1"#10;"#9;"#9;"#9;range).
+ Return the current pan depth for a given voice (-1 to +1 range).
</description>
</method>
- <method name="voice_get_filter_type" qualifiers="const" >
+ <method name="voice_get_filter_type" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="voice" type="RID">
</argument>
<description>
- Return the current selected filter type for a given"#10;"#9;"#9;"#9;voice, from the FILTER_* enum.
+ Return the current selected filter type for a given voice, from the FILTER_* enum.
</description>
</method>
- <method name="voice_get_filter_cutoff" qualifiers="const" >
+ <method name="voice_get_filter_cutoff" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="voice" type="RID">
</argument>
<description>
- Return the current filter cutoff (in hz) for a given"#10;"#9;"#9;"#9;voice.
+ Return the current filter cutoff (in hz) for a given voice.
</description>
</method>
- <method name="voice_get_filter_resonance" qualifiers="const" >
+ <method name="voice_get_filter_resonance" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="voice" type="RID">
</argument>
<description>
- Return the current filter resonance for a given"#10;"#9;"#9;"#9;voice.
+ Return the current filter resonance for a given voice.
</description>
</method>
- <method name="voice_get_chorus" qualifiers="const" >
+ <method name="voice_get_chorus" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="voice" type="RID">
</argument>
<description>
- Return the current chorus send for a given"#10;"#9;"#9;"#9;voice (0 to 1).
+ Return the current chorus send for a given voice (0 to 1).
</description>
</method>
- <method name="voice_get_reverb_type" qualifiers="const" >
+ <method name="voice_get_reverb_type" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="voice" type="RID">
</argument>
<description>
- Return the current reverb type for a given voice"#10;"#9;"#9;"#9;from the REVERB_* enum.
+ Return the current reverb type for a given voice from the REVERB_* enum.
</description>
</method>
- <method name="voice_get_reverb" qualifiers="const" >
+ <method name="voice_get_reverb" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="voice" type="RID">
</argument>
<description>
- Return the current reverb send for a given voice"#10;"#9;"#9;"#9;(0 to 1).
+ Return the current reverb send for a given voice (0 to 1).
</description>
</method>
- <method name="voice_get_mix_rate" qualifiers="const" >
+ <method name="voice_get_mix_rate" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="voice" type="RID">
@@ -4051,62 +4457,62 @@
Return the current mix rate for a given voice.
</description>
</method>
- <method name="voice_is_positional" qualifiers="const" >
+ <method name="voice_is_positional" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="voice" type="RID">
</argument>
<description>
- Return wether the current voice is positional. See"#10;"#9;"#9;"#9;[method voice_set_positional].
+ Return wether the current voice is positional. See [method voice_set_positional].
</description>
</method>
- <method name="voice_stop" >
+ <method name="voice_stop">
<argument index="0" name="voice" type="RID">
</argument>
<description>
Stop a given voice.
</description>
</method>
- <method name="free" >
+ <method name="free_rid">
<argument index="0" name="rid" type="RID">
</argument>
<description>
Free a [RID] resource.
</description>
</method>
- <method name="set_stream_global_volume_scale" >
+ <method name="set_stream_global_volume_scale">
<argument index="0" name="scale" type="float">
</argument>
<description>
Set global scale for stream playback. Default is 1.0.
</description>
</method>
- <method name="get_stream_global_volume_scale" qualifiers="const" >
+ <method name="get_stream_global_volume_scale" qualifiers="const">
<return type="float">
</return>
<description>
Return the global scale for stream playback.
</description>
</method>
- <method name="set_fx_global_volume_scale" >
+ <method name="set_fx_global_volume_scale">
<argument index="0" name="scale" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_fx_global_volume_scale" qualifiers="const" >
+ <method name="get_fx_global_volume_scale" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_event_voice_global_volume_scale" >
+ <method name="set_event_voice_global_volume_scale">
<argument index="0" name="scale" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_event_voice_global_volume_scale" qualifiers="const" >
+ <method name="get_event_voice_global_volume_scale" qualifiers="const">
<return type="float">
</return>
<description>
@@ -4133,7 +4539,7 @@
Sample loops in a bidirectional way.
</constant>
<constant name="FILTER_NONE" value="0">
- Filter is disable.
+ Filter is disabled.
</constant>
<constant name="FILTER_LOWPASS" value="1">
Filter is a resonant lowpass.
@@ -4145,7 +4551,7 @@
Filter is a resonant highpass.
</constant>
<constant name="FILTER_NOTCH" value="4">
- Filter is a notch.
+ Filter is a notch (band reject).
</constant>
<constant name="FILTER_BANDLIMIT" value="6">
Filter is a bandlimit (resonance used as highpass).
@@ -4179,241 +4585,179 @@
Base class for audio streams.
</brief_description>
<description>
- Base class for audio streams. Audio streams are used for music"#10;"#9;playback, or other types of streamed sounds that don't fit or"#10;"#9;requiere more flexibility than a [Sample].
+ Base class for audio streams. Audio streams are used for music playback, or other types of streamed sounds that don't fit or requiere more flexibility than a [Sample].
+ </description>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
+<class name="AudioStreamMPC" inherits="AudioStream" category="Core">
+ <brief_description>
+ MusePack audio stream driver.
+ </brief_description>
+ <description>
+ MusePack audio stream driver.
+ </description>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
+<class name="AudioStreamOGGVorbis" inherits="AudioStream" category="Core">
+ <brief_description>
+ OGG Vorbis audio stream driver.
+ </brief_description>
+ <description>
+ OGG Vorbis audio stream driver.
+ </description>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
+<class name="AudioStreamOpus" inherits="AudioStream" category="Core">
+ <brief_description>
+ Opus Codec audio stream driver.
+ </brief_description>
+ <description>
+ Opus Codec audio stream driver.
</description>
<methods>
- <method name="play" >
+ </methods>
+ <constants>
+ </constants>
+</class>
+<class name="AudioStreamPlayback" inherits="Reference" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="play">
+ <argument index="0" name="from_pos_sec" type="float" default="0">
+ </argument>
<description>
- Start playback of an audio stream.
</description>
</method>
- <method name="stop" >
+ <method name="stop">
<description>
- Stop playback of an audio stream.
</description>
</method>
- <method name="is_playing" qualifiers="const" >
+ <method name="is_playing" qualifiers="const">
<return type="bool">
</return>
<description>
- Return wether the audio stream is currently playing.
</description>
</method>
- <method name="set_loop" >
+ <method name="set_loop">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
- Set the loop hint for the audio stream playback. if"#10;"#9;"#9;"#9;true, audio stream will attempt to loop (restart)"#10;"#9;"#9;"#9;when finished.
</description>
</method>
- <method name="has_loop" qualifiers="const" >
+ <method name="has_loop" qualifiers="const">
<return type="bool">
</return>
<description>
- Return wether the audio stream loops. See [method set_loop]
- </description>
- </method>
- <method name="get_stream_name" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- Return the name of the audio stream. Often the song"#10;"#9;"#9;"#9;title when the stream is music.
</description>
</method>
- <method name="get_loop_count" qualifiers="const" >
+ <method name="get_loop_count" qualifiers="const">
<return type="int">
</return>
<description>
- Return the amount of times that the stream has"#10;"#9;"#9;"#9;looped (if loop is supported).
</description>
</method>
- <method name="seek_pos" >
+ <method name="seek_pos">
<argument index="0" name="pos" type="float">
</argument>
<description>
- Seek to a certain position (in seconds) in an audio"#10;"#9;"#9;"#9;stream.
</description>
</method>
- <method name="get_pos" qualifiers="const" >
+ <method name="get_pos" qualifiers="const">
<return type="float">
</return>
<description>
- Return the current playing position (in seconds) of the audio"#10;"#9;"#9;"#9;stream (if supported). Since this value is updated"#10;"#9;"#9;"#9;internally, it may not be exact or updated"#10;"#9;"#9;"#9;continuosly. Accuracy depends on the sample buffer"#10;"#9;"#9;"#9;size of the audio driver.
</description>
</method>
- <method name="get_length" qualifiers="const" >
+ <method name="get_length" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="get_update_mode" qualifiers="const" >
+ <method name="get_channels" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_mix_rate" qualifiers="const">
<return type="int">
</return>
<description>
- Return the type of update that the stream uses. Some"#10;"#9;"#9;"#9;types of stream may need manual polling.
</description>
</method>
- <method name="update" >
+ <method name="get_minimum_buffer_size" qualifiers="const">
+ <return type="int">
+ </return>
<description>
- Manually poll the audio stream (if it is requested"#10;"#9;"#9;"#9;to).
</description>
</method>
</methods>
<constants>
- <constant name="UPDATE_NONE" value="0">
- Does not need update, or manual polling.
- </constant>
- <constant name="UPDATE_IDLE" value="1">
- Stream is updated on the main thread, when idle.
- </constant>
- <constant name="UPDATE_THREAD" value="2">
- Stream is updated on its own thread.
- </constant>
</constants>
</class>
-<class name="AudioStreamGibberish" inherits="AudioStream" category="Core">
+<class name="AudioStreamSpeex" inherits="AudioStream" category="Core">
<brief_description>
- Simple gibberish speech stream playback.
+ Speex audio stream driver.
</brief_description>
<description>
- AudioStream used for gibberish playback. It plays randomized phonemes, which can be used to accompany text dialogs.
+ Speex audio stream driver. Speex is very useful for compressed speech. It allows loading a very large amount of speech in memory at little IO/latency cost.
</description>
<methods>
- <method name="set_phonemes" >
- <argument index="0" name="phonemes" type="Object">
- </argument>
- <description>
- Set the phoneme library.
- </description>
- </method>
- <method name="get_phonemes" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- Return the phoneme library.
- </description>
- </method>
- <method name="set_pitch_scale" >
- <argument index="0" name="pitch_scale" type="float">
- </argument>
- <description>
- Set pitch scale for the speech. Animating this value holds amusing results.
- </description>
- </method>
- <method name="get_pitch_scale" qualifiers="const" >
- <return type="float">
- </return>
- <description>
- Return the pitch scale.
- </description>
- </method>
- <method name="set_pitch_random_scale" >
- <argument index="0" name="pitch_random_scale" type="float">
- </argument>
- <description>
- Set the random scaling for the pitch.
- </description>
- </method>
- <method name="get_pitch_random_scale" qualifiers="const" >
- <return type="float">
- </return>
- <description>
- Return the pitch random scaling.
- </description>
- </method>
- <method name="set_xfade_time" >
- <argument index="0" name="sec" type="float">
- </argument>
- <description>
- Set the cross-fade time between random phonemes.
- </description>
- </method>
- <method name="get_xfade_time" qualifiers="const" >
- <return type="float">
- </return>
- <description>
- Return the cross-fade time between random phonemes.
- </description>
- </method>
</methods>
<constants>
</constants>
</class>
-<class name="AudioStreamMPC" inherits="AudioStreamResampled" category="Core">
+<class name="BackBufferCopy" inherits="Node2D" category="Core">
<brief_description>
- MusePack audio stream driver.
</brief_description>
<description>
- MusePack audio stream driver.
</description>
<methods>
- <method name="set_file" >
- <argument index="0" name="name" type="String">
+ <method name="set_rect">
+ <argument index="0" name="rect" type="Rect2">
</argument>
<description>
- Set the file to be played.
</description>
</method>
- <method name="get_file" qualifiers="const" >
- <return type="String">
+ <method name="get_rect" qualifiers="const">
+ <return type="Rect2">
</return>
<description>
- Return the file being played.
</description>
</method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="AudioStreamOGGVorbis" inherits="AudioStreamResampled" category="Core">
- <brief_description>
- OGG Vorbis audio stream driver.
- </brief_description>
- <description>
- OGG Vorbis audio stream driver.
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="AudioStreamResampled" inherits="AudioStream" category="Core">
- <brief_description>
- Base class for resampled audio streams.
- </brief_description>
- <description>
- Base class for resampled audio streams.
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="AudioStreamSpeex" inherits="AudioStreamResampled" category="Core">
- <brief_description>
- Speex audio stream driver.
- </brief_description>
- <description>
- Speex audio stream driver. Speex is very useful for compressed speech. It allows loading a very large amount of speech in memory at little IO/latency cost.
- </description>
- <methods>
- <method name="set_file" >
- <argument index="0" name="file" type="String">
+ <method name="set_copy_mode">
+ <argument index="0" name="copy_mode" type="int">
</argument>
<description>
- Set the speech file (which is loaded to memory).
</description>
</method>
- <method name="get_file" qualifiers="const" >
- <return type="String">
+ <method name="get_copy_mode" qualifiers="const">
+ <return type="int">
</return>
<description>
- Return the speech file.
</description>
</method>
</methods>
<constants>
+ <constant name="COPY_MODE_DISABLED" value="0">
+ </constant>
+ <constant name="COPY_MODE_RECT" value="1">
+ </constant>
+ <constant name="COPY_MODE_VIEWPORT" value="2">
+ </constant>
</constants>
</class>
<class name="BakedLight" inherits="Resource" category="Core">
@@ -4422,55 +4766,55 @@
<description>
</description>
<methods>
- <method name="set_mode" >
+ <method name="set_mode">
<argument index="0" name="mode" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_mode" qualifiers="const" >
+ <method name="get_mode" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_octree" >
+ <method name="set_octree">
<argument index="0" name="octree" type="RawArray">
</argument>
<description>
</description>
</method>
- <method name="get_octree" qualifiers="const" >
+ <method name="get_octree" qualifiers="const">
<return type="RawArray">
</return>
<description>
</description>
</method>
- <method name="set_light" >
+ <method name="set_light">
<argument index="0" name="light" type="RawArray">
</argument>
<description>
</description>
</method>
- <method name="get_light" qualifiers="const" >
+ <method name="get_light" qualifiers="const">
<return type="RawArray">
</return>
<description>
</description>
</method>
- <method name="set_sampler_octree" >
+ <method name="set_sampler_octree">
<argument index="0" name="sampler_octree" type="IntArray">
</argument>
<description>
</description>
</method>
- <method name="get_sampler_octree" qualifiers="const" >
+ <method name="get_sampler_octree" qualifiers="const">
<return type="IntArray">
</return>
<description>
</description>
</method>
- <method name="add_lightmap" >
+ <method name="add_lightmap">
<argument index="0" name="texture" type="Texture">
</argument>
<argument index="1" name="gen_size" type="Vector2">
@@ -4478,197 +4822,197 @@
<description>
</description>
</method>
- <method name="erase_lightmap" >
+ <method name="erase_lightmap">
<argument index="0" name="id" type="int">
</argument>
<description>
</description>
</method>
- <method name="clear_lightmaps" >
+ <method name="clear_lightmaps">
<description>
</description>
</method>
- <method name="set_cell_subdivision" >
+ <method name="set_cell_subdivision">
<argument index="0" name="cell_subdivision" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_cell_subdivision" qualifiers="const" >
+ <method name="get_cell_subdivision" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_initial_lattice_subdiv" >
+ <method name="set_initial_lattice_subdiv">
<argument index="0" name="cell_subdivision" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_initial_lattice_subdiv" qualifiers="const" >
+ <method name="get_initial_lattice_subdiv" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_plot_size" >
+ <method name="set_plot_size">
<argument index="0" name="plot_size" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_plot_size" qualifiers="const" >
+ <method name="get_plot_size" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_bounces" >
+ <method name="set_bounces">
<argument index="0" name="bounces" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_bounces" qualifiers="const" >
+ <method name="get_bounces" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_cell_extra_margin" >
+ <method name="set_cell_extra_margin">
<argument index="0" name="cell_extra_margin" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_cell_extra_margin" qualifiers="const" >
+ <method name="get_cell_extra_margin" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_edge_damp" >
+ <method name="set_edge_damp">
<argument index="0" name="edge_damp" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_edge_damp" qualifiers="const" >
+ <method name="get_edge_damp" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_normal_damp" >
+ <method name="set_normal_damp">
<argument index="0" name="normal_damp" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_normal_damp" qualifiers="const" >
+ <method name="get_normal_damp" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_tint" >
+ <method name="set_tint">
<argument index="0" name="tint" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_tint" qualifiers="const" >
+ <method name="get_tint" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_saturation" >
+ <method name="set_saturation">
<argument index="0" name="saturation" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_saturation" qualifiers="const" >
+ <method name="get_saturation" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_ao_radius" >
+ <method name="set_ao_radius">
<argument index="0" name="ao_radius" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_ao_radius" qualifiers="const" >
+ <method name="get_ao_radius" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_ao_strength" >
+ <method name="set_ao_strength">
<argument index="0" name="ao_strength" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_ao_strength" qualifiers="const" >
+ <method name="get_ao_strength" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_format" >
+ <method name="set_format">
<argument index="0" name="format" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_format" qualifiers="const" >
+ <method name="get_format" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_transfer_lightmaps_only_to_uv2" >
+ <method name="set_transfer_lightmaps_only_to_uv2">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="get_transfer_lightmaps_only_to_uv2" qualifiers="const" >
+ <method name="get_transfer_lightmaps_only_to_uv2" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_energy_multiplier" >
+ <method name="set_energy_multiplier">
<argument index="0" name="energy_multiplier" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_energy_multiplier" qualifiers="const" >
+ <method name="get_energy_multiplier" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_gamma_adjust" >
+ <method name="set_gamma_adjust">
<argument index="0" name="gamma_adjust" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_gamma_adjust" qualifiers="const" >
+ <method name="get_gamma_adjust" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_bake_flag" >
+ <method name="set_bake_flag">
<argument index="0" name="flag" type="int">
</argument>
<argument index="1" name="enabled" type="bool">
@@ -4676,7 +5020,7 @@
<description>
</description>
</method>
- <method name="get_bake_flag" qualifiers="const" >
+ <method name="get_bake_flag" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="flag" type="int">
@@ -4708,19 +5052,19 @@
<description>
</description>
<methods>
- <method name="set_baked_light" >
+ <method name="set_baked_light">
<argument index="0" name="baked_light" type="Object">
</argument>
<description>
</description>
</method>
- <method name="get_baked_light" qualifiers="const" >
+ <method name="get_baked_light" qualifiers="const">
<return type="Object">
</return>
<description>
</description>
</method>
- <method name="get_baked_light_instance" qualifiers="const" >
+ <method name="get_baked_light_instance" qualifiers="const">
<return type="RID">
</return>
<description>
@@ -4742,7 +5086,7 @@
<description>
</description>
<methods>
- <method name="set_param" >
+ <method name="set_param">
<argument index="0" name="param" type="int">
</argument>
<argument index="1" name="value" type="float">
@@ -4750,7 +5094,7 @@
<description>
</description>
</method>
- <method name="get_param" qualifiers="const" >
+ <method name="get_param" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="param" type="int">
@@ -4758,13 +5102,13 @@
<description>
</description>
</method>
- <method name="set_resolution" >
+ <method name="set_resolution">
<argument index="0" name="resolution" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_resolution" qualifiers="const" >
+ <method name="get_resolution" qualifiers="const">
<return type="int">
</return>
<description>
@@ -4792,69 +5136,79 @@
BaseButton is the abstract base class for buttons, so it shouldn't be used directly (It doesnt display anything). Other types of buttons inherit from it.
</description>
<methods>
- <method name="set_pressed" >
+ <method name="_pressed" qualifiers="virtual">
+ <description>
+ </description>
+ </method>
+ <method name="_toggled" qualifiers="virtual">
+ <argument index="0" name="pressed" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_pressed">
<argument index="0" name="pressed" type="bool">
</argument>
<description>
Set the button to pressed state (only if toggle_mode is active).
</description>
</method>
- <method name="is_pressed" qualifiers="const" >
+ <method name="is_pressed" qualifiers="const">
<return type="bool">
</return>
<description>
- Return when the button is pressed (only if toggle_mode is active).
+ If toggle_mode is active, return whether the button is toggled. If toggle_mode is not active, return whether the button is pressed down.
</description>
</method>
- <method name="is_hovered" qualifiers="const" >
+ <method name="is_hovered" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_toggle_mode" >
+ <method name="set_toggle_mode">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
Set the button toggle_mode property. Toggle mode makes the button flip state between pressed and unpressed each time its area is clicked.
</description>
</method>
- <method name="is_toggle_mode" qualifiers="const" >
+ <method name="is_toggle_mode" qualifiers="const">
<return type="bool">
</return>
<description>
Return the toggle_mode property (see [method set_toggle_mode]).
</description>
</method>
- <method name="set_disabled" >
+ <method name="set_disabled">
<argument index="0" name="disabled" type="bool">
</argument>
<description>
- Set the button into disabled state. When a button is disabled, it can"apos;t be clicked or toggled.
+ Set the button into disabled state. When a button is disabled, it can't be clicked or toggled.
</description>
</method>
- <method name="is_disabled" qualifiers="const" >
+ <method name="is_disabled" qualifiers="const">
<return type="bool">
</return>
<description>
Return wether the button is in disabled state (see [method set_disabled]).
</description>
</method>
- <method name="set_click_on_press" >
+ <method name="set_click_on_press">
<argument index="0" name="enable" type="bool">
</argument>
<description>
Set the button click_on_press mode. This mode generates click events when a mousebutton or key is just pressed (by default events are generated when the button/keys are released and both press and release occur in the visual area of the Button).
</description>
</method>
- <method name="get_click_on_press" qualifiers="const" >
+ <method name="get_click_on_press" qualifiers="const">
<return type="bool">
</return>
<description>
Return the state of the click_on_press property (see [method set_click_on_press]).
</description>
</method>
- <method name="get_draw_mode" qualifiers="const" >
+ <method name="get_draw_mode" qualifiers="const">
<return type="int">
</return>
<description>
@@ -4897,19 +5251,19 @@
<description>
</description>
<methods>
- <method name="create" >
+ <method name="create">
<argument index="0" name="size" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="create_from_image_alpha" >
+ <method name="create_from_image_alpha">
<argument index="0" name="image" type="Image">
</argument>
<description>
</description>
</method>
- <method name="set_bit" >
+ <method name="set_bit">
<argument index="0" name="pos" type="Vector2">
</argument>
<argument index="1" name="bit" type="bool">
@@ -4917,7 +5271,7 @@
<description>
</description>
</method>
- <method name="get_bit" qualifiers="const" >
+ <method name="get_bit" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="pos" type="Vector2">
@@ -4925,7 +5279,7 @@
<description>
</description>
</method>
- <method name="set_bit_rect" >
+ <method name="set_bit_rect">
<argument index="0" name="p_rect" type="Rect2">
</argument>
<argument index="1" name="bit" type="bool">
@@ -4933,13 +5287,13 @@
<description>
</description>
</method>
- <method name="get_true_bit_count" qualifiers="const" >
+ <method name="get_true_bit_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_size" qualifiers="const" >
+ <method name="get_size" qualifiers="const">
<return type="Vector2">
</return>
<description>
@@ -4967,8 +5321,26 @@
Base class for Box containers. It arranges children controls vertically or horizontally, and rearranges them automatically when their minimum size changes.
</description>
<methods>
+ <method name="get_alignment" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_alignment">
+ <argument index="0" name="alignment" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
+ <constant name="ALIGN_BEGIN" value="0">
+ </constant>
+ <constant name="ALIGN_CENTER" value="1">
+ </constant>
+ <constant name="ALIGN_END" value="2">
+ </constant>
</constants>
</class>
<class name="BoxShape" inherits="Shape" category="Core">
@@ -4979,14 +5351,14 @@
Box shape resource, which can be set into a [PhysicsBody] or area.
</description>
<methods>
- <method name="set_extents" >
+ <method name="set_extents">
<argument index="0" name="extents" type="Vector3">
</argument>
<description>
Set the half extents for the shape.
</description>
</method>
- <method name="get_extents" qualifiers="const" >
+ <method name="get_extents" qualifiers="const">
<return type="Vector3">
</return>
<description>
@@ -5005,66 +5377,66 @@
Button is just the standard themed button: [image src="images/button_example.png"/] It can contain text and an icon, and will display them according to the current [Theme].
</description>
<methods>
- <method name="set_text" >
+ <method name="set_text">
<argument index="0" name="text" type="String">
</argument>
<description>
Set the button text, which will be displayed inside the button area.
</description>
</method>
- <method name="get_text" qualifiers="const" >
+ <method name="get_text" qualifiers="const">
<return type="String">
</return>
<description>
Return the button text.
</description>
</method>
- <method name="set_button_icon" >
+ <method name="set_button_icon">
<argument index="0" name="texture" type="Texture">
</argument>
<description>
</description>
</method>
- <method name="get_button_icon" qualifiers="const" >
+ <method name="get_button_icon" qualifiers="const">
<return type="Texture">
</return>
<description>
</description>
</method>
- <method name="set_flat" >
+ <method name="set_flat">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
- Set the [i]flat[/i] property of a Button. Flat buttons don"apos;t display decoration unless hoevered or pressed.
+ Set the [i]flat[/i] property of a Button. Flat buttons don't display decoration unless hoevered or pressed.
</description>
</method>
- <method name="set_clip_text" >
+ <method name="set_clip_text">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
Set the [i]clip_text[/i] property of a Button. When this property is enabled, text that is too large to fit the button is clipped, when disabled (default) the Button will always be wide enough to hold the text.
</description>
</method>
- <method name="get_clip_text" qualifiers="const" >
+ <method name="get_clip_text" qualifiers="const">
<return type="bool">
</return>
<description>
Return the state of the [i]clip_text[/i] property (see [method set_clip_text])
</description>
</method>
- <method name="set_text_align" >
+ <method name="set_text_align">
<argument index="0" name="align" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_text_align" qualifiers="const" >
+ <method name="get_text_align" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="is_flat" qualifiers="const" >
+ <method name="is_flat" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -5107,14 +5479,14 @@
Array of Buttons. A Button array is useful to have an array of buttons laid out vertically or horizontally. Only one can be selected. This is useful for joypad based interfaces and option menus.
</description>
<methods>
- <method name="add_button" >
+ <method name="add_button">
<argument index="0" name="text" type="String">
</argument>
<description>
Add a new button.
</description>
</method>
- <method name="add_icon_button" >
+ <method name="add_icon_button">
<argument index="0" name="icon" type="Object">
</argument>
<argument index="1" name="text" type="String" default="&quot;&quot;">
@@ -5122,7 +5494,7 @@
<description>
</description>
</method>
- <method name="set_button_text" >
+ <method name="set_button_text">
<argument index="0" name="button" type="int">
</argument>
<argument index="1" name="text" type="String">
@@ -5130,7 +5502,7 @@
<description>
</description>
</method>
- <method name="set_button_icon" >
+ <method name="set_button_icon">
<argument index="0" name="button" type="int">
</argument>
<argument index="1" name="icon" type="Object">
@@ -5139,7 +5511,7 @@
Set the icon of an existing button.
</description>
</method>
- <method name="get_button_text" qualifiers="const" >
+ <method name="get_button_text" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="button" type="int">
@@ -5148,7 +5520,7 @@
Return the text of an existing button.
</description>
</method>
- <method name="get_button_icon" qualifiers="const" >
+ <method name="get_button_icon" qualifiers="const">
<return type="Object">
</return>
<argument index="0" name="button" type="int">
@@ -5157,42 +5529,42 @@
Return the icon of an existing button.
</description>
</method>
- <method name="get_button_count" qualifiers="const" >
+ <method name="get_button_count" qualifiers="const">
<return type="int">
</return>
<description>
Return the amount of buttons in the array.
</description>
</method>
- <method name="get_selected" qualifiers="const" >
+ <method name="get_selected" qualifiers="const">
<return type="int">
</return>
<description>
Return the currently selected button in the array.
</description>
</method>
- <method name="get_hovered" qualifiers="const" >
+ <method name="get_hovered" qualifiers="const">
<return type="int">
</return>
<description>
Return the currently hovered button in the array.
</description>
</method>
- <method name="set_selected" >
+ <method name="set_selected">
<argument index="0" name="button" type="int">
</argument>
<description>
Sekect a button in the array.
</description>
</method>
- <method name="erase_button" >
+ <method name="erase_button">
<argument index="0" name="button" type="int">
</argument>
<description>
Remove a button in the array, by index.
</description>
</method>
- <method name="clear" >
+ <method name="clear">
<description>
Clear the button array.
</description>
@@ -5225,7 +5597,7 @@
</constant>
</constants>
</class>
-<class name="ButtonGroup" inherits="Control" category="Core">
+<class name="ButtonGroup" inherits="BoxContainer" category="Core">
<brief_description>
Group of Buttons.
</brief_description>
@@ -5233,35 +5605,35 @@
Group of [Button]s. All direct and indirect children buttons become radios. Only one allows being pressed.
</description>
<methods>
- <method name="get_pressed_button" qualifiers="const" >
+ <method name="get_pressed_button" qualifiers="const">
<return type="BaseButton">
</return>
<description>
Return the pressed button.
</description>
</method>
- <method name="get_pressed_button_index" qualifiers="const" >
+ <method name="get_pressed_button_index" qualifiers="const">
<return type="int">
</return>
<description>
Return the index of the pressed button (by tree order).
</description>
</method>
- <method name="get_focused_button" qualifiers="const" >
+ <method name="get_focused_button" qualifiers="const">
<return type="BaseButton">
</return>
<description>
Return the focused button.
</description>
</method>
- <method name="get_button_list" qualifiers="const" >
+ <method name="get_button_list" qualifiers="const">
<return type="Array">
</return>
<description>
Return the list of all the buttons in the group.
</description>
</method>
- <method name="set_pressed_button" >
+ <method name="set_pressed_button">
<argument index="0" name="button" type="BaseButton">
</argument>
<description>
@@ -5271,6 +5643,10 @@
</methods>
<constants>
</constants>
+ <theme_items>
+ <theme_item name="panel" type="StyleBox">
+ </theme_item>
+ </theme_items>
</class>
<class name="Camera" inherits="Spatial" category="Core">
<brief_description>
@@ -5280,7 +5656,7 @@
Camera is a special node that displays what is visible from its current location. Cameras register themselves in the nearest [Viewport] node (when ascending the tree). Only one camera can be active per viewport. If no viewport is available ascending the tree, the Camera will register in the global viewport. In other words, a Camera just provides [i]3D[/i] display capabilities to a [Viewport], and, without one, a [Scene] registered in that [Viewport] (or higher viewports) can't be displayed.
</description>
<methods>
- <method name="project_ray_normal" qualifiers="const" >
+ <method name="project_ray_normal" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="screen_point" type="Vector2">
@@ -5289,7 +5665,7 @@
Return a normal vector in worldspace, that is the result of projecting a point on the [Viewport] rectangle by the camera projection. This is useful for casting rays in the form of (origin,normal) for object intersection or picking.
</description>
</method>
- <method name="project_local_ray_normal" qualifiers="const" >
+ <method name="project_local_ray_normal" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="screen_point" type="Vector2">
@@ -5297,7 +5673,7 @@
<description>
</description>
</method>
- <method name="project_ray_origin" qualifiers="const" >
+ <method name="project_ray_origin" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="screen_point" type="Vector2">
@@ -5306,7 +5682,7 @@
Return a 3D position in worldspace, that is the result of projecting a point on the [Viewport] rectangle by the camera projection. This is useful for casting rays in the form of (origin,normal) for object intersection or picking.
</description>
</method>
- <method name="unproject_position" qualifiers="const" >
+ <method name="unproject_position" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="world_point" type="Vector3">
@@ -5315,7 +5691,15 @@
Return how a 3D point in worldpsace maps to a 2D coordinate in the [Viewport] rectangle.
</description>
</method>
- <method name="project_position" qualifiers="const" >
+ <method name="is_position_behind" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="world_point" type="Vector3">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="project_position" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="screen_point" type="Vector2">
@@ -5323,7 +5707,7 @@
<description>
</description>
</method>
- <method name="set_perspective" >
+ <method name="set_perspective">
<argument index="0" name="fov" type="float">
</argument>
<argument index="1" name="z_near" type="float">
@@ -5334,7 +5718,7 @@
Set the camera projection to perspective mode, by specifying a [i]FOV[/i] Y angle in degrees (FOV means Field of View), and the [i]near[/i] and [i]far[/i] clip planes in worldspace units.
</description>
</method>
- <method name="set_orthogonal" >
+ <method name="set_orthogonal">
<argument index="0" name="size" type="float">
</argument>
<argument index="1" name="z_near" type="float">
@@ -5342,111 +5726,93 @@
<argument index="2" name="z_far" type="float">
</argument>
<description>
- Set the camera projection to orthogonal mode, by specifying a"#10;"#9;"#9;"#9;width and the [i]near[/i] and [i]far[/i] clip planes in worldspace units. (As a hint, 2D games often use this projection, with values specified in pixels)
+ Set the camera projection to orthogonal mode, by specifying a width and the [i]near[/i] and [i]far[/i] clip planes in worldspace units. (As a hint, 2D games often use this projection, with values specified in pixels)
</description>
</method>
- <method name="make_current" >
+ <method name="make_current">
<description>
- Make this camera the current Camera for the [Viewport] (see class description). If the Camera Node is outside the scene tree, it will attempt to become current once it"apos;s added.
+ Make this camera the current Camera for the [Viewport] (see class description). If the Camera Node is outside the scene tree, it will attempt to become current once it's added.
</description>
</method>
- <method name="clear_current" >
+ <method name="clear_current">
<description>
</description>
</method>
- <method name="is_current" qualifiers="const" >
+ <method name="is_current" qualifiers="const">
<return type="bool">
</return>
<description>
Return wether the Camera is the current one in the [Viewport], or plans to become current (if outside the scene tree).
</description>
</method>
- <method name="get_camera_transform" qualifiers="const" >
+ <method name="get_camera_transform" qualifiers="const">
<return type="Transform">
</return>
<description>
Get the camera transform. Subclassed cameras (such as CharacterCamera) may provide different transforms than the [Node] transform.
</description>
</method>
- <method name="get_fov" qualifiers="const" >
+ <method name="get_fov" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="get_size" qualifiers="const" >
+ <method name="get_size" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="get_zfar" qualifiers="const" >
+ <method name="get_zfar" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="get_znear" qualifiers="const" >
+ <method name="get_znear" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="get_projection" qualifiers="const" >
+ <method name="get_projection" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_visible_layers" >
+ <method name="set_visible_layers">
<argument index="0" name="mask" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_visible_layers" qualifiers="const" >
+ <method name="get_visible_layers" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="look_at" >
- <argument index="0" name="target" type="Vector3">
- </argument>
- <argument index="1" name="up" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="look_at_from_pos" >
- <argument index="0" name="pos" type="Vector3">
- </argument>
- <argument index="1" name="target" type="Vector3">
- </argument>
- <argument index="2" name="up" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_environment" >
+ <method name="set_environment">
<argument index="0" name="env" type="Environment">
</argument>
<description>
</description>
</method>
- <method name="get_environment" qualifiers="const" >
+ <method name="get_environment" qualifiers="const">
<return type="Environment">
</return>
<description>
</description>
</method>
- <method name="set_keep_aspect_mode" >
+ <method name="set_keep_aspect_mode">
<argument index="0" name="mode" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_keep_aspect_mode" qualifiers="const" >
+ <method name="get_keep_aspect_mode" qualifiers="const">
<return type="int">
</return>
<description>
@@ -5472,142 +5838,139 @@
</brief_description>
<description>
Camera node for 2D scenes. It forces the screen (current layer) to scroll following this node. This makes it easier (and faster) to program scrollable scenes than manually changing the position of [CanvasItem] based nodes.
- This node is intended to be a simple helper get get things going quickly
- and it may happen often that more functionality is desired to change
- how the camera works. To make your own custom camera node, simply
- inherit from [Node2D] and change the transform of the canvas by
- calling get_viewport().set_canvas_transform(m) in [Viewport].
+ This node is intended to be a simple helper get get things going quickly and it may happen often that more functionality is desired to change how the camera works. To make your own custom camera node, simply inherit from [Node2D] and change the transform of the canvas by calling get_viewport().set_canvas_transform(m) in [Viewport].
</description>
<methods>
- <method name="set_offset" >
+ <method name="set_offset">
<argument index="0" name="offset" type="Vector2">
</argument>
<description>
- Set the scroll offset. Useful for looking around or
- camera shake animations.
+ Set the scroll offset. Useful for looking around or camera shake animations.
</description>
</method>
- <method name="get_offset" qualifiers="const" >
+ <method name="get_offset" qualifiers="const">
<return type="Vector2">
</return>
<description>
Return the scroll offset.
</description>
</method>
- <method name="set_centered" >
- <argument index="0" name="centered" type="bool">
+ <method name="set_anchor_mode">
+ <argument index="0" name="anchor_mode" type="int">
</argument>
<description>
- Set to true if the camera is at the center of the screen (default: true).
</description>
</method>
- <method name="is_centered" qualifiers="const" >
- <return type="bool">
+ <method name="get_anchor_mode" qualifiers="const">
+ <return type="int">
</return>
<description>
- Return true if the camera is at the center of the screen (default: true).
</description>
</method>
- <method name="set_rotating" >
+ <method name="set_rotating">
<argument index="0" name="rotating" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_rotating" qualifiers="const" >
+ <method name="is_rotating" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="make_current" >
+ <method name="make_current">
<description>
Make this the current 2D camera for the scene (viewport and layer), in case there's many cameras in the scene.
</description>
</method>
- <method name="is_current" qualifiers="const" >
+ <method name="clear_current">
+ <description>
+ </description>
+ </method>
+ <method name="is_current" qualifiers="const">
<return type="bool">
</return>
<description>
Return true of this is the current camera (see [method Camera2D.make_current]).
</description>
</method>
- <method name="set_limit" >
+ <method name="set_limit">
<argument index="0" name="margin" type="int">
</argument>
<argument index="1" name="limit" type="int">
</argument>
<description>
- Set the scrolling limit in pixels
+ Set the scrolling limit in pixels.
</description>
</method>
- <method name="get_limit" qualifiers="const" >
+ <method name="get_limit" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="margin" type="int">
</argument>
<description>
- Return the scrolling limit in pixels
+ Return the scrolling limit in pixels.
</description>
</method>
- <method name="set_v_drag_enabled" >
+ <method name="set_v_drag_enabled">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_v_drag_enabled" qualifiers="const" >
+ <method name="is_v_drag_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_h_drag_enabled" >
+ <method name="set_h_drag_enabled">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_h_drag_enabled" qualifiers="const" >
+ <method name="is_h_drag_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_v_offset" >
+ <method name="set_v_offset">
<argument index="0" name="ofs" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_v_offset" qualifiers="const" >
+ <method name="get_v_offset" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_h_offset" >
+ <method name="set_h_offset">
<argument index="0" name="ofs" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_h_offset" qualifiers="const" >
+ <method name="get_h_offset" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_drag_margin" >
+ <method name="set_drag_margin">
<argument index="0" name="margin" type="int">
</argument>
<argument index="1" name="drag_margin" type="float">
</argument>
<description>
- Set the margins needed to drag the camera (relative to the screen size). Margin uses the MARGIN_* enum. Drag margins of 0,0,0,0 will keep the camera at the center of the screen, while drag margins of 1,1,1,1 will only move when the camera is at the edges.
+ Set the margins needed to drag the camera (relative to the screen size). Margin uses the MARGIN_* enum. Drag margins of 0,0,0,0 will keep the camera at the center of the screen, while drag margins of 1,1,1,1 will only move when the camera is at the edges.
</description>
</method>
- <method name="get_drag_margin" qualifiers="const" >
+ <method name="get_drag_margin" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="margin" type="int">
@@ -5616,50 +5979,66 @@
Return the margins needed to drag the camera (see [method set_drag_margin]).
</description>
</method>
- <method name="get_camera_pos" qualifiers="const" >
+ <method name="get_camera_pos" qualifiers="const">
<return type="Vector2">
</return>
<description>
Return the camera position.
</description>
</method>
- <method name="get_camera_screen_center" qualifiers="const" >
+ <method name="get_camera_screen_center" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="set_zoom" >
- <argument index="0" name="arg0" type="Vector2">
+ <method name="set_zoom">
+ <argument index="0" name="zoom" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_zoom" qualifiers="const" >
+ <method name="get_zoom" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="set_follow_smoothing" >
+ <method name="set_follow_smoothing">
<argument index="0" name="follow_smoothing" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_follow_smoothing" qualifiers="const" >
+ <method name="get_follow_smoothing" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="force_update_scroll" >
+ <method name="set_enable_follow_smoothing">
+ <argument index="0" name="follow_smoothing" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_follow_smoothing_enabled" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="force_update_scroll">
<description>
Force the camera to update scroll immediately.
</description>
</method>
</methods>
<constants>
+ <constant name="ANCHOR_MODE_DRAG_CENTER" value="1">
+ </constant>
+ <constant name="ANCHOR_MODE_FIXED_TOP_LEFT" value="0">
+ </constant>
</constants>
</class>
<class name="CanvasItem" inherits="Node" category="Core">
@@ -5668,152 +6047,173 @@
</brief_description>
<description>
Base class of anything 2D. Canvas items are laid out in a tree and children inherit and extend the transform of their parent. CanvasItem is extended by [Control], for anything GUI related, and by [Node2D] for anything 2D engine related.
- Any CanvasItem can draw. For this, the "update" function must be called, then NOTIFICATION_DRAW will be received on idle time to request redraw. Because of this, canvas items don't need to be redraw on every frame, improving the performance significantly. Several functions for drawing on the CanvasItem are provided (see draw_* functions). They can only be used inside the notification, signal or _draw() overrided function, though.
- Canvas items are draw in tree order. By default, children are on top of their parents so a root CanvasItem will be drawn behind everything (this can be changed per item though).
+ Any CanvasItem can draw. For this, the "update" function must be called, then NOTIFICATION_DRAW will be received on idle time to request redraw. Because of this, canvas items don't need to be redraw on every frame, improving the performance significan'tly. Several functions for drawing on the CanvasItem are provided (see draw_* functions). They can only be used inside the notification, signal or _draw() overrided function, though.
+ Canvas items are draw in tree order. By default, children are on top of their parents so a root CanvasItem will be drawn behind everything (this can be changed per item though).
Canvas items can also be hidden (hiding also their subtree). They provide many means for changing standard parameters such as opacity (for it and the subtree) and self opacity, blend mode.
Ultimately, a transform notification can be requested, which will notify the node that its global position changed in case the parent tree changed.
</description>
<methods>
- <method name="_draw" qualifiers="virtual" >
+ <method name="_draw" qualifiers="virtual">
<description>
Called (if exists) to draw the canvas item.
</description>
</method>
- <method name="edit_set_state" >
+ <method name="edit_set_state">
<argument index="0" name="state" type="var">
</argument>
<description>
Used for editing, returns an opaque value represeting the transform state.
</description>
</method>
- <method name="edit_get" qualifiers="const" >
+ <method name="edit_get" qualifiers="const">
<description>
</description>
</method>
- <method name="edit_set_rect" >
+ <method name="edit_set_rect">
<argument index="0" name="rect" type="Rect2">
</argument>
<description>
</description>
</method>
- <method name="edit_rotate" >
+ <method name="edit_rotate">
<argument index="0" name="degrees" type="float">
</argument>
<description>
Used for editing, handle rotation.
</description>
</method>
- <method name="get_item_rect" qualifiers="const" >
+ <method name="get_item_rect" qualifiers="const">
<return type="Rect2">
</return>
<description>
Return a rect containing the editable contents of the item.
</description>
</method>
- <method name="get_canvas_item" qualifiers="const" >
+ <method name="get_canvas_item" qualifiers="const">
<return type="RID">
</return>
<description>
Return the canvas item RID used by [VisualServer] for this item.
</description>
</method>
- <method name="is_visible" qualifiers="const" >
+ <method name="is_visible" qualifiers="const">
<return type="bool">
</return>
<description>
Return true if this CanvasItem is visible. It may be invisible because itself or a parent canvas item is hidden.
</description>
</method>
- <method name="is_hidden" qualifiers="const" >
+ <method name="is_hidden" qualifiers="const">
<return type="bool">
</return>
<description>
Return true if this CanvasItem is hidden. Note that the CanvasItem may not be visible, but as long as it's not hidden ([method hide] called) the function will return false.
</description>
</method>
- <method name="show" >
+ <method name="show">
<description>
Show the CanvasItem currently hidden.
</description>
</method>
- <method name="hide" >
+ <method name="hide">
<description>
Hide the CanvasItem currently visible.
</description>
</method>
- <method name="update" >
+ <method name="set_hidden">
+ <argument index="0" name="hidden" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="update">
<description>
Queue the CanvasItem for update. NOTIFICATION_DRAW will be called on idle time to request redraw.
</description>
</method>
- <method name="set_as_toplevel" >
+ <method name="set_as_toplevel">
<argument index="0" name="enable" type="bool">
</argument>
<description>
Set as toplevel. This means that it will not inherit transform from parent canvas items.
</description>
</method>
- <method name="is_set_as_toplevel" qualifiers="const" >
+ <method name="is_set_as_toplevel" qualifiers="const">
<return type="bool">
</return>
<description>
Return if set as toplevel. See [method set_as_toplevel]/
</description>
</method>
- <method name="set_blend_mode" >
+ <method name="set_blend_mode">
<argument index="0" name="blend_mode" type="int">
</argument>
<description>
Set the blending mode from enum BLEND_MODE_*.
</description>
</method>
- <method name="get_blend_mode" qualifiers="const" >
+ <method name="get_blend_mode" qualifiers="const">
<return type="int">
</return>
<description>
Return the current blending mode from enum BLEND_MODE_*.
</description>
</method>
- <method name="set_opacity" >
+ <method name="set_light_mask">
+ <argument index="0" name="light_mask" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_light_mask" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_opacity">
<argument index="0" name="opacity" type="float">
</argument>
<description>
Set canvas item opacity. This will affect the canvas item and all the children.
</description>
</method>
- <method name="get_opacity" qualifiers="const" >
+ <method name="get_opacity" qualifiers="const">
<return type="float">
</return>
<description>
Return the canvas item opacity. This affects the canvas item and all the children.
</description>
</method>
- <method name="set_self_opacity" >
+ <method name="set_self_opacity">
<argument index="0" name="self_opacity" type="float">
</argument>
<description>
+ Set canvas item self-opacity. This does not affect the opacity of children items.
</description>
</method>
- <method name="get_self_opacity" qualifiers="const" >
+ <method name="get_self_opacity" qualifiers="const">
<return type="float">
</return>
<description>
- Set canvas item self-opacity. This does not affect the opacity of children items.
+ Return the canvas item self-opacity.
</description>
</method>
- <method name="set_draw_behind_parent" >
- <argument index="0" name="enabe" type="bool">
+ <method name="set_draw_behind_parent">
+ <argument index="0" name="enable" type="bool">
</argument>
<description>
+ Sets whether the canvas item is drawn behind its parent.
</description>
</method>
- <method name="is_draw_behind_parent_enabled" qualifiers="const" >
+ <method name="is_draw_behind_parent_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
+ Return whether the item is drawn behind its parent.
</description>
</method>
- <method name="draw_line" >
+ <method name="draw_line">
<argument index="0" name="from" type="Vector2">
</argument>
<argument index="1" name="to" type="Vector2">
@@ -5826,7 +6226,7 @@
Draw a line from a 2D point to another, with a given color and width.
</description>
</method>
- <method name="draw_rect" >
+ <method name="draw_rect">
<argument index="0" name="rect" type="Rect2">
</argument>
<argument index="1" name="color" type="Color">
@@ -5835,7 +6235,7 @@
Draw a colored rectangle.
</description>
</method>
- <method name="draw_circle" >
+ <method name="draw_circle">
<argument index="0" name="pos" type="Vector2">
</argument>
<argument index="1" name="radius" type="float">
@@ -5846,29 +6246,33 @@
Draw a colored circle.
</description>
</method>
- <method name="draw_texture" >
+ <method name="draw_texture">
<argument index="0" name="texture" type="Texture">
</argument>
<argument index="1" name="pos" type="Vector2">
</argument>
+ <argument index="2" name="modulate" type="Color" default="Color(1,1,1,1)">
+ </argument>
<description>
Draw a texture at a given position.
</description>
</method>
- <method name="draw_texture_rect" >
+ <method name="draw_texture_rect">
<argument index="0" name="texture" type="Texture">
</argument>
<argument index="1" name="rect" type="Rect2">
</argument>
- <argument index="2" name="tile" type="bool" default="false">
+ <argument index="2" name="tile" type="bool">
</argument>
<argument index="3" name="modulate" type="Color" default="Color(1,1,1,1)">
</argument>
+ <argument index="4" name="transpose" type="bool" default="false">
+ </argument>
<description>
- Draw a textured rectangle at a given position, optionally modulated by a color.
+ Draw a textured rectangle at a given position, optionally modulated by a color. Transpose swaps the x and y coordinates when reading the texture.
</description>
</method>
- <method name="draw_texture_rect_region" >
+ <method name="draw_texture_rect_region">
<argument index="0" name="texture" type="Texture">
</argument>
<argument index="1" name="rect" type="Rect2">
@@ -5877,11 +6281,13 @@
</argument>
<argument index="3" name="modulate" type="Color" default="Color(1,1,1,1)">
</argument>
+ <argument index="4" name="transpose" type="bool" default="false">
+ </argument>
<description>
- Draw a textured rectangle region at a given position, optionally modulated by a color.
+ Draw a textured rectangle region at a given position, optionally modulated by a color. Transpose swaps the x and y coordinates when reading the texture.
</description>
</method>
- <method name="draw_style_box" >
+ <method name="draw_style_box">
<argument index="0" name="style_box" type="StyleBox">
</argument>
<argument index="1" name="rect" type="Rect2">
@@ -5890,7 +6296,7 @@
Draw a styled rectangle.
</description>
</method>
- <method name="draw_primitive" >
+ <method name="draw_primitive">
<argument index="0" name="points" type="Vector2Array">
</argument>
<argument index="1" name="colors" type="ColorArray">
@@ -5905,7 +6311,7 @@
Draw a custom primitive, 1 point for a point, 2 points for a line, 3 points for a triangle and 4 points for a quad.
</description>
</method>
- <method name="draw_polygon" >
+ <method name="draw_polygon">
<argument index="0" name="points" type="Vector2Array">
</argument>
<argument index="1" name="colors" type="ColorArray">
@@ -5918,7 +6324,7 @@
Draw a polygon of any amount of points, convex or concave.
</description>
</method>
- <method name="draw_colored_polygon" >
+ <method name="draw_colored_polygon">
<argument index="0" name="points" type="Vector2Array">
</argument>
<argument index="1" name="color" type="Color">
@@ -5931,7 +6337,7 @@
Draw a colored polygon of any amount of points, convex or concave.
</description>
</method>
- <method name="draw_string" >
+ <method name="draw_string">
<argument index="0" name="font" type="Font">
</argument>
<argument index="1" name="pos" type="Vector2">
@@ -5946,7 +6352,7 @@
Draw a string using a custom font.
</description>
</method>
- <method name="draw_char" >
+ <method name="draw_char">
<return type="float">
</return>
<argument index="0" name="font" type="Font">
@@ -5963,7 +6369,7 @@
Draw a string character using a custom font. Returns the advance, depending on the char width and kerning with an optional next char.
</description>
</method>
- <method name="draw_set_transform" >
+ <method name="draw_set_transform">
<argument index="0" name="pos" type="Vector2">
</argument>
<argument index="1" name="rot" type="float">
@@ -5974,42 +6380,98 @@
Set a custom transform for drawing. Anything drawn afterwards will be transformed by this.
</description>
</method>
- <method name="get_transform" qualifiers="const" >
+ <method name="get_transform" qualifiers="const">
+ <return type="Matrix32">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_global_transform" qualifiers="const">
<return type="Matrix32">
</return>
<description>
</description>
</method>
- <method name="get_global_transform" qualifiers="const" >
+ <method name="get_global_transform_with_canvas" qualifiers="const">
<return type="Matrix32">
</return>
<description>
</description>
</method>
- <method name="get_viewport_transform" qualifiers="const" >
+ <method name="get_viewport_transform" qualifiers="const">
<return type="Matrix32">
</return>
<description>
</description>
</method>
- <method name="get_viewport_rect" qualifiers="const" >
+ <method name="get_viewport_rect" qualifiers="const">
<return type="Rect2">
</return>
<description>
</description>
</method>
- <method name="get_canvas" qualifiers="const" >
+ <method name="get_canvas_transform" qualifiers="const">
+ <return type="Matrix32">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_local_mouse_pos" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_global_mouse_pos" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_canvas" qualifiers="const">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="get_world_2d" qualifiers="const" >
+ <method name="get_world_2d" qualifiers="const">
<return type="Object">
</return>
<description>
</description>
</method>
+ <method name="set_material">
+ <argument index="0" name="material" type="CanvasItemMaterial">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_material" qualifiers="const">
+ <return type="CanvasItemMaterial">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_use_parent_material">
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_use_parent_material" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="make_input_local" qualifiers="const">
+ <return type="InputEvent">
+ </return>
+ <argument index="0" name="event" type="InputEvent">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<signals>
<signal name="item_rect_changed">
@@ -6029,13 +6491,13 @@
</signal>
<signal name="hide">
<description>
- Emitten when becoming hidden.
+ Emitted when becoming hidden.
</description>
</signal>
</signals>
<constants>
<constant name="BLEND_MODE_MIX" value="0">
- Mix blending mode.
+ Mix blending mode. Colors are assumed to be independent of the alpha (opacity) value.
</constant>
<constant name="BLEND_MODE_ADD" value="1">
Additive blending mode.
@@ -6047,6 +6509,7 @@
Multiplicative blending mode.
</constant>
<constant name="BLEND_MODE_PREMULT_ALPHA" value="4">
+ Mix blending mode. Colors are assumed to be premultiplied by the alpha (opacity) value.
</constant>
<constant name="NOTIFICATION_DRAW" value="30">
CanvasItem is requested to draw.
@@ -6065,6 +6528,80 @@
</constant>
</constants>
</class>
+<class name="CanvasItemMaterial" inherits="Resource" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="set_shader">
+ <argument index="0" name="shader" type="Shader">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_shader" qualifiers="const">
+ <return type="Shader">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_shader_param">
+ <argument index="0" name="param" type="String">
+ </argument>
+ <argument index="1" name="value" type="var">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_shader_param" qualifiers="const">
+ <argument index="0" name="param" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_shading_mode">
+ <argument index="0" name="mode" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_shading_mode" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ <constant name="SHADING_NORMAL" value="0">
+ </constant>
+ <constant name="SHADING_UNSHADED" value="1">
+ </constant>
+ <constant name="SHADING_ONLY_LIGHT" value="2">
+ </constant>
+ </constants>
+</class>
+<class name="CanvasItemShader" inherits="Shader" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
+<class name="CanvasItemShaderGraph" inherits="ShaderGraph" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
<class name="CanvasLayer" inherits="Node" category="Core">
<brief_description>
Canvas Item layer.
@@ -6073,84 +6610,84 @@
Canvas Item layer. [CanvasItem] nodes that are direct or indirect children of a [CanvasLayer] will be drawn in that layer. The layer is a numeric index that defines the draw order. The default 2D scene renders with index 0, so a [CanvasLayer] with index -1 will be drawn below, and one with index 1 will be drawn above. This is very useful for HUDs (in layer 1+ or above), or backgrounds (in layer -1 or below).
</description>
<methods>
- <method name="set_layer" >
+ <method name="set_layer">
<argument index="0" name="layer" type="int">
</argument>
<description>
Set the layer index, determines the draw order, a lower value will be below a higher one.
</description>
</method>
- <method name="get_layer" qualifiers="const" >
+ <method name="get_layer" qualifiers="const">
<return type="int">
</return>
<description>
Return the layer index, determines the draw order, a lower value will be below a higher one.
</description>
</method>
- <method name="set_transform" >
+ <method name="set_transform">
<argument index="0" name="transform" type="Matrix32">
</argument>
<description>
Set the base transform for this layer.
</description>
</method>
- <method name="get_transform" qualifiers="const" >
+ <method name="get_transform" qualifiers="const">
<return type="Matrix32">
</return>
<description>
Return the base transform for this layer.
</description>
</method>
- <method name="set_offset" >
+ <method name="set_offset">
<argument index="0" name="offset" type="Vector2">
</argument>
<description>
Set the base offset for this layer (helper).
</description>
</method>
- <method name="get_offset" qualifiers="const" >
+ <method name="get_offset" qualifiers="const">
<return type="Vector2">
</return>
<description>
Return the base offset for this layer (helper).
</description>
</method>
- <method name="set_rotation" >
+ <method name="set_rotation">
<argument index="0" name="rotation" type="float">
</argument>
<description>
Set the base rotation for this layer (helper).
</description>
</method>
- <method name="get_rotation" qualifiers="const" >
+ <method name="get_rotation" qualifiers="const">
<return type="float">
</return>
<description>
Return the base rotation for this layer (helper).
</description>
</method>
- <method name="set_scale" >
+ <method name="set_scale">
<argument index="0" name="scale" type="Vector2">
</argument>
<description>
Set the base scale for this layer (helper).
</description>
</method>
- <method name="get_scale" qualifiers="const" >
+ <method name="get_scale" qualifiers="const">
<return type="Vector2">
</return>
<description>
Return the base scale for this layer (helper).
</description>
</method>
- <method name="get_world_2d" qualifiers="const" >
+ <method name="get_world_2d" qualifiers="const">
<return type="Canvas">
</return>
<description>
Return the [World2D] used by this layer.
</description>
</method>
- <method name="get_viewport" qualifiers="const" >
+ <method name="get_viewport" qualifiers="const">
<return type="RID">
</return>
<description>
@@ -6161,6 +6698,28 @@
<constants>
</constants>
</class>
+<class name="CanvasModulate" inherits="Node2D" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="set_color">
+ <argument index="0" name="color" type="Color">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_color" qualifiers="const">
+ <return type="Color">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
<class name="CapsuleShape" inherits="Shape" category="Core">
<brief_description>
Capsule shape resource.
@@ -6169,28 +6728,28 @@
Capsule shape resource, which can be set into a [PhysicsBody] or area.
</description>
<methods>
- <method name="set_radius" >
+ <method name="set_radius">
<argument index="0" name="radius" type="float">
</argument>
<description>
Set the capsule radius.
</description>
</method>
- <method name="get_radius" qualifiers="const" >
+ <method name="get_radius" qualifiers="const">
<return type="float">
</return>
<description>
Return the capsule radius.
</description>
</method>
- <method name="set_height" >
+ <method name="set_height">
<argument index="0" name="height" type="float">
</argument>
<description>
Set the capsule height.
</description>
</method>
- <method name="get_height" qualifiers="const" >
+ <method name="get_height" qualifiers="const">
<return type="float">
</return>
<description>
@@ -6209,28 +6768,28 @@
Capsule 2D shape resource for physics. A capsule (or sometimes called "pill") is like a line grown in all directions. It has a radius and a height, and is often useful for modelling biped characters.
</description>
<methods>
- <method name="set_radius" >
+ <method name="set_radius">
<argument index="0" name="radius" type="float">
</argument>
<description>
- Radius of the [CapsuleShape2D].
+ Set the radius of the [CapsuleShape2D].
</description>
</method>
- <method name="get_radius" qualifiers="const" >
+ <method name="get_radius" qualifiers="const">
<return type="float">
</return>
<description>
Return the radius of the [CapsuleShape2D].
</description>
</method>
- <method name="set_height" >
+ <method name="set_height">
<argument index="0" name="height" type="float">
</argument>
<description>
- Height of the [CapsuleShape2D].
+ Set the height of the [CapsuleShape2D].
</description>
</method>
- <method name="get_height" qualifiers="const" >
+ <method name="get_height" qualifiers="const">
<return type="float">
</return>
<description>
@@ -6249,13 +6808,13 @@
CenterContainer Keeps children controls centered. This container keeps all children to their minimum size, in the center.
</description>
<methods>
- <method name="set_use_top_left" >
+ <method name="set_use_top_left">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_using_top_left" qualifiers="const" >
+ <method name="is_using_top_left" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -6265,6 +6824,50 @@
<constants>
</constants>
</class>
+<class name="CheckBox" inherits="Button" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+ <theme_items>
+ <theme_item name="check_vadjust" type="int">
+ </theme_item>
+ <theme_item name="hseparation" type="int">
+ </theme_item>
+ <theme_item name="font_color_disabled" type="Color">
+ </theme_item>
+ <theme_item name="font_color" type="Color">
+ </theme_item>
+ <theme_item name="font_color_hover" type="Color">
+ </theme_item>
+ <theme_item name="font_color_pressed" type="Color">
+ </theme_item>
+ <theme_item name="radio_checked" type="Texture">
+ </theme_item>
+ <theme_item name="checked" type="Texture">
+ </theme_item>
+ <theme_item name="radio_unchecked" type="Texture">
+ </theme_item>
+ <theme_item name="unchecked" type="Texture">
+ </theme_item>
+ <theme_item name="font" type="Font">
+ </theme_item>
+ <theme_item name="hover" type="StyleBox">
+ </theme_item>
+ <theme_item name="pressed" type="StyleBox">
+ </theme_item>
+ <theme_item name="focus" type="StyleBox">
+ </theme_item>
+ <theme_item name="disabled" type="StyleBox">
+ </theme_item>
+ <theme_item name="normal" type="StyleBox">
+ </theme_item>
+ </theme_items>
+</class>
<class name="CheckButton" inherits="Button" category="Core">
<brief_description>
Checkable button.
@@ -6315,14 +6918,14 @@
Circular Shape for 2D Physics. This shape is useful for modelling balls or small characters and it's collision detection with everything else is very fast.
</description>
<methods>
- <method name="set_radius" >
+ <method name="set_radius">
<argument index="0" name="radius" type="float">
</argument>
<description>
- Set the radius of the circle shape;
+ Set the radius of the circle shape.
</description>
</method>
- <method name="get_radius" qualifiers="const" >
+ <method name="get_radius" qualifiers="const">
<return type="float">
</return>
<description>
@@ -6339,7 +6942,7 @@
<description>
</description>
<methods>
- <method name="_input_event" qualifiers="virtual" >
+ <method name="_input_event" qualifiers="virtual">
<argument index="0" name="camera" type="Object">
</argument>
<argument index="1" name="event" type="InputEvent">
@@ -6353,7 +6956,7 @@
<description>
</description>
</method>
- <method name="add_shape" >
+ <method name="add_shape">
<argument index="0" name="shape" type="Shape">
</argument>
<argument index="1" name="transform" type="Transform" default="Transform()">
@@ -6361,13 +6964,13 @@
<description>
</description>
</method>
- <method name="get_shape_count" qualifiers="const" >
+ <method name="get_shape_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_shape" >
+ <method name="set_shape">
<argument index="0" name="shape_idx" type="int">
</argument>
<argument index="1" name="shape" type="Shape">
@@ -6375,7 +6978,7 @@
<description>
</description>
</method>
- <method name="set_shape_transform" >
+ <method name="set_shape_transform">
<argument index="0" name="shape_idx" type="int">
</argument>
<argument index="1" name="transform" type="Transform">
@@ -6383,7 +6986,7 @@
<description>
</description>
</method>
- <method name="set_shape_as_trigger" >
+ <method name="set_shape_as_trigger">
<argument index="0" name="shape_idx" type="int">
</argument>
<argument index="1" name="enable" type="bool">
@@ -6391,7 +6994,7 @@
<description>
</description>
</method>
- <method name="is_shape_set_as_trigger" qualifiers="const" >
+ <method name="is_shape_set_as_trigger" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="shape_idx" type="int">
@@ -6399,7 +7002,7 @@
<description>
</description>
</method>
- <method name="get_shape" qualifiers="const" >
+ <method name="get_shape" qualifiers="const">
<return type="Shape">
</return>
<argument index="0" name="shape_idx" type="int">
@@ -6407,7 +7010,7 @@
<description>
</description>
</method>
- <method name="get_shape_transform" qualifiers="const" >
+ <method name="get_shape_transform" qualifiers="const">
<return type="Transform">
</return>
<argument index="0" name="shape_idx" type="int">
@@ -6415,41 +7018,41 @@
<description>
</description>
</method>
- <method name="remove_shape" >
+ <method name="remove_shape">
<argument index="0" name="shape_idx" type="int">
</argument>
<description>
</description>
</method>
- <method name="clear_shapes" >
+ <method name="clear_shapes">
<description>
</description>
</method>
- <method name="set_ray_pickable" >
+ <method name="set_ray_pickable">
<argument index="0" name="ray_pickable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_ray_pickable" qualifiers="const" >
+ <method name="is_ray_pickable" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_capture_input_on_drag" >
+ <method name="set_capture_input_on_drag">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="get_capture_input_on_drag" qualifiers="const" >
+ <method name="get_capture_input_on_drag" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="get_rid" qualifiers="const" >
+ <method name="get_rid" qualifiers="const">
<return type="RID">
</return>
<description>
@@ -6488,10 +7091,21 @@
Base node for 2D collisionables.
</brief_description>
<description>
- CollisionObject2D is the base class for 2D physics collisionables. They can hold any number of 2D collision shapes. Usually, they are edited by placing CollisionBody2D and CollisionPolygon2D nodes as children. Such nodes are for reference ant not present outside the editor, so code should use the regular shape API.
+ CollisionObject2D is the base class for 2D physics collisionables. They can hold any number of 2D collision shapes. Usually, they are edited by placing [CollisionShape2D] and/or [CollisionPolygon2D] nodes as children. Such nodes are for reference and not present outside the editor, so code should use the regular shape API.
</description>
<methods>
- <method name="add_shape" >
+ <method name="_input_event" qualifiers="virtual">
+ <argument index="0" name="viewport" type="Object">
+ </argument>
+ <argument index="1" name="event" type="InputEvent">
+ </argument>
+ <argument index="2" name="shape_idx" type="int">
+ </argument>
+ <description>
+ This method can be used to override normal input processing. The first parameter is the viewport where the event took place. The second holds the input event received, and the third the shape of this object where it happened.
+ </description>
+ </method>
+ <method name="add_shape">
<argument index="0" name="shape" type="Shape2D">
</argument>
<argument index="1" name="transform" type="Matrix32" default="1,0, 0,1, 0,0">
@@ -6500,14 +7114,14 @@
Add a [Shape2D] to the collision body, with a given custom transform.
</description>
</method>
- <method name="get_shape_count" qualifiers="const" >
+ <method name="get_shape_count" qualifiers="const">
<return type="int">
</return>
<description>
- Return the amount of shapes in the collision body.
+ Return the amount of shapes in the collision body. Because a [CollisionPolygon2D] can generate more than one [Shape2D], the amount returned does not have to match the sum of [CollisionShape2D] and [CollisionPolygon2D].
</description>
</method>
- <method name="set_shape" >
+ <method name="set_shape">
<argument index="0" name="shape_idx" type="int">
</argument>
<argument index="1" name="shape" type="Shape">
@@ -6516,7 +7130,7 @@
Change a shape in the collision body.
</description>
</method>
- <method name="set_shape_transform" >
+ <method name="set_shape_transform">
<argument index="0" name="shape_idx" type="int">
</argument>
<argument index="1" name="transform" type="Matrix32">
@@ -6525,15 +7139,16 @@
Change the shape transform in the collision body.
</description>
</method>
- <method name="set_shape_as_trigger" >
+ <method name="set_shape_as_trigger">
<argument index="0" name="shape_idx" type="int">
</argument>
<argument index="1" name="enable" type="bool">
</argument>
<description>
+ Set whether a shape is a trigger. A trigger shape detects collisions, but is otherwise unaffected by physics (i.e. colliding objects will not get blocked).
</description>
</method>
- <method name="get_shape" qualifiers="const" >
+ <method name="get_shape" qualifiers="const">
<return type="Shape2D">
</return>
<argument index="0" name="shape_idx" type="int">
@@ -6542,7 +7157,7 @@
Return the shape in the given index.
</description>
</method>
- <method name="get_shape_transform" qualifiers="const" >
+ <method name="get_shape_transform" qualifiers="const">
<return type="Matrix32">
</return>
<argument index="0" name="shape_idx" type="int">
@@ -6551,33 +7166,72 @@
Return the shape transform in the given index.
</description>
</method>
- <method name="is_shape_set_as_trigger" qualifiers="const" >
+ <method name="is_shape_set_as_trigger" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="shape_idx" type="int">
</argument>
<description>
+ Return whether a shape is a trigger. A trigger shape detects collisions, but is otherwise unaffected by physics (i.e. colliding objects will not get blocked).
</description>
</method>
- <method name="remove_shape" >
+ <method name="remove_shape">
<argument index="0" name="shape_idx" type="int">
</argument>
<description>
Remove the shape in the given index.
</description>
</method>
- <method name="clear_shapes" >
+ <method name="clear_shapes">
<description>
Remove all shapes.
</description>
</method>
- <method name="get_rid" qualifiers="const" >
+ <method name="get_rid" qualifiers="const">
<return type="RID">
</return>
<description>
+ Return the RID of this object.
+ </description>
+ </method>
+ <method name="set_pickable">
+ <argument index="0" name="enabled" type="bool">
+ </argument>
+ <description>
+ Set whether this object is pickable. A pickable object can detect the mouse pointer enter/leave it and, if the mouse is inside it, report input events.
+ </description>
+ </method>
+ <method name="is_pickable" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Return whether this object is pickable.
</description>
</method>
</methods>
+ <signals>
+ <signal name="mouse_enter">
+ <description>
+ This event fires only once when the mouse pointer enters any shape of this object.
+ </description>
+ </signal>
+ <signal name="input_event">
+ <argument index="0" name="viewport" type="Object">
+ </argument>
+ <argument index="1" name="event" type="InputEvent">
+ </argument>
+ <argument index="2" name="shape_idx" type="int">
+ </argument>
+ <description>
+ This signal triggers when an input event fires over a shape. The first parameter is the viewport where the event took place. The second holds the input event received, and the third the shape of this object where it happened.
+ </description>
+ </signal>
+ <signal name="mouse_exit">
+ <description>
+ This event fires only once when the mouse pointer exits all shapes of this object.
+ </description>
+ </signal>
+ </signals>
<constants>
</constants>
</class>
@@ -6587,37 +7241,49 @@
<description>
</description>
<methods>
- <method name="set_polygon" >
- <argument index="0" name="polygon" type="Vector2Array">
+ <method name="set_build_mode">
+ <argument index="0" name="build_mode" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_polygon" qualifiers="const" >
- <return type="Vector2Array">
+ <method name="get_build_mode" qualifiers="const">
+ <return type="int">
</return>
<description>
</description>
</method>
- <method name="set_depth" >
+ <method name="set_depth">
<argument index="0" name="depth" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_depth" qualifiers="const" >
+ <method name="get_depth" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_build_mode" >
- <argument index="0" name="arg0" type="int">
+ <method name="set_polygon">
+ <argument index="0" name="polygon" type="Vector2Array">
</argument>
<description>
</description>
</method>
- <method name="get_build_mode" qualifiers="const" >
+ <method name="get_polygon" qualifiers="const">
+ <return type="Vector2Array">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_collision_object_first_shape" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_collision_object_last_shape" qualifiers="const">
<return type="int">
</return>
<description>
@@ -6629,12 +7295,71 @@
</class>
<class name="CollisionPolygon2D" inherits="Node2D" category="Core">
<brief_description>
- Editor-Only class.
+ Editor-only class for easy editing of collision polygons.
</brief_description>
<description>
- Editor-Only class. This is not present when running the game. It's used in the editor to properly edit and position collision shapes in [CollisionObject2D]. This is not accessible from regular code. This class is for editing custom shape polygons.
+ Editor-only class. This is not present when running the game. It's used in the editor to properly edit and position collision shapes in [CollisionObject2D]. This is not accessible from regular code. This class is for editing custom shape polygons.
</description>
<methods>
+ <method name="set_polygon">
+ <argument index="0" name="polygon" type="Vector2Array">
+ </argument>
+ <description>
+ Set the array of points forming the polygon.
+ When editing the point list via the editor, depending on [method get_build_mode], it has to be a list of points (for [code]build_mode[/code]=0), or a list of lines (for [code]build_mode[/code]=1). In the second case, the even elements of the array define the start point of the line, and the odd elements the end point.
+ </description>
+ </method>
+ <method name="get_polygon" qualifiers="const">
+ <return type="Vector2Array">
+ </return>
+ <description>
+ Return the list of points that define the polygon.
+ </description>
+ </method>
+ <method name="set_build_mode">
+ <argument index="0" name="build_mode" type="int">
+ </argument>
+ <description>
+ Set whether the polygon is to be a [ConvexPolygon2D] ([code]build_mode[/code]=0), or a [ConcavePolygon2D] ([code]build_mode[/code]=1).
+ </description>
+ </method>
+ <method name="get_build_mode" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Return whether the polygon is a [ConvexPolygon2D] ([code]build_mode[/code]=0), or a [ConcavePolygon2D] ([code]build_mode[/code]=1).
+ </description>
+ </method>
+ <method name="set_trigger">
+ <argument index="0" name="trigger" type="bool">
+ </argument>
+ <description>
+ Set whether this polygon is a trigger. A trigger polygon detects collisions, but is otherwise unaffected by physics (i.e. colliding objects will not get blocked).
+ </description>
+ </method>
+ <method name="is_trigger" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Return whether this polygon is a trigger.
+ </description>
+ </method>
+ <method name="get_collision_object_first_shape" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Return the index of the first shape generated by the editor.
+ When [code]build_mode[/code] is set to generate convex polygons, the shape shown in the editor may be decomopsed into many convex polygons. In that case, a range of indexes is needed to directly access the [Shape2D]s.
+ When [code]build_mode[/code] is set to generate concave polygons, there is only one [Shape2D] generated, so the start index and the end index are the same.
+ </description>
+ </method>
+ <method name="get_collision_object_last_shape" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Return the index of the last shape generated by the editor.
+ </description>
+ </method>
</methods>
<constants>
</constants>
@@ -6645,18 +7370,93 @@
<description>
</description>
<methods>
+ <method name="resource_changed">
+ <argument index="0" name="resource" type="Object">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_shape">
+ <argument index="0" name="shape" type="Object">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_shape" qualifiers="const">
+ <return type="Object">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_trigger">
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_trigger" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="make_convex_from_brothers">
+ <description>
+ </description>
+ </method>
+ <method name="get_collision_object_shape_index" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
</constants>
</class>
<class name="CollisionShape2D" inherits="Node2D" category="Core">
<brief_description>
- Editor-Only class.
+ Editor-only class for easy editing of shapes.
</brief_description>
<description>
- Editor-Only class. This is not present when running the game. It's used in the editor to properly edit and position collision shapes in [CollisionObject2D]. This is not accessible from regular code.
+ Editor-only class. This is not present when running the game. It's used in the editor to properly edit and position collision shapes in [CollisionObject2D]. This is not accessible from regular code.
</description>
<methods>
+ <method name="set_shape">
+ <argument index="0" name="shape" type="Object">
+ </argument>
+ <description>
+ Set this shape's [Shape2D]. This will not appear as a node, but can be directly edited as a property.
+ </description>
+ </method>
+ <method name="get_shape" qualifiers="const">
+ <return type="Object">
+ </return>
+ <description>
+ Return this shape's [Shape2D].
+ </description>
+ </method>
+ <method name="set_trigger">
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ Set whether this shape is a trigger. A trigger shape detects collisions, but is otherwise unaffected by physics (i.e. will not block movement of colliding objects).
+ </description>
+ </method>
+ <method name="is_trigger" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Return whether this shape is a trigger.
+ </description>
+ </method>
+ <method name="get_collision_object_shape_index" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Return the index of this shape inside its container [CollisionObject2D]. This can be used to directly access the underlying [Shape2D].
+ </description>
+ </method>
</methods>
<constants>
</constants>
@@ -6666,10 +7466,10 @@
Color in RGBA format.
</brief_description>
<description>
- A color is represented as red, green and blue (r,g,b) components. Additionally, "a" represents the alpha component, often used for transparency. Values are in floating point, ranging from 0 to 1.
+ A color is represented as red, green and blue (r,g,b) components. Additionally, "a" represents the alpha component, often used for transparency. Values are in floating point and usually range from 0 to 1. Some methods (such as set_modulate() ) may accept values &gt; 1.
</description>
<methods>
- <method name="blend" >
+ <method name="blend">
<return type="Color">
</return>
<argument index="0" name="over" type="Color">
@@ -6677,28 +7477,28 @@
<description>
</description>
</method>
- <method name="contrasted" >
+ <method name="contrasted">
<return type="Color">
</return>
<description>
Return the most contrasting color with this one.
</description>
</method>
- <method name="gray" >
+ <method name="gray">
<return type="float">
</return>
<description>
Convert the color to gray.
</description>
</method>
- <method name="inverted" >
+ <method name="inverted">
<return type="Color">
</return>
<description>
Return the inverted color (1-r, 1-g, 1-b, 1-a).
</description>
</method>
- <method name="linear_interpolate" >
+ <method name="linear_interpolate">
<return type="Color">
</return>
<argument index="0" name="b" type="Color">
@@ -6709,21 +7509,21 @@
Return the linear interpolation with another color.
</description>
</method>
- <method name="to_32" >
+ <method name="to_32">
<return type="int">
</return>
<description>
Convert the color to a 32 its integer (each byte represets a RGBA).
</description>
</method>
- <method name="to_ARGB32" >
+ <method name="to_ARGB32">
<return type="int">
</return>
<description>
Convert color to ARGB32, more compatible with DirectX.
</description>
</method>
- <method name="to_html" >
+ <method name="to_html">
<return type="String">
</return>
<argument index="0" name="with_alpha" type="bool" default="True">
@@ -6732,7 +7532,9 @@
Return the HTML hexadecimal color string.
</description>
</method>
- <method name="Color" >
+ <method name="Color">
+ <return type="Color">
+ </return>
<argument index="0" name="r" type="float">
</argument>
<argument index="1" name="g" type="float">
@@ -6745,7 +7547,9 @@
Construct the color from an RGBA profile.
</description>
</method>
- <method name="Color" >
+ <method name="Color">
+ <return type="Color">
+ </return>
<argument index="0" name="r" type="float">
</argument>
<argument index="1" name="g" type="float">
@@ -6756,14 +7560,18 @@
Construct the color from an RGBA profile.
</description>
</method>
- <method name="Color" >
+ <method name="Color">
+ <return type="Color">
+ </return>
<argument index="0" name="from" type="int">
</argument>
<description>
Construct the color from an RGBA profile.
</description>
</method>
- <method name="Color" >
+ <method name="Color">
+ <return type="Color">
+ </return>
<argument index="0" name="from" type="String">
</argument>
<description>
@@ -6786,6 +7594,14 @@
</member>
<member name="v" type="float">
</member>
+ <member name="r8" type="int">
+ </member>
+ <member name="g8" type="int">
+ </member>
+ <member name="b8" type="int">
+ </member>
+ <member name="a8" type="int">
+ </member>
</members>
<constants>
</constants>
@@ -6795,10 +7611,10 @@
Array of Colors
</brief_description>
<description>
- Array of Color, can only contains colors. Optimized for memory usage, cant fragment the memory.
+ Array of Color, can only contains colors. Optimized for memory usage, can't fragment the memory.
</description>
<methods>
- <method name="get" >
+ <method name="get">
<return type="Color">
</return>
<argument index="0" name="idx" type="int">
@@ -6807,21 +7623,21 @@
Get an index in the array.
</description>
</method>
- <method name="push_back" >
+ <method name="push_back">
<argument index="0" name="color" type="Color">
</argument>
<description>
Append a value to the array.
</description>
</method>
- <method name="resize" >
+ <method name="resize">
<argument index="0" name="idx" type="int">
</argument>
<description>
Resize the array.
</description>
</method>
- <method name="set" >
+ <method name="set">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="color" type="Color">
@@ -6830,14 +7646,16 @@
Set an index in the array.
</description>
</method>
- <method name="size" >
+ <method name="size">
<return type="int">
</return>
<description>
Return the array size.
</description>
</method>
- <method name="ColorArray" >
+ <method name="ColorArray">
+ <return type="ColorArray">
+ </return>
<argument index="0" name="from" type="Array">
</argument>
<description>
@@ -6856,39 +7674,39 @@
This is a simple color picker [Control]. It's useful for selecting a color from an RGB/RGBA colorspace.
</description>
<methods>
- <method name="set_color" >
+ <method name="set_color">
<argument index="0" name="color" type="Color">
</argument>
<description>
Select the current color.
</description>
</method>
- <method name="get_color" qualifiers="const" >
+ <method name="get_color" qualifiers="const">
<return type="Color">
</return>
<description>
Return the current (edited) color.
</description>
</method>
- <method name="set_mode" >
+ <method name="set_mode">
<argument index="0" name="mode" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_mode" qualifiers="const" >
+ <method name="get_mode" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_edit_alpha" >
+ <method name="set_edit_alpha">
<argument index="0" name="show" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_editing_alpha" qualifiers="const" >
+ <method name="is_editing_alpha" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -6925,25 +7743,25 @@
<description>
</description>
<methods>
- <method name="set_color" >
+ <method name="set_color">
<argument index="0" name="color" type="Color">
</argument>
<description>
</description>
</method>
- <method name="get_color" qualifiers="const" >
+ <method name="get_color" qualifiers="const">
<return type="Color">
</return>
<description>
</description>
</method>
- <method name="set_edit_alpha" >
+ <method name="set_edit_alpha">
<argument index="0" name="show" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_editing_alpha" qualifiers="const" >
+ <method name="is_editing_alpha" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -6985,22 +7803,116 @@
</theme_item>
</theme_items>
</class>
+<class name="ColorRamp" inherits="Resource" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="add_point">
+ <argument index="0" name="offset" type="float">
+ </argument>
+ <argument index="1" name="color" type="Color">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="remove_point">
+ <argument index="0" name="offset" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_offset">
+ <argument index="0" name="point" type="int">
+ </argument>
+ <argument index="1" name="offset" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_offset" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="point" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_color">
+ <argument index="0" name="point" type="int">
+ </argument>
+ <argument index="1" name="color" type="Color">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_color" qualifiers="const">
+ <return type="Color">
+ </return>
+ <argument index="0" name="point" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="interpolate">
+ <return type="Color">
+ </return>
+ <argument index="0" name="offset" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_point_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_offsets">
+ <argument index="0" name="offsets" type="RealArray">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_offsets" qualifiers="const">
+ <return type="RealArray">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_colors">
+ <argument index="0" name="colors" type="ColorArray">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_colors" qualifiers="const">
+ <return type="ColorArray">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
<class name="ConcavePolygonShape" inherits="Shape" category="Core">
<brief_description>
Concave polygon shape.
</brief_description>
<description>
- Concave polygon shape resource, which can be set into a [PhysicsBody] or area."#10; This shape is created by feeding a list of triangles.
+ Concave polygon shape resource, which can be set into a [PhysicsBody] or area. This shape is created by feeding a list of triangles.
</description>
<methods>
- <method name="set_faces" >
+ <method name="set_faces">
<argument index="0" name="faces" type="Vector3Array">
</argument>
<description>
Set the faces (an array of triangles).
</description>
</method>
- <method name="get_faces" qualifiers="const" >
+ <method name="get_faces" qualifiers="const">
<return type="Vector3Array">
</return>
<description>
@@ -7017,16 +7929,17 @@
</brief_description>
<description>
Concave polygon 2D shape resource for physics. It is made out of segments and is very optimal for complex polygonal concave collisions. It is really not advised to use for RigidBody nodes. A CollisionPolygon2D in convex decomposition mode (solids) or several convex objects are advised for that instead. Otherwise, a concave polygon 2D shape is better for static collisions.
+ The main difference between a [ConvexPolygonShape2D] and a [ConcavePolygonShape2D] is that a concave polygon assumes it is concave and uses a more complex method of collision detection, and a convex one forces itself to be convex in order to speed up collision detection.
</description>
<methods>
- <method name="set_segments" >
+ <method name="set_segments">
<argument index="0" name="segments" type="Vector2Array">
</argument>
<description>
Set the array of segments.
</description>
</method>
- <method name="get_segments" qualifiers="const" >
+ <method name="get_segments" qualifiers="const">
<return type="Vector2Array">
</return>
<description>
@@ -7043,7 +7956,7 @@
<description>
</description>
<methods>
- <method name="set_param" >
+ <method name="set_param">
<argument index="0" name="param" type="int">
</argument>
<argument index="1" name="value" type="float">
@@ -7051,7 +7964,7 @@
<description>
</description>
</method>
- <method name="get_param" qualifiers="const" >
+ <method name="get_param" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="param" type="int">
@@ -7081,7 +7994,7 @@
<description>
</description>
<methods>
- <method name="set_value" >
+ <method name="set_value">
<argument index="0" name="section" type="String">
</argument>
<argument index="1" name="key" type="String">
@@ -7091,15 +8004,17 @@
<description>
</description>
</method>
- <method name="get_value" qualifiers="const" >
+ <method name="get_value" qualifiers="const">
<argument index="0" name="section" type="String">
</argument>
<argument index="1" name="key" type="String">
</argument>
+ <argument index="2" name="default" type="var" default="NULL">
+ </argument>
<description>
</description>
</method>
- <method name="has_section" qualifiers="const" >
+ <method name="has_section" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="section" type="String">
@@ -7107,7 +8022,7 @@
<description>
</description>
</method>
- <method name="has_section_key" qualifiers="const" >
+ <method name="has_section_key" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="section" type="String">
@@ -7117,30 +8032,30 @@
<description>
</description>
</method>
- <method name="get_sections" qualifiers="const" >
+ <method name="get_sections" qualifiers="const">
<return type="StringArray">
</return>
<description>
</description>
</method>
- <method name="get_section_keys" qualifiers="const" >
+ <method name="get_section_keys" qualifiers="const">
<return type="StringArray">
</return>
- <argument index="0" name="arg0" type="String">
+ <argument index="0" name="section" type="String">
</argument>
<description>
</description>
</method>
- <method name="load" >
- <return type="int">
+ <method name="load">
+ <return type="Error">
</return>
<argument index="0" name="path" type="String">
</argument>
<description>
</description>
</method>
- <method name="save" >
- <return type="int">
+ <method name="save">
+ <return type="Error">
</return>
<argument index="0" name="path" type="String">
</argument>
@@ -7159,7 +8074,7 @@
Dialog for confirmation of actions. This dialog inherits from [AcceptDialog], but has by default an OK and Cancel buton (in host OS order).
</description>
<methods>
- <method name="get_cancel" >
+ <method name="get_cancel">
<return type="Button">
</return>
<description>
@@ -7179,12 +8094,12 @@
A Control can inherit this to reate custom container classes.
</description>
<methods>
- <method name="queue_sort" >
+ <method name="queue_sort">
<description>
Queue resort of the contained children. This is called automatically anyway, but can be called upon request.
</description>
</method>
- <method name="fit_child_in_rect" >
+ <method name="fit_child_in_rect">
<argument index="0" name="child" type="Control">
</argument>
<argument index="1" name="rect" type="Rect2">
@@ -7221,14 +8136,14 @@
Finally, controls are skinned according to a [Theme]. Setting a [Theme] on a control will propagate all the skinning down the tree. Optionally, skinning can be overrided per each control by calling the add_*_override functions, or from the editor.
</description>
<methods>
- <method name="_input_event" qualifiers="virtual" >
+ <method name="_input_event" qualifiers="virtual">
<argument index="0" name="event" type="InputEvent">
</argument>
<description>
Called when an input event reaches the control.
</description>
</method>
- <method name="can_drop_data" qualifiers="virtual" >
+ <method name="can_drop_data" qualifiers="virtual">
<return type="bool">
</return>
<argument index="0" name="pos" type="Vector2">
@@ -7238,7 +8153,7 @@
<description>
</description>
</method>
- <method name="drop_data" qualifiers="virtual" >
+ <method name="drop_data" qualifiers="virtual">
<argument index="0" name="pos" type="Vector2">
</argument>
<argument index="1" name="data" type="var">
@@ -7246,7 +8161,7 @@
<description>
</description>
</method>
- <method name="get_drag_data" qualifiers="virtual" >
+ <method name="get_drag_data" qualifiers="virtual">
<return type="Object">
</return>
<argument index="0" name="pos" type="Vector2">
@@ -7254,46 +8169,46 @@
<description>
</description>
</method>
- <method name="get_minimum_size" qualifiers="virtual" >
+ <method name="get_minimum_size" qualifiers="virtual">
<return type="Vector2">
</return>
<description>
Return the minimum size this Control can shrink to. A control will never be displayed or resized smaller than its minimum size.
</description>
</method>
- <method name="accept_event" >
+ <method name="accept_event">
<description>
Handles the event, no other control will receive it and it will not be sent to nodes waiting on [method Node._unhandled_input] or [method Node._unhandled_key_input].
</description>
</method>
- <method name="get_minimum_size" qualifiers="const" >
+ <method name="get_minimum_size" qualifiers="const">
<return type="Vector2">
</return>
<description>
Return the minimum size this Control can shrink to. A control will never be displayed or resized smaller than its minimum size.
</description>
</method>
- <method name="get_combined_minimum_size" qualifiers="const" >
+ <method name="get_combined_minimum_size" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="is_window" qualifiers="const" >
+ <method name="is_window" qualifiers="const">
<return type="bool">
</return>
<description>
Return wether this control is a [i]window[/i]. Controls are considered windows when their parent [Node] is not a Control.
</description>
</method>
- <method name="get_window" qualifiers="const" >
+ <method name="get_window" qualifiers="const">
<return type="Object">
</return>
<description>
Return the [i]window[/i] for this control, ascending the scene tree (see [method is_window]).
</description>
</method>
- <method name="set_anchor" >
+ <method name="set_anchor">
<argument index="0" name="margin" type="int">
</argument>
<argument index="1" name="anchor_mode" type="int">
@@ -7302,7 +8217,7 @@
Change the anchor (ANCHOR_BEGIN, ANCHOR_END, ANCHOR_RATIO) type for a margin (MARGIN_LEFT, MARGIN_TOP, MARGIN_RIGHT, MARGIN_BOTTOM). Changing the anchor mode converts the current margin offset from the previos anchor mode to the new one, so margin offsets ([method set_margin]) must be done after setting anchors, or at the same time ([method set_anchor_and_margin]).
</description>
</method>
- <method name="get_anchor" qualifiers="const" >
+ <method name="get_anchor" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="margin" type="int">
@@ -7311,7 +8226,7 @@
Return the anchor type (ANCHOR_BEGIN, ANCHOR_END, ANCHOR_RATIO) for a given margin (MARGIN_LEFT, MARGIN_TOP, MARGIN_RIGHT, MARGIN_BOTTOM).
</description>
</method>
- <method name="set_margin" >
+ <method name="set_margin">
<argument index="0" name="margin" type="int">
</argument>
<argument index="1" name="offset" type="float">
@@ -7320,7 +8235,7 @@
Set a margin offset. Margin can be one of (MARGIN_LEFT, MARGIN_TOP, MARGIN_RIGHT, MARGIN_BOTTOM). Offset value being set depends on the anchor mode.
</description>
</method>
- <method name="set_anchor_and_margin" >
+ <method name="set_anchor_and_margin">
<argument index="0" name="margin" type="int">
</argument>
<argument index="1" name="anchor_mode" type="int">
@@ -7331,48 +8246,60 @@
Change the anchor (ANCHOR_BEGIN, ANCHOR_END, ANCHOR_RATIO) type for a margin (MARGIN_LEFT, MARGIN_TOP, MARGIN_RIGHT, MARGIN_BOTTOM), and also set its offset. This is a helper (see [method set_anchor] and [method set_margin]).
</description>
</method>
- <method name="set_begin" >
+ <method name="set_begin">
<argument index="0" name="pos" type="Vector2">
</argument>
<description>
Sets MARGIN_LEFT and MARGIN_TOP at the same time. This is a helper (see [method set_margin]).
</description>
</method>
- <method name="set_end" >
+ <method name="set_end">
<argument index="0" name="pos" type="Vector2">
</argument>
<description>
Sets MARGIN_RIGHT and MARGIN_BOTTOM at the same time. This is a helper (see [method set_margin]).
</description>
</method>
- <method name="set_pos" >
+ <method name="set_pos">
<argument index="0" name="pos" type="Vector2">
</argument>
<description>
Move the Control to a new position, relative to the top-left corner of the parent Control, changing all margins if needed and without changing current anchor mode. This is a helper (see [method set_margin]).
</description>
</method>
- <method name="set_size" >
+ <method name="set_size">
<argument index="0" name="size" type="Vector2">
</argument>
<description>
Changes MARGIN_RIGHT and MARGIN_BOTTOM to fit a given size. This is a helper (see [method set_margin]).
</description>
</method>
- <method name="set_custom_minimum_size" >
+ <method name="set_custom_minimum_size">
<argument index="0" name="size" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="set_global_pos" >
+ <method name="set_global_pos">
<argument index="0" name="pos" type="Vector2">
</argument>
<description>
Move the Control to a new position, relative to the top-left corner of the [i]window[/i] Control, and without changing current anchor mode. (see [method set_margin]).
</description>
</method>
- <method name="get_margin" qualifiers="const" >
+ <method name="set_rotation">
+ <argument index="0" name="rotation" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_scale">
+ <argument index="0" name="scale" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_margin" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="margin" type="int">
@@ -7381,168 +8308,180 @@
Return a margin offset. Margin can be one of (MARGIN_LEFT, MARGIN_TOP, MARGIN_RIGHT, MARGIN_BOTTOM). Offset value being returned depends on the anchor mode.
</description>
</method>
- <method name="get_begin" qualifiers="const" >
+ <method name="get_begin" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="get_end" qualifiers="const" >
+ <method name="get_end" qualifiers="const">
<return type="Vector2">
</return>
<description>
Returns MARGIN_LEFT and MARGIN_TOP at the same time. This is a helper (see [method set_margin]).
</description>
</method>
- <method name="get_pos" qualifiers="const" >
+ <method name="get_pos" qualifiers="const">
<return type="Vector2">
</return>
<description>
Returns the Control position, relative to the top-left corner of the parent Control and independly of the anchor mode.
</description>
</method>
- <method name="get_size" qualifiers="const" >
+ <method name="get_size" qualifiers="const">
<return type="Vector2">
</return>
<description>
Returns the size of the Control, computed from all margins, however the size returned will [b]never be smaller than the minimum size reported by [method get_minimum_size][/b]. This means that even if end position of the Control rectangle is smaller than the begin position, the Control will still display and interact correctly. (see description, [method get_minimum_size], [method set_margin], [method set_anchor]).
</description>
</method>
- <method name="get_custom_minimum_size" qualifiers="const" >
+ <method name="get_rotation" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_scale" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="get_parent_area_size" qualifiers="const" >
+ <method name="get_custom_minimum_size" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="get_global_pos" qualifiers="const" >
+ <method name="get_parent_area_size" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_global_pos" qualifiers="const">
<return type="Vector2">
</return>
<description>
Returns the Control position, relative to the top-left corner of the parent Control and independent of the anchor mode.
</description>
</method>
- <method name="get_rect" qualifiers="const" >
+ <method name="get_rect" qualifiers="const">
<return type="Rect2">
</return>
<description>
Return position and size of the Control, relative to the top-left corner of the parent Control. This is a helper (see [method get_pos],[method get_size]).
</description>
</method>
- <method name="get_global_rect" qualifiers="const" >
+ <method name="get_global_rect" qualifiers="const">
<return type="Rect2">
</return>
<description>
Return position and size of the Control, relative to the top-left corner of the [i]window[/i] Control. This is a helper (see [method get_global_pos],[method get_size]).
</description>
</method>
- <method name="set_area_as_parent_rect" >
+ <method name="set_area_as_parent_rect">
<argument index="0" name="margin" type="int" default="0">
</argument>
<description>
Change all margins and anchors, so this Control always takes up the same area as the parent Control. This is a helper (see [method set_anchor],[method set_margin]).
</description>
</method>
- <method name="show_modal" >
+ <method name="show_modal">
<argument index="0" name="exclusive" type="bool" default="false">
</argument>
<description>
Display a Control as modal. Control must be a subwindow (see [method set_as_subwindow]). Modal controls capture the input signals until closed or the area outside them is accessed. When a modal control loses focus, or the ESC key is pressed, they automatically hide. Modal controls are used extensively for popup dialogs and menus.
</description>
</method>
- <method name="set_focus_mode" >
+ <method name="set_focus_mode">
<argument index="0" name="mode" type="int">
</argument>
<description>
Set the focus access mode for the control (FOCUS_NONE, FOCUS_CLICK, FOCUS_ALL). Only one Control can be focused at the same time, and it will receive keyboard signals.
</description>
</method>
- <method name="has_focus" qualifiers="const" >
+ <method name="has_focus" qualifiers="const">
<return type="bool">
</return>
<description>
Return wether the Control is the current focused control (see [method set_focus_mode]).
</description>
</method>
- <method name="grab_focus" >
+ <method name="grab_focus">
<description>
Steal the focus from another control and become the focused control (see [method set_focus_mode]).
</description>
</method>
- <method name="release_focus" >
+ <method name="release_focus">
<description>
Give up the focus, no other control will be able to receive keyboard input.
</description>
</method>
- <method name="get_focus_owner" qualifiers="const" >
+ <method name="get_focus_owner" qualifiers="const">
<return type="Control">
</return>
<description>
Return which control is owning the keyboard focus, or null if no one.
</description>
</method>
- <method name="set_h_size_flags" >
+ <method name="set_h_size_flags">
<argument index="0" name="flags" type="int">
</argument>
<description>
Hint for containers, set horizontal positioning flags.
</description>
</method>
- <method name="get_h_size_flags" qualifiers="const" >
+ <method name="get_h_size_flags" qualifiers="const">
<return type="int">
</return>
<description>
Hint for containers, return horizontal positioning flags.
</description>
</method>
- <method name="set_stretch_ratio" >
+ <method name="set_stretch_ratio">
<argument index="0" name="ratio" type="float">
</argument>
<description>
Hint for containers, set the stretch ratio. This value is relative to other stretch ratio, so if this control has 2 and another has 1, this one will be twice as big.
</description>
</method>
- <method name="get_stretch_ratio" qualifiers="const" >
+ <method name="get_stretch_ratio" qualifiers="const">
<return type="float">
</return>
<description>
Hint for containers, return the stretch ratio. This value is relative to other stretch ratio, so if this control has 2 and another has 1, this one will be twice as big.
</description>
</method>
- <method name="set_v_size_flags" >
+ <method name="set_v_size_flags">
<argument index="0" name="flags" type="int">
</argument>
<description>
Hint for containers, set vertical positioning flags.
</description>
</method>
- <method name="get_v_size_flags" qualifiers="const" >
+ <method name="get_v_size_flags" qualifiers="const">
<return type="int">
</return>
<description>
Hint for containers, return vertical positioning flags.
</description>
</method>
- <method name="set_theme" >
+ <method name="set_theme">
<argument index="0" name="theme" type="Theme">
</argument>
<description>
Override whole the [Theme] for this Control and all its children controls.
</description>
</method>
- <method name="get_theme" qualifiers="const" >
+ <method name="get_theme" qualifiers="const">
<return type="Theme">
</return>
<description>
Return a [Theme] override, if one exists (see [method set_theme]).
</description>
</method>
- <method name="add_icon_override" >
+ <method name="add_icon_override">
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="texture" type="Texture">
@@ -7551,7 +8490,7 @@
Override a single icon ([Texture]) in the theme of this Control. If texture is empty, override is cleared.
</description>
</method>
- <method name="add_style_override" >
+ <method name="add_style_override">
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="stylebox" type="StyleBox">
@@ -7560,7 +8499,7 @@
Override a single stylebox ([Stylebox]) in the theme of this Control. If stylebox is empty, override is cleared.
</description>
</method>
- <method name="add_font_override" >
+ <method name="add_font_override">
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="font" type="Font">
@@ -7569,7 +8508,7 @@
Override a single font (font) in the theme of this Control. If font is empty, override is cleared.
</description>
</method>
- <method name="add_color_override" >
+ <method name="add_color_override">
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="color" type="Color">
@@ -7577,7 +8516,7 @@
<description>
</description>
</method>
- <method name="add_constant_override" >
+ <method name="add_constant_override">
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="constant" type="int">
@@ -7586,7 +8525,7 @@
Override a single constant (integer) in the theme of this Control. If constant equals Theme.INVALID_CONSTANT, override is cleared.
</description>
</method>
- <method name="get_icon" qualifiers="const" >
+ <method name="get_icon" qualifiers="const">
<return type="Texture">
</return>
<argument index="0" name="name" type="String">
@@ -7596,7 +8535,7 @@
<description>
</description>
</method>
- <method name="get_stylebox" qualifiers="const" >
+ <method name="get_stylebox" qualifiers="const">
<return type="StyleBox">
</return>
<argument index="0" name="name" type="String">
@@ -7606,7 +8545,7 @@
<description>
</description>
</method>
- <method name="get_font" qualifiers="const" >
+ <method name="get_font" qualifiers="const">
<return type="Font">
</return>
<argument index="0" name="name" type="String">
@@ -7616,7 +8555,7 @@
<description>
</description>
</method>
- <method name="get_color" qualifiers="const" >
+ <method name="get_color" qualifiers="const">
<return type="Color">
</return>
<argument index="0" name="name" type="String">
@@ -7626,7 +8565,7 @@
<description>
</description>
</method>
- <method name="get_constant" qualifiers="const" >
+ <method name="get_constant" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="name" type="String">
@@ -7636,20 +8575,20 @@
<description>
</description>
</method>
- <method name="get_parent_control" qualifiers="const" >
+ <method name="get_parent_control" qualifiers="const">
<return type="Control">
</return>
<description>
</description>
</method>
- <method name="set_tooltip" >
+ <method name="set_tooltip">
<argument index="0" name="tooltip" type="String">
</argument>
<description>
Set a tooltip, which will appear when the cursor is resting over this control.
</description>
</method>
- <method name="get_tooltip" qualifiers="const" >
+ <method name="get_tooltip" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="atpos" type="Vector2" default="Vector2(0,0)">
@@ -7658,21 +8597,21 @@
Return the tooltip, which will appear when the cursor is resting over this control.
</description>
</method>
- <method name="set_default_cursor_shape" >
+ <method name="set_default_cursor_shape">
<argument index="0" name="shape" type="int">
</argument>
<description>
Set the default cursor shape for this control. See enum CURSOR_* for the list of shapes.
</description>
</method>
- <method name="get_default_cursor_shape" qualifiers="const" >
+ <method name="get_default_cursor_shape" qualifiers="const">
<return type="int">
</return>
<description>
Return the default cursor shape for this control. See enum CURSOR_* for the list of shapes.
</description>
</method>
- <method name="get_cursor_shape" qualifiers="const" >
+ <method name="get_cursor_shape" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="pos" type="Vector2" default="Vector2(0,0)">
@@ -7681,7 +8620,7 @@
Return the cursor shape at a certain position in the control.
</description>
</method>
- <method name="set_focus_neighbour" >
+ <method name="set_focus_neighbour">
<argument index="0" name="margin" type="int">
</argument>
<argument index="1" name="neighbour" type="NodePath">
@@ -7690,7 +8629,7 @@
Force a neighbour for moving the input focus to. When pressing TAB or directional/joypad directions focus is moved to the next control in that direction. However, the neighbour to move to can be forced with this function.
</description>
</method>
- <method name="get_focus_neighbour" qualifiers="const" >
+ <method name="get_focus_neighbour" qualifiers="const">
<return type="NodePath">
</return>
<argument index="0" name="margin" type="int">
@@ -7699,21 +8638,21 @@
Return the forced neighbour for moving the input focus to. When pressing TAB or directional/joypad directions focus is moved to the next control in that direction. However, the neighbour to move to can be forced with this function.
</description>
</method>
- <method name="set_ignore_mouse" >
+ <method name="set_ignore_mouse">
<argument index="0" name="ignore" type="bool">
</argument>
<description>
Ignore mouse events on this control (even touchpad events send mouse events).
</description>
</method>
- <method name="is_ignoring_mouse" qualifiers="const" >
+ <method name="is_ignoring_mouse" qualifiers="const">
<return type="bool">
</return>
<description>
Return if the control is ignoring mouse events (even touchpad events send mouse events).
</description>
</method>
- <method name="force_drag" >
+ <method name="force_drag">
<argument index="0" name="data" type="var">
</argument>
<argument index="1" name="preview" type="Object">
@@ -7721,28 +8660,34 @@
<description>
</description>
</method>
- <method name="set_stop_mouse" >
+ <method name="set_stop_mouse">
<argument index="0" name="stop" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_stopping_mouse" qualifiers="const" >
+ <method name="is_stopping_mouse" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="grab_click_focus" >
+ <method name="grab_click_focus">
<description>
</description>
</method>
- <method name="set_drag_preview" >
+ <method name="set_drag_preview">
<argument index="0" name="control" type="Control">
</argument>
<description>
</description>
</method>
+ <method name="warp_mouse">
+ <argument index="0" name="to_pos" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<signals>
<signal name="focus_enter">
@@ -7776,6 +8721,8 @@
</description>
</signal>
<signal name="input_event">
+ <argument index="0" name="ev" type="InputEvent">
+ </argument>
<description>
Emitted when an input event is received. Connecting in realtime is recommended for accepting the events.
</description>
@@ -7788,10 +8735,10 @@
</signals>
<constants>
<constant name="ANCHOR_BEGIN" value="0">
- X is relative to MARGIN_LEFT, Y is relative to MARGIN_TOP,
+ X is relative to MARGIN_LEFT, Y is relative to MARGIN_TOP.
</constant>
<constant name="ANCHOR_END" value="1">
- X is relative to -MARGIN_RIGHT, Y is relative to -MARGIN_BOTTOM,
+ X is relative to -MARGIN_RIGHT, Y is relative to -MARGIN_BOTTOM.
</constant>
<constant name="ANCHOR_RATIO" value="2">
X and Y are a ratio (0 to 1) relative to the parent size 0 is left/top, 1 is right/bottom.
@@ -7872,19 +8819,19 @@
</class>
<class name="ConvexPolygonShape" inherits="Shape" category="Core">
<brief_description>
- Convex Polygon Shape
+ Convex Polygon Shape.
</brief_description>
<description>
Convex polygon shape resource, which can be set into a [PhysicsBody] or area.
</description>
<methods>
- <method name="set_points" >
+ <method name="set_points">
<argument index="0" name="points" type="Vector3Array">
</argument>
<description>
</description>
</method>
- <method name="get_points" qualifiers="const" >
+ <method name="get_points" qualifiers="const">
<return type="Vector3Array">
</return>
<description>
@@ -7896,27 +8843,28 @@
</class>
<class name="ConvexPolygonShape2D" inherits="Shape2D" category="Core">
<brief_description>
- Convex Polygon Shape for 2D physics
+ Convex Polygon Shape for 2D physics.
</brief_description>
<description>
- Convex Polygon Shape for 2D physics.
+ Convex Polygon Shape for 2D physics. A convex polygon, whatever its shape, is internally decomposed into as many convex polygons as needed to ensure all collision checks against it are always done on convex polygons (which are faster to check).
+ The main difference between a [ConvexPolygonShape2D] and a [ConcavePolygonShape2D] is that a concave polygon assumes it is concave and uses a more complex method of collision detection, and a convex one forces itself to be convex in order to speed up collision detection.
</description>
<methods>
- <method name="set_point_cloud" >
+ <method name="set_point_cloud">
<argument index="0" name="point_cloud" type="Vector2Array">
</argument>
<description>
- Create the point set from a point cloud. The resulting convex hull will be set as the shape.
+ Currently, this method does nothing.
</description>
</method>
- <method name="set_points" >
+ <method name="set_points">
<argument index="0" name="points" type="Vector2Array">
</argument>
<description>
Set a list of points in either clockwise or counter clockwise order, forming a convex polygon.
</description>
</method>
- <method name="get_points" qualifiers="const" >
+ <method name="get_points" qualifiers="const">
<return type="Vector2Array">
</return>
<description>
@@ -7933,37 +8881,37 @@
<description>
</description>
<methods>
- <method name="get_width" qualifiers="const" >
+ <method name="get_width" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_height" qualifiers="const" >
+ <method name="get_height" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_rid" qualifiers="const" >
+ <method name="get_rid" qualifiers="const">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="set_flags" >
+ <method name="set_flags">
<argument index="0" name="flags" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_flags" qualifiers="const" >
+ <method name="get_flags" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_side" >
+ <method name="set_side">
<argument index="0" name="side" type="int">
</argument>
<argument index="1" name="image" type="Image">
@@ -7971,7 +8919,7 @@
<description>
</description>
</method>
- <method name="get_side" qualifiers="const" >
+ <method name="get_side" qualifiers="const">
<return type="Image">
</return>
<argument index="0" name="side" type="int">
@@ -7979,25 +8927,25 @@
<description>
</description>
</method>
- <method name="set_storage" >
+ <method name="set_storage">
<argument index="0" name="mode" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_storage" qualifiers="const" >
+ <method name="get_storage" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_lossy_storage_quality" >
+ <method name="set_lossy_storage_quality">
<argument index="0" name="quality" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_lossy_storage_quality" qualifiers="const" >
+ <method name="get_lossy_storage_quality" qualifiers="const">
<return type="float">
</return>
<description>
@@ -8035,17 +8983,21 @@
</class>
<class name="Curve2D" inherits="Resource" category="Core">
<brief_description>
+ Describes a Bezier curve in 2D space.
</brief_description>
<description>
+ This class describes a Bezier curve in 2D space. It is mainly used to give a shape to a [Path2D], but can be manually sampled for other purposes.
+It keeps a cache of precalculated points along the curve, to speed further calculations up.
</description>
<methods>
- <method name="get_point_count" qualifiers="const" >
+ <method name="get_point_count" qualifiers="const">
<return type="int">
</return>
<description>
+ Returns the number of points describing the curve.
</description>
</method>
- <method name="add_point" >
+ <method name="add_point">
<argument index="0" name="pos" type="Vector2">
</argument>
<argument index="1" name="in" type="Vector2" default="Vector2(0,0)">
@@ -8055,63 +9007,72 @@
<argument index="3" name="atpos" type="int" default="-1">
</argument>
<description>
+ Adds a point to a curve, at position "pos", with control points "in" and "out".
+If "atpos" is given, the point is inserted before the point number "atpos", moving that point (and every point after) after the inserted point. If "atpos" is not given, or is an illegal value (atpos &lt;0 or atpos &gt;= [method get_point_count]), the point will be appended at the end of the point list.
</description>
</method>
- <method name="set_point_pos" >
+ <method name="set_point_pos">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="pos" type="Vector2">
</argument>
<description>
+ Sets the position for the vertex "idx". If the index is out of bounds, the function sends an error to the console.
</description>
</method>
- <method name="get_point_pos" qualifiers="const" >
+ <method name="get_point_pos" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="idx" type="int">
</argument>
<description>
+ Returns the position of the vertex "idx". If the index is out of bounds, the function sends an error to the console, and returns (0, 0).
</description>
</method>
- <method name="set_point_in" >
+ <method name="set_point_in">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="pos" type="Vector2">
</argument>
<description>
+ Sets the position of the control point leading to the vertex "idx". If the index is out of bounds, the function sends an error to the console.
</description>
</method>
- <method name="get_point_in" qualifiers="const" >
+ <method name="get_point_in" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="idx" type="int">
</argument>
<description>
+ Returns the position of the control point leading to the vertex "idx". If the index is out of bounds, the function sends an error to the console, and returns (0, 0).
</description>
</method>
- <method name="set_point_out" >
+ <method name="set_point_out">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="pos" type="Vector2">
</argument>
<description>
+ Sets the position of the control point leading out of the vertex "idx". If the index is out of bounds, the function sends an error to the console.
</description>
</method>
- <method name="get_point_out" qualifiers="const" >
+ <method name="get_point_out" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="idx" type="int">
</argument>
<description>
+ Returns the position of the control point leading out of the vertex "idx". If the index is out of bounds, the function sends an error to the console, and returns (0, 0).
</description>
</method>
- <method name="remove_point" >
+ <method name="remove_point">
<argument index="0" name="idx" type="int">
</argument>
<description>
+ Deletes the point "idx" from the curve. Sends an error to the console if "idx" is out of bounds.
</description>
</method>
- <method name="interpolate" qualifiers="const" >
+ <method name="interpolate" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="idx" type="int">
@@ -8119,35 +9080,41 @@
<argument index="1" name="t" type="float">
</argument>
<description>
+ Returns the position between the vertex "idx" and the vertex "idx"+1, where "t" controls if the point is the first vertex (t = 0.0), the last vertex (t = 1.0), or in between. Values of "t" outside the range (0.0 &gt;= t &lt;=1) give strange, but predictable results.
+If "idx" is out of bounds it is truncated to the first or last vertex, and "t" is ignored. If the curve has no points, the function sends an error to the console, and returns (0, 0).
</description>
</method>
- <method name="interpolatef" qualifiers="const" >
+ <method name="interpolatef" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="fofs" type="float">
</argument>
<description>
+ Returns the position at the vertex "fofs". It calls [method interpolate] using the integer part of fofs as "idx", and its fractional part as "t".
</description>
</method>
- <method name="set_bake_interval" >
+ <method name="set_bake_interval">
<argument index="0" name="distance" type="float">
</argument>
<description>
+ Sets the distance in pixels between two adjacent cached points. Changing it forces the cache to be recomputed the next time a xxx_baked_xxx function is called. The less distance, the more points the cache will have, and the more memory it will consume, so use with care.
</description>
</method>
- <method name="get_bake_interval" qualifiers="const" >
+ <method name="get_bake_interval" qualifiers="const">
<return type="float">
</return>
<description>
+ Returns the distance between two adjacent cached points.
</description>
</method>
- <method name="get_baked_length" qualifiers="const" >
+ <method name="get_baked_length" qualifiers="const">
<return type="float">
</return>
<description>
+ Returns the total length of the curve, based on the cached points. Given enough density (see [method set_bake_interval]), it should be approximate enough.
</description>
</method>
- <method name="interpolate_baked" qualifiers="const" >
+ <method name="interpolate_baked" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="offset" type="float">
@@ -8155,12 +9122,30 @@
<argument index="1" name="cubic" type="bool" default="false">
</argument>
<description>
+ Returns a point within the curve at position "offset", where "offset" is measured as a pixel distance along the curve.
+To do that, it finds the two cached points where the "offset" lies between, then interpolates the values. This interpolation is cubic if "cubic" is set to true, or linear if set to false.
+Cubic interpolation tends to follow the curves better, but linear is faster (and often, precise enough).
</description>
</method>
- <method name="get_baked_points" qualifiers="const" >
+ <method name="get_baked_points" qualifiers="const">
<return type="Vector2Array">
</return>
<description>
+ Returns the cache of points as a [Vector2Array].
+ </description>
+ </method>
+ <method name="tesselate" qualifiers="const">
+ <return type="Vector2Array">
+ </return>
+ <argument index="0" name="max_stages" type="int" default="5">
+ </argument>
+ <argument index="1" name="tolerance_degrees" type="float" default="4">
+ </argument>
+ <description>
+ Returns a list of points along the curve, with a curvature controlled point density. That is, the curvier parts will have more points than the straighter parts.
+This approximation makes straight segments between each point, then subdivides those segments until the resulting shape is similar enough.
+"max_stages" controls how many subdivisions a curve segment may face before it is considered approximate enough. Each subdivision splits the segment in half, so the default 5 stages may mean up to 32 subdivisions per curve segment. Increase with care!
+"tolerance_degrees" controls how many degrees the midpoint of a segment may deviate from the real curve, before the segment has to be subdivided.
</description>
</method>
</methods>
@@ -8169,17 +9154,21 @@
</class>
<class name="Curve3D" inherits="Resource" category="Core">
<brief_description>
+ Describes a Bezier curve in 3D space.
</brief_description>
<description>
+ This class describes a Bezier curve in 3D space. It is mainly used to give a shape to a [Path], but can be manually sampled for other purposes.
+It keeps a cache of precalculated points along the curve, to speed further calculations up.
</description>
<methods>
- <method name="get_point_count" qualifiers="const" >
+ <method name="get_point_count" qualifiers="const">
<return type="int">
</return>
<description>
+ Returns the number of points describing the curve.
</description>
</method>
- <method name="add_point" >
+ <method name="add_point">
<argument index="0" name="pos" type="Vector3">
</argument>
<argument index="1" name="in" type="Vector3" default="Vector3(0, 0, 0)">
@@ -8189,79 +9178,91 @@
<argument index="3" name="atpos" type="int" default="-1">
</argument>
<description>
+ Adds a point to a curve, at position "pos", with control points "in" and "out".
+If "atpos" is given, the point is inserted before the point number "atpos", moving that point (and every point after) after the inserted point. If "atpos" is not given, or is an illegal value (atpos &lt;0 or atpos &gt;= [method get_point_count]), the point will be appended at the end of the point list.
</description>
</method>
- <method name="set_point_pos" >
+ <method name="set_point_pos">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="pos" type="Vector3">
</argument>
<description>
+ Sets the position for the vertex "idx". If the index is out of bounds, the function sends an error to the console.
</description>
</method>
- <method name="get_point_pos" qualifiers="const" >
+ <method name="get_point_pos" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="idx" type="int">
</argument>
<description>
+ Returns the position of the vertex "idx". If the index is out of bounds, the function sends an error to the console, and returns (0, 0, 0).
</description>
</method>
- <method name="set_point_tilt" >
+ <method name="set_point_tilt">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="tilt" type="float">
</argument>
<description>
+ Sets the tilt angle in radians for the point "idx". If the index is out of bounds, the function sends an error to the console.
+The tilt controls the rotation along the look-at axis an object travelling the path would have. In the case of a curve controlling a [PathFollow], this tilt is an offset over the natural tilt the PathFollow calculates.
</description>
</method>
- <method name="get_point_tilt" qualifiers="const" >
+ <method name="get_point_tilt" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="idx" type="int">
</argument>
<description>
+ Returns the tilt angle in radians for the point "idx". If the index is out of bounds, the function sends an error to the console, and returns 0.
</description>
</method>
- <method name="set_point_in" >
+ <method name="set_point_in">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="pos" type="Vector3">
</argument>
<description>
+ Sets the position of the control point leading to the vertex "idx". If the index is out of bounds, the function sends an error to the console.
</description>
</method>
- <method name="get_point_in" qualifiers="const" >
+ <method name="get_point_in" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="idx" type="int">
</argument>
<description>
+ Returns the position of the control point leading to the vertex "idx". If the index is out of bounds, the function sends an error to the console, and returns (0, 0, 0).
</description>
</method>
- <method name="set_point_out" >
+ <method name="set_point_out">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="pos" type="Vector3">
</argument>
<description>
+ Sets the position of the control point leading out of the vertex "idx". If the index is out of bounds, the function sends an error to the console.
</description>
</method>
- <method name="get_point_out" qualifiers="const" >
+ <method name="get_point_out" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="idx" type="int">
</argument>
<description>
+ Returns the position of the control point leading out of the vertex "idx". If the index is out of bounds, the function sends an error to the console, and returns (0, 0, 0).
</description>
</method>
- <method name="remove_point" >
+ <method name="remove_point">
<argument index="0" name="idx" type="int">
</argument>
<description>
+ Deletes the point "idx" from the curve. Sends an error to the console if "idx" is out of bounds.
</description>
</method>
- <method name="interpolate" qualifiers="const" >
+ <method name="interpolate" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="idx" type="int">
@@ -8269,35 +9270,41 @@
<argument index="1" name="t" type="float">
</argument>
<description>
+ Returns the position between the vertex "idx" and the vertex "idx"+1, where "t" controls if the point is the first vertex (t = 0.0), the last vertex (t = 1.0), or in between. Values of "t" outside the range (0.0 &gt;= t &lt;=1) give strange, but predictable results.
+If "idx" is out of bounds it is truncated to the first or last vertex, and "t" is ignored. If the curve has no points, the function sends an error to the console, and returns (0, 0, 0).
</description>
</method>
- <method name="interpolatef" qualifiers="const" >
+ <method name="interpolatef" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="fofs" type="float">
</argument>
<description>
+ Returns the position at the vertex "fofs". It calls [method interpolate] using the integer part of fofs as "idx", and its fractional part as "t".
</description>
</method>
- <method name="set_bake_interval" >
+ <method name="set_bake_interval">
<argument index="0" name="distance" type="float">
</argument>
<description>
+ Sets the distance in 3D units between two adjacent cached points. Changing it forces the cache to be recomputed the next time a xxx_baked_xxx function is called. The less distance, the more points the cache will have, and the more memory it will consume, so use with care.
</description>
</method>
- <method name="get_bake_interval" qualifiers="const" >
+ <method name="get_bake_interval" qualifiers="const">
<return type="float">
</return>
<description>
+ Returns the distance between two adjacent cached points.
</description>
</method>
- <method name="get_baked_length" qualifiers="const" >
+ <method name="get_baked_length" qualifiers="const">
<return type="float">
</return>
<description>
+ Returns the total length of the curve, based on the cached points. Given enough density (see [method set_bake_interval]), it should be approximate enough.
</description>
</method>
- <method name="interpolate_baked" qualifiers="const" >
+ <method name="interpolate_baked" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="offset" type="float">
@@ -8305,18 +9312,37 @@
<argument index="1" name="cubic" type="bool" default="false">
</argument>
<description>
+ Returns a point within the curve at position "offset", where "offset" is measured as a distance in 3D units along the curve.
+To do that, it finds the two cached points where the "offset" lies between, then interpolates the values. This interpolation is cubic if "cubic" is set to true, or linear if set to false.
+Cubic interpolation tends to follow the curves better, but linear is faster (and often, precise enough).
</description>
</method>
- <method name="get_baked_points" qualifiers="const" >
+ <method name="get_baked_points" qualifiers="const">
<return type="Vector3Array">
</return>
<description>
+ Returns the cache of points as a [Vector3Array].
</description>
</method>
- <method name="get_baked_tilts" qualifiers="const" >
+ <method name="get_baked_tilts" qualifiers="const">
<return type="RealArray">
</return>
<description>
+ Returns the cache of tilts as a [RealArray].
+ </description>
+ </method>
+ <method name="tesselate" qualifiers="const">
+ <return type="Vector3Array">
+ </return>
+ <argument index="0" name="max_stages" type="int" default="5">
+ </argument>
+ <argument index="1" name="tolerance_degrees" type="float" default="4">
+ </argument>
+ <description>
+ Returns a list of points along the curve, with a curvature controlled point density. That is, the curvier parts will have more points than the straighter parts.
+This approximation makes straight segments between each point, then subdivides those segments until the resulting shape is similar enough.
+"max_stages" controls how many subdivisions a curve segment may face before it is considered approximate enough. Each subdivision splits the segment in half, so the default 5 stages may mean up to 32 subdivisions per curve segment. Increase with care!
+"tolerance_degrees" controls how many degrees the midpoint of a segment may deviate from the real curve, before the segment has to be subdivided.
</description>
</method>
</methods>
@@ -8325,62 +9351,62 @@
</class>
<class name="DampedSpringJoint2D" inherits="Joint2D" category="Core">
<brief_description>
- Damped sprint constraint for 2D physics.
+ Damped spring constraint for 2D physics.
</brief_description>
<description>
- Damped sprint constraint for 2D physics. This resembles a sprint joint that always want to go back to a given length.
+ Damped spring constraint for 2D physics. This resembles a spring joint that always want to go back to a given length.
</description>
<methods>
- <method name="set_length" >
+ <method name="set_length">
<argument index="0" name="length" type="float">
</argument>
<description>
- Set the maximum length of the sprint joint.
+ Set the maximum length of the spring joint.
</description>
</method>
- <method name="get_length" qualifiers="const" >
+ <method name="get_length" qualifiers="const">
<return type="float">
</return>
<description>
- Return the maximum length of the sprint joint.
+ Return the maximum length of the spring joint.
</description>
</method>
- <method name="set_rest_length" >
+ <method name="set_rest_length">
<argument index="0" name="rest_length" type="float">
</argument>
<description>
- Set the resting length of the sprint joint. The joint will always try to go to back this length when pulled apart.
+ Set the resting length of the spring joint. The joint will always try to go to back this length when pulled apart.
</description>
</method>
- <method name="get_rest_length" qualifiers="const" >
+ <method name="get_rest_length" qualifiers="const">
<return type="float">
</return>
<description>
- Return the resting length of the sprint joint. The joint will always try to go to back this length when pulled apart.
+ Return the resting length of the spring joint. The joint will always try to go to back this length when pulled apart.
</description>
</method>
- <method name="set_stiffness" >
+ <method name="set_stiffness">
<argument index="0" name="stiffness" type="float">
</argument>
<description>
Set the stiffness of the spring joint.
</description>
</method>
- <method name="get_stiffness" qualifiers="const" >
+ <method name="get_stiffness" qualifiers="const">
<return type="float">
</return>
<description>
Return the stiffness of the spring joint.
</description>
</method>
- <method name="set_damping" >
+ <method name="set_damping">
<argument index="0" name="damping" type="float">
</argument>
<description>
Set the damping of the spring joint.
</description>
</method>
- <method name="get_damping" qualifiers="const" >
+ <method name="get_damping" qualifiers="const">
<return type="float">
</return>
<description>
@@ -8399,26 +9425,26 @@
Dictionary type. Associative container which contains values referenced by unique keys. Dictionaries are always passed by reference.
</description>
<methods>
- <method name="clear" >
+ <method name="clear">
<description>
Clear the dictionary, removing all key/value pairs.
</description>
</method>
- <method name="empty" >
+ <method name="empty">
<return type="bool">
</return>
<description>
Return true if the dictionary is empty.
</description>
</method>
- <method name="erase" >
+ <method name="erase">
<argument index="0" name="value" type="var">
</argument>
<description>
Erase a dictionary key/value pair by key.
</description>
</method>
- <method name="has" >
+ <method name="has">
<return type="bool">
</return>
<argument index="0" name="value" type="var">
@@ -8427,21 +9453,21 @@
Return true if the dictionary has a given key.
</description>
</method>
- <method name="hash" >
+ <method name="hash">
<return type="int">
</return>
<description>
Return a hashed integer value representing the dictionary contents.
</description>
</method>
- <method name="keys" >
+ <method name="keys">
<return type="Array">
</return>
<description>
Return the list of keys in the dictionary.
</description>
</method>
- <method name="parse_json" >
+ <method name="parse_json">
<return type="int">
</return>
<argument index="0" name="json" type="String">
@@ -8449,14 +9475,14 @@
<description>
</description>
</method>
- <method name="size" >
+ <method name="size">
<return type="int">
</return>
<description>
Return the size of the dictionary (in pairs).
</description>
</method>
- <method name="to_json" >
+ <method name="to_json">
<return type="String">
</return>
<description>
@@ -8474,19 +9500,19 @@
A DirectionalLight is a type of [Light] node that emits light constantly in one direction (the negative z axis of the node). It is used lights with strong intensity that are located far away from the scene to model sunlight or moonlight. The worldpace location of the DirectionalLight transform (origin) is ignored, only the basis is used do determine light direction.
</description>
<methods>
- <method name="set_shadow_mode" >
+ <method name="set_shadow_mode">
<argument index="0" name="mode" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_shadow_mode" qualifiers="const" >
+ <method name="get_shadow_mode" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_shadow_param" >
+ <method name="set_shadow_param">
<argument index="0" name="param" type="int">
</argument>
<argument index="1" name="value" type="float">
@@ -8494,7 +9520,7 @@
<description>
</description>
</method>
- <method name="get_shadow_param" qualifiers="const" >
+ <method name="get_shadow_param" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="param" type="int">
@@ -8526,43 +9552,43 @@
<description>
</description>
<methods>
- <method name="open" >
- <return type="int">
+ <method name="open">
+ <return type="Error">
</return>
<argument index="0" name="path" type="String">
</argument>
<description>
</description>
</method>
- <method name="list_dir_begin" >
+ <method name="list_dir_begin">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="get_next" >
+ <method name="get_next">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="current_is_dir" qualifiers="const" >
+ <method name="current_is_dir" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="list_dir_end" >
+ <method name="list_dir_end">
<description>
</description>
</method>
- <method name="get_drive_count" >
+ <method name="get_drive_count">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_drive" >
+ <method name="get_drive">
<return type="String">
</return>
<argument index="0" name="idx" type="int">
@@ -8570,37 +9596,37 @@
<description>
</description>
</method>
- <method name="change_dir" >
- <return type="int">
+ <method name="change_dir">
+ <return type="Error">
</return>
<argument index="0" name="todir" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_current_dir" >
+ <method name="get_current_dir">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="make_dir" >
- <return type="int">
+ <method name="make_dir">
+ <return type="Error">
</return>
<argument index="0" name="name" type="String">
</argument>
<description>
</description>
</method>
- <method name="make_dir_recursive" >
- <return type="int">
+ <method name="make_dir_recursive">
+ <return type="Error">
</return>
<argument index="0" name="name" type="String">
</argument>
<description>
</description>
</method>
- <method name="file_exists" >
+ <method name="file_exists">
<return type="bool">
</return>
<argument index="0" name="name" type="String">
@@ -8608,7 +9634,7 @@
<description>
</description>
</method>
- <method name="dir_exists" >
+ <method name="dir_exists">
<return type="bool">
</return>
<argument index="0" name="name" type="String">
@@ -8616,14 +9642,14 @@
<description>
</description>
</method>
- <method name="get_space_left" >
+ <method name="get_space_left">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="copy" >
- <return type="int">
+ <method name="copy">
+ <return type="Error">
</return>
<argument index="0" name="from" type="String">
</argument>
@@ -8632,8 +9658,8 @@
<description>
</description>
</method>
- <method name="rename" >
- <return type="int">
+ <method name="rename">
+ <return type="Error">
</return>
<argument index="0" name="from" type="String">
</argument>
@@ -8642,16 +9668,164 @@
<description>
</description>
</method>
- <method name="remove" >
- <return type="int">
+ <method name="remove">
+ <return type="Error">
+ </return>
+ <argument index="0" name="file" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
+<class name="EditorFileDialog" inherits="ConfirmationDialog" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="clear_filters">
+ <description>
+ </description>
+ </method>
+ <method name="add_filter">
+ <argument index="0" name="filter" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_current_dir" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_current_file" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_current_path" qualifiers="const">
+ <return type="String">
</return>
+ <description>
+ </description>
+ </method>
+ <method name="set_current_dir">
+ <argument index="0" name="dir" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_current_file">
<argument index="0" name="file" type="String">
</argument>
<description>
</description>
</method>
+ <method name="set_current_path">
+ <argument index="0" name="path" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_mode">
+ <argument index="0" name="mode" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_mode" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_vbox">
+ <return type="VBoxContainer">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_access">
+ <argument index="0" name="access" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_access" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_show_hidden_files">
+ <argument index="0" name="show" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_showing_hidden_files" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_display_mode">
+ <argument index="0" name="mode" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_display_mode" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="invalidate">
+ <description>
+ </description>
+ </method>
</methods>
+ <signals>
+ <signal name="files_selected">
+ <argument index="0" name="paths" type="StringArray">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ <signal name="dir_selected">
+ <argument index="0" name="dir" type="String">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ <signal name="file_selected">
+ <argument index="0" name="path" type="String">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ </signals>
<constants>
+ <constant name="MODE_OPEN_FILE" value="0">
+ </constant>
+ <constant name="MODE_OPEN_FILES" value="1">
+ </constant>
+ <constant name="MODE_OPEN_DIR" value="2">
+ </constant>
+ <constant name="MODE_SAVE_FILE" value="3">
+ </constant>
+ <constant name="ACCESS_RESOURCES" value="0">
+ </constant>
+ <constant name="ACCESS_USERDATA" value="1">
+ </constant>
+ <constant name="ACCESS_FILESYSTEM" value="2">
+ </constant>
</constants>
</class>
<class name="EditorImportPlugin" inherits="Reference" category="Core">
@@ -8660,7 +9834,7 @@
<description>
</description>
<methods>
- <method name="custom_export" qualifiers="virtual" >
+ <method name="custom_export" qualifiers="virtual">
<return type="RawArray">
</return>
<argument index="0" name="path" type="String">
@@ -8668,19 +9842,19 @@
<description>
</description>
</method>
- <method name="get_name" qualifiers="virtual" >
+ <method name="get_name" qualifiers="virtual">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="get_visible_name" qualifiers="virtual" >
+ <method name="get_visible_name" qualifiers="virtual">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="import" qualifiers="virtual" >
+ <method name="import" qualifiers="virtual">
<return type="int">
</return>
<argument index="0" name="path" type="String">
@@ -8690,7 +9864,7 @@
<description>
</description>
</method>
- <method name="import_dialog" qualifiers="virtual" >
+ <method name="import_dialog" qualifiers="virtual">
<argument index="0" name="from" type="String">
</argument>
<description>
@@ -8706,21 +9880,21 @@
<description>
</description>
<methods>
- <method name="apply_changes" qualifiers="virtual" >
+ <method name="apply_changes" qualifiers="virtual">
<description>
</description>
</method>
- <method name="clear" qualifiers="virtual" >
+ <method name="clear" qualifiers="virtual">
<description>
</description>
</method>
- <method name="edit" qualifiers="virtual" >
+ <method name="edit" qualifiers="virtual">
<argument index="0" name="object" type="Object">
</argument>
<description>
</description>
</method>
- <method name="forward_input_event" qualifiers="virtual" >
+ <method name="forward_input_event" qualifiers="virtual">
<return type="bool">
</return>
<argument index="0" name="event" type="InputEvent">
@@ -8728,7 +9902,7 @@
<description>
</description>
</method>
- <method name="forward_spatial_input_event" qualifiers="virtual" >
+ <method name="forward_spatial_input_event" qualifiers="virtual">
<return type="bool">
</return>
<argument index="0" name="camera" type="Camera">
@@ -8738,25 +9912,25 @@
<description>
</description>
</method>
- <method name="get_breakpoints" qualifiers="virtual" >
+ <method name="get_breakpoints" qualifiers="virtual">
<return type="StringArray">
</return>
<description>
</description>
</method>
- <method name="get_name" qualifiers="virtual" >
+ <method name="get_name" qualifiers="virtual">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="get_state" qualifiers="virtual" >
+ <method name="get_state" qualifiers="virtual">
<return type="Dictionary">
</return>
<description>
</description>
</method>
- <method name="handles" qualifiers="virtual" >
+ <method name="handles" qualifiers="virtual">
<return type="bool">
</return>
<argument index="0" name="object" type="Object">
@@ -8764,31 +9938,31 @@
<description>
</description>
</method>
- <method name="has_main_screen" qualifiers="virtual" >
+ <method name="has_main_screen" qualifiers="virtual">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="make_visible" qualifiers="virtual" >
+ <method name="make_visible" qualifiers="virtual">
<argument index="0" name="visible" type="bool">
</argument>
<description>
</description>
</method>
- <method name="set_state" qualifiers="virtual" >
+ <method name="set_state" qualifiers="virtual">
<argument index="0" name="state" type="Dictionary">
</argument>
<description>
</description>
</method>
- <method name="get_undo_redo" >
- <return type="UndoRedo">
+ <method name="get_undo_redo">
+ <return type="Object">
</return>
<description>
</description>
</method>
- <method name="add_custom_control" >
+ <method name="add_custom_control">
<argument index="0" name="container" type="int">
</argument>
<argument index="1" name="control" type="Object">
@@ -8796,7 +9970,7 @@
<description>
</description>
</method>
- <method name="add_custom_type" >
+ <method name="add_custom_type">
<argument index="0" name="type" type="String">
</argument>
<argument index="1" name="base" type="String">
@@ -8808,7 +9982,7 @@
<description>
</description>
</method>
- <method name="remove_custom_type" >
+ <method name="remove_custom_type">
<argument index="0" name="type" type="String">
</argument>
<description>
@@ -8836,7 +10010,7 @@
<description>
</description>
<methods>
- <method name="post_import" qualifiers="virtual" >
+ <method name="post_import" qualifiers="virtual">
<argument index="0" name="scene" type="Object">
</argument>
<description>
@@ -8852,17 +10026,17 @@
<description>
</description>
<methods>
- <method name="_run" qualifiers="virtual" >
+ <method name="_run" qualifiers="virtual">
<description>
</description>
</method>
- <method name="add_root_node" >
+ <method name="add_root_node">
<argument index="0" name="node" type="Object">
</argument>
<description>
</description>
</method>
- <method name="get_scene" >
+ <method name="get_scene">
<return type="Object">
</return>
<description>
@@ -8872,47 +10046,25 @@
<constants>
</constants>
</class>
-<class name="EmptyControl" inherits="Control" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_minsize" >
- <argument index="0" name="minsize" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_minsize" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
<class name="Environment" inherits="Resource" category="Core">
<brief_description>
</brief_description>
<description>
</description>
<methods>
- <method name="set_background" >
+ <method name="set_background">
<argument index="0" name="bgmode" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_background" qualifiers="const" >
+ <method name="get_background" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_background_param" >
+ <method name="set_background_param">
<argument index="0" name="param" type="int">
</argument>
<argument index="1" name="value" type="var">
@@ -8920,13 +10072,13 @@
<description>
</description>
</method>
- <method name="get_background_param" qualifiers="const" >
+ <method name="get_background_param" qualifiers="const">
<argument index="0" name="param" type="int">
</argument>
<description>
</description>
</method>
- <method name="set_enable_fx" >
+ <method name="set_enable_fx">
<argument index="0" name="effect" type="int">
</argument>
<argument index="1" name="enabled" type="bool">
@@ -8934,7 +10086,7 @@
<description>
</description>
</method>
- <method name="is_fx_enabled" qualifiers="const" >
+ <method name="is_fx_enabled" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="effect" type="int">
@@ -8942,7 +10094,7 @@
<description>
</description>
</method>
- <method name="fx_set_param" >
+ <method name="fx_set_param">
<argument index="0" name="param" type="int">
</argument>
<argument index="1" name="value" type="var">
@@ -8950,7 +10102,7 @@
<description>
</description>
</method>
- <method name="fx_get_param" qualifiers="const" >
+ <method name="fx_get_param" qualifiers="const">
<argument index="0" name="param" type="int">
</argument>
<description>
@@ -8968,23 +10120,23 @@
</constant>
<constant name="BG_CUBEMAP" value="4">
</constant>
- <constant name="BG_TEXTURE_RGBE" value="5">
+ <constant name="BG_CANVAS" value="5">
</constant>
- <constant name="BG_CUBEMAP_RGBE" value="6">
+ <constant name="BG_MAX" value="6">
</constant>
- <constant name="BG_MAX" value="7">
+ <constant name="BG_PARAM_CANVAS_MAX_LAYER" value="0">
</constant>
- <constant name="BG_PARAM_COLOR" value="0">
+ <constant name="BG_PARAM_COLOR" value="1">
</constant>
- <constant name="BG_PARAM_TEXTURE" value="1">
+ <constant name="BG_PARAM_TEXTURE" value="2">
</constant>
- <constant name="BG_PARAM_CUBEMAP" value="2">
+ <constant name="BG_PARAM_CUBEMAP" value="3">
</constant>
- <constant name="BG_PARAM_ENERGY" value="3">
+ <constant name="BG_PARAM_ENERGY" value="4">
</constant>
- <constant name="BG_PARAM_GLOW" value="5">
+ <constant name="BG_PARAM_GLOW" value="6">
</constant>
- <constant name="BG_PARAM_MAX" value="6">
+ <constant name="BG_PARAM_MAX" value="7">
</constant>
<constant name="FX_AMBIENT_LIGHT" value="0">
</constant>
@@ -9082,141 +10234,147 @@
<description>
</description>
<methods>
- <method name="set_stream" >
+ <method name="set_stream">
<argument index="0" name="stream" type="EventStream">
</argument>
<description>
</description>
</method>
- <method name="get_stream" qualifiers="const" >
+ <method name="get_stream" qualifiers="const">
<return type="EventStream">
</return>
<description>
</description>
</method>
- <method name="play" >
+ <method name="play">
<description>
</description>
</method>
- <method name="stop" >
+ <method name="stop">
<description>
</description>
</method>
- <method name="is_playing" qualifiers="const" >
+ <method name="is_playing" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_paused" >
+ <method name="set_paused">
<argument index="0" name="paused" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_paused" qualifiers="const" >
+ <method name="is_paused" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_loop" >
+ <method name="set_loop">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="has_loop" qualifiers="const" >
+ <method name="has_loop" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_volume" >
+ <method name="set_volume">
<argument index="0" name="volume" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_volume" qualifiers="const" >
+ <method name="get_volume" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_pitch_scale" >
+ <method name="set_pitch_scale">
<argument index="0" name="pitch_scale" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_pitch_scale" qualifiers="const" >
+ <method name="get_pitch_scale" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_tempo_scale" >
+ <method name="set_tempo_scale">
<argument index="0" name="tempo_scale" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_tempo_scale" qualifiers="const" >
+ <method name="get_tempo_scale" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_volume_db" >
+ <method name="set_volume_db">
<argument index="0" name="db" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_volume_db" qualifiers="const" >
+ <method name="get_volume_db" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="get_stream_name" qualifiers="const" >
+ <method name="get_stream_name" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="get_loop_count" qualifiers="const" >
+ <method name="get_loop_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_pos" qualifiers="const" >
+ <method name="get_pos" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="seek_pos" >
+ <method name="seek_pos">
<argument index="0" name="time" type="float">
</argument>
<description>
</description>
</method>
- <method name="set_autoplay" >
+ <method name="get_length" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_autoplay">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="has_autoplay" qualifiers="const" >
+ <method name="has_autoplay" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_channel_volume" >
+ <method name="set_channel_volume">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="channel_volume" type="float">
@@ -9224,24 +10382,18 @@
<description>
</description>
</method>
- <method name="get_channel_volumeidx" qualifiers="const" >
+ <method name="get_channel_volume" qualifiers="const">
<return type="float">
</return>
- <argument index="0" name="arg0" type="int">
+ <argument index="0" name="idx" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_length" qualifiers="const" >
+ <method name="get_channel_last_note_time" qualifiers="const">
<return type="float">
</return>
- <description>
- </description>
- </method>
- <method name="get_channel_last_note_time" qualifiers="const" >
- <return type="float">
- </return>
- <argument index="0" name="arg0" type="int">
+ <argument index="0" name="idx" type="int">
</argument>
<description>
</description>
@@ -9276,7 +10428,7 @@
<description>
</description>
<methods>
- <method name="open_encrypted" >
+ <method name="open_encrypted">
<return type="int">
</return>
<argument index="0" name="path" type="String">
@@ -9288,7 +10440,7 @@
<description>
</description>
</method>
- <method name="open_encrypted_with_pass" >
+ <method name="open_encrypted_with_pass">
<return type="int">
</return>
<argument index="0" name="path" type="String">
@@ -9300,7 +10452,7 @@
<description>
</description>
</method>
- <method name="open" >
+ <method name="open">
<return type="int">
</return>
<argument index="0" name="path" type="String">
@@ -9310,89 +10462,89 @@
<description>
</description>
</method>
- <method name="close" >
+ <method name="close">
<description>
</description>
</method>
- <method name="is_open" qualifiers="const" >
+ <method name="is_open" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="seek" >
+ <method name="seek">
<argument index="0" name="pos" type="int">
</argument>
<description>
</description>
</method>
- <method name="seek_end" >
+ <method name="seek_end">
<argument index="0" name="pos" type="int" default="0">
</argument>
<description>
</description>
</method>
- <method name="get_pos" qualifiers="const" >
+ <method name="get_pos" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_len" qualifiers="const" >
+ <method name="get_len" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="eof_reached" qualifiers="const" >
+ <method name="eof_reached" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="get_8" qualifiers="const" >
+ <method name="get_8" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_16" qualifiers="const" >
+ <method name="get_16" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_32" qualifiers="const" >
+ <method name="get_32" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_64" qualifiers="const" >
+ <method name="get_64" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_float" qualifiers="const" >
+ <method name="get_float" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="get_double" qualifiers="const" >
+ <method name="get_double" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="get_real" qualifiers="const" >
+ <method name="get_real" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="get_buffer" qualifiers="const" >
+ <method name="get_buffer" qualifiers="const">
<return type="RawArray">
</return>
<argument index="0" name="len" type="int">
@@ -9400,125 +10552,125 @@
<description>
</description>
</method>
- <method name="get_line" qualifiers="const" >
+ <method name="get_line" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="get_as_text" qualifiers="const" >
+ <method name="get_as_text" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="get_endian_swap" >
+ <method name="get_endian_swap">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_endian_swap" >
+ <method name="set_endian_swap">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="get_error" qualifiers="const" >
- <return type="int">
+ <method name="get_error" qualifiers="const">
+ <return type="Error">
</return>
<description>
</description>
</method>
- <method name="get_var" qualifiers="const" >
+ <method name="get_var" qualifiers="const">
<description>
</description>
</method>
- <method name="get_csv_line" qualifiers="const" >
+ <method name="get_csv_line" qualifiers="const">
<return type="StringArray">
</return>
<description>
</description>
</method>
- <method name="store_8" >
+ <method name="store_8">
<argument index="0" name="value" type="int">
</argument>
<description>
</description>
</method>
- <method name="store_16" >
+ <method name="store_16">
<argument index="0" name="value" type="int">
</argument>
<description>
</description>
</method>
- <method name="store_32" >
+ <method name="store_32">
<argument index="0" name="value" type="int">
</argument>
<description>
</description>
</method>
- <method name="store_64" >
+ <method name="store_64">
<argument index="0" name="value" type="int">
</argument>
<description>
</description>
</method>
- <method name="store_float" >
+ <method name="store_float">
<argument index="0" name="value" type="float">
</argument>
<description>
</description>
</method>
- <method name="store_double" >
+ <method name="store_double">
<argument index="0" name="value" type="float">
</argument>
<description>
</description>
</method>
- <method name="store_real" >
+ <method name="store_real">
<argument index="0" name="value" type="float">
</argument>
<description>
</description>
</method>
- <method name="store_buffer" >
+ <method name="store_buffer">
<argument index="0" name="buffer" type="RawArray">
</argument>
<description>
</description>
</method>
- <method name="store_line" >
+ <method name="store_line">
<argument index="0" name="line" type="String">
</argument>
<description>
</description>
</method>
- <method name="store_string" >
+ <method name="store_string">
<argument index="0" name="string" type="String">
</argument>
<description>
</description>
</method>
- <method name="store_var" >
+ <method name="store_var">
<argument index="0" name="value" type="var">
</argument>
<description>
</description>
</method>
- <method name="store_pascal_string" >
+ <method name="store_pascal_string">
<argument index="0" name="string" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_pascal_string" >
+ <method name="get_pascal_string">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="file_exists" qualifiers="const" >
+ <method name="file_exists" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="path" type="String">
@@ -9544,90 +10696,102 @@
FileDialog is a preset dialog used to choose files and directories in the filesystem. It supports filter masks.
</description>
<methods>
- <method name="clear_filters" >
+ <method name="clear_filters">
<description>
Clear all the added filters in the dialog.
</description>
</method>
- <method name="add_filter" >
+ <method name="add_filter">
<argument index="0" name="filter" type="String">
</argument>
<description>
- Add a custom filter. Filter format is: "mask ; description", example (C++): dialog-"lt;add_filter("*.png ; PNG Images");
+ Add a custom filter. Filter format is: "mask ; description", example (C++): dialog-&gt;add_filter("*.png ; PNG Images");
</description>
</method>
- <method name="get_current_dir" qualifiers="const" >
+ <method name="get_current_dir" qualifiers="const">
<return type="String">
</return>
<description>
Get the current working directory of the file dialog.
</description>
</method>
- <method name="get_current_file" qualifiers="const" >
+ <method name="get_current_file" qualifiers="const">
<return type="String">
</return>
<description>
Get the current selected file of the file dialog (empty if none).
</description>
</method>
- <method name="get_current_path" qualifiers="const" >
+ <method name="get_current_path" qualifiers="const">
<return type="String">
</return>
<description>
Get the current selected path (directory and file) of the file dialog (empty if none).
</description>
</method>
- <method name="set_current_dir" >
+ <method name="set_current_dir">
<argument index="0" name="dir" type="String">
</argument>
<description>
</description>
</method>
- <method name="set_current_file" >
+ <method name="set_current_file">
<argument index="0" name="file" type="String">
</argument>
<description>
</description>
</method>
- <method name="set_current_path" >
+ <method name="set_current_path">
<argument index="0" name="path" type="String">
</argument>
<description>
</description>
</method>
- <method name="set_mode" >
+ <method name="set_mode">
<argument index="0" name="mode" type="int">
</argument>
<description>
Set the file dialog mode from the MODE_* enum.
</description>
</method>
- <method name="get_mode" qualifiers="const" >
+ <method name="get_mode" qualifiers="const">
<return type="int">
</return>
<description>
Get the file dialog mode from the MODE_* enum.
</description>
</method>
- <method name="get_vbox" >
+ <method name="get_vbox">
<return type="VBoxContainer">
</return>
<description>
</description>
</method>
- <method name="set_access" >
+ <method name="set_access">
<argument index="0" name="access" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_access" qualifiers="const" >
+ <method name="get_access" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="invalidate" >
+ <method name="set_show_hidden_files">
+ <argument index="0" name="show" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_showing_hidden_files" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="invalidate">
<description>
</description>
</method>
@@ -9655,14 +10819,16 @@
</signals>
<constants>
<constant name="MODE_OPEN_FILE" value="0">
- Editor will not allow to select nonexistent files.
+ The dialog allows the selection of one, and only one file.
</constant>
<constant name="MODE_OPEN_FILES" value="1">
+ The dialog allows the selection of multiple files.
</constant>
<constant name="MODE_OPEN_DIR" value="2">
+ The dialog functions as a folder selector, disallowing the selection of any file.
</constant>
<constant name="MODE_SAVE_FILE" value="3">
- Editor will warn when a file exists.
+ The dialog will warn when a file exists.
</constant>
<constant name="ACCESS_RESOURCES" value="0">
</constant>
@@ -9676,6 +10842,8 @@
</theme_item>
<theme_item name="folder" type="Texture">
</theme_item>
+ <theme_item name="reload" type="Texture">
+ </theme_item>
</theme_items>
</class>
<class name="FixedMaterial" inherits="Material" category="Core">
@@ -9686,23 +10854,23 @@
FixedMaterial is a simple type of material [Resource], which contains a fixed amount of paramters. It is the only type of material supported in fixed-pipeline devices and APIs. It is also an often a better alternative to [ShaderMaterial] for most simple use cases.
</description>
<methods>
- <method name="set_parameter" >
+ <method name="set_parameter">
<argument index="0" name="param" type="int">
</argument>
<argument index="1" name="value" type="var">
</argument>
<description>
- Set a parameter, parameters are defined in the PARAM_* enum. The type of each parameter may change, so it"apos;s best to check the enum.
+ Set a parameter, parameters are defined in the PARAM_* enum. The type of each parameter may change, so it's best to check the enum.
</description>
</method>
- <method name="get_parameter" qualifiers="const" >
+ <method name="get_parameter" qualifiers="const">
<argument index="0" name="param" type="int">
</argument>
<description>
- Return a parameter, parameters are defined in the PARAM_* enum. The type of each parameter may change, so it"apos;s best to check the enum.
+ Return a parameter, parameters are defined in the PARAM_* enum. The type of each parameter may change, so it's best to check the enum.
</description>
</method>
- <method name="set_texture" >
+ <method name="set_texture">
<argument index="0" name="param" type="int">
</argument>
<argument index="1" name="texture" type="Texture">
@@ -9711,7 +10879,7 @@
Set a texture. Textures change parameters per texel and are mapped to the model depending on the texcoord mode (see [method set_texcoord_mode]).
</description>
</method>
- <method name="get_texture" qualifiers="const" >
+ <method name="get_texture" qualifiers="const">
<return type="Texture">
</return>
<argument index="0" name="param" type="int">
@@ -9720,7 +10888,7 @@
Return a texture. Textures change parameters per texel and are mapped to the model depending on the texcoord mode (see [method set_texcoord_mode]).
</description>
</method>
- <method name="set_texcoord_mode" >
+ <method name="set_texcoord_mode">
<argument index="0" name="param" type="int">
</argument>
<argument index="1" name="mode" type="int">
@@ -9729,7 +10897,7 @@
Set the texture coordinate mode. Each texture param (from the PARAM_* enum) has one. It defines how the textures are mapped to the object.
</description>
</method>
- <method name="get_texcoord_mode" qualifiers="const" >
+ <method name="get_texcoord_mode" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="param" type="int">
@@ -9738,7 +10906,7 @@
Return the texture coordinate mode. Each texture param (from the PARAM_* enum) has one. It defines how the textures are mapped to the object.
</description>
</method>
- <method name="set_fixed_flag" >
+ <method name="set_fixed_flag">
<argument index="0" name="flag" type="int">
</argument>
<argument index="1" name="value" type="bool">
@@ -9746,7 +10914,7 @@
<description>
</description>
</method>
- <method name="get_fixed_flag" qualifiers="const" >
+ <method name="get_fixed_flag" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="flag" type="int">
@@ -9754,39 +10922,39 @@
<description>
</description>
</method>
- <method name="set_uv_transform" >
+ <method name="set_uv_transform">
<argument index="0" name="transform" type="Transform">
</argument>
<description>
- Sets a special transform used to post-transform UV coordinates of the uv_xfrom tecoord mode: TEXCOORD_UV_TRANSFORM
+ Sets a special transform used to post-transform UV coordinates of the uv_xfrom tecoord mode: TEXCOORD_UV_TRANSFORM.
</description>
</method>
- <method name="get_uv_transform" qualifiers="const" >
+ <method name="get_uv_transform" qualifiers="const">
<return type="Transform">
</return>
<description>
- Returns the special transform used to post-transform UV coordinates of the uv_xfrom tecoord mode: TEXCOORD_UV_TRANSFORM
+ Returns the special transform used to post-transform UV coordinates of the uv_xfrom tecoord mode: TEXCOORD_UV_TRANSFORM.
</description>
</method>
- <method name="set_light_shader" >
+ <method name="set_light_shader">
<argument index="0" name="shader" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_light_shader" qualifiers="const" >
+ <method name="get_light_shader" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_point_size" >
+ <method name="set_point_size">
<argument index="0" name="size" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_point_size" qualifiers="const" >
+ <method name="get_point_size" qualifiers="const">
<return type="float">
</return>
<description>
@@ -9804,10 +10972,10 @@
Specular Lighting (light reflected from the surface).
</constant>
<constant name="PARAM_EMISSION" value="3">
- Emission Lighting (light emitted from the surface)
+ Emission Lighting (light emitted from the surface).
</constant>
<constant name="PARAM_SPECULAR_EXP" value="4">
- Specular Exponent (size of the specular dot)
+ Specular Exponent (size of the specular dot).
</constant>
<constant name="PARAM_GLOW" value="5">
Glow (Visible emitted scattered light).
@@ -9818,7 +10986,7 @@
<constant name="PARAM_SHADE_PARAM" value="7">
</constant>
<constant name="PARAM_MAX" value="8">
- Maximum amount of parameters
+ Maximum amount of parameters.
</constant>
<constant name="TEXCOORD_SPHERE" value="3">
</constant>
@@ -9839,6 +11007,14 @@
</constant>
<constant name="FLAG_DISCARD_ALPHA" value="3">
</constant>
+ <constant name="LIGHT_SHADER_LAMBERT" value="0">
+ </constant>
+ <constant name="LIGHT_SHADER_WRAP" value="1">
+ </constant>
+ <constant name="LIGHT_SHADER_VELVET" value="2">
+ </constant>
+ <constant name="LIGHT_SHADER_TOON" value="3">
+ </constant>
</constants>
</class>
<class name="Font" inherits="Resource" category="Core">
@@ -9849,42 +11025,50 @@
Font contains an unicode compatible character set, as well as the ability to draw it with variable width, ascent, descent and kerning. For creating fonts from TTF files (or other font formats), see the editor support for fonts. TODO check wikipedia for graph of ascent/baseline/descent/height/etc.
</description>
<methods>
- <method name="set_height" >
+ <method name="create_from_fnt">
+ <return type="int">
+ </return>
+ <argument index="0" name="path" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_height">
<argument index="0" name="px" type="float">
</argument>
<description>
Set the total font height (ascent plus descent) in pixels.
</description>
</method>
- <method name="get_height" qualifiers="const" >
+ <method name="get_height" qualifiers="const">
<return type="float">
</return>
<description>
Return the total font height (ascent plus descent) in pixels.
</description>
</method>
- <method name="set_ascent" >
+ <method name="set_ascent">
<argument index="0" name="px" type="float">
</argument>
<description>
Set the font ascent (number of pixels above the baseline).
</description>
</method>
- <method name="get_ascent" qualifiers="const" >
+ <method name="get_ascent" qualifiers="const">
<return type="float">
</return>
<description>
Return the font ascent (number of pixels above the baseline).
</description>
</method>
- <method name="get_descent" qualifiers="const" >
+ <method name="get_descent" qualifiers="const">
<return type="float">
</return>
<description>
Return the font descent (number of pixels below the baseline).
</description>
</method>
- <method name="add_kerning_pair" >
+ <method name="add_kerning_pair">
<argument index="0" name="char_a" type="int">
</argument>
<argument index="1" name="char_b" type="int">
@@ -9895,25 +11079,25 @@
Add a kerning pair to the [Font] as a difference. Kerning pairs are special cases where a typeface advance is determined by the next character.
</description>
</method>
- <method name="get_kerning_pair" qualifiers="const" >
+ <method name="get_kerning_pair" qualifiers="const">
<return type="int">
</return>
- <argument index="0" name="arg0" type="int">
+ <argument index="0" name="char_a" type="int">
</argument>
- <argument index="1" name="arg1" type="int">
+ <argument index="1" name="char_b" type="int">
</argument>
<description>
Return a kerning pair as a difference. Kerning pairs are special cases where a typeface advance is determined by the next character.
</description>
</method>
- <method name="add_texture" >
+ <method name="add_texture">
<argument index="0" name="texture" type="Texture">
</argument>
<description>
Add a texture to the [Font].
</description>
</method>
- <method name="add_char" >
+ <method name="add_char">
<argument index="0" name="character" type="int">
</argument>
<argument index="1" name="texture" type="int">
@@ -9928,7 +11112,21 @@
Add a character to the font, where "character" is the unicode value, "texture" is the texture index, "rect" is the region in the texture (in pixels!), "align" is the (optional) alignment for the character and "advance" is the (optional) advance.
</description>
</method>
- <method name="get_char_size" qualifiers="const" >
+ <method name="get_texture_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_texture" qualifiers="const">
+ <return type="Texture">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_char_size" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="char" type="int">
@@ -9939,7 +11137,7 @@
Return the size of a character, optionally taking kerning into account if the next character is provided.
</description>
</method>
- <method name="get_string_size" qualifiers="const" >
+ <method name="get_string_size" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="string" type="String">
@@ -9948,12 +11146,24 @@
Return the size of a string, taking kerning and advance into account.
</description>
</method>
- <method name="clear" >
+ <method name="set_distance_field_hint">
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_distance_field_hint" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="clear">
<description>
Clear all the font data.
</description>
</method>
- <method name="draw" qualifiers="const" >
+ <method name="draw" qualifiers="const">
<argument index="0" name="canvas_item" type="RID">
</argument>
<argument index="1" name="pos" type="Vector2">
@@ -9968,7 +11178,7 @@
Draw "string" into a canvas item using the font at a given "pos" position, with "modulate" color, and optionally clipping the width. "pos" specifies te baseline, not the top. To draw from the top, [i]ascent[/i] must be added to the Y axis.
</description>
</method>
- <method name="draw_char" qualifiers="const" >
+ <method name="draw_char" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="canvas_item" type="RID">
@@ -9985,6 +11195,18 @@
Draw character "char" into a canvas item using the font at a given "pos" position, with "modulate" color, and optionally kerning if "next" is apassed. clipping the width. "pos" specifies te baseline, not the top. To draw from the top, [i]ascent[/i] must be added to the Y axis. The width used by the character is returned, making this function useful for drawing strings character by character.
</description>
</method>
+ <method name="set_fallback">
+ <argument index="0" name="fallback" type="Object">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_fallback" qualifiers="const">
+ <return type="Object">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
</constants>
@@ -9995,39 +11217,37 @@
<description>
</description>
<methods>
- <method name="call_func" >
- <argument index="0" name="method" type="String">
+ <method name="call_func">
+ <argument index="0" name="arg0" type="var" default="NULL">
</argument>
- <argument index="1" name="arg0" type="var" default="NULL">
+ <argument index="1" name="arg1" type="var" default="NULL">
</argument>
- <argument index="2" name="arg1" type="var" default="NULL">
+ <argument index="2" name="arg2" type="var" default="NULL">
</argument>
- <argument index="3" name="arg2" type="var" default="NULL">
+ <argument index="3" name="arg3" type="var" default="NULL">
</argument>
- <argument index="4" name="arg3" type="var" default="NULL">
+ <argument index="4" name="arg4" type="var" default="NULL">
</argument>
- <argument index="5" name="arg4" type="var" default="NULL">
+ <argument index="5" name="arg5" type="var" default="NULL">
</argument>
- <argument index="6" name="arg5" type="var" default="NULL">
+ <argument index="6" name="arg6" type="var" default="NULL">
</argument>
- <argument index="7" name="arg6" type="var" default="NULL">
+ <argument index="7" name="arg7" type="var" default="NULL">
</argument>
- <argument index="8" name="arg7" type="var" default="NULL">
+ <argument index="8" name="arg8" type="var" default="NULL">
</argument>
- <argument index="9" name="arg8" type="var" default="NULL">
- </argument>
- <argument index="10" name="arg9" type="var" default="NULL">
+ <argument index="9" name="arg9" type="var" default="NULL">
</argument>
<description>
</description>
</method>
- <method name="set_instance" >
+ <method name="set_instance">
<argument index="0" name="instance" type="Object">
</argument>
<description>
</description>
</method>
- <method name="set_function" >
+ <method name="set_function">
<argument index="0" name="name" type="String">
</argument>
<description>
@@ -10043,13 +11263,15 @@
<description>
</description>
<methods>
- <method name="resume" >
+ <method name="resume">
+ <return type="Variant">
+ </return>
<argument index="0" name="arg" type="var" default="NULL">
</argument>
<description>
</description>
</method>
- <method name="is_valid" qualifiers="const" >
+ <method name="is_valid" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -10065,7 +11287,7 @@
<description>
</description>
<methods>
- <method name="new" >
+ <method name="new">
<description>
</description>
</method>
@@ -10079,7 +11301,13 @@
<description>
</description>
<methods>
- <method name="new" >
+ <method name="new">
+ <description>
+ </description>
+ </method>
+ <method name="get_as_byte_code" qualifiers="const">
+ <return type="RawArray">
+ </return>
<description>
</description>
</method>
@@ -10093,7 +11321,7 @@
<description>
</description>
<methods>
- <method name="set_param_x" >
+ <method name="set_param_x">
<argument index="0" name="param" type="int">
</argument>
<argument index="1" name="value" type="float">
@@ -10101,7 +11329,7 @@
<description>
</description>
</method>
- <method name="get_param_x" qualifiers="const" >
+ <method name="get_param_x" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="param" type="int">
@@ -10109,7 +11337,7 @@
<description>
</description>
</method>
- <method name="set_param_y" >
+ <method name="set_param_y">
<argument index="0" name="param" type="int">
</argument>
<argument index="1" name="value" type="float">
@@ -10117,7 +11345,7 @@
<description>
</description>
</method>
- <method name="get_param_y" qualifiers="const" >
+ <method name="get_param_y" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="param" type="int">
@@ -10125,7 +11353,7 @@
<description>
</description>
</method>
- <method name="set_param_z" >
+ <method name="set_param_z">
<argument index="0" name="param" type="int">
</argument>
<argument index="1" name="value" type="float">
@@ -10133,7 +11361,7 @@
<description>
</description>
</method>
- <method name="get_param_z" qualifiers="const" >
+ <method name="get_param_z" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="param" type="int">
@@ -10141,7 +11369,7 @@
<description>
</description>
</method>
- <method name="set_flag_x" >
+ <method name="set_flag_x">
<argument index="0" name="flag" type="int">
</argument>
<argument index="1" name="value" type="bool">
@@ -10149,7 +11377,7 @@
<description>
</description>
</method>
- <method name="get_flag_x" qualifiers="const" >
+ <method name="get_flag_x" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="flag" type="int">
@@ -10157,7 +11385,7 @@
<description>
</description>
</method>
- <method name="set_flag_y" >
+ <method name="set_flag_y">
<argument index="0" name="flag" type="int">
</argument>
<argument index="1" name="value" type="bool">
@@ -10165,7 +11393,7 @@
<description>
</description>
</method>
- <method name="get_flag_y" qualifiers="const" >
+ <method name="get_flag_y" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="flag" type="int">
@@ -10173,7 +11401,7 @@
<description>
</description>
</method>
- <method name="set_flag_z" >
+ <method name="set_flag_z">
<argument index="0" name="flag" type="int">
</argument>
<argument index="1" name="value" type="bool">
@@ -10181,7 +11409,7 @@
<description>
</description>
</method>
- <method name="get_flag_z" qualifiers="const" >
+ <method name="get_flag_z" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="flag" type="int">
@@ -10237,7 +11465,7 @@
<description>
</description>
<methods>
- <method name="build_box_planes" >
+ <method name="build_box_planes">
<return type="Array">
</return>
<argument index="0" name="extents" type="Vector3">
@@ -10245,7 +11473,7 @@
<description>
</description>
</method>
- <method name="build_cylinder_planes" >
+ <method name="build_cylinder_planes">
<return type="Array">
</return>
<argument index="0" name="radius" type="float">
@@ -10259,7 +11487,7 @@
<description>
</description>
</method>
- <method name="build_capsule_planes" >
+ <method name="build_capsule_planes">
<return type="Array">
</return>
<argument index="0" name="radius" type="float">
@@ -10275,7 +11503,7 @@
<description>
</description>
</method>
- <method name="segment_intersects_circle" >
+ <method name="segment_intersects_circle">
<return type="float">
</return>
<argument index="0" name="segment_from" type="Vector2">
@@ -10289,7 +11517,7 @@
<description>
</description>
</method>
- <method name="segment_intersects_segment_2d" >
+ <method name="segment_intersects_segment_2d">
<argument index="0" name="from_a" type="Vector2">
</argument>
<argument index="1" name="to_a" type="Vector2">
@@ -10301,7 +11529,7 @@
<description>
</description>
</method>
- <method name="get_closest_points_between_segments_2d" >
+ <method name="get_closest_points_between_segments_2d">
<return type="Vector2Array">
</return>
<argument index="0" name="p1" type="Vector2">
@@ -10315,7 +11543,7 @@
<description>
</description>
</method>
- <method name="get_closest_points_between_segments" >
+ <method name="get_closest_points_between_segments">
<return type="Vector3Array">
</return>
<argument index="0" name="p1" type="Vector3">
@@ -10329,7 +11557,7 @@
<description>
</description>
</method>
- <method name="get_closest_point_to_segment" >
+ <method name="get_closest_point_to_segment">
<return type="Vector3">
</return>
<argument index="0" name="point" type="Vector3">
@@ -10341,7 +11569,7 @@
<description>
</description>
</method>
- <method name="get_uv84_normal_bit" >
+ <method name="get_uv84_normal_bit">
<return type="int">
</return>
<argument index="0" name="normal" type="Vector3">
@@ -10349,7 +11577,7 @@
<description>
</description>
</method>
- <method name="ray_intersects_triangle" >
+ <method name="ray_intersects_triangle">
<argument index="0" name="from" type="Vector3">
</argument>
<argument index="1" name="dir" type="Vector3">
@@ -10363,7 +11591,7 @@
<description>
</description>
</method>
- <method name="segment_intersects_triangle" >
+ <method name="segment_intersects_triangle">
<argument index="0" name="from" type="Vector3">
</argument>
<argument index="1" name="to" type="Vector3">
@@ -10377,7 +11605,7 @@
<description>
</description>
</method>
- <method name="segment_intersects_sphere" >
+ <method name="segment_intersects_sphere">
<return type="Vector3Array">
</return>
<argument index="0" name="from" type="Vector3">
@@ -10391,7 +11619,7 @@
<description>
</description>
</method>
- <method name="segment_intersects_cylinder" >
+ <method name="segment_intersects_cylinder">
<return type="Vector3Array">
</return>
<argument index="0" name="from" type="Vector3">
@@ -10405,7 +11633,7 @@
<description>
</description>
</method>
- <method name="segment_intersects_convex" >
+ <method name="segment_intersects_convex">
<return type="Vector3Array">
</return>
<argument index="0" name="from" type="Vector3">
@@ -10417,7 +11645,21 @@
<description>
</description>
</method>
- <method name="triangulate_polygon" >
+ <method name="point_is_inside_triangle" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="point" type="Vector2">
+ </argument>
+ <argument index="1" name="a" type="Vector2">
+ </argument>
+ <argument index="2" name="b" type="Vector2">
+ </argument>
+ <argument index="3" name="c" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="triangulate_polygon">
<return type="IntArray">
</return>
<argument index="0" name="polygon" type="Vector2Array">
@@ -10425,7 +11667,7 @@
<description>
</description>
</method>
- <method name="make_atlas" >
+ <method name="make_atlas">
<return type="Dictionary">
</return>
<argument index="0" name="sizes" type="Vector2Array">
@@ -10445,21 +11687,21 @@
Base node for geometry based visual instances. Shares some common functionality like visibility and custom materials.
</description>
<methods>
- <method name="set_material_override" >
+ <method name="set_material_override">
<argument index="0" name="material" type="Object">
</argument>
<description>
Set the material override for the whole geometry.
</description>
</method>
- <method name="get_material_override" qualifiers="const" >
+ <method name="get_material_override" qualifiers="const">
<return type="Object">
</return>
<description>
Return the material override for the whole geometry.
</description>
</method>
- <method name="set_flag" >
+ <method name="set_flag">
<argument index="0" name="flag" type="int">
</argument>
<argument index="1" name="value" type="bool">
@@ -10467,7 +11709,7 @@
<description>
</description>
</method>
- <method name="get_flag" qualifiers="const" >
+ <method name="get_flag" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="flag" type="int">
@@ -10475,42 +11717,54 @@
<description>
</description>
</method>
- <method name="set_draw_range_begin" >
+ <method name="set_draw_range_begin">
<argument index="0" name="mode" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_draw_range_begin" qualifiers="const" >
+ <method name="get_draw_range_begin" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_draw_range_end" >
+ <method name="set_draw_range_end">
<argument index="0" name="mode" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_draw_range_end" qualifiers="const" >
+ <method name="get_draw_range_end" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_baked_light_texture_id" >
+ <method name="set_baked_light_texture_id">
<argument index="0" name="id" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_baked_light_texture_id" qualifiers="const" >
+ <method name="get_baked_light_texture_id" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
+ <method name="set_extra_cull_margin">
+ <argument index="0" name="margin" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_extra_cull_margin" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
<constant name="FLAG_VISIBLE" value="0">
@@ -10539,7 +11793,7 @@
Contains global variables accessible from everywhere. Use the normal [Object] API, such as "Globals.get(variable)", "Globals.set(variable,value)" or "Globals.has(variable)" to access them. Variables stored in engine.cfg are also loaded into globals, making this object very useful for reading custom game configuration options.
</description>
<methods>
- <method name="has" qualifiers="const" >
+ <method name="has" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="name" type="String">
@@ -10548,7 +11802,7 @@
Return true if a configuration value is present.
</description>
</method>
- <method name="set_order" >
+ <method name="set_order">
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="pos" type="int">
@@ -10557,7 +11811,7 @@
Set the order of a configuration value (influences when saved to the config file).
</description>
</method>
- <method name="get_order" qualifiers="const" >
+ <method name="get_order" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="name" type="String">
@@ -10566,7 +11820,7 @@
Return the order of a configuration value (influences when saved to the config file).
</description>
</method>
- <method name="set_persisting" >
+ <method name="set_persisting">
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="enable" type="bool">
@@ -10575,7 +11829,7 @@
If set to true, this value can be saved to the configuration file. This is useful for editors.
</description>
</method>
- <method name="is_persisting" qualifiers="const" >
+ <method name="is_persisting" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="name" type="String">
@@ -10584,14 +11838,14 @@
If returns true, this value can be saved to the configuration file. This is useful for editors.
</description>
</method>
- <method name="clear" >
+ <method name="clear">
<argument index="0" name="name" type="String">
</argument>
<description>
Clear the whole configuration (not recommended, may break things).
</description>
</method>
- <method name="localize_path" qualifiers="const" >
+ <method name="localize_path" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="path" type="String">
@@ -10600,7 +11854,7 @@
Convert a path to a localized path (res:// path).
</description>
</method>
- <method name="globalize_path" qualifiers="const" >
+ <method name="globalize_path" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="path" type="String">
@@ -10609,32 +11863,40 @@
Convert a localized path (res://) to a full native OS path.
</description>
</method>
- <method name="save" >
+ <method name="save">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="has_singleton" qualifiers="const" >
+ <method name="has_singleton" qualifiers="const">
<return type="bool">
</return>
- <argument index="0" name="arg0" type="String">
+ <argument index="0" name="name" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_singleton" qualifiers="const" >
+ <method name="get_singleton" qualifiers="const">
<return type="Object">
</return>
- <argument index="0" name="arg0" type="String">
+ <argument index="0" name="name" type="String">
</argument>
<description>
</description>
</method>
- <method name="load_resource_pack" >
+ <method name="load_resource_pack">
<return type="bool">
</return>
- <argument index="0" name="arg0" type="String">
+ <argument index="0" name="pack" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="save_custom">
+ <return type="int">
+ </return>
+ <argument index="0" name="file" type="String">
</argument>
<description>
</description>
@@ -10643,19 +11905,405 @@
<constants>
</constants>
</class>
+<class name="GraphEdit" inherits="Control" category="Core">
+ <brief_description>
+ GraphEdit is an area capable of showing various GraphNodes. It manages connection events between them.
+ </brief_description>
+ <description>
+ GraphEdit manages the showing of GraphNodes it contains, as well as connections an disconnections between them. Signals are sent for each of these two events. Disconnection between GraphNodes slots is disabled by default.
+ It is greatly advised to enable low processor usage mode [OS.set_low_processor_usage_mode()] when using GraphEdits.
+ </description>
+ <methods>
+ <method name="connect_node">
+ <return type="Error">
+ </return>
+ <argument index="0" name="from" type="String">
+ </argument>
+ <argument index="1" name="from_port" type="int">
+ </argument>
+ <argument index="2" name="to" type="String">
+ </argument>
+ <argument index="3" name="to_port" type="int">
+ </argument>
+ <description>
+ Create a connection between 'from_port' slot of 'from' GraphNode and 'to_port' slot of 'to' GraphNode. If the connection already exists, no connection is created.
+ </description>
+ </method>
+ <method name="is_node_connected">
+ <return type="bool">
+ </return>
+ <argument index="0" name="from" type="String">
+ </argument>
+ <argument index="1" name="from_port" type="int">
+ </argument>
+ <argument index="2" name="to" type="String">
+ </argument>
+ <argument index="3" name="to_port" type="int">
+ </argument>
+ <description>
+ Return true if the 'from_port' slot of 'from' GraphNode is connected to the 'to_port' slot of 'to' GraphNode.
+ </description>
+ </method>
+ <method name="disconnect_node">
+ <argument index="0" name="from" type="String">
+ </argument>
+ <argument index="1" name="from_port" type="int">
+ </argument>
+ <argument index="2" name="to" type="String">
+ </argument>
+ <argument index="3" name="to_port" type="int">
+ </argument>
+ <description>
+ Remove the connection between 'from_port' slot of 'from' GraphNode and 'to_port' slot of 'to' GraphNode, if connection exists.
+ </description>
+ </method>
+ <method name="get_connection_list" qualifiers="const">
+ <return type="Array">
+ </return>
+ <description>
+ Return an Array containing the list of connections. A connection consists in a structure of the form {from_slot: 0, from: "GraphNode name 0", to_slot: 1, to: "GraphNode name 1" }
+ </description>
+ </method>
+ <method name="set_right_disconnects">
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ Enable the disconnection of existing connections in the visual GraphEdit by left-clicking a connection and releasing into the void.
+ </description>
+ </method>
+ <method name="is_right_disconnects_enabled" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Return true is the disconnection of connections is enable in the visual GraphEdit. False otherwise.
+ </description>
+ </method>
+ </methods>
+ <signals>
+ <signal name="delete_nodes_request">
+ <description>
+ </description>
+ </signal>
+ <signal name="duplicate_nodes_request">
+ <description>
+ </description>
+ </signal>
+ <signal name="popup_request">
+ <argument index="0" name="p_position" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ <signal name="_begin_node_move">
+ <description>
+ </description>
+ </signal>
+ <signal name="disconnection_request">
+ <argument index="0" name="from" type="String">
+ </argument>
+ <argument index="1" name="from_slot" type="int">
+ </argument>
+ <argument index="2" name="to" type="String">
+ </argument>
+ <argument index="3" name="to_slot" type="int">
+ </argument>
+ <description>
+ Signal sent to the GraphEdit when the connection between 'from_slot' slot of 'from' GraphNode and 'to_slot' slot of 'to' GraphNode is attempted to be removed.
+ </description>
+ </signal>
+ <signal name="connection_request">
+ <argument index="0" name="from" type="String">
+ </argument>
+ <argument index="1" name="from_slot" type="int">
+ </argument>
+ <argument index="2" name="to" type="String">
+ </argument>
+ <argument index="3" name="to_slot" type="int">
+ </argument>
+ <description>
+ Signal sent to the GraphEdit when the connection between 'from_slot' slot of 'from' GraphNode and 'to_slot' slot of 'to' GraphNode is attempted to be created.
+ </description>
+ </signal>
+ <signal name="_end_node_move">
+ <description>
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ </constants>
+</class>
+<class name="GraphNode" inherits="Container" category="Core">
+ <brief_description>
+ A GraphNode is a container with several input and output slots allowing connections between GraphNodes. Slots can have different, incompatible types.
+ </brief_description>
+ <description>
+ A GraphNode is a container defined by a title. It can have 1 or more input and output slots, which can be enabled (shown) or disabled (not shown) and have different (incompatible) types. Colors can also be assigned to slots. A tuple of input and output slots is defined for each GUI element included in the GraphNode. Input and output connections are left and right slots, but only enabled slots are counted as connections.
+ </description>
+ <methods>
+ <method name="set_title">
+ <argument index="0" name="title" type="String">
+ </argument>
+ <description>
+ Set the title of the GraphNode.
+ </description>
+ </method>
+ <method name="get_title" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ Return the title of the GraphNode.
+ </description>
+ </method>
+ <method name="set_slot">
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <argument index="1" name="enable_left" type="bool">
+ </argument>
+ <argument index="2" name="type_left" type="int">
+ </argument>
+ <argument index="3" name="color_left" type="Color">
+ </argument>
+ <argument index="4" name="enable_right" type="bool">
+ </argument>
+ <argument index="5" name="type_right" type="int">
+ </argument>
+ <argument index="6" name="color_right" type="Color">
+ </argument>
+ <description>
+ Set the tuple of input/output slots defined by 'idx' ID. 'left' slots are input, 'right' are output. 'type' is an integer defining the type of the slot. Refer to description for the compatibility between slot types.
+ </description>
+ </method>
+ <method name="clear_slot">
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ Disable input and ouput slot whose index is 'idx'.
+ </description>
+ </method>
+ <method name="clear_all_slots">
+ <description>
+ Disable all input and output slots of the GraphNode.
+ </description>
+ </method>
+ <method name="is_slot_enabled_left" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ Return true if left (input) slot 'idx' is enabled. False otherwise.
+ </description>
+ </method>
+ <method name="get_slot_type_left" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ Return the (integer) type of left (input) 'idx' slot.
+ </description>
+ </method>
+ <method name="get_slot_color_left" qualifiers="const">
+ <return type="Color">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ Return the color set to 'idx' left (input) slot.
+ </description>
+ </method>
+ <method name="is_slot_enabled_right" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ Return true if right (output) slot 'idx' is enabled. False otherwise.
+ </description>
+ </method>
+ <method name="get_slot_type_right" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ Return the (integer) type of right (output) 'idx' slot.
+ </description>
+ </method>
+ <method name="get_slot_color_right" qualifiers="const">
+ <return type="Color">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ Return the color set to 'idx' right (output) slot.
+ </description>
+ </method>
+ <method name="set_offset">
+ <argument index="0" name="offset" type="Vector2">
+ </argument>
+ <description>
+ Set the offset of the GraphNode.
+ </description>
+ </method>
+ <method name="get_offset" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <description>
+ Return the offset of the GraphNode.
+ </description>
+ </method>
+ <method name="get_connection_output_count">
+ <return type="int">
+ </return>
+ <description>
+ Return the number of enabled output slots (connections) of the GraphNode.
+ </description>
+ </method>
+ <method name="get_connection_input_count">
+ <return type="int">
+ </return>
+ <description>
+ Return the number of enabled input slots (connections) to the GraphNode.
+ </description>
+ </method>
+ <method name="get_connection_output_pos">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ Return the position of the output connection 'idx'.
+ </description>
+ </method>
+ <method name="get_connection_output_type">
+ <return type="int">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ Return the type of the output connection 'idx'.
+ </description>
+ </method>
+ <method name="get_connection_output_color">
+ <return type="Color">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ Return the color of the output connection 'idx'.
+ </description>
+ </method>
+ <method name="get_connection_input_pos">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ Return the position of the input connection 'idx'.
+ </description>
+ </method>
+ <method name="get_connection_input_type">
+ <return type="int">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ Return the type of the input connection 'idx'.
+ </description>
+ </method>
+ <method name="get_connection_input_color">
+ <return type="Color">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ Return the color of the input connection 'idx'.
+ </description>
+ </method>
+ <method name="set_show_close_button">
+ <argument index="0" name="show" type="bool">
+ </argument>
+ <description>
+ Show the close button on the GraphNode if 'show' is true (disabled by default). If enabled, a connection on the signal close_request is needed for the close button to work.
+ </description>
+ </method>
+ <method name="is_close_button_visible" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns true if the close button is shown. False otherwise.
+ </description>
+ </method>
+ </methods>
+ <signals>
+ <signal name="raise_request">
+ <description>
+ Signal sent when the GraphNode is requested to be displayed over other ones. Happens on focusing (clicking into) the GraphNode.
+ </description>
+ </signal>
+ <signal name="close_request">
+ <description>
+ Signal sent on closing the GraphNode.
+ </description>
+ </signal>
+ <signal name="dragged">
+ <argument index="0" name="from" type="Vector2">
+ </argument>
+ <argument index="1" name="to" type="Vector2">
+ </argument>
+ <description>
+ Signal sent when the GraphNode is dragged.
+ </description>
+ </signal>
+ <signal name="offset_changed">
+ <description>
+ Signal sent when the GraphNode is moved.
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ </constants>
+ <theme_items>
+ <theme_item name="port_offset" type="int">
+ </theme_item>
+ <theme_item name="close_offset" type="int">
+ </theme_item>
+ <theme_item name="separation" type="int">
+ </theme_item>
+ <theme_item name="title_offset" type="int">
+ </theme_item>
+ <theme_item name="title_color" type="Color">
+ </theme_item>
+ <theme_item name="port" type="Texture">
+ </theme_item>
+ <theme_item name="close" type="Texture">
+ </theme_item>
+ <theme_item name="title_font" type="Font">
+ </theme_item>
+ <theme_item name="frame" type="StyleBox">
+ </theme_item>
+ <theme_item name="selectedframe" type="StyleBox">
+ </theme_item>
+ <theme_item name="defaultfocus" type="StyleBox">
+ </theme_item>
+ <theme_item name="defaultframe" type="StyleBox">
+ </theme_item>
+ </theme_items>
+</class>
<class name="GridContainer" inherits="Container" category="Core">
<brief_description>
</brief_description>
<description>
</description>
<methods>
- <method name="set_columns" >
+ <method name="set_columns">
<argument index="0" name="columns" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_columns" qualifiers="const" >
+ <method name="get_columns" qualifiers="const">
<return type="int">
</return>
<description>
@@ -10665,7 +12313,9 @@
<constants>
</constants>
<theme_items>
- <theme_item name="separation" type="int">
+ <theme_item name="vseparation" type="int">
+ </theme_item>
+ <theme_item name="hseparation" type="int">
</theme_item>
</theme_items>
</class>
@@ -10675,55 +12325,55 @@
<description>
</description>
<methods>
- <method name="set_theme" >
+ <method name="set_theme">
<argument index="0" name="theme" type="MeshLibrary">
</argument>
<description>
</description>
</method>
- <method name="get_theme" qualifiers="const" >
+ <method name="get_theme" qualifiers="const">
<return type="MeshLibrary">
</return>
<description>
</description>
</method>
- <method name="set_bake" >
+ <method name="set_bake">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_baking_enabled" qualifiers="const" >
+ <method name="is_baking_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_cell_size" >
+ <method name="set_cell_size">
<argument index="0" name="size" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_cell_size" qualifiers="const" >
+ <method name="get_cell_size" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_octant_size" >
+ <method name="set_octant_size">
<argument index="0" name="size" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_octant_size" qualifiers="const" >
+ <method name="get_octant_size" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_cell_item" >
+ <method name="set_cell_item">
<argument index="0" name="x" type="int">
</argument>
<argument index="1" name="y" type="int">
@@ -10737,7 +12387,7 @@
<description>
</description>
</method>
- <method name="get_cell_item" qualifiers="const" >
+ <method name="get_cell_item" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="x" type="int">
@@ -10749,7 +12399,7 @@
<description>
</description>
</method>
- <method name="get_cell_item_orientation" qualifiers="const" >
+ <method name="get_cell_item_orientation" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="x" type="int">
@@ -10761,49 +12411,49 @@
<description>
</description>
</method>
- <method name="resource_changed" >
- <argument index="0" name="arg0" type="Object">
+ <method name="resource_changed">
+ <argument index="0" name="resource" type="Object">
</argument>
<description>
</description>
</method>
- <method name="set_center_x" >
+ <method name="set_center_x">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="get_center_x" qualifiers="const" >
+ <method name="get_center_x" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_center_y" >
+ <method name="set_center_y">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="get_center_y" qualifiers="const" >
+ <method name="get_center_y" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_center_z" >
+ <method name="set_center_z">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="get_center_z" qualifiers="const" >
+ <method name="get_center_z" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_clip" >
+ <method name="set_clip">
<argument index="0" name="enabled" type="bool">
</argument>
<argument index="1" name="clipabove" type="bool" default="true">
@@ -10815,7 +12465,7 @@
<description>
</description>
</method>
- <method name="create_area" >
+ <method name="create_area">
<return type="int">
</return>
<argument index="0" name="id" type="int">
@@ -10825,7 +12475,7 @@
<description>
</description>
</method>
- <method name="area_get_bounds" qualifiers="const" >
+ <method name="area_get_bounds" qualifiers="const">
<return type="AABB">
</return>
<argument index="0" name="area" type="int">
@@ -10833,7 +12483,7 @@
<description>
</description>
</method>
- <method name="area_set_exterior_portal" >
+ <method name="area_set_exterior_portal">
<argument index="0" name="area" type="int">
</argument>
<argument index="1" name="enable" type="bool">
@@ -10841,7 +12491,7 @@
<description>
</description>
</method>
- <method name="area_set_name" >
+ <method name="area_set_name">
<argument index="0" name="area" type="int">
</argument>
<argument index="1" name="name" type="String">
@@ -10849,7 +12499,7 @@
<description>
</description>
</method>
- <method name="area_get_name" qualifiers="const" >
+ <method name="area_get_name" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="area" type="int">
@@ -10857,7 +12507,7 @@
<description>
</description>
</method>
- <method name="area_is_exterior_portal" qualifiers="const" >
+ <method name="area_is_exterior_portal" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="area" type="int">
@@ -10865,7 +12515,7 @@
<description>
</description>
</method>
- <method name="area_set_portal_disable_distance" >
+ <method name="area_set_portal_disable_distance">
<argument index="0" name="area" type="int">
</argument>
<argument index="1" name="distance" type="float">
@@ -10873,7 +12523,7 @@
<description>
</description>
</method>
- <method name="area_get_portal_disable_distance" qualifiers="const" >
+ <method name="area_get_portal_disable_distance" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="area" type="int">
@@ -10881,7 +12531,7 @@
<description>
</description>
</method>
- <method name="area_set_portal_disable_color" >
+ <method name="area_set_portal_disable_color">
<argument index="0" name="area" type="int">
</argument>
<argument index="1" name="color" type="Color">
@@ -10889,7 +12539,7 @@
<description>
</description>
</method>
- <method name="area_get_portal_disable_color" qualifiers="const" >
+ <method name="area_get_portal_disable_color" qualifiers="const">
<return type="Color">
</return>
<argument index="0" name="area" type="int">
@@ -10897,35 +12547,35 @@
<description>
</description>
</method>
- <method name="erase_area" >
+ <method name="erase_area">
<argument index="0" name="area" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_unused_area_id" qualifiers="const" >
+ <method name="get_unused_area_id" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="bake_geometry" >
+ <method name="bake_geometry">
<description>
</description>
</method>
- <method name="set_use_baked_light" >
+ <method name="set_use_baked_light">
<argument index="0" name="use" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_using_baked_light" qualifiers="const" >
+ <method name="is_using_baked_light" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="clear" >
+ <method name="clear">
<description>
</description>
</method>
@@ -10943,28 +12593,28 @@
Groove constraint for 2D physics. This is useful for making a body "slide" through a segment placed in another.
</description>
<methods>
- <method name="set_length" >
+ <method name="set_length">
<argument index="0" name="length" type="float">
</argument>
<description>
Set the length of the groove.
</description>
</method>
- <method name="get_length" qualifiers="const" >
+ <method name="get_length" qualifiers="const">
<return type="float">
</return>
<description>
Return the length of the groove.
</description>
</method>
- <method name="set_initial_offset" >
+ <method name="set_initial_offset">
<argument index="0" name="offset" type="float">
</argument>
<description>
Set the initial offset of the groove on body A.
</description>
</method>
- <method name="get_initial_offset" qualifiers="const" >
+ <method name="get_initial_offset" qualifiers="const">
<return type="float">
</return>
<description>
@@ -11127,8 +12777,8 @@
<description>
</description>
<methods>
- <method name="connect" >
- <return type="int">
+ <method name="connect">
+ <return type="Error">
</return>
<argument index="0" name="host" type="String">
</argument>
@@ -11136,18 +12786,22 @@
</argument>
<argument index="2" name="use_ssl" type="bool" default="false">
</argument>
- <argument index="3" name="arg3" type="bool" default="true">
+ <argument index="3" name="verify_host" type="bool" default="true">
</argument>
<description>
+ Connect to a host. This needs to be done before any requests are sent.
+The host should not have http:// prepended but will strip the protocol identifier if provided.
+
+verify_host will check the SSL identity of the host if set to true.
</description>
</method>
- <method name="set_connection" >
+ <method name="set_connection">
<argument index="0" name="connection" type="StreamPeer">
</argument>
<description>
</description>
</method>
- <method name="request" >
+ <method name="request">
<return type="int">
</return>
<argument index="0" name="method" type="int">
@@ -11159,92 +12813,131 @@
<argument index="3" name="body" type="String" default="&quot;&quot;">
</argument>
<description>
+ Sends a request to the connected host. The url is the what is normally behind the hostname, i.e:
+http://somehost.com/index.php
+url would be "index.php"
+
+Headers are HTTP request headers
+
+To create a POST request with query strings to push to the server, do:
+var fields = {"username" : "user",
+ "password" : "pass"}
+var queryString = httpClient.query_string_from_dict(fields)
+var headers = ["Content-Type: application/x-www-form-urlencoded",
+ "Content-Length: " + str(queryString.length())]
+var result = httpClient.request(httpClient.METHOD_POST, "index.php", headers, queryString)
</description>
</method>
- <method name="send_body_text" >
+ <method name="send_body_text">
<return type="int">
</return>
<argument index="0" name="body" type="String">
</argument>
<description>
+ Stub function
</description>
</method>
- <method name="send_body_data" >
+ <method name="send_body_data">
<return type="int">
</return>
<argument index="0" name="body" type="RawArray">
</argument>
<description>
+ Stub function
</description>
</method>
- <method name="close" >
+ <method name="close">
<description>
</description>
</method>
- <method name="has_response" qualifiers="const" >
+ <method name="has_response" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="is_response_chunked" qualifiers="const" >
+ <method name="is_response_chunked" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="get_response_code" qualifiers="const" >
+ <method name="get_response_code" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_response_headers" >
+ <method name="get_response_headers">
<return type="StringArray">
</return>
<description>
</description>
</method>
- <method name="get_response_headers_as_dictionary" >
+ <method name="get_response_headers_as_dictionary">
<return type="Dictionary">
</return>
<description>
</description>
</method>
- <method name="get_response_body_length" qualifiers="const" >
+ <method name="get_response_body_length" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="read_response_body_chunk" >
+ <method name="read_response_body_chunk">
<return type="RawArray">
</return>
<description>
</description>
</method>
- <method name="set_blocking_mode" >
+ <method name="set_read_chunk_size">
+ <argument index="0" name="bytes" type="int">
+ </argument>
+ <description>
+ Sets the size of the buffer used and maximum bytes to read per iteration
+ </description>
+ </method>
+ <method name="set_blocking_mode">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
+ If set to true, execute will wait until all data is read from the response.
</description>
</method>
- <method name="is_blocking_mode_enabled" qualifiers="const" >
+ <method name="is_blocking_mode_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="get_status" qualifiers="const" >
+ <method name="get_status" qualifiers="const">
<return type="int">
</return>
<description>
+ Returns a status string like STATUS_REQUESTING. Need to call [method poll] in order to get status updates.
</description>
</method>
- <method name="poll" >
- <return type="int">
+ <method name="poll">
+ <return type="Error">
</return>
<description>
+ This needs to be called in order to have any request processed. Check results with [method get_status]
+ </description>
+ </method>
+ <method name="query_string_from_dict">
+ <return type="String">
+ </return>
+ <argument index="0" name="fields" type="Dictionary">
+ </argument>
+ <description>
+ Generates a GET/POST application/x-www-form-urlencoded style query string from a provided dictionary.
+
+var fields = {"username": "user", "password": "pass"}
+String queryString = httpClient.query_string_from_dict(fields)
+
+returns:= "username=user&amp;password=pass"
</description>
</method>
</methods>
@@ -11393,7 +13086,7 @@
<description>
</description>
<methods>
- <method name="set_param" >
+ <method name="set_param">
<argument index="0" name="param" type="int">
</argument>
<argument index="1" name="value" type="float">
@@ -11401,7 +13094,7 @@
<description>
</description>
</method>
- <method name="get_param" qualifiers="const" >
+ <method name="get_param" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="param" type="int">
@@ -11409,7 +13102,7 @@
<description>
</description>
</method>
- <method name="set_flag" >
+ <method name="set_flag">
<argument index="0" name="flag" type="int">
</argument>
<argument index="1" name="enabled" type="bool">
@@ -11417,7 +13110,7 @@
<description>
</description>
</method>
- <method name="get_flag" qualifiers="const" >
+ <method name="get_flag" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="flag" type="int">
@@ -11461,7 +13154,7 @@
IP contains some support functions for the IPv4 protocol. TCP/IP support is in different classes (see [TCP_Client], [TCP_Server]). IP provides hostname resolution support, both blocking and threaded.
</description>
<methods>
- <method name="resolve_hostname" >
+ <method name="resolve_hostname">
<return type="String">
</return>
<argument index="0" name="host" type="String">
@@ -11470,7 +13163,7 @@
Resolve a given hostname, blocking. Resolved hostname is returned as an IP.
</description>
</method>
- <method name="resolve_hostname_queue_item" >
+ <method name="resolve_hostname_queue_item">
<return type="int">
</return>
<argument index="0" name="host" type="String">
@@ -11479,32 +13172,32 @@
Create a queue item for resolving a given hostname. The queue ID is returned, or RESOLVER_INVALID_ID on error.
</description>
</method>
- <method name="get_resolve_item_status" qualifiers="const" >
+ <method name="get_resolve_item_status" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="id" type="int">
</argument>
<description>
- Return the status of hostname queued for resolving, given it"apos;s queue ID. Returned status can be any of the RESOLVER_STATUS_* enumeration.
+ Return the status of hostname queued for resolving, given it's queue ID. Returned status can be any of the RESOLVER_STATUS_* enumeration.
</description>
</method>
- <method name="get_resolve_item_address" qualifiers="const" >
+ <method name="get_resolve_item_address" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="id" type="int">
</argument>
<description>
- Return a resolved item address, or an empty string if an error happened or resolution didn"apos;t happen yet (see [method get_resolve_item_status]).
+ Return a resolved item address, or an empty string if an error happened or resolution didn't happen yet (see [method get_resolve_item_status]).
</description>
</method>
- <method name="erase_resolve_item" >
+ <method name="erase_resolve_item">
<argument index="0" name="id" type="int">
</argument>
<description>
Erase a queue ID, removing it from the queue if needed. This should be used after a queue is completed to free it and enable more queries to happen.
</description>
</method>
- <method name="get_local_addresses" qualifiers="const" >
+ <method name="get_local_addresses" qualifiers="const">
<return type="Array">
</return>
<description>
@@ -11544,7 +13237,7 @@
Built in native image datatype. Contains image data, which can be converted to a texture, and several functions to interact with it.
</description>
<methods>
- <method name="blit_rect" >
+ <method name="blit_rect">
<argument index="0" name="src" type="Image">
</argument>
<argument index="1" name="src_rect" type="Rect2">
@@ -11554,7 +13247,7 @@
<description>
</description>
</method>
- <method name="brush_transfer" >
+ <method name="brush_transfer">
<argument index="0" name="src" type="Image">
</argument>
<argument index="1" name="brush" type="Image">
@@ -11564,7 +13257,7 @@
<description>
</description>
</method>
- <method name="brushed" >
+ <method name="brushed">
<return type="Image">
</return>
<argument index="0" name="src" type="Image">
@@ -11576,7 +13269,7 @@
<description>
</description>
</method>
- <method name="compressed" >
+ <method name="compressed">
<return type="Image">
</return>
<argument index="0" name="format" type="int" default="0">
@@ -11584,7 +13277,7 @@
<description>
</description>
</method>
- <method name="converted" >
+ <method name="converted">
<return type="Image">
</return>
<argument index="0" name="format" type="int" default="0">
@@ -11592,37 +13285,37 @@
<description>
</description>
</method>
- <method name="decompressed" >
+ <method name="decompressed">
<return type="Image">
</return>
<description>
</description>
</method>
- <method name="empty" >
+ <method name="empty">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="get_data" >
+ <method name="get_data">
<return type="RawArray">
</return>
<description>
</description>
</method>
- <method name="get_format" >
+ <method name="get_format">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_height" >
+ <method name="get_height">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_pixel" >
+ <method name="get_pixel">
<return type="Color">
</return>
<argument index="0" name="x" type="int">
@@ -11634,7 +13327,7 @@
<description>
</description>
</method>
- <method name="get_rect" >
+ <method name="get_rect">
<return type="Image">
</return>
<argument index="0" name="area" type="Rect2" default="0">
@@ -11642,19 +13335,19 @@
<description>
</description>
</method>
- <method name="get_used_rect" >
+ <method name="get_used_rect">
<return type="Rect2">
</return>
<description>
</description>
</method>
- <method name="get_width" >
+ <method name="get_width">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="load" >
+ <method name="load">
<return type="int">
</return>
<argument index="0" name="path" type="String" default="0">
@@ -11662,7 +13355,7 @@
<description>
</description>
</method>
- <method name="put_pixel" >
+ <method name="put_pixel">
<argument index="0" name="x" type="int">
</argument>
<argument index="1" name="y" type="int">
@@ -11674,7 +13367,7 @@
<description>
</description>
</method>
- <method name="resized" >
+ <method name="resized">
<return type="Image">
</return>
<argument index="0" name="x" type="int">
@@ -11686,7 +13379,7 @@
<description>
</description>
</method>
- <method name="save_png" >
+ <method name="save_png">
<return type="int">
</return>
<argument index="0" name="path" type="String" default="0">
@@ -11694,6 +13387,21 @@
<description>
</description>
</method>
+ <method name="Image">
+ <return type="Image">
+ </return>
+ <argument index="0" name="width" type="int">
+ </argument>
+ <argument index="1" name="height" type="int">
+ </argument>
+ <argument index="2" name="mipmaps" type="bool">
+ </argument>
+ <argument index="3" name="format" type="int">
+ </argument>
+ <description>
+ Create an empty image of a specific size and format.
+ </description>
+ </method>
</methods>
<constants>
<constant name="COMPRESS_BC" value="0">
@@ -11758,7 +13466,7 @@
<description>
</description>
<methods>
- <method name="create" >
+ <method name="create">
<argument index="0" name="width" type="int">
</argument>
<argument index="1" name="height" type="int">
@@ -11770,7 +13478,7 @@
<description>
</description>
</method>
- <method name="create_from_image" >
+ <method name="create_from_image">
<argument index="0" name="image" type="Image">
</argument>
<argument index="1" name="flags" type="int" default="7">
@@ -11778,63 +13486,71 @@
<description>
</description>
</method>
- <method name="get_format" qualifiers="const" >
+ <method name="get_format" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="load" >
+ <method name="load">
<argument index="0" name="path" type="String">
</argument>
<description>
</description>
</method>
- <method name="set_data" >
+ <method name="set_data">
<argument index="0" name="image" type="Image">
</argument>
<description>
</description>
</method>
- <method name="get_data" qualifiers="const" >
+ <method name="get_data" qualifiers="const">
<return type="Image">
</return>
<description>
</description>
</method>
- <method name="set_storage" >
+ <method name="set_storage">
<argument index="0" name="mode" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_storage" qualifiers="const" >
+ <method name="get_storage" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_lossy_storage_quality" >
+ <method name="set_lossy_storage_quality">
<argument index="0" name="quality" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_lossy_storage_quality" qualifiers="const" >
+ <method name="get_lossy_storage_quality" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="fix_alpha_edges" >
+ <method name="fix_alpha_edges">
<description>
</description>
</method>
- <method name="premultiply_alpha" >
+ <method name="premultiply_alpha">
<description>
</description>
</method>
- <method name="set_size_override" >
+ <method name="normal_to_xy">
+ <description>
+ </description>
+ </method>
+ <method name="shrink_x2_and_keep_size">
+ <description>
+ </description>
+ </method>
+ <method name="set_size_override">
<argument index="0" name="size" type="Vector2">
</argument>
<description>
@@ -11856,7 +13572,7 @@
<description>
</description>
<methods>
- <method name="begin" >
+ <method name="begin">
<argument index="0" name="primitive" type="int">
</argument>
<argument index="1" name="texture" type="Texture">
@@ -11864,43 +13580,43 @@
<description>
</description>
</method>
- <method name="set_normal" >
+ <method name="set_normal">
<argument index="0" name="normal" type="Vector3">
</argument>
<description>
</description>
</method>
- <method name="set_tangent" >
+ <method name="set_tangent">
<argument index="0" name="tangent" type="Plane">
</argument>
<description>
</description>
</method>
- <method name="set_color" >
+ <method name="set_color">
<argument index="0" name="color" type="Color">
</argument>
<description>
</description>
</method>
- <method name="set_uv" >
+ <method name="set_uv">
<argument index="0" name="uv" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="set_uv2" >
+ <method name="set_uv2">
<argument index="0" name="uv" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="add_vertex" >
- <argument index="0" name="color" type="Vector3">
+ <method name="add_vertex">
+ <argument index="0" name="pos" type="Vector3">
</argument>
<description>
</description>
</method>
- <method name="add_sphere" >
+ <method name="add_sphere">
<argument index="0" name="lats" type="int">
</argument>
<argument index="1" name="lons" type="int">
@@ -11910,11 +13626,11 @@
<description>
</description>
</method>
- <method name="end" >
+ <method name="end">
<description>
</description>
</method>
- <method name="clear" >
+ <method name="clear">
<description>
</description>
</method>
@@ -11928,7 +13644,7 @@
<description>
</description>
<methods>
- <method name="is_key_pressed" >
+ <method name="is_key_pressed">
<return type="bool">
</return>
<argument index="0" name="scancode" type="int">
@@ -11936,7 +13652,7 @@
<description>
</description>
</method>
- <method name="is_mouse_button_pressed" >
+ <method name="is_mouse_button_pressed">
<return type="bool">
</return>
<argument index="0" name="button" type="int">
@@ -11944,7 +13660,7 @@
<description>
</description>
</method>
- <method name="is_joy_button_pressed" >
+ <method name="is_joy_button_pressed">
<return type="bool">
</return>
<argument index="0" name="device" type="int">
@@ -11952,9 +13668,10 @@
<argument index="1" name="button" type="int">
</argument>
<description>
+ Returns true if the joystick button at the given index is currently pressed. Returns false otherwise. (see JOY_* constans in [InputEvent])
</description>
</method>
- <method name="is_action_pressed" >
+ <method name="is_action_pressed">
<return type="bool">
</return>
<argument index="0" name="action" type="String">
@@ -11962,7 +13679,32 @@
<description>
</description>
</method>
- <method name="get_joy_axis" >
+ <method name="add_joy_mapping">
+ <argument index="0" name="mapping" type="String">
+ </argument>
+ <argument index="1" name="update_existing" type="bool" default="false">
+ </argument>
+ <description>
+ Add a new mapping entry (in SDL2 format) to the mapping database. Optionally update already connected devices.
+ </description>
+ </method>
+ <method name="remove_joy_mapping">
+ <argument index="0" name="guid" type="String">
+ </argument>
+ <description>
+ Removes all mappings from the internal db that match the given uid.
+ </description>
+ </method>
+ <method name="is_joy_known">
+ <return type="bool">
+ </return>
+ <argument index="0" name="device" type="int">
+ </argument>
+ <description>
+ Returns true if the specified device is known by the system. This means that it sets all button and axis indices exactly as defined in [InputEvent]. Unknown joysticks are not expected to match these constants, but you can still retrieve events from them.
+ </description>
+ </method>
+ <method name="get_joy_axis">
<return type="float">
</return>
<argument index="0" name="device" type="int">
@@ -11970,61 +13712,83 @@
<argument index="1" name="axis" type="int">
</argument>
<description>
+ Returns the current value of the joystick axis at given index (see JOY_* enum in [InputEvent])
</description>
</method>
- <method name="get_joy_name" >
+ <method name="get_joy_name">
<return type="String">
</return>
<argument index="0" name="device" type="int">
</argument>
<description>
+ Returns the name of the joystick at the specified device index
</description>
</method>
- <method name="get_accelerometer" >
- <return type="Vector3">
+ <method name="get_joy_guid" qualifiers="const">
+ <return type="String">
</return>
+ <argument index="0" name="device" type="int">
+ </argument>
<description>
+ Returns a SDL2 compatible device guid on platforms that use gamepad remapping. Returns "Default Gamepad" otherwise.
</description>
</method>
- <method name="get_mouse_pos" qualifiers="const" >
- <return type="Vector2">
+ <method name="get_accelerometer">
+ <return type="Vector3">
</return>
<description>
- Return the global, unscaled, screen pointer coordinates.
- If the 2D viewport has been scaled, it may not work well
- with [Camera] or controls.
</description>
</method>
- <method name="get_mouse_speed" qualifiers="const" >
+ <method name="get_mouse_speed" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="get_mouse_button_mask" qualifiers="const" >
+ <method name="get_mouse_button_mask" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_mouse_mode" >
+ <method name="set_mouse_mode">
<argument index="0" name="mode" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_mouse_mode" qualifiers="const" >
+ <method name="get_mouse_mode" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="warp_mouse_pos" >
+ <method name="warp_mouse_pos">
<argument index="0" name="to" type="Vector2">
</argument>
<description>
</description>
</method>
+ <method name="action_press">
+ <argument index="0" name="action" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="action_release">
+ <argument index="0" name="action" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_custom_mouse_cursor">
+ <argument index="0" name="image" type="Texture">
+ </argument>
+ <argument index="1" name="hotspot" type="Vector2" default="Vector2(0,0)">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<signals>
<signal name="joy_connection_changed">
@@ -12060,10 +13824,10 @@
Built-in input event data.
</brief_description>
<description>
- Built-in input event data. InputEvent is a built-in engine datatype, given that it's passed around and used so much . Depending on it's type, the members contained can be different, so read the documentation well!. Input events can also represent actions (editable from the project settings).
+ Built-in input event data. InputEvent is a built-in engine datatype, given that it's passed around and used so much. Depending on it's type, the members contained can be different, so read the documentation well!. Input events can also represent actions (editable from the project settings).
</description>
<methods>
- <method name="is_action" >
+ <method name="is_action">
<return type="bool">
</return>
<argument index="0" name="action" type="String">
@@ -12072,20 +13836,44 @@
Return if this input event matches a pre-defined action, no matter the type.
</description>
</method>
- <method name="is_echo" >
+ <method name="is_action_pressed">
+ <return type="bool">
+ </return>
+ <argument index="0" name="is_action_pressed" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_action_released">
+ <return type="bool">
+ </return>
+ <argument index="0" name="is_action_released" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_echo">
<return type="bool">
</return>
<description>
Return if this input event is an echo event (usually for key events).
</description>
</method>
- <method name="is_pressed" >
+ <method name="is_pressed">
<return type="bool">
</return>
<description>
Return if this input event is pressed (for key, mouse, joy button or screen press events).
</description>
</method>
+ <method name="set_as_action">
+ <argument index="0" name="action" type="String">
+ </argument>
+ <argument index="1" name="pressed" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<members>
<member name="type" type="int">
@@ -12128,7 +13916,7 @@
<description>
</description>
<methods>
- <method name="is_action" >
+ <method name="is_action">
<return type="bool">
</return>
<argument index="0" name="action" type="String">
@@ -12136,15 +13924,39 @@
<description>
</description>
</method>
- <method name="is_echo" >
+ <method name="is_action_pressed">
<return type="bool">
</return>
+ <argument index="0" name="is_action_pressed" type="String">
+ </argument>
<description>
</description>
</method>
- <method name="is_pressed" >
+ <method name="is_action_released">
<return type="bool">
</return>
+ <argument index="0" name="is_action_released" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_echo">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="is_pressed">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_as_action">
+ <argument index="0" name="action" type="String">
+ </argument>
+ <argument index="1" name="pressed" type="bool">
+ </argument>
<description>
</description>
</method>
@@ -12184,7 +13996,7 @@
<description>
</description>
<methods>
- <method name="is_action" >
+ <method name="is_action">
<return type="bool">
</return>
<argument index="0" name="action" type="String">
@@ -12192,18 +14004,42 @@
<description>
</description>
</method>
- <method name="is_echo" >
+ <method name="is_action_pressed">
+ <return type="bool">
+ </return>
+ <argument index="0" name="is_action_pressed" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_action_released">
<return type="bool">
</return>
+ <argument index="0" name="is_action_released" type="String">
+ </argument>
<description>
</description>
</method>
- <method name="is_pressed" >
+ <method name="is_echo">
<return type="bool">
</return>
<description>
</description>
</method>
+ <method name="is_pressed">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_as_action">
+ <argument index="0" name="action" type="String">
+ </argument>
+ <argument index="1" name="pressed" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<members>
<member name="type" type="int">
@@ -12246,7 +14082,7 @@
<description>
</description>
<methods>
- <method name="is_action" >
+ <method name="is_action">
<return type="bool">
</return>
<argument index="0" name="action" type="String">
@@ -12254,18 +14090,42 @@
<description>
</description>
</method>
- <method name="is_echo" >
+ <method name="is_action_pressed">
+ <return type="bool">
+ </return>
+ <argument index="0" name="is_action_pressed" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_action_released">
+ <return type="bool">
+ </return>
+ <argument index="0" name="is_action_released" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_echo">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="is_pressed" >
+ <method name="is_pressed">
<return type="bool">
</return>
<description>
</description>
</method>
+ <method name="set_as_action">
+ <argument index="0" name="action" type="String">
+ </argument>
+ <argument index="1" name="pressed" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<members>
<member name="type" type="int">
@@ -12306,7 +14166,7 @@
<description>
</description>
<methods>
- <method name="is_action" >
+ <method name="is_action">
<return type="bool">
</return>
<argument index="0" name="action" type="String">
@@ -12314,18 +14174,42 @@
<description>
</description>
</method>
- <method name="is_echo" >
+ <method name="is_action_pressed">
+ <return type="bool">
+ </return>
+ <argument index="0" name="is_action_pressed" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_action_released">
+ <return type="bool">
+ </return>
+ <argument index="0" name="is_action_released" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_echo">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="is_pressed" >
+ <method name="is_pressed">
<return type="bool">
</return>
<description>
</description>
</method>
+ <method name="set_as_action">
+ <argument index="0" name="action" type="String">
+ </argument>
+ <argument index="1" name="pressed" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<members>
<member name="type" type="int">
@@ -12378,7 +14262,7 @@
<description>
</description>
<methods>
- <method name="is_action" >
+ <method name="is_action">
<return type="bool">
</return>
<argument index="0" name="action" type="String">
@@ -12386,15 +14270,39 @@
<description>
</description>
</method>
- <method name="is_echo" >
+ <method name="is_action_pressed">
<return type="bool">
</return>
+ <argument index="0" name="is_action_pressed" type="String">
+ </argument>
<description>
</description>
</method>
- <method name="is_pressed" >
+ <method name="is_action_released">
<return type="bool">
</return>
+ <argument index="0" name="is_action_released" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_echo">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="is_pressed">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_as_action">
+ <argument index="0" name="action" type="String">
+ </argument>
+ <argument index="1" name="pressed" type="bool">
+ </argument>
<description>
</description>
</method>
@@ -12462,7 +14370,7 @@
<description>
</description>
<methods>
- <method name="is_action" >
+ <method name="is_action">
<return type="bool">
</return>
<argument index="0" name="action" type="String">
@@ -12470,15 +14378,39 @@
<description>
</description>
</method>
- <method name="is_echo" >
+ <method name="is_action_pressed">
<return type="bool">
</return>
+ <argument index="0" name="is_action_pressed" type="String">
+ </argument>
<description>
</description>
</method>
- <method name="is_pressed" >
+ <method name="is_action_released">
<return type="bool">
</return>
+ <argument index="0" name="is_action_released" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_echo">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="is_pressed">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_as_action">
+ <argument index="0" name="action" type="String">
+ </argument>
+ <argument index="1" name="pressed" type="bool">
+ </argument>
<description>
</description>
</method>
@@ -12552,7 +14484,7 @@
<description>
</description>
<methods>
- <method name="is_action" >
+ <method name="is_action">
<return type="bool">
</return>
<argument index="0" name="action" type="String">
@@ -12560,18 +14492,42 @@
<description>
</description>
</method>
- <method name="is_echo" >
+ <method name="is_action_pressed">
+ <return type="bool">
+ </return>
+ <argument index="0" name="is_action_pressed" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_action_released">
+ <return type="bool">
+ </return>
+ <argument index="0" name="is_action_released" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_echo">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="is_pressed" >
+ <method name="is_pressed">
<return type="bool">
</return>
<description>
</description>
</method>
+ <method name="set_as_action">
+ <argument index="0" name="action" type="String">
+ </argument>
+ <argument index="1" name="pressed" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<members>
<member name="type" type="int">
@@ -12628,7 +14584,7 @@
<description>
</description>
<methods>
- <method name="is_action" >
+ <method name="is_action">
<return type="bool">
</return>
<argument index="0" name="action" type="String">
@@ -12636,18 +14592,42 @@
<description>
</description>
</method>
- <method name="is_echo" >
+ <method name="is_action_pressed">
+ <return type="bool">
+ </return>
+ <argument index="0" name="is_action_pressed" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_action_released">
<return type="bool">
</return>
+ <argument index="0" name="is_action_released" type="String">
+ </argument>
<description>
</description>
</method>
- <method name="is_pressed" >
+ <method name="is_echo">
<return type="bool">
</return>
<description>
</description>
</method>
+ <method name="is_pressed">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_as_action">
+ <argument index="0" name="action" type="String">
+ </argument>
+ <argument index="1" name="pressed" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<members>
<member name="type" type="int">
@@ -12696,7 +14676,7 @@
Singleton that manages actions. InputMap has a list of the actions used in InputEvent, which can be modified.
</description>
<methods>
- <method name="has_action" qualifiers="const" >
+ <method name="has_action" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="action" type="String">
@@ -12704,7 +14684,7 @@
<description>
</description>
</method>
- <method name="get_action_id" qualifiers="const" >
+ <method name="get_action_id" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="action" type="String">
@@ -12712,7 +14692,7 @@
<description>
</description>
</method>
- <method name="get_action_from_id" qualifiers="const" >
+ <method name="get_action_from_id" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="id" type="int">
@@ -12720,19 +14700,19 @@
<description>
</description>
</method>
- <method name="add_action" >
+ <method name="add_action">
<argument index="0" name="action" type="String">
</argument>
<description>
</description>
</method>
- <method name="erase_action" >
+ <method name="erase_action">
<argument index="0" name="action" type="String">
</argument>
<description>
</description>
</method>
- <method name="action_add_event" >
+ <method name="action_add_event">
<argument index="0" name="action" type="String">
</argument>
<argument index="1" name="event" type="InputEvent">
@@ -12740,7 +14720,7 @@
<description>
</description>
</method>
- <method name="action_has_event" >
+ <method name="action_has_event">
<return type="bool">
</return>
<argument index="0" name="action" type="String">
@@ -12750,7 +14730,7 @@
<description>
</description>
</method>
- <method name="action_erase_event" >
+ <method name="action_erase_event">
<argument index="0" name="action" type="String">
</argument>
<argument index="1" name="event" type="InputEvent">
@@ -12758,15 +14738,15 @@
<description>
</description>
</method>
- <method name="get_action_list" >
- <return type="bool">
+ <method name="get_action_list">
+ <return type="Array">
</return>
<argument index="0" name="action" type="String">
</argument>
<description>
</description>
</method>
- <method name="event_is_action" qualifiers="const" >
+ <method name="event_is_action" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="event" type="InputEvent">
@@ -12776,7 +14756,29 @@
<description>
</description>
</method>
- <method name="load_from_globals" >
+ <method name="load_from_globals">
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
+<class name="InstancePlaceholder" inherits="Node" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="replace_by_instance">
+ <argument index="0" name="custom_scene" type="PackedScene" default="NULL">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_instance_path" qualifiers="const">
+ <return type="String">
+ </return>
<description>
</description>
</method>
@@ -12786,13 +14788,13 @@
</class>
<class name="IntArray" category="Built-In Types">
<brief_description>
- Integer Array .
+ Integer Array.
</brief_description>
<description>
- Integer Array. Array of integers. Can only contain integers. Optimized for memory usage, cant fragment the memory.
+ Integer Array. Array of integers. Can only contain integers. Optimized for memory usage, can't fragment the memory.
</description>
<methods>
- <method name="get" >
+ <method name="get">
<return type="int">
</return>
<argument index="0" name="idx" type="int">
@@ -12801,21 +14803,21 @@
Get an index in the array.
</description>
</method>
- <method name="push_back" >
+ <method name="push_back">
<argument index="0" name="integer" type="int">
</argument>
<description>
Append a value to the array.
</description>
</method>
- <method name="resize" >
+ <method name="resize">
<argument index="0" name="idx" type="int">
</argument>
<description>
Resize the array.
</description>
</method>
- <method name="set" >
+ <method name="set">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="integer" type="int">
@@ -12824,14 +14826,16 @@
Set an index in the array.
</description>
</method>
- <method name="size" >
+ <method name="size">
<return type="int">
</return>
<description>
Return the array size.
</description>
</method>
- <method name="IntArray" >
+ <method name="IntArray">
+ <return type="IntArray">
+ </return>
<argument index="0" name="from" type="Array">
</argument>
<description>
@@ -12848,43 +14852,43 @@
<description>
</description>
<methods>
- <method name="set_target_path" >
+ <method name="set_target_path">
<argument index="0" name="target_path" type="NodePath">
</argument>
<description>
</description>
</method>
- <method name="get_target_path" qualifiers="const" >
+ <method name="get_target_path" qualifiers="const">
<return type="NodePath">
</return>
<description>
</description>
</method>
- <method name="set_target" >
+ <method name="set_target">
<argument index="0" name="target" type="Camera">
</argument>
<description>
</description>
</method>
- <method name="set_speed" >
+ <method name="set_speed">
<argument index="0" name="speed" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_speed" qualifiers="const" >
+ <method name="get_speed" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_interpolation_enabled" >
+ <method name="set_interpolation_enabled">
<argument index="0" name="target_path" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_interpolation_enabled" qualifiers="const" >
+ <method name="is_interpolation_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -12894,48 +14898,376 @@
<constants>
</constants>
</class>
+<class name="ItemList" inherits="Control" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="add_item">
+ <argument index="0" name="text" type="String">
+ </argument>
+ <argument index="1" name="icon" type="Texture" default="Object()">
+ </argument>
+ <argument index="2" name="selectable" type="bool" default="true">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="add_icon_item">
+ <argument index="0" name="icon" type="Texture">
+ </argument>
+ <argument index="1" name="selectable" type="bool" default="true">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_item_text">
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <argument index="1" name="text" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_item_text" qualifiers="const">
+ <return type="String">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_item_icon">
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <argument index="1" name="icon" type="Texture">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_item_icon" qualifiers="const">
+ <return type="Texture">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_item_selectable">
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <argument index="1" name="selectable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_item_selectable" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_item_disabled">
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <argument index="1" name="disabled" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_item_disabled" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_item_metadata">
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <argument index="1" name="metadata" type="var">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_item_metadata" qualifiers="const">
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_item_custom_bg_color">
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <argument index="1" name="custom_bg_color" type="Color">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_item_custom_bg_color" qualifiers="const">
+ <return type="Color">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_item_tooltip">
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <argument index="1" name="tooltip" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_item_tooltip" qualifiers="const">
+ <return type="String">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="select">
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <argument index="1" name="single" type="bool" default="true">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="unselect">
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_selected" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_item_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="remove_item">
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="clear">
+ <description>
+ </description>
+ </method>
+ <method name="sort_items_by_text">
+ <description>
+ </description>
+ </method>
+ <method name="set_fixed_column_width">
+ <argument index="0" name="width" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_fixed_column_width" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_max_text_lines">
+ <argument index="0" name="lines" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_max_text_lines" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_max_columns">
+ <argument index="0" name="amount" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_max_columns" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_select_mode">
+ <argument index="0" name="mode" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_select_mode" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_icon_mode">
+ <argument index="0" name="mode" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_icon_mode" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_min_icon_size">
+ <argument index="0" name="size" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_min_icon_size" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="ensure_current_is_visible">
+ <description>
+ </description>
+ </method>
+ </methods>
+ <signals>
+ <signal name="item_activated">
+ <argument index="0" name="index" type="int">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ <signal name="multi_selected">
+ <argument index="0" name="index" type="int">
+ </argument>
+ <argument index="1" name="selected" type="bool">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ <signal name="item_selected">
+ <argument index="0" name="index" type="int">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ <constant name="ICON_MODE_TOP" value="0">
+ </constant>
+ <constant name="ICON_MODE_LEFT" value="1">
+ </constant>
+ <constant name="SELECT_SINGLE" value="0">
+ </constant>
+ <constant name="SELECT_MULTI" value="1">
+ </constant>
+ </constants>
+ <theme_items>
+ <theme_item name="vseparation" type="int">
+ </theme_item>
+ <theme_item name="line_separation" type="int">
+ </theme_item>
+ <theme_item name="icon_margin" type="int">
+ </theme_item>
+ <theme_item name="hseparation" type="int">
+ </theme_item>
+ <theme_item name="guide_color" type="Color">
+ </theme_item>
+ <theme_item name="font_color_selected" type="Color">
+ </theme_item>
+ <theme_item name="font_color" type="Color">
+ </theme_item>
+ <theme_item name="font" type="Font">
+ </theme_item>
+ <theme_item name="cursor" type="StyleBox">
+ </theme_item>
+ <theme_item name="selected_focus" type="StyleBox">
+ </theme_item>
+ <theme_item name="bg_focus" type="StyleBox">
+ </theme_item>
+ <theme_item name="cursor_unfocused" type="StyleBox">
+ </theme_item>
+ <theme_item name="selected" type="StyleBox">
+ </theme_item>
+ <theme_item name="bg" type="StyleBox">
+ </theme_item>
+ </theme_items>
+</class>
<class name="Joint" inherits="Spatial" category="Core">
<brief_description>
</brief_description>
<description>
</description>
<methods>
- <method name="set_node_a" >
+ <method name="set_node_a">
<argument index="0" name="node" type="NodePath">
</argument>
<description>
</description>
</method>
- <method name="get_node_a" qualifiers="const" >
+ <method name="get_node_a" qualifiers="const">
<return type="NodePath">
</return>
<description>
</description>
</method>
- <method name="set_node_b" >
+ <method name="set_node_b">
<argument index="0" name="node" type="NodePath">
</argument>
<description>
</description>
</method>
- <method name="get_node_b" qualifiers="const" >
+ <method name="get_node_b" qualifiers="const">
<return type="NodePath">
</return>
<description>
</description>
</method>
- <method name="set_solver_priority" >
+ <method name="set_solver_priority">
<argument index="0" name="priority" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_solver_priority" qualifiers="const" >
+ <method name="get_solver_priority" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
+ <method name="set_exclude_nodes_from_collision">
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_exclude_nodes_from_collision" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
</constants>
@@ -12948,46 +15280,58 @@
Base node for all joint constraints in 2D phyisics. Joints take 2 bodies and apply a custom constraint.
</description>
<methods>
- <method name="set_node_a" >
+ <method name="set_node_a">
<argument index="0" name="node" type="NodePath">
</argument>
<description>
- Set the path to the A node for the joint. Must be of type PhysicsBody2D.
+ Set the path to the A node for the joint. Must be of type [PhysicsBody2D].
</description>
</method>
- <method name="get_node_a" qualifiers="const" >
+ <method name="get_node_a" qualifiers="const">
<return type="NodePath">
</return>
<description>
Return the path to the A node for the joint.
</description>
</method>
- <method name="set_node_b" >
+ <method name="set_node_b">
<argument index="0" name="node" type="NodePath">
</argument>
<description>
- Set the path to the B node for the joint. Must be of type PhysicsBody2D.
+ Set the path to the B node for the joint. Must be of type [PhysicsBody2D].
</description>
</method>
- <method name="get_node_b" qualifiers="const" >
+ <method name="get_node_b" qualifiers="const">
<return type="NodePath">
</return>
<description>
Return the path to the B node for the joint.
</description>
</method>
- <method name="set_bias" >
+ <method name="set_bias">
<argument index="0" name="bias" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_bias" qualifiers="const" >
+ <method name="get_bias" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
+ <method name="set_exclude_nodes_from_collision">
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_exclude_nodes_from_collision" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
</constants>
@@ -12998,7 +15342,7 @@
<description>
</description>
<methods>
- <method name="move" >
+ <method name="move">
<return type="Vector3">
</return>
<argument index="0" name="rel_vec" type="Vector3">
@@ -13006,7 +15350,7 @@
<description>
</description>
</method>
- <method name="move_to" >
+ <method name="move_to">
<return type="Vector3">
</return>
<argument index="0" name="position" type="Vector3">
@@ -13014,105 +15358,106 @@
<description>
</description>
</method>
- <method name="can_move_to" >
+ <method name="can_teleport_to">
<return type="bool">
</return>
<argument index="0" name="position" type="Vector3">
</argument>
- <argument index="1" name="arg1" type="bool">
- </argument>
<description>
+ Returns whether the KinematicBody can be teleported to the destination given as an argument, checking all collision shapes of the body against potential colliders at the destination.
</description>
</method>
- <method name="is_colliding" qualifiers="const" >
+ <method name="is_colliding" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="get_collision_pos" qualifiers="const" >
+ <method name="get_collision_pos" qualifiers="const">
<return type="Vector3">
</return>
<description>
</description>
</method>
- <method name="get_collision_normal" qualifiers="const" >
+ <method name="get_collision_normal" qualifiers="const">
<return type="Vector3">
</return>
<description>
</description>
</method>
- <method name="get_collider_velocity" qualifiers="const" >
+ <method name="get_collider_velocity" qualifiers="const">
<return type="Vector3">
</return>
<description>
</description>
</method>
- <method name="get_collider" qualifiers="const" >
+ <method name="get_collider" qualifiers="const">
+ <return type="Object">
+ </return>
<description>
</description>
</method>
- <method name="get_collider_shape" qualifiers="const" >
+ <method name="get_collider_shape" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_collide_with_static_bodies" >
+ <method name="set_collide_with_static_bodies">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="can_collide_with_static_bodies" qualifiers="const" >
+ <method name="can_collide_with_static_bodies" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_collide_with_kinematic_bodies" >
+ <method name="set_collide_with_kinematic_bodies">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="can_collide_with_kinematic_bodies" qualifiers="const" >
+ <method name="can_collide_with_kinematic_bodies" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_collide_with_rigid_bodies" >
+ <method name="set_collide_with_rigid_bodies">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="can_collide_with_rigid_bodies" qualifiers="const" >
+ <method name="can_collide_with_rigid_bodies" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_collide_with_character_bodies" >
+ <method name="set_collide_with_character_bodies">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="can_collide_with_character_bodies" qualifiers="const" >
+ <method name="can_collide_with_character_bodies" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_collision_margin" >
+ <method name="set_collision_margin">
<argument index="0" name="pixels" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_collision_margin" qualifiers="const" >
+ <method name="get_collision_margin" qualifiers="const">
<return type="float">
</return>
<description>
@@ -13124,139 +15469,121 @@
</class>
<class name="KinematicBody2D" inherits="PhysicsBody2D" category="Core">
<brief_description>
+ Kinematic body 2D node.
</brief_description>
<description>
+ Kinematic bodies are special types of bodies that are meant to be user-controlled. They are not affected by physics at all (to other types of bodies, such a character or a rigid body, these are the same as a static body). They have however, two main uses:
+ Simulated Motion: When these bodies are moved manually, either from code or from an AnimationPlayer (with process mode set to fixed), the physics will automatically compute an estimate of their linear and angular velocity. This makes them very useful for moving platforms or other AnimationPlayer-controlled objects (like a door, a bridge that opens, etc).
+ Kinematic Characters: KinematicBody2D also has an api for moving objects (the [method move] method) while performing collision tests. This makes them really useful to implement characters that collide against a world, but that don't require advanced physics.
</description>
<methods>
- <method name="move" >
+ <method name="move">
<return type="Vector2">
</return>
<argument index="0" name="rel_vec" type="Vector2">
</argument>
<description>
+ Move the body in the given direction, stopping if there is an obstacle.
</description>
</method>
- <method name="move_to" >
+ <method name="move_to">
<return type="Vector2">
</return>
<argument index="0" name="position" type="Vector2">
</argument>
<description>
+ Move the body to the given position. This is not a teleport, and the body will stop if there is an obstacle.
</description>
</method>
- <method name="can_move_to" >
+ <method name="test_move">
<return type="bool">
</return>
- <argument index="0" name="position" type="Vector2">
- </argument>
- <argument index="1" name="arg1" type="bool">
+ <argument index="0" name="rel_vec" type="Vector2">
</argument>
<description>
+ Return true if there would be a collision if the body moved in the given direction.
</description>
</method>
- <method name="is_colliding" qualifiers="const" >
- <return type="bool">
+ <method name="get_travel" qualifiers="const">
+ <return type="Vector2">
</return>
<description>
+ Return the last movement done by the body.
</description>
</method>
- <method name="get_collision_pos" qualifiers="const" >
- <return type="Vector2">
- </return>
+ <method name="revert_motion">
<description>
+ Undo the last movement done by the body.
</description>
</method>
- <method name="get_collision_normal" qualifiers="const" >
- <return type="Vector2">
+ <method name="is_colliding" qualifiers="const">
+ <return type="bool">
</return>
<description>
+ Return whether the body is colliding with another.
</description>
</method>
- <method name="get_collider_velocity" qualifiers="const" >
+ <method name="get_collision_pos" qualifiers="const">
<return type="Vector2">
</return>
<description>
+ Return the point in space where the body is touching another. If there is no collision, this method will return (0,0), so collisions must be checked first with [method is_colliding].
</description>
</method>
- <method name="get_collider" qualifiers="const" >
- <description>
- </description>
- </method>
- <method name="get_collider_shape" qualifiers="const" >
- <return type="int">
+ <method name="get_collision_normal" qualifiers="const">
+ <return type="Vector2">
</return>
<description>
+ Return the normal of the surface the body collided with. This is useful to implement sliding along a surface.
</description>
</method>
- <method name="get_collider_metadata" qualifiers="const" >
- <description>
- </description>
- </method>
- <method name="set_collide_with_static_bodies" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="can_collide_with_static_bodies" qualifiers="const" >
- <return type="bool">
+ <method name="get_collider_velocity" qualifiers="const">
+ <return type="Vector2">
</return>
<description>
+ Return the velocity of the body that collided with this one.
</description>
</method>
- <method name="set_collide_with_kinematic_bodies" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="can_collide_with_kinematic_bodies" qualifiers="const" >
- <return type="bool">
+ <method name="get_collider" qualifiers="const">
+ <return type="Object">
</return>
<description>
+ Return the body that collided with this one.
</description>
</method>
- <method name="set_collide_with_rigid_bodies" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="can_collide_with_rigid_bodies" qualifiers="const" >
- <return type="bool">
+ <method name="get_collider_shape" qualifiers="const">
+ <return type="int">
</return>
<description>
+ Return the shape index from the body that collided with this one. If there is no collision, this method will return 0, so collisions must be checked first with [method is_colliding].
</description>
</method>
- <method name="set_collide_with_character_bodies" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="can_collide_with_character_bodies" qualifiers="const" >
- <return type="bool">
+ <method name="get_collider_metadata" qualifiers="const">
+ <return type="Variant">
</return>
<description>
+ Return the metadata of the shape that collided with this body. If there is no collision, it will return 0, so collisions must be checked first with [method is_colliding]. Aditionally, this metadata can not be set with [method Object.set_meta], it must be set with [method Physics2DServer.body_set_shape_metadata].
</description>
</method>
- <method name="set_collision_margin" >
+ <method name="set_collision_margin">
<argument index="0" name="pixels" type="float">
</argument>
<description>
+ Set the collision margin for this object. A collision margin is an amount (in pixels) that all shapes will grow when computing collisions, to account for numerical imprecision.
</description>
</method>
- <method name="get_collision_margin" qualifiers="const" >
+ <method name="get_collision_margin" qualifiers="const">
<return type="float">
</return>
<description>
+ Return the collision margin for this object.
</description>
</method>
</methods>
<constants>
</constants>
</class>
-<class name="Label" inherits="Range" category="Core">
+<class name="Label" inherits="Control" category="Core">
<brief_description>
Control that displays formatted text.
</brief_description>
@@ -13264,108 +15591,165 @@
Label is a control that displays formatted text, optionally autowrapping it to the [Control] area. It inherits from range to be able to scroll wrapped text vertically.
</description>
<methods>
- <method name="set_align" >
+ <method name="set_align">
<argument index="0" name="align" type="int">
</argument>
<description>
- Set the alignmend mode to any of the ALIGN_* enumeration values.
+ Sets the alignment mode to any of the ALIGN_* enumeration values.
</description>
</method>
- <method name="get_align" qualifiers="const" >
+ <method name="get_align" qualifiers="const">
<return type="int">
</return>
<description>
- Return the alignmend mode (any of the ALIGN_* enumeration values).
+ Return the alignment mode (any of the ALIGN_* enumeration values).
</description>
</method>
- <method name="set_valign" >
+ <method name="set_valign">
<argument index="0" name="valign" type="int">
</argument>
<description>
+ Sets the vertical alignment mode to any of the VALIGN_* enumeration values.
</description>
</method>
- <method name="get_valign" qualifiers="const" >
+ <method name="get_valign" qualifiers="const">
<return type="int">
</return>
<description>
+ Return the vertical alignment mode (any of the VALIGN_* enumeration values).
</description>
</method>
- <method name="set_text" >
+ <method name="set_text">
<argument index="0" name="text" type="String">
</argument>
<description>
Set the label text. Text can contain newlines.
</description>
</method>
- <method name="get_text" qualifiers="const" >
+ <method name="get_text" qualifiers="const">
<return type="String">
</return>
<description>
Return the label text. Text can contain newlines.
</description>
</method>
- <method name="set_autowrap" >
+ <method name="set_autowrap">
<argument index="0" name="enable" type="bool">
</argument>
<description>
Set [i]autowrap[/i] mode. When enabled, autowrap will fit text to the control width, breaking sentences when they exceed the available horizontal space. When disabled, the label minimum width becomes the width of the longest row, and the minimum height large enough to fit all rows.
</description>
</method>
- <method name="has_autowrap" qualifiers="const" >
+ <method name="has_autowrap" qualifiers="const">
<return type="bool">
</return>
<description>
Return the state of the [i]autowrap[/i] mode (see [method set_autowrap]).
</description>
</method>
- <method name="set_uppercase" >
+ <method name="set_clip_text">
<argument index="0" name="enable" type="bool">
</argument>
<description>
+ Cuts off the rest of the text if it is too wide.
</description>
</method>
- <method name="is_uppercase" qualifiers="const" >
+ <method name="is_clipping_text" qualifiers="const">
<return type="bool">
</return>
<description>
+ Return true if text would be cut off if it is too wide.
</description>
</method>
- <method name="get_line_height" qualifiers="const" >
+ <method name="set_uppercase">
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ Display text in all capitals.
+ </description>
+ </method>
+ <method name="is_uppercase" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Return true if text is displayed in all capitals.
+ </description>
+ </method>
+ <method name="get_line_height" qualifiers="const">
<return type="int">
</return>
<description>
Return the height of a line.
</description>
</method>
- <method name="get_line_count" qualifiers="const" >
+ <method name="get_line_count" qualifiers="const">
<return type="int">
</return>
<description>
Return the amount of lines.
</description>
</method>
- <method name="get_total_character_count" qualifiers="const" >
+ <method name="get_total_character_count" qualifiers="const">
<return type="int">
</return>
<description>
+ Return the total length of the text.
</description>
</method>
- <method name="set_visible_characters" >
- <argument index="0" name="arg0" type="int">
+ <method name="set_visible_characters">
+ <argument index="0" name="amount" type="int">
</argument>
<description>
+ Restricts the number of characters to display. Set to -1 to disable.
+ </description>
+ </method>
+ <method name="get_visible_characters" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Return the restricted number of characters to display. Returns -1 if unrestricted.
</description>
</method>
- <method name="set_percent_visible" >
+ <method name="set_percent_visible">
<argument index="0" name="percent_visible" type="float">
</argument>
<description>
+ Restricts the number of characters to display (as a percentage of the total text).
</description>
</method>
- <method name="get_percent_visible" qualifiers="const" >
+ <method name="get_percent_visible" qualifiers="const">
<return type="float">
</return>
<description>
+ Return the restricted number of characters to display (as a percentage of the total text).
+ </description>
+ </method>
+ <method name="set_lines_skipped">
+ <argument index="0" name="lines_skipped" type="int">
+ </argument>
+ <description>
+ Sets the number of lines to skip before displaying. Useful for scrolling text.
+ </description>
+ </method>
+ <method name="get_lines_skipped" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Return the the number of lines to skipped before displaying.
+ </description>
+ </method>
+ <method name="set_max_lines_visible">
+ <argument index="0" name="lines_visible" type="int">
+ </argument>
+ <description>
+ Restricts the number of lines to display. Set to -1 to disable.
+ </description>
+ </method>
+ <method name="get_max_lines_visible" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Return the restricted number of lines to display. Returns -1 if unrestricted.
</description>
</method>
</methods>
@@ -13416,7 +15800,7 @@
<description>
</description>
<methods>
- <method name="add_piece" >
+ <method name="add_piece">
<return type="int">
</return>
<argument index="0" name="ofs" type="Vector2">
@@ -13426,7 +15810,7 @@
<description>
</description>
</method>
- <method name="set_piece_offset" >
+ <method name="set_piece_offset">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="ofs" type="Vector2">
@@ -13434,7 +15818,7 @@
<description>
</description>
</method>
- <method name="set_piece_texture" >
+ <method name="set_piece_texture">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="texture" type="Texture">
@@ -13442,23 +15826,23 @@
<description>
</description>
</method>
- <method name="set_size" >
+ <method name="set_size">
<argument index="0" name="size" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="clear" >
+ <method name="clear">
<description>
</description>
</method>
- <method name="get_piece_count" qualifiers="const" >
+ <method name="get_piece_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_piece_offset" qualifiers="const" >
+ <method name="get_piece_offset" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="idx" type="int">
@@ -13466,7 +15850,7 @@
<description>
</description>
</method>
- <method name="get_piece_texture" qualifiers="const" >
+ <method name="get_piece_texture" qualifiers="const">
<return type="Texture">
</return>
<argument index="0" name="idx" type="int">
@@ -13486,7 +15870,7 @@
Light is the abstract base class for light nodes, so it shouldn't be used directly (It can't be instanced). Other types of light nodes inherit from it. Light contains the common variables and parameters used for lighting.
</description>
<methods>
- <method name="set_parameter" >
+ <method name="set_parameter">
<argument index="0" name="variable" type="int">
</argument>
<argument index="1" name="value" type="float">
@@ -13494,15 +15878,15 @@
<description>
</description>
</method>
- <method name="get_parameter" qualifiers="const" >
+ <method name="get_parameter" qualifiers="const">
<return type="float">
</return>
- <argument index="0" name="arg0" type="int">
+ <argument index="0" name="variable" type="int">
</argument>
<description>
</description>
</method>
- <method name="set_color" >
+ <method name="set_color">
<argument index="0" name="color" type="int">
</argument>
<argument index="1" name="value" type="Color">
@@ -13510,81 +15894,81 @@
<description>
</description>
</method>
- <method name="get_color" qualifiers="const" >
+ <method name="get_color" qualifiers="const">
<return type="Color">
</return>
- <argument index="0" name="arg0" type="int">
+ <argument index="0" name="color" type="int">
</argument>
<description>
</description>
</method>
- <method name="set_project_shadows" >
+ <method name="set_project_shadows">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="has_project_shadows" qualifiers="const" >
+ <method name="has_project_shadows" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_projector" >
+ <method name="set_projector">
<argument index="0" name="projector" type="Texture">
</argument>
<description>
</description>
</method>
- <method name="get_projector" qualifiers="const" >
+ <method name="get_projector" qualifiers="const">
<return type="Texture">
</return>
<description>
</description>
</method>
- <method name="set_operator" >
+ <method name="set_operator">
<argument index="0" name="operator" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_operator" qualifiers="const" >
+ <method name="get_operator" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_bake_mode" >
+ <method name="set_bake_mode">
<argument index="0" name="bake_mode" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_bake_mode" qualifiers="const" >
+ <method name="get_bake_mode" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_enabled" >
+ <method name="set_enabled">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_enabled" qualifiers="const" >
+ <method name="is_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_editor_only" >
+ <method name="set_editor_only">
<argument index="0" name="editor_only" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_editor_only" qualifiers="const" >
+ <method name="is_editor_only" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -13600,7 +15984,7 @@
</constant>
<constant name="PARAM_SPOT_ANGLE" value="1">
</constant>
- <constant name="PARAM_SPOT_ATTENUATION" value="4">
+ <constant name="PARAM_SPOT_ATTENUATION" value="0">
</constant>
<constant name="PARAM_SHADOW_DARKENING" value="5">
</constant>
@@ -13620,6 +16004,274 @@
</constant>
</constants>
</class>
+<class name="Light2D" inherits="Node2D" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="set_enabled">
+ <argument index="0" name="enabled" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_enabled" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_texture">
+ <argument index="0" name="texture" type="Object">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_texture" qualifiers="const">
+ <return type="Object">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_texture_offset">
+ <argument index="0" name="texture_offset" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_texture_offset" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_color">
+ <argument index="0" name="color" type="Color">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_color" qualifiers="const">
+ <return type="Color">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_height">
+ <argument index="0" name="height" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_height" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_energy">
+ <argument index="0" name="energy" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_energy" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_texture_scale">
+ <argument index="0" name="texture_scale" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_texture_scale" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_z_range_min">
+ <argument index="0" name="z" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_z_range_min" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_z_range_max">
+ <argument index="0" name="z" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_z_range_max" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_layer_range_min">
+ <argument index="0" name="layer" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_layer_range_min" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_layer_range_max">
+ <argument index="0" name="layer" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_layer_range_max" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_item_mask">
+ <argument index="0" name="item_mask" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_item_mask" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_item_shadow_mask">
+ <argument index="0" name="item_shadow_mask" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_item_shadow_mask" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_mode">
+ <argument index="0" name="mode" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_mode" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_shadow_enabled">
+ <argument index="0" name="enabled" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_shadow_enabled" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_shadow_buffer_size">
+ <argument index="0" name="size" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_shadow_buffer_size" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_shadow_esm_multiplier">
+ <argument index="0" name="multiplier" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_shadow_esm_multiplier" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_shadow_color">
+ <argument index="0" name="shadow_color" type="Color">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_shadow_color" qualifiers="const">
+ <return type="Color">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ <constant name="MODE_ADD" value="0">
+ </constant>
+ <constant name="MODE_SUB" value="1">
+ </constant>
+ <constant name="MODE_MIX" value="2">
+ </constant>
+ <constant name="MODE_MASK" value="3">
+ </constant>
+ </constants>
+</class>
+<class name="LightOccluder2D" inherits="Node2D" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="set_occluder_polygon">
+ <argument index="0" name="polygon" type="OccluderPolygon2D">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_occluder_polygon" qualifiers="const">
+ <return type="OccluderPolygon2D">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_occluder_light_mask">
+ <argument index="0" name="mask" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_occluder_light_mask" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
<class name="LineEdit" inherits="Control" category="Core">
<brief_description>
Control that provides single line string editing.
@@ -13628,94 +16280,106 @@
LineEdit provides a single line string editor, used for text fields.
</description>
<methods>
- <method name="clear" >
+ <method name="set_align">
+ <argument index="0" name="align" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_align" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="clear">
<description>
Clear the [LineEdit] text.
</description>
</method>
- <method name="select_all" >
+ <method name="select_all">
<description>
Select the whole string.
</description>
</method>
- <method name="set_text" >
+ <method name="set_text">
<argument index="0" name="text" type="String">
</argument>
<description>
Set the text in the [LineEdit], clearing the existing one and the selection.
</description>
</method>
- <method name="get_text" qualifiers="const" >
+ <method name="get_text" qualifiers="const">
<return type="String">
</return>
<description>
Return the text in the [LineEdit].
</description>
</method>
- <method name="set_cursor_pos" >
+ <method name="set_cursor_pos">
<argument index="0" name="pos" type="int">
</argument>
<description>
Set the cursor position inside the [LineEdit], causing it to scroll if needed.
</description>
</method>
- <method name="get_cursor_pos" qualifiers="const" >
+ <method name="get_cursor_pos" qualifiers="const">
<return type="int">
</return>
<description>
Return the cursor position inside the [LineEdit].
</description>
</method>
- <method name="set_max_length" >
+ <method name="set_max_length">
<argument index="0" name="chars" type="int">
</argument>
<description>
Set the maximum amount of characters the [LineEdit] can edit, and cropping existing text in case it exceeds that limit. Setting 0 removes the limit.
</description>
</method>
- <method name="get_max_length" qualifiers="const" >
+ <method name="get_max_length" qualifiers="const">
<return type="int">
</return>
<description>
Return the maximum amount of characters the [LineEdit] can edit. If 0 is returned, no limit exists.
</description>
</method>
- <method name="append_at_cursor" >
+ <method name="append_at_cursor">
<argument index="0" name="text" type="String">
</argument>
<description>
Append text at cursor, scrolling the [LineEdit] when needed.
</description>
</method>
- <method name="set_editable" >
+ <method name="set_editable">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
- Set the [i]editable[/i] status of the [LineEdit]. When disabled, existing text can"apos;t be modified and new text can"apos;t be added.
+ Set the [i]editable[/i] status of the [LineEdit]. When disabled, existing text can't be modified and new text can't be added.
</description>
</method>
- <method name="is_editable" qualifiers="const" >
+ <method name="is_editable" qualifiers="const">
<return type="bool">
</return>
<description>
Return the [i]editable[/i] status of the [LineEdit] (see [method set_editable]).
</description>
</method>
- <method name="set_secret" >
+ <method name="set_secret">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
Set the [i]secret[/i] status of the [LineEdit]. When enabled, every character is displayed as "*".
</description>
</method>
- <method name="is_secret" qualifiers="const" >
+ <method name="is_secret" qualifiers="const">
<return type="bool">
</return>
<description>
Return the [i]secret[/i] status of the [LineEdit] (see [method set_secret]).
</description>
</method>
- <method name="select" >
+ <method name="select">
<argument index="0" name="from" type="int" default="0">
</argument>
<argument index="1" name="to" type="int" default="-1">
@@ -13741,6 +16405,14 @@
</signal>
</signals>
<constants>
+ <constant name="ALIGN_LEFT" value="0">
+ </constant>
+ <constant name="ALIGN_CENTER" value="1">
+ </constant>
+ <constant name="ALIGN_RIGHT" value="2">
+ </constant>
+ <constant name="ALIGN_FILL" value="3">
+ </constant>
</constants>
<theme_items>
<theme_item name="minimum_spaces" type="int">
@@ -13771,28 +16443,28 @@
Line shape for 2D collision objects. It works like a 2D plane and will not allow any body to go to the negative side. Not recommended for rigid bodies, and usually not recommended for static bodies either because it forces checks against it on every frame.
</description>
<methods>
- <method name="set_normal" >
+ <method name="set_normal">
<argument index="0" name="normal" type="Vector2">
</argument>
<description>
Set the line normal.
</description>
</method>
- <method name="get_normal" qualifiers="const" >
+ <method name="get_normal" qualifiers="const">
<return type="Vector2">
</return>
<description>
Return the line normal.
</description>
</method>
- <method name="set_d" >
+ <method name="set_d">
<argument index="0" name="d" type="float">
</argument>
<description>
Set the line distance from the origin.
</description>
</method>
- <method name="get_d" qualifiers="const" >
+ <method name="get_d" qualifiers="const">
<return type="float">
</return>
<description>
@@ -13811,14 +16483,80 @@
Main loop is the abstract main loop base class. All other main loop classes are derived from it. Upon application start, a [MainLoop] has to be provided to OS, else the application will exit. This happens automatically (and a [SceneMainLoop] is created), unless a main [Script] is supplied, which may or not create and return a [MainLoop].
</description>
<methods>
- <method name="input_event" >
- <argument index="0" name="arg0" type="InputEvent">
+ <method name="_finalize" qualifiers="virtual">
+ <description>
+ </description>
+ </method>
+ <method name="_idle" qualifiers="virtual">
+ <argument index="0" name="delta" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="_initialize" qualifiers="virtual">
+ <description>
+ </description>
+ </method>
+ <method name="_input_event" qualifiers="virtual">
+ <argument index="0" name="ev" type="InputEvent">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="_input_text" qualifiers="virtual">
+ <argument index="0" name="text" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="_iteration" qualifiers="virtual">
+ <argument index="0" name="delta" type="float">
</argument>
<description>
</description>
</method>
+ <method name="input_event">
+ <argument index="0" name="ev" type="InputEvent">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="input_text">
+ <argument index="0" name="text" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="init">
+ <description>
+ </description>
+ </method>
+ <method name="iteration">
+ <return type="bool">
+ </return>
+ <argument index="0" name="delta" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="idle">
+ <return type="bool">
+ </return>
+ <argument index="0" name="delta" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="finish">
+ <description>
+ </description>
+ </method>
</methods>
<constants>
+ <constant name="NOTIFICATION_WM_MOUSE_ENTER" value="3">
+ </constant>
+ <constant name="NOTIFICATION_WM_MOUSE_EXIT" value="4">
+ </constant>
<constant name="NOTIFICATION_WM_FOCUS_IN" value="5">
</constant>
<constant name="NOTIFICATION_WM_FOCUS_OUT" value="6">
@@ -13853,7 +16591,7 @@
<description>
</description>
<methods>
- <method name="variant_to_base64" >
+ <method name="variant_to_base64">
<return type="String">
</return>
<argument index="0" name="variant" type="var">
@@ -13861,7 +16599,41 @@
<description>
</description>
</method>
- <method name="base64_to_variant" >
+ <method name="base64_to_variant">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="base64_str" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="raw_to_base64">
+ <return type="String">
+ </return>
+ <argument index="0" name="array" type="RawArray">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="base64_to_raw">
+ <return type="RawArray">
+ </return>
+ <argument index="0" name="base64_str" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="utf8_to_base64">
+ <return type="String">
+ </return>
+ <argument index="0" name="utf8_str" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="base64_to_utf8">
+ <return type="String">
+ </return>
<argument index="0" name="base64_str" type="String">
</argument>
<description>
@@ -13879,7 +16651,7 @@
Material is a base [Resource] used for coloring and shading geometry. All materials inherit from it and almost all [VisualInstance] derived nodes carry a Material. A few flags and parameters are shared between all material types and are configured here.
</description>
<methods>
- <method name="set_flag" >
+ <method name="set_flag">
<argument index="0" name="flag" type="int">
</argument>
<argument index="1" name="enable" type="bool">
@@ -13888,7 +16660,7 @@
Set a [Material] flag, which toggles on or off a behavior when rendering. See enumeration FLAG_* for a list.
</description>
</method>
- <method name="get_flag" qualifiers="const" >
+ <method name="get_flag" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="flag" type="int">
@@ -13897,41 +16669,41 @@
Return a [Material] flag, which toggles on or off a behavior when rendering. See enumeration FLAG_* for a list.
</description>
</method>
- <method name="set_blend_mode" >
+ <method name="set_blend_mode">
<argument index="0" name="mode" type="int">
</argument>
<description>
Set blend mode for the material, which can be one of BLEND_MODE_MIX (default), BLEND_MODE_ADD, BLEND_MODE_SUB. Keep in mind that only BLEND_MODE_MIX ensures that the material [i]may[/i] be opaque, any other blend mode will render with alpha blending enabled in raster-based [VisualServer] implementations.
</description>
</method>
- <method name="get_blend_mode" qualifiers="const" >
+ <method name="get_blend_mode" qualifiers="const">
<return type="int">
</return>
<description>
Return blend mode for the material, which can be one of BLEND_MODE_MIX (default), BLEND_MODE_ADD, BLEND_MODE_SUB. Keep in mind that only BLEND_MODE_MIX ensures that the material [i]may[/i] be opaque, any other blend mode will render with alpha blending enabled in raster-based [VisualServer] implementations.
</description>
</method>
- <method name="set_line_width" >
+ <method name="set_line_width">
<argument index="0" name="width" type="float">
</argument>
<description>
Set the line width for geometry drawn with FLAG_WIREFRAME enabled, or LINE primitives. Note that not all hardware or VisualServer backends support this (like DirectX).
</description>
</method>
- <method name="get_line_width" qualifiers="const" >
+ <method name="get_line_width" qualifiers="const">
<return type="float">
</return>
<description>
Return the line width for geometry drawn with FLAG_WIREFRAME enabled, or LINE primitives. Note that not all hardware or VisualServer backends support this (like DirectX).
</description>
</method>
- <method name="set_depth_draw_mode" >
+ <method name="set_depth_draw_mode">
<argument index="0" name="mode" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_depth_draw_mode" qualifiers="const" >
+ <method name="get_depth_draw_mode" qualifiers="const">
<return type="int">
</return>
<description>
@@ -13958,7 +16730,7 @@
<constant name="FLAG_COLOR_ARRAY_SRGB" value="6">
</constant>
<constant name="FLAG_MAX" value="7">
- Maximum amount of flags
+ Maximum amount of flags.
</constant>
<constant name="DEPTH_DRAW_ALWAYS" value="0">
</constant>
@@ -13983,6 +16755,26 @@
</constant>
</constants>
</class>
+<class name="MaterialShader" inherits="Shader" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
+<class name="MaterialShaderGraph" inherits="ShaderGraph" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
<class name="Matrix3" category="Built-In Types">
<brief_description>
3x3 matrix datatype.
@@ -13991,47 +16783,47 @@
3x3 matrix used for 3D rotation and scale. Contains 3 vector fields x,y and z. Can also be accessed as array of 3D vectors. Almost always used as orthogonal basis for a [Transform].
</description>
<methods>
- <method name="determinant" >
+ <method name="determinant">
<return type="float">
</return>
<description>
Return the determinant of the matrix.
</description>
</method>
- <method name="get_euler" >
+ <method name="get_euler">
<return type="Vector3">
</return>
<description>
Return euler angles from the matrix.
</description>
</method>
- <method name="get_orthogonal_index" >
+ <method name="get_orthogonal_index">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_scale" >
+ <method name="get_scale">
<return type="Vector3">
</return>
<description>
</description>
</method>
- <method name="inverse" >
+ <method name="inverse">
<return type="Matrix3">
</return>
<description>
Return the affine inverse of the matrix.
</description>
</method>
- <method name="orthonormalized" >
+ <method name="orthonormalized">
<return type="Matrix3">
</return>
<description>
Return the orthonormalized version of the matrix (useful to call from time to time to avoid rounding error).
</description>
</method>
- <method name="rotated" >
+ <method name="rotated">
<return type="Matrix3">
</return>
<argument index="0" name="axis" type="Vector3">
@@ -14042,7 +16834,7 @@
Return the rotated version of the matrix, by a given axis and angle.
</description>
</method>
- <method name="scaled" >
+ <method name="scaled">
<return type="Matrix3">
</return>
<argument index="0" name="scale" type="Vector3">
@@ -14051,7 +16843,7 @@
Return the scaled version of the matrix, by a 3D scale.
</description>
</method>
- <method name="tdotx" >
+ <method name="tdotx">
<return type="float">
</return>
<argument index="0" name="with" type="Vector3">
@@ -14060,7 +16852,7 @@
Transposed dot product with the x axis of the matrix.
</description>
</method>
- <method name="tdoty" >
+ <method name="tdoty">
<return type="float">
</return>
<argument index="0" name="with" type="Vector3">
@@ -14069,7 +16861,7 @@
Transposed dot product with the y axis of the matrix.
</description>
</method>
- <method name="tdotz" >
+ <method name="tdotz">
<return type="float">
</return>
<argument index="0" name="with" type="Vector3">
@@ -14078,14 +16870,14 @@
Transposed dot product with the z axis of the matrix.
</description>
</method>
- <method name="transposed" >
+ <method name="transposed">
<return type="Matrix3">
</return>
<description>
Return the transposed version of the matrix.
</description>
</method>
- <method name="xform" >
+ <method name="xform">
<return type="Vector3">
</return>
<argument index="0" name="v" type="Vector3">
@@ -14094,7 +16886,7 @@
Return a vector transformed by the matrix and return it.
</description>
</method>
- <method name="xform_inv" >
+ <method name="xform_inv">
<return type="Vector3">
</return>
<argument index="0" name="v" type="Vector3">
@@ -14103,7 +16895,9 @@
Return a vector transformed by the transposed matrix and return it.
</description>
</method>
- <method name="Matrix3" >
+ <method name="Matrix3">
+ <return type="Matrix3">
+ </return>
<argument index="0" name="x_axis" type="Vector3">
</argument>
<argument index="1" name="y_axis" type="Vector3">
@@ -14114,7 +16908,9 @@
Create a matrix from 3 axis vectors.
</description>
</method>
- <method name="Matrix3" >
+ <method name="Matrix3">
+ <return type="Matrix3">
+ </return>
<argument index="0" name="axis" type="Vector3">
</argument>
<argument index="1" name="phi" type="float">
@@ -14123,7 +16919,9 @@
Create a matrix from an axis vector and an angle.
</description>
</method>
- <method name="Matrix3" >
+ <method name="Matrix3">
+ <return type="Matrix3">
+ </return>
<argument index="0" name="from" type="Quat">
</argument>
<description>
@@ -14150,13 +16948,13 @@
3x2 Matrix for 2D transforms.
</description>
<methods>
- <method name="affine_inverse" >
+ <method name="affine_inverse">
<return type="Matrix32">
</return>
<description>
</description>
</method>
- <method name="basis_xform" >
+ <method name="basis_xform">
<return type="Matrix32">
</return>
<argument index="0" name="v" type="var">
@@ -14164,7 +16962,7 @@
<description>
</description>
</method>
- <method name="basis_xform_inv" >
+ <method name="basis_xform_inv">
<return type="Matrix32">
</return>
<argument index="0" name="v" type="var">
@@ -14172,25 +16970,25 @@
<description>
</description>
</method>
- <method name="get_origin" >
+ <method name="get_origin">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="get_rotation" >
+ <method name="get_rotation">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="get_scale" >
+ <method name="get_scale">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="interpolate_with" >
+ <method name="interpolate_with">
<return type="Matrix32">
</return>
<argument index="0" name="m" type="Matrix32">
@@ -14200,19 +16998,19 @@
<description>
</description>
</method>
- <method name="inverse" >
+ <method name="inverse">
<return type="Matrix32">
</return>
<description>
</description>
</method>
- <method name="orthonormalized" >
+ <method name="orthonormalized">
<return type="Matrix32">
</return>
<description>
</description>
</method>
- <method name="rotated" >
+ <method name="rotated">
<return type="Matrix32">
</return>
<argument index="0" name="phi" type="float">
@@ -14220,7 +17018,7 @@
<description>
</description>
</method>
- <method name="scaled" >
+ <method name="scaled">
<return type="Matrix32">
</return>
<argument index="0" name="scale" type="Vector2">
@@ -14228,7 +17026,7 @@
<description>
</description>
</method>
- <method name="translated" >
+ <method name="translated">
<return type="Matrix32">
</return>
<argument index="0" name="offset" type="Vector2">
@@ -14236,7 +17034,7 @@
<description>
</description>
</method>
- <method name="xform" >
+ <method name="xform">
<return type="Matrix32">
</return>
<argument index="0" name="v" type="var">
@@ -14244,7 +17042,7 @@
<description>
</description>
</method>
- <method name="xform_inv" >
+ <method name="xform_inv">
<return type="Matrix32">
</return>
<argument index="0" name="v" type="var">
@@ -14252,7 +17050,19 @@
<description>
</description>
</method>
- <method name="Matrix32" >
+ <method name="Matrix32">
+ <return type="Matrix32">
+ </return>
+ <argument index="0" name="rot" type="float">
+ </argument>
+ <argument index="1" name="pos" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="Matrix32">
+ <return type="Matrix32">
+ </return>
<argument index="0" name="x_axis" type="Vector2">
</argument>
<argument index="1" name="y_axis" type="Vector2">
@@ -14262,13 +17072,21 @@
<description>
</description>
</method>
+ <method name="Matrix32">
+ <return type="Matrix32">
+ </return>
+ <argument index="0" name="from" type="Transform">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<members>
- <member name="x" type="float">
+ <member name="x" type="Vector2">
</member>
- <member name="y" type="float">
+ <member name="y" type="Vector2">
</member>
- <member name="o" type="float">
+ <member name="o" type="Vector2">
</member>
</members>
<constants>
@@ -14282,8 +17100,8 @@
Special button that brings up a [PopupMenu] when clicked. That's pretty much all it does, as it's just a helper class when bulding GUIs.
</description>
<methods>
- <method name="get_popup" >
- <return type="Object">
+ <method name="get_popup">
+ <return type="PopupMenu">
</return>
<description>
Return the [PopupMenu] contained in this button.
@@ -14315,6 +17133,8 @@
</theme_item>
<theme_item name="pressed" type="StyleBox">
</theme_item>
+ <theme_item name="focus" type="StyleBox">
+ </theme_item>
<theme_item name="disabled" type="StyleBox">
</theme_item>
<theme_item name="normal" type="StyleBox">
@@ -14329,19 +17149,19 @@
Mesh is a type of [Resource] that contains vertex-array based geometry, divided in [i]surfaces[/i]. Each surface contains a completely separate array and a material used to draw it. Design wise, a mesh with multiple surfaces is prefered to a single surface, because objects created in 3D editing software commonly contain multiple materials.
</description>
<methods>
- <method name="add_morph_target" >
+ <method name="add_morph_target">
<argument index="0" name="name" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_morph_target_count" qualifiers="const" >
+ <method name="get_morph_target_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_morph_target_name" qualifiers="const" >
+ <method name="get_morph_target_name" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="index" type="int">
@@ -14349,50 +17169,52 @@
<description>
</description>
</method>
- <method name="clear_morph_targets" >
+ <method name="clear_morph_targets">
<description>
</description>
</method>
- <method name="set_morph_target_mode" >
+ <method name="set_morph_target_mode">
<argument index="0" name="mode" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_morph_target_mode" qualifiers="const" >
+ <method name="get_morph_target_mode" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="add_surface" >
+ <method name="add_surface">
<argument index="0" name="primitive" type="int">
</argument>
<argument index="1" name="arrays" type="Array">
</argument>
- <argument index="2" name="morph_arrays" type="Array">
+ <argument index="2" name="morph_arrays" type="Array" default="Array()">
</argument>
- <argument index="3" name="arg3" type="bool" default="Array()">
+ <argument index="3" name="alphasort" type="bool" default="false">
</argument>
<description>
- Create a new surface ([method get_surface_count] will become surf_idx for this.[br]"#10;"#9;"#9;"#9;Surfaces are created to be rendered using a "primitive", which may be PRIMITIVE_POINTS, PRIMITIVE_LINES, PRIMITIVE_LINE_STRIP, PRIMITIVE_LINE_LOOP, PRIMITIVE_TRIANGLES, PRIMITIVE_TRIANGLE_STRIP, PRIMITIVE_TRIANGLE_FAN. (As a note, when using indices, it is recommended to only use just points, lines or triangles).[br]"#10;"#9;"#9;"#9;The format of a surface determines which arrays it will allocate and hold, so "format" is a combination of ARRAY_FORMAT_* mask constants ORed together. ARRAY_FORMAT_VERTEX must be always present. "array_len" determines the amount of vertices in the array (not primitives!). if ARRAY_FORMAT_INDEX is in the format mask, then it means that an index array will be allocated and "index_array_len" must be passed.
+ Create a new surface ([method get_surface_count] that will become surf_idx for this.
+ Surfaces are created to be rendered using a "primitive", which may be PRIMITIVE_POINTS, PRIMITIVE_LINES, PRIMITIVE_LINE_STRIP, PRIMITIVE_LINE_LOOP, PRIMITIVE_TRIANGLES, PRIMITIVE_TRIANGLE_STRIP, PRIMITIVE_TRIANGLE_FAN. (As a note, when using indices, it is recommended to only use just points, lines or triangles).
+ The format of a surface determines which arrays it will allocate and hold, so "format" is a combination of ARRAY_FORMAT_* mask constants ORed together. ARRAY_FORMAT_VERTEX must be always present. "array_len" determines the amount of vertices in the array (not primitives!). if ARRAY_FORMAT_INDEX is in the format mask, then it means that an index array will be allocated and "index_array_len" must be passed.
</description>
</method>
- <method name="get_surface_count" qualifiers="const" >
+ <method name="get_surface_count" qualifiers="const">
<return type="int">
</return>
<description>
Return the amount of surfaces that the [Mesh] holds.
</description>
</method>
- <method name="surface_remove" >
+ <method name="surface_remove">
<argument index="0" name="surf_idx" type="int">
</argument>
<description>
Remove a surface at position surf_idx, shifting greater surfaces one surf_idx slot down.
</description>
</method>
- <method name="surface_get_array_len" qualifiers="const" >
+ <method name="surface_get_array_len" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="surf_idx" type="int">
@@ -14401,7 +17223,7 @@
Return the length in vertices of the vertex array in the requested surface (see [method add_surface]).
</description>
</method>
- <method name="surface_get_array_index_len" qualifiers="const" >
+ <method name="surface_get_array_index_len" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="surf_idx" type="int">
@@ -14410,7 +17232,7 @@
Return the length in indices of the index array in the requested surface (see [method add_surface]).
</description>
</method>
- <method name="surface_get_format" qualifiers="const" >
+ <method name="surface_get_format" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="surf_idx" type="int">
@@ -14419,7 +17241,7 @@
Return the format mask of the requested surface (see [method add_surface]).
</description>
</method>
- <method name="surface_get_primitive_type" qualifiers="const" >
+ <method name="surface_get_primitive_type" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="surf_idx" type="int">
@@ -14428,7 +17250,7 @@
Return the primitive type of the requested surface (see [method add_surface]).
</description>
</method>
- <method name="surface_set_material" >
+ <method name="surface_set_material">
<argument index="0" name="surf_idx" type="int">
</argument>
<argument index="1" name="material" type="Material">
@@ -14437,7 +17259,7 @@
Set a [Material] for a given surface. Surface will be rendered using this material.
</description>
</method>
- <method name="surface_get_material" qualifiers="const" >
+ <method name="surface_get_material" qualifiers="const">
<return type="Material">
</return>
<argument index="0" name="surf_idx" type="int">
@@ -14446,7 +17268,7 @@
Return a [Material] in a given surface. Surface is rendered using this material.
</description>
</method>
- <method name="surface_set_name" >
+ <method name="surface_set_name">
<argument index="0" name="surf_idx" type="int">
</argument>
<argument index="1" name="name" type="String">
@@ -14454,7 +17276,7 @@
<description>
</description>
</method>
- <method name="surface_get_name" qualifiers="const" >
+ <method name="surface_get_name" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="surf_idx" type="int">
@@ -14462,21 +17284,21 @@
<description>
</description>
</method>
- <method name="center_geometry" >
+ <method name="center_geometry">
<description>
</description>
</method>
- <method name="regen_normalmaps" >
+ <method name="regen_normalmaps">
<description>
</description>
</method>
- <method name="set_custom_aabb" >
+ <method name="set_custom_aabb">
<argument index="0" name="aabb" type="AABB">
</argument>
<description>
</description>
</method>
- <method name="get_custom_aabb" qualifiers="const" >
+ <method name="get_custom_aabb" qualifiers="const">
<return type="AABB">
</return>
<description>
@@ -14506,6 +17328,7 @@
UV array (array of [Vector3]() UVs or float array of groups of 2 floats (u,v)).
</constant>
<constant name="ARRAY_TEX_UV2" value="5">
+ Second UV array (array of [Vector3]() UVs or float array of groups of 2 floats (u,v)).
</constant>
<constant name="ARRAY_BONES" value="6">
Array of bone indices, as a float array. Each element in groups of 4 floats.
@@ -14532,6 +17355,7 @@
Array format will include UVs.
</constant>
<constant name="ARRAY_FORMAT_TEX_UV2" value="32">
+ Array format will include another set of UVs.
</constant>
<constant name="ARRAY_FORMAT_BONES" value="64">
Array format will include bone indices.
@@ -14571,11 +17395,11 @@
<description>
</description>
<methods>
- <method name="clear" >
+ <method name="clear">
<description>
</description>
</method>
- <method name="create_from_surface" >
+ <method name="create_from_surface">
<return type="int">
</return>
<argument index="0" name="mesh" type="Object">
@@ -14585,7 +17409,7 @@
<description>
</description>
</method>
- <method name="commit_to_surface" >
+ <method name="commit_to_surface">
<return type="int">
</return>
<argument index="0" name="mesh" type="Object">
@@ -14593,31 +17417,31 @@
<description>
</description>
</method>
- <method name="get_format" qualifiers="const" >
+ <method name="get_format" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_vertex_count" qualifiers="const" >
+ <method name="get_vertex_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_edge_count" qualifiers="const" >
+ <method name="get_edge_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_face_count" qualifiers="const" >
+ <method name="get_face_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_vertex" >
+ <method name="set_vertex">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="vertex" type="Vector3">
@@ -14625,7 +17449,7 @@
<description>
</description>
</method>
- <method name="get_vertex" qualifiers="const" >
+ <method name="get_vertex" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="idx" type="int">
@@ -14633,7 +17457,7 @@
<description>
</description>
</method>
- <method name="set_vertex_normal" >
+ <method name="set_vertex_normal">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="normal" type="Vector3">
@@ -14641,7 +17465,7 @@
<description>
</description>
</method>
- <method name="get_vertex_normal" qualifiers="const" >
+ <method name="get_vertex_normal" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="idx" type="int">
@@ -14649,7 +17473,7 @@
<description>
</description>
</method>
- <method name="set_vertex_tangent" >
+ <method name="set_vertex_tangent">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="tangent" type="Plane">
@@ -14657,7 +17481,7 @@
<description>
</description>
</method>
- <method name="get_vertex_tangent" qualifiers="const" >
+ <method name="get_vertex_tangent" qualifiers="const">
<return type="Plane">
</return>
<argument index="0" name="idx" type="int">
@@ -14665,7 +17489,7 @@
<description>
</description>
</method>
- <method name="set_vertex_uv" >
+ <method name="set_vertex_uv">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="uv" type="Vector2">
@@ -14673,7 +17497,7 @@
<description>
</description>
</method>
- <method name="get_vertex_uv" qualifiers="const" >
+ <method name="get_vertex_uv" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="idx" type="int">
@@ -14681,7 +17505,7 @@
<description>
</description>
</method>
- <method name="set_vertex_uv2" >
+ <method name="set_vertex_uv2">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="uv2" type="Vector2">
@@ -14689,7 +17513,7 @@
<description>
</description>
</method>
- <method name="get_vertex_uv2" qualifiers="const" >
+ <method name="get_vertex_uv2" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="idx" type="int">
@@ -14697,7 +17521,7 @@
<description>
</description>
</method>
- <method name="set_vertex_color" >
+ <method name="set_vertex_color">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="color" type="Color">
@@ -14705,7 +17529,7 @@
<description>
</description>
</method>
- <method name="get_vertex_color" qualifiers="const" >
+ <method name="get_vertex_color" qualifiers="const">
<return type="Color">
</return>
<argument index="0" name="idx" type="int">
@@ -14713,7 +17537,7 @@
<description>
</description>
</method>
- <method name="set_vertex_bones" >
+ <method name="set_vertex_bones">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="bones" type="IntArray">
@@ -14721,7 +17545,7 @@
<description>
</description>
</method>
- <method name="get_vertex_bones" qualifiers="const" >
+ <method name="get_vertex_bones" qualifiers="const">
<return type="IntArray">
</return>
<argument index="0" name="idx" type="int">
@@ -14729,7 +17553,7 @@
<description>
</description>
</method>
- <method name="set_vertex_weights" >
+ <method name="set_vertex_weights">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="weights" type="RealArray">
@@ -14737,7 +17561,7 @@
<description>
</description>
</method>
- <method name="get_vertex_weights" qualifiers="const" >
+ <method name="get_vertex_weights" qualifiers="const">
<return type="RealArray">
</return>
<argument index="0" name="idx" type="int">
@@ -14745,7 +17569,7 @@
<description>
</description>
</method>
- <method name="set_vertex_meta" >
+ <method name="set_vertex_meta">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="meta" type="var">
@@ -14753,13 +17577,13 @@
<description>
</description>
</method>
- <method name="get_vertex_meta" qualifiers="const" >
+ <method name="get_vertex_meta" qualifiers="const">
<argument index="0" name="idx" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_vertex_edges" qualifiers="const" >
+ <method name="get_vertex_edges" qualifiers="const">
<return type="IntArray">
</return>
<argument index="0" name="idx" type="int">
@@ -14767,7 +17591,7 @@
<description>
</description>
</method>
- <method name="get_vertex_faces" qualifiers="const" >
+ <method name="get_vertex_faces" qualifiers="const">
<return type="IntArray">
</return>
<argument index="0" name="idx" type="int">
@@ -14775,7 +17599,7 @@
<description>
</description>
</method>
- <method name="get_edge_vertex" qualifiers="const" >
+ <method name="get_edge_vertex" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="idx" type="int">
@@ -14785,7 +17609,7 @@
<description>
</description>
</method>
- <method name="get_edge_faces" qualifiers="const" >
+ <method name="get_edge_faces" qualifiers="const">
<return type="IntArray">
</return>
<argument index="0" name="idx" type="int">
@@ -14793,7 +17617,7 @@
<description>
</description>
</method>
- <method name="set_edge_meta" >
+ <method name="set_edge_meta">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="meta" type="var">
@@ -14801,13 +17625,13 @@
<description>
</description>
</method>
- <method name="get_edge_meta" qualifiers="const" >
+ <method name="get_edge_meta" qualifiers="const">
<argument index="0" name="idx" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_face_vertex" qualifiers="const" >
+ <method name="get_face_vertex" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="idx" type="int">
@@ -14817,7 +17641,7 @@
<description>
</description>
</method>
- <method name="get_face_edge" qualifiers="const" >
+ <method name="get_face_edge" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="idx" type="int">
@@ -14827,7 +17651,7 @@
<description>
</description>
</method>
- <method name="set_face_meta" >
+ <method name="set_face_meta">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="meta" type="var">
@@ -14835,13 +17659,13 @@
<description>
</description>
</method>
- <method name="get_face_meta" qualifiers="const" >
+ <method name="get_face_meta" qualifiers="const">
<argument index="0" name="idx" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_face_normal" qualifiers="const" >
+ <method name="get_face_normal" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="idx" type="int">
@@ -14849,13 +17673,13 @@
<description>
</description>
</method>
- <method name="set_material" >
+ <method name="set_material">
<argument index="0" name="material" type="Material">
</argument>
<description>
</description>
</method>
- <method name="get_material" qualifiers="const" >
+ <method name="get_material" qualifiers="const">
<return type="Object">
</return>
<description>
@@ -14873,45 +17697,45 @@
MeshInstance is a [Node] that takes a [Mesh] resource and adds it to the current [Scenario] by creating an instance of it. This is the class most often used to get 3D geometry rendered and can be used to instance a sigle [Mesh] in many places. This allows to reuse geometry and save on resources. When a [Mesh] has to be instanced more than thousands of times at close proximity, consider using a [MultiMesh] in a [MultiMeshInstance] instead.
</description>
<methods>
- <method name="set_mesh" >
+ <method name="set_mesh">
<argument index="0" name="mesh" type="Mesh">
</argument>
<description>
Set the [Mesh] resource for the instance.
</description>
</method>
- <method name="get_mesh" qualifiers="const" >
+ <method name="get_mesh" qualifiers="const">
<return type="Mesh">
</return>
<description>
Return the current [Mesh] resource for the instance.
</description>
</method>
- <method name="set_skeleton_path" >
+ <method name="set_skeleton_path">
<argument index="0" name="skeleton_path" type="NodePath">
</argument>
<description>
</description>
</method>
- <method name="get_skeleton_path" >
+ <method name="get_skeleton_path">
<return type="NodePath">
</return>
<description>
</description>
</method>
- <method name="get_aabb" qualifiers="const" >
+ <method name="get_aabb" qualifiers="const">
<return type="AABB">
</return>
<description>
Return the AABB of the mesh, in local coordinates.
</description>
</method>
- <method name="create_trimesh_collision" >
+ <method name="create_trimesh_collision">
<description>
- This helper creates a [StaticBody] child [Node] using the mesh geometry as collision. It"apos;s mainly used for testing.
+ This helper creates a [StaticBody] child [Node] using the mesh geometry as collision. It's mainly used for testing.
</description>
</method>
- <method name="create_convex_collision" >
+ <method name="create_convex_collision">
<description>
</description>
</method>
@@ -14927,14 +17751,14 @@
Library of meshes. Contains a list of [Mesh] resources, each with name and ID. Useful for GridMap or painting Terrain.
</description>
<methods>
- <method name="create_item" >
+ <method name="create_item">
<argument index="0" name="id" type="int">
</argument>
<description>
Create a new item in the library, supplied an id.
</description>
</method>
- <method name="set_item_name" >
+ <method name="set_item_name">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="name" type="String">
@@ -14943,7 +17767,7 @@
Set the name of the item.
</description>
</method>
- <method name="set_item_mesh" >
+ <method name="set_item_mesh">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="mesh" type="Mesh">
@@ -14952,7 +17776,7 @@
Set the mesh of the item.
</description>
</method>
- <method name="set_item_shape" >
+ <method name="set_item_shape">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="shape" type="Shape">
@@ -14960,7 +17784,7 @@
<description>
</description>
</method>
- <method name="get_item_name" qualifiers="const" >
+ <method name="get_item_name" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="id" type="int">
@@ -14969,7 +17793,7 @@
Return the name of the item.
</description>
</method>
- <method name="get_item_mesh" qualifiers="const" >
+ <method name="get_item_mesh" qualifiers="const">
<return type="Mesh">
</return>
<argument index="0" name="id" type="int">
@@ -14978,7 +17802,7 @@
Return the mesh of the item.
</description>
</method>
- <method name="get_item_shape" qualifiers="const" >
+ <method name="get_item_shape" qualifiers="const">
<return type="Shape">
</return>
<argument index="0" name="id" type="int">
@@ -14986,26 +17810,26 @@
<description>
</description>
</method>
- <method name="remove_item" >
+ <method name="remove_item">
<argument index="0" name="id" type="int">
</argument>
<description>
Remove the item.
</description>
</method>
- <method name="clear" >
+ <method name="clear">
<description>
Clear the library.
</description>
</method>
- <method name="get_item_list" qualifiers="const" >
+ <method name="get_item_list" qualifiers="const">
<return type="IntArray">
</return>
<description>
Return the list of items.
</description>
</method>
- <method name="get_last_unused_item_id" qualifiers="const" >
+ <method name="get_last_unused_item_id" qualifiers="const">
<return type="int">
</return>
<description>
@@ -15021,88 +17845,90 @@
Provides high perfomance mesh instancing.
</brief_description>
<description>
- MultiMesh provides low level mesh instancing. If the amount of [Mesh] instances needed goes from hundreds to thousands (and most need to be visible at close proximity) creating such a large amount of [MeshInstance] nodes may affect performance by using too much CPU or video memory. [br]For this case a MultiMesh becomes very useful, as it can draw thousands of instances with little API overhead.[br] As a drawback, if the instances are too far away of each other, performance may be reduced as every sigle instance will always rendered (they are spatially indexed as one, for the whole object).[br] Since instances may have any behavior, the AABB used for visibility must be provided by the user, or generated with [method generate_aabb].
+ MultiMesh provides low level mesh instancing. If the amount of [Mesh] instances needed goes from hundreds to thousands (and most need to be visible at close proximity) creating such a large amount of [MeshInstance] nodes may affect performance by using too much CPU or video memory.
+ For this case a MultiMesh becomes very useful, as it can draw thousands of instances with little API overhead.[br] As a drawback, if the instances are too far away of each other, performance may be reduced as every sigle instance will always rendered (they are spatially indexed as one, for the whole object).
+ Since instances may have any behavior, the AABB used for visibility must be provided by the user, or generated with [method generate_aabb].
</description>
<methods>
- <method name="set_mesh" >
+ <method name="set_mesh">
<argument index="0" name="mesh" type="Mesh">
</argument>
<description>
Set the [Mesh] resource to be drawn in multiple instances.
</description>
</method>
- <method name="get_mesh" qualifiers="const" >
+ <method name="get_mesh" qualifiers="const">
<return type="Mesh">
</return>
<description>
Return the [Mesh] resource drawn as multiple instances.
</description>
</method>
- <method name="set_instance_count" >
- <argument index="0" name="arg0" type="int">
+ <method name="set_instance_count">
+ <argument index="0" name="count" type="int">
</argument>
<description>
Set the amount of instnces that is going to be drawn. Changing this number will erase all the existing instance transform and color data.
</description>
</method>
- <method name="get_instance_count" qualifiers="const" >
+ <method name="get_instance_count" qualifiers="const">
<return type="int">
</return>
<description>
Return the amount of instnces that is going to be drawn.
</description>
</method>
- <method name="set_instance_transform" >
- <argument index="0" name="arg0" type="int">
+ <method name="set_instance_transform">
+ <argument index="0" name="instance" type="int">
</argument>
- <argument index="1" name="arg1" type="Transform">
+ <argument index="1" name="transform" type="Transform">
</argument>
<description>
Set the transform for a specific instance.
</description>
</method>
- <method name="get_instance_transform" qualifiers="const" >
+ <method name="get_instance_transform" qualifiers="const">
<return type="Transform">
</return>
- <argument index="0" name="arg0" type="int">
+ <argument index="0" name="instance" type="int">
</argument>
<description>
Return the transform of a specific instance.
</description>
</method>
- <method name="set_instance_color" >
- <argument index="0" name="arg0" type="int">
+ <method name="set_instance_color">
+ <argument index="0" name="instance" type="int">
</argument>
- <argument index="1" name="arg1" type="Color">
+ <argument index="1" name="color" type="Color">
</argument>
<description>
Set the color of a specific instance.
</description>
</method>
- <method name="get_instance_color" qualifiers="const" >
+ <method name="get_instance_color" qualifiers="const">
<return type="Color">
</return>
- <argument index="0" name="arg0" type="int">
+ <argument index="0" name="instance" type="int">
</argument>
<description>
Get the color of a specific instance.
</description>
</method>
- <method name="set_aabb" >
- <argument index="0" name="arg0" type="AABB">
+ <method name="set_aabb">
+ <argument index="0" name="visibility_aabb" type="AABB">
</argument>
<description>
Set the visibility AABB. If not provided, MultiMesh will not be visible.
</description>
</method>
- <method name="get_aabb" qualifiers="const" >
+ <method name="get_aabb" qualifiers="const">
<return type="AABB">
</return>
<description>
Return the visibility AABB.
</description>
</method>
- <method name="generate_aabb" >
+ <method name="generate_aabb">
<description>
Generate a new visibility AABB, using mesh AABB and instance transforms. Since instance information is stored in the [VisualServer], this function is VERY SLOW and must NOT be used often.
</description>
@@ -15119,14 +17945,14 @@
MultiMeshInstance is a [Node] that takes a [MultiMesh] resource and adds it to the current [Scenario] by creating an instance of it (yes, this is an instance of instances).
</description>
<methods>
- <method name="set_multimesh" >
+ <method name="set_multimesh">
<argument index="0" name="multimesh" type="Object">
</argument>
<description>
Set the [MultiMesh] to be instance.
</description>
</method>
- <method name="get_multimesh" qualifiers="const" >
+ <method name="get_multimesh" qualifiers="const">
<return type="Object">
</return>
<description>
@@ -15143,17 +17969,17 @@
<description>
</description>
<methods>
- <method name="lock" >
+ <method name="lock">
<description>
</description>
</method>
- <method name="try_lock" >
- <return type="int">
+ <method name="try_lock">
+ <return type="Error">
</return>
<description>
</description>
</method>
- <method name="unlock" >
+ <method name="unlock">
<description>
</description>
</method>
@@ -15167,7 +17993,7 @@
<description>
</description>
<methods>
- <method name="navmesh_create" >
+ <method name="navmesh_create">
<return type="int">
</return>
<argument index="0" name="mesh" type="NavigationMesh">
@@ -15179,7 +18005,7 @@
<description>
</description>
</method>
- <method name="navmesh_set_transform" >
+ <method name="navmesh_set_transform">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="xform" type="Transform">
@@ -15187,13 +18013,13 @@
<description>
</description>
</method>
- <method name="navmesh_remove" >
+ <method name="navmesh_remove">
<argument index="0" name="id" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_simple_path" >
+ <method name="get_simple_path">
<return type="Vector3Array">
</return>
<argument index="0" name="start" type="Vector3">
@@ -15205,17 +18031,19 @@
<description>
</description>
</method>
- <method name="get_closest_point_to_segment" >
+ <method name="get_closest_point_to_segment">
<return type="Vector3">
</return>
<argument index="0" name="start" type="Vector3">
</argument>
<argument index="1" name="end" type="Vector3">
</argument>
+ <argument index="2" name="use_collision" type="bool" default="false">
+ </argument>
<description>
</description>
</method>
- <method name="get_closest_point" >
+ <method name="get_closest_point">
<return type="Vector3">
</return>
<argument index="0" name="to_point" type="Vector3">
@@ -15223,7 +18051,7 @@
<description>
</description>
</method>
- <method name="get_closest_point_normal" >
+ <method name="get_closest_point_normal">
<return type="Vector3">
</return>
<argument index="0" name="to_point" type="Vector3">
@@ -15231,13 +18059,21 @@
<description>
</description>
</method>
- <method name="set_up_vector" >
+ <method name="get_closest_point_owner">
+ <return type="Object">
+ </return>
+ <argument index="0" name="to_point" type="Vector3">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_up_vector">
<argument index="0" name="up" type="Vector3">
</argument>
<description>
</description>
</method>
- <method name="get_up_vector" qualifiers="const" >
+ <method name="get_up_vector" qualifiers="const">
<return type="Vector3">
</return>
<description>
@@ -15247,37 +18083,101 @@
<constants>
</constants>
</class>
+<class name="Navigation2D" inherits="Node2D" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="navpoly_create">
+ <return type="int">
+ </return>
+ <argument index="0" name="mesh" type="NavigationPolygon">
+ </argument>
+ <argument index="1" name="xform" type="Matrix32">
+ </argument>
+ <argument index="2" name="owner" type="Object" default="NULL">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="navpoly_set_transform">
+ <argument index="0" name="id" type="int">
+ </argument>
+ <argument index="1" name="xform" type="Matrix32">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="navpoly_remove">
+ <argument index="0" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_simple_path">
+ <return type="Vector2Array">
+ </return>
+ <argument index="0" name="start" type="Vector2">
+ </argument>
+ <argument index="1" name="end" type="Vector2">
+ </argument>
+ <argument index="2" name="optimize" type="bool" default="true">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_closest_point">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="to_point" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_closest_point_owner">
+ <return type="Object">
+ </return>
+ <argument index="0" name="to_point" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
<class name="NavigationMesh" inherits="Resource" category="Core">
<brief_description>
</brief_description>
<description>
</description>
<methods>
- <method name="set_vertices" >
+ <method name="set_vertices">
<argument index="0" name="vertices" type="Vector3Array">
</argument>
<description>
</description>
</method>
- <method name="get_vertices" qualifiers="const" >
+ <method name="get_vertices" qualifiers="const">
<return type="Vector3Array">
</return>
<description>
</description>
</method>
- <method name="add_polygon" >
+ <method name="add_polygon">
<argument index="0" name="polygon" type="IntArray">
</argument>
<description>
</description>
</method>
- <method name="get_polygon_count" qualifiers="const" >
+ <method name="get_polygon_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_polygon" >
+ <method name="get_polygon">
<return type="IntArray">
</return>
<argument index="0" name="idx" type="int">
@@ -15285,7 +18185,7 @@
<description>
</description>
</method>
- <method name="clear_polygons" >
+ <method name="clear_polygons">
<description>
</description>
</method>
@@ -15299,25 +18199,155 @@
<description>
</description>
<methods>
- <method name="set_navigation_mesh" >
+ <method name="set_navigation_mesh">
<argument index="0" name="navmesh" type="Object">
</argument>
<description>
</description>
</method>
- <method name="get_navigation_mesh" qualifiers="const" >
+ <method name="get_navigation_mesh" qualifiers="const">
<return type="Object">
</return>
<description>
</description>
</method>
- <method name="set_enabled" >
+ <method name="set_enabled">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_enabled" qualifiers="const" >
+ <method name="is_enabled" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
+<class name="NavigationPolygon" inherits="Resource" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="set_vertices">
+ <argument index="0" name="vertices" type="Vector2Array">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_vertices" qualifiers="const">
+ <return type="Vector2Array">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="add_polygon">
+ <argument index="0" name="polygon" type="IntArray">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_polygon_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_polygon">
+ <return type="IntArray">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="clear_polygons">
+ <description>
+ </description>
+ </method>
+ <method name="add_outline">
+ <argument index="0" name="outline" type="Vector2Array">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="add_outline_at_index">
+ <argument index="0" name="outline" type="Vector2Array">
+ </argument>
+ <argument index="1" name="index" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_outline_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_outline">
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <argument index="1" name="outline" type="Vector2Array">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_outline" qualifiers="const">
+ <return type="Vector2Array">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="remove_outline">
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="clear_outlines">
+ <description>
+ </description>
+ </method>
+ <method name="make_polygons_from_outlines">
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
+<class name="NavigationPolygonInstance" inherits="Node2D" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="set_navigation_polygon">
+ <argument index="0" name="navpoly" type="Object">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_navigation_polygon" qualifiers="const">
+ <return type="Object">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_enabled">
+ <argument index="0" name="enabled" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -15333,169 +18363,169 @@
<description>
</description>
<methods>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="bool">
</argument>
<description>
</description>
</method>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="int">
</argument>
<description>
</description>
</method>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="float">
</argument>
<description>
</description>
</method>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="String">
</argument>
<description>
</description>
</method>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="Rect2">
</argument>
<description>
</description>
</method>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="Vector3">
</argument>
<description>
</description>
</method>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="Matrix32">
</argument>
<description>
</description>
</method>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="Plane">
</argument>
<description>
</description>
</method>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="Quat">
</argument>
<description>
</description>
</method>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="AABB">
</argument>
<description>
</description>
</method>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="Matrix3">
</argument>
<description>
</description>
</method>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="Transform">
</argument>
<description>
</description>
</method>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="Color">
</argument>
<description>
</description>
</method>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="Image">
</argument>
<description>
</description>
</method>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="NodePath">
</argument>
<description>
</description>
</method>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="RID">
</argument>
<description>
</description>
</method>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="Object">
</argument>
<description>
</description>
</method>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="InputEvent">
</argument>
<description>
</description>
</method>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="Dictionary">
</argument>
<description>
</description>
</method>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="Array">
</argument>
<description>
</description>
</method>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="RawArray">
</argument>
<description>
</description>
</method>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="IntArray">
</argument>
<description>
</description>
</method>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="RealArray">
</argument>
<description>
</description>
</method>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="StringArray">
</argument>
<description>
</description>
</method>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="Vector2Array">
</argument>
<description>
</description>
</method>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="Vector3Array">
</argument>
<description>
</description>
</method>
- <method name="Nil" >
+ <method name="Nil">
<argument index="0" name="from" type="ColorArray">
</argument>
<description>
@@ -15511,121 +18541,118 @@
</brief_description>
<description>
Nodes can be set as children of other nodes, resulting in a tree arrangement. Any tree of nodes is called a "Scene".
- Scenes can be saved to disk, and then instanced into other scenes. This allows for very high flexibility in the architecture and data model of the projects.
- [SceneMainLoop] contains the "active" tree of nodes, and a node becomes active (receinving NOTIFICATION_ENTER_SCENE) when added to that tree.
- A node can contain any number of nodes as a children (but there is only one tree root) with the requirement that no two childrens with the same name can exist.
- Nodes can, optionally, be added to groups. This makes it easy to reach a number of nodes from the code (for example an "enemies" group).
- Nodes can be set to "process" state, so they constantly receive a callback requesting them to process (do anything). Normal processing ([method _process]) happens as fast as possible and is dependent on the frame rate, so the processing time delta is variable. Fixed processing ([method _fixed_process]) happens a fixed amount of times per second (by default 60) and is useful to link itself to the physics.
- Nodes can also process input events. When set, the [method _input] function will be called with every input that the program receives. Since this is usually too overkill (unless used for simple projects), an [method _unhandled_input] function is called when the input was not handled by anyone else (usually, GUI [Control] nodes).
- To keep track of the scene hieararchy (specially when instancing scenes into scenes) an "owner" can be set to a node. This keeps track of who instanced what. This is mostly useful when writing editors and tools, though.
- Finally, when a node is freed, it will free all its children nodes too.
+ Scenes can be saved to disk, and then instanced into other scenes. This allows for very high flexibility in the architecture and data model of the projects.
+ [SceneMainLoop] contains the "active" tree of nodes, and a node becomes active (receinving NOTIFICATION_ENTER_SCENE) when added to that tree.
+ A node can contain any number of nodes as a children (but there is only one tree root) with the requirement that no two childrens with the same name can exist.
+ Nodes can, optionally, be added to groups. This makes it easy to reach a number of nodes from the code (for example an "enemies" group).
+ Nodes can be set to "process" state, so they constantly receive a callback requesting them to process (do anything). Normal processing ([method _process]) happens as fast as possible and is dependent on the frame rate, so the processing time delta is variable. Fixed processing ([method _fixed_process]) happens a fixed amount of times per second (by default 60) and is useful to link itself to the physics.
+ Nodes can also process input events. When set, the [method _input] function will be called with every input that the program receives. Since this is usually too overkill (unless used for simple projects), an [method _unhandled_input] function is called when the input was not handled by anyone else (usually, GUI [Control] nodes).
+ To keep track of the scene hieararchy (specially when instancing scenes into scenes) an "owner" can be set to a node. This keeps track of who instanced what. This is mostly useful when writing editors and tools, though.
+ Finally, when a node is freed, it will free all its children nodes too.
</description>
<methods>
- <method name="_enter_tree" qualifiers="virtual" >
+ <method name="_enter_tree" qualifiers="virtual">
<description>
</description>
</method>
- <method name="_exit_tree" qualifiers="virtual" >
+ <method name="_exit_tree" qualifiers="virtual">
<description>
</description>
</method>
- <method name="_fixed_process" qualifiers="virtual" >
+ <method name="_fixed_process" qualifiers="virtual">
<argument index="0" name="delta" type="float">
</argument>
<description>
Called for fixed processing (synced to the physics).
</description>
</method>
- <method name="_input" qualifiers="virtual" >
+ <method name="_input" qualifiers="virtual">
<argument index="0" name="event" type="InputEvent">
</argument>
<description>
Called when any input happens (also must enable with [method set_process_input] or the property).
</description>
</method>
- <method name="_process" qualifiers="virtual" >
+ <method name="_process" qualifiers="virtual">
<argument index="0" name="delta" type="float">
</argument>
<description>
Called for processing. This is called every frame, with the delta time from the previous frame.
</description>
</method>
- <method name="_ready" qualifiers="virtual" >
+ <method name="_ready" qualifiers="virtual">
<description>
Called when ready (entered scene and children entered too).
</description>
</method>
- <method name="_unhandled_input" qualifiers="virtual" >
+ <method name="_unhandled_input" qualifiers="virtual">
<argument index="0" name="event" type="InputEvent">
</argument>
<description>
Called when any input happens that was not handled by something else (also must enable with [method set_process_unhandled_input] or the property).
</description>
</method>
- <method name="_unhandled_key_input" qualifiers="virtual" >
+ <method name="_unhandled_key_input" qualifiers="virtual">
<argument index="0" name="key_event" type="InputEvent">
</argument>
<description>
Called when any key input happens that was not handled by something else.
</description>
</method>
- <method name="set_name" >
+ <method name="set_name">
<argument index="0" name="name" type="String">
</argument>
<description>
Set the name of the [Node]. Name must be unique within parent, and setting an already existing name will cause for the node to be automatically renamed.
</description>
</method>
- <method name="get_name" qualifiers="const" >
+ <method name="get_name" qualifiers="const">
<return type="String">
</return>
<description>
Return the name of the [Node]. Name is be unique within parent.
</description>
</method>
- <method name="add_child" >
+ <method name="add_child">
<argument index="0" name="node" type="Node">
</argument>
+ <argument index="1" name="legible_unique_name" type="bool" default="false">
+ </argument>
<description>
Add a child [Node]. Nodes can have as many children as they want, but every child must have a unique name. Children nodes are automatically deleted when the parent node is deleted, so deleting a whole scene is performed by deleting its topmost node.
+ The optional boolean argument enforces creating child node with human-readable names, based on the name of node being instanced instead of its type only.
</description>
</method>
- <method name="remove_child" >
+ <method name="remove_child">
<argument index="0" name="node" type="Node">
</argument>
<description>
Remove a child [Node]. Node is NOT deleted and will have to be deleted manually.
</description>
</method>
- <method name="remove_and_delete_child" >
- <argument index="0" name="node" type="Node">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_child_count" qualifiers="const" >
+ <method name="get_child_count" qualifiers="const">
<return type="int">
</return>
<description>
Return the amount of children nodes.
</description>
</method>
- <method name="get_children" qualifiers="const" >
+ <method name="get_children" qualifiers="const">
<return type="Array">
</return>
<description>
</description>
</method>
- <method name="get_child" qualifiers="const" >
+ <method name="get_child" qualifiers="const">
<return type="Node">
</return>
<argument index="0" name="idx" type="int">
</argument>
<description>
- Return a children node by it"apos;s index (see [method get_child_count]). This method is often used for iterating all children of a node.
+ Return a children node by it's index (see [method get_child_count]). This method is often used for iterating all children of a node.
</description>
</method>
- <method name="has_node" qualifiers="const" >
+ <method name="has_node" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="path" type="NodePath">
@@ -15633,37 +18660,50 @@
<description>
</description>
</method>
- <method name="get_node" qualifiers="const" >
+ <method name="get_node" qualifiers="const">
<return type="Node">
</return>
<argument index="0" name="path" type="NodePath">
</argument>
<description>
- Fetch a node. NodePath must be valid (or else error will occur) and can be either the path to child node, a relative path (from the current node to another node), or an absolute path to a node.[br] Note: fetching absolute paths only works when the node is inside the scene tree (see [method is_inside_scene]). Examples. Assume your current node is Character and following tree:[br]
- root/[br]
- root/Character[br]
- root/Character/Sword[br]
- root/Character/Backpack/Dagger[br]
- root/MyGame[br]
- root/Swamp/Alligator[br]
- root/Swamp/Mosquito[br]
- root/Swamp/Goblin[br]
-[br]
- Possible paths are:[br]
- - get_node("Sword")[br]
- - get_node("Backpack/Dagger")[br]
- - get_node("../Swamp/Alligator")[br]
- - get_node("/root/MyGame")[br]
- </description>
- </method>
- <method name="get_parent" qualifiers="const" >
+ Fetch a node. NodePath must be valid (or else error will occur) and can be either the path to child node, a relative path (from the current node to another node), or an absolute path to a node.
+ Note: fetching absolute paths only works when the node is inside the scene tree (see [method is_inside_scene]). Examples. Assume your current node is Character and following tree:[br]
+ root/
+ root/Character
+ root/Character/Sword
+ root/Character/Backpack/Dagger
+ root/MyGame
+ root/Swamp/Alligator
+ root/Swamp/Mosquito
+ root/Swamp/Goblin
+
+ Possible paths are:
+ - get_node("Sword")
+ - get_node("Backpack/Dagger")
+ - get_node("../Swamp/Alligator")
+ - get_node("/root/MyGame")
+ </description>
+ </method>
+ <method name="get_parent" qualifiers="const">
<return type="Parent">
</return>
<description>
Return the parent [Node] of the current [Node], or an empty Object if the node lacks a parent.
</description>
</method>
- <method name="has_node_and_resource" qualifiers="const" >
+ <method name="find_node" qualifiers="const">
+ <return type="Node">
+ </return>
+ <argument index="0" name="mask" type="String">
+ </argument>
+ <argument index="1" name="recursive" type="bool" default="true">
+ </argument>
+ <argument index="2" name="owned" type="bool" default="true">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="has_node_and_resource" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="path" type="NodePath">
@@ -15671,7 +18711,7 @@
<description>
</description>
</method>
- <method name="get_node_and_resource" >
+ <method name="get_node_and_resource">
<return type="Array">
</return>
<argument index="0" name="path" type="NodePath">
@@ -15679,13 +18719,13 @@
<description>
</description>
</method>
- <method name="is_inside_tree" qualifiers="const" >
+ <method name="is_inside_tree" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="is_a_parent_of" qualifiers="const" >
+ <method name="is_a_parent_of" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="node" type="Node">
@@ -15694,7 +18734,7 @@
Return [i]true[/i] if the "node" argument is a direct or indirect child of the current node, otherwise return [i]false[/i].
</description>
</method>
- <method name="is_greater_than" qualifiers="const" >
+ <method name="is_greater_than" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="node" type="Node">
@@ -15703,14 +18743,14 @@
Return [i]true[/i] if "node" occurs later in the scene hierarchy than the current node, otherwise return [i]false[/i].
</description>
</method>
- <method name="get_path" qualifiers="const" >
+ <method name="get_path" qualifiers="const">
<return type="NodePath">
</return>
<description>
Return the absolute path of the current node. This only works if the curent node is inside the scene tree (see [method is_inside_scene]).
</description>
</method>
- <method name="get_path_to" qualifiers="const" >
+ <method name="get_path_to" qualifiers="const">
<return type="NodePath">
</return>
<argument index="0" name="node" type="Node">
@@ -15719,23 +18759,23 @@
Return the relative path from the current node to the specified node in "node" argument. Both nodes must be in the same scene, or else the function will fail.
</description>
</method>
- <method name="add_to_group" >
+ <method name="add_to_group">
<argument index="0" name="group" type="String">
</argument>
- <argument index="1" name="arg1" type="bool" default="false">
+ <argument index="1" name="persistent" type="bool" default="false">
</argument>
<description>
- Add a node to a group. Groups are helpers to name and organize group of nodes, like for example: "Enemies" "Collectables", etc. A [Node] can be in any number of groups. Nodes can be assigned a group at any time, but will not be added to it until they are inside the scene tree (see [method is_inside_scene]).
+ Add a node to a group. Groups are helpers to name and organize group of nodes, like for example: "Enemies", "Collectables", etc. A [Node] can be in any number of groups. Nodes can be assigned a group at any time, but will not be added to it until they are inside the scene tree (see [method is_inside_scene]).
</description>
</method>
- <method name="remove_from_group" >
+ <method name="remove_from_group">
<argument index="0" name="group" type="String">
</argument>
<description>
Remove a node from a group.
</description>
</method>
- <method name="is_in_group" qualifiers="const" >
+ <method name="is_in_group" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="group" type="String">
@@ -15743,7 +18783,7 @@
<description>
</description>
</method>
- <method name="move_child" >
+ <method name="move_child">
<argument index="0" name="child_node" type="Node">
</argument>
<argument index="1" name="to_pos" type="int">
@@ -15752,194 +18792,195 @@
Move a child node to a different position (order) amongst the other children. Since calls, signals, etc are performed by tree order, changing the order of chilren nodes may be useful.
</description>
</method>
- <method name="get_groups" qualifiers="const" >
+ <method name="get_groups" qualifiers="const">
<return type="Array">
</return>
<description>
</description>
</method>
- <method name="raise" >
+ <method name="raise">
<description>
Move this node to the top of the array of nodes of the parent node. This is often useful on GUIs ([Control]), because their order of drawing fully depends on their order in the tree.
</description>
</method>
- <method name="set_owner" >
+ <method name="set_owner">
<argument index="0" name="owner" type="Node">
</argument>
<description>
Set the node owner. A node can have any other node as owner (as long as a valid parent, grandparent, etc ascending in the tree). When saving a node (using SceneSaver) all the nodes it owns will be saved with it. This allows to create complex SceneTrees, with instancing and subinstancing.
</description>
</method>
- <method name="get_owner" qualifiers="const" >
+ <method name="get_owner" qualifiers="const">
<return type="Node">
</return>
<description>
Get the node owner (see [method set_node_owner]).
</description>
</method>
- <method name="remove_and_skip" >
+ <method name="remove_and_skip">
<description>
Remove a node and set all its children as childrens of the parent node (if exists). All even subscriptions that pass by the removed node will be unsubscribed.
</description>
</method>
- <method name="get_index" qualifiers="const" >
+ <method name="get_index" qualifiers="const">
<return type="int">
</return>
<description>
Get the node index in the parent (assuming it has a parent).
</description>
</method>
- <method name="print_tree" >
+ <method name="print_tree">
<description>
Print the screne to stdout. Used mainly for debugging purposes.
</description>
</method>
- <method name="set_filename" >
+ <method name="set_filename">
<argument index="0" name="filename" type="String">
</argument>
<description>
A node can contain a filename. This filename should not be changed by the user, unless writing editors and tools. When a scene is instanced from a file, it topmost node contains the filename from where it was loaded.
</description>
</method>
- <method name="get_filename" qualifiers="const" >
+ <method name="get_filename" qualifiers="const">
<return type="String">
</return>
<description>
Return a filename that may be containedA node can contained by the node. When a scene is instanced from a file, it topmost node contains the filename from where it was loaded (see [method set_filename]).
</description>
</method>
- <method name="propagate_notification" >
+ <method name="propagate_notification">
<argument index="0" name="what" type="int">
</argument>
<description>
Notify the current node and all its chldren recursively by calling notification() in all of them.
</description>
</method>
- <method name="set_fixed_process" >
+ <method name="set_fixed_process">
<argument index="0" name="enable" type="bool">
</argument>
<description>
Enables or disables node fixed framerate processing. When a node is being processed, it will receive a NOTIFICATION_PROCESS at a fixed (usually 60fps, check [OS] to change that) interval (and the [method _fixed_process] callback will be called if exists). It is common to check how much time was elapsed since the previous frame by calling [method get_fixed_process_time].
</description>
</method>
- <method name="get_fixed_process_delta_time" qualifiers="const" >
+ <method name="get_fixed_process_delta_time" qualifiers="const">
<return type="float">
</return>
<description>
Return the time elapsed since the last fixed frame. This is always the same in fixed proecssing unless the frames per second is changed in [OS].
</description>
</method>
- <method name="is_fixed_processing" qualifiers="const" >
+ <method name="is_fixed_processing" qualifiers="const">
<return type="bool">
</return>
<description>
Return true if fixed processing is enabled (see [method set_fixed_process]).
</description>
</method>
- <method name="set_process" >
+ <method name="set_process">
<argument index="0" name="enable" type="bool">
</argument>
<description>
Enables or disables node processing. When a node is being processed, it will receive a NOTIFICATION_PROCESS on every drawn frame (and the [method _process] callback will be called if exists). It is common to check how much time was elapsed since the previous frame by calling [method get_process_time].
</description>
</method>
- <method name="get_process_delta_time" qualifiers="const" >
+ <method name="get_process_delta_time" qualifiers="const">
<return type="float">
</return>
<description>
Return the time elapsed (in seconds) since the last process callback. This is almost always different each time.
</description>
</method>
- <method name="is_processing" qualifiers="const" >
+ <method name="is_processing" qualifiers="const">
<return type="bool">
</return>
<description>
- Return wether processing is enabled in the current node (see [method set_process]).
+ Return whether processing is enabled in the current node (see [method set_process]).
</description>
</method>
- <method name="set_process_input" >
+ <method name="set_process_input">
<argument index="0" name="enable" type="bool">
</argument>
<description>
Enable input processing for node. This is not requiered for GUI controls! It hooks up the node to receive all input (see [method _input]).
</description>
</method>
- <method name="is_processing_input" qualifiers="const" >
+ <method name="is_processing_input" qualifiers="const">
<return type="bool">
</return>
<description>
Return true if the node is processing input (see [method set_process_input]).
</description>
</method>
- <method name="set_process_unhandled_input" >
+ <method name="set_process_unhandled_input">
<argument index="0" name="enable" type="bool">
</argument>
<description>
Enable unhandled input processing for node. This is not requiered for GUI controls! It hooks up the node to receive all input that was not previously handled before (usually by a [Control]). (see [method _unhandled_input]).
</description>
</method>
- <method name="is_processing_unhandled_input" qualifiers="const" >
+ <method name="is_processing_unhandled_input" qualifiers="const">
<return type="bool">
</return>
<description>
Return true if the node is processing unhandled input (see [method set_process_unhandled_input]).
</description>
</method>
- <method name="set_process_unhandled_key_input" >
+ <method name="set_process_unhandled_key_input">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_processing_unhandled_key_input" qualifiers="const" >
+ <method name="is_processing_unhandled_key_input" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_pause_mode" >
+ <method name="set_pause_mode">
<argument index="0" name="mode" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_pause_mode" qualifiers="const" >
+ <method name="get_pause_mode" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="can_process" qualifiers="const" >
+ <method name="can_process" qualifiers="const">
<return type="bool">
</return>
<description>
Return true if the node can process.
</description>
</method>
- <method name="print_stray_nodes" >
+ <method name="print_stray_nodes">
<description>
</description>
</method>
- <method name="get_position_in_parent" qualifiers="const" >
+ <method name="get_position_in_parent" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_tree" qualifiers="const" >
+ <method name="get_tree" qualifiers="const">
<return type="SceneTree">
</return>
<description>
</description>
</method>
- <method name="duplicate" qualifiers="const" >
+ <method name="duplicate" qualifiers="const">
<return type="Node">
</return>
+ <argument index="0" name="use_instancing" type="bool" default="false">
+ </argument>
<description>
- Return a duplicate of the scene, with all nodes and parameters copied. Subscriptions will not be duplicated.
</description>
</method>
- <method name="replace_by" >
+ <method name="replace_by">
<argument index="0" name="node" type="Node">
</argument>
<argument index="1" name="keep_data" type="bool" default="false">
@@ -15948,13 +18989,25 @@
Replace a node in a scene by a given one. Subscriptions that pass through this node will be lost.
</description>
</method>
- <method name="get_viewport" qualifiers="const" >
+ <method name="set_scene_instance_load_placeholder">
+ <argument index="0" name="load_placeholder" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_scene_instance_load_placeholder" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_viewport" qualifiers="const">
<return type="Object">
</return>
<description>
</description>
</method>
- <method name="queue_free" >
+ <method name="queue_free">
<description>
</description>
</method>
@@ -15998,6 +19051,8 @@
</constant>
<constant name="NOTIFICATION_UNPAUSED" value="15">
</constant>
+ <constant name="NOTIFICATION_INSTANCED" value="20">
+ </constant>
<constant name="PAUSE_MODE_INHERIT" value="0">
</constant>
<constant name="PAUSE_MODE_STOP" value="1">
@@ -16011,60 +19066,58 @@
Base node for 2D system.
</brief_description>
<description>
- Base node for 2D system. Node2D contains a position, rotation and scale, which is used to position and animate.
- It can alternatively be used with a custom 2D transform ([Matrix32]).
- A tree of Node2Ds allows complex hierachies for animation and positioning.
+ Base node for 2D system. Node2D contains a position, rotation and scale, which is used to position and animate. It can alternatively be used with a custom 2D transform ([Matrix32]). A tree of Node2Ds allows complex hierachies for animation and positioning.
</description>
<methods>
- <method name="set_pos" >
+ <method name="set_pos">
<argument index="0" name="pos" type="Vector2">
</argument>
<description>
Set the position of the 2d node.
</description>
</method>
- <method name="set_rot" >
+ <method name="set_rot">
<argument index="0" name="rot" type="float">
</argument>
<description>
Set the rotation of the 2d node.
</description>
</method>
- <method name="set_scale" >
+ <method name="set_scale">
<argument index="0" name="scale" type="Vector2">
</argument>
<description>
Set the scale of the 2d node.
</description>
</method>
- <method name="get_pos" qualifiers="const" >
+ <method name="get_pos" qualifiers="const">
<return type="Vector2">
</return>
<description>
Return the position of the 2D node.
</description>
</method>
- <method name="get_rot" qualifiers="const" >
+ <method name="get_rot" qualifiers="const">
<return type="float">
</return>
<description>
Return the rotation of the 2D node.
</description>
</method>
- <method name="get_scale" qualifiers="const" >
+ <method name="get_scale" qualifiers="const">
<return type="Vector2">
</return>
<description>
Return the scale of the 2D node.
</description>
</method>
- <method name="rotate" >
- <argument index="0" name="degrees" type="float">
+ <method name="rotate">
+ <argument index="0" name="radians" type="float">
</argument>
<description>
</description>
</method>
- <method name="move_local_x" >
+ <method name="move_local_x">
<argument index="0" name="delta" type="float">
</argument>
<argument index="1" name="scaled" type="bool" default="false">
@@ -16072,7 +19125,7 @@
<description>
</description>
</method>
- <method name="move_local_y" >
+ <method name="move_local_y">
<argument index="0" name="delta" type="float">
</argument>
<argument index="1" name="scaled" type="bool" default="false">
@@ -16080,33 +19133,97 @@
<description>
</description>
</method>
- <method name="get_global_pos" qualifiers="const" >
+ <method name="translate">
+ <argument index="0" name="offset" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="global_translate">
+ <argument index="0" name="offset" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="scale">
+ <argument index="0" name="ratio" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_global_pos">
+ <argument index="0" name="pos" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_global_pos" qualifiers="const">
<return type="Vector2">
</return>
<description>
Return the global position of the 2D node.
</description>
</method>
- <method name="set_global_pos" >
- <argument index="0" name="arg0" type="Vector2">
+ <method name="set_transform">
+ <argument index="0" name="xform" type="Matrix32">
</argument>
<description>
</description>
</method>
- <method name="set_transform" >
+ <method name="set_global_transform">
<argument index="0" name="xform" type="Matrix32">
</argument>
<description>
</description>
</method>
- <method name="set_global_transform" >
- <argument index="0" name="xform" type="Matrix32">
+ <method name="look_at">
+ <argument index="0" name="point" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="edit_set_pivot" >
- <argument index="0" name="arg0" type="Vector2">
+ <method name="get_angle_to" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="point" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_z">
+ <argument index="0" name="z" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_z" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_z_as_relative">
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_z_relative" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="edit_set_pivot">
+ <argument index="0" name="pivot" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_relative_transform_to_parent" qualifiers="const">
+ <return type="Matrix32">
+ </return>
+ <argument index="0" name="parent" type="Object">
</argument>
<description>
</description>
@@ -16120,11 +19237,10 @@
Built-in type optimized for path traversing.
</brief_description>
<description>
- Built-in type optimized for path traversing. A Node path is an optimized compiled path used for traversing the scene tree.
- It references nodes and can reference properties in that node, or even reference properties inside the resources of the node.
+ Built-in type optimized for path traversing. A Node path is an optimized compiled path used for traversing the scene tree. It references nodes and can reference properties in that node, or even reference properties inside the resources of the node.
</description>
<methods>
- <method name="get_name" >
+ <method name="get_name">
<return type="String">
</return>
<argument index="0" name="idx" type="int">
@@ -16133,21 +19249,21 @@
Return a path level name.
</description>
</method>
- <method name="get_name_count" >
+ <method name="get_name_count">
<return type="int">
</return>
<description>
Return the path level count.
</description>
</method>
- <method name="get_property" >
+ <method name="get_property">
<return type="String">
</return>
<description>
Return the property associated (empty if none).
</description>
</method>
- <method name="get_subname" >
+ <method name="get_subname">
<return type="String">
</return>
<argument index="0" name="idx" type="int">
@@ -16156,28 +19272,30 @@
Return the subname level name.
</description>
</method>
- <method name="get_subname_count" >
+ <method name="get_subname_count">
<return type="int">
</return>
<description>
Return the subname count.
</description>
</method>
- <method name="is_absolute" >
+ <method name="is_absolute">
<return type="bool">
</return>
<description>
Return true if the node path is absolute (not relative).
</description>
</method>
- <method name="is_empty" >
+ <method name="is_empty">
<return type="bool">
</return>
<description>
Return true if the node path is empty.
</description>
</method>
- <method name="NodePath" >
+ <method name="NodePath">
+ <return type="NodePath">
+ </return>
<argument index="0" name="from" type="String">
</argument>
<description>
@@ -16193,32 +19311,32 @@
</brief_description>
<description>
Operating System functions. OS Wraps the most common functionality to communicate with the host Operating System, such as:
- -Mouse Grabbing
- -Mouse Cursors
- -Clipboard
- -Video Mode
- -Date " Time
- -Timers
- -Environment Variables
- -Execution of Binaries
- -Command Line
- </description>
- <methods>
- <method name="set_clipboard" >
+ -Mouse Grabbing
+ -Mouse Cursors
+ -Clipboard
+ -Video Mode
+ -Date " Time
+ -Timers
+ -Environment Variables
+ -Execution of Binaries
+ -Command Line
+ </description>
+ <methods>
+ <method name="set_clipboard">
<argument index="0" name="clipboard" type="String">
</argument>
<description>
Set clipboard to the OS.
</description>
</method>
- <method name="get_clipboard" qualifiers="const" >
+ <method name="get_clipboard" qualifiers="const">
<return type="String">
</return>
<description>
Get clipboard from the host OS.
</description>
</method>
- <method name="set_video_mode" >
+ <method name="set_video_mode">
<argument index="0" name="size" type="Vector2">
</argument>
<argument index="1" name="fullscreen" type="bool">
@@ -16231,7 +19349,7 @@
Change the video mode.
</description>
</method>
- <method name="get_video_mode_size" qualifiers="const" >
+ <method name="get_video_mode_size" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="screen" type="int" default="0">
@@ -16240,7 +19358,7 @@
Return the current video mode size.
</description>
</method>
- <method name="is_video_mode_fullscreen" qualifiers="const" >
+ <method name="is_video_mode_fullscreen" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="screen" type="int" default="0">
@@ -16249,7 +19367,7 @@
Return true if the current video mode is fullscreen.
</description>
</method>
- <method name="is_video_mode_resizable" qualifiers="const" >
+ <method name="is_video_mode_resizable" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="screen" type="int" default="0">
@@ -16258,7 +19376,7 @@
Return true if the window is resizable.
</description>
</method>
- <method name="get_fullscreen_mode_list" qualifiers="const" >
+ <method name="get_fullscreen_mode_list" qualifiers="const">
<return type="Array">
</return>
<argument index="0" name="screen" type="int" default="0">
@@ -16267,79 +19385,215 @@
Return the list of fullscreen modes.
</description>
</method>
- <method name="set_iterations_per_second" >
+ <method name="get_screen_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_current_screen" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_current_screen">
+ <argument index="0" name="screen" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_screen_position" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="screen" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_screen_size" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="screen" type="int" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_window_position" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_window_position">
+ <argument index="0" name="position" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_window_size" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_window_size">
+ <argument index="0" name="size" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_window_fullscreen">
+ <argument index="0" name="enabled" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_window_fullscreen" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_window_resizable">
+ <argument index="0" name="enabled" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_window_resizable" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_window_minimized">
+ <argument index="0" name="enabled" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_window_minimized" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_window_maximized">
+ <argument index="0" name="enabled" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_window_maximized" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_screen_orientation">
+ <argument index="0" name="orientation" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_screen_orientation" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_keep_screen_on">
+ <argument index="0" name="enabled" type="bool">
+ </argument>
+ <description>
+ Set keep screen on if true, or goes to sleep by device setting if false. (for Android/iOS)
+ </description>
+ </method>
+ <method name="is_keep_screen_on" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_iterations_per_second">
<argument index="0" name="iterations_per_second" type="int">
</argument>
<description>
Set the amount of fixed iterations per second (for fixed process and physics).
</description>
</method>
- <method name="get_iterations_per_second" qualifiers="const" >
+ <method name="get_iterations_per_second" qualifiers="const">
<return type="int">
</return>
<description>
Return the amount of fixed iterations per second (for fixed process and physics).
</description>
</method>
- <method name="set_target_fps" >
+ <method name="set_target_fps">
<argument index="0" name="target_fps" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_target_fps" qualifiers="const" >
+ <method name="get_target_fps" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_time_scale" >
+ <method name="set_time_scale">
<argument index="0" name="time_scale" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_time_scale" >
+ <method name="get_time_scale">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="has_touchscreen_ui_hint" qualifiers="const" >
+ <method name="has_touchscreen_ui_hint" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_low_processor_usage_mode" >
+ <method name="set_window_title">
+ <argument index="0" name="title" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_low_processor_usage_mode">
<argument index="0" name="enable" type="bool">
</argument>
<description>
- Set to true to enable the low cpu usage mode. In this mode, the screen only redraws when there are changes, and a considerable sleep time is inserted between frames.
- This way, editors using the engine UI only use very little cpu.
+ Set to true to enable the low cpu usage mode. In this mode, the screen only redraws when there are changes, and a considerable sleep time is inserted between frames. This way, editors using the engine UI only use very little cpu.
</description>
</method>
- <method name="is_in_low_processor_usage_mode" qualifiers="const" >
+ <method name="is_in_low_processor_usage_mode" qualifiers="const">
<return type="bool">
</return>
<description>
Return true if low cpu usage mode is enabled.
</description>
</method>
- <method name="get_processor_count" qualifiers="const" >
+ <method name="get_processor_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_executable_path" qualifiers="const" >
+ <method name="get_executable_path" qualifiers="const">
<return type="String">
</return>
<description>
- Return the path tot he current engine executable.
+ Return the path to the current engine executable.
</description>
</method>
- <method name="execute" >
+ <method name="execute">
<return type="int">
</return>
<argument index="0" name="path" type="String">
@@ -16354,7 +19608,7 @@
Execute the binary file in given path, optionally blocking until it returns. A process ID is returned.
</description>
</method>
- <method name="kill" >
+ <method name="kill">
<return type="int">
</return>
<argument index="0" name="pid" type="int">
@@ -16363,7 +19617,7 @@
Kill a process ID.
</description>
</method>
- <method name="shell_open" >
+ <method name="shell_open">
<return type="int">
</return>
<argument index="0" name="uri" type="String">
@@ -16371,13 +19625,13 @@
<description>
</description>
</method>
- <method name="get_process_ID" qualifiers="const" >
+ <method name="get_process_ID" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_environment" qualifiers="const" >
+ <method name="get_environment" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="environment" type="String">
@@ -16386,7 +19640,7 @@
Return an environment variable.
</description>
</method>
- <method name="has_environment" qualifiers="const" >
+ <method name="has_environment" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="environment" type="String">
@@ -16395,231 +19649,298 @@
Return true if an envieronment variable exists.
</description>
</method>
- <method name="get_name" qualifiers="const" >
+ <method name="get_name" qualifiers="const">
<return type="String">
</return>
<description>
Return the name of the host OS.
</description>
</method>
- <method name="get_cmdline_args" >
+ <method name="get_cmdline_args">
<return type="StringArray">
</return>
<description>
Return the commandline passed to the engine.
</description>
</method>
- <method name="get_main_loop" qualifiers="const" >
+ <method name="get_main_loop" qualifiers="const">
<return type="Object">
</return>
<description>
Return the main loop object (see [MainLoop]).
</description>
</method>
- <method name="get_date" qualifiers="const" >
+ <method name="get_date" qualifiers="const">
<return type="Dictionary">
</return>
+ <argument index="0" name="utc" type="bool" default="false">
+ </argument>
<description>
- Return the current date.
</description>
</method>
- <method name="get_time" qualifiers="const" >
+ <method name="get_time" qualifiers="const">
<return type="Dictionary">
</return>
+ <argument index="0" name="utc" type="bool" default="false">
+ </argument>
<description>
- Return the current time.
</description>
</method>
- <method name="get_unix_time" qualifiers="const" >
+ <method name="get_time_zone_info" qualifiers="const">
+ <return type="Dictionary">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_unix_time" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_icon" >
- <argument index="0" name="arg0" type="Image">
+ <method name="get_system_time_msec" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_icon">
+ <argument index="0" name="icon" type="Image">
</argument>
<description>
</description>
</method>
- <method name="delay_usec" qualifiers="const" >
+ <method name="delay_usec" qualifiers="const">
<argument index="0" name="usec" type="int">
</argument>
<description>
- Delay executing of the current thread by given usecs.
+ Delay executing of the current thread by given microseconds.
</description>
</method>
- <method name="delay_msec" qualifiers="const" >
+ <method name="delay_msec" qualifiers="const">
<argument index="0" name="msec" type="int">
</argument>
<description>
+ Delay executing of the current thread by given milliseconds.
</description>
</method>
- <method name="get_ticks_msec" qualifiers="const" >
+ <method name="get_ticks_msec" qualifiers="const">
<return type="int">
</return>
<description>
Return the amount of time passed in milliseconds since the engine started.
</description>
</method>
- <method name="get_locale" qualifiers="const" >
+ <method name="get_splash_tick_msec" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_locale" qualifiers="const">
<return type="String">
</return>
<description>
Return the host OS locale.
</description>
</method>
- <method name="get_model_name" qualifiers="const" >
+ <method name="get_model_name" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="get_custom_level" qualifiers="const" >
+ <method name="get_custom_level" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="can_draw" qualifiers="const" >
+ <method name="can_draw" qualifiers="const">
<return type="bool">
</return>
<description>
Return true if the host OS allows drawing.
</description>
</method>
- <method name="get_frames_drawn" >
+ <method name="get_frames_drawn">
<return type="int">
</return>
<description>
Return the total amount of frames drawn.
</description>
</method>
- <method name="is_stdout_verbose" qualifiers="const" >
+ <method name="is_stdout_verbose" qualifiers="const">
<return type="bool">
</return>
<description>
Return true if the engine was executed with -v (verbose stdout).
</description>
</method>
- <method name="can_use_threads" qualifiers="const" >
+ <method name="can_use_threads" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="is_debug_build" qualifiers="const" >
+ <method name="is_debug_build" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="dump_memory_to_file" >
+ <method name="dump_memory_to_file">
<argument index="0" name="file" type="String">
</argument>
<description>
</description>
</method>
- <method name="dump_resources_to_file" >
+ <method name="dump_resources_to_file">
<argument index="0" name="file" type="String">
</argument>
<description>
</description>
</method>
- <method name="print_resources_in_use" >
+ <method name="print_resources_in_use">
<argument index="0" name="short" type="bool" default="false">
</argument>
<description>
</description>
</method>
- <method name="print_all_resources" >
+ <method name="print_all_resources">
<argument index="0" name="tofile" type="String" default="&quot;&quot;">
</argument>
<description>
</description>
</method>
- <method name="get_static_memory_usage" qualifiers="const" >
+ <method name="get_static_memory_usage" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_static_memory_peak_usage" qualifiers="const" >
+ <method name="get_static_memory_peak_usage" qualifiers="const">
<return type="int">
</return>
<description>
Return the max amount of static memory used (only works in debug).
</description>
</method>
- <method name="get_dynamic_memory_usage" qualifiers="const" >
+ <method name="get_dynamic_memory_usage" qualifiers="const">
<return type="int">
</return>
<description>
Return the total amount of dynamic memory used (only works in debug).
</description>
</method>
- <method name="get_data_dir" qualifiers="const" >
+ <method name="get_data_dir" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_system_dir" qualifiers="const">
<return type="String">
</return>
+ <argument index="0" name="dir" type="int">
+ </argument>
<description>
</description>
</method>
- <method name="get_unique_ID" qualifiers="const" >
+ <method name="get_unique_ID" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="get_frames_per_second" qualifiers="const" >
+ <method name="is_ok_left_and_cancel_right" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_frames_per_second" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="print_all_textures_by_size" >
+ <method name="print_all_textures_by_size">
<description>
</description>
</method>
- <method name="print_resources_by_type" >
- <argument index="0" name="arg0" type="StringArray">
+ <method name="print_resources_by_type">
+ <argument index="0" name="types" type="StringArray">
</argument>
<description>
</description>
</method>
- <method name="native_video_play" >
+ <method name="native_video_play">
<return type="int">
</return>
- <argument index="0" name="arg0" type="String">
+ <argument index="0" name="path" type="String">
</argument>
- <argument index="1" name="arg1" type="float">
+ <argument index="1" name="volume" type="float">
</argument>
- <argument index="2" name="arg2" type="int">
+ <argument index="2" name="audio_track" type="String">
</argument>
- <argument index="3" name="arg3" type="int">
+ <argument index="3" name="subtitle_track" type="String">
</argument>
<description>
</description>
</method>
- <method name="native_video_is_playing" >
+ <method name="native_video_is_playing">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="native_video_stop" >
+ <method name="native_video_stop">
+ <description>
+ </description>
+ </method>
+ <method name="native_video_pause">
+ <description>
+ </description>
+ </method>
+ <method name="get_scancode_string" qualifiers="const">
+ <return type="String">
+ </return>
+ <argument index="0" name="code" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_scancode_unicode" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="code" type="int">
+ </argument>
<description>
</description>
</method>
- <method name="native_video_pause" >
+ <method name="find_scancode_from_string" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="string" type="String">
+ </argument>
<description>
</description>
</method>
- <method name="set_use_file_access_save_and_swap" >
+ <method name="set_use_file_access_save_and_swap">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
+ <method name="alert">
+ <argument index="0" name="text" type="String">
+ </argument>
+ <argument index="1" name="title" type="String" default="&quot;Alert!&quot;">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
<constant name="DAY_SUNDAY" value="0">
@@ -16660,6 +19981,36 @@
</constant>
<constant name="MONTH_DECEMBER" value="11">
</constant>
+ <constant name="SCREEN_ORIENTATION_LANDSCAPE" value="0">
+ </constant>
+ <constant name="SCREEN_ORIENTATION_PORTRAIT" value="1">
+ </constant>
+ <constant name="SCREEN_ORIENTATION_REVERSE_LANDSCAPE" value="2">
+ </constant>
+ <constant name="SCREEN_ORIENTATION_REVERSE_PORTRAIT" value="3">
+ </constant>
+ <constant name="SCREEN_ORIENTATION_SENSOR_LANDSCAPE" value="4">
+ </constant>
+ <constant name="SCREEN_ORIENTATION_SENSOR_PORTRAIT" value="5">
+ </constant>
+ <constant name="SCREEN_ORIENTATION_SENSOR" value="6">
+ </constant>
+ <constant name="SYSTEM_DIR_DESKTOP" value="0">
+ </constant>
+ <constant name="SYSTEM_DIR_DCIM" value="1">
+ </constant>
+ <constant name="SYSTEM_DIR_DOCUMENTS" value="2">
+ </constant>
+ <constant name="SYSTEM_DIR_DOWNLOADS" value="3">
+ </constant>
+ <constant name="SYSTEM_DIR_MOVIES" value="4">
+ </constant>
+ <constant name="SYSTEM_DIR_MUSIC" value="5">
+ </constant>
+ <constant name="SYSTEM_DIR_PICTURES" value="6">
+ </constant>
+ <constant name="SYSTEM_DIR_RINGTONES" value="7">
+ </constant>
</constants>
</class>
<class name="Object" category="Core">
@@ -16668,38 +20019,38 @@
</brief_description>
<description>
Base class for all non built-in types. Everything not a built-in type starts the inheritance chain from this class.
- Objects do not manage memory, if inheriting from one the object will most likely have to be deleted manually (call the [method free] function from the script or delete from C++).
- Some derivates add memory management, such as [Reference] (which keps a reference count and deletes itself automatically when no longer referenced) and [Node], which deletes the children tree when deleted.
- Objects export properties, which are mainly useful for storage and editing, but not really so much in programming. Properties are exported in [method _get_property_list] and handled in [method _get] and [_set]. However, scripting languages and C++ have simper means to export them.
- Objects also receive notifications ([method _notification]). Notifications are a simple way to notify the object about simple events, so they can all be handled together.
+ Objects do not manage memory, if inheriting from one the object will most likely have to be deleted manually (call the [method free] function from the script or delete from C++).
+ Some derivates add memory management, such as [Reference] (which keps a reference count and deletes itself automatically when no longer referenced) and [Node], which deletes the children tree when deleted.
+ Objects export properties, which are mainly useful for storage and editing, but not really so much in programming. Properties are exported in [method _get_property_list] and handled in [method _get] and [_set]. However, scripting languages and C++ have simper means to export them.
+ Objects also receive notifications ([method _notification]). Notifications are a simple way to notify the object about simple events, so they can all be handled together.
</description>
<methods>
- <method name="_get" qualifiers="virtual" >
+ <method name="_get" qualifiers="virtual">
<argument index="0" name="property" type="String">
</argument>
<description>
Return a property, return null if the property does not exist.
</description>
</method>
- <method name="_get_property_list" qualifiers="virtual" >
+ <method name="_get_property_list" qualifiers="virtual">
<return type="Array">
</return>
<description>
Return the property list, array of dictionaries, dictionaries must countain: name:String, type:int (see TYPE_* enum in globals) and optionally: hint:int (see PROPERTY_HINT_* in globals), hint_string:String, usage:int (see PROPERTY_USAGE_* in globals).
</description>
</method>
- <method name="_init" qualifiers="virtual" >
+ <method name="_init" qualifiers="virtual">
<description>
</description>
</method>
- <method name="_notification" qualifiers="virtual" >
+ <method name="_notification" qualifiers="virtual">
<argument index="0" name="what" type="int">
</argument>
<description>
Notification request, the notification id is received.
</description>
</method>
- <method name="_set" qualifiers="virtual" >
+ <method name="_set" qualifiers="virtual">
<argument index="0" name="property" type="String">
</argument>
<argument index="1" name="value" type="var">
@@ -16708,14 +20059,18 @@
Set a property. Return true if the property was found.
</description>
</method>
- <method name="get_type" qualifiers="const" >
+ <method name="free">
+ <description>
+ </description>
+ </method>
+ <method name="get_type" qualifiers="const">
<return type="String">
</return>
<description>
Return the type of the object as a string.
</description>
</method>
- <method name="is_type" qualifiers="const" >
+ <method name="is_type" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="type" type="String">
@@ -16724,7 +20079,7 @@
Check the type of the obeject against a string (including inheritance).
</description>
</method>
- <method name="set" >
+ <method name="set">
<argument index="0" name="property" type="String">
</argument>
<argument index="1" name="value" type="var">
@@ -16733,51 +20088,57 @@
Set property into the object.
</description>
</method>
- <method name="get" qualifiers="const" >
+ <method name="get" qualifiers="const">
<argument index="0" name="property" type="String">
</argument>
<description>
Get a property from the object.
</description>
</method>
- <method name="get_property_list" qualifiers="const" >
+ <method name="get_property_list" qualifiers="const">
<return type="Array">
</return>
<description>
Return the list of properties as an array of dictionaries, dictionaries countain: name:String, type:int (see TYPE_* enum in globals) and optionally: hint:int (see PROPERTY_HINT_* in globals), hint_string:String, usage:int (see PROPERTY_USAGE_* in globals).
</description>
</method>
- <method name="notification" >
+ <method name="get_method_list" qualifiers="const">
+ <return type="Array">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="notification">
<argument index="0" name="what" type="int">
</argument>
- <argument index="1" name="arg1" type="bool" default="false">
+ <argument index="1" name="reversed" type="bool" default="false">
</argument>
<description>
Notify the object of something.
</description>
</method>
- <method name="get_instance_ID" qualifiers="const" >
+ <method name="get_instance_ID" qualifiers="const">
<return type="int">
</return>
<description>
Return the instance ID. All objects have a unique instance ID.
</description>
</method>
- <method name="set_script" >
+ <method name="set_script">
<argument index="0" name="script" type="Script">
</argument>
<description>
Set a script into the object, scripts extend the object functionality.
</description>
</method>
- <method name="get_script" qualifiers="const" >
+ <method name="get_script" qualifiers="const">
<return type="Script">
</return>
<description>
Return the object script (or null if it doesn't have one).
</description>
</method>
- <method name="set_meta" >
+ <method name="set_meta">
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="value" type="var">
@@ -16786,14 +20147,14 @@
Set a metadata into the object. Medatada is serialized. Metadata can be [i]anything[/i].
</description>
</method>
- <method name="get_meta" qualifiers="const" >
+ <method name="get_meta" qualifiers="const">
<argument index="0" name="name" type="String">
</argument>
<description>
Return a metadata from the object.
</description>
</method>
- <method name="has_meta" qualifiers="const" >
+ <method name="has_meta" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="name" type="String">
@@ -16802,14 +20163,14 @@
Return true if a metadata is found with the requested name.
</description>
</method>
- <method name="get_meta_list" qualifiers="const" >
+ <method name="get_meta_list" qualifiers="const">
<return type="StringArray">
</return>
<description>
Return the list of metadatas in the object.
</description>
</method>
- <method name="add_user_signal" >
+ <method name="add_user_signal">
<argument index="0" name="signal" type="String">
</argument>
<argument index="1" name="arguments" type="Array" default="Array()">
@@ -16818,7 +20179,15 @@
Add a user signal (can be added anytime). Arguments are optional, but can be added as an array of dictionaries, each containing "name" and "type" (from [@GlobalScope] TYPE_*).
</description>
</method>
- <method name="emit_signal" >
+ <method name="has_user_signal" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="signal" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="emit_signal">
<argument index="0" name="signal" type="String">
</argument>
<argument index="1" name="arg0" type="var" default="NULL">
@@ -16835,7 +20204,7 @@
Emit a signal. Arguments are passed in an array.
</description>
</method>
- <method name="call" >
+ <method name="call">
<argument index="0" name="method" type="String">
</argument>
<argument index="1" name="arg0" type="var" default="NULL">
@@ -16862,7 +20231,7 @@
Call a function in the object, result is returned.
</description>
</method>
- <method name="call_deferred" >
+ <method name="call_deferred">
<argument index="0" name="method" type="String">
</argument>
<argument index="1" name="arg0" type="var" default="NULL">
@@ -16879,7 +20248,9 @@
Create and store a function in the object. The call will take place on idle time.
</description>
</method>
- <method name="callv" >
+ <method name="callv">
+ <return type="Variant">
+ </return>
<argument index="0" name="method" type="String">
</argument>
<argument index="1" name="arg_array" type="Array">
@@ -16887,22 +20258,30 @@
<description>
</description>
</method>
- <method name="has_method" qualifiers="const" >
+ <method name="has_method" qualifiers="const">
<return type="bool">
</return>
- <argument index="0" name="arg0" type="String">
+ <argument index="0" name="method" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_signal_list" qualifiers="const" >
+ <method name="get_signal_list" qualifiers="const">
<return type="Array">
</return>
<description>
Return the list of signals as an array of dictionaries.
</description>
</method>
- <method name="connect" >
+ <method name="get_signal_connection_list" qualifiers="const">
+ <return type="Array">
+ </return>
+ <argument index="0" name="signal" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="connect">
<return type="int">
</return>
<argument index="0" name="signal" type="String">
@@ -16916,11 +20295,10 @@
<argument index="4" name="flags" type="int" default="0">
</argument>
<description>
- Connect a signal to a method at a target (member function). Binds are optional and are passed as extra arguments to the call. Flags specify optional deferred or one shot connections, see enum CONNECT_*.
- A signal can only be connected once to a method, and it will throw an error if already connected. If you want to avoid this, use [method is_connected] to check.
+ Connect a signal to a method at a target (member function). Binds are optional and are passed as extra arguments to the call. Flags specify optional deferred or one shot connections, see enum CONNECT_*. A signal can only be connected once to a method, and it will throw an error if already connected. If you want to avoid this, use [method is_connected] to check.
</description>
</method>
- <method name="disconnect" >
+ <method name="disconnect">
<argument index="0" name="signal" type="String">
</argument>
<argument index="1" name="target" type="Object">
@@ -16931,7 +20309,7 @@
Disconnect a signal from a method.
</description>
</method>
- <method name="is_connected" qualifiers="const" >
+ <method name="is_connected" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="signal" type="String">
@@ -16944,48 +20322,48 @@
Return true if a connection exists for a given signal and target/method.
</description>
</method>
- <method name="set_block_signals" >
+ <method name="set_block_signals">
<argument index="0" name="enable" type="bool">
</argument>
<description>
If set to true, signal emission is blocked.
</description>
</method>
- <method name="is_blocking_signals" qualifiers="const" >
+ <method name="is_blocking_signals" qualifiers="const">
<return type="bool">
</return>
<description>
Return true if signal emission blocking is enabled.
</description>
</method>
- <method name="set_message_translation" >
+ <method name="set_message_translation">
<argument index="0" name="enable" type="bool">
</argument>
<description>
Set true if this object can translate strings (in calls to tr() ). Default is true.
</description>
</method>
- <method name="can_translate_messages" qualifiers="const" >
+ <method name="can_translate_messages" qualifiers="const">
<return type="bool">
</return>
<description>
Return true if this object can translate strings.
</description>
</method>
- <method name="property_list_changed_notify" >
+ <method name="property_list_changed_notify">
<description>
</description>
</method>
- <method name="XL_MESSAGE" qualifiers="const" >
+ <method name="XL_MESSAGE" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="message" type="String">
</argument>
<description>
- deprecated, will go away.
+ Deprecated, will go away.
</description>
</method>
- <method name="tr" qualifiers="const" >
+ <method name="tr" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="message" type="String">
@@ -16994,6 +20372,12 @@
Translate a message. Only works in message translation is enabled (which is by default). See [method set_message_translation].
</description>
</method>
+ <method name="is_queued_for_deletion" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<signals>
<signal name="script_changed">
@@ -17019,6 +20403,58 @@
</constant>
</constants>
</class>
+<class name="OccluderPolygon2D" inherits="Resource" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="set_closed">
+ <argument index="0" name="closed" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_closed" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_cull_mode">
+ <argument index="0" name="cull_mode" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_cull_mode" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_polygon">
+ <argument index="0" name="polygon" type="Vector2Array">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_polygon" qualifiers="const">
+ <return type="Vector2Array">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ <constant name="CULL_DISABLED" value="0">
+ </constant>
+ <constant name="CULL_CLOCKWISE" value="1">
+ </constant>
+ <constant name="CULL_COUNTER_CLOCKWISE" value="2">
+ </constant>
+ </constants>
+</class>
<class name="OmniLight" inherits="Light" category="Core">
<brief_description>
OmniDirectional Light, such as a lightbulb or a candle.
@@ -17039,7 +20475,7 @@
OptionButton is a type button that provides a selectable list of items when pressed. The item selected becomes the "current" item and is displayed as the button text.
</description>
<methods>
- <method name="add_item" >
+ <method name="add_item">
<argument index="0" name="label" type="String">
</argument>
<argument index="1" name="id" type="int" default="-1">
@@ -17048,7 +20484,7 @@
Add an item, with text "label" and (optionally) id. If no "id" is passed, "id" becomes the item index. New items are appended at the end.
</description>
</method>
- <method name="add_icon_item" >
+ <method name="add_icon_item">
<argument index="0" name="texture" type="Texture">
</argument>
<argument index="1" name="label" type="String">
@@ -17059,7 +20495,7 @@
Add an item, with a "texture" icon, text "label" and (optionally) id. If no "id" is passed, "id" becomes the item index. New items are appended at the end.
</description>
</method>
- <method name="set_item_text" >
+ <method name="set_item_text">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="text" type="String">
@@ -17068,7 +20504,7 @@
Set the text of an item at index "idx".
</description>
</method>
- <method name="set_item_icon" >
+ <method name="set_item_icon">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="texture" type="Texture">
@@ -17077,7 +20513,7 @@
Set the icon of an item at index "idx".
</description>
</method>
- <method name="set_item_disabled" >
+ <method name="set_item_disabled">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="disabled" type="bool">
@@ -17085,7 +20521,7 @@
<description>
</description>
</method>
- <method name="set_item_ID" >
+ <method name="set_item_ID">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="id" type="int">
@@ -17094,7 +20530,7 @@
Set the ID of an item at index "idx".
</description>
</method>
- <method name="set_item_metadata" >
+ <method name="set_item_metadata">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="metadata" type="var">
@@ -17102,7 +20538,7 @@
<description>
</description>
</method>
- <method name="get_item_text" qualifiers="const" >
+ <method name="get_item_text" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="idx" type="int">
@@ -17111,7 +20547,7 @@
Return the text of the item at index "idx".
</description>
</method>
- <method name="get_item_icon" qualifiers="const" >
+ <method name="get_item_icon" qualifiers="const">
<return type="Texture">
</return>
<argument index="0" name="idx" type="int">
@@ -17120,7 +20556,7 @@
Return the icon of the item at index "idx".
</description>
</method>
- <method name="get_item_ID" qualifiers="const" >
+ <method name="get_item_ID" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="idx" type="int">
@@ -17129,13 +20565,13 @@
Return the ID of the item at index "idx".
</description>
</method>
- <method name="get_item_metadata" qualifiers="const" >
+ <method name="get_item_metadata" qualifiers="const">
<argument index="0" name="idx" type="int">
</argument>
<description>
</description>
</method>
- <method name="is_item_disabled" qualifiers="const" >
+ <method name="is_item_disabled" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="idx" type="int">
@@ -17143,48 +20579,48 @@
<description>
</description>
</method>
- <method name="get_item_count" qualifiers="const" >
+ <method name="get_item_count" qualifiers="const">
<return type="int">
</return>
<description>
Return the amount of items in the OptionButton.
</description>
</method>
- <method name="add_separator" >
+ <method name="add_separator">
<description>
Add a separator to the list of items. Separators help to group items. Separator also takes up an index and is appended at the end.
</description>
</method>
- <method name="clear" >
+ <method name="clear">
<description>
Clear all the items in the [OptionButton].
</description>
</method>
- <method name="select" >
- <argument index="0" name="arg0" type="int">
+ <method name="select">
+ <argument index="0" name="idx" type="int">
</argument>
<description>
Select an item by index and make it the current item.
</description>
</method>
- <method name="get_selected" qualifiers="const" >
+ <method name="get_selected" qualifiers="const">
<return type="int">
</return>
<description>
Return the current item index
</description>
</method>
- <method name="get_selected_ID" qualifiers="const" >
+ <method name="get_selected_ID" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_selected_metadata" qualifiers="const" >
+ <method name="get_selected_metadata" qualifiers="const">
<description>
</description>
</method>
- <method name="remove_item" >
+ <method name="remove_item">
<argument index="0" name="idx" type="int">
</argument>
<description>
@@ -17231,13 +20667,13 @@
</theme_item>
</theme_items>
</class>
-<class name="PCKPacker" inherits="Object" category="Core">
+<class name="PCKPacker" inherits="Reference" category="Core">
<brief_description>
</brief_description>
<description>
</description>
<methods>
- <method name="pck_start" >
+ <method name="pck_start">
<return type="int">
</return>
<argument index="0" name="pck_name" type="String">
@@ -17247,7 +20683,7 @@
<description>
</description>
</method>
- <method name="add_file" >
+ <method name="add_file">
<return type="int">
</return>
<argument index="0" name="pck_path" type="String">
@@ -17257,10 +20693,10 @@
<description>
</description>
</method>
- <method name="flush" >
+ <method name="flush">
<return type="int">
</return>
- <argument index="0" name="arg0" type="bool">
+ <argument index="0" name="verbose" type="bool">
</argument>
<description>
</description>
@@ -17277,7 +20713,7 @@
Optimized translation. Uses real-time compressed translations, which results in very small dictionaries.
</description>
<methods>
- <method name="generate" >
+ <method name="generate">
<argument index="0" name="from" type="Translation">
</argument>
<description>
@@ -17293,15 +20729,15 @@
<description>
</description>
<methods>
- <method name="pack" >
- <return type="int">
+ <method name="pack">
+ <return type="Error">
</return>
<argument index="0" name="value" type="var">
</argument>
<description>
</description>
</method>
- <method name="size" qualifiers="const" >
+ <method name="size" qualifiers="const">
<return type="int">
</return>
<description>
@@ -17317,7 +20753,7 @@
<description>
</description>
<methods>
- <method name="size" qualifiers="const" >
+ <method name="size" qualifiers="const">
<return type="int">
</return>
<description>
@@ -17331,28 +20767,27 @@
<brief_description>
</brief_description>
<description>
- explain ownership, and that node does not need to own itself
+ TODO: explain ownership, and that node does not need to own itself
</description>
<methods>
- <method name="pack" >
+ <method name="pack">
<return type="int">
</return>
<argument index="0" name="path" type="Node">
</argument>
<description>
- Pack will ignore any sub-nodes not owned by given
- node. See [Node.set_owner].
+ Pack will ignore any sub-nodes not owned by given node. See [Node.set_owner].
</description>
</method>
- <method name="instance" qualifiers="const" >
+ <method name="instance" qualifiers="const">
<return type="Node">
</return>
- <argument index="0" name="arg0" type="bool" default="false">
+ <argument index="0" name="gen_edit_state" type="bool" default="false">
</argument>
<description>
</description>
</method>
- <method name="can_instance" qualifiers="const" >
+ <method name="can_instance" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -17370,19 +20805,39 @@
PacketPeer is an abstration and base class for packet-based protocols (such as UDP). It provides an API for sending and receiving packets both as raw data or variables. This makes it easy to transfer data over a protocol, without having to encode data as low level bytes or having to worry about network ordering.
</description>
<methods>
- <method name="get_var" qualifiers="const" >
+ <method name="get_var" qualifiers="const">
<description>
</description>
</method>
- <method name="put_var" >
+ <method name="put_var">
<return type="int">
</return>
- <argument index="0" name="var" type="var">
+ <argument index="0" name="var" type="Variant">
</argument>
<description>
</description>
</method>
- <method name="get_available_packet_count" qualifiers="const" >
+ <method name="get_packet" qualifiers="const">
+ <return type="RawArray">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="put_packet">
+ <return type="Error">
+ </return>
+ <argument index="0" name="buffer" type="RawArray">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_packet_error" qualifiers="const">
+ <return type="Error">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_available_packet_count" qualifiers="const">
<return type="int">
</return>
<description>
@@ -17400,7 +20855,7 @@
PacketStreamPeer provides a wrapper for working using packets over a stream. This allows for using packet based code with StreamPeers. PacketPeerStream implements a custom protocol over the StreamPeer, so the user should not read or write to the wrapped StreamPeer directly.
</description>
<methods>
- <method name="set_stream_peer" >
+ <method name="set_stream_peer">
<argument index="0" name="peer" type="StreamPeer">
</argument>
<description>
@@ -17417,8 +20872,8 @@
<description>
</description>
<methods>
- <method name="listen" >
- <return type="int">
+ <method name="listen">
+ <return type="Error">
</return>
<argument index="0" name="port" type="int">
</argument>
@@ -17427,41 +20882,41 @@
<description>
</description>
</method>
- <method name="close" >
+ <method name="close">
<description>
</description>
</method>
- <method name="wait" >
- <return type="int">
+ <method name="wait">
+ <return type="Error">
</return>
<description>
</description>
</method>
- <method name="is_listening" qualifiers="const" >
+ <method name="is_listening" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="get_packet_ip" qualifiers="const" >
+ <method name="get_packet_ip" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="get_packet_address" qualifiers="const" >
+ <method name="get_packet_address" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_packet_port" qualifiers="const" >
+ <method name="get_packet_port" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_send_address" >
+ <method name="set_send_address">
<return type="int">
</return>
<argument index="0" name="host" type="String">
@@ -17480,8 +20935,7 @@
Provides an opaque background for [Control] children.
</brief_description>
<description>
- Panel is a [Control] that displays an opaque background. It's commoly used as a parent and container for other types of [Control]
- nodes."#10;"#9;[center][img]images/panel_example.png[/img][/center]
+ Panel is a [Control] that displays an opaque background. It's commoly used as a parent and container for other types of [Control] nodes. [center][img]images/panel_example.png[/img][/center]
</description>
<methods>
</methods>
@@ -17518,66 +20972,78 @@
<description>
</description>
<methods>
- <method name="set_scroll_offset" >
+ <method name="set_scroll_offset">
<argument index="0" name="ofs" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_scroll_offset" qualifiers="const" >
+ <method name="get_scroll_offset" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="set_scroll_base_offset" >
+ <method name="set_scroll_base_offset">
<argument index="0" name="ofs" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_scroll_base_offset" qualifiers="const" >
+ <method name="get_scroll_base_offset" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="set_scroll_base_scale" >
+ <method name="set_scroll_base_scale">
<argument index="0" name="scale" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_scroll_base_scale" qualifiers="const" >
+ <method name="get_scroll_base_scale" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="set_limit_begin" >
+ <method name="set_limit_begin">
<argument index="0" name="ofs" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_limit_begin" qualifiers="const" >
+ <method name="get_limit_begin" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="set_limit_end" >
+ <method name="set_limit_end">
<argument index="0" name="ofs" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_limit_end" qualifiers="const" >
+ <method name="get_limit_end" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
+ <method name="set_ignore_camera_zoom">
+ <argument index="0" name="ignore" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_ignore_camera_zoom">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
</constants>
@@ -17588,25 +21054,25 @@
<description>
</description>
<methods>
- <method name="set_motion_scale" >
+ <method name="set_motion_scale">
<argument index="0" name="scale" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_motion_scale" qualifiers="const" >
+ <method name="get_motion_scale" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="set_mirroring" >
+ <method name="set_mirroring">
<argument index="0" name="mirror" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_mirroring" qualifiers="const" >
+ <method name="get_mirroring" qualifiers="const">
<return type="Vector2">
</return>
<description>
@@ -17622,73 +21088,73 @@
<description>
</description>
<methods>
- <method name="set_enabled" >
+ <method name="set_enabled">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_enabled" qualifiers="const" >
+ <method name="is_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_radius" >
+ <method name="set_radius">
<argument index="0" name="radius" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_radius" qualifiers="const" >
+ <method name="get_radius" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_disable_radius" >
+ <method name="set_disable_radius">
<argument index="0" name="radius" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_disable_radius" qualifiers="const" >
+ <method name="get_disable_radius" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_gravity" >
+ <method name="set_gravity">
<argument index="0" name="gravity" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_gravity" qualifiers="const" >
+ <method name="get_gravity" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_absorption" >
+ <method name="set_absorption">
<argument index="0" name="absorption" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_absorption" qualifiers="const" >
+ <method name="get_absorption" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_particles_path" >
+ <method name="set_particles_path">
<argument index="0" name="path" type="NodePath">
</argument>
<description>
</description>
</method>
- <method name="get_particles_path" qualifiers="const" >
+ <method name="get_particles_path" qualifiers="const">
<return type="NodePath">
</return>
<description>
@@ -17698,28 +21164,6 @@
<constants>
</constants>
</class>
-<class name="ParticleSystemMaterial" inherits="Material" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_texture" >
- <argument index="0" name="texture" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_texture" qualifiers="const" >
- <return type="Texture">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
<class name="Particles" inherits="GeometryInstance" category="Core">
<brief_description>
Particle system 3D Node
@@ -17728,101 +21172,101 @@
Particles is a particle system 3D [Node] that is used to simulate several types of particle effects, such as explosions, rain, snow, fireflies, or other magical-like shinny sparkles. Particles are drawn using impostors, and given their dynamic behavior, the user must provide a visibility AABB (although helpers to create one automatically exist).
</description>
<methods>
- <method name="set_amount" >
+ <method name="set_amount">
<argument index="0" name="amount" type="int">
</argument>
<description>
Set total amount of particles in the system.
</description>
</method>
- <method name="get_amount" qualifiers="const" >
+ <method name="get_amount" qualifiers="const">
<return type="int">
</return>
<description>
Return the total amount of particles in the system.
</description>
</method>
- <method name="set_emitting" >
+ <method name="set_emitting">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
Set the "emitting" property state. When emitting, the particle system generates new particles at constant rate.
</description>
</method>
- <method name="is_emitting" qualifiers="const" >
+ <method name="is_emitting" qualifiers="const">
<return type="bool">
</return>
<description>
Return the "emitting" property state (see [method set_emitting]).
</description>
</method>
- <method name="set_visibility_aabb" >
+ <method name="set_visibility_aabb">
<argument index="0" name="aabb" type="AABB">
</argument>
<description>
Set the visibility AABB for the particle system, since the default one will not work properly most of the time.
</description>
</method>
- <method name="get_visibility_aabb" qualifiers="const" >
+ <method name="get_visibility_aabb" qualifiers="const">
<return type="AABB">
</return>
<description>
Return the current visibility AABB.
</description>
</method>
- <method name="set_emission_half_extents" >
+ <method name="set_emission_half_extents">
<argument index="0" name="half_extents" type="Vector3">
</argument>
<description>
Set the half extents for the emission box.
</description>
</method>
- <method name="get_emission_half_extents" qualifiers="const" >
+ <method name="get_emission_half_extents" qualifiers="const">
<return type="Vector3">
</return>
<description>
Return the half extents for the emission box.
</description>
</method>
- <method name="set_emission_base_velocity" >
+ <method name="set_emission_base_velocity">
<argument index="0" name="base_velocity" type="Vector3">
</argument>
<description>
</description>
</method>
- <method name="get_emission_base_velocity" qualifiers="const" >
+ <method name="get_emission_base_velocity" qualifiers="const">
<return type="Vector3">
</return>
<description>
</description>
</method>
- <method name="set_emission_points" >
+ <method name="set_emission_points">
<argument index="0" name="points" type="Vector3Array">
</argument>
<description>
</description>
</method>
- <method name="get_emission_points" qualifiers="const" >
+ <method name="get_emission_points" qualifiers="const">
<return type="Vector3Array">
</return>
<description>
</description>
</method>
- <method name="set_gravity_normal" >
+ <method name="set_gravity_normal">
<argument index="0" name="normal" type="Vector3">
</argument>
<description>
Set the normal vector towards where gravity is pulling (by default, negative Y).
</description>
</method>
- <method name="get_gravity_normal" qualifiers="const" >
+ <method name="get_gravity_normal" qualifiers="const">
<return type="Vector3">
</return>
<description>
Return the normal vector towards where gravity is pulling (by default, negative Y).
</description>
</method>
- <method name="set_variable" >
+ <method name="set_variable">
<argument index="0" name="variable" type="int">
</argument>
<argument index="1" name="value" type="float">
@@ -17831,7 +21275,7 @@
Set a specific variable for the particle system (see VAR_* enum).
</description>
</method>
- <method name="get_variable" qualifiers="const" >
+ <method name="get_variable" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="variable" type="int">
@@ -17840,7 +21284,7 @@
Return a specific variable for the particle system (see VAR_* enum).
</description>
</method>
- <method name="set_randomness" >
+ <method name="set_randomness">
<argument index="0" name="variable" type="int">
</argument>
<argument index="1" name="randomness" type="float">
@@ -17849,34 +21293,34 @@
Set the randomness for a specific variable of the particle system. Randomness produces small changes from the default each time a particle is emitted.
</description>
</method>
- <method name="get_randomness" qualifiers="const" >
+ <method name="get_randomness" qualifiers="const">
<return type="float">
</return>
- <argument index="0" name="arg0" type="int">
+ <argument index="0" name="variable" type="int">
</argument>
<description>
Return the randomness for a specific variable of the particle system. Randomness produces small changes from the default each time a particle is emitted.
</description>
</method>
- <method name="set_color_phase_pos" >
+ <method name="set_color_phase_pos">
<argument index="0" name="phase" type="int">
</argument>
<argument index="1" name="pos" type="float">
</argument>
<description>
- Set the position of a color phase (0 to 1)
+ Set the position of a color phase (0 to 1).
</description>
</method>
- <method name="get_color_phase_pos" qualifiers="const" >
+ <method name="get_color_phase_pos" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="phase" type="int">
</argument>
<description>
- Return the position of a color phase (0 to 1)
+ Return the position of a color phase (0 to 1).
</description>
</method>
- <method name="set_color_phase_color" >
+ <method name="set_color_phase_color">
<argument index="0" name="phase" type="int">
</argument>
<argument index="1" name="color" type="Color">
@@ -17885,7 +21329,7 @@
Set the color of a color phase.
</description>
</method>
- <method name="get_color_phase_color" qualifiers="const" >
+ <method name="get_color_phase_color" qualifiers="const">
<return type="Color">
</return>
<argument index="0" name="phase" type="int">
@@ -17894,63 +21338,63 @@
Return the color of a color phase.
</description>
</method>
- <method name="set_material" >
+ <method name="set_material">
<argument index="0" name="material" type="Material">
</argument>
<description>
- Set the material used to draw particles
+ Set the material used to draw particles.
</description>
</method>
- <method name="get_material" qualifiers="const" >
+ <method name="get_material" qualifiers="const">
<return type="Material">
</return>
<description>
- Return the material used to draw particles
+ Return the material used to draw particles.
</description>
</method>
- <method name="set_emit_timeout" >
- <argument index="0" name="arg0" type="float">
+ <method name="set_emit_timeout">
+ <argument index="0" name="timeout" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_emit_timeout" qualifiers="const" >
+ <method name="get_emit_timeout" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_height_from_velocity" >
+ <method name="set_height_from_velocity">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="has_height_from_velocity" qualifiers="const" >
+ <method name="has_height_from_velocity" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_use_local_coordinates" >
+ <method name="set_use_local_coordinates">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_using_local_coordinates" qualifiers="const" >
+ <method name="is_using_local_coordinates" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_color_phases" >
+ <method name="set_color_phases">
<argument index="0" name="count" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_color_phases" qualifiers="const" >
+ <method name="get_color_phases" qualifiers="const">
<return type="int">
</return>
<description>
@@ -17994,79 +21438,79 @@
<description>
</description>
<methods>
- <method name="set_emitting" >
+ <method name="set_emitting">
<argument index="0" name="active" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_emitting" qualifiers="const" >
+ <method name="is_emitting" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_amount" >
+ <method name="set_amount">
<argument index="0" name="amount" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_amount" qualifiers="const" >
+ <method name="get_amount" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_lifetime" >
+ <method name="set_lifetime">
<argument index="0" name="lifetime" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_lifetime" qualifiers="const" >
+ <method name="get_lifetime" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_time_scale" >
+ <method name="set_time_scale">
<argument index="0" name="time_scale" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_time_scale" qualifiers="const" >
+ <method name="get_time_scale" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_pre_process_time" >
+ <method name="set_pre_process_time">
<argument index="0" name="time" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_pre_process_time" qualifiers="const" >
+ <method name="get_pre_process_time" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_emit_timeout" >
+ <method name="set_emit_timeout">
<argument index="0" name="value" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_emit_timeout" qualifiers="const" >
+ <method name="get_emit_timeout" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_param" >
+ <method name="set_param">
<argument index="0" name="param" type="int">
</argument>
<argument index="1" name="value" type="float">
@@ -18074,7 +21518,7 @@
<description>
</description>
</method>
- <method name="get_param" qualifiers="const" >
+ <method name="get_param" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="param" type="int">
@@ -18082,7 +21526,7 @@
<description>
</description>
</method>
- <method name="set_randomness" >
+ <method name="set_randomness">
<argument index="0" name="param" type="int">
</argument>
<argument index="1" name="value" type="float">
@@ -18090,7 +21534,7 @@
<description>
</description>
</method>
- <method name="get_randomness" qualifiers="const" >
+ <method name="get_randomness" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="param" type="int">
@@ -18098,103 +21542,131 @@
<description>
</description>
</method>
- <method name="set_texture" >
+ <method name="set_texture">
+ <return type="Texture">
+ </return>
<argument index="0" name="texture" type="Object">
</argument>
<description>
</description>
</method>
- <method name="get_texture" qualifiers="const" >
+ <method name="get_texture" qualifiers="const">
<return type="Texture">
</return>
<description>
</description>
</method>
- <method name="set_emissor_offset" >
+ <method name="set_color">
+ <argument index="0" name="color" type="Color">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_color" qualifiers="const">
+ <return type="Color">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_color_ramp">
+ <return type="ColorRamp">
+ </return>
+ <argument index="0" name="color_ramp" type="Object">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_color_ramp" qualifiers="const">
+ <return type="ColorRamp">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_emissor_offset">
<argument index="0" name="offset" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_emissor_offset" qualifiers="const" >
+ <method name="get_emissor_offset" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="set_flip_h" >
+ <method name="set_flip_h">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_flipped_h" qualifiers="const" >
+ <method name="is_flipped_h" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_flip_v" >
+ <method name="set_flip_v">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_flipped_v" qualifiers="const" >
+ <method name="is_flipped_v" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_h_frames" >
+ <method name="set_h_frames">
<argument index="0" name="enable" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_h_frames" qualifiers="const" >
+ <method name="get_h_frames" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_v_frames" >
+ <method name="set_v_frames">
<argument index="0" name="enable" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_v_frames" qualifiers="const" >
+ <method name="get_v_frames" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_emission_half_extents" >
+ <method name="set_emission_half_extents">
<argument index="0" name="extents" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_emission_half_extents" qualifiers="const" >
+ <method name="get_emission_half_extents" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="set_color_phases" >
+ <method name="set_color_phases">
<argument index="0" name="phases" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_color_phases" qualifiers="const" >
+ <method name="get_color_phases" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_color_phase_color" >
+ <method name="set_color_phase_color">
<argument index="0" name="phase" type="int">
</argument>
<argument index="1" name="color" type="Color">
@@ -18202,7 +21674,7 @@
<description>
</description>
</method>
- <method name="get_color_phase_color" qualifiers="const" >
+ <method name="get_color_phase_color" qualifiers="const">
<return type="Color">
</return>
<argument index="0" name="phase" type="int">
@@ -18210,7 +21682,7 @@
<description>
</description>
</method>
- <method name="set_color_phase_pos" >
+ <method name="set_color_phase_pos">
<argument index="0" name="phase" type="int">
</argument>
<argument index="1" name="pos" type="float">
@@ -18218,7 +21690,7 @@
<description>
</description>
</method>
- <method name="get_color_phase_pos" qualifiers="const" >
+ <method name="get_color_phase_pos" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="phase" type="int">
@@ -18226,55 +21698,59 @@
<description>
</description>
</method>
- <method name="pre_process" >
+ <method name="pre_process">
<argument index="0" name="time" type="float">
</argument>
<description>
</description>
</method>
- <method name="set_use_local_space" >
+ <method name="reset">
+ <description>
+ </description>
+ </method>
+ <method name="set_use_local_space">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_using_local_space" qualifiers="const" >
+ <method name="is_using_local_space" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_initial_velocity" >
+ <method name="set_initial_velocity">
<argument index="0" name="velocity" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_initial_velocity" qualifiers="const" >
+ <method name="get_initial_velocity" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="set_explosiveness" >
+ <method name="set_explosiveness">
<argument index="0" name="amount" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_explosiveness" qualifiers="const" >
+ <method name="get_explosiveness" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_emission_points" >
+ <method name="set_emission_points">
<argument index="0" name="points" type="Vector2Array">
</argument>
<description>
</description>
</method>
- <method name="get_emission_points" qualifiers="const" >
+ <method name="get_emission_points" qualifiers="const">
<return type="Vector2Array">
</return>
<description>
@@ -18290,6 +21766,8 @@
</constant>
<constant name="PARAM_SPIN_VELOCITY" value="3">
</constant>
+ <constant name="PARAM_ORBIT_VELOCITY" value="4">
+ </constant>
<constant name="PARAM_GRAVITY_DIRECTION" value="5">
</constant>
<constant name="PARAM_GRAVITY_STRENGTH" value="6">
@@ -18298,34 +21776,108 @@
</constant>
<constant name="PARAM_TANGENTIAL_ACCEL" value="8">
</constant>
+ <constant name="PARAM_DAMPING" value="9">
+ </constant>
+ <constant name="PARAM_INITIAL_ANGLE" value="10">
+ </constant>
<constant name="PARAM_INITIAL_SIZE" value="11">
</constant>
<constant name="PARAM_FINAL_SIZE" value="12">
</constant>
<constant name="PARAM_HUE_VARIATION" value="13">
</constant>
+ <constant name="PARAM_ANIM_SPEED_SCALE" value="14">
+ </constant>
+ <constant name="PARAM_ANIM_INITIAL_POS" value="15">
+ </constant>
<constant name="PARAM_MAX" value="16">
</constant>
<constant name="MAX_COLOR_PHASES" value="4">
</constant>
</constants>
</class>
+<class name="Patch9Frame" inherits="Control" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="set_texture">
+ <argument index="0" name="texture" type="Object">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_texture" qualifiers="const">
+ <return type="Object">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_modulate">
+ <argument index="0" name="modulate" type="Color">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_modulate" qualifiers="const">
+ <return type="Color">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_patch_margin">
+ <argument index="0" name="margin" type="int">
+ </argument>
+ <argument index="1" name="value" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_patch_margin" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="margin" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_draw_center">
+ <argument index="0" name="draw_center" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_draw_center" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
<class name="Path" inherits="Spatial" category="Core">
<brief_description>
+ Container for a [Curve3D].
</brief_description>
<description>
+ This class is a container/Node-ification of a [Curve3D], so it can have [Spatial] properties and [Node] info.
</description>
<methods>
- <method name="set_curve" >
+ <method name="set_curve">
<argument index="0" name="curve" type="Curve3D">
</argument>
<description>
+ Sets the [Curve3D].
</description>
</method>
- <method name="get_curve" qualifiers="const" >
+ <method name="get_curve" qualifiers="const">
<return type="Curve3D">
</return>
<description>
+ Returns the [Curve3D] contained.
</description>
</method>
</methods>
@@ -18334,20 +21886,24 @@
</class>
<class name="Path2D" inherits="Node2D" category="Core">
<brief_description>
+ Container for a [Curve2D].
</brief_description>
<description>
+ This class is a container/Node-ification of a [Curve2D], so it can have [Node2D] properties and [Node] info.
</description>
<methods>
- <method name="set_curve" >
+ <method name="set_curve">
<argument index="0" name="curve" type="Curve2D">
</argument>
<description>
+ Sets the [Curve2D].
</description>
</method>
- <method name="get_curve" qualifiers="const" >
+ <method name="get_curve" qualifiers="const">
<return type="Curve2D">
</return>
<description>
+ Returns the [Curve2D] contained.
</description>
</method>
</methods>
@@ -18356,194 +21912,238 @@
</class>
<class name="PathFollow" inherits="Spatial" category="Core">
<brief_description>
+ Point sampler for a [Path].
</brief_description>
<description>
+ This node takes its parent [Path], and returns the coordinates of a point within it, given a distance from the first vertex.
+It is useful for making other nodes follow a path, without coding the movement pattern. For that, the nodes must be descendants of this node. Then, when setting an offset in this node, the descendant nodes will move accordingly.
</description>
<methods>
- <method name="set_offset" >
+ <method name="set_offset">
<argument index="0" name="offset" type="float">
</argument>
<description>
+ Sets the distance from the first vertex, measured in 3D units along the path. This sets this node's position to a point within the path.
</description>
</method>
- <method name="get_offset" qualifiers="const" >
+ <method name="get_offset" qualifiers="const">
<return type="float">
</return>
<description>
+ Returns the distance along the path in 3D units.
</description>
</method>
- <method name="set_h_offset" >
+ <method name="set_h_offset">
<argument index="0" name="h_offset" type="float">
</argument>
<description>
+ Moves this node in the X axis. As this node's position will be set every time its offset is set, this allows many PathFollow to share the same curve (and thus the same movement pattern), yet not return the same position for a given path offset.
+A similar effect may be achieved moving the this node's descendants.
</description>
</method>
- <method name="get_h_offset" qualifiers="const" >
+ <method name="get_h_offset" qualifiers="const">
<return type="float">
</return>
<description>
+ Returns the X displacement this node has from its parent [Path].
</description>
</method>
- <method name="set_v_offset" >
+ <method name="set_v_offset">
<argument index="0" name="v_offset" type="float">
</argument>
<description>
+ Moves this node in the Y axis, for the same reasons of [method set_h_offset].
</description>
</method>
- <method name="get_v_offset" qualifiers="const" >
+ <method name="get_v_offset" qualifiers="const">
<return type="float">
</return>
<description>
+ Returns the Y displacement this node has from its parent [Path].
</description>
</method>
- <method name="set_unit_offset" >
+ <method name="set_unit_offset">
<argument index="0" name="unit_offset" type="float">
</argument>
<description>
+ Sets the distance from the first vertex, considering 0.0 as the first vertex and 1.0 as the last. This is just another way of expressing the offset within the path, as the offset supplied is multiplied internally by the path's length.
</description>
</method>
- <method name="get_unit_offset" qualifiers="const" >
+ <method name="get_unit_offset" qualifiers="const">
<return type="float">
</return>
<description>
+ Returns the distance along the path as a number in the range 0.0 (for the first vertex) to 1.0 (for the last).
</description>
</method>
- <method name="set_rotation_mode" >
+ <method name="set_rotation_mode">
<argument index="0" name="rotation_mode" type="int">
</argument>
<description>
+ Allows or forbids rotation on one or more axes, per the constants below.
</description>
</method>
- <method name="get_rotation_mode" qualifiers="const" >
+ <method name="get_rotation_mode" qualifiers="const">
<return type="int">
</return>
<description>
+ Returns the rotation mode. The constants below list which axes are allowed to rotate for each mode.
</description>
</method>
- <method name="set_cubic_interpolation" >
+ <method name="set_cubic_interpolation">
<argument index="0" name="enable" type="bool">
</argument>
<description>
+ The points along the [Curve3D] of the [Path] are precomputed before use, for faster calculations. The point at the requested offset is then calculated interpolating between two adjacent cached points. This may present a problem if the curve makes sharp turns, as the cached points may not follow the curve closely enough.
+There are two answers to this problem: Either increase the number of cached points and increase memory consumption, or make a cubic interpolation between two points at the cost of (slightly) slower calculations.
+This method controls whether the position between two cached points is interpolated linearly, or cubicly.
</description>
</method>
- <method name="get_cubic_interpolation" qualifiers="const" >
+ <method name="get_cubic_interpolation" qualifiers="const">
<return type="bool">
</return>
<description>
+ This method returns whether the position between two cached points (see [method set_cubic_interpolation]) is interpolated linearly, or cubicly.
</description>
</method>
- <method name="set_loop" >
+ <method name="set_loop">
<argument index="0" name="loop" type="bool">
</argument>
<description>
+ If set, any offset outside the path's length (whether set by [method set_offset] or [method set_unit_offset] will wrap around, instead of stopping at the ends. Set it for cyclic paths.
</description>
</method>
- <method name="has_loop" qualifiers="const" >
+ <method name="has_loop" qualifiers="const">
<return type="bool">
</return>
<description>
+ Returns whether this node wraps its offsets around, or truncates them to the path ends.
</description>
</method>
</methods>
<constants>
<constant name="ROTATION_NONE" value="0">
+ Forbids the PathFollow to rotate.
</constant>
<constant name="ROTATION_Y" value="1">
+ Allows the PathFollow to rotate in the Y axis only.
</constant>
<constant name="ROTATION_XY" value="2">
+ Allows the PathFollow to rotate in both the X, and Y axes.
</constant>
<constant name="ROTATION_XYZ" value="3">
+ Allows the PathFollow to rotate in any axis.
</constant>
</constants>
</class>
<class name="PathFollow2D" inherits="Node2D" category="Core">
<brief_description>
+ Point sampler for a [Path2D].
</brief_description>
<description>
+ This node takes its parent [Path2D], and returns the coordinates of a point within it, given a distance from the first vertex.
+It is useful for making other nodes follow a path, without coding the movement pattern. For that, the nodes must be descendants of this node. Then, when setting an offset in this node, the descendant nodes will move accordingly.
</description>
<methods>
- <method name="set_offset" >
+ <method name="set_offset">
<argument index="0" name="offset" type="float">
</argument>
<description>
+ Sets the distance from the first vertex, measured in pixels along the path. This sets this node's position to a point within the path.
</description>
</method>
- <method name="get_offset" qualifiers="const" >
+ <method name="get_offset" qualifiers="const">
<return type="float">
</return>
<description>
+ Returns the distance along the path in pixels.
</description>
</method>
- <method name="set_h_offset" >
+ <method name="set_h_offset">
<argument index="0" name="h_offset" type="float">
</argument>
<description>
+ Moves this node horizontally. As this node's position will be set every time its offset is set, this allows many PathFollow2D to share the same curve (and thus the same movement pattern), yet not return the same position for a given path offset.
+A similar effect may be achieved moving this node's descendants.
</description>
</method>
- <method name="get_h_offset" qualifiers="const" >
+ <method name="get_h_offset" qualifiers="const">
<return type="float">
</return>
<description>
+ Returns the horizontal displacement this node has from its parent [Path2D].
</description>
</method>
- <method name="set_v_offset" >
+ <method name="set_v_offset">
<argument index="0" name="v_offset" type="float">
</argument>
<description>
+ Moves the PathFollow2D vertically, for the same reasons of [method set_h_offset].
</description>
</method>
- <method name="get_v_offset" qualifiers="const" >
+ <method name="get_v_offset" qualifiers="const">
<return type="float">
</return>
<description>
+ Returns the vertical displacement this node has from its parent [Path2D].
</description>
</method>
- <method name="set_unit_offset" >
+ <method name="set_unit_offset">
<argument index="0" name="unit_offset" type="float">
</argument>
<description>
+ Sets the distance from the first vertex, considering 0.0 as the first vertex and 1.0 as the last. This is just another way of expressing the offset within the path, as the offset supplied is multiplied internally by the path's length.
</description>
</method>
- <method name="get_unit_offset" qualifiers="const" >
+ <method name="get_unit_offset" qualifiers="const">
<return type="float">
</return>
<description>
+ Returns the distance along the path as a number in the range 0.0 (for the first vertex) to 1.0 (for the last).
</description>
</method>
- <method name="set_rotate" >
+ <method name="set_rotate">
<argument index="0" name="enable" type="bool">
</argument>
<description>
+ If set, this node rotates to follow the path, making its descendants rotate.
</description>
</method>
- <method name="is_rotating" qualifiers="const" >
+ <method name="is_rotating" qualifiers="const">
<return type="bool">
</return>
<description>
+ Returns whether this node rotates to follow the path.
</description>
</method>
- <method name="set_cubic_interpolation" >
+ <method name="set_cubic_interpolation">
<argument index="0" name="enable" type="bool">
</argument>
<description>
+ The points along the [Curve2D] of the [Path2D] are precomputed before use, for faster calculations. The point at the requested offset is then calculated interpolating between two adjacent cached points. This may present a problem if the curve makes sharp turns, as the cached points may not follow the curve closely enough.
+There are two answers to this problem: Either increase the number of cached points and increase memory consumption, or make a cubic interpolation between two points at the cost of (slightly) slower calculations.
+This method controls whether the position between two cached points is interpolated linearly, or cubicly.
</description>
</method>
- <method name="get_cubic_interpolation" qualifiers="const" >
+ <method name="get_cubic_interpolation" qualifiers="const">
<return type="bool">
</return>
<description>
+ This method returns whether the position between two cached points (see [method set_cubic_interpolation]) is interpolated linearly, or cubicly.
</description>
</method>
- <method name="set_loop" >
+ <method name="set_loop">
<argument index="0" name="loop" type="bool">
</argument>
<description>
+ If set, any offset outside the path's length (whether set by [method set_offset] or [method set_unit_offset] will wrap around, instead of stopping at the ends. Set it for cyclic paths.
</description>
</method>
- <method name="has_loop" qualifiers="const" >
+ <method name="has_loop" qualifiers="const">
<return type="bool">
</return>
<description>
+ Returns whether this node wraps its offsets around, or truncates them to the path ends.
</description>
</method>
</methods>
@@ -18558,7 +22158,7 @@
When exporting, the types of some resources may change internally so they are converted to more optimized versions. While it's not usually necesary to access to this directly (path remapping happens automatically when opeining a file), it's exported just for information.
</description>
<methods>
- <method name="add_remap" >
+ <method name="add_remap">
<argument index="0" name="from" type="String">
</argument>
<argument index="1" name="to" type="String">
@@ -18569,7 +22169,7 @@
Add a remap from a file to another.
</description>
</method>
- <method name="has_remap" qualifiers="const" >
+ <method name="has_remap" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="path" type="String">
@@ -18578,7 +22178,7 @@
Return true if a file is being remapped.
</description>
</method>
- <method name="get_remap" qualifiers="const" >
+ <method name="get_remap" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="path" type="String">
@@ -18587,14 +22187,14 @@
Return the remapped new path of a file.
</description>
</method>
- <method name="erase_remap" >
+ <method name="erase_remap">
<argument index="0" name="path" type="String">
</argument>
<description>
Erase a remap.
</description>
</method>
- <method name="clear_remaps" >
+ <method name="clear_remaps">
<description>
Clear all remaps.
</description>
@@ -18609,7 +22209,7 @@
<description>
</description>
<methods>
- <method name="get_monitor" qualifiers="const" >
+ <method name="get_monitor" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="monitor" type="int">
@@ -18685,98 +22285,103 @@
Direct access object to a physics body in the [Physics2DServer]. This object is passed via the direct state callback of rigid/character bodies, and is intended for changing the direct state of that body.
</description>
<methods>
- <method name="get_total_gravity" qualifiers="const" >
+ <method name="get_total_gravity" qualifiers="const">
<return type="Vector2">
</return>
<description>
Return the total gravity vector being currently applied to this body.
</description>
</method>
- <method name="get_total_density" qualifiers="const" >
+ <method name="get_total_linear_damp" qualifiers="const">
<return type="float">
</return>
<description>
- Return the space density currently being applied to this body.
</description>
</method>
- <method name="get_inverse_mass" qualifiers="const" >
+ <method name="get_total_angular_damp" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_inverse_mass" qualifiers="const">
<return type="float">
</return>
<description>
Return the inverse of the mass of the body.
</description>
</method>
- <method name="get_inverse_inertia" qualifiers="const" >
+ <method name="get_inverse_inertia" qualifiers="const">
<return type="float">
</return>
<description>
Return the inverse of the inertia of the body.
</description>
</method>
- <method name="set_linear_velocity" >
+ <method name="set_linear_velocity">
<argument index="0" name="velocity" type="Vector2">
</argument>
<description>
Change the linear velocity of the body.
</description>
</method>
- <method name="get_linear_velocity" qualifiers="const" >
+ <method name="get_linear_velocity" qualifiers="const">
<return type="Vector2">
</return>
<description>
Return the current linear velocity of the body.
</description>
</method>
- <method name="set_angular_velocity" >
+ <method name="set_angular_velocity">
<argument index="0" name="velocity" type="float">
</argument>
<description>
Change the angular velocity of the body.
</description>
</method>
- <method name="get_angular_velocity" qualifiers="const" >
+ <method name="get_angular_velocity" qualifiers="const">
<return type="float">
</return>
<description>
Return the angular velocity of the body.
</description>
</method>
- <method name="set_transform" >
+ <method name="set_transform">
<argument index="0" name="transform" type="Matrix32">
</argument>
<description>
Change the transform matrix of the body.
</description>
</method>
- <method name="get_transform" qualifiers="const" >
+ <method name="get_transform" qualifiers="const">
<return type="Matrix32">
</return>
<description>
Return the transform matrix of the body.
</description>
</method>
- <method name="set_sleep_state" >
+ <method name="set_sleep_state">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
Set the sleeping state of the body, only affects character/rigid bodies.
</description>
</method>
- <method name="is_sleeping" qualifiers="const" >
+ <method name="is_sleeping" qualifiers="const">
<return type="bool">
</return>
<description>
Return true if this body is currently sleeping (not active).
</description>
</method>
- <method name="get_contact_count" qualifiers="const" >
+ <method name="get_contact_count" qualifiers="const">
<return type="int">
</return>
<description>
Return the amount of contacts this body has with other bodies. Note that by default this returns 0 unless bodies are configured to log contacts.
</description>
</method>
- <method name="get_contact_local_pos" qualifiers="const" >
+ <method name="get_contact_local_pos" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="contact_idx" type="int">
@@ -18785,7 +22390,7 @@
Return the local position (of this body) of the contact point.
</description>
</method>
- <method name="get_contact_local_normal" qualifiers="const" >
+ <method name="get_contact_local_normal" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="contact_idx" type="int">
@@ -18793,7 +22398,7 @@
<description>
</description>
</method>
- <method name="get_contact_local_shape" qualifiers="const" >
+ <method name="get_contact_local_shape" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="contact_idx" type="int">
@@ -18802,7 +22407,7 @@
Return the local shape index of the collision.
</description>
</method>
- <method name="get_contact_collider" qualifiers="const" >
+ <method name="get_contact_collider" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="contact_idx" type="int">
@@ -18811,7 +22416,7 @@
Return the RID of the collider.
</description>
</method>
- <method name="get_contact_collider_pos" qualifiers="const" >
+ <method name="get_contact_collider_pos" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="contact_idx" type="int">
@@ -18820,7 +22425,7 @@
Return the contact position in the collider.
</description>
</method>
- <method name="get_contact_collider_id" qualifiers="const" >
+ <method name="get_contact_collider_id" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="contact_idx" type="int">
@@ -18829,7 +22434,7 @@
Return the object id of the collider.
</description>
</method>
- <method name="get_contact_collider_object" qualifiers="const" >
+ <method name="get_contact_collider_object" qualifiers="const">
<return type="Object">
</return>
<argument index="0" name="contact_idx" type="int">
@@ -18838,7 +22443,7 @@
Return the collider object, this depends on how it was created (will return a scene node if such was used to create it).
</description>
</method>
- <method name="get_contact_collider_shape" qualifiers="const" >
+ <method name="get_contact_collider_shape" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="contact_idx" type="int">
@@ -18847,13 +22452,15 @@
Return the collider shape index.
</description>
</method>
- <method name="get_contact_collider_shape_metadata" qualifiers="const" >
+ <method name="get_contact_collider_shape_metadata" qualifiers="const">
+ <return type="Variant">
+ </return>
<argument index="0" name="contact_idx" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_contact_collider_velocity_at_pos" qualifiers="const" >
+ <method name="get_contact_collider_velocity_at_pos" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="contact_idx" type="int">
@@ -18862,19 +22469,19 @@
Return the linear velocity vector at contact point of the collider.
</description>
</method>
- <method name="get_step" qualifiers="const" >
+ <method name="get_step" qualifiers="const">
<return type="float">
</return>
<description>
Return the timestep (delta) used for the simulation.
</description>
</method>
- <method name="integrate_forces" >
+ <method name="integrate_forces">
<description>
Call the built-in force integration code.
</description>
</method>
- <method name="get_space_state" >
+ <method name="get_space_state">
<return type="Physics2DDirectSpaceState">
</return>
<description>
@@ -18903,7 +22510,23 @@
Direct access object to a space in the [Physics2DServer]. It's used mainly to do queries against objects and areas residing in a given space.
</description>
<methods>
- <method name="intersect_ray" >
+ <method name="intersect_point">
+ <return type="Array">
+ </return>
+ <argument index="0" name="point" type="Vector2">
+ </argument>
+ <argument index="1" name="max_results" type="int" default="32">
+ </argument>
+ <argument index="2" name="exclude" type="Array" default="Array()">
+ </argument>
+ <argument index="3" name="layer_mask" type="int" default="2147483647">
+ </argument>
+ <argument index="4" name="type_mask" type="int" default="15">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="intersect_ray">
<return type="Dictionary">
</return>
<argument index="0" name="from" type="Vector2">
@@ -18917,19 +22540,18 @@
<argument index="4" name="type_mask" type="int" default="15">
</argument>
<description>
- Intersect a ray in a given space, the returned object is a dictionary with the following fields: [br]
- position: place where ray is stopped[br]
- normal: normal of the object at the point where the ray was stopped [br]
- shape: shape index of the object agaisnt which the ray was stopped[br]
- collider_: collider agaisnt which the ray was stopped[br]
- collider_id: collider id of the object agaisnt which the ray was stopped[br]
- collider: collider object agaisnt which the ray was stopped[br]
- rid: [RID] of the object agaisnt which the ray was stopped[br]
- If the ray did not intersect anything, then an empty
- dictionary (dir.empty()==true) is returned instead.
+ Intersect a ray in a given space, the returned object is a dictionary with the following fields:
+ position: place where ray is stopped.
+ normal: normal of the object at the point where the ray was stopped.
+ shape: shape index of the object agaisnt which the ray was stopped.
+ collider_: collider agaisnt which the ray was stopped.
+ collider_id: collider id of the object agaisnt which the ray was stopped.
+ collider: collider object agaisnt which the ray was stopped.
+ rid: [RID] of the object agaisnt which the ray was stopped.
+ If the ray did not intersect anything, then an empty dictionary (dir.empty()==true) is returned instead.
</description>
</method>
- <method name="intersect_shape" >
+ <method name="intersect_shape">
<return type="Array">
</return>
<argument index="0" name="shape" type="Physics2DShapeQueryParameters">
@@ -18940,7 +22562,7 @@
Intersect a given shape (RID or [Shape2D]) against the space, the intersected shapes are returned in a special result object.
</description>
</method>
- <method name="cast_motion" >
+ <method name="cast_motion">
<return type="Array">
</return>
<argument index="0" name="shape" type="Physics2DShapeQueryParameters">
@@ -18948,7 +22570,7 @@
<description>
</description>
</method>
- <method name="collide_shape" >
+ <method name="collide_shape">
<return type="Array">
</return>
<argument index="0" name="shape" type="Physics2DShapeQueryParameters">
@@ -18958,7 +22580,7 @@
<description>
</description>
</method>
- <method name="get_rest_info" >
+ <method name="get_rest_info">
<return type="Dictionary">
</return>
<argument index="0" name="shape" type="Physics2DShapeQueryParameters">
@@ -18990,7 +22612,7 @@
Physics 2D Server is the server responsible for all 2D physics.
</description>
<methods>
- <method name="shape_create" >
+ <method name="shape_create">
<return type="RID">
</return>
<argument index="0" name="type" type="int">
@@ -18998,7 +22620,7 @@
<description>
</description>
</method>
- <method name="shape_set_data" >
+ <method name="shape_set_data">
<argument index="0" name="shape" type="RID">
</argument>
<argument index="1" name="data" type="var">
@@ -19006,7 +22628,7 @@
<description>
</description>
</method>
- <method name="shape_get_type" qualifiers="const" >
+ <method name="shape_get_type" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="shape" type="RID">
@@ -19014,19 +22636,19 @@
<description>
</description>
</method>
- <method name="shape_get_data" qualifiers="const" >
+ <method name="shape_get_data" qualifiers="const">
<argument index="0" name="shape" type="RID">
</argument>
<description>
</description>
</method>
- <method name="space_create" >
+ <method name="space_create">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="space_set_active" >
+ <method name="space_set_active">
<argument index="0" name="space" type="RID">
</argument>
<argument index="1" name="active" type="bool">
@@ -19034,7 +22656,7 @@
<description>
</description>
</method>
- <method name="space_is_active" qualifiers="const" >
+ <method name="space_is_active" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="space" type="RID">
@@ -19042,7 +22664,7 @@
<description>
</description>
</method>
- <method name="space_set_param" >
+ <method name="space_set_param">
<argument index="0" name="space" type="RID">
</argument>
<argument index="1" name="param" type="int">
@@ -19052,7 +22674,7 @@
<description>
</description>
</method>
- <method name="space_get_param" qualifiers="const" >
+ <method name="space_get_param" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="space" type="RID">
@@ -19062,7 +22684,7 @@
<description>
</description>
</method>
- <method name="space_get_direct_state" >
+ <method name="space_get_direct_state">
<return type="Physics2DDirectSpaceState">
</return>
<argument index="0" name="space" type="RID">
@@ -19070,13 +22692,13 @@
<description>
</description>
</method>
- <method name="area_create" >
+ <method name="area_create">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="area_set_space" >
+ <method name="area_set_space">
<argument index="0" name="area" type="RID">
</argument>
<argument index="1" name="space" type="RID">
@@ -19084,7 +22706,7 @@
<description>
</description>
</method>
- <method name="area_get_space" qualifiers="const" >
+ <method name="area_get_space" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="area" type="RID">
@@ -19092,7 +22714,7 @@
<description>
</description>
</method>
- <method name="area_set_space_override_mode" >
+ <method name="area_set_space_override_mode">
<argument index="0" name="area" type="RID">
</argument>
<argument index="1" name="mode" type="int">
@@ -19100,7 +22722,7 @@
<description>
</description>
</method>
- <method name="area_get_space_override_mode" qualifiers="const" >
+ <method name="area_get_space_override_mode" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="area" type="RID">
@@ -19108,7 +22730,7 @@
<description>
</description>
</method>
- <method name="area_add_shape" >
+ <method name="area_add_shape">
<argument index="0" name="area" type="RID">
</argument>
<argument index="1" name="shape" type="RID">
@@ -19118,7 +22740,7 @@
<description>
</description>
</method>
- <method name="area_set_shape" >
+ <method name="area_set_shape">
<argument index="0" name="area" type="RID">
</argument>
<argument index="1" name="shape_idx" type="int">
@@ -19128,7 +22750,7 @@
<description>
</description>
</method>
- <method name="area_set_shape_transform" >
+ <method name="area_set_shape_transform">
<argument index="0" name="area" type="RID">
</argument>
<argument index="1" name="shape_idx" type="int">
@@ -19138,7 +22760,7 @@
<description>
</description>
</method>
- <method name="area_get_shape_count" qualifiers="const" >
+ <method name="area_get_shape_count" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="area" type="RID">
@@ -19146,7 +22768,7 @@
<description>
</description>
</method>
- <method name="area_get_shape" qualifiers="const" >
+ <method name="area_get_shape" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="area" type="RID">
@@ -19156,7 +22778,7 @@
<description>
</description>
</method>
- <method name="area_get_shape_transform" qualifiers="const" >
+ <method name="area_get_shape_transform" qualifiers="const">
<return type="Matrix32">
</return>
<argument index="0" name="area" type="RID">
@@ -19166,7 +22788,7 @@
<description>
</description>
</method>
- <method name="area_remove_shape" >
+ <method name="area_remove_shape">
<argument index="0" name="area" type="RID">
</argument>
<argument index="1" name="shape_idx" type="int">
@@ -19174,13 +22796,29 @@
<description>
</description>
</method>
- <method name="area_clear_shapes" >
+ <method name="area_clear_shapes">
<argument index="0" name="area" type="RID">
</argument>
<description>
</description>
</method>
- <method name="area_set_param" >
+ <method name="area_set_layer_mask">
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="mask" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="area_set_collision_mask">
+ <argument index="0" name="area" type="RID">
+ </argument>
+ <argument index="1" name="mask" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="area_set_param">
<argument index="0" name="area" type="RID">
</argument>
<argument index="1" name="param" type="int">
@@ -19190,7 +22828,7 @@
<description>
</description>
</method>
- <method name="area_set_transform" >
+ <method name="area_set_transform">
<argument index="0" name="area" type="RID">
</argument>
<argument index="1" name="transform" type="Matrix32">
@@ -19198,7 +22836,7 @@
<description>
</description>
</method>
- <method name="area_get_param" qualifiers="const" >
+ <method name="area_get_param" qualifiers="const">
<argument index="0" name="area" type="RID">
</argument>
<argument index="1" name="param" type="int">
@@ -19206,7 +22844,7 @@
<description>
</description>
</method>
- <method name="area_get_transform" qualifiers="const" >
+ <method name="area_get_transform" qualifiers="const">
<return type="Matrix32">
</return>
<argument index="0" name="area" type="RID">
@@ -19214,7 +22852,7 @@
<description>
</description>
</method>
- <method name="area_attach_object_instance_ID" >
+ <method name="area_attach_object_instance_ID">
<argument index="0" name="area" type="RID">
</argument>
<argument index="1" name="id" type="int">
@@ -19222,7 +22860,7 @@
<description>
</description>
</method>
- <method name="area_get_object_instance_ID" qualifiers="const" >
+ <method name="area_get_object_instance_ID" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="area" type="RID">
@@ -19230,17 +22868,17 @@
<description>
</description>
</method>
- <method name="area_set_monitor_callback" >
- <argument index="0" name="receiver" type="RID">
+ <method name="area_set_monitor_callback">
+ <argument index="0" name="area" type="RID">
</argument>
- <argument index="1" name="method" type="Object">
+ <argument index="1" name="receiver" type="Object">
</argument>
- <argument index="2" name="arg2" type="String">
+ <argument index="2" name="method" type="String">
</argument>
<description>
</description>
</method>
- <method name="body_create" >
+ <method name="body_create">
<return type="RID">
</return>
<argument index="0" name="mode" type="int" default="2">
@@ -19250,7 +22888,7 @@
<description>
</description>
</method>
- <method name="body_set_space" >
+ <method name="body_set_space">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="space" type="RID">
@@ -19258,7 +22896,7 @@
<description>
</description>
</method>
- <method name="body_get_space" qualifiers="const" >
+ <method name="body_get_space" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="body" type="RID">
@@ -19266,7 +22904,7 @@
<description>
</description>
</method>
- <method name="body_set_mode" >
+ <method name="body_set_mode">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="mode" type="int">
@@ -19274,7 +22912,7 @@
<description>
</description>
</method>
- <method name="body_get_mode" qualifiers="const" >
+ <method name="body_get_mode" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="body" type="RID">
@@ -19282,7 +22920,7 @@
<description>
</description>
</method>
- <method name="body_add_shape" >
+ <method name="body_add_shape">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="shape" type="RID">
@@ -19292,7 +22930,7 @@
<description>
</description>
</method>
- <method name="body_set_shape" >
+ <method name="body_set_shape">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="shape_idx" type="int">
@@ -19302,7 +22940,7 @@
<description>
</description>
</method>
- <method name="body_set_shape_transform" >
+ <method name="body_set_shape_transform">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="shape_idx" type="int">
@@ -19312,7 +22950,7 @@
<description>
</description>
</method>
- <method name="body_set_shape_metadata" >
+ <method name="body_set_shape_metadata">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="shape_idx" type="int">
@@ -19322,7 +22960,7 @@
<description>
</description>
</method>
- <method name="body_get_shape_count" qualifiers="const" >
+ <method name="body_get_shape_count" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="body" type="RID">
@@ -19330,7 +22968,7 @@
<description>
</description>
</method>
- <method name="body_get_shape" qualifiers="const" >
+ <method name="body_get_shape" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="body" type="RID">
@@ -19340,7 +22978,7 @@
<description>
</description>
</method>
- <method name="body_get_shape_transform" qualifiers="const" >
+ <method name="body_get_shape_transform" qualifiers="const">
<return type="Matrix32">
</return>
<argument index="0" name="body" type="RID">
@@ -19350,7 +22988,7 @@
<description>
</description>
</method>
- <method name="body_get_shape_metadata" qualifiers="const" >
+ <method name="body_get_shape_metadata" qualifiers="const">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="shape_idx" type="int">
@@ -19358,7 +22996,7 @@
<description>
</description>
</method>
- <method name="body_remove_shape" >
+ <method name="body_remove_shape">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="shape_idx" type="int">
@@ -19366,13 +23004,13 @@
<description>
</description>
</method>
- <method name="body_clear_shapes" >
+ <method name="body_clear_shapes">
<argument index="0" name="body" type="RID">
</argument>
<description>
</description>
</method>
- <method name="body_set_shape_as_trigger" >
+ <method name="body_set_shape_as_trigger">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="shape_idx" type="int">
@@ -19382,7 +23020,7 @@
<description>
</description>
</method>
- <method name="body_is_shape_set_as_trigger" qualifiers="const" >
+ <method name="body_is_shape_set_as_trigger" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="body" type="RID">
@@ -19392,7 +23030,7 @@
<description>
</description>
</method>
- <method name="body_attach_object_instance_ID" >
+ <method name="body_attach_object_instance_ID">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="id" type="int">
@@ -19400,7 +23038,7 @@
<description>
</description>
</method>
- <method name="body_get_object_instance_ID" qualifiers="const" >
+ <method name="body_get_object_instance_ID" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="body" type="RID">
@@ -19408,7 +23046,7 @@
<description>
</description>
</method>
- <method name="body_set_continuous_collision_detection_mode" >
+ <method name="body_set_continuous_collision_detection_mode">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="mode" type="int">
@@ -19416,7 +23054,7 @@
<description>
</description>
</method>
- <method name="body_get_continuous_collision_detection_mode" qualifiers="const" >
+ <method name="body_get_continuous_collision_detection_mode" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="body" type="RID">
@@ -19424,7 +23062,7 @@
<description>
</description>
</method>
- <method name="body_set_layer_mask" >
+ <method name="body_set_layer_mask">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="mask" type="int">
@@ -19432,17 +23070,15 @@
<description>
</description>
</method>
- <method name="body_get_layer_mask" qualifiers="const" >
+ <method name="body_get_layer_mask" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="body" type="RID">
</argument>
- <argument index="1" name="arg1" type="int">
- </argument>
<description>
</description>
</method>
- <method name="body_set_collision_mask" >
+ <method name="body_set_collision_mask">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="mask" type="int">
@@ -19450,17 +23086,15 @@
<description>
</description>
</method>
- <method name="body_get_collision_mask" qualifiers="const" >
+ <method name="body_get_collision_mask" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="body" type="RID">
</argument>
- <argument index="1" name="arg1" type="int">
- </argument>
<description>
</description>
</method>
- <method name="body_set_param" >
+ <method name="body_set_param">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="param" type="int">
@@ -19470,7 +23104,7 @@
<description>
</description>
</method>
- <method name="body_get_param" qualifiers="const" >
+ <method name="body_get_param" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="body" type="RID">
@@ -19480,7 +23114,7 @@
<description>
</description>
</method>
- <method name="body_set_state" >
+ <method name="body_set_state">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="state" type="int">
@@ -19490,7 +23124,7 @@
<description>
</description>
</method>
- <method name="body_get_state" qualifiers="const" >
+ <method name="body_get_state" qualifiers="const">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="state" type="int">
@@ -19498,7 +23132,7 @@
<description>
</description>
</method>
- <method name="body_apply_impulse" >
+ <method name="body_apply_impulse">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="pos" type="Vector2">
@@ -19508,7 +23142,7 @@
<description>
</description>
</method>
- <method name="body_set_axis_velocity" >
+ <method name="body_set_axis_velocity">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="axis_velocity" type="Vector2">
@@ -19516,7 +23150,7 @@
<description>
</description>
</method>
- <method name="body_add_collision_exception" >
+ <method name="body_add_collision_exception">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="excepted_body" type="RID">
@@ -19524,7 +23158,7 @@
<description>
</description>
</method>
- <method name="body_remove_collision_exception" >
+ <method name="body_remove_collision_exception">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="excepted_body" type="RID">
@@ -19532,7 +23166,7 @@
<description>
</description>
</method>
- <method name="body_set_max_contacts_reported" >
+ <method name="body_set_max_contacts_reported">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="amount" type="int">
@@ -19540,7 +23174,7 @@
<description>
</description>
</method>
- <method name="body_get_max_contacts_reported" qualifiers="const" >
+ <method name="body_get_max_contacts_reported" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="body" type="RID">
@@ -19548,7 +23182,39 @@
<description>
</description>
</method>
- <method name="body_set_omit_force_integration" >
+ <method name="body_set_one_way_collision_direction">
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="normal" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_get_one_way_collision_direction" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_set_one_way_collision_max_depth">
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="depth" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_get_one_way_collision_max_depth" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_set_omit_force_integration">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="enable" type="bool">
@@ -19556,7 +23222,7 @@
<description>
</description>
</method>
- <method name="body_is_omitting_force_integration" qualifiers="const" >
+ <method name="body_is_omitting_force_integration" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="body" type="RID">
@@ -19564,19 +23230,33 @@
<description>
</description>
</method>
- <method name="body_set_force_integration_callback" >
+ <method name="body_set_force_integration_callback">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="receiver" type="Object">
</argument>
<argument index="2" name="method" type="String">
</argument>
- <argument index="3" name="arg3" type="var">
+ <argument index="3" name="userdata" type="var" default="NULL">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="body_test_motion">
+ <return type="bool">
+ </return>
+ <argument index="0" name="body" type="RID">
+ </argument>
+ <argument index="1" name="motion" type="Vector2">
+ </argument>
+ <argument index="2" name="margin" type="float" default="0.08">
+ </argument>
+ <argument index="3" name="result" type="Physics2DTestMotionResult" default="NULL">
</argument>
<description>
</description>
</method>
- <method name="joint_set_param" >
+ <method name="joint_set_param">
<argument index="0" name="joint" type="RID">
</argument>
<argument index="1" name="param" type="int">
@@ -19586,7 +23266,7 @@
<description>
</description>
</method>
- <method name="joint_get_param" qualifiers="const" >
+ <method name="joint_get_param" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="joint" type="RID">
@@ -19596,7 +23276,7 @@
<description>
</description>
</method>
- <method name="pin_joint_create" >
+ <method name="pin_joint_create">
<return type="RID">
</return>
<argument index="0" name="anchor" type="Vector2">
@@ -19608,7 +23288,7 @@
<description>
</description>
</method>
- <method name="groove_joint_create" >
+ <method name="groove_joint_create">
<return type="RID">
</return>
<argument index="0" name="groove1_a" type="Vector2">
@@ -19624,7 +23304,7 @@
<description>
</description>
</method>
- <method name="damped_spring_joint_create" >
+ <method name="damped_spring_joint_create">
<return type="RID">
</return>
<argument index="0" name="anchor_a" type="Vector2">
@@ -19638,7 +23318,7 @@
<description>
</description>
</method>
- <method name="damped_string_joint_set_param" >
+ <method name="damped_string_joint_set_param">
<argument index="0" name="joint" type="RID">
</argument>
<argument index="1" name="param" type="int">
@@ -19648,7 +23328,7 @@
<description>
</description>
</method>
- <method name="damped_string_joint_get_param" qualifiers="const" >
+ <method name="damped_string_joint_get_param" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="joint" type="RID">
@@ -19658,7 +23338,7 @@
<description>
</description>
</method>
- <method name="joint_get_type" qualifiers="const" >
+ <method name="joint_get_type" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="joint" type="RID">
@@ -19666,22 +23346,22 @@
<description>
</description>
</method>
- <method name="free_rid" >
+ <method name="free_rid">
<argument index="0" name="rid" type="RID">
</argument>
<description>
</description>
</method>
- <method name="set_active" >
+ <method name="set_active">
<argument index="0" name="active" type="bool">
</argument>
<description>
</description>
</method>
- <method name="get_process_info" >
+ <method name="get_process_info">
<return type="int">
</return>
- <argument index="0" name="arg0" type="int">
+ <argument index="0" name="process_info" type="int">
</argument>
<description>
</description>
@@ -19710,17 +23390,30 @@
</constant>
<constant name="AREA_PARAM_GRAVITY_IS_POINT" value="2">
</constant>
- <constant name="AREA_PARAM_GRAVITY_POINT_ATTENUATION" value="3">
+ <constant name="AREA_PARAM_GRAVITY_DISTANCE_SCALE" value="3">
</constant>
- <constant name="AREA_PARAM_DENSITY" value="4">
+ <constant name="AREA_PARAM_GRAVITY_POINT_ATTENUATION" value="4">
</constant>
- <constant name="AREA_PARAM_PRIORITY" value="5">
+ <constant name="AREA_PARAM_LINEAR_DAMP" value="5">
</constant>
- <constant name="AREA_SPACE_OVERRIDE_COMBINE" value="1">
+ <constant name="AREA_PARAM_ANGULAR_DAMP" value="6">
+ </constant>
+ <constant name="AREA_PARAM_PRIORITY" value="7">
</constant>
<constant name="AREA_SPACE_OVERRIDE_DISABLED" value="0">
+ This area does not affect gravity/damp. These are generally areas that exist only to detect collisions, and objects entering or exiting them.
+ </constant>
+ <constant name="AREA_SPACE_OVERRIDE_COMBINE" value="1">
+ This area adds its gravity/damp values to whatever has been calculated so far. This way, many overlapping areas can combine their physics to make interesting effects.
+ </constant>
+ <constant name="AREA_SPACE_OVERRIDE_COMBINE_REPLACE" value="2">
+ This area adds its gravity/damp values to whatever has been calculated so far. Then stops taking into account the rest of the areas, even the default one.
</constant>
- <constant name="AREA_SPACE_OVERRIDE_REPLACE" value="2">
+ <constant name="AREA_SPACE_OVERRIDE_REPLACE" value="3">
+ This area replaces any gravity/damp, even the default one, and stops taking into account the rest of the areas.
+ </constant>
+ <constant name="AREA_SPACE_OVERRIDE_REPLACE_COMBINE" value="4">
+ This area replaces any gravity/damp calculated so far, but keeps calculating the rest of the areas, down to the default one.
</constant>
<constant name="BODY_MODE_STATIC" value="0">
</constant>
@@ -19736,7 +23429,13 @@
</constant>
<constant name="BODY_PARAM_MASS" value="2">
</constant>
- <constant name="BODY_PARAM_MAX" value="3">
+ <constant name="BODY_PARAM_GRAVITY_SCALE" value="3">
+ </constant>
+ <constant name="BODY_PARAM_LINEAR_DAMP" value="4">
+ </constant>
+ <constant name="BODY_PARAM_ANGULAR_DAMP" value="5">
+ </constant>
+ <constant name="BODY_PARAM_MAX" value="6">
</constant>
<constant name="BODY_STATE_TRANSFORM" value="0">
</constant>
@@ -19794,91 +23493,91 @@
<description>
</description>
<methods>
- <method name="set_shape" >
+ <method name="set_shape">
<argument index="0" name="shape" type="Shape2D">
</argument>
<description>
</description>
</method>
- <method name="set_shape_rid" >
+ <method name="set_shape_rid">
<argument index="0" name="shape" type="RID">
</argument>
<description>
</description>
</method>
- <method name="get_shape_rid" qualifiers="const" >
+ <method name="get_shape_rid" qualifiers="const">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="set_transform" >
+ <method name="set_transform">
<argument index="0" name="transform" type="Matrix32">
</argument>
<description>
</description>
</method>
- <method name="get_transform" qualifiers="const" >
+ <method name="get_transform" qualifiers="const">
<return type="Matrix32">
</return>
<description>
</description>
</method>
- <method name="set_motion" >
+ <method name="set_motion">
<argument index="0" name="motion" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_motion" qualifiers="const" >
+ <method name="get_motion" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="set_margin" >
+ <method name="set_margin">
<argument index="0" name="margin" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_margin" qualifiers="const" >
+ <method name="get_margin" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_layer_mask" >
+ <method name="set_layer_mask">
<argument index="0" name="layer_mask" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_layer_mask" qualifiers="const" >
+ <method name="get_layer_mask" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_object_type_mask" >
+ <method name="set_object_type_mask">
<argument index="0" name="object_type_mask" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_object_type_mask" qualifiers="const" >
+ <method name="get_object_type_mask" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_exclude" >
+ <method name="set_exclude">
<argument index="0" name="exclude" type="Array">
</argument>
<description>
</description>
</method>
- <method name="get_exclude" qualifiers="const" >
+ <method name="get_exclude" qualifiers="const">
<return type="Array">
</return>
<description>
@@ -19894,13 +23593,13 @@
<description>
</description>
<methods>
- <method name="get_result_count" qualifiers="const" >
+ <method name="get_result_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_result_rid" qualifiers="const" >
+ <method name="get_result_rid" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="idx" type="int">
@@ -19908,7 +23607,7 @@
<description>
</description>
</method>
- <method name="get_result_object_id" qualifiers="const" >
+ <method name="get_result_object_id" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="idx" type="int">
@@ -19916,7 +23615,7 @@
<description>
</description>
</method>
- <method name="get_result_object" qualifiers="const" >
+ <method name="get_result_object" qualifiers="const">
<return type="Object">
</return>
<argument index="0" name="idx" type="int">
@@ -19924,7 +23623,7 @@
<description>
</description>
</method>
- <method name="get_result_object_shape" qualifiers="const" >
+ <method name="get_result_object_shape" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="idx" type="int">
@@ -19936,33 +23635,97 @@
<constants>
</constants>
</class>
+<class name="Physics2DTestMotionResult" inherits="Reference" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="get_motion" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_motion_remainder" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_collision_point" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_collision_normal" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_collider_velocity" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_collider_id" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_collider_rid" qualifiers="const">
+ <return type="RID">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_collider" qualifiers="const">
+ <return type="Object">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_collider_shape" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
<class name="PhysicsBody" inherits="CollisionObject" category="Core">
<brief_description>
- Base class for differnt types of Physics bodies.
+ Base class for different types of Physics bodies.
</brief_description>
<description>
PhysicsBody is an abstract base class for implementing a physics body. All PhysicsBody types inherit from it.
</description>
<methods>
- <method name="set_layer_mask" >
+ <method name="set_layer_mask">
<argument index="0" name="mask" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_layer_mask" qualifiers="const" >
+ <method name="get_layer_mask" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="add_collision_exception_with" >
+ <method name="add_collision_exception_with">
<argument index="0" name="body" type="PhysicsBody">
</argument>
<description>
</description>
</method>
- <method name="remove_collision_exception_with" >
+ <method name="remove_collision_exception_with">
<argument index="0" name="body" type="PhysicsBody">
</argument>
<description>
@@ -19974,32 +23737,118 @@
</class>
<class name="PhysicsBody2D" inherits="CollisionObject2D" category="Core">
<brief_description>
+ Base class for all objects affected by physics.
</brief_description>
<description>
+ PhysicsBody2D is an abstract base class for implementing a physics body. All [i]x[/i]Body2D types inherit from it.
</description>
<methods>
- <method name="set_layer_mask" >
+ <method name="set_layer_mask">
+ <argument index="0" name="mask" type="int">
+ </argument>
+ <description>
+ Set the physics layers this area is in.
+ Collidable objects can exist in any of 32 different layers. These layers are not visual, but more of a tagging system instead. A collidable can use these layers/tags to select with which objects it can collide, using [method set_collision_mask].
+ A contact is detected if object A is in any of the layers that object B scans, or object B is in any layer scanned by object A.
+ </description>
+ </method>
+ <method name="get_layer_mask" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Return the physics layer this area is in.
+ </description>
+ </method>
+ <method name="set_collision_mask">
<argument index="0" name="mask" type="int">
</argument>
<description>
+ Set the physics layers this area can scan for collisions.
</description>
</method>
- <method name="get_layer_mask" qualifiers="const" >
+ <method name="get_collision_mask" qualifiers="const">
<return type="int">
</return>
<description>
+ Return the physics layers this area can scan for collisions.
+ </description>
+ </method>
+ <method name="set_collision_mask_bit">
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <argument index="1" name="value" type="bool">
+ </argument>
+ <description>
+ Set/clear individual bits on the collision mask. This makes selecting the areas scanned easier.
</description>
</method>
- <method name="add_collision_exception_with" >
+ <method name="get_collision_mask_bit" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <description>
+ Return an individual bit on the collision mask.
+ </description>
+ </method>
+ <method name="set_layer_mask_bit">
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <argument index="1" name="value" type="bool">
+ </argument>
+ <description>
+ Set/clear individual bits on the layer mask. This makes getting a body in/out of only one layer easier.
+ </description>
+ </method>
+ <method name="get_layer_mask_bit" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="bit" type="int">
+ </argument>
+ <description>
+ Return an individual bit on the collision mask.
+ </description>
+ </method>
+ <method name="set_one_way_collision_direction">
+ <argument index="0" name="dir" type="Vector2">
+ </argument>
+ <description>
+ Set a direction in which bodies can go through this one. If this value is different from (0,0), any movement within 90 degrees of this vector is considered a valid movement. Set this direction to (0,0) to disable one-way collisions.
+ </description>
+ </method>
+ <method name="get_one_way_collision_direction" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <description>
+ Return the direction used for one-way collision detection.
+ </description>
+ </method>
+ <method name="set_one_way_collision_max_depth">
+ <argument index="0" name="depth" type="float">
+ </argument>
+ <description>
+ Set how far a body can go through this one, when it allows one-way collisions (see [method set_one_way_collision_detection]).
+ </description>
+ </method>
+ <method name="get_one_way_collision_max_depth" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ Return how far a body can go through this one, when it allows one-way collisions.
+ </description>
+ </method>
+ <method name="add_collision_exception_with">
<argument index="0" name="body" type="PhysicsBody2D">
</argument>
<description>
+ Adds a body to the collision exception list. This list contains bodies that this body will not collide with.
</description>
</method>
- <method name="remove_collision_exception_with" >
+ <method name="remove_collision_exception_with">
<argument index="0" name="body" type="PhysicsBody2D">
</argument>
<description>
+ Removes a body from the collision exception list.
</description>
</method>
</methods>
@@ -20012,67 +23861,73 @@
<description>
</description>
<methods>
- <method name="get_total_gravity" qualifiers="const" >
+ <method name="get_total_gravity" qualifiers="const">
<return type="Vector3">
</return>
<description>
</description>
</method>
- <method name="get_total_density" qualifiers="const" >
+ <method name="get_total_linear_damp" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_total_angular_damp" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="get_inverse_mass" qualifiers="const" >
+ <method name="get_inverse_mass" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="get_inverse_inertia" qualifiers="const" >
+ <method name="get_inverse_inertia" qualifiers="const">
<return type="Vector3">
</return>
<description>
</description>
</method>
- <method name="set_linear_velocity" >
+ <method name="set_linear_velocity">
<argument index="0" name="velocity" type="Vector3">
</argument>
<description>
</description>
</method>
- <method name="get_linear_velocity" qualifiers="const" >
+ <method name="get_linear_velocity" qualifiers="const">
<return type="Vector3">
</return>
<description>
</description>
</method>
- <method name="set_angular_velocity" >
+ <method name="set_angular_velocity">
<argument index="0" name="velocity" type="Vector3">
</argument>
<description>
</description>
</method>
- <method name="get_angular_velocity" qualifiers="const" >
+ <method name="get_angular_velocity" qualifiers="const">
<return type="Vector3">
</return>
<description>
</description>
</method>
- <method name="set_transform" >
+ <method name="set_transform">
<argument index="0" name="transform" type="Transform">
</argument>
<description>
</description>
</method>
- <method name="get_transform" qualifiers="const" >
+ <method name="get_transform" qualifiers="const">
<return type="Transform">
</return>
<description>
</description>
</method>
- <method name="add_force" >
+ <method name="add_force">
<argument index="0" name="force" type="Vector3">
</argument>
<argument index="1" name="pos" type="Vector3">
@@ -20080,7 +23935,7 @@
<description>
</description>
</method>
- <method name="apply_impulse" >
+ <method name="apply_impulse">
<argument index="0" name="pos" type="Vector3">
</argument>
<argument index="1" name="j" type="Vector3">
@@ -20088,25 +23943,25 @@
<description>
</description>
</method>
- <method name="set_sleep_state" >
+ <method name="set_sleep_state">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_sleeping" qualifiers="const" >
+ <method name="is_sleeping" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="get_contact_count" qualifiers="const" >
+ <method name="get_contact_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_contact_local_pos" qualifiers="const" >
+ <method name="get_contact_local_pos" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="contact_idx" type="int">
@@ -20114,7 +23969,7 @@
<description>
</description>
</method>
- <method name="get_contact_local_normal" qualifiers="const" >
+ <method name="get_contact_local_normal" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="contact_idx" type="int">
@@ -20122,7 +23977,7 @@
<description>
</description>
</method>
- <method name="get_contact_local_shape" qualifiers="const" >
+ <method name="get_contact_local_shape" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="contact_idx" type="int">
@@ -20130,7 +23985,7 @@
<description>
</description>
</method>
- <method name="get_contact_collider" qualifiers="const" >
+ <method name="get_contact_collider" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="contact_idx" type="int">
@@ -20138,7 +23993,7 @@
<description>
</description>
</method>
- <method name="get_contact_collider_pos" qualifiers="const" >
+ <method name="get_contact_collider_pos" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="contact_idx" type="int">
@@ -20146,7 +24001,7 @@
<description>
</description>
</method>
- <method name="get_contact_collider_id" qualifiers="const" >
+ <method name="get_contact_collider_id" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="contact_idx" type="int">
@@ -20154,7 +24009,7 @@
<description>
</description>
</method>
- <method name="get_contact_collider_object" qualifiers="const" >
+ <method name="get_contact_collider_object" qualifiers="const">
<return type="Object">
</return>
<argument index="0" name="contact_idx" type="int">
@@ -20162,7 +24017,7 @@
<description>
</description>
</method>
- <method name="get_contact_collider_shape" qualifiers="const" >
+ <method name="get_contact_collider_shape" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="contact_idx" type="int">
@@ -20170,7 +24025,7 @@
<description>
</description>
</method>
- <method name="get_contact_collider_velocity_at_pos" qualifiers="const" >
+ <method name="get_contact_collider_velocity_at_pos" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="contact_idx" type="int">
@@ -20178,17 +24033,17 @@
<description>
</description>
</method>
- <method name="get_step" qualifiers="const" >
+ <method name="get_step" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="integrate_forces" >
+ <method name="integrate_forces">
<description>
</description>
</method>
- <method name="get_space_state" >
+ <method name="get_space_state">
<return type="PhysicsDirectSpaceState">
</return>
<description>
@@ -20214,7 +24069,7 @@
<description>
</description>
<methods>
- <method name="intersect_ray" >
+ <method name="intersect_ray">
<return type="Dictionary">
</return>
<argument index="0" name="from" type="Vector3">
@@ -20230,7 +24085,7 @@
<description>
</description>
</method>
- <method name="intersect_shape" >
+ <method name="intersect_shape">
<return type="Array">
</return>
<argument index="0" name="shape" type="PhysicsShapeQueryParameters">
@@ -20240,7 +24095,7 @@
<description>
</description>
</method>
- <method name="cast_motion" >
+ <method name="cast_motion">
<return type="Array">
</return>
<argument index="0" name="shape" type="PhysicsShapeQueryParameters">
@@ -20250,7 +24105,7 @@
<description>
</description>
</method>
- <method name="collide_shape" >
+ <method name="collide_shape">
<return type="Array">
</return>
<argument index="0" name="shape" type="PhysicsShapeQueryParameters">
@@ -20260,7 +24115,7 @@
<description>
</description>
</method>
- <method name="get_rest_info" >
+ <method name="get_rest_info">
<return type="Dictionary">
</return>
<argument index="0" name="shape" type="PhysicsShapeQueryParameters">
@@ -20290,7 +24145,7 @@
<description>
</description>
<methods>
- <method name="shape_create" >
+ <method name="shape_create">
<return type="RID">
</return>
<argument index="0" name="type" type="int">
@@ -20298,7 +24153,7 @@
<description>
</description>
</method>
- <method name="shape_set_data" >
+ <method name="shape_set_data">
<argument index="0" name="shape" type="RID">
</argument>
<argument index="1" name="data" type="var">
@@ -20306,7 +24161,7 @@
<description>
</description>
</method>
- <method name="shape_get_type" qualifiers="const" >
+ <method name="shape_get_type" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="shape" type="RID">
@@ -20314,19 +24169,19 @@
<description>
</description>
</method>
- <method name="shape_get_data" qualifiers="const" >
+ <method name="shape_get_data" qualifiers="const">
<argument index="0" name="shape" type="RID">
</argument>
<description>
</description>
</method>
- <method name="space_create" >
+ <method name="space_create">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="space_set_active" >
+ <method name="space_set_active">
<argument index="0" name="space" type="RID">
</argument>
<argument index="1" name="active" type="bool">
@@ -20334,7 +24189,7 @@
<description>
</description>
</method>
- <method name="space_is_active" qualifiers="const" >
+ <method name="space_is_active" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="space" type="RID">
@@ -20342,7 +24197,7 @@
<description>
</description>
</method>
- <method name="space_set_param" >
+ <method name="space_set_param">
<argument index="0" name="space" type="RID">
</argument>
<argument index="1" name="param" type="int">
@@ -20352,7 +24207,7 @@
<description>
</description>
</method>
- <method name="space_get_param" qualifiers="const" >
+ <method name="space_get_param" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="space" type="RID">
@@ -20362,7 +24217,7 @@
<description>
</description>
</method>
- <method name="space_get_direct_state" >
+ <method name="space_get_direct_state">
<return type="PhysicsDirectSpaceState">
</return>
<argument index="0" name="space" type="RID">
@@ -20370,13 +24225,13 @@
<description>
</description>
</method>
- <method name="area_create" >
+ <method name="area_create">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="area_set_space" >
+ <method name="area_set_space">
<argument index="0" name="area" type="RID">
</argument>
<argument index="1" name="space" type="RID">
@@ -20384,7 +24239,7 @@
<description>
</description>
</method>
- <method name="area_get_space" qualifiers="const" >
+ <method name="area_get_space" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="area" type="RID">
@@ -20392,7 +24247,7 @@
<description>
</description>
</method>
- <method name="area_set_space_override_mode" >
+ <method name="area_set_space_override_mode">
<argument index="0" name="area" type="RID">
</argument>
<argument index="1" name="mode" type="int">
@@ -20400,7 +24255,7 @@
<description>
</description>
</method>
- <method name="area_get_space_override_mode" qualifiers="const" >
+ <method name="area_get_space_override_mode" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="area" type="RID">
@@ -20408,7 +24263,7 @@
<description>
</description>
</method>
- <method name="area_add_shape" >
+ <method name="area_add_shape">
<argument index="0" name="area" type="RID">
</argument>
<argument index="1" name="shape" type="RID">
@@ -20418,7 +24273,7 @@
<description>
</description>
</method>
- <method name="area_set_shape" >
+ <method name="area_set_shape">
<argument index="0" name="area" type="RID">
</argument>
<argument index="1" name="shape_idx" type="int">
@@ -20428,7 +24283,7 @@
<description>
</description>
</method>
- <method name="area_set_shape_transform" >
+ <method name="area_set_shape_transform">
<argument index="0" name="area" type="RID">
</argument>
<argument index="1" name="shape_idx" type="int">
@@ -20438,7 +24293,7 @@
<description>
</description>
</method>
- <method name="area_get_shape_count" qualifiers="const" >
+ <method name="area_get_shape_count" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="area" type="RID">
@@ -20446,7 +24301,7 @@
<description>
</description>
</method>
- <method name="area_get_shape" qualifiers="const" >
+ <method name="area_get_shape" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="area" type="RID">
@@ -20456,7 +24311,7 @@
<description>
</description>
</method>
- <method name="area_get_shape_transform" qualifiers="const" >
+ <method name="area_get_shape_transform" qualifiers="const">
<return type="Transform">
</return>
<argument index="0" name="area" type="RID">
@@ -20466,7 +24321,7 @@
<description>
</description>
</method>
- <method name="area_remove_shape" >
+ <method name="area_remove_shape">
<argument index="0" name="area" type="RID">
</argument>
<argument index="1" name="shape_idx" type="int">
@@ -20474,13 +24329,13 @@
<description>
</description>
</method>
- <method name="area_clear_shapes" >
+ <method name="area_clear_shapes">
<argument index="0" name="area" type="RID">
</argument>
<description>
</description>
</method>
- <method name="area_set_param" >
+ <method name="area_set_param">
<argument index="0" name="area" type="RID">
</argument>
<argument index="1" name="param" type="int">
@@ -20490,7 +24345,7 @@
<description>
</description>
</method>
- <method name="area_set_transform" >
+ <method name="area_set_transform">
<argument index="0" name="area" type="RID">
</argument>
<argument index="1" name="transform" type="Transform">
@@ -20498,7 +24353,7 @@
<description>
</description>
</method>
- <method name="area_get_param" qualifiers="const" >
+ <method name="area_get_param" qualifiers="const">
<argument index="0" name="area" type="RID">
</argument>
<argument index="1" name="param" type="int">
@@ -20506,7 +24361,7 @@
<description>
</description>
</method>
- <method name="area_get_transform" qualifiers="const" >
+ <method name="area_get_transform" qualifiers="const">
<return type="Transform">
</return>
<argument index="0" name="area" type="RID">
@@ -20514,7 +24369,7 @@
<description>
</description>
</method>
- <method name="area_attach_object_instance_ID" >
+ <method name="area_attach_object_instance_ID">
<argument index="0" name="area" type="RID">
</argument>
<argument index="1" name="id" type="int">
@@ -20522,7 +24377,7 @@
<description>
</description>
</method>
- <method name="area_get_object_instance_ID" qualifiers="const" >
+ <method name="area_get_object_instance_ID" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="area" type="RID">
@@ -20530,17 +24385,17 @@
<description>
</description>
</method>
- <method name="area_set_monitor_callback" >
- <argument index="0" name="receiver" type="RID">
+ <method name="area_set_monitor_callback">
+ <argument index="0" name="area" type="RID">
</argument>
- <argument index="1" name="method" type="Object">
+ <argument index="1" name="receiver" type="Object">
</argument>
- <argument index="2" name="arg2" type="String">
+ <argument index="2" name="method" type="String">
</argument>
<description>
</description>
</method>
- <method name="area_set_ray_pickable" >
+ <method name="area_set_ray_pickable">
<argument index="0" name="area" type="RID">
</argument>
<argument index="1" name="enable" type="bool">
@@ -20548,7 +24403,7 @@
<description>
</description>
</method>
- <method name="area_is_ray_pickable" qualifiers="const" >
+ <method name="area_is_ray_pickable" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="area" type="RID">
@@ -20556,7 +24411,7 @@
<description>
</description>
</method>
- <method name="body_create" >
+ <method name="body_create">
<return type="RID">
</return>
<argument index="0" name="mode" type="int" default="2">
@@ -20566,7 +24421,7 @@
<description>
</description>
</method>
- <method name="body_set_space" >
+ <method name="body_set_space">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="space" type="RID">
@@ -20574,7 +24429,7 @@
<description>
</description>
</method>
- <method name="body_get_space" qualifiers="const" >
+ <method name="body_get_space" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="body" type="RID">
@@ -20582,7 +24437,7 @@
<description>
</description>
</method>
- <method name="body_set_mode" >
+ <method name="body_set_mode">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="mode" type="int">
@@ -20590,17 +24445,15 @@
<description>
</description>
</method>
- <method name="body_get_mode" qualifiers="const" >
+ <method name="body_get_mode" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="body" type="RID">
</argument>
- <argument index="1" name="arg1" type="int">
- </argument>
<description>
</description>
</method>
- <method name="body_add_shape" >
+ <method name="body_add_shape">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="shape" type="RID">
@@ -20610,7 +24463,7 @@
<description>
</description>
</method>
- <method name="body_set_shape" >
+ <method name="body_set_shape">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="shape_idx" type="int">
@@ -20620,7 +24473,7 @@
<description>
</description>
</method>
- <method name="body_set_shape_transform" >
+ <method name="body_set_shape_transform">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="shape_idx" type="int">
@@ -20630,7 +24483,7 @@
<description>
</description>
</method>
- <method name="body_get_shape_count" qualifiers="const" >
+ <method name="body_get_shape_count" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="body" type="RID">
@@ -20638,7 +24491,7 @@
<description>
</description>
</method>
- <method name="body_get_shape" qualifiers="const" >
+ <method name="body_get_shape" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="body" type="RID">
@@ -20648,7 +24501,7 @@
<description>
</description>
</method>
- <method name="body_get_shape_transform" qualifiers="const" >
+ <method name="body_get_shape_transform" qualifiers="const">
<return type="Transform">
</return>
<argument index="0" name="body" type="RID">
@@ -20658,7 +24511,7 @@
<description>
</description>
</method>
- <method name="body_remove_shape" >
+ <method name="body_remove_shape">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="shape_idx" type="int">
@@ -20666,13 +24519,13 @@
<description>
</description>
</method>
- <method name="body_clear_shapes" >
+ <method name="body_clear_shapes">
<argument index="0" name="body" type="RID">
</argument>
<description>
</description>
</method>
- <method name="body_attach_object_instance_ID" >
+ <method name="body_attach_object_instance_ID">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="id" type="int">
@@ -20680,7 +24533,7 @@
<description>
</description>
</method>
- <method name="body_get_object_instance_ID" qualifiers="const" >
+ <method name="body_get_object_instance_ID" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="body" type="RID">
@@ -20688,7 +24541,7 @@
<description>
</description>
</method>
- <method name="body_set_enable_continuous_collision_detection" >
+ <method name="body_set_enable_continuous_collision_detection">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="enable" type="bool">
@@ -20696,7 +24549,7 @@
<description>
</description>
</method>
- <method name="body_is_continuous_collision_detection_enabled" qualifiers="const" >
+ <method name="body_is_continuous_collision_detection_enabled" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="body" type="RID">
@@ -20704,7 +24557,7 @@
<description>
</description>
</method>
- <method name="body_set_param" >
+ <method name="body_set_param">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="param" type="int">
@@ -20714,7 +24567,7 @@
<description>
</description>
</method>
- <method name="body_get_param" qualifiers="const" >
+ <method name="body_get_param" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="body" type="RID">
@@ -20724,7 +24577,7 @@
<description>
</description>
</method>
- <method name="body_set_state" >
+ <method name="body_set_state">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="state" type="int">
@@ -20734,7 +24587,7 @@
<description>
</description>
</method>
- <method name="body_get_state" qualifiers="const" >
+ <method name="body_get_state" qualifiers="const">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="state" type="int">
@@ -20742,7 +24595,7 @@
<description>
</description>
</method>
- <method name="body_apply_impulse" >
+ <method name="body_apply_impulse">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="pos" type="Vector3">
@@ -20752,7 +24605,7 @@
<description>
</description>
</method>
- <method name="body_set_axis_velocity" >
+ <method name="body_set_axis_velocity">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="axis_velocity" type="Vector3">
@@ -20760,7 +24613,7 @@
<description>
</description>
</method>
- <method name="body_set_axis_lock" >
+ <method name="body_set_axis_lock">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="axis" type="int">
@@ -20768,7 +24621,7 @@
<description>
</description>
</method>
- <method name="body_get_axis_lock" qualifiers="const" >
+ <method name="body_get_axis_lock" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="body" type="RID">
@@ -20776,7 +24629,7 @@
<description>
</description>
</method>
- <method name="body_add_collision_exception" >
+ <method name="body_add_collision_exception">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="excepted_body" type="RID">
@@ -20784,7 +24637,7 @@
<description>
</description>
</method>
- <method name="body_remove_collision_exception" >
+ <method name="body_remove_collision_exception">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="excepted_body" type="RID">
@@ -20792,7 +24645,7 @@
<description>
</description>
</method>
- <method name="body_set_max_contacts_reported" >
+ <method name="body_set_max_contacts_reported">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="amount" type="int">
@@ -20800,7 +24653,7 @@
<description>
</description>
</method>
- <method name="body_get_max_contacts_reported" qualifiers="const" >
+ <method name="body_get_max_contacts_reported" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="body" type="RID">
@@ -20808,7 +24661,7 @@
<description>
</description>
</method>
- <method name="body_set_omit_force_integration" >
+ <method name="body_set_omit_force_integration">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="enable" type="bool">
@@ -20816,7 +24669,7 @@
<description>
</description>
</method>
- <method name="body_is_omitting_force_integration" qualifiers="const" >
+ <method name="body_is_omitting_force_integration" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="body" type="RID">
@@ -20824,7 +24677,7 @@
<description>
</description>
</method>
- <method name="body_set_force_integration_callback" >
+ <method name="body_set_force_integration_callback">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="receiver" type="Object">
@@ -20836,7 +24689,7 @@
<description>
</description>
</method>
- <method name="body_set_ray_pickable" >
+ <method name="body_set_ray_pickable">
<argument index="0" name="body" type="RID">
</argument>
<argument index="1" name="enable" type="bool">
@@ -20844,7 +24697,7 @@
<description>
</description>
</method>
- <method name="body_is_ray_pickable" qualifiers="const" >
+ <method name="body_is_ray_pickable" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="body" type="RID">
@@ -20852,7 +24705,7 @@
<description>
</description>
</method>
- <method name="joint_create_pin" >
+ <method name="joint_create_pin">
<return type="RID">
</return>
<argument index="0" name="body_A" type="RID">
@@ -20866,7 +24719,7 @@
<description>
</description>
</method>
- <method name="pin_joint_set_param" >
+ <method name="pin_joint_set_param">
<argument index="0" name="joint" type="RID">
</argument>
<argument index="1" name="param" type="int">
@@ -20876,7 +24729,7 @@
<description>
</description>
</method>
- <method name="pin_joint_get_param" qualifiers="const" >
+ <method name="pin_joint_get_param" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="joint" type="RID">
@@ -20886,7 +24739,7 @@
<description>
</description>
</method>
- <method name="pin_joint_set_local_A" >
+ <method name="pin_joint_set_local_A">
<argument index="0" name="joint" type="RID">
</argument>
<argument index="1" name="local_A" type="Vector3">
@@ -20894,7 +24747,7 @@
<description>
</description>
</method>
- <method name="pin_joint_get_local_A" qualifiers="const" >
+ <method name="pin_joint_get_local_A" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="joint" type="RID">
@@ -20902,7 +24755,7 @@
<description>
</description>
</method>
- <method name="pin_joint_set_local_B" >
+ <method name="pin_joint_set_local_B">
<argument index="0" name="joint" type="RID">
</argument>
<argument index="1" name="local_B" type="Vector3">
@@ -20910,7 +24763,7 @@
<description>
</description>
</method>
- <method name="pin_joint_get_local_B" qualifiers="const" >
+ <method name="pin_joint_get_local_B" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="joint" type="RID">
@@ -20918,7 +24771,7 @@
<description>
</description>
</method>
- <method name="joint_create_hinge" >
+ <method name="joint_create_hinge">
<return type="RID">
</return>
<argument index="0" name="body_A" type="RID">
@@ -20932,7 +24785,7 @@
<description>
</description>
</method>
- <method name="hinge_joint_set_param" >
+ <method name="hinge_joint_set_param">
<argument index="0" name="joint" type="RID">
</argument>
<argument index="1" name="param" type="int">
@@ -20942,7 +24795,7 @@
<description>
</description>
</method>
- <method name="hinge_joint_get_param" qualifiers="const" >
+ <method name="hinge_joint_get_param" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="joint" type="RID">
@@ -20952,7 +24805,7 @@
<description>
</description>
</method>
- <method name="hinge_joint_set_flag" >
+ <method name="hinge_joint_set_flag">
<argument index="0" name="joint" type="RID">
</argument>
<argument index="1" name="flag" type="int">
@@ -20962,7 +24815,7 @@
<description>
</description>
</method>
- <method name="hinge_joint_get_flag" qualifiers="const" >
+ <method name="hinge_joint_get_flag" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="joint" type="RID">
@@ -20972,7 +24825,7 @@
<description>
</description>
</method>
- <method name="joint_create_slider" >
+ <method name="joint_create_slider">
<return type="RID">
</return>
<argument index="0" name="body_A" type="RID">
@@ -20986,7 +24839,7 @@
<description>
</description>
</method>
- <method name="slider_joint_set_param" >
+ <method name="slider_joint_set_param">
<argument index="0" name="joint" type="RID">
</argument>
<argument index="1" name="param" type="int">
@@ -20996,7 +24849,7 @@
<description>
</description>
</method>
- <method name="slider_joint_get_param" qualifiers="const" >
+ <method name="slider_joint_get_param" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="joint" type="RID">
@@ -21006,7 +24859,7 @@
<description>
</description>
</method>
- <method name="joint_create_cone_twist" >
+ <method name="joint_create_cone_twist">
<return type="RID">
</return>
<argument index="0" name="body_A" type="RID">
@@ -21020,7 +24873,7 @@
<description>
</description>
</method>
- <method name="cone_twist_joint_set_param" >
+ <method name="cone_twist_joint_set_param">
<argument index="0" name="joint" type="RID">
</argument>
<argument index="1" name="param" type="int">
@@ -21030,7 +24883,7 @@
<description>
</description>
</method>
- <method name="cone_twist_joint_get_param" qualifiers="const" >
+ <method name="cone_twist_joint_get_param" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="joint" type="RID">
@@ -21040,7 +24893,7 @@
<description>
</description>
</method>
- <method name="joint_get_type" qualifiers="const" >
+ <method name="joint_get_type" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="joint" type="RID">
@@ -21048,7 +24901,7 @@
<description>
</description>
</method>
- <method name="joint_set_solver_priority" >
+ <method name="joint_set_solver_priority">
<argument index="0" name="joint" type="RID">
</argument>
<argument index="1" name="priority" type="int">
@@ -21056,7 +24909,7 @@
<description>
</description>
</method>
- <method name="joint_get_solver_priority" qualifiers="const" >
+ <method name="joint_get_solver_priority" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="joint" type="RID">
@@ -21064,7 +24917,7 @@
<description>
</description>
</method>
- <method name="joint_create_generic_6dof" >
+ <method name="joint_create_generic_6dof">
<return type="RID">
</return>
<argument index="0" name="body_A" type="RID">
@@ -21078,7 +24931,7 @@
<description>
</description>
</method>
- <method name="generic_6dof_joint_set_param" >
+ <method name="generic_6dof_joint_set_param">
<argument index="0" name="joint" type="RID">
</argument>
<argument index="1" name="axis" type="int">
@@ -21090,7 +24943,7 @@
<description>
</description>
</method>
- <method name="generic_6dof_joint_get_param" >
+ <method name="generic_6dof_joint_get_param">
<return type="float">
</return>
<argument index="0" name="joint" type="RID">
@@ -21102,7 +24955,7 @@
<description>
</description>
</method>
- <method name="generic_6dof_joint_set_flag" >
+ <method name="generic_6dof_joint_set_flag">
<argument index="0" name="joint" type="RID">
</argument>
<argument index="1" name="axis" type="int">
@@ -21114,7 +24967,7 @@
<description>
</description>
</method>
- <method name="generic_6dof_joint_get_flag" >
+ <method name="generic_6dof_joint_get_flag">
<return type="bool">
</return>
<argument index="0" name="joint" type="RID">
@@ -21126,22 +24979,22 @@
<description>
</description>
</method>
- <method name="free_rid" >
+ <method name="free_rid">
<argument index="0" name="rid" type="RID">
</argument>
<description>
</description>
</method>
- <method name="set_active" >
+ <method name="set_active">
<argument index="0" name="active" type="bool">
</argument>
<description>
</description>
</method>
- <method name="get_process_info" >
+ <method name="get_process_info">
<return type="int">
</return>
- <argument index="0" name="arg0" type="int">
+ <argument index="0" name="process_info" type="int">
</argument>
<description>
</description>
@@ -21298,17 +25151,30 @@
</constant>
<constant name="AREA_PARAM_GRAVITY_IS_POINT" value="2">
</constant>
- <constant name="AREA_PARAM_GRAVITY_POINT_ATTENUATION" value="3">
+ <constant name="AREA_PARAM_GRAVITY_DISTANCE_SCALE" value="3">
</constant>
- <constant name="AREA_PARAM_DENSITY" value="4">
+ <constant name="AREA_PARAM_GRAVITY_POINT_ATTENUATION" value="4">
</constant>
- <constant name="AREA_PARAM_PRIORITY" value="5">
+ <constant name="AREA_PARAM_LINEAR_DAMP" value="5">
</constant>
- <constant name="AREA_SPACE_OVERRIDE_COMBINE" value="1">
+ <constant name="AREA_PARAM_ANGULAR_DAMP" value="6">
+ </constant>
+ <constant name="AREA_PARAM_PRIORITY" value="7">
</constant>
<constant name="AREA_SPACE_OVERRIDE_DISABLED" value="0">
+ This area does not affect gravity/damp. These are generally areas that exist only to detect collisions, and objects entering or exiting them.
</constant>
- <constant name="AREA_SPACE_OVERRIDE_REPLACE" value="2">
+ <constant name="AREA_SPACE_OVERRIDE_COMBINE" value="1">
+ This area adds its gravity/damp values to whatever has been calculated so far. This way, many overlapping areas can combine their physics to make interesting effects.
+ </constant>
+ <constant name="AREA_SPACE_OVERRIDE_COMBINE_REPLACE" value="2">
+ This area adds its gravity/damp values to whatever has been calculated so far. Then stops taking into account the rest of the areas, even the default one.
+ </constant>
+ <constant name="AREA_SPACE_OVERRIDE_REPLACE" value="3">
+ This area replaces any gravity/damp, even the default one, and stops taking into account the rest of the areas.
+ </constant>
+ <constant name="AREA_SPACE_OVERRIDE_REPLACE_COMBINE" value="4">
+ This area replaces any gravity/damp calculated so far, but keeps calculating the rest of the areas, down to the default one.
</constant>
<constant name="BODY_MODE_STATIC" value="0">
</constant>
@@ -21324,7 +25190,13 @@
</constant>
<constant name="BODY_PARAM_MASS" value="2">
</constant>
- <constant name="BODY_PARAM_MAX" value="3">
+ <constant name="BODY_PARAM_GRAVITY_SCALE" value="3">
+ </constant>
+ <constant name="BODY_PARAM_ANGULAR_DAMP" value="5">
+ </constant>
+ <constant name="BODY_PARAM_LINEAR_DAMP" value="4">
+ </constant>
+ <constant name="BODY_PARAM_MAX" value="6">
</constant>
<constant name="BODY_STATE_TRANSFORM" value="0">
</constant>
@@ -21364,79 +25236,79 @@
<description>
</description>
<methods>
- <method name="set_shape" >
+ <method name="set_shape">
<argument index="0" name="shape" type="Shape">
</argument>
<description>
</description>
</method>
- <method name="set_shape_rid" >
+ <method name="set_shape_rid">
<argument index="0" name="shape" type="RID">
</argument>
<description>
</description>
</method>
- <method name="get_shape_rid" qualifiers="const" >
+ <method name="get_shape_rid" qualifiers="const">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="set_transform" >
+ <method name="set_transform">
<argument index="0" name="transform" type="Transform">
</argument>
<description>
</description>
</method>
- <method name="get_transform" qualifiers="const" >
+ <method name="get_transform" qualifiers="const">
<return type="Transform">
</return>
<description>
</description>
</method>
- <method name="set_margin" >
+ <method name="set_margin">
<argument index="0" name="margin" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_margin" qualifiers="const" >
+ <method name="get_margin" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_layer_mask" >
+ <method name="set_layer_mask">
<argument index="0" name="layer_mask" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_layer_mask" qualifiers="const" >
+ <method name="get_layer_mask" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_object_type_mask" >
+ <method name="set_object_type_mask">
<argument index="0" name="object_type_mask" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_object_type_mask" qualifiers="const" >
+ <method name="get_object_type_mask" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_exclude" >
+ <method name="set_exclude">
<argument index="0" name="exclude" type="Array">
</argument>
<description>
</description>
</method>
- <method name="get_exclude" qualifiers="const" >
+ <method name="get_exclude" qualifiers="const">
<return type="Array">
</return>
<description>
@@ -21453,13 +25325,13 @@
<description>
</description>
<methods>
- <method name="get_result_count" qualifiers="const" >
+ <method name="get_result_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_result_rid" qualifiers="const" >
+ <method name="get_result_rid" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="idx" type="int">
@@ -21467,7 +25339,7 @@
<description>
</description>
</method>
- <method name="get_result_object_id" qualifiers="const" >
+ <method name="get_result_object_id" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="idx" type="int">
@@ -21475,7 +25347,7 @@
<description>
</description>
</method>
- <method name="get_result_object" qualifiers="const" >
+ <method name="get_result_object" qualifiers="const">
<return type="Object">
</return>
<argument index="0" name="idx" type="int">
@@ -21483,7 +25355,7 @@
<description>
</description>
</method>
- <method name="get_result_object_shape" qualifiers="const" >
+ <method name="get_result_object_shape" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="idx" type="int">
@@ -21501,7 +25373,7 @@
<description>
</description>
<methods>
- <method name="set_param" >
+ <method name="set_param">
<argument index="0" name="param" type="int">
</argument>
<argument index="1" name="value" type="float">
@@ -21509,7 +25381,7 @@
<description>
</description>
</method>
- <method name="get_param" qualifiers="const" >
+ <method name="get_param" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="param" type="int">
@@ -21535,6 +25407,18 @@
Pin Joint for 2D Rigid Bodies. It pins 2 bodies (rigid or static) together, or a single body to a fixed position in space.
</description>
<methods>
+ <method name="set_softness">
+ <argument index="0" name="softness" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_softness" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
</constants>
@@ -21547,14 +25431,14 @@
Plane represents a normalized plane equation. Basically, "normal" is the normal of the plane (a,b,c normalized), and "d" is the distance from the origin to the plane (in the direction of "normal"). "Over" or "Above" the plane is considered the side of the plane towards where the normal is pointing.
</description>
<methods>
- <method name="center" >
+ <method name="center">
<return type="Vector3">
</return>
<description>
Returns the center of the plane.
</description>
</method>
- <method name="distance_to" >
+ <method name="distance_to">
<return type="float">
</return>
<argument index="0" name="point" type="Vector3">
@@ -21563,14 +25447,14 @@
Returns the shortest distance from the plane to the position "point".
</description>
</method>
- <method name="get_any_point" >
+ <method name="get_any_point">
<return type="Vector3">
</return>
<description>
Returns a point on the plane.
</description>
</method>
- <method name="has_point" >
+ <method name="has_point">
<return type="bool">
</return>
<argument index="0" name="point" type="Vector3">
@@ -21581,7 +25465,7 @@
Returns true if "point" is inside the plane (by a very minimum treshold).
</description>
</method>
- <method name="intersect_3" >
+ <method name="intersect_3">
<return type="Vector3">
</return>
<argument index="0" name="b" type="Plane">
@@ -21592,7 +25476,7 @@
Returns the intersection point of the three planes "b", "c" and this plane. If no intersection is found null is returned.
</description>
</method>
- <method name="intersects_ray" >
+ <method name="intersects_ray">
<return type="Vector3">
</return>
<argument index="0" name="from" type="Vector3">
@@ -21603,7 +25487,7 @@
Returns the intersection point of a ray consisting of the position "from" and the direction normal "dir" with this plane. If no intersection is found null is returned.
</description>
</method>
- <method name="intersects_segment" >
+ <method name="intersects_segment">
<return type="Vector3">
</return>
<argument index="0" name="begin" type="Vector3">
@@ -21614,7 +25498,7 @@
Returns the intersection point of a segment from position "begin" to position "end" with this plane. If no intersection is found null is returned.
</description>
</method>
- <method name="is_point_over" >
+ <method name="is_point_over">
<return type="bool">
</return>
<argument index="0" name="point" type="Vector3">
@@ -21623,14 +25507,14 @@
Returns true if "point" is located above the plane.
</description>
</method>
- <method name="normalized" >
+ <method name="normalized">
<return type="Plane">
</return>
<description>
Returns a copy of the plane, normalized.
</description>
</method>
- <method name="project" >
+ <method name="project">
<return type="Vector3">
</return>
<argument index="0" name="point" type="Vector3">
@@ -21639,7 +25523,9 @@
Returns the orthogonal projection of point "p" into a point in the plane.
</description>
</method>
- <method name="Plane" >
+ <method name="Plane">
+ <return type="Plane">
+ </return>
<argument index="0" name="a" type="float">
</argument>
<argument index="1" name="b" type="float">
@@ -21652,7 +25538,9 @@
Creates a plane from the three parameters "a", "b", "c" and "d".
</description>
</method>
- <method name="Plane" >
+ <method name="Plane">
+ <return type="Plane">
+ </return>
<argument index="0" name="v1" type="Vector3">
</argument>
<argument index="1" name="v2" type="Vector3">
@@ -21663,7 +25551,9 @@
Creates a plane from three points.
</description>
</method>
- <method name="Plane" >
+ <method name="Plane">
+ <return type="Plane">
+ </return>
<argument index="0" name="normal" type="Vector3">
</argument>
<argument index="1" name="d" type="float">
@@ -21694,13 +25584,13 @@
<description>
</description>
<methods>
- <method name="set_plane" >
+ <method name="set_plane">
<argument index="0" name="plane" type="Plane">
</argument>
<description>
</description>
</method>
- <method name="get_plane" qualifiers="const" >
+ <method name="get_plane" qualifiers="const">
<return type="Plane">
</return>
<description>
@@ -21716,133 +25606,121 @@
<description>
</description>
<methods>
- <method name="set_polygon" >
+ <method name="set_polygon">
<argument index="0" name="polygon" type="Vector2Array">
</argument>
<description>
</description>
</method>
- <method name="get_polygon" qualifiers="const" >
+ <method name="get_polygon" qualifiers="const">
<return type="Vector2Array">
</return>
<description>
</description>
</method>
- <method name="set_uv" >
+ <method name="set_uv">
<argument index="0" name="uv" type="Vector2Array">
</argument>
<description>
</description>
</method>
- <method name="get_uv" qualifiers="const" >
+ <method name="get_uv" qualifiers="const">
<return type="Vector2Array">
</return>
<description>
</description>
</method>
- <method name="set_color" >
+ <method name="set_color">
<argument index="0" name="color" type="Color">
</argument>
<description>
</description>
</method>
- <method name="get_color" qualifiers="const" >
+ <method name="get_color" qualifiers="const">
<return type="Color">
</return>
<description>
</description>
</method>
- <method name="set_texture" >
+ <method name="set_texture">
<argument index="0" name="texture" type="Object">
</argument>
<description>
</description>
</method>
- <method name="get_texture" qualifiers="const" >
+ <method name="get_texture" qualifiers="const">
<return type="Object">
</return>
<description>
</description>
</method>
- <method name="set_texture_offset" >
+ <method name="set_texture_offset">
<argument index="0" name="texture_offset" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_texture_offset" qualifiers="const" >
+ <method name="get_texture_offset" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="set_texture_rotation" >
+ <method name="set_texture_rotation">
<argument index="0" name="texture_rotation" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_texture_rotation" qualifiers="const" >
+ <method name="get_texture_rotation" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_texture_scale" >
+ <method name="set_texture_scale">
<argument index="0" name="texture_scale" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_texture_scale" qualifiers="const" >
+ <method name="get_texture_scale" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="set_texture_repeat" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_texture_repeat" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_invert" >
+ <method name="set_invert">
<argument index="0" name="invert" type="bool">
</argument>
<description>
</description>
</method>
- <method name="get_invert" qualifiers="const" >
+ <method name="get_invert" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_invert_border" >
+ <method name="set_invert_border">
<argument index="0" name="invert_border" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_invert_border" qualifiers="const" >
+ <method name="get_invert_border" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_offset" >
+ <method name="set_offset">
<argument index="0" name="offset" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_offset" qualifiers="const" >
+ <method name="get_offset" qualifiers="const">
<return type="Vector2">
</return>
<description>
@@ -21858,7 +25736,7 @@
<description>
</description>
<methods>
- <method name="setup" >
+ <method name="setup">
<argument index="0" name="points" type="Vector2Array">
</argument>
<argument index="1" name="connections" type="IntArray">
@@ -21866,7 +25744,7 @@
<description>
</description>
</method>
- <method name="find_path" >
+ <method name="find_path">
<return type="Vector2Array">
</return>
<argument index="0" name="from" type="Vector2">
@@ -21876,7 +25754,7 @@
<description>
</description>
</method>
- <method name="get_intersections" qualifiers="const" >
+ <method name="get_intersections" qualifiers="const">
<return type="Vector2Array">
</return>
<argument index="0" name="from" type="Vector2">
@@ -21886,7 +25764,7 @@
<description>
</description>
</method>
- <method name="get_closest_point" qualifiers="const" >
+ <method name="get_closest_point" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="point" type="Vector2">
@@ -21894,7 +25772,7 @@
<description>
</description>
</method>
- <method name="is_point_inside" qualifiers="const" >
+ <method name="is_point_inside" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="point" type="Vector2">
@@ -21902,7 +25780,7 @@
<description>
</description>
</method>
- <method name="set_point_penalty" >
+ <method name="set_point_penalty">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="penalty" type="float">
@@ -21910,7 +25788,7 @@
<description>
</description>
</method>
- <method name="get_point_penalty" qualifiers="const" >
+ <method name="get_point_penalty" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="idx" type="int">
@@ -21918,7 +25796,7 @@
<description>
</description>
</method>
- <method name="get_bounds" qualifiers="const" >
+ <method name="get_bounds" qualifiers="const">
<return type="Rect2">
</return>
<description>
@@ -21936,38 +25814,38 @@
PopUp is a base [Control] used to show dialogs and popups. It's a subwindow and modal by default (see [Control]) and has helpers for custom popup behavior.
</description>
<methods>
- <method name="popup_centered" >
+ <method name="popup_centered">
<argument index="0" name="size" type="Vector2" default="Vector2(0,0)">
</argument>
<description>
Popup (show the control in modal form) in the center of the screen, at the curent size, or at a size determined by "size".
</description>
</method>
- <method name="popup_centered_ratio" >
+ <method name="popup_centered_ratio">
<argument index="0" name="ratio" type="float" default="0.75">
</argument>
<description>
Popup (show the control in modal form) in the center of the screen, scalled at a ratio of size of the screen.
</description>
</method>
- <method name="popup_centered_minsize" >
+ <method name="popup_centered_minsize">
<argument index="0" name="minsize" type="Vector2" default="Vector2(0,0)">
</argument>
<description>
</description>
</method>
- <method name="popup" >
+ <method name="popup">
<description>
Popup (show the control in modal form).
</description>
</method>
- <method name="set_exclusive" >
+ <method name="set_exclusive">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_exclusive" qualifiers="const" >
+ <method name="is_exclusive" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -21994,7 +25872,7 @@
</class>
<class name="PopupDialog" inherits="Popup" category="Core">
<brief_description>
- Base class for Popup Dialogs
+ Base class for Popup Dialogs.
</brief_description>
<description>
</description>
@@ -22011,7 +25889,7 @@
PopupMenu is the typical Control that displays a list of options. They are popular in toolbars or context menus.
</description>
<methods>
- <method name="add_icon_item" >
+ <method name="add_icon_item">
<argument index="0" name="texture" type="Object">
</argument>
<argument index="1" name="label" type="String">
@@ -22021,10 +25899,10 @@
<argument index="3" name="accel" type="int" default="0">
</argument>
<description>
- Add a new item with text "label" and icon "texture. An id can optonally be provided, as well as an accelerator. If no id is provided, one will be created from the index.
+ Add a new item with text "label" and icon "texture". An id can optonally be provided, as well as an accelerator. If no id is provided, one will be created from the index.
</description>
</method>
- <method name="add_item" >
+ <method name="add_item">
<argument index="0" name="label" type="String">
</argument>
<argument index="1" name="id" type="int" default="-1">
@@ -22035,7 +25913,7 @@
Add a new item with text "label". An id can optonally be provided, as well as an accelerator. If no id is provided, one will be created from the index.
</description>
</method>
- <method name="add_icon_check_item" >
+ <method name="add_icon_check_item">
<argument index="0" name="texture" type="Object">
</argument>
<argument index="1" name="label" type="String">
@@ -22045,10 +25923,10 @@
<argument index="3" name="accel" type="int" default="0">
</argument>
<description>
- Add a new checkable item with text "label" and icon "texture. An id can optonally be provided, as well as an accelerator. If no id is provided, one will be created from the index. Note that checkable items just display a checkmark, but don"apos;t have any built-in checking behavior and must be checked/unchecked manually.
+ Add a new checkable item with text "label" and icon "texture". An id can optonally be provided, as well as an accelerator. If no id is provided, one will be created from the index. Note that checkable items just display a checkmark, but don't have any built-in checking behavior and must be checked/unchecked manually.
</description>
</method>
- <method name="add_check_item" >
+ <method name="add_check_item">
<argument index="0" name="label" type="String">
</argument>
<argument index="1" name="id" type="int" default="-1">
@@ -22056,10 +25934,10 @@
<argument index="2" name="accel" type="int" default="0">
</argument>
<description>
- Add a new checkable item with text "label". An id can optonally be provided, as well as an accelerator. If no id is provided, one will be created from the index. Note that checkable items just display a checkmark, but don"apos;t have any built-in checking behavior and must be checked/unchecked manually.
+ Add a new checkable item with text "label". An id can optonally be provided, as well as an accelerator. If no id is provided, one will be created from the index. Note that checkable items just display a checkmark, but don't have any built-in checking behavior and must be checked/unchecked manually.
</description>
</method>
- <method name="add_submenu_item" >
+ <method name="add_submenu_item">
<argument index="0" name="label" type="String">
</argument>
<argument index="1" name="submenu" type="String">
@@ -22069,7 +25947,7 @@
<description>
</description>
</method>
- <method name="set_item_text" >
+ <method name="set_item_text">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="text" type="String">
@@ -22078,7 +25956,7 @@
Set the text of the item at index "idx".
</description>
</method>
- <method name="set_item_icon" >
+ <method name="set_item_icon">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="icon" type="Object">
@@ -22087,16 +25965,16 @@
Set the icon of the item at index "idx".
</description>
</method>
- <method name="set_item_accelerator" >
+ <method name="set_item_accelerator">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="accel" type="int">
</argument>
<description>
- Set the accelerator of the item at index "idx". Accelerators are special combinations of keys that activate the item, no matter which control is fucused.
+ Set the accelerator of the item at index "idx". Accelerators are special combinations of keys that activate the item, no matter which control is focused.
</description>
</method>
- <method name="set_item_metadata" >
+ <method name="set_item_metadata">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="metadata" type="var">
@@ -22104,16 +25982,16 @@
<description>
</description>
</method>
- <method name="set_item_checked" >
+ <method name="set_item_checked">
<argument index="0" name="idx" type="int">
</argument>
- <argument index="1" name="arg1" type="bool">
+ <argument index="1" name="checked" type="bool">
</argument>
<description>
Set the checkstate status of the item at index "idx".
</description>
</method>
- <method name="set_item_disabled" >
+ <method name="set_item_disabled">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="disabled" type="bool">
@@ -22121,7 +25999,7 @@
<description>
</description>
</method>
- <method name="set_item_submenu" >
+ <method name="set_item_submenu">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="submenu" type="String">
@@ -22129,7 +26007,7 @@
<description>
</description>
</method>
- <method name="set_item_as_separator" >
+ <method name="set_item_as_separator">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="enable" type="bool">
@@ -22137,7 +26015,7 @@
<description>
</description>
</method>
- <method name="set_item_as_checkable" >
+ <method name="set_item_as_checkable">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="enable" type="bool">
@@ -22145,7 +26023,7 @@
<description>
</description>
</method>
- <method name="set_item_ID" >
+ <method name="set_item_ID">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="id" type="int">
@@ -22154,7 +26032,7 @@
Set the id of the item at index "idx".
</description>
</method>
- <method name="get_item_text" qualifiers="const" >
+ <method name="get_item_text" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="idx" type="int">
@@ -22163,7 +26041,7 @@
Return the text of the item at index "idx".
</description>
</method>
- <method name="get_item_icon" qualifiers="const" >
+ <method name="get_item_icon" qualifiers="const">
<return type="Object">
</return>
<argument index="0" name="idx" type="int">
@@ -22172,22 +26050,22 @@
Return the icon of the item at index "idx".
</description>
</method>
- <method name="get_item_metadata" qualifiers="const" >
+ <method name="get_item_metadata" qualifiers="const">
<argument index="0" name="idx" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_item_accelerator" qualifiers="const" >
+ <method name="get_item_accelerator" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="idx" type="int">
</argument>
<description>
- Return the accelerator of the item at index "idx". Accelerators are special combinations of keys that activate the item, no matter which control is fucused.
+ Return the accelerator of the item at index "idx". Accelerators are special combinations of keys that activate the item, no matter which control is focused.
</description>
</method>
- <method name="get_item_submenu" qualifiers="const" >
+ <method name="get_item_submenu" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="idx" type="int">
@@ -22195,7 +26073,7 @@
<description>
</description>
</method>
- <method name="is_item_separator" qualifiers="const" >
+ <method name="is_item_separator" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="idx" type="int">
@@ -22203,7 +26081,7 @@
<description>
</description>
</method>
- <method name="is_item_checkable" qualifiers="const" >
+ <method name="is_item_checkable" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="idx" type="int">
@@ -22211,7 +26089,7 @@
<description>
</description>
</method>
- <method name="is_item_checked" qualifiers="const" >
+ <method name="is_item_checked" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="idx" type="int">
@@ -22220,7 +26098,7 @@
Return the checkstate status of the item at index "idx".
</description>
</method>
- <method name="is_item_disabled" qualifiers="const" >
+ <method name="is_item_disabled" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="idx" type="int">
@@ -22228,7 +26106,7 @@
<description>
</description>
</method>
- <method name="get_item_ID" qualifiers="const" >
+ <method name="get_item_ID" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="idx" type="int">
@@ -22237,7 +26115,7 @@
Return the id of the item at index "idx".
</description>
</method>
- <method name="get_item_index" qualifiers="const" >
+ <method name="get_item_index" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="id" type="int">
@@ -22246,25 +26124,25 @@
Find and return the index of the item containing a given id.
</description>
</method>
- <method name="get_item_count" qualifiers="const" >
+ <method name="get_item_count" qualifiers="const">
<return type="int">
</return>
<description>
Return the amount of items.
</description>
</method>
- <method name="add_separator" >
+ <method name="add_separator">
<description>
Add a separator between items. Separators also occupy an index.
</description>
</method>
- <method name="remove_item" >
+ <method name="remove_item">
<argument index="0" name="idx" type="int">
</argument>
<description>
</description>
</method>
- <method name="clear" >
+ <method name="clear">
<description>
Clear the popup menu.
</description>
@@ -22332,74 +26210,73 @@
Portals provide virtual openings to rooms.
</brief_description>
<description>
- Portals provide virtual openings to [RoomInstance] nodes, so cameras can look at them from the outside. Note that portals are a visibility optimization technique, and are in no way related to the game of the same name (as in, they are not used for teleportation). For more information on how rooms and portals work, see [RoomInstance]. Portals are represented as 2D convex polygon shapes (in the X,Y local plane), and are placed on the surface of the areas occupied by a [RoomInstance], to indicate that the room can be accessed or looked-at through them. If two rooms are next to each other, and two similar portals in each of them share the same world position (and are parallel and opposed to each other), they will automatically "connect" and form "doors" (for example, the portals that connect a kitchen to a living room are placed in the door they share). Portals must always have a [RoomInstance] node as a parent, grandparent or far parent, or else they will not be
- active.
+ Portals provide virtual openings to [RoomInstance] nodes, so cameras can look at them from the outside. Note that portals are a visibility optimization technique, and are in no way related to the game of the same name (as in, they are not used for teleportation). For more information on how rooms and portals work, see [RoomInstance]. Portals are represented as 2D convex polygon shapes (in the X,Y local plane), and are placed on the surface of the areas occupied by a [RoomInstance], to indicate that the room can be accessed or looked-at through them. If two rooms are next to each other, and two similar portals in each of them share the same world position (and are parallel and opposed to each other), they will automatically "connect" and form "doors" (for example, the portals that connect a kitchen to a living room are placed in the door they share). Portals must always have a [RoomInstance] node as a parent, grandparent or far parent, or else they will not be active.
</description>
<methods>
- <method name="set_shape" >
+ <method name="set_shape">
<argument index="0" name="points" type="Vector2Array">
</argument>
<description>
- Set the portal shape. The shape is an array of [Point2] points, representing a convex polygon in the X,Y plane.
+ Set the portal shape. The shape is an array of [Point2] points, representing a convex polygon in the X,Y plane.
</description>
</method>
- <method name="get_shape" qualifiers="const" >
+ <method name="get_shape" qualifiers="const">
<return type="Vector2Array">
</return>
<description>
- Return the portal shape. The shape is an array of [Point2] points, representing a convex polygon in the X,Y plane.
+ Return the portal shape. The shape is an array of [Point2] points, representing a convex polygon in the X,Y plane.
</description>
</method>
- <method name="set_enabled" >
+ <method name="set_enabled">
<argument index="0" name="enable" type="bool">
</argument>
<description>
Enable the portal (it is enabled by defaul though), disabling it will cause the parent [RoomInstance] to not be visible any longer when looking through the portal.
</description>
</method>
- <method name="is_enabled" qualifiers="const" >
+ <method name="is_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
Return wether the portal is active. When disabled it causes the parent [RoomInstance] to not be visible any longer when looking through the portal.
</description>
</method>
- <method name="set_disable_distance" >
+ <method name="set_disable_distance">
<argument index="0" name="distance" type="float">
</argument>
<description>
Set the distance threshold for disabling the portal. Every time that the portal goes beyond "distance", it disables itself, becoming the opaque color (see [method set_disabled_color]).
</description>
</method>
- <method name="get_disable_distance" qualifiers="const" >
+ <method name="get_disable_distance" qualifiers="const">
<return type="float">
</return>
<description>
Return the distance threshold for disabling the portal. Every time that the portal goes beyond "distance", it disables itself, becoming the opaque color (see [method set_disabled_color]).
</description>
</method>
- <method name="set_disabled_color" >
+ <method name="set_disabled_color">
<argument index="0" name="color" type="Color">
</argument>
<description>
When the portal goes beyond the disable distance (see [method set_disable_distance]), it becomes opaque and displayed with color "color".
</description>
</method>
- <method name="get_disabled_color" qualifiers="const" >
+ <method name="get_disabled_color" qualifiers="const">
<return type="Color">
</return>
<description>
Return the color for when the portal goes beyond the disable distance (see [method set_disable_distance]) and becomes disabled.
</description>
</method>
- <method name="set_connect_range" >
+ <method name="set_connect_range">
<argument index="0" name="range" type="float">
</argument>
<description>
Set the range for auto-connecting two portals from different rooms sharing the same space.
</description>
</method>
- <method name="get_connect_range" qualifiers="const" >
+ <method name="get_connect_range" qualifiers="const">
<return type="float">
</return>
<description>
@@ -22436,19 +26313,19 @@
</class>
<class name="ProgressBar" inherits="Range" category="Core">
<brief_description>
- General purpose progres bar.
+ General purpose progress bar.
</brief_description>
<description>
- General purpose progres bar. Shows fill percentage from right to left.
+ General purpose progress bar. Shows fill percentage from right to left.
</description>
<methods>
- <method name="set_percent_visible" >
+ <method name="set_percent_visible">
<argument index="0" name="visible" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_percent_visible" qualifiers="const" >
+ <method name="is_percent_visible" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -22478,13 +26355,13 @@
General purpose proximity-detection node.
</description>
<methods>
- <method name="set_group_name" >
+ <method name="set_group_name">
<argument index="0" name="name" type="String">
</argument>
<description>
</description>
</method>
- <method name="broadcast" >
+ <method name="broadcast">
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="parameters" type="var">
@@ -22492,19 +26369,19 @@
<description>
</description>
</method>
- <method name="set_dispatch_mode" >
+ <method name="set_dispatch_mode">
<argument index="0" name="mode" type="int">
</argument>
<description>
</description>
</method>
- <method name="set_grid_radius" >
+ <method name="set_grid_radius">
<argument index="0" name="radius" type="Vector3">
</argument>
<description>
</description>
</method>
- <method name="get_grid_radius" qualifiers="const" >
+ <method name="get_grid_radius" qualifiers="const">
<return type="Vector3">
</return>
<description>
@@ -22530,49 +26407,49 @@
<description>
</description>
<methods>
- <method name="set_axis" >
+ <method name="set_axis">
<argument index="0" name="axis" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_axis" qualifiers="const" >
+ <method name="get_axis" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_size" >
+ <method name="set_size">
<argument index="0" name="size" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_size" qualifiers="const" >
+ <method name="get_size" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="set_centered" >
+ <method name="set_centered">
<argument index="0" name="centered" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_centered" qualifiers="const" >
+ <method name="is_centered" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_offset" >
+ <method name="set_offset">
<argument index="0" name="offset" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_offset" qualifiers="const" >
+ <method name="get_offset" qualifiers="const">
<return type="Vector2">
</return>
<description>
@@ -22587,10 +26464,10 @@
Quaternion.
</brief_description>
<description>
- Quaternion is a 4 dimensional vector that is used to represet a rotation. It mainly exists to perform SLERP (spherical-linear interpolation) between to rotations obtained by a Matrix3 cheaply. Adding quaternions also cheaply adds the rotations, however quaternions need to be often normalized, or else they suffer from precision issues.
+ Quaternion is a 4 dimensional vector that is used to represent a rotation. It mainly exists to perform SLERP (spherical-linear interpolation) between to rotations obtained by a Matrix3 cheaply. Adding quaternions also cheaply adds the rotations, however quaternions need to be often normalized, or else they suffer from precision issues.
</description>
<methods>
- <method name="cubic_slerp" >
+ <method name="cubic_slerp">
<return type="Quat">
</return>
<argument index="0" name="b" type="Quat">
@@ -22604,7 +26481,7 @@
<description>
</description>
</method>
- <method name="dot" >
+ <method name="dot">
<return type="float">
</return>
<argument index="0" name="b" type="Quat">
@@ -22613,35 +26490,35 @@
Returns the dot product between two quaternions.
</description>
</method>
- <method name="inverse" >
+ <method name="inverse">
<return type="Quat">
</return>
<description>
Returns the inverse of the quaternion (applies to the inverse rotatio too).
</description>
</method>
- <method name="length" >
+ <method name="length">
<return type="float">
</return>
<description>
Returns the length of the quaternion.
</description>
</method>
- <method name="length_squared" >
+ <method name="length_squared">
<return type="float">
</return>
<description>
- Returns the length of the quaternion, minus the square root.
+ Returns the length of the quaternion, squared.
</description>
</method>
- <method name="normalized" >
+ <method name="normalized">
<return type="Quat">
</return>
<description>
Returns a copy of the quaternion, normalized to unit length.
</description>
</method>
- <method name="slerp" >
+ <method name="slerp">
<return type="Quat">
</return>
<argument index="0" name="b" type="Quat">
@@ -22652,7 +26529,7 @@
Perform a spherical-linear interpolation with another quaternion.
</description>
</method>
- <method name="slerpni" >
+ <method name="slerpni">
<return type="Quat">
</return>
<argument index="0" name="b" type="Quat">
@@ -22662,7 +26539,17 @@
<description>
</description>
</method>
- <method name="Quat" >
+ <method name="xform">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="v" type="Vector3">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="Quat">
+ <return type="Quat">
+ </return>
<argument index="0" name="x" type="float">
</argument>
<argument index="1" name="y" type="float">
@@ -22674,7 +26561,19 @@
<description>
</description>
</method>
- <method name="Quat" >
+ <method name="Quat">
+ <return type="Quat">
+ </return>
+ <argument index="0" name="axis" type="Vector3">
+ </argument>
+ <argument index="1" name="angle" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="Quat">
+ <return type="Quat">
+ </return>
<argument index="0" name="from" type="Matrix3">
</argument>
<description>
@@ -22700,13 +26599,15 @@
<description>
</description>
<methods>
- <method name="get_id" >
+ <method name="get_id">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="RID" >
+ <method name="RID">
+ <return type="RID">
+ </return>
<argument index="0" name="from" type="Object">
</argument>
<description>
@@ -22721,134 +26622,134 @@
Abstract base class for range-based controls.
</brief_description>
<description>
- Range is a base class for [Control] nodes that change a floating point [i]value[/i] between a need a [i]minimum[/i], [i]maximum[/i], using [i]step[/i] and [i]page[/i], for example a [ScrollBar].
+ Range is a base class for [Control] nodes that change a floating point [i]value[/i] between a [i]minimum[/i] and a [i]maximum[/i], using [i]step[/i] and [i]page[/i], for example a [ScrollBar].
</description>
<methods>
- <method name="get_val" qualifiers="const" >
+ <method name="get_val" qualifiers="const">
<return type="float">
</return>
<description>
Return the current value.
</description>
</method>
- <method name="get_value" qualifiers="const" >
+ <method name="get_value" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="get_min" qualifiers="const" >
+ <method name="get_min" qualifiers="const">
<return type="float">
</return>
<description>
Return the minimum value.
</description>
</method>
- <method name="get_max" qualifiers="const" >
+ <method name="get_max" qualifiers="const">
<return type="float">
</return>
<description>
Return the maximum value.
</description>
</method>
- <method name="get_step" qualifiers="const" >
+ <method name="get_step" qualifiers="const">
<return type="float">
</return>
<description>
Return the stepping, if step is 0, stepping is disabled.
</description>
</method>
- <method name="get_page" qualifiers="const" >
+ <method name="get_page" qualifiers="const">
<return type="float">
</return>
<description>
Return the page size, if page is 0, paging is disabled.
</description>
</method>
- <method name="get_unit_value" qualifiers="const" >
+ <method name="get_unit_value" qualifiers="const">
<return type="float">
</return>
<description>
Return value mapped to 0 to 1 (unit) range.
</description>
</method>
- <method name="get_rounded_values" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_val" >
+ <method name="set_val">
<argument index="0" name="value" type="float">
</argument>
<description>
</description>
</method>
- <method name="set_value" >
+ <method name="set_value">
<argument index="0" name="value" type="float">
</argument>
<description>
</description>
</method>
- <method name="set_min" >
+ <method name="set_min">
<argument index="0" name="minimum" type="float">
</argument>
<description>
- Set minimum value, clamped range value to it if it"apos;s less.
+ Set minimum value, clamped range value to it if it's less.
</description>
</method>
- <method name="set_max" >
+ <method name="set_max">
<argument index="0" name="maximum" type="float">
</argument>
<description>
</description>
</method>
- <method name="set_step" >
+ <method name="set_step">
<argument index="0" name="step" type="float">
</argument>
<description>
Set step value. If step is 0, stepping will be disabled.
</description>
</method>
- <method name="set_page" >
+ <method name="set_page">
<argument index="0" name="pagesize" type="float">
</argument>
<description>
Set page size. Page is mainly used for scrollbars or anything that controls text scrolling.
</description>
</method>
- <method name="set_unit_value" >
+ <method name="set_unit_value">
<argument index="0" name="value" type="float">
</argument>
<description>
Set value mapped to 0 to 1 (unit) range, it will then be converted to the actual value within min and max.
</description>
</method>
- <method name="set_rounded_values" >
- <argument index="0" name="arg0" type="bool">
+ <method name="set_rounded_values">
+ <argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="set_exp_unit_value" >
+ <method name="is_rounded_values" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_exp_unit_value">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_unit_value_exp" qualifiers="const" >
+ <method name="is_unit_value_exp" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="share" >
+ <method name="share">
<argument index="0" name="with" type="Object">
</argument>
<description>
</description>
</method>
- <method name="unshare" >
+ <method name="unshare">
<description>
</description>
</method>
@@ -22875,10 +26776,10 @@
Raw byte array.
</brief_description>
<description>
- Raw byte array. Contains bytes. Optimized for memory usage, cant fragment the memory.
+ Raw byte array. Contains bytes. Optimized for memory usage, can't fragment the memory.
</description>
<methods>
- <method name="get" >
+ <method name="get">
<return type="int">
</return>
<argument index="0" name="idx" type="int">
@@ -22886,31 +26787,33 @@
<description>
</description>
</method>
- <method name="get_string_from_ascii" >
+ <method name="get_string_from_ascii">
<return type="String">
</return>
<description>
+ Returns a copy of the array's contents formatted as String. Fast alternative to get_string_from_utf8(), assuming the content is ASCII-only (unlike the UTF-8 function, this function maps every byte to a character in the string, so any multibyte sequence will be torn apart).
</description>
</method>
- <method name="get_string_from_utf8" >
+ <method name="get_string_from_utf8">
<return type="String">
</return>
<description>
+ Returns a copy of the array's contents formatted as String, assuming the array is formatted as UTF-8. Slower than get_string_from_ascii(), but works for UTF-8. Usually you should prefer this function over get_string_from_ascii() to support international input.
</description>
</method>
- <method name="push_back" >
+ <method name="push_back">
<argument index="0" name="byte" type="int">
</argument>
<description>
</description>
</method>
- <method name="resize" >
+ <method name="resize">
<argument index="0" name="idx" type="int">
</argument>
<description>
</description>
</method>
- <method name="set" >
+ <method name="set">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="byte" type="int">
@@ -22918,13 +26821,15 @@
<description>
</description>
</method>
- <method name="size" >
+ <method name="size">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="RawArray" >
+ <method name="RawArray">
+ <return type="RawArray">
+ </return>
<argument index="0" name="from" type="Array">
</argument>
<description>
@@ -22940,60 +26845,88 @@
<description>
</description>
<methods>
- <method name="set_enabled" >
+ <method name="set_enabled">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_enabled" qualifiers="const" >
+ <method name="is_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_cast_to" >
+ <method name="set_cast_to">
<argument index="0" name="local_point" type="Vector3">
</argument>
<description>
</description>
</method>
- <method name="get_cast_to" qualifiers="const" >
+ <method name="get_cast_to" qualifiers="const">
<return type="Vector3">
</return>
<description>
</description>
</method>
- <method name="is_colliding" qualifiers="const" >
+ <method name="is_colliding" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="get_collider" qualifiers="const" >
+ <method name="get_collider" qualifiers="const">
<return type="Object">
</return>
<description>
</description>
</method>
- <method name="get_collider_shape" qualifiers="const" >
+ <method name="get_collider_shape" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_collision_point" qualifiers="const" >
+ <method name="get_collision_point" qualifiers="const">
<return type="Vector3">
</return>
<description>
</description>
</method>
- <method name="get_collision_normal" qualifiers="const" >
+ <method name="get_collision_normal" qualifiers="const">
<return type="Vector3">
</return>
<description>
</description>
</method>
+ <method name="add_exception_rid">
+ <argument index="0" name="rid" type="RID">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="add_exception">
+ <argument index="0" name="node" type="Object">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="remove_exception_rid">
+ <argument index="0" name="rid" type="RID">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="remove_exception">
+ <argument index="0" name="node" type="Object">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="clear_exceptions">
+ <description>
+ </description>
+ </method>
</methods>
<constants>
</constants>
@@ -23004,95 +26937,109 @@
<description>
</description>
<methods>
- <method name="set_enabled" >
+ <method name="set_enabled">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_enabled" qualifiers="const" >
+ <method name="is_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_cast_to" >
+ <method name="set_cast_to">
<argument index="0" name="local_point" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_cast_to" qualifiers="const" >
+ <method name="get_cast_to" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="is_colliding" qualifiers="const" >
+ <method name="is_colliding" qualifiers="const">
<return type="bool">
</return>
<description>
+ Return whether the closest object the ray is pointing to is colliding with the vector, with the vector length considered.
</description>
</method>
- <method name="get_collider" qualifiers="const" >
+ <method name="get_collider" qualifiers="const">
<return type="Object">
</return>
<description>
+ Return the closest object the ray is pointing to. Note that this does not consider the length of the vector, so you must also use [is_colliding] to check if the object returned is actually colliding with the ray.
</description>
</method>
- <method name="get_collider_shape" qualifiers="const" >
+ <method name="get_collider_shape" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_collision_point" qualifiers="const" >
+ <method name="get_collision_point" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="get_collision_normal" qualifiers="const" >
+ <method name="get_collision_normal" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="add_exception_rid" >
+ <method name="add_exception_rid">
<argument index="0" name="rid" type="RID">
</argument>
<description>
</description>
</method>
- <method name="add_exception" >
+ <method name="add_exception">
<argument index="0" name="node" type="Object">
</argument>
<description>
</description>
</method>
- <method name="remove_exception_rid" >
+ <method name="remove_exception_rid">
<argument index="0" name="rid" type="RID">
</argument>
<description>
</description>
</method>
- <method name="remove_exception" >
+ <method name="remove_exception">
<argument index="0" name="node" type="Object">
</argument>
<description>
</description>
</method>
- <method name="clear_exceptions" >
+ <method name="clear_exceptions">
<description>
</description>
</method>
- <method name="set_layer_mask" >
+ <method name="set_layer_mask">
<argument index="0" name="mask" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_layer_mask" qualifiers="const" >
+ <method name="get_layer_mask" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_type_mask">
+ <argument index="0" name="mask" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_type_mask" qualifiers="const">
<return type="int">
</return>
<description>
@@ -23108,13 +27055,13 @@
<description>
</description>
<methods>
- <method name="set_length" >
+ <method name="set_length">
<argument index="0" name="length" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_length" qualifiers="const" >
+ <method name="get_length" qualifiers="const">
<return type="float">
</return>
<description>
@@ -23129,19 +27076,21 @@
Ray 2D shape resource for physics.
</brief_description>
<description>
- Ray 2D shape resource for physics. A ray is not really a collision body, isntead it tries to separate itself from wathever is touching it's far endpoint. It's often useful for ccharacters.
+ Ray 2D shape resource for physics. A ray is not really a collision body, isntead it tries to separate itself from whatever is touching its far endpoint. It's often useful for characters.
</description>
<methods>
- <method name="set_length" >
+ <method name="set_length">
<argument index="0" name="length" type="float">
</argument>
<description>
+ Set the length of the ray.
</description>
</method>
- <method name="get_length" qualifiers="const" >
+ <method name="get_length" qualifiers="const">
<return type="float">
</return>
<description>
+ Return the length of the ray.
</description>
</method>
</methods>
@@ -23153,10 +27102,10 @@
Real Array .
</brief_description>
<description>
- Real Array. Array of floating point values. Can only contain floats. Optimized for memory usage, cant fragment the memory.
+ Real Array. Array of floating point values. Can only contain floats. Optimized for memory usage, can't fragment the memory.
</description>
<methods>
- <method name="get" >
+ <method name="get">
<return type="float">
</return>
<argument index="0" name="idx" type="int">
@@ -23164,19 +27113,19 @@
<description>
</description>
</method>
- <method name="push_back" >
+ <method name="push_back">
<argument index="0" name="value" type="float">
</argument>
<description>
</description>
</method>
- <method name="resize" >
+ <method name="resize">
<argument index="0" name="idx" type="int">
</argument>
<description>
</description>
</method>
- <method name="set" >
+ <method name="set">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="value" type="float">
@@ -23184,13 +27133,15 @@
<description>
</description>
</method>
- <method name="size" >
+ <method name="size">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="RealArray" >
+ <method name="RealArray">
+ <return type="RealArray">
+ </return>
<argument index="0" name="from" type="Array">
</argument>
<description>
@@ -23202,87 +27153,103 @@
</class>
<class name="Rect2" category="Built-In Types">
<brief_description>
+ 2D Axis-aligned bounding box.
</brief_description>
<description>
+ Rect2 provides an 2D Axis-Aligned Bounding Box. It consists of a position, a size, and several utility functions. It is typically used for fast overlap tests.
</description>
<methods>
- <method name="clip" >
+ <method name="clip">
<return type="Rect2">
</return>
<argument index="0" name="b" type="Rect2">
</argument>
<description>
+ Returns the intersection of this [Rect2] and b.
</description>
</method>
- <method name="encloses" >
+ <method name="encloses">
<return type="bool">
</return>
<argument index="0" name="b" type="Rect2">
</argument>
<description>
+ Returns true if this [Rect2] completely encloses another one.
</description>
</method>
- <method name="expand" >
+ <method name="expand">
<return type="Rect2">
</return>
<argument index="0" name="to" type="Vector2">
</argument>
<description>
+ Return this [Rect2] expanded to include a given point.
</description>
</method>
- <method name="get_area" >
+ <method name="get_area">
<return type="float">
</return>
<description>
+ Get the area of the [Rect2].
</description>
</method>
- <method name="grow" >
+ <method name="grow">
<return type="Rect2">
</return>
<argument index="0" name="by" type="float">
</argument>
<description>
+ Return a copy of the [Rect2] grown a given amount of units towards all the sides.
</description>
</method>
- <method name="has_no_area" >
+ <method name="has_no_area">
<return type="bool">
</return>
<description>
+ Return true if the [Rect2] is flat or empty.
</description>
</method>
- <method name="has_point" >
+ <method name="has_point">
<return type="bool">
</return>
<argument index="0" name="point" type="Vector2">
</argument>
<description>
+ Return true if the [Rect2] contains a point.
</description>
</method>
- <method name="intersects" >
+ <method name="intersects">
<return type="bool">
</return>
<argument index="0" name="b" type="Rect2">
</argument>
<description>
+ Return true if the [Rect2] overlaps with another.
</description>
</method>
- <method name="merge" >
+ <method name="merge">
<return type="Rect2">
</return>
<argument index="0" name="b" type="Rect2">
</argument>
<description>
+ Combine this [Rect2] with another, a larger one is returned that contains both.
</description>
</method>
- <method name="Rect2" >
+ <method name="Rect2">
+ <return type="Rect2">
+ </return>
<argument index="0" name="pos" type="Vector2">
</argument>
<argument index="1" name="size" type="Vector2">
</argument>
<description>
+ Construct a [Rect2] by position and size.
</description>
</method>
- <method name="Rect2" >
+ <method name="Rect2">
+ <return type="Rect2">
+ </return>
<argument index="0" name="x" type="float">
</argument>
<argument index="1" name="y" type="float">
@@ -23292,6 +27259,7 @@
<argument index="3" name="height" type="float">
</argument>
<description>
+ Construct a [Rect2] by x, y, width and height.
</description>
</method>
</methods>
@@ -23314,14 +27282,14 @@
Rectangle Shape for 2D Physics. This shape is useful for modelling box-like 2D objects.
</description>
<methods>
- <method name="set_extents" >
+ <method name="set_extents">
<argument index="0" name="extents" type="Vector2">
</argument>
<description>
Set the half extents, the actual width and height of this shape is twice the half extents.
</description>
</method>
- <method name="get_extents" qualifiers="const" >
+ <method name="get_extents" qualifiers="const">
<return type="Vector2">
</return>
<description>
@@ -23334,24 +27302,24 @@
</class>
<class name="Reference" inherits="Object" category="Core">
<brief_description>
- Base class for anything refcounted.
+ Base class for anything that keeps a reference count.
</brief_description>
<description>
- Base class for anything refcounted. Resource and many other helper objects inherit this. References keep an internal reference counter so they are only released when no longer in use.
+ Base class for anything that keeps a reference count. Resource and many other helper objects inherit this. References keep an internal reference counter so they are only released when no longer in use.
</description>
<methods>
- <method name="init_ref" >
+ <method name="init_ref">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="reference" >
+ <method name="reference">
<description>
Increase the internal reference counter. Use this only if you really know what you are doing.
</description>
</method>
- <method name="unreference" >
+ <method name="unreference">
<return type="bool">
</return>
<description>
@@ -23367,7 +27335,7 @@
Reference frame for GUI.
</brief_description>
<description>
- Reference frame for GUI. It's just like an empty control, except a red box is displayed while editing around it's size at all times.
+ Reference frame for GUI. It's just like an empty control, except a red box is displayed while editing around its size at all times.
</description>
<methods>
</methods>
@@ -23380,19 +27348,41 @@
</class>
<class name="RegEx" inherits="Reference" category="Core">
<brief_description>
+ Simple regular expression matcher.
</brief_description>
<description>
+ Class for finding text patterns in a string using regular expressions. Regular expressions are a way to define patterns of text to be searched.
+ This class only finds patterns in a string. It can not perform replacements.
+ Usage of regular expressions is too long to be explained here, but Internet is full of tutorials and detailed explanations.
+ Currently supported features:
+ Capturing [code]()[/code] and non-capturing [code](?:)[/code] groups
+ Any character [code].[/code]
+ Shorthand caracter classes [code]\w \W \s \S \d \D[/code]
+ User-defined character classes such as [code][A-Za-z][/code]
+ Simple quantifiers [code]?[/code], [code]*[/code] and [code]+[/code]
+ Range quantifiers [code]{x,y}[/code]
+ Lazy (non-greedy) quantifiers [code]*?[/code]
+ Begining [code]^[/code] and end [code]$[/code] anchors
+ Alternation [code]|[/code]
+ Backreferences [code]\1[/code] and [code]\g{1}[/code]
+ POSIX character classes [code][[:alnum:]][/code]
+ Lookahead [code](?=)[/code], [code](?!)[/code] and lookbehind [code](?&lt;=)[/code], [code](?&lt;!)[/code]
+ ASCII [code]\xFF[/code] and Unicode [code]\uFFFF[/code] code points (in a style similar to Python)
+ Word boundaries [code]\b[/code], [code]\B[/code]
</description>
<methods>
- <method name="compile" >
+ <method name="compile">
<return type="int">
</return>
<argument index="0" name="pattern" type="String">
</argument>
+ <argument index="1" name="capture" type="int" default="9">
+ </argument>
<description>
+ Compiles and assign the regular expression pattern to use. The limit on the number of capturing groups can be specified or made unlimited if negative.
</description>
</method>
- <method name="find" qualifiers="const" >
+ <method name="find" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="text" type="String">
@@ -23402,12 +27392,42 @@
<argument index="2" name="end" type="int" default="-1">
</argument>
<description>
+ This method tries to find the pattern within the string, and returns the position where it was found. It also stores any capturing group (see [method get_capture]) for further retrieval.
+ </description>
+ </method>
+ <method name="clear">
+ <description>
+ This method resets the state of the object, as it was freshly created. Namely, it unassigns the regular expression of this object, and forgets all captures made by the last [method find].
+ </description>
+ </method>
+ <method name="is_valid" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Returns whether this object has a valid regular expression assigned.
+ </description>
+ </method>
+ <method name="get_capture_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Returns the number of capturing groups. A captured group is the part of a string that matches a part of the pattern delimited by parentheses (unless they are non-capturing parentheses [i](?:)[/i]).
+ </description>
+ </method>
+ <method name="get_capture" qualifiers="const">
+ <return type="String">
+ </return>
+ <argument index="0" name="capture" type="int">
+ </argument>
+ <description>
+ Returns a captured group. A captured group is the part of a string that matches a part of the pattern delimited by parentheses (unless they are non-capturing parentheses [i](?:)[/i]).
</description>
</method>
- <method name="get_captures" qualifiers="const" >
+ <method name="get_captures" qualifiers="const">
<return type="StringArray">
</return>
<description>
+ Return a list of all the captures made by the regular expression.
</description>
</method>
</methods>
@@ -23420,13 +27440,13 @@
<description>
</description>
<methods>
- <method name="set_remote_node" >
+ <method name="set_remote_node">
<argument index="0" name="path" type="NodePath">
</argument>
<description>
</description>
</method>
- <method name="get_remote_node" qualifiers="const" >
+ <method name="get_remote_node" qualifiers="const">
<return type="NodePath">
</return>
<description>
@@ -23454,63 +27474,63 @@
Resource is the base class for all resource types. Resources are primarily data containers. They are reference counted and freed when no longer in use. They are also loaded only once from disk, and further attempts to load the resource will return the same reference (all this in contrast to a [Node], which is not reference counted and can be instanced from disk as many times as desred). Resources can be saved externally on disk or bundled into another object, such as a [Node] or another resource.
</description>
<methods>
- <method name="set_path" >
+ <method name="set_path">
<argument index="0" name="path" type="String">
</argument>
<description>
- Set the path of the resource. This is useful mainly for editors when saving/loading, and shouldn"apos;t be changed by anything else.
+ Set the path of the resource. This is useful mainly for editors when saving/loading, and shouldn't be changed by anything else.
</description>
</method>
- <method name="take_over_path" >
+ <method name="take_over_path">
<argument index="0" name="path" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_path" qualifiers="const" >
+ <method name="get_path" qualifiers="const">
<return type="String">
</return>
<description>
- Return the path of the resource. This is useful mainly for editors when saving/loading, and shouldn"apos;t be changed by anything else.
+ Return the path of the resource. This is useful mainly for editors when saving/loading, and shouldn't be changed by anything else.
</description>
</method>
- <method name="set_name" >
+ <method name="set_name">
<argument index="0" name="name" type="String">
</argument>
<description>
- Set the name of the resources, any name is ok (it doesn"apos;t have to be unique). Name is for descriptive purposes only.
+ Set the name of the resources, any name is valid (it doesn't have to be unique). Name is for descriptive purposes only.
</description>
</method>
- <method name="get_name" qualifiers="const" >
+ <method name="get_name" qualifiers="const">
<return type="String">
</return>
<description>
- Return the name of the resources, any name is ok (it doesn"apos;t have to be unique). Name is for descriptive purposes only.
+ Return the name of the resources, any name is valid (it doesn't have to be unique). Name is for descriptive purposes only.
</description>
</method>
- <method name="get_rid" qualifiers="const" >
+ <method name="get_rid" qualifiers="const">
<return type="RID">
</return>
<description>
Return the RID of the resource (or an empty RID). Many resources (such as [Texture], [Mesh], etc) are high level abstractions of resources stored in a server, so this function will return the original RID.
</description>
</method>
- <method name="set_import_metadata" >
+ <method name="set_import_metadata">
<argument index="0" name="metadata" type="Object">
</argument>
<description>
</description>
</method>
- <method name="get_import_metadata" qualifiers="const" >
+ <method name="get_import_metadata" qualifiers="const">
<return type="Object">
</return>
<description>
</description>
</method>
- <method name="duplicate" >
+ <method name="duplicate">
<return type="Object">
</return>
- <argument index="0" name="arg0" type="bool" default="false">
+ <argument index="0" name="subresources" type="bool" default="false">
</argument>
<description>
</description>
@@ -23531,27 +27551,27 @@
<description>
</description>
<methods>
- <method name="set_editor" >
+ <method name="set_editor">
<argument index="0" name="name" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_editor" qualifiers="const" >
+ <method name="get_editor" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="add_source" >
+ <method name="add_source">
<argument index="0" name="path" type="String">
</argument>
- <argument index="1" name="md5" type="String">
+ <argument index="1" name="md5" type="String" default="&quot;&quot;">
</argument>
<description>
</description>
</method>
- <method name="get_source_path" qualifiers="const" >
+ <method name="get_source_path" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="idx" type="int">
@@ -23559,7 +27579,7 @@
<description>
</description>
</method>
- <method name="get_source_md5" qualifiers="const" >
+ <method name="get_source_md5" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="idx" type="int">
@@ -23567,19 +27587,19 @@
<description>
</description>
</method>
- <method name="remove_source" >
+ <method name="remove_source">
<argument index="0" name="idx" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_source_count" qualifiers="const" >
+ <method name="get_source_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_option" >
+ <method name="set_option">
<argument index="0" name="key" type="String">
</argument>
<argument index="1" name="value" type="var">
@@ -23587,13 +27607,13 @@
<description>
</description>
</method>
- <method name="get_option" qualifiers="const" >
+ <method name="get_option" qualifiers="const">
<argument index="0" name="key" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_options" qualifiers="const" >
+ <method name="get_options" qualifiers="const">
<return type="StringArray">
</return>
<description>
@@ -23611,34 +27631,34 @@
Interactive Resource Loader. This object is returned by ResourceLoader when performing an interactive load. It allows to load with high granularity, so this is mainly useful for displaying load bars/percentages.
</description>
<methods>
- <method name="get_resource" >
+ <method name="get_resource">
<return type="Object">
</return>
<description>
Return the loaded resource (only if loaded). Otherwise, returns null.
</description>
</method>
- <method name="poll" >
+ <method name="poll">
<return type="int">
</return>
<description>
Poll the load. If OK is returned, this means poll will have to be called again. If ERR_EOF is returned, them the load has finished and the resource can be obtained by calling [get_resource].
</description>
</method>
- <method name="wait" >
+ <method name="wait">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_stage" qualifiers="const" >
+ <method name="get_stage" qualifiers="const">
<return type="int">
</return>
<description>
Return the load stage. The total amount of stages can be queried with [get_stage_count]
</description>
</method>
- <method name="get_stage_count" qualifiers="const" >
+ <method name="get_stage_count" qualifiers="const">
<return type="int">
</return>
<description>
@@ -23657,7 +27677,7 @@
Resource Loader. This is a static object accessible as [ResourceLoader]. GDScript has a simplified load() function, though.
</description>
<methods>
- <method name="load_interactive" >
+ <method name="load_interactive">
<return type="ResourceInteractiveLoader">
</return>
<argument index="0" name="path" type="String">
@@ -23668,18 +27688,19 @@
Load a resource interactively, the returned object allows to load with high granularity.
</description>
</method>
- <method name="load" >
+ <method name="load">
<return type="Resource">
</return>
<argument index="0" name="path" type="String">
</argument>
<argument index="1" name="type_hint" type="String" default="&quot;&quot;">
</argument>
+ <argument index="2" name="p_no_cache" type="bool" default="false">
+ </argument>
<description>
- Load a resource. Optionally a hint can be given for the resource type to load.
</description>
</method>
- <method name="get_recognized_extensions_for_type" >
+ <method name="get_recognized_extensions_for_type">
<return type="StringArray">
</return>
<argument index="0" name="type" type="String">
@@ -23688,25 +27709,25 @@
Return the list of recognized extensions for a resource type.
</description>
</method>
- <method name="set_abort_on_missing_resources" >
+ <method name="set_abort_on_missing_resources">
<argument index="0" name="abort" type="bool">
</argument>
<description>
Change the behavior on missing sub-resources. Default is to abort load.
</description>
</method>
- <method name="get_dependencies" >
+ <method name="get_dependencies">
<return type="StringArray">
</return>
- <argument index="0" name="arg0" type="String">
+ <argument index="0" name="path" type="String">
</argument>
<description>
</description>
</method>
- <method name="has" >
+ <method name="has">
<return type="bool">
</return>
- <argument index="0" name="arg0" type="String">
+ <argument index="0" name="path" type="String">
</argument>
<description>
</description>
@@ -23723,7 +27744,7 @@
Resource Preloader Node. This node is used to preload sub-resources inside a scene, so when the scene is loaded all the resourcs are ready to use and be retrieved from here.
</description>
<methods>
- <method name="add_resource" >
+ <method name="add_resource">
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="resource" type="Object">
@@ -23732,14 +27753,14 @@
Add a resource to the preloader. Set the text-id that will be used to identify it (retrieve it/erase it/etc).
</description>
</method>
- <method name="remove_resource" >
+ <method name="remove_resource">
<argument index="0" name="name" type="String">
</argument>
<description>
Remove a resource from the preloader by text id.
</description>
</method>
- <method name="rename_resource" >
+ <method name="rename_resource">
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="newname" type="String">
@@ -23748,7 +27769,7 @@
Rename a resource inside the preloader, from a text-id to a new text-id.
</description>
</method>
- <method name="has_resource" qualifiers="const" >
+ <method name="has_resource" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="name" type="String">
@@ -23757,7 +27778,7 @@
Return true if the preloader has a given resource.
</description>
</method>
- <method name="get_resource" qualifiers="const" >
+ <method name="get_resource" qualifiers="const">
<return type="Object">
</return>
<argument index="0" name="name" type="String">
@@ -23766,7 +27787,7 @@
Return the resource given a text-id.
</description>
</method>
- <method name="get_resource_list" qualifiers="const" >
+ <method name="get_resource_list" qualifiers="const">
<return type="StringArray">
</return>
<description>
@@ -23785,20 +27806,20 @@
Resource Saving Interface. This interface is used for saving resources to disk.
</description>
<methods>
- <method name="save" >
+ <method name="save">
<return type="int">
</return>
<argument index="0" name="path" type="String">
</argument>
<argument index="1" name="resource" type="Resource">
</argument>
- <argument index="2" name="arg2" type="int" default="0">
+ <argument index="2" name="flags" type="int" default="0">
</argument>
<description>
Save a resource to disk, to a given path.
</description>
</method>
- <method name="get_recognized_extensions" >
+ <method name="get_recognized_extensions">
<return type="StringArray">
</return>
<argument index="0" name="type" type="Object">
@@ -23831,133 +27852,165 @@
Label that displays rich text. Rich text can contain custom text, fonts, images and some basic formatting. It also adapts itself to given width/heights.
</description>
<methods>
- <method name="add_text" >
+ <method name="add_text">
<argument index="0" name="text" type="String">
</argument>
<description>
</description>
</method>
- <method name="add_image" >
+ <method name="add_image">
<argument index="0" name="image" type="Texture">
</argument>
<description>
</description>
</method>
- <method name="newline" >
+ <method name="newline">
<description>
</description>
</method>
- <method name="push_font" >
+ <method name="push_font">
<argument index="0" name="font" type="Object">
</argument>
<description>
</description>
</method>
- <method name="push_color" >
+ <method name="push_color">
<argument index="0" name="color" type="Color">
</argument>
<description>
</description>
</method>
- <method name="push_align" >
+ <method name="push_align">
<argument index="0" name="align" type="int">
</argument>
<description>
</description>
</method>
- <method name="push_indent" >
+ <method name="push_indent">
<argument index="0" name="level" type="int">
</argument>
<description>
</description>
</method>
- <method name="push_list" >
+ <method name="push_list">
<argument index="0" name="type" type="int">
</argument>
<description>
</description>
</method>
- <method name="push_meta" >
+ <method name="push_meta">
<argument index="0" name="data" type="var">
</argument>
<description>
</description>
</method>
- <method name="push_underline" >
+ <method name="push_underline">
+ <description>
+ </description>
+ </method>
+ <method name="push_table">
+ <argument index="0" name="columns" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_table_column_expand">
+ <argument index="0" name="column" type="int">
+ </argument>
+ <argument index="1" name="expand" type="bool">
+ </argument>
+ <argument index="2" name="ratio" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="push_cell">
<description>
</description>
</method>
- <method name="pop" >
+ <method name="pop">
<description>
</description>
</method>
- <method name="clear" >
+ <method name="clear">
<description>
</description>
</method>
- <method name="set_meta_underline" >
+ <method name="set_meta_underline">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_meta_underlined" qualifiers="const" >
+ <method name="is_meta_underlined" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_scroll_active" >
+ <method name="set_scroll_active">
<argument index="0" name="active" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_scroll_active" qualifiers="const" >
+ <method name="is_scroll_active" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_scroll_follow" >
+ <method name="set_scroll_follow">
<argument index="0" name="follow" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_scroll_following" qualifiers="const" >
+ <method name="is_scroll_following" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_tab_size" >
+ <method name="get_v_scroll">
+ <return type="Object">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="scroll_to_line">
+ <argument index="0" name="line" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_tab_size">
<argument index="0" name="spaces" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_tab_size" qualifiers="const" >
+ <method name="get_tab_size" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_selection_enabled" >
+ <method name="set_selection_enabled">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
Set to true if selecting the text inside this richtext is allowed.
</description>
</method>
- <method name="is_selection_enabled" qualifiers="const" >
+ <method name="is_selection_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
Return true if selecting the text inside this richtext is allowed.
</description>
</method>
- <method name="parse_bbcode" >
+ <method name="parse_bbcode">
<return type="int">
</return>
<argument index="0" name="bbcode" type="String">
@@ -23965,7 +28018,7 @@
<description>
</description>
</method>
- <method name="append_bbcode" >
+ <method name="append_bbcode">
<return type="int">
</return>
<argument index="0" name="bbcode" type="String">
@@ -23973,6 +28026,48 @@
<description>
</description>
</method>
+ <method name="set_bbcode">
+ <argument index="0" name="text" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_bbcode" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_visible_characters">
+ <argument index="0" name="amount" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_visible_characters" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_total_character_count" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_use_bbcode">
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_using_bbcode" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<signals>
<signal name="meta_clicked">
@@ -23997,7 +28092,7 @@
</constant>
<constant name="LIST_DOTS" value="2">
</constant>
- <constant name="ITEM_MAIN" value="0">
+ <constant name="ITEM_FRAME" value="0">
</constant>
<constant name="ITEM_TEXT" value="1">
</constant>
@@ -24017,10 +28112,14 @@
</constant>
<constant name="ITEM_LIST" value="9">
</constant>
- <constant name="ITEM_META" value="10">
+ <constant name="ITEM_META" value="11">
</constant>
</constants>
<theme_items>
+ <theme_item name="table_vseparation" type="int">
+ </theme_item>
+ <theme_item name="table_hseparation" type="int">
+ </theme_item>
<theme_item name="line_separation" type="int">
</theme_item>
<theme_item name="default_color" type="Color">
@@ -24029,7 +28128,15 @@
</theme_item>
<theme_item name="font_color_selected" type="Color">
</theme_item>
- <theme_item name="default_font" type="Font">
+ <theme_item name="mono_font" type="Font">
+ </theme_item>
+ <theme_item name="bold_italics_font" type="Font">
+ </theme_item>
+ <theme_item name="italics_font" type="Font">
+ </theme_item>
+ <theme_item name="bold_font" type="Font">
+ </theme_item>
+ <theme_item name="normal_font" type="Font">
</theme_item>
<theme_item name="focus" type="StyleBox">
</theme_item>
@@ -24041,151 +28148,187 @@
<description>
</description>
<methods>
- <method name="_integrate_forces" qualifiers="virtual" >
+ <method name="_integrate_forces" qualifiers="virtual">
<argument index="0" name="state" type="PhysicsDirectBodyState">
</argument>
<description>
</description>
</method>
- <method name="set_mode" >
+ <method name="set_mode">
<argument index="0" name="mode" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_mode" qualifiers="const" >
+ <method name="get_mode" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_mass" >
+ <method name="set_mass">
<argument index="0" name="mass" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_mass" qualifiers="const" >
+ <method name="get_mass" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_weight" >
+ <method name="set_weight">
<argument index="0" name="weight" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_weight" qualifiers="const" >
+ <method name="get_weight" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_friction" >
+ <method name="set_friction">
<argument index="0" name="friction" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_friction" qualifiers="const" >
+ <method name="get_friction" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_bounce" >
+ <method name="set_bounce">
<argument index="0" name="bounce" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_bounce" qualifiers="const" >
+ <method name="get_bounce" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_linear_velocity" >
+ <method name="set_linear_velocity">
<argument index="0" name="linear_velocity" type="Vector3">
</argument>
<description>
</description>
</method>
- <method name="get_linear_velocity" qualifiers="const" >
+ <method name="get_linear_velocity" qualifiers="const">
<return type="Vector3">
</return>
<description>
</description>
</method>
- <method name="set_angular_velocity" >
+ <method name="set_angular_velocity">
<argument index="0" name="angular_velocity" type="Vector3">
</argument>
<description>
</description>
</method>
- <method name="get_angular_velocity" qualifiers="const" >
+ <method name="get_angular_velocity" qualifiers="const">
<return type="Vector3">
</return>
<description>
</description>
</method>
- <method name="set_max_contacts_reported" >
+ <method name="set_gravity_scale">
+ <argument index="0" name="gravity_scale" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_gravity_scale" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_linear_damp">
+ <argument index="0" name="linear_damp" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_linear_damp" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_angular_damp">
+ <argument index="0" name="angular_damp" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_angular_damp" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_max_contacts_reported">
<argument index="0" name="amount" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_max_contacts_reported" qualifiers="const" >
+ <method name="get_max_contacts_reported" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_use_custom_integrator" >
+ <method name="set_use_custom_integrator">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_using_custom_integrator" >
+ <method name="is_using_custom_integrator">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_contact_monitor" >
+ <method name="set_contact_monitor">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_contact_monitor_enabled" qualifiers="const" >
+ <method name="is_contact_monitor_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_use_continuous_collision_detection" >
+ <method name="set_use_continuous_collision_detection">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_using_continuous_collision_detection" qualifiers="const" >
+ <method name="is_using_continuous_collision_detection" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_axis_velocity" >
+ <method name="set_axis_velocity">
<argument index="0" name="axis_velocity" type="Vector3">
</argument>
<description>
</description>
</method>
- <method name="apply_impulse" >
+ <method name="apply_impulse">
<argument index="0" name="pos" type="Vector3">
</argument>
<argument index="1" name="impulse" type="Vector3">
@@ -24193,43 +28336,43 @@
<description>
</description>
</method>
- <method name="set_sleeping" >
+ <method name="set_sleeping">
<argument index="0" name="sleeping" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_sleeping" qualifiers="const" >
+ <method name="is_sleeping" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_can_sleep" >
+ <method name="set_can_sleep">
<argument index="0" name="able_to_sleep" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_able_to_sleep" qualifiers="const" >
+ <method name="is_able_to_sleep" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_axis_lock" >
+ <method name="set_axis_lock">
<argument index="0" name="axis_lock" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_axis_lock" qualifiers="const" >
+ <method name="get_axis_lock" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_colliding_bodies" qualifiers="const" >
+ <method name="get_colliding_bodies" qualifiers="const">
<return type="Array">
</return>
<description>
@@ -24290,228 +28433,292 @@
Rigid body 2D node.
</brief_description>
<description>
- Rigid body 2D node. This node is used for placing rigid bodies in the scene. It can contain a number of shapes, and also shift state between regular Rigid Body to Character or even Static.
- Character mode forbids the node from being rotated. This node can have a custom force integrator function, for writing complex physics motion behavior per node.[br]
+ Rigid body 2D node. This node is used for placing rigid bodies in the scene. It can contain a number of shapes, and also shift state between regular Rigid body, Kinematic, Character or Static.
+ Character mode forbids the node from being rotated. This node can have a custom force integrator function, for writing complex physics motion behavior per node.
As a warning, don't change this node position every frame or very often. Sporadic changes work fine, but physics runs at a different granularity (fixed hz) than usual rendering (process callback) and maybe even in a separate thread, so changing this from a process loop will yield strange behavior.
</description>
<methods>
- <method name="_integrate_forces" qualifiers="virtual" >
+ <method name="_integrate_forces" qualifiers="virtual">
<argument index="0" name="state" type="Physics2DDirectBodyState">
</argument>
<description>
Override this function to use a custom force integrator. This allows to hook up to the physics processing and alter the simulation state for the object on every frame.
</description>
</method>
- <method name="set_mode" >
+ <method name="set_mode">
<argument index="0" name="mode" type="int">
</argument>
<description>
- Set the body mode, fromt he MODE_* enum. This allows to change to a static body or a character body.
+ Set the body mode, from the MODE_* enum. This allows to change to a static body or a character body.
</description>
</method>
- <method name="get_mode" qualifiers="const" >
+ <method name="get_mode" qualifiers="const">
<return type="int">
</return>
<description>
- Return the current body mode, see [set_mode].
+ Return the current body mode, see [method set_mode].
</description>
</method>
- <method name="set_mass" >
+ <method name="set_mass">
<argument index="0" name="mass" type="float">
</argument>
<description>
Set the body mass.
</description>
</method>
- <method name="get_mass" qualifiers="const" >
+ <method name="get_mass" qualifiers="const">
<return type="float">
</return>
<description>
Return the body mass.
</description>
</method>
- <method name="set_weight" >
+ <method name="set_weight">
<argument index="0" name="weight" type="float">
</argument>
<description>
- Set the body mass given standard earth-weight (gravity 9.8). Not really useful for 2D since most measuers for this node are in pixels.
+ Set the body weight given standard earth-weight (gravity 9.8). Not really useful for 2D since most measures for this node are in pixels.
</description>
</method>
- <method name="get_weight" qualifiers="const" >
+ <method name="get_weight" qualifiers="const">
<return type="float">
</return>
<description>
- Return the body mass given standard earth-weight (gravity 9.8).
+ Return the body weight given standard earth-weight (gravity 9.8).
</description>
</method>
- <method name="set_friction" >
+ <method name="set_friction">
<argument index="0" name="friction" type="float">
</argument>
<description>
- Set the body friction, from 0 (friction less) to 1 (full friction).
+ Set the body friction, from 0 (frictionless) to 1 (full friction).
</description>
</method>
- <method name="get_friction" qualifiers="const" >
+ <method name="get_friction" qualifiers="const">
<return type="float">
</return>
<description>
Return the body friction.
</description>
</method>
- <method name="set_bounce" >
+ <method name="set_bounce">
<argument index="0" name="bounce" type="float">
</argument>
<description>
- Set the body bounciness, from 0 (no bounce) to 1 (bounce).
+ Set the body bounciness, from 0 (no bounce) to 1 (full bounce).
</description>
</method>
- <method name="get_bounce" qualifiers="const" >
+ <method name="get_bounce" qualifiers="const">
<return type="float">
</return>
<description>
- Return the body bouncyness.
+ Return the body bounciness.
+ </description>
+ </method>
+ <method name="set_gravity_scale">
+ <argument index="0" name="gravity_scale" type="float">
+ </argument>
+ <description>
+ Set The gravity factor. This factor multiplies gravity intensity just for this body.
</description>
</method>
- <method name="set_linear_velocity" >
+ <method name="get_gravity_scale" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ Return the gravity factor.
+ </description>
+ </method>
+ <method name="set_linear_damp">
+ <argument index="0" name="linear_damp" type="float">
+ </argument>
+ <description>
+ Set the linear damp for this body. If this value is different from -1, any linear damp derived from the world or areas will be overriden.
+ </description>
+ </method>
+ <method name="get_linear_damp" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ Return the linear damp for this body.
+ </description>
+ </method>
+ <method name="set_angular_damp">
+ <argument index="0" name="angular_damp" type="float">
+ </argument>
+ <description>
+ Set the angular damp for this body. If this value is different from -1, any angular damp derived from the world or areas will be overriden.
+ </description>
+ </method>
+ <method name="get_angular_damp" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ Return the angular damp for this body.
+ </description>
+ </method>
+ <method name="set_linear_velocity">
<argument index="0" name="linear_velocity" type="Vector2">
</argument>
<description>
Set the body linear velocity. Can be used sporadically, but[b] DONT SET THIS IN EVERY FRAME [/b], because physics may be running in another thread and definitely runs at a different granularity. Use [_integrate_forces] as your process loop if you want to have precise control of the body state.
</description>
</method>
- <method name="get_linear_velocity" qualifiers="const" >
+ <method name="get_linear_velocity" qualifiers="const">
<return type="Vector2">
</return>
<description>
- Return the body linear velocity. This changes by physics granularity. See [set_linear_velocity].
+ Return the body linear velocity. This changes by physics granularity. See [method set_linear_velocity].
</description>
</method>
- <method name="set_angular_velocity" >
+ <method name="set_angular_velocity">
<argument index="0" name="angular_velocity" type="float">
</argument>
<description>
Set the body angular velocity. Can be used sporadically, but[b] DONT SET THIS IN EVERY FRAME [/b], because physics may be running in another thread and definitely runs at a different granularity. Use [_integrate_forces] as your process loop if you want to have precise control of the body state.
</description>
</method>
- <method name="get_angular_velocity" qualifiers="const" >
+ <method name="get_angular_velocity" qualifiers="const">
<return type="float">
</return>
<description>
- Return the body angular velocity. This changes by physics granularity. See [set_angular_velocity].
+ Return the body angular velocity. This changes by physics granularity. See [method set_angular_velocity].
</description>
</method>
- <method name="set_max_contacts_reported" >
+ <method name="set_max_contacts_reported">
<argument index="0" name="amount" type="int">
</argument>
<description>
Set the maximum contacts to report. Bodies can keep a log of the contacts with other bodies, this is enabled by setting the maximum amount of contacts reported to a number greater than 0.
</description>
</method>
- <method name="get_max_contacts_reported" qualifiers="const" >
+ <method name="get_max_contacts_reported" qualifiers="const">
<return type="int">
</return>
<description>
- Return the maximum contacts that can be reported. See [set_max_contacts_reported].
+ Return the maximum contacts that can be reported. See [method set_max_contacts_reported].
</description>
</method>
- <method name="set_use_custom_integrator" >
+ <method name="set_use_custom_integrator">
<argument index="0" name="enable" type="bool">
</argument>
<description>
- Set to true if the body shall not do any internal force integration at all (like gravity or air friction). Only the [_integrate_forces] will be able to integrate them if overrided.
+ Set to true if the body shall not do any internal force integration at all (like gravity or air friction). Only the [method _integrate_forces] will be able to integrate them if overrided.
</description>
</method>
- <method name="is_using_custom_integrator" >
+ <method name="is_using_custom_integrator">
<return type="bool">
</return>
<description>
Return true if the body is not doing any built-in force integration.
</description>
</method>
- <method name="set_contact_monitor" >
+ <method name="set_contact_monitor">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
- Enable contact monitoring. (the signals to notify when a body entered/exited collision).
+ Enable contact monitoring. This allows the body to emit signals when it collides with another.
</description>
</method>
- <method name="is_contact_monitor_enabled" qualifiers="const" >
+ <method name="is_contact_monitor_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
- Return wether contact monitoring is enabled.
+ Return whether contact monitoring is enabled.
</description>
</method>
- <method name="set_continuous_collision_detection_mode" >
+ <method name="set_continuous_collision_detection_mode">
<argument index="0" name="mode" type="int">
</argument>
<description>
+ Set the continuous collision detection mode from the enum CCD_MODE_*.
+ Coninuous collision detection tries to predict where a moving body will collide, instead of moving it and correcting its movement if it collided. The first is more precise, and misses less impacts by small, fast-moving objects. The second is faster to compute, but can miss small, fat-moving objects.
</description>
</method>
- <method name="get_continuous_collision_detection_mode" qualifiers="const" >
+ <method name="get_continuous_collision_detection_mode" qualifiers="const">
<return type="int">
</return>
<description>
+ Return whether this body is using continuous collision detection.
</description>
</method>
- <method name="set_axis_velocity" >
+ <method name="set_axis_velocity">
<argument index="0" name="axis_velocity" type="Vector2">
</argument>
<description>
- Set an axis velocity. The velocity in the given vector axis will be set as the given vector length. (This is useful for jumping behavior).
+ Set an axis velocity. The velocity in the given vector axis will be set as the given vector length. This is useful for jumping behavior.
</description>
</method>
- <method name="apply_impulse" >
+ <method name="apply_impulse">
<argument index="0" name="pos" type="Vector2">
</argument>
<argument index="1" name="impulse" type="Vector2">
</argument>
<description>
- Apply a positioned impulse (which will be affected by the body mass and shape).
+ Apply a positioned impulse (which will be affected by the body mass and shape). This is the equivalent of hitting a billiard ball with a cue: a force that is applied once, and only once.
</description>
</method>
- <method name="set_applied_force" >
+ <method name="set_applied_force">
<argument index="0" name="force" type="Vector2">
</argument>
<description>
+ Set the applied force vector. This is the equivalent of pushing a box over the ground: the force applied is applied constantly.
</description>
</method>
- <method name="get_applied_force" qualifiers="const" >
+ <method name="get_applied_force" qualifiers="const">
<return type="Vector2">
</return>
<description>
+ Return the applied force vector.
</description>
</method>
- <method name="set_sleeping" >
+ <method name="set_sleeping">
<argument index="0" name="sleeping" type="bool">
</argument>
<description>
+ Set whether a body is isleeping or not. Sleeping bodies are not affected by forces until a collision or an [method apply_impulse]/[method set_applied_force] wakes them up. Until then, they behave like a static body.
</description>
</method>
- <method name="is_sleeping" qualifiers="const" >
+ <method name="is_sleeping" qualifiers="const">
<return type="bool">
</return>
<description>
+ Return whether the body is sleeping.
</description>
</method>
- <method name="set_can_sleep" >
+ <method name="set_can_sleep">
<argument index="0" name="able_to_sleep" type="bool">
</argument>
<description>
Set the body ability to fall asleep when not moving. This saves an enormous amount of processor time when there are plenty of rigid bodies (non static) in a scene.
+ Sleeping bodies are not affected by forces until a collision or an [method apply_impulse]/[method set_applied_force] wakes them up. Until then, they behave like a static body.
</description>
</method>
- <method name="is_able_to_sleep" qualifiers="const" >
+ <method name="is_able_to_sleep" qualifiers="const">
<return type="bool">
</return>
<description>
- Return true if the body has the ability to fall asleep when not moving. See [set_can_sleep].
+ Return true if the body has the ability to fall asleep when not moving. See [method set_can_sleep].
</description>
</method>
- <method name="get_colliding_bodies" qualifiers="const" >
+ <method name="test_motion">
+ <return type="bool">
+ </return>
+ <argument index="0" name="motion" type="Vector2">
+ </argument>
+ <argument index="1" name="margin" type="float" default="0.08">
+ </argument>
+ <argument index="2" name="result" type="Physics2DTestMotionResult" default="NULL">
+ </argument>
+ <description>
+ Return whether the body would collide, if it tried to move in the given vector. This method allows two extra parameters: A margin, which increases slightly the size of the shapes involved in the collision detection, and an object of type [Physics2DTestMotionResult], which will store additional information about the collision (should there be one).
+ </description>
+ </method>
+ <method name="get_colliding_bodies" qualifiers="const">
<return type="Array">
</return>
<description>
+ Return a list of the bodies colliding with this one.
</description>
</method>
</methods>
@@ -24520,7 +28727,7 @@
<argument index="0" name="body" type="Object">
</argument>
<description>
- Emitted when a new body enters into contact with this one. Contact monitor and contacts reported must be enabled for this to work.
+ Emitted when a body enters into contact with this one. Contact monitor and contacts reported must be enabled for this to work.
</description>
</signal>
<signal name="body_enter_shape">
@@ -24533,7 +28740,8 @@
<argument index="3" name="local_shape" type="int">
</argument>
<description>
- Emitted when a new body sub-shape enters into contact with this one. Contact monitor and contacts reported must be enabled for this to work.
+ Emitted when a body enters into contact with this one. Contact monitor and contacts reported must be enabled for this to work.
+ This signal not only receives the body that collided with this one, but also its [RID] (body_id), the shape index from the colliding body (body_shape), and the shape index from this body (local_shape) the other body collided with.
</description>
</signal>
<signal name="body_exit">
@@ -24554,26 +28762,31 @@
</argument>
<description>
Emitted when a body shape exits contact with this one. Contact monitor and contacts reported must be enabled for this to work.
+ This signal not only receives the body that stopped colliding with this one, but also its [RID] (body_id), the shape index from the colliding body (body_shape), and the shape index from this body (local_shape) the other body stopped colliding with.
</description>
</signal>
</signals>
<constants>
<constant name="MODE_STATIC" value="1">
- Static mode (does not move, can't be moved).
+ Static mode. The body behaves like a [StaticBody2D], and can only move by user code.
</constant>
<constant name="MODE_KINEMATIC" value="3">
+ Kinematic body. The body behaves like a [KinematicBody2D], and can only move by user code.
</constant>
<constant name="MODE_RIGID" value="0">
- Rigid body, can move and rotate.
+ Rigid body. This is the "natural" state of a rigid body. It is affected by forces, and can move, rotate, and be affected by user code.
</constant>
<constant name="MODE_CHARACTER" value="2">
- Character body, can move but not rotate.
+ Character body. This behaves like a rigid body, but can not rotate.
</constant>
<constant name="CCD_MODE_DISABLED" value="0">
+ Disables continuous collision detection. This is the fastest way to detect body collisions, but can miss small, fast-moving objects.
</constant>
<constant name="CCD_MODE_CAST_RAY" value="1">
+ Enables continuous collision detection by raycasting. It is faster than shapecasting, but less precise.
</constant>
<constant name="CCD_MODE_CAST_SHAPE" value="2">
+ Enables continuous collision detection by shapecasting. It is the slowest CCD method, and the most precise.
</constant>
</constants>
</class>
@@ -24585,29 +28798,29 @@
Room contains the data to define the bounds of a scene (using a BSP Tree). It is instanced by a [RoomInstance] node to create rooms. See that class documentation for more information about rooms.
</description>
<methods>
- <method name="set_room" >
+ <method name="set_room">
<argument index="0" name="room" type="Room">
</argument>
<description>
</description>
</method>
- <method name="get_room" qualifiers="const" >
+ <method name="get_room" qualifiers="const">
<return type="Room">
</return>
<description>
</description>
</method>
- <method name="compute_room_from_subtree" >
+ <method name="compute_room_from_subtree">
<description>
</description>
</method>
- <method name="set_simulate_acoustics" >
+ <method name="set_simulate_acoustics">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_simulating_acoustics" qualifiers="const" >
+ <method name="is_simulating_acoustics" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -24623,35 +28836,35 @@
<description>
</description>
<methods>
- <method name="set_bounds" >
+ <method name="set_bounds">
<argument index="0" name="bsp_tree" type="Dictionary">
</argument>
<description>
</description>
</method>
- <method name="get_bounds" qualifiers="const" >
+ <method name="get_bounds" qualifiers="const">
<return type="Dictionary">
</return>
<description>
</description>
</method>
- <method name="set_geometry_hint" >
+ <method name="set_geometry_hint">
<argument index="0" name="triangles" type="Vector3Array">
</argument>
<description>
</description>
</method>
- <method name="get_geometry_hint" qualifiers="const" >
+ <method name="get_geometry_hint" qualifiers="const">
<return type="Vector3Array">
</return>
<description>
</description>
</method>
- <method name="regenerate_bsp" >
+ <method name="regenerate_bsp">
<description>
</description>
</method>
- <method name="regenerate_bsp_cubic" >
+ <method name="regenerate_bsp_cubic">
<description>
</description>
</method>
@@ -24661,13 +28874,13 @@
</class>
<class name="Sample" inherits="Resource" category="Core">
<brief_description>
- Audio Sample (sound) class.
+ Audio sample (sound) class.
</brief_description>
<description>
Sample provides an audio sample class, containing audio data, together with some information for playback, such as format, mix rate and loop. It is used by sound playback routines.
</description>
<methods>
- <method name="create" >
+ <method name="create">
<argument index="0" name="format" type="int">
</argument>
<argument index="1" name="stereo" type="bool">
@@ -24675,194 +28888,200 @@
<argument index="2" name="length" type="int">
</argument>
<description>
- Create new data for the sample, with format "format" (see FORMAT_* enum), stereo hint, and length in frames (not samples or bytes!) "frame". Calling create overrides previous existing data if it exists. Stereo samples are interleaved pairs of left and right (in that order) points
+ Create new data for the sample, with format (see FORMAT_* constants), stereo hint, and length in frames (not samples or bytes!).
+ Calling this method overrides previously existing data. Stereo samples are interleaved pairs of left and right points (in that order).
</description>
</method>
- <method name="get_format" qualifiers="const" >
+ <method name="get_format" qualifiers="const">
<return type="int">
</return>
<description>
- Return the sample format (see FORMAT_* enum).
+ Return the sample format.
</description>
</method>
- <method name="is_stereo" qualifiers="const" >
+ <method name="is_stereo" qualifiers="const">
<return type="bool">
</return>
<description>
- Return true if the sample was created stereo.
+ Return whether the current sample was created as stereo.
</description>
</method>
- <method name="get_length" qualifiers="const" >
+ <method name="get_length" qualifiers="const">
<return type="int">
</return>
<description>
Return the sample length in frames.
</description>
</method>
- <method name="set_data" >
+ <method name="set_data">
<argument index="0" name="data" type="RawArray">
</argument>
<description>
- Set sample data. Data must be little endian, no matter the host platform, and exactly as long to fit all frames. Example, if data is Stereo, 16 bits, 256 frames, it will be 1024 bytes long.
+ Set sample data. Data must be little endian, no matter the host platform, and exactly as long as to fit all frames.
+ For example, if data is stereo, 16 bits, 256 frames, it will be 1024 bytes long.
</description>
</method>
- <method name="get_data" qualifiers="const" >
+ <method name="get_data" qualifiers="const">
<return type="RawArray">
</return>
<description>
- Return sample data. Data will be endian, no matter with the host platform, and exactly as long to fit all frames. Example, if data is Stereo, 16 bits, 256 frames, it will be 1024 bytes long.
+ Return sample data as little endian.
</description>
</method>
- <method name="set_mix_rate" >
+ <method name="set_mix_rate">
<argument index="0" name="hz" type="int">
</argument>
<description>
Set the mix rate for the sample (expected playback frequency).
</description>
</method>
- <method name="get_mix_rate" qualifiers="const" >
+ <method name="get_mix_rate" qualifiers="const">
<return type="int">
</return>
<description>
- Return the mix rate for the sample (expected playback frequency).
+ Return the mix rate for the sample.
</description>
</method>
- <method name="set_loop_format" >
+ <method name="set_loop_format">
<argument index="0" name="format" type="int">
</argument>
<description>
- Set the loop format, see LOOP_* enum
+ Set the loop format (use LOOP_* constants as argument).
</description>
</method>
- <method name="get_loop_format" qualifiers="const" >
+ <method name="get_loop_format" qualifiers="const">
<return type="int">
</return>
<description>
- Return the loop format, see LOOP_* enum.
+ Return the loop format.
</description>
</method>
- <method name="set_loop_begin" >
+ <method name="set_loop_begin">
<argument index="0" name="pos" type="int">
</argument>
<description>
- Set the loop begin position, it must be a valid frame and less than the loop end position.
+ Set the loop begin position. It must be a valid frame and less than the loop end position.
</description>
</method>
- <method name="get_loop_begin" qualifiers="const" >
+ <method name="get_loop_begin" qualifiers="const">
<return type="int">
</return>
<description>
Return the loop begin position.
</description>
</method>
- <method name="set_loop_end" >
+ <method name="set_loop_end">
<argument index="0" name="pos" type="int">
</argument>
<description>
- Set the loop end position, it must be a valid frame and greater than the loop begin position.
+ Set the loop end position. It must be a valid frame and greater than the loop begin position.
</description>
</method>
- <method name="get_loop_end" qualifiers="const" >
+ <method name="get_loop_end" qualifiers="const">
<return type="int">
</return>
<description>
- Return the loop begin position.
+ Return the loop end position.
</description>
</method>
</methods>
<constants>
<constant name="FORMAT_PCM8" value="0">
- 8-Bits signed little endian PCM audio.
+ 8-bits signed little endian PCM audio.
</constant>
<constant name="FORMAT_PCM16" value="1">
- 16-Bits signed little endian PCM audio.
+ 16-bits signed little endian PCM audio.
</constant>
<constant name="FORMAT_IMA_ADPCM" value="2">
- Ima-ADPCM Audio.
+ IMA-ADPCM Audio.
</constant>
<constant name="LOOP_NONE" value="0">
No loop enabled.
</constant>
<constant name="LOOP_FORWARD" value="1">
- Forward looping (when playback reaches loop end, goes back to loop begin)
+ Forward looping (when playback reaches loop end, goes back to loop begin).
</constant>
<constant name="LOOP_PING_PONG" value="2">
- Ping-Pong looping (when playback reaches loop end, plays backward untilloop begin). Not available in all platforms.
+ Ping-pong looping (when playback reaches loop end, plays backward until loop begin). Not available in all platforms.
</constant>
</constants>
</class>
<class name="SampleLibrary" inherits="Resource" category="Core">
<brief_description>
- Library that contains a collection of Samples.
+ Library that contains a collection of samples.
</brief_description>
<description>
- Library that contains a collection of Samples, each identified by an text id. This is used as a data containeer for the majority of the SamplePlayer classes and derivatives.
+ Library that contains a collection of [Sample]s, each identified by a text ID. This is used as a data container for the majority of the SamplePlayer classes and derivatives.
</description>
<methods>
- <method name="add_sample" >
+ <method name="add_sample">
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="sample" type="Sample">
</argument>
<description>
- Add a sample to the library, with a given text id;
+ Add a sample to the library, with a given text ID.
</description>
</method>
- <method name="get_sample" qualifiers="const" >
+ <method name="get_sample" qualifiers="const">
<return type="Sample">
</return>
<argument index="0" name="name" type="String">
</argument>
<description>
- Return a sample from the library, from a given text-id. Return null if the sample is not found.
+ Return the sample from the library matching the given text ID. Return null if the sample is not found.
</description>
</method>
- <method name="has_sample" qualifiers="const" >
+ <method name="has_sample" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="name" type="String">
</argument>
<description>
- Return true if the sample text id exists in the library.
+ Return true if the sample text ID exists in the library.
</description>
</method>
- <method name="remove_sample" >
+ <method name="remove_sample">
<argument index="0" name="name" type="String">
</argument>
<description>
- Remove a sample given a specific text id.
+ Remove the sample matching the given text ID.
</description>
</method>
- <method name="sample_set_volume_db" >
+ <method name="sample_set_volume_db">
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="db" type="float">
</argument>
<description>
+ Set the volume (in dB) for the given sample.
</description>
</method>
- <method name="sample_get_volume_db" qualifiers="const" >
+ <method name="sample_get_volume_db" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="name" type="String">
</argument>
<description>
+ Return the volume (in dB) for the given sample.
</description>
</method>
- <method name="sample_set_pitch_scale" >
+ <method name="sample_set_pitch_scale">
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="pitch" type="float">
</argument>
<description>
+ Set the pitch scale for the given sample.
</description>
</method>
- <method name="sample_get_pitch_scale" qualifiers="const" >
+ <method name="sample_get_pitch_scale" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="name" type="String">
</argument>
<description>
+ Return the pitch scale for the given sample.
</description>
</method>
</methods>
@@ -24877,33 +29096,35 @@
SamplePlayer is a [Node] meant for simple sample playback. A library of samples is loaded and played back "as is", without positioning or anything.
</description>
<methods>
- <method name="set_sample_library" >
+ <method name="set_sample_library">
<argument index="0" name="library" type="SampleLibrary">
</argument>
<description>
+ Set the sample library for the player.
</description>
</method>
- <method name="get_sample_library" qualifiers="const" >
+ <method name="get_sample_library" qualifiers="const">
<return type="SampleLibrary">
</return>
<description>
+ Return the sample library used by the player.
</description>
</method>
- <method name="set_voice_count" >
+ <method name="set_polyphony">
<argument index="0" name="max_voices" type="int">
</argument>
<description>
- Set the amount of simultaneous voices that will be used for playback.
+ Set the polyphony of the player (maximum amount of simultaneous voices).
</description>
</method>
- <method name="get_voice_count" qualifiers="const" >
+ <method name="get_polyphony" qualifiers="const">
<return type="int">
</return>
<description>
- Return the amount of simultaneous voices that will be used for playback.
+ Return the polyphony of the player.
</description>
</method>
- <method name="play" >
+ <method name="play">
<return type="int">
</return>
<argument index="0" name="name" type="String">
@@ -24911,56 +29132,62 @@
<argument index="1" name="unique" type="bool" default="false">
</argument>
<description>
- Play back sample, given it"apos;s identifier "name". if "unique" is true, all othere previous samples will be stopped. The voice allocated for playback will be returned.
+ Play a sample referenced by its name.
+ Optionally, the playback can be made "unique" to force stopping all other samples currently played. The voices allocated for playback will then be returned.
</description>
</method>
- <method name="stop" >
+ <method name="stop">
<argument index="0" name="voice" type="int">
</argument>
<description>
- Stop a voice "voice". (see [method play]).
+ Stop a given voice.
</description>
</method>
- <method name="stop_all" >
+ <method name="stop_all">
<description>
+ Stop all playing voices.
</description>
</method>
- <method name="set_mix_rate" >
+ <method name="set_mix_rate">
<argument index="0" name="voice" type="int">
</argument>
<argument index="1" name="hz" type="int">
</argument>
<description>
- Change the mix rate of a voice "voice" to given "hz".
+ Set the mix rate (in Hz) of a given voice.
</description>
</method>
- <method name="set_pitch_scale" >
+ <method name="set_pitch_scale">
<argument index="0" name="voice" type="int">
</argument>
<argument index="1" name="ratio" type="float">
</argument>
<description>
- Scale the pitch (mix rate) of a voice by a ratio value "ratio". A ratio of 1.0 means the voice is unscaled.
+ Set the pitch scale of a given voice. A ratio of 1.0 is the normal scale.
</description>
</method>
- <method name="set_volume" >
+ <method name="set_volume">
<argument index="0" name="voice" type="int">
</argument>
- <argument index="1" name="nrg" type="float">
+ <argument index="1" name="volume" type="float">
</argument>
<description>
- Set the volume of a voice, 0db is maximum volume (every about -6db, volume is reduced in half). "db" does in fact go from zero to negative.
+ Set the volume of a given voice using a linear scale.
+ The "volume" argument should be a positive factor ranging from 0.0 (mute) up to 16.0 (i.e. 24 dB).
+ A factor of 1.0 means that the voice will be played at normal system volume. Factors above 1.0 might be limited by the platform's audio output.
</description>
</method>
- <method name="set_volume_db" >
+ <method name="set_volume_db">
<argument index="0" name="voice" type="int">
</argument>
- <argument index="1" name="nrg" type="float">
+ <argument index="1" name="db" type="float">
</argument>
<description>
+ Set the volume of a given voice in dB.
+ The "dB" argument can range from -80 to 24 dB, 0 dB being the maximum volume. Every 6 dB (resp. -6 dB), the volume is increased (resp. reduced) by half.
</description>
</method>
- <method name="set_pan" >
+ <method name="set_pan">
<argument index="0" name="voice" type="int">
</argument>
<argument index="1" name="pan" type="float">
@@ -24970,10 +29197,11 @@
<argument index="3" name="height" type="float" default="0">
</argument>
<description>
- Set the panning of a voice. Panning goes from -1 (left) to +1 (right). Optionally, if the hardware supports 3D sound, also set depth and height (also in range -1 to +1).
+ Set the panning of a voice. Panning goes from -1.0 (left) to +1.0 (right).
+ Optionally, for hardware than support 3D sound, one can also set depth and height (also in range -1.0 to +1.0).
</description>
</method>
- <method name="set_filter" >
+ <method name="set_filter">
<argument index="0" name="voice" type="int">
</argument>
<argument index="1" name="type" type="int">
@@ -24985,19 +29213,20 @@
<argument index="4" name="gain" type="float" default="0">
</argument>
<description>
- Set and enable a filter of a voice, with type "type" (see FILTER_* enum), cutoff (0 to 22khz) frequency and resonance (0+).
+ Set the filter for a given voice, using the given type (see FILTER_* constants), cutoff frequency (from 20 to 16,384 Hz) and resonance (from 0 to 4.0).
+ Optionally, a gain can also be given (from 0 to 2.0).
</description>
</method>
- <method name="set_chorus" >
+ <method name="set_chorus">
<argument index="0" name="voice" type="int">
</argument>
<argument index="1" name="send" type="float">
</argument>
<description>
- Set the chorus send level of a voice (0 to 1). For setting chorus parameters, see [AudioServer].
+ Set the chorus send level of a voice (from 0 to 1.0). For setting chorus parameters, see [AudioServer].
</description>
</method>
- <method name="set_reverb" >
+ <method name="set_reverb">
<argument index="0" name="voice" type="int">
</argument>
<argument index="1" name="room_type" type="int">
@@ -25005,10 +29234,10 @@
<argument index="2" name="send" type="float">
</argument>
<description>
- Set the reverb send level and type of a voice (0 to 1). (see REVERB_* enum for type).
+ Set the reverberation type (see REVERB_* constants) and send level (from 0 to 1.0) of a voice.
</description>
</method>
- <method name="get_mix_rate" qualifiers="const" >
+ <method name="get_mix_rate" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="voice" type="int">
@@ -25017,7 +29246,7 @@
Return the current mix rate for a given voice.
</description>
</method>
- <method name="get_pitch_scale" qualifiers="const" >
+ <method name="get_pitch_scale" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="voice" type="int">
@@ -25026,131 +29255,139 @@
Return the current pitch scale for a given voice.
</description>
</method>
- <method name="get_volume" qualifiers="const" >
+ <method name="get_volume" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="voice" type="int">
</argument>
<description>
- Return the current volume (in db) for a given voice. 0db is maximum volume (every about -6db, volume is reduced in half). "db" does in fact go from zero to negative.
+ Return the current volume (on a linear scale) for a given voice.
</description>
</method>
- <method name="get_volume_db" qualifiers="const" >
+ <method name="get_volume_db" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="voice" type="int">
</argument>
<description>
+ Return the current volume (in dB) for a given voice.
</description>
</method>
- <method name="get_pan" qualifiers="const" >
+ <method name="get_pan" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="voice" type="int">
</argument>
<description>
- Return the current panning for a given voice. Panning goes from -1 (left) to +1 (right).
+ Return the current panning for a given voice.
</description>
</method>
- <method name="get_pan_depth" qualifiers="const" >
+ <method name="get_pan_depth" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="voice" type="int">
</argument>
<description>
- Return the current pan depth for a given voice (not used unless the hardware supports 3D sound)
+ Return the current pan depth for a given voice.
</description>
</method>
- <method name="get_pan_height" qualifiers="const" >
+ <method name="get_pan_height" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="voice" type="int">
</argument>
<description>
- Return the current pan height for a given voice (not used unless the hardware supports 3D sound)
+ Return the current pan height for a given voice.
</description>
</method>
- <method name="get_filter_type" qualifiers="const" >
+ <method name="get_filter_type" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="voice" type="int">
</argument>
<description>
- Return the current filter type in use (see FILTER_* enum) for a given voice.
+ Return the current filter type in use (see FILTER_* constants) for a given voice.
</description>
</method>
- <method name="get_filter_cutoff" qualifiers="const" >
+ <method name="get_filter_cutoff" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="voice" type="int">
</argument>
<description>
- Return the current filter cutoff for a given voice. Cutoff goes from 0 to 22khz.
+ Return the current filter cutoff frequency for a given voice.
</description>
</method>
- <method name="get_filter_resonance" qualifiers="const" >
+ <method name="get_filter_resonance" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="voice" type="int">
</argument>
<description>
- Return the current filter resonance for a given voice. Resonance goes from 0 up.
+ Return the current filter resonance for a given voice.
</description>
</method>
- <method name="get_filter_gain" qualifiers="const" >
+ <method name="get_filter_gain" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="voice" type="int">
</argument>
<description>
+ Return the current filter gain for a given voice.
</description>
</method>
- <method name="get_chorus" qualifiers="const" >
+ <method name="get_chorus" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="voice" type="int">
</argument>
<description>
- Return the current chorus send level for a given voice. (0 to 1).
+ Return the current chorus send level for a given voice.
</description>
</method>
- <method name="get_reverb_room" qualifiers="const" >
- <return type="float">
+ <method name="get_reverb_room" qualifiers="const">
+ <return type="int">
</return>
<argument index="0" name="voice" type="int">
</argument>
<description>
- Return the current reverb room type for a given voice (see REVERB_* enum).
+ Return the current reverberation room type for a given voice (see REVERB_* enum).
</description>
</method>
- <method name="get_reverb" qualifiers="const" >
+ <method name="get_reverb" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="voice" type="int">
</argument>
<description>
- Return the current reverb send level for a given voice. (0 to 1).
+ Return the current reverberation send level for a given voice.
</description>
</method>
- <method name="set_default_pitch_scale" >
+ <method name="set_default_pitch_scale">
<argument index="0" name="ratio" type="float">
</argument>
<description>
+ Set the default pitch scale of the player. A ratio of 1.0 is the normal scale.
</description>
</method>
- <method name="set_default_volume" >
- <argument index="0" name="nrg" type="float">
+ <method name="set_default_volume">
+ <argument index="0" name="volume" type="float">
</argument>
<description>
+ Set the default volume of the player using a linear scale.
+ The "volume" argument should be a positive factor ranging from 0.0 (mute) up to 16.0 (i.e. 24 dB).
+ A factor of 1.0 means that the voice will be played at normal system volume. Factors above 1.0 might be limited by the platform's audio output.
</description>
</method>
- <method name="set_default_volume_db" >
+ <method name="set_default_volume_db">
<argument index="0" name="db" type="float">
</argument>
<description>
+ Set the default volume of the player in dB.
+ The "dB" argument can range from -80 to 24 dB, 0 dB being the maximum volume. Every 6 dB (resp. -6 dB), the volume is increased (resp. reduced) by half.
</description>
</method>
- <method name="set_default_pan" >
+ <method name="set_default_pan">
<argument index="0" name="pan" type="float">
</argument>
<argument index="1" name="depth" type="float" default="0">
@@ -25158,9 +29395,11 @@
<argument index="2" name="height" type="float" default="0">
</argument>
<description>
+ Set the default panning of the player. Panning goes from -1.0 (left) to +1.0 (right).
+ Optionally, for hardware than support 3D sound, one can also set depth and height (also in range -1.0 to +1.0).
</description>
</method>
- <method name="set_default_filter" >
+ <method name="set_default_filter">
<argument index="0" name="type" type="int">
</argument>
<argument index="1" name="cutoff_hz" type="float">
@@ -25170,112 +29409,131 @@
<argument index="3" name="gain" type="float" default="0">
</argument>
<description>
+ Set the default filter for the player, using the given type (see FILTER_* constants), cutoff frequency (from 20 to 16,384 Hz) and resonance (from 0 to 4.0).
+ Optionally, a gain can also be given (from 0 to 2.0).
</description>
</method>
- <method name="set_default_chorus" >
+ <method name="set_default_chorus">
<argument index="0" name="send" type="float">
</argument>
<description>
+ Set the default chorus send level of the player (from 0 to 1.0). For setting chorus parameters, see [AudioServer].
</description>
</method>
- <method name="set_default_reverb" >
+ <method name="set_default_reverb">
<argument index="0" name="room_type" type="int">
</argument>
<argument index="1" name="send" type="float">
</argument>
<description>
+ Set the default reverberation type (see REVERB_* constants) and send level (from 0 to 1.0) of the player.
</description>
</method>
- <method name="get_default_pitch_scale" qualifiers="const" >
+ <method name="get_default_pitch_scale" qualifiers="const">
<return type="float">
</return>
<description>
+ Return the default pitch scale of the player.
</description>
</method>
- <method name="get_default_volume" qualifiers="const" >
+ <method name="get_default_volume" qualifiers="const">
<return type="float">
</return>
<description>
+ Return the default volume (on a linear scale) of the player.
</description>
</method>
- <method name="get_default_volume_db" qualifiers="const" >
+ <method name="get_default_volume_db" qualifiers="const">
<return type="float">
</return>
<description>
+ Return the default volume (in dB) of the player.
</description>
</method>
- <method name="get_default_pan" qualifiers="const" >
+ <method name="get_default_pan" qualifiers="const">
<return type="float">
</return>
<description>
+ Return the default panning of the player.
</description>
</method>
- <method name="get_default_pan_depth" qualifiers="const" >
+ <method name="get_default_pan_depth" qualifiers="const">
<return type="float">
</return>
<description>
+ Return the default pan depth of the player.
</description>
</method>
- <method name="get_default_pan_height" qualifiers="const" >
+ <method name="get_default_pan_height" qualifiers="const">
<return type="float">
</return>
<description>
+ Return the default pan height of the player.
</description>
</method>
- <method name="get_default_filter_type" qualifiers="const" >
+ <method name="get_default_filter_type" qualifiers="const">
<return type="int">
</return>
<description>
+ Return the default filter type in use (see FILTER_* constants) for the player.
</description>
</method>
- <method name="get_default_filter_cutoff" qualifiers="const" >
+ <method name="get_default_filter_cutoff" qualifiers="const">
<return type="float">
</return>
<description>
+ Return the default filter cutoff frequency of the player.
</description>
</method>
- <method name="get_default_filter_resonance" qualifiers="const" >
+ <method name="get_default_filter_resonance" qualifiers="const">
<return type="float">
</return>
<description>
+ Return the default filter resonance of the player.
</description>
</method>
- <method name="get_default_filter_gain" qualifiers="const" >
+ <method name="get_default_filter_gain" qualifiers="const">
<return type="float">
</return>
<description>
+ Return the default filter gain of the player.
</description>
</method>
- <method name="get_default_chorus" qualifiers="const" >
+ <method name="get_default_chorus" qualifiers="const">
<return type="float">
</return>
<description>
+ Return the default chorus send level of the player.
</description>
</method>
- <method name="get_default_reverb_room" qualifiers="const" >
- <return type="float">
+ <method name="get_default_reverb_room" qualifiers="const">
+ <return type="int">
</return>
<description>
+ Return the default reverberation room type of the player (see REVERB_* enum).
</description>
</method>
- <method name="get_default_reverb" qualifiers="const" >
+ <method name="get_default_reverb" qualifiers="const">
<return type="float">
</return>
<description>
+ Return the default reverberation send level of the player.
</description>
</method>
- <method name="is_active" qualifiers="const" >
+ <method name="is_active" qualifiers="const">
<return type="bool">
</return>
<description>
+ Return whether the player is currently active.
</description>
</method>
- <method name="is_voice_active" qualifiers="const" >
+ <method name="is_voice_active" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="voice" type="int">
</argument>
<description>
+ Return whether the given voice is currently active.
</description>
</method>
</methods>
@@ -25284,77 +29542,83 @@
Filter is disabled for voice.
</constant>
<constant name="FILTER_LOWPASS" value="1">
- Lowpass filter is used for voice.
+ Low-pass filter is used for voice.
</constant>
<constant name="FILTER_BANDPASS" value="2">
- Bandpass filter is used for voice.
+ Band-pass filter is used for voice.
</constant>
<constant name="FILTER_HIPASS" value="3">
- HighPass filter is used for voice.
+ High-pass filter is used for voice.
</constant>
<constant name="FILTER_NOTCH" value="4">
- Notch filter is used for voice.
+ Notch (band reject) filter is used for voice.
</constant>
<constant name="FILTER_PEAK" value="5">
+ Peak (exclusive band) filter is used for voice.
</constant>
<constant name="FILTER_BANDLIMIT" value="6">
- Band-Limit filter is used for voice, in this case resonance is the highpass cutoff.
+ Band-limit filter is used for voice, in this case resonance is the high-pass cutoff. A band-limit filter has a different frequency response than a notch filter, but otherwise both are band-rejecting filters.
</constant>
<constant name="FILTER_LOW_SHELF" value="7">
+ Low-shelf filter is used for voice.
</constant>
<constant name="FILTER_HIGH_SHELF" value="8">
+ High-shelf filter is used for voice.
</constant>
<constant name="REVERB_SMALL" value="0">
- Small reverb room (house room).
+ Small reverberation room (house room).
</constant>
<constant name="REVERB_MEDIUM" value="1">
- Medium reverb room (street)
+ Medium reverberation room (street)
</constant>
<constant name="REVERB_LARGE" value="2">
- Large reverb room (Theather)
+ Large reverberation room (theatre)
</constant>
<constant name="REVERB_HALL" value="3">
- Huge reverb room (cathedral, warehouse).
+ Huge reverberation room (cathedral, warehouse).
+ </constant>
+ <constant name="INVALID_VOICE_ID" value="-1">
+ Value returned if the voice ID is invalid.
</constant>
</constants>
</class>
<class name="SamplePlayer2D" inherits="SoundPlayer2D" category="Core">
<brief_description>
- Sample player for Positional 2D Sound.
+ Sample player for positional 2D Sound.
</brief_description>
<description>
- Sample player for Positional 2D Sound. Plays sound samples positionally, left and right depending on the distance/place on the screen.
+ Sample player for positional 2D Sound. Plays sound samples positionally, left and right depending on the distance/place on the screen.
</description>
<methods>
- <method name="set_sample_library" >
+ <method name="set_sample_library">
<argument index="0" name="library" type="SampleLibrary">
</argument>
<description>
Set the sample library for the player.
</description>
</method>
- <method name="get_sample_library" qualifiers="const" >
+ <method name="get_sample_library" qualifiers="const">
<return type="SampleLibrary">
</return>
<description>
- Return the sample library used for the player.
+ Return the sample library used by the player.
</description>
</method>
- <method name="set_polyphony" >
- <argument index="0" name="voices" type="int">
+ <method name="set_polyphony">
+ <argument index="0" name="max_voices" type="int">
</argument>
<description>
Set the polyphony of the player (maximum amount of simultaneous voices).
</description>
</method>
- <method name="get_polyphony" qualifiers="const" >
+ <method name="get_polyphony" qualifiers="const">
<return type="int">
</return>
<description>
- Return the polyphony of the player (maximum amount of simultaneous voices).
+ Return the polyphony of the player.
</description>
</method>
- <method name="play" >
+ <method name="play">
<return type="int">
</return>
<argument index="0" name="sample" type="String">
@@ -25362,10 +29626,11 @@
<argument index="1" name="voice" type="int" default="-2">
</argument>
<description>
- Play a sample, an internal polyphony id can be passed, or else it's assigned automatically. Returns a voice id which can be used to modify the voice parameters.
+ Play a sample. An internal polyphony ID can optionally be passed, or defaults to NEXT_VOICE.
+ Return a voice ID which can be used to modify the voice parameters, or INVALID_VOICE if the voice or sample are invalid.
</description>
</method>
- <method name="voice_set_pitch_scale" >
+ <method name="voice_set_pitch_scale">
<argument index="0" name="voice" type="int">
</argument>
<argument index="1" name="ratio" type="float">
@@ -25374,54 +29639,60 @@
Change the pitch scale of a currently playing voice.
</description>
</method>
- <method name="voice_set_volume_scale_db" >
+ <method name="voice_set_volume_scale_db">
<argument index="0" name="voice" type="int">
</argument>
<argument index="1" name="db" type="float">
</argument>
<description>
- Change the volume scale of a currently playing voice (using dB).
+ Change the volume scale (in dB) of a currently playing voice.
</description>
</method>
- <method name="is_voice_active" qualifiers="const" >
+ <method name="is_voice_active" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="voice" type="int">
</argument>
<description>
- Return true if a voice is still active (false if it stopped playing).
+ Return whether a voice is still active or has stopped playing.
</description>
</method>
- <method name="stop_voice" >
+ <method name="stop_voice">
<argument index="0" name="voice" type="int">
</argument>
<description>
Stop a given voice.
</description>
</method>
- <method name="stop_all" >
+ <method name="stop_all">
<description>
Stop all playing voices.
</description>
</method>
- <method name="set_random_pitch_scale" >
+ <method name="set_random_pitch_scale">
<argument index="0" name="val" type="float">
</argument>
<description>
+ Set the amplitude for random pitch scale variations. If different from zero, the pitch scale will vary randomly around 1.0 in a range defined by val.
+ The actual pitch scale will be, with "variation" ranging from -val to val:
+ * variation &gt; 0: 1.0 + variation
+ * variation &lt; 0: 1.0/(1.0 - variation)
</description>
</method>
- <method name="get_random_pitch_scale" qualifiers="const" >
+ <method name="get_random_pitch_scale" qualifiers="const">
<return type="float">
</return>
<description>
+ Return the amplitude used for random pitch scale variations.
</description>
</method>
</methods>
<constants>
<constant name="INVALID_VOICE" value="-1">
- If the voice is invalid, this is returned.
+ Value returned if the voice or sample are invalid.
</constant>
<constant name="NEXT_VOICE" value="-2">
+ Default voice for the play method. Corresponds to the first voice following the last used voice.
</constant>
</constants>
</class>
@@ -25431,7 +29702,7 @@
<description>
</description>
<methods>
- <method name="notify_group" >
+ <method name="notify_group">
<argument index="0" name="call_flags" type="int">
</argument>
<argument index="1" name="group" type="String">
@@ -25441,7 +29712,7 @@
<description>
</description>
</method>
- <method name="set_group" >
+ <method name="set_group">
<argument index="0" name="call_flags" type="int">
</argument>
<argument index="1" name="group" type="String">
@@ -25453,83 +29724,115 @@
<description>
</description>
</method>
- <method name="get_nodes_in_group" >
+ <method name="get_nodes_in_group">
<return type="Array">
</return>
- <argument index="0" name="arg0" type="String">
+ <argument index="0" name="group" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_root" qualifiers="const" >
+ <method name="get_root" qualifiers="const">
<return type="Viewport">
</return>
<description>
</description>
</method>
- <method name="set_auto_accept_quit" >
+ <method name="has_group" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="name" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_auto_accept_quit">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="set_editor_hint" >
+ <method name="set_editor_hint">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_editor_hint" qualifiers="const" >
+ <method name="is_editor_hint" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_edited_scene_root" >
+ <method name="set_debug_collisions_hint">
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_debugging_collisions_hint" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_debug_navigation_hint">
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_debugging_navigation_hint" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_edited_scene_root">
<argument index="0" name="scene" type="Object">
</argument>
<description>
</description>
</method>
- <method name="get_edited_scene_root" qualifiers="const" >
+ <method name="get_edited_scene_root" qualifiers="const">
<return type="Object">
</return>
<description>
</description>
</method>
- <method name="set_pause" >
+ <method name="set_pause">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_paused" qualifiers="const" >
+ <method name="is_paused" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_input_as_handled" >
+ <method name="set_input_as_handled">
<description>
</description>
</method>
- <method name="get_node_count" qualifiers="const" >
+ <method name="get_node_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_frame" qualifiers="const" >
+ <method name="get_frame" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="quit" >
+ <method name="quit">
<description>
</description>
</method>
- <method name="set_screen_stretch" >
+ <method name="set_screen_stretch">
<argument index="0" name="mode" type="int">
</argument>
<argument index="1" name="aspect" type="int">
@@ -25539,13 +29842,13 @@
<description>
</description>
</method>
- <method name="queue_delete" >
+ <method name="queue_delete">
<argument index="0" name="obj" type="Object">
</argument>
<description>
</description>
</method>
- <method name="call_group" >
+ <method name="call_group">
<argument index="0" name="flags" type="int">
</argument>
<argument index="1" name="group" type="String">
@@ -25565,6 +29868,40 @@
<description>
</description>
</method>
+ <method name="set_current_scene">
+ <argument index="0" name="child_node" type="Node">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_current_scene" qualifiers="const">
+ <return type="Node">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="change_scene">
+ <return type="int">
+ </return>
+ <argument index="0" name="path" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="change_scene_to">
+ <return type="int">
+ </return>
+ <argument index="0" name="packed_scene" type="PackedScene">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="reload_current_scene">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<signals>
<signal name="screen_resized">
@@ -25577,10 +29914,18 @@
<description>
</description>
</signal>
+ <signal name="idle_frame">
+ <description>
+ </description>
+ </signal>
<signal name="tree_changed">
<description>
</description>
</signal>
+ <signal name="fixed_frame">
+ <description>
+ </description>
+ </signal>
</signals>
<constants>
<constant name="GROUP_CALL_DEFAULT" value="0">
@@ -25615,14 +29960,14 @@
Base class for scripts. Any script that is loaded becomes one of these resources, which can then create instances.
</description>
<methods>
- <method name="can_instance" qualifiers="const" >
+ <method name="can_instance" qualifiers="const">
<return type="bool">
</return>
<description>
Return true if this script can be instance (ie not a library).
</description>
</method>
- <method name="instance_has" qualifiers="const" >
+ <method name="instance_has" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="base_object" type="Object">
@@ -25631,28 +29976,28 @@
Return true if a given object uses an instance of this script.
</description>
</method>
- <method name="has_source_code" qualifiers="const" >
+ <method name="has_source_code" qualifiers="const">
<return type="bool">
</return>
<description>
Return true if the script contains source code.
</description>
</method>
- <method name="get_source_code" qualifiers="const" >
+ <method name="get_source_code" qualifiers="const">
<return type="String">
</return>
<description>
Return the script source code (if available).
</description>
</method>
- <method name="set_source_code" >
+ <method name="set_source_code">
<argument index="0" name="source" type="String">
</argument>
<description>
Set the script source code.
</description>
</method>
- <method name="reload" >
+ <method name="reload">
<return type="int">
</return>
<description>
@@ -25671,13 +30016,13 @@
Scrollbars are a [Range] based [Control], that display a draggable area (the size of the page). Horizontal ([HScrollBar]) and Vertical ([VScrollBar]) versions are available.
</description>
<methods>
- <method name="set_custom_step" >
+ <method name="set_custom_step">
<argument index="0" name="step" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_custom_step" qualifiers="const" >
+ <method name="get_custom_step" qualifiers="const">
<return type="float">
</return>
<description>
@@ -25689,53 +30034,55 @@
</class>
<class name="ScrollContainer" inherits="Container" category="Core">
<brief_description>
+ A helper node for displaying scollable elements (e.g. lists).
</brief_description>
<description>
+ A ScrollContainer node with a [Control] child and scrollbar child ([HScrollbar], [VScrollBar], or both) will only draw the Control within the ScrollContainer area. Scrollbars will automatically be drawn at the right (for vertical) or bottom (for horizontal) and will enable dragging to move the viewable Control (and its children) within the ScrollContainer. Scrollbars will also automatically resize the grabber based on the minimum_size of the Control relative to the ScrollContainer. Works great with a [Panel] control.
</description>
<methods>
- <method name="set_enable_h_scroll" >
+ <method name="set_enable_h_scroll">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_h_scroll_enabled" qualifiers="const" >
+ <method name="is_h_scroll_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_enable_v_scroll" >
+ <method name="set_enable_v_scroll">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_v_scroll_enabled" qualifiers="const" >
+ <method name="is_v_scroll_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_h_scroll" >
+ <method name="set_h_scroll">
<argument index="0" name="val" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_h_scroll" qualifiers="const" >
+ <method name="get_h_scroll" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_v_scroll" >
+ <method name="set_v_scroll">
<argument index="0" name="val" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_v_scroll" qualifiers="const" >
+ <method name="get_v_scroll" qualifiers="const">
<return type="int">
</return>
<description>
@@ -25753,28 +30100,32 @@
Segment Shape for 2D Collision Detection, consists of two points, 'a' and 'b'.
</description>
<methods>
- <method name="set_a" >
+ <method name="set_a">
<argument index="0" name="a" type="Vector2">
</argument>
<description>
+ Set the first point's position.
</description>
</method>
- <method name="get_a" qualifiers="const" >
+ <method name="get_a" qualifiers="const">
<return type="Vector2">
</return>
<description>
+ Return the first point's position.
</description>
</method>
- <method name="set_b" >
+ <method name="set_b">
<argument index="0" name="b" type="Vector2">
</argument>
<description>
+ Set the second point's position.
</description>
</method>
- <method name="get_b" qualifiers="const" >
+ <method name="get_b" qualifiers="const">
<return type="Vector2">
</return>
<description>
+ Return the second point's position.
</description>
</method>
</methods>
@@ -25787,14 +30138,14 @@
<description>
</description>
<methods>
- <method name="wait" >
- <return type="int">
+ <method name="wait">
+ <return type="Error">
</return>
<description>
</description>
</method>
- <method name="post" >
- <return type="int">
+ <method name="post">
+ <return type="Error">
</return>
<description>
</description>
@@ -25823,19 +30174,13 @@
To be changed, ignore.
</description>
<methods>
- <method name="set_mode" >
- <argument index="0" name="mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_mode" qualifiers="const" >
+ <method name="get_mode" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_code" >
+ <method name="set_code">
<argument index="0" name="vcode" type="String">
</argument>
<argument index="1" name="fcode" type="String">
@@ -25849,25 +30194,41 @@
<description>
</description>
</method>
- <method name="get_vertex_code" qualifiers="const" >
+ <method name="get_vertex_code" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="get_fragment_code" qualifiers="const" >
+ <method name="get_fragment_code" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="get_light_code" qualifiers="const" >
+ <method name="get_light_code" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="has_param" qualifiers="const" >
+ <method name="set_default_texture_param">
+ <argument index="0" name="param" type="String">
+ </argument>
+ <argument index="1" name="texture" type="Texture">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_default_texture_param" qualifiers="const">
+ <return type="Texture">
+ </return>
+ <argument index="0" name="param" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="has_param" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="name" type="String">
@@ -25885,33 +30246,905 @@
</constant>
</constants>
</class>
+<class name="ShaderGraph" inherits="Shader" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="node_add">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="node_type" type="int">
+ </argument>
+ <argument index="2" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="node_remove">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="node_set_pos">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <argument index="2" name="pos" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="node_get_pos" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="node_get_type" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_node_list" qualifiers="const">
+ <return type="Array">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="default_set_value">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <argument index="2" name="param_id" type="int">
+ </argument>
+ <argument index="3" name="value" type="var">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="default_get_value">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <argument index="2" name="param_id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="scalar_const_node_set_value">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <argument index="2" name="value" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="scalar_const_node_get_value" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="vec_const_node_set_value">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <argument index="2" name="value" type="Vector3">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="vec_const_node_get_value" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="rgb_const_node_set_value">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <argument index="2" name="value" type="Color">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="rgb_const_node_get_value" qualifiers="const">
+ <return type="Color">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="xform_const_node_set_value">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <argument index="2" name="value" type="Transform">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="xform_const_node_get_value" qualifiers="const">
+ <return type="Transform">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="texture_node_set_filter_size">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <argument index="2" name="filter_size" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="texture_node_get_filter_size" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="texture_node_set_filter_strength">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="float">
+ </argument>
+ <argument index="2" name="filter_strength" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="texture_node_get_filter_strength" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="scalar_op_node_set_op">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="float">
+ </argument>
+ <argument index="2" name="op" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="scalar_op_node_get_op" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="vec_op_node_set_op">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="float">
+ </argument>
+ <argument index="2" name="op" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="vec_op_node_get_op" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="vec_scalar_op_node_set_op">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="float">
+ </argument>
+ <argument index="2" name="op" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="vec_scalar_op_node_get_op" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="rgb_op_node_set_op">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="float">
+ </argument>
+ <argument index="2" name="op" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="rgb_op_node_get_op" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="xform_vec_mult_node_set_no_translation">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <argument index="2" name="disable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="xform_vec_mult_node_get_no_translation" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="scalar_func_node_set_function">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <argument index="2" name="func" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="scalar_func_node_get_function" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="vec_func_node_set_function">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <argument index="2" name="func" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="vec_func_node_get_function" qualifiers="const">
+ <return type="int">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="input_node_set_name">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <argument index="2" name="name" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="input_node_get_name">
+ <return type="String">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="scalar_input_node_set_value">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <argument index="2" name="value" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="scalar_input_node_get_value" qualifiers="const">
+ <return type="float">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="vec_input_node_set_value">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <argument index="2" name="value" type="Vector3">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="vec_input_node_get_value" qualifiers="const">
+ <return type="Vector3">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="rgb_input_node_set_value">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <argument index="2" name="value" type="Color">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="rgb_input_node_get_value" qualifiers="const">
+ <return type="Color">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="xform_input_node_set_value">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <argument index="2" name="value" type="Transform">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="xform_input_node_get_value" qualifiers="const">
+ <return type="Transform">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="texture_input_node_set_value">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <argument index="2" name="value" type="Texture">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="texture_input_node_get_value" qualifiers="const">
+ <return type="Texture">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="cubemap_input_node_set_value">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <argument index="2" name="value" type="CubeMap">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="cubemap_input_node_get_value" qualifiers="const">
+ <return type="CubeMap">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="comment_node_set_text">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <argument index="2" name="text" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="comment_node_get_text" qualifiers="const">
+ <return type="String">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="color_ramp_node_set_ramp">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <argument index="2" name="colors" type="ColorArray">
+ </argument>
+ <argument index="3" name="offsets" type="RealArray">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="color_ramp_node_get_colors" qualifiers="const">
+ <return type="ColorArray">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="color_ramp_node_get_offsets" qualifiers="const">
+ <return type="RealArray">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="curve_map_node_set_points">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <argument index="2" name="points" type="Vector2Array">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="curve_map_node_get_points" qualifiers="const">
+ <return type="Vector2Array">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="connect_node">
+ <return type="Error">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="src_id" type="int">
+ </argument>
+ <argument index="2" name="src_slot" type="int">
+ </argument>
+ <argument index="3" name="dst_id" type="int">
+ </argument>
+ <argument index="4" name="dst_slot" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_node_connected" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="src_id" type="int">
+ </argument>
+ <argument index="2" name="src_slot" type="int">
+ </argument>
+ <argument index="3" name="dst_id" type="int">
+ </argument>
+ <argument index="4" name="dst_slot" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="disconnect_node">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="src_id" type="int">
+ </argument>
+ <argument index="2" name="src_slot" type="int">
+ </argument>
+ <argument index="3" name="dst_id" type="int">
+ </argument>
+ <argument index="4" name="dst_slot" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_node_connections" qualifiers="const">
+ <return type="Array">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="clear">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="node_set_state">
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <argument index="2" name="state" type="var">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="node_get_state" qualifiers="const">
+ <return type="Variant">
+ </return>
+ <argument index="0" name="shader_type" type="int">
+ </argument>
+ <argument index="1" name="id" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <signals>
+ <signal name="updated">
+ <description>
+ </description>
+ </signal>
+ </signals>
+ <constants>
+ <constant name="NODE_INPUT" value="0">
+ </constant>
+ <constant name="NODE_SCALAR_CONST" value="1">
+ </constant>
+ <constant name="NODE_VEC_CONST" value="2">
+ </constant>
+ <constant name="NODE_RGB_CONST" value="3">
+ </constant>
+ <constant name="NODE_XFORM_CONST" value="4">
+ </constant>
+ <constant name="NODE_TIME" value="5">
+ </constant>
+ <constant name="NODE_SCREEN_TEX" value="6">
+ </constant>
+ <constant name="NODE_SCALAR_OP" value="7">
+ </constant>
+ <constant name="NODE_VEC_OP" value="8">
+ </constant>
+ <constant name="NODE_VEC_SCALAR_OP" value="9">
+ </constant>
+ <constant name="NODE_RGB_OP" value="10">
+ </constant>
+ <constant name="NODE_XFORM_MULT" value="11">
+ </constant>
+ <constant name="NODE_XFORM_VEC_MULT" value="12">
+ </constant>
+ <constant name="NODE_XFORM_VEC_INV_MULT" value="13">
+ </constant>
+ <constant name="NODE_SCALAR_FUNC" value="14">
+ </constant>
+ <constant name="NODE_VEC_FUNC" value="15">
+ </constant>
+ <constant name="NODE_VEC_LEN" value="16">
+ </constant>
+ <constant name="NODE_DOT_PROD" value="17">
+ </constant>
+ <constant name="NODE_VEC_TO_SCALAR" value="18">
+ </constant>
+ <constant name="NODE_SCALAR_TO_VEC" value="19">
+ </constant>
+ <constant name="NODE_VEC_TO_XFORM" value="21">
+ </constant>
+ <constant name="NODE_XFORM_TO_VEC" value="20">
+ </constant>
+ <constant name="NODE_SCALAR_INTERP" value="22">
+ </constant>
+ <constant name="NODE_VEC_INTERP" value="23">
+ </constant>
+ <constant name="NODE_COLOR_RAMP" value="24">
+ </constant>
+ <constant name="NODE_CURVE_MAP" value="25">
+ </constant>
+ <constant name="NODE_SCALAR_INPUT" value="26">
+ </constant>
+ <constant name="NODE_VEC_INPUT" value="27">
+ </constant>
+ <constant name="NODE_RGB_INPUT" value="28">
+ </constant>
+ <constant name="NODE_XFORM_INPUT" value="29">
+ </constant>
+ <constant name="NODE_TEXTURE_INPUT" value="30">
+ </constant>
+ <constant name="NODE_CUBEMAP_INPUT" value="31">
+ </constant>
+ <constant name="NODE_DEFAULT_TEXTURE" value="32">
+ </constant>
+ <constant name="NODE_OUTPUT" value="33">
+ </constant>
+ <constant name="NODE_COMMENT" value="34">
+ </constant>
+ <constant name="NODE_TYPE_MAX" value="35">
+ </constant>
+ <constant name="SLOT_TYPE_SCALAR" value="0">
+ </constant>
+ <constant name="SLOT_TYPE_VEC" value="1">
+ </constant>
+ <constant name="SLOT_TYPE_XFORM" value="2">
+ </constant>
+ <constant name="SLOT_TYPE_TEXTURE" value="3">
+ </constant>
+ <constant name="SLOT_MAX" value="4">
+ </constant>
+ <constant name="SHADER_TYPE_VERTEX" value="0">
+ </constant>
+ <constant name="SHADER_TYPE_FRAGMENT" value="1">
+ </constant>
+ <constant name="SHADER_TYPE_LIGHT" value="2">
+ </constant>
+ <constant name="SHADER_TYPE_MAX" value="3">
+ </constant>
+ <constant name="SLOT_IN" value="0">
+ </constant>
+ <constant name="SLOT_OUT" value="1">
+ </constant>
+ <constant name="GRAPH_OK" value="0">
+ </constant>
+ <constant name="GRAPH_ERROR_CYCLIC" value="1">
+ </constant>
+ <constant name="GRAPH_ERROR_MISSING_CONNECTIONS" value="2">
+ </constant>
+ <constant name="SCALAR_OP_ADD" value="0">
+ </constant>
+ <constant name="SCALAR_OP_SUB" value="1">
+ </constant>
+ <constant name="SCALAR_OP_MUL" value="2">
+ </constant>
+ <constant name="SCALAR_OP_DIV" value="3">
+ </constant>
+ <constant name="SCALAR_OP_MOD" value="4">
+ </constant>
+ <constant name="SCALAR_OP_POW" value="5">
+ </constant>
+ <constant name="SCALAR_OP_MAX" value="6">
+ </constant>
+ <constant name="SCALAR_OP_MIN" value="7">
+ </constant>
+ <constant name="SCALAR_OP_ATAN2" value="8">
+ </constant>
+ <constant name="SCALAR_MAX_OP" value="9">
+ </constant>
+ <constant name="VEC_OP_ADD" value="0">
+ </constant>
+ <constant name="VEC_OP_SUB" value="1">
+ </constant>
+ <constant name="VEC_OP_MUL" value="2">
+ </constant>
+ <constant name="VEC_OP_DIV" value="3">
+ </constant>
+ <constant name="VEC_OP_MOD" value="4">
+ </constant>
+ <constant name="VEC_OP_POW" value="5">
+ </constant>
+ <constant name="VEC_OP_MAX" value="6">
+ </constant>
+ <constant name="VEC_OP_MIN" value="7">
+ </constant>
+ <constant name="VEC_OP_CROSS" value="8">
+ </constant>
+ <constant name="VEC_MAX_OP" value="9">
+ </constant>
+ <constant name="VEC_SCALAR_OP_MUL" value="0">
+ </constant>
+ <constant name="VEC_SCALAR_OP_DIV" value="1">
+ </constant>
+ <constant name="VEC_SCALAR_OP_POW" value="2">
+ </constant>
+ <constant name="VEC_SCALAR_MAX_OP" value="3">
+ </constant>
+ <constant name="RGB_OP_SCREEN" value="0">
+ </constant>
+ <constant name="RGB_OP_DIFFERENCE" value="1">
+ </constant>
+ <constant name="RGB_OP_DARKEN" value="2">
+ </constant>
+ <constant name="RGB_OP_LIGHTEN" value="3">
+ </constant>
+ <constant name="RGB_OP_OVERLAY" value="4">
+ </constant>
+ <constant name="RGB_OP_DODGE" value="5">
+ </constant>
+ <constant name="RGB_OP_BURN" value="6">
+ </constant>
+ <constant name="RGB_OP_SOFT_LIGHT" value="7">
+ </constant>
+ <constant name="RGB_OP_HARD_LIGHT" value="8">
+ </constant>
+ <constant name="RGB_MAX_OP" value="9">
+ </constant>
+ <constant name="SCALAR_FUNC_SIN" value="0">
+ </constant>
+ <constant name="SCALAR_FUNC_COS" value="1">
+ </constant>
+ <constant name="SCALAR_FUNC_TAN" value="2">
+ </constant>
+ <constant name="SCALAR_FUNC_ASIN" value="3">
+ </constant>
+ <constant name="SCALAR_FUNC_ACOS" value="4">
+ </constant>
+ <constant name="SCALAR_FUNC_ATAN" value="5">
+ </constant>
+ <constant name="SCALAR_FUNC_SINH" value="6">
+ </constant>
+ <constant name="SCALAR_FUNC_COSH" value="7">
+ </constant>
+ <constant name="SCALAR_FUNC_TANH" value="8">
+ </constant>
+ <constant name="SCALAR_FUNC_LOG" value="9">
+ </constant>
+ <constant name="SCALAR_FUNC_EXP" value="10">
+ </constant>
+ <constant name="SCALAR_FUNC_SQRT" value="11">
+ </constant>
+ <constant name="SCALAR_FUNC_ABS" value="12">
+ </constant>
+ <constant name="SCALAR_FUNC_SIGN" value="13">
+ </constant>
+ <constant name="SCALAR_FUNC_FLOOR" value="14">
+ </constant>
+ <constant name="SCALAR_FUNC_ROUND" value="15">
+ </constant>
+ <constant name="SCALAR_FUNC_CEIL" value="16">
+ </constant>
+ <constant name="SCALAR_FUNC_FRAC" value="17">
+ </constant>
+ <constant name="SCALAR_FUNC_SATURATE" value="18">
+ </constant>
+ <constant name="SCALAR_FUNC_NEGATE" value="19">
+ </constant>
+ <constant name="SCALAR_MAX_FUNC" value="20">
+ </constant>
+ <constant name="VEC_FUNC_NORMALIZE" value="0">
+ </constant>
+ <constant name="VEC_FUNC_SATURATE" value="1">
+ </constant>
+ <constant name="VEC_FUNC_NEGATE" value="2">
+ </constant>
+ <constant name="VEC_FUNC_RECIPROCAL" value="3">
+ </constant>
+ <constant name="VEC_FUNC_RGB2HSV" value="4">
+ </constant>
+ <constant name="VEC_FUNC_HSV2RGB" value="5">
+ </constant>
+ <constant name="VEC_MAX_FUNC" value="6">
+ </constant>
+ </constants>
+</class>
<class name="ShaderMaterial" inherits="Material" category="Core">
<brief_description>
</brief_description>
<description>
</description>
<methods>
- <method name="set_shader" >
+ <method name="set_shader">
<argument index="0" name="shader" type="Shader">
</argument>
<description>
</description>
</method>
- <method name="get_shader" qualifiers="const" >
+ <method name="get_shader" qualifiers="const">
<return type="Shader">
</return>
<description>
</description>
</method>
- <method name="set_shader_param" >
+ <method name="set_shader_param">
<argument index="0" name="param" type="String">
</argument>
- <argument index="1" name="value" type="var">
+ <argument index="1" name="value" type="Variant">
</argument>
<description>
</description>
</method>
- <method name="get_shader_param" qualifiers="const" >
+ <method name="get_shader_param" qualifiers="const">
+ <return type="Variant">
+ </return>
<argument index="0" name="param" type="String">
</argument>
<description>
@@ -25939,21 +31172,22 @@
Base class for all 2D Shapes. All 2D shape types inherit from this.
</description>
<methods>
- <method name="set_custom_solver_bias" >
+ <method name="set_custom_solver_bias">
<argument index="0" name="bias" type="float">
</argument>
<description>
Use a custom solver bias. No need to change this unless you really know what you are doing.
+ The solver bias is a factor controlling how much two objects "rebound" off each other, when colliding, to avoid them getting into each other because of numerical imprecision.
</description>
</method>
- <method name="get_custom_solver_bias" qualifiers="const" >
+ <method name="get_custom_solver_bias" qualifiers="const">
<return type="float">
</return>
<description>
- Return the custom solver bias. No need to change this unless you really know what you are doing.
+ Return the custom solver bias.
</description>
</method>
- <method name="collide" >
+ <method name="collide">
<return type="bool">
</return>
<argument index="0" name="local_xform" type="Matrix32">
@@ -25963,9 +31197,11 @@
<argument index="2" name="shape_xform" type="Matrix32">
</argument>
<description>
+ Return whether this shape is colliding with another.
+ This method needs the transformation matrix for this shape ([code]local_xform[/code]), the shape to check collisions with ([code]with_shape[/code]), and the transformation matrix of that shape ([code]shape_xform[/code]).
</description>
</method>
- <method name="collide_with_motion" >
+ <method name="collide_with_motion">
<return type="bool">
</return>
<argument index="0" name="local_xform" type="Matrix32">
@@ -25979,9 +31215,13 @@
<argument index="4" name="shape_motion" type="Vector2">
</argument>
<description>
+ Return whether this shape would collide with another, if a given movemen was applied.
+ This method needs the transformation matrix for this shape ([code]local_xform[/code]), the movement to test on this shape ([code]local_motion[/code]), the shape to check collisions with ([code]with_shape[/code]), the transformation matrix of that shape ([code]shape_xform[/code]), and the movement to test ont the other object ([code]shape_motion[/code]).
</description>
</method>
- <method name="collide_and_get_contacts" >
+ <method name="collide_and_get_contacts">
+ <return type="Variant">
+ </return>
<argument index="0" name="local_xform" type="Matrix32">
</argument>
<argument index="1" name="with_shape" type="Shape2D">
@@ -25989,9 +31229,13 @@
<argument index="2" name="shape_xform" type="Matrix32">
</argument>
<description>
+ Return a list of the points where this shape touches another. If there are no collisions, the list is empty.
+ This method needs the transformation matrix for this shape ([code]local_xform[/code]), the shape to check collisions with ([code]with_shape[/code]), and the transformation matrix of that shape ([code]shape_xform[/code]).
</description>
</method>
- <method name="collide_with_motion_and_get_contacts" >
+ <method name="collide_with_motion_and_get_contacts">
+ <return type="Variant">
+ </return>
<argument index="0" name="local_xform" type="Matrix32">
</argument>
<argument index="1" name="local_motion" type="Vector2">
@@ -26003,6 +31247,8 @@
<argument index="4" name="shape_motion" type="Vector2">
</argument>
<description>
+ Return a list of the points where this shape would touch another, if a given movement was applied. If there are no collisions, the list is empty.
+ This method needs the transformation matrix for this shape ([code]local_xform[/code]), the movement to test on this shape ([code]local_motion[/code]), the shape to check collisions with ([code]with_shape[/code]), the transformation matrix of that shape ([code]shape_xform[/code]), and the movement to test ont the other object ([code]shape_motion[/code]).
</description>
</method>
</methods>
@@ -26017,14 +31263,14 @@
Skeleton provides a hierachial interface for managing bones, including pose, rest and animation (see [Animation]). Skeleton will support rag doll dynamics in the future.
</description>
<methods>
- <method name="add_bone" >
+ <method name="add_bone">
<argument index="0" name="name" type="String">
</argument>
<description>
Add a bone, with name "name". [method get_bone_count] will become the bone index.
</description>
</method>
- <method name="find_bone" qualifiers="const" >
+ <method name="find_bone" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="name" type="String">
@@ -26033,7 +31279,7 @@
Return the bone index that matches "name" as its name.
</description>
</method>
- <method name="get_bone_name" qualifiers="const" >
+ <method name="get_bone_name" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="bone_idx" type="int">
@@ -26042,7 +31288,7 @@
Return the name of the bone at index "index"
</description>
</method>
- <method name="get_bone_parent" qualifiers="const" >
+ <method name="get_bone_parent" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="bone_idx" type="int">
@@ -26051,7 +31297,7 @@
Return the bone index which is the parent of the bone at "bone_idx". If -1, then bone has no parent. Note that the parent bone returned will always be less than "bone_idx".
</description>
</method>
- <method name="set_bone_parent" >
+ <method name="set_bone_parent">
<argument index="0" name="bone_idx" type="int">
</argument>
<argument index="1" name="parent_idx" type="int">
@@ -26060,14 +31306,20 @@
Set the bone index "parent_idx" as the parent of the bone at "bone_idx". If -1, then bone has no parent. Note: "parent_idx" must be less than "bone_idx".
</description>
</method>
- <method name="get_bone_count" qualifiers="const" >
+ <method name="get_bone_count" qualifiers="const">
<return type="int">
</return>
<description>
Return the amount of bones in the skeleton.
</description>
</method>
- <method name="get_bone_rest" qualifiers="const" >
+ <method name="unparent_bone_and_rest">
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_bone_rest" qualifiers="const">
<return type="Transform">
</return>
<argument index="0" name="bone_idx" type="int">
@@ -26076,7 +31328,7 @@
Return the rest transform for a bone "bone_idx".
</description>
</method>
- <method name="set_bone_rest" >
+ <method name="set_bone_rest">
<argument index="0" name="bone_idx" type="int">
</argument>
<argument index="1" name="rest" type="Transform">
@@ -26085,39 +31337,55 @@
Set the rest transform for bone "bone_idx"
</description>
</method>
- <method name="bind_child_node_to_bone" >
+ <method name="set_bone_disable_rest">
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <argument index="1" name="disable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_bone_rest_disabled" qualifiers="const">
+ <return type="bool">
+ </return>
+ <argument index="0" name="bone_idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="bind_child_node_to_bone">
<argument index="0" name="bone_idx" type="int">
</argument>
<argument index="1" name="node" type="Node">
</argument>
<description>
- Deprecated soon
+ Deprecated soon.
</description>
</method>
- <method name="unbind_child_node_from_bone" >
+ <method name="unbind_child_node_from_bone">
<argument index="0" name="bone_idx" type="int">
</argument>
<argument index="1" name="node" type="Node">
</argument>
<description>
- Deprecated soon
+ Deprecated soon.
</description>
</method>
- <method name="get_bound_child_nodes_to_bone" qualifiers="const" >
+ <method name="get_bound_child_nodes_to_bone" qualifiers="const">
<return type="Array">
</return>
<argument index="0" name="bone_idx" type="int">
</argument>
<description>
- Deprecated Soon
+ Deprecated soon.
</description>
</method>
- <method name="clear_bones" >
+ <method name="clear_bones">
<description>
Clear all the bones in this skeleton.
</description>
</method>
- <method name="get_bone_pose" qualifiers="const" >
+ <method name="get_bone_pose" qualifiers="const">
<return type="Transform">
</return>
<argument index="0" name="bone_idx" type="int">
@@ -26126,7 +31394,7 @@
Return the pose transform for bone "bone_idx".
</description>
</method>
- <method name="set_bone_pose" >
+ <method name="set_bone_pose">
<argument index="0" name="bone_idx" type="int">
</argument>
<argument index="1" name="pose" type="Transform">
@@ -26135,7 +31403,7 @@
Return the pose transform for bone "bone_idx".
</description>
</method>
- <method name="set_bone_global_pose" >
+ <method name="set_bone_global_pose">
<argument index="0" name="bone_idx" type="int">
</argument>
<argument index="1" name="pose" type="Transform">
@@ -26143,7 +31411,7 @@
<description>
</description>
</method>
- <method name="get_bone_global_pose" qualifiers="const" >
+ <method name="get_bone_global_pose" qualifiers="const">
<return type="Transform">
</return>
<argument index="0" name="bone_idx" type="int">
@@ -26151,7 +31419,7 @@
<description>
</description>
</method>
- <method name="get_bone_custom_pose" qualifiers="const" >
+ <method name="get_bone_custom_pose" qualifiers="const">
<return type="Transform">
</return>
<argument index="0" name="bone_idx" type="int">
@@ -26159,7 +31427,7 @@
<description>
</description>
</method>
- <method name="set_bone_custom_pose" >
+ <method name="set_bone_custom_pose">
<argument index="0" name="bone_idx" type="int">
</argument>
<argument index="1" name="custom_pose" type="Transform">
@@ -26167,7 +31435,7 @@
<description>
</description>
</method>
- <method name="get_bone_transform" qualifiers="const" >
+ <method name="get_bone_transform" qualifiers="const">
<return type="Transform">
</return>
<argument index="0" name="bone_idx" type="int">
@@ -26189,28 +31457,28 @@
Base class for GUI Sliders.
</description>
<methods>
- <method name="set_ticks" >
+ <method name="set_ticks">
<argument index="0" name="count" type="int">
</argument>
<description>
Set amount of ticks to display in slider.
</description>
</method>
- <method name="get_ticks" qualifiers="const" >
+ <method name="get_ticks" qualifiers="const">
<return type="int">
</return>
<description>
Return amounts of ticks to display on slider.
</description>
</method>
- <method name="get_ticks_on_borders" qualifiers="const" >
+ <method name="get_ticks_on_borders" qualifiers="const">
<return type="bool">
</return>
<description>
Return true if ticks are visible on borders.
</description>
</method>
- <method name="set_ticks_on_borders" >
+ <method name="set_ticks_on_borders">
<argument index="0" name="ticks_on_border" type="bool">
</argument>
<description>
@@ -26227,7 +31495,7 @@
<description>
</description>
<methods>
- <method name="set_param" >
+ <method name="set_param">
<argument index="0" name="param" type="int">
</argument>
<argument index="1" name="value" type="float">
@@ -26235,7 +31503,7 @@
<description>
</description>
</method>
- <method name="get_param" qualifiers="const" >
+ <method name="get_param" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="param" type="int">
@@ -26301,7 +31569,7 @@
Base class for playing spatial 2D sound.
</description>
<methods>
- <method name="set_param" >
+ <method name="set_param">
<argument index="0" name="param" type="int">
</argument>
<argument index="1" name="value" type="float">
@@ -26309,7 +31577,7 @@
<description>
</description>
</method>
- <method name="get_param" qualifiers="const" >
+ <method name="get_param" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="param" type="int">
@@ -26339,7 +31607,7 @@
<description>
</description>
<methods>
- <method name="set_param" >
+ <method name="set_param">
<argument index="0" name="param" type="int">
</argument>
<argument index="1" name="value" type="float">
@@ -26347,7 +31615,7 @@
<description>
</description>
</method>
- <method name="get_param" qualifiers="const" >
+ <method name="get_param" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="param" type="int">
@@ -26355,25 +31623,25 @@
<description>
</description>
</method>
- <method name="set_reverb_mode" >
+ <method name="set_reverb_mode">
<argument index="0" name="reverb_mode" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_reverb_mode" qualifiers="const" >
+ <method name="get_reverb_mode" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_force_params_to_all_sources" >
+ <method name="set_force_params_to_all_sources">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_forcing_params_to_all_sources" >
+ <method name="is_forcing_params_to_all_sources">
<return type="bool">
</return>
<description>
@@ -26391,137 +31659,227 @@
Spatial is the base for every type of 3D [Node]. It contains a 3D [Transform] which can be set or get as local or global. If a Spatial [Node] has Spatial children, their transforms will be relative to the parent.
</description>
<methods>
- <method name="set_transform" >
+ <method name="set_transform">
<argument index="0" name="local" type="Transform">
</argument>
<description>
Set the transform locally, relative to the parent spatial node.
</description>
</method>
- <method name="get_transform" qualifiers="const" >
+ <method name="get_transform" qualifiers="const">
<return type="Transform">
</return>
<description>
Return the local transform, relative to the bone parent.
</description>
</method>
- <method name="set_translation" >
+ <method name="set_translation">
<argument index="0" name="translation" type="Vector3">
</argument>
<description>
</description>
</method>
- <method name="get_translation" qualifiers="const" >
+ <method name="get_translation" qualifiers="const">
<return type="Vector3">
</return>
<description>
</description>
</method>
- <method name="set_rotation" >
+ <method name="set_rotation">
<argument index="0" name="rotation" type="Vector3">
</argument>
<description>
</description>
</method>
- <method name="get_rotation" qualifiers="const" >
+ <method name="get_rotation" qualifiers="const">
<return type="Vector3">
</return>
<description>
</description>
</method>
- <method name="set_scale" >
+ <method name="set_scale">
<argument index="0" name="scale" type="Vector3">
</argument>
<description>
</description>
</method>
- <method name="get_scale" qualifiers="const" >
+ <method name="get_scale" qualifiers="const">
<return type="Vector3">
</return>
<description>
</description>
</method>
- <method name="set_global_transform" >
+ <method name="set_global_transform">
<argument index="0" name="global" type="Transform">
</argument>
<description>
Set the transform globally, relative to worldspace.
</description>
</method>
- <method name="get_global_transform" qualifiers="const" >
+ <method name="get_global_transform" qualifiers="const">
<return type="Transform">
</return>
<description>
Return the gloal transform, relative to worldspace.
</description>
</method>
- <method name="get_parent_spatial" qualifiers="const" >
+ <method name="get_parent_spatial" qualifiers="const">
<return type="Object">
</return>
<description>
- Return the parent [Spatial], or an empty [Object] if no parent exists or parent is not of type [Spatial.
+ Return the parent [Spatial], or an empty [Object] if no parent exists or parent is not of type [Spatial].
</description>
</method>
- <method name="set_ignore_transform_notification" >
+ <method name="set_ignore_transform_notification">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="set_as_toplevel" >
+ <method name="set_as_toplevel">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_set_as_toplevel" qualifiers="const" >
+ <method name="is_set_as_toplevel" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="get_world" qualifiers="const" >
+ <method name="get_world" qualifiers="const">
<return type="World">
</return>
<description>
</description>
</method>
- <method name="update_gizmo" >
+ <method name="update_gizmo">
<description>
</description>
</method>
- <method name="set_gizmo" >
+ <method name="set_gizmo">
<argument index="0" name="gizmo" type="SpatialGizmo">
</argument>
<description>
</description>
</method>
- <method name="get_gizmo" qualifiers="const" >
+ <method name="get_gizmo" qualifiers="const">
<return type="SpatialGizmo">
</return>
<description>
</description>
</method>
- <method name="show" >
+ <method name="show">
+ <description>
+ </description>
+ </method>
+ <method name="hide">
<description>
</description>
</method>
- <method name="hide" >
+ <method name="is_visible" qualifiers="const">
+ <return type="bool">
+ </return>
<description>
</description>
</method>
- <method name="is_visible" qualifiers="const" >
+ <method name="is_hidden" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="is_hidden" qualifiers="const" >
+ <method name="set_hidden">
+ <argument index="0" name="hidden" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_notify_local_transform">
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_local_transform_notification_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
+ <method name="rotate">
+ <argument index="0" name="normal" type="Vector3">
+ </argument>
+ <argument index="1" name="radians" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="global_rotate">
+ <argument index="0" name="normal" type="Vector3">
+ </argument>
+ <argument index="1" name="radians" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="rotate_x">
+ <argument index="0" name="radians" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="rotate_y">
+ <argument index="0" name="radians" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="rotate_z">
+ <argument index="0" name="radians" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="translate">
+ <argument index="0" name="offset" type="Vector3">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="global_translate">
+ <argument index="0" name="offset" type="Vector3">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="orthonormalize">
+ <description>
+ </description>
+ </method>
+ <method name="set_identity">
+ <description>
+ </description>
+ </method>
+ <method name="look_at">
+ <argument index="0" name="target" type="Vector3">
+ </argument>
+ <argument index="1" name="up" type="Vector3">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="look_at_from_pos">
+ <argument index="0" name="pos" type="Vector3">
+ </argument>
+ <argument index="1" name="target" type="Vector3">
+ </argument>
+ <argument index="2" name="up" type="Vector3">
+ </argument>
+ <description>
+ </description>
+ </method>
</methods>
<signals>
<signal name="visibility_changed">
@@ -26531,7 +31889,7 @@
</signals>
<constants>
<constant name="NOTIFICATION_TRANSFORM_CHANGED" value="29">
- Spatial nodes receive this notifacation with their global transform changes. This means that either the current or a parent node changed it's transform.
+ Spatial nodes receive this notifacation with their global transform changes. This means that either the current or a parent node changed its transform.
</constant>
<constant name="NOTIFICATION_ENTER_WORLD" value="41">
</constant>
@@ -26547,7 +31905,7 @@
<description>
</description>
<methods>
- <method name="set_param" >
+ <method name="set_param">
<argument index="0" name="param" type="int">
</argument>
<argument index="1" name="value" type="float">
@@ -26555,7 +31913,7 @@
<description>
</description>
</method>
- <method name="get_param" qualifiers="const" >
+ <method name="get_param" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="param" type="int">
@@ -26589,31 +31947,31 @@
<description>
</description>
<methods>
- <method name="set_sample_library" >
+ <method name="set_sample_library">
<argument index="0" name="library" type="SampleLibrary">
</argument>
<description>
</description>
</method>
- <method name="get_sample_library" qualifiers="const" >
+ <method name="get_sample_library" qualifiers="const">
<return type="SampleLibrary">
</return>
<description>
</description>
</method>
- <method name="set_polyphony" >
+ <method name="set_polyphony">
<argument index="0" name="voices" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_polyphony" qualifiers="const" >
+ <method name="get_polyphony" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="play" >
+ <method name="play">
<return type="int">
</return>
<argument index="0" name="sample" type="String">
@@ -26623,7 +31981,7 @@
<description>
</description>
</method>
- <method name="voice_set_pitch_scale" >
+ <method name="voice_set_pitch_scale">
<argument index="0" name="voice" type="int">
</argument>
<argument index="1" name="ratio" type="float">
@@ -26631,7 +31989,7 @@
<description>
</description>
</method>
- <method name="voice_set_volume_scale_db" >
+ <method name="voice_set_volume_scale_db">
<argument index="0" name="voice" type="int">
</argument>
<argument index="1" name="db" type="float">
@@ -26639,7 +31997,7 @@
<description>
</description>
</method>
- <method name="is_voice_active" qualifiers="const" >
+ <method name="is_voice_active" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="voice" type="int">
@@ -26647,13 +32005,13 @@
<description>
</description>
</method>
- <method name="stop_voice" >
+ <method name="stop_voice">
<argument index="0" name="voice" type="int">
</argument>
<description>
</description>
</method>
- <method name="stop_all" >
+ <method name="stop_all">
<description>
</description>
</method>
@@ -26713,68 +32071,148 @@
<description>
</description>
<methods>
- <method name="set_stream" >
+ <method name="set_stream">
<argument index="0" name="stream" type="Stream">
</argument>
<description>
</description>
</method>
- <method name="get_stream" qualifiers="const" >
+ <method name="get_stream" qualifiers="const">
<return type="Stream">
</return>
<description>
</description>
</method>
- <method name="play" >
+ <method name="play">
+ <argument index="0" name="offset" type="float" default="0">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="stop">
<description>
</description>
</method>
- <method name="stop" >
+ <method name="is_playing" qualifiers="const">
+ <return type="bool">
+ </return>
<description>
</description>
</method>
- <method name="is_playing" qualifiers="const" >
+ <method name="set_paused">
+ <argument index="0" name="paused" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_paused" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_loop" >
+ <method name="set_loop">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="has_loop" qualifiers="const" >
+ <method name="has_loop" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="get_stream_name" qualifiers="const" >
+ <method name="set_volume">
+ <argument index="0" name="volume" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_volume" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_volume_db">
+ <argument index="0" name="db" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_volume_db" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_buffering_msec">
+ <argument index="0" name="msec" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_buffering_msec" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_loop_restart_time">
+ <argument index="0" name="secs" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_loop_restart_time" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_stream_name" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="get_loop_count" qualifiers="const" >
+ <method name="get_loop_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_pos" qualifiers="const" >
+ <method name="get_pos" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="seek_pos" >
+ <method name="seek_pos">
<argument index="0" name="time" type="float">
</argument>
<description>
</description>
</method>
+ <method name="set_autoplay">
+ <argument index="0" name="enabled" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="has_autoplay" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_length" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
</constants>
@@ -26785,13 +32223,13 @@
<description>
</description>
<methods>
- <method name="set_radius" >
+ <method name="set_radius">
<argument index="0" name="radius" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_radius" qualifiers="const" >
+ <method name="get_radius" qualifiers="const">
<return type="float">
</return>
<description>
@@ -26809,48 +32247,48 @@
SpinBox is a numerical input text field. It allows entering integers and floats.
</description>
<methods>
- <method name="set_suffix" >
+ <method name="set_suffix">
<argument index="0" name="suffix" type="String">
</argument>
<description>
Set a specific suffix.
</description>
</method>
- <method name="get_suffix" qualifiers="const" >
+ <method name="get_suffix" qualifiers="const">
<return type="String">
</return>
<description>
Return the specific suffix.
</description>
</method>
- <method name="set_prefix" >
+ <method name="set_prefix">
<argument index="0" name="prefix" type="String">
</argument>
<description>
Set a prefix.
</description>
</method>
- <method name="get_prefix" qualifiers="const" >
+ <method name="get_prefix" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="set_editable" >
+ <method name="set_editable">
<argument index="0" name="editable" type="bool">
</argument>
<description>
Set whether the spinbox is editable.
</description>
</method>
- <method name="is_editable" qualifiers="const" >
+ <method name="is_editable" qualifiers="const">
<return type="bool">
</return>
<description>
Return if the spinbox is editable.
</description>
</method>
- <method name="get_line_edit" >
+ <method name="get_line_edit">
<return type="Object">
</return>
<description>
@@ -26872,53 +32310,61 @@
Container for splitting two controls vertically or horizontally, with a grabber that allows adjusting the split offset or ratio.
</description>
<methods>
- <method name="set_split_offset" >
+ <method name="set_split_offset">
<argument index="0" name="offset" type="int">
</argument>
<description>
Set the split offset.
</description>
</method>
- <method name="get_split_offset" qualifiers="const" >
+ <method name="get_split_offset" qualifiers="const">
<return type="int">
</return>
<description>
- Return the spluit offset;
+ Return the split offset.
</description>
</method>
- <method name="set_collapsed" >
+ <method name="set_collapsed">
<argument index="0" name="collapsed" type="bool">
</argument>
<description>
Set if the split must be collapsed.
</description>
</method>
- <method name="is_collapsed" qualifiers="const" >
+ <method name="is_collapsed" qualifiers="const">
<return type="bool">
</return>
<description>
- Return if the split is collapsed;
+ Return if the split is collapsed.
</description>
</method>
- <method name="set_dragger_visible" >
+ <method name="set_dragger_visible">
<argument index="0" name="visible" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_dragger_visible" qualifiers="const" >
+ <method name="is_dragger_visible" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
</methods>
+ <signals>
+ <signal name="dragged">
+ <argument index="0" name="offset" type="int">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ </signals>
<constants>
</constants>
</class>
<class name="SpotLight" inherits="Light" category="Core">
<brief_description>
- Spotlight Light, such as a reflector spotlight or a latern.
+ Spotlight [Light], such as a reflector spotlight or a latern.
</brief_description>
<description>
A SpotLight light is a type of [Light] node that emits lights in a specific direction, in the shape of a cone. The light is attenuated through the distance and this attenuation can be configured by changing the energy, radius and attenuation parameters of [Light]. TODO: Image of a spotlight.
@@ -26936,154 +32382,154 @@
General purpose Sprite node. This Sprite node can show any texture as a sprite. The texture can be used as a spritesheet for animation, or only a region from a bigger texture can referenced, like an atlas.
</description>
<methods>
- <method name="set_texture" >
+ <method name="set_texture">
<argument index="0" name="texture" type="Texture">
</argument>
<description>
Set the base texture for the sprite.
</description>
</method>
- <method name="get_texture" qualifiers="const" >
+ <method name="get_texture" qualifiers="const">
<return type="Texture">
</return>
<description>
Return the base texture for the sprite.
</description>
</method>
- <method name="set_centered" >
+ <method name="set_centered">
<argument index="0" name="centered" type="bool">
</argument>
<description>
Set whether the sprite should be centered on the origin.
</description>
</method>
- <method name="is_centered" qualifiers="const" >
+ <method name="is_centered" qualifiers="const">
<return type="bool">
</return>
<description>
Return if the sprite is centered at the local origin.
</description>
</method>
- <method name="set_offset" >
+ <method name="set_offset">
<argument index="0" name="offset" type="Vector2">
</argument>
<description>
Set the sprite draw offset, useful for setting rotation pivots.
</description>
</method>
- <method name="get_offset" qualifiers="const" >
+ <method name="get_offset" qualifiers="const">
<return type="Vector2">
</return>
<description>
Return sprite draw offst.
</description>
</method>
- <method name="set_flip_h" >
+ <method name="set_flip_h">
<argument index="0" name="flip_h" type="bool">
</argument>
<description>
Set true to flip the sprite horizontaly.
</description>
</method>
- <method name="is_flipped_h" qualifiers="const" >
+ <method name="is_flipped_h" qualifiers="const">
<return type="bool">
</return>
<description>
Return true if the sprite is flipped horizontally.
</description>
</method>
- <method name="set_flip_v" >
+ <method name="set_flip_v">
<argument index="0" name="flip_v" type="bool">
</argument>
<description>
Set true to flip the sprite vertically.
</description>
</method>
- <method name="is_flipped_v" qualifiers="const" >
+ <method name="is_flipped_v" qualifiers="const">
<return type="bool">
</return>
<description>
Return true if the sprite is flipped vertically.
</description>
</method>
- <method name="set_region" >
+ <method name="set_region">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
Set the sprite as a sub-region of a bigger texture. Useful for texture-atlases.
</description>
</method>
- <method name="is_region" qualifiers="const" >
+ <method name="is_region" qualifiers="const">
<return type="bool">
</return>
<description>
Return if the sprite reads from a region.
</description>
</method>
- <method name="set_region_rect" >
+ <method name="set_region_rect">
<argument index="0" name="rect" type="Rect2">
</argument>
<description>
Set the region rect to read from.
</description>
</method>
- <method name="get_region_rect" qualifiers="const" >
+ <method name="get_region_rect" qualifiers="const">
<return type="Rect2">
</return>
<description>
Return the region rect to read from.
</description>
</method>
- <method name="set_frame" >
+ <method name="set_frame">
<argument index="0" name="frame" type="int">
</argument>
<description>
Set the texture frame for a sprite-sheet, works when vframes or hframes are greater than 1.
</description>
</method>
- <method name="get_frame" qualifiers="const" >
+ <method name="get_frame" qualifiers="const">
<return type="int">
</return>
<description>
Return the texture frame for a sprite-sheet, works when vframes or hframes are greater than 1.
</description>
</method>
- <method name="set_vframes" >
+ <method name="set_vframes">
<argument index="0" name="vframes" type="int">
</argument>
<description>
Set the amount of vertical frames and converts the sprite into a sprite-sheet. This is useful for animation.
</description>
</method>
- <method name="get_vframes" qualifiers="const" >
+ <method name="get_vframes" qualifiers="const">
<return type="int">
</return>
<description>
Return the amount of vertical frames. See [set_vframes].
</description>
</method>
- <method name="set_hframes" >
+ <method name="set_hframes">
<argument index="0" name="hframes" type="int">
</argument>
<description>
Set the amount of horizontal frames and converts the sprite into a sprite-sheet. This is useful for animation.
</description>
</method>
- <method name="get_hframes" qualifiers="const" >
+ <method name="get_hframes" qualifiers="const">
<return type="int">
</return>
<description>
Return the amount of horizontal frames. See [set_hframes].
</description>
</method>
- <method name="set_modulate" >
+ <method name="set_modulate">
<argument index="0" name="modulate" type="Color">
</argument>
<description>
- Set color modulation for the sprite. All sprite pixels are multiplied by this color.
+ Set color modulation for the sprite. All sprite pixels are multiplied by this color. Color may contain rgb values above 1 to achieve a highlight effect.
</description>
</method>
- <method name="get_modulate" qualifiers="const" >
+ <method name="get_modulate" qualifiers="const">
<return type="Color">
</return>
<description>
@@ -27091,6 +32537,12 @@
</description>
</method>
</methods>
+ <signals>
+ <signal name="frame_changed">
+ <description>
+ </description>
+ </signal>
+ </signals>
<constants>
</constants>
</class>
@@ -27100,79 +32552,85 @@
<description>
</description>
<methods>
- <method name="set_texture" >
+ <method name="set_texture">
<argument index="0" name="texture" type="Texture">
</argument>
<description>
</description>
</method>
- <method name="get_texture" qualifiers="const" >
+ <method name="get_texture" qualifiers="const">
<return type="Texture">
</return>
<description>
</description>
</method>
- <method name="set_region" >
+ <method name="set_region">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_region" qualifiers="const" >
+ <method name="is_region" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_region_rect" >
+ <method name="set_region_rect">
<argument index="0" name="rect" type="Rect2">
</argument>
<description>
</description>
</method>
- <method name="get_region_rect" qualifiers="const" >
+ <method name="get_region_rect" qualifiers="const">
<return type="Rect2">
</return>
<description>
</description>
</method>
- <method name="set_frame" >
+ <method name="set_frame">
<argument index="0" name="frame" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_frame" qualifiers="const" >
+ <method name="get_frame" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_vframes" >
+ <method name="set_vframes">
<argument index="0" name="vframes" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_vframes" qualifiers="const" >
+ <method name="get_vframes" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_hframes" >
+ <method name="set_hframes">
<argument index="0" name="hframes" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_hframes" qualifiers="const" >
+ <method name="get_hframes" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
</methods>
+ <signals>
+ <signal name="frame_changed">
+ <description>
+ </description>
+ </signal>
+ </signals>
<constants>
</constants>
</class>
@@ -27182,103 +32640,103 @@
<description>
</description>
<methods>
- <method name="set_centered" >
+ <method name="set_centered">
<argument index="0" name="centered" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_centered" qualifiers="const" >
+ <method name="is_centered" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_offset" >
+ <method name="set_offset">
<argument index="0" name="offset" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_offset" qualifiers="const" >
+ <method name="get_offset" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="set_flip_h" >
+ <method name="set_flip_h">
<argument index="0" name="flip_h" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_flipped_h" qualifiers="const" >
+ <method name="is_flipped_h" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_flip_v" >
+ <method name="set_flip_v">
<argument index="0" name="flip_v" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_flipped_v" qualifiers="const" >
+ <method name="is_flipped_v" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_modulate" >
+ <method name="set_modulate">
<argument index="0" name="modulate" type="Color">
</argument>
<description>
</description>
</method>
- <method name="get_modulate" qualifiers="const" >
+ <method name="get_modulate" qualifiers="const">
<return type="Color">
</return>
<description>
</description>
</method>
- <method name="set_opacity" >
+ <method name="set_opacity">
<argument index="0" name="opacity" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_opacity" qualifiers="const" >
+ <method name="get_opacity" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_pixel_size" >
+ <method name="set_pixel_size">
<argument index="0" name="pixel_size" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_pixel_size" qualifiers="const" >
+ <method name="get_pixel_size" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_axis" >
+ <method name="set_axis">
<argument index="0" name="axis" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_axis" qualifiers="const" >
+ <method name="get_axis" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_draw_flag" >
+ <method name="set_draw_flag">
<argument index="0" name="flag" type="int">
</argument>
<argument index="1" name="enabled" type="bool">
@@ -27286,7 +32744,7 @@
<description>
</description>
</method>
- <method name="get_draw_flag" qualifiers="const" >
+ <method name="get_draw_flag" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="flag" type="int">
@@ -27294,19 +32752,19 @@
<description>
</description>
</method>
- <method name="set_alpha_cut_mode" >
+ <method name="set_alpha_cut_mode">
<argument index="0" name="mode" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_alpha_cut_mode" qualifiers="const" >
+ <method name="get_alpha_cut_mode" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_item_rect" qualifiers="const" >
+ <method name="get_item_rect" qualifiers="const">
<return type="Rect2">
</return>
<description>
@@ -27336,7 +32794,7 @@
Sprite frame library for [AnimatedSprite].
</description>
<methods>
- <method name="add_frame" >
+ <method name="add_frame">
<argument index="0" name="frame" type="Object">
</argument>
<argument index="1" name="atpos" type="int" default="-1">
@@ -27345,14 +32803,14 @@
Add a frame (texture).
</description>
</method>
- <method name="get_frame_count" qualifiers="const" >
+ <method name="get_frame_count" qualifiers="const">
<return type="int">
</return>
<description>
Return the amount of frames.
</description>
</method>
- <method name="get_frame" qualifiers="const" >
+ <method name="get_frame" qualifiers="const">
<return type="Object">
</return>
<argument index="0" name="idx" type="int">
@@ -27361,7 +32819,7 @@
Return a texture (frame).
</description>
</method>
- <method name="set_frame" >
+ <method name="set_frame">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="txt" type="Object">
@@ -27369,14 +32827,14 @@
<description>
</description>
</method>
- <method name="remove_frame" >
+ <method name="remove_frame">
<argument index="0" name="idx" type="int">
</argument>
<description>
Remove a frame
</description>
</method>
- <method name="clear" >
+ <method name="clear">
<description>
Clear the frames.
</description>
@@ -27393,49 +32851,49 @@
StaticBody implements a static collision [Node], by utilizing a rigid body in the [PhysicsServer]. Static bodies are used for static collision. For more information on physics body nodes, see [PhysicsBody].
</description>
<methods>
- <method name="set_constant_linear_velocity" >
+ <method name="set_constant_linear_velocity">
<argument index="0" name="vel" type="Vector3">
</argument>
<description>
</description>
</method>
- <method name="set_constant_angular_velocity" >
+ <method name="set_constant_angular_velocity">
<argument index="0" name="vel" type="Vector3">
</argument>
<description>
</description>
</method>
- <method name="get_constant_linear_velocity" qualifiers="const" >
+ <method name="get_constant_linear_velocity" qualifiers="const">
<return type="Vector3">
</return>
<description>
</description>
</method>
- <method name="get_constant_angular_velocity" qualifiers="const" >
+ <method name="get_constant_angular_velocity" qualifiers="const">
<return type="Vector3">
</return>
<description>
</description>
</method>
- <method name="set_friction" >
+ <method name="set_friction">
<argument index="0" name="friction" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_friction" qualifiers="const" >
+ <method name="get_friction" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_bounce" >
+ <method name="set_bounce">
<argument index="0" name="bounce" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_bounce" qualifiers="const" >
+ <method name="get_bounce" qualifiers="const">
<return type="float">
</return>
<description>
@@ -27450,61 +32908,65 @@
Static body for 2D Physics.
</brief_description>
<description>
- Static body for 2D Physics. A static body is a simple body that is not intended to move. They don't consume any CPU resources in contrast to a [RigidBody2D] so they are great for scenaro collision.[br]
- A static body also can be animated by using simulated motion mode, this is useful for implementing functionalities such as moving platforms, when this mode is active the body can be animated and automatically compute linear and angular velocity to apply in that frame and to influence other bodies.
+ Static body for 2D Physics. A static body is a simple body that is not intended to move. They don't consume any CPU resources in contrast to a [RigidBody2D] so they are great for scenaro collision.
+ A static body can also be animated by using simulated motion mode. This is useful for implementing functionalities such as moving platforms. When this mode is active the body can be animated and automatically computes linear and angular velocity to apply in that frame and to influence other bodies.
Alternatively, a constant linear or angular velocity can be set for the static body, so even if it doesn't move, it affects other bodies as if it was moving (this is useful for simulating conveyor belts or conveyor wheels).
</description>
<methods>
- <method name="set_constant_linear_velocity" >
+ <method name="set_constant_linear_velocity">
<argument index="0" name="vel" type="Vector2">
</argument>
<description>
- Set a constant linear velocity for the body.
+ Set a constant linear velocity for the body. This does not move the body, but affects other bodies touching it, as if it was moving.
</description>
</method>
- <method name="set_constant_angular_velocity" >
+ <method name="set_constant_angular_velocity">
<argument index="0" name="vel" type="float">
</argument>
<description>
Set a constant angular velocity for the body.
</description>
</method>
- <method name="get_constant_linear_velocity" qualifiers="const" >
+ <method name="get_constant_linear_velocity" qualifiers="const">
<return type="Vector2">
</return>
<description>
- Return the constant linear velocity for the body.
+ Return the constant linear velocity for the body. This does not rotate the body, but affects other bodies touching it, as if it was rotating.
</description>
</method>
- <method name="get_constant_angular_velocity" qualifiers="const" >
+ <method name="get_constant_angular_velocity" qualifiers="const">
<return type="float">
</return>
<description>
Return the constant angular velocity for the body.
</description>
</method>
- <method name="set_friction" >
+ <method name="set_friction">
<argument index="0" name="friction" type="float">
</argument>
<description>
+ Set the body friction, from 0 (frictionless) to 1 (full friction).
</description>
</method>
- <method name="get_friction" qualifiers="const" >
+ <method name="get_friction" qualifiers="const">
<return type="float">
</return>
<description>
+ Return the body friction.
</description>
</method>
- <method name="set_bounce" >
+ <method name="set_bounce">
<argument index="0" name="bounce" type="float">
</argument>
<description>
+ Set the body bounciness, from 0 (not bouncy) to 1 (bouncy).
</description>
</method>
- <method name="get_bounce" qualifiers="const" >
+ <method name="get_bounce" qualifiers="const">
<return type="float">
</return>
<description>
+ Return the body bounciness.
</description>
</method>
</methods>
@@ -27519,7 +32981,7 @@
StreamPeer is an abstration and base class for stream-based protocols (such as TCP or Unix Sockets). It provides an API for sending and receiving data through streams as raw data or strings.
</description>
<methods>
- <method name="put_data" >
+ <method name="put_data">
<return type="int">
</return>
<argument index="0" name="data" type="RawArray">
@@ -27528,7 +32990,7 @@
Send a chunk of data through the connection, blocking if necesary until the data is done sending. This function returns an [Error] code.
</description>
</method>
- <method name="put_partial_data" >
+ <method name="put_partial_data">
<return type="Array">
</return>
<argument index="0" name="data" type="RawArray">
@@ -27537,7 +32999,7 @@
Send a chunk of data through the connection, if all the data could not be sent at once, only part of it will. This function returns two values, an [Error] code and an integer, describing how much data was actually sent.
</description>
</method>
- <method name="get_data" >
+ <method name="get_data">
<return type="Array">
</return>
<argument index="0" name="bytes" type="int">
@@ -27546,7 +33008,7 @@
Return a chunk data with the received bytes. The amount of bytes to be received can be requested in the "bytes" argument. If not enough bytes are available, the function will block until the desired amount is received. This function returns two values, an [Error] code and a data array.
</description>
</method>
- <method name="get_partial_data" >
+ <method name="get_partial_data">
<return type="Array">
</return>
<argument index="0" name="bytes" type="int">
@@ -27555,6 +33017,178 @@
Return a chunk data with the received bytes. The amount of bytes to be received can be requested in the "bytes" argument. If not enough bytes are available, the function will return how many were actually received. This function returns two values, an [Error] code, and a data array.
</description>
</method>
+ <method name="get_available_bytes" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_big_endian">
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_big_endian_enabled" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="put_8">
+ <argument index="0" name="val" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="put_u8">
+ <argument index="0" name="val" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="put_16">
+ <argument index="0" name="val" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="put_u16">
+ <argument index="0" name="val" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="put_32">
+ <argument index="0" name="val" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="put_u32">
+ <argument index="0" name="val" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="put_64">
+ <argument index="0" name="val" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="put_u64">
+ <argument index="0" name="val" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="put_float">
+ <argument index="0" name="val" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="put_double">
+ <argument index="0" name="val" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="put_utf8_string">
+ <argument index="0" name="val" type="String">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="put_var">
+ <argument index="0" name="val" type="Variant">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_8">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_u8">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_16">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_u16">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_32">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_u32">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_64">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_u64">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_float">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_double">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_string">
+ <return type="String">
+ </return>
+ <argument index="0" name="bytes" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_utf8_string">
+ <return type="String">
+ </return>
+ <argument index="0" name="bytes" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_var">
+ <return type="Variant">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
</constants>
@@ -27565,16 +33199,16 @@
<description>
</description>
<methods>
- <method name="accept" >
- <return type="int">
+ <method name="accept">
+ <return type="Error">
</return>
<argument index="0" name="stream" type="StreamPeer">
</argument>
<description>
</description>
</method>
- <method name="connect" >
- <return type="int">
+ <method name="connect">
+ <return type="Error">
</return>
<argument index="0" name="stream" type="StreamPeer">
</argument>
@@ -27585,13 +33219,13 @@
<description>
</description>
</method>
- <method name="get_status" qualifiers="const" >
+ <method name="get_status" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="disconnect" >
+ <method name="disconnect">
<description>
</description>
</method>
@@ -27615,41 +33249,41 @@
TCP Stream peer. This object can be used to connect to TCP servers, or also is returned by a tcp server.
</description>
<methods>
- <method name="connect" >
+ <method name="connect">
<return type="int">
</return>
<argument index="0" name="host" type="String">
</argument>
- <argument index="1" name="ip" type="int">
+ <argument index="1" name="port" type="int">
</argument>
<description>
</description>
</method>
- <method name="is_connected" qualifiers="const" >
+ <method name="is_connected" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="get_status" qualifiers="const" >
+ <method name="get_status" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_connected_host" qualifiers="const" >
+ <method name="get_connected_host" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="get_connected_port" qualifiers="const" >
+ <method name="get_connected_port" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="disconnect" >
+ <method name="disconnect">
<description>
</description>
</method>
@@ -27673,142 +33307,174 @@
Base class for audio stream playback. Audio stream players inherit from it.
</description>
<methods>
- <method name="set_stream" >
+ <method name="set_stream">
<argument index="0" name="stream" type="Stream">
</argument>
<description>
</description>
</method>
- <method name="get_stream" qualifiers="const" >
+ <method name="get_stream" qualifiers="const">
<return type="Stream">
</return>
<description>
</description>
</method>
- <method name="play" >
+ <method name="play">
+ <argument index="0" name="offset" type="float" default="0">
+ </argument>
<description>
</description>
</method>
- <method name="stop" >
+ <method name="stop">
<description>
</description>
</method>
- <method name="is_playing" qualifiers="const" >
+ <method name="is_playing" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_paused" >
+ <method name="set_paused">
<argument index="0" name="paused" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_paused" qualifiers="const" >
+ <method name="is_paused" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_loop" >
+ <method name="set_loop">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="has_loop" qualifiers="const" >
+ <method name="has_loop" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_volume" >
+ <method name="set_volume">
<argument index="0" name="volume" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_volume" qualifiers="const" >
+ <method name="get_volume" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_volume_db" >
+ <method name="set_volume_db">
<argument index="0" name="db" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_volume_db" qualifiers="const" >
+ <method name="get_volume_db" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="get_stream_name" qualifiers="const" >
+ <method name="set_buffering_msec">
+ <argument index="0" name="msec" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_buffering_msec" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_loop_restart_time">
+ <argument index="0" name="secs" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_loop_restart_time" qualifiers="const">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_stream_name" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="get_loop_count" qualifiers="const" >
+ <method name="get_loop_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_pos" qualifiers="const" >
+ <method name="get_pos" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="seek_pos" >
+ <method name="seek_pos">
<argument index="0" name="time" type="float">
</argument>
<description>
</description>
</method>
- <method name="set_autoplay" >
+ <method name="set_autoplay">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="has_autoplay" qualifiers="const" >
+ <method name="has_autoplay" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="get_length" qualifiers="const" >
+ <method name="get_length" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
</methods>
+ <signals>
+ <signal name="finished">
+ <description>
+ </description>
+ </signal>
+ </signals>
<constants>
</constants>
</class>
<class name="String" category="Built-In Types">
<brief_description>
- Built-In string class.
+ Built-in string class.
</brief_description>
<description>
- This is the built in string class (and the one used by GDScript). It supports Unicode and provides all necesary means for string handling. Strings are reference counted and use a copy-on-write approach, so passing them around is cheap in resources.
+ This is the built-in string class (and the one used by GDScript). It supports Unicode and provides all necesary means for string handling. Strings are reference counted and use a copy-on-write approach, so passing them around is cheap in resources.
</description>
<methods>
- <method name="basename" >
+ <method name="basename">
<return type="String">
</return>
<description>
If the string is a path to a file, return the path to the file without the extension.
</description>
</method>
- <method name="begins_with" >
+ <method name="begins_with">
<return type="bool">
</return>
<argument index="0" name="text" type="String">
@@ -27817,14 +33483,14 @@
Return true if the strings begins with the given string.
</description>
</method>
- <method name="capitalize" >
+ <method name="capitalize">
<return type="String">
</return>
<description>
Return the string in uppercase.
</description>
</method>
- <method name="casecmp_to" >
+ <method name="casecmp_to">
<return type="int">
</return>
<argument index="0" name="to" type="String">
@@ -27833,21 +33499,21 @@
Perform a case-sensitive comparison to antoher string, return -1 if less, 0 if equal and +1 if greater.
</description>
</method>
- <method name="empty" >
+ <method name="empty">
<return type="bool">
</return>
<description>
Return true if the string is empty.
</description>
</method>
- <method name="extension" >
+ <method name="extension">
<return type="String">
</return>
<description>
If the string is a path to a file, return the extension.
</description>
</method>
- <method name="find" >
+ <method name="find">
<return type="int">
</return>
<argument index="0" name="what" type="String">
@@ -27858,7 +33524,7 @@
Find the first occurence of a substring, return the starting position of the substring or -1 if not found. Optionally, the initial search index can be passed.
</description>
</method>
- <method name="find_last" >
+ <method name="find_last">
<return type="int">
</return>
<argument index="0" name="what" type="String">
@@ -27867,7 +33533,7 @@
Find the last occurence of a substring, return the starting position of the substring or -1 if not found. Optionally, the initial search index can be passed.
</description>
</method>
- <method name="findn" >
+ <method name="findn">
<return type="int">
</return>
<argument index="0" name="what" type="String">
@@ -27878,34 +33544,35 @@
Find the first occurence of a substring but search as case-insensitive, return the starting position of the substring or -1 if not found. Optionally, the initial search index can be passed.
</description>
</method>
- <method name="get_base_dir" >
+ <method name="get_base_dir">
<return type="String">
</return>
<description>
If the string is a path to a file, return the base directory.
</description>
</method>
- <method name="get_file" >
+ <method name="get_file">
<return type="String">
</return>
<description>
If the string is a path to a file, return the file and ignore the base directory.
</description>
</method>
- <method name="hash" >
+ <method name="hash">
<return type="int">
</return>
<description>
Hash the string and return a 32 bits integer.
</description>
</method>
- <method name="hex_to_int" >
+ <method name="hex_to_int">
<return type="int">
</return>
<description>
+ Convert a string containing an hexadecimal number into an int.
</description>
</method>
- <method name="insert" >
+ <method name="insert">
<return type="String">
</return>
<argument index="0" name="pos" type="int">
@@ -27916,51 +33583,55 @@
Insert a substring at a given position.
</description>
</method>
- <method name="is_abs_path" >
+ <method name="is_abs_path">
<return type="bool">
</return>
<description>
If the string is a path to a file or directory, return true if the path is absolute.
</description>
</method>
- <method name="is_rel_path" >
+ <method name="is_rel_path">
<return type="bool">
</return>
<description>
If the string is a path to a file or directory, return true if the path is relative.
</description>
</method>
- <method name="is_valid_float" >
+ <method name="is_valid_float">
<return type="bool">
</return>
<description>
+ Check whether the string contains a valid float.
</description>
</method>
- <method name="is_valid_html_color" >
+ <method name="is_valid_html_color">
<return type="bool">
</return>
<description>
+ Check whether the string contains a valid color in HTML notation.
</description>
</method>
- <method name="is_valid_identifier" >
+ <method name="is_valid_identifier">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="is_valid_integer" >
+ <method name="is_valid_integer">
<return type="bool">
</return>
<description>
+ Check whether the string contains a valid integer.
</description>
</method>
- <method name="is_valid_ip_address" >
+ <method name="is_valid_ip_address">
<return type="bool">
</return>
<description>
+ Check whether the string contains a valid IP address.
</description>
</method>
- <method name="left" >
+ <method name="left">
<return type="String">
</return>
<argument index="0" name="pos" type="int">
@@ -27969,14 +33640,14 @@
Return an amount of characters from the left of the string.
</description>
</method>
- <method name="length" >
+ <method name="length">
<return type="int">
</return>
<description>
Return the length of the string in characters.
</description>
</method>
- <method name="match" >
+ <method name="match">
<return type="bool">
</return>
<argument index="0" name="expr" type="String">
@@ -27985,7 +33656,7 @@
Do a simple expression matching, using ? and * wildcards.
</description>
</method>
- <method name="matchn" >
+ <method name="matchn">
<return type="bool">
</return>
<argument index="0" name="expr" type="String">
@@ -27994,19 +33665,19 @@
Do a simple, case insensitive, expression matching, using ? and * wildcards.
</description>
</method>
- <method name="md5_buffer" >
+ <method name="md5_buffer">
<return type="RawArray">
</return>
<description>
</description>
</method>
- <method name="md5_text" >
+ <method name="md5_text">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="nocasecmp_to" >
+ <method name="nocasecmp_to">
<return type="int">
</return>
<argument index="0" name="to" type="String">
@@ -28015,15 +33686,16 @@
Perform a case-insensitive comparison to antoher string, return -1 if less, 0 if equal and +1 if greater.
</description>
</method>
- <method name="ord_at" >
+ <method name="ord_at">
<return type="String">
</return>
<argument index="0" name="at" type="int">
</argument>
<description>
+ Return the character code at position "at".
</description>
</method>
- <method name="pad_decimals" >
+ <method name="pad_decimals">
<return type="String">
</return>
<argument index="0" name="digits" type="int">
@@ -28031,7 +33703,7 @@
<description>
</description>
</method>
- <method name="pad_zeros" >
+ <method name="pad_zeros">
<return type="String">
</return>
<argument index="0" name="digits" type="int">
@@ -28039,19 +33711,19 @@
<description>
</description>
</method>
- <method name="percent_decode" >
+ <method name="percent_decode">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="percent_encode" >
+ <method name="percent_encode">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="plus_file" >
+ <method name="plus_file">
<return type="String">
</return>
<argument index="0" name="file" type="String">
@@ -28059,7 +33731,7 @@
<description>
</description>
</method>
- <method name="replace" >
+ <method name="replace">
<return type="String">
</return>
<argument index="0" name="what" type="String">
@@ -28070,7 +33742,7 @@
Replace occurrences of a substring for different ones inside the string.
</description>
</method>
- <method name="replacen" >
+ <method name="replacen">
<return type="String">
</return>
<argument index="0" name="what" type="String">
@@ -28081,7 +33753,7 @@
Replace occurrences of a substring for different ones inside the string, but search case-insensitive.
</description>
</method>
- <method name="rfind" >
+ <method name="rfind">
<return type="int">
</return>
<argument index="0" name="what" type="String">
@@ -28092,7 +33764,7 @@
Perform a search for a substring, but start from the end of the string instead of the begining.
</description>
</method>
- <method name="rfindn" >
+ <method name="rfindn">
<return type="int">
</return>
<argument index="0" name="what" type="String">
@@ -28103,7 +33775,7 @@
Perform a search for a substring, but start from the end of the string instead of the begining. Also search case-insensitive.
</description>
</method>
- <method name="right" >
+ <method name="right">
<return type="String">
</return>
<argument index="0" name="pos" type="int">
@@ -28112,7 +33784,7 @@
Return the right side of the string from a given position.
</description>
</method>
- <method name="split" >
+ <method name="split">
<return type="StringArray">
</return>
<argument index="0" name="divisor" type="String">
@@ -28123,7 +33795,7 @@
Split the string by a divisor string, return an array of the substrings. Example "One,Two,Three" will return ["One","Two","Three"] if split by ",".
</description>
</method>
- <method name="split_floats" >
+ <method name="split_floats">
<return type="RealArray">
</return>
<argument index="0" name="divisor" type="String">
@@ -28134,14 +33806,14 @@
Split the string in floats by using a divisor string, return an array of the substrings. Example "1,2.5,3" will return [1,2.5,3] if split by ",".
</description>
</method>
- <method name="strip_edges" >
+ <method name="strip_edges">
<return type="String">
</return>
<description>
Return a copy of the string stripped of any non-printable character at the begining and the end.
</description>
</method>
- <method name="substr" >
+ <method name="substr">
<return type="String">
</return>
<argument index="0" name="from" type="int">
@@ -28149,42 +33821,59 @@
<argument index="1" name="len" type="int">
</argument>
<description>
+ Return part of the string from "from", with length "len".
</description>
</method>
- <method name="to_float" >
+ <method name="to_ascii">
+ <return type="RawArray">
+ </return>
+ <description>
+ Convert the String (which is a character array) to RawArray (which is an array of bytes). The conversion is speeded up in comparison to to_utf8() with the assumption that all the characters the String contains are only ASCII characters.
+ </description>
+ </method>
+ <method name="to_float">
<return type="float">
</return>
<description>
+ Convert a string, containing a decimal number, into a float.
</description>
</method>
- <method name="to_int" >
+ <method name="to_int">
<return type="int">
</return>
<description>
+ Convert a string, containing an integer number, into an int.
</description>
</method>
- <method name="to_lower" >
+ <method name="to_lower">
<return type="String">
</return>
<description>
Return the string converted to lowercase.
</description>
</method>
- <method name="to_upper" >
+ <method name="to_upper">
<return type="String">
</return>
<description>
Return the string converted to uppercase.
</description>
</method>
- <method name="xml_escape" >
+ <method name="to_utf8">
+ <return type="RawArray">
+ </return>
+ <description>
+ Convert the String (which is an array of characters) to RawArray (which is an array of bytes). The conversion is a bit slower than to_ascii(), but supports all UTF-8 characters. Therefore, you should prefer this function over to_ascii().
+ </description>
+ </method>
+ <method name="xml_escape">
<return type="String">
</return>
<description>
Perform XML escaping on the string.
</description>
</method>
- <method name="xml_unescape" >
+ <method name="xml_unescape">
<return type="String">
</return>
<description>
@@ -28197,13 +33886,13 @@
</class>
<class name="StringArray" category="Built-In Types">
<brief_description>
- String Array .
+ String Array.
</brief_description>
<description>
- String Array. Array of strings. Can only contain strings. Optimized for memory usage, cant fragment the memory.
+ String Array. Array of strings. Can only contain strings. Optimized for memory usage, can't fragment the memory.
</description>
<methods>
- <method name="get" >
+ <method name="get">
<return type="String">
</return>
<argument index="0" name="idx" type="int">
@@ -28211,19 +33900,19 @@
<description>
</description>
</method>
- <method name="push_back" >
+ <method name="push_back">
<argument index="0" name="string" type="String">
</argument>
<description>
</description>
</method>
- <method name="resize" >
+ <method name="resize">
<argument index="0" name="idx" type="int">
</argument>
<description>
</description>
</method>
- <method name="set" >
+ <method name="set">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="string" type="String">
@@ -28231,13 +33920,15 @@
<description>
</description>
</method>
- <method name="size" >
+ <method name="size">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="StringArray" >
+ <method name="StringArray">
+ <return type="StringArray">
+ </return>
<argument index="0" name="from" type="Array">
</argument>
<description>
@@ -28249,13 +33940,13 @@
</class>
<class name="StyleBox" inherits="Resource" category="Core">
<brief_description>
- Base class for dawing stylized boxes for the UI.
+ Base class for drawing stylized boxes for the UI.
</brief_description>
<description>
- StyleBox is [Resource] that provides an abstract base class for dawing stylized boxes for the UI. StyleBoxes are used for dawing the styles of buttons, line edit backgrounds, tree backgrounds, etc. and also for testing a transparency mask for pointer signals. If mask test fails on a StyleBox assigned as mask to a control, clicks and motion signals will go through it to the one below.
+ StyleBox is [Resource] that provides an abstract base class for drawing stylized boxes for the UI. StyleBoxes are used for drawing the styles of buttons, line edit backgrounds, tree backgrounds, etc. and also for testing a transparency mask for pointer signals. If mask test fails on a StyleBox assigned as mask to a control, clicks and motion signals will go through it to the one below.
</description>
<methods>
- <method name="test_mask" qualifiers="const" >
+ <method name="test_mask" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="point" type="Vector2">
@@ -28266,7 +33957,7 @@
Test a position in a rectangle, return wether it pases the mask test.
</description>
</method>
- <method name="set_default_margin" >
+ <method name="set_default_margin">
<argument index="0" name="margin" type="int">
</argument>
<argument index="1" name="offset" type="float">
@@ -28275,7 +33966,7 @@
Set the default offset "offset" of the margin "margin" (see MARGIN_* enum) for a StyleBox, Controls that draw styleboxes with context inside need to know the margin, so the border of the stylebox is not occluded.
</description>
</method>
- <method name="get_default_margin" qualifiers="const" >
+ <method name="get_default_margin" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="margin" type="int">
@@ -28284,7 +33975,7 @@
Return the default offset of the margin "margin" (see MARGIN_* enum) of a StyleBox, Controls that draw styleboxes with context inside need to know the margin, so the border of the stylebox is not occluded.
</description>
</method>
- <method name="get_margin" qualifiers="const" >
+ <method name="get_margin" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="margin" type="int">
@@ -28293,30 +33984,30 @@
Return the offset of margin "margin" (see MARGIN_* enum).
</description>
</method>
- <method name="get_minimum_size" qualifiers="const" >
+ <method name="get_minimum_size" qualifiers="const">
<return type="Vector2">
</return>
<description>
Return the minimum size that this stylebox can be shrunk to.
</description>
</method>
- <method name="get_center_size" qualifiers="const" >
+ <method name="get_center_size" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="get_offset" qualifiers="const" >
+ <method name="get_offset" qualifiers="const">
<return type="Vector2">
</return>
<description>
Return the "offset" of a stylebox, this is a helper function, like writing Point2( style.get_margin(MARGIN_LEFT), style.get_margin(MARGIN_TOP) )
</description>
</method>
- <method name="draw" qualifiers="const" >
- <argument index="0" name="arg0" type="RID">
+ <method name="draw" qualifiers="const">
+ <argument index="0" name="canvas_item" type="RID">
</argument>
- <argument index="1" name="arg1" type="Rect2">
+ <argument index="1" name="rect" type="Rect2">
</argument>
<description>
</description>
@@ -28345,73 +34036,73 @@
Stylebox of a single color. Displays the stylebox of a single color, alternatively a border with light/dark colors can be assigned.
</description>
<methods>
- <method name="set_bg_color" >
+ <method name="set_bg_color">
<argument index="0" name="color" type="Color">
</argument>
<description>
</description>
</method>
- <method name="get_bg_color" qualifiers="const" >
+ <method name="get_bg_color" qualifiers="const">
<return type="Color">
</return>
<description>
</description>
</method>
- <method name="set_light_color" >
+ <method name="set_light_color">
<argument index="0" name="color" type="Color">
</argument>
<description>
</description>
</method>
- <method name="get_light_color" qualifiers="const" >
+ <method name="get_light_color" qualifiers="const">
<return type="Color">
</return>
<description>
</description>
</method>
- <method name="set_dark_color" >
+ <method name="set_dark_color">
<argument index="0" name="color" type="Color">
</argument>
<description>
</description>
</method>
- <method name="get_dark_color" qualifiers="const" >
+ <method name="get_dark_color" qualifiers="const">
<return type="Color">
</return>
<description>
</description>
</method>
- <method name="set_border_size" >
+ <method name="set_border_size">
<argument index="0" name="size" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_border_size" qualifiers="const" >
+ <method name="get_border_size" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_border_blend" >
+ <method name="set_border_blend">
<argument index="0" name="blend" type="bool">
</argument>
<description>
</description>
</method>
- <method name="get_border_blend" qualifiers="const" >
+ <method name="get_border_blend" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_draw_center" >
+ <method name="set_draw_center">
<argument index="0" name="size" type="bool">
</argument>
<description>
</description>
</method>
- <method name="get_draw_center" qualifiers="const" >
+ <method name="get_draw_center" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -28429,35 +34120,35 @@
This StyleBox is similar to [StyleBoxTexture], but only meant to be used for mask testing. It takes an image and applies stretch rules to determine if the poit clicked is masked or not.
</description>
<methods>
- <method name="set_image" >
+ <method name="set_image">
<argument index="0" name="image" type="Image">
</argument>
<description>
Set the image used for mask testing. Pixels (converted to grey) that have a value, less than 0.5 will fail the test.
</description>
</method>
- <method name="get_image" qualifiers="const" >
+ <method name="get_image" qualifiers="const">
<return type="Image">
</return>
<description>
Return the image used for mask testing. (see [method set_imag]).
</description>
</method>
- <method name="set_expand" >
+ <method name="set_expand">
<argument index="0" name="expand" type="bool">
</argument>
<description>
Set the expand property (default). When expanding, the image will use the same rules as [StyleBoxTexture] for expand. If not expanding, the image will always be tested at its original size.
</description>
</method>
- <method name="get_expand" qualifiers="const" >
+ <method name="get_expand" qualifiers="const">
<return type="bool">
</return>
<description>
Return wether the expand property is set(default). When expanding, the image will use the same rules as [StyleBoxTexture] for expand. If not expanding, the image will always be tested at its original size.
</description>
</method>
- <method name="set_expand_margin_size" >
+ <method name="set_expand_margin_size">
<argument index="0" name="margin" type="int">
</argument>
<argument index="1" name="size" type="float">
@@ -28466,10 +34157,10 @@
Set an expand margin size (from enum MARGIN_*). Parts of the image below the size of the margin (and in the direction of the margin) will not expand.
</description>
</method>
- <method name="get_expand_margin_size" qualifiers="const" >
+ <method name="get_expand_margin_size" qualifiers="const">
<return type="float">
</return>
- <argument index="0" name="arg0" type="int">
+ <argument index="0" name="margin" type="int">
</argument>
<description>
Return the expand margin size (from enum MARGIN_*). Parts of the image below the size of the margin (and in the direction of the margin) will not expand.
@@ -28487,19 +34178,19 @@
Texture Based 3x3 scale style. This stylebox performs a 3x3 scaling of a texture, where only the center cell is fully stretched. This allows for the easy creation of bordered styles.
</description>
<methods>
- <method name="set_texture" >
+ <method name="set_texture">
<argument index="0" name="texture" type="Texture">
</argument>
<description>
</description>
</method>
- <method name="get_texture" qualifiers="const" >
+ <method name="get_texture" qualifiers="const">
<return type="Texture">
</return>
<description>
</description>
</method>
- <method name="set_margin_size" >
+ <method name="set_margin_size">
<argument index="0" name="margin" type="int">
</argument>
<argument index="1" name="size" type="float">
@@ -28507,15 +34198,15 @@
<description>
</description>
</method>
- <method name="get_margin_size" qualifiers="const" >
+ <method name="get_margin_size" qualifiers="const">
<return type="float">
</return>
- <argument index="0" name="arg0" type="int">
+ <argument index="0" name="margin" type="int">
</argument>
<description>
</description>
</method>
- <method name="set_expand_margin_size" >
+ <method name="set_expand_margin_size">
<argument index="0" name="margin" type="int">
</argument>
<argument index="1" name="size" type="float">
@@ -28523,21 +34214,21 @@
<description>
</description>
</method>
- <method name="get_expand_margin_size" qualifiers="const" >
+ <method name="get_expand_margin_size" qualifiers="const">
<return type="float">
</return>
- <argument index="0" name="arg0" type="int">
+ <argument index="0" name="margin" type="int">
</argument>
<description>
</description>
</method>
- <method name="set_draw_center" >
+ <method name="set_draw_center">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="get_draw_center" qualifiers="const" >
+ <method name="get_draw_center" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -28555,85 +34246,85 @@
Helper tool to create geometry.
</description>
<methods>
- <method name="begin" >
+ <method name="begin">
<argument index="0" name="primitive" type="int">
</argument>
<description>
</description>
</method>
- <method name="add_vertex" >
+ <method name="add_vertex">
<argument index="0" name="vertex" type="Vector3">
</argument>
<description>
</description>
</method>
- <method name="add_color" >
+ <method name="add_color">
<argument index="0" name="color" type="Color">
</argument>
<description>
</description>
</method>
- <method name="add_normal" >
+ <method name="add_normal">
<argument index="0" name="normal" type="Vector3">
</argument>
<description>
</description>
</method>
- <method name="add_tangent" >
+ <method name="add_tangent">
<argument index="0" name="tangent" type="Plane">
</argument>
<description>
</description>
</method>
- <method name="add_uv" >
+ <method name="add_uv">
<argument index="0" name="uv" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="add_uv2" >
+ <method name="add_uv2">
<argument index="0" name="uv2" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="add_bones" >
+ <method name="add_bones">
<argument index="0" name="bones" type="IntArray">
</argument>
<description>
</description>
</method>
- <method name="add_weights" >
+ <method name="add_weights">
<argument index="0" name="weights" type="RealArray">
</argument>
<description>
</description>
</method>
- <method name="add_smooth_group" >
+ <method name="add_smooth_group">
<argument index="0" name="smooth" type="bool">
</argument>
<description>
</description>
</method>
- <method name="set_material" >
+ <method name="set_material">
<argument index="0" name="material" type="Material">
</argument>
<description>
</description>
</method>
- <method name="index" >
+ <method name="index">
<description>
</description>
</method>
- <method name="deindex" >
+ <method name="deindex">
<description>
</description>
</method>
- <method name="generate_normals" >
+ <method name="generate_normals">
<description>
</description>
</method>
- <method name="commit" >
+ <method name="commit">
<return type="Mesh">
</return>
<argument index="0" name="existing" type="Mesh" default="Object()">
@@ -28641,7 +34332,7 @@
<description>
</description>
</method>
- <method name="clear" >
+ <method name="clear">
<description>
</description>
</method>
@@ -28654,10 +34345,10 @@
TCP Server.
</brief_description>
<description>
- TCP Server class. Listens to connections on a port and returns a StreamPeerTCP when got a connection.
+ TCP Server class. Listens to connections on a port and returns a [StreamPeerTCP] when got a connection.
</description>
<methods>
- <method name="listen" >
+ <method name="listen">
<return type="int">
</return>
<argument index="0" name="port" type="int">
@@ -28668,21 +34359,21 @@
Listen on a port, alternatively give a white-list of accepted hosts.
</description>
</method>
- <method name="is_connection_available" qualifiers="const" >
+ <method name="is_connection_available" qualifiers="const">
<return type="bool">
</return>
<description>
Return true if a connection is available for taking.
</description>
</method>
- <method name="take_connection" >
+ <method name="take_connection">
<return type="Object">
</return>
<description>
If a connection is available, return a StreamPeerTCP with the connection/
</description>
</method>
- <method name="stop" >
+ <method name="stop">
<description>
Stop listening.
</description>
@@ -28696,60 +34387,74 @@
Tabbed Container.
</brief_description>
<description>
- Tabbed Container. Contains several children controls, but shows only one at the same time. Clicking ont he top tabs allows to change the current visible one.[br]
+ Tabbed Container. Contains several children controls, but shows only one at the same time. Clicking on the top tabs allows to change the currently visible one.
Children controls of this one automatically.
</description>
<methods>
- <method name="get_tab_count" qualifiers="const" >
+ <method name="get_tab_count" qualifiers="const">
<return type="int">
</return>
<description>
Return the amount of tabs.
</description>
</method>
- <method name="set_current_tab" >
+ <method name="set_current_tab">
<argument index="0" name="tab_idx" type="int">
</argument>
<description>
Bring a tab (and the Control it represents) to the front, and hide the rest.
</description>
</method>
- <method name="get_current_tab" qualifiers="const" >
+ <method name="get_current_tab" qualifiers="const">
<return type="int">
</return>
<description>
Return the current tab that is being showed.
</description>
</method>
- <method name="set_tab_align" >
+ <method name="get_current_tab_control" qualifiers="const">
+ <return type="Control">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_tab_control" qualifiers="const">
+ <return type="Control">
+ </return>
+ <argument index="0" name="idx" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_tab_align">
<argument index="0" name="align" type="int">
</argument>
<description>
Set tab alignment, from the ALIGN_* enum. Moves tabs to the left, right or center.
</description>
</method>
- <method name="get_tab_align" qualifiers="const" >
+ <method name="get_tab_align" qualifiers="const">
<return type="int">
</return>
<description>
- Return tab alignment, from the ALIGN_* enum
+ Return tab alignment, from the ALIGN_* enum.
</description>
</method>
- <method name="set_tabs_visible" >
+ <method name="set_tabs_visible">
<argument index="0" name="visible" type="bool">
</argument>
<description>
Set whether the tabs should be visible or hidden.
</description>
</method>
- <method name="are_tabs_visible" qualifiers="const" >
+ <method name="are_tabs_visible" qualifiers="const">
<return type="bool">
</return>
<description>
Return whether the tabs should be visible or hidden.
</description>
</method>
- <method name="set_tab_title" >
+ <method name="set_tab_title">
<argument index="0" name="tab_idx" type="int">
</argument>
<argument index="1" name="title" type="String">
@@ -28758,7 +34463,7 @@
Set a title for the tab. Tab titles are by default the children node name, but this can be overriden.
</description>
</method>
- <method name="get_tab_title" qualifiers="const" >
+ <method name="get_tab_title" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="tab_idx" type="int">
@@ -28767,7 +34472,7 @@
Return the title for the tab. Tab titles are by default the children node name, but this can be overriden.
</description>
</method>
- <method name="set_tab_icon" >
+ <method name="set_tab_icon">
<argument index="0" name="tab_idx" type="int">
</argument>
<argument index="1" name="icon" type="Texture">
@@ -28776,7 +34481,7 @@
Set an icon for a tab.
</description>
</method>
- <method name="get_tab_icon" qualifiers="const" >
+ <method name="get_tab_icon" qualifiers="const">
<return type="Texture">
</return>
<argument index="0" name="tab_idx" type="int">
@@ -28784,8 +34489,24 @@
<description>
</description>
</method>
+ <method name="set_popup">
+ <argument index="0" name="popup" type="Popup">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_popup" qualifiers="const">
+ <return type="Popup">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<signals>
+ <signal name="pre_popup_pressed">
+ <description>
+ </description>
+ </signal>
<signal name="tab_changed">
<argument index="0" name="tab" type="int">
</argument>
@@ -28811,8 +34532,12 @@
</theme_item>
<theme_item name="font_color_fg" type="Color">
</theme_item>
+ <theme_item name="menu_hilite" type="Texture">
+ </theme_item>
<theme_item name="increment_hilite" type="Texture">
</theme_item>
+ <theme_item name="menu" type="Texture">
+ </theme_item>
<theme_item name="decrement_hilite" type="Texture">
</theme_item>
<theme_item name="increment" type="Texture">
@@ -28837,25 +34562,25 @@
Simple tabs control, similar to [TabContainer] but is only in charge of drawing tabs, not interact with children.
</description>
<methods>
- <method name="get_tab_count" qualifiers="const" >
+ <method name="get_tab_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_current_tab" >
+ <method name="set_current_tab">
<argument index="0" name="tab_idx" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_current_tab" qualifiers="const" >
+ <method name="get_current_tab" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_tab_title" >
+ <method name="set_tab_title">
<argument index="0" name="tab_idx" type="int">
</argument>
<argument index="1" name="title" type="String">
@@ -28863,7 +34588,7 @@
<description>
</description>
</method>
- <method name="get_tab_title" qualifiers="const" >
+ <method name="get_tab_title" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="tab_idx" type="int">
@@ -28871,7 +34596,7 @@
<description>
</description>
</method>
- <method name="set_tab_icon" >
+ <method name="set_tab_icon">
<argument index="0" name="tab_idx" type="int">
</argument>
<argument index="1" name="icon" type="Texture">
@@ -28879,7 +34604,7 @@
<description>
</description>
</method>
- <method name="get_tab_icon" qualifiers="const" >
+ <method name="get_tab_icon" qualifiers="const">
<return type="Texture">
</return>
<argument index="0" name="tab_idx" type="int">
@@ -28887,13 +34612,13 @@
<description>
</description>
</method>
- <method name="remove_tab" >
+ <method name="remove_tab">
<argument index="0" name="tab_idx" type="int">
</argument>
<description>
</description>
</method>
- <method name="add_tab" >
+ <method name="add_tab">
<argument index="0" name="title" type="String">
</argument>
<argument index="1" name="icon" type="Texture">
@@ -28901,8 +34626,32 @@
<description>
</description>
</method>
+ <method name="set_tab_align">
+ <argument index="0" name="align" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_tab_align" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<signals>
+ <signal name="tab_close">
+ <argument index="0" name="tab" type="int">
+ </argument>
+ <description>
+ </description>
+ </signal>
+ <signal name="right_button_pressed">
+ <argument index="0" name="tab" type="int">
+ </argument>
+ <description>
+ </description>
+ </signal>
<signal name="tab_changed">
<argument index="0" name="tab" type="int">
</argument>
@@ -28911,6 +34660,20 @@
</signal>
</signals>
<constants>
+ <constant name="ALIGN_LEFT" value="0">
+ </constant>
+ <constant name="ALIGN_CENTER" value="1">
+ </constant>
+ <constant name="ALIGN_RIGHT" value="2">
+ </constant>
+ <constant name="SHOW_ACTIVE_ONLY" value="1">
+ </constant>
+ <constant name="SHOW_ALWAYS" value="0">
+ </constant>
+ <constant name="SHOW_HOVER" value="2">
+ </constant>
+ <constant name="SHOW_NEVER" value="3">
+ </constant>
</constants>
<theme_items>
<theme_item name="label_valign_fg" type="int">
@@ -28925,14 +34688,26 @@
</theme_item>
<theme_item name="font_color_fg" type="Color">
</theme_item>
+ <theme_item name="increment_hilite" type="Texture">
+ </theme_item>
+ <theme_item name="decrement_hilite" type="Texture">
+ </theme_item>
+ <theme_item name="increment" type="Texture">
+ </theme_item>
+ <theme_item name="decrement" type="Texture">
+ </theme_item>
<theme_item name="font" type="Font">
</theme_item>
<theme_item name="tab_fg" type="StyleBox">
</theme_item>
+ <theme_item name="button" type="StyleBox">
+ </theme_item>
<theme_item name="tab_bg" type="StyleBox">
</theme_item>
<theme_item name="panel" type="StyleBox">
</theme_item>
+ <theme_item name="button_pressed" type="StyleBox">
+ </theme_item>
</theme_items>
</class>
<class name="TestCube" inherits="GeometryInstance" category="Core">
@@ -28953,113 +34728,115 @@
TextEdit is meant for editing large, multiline text. It also has facilities for editing code, such as syntax highlighting support and multiple levels of undo/redo.
</description>
<methods>
- <method name="set_text" >
+ <method name="set_text">
<argument index="0" name="text" type="String">
</argument>
<description>
Set the entire text.
</description>
</method>
- <method name="insert_text_at_cursor" >
+ <method name="insert_text_at_cursor">
<argument index="0" name="text" type="String">
</argument>
<description>
Insert a given text at the cursor position.
</description>
</method>
- <method name="get_line_count" qualifiers="const" >
+ <method name="get_line_count" qualifiers="const">
<return type="int">
</return>
<description>
Return the amount of total lines in the text.
</description>
</method>
- <method name="get_text" >
+ <method name="get_text">
<return type="String">
</return>
<description>
Return the whole text.
</description>
</method>
- <method name="get_line" qualifiers="const" >
+ <method name="get_line" qualifiers="const">
<return type="String">
</return>
- <argument index="0" name="arg0" type="int">
+ <argument index="0" name="line" type="int">
</argument>
<description>
Return the text of a specific line.
</description>
</method>
- <method name="cursor_set_column" >
+ <method name="cursor_set_column">
<argument index="0" name="column" type="int">
</argument>
+ <argument index="1" name="adjust_viewport" type="bool" default="false">
+ </argument>
<description>
- Set the current column of the text editor.
</description>
</method>
- <method name="cursor_set_line" >
+ <method name="cursor_set_line">
<argument index="0" name="line" type="int">
</argument>
+ <argument index="1" name="adjust_viewport" type="bool" default="false">
+ </argument>
<description>
- Set the current line of the text editor.
</description>
</method>
- <method name="cursor_get_column" qualifiers="const" >
+ <method name="cursor_get_column" qualifiers="const">
<return type="int">
</return>
<description>
Return the column the editing cursor is at.
</description>
</method>
- <method name="cursor_get_line" qualifiers="const" >
+ <method name="cursor_get_line" qualifiers="const">
<return type="int">
</return>
<description>
Return the line the editing cursor is at.
</description>
</method>
- <method name="set_readonly" >
+ <method name="set_readonly">
<argument index="0" name="enable" type="bool">
</argument>
<description>
Set the text editor as read-only. Text can be displayed but not edited.
</description>
</method>
- <method name="set_wrap" >
+ <method name="set_wrap">
<argument index="0" name="enable" type="bool">
</argument>
<description>
Enable text wrapping when it goes beyond he edge of what is visible.
</description>
</method>
- <method name="set_max_chars" >
+ <method name="set_max_chars">
<argument index="0" name="amount" type="int">
</argument>
<description>
Set the maximum amount of characters editable.
</description>
</method>
- <method name="cut" >
+ <method name="cut">
<description>
Cut the current selection.
</description>
</method>
- <method name="copy" >
+ <method name="copy">
<description>
Copy the current selection.
</description>
</method>
- <method name="paste" >
+ <method name="paste">
<description>
Paste the current selection.
</description>
</method>
- <method name="select_all" >
+ <method name="select_all">
<description>
Select all the text.
</description>
</method>
- <method name="select" >
+ <method name="select">
<argument index="0" name="from_line" type="int">
</argument>
<argument index="1" name="from_column" type="int">
@@ -29072,55 +34849,55 @@
Perform selection, from line/column to line/column.
</description>
</method>
- <method name="is_selection_active" qualifiers="const" >
+ <method name="is_selection_active" qualifiers="const">
<return type="bool">
</return>
<description>
Return true if the selection is active.
</description>
</method>
- <method name="get_selection_from_line" qualifiers="const" >
+ <method name="get_selection_from_line" qualifiers="const">
<return type="int">
</return>
<description>
Return the selection begin line.
</description>
</method>
- <method name="get_selection_from_column" qualifiers="const" >
+ <method name="get_selection_from_column" qualifiers="const">
<return type="int">
</return>
<description>
Return the selection begin column.
</description>
</method>
- <method name="get_selection_to_line" qualifiers="const" >
+ <method name="get_selection_to_line" qualifiers="const">
<return type="int">
</return>
<description>
Return the selection end line.
</description>
</method>
- <method name="get_selection_to_column" qualifiers="const" >
+ <method name="get_selection_to_column" qualifiers="const">
<return type="int">
</return>
<description>
Return the selection end column.
</description>
</method>
- <method name="get_selection_text" qualifiers="const" >
+ <method name="get_selection_text" qualifiers="const">
<return type="String">
</return>
<description>
Return the text inside the selection.
</description>
</method>
- <method name="get_word_under_cursor" qualifiers="const" >
+ <method name="get_word_under_cursor" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="search" qualifiers="const" >
+ <method name="search" qualifiers="const">
<return type="IntArray">
</return>
<argument index="0" name="flags" type="String">
@@ -29135,45 +34912,45 @@
Perform a search inside the text. Search flags can be specified in the SEARCH_* enum.
</description>
</method>
- <method name="undo" >
+ <method name="undo">
<description>
Perform undo operation.
</description>
</method>
- <method name="redo" >
+ <method name="redo">
<description>
Perform redo operation.
</description>
</method>
- <method name="clear_undo_history" >
+ <method name="clear_undo_history">
<description>
Clear the undo history.
</description>
</method>
- <method name="set_syntax_coloring" >
+ <method name="set_syntax_coloring">
<argument index="0" name="enable" type="bool">
</argument>
<description>
Set to enable the syntax coloring.
</description>
</method>
- <method name="is_syntax_coloring_enabled" qualifiers="const" >
+ <method name="is_syntax_coloring_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
Return true if the syntax coloring is enabled.
</description>
</method>
- <method name="add_keyword_color" >
+ <method name="add_keyword_color">
<argument index="0" name="keyword" type="String">
</argument>
<argument index="1" name="color" type="Color">
</argument>
<description>
- Add a keyword and it's color.
+ Add a keyword and its color.
</description>
</method>
- <method name="add_color_region" >
+ <method name="add_color_region">
<argument index="0" name="begin_key" type="String">
</argument>
<argument index="1" name="end_key" type="String">
@@ -29183,24 +34960,24 @@
<argument index="3" name="line_only" type="bool" default="false">
</argument>
<description>
- Add color region (given the delimiters) and it's colors.
+ Add color region (given the delimiters) and its colors.
</description>
</method>
- <method name="set_symbol_color" >
+ <method name="set_symbol_color">
<argument index="0" name="color" type="Color">
</argument>
<description>
Set the color for symbols.
</description>
</method>
- <method name="set_custom_bg_color" >
+ <method name="set_custom_bg_color">
<argument index="0" name="color" type="Color">
</argument>
<description>
Set a custom background color. A background color with alpha==0 disables this.
</description>
</method>
- <method name="clear_colors" >
+ <method name="clear_colors">
<description>
Clear all the syntax coloring information.
</description>
@@ -29218,10 +34995,6 @@
</description>
</signal>
<signal name="request_completion">
- <argument index="0" name="keyword" type="String">
- </argument>
- <argument index="1" name="line" type="int">
- </argument>
<description>
</description>
</signal>
@@ -29262,6 +35035,8 @@
</theme_item>
<theme_item name="completion_scroll_color" type="Color">
</theme_item>
+ <theme_item name="brace_mismatch_color" type="Color">
+ </theme_item>
<theme_item name="current_line_color" type="Color">
</theme_item>
<theme_item name="mark_color" type="Color">
@@ -29288,66 +35063,67 @@
A texture works by registering an image in the video hardware, which then can be used in 3D models or 2D [Sprite] or GUI [Control]s.
</description>
<methods>
- <method name="get_width" qualifiers="const" >
+ <method name="get_width" qualifiers="const">
<return type="int">
</return>
<description>
Return the texture width.
</description>
</method>
- <method name="get_height" qualifiers="const" >
+ <method name="get_height" qualifiers="const">
<return type="int">
</return>
<description>
Return the texture height.
</description>
</method>
- <method name="get_size" qualifiers="const" >
+ <method name="get_size" qualifiers="const">
<return type="Vector2">
</return>
<description>
Return the texture size.
</description>
</method>
- <method name="get_rid" qualifiers="const" >
+ <method name="get_rid" qualifiers="const">
<return type="RID">
</return>
<description>
Return the texture RID as used in the [VisualServer].
</description>
</method>
- <method name="has_alpha" qualifiers="const" >
+ <method name="has_alpha" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_flags" >
+ <method name="set_flags">
<argument index="0" name="flags" type="int">
</argument>
<description>
Change the texture flags.
</description>
</method>
- <method name="get_flags" qualifiers="const" >
+ <method name="get_flags" qualifiers="const">
<return type="int">
</return>
<description>
Return the current texture flags.
</description>
</method>
- <method name="draw" qualifiers="const" >
+ <method name="draw" qualifiers="const">
<argument index="0" name="canvas_item" type="RID">
</argument>
<argument index="1" name="pos" type="Vector2">
</argument>
<argument index="2" name="modulate" type="Color" default="Color(1,1,1,1)">
</argument>
+ <argument index="3" name="transpose" type="bool" default="false">
+ </argument>
<description>
- Draw the texture into a a [VisualServer] canvas item.
</description>
</method>
- <method name="draw_rect" qualifiers="const" >
+ <method name="draw_rect" qualifiers="const">
<argument index="0" name="canvas_item" type="RID">
</argument>
<argument index="1" name="rect" type="Rect2">
@@ -29356,10 +35132,12 @@
</argument>
<argument index="3" name="modulate" type="Color" default="Color(1,1,1,1)">
</argument>
+ <argument index="4" name="transpose" type="bool" default="false">
+ </argument>
<description>
</description>
</method>
- <method name="draw_rect_region" qualifiers="const" >
+ <method name="draw_rect_region" qualifiers="const">
<argument index="0" name="canvas_item" type="RID">
</argument>
<argument index="1" name="rect" type="Rect2">
@@ -29368,30 +35146,34 @@
</argument>
<argument index="3" name="modulate" type="Color" default="Color(1,1,1,1)">
</argument>
+ <argument index="4" name="transpose" type="bool" default="false">
+ </argument>
<description>
</description>
</method>
</methods>
<constants>
<constant name="FLAG_MIPMAPS" value="1">
- Generate mipmaps.
+ Generate mipmaps, to enable smooth zooming out of the texture.
</constant>
<constant name="FLAG_REPEAT" value="2">
Repeat (instead of clamp to edge).
</constant>
<constant name="FLAG_FILTER" value="4">
- Turn on magnifying filter.
+ Turn on magnifying filter, to enable smooth zooming in of the texture.
</constant>
<constant name="FLAG_VIDEO_SURFACE" value="4096">
- Texture is a video surface
+ Texture is a video surface.
</constant>
<constant name="FLAGS_DEFAULT" value="7">
- Default flags
+ Default flags. Generate mipmaps, repeat, and filter are enabled.
</constant>
<constant name="FLAG_ANISOTROPIC_FILTER" value="8">
</constant>
<constant name="FLAG_CONVERT_TO_LINEAR" value="16">
</constant>
+ <constant name="FLAG_MIRRORED_REPEAT" value="32">
+ </constant>
</constants>
</class>
<class name="TextureButton" inherits="BaseButton" category="Core">
@@ -29399,82 +35181,106 @@
Button that can be themed with textures.
</brief_description>
<description>
- Button that can be themed with textures. This is like a regular [Button] but can be themed by assigning textures to it. This button is intended to be easy to theme, however a regular button can expand (that uses styleboxes) and still be better if the interface is expect to have internationalization of texts.[br]
+ Button that can be themed with textures. This is like a regular [Button] but can be themed by assigning textures to it. This button is intended to be easy to theme, however a regular button can expand (that uses styleboxes) and still be better if the interface is expect to have internationalization of texts.
Only the normal texture is required, the others are optional.
</description>
<methods>
- <method name="set_normal_texture" >
+ <method name="set_normal_texture">
<argument index="0" name="texture" type="Texture">
</argument>
<description>
</description>
</method>
- <method name="set_pressed_texture" >
+ <method name="set_pressed_texture">
<argument index="0" name="texture" type="Texture">
</argument>
<description>
</description>
</method>
- <method name="set_hover_texture" >
+ <method name="set_hover_texture">
<argument index="0" name="texture" type="Texture">
</argument>
<description>
</description>
</method>
- <method name="set_disabled_texture" >
+ <method name="set_disabled_texture">
<argument index="0" name="texture" type="Texture">
</argument>
<description>
</description>
</method>
- <method name="set_focused_texture" >
+ <method name="set_focused_texture">
<argument index="0" name="texture" type="Texture">
</argument>
<description>
</description>
</method>
- <method name="set_click_mask" >
+ <method name="set_click_mask">
<argument index="0" name="mask" type="BitMap">
</argument>
<description>
</description>
</method>
- <method name="get_normal_texture" qualifiers="const" >
+ <method name="set_texture_scale">
+ <argument index="0" name="scale" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="set_modulate">
+ <argument index="0" name="color" type="Color">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_normal_texture" qualifiers="const">
<return type="Texture">
</return>
<description>
</description>
</method>
- <method name="get_pressed_texture" qualifiers="const" >
+ <method name="get_pressed_texture" qualifiers="const">
<return type="Texture">
</return>
<description>
</description>
</method>
- <method name="get_hover_texture" qualifiers="const" >
+ <method name="get_hover_texture" qualifiers="const">
<return type="Texture">
</return>
<description>
</description>
</method>
- <method name="get_disabled_texture" qualifiers="const" >
+ <method name="get_disabled_texture" qualifiers="const">
<return type="Texture">
</return>
<description>
</description>
</method>
- <method name="get_focused_texture" qualifiers="const" >
+ <method name="get_focused_texture" qualifiers="const">
<return type="Texture">
</return>
<description>
</description>
</method>
- <method name="get_click_mask" qualifiers="const" >
+ <method name="get_click_mask" qualifiers="const">
<return type="BitMap">
</return>
<description>
</description>
</method>
+ <method name="get_texture_scale" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_modulate" qualifiers="const">
+ <return type="Color">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
</constants>
@@ -29487,37 +35293,37 @@
Control frame that simply draws an assigned texture. It can stretch or not. It's a simple way to just show an image in a UI.
</description>
<methods>
- <method name="set_texture" >
+ <method name="set_texture">
<argument index="0" name="texture" type="Object">
</argument>
<description>
</description>
</method>
- <method name="get_texture" qualifiers="const" >
+ <method name="get_texture" qualifiers="const">
<return type="Object">
</return>
<description>
</description>
</method>
- <method name="set_modulate" >
+ <method name="set_modulate">
<argument index="0" name="modulate" type="Color">
</argument>
<description>
</description>
</method>
- <method name="get_modulate" qualifiers="const" >
+ <method name="get_modulate" qualifiers="const">
<return type="Color">
</return>
<description>
</description>
</method>
- <method name="set_expand" >
+ <method name="set_expand">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="has_expand" qualifiers="const" >
+ <method name="has_expand" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -29535,44 +35341,104 @@
[ProgressBar] implementation that is easier to theme (by just passing a few textures).
</description>
<methods>
- <method name="set_under_texture" >
+ <method name="set_under_texture">
<argument index="0" name="tex" type="Object">
</argument>
<description>
</description>
</method>
- <method name="get_under_texture" qualifiers="const" >
+ <method name="get_under_texture" qualifiers="const">
<return type="Object">
</return>
<description>
</description>
</method>
- <method name="set_progress_texture" >
+ <method name="set_progress_texture">
<argument index="0" name="tex" type="Object">
</argument>
<description>
</description>
</method>
- <method name="get_progress_texture" qualifiers="const" >
+ <method name="get_progress_texture" qualifiers="const">
<return type="Object">
</return>
<description>
</description>
</method>
- <method name="set_over_texture" >
+ <method name="set_over_texture">
<argument index="0" name="tex" type="Object">
</argument>
<description>
</description>
</method>
- <method name="get_over_texture" qualifiers="const" >
+ <method name="get_over_texture" qualifiers="const">
<return type="Object">
</return>
<description>
</description>
</method>
+ <method name="set_fill_mode">
+ <argument index="0" name="mode" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_fill_mode">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_radial_initial_angle">
+ <argument index="0" name="mode" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_radial_initial_angle">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_radial_center_offset">
+ <argument index="0" name="mode" type="Vector2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_radial_center_offset">
+ <return type="Vector2">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_fill_degrees">
+ <argument index="0" name="mode" type="float">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_fill_degrees">
+ <return type="float">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
+ <constant name="FILL_LEFT_TO_RIGHT" value="0">
+ </constant>
+ <constant name="FILL_RIGHT_TO_LEFT" value="1">
+ </constant>
+ <constant name="FILL_TOP_TO_BOTTOM" value="2">
+ </constant>
+ <constant name="FILL_BOTTOM_TO_TOP" value="3">
+ </constant>
+ <constant name="FILL_CLOCKWISE" value="4">
+ </constant>
+ <constant name="FILL_COUNTER_CLOCKWISE" value="5">
+ </constant>
</constants>
</class>
<class name="Theme" inherits="Resource" category="Core">
@@ -29580,11 +35446,11 @@
Theme for controls.
</brief_description>
<description>
- Theme for skinning controls. Controls can be skinned individually, but for complex applications it's more efficient to just create a global theme that defines everything. This theme can be applied to any [Control], and it and the children will automatically use it.[br]
+ Theme for skinning controls. Controls can be skinned individually, but for complex applications it's more efficient to just create a global theme that defines everything. This theme can be applied to any [Control], and it and its children will automatically use it.
Theme resources can be alternatively loaded by writing them in a .theme file, see wiki for more info.
</description>
<methods>
- <method name="set_icon" >
+ <method name="set_icon">
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="type" type="String">
@@ -29594,7 +35460,7 @@
<description>
</description>
</method>
- <method name="get_icon" qualifiers="const" >
+ <method name="get_icon" qualifiers="const">
<return type="Texture">
</return>
<argument index="0" name="name" type="String">
@@ -29604,7 +35470,7 @@
<description>
</description>
</method>
- <method name="has_icon" qualifiers="const" >
+ <method name="has_icon" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="name" type="String">
@@ -29614,7 +35480,7 @@
<description>
</description>
</method>
- <method name="clear_icon" >
+ <method name="clear_icon">
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="type" type="String">
@@ -29622,15 +35488,15 @@
<description>
</description>
</method>
- <method name="get_icon_list" qualifiers="const" >
+ <method name="get_icon_list" qualifiers="const">
<return type="StringArray">
</return>
- <argument index="0" name="arg0" type="String">
+ <argument index="0" name="type" type="String">
</argument>
<description>
</description>
</method>
- <method name="set_stylebox" >
+ <method name="set_stylebox">
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="type" type="String">
@@ -29640,7 +35506,7 @@
<description>
</description>
</method>
- <method name="get_stylebox" qualifiers="const" >
+ <method name="get_stylebox" qualifiers="const">
<return type="StyleBox">
</return>
<argument index="0" name="name" type="String">
@@ -29650,7 +35516,7 @@
<description>
</description>
</method>
- <method name="has_stylebox" qualifiers="const" >
+ <method name="has_stylebox" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="name" type="String">
@@ -29660,7 +35526,7 @@
<description>
</description>
</method>
- <method name="clear_stylebox" >
+ <method name="clear_stylebox">
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="type" type="String">
@@ -29668,15 +35534,15 @@
<description>
</description>
</method>
- <method name="get_stylebox_list" qualifiers="const" >
+ <method name="get_stylebox_list" qualifiers="const">
<return type="StringArray">
</return>
- <argument index="0" name="arg0" type="String">
+ <argument index="0" name="type" type="String">
</argument>
<description>
</description>
</method>
- <method name="set_font" >
+ <method name="set_font">
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="type" type="String">
@@ -29686,7 +35552,7 @@
<description>
</description>
</method>
- <method name="get_font" qualifiers="const" >
+ <method name="get_font" qualifiers="const">
<return type="Font">
</return>
<argument index="0" name="name" type="String">
@@ -29696,7 +35562,7 @@
<description>
</description>
</method>
- <method name="has_font" qualifiers="const" >
+ <method name="has_font" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="name" type="String">
@@ -29706,7 +35572,7 @@
<description>
</description>
</method>
- <method name="clear_font" >
+ <method name="clear_font">
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="type" type="String">
@@ -29714,15 +35580,15 @@
<description>
</description>
</method>
- <method name="get_font_list" qualifiers="const" >
+ <method name="get_font_list" qualifiers="const">
<return type="StringArray">
</return>
- <argument index="0" name="arg0" type="String">
+ <argument index="0" name="type" type="String">
</argument>
<description>
</description>
</method>
- <method name="set_color" >
+ <method name="set_color">
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="type" type="String">
@@ -29732,7 +35598,7 @@
<description>
</description>
</method>
- <method name="get_color" qualifiers="const" >
+ <method name="get_color" qualifiers="const">
<return type="Color">
</return>
<argument index="0" name="name" type="String">
@@ -29742,7 +35608,7 @@
<description>
</description>
</method>
- <method name="has_color" qualifiers="const" >
+ <method name="has_color" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="name" type="String">
@@ -29752,7 +35618,7 @@
<description>
</description>
</method>
- <method name="clear_color" >
+ <method name="clear_color">
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="type" type="String">
@@ -29760,15 +35626,15 @@
<description>
</description>
</method>
- <method name="get_color_list" qualifiers="const" >
+ <method name="get_color_list" qualifiers="const">
<return type="StringArray">
</return>
- <argument index="0" name="arg0" type="String">
+ <argument index="0" name="type" type="String">
</argument>
<description>
</description>
</method>
- <method name="set_constant" >
+ <method name="set_constant">
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="type" type="String">
@@ -29778,7 +35644,7 @@
<description>
</description>
</method>
- <method name="get_constant" qualifiers="const" >
+ <method name="get_constant" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="name" type="String">
@@ -29788,7 +35654,7 @@
<description>
</description>
</method>
- <method name="has_constant" qualifiers="const" >
+ <method name="has_constant" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="name" type="String">
@@ -29798,7 +35664,7 @@
<description>
</description>
</method>
- <method name="clear_constant" >
+ <method name="clear_constant">
<argument index="0" name="name" type="String">
</argument>
<argument index="1" name="type" type="String">
@@ -29806,35 +35672,35 @@
<description>
</description>
</method>
- <method name="get_constant_list" qualifiers="const" >
+ <method name="get_constant_list" qualifiers="const">
<return type="StringArray">
</return>
- <argument index="0" name="arg0" type="String">
+ <argument index="0" name="type" type="String">
</argument>
<description>
</description>
</method>
- <method name="set_default_font" >
+ <method name="set_default_font">
<argument index="0" name="font" type="Object">
</argument>
<description>
</description>
</method>
- <method name="get_default_font" qualifiers="const" >
+ <method name="get_default_font" qualifiers="const">
<return type="Object">
</return>
<description>
</description>
</method>
- <method name="get_type_list" qualifiers="const" >
+ <method name="get_type_list" qualifiers="const">
<return type="StringArray">
</return>
- <argument index="0" name="arg0" type="String">
+ <argument index="0" name="type" type="String">
</argument>
<description>
</description>
</method>
- <method name="copy_default_theme" >
+ <method name="copy_default_theme">
<description>
</description>
</method>
@@ -29848,8 +35714,8 @@
<description>
</description>
<methods>
- <method name="start" >
- <return type="int">
+ <method name="start">
+ <return type="Error">
</return>
<argument index="0" name="instance" type="Object">
</argument>
@@ -29862,19 +35728,29 @@
<description>
</description>
</method>
- <method name="get_id" qualifiers="const" >
+ <method name="get_id" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="is_active" qualifiers="const" >
+ <method name="is_active" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="wait_to_finish" >
+ <method name="wait_to_finish">
+ <return type="Variant">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_name">
+ <return type="Error">
+ </return>
+ <argument index="0" name="name" type="String">
+ </argument>
<description>
</description>
</method>
@@ -29890,156 +35766,243 @@
</class>
<class name="TileMap" inherits="Node2D" category="Core">
<brief_description>
- Node for 2D Tile-Based games.
+ Node for 2D tile-based games.
</brief_description>
<description>
- Node for 2D Tile-Based games. Tilemaps use a TileSet which contain a list of tiles (textures, their rect and a collision) and are used to create complex grid-based maps.
- To optimize drawing and culling (sort of like [GridMap]), you can specify a quadrant size, so chunks of the map will be batched together the time of drawing.
+ Node for 2D tile-based games. Tilemaps use a [TileSet] which contain a list of tiles (textures, their rect and a collision) and are used to create complex grid-based maps.
+ To optimize drawing and culling (sort of like [GridMap]), you can specify a quadrant size, so chunks of the map will be batched together at drawing time.
</description>
<methods>
- <method name="set_tileset" >
+ <method name="set_tileset">
<argument index="0" name="tileset" type="TileSet">
</argument>
<description>
Set the current tileset.
</description>
</method>
- <method name="get_tileset" qualifiers="const" >
+ <method name="get_tileset" qualifiers="const">
<return type="TileSet">
</return>
<description>
Return the current tileset.
</description>
</method>
- <method name="set_mode" >
+ <method name="set_mode">
<argument index="0" name="mode" type="int">
</argument>
<description>
+ Set the orientation mode as square, isometric or custom (use MODE_* constants as argument).
</description>
</method>
- <method name="get_mode" qualifiers="const" >
+ <method name="get_mode" qualifiers="const">
<return type="int">
</return>
<description>
+ Return the orientation mode.
</description>
</method>
- <method name="set_half_offset" >
+ <method name="set_half_offset">
<argument index="0" name="half_offset" type="int">
</argument>
<description>
+ Set an half offset on the X coordinate, Y coordinate, or none (use HALF_OFFSET_* constants as argument).
+ Half offset sets every other tile off by a half tile size in the specified direction.
</description>
</method>
- <method name="get_half_offset" qualifiers="const" >
+ <method name="get_half_offset" qualifiers="const">
<return type="int">
</return>
<description>
+ Return the current half offset configuration.
</description>
</method>
- <method name="set_custom_transform" >
+ <method name="set_custom_transform">
<argument index="0" name="custom_transform" type="Matrix32">
</argument>
<description>
+ Set custom transform matrix, to use in combination with the custom orientation mode.
</description>
</method>
- <method name="get_custom_transform" qualifiers="const" >
+ <method name="get_custom_transform" qualifiers="const">
<return type="Matrix32">
</return>
<description>
+ Return the custom transform matrix.
</description>
</method>
- <method name="set_cell_size" >
+ <method name="set_cell_size">
<argument index="0" name="size" type="Vector2">
</argument>
<description>
Set the cell size.
</description>
</method>
- <method name="get_cell_size" qualifiers="const" >
+ <method name="get_cell_size" qualifiers="const">
<return type="Vector2">
</return>
<description>
Return the cell size.
</description>
</method>
- <method name="set_quadrant_size" >
+ <method name="set_quadrant_size">
<argument index="0" name="size" type="int">
</argument>
<description>
Set the quadrant size, this optimizes drawing by batching chunks of map at draw/cull time.
+ Allowed values are integers ranging from 1 to 128.
+ </description>
+ </method>
+ <method name="get_quadrant_size" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Return the quadrant size.
+ </description>
+ </method>
+ <method name="set_tile_origin">
+ <argument index="0" name="origin" type="int">
+ </argument>
+ <description>
+ Set the tile origin to the tile center or its top-left corner (use TILE_ORIGIN_* constants as argument).
</description>
</method>
- <method name="get_quadrant_size" qualifiers="const" >
+ <method name="get_tile_origin" qualifiers="const">
<return type="int">
</return>
<description>
- Return the quadrant size, this optimizes drawing by batching chunks of map at draw/cull time.
+ Return the tile origin configuration.
</description>
</method>
- <method name="set_center_x" >
+ <method name="set_center_x">
<argument index="0" name="enable" type="bool">
</argument>
<description>
Set tiles to be centered in x coordinate. (by default this is false and they are drawn from upper left cell corner).
</description>
</method>
- <method name="get_center_x" qualifiers="const" >
+ <method name="get_center_x" qualifiers="const">
<return type="bool">
</return>
<description>
Return true if tiles are to be centered in x coordinate (by default this is false and they are drawn from upper left cell corner).
</description>
</method>
- <method name="set_center_y" >
+ <method name="set_center_y">
<argument index="0" name="enable" type="bool">
</argument>
<description>
Set tiles to be centered in y coordinate. (by default this is false and they are drawn from upper left cell corner).
</description>
</method>
- <method name="get_center_y" qualifiers="const" >
+ <method name="get_center_y" qualifiers="const">
<return type="bool">
</return>
<description>
Return true if tiles are to be centered in y coordinate (by default this is false and they are drawn from upper left cell corner).
</description>
</method>
- <method name="set_collision_layer_mask" >
+ <method name="set_y_sort_mode">
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ Set the Y sort mode. Enabled Y sort mode means that children of the tilemap will be drawn in the order defined by their Y coordinate.
+ A tile with a higher Y coordinate will therefore be drawn later, potentially covering up the tile(s) above it if its sprite is higher than its cell size.
+ </description>
+ </method>
+ <method name="is_y_sort_mode_enabled" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Return the Y sort mode.
+ </description>
+ </method>
+ <method name="set_collision_use_kinematic">
+ <argument index="0" name="use_kinematic" type="bool">
+ </argument>
+ <description>
+ Set the tilemap to handle collisions as a kinematic body (enabled) or a static body (disabled).
+ </description>
+ </method>
+ <method name="get_collision_use_kinematic" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ Return whether the tilemap handles collisions as a kinematic body.
+ </description>
+ </method>
+ <method name="set_collision_layer">
+ <argument index="0" name="mask" type="int">
+ </argument>
+ <description>
+ Set the collision layer.
+ Layers are referenced by binary indexes, so allowable values to describe the 20 available layers range from 0 to 2^20-1.
+ </description>
+ </method>
+ <method name="get_collision_layer" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Return the collision layer.
+ </description>
+ </method>
+ <method name="set_collision_mask">
<argument index="0" name="mask" type="int">
</argument>
<description>
+ Set the collision masks.
+ Masks are referenced by binary indexes, so allowable values to describe the 20 available masks range from 0 to 2^20-1.
</description>
</method>
- <method name="get_collision_layer_mask" qualifiers="const" >
+ <method name="get_collision_mask" qualifiers="const">
<return type="int">
</return>
<description>
+ Return the collision mask.
</description>
</method>
- <method name="set_collision_friction" >
+ <method name="set_collision_friction">
<argument index="0" name="value" type="float">
</argument>
<description>
+ Set the collision friction parameter.
+ Allowable values range from 0 to 1.
</description>
</method>
- <method name="get_collision_friction" qualifiers="const" >
+ <method name="get_collision_friction" qualifiers="const">
<return type="float">
</return>
<description>
+ Return the collision friction parameter.
</description>
</method>
- <method name="set_collision_bounce" >
+ <method name="set_collision_bounce">
<argument index="0" name="value" type="float">
</argument>
<description>
+ Set the collision bounce parameter.
+ Allowable values range from 0 to 1.
</description>
</method>
- <method name="get_collision_bounce" qualifiers="const" >
+ <method name="get_collision_bounce" qualifiers="const">
<return type="float">
</return>
<description>
+ Return the collision bounce parameter.
+ </description>
+ </method>
+ <method name="set_occluder_light_mask">
+ <argument index="0" name="mask" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_occluder_light_mask" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
</description>
</method>
- <method name="set_cell" >
+ <method name="set_cell">
<argument index="0" name="x" type="int">
</argument>
<argument index="1" name="y" type="int">
@@ -30050,11 +36013,32 @@
</argument>
<argument index="4" name="flip_y" type="bool" default="false">
</argument>
+ <argument index="5" name="transpose" type="bool" default="false">
+ </argument>
+ <description>
+ Set the tile index for the cell referenced by its grid-based X and Y coordinates.
+ A tile index of -1 clears the cell.
+ Optionally, the tile can also be flipped over the X and Y coordinates or transposed.
+ </description>
+ </method>
+ <method name="set_cellv">
+ <argument index="0" name="pos" type="Vector2">
+ </argument>
+ <argument index="1" name="tile" type="int">
+ </argument>
+ <argument index="2" name="flip_x" type="bool" default="false">
+ </argument>
+ <argument index="3" name="flip_y" type="bool" default="false">
+ </argument>
+ <argument index="4" name="transpose" type="bool" default="false">
+ </argument>
<description>
- Set the contents of a cell. Cells can be optionally flipped in y or x.
+ Set the tile index for the cell referenced by a Vector2 of grid-based coordinates.
+ A tile index of -1 clears the cell.
+ Optionally, the tile can also be flipped over the X and Y axes or transposed.
</description>
</method>
- <method name="get_cell" qualifiers="const" >
+ <method name="get_cell" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="x" type="int">
@@ -30062,10 +36046,10 @@
<argument index="1" name="y" type="int">
</argument>
<description>
- Return the contents of a cell.
+ Return the tile index of the referenced cell.
</description>
</method>
- <method name="is_cell_x_flipped" qualifiers="const" >
+ <method name="is_cell_x_flipped" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="x" type="int">
@@ -30073,10 +36057,10 @@
<argument index="1" name="y" type="int">
</argument>
<description>
- Return if a given cell is flipped in x axis.
+ Return whether the referenced cell is flipped over the X axis.
</description>
</method>
- <method name="is_cell_y_flipped" qualifiers="const" >
+ <method name="is_cell_y_flipped" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="x" type="int">
@@ -30084,15 +36068,22 @@
<argument index="1" name="y" type="int">
</argument>
<description>
- Return if a given cell is flipped in y axis.
+ Return whether the referenced cell is flipped over the Y axis.
</description>
</method>
- <method name="clear" >
+ <method name="clear">
<description>
Clear all cells.
</description>
</method>
- <method name="map_to_world" qualifiers="const" >
+ <method name="get_used_cells" qualifiers="const">
+ <return type="Array">
+ </return>
+ <description>
+ Return an array of all cells containing a tile from the tileset (i.e. a tile index different from -1).
+ </description>
+ </method>
+ <method name="map_to_world" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="mappos" type="Vector2">
@@ -30100,20 +36091,24 @@
<argument index="1" name="ignore_half_ofs" type="bool" default="false">
</argument>
<description>
+ Return the absolute world position corresponding to the tilemap (grid-based) coordinates given as an argument.
+ Optionally, the tilemap's potential half offset can be ignored.
</description>
</method>
- <method name="world_to_map" qualifiers="const" >
+ <method name="world_to_map" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="worldpos" type="Vector2">
</argument>
<description>
+ Return the tilemap (grid-based) coordinates corresponding to the absolute world position given as an argument.
</description>
</method>
</methods>
<signals>
<signal name="settings_changed">
<description>
+ Signal indicating that a tilemap setting has changed.
</description>
</signal>
</signals>
@@ -30122,16 +36117,28 @@
Returned when a cell doesn't exist.
</constant>
<constant name="MODE_SQUARE" value="0">
+ Orthogonal orientation mode.
</constant>
<constant name="MODE_ISOMETRIC" value="1">
+ Isometric orientation mode.
</constant>
<constant name="MODE_CUSTOM" value="2">
+ Custom orientation mode.
</constant>
<constant name="HALF_OFFSET_X" value="0">
+ Half offset on the X coordinate.
</constant>
<constant name="HALF_OFFSET_Y" value="1">
+ Half offset on the Y coordinate.
</constant>
<constant name="HALF_OFFSET_DISABLED" value="2">
+ Half offset disabled.
+ </constant>
+ <constant name="TILE_ORIGIN_TOP_LEFT" value="0">
+ Tile origin at its top-left corner.
+ </constant>
+ <constant name="TILE_ORIGIN_CENTER" value="1">
+ Tile origin at its center.
</constant>
</constants>
</class>
@@ -30141,34 +36148,35 @@
</brief_description>
<description>
A TileSet is a library of tiles for a [TileMap]. It contains a list of tiles, each consisting of a sprite and optional collision shapes.
+ Tiles are referenced by a unique integer ID.
</description>
<methods>
- <method name="create_tile" >
+ <method name="create_tile">
<argument index="0" name="id" type="int">
</argument>
<description>
- Create a new tile, the ID must be specified.
+ Create a new tile which will be referenced by the given ID.
</description>
</method>
- <method name="tile_set_name" >
+ <method name="tile_set_name">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="name" type="String">
</argument>
<description>
- Set the name of a tile, for decriptive purposes.
+ Set the name of the tile, for descriptive purposes.
</description>
</method>
- <method name="tile_get_name" qualifiers="const" >
+ <method name="tile_get_name" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="id" type="int">
</argument>
<description>
- Return the name of a tile, for decriptive purposes.
+ Return the name of the tile.
</description>
</method>
- <method name="tile_set_texture" >
+ <method name="tile_set_texture">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="texture" type="Texture">
@@ -30177,7 +36185,7 @@
Set the texture of the tile.
</description>
</method>
- <method name="tile_get_texture" qualifiers="const" >
+ <method name="tile_get_texture" qualifiers="const">
<return type="Texture">
</return>
<argument index="0" name="id" type="int">
@@ -30186,39 +36194,61 @@
Return the texture of the tile.
</description>
</method>
- <method name="tile_set_texture_offset" >
+ <method name="tile_set_material">
+ <argument index="0" name="id" type="int">
+ </argument>
+ <argument index="1" name="material" type="CanvasItemMaterial">
+ </argument>
+ <description>
+ Set the material of the tile.
+ </description>
+ </method>
+ <method name="tile_get_material" qualifiers="const">
+ <return type="CanvasItemMaterial">
+ </return>
+ <argument index="0" name="id" type="int">
+ </argument>
+ <description>
+ Return the material of the tile.
+ </description>
+ </method>
+ <method name="tile_set_texture_offset">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="texture_offset" type="Vector2">
</argument>
<description>
+ Set the texture offset of the tile.
</description>
</method>
- <method name="tile_get_texture_offset" qualifiers="const" >
+ <method name="tile_get_texture_offset" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="id" type="int">
</argument>
<description>
+ Return the texture offset of the tile.
</description>
</method>
- <method name="tile_set_shape_offset" >
+ <method name="tile_set_shape_offset">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="shape_offset" type="Vector2">
</argument>
<description>
+ Set the shape offset of the tile.
</description>
</method>
- <method name="tile_get_shape_offset" qualifiers="const" >
+ <method name="tile_get_shape_offset" qualifiers="const">
<return type="Vector2">
</return>
<argument index="0" name="id" type="int">
</argument>
<description>
+ Return the shape offset of the tile.
</description>
</method>
- <method name="tile_set_region" >
+ <method name="tile_set_region">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="region" type="Rect2">
@@ -30227,25 +36257,25 @@
Set the tile sub-region in the texture. This is common in texture atlases.
</description>
</method>
- <method name="tile_get_region" qualifiers="const" >
+ <method name="tile_get_region" qualifiers="const">
<return type="Rect2">
</return>
<argument index="0" name="id" type="int">
</argument>
<description>
- Return the tile sub-region in the texture. This is common in texture atlases.
+ Return the tile sub-region in the texture.
</description>
</method>
- <method name="tile_set_shape" >
+ <method name="tile_set_shape">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="shape" type="Shape2D">
</argument>
<description>
- Set a shape for the tile, enabling physics to collide it.
+ Set a shape for the tile, enabling physics to collide with it.
</description>
</method>
- <method name="tile_get_shape" qualifiers="const" >
+ <method name="tile_get_shape" qualifiers="const">
<return type="Shape2D">
</return>
<argument index="0" name="id" type="int">
@@ -30254,54 +36284,129 @@
Return the shape of the tile.
</description>
</method>
- <method name="tile_set_shapes" >
+ <method name="tile_set_shapes">
<argument index="0" name="id" type="int">
</argument>
<argument index="1" name="shapes" type="Array">
</argument>
<description>
+ Set an array of shapes for the tile, enabling physics to collide with it.
</description>
</method>
- <method name="tile_get_shapes" qualifiers="const" >
+ <method name="tile_get_shapes" qualifiers="const">
<return type="Array">
</return>
<argument index="0" name="id" type="int">
</argument>
<description>
+ Return the array of shapes of the tile.
+ </description>
+ </method>
+ <method name="tile_set_navigation_polygon">
+ <argument index="0" name="id" type="int">
+ </argument>
+ <argument index="1" name="navigation_polygon" type="NavigationPolygon">
+ </argument>
+ <description>
+ Set a navigation polygon for the tile.
+ </description>
+ </method>
+ <method name="tile_get_navigation_polygon" qualifiers="const">
+ <return type="NavigationPolygon">
+ </return>
+ <argument index="0" name="id" type="int">
+ </argument>
+ <description>
+ Return the navigation polygon of the tile.
</description>
</method>
- <method name="remove_tile" >
+ <method name="tile_set_navigation_polygon_offset">
<argument index="0" name="id" type="int">
</argument>
+ <argument index="1" name="navigation_polygon_offset" type="Vector2">
+ </argument>
<description>
- Remove a tile, by integer id.
+ Set an offset for the tile's navigation polygon.
</description>
</method>
- <method name="clear" >
+ <method name="tile_get_navigation_polygon_offset" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="id" type="int">
+ </argument>
+ <description>
+ Return the offset of the tile's navigation polygon.
+ </description>
+ </method>
+ <method name="tile_set_light_occluder">
+ <argument index="0" name="id" type="int">
+ </argument>
+ <argument index="1" name="light_occluder" type="OccluderPolygon2D">
+ </argument>
+ <description>
+ Set a light occluder for the tile.
+ </description>
+ </method>
+ <method name="tile_get_light_occluder" qualifiers="const">
+ <return type="OccluderPolygon2D">
+ </return>
+ <argument index="0" name="id" type="int">
+ </argument>
+ <description>
+ Return the light occluder of the tile.
+ </description>
+ </method>
+ <method name="tile_set_occluder_offset">
+ <argument index="0" name="id" type="int">
+ </argument>
+ <argument index="1" name="occluder_offset" type="Vector2">
+ </argument>
+ <description>
+ Set an offset for the tile's light occluder.
+ </description>
+ </method>
+ <method name="tile_get_occluder_offset" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <argument index="0" name="id" type="int">
+ </argument>
+ <description>
+ Return the offset of the tile's light occluder.
+ </description>
+ </method>
+ <method name="remove_tile">
+ <argument index="0" name="id" type="int">
+ </argument>
+ <description>
+ Remove the tile referenced by the given ID.
+ </description>
+ </method>
+ <method name="clear">
<description>
Clear all tiles.
</description>
</method>
- <method name="get_last_unused_tile_id" qualifiers="const" >
+ <method name="get_last_unused_tile_id" qualifiers="const">
<return type="int">
</return>
<description>
- Find an empty id for creating a new tile.
+ Return the ID following the last currently used ID, useful when creating a new tile.
</description>
</method>
- <method name="find_tile_by_name" qualifiers="const" >
+ <method name="find_tile_by_name" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="name" type="String">
</argument>
<description>
- Find the first tile with the given name.
+ Find the first tile matching the given name.
</description>
</method>
- <method name="get_tiles_ids" qualifiers="const" >
+ <method name="get_tiles_ids" qualifiers="const">
<return type="Array">
</return>
<description>
+ Return an array of all currently used tile IDs.
</description>
</method>
</methods>
@@ -30312,66 +36417,80 @@
<brief_description>
</brief_description>
<description>
- Timer node. This is a simple node that will emit a timeout callback when the timer runs out. It can optinally be set to loop.
+ Timer node. This is a simple node that will emit a timeout callback when the timer runs out. It can optionally be set to loop.
</description>
<methods>
- <method name="set_wait_time" >
+ <method name="set_wait_time">
<argument index="0" name="time_sec" type="float">
</argument>
<description>
- Set wait time. When the time is over, it will emit timeout signal.
+ Set wait time in seconds. When the time is over, it will emit the timeout signal.
</description>
</method>
- <method name="get_wait_time" qualifiers="const" >
+ <method name="get_wait_time" qualifiers="const">
<return type="float">
</return>
<description>
- Return the wait time. When the time is over, it will emit timeout signal.
+ Return the wait time in seconds.
</description>
</method>
- <method name="set_one_shot" >
+ <method name="set_one_shot">
<argument index="0" name="enable" type="bool">
</argument>
<description>
- Set as one-shot. If true, timer will stop after timeout, otherwise it will automatically restart.
+ Set as one-shot. If enabled, the timer will stop after timeout, otherwise it will automatically restart.
</description>
</method>
- <method name="is_one_shot" qualifiers="const" >
+ <method name="is_one_shot" qualifiers="const">
<return type="bool">
</return>
<description>
- Return true if is set as one-shot. If true, timer will stop after timeout, otherwise it will automatically restart.
+ Return true if configured as one-shot.
</description>
</method>
- <method name="set_autostart" >
+ <method name="set_autostart">
<argument index="0" name="enable" type="bool">
</argument>
<description>
Set to automatically start when entering the scene.
</description>
</method>
- <method name="has_autostart" qualifiers="const" >
+ <method name="has_autostart" qualifiers="const">
<return type="bool">
</return>
<description>
Return true if set to automatically start when entering the scene.
</description>
</method>
- <method name="start" >
+ <method name="start">
<description>
Start the timer.
</description>
</method>
- <method name="stop" >
+ <method name="stop">
<description>
Stop (cancel) the timer.
</description>
</method>
- <method name="get_time_left" qualifiers="const" >
+ <method name="get_time_left" qualifiers="const">
<return type="float">
</return>
<description>
- Return the time left for timeout if the timer is active.
+ Return the time left for timeout in seconds if the timer is active, 0 otherwise.
+ </description>
+ </method>
+ <method name="set_timer_process_mode">
+ <argument index="0" name="mode" type="int">
+ </argument>
+ <description>
+ Set the timer's processing mode (fixed or idle, use TIMER_PROCESS_* constants as argument).
+ </description>
+ </method>
+ <method name="get_timer_process_mode" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ Return the timer's processing mode.
</description>
</method>
</methods>
@@ -30383,87 +36502,127 @@
</signal>
</signals>
<constants>
+ <constant name="TIMER_PROCESS_FIXED" value="0">
+ Update the timer at fixed intervals (framerate processing).
+ </constant>
+ <constant name="TIMER_PROCESS_IDLE" value="1">
+ Update the timer during the idle time at each frame.
+ </constant>
</constants>
</class>
+<class name="ToolButton" inherits="Button" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+ <theme_items>
+ <theme_item name="hseparation" type="int">
+ </theme_item>
+ <theme_item name="font_color_disabled" type="Color">
+ </theme_item>
+ <theme_item name="font_color" type="Color">
+ </theme_item>
+ <theme_item name="font_color_hover" type="Color">
+ </theme_item>
+ <theme_item name="font_color_pressed" type="Color">
+ </theme_item>
+ <theme_item name="font" type="Font">
+ </theme_item>
+ <theme_item name="hover" type="StyleBox">
+ </theme_item>
+ <theme_item name="pressed" type="StyleBox">
+ </theme_item>
+ <theme_item name="focus" type="StyleBox">
+ </theme_item>
+ <theme_item name="disabled" type="StyleBox">
+ </theme_item>
+ <theme_item name="normal" type="StyleBox">
+ </theme_item>
+ </theme_items>
+</class>
<class name="TouchScreenButton" inherits="Node2D" category="Core">
<brief_description>
</brief_description>
<description>
</description>
<methods>
- <method name="set_texture" >
+ <method name="set_texture">
<argument index="0" name="texture" type="Object">
</argument>
<description>
</description>
</method>
- <method name="get_texture" qualifiers="const" >
+ <method name="get_texture" qualifiers="const">
<return type="Object">
</return>
<description>
</description>
</method>
- <method name="set_texture_pressed" >
+ <method name="set_texture_pressed">
<argument index="0" name="texture_pressed" type="Object">
</argument>
<description>
</description>
</method>
- <method name="get_texture_pressed" qualifiers="const" >
+ <method name="get_texture_pressed" qualifiers="const">
<return type="Object">
</return>
<description>
</description>
</method>
- <method name="set_bitmask" >
+ <method name="set_bitmask">
<argument index="0" name="bitmask" type="Object">
</argument>
<description>
</description>
</method>
- <method name="get_bitmask" qualifiers="const" >
+ <method name="get_bitmask" qualifiers="const">
<return type="Object">
</return>
<description>
</description>
</method>
- <method name="set_action" >
+ <method name="set_action">
<argument index="0" name="action" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_action" qualifiers="const" >
+ <method name="get_action" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="set_visibility_mode" >
+ <method name="set_visibility_mode">
<argument index="0" name="mode" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_visibility_mode" qualifiers="const" >
+ <method name="get_visibility_mode" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_passby_press" >
+ <method name="set_passby_press">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_passby_press_enabled" qualifiers="const" >
+ <method name="is_passby_press_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="is_pressed" qualifiers="const" >
+ <method name="is_pressed" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -30491,20 +36650,20 @@
Transform is used to store transformations, including translations. It consists of a Matrix3 "basis" and Vector3 "origin". Transform is used to represent transformations of any object in space. It is similar to a 4x3 matrix.
</description>
<methods>
- <method name="affine_inverse" >
+ <method name="affine_inverse">
<return type="Transform">
</return>
<description>
</description>
</method>
- <method name="inverse" >
+ <method name="inverse">
<return type="Transform">
</return>
<description>
Returns the inverse of the transform.
</description>
</method>
- <method name="looking_at" >
+ <method name="looking_at">
<return type="Transform">
</return>
<argument index="0" name="target" type="Vector3">
@@ -30514,13 +36673,13 @@
<description>
</description>
</method>
- <method name="orthonormalized" >
+ <method name="orthonormalized">
<return type="Transform">
</return>
<description>
</description>
</method>
- <method name="rotated" >
+ <method name="rotated">
<return type="Transform">
</return>
<argument index="0" name="axis" type="Vector3">
@@ -30530,7 +36689,7 @@
<description>
</description>
</method>
- <method name="scaled" >
+ <method name="scaled">
<return type="Transform">
</return>
<argument index="0" name="scale" type="Vector3">
@@ -30538,7 +36697,7 @@
<description>
</description>
</method>
- <method name="translated" >
+ <method name="translated">
<return type="Transform">
</return>
<argument index="0" name="ofs" type="Vector3">
@@ -30546,7 +36705,7 @@
<description>
</description>
</method>
- <method name="xform" >
+ <method name="xform">
<return type="var">
</return>
<argument index="0" name="v" type="var">
@@ -30555,7 +36714,7 @@
Transforms vector "v" by this transform.
</description>
</method>
- <method name="xform_inv" >
+ <method name="xform_inv">
<return type="var">
</return>
<argument index="0" name="v" type="var">
@@ -30564,7 +36723,9 @@
Inverse-transforms vector "v" by this transform.
</description>
</method>
- <method name="Transform" >
+ <method name="Transform">
+ <return type="Transform">
+ </return>
<argument index="0" name="x_axis" type="Vector3">
</argument>
<argument index="1" name="y_axis" type="Vector3">
@@ -30576,7 +36737,9 @@
<description>
</description>
</method>
- <method name="Transform" >
+ <method name="Transform">
+ <return type="Transform">
+ </return>
<argument index="0" name="basis" type="Matrix3">
</argument>
<argument index="1" name="origin" type="Vector3">
@@ -30584,19 +36747,25 @@
<description>
</description>
</method>
- <method name="Transform" >
+ <method name="Transform">
+ <return type="Transform">
+ </return>
<argument index="0" name="from" type="Matrix32">
</argument>
<description>
</description>
</method>
- <method name="Transform" >
+ <method name="Transform">
+ <return type="Transform">
+ </return>
<argument index="0" name="from" type="Quat">
</argument>
<description>
</description>
</method>
- <method name="Transform" >
+ <method name="Transform">
+ <return type="Transform">
+ </return>
<argument index="0" name="from" type="Matrix3">
</argument>
<description>
@@ -30620,21 +36789,21 @@
Translations are resources that can be loaded/unloaded on demand. They map a string to another string.
</description>
<methods>
- <method name="set_locale" >
+ <method name="set_locale">
<argument index="0" name="locale" type="String">
</argument>
<description>
Set the locale of the translation.
</description>
</method>
- <method name="get_locale" qualifiers="const" >
+ <method name="get_locale" qualifiers="const">
<return type="String">
</return>
<description>
Return the locale of the translation.
</description>
</method>
- <method name="add_message" >
+ <method name="add_message">
<argument index="0" name="src_message" type="String">
</argument>
<argument index="1" name="xlated_message" type="String">
@@ -30643,7 +36812,7 @@
Add a message for translation.
</description>
</method>
- <method name="get_message" qualifiers="const" >
+ <method name="get_message" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="src_message" type="String">
@@ -30652,21 +36821,21 @@
Return a message for translation.
</description>
</method>
- <method name="erase_message" >
+ <method name="erase_message">
<argument index="0" name="src_message" type="String">
</argument>
<description>
Erase a message.
</description>
</method>
- <method name="get_message_list" qualifiers="const" >
+ <method name="get_message_list" qualifiers="const">
<return type="StringArray">
</return>
<description>
Return all the messages (keys).
</description>
</method>
- <method name="get_message_count" qualifiers="const" >
+ <method name="get_message_count" qualifiers="const">
<return type="int">
</return>
<description>
@@ -30683,39 +36852,39 @@
<description>
</description>
<methods>
- <method name="set_locale" >
+ <method name="set_locale">
<argument index="0" name="locale" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_locale" qualifiers="const" >
+ <method name="get_locale" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="translate" qualifiers="const" >
+ <method name="translate" qualifiers="const">
<return type="String">
</return>
- <argument index="0" name="arg0" type="String">
+ <argument index="0" name="message" type="String">
</argument>
<description>
</description>
</method>
- <method name="add_translation" >
- <argument index="0" name="arg0" type="Object">
+ <method name="add_translation">
+ <argument index="0" name="translation" type="Translation">
</argument>
<description>
</description>
</method>
- <method name="remove_translation" >
- <argument index="0" name="arg0" type="Object">
+ <method name="remove_translation">
+ <argument index="0" name="translation" type="Translation">
</argument>
<description>
</description>
</method>
- <method name="clear" >
+ <method name="clear">
<description>
</description>
</method>
@@ -30729,11 +36898,11 @@
<description>
</description>
<methods>
- <method name="clear" >
+ <method name="clear">
<description>
</description>
</method>
- <method name="create_item" >
+ <method name="create_item">
<return type="TreeItem">
</return>
<argument index="0" name="parent" type="TreeItem" default="Object()">
@@ -30741,43 +36910,43 @@
<description>
</description>
</method>
- <method name="get_root" >
+ <method name="get_root">
<return type="TreeItem">
</return>
<description>
</description>
</method>
- <method name="set_column_min_width" >
- <argument index="0" name="arg0" type="int">
+ <method name="set_column_min_width">
+ <argument index="0" name="column" type="int">
</argument>
- <argument index="1" name="arg1" type="int">
+ <argument index="1" name="min_width" type="int">
</argument>
<description>
</description>
</method>
- <method name="set_column_expand" >
- <argument index="0" name="arg0" type="int">
+ <method name="set_column_expand">
+ <argument index="0" name="column" type="int">
</argument>
- <argument index="1" name="arg1" type="bool">
+ <argument index="1" name="expand" type="bool">
</argument>
<description>
</description>
</method>
- <method name="get_column_width" qualifiers="const" >
+ <method name="get_column_width" qualifiers="const">
<return type="int">
</return>
- <argument index="0" name="arg0" type="int">
+ <argument index="0" name="column" type="int">
</argument>
<description>
</description>
</method>
- <method name="set_hide_root" >
- <argument index="0" name="arg0" type="bool">
+ <method name="set_hide_root">
+ <argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="get_next_selected" >
+ <method name="get_next_selected">
<return type="TreeItem">
</return>
<argument index="0" name="from" type="TreeItem">
@@ -30785,61 +36954,61 @@
<description>
</description>
</method>
- <method name="get_selected" qualifiers="const" >
+ <method name="get_selected" qualifiers="const">
<return type="TreeItem">
</return>
<description>
</description>
</method>
- <method name="get_selected_column" qualifiers="const" >
+ <method name="get_selected_column" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_pressed_button" qualifiers="const" >
+ <method name="get_pressed_button" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="set_select_mode" >
+ <method name="set_select_mode">
<argument index="0" name="mode" type="int">
</argument>
<description>
</description>
</method>
- <method name="set_columns" >
+ <method name="set_columns">
<argument index="0" name="amount" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_columns" qualifiers="const" >
+ <method name="get_columns" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_edited" qualifiers="const" >
+ <method name="get_edited" qualifiers="const">
<return type="TreeItem">
</return>
<description>
</description>
</method>
- <method name="get_edited_column" qualifiers="const" >
+ <method name="get_edited_column" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_custom_popup_rect" qualifiers="const" >
+ <method name="get_custom_popup_rect" qualifiers="const">
<return type="Rect2">
</return>
<description>
</description>
</method>
- <method name="get_item_area_rect" qualifiers="const" >
+ <method name="get_item_area_rect" qualifiers="const">
<return type="Rect2">
</return>
<argument index="0" name="item" type="TreeItem">
@@ -30849,23 +37018,23 @@
<description>
</description>
</method>
- <method name="ensure_cursor_is_visible" >
+ <method name="ensure_cursor_is_visible">
<description>
</description>
</method>
- <method name="set_column_titles_visible" >
+ <method name="set_column_titles_visible">
<argument index="0" name="visible" type="bool">
</argument>
<description>
</description>
</method>
- <method name="are_column_titles_visible" qualifiers="const" >
+ <method name="are_column_titles_visible" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_column_title" >
+ <method name="set_column_title">
<argument index="0" name="column" type="int">
</argument>
<argument index="1" name="title" type="String">
@@ -30873,7 +37042,7 @@
<description>
</description>
</method>
- <method name="get_column_title" qualifiers="const" >
+ <method name="get_column_title" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="column" type="int">
@@ -30881,12 +37050,24 @@
<description>
</description>
</method>
- <method name="get_scroll" qualifiers="const" >
+ <method name="get_scroll" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
+ <method name="set_hide_folding">
+ <argument index="0" name="hide" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="is_folding_hidden" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<signals>
<signal name="item_activated">
@@ -31013,7 +37194,7 @@
<description>
</description>
<methods>
- <method name="set_cell_mode" >
+ <method name="set_cell_mode">
<argument index="0" name="column" type="int">
</argument>
<argument index="1" name="mode" type="int">
@@ -31021,7 +37202,7 @@
<description>
</description>
</method>
- <method name="get_cell_mode" qualifiers="const" >
+ <method name="get_cell_mode" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="column" type="int">
@@ -31029,7 +37210,7 @@
<description>
</description>
</method>
- <method name="set_checked" >
+ <method name="set_checked">
<argument index="0" name="column" type="int">
</argument>
<argument index="1" name="checked" type="bool">
@@ -31037,7 +37218,7 @@
<description>
</description>
</method>
- <method name="is_checked" qualifiers="const" >
+ <method name="is_checked" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="column" type="int">
@@ -31045,7 +37226,7 @@
<description>
</description>
</method>
- <method name="set_text" >
+ <method name="set_text">
<argument index="0" name="column" type="int">
</argument>
<argument index="1" name="text" type="String">
@@ -31053,7 +37234,7 @@
<description>
</description>
</method>
- <method name="get_text" qualifiers="const" >
+ <method name="get_text" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="column" type="int">
@@ -31061,7 +37242,7 @@
<description>
</description>
</method>
- <method name="set_icon" >
+ <method name="set_icon">
<argument index="0" name="column" type="int">
</argument>
<argument index="1" name="texture" type="Texture">
@@ -31069,7 +37250,7 @@
<description>
</description>
</method>
- <method name="get_icon" qualifiers="const" >
+ <method name="get_icon" qualifiers="const">
<return type="Texture">
</return>
<argument index="0" name="column" type="int">
@@ -31077,7 +37258,7 @@
<description>
</description>
</method>
- <method name="set_icon_region" >
+ <method name="set_icon_region">
<argument index="0" name="column" type="int">
</argument>
<argument index="1" name="region" type="Rect2">
@@ -31085,7 +37266,7 @@
<description>
</description>
</method>
- <method name="get_icon_region" qualifiers="const" >
+ <method name="get_icon_region" qualifiers="const">
<return type="Rect2">
</return>
<argument index="0" name="column" type="int">
@@ -31093,7 +37274,7 @@
<description>
</description>
</method>
- <method name="set_icon_max_width" >
+ <method name="set_icon_max_width">
<argument index="0" name="column" type="int">
</argument>
<argument index="1" name="width" type="int">
@@ -31101,7 +37282,7 @@
<description>
</description>
</method>
- <method name="get_icon_max_width" qualifiers="const" >
+ <method name="get_icon_max_width" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="column" type="int">
@@ -31109,7 +37290,7 @@
<description>
</description>
</method>
- <method name="set_range" >
+ <method name="set_range">
<argument index="0" name="column" type="int">
</argument>
<argument index="1" name="value" type="float">
@@ -31117,7 +37298,7 @@
<description>
</description>
</method>
- <method name="get_range" qualifiers="const" >
+ <method name="get_range" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="column" type="int">
@@ -31125,7 +37306,7 @@
<description>
</description>
</method>
- <method name="set_range_config" >
+ <method name="set_range_config">
<argument index="0" name="column" type="int">
</argument>
<argument index="1" name="min" type="float">
@@ -31139,7 +37320,7 @@
<description>
</description>
</method>
- <method name="get_range_config" >
+ <method name="get_range_config">
<return type="Dictionary">
</return>
<argument index="0" name="column" type="int">
@@ -31147,7 +37328,7 @@
<description>
</description>
</method>
- <method name="set_metadata" >
+ <method name="set_metadata">
<argument index="0" name="column" type="int">
</argument>
<argument index="1" name="meta" type="var">
@@ -31155,13 +37336,13 @@
<description>
</description>
</method>
- <method name="get_metadata" qualifiers="const" >
+ <method name="get_metadata" qualifiers="const">
<argument index="0" name="column" type="int">
</argument>
<description>
</description>
</method>
- <method name="set_custom_draw" >
+ <method name="set_custom_draw">
<argument index="0" name="column" type="int">
</argument>
<argument index="1" name="object" type="Object">
@@ -31171,61 +37352,63 @@
<description>
</description>
</method>
- <method name="set_collapsed" >
+ <method name="set_collapsed">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_collapsed" >
+ <method name="is_collapsed">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="get_next" >
+ <method name="get_next">
<return type="TreeItem">
</return>
<description>
</description>
</method>
- <method name="get_prev" >
+ <method name="get_prev">
<return type="TreeItem">
</return>
<description>
</description>
</method>
- <method name="get_parent" >
+ <method name="get_parent">
<return type="TreeItem">
</return>
<description>
</description>
</method>
- <method name="get_children" >
+ <method name="get_children">
<return type="TreeItem">
</return>
<description>
</description>
</method>
- <method name="get_next_visible" >
+ <method name="get_next_visible">
<return type="TreeItem">
</return>
<description>
</description>
</method>
- <method name="get_prev_visible" >
+ <method name="get_prev_visible">
<return type="TreeItem">
</return>
<description>
</description>
</method>
- <method name="remove_child" >
+ <method name="remove_child">
+ <return type="TreeItem">
+ </return>
<argument index="0" name="child" type="Object">
</argument>
<description>
</description>
</method>
- <method name="set_selectable" >
+ <method name="set_selectable">
<argument index="0" name="column" type="int">
</argument>
<argument index="1" name="selectable" type="bool">
@@ -31233,7 +37416,7 @@
<description>
</description>
</method>
- <method name="is_selectable" qualifiers="const" >
+ <method name="is_selectable" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="column" type="int">
@@ -31241,7 +37424,7 @@
<description>
</description>
</method>
- <method name="is_selected" >
+ <method name="is_selected">
<return type="bool">
</return>
<argument index="0" name="column" type="int">
@@ -31249,19 +37432,19 @@
<description>
</description>
</method>
- <method name="select" >
+ <method name="select">
<argument index="0" name="column" type="int">
</argument>
<description>
</description>
</method>
- <method name="deselect" >
+ <method name="deselect">
<argument index="0" name="column" type="int">
</argument>
<description>
</description>
</method>
- <method name="set_editable" >
+ <method name="set_editable">
<argument index="0" name="column" type="int">
</argument>
<argument index="1" name="enabled" type="bool">
@@ -31269,7 +37452,7 @@
<description>
</description>
</method>
- <method name="is_editable" >
+ <method name="is_editable">
<return type="bool">
</return>
<argument index="0" name="column" type="int">
@@ -31277,7 +37460,7 @@
<description>
</description>
</method>
- <method name="set_custom_color" >
+ <method name="set_custom_color">
<argument index="0" name="column" type="int">
</argument>
<argument index="1" name="color" type="Color">
@@ -31285,13 +37468,13 @@
<description>
</description>
</method>
- <method name="clear_custom_color" >
+ <method name="clear_custom_color">
<argument index="0" name="column" type="int">
</argument>
<description>
</description>
</method>
- <method name="set_custom_bg_color" >
+ <method name="set_custom_bg_color">
<argument index="0" name="column" type="int">
</argument>
<argument index="1" name="color" type="Color">
@@ -31299,13 +37482,13 @@
<description>
</description>
</method>
- <method name="clear_custom_bg_color" >
+ <method name="clear_custom_bg_color">
<argument index="0" name="column" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_custom_bg_color" qualifiers="const" >
+ <method name="get_custom_bg_color" qualifiers="const">
<return type="Color">
</return>
<argument index="0" name="column" type="int">
@@ -31313,17 +37496,17 @@
<description>
</description>
</method>
- <method name="add_button" >
+ <method name="add_button">
<argument index="0" name="column" type="int">
</argument>
<argument index="1" name="button" type="Texture">
</argument>
- <argument index="2" name="arg2" type="int">
+ <argument index="2" name="button_idx" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_button_count" qualifiers="const" >
+ <method name="get_button_count" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="column" type="int">
@@ -31331,7 +37514,7 @@
<description>
</description>
</method>
- <method name="get_button" qualifiers="const" >
+ <method name="get_button" qualifiers="const">
<return type="Texture">
</return>
<argument index="0" name="column" type="int">
@@ -31341,7 +37524,7 @@
<description>
</description>
</method>
- <method name="erase_button" >
+ <method name="erase_button">
<argument index="0" name="column" type="int">
</argument>
<argument index="1" name="button_idx" type="int">
@@ -31349,7 +37532,7 @@
<description>
</description>
</method>
- <method name="set_tooltip" >
+ <method name="set_tooltip">
<argument index="0" name="column" type="int">
</argument>
<argument index="1" name="tooltip" type="String">
@@ -31357,7 +37540,7 @@
<description>
</description>
</method>
- <method name="get_tooltip" qualifiers="const" >
+ <method name="get_tooltip" qualifiers="const">
<return type="String">
</return>
<argument index="0" name="column" type="int">
@@ -31365,11 +37548,11 @@
<description>
</description>
</method>
- <method name="move_to_top" >
+ <method name="move_to_top">
<description>
</description>
</method>
- <method name="move_to_bottom" >
+ <method name="move_to_bottom">
<description>
</description>
</method>
@@ -31393,125 +37576,125 @@
<description>
</description>
<methods>
- <method name="is_active" qualifiers="const" >
+ <method name="is_active" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_active" >
+ <method name="set_active">
<argument index="0" name="active" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_repeat" qualifiers="const" >
+ <method name="is_repeat" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_repeat" >
+ <method name="set_repeat">
<argument index="0" name="repeat" type="bool">
</argument>
<description>
</description>
</method>
- <method name="set_speed" >
+ <method name="set_speed">
<argument index="0" name="speed" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_speed" qualifiers="const" >
+ <method name="get_speed" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_tween_process_mode" >
+ <method name="set_tween_process_mode">
<argument index="0" name="mode" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_tween_process_mode" qualifiers="const" >
+ <method name="get_tween_process_mode" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="start" >
+ <method name="start">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="reset" >
+ <method name="reset">
<return type="bool">
</return>
- <argument index="0" name="node" type="Object">
+ <argument index="0" name="object" type="Object">
</argument>
<argument index="1" name="key" type="String">
</argument>
<description>
</description>
</method>
- <method name="reset_all" >
+ <method name="reset_all">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="stop" >
+ <method name="stop">
<return type="bool">
</return>
- <argument index="0" name="node" type="Object">
+ <argument index="0" name="object" type="Object">
</argument>
<argument index="1" name="key" type="String">
</argument>
<description>
</description>
</method>
- <method name="stop_all" >
+ <method name="stop_all">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="resume" >
+ <method name="resume">
<return type="bool">
</return>
- <argument index="0" name="node" type="Object">
+ <argument index="0" name="object" type="Object">
</argument>
<argument index="1" name="key" type="String">
</argument>
<description>
</description>
</method>
- <method name="resume_all" >
+ <method name="resume_all">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="remove" >
+ <method name="remove">
<return type="bool">
</return>
- <argument index="0" name="node" type="Object">
+ <argument index="0" name="object" type="Object">
</argument>
<argument index="1" name="key" type="String">
</argument>
<description>
</description>
</method>
- <method name="remove_all" >
+ <method name="remove_all">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="seek" >
+ <method name="seek">
<return type="bool">
</return>
<argument index="0" name="time" type="float">
@@ -31519,22 +37702,22 @@
<description>
</description>
</method>
- <method name="tell" qualifiers="const" >
+ <method name="tell" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="get_runtime" qualifiers="const" >
+ <method name="get_runtime" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="interpolate_property" >
+ <method name="interpolate_property">
<return type="bool">
</return>
- <argument index="0" name="node" type="Object">
+ <argument index="0" name="object" type="Object">
</argument>
<argument index="1" name="property" type="String">
</argument>
@@ -31553,10 +37736,10 @@
<description>
</description>
</method>
- <method name="interpolate_method" >
+ <method name="interpolate_method">
<return type="bool">
</return>
- <argument index="0" name="node" type="Object">
+ <argument index="0" name="object" type="Object">
</argument>
<argument index="1" name="method" type="String">
</argument>
@@ -31575,24 +37758,54 @@
<description>
</description>
</method>
- <method name="interpolate_callback" >
+ <method name="interpolate_callback">
<return type="bool">
</return>
- <argument index="0" name="node" type="Object">
+ <argument index="0" name="object" type="Object">
+ </argument>
+ <argument index="1" name="times_in_sec" type="float">
+ </argument>
+ <argument index="2" name="callback" type="String">
+ </argument>
+ <argument index="3" name="arg1" type="var" default="NULL">
+ </argument>
+ <argument index="4" name="arg2" type="var" default="NULL">
</argument>
- <argument index="1" name="callback" type="String">
+ <argument index="5" name="arg3" type="var" default="NULL">
</argument>
- <argument index="2" name="times_in_sec" type="float">
+ <argument index="6" name="arg4" type="var" default="NULL">
</argument>
- <argument index="3" name="args" type="var" default="NULL">
+ <argument index="7" name="arg5" type="var" default="NULL">
</argument>
<description>
</description>
</method>
- <method name="follow_property" >
+ <method name="interpolate_deferred_callback">
<return type="bool">
</return>
- <argument index="0" name="node" type="Object">
+ <argument index="0" name="object" type="Object">
+ </argument>
+ <argument index="1" name="times_in_sec" type="float">
+ </argument>
+ <argument index="2" name="callback" type="String">
+ </argument>
+ <argument index="3" name="arg1" type="var" default="NULL">
+ </argument>
+ <argument index="4" name="arg2" type="var" default="NULL">
+ </argument>
+ <argument index="5" name="arg3" type="var" default="NULL">
+ </argument>
+ <argument index="6" name="arg4" type="var" default="NULL">
+ </argument>
+ <argument index="7" name="arg5" type="var" default="NULL">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="follow_property">
+ <return type="bool">
+ </return>
+ <argument index="0" name="object" type="Object">
</argument>
<argument index="1" name="property" type="String">
</argument>
@@ -31613,10 +37826,10 @@
<description>
</description>
</method>
- <method name="follow_method" >
+ <method name="follow_method">
<return type="bool">
</return>
- <argument index="0" name="node" type="Object">
+ <argument index="0" name="object" type="Object">
</argument>
<argument index="1" name="method" type="String">
</argument>
@@ -31637,10 +37850,10 @@
<description>
</description>
</method>
- <method name="targeting_property" >
+ <method name="targeting_property">
<return type="bool">
</return>
- <argument index="0" name="node" type="Object">
+ <argument index="0" name="object" type="Object">
</argument>
<argument index="1" name="property" type="String">
</argument>
@@ -31661,10 +37874,10 @@
<description>
</description>
</method>
- <method name="targeting_method" >
+ <method name="targeting_method">
<return type="bool">
</return>
- <argument index="0" name="node" type="Object">
+ <argument index="0" name="object" type="Object">
</argument>
<argument index="1" name="method" type="String">
</argument>
@@ -31688,7 +37901,7 @@
</methods>
<signals>
<signal name="tween_complete">
- <argument index="0" name="node" type="Object">
+ <argument index="0" name="object" type="Object">
</argument>
<argument index="1" name="key" type="String">
</argument>
@@ -31696,7 +37909,7 @@
</description>
</signal>
<signal name="tween_step">
- <argument index="0" name="node" type="Object">
+ <argument index="0" name="object" type="Object">
</argument>
<argument index="1" name="key" type="String">
</argument>
@@ -31708,7 +37921,7 @@
</description>
</signal>
<signal name="tween_start">
- <argument index="0" name="node" type="Object">
+ <argument index="0" name="object" type="Object">
</argument>
<argument index="1" name="key" type="String">
</argument>
@@ -31717,6 +37930,10 @@
</signal>
</signals>
<constants>
+ <constant name="TWEEN_PROCESS_FIXED" value="0">
+ </constant>
+ <constant name="TWEEN_PROCESS_IDLE" value="1">
+ </constant>
<constant name="TRANS_LINEAR" value="0">
</constant>
<constant name="TRANS_SINE" value="1">
@@ -31749,44 +37966,104 @@
</constant>
</constants>
</class>
-<class name="UnshadedMaterial" inherits="Material" category="Core">
+<class name="UndoRedo" inherits="Object" category="Core">
<brief_description>
</brief_description>
<description>
</description>
<methods>
- <method name="set_texture" >
- <argument index="0" name="texture" type="Object">
+ <method name="create_action">
+ <argument index="0" name="name" type="String">
+ </argument>
+ <argument index="1" name="mergeable" type="bool" default="false">
</argument>
<description>
</description>
</method>
- <method name="get_texture" qualifiers="const" >
- <return type="Texture">
- </return>
+ <method name="commit_action">
<description>
</description>
</method>
- <method name="set_use_alpha" >
- <argument index="0" name="enable" type="bool">
+ <method name="add_do_method">
+ <argument index="0" name="object" type="Object">
+ </argument>
+ <argument index="1" name="method" type="String">
+ </argument>
+ <argument index="2" name="arg0" type="var" default="NULL">
+ </argument>
+ <argument index="3" name="arg1" type="var" default="NULL">
+ </argument>
+ <argument index="4" name="arg2" type="var" default="NULL">
+ </argument>
+ <argument index="5" name="arg3" type="var" default="NULL">
+ </argument>
+ <argument index="6" name="arg4" type="var" default="NULL">
</argument>
<description>
</description>
</method>
- <method name="is_using_alpha" qualifiers="const" >
- <return type="bool">
- </return>
+ <method name="add_undo_method">
+ <argument index="0" name="object" type="Object">
+ </argument>
+ <argument index="1" name="method" type="String">
+ </argument>
+ <argument index="2" name="arg0" type="var" default="NULL">
+ </argument>
+ <argument index="3" name="arg1" type="var" default="NULL">
+ </argument>
+ <argument index="4" name="arg2" type="var" default="NULL">
+ </argument>
+ <argument index="5" name="arg3" type="var" default="NULL">
+ </argument>
+ <argument index="6" name="arg4" type="var" default="NULL">
+ </argument>
<description>
</description>
</method>
- <method name="set_use_color_array" >
- <argument index="0" name="enable" type="bool">
+ <method name="add_do_property">
+ <argument index="0" name="object" type="Object">
+ </argument>
+ <argument index="1" name="property" type="String">
+ </argument>
+ <argument index="2" name="value" type="Variant">
</argument>
<description>
</description>
</method>
- <method name="is_using_color_array" qualifiers="const" >
- <return type="bool">
+ <method name="add_undo_property">
+ <argument index="0" name="object" type="Object">
+ </argument>
+ <argument index="1" name="property" type="String">
+ </argument>
+ <argument index="2" name="value" type="Variant">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="add_do_reference">
+ <argument index="0" name="object" type="Object">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="add_undo_reference">
+ <argument index="0" name="object" type="Object">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="clear_history">
+ <description>
+ </description>
+ </method>
+ <method name="get_current_action_name" qualifiers="const">
+ <return type="String">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_version" qualifiers="const">
+ <return type="int">
</return>
<description>
</description>
@@ -31945,29 +38222,33 @@
<description>
</description>
<methods>
- <method name="angle_to" >
+ <method name="angle">
<return type="float">
</return>
- <argument index="0" name="to" type="Vector2">
- </argument>
<description>
+ Returns the result of atan2 when called with the Vector's x and y as parameters (Math::atan2(x,y)).
+ Be aware that it therefore returns an angle oriented clockwise with regard to the (0, 1) unit vector, and not an angle oriented counter-clockwise with regard to the (1, 0) unit vector (which would be the typical trigonometric representation of the angle when calling Math::atan2(y,x)).
</description>
</method>
- <method name="angle_to_point" >
+ <method name="angle_to">
<return type="float">
</return>
<argument index="0" name="to" type="Vector2">
</argument>
<description>
+ Returns the angle in radians between the two vectors.
</description>
</method>
- <method name="atan2" >
+ <method name="angle_to_point">
<return type="float">
</return>
+ <argument index="0" name="to" type="Vector2">
+ </argument>
<description>
+ Returns the angle in radians between the line connecting the two points and the x coordinate.
</description>
</method>
- <method name="cubic_interpolate" >
+ <method name="cubic_interpolate">
<return type="Vector2">
</return>
<argument index="0" name="b" type="Vector2">
@@ -31979,17 +38260,19 @@
<argument index="3" name="t" type="float">
</argument>
<description>
+ Cubicly interpolates between this Vector and "b", using "pre_a" and "post_b" as handles, and returning the result at position "t".
</description>
</method>
- <method name="distance_squared_to" >
+ <method name="distance_squared_to">
<return type="float">
</return>
<argument index="0" name="to" type="Vector2">
</argument>
<description>
+ Returns the squared distance to vector "b". Prefer this function over "distance_to" if you need to sort vectors or need the squared distance for some formula.
</description>
</method>
- <method name="distance_to" >
+ <method name="distance_to">
<return type="float">
</return>
<argument index="0" name="to" type="Vector2">
@@ -31998,7 +38281,7 @@
Returns the distance to vector "b".
</description>
</method>
- <method name="dot" >
+ <method name="dot">
<return type="float">
</return>
<argument index="0" name="with" type="Vector2">
@@ -32007,39 +38290,41 @@
Returns the dot product with vector "b".
</description>
</method>
- <method name="floor" >
+ <method name="floor">
<return type="Vector2">
</return>
<description>
Remove the fractional part of x and y.
</description>
</method>
- <method name="floorf" >
+ <method name="floorf">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="get_aspect" >
+ <method name="get_aspect">
<return type="float">
</return>
<description>
+ Returns the ratio of X to Y.
</description>
</method>
- <method name="length" >
+ <method name="length">
<return type="float">
</return>
<description>
Returns the length of the vector.
</description>
</method>
- <method name="length_squared" >
+ <method name="length_squared">
<return type="float">
</return>
<description>
+ Returns the squared length of the vector. Prefer this function over "length" if you need to sort vectors or need the squared length for some formula.
</description>
</method>
- <method name="linear_interpolate" >
+ <method name="linear_interpolate">
<return type="Vector2">
</return>
<argument index="0" name="b" type="Vector2">
@@ -32047,60 +38332,68 @@
<argument index="1" name="t" type="float">
</argument>
<description>
- Returns the result of the linear interpolation between this vector and "b", by amount "i".
+ Returns the result of the linear interpolation between this vector and "b", by amount "t".
</description>
</method>
- <method name="normalized" >
+ <method name="normalized">
<return type="Vector2">
</return>
<description>
Returns a normalized vector to unit length.
</description>
</method>
- <method name="reflect" >
- <return type="float">
+ <method name="reflect">
+ <return type="Vector2">
</return>
<argument index="0" name="vec" type="Vector2">
</argument>
<description>
+ Like "slide", but reflects the Vector instead of continuing along the wall.
</description>
</method>
- <method name="rotated" >
+ <method name="rotated">
<return type="Vector2">
</return>
<argument index="0" name="phi" type="float">
</argument>
<description>
+ Rotates the vector by "phi" radians.
</description>
</method>
- <method name="slide" >
- <return type="float">
+ <method name="slide">
+ <return type="Vector2">
</return>
<argument index="0" name="vec" type="Vector2">
</argument>
<description>
+ Slides the vector by the other vector.
</description>
</method>
- <method name="snapped" >
+ <method name="snapped">
<return type="Vector2">
</return>
<argument index="0" name="by" type="Vector2">
</argument>
<description>
+ Snaps the vector to a grid with the given size.
</description>
</method>
- <method name="tangent" >
+ <method name="tangent">
<return type="Vector2">
</return>
<description>
+ Returns a perpendicular vector.
</description>
</method>
- <method name="Vector2" >
+ <method name="Vector2">
+ <return type="Vector2">
+ </return>
<argument index="0" name="x" type="float">
</argument>
<argument index="1" name="y" type="float">
</argument>
<description>
+ Constructs a new Vector2 from the given x and y.
</description>
</method>
</methods>
@@ -32119,48 +38412,58 @@
</class>
<class name="Vector2Array" category="Built-In Types">
<brief_description>
+ An Array of Vector2.
</brief_description>
<description>
+ An Array specifically designed to hold Vector2.
</description>
<methods>
- <method name="get" >
+ <method name="get">
<return type="Vector2">
</return>
<argument index="0" name="idx" type="int">
</argument>
<description>
+ Returns the Vector2 at the given index.
</description>
</method>
- <method name="push_back" >
+ <method name="push_back">
<argument index="0" name="vector2" type="Vector2">
</argument>
<description>
+ Inserts a Vector2 at the end.
</description>
</method>
- <method name="resize" >
+ <method name="resize">
<argument index="0" name="idx" type="int">
</argument>
<description>
+ Sets the size of the Vector2Array. If larger than the current size it will reserve some space beforehand, and if it is smaller it will cut off the array.
</description>
</method>
- <method name="set" >
+ <method name="set">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="vector2" type="Vector2">
</argument>
<description>
+ Changes the Vector2 at the given index.
</description>
</method>
- <method name="size" >
+ <method name="size">
<return type="int">
</return>
<description>
+ Returns the size of the array.
</description>
</method>
- <method name="Vector2Array" >
+ <method name="Vector2Array">
+ <return type="Vector2Array">
+ </return>
<argument index="0" name="from" type="Array">
</argument>
<description>
+ Constructs a new Vector2Array. Optionally, you can pass in an Array that will be converted.
</description>
</method>
</methods>
@@ -32172,16 +38475,24 @@
Vector class, which performs basic 3D vector math operations.
</brief_description>
<description>
- Vector3 is one of the core classes of the engine, and includes several built-in helper functions to perform basic vecor math operations.
+ Vector3 is one of the core classes of the engine, and includes several built-in helper functions to perform basic vector math operations.
</description>
<methods>
- <method name="abs" >
+ <method name="abs">
<return type="Vector3">
</return>
<description>
+ Returns a new vector with all components in absolute values (e.g. positive).
</description>
</method>
- <method name="cross" >
+ <method name="ceil">
+ <return type="Vector3">
+ </return>
+ <description>
+ Returns a new vector with all components rounded up.
+ </description>
+ </method>
+ <method name="cross">
<return type="Vector3">
</return>
<argument index="0" name="b" type="Vector3">
@@ -32190,7 +38501,7 @@
Return the cross product with b.
</description>
</method>
- <method name="cubic_interpolate" >
+ <method name="cubic_interpolate">
<return type="Vector3">
</return>
<argument index="0" name="b" type="Vector3">
@@ -32202,19 +38513,19 @@
<argument index="3" name="t" type="float">
</argument>
<description>
- Perform a cubic interpolation between vectors a,b,c,d (b is current), by the given amount (i).
+ Perform a cubic interpolation between vectors pre_a, a, b, post_b (a is current), by the given amount (t).
</description>
</method>
- <method name="distance_squared_to" >
+ <method name="distance_squared_to">
<return type="float">
</return>
<argument index="0" name="b" type="Vector3">
</argument>
<description>
- Return the squared distance (distance minus the last square root) to b.
+ Return the squared distance (distance minus the last square root) to b. Prefer this function over distance_to if you need to sort vectors or need the squared distance for some formula.
</description>
</method>
- <method name="distance_to" >
+ <method name="distance_to">
<return type="float">
</return>
<argument index="0" name="b" type="Vector3">
@@ -32223,7 +38534,7 @@
Return the distance to b.
</description>
</method>
- <method name="dot" >
+ <method name="dot">
<return type="float">
</return>
<argument index="0" name="b" type="Vector3">
@@ -32232,28 +38543,35 @@
Return the dot product with b.
</description>
</method>
- <method name="inverse" >
+ <method name="floor">
+ <return type="Vector3">
+ </return>
+ <description>
+ Returns a new vector with all components rounded down.
+ </description>
+ </method>
+ <method name="inverse">
<return type="Vector3">
</return>
<description>
- Returns the inverse of the vector. this is the same as Vector3( 1.0 / v.x, 1.0 / v.y, 1.0 / v.z )
+ Returns the inverse of the vector. This is the same as Vector3( 1.0 / v.x, 1.0 / v.y, 1.0 / v.z )
</description>
</method>
- <method name="length" >
+ <method name="length">
<return type="float">
</return>
<description>
Return the length of the vector.
</description>
</method>
- <method name="length_squared" >
+ <method name="length_squared">
<return type="float">
</return>
<description>
- Return the length of the vector, without the square root step.
+ Return the length of the vector, squared. Prefer this function over "length" if you need to sort vectors or need the squared length for some formula.
</description>
</method>
- <method name="linear_interpolate" >
+ <method name="linear_interpolate">
<return type="Vector3">
</return>
<argument index="0" name="b" type="Vector3">
@@ -32261,37 +38579,40 @@
<argument index="1" name="t" type="float">
</argument>
<description>
- Linearly interpolates the vector to a given one (b), by the given amount (i)
+ Linearly interpolates the vector to a given one (b), by the given amount (t).
</description>
</method>
- <method name="max_axis" >
+ <method name="max_axis">
<return type="int">
</return>
<description>
+ Returns AXIS_X, AXIS_Y or AXIS_Z depending on which axis is the largest.
</description>
</method>
- <method name="min_axis" >
+ <method name="min_axis">
<return type="int">
</return>
<description>
+ Returns AXIS_X, AXIS_Y or AXIS_Z depending on which axis is the smallest.
</description>
</method>
- <method name="normalized" >
+ <method name="normalized">
<return type="Vector3">
</return>
<description>
- Return a copy of the normalized vector to unit length. This is the same as v / v.length()
+ Return a copy of the normalized vector to unit length. This is the same as v / v.length().
</description>
</method>
- <method name="reflect" >
+ <method name="reflect">
<return type="Vector3">
</return>
<argument index="0" name="by" type="Vector3">
</argument>
<description>
+ Like "slide", but reflects the Vector instead of continuing along the wall.
</description>
</method>
- <method name="rotated" >
+ <method name="rotated">
<return type="Vector3">
</return>
<argument index="0" name="axis" type="Vector3">
@@ -32299,17 +38620,19 @@
<argument index="1" name="phi" type="float">
</argument>
<description>
+ Rotates the vector around some axis by phi radians.
</description>
</method>
- <method name="slide" >
+ <method name="slide">
<return type="Vector3">
</return>
<argument index="0" name="by" type="Vector3">
</argument>
<description>
+ Slides the vector along a wall.
</description>
</method>
- <method name="snapped" >
+ <method name="snapped">
<return type="Vector3">
</return>
<argument index="0" name="by" type="float">
@@ -32318,7 +38641,9 @@
Return a copy of the vector, snapped to the lowest neared multiple.
</description>
</method>
- <method name="Vector3" >
+ <method name="Vector3">
+ <return type="Vector3">
+ </return>
<argument index="0" name="x" type="float">
</argument>
<argument index="1" name="y" type="float">
@@ -32326,6 +38651,7 @@
<argument index="2" name="z" type="float">
</argument>
<description>
+ Returns a Vector3 with the given components.
</description>
</method>
</methods>
@@ -32339,57 +38665,70 @@
</members>
<constants>
<constant name="AXIS_X" value="0">
+ Enumerated value for the X axis. Returned by functions like max_axis or min_axis.
</constant>
<constant name="AXIS_Y" value="1">
+ Enumerated value for the Y axis.
</constant>
<constant name="AXIS_Z" value="2">
+ Enumerated value for the Z axis.
</constant>
</constants>
</class>
<class name="Vector3Array" category="Built-In Types">
<brief_description>
+ An Array of Vector3.
</brief_description>
<description>
+ An Array specifically designed to hold Vector3.
</description>
<methods>
- <method name="get" >
+ <method name="get">
<return type="Vector3">
</return>
<argument index="0" name="idx" type="int">
</argument>
<description>
+ Returns the Vector3 at the given index.
</description>
</method>
- <method name="push_back" >
+ <method name="push_back">
<argument index="0" name="vector3" type="Vector3">
</argument>
<description>
+ Inserts a Vector3 at the end.
</description>
</method>
- <method name="resize" >
+ <method name="resize">
<argument index="0" name="idx" type="int">
</argument>
<description>
+ Sets the size of the Vector3Array. If larger than the current size it will reserve some space beforehand, and if it is smaller it will cut off the array.
</description>
</method>
- <method name="set" >
+ <method name="set">
<argument index="0" name="idx" type="int">
</argument>
<argument index="1" name="vector3" type="Vector3">
</argument>
<description>
+ Changes the Vector3 at the given index.
</description>
</method>
- <method name="size" >
+ <method name="size">
<return type="int">
</return>
<description>
+ Returns the size of the array.
</description>
</method>
- <method name="Vector3Array" >
+ <method name="Vector3Array">
+ <return type="Vector3Array">
+ </return>
<argument index="0" name="from" type="Array">
</argument>
<description>
+ Constructs a new Vector3Array. Optionally, you can pass in an Array that will be converted.
</description>
</method>
</methods>
@@ -32402,61 +38741,61 @@
<description>
</description>
<methods>
- <method name="set_mass" >
+ <method name="set_mass">
<argument index="0" name="mass" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_mass" qualifiers="const" >
+ <method name="get_mass" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_friction" >
+ <method name="set_friction">
<argument index="0" name="friction" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_friction" qualifiers="const" >
+ <method name="get_friction" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_engine_force" >
+ <method name="set_engine_force">
<argument index="0" name="engine_force" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_engine_force" qualifiers="const" >
+ <method name="get_engine_force" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_brake" >
+ <method name="set_brake">
<argument index="0" name="brake" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_brake" qualifiers="const" >
+ <method name="get_brake" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_steering" >
+ <method name="set_steering">
<argument index="0" name="steering" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_steering" qualifiers="const" >
+ <method name="get_steering" qualifiers="const">
<return type="float">
</return>
<description>
@@ -32472,121 +38811,121 @@
<description>
</description>
<methods>
- <method name="set_radius" >
+ <method name="set_radius">
<argument index="0" name="length" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_radius" qualifiers="const" >
+ <method name="get_radius" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_suspension_rest_length" >
+ <method name="set_suspension_rest_length">
<argument index="0" name="length" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_suspension_rest_length" qualifiers="const" >
+ <method name="get_suspension_rest_length" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_suspension_travel" >
+ <method name="set_suspension_travel">
<argument index="0" name="length" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_suspension_travel" qualifiers="const" >
+ <method name="get_suspension_travel" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_suspension_stiffness" >
+ <method name="set_suspension_stiffness">
<argument index="0" name="length" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_suspension_stiffness" qualifiers="const" >
+ <method name="get_suspension_stiffness" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_suspension_max_force" >
+ <method name="set_suspension_max_force">
<argument index="0" name="length" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_suspension_max_force" qualifiers="const" >
+ <method name="get_suspension_max_force" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_damping_compression" >
+ <method name="set_damping_compression">
<argument index="0" name="length" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_damping_compression" qualifiers="const" >
+ <method name="get_damping_compression" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_damping_relaxation" >
+ <method name="set_damping_relaxation">
<argument index="0" name="length" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_damping_relaxation" qualifiers="const" >
+ <method name="get_damping_relaxation" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_use_as_traction" >
+ <method name="set_use_as_traction">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_used_as_traction" qualifiers="const" >
+ <method name="is_used_as_traction" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_use_as_steering" >
+ <method name="set_use_as_steering">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_used_as_steering" qualifiers="const" >
+ <method name="is_used_as_steering" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_friction_slip" >
+ <method name="set_friction_slip">
<argument index="0" name="length" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_friction_slip" qualifiers="const" >
+ <method name="get_friction_slip" qualifiers="const">
<return type="float">
</return>
<description>
@@ -32602,135 +38941,131 @@
<description>
</description>
<methods>
- <method name="set_stream" >
+ <method name="set_stream">
<argument index="0" name="stream" type="Stream">
</argument>
<description>
</description>
</method>
- <method name="get_stream" qualifiers="const" >
+ <method name="get_stream" qualifiers="const">
<return type="Stream">
</return>
<description>
</description>
</method>
- <method name="play" >
+ <method name="play">
<description>
</description>
</method>
- <method name="stop" >
+ <method name="stop">
<description>
</description>
</method>
- <method name="is_playing" qualifiers="const" >
+ <method name="is_playing" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_paused" >
+ <method name="set_paused">
<argument index="0" name="paused" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_paused" qualifiers="const" >
+ <method name="is_paused" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_volume" >
+ <method name="set_volume">
<argument index="0" name="volume" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_volume" qualifiers="const" >
+ <method name="get_volume" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_volume_db" >
+ <method name="set_volume_db">
<argument index="0" name="db" type="float">
</argument>
<description>
</description>
</method>
- <method name="get_volume_db" qualifiers="const" >
+ <method name="get_volume_db" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="get_stream_name" qualifiers="const" >
+ <method name="set_audio_track">
+ <argument index="0" name="track" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_audio_track" qualifiers="const">
+ <return type="int">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="get_stream_name" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="get_stream_pos" qualifiers="const" >
+ <method name="get_stream_pos" qualifiers="const">
<return type="float">
</return>
<description>
</description>
</method>
- <method name="set_autoplay" >
+ <method name="set_autoplay">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="has_autoplay" qualifiers="const" >
+ <method name="has_autoplay" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_expand" >
+ <method name="set_expand">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="has_expand" qualifiers="const" >
+ <method name="has_expand" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="VideoStream" inherits="Resource" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="get_pending_frame_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="pop_frame" >
- <argument index="0" name="arg0" type="Object">
+ <method name="set_buffering_msec">
+ <argument index="0" name="msec" type="int">
</argument>
<description>
</description>
</method>
- <method name="peek_frame" qualifiers="const" >
- <return type="Image">
+ <method name="get_buffering_msec" qualifiers="const">
+ <return type="int">
</return>
<description>
</description>
</method>
- <method name="set_audio_track" >
- <argument index="0" name="idx" type="int">
- </argument>
+ <method name="get_video_texutre">
+ <return type="Texture">
+ </return>
<description>
</description>
</method>
@@ -32738,109 +39073,129 @@
<constants>
</constants>
</class>
+<class name="VideoStream" inherits="Resource" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
+<class name="VideoStreamTheora" inherits="VideoStream" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ </methods>
+ <constants>
+ </constants>
+</class>
<class name="Viewport" inherits="Node" category="Core">
<brief_description>
Creates a sub-view into the screen.
</brief_description>
<description>
- A Viewport creates a different view into the screen, or a sub-view inside another viewport. Children 2D Nodes will display on it, and children Camera 3D nodes will renderon it too.[br]
- Optionally, a viewport can have it's own 2D or 3D world, so they don't share what they draw with other viewports.[br]
- If a viewport is a child of a [Control], it will automatically take up it's same rect and position, otherwise they must be set manually.[br]
- Viewports can also choose to be audio listeners, so they generate positional audio depending on a 2D or 3D camera child of it.[br]
- Also, viewports can be assigned to different screens in the situation while devices have multiple screens.[br]
- Finaly, viewports can also behave as render targets, in which case they will not be visible unless the associated texture is used to draw.
+ A Viewport creates a different view into the screen, or a sub-view inside another viewport. Children 2D Nodes will display on it, and children Camera 3D nodes will render on it too.
+ Optionally, a viewport can have its own 2D or 3D world, so they don't share what they draw with other viewports.
+ If a viewport is a child of a [Control], it will automatically take up its same rect and position, otherwise they must be set manually.
+ Viewports can also choose to be audio listeners, so they generate positional audio depending on a 2D or 3D camera child of it.
+ Also, viewports can be assigned to different screens in case the devices have multiple screens.
+ Finally, viewports can also behave as render targets, in which case they will not be visible unless the associated texture is used to draw.
</description>
<methods>
- <method name="set_rect" >
+ <method name="set_rect">
<argument index="0" name="rect" type="Rect2">
</argument>
<description>
- Set the viewport rect. If the viewport is child of a control, it will use the same as the parent.
+ Set the viewport rect. If the viewport is child of a control, it will use the same rect as the parent.
</description>
</method>
- <method name="get_rect" qualifiers="const" >
+ <method name="get_rect" qualifiers="const">
<return type="Rect2">
</return>
<description>
- Return the viewport rect. If the viewport is child of a control, it will use the same as the parent, otherwise if the rect is empty, the viewport will use all the allowed space.
+ Return the viewport rect. If the viewport is child of a control, it will use the same rect as the parent. Otherwise, if the rect is empty, the viewport will use all the allowed space.
</description>
</method>
- <method name="find_world_2d" qualifiers="const" >
+ <method name="find_world_2d" qualifiers="const">
<return type="World2D">
</return>
<description>
</description>
</method>
- <method name="set_world" >
+ <method name="set_world">
<argument index="0" name="world" type="World">
</argument>
<description>
</description>
</method>
- <method name="get_world" qualifiers="const" >
+ <method name="get_world" qualifiers="const">
<return type="World">
</return>
<description>
</description>
</method>
- <method name="find_world" qualifiers="const" >
+ <method name="find_world" qualifiers="const">
<return type="World">
</return>
<description>
</description>
</method>
- <method name="set_canvas_transform" >
+ <method name="set_canvas_transform">
<argument index="0" name="xform" type="Matrix32">
</argument>
<description>
</description>
</method>
- <method name="get_canvas_transform" qualifiers="const" >
+ <method name="get_canvas_transform" qualifiers="const">
<return type="Matrix32">
</return>
<description>
</description>
</method>
- <method name="set_global_canvas_transform" >
+ <method name="set_global_canvas_transform">
<argument index="0" name="xform" type="Matrix32">
</argument>
<description>
</description>
</method>
- <method name="get_global_canvas_transform" qualifiers="const" >
+ <method name="get_global_canvas_transform" qualifiers="const">
<return type="Matrix32">
</return>
<description>
</description>
</method>
- <method name="get_final_transform" qualifiers="const" >
+ <method name="get_final_transform" qualifiers="const">
<return type="Matrix32">
</return>
<description>
</description>
</method>
- <method name="get_visible_rect" qualifiers="const" >
+ <method name="get_visible_rect" qualifiers="const">
<return type="Rect2">
</return>
<description>
Return the final, visuble rect in global screen coordinates.
</description>
</method>
- <method name="set_transparent_background" >
+ <method name="set_transparent_background">
<argument index="0" name="enable" type="bool">
</argument>
<description>
- Keep whathver the parent viewport has drawn
+ If this viewport is a child of another viewport, keep the previously drawn background visible.
</description>
</method>
- <method name="has_transparent_background" qualifiers="const" >
+ <method name="has_transparent_background" qualifiers="const">
<return type="bool">
</return>
<description>
- If this viewport is a child of another viewport, keep the previously drawn background visible.
+ Reurn whether the viewport lets whatever is behind it to show.
</description>
</method>
- <method name="set_size_override" >
+ <method name="set_size_override">
<argument index="0" name="enable" type="bool">
</argument>
<argument index="1" name="size" type="Vector2" default="Vector2(-1,-1)">
@@ -32850,185 +39205,213 @@
<description>
</description>
</method>
- <method name="get_size_override" qualifiers="const" >
+ <method name="get_size_override" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="is_size_override_enabled" qualifiers="const" >
+ <method name="is_size_override_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_size_override_stretch" >
+ <method name="set_size_override_stretch">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_size_override_stretch_enabled" qualifiers="const" >
+ <method name="is_size_override_stretch_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="queue_screen_capture" >
+ <method name="queue_screen_capture">
<description>
</description>
</method>
- <method name="get_screen_capture" qualifiers="const" >
+ <method name="get_screen_capture" qualifiers="const">
<return type="Image">
</return>
<description>
</description>
</method>
- <method name="set_as_render_target" >
+ <method name="set_as_render_target">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_set_as_render_target" qualifiers="const" >
+ <method name="is_set_as_render_target" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_render_target_vflip" >
+ <method name="set_render_target_vflip">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="get_render_target_vflip" qualifiers="const" >
+ <method name="get_render_target_vflip" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_render_target_filter" >
+ <method name="set_render_target_clear_on_new_frame">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="get_render_target_filter" qualifiers="const" >
+ <method name="get_render_target_clear_on_new_frame" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_render_target_gen_mipmaps" >
+ <method name="render_target_clear">
+ <description>
+ </description>
+ </method>
+ <method name="set_render_target_filter">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="get_render_target_gen_mipmaps" qualifiers="const" >
+ <method name="get_render_target_filter" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_render_target_update_mode" >
+ <method name="set_render_target_gen_mipmaps">
+ <argument index="0" name="enable" type="bool">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_render_target_gen_mipmaps" qualifiers="const">
+ <return type="bool">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="set_render_target_update_mode">
<argument index="0" name="mode" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_render_target_update_mode" qualifiers="const" >
+ <method name="get_render_target_update_mode" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_render_target_texture" qualifiers="const" >
+ <method name="get_render_target_texture" qualifiers="const">
<return type="RenderTargetTexture">
</return>
<description>
</description>
</method>
- <method name="set_physics_object_picking" >
+ <method name="set_physics_object_picking">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="get_physics_object_picking" >
+ <method name="get_physics_object_picking">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="get_viewport" qualifiers="const" >
+ <method name="get_viewport" qualifiers="const">
<return type="RID">
</return>
<description>
Get the viewport RID from the visual server.
</description>
</method>
- <method name="input" >
+ <method name="input">
<argument index="0" name="local_event" type="InputEvent">
</argument>
<description>
</description>
</method>
- <method name="unhandled_input" >
+ <method name="unhandled_input">
<argument index="0" name="local_event" type="InputEvent">
</argument>
<description>
</description>
</method>
- <method name="update_worlds" >
+ <method name="update_worlds">
<description>
</description>
</method>
- <method name="set_use_own_world" >
+ <method name="set_use_own_world">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_using_own_world" qualifiers="const" >
+ <method name="is_using_own_world" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="get_camera" qualifiers="const" >
+ <method name="get_camera" qualifiers="const">
<return type="Camera">
</return>
<description>
</description>
</method>
- <method name="set_as_audio_listener" >
+ <method name="set_as_audio_listener">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_audio_listener" qualifiers="const" >
+ <method name="is_audio_listener" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_as_audio_listener_2d" >
+ <method name="set_as_audio_listener_2d">
<argument index="0" name="enable" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_audio_listener_2d" qualifiers="const" >
+ <method name="is_audio_listener_2d" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_render_target_to_screen_rect" >
- <argument index="0" name="arg0" type="Rect2">
+ <method name="set_render_target_to_screen_rect">
+ <argument index="0" name="rect" type="Rect2">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="get_mouse_pos" qualifiers="const">
+ <return type="Vector2">
+ </return>
+ <description>
+ </description>
+ </method>
+ <method name="warp_mouse">
+ <argument index="0" name="to_pos" type="Vector2">
</argument>
<description>
</description>
@@ -33057,49 +39440,49 @@
<description>
</description>
<methods>
- <method name="set_viewport_path" >
+ <method name="set_viewport_path">
<argument index="0" name="path" type="NodePath">
</argument>
<description>
</description>
</method>
- <method name="get_viewport_path" qualifiers="const" >
+ <method name="get_viewport_path" qualifiers="const">
<return type="NodePath">
</return>
<description>
</description>
</method>
- <method name="set_centered" >
+ <method name="set_centered">
<argument index="0" name="centered" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_centered" qualifiers="const" >
+ <method name="is_centered" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="set_offset" >
+ <method name="set_offset">
<argument index="0" name="offset" type="Vector2">
</argument>
<description>
</description>
</method>
- <method name="get_offset" qualifiers="const" >
+ <method name="get_offset" qualifiers="const">
<return type="Vector2">
</return>
<description>
</description>
</method>
- <method name="set_modulate" >
+ <method name="set_modulate">
<argument index="0" name="modulate" type="Color">
</argument>
<description>
</description>
</method>
- <method name="get_modulate" qualifiers="const" >
+ <method name="get_modulate" qualifiers="const">
<return type="Color">
</return>
<description>
@@ -33115,7 +39498,7 @@
<description>
</description>
<methods>
- <method name="set_enabler" >
+ <method name="set_enabler">
<argument index="0" name="enabler" type="int">
</argument>
<argument index="1" name="enabled" type="bool">
@@ -33123,7 +39506,7 @@
<description>
</description>
</method>
- <method name="is_enabler_enabled" qualifiers="const" >
+ <method name="is_enabler_enabled" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="enabler" type="int">
@@ -33147,7 +39530,7 @@
<description>
</description>
<methods>
- <method name="set_enabler" >
+ <method name="set_enabler">
<argument index="0" name="enabler" type="int">
</argument>
<argument index="1" name="enabled" type="bool">
@@ -33155,7 +39538,7 @@
<description>
</description>
</method>
- <method name="is_enabler_enabled" qualifiers="const" >
+ <method name="is_enabler_enabled" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="enabler" type="int">
@@ -33169,7 +39552,13 @@
</constant>
<constant name="ENABLER_PAUSE_ANIMATIONS" value="0">
</constant>
- <constant name="ENABLER_MAX" value="2">
+ <constant name="ENABLER_PAUSE_PARTICLES" value="2">
+ </constant>
+ <constant name="ENABLER_PARENT_PROCESS" value="3">
+ </constant>
+ <constant name="ENABLER_PARENT_FIXED_PROCESS" value="4">
+ </constant>
+ <constant name="ENABLER_MAX" value="5">
</constant>
</constants>
</class>
@@ -33179,19 +39568,19 @@
<description>
</description>
<methods>
- <method name="set_aabb" >
+ <method name="set_aabb">
<argument index="0" name="rect" type="AABB">
</argument>
<description>
</description>
</method>
- <method name="get_aabb" qualifiers="const" >
+ <method name="get_aabb" qualifiers="const">
<return type="AABB">
</return>
<description>
</description>
</method>
- <method name="is_on_screen" qualifiers="const" >
+ <method name="is_on_screen" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -33229,19 +39618,19 @@
<description>
</description>
<methods>
- <method name="set_rect" >
+ <method name="set_rect">
<argument index="0" name="rect" type="Rect2">
</argument>
<description>
</description>
</method>
- <method name="get_rect" qualifiers="const" >
+ <method name="get_rect" qualifiers="const">
<return type="Rect2">
</return>
<description>
</description>
</method>
- <method name="is_on_screen" qualifiers="const" >
+ <method name="is_on_screen" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -33279,19 +39668,19 @@
<description>
</description>
<methods>
- <method name="set_base" >
+ <method name="set_base">
<argument index="0" name="base" type="RID">
</argument>
<description>
</description>
</method>
- <method name="set_layer_mask" >
+ <method name="set_layer_mask">
<argument index="0" name="mask" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_layer_mask" qualifiers="const" >
+ <method name="get_layer_mask" qualifiers="const">
<return type="int">
</return>
<description>
@@ -33306,17 +39695,17 @@
Server for anything visible.
</brief_description>
<description>
- Server for anything visible. The visual server is the API backend for everything visible. The whole scene system mounts on it to display.[br]
+ Server for anything visible. The visual server is the API backend for everything visible. The whole scene system mounts on it to display.
The visual server is completely opaque, the internals are entirely implementation specific and cannot be accessed.
</description>
<methods>
- <method name="texture_create" >
+ <method name="texture_create">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="texture_create_from_image" >
+ <method name="texture_create_from_image">
<return type="RID">
</return>
<argument index="0" name="arg0" type="Image">
@@ -33326,7 +39715,7 @@
<description>
</description>
</method>
- <method name="texture_set_flags" >
+ <method name="texture_set_flags">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -33334,7 +39723,7 @@
<description>
</description>
</method>
- <method name="texture_get_flags" qualifiers="const" >
+ <method name="texture_get_flags" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33342,7 +39731,7 @@
<description>
</description>
</method>
- <method name="texture_get_width" qualifiers="const" >
+ <method name="texture_get_width" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33350,7 +39739,7 @@
<description>
</description>
</method>
- <method name="texture_get_height" qualifiers="const" >
+ <method name="texture_get_height" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33358,7 +39747,7 @@
<description>
</description>
</method>
- <method name="shader_create" >
+ <method name="shader_create">
<return type="RID">
</return>
<argument index="0" name="mode" type="int" default="0">
@@ -33366,7 +39755,7 @@
<description>
</description>
</method>
- <method name="shader_set_mode" >
+ <method name="shader_set_mode">
<argument index="0" name="shader" type="RID">
</argument>
<argument index="1" name="mode" type="int">
@@ -33374,13 +39763,13 @@
<description>
</description>
</method>
- <method name="material_create" >
+ <method name="material_create">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="material_set_shader" >
+ <method name="material_set_shader">
<argument index="0" name="shader" type="RID">
</argument>
<argument index="1" name="arg1" type="RID">
@@ -33388,7 +39777,7 @@
<description>
</description>
</method>
- <method name="material_get_shader" qualifiers="const" >
+ <method name="material_get_shader" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33396,7 +39785,7 @@
<description>
</description>
</method>
- <method name="material_set_param" >
+ <method name="material_set_param">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="String">
@@ -33406,7 +39795,7 @@
<description>
</description>
</method>
- <method name="material_get_param" qualifiers="const" >
+ <method name="material_get_param" qualifiers="const">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="String">
@@ -33414,7 +39803,7 @@
<description>
</description>
</method>
- <method name="material_set_flag" >
+ <method name="material_set_flag">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -33424,7 +39813,7 @@
<description>
</description>
</method>
- <method name="material_get_flag" qualifiers="const" >
+ <method name="material_get_flag" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33434,7 +39823,7 @@
<description>
</description>
</method>
- <method name="material_set_blend_mode" >
+ <method name="material_set_blend_mode">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -33442,7 +39831,7 @@
<description>
</description>
</method>
- <method name="material_get_blend_mode" qualifiers="const" >
+ <method name="material_get_blend_mode" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33450,7 +39839,7 @@
<description>
</description>
</method>
- <method name="material_set_line_width" >
+ <method name="material_set_line_width">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="float">
@@ -33458,7 +39847,7 @@
<description>
</description>
</method>
- <method name="material_get_line_width" qualifiers="const" >
+ <method name="material_get_line_width" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33466,13 +39855,13 @@
<description>
</description>
</method>
- <method name="mesh_create" >
+ <method name="mesh_create">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="mesh_add_surface" >
+ <method name="mesh_add_surface">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -33486,7 +39875,7 @@
<description>
</description>
</method>
- <method name="mesh_surface_set_material" >
+ <method name="mesh_surface_set_material">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -33498,7 +39887,7 @@
<description>
</description>
</method>
- <method name="mesh_surface_get_material" qualifiers="const" >
+ <method name="mesh_surface_get_material" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33508,7 +39897,7 @@
<description>
</description>
</method>
- <method name="mesh_surface_get_array_len" qualifiers="const" >
+ <method name="mesh_surface_get_array_len" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33518,7 +39907,7 @@
<description>
</description>
</method>
- <method name="mesh_surface_get_array_index_len" qualifiers="const" >
+ <method name="mesh_surface_get_array_index_len" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33528,7 +39917,7 @@
<description>
</description>
</method>
- <method name="mesh_surface_get_format" qualifiers="const" >
+ <method name="mesh_surface_get_format" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33538,7 +39927,7 @@
<description>
</description>
</method>
- <method name="mesh_surface_get_primitive_type" qualifiers="const" >
+ <method name="mesh_surface_get_primitive_type" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33548,7 +39937,7 @@
<description>
</description>
</method>
- <method name="mesh_remove_surface" >
+ <method name="mesh_remove_surface">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -33556,7 +39945,7 @@
<description>
</description>
</method>
- <method name="mesh_get_surface_count" qualifiers="const" >
+ <method name="mesh_get_surface_count" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33564,13 +39953,13 @@
<description>
</description>
</method>
- <method name="multimesh_create" >
+ <method name="multimesh_create">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="multimesh_set_mesh" >
+ <method name="multimesh_set_mesh">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="RID">
@@ -33578,7 +39967,7 @@
<description>
</description>
</method>
- <method name="multimesh_set_aabb" >
+ <method name="multimesh_set_aabb">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="AABB">
@@ -33586,7 +39975,7 @@
<description>
</description>
</method>
- <method name="multimesh_instance_set_transform" >
+ <method name="multimesh_instance_set_transform">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -33596,7 +39985,7 @@
<description>
</description>
</method>
- <method name="multimesh_instance_set_color" >
+ <method name="multimesh_instance_set_color">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -33606,7 +39995,7 @@
<description>
</description>
</method>
- <method name="multimesh_get_mesh" qualifiers="const" >
+ <method name="multimesh_get_mesh" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33614,7 +40003,7 @@
<description>
</description>
</method>
- <method name="multimesh_get_aabb" qualifiers="const" >
+ <method name="multimesh_get_aabb" qualifiers="const">
<return type="AABB">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33624,7 +40013,7 @@
<description>
</description>
</method>
- <method name="multimesh_instance_get_transform" qualifiers="const" >
+ <method name="multimesh_instance_get_transform" qualifiers="const">
<return type="Transform">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33634,7 +40023,7 @@
<description>
</description>
</method>
- <method name="multimesh_instance_get_color" qualifiers="const" >
+ <method name="multimesh_instance_get_color" qualifiers="const">
<return type="Color">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33644,13 +40033,13 @@
<description>
</description>
</method>
- <method name="particles_create" >
+ <method name="particles_create">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="particles_set_amount" >
+ <method name="particles_set_amount">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -33658,7 +40047,7 @@
<description>
</description>
</method>
- <method name="particles_get_amount" qualifiers="const" >
+ <method name="particles_get_amount" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33666,7 +40055,7 @@
<description>
</description>
</method>
- <method name="particles_set_emitting" >
+ <method name="particles_set_emitting">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="bool">
@@ -33674,7 +40063,7 @@
<description>
</description>
</method>
- <method name="particles_is_emitting" qualifiers="const" >
+ <method name="particles_is_emitting" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33682,7 +40071,7 @@
<description>
</description>
</method>
- <method name="particles_set_visibility_aabb" >
+ <method name="particles_set_visibility_aabb">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="AABB">
@@ -33690,7 +40079,7 @@
<description>
</description>
</method>
- <method name="particles_get_visibility_aabb" qualifiers="const" >
+ <method name="particles_get_visibility_aabb" qualifiers="const">
<return type="AABB">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33698,7 +40087,7 @@
<description>
</description>
</method>
- <method name="particles_set_variable" >
+ <method name="particles_set_variable">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -33708,7 +40097,7 @@
<description>
</description>
</method>
- <method name="particles_get_variable" qualifiers="const" >
+ <method name="particles_get_variable" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33718,7 +40107,7 @@
<description>
</description>
</method>
- <method name="particles_set_randomness" >
+ <method name="particles_set_randomness">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -33728,7 +40117,7 @@
<description>
</description>
</method>
- <method name="particles_get_randomness" qualifiers="const" >
+ <method name="particles_get_randomness" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33738,7 +40127,7 @@
<description>
</description>
</method>
- <method name="particles_set_color_phases" >
+ <method name="particles_set_color_phases">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -33746,7 +40135,7 @@
<description>
</description>
</method>
- <method name="particles_get_color_phases" qualifiers="const" >
+ <method name="particles_get_color_phases" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33754,7 +40143,7 @@
<description>
</description>
</method>
- <method name="particles_set_color_phase_pos" >
+ <method name="particles_set_color_phase_pos">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -33764,7 +40153,7 @@
<description>
</description>
</method>
- <method name="particles_get_color_phase_pos" qualifiers="const" >
+ <method name="particles_get_color_phase_pos" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33774,7 +40163,7 @@
<description>
</description>
</method>
- <method name="particles_set_color_phase_color" >
+ <method name="particles_set_color_phase_color">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -33784,7 +40173,7 @@
<description>
</description>
</method>
- <method name="particles_get_color_phase_color" qualifiers="const" >
+ <method name="particles_get_color_phase_color" qualifiers="const">
<return type="Color">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33794,7 +40183,7 @@
<description>
</description>
</method>
- <method name="particles_set_attractors" >
+ <method name="particles_set_attractors">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -33802,7 +40191,7 @@
<description>
</description>
</method>
- <method name="particles_get_attractors" qualifiers="const" >
+ <method name="particles_get_attractors" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33810,7 +40199,7 @@
<description>
</description>
</method>
- <method name="particles_set_attractor_pos" >
+ <method name="particles_set_attractor_pos">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -33820,7 +40209,7 @@
<description>
</description>
</method>
- <method name="particles_get_attractor_pos" qualifiers="const" >
+ <method name="particles_get_attractor_pos" qualifiers="const">
<return type="Vector3">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33830,7 +40219,7 @@
<description>
</description>
</method>
- <method name="particles_set_attractor_strength" >
+ <method name="particles_set_attractor_strength">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -33840,7 +40229,7 @@
<description>
</description>
</method>
- <method name="particles_get_attractor_strength" qualifiers="const" >
+ <method name="particles_get_attractor_strength" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33850,7 +40239,7 @@
<description>
</description>
</method>
- <method name="particles_set_material" >
+ <method name="particles_set_material">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="RID">
@@ -33860,7 +40249,7 @@
<description>
</description>
</method>
- <method name="particles_set_height_from_velocity" >
+ <method name="particles_set_height_from_velocity">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="bool">
@@ -33868,7 +40257,7 @@
<description>
</description>
</method>
- <method name="particles_has_height_from_velocity" qualifiers="const" >
+ <method name="particles_has_height_from_velocity" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33876,7 +40265,7 @@
<description>
</description>
</method>
- <method name="light_create" >
+ <method name="light_create">
<return type="RID">
</return>
<argument index="0" name="arg0" type="int">
@@ -33884,7 +40273,7 @@
<description>
</description>
</method>
- <method name="light_get_type" qualifiers="const" >
+ <method name="light_get_type" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33892,7 +40281,7 @@
<description>
</description>
</method>
- <method name="light_set_color" >
+ <method name="light_set_color">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -33902,7 +40291,7 @@
<description>
</description>
</method>
- <method name="light_get_color" qualifiers="const" >
+ <method name="light_get_color" qualifiers="const">
<return type="Color">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33912,7 +40301,7 @@
<description>
</description>
</method>
- <method name="light_set_shadow" >
+ <method name="light_set_shadow">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="bool">
@@ -33920,7 +40309,7 @@
<description>
</description>
</method>
- <method name="light_has_shadow" qualifiers="const" >
+ <method name="light_has_shadow" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33928,7 +40317,7 @@
<description>
</description>
</method>
- <method name="light_set_volumetric" >
+ <method name="light_set_volumetric">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="bool">
@@ -33936,7 +40325,7 @@
<description>
</description>
</method>
- <method name="light_is_volumetric" qualifiers="const" >
+ <method name="light_is_volumetric" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33944,7 +40333,7 @@
<description>
</description>
</method>
- <method name="light_set_projector" >
+ <method name="light_set_projector">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="RID">
@@ -33952,7 +40341,7 @@
<description>
</description>
</method>
- <method name="light_get_projector" qualifiers="const" >
+ <method name="light_get_projector" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33960,7 +40349,7 @@
<description>
</description>
</method>
- <method name="light_set_var" >
+ <method name="light_set_var">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -33970,7 +40359,7 @@
<description>
</description>
</method>
- <method name="light_get_var" qualifiers="const" >
+ <method name="light_get_var" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="arg0" type="RID">
@@ -33980,13 +40369,13 @@
<description>
</description>
</method>
- <method name="skeleton_create" >
+ <method name="skeleton_create">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="skeleton_resize" >
+ <method name="skeleton_resize">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -33994,7 +40383,7 @@
<description>
</description>
</method>
- <method name="skeleton_get_bone_count" qualifiers="const" >
+ <method name="skeleton_get_bone_count" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="arg0" type="RID">
@@ -34002,7 +40391,7 @@
<description>
</description>
</method>
- <method name="skeleton_bone_set_transform" >
+ <method name="skeleton_bone_set_transform">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -34012,7 +40401,7 @@
<description>
</description>
</method>
- <method name="skeleton_bone_get_transform" >
+ <method name="skeleton_bone_get_transform">
<return type="Transform">
</return>
<argument index="0" name="arg0" type="RID">
@@ -34022,13 +40411,13 @@
<description>
</description>
</method>
- <method name="room_create" >
+ <method name="room_create">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="room_set_bounds" >
+ <method name="room_set_bounds">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="Dictionary">
@@ -34036,7 +40425,7 @@
<description>
</description>
</method>
- <method name="room_get_bounds" qualifiers="const" >
+ <method name="room_get_bounds" qualifiers="const">
<return type="Dictionary">
</return>
<argument index="0" name="arg0" type="RID">
@@ -34044,13 +40433,13 @@
<description>
</description>
</method>
- <method name="portal_create" >
+ <method name="portal_create">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="portal_set_shape" >
+ <method name="portal_set_shape">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="Vector2Array">
@@ -34058,7 +40447,7 @@
<description>
</description>
</method>
- <method name="portal_get_shape" qualifiers="const" >
+ <method name="portal_get_shape" qualifiers="const">
<return type="Vector2Array">
</return>
<argument index="0" name="arg0" type="RID">
@@ -34066,7 +40455,7 @@
<description>
</description>
</method>
- <method name="portal_set_enabled" >
+ <method name="portal_set_enabled">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="bool">
@@ -34074,7 +40463,7 @@
<description>
</description>
</method>
- <method name="portal_is_enabled" qualifiers="const" >
+ <method name="portal_is_enabled" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="arg0" type="RID">
@@ -34082,7 +40471,7 @@
<description>
</description>
</method>
- <method name="portal_set_disable_distance" >
+ <method name="portal_set_disable_distance">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="float">
@@ -34090,7 +40479,7 @@
<description>
</description>
</method>
- <method name="portal_get_disable_distance" qualifiers="const" >
+ <method name="portal_get_disable_distance" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="arg0" type="RID">
@@ -34098,7 +40487,7 @@
<description>
</description>
</method>
- <method name="portal_set_disabled_color" >
+ <method name="portal_set_disabled_color">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="Color">
@@ -34106,7 +40495,7 @@
<description>
</description>
</method>
- <method name="portal_get_disabled_color" qualifiers="const" >
+ <method name="portal_get_disabled_color" qualifiers="const">
<return type="Color">
</return>
<argument index="0" name="arg0" type="RID">
@@ -34114,13 +40503,13 @@
<description>
</description>
</method>
- <method name="camera_create" >
+ <method name="camera_create">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="camera_set_perspective" >
+ <method name="camera_set_perspective">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="float">
@@ -34132,7 +40521,7 @@
<description>
</description>
</method>
- <method name="camera_set_orthogonal" >
+ <method name="camera_set_orthogonal">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="float">
@@ -34144,7 +40533,7 @@
<description>
</description>
</method>
- <method name="camera_set_transform" >
+ <method name="camera_set_transform">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="Transform">
@@ -34152,13 +40541,13 @@
<description>
</description>
</method>
- <method name="viewport_create" >
+ <method name="viewport_create">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="viewport_set_rect" >
+ <method name="viewport_set_rect">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="Rect2">
@@ -34166,7 +40555,7 @@
<description>
</description>
</method>
- <method name="viewport_get_rect" qualifiers="const" >
+ <method name="viewport_get_rect" qualifiers="const">
<return type="Rect2">
</return>
<argument index="0" name="arg0" type="RID">
@@ -34174,7 +40563,7 @@
<description>
</description>
</method>
- <method name="viewport_attach_camera" >
+ <method name="viewport_attach_camera">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="RID" default="RID()">
@@ -34182,7 +40571,7 @@
<description>
</description>
</method>
- <method name="viewport_get_attached_camera" qualifiers="const" >
+ <method name="viewport_get_attached_camera" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="arg0" type="RID">
@@ -34190,7 +40579,7 @@
<description>
</description>
</method>
- <method name="viewport_get_scenario" qualifiers="const" >
+ <method name="viewport_get_scenario" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="arg0" type="RID">
@@ -34198,7 +40587,7 @@
<description>
</description>
</method>
- <method name="viewport_attach_canvas" >
+ <method name="viewport_attach_canvas">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="RID">
@@ -34206,7 +40595,7 @@
<description>
</description>
</method>
- <method name="viewport_remove_canvas" >
+ <method name="viewport_remove_canvas">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="RID">
@@ -34214,7 +40603,7 @@
<description>
</description>
</method>
- <method name="viewport_set_global_canvas_transform" >
+ <method name="viewport_set_global_canvas_transform">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="Matrix32">
@@ -34222,13 +40611,13 @@
<description>
</description>
</method>
- <method name="scenario_create" >
+ <method name="scenario_create">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="scenario_set_debug" >
+ <method name="scenario_set_debug">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -34236,13 +40625,13 @@
<description>
</description>
</method>
- <method name="instance_create" >
+ <method name="instance_create">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="instance_get_base" qualifiers="const" >
+ <method name="instance_get_base" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="arg0" type="RID">
@@ -34250,7 +40639,7 @@
<description>
</description>
</method>
- <method name="instance_get_base_aabb" qualifiers="const" >
+ <method name="instance_get_base_aabb" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="arg0" type="RID">
@@ -34258,7 +40647,7 @@
<description>
</description>
</method>
- <method name="instance_set_transform" >
+ <method name="instance_set_transform">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="Transform">
@@ -34266,7 +40655,7 @@
<description>
</description>
</method>
- <method name="instance_get_transform" qualifiers="const" >
+ <method name="instance_get_transform" qualifiers="const">
<return type="Transform">
</return>
<argument index="0" name="arg0" type="RID">
@@ -34274,7 +40663,7 @@
<description>
</description>
</method>
- <method name="instance_attach_object_instance_ID" >
+ <method name="instance_attach_object_instance_ID">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="int">
@@ -34282,7 +40671,7 @@
<description>
</description>
</method>
- <method name="instance_get_object_instance_ID" qualifiers="const" >
+ <method name="instance_get_object_instance_ID" qualifiers="const">
<return type="int">
</return>
<argument index="0" name="arg0" type="RID">
@@ -34290,7 +40679,7 @@
<description>
</description>
</method>
- <method name="instance_attach_skeleton" >
+ <method name="instance_attach_skeleton">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="RID">
@@ -34298,7 +40687,7 @@
<description>
</description>
</method>
- <method name="instance_get_skeleton" qualifiers="const" >
+ <method name="instance_get_skeleton" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="arg0" type="RID">
@@ -34306,7 +40695,7 @@
<description>
</description>
</method>
- <method name="instance_set_room" >
+ <method name="instance_set_room">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="RID">
@@ -34314,7 +40703,7 @@
<description>
</description>
</method>
- <method name="instance_get_room" qualifiers="const" >
+ <method name="instance_get_room" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="arg0" type="RID">
@@ -34322,7 +40711,7 @@
<description>
</description>
</method>
- <method name="instance_set_exterior" >
+ <method name="instance_set_exterior">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="bool">
@@ -34330,7 +40719,7 @@
<description>
</description>
</method>
- <method name="instance_is_exterior" qualifiers="const" >
+ <method name="instance_is_exterior" qualifiers="const">
<return type="bool">
</return>
<argument index="0" name="arg0" type="RID">
@@ -34338,7 +40727,7 @@
<description>
</description>
</method>
- <method name="instances_cull_aabb" qualifiers="const" >
+ <method name="instances_cull_aabb" qualifiers="const">
<return type="Array">
</return>
<argument index="0" name="arg0" type="AABB">
@@ -34348,7 +40737,7 @@
<description>
</description>
</method>
- <method name="instances_cull_ray" qualifiers="const" >
+ <method name="instances_cull_ray" qualifiers="const">
<return type="Array">
</return>
<argument index="0" name="arg0" type="Vector3">
@@ -34360,7 +40749,7 @@
<description>
</description>
</method>
- <method name="instances_cull_convex" qualifiers="const" >
+ <method name="instances_cull_convex" qualifiers="const">
<return type="Array">
</return>
<argument index="0" name="arg0" type="Array">
@@ -34370,7 +40759,7 @@
<description>
</description>
</method>
- <method name="instance_geometry_override_material_param" qualifiers="const" >
+ <method name="instance_geometry_override_material_param" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="arg0" type="RID">
@@ -34378,7 +40767,7 @@
<description>
</description>
</method>
- <method name="instance_geometry_get_material_param" qualifiers="const" >
+ <method name="instance_geometry_get_material_param" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="arg0" type="RID">
@@ -34386,25 +40775,25 @@
<description>
</description>
</method>
- <method name="get_test_cube" >
+ <method name="get_test_cube">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="canvas_create" >
+ <method name="canvas_create">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="canvas_item_create" >
+ <method name="canvas_item_create">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="canvas_item_set_parent" >
+ <method name="canvas_item_set_parent">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="RID">
@@ -34412,7 +40801,7 @@
<description>
</description>
</method>
- <method name="canvas_item_get_parent" qualifiers="const" >
+ <method name="canvas_item_get_parent" qualifiers="const">
<return type="RID">
</return>
<argument index="0" name="arg0" type="RID">
@@ -34420,7 +40809,7 @@
<description>
</description>
</method>
- <method name="canvas_item_set_transform" >
+ <method name="canvas_item_set_transform">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="Matrix32">
@@ -34428,7 +40817,7 @@
<description>
</description>
</method>
- <method name="canvas_item_set_custom_rect" >
+ <method name="canvas_item_set_custom_rect">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="bool">
@@ -34438,7 +40827,7 @@
<description>
</description>
</method>
- <method name="canvas_item_set_clip" >
+ <method name="canvas_item_set_clip">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="bool">
@@ -34446,7 +40835,7 @@
<description>
</description>
</method>
- <method name="canvas_item_set_opacity" >
+ <method name="canvas_item_set_opacity">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="float">
@@ -34454,7 +40843,7 @@
<description>
</description>
</method>
- <method name="canvas_item_get_opacity" qualifiers="const" >
+ <method name="canvas_item_get_opacity" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="arg0" type="RID">
@@ -34464,7 +40853,7 @@
<description>
</description>
</method>
- <method name="canvas_item_set_self_opacity" >
+ <method name="canvas_item_set_self_opacity">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="float">
@@ -34472,7 +40861,7 @@
<description>
</description>
</method>
- <method name="canvas_item_get_self_opacity" qualifiers="const" >
+ <method name="canvas_item_get_self_opacity" qualifiers="const">
<return type="float">
</return>
<argument index="0" name="arg0" type="RID">
@@ -34482,7 +40871,15 @@
<description>
</description>
</method>
- <method name="canvas_item_add_line" >
+ <method name="canvas_item_set_z">
+ <argument index="0" name="arg0" type="RID">
+ </argument>
+ <argument index="1" name="arg1" type="int">
+ </argument>
+ <description>
+ </description>
+ </method>
+ <method name="canvas_item_add_line">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="Vector2">
@@ -34496,7 +40893,7 @@
<description>
</description>
</method>
- <method name="canvas_item_add_rect" >
+ <method name="canvas_item_add_rect">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="Rect2">
@@ -34506,7 +40903,7 @@
<description>
</description>
</method>
- <method name="canvas_item_add_texture_rect" >
+ <method name="canvas_item_add_texture_rect">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="Rect2">
@@ -34517,10 +40914,12 @@
</argument>
<argument index="4" name="arg4" type="Color" default="Color(1,1,1,1)">
</argument>
+ <argument index="5" name="arg5" type="bool" default="false">
+ </argument>
<description>
</description>
</method>
- <method name="canvas_item_add_texture_rect_region" >
+ <method name="canvas_item_add_texture_rect_region">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="Rect2">
@@ -34531,10 +40930,12 @@
</argument>
<argument index="4" name="arg4" type="Color" default="Color(1,1,1,1)">
</argument>
+ <argument index="5" name="arg5" type="bool" default="false">
+ </argument>
<description>
</description>
</method>
- <method name="canvas_item_add_style_box" >
+ <method name="canvas_item_add_style_box">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="Rect2">
@@ -34548,7 +40949,7 @@
<description>
</description>
</method>
- <method name="canvas_item_add_circle" >
+ <method name="canvas_item_add_circle">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="Vector2">
@@ -34560,7 +40961,7 @@
<description>
</description>
</method>
- <method name="viewport_set_canvas_transform" >
+ <method name="viewport_set_canvas_transform">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="RID">
@@ -34570,19 +40971,19 @@
<description>
</description>
</method>
- <method name="canvas_item_clear" >
+ <method name="canvas_item_clear">
<argument index="0" name="arg0" type="RID">
</argument>
<description>
</description>
</method>
- <method name="canvas_item_raise" >
+ <method name="canvas_item_raise">
<argument index="0" name="arg0" type="RID">
</argument>
<description>
</description>
</method>
- <method name="cursor_set_rotation" >
+ <method name="cursor_set_rotation">
<argument index="0" name="arg0" type="float">
</argument>
<argument index="1" name="arg1" type="int">
@@ -34590,7 +40991,7 @@
<description>
</description>
</method>
- <method name="cursor_set_texture" >
+ <method name="cursor_set_texture">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="Vector2">
@@ -34600,7 +41001,7 @@
<description>
</description>
</method>
- <method name="cursor_set_visible" >
+ <method name="cursor_set_visible">
<argument index="0" name="arg0" type="bool">
</argument>
<argument index="1" name="arg1" type="int">
@@ -34608,7 +41009,7 @@
<description>
</description>
</method>
- <method name="cursor_set_pos" >
+ <method name="cursor_set_pos">
<argument index="0" name="arg0" type="Vector2">
</argument>
<argument index="1" name="arg1" type="int">
@@ -34616,7 +41017,7 @@
<description>
</description>
</method>
- <method name="black_bars_set_margins" >
+ <method name="black_bars_set_margins">
<argument index="0" name="left" type="int">
</argument>
<argument index="1" name="top" type="int">
@@ -34628,7 +41029,7 @@
<description>
</description>
</method>
- <method name="black_bars_set_images" >
+ <method name="black_bars_set_images">
<argument index="0" name="left" type="RID">
</argument>
<argument index="1" name="top" type="RID">
@@ -34640,7 +41041,7 @@
<description>
</description>
</method>
- <method name="make_sphere_mesh" >
+ <method name="make_sphere_mesh">
<return type="RID">
</return>
<argument index="0" name="arg0" type="int">
@@ -34652,7 +41053,7 @@
<description>
</description>
</method>
- <method name="mesh_add_surface_from_planes" >
+ <method name="mesh_add_surface_from_planes">
<argument index="0" name="arg0" type="RID">
</argument>
<argument index="1" name="arg1" type="Array">
@@ -34660,27 +41061,27 @@
<description>
</description>
</method>
- <method name="draw" >
+ <method name="draw">
<description>
</description>
</method>
- <method name="flush" >
+ <method name="sync">
<description>
</description>
</method>
- <method name="free" >
+ <method name="free">
<argument index="0" name="arg0" type="RID">
</argument>
<description>
</description>
</method>
- <method name="set_default_clear_color" >
+ <method name="set_default_clear_color">
<argument index="0" name="arg0" type="Color">
</argument>
<description>
</description>
</method>
- <method name="get_render_info" >
+ <method name="get_render_info">
<return type="int">
</return>
<argument index="0" name="arg0" type="int">
@@ -34916,6 +41317,22 @@
</constant>
</constants>
</class>
+<class name="WeakRef" inherits="Reference" category="Core">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <methods>
+ <method name="get_ref" qualifiers="const">
+ <return type="Object">
+ </return>
+ <description>
+ </description>
+ </method>
+ </methods>
+ <constants>
+ </constants>
+</class>
<class name="WindowDialog" inherits="Popup" category="Core">
<brief_description>
Base class for window dialogs.
@@ -34924,21 +41341,21 @@
Windowdialog is the base class for all window-based dialogs. It's a by-default toplevel [Control] that draws a window decoration and allows motion and resizing.
</description>
<methods>
- <method name="set_title" >
+ <method name="set_title">
<argument index="0" name="title" type="String">
</argument>
<description>
Set the title of the window.
</description>
</method>
- <method name="get_title" qualifiers="const" >
+ <method name="get_title" qualifiers="const">
<return type="String">
</return>
<description>
Return the title of the window.
</description>
</method>
- <method name="get_close_button" >
+ <method name="get_close_button">
<return type="TextureButton">
</return>
<description>
@@ -34953,10 +41370,10 @@
</theme_item>
<theme_item name="titlebar_height" type="int">
</theme_item>
- <theme_item name="close_v_ofs" type="int">
- </theme_item>
<theme_item name="title_height" type="int">
</theme_item>
+ <theme_item name="close_v_ofs" type="int">
+ </theme_item>
<theme_item name="title_color" type="Color">
</theme_item>
<theme_item name="close_hilite" type="Texture">
@@ -34977,36 +41394,42 @@
Class that has everything pertaining to a world. A physics space, a visual scenario and a sound space. Spatial nodes register their resources into the current world.
</description>
<methods>
- <method name="get_space" qualifiers="const" >
+ <method name="get_space" qualifiers="const">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="get_scenario" qualifiers="const" >
+ <method name="get_scenario" qualifiers="const">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="get_sound_space" qualifiers="const" >
+ <method name="get_sound_space" qualifiers="const">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="set_environment" >
+ <method name="set_environment">
<argument index="0" name="env" type="Environment">
</argument>
<description>
</description>
</method>
- <method name="get_environment" qualifiers="const" >
+ <method name="get_environment" qualifiers="const">
<return type="Environment">
</return>
<description>
</description>
</method>
+ <method name="get_direct_space_state">
+ <return type="PhysicsDirectSpaceState">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
</constants>
@@ -35019,24 +41442,30 @@
Class that has everything pertaining to a 2D world. A physics space, a visual scenario and a sound space. 2D nodes register their resources into the current 2D world.
</description>
<methods>
- <method name="get_canvas" >
+ <method name="get_canvas">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="get_space" >
+ <method name="get_space">
<return type="RID">
</return>
<description>
</description>
</method>
- <method name="get_sound_space" >
+ <method name="get_sound_space">
<return type="RID">
</return>
<description>
</description>
</method>
+ <method name="get_direct_space_state">
+ <return type="Physics2DDirectSpaceState">
+ </return>
+ <description>
+ </description>
+ </method>
</methods>
<constants>
</constants>
@@ -35047,13 +41476,13 @@
<description>
</description>
<methods>
- <method name="set_environment" >
+ <method name="set_environment">
<argument index="0" name="env" type="Environment">
</argument>
<description>
</description>
</method>
- <method name="get_environment" qualifiers="const" >
+ <method name="get_environment" qualifiers="const">
<return type="Environment">
</return>
<description>
@@ -35069,107 +41498,107 @@
<description>
</description>
<methods>
- <method name="read" >
+ <method name="read">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_node_type" >
+ <method name="get_node_type">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_node_name" qualifiers="const" >
+ <method name="get_node_name" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="get_node_data" qualifiers="const" >
+ <method name="get_node_data" qualifiers="const">
<return type="String">
</return>
<description>
</description>
</method>
- <method name="get_node_offset" qualifiers="const" >
+ <method name="get_node_offset" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_attribute_count" qualifiers="const" >
+ <method name="get_attribute_count" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="get_attribute_name" qualifiers="const" >
+ <method name="get_attribute_name" qualifiers="const">
<return type="String">
</return>
- <argument index="0" name="arg0" type="int">
+ <argument index="0" name="idx" type="int">
</argument>
<description>
</description>
</method>
- <method name="get_attribute_value" qualifiers="const" >
+ <method name="get_attribute_value" qualifiers="const">
<return type="String">
</return>
- <argument index="0" name="arg0" type="int">
+ <argument index="0" name="idx" type="int">
</argument>
<description>
</description>
</method>
- <method name="has_attribute" qualifiers="const" >
+ <method name="has_attribute" qualifiers="const">
<return type="bool">
</return>
- <argument index="0" name="arg0" type="String">
+ <argument index="0" name="name" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_named_attribute_value" qualifiers="const" >
+ <method name="get_named_attribute_value" qualifiers="const">
<return type="String">
</return>
- <argument index="0" name="arg0" type="String">
+ <argument index="0" name="name" type="String">
</argument>
<description>
</description>
</method>
- <method name="get_named_attribute_value_safe" qualifiers="const" >
+ <method name="get_named_attribute_value_safe" qualifiers="const">
<return type="String">
</return>
- <argument index="0" name="arg0" type="String">
+ <argument index="0" name="name" type="String">
</argument>
<description>
</description>
</method>
- <method name="is_empty" qualifiers="const" >
+ <method name="is_empty" qualifiers="const">
<return type="bool">
</return>
<description>
</description>
</method>
- <method name="get_current_line" qualifiers="const" >
+ <method name="get_current_line" qualifiers="const">
<return type="int">
</return>
<description>
</description>
</method>
- <method name="skip_section" >
+ <method name="skip_section">
<description>
</description>
</method>
- <method name="seek" >
+ <method name="seek">
<return type="int">
</return>
- <argument index="0" name="arg0" type="int">
+ <argument index="0" name="pos" type="int">
</argument>
<description>
</description>
</method>
- <method name="open" >
+ <method name="open">
<return type="int">
</return>
<argument index="0" name="file" type="String">
@@ -35177,7 +41606,7 @@
<description>
</description>
</method>
- <method name="open_buffer" >
+ <method name="open_buffer">
<return type="int">
</return>
<argument index="0" name="buffer" type="RawArray">
@@ -35209,13 +41638,13 @@
<description>
</description>
<methods>
- <method name="set_sort_enabled" >
+ <method name="set_sort_enabled">
<argument index="0" name="enabled" type="bool">
</argument>
<description>
</description>
</method>
- <method name="is_sort_enabled" qualifiers="const" >
+ <method name="is_sort_enabled" qualifiers="const">
<return type="bool">
</return>
<description>
@@ -35233,19 +41662,25 @@
Boolean built-in type.
</description>
<methods>
- <method name="bool" >
+ <method name="bool">
+ <return type="bool">
+ </return>
<argument index="0" name="from" type="int">
</argument>
<description>
</description>
</method>
- <method name="bool" >
+ <method name="bool">
+ <return type="bool">
+ </return>
<argument index="0" name="from" type="float">
</argument>
<description>
</description>
</method>
- <method name="bool" >
+ <method name="bool">
+ <return type="bool">
+ </return>
<argument index="0" name="from" type="String">
</argument>
<description>
@@ -35261,19 +41696,25 @@
<description>
</description>
<methods>
- <method name="float" >
+ <method name="float">
+ <return type="float">
+ </return>
<argument index="0" name="from" type="bool">
</argument>
<description>
</description>
</method>
- <method name="float" >
+ <method name="float">
+ <return type="float">
+ </return>
<argument index="0" name="from" type="int">
</argument>
<description>
</description>
</method>
- <method name="float" >
+ <method name="float">
+ <return type="float">
+ </return>
<argument index="0" name="from" type="String">
</argument>
<description>
@@ -35291,19 +41732,25 @@
Integer built-in type.
</description>
<methods>
- <method name="int" >
+ <method name="int">
+ <return type="int">
+ </return>
<argument index="0" name="from" type="bool">
</argument>
<description>
</description>
</method>
- <method name="int" >
+ <method name="int">
+ <return type="int">
+ </return>
<argument index="0" name="from" type="float">
</argument>
<description>
</description>
</method>
- <method name="int" >
+ <method name="int">
+ <return type="int">
+ </return>
<argument index="0" name="from" type="String">
</argument>
<description>
diff --git a/doc/core_classes.xml b/doc/core_classes.xml
deleted file mode 100644
index 02b46ac4b9..0000000000
--- a/doc/core_classes.xml
+++ /dev/null
@@ -1,2654 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<doc version="1.0" name="Core Types">
-<class category="Core" name="Vector3">
- <brief_description>
- Vector class, which performs basic 3D vector math operations.
- </brief_description>
- <description>
- Vector3 is one of the core classes of the engine, and includes several built-in helper functions to perform basic vecor math operations.
- </description>
- <methods>
- <method name="operator+">
- <argument index="0" name="b" type="Vector3">
- </argument>
- <return type="Vector3">
- Sum.
- </return>
- <description>
- Add two vectors.
- </description>
- </method>
- <method name="operator-">
- <argument index="0" name="b" type="Vector3">
- </argument>
- <return type="Vector3">
- Difference.
- </return>
- <description>
- Substract two vectors.
- </description>
- </method>
- <method name="operator/">
- <argument index="0" name="b" type="Vector3">
- </argument>
- <return type="Vector3">
- Quotient.
- </return>
- <description>
- Divide two vectors (component wise).
- </description>
- </method>
- <method name="operator*">
- <argument index="0" name="b" type="Vector3">
- </argument>
- <return type="Vector3">
- Product.
- </return>
- <description>
- Multiply two vectors (components wise).
- </description>
- </method>
- <method name="set_axis">
- <argument index="0" name="axis" type="int">
- Axis Index.
- </argument>
- <argument index="1" name="value" type="real">
- Value.
- </argument>
- <description>
- Set an individual axis (0 is X, 1 is Y and 2 is Z). the enum constants Vector.AXIS_X, Vector.AXIS_Y, and Vector.AXIS_Z, are also valid. This is specially useful for for-loops.
- </description>
- </method>
- <method name="get_axis">
- <argument index="0" name="axis" type="int">
- Axis Index.
- </argument>
- <return type="real">
- Value.
- </return>
- <description>
- Set an individual axis (0 is X, 1 is Y and 2 is Z). the enum constants Vector.AXIS_X, Vector.AXIS_Y, and Vector.AXIS_Z, are also valid. This is specially useful for for-loops.
- </description>
- </method>
- <method name="length">
- <return type="real">
- Length: sqrt(x^2+y^2+z^2)
- </return>
- <description>
- Return the length of the vector.
- </description>
- </method>
- <method name="length_squared">
- <return type="real">
- Squared Length: x^2+y^2+z^2.
- </return>
- <description>
- Return the length of the vector, without the square root step.
- </description>
- </method>
- <method name="normalize">
- <description>
- Normalize the vector to unit length. This is the same as v = v / v.length()
- </description>
- </method>
- <method name="normalized">
- <return type="Vector3">
- </return>
- <description>
- Return a copy of the normalized vector to unit length. This is the same as v / v.length()
- </description>
- </method>
- <method name="inverse">
- <return type="Vector3">
- Inverse: 1/v
- </return>
- <description>
- Returns the inverse of the vector. this is the same as Vector3( 1.0 / v.x, 1.0 / v.y, 1.0 / v.z )
- </description>
- </method>
- <method name="zero">
- <description>
- Set x,y and z to 0.
- </description>
- </method>
- <method name="snap">
- <argument index="0" name="snap" type="real">
- </argument>
- <description>
- Snap the vector in each axis the the lowest nearest multiple. ie: 4,5,7 snapped to 2 equals 4,4,6.
- </description>
- </method>
- <method name="snapped">
- <argument index="0" name="snap" type="real">
- </argument>
- <return type="Vector3">
- Snapped copy.
- </return>
- <description>
- Return a copy of the vector, snapped to the lowest neared multiple.
- </description>
- </method>
- <method name="linear_interpolate">
- <argument index="0" name="b" type="Vector3">
- </argument>
- <argument index="1" name="i" type="real">
- </argument>
- <return type="Vector3">
- </return>
- <description>
- Linearly interpolates the vector to a given one (b), by the given amount (i)
- </description>
- </method>
- <method name="cubic_interpolate">
- <argument index="0" name="a" type="Vector3">
- </argument>
- <argument index="1" name="c" type="Vector3">
- </argument>
- <argument index="2" name="d" type="Vector3">
- </argument>
- <argument index="3" name="i" type="real">
- </argument>
- <return type="Vector3">
- </return>
- <description>
- Perform a cubic interpolation between vectors a,b,c,d (b is current), by the given amount (i).
- </description>
- </method>
- <method name="cross">
- <argument index="0" name="b" type="Vector3">
- </argument>
- <return type="Vector3">
- Cross product.
- </return>
- <description>
- Return the cross product with b.
- </description>
- </method>
- <method name="dot">
- <argument index="0" name="b" type="Vector3">
- </argument>
- <return type="real">
- </return>
- <description>
- Return the dot product with b.
- </description>
- </method>
- <method name="distance_to">
- <argument index="0" name="b" type="Vector3">
- </argument>
- <return type="real">
- </return>
- <description>
- Return the distance to b.
- </description>
- </method>
- <method name="distance_squared_to">
- <argument index="0" name="b" type="Vector3">
- </argument>
- <return type="real">
- </return>
- <description>
- Return the squared distance (distance minus the last square root) to b.
- </description>
- </method>
- </methods>
- <constants>
- <constant name="AXIS_X" value="0">
- </constant>
- <constant name="AXIS_Y" value="1">
- </constant>
- <constant name="AXIS_Z" value="2">
- </constant>
- </constants>
- <members>
- <member name="x" type="real">
- </member>
- <member name="y" type="real">
- </member>
- <member name="z" type="real">
- </member>
- </members>
-</class>
-<class category="Core" name="AABB">
- <brief_description>
- Axis-Aligned-Bounding-Box.
- </brief_description>
- <description>
- AABB stands for "Axis Aligned Bounding Box". It consits of a position and a size, which for an box that is always aligned to the x, y and z axis, which goes from "pos" to "pos+size".
- </description>
- <methods>
- <method name="has_no_area">
- <return type="bool">
- </return>
- <description>
- Returns true if the AABB volume is empty (even if it has a surface). Holds true if size.x,y or z is 0.
- </description>
- </method>
- <method name="has_no_surface">
- <return type="bool">
- </return>
- <description>
- Return true if size is 0,0,0.
- </description>
- </method>
- <method name="area">
- <return type="real">
- </return>
- <description>
- Compute the volume of the AABB.
- </description>
- </method>
- <method name="intersects">
- <argument index="0" name="b" type="AABB">
- </argument>
- <return type="bool">
- </return>
- <description>
- Returns true if this AABB shares a portion of space with b.
- </description>
- </method>
- <method name="encloses">
- <argument index="0" name="b" type="AABB">
- </argument>
- <return type="bool">
- </return>
- <description>
- Returns true if this AABB completely encloses b.
- </description>
- </method>
- <method name="merge_with">
- <argument index="0" name="b" type="AABB">
- </argument>
- <description>
- Expand this AABB to also enclose the area of b.
- </description>
- </method>
- <method name="intersection_with">
- <argument index="0" name="b" type="AABB">
- </argument>
- <return type="AABB">
- </return>
- <description>
- Return the shared portion of space with b (empty if they don't intersect).
- </description>
- </method>
- <method name="intersects_segment">
- <argument index="0" name="a" type="Vector3">
- </argument>
- <argument index="1" name="b" type="Vector3">
- </argument>
- <argument index="2" name="@r" type="Vector3">
- result (if they intersect)
- </argument>
- <argument index="3" name="@n" type="Vector3">
- normal (if they intersect)
- </argument>
- <return type="bool">
- </return>
- <description>
- Returns true if this AABB intersects segment "a" towards "b". Also, return the point and normal of intersection.
- </description>
- </method>
- <method name="intersects_plane">
- <argument index="0" name="p" type="Plane">
- </argument>
- <return type="bool">
- </return>
- <description>
- Returns true if this AABB intersects the plane b.
- </description>
- </method>
- <method name="has_point">
- <argument index="0" name="p" type="Vector3">
- </argument>
- <return type="bool">
- </return>
- <description>
- Return true if this AABB contains point "p".
- </description>
- </method>
- <method name="get_longest_axis">
- <return type="Vector3">
- Axis direction
- </return>
- <description>
- Get the normal of the longest axis in this AABB.
- </description>
- </method>
- <method name="get_longest_axis_index">
- <return type="int">
- </return>
- <description>
- Get the index of the longest axis in this AABB.
- </description>
- </method>
- <method name="get_longest_axis_size">
- <return type="real">
- Get the length of the longest axis in this AABB.
- </return>
- <description>
- </description>
- </method>
- <method name="get_edge">
- <argument index="0" name="@ra" type="Vector3">
- </argument>
- <argument index="1" name="@rb" type="Vector3">
- </argument>
- <description>
- Get one of the edges (0 to 11) of this AABB in "ra" and "rb".
- </description>
- </method>
- <method name="grow_by">
- <argument index="0" name="s" type="real">
- </argument>
- <description>
- Grow this AABB, by expanding its margin, by "s".
- </description>
- </method>
- <method name="expand_to">
- <argument index="0" name="p" type="Vector3">
- </argument>
- <description>
- Expand this AABB to contain point "p".
- </description>
- </method>
- </methods>
- <members>
- <member name="pos" type="Vector3">
- Position of the AABB.
- </member>
- <member name="size" type="Vector3">
- Suze of the AABB (should always be positive).
- </member>
- </members>
-</class>
-<class category="Core" name="Plane">
- <brief_description>
- Plane in hessian form.
- </brief_description>
- <description>
- Plane represents a normalized plane equation. Basically, "normal" is the normal of the plane (a,b,c normalized), and "d" is the distance from the origin to the plane (in the direction of "normal"). "Over" or "Above" the plane is considered the side of the plane towards where the normal is pointing.
- </description>
- <methods>
- <method name="normalize">
- <description>
- Normalize the plane (although it will be often normalized already).
- </description>
- </method>
- <method name="normalized">
- <return type="Plane">
- </return>
- <description>
- Returns a copy of the plane, normalized.
- </description>
- </method>
- <method name="is_point_over">
- <argument index="0" name="p" type="Vector3">
- </argument>
- <return type="bool">
- </return>
- <description>
- Returns true if "p" is located above the plane.
- </description>
- </method>
- <method name="distance">
- <argument index="0" name="p" type="Vector3">
- </argument>
- <return type="real">
- </return>
- <description>
- Returns the orthogonal distance from "p" to the plane. If positive, "p" is above, if negative, "p" is below.
- </description>
- </method>
- <method name="has_point">
- <argument index="0" name="p" type="Vector3">
- </argument>
- <return type="bool">
- </return>
- <description>
- Returns true if "p" is inside the plane (by a very minimum treshold).
- </description>
- </method>
- <method name="intersect_3">
- <argument index="0" name="a" type="Plane">
- </argument>
- <argument index="1" name="b" type="Plane">
- </argument>
- <argument index="2" name="@r" type="Vector3">
- </argument>
- <return type="bool">
- </return>
- <description>
- Returns true if this plane intersects with planes "a" and "b". The resulting intersectin is placed in "r".
- </description>
- </method>
- <method name="intersects_ray">
- <argument index="0" name="p" type="Vector3">
- </argument>
- <argument index="1" name="d" type="Vector3">
- </argument>
- <argument index="2" name="@r" type="Vector3">
- </argument>
- <return type="bool">
- </return>
- <description>
- Returns true if ray consiting of position "p" and direction normal "d" intersects this plane. If true, the result is placed in "r".
- </description>
- </method>
- <method name="intersects_segment">
- <argument index="0" name="sa" type="Vector3">
- </argument>
- <argument index="1" name="sb" type="Vector3">
- </argument>
- <argument index="2" name="@r" type="Vector3">
- </argument>
- <return type="bool">
- </return>
- <description>
- Returns true if segment from position "sa" to position "sb" intersects this plane. If true, the result is placed in "r".
-
- </description>
- </method>
- <method name="project">
- <argument index="0" name="p" type="Vector3">
- </argument>
- <return type="Vector3">
- </return>
- <description>
- Returns the orthogonal projection of point "p" into a point in the plane.
- </description>
- </method>
- <method name="is_almost_like">
- <argument index="0" name="b" type="plane">
- </argument>
- <return type="bool">
- </return>
- <description>
- Returns true if plane "b" is very similar to this one.
- </description>
- </method>
- </methods>
- <members>
- <member name="normal" type="Vector3">
- Plane normal vector (a,c and d in the plane equation normalized).
- </member>
- <member name="d" type="real">
- Plane distance (d in the plane equation).
- </member>
- </members>
-</class>
-<class category="Core" name="Quat">
- <brief_description>
- Quaternion.
- </brief_description>
- <description>
- Quaternion is a 4 dimensional vector that is used to represet a rotation. It mainly exists to perform SLERP (spherical-linear interpolation) between to rotations obtained by a Matrix3 cheaply. Adding quaternions also cheaply adds the rotations, however quaternions need to be often normalized, or else they suffer from precision issues.
- </description>
- <methods>
- <method name="length">
- <return type="real">
- </return>
- <description>
- Returns the length of the quaternion.
- </description>
- </method>
- <method name="length_squared">
- <return type="real">
- </return>
- <description>
- Returns the length of the quaternion, minus the square root.
- </description>
- </method>
- <method name="normalize">
- <description>
- Normalize the quaternion to unit length.
- </description>
- </method>
- <method name="normalized">
- <return type="Quat">
- </return>
- <description>
- Returns a copy of the quaternion, normalized to unit length.
- </description>
- </method>
- <method name="inverse">
- <return type="Quat">
- </return>
- <description>
- Returns the inverse of the quaternion (applies to the inverse rotatio too).
- </description>
- </method>
- <method name="dot">
- <argument index="0" name="b" type="Quat">
- </argument>
- <return type="real">
- </return>
- <description>
- Returns the dot product between two quaternions.
- </description>
- </method>
- <method name="set_euler">
- <argument index="0" name="e" type="Vector3">
- </argument>
- <description>
- Create a quaternion from euler rotation "e", as yaw, pitch, roll.
- </description>
- </method>
- <method name="slerp">
- <argument index="0" name="b" type="Quat">
- </argument>
- <argument index="1" name="i" type="real">
- </argument>
- <return type="Quat">
- </return>
- <description>
- Perform a spherical-linear interpolation with another quaternion.
- </description>
- </method>
- <method name="operator*">
- <argument index="0" name="arg1" type="Quat">
- </argument>
- <return type="Quat">
- </return>
- <description>
- Peform multiplication between two quaternions.
- </description>
- </method>
- </methods>
- <members>
- <member name="x" type="real">
- x-axis
- </member>
- <member name="y" type="real">
- y-axis
- </member>
- <member name="z" type="real">
- z-axis
- </member>
- <member name="w" type="real">
- w-axis
- </member>
- </members>
-</class>
-<class category="Core" name="Matrix3">
- <brief_description>
- 3x3 Matrix.
- </brief_description>
- <description>
- </description>
- Matrix represent a 3x3 (3 rows by 3 columns) transformation matrix. it is used mainly to represent and accumulate transformations such as rotation or scale when used as an OCS (oriented coordinate system).
- <methods>
- <method name="invert">
- <description>
- Invert the matrix (transformations are reversed).
- </description>
- </method>
- <method name="transpose">
- <description>
- Transpose the matrix (transformations are reversed only for orthogonal matrices).
- </description>
- </method>
- <method name="inverse">
- <return type="Matrix3">
- </return>
- <description>
- Returns the inverse of the matrix.
- </description>
- </method>
- <method name="transposed">
- <return type="Matrix3">
- </return>
- <description>
- Returns the transposition of the matrix.
- </description>
- </method>
- <method name="rotate">
- <argument index="0" name="axis" type="Vector3">
- </argument>
- <argument index="1" name="phi" type="real">
- </argument>
- <description>
- Rotates the matrix in normalized "axis" by amount "phi" in radians. (This is equivalent to glRotate from OpenGL).
- </description>
- </method>
- <method name="scale">
- <argument index="0" name="s" type="Vector3">
- </argument>
- <description>
- Scale each axis of the rotated matrix by 's".
- </description>
- </method>
- <method name="get_scale">
- <return type="Vector3">
- </return>
- <description>
- Get the scale of the matrix.
- </description>
- </method>
- <method name="set_euler">
- <argument index="0" name="e" type="Vector3">
- </argument>
- <description>
- Create an orthogonal matrix from euler angles "e", as yaw, pitch, roll.
- </description>
- </method>
- <method name="get_euler">
- <return type="Vector3">
- </return>
- <description>
- Computes and returns the euler engles for an orthogonal matrix, as yaw, pitch, roll.
- </description>
- </method>
- <method name="tdotx">
- <argument index="0" name="v" type="Vector3">
- </argument>
- <return type="Vector3">
- </return>
- <description>
- Computes and returns a dot product with transposed axis x.
- </description>
- </method>
- <method name="tdoty">
- <argument index="0" name="v" type="Vector3">
- </argument>
- <return type="Vector3">
- </return>
- <description>
- Computes and returns a dot product with transposed axis y.
- </description>
- </method>
- <method name="tdotz">
- <argument index="0" name="arg1" type="Vector3">
- </argument>
- <return type="Vector3">
- </return>
- <description>
- Computes and returns a dot product with transposed axis z.
- </description>
- </method>
- <method name="xform">
- <argument index="0" name="v" type="Vector3">
- </argument>
- <return type="Vector3">
- </return>
- <description>
- Transforms vector "v" by this matrix (as M x V) and returns the result.
- </description>
- </method>
- <method name="xform_inv">
- <argument index="0" name="v" type="Vector3">
- </argument>
- <return type="Vector3">
- </return>
- <description>
- Inverse-transforms vector "v" by this matrix (as V x M) and returns the result.
- </description>
- </method>
- <method name="get_axis">
- <argument index="0" name="axis" type="int">
- </argument>
- <return type="Vector3">
- </return>
- <description>
- Get an axis of the OCS. (0 is X, 1 is Y and 2 is Z). The enum constants Vector.AXIS_X, Vector.AXIS_Y, and Vector.AXIS_Z, are also valid. This is equivalent to get_column().
- </description>
- </method>
- <method name="set_axis">
- <argument index="0" name="axis" type="int">
- </argument>
- <argument index="1" name="v" type="Vector3">
- </argument>
- <description>
- Set an axis of the OCS. (0 is X, 1 is Y and 2 is Z). The enum constants Vector.AXIS_X, Vector.AXIS_Y, and Vector.AXIS_Z, are also valid. This is equivalent to set_column()
- </description>
- </method>
- <method name="get_row">
- <argument index="0" name="i" type="int">
- </argument>
- <return type="Vector3">
- </return>
- <description>
- Get a matrix row.
- </description>
- </method>
- <method name="set_row">
- <argument index="0" name="i" type="int">
- </argument>
- <argument index="1" name="v" type="Vector3">
- </argument>
- <description>
- Set a matrix row.
- </description>
- </method>
- <method name="get_column">
- <argument index="0" name="axis" type="int">
- </argument>
- <return type="Vector3">
- </return>
- <description>
- Get a matrix column. This is equivalent to get_axis()
- </description>
- </method>
- <method name="set_column">
- <argument index="0" name="axis" type="int">
- </argument>
- <argument index="1" name="av" type="Vector3">
- </argument>
- Set a matrix column. This is equivalent to set_axis
- <description>
- </description>
- </method>
- <method name="operator*">
- <argument index="0" name="N" type="Matrix3">
- </argument>
- <return type="Matrix3">
- </return>
- <description>
- Perform a matrix multiplication (M x N) and return the result.
- </description>
- </method>
- <method name="transpose_xform">
- <argument index="0" name="arg1" type="Matrix3">
- </argument>
- <return type="Matrix3">
- </return>
- <description>
- Perform a transposed-matrix multiplication (Mt x N) and return the result.
- </description>
- </method>
- </methods>
- <members>
- <member name="xx" type="real">
- </member>
- <member name="xy" type="real">
- </member>
- <member name="xz" type="real">
- </member>
- <member name="yx" type="real">
- </member>
- <member name="yy" type="real">
- </member>
- <member name="yz" type="real">
- </member>
- <member name="zx" type="real">
- </member>
- <member name="zy" type="real">
- </member>
- <member name="zz" type="real">
- </member>
- </members>
-</class>
-<class category="Core" name="Transform">
- <brief_description>
- Transformation.
- </brief_description>
- <description>
- Transform is used to store transformations, including translations. It consists of a Matrix3 "basis" and Vector3 "origin". Transform is used to represent transformations of any object in space. It is similar to a 4x3 matrix.
- </description>
- <methods>
- <method name="invert">
- <description>
- Invert the transform.
- </description>
- </method>
-
- <method name="inverse">
- <return type="Transform">
- </return>
- <description>
- Returns the inverse of the transform.
- </description>
- </method>
- <method name="rotate">
- <argument index="0" name="axis" type="Vector3">
- </argument>
- <argument index="1" name="phi" type="real">
- </argument>
- <description>
- Rotates the transform in normalized "axis" by amount "phi" in radians. (This is equivalent to glRotate from OpenGL).
- </description>
- </method>
- <method name="scale">
- <argument index="0" name="s" type="Vector3">
- </argument>
- <description>
- Scales the whole transform by "s" (including the origin)
- </description>
- </method>
- <method name="get_basis">
- <return type="Matrix3">
- </return>
- <description>
- Get the basis.
- </description>
- </method>
- <method name="translate">
- <argument index="0" name="v" type="Vector3">
- </argument>
- <description>
- Translate the transform by "v".
- </description>
- </method>
- <method name="set_look_at">
- <argument index="0" name="eye" type="Vector3">
- "Eye" Position.
- </argument>
- <argument index="1" name="target" type="Vector3">
- "Target" Position.
- </argument>
- <argument index="2" name="up" type="Vector3">
- "Up" Normal Vector.
- </argument>
- <description>
- Creates a transform positioned at "eye", looking towards "target". "up" represents the direction where "up" is. This function is useful for setting up cameras.
- </description>
- </method>
- <method name="xform">
- <argument index="0" name="v" type="Vector3">
- </argument>
- <return type="Vector3">
- </return>
- <description>
- Transforms vector "v" by this transform.
- </description>
- </method>
- <method name="xform_inv">
- <argument index="0" name="arg1" type="Vector3">
- </argument>
- <return type="Vector3">
- </return>
- <description>
- Inverse-transforms vector "v" by this transform.
- </description>
- </method>
- <method name="xform_aabb">
- <argument index="0" name="a" type="AABB">
- </argument>
- <return type="AABB">
- </return>
- <description>
- Transforms AABB "a" by this transform. The resulting aabb will often be larger, so succesive transforms are not recommended.
- </description>
- </method>
- <method name="xform_aabb_inv">
- <argument index="0" name="a" type="AABB">
- </argument>
- <return type="AABB">
- </return>
- <description>
- Inverse-transforms AABB "a" by this transform. The resulting aabb will often be larger, so succesive transforms are not recommended.
- </description>
- </method>
- <method name="xform_plane">
- <argument index="0" name="p" type="Plane">
- </argument>
- <return type="Plane">
- </return>
- <description>
- Transform plane "p" by this transform.
- </description>
- </method>
- <method name="xform_plane_inv">
- <argument index="0" name="p" type="Plane">
- </argument>
- <return type="Plane">
- </return>
- <description>
- Inverse-transforms plane "p" by this transform.
- </description>
- </method>
- </methods>
- <members>
- <member name="basis" type="Matrix3">
- Transform "basis" or OCS.
- </member>
- <member name="origin" type="Vector3">
- Transform origin.
- </member>
- <member name="xx" type="real">
- </member>
- <member name="xy" type="real">
- </member>
- <member name="xz" type="real">
- </member>
- <member name="yx" type="real">
- </member>
- <member name="yy" type="real">
- </member>
- <member name="yz" type="real">
- </member>
- <member name="zx" type="real">
- </member>
- <member name="zy" type="real">
- </member>
- <member name="zz" type="real">
- </member>
- <member name="tx" type="real">
- </member>
- <member name="ty" type="real">
- </member>
- <member name="tz" type="real">
- </member>
-
- </members>
-</class>
-<class category="Core" name="Vector2">
- <brief_description>
- Vector used for 2D Math.
- </brief_description>
- <description>
- </description>
- Vector class, which performs basic 2D vector math operations.
- <methods>
- <method name="operator+">
- <argument index="0" name="b" type="Vector2">
- </argument>
- <return type="Vector2">
- </return>
- <description>
- Add two vectors.
- </description>
- </method>
- <method name="operator-">
- <argument index="0" name="b" type="Vector2">
- </argument>
- <return type="Vector2">
- </return>
- <description>
- Substract two vectors.
- </description>
- </method>
- <method name="operator/">
- <argument index="0" name="b" type="Vector2">
- </argument>
- <return type="Vector2">
- </return>
- <description>
- Divide two vectors.
- </description>
- </method>
- <method name="operator*">
- <argument index="0" name="b" type="Vector2">
- </argument>
- <return type="Vector2">
- </return>
- <description>
- Multiply two vectors.
- </description>
- </method>
- <method name="length">
- <return type="real">
- </return>
- <description>
- Returns the length of the vector.
- </description>
- </method>
- <method name="length_squared">
- <return type="real">
- </return>
- <description>
- Returns the squared length of the vector.
- </description>
- </method>
- <method name="normalize">
- <description>
- Normalizes the vector to unit length.
- </description>
- </method>
- <method name="normalized">
- <return type="Vector2">
- </return>
- <description>
- Returns a normalized vector to unit length.
- </description>
- </method>
- <method name="zero">
- <description>
- Sets x and y to 0.
- </description>
- </method>
- <method name="linear_interpolate">
- <argument index="0" name="b" type="Vector2">
- </argument>
- <argument index="1" name="i" type="real">
- </argument>
- <return type="Vector2">
- </return>
- <description>
- Returns the result of the linear interpolation between this vector and "b", by amount "i".
- </description>
- </method>
- <method name="dot">
- <argument index="0" name="b" type="Vector2">
- </argument>
- <return type="real">
- </return>
- <description>
- Returns the dot product with vector "b".
- </description>
- </method>
- <method name="distance_to">
- <argument index="0" name="b" type="Vector2">
- </argument>
- <return type="real">
- </return>
- <description>
- Returns the distance to vector "b".
- </description>
- </method>
- <method name="floor">
- <return type="Vector2">
- </return>
- <description>
- Remove the fractional part of x and y.
- </description>
- </method>
- </methods>
-
- <members>
- <member name="x" type="real">
- </member>
- <member name="y" type="real">
- </member>
-
- </members>
-</class>
-<class category="Core" name="Rect2">
- <brief_description>
- Positioned rectangle in 2D.
- </brief_description>
- <description>
- Rect2 represets a positioned rectangle of position "pos" and "size".
- </description>
- <methods>
- <method name="has_no_area">
- <return type="bool">
- </return>
- <description>
- Returns "true" if the rectangle has no area.
- </description>
- </method>
- <method name="has_point">
- <argument index="0" name="v" type="Vector2">
- </argument>
- <return type="bool">
- </return>
- <description>
- Returns true if v is contained within the rectangle.
- </description>
- </method>
- <method name="merge">
- <argument index="0" name="b" type="Rect2">
- </argument>
- <description>
- Extend the rectangle to enclose "b".
- </description>
- </method>
- <method name="clip">
- <argument index="0" name="b" type="Rect2">
- </argument>
- <return type="Rect2">
- </return>
- <description>
- Return the interection with rectangle "b"
- </description>
- </method>
- <method name="grow">
- <argument index="0" name="m" type="Vector2">
- </argument>
- <description>
- Extend the rectangle margin by "m".
- </description>
- </method>
- </methods>
- <members>
- <member name="pos" type="Vector2">
- Position of the rectangle.
- </member>
- <member name="size" type="Vector2">
- Size of the rectangle.
- </member>
- <member name="x" type="real">
- </member>
- <member name="y" type="real">
- </member>
- <member name="size_x" type="real">
- </member>
- <member name="size_y" type="real">
- </member>
- </members>
-</class>
-
-<class category="Core" name="Color">
- <brief_description>
- Color in RGBA format.
- </brief_description>
- <description>
- A color is represented as red, green and blue (r,g,b) components. Additionally, "a" represents the alpha component, often used for transparency.
- </description>
- <methods>
- <method name="to_32">
- <return type="real">
- </return>
- <description>
- Convert the color to a 32 its integer (each byte represets a RGBA).
- </description>
- </method>
- <method name="gray">
- <return type="real">
- </return>
- <description>
- Convert the color to gray.
- </description>
- </method>
- <method name="get_h">
- <return type="real">
- </return>
- <description>
- Compute the "hue" of the color.
- </description>
- </method>
- <method name="get_s">
- <return type="real">
- </return>
- <description>
- Compute the "saturation" of the color.
- </description>
- </method>
- <method name="get_v">
- <return type="real">
- </return>
- <description>
- Compute the "value" of the color.
- </description>
- </method>
- <method name="set_hsv">
- <argument index="0" name="h" type="real">
- </argument>
- <argument index="1" name="s" type="real">
- </argument>
- <argument index="2" name="v" type="real">
- </argument>
- <description>
- Set the color from the HSV format.
- </description>
- </method>
- <method name="invert">
- <description>
- Invert the color.
- </description>
- </method>
- <method name="contrast">
- <description>
- Contrast the color.
- </description>
- </method>
- <method name="interpolate">
- <argument index="0" name="c" type="Vector3">
- </argument>
- <argument index="1" name="i" type="real">
- (0 to 1)
- </argument>
- <description>
- Linearly blend with color "c", by amount "i".
- </description>
- </method>
- </methods>
- <members>
- <member name="r" type="real">
- Red.
- </member>
- <member name="g" type="real">
- Green.
- </member>
- <member name="b" type="real">
- Blue.
- </member>
- <member name="a" type="real">
- Alpha.
- </member>
- </members>
-</class>
-<class category="Core" name="Image">
- <brief_description>
- Two Dimensional Image.
- </brief_description>
- <description>
- Image represents a two-dimensional representation of an image, composed by a color per pixel.
- </description>
- <methods>
- <method name="get_width">
- <return type="real">
- </return>
- <description>
- Returns the width of the image (in pixels).
- </description>
- </method>
- <method name="get_height">
- <return type="real">
- </return>
- <description>
- Returns the height of the image (in pixels).
- </description>
- </method>
- <method name="get_pixel">
- <argument index="0" name="x" type="int">
- </argument>
- <argument index="1" name="y" type="int">
- </argument>
- <return type="Color">
- </return>
- <description>
- Get the color of the pixel at position (x,y).
- </description>
- </method>
- <method name="put_pixel">
- <argument index="0" name="x" type="int">
- </argument>
- <argument index="1" name="y" type="int">
- </argument>
- <argument index="2" name="color" type="Color">
- </argument>
- <description>
- Sets the color of the pixel at position (x,y).
- </description>
- </method>
- <method name="convert">
- <argument index="0" name="format" type="int">
- </argument>
- <description>
- Convert the image to a new format (valid values in the FORMAT_* enumeration).
- </description>
- </method>
- <method name="get_format">
- <return type="int">
- </return>
- <description>
- Get the image format (valid values in the FORMAT_* enumeration).
- </description>
- </method>
- <method name="resize">
- <argument index="0" name="width" type="int">
- </argument>
- <argument index="1" name="height" type="int">
- </argument>
- <description>
- Resize the image to a new pixel resolution given by width,height.
- </description>
- </method>
- <method name="crop">
- <argument index="0" name="width" type="int">
- </argument>
- <argument index="1" name="height" type="int">
- </argument>
- <description>
- Crop the image to a new pixel resolution given by width,height.
- </description>
- </method>
- <method name="flip_x">
- <description>
- Flip the X axis of the image.
- </description>
- </method>
- <method name="flip_y">
- <description>
- Flip the Y axis of the image.
- </description>
- </method>
- <method name="make_mipmap">
- <argument index="0" name="source" type="Image">
- </argument>
- <description>
- Create a mipmap from "source" image.
- </description>
- </method>
- <method name="make_normalmap">
- <argument index="0" name="height_scale" type="real">
- </argument>
- <description>
- Create a normalmap from "height_scale" image.
- </description>
- </method>
- <method name="create">
- <argument index="0" name="width" type="int">
- </argument>
- <argument index="1" name="height" type="int">
- </argument>
- <argument index="2" name="format" type="int">
- </argument>
- <description>
- Create a new image of size width, height and format.
- </description>
- </method>
- <method name="import">
- <argument index="0" name="width" type="int">
- </argument>
- <argument index="1" name="height" type="int">
- </argument>
- <argument index="2" name="format" type="int">
- </argument>
- <argument index="3" name="data" type="RawArray">
- </argument>
- <description>
- Import an image from raw data, given a specific format.
- </description>
- </method>
- <method name="empty">
- <return type="bool">
- </return>
- <description>
- Returns true if the image is empty.
- </description>
- </method>
- <method name="load">
- <argument index="0" name="path" type="String">
- </argument>
- <return type="Error">
- </return>
- <description>
- Load an image from a file in "path".
- </description>
- </method>
- </methods>
- <constants>
- <constant name="FORMAT_GRAYSCALE" value="0">
- </constant>
- <constant name="FORMAT_INTENSITY" value="1">
- </constant>
- <constant name="FORMAT_GRAYSCALE_ALPHA" value="2">
- </constant>
- <constant name="FORMAT_RGB" value="3">
- </constant>
- <constant name="FORMAT_RGBA" value="4">
- </constant>
- <constant name="FORMAT_INDEXED" value="5">
- </constant>
- <constant name="FORMAT_INDEXED_ALPHA" value="6">
- </constant>
- </constants>
-</class>
-<class category="Core" name="RID">
- <brief_description>
- Resource ID.
- </brief_description>
- <description>
- RID references a resource, typically created in a server.
- </description>
- <methods>
- <method name="is_valid">
- <return type="bool">
- </return>
- <description>
- Returns true if the resource is valid.
- </description>
- </method>
- </methods>
-</class>
-<class category="Core" name="InputEvent">
- <brief_description>
- A struct containing information fron an input device.
- </brief_description>
- <description>
- A struct containing information fron an input event, such as mouse, keyboard, joystick, etc. Valid event types are:<br></br>
- <list>
- <li> InputEvent.NONE </li>
- <li> InputEvent.KEY </li>
- <li> InputEvent.MOUSE_BUTTON </li>
- <li> InputEvent.MOUSE_MOTION </li>
- <li> InputEvent.JOYSTICK_MOTION </li>
- <li> InputEvent.JOYSTICK_BUTTON </li>
- </list>
-
- </description>
- <members>
- <member name="ID" type="int">
- Event ID. Every event as a unique ID.
- </member>
- <member name="type" type="int">
- Event type (check description).
- </member>
- <member name="device" type="int">
- Device that originated the event.
- </member>
- <member name="mouse_x" type="int">
- Mouse x position (for mouse events).
- </member>
- <member name="mouse_y" type="int">
- Mouse y position (for mouse events).
- </member>
- <member name="mouse_button_mask" type="int">
- State of the mouse buttons as a bitmask (for key and mouse events)
- </member>
- <member name="mouse_global_x" type="int">
- Global mouse x position (used in GUI Controls).
- </member>
- <member name="mouse_global_y" type="int">
- Global mouse y position (used in GUI Controls).
- </member>
- <member name="mouse_pressed" type="bool">
- if MOUSE_BUTTON was a press, this value is true.
- </member>
- <member name="mouse_doubleclick" type="bool">
- if MOUSE_BUTTON was a doubleclick, this value is true.
- </member>
- <member name="mouse_button_index" type="int">
- Index of the clicked button (mouse button event).
- </member>
- <member name="mouse_motion_x" type="int">
- Relative x motion of the mouse (mouse motion event).
- </member>
- <member name="mouse_motion_y" type="int">
- Relative y motion of the mouse (mouse motion event).
- </member>
- <member name="mod_alt" type="bool">
- If ALT modifier is pressed, this is true (mouse and key events).
- </member>
- <member name="mod_shift" type="bool">
- If SHIFT modifier is pressed, this is true (mouse and key events).
- </member>
- <member name="mod_control" type="bool">
- If CONTROL modifier is pressed, this is true (mouse and key events).
- </member>
- <member name="mod_meta" type="bool">
- If META modifier (win/apple/etc keys) is pressed, this is true (mouse and key events).
- </member>
- <member name="key_pressed" type="bool">
- if a KEY event originated from a keypress, this is true.
- </member>
- <member name="key_echo" type="bool">
- if a KEY event originated from an echo key, this is true.
- </member>
- <member name="key_unicode" type="int">
- Unicode value of a key pressed (key event).
- </member>
- <member name="key_scancode" type="Key">
- Scancode of a key pressed (check the KEY_* enumeration) (key event).
- </member>
- <member name="joy_button_index" type="int">
- Joystick button index (joy button event).
- </member>
- <member name="joy_button_pressed" type="bool">
- If joystick button was pressed, this is true (joy button event).
- </member>
- <member name="joy_button_index" type="int">
- Index of the pressed/released joystick button.
- </member>
- <member name="joy_axis" type="int">
- Axis of a joystick (joy axis event).
- </member>
- <member name="joy_axis_value" type="real">
- Axis value a joystick, from -1 to 1 (joy axis event).
- </member>
- </members>
- <constants>
- <constant name="NONE" value="0">
- Empty input event.
- </constant>
- <constant name="KEY" value="1">
- Key pressed/released event.
- </constant>
- <constant name="MOUSE_BUTTON" value="2">
- Mouse button pressed/released event.
- </constant>
- <constant name="JOYSTICK_MOTION" value="3">
- Joystick axis motion event.
- </constant>
- <constant name="JOYSTICK_BUTTON" value="4">
- Joystick button press/release event.
- </constant>
- </constants>
-
-</class>
-<class category="Core" name="FileAccess">
- <brief_description>
- File Access Interface.
- </brief_description>
- <description>
- FileAccess provides access to files in the host platform (remote access to files in webserver in the web plugin, as web plugin does not access the local filesystem).
- </description>
- <methods>
- <method name="open">
- <argument index="0" name="path" type="String">
- Path to a file
- </argument>
- <argument index="1" name="mode" type="int">
- Open mode: FileAccess.READ, FileAccess.WRITE or FileAccess.READ_WRITE
- </argument>
- <return type="Error">
- Error value (check the ERR_ macro for the meaning of the values)
- </return>
- <description>
- Open a file in a given path. Error is returned if the file can't be opened, is nt found, etc.
- </description>
- </method>
- <method name="close">
- <description>
- Closes a currently open file.
- </description>
- </method>
- <method name="is_open">
- <return type="bool">
- </return>
- <description>
- Returns true if a file is currently open.
- </description>
- </method>
- <method name="seek">
- <argument index="0" name="pos" type="int">
- </argument>
- <description>
- Seek to a given position (in bytes) in the file.
- </description>
- </method>
- <method name="seek_end">
- <argument index="0" name="pos" type="int">
- </argument>
- <description>
- Seek to a given position (in bytes) in the file, from the end of the file.
- </description>
- </method>
- <method name="get_pos">
- <return type="int">
- </return>
- <description>
- Get the current position in the file.
- </description>
- </method>
- <method name="get_len">
- <return type="int">
- </return>
- <description>
- Get the open file size (in bytes).
- </description>
- </method>
- <method name="eof_reached">
- <return type="bool">
- </return>
- <description>
- Returns true if EOF was reached (read past end of file).
- </description>
- </method>
- <method name="get_8">
- <return type="int">
- </return>
- <description>
- Read a byte from the file.
- </description>
- </method>
- <method name="get_16">
- <return type="int">
- </return>
- <description>
- Read a 16-bits unsigned integer from the file, in little/big endian format.
- </description>
- </method>
- <method name="get_32">
- <return type="int">
- </return>
- <description>
- Read a 32-bits unsigned integer from the file, in little/big endian format.
- </description>
- </method>
- <method name="set_endian_swap">
- <argument index="0" name="swap" type="bool">
- </argument>
- <description>
- Change the endian mode for reading sizes larger than a byte (read big endian files).
- </description>
- </method>
- <method name="get_endian_swap">
- <return type="bool">
- </return>
- <description>
- Return the status of the endian swap.
- </description>
- </method>
- <method name="store_8">
- <argument index="0" name="byte" type="int">
- </argument>
- <description>
- Store a byte in the file.
- </description>
- </method>
- <method name="store_16">
- <argument index="0" name="word" type="int">
- </argument>
- <description>
- Store a 16-bits integer in the file.
- </description>
- </method>
- <method name="store_32">
- <argument index="0" name="dword" type="int">
- </argument>
- <description>
- Store a 32 bits integer in the file.
- </description>
- </method>
- <method name="file_exists">
- <argument index="0" name="path" type="String">
- </argument>
- <return type="bool">
- </return>
- <description>
- Returns true if a given file (in path) exist.
- </description>
- </method>
- </methods>
- <constants>
- <constant name="READ" value="1">
- </constant>
- <constant name="WRITE" value="2">
- </constant>
- <constant name="READ_WRITE" value="4">
- </constant>
-
- </constants>
-</class>
-<class category="Core" name="Dir">
- <brief_description>
- Directory Tree Access Interface.
- </brief_description>
- <description>
- Dir provides access to directories in the host platform (remote access to files in webserver in the web plugin, as web plugin does not access the local filesystem).
- </description>
- <methods>
- <method name="list_dir_begin">
- <return type="bool">
- true if an error ocurred.
- </return>
- <description>
- Begin a directory listing. This is done iteratively due to the positility of directories with a large amount of entries.
- </description>
- </method>
- <method name="get_next">
- <return type="String">
- </return>
- <description>
- Get the next item. If the return value is empty (""), then the end of the directory has been reached.
- </description>
- </method>
- <method name="current_is_dir">
- <return type="bool">
- </return>
- <description>
- Returns true if the current item is a directory (not a file).
- </description>
- </method>
- <method name="list_dir_end">
- <description>
- End the directory listing.
- </description>
- </method>
- <method name="get_drive_count">
- <return type="int">
- </return>
- <description>
- Get the amount of drives (windows only, returns 0 on other platforms).
- </description>
- </method>
- <method name="get_drive">
- <argument index="0" name="di" type="int">
- </argument>
- <return type="String">
- </return>
- <description>
- Get the string (or character) representing the drive (such as "C","D",etc).
- </description>
- </method>
- <method name="change_dir">
- <argument index="0" name="dir" type="String">
- </argument>
- <return type="bool">
- </return>
- <description>
- Change the current directory of the dir access. "dir" can be either absolute or relative.
- </description>
- </method>
- <method name="get_current_dir">
- <return type="String">
- </return>
- <description>
- Get the full path of the current dir.
- </description>
- </method>
- <method name="get_dir_separator">
- <return type="String">
- </return>
- <description>
- Get the string or character most commonly used as drive separator in the host OS.
- </description>
- </method>
- <method name="make_dir">
- <argument index="0" name="name" type="String">
- </argument>
- <return type="bool">
- true on error.
- </return>
- <description>
- Create a new directory. "name" can be either absolute or relative.
- </description>
- </method>
- <method name="file_exists">
- <argument index="0" name="path" type="String">
- </argument>
- <return type="bool">
- </return>
- <description>
- Returns true if a file exist. "path" can be either absolute or relative.
- </description>
- </method>
- <method name="get_space_left">
- <return type="int">
- </return>
- <description>
- Return the space left on the device, in kilobytes.
- </description>
- </method>
- </methods>
-</class>
-<class category="Core" name="VideoMode">
- <brief_description>
- Video Mode structure.
- </brief_description>
- <description>
- Describes a video mode.
- </description>
- <members>
- <member name="width" type="int">
- </member>
- <member name="height" type="int">
- </member>
- <member name="fullscreen" type="bool">
- "true" if the video mode is full scren.
- </member>
- <member name="resizable" type="bool">
- "true" if the video mode can be resized to another video mode.
- </member>
- </members>
-</class>
-<class category="Core" name="Date">
- <brief_description>
- Date structure.
- </brief_description>
- <description>
- Describes a date.
- </description>
- <members>
- <member name="year" type="int">
- year (integer)
- </member>
- <member name="day" type="int">
- day of the year
- </member>
- <member name="weekday" type="int">
- day of the week (0 to 6)
- </member>
- <member name="month" type="int">
- month of the year (0 to 11)
- </member>
- <member name="dst" type="bool">
- "true" if daylight savings is enabled.
- </member>
- </members>
-</class>
-<class category="Core" name="Time">
- <brief_description>
- Current Time.
- </brief_description>
- <description>
- Describes the current time.
- </description>
- <members>
- <member name="hour" type="int">
- (0 to 11)
- </member>
- <member name="min" type="int">
- (0 to 59)
- </member>
- <member name="sec" type="int">
- (0 to 59)
- </member>
- </members>
-</class>
-<class category="Core" name="OS">
- <brief_description>
- Operating System common functions.
- </brief_description>
- <description>
- OS provides access to common host OS functions. "OS" Must not be instanced. All members are static (called like OS.get_name() ).
- </description>
- <methods>
- <method name="alert">
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- Produce an alert. On OSs such as windows or mac, this may result in a popup dialog.
- </description>
- </method>
- <method name="set_mouse_show">
- <argument index="0" name="show" type="bool">
- </argument>
- <description>
- Determine the hardware cursor visibility (if available).
- </description>
- </method>
- <method name="set_mouse_grab">
- <argument index="0" name="grab" type="bool">
- </argument>
- <description>
- Capture the hardware cursor (if available).
- </description>
- </method>
- <method name="is_mouse_grab_enabled">
- <return type="bool">
- </return>
- <description>
- Returns true if the application is capturing the hardware cursor.
- </description>
- </method>
- <method name="get_name">
- <return type="String">
- </return>
- <description>
- Get the name of the host OS or Platform.
- </description>
- </method>
- <method name="set_video_mode">
- <argument index="0" name="mode" type="VideoMode">
- </argument>
- <description>
- Change the current videomode (if available).
- </description>
- </method>
- <method name="get_video_mode">
- <return type="VideoMode">
- </return>
- <description>
- Get the current videomode.
- </description>
- </method>
- <method name="get_date">
- <return type="Date">
- </return>
- <description>
- Get the current date.
- </description>
- </method>
- <method name="get_time">
- <return type="Time">
- </return>
- <description>
- Get the current time.
- </description>
- </method>
- <method name="get_ticks_msec">
- <return type="int">
- </return>
- <description>
- Get the amount of milliseconds since the app started.
- </description>
- </method>
- <method name="delay_usec">
- <argument index="0" name="usec" type="int">
- </argument>
- <description>
- Suspend the calling thread for "usec" milliseconds
- </description>
- </method>
- </methods>
-</class>
-<class category="Core" name="Math">
- <brief_description>
- Common math functions.
- </brief_description>
- <description>
- Math provides implementations of commonly used math functions."Math" shouldt not be instanced since all members are static (called like Math.cos() ).
- </description>
- <methods>
- <method name="sin">
- <argument index="0" name="rad" type="real">
- </argument>
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="cos">
- <argument index="0" name="rad" type="real">
- </argument>
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="tan">
- <argument index="0" name="rad" type="real">
- </argument>
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="asin">
- <argument index="0" name="s" type="real">
- </argument>
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="acos">
- <argument index="0" name="s" type="real">
- </argument>
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="atan2">
- <argument index="0" name="x" type="real">
- </argument>
- <argument index="1" name="y" type="real">
- </argument>
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="deg2rad">
- <argument index="0" name="deg" type="real">
- </argument>
- <return type="real">
- </return>
- <description>
- Degrees to Radians conversion.
- </description>
- </method>
- <method name="sqrt">
- <argument index="0" name="s" type="real">
- </argument>
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="pow">
- <argument index="0" name="base" type="real">
- </argument>
- <argument index="1" name="power" type="real">
- </argument>
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="exp">
- <argument index="0" name="s" type="real">
- </argument>
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="log">
- <argument index="0" name="s" type="real">
- </argument>
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="fmod">
- <argument index="0" name="x" type="real">
- </argument>
- <argument index="1" name="y" type="real">
- </argument>
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="stepify">
- <argument index="0" name="x" type="real">
- </argument>
- <argument index="1" name="step" type="real">
- </argument>
- <return type="real">
- </return>
- <description>
- Round to nearest (lowest) value in given step.
- </description>
- </method>
- <method name="floor">
- <argument index="0" name="s" type="real">
- </argument>
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="round">
- <argument index="0" name="s" type="real">
- </argument>
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="decimals">
- <argument index="0" name="s" type="real">
- </argument>
- <return type="int">
- </return>
- <description>
- Returns the amount of decimals used by "s".
- </description>
- </method>
- <method name="randf">
- <return type="real">
- </return>
- <description>
- Returns a random number fro 0 to 1
- </description>
- </method>
- <method name="random">
- <argument index="0" name="min" type="real">
- </argument>
- <argument index="1" name="max" type="real">
- </argument>
- <return type="real">
- </return>
- <description>
- Returns a random number between "min" and "max"
- </description>
- </method>
- </methods>
- <constants>
- <constant name="PI" value="3.14159265358979323846">
- </constant>
- </constants>
-
-</class>
-<class category="Core" name="Shell">
- <brief_description>
- Shell Execution interface.
- </brief_description>
- <description>
- Shell allows the application to open a given URL in the host OS. It can be anything the host OS understands, from a web page to a media file.
- </description>
- <methods>
- <method name="exec">
- <argument index="0" name="url" type="String">
- </argument>
- <description>
- Open any URL the host OS understands.
- </description>
- </method>
- </methods>
-</class>
-<class category="Core" name="ResourceLoader">
- <brief_description>
- Resource Loader.
- </brief_description>
- <description>
- ResourceLoader loads resources from disk and returns a resource object.
- </description>
- <methods>
- <method name="load">
- <argument index="0" name="path" type="String">
- </argument>
- <return type="Resource">
- null on failure.
- </return>
- <description>
- Open a resource in the given path.
- </description>
- </method>
- </methods>
-</class>
-<class category="Core" name="SceneLoader">
- <brief_description>
- Scene Loader
- </brief_description>
- <description>
- SceneLoader loads scenes from disk and returns a scene node.
- </description>
- <methods>
- <method name="load">
- <argument index="0" name="path" type="String">
- </argument>
- <return type="Node">
- A scene node, null on error.
- </return>
- <description>
- Load a scene from disk at given "path" and return a node object.
- </description>
- </method>
- </methods>
-</class>
-<class category="Core" name="Object">
- <brief_description>
- Base class for the Object Model.
- </brief_description>
- <description>
- Object is the building block of most of the high level engine interfaces. The "Object" interface contains a reference to an actual internal Object.
- Usually, Object memory should not be managed by the API, as resources will be fred automatically when not in use and nodes are deleted by their parent nodes.
- </description>
- <methods>
- <method name="free">
- <description>
- Free the Object reference. This should not be used with nodes inside a scene tree, as they are removed by their parent node. This function can also be used to unreference resources.
- </description>
- </method>
- <method name="get_type">
- <return type="String">
- </return>
- <description>
- Get a string with the type name of the object.
- </description>
- </method>
- <method name="has_instance">
- <return type="bool">
- </return>
- <description>
- Returns true if the Object datatype contains a reference to an actual object instance.
- </description>
- </method>
- <method name="get_instance_ID">
- <return type="bool">
- </return>
- <description>
- Return the instance ID of the object. Every Object has a unique instance ID.
- </description>
- </method>
- <method name="is_type" qualifiers="const" >
- <return type="bool" >
- </return>
- <argument index="0" name="type" type="String" >
- </argument>
- <description>
- Return true if the type of the object class (or any base clases) match "type.
- </description>
- </method>
- <method name="set" >
- <argument index="0" name="property" type="String" >
- </argument>
- <argument index="1" name="value" type="var" >
- </argument>
- <description>
- Set a property "property", with any value "value. This function can be inherited with "_set" (but base class "_set" will still be called).
- </description>
- </method>
- <method name="get" qualifiers="const" >
- <return type="var" >
- </return>
- <argument index="0" name="property" type="String" >
- </argument>
- <description>
- Return a property "property". This function can be inherited with "_get" (but base class "_get" will still be called).
- </description>
- </method>
- <method name="notification" >
- <argument index="0" name="what" type="int" >
- </argument>
- <argument index="1" name="reverse" type="bool" default="false" >
- </argument>
- <description>
- Perform a notification. Notifications are quick ways to tell an Object that something happened or changed regarding it's state and surroundings. This function can be inherited with "_notification" (but base class "_notification" will still be called).
- </description>
- </method>
- <method name="set_script" >
- <argument index="0" name="script" type="RefPtr" >
- </argument>
- <description>
- Set the script of the object. Any object can contain a script. Scripts behave as if they inherited the object they are set to
- </description>
- </method>
- <method name="get_script" qualifiers="const" >
- <return type="RefPtr" >
- </return>
- <description>
- Return the script of the object. Any object can contain a script. Scripts behave as if they inherited the object they are set to
- </description>
- </method>
- <method name="set_meta" >
- <argument index="0" name="name" type="String" >
- </argument>
- <description>
- Set a meta property. Meta properties are just containers for setting and retrieving any custom data to an object. Metaproperties are also saved with the object.
- </description>
- </method>
- <method name="get_meta" qualifiers="const" >
- <argument index="0" name="name" type="String" >
- </argument>
- <description>
- Return a meta property. Meta properties are just containers for setting and retrieving any custom data to an object. Metaproperties are also saved with the object.
- </description>
- </method>
- <method name="has_meta" qualifiers="const" >
- <return type="bool" >
- </return>
- <argument index="0" name="name" type="String" >
- </argument>
- <description>
- Return wether an object has a meta property. Meta properties are just containers for setting and retrieving any custom data to an object. Metaproperties are also saved with the object.
- </description>
- </method>
- <method name="get_meta_list" qualifiers="const" >
- <return type="StringArray" >
- </return>
- <description>
- Return the list of meta properties in the object. Meta properties are just containers for setting and retrieving any custom data to an object. Metaproperties are also saved with the object.
- </description>
- </method>
- <method name="call" >
- <argument index="0" name="method" type="String" >
- </argument>
- <description>
- Call any method in the object (syntax: call("method", .. arguments..).
- </description>
- </method>
- </methods>
- <constants>
- <constant name="NOTIFICATION_POSTINITIALIZE" value="0">
- This notification is called right after the object is done initializing
- </constant>
- <constant name="NOTIFICATION_PREDELETE" value="1">
- This notification is called right before the object will e deleted.
- </constant>
- </constants>
-</class>
-<class category="Core" name="Key">
- <brief_description>
- All Symbolic Key Names
- </brief_description>
- <description>
- Key is an enumaration containing the constants for all the symbolic key names. They are used directly (not with Key. prefix). This value is used in the "scancode" field of the "KEY" InputEvent.
- </description>
- <constants>
- <constant name="SPKEY">Special Key Mask</constant>
- <constant name="KEY_ESCAPE"></constant>
- <constant name="KEY_TAB"></constant>
- <constant name="KEY_BACKTAB"></constant>
- <constant name="KEY_BACKSPACE"></constant>
- <constant name="KEY_RETURN"></constant>
- <constant name="KEY_ENTER"></constant>
- <constant name="KEY_INSERT"></constant>
- <constant name="KEY_DELETE"></constant>
- <constant name="KEY_PAUSE"></constant>
- <constant name="KEY_PRINT"></constant>
- <constant name="KEY_SYSREQ"></constant>
- <constant name="KEY_CLEAR"></constant>
- <constant name="KEY_HOME"></constant>
- <constant name="KEY_END"></constant>
- <constant name="KEY_LEFT"></constant>
- <constant name="KEY_UP"></constant>
- <constant name="KEY_RIGHT"></constant>
- <constant name="KEY_DOWN"></constant>
- <constant name="KEY_PAGEUP"></constant>
- <constant name="KEY_PAGEDOWN"></constant>
- <constant name="KEY_SHIFT"></constant>
- <constant name="KEY_CONTROL"></constant>
- <constant name="KEY_META"></constant>
- <constant name="KEY_ALT"></constant>
- <constant name="KEY_CAPSLOCK"></constant>
- <constant name="KEY_NUMLOCK"></constant>
- <constant name="KEY_SCROLLLOCK"></constant>
- <constant name="KEY_F1"></constant>
- <constant name="KEY_F2"></constant>
- <constant name="KEY_F3"></constant>
- <constant name="KEY_F4"></constant>
- <constant name="KEY_F5"></constant>
- <constant name="KEY_F6"></constant>
- <constant name="KEY_F7"></constant>
- <constant name="KEY_F8"></constant>
- <constant name="KEY_F9"></constant>
- <constant name="KEY_F10"></constant>
- <constant name="KEY_F11"></constant>
- <constant name="KEY_F12"></constant>
- <constant name="KEY_F13"></constant>
- <constant name="KEY_F14"></constant>
- <constant name="KEY_F15"></constant>
- <constant name="KEY_F16"></constant>
- <constant name="KEY_KP_ENTER"></constant>
- <constant name="KEY_KP_MULTIPLY"></constant>
- <constant name="KEY_KP_DIVIDE"></constant>
- <constant name="KEY_KP_SUBSTRACT"></constant>
- <constant name="KEY_KP_PERIOD"></constant>
- <constant name="KEY_KP_ADD"></constant>
- <constant name="KEY_KP_0"></constant>
- <constant name="KEY_KP_1"></constant>
- <constant name="KEY_KP_2"></constant>
- <constant name="KEY_KP_3"></constant>
- <constant name="KEY_KP_4"></constant>
- <constant name="KEY_KP_5"></constant>
- <constant name="KEY_KP_6"></constant>
- <constant name="KEY_KP_7"></constant>
- <constant name="KEY_KP_8"></constant>
- <constant name="KEY_KP_9"></constant>
- <constant name="KEY_SUPER_L"></constant>
- <constant name="KEY_SUPER_R"></constant>
- <constant name="KEY_MENU"></constant>
- <constant name="KEY_HYPER_L"></constant>
- <constant name="KEY_HYPER_R"></constant>
- <constant name="KEY_HELP"></constant>
- <constant name="KEY_DIRECTION_L"></constant>
- <constant name="KEY_DIRECTION_R"></constant>
- <constant name="KEY_BACK"></constant>
- <constant name="KEY_FORWARD"></constant>
- <constant name="KEY_STOP"></constant>
- <constant name="KEY_REFRESH"></constant>
- <constant name="KEY_VOLUMEDOWN"></constant>
- <constant name="KEY_VOLUMEMUTE"></constant>
- <constant name="KEY_VOLUMEUP"></constant>
- <constant name="KEY_BASSBOOST"></constant>
- <constant name="KEY_BASSUP"></constant>
- <constant name="KEY_BASSDOWN"></constant>
- <constant name="KEY_TREBLEUP"></constant>
- <constant name="KEY_TREBLEDOWN"></constant>
- <constant name="KEY_MEDIAPLAY"></constant>
- <constant name="KEY_MEDIASTOP"></constant>
- <constant name="KEY_MEDIAPREVIOUS"></constant>
- <constant name="KEY_MEDIANEXT"></constant>
- <constant name="KEY_MEDIARECORD"></constant>
- <constant name="KEY_HOMEPAGE"></constant>
- <constant name="KEY_FAVORITES"></constant>
- <constant name="KEY_SEARCH"></constant>
- <constant name="KEY_STANDBY"></constant>
- <constant name="KEY_OPENURL"></constant>
- <constant name="KEY_LAUNCHMAIL"></constant>
- <constant name="KEY_LAUNCHMEDIA"></constant>
- <constant name="KEY_LAUNCH0"></constant>
- <constant name="KEY_LAUNCH1"></constant>
- <constant name="KEY_LAUNCH2"></constant>
- <constant name="KEY_LAUNCH3"></constant>
- <constant name="KEY_LAUNCH4"></constant>
- <constant name="KEY_LAUNCH5"></constant>
- <constant name="KEY_LAUNCH6"></constant>
- <constant name="KEY_LAUNCH7"></constant>
- <constant name="KEY_LAUNCH8"></constant>
- <constant name="KEY_LAUNCH9"></constant>
- <constant name="KEY_LAUNCHA"></constant>
- <constant name="KEY_LAUNCHB"></constant>
- <constant name="KEY_LAUNCHC"></constant>
- <constant name="KEY_LAUNCHD"></constant>
- <constant name="KEY_LAUNCHE"></constant>
- <constant name="KEY_LAUNCHF"></constant>
-
- <constant name="KEY_UNKNOWN"></constant>
- <constant name="KEY_SPACE"></constant>
- <constant name="KEY_EXCLAM"></constant>
- <constant name="KEY_QUOTEDBL"></constant>
- <constant name="KEY_NUMBERSIGN"></constant>
- <constant name="KEY_DOLLAR"></constant>
- <constant name="KEY_PERCENT"></constant>
- <constant name="KEY_AMPERSAND"></constant>
- <constant name="KEY_APOSTROPHE"></constant>
- <constant name="KEY_PARENLEFT"></constant>
- <constant name="KEY_PARENRIGHT"></constant>
- <constant name="KEY_ASTERISK"></constant>
- <constant name="KEY_PLUS"></constant>
- <constant name="KEY_COMMA"></constant>
- <constant name="KEY_MINUS"></constant>
- <constant name="KEY_PERIOD"></constant>
- <constant name="KEY_SLASH"></constant>
- <constant name="KEY_0"></constant>
- <constant name="KEY_1"></constant>
- <constant name="KEY_2"></constant>
- <constant name="KEY_3"></constant>
- <constant name="KEY_4"></constant>
- <constant name="KEY_5"></constant>
- <constant name="KEY_6"></constant>
- <constant name="KEY_7"></constant>
- <constant name="KEY_8"></constant>
- <constant name="KEY_9"></constant>
- <constant name="KEY_COLON"></constant>
- <constant name="KEY_SEMICOLON"></constant>
- <constant name="KEY_LESS"></constant>
- <constant name="KEY_EQUAL"></constant>
- <constant name="KEY_GREATER"></constant>
- <constant name="KEY_QUESTION"></constant>
- <constant name="KEY_AT"></constant>
- <constant name="KEY_A"></constant>
- <constant name="KEY_B"></constant>
- <constant name="KEY_C"></constant>
- <constant name="KEY_D"></constant>
- <constant name="KEY_E"></constant>
- <constant name="KEY_F"></constant>
- <constant name="KEY_G"></constant>
- <constant name="KEY_H"></constant>
- <constant name="KEY_I"></constant>
- <constant name="KEY_J"></constant>
- <constant name="KEY_K"></constant>
- <constant name="KEY_L"></constant>
- <constant name="KEY_M"></constant>
- <constant name="KEY_N"></constant>
- <constant name="KEY_O"></constant>
- <constant name="KEY_P"></constant>
- <constant name="KEY_Q"></constant>
- <constant name="KEY_R"></constant>
- <constant name="KEY_S"></constant>
- <constant name="KEY_T"></constant>
- <constant name="KEY_U"></constant>
- <constant name="KEY_V"></constant>
- <constant name="KEY_W"></constant>
- <constant name="KEY_X"></constant>
- <constant name="KEY_Y"></constant>
- <constant name="KEY_Z"></constant>
- <constant name="KEY_BRACKETLEFT"></constant>
- <constant name="KEY_BACKSLASH"></constant>
- <constant name="KEY_BRACKETRIGHT"></constant>
- <constant name="KEY_ASCIICIRCUM"></constant>
- <constant name="KEY_UNDERSCORE"></constant>
- <constant name="KEY_QUOTELEFT"></constant>
- <constant name="KEY_BRACELEFT"></constant>
- <constant name="KEY_BAR"></constant>
- <constant name="KEY_BRACERIGHT"></constant>
- <constant name="KEY_ASCIITILDE"></constant>
- <constant name="KEY_NOBREAKSPACE"></constant>
- <constant name="KEY_EXCLAMDOWN"></constant>
- <constant name="KEY_CENT"></constant>
- <constant name="KEY_STERLING"></constant>
- <constant name="KEY_CURRENCY"></constant>
- <constant name="KEY_YEN"></constant>
- <constant name="KEY_BROKENBAR"></constant>
- <constant name="KEY_SECTION"></constant>
- <constant name="KEY_DIAERESIS"></constant>
- <constant name="KEY_COPYRIGHT"></constant>
- <constant name="KEY_ORDFEMININE"></constant>
- <constant name="KEY_GUILLEMOTLEFT"></constant>
- <constant name="KEY_NOTSIGN"></constant>
- <constant name="KEY_HYPHEN"></constant>
- <constant name="KEY_REGISTERED"></constant>
- <constant name="KEY_MACRON"></constant>
- <constant name="KEY_DEGREE"></constant>
- <constant name="KEY_PLUSMINUS"></constant>
- <constant name="KEY_TWOSUPERIOR"></constant>
- <constant name="KEY_THREESUPERIOR"></constant>
- <constant name="KEY_ACUTE"></constant>
- <constant name="KEY_MU"></constant>
- <constant name="KEY_PARAGRAPH"></constant>
- <constant name="KEY_PERIODCENTERED"></constant>
- <constant name="KEY_CEDILLA"></constant>
- <constant name="KEY_ONESUPERIOR"></constant>
- <constant name="KEY_MASCULINE"></constant>
- <constant name="KEY_GUILLEMOTRIGHT"></constant>
- <constant name="KEY_ONEQUARTER"></constant>
- <constant name="KEY_ONEHALF"></constant>
- <constant name="KEY_THREEQUARTERS"></constant>
- <constant name="KEY_QUESTIONDOWN"></constant>
- <constant name="KEY_AGRAVE"></constant>
- <constant name="KEY_AACUTE"></constant>
- <constant name="KEY_ACIRCUMFLEX"></constant>
- <constant name="KEY_ATILDE"></constant>
- <constant name="KEY_ADIAERESIS"></constant>
- <constant name="KEY_ARING"></constant>
- <constant name="KEY_AE"></constant>
- <constant name="KEY_CCEDILLA"></constant>
- <constant name="KEY_EGRAVE"></constant>
- <constant name="KEY_EACUTE"></constant>
- <constant name="KEY_ECIRCUMFLEX"></constant>
- <constant name="KEY_EDIAERESIS"></constant>
- <constant name="KEY_IGRAVE"></constant>
- <constant name="KEY_IACUTE"></constant>
- <constant name="KEY_ICIRCUMFLEX"></constant>
- <constant name="KEY_IDIAERESIS"></constant>
- <constant name="KEY_ETH"></constant>
- <constant name="KEY_NTILDE"></constant>
- <constant name="KEY_OGRAVE"></constant>
- <constant name="KEY_OACUTE"></constant>
- <constant name="KEY_OCIRCUMFLEX"></constant>
- <constant name="KEY_OTILDE"></constant>
- <constant name="KEY_ODIAERESIS"></constant>
- <constant name="KEY_MULTIPLY"></constant>
- <constant name="KEY_OOBLIQUE"></constant>
- <constant name="KEY_UGRAVE"></constant>
- <constant name="KEY_UACUTE"></constant>
- <constant name="KEY_UCIRCUMFLEX"></constant>
- <constant name="KEY_UDIAERESIS"></constant>
- <constant name="KEY_YACUTE"></constant>
- <constant name="KEY_THORN"></constant>
- <constant name="KEY_SSHARP"></constant>
-
- <constant name="KEY_DIVISION"></constant>
- <constant name="KEY_YDIAERESIS"></constant>
-
- <constant name="KEY_CODE_MASK"></constant>
- <constant name="KEY_MODIFIER_MASK"></constant>
-
- <constant name="KEY_MASK_SHIFT"></constant>
- <constant name="KEY_MASK_ALT"></constant>
- <constant name="KEY_MASK_META"></constant>
- <constant name="KEY_MASK_CTRL"></constant>
- <constant name="KEY_MASK_KPAD"></constant>
- <constant name="KEY_MASK_GROUP_SWITCH"></constant>
-
- </constants>
-</class>
-<class category="Core" name="PropertyHint">
- <brief_description>
- Property Hints.
- </brief_description>
- <description>
- PropertyHint hints editors on how to edit a property. In many cases, hint_string (in the PropertyInfo) will contain extra data. These constants are used globally ("PropertyHint" class doesn't exist").
- </description>
- <constants>
- <constant name="PROPERTY_HINT_NONE"></constant>
- <constant name="PROPERTY_HINT_RANGE">Hint_string defined as "min,max,step
- "</constant>
- <constant name="PROPERTY_HINT_ENUM">Values such as 0,1,2 are represented in hint_string as "A,B,C"</constant>
- <constant name="PROPERTY_HINT_LENGTH">hint_string is the length of an array type.</constant>
- <constant name="PROPERTY_HINT_FLAGS">Flags names are in hint_string from MSB to LSB as "flag8,fla7,flag6,,,,flag1"</constant>
- <constant name="PROPERTY_HINT_PATH">Property is a path.</constant>
- <constant name="PROPERTY_HINT_FILE">Property is a path to a file.</constant>
- <constant name="PROPERTY_HINT_DIR">Property is a path to a dir.</constant>
- <constant name="PROPERTY_HINT_RESOURCE_TYPE">hint_string contains the valid resource types the property accept (separated by ",").</constant>
- </constants>
-</class>
-<class category="Core" name="PropertyUsage">
- <brief_description>
- Usage for an object property.
- </brief_description>
- <description>
- PropertyUsage defines a list of (inclusive) usages that can be ORed together to specify how the property will be treated in different scenarios. These constants are used globally ("PropertyUsage" class doesn't exist").
- </description>
- <constants>
- <constant name="PROPERTY_USAGE_STORAGE"> Property is Saved/Loaded from disk.</constant>
- <constant name="PROPERTY_USAGE_EDITOR">Property is visible in editor (for editing).</constant>
- <constant name="PROPERTY_USAGE_NETWORK">Property can be syncronized on network.</constant>
- <constant name="PROPERTY_USAGE_DEFAULT">Default usage.</constant>
- </constants>
-</class>
-<class category="Core" name="Type">
- <brief_description>
- Valid Data Types.
- </brief_description>
- <description>
- Type consists of a list of valid types. It is usually used for property type hinting. These constants are used globally ("Type" class doesn't exist").
- </description>
- <constants>
- <constant name="TYPE_NIL"></constant>
- <constant name="TYPE_BOOL"></constant>
- <constant name="TYPE_INT"></constant>
- <constant name="TYPE_REAL"></constant>
- <constant name="TYPE_STRING"></constant>
- <constant name="TYPE_VECTOR2"></constant>
- <constant name="TYPE_RECT2"></constant>
- <constant name="TYPE_VECTOR3"></constant>
- <constant name="TYPE_PLANE"></constant>
- <constant name="TYPE_QUAT"></constant>
- <constant name="TYPE_AABB"></constant>
- <constant name="TYPE_MATRIX3"></constant>
- <constant name="TYPE_TRANSFORM"></constant>
- <constant name="TYPE_COLOR"></constant>
- <constant name="TYPE_IMAGE"></constant>
- <constant name="TYPE_NODE_PATH"></constant>
- <constant name="TYPE_RESOURCE"></constant>
- <constant name="TYPE_RID"></constant>
- <constant name="TYPE_OBJECT"></constant>
- <constant name="TYPE_INPUT_EVENT"></constant>
- <constant name="TYPE_DICTIONARY"></constant>
- <constant name="TYPE_ARRAY"></constant>
- <constant name="TYPE_RAW_ARRAY"></constant>
- <constant name="TYPE_INT_ARRAY"></constant>
- <constant name="TYPE_REAL_ARRAY"></constant>
- <constant name="TYPE_STRING_ARRAY"></constant>
- <constant name="TYPE_VECTOR3_ARRAY"></constant>
- <constant name="TYPE_COLOR_ARRAY"></constant>
- </constants>
-</class>
-
-
-<class category="Core" name="Error">
- <brief_description>
- List of generic errors.
- </brief_description>
- <description>
- Error is a list of generic errors
- </description>
- <constants>
- <constant name="OK"></constant>
- <constant name="FAILED"> Generic fail error</constant>
- <constant name="ERR_UNAVAILABLE"> What is requested is unsupported/unavailable</constant>
- <constant name="ERR_UNCONFIGURED"> The object being used hasnt been properly set up yet</constant>
- <constant name="ERR_UNAUTHORIZED"> Missing credentials for requested resource</constant>
- <constant name="ERR_PARAMETER_RANGE_ERROR"> Parameter given out of range</constant>
- <constant name="ERR_OUT_OF_MEMORY"> Out of memory</constant>
- <constant name="ERR_FILE_NOT_FOUND"></constant>
- <constant name="ERR_FILE_BAD_DRIVE"></constant>
- <constant name="ERR_FILE_BAD_PATH"></constant>
- <constant name="ERR_FILE_NO_PERMISSION"></constant>
- <constant name="ERR_FILE_ALREADY_IN_USE"></constant>
- <constant name="ERR_FILE_CANT_OPEN"></constant>
- <constant name="ERR_FILE_CANT_WRITE"></constant>
- <constant name="ERR_FILE_CANT_READ"></constant>
- <constant name="ERR_FILE_UNRECOGNIZED"></constant>
- <constant name="ERR_FILE_CORRUPT"></constant>
- <constant name="ERR_FILE_EOF"></constant>
- <constant name="ERR_CANT_OPEN"> Can't open a resource/socket/file</constant>
- <constant name="ERR_CANT_CREATE"></constant>
- <constant name="ERROR_QUERY_FAILED"></constant>
- <constant name="ERR_ALREADY_IN_USE"></constant>
- <constant name="ERR_LOCKED"> resource is locked</constant>
- <constant name="ERR_TIMEOUT"></constant>
- <constant name="ERR_CANT_AQUIRE_RESOURCE"></constant>
- <constant name="ERR_INVALID_DATA"> Data passed is invalid</constant>
- <constant name="ERR_INVALID_PARAMETER"> Parameter passed is invalid</constant>
- <constant name="ERR_ALREADY_EXISTS"> When adding"> item already exists</constant>
- <constant name="ERR_DOES_NOT_EXIST"> When retrieving/erasing"> it item does not exist</constant>
- <constant name="ERR_DATABASE_CANT_READ"> database is full</constant>
- <constant name="ERR_DATABASE_CANT_WRITE"> database is full</constant>
- <constant name="ERR_COMPILATION_FAILED"></constant>
- <constant name="ERR_METHOD_NOT_FOUND"></constant>
- <constant name="ERR_LINK_FAILED"></constant>
- <constant name="ERR_SCRIPT_FAILED"></constant>
- <constant name="ERR_CYCLIC_LINK"></constant>
- <constant name="ERR_BUSY"></constant>
- <constant name="ERR_HELP"> user requested help!!</constant>
- <constant name="ERR_BUG"> a bug in the software certainly happeneddue to a double check failing or unexpected behavior.</constant>
- <constant name="ERR_WTF "> an impossible to trigger check due to paranoid programmer was triggered</constant>
- </constants>
-</class>
-</doc>
-
-
diff --git a/doc/deferred_format.txt b/doc/deferred_format.txt
deleted file mode 100644
index 76a158a3ce..0000000000
--- a/doc/deferred_format.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-deferred:
-
-ar ag ab gl - accumulation RGB + glow
-
-nx ny mx my? - normal, motion
-dr dg db sm - diffuse, shademodel
-sr sg sb sp - specular OR shadeparams
-
-ar ag ab gl
-nx ny sp sp
-dr dg db se
-444 6
-se can be 6 bits, 2 for shade model
-
-shade models:
-
-0 - none
-1 - wrap
-2 - toon
-3 - fresne
-
-
-
-sp: 2 bits what - 6 bits param
-
-16
-
-
-
-
-
-
-
diff --git a/doc/demos.txt b/doc/demos.txt
deleted file mode 100644
index cf56a5cbc6..0000000000
--- a/doc/demos.txt
+++ /dev/null
@@ -1,40 +0,0 @@
--Oceano
--Portales
--Grilla
--Personaje
--Auto (?)
--Fisica
--Fisica Idle
--Low level APIS (Server)
--Sonido Posicional
--Custom Shaders
--HDR
--Trees Waving
--luces
--fixed material
--shader material
--synctoaudio speech and speex
--particulas con gif animados para mostrar que es cada parametro
--soporte de syntax hilight de gdscript para editores mas comunes
--instanciar enemigos usando duplicate
--simulated motion con animacion
--animation player controla otro animation player (tipo camina de lugar a otro y saluda)
--corutinas y loops con yield para animation, audio, etc
--CCD (bullets)
-
--custom gizmos, editor plugins en script
-
-Clases que necesitan tutorial.
-
-Animation/AnimationPlayer
-Area2D (space override, notifications)
-custom container demo
-custon drawing in a canvas item
-ignore mouse on top of button
-input in a game, with _unhandled_input
-demo containers
-Control, anchors e input event handling
-lots of 2D physics examples
-dictionary and array doc of passing by reference?
-
-
diff --git a/doc/engine_classes.xml b/doc/engine_classes.xml
deleted file mode 100644
index fca2be0318..0000000000
--- a/doc/engine_classes.xml
+++ /dev/null
@@ -1,17936 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<doc version="0.99.2555-pre-beta" name="Engine Types">
-<class name="AcceptDialog" inherits="WindowDialog" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="get_ok" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="get_label" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="set_hide_on_ok" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_hide_on_ok" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="add_button" >
- <return type="Button">
- </return>
- <argument index="0" name="text" type="String" default="&quot;&quot;">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_cancel" >
- <return type="Button">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="register_text_enter" >
- <argument index="0" name="line_edit" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_text" >
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_text" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="confirmed">
- <description>
- </description>
- </signal>
- <signal name="custom_action">
- <argument index="0" name="action" type="String">
- </argument>
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="Animation" inherits="Resource" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="add_track" >
- <return type="int">
- </return>
- <argument index="0" name="type" type="int">
- </argument>
- <argument index="1" name="at_pos" type="int" default="-1">
- </argument>
- <description>
- </description>
- </method>
- <method name="remove_track" >
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_track_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="track_get_type" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="track_get_path" qualifiers="const" >
- <return type="NodePath">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="track_set_path" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="path" type="NodePath">
- </argument>
- <description>
- </description>
- </method>
- <method name="track_move_up" >
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="track_move_down" >
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="transform_track_insert_key" >
- <return type="int">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="time" type="real">
- </argument>
- <argument index="2" name="loc" type="Vector3">
- </argument>
- <argument index="3" name="rot" type="Quat">
- </argument>
- <argument index="4" name="scale" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="track_insert_key" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="time" type="real">
- </argument>
- <argument index="2" name="key" type="var">
- </argument>
- <argument index="3" name="transition" type="real" default="1">
- </argument>
- <description>
- </description>
- </method>
- <method name="track_remove_key" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="key_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="track_remove_key_at_pos" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="pos" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="track_set_key_value" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="key" type="int">
- </argument>
- <argument index="2" name="value" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="track_set_key_transition" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="key_idx" type="int">
- </argument>
- <argument index="2" name="transition" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="track_get_key_transition" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="key_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="track_get_key_count" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="track_get_key_value" qualifiers="const" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="key_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="track_get_key_time" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="key_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="track_find_key" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="time" type="real">
- </argument>
- <argument index="2" name="exact" type="bool" default="false">
- </argument>
- <description>
- </description>
- </method>
- <method name="track_set_interpolation_type" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="interpolation" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="track_get_interpolation_type" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="transform_track_interpolate" qualifiers="const" >
- <return type="Array">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="time_sec" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="value_track_set_continuous" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="continuous" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="value_track_is_continuous" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="value_track_get_key_indices" qualifiers="const" >
- <return type="IntArray">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="time_sec" type="real">
- </argument>
- <argument index="2" name="delta" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="method_track_get_key_indices" qualifiers="const" >
- <return type="IntArray">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="time_sec" type="real">
- </argument>
- <argument index="2" name="delta" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="method_track_get_name" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="key_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="method_track_get_params" qualifiers="const" >
- <return type="Array">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="key_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_length" >
- <argument index="0" name="time_sec" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_length" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_loop" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_loop" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="clear" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="TYPE_TRANSFORM" value="0">
- </constant>
- <constant name="TYPE_VALUE" value="1">
- </constant>
- <constant name="TYPE_METHOD" value="2">
- </constant>
- <constant name="INTERPOLATION_NEAREST" value="0">
- </constant>
- <constant name="INTERPOLATION_LINEAR" value="1">
- </constant>
- <constant name="INTERPOLATION_CUBIC" value="2">
- </constant>
- </constants>
-</class>
-<class name="AnimationPlayer" inherits="Node" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="add_animation" >
- <return type="int">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="animation" type="Animation">
- </argument>
- <description>
- </description>
- </method>
- <method name="remove_animation" >
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="rename_animation" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="newname" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_animation" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_animation" qualifiers="const" >
- <return type="Animation">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_animation_list" qualifiers="const" >
- <return type="StringArray">
- </return>
- <description>
- </description>
- </method>
- <method name="set_blend_time" >
- <argument index="0" name="anim_from" type="String">
- </argument>
- <argument index="1" name="anim_to" type="String">
- </argument>
- <argument index="2" name="sec" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_blend_time" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="anim_from" type="String">
- </argument>
- <argument index="1" name="anim_to" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="play" >
- <argument index="0" name="name" type="String" default="&quot;&quot;">
- </argument>
- <description>
- </description>
- </method>
- <method name="stop" >
- <description>
- </description>
- </method>
- <method name="stop_all" >
- <description>
- </description>
- </method>
- <method name="is_playing" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_current_animation" >
- <argument index="0" name="anim" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_current_animation" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="queue" >
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_pause" >
- <argument index="0" name="paused" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_paused" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_speed" >
- <argument index="0" name="speed" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_speed" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_autoplay" >
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_autoplay" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="seek" >
- <argument index="0" name="pos_sec" type="real">
- </argument>
- <argument index="1" name="update" type="bool" default="false">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_pos" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="find_animation" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="animation" type="Animation">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear_caches" >
- <description>
- </description>
- </method>
- <method name="set_animation_process_mode" >
- <argument index="0" name="mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_animation_process_mode" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="finished">
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- <constant name="ANIMATION_PROCESS_FIXED" value="0">
- </constant>
- <constant name="ANIMATION_PROCESS_IDLE" value="1">
- </constant>
- </constants>
-</class>
-<class name="AnimationTreePlayer" inherits="Node" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="add_node" >
- <argument index="0" name="type" type="int">
- </argument>
- <argument index="1" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_node_id" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="node_set_name" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="node_get_name" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="node_get_type" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="node_get_input_count" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="animation_node_set_animation" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="animation" type="Animation">
- </argument>
- <description>
- </description>
- </method>
- <method name="animation_node_get_animation" qualifiers="const" >
- <return type="Animation">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="oneshot_node_set_fadein_time" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="time_sec" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="oneshot_node_get_fadein_time" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="oneshot_node_set_fadeout_time" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="time_sec" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="oneshot_node_get_fadeout_time" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="oneshot_node_set_autorestart" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="oneshot_node_set_autorestart_delay" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="delay_sec" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="oneshot_node_set_autorestart_random_delay" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="rand_sec" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="oneshot_node_has_autorestart" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="oneshot_node_get_autorestart_delay" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="oneshot_node_get_autorestart_random_delay" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="oneshot_node_start" >
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="oneshot_node_stop" >
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="oneshot_node_is_active" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="mix_node_set_amount" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="ratio" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="mix_node_get_amount" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="blend2_node_set_amount" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="blend" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="blend2_node_get_amount" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="blend3_node_set_amount" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="blend" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="blend3_node_get_amount" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="blend4_node_set_amount" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="blend" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="blend4_node_get_amount" qualifiers="const" >
- <return type="Vector2">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="timescale_node_set_scale" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="scale" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="timescale_node_get_scale" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="timeseek_node_seek" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="pos_sec" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="transition_node_set_input_count" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="count" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="transition_node_get_input_count" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="transition_node_delete_input" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="input_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="transition_node_set_input_auto_advance" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="input_idx" type="int">
- </argument>
- <argument index="2" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="transition_node_has_input_auto_advance" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="input_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="transition_node_set_xfade_time" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="time_sec" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="transition_node_get_xfade_time" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="transition_node_set_current" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="input_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="transition_node_get_current" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="node_set_pos" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="screen_pos" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="node_get_pos" qualifiers="const" >
- <return type="Vector2">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="remove_node" >
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="connect" >
- <return type="int">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="dst_id" type="int">
- </argument>
- <argument index="2" name="dst_input_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_connected" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="dst_id" type="int">
- </argument>
- <argument index="2" name="dst_input_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="disconnect" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="dst_input_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_active" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_active" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_base_path" >
- <argument index="0" name="path" type="NodePath">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_base_path" qualifiers="const" >
- <return type="NodePath">
- </return>
- <description>
- </description>
- </method>
- <method name="get_node_list" >
- <return type="IntArray">
- </return>
- <description>
- </description>
- </method>
- <method name="reset" >
- <description>
- </description>
- </method>
- <method name="recompute_caches" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="NODE_OUTPUT" value="0">
- </constant>
- <constant name="NODE_ANIMATION" value="1">
- </constant>
- <constant name="NODE_ONESHOT" value="2">
- </constant>
- <constant name="NODE_MIX" value="3">
- </constant>
- <constant name="NODE_BLEND2" value="4">
- </constant>
- <constant name="NODE_BLEND3" value="5">
- </constant>
- <constant name="NODE_BLEND4" value="6">
- </constant>
- <constant name="NODE_TIMESCALE" value="7">
- </constant>
- <constant name="NODE_TIMESEEK" value="8">
- </constant>
- <constant name="NODE_TRANSITION" value="9">
- </constant>
- </constants>
-</class>
-<class name="Area2D" inherits="CollisionObject2D" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_override_space_params" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_overriding_space_params" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_gravity_is_point" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_gravity_a_point" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_gravity_vector" >
- <argument index="0" name="vector" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_gravity_vector" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="set_gravity" >
- <argument index="0" name="gravity" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_gravity" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_density" >
- <argument index="0" name="density" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_density" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_priority" >
- <argument index="0" name="priority" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_priority" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_enable_monitoring" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_monitoring_enabled" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="body_enter">
- <argument index="0" name="body_id" type="int">
- </argument>
- <argument index="1" name="body" type="Object">
- </argument>
- <description>
- </description>
- </signal>
- <signal name="body_enter_shape">
- <argument index="0" name="body_id" type="int">
- </argument>
- <argument index="1" name="body" type="Object">
- </argument>
- <argument index="2" name="body_shape" type="int">
- </argument>
- <argument index="3" name="area_shape" type="int">
- </argument>
- <description>
- </description>
- </signal>
- <signal name="body_exit">
- <argument index="0" name="body_id" type="int">
- </argument>
- <argument index="1" name="body" type="Object">
- </argument>
- <description>
- </description>
- </signal>
- <signal name="body_exit_shape">
- <argument index="0" name="body_id" type="int">
- </argument>
- <argument index="1" name="body" type="Object">
- </argument>
- <argument index="2" name="body_shape" type="int">
- </argument>
- <argument index="3" name="area_shape" type="int">
- </argument>
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="AudioServer" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="sample_create" >
- <return type="RID">
- </return>
- <argument index="0" name="format" type="int">
- </argument>
- <argument index="1" name="stereo" type="bool">
- </argument>
- <argument index="2" name="length" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_set_description" >
- <argument index="0" name="sample" type="RID">
- </argument>
- <argument index="1" name="description" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_get_description" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="sample" type="RID">
- </argument>
- <argument index="1" name="arg1" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_get_format" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="sample" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_is_stereo" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="sample" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_get_length" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="sample" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_set_signed_data" >
- <argument index="0" name="sample" type="RID">
- </argument>
- <argument index="1" name="data" type="RealArray">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_set_data" >
- <argument index="0" name="sample" type="RID">
- </argument>
- <argument index="1" name="arg1" type="RawArray">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_get_data" qualifiers="const" >
- <return type="RawArray">
- </return>
- <argument index="0" name="sample" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_set_mix_rate" >
- <argument index="0" name="sample" type="RID">
- </argument>
- <argument index="1" name="mix_rate" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_get_mix_rate" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="sample" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_set_loop_format" >
- <argument index="0" name="sample" type="RID">
- </argument>
- <argument index="1" name="loop_format" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_get_loop_format" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="sample" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_set_loop_begin" >
- <argument index="0" name="sample" type="RID">
- </argument>
- <argument index="1" name="pos" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_get_loop_begin" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="sample" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_set_loop_end" >
- <argument index="0" name="sample" type="RID">
- </argument>
- <argument index="1" name="pos" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_get_loop_end" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="sample" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="voice_play" >
- <argument index="0" name="voice" type="RID">
- </argument>
- <argument index="1" name="sample" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_set_volume" >
- <argument index="0" name="voice" type="RID">
- </argument>
- <argument index="1" name="volume" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_set_pan" >
- <argument index="0" name="voice" type="RID">
- </argument>
- <argument index="1" name="pan" type="real">
- </argument>
- <argument index="2" name="depth" type="real" default="0">
- </argument>
- <argument index="3" name="height" type="real" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_set_filter" >
- <argument index="0" name="voice" type="RID">
- </argument>
- <argument index="1" name="type" type="int">
- </argument>
- <argument index="2" name="cutoff" type="real">
- </argument>
- <argument index="3" name="resonance" type="real">
- </argument>
- <argument index="4" name="gain" type="real" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_set_chorus" >
- <argument index="0" name="voice" type="RID">
- </argument>
- <argument index="1" name="chorus" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_set_reverb" >
- <argument index="0" name="voice" type="RID">
- </argument>
- <argument index="1" name="room" type="int">
- </argument>
- <argument index="2" name="reverb" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_set_mix_rate" >
- <argument index="0" name="voice" type="RID">
- </argument>
- <argument index="1" name="rate" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_set_positional" >
- <argument index="0" name="voice" type="RID">
- </argument>
- <argument index="1" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_get_volume" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_get_pan" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_get_pan_height" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_get_pan_depth" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_get_filter_type" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="voice" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_get_filter_cutoff" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_get_filter_resonance" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_get_chorus" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_get_reverb_type" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="voice" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_get_reverb" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_get_mix_rate" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="voice" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_is_positional" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="voice" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_stop" >
- <argument index="0" name="voice" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="free" >
- <argument index="0" name="rid" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_stream_global_volume_scale" >
- <argument index="0" name="scale" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_stream_global_volume_scale" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_mixer_global_volume_scale" >
- <argument index="0" name="scale" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_mixer_global_volume_scale" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="SAMPLE_FORMAT_PCM8" value="0">
- </constant>
- <constant name="SAMPLE_FORMAT_PCM16" value="1">
- </constant>
- <constant name="SAMPLE_FORMAT_IMA_ADPCM" value="2">
- </constant>
- <constant name="SAMPLE_LOOP_NONE" value="0">
- </constant>
- <constant name="SAMPLE_LOOP_FORWARD" value="1">
- </constant>
- <constant name="SAMPLE_LOOP_PING_PONG" value="2">
- </constant>
- <constant name="FILTER_NONE" value="0">
- </constant>
- <constant name="FILTER_LOWPASS" value="1">
- </constant>
- <constant name="FILTER_BANDPASS" value="2">
- </constant>
- <constant name="FILTER_HIPASS" value="3">
- </constant>
- <constant name="FILTER_NOTCH" value="4">
- </constant>
- <constant name="FILTER_BANDLIMIT" value="6">
- </constant>
- <constant name="REVERB_SMALL" value="0">
- </constant>
- <constant name="REVERB_MEDIUM" value="1">
- </constant>
- <constant name="REVERB_LARGE" value="2">
- </constant>
- <constant name="REVERB_HALL" value="3">
- </constant>
- </constants>
-</class>
-<class name="AudioServerSW" inherits="AudioServer" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="AudioStream" inherits="Resource" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="play" >
- <description>
- </description>
- </method>
- <method name="stop" >
- <description>
- </description>
- </method>
- <method name="is_playing" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_loop" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_loop" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_stream_name" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="get_loop_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="seek_pos" >
- <argument index="0" name="pos" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_pos" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_length" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_update_mode" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="update" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="UPDATE_NONE" value="0">
- </constant>
- <constant name="UPDATE_IDLE" value="1">
- </constant>
- <constant name="UPDATE_THREAD" value="2">
- </constant>
- </constants>
-</class>
-<class name="AudioStreamGibberish" inherits="AudioStream" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_phonemes" >
- <argument index="0" name="phonemes" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_phonemes" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="set_pitch_scale" >
- <argument index="0" name="pitch_scale" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_pitch_scale" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_pitch_random_scale" >
- <argument index="0" name="pitch_random_scale" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_pitch_random_scale" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_xfade_time" >
- <argument index="0" name="sec" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_xfade_time" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="AudioStreamMPC" inherits="AudioStreamResampled" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_file" >
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_file" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="AudioStreamOGGVorbis" inherits="AudioStreamResampled" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="AudioStreamResampled" inherits="AudioStream" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="AudioStreamSpeex" inherits="AudioStreamResampled" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_file" >
- <argument index="0" name="file" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_file" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="BCSFX" inherits="ScenarioFX" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="BGColorFX" inherits="ScenarioFX" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="BGImageFX" inherits="ScenarioFX" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="BaseButton" inherits="Control" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_pressed" >
- <argument index="0" name="pressed" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_pressed" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_toggle_mode" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_toggle_mode" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_disabled" >
- <argument index="0" name="disabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_disabled" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_click_on_press" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_click_on_press" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="toggled">
- <argument index="0" name="pressed" type="bool">
- </argument>
- <description>
- </description>
- </signal>
- <signal name="pressed">
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="BodyShape" inherits="Spatial" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="BoxContainer" inherits="Container" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="BoxShape" inherits="Shape" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_extents" >
- <argument index="0" name="extents" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_extents" qualifiers="const" >
- <return type="Vector3">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Button" inherits="BaseButton" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_text" >
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_text" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="set_icon" >
- <argument index="0" name="texture" type="Texture">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_icon" qualifiers="const" >
- <return type="Texture">
- </return>
- <description>
- </description>
- </method>
- <method name="set_flat" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_clip_text" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_clip_text" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="is_flat" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="ButtonArray" inherits="Control" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="add_button" >
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_icon_button" >
- <argument index="0" name="icon" type="Object">
- </argument>
- <argument index="1" name="text" type="String" default="&quot;&quot;">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_button_text" >
- <argument index="0" name="button" type="int">
- </argument>
- <argument index="1" name="text" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_button_icon" >
- <argument index="0" name="button" type="int">
- </argument>
- <argument index="1" name="icon" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_button_text" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="button" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_button_icon" qualifiers="const" >
- <return type="Object">
- </return>
- <argument index="0" name="button" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_button_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_selected" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_hovered" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_selected" >
- <argument index="0" name="button" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="erase_button" >
- <argument index="0" name="button" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear" >
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="button_selected">
- <argument index="0" name="button" type="int">
- </argument>
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- <constant name="ALIGN_BEGIN" value="0">
- </constant>
- <constant name="ALIGN_CENTER" value="1">
- </constant>
- <constant name="ALIGN_END" value="2">
- </constant>
- <constant name="ALIGN_FILL" value="3">
- </constant>
- <constant name="ALIGN_EXPAND_FILL" value="4">
- </constant>
- </constants>
-</class>
-<class name="ButtonGroup" inherits="Control" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="get_pressed_button" qualifiers="const" >
- <return type="BaseButton">
- </return>
- <description>
- </description>
- </method>
- <method name="get_pressed_button_index" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_focused_button" qualifiers="const" >
- <return type="BaseButton">
- </return>
- <description>
- </description>
- </method>
- <method name="get_button_list" qualifiers="const" >
- <return type="Array">
- </return>
- <description>
- </description>
- </method>
- <method name="set_pressed_button" >
- <argument index="0" name="button" type="BaseButton">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Camera" inherits="Spatial" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="project_ray_normal" qualifiers="const" >
- <return type="Vector3">
- </return>
- <argument index="0" name="screen_point" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="project_local_ray_normal" qualifiers="const" >
- <return type="Vector3">
- </return>
- <argument index="0" name="screen_point" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="project_ray_origin" qualifiers="const" >
- <return type="Vector3">
- </return>
- <argument index="0" name="screen_point" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="unproject_position" qualifiers="const" >
- <return type="Vector2">
- </return>
- <argument index="0" name="world_point" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="project_position" qualifiers="const" >
- <return type="Vector3">
- </return>
- <argument index="0" name="screen_point" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_perspective" >
- <argument index="0" name="fov" type="real">
- </argument>
- <argument index="1" name="z_near" type="real">
- </argument>
- <argument index="2" name="z_far" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_orthogonal" >
- <argument index="0" name="size" type="real">
- </argument>
- <argument index="1" name="z_near" type="real">
- </argument>
- <argument index="2" name="z_far" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="make_current" >
- <description>
- </description>
- </method>
- <method name="clear_current" >
- <description>
- </description>
- </method>
- <method name="is_current" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_camera_transform" qualifiers="const" >
- <return type="Transform">
- </return>
- <description>
- </description>
- </method>
- <method name="get_fov" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_size" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_zfar" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_znear" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_projection" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="PROJECTION_PERSPECTIVE" value="0">
- </constant>
- <constant name="PROJECTION_ORTHOGONAL" value="1">
- </constant>
- </constants>
-</class>
-<class name="Camera2D" inherits="ScreenProximity2D" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_offset" >
- <argument index="0" name="offset" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_offset" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="set_centered" >
- <argument index="0" name="centered" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_centered" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="make_current" >
- <description>
- </description>
- </method>
- <method name="is_current" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_limit" >
- <argument index="0" name="margin" type="int">
- </argument>
- <argument index="1" name="limit" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_limit" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="margin" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_drag_margin" >
- <argument index="0" name="margin" type="int">
- </argument>
- <argument index="1" name="drag_margin" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_drag_margin" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="margin" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_camera_pos" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="force_update_scroll" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="CanvasItem" inherits="Node" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="edit_set_state" >
- <argument index="0" name="state" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="edit_get" qualifiers="const" >
- <description>
- </description>
- </method>
- <method name="edit_set_rect" >
- <argument index="0" name="rect" type="Rect2">
- </argument>
- <description>
- </description>
- </method>
- <method name="edit_rotate" >
- <argument index="0" name="degrees" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_item_rect" qualifiers="const" >
- <return type="Rect2">
- </return>
- <description>
- </description>
- </method>
- <method name="get_canvas_item" qualifiers="const" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="is_visible" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="is_hidden" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="show" >
- <description>
- </description>
- </method>
- <method name="hide" >
- <description>
- </description>
- </method>
- <method name="update" >
- <description>
- </description>
- </method>
- <method name="set_as_toplevel" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_set_as_toplevel" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_blend_mode" >
- <argument index="0" name="blend_mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_blend_mode" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_opacity" >
- <argument index="0" name="opacity" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_opacity" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_self_opacity" >
- <argument index="0" name="self_opacity" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_self_opacity" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="draw_line" >
- <argument index="0" name="from" type="Vector2">
- </argument>
- <argument index="1" name="to" type="Vector2">
- </argument>
- <argument index="2" name="color" type="Color">
- </argument>
- <argument index="3" name="width" type="real" default="1">
- </argument>
- <description>
- </description>
- </method>
- <method name="draw_rect" >
- <argument index="0" name="rect" type="Rect2">
- </argument>
- <argument index="1" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="draw_circle" >
- <argument index="0" name="pos" type="Vector2">
- </argument>
- <argument index="1" name="radius" type="real">
- </argument>
- <argument index="2" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="draw_texture" >
- <argument index="0" name="texture" type="Texture">
- </argument>
- <argument index="1" name="pos" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="draw_texture_rect" >
- <argument index="0" name="texture" type="Texture">
- </argument>
- <argument index="1" name="rect" type="Rect2">
- </argument>
- <argument index="2" name="tile" type="bool" default="false">
- </argument>
- <argument index="3" name="modulate" type="Color" default="Color(1,1,1,1)">
- </argument>
- <description>
- </description>
- </method>
- <method name="draw_texture_rect_region" >
- <argument index="0" name="texture" type="Texture">
- </argument>
- <argument index="1" name="rect" type="Rect2">
- </argument>
- <argument index="2" name="src_rect" type="Rect2">
- </argument>
- <argument index="3" name="modulate" type="Color" default="Color(1,1,1,1)">
- </argument>
- <description>
- </description>
- </method>
- <method name="draw_style_box" >
- <argument index="0" name="style_box" type="StyleBox">
- </argument>
- <argument index="1" name="rect" type="Rect2">
- </argument>
- <description>
- </description>
- </method>
- <method name="draw_primitive" >
- <argument index="0" name="points" type="Vector2Array">
- </argument>
- <argument index="1" name="colors" type="ColorArray">
- </argument>
- <argument index="2" name="uvs" type="Vector2Array" default="Array()">
- </argument>
- <argument index="3" name="texture" type="Texture" default="Object()">
- </argument>
- <argument index="4" name="width" type="real" default="1">
- </argument>
- <description>
- </description>
- </method>
- <method name="draw_polygon" >
- <argument index="0" name="points" type="Vector2Array">
- </argument>
- <argument index="1" name="colors" type="ColorArray">
- </argument>
- <argument index="2" name="uvs" type="Vector2Array">
- </argument>
- <argument index="3" name="texture" type="Texture" default="Array()">
- </argument>
- <argument index="4" name="arg4" type="real" default="Object()">
- </argument>
- <description>
- </description>
- </method>
- <method name="draw_colored_polygon" >
- <argument index="0" name="points" type="Vector2Array">
- </argument>
- <argument index="1" name="color" type="ColorArray">
- </argument>
- <argument index="2" name="uvs" type="Vector2Array">
- </argument>
- <argument index="3" name="texture" type="Texture" default="Array()">
- </argument>
- <argument index="4" name="arg4" type="real" default="Object()">
- </argument>
- <description>
- </description>
- </method>
- <method name="draw_string" >
- <argument index="0" name="font" type="Font">
- </argument>
- <argument index="1" name="pos" type="Vector2">
- </argument>
- <argument index="2" name="text" type="String">
- </argument>
- <argument index="3" name="modulate" type="Color" default="Color(1,1,1,1)">
- </argument>
- <argument index="4" name="clip_w" type="int" default="-1">
- </argument>
- <description>
- </description>
- </method>
- <method name="draw_char" >
- <return type="real">
- </return>
- <argument index="0" name="font" type="Font">
- </argument>
- <argument index="1" name="pos" type="Vector2">
- </argument>
- <argument index="2" name="char" type="String">
- </argument>
- <argument index="3" name="next" type="String">
- </argument>
- <argument index="4" name="modulate" type="Color" default="Color(1,1,1,1)">
- </argument>
- <description>
- </description>
- </method>
- <method name="draw_set_transform" >
- <argument index="0" name="pos" type="Vector2">
- </argument>
- <argument index="1" name="rot" type="real">
- </argument>
- <argument index="2" name="scale" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_transform_notify" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_transform_notify_enabled" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="item_rect_changed">
- <description>
- </description>
- </signal>
- <signal name="draw">
- <description>
- </description>
- </signal>
- <signal name="visibility_changed">
- <description>
- </description>
- </signal>
- <signal name="hide">
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- <constant name="BLEND_MODE_MIX" value="0">
- </constant>
- <constant name="BLEND_MODE_ADD" value="1">
- </constant>
- <constant name="BLEND_MODE_SUB" value="2">
- </constant>
- <constant name="BLEND_MODE_MUL" value="3">
- </constant>
- <constant name="NOTIFICATION_DRAW" value="30">
- </constant>
- <constant name="NOTIFICATION_VISIBILITY_CHANGED" value="31">
- </constant>
- <constant name="NOTIFICATION_ENTER_CANVAS" value="32">
- </constant>
- <constant name="NOTIFICATION_EXIT_CANVAS" value="33">
- </constant>
- <constant name="NOTIFICATION_TRANSFORM_CHANGED" value="34">
- </constant>
- </constants>
-</class>
-<class name="CanvasLayer" inherits="Node" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_layer" >
- <argument index="0" name="layer" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_layer" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_transform" >
- <argument index="0" name="transform" type="Matrix32">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_transform" qualifiers="const" >
- <return type="Matrix32">
- </return>
- <description>
- </description>
- </method>
- <method name="set_offset" >
- <argument index="0" name="offset" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_offset" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="set_rotation" >
- <argument index="0" name="rotation" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_rotation" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_scale" >
- <argument index="0" name="scale" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_scale" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="get_canvas" qualifiers="const" >
- <return type="Canvas">
- </return>
- <description>
- </description>
- </method>
- <method name="get_viewport" qualifiers="const" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="CapsuleShape" inherits="Shape" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_radius" >
- <argument index="0" name="radius" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_radius" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_height" >
- <argument index="0" name="height" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_height" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="CapsuleShape2D" inherits="Shape2D" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_radius" >
- <argument index="0" name="radius" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_radius" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_height" >
- <argument index="0" name="height" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_height" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="CenterContainer" inherits="Container" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="CheckButton" inherits="BaseButton" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_text" >
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_text" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="CircleShape2D" inherits="Shape2D" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_radius" >
- <argument index="0" name="radius" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_radius" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="CollisionObject2D" inherits="Node2D" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="add_shape" >
- <argument index="0" name="shape" type="Shape2D">
- </argument>
- <argument index="1" name="transform" type="Matrix32" default="1,0, 0,1, 0,0">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_shape_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_shape" >
- <argument index="0" name="shape_idx" type="int">
- </argument>
- <argument index="1" name="shape" type="Shape">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_shape_transform" >
- <argument index="0" name="shape_idx" type="int">
- </argument>
- <argument index="1" name="transform" type="Matrix32">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_shape" qualifiers="const" >
- <return type="Shape2D">
- </return>
- <argument index="0" name="shape_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_shape_transform" qualifiers="const" >
- <return type="Matrix32">
- </return>
- <argument index="0" name="shape_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="remove_shape" >
- <argument index="0" name="shape_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear_shapes" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="CollisionPolygon2D" inherits="Node2D" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="CollisionShape2D" inherits="Node2D" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="ColorPicker" inherits="Control" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_color" >
- <argument index="0" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_color" qualifiers="const" >
- <return type="Color">
- </return>
- <description>
- </description>
- </method>
- <method name="set_show_alpha" >
- <argument index="0" name="show" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_showing_alpha" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="color_changed">
- <argument index="0" name="color" type="Color">
- </argument>
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="ConcavePolygonShape" inherits="Shape" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_faces" >
- <argument index="0" name="faces" type="Vector3Array">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_faces" qualifiers="const" >
- <return type="Vector3Array">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="ConcavePolygonShape2D" inherits="Shape2D" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_segments" >
- <argument index="0" name="segments" type="Vector2Array">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_segments" qualifiers="const" >
- <return type="Vector2Array">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="ConfirmationDialog" inherits="AcceptDialog" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="get_cancel" >
- <return type="Button">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Container" inherits="Control" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="queue_sort" >
- <description>
- </description>
- </method>
- <method name="fit_child_in_rect" >
- <argument index="0" name="child" type="Control">
- </argument>
- <argument index="1" name="rect" type="Rect2">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="sort_children">
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- <constant name="NOTIFICATION_SORT_CHILDREN" value="50">
- </constant>
- </constants>
-</class>
-<class name="Control" inherits="CanvasItem" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="accept_event" >
- <description>
- </description>
- </method>
- <method name="get_minimum_size" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="is_window" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_window" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="set_anchor" >
- <argument index="0" name="margin" type="int">
- </argument>
- <argument index="1" name="anchor_mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_anchor" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="margin" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_margin" >
- <argument index="0" name="margin" type="int">
- </argument>
- <argument index="1" name="offset" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_anchor_and_margin" >
- <argument index="0" name="margin" type="int">
- </argument>
- <argument index="1" name="anchor_mode" type="int">
- </argument>
- <argument index="2" name="offset" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_begin" >
- <argument index="0" name="pos" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_end" >
- <argument index="0" name="pos" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_pos" >
- <argument index="0" name="pos" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_size" >
- <argument index="0" name="size" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_global_pos" >
- <argument index="0" name="pos" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_margin" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="margin" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_begin" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="get_end" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="get_pos" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="get_size" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="get_parent_area_size" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="get_global_pos" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="get_rect" qualifiers="const" >
- <return type="Rect2">
- </return>
- <description>
- </description>
- </method>
- <method name="get_global_rect" qualifiers="const" >
- <return type="Rect2">
- </return>
- <description>
- </description>
- </method>
- <method name="set_area_as_parent_rect" >
- <argument index="0" name="margin" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="show_modal" >
- <argument index="0" name="exclusive" type="bool" default="false">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_focus_mode" >
- <argument index="0" name="mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_focus" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="grab_focus" >
- <description>
- </description>
- </method>
- <method name="release_focus" >
- <description>
- </description>
- </method>
- <method name="get_focus_owner" qualifiers="const" >
- <return type="Control">
- </return>
- <description>
- </description>
- </method>
- <method name="set_h_size_flags" >
- <argument index="0" name="flags" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_h_size_flags" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_stretch_ratio" >
- <argument index="0" name="ratio" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_stretch_ratio" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_v_size_flags" >
- <argument index="0" name="flags" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_v_size_flags" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_theme" >
- <argument index="0" name="theme" type="Theme">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_theme" qualifiers="const" >
- <return type="Theme">
- </return>
- <description>
- </description>
- </method>
- <method name="add_icon_override" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="texture" type="Texture">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_style_override" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="stylebox" type="StyleBox">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_font_override" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="font" type="Font">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_color_override" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_constant_override" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="constant" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_icon" qualifiers="const" >
- <return type="Texture">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String" default="&quot;&quot;">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_stylebox" qualifiers="const" >
- <return type="StyleBox">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String" default="&quot;&quot;">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_font" qualifiers="const" >
- <return type="Font">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String" default="&quot;&quot;">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_color" qualifiers="const" >
- <return type="Color">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String" default="&quot;&quot;">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_constant" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String" default="&quot;&quot;">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_parent_control" qualifiers="const" >
- <return type="Control">
- </return>
- <description>
- </description>
- </method>
- <method name="set_tooltip" >
- <argument index="0" name="tooltip" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_tooltip" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="atpos" type="Vector2" default="Vector2(0,0)">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_default_cursor_shape" >
- <argument index="0" name="shape" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_default_cursor_shape" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_cursor_shape" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="pos" type="Vector2" default="Vector2(0,0)">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_focus_neighbour" >
- <argument index="0" name="margin" type="int">
- </argument>
- <argument index="1" name="neighbour" type="NodePath">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_focus_neighbour" qualifiers="const" >
- <return type="NodePath">
- </return>
- <argument index="0" name="margin" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_ignore_mouse" >
- <argument index="0" name="ignore" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_ignoring_mouse" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="focus_enter">
- <description>
- </description>
- </signal>
- <signal name="mouse_enter">
- <description>
- </description>
- </signal>
- <signal name="resized">
- <description>
- </description>
- </signal>
- <signal name="minimum_size_changed">
- <description>
- </description>
- </signal>
- <signal name="size_flags_changed">
- <description>
- </description>
- </signal>
- <signal name="focus_exit">
- <description>
- </description>
- </signal>
- <signal name="input_event">
- <description>
- </description>
- </signal>
- <signal name="mouse_exit">
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- <constant name="ANCHOR_BEGIN" value="0">
- </constant>
- <constant name="ANCHOR_END" value="1">
- </constant>
- <constant name="ANCHOR_RATIO" value="2">
- </constant>
- <constant name="FOCUS_NONE" value="0">
- </constant>
- <constant name="FOCUS_CLICK" value="1">
- </constant>
- <constant name="FOCUS_ALL" value="2">
- </constant>
- <constant name="NOTIFICATION_RESIZED" value="34">
- </constant>
- <constant name="NOTIFICATION_MOUSE_ENTER" value="35">
- </constant>
- <constant name="NOTIFICATION_MOUSE_EXIT" value="36">
- </constant>
- <constant name="NOTIFICATION_FOCUS_ENTER" value="37">
- </constant>
- <constant name="NOTIFICATION_FOCUS_EXIT" value="38">
- </constant>
- <constant name="NOTIFICATION_THEME_CHANGED" value="39">
- </constant>
- <constant name="NOTIFICATION_MODAL_CLOSE" value="40">
- </constant>
- <constant name="CURSOR_ARROW" value="0">
- </constant>
- <constant name="CURSOR_IBEAM" value="1">
- </constant>
- <constant name="CURSOR_POINTING_HAND" value="2">
- </constant>
- <constant name="CURSOR_CROSS" value="3">
- </constant>
- <constant name="CURSOR_WAIT" value="4">
- </constant>
- <constant name="CURSOR_BUSY" value="5">
- </constant>
- <constant name="CURSOR_DRAG" value="6">
- </constant>
- <constant name="CURSOR_CAN_DROP" value="7">
- </constant>
- <constant name="CURSOR_FORBIDDEN" value="8">
- </constant>
- <constant name="CURSOR_VSIZE" value="9">
- </constant>
- <constant name="CURSOR_HSIZE" value="10">
- </constant>
- <constant name="CURSOR_BDIAGSIZE" value="11">
- </constant>
- <constant name="CURSOR_FDIAGSIZE" value="12">
- </constant>
- <constant name="CURSOR_MOVE" value="13">
- </constant>
- <constant name="CURSOR_VSPLIT" value="14">
- </constant>
- <constant name="CURSOR_HSPLIT" value="15">
- </constant>
- <constant name="CURSOR_HELP" value="16">
- </constant>
- </constants>
-</class>
-<class name="ConvexPolygonShape" inherits="Shape" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_planes" >
- <argument index="0" name="planes" type="Array">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_planes" qualifiers="const" >
- <return type="Array">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="ConvexPolygonShape2D" inherits="Shape2D" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_points" >
- <argument index="0" name="points" type="Vector2Array">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_points" qualifiers="const" >
- <return type="Vector2Array">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="DOFBlurFX" inherits="ScenarioFX" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="DampedSpringJoint2D" inherits="Joint2D" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_length" >
- <argument index="0" name="length" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_length" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_rest_length" >
- <argument index="0" name="rest_length" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_rest_length" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_stiffness" >
- <argument index="0" name="stiffness" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_stiffness" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_damping" >
- <argument index="0" name="damping" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_damping" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="DirectionalLight" inherits="Light" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="DynamicBody" inherits="PhysicsBody" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_mass" >
- <argument index="0" name="mass" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_friction" >
- <argument index="0" name="friction" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_bounce" >
- <argument index="0" name="bounce" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_mass" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_friction" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_bounce" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_linear_velocity" >
- <argument index="0" name="linear_velocity" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_linear_velocity" qualifiers="const" >
- <return type="Vector3">
- </return>
- <description>
- </description>
- </method>
- <method name="set_angular_velocity" >
- <argument index="0" name="angular_velocity" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_angular_velocity" qualifiers="const" >
- <return type="Vector3">
- </return>
- <description>
- </description>
- </method>
- <method name="set_sleeping" >
- <argument index="0" name="sleeping" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_sleeping" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_applied_force" >
- <argument index="0" name="applied_force" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_applied_force" qualifiers="const" >
- <return type="Vector3">
- </return>
- <description>
- </description>
- </method>
- <method name="set_applied_torque" >
- <argument index="0" name="applied_torque" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_applied_torque" qualifiers="const" >
- <return type="Vector3">
- </return>
- <description>
- </description>
- </method>
- <method name="apply_local_impulse" >
- <argument index="0" name="pos" type="Vector3">
- </argument>
- <argument index="1" name="impulse" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_axis_velocity" >
- <argument index="0" name="axis_velocity" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_direct_state_control" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_direct_state_control_enabled" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_omit_force_integration" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_omitting_force_integration" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="DynamicCharacterBody" inherits="DynamicBody" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="DynamicCustomBody" inherits="DynamicBody" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_mode" >
- <argument index="0" name="mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="DynamicRigidBody" inherits="DynamicBody" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="EmptyControl" inherits="Control" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_minsize" >
- <argument index="0" name="minsize" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_minsize" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="_File" inherits="Reference" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="open" >
- <return type="int">
- </return>
- <argument index="0" name="path" type="String">
- </argument>
- <argument index="1" name="flags" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="close" >
- <description>
- </description>
- </method>
- <method name="is_open" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="seek" >
- <argument index="0" name="pos" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="seek_end" >
- <argument index="0" name="pos" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_pos" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_len" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="eof_reached" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_8" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_16" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_32" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_64" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_float" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_double" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_real" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_buffer" qualifiers="const" >
- <return type="RawArray">
- </return>
- <argument index="0" name="len" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_line" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="get_endian_swap" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_endian_swap" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_error" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_var" qualifiers="const" >
- <description>
- </description>
- </method>
- <method name="store_8" >
- <argument index="0" name="value" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="store_16" >
- <argument index="0" name="value" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="store_32" >
- <argument index="0" name="value" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="store_64" >
- <argument index="0" name="value" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="store_float" >
- <argument index="0" name="value" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="store_double" >
- <argument index="0" name="value" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="store_real" >
- <argument index="0" name="value" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="store_buffer" >
- <argument index="0" name="buffer" type="RawArray">
- </argument>
- <description>
- </description>
- </method>
- <method name="store_line" >
- <argument index="0" name="line" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="store_string" >
- <argument index="0" name="string" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="store_var" >
- <argument index="0" name="value" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="file_exists" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="path" type="String">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="READ" value="1">
- </constant>
- <constant name="WRITE" value="2">
- </constant>
- <constant name="READ_WRITE" value="3">
- </constant>
- </constants>
-</class>
-<class name="FileDialog" inherits="ConfirmationDialog" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="clear_filters" >
- <description>
- </description>
- </method>
- <method name="add_filter" >
- <argument index="0" name="filter" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_current_dir" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="get_current_file" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="get_current_path" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="set_current_dir" >
- <argument index="0" name="dir" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_current_file" >
- <argument index="0" name="file" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_current_path" >
- <argument index="0" name="path" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_mode" >
- <argument index="0" name="mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_mode" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_vbox" >
- <return type="VBoxContainer">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="dir_selected">
- <argument index="0" name="dir" type="String">
- </argument>
- <description>
- </description>
- </signal>
- <signal name="file_selected">
- <argument index="0" name="path" type="String">
- </argument>
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- <constant name="MODE_OPEN_FILE" value="0">
- </constant>
- <constant name="MODE_OPEN_DIR" value="1">
- </constant>
- <constant name="MODE_SAVE_FILE" value="2">
- </constant>
- </constants>
-</class>
-<class name="FixedMaterial" inherits="Material" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_shader" >
- <argument index="0" name="shader" type="Shader">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_shader" qualifiers="const" >
- <return type="Shader">
- </return>
- <description>
- </description>
- </method>
- <method name="set_parameter" >
- <argument index="0" name="param" type="int">
- </argument>
- <argument index="1" name="value" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_parameter" qualifiers="const" >
- <argument index="0" name="param" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_texture" >
- <argument index="0" name="param" type="int">
- </argument>
- <argument index="1" name="texture" type="Texture">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_texture" qualifiers="const" >
- <return type="Texture">
- </return>
- <argument index="0" name="param" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_texgen_mode" >
- <argument index="0" name="mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_texgen_mode" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_texcoord_mode" >
- <argument index="0" name="param" type="int">
- </argument>
- <argument index="1" name="mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_texcoord_mode" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="param" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_uv_transform" >
- <argument index="0" name="transform" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_uv_transform" qualifiers="const" >
- <return type="Transform">
- </return>
- <description>
- </description>
- </method>
- <method name="set_detail_blend_mode" >
- <argument index="0" name="mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_detail_blend_mode" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="PARAM_DIFFUSE" value="0">
- </constant>
- <constant name="PARAM_DETAIL" value="1">
- </constant>
- <constant name="PARAM_SPECULAR" value="2">
- </constant>
- <constant name="PARAM_EMISSION" value="3">
- </constant>
- <constant name="PARAM_SPECULAR_EXP" value="4">
- </constant>
- <constant name="PARAM_GLOW" value="5">
- </constant>
- <constant name="PARAM_NORMAL" value="6">
- </constant>
- <constant name="PARAM_SHADE_PARAM" value="7">
- </constant>
- <constant name="PARAM_MAX" value="8">
- </constant>
- <constant name="TEXGEN_SPHERE" value="1">
- </constant>
- <constant name="TEXGEN_SCREEN" value="2">
- </constant>
- <constant name="TEXGEN_SCREENZ" value="3">
- </constant>
- <constant name="TEXGEN_LOCAL_XY" value="0">
- </constant>
- <constant name="TEXCOORD_TEXGEN" value="3">
- </constant>
- <constant name="TEXCOORD_UV" value="0">
- </constant>
- <constant name="TEXCOORD_UV_TRANSFORM" value="1">
- </constant>
- <constant name="TEXCOORD_UV2" value="2">
- </constant>
- </constants>
-</class>
-<class name="FogFX" inherits="ScenarioFX" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="FollowCamera" inherits="Camera" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_orbit" >
- <argument index="0" name="orbit" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_orbit" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="set_orbit_x" >
- <argument index="0" name="x" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_orbit_y" >
- <argument index="0" name="y" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_min_orbit_x" >
- <argument index="0" name="x" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_min_orbit_x" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_max_orbit_x" >
- <argument index="0" name="x" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_max_orbit_x" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_height" >
- <argument index="0" name="height" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_height" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_inclination" >
- <argument index="0" name="inclination" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_inclination" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="rotate_orbit" >
- <argument index="0" name="arg0" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_distance" >
- <argument index="0" name="distance" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_distance" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_max_distance" >
- <argument index="0" name="max_distance" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_max_distance" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_min_distance" >
- <argument index="0" name="min_distance" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_min_distance" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_clip" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_clip" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_autoturn" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_autoturn" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_autoturn_tolerance" >
- <argument index="0" name="degrees" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_autoturn_tolerance" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_autoturn_speed" >
- <argument index="0" name="speed" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_autoturn_speed" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_smoothing" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_smoothing" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_rotation_smoothing" >
- <argument index="0" name="amount" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_rotation_smoothing" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_translation_smoothing" >
- <argument index="0" name="amount" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_translation_smoothing" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_use_lookat_target" >
- <argument index="0" name="use" type="bool">
- </argument>
- <argument index="1" name="lookat" type="Vector3" default="Vector3(0, 0, 0)">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Font" inherits="Resource" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_height" >
- <argument index="0" name="px" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_height" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_ascent" >
- <argument index="0" name="px" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_ascent" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_descent" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="add_kerning_pair" >
- <argument index="0" name="char_a" type="int">
- </argument>
- <argument index="1" name="char_b" type="int">
- </argument>
- <argument index="2" name="kerning" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_kerning_pair" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="int">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_texture" >
- <argument index="0" name="texture" type="Texture">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_char" >
- <argument index="0" name="character" type="int">
- </argument>
- <argument index="1" name="texture" type="int">
- </argument>
- <argument index="2" name="rect" type="Rect2">
- </argument>
- <argument index="3" name="align" type="Vector2" default="Vector2(0,0)">
- </argument>
- <argument index="4" name="advance" type="real" default="-1">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_char_size" qualifiers="const" >
- <return type="Vector2">
- </return>
- <argument index="0" name="char" type="int">
- </argument>
- <argument index="1" name="next" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_string_size" qualifiers="const" >
- <return type="Vector2">
- </return>
- <argument index="0" name="string" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear" >
- <description>
- </description>
- </method>
- <method name="draw" qualifiers="const" >
- <argument index="0" name="canvas_item" type="RID">
- </argument>
- <argument index="1" name="pos" type="Vector2">
- </argument>
- <argument index="2" name="string" type="String">
- </argument>
- <argument index="3" name="modulate" type="Color" default="Color(1,1,1,1)">
- </argument>
- <argument index="4" name="clip_w" type="int" default="-1">
- </argument>
- <description>
- </description>
- </method>
- <method name="draw_char" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="canvas_item" type="RID">
- </argument>
- <argument index="1" name="pos" type="Vector2">
- </argument>
- <argument index="2" name="char" type="int">
- </argument>
- <argument index="3" name="next" type="int" default="-1">
- </argument>
- <argument index="4" name="modulate" type="Color" default="Color(1,1,1,1)">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="GDNativeClass" inherits="Reference" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="new" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="GDScript" inherits="Script" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="new" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="GammaFX" inherits="ScenarioFX" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="_Geometry" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="build_box_planes" >
- <return type="Array">
- </return>
- <argument index="0" name="extents" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="build_cylinder_planes" >
- <return type="Array">
- </return>
- <argument index="0" name="radius" type="real">
- </argument>
- <argument index="1" name="height" type="real">
- </argument>
- <argument index="2" name="sides" type="int">
- </argument>
- <argument index="3" name="axis" type="int" default="2">
- </argument>
- <description>
- </description>
- </method>
- <method name="build_capsule_planes" >
- <return type="Array">
- </return>
- <argument index="0" name="radius" type="real">
- </argument>
- <argument index="1" name="height" type="real">
- </argument>
- <argument index="2" name="sides" type="int">
- </argument>
- <argument index="3" name="lats" type="int">
- </argument>
- <argument index="4" name="axis" type="int" default="2">
- </argument>
- <description>
- </description>
- </method>
- <method name="segment_intersects_circle" >
- <return type="real">
- </return>
- <argument index="0" name="segment_from" type="Vector2">
- </argument>
- <argument index="1" name="segment_to" type="Vector2">
- </argument>
- <argument index="2" name="circle_pos" type="Vector2">
- </argument>
- <argument index="3" name="circle_radius" type="real">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="GeometryInstance" inherits="VisualInstance" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_visible" >
- <argument index="0" name="visible" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_visible" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_material_override" >
- <argument index="0" name="material" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_material_override" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Globals" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="has" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_order" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="pos" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_order" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_persisting" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_persisting" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear" >
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="localize_path" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="path" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="globalize_path" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="path" type="String">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="GlowFX" inherits="ScenarioFX" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="GridMap" inherits="Spatial" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_theme" >
- <argument index="0" name="theme" type="MeshLibrary">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_theme" qualifiers="const" >
- <return type="MeshLibrary">
- </return>
- <description>
- </description>
- </method>
- <method name="set_cell_size" >
- <argument index="0" name="size" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_cell_size" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_octant_size" >
- <argument index="0" name="size" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_octant_size" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_width" >
- <argument index="0" name="width" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_width" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_height" >
- <argument index="0" name="height" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_height" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_depth" >
- <argument index="0" name="depth" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_depth" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_cell_item" >
- <argument index="0" name="x" type="int">
- </argument>
- <argument index="1" name="y" type="int">
- </argument>
- <argument index="2" name="z" type="int">
- </argument>
- <argument index="3" name="item" type="int">
- </argument>
- <argument index="4" name="orientation" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_cell_item" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="x" type="int">
- </argument>
- <argument index="1" name="y" type="int">
- </argument>
- <argument index="2" name="z" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_cell_item_orientation" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="x" type="int">
- </argument>
- <argument index="1" name="y" type="int">
- </argument>
- <argument index="2" name="z" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="resource_changed" >
- <argument index="0" name="arg0" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_center_x" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_center_x" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_center_y" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_center_y" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_center_z" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_center_z" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_clip" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <argument index="1" name="clipabove" type="bool" default="true">
- </argument>
- <argument index="2" name="floor" type="int" default="0">
- </argument>
- <argument index="3" name="axis" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="crate_area" >
- <return type="int">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="area" type="AABB">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_get_bounds" qualifiers="const" >
- <return type="AABB">
- </return>
- <argument index="0" name="area" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_set_exterior_portal" >
- <argument index="0" name="area" type="int">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_set_name" >
- <argument index="0" name="area" type="int">
- </argument>
- <argument index="1" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_get_name" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="area" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_is_exterior_portal" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="area" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_set_portal_disable_distance" >
- <argument index="0" name="area" type="int">
- </argument>
- <argument index="1" name="distance" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_get_portal_disable_distance" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="area" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_set_portal_disable_color" >
- <argument index="0" name="area" type="int">
- </argument>
- <argument index="1" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_get_portal_disable_color" qualifiers="const" >
- <return type="Color">
- </return>
- <argument index="0" name="area" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="erase_area" >
- <argument index="0" name="area" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_unused_area_id" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="INVALID_CELL_ITEM" value="-1">
- </constant>
- </constants>
-</class>
-<class name="GrooveJoint2D" inherits="Joint2D" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_length" >
- <argument index="0" name="length" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_length" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_initial_offset" >
- <argument index="0" name="offset" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_initial_offset" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="HBoxContainer" inherits="BoxContainer" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="HButtonArray" inherits="ButtonArray" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="HDRFX" inherits="ScenarioFX" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="HScrollBar" inherits="ScrollBar" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="HSeparator" inherits="Separator" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="HSlider" inherits="Slider" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="IP" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="resolve_hostname" >
- <return type="String">
- </return>
- <argument index="0" name="host" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="resolve_hostname_queue_item" >
- <return type="int">
- </return>
- <argument index="0" name="host" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_resolve_item_status" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_resolve_item_address" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="erase_resolve_item" >
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="RESOLVER_STATUS_NONE" value="0">
- </constant>
- <constant name="RESOLVER_STATUS_WAITING" value="1">
- </constant>
- <constant name="RESOLVER_STATUS_DONE" value="2">
- </constant>
- <constant name="RESOLVER_STATUS_ERROR" value="3">
- </constant>
- <constant name="RESOLVER_MAX_QUERIES" value="32">
- </constant>
- <constant name="RESOLVER_INVALID_ID" value="-1">
- </constant>
- </constants>
-</class>
-<class name="IP_Unix" inherits="IP" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="InputMap" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="InterpolatedCamera" inherits="Camera" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_target_path" >
- <argument index="0" name="target_path" type="NodePath">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_target_path" qualifiers="const" >
- <return type="NodePath">
- </return>
- <description>
- </description>
- </method>
- <method name="set_target" >
- <argument index="0" name="target" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_speed" >
- <argument index="0" name="speed" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_speed" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_interpolation_enabled" >
- <argument index="0" name="target_path" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_interpolation_enabled" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Joint2D" inherits="Node2D" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_node_a" >
- <argument index="0" name="node" type="NodePath">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_node_a" qualifiers="const" >
- <return type="NodePath">
- </return>
- <description>
- </description>
- </method>
- <method name="set_node_b" >
- <argument index="0" name="node" type="NodePath">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_node_b" qualifiers="const" >
- <return type="NodePath">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Label" inherits="Range" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_align" >
- <argument index="0" name="align" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_align" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_valign" >
- <argument index="0" name="valign" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_valign" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_text" >
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_text" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="set_autowrap" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_autowrap" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_line_height" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_line_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="ALIGN_LEFT" value="0">
- </constant>
- <constant name="ALIGN_CENTER" value="1">
- </constant>
- <constant name="ALIGN_RIGHT" value="2">
- </constant>
- <constant name="ALIGN_FILL" value="3">
- </constant>
- <constant name="VALIGN_TOP" value="0">
- </constant>
- <constant name="VALIGN_CENTER" value="1">
- </constant>
- <constant name="VALIGN_BOTTOM" value="2">
- </constant>
- <constant name="VALIGN_FILL" value="3">
- </constant>
- </constants>
-</class>
-<class name="Light" inherits="VisualInstance" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_parameter" >
- <argument index="0" name="variable" type="int">
- </argument>
- <argument index="1" name="value" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_parameter" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_color" >
- <argument index="0" name="color" type="int">
- </argument>
- <argument index="1" name="value" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_color" qualifiers="const" >
- <return type="Color">
- </return>
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_project_shadows" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_project_shadows" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_projector" >
- <argument index="0" name="projector" type="Texture">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_projector" qualifiers="const" >
- <return type="Texture">
- </return>
- <description>
- </description>
- </method>
- <method name="set_operator" >
- <argument index="0" name="operator" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_operator" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="PARAM_RADIUS" value="2">
- </constant>
- <constant name="PARAM_ENERGY" value="3">
- </constant>
- <constant name="PARAM_ATTENUATION" value="4">
- </constant>
- <constant name="PARAM_SPOT_ANGLE" value="1">
- </constant>
- <constant name="PARAM_SPOT_ATTENUATION" value="4">
- </constant>
- <constant name="PARAM_SHADOW_DARKENING" value="5">
- </constant>
- <constant name="COLOR_AMBIENT" value="0">
- </constant>
- <constant name="COLOR_DIFFUSE" value="1">
- </constant>
- <constant name="COLOR_SPECULAR" value="2">
- </constant>
- </constants>
-</class>
-<class name="LineEdit" inherits="Control" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="clear" >
- <description>
- </description>
- </method>
- <method name="select_all" >
- <description>
- </description>
- </method>
- <method name="set_text" >
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_text" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="set_cursor_pos" >
- <argument index="0" name="pos" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_cursor_pos" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_max_length" >
- <argument index="0" name="chars" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_max_length" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="append_at_cursor" >
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_editable" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_editable" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_secret" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_secret" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="select" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="text_entered">
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- </description>
- </signal>
- <signal name="text_changed">
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="LineShape2D" inherits="Shape2D" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_normal" >
- <argument index="0" name="normal" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_normal" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="set_d" >
- <argument index="0" name="d" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_d" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="MainLoop" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="input_event" >
- <argument index="0" name="arg0" type="InputEvent">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="NOTIFICATION_WM_FOCUS_IN" value="5">
- </constant>
- <constant name="NOTIFICATION_WM_FOCUS_OUT" value="6">
- </constant>
- <constant name="NOTIFICATION_WM_QUIT_REQUEST" value="7">
- </constant>
- </constants>
-</class>
-<class name="MarginContainer" inherits="Container" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Material" inherits="Resource" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_flag" >
- <argument index="0" name="flag" type="int">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_flag" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="flag" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_hint" >
- <argument index="0" name="hint" type="int">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_hint" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="hint" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_blend_mode" >
- <argument index="0" name="mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_blend_mode" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_shade_model" >
- <argument index="0" name="model" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_shade_model" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_line_width" >
- <argument index="0" name="width" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_line_width" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_shader_param" >
- <argument index="0" name="param" type="String">
- </argument>
- <argument index="1" name="arg1" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_shader_param" qualifiers="const" >
- <argument index="0" name="arg0" type="String">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="FLAG_VISIBLE" value="0">
- </constant>
- <constant name="FLAG_DOUBLE_SIDED" value="1">
- </constant>
- <constant name="FLAG_INVERT_FACES" value="2">
- </constant>
- <constant name="FLAG_UNSHADED" value="3">
- </constant>
- <constant name="FLAG_ONTOP" value="4">
- </constant>
- <constant name="FLAG_WIREFRAME" value="5">
- </constant>
- <constant name="FLAG_BILLBOARD_TOGGLE" value="6">
- </constant>
- <constant name="FLAG_MAX" value="7">
- </constant>
- <constant name="HINT_DECAL" value="0">
- </constant>
- <constant name="HINT_OPAQUE_PRE_PASS" value="1">
- </constant>
- <constant name="HINT_NO_SHADOW" value="2">
- </constant>
- <constant name="HINT_NO_DEPTH_DRAW" value="3">
- </constant>
- <constant name="HINT_MAX" value="4">
- </constant>
- <constant name="SHADE_MODEL_LAMBERT" value="0">
- </constant>
- <constant name="SHADE_MODEL_LAMBERT_WRAP" value="1">
- </constant>
- <constant name="SHADE_MODEL_FRESNEL" value="2">
- </constant>
- <constant name="SHADE_MODEL_TOON" value="3">
- </constant>
- <constant name="SHADE_MODEL_CUSTOM_0" value="4">
- </constant>
- <constant name="SHADE_MODEL_CUSTOM_1" value="5">
- </constant>
- <constant name="SHADE_MODEL_CUSTOM_2" value="6">
- </constant>
- <constant name="SHADE_MODEL_CUSTOM_3" value="7">
- </constant>
- <constant name="BLEND_MODE_MIX" value="0">
- </constant>
- <constant name="BLEND_MODE_ADD" value="1">
- </constant>
- <constant name="BLEND_MODE_SUB" value="2">
- </constant>
- </constants>
-</class>
-<class name="MenuButton" inherits="Button" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="get_popup" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="about_to_show">
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="Mesh" inherits="Resource" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="add_morph_target" >
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_morph_target_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_morph_target_name" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="index" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear_morph_targets" >
- <description>
- </description>
- </method>
- <method name="set_morph_target_mode" >
- <argument index="0" name="mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_morph_target_mode" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="add_surface" >
- <argument index="0" name="primitive" type="int">
- </argument>
- <argument index="1" name="format" type="int">
- </argument>
- <argument index="2" name="array_len" type="int">
- </argument>
- <argument index="3" name="index_array_len" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_surface_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="surface_remove" >
- <argument index="0" name="surf_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="surface_set_array" >
- <return type="int">
- </return>
- <argument index="0" name="surf_idx" type="int">
- </argument>
- <argument index="1" name="array" type="int">
- </argument>
- <argument index="2" name="data" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="surface_get_array" qualifiers="const" >
- <argument index="0" name="surf_idx" type="int">
- </argument>
- <argument index="1" name="array" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="surface_get_array_len" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="surf_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="surface_get_array_index_len" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="surf_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="surface_get_format" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="surf_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="surface_get_primitive_type" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="surf_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="surface_set_material" >
- <argument index="0" name="surf_idx:Material" type="int">
- </argument>
- <argument index="1" name="arg1" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="surface_get_material" qualifiers="const" >
- <return type="Material">
- </return>
- <argument index="0" name="surf_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="NO_INDEX_ARRAY" value="-1">
- </constant>
- <constant name="ARRAY_WEIGHTS_SIZE" value="4">
- </constant>
- <constant name="ARRAY_VERTEX" value="0">
- </constant>
- <constant name="ARRAY_NORMAL" value="1">
- </constant>
- <constant name="ARRAY_TANGENT" value="2">
- </constant>
- <constant name="ARRAY_COLOR" value="3">
- </constant>
- <constant name="ARRAY_TEX_UV" value="4">
- </constant>
- <constant name="ARRAY_TEX_UV2" value="5">
- </constant>
- <constant name="ARRAY_BONES" value="6">
- </constant>
- <constant name="ARRAY_WEIGHTS" value="7">
- </constant>
- <constant name="ARRAY_INDEX" value="8">
- </constant>
- <constant name="ARRAY_FORMAT_VERTEX" value="1">
- </constant>
- <constant name="ARRAY_FORMAT_NORMAL" value="2">
- </constant>
- <constant name="ARRAY_FORMAT_TANGENT" value="4">
- </constant>
- <constant name="ARRAY_FORMAT_COLOR" value="8">
- </constant>
- <constant name="ARRAY_FORMAT_TEX_UV" value="16">
- </constant>
- <constant name="ARRAY_FORMAT_TEX_UV2" value="32">
- </constant>
- <constant name="ARRAY_FORMAT_BONES" value="64">
- </constant>
- <constant name="ARRAY_FORMAT_WEIGHTS" value="128">
- </constant>
- <constant name="ARRAY_FORMAT_INDEX" value="256">
- </constant>
- <constant name="PRIMITIVE_POINTS" value="0">
- </constant>
- <constant name="PRIMITIVE_LINES" value="1">
- </constant>
- <constant name="PRIMITIVE_LINE_STRIP" value="2">
- </constant>
- <constant name="PRIMITIVE_LINE_LOOP" value="3">
- </constant>
- <constant name="PRIMITIVE_TRIANGLES" value="4">
- </constant>
- <constant name="PRIMITIVE_TRIANGLE_STRIP" value="5">
- </constant>
- <constant name="PRIMITIVE_TRIANGLE_FAN" value="6">
- </constant>
- </constants>
-</class>
-<class name="MeshInstance" inherits="GeometryInstance" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_mesh" >
- <argument index="0" name="mesh" type="Mesh">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_mesh" qualifiers="const" >
- <return type="Mesh">
- </return>
- <description>
- </description>
- </method>
- <method name="get_aabb" qualifiers="const" >
- <return type="AABB">
- </return>
- <description>
- </description>
- </method>
- <method name="create_trimesh_collision" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="MeshLibrary" inherits="Resource" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="create_item" >
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_item_name" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_item_mesh" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="mesh" type="Mesh">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_item_shape" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="shape" type="Shape">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_item_name" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_item_mesh" qualifiers="const" >
- <return type="Mesh">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_item_shape" qualifiers="const" >
- <return type="Shape">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="remove_item" >
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear" >
- <description>
- </description>
- </method>
- <method name="get_item_list" qualifiers="const" >
- <return type="IntArray">
- </return>
- <description>
- </description>
- </method>
- <method name="get_last_unused_item_id" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="MultiMesh" inherits="Resource" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_mesh" >
- <argument index="0" name="mesh" type="Mesh">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_mesh" qualifiers="const" >
- <return type="Mesh">
- </return>
- <description>
- </description>
- </method>
- <method name="set_instance_count" >
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_instance_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_instance_transform" >
- <argument index="0" name="arg0" type="int">
- </argument>
- <argument index="1" name="arg1" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_instance_transform" qualifiers="const" >
- <return type="Transform">
- </return>
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_instance_color" >
- <argument index="0" name="arg0" type="int">
- </argument>
- <argument index="1" name="arg1" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_instance_color" qualifiers="const" >
- <return type="Color">
- </return>
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_aabb" >
- <argument index="0" name="arg0" type="AABB">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_aabb" qualifiers="const" >
- <return type="AABB">
- </return>
- <description>
- </description>
- </method>
- <method name="generate_aabb" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="MultiMeshInstance" inherits="GeometryInstance" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_multimesh" >
- <argument index="0" name="multimesh" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_multimesh" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Node" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_name" >
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_name" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="add_child" >
- <argument index="0" name="node" type="Node">
- </argument>
- <description>
- </description>
- </method>
- <method name="remove_child" >
- <argument index="0" name="node" type="Node">
- </argument>
- <description>
- </description>
- </method>
- <method name="remove_and_delete_child" >
- <argument index="0" name="node" type="Node">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_child_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_child" qualifiers="const" >
- <return type="Node">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_node" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="path" type="NodePath">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_node" qualifiers="const" >
- <return type="Node">
- </return>
- <argument index="0" name="path" type="NodePath">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_parent" qualifiers="const" >
- <return type="Parent">
- </return>
- <description>
- </description>
- </method>
- <method name="has_node_and_resource" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="path" type="NodePath">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_node_and_resource" >
- <return type="Array">
- </return>
- <argument index="0" name="path" type="NodePath">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_inside_scene" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="is_a_parent_of" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="node" type="Node">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_greater_than" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="node" type="Node">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_path" qualifiers="const" >
- <return type="NodePath">
- </return>
- <description>
- </description>
- </method>
- <method name="get_path_to" qualifiers="const" >
- <return type="NodePath">
- </return>
- <argument index="0" name="node" type="Node">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_to_group" >
- <argument index="0" name="group" type="String">
- </argument>
- <argument index="1" name="arg1" type="bool" default="false">
- </argument>
- <description>
- </description>
- </method>
- <method name="remove_from_group" >
- <argument index="0" name="group" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_in_group" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="group" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="move_child" >
- <argument index="0" name="child_node" type="Node">
- </argument>
- <argument index="1" name="to_pos" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="raise" >
- <description>
- </description>
- </method>
- <method name="set_owner" >
- <argument index="0" name="owner" type="Node">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_owner" qualifiers="const" >
- <return type="Node">
- </return>
- <description>
- </description>
- </method>
- <method name="remove_and_skip" >
- <description>
- </description>
- </method>
- <method name="get_index" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="print_tree" >
- <description>
- </description>
- </method>
- <method name="set_filename" >
- <argument index="0" name="filename" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_filename" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="propagate_notification" >
- <argument index="0" name="what" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_process" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_process_time" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="is_processing" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_idle_process" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_idle_process_time" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="is_idle_processing" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_process_input" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_processing_input" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_process_unhandled_input" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_processing_unhandled_input" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_process_mode" >
- <argument index="0" name="mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_process_mode" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="can_process" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="print_stray_nodes" >
- <description>
- </description>
- </method>
- <method name="set_world" >
- <argument index="0" name="world" type="World">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_world" qualifiers="const" >
- <return type="World">
- </return>
- <description>
- </description>
- </method>
- <method name="get_current_world" qualifiers="const" >
- <return type="World">
- </return>
- <description>
- </description>
- </method>
- <method name="get_scene" qualifiers="const" >
- <return type="SceneMainLoop">
- </return>
- <description>
- </description>
- </method>
- <method name="duplicate" qualifiers="const" >
- <return type="Node">
- </return>
- <description>
- </description>
- </method>
- <method name="replace_by" >
- <argument index="0" name="node" type="Node">
- </argument>
- <argument index="1" name="keep_data" type="bool" default="false">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="enter_scene">
- <description>
- </description>
- </signal>
- <signal name="renamed">
- <description>
- </description>
- </signal>
- <signal name="exit_scene">
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- <constant name="NOTIFICATION_ENTER_SCENE" value="10">
- </constant>
- <constant name="NOTIFICATION_EXIT_SCENE" value="11">
- </constant>
- <constant name="NOTIFICATION_MOVED_IN_PARENT" value="12">
- </constant>
- <constant name="NOTIFICATION_CHILDREN_CONFIGURED" value="13">
- </constant>
- <constant name="NOTIFICATION_PROCESS" value="16">
- </constant>
- <constant name="NOTIFICATION_IDLE_PROCESS" value="17">
- </constant>
- <constant name="NOTIFICATION_PARENTED" value="18">
- </constant>
- <constant name="NOTIFICATION_UNPARENTED" value="19">
- </constant>
- <constant name="NOTIFICATION_ENTER_WORLD" value="20">
- </constant>
- <constant name="NOTIFICATION_EXIT_WORLD" value="21">
- </constant>
- <constant name="NOTIFICATION_PAUSED" value="14">
- </constant>
- <constant name="NOTIFICATION_UNPAUSED" value="15">
- </constant>
- <constant name="PROCESS_NORMAL" value="0">
- </constant>
- <constant name="PROCESS_PAUSE" value="1">
- </constant>
- <constant name="PROCESS_ALWAYS" value="2">
- </constant>
- </constants>
-</class>
-<class name="Node2D" inherits="CanvasItem" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_pos" >
- <argument index="0" name="pos" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_rot" >
- <argument index="0" name="rot" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_scale" >
- <argument index="0" name="scale" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_pos" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="get_rot" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_scale" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="get_global_pos" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="_OS" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_mouse_show" >
- <argument index="0" name="show" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_mouse_grab" >
- <argument index="0" name="grab" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_mouse_grab_enabled" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_mouse_pos" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="set_clipboard" >
- <argument index="0" name="clipboard" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_clipboard" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="set_video_mode" >
- <argument index="0" name="size" type="Vector2">
- </argument>
- <argument index="1" name="fullscreen" type="bool">
- </argument>
- <argument index="2" name="resizable" type="bool">
- </argument>
- <argument index="3" name="screen" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_video_mode_size" qualifiers="const" >
- <return type="Vector2">
- </return>
- <argument index="0" name="screen" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_video_mode_fullscreen" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="screen" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_video_mode_resizable" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="screen" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_fullscreen_mode_list" qualifiers="const" >
- <return type="Array">
- </return>
- <argument index="0" name="screen" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_iterations_per_second" >
- <argument index="0" name="iterations_per_second" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_iterations_per_second" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_low_processor_usage_mode" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_in_low_processor_usage_mode" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_executable_path" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="execute" >
- <return type="int">
- </return>
- <argument index="0" name="path" type="String">
- </argument>
- <argument index="1" name="arguments" type="StringArray">
- </argument>
- <argument index="2" name="blocking" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="kill" >
- <return type="int">
- </return>
- <argument index="0" name="pid" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_environment" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="environment" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_environment" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="environment" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_name" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="get_cmdline_args" >
- <return type="StringArray">
- </return>
- <description>
- </description>
- </method>
- <method name="get_main_loop" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="get_date" qualifiers="const" >
- <return type="Dictionary">
- </return>
- <description>
- </description>
- </method>
- <method name="get_time" qualifiers="const" >
- <return type="Dictionary">
- </return>
- <description>
- </description>
- </method>
- <method name="delay_usec" qualifiers="const" >
- <argument index="0" name="usec" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_ticks_msec" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_locale" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="can_draw" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_frames_drawn" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="is_stdout_verbose" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_mouse_button_state" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="dump_memory_to_file" >
- <argument index="0" name="file" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="dump_resources_to_file" >
- <argument index="0" name="file" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="print_resources_in_use" >
- <argument index="0" name="short" type="bool" default="false">
- </argument>
- <description>
- </description>
- </method>
- <method name="print_all_resources" >
- <argument index="0" name="tofile" type="String" default="&quot;&quot;">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_static_memory_usage" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_static_memory_peak_usage" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_dynamic_memory_usage" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="DAY_SUNDAY" value="0">
- </constant>
- <constant name="DAY_MONDAY" value="1">
- </constant>
- <constant name="DAY_TUESDAY" value="2">
- </constant>
- <constant name="DAY_WEDNESDAY" value="3">
- </constant>
- <constant name="DAY_THURSDAY" value="4">
- </constant>
- <constant name="DAY_FRIDAY" value="5">
- </constant>
- <constant name="DAY_SATURDAY" value="6">
- </constant>
- <constant name="MONTH_JANUARY" value="0">
- </constant>
- <constant name="MONTH_FEBRUARY" value="1">
- </constant>
- <constant name="MONTH_MARCH" value="2">
- </constant>
- <constant name="MONTH_APRIL" value="3">
- </constant>
- <constant name="MONTH_MAY" value="4">
- </constant>
- <constant name="MONTH_JUNE" value="5">
- </constant>
- <constant name="MONTH_JULY" value="6">
- </constant>
- <constant name="MONTH_AUGUST" value="7">
- </constant>
- <constant name="MONTH_SEPTEMBER" value="8">
- </constant>
- <constant name="MONTH_OCTOBER" value="9">
- </constant>
- <constant name="MONTH_NOVEMBER" value="10">
- </constant>
- <constant name="MONTH_DECEMBER" value="11">
- </constant>
- </constants>
-</class>
-<class name="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="get_type" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="is_type" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set" >
- <argument index="0" name="property" type="String">
- </argument>
- <argument index="1" name="value" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="get" qualifiers="const" >
- <argument index="0" name="property" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_property_list" qualifiers="const" >
- <return type="Array">
- </return>
- <description>
- </description>
- </method>
- <method name="notification" >
- <argument index="0" name="what" type="int">
- </argument>
- <argument index="1" name="arg1" type="bool" default="false">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_instance_ID" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_script" >
- <argument index="0" name="script" type="Script">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_script" qualifiers="const" >
- <return type="Script">
- </return>
- <description>
- </description>
- </method>
- <method name="set_meta" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="value" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_meta" qualifiers="const" >
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_meta" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_meta_list" qualifiers="const" >
- <return type="StringArray">
- </return>
- <description>
- </description>
- </method>
- <method name="call" >
- <argument index="0" name="method" type="String">
- </argument>
- <argument index="1" name="arg1" type="var" default="NULL">
- </argument>
- <argument index="2" name="arg2" type="var" default="NULL">
- </argument>
- <argument index="3" name="arg3" type="var" default="NULL">
- </argument>
- <argument index="4" name="arg4" type="var" default="NULL">
- </argument>
- <description>
- </description>
- </method>
- <method name="call_deferred" >
- <argument index="0" name="method" type="String">
- </argument>
- <argument index="1" name="arg1" type="var" default="NULL">
- </argument>
- <argument index="2" name="arg2" type="var" default="NULL">
- </argument>
- <argument index="3" name="arg3" type="var" default="NULL">
- </argument>
- <argument index="4" name="arg4" type="var" default="NULL">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_user_signal" >
- <argument index="0" name="signal" type="String">
- </argument>
- <argument index="1" name="arguments" type="Array" default="Array()">
- </argument>
- <description>
- </description>
- </method>
- <method name="emit_signal" >
- <argument index="0" name="signal" type="String">
- </argument>
- <argument index="1" name="arguments" type="Array" default="Array()">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_signal_list" qualifiers="const" >
- <return type="Array">
- </return>
- <description>
- </description>
- </method>
- <method name="connect" >
- <argument index="0" name="signal" type="String">
- </argument>
- <argument index="1" name="target" type="Object">
- </argument>
- <argument index="2" name="method" type="String">
- </argument>
- <argument index="3" name="binds" type="Array" default="Array()">
- </argument>
- <argument index="4" name="flags" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="disconnect" >
- <argument index="0" name="signal" type="String">
- </argument>
- <argument index="1" name="target" type="Object">
- </argument>
- <argument index="2" name="method" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_connected" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="signal" type="String">
- </argument>
- <argument index="1" name="target" type="Object">
- </argument>
- <argument index="2" name="method" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_block_signals" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_blocking_signals" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_message_translation" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="can_translate_messages" >
- <argument index="0" name="arg0" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="XL_MESSAGE" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="message" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="tr" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="message" type="String">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="NOTIFICATION_POSTINITIALIZE" value="0">
- </constant>
- <constant name="NOTIFICATION_PREDELETE" value="1">
- </constant>
- <constant name="CONNECT_DEFERRED" value="1">
- </constant>
- <constant name="CONNECT_PERSIST" value="2">
- </constant>
- <constant name="CONNECT_ONESHOT" value="4">
- </constant>
- </constants>
-</class>
-<class name="OmniLight" inherits="Light" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="OptimizedSaver" inherits="Reference" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_target_platform" >
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_target_platform" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="set_target_name" >
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_property" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="value" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="optimize_object" >
- <return type="bool">
- </return>
- <argument index="0" name="obj" type="Object">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="OptionButton" inherits="Button" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="add_item" >
- <argument index="0" name="label" type="String">
- </argument>
- <argument index="1" name="id" type="int" default="-1">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_icon_item" >
- <argument index="0" name="texture" type="Texture">
- </argument>
- <argument index="1" name="label" type="String">
- </argument>
- <argument index="2" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_item_text" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="text" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_item_icon" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="texture" type="Texture">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_item_disabled" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="disabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_item_ID" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_item_metadata" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="metadata" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_item_text" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_item_icon" qualifiers="const" >
- <return type="Texture">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_item_ID" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_item_metadata" qualifiers="const" >
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_item_disabled" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_item_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="add_separator" >
- <description>
- </description>
- </method>
- <method name="clear" >
- <description>
- </description>
- </method>
- <method name="select" >
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_selected" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_selected_ID" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_selected_metadata" qualifiers="const" >
- <description>
- </description>
- </method>
- <method name="remove_item" >
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="item_selected">
- <argument index="0" name="ID" type="int">
- </argument>
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="PHashTranslation" inherits="Translation" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="PacketPeer" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="PacketPeerStream" inherits="PacketPeer" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_stream_peer" >
- <argument index="0" name="peer" type="StreamPeer">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Panel" inherits="Control" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="ParallaxBackground" inherits="CanvasLayer" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_scroll_offset" >
- <argument index="0" name="ofs" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_scroll_offset" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="set_scroll_base_offset" >
- <argument index="0" name="ofs" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_scroll_base_offset" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="set_scroll_base_scale" >
- <argument index="0" name="scale" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_scroll_base_scale" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="set_limit_begin" >
- <argument index="0" name="ofs" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_limit_begin" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="set_limit_end" >
- <argument index="0" name="ofs" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_limit_end" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="ParallaxLayer" inherits="Node2D" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_motion_scale" >
- <argument index="0" name="scale" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_motion_scale" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="set_motion_wrap_begin" >
- <argument index="0" name="wrap_begin" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_motion_wrap_begin" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="set_motion_wrap_end" >
- <argument index="0" name="wrap_end" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_motion_wrap_end" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Particles" inherits="VisualInstance" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_amount" >
- <argument index="0" name="amount" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_amount" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_emitting" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_emitting" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_visibility_aabb" >
- <argument index="0" name="aabb" type="AABB">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_visibility_aabb" qualifiers="const" >
- <return type="AABB">
- </return>
- <description>
- </description>
- </method>
- <method name="set_emission_half_extents" >
- <argument index="0" name="half_extents" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_emission_half_extents" qualifiers="const" >
- <return type="Vector3">
- </return>
- <description>
- </description>
- </method>
- <method name="set_emission_base_velocity" >
- <argument index="0" name="base_velocity" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_emission_base_velocity" qualifiers="const" >
- <return type="Vector3">
- </return>
- <description>
- </description>
- </method>
- <method name="set_emission_points" >
- <argument index="0" name="points" type="Vector3Array">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_emission_points" qualifiers="const" >
- <return type="Vector3Array">
- </return>
- <description>
- </description>
- </method>
- <method name="set_gravity_normal" >
- <argument index="0" name="normal" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_gravity_normal" qualifiers="const" >
- <return type="Vector3">
- </return>
- <description>
- </description>
- </method>
- <method name="set_variable" >
- <argument index="0" name="variable" type="int">
- </argument>
- <argument index="1" name="value" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_variable" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="variable" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_randomness" >
- <argument index="0" name="variable" type="int">
- </argument>
- <argument index="1" name="randomness" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_randomness" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_color_phase_pos" >
- <argument index="0" name="phase" type="int">
- </argument>
- <argument index="1" name="pos" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_color_phase_pos" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="phase" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_color_phase_color" >
- <argument index="0" name="phase" type="int">
- </argument>
- <argument index="1" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_color_phase_color" qualifiers="const" >
- <return type="Color">
- </return>
- <argument index="0" name="phase" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_material" >
- <argument index="0" name="material" type="Material">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_material" qualifiers="const" >
- <return type="Material">
- </return>
- <description>
- </description>
- </method>
- <method name="set_emit_timeout" >
- <argument index="0" name="arg0" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_emit_timeout" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_height_from_velocity" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_height_from_velocity" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_color_phases" >
- <argument index="0" name="count" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_color_phases" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="VAR_LIFETIME" value="0">
- </constant>
- <constant name="VAR_SPREAD" value="1">
- </constant>
- <constant name="VAR_GRAVITY" value="2">
- </constant>
- <constant name="VAR_LINEAR_VELOCITY" value="3">
- </constant>
- <constant name="VAR_ANGULAR_VELOCITY" value="4">
- </constant>
- <constant name="VAR_LINEAR_ACCELERATION" value="5">
- </constant>
- <constant name="VAR_DRAG" value="6">
- </constant>
- <constant name="VAR_TANGENTIAL_ACCELERATION" value="7">
- </constant>
- <constant name="VAR_INITIAL_SIZE" value="9">
- </constant>
- <constant name="VAR_FINAL_SIZE" value="10">
- </constant>
- <constant name="VAR_INITIAL_ANGLE" value="11">
- </constant>
- <constant name="VAR_HEIGHT" value="12">
- </constant>
- <constant name="VAR_HEIGHT_SPEED_SCALE" value="13">
- </constant>
- <constant name="VAR_MAX" value="14">
- </constant>
- </constants>
-</class>
-<class name="Particles2D" inherits="Node2D" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_emitting" >
- <argument index="0" name="active" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_emitting" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_amount" >
- <argument index="0" name="amount" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_amount" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_lifetime" >
- <argument index="0" name="lifetime" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_lifetime" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_pre_process_time" >
- <argument index="0" name="time" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_pre_process_time" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_emit_timeout" >
- <argument index="0" name="value" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_emit_timeout" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_param" >
- <argument index="0" name="param" type="int">
- </argument>
- <argument index="1" name="value" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_param" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="param" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_randomness" >
- <argument index="0" name="param" type="int">
- </argument>
- <argument index="1" name="value" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_randomness" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="param" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_texture" >
- <argument index="0" name="texture" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_texture" qualifiers="const" >
- <return type="Texture">
- </return>
- <description>
- </description>
- </method>
- <method name="set_emissor_offset" >
- <argument index="0" name="offset" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_emissor_offset" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="set_emission_half_extents" >
- <argument index="0" name="extents" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_emission_half_extents" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="set_color_phases" >
- <argument index="0" name="phases" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_color_phases" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_color_phase_color" >
- <argument index="0" name="phase" type="int">
- </argument>
- <argument index="1" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_color_phase_color" qualifiers="const" >
- <return type="Color">
- </return>
- <argument index="0" name="phase" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_color_phase_pos" >
- <argument index="0" name="phase" type="int">
- </argument>
- <argument index="1" name="pos" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_color_phase_pos" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="phase" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="pre_process" >
- <argument index="0" name="time" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_use_local_space" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_using_local_space" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_initial_velocity" >
- <argument index="0" name="velocity" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_initial_velocity" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="testee" >
- <argument index="0" name="arg0" type="int" default="0">
- </argument>
- <argument index="1" name="arg1" type="int" default="1">
- </argument>
- <argument index="2" name="arg2" type="int" default="2">
- </argument>
- <argument index="3" name="arg3" type="int" default="3">
- </argument>
- <argument index="4" name="arg4" type="int" default="4">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="PARAM_DIRECTION" value="0">
- </constant>
- <constant name="PARAM_SPREAD" value="1">
- </constant>
- <constant name="PARAM_LINEAR_VELOCITY" value="2">
- </constant>
- <constant name="PARAM_SPIN_VELOCITY" value="3">
- </constant>
- <constant name="PARAM_GRAVITY_DIRECTION" value="4">
- </constant>
- <constant name="PARAM_GRAVITY_STRENGTH" value="5">
- </constant>
- <constant name="PARAM_RADIAL_ACCEL" value="6">
- </constant>
- <constant name="PARAM_TANGENTIAL_ACCEL" value="7">
- </constant>
- <constant name="PARAM_INITIAL_SIZE" value="9">
- </constant>
- <constant name="PARAM_FINAL_SIZE" value="10">
- </constant>
- <constant name="PARAM_HUE_VARIATION" value="11">
- </constant>
- <constant name="PARAM_MAX" value="12">
- </constant>
- <constant name="MAX_COLOR_PHASES" value="4">
- </constant>
- </constants>
-</class>
-<class name="PathRemap" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="add_remap" >
- <argument index="0" name="from" type="String">
- </argument>
- <argument index="1" name="to" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_remap" >
- <argument index="0" name="path" type="String">
- </argument>
- <argument index="1" name="arg1" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_remap" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="path" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="erase_remap" >
- <argument index="0" name="path" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear_remaps" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Physics2DDirectBodyState" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="get_total_gravity" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="get_total_density" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_inverse_mass" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_inverse_inertia" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_linear_velocity" >
- <argument index="0" name="velocity" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_linear_velocity" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="set_angular_velocity" >
- <argument index="0" name="velocity" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_angular_velocity" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_transform" >
- <argument index="0" name="transform" type="Matrix32">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_transform" qualifiers="const" >
- <return type="Matrix32">
- </return>
- <description>
- </description>
- </method>
- <method name="set_sleep_state" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_sleeping" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_contact_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_contact_local_pos" qualifiers="const" >
- <return type="Vector2">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_contact_local_normal" qualifiers="const" >
- <return type="Vector2">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_contact_local_shape" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_contact_collider" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_contact_collider_pos" qualifiers="const" >
- <return type="Vector2">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_contact_collider_id" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_contact_collider_object" qualifiers="const" >
- <return type="Object">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_contact_collider_shape" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_contact_collider_velocity_at_pos" qualifiers="const" >
- <return type="Vector2">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_step" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="integrate_forces" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Physics2DDirectBodyStateSW" inherits="Physics2DDirectBodyState" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Physics2DServer" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="shape_create" >
- <return type="RID">
- </return>
- <argument index="0" name="type" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="shape_set_data" >
- <argument index="0" name="shape" type="RID">
- </argument>
- <argument index="1" name="data" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="shape_get_type" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="shape" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="shape_get_data" qualifiers="const" >
- <argument index="0" name="shape" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="space_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="space_set_active" >
- <argument index="0" name="space" type="RID">
- </argument>
- <argument index="1" name="active" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="space_is_active" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="space" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="space_set_param" >
- <argument index="0" name="space" type="RID">
- </argument>
- <argument index="1" name="param" type="int">
- </argument>
- <argument index="2" name="value" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="space_get_param" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="space" type="RID">
- </argument>
- <argument index="1" name="param" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="area_set_space" >
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="space" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_get_space" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_add_shape" >
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="shape" type="int">
- </argument>
- <argument index="2" name="transform" type="RID" default="1,0, 0,1, 0,0">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_set_shape" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_set_shape_transform" >
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <argument index="2" name="transform" type="Matrix32">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_get_shape_count" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_get_shape" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_get_shape_transform" qualifiers="const" >
- <return type="Matrix32">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_remove_shape" >
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_clear_shapes" >
- <argument index="0" name="area" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_set_param" qualifiers="const" >
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="param" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_set_transform" qualifiers="const" >
- <return type="Matrix32">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_get_param" qualifiers="const" >
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="param" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_get_transform" qualifiers="const" >
- <return type="Matrix32">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_attach_object_instance_ID" >
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_get_object_instance_ID" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_create" >
- <return type="RID">
- </return>
- <argument index="0" name="mode" type="int" default="1">
- </argument>
- <argument index="1" name="init_sleeping" type="bool" default="false">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_space" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="space" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_space" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_mode" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_mode" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_add_shape" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape" type="RID">
- </argument>
- <argument index="2" name="transform" type="Matrix32" default="1,0, 0,1, 0,0">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_shape" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <argument index="2" name="shape" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_shape_transform" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <argument index="2" name="transform" type="Matrix32">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_shape_count" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_shape" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_shape_transform" qualifiers="const" >
- <return type="Matrix32">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_remove_shape" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_clear_shapes" >
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_attach_object_instance_ID" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_object_instance_ID" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_enable_continuous_collision_detection" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_is_continuous_collision_detection_enabled" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_param" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="param" type="int">
- </argument>
- <argument index="2" name="value" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_param" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="param" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_static_simulate_motion" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="new_xform" type="Matrix32">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_state" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="state" type="int">
- </argument>
- <argument index="2" name="value" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_state" qualifiers="const" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="state" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_apply_impulse" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="pos" type="Vector2">
- </argument>
- <argument index="2" name="impulse" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_axis_velocity" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="axis_velocity" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_add_collision_exception" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="excepted_body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_remove_collision_exception" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="excepted_body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_max_contacts_reported" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="amount" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_max_contacts_reported" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_omit_force_integration" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_is_omitting_force_integration" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="pin_joint_create" >
- <return type="RID">
- </return>
- <argument index="0" name="anchor" type="Vector2">
- </argument>
- <argument index="1" name="body_a" type="RID">
- </argument>
- <argument index="2" name="body_b" type="RID" default="RID()">
- </argument>
- <description>
- </description>
- </method>
- <method name="groove_joint_create" >
- <return type="RID">
- </return>
- <argument index="0" name="groove1_a" type="Vector2">
- </argument>
- <argument index="1" name="groove2_a" type="Vector2">
- </argument>
- <argument index="2" name="anchor_b" type="Vector2">
- </argument>
- <argument index="3" name="body_a" type="RID" default="RID()">
- </argument>
- <argument index="4" name="body_b" type="RID" default="RID()">
- </argument>
- <description>
- </description>
- </method>
- <method name="damped_spring_joint_create" >
- <return type="RID">
- </return>
- <argument index="0" name="anchor_a" type="Vector2">
- </argument>
- <argument index="1" name="anchor_b" type="Vector2">
- </argument>
- <argument index="2" name="body_a" type="RID">
- </argument>
- <argument index="3" name="body_b" type="RID" default="RID()">
- </argument>
- <description>
- </description>
- </method>
- <method name="damped_string_joint_set_param" >
- <argument index="0" name="joint" type="RID">
- </argument>
- <argument index="1" name="param" type="int">
- </argument>
- <argument index="2" name="value" type="real" default="RID()">
- </argument>
- <description>
- </description>
- </method>
- <method name="damped_string_joint_get_param" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="joint" type="RID">
- </argument>
- <argument index="1" name="param" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="joint_get_type" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="joint" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_create" >
- <return type="RID">
- </return>
- <argument index="0" name="receiver" type="Object">
- </argument>
- <argument index="1" name="callback" type="String">
- </argument>
- <argument index="2" name="userdata" type="var" default="NULL">
- </argument>
- <argument index="3" name="persist" type="bool" default="true">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_body_state" >
- <argument index="0" name="query" type="RID">
- </argument>
- <argument index="1" name="body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_body_direct_state" >
- <argument index="0" name="query" type="RID">
- </argument>
- <argument index="1" name="body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_area" >
- <argument index="0" name="query" type="RID">
- </argument>
- <argument index="1" name="area" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_intersection" >
- <argument index="0" name="query" type="RID">
- </argument>
- <argument index="1" name="space" type="RID">
- </argument>
- <argument index="2" name="notify_hint_only" type="bool" default="false">
- </argument>
- <argument index="3" name="exclude" type="Array" default="Array()">
- </argument>
- <argument index="4" name="usermask" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_intersection_ray" >
- <argument index="0" name="query" type="RID">
- </argument>
- <argument index="1" name="from" type="Vector2">
- </argument>
- <argument index="2" name="dir" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_intersection_segment" >
- <argument index="0" name="query" type="RID">
- </argument>
- <argument index="1" name="from" type="Vector2">
- </argument>
- <argument index="2" name="to" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_intersection_shape" >
- <argument index="0" name="query" type="RID">
- </argument>
- <argument index="1" name="shape" type="RID">
- </argument>
- <argument index="2" name="transform" type="Matrix32">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_clear" >
- <argument index="0" name="query" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_get_type" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="query" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_get_target" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="query" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="free" >
- <argument index="0" name="rid" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_active" >
- <argument index="0" name="active" type="bool">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="SHAPE_LINE" value="0">
- </constant>
- <constant name="SHAPE_SEGMENT" value="1">
- </constant>
- <constant name="SHAPE_CIRCLE" value="2">
- </constant>
- <constant name="SHAPE_RECTANGLE" value="3">
- </constant>
- <constant name="SHAPE_CAPSULE" value="4">
- </constant>
- <constant name="SHAPE_CONVEX_POLYGON" value="5">
- </constant>
- <constant name="SHAPE_CONCAVE_POLYGON" value="6">
- </constant>
- <constant name="SHAPE_CUSTOM" value="7">
- </constant>
- <constant name="AREA_PARAM_OVERRIDE_PARAMS" value="0">
- </constant>
- <constant name="AREA_PARAM_GRAVITY" value="1">
- </constant>
- <constant name="AREA_PARAM_GRAVITY_VECTOR" value="2">
- </constant>
- <constant name="AREA_PARAM_GRAVITY_IS_POINT" value="3">
- </constant>
- <constant name="AREA_PARAM_GRAVITY_POINT_ATTENUATION" value="4">
- </constant>
- <constant name="AREA_PARAM_DENSITY" value="5">
- </constant>
- <constant name="AREA_PARAM_PRIORITY" value="6">
- </constant>
- <constant name="BODY_MODE_STATIC" value="0">
- </constant>
- <constant name="BODY_MODE_RIGID" value="1">
- </constant>
- <constant name="BODY_MODE_CHARACTER" value="2">
- </constant>
- <constant name="BODY_PARAM_BOUNCE" value="0">
- </constant>
- <constant name="BODY_PARAM_FRICTION" value="1">
- </constant>
- <constant name="BODY_PARAM_MASS" value="2">
- </constant>
- <constant name="BODY_PARAM_MAX" value="3">
- </constant>
- <constant name="BODY_STATE_TRANSFORM" value="0">
- </constant>
- <constant name="BODY_STATE_LINEAR_VELOCITY" value="1">
- </constant>
- <constant name="BODY_STATE_ANGULAR_VELOCITY" value="2">
- </constant>
- <constant name="BODY_STATE_SLEEPING" value="3">
- </constant>
- <constant name="JOINT_PIN" value="0">
- </constant>
- <constant name="JOINT_GROOVE" value="1">
- </constant>
- <constant name="JOINT_DAMPED_SPRING" value="2">
- </constant>
- <constant name="DAMPED_STRING_REST_LENGTH" value="0">
- </constant>
- <constant name="DAMPED_STRING_STIFFNESS" value="1">
- </constant>
- <constant name="DAMPED_STRING_DAMPING" value="2">
- </constant>
- <constant name="TYPE_BODY" value="0">
- </constant>
- <constant name="TYPE_AREA" value="1">
- </constant>
- <constant name="AREA_BODY_ADDED" value="0">
- </constant>
- <constant name="AREA_BODY_REMOVED" value="1">
- </constant>
- <constant name="QUERY_NONE" value="0">
- </constant>
- <constant name="QUERY_BODY_STATE" value="1">
- </constant>
- <constant name="QUERY_BODY_DIRECT_STATE" value="2">
- </constant>
- <constant name="QUERY_AREA_MONITOR" value="3">
- </constant>
- <constant name="QUERY_INTERSECTION" value="4">
- </constant>
- </constants>
-</class>
-<class name="Physics2DServerSW" inherits="Physics2DServer" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="PhysicsBody" inherits="Spatial" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="add_shape" >
- <argument index="0" name="shape" type="Shape">
- </argument>
- <argument index="1" name="transform" type="Transform" default="Transform()">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_shape_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_shape" >
- <argument index="0" name="shape_idx" type="int">
- </argument>
- <argument index="1" name="shape" type="Shape">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_shape_transform" >
- <argument index="0" name="shape_idx" type="int">
- </argument>
- <argument index="1" name="transform" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_shape" qualifiers="const" >
- <return type="Shape">
- </return>
- <argument index="0" name="shape_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_shape_transform" qualifiers="const" >
- <return type="Transform">
- </return>
- <argument index="0" name="shape_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="remove_shape" >
- <argument index="0" name="shape_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear_shapes" >
- <description>
- </description>
- </method>
- <method name="get_body" qualifiers="const" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="set_max_contacts_reported" >
- <argument index="0" name="contacts" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_max_contacts_reported" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_contacts_reported_depth_treshold" >
- <argument index="0" name="depth" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_contacts_reported_depth_treshold" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="PhysicsBody2D" inherits="CollisionObject2D" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="PhysicsDirectBodyState" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="get_total_gravity" qualifiers="const" >
- <return type="Vector3">
- </return>
- <description>
- </description>
- </method>
- <method name="get_total_density" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_inverse_mass" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_inverse_inertia_tensor" qualifiers="const" >
- <return type="Matrix3">
- </return>
- <description>
- </description>
- </method>
- <method name="set_linear_velocity" >
- <argument index="0" name="velocity" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_linear_velocity" qualifiers="const" >
- <return type="Vector3">
- </return>
- <description>
- </description>
- </method>
- <method name="set_angular_velocity" >
- <argument index="0" name="velocity" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_angular_velocity" qualifiers="const" >
- <return type="Vector3">
- </return>
- <description>
- </description>
- </method>
- <method name="set_transform" >
- <argument index="0" name="transform" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_transform" qualifiers="const" >
- <return type="Transform">
- </return>
- <description>
- </description>
- </method>
- <method name="set_sleep_state" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_sleeping" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_contact_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_contact_local_pos" qualifiers="const" >
- <return type="Vector3">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_contact_local_normal" qualifiers="const" >
- <return type="Vector3">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_contact_local_shape" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_contact_collider" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_contact_collider_pos" qualifiers="const" >
- <return type="Vector3">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_contact_collider_id" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_contact_collider_shape" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_contact_collider_velocity_at_pos" qualifiers="const" >
- <return type="Vector3">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="PhysicsDirectBodyStateSW" inherits="PhysicsDirectBodyState" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="PhysicsServer" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="shape_create" >
- <return type="RID">
- </return>
- <argument index="0" name="shape_type" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="shape_set_data" >
- <argument index="0" name="shape" type="RID">
- </argument>
- <argument index="1" name="data" type="var" default="-1">
- </argument>
- <description>
- </description>
- </method>
- <method name="shape_get_type" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="shape" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="shape_get_data" qualifiers="const" >
- <argument index="0" name="shape" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="space_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="area_create" >
- <return type="RID">
- </return>
- <argument index="0" name="space" type="int">
- </argument>
- <argument index="1" name="arg1" type="bool" default="RID()">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_set_param" >
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="param" type="int">
- </argument>
- <argument index="2" name="value" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_set_shape" >
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="shape" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_set_bounds" >
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="bounds" type="Dictionary">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_set_transform" >
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="transform" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_get_param" qualifiers="const" >
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="param" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_get_shape" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_get_bounds" qualifiers="const" >
- <return type="Dictionary">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_get_transform" qualifiers="const" >
- <return type="Transform">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_create" >
- <return type="RID">
- </return>
- <argument index="0" name="space" type="int">
- </argument>
- <argument index="1" name="arg1" type="bool" default="RID()">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_mode" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_mode" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_add_shape" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape" type="RID">
- </argument>
- <argument index="2" name="transform" type="Transform" default="Transform()">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_shape" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <argument index="2" name="shape" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_shape_transform" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <argument index="2" name="transform" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_shape_count" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_shape" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_shape_transform" qualifiers="const" >
- <return type="Transform">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_attach_object_instance_ID" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="ID" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_object_instance_ID" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_user_flags" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="user_flags" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_user_flags" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_param" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="param" type="int">
- </argument>
- <argument index="2" name="value" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_param" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="param" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_static_simulate_motion" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="motion" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_state" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="state" type="int">
- </argument>
- <argument index="2" name="value" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_state" qualifiers="const" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="state" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_applied_force" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="applied_force" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_applied_force" qualifiers="const" >
- <return type="Vector3">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_applied_torque" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="applied_torque" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_applied_torque" qualifiers="const" >
- <return type="Vector3">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_axis_velocity" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="axis_velocity" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_apply_impulse" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="pos" type="Vector3">
- </argument>
- <argument index="2" name="impulse" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_add_collision_exception" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="against_body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_remove_collision_exception" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="against_body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_create" >
- <return type="RID">
- </return>
- <argument index="0" name="receiver" type="Object">
- </argument>
- <argument index="1" name="callback" type="String">
- </argument>
- <argument index="2" name="userdata" type="var">
- </argument>
- <argument index="3" name="persist" type="bool" default="true">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_body_state" >
- <argument index="0" name="query" type="RID">
- </argument>
- <argument index="1" name="body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_body_direct_state" >
- <argument index="0" name="query" type="RID">
- </argument>
- <argument index="1" name="body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_area" >
- <argument index="0" name="query" type="RID">
- </argument>
- <argument index="1" name="area" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_intersection" >
- <argument index="0" name="query" type="RID">
- </argument>
- <argument index="1" name="space" type="RID">
- </argument>
- <argument index="2" name="exclude" type="Array" default="Array()">
- </argument>
- <argument index="3" name="usermask" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_intersection_ray" >
- <argument index="0" name="query" type="RID">
- </argument>
- <argument index="1" name="origin" type="Vector3">
- </argument>
- <argument index="2" name="dir" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_intersection_segment" >
- <argument index="0" name="query" type="RID">
- </argument>
- <argument index="1" name="from" type="Vector3">
- </argument>
- <argument index="2" name="to" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_intersection_shape" >
- <argument index="0" name="query" type="RID">
- </argument>
- <argument index="1" name="shape" type="RID">
- </argument>
- <argument index="2" name="arg2" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_intersection_bounds" >
- <argument index="0" name="query" type="RID">
- </argument>
- <argument index="1" name="bounds" type="Dictionary">
- </argument>
- <argument index="2" name="arg2" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_clear" >
- <argument index="0" name="query" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_get_type" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="query" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_get_target" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="query" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="free" >
- <argument index="0" name="rid" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_active" >
- <argument index="0" name="active" type="bool">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="SHAPE_PLANE" value="0">
- </constant>
- <constant name="SHAPE_SPHERE" value="2">
- </constant>
- <constant name="SHAPE_BOX" value="3">
- </constant>
- <constant name="SHAPE_CAPSULE" value="4">
- </constant>
- <constant name="SHAPE_CONVEX_POLYGON" value="5">
- </constant>
- <constant name="SHAPE_CONCAVE_POLYGON" value="6">
- </constant>
- <constant name="SHAPE_HEIGHTMAP" value="7">
- </constant>
- <constant name="SHAPE_CUSTOM" value="8">
- </constant>
- <constant name="AREA_PARAM_OVERRIDE_PARAMS" value="0">
- </constant>
- <constant name="AREA_PARAM_GRAVITY" value="1">
- </constant>
- <constant name="AREA_PARAM_GRAVITY_VECTOR" value="2">
- </constant>
- <constant name="AREA_PARAM_GRAVITY_IS_POINT" value="3">
- </constant>
- <constant name="AREA_PARAM_GRAVITY_POINT_ATTENUATION" value="4">
- </constant>
- <constant name="AREA_PARAM_DENSITY" value="5">
- </constant>
- <constant name="AREA_PARAM_PRIORITY" value="6">
- </constant>
- <constant name="BODY_MODE_STATIC" value="0">
- </constant>
- <constant name="BODY_MODE_RIGID" value="1">
- </constant>
- <constant name="BODY_MODE_CHARACTER" value="2">
- </constant>
- <constant name="BODY_PARAM_BOUNCE" value="0">
- </constant>
- <constant name="BODY_PARAM_FRICTION" value="1">
- </constant>
- <constant name="BODY_PARAM_MASS" value="2">
- </constant>
- <constant name="BODY_STATE_TRANSFORM" value="0">
- </constant>
- <constant name="BODY_STATE_LINEAR_VELOCITY" value="1">
- </constant>
- <constant name="BODY_STATE_ANGULAR_VELOCITY" value="2">
- </constant>
- <constant name="BODY_STATE_SLEEPING" value="3">
- </constant>
- <constant name="HINGE_VAR_ANGULAR_ONLY" value="0">
- </constant>
- <constant name="HINGE_VAR_LOWER_LIMIT" value="1">
- </constant>
- <constant name="HINGE_VAR_HIGHER_LIMIT" value="2">
- </constant>
- <constant name="HINGE_VAR_LIMIT_SOFTNESS" value="3">
- </constant>
- <constant name="HINGE_VAR_RELAXATION" value="4">
- </constant>
- <constant name="HINGE_VAR_MOTOR_ENABLED" value="5">
- </constant>
- <constant name="HINGE_VAR_MOTOR_TARGET_VELOCITY" value="6">
- </constant>
- <constant name="HINGE_VAR_MOTOR_IMPULSE" value="7">
- </constant>
- <constant name="CONE_TWIST_VAR_SWING_SPAN_LIMIT_1" value="0">
- </constant>
- <constant name="CONE_TWIST_VAR_SWING_SPAN_LIMIT_2" value="1">
- </constant>
- <constant name="CONE_TWIST_VAR_TWIST_SPAN_LIMIT" value="2">
- </constant>
- <constant name="CONE_TWIST_VAR_BIAS" value="3">
- </constant>
- <constant name="CONE_TWIST_VAR_RELAXATION" value="4">
- </constant>
- <constant name="TYPE_BODY" value="0">
- </constant>
- <constant name="TYPE_AREA" value="1">
- </constant>
- <constant name="QUERY_NONE" value="0">
- </constant>
- <constant name="QUERY_BODY_STATE" value="1">
- </constant>
- <constant name="QUERY_BODY_DIRECT_STATE" value="2">
- </constant>
- <constant name="QUERY_AREA_MONITOR" value="3">
- </constant>
- <constant name="QUERY_INTERSECTION" value="4">
- </constant>
- </constants>
-</class>
-<class name="PhysicsServerSW" inherits="PhysicsServer" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="PinJoint2D" inherits="Joint2D" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="PlaneShape" inherits="Shape" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_plane" >
- <argument index="0" name="plane" type="Plane">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_plane" qualifiers="const" >
- <return type="Plane">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Popup" inherits="Control" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="popup_centered" >
- <argument index="0" name="size" type="Vector2" default="Vector2(0,0)">
- </argument>
- <description>
- </description>
- </method>
- <method name="popup_centered_ratio" >
- <argument index="0" name="ratio" type="real" default="0.75">
- </argument>
- <description>
- </description>
- </method>
- <method name="popup_centered_minsize" >
- <argument index="0" name="minsize" type="Vector2" default="Vector2(0,0)">
- </argument>
- <description>
- </description>
- </method>
- <method name="popup" >
- <description>
- </description>
- </method>
- <method name="set_exclusive" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_exclusive" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="about_to_show">
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- <constant name="NOTIFICATION_POST_POPUP" value="80">
- </constant>
- </constants>
-</class>
-<class name="PopupDialog" inherits="Popup" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="PopupMenu" inherits="Popup" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="add_icon_item" >
- <argument index="0" name="texture" type="Object">
- </argument>
- <argument index="1" name="label" type="String">
- </argument>
- <argument index="2" name="id" type="int" default="-1">
- </argument>
- <argument index="3" name="accel" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_item" >
- <argument index="0" name="label" type="String">
- </argument>
- <argument index="1" name="id" type="int" default="-1">
- </argument>
- <argument index="2" name="accel" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_icon_check_item" >
- <argument index="0" name="texture" type="Object">
- </argument>
- <argument index="1" name="label" type="String">
- </argument>
- <argument index="2" name="id" type="int" default="-1">
- </argument>
- <argument index="3" name="accel" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_check_item" >
- <argument index="0" name="label" type="String">
- </argument>
- <argument index="1" name="id" type="int" default="-1">
- </argument>
- <argument index="2" name="accel" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_submenu_item" >
- <argument index="0" name="label" type="String">
- </argument>
- <argument index="1" name="submenu" type="int">
- </argument>
- <argument index="2" name="id" type="int" default="-1">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_item_text" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="text" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_item_icon" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="icon" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_item_accelerator" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="accel" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_item_metadata" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="metadata" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_item_checked" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="arg1" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_item_disabled" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="disabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_item_submenu" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="submenu" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_item_as_separator" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_item_as_checkable" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_item_ID" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_item_text" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_item_icon" qualifiers="const" >
- <return type="Object">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_item_metadata" qualifiers="const" >
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_item_accelerator" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_item_submenu" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_item_separator" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_item_checkable" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_item_checked" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_item_disabled" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_item_ID" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_item_index" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_item_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="add_separator" >
- <description>
- </description>
- </method>
- <method name="remove_item" >
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear" >
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="item_pressed">
- <argument index="0" name="ID" type="int">
- </argument>
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="PopupPanel" inherits="Popup" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Portal" inherits="VisualInstance" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_shape" >
- <argument index="0" name="points" type="Vector2Array">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_shape" qualifiers="const" >
- <return type="Vector2Array">
- </return>
- <description>
- </description>
- </method>
- <method name="set_enabled" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_enabled" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_disable_distance" >
- <argument index="0" name="distance" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_disable_distance" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_disabled_color" >
- <argument index="0" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_disabled_color" qualifiers="const" >
- <return type="Color">
- </return>
- <description>
- </description>
- </method>
- <method name="set_connect_range" >
- <argument index="0" name="range" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_connect_range" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Position2D" inherits="Node2D" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Position3D" inherits="Spatial" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="ProximityGroup" inherits="Spatial" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_group_name" >
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="broadcast" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="parameters" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_dispatch_mode" >
- <argument index="0" name="mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_grid_radius" >
- <argument index="0" name="radius" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_grid_radius" qualifiers="const" >
- <return type="Vector3">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="broadcast">
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="parameters" type="Array">
- </argument>
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="ProximityGroup2D" inherits="Node2D" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_group_size" >
- <argument index="0" name="size" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_group_size" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_group_notifym" >
- <argument index="0" name="notify" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_group_notify" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="grouped">
- <argument index="0" name="pgroup" type="Object">
- </argument>
- <description>
- </description>
- </signal>
- <signal name="ungrouped">
- <argument index="0" name="pgroup" type="Object">
- </argument>
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="Range" inherits="Control" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="get_val" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_value" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_min" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_max" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_step" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_page" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_unit_value" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_rounded_values" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_val" >
- <argument index="0" name="value" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_value" >
- <argument index="0" name="value" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_min" >
- <argument index="0" name="minimum" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_max" >
- <argument index="0" name="maximum" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_step" >
- <argument index="0" name="step" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_page" >
- <argument index="0" name="pagesize" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_unit_value" >
- <argument index="0" name="value" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_rounded_values" >
- <argument index="0" name="arg0" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_exp_unit_value" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_unit_value_exp" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="share" >
- <argument index="0" name="with" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="unshare" >
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="value_changed">
- <argument index="0" name="value" type="real">
- </argument>
- <description>
- </description>
- </signal>
- <signal name="changed">
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="RayShape" inherits="Shape" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_length" >
- <argument index="0" name="length" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_length" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="RectangleShape2D" inherits="Shape2D" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_extents" >
- <argument index="0" name="extents" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_extents" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Reference" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="init_ref" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="reference" >
- <description>
- </description>
- </method>
- <method name="unreference" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="ReferenceFrame" inherits="Control" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Resource" inherits="Reference" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_path" >
- <argument index="0" name="path" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_path" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="set_name" >
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_name" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="get_rid" qualifiers="const" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="changed">
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="_ResourceLoader" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="load" >
- <return type="Resource">
- </return>
- <argument index="0" name="path" type="String">
- </argument>
- <argument index="1" name="type_hint" type="String" default="&quot;&quot;">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_recognized_extensions_for_type" >
- <return type="StringArray">
- </return>
- <argument index="0" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="ResourcePreloader" inherits="Node" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="add_resource" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="resource" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="remove_resource" >
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="rename_resource" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="newname" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_resource" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_resource" qualifiers="const" >
- <return type="Object">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_resource_list" qualifiers="const" >
- <return type="StringArray">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="_ResourceSaver" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="save" >
- <return type="int">
- </return>
- <argument index="0" name="path" type="String">
- </argument>
- <argument index="1" name="resource" type="Resource">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_recognized_extensions" >
- <return type="StringArray">
- </return>
- <argument index="0" name="type" type="Object">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="RichTextLabel" inherits="Control" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="add_text" >
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_image" >
- <argument index="0" name="image" type="Texture">
- </argument>
- <description>
- </description>
- </method>
- <method name="newline" >
- <description>
- </description>
- </method>
- <method name="push_font" >
- <argument index="0" name="font" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="push_color" >
- <argument index="0" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="push_align" >
- <argument index="0" name="align" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="push_indent" >
- <argument index="0" name="level" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="push_list" >
- <argument index="0" name="type" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="push_meta" >
- <argument index="0" name="data" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="push_underline" >
- <description>
- </description>
- </method>
- <method name="pop" >
- <description>
- </description>
- </method>
- <method name="clear" >
- <description>
- </description>
- </method>
- <method name="set_meta_underline" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_meta_underlined" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_scroll_active" >
- <argument index="0" name="active" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_scroll_active" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_scroll_follow" >
- <argument index="0" name="follow" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_scroll_following" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_tab_size" >
- <argument index="0" name="spaces" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_tab_size" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="meta_clicked">
- <argument index="0" name="meta" type="Nil">
- </argument>
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- <constant name="ALIGN_LEFT" value="0">
- </constant>
- <constant name="ALIGN_CENTER" value="1">
- </constant>
- <constant name="ALIGN_RIGHT" value="2">
- </constant>
- <constant name="ALIGN_FILL" value="3">
- </constant>
- <constant name="LIST_NUMBERS" value="0">
- </constant>
- <constant name="LIST_LETTERS" value="1">
- </constant>
- <constant name="LIST_DOTS" value="2">
- </constant>
- <constant name="ITEM_MAIN" value="0">
- </constant>
- <constant name="ITEM_TEXT" value="1">
- </constant>
- <constant name="ITEM_IMAGE" value="2">
- </constant>
- <constant name="ITEM_NEWLINE" value="3">
- </constant>
- <constant name="ITEM_FONT" value="4">
- </constant>
- <constant name="ITEM_COLOR" value="5">
- </constant>
- <constant name="ITEM_UNDERLINE" value="6">
- </constant>
- <constant name="ITEM_ALIGN" value="7">
- </constant>
- <constant name="ITEM_INDENT" value="8">
- </constant>
- <constant name="ITEM_LIST" value="9">
- </constant>
- <constant name="ITEM_META" value="10">
- </constant>
- </constants>
-</class>
-<class name="RigidBody2D" inherits="PhysicsBody2D" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_mode" >
- <argument index="0" name="mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_mode" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_mass" >
- <argument index="0" name="mass" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_mass" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_weight" >
- <argument index="0" name="weight" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_weight" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_friction" >
- <argument index="0" name="friction" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_friction" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_bounce" >
- <argument index="0" name="bounce" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_bounce" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_linear_velocity" >
- <argument index="0" name="linear_velocity" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_linear_velocity" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="set_angular_velocity" >
- <argument index="0" name="angular_velocity" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_angular_velocity" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_max_contacts_reported" >
- <argument index="0" name="amount" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_max_contacts_reported" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_use_custom_integrator" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_using_custom_integrator" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_contact_monitor" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_contact_monitor_enabled" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_use_continuous_collision_detection" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_using_continuous_collision_detection" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_axis_velocity" >
- <argument index="0" name="axis_velocity" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="apply_impulse" >
- <argument index="0" name="pos" type="Vector2">
- </argument>
- <argument index="1" name="impulse" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_active" >
- <argument index="0" name="active" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_active" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="body_enter">
- <argument index="0" name="body_id" type="int">
- </argument>
- <argument index="1" name="body" type="Object">
- </argument>
- <description>
- </description>
- </signal>
- <signal name="body_enter_shape">
- <argument index="0" name="body_id" type="int">
- </argument>
- <argument index="1" name="body" type="Object">
- </argument>
- <argument index="2" name="body_shape" type="int">
- </argument>
- <argument index="3" name="local_shape" type="int">
- </argument>
- <description>
- </description>
- </signal>
- <signal name="body_exit">
- <argument index="0" name="body_id" type="int">
- </argument>
- <argument index="1" name="body" type="Object">
- </argument>
- <description>
- </description>
- </signal>
- <signal name="body_exit_shape">
- <argument index="0" name="body_id" type="int">
- </argument>
- <argument index="1" name="body" type="Object">
- </argument>
- <argument index="2" name="body_shape" type="int">
- </argument>
- <argument index="3" name="local_shape" type="int">
- </argument>
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- <constant name="MODE_STATIC" value="1">
- </constant>
- <constant name="MODE_RIGID" value="0">
- </constant>
- <constant name="MODE_CHARACTER" value="2">
- </constant>
- </constants>
-</class>
-<class name="Room" inherits="Resource" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_bounds" >
- <argument index="0" name="bsp_tree" type="Dictionary">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_bounds" qualifiers="const" >
- <return type="Dictionary">
- </return>
- <description>
- </description>
- </method>
- <method name="set_geometry_hint" >
- <argument index="0" name="triangles" type="Vector3Array">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_geometry_hint" qualifiers="const" >
- <return type="Vector3Array">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="RoomInstance" inherits="VisualInstance" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_room" >
- <argument index="0" name="room" type="Room">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_room" qualifiers="const" >
- <return type="Room">
- </return>
- <description>
- </description>
- </method>
- <method name="compute_room_from_subtree" >
- <description>
- </description>
- </method>
- <method name="set_simulate_acoustics" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_simulating_acoustics" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="SSAOFX" inherits="ScenarioFX" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Sample" inherits="Resource" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="create" >
- <argument index="0" name="format" type="int">
- </argument>
- <argument index="1" name="stereo" type="bool">
- </argument>
- <argument index="2" name="length" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_format" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="is_stereo" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_length" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_data" >
- <argument index="0" name="data" type="RawArray">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_data" qualifiers="const" >
- <return type="RawArray">
- </return>
- <description>
- </description>
- </method>
- <method name="set_mix_rate" >
- <argument index="0" name="hz" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_mix_rate" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_loop_format" >
- <argument index="0" name="format" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_loop_format" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_loop_begin" >
- <argument index="0" name="pos" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_loop_begin" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_loop_end" >
- <argument index="0" name="pos" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_loop_end" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="FORMAT_PCM8" value="0">
- </constant>
- <constant name="FORMAT_PCM16" value="1">
- </constant>
- <constant name="FORMAT_IMA_ADPCM" value="2">
- </constant>
- <constant name="LOOP_NONE" value="0">
- </constant>
- <constant name="LOOP_FORWARD" value="1">
- </constant>
- <constant name="LOOP_PING_PONG" value="2">
- </constant>
- </constants>
-</class>
-<class name="SampleLibrary" inherits="Resource" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="add_sample" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="sample" type="Sample">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_sample" qualifiers="const" >
- <return type="Sample">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_sample" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="remove_sample" >
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="SamplePlayer" inherits="Node" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_sample_library" >
- <argument index="0" name="library" type="SampleLibrary">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_sample_library" qualifiers="const" >
- <return type="SampleLibrary">
- </return>
- <description>
- </description>
- </method>
- <method name="set_voice_count" >
- <argument index="0" name="max_voices" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_voice_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="play" >
- <return type="int">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="unique" type="bool" default="false">
- </argument>
- <description>
- </description>
- </method>
- <method name="stop" >
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="stop_all" >
- <description>
- </description>
- </method>
- <method name="set_mix_rate" >
- <argument index="0" name="voice" type="int">
- </argument>
- <argument index="1" name="hz" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_pitch_scale" >
- <argument index="0" name="voice" type="int">
- </argument>
- <argument index="1" name="ratio" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_volume" >
- <argument index="0" name="voice" type="int">
- </argument>
- <argument index="1" name="nrg" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_volume_db" >
- <argument index="0" name="voice" type="int">
- </argument>
- <argument index="1" name="nrg" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_pan" >
- <argument index="0" name="voice" type="int">
- </argument>
- <argument index="1" name="pan" type="real">
- </argument>
- <argument index="2" name="depth" type="real" default="0">
- </argument>
- <argument index="3" name="height" type="real" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_filter" >
- <argument index="0" name="voice" type="int">
- </argument>
- <argument index="1" name="type" type="int">
- </argument>
- <argument index="2" name="cutoff_hz" type="real">
- </argument>
- <argument index="3" name="resonance" type="real">
- </argument>
- <argument index="4" name="gain" type="real" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_chorus" >
- <argument index="0" name="voice" type="int">
- </argument>
- <argument index="1" name="send" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_reverb" >
- <argument index="0" name="voice" type="int">
- </argument>
- <argument index="1" name="room_type" type="int">
- </argument>
- <argument index="2" name="send" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_mix_rate" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_pitch_scale" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_volume" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_volume_db" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_pan" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_pan_depth" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_pan_height" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_filter_type" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_filter_cutoff" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_filter_resonance" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_filter_gain" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_chorus" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_reverb_room" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_reverb" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_default_pitch_scale" >
- <argument index="0" name="ratio" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_default_volume" >
- <argument index="0" name="nrg" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_default_volume_db" >
- <argument index="0" name="db" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_default_pan" >
- <argument index="0" name="pan" type="real">
- </argument>
- <argument index="1" name="depth" type="real" default="0">
- </argument>
- <argument index="2" name="height" type="real" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_default_filter" >
- <argument index="0" name="type" type="int">
- </argument>
- <argument index="1" name="cutoff_hz" type="real">
- </argument>
- <argument index="2" name="resonance" type="real">
- </argument>
- <argument index="3" name="gain" type="real" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_default_chorus" >
- <argument index="0" name="send" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_default_reverb" >
- <argument index="0" name="room_type" type="int">
- </argument>
- <argument index="1" name="send" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_default_pitch_scale" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_volume" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_volume_db" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_pan" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_pan_depth" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_pan_height" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_filter_type" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_filter_cutoff" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_filter_resonance" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_filter_gain" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_chorus" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_reverb_room" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_reverb" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="is_active" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="is_voice_active" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="FILTER_NONE" value="0">
- </constant>
- <constant name="FILTER_LOWPASS" value="1">
- </constant>
- <constant name="FILTER_BANDPASS" value="2">
- </constant>
- <constant name="FILTER_HIPASS" value="3">
- </constant>
- <constant name="FILTER_NOTCH" value="4">
- </constant>
- <constant name="FILTER_PEAK" value="5">
- </constant>
- <constant name="FILTER_BANDLIMIT" value="6">
- </constant>
- <constant name="FILTER_LOW_SHELF" value="7">
- </constant>
- <constant name="FILTER_HIGH_SHELF" value="8">
- </constant>
- <constant name="REVERB_SMALL" value="0">
- </constant>
- <constant name="REVERB_MEDIUM" value="1">
- </constant>
- <constant name="REVERB_LARGE" value="2">
- </constant>
- <constant name="REVERB_HALL" value="3">
- </constant>
- </constants>
-</class>
-<class name="ScenarioFX" inherits="Node" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="SceneIO" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="load" >
- <return type="Object">
- </return>
- <argument index="0" name="path" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="save" >
- <return type="int">
- </return>
- <argument index="0" name="path" type="String">
- </argument>
- <argument index="1" name="scene" type="Object">
- </argument>
- <argument index="2" name="flags" type="int" default="0">
- </argument>
- <argument index="3" name="optimizer" type="Object" default="Object()">
- </argument>
- <description>
- </description>
- </method>
- <method name="load_interactive" >
- <return type="SceneInteractiveLoader">
- </return>
- <argument index="0" name="path" type="String">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="SceneMainLoop" inherits="MainLoop" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="get_default_world" qualifiers="const" >
- <return type="World">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_viewport" qualifiers="const" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_viewport_size" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_canvas" qualifiers="const" >
- <return type="Canvas">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_space_2d" qualifiers="const" >
- <return type="Space2D">
- </return>
- <description>
- </description>
- </method>
- <method name="notify_group" >
- <argument index="0" name="call_flags" type="int">
- </argument>
- <argument index="1" name="group" type="String">
- </argument>
- <argument index="2" name="notification" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_group" >
- <argument index="0" name="call_flags" type="int">
- </argument>
- <argument index="1" name="group" type="String">
- </argument>
- <argument index="2" name="property" type="String">
- </argument>
- <argument index="3" name="value" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_root_node" >
- <return type="Node">
- </return>
- <description>
- </description>
- </method>
- <method name="set_root_node" >
- <argument index="0" name="node" type="Node">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_auto_accept_quit" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_editor_hint" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_editor_hint" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_pause" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_paused" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_input_as_handled" >
- <description>
- </description>
- </method>
- <method name="get_frame" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="quit" >
- <description>
- </description>
- </method>
- <method name="call_group" >
- <argument index="0" name="flags" type="int">
- </argument>
- <argument index="1" name="group" type="String">
- </argument>
- <argument index="2" name="method" type="String">
- </argument>
- <argument index="3" name="arg0" type="var" default="NULL">
- </argument>
- <argument index="4" name="arg1" type="var" default="NULL">
- </argument>
- <argument index="5" name="arg2" type="var" default="NULL">
- </argument>
- <argument index="6" name="arg3" type="var" default="NULL">
- </argument>
- <argument index="7" name="arg4" type="var" default="NULL">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="screen_resized">
- <description>
- </description>
- </signal>
- <signal name="node_removed">
- <argument index="0" name="node" type="Object">
- </argument>
- <description>
- </description>
- </signal>
- <signal name="tree_changed">
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- <constant name="GROUP_CALL_DEFAULT" value="0">
- </constant>
- <constant name="GROUP_CALL_REVERSE" value="1">
- </constant>
- <constant name="GROUP_CALL_REALTIME" value="2">
- </constant>
- <constant name="GROUP_CALL_UNIQUE" value="4">
- </constant>
- </constants>
-</class>
-<class name="ScenePreloader" inherits="Resource" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="load_scene" >
- <return type="int">
- </return>
- <argument index="0" name="path" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_scene_path" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="instance" qualifiers="const" >
- <return type="Node">
- </return>
- <description>
- </description>
- </method>
- <method name="can_instance" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="ScreenProximity2D" inherits="ProximityGroup2D" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="enter_screen" >
- <description>
- </description>
- </method>
- <method name="exit_screen" >
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="enter_screen">
- <description>
- </description>
- </signal>
- <signal name="exit_screen">
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="Script" inherits="Resource" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="can_instance" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="instance_has" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="base_object" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_source_code" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_source_code" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="set_source_code" >
- <argument index="0" name="source" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="reload" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="ScrollBar" inherits="Range" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_custom_step" >
- <argument index="0" name="step" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_custom_step" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="SegmentShape2D" inherits="Shape2D" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_a" >
- <argument index="0" name="a" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_a" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="set_b" >
- <argument index="0" name="b" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_b" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Separator" inherits="Control" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Shader" inherits="Resource" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_mode" >
- <argument index="0" name="mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_mode" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_vertex_code" >
- <argument index="0" name="code" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_vertex_code" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="set_fragment_code" >
- <argument index="0" name="code" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_fragment_code" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="set_use_world_transform" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_using_world_transform" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_param" >
- <argument index="0" name="param" type="String">
- </argument>
- <argument index="1" name="value" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_param" qualifiers="const" >
- <argument index="0" name="param" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_param_list" qualifiers="const" >
- <return type="StringArray">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="MODE_MATERIAL" value="0">
- </constant>
- <constant name="MODE_POST_PROCESS" value="1">
- </constant>
- </constants>
-</class>
-<class name="ShaderMaterial" inherits="Material" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_shader" >
- <argument index="0" name="shader" type="Shader">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_shader" qualifiers="const" >
- <return type="Shader">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Shape" inherits="Resource" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Shape2D" inherits="Resource" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Skeleton" inherits="Spatial" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="add_bone" >
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="find_bone" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_bone_name" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_bone_parent" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_bone_parent" >
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <argument index="1" name="parent_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_bone_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_bone_rest" qualifiers="const" >
- <return type="Transform">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_bone_rest" >
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <argument index="1" name="rest" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="bind_child_node_to_bone" >
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <argument index="1" name="node" type="Node">
- </argument>
- <description>
- </description>
- </method>
- <method name="unbind_child_node_from_bone" >
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <argument index="1" name="node" type="Node">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_bound_child_nodes_to_bone" qualifiers="const" >
- <return type="Array">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear_bones" >
- <description>
- </description>
- </method>
- <method name="get_bone_pose" qualifiers="const" >
- <return type="Transform">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_bone_pose" >
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <argument index="1" name="pose" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_bone_custom_pose" qualifiers="const" >
- <return type="Transform">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_bone_custom_pose" >
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <argument index="1" name="custom_pose" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_bone_transform" qualifiers="const" >
- <return type="Transform">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="NOTIFICATION_UPDATE_SKELETON" value="50">
- </constant>
- </constants>
-</class>
-<class name="SkyBoxFX" inherits="ScenarioFX" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Slider" inherits="Range" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_ticks" >
- <argument index="0" name="count" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_ticks" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_ticks_on_borders" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_ticks_on_borders" >
- <argument index="0" name="ticks_on_border" type="bool">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="SoundRoomParams" inherits="Node" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_param" >
- <argument index="0" name="param" type="int">
- </argument>
- <argument index="1" name="value" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_param" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="param" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_reverb_mode" >
- <argument index="0" name="reverb_mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_reverb_mode" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_force_params_to_all_sources" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_forcing_params_to_all_sources" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Spatial" inherits="Node" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_transform" >
- <argument index="0" name="local" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_transform" qualifiers="const" >
- <return type="Transform">
- </return>
- <description>
- </description>
- </method>
- <method name="set_global_transform" >
- <argument index="0" name="global" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_global_transform" qualifiers="const" >
- <return type="Transform">
- </return>
- <description>
- </description>
- </method>
- <method name="get_parent_spatial" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="update_gizmo" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="NOTIFICATION_UPDATE_GIZMO" value="43">
- </constant>
- <constant name="NOTIFICATION_TRANSFORM_CHANGED" value="40">
- </constant>
- <constant name="NOTIFICATION_SCENARIO_CHANGED" value="41">
- </constant>
- </constants>
-</class>
-<class name="SpatialPlayer" inherits="Spatial" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_param" >
- <argument index="0" name="param" type="int">
- </argument>
- <argument index="1" name="value" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_param" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="param" type="int">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="PARAM_VOLUME_DB" value="0">
- </constant>
- <constant name="PARAM_PITCH_SCALE" value="1">
- </constant>
- <constant name="PARAM_ATTENUATION_MIN_DISTANCE" value="2">
- </constant>
- <constant name="PARAM_ATTENUATION_MAX_DISTANCE" value="3">
- </constant>
- <constant name="PARAM_ATTENUATION_DISTANCE_EXP" value="4">
- </constant>
- <constant name="PARAM_EMISSION_CONE_DEGREES" value="5">
- </constant>
- <constant name="PARAM_EMISSION_CONE_ATTENUATION_DB" value="6">
- </constant>
- <constant name="PARAM_MAX" value="7">
- </constant>
- </constants>
-</class>
-<class name="SpatialSamplePlayer" inherits="SpatialPlayer" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_sample_library" >
- <argument index="0" name="library" type="SampleLibrary">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_sample_library" qualifiers="const" >
- <return type="SampleLibrary">
- </return>
- <description>
- </description>
- </method>
- <method name="set_polyphony" >
- <argument index="0" name="voices" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_polyphony" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="play" >
- <return type="int">
- </return>
- <argument index="0" name="sample" type="String">
- </argument>
- <argument index="1" name="voice" type="int" default="-2">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_set_pitch_scale" >
- <argument index="0" name="voice" type="int">
- </argument>
- <argument index="1" name="ratio" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_set_volume_scale_db" >
- <argument index="0" name="voice" type="int">
- </argument>
- <argument index="1" name="db" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_voice_active" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="stop_voice" >
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="stop_all" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="INVALID_VOICE" value="-1">
- </constant>
- <constant name="NEXT_VOICE" value="-2">
- </constant>
- </constants>
-</class>
-<class name="SpatialSoundServer" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="SpatialSoundServerSW" inherits="SpatialSoundServer" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="SpatialStreamPlayer" inherits="SpatialPlayer" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_stream" >
- <argument index="0" name="stream" type="Stream">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_stream" qualifiers="const" >
- <return type="Stream">
- </return>
- <description>
- </description>
- </method>
- <method name="play" >
- <description>
- </description>
- </method>
- <method name="stop" >
- <description>
- </description>
- </method>
- <method name="is_playing" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_loop" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_loop" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_stream_name" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="get_loop_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_pos" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="seek_pos" >
- <argument index="0" name="time" type="real">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="SphereShape" inherits="Shape" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_radius" >
- <argument index="0" name="radius" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_radius" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="SpinBox" inherits="Range" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_suffix" >
- <argument index="0" name="suffix" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_suffix" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="set_prefix" >
- <argument index="0" name="prefix" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_prefix" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="set_editable" >
- <argument index="0" name="editable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_editable" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="SpotLight" inherits="Light" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Sprite" inherits="Node2D" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_texture" >
- <argument index="0" name="texture" type="Texture">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_texture" qualifiers="const" >
- <return type="Texture">
- </return>
- <description>
- </description>
- </method>
- <method name="set_centered" >
- <argument index="0" name="centered" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_centered" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_flip_h" >
- <argument index="0" name="flip_h" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_flipped_h" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_flip_v" >
- <argument index="0" name="flip_v" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_flipped_v" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_region" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_region" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_region_rect" >
- <argument index="0" name="rect" type="Rect2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_region_rect" qualifiers="const" >
- <return type="Rect2">
- </return>
- <description>
- </description>
- </method>
- <method name="set_frame" >
- <argument index="0" name="frame" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_frame" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_vframes" >
- <argument index="0" name="vframes" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_vframes" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_hframes" >
- <argument index="0" name="hframes" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_hframes" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_modulate" >
- <argument index="0" name="modulate" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_modulate" qualifiers="const" >
- <return type="Color">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="SquirrelScript" inherits="Script" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="StaticBody" inherits="PhysicsBody" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_simulated_motion" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_simulating_motion" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="simulate_motion" >
- <argument index="0" name="new_transform" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="create_shapes_from_child_meshes" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="StaticBody2D" inherits="PhysicsBody2D" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_simulate_motion" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_simulating_motion" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_constant_linear_velocity" >
- <argument index="0" name="vel" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_constant_angular_velocity" >
- <argument index="0" name="vel" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_constant_linear_velocity" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="get_constant_angular_velocity" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="StreamPeer" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="put_data" >
- <return type="int">
- </return>
- <argument index="0" name="data" type="RawArray">
- </argument>
- <description>
- </description>
- </method>
- <method name="put_partial_data" >
- <return type="Array">
- </return>
- <argument index="0" name="data" type="RawArray">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_data" >
- <return type="Array">
- </return>
- <argument index="0" name="bytes" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_partial_data" >
- <return type="Array">
- </return>
- <argument index="0" name="bytes" type="int">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="StreamPeerTCP" inherits="StreamPeer" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="connect" >
- <return type="int">
- </return>
- <argument index="0" name="host" type="String">
- </argument>
- <argument index="1" name="ip" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_connected" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_connected_host" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="get_connected_port" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="disconnect" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="StreamPlayer" inherits="Node" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_stream" >
- <argument index="0" name="stream" type="Stream">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_stream" qualifiers="const" >
- <return type="Stream">
- </return>
- <description>
- </description>
- </method>
- <method name="play" >
- <description>
- </description>
- </method>
- <method name="stop" >
- <description>
- </description>
- </method>
- <method name="is_playing" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_paused" >
- <argument index="0" name="paused" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_paused" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_loop" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_loop" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_volume" >
- <argument index="0" name="volume" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_volume" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_volume_db" >
- <argument index="0" name="db" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_volume_db" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_stream_name" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="get_loop_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_pos" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="seek_pos" >
- <argument index="0" name="time" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_autoplay" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_autoplay" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_length" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="StyleBox" inherits="Resource" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="test_mask" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="point" type="Vector2">
- </argument>
- <argument index="1" name="rect" type="Rect2">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_default_margin" >
- <argument index="0" name="margin" type="int">
- </argument>
- <argument index="1" name="offset" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_default_margin" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="margin" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_margin" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="margin" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_minimum_size" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="get_center_size" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="get_offset" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="draw" qualifiers="const" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Rect2">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="StyleBoxEmpty" inherits="StyleBox" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="StyleBoxFlat" inherits="StyleBox" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_bg_color" >
- <argument index="0" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_bg_color" qualifiers="const" >
- <return type="Color">
- </return>
- <description>
- </description>
- </method>
- <method name="set_light_color" >
- <argument index="0" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_light_color" qualifiers="const" >
- <return type="Color">
- </return>
- <description>
- </description>
- </method>
- <method name="set_dark_color" >
- <argument index="0" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_dark_color" qualifiers="const" >
- <return type="Color">
- </return>
- <description>
- </description>
- </method>
- <method name="set_border_size" >
- <argument index="0" name="size" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_border_size" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_border_blend" >
- <argument index="0" name="blend" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_border_blend" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_draw_center" >
- <argument index="0" name="size" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_draw_center" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="StyleBoxImageMask" inherits="StyleBox" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_image" >
- <argument index="0" name="image" type="Image">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_image" qualifiers="const" >
- <return type="Image">
- </return>
- <description>
- </description>
- </method>
- <method name="set_expand" >
- <argument index="0" name="expand" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_expand" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_expand_margin_size" >
- <argument index="0" name="margin" type="int">
- </argument>
- <argument index="1" name="size" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_expand_margin_size" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="StyleBoxTexture" inherits="StyleBox" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_texture" >
- <argument index="0" name="texture" type="Texture">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_texture" qualifiers="const" >
- <return type="Texture">
- </return>
- <description>
- </description>
- </method>
- <method name="set_margin_size" >
- <argument index="0" name="margin" type="int">
- </argument>
- <argument index="1" name="size" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_margin_size" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_expand_margin_size" >
- <argument index="0" name="margin" type="int">
- </argument>
- <argument index="1" name="size" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_expand_margin_size" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_draw_center" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_draw_center" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="SurfaceTool" inherits="Reference" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="begin" >
- <argument index="0" name="primitive" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_vertex" >
- <argument index="0" name="vertex" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_color" >
- <argument index="0" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_normal" >
- <argument index="0" name="normal" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_tangent" >
- <argument index="0" name="tangent" type="Plane">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_uv" >
- <argument index="0" name="uv" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_uv2" >
- <argument index="0" name="uv2" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_bones" >
- <argument index="0" name="bones" type="IntArray">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_weights" >
- <argument index="0" name="weights" type="RealArray">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_material" >
- <argument index="0" name="material" type="Material">
- </argument>
- <description>
- </description>
- </method>
- <method name="index" >
- <description>
- </description>
- </method>
- <method name="deindex" >
- <description>
- </description>
- </method>
- <method name="generate_flat_normals" >
- <description>
- </description>
- </method>
- <method name="generate_smooth_normals" >
- <description>
- </description>
- </method>
- <method name="generate_tangents" >
- <description>
- </description>
- </method>
- <method name="commit" >
- <return type="Mesh">
- </return>
- <argument index="0" name="existing" type="Mesh" default="Object()">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="TCP_Server" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="listen" >
- <return type="int">
- </return>
- <argument index="0" name="port" type="int">
- </argument>
- <argument index="1" name="accepted_hosts" type="StringArray" default="StringArray()">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_connection_available" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="take_connection" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="stop" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="TabContainer" inherits="Control" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="get_tab_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_current_tab" >
- <argument index="0" name="tab_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_current_tab" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_tab_align" >
- <argument index="0" name="align" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_tab_align" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_tabs_visible" >
- <argument index="0" name="visible" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="are_tabs_visible" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_tab_title" >
- <argument index="0" name="tab_idx" type="int">
- </argument>
- <argument index="1" name="title" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_tab_title" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="tab_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_tab_icon" >
- <argument index="0" name="tab_idx" type="int">
- </argument>
- <argument index="1" name="icon" type="Texture">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_tab_icon" qualifiers="const" >
- <return type="Texture">
- </return>
- <argument index="0" name="tab_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="tab_changed">
- <argument index="0" name="tab" type="int">
- </argument>
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="TestCube" inherits="GeometryInstance" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="TextEdit" inherits="Control" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_text" >
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="insert_text_at_cursor" >
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_line_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_text" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="get_line" >
- <return type="String">
- </return>
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="cursor_set_column" >
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="cursor_set_line" >
- <argument index="0" name="line" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="cursor_get_column" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="cursor_get_line" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_readonly" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_wrap" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_max_chars" >
- <argument index="0" name="amount" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="cut" >
- <description>
- </description>
- </method>
- <method name="copy" >
- <description>
- </description>
- </method>
- <method name="paste" >
- <description>
- </description>
- </method>
- <method name="select_all" >
- <description>
- </description>
- </method>
- <method name="select" >
- <argument index="0" name="from_line" type="int">
- </argument>
- <argument index="1" name="from_column" type="int">
- </argument>
- <argument index="2" name="to_line" type="int">
- </argument>
- <argument index="3" name="to_column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_selection_active" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_selection_from_line" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_selection_from_column" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_selection_to_line" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_selection_to_column" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_selection_text" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="search" qualifiers="const" >
- <return type="IntArray">
- </return>
- <argument index="0" name="flags" type="String">
- </argument>
- <argument index="1" name="from_line" type="int">
- </argument>
- <argument index="2" name="from_column" type="int">
- </argument>
- <argument index="3" name="to_line" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="undo" >
- <description>
- </description>
- </method>
- <method name="redo" >
- <description>
- </description>
- </method>
- <method name="clear_undo_history" >
- <description>
- </description>
- </method>
- <method name="set_syntax_coloring" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_syntax_coloring_enabled" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="add_keyword_color" >
- <argument index="0" name="keyword" type="String">
- </argument>
- <argument index="1" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_color_region" >
- <argument index="0" name="begin_key" type="String">
- </argument>
- <argument index="1" name="end_key" type="String">
- </argument>
- <argument index="2" name="color" type="Color">
- </argument>
- <argument index="3" name="line_only" type="bool" default="false">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_symbol_color" >
- <argument index="0" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_custom_bg_color" >
- <argument index="0" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear_colors" >
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="text_changed">
- <description>
- </description>
- </signal>
- <signal name="cursor_changed">
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- <constant name="SEARCH_MATCH_CASE" value="1">
- </constant>
- <constant name="SEARCH_WHOLE_WORDS" value="2">
- </constant>
- <constant name="SEARCH_BACKWARDS" value="4">
- </constant>
- </constants>
-</class>
-<class name="Texture" inherits="Resource" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="create" >
- <argument index="0" name="width" type="int">
- </argument>
- <argument index="1" name="height" type="int">
- </argument>
- <argument index="2" name="format" type="int">
- </argument>
- <argument index="3" name="flags" type="int">
- </argument>
- <argument index="4" name="arg4" type="int" default="7">
- </argument>
- <description>
- </description>
- </method>
- <method name="create_from_image" >
- <argument index="0" name="image" type="Image">
- </argument>
- <argument index="1" name="flags" type="int" default="7">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_flags" >
- <argument index="0" name="flags" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_flags" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_format" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="load" >
- <argument index="0" name="path" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_data" >
- <argument index="0" name="image" type="Image">
- </argument>
- <argument index="1" name="cube_side" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_data" qualifiers="const" >
- <return type="Image">
- </return>
- <argument index="0" name="cube_side" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_width" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_height" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_size" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="get_rid" qualifiers="const" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="has_alpha" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="draw" qualifiers="const" >
- <argument index="0" name="canvas_item" type="RID">
- </argument>
- <argument index="1" name="pos" type="Vector2">
- </argument>
- <argument index="2" name="modulate" type="Color" default="Color(1,1,1,1)">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="FLAG_MIPMAPS" value="1">
- </constant>
- <constant name="FLAG_REPEAT" value="2">
- </constant>
- <constant name="FLAG_FILTER" value="4">
- </constant>
- <constant name="FLAG_CUBEMAP" value="8">
- </constant>
- <constant name="FLAG_VIDEO_SURFACE" value="16">
- </constant>
- <constant name="FLAGS_DEFAULT" value="7">
- </constant>
- <constant name="CUBEMAP_LEFT" value="0">
- </constant>
- <constant name="CUBEMAP_RIGHT" value="1">
- </constant>
- <constant name="CUBEMAP_BOTTOM" value="2">
- </constant>
- <constant name="CUBEMAP_TOP" value="3">
- </constant>
- <constant name="CUBEMAP_FRONT" value="4">
- </constant>
- <constant name="CUBEMAP_BACK" value="5">
- </constant>
- </constants>
-</class>
-<class name="TextureButton" inherits="BaseButton" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_normal_texture" >
- <argument index="0" name="texture" type="Texture">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_pressed_texture" >
- <argument index="0" name="texture" type="Texture">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_hover_texture" >
- <argument index="0" name="texture" type="Texture">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_disabled_texture" >
- <argument index="0" name="texture" type="Texture">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_focused_texture" >
- <argument index="0" name="texture" type="Texture">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_click_mask" >
- <argument index="0" name="texture:Image" type="Image">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_normal_texture" qualifiers="const" >
- <return type="Texture">
- </return>
- <description>
- </description>
- </method>
- <method name="get_pressed_texture" qualifiers="const" >
- <return type="Texture">
- </return>
- <description>
- </description>
- </method>
- <method name="get_hover_texture" qualifiers="const" >
- <return type="Texture">
- </return>
- <description>
- </description>
- </method>
- <method name="get_disabled_texture" qualifiers="const" >
- <return type="Texture">
- </return>
- <description>
- </description>
- </method>
- <method name="get_focused_texture" qualifiers="const" >
- <return type="Texture">
- </return>
- <description>
- </description>
- </method>
- <method name="get_click_mask" qualifiers="const" >
- <return type="Image">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="TextureFrame" inherits="Control" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_texture" >
- <argument index="0" name="texture" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_texture" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="set_expand" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_expand" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="TextureProgress" inherits="Range" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_under_texture" >
- <argument index="0" name="tex" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_under_texture" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="set_progress_texture" >
- <argument index="0" name="tex" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_progress_texture" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="set_over_texture" >
- <argument index="0" name="tex" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_over_texture" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Theme" inherits="Resource" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_icon" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <argument index="2" name="texture" type="Texture">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_icon" qualifiers="const" >
- <return type="Texture">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_icon" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear_icon" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_icon_list" qualifiers="const" >
- <return type="StringArray">
- </return>
- <argument index="0" name="arg0" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_stylebox" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <argument index="2" name="texture" type="StyleBox">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_stylebox" qualifiers="const" >
- <return type="StyleBox">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_stylebox" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear_stylebox" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_stylebox_list" qualifiers="const" >
- <return type="StringArray">
- </return>
- <argument index="0" name="arg0" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_font" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <argument index="2" name="font" type="Font">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_font" qualifiers="const" >
- <return type="Font">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_font" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear_font" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_font_list" qualifiers="const" >
- <return type="StringArray">
- </return>
- <argument index="0" name="arg0" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_color" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <argument index="2" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_color" qualifiers="const" >
- <return type="Color">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_color" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear_color" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_color_list" qualifiers="const" >
- <return type="StringArray">
- </return>
- <argument index="0" name="arg0" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_constant" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <argument index="2" name="constant" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_constant" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_constant" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear_constant" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_constant_list" qualifiers="const" >
- <return type="StringArray">
- </return>
- <argument index="0" name="arg0" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_type_list" qualifiers="const" >
- <return type="StringArray">
- </return>
- <argument index="0" name="arg0" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="copy_default_theme" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="TileMap" inherits="Node2D" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_tileset" >
- <argument index="0" name="tileset" type="TileSet">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_tileset" qualifiers="const" >
- <return type="TileSet">
- </return>
- <description>
- </description>
- </method>
- <method name="set_cell_size" >
- <argument index="0" name="size" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_cell_size" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_quadrant_size" >
- <argument index="0" name="size" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_quadrant_size" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_center_x" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_center_x" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_center_y" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_center_y" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_cell" >
- <argument index="0" name="x" type="int">
- </argument>
- <argument index="1" name="y" type="int">
- </argument>
- <argument index="2" name="tile" type="int">
- </argument>
- <argument index="3" name="flip_x" type="bool" default="false">
- </argument>
- <argument index="4" name="flip_y" type="bool" default="false">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_cell" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="x" type="int">
- </argument>
- <argument index="1" name="y" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_cell_x_flipped" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="x" type="int">
- </argument>
- <argument index="1" name="y" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_cell_y_flipped" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="x" type="int">
- </argument>
- <argument index="1" name="y" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="INVALID_CELL" value="-1">
- </constant>
- </constants>
-</class>
-<class name="TileSet" inherits="Resource" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="create_tile" >
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="tile_set_name" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="tile_get_name" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="tile_set_texture" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="texture" type="Texture">
- </argument>
- <description>
- </description>
- </method>
- <method name="tile_get_texture" qualifiers="const" >
- <return type="Texture">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="tile_set_offset" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="offset" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="tile_get_offset" qualifiers="const" >
- <return type="Vector2">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="tile_set_region" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="region" type="Rect2">
- </argument>
- <description>
- </description>
- </method>
- <method name="tile_get_region" qualifiers="const" >
- <return type="Rect2">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="tile_set_shape" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="shape" type="Shape2D">
- </argument>
- <description>
- </description>
- </method>
- <method name="tile_get_shape" qualifiers="const" >
- <return type="Shape2D">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="remove_tile" >
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear" >
- <description>
- </description>
- </method>
- <method name="get_last_unused_tile_id" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="find_tile_by_name" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_tiles_ids" qualifiers="const" >
- <return type="Array">
- </return>
- <description>
-
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Timer" inherits="Node" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_wait_time" >
- <argument index="0" name="time_sec" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_wait_time" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_one_shot" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_one_shot" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_autostart" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_autostart" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="start" >
- <description>
- </description>
- </method>
- <method name="stop" >
- <description>
- </description>
- </method>
- <method name="get_time_left" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="timeout">
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="Translation" inherits="Resource" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_locale" >
- <argument index="0" name="locale" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_locale" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="add_message" >
- <argument index="0" name="src_message" type="String">
- </argument>
- <argument index="1" name="xlated_message" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_message" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="src_message" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="erase_message" >
- <argument index="0" name="src_message" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_message_list" qualifiers="const" >
- <return type="StringArray">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="TranslationServer" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Tree" inherits="Control" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="clear" >
- <description>
- </description>
- </method>
- <method name="create_item" >
- <return type="TreeItem">
- </return>
- <argument index="0" name="parent" type="TreeItem" default="Object()">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_root" >
- <return type="TreeItem">
- </return>
- <description>
- </description>
- </method>
- <method name="set_column_min_width" >
- <argument index="0" name="arg0" type="int">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_column_expand" >
- <argument index="0" name="arg0" type="int">
- </argument>
- <argument index="1" name="arg1" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_column_width" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_hide_root" >
- <argument index="0" name="arg0" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_next_selected" >
- <return type="TreeItem">
- </return>
- <argument index="0" name="from" type="TreeItem">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_selected" qualifiers="const" >
- <return type="TreeItem">
- </return>
- <description>
- </description>
- </method>
- <method name="get_selected_column" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_pressed_button" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_select_mode" >
- <argument index="0" name="mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_columns" >
- <argument index="0" name="amount" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_columns" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_edited" qualifiers="const" >
- <return type="TreeItem">
- </return>
- <description>
- </description>
- </method>
- <method name="get_edited_column" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_custom_popup_rect" qualifiers="const" >
- <return type="Rect2">
- </return>
- <description>
- </description>
- </method>
- <method name="get_item_area_rect" qualifiers="const" >
- <return type="Rect2">
- </return>
- <argument index="0" name="item" type="TreeItem">
- </argument>
- <argument index="1" name="column" type="int" default="-1">
- </argument>
- <description>
- </description>
- </method>
- <method name="ensure_cursor_is_visible" >
- <description>
- </description>
- </method>
- <method name="set_column_titles_visible" >
- <argument index="0" name="visible" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="are_column_titles_visible" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_column_title" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="title" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_column_title" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_scroll" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="item_activated">
- <description>
- </description>
- </signal>
- <signal name="multi_selected">
- <argument index="0" name="item" type="Object">
- </argument>
- <argument index="1" name="column" type="int">
- </argument>
- <argument index="2" name="selected" type="bool">
- </argument>
- <description>
- </description>
- </signal>
- <signal name="custom_popup_edited">
- <argument index="0" name="arrow_clicked" type="bool">
- </argument>
- <description>
- </description>
- </signal>
- <signal name="item_edited">
- <description>
- </description>
- </signal>
- <signal name="item_selected">
- <description>
- </description>
- </signal>
- <signal name="cell_selected">
- <description>
- </description>
- </signal>
- <signal name="button_pressed">
- <argument index="0" name="item" type="Object">
- </argument>
- <argument index="1" name="column" type="int">
- </argument>
- <argument index="2" name="id" type="int">
- </argument>
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- <constant name="SELECT_SINGLE" value="0">
- </constant>
- <constant name="SELECT_ROW" value="1">
- </constant>
- <constant name="SELECT_MULTI" value="2">
- </constant>
- </constants>
-</class>
-<class name="TreeItem" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_cell_mode" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_cell_mode" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_checked" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="checked" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_checked" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_text" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="text" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_text" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_icon" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="texture" type="Texture">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_icon" qualifiers="const" >
- <return type="Texture">
- </return>
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_icon_region" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="region" type="Rect2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_icon_region" qualifiers="const" >
- <return type="Rect2">
- </return>
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_icon_max_width" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="width" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_icon_max_width" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_range" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="value" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_range" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_range_config" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="min" type="real">
- </argument>
- <argument index="2" name="max" type="real">
- </argument>
- <argument index="3" name="step" type="real">
- </argument>
- <argument index="4" name="expr" type="bool" default="false">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_range_config" >
- <return type="Dictionary">
- </return>
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_metadata" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="meta" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_metadata" qualifiers="const" >
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_collapsed" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_collapsed" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_next" >
- <return type="TreeItem">
- </return>
- <description>
- </description>
- </method>
- <method name="get_prev" >
- <return type="TreeItem">
- </return>
- <description>
- </description>
- </method>
- <method name="get_parent" >
- <return type="TreeItem">
- </return>
- <description>
- </description>
- </method>
- <method name="get_children" >
- <return type="TreeItem">
- </return>
- <description>
- </description>
- </method>
- <method name="get_next_visible" >
- <return type="TreeItem">
- </return>
- <description>
- </description>
- </method>
- <method name="get_prev_visible" >
- <return type="TreeItem">
- </return>
- <description>
- </description>
- </method>
- <method name="remove_child" >
- <argument index="0" name="child" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_selectable" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="selectable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_selectable" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_selected" >
- <return type="bool">
- </return>
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="select" >
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="deselect" >
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_editable" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_editable" >
- <return type="bool">
- </return>
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_custom_color" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear_custom_color" >
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_custom_bg_color" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear_custom_bg_color" >
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_custom_bg_color" qualifiers="const" >
- <return type="Color">
- </return>
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_button" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="button" type="Texture">
- </argument>
- <argument index="2" name="arg2" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_button_count" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_button" qualifiers="const" >
- <return type="Texture">
- </return>
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="button_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="erase_button" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="button_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_tooltip" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="tooltip" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_tooltip" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="CELL_MODE_STRING" value="0">
- </constant>
- <constant name="CELL_MODE_CHECK" value="1">
- </constant>
- <constant name="CELL_MODE_RANGE" value="2">
- </constant>
- <constant name="CELL_MODE_ICON" value="3">
- </constant>
- <constant name="CELL_MODE_CUSTOM" value="4">
- </constant>
- </constants>
-</class>
-<class name="VBoxContainer" inherits="BoxContainer" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="VButtonArray" inherits="ButtonArray" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="VScrollBar" inherits="ScrollBar" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="VSeparator" inherits="Separator" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="VSlider" inherits="Slider" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="VideoPlayer" inherits="Control" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_stream" >
- <argument index="0" name="stream" type="Stream">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_stream" qualifiers="const" >
- <return type="Stream">
- </return>
- <description>
- </description>
- </method>
- <method name="play" >
- <description>
- </description>
- </method>
- <method name="stop" >
- <description>
- </description>
- </method>
- <method name="is_playing" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_paused" >
- <argument index="0" name="paused" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_paused" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_volume" >
- <argument index="0" name="volume" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_volume" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_volume_db" >
- <argument index="0" name="db" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_volume_db" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_stream_name" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="get_pos" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_autoplay" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_autoplay" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_expand" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_expand" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="VideoStream" inherits="AudioStreamResampled" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="get_pending_frame_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="pop_frame" >
- <return type="Image">
- </return>
- <description>
- </description>
- </method>
- <method name="peek_frame" qualifiers="const" >
- <return type="Image">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="VideoStreamTheora" inherits="VideoStream" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Viewport" inherits="Node" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_rect" >
- <argument index="0" name="rect" type="Rect2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_rect" qualifiers="const" >
- <return type="Rect2">
- </return>
- <description>
- </description>
- </method>
- <method name="get_visible_rect" qualifiers="const" >
- <return type="Rect2">
- </return>
- <description>
- </description>
- </method>
- <method name="set_transparent_background" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_transparent_background" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_viewport" qualifiers="const" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="VisualInstance" inherits="Spatial" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_base" >
- <argument index="0" name="base" type="RID">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="VisualServer" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="texture_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="texture_create_from_image" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="Image">
- </argument>
- <argument index="1" name="arg1" type="int" default="7">
- </argument>
- <description>
- </description>
- </method>
- <method name="texture_set_flags" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="texture_get_flags" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="texture_get_width" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="texture_get_height" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="shader_create" >
- <return type="RID">
- </return>
- <argument index="0" name="mode" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="shader_set_mode" >
- <argument index="0" name="shader" type="RID">
- </argument>
- <argument index="1" name="mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="shader_get_mode" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="shader" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="shader_set_vertex_code" >
- <argument index="0" name="shader" type="RID">
- </argument>
- <argument index="1" name="code" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="shader_get_vertex_code" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="shader" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="shader_set_fragment_code" >
- <argument index="0" name="shader" type="RID">
- </argument>
- <argument index="1" name="code" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="shader_get_fragment_code" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="shader" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="shader_set_param" >
- <argument index="0" name="shader" type="RID">
- </argument>
- <argument index="1" name="param" type="String">
- </argument>
- <argument index="2" name="value" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="shader_get_param" qualifiers="const" >
- <argument index="0" name="shader" type="RID">
- </argument>
- <argument index="1" name="param" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="shader_get_param_list" qualifiers="const" >
- <return type="StringArray">
- </return>
- <argument index="0" name="shader" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="shader_set_use_world_transform" >
- <argument index="0" name="shader" type="RID">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="shader_is_using_world_transform" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="shader" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="material_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="material_set_shader" >
- <argument index="0" name="shader" type="RID">
- </argument>
- <argument index="1" name="arg1" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="material_get_shader" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="material_set_param" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="String">
- </argument>
- <argument index="2" name="arg2" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="material_get_param" qualifiers="const" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="material_set_flag" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="material_get_flag" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="material_set_blend_mode" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="material_get_blend_mode" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="material_set_line_width" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="material_get_line_width" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="fixed_material_set_parameter" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="fixed_material_get_parameter" qualifiers="const" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="fixed_material_set_texture" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="fixed_material_get_texture" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="fixed_material_set_texgen_mode" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="fixed_material_get_texgen_mode" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="fixed_material_set_texcoord_mode" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="fixed_material_get_texcoord_mode" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="fixed_material_set_uv_transform" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="fixed_material_get_uv_transform" qualifiers="const" >
- <return type="Transform">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="mesh_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="mesh_add_surface" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="int">
- </argument>
- <argument index="3" name="arg3" type="int">
- </argument>
- <argument index="4" name="arg4" type="int" default="-1">
- </argument>
- <description>
- </description>
- </method>
- <method name="mesh_surface_set_array" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="int">
- </argument>
- <argument index="3" name="arg3" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="mesh_surface_get_array" qualifiers="const" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="mesh_surface_set_material" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="RID">
- </argument>
- <argument index="3" name="arg3" type="bool" default="false">
- </argument>
- <description>
- </description>
- </method>
- <method name="mesh_surface_get_material" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="mesh_surface_get_array_len" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="mesh_surface_get_array_index_len" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="mesh_surface_get_format" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="mesh_surface_get_primitive_type" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="mesh_erase_surface" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="mesh_get_surface_count" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="multimesh_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="multimesh_set_mesh" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="multimesh_set_aabb" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="AABB">
- </argument>
- <description>
- </description>
- </method>
- <method name="multimesh_instance_set_transform" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="multimesh_instance_set_color" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="multimesh_get_mesh" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="multimesh_get_aabb" qualifiers="const" >
- <return type="AABB">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="AABB">
- </argument>
- <description>
- </description>
- </method>
- <method name="multimesh_instance_get_transform" qualifiers="const" >
- <return type="Transform">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="multimesh_instance_get_color" qualifiers="const" >
- <return type="Color">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="poly_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="poly_set_material" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="RID">
- </argument>
- <argument index="2" name="arg2" type="bool" default="false">
- </argument>
- <description>
- </description>
- </method>
- <method name="poly_clear" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="particles_set_amount" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_get_amount" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_set_emitting" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_is_emitting" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_set_visibility_aabb" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="AABB">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_get_visibility_aabb" qualifiers="const" >
- <return type="AABB">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_set_variable" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_get_variable" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_set_randomness" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_get_randomness" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_set_color_phases" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_get_color_phases" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_set_color_phase_pos" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_get_color_phase_pos" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_set_color_phase_color" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_get_color_phase_color" qualifiers="const" >
- <return type="Color">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_set_attractors" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_get_attractors" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_set_attractor_pos" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_get_attractor_pos" qualifiers="const" >
- <return type="Vector3">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_set_attractor_strength" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_get_attractor_strength" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_set_material" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="RID">
- </argument>
- <argument index="2" name="arg2" type="bool" default="false">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_set_height_from_velocity" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_has_height_from_velocity" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="light_create" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="light_get_type" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="light_set_color" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="light_get_color" qualifiers="const" >
- <return type="Color">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="light_set_shadow" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="light_has_shadow" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="light_set_volumetric" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="light_is_volumetric" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="light_set_projector" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="light_get_projector" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="light_set_var" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="light_get_var" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="skeleton_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="skeleton_resize" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="skeleton_get_bone_count" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="skeleton_bone_set_transform" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="skeleton_bone_get_transform" >
- <return type="Transform">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="room_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="room_set_bounds" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Dictionary">
- </argument>
- <description>
- </description>
- </method>
- <method name="room_get_bounds" qualifiers="const" >
- <return type="Dictionary">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="portal_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="portal_set_shape" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Vector2Array">
- </argument>
- <description>
- </description>
- </method>
- <method name="portal_get_shape" qualifiers="const" >
- <return type="Vector2Array">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="portal_set_enabled" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="portal_is_enabled" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="portal_set_disable_distance" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="portal_get_disable_distance" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="portal_set_disabled_color" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="portal_get_disabled_color" qualifiers="const" >
- <return type="Color">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="camera_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="camera_set_perspective" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="real">
- </argument>
- <argument index="2" name="arg2" type="real">
- </argument>
- <argument index="3" name="arg3" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="camera_set_orthogonal" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="real">
- </argument>
- <argument index="2" name="arg2" type="real">
- </argument>
- <argument index="3" name="arg3" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="camera_set_transform" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="viewport_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="viewport_set_rect" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Rect2">
- </argument>
- <description>
- </description>
- </method>
- <method name="viewport_get_rect" qualifiers="const" >
- <return type="Rect2">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="viewport_attach_camera" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="RID" default="RID()">
- </argument>
- <description>
- </description>
- </method>
- <method name="viewport_get_attached_camera" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="viewport_get_scenario" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="viewport_attach_canvas" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="viewport_remove_canvas" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="scenario_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="scenario_set_debug" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="scenario_fx_get_effects" qualifiers="const" >
- <return type="StringArray">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="scenario_fx_set_active" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="String">
- </argument>
- <argument index="2" name="arg2" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="scenario_fx_is_active" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="scenario_fx_get_effect_params" qualifiers="const" >
- <return type="Array">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="scenario_fx_get_effect_param" qualifiers="const" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="String">
- </argument>
- <argument index="2" name="arg2" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="scenario_fx_set_effect_param" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="String">
- </argument>
- <argument index="2" name="arg2" type="String">
- </argument>
- <argument index="3" name="arg3" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="instance_get_base" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_get_base_aabb" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_set_transform" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_get_transform" qualifiers="const" >
- <return type="Transform">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_attach_object_instance_ID" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_get_object_instance_ID" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_attach_skeleton" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_get_skeleton" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_set_room" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_get_room" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_set_exterior" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_is_exterior" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instances_cull_aabb" qualifiers="const" >
- <return type="Array">
- </return>
- <argument index="0" name="arg0" type="AABB">
- </argument>
- <argument index="1" name="arg1" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instances_cull_ray" qualifiers="const" >
- <return type="Array">
- </return>
- <argument index="0" name="arg0" type="Vector3">
- </argument>
- <argument index="1" name="arg1" type="Vector3">
- </argument>
- <argument index="2" name="arg2" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instances_cull_convex" qualifiers="const" >
- <return type="Array">
- </return>
- <argument index="0" name="arg0" type="Vector3">
- </argument>
- <argument index="1" name="arg1" type="Vector3">
- </argument>
- <argument index="2" name="arg2" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_geometry_set_visible" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_geometry_is_visible" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_geometry_override_material_param" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_geometry_get_material_param" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="canvas_item_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="canvas_item_set_parent" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_get_parent" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_set_transform" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Matrix32">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_set_custom_rect" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="bool">
- </argument>
- <argument index="2" name="arg2" type="Rect2">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_set_clip" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_set_opacity" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_get_opacity" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_set_self_opacity" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_get_self_opacity" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_add_line" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Vector2">
- </argument>
- <argument index="2" name="arg2" type="Vector2">
- </argument>
- <argument index="3" name="arg3" type="Color">
- </argument>
- <argument index="4" name="arg4" type="real" default="1">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_add_rect" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Rect2">
- </argument>
- <argument index="2" name="arg2" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_add_texture_rect" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Rect2">
- </argument>
- <argument index="2" name="arg2" type="RID">
- </argument>
- <argument index="3" name="arg3" type="bool">
- </argument>
- <argument index="4" name="arg4" type="Color" default="Color(1,1,1,1)">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_add_texture_rect_region" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Rect2">
- </argument>
- <argument index="2" name="arg2" type="RID">
- </argument>
- <argument index="3" name="arg3" type="Rect2">
- </argument>
- <argument index="4" name="arg4" type="Color" default="Color(1,1,1,1)">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_add_style_box" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Rect2">
- </argument>
- <argument index="2" name="arg2" type="RID">
- </argument>
- <argument index="3" name="arg3" type="RealArray">
- </argument>
- <argument index="4" name="arg4" type="Color" default="Color(1,1,1,1)">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_add_circle" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Vector2">
- </argument>
- <argument index="2" name="arg2" type="real">
- </argument>
- <argument index="3" name="arg3" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="viewport_set_canvas_transform" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="RID">
- </argument>
- <argument index="2" name="arg2" type="Matrix32">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_clear" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_raise" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="cursor_set_rotation" >
- <argument index="0" name="arg0" type="real">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="cursor_set_texture" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Vector2">
- </argument>
- <argument index="2" name="arg2" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="cursor_set_visible" >
- <argument index="0" name="arg0" type="bool">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="cursor_set_pos" >
- <argument index="0" name="arg0" type="Vector2">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="make_sphere_mesh" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="int">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="mesh_add_surface_from_planes" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Array">
- </argument>
- <description>
- </description>
- </method>
- <method name="free" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="NO_INDEX_ARRAY" value="-1">
- </constant>
- <constant name="CUSTOM_ARRAY_SIZE" value="8">
- </constant>
- <constant name="ARRAY_WEIGHTS_SIZE" value="4">
- </constant>
- <constant name="MAX_PARTICLE_COLOR_PHASES" value="4">
- </constant>
- <constant name="MAX_PARTICLE_ATTRACTORS" value="4">
- </constant>
- <constant name="MAX_CURSORS" value="8">
- </constant>
- <constant name="TEXTURE_FLAG_MIPMAPS" value="1">
- </constant>
- <constant name="TEXTURE_FLAG_REPEAT" value="2">
- </constant>
- <constant name="TEXTURE_FLAG_FILTER" value="4">
- </constant>
- <constant name="TEXTURE_FLAG_CUBEMAP" value="8">
- </constant>
- <constant name="TEXTURE_FLAGS_DEFAULT" value="7">
- </constant>
- <constant name="CUBEMAP_LEFT" value="0">
- </constant>
- <constant name="CUBEMAP_RIGHT" value="1">
- </constant>
- <constant name="CUBEMAP_BOTTOM" value="2">
- </constant>
- <constant name="CUBEMAP_TOP" value="3">
- </constant>
- <constant name="CUBEMAP_FRONT" value="4">
- </constant>
- <constant name="CUBEMAP_BACK" value="5">
- </constant>
- <constant name="SHADER_MATERIAL" value="0">
- </constant>
- <constant name="SHADER_POST_PROCESS" value="1">
- </constant>
- <constant name="MATERIAL_FLAG_VISIBLE" value="0">
- </constant>
- <constant name="MATERIAL_FLAG_DOUBLE_SIDED" value="1">
- </constant>
- <constant name="MATERIAL_FLAG_INVERT_FACES" value="2">
- </constant>
- <constant name="MATERIAL_FLAG_UNSHADED" value="3">
- </constant>
- <constant name="MATERIAL_FLAG_ONTOP" value="4">
- </constant>
- <constant name="MATERIAL_FLAG_WIREFRAME" value="5">
- </constant>
- <constant name="MATERIAL_FLAG_BILLBOARD" value="6">
- </constant>
- <constant name="MATERIAL_FLAG_MAX" value="7">
- </constant>
- <constant name="MATERIAL_BLEND_MODE_MIX" value="0">
- </constant>
- <constant name="MATERIAL_BLEND_MODE_ADD" value="1">
- </constant>
- <constant name="MATERIAL_BLEND_MODE_SUB" value="2">
- </constant>
- <constant name="MATERIAL_BLEND_MODE_MUL" value="3">
- </constant>
- <constant name="FIXED_MATERIAL_PARAM_DIFFUSE" value="0">
- </constant>
- <constant name="FIXED_MATERIAL_PARAM_DETAIL" value="1">
- </constant>
- <constant name="FIXED_MATERIAL_PARAM_SPECULAR" value="2">
- </constant>
- <constant name="FIXED_MATERIAL_PARAM_EMISSION" value="3">
- </constant>
- <constant name="FIXED_MATERIAL_PARAM_SPECULAR_EXP" value="4">
- </constant>
- <constant name="FIXED_MATERIAL_PARAM_GLOW" value="5">
- </constant>
- <constant name="FIXED_MATERIAL_PARAM_NORMAL" value="6">
- </constant>
- <constant name="FIXED_MATERIAL_PARAM_SHADE_PARAM" value="7">
- </constant>
- <constant name="FIXED_MATERIAL_PARAM_MAX" value="8">
- </constant>
- <constant name="FIXED_MATERIAL_TEXGEN_SPHERE" value="1">
- </constant>
- <constant name="FIXED_MATERIAL_TEXGEN_SCREEN" value="2">
- </constant>
- <constant name="FIXED_MATERIAL_TEXGEN_SCREENZ" value="3">
- </constant>
- <constant name="FIXED_MATERIAL_TEXGEN_LOCAL_XY" value="0">
- </constant>
- <constant name="FIXED_MATERIAL_TEXCOORD_TEXGEN" value="3">
- </constant>
- <constant name="FIXED_MATERIAL_TEXCOORD_UV" value="0">
- </constant>
- <constant name="FIXED_MATERIAL_TEXCOORD_UV_TRANSFORM" value="1">
- </constant>
- <constant name="FIXED_MATERIAL_TEXCOORD_UV2" value="2">
- </constant>
- <constant name="ARRAY_VERTEX" value="0">
- </constant>
- <constant name="ARRAY_NORMAL" value="1">
- </constant>
- <constant name="ARRAY_TANGENT" value="2">
- </constant>
- <constant name="ARRAY_COLOR" value="3">
- </constant>
- <constant name="ARRAY_TEX_UV" value="4">
- </constant>
- <constant name="ARRAY_BONES" value="6">
- </constant>
- <constant name="ARRAY_WEIGHTS" value="7">
- </constant>
- <constant name="ARRAY_INDEX" value="8">
- </constant>
- <constant name="ARRAY_MAX" value="9">
- </constant>
- <constant name="ARRAY_FORMAT_VERTEX" value="1">
- </constant>
- <constant name="ARRAY_FORMAT_NORMAL" value="2">
- </constant>
- <constant name="ARRAY_FORMAT_TANGENT" value="4">
- </constant>
- <constant name="ARRAY_FORMAT_COLOR" value="8">
- </constant>
- <constant name="ARRAY_FORMAT_TEX_UV" value="16">
- </constant>
- <constant name="ARRAY_FORMAT_BONES" value="64">
- </constant>
- <constant name="ARRAY_FORMAT_WEIGHTS" value="128">
- </constant>
- <constant name="ARRAY_FORMAT_INDEX" value="256">
- </constant>
- <constant name="PRIMITIVE_POINTS" value="0">
- </constant>
- <constant name="PRIMITIVE_LINES" value="1">
- </constant>
- <constant name="PRIMITIVE_LINE_STRIP" value="2">
- </constant>
- <constant name="PRIMITIVE_LINE_LOOP" value="3">
- </constant>
- <constant name="PRIMITIVE_TRIANGLES" value="4">
- </constant>
- <constant name="PRIMITIVE_TRIANGLE_STRIP" value="5">
- </constant>
- <constant name="PRIMITIVE_TRIANGLE_FAN" value="6">
- </constant>
- <constant name="PRIMITIVE_MAX" value="7">
- </constant>
- <constant name="PARTICLE_LIFETIME" value="0">
- </constant>
- <constant name="PARTICLE_SPREAD" value="1">
- </constant>
- <constant name="PARTICLE_GRAVITY" value="2">
- </constant>
- <constant name="PARTICLE_LINEAR_VELOCITY" value="3">
- </constant>
- <constant name="PARTICLE_ANGULAR_VELOCITY" value="4">
- </constant>
- <constant name="PARTICLE_LINEAR_ACCELERATION" value="5">
- </constant>
- <constant name="PARTICLE_RADIAL_ACCELERATION" value="6">
- </constant>
- <constant name="PARTICLE_TANGENTIAL_ACCELERATION" value="7">
- </constant>
- <constant name="PARTICLE_INITIAL_SIZE" value="9">
- </constant>
- <constant name="PARTICLE_FINAL_SIZE" value="10">
- </constant>
- <constant name="PARTICLE_INITIAL_ANGLE" value="11">
- </constant>
- <constant name="PARTICLE_HEIGHT" value="12">
- </constant>
- <constant name="PARTICLE_HEIGHT_SPEED_SCALE" value="13">
- </constant>
- <constant name="PARTICLE_VAR_MAX" value="14">
- </constant>
- <constant name="LIGHT_DIRECTIONAL" value="0">
- </constant>
- <constant name="LIGHT_OMNI" value="1">
- </constant>
- <constant name="LIGHT_SPOT" value="2">
- </constant>
- <constant name="LIGHT_COLOR_AMBIENT" value="0">
- </constant>
- <constant name="LIGHT_COLOR_DIFFUSE" value="1">
- </constant>
- <constant name="LIGHT_COLOR_SPECULAR" value="2">
- </constant>
- <constant name="LIGHT_VAR_SPOT_ATTENUATION" value="0">
- </constant>
- <constant name="LIGHT_VAR_SPOT_ANGLE" value="1">
- </constant>
- <constant name="LIGHT_VAR_RADIUS" value="2">
- </constant>
- <constant name="LIGHT_VAR_ENERGY" value="3">
- </constant>
- <constant name="LIGHT_VAR_ATTENUATION" value="4">
- </constant>
- <constant name="LIGHT_VAR_MAX" value="6">
- </constant>
- <constant name="SCENARIO_DEBUG_DISABLED" value="0">
- </constant>
- <constant name="SCENARIO_DEBUG_WIREFRAME" value="1">
- </constant>
- <constant name="SCENARIO_DEBUG_OVERDRAW" value="2">
- </constant>
- <constant name="INSTANCE_MESH" value="1">
- </constant>
- <constant name="INSTANCE_MULTIMESH" value="2">
- </constant>
- <constant name="INSTANCE_POLY" value="3">
- </constant>
- <constant name="INSTANCE_PARTICLES" value="4">
- </constant>
- <constant name="INSTANCE_LIGHT" value="5">
- </constant>
- <constant name="INSTANCE_ROOM" value="6">
- </constant>
- <constant name="INSTANCE_PORTAL" value="7">
- </constant>
- <constant name="INSTANCE_GEOMETRY_MASK" value="30">
- </constant>
- <constant name="INFO_OBJECTS_IN_FRAME" value="0">
- </constant>
- <constant name="INFO_MATERIAL_CHANGES_IN_FRAME" value="1">
- </constant>
- <constant name="INFO_USAGE_VIDEO_MEM_TOTAL" value="2">
- </constant>
- <constant name="INFO_VIDEO_MEM_USED" value="3">
- </constant>
- <constant name="INFO_TEXTURE_MEM_USED" value="4">
- </constant>
- <constant name="INFO_VERTEX_MEM_USED" value="5">
- </constant>
- </constants>
-</class>
-<class name="WindowDialog" inherits="Popup" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_title" >
- <argument index="0" name="title" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_title" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="get_close_button" >
- <return type="TextureButton">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="World" inherits="Resource" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="get_space" qualifiers="const" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="get_scenario" qualifiers="const" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="get_sound_space" qualifiers="const" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-</doc>
diff --git a/doc/examples/physics/script/test_base.sq b/doc/examples/physics/script/test_base.sq
deleted file mode 100644
index 9d5451728f..0000000000
--- a/doc/examples/physics/script/test_base.sq
+++ /dev/null
@@ -1,295 +0,0 @@
-
-class PhysicsTestBase extends MainLoopScripted {
-
-
- bodies=[]
- type_mesh_map={}
- type_shape_map={}
- cameratr=Transform()
-
-
- function body_changed_transform(p_transform, p_velocity, p_angular_velocity,p_sleeping, p_visual_instance) {
-
- VisualServer.instance_set_transform(p_visual_instance,p_transform);
- }
-
-
- function create_body(p_shape, p_body_mode, p_location, p_active=true) {
-
- local mesh_instance = VisualServer.instance_create( type_mesh_map[p_shape] )
- local body = PhysicsServer.body_create(RID(),p_body_mode,!p_active)
- PhysicsServer.body_add_shape(body,type_shape_map[p_shape])
-
- local query = PhysicsServer.query_create(this,"body_changed_transform",mesh_instance)
- PhysicsServer.query_body_state(query, body)
-
- PhysicsServer.body_set_state( body, PhysicsServer.BODY_STATE_TRANSFORM, p_location )
- bodies.append( body )
- return body
-
- }
-
-
- function create_static_plane(p_plane) {
-
- local plane_shape = PhysicsServer.shape_create(PhysicsServer.SHAPE_PLANE)
- PhysicsServer.shape_set_data( plane_shape, p_plane );
-
- local b = PhysicsServer.body_create(RID(), PhysicsServer.BODY_MODE_STATIC );
- PhysicsServer.body_add_shape(b, plane_shape);
- return b;
- }
-
- function configure_body( p_body, p_mass, p_friction, p_bounce) {
-
- PhysicsServer.body_set_param( p_body, PhysicsServer.BODY_PARAM_MASS, p_mass );
- PhysicsServer.body_set_param( p_body, PhysicsServer.BODY_PARAM_FRICTION, p_friction );
- PhysicsServer.body_set_param( p_body, PhysicsServer.BODY_PARAM_BOUNCE, p_bounce );
-
- }
-
- function init_shapes() {
-
-
- /* SPHERE SHAPE */
- local sphere_mesh = VisualServer.make_sphere_mesh(10,20,1.0);
- local sphere_material = VisualServer.fixed_material_create();
- //VisualServer.material_set_flag( sphere_material, VisualServer.MATERIAL_FLAG_WIREFRAME, true );
- VisualServer.fixed_material_set_parameter( sphere_material, VisualServer.FIXED_MATERIAL_PARAM_DIFFUSE, Color(0.7,0.8,3.0) );
- VisualServer.mesh_surface_set_material( sphere_mesh, 0, sphere_material );
- type_mesh_map[PhysicsServer.SHAPE_SPHERE] <- sphere_mesh;
-
- local sphere_shape=PhysicsServer.shape_create(PhysicsServer.SHAPE_SPHERE);
- PhysicsServer.shape_set_data( sphere_shape, 1.0 );
- type_shape_map[PhysicsServer.SHAPE_SPHERE] <- sphere_shape;
-
- /* BOX SHAPE */
-
- local box_planes = GeometryUtils.build_box_planes(Vector3(0.5,0.5,0.5));
- local box_material = VisualServer.fixed_material_create();
- VisualServer.fixed_material_set_parameter( box_material, VisualServer.FIXED_MATERIAL_PARAM_DIFFUSE, Color(1.0,0.2,0.2) );
- local box_mesh = VisualServer.mesh_create();
-
- VisualServer.mesh_add_surface_from_planes(box_mesh,box_planes);
- VisualServer.mesh_surface_set_material( box_mesh, 0, box_material );
- type_mesh_map[PhysicsServer.SHAPE_BOX]<- box_mesh;
-
- local box_shape=PhysicsServer.shape_create(PhysicsServer.SHAPE_BOX);
- PhysicsServer.shape_set_data( box_shape, Vector3(0.5,0.5,0.5) );
- type_shape_map[PhysicsServer.SHAPE_BOX]<- box_shape;
-
- /* CYLINDER SHAPE */
-
- local cylinder_planes = GeometryUtils.build_cylinder_planes(0.5,1,12
- ,Vector3.AXIS_Z);
- local cylinder_material = VisualServer.fixed_material_create();
- VisualServer.fixed_material_set_parameter( cylinder_material, VisualServer.FIXED_MATERIAL_PARAM_DIFFUSE, Color(0.3,0.4,1.0) );
- local cylinder_mesh = VisualServer.mesh_create();
-
- VisualServer.mesh_add_surface_from_planes(cylinder_mesh,cylinder_planes);
- VisualServer.mesh_surface_set_material( cylinder_mesh, 0, cylinder_material );
- type_mesh_map[PhysicsServer.SHAPE_CYLINDER]<- cylinder_mesh;
-
- local cylinder_shape=PhysicsServer.shape_create(PhysicsServer.SHAPE_CYLINDER);
- local cylinder_params={}
- cylinder_params["radius"]<- 0.5;
- cylinder_params["height"]<- 2;
- PhysicsServer.shape_set_data( cylinder_shape, cylinder_params );
- type_shape_map[PhysicsServer.SHAPE_CYLINDER]<- cylinder_shape;
-
- /* CAPSULE SHAPE */
-
- local capsule_planes = GeometryUtils.build_capsule_planes(0.5,0.7,12,Vector3.AXIS_Z);
- local capsule_material = VisualServer.fixed_material_create();
- VisualServer.fixed_material_set_parameter( capsule_material, VisualServer.FIXED_MATERIAL_PARAM_DIFFUSE, Color(0.3,0.4,1.0) );
-
- local capsule_mesh = VisualServer.mesh_create();
-
- VisualServer.mesh_add_surface_from_planes(capsule_mesh,capsule_planes);
- VisualServer.mesh_surface_set_material( capsule_mesh, 0, capsule_material );
- type_mesh_map[PhysicsServer.SHAPE_CAPSULE]<-capsule_mesh;
-
- local capsule_shape=PhysicsServer.shape_create(PhysicsServer.SHAPE_CAPSULE);
- local capsule_params={}
- capsule_params["radius"]<- 0.5;
- capsule_params["height"]<- 1.4;
- PhysicsServer.shape_set_data( capsule_shape, capsule_params );
- type_shape_map[PhysicsServer.SHAPE_CAPSULE]<- capsule_shape;
-
- /* CONVEX SHAPE */
-
- local convex_planes = GeometryUtils.build_cylinder_planes(0.5,0.7,5,Vector3.AXIS_Z);
- local convex_material = VisualServer.fixed_material_create();
- VisualServer.fixed_material_set_parameter( convex_material, VisualServer.FIXED_MATERIAL_PARAM_DIFFUSE, Color(0.8,0.2,0.9));
-
- local convex_mesh = VisualServer.mesh_create();
- VisualServer.mesh_add_surface_from_planes(convex_mesh,convex_planes);
- VisualServer.mesh_surface_set_material( convex_mesh, 0, convex_material );
- type_mesh_map[PhysicsServer.SHAPE_CONVEX_POLYGON]<- convex_mesh;
-
- local convex_shape=PhysicsServer.shape_create(PhysicsServer.SHAPE_CONVEX_POLYGON);
- PhysicsServer.shape_set_data( convex_shape, convex_planes );
- type_shape_map[PhysicsServer.SHAPE_CONVEX_POLYGON]<- convex_shape;
-
- }
-
- function make_trimesh(p_faces,p_xform=Transform()) {
-
- local trimesh_shape = PhysicsServer.shape_create(PhysicsServer.SHAPE_CONCAVE_POLYGON);
- PhysicsServer.shape_set_data(trimesh_shape, p_faces);
- p_faces=PhysicsServer.shape_get_data(trimesh_shape); // optimized one
- normals=[]
-
- for (i=0;i<p_faces.length()/3;i++) {
-
- p=Plane( p_faces[i*3+0],p_faces[i*3+1], p_faces[i*3+2] );
- normals.append(p.normal);
- normals.append(p.normal);
- normals.append(p.normal);
- }
-
- local trimesh_mesh = VisualServer.mesh_create();
- VisualServer.mesh_add_surface(trimesh_mesh, VS::PRIMITIVE_TRIANGLES, VS::ARRAY_FORMAT_VERTEX|VS::ARRAY_FORMAT_NORMAL, p_faces.length() );
- VisualServer.mesh_surface_set_array(trimesh_mesh,0,VS::ARRAY_VERTEX, p_faces );
- VisualServer.mesh_surface_set_array(trimesh_mesh,0,VS::ARRAY_NORMAL, normals );
- local trimesh_mat = VisualServer.fixed_material_create();
- VisualServer.fixed_material_set_parameter( trimesh_mat, VisualServer.FIXED_MATERIAL_PARAM_DIFFUSE, Color(1.0,0.5,0.8));
- //VisualServer.material_set_flag( trimesh_mat, VisualServer.MATERIAL_FLAG_UNSHADED,true);
- VisualServer.mesh_surface_set_material( trimesh_mesh, 0, trimesh_mat );
-
- local triins = VisualServer.instance_create(trimesh_mesh);
-
-
- local tribody = PhysicsServer.body_create(RID(), PhysicsServer.BODY_MODE_STATIC);
- PhysicsServer.body_add_shape(tribody, trimesh_shape);
- tritrans = p_xform;
- PhysicsServer.body_set_state( tribody, PhysicsServer.BODY_STATE_TRANSFORM, tritrans );
- VisualServer.instance_set_transform( triins, tritrans );
- //RID trimesh_material = VisualServer.fixed_material_create();
- //VisualServer.material_generate( trimesh_material, Color(0.2,0.4,0.6) );
- //VisualServer.mesh_surface_set_material( trimesh_mesh, 0, trimesh_material );
-
- }
-
- function make_grid(p_width,p_height,p_cellsize,p_cellheight,p_xform=Transform()) {
-
- local grid = []
-
- for (local i =0;i<p_width;i++) {
-
- local row = []
-
- for (local j=0;j<p_height;j++) {
-
- local val = 1.0+Math.random(-p_cellheight, p_cellheight );
- row.append(val)
- }
- grid.append(row)
- }
-
- local faces=[]
-
- for (local i =1;i<p_width;i++) {
-
- for (local j=1;j<p_height;j++) {
-
- function MAKE_VERTEX(m_x,m_z) {
- local v= Vector3( (m_x-p_width/2)*p_cellsize, grid[m_x][m_z], (m_z-p_height/2)*p_cellsize )
- faces.push_back(v)
- }
-
-
- MAKE_VERTEX(i,j-1)
- MAKE_VERTEX(i,j)
- MAKE_VERTEX(i-1,j)
-
- MAKE_VERTEX(i-1,j-1)
- MAKE_VERTEX(i,j-1)
- MAKE_VERTEX(i-1,j)
-
- }
- }
-
- make_trimesh(faces,p_xform);
- }
-
- quit=false
-
- transform = Transform()
- camera=RID()
-
- function init_internal() {}
- function iteration_internal(time) {}
-//public
-
-
- function input_event(p_event) {
-
-
- }
-
- function request_quit() {
-
- quit=true;
- }
-
- function init() {
-
- init_shapes();
-
-
- /* LIGHT */
- local lightaux = VisualServer.light_create( VisualServer.LIGHT_DIRECTIONAL );
- //VisualServer.light_set_color( lightaux, VisualServer.LIGHT_COLOR_AMBIENT, Color(0.0,0.0,0.0) );
- VisualServer.light_set_shadow(lightaux,true);
- local light = VisualServer.instance_create( lightaux );
- local t=Transform()
- t.rotate(Vector3(1.0,0,0),0.6);
- VisualServer.instance_set_transform(light,t);
-
-
- /* CAMERA */
-
- camera = VisualServer.camera_create();
- local viewport = VisualServer.viewport_create();
- VisualServer.viewport_attach_camera( viewport, camera );
- VisualServer.viewport_set_parent(viewport, RID() );
-
- VisualServer.camera_set_perspective(camera,60,0.1,20.0);
- cameratr=Transform( Matrix3(), Vector3(0,2,8))
- VisualServer.camera_set_transform(camera,cameratr);
-
- quit=false;
-
- init_internal()
-
- }
-
-
- function iteration(p_time) {
-
- // VisualServer.camera_set_transform(camera,cameratr);
- iteration_internal(p_time)
-
- return quit;
- }
-
- function idle(p_time) {
-
- return quit;
- }
-
-
- function finish() {
-
- }
-
-
- constructor() {
- MainLoopScripted.constructor();
- }
-
-}
-
-
-return PhysicsTestBase;
diff --git a/doc/examples/physics/script/test_fall.sq b/doc/examples/physics/script/test_fall.sq
deleted file mode 100644
index 79526da8b4..0000000000
--- a/doc/examples/physics/script/test_fall.sq
+++ /dev/null
@@ -1,42 +0,0 @@
-
-include("test_base.sq")
-
-class TestFall extends PhysicsTestBase {
-
-
- fall_elements=10
-
- function init_internal() {
-
- for (local i=0;i<10;i++) {
-
- local shape_idx=[
- PhysicsServer.SHAPE_SPHERE,
- PhysicsServer.SHAPE_BOX,
- PhysicsServer.SHAPE_CAPSULE,
- PhysicsServer.SHAPE_CYLINDER,
- PhysicsServer.SHAPE_CONVEX_POLYGON
- ];
-
- local stype=shape_idx[i%5];
-// stype=PhysicsServer.SHAPE_SPHERE;
-
- local t=Transform()
- t.set_origin(Vector3(-0.7+0.0*i,3.5+4.1*i,0))
- t.rotate_basis(Vector3(1,0,0),Math.PI/4*i)
-
- local b = create_body(stype,PhysicsServer.BODY_MODE_RIGID,t);
-
- }
-
- create_static_plane( Plane( Vector3(0,1,0), -1) );
-
- }
-
- constructor() {
- PhysicsTestBase.constructor()
- }
-}
-
-
-return TestFall
diff --git a/doc/gdscript.lyx b/doc/gdscript.lyx
deleted file mode 100644
index a4b2230121..0000000000
--- a/doc/gdscript.lyx
+++ /dev/null
@@ -1,2531 +0,0 @@
-#LyX 2.0 created this file. For more info see http://www.lyx.org/
-\lyxformat 413
-\begin_document
-\begin_header
-\textclass article
-\use_default_options true
-\maintain_unincluded_children false
-\language english
-\language_package default
-\inputencoding auto
-\fontencoding global
-\font_roman default
-\font_sans default
-\font_typewriter default
-\font_default_family default
-\use_non_tex_fonts false
-\font_sc false
-\font_osf false
-\font_sf_scale 100
-\font_tt_scale 100
-
-\graphics default
-\default_output_format default
-\output_sync 0
-\bibtex_command default
-\index_command default
-\paperfontsize default
-\use_hyperref false
-\papersize default
-\use_geometry false
-\use_amsmath 1
-\use_esint 1
-\use_mhchem 1
-\use_mathdots 1
-\cite_engine basic
-\use_bibtopic false
-\use_indices false
-\paperorientation portrait
-\suppress_date false
-\use_refstyle 0
-\index Index
-\shortcut idx
-\color #008000
-\end_index
-\secnumdepth 3
-\tocdepth 3
-\paragraph_separation indent
-\paragraph_indentation default
-\quotes_language english
-\papercolumns 1
-\papersides 1
-\paperpagestyle default
-\tracking_changes false
-\output_changes false
-\html_math_output 0
-\html_css_as_file 0
-\html_be_strict false
-\end_header
-
-\begin_body
-
-\begin_layout Title
-GD Scripting Language (GDScript)
-\end_layout
-
-\begin_layout Section
-Introduction
-\end_layout
-
-\begin_layout Standard
-GDScript is a high level, dynamically typed programming language used to
- create content.
- It uses a syntax that is very similar to the Python language (blocks are
- indent-based) and it's goal is to be very optimal and tigthly integrated
- with the engine, allowing great flexibility for content creation and integratio
-n.
-
-\end_layout
-
-\begin_layout Section
-Example
-\end_layout
-
-\begin_layout Standard
-Some people can learn better by just taking a look at the syntax, so here's
- a simple example of how it looks.
-
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-#a file is a class!
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-#inheritance
-\end_layout
-
-\begin_layout Plain Layout
-
-extends BaseClass
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-#member variables
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-var a=5
-\end_layout
-
-\begin_layout Plain Layout
-
-var s="Hello"
-\end_layout
-
-\begin_layout Plain Layout
-
-var arr=[1,2,3]
-\end_layout
-
-\begin_layout Plain Layout
-
-var dict={"key":"value", 2:3}
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-#constants
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-const answer=42
-\end_layout
-
-\begin_layout Plain Layout
-
-const thename="Charly"
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-#built-in vector types
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-var v2 = Vector2(1,2)
-\end_layout
-
-\begin_layout Plain Layout
-
-var v3 = Vector3(1,2,3)
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-#function
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-func some_function(param1,param2):
-\end_layout
-
-\begin_layout Plain Layout
-
- var local_var=5
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
- if param1 < local_var:
-\end_layout
-
-\begin_layout Plain Layout
-
- print(param1)
-\end_layout
-
-\begin_layout Plain Layout
-
- elif param2 > 5:
-\end_layout
-
-\begin_layout Plain Layout
-
- print(param2)
-\end_layout
-
-\begin_layout Plain Layout
-
- else:
-\end_layout
-
-\begin_layout Plain Layout
-
- print("fail!")
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
- for i in range(20):
-\end_layout
-
-\begin_layout Plain Layout
-
- print(i)
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
- while(param2!=0):
-\end_layout
-
-\begin_layout Plain Layout
-
- param2-=1
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
- var local_var2 = param1+3
-\end_layout
-
-\begin_layout Plain Layout
-
- return local_var2
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-#subclass
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-class Something:
-\end_layout
-
-\begin_layout Plain Layout
-
- var a=10
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-#constructor
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-func _init():
-\end_layout
-
-\begin_layout Plain Layout
-
- print("constructed!")
-\end_layout
-
-\begin_layout Plain Layout
-
- var lv = Something.new()
-\end_layout
-
-\begin_layout Plain Layout
-
- print(lv.a)
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Section
-Language
-\end_layout
-
-\begin_layout Subsection
-Identifiers
-\end_layout
-
-\begin_layout Standard
-Any string that restricts itself to alphabetic characters ('a' to 'z' and
- 'A' to 'Z'), digits ('0' to '9') and '_' qualifies as an identifier.
- As an extra restriction, identifiers must not begin with a digit.
- Identifiers are case-sensitive ('foo' is different to 'FOO').
-\end_layout
-
-\begin_layout Subsection
-Keywords
-\end_layout
-
-\begin_layout Standard
-The following is the list of keywords supported by the language.
- Since keywords are reserved words (tokens), they can't be used as identifiers.
-\end_layout
-
-\begin_layout Subsection
-Operators
-\end_layout
-
-\begin_layout Standard
-The following is the list of supported operators and their precedence (TODO,
- change since this was made to reflect python operators)
-\end_layout
-
-\begin_layout Standard
-\begin_inset Tabular
-<lyxtabular version="3" rows="18" columns="2">
-<features tabularvalignment="middle">
-<column alignment="center" valignment="top" width="0">
-<column alignment="center" valignment="top" width="0">
-<row>
-<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-Operator
-\end_layout
-
-\end_inset
-</cell>
-<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" rightline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-Note
-\end_layout
-
-\end_inset
-</cell>
-</row>
-<row>
-<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-x[index]
-\end_layout
-
-\end_inset
-</cell>
-<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-Subscription, Highest Priority
-\end_layout
-
-\end_inset
-</cell>
-</row>
-<row>
-<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-x.attribute
-\end_layout
-
-\end_inset
-</cell>
-<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-Attribute Reference
-\end_layout
-
-\end_inset
-</cell>
-</row>
-<row>
-<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-extends
-\end_layout
-
-\end_inset
-</cell>
-<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-Instance Type Checker
-\end_layout
-
-\end_inset
-</cell>
-</row>
-<row>
-<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-~
-\end_layout
-
-\end_inset
-</cell>
-<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-Bitwise NOT
-\end_layout
-
-\end_inset
-</cell>
-</row>
-<row>
-<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
--x
-\end_layout
-
-\end_inset
-</cell>
-<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-Negative
-\end_layout
-
-\end_inset
-</cell>
-</row>
-<row>
-<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-* / %
-\end_layout
-
-\end_inset
-</cell>
-<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-Mult / Div / Remainder
-\end_layout
-
-\end_inset
-</cell>
-</row>
-<row>
-<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-+ -
-\end_layout
-
-\end_inset
-</cell>
-<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-Addition / Substraction
-\end_layout
-
-\end_inset
-</cell>
-</row>
-<row>
-<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-<< >>
-\end_layout
-
-\end_inset
-</cell>
-<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-Bit Shifting
-\end_layout
-
-\end_inset
-</cell>
-</row>
-<row>
-<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-&
-\end_layout
-
-\end_inset
-</cell>
-<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-Bitwise AND
-\end_layout
-
-\end_inset
-</cell>
-</row>
-<row>
-<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-^
-\end_layout
-
-\end_inset
-</cell>
-<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-Bitwise XOR
-\end_layout
-
-\end_inset
-</cell>
-</row>
-<row>
-<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-|
-\end_layout
-
-\end_inset
-</cell>
-<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-Bitwise OR
-\end_layout
-
-\end_inset
-</cell>
-</row>
-<row>
-<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-< > == != >= <=
-\end_layout
-
-\end_inset
-</cell>
-<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-Comparisons
-\end_layout
-
-\end_inset
-</cell>
-</row>
-<row>
-<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-in
-\end_layout
-
-\end_inset
-</cell>
-<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-Content Test
-\end_layout
-
-\end_inset
-</cell>
-</row>
-<row>
-<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-! not
-\end_layout
-
-\end_inset
-</cell>
-<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-Boolean NOT
-\end_layout
-
-\end_inset
-</cell>
-</row>
-<row>
-<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-and &&
-\end_layout
-
-\end_inset
-</cell>
-<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-Boolean AND
-\end_layout
-
-\end_inset
-</cell>
-</row>
-<row>
-<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-or ||
-\end_layout
-
-\end_inset
-</cell>
-<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-Boolean OR
-\end_layout
-
-\end_inset
-</cell>
-</row>
-<row>
-<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-= += -= *= /= ^= &= |=
-\end_layout
-
-\end_inset
-</cell>
-<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" rightline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-Assignment, Lowest Priority
-\end_layout
-
-\end_inset
-</cell>
-</row>
-</lyxtabular>
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Subsection
-Literals
-\end_layout
-
-\begin_layout Standard
-\begin_inset Tabular
-<lyxtabular version="3" rows="6" columns="2">
-<features tabularvalignment="middle">
-<column alignment="center" valignment="top" width="0">
-<column alignment="center" valignment="top" width="0">
-<row>
-<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-Literal
-\end_layout
-
-\end_inset
-</cell>
-<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" rightline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-Name
-\end_layout
-
-\end_inset
-</cell>
-</row>
-<row>
-<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-45
-\end_layout
-
-\end_inset
-</cell>
-<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-Base 10 Integer
-\end_layout
-
-\end_inset
-</cell>
-</row>
-<row>
-<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-0x8F51
-\end_layout
-
-\end_inset
-</cell>
-<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-Base 16 (hex) Integer
-\end_layout
-
-\end_inset
-</cell>
-</row>
-<row>
-<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-3.14, 58.1e-10
-\end_layout
-
-\end_inset
-</cell>
-<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-Floating Point Number (real)
-\end_layout
-
-\end_inset
-</cell>
-</row>
-<row>
-<cell alignment="center" valignment="top" topline="true" leftline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-'Hello',
-\begin_inset Quotes eld
-\end_inset
-
-Hi
-\begin_inset Quotes erd
-\end_inset
-
-
-\end_layout
-
-\end_inset
-</cell>
-<cell alignment="center" valignment="top" topline="true" leftline="true" rightline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-Strings
-\end_layout
-
-\end_inset
-</cell>
-</row>
-<row>
-<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-@'Hello', @'Hi'
-\end_layout
-
-\end_inset
-</cell>
-<cell alignment="center" valignment="top" topline="true" bottomline="true" leftline="true" rightline="true" usebox="none">
-\begin_inset Text
-
-\begin_layout Plain Layout
-Internationalized Strings
-\end_layout
-
-\end_inset
-</cell>
-</row>
-</lyxtabular>
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Subsection
-Comments
-\end_layout
-
-\begin_layout Standard
-Anything from a '#' to the end of the line is ignored and is considered
- a comment.
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-lstparams "language=Python"
-inline false
-status open
-
-\begin_layout Plain Layout
-
-# This is a comment
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Section
-Built-in Types
-\end_layout
-
-\begin_layout Subsection
-Basic Bult-In Types
-\end_layout
-
-\begin_layout Standard
-A variable in GDScript can be assigned many of several built-in types.
-
-\end_layout
-
-\begin_layout Subsubsection
-null
-\end_layout
-
-\begin_layout Standard
-'null' is a data type that contains no information, nothing assigned, and
- it's just empy.
- It can only be set to one value: 'null'.
-\end_layout
-
-\begin_layout Subsubsection
-bool
-\end_layout
-
-\begin_layout Standard
-Boolean data type, can only contain 'true' or 'false'.
-\end_layout
-
-\begin_layout Subsubsection
-int
-\end_layout
-
-\begin_layout Standard
-Integer data type, can only contain integer numbers, negative and positive.
-\end_layout
-
-\begin_layout Subsubsection
-float
-\end_layout
-
-\begin_layout Standard
-contains a floating point value (real).
-\end_layout
-
-\begin_layout Subsubsection
-String
-\end_layout
-
-\begin_layout Standard
-Sequence of characters in unicode format.
- Strings can contain the standard C escape sequences.
-\end_layout
-
-\begin_layout Subsection
-Vector Built-In Types
-\end_layout
-
-\begin_layout Subsubsection
-Vector2/Size2
-\end_layout
-
-\begin_layout Standard
-2D vector type, containing x and y fields.
- Can alternatively access fields as width and height for readability.
- Can also be accessed as array.
-\end_layout
-
-\begin_layout Subsubsection
-Rect2
-\end_layout
-
-\begin_layout Standard
-2D Rectangle type.
- Contains 2 vectors fields,
-\begin_inset Quotes eld
-\end_inset
-
-pos
-\begin_inset Quotes erd
-\end_inset
-
- and size
-\begin_inset Quotes erd
-\end_inset
-
-.
- Alternatively contains an
-\begin_inset Quotes eld
-\end_inset
-
-end
-\begin_inset Quotes erd
-\end_inset
-
- field which is
-\begin_inset Quotes eld
-\end_inset
-
-pos+size
-\begin_inset Quotes erd
-\end_inset
-
-.
-\end_layout
-
-\begin_layout Subsubsection
-Vector3
-\end_layout
-
-\begin_layout Standard
-3D vector type.
- Contains x, y and z fields.
- Can also be accessed as array.
-\end_layout
-
-\begin_layout Subsubsection
-Matrix32
-\end_layout
-
-\begin_layout Standard
-3x2 matrix used for 2D transforms.
-\end_layout
-
-\begin_layout Subsubsection
-Plane
-\end_layout
-
-\begin_layout Standard
-3D Plane type in normalized form.
- Contains a
-\begin_inset Quotes eld
-\end_inset
-
-normal
-\begin_inset Quotes erd
-\end_inset
-
- vector field and a
-\begin_inset Quotes eld
-\end_inset
-
-d
-\begin_inset Quotes erd
-\end_inset
-
- scalar distance.
-\end_layout
-
-\begin_layout Subsubsection
-Quat
-\end_layout
-
-\begin_layout Standard
-Quaternion, datatype used for representing a 3D rotation.
- It's useful for interpolating rotations.
-\end_layout
-
-\begin_layout Subsubsection
-AABB/Box3
-\end_layout
-
-\begin_layout Standard
-Axis Aligned bounding box (or alternatively, 3D box).
- Contains 2 vectors fields,
-\begin_inset Quotes eld
-\end_inset
-
-pos
-\begin_inset Quotes erd
-\end_inset
-
- and size
-\begin_inset Quotes erd
-\end_inset
-
-.
- Alternatively contains an
-\begin_inset Quotes eld
-\end_inset
-
-end
-\begin_inset Quotes erd
-\end_inset
-
- field which is
-\begin_inset Quotes eld
-\end_inset
-
-pos+size
-\begin_inset Quotes erd
-\end_inset
-
-.
-\end_layout
-
-\begin_layout Subsubsection
-Matrix3
-\end_layout
-
-\begin_layout Standard
-3x3 matrix used for 3D rotation and scale.
- Contains 3 vector fields x,y and z.
- Can also be accessed as array of 3D vectors.
-\end_layout
-
-\begin_layout Subsubsection
-Transform
-\end_layout
-
-\begin_layout Standard
-3D Transform, contains a Matrix3 field
-\begin_inset Quotes eld
-\end_inset
-
-basis
-\begin_inset Quotes erd
-\end_inset
-
- and a Vector3 field
-\begin_inset Quotes eld
-\end_inset
-
-origin
-\begin_inset Quotes erd
-\end_inset
-
-.
-\end_layout
-
-\begin_layout Subsection
-Engine Built-In Types
-\end_layout
-
-\begin_layout Subsubsection
-Color
-\end_layout
-
-\begin_layout Standard
-Color datatype, contains r,g,b,a fields.
- Can also be accessed as h,s,v for hue/saturation/value.
-\end_layout
-
-\begin_layout Subsubsection
-Image
-\end_layout
-
-\begin_layout Standard
-Contains a 2D Image of custom format and allows direct access to the pixels.
-\end_layout
-
-\begin_layout Subsubsection
-NodePath
-\end_layout
-
-\begin_layout Standard
-Compiled path to a node, used mainly in the scene system.
- Can be easily asigned from/to a String.
-\end_layout
-
-\begin_layout Subsubsection
-RID
-\end_layout
-
-\begin_layout Standard
-Resource ID (RID).
- Servers use generic RIDs to reference opaque data.
-\end_layout
-
-\begin_layout Subsubsection
-Object
-\end_layout
-
-\begin_layout Standard
-Base class for anything not a built-in type.
-
-\end_layout
-
-\begin_layout Subsubsection
-InputEvent
-\end_layout
-
-\begin_layout Standard
-Events from input devices are contained in very compact form in InputEvent
- objects.
- Due to fact they can be received in high amounts from frame to frame, they
- are optimized in their own datatype.
-
-\end_layout
-
-\begin_layout Subsection
-Container Built-In Types
-\end_layout
-
-\begin_layout Subsubsection
-Array
-\end_layout
-
-\begin_layout Standard
-Generic sequence of objects.
- It's size can be changed to anything and starts from index 0.
-
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-var arr=[]
-\end_layout
-
-\begin_layout Plain Layout
-
-arr=[1,2,3]
-\end_layout
-
-\begin_layout Plain Layout
-
-arr[0]="Hi!"
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Standard
-Arrays are allocated linearly in memory, so they are fast, but very large
- arrays (more than tens of thousands of elements) may cause fragmentation.
- There are specialized arrays for some built-in datatypes which do not suffer
- from this and use much less memory.
-\end_layout
-
-\begin_layout Subsubsection
-Dictionary
-\end_layout
-
-\begin_layout Standard
-Associative container which contains values referenced by unique keys.
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-var dict={4:5, "a key":"a value", 28:[1,2,3]}
-\end_layout
-
-\begin_layout Plain Layout
-
-dict["Hi!"]=0
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Subsubsection
-ByteArray
-\end_layout
-
-\begin_layout Standard
-Array of bytes.
- Can only contains bytes (integers from 0 to 255).
- Optimized for memory usage, can't fragment the memory.
-\end_layout
-
-\begin_layout Subsubsection
-IntArray
-\end_layout
-
-\begin_layout Standard
-Array of integers.
- Can only contain integers.
- Optimized for memory usage, can't fragment the memory.
-\end_layout
-
-\begin_layout Subsubsection
-FloatArray
-\end_layout
-
-\begin_layout Standard
-Array of floats, can only contain floats.
- Optimized for memory usage, can't fragment the memory.
-\end_layout
-
-\begin_layout Subsubsection
-StringArray
-\end_layout
-
-\begin_layout Standard
-Array of strings, can only contain strings.
- Optimized for memory usage, can't fragment the memory.
-\end_layout
-
-\begin_layout Subsubsection
-Vector2Array
-\end_layout
-
-\begin_layout Standard
-Array of Vector2, can only contain 2D Vectors.
- Optimized for memory usage, can't fragment the memory.
-\end_layout
-
-\begin_layout Subsubsection
-Vector3Array
-\end_layout
-
-\begin_layout Standard
-Array of Vector3, can only contain 3D Vectors.
- Optimized for memory usage, can't fragment the memory.
-\end_layout
-
-\begin_layout Subsubsection
-ColorArray
-\end_layout
-
-\begin_layout Standard
-Array of Color, can only contains colors.
- Optimized for memory usage, can't fragment the memory.
-\end_layout
-
-\begin_layout Section
-Data
-\end_layout
-
-\begin_layout Subsection
-Variables
-\end_layout
-
-\begin_layout Standard
-Variables can exist as class members or local to functions.
- They are created with the
-\begin_inset Quotes eld
-\end_inset
-
-var
-\begin_inset Quotes erd
-\end_inset
-
- keyword and may be, optionally, be assigned a value upon initialization.
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-var a # datatype is null by default
-\end_layout
-
-\begin_layout Plain Layout
-
-var b = 5
-\end_layout
-
-\begin_layout Plain Layout
-
-var c = 3.8
-\end_layout
-
-\begin_layout Plain Layout
-
-var d = b+c # variables are always initialized in order
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Subsection
-Constants
-\end_layout
-
-\begin_layout Standard
-Constants are similar to variables, but must be constants or constant expression
-s and must be assigned on initialization.
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-const a = 5
-\end_layout
-
-\begin_layout Plain Layout
-
-const b = Vector2(20,20)
-\end_layout
-
-\begin_layout Plain Layout
-
-const c = 10+20 # constant expression
-\end_layout
-
-\begin_layout Plain Layout
-
-const d = Vector2(20,30).x # constant expression: 20
-\end_layout
-
-\begin_layout Plain Layout
-
-const e = [1,2,3,4][0] # constant expression: 1
-\end_layout
-
-\begin_layout Plain Layout
-
-const f = sin(20) # sin() can be used in constant expression
-\end_layout
-
-\begin_layout Plain Layout
-
-const g = x+20 # invalid, not a constant expression!
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Subsection
-Functions
-\end_layout
-
-\begin_layout Standard
-Functions always belong to a class.
- The scope priority for variable look-up is: local -> class member -> global.
-
-\begin_inset Quotes eld
-\end_inset
-
-self
-\begin_inset Quotes erd
-\end_inset
-
- is provided as an option for accessing class members but is not required
- always (and must
-\emph on
-not
-\emph default
- be defined as first parameter, like in Python).
- For performance reasons, functions are not considered class members, so
- they can't be referenced directly.
- A function can return at any point.
- The default return value is null.
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-func myfunction(a,b):
-\end_layout
-
-\begin_layout Plain Layout
-
- print(a)
-\end_layout
-
-\begin_layout Plain Layout
-
- print(b)
-\end_layout
-
-\begin_layout Plain Layout
-
- return a+b # return is optional, otherwise null is returned
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Subsubsection
-Statements and Control Flow
-\end_layout
-
-\begin_layout Standard
-Statements are standard, and can be assignments, function calls, control
- flow structures, etc (see below).
-
-\begin_inset Quotes eld
-\end_inset
-
-;
-\begin_inset Quotes erd
-\end_inset
-
- as separator is entirely optional.
-\end_layout
-
-\begin_layout Subsubsection
-if/else/elif
-\end_layout
-
-\begin_layout Standard
-Simple conditions are created by using the
-\emph on
-if/else/elif
-\emph default
- syntax.
- Parenthesis around statements is allowed but not requiered.
- Given the nature of the tab-based indentation, elif can be used instead
- of else:/if: to mantain a level of indentation.
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-if [expression]:
-\end_layout
-
-\begin_layout Plain Layout
-
- statement(s)
-\end_layout
-
-\begin_layout Plain Layout
-
-elif [expression]:
-\end_layout
-
-\begin_layout Plain Layout
-
- statement(s)
-\end_layout
-
-\begin_layout Plain Layout
-
-else:
-\end_layout
-
-\begin_layout Plain Layout
-
- statement(s)
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Subsubsection
-while
-\end_layout
-
-\begin_layout Standard
-Simple loops are created by using
-\emph on
-while
-\emph default
- syntax.
- Loops can be broken using
-\emph on
-break
-\emph default
-, or continued using
-\emph on
-continue
-\emph default
-:
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-while [expression]:
-\end_layout
-
-\begin_layout Plain Layout
-
- statement(s)
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Subsubsection
-for
-\end_layout
-
-\begin_layout Standard
-To iterate a range, array or table a
-\emph on
-for
-\emph default
- loop is used.
- For loops store the index in the loop variable on each iteration.
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-for i in [0,1,2]:
-\end_layout
-
-\begin_layout Plain Layout
-
- statement # loop iterates 3 times, i being 0,1 and 2
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-var dict = {"a":0, "b":1, "c": 2}
-\end_layout
-
-\begin_layout Plain Layout
-
-for i in dict:
-\end_layout
-
-\begin_layout Plain Layout
-
- print(dict[i]) # loop iterates the keys, i being "a","b" and c".
- It prints 0, 1 and 2.
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-for i in range(3):
-\end_layout
-
-\begin_layout Plain Layout
-
- statement # similar to [0,1,2] but does not allocate an array
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-for i in range(1,3):
-\end_layout
-
-\begin_layout Plain Layout
-
- statement # similar to [1,2] but does not allocate an array
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-for i in range(2,8,2):
-\end_layout
-
-\begin_layout Plain Layout
-
- statement # similar to [2,4,6] but does not allocate an array
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Section
-Classes
-\end_layout
-
-\begin_layout Standard
-By default, the body of a script file is an unnamed class, and it can only
- be referenced externally as a resource or file.
- Class syntax is meant to be very compact and can only contain member variables
- or functions.
- Static functions are allowed, but not static members (in the spirit of
- thread safety, since scripts can be initialized in separate threads without
- the user knowing).
- In the same way, member variables (including arrays and dictionaries) are
- initialized every time an instance is created.
-
-\end_layout
-
-\begin_layout Subsection
-Class File Example
-\end_layout
-
-\begin_layout Standard
-Example of a class file, imagine it being stored in a file like myclass.gd.
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-var a=5
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-function print_value_of_a():
-\end_layout
-
-\begin_layout Plain Layout
-
- print(a)
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Subsection
-Inheritance
-\end_layout
-
-\begin_layout Standard
-A class-file can inherit from a global class, another file or a subclass
- inside another file.
- Multiple inheritance is not allowed.
- The
-\begin_inset Quotes eld
-\end_inset
-
-extends
-\begin_inset Quotes erd
-\end_inset
-
- syntax is used:
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-# extend from some class (global)
-\end_layout
-
-\begin_layout Plain Layout
-
-extends SomeClass
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-# optionally, extend from another file
-\end_layout
-
-\begin_layout Plain Layout
-
-extends "somefile.gd"
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-# extend from a subclass in another file
-\end_layout
-
-\begin_layout Plain Layout
-
-extends "somefile.gd".Subclass
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Subsection
-Inheritance Testing
-\end_layout
-
-\begin_layout Standard
-It is possible to check if an instance inherits from a given class.
- For this the
-\begin_inset Quotes eld
-\end_inset
-
-extends
-\begin_inset Quotes erd
-\end_inset
-
- keyword can be used as an operator instead:
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-static var enemy_class = preload("enemy.gd") # cache the enemy class
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-[..]
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-if ( entity extends enemy_class ):
-\end_layout
-
-\begin_layout Plain Layout
-
- entity.apply_damage()
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Subsection
-Constructor
-\end_layout
-
-\begin_layout Standard
-A class can have an optional constructor, a function named
-\begin_inset Quotes eld
-\end_inset
-
-_init
-\begin_inset Quotes erd
-\end_inset
-
- that is called when the class is instanced.
-\end_layout
-
-\begin_layout Subsection
-Sub Classes
-\end_layout
-
-\begin_layout Standard
-A class file can have subclasses.
- Syntax should be straightforward:
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-class SomeSubClass:
-\end_layout
-
-\begin_layout Plain Layout
-
- var a=5
-\end_layout
-
-\begin_layout Plain Layout
-
- function print_value_of_a():
-\end_layout
-
-\begin_layout Plain Layout
-
- print(a)
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-function _init():
-\end_layout
-
-\begin_layout Plain Layout
-
- var sc = SomeSubClass.new() #instance by calling built-in new
-\end_layout
-
-\begin_layout Plain Layout
-
- sc.print_value_of_a()
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Subsection
-Classes as Objects
-\end_layout
-
-\begin_layout Standard
-It may be desired at some point to load a class from a file and then instance
- it.
- Since the global scope does not exist, classes must be loaded as a resource.
- Instancing is done by calling the
-\begin_inset Quotes eld
-\end_inset
-
-new
-\begin_inset Quotes erd
-\end_inset
-
- function in a class object:
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-#load the class (loaded every time the script is instanced)
-\end_layout
-
-\begin_layout Plain Layout
-
-var MyClass = load("myclass.gd")
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-#alternatively, using the preload() function preloads the class at compile
- time
-\end_layout
-
-\begin_layout Plain Layout
-
-var MyClass2 = preload("myclass.gd")
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-function _init():
-\end_layout
-
-\begin_layout Plain Layout
-
- var a = MyClass.new()
-\end_layout
-
-\begin_layout Plain Layout
-
- a.somefunction()
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Subsection
-Exports
-\end_layout
-
-\begin_layout Standard
-Class members can be exported.
- This means their value gets saved along with a scene.
- If class members have initializers to constant expressions, they will be
- available for editing in the property editor.
- Exporting is done by using the export keyword:
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-extends Button
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-export var data # value will be saved
-\end_layout
-
-\begin_layout Plain Layout
-
-export var number=5 # also available to the property editor
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Standard
-One of the fundamental benefits of exporting member variables is to have
- them visible in the property editor.
- This way artists and game designers can modify values that later influence
- how the program runs.
- For this, a special export syntax is provided for more detail in the exported
- variables:
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-#if the exported value assigns a constant or constant expression, the type
- will be infered and used in the editor
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-export var number=5
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-#export can take a basic datatype as argument, which will be used in the
- editor
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-export(int) var number
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-#export can also take a resource type as hint
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-export(Texture) var character_face
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-#integers and strings hint enumerated values
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-export(int,"Warrior","Magician","Thief") var character_class # (editor will
- set them as 0,1 and 2)
-\end_layout
-
-\begin_layout Plain Layout
-
-export(String,"Rebecca","Mary","Leah") var character_name
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-#strings as paths
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-export(String,FILE) var f # string is a path to a file
-\end_layout
-
-\begin_layout Plain Layout
-
-export(String,DIR) var f # string is a path to a directory
-\end_layout
-
-\begin_layout Plain Layout
-
-export(String,FILE,"*.txt") var f # string is a path to a file, custom filter
- provided as hint
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-#integers and floats hint ranges
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-export(int,20) var i # 0 to 20 allowed
-\end_layout
-
-\begin_layout Plain Layout
-
-export(int,-10,20) var j # -10 to 20 allowed
-\end_layout
-
-\begin_layout Plain Layout
-
-export(float,-10,20,0.2) var k # -10 to 20 allowed, with stepping of 0.2
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-#color can hint availability of alpha
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-export(Color,RGB) var col # Color is RGB
-\end_layout
-
-\begin_layout Plain Layout
-
-export(Color,RGBA) var col # Color is RGBA
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Standard
-It must be noted that even if the script is not being run while at the editor,
- the exported properties are still editable (see below for
-\begin_inset Quotes eld
-\end_inset
-
-tool
-\begin_inset Quotes erd
-\end_inset
-
-).
-\end_layout
-
-\begin_layout Subsection
-Static Functions
-\end_layout
-
-\begin_layout Standard
-A function can be declared static.
- When static, it has no access to the instance member variables or
-\begin_inset Quotes eld
-\end_inset
-
-self
-\begin_inset Quotes erd
-\end_inset
-
-.
- This is mainly useful to make libraries of helper functions:
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-static func sum2(a,b):
-\end_layout
-
-\begin_layout Plain Layout
-
- return a+b
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Subsection
-Asserting
-\end_layout
-
-\begin_layout Standard
-It is possible to assert a condition, which will cause a debugger break
- if false.
- Just use the built-in 'assert' function.
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-assert(a==2)
-\end_layout
-
-\begin_layout Plain Layout
-
-# if a is not 2, it will generate a debugger break
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Subsection
-Tool Mode
-\end_layout
-
-\begin_layout Standard
-Scripts by default don't run inside the editor, and only the exported properties
- can be changed.
- In some cases it is desired that they do (as long as they don't execute
- game code or manually avoid doing so).
- For this, the
-\begin_inset Quotes eld
-\end_inset
-
-tool
-\begin_inset Quotes erd
-\end_inset
-
- keyword exists, and must be placed at the top of the file:
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-tool
-\end_layout
-
-\begin_layout Plain Layout
-
-extends Button
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-func _init():
-\end_layout
-
-\begin_layout Plain Layout
-
- print("Hello")
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Subsection
-Memory Management
-\end_layout
-
-\begin_layout Standard
-If a class inherits from
-\emph on
-Reference
-\emph default
-, then instances will be freed when no longer in use.
- No garbage collector exists, just simple reference counting.
- By default, all classes that don't define inheritance extend
-\emph on
-Reference
-\emph default
-.
- If this is not desired, then a class must inherit
-\emph on
-Object
-\emph default
- manually and must call instance.free().
- To avoid reference cycles that can't be freed, a weakref() function is
- provided for creating weak references.
-
-\end_layout
-
-\begin_layout Subsection
-Function References
-\end_layout
-
-\begin_layout Standard
-Functions can't be referenced because they are not treated as class members.
- There are two alternatives to this, though.
- The
-\begin_inset Quotes eld
-\end_inset
-
-call
-\begin_inset Quotes erd
-\end_inset
-
- function or the funcref() helper.
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-instance.call("funcname",args) # call a function by bane
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-var fr = funcref(instance,"funcname") #create a function ref
-\end_layout
-
-\begin_layout Plain Layout
-
-fr.exec(args)
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\end_body
-\end_document
diff --git a/doc/godot_splash.png b/doc/godot_splash.png
deleted file mode 100644
index da56fa15cc..0000000000
--- a/doc/godot_splash.png
+++ /dev/null
Binary files differ
diff --git a/doc/header.txt b/doc/header.txt
deleted file mode 100644
index 359949cc3b..0000000000
--- a/doc/header.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-/*************************************************/
-/* $filename */
-/*************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/*************************************************/
-/* Source code within this file is: */
-/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
-/* All Rights Reserved. */
-/*************************************************/
-
-
diff --git a/doc/html/@GDScript.html b/doc/html/@GDScript.html
deleted file mode 100644
index 5d5d77ffbf..0000000000
--- a/doc/html/@GDScript.html
+++ /dev/null
@@ -1,93 +0,0 @@
-<html><link href="main.css" rel="stylesheet" type="text/css" /><body><table class="top_table"><tr><td class="top_table"><image src="images/logo.png" /></td><td class="top_table"><a href="index.html">Index</a></td><td class="top_table"><a href="alphabetical.html">Classes</a></td><td class="top_table"><a href="category.html">Categories</a></td><td><a href="inheritance.html">Inheritance</a></td></tr></table><hr /><div class="class"><a name="@GDScript"><h3 class="title class_title">@GDScript</h3></a><div class="description class_description">
- Built-in GDScript functions.
- </div><br /><div class="category"><span class="category">Category: </span><a class="category_ref" href="category.html#CATEGORY_Core">Core</a></div><h4>Public Methods:</h4><table class="method_list"><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_sin">sin</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_cos">cos</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_tan">tan</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_sinh">sinh</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_cosh">cosh</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_tanh">tanh</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_asin">asin</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_acos">acos</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_atan">atan</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_atan2">atan2</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>x</span><span>, </span><a class="datatype_existing" href="real.html">real </a><span>y</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_sqrt">sqrt</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_fmod">fmod</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>x</span><span>, </span><a class="datatype_existing" href="real.html">real </a><span>y</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_fposmod">fposmod</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>x</span><span>, </span><a class="datatype_existing" href="real.html">real </a><span>y</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_floor">floor</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_ceil">ceil</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_round">round</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_abs">abs</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_sign">sign</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_pow">pow</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>x</span><span>, </span><a class="datatype_existing" href="real.html">real </a><span>y</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_log">log</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_exp">exp</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_isnan">isnan</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_isinf">isinf</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_ease">ease</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span>, </span><a class="datatype_existing" href="real.html">real </a><span>curve</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_decimals">decimals</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>step</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_stepify">stepify</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span>, </span><a class="datatype_existing" href="real.html">real </a><span>step</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="int.html">int </a></td><td><span class="identifier funcdef"><a href="#@GDScript_rand">rand</a></span><span class="symbol"> (</span><span class="symbol">)</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_randf">randf</a></span><span class="symbol"> (</span><span class="symbol">)</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_rand_range">rand_range</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>from</span><span>, </span><a class="datatype_existing" href="real.html">real </a><span>to</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="Array.html">Array </a></td><td><span class="identifier funcdef"><a href="#@GDScript_rand_seed">rand_seed</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>seed</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_deg2rad">deg2rad</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>deg</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_rad2deg">rad2deg</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>rad</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_linear2db">linear2db</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>nrg</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_db2linear">db2linear</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>db</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_max">max</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>a</span><span>, </span><a class="datatype_existing" href="real.html">real </a><span>b</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_min">min</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>a</span><span>, </span><a class="datatype_existing" href="real.html">real </a><span>b</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="real.html">real </a></td><td><span class="identifier funcdef"><a href="#@GDScript_clamp">clamp</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>val</span><span>, </span><a class="datatype_existing" href="real.html">real </a><span>min</span><span>, </span><a class="datatype_existing" href="real.html">real </a><span>max</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="int.html">int </a></td><td><span class="identifier funcdef"><a href="#@GDScript_nearest_po2">nearest_po2</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="int.html">int </a><span>val</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="Object.html">Object </a></td><td><span class="identifier funcdef"><a href="#@GDScript_weakref">weakref</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="Object.html">Object </a><span>obj</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="Object.html">Object </a></td><td><span class="identifier funcdef"><a href="#@GDScript_convert">convert</a></span><span class="symbol"> (</span><span> </span><span class="datatype">var </span><span>what</span><span>, </span><a class="datatype_existing" href="int.html">int </a><span>type</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="String.html">String </a></td><td><span class="identifier funcdef"><a href="#@GDScript_str">str</a></span><span class="symbol"> (</span><span> </span><span class="datatype">var </span><span>what</span><span>, </span><span class="datatype">var </span><span>...</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="Nil.html">Nil </a></td><td><span class="identifier funcdef"><a href="#@GDScript_print">print</a></span><span class="symbol"> (</span><span> </span><span class="datatype">var </span><span>what</span><span>, </span><span class="datatype">var </span><span>...</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="Nil.html">Nil </a></td><td><span class="identifier funcdef"><a href="#@GDScript_printerr">printerr</a></span><span class="symbol"> (</span><span> </span><span class="datatype">var </span><span>what</span><span>, </span><span class="datatype">var </span><span>...</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="Nil.html">Nil </a></td><td><span class="identifier funcdef"><a href="#@GDScript_printraw">printraw</a></span><span class="symbol"> (</span><span> </span><span class="datatype">var </span><span>what</span><span>, </span><span class="datatype">var </span><span>...</span><span class="symbol"> )</span></td></tr><tr class="method"><td align="right"><a class="datatype_existing" href="Array.html">Array </a></td><td><span class="identifier funcdef"><a href="#@GDScript_range">range</a></span><span class="symbol"> (</span><span> </span><span class="datatype">var </span><span>...</span><span class="symbol"> )</span></td></tr></table><h4>Description:</h4><div class="description">
- This contains the list of built-in gdscript functions. Mostly math functions and other utilities. Everything else is expanded by objects.
- </div><h4>Method Documentation:</h4><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_sin">@GDScript::sin</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></div><div class="description">
- Standard sine function.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_cos">@GDScript::cos</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></div><div class="description">
- Standard cosine function.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_tan">@GDScript::tan</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></div><div class="description">
- Standard tangent function.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_sinh">@GDScript::sinh</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></div><div class="description">
- Hyperbolic sine.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_tanh">@GDScript::tanh</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></div><div class="description">
- Hyperbolic tangent.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_asin">@GDScript::asin</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></div><div class="description">
- Arc-sine.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_acos">@GDScript::acos</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></div><div class="description">
- Arc-cosine.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_atan">@GDScript::atan</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></div><div class="description">
- Arc-tangent.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_atan2">@GDScript::atan2</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>x</span><span>, </span><a class="datatype_existing" href="real.html">real </a><span>y</span><span class="symbol"> )</span></div><div class="description">
- Arc-tangent that takes a 2D vector as argument, retuns the full -pi to +pi range.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_sqrt">@GDScript::sqrt</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></div><div class="description">
- Square root.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_fmod">@GDScript::fmod</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>x</span><span>, </span><a class="datatype_existing" href="real.html">real </a><span>y</span><span class="symbol"> )</span></div><div class="description">
- Module (remainder of x/y).
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_fposmod">@GDScript::fposmod</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>x</span><span>, </span><a class="datatype_existing" href="real.html">real </a><span>y</span><span class="symbol"> )</span></div><div class="description">
- Module (remainder of x/y) that wraps equally in positive and negative.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_floor">@GDScript::floor</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></div><div class="description">
- Floor (rounds down to nearest integer).
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_ceil">@GDScript::ceil</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></div><div class="description">
- Ceiling (rounds up to nearest integer).
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_round">@GDScript::round</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></div><div class="description">
- Round to nearest integer.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_abs">@GDScript::abs</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></div><div class="description">
- Remove sign (works for integer and float).
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_sign">@GDScript::sign</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></div><div class="description">
- Return sign (-1 or +1).
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_pow">@GDScript::pow</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>x</span><span>, </span><a class="datatype_existing" href="real.html">real </a><span>y</span><span class="symbol"> )</span></div><div class="description">
- Power function, x elevate to y.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_log">@GDScript::log</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></div><div class="description">
- Natural logarithm.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_exp">@GDScript::exp</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></div><div class="description">
- Exponential logarithm.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_isnan">@GDScript::isnan</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></div><div class="description">
- Return true if the float is not a number.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_isinf">@GDScript::isinf</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span class="symbol"> )</span></div><div class="description">
- Return true if the float is infinite.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_ease">@GDScript::ease</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span>, </span><a class="datatype_existing" href="real.html">real </a><span>curve</span><span class="symbol"> )</span></div><div class="description">
- Easing function, based on exponent. 0 is constant, 1 is linear, 0 to 1 is ease-in, 1+ is ease out. Negative values are in-out/out in.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_decimals">@GDScript::decimals</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>step</span><span class="symbol"> )</span></div><div class="description">
- Return the amount of decimals in the floating point value.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_stepify">@GDScript::stepify</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>s</span><span>, </span><a class="datatype_existing" href="real.html">real </a><span>step</span><span class="symbol"> )</span></div><div class="description">
- Snap float value to a given step.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="int.html">int </a><span class="funcdecl"><a name="@GDScript_rand">@GDScript::rand</a></span><span class="symbol"> (</span><span class="symbol">)</span></div><div class="description">
- Random value (integer).
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_randf">@GDScript::randf</a></span><span class="symbol"> (</span><span class="symbol">)</span></div><div class="description">
- Random value (0 to 1 float).
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_rand_range">@GDScript::rand_range</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>from</span><span>, </span><a class="datatype_existing" href="real.html">real </a><span>to</span><span class="symbol"> )</span></div><div class="description">
- Random range.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="Array.html">Array </a><span class="funcdecl"><a name="@GDScript_rand_seed">@GDScript::rand_seed</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>seed</span><span class="symbol"> )</span></div><div class="description">
- random from seed, pass a seed and an array with both number and new seed is returned.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_deg2rad">@GDScript::deg2rad</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>deg</span><span class="symbol"> )</span></div><div class="description">
- Convert from degrees to radians.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_rad2deg">@GDScript::rad2deg</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>rad</span><span class="symbol"> )</span></div><div class="description">
- Convert from radias to degrees.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_linear2db">@GDScript::linear2db</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>nrg</span><span class="symbol"> )</span></div><div class="description">
- Convert from linear energy to decibels (audio).
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_db2linear">@GDScript::db2linear</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>db</span><span class="symbol"> )</span></div><div class="description">
- Convert from decibels to linear energy (audio).
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_max">@GDScript::max</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>a</span><span>, </span><a class="datatype_existing" href="real.html">real </a><span>b</span><span class="symbol"> )</span></div><div class="description">
- Return the maximum of two values.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_min">@GDScript::min</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>a</span><span>, </span><a class="datatype_existing" href="real.html">real </a><span>b</span><span class="symbol"> )</span></div><div class="description">
- Return the minimum of two values.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="real.html">real </a><span class="funcdecl"><a name="@GDScript_clamp">@GDScript::clamp</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="real.html">real </a><span>val</span><span>, </span><a class="datatype_existing" href="real.html">real </a><span>min</span><span>, </span><a class="datatype_existing" href="real.html">real </a><span>max</span><span class="symbol"> )</span></div><div class="description">
- Clamp both values to a range.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="int.html">int </a><span class="funcdecl"><a name="@GDScript_nearest_po2">@GDScript::nearest_po2</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="int.html">int </a><span>val</span><span class="symbol"> )</span></div><div class="description">
- Return the nearest larger power of 2 for an integer.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="Object.html">Object </a><span class="funcdecl"><a name="@GDScript_weakref">@GDScript::weakref</a></span><span class="symbol"> (</span><span> </span><a class="datatype_existing" href="Object.html">Object </a><span>obj</span><span class="symbol"> )</span></div><div class="description">
- Return a weak reference to an object.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="Object.html">Object </a><span class="funcdecl"><a name="@GDScript_convert">@GDScript::convert</a></span><span class="symbol"> (</span><span> </span><span class="datatype">var </span><span>what</span><span>, </span><a class="datatype_existing" href="int.html">int </a><span>type</span><span class="symbol"> )</span></div><div class="description">
- Convert from a type to another in the best way possible. The "type" parameter uses the enum TYPE_* in Global Scope.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="String.html">String </a><span class="funcdecl"><a name="@GDScript_str">@GDScript::str</a></span><span class="symbol"> (</span><span> </span><span class="datatype">var </span><span>what</span><span>, </span><span class="datatype">var </span><span>...</span><span class="symbol"> )</span></div><div class="description">
- Convert one or more arguments to strings in the best way possible.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="Nil.html">Nil </a><span class="funcdecl"><a name="@GDScript_print">@GDScript::print</a></span><span class="symbol"> (</span><span> </span><span class="datatype">var </span><span>what</span><span>, </span><span class="datatype">var </span><span>...</span><span class="symbol"> )</span></div><div class="description">
- Print one or more arguments to strings in the best way possible to a console line.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="Nil.html">Nil </a><span class="funcdecl"><a name="@GDScript_printerr">@GDScript::printerr</a></span><span class="symbol"> (</span><span> </span><span class="datatype">var </span><span>what</span><span>, </span><span class="datatype">var </span><span>...</span><span class="symbol"> )</span></div><div class="description">
- Print one or more arguments to strings in the best way possible to standard error line.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="Nil.html">Nil </a><span class="funcdecl"><a name="@GDScript_printraw">@GDScript::printraw</a></span><span class="symbol"> (</span><span> </span><span class="datatype">var </span><span>what</span><span>, </span><span class="datatype">var </span><span>...</span><span class="symbol"> )</span></div><div class="description">
- Print one or more arguments to strings in the best way possible to console. No newline is added at the end.
- </div></div><div class="method_doc"><div class="method"><a class="datatype_existing" href="Array.html">Array </a><span class="funcdecl"><a name="@GDScript_range">@GDScript::range</a></span><span class="symbol"> (</span><span> </span><span class="datatype">var </span><span>...</span><span class="symbol"> )</span></div><div class="description">
- Return an array with the given range. Range can be 1 argument N (0 to N-1), two arguments (initial, final-1) or three arguments (initial,final-1,increment).
- </div></div></div><hr /><span>Copyright 2008-2010 Codenix SRL</span></body></html> \ No newline at end of file
diff --git a/doc/html/@Global Scope.html b/doc/html/@Global Scope.html
deleted file mode 100644
index 3324383c3d..0000000000
--- a/doc/html/@Global Scope.html
+++ /dev/null
@@ -1,459 +0,0 @@
-<html><link href="main.css" rel="stylesheet" type="text/css" /><body><table class="top_table"><tr><td class="top_table"><image src="images/logo.png" /></td><td class="top_table"><a href="index.html">Index</a></td><td class="top_table"><a href="alphabetical.html">Classes</a></td><td class="top_table"><a href="category.html">Categories</a></td><td><a href="inheritance.html">Inheritance</a></td></tr></table><hr /><div class="class"><a name="@Global Scope"><h3 class="title class_title">@Global Scope</h3></a><div class="description class_description">
- Global scope constants and variables.
- </div><br /><div class="category"><span class="category">Category: </span><a class="category_ref" href="category.html#CATEGORY_Core">Core</a></div><h4>Public Variables:</h4><div class="member_list"><li><div class="member"><a class="datatype_existing" href="Globals.html">Globals </a><span class="identifier member_name"> Globals </span><span class="member_description">
- </span></div></li><li><div class="member"><a class="datatype_existing" href="IP.html">IP </a><span class="identifier member_name"> IP </span><span class="member_description">
- </span></div></li><li><div class="member"><a class="datatype_existing" href="Geometry.html">Geometry </a><span class="identifier member_name"> Geometry </span><span class="member_description">
- </span></div></li><li><div class="member"><a class="datatype_existing" href="ResourceLoader.html">ResourceLoader </a><span class="identifier member_name"> ResourceLoader </span><span class="member_description">
- </span></div></li><li><div class="member"><a class="datatype_existing" href="ResourceSaver.html">ResourceSaver </a><span class="identifier member_name"> ResourceSaver </span><span class="member_description">
- </span></div></li><li><div class="member"><a class="datatype_existing" href="PathRemap.html">PathRemap </a><span class="identifier member_name"> PathRemap </span><span class="member_description">
- </span></div></li><li><div class="member"><a class="datatype_existing" href="OS.html">OS </a><span class="identifier member_name"> OS </span><span class="member_description">
- </span></div></li><li><div class="member"><a class="datatype_existing" href="TranslationServer.html">TranslationServer </a><span class="identifier member_name"> TranslationServer </span><span class="member_description">
- </span></div></li><li><div class="member"><a class="datatype_existing" href="TranslationServer.html">TranslationServer </a><span class="identifier member_name"> TS </span><span class="member_description">
- </span></div></li><li><div class="member"><a class="datatype_existing" href="SceneIO.html">SceneIO </a><span class="identifier member_name"> SceneIO </span><span class="member_description">
- </span></div></li><li><div class="member"><a class="datatype_existing" href="VisualServer.html">VisualServer </a><span class="identifier member_name"> VisualServer </span><span class="member_description">
- </span></div></li><li><div class="member"><a class="datatype_existing" href="VisualServer.html">VisualServer </a><span class="identifier member_name"> VS </span><span class="member_description">
- </span></div></li><li><div class="member"><a class="datatype_existing" href="AudioServer.html">AudioServer </a><span class="identifier member_name"> AudioServer </span><span class="member_description">
- </span></div></li><li><div class="member"><a class="datatype_existing" href="AudioServer.html">AudioServer </a><span class="identifier member_name"> AS </span><span class="member_description">
- </span></div></li><li><div class="member"><a class="datatype_existing" href="PhysicsServer.html">PhysicsServer </a><span class="identifier member_name"> PhysicsServer </span><span class="member_description">
- </span></div></li><li><div class="member"><a class="datatype_existing" href="PhysicsServer.html">PhysicsServer </a><span class="identifier member_name"> PS </span><span class="member_description">
- </span></div></li><li><div class="member"><a class="datatype_existing" href="Physics2DServer.html">Physics2DServer </a><span class="identifier member_name"> Physics2DServer </span><span class="member_description">
- </span></div></li><li><div class="member"><a class="datatype_existing" href="Physics2DServer.html">Physics2DServer </a><span class="identifier member_name"> PS2D </span><span class="member_description">
- </span></div></li><li><div class="member"><a class="datatype_existing" href="SpatialSound2DServer.html">SpatialSound2DServer </a><span class="identifier member_name"> SpatialSoundServer </span><span class="member_description">
- </span></div></li><li><div class="member"><a class="datatype_existing" href="SpatialSound2DServer.html">SpatialSound2DServer </a><span class="identifier member_name"> SS </span><span class="member_description">
- </span></div></li><li><div class="member"><a class="datatype_existing" href="SpatialSound2DServer.html">SpatialSound2DServer </a><span class="identifier member_name"> SpatialSound2DServer </span><span class="member_description">
- </span></div></li><li><div class="member"><a class="datatype_existing" href="SpatialSound2DServer.html">SpatialSound2DServer </a><span class="identifier member_name"> SS2D </span><span class="member_description">
- </span></div></li></div><h4>Constants:</h4><div class="constant_list"><li><div class="constant"><span class="identifier constant_name">MARGIN_LEFT </span><span class="symbol">= </span><span class="constant_value">0 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">MARGIN_TOP </span><span class="symbol">= </span><span class="constant_value">1 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">MARGIN_RIGHT </span><span class="symbol">= </span><span class="constant_value">2 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">MARGIN_BOTTOM </span><span class="symbol">= </span><span class="constant_value">3 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">VERTICAL </span><span class="symbol">= </span><span class="constant_value">1 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">HORIZONTAL </span><span class="symbol">= </span><span class="constant_value">0 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">HALIGN_LEFT </span><span class="symbol">= </span><span class="constant_value">0 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">HALIGN_CENTER </span><span class="symbol">= </span><span class="constant_value">1 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">HALIGN_RIGHT </span><span class="symbol">= </span><span class="constant_value">2 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">VALIGN_TOP </span><span class="symbol">= </span><span class="constant_value">0 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">VALIGN_CENTER </span><span class="symbol">= </span><span class="constant_value">1 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">VALIGN_BOTTOM </span><span class="symbol">= </span><span class="constant_value">2 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">SPKEY </span><span class="symbol">= </span><span class="constant_value">16777216 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_ESCAPE </span><span class="symbol">= </span><span class="constant_value">16777217 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_TAB </span><span class="symbol">= </span><span class="constant_value">16777218 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_BACKTAB </span><span class="symbol">= </span><span class="constant_value">16777219 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_BACKSPACE </span><span class="symbol">= </span><span class="constant_value">16777220 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_RETURN </span><span class="symbol">= </span><span class="constant_value">16777221 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_ENTER </span><span class="symbol">= </span><span class="constant_value">16777222 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_INSERT </span><span class="symbol">= </span><span class="constant_value">16777223 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_DELETE </span><span class="symbol">= </span><span class="constant_value">16777224 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_PAUSE </span><span class="symbol">= </span><span class="constant_value">16777225 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_PRINT </span><span class="symbol">= </span><span class="constant_value">16777226 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_SYSREQ </span><span class="symbol">= </span><span class="constant_value">16777227 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_CLEAR </span><span class="symbol">= </span><span class="constant_value">16777228 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_HOME </span><span class="symbol">= </span><span class="constant_value">16777229 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_END </span><span class="symbol">= </span><span class="constant_value">16777230 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_LEFT </span><span class="symbol">= </span><span class="constant_value">16777231 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_UP </span><span class="symbol">= </span><span class="constant_value">16777232 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_RIGHT </span><span class="symbol">= </span><span class="constant_value">16777233 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_DOWN </span><span class="symbol">= </span><span class="constant_value">16777234 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_PAGEUP </span><span class="symbol">= </span><span class="constant_value">16777235 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_PAGEDOWN </span><span class="symbol">= </span><span class="constant_value">16777236 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_SHIFT </span><span class="symbol">= </span><span class="constant_value">16777237 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_CONTROL </span><span class="symbol">= </span><span class="constant_value">16777238 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_META </span><span class="symbol">= </span><span class="constant_value">16777239 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_ALT </span><span class="symbol">= </span><span class="constant_value">16777240 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_CAPSLOCK </span><span class="symbol">= </span><span class="constant_value">16777241 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_NUMLOCK </span><span class="symbol">= </span><span class="constant_value">16777242 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_SCROLLLOCK </span><span class="symbol">= </span><span class="constant_value">16777243 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_F1 </span><span class="symbol">= </span><span class="constant_value">16777244 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_F2 </span><span class="symbol">= </span><span class="constant_value">16777245 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_F3 </span><span class="symbol">= </span><span class="constant_value">16777246 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_F4 </span><span class="symbol">= </span><span class="constant_value">16777247 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_F5 </span><span class="symbol">= </span><span class="constant_value">16777248 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_F6 </span><span class="symbol">= </span><span class="constant_value">16777249 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_F7 </span><span class="symbol">= </span><span class="constant_value">16777250 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_F8 </span><span class="symbol">= </span><span class="constant_value">16777251 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_F9 </span><span class="symbol">= </span><span class="constant_value">16777252 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_F10 </span><span class="symbol">= </span><span class="constant_value">16777253 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_F11 </span><span class="symbol">= </span><span class="constant_value">16777254 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_F12 </span><span class="symbol">= </span><span class="constant_value">16777255 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_F13 </span><span class="symbol">= </span><span class="constant_value">16777256 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_F14 </span><span class="symbol">= </span><span class="constant_value">16777257 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_F15 </span><span class="symbol">= </span><span class="constant_value">16777258 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_F16 </span><span class="symbol">= </span><span class="constant_value">16777259 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_KP_ENTER </span><span class="symbol">= </span><span class="constant_value">16777344 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_KP_MULTIPLY </span><span class="symbol">= </span><span class="constant_value">16777345 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_KP_DIVIDE </span><span class="symbol">= </span><span class="constant_value">16777346 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_KP_SUBSTRACT </span><span class="symbol">= </span><span class="constant_value">16777347 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_KP_PERIOD </span><span class="symbol">= </span><span class="constant_value">16777348 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_KP_ADD </span><span class="symbol">= </span><span class="constant_value">16777349 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_KP_0 </span><span class="symbol">= </span><span class="constant_value">16777350 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_KP_1 </span><span class="symbol">= </span><span class="constant_value">16777351 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_KP_2 </span><span class="symbol">= </span><span class="constant_value">16777352 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_KP_3 </span><span class="symbol">= </span><span class="constant_value">16777353 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_KP_4 </span><span class="symbol">= </span><span class="constant_value">16777354 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_KP_5 </span><span class="symbol">= </span><span class="constant_value">16777355 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_KP_6 </span><span class="symbol">= </span><span class="constant_value">16777356 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_KP_7 </span><span class="symbol">= </span><span class="constant_value">16777357 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_KP_8 </span><span class="symbol">= </span><span class="constant_value">16777358 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_KP_9 </span><span class="symbol">= </span><span class="constant_value">16777359 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_SUPER_L </span><span class="symbol">= </span><span class="constant_value">16777260 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_SUPER_R </span><span class="symbol">= </span><span class="constant_value">16777261 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_MENU </span><span class="symbol">= </span><span class="constant_value">16777262 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_HYPER_L </span><span class="symbol">= </span><span class="constant_value">16777263 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_HYPER_R </span><span class="symbol">= </span><span class="constant_value">16777264 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_HELP </span><span class="symbol">= </span><span class="constant_value">16777265 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_DIRECTION_L </span><span class="symbol">= </span><span class="constant_value">16777266 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_DIRECTION_R </span><span class="symbol">= </span><span class="constant_value">16777267 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_BACK </span><span class="symbol">= </span><span class="constant_value">16777280 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_FORWARD </span><span class="symbol">= </span><span class="constant_value">16777281 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_STOP </span><span class="symbol">= </span><span class="constant_value">16777282 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_REFRESH </span><span class="symbol">= </span><span class="constant_value">16777283 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_VOLUMEDOWN </span><span class="symbol">= </span><span class="constant_value">16777284 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_VOLUMEMUTE </span><span class="symbol">= </span><span class="constant_value">16777285 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_VOLUMEUP </span><span class="symbol">= </span><span class="constant_value">16777286 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_BASSBOOST </span><span class="symbol">= </span><span class="constant_value">16777287 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_BASSUP </span><span class="symbol">= </span><span class="constant_value">16777288 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_BASSDOWN </span><span class="symbol">= </span><span class="constant_value">16777289 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_TREBLEUP </span><span class="symbol">= </span><span class="constant_value">16777290 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_TREBLEDOWN </span><span class="symbol">= </span><span class="constant_value">16777291 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_MEDIAPLAY </span><span class="symbol">= </span><span class="constant_value">16777292 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_MEDIASTOP </span><span class="symbol">= </span><span class="constant_value">16777293 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_MEDIAPREVIOUS </span><span class="symbol">= </span><span class="constant_value">16777294 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_MEDIANEXT </span><span class="symbol">= </span><span class="constant_value">16777295 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_MEDIARECORD </span><span class="symbol">= </span><span class="constant_value">16777296 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_HOMEPAGE </span><span class="symbol">= </span><span class="constant_value">16777297 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_FAVORITES </span><span class="symbol">= </span><span class="constant_value">16777298 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_SEARCH </span><span class="symbol">= </span><span class="constant_value">16777299 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_STANDBY </span><span class="symbol">= </span><span class="constant_value">16777300 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_OPENURL </span><span class="symbol">= </span><span class="constant_value">16777301 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_LAUNCHMAIL </span><span class="symbol">= </span><span class="constant_value">16777302 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_LAUNCHMEDIA </span><span class="symbol">= </span><span class="constant_value">16777303 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_LAUNCH0 </span><span class="symbol">= </span><span class="constant_value">16777304 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_LAUNCH1 </span><span class="symbol">= </span><span class="constant_value">16777305 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_LAUNCH2 </span><span class="symbol">= </span><span class="constant_value">16777306 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_LAUNCH3 </span><span class="symbol">= </span><span class="constant_value">16777307 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_LAUNCH4 </span><span class="symbol">= </span><span class="constant_value">16777308 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_LAUNCH5 </span><span class="symbol">= </span><span class="constant_value">16777309 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_LAUNCH6 </span><span class="symbol">= </span><span class="constant_value">16777310 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_LAUNCH7 </span><span class="symbol">= </span><span class="constant_value">16777311 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_LAUNCH8 </span><span class="symbol">= </span><span class="constant_value">16777312 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_LAUNCH9 </span><span class="symbol">= </span><span class="constant_value">16777313 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_LAUNCHA </span><span class="symbol">= </span><span class="constant_value">16777314 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_LAUNCHB </span><span class="symbol">= </span><span class="constant_value">16777315 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_LAUNCHC </span><span class="symbol">= </span><span class="constant_value">16777316 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_LAUNCHD </span><span class="symbol">= </span><span class="constant_value">16777317 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_LAUNCHE </span><span class="symbol">= </span><span class="constant_value">16777318 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_LAUNCHF </span><span class="symbol">= </span><span class="constant_value">16777319 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_UNKNOWN </span><span class="symbol">= </span><span class="constant_value">33554431 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_SPACE </span><span class="symbol">= </span><span class="constant_value">32 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_EXCLAM </span><span class="symbol">= </span><span class="constant_value">33 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_QUOTEDBL </span><span class="symbol">= </span><span class="constant_value">34 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_NUMBERSIGN </span><span class="symbol">= </span><span class="constant_value">35 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_DOLLAR </span><span class="symbol">= </span><span class="constant_value">36 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_PERCENT </span><span class="symbol">= </span><span class="constant_value">37 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_AMPERSAND </span><span class="symbol">= </span><span class="constant_value">38 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_APOSTROPHE </span><span class="symbol">= </span><span class="constant_value">39 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_PARENLEFT </span><span class="symbol">= </span><span class="constant_value">40 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_PARENRIGHT </span><span class="symbol">= </span><span class="constant_value">41 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_ASTERISK </span><span class="symbol">= </span><span class="constant_value">42 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_PLUS </span><span class="symbol">= </span><span class="constant_value">43 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_COMMA </span><span class="symbol">= </span><span class="constant_value">44 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_MINUS </span><span class="symbol">= </span><span class="constant_value">45 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_PERIOD </span><span class="symbol">= </span><span class="constant_value">46 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_SLASH </span><span class="symbol">= </span><span class="constant_value">47 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_0 </span><span class="symbol">= </span><span class="constant_value">48 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_1 </span><span class="symbol">= </span><span class="constant_value">49 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_2 </span><span class="symbol">= </span><span class="constant_value">50 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_3 </span><span class="symbol">= </span><span class="constant_value">51 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_4 </span><span class="symbol">= </span><span class="constant_value">52 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_5 </span><span class="symbol">= </span><span class="constant_value">53 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_6 </span><span class="symbol">= </span><span class="constant_value">54 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_7 </span><span class="symbol">= </span><span class="constant_value">55 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_8 </span><span class="symbol">= </span><span class="constant_value">56 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_9 </span><span class="symbol">= </span><span class="constant_value">57 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_COLON </span><span class="symbol">= </span><span class="constant_value">58 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_SEMICOLON </span><span class="symbol">= </span><span class="constant_value">59 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_LESS </span><span class="symbol">= </span><span class="constant_value">60 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_EQUAL </span><span class="symbol">= </span><span class="constant_value">61 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_GREATER </span><span class="symbol">= </span><span class="constant_value">62 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_QUESTION </span><span class="symbol">= </span><span class="constant_value">63 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_AT </span><span class="symbol">= </span><span class="constant_value">64 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_A </span><span class="symbol">= </span><span class="constant_value">65 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_B </span><span class="symbol">= </span><span class="constant_value">66 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_C </span><span class="symbol">= </span><span class="constant_value">67 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_D </span><span class="symbol">= </span><span class="constant_value">68 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_E </span><span class="symbol">= </span><span class="constant_value">69 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_F </span><span class="symbol">= </span><span class="constant_value">70 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_G </span><span class="symbol">= </span><span class="constant_value">71 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_H </span><span class="symbol">= </span><span class="constant_value">72 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_I </span><span class="symbol">= </span><span class="constant_value">73 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_J </span><span class="symbol">= </span><span class="constant_value">74 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_K </span><span class="symbol">= </span><span class="constant_value">75 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_L </span><span class="symbol">= </span><span class="constant_value">76 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_M </span><span class="symbol">= </span><span class="constant_value">77 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_N </span><span class="symbol">= </span><span class="constant_value">78 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_O </span><span class="symbol">= </span><span class="constant_value">79 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_P </span><span class="symbol">= </span><span class="constant_value">80 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_Q </span><span class="symbol">= </span><span class="constant_value">81 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_R </span><span class="symbol">= </span><span class="constant_value">82 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_S </span><span class="symbol">= </span><span class="constant_value">83 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_T </span><span class="symbol">= </span><span class="constant_value">84 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_U </span><span class="symbol">= </span><span class="constant_value">85 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_V </span><span class="symbol">= </span><span class="constant_value">86 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_W </span><span class="symbol">= </span><span class="constant_value">87 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_X </span><span class="symbol">= </span><span class="constant_value">88 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_Y </span><span class="symbol">= </span><span class="constant_value">89 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_Z </span><span class="symbol">= </span><span class="constant_value">90 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_BRACKETLEFT </span><span class="symbol">= </span><span class="constant_value">91 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_BACKSLASH </span><span class="symbol">= </span><span class="constant_value">92 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_BRACKETRIGHT </span><span class="symbol">= </span><span class="constant_value">93 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_ASCIICIRCUM </span><span class="symbol">= </span><span class="constant_value">94 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_UNDERSCORE </span><span class="symbol">= </span><span class="constant_value">95 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_QUOTELEFT </span><span class="symbol">= </span><span class="constant_value">96 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_BRACELEFT </span><span class="symbol">= </span><span class="constant_value">123 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_BAR </span><span class="symbol">= </span><span class="constant_value">124 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_BRACERIGHT </span><span class="symbol">= </span><span class="constant_value">125 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_ASCIITILDE </span><span class="symbol">= </span><span class="constant_value">126 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_NOBREAKSPACE </span><span class="symbol">= </span><span class="constant_value">160 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_EXCLAMDOWN </span><span class="symbol">= </span><span class="constant_value">161 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_CENT </span><span class="symbol">= </span><span class="constant_value">162 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_STERLING </span><span class="symbol">= </span><span class="constant_value">163 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_CURRENCY </span><span class="symbol">= </span><span class="constant_value">164 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_YEN </span><span class="symbol">= </span><span class="constant_value">165 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_BROKENBAR </span><span class="symbol">= </span><span class="constant_value">166 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_SECTION </span><span class="symbol">= </span><span class="constant_value">167 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_DIAERESIS </span><span class="symbol">= </span><span class="constant_value">168 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_COPYRIGHT </span><span class="symbol">= </span><span class="constant_value">169 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_ORDFEMININE </span><span class="symbol">= </span><span class="constant_value">170 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_GUILLEMOTLEFT </span><span class="symbol">= </span><span class="constant_value">171 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_NOTSIGN </span><span class="symbol">= </span><span class="constant_value">172 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_HYPHEN </span><span class="symbol">= </span><span class="constant_value">173 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_REGISTERED </span><span class="symbol">= </span><span class="constant_value">174 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_MACRON </span><span class="symbol">= </span><span class="constant_value">175 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_DEGREE </span><span class="symbol">= </span><span class="constant_value">176 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_PLUSMINUS </span><span class="symbol">= </span><span class="constant_value">177 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_TWOSUPERIOR </span><span class="symbol">= </span><span class="constant_value">178 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_THREESUPERIOR </span><span class="symbol">= </span><span class="constant_value">179 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_ACUTE </span><span class="symbol">= </span><span class="constant_value">180 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_MU </span><span class="symbol">= </span><span class="constant_value">181 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_PARAGRAPH </span><span class="symbol">= </span><span class="constant_value">182 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_PERIODCENTERED </span><span class="symbol">= </span><span class="constant_value">183 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_CEDILLA </span><span class="symbol">= </span><span class="constant_value">184 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_ONESUPERIOR </span><span class="symbol">= </span><span class="constant_value">185 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_MASCULINE </span><span class="symbol">= </span><span class="constant_value">186 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_GUILLEMOTRIGHT </span><span class="symbol">= </span><span class="constant_value">187 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_ONEQUARTER </span><span class="symbol">= </span><span class="constant_value">188 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_ONEHALF </span><span class="symbol">= </span><span class="constant_value">189 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_THREEQUARTERS </span><span class="symbol">= </span><span class="constant_value">190 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_QUESTIONDOWN </span><span class="symbol">= </span><span class="constant_value">191 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_AGRAVE </span><span class="symbol">= </span><span class="constant_value">192 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_AACUTE </span><span class="symbol">= </span><span class="constant_value">193 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_ACIRCUMFLEX </span><span class="symbol">= </span><span class="constant_value">194 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_ATILDE </span><span class="symbol">= </span><span class="constant_value">195 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_ADIAERESIS </span><span class="symbol">= </span><span class="constant_value">196 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_ARING </span><span class="symbol">= </span><span class="constant_value">197 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_AE </span><span class="symbol">= </span><span class="constant_value">198 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_CCEDILLA </span><span class="symbol">= </span><span class="constant_value">199 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_EGRAVE </span><span class="symbol">= </span><span class="constant_value">200 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_EACUTE </span><span class="symbol">= </span><span class="constant_value">201 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_ECIRCUMFLEX </span><span class="symbol">= </span><span class="constant_value">202 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_EDIAERESIS </span><span class="symbol">= </span><span class="constant_value">203 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_IGRAVE </span><span class="symbol">= </span><span class="constant_value">204 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_IACUTE </span><span class="symbol">= </span><span class="constant_value">205 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_ICIRCUMFLEX </span><span class="symbol">= </span><span class="constant_value">206 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_IDIAERESIS </span><span class="symbol">= </span><span class="constant_value">207 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_ETH </span><span class="symbol">= </span><span class="constant_value">208 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_NTILDE </span><span class="symbol">= </span><span class="constant_value">209 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_OGRAVE </span><span class="symbol">= </span><span class="constant_value">210 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_OACUTE </span><span class="symbol">= </span><span class="constant_value">211 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_OCIRCUMFLEX </span><span class="symbol">= </span><span class="constant_value">212 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_OTILDE </span><span class="symbol">= </span><span class="constant_value">213 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_ODIAERESIS </span><span class="symbol">= </span><span class="constant_value">214 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_MULTIPLY </span><span class="symbol">= </span><span class="constant_value">215 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_OOBLIQUE </span><span class="symbol">= </span><span class="constant_value">216 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_UGRAVE </span><span class="symbol">= </span><span class="constant_value">217 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_UACUTE </span><span class="symbol">= </span><span class="constant_value">218 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_UCIRCUMFLEX </span><span class="symbol">= </span><span class="constant_value">219 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_UDIAERESIS </span><span class="symbol">= </span><span class="constant_value">220 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_YACUTE </span><span class="symbol">= </span><span class="constant_value">221 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_THORN </span><span class="symbol">= </span><span class="constant_value">222 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_SSHARP </span><span class="symbol">= </span><span class="constant_value">223 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_DIVISION </span><span class="symbol">= </span><span class="constant_value">247 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_YDIAERESIS </span><span class="symbol">= </span><span class="constant_value">255 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_CODE_MASK </span><span class="symbol">= </span><span class="constant_value">33554431 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_MODIFIER_MASK </span><span class="symbol">= </span><span class="constant_value">-16777216 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_MASK_SHIFT </span><span class="symbol">= </span><span class="constant_value">33554432 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_MASK_ALT </span><span class="symbol">= </span><span class="constant_value">67108864 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_MASK_META </span><span class="symbol">= </span><span class="constant_value">134217728 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_MASK_CTRL </span><span class="symbol">= </span><span class="constant_value">268435456 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_MASK_KPAD </span><span class="symbol">= </span><span class="constant_value">536870912 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">KEY_MASK_GROUP_SWITCH </span><span class="symbol">= </span><span class="constant_value">1073741824 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">BUTTON_LEFT </span><span class="symbol">= </span><span class="constant_value">1 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">BUTTON_RIGHT </span><span class="symbol">= </span><span class="constant_value">2 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">BUTTON_MIDDLE </span><span class="symbol">= </span><span class="constant_value">3 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">BUTTON_WHEEL_UP </span><span class="symbol">= </span><span class="constant_value">4 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">BUTTON_WHEEL_DOWN </span><span class="symbol">= </span><span class="constant_value">5 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">BUTTON_MASK_LEFT </span><span class="symbol">= </span><span class="constant_value">1 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">BUTTON_MASK_RIGHT </span><span class="symbol">= </span><span class="constant_value">2 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">BUTTON_MASK_MIDDLE </span><span class="symbol">= </span><span class="constant_value">4 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_BUTTON_0 </span><span class="symbol">= </span><span class="constant_value">0 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_BUTTON_1 </span><span class="symbol">= </span><span class="constant_value">1 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_BUTTON_2 </span><span class="symbol">= </span><span class="constant_value">2 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_BUTTON_3 </span><span class="symbol">= </span><span class="constant_value">3 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_BUTTON_4 </span><span class="symbol">= </span><span class="constant_value">4 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_BUTTON_5 </span><span class="symbol">= </span><span class="constant_value">5 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_BUTTON_6 </span><span class="symbol">= </span><span class="constant_value">6 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_BUTTON_7 </span><span class="symbol">= </span><span class="constant_value">7 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_BUTTON_8 </span><span class="symbol">= </span><span class="constant_value">8 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_BUTTON_9 </span><span class="symbol">= </span><span class="constant_value">9 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_BUTTON_10 </span><span class="symbol">= </span><span class="constant_value">10 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_BUTTON_11 </span><span class="symbol">= </span><span class="constant_value">11 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_BUTTON_12 </span><span class="symbol">= </span><span class="constant_value">12 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_BUTTON_13 </span><span class="symbol">= </span><span class="constant_value">13 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_BUTTON_14 </span><span class="symbol">= </span><span class="constant_value">14 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_BUTTON_15 </span><span class="symbol">= </span><span class="constant_value">15 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_BUTTON_MAX </span><span class="symbol">= </span><span class="constant_value">16 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_SNES_A </span><span class="symbol">= </span><span class="constant_value">1 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_SNES_B </span><span class="symbol">= </span><span class="constant_value">0 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_SNES_X </span><span class="symbol">= </span><span class="constant_value">3 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_SNES_Y </span><span class="symbol">= </span><span class="constant_value">2 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_SONY_CIRCLE </span><span class="symbol">= </span><span class="constant_value">1 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_SONY_X </span><span class="symbol">= </span><span class="constant_value">0 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_SONY_SQUARE </span><span class="symbol">= </span><span class="constant_value">2 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_SONY_TRIANGLE </span><span class="symbol">= </span><span class="constant_value">3 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_SEGA_B </span><span class="symbol">= </span><span class="constant_value">1 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_SEGA_A </span><span class="symbol">= </span><span class="constant_value">0 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_SEGA_X </span><span class="symbol">= </span><span class="constant_value">2 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_SEGA_Y </span><span class="symbol">= </span><span class="constant_value">3 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_XBOX_B </span><span class="symbol">= </span><span class="constant_value">1 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_XBOX_A </span><span class="symbol">= </span><span class="constant_value">0 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_XBOX_X </span><span class="symbol">= </span><span class="constant_value">2 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_XBOX_Y </span><span class="symbol">= </span><span class="constant_value">3 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_DS_A </span><span class="symbol">= </span><span class="constant_value">1 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_DS_B </span><span class="symbol">= </span><span class="constant_value">0 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_DS_X </span><span class="symbol">= </span><span class="constant_value">3 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_DS_Y </span><span class="symbol">= </span><span class="constant_value">2 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_SELECT </span><span class="symbol">= </span><span class="constant_value">10 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_START </span><span class="symbol">= </span><span class="constant_value">11 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_DPAD_UP </span><span class="symbol">= </span><span class="constant_value">12 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_DPAD_DOWN </span><span class="symbol">= </span><span class="constant_value">13 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_DPAD_LEFT </span><span class="symbol">= </span><span class="constant_value">14 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_DPAD_RIGHT </span><span class="symbol">= </span><span class="constant_value">15 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_L </span><span class="symbol">= </span><span class="constant_value">4 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_L2 </span><span class="symbol">= </span><span class="constant_value">6 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_L3 </span><span class="symbol">= </span><span class="constant_value">8 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_R </span><span class="symbol">= </span><span class="constant_value">5 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_R2 </span><span class="symbol">= </span><span class="constant_value">7 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_R3 </span><span class="symbol">= </span><span class="constant_value">9 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_AXIS_0 </span><span class="symbol">= </span><span class="constant_value">0 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_AXIS_1 </span><span class="symbol">= </span><span class="constant_value">1 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_AXIS_2 </span><span class="symbol">= </span><span class="constant_value">2 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_AXIS_3 </span><span class="symbol">= </span><span class="constant_value">3 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_AXIS_4 </span><span class="symbol">= </span><span class="constant_value">4 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_AXIS_5 </span><span class="symbol">= </span><span class="constant_value">5 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_AXIS_6 </span><span class="symbol">= </span><span class="constant_value">6 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_AXIS_7 </span><span class="symbol">= </span><span class="constant_value">7 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_AXIS_MAX </span><span class="symbol">= </span><span class="constant_value">8 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_ANALOG_0_X </span><span class="symbol">= </span><span class="constant_value">0 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_ANALOG_0_Y </span><span class="symbol">= </span><span class="constant_value">1 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_ANALOG_1_X </span><span class="symbol">= </span><span class="constant_value">2 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_ANALOG_1_Y </span><span class="symbol">= </span><span class="constant_value">3 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_ANALOG_2_X </span><span class="symbol">= </span><span class="constant_value">4 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">JOY_ANALOG_2_Y </span><span class="symbol">= </span><span class="constant_value">5 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">OK </span><span class="symbol">= </span><span class="constant_value">0 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">FAILED </span><span class="symbol">= </span><span class="constant_value">1 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_UNAVAILABLE </span><span class="symbol">= </span><span class="constant_value">2 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_UNCONFIGURED </span><span class="symbol">= </span><span class="constant_value">3 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_UNAUTHORIZED </span><span class="symbol">= </span><span class="constant_value">4 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_PARAMETER_RANGE_ERROR </span><span class="symbol">= </span><span class="constant_value">5 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_OUT_OF_MEMORY </span><span class="symbol">= </span><span class="constant_value">6 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_FILE_NOT_FOUND </span><span class="symbol">= </span><span class="constant_value">7 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_FILE_BAD_DRIVE </span><span class="symbol">= </span><span class="constant_value">8 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_FILE_BAD_PATH </span><span class="symbol">= </span><span class="constant_value">9 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_FILE_NO_PERMISSION </span><span class="symbol">= </span><span class="constant_value">10 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_FILE_ALREADY_IN_USE </span><span class="symbol">= </span><span class="constant_value">11 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_FILE_CANT_OPEN </span><span class="symbol">= </span><span class="constant_value">12 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_FILE_CANT_WRITE </span><span class="symbol">= </span><span class="constant_value">13 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_FILE_CANT_READ </span><span class="symbol">= </span><span class="constant_value">14 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_FILE_UNRECOGNIZED </span><span class="symbol">= </span><span class="constant_value">15 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_FILE_CORRUPT </span><span class="symbol">= </span><span class="constant_value">16 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_FILE_EOF </span><span class="symbol">= </span><span class="constant_value">17 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_CANT_OPEN </span><span class="symbol">= </span><span class="constant_value">18 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_CANT_CREATE </span><span class="symbol">= </span><span class="constant_value">19 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERROR_QUERY_FAILED </span><span class="symbol">= </span><span class="constant_value">20 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_ALREADY_IN_USE </span><span class="symbol">= </span><span class="constant_value">21 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_LOCKED </span><span class="symbol">= </span><span class="constant_value">22 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_TIMEOUT </span><span class="symbol">= </span><span class="constant_value">23 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_CANT_AQUIRE_RESOURCE </span><span class="symbol">= </span><span class="constant_value">24 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_INVALID_DATA </span><span class="symbol">= </span><span class="constant_value">26 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_INVALID_PARAMETER </span><span class="symbol">= </span><span class="constant_value">27 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_ALREADY_EXISTS </span><span class="symbol">= </span><span class="constant_value">28 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_DOES_NOT_EXIST </span><span class="symbol">= </span><span class="constant_value">29 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_DATABASE_CANT_READ </span><span class="symbol">= </span><span class="constant_value">30 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_DATABASE_CANT_WRITE </span><span class="symbol">= </span><span class="constant_value">31 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_COMPILATION_FAILED </span><span class="symbol">= </span><span class="constant_value">32 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_METHOD_NOT_FOUND </span><span class="symbol">= </span><span class="constant_value">33 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_LINK_FAILED </span><span class="symbol">= </span><span class="constant_value">34 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_SCRIPT_FAILED </span><span class="symbol">= </span><span class="constant_value">35 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_CYCLIC_LINK </span><span class="symbol">= </span><span class="constant_value">36 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_BUSY </span><span class="symbol">= </span><span class="constant_value">40 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_HELP </span><span class="symbol">= </span><span class="constant_value">42 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_BUG </span><span class="symbol">= </span><span class="constant_value">43 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">ERR_WTF </span><span class="symbol">= </span><span class="constant_value">45 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">PROPERTY_HINT_NONE </span><span class="symbol">= </span><span class="constant_value">0 </span><span class="constant_description">
- No hint for edited property.
- </span></div></li><li><div class="constant"><span class="identifier constant_name">PROPERTY_HINT_RANGE </span><span class="symbol">= </span><span class="constant_value">1 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">PROPERTY_HINT_EXP_RANGE </span><span class="symbol">= </span><span class="constant_value">2 </span><span class="constant_description">
- Hint string is an exponential range, defined as "min,max" or "min,max,step". This is valid for integers and floats.
- </span></div></li><li><div class="constant"><span class="identifier constant_name">PROPERTY_HINT_ENUM </span><span class="symbol">= </span><span class="constant_value">3 </span><span class="constant_description">
- Property hint is an enumerated value, like "Hello,Something,Else". This is valid for integers, floats and strings properties.
- </span></div></li><li><div class="constant"><span class="identifier constant_name">PROPERTY_HINT_LENGTH </span><span class="symbol">= </span><span class="constant_value">5 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">PROPERTY_HINT_FLAGS </span><span class="symbol">= </span><span class="constant_value">7 </span><span class="constant_description">
- Property hint is a bitmask description, for bits 0,1,2,3 abd 5 the hint would be like "Bit0,Bit1,Bit2,Bit3,,Bit5". Valid only for integers.
- </span></div></li><li><div class="constant"><span class="identifier constant_name">PROPERTY_HINT_FILE </span><span class="symbol">= </span><span class="constant_value">8 </span><span class="constant_description">
- String property is a file (so pop up a file dialog when edited). Hint string can be a set of wildcards like "*.doc".
- </span></div></li><li><div class="constant"><span class="identifier constant_name">PROPERTY_HINT_DIR </span><span class="symbol">= </span><span class="constant_value">9 </span><span class="constant_description">
- String property is a directory (so pop up a file dialog when edited).
- </span></div></li><li><div class="constant"><span class="identifier constant_name">PROPERTY_HINT_RESOURCE_TYPE </span><span class="symbol">= </span><span class="constant_value">10 </span><span class="constant_description">
- String property is a resource, so open the resource popup menu when edited.
- </span></div></li><li><div class="constant"><span class="identifier constant_name">PROPERTY_USAGE_STORAGE </span><span class="symbol">= </span><span class="constant_value">1 </span><span class="constant_description">
- Property will be used as storage (default).
- </span></div></li><li><div class="constant"><span class="identifier constant_name">PROPERTY_USAGE_STORAGE </span><span class="symbol">= </span><span class="constant_value">1 </span><span class="constant_description">
- Property will be used as storage (default).
- </span></div></li><li><div class="constant"><span class="identifier constant_name">PROPERTY_USAGE_EDITOR </span><span class="symbol">= </span><span class="constant_value">2 </span><span class="constant_description">
- Property will be visible in editor (default).
- </span></div></li><li><div class="constant"><span class="identifier constant_name">PROPERTY_USAGE_NETWORK </span><span class="symbol">= </span><span class="constant_value">4 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">PROPERTY_USAGE_DEFAULT </span><span class="symbol">= </span><span class="constant_value">7 </span><span class="constant_description">
- Default usage (storage and editor).
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_NIL </span><span class="symbol">= </span><span class="constant_value">0 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_BOOL </span><span class="symbol">= </span><span class="constant_value">1 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_INT </span><span class="symbol">= </span><span class="constant_value">2 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_REAL </span><span class="symbol">= </span><span class="constant_value">3 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_STRING </span><span class="symbol">= </span><span class="constant_value">4 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_VECTOR2 </span><span class="symbol">= </span><span class="constant_value">5 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_RECT2 </span><span class="symbol">= </span><span class="constant_value">6 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_VECTOR3 </span><span class="symbol">= </span><span class="constant_value">7 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_MATRIX32 </span><span class="symbol">= </span><span class="constant_value">8 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_PLANE </span><span class="symbol">= </span><span class="constant_value">9 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_QUAT </span><span class="symbol">= </span><span class="constant_value">10 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_AABB </span><span class="symbol">= </span><span class="constant_value">11 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_MATRIX3 </span><span class="symbol">= </span><span class="constant_value">12 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_TRANSFORM </span><span class="symbol">= </span><span class="constant_value">13 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_COLOR </span><span class="symbol">= </span><span class="constant_value">14 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_IMAGE </span><span class="symbol">= </span><span class="constant_value">15 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_NODE_PATH </span><span class="symbol">= </span><span class="constant_value">16 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_RID </span><span class="symbol">= </span><span class="constant_value">17 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_OBJECT </span><span class="symbol">= </span><span class="constant_value">18 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_INPUT_EVENT </span><span class="symbol">= </span><span class="constant_value">19 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_DICTIONARY </span><span class="symbol">= </span><span class="constant_value">20 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_ARRAY </span><span class="symbol">= </span><span class="constant_value">21 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_RAW_ARRAY </span><span class="symbol">= </span><span class="constant_value">22 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_INT_ARRAY </span><span class="symbol">= </span><span class="constant_value">23 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_REAL_ARRAY </span><span class="symbol">= </span><span class="constant_value">24 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_STRING_ARRAY </span><span class="symbol">= </span><span class="constant_value">25 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_VECTOR2_ARRAY </span><span class="symbol">= </span><span class="constant_value">26 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_VECTOR3_ARRAY </span><span class="symbol">= </span><span class="constant_value">27 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_COLOR_ARRAY </span><span class="symbol">= </span><span class="constant_value">28 </span><span class="constant_description">
- </span></div></li><li><div class="constant"><span class="identifier constant_name">TYPE_MAX </span><span class="symbol">= </span><span class="constant_value">29 </span><span class="constant_description">
- </span></div></li></div><h4>Description:</h4><div class="description">
- Global scope constants and variables. This is all that resides in the globals, constants regarding error codes, scancodes, property hints, etc. It's not much.
- Singletons are also documented here, since they can be accessed from anywhere.
- </div><h4>Method Documentation:</h4></div><hr /><span>Copyright 2008-2010 Codenix SRL</span></body></html> \ No newline at end of file
diff --git a/doc/html/@Squirrel.html b/doc/html/@Squirrel.html
deleted file mode 100644
index ad4aaa49d8..0000000000
--- a/doc/html/@Squirrel.html
+++ /dev/null
@@ -1,2 +0,0 @@
-<html><link href="main.css" rel="stylesheet" type="text/css" /><body><table class="top_table"><tr><td class="top_table"><image src="images/logo.png" /></td><td class="top_table"><a href="index.html">Index</a></td><td class="top_table"><a href="alphabetical.html">Classes</a></td><td class="top_table"><a href="category.html">Categories</a></td><td><a href="inheritance.html">Inheritance</a></td></tr></table><hr /><div class="class"><a name="@Squirrel"><h3 class="title class_title">@Squirrel</h3></a><div class="description class_description">
- </div><br /><div class="category"><span class="category">Category: </span><a class="category_ref" href="category.html#CATEGORY_Core">Core</a></div><h4>Method Documentation:</h4></div><hr /><span>Copyright 2008-2010 Codenix SRL</span></body></html> \ No newline at end of file
diff --git a/doc/html/tutorial01/0_home_red_coding_godot_doc_math_position.png b/doc/html/tutorial01/0_home_red_coding_godot_doc_math_position.png
deleted file mode 100644
index df52c05462..0000000000
--- a/doc/html/tutorial01/0_home_red_coding_godot_doc_math_position.png
+++ /dev/null
Binary files differ
diff --git a/doc/html/tutorial01/1_home_red_coding_godot_doc_math_direction.png b/doc/html/tutorial01/1_home_red_coding_godot_doc_math_direction.png
deleted file mode 100644
index 5b58274bcb..0000000000
--- a/doc/html/tutorial01/1_home_red_coding_godot_doc_math_direction.png
+++ /dev/null
Binary files differ
diff --git a/doc/html/tutorial01/2_home_red_coding_godot_doc_math_normals.png b/doc/html/tutorial01/2_home_red_coding_godot_doc_math_normals.png
deleted file mode 100644
index 73681a58ce..0000000000
--- a/doc/html/tutorial01/2_home_red_coding_godot_doc_math_normals.png
+++ /dev/null
Binary files differ
diff --git a/doc/html/tutorial01/tutorial.css b/doc/html/tutorial01/tutorial.css
deleted file mode 100644
index a518c6dff7..0000000000
--- a/doc/html/tutorial01/tutorial.css
+++ /dev/null
@@ -1,128 +0,0 @@
-
-/* start css.sty */
-.cmr-7{font-size:70%;}
-.cmmi-7{font-size:70%;font-style: italic;}
-.cmmi-10{font-style: italic;}
-.ectt-1000{ font-family: monospace;}
-.ectt-1000{ font-family: monospace;}
-.ectt-1000{ font-family: monospace;}
-.ectt-1000{ font-family: monospace;}
-.ectt-1000{ font-family: monospace;}
-.ecti-1000{ font-style: italic;}
-.ecti-1000{ font-style: italic;}
-.ecti-1000{ font-style: italic;}
-.ecti-1000{ font-style: italic;}
-.ecti-1000{ font-style: italic;}
-.ecti-0700{font-size:70%; font-style: italic;}
-.ecti-0700{ font-style: italic;}
-.ecti-0700{ font-style: italic;}
-.ecti-0700{ font-style: italic;}
-.ecti-0700{ font-style: italic;}
-.ecrm-0700{font-size:70%;}
-p.noindent { text-indent: 0em }
-td p.noindent { text-indent: 0em; margin-top:0em; }
-p.nopar { text-indent: 0em; }
-p.indent{ text-indent: 1.5em }
-@media print {div.crosslinks {visibility:hidden;}}
-a img { border-top: 0; border-left: 0; border-right: 0; }
-center { margin-top:1em; margin-bottom:1em; }
-td center { margin-top:0em; margin-bottom:0em; }
-.Canvas { position:relative; }
-img.math{vertical-align:middle;}
-li p.indent { text-indent: 0em }
-.enumerate1 {list-style-type:decimal;}
-.enumerate2 {list-style-type:lower-alpha;}
-.enumerate3 {list-style-type:lower-roman;}
-.enumerate4 {list-style-type:upper-alpha;}
-div.newtheorem { margin-bottom: 2em; margin-top: 2em;}
-.obeylines-h,.obeylines-v {white-space: nowrap; }
-div.obeylines-v p { margin-top:0; margin-bottom:0; }
-.overline{ text-decoration:overline; }
-.overline img{ border-top: 1px solid black; }
-td.displaylines {text-align:center; white-space:nowrap;}
-.centerline {text-align:center;}
-.rightline {text-align:right;}
-div.verbatim {font-family: monospace; white-space: nowrap; text-align:left; clear:both; }
-.fbox {padding-left:3.0pt; padding-right:3.0pt; text-indent:0pt; border:solid black 0.4pt; }
-div.fbox {display:table}
-div.center div.fbox {text-align:center; clear:both; padding-left:3.0pt; padding-right:3.0pt; text-indent:0pt; border:solid black 0.4pt; }
-table.minipage{width:100%;}
-div.center, div.center div.center {text-align: center; margin-left:1em; margin-right:1em;}
-div.center div {text-align: left;}
-div.flushright, div.flushright div.flushright {text-align: right;}
-div.flushright div {text-align: left;}
-div.flushleft {text-align: left;}
-.underline{ text-decoration:underline; }
-.underline img{ border-bottom: 1px solid black; margin-bottom:1pt; }
-.framebox-c, .framebox-l, .framebox-r { padding-left:3.0pt; padding-right:3.0pt; text-indent:0pt; border:solid black 0.4pt; }
-.framebox-c {text-align:center;}
-.framebox-l {text-align:left;}
-.framebox-r {text-align:right;}
-span.thank-mark{ vertical-align: super }
-span.footnote-mark sup.textsuperscript, span.footnote-mark a sup.textsuperscript{ font-size:80%; }
-div.tabular, div.center div.tabular {text-align: center; margin-top:0.5em; margin-bottom:0.5em; }
-table.tabular td p{margin-top:0em;}
-table.tabular {margin-left: auto; margin-right: auto;}
-div.td00{ margin-left:0pt; margin-right:0pt; }
-div.td01{ margin-left:0pt; margin-right:5pt; }
-div.td10{ margin-left:5pt; margin-right:0pt; }
-div.td11{ margin-left:5pt; margin-right:5pt; }
-table[rules] {border-left:solid black 0.4pt; border-right:solid black 0.4pt; }
-td.td00{ padding-left:0pt; padding-right:0pt; }
-td.td01{ padding-left:0pt; padding-right:5pt; }
-td.td10{ padding-left:5pt; padding-right:0pt; }
-td.td11{ padding-left:5pt; padding-right:5pt; }
-table[rules] {border-left:solid black 0.4pt; border-right:solid black 0.4pt; }
-.hline hr, .cline hr{ height : 1px; margin:0px; }
-.tabbing-right {text-align:right;}
-span.TEX {letter-spacing: -0.125em; }
-span.TEX span.E{ position:relative;top:0.5ex;left:-0.0417em;}
-a span.TEX span.E {text-decoration: none; }
-span.LATEX span.A{ position:relative; top:-0.5ex; left:-0.4em; font-size:85%;}
-span.LATEX span.TEX{ position:relative; left: -0.4em; }
-div.float img, div.float .caption {text-align:center;}
-div.figure img, div.figure .caption {text-align:center;}
-.marginpar {width:20%; float:right; text-align:left; margin-left:auto; margin-top:0.5em; font-size:85%; text-decoration:underline;}
-.marginpar p{margin-top:0.4em; margin-bottom:0.4em;}
-table.equation {width:100%;}
-.equation td{text-align:center; }
-td.equation { margin-top:1em; margin-bottom:1em; }
-td.equation-label { width:5%; text-align:center; }
-td.eqnarray4 { width:5%; white-space: normal; }
-td.eqnarray2 { width:5%; }
-table.eqnarray-star, table.eqnarray {width:100%;}
-div.eqnarray{text-align:center;}
-div.array {text-align:center;}
-div.pmatrix {text-align:center;}
-table.pmatrix {width:100%;}
-span.pmatrix img{vertical-align:middle;}
-div.pmatrix {text-align:center;}
-table.pmatrix {width:100%;}
-img.cdots{vertical-align:middle;}
-.partToc a, .partToc, .likepartToc a, .likepartToc {line-height: 200%; font-weight:bold; font-size:110%;}
-.index-item, .index-subitem, .index-subsubitem {display:block}
-.caption td.id{font-weight: bold; white-space: nowrap; }
-table.caption {text-align:center;}
-h1.partHead{text-align: center}
-p.bibitem { text-indent: -2em; margin-left: 2em; margin-top:0.6em; margin-bottom:0.6em; }
-p.bibitem-p { text-indent: 0em; margin-left: 2em; margin-top:0.6em; margin-bottom:0.6em; }
-.paragraphHead, .likeparagraphHead { margin-top:2em; font-weight: bold;}
-.subparagraphHead, .likesubparagraphHead { font-weight: bold;}
-.quote {margin-bottom:0.25em; margin-top:0.25em; margin-left:1em; margin-right:1em; text-align:justify;}
-.verse{white-space:nowrap; margin-left:2em}
-div.maketitle {text-align:center;}
-h2.titleHead{text-align:center;}
-div.maketitle{ margin-bottom: 2em; }
-div.author, div.date {text-align:center;}
-div.thanks{text-align:left; margin-left:10%; font-size:85%; font-style:italic; }
-div.author{white-space: nowrap;}
-.quotation {margin-bottom:0.25em; margin-top:0.25em; margin-left:1em; }
-.abstract p {margin-left:5%; margin-right:5%;}
-table.abstract {width:100%;}
-.lstlisting .label{margin-right:0.5em; }
-div.lstlisting{font-family: monospace; white-space: nowrap; margin-top:0.5em; margin-bottom:0.5em; }
-div.lstinputlisting{ font-family: monospace; white-space: nowrap; }
-.lstinputlisting .label{margin-right:0.5em;}
-.figure img.graphics {margin-left:10%;}
-/* end css.sty */
-
diff --git a/doc/html/tutorial01/tutorial.html b/doc/html/tutorial01/tutorial.html
deleted file mode 100644
index 45c0258709..0000000000
--- a/doc/html/tutorial01/tutorial.html
+++ /dev/null
@@ -1,902 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
- "http://www.w3.org/TR/html4/loose.dtd">
-<html >
-<head><title></title>
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
-<meta name="generator" content="TeX4ht (http://www.cse.ohio-state.edu/~gurari/TeX4ht/)">
-<meta name="originator" content="TeX4ht (http://www.cse.ohio-state.edu/~gurari/TeX4ht/)">
-<!-- html -->
-<meta name="src" content="tutorial.tex">
-<meta name="date" content="2009-10-07 00:28:00">
-<link rel="stylesheet" type="text/css" href="tutorial.css">
-</head><body
->
- <h3 class="sectionHead"><span class="titlemark">1 </span> <a
- id="x1-10001"></a>Introduction to 3D Math</h3>
-<!--l. 27--><p class="noindent" >
- <h4 class="subsectionHead"><span class="titlemark">1.1 </span> <a
- id="x1-20001.1"></a>Introduction</h4>
-<!--l. 29--><p class="noindent" >There are many approaches to understanding the type of 3D math used in video
-games, modelling, ray-tracing, etc. The usual is through vector algebra, matrices, and
-linear transformations and, while they are not completely necesary to understand
-most of the aspects of 3D game programming (from the theorical point of view), they
-provide a common language to communicate with other programmers or
-engineers.
-<!--l. 36--><p class="indent" > This tutorial will focus on explaining all the basic concepts needed for a
-programmer to understand how to develop 3D games without getting too deep into
-algebra. Instead of a math-oriented language, code examples will be given instead
-when possible. The reason for this is that. while programmers may have
-different backgrounds or experience (be it scientific, engineering or self taught),
-code is the most familiar language and the lowest common denominator for
-understanding.
-<!--l. 45--><p class="noindent" >
- <h4 class="subsectionHead"><span class="titlemark">1.2 </span> <a
- id="x1-30001.2"></a>Vectors</h4>
-<!--l. 48--><p class="noindent" >
- <h5 class="subsubsectionHead"><span class="titlemark">1.2.1 </span> <a
- id="x1-40001.2.1"></a>Brief Introduction</h5>
-<!--l. 50--><p class="noindent" >When writing 2D games, interfaces and other applications, the typical convention is
-to define coordinates as an <span
-class="ecti-1000">x,y </span>pair, <span
-class="ecti-1000">x </span>representing the horizontal offset and <span
-class="ecti-1000">y </span>the
-vertical one. In most cases, the unit for both is <span
-class="ecti-1000">pixels</span>. This makes sense given the
-screen is just a rectangle in two dimensions.
-<!--l. 56--><p class="indent" > An <span
-class="ecti-1000">x,y </span>pair can be used for two purposes. It can be an absolute position (screen
-cordinate in the previous case), or a relative direction, if we trace an arrow from the
-origin (0,0 coordinates) to it&#8217;s position.
-<div class="center"
->
-<!--l. 60--><p class="noindent" >
-
-<div class="tabular">
- <table id="TBL-1" class="tabular"
-cellspacing="0" cellpadding="0"
-><colgroup id="TBL-1-1g"><col
-id="TBL-1-1"><col
-id="TBL-1-2"><col
-id="TBL-1-3"></colgroup><tr
- style="vertical-align:baseline;" id="TBL-1-1-"><td style="white-space:nowrap; text-align:center;" id="TBL-1-1-1"
-class="td11"><img
-src="tutorial0x.png" alt="PIC" class="graphics" width="100.375pt" height="100.375pt" ><!--tex4ht:graphics
-name="tutorial0x.png" src="0_home_red_coding_godot_doc_math_position.eps"
---></td><td style="white-space:nowrap; text-align:center;" id="TBL-1-1-2"
-class="td11"></td><td style="white-space:nowrap; text-align:center;" id="TBL-1-1-3"
-class="td11"><img
-src="tutorial1x.png" alt="PIC" class="graphics" width="100.375pt" height="100.375pt" ><!--tex4ht:graphics
-name="tutorial1x.png" src="1_home_red_coding_godot_doc_math_direction.eps"
---></td>
-</tr><tr
- style="vertical-align:baseline;" id="TBL-1-2-"><td style="white-space:nowrap; text-align:center;" id="TBL-1-2-1"
-class="td11"> <span
-class="ecti-0700">Position </span></td><td style="white-space:nowrap; text-align:center;" id="TBL-1-2-2"
-class="td11"></td><td style="white-space:nowrap; text-align:center;" id="TBL-1-2-3"
-class="td11"> <span
-class="ecti-0700">Direction </span></td>
-</tr><tr
- style="vertical-align:baseline;" id="TBL-1-3-"><td style="white-space:nowrap; text-align:center;" id="TBL-1-3-1"
-class="td11"> </td>
-</tr></table></div>
-</div>
-<!--l. 67--><p class="indent" > When used as a direction, this pair is called a <span
-class="ecti-1000">vector</span>, and two properties can be
-observed: The first is the <span
-class="ecti-1000">magnitude </span>or <span
-class="ecti-1000">length </span>, and the second is the direction. In
-two dimensions, direction can be an angle. The <span
-class="ecti-1000">magnitude </span>or <span
-class="ecti-1000">length </span>can be computed
-by simply using Pithagoras theorem:
-<div class="center"
->
-<!--l. 73--><p class="noindent" >
-<div class="tabular"> <table id="TBL-2" class="tabular"
-cellspacing="0" cellpadding="0"
-><colgroup id="TBL-2-1g"><col
-id="TBL-2-1"><col
-id="TBL-2-2"></colgroup><tr
- style="vertical-align:baseline;" id="TBL-2-1-"><td style="white-space:nowrap; text-align:center;" id="TBL-2-1-1"
-class="td11"><img
-src="tutorial2x.png" alt="&#x2218;x2-+-y2-" class="sqrt" ></td><td style="white-space:nowrap; text-align:center;" id="TBL-2-1-2"
-class="td11"><img
-src="tutorial3x.png" alt="&#x2218;x2-+-y2 +-z2" class="sqrt" ></td>
-</tr><tr
- style="vertical-align:baseline;" id="TBL-2-2-"><td style="white-space:nowrap; text-align:center;" id="TBL-2-2-1"
-class="td11"> <span
-class="ecti-0700">2D </span></td><td style="white-space:nowrap; text-align:center;" id="TBL-2-2-2"
-class="td11"> <span
-class="ecti-0700">3D </span></td>
-</tr><tr
- style="vertical-align:baseline;" id="TBL-2-3-"><td style="white-space:nowrap; text-align:center;" id="TBL-2-3-1"
-class="td11"> </td>
-</tr></table></div>
-</div>
-<!--l. 80--><p class="indent" > The direction can be an arbitrary angle from either the <span
-class="ecti-1000">x </span>or <span
-class="ecti-1000">y </span>axis, and could be
-computed by using trigonometry, or just using the usual <span
-class="ecti-1000">atan2 </span>function present in
-most math libraries. However, when dealing with 3D, the direction can&#8217;t be described
-as an angle. To separate magnitude and direction, 3D uses the concept of <span
-class="ecti-1000">normal</span>
-<span
-class="ecti-1000">vectors.</span>
-<!--l. 88--><p class="noindent" >
- <h5 class="subsubsectionHead"><span class="titlemark">1.2.2 </span> <a
- id="x1-50001.2.2"></a>Implementation</h5>
-<!--l. 90--><p class="noindent" >Vectors are implemented in Godot Engine as a class named <span
-class="ecti-1000">Vector3 </span>for 3D, and as
-both <span
-class="ecti-1000">Vector2</span>, <span
-class="ecti-1000">Point2 </span>or <span
-class="ecti-1000">Size2 </span>in 2D (they are all aliases). They are used for any
-purpose where a pair of 2D or 3D values (described as <span
-class="ecti-1000">x,y </span>or <span
-class="ecti-1000">x,y,z) </span>is needed. This is
-somewhat a standard in most libraries or engines. In the script API, they can be
-instanced like this:
- <!--l. 98-->
- <div class="lstlisting"><span class="label"><a
- id="x1-5001r1"></a></span>a&#x00A0;=&#x00A0;Vector3()&#x00A0;<br /><span class="label"><a
- id="x1-5002r2"></a></span>a&#x00A0;=&#x00A0;Vector2(&#x00A0;2.0,&#x00A0;3.4&#x00A0;)
- </div>
-
-<!--l. 104--><p class="indent" > Vectors also support the common operators <span
-class="ecti-1000">+, -, / and * </span>for addition,
-substraction, multiplication and division.
- <!--l. 108-->
- <div class="lstlisting"><span class="label"><a
- id="x1-5003r1"></a></span>a&#x00A0;=&#x00A0;Vector3(1,2,3)&#x00A0;<br /><span class="label"><a
- id="x1-5004r2"></a></span>b&#x00A0;=&#x00A0;Vector3(4,5,6)&#x00A0;<br /><span class="label"><a
- id="x1-5005r3"></a></span>c&#x00A0;=&#x00A0;Vector3()&#x00A0;<br /><span class="label"><a
- id="x1-5006r4"></a></span>&#x00A0;<br /><span class="label"><a
- id="x1-5007r5"></a></span>//&#x00A0;writing&#x00A0;<br /><span class="label"><a
- id="x1-5008r6"></a></span>&#x00A0;<br /><span class="label"><a
- id="x1-5009r7"></a></span>c&#x00A0;=&#x00A0;a&#x00A0;+&#x00A0;b&#x00A0;<br /><span class="label"><a
- id="x1-5010r8"></a></span>&#x00A0;<br /><span class="label"><a
- id="x1-5011r9"></a></span>//&#x00A0;is&#x00A0;the&#x00A0;same&#x00A0;as&#x00A0;writing&#x00A0;<br /><span class="label"><a
- id="x1-5012r10"></a></span>&#x00A0;<br /><span class="label"><a
- id="x1-5013r11"></a></span>c.x&#x00A0;=&#x00A0;a.x&#x00A0;+&#x00A0;b.x&#x00A0;<br /><span class="label"><a
- id="x1-5014r12"></a></span>c.y&#x00A0;=&#x00A0;a.y&#x00A0;+&#x00A0;b.y&#x00A0;<br /><span class="label"><a
- id="x1-5015r13"></a></span>c.z&#x00A0;=&#x00A0;a.z&#x00A0;+&#x00A0;b.z&#x00A0;<br /><span class="label"><a
- id="x1-5016r14"></a></span>&#x00A0;<br /><span class="label"><a
- id="x1-5017r15"></a></span>//&#x00A0;both&#x00A0;will&#x00A0;result&#x00A0;in&#x00A0;a&#x00A0;vector&#x00A0;containing&#x00A0;(5,7,9).&#x00A0;<br /><span class="label"><a
- id="x1-5018r16"></a></span>//&#x00A0;the&#x00A0;same&#x00A0;happens&#x00A0;for&#x00A0;the&#x00A0;rest&#x00A0;of&#x00A0;the&#x00A0;operators.
- </div>
-<!--l. 128--><p class="indent" > Vectors also can perform a wide variety of built-in functions, their most common
-usages will be explored next.
-<!--l. 132--><p class="noindent" >
- <h5 class="subsubsectionHead"><span class="titlemark">1.2.3 </span> <a
- id="x1-60001.2.3"></a>Normal Vectors</h5>
-<!--l. 134--><p class="noindent" >Two points ago, it was mentioned that 3D vectors can&#8217;t describe their direction as an
-agle (as 2D vectors can). Because of this, <span
-class="ecti-1000">normal vectors </span>become important for
-separating a vector between <span
-class="ecti-1000">direction </span>and <span
-class="ecti-1000">magnitude.</span>
-<!--l. 139--><p class="indent" > A <span
-class="ecti-1000">normal vector </span>is a vector with a <span
-class="ecti-1000">magnitude </span>of <span
-class="ecti-1000">1. </span>This means, no matter where
-the vector is pointing to, it&#8217;s length is always <span
-class="ecti-1000">1</span>.
- <div class="tabular">
- <table id="TBL-3" class="tabular"
-cellspacing="0" cellpadding="0"
-><colgroup id="TBL-3-1g"><col
-id="TBL-3-1"></colgroup><tr
- style="vertical-align:baseline;" id="TBL-3-1-"><td style="white-space:nowrap; text-align:center;" id="TBL-3-1-1"
-class="td11"><img
-src="tutorial4x.png" alt="PIC" class="graphics" width="100.375pt" height="100.375pt" ><!--tex4ht:graphics
-name="tutorial4x.png" src="2_home_red_coding_godot_doc_math_normals.eps"
---></td>
-</tr><tr
- style="vertical-align:baseline;" id="TBL-3-2-"><td style="white-space:nowrap; text-align:center;" id="TBL-3-2-1"
-class="td11"> <span
-class="ecrm-0700">Normal vectors aroud the origin. </span></td>
-</tr><tr
- style="vertical-align:baseline;" id="TBL-3-3-"><td style="white-space:nowrap; text-align:center;" id="TBL-3-3-1"
-class="td11"> </td> </tr></table>
-</div>
-<!--l. 148--><p class="indent" > Normal vectors have endless uses in 3D graphics programming, so it&#8217;s
-recommended to get familiar with them as much as possible.
-<!--l. 152--><p class="noindent" >
- <h5 class="subsubsectionHead"><span class="titlemark">1.2.4 </span> <a
- id="x1-70001.2.4"></a>Normalization</h5>
-<!--l. 154--><p class="noindent" >Normalization is the process through which normal vectors are obtained
-from regular vectors. In other words, normalization is used to reduce the
-<span
-class="ecti-1000">magnitude </span>of any vector to <span
-class="ecti-1000">1</span>. (except of course, unless the vector is (0,0,0)
-).
-<!--l. 159--><p class="indent" > To normalize a vector, it must be divided by its magnitude (which should be
-greater than zero):
- <!--l. 163-->
- <div class="lstlisting"><span class="label"><a
- id="x1-7001r1"></a></span><span
-class="ecti-1000">//</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">a</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">custom</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">vector</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">is</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">created</span>&#x00A0;<br /><span class="label"><a
- id="x1-7002r2"></a></span>a&#x00A0;=&#x00A0;Vector3(4,5,6)&#x00A0;<br /><span class="label"><a
- id="x1-7003r3"></a></span><span
-class="ecti-1000">//</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">&#8217;</span><span
-class="ecti-1000">l</span><span
-class="ecti-1000">&#8217;</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">is</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">a</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">single</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">real</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">number</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">(</span><span
-class="ecti-1000">or</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">scalar</span><span
-class="ecti-1000">)</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">containight</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">the</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">length</span>&#x00A0;<br /><span class="label"><a
- id="x1-7004r4"></a></span>l&#x00A0;=&#x00A0;Math.sqrt(&#x00A0;a.x<span
-class="cmsy-10">*</span>a.x&#x00A0;+&#x00A0;a.y<span
-class="cmsy-10">*</span>a.y&#x00A0;+&#x00A0;a.z<span
-class="cmsy-10">*</span>a.z&#x00A0;)&#x00A0;<br /><span class="label"><a
- id="x1-7005r5"></a></span><span
-class="ecti-1000">//</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">the</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">vector</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">&#8217;</span><span
-class="ecti-1000">a</span><span
-class="ecti-1000">&#8217;</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">is</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">divided</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">by</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">its</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">length</span><span
-class="ecti-1000">,</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">by</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">performing</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">scalar</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">divide</span>&#x00A0;<br /><span class="label"><a
- id="x1-7006r6"></a></span>a&#x00A0;=&#x00A0;a&#x00A0;/&#x00A0;l&#x00A0;<br /><span class="label"><a
- id="x1-7007r7"></a></span><span
-class="ecti-1000">//</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">which</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">is</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">the</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">same</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">as</span>&#x00A0;<br /><span class="label"><a
- id="x1-7008r8"></a></span>a.x&#x00A0;=&#x00A0;a.x&#x00A0;/&#x00A0;l&#x00A0;<br /><span class="label"><a
- id="x1-7009r9"></a></span>a.y&#x00A0;=&#x00A0;a.y&#x00A0;/&#x00A0;l&#x00A0;<br /><span class="label"><a
- id="x1-7010r10"></a></span>a.z&#x00A0;=&#x00A0;a.z&#x00A0;/&#x00A0;l
-
- </div>
-<!--l. 177--><p class="indent" > Vector3 contains two built in functions for normalization:
- <!--l. 180-->
- <div class="lstlisting"><span class="label"><a
- id="x1-7011r1"></a></span>a&#x00A0;=&#x00A0;Vector3(4,5,6)&#x00A0;<br /><span class="label"><a
- id="x1-7012r2"></a></span>a.normalize()&#x00A0;<span
-class="ecti-1000">//</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">in</span><span
-class="cmsy-10">-</span><span
-class="ecti-1000">place</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">normalization</span>&#x00A0;<br /><span class="label"><a
- id="x1-7013r3"></a></span>b&#x00A0;=&#x00A0;a.normalized()&#x00A0;<span
-class="ecti-1000">//</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">returns</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">a</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">copy</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">of</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">a</span><span
-class="ecti-1000">,</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">normalized</span>
- </div>
-<!--l. 188--><p class="noindent" >
- <h5 class="subsubsectionHead"><span class="titlemark">1.2.5 </span> <a
- id="x1-80001.2.5"></a>Dot Product</h5>
-<!--l. 190--><p class="noindent" >The dot product is, pheraps, the most useful operation that can be applied to 3D
-vectors. In the surface, it&#8217;s multiple usages are not very obvious, but in depth it can
-provide very useful information between two vectors (be it direction or just points in
-space).
-<!--l. 195--><p class="indent" > The dot product takes two vectors (<span
-class="ecti-1000">a </span>and <span
-class="ecti-1000">b </span>in the example) and returns a scalar
-(single real number):
-<div class="center"
->
-<!--l. 198--><p class="noindent" >
-<!--l. 199--><p class="noindent" ><span
-class="cmmi-10">a</span><sub><span
-class="cmmi-7">x</span></sub><span
-class="cmmi-10">b</span><sub><span
-class="cmmi-7">x</span></sub> <span
-class="cmr-10">+ </span><span
-class="cmmi-10">a</span><sub><span
-class="cmmi-7">y</span></sub><span
-class="cmmi-10">b</span><sub><span
-class="cmmi-7">y</span></sub> <span
-class="cmr-10">+ </span><span
-class="cmmi-10">a</span><sub><span
-class="cmmi-7">z</span></sub><span
-class="cmmi-10">b</span><sub><span
-class="cmmi-7">z</span></sub>
-</div>
-<!--l. 202--><p class="indent" > The same expressed in code:
- <!--l. 205-->
- <div class="lstlisting"><span class="label"><a
- id="x1-8001r1"></a></span>a&#x00A0;=&#x00A0;Vector3(...)&#x00A0;<br /><span class="label"><a
- id="x1-8002r2"></a></span>b&#x00A0;=&#x00A0;Vector3(...)&#x00A0;<br /><span class="label"><a
- id="x1-8003r3"></a></span>&#x00A0;<br /><span class="label"><a
- id="x1-8004r4"></a></span>c&#x00A0;=&#x00A0;a.x<span
-class="cmsy-10">*</span>b.x&#x00A0;+&#x00A0;a.y<span
-class="cmsy-10">*</span>b.y&#x00A0;+&#x00A0;a.z<span
-class="cmsy-10">*</span>b.z&#x00A0;<br /><span class="label"><a
- id="x1-8005r5"></a></span>&#x00A0;<br /><span class="label"><a
- id="x1-8006r6"></a></span><span
-class="ecti-1000">//</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">using</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">built</span><span
-class="cmsy-10">-</span><span
-class="ecti-1000">in</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">dot</span><span
-class="ecti-1000">()</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">function</span>&#x00A0;<br /><span class="label"><a
- id="x1-8007r7"></a></span>&#x00A0;<br /><span class="label"><a
- id="x1-8008r8"></a></span>c&#x00A0;=&#x00A0;a.dot(b)
- </div>
-<!--l. 218--><p class="indent" > The dot product presents several useful properties:
- <ul class="itemize1">
- <li class="itemize">If both <span
-class="ecti-1000">a </span>and <span
-class="ecti-1000">b </span>parameters to a <span
-class="ecti-1000">dot product </span>are direction vectors, dot
- product will return positive if both point towards the same direction,
- negative if both point towards opposite directions, and zero if they are
- orthogonal (one is perpendicular to the other).
- </li>
- <li class="itemize">If both <span
-class="ecti-1000">a </span>and <span
-class="ecti-1000">b </span>parameters to a <span
-class="ecti-1000">dot product </span>are <span
-class="ecti-1000">normalized </span>direction
- vectors, then the dot product will return the cosine of the angle between
- them (ranging from 1 if they are equal, 0 if they are orthogonal, and -1 if
- they are opposed (a == -b)).
- </li>
- <li class="itemize">If <span
-class="ecti-1000">a </span>is a <span
-class="ecti-1000">normalized </span>direction vector and <span
-class="ecti-1000">b </span>is a point, the dot product will
- return the distance from <span
-class="ecti-1000">b </span>to the plane passing through the origin, with
- normal <span
-class="ecti-1000">a (see item about planes)</span>
-
- </li>
- <li class="itemize">More uses will be presented later in this tutorial.</li></ul>
-<!--l. 236--><p class="noindent" >
- <h5 class="subsubsectionHead"><span class="titlemark">1.2.6 </span> <a
- id="x1-90001.2.6"></a>Cross Product</h5>
-<!--l. 238--><p class="noindent" >The <span
-class="ecti-1000">cross product </span>also takes two vectors <span
-class="ecti-1000">a </span>and <span
-class="ecti-1000">b</span>, but returns another vector <span
-class="ecti-1000">c </span>that is
-orthogonal to the two previous ones.
-<div class="center"
->
-<!--l. 242--><p class="noindent" >
-<!--l. 243--><p class="noindent" ><span
-class="cmmi-10">c</span><sub><span
-class="cmmi-7">x</span></sub> <span
-class="cmr-10">= </span><span
-class="cmmi-10">a</span><sub><span
-class="cmmi-7">x</span></sub><span
-class="cmmi-10">b</span><sub><span
-class="cmmi-7">z</span></sub> <span
-class="cmsy-10">- </span><span
-class="cmmi-10">a</span><sub><span
-class="cmmi-7">z</span></sub><span
-class="cmmi-10">b</span><sub><span
-class="cmmi-7">y</span></sub>
-</div>
-<div class="center"
->
-<!--l. 246--><p class="noindent" >
-<!--l. 247--><p class="noindent" ><span
-class="cmmi-10">c</span><sub><span
-class="cmmi-7">y</span></sub> <span
-class="cmr-10">= </span><span
-class="cmmi-10">a</span><sub><span
-class="cmmi-7">z</span></sub><span
-class="cmmi-10">b</span><sub><span
-class="cmmi-7">x</span></sub> <span
-class="cmsy-10">- </span><span
-class="cmmi-10">a</span><sub><span
-class="cmmi-7">x</span></sub><span
-class="cmmi-10">b</span><sub><span
-class="cmmi-7">z</span></sub>
-</div>
-<div class="center"
->
-<!--l. 250--><p class="noindent" >
-<!--l. 251--><p class="noindent" ><span
-class="cmmi-10">c</span><sub><span
-class="cmmi-7">z</span></sub> <span
-class="cmr-10">= </span><span
-class="cmmi-10">a</span><sub><span
-class="cmmi-7">x</span></sub><span
-class="cmmi-10">b</span><sub><span
-class="cmmi-7">y</span></sub> <span
-class="cmsy-10">- </span><span
-class="cmmi-10">a</span><sub><span
-class="cmmi-7">y</span></sub><span
-class="cmmi-10">b</span><sub><span
-class="cmmi-7">x</span></sub>
-</div>
-<!--l. 254--><p class="indent" > The same in code:
- <!--l. 257-->
- <div class="lstlisting"><span class="label"><a
- id="x1-9001r1"></a></span>a&#x00A0;=&#x00A0;Vector3(...)&#x00A0;<br /><span class="label"><a
- id="x1-9002r2"></a></span>b&#x00A0;=&#x00A0;Vector3(...)&#x00A0;<br /><span class="label"><a
- id="x1-9003r3"></a></span>c&#x00A0;=&#x00A0;Vector3(...)&#x00A0;<br /><span class="label"><a
- id="x1-9004r4"></a></span>&#x00A0;<br /><span class="label"><a
- id="x1-9005r5"></a></span>c.x&#x00A0;=&#x00A0;a.x<span
-class="cmsy-10">*</span>b.z&#x00A0;<span
-class="cmsy-10">-</span>&#x00A0;a.z<span
-class="cmsy-10">*</span>b.y&#x00A0;<br /><span class="label"><a
- id="x1-9006r6"></a></span>c.y&#x00A0;=&#x00A0;a.z<span
-class="cmsy-10">*</span>b.x&#x00A0;<span
-class="cmsy-10">-</span>&#x00A0;a.x<span
-class="cmsy-10">*</span>b.z&#x00A0;<br /><span class="label"><a
- id="x1-9007r7"></a></span>c.z&#x00A0;=&#x00A0;a.x<span
-class="cmsy-10">*</span>b.y&#x00A0;<span
-class="cmsy-10">-</span>&#x00A0;a.y<span
-class="cmsy-10">*</span>b.x&#x00A0;<br /><span class="label"><a
- id="x1-9008r8"></a></span>&#x00A0;<br /><span class="label"><a
- id="x1-9009r9"></a></span>//&#x00A0;or&#x00A0;using&#x00A0;the&#x00A0;built<span
-class="cmsy-10">-</span>in&#x00A0;function&#x00A0;<br /><span class="label"><a
- id="x1-9010r10"></a></span>&#x00A0;<br /><span class="label"><a
- id="x1-9011r11"></a></span>c&#x00A0;=&#x00A0;a.cross(b)
- </div>
-<!--l. 273--><p class="indent" > The <span
-class="ecti-1000">cross product </span>also presents several useful properties:
- <ul class="itemize1">
- <li class="itemize">As mentioned, the resulting vector <span
-class="ecti-1000">c </span>is orthogonal to the input vectors <span
-class="ecti-1000">a</span>
- and <span
-class="ecti-1000">b.</span>
- </li>
- <li class="itemize">Since the <span
-class="ecti-1000">cross product </span>is anticommutative, swapping <span
-class="ecti-1000">a </span>and <span
-class="ecti-1000">b </span>will result
- in a negated vector <span
-class="ecti-1000">c.</span>
-
- </li>
- <li class="itemize">if <span
-class="ecti-1000">a </span>and <span
-class="ecti-1000">b </span>are taken from two of the segmets <span
-class="ecti-1000">AB</span>, <span
-class="ecti-1000">BC </span>or <span
-class="ecti-1000">CA </span>that form a
- 3D triangle, the magnitude of the resulting vector divided by 2 is the area
- of that triangle.
- </li>
- <li class="itemize">The direction of the resulting vector <span
-class="ecti-1000">c </span>in the previous triangle example
- determines wether the points A,B and C are arranged in clocwise or
- counter-clockwise order.</li></ul>
-<!--l. 287--><p class="noindent" >
- <h4 class="subsectionHead"><span class="titlemark">1.3 </span> <a
- id="x1-100001.3"></a>Plane</h4>
-<!--l. 290--><p class="noindent" >
- <h5 class="subsubsectionHead"><span class="titlemark">1.3.1 </span> <a
- id="x1-110001.3.1"></a>Theory</h5>
-<!--l. 292--><p class="noindent" >A plane can be considered as an infinite, flat surface that splits space in two halves,
-usually one named positive and one named negative. In regular mathematics, a plane
-formula is described as:
-<div class="center"
->
-<!--l. 296--><p class="noindent" >
-<!--l. 297--><p class="noindent" ><span
-class="cmmi-10">ax </span><span
-class="cmr-10">+ </span><span
-class="cmmi-10">by </span><span
-class="cmr-10">+ </span><span
-class="cmmi-10">cz </span><span
-class="cmr-10">+ </span><span
-class="cmmi-10">d</span>
-</div>
-<!--l. 300--><p class="indent" > However, in 3D programming, this form alone is often of little use. For planes to
-become useful, they must be in normalized form.
-<!--l. 303--><p class="indent" > A normalized plane consists of a <span
-class="ecti-1000">normal vector n </span>and a <span
-class="ecti-1000">distance d. </span>To normalize
-a plane, a vector <span
-class="ecti-1000">n </span>and distance <span
-class="ecti-1000">d&#8217; </span>are created this way:
-<!--l. 307--><p class="indent" > <span
-class="cmmi-10">n</span><sub><span
-class="cmmi-7">x</span></sub> <span
-class="cmr-10">= </span><span
-class="cmmi-10">a</span>
-<!--l. 309--><p class="indent" > <span
-class="cmmi-10">n</span><sub><span
-class="cmmi-7">y</span></sub> <span
-class="cmr-10">= </span><span
-class="cmmi-10">b</span>
-<!--l. 311--><p class="indent" > <span
-class="cmmi-10">n</span><sub><span
-class="cmmi-7">z</span></sub> <span
-class="cmr-10">= </span><span
-class="cmmi-10">c</span>
-<!--l. 313--><p class="indent" > <span
-class="cmmi-10">d</span><span
-class="cmsy-10">&#x2032; </span><span
-class="cmr-10">= </span><span
-class="cmmi-10">d</span>
-<!--l. 315--><p class="indent" > Finally, both <span
-class="ecti-1000">n </span>and <span
-class="ecti-1000">d&#8217; </span>are both divided by the magnitude of n.
-<!--l. 318--><p class="indent" > In any case, normalizing planes is not often needed (this was mostly for
-explanation purposes), and normalized planes are useful because they can be created
-and used easily.
-<!--l. 322--><p class="indent" > A normalized plane could be visualized as a plane pointing towards normal <span
-class="ecti-1000">n,</span>
-offseted by <span
-class="ecti-1000">d </span>in the direction of <span
-class="ecti-1000">n</span>.
-<!--l. 325--><p class="indent" > In other words, take <span
-class="ecti-1000">n</span>, multiply it by scalar <span
-class="ecti-1000">d </span>and the resulting point will be part
-of the plane. This may need some thinking, so an example with a 2D normal vector
-(z is 0, so plane is orthogonal to it) is provided:
-<!--l. 330--><p class="indent" > Some operations can be done with normalized planes:
-
- <ul class="itemize1">
- <li class="itemize">Given any point <span
-class="ecti-1000">p</span>, the distance from it to a plane can be computed by
- doing: n.dot(p) - d
- </li>
- <li class="itemize">If the resulting distance in the previous point is negative, the point is
- below the plane.
- </li>
- <li class="itemize">Convex polygonal shapes can be defined by enclosing them in planes (the
- physics engine uses this property)</li></ul>
-<!--l. 340--><p class="noindent" >
- <h5 class="subsubsectionHead"><span class="titlemark">1.3.2 </span> <a
- id="x1-120001.3.2"></a>Implementation</h5>
-<!--l. 342--><p class="noindent" >Godot Engine implements normalized planes by using the <span
-class="ecti-1000">Plane </span>class.
- <!--l. 346-->
- <div class="lstlisting"><span class="label"><a
- id="x1-12001r1"></a></span>//creates&#x00A0;a&#x00A0;plane&#x00A0;with&#x00A0;normal&#x00A0;(0,1,0)&#x00A0;and&#x00A0;distance&#x00A0;5&#x00A0;<br /><span class="label"><a
- id="x1-12002r2"></a></span>p&#x00A0;=&#x00A0;Plane(&#x00A0;Vector3(0,1,0),&#x00A0;5&#x00A0;)&#x00A0;<br /><span class="label"><a
- id="x1-12003r3"></a></span>//&#x00A0;get&#x00A0;the&#x00A0;distance&#x00A0;to&#x00A0;a&#x00A0;point&#x00A0;<br /><span class="label"><a
- id="x1-12004r4"></a></span>d&#x00A0;=&#x00A0;p.distance(&#x00A0;Vector3(4,5,6)&#x00A0;)
- </div>
-<!--l. 355--><p class="noindent" >
- <h4 class="subsectionHead"><span class="titlemark">1.4 </span> <a
- id="x1-130001.4"></a>Matrices, Quaternions and Coordinate Systems</h4>
-<!--l. 357--><p class="noindent" >It is very often needed to store the location/rotation of something. In 2D, it is often
-enough to store an <span
-class="ecti-1000">x,y </span>location and maybe an angle as the rotation, as that should
-be enough to represent any posible position.
-<!--l. 362--><p class="indent" > In 3D this becomes a little more difficult, as there is nothing as simple as an angle
-to store a 3-axis rotation.
-<!--l. 365--><p class="indent" > The first think that may come to mind is to use 3 angles, one for x, one for y and
-one for z. However this suffers from the problem that it becomes very cumbersome to
-use, as the individual rotations in each axis need to be performed one after another
-(they can&#8217;t be performed at the same time), leading to a problem called &#8220;gimbal
-lock&#8221;. Also, it becomes impossible to accumulate rotations (add a rotation to an
-existing one).
-<!--l. 373--><p class="indent" > To solve this, there are two known diferent approaches that aid in solving
-rotation, <span
-class="ecti-1000">Quaternions </span>and <span
-class="ecti-1000">Oriented Coordinate Systems.</span>
-<!--l. 378--><p class="noindent" >
- <h5 class="subsubsectionHead"><span class="titlemark">1.4.1 </span> <a
- id="x1-140001.4.1"></a>Oriented Coordinate Systems</h5>
-<!--l. 380--><p class="noindent" ><span
-class="ecti-1000">Oriented Coordinate Systems </span>(<span
-class="ecti-1000">OCS</span>) are a way of representing a coordinate system
-inside the cartesian coordinate system. They are mainly composed of 3 Vectors, one
-for each axis. The first vector is the <span
-class="ecti-1000">x </span>axis, the second the <span
-class="ecti-1000">y </span>axis, and the third is the
-
-<span
-class="ecti-1000">z </span>axis. The OCS vectors can be rotated around freely as long as they are kept the
-same length (as changing the length of an axis changes its cale), and as long as they
-remain orthogonal to eachother (as in, the same as the default cartesian system,
-with <span
-class="ecti-1000">y </span>pointing up, <span
-class="ecti-1000">x </span>pointing left and <span
-class="ecti-1000">z </span>pointing front, but all rotated
-together).
-<!--l. 391--><p class="indent" > <span
-class="ecti-1000">Oriented Coordinate Systems </span>are represented in 3D programming as a 3x3 matrix,
-where each row (or column, depending on the implementation) contains one of the
-axis vectors. Transforming a Vector by a rotated OCS Matrix results in the rotation
-being applied to the resulting vector. OCS Matrices can also be multiplied to
-accumulate their transformations.
-<!--l. 397--><p class="indent" > Godot Engine implements OCS Matrices in the <span
-class="ecti-1000">Matrix3 </span>class:
- <!--l. 400-->
- <div class="lstlisting"><span class="label"><a
- id="x1-14001r1"></a></span><span
-class="ecti-1000">//</span><span
-class="ecti-1000">create</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">a</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">3</span><span
-class="ecti-1000">x3</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">matrix</span>&#x00A0;<br /><span class="label"><a
- id="x1-14002r2"></a></span>m&#x00A0;=&#x00A0;Matrix3()&#x00A0;<br /><span class="label"><a
- id="x1-14003r3"></a></span><span
-class="ecti-1000">//</span><span
-class="ecti-1000">rotate</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">the</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">matrix</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">in</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">the</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">y</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">axis</span><span
-class="ecti-1000">,</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">by</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">45</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">degrees</span>&#x00A0;<br /><span class="label"><a
- id="x1-14004r4"></a></span>m.rotate(&#x00A0;Vector3(0,1,0),&#x00A0;Math.deg2rad(45)&#x00A0;)&#x00A0;<br /><span class="label"><a
- id="x1-14005r5"></a></span><span
-class="ecti-1000">//</span><span
-class="ecti-1000">transform</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">a</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">vector</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">v</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">(</span><span
-class="ecti-1000">xform</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">method</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">is</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">used</span><span
-class="ecti-1000">)</span>&#x00A0;<br /><span class="label"><a
- id="x1-14006r6"></a></span>v&#x00A0;=&#x00A0;Vector3(...)&#x00A0;<br /><span class="label"><a
- id="x1-14007r7"></a></span>result&#x00A0;=&#x00A0;m.xform(&#x00A0;v&#x00A0;)
- </div>
-<!--l. 412--><p class="indent" > However, in most usage cases, one wants to store a translation together with the
-rotation. For this, an <span
-class="ecti-1000">origin </span>vector must be added to the OCS, thus transforming it
-into a 3x4 (or 4x3, depending on preference) matrix. Godot engine implements this
-functionality in the <span
-class="ecti-1000">Transform </span>class:
- <!--l. 419-->
- <div class="lstlisting"><span class="label"><a
- id="x1-14010r1"></a></span>t&#x00A0;=&#x00A0;Transform()&#x00A0;<br /><span class="label"><a
- id="x1-14011r2"></a></span>//rotate&#x00A0;the&#x00A0;transform&#x00A0;in&#x00A0;the&#x00A0;y&#x00A0;axis,&#x00A0;by&#x00A0;45&#x00A0;degrees&#x00A0;<br /><span class="label"><a
- id="x1-14012r3"></a></span>t.rotate(&#x00A0;Vector3(0,1,0),&#x00A0;Math.deg2rad(45)&#x00A0;)&#x00A0;<br /><span class="label"><a
- id="x1-14013r4"></a></span>//translate&#x00A0;the&#x00A0;transform&#x00A0;by&#x00A0;5&#x00A0;in&#x00A0;the&#x00A0;z&#x00A0;axis&#x00A0;<br /><span class="label"><a
- id="x1-14014r5"></a></span>t.translate(&#x00A0;Vector3(&#x00A0;0,0,5&#x00A0;)&#x00A0;)&#x00A0;<br /><span class="label"><a
- id="x1-14015r6"></a></span>//transform&#x00A0;a&#x00A0;vector&#x00A0;v&#x00A0;(xform&#x00A0;method&#x00A0;is&#x00A0;used)&#x00A0;<br /><span class="label"><a
- id="x1-14016r7"></a></span>v&#x00A0;=&#x00A0;Vector3(...)&#x00A0;<br /><span class="label"><a
- id="x1-14017r8"></a></span>result&#x00A0;=&#x00A0;t.xform(&#x00A0;v&#x00A0;)
- </div>
-<!--l. 431--><p class="indent" > Transform contains internally a Matrix3 &#8220;basis&#8221; and a Vector3 &#8220;origin&#8221; (which can
-be modified individually).
-<!--l. 435--><p class="noindent" >
- <h5 class="subsubsectionHead"><span class="titlemark">1.4.2 </span> <a
- id="x1-150001.4.2"></a>Transform Internals</h5>
-<!--l. 437--><p class="noindent" >Internally, the xform() process is quite simple, to apply a 3x3 transform to a vector,
-the transposed axis vectors are used (as using the regular axis vectors will result on
-an inverse of the desired transform):
- <!--l. 442-->
- <div class="lstlisting"><span class="label"><a
- id="x1-15001r1"></a></span>m&#x00A0;=&#x00A0;Matrix3(...)&#x00A0;<br /><span class="label"><a
- id="x1-15002r2"></a></span>v&#x00A0;=&#x00A0;Vector3(..)&#x00A0;<br /><span class="label"><a
- id="x1-15003r3"></a></span>result&#x00A0;=&#x00A0;Vector3(...)&#x00A0;<br /><span class="label"><a
- id="x1-15004r4"></a></span>&#x00A0;<br /><span class="label"><a
- id="x1-15005r5"></a></span>x_axis&#x00A0;=&#x00A0;m.get_axis(0)&#x00A0;<br /><span class="label"><a
- id="x1-15006r6"></a></span>y_axis&#x00A0;=&#x00A0;m.get_axis(1)&#x00A0;<br /><span class="label"><a
- id="x1-15007r7"></a></span>z_axis&#x00A0;=&#x00A0;m.get_axis(2)&#x00A0;<br /><span class="label"><a
- id="x1-15008r8"></a></span>&#x00A0;<br /><span class="label"><a
- id="x1-15009r9"></a></span>result.x&#x00A0;=&#x00A0;Vector3(x_axis.x,&#x00A0;y_axis.x,&#x00A0;z_axis.x).dot(v)&#x00A0;<br /><span class="label"><a
- id="x1-15010r10"></a></span>result.y&#x00A0;=&#x00A0;Vector3(x_axis.y,&#x00A0;y_axis.y,&#x00A0;z_axis.y).dot(v)&#x00A0;<br /><span class="label"><a
- id="x1-15011r11"></a></span>result.z&#x00A0;=&#x00A0;Vector3(x_axis.z,&#x00A0;y_axis.z,&#x00A0;z_axis.z).dot(v)&#x00A0;<br /><span class="label"><a
- id="x1-15012r12"></a></span>&#x00A0;<br /><span class="label"><a
- id="x1-15013r13"></a></span>//&#x00A0;is&#x00A0;the&#x00A0;same&#x00A0;as&#x00A0;doing&#x00A0;<br /><span class="label"><a
- id="x1-15014r14"></a></span>&#x00A0;<br /><span class="label"><a
- id="x1-15015r15"></a></span>result&#x00A0;=&#x00A0;m.xform(v)&#x00A0;<br /><span class="label"><a
- id="x1-15016r16"></a></span>&#x00A0;<br /><span class="label"><a
- id="x1-15017r17"></a></span>//&#x00A0;if&#x00A0;m&#x00A0;this&#x00A0;was&#x00A0;a&#x00A0;Transform(),&#x00A0;the&#x00A0;origin&#x00A0;would&#x00A0;be&#x00A0;added&#x00A0;<br /><span class="label"><a
- id="x1-15018r18"></a></span>//&#x00A0;like&#x00A0;this:&#x00A0;<br /><span class="label"><a
- id="x1-15019r19"></a></span>&#x00A0;<br /><span class="label"><a
- id="x1-15020r20"></a></span>result&#x00A0;=&#x00A0;result&#x00A0;+&#x00A0;t.get_origin()
- </div>
-<!--l. 468--><p class="noindent" >
- <h5 class="subsubsectionHead"><span class="titlemark">1.4.3 </span> <a
- id="x1-160001.4.3"></a>Using The Transform</h5>
-<!--l. 470--><p class="noindent" >So, it is often desired apply sucessive operations to a transformation. For example,
-let&#8217;s a assume that there is a turtle sitting at the origin (the turtle is a logo reference,
-
-for those familiar with it). The <span
-class="ecti-1000">y </span>axis is up, and the the turtle&#8217;s nose is pointing
-towards the <span
-class="ecti-1000">z </span>axis.
-<!--l. 476--><p class="indent" > The turtle (like many other animals, or vehicles!) can only walk towards the
-direction it&#8217;s looking at. So, moving the turtle around a little should be something
-like this:
- <!--l. 481-->
- <div class="lstlisting"><span class="label"><a
- id="x1-16001r1"></a></span><span
-class="ecti-1000">//</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">turtle</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">at</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">the</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">origin</span>&#x00A0;<br /><span class="label"><a
- id="x1-16002r2"></a></span>turtle&#x00A0;=&#x00A0;Transform()&#x00A0;<br /><span class="label"><a
- id="x1-16003r3"></a></span><span
-class="ecti-1000">//</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">turtle</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">will</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">walk</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">5</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">units</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">in</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">z</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">axis</span>&#x00A0;<br /><span class="label"><a
- id="x1-16004r4"></a></span>turtle.translate(&#x00A0;Vector3(0,0,5)&#x00A0;)&#x00A0;<br /><span class="label"><a
- id="x1-16005r5"></a></span><span
-class="ecti-1000">//</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">turtle</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">eyes</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">a</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">lettuce</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">3</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">units</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">away</span><span
-class="ecti-1000">,</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">will</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">rotate</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">45</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">degrees</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">right</span>&#x00A0;<br /><span class="label"><a
- id="x1-16006r6"></a></span>turtle.rotate(&#x00A0;Vector3(0,1,0),&#x00A0;Math.deg2rad(45)&#x00A0;)&#x00A0;<br /><span class="label"><a
- id="x1-16007r7"></a></span><span
-class="ecti-1000">//</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">turtle</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">approaches</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">the</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">lettuce</span>&#x00A0;<br /><span class="label"><a
- id="x1-16008r8"></a></span>turtle.translate(&#x00A0;Vector3(0,0,5)&#x00A0;)&#x00A0;<br /><span class="label"><a
- id="x1-16009r9"></a></span><span
-class="ecti-1000">//</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">happy</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">turtle</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">over</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">lettuce</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">is</span><span
-class="ecti-1000">&#x00A0;</span><span
-class="ecti-1000">at</span>&#x00A0;<br /><span class="label"><a
- id="x1-16010r10"></a></span>print(turtle.get_origin())
- </div>
-<!--l. 496--><p class="indent" > As can be seen, every new action the turtle takes is based on the previous one it
-took. Had the order of actions been different and the turtle would have never reached
-the lettuce.
-<!--l. 500--><p class="indent" > Transforms are just that, a mean of &#8220;accumulating&#8221; rotation, translation, scale,
-etc.
-<!--l. 504--><p class="noindent" >
- <h5 class="subsubsectionHead"><span class="titlemark">1.4.4 </span> <a
- id="x1-170001.4.4"></a>A Warning about Numerical Precision</h5>
-<!--l. 506--><p class="noindent" >Performing several actions over a transform will slowly and gradually lead to
-precision loss (objects that draw according to a transform may get jittery, bigger,
-smaller, skewed, etc). This happens due to the nature of floating point numbers. if
-transforms/matrices are created from other kind of values (like a position and
-some angular rotation) this is not needed, but if has been accumulating
-transformations and was never recreated, it can be normalized by calling the
-.orthonormalize() built-in function. This function has little cost and calling it every
-now and then will avoid the effects from precision loss to become visible.
-
-</body></html>
-
-
-
diff --git a/doc/html/tutorial01/tutorial0x.png b/doc/html/tutorial01/tutorial0x.png
deleted file mode 100644
index a0ed4f53ff..0000000000
--- a/doc/html/tutorial01/tutorial0x.png
+++ /dev/null
Binary files differ
diff --git a/doc/html/tutorial01/tutorial1x.png b/doc/html/tutorial01/tutorial1x.png
deleted file mode 100644
index 80f0d099f7..0000000000
--- a/doc/html/tutorial01/tutorial1x.png
+++ /dev/null
Binary files differ
diff --git a/doc/html/tutorial01/tutorial2x.png b/doc/html/tutorial01/tutorial2x.png
deleted file mode 100644
index 76c502b6da..0000000000
--- a/doc/html/tutorial01/tutorial2x.png
+++ /dev/null
Binary files differ
diff --git a/doc/html/tutorial01/tutorial3x.png b/doc/html/tutorial01/tutorial3x.png
deleted file mode 100644
index 8431e9d15c..0000000000
--- a/doc/html/tutorial01/tutorial3x.png
+++ /dev/null
Binary files differ
diff --git a/doc/html/tutorial01/tutorial4x.png b/doc/html/tutorial01/tutorial4x.png
deleted file mode 100644
index 1ce7a2bb45..0000000000
--- a/doc/html/tutorial01/tutorial4x.png
+++ /dev/null
Binary files differ
diff --git a/doc/make_doc.sh b/doc/make_doc.sh
deleted file mode 100644
index a76f568bfc..0000000000
--- a/doc/make_doc.sh
+++ /dev/null
@@ -1,17 +0,0 @@
-#! /bin/bash
-here="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
-godotHome=$(dirname "$here")
-docTarget=${here}/html/class_list
-toolsRoot=${godotHome}/tools
-
-throw() {
- echo "$@" >&2
- exit 1
-}
-
-[ -d "$docTarget" ] || mkdir -p "$docTarget" || throw "Could not create doc target $docTarget"
-
-cd "$docTarget"
-python ${toolsRoot}/docdump/makehtml.py -multipage ${here}/base/classes.xml
-cd "$here"
-
diff --git a/doc/notes.txt b/doc/notes.txt
deleted file mode 100644
index 39c03ca4c5..0000000000
--- a/doc/notes.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-
-in FileDialog file_selected -> file_activated
-focus script/shader editor when gaining focus
-detect if errors in editor and don't allow play
-
-
--tree of files (all recognized extensions)
-
-*export: *keep|export|bundle
-*options: [make binary for xnl], then options for each filetype (texture compress method, etc)
-
-
-config.h deberia teber varias cosas de plataforma
-
-_FORCE_INLINE_
-copymem
-ftoi
-defines de funciones matematicas
-
-
diff --git a/doc/phys_engine.png b/doc/phys_engine.png
deleted file mode 100644
index 15539d47d7..0000000000
--- a/doc/phys_engine.png
+++ /dev/null
Binary files differ
diff --git a/doc/squirrel.lyx b/doc/squirrel.lyx
deleted file mode 100644
index 05270c1b8f..0000000000
--- a/doc/squirrel.lyx
+++ /dev/null
@@ -1,984 +0,0 @@
-#LyX 2.0 created this file. For more info see http://www.lyx.org/
-\lyxformat 413
-\begin_document
-\begin_header
-\textclass article
-\use_default_options true
-\maintain_unincluded_children false
-\language english
-\language_package default
-\inputencoding auto
-\fontencoding global
-\font_roman default
-\font_sans default
-\font_typewriter default
-\font_default_family default
-\use_non_tex_fonts false
-\font_sc false
-\font_osf false
-\font_sf_scale 100
-\font_tt_scale 100
-
-\graphics default
-\default_output_format default
-\output_sync 0
-\bibtex_command default
-\index_command default
-\paperfontsize default
-\use_hyperref false
-\papersize default
-\use_geometry false
-\use_amsmath 1
-\use_esint 1
-\use_mhchem 1
-\use_mathdots 1
-\cite_engine basic
-\use_bibtopic false
-\use_indices false
-\paperorientation portrait
-\suppress_date false
-\use_refstyle 1
-\index Index
-\shortcut idx
-\color #008000
-\end_index
-\secnumdepth 3
-\tocdepth 3
-\paragraph_separation indent
-\paragraph_indentation default
-\quotes_language english
-\papercolumns 1
-\papersides 1
-\paperpagestyle default
-\tracking_changes false
-\output_changes false
-\html_math_output 0
-\html_css_as_file 0
-\html_be_strict false
-\end_header
-
-\begin_body
-
-\begin_layout Title
-Squirrel Usage in Godot
-\end_layout
-
-\begin_layout Section
-Introduction
-\end_layout
-
-\begin_layout Standard
-Squirrel is a nice scripting language.
- It's sort of a mix between Lua, Java and JavaScript and ends up being easy
- to learn for most programmers.
- It has more language features than GDScript but it's also slower, more
- limited and not as well integrated.
- This guide will explain how Squirrel is integrated to Godot and all the
- quirks that are needed to know in order to use it properly.
-\end_layout
-
-\begin_layout Section
-Enabling Squirrel
-\end_layout
-
-\begin_layout Standard
-Squirrel may not be enabled by default in a Godot build.
- To enable it, execute SCons with the following parameters:
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-shell$ scons squirrel=yes <target_binary>
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Section
-Documentation
-\end_layout
-
-\begin_layout Standard
-Godot utilizes Squirrel 2.2.
- Documentation can be found at:
-\begin_inset CommandInset href
-LatexCommand href
-target "http://squirrel-lang.org/#documentation"
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Section
-Class Files
-\end_layout
-
-\begin_layout Standard
-Unless writing a library, Godot expects a class for scripting an object.
- Since a Squirrel source file can contain many classes, the main class must
- be returned.
- The following is an example of extending a button:
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-class MyButton extends Button {
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
- constructor() {
-\end_layout
-
-\begin_layout Plain Layout
-
- // ALWAYS call parent constructor
-\end_layout
-
-\begin_layout Plain Layout
-
- Button.constructor()
-\end_layout
-
-\begin_layout Plain Layout
-
- }
-\end_layout
-
-\begin_layout Plain Layout
-
-}
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-return MyButton // main class returned
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Standard
-Additionally, classes are all copied to the root table, so all class names
- in scripts must be different if they are attempted to be loaded simultaneously.
- The same can be said for any other globals declared in the script.
-
-\end_layout
-
-\begin_layout Standard
-Finally, squirrel scripts must be saved with the .nut or .sq extensions (both
- are recognized).
-\end_layout
-
-\begin_layout Section
-Including Other Scripts
-\end_layout
-
-\begin_layout Standard
-Other scripts can be included with the include() directive.
- Full and relative paths are supported.
- When included, the classes and globals are moved to the root table, so
- they become immediately available.
- Constants, however, are only inlined in the current class on load, so Squirrel
- does not make them available.
- Example of including scripts:
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-include("my_button.nut") # // relative to current script, expected to be
- in the same path
-\end_layout
-
-\begin_layout Plain Layout
-
-include("res://buttons/my_button.nut") // using resource path
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Section
-Built-In Types
-\end_layout
-
-\begin_layout Standard
-There are some small differences between the Built-In types in Godot and
- the ones in Squirrel, so the documentation will not match.
- The differences are documented here.
-\end_layout
-
-\begin_layout Standard
-An attempt will be made to document everything here,but if in doubt about
- bindings on built-in types, you can always take a loot at the bindings
- source file in script/squirrel/sq_bind_types.cpp.
-\end_layout
-
-\begin_layout Standard
-Built-In Types in Squirrel are passed by reference (unlike by value like
- in GD).
- They also don't need to be freed.
-\end_layout
-
-\begin_layout Subsection
-AABB
-\end_layout
-
-\begin_layout Standard
-\begin_inset Quotes eld
-\end_inset
-
-pos
-\begin_inset Quotes erd
-\end_inset
-
-,
-\begin_inset Quotes eld
-\end_inset
-
-size
-\begin_inset Quotes erd
-\end_inset
-
- and
-\begin_inset Quotes eld
-\end_inset
-
-end
-\begin_inset Quotes erd
-\end_inset
-
- are not available Use get_pos()/set_pos and get_size()/set_size().
-\end_layout
-
-\begin_layout Subsection
-InputEvent
-\end_layout
-
-\begin_layout Standard
-InputEvent is a single datatype and contains everything.
- Use only the fields meant for the event type:
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-//for mouse motion and button
-\end_layout
-
-\begin_layout Plain Layout
-
-int mouse_x
-\end_layout
-
-\begin_layout Plain Layout
-
-int mouse_y
-\end_layout
-
-\begin_layout Plain Layout
-
-int mouse_button_mask
-\end_layout
-
-\begin_layout Plain Layout
-
-int mouse_global_x
-\end_layout
-
-\begin_layout Plain Layout
-
-int mouse_global_y
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-//for mouse button
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-int mouse_button_index
-\end_layout
-
-\begin_layout Plain Layout
-
-bool mouse_button_pressed
-\end_layout
-
-\begin_layout Plain Layout
-
-bool mouse_button_doubleclick
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-//for mouse motion
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-int mouse_motion_x
-\end_layout
-
-\begin_layout Plain Layout
-
-int mouse_motion_y
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-//for keyboard
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-int key_scancode
-\end_layout
-
-\begin_layout Plain Layout
-
-int key_unicode
-\end_layout
-
-\begin_layout Plain Layout
-
-bool key_pressed
-\end_layout
-
-\begin_layout Plain Layout
-
-bool key_echo
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-//for keyboard and mouse
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-bool mod_alt
-\end_layout
-
-\begin_layout Plain Layout
-
-bool mod_shift
-\end_layout
-
-\begin_layout Plain Layout
-
-bool mod_meta
-\end_layout
-
-\begin_layout Plain Layout
-
-bool mod_control
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-//joy button
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-int joy_button_index
-\end_layout
-
-\begin_layout Plain Layout
-
-bool joy_button_pressed
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-//joy axis
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-int joy_axis
-\end_layout
-
-\begin_layout Plain Layout
-
-float joy_axis_value
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-//screen drag and touch
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-int screen_index
-\end_layout
-
-\begin_layout Plain Layout
-
-int screen_x
-\end_layout
-
-\begin_layout Plain Layout
-
-int screen_y
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-//screen touch
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-int screen_index
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-//action
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-int action_id
-\end_layout
-
-\begin_layout Plain Layout
-
-bool action_pressed
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Subsection
-Matrix3
-\end_layout
-
-\begin_layout Standard
-x,y,z member vectors are not available.
- Use get_row() and set_row() instead.
- Individual float values of the matrix are available as swizzle masks such
- as xxy, xyz, zzx, etc.
-\end_layout
-
-\begin_layout Standard
-Additional in-place versions of some functions are available: transpose(),
- invert(), rotate(), scale(), orthonormalize().
-\end_layout
-
-\begin_layout Subsection
-Transform
-\end_layout
-
-\begin_layout Standard
-\begin_inset Quotes eld
-\end_inset
-
-basis
-\begin_inset Quotes erd
-\end_inset
-
- and
-\begin_inset Quotes eld
-\end_inset
-
-origin
-\begin_inset Quotes erd
-\end_inset
-
- members are not available.
- Use get_basis()/set_basis() and get_origin()/set_origin() instead.
- Additional in-place versions of some functions are available: invert(),
- affine_invert(), orthonormalize(), rotate(), translate(), scale().
-\end_layout
-
-\begin_layout Standard
-Vector2
-\end_layout
-
-\begin_layout Subsection
-Plane
-\end_layout
-
-\begin_layout Standard
-\begin_inset Quotes eld
-\end_inset
-
-normal
-\begin_inset Quotes erd
-\end_inset
-
- member vector is not available.
- Use get_normal(), set_normal() instead.
-\end_layout
-
-\begin_layout Subsection
-Rect2
-\end_layout
-
-\begin_layout Standard
-\begin_inset Quotes eld
-\end_inset
-
-pos
-\begin_inset Quotes erd
-\end_inset
-
-,
-\begin_inset Quotes eld
-\end_inset
-
-size
-\begin_inset Quotes erd
-\end_inset
-
- and
-\begin_inset Quotes eld
-\end_inset
-
-end
-\begin_inset Quotes erd
-\end_inset
-
- are not available Use get_pos()/set_pos and get_size()/set_size().
-\end_layout
-
-\begin_layout Subsection
-Native Arrays
-\end_layout
-
-\begin_layout Standard
-Native arrays such as RawArray, IntArray,StringArray, etc are not supported.
- Use regular squirrel arrays instead, since conversion to/from them will
- happen automatically.
-\end_layout
-
-\begin_layout Subsection
-Math Functions
-\end_layout
-
-\begin_layout Standard
-Math functions are inside the Math namespace in Squirrel.
- For example Math.sin , Math.PI, Math.atan2().
-\end_layout
-
-\begin_layout Subsection
-Native Types
-\end_layout
-
-\begin_layout Standard
-Array, Dictionary and NodePath are not available.
- Use a native array, table and string respectively.
-\end_layout
-
-\begin_layout Section
-_get , _set
-\end_layout
-
-\begin_layout Standard
-_get and _set are reserved in Squirrel, for overriding Godot Object property
- getter/setter, use _get_property and _set_property.
-\end_layout
-
-\begin_layout Section
-Member Export
-\end_layout
-
-\begin_layout Standard
-Simple exporting of members (so far only integer, floating point and string
- are supported) is supported by the @export extension.
- It is used like this:
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-class MyButton extends Button {
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
- aprop=1 // @export
-\end_layout
-
-\begin_layout Plain Layout
-
- bprop=2.0 // @export
-\end_layout
-
-\begin_layout Plain Layout
-
- cprop="3" // @export
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
- //these will be available to the property editor, and will be loaded/saved
- with the scene.
-\end_layout
-
-\begin_layout Plain Layout
-
-}
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Section
-Always Enabled Scripts
-\end_layout
-
-\begin_layout Standard
-Scripts are not enabled in the editor by default.
- To enable a script always, add an @always_enabled comment.
- Example:
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-//@always_enabled
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-class MyButton extends Button {
-\end_layout
-
-\begin_layout Plain Layout
-
-\end_layout
-
-\begin_layout Plain Layout
-
-...
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Section
-Threads
-\end_layout
-
-\begin_layout Standard
-Thread support in Squirrel is very poor.
- This is because of the stack-based nature of the language implementation.
- Since godot can run in multiple threads, it will forcibily lock the whole
- VM when accessed from multiple threads, which will result in degraded performan
-ce.
- Creating user threads in Squirrel is definitely not recomended, as it may
- completely lock the main thread.
-\end_layout
-
-\begin_layout Section
-References
-\end_layout
-
-\begin_layout Standard
-Godot has a built-in reference counted type used in conjunction with a template
- (objects that inherit the
-\begin_inset Quotes eld
-\end_inset
-
-Reference
-\begin_inset Quotes erd
-\end_inset
-
- class).
- Since Squirrel also uses reference counting, it becomes impossible for
- such types in godot to contain a script, because it would result in an
- un-breakable reference cycle.
- To avoid this, a Ref() class was created in Squirrel.
-
-\end_layout
-
-\begin_layout Standard
-When calling Godot API functions, returned references are wrapped inside
- Ref() transparently, but the problem arises when creating a Reference-derived
- object from the code.
- In such cases, the reference must be wrapped manually like this:
-\end_layout
-
-\begin_layout Standard
-\begin_inset listings
-inline false
-status open
-
-\begin_layout Plain Layout
-
-local f = Ref( File() )
-\end_layout
-
-\begin_layout Plain Layout
-
-local err = f.open("hello.txt",File.READ)
-\end_layout
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Standard
-Anything not a reference that inherits from Object can be freed manually
- by calling .free(), just like in GDScript.
- Object classes are in itself weak references to engine objects, and their
- validity can be checked by calling the
-\begin_inset Quotes eld
-\end_inset
-
-has_instance()
-\begin_inset Quotes erd
-\end_inset
-
- built-in method.
-\end_layout
-
-\begin_layout Section
-Unicode
-\end_layout
-
-\begin_layout Standard
-Squirrel source code is supposed to support Unicode, but the implementation
- is very broken (Squirrel attempts to use 16 bit chars no matter what, making
- it incompatible when the host OS is 32 bit, like Linux).
- Squirrel source code is parsed as UTF-8, and strings also contain UTF-8.
- Wide char access in strings is not supported.
-\end_layout
-
-\begin_layout Section
-Debugging
-\end_layout
-
-\begin_layout Standard
-Squirrel is well integrated into the Godot debugger.
- To run the project in debug mode, execute the godot binary with the -debug
- argument.
- Godot will break on squirrel errors and allow the programmer to debug.
-\end_layout
-
-\begin_layout Section
-Utility Functions
-\end_layout
-
-\begin_layout Standard
-There are a few squirrel-only utility functions available:
-\end_layout
-
-\begin_layout Subsection
-print(value[,value])
-\end_layout
-
-\begin_layout Standard
-Print stuff to stdout.
-\end_layout
-
-\begin_layout Subsection
-dofile(path)
-\end_layout
-
-\begin_layout Standard
-Execute a squirrel script file and return whatever the file returns.
- Not recommended to use in production because it can't be optimized.
-\end_layout
-
-\begin_layout Subsection
-nativeref(var)
-\end_layout
-
-\begin_layout Standard
-Convert any squirrel type to an engine type.
- When this type returns to squirrel, it's converted back.
- This is useful to add to Godot callbacks to ensure that the datatype is
- not converted.
-\end_layout
-
-\begin_layout Subsection
-unicode_split(string)
-\end_layout
-
-\begin_layout Standard
-Split an unicode string (utf8) into an array of widechars.
- Useful since there is no wide char access from Squirrel.
-\end_layout
-
-\begin_layout Subsection
-breakpoint()
-\end_layout
-
-\begin_layout Standard
-Stop the debugger when reaches here (when run inside the debugger).
-\end_layout
-
-\begin_layout Subsection
-backtrace()
-\end_layout
-
-\begin_layout Standard
-Print a backtrace of the call stack.
-\end_layout
-
-\begin_layout Subsection
-tr(text)
-\end_layout
-
-\begin_layout Standard
-Translate text (use string lookup in Godot translation system).
-\end_layout
-
-\begin_layout Subsection
-printerr(text)
-\end_layout
-
-\begin_layout Standard
-Print a string to stderr.
-\end_layout
-
-\end_body
-\end_document
diff --git a/doc/todo.txt b/doc/todo.txt
deleted file mode 100644
index 511b5dbbe2..0000000000
--- a/doc/todo.txt
+++ /dev/null
@@ -1,39 +0,0 @@
--Fisica 2D
- *terminar constraints
- *terminar queries
- *desactivar on suspend
- -bugs supongo?
-
--Fisica 3D
- -portar engine 2D a 3D mayoritariamente (si puedo esperar, mejor)
- -hacer que skeletons se vuelvan ragdolls de alguna forma
- -hacer bien lo de enganchar cosas a huesos de esqueleto
-
--GUI
- - Tree necesita resizear desde los headers
-
--Escena 3D
- -Deshabilitar 3D (Opcional en compilacion)
- -Particulas 3D
- -Heightmaps
- -Arreglar fixed pipeline
- -arreglar glow y ssao
-
--Editor codigo
- -Editor de codigo (esta, pero esta lleno de bugs)
- -Debugger (esta, pero hay que integrar bien)
-
--UI General
- -Cambiar lugar el tema de resources porque es MUY poco intuitivo
- -Tal vez arreglar un poquito el theme y la estetica (para release, low priority)
- -Run deberia correr la escena main
- -new script deberia dar opcion de crear en disco
- -los scripts de deberian mantener abiertos al abrir otra escena
- -
-
--Settings
- -Hacer pantalla de optimizacion general del proyecto
-
--A futuro:
- -Scripting Propio
- -Portar a DX9/GL3 \ No newline at end of file
diff --git a/doc/tools/doc_merge.py b/doc/tools/doc_merge.py
new file mode 100644
index 0000000000..6cc7019324
--- /dev/null
+++ b/doc/tools/doc_merge.py
@@ -0,0 +1,211 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+import sys
+import xml.etree.ElementTree as ET
+
+
+tree = ET.parse(sys.argv[1])
+old_doc=tree.getroot()
+
+tree = ET.parse(sys.argv[2])
+new_doc=tree.getroot()
+
+f = file(sys.argv[3],"wb")
+tab=0
+
+old_classes={}
+
+def write_string(_f, text,newline=True):
+ for t in range(tab):
+ _f.write("\t")
+ _f.write(text)
+ if (newline):
+ _f.write("\n")
+
+def escape(ret):
+ ret=ret.replace("&","&amp;");
+ ret=ret.replace("<","&gt;");
+ ret=ret.replace(">","&lt;");
+ ret=ret.replace("'","&apos;");
+ ret=ret.replace("\"","&quot;");
+ return ret
+
+
+def inc_tab():
+ global tab
+ tab+=1
+
+def dec_tab():
+ global tab
+ tab-=1
+
+write_string(f,'<?xml version="1.0" encoding="UTF-8" ?>')
+write_string(f,'<doc version="'+new_doc.attrib["version"]+'">')
+
+def get_tag(node,name):
+ tag=""
+ if (name in node.attrib):
+ tag=' '+name+'="'+escape(node.attrib[name])+'" '
+ return tag
+
+def find_method_descr(old_class,name):
+
+ methods = old_class.find("methods")
+ if(methods!=None and len(list(methods))>0):
+ for m in list(methods):
+ if (m.attrib["name"]==name):
+ description=m.find("description")
+ if (description!=None and description.text.strip()!=""):
+ return description.text
+
+ return None
+
+def find_signal_descr(old_class,name):
+
+ signals = old_class.find("signals")
+ if(signals!=None and len(list(signals))>0):
+ for m in list(signals):
+ if (m.attrib["name"]==name):
+ description=m.find("description")
+ if (description!=None and description.text.strip()!=""):
+ return description.text
+
+ return None
+
+def find_constant_descr(old_class,name):
+
+ if (old_class==None):
+ return None
+ constants = old_class.find("constants")
+ if(constants!=None and len(list(constants))>0):
+ for m in list(constants):
+ if (m.attrib["name"]==name):
+ if (m.text.strip()!=""):
+ return m.text
+ return None
+
+def write_class(c):
+ class_name = c.attrib["name"]
+ print("Parsing Class: "+class_name)
+ if (class_name in old_classes):
+ old_class=old_classes[class_name]
+ else:
+ old_class=None
+
+
+ category=get_tag(c,"category")
+ inherits=get_tag(c,"inherits")
+ write_string(f,'<class name="'+class_name+'" '+category+inherits+'>')
+ inc_tab()
+
+ write_string(f,"<brief_description>")
+
+ if (old_class!=None):
+ old_brief_descr=old_class.find("brief_description")
+ if (old_brief_descr!=None):
+ write_string(f,escape(old_brief_descr.text.strip()))
+
+
+ write_string(f,"</brief_description>")
+
+ write_string(f,"<description>")
+ if (old_class!=None):
+ old_descr=old_class.find("description")
+ if (old_descr!=None):
+ write_string(f,escape(old_descr.text.strip()))
+
+ write_string(f,"</description>")
+
+ methods = c.find("methods")
+ if(methods!=None and len(list(methods))>0):
+
+ write_string(f,"<methods>")
+ inc_tab()
+
+ for m in list(methods):
+ qualifiers=get_tag(m,"qualifiers")
+
+ write_string(f,'<method name="'+escape(m.attrib["name"])+'" ' +qualifiers+'>')
+ inc_tab()
+
+ for a in list(m):
+ if (a.tag=="return"):
+ typ=get_tag(a,"type")
+ write_string(f,'<return'+typ+'>');
+ write_string(f,'</return>');
+ elif (a.tag=="argument"):
+
+ default=get_tag(a,"default")
+
+ write_string(f,'<argument index="'+a.attrib["index"]+'" name="'+escape(a.attrib["name"])+'" type="'+a.attrib["type"]+'"' +default+'>');
+ write_string(f,'</argument>');
+
+ write_string(f,'<description>');
+ if (old_class!=None):
+ old_method_descr=find_method_descr(old_class,m.attrib["name"])
+ if (old_method_descr):
+ write_string(f,escape(escape(old_method_descr.strip())))
+
+ write_string(f,'</description>');
+ dec_tab()
+ write_string(f,"</method>")
+ dec_tab()
+ write_string(f,"</methods>")
+
+ signals = c.find("signals")
+ if(signals!=None and len(list(signals))>0):
+
+ write_string(f,"<signals>")
+ inc_tab()
+
+ for m in list(signals):
+
+ write_string(f,'<signal name="'+escape(m.attrib["name"])+'">')
+ inc_tab()
+
+ for a in list(m):
+ if (a.tag=="argument"):
+
+ write_string(f,'<argument index="'+a.attrib["index"]+'" name="'+escape(a.attrib["name"])+'" type="'+a.attrib["type"]+'">');
+ write_string(f,'</argument>');
+
+ write_string(f,'<description>');
+ if (old_class!=None):
+ old_signal_descr=find_signal_descr(old_class,m.attrib["name"])
+ if (old_signal_descr):
+ write_string(f,escape(old_signal_descr.strip()))
+ write_string(f,'</description>');
+ dec_tab()
+ write_string(f,"</signal>")
+ dec_tab()
+ write_string(f,"</signals>")
+
+ constants = c.find("constants")
+ if(constants!=None and len(list(constants))>0):
+
+ write_string(f,"<constants>")
+ inc_tab()
+
+ for m in list(constants):
+
+ write_string(f,'<constant name="'+escape(m.attrib["name"])+'" value="'+m.attrib["value"]+'">')
+ old_constant_descr=find_constant_descr(old_class,m.attrib["name"])
+ if (old_constant_descr):
+ write_string(f,escape(old_constant_descr.strip()))
+ write_string(f,"</constant>")
+
+ dec_tab()
+ write_string(f,"</constants>")
+
+ dec_tab()
+ write_string(f,"</class>")
+
+for c in list(old_doc):
+ old_classes[c.attrib["name"]]=c
+
+for c in list(new_doc):
+ write_class(c)
+write_string(f,'</doc>\n')
+
+
diff --git a/doc/tools/locales/es/LC_MESSAGES/makedocs.mo b/doc/tools/locales/es/LC_MESSAGES/makedocs.mo
new file mode 100644
index 0000000000..8d7ea2689e
--- /dev/null
+++ b/doc/tools/locales/es/LC_MESSAGES/makedocs.mo
Binary files differ
diff --git a/doc/tools/locales/es/LC_MESSAGES/makedocs.po b/doc/tools/locales/es/LC_MESSAGES/makedocs.po
new file mode 100644
index 0000000000..82115dd897
--- /dev/null
+++ b/doc/tools/locales/es/LC_MESSAGES/makedocs.po
@@ -0,0 +1,142 @@
+# Translations template for PROJECT.
+# Copyright (C) 2015 ORGANIZATION
+# This file is distributed under the same license as the PROJECT project.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2015.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: makedocs\n"
+"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
+"POT-Creation-Date: 2015-10-07 11:47-0600\n"
+"PO-Revision-Date: 2015-10-07 13:10-0600\n"
+"Last-Translator: Jorge Araya Navarro <elcorreo@deshackra.com>\n"
+"Language-Team: \n"
+"Language: es\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 2.0\n"
+"X-Generator: Poedit 1.8.4\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+#: makedocs.py:74
+msgid ""
+"\"<code>{gclass}</code>(Go to page of class {gclass})\":/class_{lkclass}"
+msgstr ""
+"\"<code>{gclass}</code>(Ir a la pagina de la clase {gclass})\":/"
+"class_{lkclass}"
+
+#: makedocs.py:76
+msgid ""
+"\"<code>{gclass}.{method}</code>(Go to page {gclass}, section {method})\":/"
+"class_{lkclass}#{lkmethod}"
+msgstr ""
+"\"<code>{gclass}.{method}</code>(Ir a la pagina {gclass}, sección "
+"{method})\":/class_{lkclass}#{lkmethod}"
+
+#: makedocs.py:79
+msgid "\"<code>{method}</code>(Jump to method {method})\":#{lkmethod}"
+msgstr "\"<code>{method}</code>(Saltar al método {method})\":#{lkmethod}"
+
+#: makedocs.py:81
+msgid " \"{rtype}(Go to page of class {rtype})\":/class_{link} "
+msgstr " \"{rtype}(Ir a la pagina de la clase {rtype})\":/class_{link} "
+
+#: makedocs.py:82
+msgid ""
+"\"*{funcname}*(Jump to description for node {funcname})\":#{link} <b>(</b> "
+msgstr ""
+"\"*{funcname}*(Saltar a la descripción para el nodo {funcname})\":#{link} "
+"<b>(</b> "
+
+#: makedocs.py:87
+msgid "h4. Inherits: "
+msgstr "h4. Hereda de: "
+
+#: makedocs.py:232
+msgid "<doc>'s version attribute missing"
+msgstr "El atributo version de <doc> no existe"
+
+#: makedocs.py:246
+msgid "|_. Index symbol |_. Class name |_. Index symbol |_. Class name |\n"
+msgstr ""
+"|_. Índice de símbolo |_. Nombre de la clase |_. Índice de símbolo |_. "
+"Nombre de la clase |\n"
+
+#: makedocs.py:305
+msgid ""
+"h4. Category: {}\n"
+"\n"
+msgstr ""
+"h4. Categoría: {}\n"
+"\n"
+
+#: makedocs.py:310
+msgid ""
+"h2. Brief Description\n"
+"\n"
+msgstr ""
+"h2. Descripción breve\n"
+"\n"
+
+#: makedocs.py:312
+msgid ""
+"\"read more\":#more\n"
+"\n"
+msgstr ""
+"\"Leer más\":#more\n"
+"\n"
+
+#: makedocs.py:317
+msgid ""
+"\n"
+"h3. Member Functions\n"
+"\n"
+msgstr ""
+"\n"
+"h3. Funciones miembro\n"
+"\n"
+
+#: makedocs.py:323
+msgid ""
+"\n"
+"h3. Signals\n"
+"\n"
+msgstr ""
+"\n"
+"h3. Señales\n"
+"\n"
+
+#: makedocs.py:331
+msgid ""
+"\n"
+"h3. Numeric Constants\n"
+"\n"
+msgstr ""
+"\n"
+"h3. Constantes numéricas\n"
+"\n"
+
+#: makedocs.py:347
+msgid ""
+"\n"
+"h3(#more). Description\n"
+"\n"
+msgstr ""
+"\n"
+"h3(#more). Descripción\n"
+"\n"
+
+#: makedocs.py:351
+msgid "_Nothing here, yet..._\n"
+msgstr "_Aún nada por aquí..._\n"
+
+#: makedocs.py:355
+msgid ""
+"\n"
+"h3. Member Function Description\n"
+"\n"
+msgstr ""
+"\n"
+"h3. Descripción de las funciones miembro\n"
+"\n"
diff --git a/doc/html/main.css b/doc/tools/main.css
index a76e6bbed8..a76e6bbed8 100644
--- a/doc/html/main.css
+++ b/doc/tools/main.css
diff --git a/doc/tools/makedocs.pot b/doc/tools/makedocs.pot
new file mode 100644
index 0000000000..be3220f686
--- /dev/null
+++ b/doc/tools/makedocs.pot
@@ -0,0 +1,108 @@
+# Translations template for PROJECT.
+# Copyright (C) 2015 ORGANIZATION
+# This file is distributed under the same license as the PROJECT project.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2015.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: makedocs 0.1\n"
+"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
+"POT-Creation-Date: 2015-10-07 11:47-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 2.0\n"
+"X-Generator: Poedit 1.8.4\n"
+
+#: makedocs.py:74
+msgid "\"<code>{gclass}</code>(Go to page of class {gclass})\":/class_{lkclass}"
+msgstr ""
+
+#: makedocs.py:76
+msgid "\"<code>{gclass}.{method}</code>(Go to page {gclass}, section {method})\":/class_{lkclass}#{lkmethod}"
+msgstr ""
+
+#: makedocs.py:79
+msgid "\"<code>{method}</code>(Jump to method {method})\":#{lkmethod}"
+msgstr ""
+
+#: makedocs.py:81
+msgid " \"{rtype}(Go to page of class {rtype})\":/class_{link} "
+msgstr ""
+
+#: makedocs.py:82
+msgid "\"*{funcname}*(Jump to description for node {funcname})\":#{link} <b>(</b> "
+msgstr ""
+
+#: makedocs.py:87
+msgid "h4. Inherits: "
+msgstr ""
+
+#: makedocs.py:232
+msgid "<doc>'s version attribute missing"
+msgstr ""
+
+#: makedocs.py:246
+msgid "|_. Index symbol |_. Class name |_. Index symbol |_. Class name |\n"
+msgstr ""
+
+#: makedocs.py:305
+msgid ""
+"h4. Category: {}\n"
+"\n"
+msgstr ""
+
+#: makedocs.py:310
+msgid ""
+"h2. Brief Description\n"
+"\n"
+msgstr ""
+
+#: makedocs.py:312
+msgid ""
+"\"read more\":#more\n"
+"\n"
+msgstr ""
+
+#: makedocs.py:317
+msgid ""
+"\n"
+"h3. Member Functions\n"
+"\n"
+msgstr ""
+
+#: makedocs.py:323
+msgid ""
+"\n"
+"h3. Signals\n"
+"\n"
+msgstr ""
+
+#: makedocs.py:331
+msgid ""
+"\n"
+"h3. Numeric Constants\n"
+"\n"
+msgstr ""
+
+#: makedocs.py:347
+msgid ""
+"\n"
+"h3(#more). Description\n"
+"\n"
+msgstr ""
+
+#: makedocs.py:351
+msgid "_Nothing here, yet..._\n"
+msgstr ""
+
+#: makedocs.py:355
+msgid ""
+"\n"
+"h3. Member Function Description\n"
+"\n"
+msgstr ""
diff --git a/doc/tools/makedocs.py b/doc/tools/makedocs.py
new file mode 100644
index 0000000000..063ee29002
--- /dev/null
+++ b/doc/tools/makedocs.py
@@ -0,0 +1,382 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+#
+# makedocs.py: Generate documentation for Open Project Wiki
+# Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur.
+# Contributor: Jorge Araya Navarro <elcorreo@deshackra.com>
+#
+
+# IMPORTANT NOTICE:
+# If you are going to modify anything from this file, please be sure to follow
+# the Style Guide for Python Code or often called "PEP8". To do this
+# automagically just install autopep8:
+#
+# $ sudo pip3 install autopep8
+#
+# and run:
+#
+# $ autopep8 makedocs.py
+#
+# Before committing your changes. Also be sure to delete any trailing
+# whitespace you may left.
+#
+# TODO:
+# * Refactor code.
+# * Adapt this script for generating content in other markup formats like
+# reStructuredText, Markdown, DokuWiki, etc.
+#
+# Also check other TODO entries in this script for more information on what is
+# left to do.
+import argparse
+import gettext
+import logging
+import re
+from itertools import zip_longest
+from os import path, listdir
+from xml.etree import ElementTree
+
+
+# add an option to change the verbosity
+logging.basicConfig(level=logging.INFO)
+
+
+def getxmlfloc():
+ """ Returns the supposed location of the XML file
+ """
+ filepath = path.dirname(path.abspath(__file__))
+ return path.join(filepath, "class_list.xml")
+
+
+def langavailable():
+ """ Return a list of languages available for translation
+ """
+ filepath = path.join(
+ path.dirname(path.abspath(__file__)), "locales")
+ files = listdir(filepath)
+ choices = [x for x in files]
+ choices.insert(0, "none")
+ return choices
+
+
+desc = "Generates documentation from a XML file to different markup languages"
+
+parser = argparse.ArgumentParser(description=desc)
+parser.add_argument("--input", dest="xmlfp", default=getxmlfloc(),
+ help="Input XML file, default: {}".format(getxmlfloc()))
+parser.add_argument("--output-dir", dest="outputdir", required=True,
+ help="Output directory for generated files")
+parser.add_argument("--language", choices=langavailable(), default="none",
+ help=("Choose the language of translation"
+ " for the output files. Default is English (none). "
+ "Note: This is NOT for the documentation itself!"))
+# TODO: add an option for outputting different markup formats
+
+args = parser.parse_args()
+# Let's check if the file and output directory exists
+if not path.isfile(args.xmlfp):
+ logging.critical("File not found: {}".format(args.xmlfp))
+ exit(1)
+elif not path.isdir(args.outputdir):
+ logging.critical("Path does not exist: {}".format(args.outputdir))
+ exit(1)
+
+_ = gettext.gettext
+if args.language != "none":
+ lang = gettext.translation(domain="makedocs",
+ localedir="locales",
+ languages=[args.language])
+ lang.install()
+
+ _ = lang.gettext
+
+# Strings
+C_LINK = _("\"<code>{gclass}</code>(Go to page of class"
+ " {gclass})\":/class_{lkclass}")
+MC_LINK = _("\"<code>{gclass}.{method}</code>(Go "
+ "to page {gclass}, section {method})\""
+ ":/class_{lkclass}#{lkmethod}")
+TM_JUMP = _("\"<code>{method}</code>(Jump to method"
+ " {method})\":#{lkmethod}")
+GTC_LINK = _(" \"{rtype}(Go to page of class {rtype})\":/class_{link} ")
+DFN_JUMP = _("\"*{funcname}*(Jump to description for"
+ " node {funcname})\":#{link} <b>(</b> ")
+M_ARG_DEFAULT = C_LINK + " {name}={default}"
+M_ARG = C_LINK + " {name}"
+
+OPENPROJ_INH = _("h4. Inherits: ") + C_LINK + "\n\n"
+
+
+def tb(string):
+ """ Return a byte representation of a string
+ """
+ return bytes(string, "UTF-8")
+
+
+def sortkey(c):
+ """ Symbols are first, letters second
+ """
+ if "_" == c.attrib["name"][0]:
+ return "A"
+ else:
+ return c.attrib["name"]
+
+
+def toOP(text):
+ """ Convert commands in text to Open Project commands
+ """
+ # TODO: Make this capture content between [command] ... [/command]
+ groups = re.finditer((r'\[html (?P<command>/?\w+/?)(\]| |=)?(\]| |=)?(?P<a'
+ 'rg>\w+)?(\]| |=)?(?P<value>"[^"]+")?/?\]'), text)
+ alignstr = ""
+ for group in groups:
+ gd = group.groupdict()
+ if gd["command"] == "br/":
+ text = text.replace(group.group(0), "\n\n", 1)
+ elif gd["command"] == "div":
+ if gd["value"] == '"center"':
+ alignstr = ("{display:block; margin-left:auto;"
+ " margin-right:auto;}")
+ elif gd["value"] == '"left"':
+ alignstr = "<"
+ elif gd["value"] == '"right"':
+ alignstr = ">"
+ text = text.replace(group.group(0), "\n\n", 1)
+ elif gd["command"] == "/div":
+ alignstr = ""
+ text = text.replace(group.group(0), "\n\n", 1)
+ elif gd["command"] == "img":
+ text = text.replace(group.group(0), "!{align}{src}!".format(
+ align=alignstr, src=gd["value"].strip('"')), 1)
+ elif gd["command"] == "b" or gd["command"] == "/b":
+ text = text.replace(group.group(0), "*", 1)
+ elif gd["command"] == "i" or gd["command"] == "/i":
+ text = text.replace(group.group(0), "_", 1)
+ elif gd["command"] == "u" or gd["command"] == "/u":
+ text = text.replace(group.group(0), "+", 1)
+ # Process other non-html commands
+ groups = re.finditer((r'\[method ((?P<class>[aA0-zZ9_]+)(?:\.))'
+ r'?(?P<method>[aA0-zZ9_]+)\]'), text)
+ for group in groups:
+ gd = group.groupdict()
+ if gd["class"]:
+ replacewith = (MC_LINK.format(gclass=gd["class"],
+ method=gd["method"],
+ lkclass=gd["class"].lower(),
+ lkmethod=gd["method"].lower()))
+ else:
+ # The method is located in the same wiki page
+ replacewith = (TM_JUMP.format(method=gd["method"],
+ lkmethod=gd["method"].lower()))
+
+ text = text.replace(group.group(0), replacewith, 1)
+ # Finally, [Classes] are around brackets, make them direct links
+ groups = re.finditer(r'\[(?P<class>[az0-AZ0_]+)\]', text)
+ for group in groups:
+ gd = group.groupdict()
+ replacewith = (C_LINK.
+ format(gclass=gd["class"],
+ lkclass=gd["class"].lower()))
+ text = text.replace(group.group(0), replacewith, 1)
+
+ return text + "\n\n"
+
+
+def mkfn(node, is_signal=False):
+ """ Return a string containing a unsorted item for a function
+ """
+ finalstr = ""
+ name = node.attrib["name"]
+ rtype = node.find("return")
+ if rtype:
+ rtype = rtype.attrib["type"]
+ else:
+ rtype = "void"
+ # write the return type and the function name first
+ finalstr += "* "
+ # return type
+ if not is_signal:
+ if rtype != "void":
+ finalstr += GTC_LINK.format(
+ rtype=rtype,
+ link=rtype.lower())
+ else:
+ finalstr += " void "
+
+ # function name
+ if not is_signal:
+ finalstr += DFN_JUMP.format(
+ funcname=name,
+ link=name.lower())
+ else:
+ # Signals have no description
+ finalstr += "*{funcname}* <b>(</b>".format(funcname=name)
+ # loop for the arguments of the function, if any
+ args = []
+ for arg in sorted(
+ node.iter(tag="argument"),
+ key=lambda a: int(a.attrib["index"])):
+
+ ntype = arg.attrib["type"]
+ nname = arg.attrib["name"]
+
+ if "default" in arg.attrib:
+ args.insert(-1, M_ARG_DEFAULT.format(
+ gclass=ntype,
+ lkclass=ntype.lower(),
+ name=nname,
+ default=arg.attrib["default"]))
+ else:
+ # No default value present
+ args.insert(-1, M_ARG.format(gclass=ntype,
+ lkclass=ntype.lower(), name=nname))
+ # join the arguments together
+ finalstr += ", ".join(args)
+ # and, close the function with a )
+ finalstr += " <b>)</b>"
+ # write the qualifier, if any
+ if "qualifiers" in node.attrib:
+ qualifier = node.attrib["qualifiers"]
+ finalstr += " " + qualifier
+
+ finalstr += "\n"
+
+ return finalstr
+
+# Let's begin
+tree = ElementTree.parse(args.xmlfp)
+root = tree.getroot()
+
+# Check version attribute exists in <doc>
+if "version" not in root.attrib:
+ logging.critical(_("<doc>'s version attribute missing"))
+ exit(1)
+
+version = root.attrib["version"]
+classes = sorted(root, key=sortkey)
+# first column is always longer, second column of classes should be shorter
+zclasses = zip_longest(classes[:int(len(classes) / 2 + 1)],
+ classes[int(len(classes) / 2 + 1):],
+ fillvalue="")
+
+# We write the class_list file and also each class file at once
+with open(path.join(args.outputdir, "class_list.txt"), "wb") as fcl:
+ # Write header of table
+ fcl.write(tb("|^.\n"))
+ fcl.write(tb(_("|_. Index symbol |_. Class name "
+ "|_. Index symbol |_. Class name |\n")))
+ fcl.write(tb("|-.\n"))
+
+ indexletterl = ""
+ indexletterr = ""
+ for gdclassl, gdclassr in zclasses:
+ # write a row #
+ # write the index symbol column, left
+ if indexletterl != gdclassl.attrib["name"][0]:
+ indexletterl = gdclassl.attrib["name"][0]
+ fcl.write(tb("| *{}* |".format(indexletterl.upper())))
+ else:
+ # empty cell
+ fcl.write(tb("| |"))
+ # write the class name column, left
+ fcl.write(tb(C_LINK.format(
+ gclass=gdclassl.attrib["name"],
+ lkclass=gdclassl.attrib["name"].lower())))
+
+ # write the index symbol column, right
+ if isinstance(gdclassr, ElementTree.Element):
+ if indexletterr != gdclassr.attrib["name"][0]:
+ indexletterr = gdclassr.attrib["name"][0]
+ fcl.write(tb("| *{}* |".format(indexletterr.upper())))
+ else:
+ # empty cell
+ fcl.write(tb("| |"))
+ # We are dealing with an empty string
+ else:
+ # two empty cell
+ fcl.write(tb("| | |\n"))
+ # We won't get the name of the class since there is no ElementTree
+ # object for the right side of the tuple, so we iterate the next
+ # tuple instead
+ continue
+
+ # write the class name column (if any), right
+ fcl.write(tb(C_LINK.format(
+ gclass=gdclassl.attrib["name"],
+ lkclass=gdclassl.attrib["name"].lower()) + "|\n"))
+
+ # row written #
+ # now, let's write each class page for each class
+ for gdclass in [gdclassl, gdclassr]:
+ if not isinstance(gdclass, ElementTree.Element):
+ continue
+
+ classname = gdclass.attrib["name"]
+ with open(path.join(args.outputdir, "{}.txt".format(
+ classname.lower())), "wb") as clsf:
+ # First level header with the name of the class
+ clsf.write(tb("h1. {}\n\n".format(classname)))
+ # lay the attributes
+ if "inherits" in gdclass.attrib:
+ inh = gdclass.attrib["inherits"].strip()
+ clsf.write(tb(OPENPROJ_INH.format(gclass=inh,
+ lkclass=inh.lower())))
+ if "category" in gdclass.attrib:
+ clsf.write(tb(_("h4. Category: {}\n\n").
+ format(gdclass.attrib["category"].strip())))
+ # lay child nodes
+ briefd = gdclass.find("brief_description")
+ if briefd.text.strip():
+ clsf.write(tb(_("h2. Brief Description\n\n")))
+ clsf.write(tb(toOP(briefd.text.strip()) +
+ _("\"read more\":#more\n\n")))
+
+ # Write the list of member functions of this class
+ methods = gdclass.find("methods")
+ if methods and len(methods) > 0:
+ clsf.write(tb(_("\nh3. Member Functions\n\n")))
+ for method in methods.iter(tag='method'):
+ clsf.write(tb(mkfn(method)))
+
+ signals = gdclass.find("signals")
+ if signals and len(signals) > 0:
+ clsf.write(tb(_("\nh3. Signals\n\n")))
+ for signal in signals.iter(tag='signal'):
+ clsf.write(tb(mkfn(signal, True)))
+ # TODO: <members> tag is necessary to process? it does not
+ # exists in class_list.xml file.
+
+ consts = gdclass.find("constants")
+ if consts and len(consts) > 0:
+ clsf.write(tb(_("\nh3. Numeric Constants\n\n")))
+ for const in sorted(consts, key=lambda k:
+ k.attrib["name"]):
+ if const.text.strip():
+ clsf.write(tb("* *{name}* = *{value}* - {desc}\n".
+ format(
+ name=const.attrib["name"],
+ value=const.attrib["value"],
+ desc=const.text.strip())))
+ else:
+ # Constant have no description
+ clsf.write(tb("* *{name}* = *{value}*\n".
+ format(
+ name=const.attrib["name"],
+ value=const.attrib["value"])))
+ descrip = gdclass.find("description")
+ clsf.write(tb(_("\nh3(#more). Description\n\n")))
+ if descrip.text:
+ clsf.write(tb(descrip.text.strip() + "\n"))
+ else:
+ clsf.write(tb(_("_Nothing here, yet..._\n")))
+
+ # and finally, the description for each method
+ if methods and len(methods) > 0:
+ clsf.write(tb(_("\nh3. Member Function Description\n\n")))
+ for method in methods.iter(tag='method'):
+ clsf.write(tb("h4(#{n}). {name}\n\n".format(
+ n=method.attrib["name"].lower(),
+ name=method.attrib["name"])))
+ clsf.write(tb(mkfn(method) + "\n"))
+ clsf.write(tb(toOP(method.find(
+ "description").text.strip())))
diff --git a/doc/tools/makedoku.py b/doc/tools/makedoku.py
new file mode 100644
index 0000000000..1ab16841b1
--- /dev/null
+++ b/doc/tools/makedoku.py
@@ -0,0 +1,514 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+import sys
+import xml.etree.ElementTree as ET
+
+input_list = []
+
+
+for arg in sys.argv[1:]:
+ input_list.append(arg)
+
+if len(input_list) < 1:
+ print("usage: makedoku.py <classes.xml>")
+ sys.exit(0)
+
+
+def validate_tag(elem,tag):
+ if (elem.tag != tag):
+ print("Tag mismatch, expected '"+tag+"', got "+elem.tag);
+ sys.exit(255)
+
+
+class_names=[]
+classes={}
+
+
+def make_class_list(class_list,columns):
+
+ f=open("class_list.txt","wb")
+ prev=0
+ col_max = len(class_list) / columns + 1
+ print("col max is ", col_max)
+ col_count = 0
+ row_count = 0
+ last_initial = ""
+ fit_columns=[]
+
+ for n in range(0,columns):
+ fit_columns+=[[]]
+
+ indexers=[]
+ last_initial=""
+
+ idx=0
+ for n in class_list:
+ col = idx/col_max
+ if (col>=columns):
+ col=columns-1
+ fit_columns[col]+=[n]
+ idx+=1
+ if (n[:1]!=last_initial):
+ indexers+=[n]
+ last_initial=n[:1]
+
+
+ row_max=0
+
+ for n in range(0,columns):
+ if (len(fit_columns[n])>row_max):
+ row_max=len(fit_columns[n])
+
+
+ for r in range(0,row_max):
+ s="|"
+ for c in range(0,columns):
+ if (r>=len(fit_columns[c])):
+ continue
+
+ classname = fit_columns[c][r]
+ initial=classname[0]
+ if (classname in indexers):
+ s+="**"+initial+"**|"
+ else:
+ s+=" |"
+
+ s+="[["+classname.lower()+"|"+classname+"]]|"
+
+ s+="\n"
+ f.write(s)
+
+
+def dokuize_text(txt):
+
+ return txt
+
+
+def dokuize_text(text):
+ pos=0
+ while(True):
+ pos = text.find("[",pos)
+ if (pos==-1):
+ break
+
+ endq_pos=text.find("]",pos+1)
+ if (endq_pos==-1):
+ break
+
+ pre_text=text[:pos]
+ post_text=text[endq_pos+1:]
+ tag_text=text[pos+1:endq_pos]
+
+ if (tag_text in class_names):
+ tag_text="[["+tag_text.lower()+"|"+tag_text+"]]"
+ else: #command
+ cmd=tag_text
+ space_pos=tag_text.find(" ")
+ if (cmd.find("html")==0):
+ cmd=tag_text[:space_pos]
+ param=tag_text[space_pos+1:]
+ tag_text="<"+param+">"
+ elif(cmd.find("method")==0):
+ cmd=tag_text[:space_pos]
+ param=tag_text[space_pos+1:]
+
+ if (param.find(".")!=-1):
+ class_param,method_param=param.split(".")
+ tag_text="[["+class_param.lower()+"#"+method_param+"|"+class_param+'.'+method_param+"]]"
+ else:
+ tag_text="[[#"+param+"|"+param+"]]"
+ elif (cmd.find("image=")==0):
+ tag_text="{{"+cmd[6:]+"}}"
+ elif (cmd.find("url=")==0):
+ tag_text="[["+cmd[4:]+"|"
+ elif (cmd=="/url"):
+ tag_text="]]>"
+ elif (cmd=="center"):
+ tag_text=""
+ elif (cmd=="/center"):
+ tag_text=""
+ elif (cmd=="br"):
+ tag_text="\\\\\n"
+ elif (cmd=="i" or cmd=="/i"):
+ tag_text="//"
+ elif (cmd=="b" or cmd=="/b"):
+ tag_text="**"
+ elif (cmd=="u" or cmd=="/u"):
+ tag_text="__"
+ else:
+ tag_text="["+tag_text+"]"
+
+
+ text=pre_text+tag_text+post_text
+ pos=len(pre_text)+len(tag_text)
+
+ #tnode = ET.SubElement(parent,"div")
+ #tnode.text=text
+ return text
+
+
+def make_type(t):
+ global class_names
+ if (t in class_names):
+ return "[["+t.lower()+"|"+t+"]]"
+ return t
+
+
+def make_method(f,name,m,declare,event=False):
+
+ s=" * "
+ ret_type="void"
+ args=list(m)
+ mdata={}
+ mdata["argidx"]=[]
+ for a in args:
+ if (a.tag=="return"):
+ idx=-1
+ elif (a.tag=="argument"):
+ idx=int(a.attrib["index"])
+ else:
+ continue
+
+ mdata["argidx"].append(idx)
+ mdata[idx]=a
+
+
+
+ if (not event):
+ if (-1 in mdata["argidx"]):
+ s+=make_type(mdata[-1].attrib["type"])
+ else:
+ s+="void"
+ s+=" "
+
+ if (declare):
+
+ #span.attrib["class"]="funcdecl"
+ #a=ET.SubElement(span,"a")
+ #a.attrib["name"]=name+"_"+m.attrib["name"]
+ #a.text=name+"::"+m.attrib["name"]
+ s+="**"+m.attrib["name"]+"**"
+ else:
+ s+="[[#"+m.attrib["name"]+"|"+m.attrib["name"]+"]]"
+
+ s+="**(**"
+ argfound=False
+ for a in mdata["argidx"]:
+ arg=mdata[a]
+ if (a<0):
+ continue
+ if (a>0):
+ s+=", "
+ else:
+ s+=" "
+
+ s+=make_type(arg.attrib["type"])
+ if ("name" in arg.attrib):
+ s+=" "+arg.attrib["name"]
+ else:
+ s+=" arg"+str(a)
+
+ if ("default" in arg.attrib):
+ s+="="+arg.attrib["default"]
+
+
+ argfound=True
+
+ if (argfound):
+ s+=" "
+ s+="**)**"
+
+ if ("qualifiers" in m.attrib):
+ s+=" "+m.attrib["qualifiers"]
+
+ f.write(s+"\n")
+
+
+def make_doku_class(node):
+
+ name = node.attrib["name"]
+
+ f=open(name.lower()+".txt","wb")
+
+ f.write("====== "+name+" ======\n")
+
+ if ("inherits" in node.attrib):
+ inh=node.attrib["inherits"].strip()
+ f.write("**Inherits:** [["+inh.lower()+"|"+inh+"]]\\\\\n")
+ if ("category" in node.attrib):
+ f.write("**Category:** "+node.attrib["category"].strip()+"\\\\\n")
+
+ briefd = node.find("brief_description")
+ if (briefd!=None):
+ f.write("===== Brief Description ======\n")
+ f.write( dokuize_text(briefd.text.strip())+"\n" )
+
+ methods = node.find("methods")
+
+ if(methods!=None and len(list(methods))>0):
+ f.write("===== Member Functions ======\n")
+ for m in list(methods):
+ make_method(f,node.attrib["name"],m,False)
+
+ events = node.find("signals")
+ if(events!=None and len(list(events))>0):
+ f.write("===== Signals ======\n")
+ for m in list(events):
+ make_method(f,node.attrib["name"],m,True,True)
+
+ members = node.find("members")
+
+ if(members!=None and len(list(members))>0):
+ f.write("===== Member Variables ======\n")
+
+ for c in list(members):
+ s = " * "
+ s+=make_type(c.attrib["type"])+" "
+ s+="**"+c.attrib["name"]+"**"
+ if (c.text.strip()!=""):
+ s+=" - "+c.text.strip()
+ f.write(s+"\n")
+
+
+
+ constants = node.find("constants")
+ if(constants!=None and len(list(constants))>0):
+ f.write("===== Numeric Constants ======\n")
+ for c in list(constants):
+ s = " * "
+ s+="**"+c.attrib["name"]+"**"
+ if ("value" in c.attrib):
+ s+=" = **"+c.attrib["value"]+"**"
+ if (c.text.strip()!=""):
+ s+=" - "+c.text.strip()
+ f.write(s+"\n")
+
+
+ descr=node.find("description")
+ if (descr!=None and descr.text.strip()!=""):
+ f.write("===== Description ======\n")
+ f.write(dokuize_text(descr.text.strip())+"\n")
+
+ methods = node.find("methods")
+
+ if(methods!=None and len(list(methods))>0):
+ f.write("===== Member Function Description ======\n")
+ for m in list(methods):
+
+ d=m.find("description")
+ if (d==None or d.text.strip()==""):
+ continue
+ f.write("== "+m.attrib["name"]+" ==\n")
+ make_method(f,node.attrib["name"],m,False)
+ f.write("\\\\\n")
+ f.write(dokuize_text(d.text.strip()))
+ f.write("\n")
+
+
+
+
+
+ """
+ div=ET.Element("div")
+ div.attrib["class"]="class";
+
+ a=ET.SubElement(div,"a")
+ a.attrib["name"]=node.attrib["name"]
+
+ h3=ET.SubElement(a,"h3")
+ h3.attrib["class"]="title class_title"
+ h3.text=node.attrib["name"]
+
+ briefd = node.find("brief_description")
+ if (briefd!=None):
+ div2=ET.SubElement(div,"div")
+ div2.attrib["class"]="description class_description"
+ div2.text=briefd.text
+
+ if ("inherits" in node.attrib):
+ ET.SubElement(div,"br")
+
+ div2=ET.SubElement(div,"div")
+ div2.attrib["class"]="inheritance";
+
+ span=ET.SubElement(div2,"span")
+ span.text="Inherits: "
+
+ make_type(node.attrib["inherits"],div2)
+
+ if ("category" in node.attrib):
+ ET.SubElement(div,"br")
+
+ div3=ET.SubElement(div,"div")
+ div3.attrib["class"]="category";
+
+ span=ET.SubElement(div3,"span")
+ span.attrib["class"]="category"
+ span.text="Category: "
+
+ a = ET.SubElement(div3,"a")
+ a.attrib["class"]="category_ref"
+ a.text=node.attrib["category"]
+ catname=a.text
+ if (catname.rfind("/")!=-1):
+ catname=catname[catname.rfind("/"):]
+ catname="CATEGORY_"+catname
+
+ if (single_page):
+ a.attrib["href"]="#"+catname
+ else:
+ a.attrib["href"]="category.html#"+catname
+
+
+ methods = node.find("methods")
+
+ if(methods!=None and len(list(methods))>0):
+
+ h4=ET.SubElement(div,"h4")
+ h4.text="Public Methods:"
+
+ method_table=ET.SubElement(div,"table")
+ method_table.attrib["class"]="method_list";
+
+ for m in list(methods):
+# li = ET.SubElement(div2, "li")
+ method_table.append( make_method_def(node.attrib["name"],m,False) )
+
+ events = node.find("signals")
+
+ if(events!=None and len(list(events))>0):
+ h4=ET.SubElement(div,"h4")
+ h4.text="Events:"
+
+ event_table=ET.SubElement(div,"table")
+ event_table.attrib["class"]="method_list";
+
+ for m in list(events):
+# li = ET.SubElement(div2, "li")
+ event_table.append( make_method_def(node.attrib["name"],m,False,True) )
+
+
+ members = node.find("members")
+ if(members!=None and len(list(members))>0):
+
+ h4=ET.SubElement(div,"h4")
+ h4.text="Public Variables:"
+ div2=ET.SubElement(div,"div")
+ div2.attrib["class"]="member_list";
+
+ for c in list(members):
+
+ li = ET.SubElement(div2, "li")
+ div3=ET.SubElement(li,"div")
+ div3.attrib["class"]="member";
+ make_type(c.attrib["type"],div3)
+ span=ET.SubElement(div3,"span")
+ span.attrib["class"]="identifier member_name"
+ span.text=" "+c.attrib["name"]+" "
+ span=ET.SubElement(div3,"span")
+ span.attrib["class"]="member_description"
+ span.text=c.text
+
+
+ constants = node.find("constants")
+ if(constants!=None and len(list(constants))>0):
+
+ h4=ET.SubElement(div,"h4")
+ h4.text="Constants:"
+ div2=ET.SubElement(div,"div")
+ div2.attrib["class"]="constant_list";
+
+ for c in list(constants):
+ li = ET.SubElement(div2, "li")
+ div3=ET.SubElement(li,"div")
+ div3.attrib["class"]="constant";
+
+ span=ET.SubElement(div3,"span")
+ span.attrib["class"]="identifier constant_name"
+ span.text=c.attrib["name"]+" "
+ if ("value" in c.attrib):
+ span=ET.SubElement(div3,"span")
+ span.attrib["class"]="symbol"
+ span.text="= "
+ span=ET.SubElement(div3,"span")
+ span.attrib["class"]="constant_value"
+ span.text=c.attrib["value"]+" "
+ span=ET.SubElement(div3,"span")
+ span.attrib["class"]="constant_description"
+ span.text=c.text
+
+# ET.SubElement(div,"br")
+
+
+ descr=node.find("description")
+ if (descr!=None and descr.text.strip()!=""):
+
+ h4=ET.SubElement(div,"h4")
+ h4.text="Description:"
+
+ make_text_def(node.attrib["name"],div,descr.text)
+# div2=ET.SubElement(div,"div")
+# div2.attrib["class"]="description";
+# div2.text=descr.text
+
+
+
+ if(methods!=None or events!=None):
+
+ h4=ET.SubElement(div,"h4")
+ h4.text="Method Documentation:"
+ iter_list = []
+ if (methods!=None):
+ iter_list+=list(methods)
+ if (events!=None):
+ iter_list+=list(events)
+
+ for m in iter_list:
+
+ descr=m.find("description")
+
+ if (descr==None or descr.text.strip()==""):
+ continue;
+
+ div2=ET.SubElement(div,"div")
+ div2.attrib["class"]="method_doc";
+
+
+ div2.append( make_method_def(node.attrib["name"],m,True) )
+ #anchor = ET.SubElement(div2, "a")
+ #anchor.attrib["name"] =
+ make_text_def(node.attrib["name"],div2,descr.text)
+ #div3=ET.SubElement(div2,"div")
+ #div3.attrib["class"]="description";
+ #div3.text=descr.text
+
+
+ return div
+"""
+for file in input_list:
+ tree = ET.parse(file)
+ doc=tree.getroot()
+
+ if ("version" not in doc.attrib):
+ print("Version missing from 'doc'")
+ sys.exit(255)
+
+ version=doc.attrib["version"]
+
+ for c in list(doc):
+ if (c.attrib["name"] in class_names):
+ continue
+ class_names.append(c.attrib["name"])
+ classes[c.attrib["name"]]=c
+
+
+class_names.sort()
+
+make_class_list(class_names,4)
+
+for cn in class_names:
+ c=classes[cn]
+ make_doku_class(c)
+
+
diff --git a/doc/tools/makehtml.py b/doc/tools/makehtml.py
new file mode 100644
index 0000000000..34db47e424
--- /dev/null
+++ b/doc/tools/makehtml.py
@@ -0,0 +1,720 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+import sys
+import xml.etree.ElementTree as ET
+from xml.sax.saxutils import escape, unescape
+
+html_escape_table = {
+ '"': "&quot;",
+ "'": "&apos;"
+}
+
+html_unescape_table = {v:k for k, v in html_escape_table.items()}
+
+def html_escape(text):
+ return escape(text, html_escape_table)
+
+def html_unescape(text):
+ return unescape(text, html_unescape_table)
+
+input_list = []
+
+single_page=True
+
+for arg in sys.argv[1:]:
+ if arg[:1] == "-":
+ if arg[1:] == "multipage":
+ single_page = False
+ if arg[1:] == "singlepage":
+ single_page = True
+ else:
+ input_list.append(arg)
+
+if len(input_list) < 1:
+ print("usage: makehtml.py <classes.xml>")
+ sys.exit(0)
+
+
+def validate_tag(elem,tag):
+ if (elem.tag != tag):
+ print("Tag mismatch, expected '"+tag+"', got "+elem.tag);
+ sys.exit(255)
+
+def make_html_bottom(body):
+ #make_html_top(body,True)
+ ET.SubElement(body,"hr")
+ copyright = ET.SubElement(body,"span")
+ copyright.text = "Copyright 2008-2010 Codenix SRL"
+
+def make_html_top(body,bottom=False):
+
+ if (bottom):
+ ET.SubElement(body,"hr")
+
+ table = ET.SubElement(body,"table")
+ table.attrib["class"]="top_table"
+ tr = ET.SubElement(table,"tr")
+ td = ET.SubElement(tr,"td")
+ td.attrib["class"]="top_table"
+
+ img = ET.SubElement(td,"image")
+ img.attrib["src"]="images/logo.png"
+ td = ET.SubElement(tr,"td")
+ td.attrib["class"]="top_table"
+ a = ET.SubElement(td,"a")
+ a.attrib["href"]="index.html"
+ a.text="Index"
+ td = ET.SubElement(tr,"td")
+ td.attrib["class"]="top_table"
+ a = ET.SubElement(td,"a")
+ a.attrib["href"]="alphabetical.html"
+ a.text="Classes"
+ td = ET.SubElement(tr,"td")
+ td.attrib["class"]="top_table"
+ a = ET.SubElement(td,"a")
+ a.attrib["href"]="category.html"
+ a.text="Categories"
+ td = ET.SubElement(tr,"td")
+ a = ET.SubElement(td,"a")
+ a.attrib["href"]="inheritance.html"
+ a.text="Inheritance"
+ if (not bottom):
+ ET.SubElement(body,"hr")
+
+
+
+
+def make_html_class_list(class_list,columns):
+
+ div=ET.Element("div")
+ div.attrib["class"]="ClassList";
+
+ h1=ET.SubElement(div,"h2")
+ h1.text="Alphabetical Class List"
+
+ table=ET.SubElement(div,"table")
+ table.attrib["class"]="class_table"
+ table.attrib["width"]="100%"
+ prev=0
+
+ col_max = len(class_list) / columns + 1
+ print("col max is ", col_max)
+ col_count = 0
+ row_count = 0
+ last_initial = ""
+ fit_columns=[]
+
+ for n in range(0,columns):
+ fit_columns+=[[]]
+
+ indexers=[]
+ last_initial=""
+
+ idx=0
+ for n in class_list:
+ col = int(idx/col_max)
+ if (col>=columns):
+ col=columns-1
+ fit_columns[col]+=[n]
+ idx+=1
+ if (n[:1]!=last_initial):
+ indexers+=[n]
+ last_initial=n[:1]
+
+ row_max=0
+
+ for n in range(0,columns):
+ if (len(fit_columns[n])>row_max):
+ row_max=len(fit_columns[n])
+
+
+ for r in range(0,row_max):
+ tr = ET.SubElement(table,"tr")
+ for c in range(0,columns):
+ tdi = ET.SubElement(tr,"td")
+ tdi.attrib["align"]="right"
+ td = ET.SubElement(tr,"td")
+ if (r>=len(fit_columns[c])):
+ continue
+
+ classname = fit_columns[c][r]
+ print(classname)
+ if (classname in indexers):
+
+ span = ET.SubElement(tdi, "span")
+ span.attrib["class"] = "class_index_letter"
+ span.text = classname[:1].upper()
+
+ if (single_page):
+ link="#"+classname
+ else:
+ link=classname+".html"
+
+ a=ET.SubElement(td,"a")
+ a.attrib["href"]=link
+ a.text=classname
+
+
+ if (not single_page):
+ cat_class_list=ET.Element("html")
+ csscc = ET.SubElement(cat_class_list, "link")
+ csscc.attrib["href"] = "main.css"
+ csscc.attrib["rel"] = "stylesheet"
+ csscc.attrib["type"] = "text/css"
+ bodycc = ET.SubElement(cat_class_list, "body")
+ make_html_top(bodycc)
+
+ cat_class_parent=bodycc
+ else:
+ cat_class_parent=div
+
+
+
+
+ h1=ET.SubElement(cat_class_parent,"h2")
+ h1.text="Class List By Category"
+
+ class_cat_table={}
+ class_cat_list=[]
+
+ for c in class_list:
+ clss = classes[c]
+ if ("category" in clss.attrib):
+ class_cat=clss.attrib["category"]
+ else:
+ class_cat="Core"
+ if (class_cat.find("/")!=-1):
+ class_cat=class_cat[class_cat.rfind("/")+1:]
+ if (not class_cat in class_cat_list):
+ class_cat_list.append(class_cat)
+ class_cat_table[class_cat]=[]
+ class_cat_table[class_cat].append(c)
+
+ class_cat_list.sort()
+
+ ct = ET.SubElement(cat_class_parent,"table")
+ for cl in class_cat_list:
+ l = class_cat_table[cl]
+ l.sort()
+ tr = ET.SubElement(ct,"tr")
+ tr.attrib["class"]="category_title"
+ td = ET.SubElement(ct,"td")
+ td.attrib["class"]="category_title"
+
+ a = ET.SubElement(td,"a")
+ a.attrib["class"]="category_title"
+ a.text=cl
+ a.attrib["name"]="CATEGORY_"+cl
+
+ td = ET.SubElement(ct,"td")
+ td.attrib["class"]="category_title"
+
+ for clt in l:
+ tr = ET.SubElement(ct,"tr")
+ td = ET.SubElement(ct,"td")
+ make_type(clt,td)
+ clss=classes[clt]
+ bd = clss.find("brief_description")
+ bdtext=""
+ if (bd!=None):
+ bdtext=bd.text
+ td = ET.SubElement(ct,"td")
+ td.text=bdtext
+
+ if (not single_page):
+ make_html_bottom(bodycc)
+ catet_out = ET.ElementTree(cat_class_list)
+ catet_out.write("category.html")
+
+
+ if (not single_page):
+ inh_class_list=ET.Element("html")
+ cssic = ET.SubElement(inh_class_list, "link")
+ cssic.attrib["href"] = "main.css"
+ cssic.attrib["rel"] = "stylesheet"
+ cssic.attrib["type"] = "text/css"
+ bodyic = ET.SubElement(inh_class_list, "body")
+ make_html_top(bodyic)
+ inh_class_parent=bodyic
+ else:
+ inh_class_parent=div
+
+
+
+
+ h1=ET.SubElement(inh_class_parent,"h2")
+ h1.text="Class List By Inheritance"
+
+ itemlist = ET.SubElement(inh_class_parent,"list")
+
+ class_inh_table={}
+
+ def add_class(clss):
+ if (clss.attrib["name"] in class_inh_table):
+ return #already added
+ parent_list=None
+
+ if ("inherits" in clss.attrib):
+ inhc = clss.attrib["inherits"]
+ if (not (inhc in class_inh_table)):
+ add_class(classes[inhc])
+
+ parent_list = class_inh_table[inhc].find("div")
+ if (parent_list == None):
+ parent_div = ET.SubElement(class_inh_table[inhc],"div")
+ parent_list = ET.SubElement(parent_div,"list")
+ parent_div.attrib["class"]="inh_class_list"
+ else:
+ parent_list = parent_list.find("list")
+
+
+ else:
+ parent_list=itemlist
+
+ item = ET.SubElement(parent_list,"li")
+# item.attrib["class"]="inh_class_list"
+ class_inh_table[clss.attrib["name"]]=item
+ make_type(clss.attrib["name"],item)
+
+
+ for c in class_list:
+ add_class(classes[c])
+
+ if (not single_page):
+ make_html_bottom(bodyic)
+ catet_out = ET.ElementTree(inh_class_list)
+ catet_out.write("inheritance.html")
+
+
+
+
+
+ #h1=ET.SubElement(div,"h2")
+ #h1.text="Class List By Inheritance"
+
+ return div
+
+
+def make_type(p_type,p_parent):
+ if (p_type=="RefPtr"):
+ p_type="Resource"
+
+ if (p_type in class_names):
+ a=ET.SubElement(p_parent,"a")
+ a.attrib["class"]="datatype_existing"
+ a.text=p_type+" "
+ if (single_page):
+ a.attrib["href"]="#"+p_type
+ else:
+ a.attrib["href"]=p_type+".html"
+ else:
+ span=ET.SubElement(p_parent,"span")
+ span.attrib["class"]="datatype"
+ span.text=p_type+" "
+
+
+
+def make_text_def(class_name,parent,text):
+ text = html_escape(text)
+ pos=0
+ while(True):
+ pos = text.find("[",pos)
+ if (pos==-1):
+ break
+
+ endq_pos=text.find("]",pos+1)
+ if (endq_pos==-1):
+ break
+
+ pre_text=text[:pos]
+ post_text=text[endq_pos+1:]
+ tag_text=text[pos+1:endq_pos]
+
+ if (tag_text in class_names):
+ if (single_page):
+ tag_text='<a href="#'+tag_text+'">'+tag_text+'</a>'
+ else:
+ tag_text='<a href="'+tag_text+'.html">'+tag_text+'</a>'
+ else: #command
+ cmd=tag_text
+ space_pos=tag_text.find(" ")
+ if (cmd.find("html")==0):
+ cmd=tag_text[:space_pos]
+ param=tag_text[space_pos+1:]
+ tag_text="<"+param+">"
+ elif(cmd.find("method")==0):
+ cmd=tag_text[:space_pos]
+ param=tag_text[space_pos+1:]
+
+ if (not single_page and param.find(".")!=-1):
+ class_param,method_param=param.split(".")
+ tag_text=tag_text='<a href="'+class_param+'.html#'+class_param+"_"+method_param+'">'+class_param+'.'+method_param+'()</a>'
+ else:
+ tag_text=tag_text='<a href="#'+class_name+"_"+param+'">'+class_name+'.'+param+'()</a>'
+ elif (cmd.find("image=")==0):
+ print("found image: "+cmd)
+ tag_text="<img src="+cmd[6:]+"/>"
+ elif (cmd.find("url=")==0):
+ tag_text="<a href="+cmd[4:]+">"
+ elif (cmd=="/url"):
+ tag_text="</a>"
+ elif (cmd=="center"):
+ tag_text="<div align=\"center\">"
+ elif (cmd=="/center"):
+ tag_text="</div>"
+ elif (cmd=="br"):
+ tag_text="<br/>"
+ elif (cmd=="i" or cmd=="/i" or cmd=="b" or cmd=="/b" or cmd=="u" or cmd=="/u"):
+ tag_text="<"+tag_text+">" #html direct mapping
+ else:
+ tag_text="["+tag_text+"]"
+
+
+ text=pre_text+tag_text+post_text
+ pos=len(pre_text)+len(tag_text)
+
+ #tnode = ET.SubElement(parent,"div")
+ #tnode.text=text
+ text="<div class=\"description\">"+text+"</div>"
+ try:
+ tnode=ET.XML(text)
+ parent.append(tnode)
+ except:
+ print("Error parsing description text: '"+text+"'")
+ sys.exit(255)
+
+
+ return tnode
+
+
+
+
+def make_method_def(name,m,declare,event=False):
+
+ mdata={}
+
+
+ if (not declare):
+ div=ET.Element("tr")
+ div.attrib["class"]="method"
+ ret_parent=ET.SubElement(div,"td")
+ ret_parent.attrib["align"]="right"
+ func_parent=ET.SubElement(div,"td")
+ else:
+ div=ET.Element("div")
+ div.attrib["class"]="method"
+ ret_parent=div
+ func_parent=div
+
+ mdata["argidx"]=[]
+ mdata["name"]=m.attrib["name"]
+ qualifiers=""
+ if ("qualifiers" in m.attrib):
+ qualifiers=m.attrib["qualifiers"]
+
+ args=list(m)
+ for a in args:
+ if (a.tag=="return"):
+ idx=-1
+ elif (a.tag=="argument"):
+ idx=int(a.attrib["index"])
+ else:
+ continue
+
+ mdata["argidx"].append(idx)
+ mdata[idx]=a
+
+ if (not event):
+ if (-1 in mdata["argidx"]):
+ make_type(mdata[-1].attrib["type"],ret_parent)
+ mdata["argidx"].remove(-1)
+ else:
+ make_type("void",ret_parent)
+
+ span=ET.SubElement(func_parent,"span")
+ if (declare):
+ span.attrib["class"]="funcdecl"
+ a=ET.SubElement(span,"a")
+ a.attrib["name"]=name+"_"+m.attrib["name"]
+ a.text=name+"::"+m.attrib["name"]
+ else:
+ span.attrib["class"]="identifier funcdef"
+ a=ET.SubElement(span,"a")
+ a.attrib["href"]="#"+name+"_"+m.attrib["name"]
+ a.text=m.attrib["name"]
+
+ span=ET.SubElement(func_parent,"span")
+ span.attrib["class"]="symbol"
+ span.text=" ("
+
+ for a in mdata["argidx"]:
+ arg=mdata[a]
+ if (a>0):
+ span=ET.SubElement(func_parent,"span")
+ span.text=", "
+ else:
+ span=ET.SubElement(func_parent,"span")
+ span.text=" "
+
+
+ make_type(arg.attrib["type"],func_parent)
+
+ span=ET.SubElement(func_parent,"span")
+ span.text=arg.attrib["name"]
+ if ("default" in arg.attrib):
+ span.text=span.text+"="+arg.attrib["default"]
+
+
+ span=ET.SubElement(func_parent,"span")
+ span.attrib["class"]="symbol"
+ if (len(mdata["argidx"])):
+ span.text=" )"
+ else:
+ span.text=")"
+
+ if (qualifiers):
+ span=ET.SubElement(func_parent,"span")
+ span.attrib["class"]="qualifier"
+ span.text=" "+qualifiers
+
+ return div
+
+
+def make_html_class(node):
+
+ div=ET.Element("div")
+ div.attrib["class"]="class";
+
+ a=ET.SubElement(div,"a")
+ a.attrib["name"]=node.attrib["name"]
+
+ h3=ET.SubElement(a,"h3")
+ h3.attrib["class"]="title class_title"
+ h3.text=node.attrib["name"]
+
+ briefd = node.find("brief_description")
+ if (briefd!=None):
+ div2=ET.SubElement(div,"div")
+ div2.attrib["class"]="description class_description"
+ div2.text=briefd.text
+
+ if ("inherits" in node.attrib):
+ ET.SubElement(div,"br")
+
+ div2=ET.SubElement(div,"div")
+ div2.attrib["class"]="inheritance";
+
+ span=ET.SubElement(div2,"span")
+ span.text="Inherits: "
+
+ make_type(node.attrib["inherits"],div2)
+
+ if ("category" in node.attrib):
+ ET.SubElement(div,"br")
+
+ div3=ET.SubElement(div,"div")
+ div3.attrib["class"]="category";
+
+ span=ET.SubElement(div3,"span")
+ span.attrib["class"]="category"
+ span.text="Category: "
+
+ a = ET.SubElement(div3,"a")
+ a.attrib["class"]="category_ref"
+ a.text=node.attrib["category"]
+ catname=a.text
+ if (catname.rfind("/")!=-1):
+ catname=catname[catname.rfind("/"):]
+ catname="CATEGORY_"+catname
+
+ if (single_page):
+ a.attrib["href"]="#"+catname
+ else:
+ a.attrib["href"]="category.html#"+catname
+
+
+ methods = node.find("methods")
+
+ if(methods!=None and len(list(methods))>0):
+
+ h4=ET.SubElement(div,"h4")
+ h4.text="Public Methods:"
+
+ method_table=ET.SubElement(div,"table")
+ method_table.attrib["class"]="method_list";
+
+ for m in list(methods):
+# li = ET.SubElement(div2, "li")
+ method_table.append( make_method_def(node.attrib["name"],m,False) )
+
+ events = node.find("signals")
+
+ if(events!=None and len(list(events))>0):
+ h4=ET.SubElement(div,"h4")
+ h4.text="Events:"
+
+ event_table=ET.SubElement(div,"table")
+ event_table.attrib["class"]="method_list";
+
+ for m in list(events):
+# li = ET.SubElement(div2, "li")
+ event_table.append( make_method_def(node.attrib["name"],m,False,True) )
+
+
+ members = node.find("members")
+ if(members!=None and len(list(members))>0):
+
+ h4=ET.SubElement(div,"h4")
+ h4.text="Public Variables:"
+ div2=ET.SubElement(div,"div")
+ div2.attrib["class"]="member_list";
+
+ for c in list(members):
+
+ li = ET.SubElement(div2, "li")
+ div3=ET.SubElement(li,"div")
+ div3.attrib["class"]="member";
+ make_type(c.attrib["type"],div3)
+ span=ET.SubElement(div3,"span")
+ span.attrib["class"]="identifier member_name"
+ span.text=" "+c.attrib["name"]+" "
+ span=ET.SubElement(div3,"span")
+ span.attrib["class"]="member_description"
+ span.text=c.text
+
+
+ constants = node.find("constants")
+ if(constants!=None and len(list(constants))>0):
+
+ h4=ET.SubElement(div,"h4")
+ h4.text="Constants:"
+ div2=ET.SubElement(div,"div")
+ div2.attrib["class"]="constant_list";
+
+ for c in list(constants):
+ li = ET.SubElement(div2, "li")
+ div3=ET.SubElement(li,"div")
+ div3.attrib["class"]="constant";
+
+ span=ET.SubElement(div3,"span")
+ span.attrib["class"]="identifier constant_name"
+ span.text=c.attrib["name"]+" "
+ if ("value" in c.attrib):
+ span=ET.SubElement(div3,"span")
+ span.attrib["class"]="symbol"
+ span.text="= "
+ span=ET.SubElement(div3,"span")
+ span.attrib["class"]="constant_value"
+ span.text=c.attrib["value"]+" "
+ span=ET.SubElement(div3,"span")
+ span.attrib["class"]="constant_description"
+ span.text=c.text
+
+# ET.SubElement(div,"br")
+
+
+ descr=node.find("description")
+ if (descr!=None and descr.text.strip()!=""):
+ h4=ET.SubElement(div,"h4")
+ h4.text="Description:"
+
+ make_text_def(node.attrib["name"],div,descr.text)
+# div2=ET.SubElement(div,"div")
+# div2.attrib["class"]="description";
+# div2.text=descr.text
+
+
+
+ if(methods!=None or events!=None):
+
+ h4=ET.SubElement(div,"h4")
+ h4.text="Method Documentation:"
+ iter_list = []
+ if (methods!=None):
+ iter_list+=list(methods)
+ if (events!=None):
+ iter_list+=list(events)
+
+ for m in iter_list:
+
+ descr=m.find("description")
+
+ if (descr==None or descr.text.strip()==""):
+ continue;
+
+ div2=ET.SubElement(div,"div")
+ div2.attrib["class"]="method_doc";
+
+
+ div2.append( make_method_def(node.attrib["name"],m,True) )
+ #anchor = ET.SubElement(div2, "a")
+ #anchor.attrib["name"] =
+ make_text_def(node.attrib["name"],div2,descr.text)
+ #div3=ET.SubElement(div2,"div")
+ #div3.attrib["class"]="description";
+ #div3.text=descr.text
+
+
+ return div
+
+class_names=[]
+classes={}
+
+for file in input_list:
+ tree = ET.parse(file)
+ doc=tree.getroot()
+
+ if ("version" not in doc.attrib):
+ print("Version missing from 'doc'")
+ sys.exit(255)
+
+ version=doc.attrib["version"]
+
+ for c in list(doc):
+ if (c.attrib["name"] in class_names):
+ continue
+ class_names.append(c.attrib["name"])
+ classes[c.attrib["name"]]=c
+
+html = ET.Element("html")
+css = ET.SubElement(html, "link")
+css.attrib["href"] = "main.css"
+css.attrib["rel"] = "stylesheet"
+css.attrib["type"] = "text/css"
+
+body = ET.SubElement(html, "body")
+if (not single_page):
+ make_html_top(body)
+
+
+
+class_names.sort()
+
+body.append( make_html_class_list(class_names,5) )
+
+for cn in class_names:
+ c=classes[cn]
+ if (single_page):
+ body.append( make_html_class(c))
+ else:
+ html2 = ET.Element("html")
+ css = ET.SubElement(html2, "link")
+ css.attrib["href"] = "main.css"
+ css.attrib["rel"] = "stylesheet"
+ css.attrib["type"] = "text/css"
+ body2 = ET.SubElement(html2, "body" )
+ make_html_top(body2)
+ body2.append( make_html_class(c) );
+ make_html_bottom(body2)
+ et_out = ET.ElementTree(html2)
+ et_out.write(c.attrib["name"]+".html")
+
+
+et_out = ET.ElementTree(html)
+if (single_page):
+ et_out.write("singlepage.html")
+else:
+ make_html_bottom(body)
+ et_out.write("alphabetical.html")
+
diff --git a/doc/tools/makemd.py b/doc/tools/makemd.py
new file mode 100644
index 0000000000..e012287b0e
--- /dev/null
+++ b/doc/tools/makemd.py
@@ -0,0 +1,346 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+import sys
+import xml.etree.ElementTree as ET
+
+input_list = []
+
+for arg in sys.argv[1:]:
+ input_list.append(arg)
+
+if len(input_list) < 1:
+ print 'usage: makemd.py <classes.xml>'
+ sys.exit(0)
+
+
+def validate_tag(elem, tag):
+ if elem.tag != tag:
+ print "Tag mismatch, expected '" + tag + "', got " + elem.tag
+ sys.exit(255)
+
+
+class_names = []
+classes = {}
+
+
+def make_class_list(class_list, columns):
+
+ f = open('class_list.md', 'wb')
+ prev = 0
+ col_max = len(class_list) / columns + 1
+ print ('col max is ', col_max)
+ col_count = 0
+ row_count = 0
+ last_initial = ''
+ fit_columns = []
+
+ for n in range(0, columns):
+ fit_columns += [[]]
+
+ indexers = []
+ last_initial = ''
+
+ idx = 0
+ for n in class_list:
+ col = idx / col_max
+ if col >= columns:
+ col = columns - 1
+ fit_columns[col] += [n]
+ idx += 1
+ if n[:1] != last_initial:
+ indexers += [n]
+ last_initial = n[:1]
+
+ row_max = 0
+ f.write("\n")
+
+ for n in range(0, columns):
+ if len(fit_columns[n]) > row_max:
+ row_max = len(fit_columns[n])
+
+ f.write("| ")
+ for n in range(0, columns):
+ f.write(" | |")
+
+ f.write("\n")
+ f.write("| ")
+ for n in range(0, columns):
+ f.write(" --- | ------- |")
+ f.write("\n")
+
+ for r in range(0, row_max):
+ s = '| '
+ for c in range(0, columns):
+ if r >= len(fit_columns[c]):
+ continue
+
+ classname = fit_columns[c][r]
+ initial = classname[0]
+ if classname in indexers:
+ s += '**' + initial + '** | '
+ else:
+ s += ' | '
+
+ s += '[' + classname + '](class_'+ classname.lower()+') | '
+
+ s += '\n'
+ f.write(s)
+
+
+def dokuize_text(txt):
+
+ return txt
+
+
+def dokuize_text(text):
+ pos = 0
+ while True:
+ pos = text.find('[', pos)
+ if pos == -1:
+ break
+
+ endq_pos = text.find(']', pos + 1)
+ if endq_pos == -1:
+ break
+
+ pre_text = text[:pos]
+ post_text = text[endq_pos + 1:]
+ tag_text = text[pos + 1:endq_pos]
+
+ if tag_text in class_names:
+ tag_text = make_type(tag_text)
+ else:
+
+ # command
+
+ cmd = tag_text
+ space_pos = tag_text.find(' ')
+ if cmd.find('html') == 0:
+ cmd = tag_text[:space_pos]
+ param = tag_text[space_pos + 1:]
+ tag_text = '<' + param + '>'
+ elif cmd.find('method') == 0:
+ cmd = tag_text[:space_pos]
+ param = tag_text[space_pos + 1:]
+
+ if param.find('.') != -1:
+ (class_param, method_param) = param.split('.')
+ tag_text = '['+class_param+'.'+method_param.replace("_","&#95;")+'](' + class_param.lower() + '#' \
+ + method_param + ')'
+ else:
+ tag_text = '[' + param.replace("_","&#95;") + '](#' + param + ')'
+ elif cmd.find('image=') == 0:
+ tag_text = '![](' + cmd[6:] + ')'
+ elif cmd.find('url=') == 0:
+ tag_text = '[' + cmd[4:] + ']('+cmd[4:]
+ elif cmd == '/url':
+ tag_text = ')'
+ elif cmd == 'center':
+ tag_text = ''
+ elif cmd == '/center':
+ tag_text = ''
+ elif cmd == 'br':
+ tag_text = '\n'
+ elif cmd == 'i' or cmd == '/i':
+ tag_text = '_'
+ elif cmd == 'b' or cmd == '/b':
+ tag_text = '**'
+ elif cmd == 'u' or cmd == '/u':
+ tag_text = '__'
+ else:
+ tag_text = '[' + tag_text + ']'
+
+ text = pre_text + tag_text + post_text
+ pos = len(pre_text) + len(tag_text)
+
+ # tnode = ET.SubElement(parent,"div")
+ # tnode.text=text
+
+ return text
+
+
+def make_type(t):
+ global class_names
+ if t in class_names:
+ return '[' + t + '](class_' + t.lower() + ')'
+ return t
+
+
+def make_method(
+ f,
+ name,
+ m,
+ declare,
+ event=False,
+ ):
+
+ s = ' * '
+ ret_type = 'void'
+ args = list(m)
+ mdata = {}
+ mdata['argidx'] = []
+ for a in args:
+ if a.tag == 'return':
+ idx = -1
+ elif a.tag == 'argument':
+ idx = int(a.attrib['index'])
+ else:
+ continue
+
+ mdata['argidx'].append(idx)
+ mdata[idx] = a
+
+ if not event:
+ if -1 in mdata['argidx']:
+ s += make_type(mdata[-1].attrib['type'])
+ else:
+ s += 'void'
+ s += ' '
+
+ if declare:
+
+ # span.attrib["class"]="funcdecl"
+ # a=ET.SubElement(span,"a")
+ # a.attrib["name"]=name+"_"+m.attrib["name"]
+ # a.text=name+"::"+m.attrib["name"]
+
+ s += ' **'+m.attrib['name'].replace("_","&#95;")+'** '
+ else:
+ s += ' **['+ m.attrib['name'].replace("_","&#95;")+'](#' + m.attrib['name'] + ')** '
+
+ s += ' **(**'
+ argfound = False
+ for a in mdata['argidx']:
+ arg = mdata[a]
+ if a < 0:
+ continue
+ if a > 0:
+ s += ', '
+ else:
+ s += ' '
+
+ s += make_type(arg.attrib['type'])
+ if 'name' in arg.attrib:
+ s += ' ' + arg.attrib['name']
+ else:
+ s += ' arg' + str(a)
+
+ if 'default' in arg.attrib:
+ s += '=' + arg.attrib['default']
+
+ argfound = True
+
+ if argfound:
+ s += ' '
+ s += ' **)**'
+
+ if 'qualifiers' in m.attrib:
+ s += ' ' + m.attrib['qualifiers']
+
+ f.write(s + '\n')
+
+
+def make_doku_class(node):
+
+ name = node.attrib['name']
+
+ f = open("class_"+name.lower() + '.md', 'wb')
+
+ f.write('# ' + name + ' \n')
+
+ if 'inherits' in node.attrib:
+ inh = node.attrib['inherits'].strip()
+ f.write('####**Inherits:** '+make_type(inh)+'\n')
+ if 'category' in node.attrib:
+ f.write('####**Category:** ' + node.attrib['category'].strip()
+ + '\n')
+
+ briefd = node.find('brief_description')
+ if briefd != None:
+ f.write('\n### Brief Description \n')
+ f.write(dokuize_text(briefd.text.strip()) + '\n')
+
+ methods = node.find('methods')
+
+ if methods != None and len(list(methods)) > 0:
+ f.write('\n### Member Functions \n')
+ for m in list(methods):
+ make_method(f, node.attrib['name'], m, False)
+
+ events = node.find('signals')
+ if events != None and len(list(events)) > 0:
+ f.write('\n### Signals \n')
+ for m in list(events):
+ make_method(f, node.attrib['name'], m, True, True)
+
+ members = node.find('members')
+
+ if members != None and len(list(members)) > 0:
+ f.write('\n### Member Variables \n')
+
+ for c in list(members):
+ s = ' * '
+ s += make_type(c.attrib['type']) + ' '
+ s += '**' + c.attrib['name'] + '**'
+ if c.text.strip() != '':
+ s += ' - ' + c.text.strip()
+ f.write(s + '\n')
+
+ constants = node.find('constants')
+ if constants != None and len(list(constants)) > 0:
+ f.write('\n### Numeric Constants \n')
+ for c in list(constants):
+ s = ' * '
+ s += '**' + c.attrib['name'] + '**'
+ if 'value' in c.attrib:
+ s += ' = **' + c.attrib['value'] + '**'
+ if c.text.strip() != '':
+ s += ' - ' + c.text.strip()
+ f.write(s + '\n')
+
+ descr = node.find('description')
+ if descr != None and descr.text.strip() != '':
+ f.write('\n### Description \n')
+ f.write(dokuize_text(descr.text.strip()) + '\n')
+
+ methods = node.find('methods')
+
+ if methods != None and len(list(methods)) > 0:
+ f.write('\n### Member Function Description \n')
+ for m in list(methods):
+
+ d = m.find('description')
+ if d == None or d.text.strip() == '':
+ continue
+ f.write('\n#### <a name="'+m.attrib['name']+'">' + m.attrib['name'] + '</a>\n')
+ make_method(f, node.attrib['name'], m, True)
+ f.write('\n')
+ f.write(dokuize_text(d.text.strip()))
+ f.write('\n')
+
+
+for file in input_list:
+ tree = ET.parse(file)
+ doc = tree.getroot()
+
+ if 'version' not in doc.attrib:
+ print "Version missing from 'doc'"
+ sys.exit(255)
+
+ version = doc.attrib['version']
+
+ for c in list(doc):
+ if c.attrib['name'] in class_names:
+ continue
+ class_names.append(c.attrib['name'])
+ classes[c.attrib['name']] = c
+
+class_names.sort()
+
+make_class_list(class_names, 2)
+
+for cn in class_names:
+ c = classes[cn]
+ make_doku_class(c)
+
diff --git a/doc/tutorial/01 Getting Started.lyx b/doc/tutorial/01 Getting Started.lyx
deleted file mode 100644
index bdb4c7706d..0000000000
--- a/doc/tutorial/01 Getting Started.lyx
+++ /dev/null
@@ -1,557 +0,0 @@
-#LyX 1.6.5 created this file. For more info see http://www.lyx.org/
-\lyxformat 345
-\begin_document
-\begin_header
-\textclass article
-\use_default_options true
-\language english
-\inputencoding auto
-\font_roman default
-\font_sans default
-\font_typewriter default
-\font_default_family default
-\font_sc false
-\font_osf false
-\font_sf_scale 100
-\font_tt_scale 100
-
-\graphics default
-\paperfontsize default
-\use_hyperref false
-\papersize default
-\use_geometry false
-\use_amsmath 1
-\use_esint 1
-\cite_engine basic
-\use_bibtopic false
-\paperorientation portrait
-\secnumdepth 3
-\tocdepth 3
-\paragraph_separation indent
-\defskip medskip
-\quotes_language english
-\papercolumns 1
-\papersides 1
-\paperpagestyle default
-\tracking_changes false
-\output_changes false
-\author ""
-\author ""
-\end_header
-
-\begin_body
-
-\begin_layout Title
-01.
- Getting Started with Godot Engine
-\end_layout
-
-\begin_layout Section*
-Introduction:
-\end_layout
-
-\begin_layout Standard
-Godot Engine is designed to be useful.
- This may sound rather vague and is difficult to explain without repeating
- the same claims that every other engine does, but, as we progress through
- this (and the next) tutorials, hopefully it will be made clear what
-\begin_inset Quotes eld
-\end_inset
-
-useful
-\begin_inset Quotes erd
-\end_inset
-
- means.
-\end_layout
-
-\begin_layout Standard
-Godot Engine has many components, both high and low level, and is usually
- more abstract and complex than most other engines.
- This is, however, to the advantage of the user as complexity is presented
- in a way that it only needs to be discovered when more power needs to be
- untapped.
- This helps to provide an easy learning curve.
-\end_layout
-
-\begin_layout Standard
-Design wise, the whole API and set of components were created with a clear
- goal in mind, which is to allow for smooth integration of design ideas,
- code and assets.
- This is achieved by defining the following rules:
-\end_layout
-
-\begin_layout Itemize
-Implementing a game feature should never be too many steps away from an
- existing component.
-\end_layout
-
-\begin_layout Itemize
-More complex features should be leveraged by combining or extending existing
- components.
-\end_layout
-
-\begin_layout Itemize
-If the above fails, creating custom components should be extremely simple.
-\end_layout
-
-\begin_layout Standard
-Ultimately, Godot Engine provides an editor and tools that allows everyone
- to work with it:
-\end_layout
-
-\begin_layout Itemize
-Programmers can script and extend any component of the project.
-\end_layout
-
-\begin_layout Itemize
-Designers can tweak and animate any parameter from a friendly user interface.
-\end_layout
-
-\begin_layout Itemize
-Artists can import their art and models and tweak the look of everything
- in realtime.
-\end_layout
-
-\begin_layout Section*
-Editor:
-\end_layout
-
-\begin_layout Standard
-As mentioned before, Godot Engine is very abstract so projects consist of
- just a
-\emph on
-path
-\emph default
- (ie: C:
-\backslash
-games
-\backslash
-mygame5).
- Projects don't have to be specifically created, and many can be placed
- inside the same path (useful for not wasting folders on tests and experiments).
-
-\end_layout
-
-\begin_layout Standard
-In any case, to ease the management of projects, a graphical util exists.
-\end_layout
-
-\begin_layout Subsection*
-Running From The Project Manager
-\end_layout
-
-\begin_layout Standard
-Godot Engine includes a built-in project manager.
- This is installed by default on Windows and OSX and it allows for the creation
- and removal projects that will be remembered at the next startup:
-\end_layout
-
-\begin_layout Standard
-\align center
-\begin_inset Graphics
- filename pm.png
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Standard
-To create a new project, the [Create] button must be pressed and a dialog
- will appear, prompting for a path and project name.
- Afterwards, the [Open] button will close the project manager and open the
- desired project.
-\end_layout
-
-\begin_layout Subsection*
-Running From the Command Line
-\end_layout
-
-\begin_layout Standard
-To create and manage projects, it is perfectly possible to use the command
- line.
- Many users prefer this way of working with project data.
-\end_layout
-
-\begin_layout Standard
-\align center
-\begin_inset Graphics
- filename pmc.png
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Standard
-For ease of use, it is recommended that the
-\begin_inset Quotes eld
-\end_inset
-
-godot
-\begin_inset Quotes erd
-\end_inset
-
- binary exists in the path, so any project can be opened easily aywhere
- just by changing location to the projec and executing the editor.
-\end_layout
-
-\begin_layout Subsection*
-Godot Editor
-\end_layout
-
-\begin_layout Standard
-Godot Editor should have been opened by now, if not please check the previous
- steps again.
-\end_layout
-
-\begin_layout Standard
-Godot has a powerful buit-in editor.
- It uses the graphics toolkint within itself to display the UI, so it runs
- identical on any platform (even consoles or phones!).
-\end_layout
-
-\begin_layout Standard
-\align center
-\begin_inset Graphics
- filename editor.png
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Standard
-In the above screenshots, a few regions are labelled to be explained as
- follows:
-\end_layout
-
-\begin_layout Subsubsection*
-Viewport
-\end_layout
-
-\begin_layout Standard
-The
-\emph on
-Viewport
-\emph default
- is the main space where the content is displayed.
- Content includes 3D Nodes or Graphical User Interface (GUI) controls.
- Other types of data spawn editors of their own when being edited.
- The default viewport is the 3D viewport, which can be panned, zoomed, etc.
-\end_layout
-
-\begin_layout Subsubsection*
-Scene Tree
-\end_layout
-
-\begin_layout Standard
-The
-\emph on
-Scene Tree
-\emph default
- is a small dock that displays the tree of the current scene being edited.
- A scene is a collection of nodes arranged in a tree-hierarchy (any node
- can have several owned children-nodes).
- The meaning of this ownership depends purely on the
-\emph on
-type
-\emph default
- of the node, but it will become clear after going through the examples.
- In a
-\emph on
-MVC
-\emph default
- pattern, the scene tree could be considered the
-\emph on
-View
-\emph default
-.
-\end_layout
-
-\begin_layout Subsubsection*
-Property Editor
-\end_layout
-
-\begin_layout Standard
-The
-\emph on
-Property Editor
-\emph default
- is another small dock.
- Every node contains a finite number of
-\emph on
-properties
-\emph default
-, which can be edited.
- Properties can be of several types, such as integers, strings, images,
- matrices, etc.
- Usually, changes to properties are reflected in the
-\emph on
-viewport
-\emph default
- in real time.
-\end_layout
-
-\begin_layout Section*
-Examples:
-\end_layout
-
-\begin_layout Standard
-From now, a few, simple examples will be presented that will help understand
- a little better how Godot Engine works.
-
-\end_layout
-
-\begin_layout Subsubsection*
-Hello, World!
-\end_layout
-
-\begin_layout Enumerate
-Open the editor
-\end_layout
-
-\begin_layout Enumerate
-Click on
-\begin_inset Quotes eld
-\end_inset
-
-Node
-\begin_inset Quotes erd
-\end_inset
-
- (Node Menu), then on
-\begin_inset Quotes eld
-\end_inset
-
-Create Root
-\begin_inset Quotes erd
-\end_inset
-
-
-\end_layout
-
-\begin_deeper
-\begin_layout Standard
-\align center
-\begin_inset Graphics
- filename tute1_1.png
-
-\end_inset
-
-
-\end_layout
-
-\end_deeper
-\begin_layout Enumerate
-Create a node of type
-\emph on
-Label,
-\emph default
-then instruct the
-\emph on
-editor
-\emph default
-to switch to GUI editing mode.
- A few red squares will appear on the top left corner, don't mind them yet.
-\end_layout
-
-\begin_deeper
-\begin_layout Standard
-\align center
-\begin_inset Graphics
- filename tute1_2.png
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Standard
-\align center
-\begin_inset Graphics
- filename tute1_2b.png
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Standard
-\align center
-\begin_inset Graphics
- filename tute1_3c.png
-
-\end_inset
-
-
-\end_layout
-
-\end_deeper
-\begin_layout Enumerate
-Select the
-\emph on
-Label
-\emph default
-node in the
-\emph on
-Scene Tree
-\emph default
- (if it's not selected yet), the properties of the selected node will appear
- in the
-\emph on
-Property Editor
-\end_layout
-
-\begin_deeper
-\begin_layout Standard
-\align center
-\begin_inset Graphics
- filename tute1_3a.png
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Standard
-\align center
-\begin_inset Graphics
- filename tute1_3b.png
-
-\end_inset
-
-
-\end_layout
-
-\end_deeper
-\begin_layout Enumerate
-Look for the
-\emph on
-Text
-\emph default
- property in the
-\emph on
-Property Editor
-\emph default
- and click the right column, so it becomes editable.
- Enter the text
-\begin_inset Quotes eld
-\end_inset
-
-Hello, World!
-\begin_inset Quotes erd
-\end_inset
-
-.
- A red square containing
-\begin_inset Quotes eld
-\end_inset
-
-Hello World!
-\begin_inset Quotes erd
-\end_inset
-
- will appear at the top left, move it to the center.
-\end_layout
-
-\begin_deeper
-\begin_layout Standard
-\align center
-\begin_inset Graphics
- filename tute1_4a.png
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Standard
-\align center
-\begin_inset Graphics
- filename tute1_4b.png
-
-\end_inset
-
-
-\end_layout
-
-\end_deeper
-\begin_layout Enumerate
-Save the scene.
-\end_layout
-
-\begin_deeper
-\begin_layout Standard
-\align center
-\begin_inset Graphics
- filename tute1_5a.png
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Standard
-\align center
-\begin_inset Graphics
- filename tute1_5b.png
-
-\end_inset
-
-
-\end_layout
-
-\end_deeper
-\begin_layout Enumerate
-Press PLAY.
- A new window will appear running the application.
-\end_layout
-
-\begin_deeper
-\begin_layout Standard
-\align center
-\begin_inset Graphics
- filename tute1_6.png
-
-\end_inset
-
-
-\end_layout
-
-\begin_layout Standard
-\align center
-\begin_inset Graphics
- filename tute1_7.png
-
-\end_inset
-
-
-\end_layout
-
-\end_deeper
-\begin_layout Subsubsection*
-Hello World 2 (a little more complex)
-\end_layout
-
-\begin_layout Subsubsection*
-A 3D Cube in Space
-\end_layout
-
-\begin_layout Standard
-
-\end_layout
-
-\begin_layout Standard
-In many cases, nodes and other types of engine objects need to express changes
- in their state, such as a button being pressed, a scroll being dragged,
- or a projectile colliding against a tank.
- Godot Engine utilizes the concept of signals for this.
- Different types of nodes and objects can emit signals, and any other node
- or object can connect to them.
-
-\end_layout
-
-\end_body
-\end_document
diff --git a/doc/tutorial/editor.png b/doc/tutorial/editor.png
deleted file mode 100644
index 92255a6f17..0000000000
--- a/doc/tutorial/editor.png
+++ /dev/null
Binary files differ
diff --git a/doc/tutorial/pm.png b/doc/tutorial/pm.png
deleted file mode 100644
index 00d46d9a64..0000000000
--- a/doc/tutorial/pm.png
+++ /dev/null
Binary files differ
diff --git a/doc/tutorial/pmc.png b/doc/tutorial/pmc.png
deleted file mode 100644
index 847d32b3a2..0000000000
--- a/doc/tutorial/pmc.png
+++ /dev/null
Binary files differ
diff --git a/doc/tutorial/tute1_1.png b/doc/tutorial/tute1_1.png
deleted file mode 100644
index 82152c7255..0000000000
--- a/doc/tutorial/tute1_1.png
+++ /dev/null
Binary files differ
diff --git a/doc/tutorial/tute1_2.png b/doc/tutorial/tute1_2.png
deleted file mode 100644
index 852015894c..0000000000
--- a/doc/tutorial/tute1_2.png
+++ /dev/null
Binary files differ
diff --git a/doc/tutorial/tute1_2b.png b/doc/tutorial/tute1_2b.png
deleted file mode 100644
index e97a40b4c5..0000000000
--- a/doc/tutorial/tute1_2b.png
+++ /dev/null
Binary files differ
diff --git a/doc/tutorial/tute1_3a.png b/doc/tutorial/tute1_3a.png
deleted file mode 100644
index 5feef01e03..0000000000
--- a/doc/tutorial/tute1_3a.png
+++ /dev/null
Binary files differ
diff --git a/doc/tutorial/tute1_3b.png b/doc/tutorial/tute1_3b.png
deleted file mode 100644
index 1f2ded42bb..0000000000
--- a/doc/tutorial/tute1_3b.png
+++ /dev/null
Binary files differ
diff --git a/doc/tutorial/tute1_3c.png b/doc/tutorial/tute1_3c.png
deleted file mode 100644
index 2c52ccd780..0000000000
--- a/doc/tutorial/tute1_3c.png
+++ /dev/null
Binary files differ
diff --git a/doc/tutorial/tute1_4a.png b/doc/tutorial/tute1_4a.png
deleted file mode 100644
index 8d0d04ff6b..0000000000
--- a/doc/tutorial/tute1_4a.png
+++ /dev/null
Binary files differ
diff --git a/doc/tutorial/tute1_4b.png b/doc/tutorial/tute1_4b.png
deleted file mode 100644
index fff5f8d723..0000000000
--- a/doc/tutorial/tute1_4b.png
+++ /dev/null
Binary files differ
diff --git a/doc/tutorial/tute1_5a.png b/doc/tutorial/tute1_5a.png
deleted file mode 100644
index 37bea04570..0000000000
--- a/doc/tutorial/tute1_5a.png
+++ /dev/null
Binary files differ
diff --git a/doc/tutorial/tute1_5b.png b/doc/tutorial/tute1_5b.png
deleted file mode 100644
index df9a987ef3..0000000000
--- a/doc/tutorial/tute1_5b.png
+++ /dev/null
Binary files differ
diff --git a/doc/tutorial/tute1_6.png b/doc/tutorial/tute1_6.png
deleted file mode 100644
index bbe04c8547..0000000000
--- a/doc/tutorial/tute1_6.png
+++ /dev/null
Binary files differ
diff --git a/doc/tutorial/tute1_7.png b/doc/tutorial/tute1_7.png
deleted file mode 100644
index 7653a89064..0000000000
--- a/doc/tutorial/tute1_7.png
+++ /dev/null
Binary files differ
diff --git a/doc/undoredoapi.txt b/doc/undoredoapi.txt
deleted file mode 100644
index eb73b8ccff..0000000000
--- a/doc/undoredoapi.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-undo/redo api proposal
-
-
-
-o o o o o o o o
-
-
-undoredo.create_method();
-undoredo.add_do_method(node,"add_child",node_to_add);
-undoredo.add_undo_method(node,"remove_child",node_to_add);
-undoredo.add_add_data(node_to_add);
-undoredo.commit()
-
-undoredo.create_method();
-undoredo.add_do_method(node,"remove_node",node_to_remove);
-undoredo.add_undo_method(node,"add_node",node_to_remove);
-undoredo.add_remove_data(node_to_remove);
-undoredo.commit()
-
-
-undoredo.create_property();
-undoredo.add_do_set(node,"property",value);
-undoredo.add_undo_set(node,"property",previous_value);
-undoredo.add_remove_data(node_to_remove);
-undoredo.commit()
diff --git a/drivers/SCsub b/drivers/SCsub
index 6ab0973625..a00d7fc3f9 100644
--- a/drivers/SCsub
+++ b/drivers/SCsub
@@ -12,11 +12,13 @@ SConscript('windows/SCsub');
SConscript('gles2/SCsub');
SConscript('gl_context/SCsub');
SConscript('openssl/SCsub');
+SConscript('pnm/SCsub');
if (env["png"]=="yes"):
SConscript("png/SCsub");
if (env["jpg"]=="yes"):
- SConscript("jpg/SCsub");
+ #SConscript("jpg/SCsub");
+ SConscript("jpegd/SCsub");
if (env["webp"]=="yes"):
SConscript("webp/SCsub");
SConscript("dds/SCsub");
@@ -29,18 +31,18 @@ if (env["openssl"]=="builtin"):
SConscript("rtaudio/SCsub");
SConscript("nedmalloc/SCsub");
-SConscript("trex/SCsub");
+SConscript("nrex/SCsub");
SConscript("chibi/SCsub");
-if (env["vorbis"]=="yes" or env["speex"]=="yes" or env["theora"]=="yes"):
+if (env["vorbis"]=="yes" or env["speex"]=="yes" or env["theoralib"]=="yes" or env["opus"]=="yes"):
SConscript("ogg/SCsub");
if (env["vorbis"]=="yes"):
SConscript("vorbis/SCsub");
+if (env["opus"]=="yes"):
+ SConscript('opus/SCsub');
if (env["tools"]=="yes"):
SConscript("convex_decomp/SCsub");
-if env["theora"]=="yes":
- SConscript("theoraplayer/SCsub")
-if (env["theora"]=="yes"):
+if (env["theoralib"]=="yes"):
SConscript("theora/SCsub");
if (env['speex']=='yes'):
SConscript("speex/SCsub");
@@ -61,34 +63,42 @@ import string
if env['vsproj']=="yes":
env.AddToVSProject(env.drivers_sources)
-for f in env.drivers_sources:
- fname = ""
- if type(f) == type(""):
- fname = env.File(f).path
- else:
- fname = env.File(f)[0].path
- #base = string.join(fname.split("/")[:-1], "/")
- fname = fname.replace("\\", "/")
- base = string.join(fname.split("/")[:2], "/")
- if base != cur_base and len(list) > max_src:
- lib = env.Library("drivers"+str(num), list)
- lib_list.append(lib)
- list = []
- num = num+1
- cur_base = base
- list.append(f)
+if (False): #split drivers, this used to be needed for windows until separate builders for windows were created
+
+ for f in env.drivers_sources:
+ fname = ""
+ if type(f) == type(""):
+ fname = env.File(f).path
+ else:
+ fname = env.File(f)[0].path
+ fname = fname.replace("\\", "/")
+ base = string.join(fname.split("/")[:2], "/")
+ if base != cur_base and len(list) > max_src:
+ if num > 0:
+ lib = env.Library("drivers"+str(num), list)
+ lib_list.append(lib)
+ list = []
+ num = num+1
+ cur_base = base
+ list.append(f)
-if len(list) > 0:
lib = env.Library("drivers"+str(num), list)
lib_list.append(lib)
+ if len(lib_list) > 0:
+ import os, sys
+ if os.name=='posix' and sys.platform=='msys':
+ env.Replace(ARFLAGS=['rcsT'])
-drivers_base=[]
-env.add_source_files(drivers_base,"*.cpp")
-lib_list.insert(0, env.Library("drivers", drivers_base))
-
-env.Prepend(LIBS=lib_list)
+ lib = env.Library("drivers_collated", lib_list)
+ lib_list = [lib]
-#lib = env.Library("drivers",env.drivers_sources)
-#env.Prepend(LIBS=[lib])
+ drivers_base=[]
+ env.add_source_files(drivers_base,"*.cpp")
+ lib_list.insert(0, env.Library("drivers", drivers_base))
+ env.Prepend(LIBS=lib_list)
+else:
+ env.add_source_files(env.drivers_sources,"*.cpp")
+ lib = env.Library("drivers",env.drivers_sources)
+ env.Prepend(LIBS=[lib])
diff --git a/drivers/alsa/SCsub b/drivers/alsa/SCsub
index bcd231579c..9fbb467baa 100644
--- a/drivers/alsa/SCsub
+++ b/drivers/alsa/SCsub
@@ -3,5 +3,3 @@ Import('env')
env.add_source_files(env.drivers_sources,"*.cpp")
Export('env')
-
-
diff --git a/drivers/alsa/audio_driver_alsa.cpp b/drivers/alsa/audio_driver_alsa.cpp
index 4bc35f86ee..6a3bd9bb22 100644
--- a/drivers/alsa/audio_driver_alsa.cpp
+++ b/drivers/alsa/audio_driver_alsa.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/alsa/audio_driver_alsa.h b/drivers/alsa/audio_driver_alsa.h
index 10f9298859..54fc8dccc9 100644
--- a/drivers/alsa/audio_driver_alsa.h
+++ b/drivers/alsa/audio_driver_alsa.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/builtin_openssl2/e_os.h b/drivers/builtin_openssl2/e_os.h
index e801b4106a..7323a7b4bf 100644
--- a/drivers/builtin_openssl2/e_os.h
+++ b/drivers/builtin_openssl2/e_os.h
@@ -318,8 +318,8 @@ static unsigned int _strlen31(const char *str)
# undef isupper
# undef isxdigit
# endif
-# if defined(_MSC_VER) && !defined(_DLL) && defined(stdin)
-# if _MSC_VER>=1300
+# if defined(_MSC_VER) && !defined(_WIN32_WCE) && !defined(_DLL) && defined(stdin)
+# if _MSC_VER>=1300 && _MSC_VER<1600
# undef stdin
# undef stdout
# undef stderr
@@ -327,7 +327,7 @@ static unsigned int _strlen31(const char *str)
# define stdin (&__iob_func()[0])
# define stdout (&__iob_func()[1])
# define stderr (&__iob_func()[2])
-# elif defined(I_CAN_LIVE_WITH_LNK4049)
+# elif _MSC_VER<1300 && defined(I_CAN_LIVE_WITH_LNK4049)
# undef stdin
# undef stdout
# undef stderr
diff --git a/drivers/builtin_zlib/SCsub b/drivers/builtin_zlib/SCsub
index c322b236ab..e5c81c0b3b 100644
--- a/drivers/builtin_zlib/SCsub
+++ b/drivers/builtin_zlib/SCsub
@@ -1,7 +1,7 @@
Import('env')
zlib_sources = [
-
+
"builtin_zlib/zlib/adler32.c",
"builtin_zlib/zlib/compress.c",
"builtin_zlib/zlib/crc32.c",
diff --git a/drivers/chibi/SCsub b/drivers/chibi/SCsub
index bcd231579c..9fbb467baa 100644
--- a/drivers/chibi/SCsub
+++ b/drivers/chibi/SCsub
@@ -3,5 +3,3 @@ Import('env')
env.add_source_files(env.drivers_sources,"*.cpp")
Export('env')
-
-
diff --git a/drivers/chibi/cp_config.h b/drivers/chibi/cp_config.h
index 9cd754ed47..2ad704ace7 100644
--- a/drivers/chibi/cp_config.h
+++ b/drivers/chibi/cp_config.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_envelope.cpp b/drivers/chibi/cp_envelope.cpp
index 6ed42a1167..fab8a68ada 100644
--- a/drivers/chibi/cp_envelope.cpp
+++ b/drivers/chibi/cp_envelope.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_envelope.h b/drivers/chibi/cp_envelope.h
index e01605ada3..d1ada53f7d 100644
--- a/drivers/chibi/cp_envelope.h
+++ b/drivers/chibi/cp_envelope.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_file_access_wrapper.cpp b/drivers/chibi/cp_file_access_wrapper.cpp
index d7c6c6d0b6..8ccde3735c 100644
--- a/drivers/chibi/cp_file_access_wrapper.cpp
+++ b/drivers/chibi/cp_file_access_wrapper.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_file_access_wrapper.h b/drivers/chibi/cp_file_access_wrapper.h
index c54ce5868d..5b361c0ea8 100644
--- a/drivers/chibi/cp_file_access_wrapper.h
+++ b/drivers/chibi/cp_file_access_wrapper.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_instrument.cpp b/drivers/chibi/cp_instrument.cpp
index 2e5af70565..7a732e33a4 100644
--- a/drivers/chibi/cp_instrument.cpp
+++ b/drivers/chibi/cp_instrument.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_instrument.h b/drivers/chibi/cp_instrument.h
index 8b434402c5..d8eb8333ee 100644
--- a/drivers/chibi/cp_instrument.h
+++ b/drivers/chibi/cp_instrument.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_loader.h b/drivers/chibi/cp_loader.h
index 7763c395b9..9d1074d1b8 100644
--- a/drivers/chibi/cp_loader.h
+++ b/drivers/chibi/cp_loader.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_loader_it.cpp b/drivers/chibi/cp_loader_it.cpp
index 74dd228437..20a3960a23 100644
--- a/drivers/chibi/cp_loader_it.cpp
+++ b/drivers/chibi/cp_loader_it.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_loader_it.h b/drivers/chibi/cp_loader_it.h
index 6ba605bf04..38a1cdd9c4 100644
--- a/drivers/chibi/cp_loader_it.h
+++ b/drivers/chibi/cp_loader_it.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_loader_it_info.cpp b/drivers/chibi/cp_loader_it_info.cpp
index 0cfd73f1e3..0360f7f9a4 100644
--- a/drivers/chibi/cp_loader_it_info.cpp
+++ b/drivers/chibi/cp_loader_it_info.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_loader_it_instruments.cpp b/drivers/chibi/cp_loader_it_instruments.cpp
index 6293be162c..ccb24bd81c 100644
--- a/drivers/chibi/cp_loader_it_instruments.cpp
+++ b/drivers/chibi/cp_loader_it_instruments.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_loader_it_patterns.cpp b/drivers/chibi/cp_loader_it_patterns.cpp
index c79dffc180..d951a91620 100644
--- a/drivers/chibi/cp_loader_it_patterns.cpp
+++ b/drivers/chibi/cp_loader_it_patterns.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_loader_it_samples.cpp b/drivers/chibi/cp_loader_it_samples.cpp
index 24d3a12781..ced7252a6c 100644
--- a/drivers/chibi/cp_loader_it_samples.cpp
+++ b/drivers/chibi/cp_loader_it_samples.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_loader_mod.cpp b/drivers/chibi/cp_loader_mod.cpp
index 98174ff9b1..f867b77914 100644
--- a/drivers/chibi/cp_loader_mod.cpp
+++ b/drivers/chibi/cp_loader_mod.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -446,18 +446,19 @@ CPLoader::Error CPLoader_MOD::load_song(const char *p_file,CPSong *p_song,bool p
if (sid.is_null()) {
continue; //empty sample, not stored?
}
-
+ sm->lock_data(sid);
+ uint8_t *dataptr = (uint8_t*)sm->get_data(sid);
+
int len=sm->get_size(sid);
for (int s=0;s<len;s++) {
uint8_t d=file->get_byte();
//d-=128; //convert to signed
int8_t*ds=(int8_t*)&d;
- int16_t d16=*ds;
- d16<<=8;
- sm->set_data( sid, s, d16 );
+ dataptr[s]=*ds;
}
+ sm->unlock_data(sid);
}
file->close();
diff --git a/drivers/chibi/cp_loader_mod.h b/drivers/chibi/cp_loader_mod.h
index 77245349b7..636f4f00f2 100644
--- a/drivers/chibi/cp_loader_mod.h
+++ b/drivers/chibi/cp_loader_mod.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_loader_s3m.cpp b/drivers/chibi/cp_loader_s3m.cpp
index c21f7bdd38..0fc15c1e2f 100644
--- a/drivers/chibi/cp_loader_s3m.cpp
+++ b/drivers/chibi/cp_loader_s3m.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -196,8 +196,12 @@ CPLoader::Error CPLoader_S3M::load_sample(CPSample *p_sample) {
if (id.is_null())
return FILE_OUT_OF_MEMORY;
+
+ sm->lock_data(id);
+ void *dataptr = sm->get_data(id);
- for (int c=0;c<(data_is_stereo?2:1);c++) {
+ int chans = (data_is_stereo?2:1);
+ for (int c=0;c<chans;c++) {
for (int i=0;i<sample_size;i++) {
if (data_is_16bits) {
@@ -206,7 +210,7 @@ CPLoader::Error CPLoader_S3M::load_sample(CPSample *p_sample) {
s-=32768; //toggle sign
int16_t *v=(int16_t*)&s;
- sm->set_data(id,i,*v,c);
+ ((int16_t*)dataptr)[i*chans+c]=*v;
} else {
@@ -214,16 +218,16 @@ CPLoader::Error CPLoader_S3M::load_sample(CPSample *p_sample) {
uint8_t s=file->get_byte();
s-=128; //toggle sign
v=(int8_t*)&s;
- int16_t v16=*v;
- v16<<=8;
- sm->set_data(id,i,v16,c);
-
+ ((int8_t*)dataptr)[i*chans+c]=*v;
+
}
-
-
+
}
}
+
+ sm->unlock_data(id);
+
sm->set_loop_begin( id, loop_begin );
sm->set_loop_end( id, loop_end );
diff --git a/drivers/chibi/cp_loader_s3m.h b/drivers/chibi/cp_loader_s3m.h
index 6fe9f0ca44..175e5e80fe 100644
--- a/drivers/chibi/cp_loader_s3m.h
+++ b/drivers/chibi/cp_loader_s3m.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_loader_xm.cpp b/drivers/chibi/cp_loader_xm.cpp
index 8bde6b673e..8ab6abc650 100644
--- a/drivers/chibi/cp_loader_xm.cpp
+++ b/drivers/chibi/cp_loader_xm.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -627,6 +627,10 @@ CPLoader::Error CPLoader_XM::load_instrument_internal(CPInstrument *p_instr,bool
CPSample *sample=song->get_sample(sample_index[j]);
CPSample_ID sid=sample->get_sample_data();
+ sm->lock_data(sid);
+
+ void*dataptr=sm->get_data(sid);
+
if (sm->is_16bits( sid)) {
int16_t old=0;
@@ -638,8 +642,9 @@ CPLoader::Error CPLoader_XM::load_instrument_internal(CPInstrument *p_instr,bool
int16_t sampleval=file->get_word();
newsample=sampleval+old;
old=newsample;
-
- sm->set_data( sid, k, newsample );
+
+ ((int16_t*)dataptr)[k]=newsample;
+ //sm->set_data( sid, k, newsample );
}
} else {
@@ -653,10 +658,15 @@ CPLoader::Error CPLoader_XM::load_instrument_internal(CPInstrument *p_instr,bool
newsample=sampleval+old;
old=newsample;
- sm->set_data( sid, k, (int16_t)newsample << 8 );
+ ((int8_t*)dataptr)[k]=newsample;
+
+ //sm->set_data( sid, k, (int16_t)newsample << 8 );
}
}
+
+ sm->unlock_data(sid);
+
}
for (int j=0;j<96;j++) {
diff --git a/drivers/chibi/cp_loader_xm.h b/drivers/chibi/cp_loader_xm.h
index 0a2465475f..9ae480cc8f 100644
--- a/drivers/chibi/cp_loader_xm.h
+++ b/drivers/chibi/cp_loader_xm.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_mixer.h b/drivers/chibi/cp_mixer.h
index bac2087edf..7ad22ac146 100644
--- a/drivers/chibi/cp_mixer.h
+++ b/drivers/chibi/cp_mixer.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_note.h b/drivers/chibi/cp_note.h
index 5d2c01844a..5cfa3f11ec 100644
--- a/drivers/chibi/cp_note.h
+++ b/drivers/chibi/cp_note.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_order.h b/drivers/chibi/cp_order.h
index a20e202bde..03ecc00bba 100644
--- a/drivers/chibi/cp_order.h
+++ b/drivers/chibi/cp_order.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_pattern.cpp b/drivers/chibi/cp_pattern.cpp
index cc65833d68..83e165bf87 100644
--- a/drivers/chibi/cp_pattern.cpp
+++ b/drivers/chibi/cp_pattern.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_pattern.h b/drivers/chibi/cp_pattern.h
index 22611eabab..4065caa5e5 100644
--- a/drivers/chibi/cp_pattern.h
+++ b/drivers/chibi/cp_pattern.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_player_data.cpp b/drivers/chibi/cp_player_data.cpp
index 76d8f280d2..3f3e9a5202 100644
--- a/drivers/chibi/cp_player_data.cpp
+++ b/drivers/chibi/cp_player_data.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_player_data.h b/drivers/chibi/cp_player_data.h
index 36a27942cb..282592b8f4 100644
--- a/drivers/chibi/cp_player_data.h
+++ b/drivers/chibi/cp_player_data.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_player_data_control.cpp b/drivers/chibi/cp_player_data_control.cpp
index d5ca648fff..d9aaed904f 100644
--- a/drivers/chibi/cp_player_data_control.cpp
+++ b/drivers/chibi/cp_player_data_control.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_player_data_effects.cpp b/drivers/chibi/cp_player_data_effects.cpp
index eb62b8d962..3a52a3b91b 100644
--- a/drivers/chibi/cp_player_data_effects.cpp
+++ b/drivers/chibi/cp_player_data_effects.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_player_data_envelopes.cpp b/drivers/chibi/cp_player_data_envelopes.cpp
index 94378b8bf4..96af42d19f 100644
--- a/drivers/chibi/cp_player_data_envelopes.cpp
+++ b/drivers/chibi/cp_player_data_envelopes.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_player_data_events.cpp b/drivers/chibi/cp_player_data_events.cpp
index 7a7cfdf5bb..8122988516 100644
--- a/drivers/chibi/cp_player_data_events.cpp
+++ b/drivers/chibi/cp_player_data_events.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_player_data_filter.cpp b/drivers/chibi/cp_player_data_filter.cpp
index fd87e4ae7a..30db807eed 100644
--- a/drivers/chibi/cp_player_data_filter.cpp
+++ b/drivers/chibi/cp_player_data_filter.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_player_data_nna.cpp b/drivers/chibi/cp_player_data_nna.cpp
index 3960234f5e..844f043694 100644
--- a/drivers/chibi/cp_player_data_nna.cpp
+++ b/drivers/chibi/cp_player_data_nna.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_player_data_notes.cpp b/drivers/chibi/cp_player_data_notes.cpp
index ea3ba42e86..621be019e1 100644
--- a/drivers/chibi/cp_player_data_notes.cpp
+++ b/drivers/chibi/cp_player_data_notes.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_player_data_reserved.cpp b/drivers/chibi/cp_player_data_reserved.cpp
index 8d9439158b..a626ffd111 100644
--- a/drivers/chibi/cp_player_data_reserved.cpp
+++ b/drivers/chibi/cp_player_data_reserved.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_player_data_utils.cpp b/drivers/chibi/cp_player_data_utils.cpp
index 5294fc8139..170a849863 100644
--- a/drivers/chibi/cp_player_data_utils.cpp
+++ b/drivers/chibi/cp_player_data_utils.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_sample.cpp b/drivers/chibi/cp_sample.cpp
index bff24d4c4c..55c2c910a5 100644
--- a/drivers/chibi/cp_sample.cpp
+++ b/drivers/chibi/cp_sample.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_sample.h b/drivers/chibi/cp_sample.h
index 71b57aaa81..4b3d218106 100644
--- a/drivers/chibi/cp_sample.h
+++ b/drivers/chibi/cp_sample.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_sample_defs.h b/drivers/chibi/cp_sample_defs.h
index 32817efc7d..169963c98e 100644
--- a/drivers/chibi/cp_sample_defs.h
+++ b/drivers/chibi/cp_sample_defs.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_sample_manager.cpp b/drivers/chibi/cp_sample_manager.cpp
index 601db07acf..5c2988e3f9 100644
--- a/drivers/chibi/cp_sample_manager.cpp
+++ b/drivers/chibi/cp_sample_manager.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_sample_manager.h b/drivers/chibi/cp_sample_manager.h
index 2891034482..74bcafc0cf 100644
--- a/drivers/chibi/cp_sample_manager.h
+++ b/drivers/chibi/cp_sample_manager.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_song.cpp b/drivers/chibi/cp_song.cpp
index 956e2ee6d4..4aa1a4228d 100644
--- a/drivers/chibi/cp_song.cpp
+++ b/drivers/chibi/cp_song.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_song.h b/drivers/chibi/cp_song.h
index 6c35b43c76..da5d106a63 100644
--- a/drivers/chibi/cp_song.h
+++ b/drivers/chibi/cp_song.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_tables.cpp b/drivers/chibi/cp_tables.cpp
index 9f1ae30c9a..8c62150f31 100644
--- a/drivers/chibi/cp_tables.cpp
+++ b/drivers/chibi/cp_tables.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/cp_tables.h b/drivers/chibi/cp_tables.h
index 6c3c9271b0..ac7ee562b7 100644
--- a/drivers/chibi/cp_tables.h
+++ b/drivers/chibi/cp_tables.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/chibi/event_stream_chibi.cpp b/drivers/chibi/event_stream_chibi.cpp
index e87e0a9aaa..3449583d36 100644
--- a/drivers/chibi/event_stream_chibi.cpp
+++ b/drivers/chibi/event_stream_chibi.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -779,8 +779,10 @@ EventStreamChibi::EventStreamChibi() {
-RES ResourceFormatLoaderChibi::load(const String &p_path,const String& p_original_path) {
+RES ResourceFormatLoaderChibi::load(const String &p_path, const String& p_original_path, Error *r_error) {
+ if (r_error)
+ *r_error=ERR_FILE_CANT_OPEN;
String el = p_path.extension().to_lower();
CPFileAccessWrapperImpl f;
@@ -791,6 +793,8 @@ RES ResourceFormatLoaderChibi::load(const String &p_path,const String& p_origina
CPLoader_IT loader(&f);
CPLoader::Error err = loader.load_song(p_path.utf8().get_data(),&esc->song,false);
ERR_FAIL_COND_V(err!=CPLoader::FILE_OK,RES());
+ if (r_error)
+ *r_error=OK;
return esc;
@@ -800,6 +804,8 @@ RES ResourceFormatLoaderChibi::load(const String &p_path,const String& p_origina
CPLoader_XM loader(&f);
CPLoader::Error err=loader.load_song(p_path.utf8().get_data(),&esc->song,false);
ERR_FAIL_COND_V(err!=CPLoader::FILE_OK,RES());
+ if (r_error)
+ *r_error=OK;
return esc;
} else if (el=="s3m") {
@@ -808,6 +814,9 @@ RES ResourceFormatLoaderChibi::load(const String &p_path,const String& p_origina
CPLoader_S3M loader(&f);
CPLoader::Error err=loader.load_song(p_path.utf8().get_data(),&esc->song,false);
ERR_FAIL_COND_V(err!=CPLoader::FILE_OK,RES());
+ if (r_error)
+ *r_error=OK;
+
return esc;
} else if (el=="mod") {
@@ -816,6 +825,8 @@ RES ResourceFormatLoaderChibi::load(const String &p_path,const String& p_origina
CPLoader_MOD loader(&f);
CPLoader::Error err=loader.load_song(p_path.utf8().get_data(),&esc->song,false);
ERR_FAIL_COND_V(err!=CPLoader::FILE_OK,RES());
+ if (r_error)
+ *r_error=OK;
return esc;
}
diff --git a/drivers/chibi/event_stream_chibi.h b/drivers/chibi/event_stream_chibi.h
index 7b2ee4b471..cc7b0ace86 100644
--- a/drivers/chibi/event_stream_chibi.h
+++ b/drivers/chibi/event_stream_chibi.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -301,7 +301,7 @@ public:
class ResourceFormatLoaderChibi : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path,const String& p_original_path="");
+ virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String& p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/drivers/convex_decomp/b2Glue.h b/drivers/convex_decomp/b2Glue.h
index db765f7eb9..7ec6d7f181 100644
--- a/drivers/convex_decomp/b2Glue.h
+++ b/drivers/convex_decomp/b2Glue.h
@@ -20,7 +20,8 @@
#define B2GLUE_H
#include "math_2d.h"
-#include <limits>
+#include <limits.h>
+
namespace b2ConvexDecomp {
typedef real_t float32;
diff --git a/drivers/convex_decomp/b2Polygon.cpp b/drivers/convex_decomp/b2Polygon.cpp
index 668313967e..73955d3573 100644
--- a/drivers/convex_decomp/b2Polygon.cpp
+++ b/drivers/convex_decomp/b2Polygon.cpp
@@ -21,8 +21,8 @@
#include "b2Triangle.h"
#include "b2Polygon.h"
-#include <cmath>
-#include <climits>
+#include <math.h>
+#include <limits.h>
#include <assert.h>
#define b2Assert assert
@@ -217,8 +217,8 @@ b2Polygon::b2Polygon(b2Triangle& t) {
void b2Polygon::Set(const b2Polygon& p) {
if (nVertices != p.nVertices){
nVertices = p.nVertices;
- if (x) delete[] x;
- if (y) delete[] y;
+ delete[] x;
+ delete[] y;
x = new float32[nVertices];
y = new float32[nVertices];
}
diff --git a/drivers/convex_decomp/b2Polygon.h b/drivers/convex_decomp/b2Polygon.h
index 82cdc56804..36af2fd9d0 100644
--- a/drivers/convex_decomp/b2Polygon.h
+++ b/drivers/convex_decomp/b2Polygon.h
@@ -22,7 +22,7 @@
#include "b2Triangle.h"
#include "stdio.h"
#include <string.h>
-#include <limits>
+#include <limits.h>
namespace b2ConvexDecomp {
static bool B2_POLYGON_REPORT_ERRORS = false;
diff --git a/drivers/dds/SCsub b/drivers/dds/SCsub
index e475de1dba..159829384f 100644
--- a/drivers/dds/SCsub
+++ b/drivers/dds/SCsub
@@ -8,4 +8,3 @@ dds_sources = [
env.drivers_sources+=dds_sources
#env.add_source_files(env.drivers_sources, dds_sources)
-
diff --git a/drivers/dds/texture_loader_dds.cpp b/drivers/dds/texture_loader_dds.cpp
index 8e6c3b62e6..9b2e401fd9 100644
--- a/drivers/dds/texture_loader_dds.cpp
+++ b/drivers/dds/texture_loader_dds.cpp
@@ -64,8 +64,10 @@ static const DDSFormatInfo dds_format_info[DDS_MAX]={
};
-RES ResourceFormatDDS::load(const String &p_path,const String& p_original_path) {
+RES ResourceFormatDDS::load(const String &p_path, const String& p_original_path, Error *r_error) {
+ if (r_error)
+ *r_error=ERR_CANT_OPEN;
Error err;
FileAccess *f = FileAccess::open(p_path,FileAccess::READ,&err);
@@ -73,6 +75,8 @@ RES ResourceFormatDDS::load(const String &p_path,const String& p_original_path)
return RES();
FileAccessRef fref(f);
+ if (r_error)
+ *r_error=ERR_FILE_CORRUPT;
ERR_EXPLAIN("Unable to open DDS texture file: "+p_path);
ERR_FAIL_COND_V(err!=OK,RES());
@@ -427,6 +431,10 @@ RES ResourceFormatDDS::load(const String &p_path,const String& p_original_path)
Ref<ImageTexture> texture = memnew( ImageTexture );
texture->create_from_image(img);
+ if (r_error)
+ *r_error=OK;
+
+
return texture;
}
diff --git a/drivers/dds/texture_loader_dds.h b/drivers/dds/texture_loader_dds.h
index 18a1485073..c8b3610063 100644
--- a/drivers/dds/texture_loader_dds.h
+++ b/drivers/dds/texture_loader_dds.h
@@ -7,7 +7,7 @@
class ResourceFormatDDS : public ResourceFormatLoader{
public:
- virtual RES load(const String &p_path,const String& p_original_path="");
+ virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String& p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/drivers/etc1/SCsub b/drivers/etc1/SCsub
index 251c3ffb86..4ce921ad9f 100644
--- a/drivers/etc1/SCsub
+++ b/drivers/etc1/SCsub
@@ -12,4 +12,3 @@ if (env["etc1"] != "no"):
#env.add_source_files(env.drivers_sources, etc_sources)
Export('env')
-
diff --git a/drivers/etc1/rg_etc1.cpp b/drivers/etc1/rg_etc1.cpp
index fd109f003c..47dcb57e6b 100644
--- a/drivers/etc1/rg_etc1.cpp
+++ b/drivers/etc1/rg_etc1.cpp
@@ -1,2454 +1,2454 @@
-// File: rg_etc1.cpp - Fast, high quality ETC1 block packer/unpacker - Rich Geldreich <richgel99@gmail.com>
-// Please see ZLIB license at the end of rg_etc1.h.
-//
-// For more information Ericsson Texture Compression (ETC/ETC1), see:
-// http://www.khronos.org/registry/gles/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt
-//
-// v1.03 - 5/12/13 - Initial public release
-#include "rg_etc1.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-//#include <stdio.h>
-#include <math.h>
-#include <stdio.h>
-#pragma warning (disable: 4201) // nonstandard extension used : nameless struct/union
-
-#if defined(_DEBUG) || defined(DEBUG)
-#define RG_ETC1_BUILD_DEBUG
-#endif
-
-#define RG_ETC1_ASSERT assert
-
-namespace rg_etc1
-{
-
- inline long labs(long val) {
- return val < 0 ? -val : val;
- }
-
- inline int intabs(int val) {
-
- return val<0?-val:val;
- }
-
- typedef unsigned char uint8;
- typedef unsigned short uint16;
- typedef unsigned int uint;
- typedef unsigned int uint32;
- typedef long long int64;
- typedef unsigned long long uint64;
-
- const uint32 cUINT32_MAX = 0xFFFFFFFFU;
- const uint64 cUINT64_MAX = 0xFFFFFFFFFFFFFFFFULL; //0xFFFFFFFFFFFFFFFFui64;
-
- template<typename T> inline T minimum(T a, T b) { return (a < b) ? a : b; }
- template<typename T> inline T minimum(T a, T b, T c) { return minimum(minimum(a, b), c); }
- template<typename T> inline T maximum(T a, T b) { return (a > b) ? a : b; }
- template<typename T> inline T maximum(T a, T b, T c) { return maximum(maximum(a, b), c); }
- template<typename T> inline T clamp(T value, T low, T high) { return (value < low) ? low : ((value > high) ? high : value); }
- template<typename T> inline T square(T value) { return value * value; }
- template<typename T> inline void zero_object(T& obj) { memset((void*)&obj, 0, sizeof(obj)); }
- template<typename T> inline void zero_this(T* pObj) { memset((void*)pObj, 0, sizeof(*pObj)); }
-
- template<class T, size_t N> T decay_array_to_subtype(T (&a)[N]);
-
-#define RG_ETC1_ARRAY_SIZE(X) (sizeof(X) / sizeof(decay_array_to_subtype(X)))
-
- enum eNoClamp { cNoClamp };
-
- struct color_quad_u8
- {
- static inline int clamp(int v) { if (v & 0xFFFFFF00U) v = (~(static_cast<int>(v) >> 31)) & 0xFF; return v; }
-
- struct component_traits { enum { cSigned = false, cFloat = false, cMin = 0U, cMax = 255U }; };
-
- public:
- typedef unsigned char component_t;
- typedef int parameter_t;
-
- enum { cNumComps = 4 };
-
- union
- {
- struct
- {
- component_t r;
- component_t g;
- component_t b;
- component_t a;
- };
-
- component_t c[cNumComps];
-
- uint32 m_u32;
- };
-
- inline color_quad_u8()
- {
- }
-
- inline color_quad_u8(const color_quad_u8& other) : m_u32(other.m_u32)
- {
- }
-
- explicit inline color_quad_u8(parameter_t y, parameter_t alpha = component_traits::cMax)
- {
- set(y, alpha);
- }
-
- inline color_quad_u8(parameter_t red, parameter_t green, parameter_t blue, parameter_t alpha = component_traits::cMax)
- {
- set(red, green, blue, alpha);
- }
-
- explicit inline color_quad_u8(eNoClamp, parameter_t y, parameter_t alpha = component_traits::cMax)
- {
- set_noclamp_y_alpha(y, alpha);
- }
-
- inline color_quad_u8(eNoClamp, parameter_t red, parameter_t green, parameter_t blue, parameter_t alpha = component_traits::cMax)
- {
- set_noclamp_rgba(red, green, blue, alpha);
- }
-
- inline void clear()
- {
- m_u32 = 0;
- }
-
- inline color_quad_u8& operator= (const color_quad_u8& other)
- {
- m_u32 = other.m_u32;
- return *this;
- }
-
- inline color_quad_u8& set_rgb(const color_quad_u8& other)
- {
- r = other.r;
- g = other.g;
- b = other.b;
- return *this;
- }
-
- inline color_quad_u8& operator= (parameter_t y)
- {
- set(y, component_traits::cMax);
- return *this;
- }
-
- inline color_quad_u8& set(parameter_t y, parameter_t alpha = component_traits::cMax)
- {
- y = clamp(y);
- alpha = clamp(alpha);
- r = static_cast<component_t>(y);
- g = static_cast<component_t>(y);
- b = static_cast<component_t>(y);
- a = static_cast<component_t>(alpha);
- return *this;
- }
-
- inline color_quad_u8& set_noclamp_y_alpha(parameter_t y, parameter_t alpha = component_traits::cMax)
- {
- RG_ETC1_ASSERT( (y >= component_traits::cMin) && (y <= component_traits::cMax) );
- RG_ETC1_ASSERT( (alpha >= component_traits::cMin) && (alpha <= component_traits::cMax) );
-
- r = static_cast<component_t>(y);
- g = static_cast<component_t>(y);
- b = static_cast<component_t>(y);
- a = static_cast<component_t>(alpha);
- return *this;
- }
-
- inline color_quad_u8& set(parameter_t red, parameter_t green, parameter_t blue, parameter_t alpha = component_traits::cMax)
- {
- r = static_cast<component_t>(clamp(red));
- g = static_cast<component_t>(clamp(green));
- b = static_cast<component_t>(clamp(blue));
- a = static_cast<component_t>(clamp(alpha));
- return *this;
- }
-
- inline color_quad_u8& set_noclamp_rgba(parameter_t red, parameter_t green, parameter_t blue, parameter_t alpha)
- {
- RG_ETC1_ASSERT( (red >= component_traits::cMin) && (red <= component_traits::cMax) );
- RG_ETC1_ASSERT( (green >= component_traits::cMin) && (green <= component_traits::cMax) );
- RG_ETC1_ASSERT( (blue >= component_traits::cMin) && (blue <= component_traits::cMax) );
- RG_ETC1_ASSERT( (alpha >= component_traits::cMin) && (alpha <= component_traits::cMax) );
-
- r = static_cast<component_t>(red);
- g = static_cast<component_t>(green);
- b = static_cast<component_t>(blue);
- a = static_cast<component_t>(alpha);
- return *this;
- }
-
- inline color_quad_u8& set_noclamp_rgb(parameter_t red, parameter_t green, parameter_t blue)
- {
- RG_ETC1_ASSERT( (red >= component_traits::cMin) && (red <= component_traits::cMax) );
- RG_ETC1_ASSERT( (green >= component_traits::cMin) && (green <= component_traits::cMax) );
- RG_ETC1_ASSERT( (blue >= component_traits::cMin) && (blue <= component_traits::cMax) );
-
- r = static_cast<component_t>(red);
- g = static_cast<component_t>(green);
- b = static_cast<component_t>(blue);
- return *this;
- }
-
- static inline parameter_t get_min_comp() { return component_traits::cMin; }
- static inline parameter_t get_max_comp() { return component_traits::cMax; }
- static inline bool get_comps_are_signed() { return component_traits::cSigned; }
-
- inline component_t operator[] (uint i) const { RG_ETC1_ASSERT(i < cNumComps); return c[i]; }
- inline component_t& operator[] (uint i) { RG_ETC1_ASSERT(i < cNumComps); return c[i]; }
-
- inline color_quad_u8& set_component(uint i, parameter_t f)
- {
- RG_ETC1_ASSERT(i < cNumComps);
-
- c[i] = static_cast<component_t>(clamp(f));
-
- return *this;
- }
-
- inline color_quad_u8& set_grayscale(parameter_t l)
- {
- component_t x = static_cast<component_t>(clamp(l));
- c[0] = x;
- c[1] = x;
- c[2] = x;
- return *this;
- }
-
- inline color_quad_u8& clamp(const color_quad_u8& l, const color_quad_u8& h)
- {
- for (uint i = 0; i < cNumComps; i++)
- c[i] = static_cast<component_t>(rg_etc1::clamp<parameter_t>(c[i], l[i], h[i]));
- return *this;
- }
-
- inline color_quad_u8& clamp(parameter_t l, parameter_t h)
- {
- for (uint i = 0; i < cNumComps; i++)
- c[i] = static_cast<component_t>(rg_etc1::clamp<parameter_t>(c[i], l, h));
- return *this;
- }
-
- // Returns CCIR 601 luma (consistent with color_utils::RGB_To_Y).
- inline parameter_t get_luma() const
- {
- return static_cast<parameter_t>((19595U * r + 38470U * g + 7471U * b + 32768U) >> 16U);
- }
-
- // Returns REC 709 luma.
- inline parameter_t get_luma_rec709() const
- {
- return static_cast<parameter_t>((13938U * r + 46869U * g + 4729U * b + 32768U) >> 16U);
- }
-
- inline uint squared_distance_rgb(const color_quad_u8& c) const
- {
- return rg_etc1::square(r - c.r) + rg_etc1::square(g - c.g) + rg_etc1::square(b - c.b);
- }
-
- inline uint squared_distance_rgba(const color_quad_u8& c) const
- {
- return rg_etc1::square(r - c.r) + rg_etc1::square(g - c.g) + rg_etc1::square(b - c.b) + rg_etc1::square(a - c.a);
- }
-
- inline bool rgb_equals(const color_quad_u8& rhs) const
- {
- return (r == rhs.r) && (g == rhs.g) && (b == rhs.b);
- }
-
- inline bool operator== (const color_quad_u8& rhs) const
- {
- return m_u32 == rhs.m_u32;
- }
-
- color_quad_u8& operator+= (const color_quad_u8& other)
- {
- for (uint i = 0; i < 4; i++)
- c[i] = static_cast<component_t>(clamp(c[i] + other.c[i]));
- return *this;
- }
-
- color_quad_u8& operator-= (const color_quad_u8& other)
- {
- for (uint i = 0; i < 4; i++)
- c[i] = static_cast<component_t>(clamp(c[i] - other.c[i]));
- return *this;
- }
-
- friend color_quad_u8 operator+ (const color_quad_u8& lhs, const color_quad_u8& rhs)
- {
- color_quad_u8 result(lhs);
- result += rhs;
- return result;
- }
-
- friend color_quad_u8 operator- (const color_quad_u8& lhs, const color_quad_u8& rhs)
- {
- color_quad_u8 result(lhs);
- result -= rhs;
- return result;
- }
- }; // class color_quad_u8
-
- struct vec3F
- {
- float m_s[3];
-
- inline vec3F() { }
- inline vec3F(float s) { m_s[0] = s; m_s[1] = s; m_s[2] = s; }
- inline vec3F(float x, float y, float z) { m_s[0] = x; m_s[1] = y; m_s[2] = z; }
-
- inline float operator[] (uint i) const { RG_ETC1_ASSERT(i < 3); return m_s[i]; }
-
- inline vec3F& operator += (const vec3F& other) { for (uint i = 0; i < 3; i++) m_s[i] += other.m_s[i]; return *this; }
-
- inline vec3F& operator *= (float s) { for (uint i = 0; i < 3; i++) m_s[i] *= s; return *this; }
- };
-
- enum etc_constants
- {
- cETC1BytesPerBlock = 8U,
-
- cETC1SelectorBits = 2U,
- cETC1SelectorValues = 1U << cETC1SelectorBits,
- cETC1SelectorMask = cETC1SelectorValues - 1U,
-
- cETC1BlockShift = 2U,
- cETC1BlockSize = 1U << cETC1BlockShift,
-
- cETC1LSBSelectorIndicesBitOffset = 0,
- cETC1MSBSelectorIndicesBitOffset = 16,
-
- cETC1FlipBitOffset = 32,
- cETC1DiffBitOffset = 33,
-
- cETC1IntenModifierNumBits = 3,
- cETC1IntenModifierValues = 1 << cETC1IntenModifierNumBits,
- cETC1RightIntenModifierTableBitOffset = 34,
- cETC1LeftIntenModifierTableBitOffset = 37,
-
- // Base+Delta encoding (5 bit bases, 3 bit delta)
- cETC1BaseColorCompNumBits = 5,
- cETC1BaseColorCompMax = 1 << cETC1BaseColorCompNumBits,
-
- cETC1DeltaColorCompNumBits = 3,
- cETC1DeltaColorComp = 1 << cETC1DeltaColorCompNumBits,
- cETC1DeltaColorCompMax = 1 << cETC1DeltaColorCompNumBits,
-
- cETC1BaseColor5RBitOffset = 59,
- cETC1BaseColor5GBitOffset = 51,
- cETC1BaseColor5BBitOffset = 43,
-
- cETC1DeltaColor3RBitOffset = 56,
- cETC1DeltaColor3GBitOffset = 48,
- cETC1DeltaColor3BBitOffset = 40,
-
- // Absolute (non-delta) encoding (two 4-bit per component bases)
- cETC1AbsColorCompNumBits = 4,
- cETC1AbsColorCompMax = 1 << cETC1AbsColorCompNumBits,
-
- cETC1AbsColor4R1BitOffset = 60,
- cETC1AbsColor4G1BitOffset = 52,
- cETC1AbsColor4B1BitOffset = 44,
-
- cETC1AbsColor4R2BitOffset = 56,
- cETC1AbsColor4G2BitOffset = 48,
- cETC1AbsColor4B2BitOffset = 40,
-
- cETC1ColorDeltaMin = -4,
- cETC1ColorDeltaMax = 3,
-
- // Delta3:
- // 0 1 2 3 4 5 6 7
- // 000 001 010 011 100 101 110 111
- // 0 1 2 3 -4 -3 -2 -1
- };
-
- static uint8 g_quant5_tab[256+16];
-
-
- static const int g_etc1_inten_tables[cETC1IntenModifierValues][cETC1SelectorValues] =
- {
- { -8, -2, 2, 8 }, { -17, -5, 5, 17 }, { -29, -9, 9, 29 }, { -42, -13, 13, 42 },
- { -60, -18, 18, 60 }, { -80, -24, 24, 80 }, { -106, -33, 33, 106 }, { -183, -47, 47, 183 }
- };
-
- static const uint8 g_etc1_to_selector_index[cETC1SelectorValues] = { 2, 3, 1, 0 };
- static const uint8 g_selector_index_to_etc1[cETC1SelectorValues] = { 3, 2, 0, 1 };
-
- // Given an ETC1 diff/inten_table/selector, and an 8-bit desired color, this table encodes the best packed_color in the low byte, and the abs error in the high byte.
- static uint16 g_etc1_inverse_lookup[2*8*4][256]; // [diff/inten_table/selector][desired_color]
-
- // g_color8_to_etc_block_config[color][table_index] = Supplies for each 8-bit color value a list of packed ETC1 diff/intensity table/selectors/packed_colors that map to that color.
- // To pack: diff | (inten << 1) | (selector << 4) | (packed_c << 8)
- static const uint16 g_color8_to_etc_block_config_0_255[2][33] =
- {
- { 0x0000, 0x0010, 0x0002, 0x0012, 0x0004, 0x0014, 0x0006, 0x0016, 0x0008, 0x0018, 0x000A, 0x001A, 0x000C, 0x001C, 0x000E, 0x001E,
- 0x0001, 0x0011, 0x0003, 0x0013, 0x0005, 0x0015, 0x0007, 0x0017, 0x0009, 0x0019, 0x000B, 0x001B, 0x000D, 0x001D, 0x000F, 0x001F, 0xFFFF },
- { 0x0F20, 0x0F30, 0x0E32, 0x0F22, 0x0E34, 0x0F24, 0x0D36, 0x0F26, 0x0C38, 0x0E28, 0x0B3A, 0x0E2A, 0x093C, 0x0E2C, 0x053E, 0x0D2E,
- 0x1E31, 0x1F21, 0x1D33, 0x1F23, 0x1C35, 0x1E25, 0x1A37, 0x1E27, 0x1839, 0x1D29, 0x163B, 0x1C2B, 0x133D, 0x1B2D, 0x093F, 0x1A2F, 0xFFFF },
- };
-
- // Really only [254][11].
- static const uint16 g_color8_to_etc_block_config_1_to_254[254][12] =
- {
- { 0x021C, 0x0D0D, 0xFFFF }, { 0x0020, 0x0021, 0x0A0B, 0x061F, 0xFFFF }, { 0x0113, 0x0217, 0xFFFF }, { 0x0116, 0x031E,
- 0x0B0E, 0x0405, 0xFFFF }, { 0x0022, 0x0204, 0x050A, 0x0023, 0xFFFF }, { 0x0111, 0x0319, 0x0809, 0x170F, 0xFFFF }, {
- 0x0303, 0x0215, 0x0607, 0xFFFF }, { 0x0030, 0x0114, 0x0408, 0x0031, 0x0201, 0x051D, 0xFFFF }, { 0x0100, 0x0024, 0x0306,
- 0x0025, 0x041B, 0x0E0D, 0xFFFF }, { 0x021A, 0x0121, 0x0B0B, 0x071F, 0xFFFF }, { 0x0213, 0x0317, 0xFFFF }, { 0x0112,
- 0x0505, 0xFFFF }, { 0x0026, 0x070C, 0x0123, 0x0027, 0xFFFF }, { 0x0211, 0x0909, 0xFFFF }, { 0x0110, 0x0315, 0x0707,
- 0x0419, 0x180F, 0xFFFF }, { 0x0218, 0x0131, 0x0301, 0x0403, 0x061D, 0xFFFF }, { 0x0032, 0x0202, 0x0033, 0x0125, 0x051B,
- 0x0F0D, 0xFFFF }, { 0x0028, 0x031C, 0x0221, 0x0029, 0xFFFF }, { 0x0120, 0x0313, 0x0C0B, 0x081F, 0xFFFF }, { 0x0605,
- 0x0417, 0xFFFF }, { 0x0216, 0x041E, 0x0C0E, 0x0223, 0x0127, 0xFFFF }, { 0x0122, 0x0304, 0x060A, 0x0311, 0x0A09, 0xFFFF
- }, { 0x0519, 0x190F, 0xFFFF }, { 0x002A, 0x0231, 0x0503, 0x0415, 0x0807, 0x002B, 0x071D, 0xFFFF }, { 0x0130, 0x0214,
- 0x0508, 0x0401, 0x0133, 0x0225, 0x061B, 0xFFFF }, { 0x0200, 0x0124, 0x0406, 0x0321, 0x0129, 0x100D, 0xFFFF }, { 0x031A,
- 0x0D0B, 0x091F, 0xFFFF }, { 0x0413, 0x0705, 0x0517, 0xFFFF }, { 0x0212, 0x0034, 0x0323, 0x0035, 0x0227, 0xFFFF }, {
- 0x0126, 0x080C, 0x0B09, 0xFFFF }, { 0x0411, 0x0619, 0x1A0F, 0xFFFF }, { 0x0210, 0x0331, 0x0603, 0x0515, 0x0907, 0x012B,
- 0xFFFF }, { 0x0318, 0x002C, 0x0501, 0x0233, 0x0325, 0x071B, 0x002D, 0x081D, 0xFFFF }, { 0x0132, 0x0302, 0x0229, 0x110D,
- 0xFFFF }, { 0x0128, 0x041C, 0x0421, 0x0E0B, 0x0A1F, 0xFFFF }, { 0x0220, 0x0513, 0x0617, 0xFFFF }, { 0x0135, 0x0805,
- 0x0327, 0xFFFF }, { 0x0316, 0x051E, 0x0D0E, 0x0423, 0xFFFF }, { 0x0222, 0x0404, 0x070A, 0x0511, 0x0719, 0x0C09, 0x1B0F,
- 0xFFFF }, { 0x0703, 0x0615, 0x0A07, 0x022B, 0xFFFF }, { 0x012A, 0x0431, 0x0601, 0x0333, 0x012D, 0x091D, 0xFFFF }, {
- 0x0230, 0x0314, 0x0036, 0x0608, 0x0425, 0x0037, 0x0329, 0x081B, 0x120D, 0xFFFF }, { 0x0300, 0x0224, 0x0506, 0x0521,
- 0x0F0B, 0x0B1F, 0xFFFF }, { 0x041A, 0x0613, 0x0717, 0xFFFF }, { 0x0235, 0x0905, 0xFFFF }, { 0x0312, 0x0134, 0x0523,
- 0x0427, 0xFFFF }, { 0x0226, 0x090C, 0x002E, 0x0611, 0x0D09, 0x002F, 0xFFFF }, { 0x0715, 0x0B07, 0x0819, 0x032B, 0x1C0F,
- 0xFFFF }, { 0x0310, 0x0531, 0x0701, 0x0803, 0x022D, 0x0A1D, 0xFFFF }, { 0x0418, 0x012C, 0x0433, 0x0525, 0x0137, 0x091B,
- 0x130D, 0xFFFF }, { 0x0232, 0x0402, 0x0621, 0x0429, 0xFFFF }, { 0x0228, 0x051C, 0x0713, 0x100B, 0x0C1F, 0xFFFF }, {
- 0x0320, 0x0335, 0x0A05, 0x0817, 0xFFFF }, { 0x0623, 0x0527, 0xFFFF }, { 0x0416, 0x061E, 0x0E0E, 0x0711, 0x0E09, 0x012F,
- 0xFFFF }, { 0x0322, 0x0504, 0x080A, 0x0919, 0x1D0F, 0xFFFF }, { 0x0631, 0x0903, 0x0815, 0x0C07, 0x042B, 0x032D, 0x0B1D,
- 0xFFFF }, { 0x022A, 0x0801, 0x0533, 0x0625, 0x0237, 0x0A1B, 0xFFFF }, { 0x0330, 0x0414, 0x0136, 0x0708, 0x0721, 0x0529,
- 0x140D, 0xFFFF }, { 0x0400, 0x0324, 0x0606, 0x0038, 0x0039, 0x110B, 0x0D1F, 0xFFFF }, { 0x051A, 0x0813, 0x0B05, 0x0917,
- 0xFFFF }, { 0x0723, 0x0435, 0x0627, 0xFFFF }, { 0x0412, 0x0234, 0x0F09, 0x022F, 0xFFFF }, { 0x0326, 0x0A0C, 0x012E,
- 0x0811, 0x0A19, 0x1E0F, 0xFFFF }, { 0x0731, 0x0A03, 0x0915, 0x0D07, 0x052B, 0xFFFF }, { 0x0410, 0x0901, 0x0633, 0x0725,
- 0x0337, 0x0B1B, 0x042D, 0x0C1D, 0xFFFF }, { 0x0518, 0x022C, 0x0629, 0x150D, 0xFFFF }, { 0x0332, 0x0502, 0x0821, 0x0139,
- 0x120B, 0x0E1F, 0xFFFF }, { 0x0328, 0x061C, 0x0913, 0x0A17, 0xFFFF }, { 0x0420, 0x0535, 0x0C05, 0x0727, 0xFFFF }, {
- 0x0823, 0x032F, 0xFFFF }, { 0x0516, 0x071E, 0x0F0E, 0x0911, 0x0B19, 0x1009, 0x1F0F, 0xFFFF }, { 0x0422, 0x0604, 0x090A,
- 0x0B03, 0x0A15, 0x0E07, 0x062B, 0xFFFF }, { 0x0831, 0x0A01, 0x0733, 0x052D, 0x0D1D, 0xFFFF }, { 0x032A, 0x0825, 0x0437,
- 0x0729, 0x0C1B, 0x160D, 0xFFFF }, { 0x0430, 0x0514, 0x0236, 0x0808, 0x0921, 0x0239, 0x130B, 0x0F1F, 0xFFFF }, { 0x0500,
- 0x0424, 0x0706, 0x0138, 0x0A13, 0x0B17, 0xFFFF }, { 0x061A, 0x0635, 0x0D05, 0xFFFF }, { 0x0923, 0x0827, 0xFFFF }, {
- 0x0512, 0x0334, 0x003A, 0x0A11, 0x1109, 0x003B, 0x042F, 0xFFFF }, { 0x0426, 0x0B0C, 0x022E, 0x0B15, 0x0F07, 0x0C19,
- 0x072B, 0xFFFF }, { 0x0931, 0x0B01, 0x0C03, 0x062D, 0x0E1D, 0xFFFF }, { 0x0510, 0x0833, 0x0925, 0x0537, 0x0D1B, 0x170D,
- 0xFFFF }, { 0x0618, 0x032C, 0x0A21, 0x0339, 0x0829, 0xFFFF }, { 0x0432, 0x0602, 0x0B13, 0x140B, 0x101F, 0xFFFF }, {
- 0x0428, 0x071C, 0x0735, 0x0E05, 0x0C17, 0xFFFF }, { 0x0520, 0x0A23, 0x0927, 0xFFFF }, { 0x0B11, 0x1209, 0x013B, 0x052F,
- 0xFFFF }, { 0x0616, 0x081E, 0x0D19, 0xFFFF }, { 0x0522, 0x0704, 0x0A0A, 0x0A31, 0x0D03, 0x0C15, 0x1007, 0x082B, 0x072D,
- 0x0F1D, 0xFFFF }, { 0x0C01, 0x0933, 0x0A25, 0x0637, 0x0E1B, 0xFFFF }, { 0x042A, 0x0B21, 0x0929, 0x180D, 0xFFFF }, {
- 0x0530, 0x0614, 0x0336, 0x0908, 0x0439, 0x150B, 0x111F, 0xFFFF }, { 0x0600, 0x0524, 0x0806, 0x0238, 0x0C13, 0x0F05,
- 0x0D17, 0xFFFF }, { 0x071A, 0x0B23, 0x0835, 0x0A27, 0xFFFF }, { 0x1309, 0x023B, 0x062F, 0xFFFF }, { 0x0612, 0x0434,
- 0x013A, 0x0C11, 0x0E19, 0xFFFF }, { 0x0526, 0x0C0C, 0x032E, 0x0B31, 0x0E03, 0x0D15, 0x1107, 0x092B, 0xFFFF }, { 0x0D01,
- 0x0A33, 0x0B25, 0x0737, 0x0F1B, 0x082D, 0x101D, 0xFFFF }, { 0x0610, 0x0A29, 0x190D, 0xFFFF }, { 0x0718, 0x042C, 0x0C21,
- 0x0539, 0x160B, 0x121F, 0xFFFF }, { 0x0532, 0x0702, 0x0D13, 0x0E17, 0xFFFF }, { 0x0528, 0x081C, 0x0935, 0x1005, 0x0B27,
- 0xFFFF }, { 0x0620, 0x0C23, 0x033B, 0x072F, 0xFFFF }, { 0x0D11, 0x0F19, 0x1409, 0xFFFF }, { 0x0716, 0x003C, 0x091E,
- 0x0F03, 0x0E15, 0x1207, 0x0A2B, 0x003D, 0xFFFF }, { 0x0622, 0x0804, 0x0B0A, 0x0C31, 0x0E01, 0x0B33, 0x092D, 0x111D,
- 0xFFFF }, { 0x0C25, 0x0837, 0x0B29, 0x101B, 0x1A0D, 0xFFFF }, { 0x052A, 0x0D21, 0x0639, 0x170B, 0x131F, 0xFFFF }, {
- 0x0630, 0x0714, 0x0436, 0x0A08, 0x0E13, 0x0F17, 0xFFFF }, { 0x0700, 0x0624, 0x0906, 0x0338, 0x0A35, 0x1105, 0xFFFF }, {
- 0x081A, 0x0D23, 0x0C27, 0xFFFF }, { 0x0E11, 0x1509, 0x043B, 0x082F, 0xFFFF }, { 0x0712, 0x0534, 0x023A, 0x0F15, 0x1307,
- 0x1019, 0x0B2B, 0x013D, 0xFFFF }, { 0x0626, 0x0D0C, 0x042E, 0x0D31, 0x0F01, 0x1003, 0x0A2D, 0x121D, 0xFFFF }, { 0x0C33,
- 0x0D25, 0x0937, 0x111B, 0x1B0D, 0xFFFF }, { 0x0710, 0x0E21, 0x0739, 0x0C29, 0xFFFF }, { 0x0818, 0x052C, 0x0F13, 0x180B,
- 0x141F, 0xFFFF }, { 0x0632, 0x0802, 0x0B35, 0x1205, 0x1017, 0xFFFF }, { 0x0628, 0x091C, 0x0E23, 0x0D27, 0xFFFF }, {
- 0x0720, 0x0F11, 0x1609, 0x053B, 0x092F, 0xFFFF }, { 0x1119, 0x023D, 0xFFFF }, { 0x0816, 0x013C, 0x0A1E, 0x0E31, 0x1103,
- 0x1015, 0x1407, 0x0C2B, 0x0B2D, 0x131D, 0xFFFF }, { 0x0722, 0x0904, 0x0C0A, 0x1001, 0x0D33, 0x0E25, 0x0A37, 0x121B,
- 0xFFFF }, { 0x0F21, 0x0D29, 0x1C0D, 0xFFFF }, { 0x062A, 0x0839, 0x190B, 0x151F, 0xFFFF }, { 0x0730, 0x0814, 0x0536,
- 0x0B08, 0x1013, 0x1305, 0x1117, 0xFFFF }, { 0x0800, 0x0724, 0x0A06, 0x0438, 0x0F23, 0x0C35, 0x0E27, 0xFFFF }, { 0x091A,
- 0x1709, 0x063B, 0x0A2F, 0xFFFF }, { 0x1011, 0x1219, 0x033D, 0xFFFF }, { 0x0812, 0x0634, 0x033A, 0x0F31, 0x1203, 0x1115,
- 0x1507, 0x0D2B, 0xFFFF }, { 0x0726, 0x0E0C, 0x052E, 0x1101, 0x0E33, 0x0F25, 0x0B37, 0x131B, 0x0C2D, 0x141D, 0xFFFF }, {
- 0x0E29, 0x1D0D, 0xFFFF }, { 0x0810, 0x1021, 0x0939, 0x1A0B, 0x161F, 0xFFFF }, { 0x0918, 0x062C, 0x1113, 0x1217, 0xFFFF
- }, { 0x0732, 0x0902, 0x0D35, 0x1405, 0x0F27, 0xFFFF }, { 0x0728, 0x0A1C, 0x1023, 0x073B, 0x0B2F, 0xFFFF }, { 0x0820,
- 0x1111, 0x1319, 0x1809, 0xFFFF }, { 0x1303, 0x1215, 0x1607, 0x0E2B, 0x043D, 0xFFFF }, { 0x0916, 0x023C, 0x0B1E, 0x1031,
- 0x1201, 0x0F33, 0x0D2D, 0x151D, 0xFFFF }, { 0x0822, 0x0A04, 0x0D0A, 0x1025, 0x0C37, 0x0F29, 0x141B, 0x1E0D, 0xFFFF }, {
- 0x1121, 0x0A39, 0x1B0B, 0x171F, 0xFFFF }, { 0x072A, 0x1213, 0x1317, 0xFFFF }, { 0x0830, 0x0914, 0x0636, 0x0C08, 0x0E35,
- 0x1505, 0xFFFF }, { 0x0900, 0x0824, 0x0B06, 0x0538, 0x1123, 0x1027, 0xFFFF }, { 0x0A1A, 0x1211, 0x1909, 0x083B, 0x0C2F,
- 0xFFFF }, { 0x1315, 0x1707, 0x1419, 0x0F2B, 0x053D, 0xFFFF }, { 0x0912, 0x0734, 0x043A, 0x1131, 0x1301, 0x1403, 0x0E2D,
- 0x161D, 0xFFFF }, { 0x0826, 0x0F0C, 0x062E, 0x1033, 0x1125, 0x0D37, 0x151B, 0x1F0D, 0xFFFF }, { 0x1221, 0x0B39, 0x1029,
- 0xFFFF }, { 0x0910, 0x1313, 0x1C0B, 0x181F, 0xFFFF }, { 0x0A18, 0x072C, 0x0F35, 0x1605, 0x1417, 0xFFFF }, { 0x0832,
- 0x0A02, 0x1223, 0x1127, 0xFFFF }, { 0x0828, 0x0B1C, 0x1311, 0x1A09, 0x093B, 0x0D2F, 0xFFFF }, { 0x0920, 0x1519, 0x063D,
- 0xFFFF }, { 0x1231, 0x1503, 0x1415, 0x1807, 0x102B, 0x0F2D, 0x171D, 0xFFFF }, { 0x0A16, 0x033C, 0x0C1E, 0x1401, 0x1133,
- 0x1225, 0x0E37, 0x161B, 0xFFFF }, { 0x0922, 0x0B04, 0x0E0A, 0x1321, 0x1129, 0xFFFF }, { 0x0C39, 0x1D0B, 0x191F, 0xFFFF
- }, { 0x082A, 0x1413, 0x1705, 0x1517, 0xFFFF }, { 0x0930, 0x0A14, 0x0736, 0x0D08, 0x1323, 0x1035, 0x1227, 0xFFFF }, {
- 0x0A00, 0x0924, 0x0C06, 0x0638, 0x1B09, 0x0A3B, 0x0E2F, 0xFFFF }, { 0x0B1A, 0x1411, 0x1619, 0x073D, 0xFFFF }, { 0x1331,
- 0x1603, 0x1515, 0x1907, 0x112B, 0xFFFF }, { 0x0A12, 0x0834, 0x053A, 0x1501, 0x1233, 0x1325, 0x0F37, 0x171B, 0x102D,
- 0x181D, 0xFFFF }, { 0x0926, 0x072E, 0x1229, 0xFFFF }, { 0x1421, 0x0D39, 0x1E0B, 0x1A1F, 0xFFFF }, { 0x0A10, 0x1513,
- 0x1617, 0xFFFF }, { 0x0B18, 0x082C, 0x1135, 0x1805, 0x1327, 0xFFFF }, { 0x0932, 0x0B02, 0x1423, 0x0B3B, 0x0F2F, 0xFFFF
- }, { 0x0928, 0x0C1C, 0x1511, 0x1719, 0x1C09, 0xFFFF }, { 0x0A20, 0x1703, 0x1615, 0x1A07, 0x122B, 0x083D, 0xFFFF }, {
- 0x1431, 0x1601, 0x1333, 0x112D, 0x191D, 0xFFFF }, { 0x0B16, 0x043C, 0x0D1E, 0x1425, 0x1037, 0x1329, 0x181B, 0xFFFF }, {
- 0x0A22, 0x0C04, 0x0F0A, 0x1521, 0x0E39, 0x1F0B, 0x1B1F, 0xFFFF }, { 0x1613, 0x1717, 0xFFFF }, { 0x092A, 0x1235, 0x1905,
- 0xFFFF }, { 0x0A30, 0x0B14, 0x0836, 0x0E08, 0x1523, 0x1427, 0xFFFF }, { 0x0B00, 0x0A24, 0x0D06, 0x0738, 0x1611, 0x1D09,
- 0x0C3B, 0x102F, 0xFFFF }, { 0x0C1A, 0x1715, 0x1B07, 0x1819, 0x132B, 0x093D, 0xFFFF }, { 0x1531, 0x1701, 0x1803, 0x122D,
- 0x1A1D, 0xFFFF }, { 0x0B12, 0x0934, 0x063A, 0x1433, 0x1525, 0x1137, 0x191B, 0xFFFF }, { 0x0A26, 0x003E, 0x082E, 0x1621,
- 0x0F39, 0x1429, 0x003F, 0xFFFF }, { 0x1713, 0x1C1F, 0xFFFF }, { 0x0B10, 0x1335, 0x1A05, 0x1817, 0xFFFF }, { 0x0C18,
- 0x092C, 0x1623, 0x1527, 0xFFFF }, { 0x0A32, 0x0C02, 0x1711, 0x1E09, 0x0D3B, 0x112F, 0xFFFF }, { 0x0A28, 0x0D1C, 0x1919,
- 0x0A3D, 0xFFFF }, { 0x0B20, 0x1631, 0x1903, 0x1815, 0x1C07, 0x142B, 0x132D, 0x1B1D, 0xFFFF }, { 0x1801, 0x1533, 0x1625,
- 0x1237, 0x1A1B, 0xFFFF }, { 0x0C16, 0x053C, 0x0E1E, 0x1721, 0x1529, 0x013F, 0xFFFF }, { 0x0B22, 0x0D04, 0x1039, 0x1D1F,
- 0xFFFF }, { 0x1813, 0x1B05, 0x1917, 0xFFFF }, { 0x0A2A, 0x1723, 0x1435, 0x1627, 0xFFFF }, { 0x0B30, 0x0C14, 0x0936,
- 0x0F08, 0x1F09, 0x0E3B, 0x122F, 0xFFFF }, { 0x0C00, 0x0B24, 0x0E06, 0x0838, 0x1811, 0x1A19, 0x0B3D, 0xFFFF }, { 0x0D1A,
- 0x1731, 0x1A03, 0x1915, 0x1D07, 0x152B, 0xFFFF }, { 0x1901, 0x1633, 0x1725, 0x1337, 0x1B1B, 0x142D, 0x1C1D, 0xFFFF }, {
- 0x0C12, 0x0A34, 0x073A, 0x1629, 0x023F, 0xFFFF }, { 0x0B26, 0x013E, 0x092E, 0x1821, 0x1139, 0x1E1F, 0xFFFF }, { 0x1913,
- 0x1A17, 0xFFFF }, { 0x0C10, 0x1535, 0x1C05, 0x1727, 0xFFFF }, { 0x0D18, 0x0A2C, 0x1823, 0x0F3B, 0x132F, 0xFFFF }, {
- 0x0B32, 0x0D02, 0x1911, 0x1B19, 0xFFFF }, { 0x0B28, 0x0E1C, 0x1B03, 0x1A15, 0x1E07, 0x162B, 0x0C3D, 0xFFFF }, { 0x0C20,
- 0x1831, 0x1A01, 0x1733, 0x152D, 0x1D1D, 0xFFFF }, { 0x1825, 0x1437, 0x1729, 0x1C1B, 0x033F, 0xFFFF }, { 0x0D16, 0x063C,
- 0x0F1E, 0x1921, 0x1239, 0x1F1F, 0xFFFF }, { 0x0C22, 0x0E04, 0x1A13, 0x1B17, 0xFFFF }, { 0x1635, 0x1D05, 0xFFFF }, {
- 0x0B2A, 0x1923, 0x1827, 0xFFFF }, { 0x0C30, 0x0D14, 0x0A36, 0x1A11, 0x103B, 0x142F, 0xFFFF }, { 0x0D00, 0x0C24, 0x0F06,
- 0x0938, 0x1B15, 0x1F07, 0x1C19, 0x172B, 0x0D3D, 0xFFFF }, { 0x0E1A, 0x1931, 0x1B01, 0x1C03, 0x162D, 0x1E1D, 0xFFFF }, {
- 0x1833, 0x1925, 0x1537, 0x1D1B, 0xFFFF }, { 0x0D12, 0x0B34, 0x083A, 0x1A21, 0x1339, 0x1829, 0x043F, 0xFFFF }, { 0x0C26,
- 0x023E, 0x0A2E, 0x1B13, 0xFFFF }, { 0x1735, 0x1E05, 0x1C17, 0xFFFF }, { 0x0D10, 0x1A23, 0x1927, 0xFFFF }, { 0x0E18,
- 0x0B2C, 0x1B11, 0x113B, 0x152F, 0xFFFF }, { 0x0C32, 0x0E02, 0x1D19, 0x0E3D, 0xFFFF }, { 0x0C28, 0x0F1C, 0x1A31, 0x1D03,
- 0x1C15, 0x182B, 0x172D, 0x1F1D, 0xFFFF }, { 0x0D20, 0x1C01, 0x1933, 0x1A25, 0x1637, 0x1E1B, 0xFFFF }, { 0x1B21, 0x1929,
- 0x053F, 0xFFFF }, { 0x0E16, 0x073C, 0x1439, 0xFFFF }, { 0x0D22, 0x0F04, 0x1C13, 0x1F05, 0x1D17, 0xFFFF }, { 0x1B23,
- 0x1835, 0x1A27, 0xFFFF }, { 0x0C2A, 0x123B, 0x162F, 0xFFFF }, { 0x0D30, 0x0E14, 0x0B36, 0x1C11, 0x1E19, 0x0F3D, 0xFFFF
- }, { 0x0E00, 0x0D24, 0x0A38, 0x1B31, 0x1E03, 0x1D15, 0x192B, 0xFFFF }, { 0x0F1A, 0x1D01, 0x1A33, 0x1B25, 0x1737, 0x1F1B,
- 0x182D, 0xFFFF }, { 0x1A29, 0x063F, 0xFFFF }, { 0x0E12, 0x0C34, 0x093A, 0x1C21, 0x1539, 0xFFFF }, { 0x0D26, 0x033E,
- 0x0B2E, 0x1D13, 0x1E17, 0xFFFF }, { 0x1935, 0x1B27, 0xFFFF }, { 0x0E10, 0x1C23, 0x133B, 0x172F, 0xFFFF }, { 0x0F18,
- 0x0C2C, 0x1D11, 0x1F19, 0xFFFF }, { 0x0D32, 0x0F02, 0x1F03, 0x1E15, 0x1A2B, 0x103D, 0xFFFF }, { 0x0D28, 0x1C31, 0x1E01,
- 0x1B33, 0x192D, 0xFFFF }, { 0x0E20, 0x1C25, 0x1837, 0x1B29, 0x073F, 0xFFFF }, { 0x1D21, 0x1639, 0xFFFF }, { 0x0F16,
- 0x083C, 0x1E13, 0x1F17, 0xFFFF }, { 0x0E22, 0x1A35, 0xFFFF }, { 0x1D23, 0x1C27, 0xFFFF }, { 0x0D2A, 0x1E11, 0x143B,
- 0x182F, 0xFFFF }, { 0x0E30, 0x0F14, 0x0C36, 0x1F15, 0x1B2B, 0x113D, 0xFFFF }, { 0x0F00, 0x0E24, 0x0B38, 0x1D31, 0x1F01,
- 0x1A2D, 0xFFFF }, { 0x1C33, 0x1D25, 0x1937, 0xFFFF }, { 0x1E21, 0x1739, 0x1C29, 0x083F, 0xFFFF }, { 0x0F12, 0x0D34,
- 0x0A3A, 0x1F13, 0xFFFF }, { 0x0E26, 0x043E, 0x0C2E, 0x1B35, 0xFFFF }, { 0x1E23, 0x1D27, 0xFFFF }, { 0x0F10, 0x1F11,
- 0x153B, 0x192F, 0xFFFF }, { 0x0D2C, 0x123D, 0xFFFF },
- };
-
- struct etc1_block
- {
- // big endian uint64:
- // bit ofs: 56 48 40 32 24 16 8 0
- // byte ofs: b0, b1, b2, b3, b4, b5, b6, b7
- union
- {
- uint64 m_uint64;
- uint8 m_bytes[8];
- };
-
- uint8 m_low_color[2];
- uint8 m_high_color[2];
-
- enum { cNumSelectorBytes = 4 };
- uint8 m_selectors[cNumSelectorBytes];
-
- inline void clear()
- {
- zero_this(this);
- }
-
- inline uint get_byte_bits(uint ofs, uint num) const
- {
- RG_ETC1_ASSERT((ofs + num) <= 64U);
- RG_ETC1_ASSERT(num && (num <= 8U));
- RG_ETC1_ASSERT((ofs >> 3) == ((ofs + num - 1) >> 3));
- const uint byte_ofs = 7 - (ofs >> 3);
- const uint byte_bit_ofs = ofs & 7;
- return (m_bytes[byte_ofs] >> byte_bit_ofs) & ((1 << num) - 1);
- }
-
- inline void set_byte_bits(uint ofs, uint num, uint bits)
- {
- RG_ETC1_ASSERT((ofs + num) <= 64U);
- RG_ETC1_ASSERT(num && (num < 32U));
- RG_ETC1_ASSERT((ofs >> 3) == ((ofs + num - 1) >> 3));
- RG_ETC1_ASSERT(bits < (1U << num));
- const uint byte_ofs = 7 - (ofs >> 3);
- const uint byte_bit_ofs = ofs & 7;
- const uint mask = (1 << num) - 1;
- m_bytes[byte_ofs] &= ~(mask << byte_bit_ofs);
- m_bytes[byte_ofs] |= (bits << byte_bit_ofs);
- }
-
- // false = left/right subblocks
- // true = upper/lower subblocks
- inline bool get_flip_bit() const
- {
- return (m_bytes[3] & 1) != 0;
- }
-
- inline void set_flip_bit(bool flip)
- {
- m_bytes[3] &= ~1;
- m_bytes[3] |= static_cast<uint8>(flip);
- }
-
- inline bool get_diff_bit() const
- {
- return (m_bytes[3] & 2) != 0;
- }
-
- inline void set_diff_bit(bool diff)
- {
- m_bytes[3] &= ~2;
- m_bytes[3] |= (static_cast<uint>(diff) << 1);
- }
-
- // Returns intensity modifier table (0-7) used by subblock subblock_id.
- // subblock_id=0 left/top (CW 1), 1=right/bottom (CW 2)
- inline uint get_inten_table(uint subblock_id) const
- {
- RG_ETC1_ASSERT(subblock_id < 2);
- const uint ofs = subblock_id ? 2 : 5;
- return (m_bytes[3] >> ofs) & 7;
- }
-
- // Sets intensity modifier table (0-7) used by subblock subblock_id (0 or 1)
- inline void set_inten_table(uint subblock_id, uint t)
- {
- RG_ETC1_ASSERT(subblock_id < 2);
- RG_ETC1_ASSERT(t < 8);
- const uint ofs = subblock_id ? 2 : 5;
- m_bytes[3] &= ~(7 << ofs);
- m_bytes[3] |= (t << ofs);
- }
-
- // Returned selector value ranges from 0-3 and is a direct index into g_etc1_inten_tables.
- inline uint get_selector(uint x, uint y) const
- {
- RG_ETC1_ASSERT((x | y) < 4);
-
- const uint bit_index = x * 4 + y;
- const uint byte_bit_ofs = bit_index & 7;
- const uint8 *p = &m_bytes[7 - (bit_index >> 3)];
- const uint lsb = (p[0] >> byte_bit_ofs) & 1;
- const uint msb = (p[-2] >> byte_bit_ofs) & 1;
- const uint val = lsb | (msb << 1);
-
- return g_etc1_to_selector_index[val];
- }
-
- // Selector "val" ranges from 0-3 and is a direct index into g_etc1_inten_tables.
- inline void set_selector(uint x, uint y, uint val)
- {
- RG_ETC1_ASSERT((x | y | val) < 4);
- const uint bit_index = x * 4 + y;
-
- uint8 *p = &m_bytes[7 - (bit_index >> 3)];
-
- const uint byte_bit_ofs = bit_index & 7;
- const uint mask = 1 << byte_bit_ofs;
-
- const uint etc1_val = g_selector_index_to_etc1[val];
-
- const uint lsb = etc1_val & 1;
- const uint msb = etc1_val >> 1;
-
- p[0] &= ~mask;
- p[0] |= (lsb << byte_bit_ofs);
-
- p[-2] &= ~mask;
- p[-2] |= (msb << byte_bit_ofs);
- }
-
- inline void set_base4_color(uint idx, uint16 c)
- {
- if (idx)
- {
- set_byte_bits(cETC1AbsColor4R2BitOffset, 4, (c >> 8) & 15);
- set_byte_bits(cETC1AbsColor4G2BitOffset, 4, (c >> 4) & 15);
- set_byte_bits(cETC1AbsColor4B2BitOffset, 4, c & 15);
- }
- else
- {
- set_byte_bits(cETC1AbsColor4R1BitOffset, 4, (c >> 8) & 15);
- set_byte_bits(cETC1AbsColor4G1BitOffset, 4, (c >> 4) & 15);
- set_byte_bits(cETC1AbsColor4B1BitOffset, 4, c & 15);
- }
- }
-
- inline uint16 get_base4_color(uint idx) const
- {
- uint r, g, b;
- if (idx)
- {
- r = get_byte_bits(cETC1AbsColor4R2BitOffset, 4);
- g = get_byte_bits(cETC1AbsColor4G2BitOffset, 4);
- b = get_byte_bits(cETC1AbsColor4B2BitOffset, 4);
- }
- else
- {
- r = get_byte_bits(cETC1AbsColor4R1BitOffset, 4);
- g = get_byte_bits(cETC1AbsColor4G1BitOffset, 4);
- b = get_byte_bits(cETC1AbsColor4B1BitOffset, 4);
- }
- return static_cast<uint16>(b | (g << 4U) | (r << 8U));
- }
-
- inline void set_base5_color(uint16 c)
- {
- set_byte_bits(cETC1BaseColor5RBitOffset, 5, (c >> 10) & 31);
- set_byte_bits(cETC1BaseColor5GBitOffset, 5, (c >> 5) & 31);
- set_byte_bits(cETC1BaseColor5BBitOffset, 5, c & 31);
- }
-
- inline uint16 get_base5_color() const
- {
- const uint r = get_byte_bits(cETC1BaseColor5RBitOffset, 5);
- const uint g = get_byte_bits(cETC1BaseColor5GBitOffset, 5);
- const uint b = get_byte_bits(cETC1BaseColor5BBitOffset, 5);
- return static_cast<uint16>(b | (g << 5U) | (r << 10U));
- }
-
- void set_delta3_color(uint16 c)
- {
- set_byte_bits(cETC1DeltaColor3RBitOffset, 3, (c >> 6) & 7);
- set_byte_bits(cETC1DeltaColor3GBitOffset, 3, (c >> 3) & 7);
- set_byte_bits(cETC1DeltaColor3BBitOffset, 3, c & 7);
- }
-
- inline uint16 get_delta3_color() const
- {
- const uint r = get_byte_bits(cETC1DeltaColor3RBitOffset, 3);
- const uint g = get_byte_bits(cETC1DeltaColor3GBitOffset, 3);
- const uint b = get_byte_bits(cETC1DeltaColor3BBitOffset, 3);
- return static_cast<uint16>(b | (g << 3U) | (r << 6U));
- }
-
- // Base color 5
- static uint16 pack_color5(const color_quad_u8& color, bool scaled, uint bias = 127U);
- static uint16 pack_color5(uint r, uint g, uint b, bool scaled, uint bias = 127U);
-
- static color_quad_u8 unpack_color5(uint16 packed_color5, bool scaled, uint alpha = 255U);
- static void unpack_color5(uint& r, uint& g, uint& b, uint16 packed_color, bool scaled);
-
- static bool unpack_color5(color_quad_u8& result, uint16 packed_color5, uint16 packed_delta3, bool scaled, uint alpha = 255U);
- static bool unpack_color5(uint& r, uint& g, uint& b, uint16 packed_color5, uint16 packed_delta3, bool scaled, uint alpha = 255U);
-
- // Delta color 3
- // Inputs range from -4 to 3 (cETC1ColorDeltaMin to cETC1ColorDeltaMax)
- static uint16 pack_delta3(int r, int g, int b);
-
- // Results range from -4 to 3 (cETC1ColorDeltaMin to cETC1ColorDeltaMax)
- static void unpack_delta3(int& r, int& g, int& b, uint16 packed_delta3);
-
- // Abs color 4
- static uint16 pack_color4(const color_quad_u8& color, bool scaled, uint bias = 127U);
- static uint16 pack_color4(uint r, uint g, uint b, bool scaled, uint bias = 127U);
-
- static color_quad_u8 unpack_color4(uint16 packed_color4, bool scaled, uint alpha = 255U);
- static void unpack_color4(uint& r, uint& g, uint& b, uint16 packed_color4, bool scaled);
-
- // subblock colors
- static void get_diff_subblock_colors(color_quad_u8* pDst, uint16 packed_color5, uint table_idx);
- static bool get_diff_subblock_colors(color_quad_u8* pDst, uint16 packed_color5, uint16 packed_delta3, uint table_idx);
- static void get_abs_subblock_colors(color_quad_u8* pDst, uint16 packed_color4, uint table_idx);
-
- static inline void unscaled_to_scaled_color(color_quad_u8& dst, const color_quad_u8& src, bool color4)
- {
- if (color4)
- {
- dst.r = src.r | (src.r << 4);
- dst.g = src.g | (src.g << 4);
- dst.b = src.b | (src.b << 4);
- }
- else
- {
- dst.r = (src.r >> 2) | (src.r << 3);
- dst.g = (src.g >> 2) | (src.g << 3);
- dst.b = (src.b >> 2) | (src.b << 3);
- }
- dst.a = src.a;
- }
- };
-
- // Returns pointer to sorted array.
- template<typename T, typename Q>
- T* indirect_radix_sort(uint num_indices, T* pIndices0, T* pIndices1, const Q* pKeys, uint key_ofs, uint key_size, bool init_indices)
- {
- RG_ETC1_ASSERT((key_ofs >= 0) && (key_ofs < sizeof(T)));
- RG_ETC1_ASSERT((key_size >= 1) && (key_size <= 4));
-
- if (init_indices)
- {
- T* p = pIndices0;
- T* q = pIndices0 + (num_indices >> 1) * 2;
- uint i;
- for (i = 0; p != q; p += 2, i += 2)
- {
- p[0] = static_cast<T>(i);
- p[1] = static_cast<T>(i + 1);
- }
-
- if (num_indices & 1)
- *p = static_cast<T>(i);
- }
-
- uint hist[256 * 4];
-
- memset(hist, 0, sizeof(hist[0]) * 256 * key_size);
-
-#define RG_ETC1_GET_KEY(p) (*(const uint*)((const uint8*)(pKeys + *(p)) + key_ofs))
-#define RG_ETC1_GET_KEY_FROM_INDEX(i) (*(const uint*)((const uint8*)(pKeys + (i)) + key_ofs))
-
- if (key_size == 4)
- {
- T* p = pIndices0;
- T* q = pIndices0 + num_indices;
- for ( ; p != q; p++)
- {
- const uint key = RG_ETC1_GET_KEY(p);
-
- hist[ key & 0xFF]++;
- hist[256 + ((key >> 8) & 0xFF)]++;
- hist[512 + ((key >> 16) & 0xFF)]++;
- hist[768 + ((key >> 24) & 0xFF)]++;
- }
- }
- else if (key_size == 3)
- {
- T* p = pIndices0;
- T* q = pIndices0 + num_indices;
- for ( ; p != q; p++)
- {
- const uint key = RG_ETC1_GET_KEY(p);
-
- hist[ key & 0xFF]++;
- hist[256 + ((key >> 8) & 0xFF)]++;
- hist[512 + ((key >> 16) & 0xFF)]++;
- }
- }
- else if (key_size == 2)
- {
- T* p = pIndices0;
- T* q = pIndices0 + (num_indices >> 1) * 2;
-
- for ( ; p != q; p += 2)
- {
- const uint key0 = RG_ETC1_GET_KEY(p);
- const uint key1 = RG_ETC1_GET_KEY(p+1);
-
- hist[ key0 & 0xFF]++;
- hist[256 + ((key0 >> 8) & 0xFF)]++;
-
- hist[ key1 & 0xFF]++;
- hist[256 + ((key1 >> 8) & 0xFF)]++;
- }
-
- if (num_indices & 1)
- {
- const uint key = RG_ETC1_GET_KEY(p);
-
- hist[ key & 0xFF]++;
- hist[256 + ((key >> 8) & 0xFF)]++;
- }
- }
- else
- {
- RG_ETC1_ASSERT(key_size == 1);
- if (key_size != 1)
- return NULL;
-
- T* p = pIndices0;
- T* q = pIndices0 + (num_indices >> 1) * 2;
-
- for ( ; p != q; p += 2)
- {
- const uint key0 = RG_ETC1_GET_KEY(p);
- const uint key1 = RG_ETC1_GET_KEY(p+1);
-
- hist[key0 & 0xFF]++;
- hist[key1 & 0xFF]++;
- }
-
- if (num_indices & 1)
- {
- const uint key = RG_ETC1_GET_KEY(p);
-
- hist[key & 0xFF]++;
- }
- }
-
- T* pCur = pIndices0;
- T* pNew = pIndices1;
-
- for (uint pass = 0; pass < key_size; pass++)
- {
- const uint* pHist = &hist[pass << 8];
-
- uint offsets[256];
-
- uint cur_ofs = 0;
- for (uint i = 0; i < 256; i += 2)
- {
- offsets[i] = cur_ofs;
- cur_ofs += pHist[i];
-
- offsets[i+1] = cur_ofs;
- cur_ofs += pHist[i+1];
- }
-
- const uint pass_shift = pass << 3;
-
- T* p = pCur;
- T* q = pCur + (num_indices >> 1) * 2;
-
- for ( ; p != q; p += 2)
- {
- uint index0 = p[0];
- uint index1 = p[1];
-
- uint c0 = (RG_ETC1_GET_KEY_FROM_INDEX(index0) >> pass_shift) & 0xFF;
- uint c1 = (RG_ETC1_GET_KEY_FROM_INDEX(index1) >> pass_shift) & 0xFF;
-
- if (c0 == c1)
- {
- uint dst_offset0 = offsets[c0];
-
- offsets[c0] = dst_offset0 + 2;
-
- pNew[dst_offset0] = static_cast<T>(index0);
- pNew[dst_offset0 + 1] = static_cast<T>(index1);
- }
- else
- {
- uint dst_offset0 = offsets[c0]++;
- uint dst_offset1 = offsets[c1]++;
-
- pNew[dst_offset0] = static_cast<T>(index0);
- pNew[dst_offset1] = static_cast<T>(index1);
- }
- }
-
- if (num_indices & 1)
- {
- uint index = *p;
- uint c = (RG_ETC1_GET_KEY_FROM_INDEX(index) >> pass_shift) & 0xFF;
-
- uint dst_offset = offsets[c];
- offsets[c] = dst_offset + 1;
-
- pNew[dst_offset] = static_cast<T>(index);
- }
-
- T* t = pCur;
- pCur = pNew;
- pNew = t;
- }
-
- return pCur;
- }
-
-#undef RG_ETC1_GET_KEY
-#undef RG_ETC1_GET_KEY_FROM_INDEX
-
- uint16 etc1_block::pack_color5(const color_quad_u8& color, bool scaled, uint bias)
- {
- return pack_color5(color.r, color.g, color.b, scaled, bias);
- }
-
- uint16 etc1_block::pack_color5(uint r, uint g, uint b, bool scaled, uint bias)
- {
- if (scaled)
- {
- r = (r * 31U + bias) / 255U;
- g = (g * 31U + bias) / 255U;
- b = (b * 31U + bias) / 255U;
- }
-
- r = rg_etc1::minimum(r, 31U);
- g = rg_etc1::minimum(g, 31U);
- b = rg_etc1::minimum(b, 31U);
-
- return static_cast<uint16>(b | (g << 5U) | (r << 10U));
- }
-
- color_quad_u8 etc1_block::unpack_color5(uint16 packed_color5, bool scaled, uint alpha)
- {
- uint b = packed_color5 & 31U;
- uint g = (packed_color5 >> 5U) & 31U;
- uint r = (packed_color5 >> 10U) & 31U;
-
- if (scaled)
- {
- b = (b << 3U) | (b >> 2U);
- g = (g << 3U) | (g >> 2U);
- r = (r << 3U) | (r >> 2U);
- }
-
- return color_quad_u8(cNoClamp, r, g, b, rg_etc1::minimum(alpha, 255U));
- }
-
- void etc1_block::unpack_color5(uint& r, uint& g, uint& b, uint16 packed_color5, bool scaled)
- {
- color_quad_u8 c(unpack_color5(packed_color5, scaled, 0));
- r = c.r;
- g = c.g;
- b = c.b;
- }
-
- bool etc1_block::unpack_color5(color_quad_u8& result, uint16 packed_color5, uint16 packed_delta3, bool scaled, uint alpha)
- {
- int dc_r, dc_g, dc_b;
- unpack_delta3(dc_r, dc_g, dc_b, packed_delta3);
-
- int b = (packed_color5 & 31U) + dc_b;
- int g = ((packed_color5 >> 5U) & 31U) + dc_g;
- int r = ((packed_color5 >> 10U) & 31U) + dc_r;
-
- bool success = true;
- if (static_cast<uint>(r | g | b) > 31U)
- {
- success = false;
- r = rg_etc1::clamp<int>(r, 0, 31);
- g = rg_etc1::clamp<int>(g, 0, 31);
- b = rg_etc1::clamp<int>(b, 0, 31);
- }
-
- if (scaled)
- {
- b = (b << 3U) | (b >> 2U);
- g = (g << 3U) | (g >> 2U);
- r = (r << 3U) | (r >> 2U);
- }
-
- result.set_noclamp_rgba(r, g, b, rg_etc1::minimum(alpha, 255U));
- return success;
- }
-
- bool etc1_block::unpack_color5(uint& r, uint& g, uint& b, uint16 packed_color5, uint16 packed_delta3, bool scaled, uint alpha)
- {
- color_quad_u8 result;
- const bool success = unpack_color5(result, packed_color5, packed_delta3, scaled, alpha);
- r = result.r;
- g = result.g;
- b = result.b;
- return success;
- }
-
- uint16 etc1_block::pack_delta3(int r, int g, int b)
- {
- RG_ETC1_ASSERT((r >= cETC1ColorDeltaMin) && (r <= cETC1ColorDeltaMax));
- RG_ETC1_ASSERT((g >= cETC1ColorDeltaMin) && (g <= cETC1ColorDeltaMax));
- RG_ETC1_ASSERT((b >= cETC1ColorDeltaMin) && (b <= cETC1ColorDeltaMax));
- if (r < 0) r += 8;
- if (g < 0) g += 8;
- if (b < 0) b += 8;
- return static_cast<uint16>(b | (g << 3) | (r << 6));
- }
-
- void etc1_block::unpack_delta3(int& r, int& g, int& b, uint16 packed_delta3)
- {
- r = (packed_delta3 >> 6) & 7;
- g = (packed_delta3 >> 3) & 7;
- b = packed_delta3 & 7;
- if (r >= 4) r -= 8;
- if (g >= 4) g -= 8;
- if (b >= 4) b -= 8;
- }
-
- uint16 etc1_block::pack_color4(const color_quad_u8& color, bool scaled, uint bias)
- {
- return pack_color4(color.r, color.g, color.b, scaled, bias);
- }
-
- uint16 etc1_block::pack_color4(uint r, uint g, uint b, bool scaled, uint bias)
- {
- if (scaled)
- {
- r = (r * 15U + bias) / 255U;
- g = (g * 15U + bias) / 255U;
- b = (b * 15U + bias) / 255U;
- }
-
- r = rg_etc1::minimum(r, 15U);
- g = rg_etc1::minimum(g, 15U);
- b = rg_etc1::minimum(b, 15U);
-
- return static_cast<uint16>(b | (g << 4U) | (r << 8U));
- }
-
- color_quad_u8 etc1_block::unpack_color4(uint16 packed_color4, bool scaled, uint alpha)
- {
- uint b = packed_color4 & 15U;
- uint g = (packed_color4 >> 4U) & 15U;
- uint r = (packed_color4 >> 8U) & 15U;
-
- if (scaled)
- {
- b = (b << 4U) | b;
- g = (g << 4U) | g;
- r = (r << 4U) | r;
- }
-
- return color_quad_u8(cNoClamp, r, g, b, rg_etc1::minimum(alpha, 255U));
- }
-
- void etc1_block::unpack_color4(uint& r, uint& g, uint& b, uint16 packed_color4, bool scaled)
- {
- color_quad_u8 c(unpack_color4(packed_color4, scaled, 0));
- r = c.r;
- g = c.g;
- b = c.b;
- }
-
- void etc1_block::get_diff_subblock_colors(color_quad_u8* pDst, uint16 packed_color5, uint table_idx)
- {
- RG_ETC1_ASSERT(table_idx < cETC1IntenModifierValues);
- const int *pInten_modifer_table = &g_etc1_inten_tables[table_idx][0];
-
- uint r, g, b;
- unpack_color5(r, g, b, packed_color5, true);
-
- const int ir = static_cast<int>(r), ig = static_cast<int>(g), ib = static_cast<int>(b);
-
- const int y0 = pInten_modifer_table[0];
- pDst[0].set(ir + y0, ig + y0, ib + y0);
-
- const int y1 = pInten_modifer_table[1];
- pDst[1].set(ir + y1, ig + y1, ib + y1);
-
- const int y2 = pInten_modifer_table[2];
- pDst[2].set(ir + y2, ig + y2, ib + y2);
-
- const int y3 = pInten_modifer_table[3];
- pDst[3].set(ir + y3, ig + y3, ib + y3);
- }
-
- bool etc1_block::get_diff_subblock_colors(color_quad_u8* pDst, uint16 packed_color5, uint16 packed_delta3, uint table_idx)
- {
- RG_ETC1_ASSERT(table_idx < cETC1IntenModifierValues);
- const int *pInten_modifer_table = &g_etc1_inten_tables[table_idx][0];
-
- uint r, g, b;
- bool success = unpack_color5(r, g, b, packed_color5, packed_delta3, true);
-
- const int ir = static_cast<int>(r), ig = static_cast<int>(g), ib = static_cast<int>(b);
-
- const int y0 = pInten_modifer_table[0];
- pDst[0].set(ir + y0, ig + y0, ib + y0);
-
- const int y1 = pInten_modifer_table[1];
- pDst[1].set(ir + y1, ig + y1, ib + y1);
-
- const int y2 = pInten_modifer_table[2];
- pDst[2].set(ir + y2, ig + y2, ib + y2);
-
- const int y3 = pInten_modifer_table[3];
- pDst[3].set(ir + y3, ig + y3, ib + y3);
-
- return success;
- }
-
- void etc1_block::get_abs_subblock_colors(color_quad_u8* pDst, uint16 packed_color4, uint table_idx)
- {
- RG_ETC1_ASSERT(table_idx < cETC1IntenModifierValues);
- const int *pInten_modifer_table = &g_etc1_inten_tables[table_idx][0];
-
- uint r, g, b;
- unpack_color4(r, g, b, packed_color4, true);
-
- const int ir = static_cast<int>(r), ig = static_cast<int>(g), ib = static_cast<int>(b);
-
- const int y0 = pInten_modifer_table[0];
- pDst[0].set(ir + y0, ig + y0, ib + y0);
-
- const int y1 = pInten_modifer_table[1];
- pDst[1].set(ir + y1, ig + y1, ib + y1);
-
- const int y2 = pInten_modifer_table[2];
- pDst[2].set(ir + y2, ig + y2, ib + y2);
-
- const int y3 = pInten_modifer_table[3];
- pDst[3].set(ir + y3, ig + y3, ib + y3);
- }
-
- bool unpack_etc1_block(const void* pETC1_block, unsigned int* pDst_pixels_rgba, bool preserve_alpha)
- {
- color_quad_u8* pDst = reinterpret_cast<color_quad_u8*>(pDst_pixels_rgba);
- const etc1_block& block = *static_cast<const etc1_block*>(pETC1_block);
-
- const bool diff_flag = block.get_diff_bit();
- const bool flip_flag = block.get_flip_bit();
- const uint table_index0 = block.get_inten_table(0);
- const uint table_index1 = block.get_inten_table(1);
-
- color_quad_u8 subblock_colors0[4];
- color_quad_u8 subblock_colors1[4];
- bool success = true;
-
- if (diff_flag)
- {
- const uint16 base_color5 = block.get_base5_color();
- const uint16 delta_color3 = block.get_delta3_color();
- etc1_block::get_diff_subblock_colors(subblock_colors0, base_color5, table_index0);
-
- if (!etc1_block::get_diff_subblock_colors(subblock_colors1, base_color5, delta_color3, table_index1))
- success = false;
- }
- else
- {
- const uint16 base_color4_0 = block.get_base4_color(0);
- etc1_block::get_abs_subblock_colors(subblock_colors0, base_color4_0, table_index0);
-
- const uint16 base_color4_1 = block.get_base4_color(1);
- etc1_block::get_abs_subblock_colors(subblock_colors1, base_color4_1, table_index1);
- }
-
- if (preserve_alpha)
- {
- if (flip_flag)
- {
- for (uint y = 0; y < 2; y++)
- {
- pDst[0].set_rgb(subblock_colors0[block.get_selector(0, y)]);
- pDst[1].set_rgb(subblock_colors0[block.get_selector(1, y)]);
- pDst[2].set_rgb(subblock_colors0[block.get_selector(2, y)]);
- pDst[3].set_rgb(subblock_colors0[block.get_selector(3, y)]);
- pDst += 4;
- }
-
- for (uint y = 2; y < 4; y++)
- {
- pDst[0].set_rgb(subblock_colors1[block.get_selector(0, y)]);
- pDst[1].set_rgb(subblock_colors1[block.get_selector(1, y)]);
- pDst[2].set_rgb(subblock_colors1[block.get_selector(2, y)]);
- pDst[3].set_rgb(subblock_colors1[block.get_selector(3, y)]);
- pDst += 4;
- }
- }
- else
- {
- for (uint y = 0; y < 4; y++)
- {
- pDst[0].set_rgb(subblock_colors0[block.get_selector(0, y)]);
- pDst[1].set_rgb(subblock_colors0[block.get_selector(1, y)]);
- pDst[2].set_rgb(subblock_colors1[block.get_selector(2, y)]);
- pDst[3].set_rgb(subblock_colors1[block.get_selector(3, y)]);
- pDst += 4;
- }
- }
- }
- else
- {
- if (flip_flag)
- {
- // 0000
- // 0000
- // 1111
- // 1111
- for (uint y = 0; y < 2; y++)
- {
- pDst[0] = subblock_colors0[block.get_selector(0, y)];
- pDst[1] = subblock_colors0[block.get_selector(1, y)];
- pDst[2] = subblock_colors0[block.get_selector(2, y)];
- pDst[3] = subblock_colors0[block.get_selector(3, y)];
- pDst += 4;
- }
-
- for (uint y = 2; y < 4; y++)
- {
- pDst[0] = subblock_colors1[block.get_selector(0, y)];
- pDst[1] = subblock_colors1[block.get_selector(1, y)];
- pDst[2] = subblock_colors1[block.get_selector(2, y)];
- pDst[3] = subblock_colors1[block.get_selector(3, y)];
- pDst += 4;
- }
- }
- else
- {
- // 0011
- // 0011
- // 0011
- // 0011
- for (uint y = 0; y < 4; y++)
- {
- pDst[0] = subblock_colors0[block.get_selector(0, y)];
- pDst[1] = subblock_colors0[block.get_selector(1, y)];
- pDst[2] = subblock_colors1[block.get_selector(2, y)];
- pDst[3] = subblock_colors1[block.get_selector(3, y)];
- pDst += 4;
- }
- }
- }
-
- return success;
- }
-
- struct etc1_solution_coordinates
- {
- inline etc1_solution_coordinates() :
- m_unscaled_color(0, 0, 0, 0),
- m_inten_table(0),
- m_color4(false)
- {
- }
-
- inline etc1_solution_coordinates(uint r, uint g, uint b, uint inten_table, bool color4) :
- m_unscaled_color(r, g, b, 255),
- m_inten_table(inten_table),
- m_color4(color4)
- {
- }
-
- inline etc1_solution_coordinates(const color_quad_u8& c, uint inten_table, bool color4) :
- m_unscaled_color(c),
- m_inten_table(inten_table),
- m_color4(color4)
- {
- }
-
- inline etc1_solution_coordinates(const etc1_solution_coordinates& other)
- {
- *this = other;
- }
-
- inline etc1_solution_coordinates& operator= (const etc1_solution_coordinates& rhs)
- {
- m_unscaled_color = rhs.m_unscaled_color;
- m_inten_table = rhs.m_inten_table;
- m_color4 = rhs.m_color4;
- return *this;
- }
-
- inline void clear()
- {
- m_unscaled_color.clear();
- m_inten_table = 0;
- m_color4 = false;
- }
-
- inline color_quad_u8 get_scaled_color() const
- {
- int br, bg, bb;
- if (m_color4)
- {
- br = m_unscaled_color.r | (m_unscaled_color.r << 4);
- bg = m_unscaled_color.g | (m_unscaled_color.g << 4);
- bb = m_unscaled_color.b | (m_unscaled_color.b << 4);
- }
- else
- {
- br = (m_unscaled_color.r >> 2) | (m_unscaled_color.r << 3);
- bg = (m_unscaled_color.g >> 2) | (m_unscaled_color.g << 3);
- bb = (m_unscaled_color.b >> 2) | (m_unscaled_color.b << 3);
- }
- return color_quad_u8(br, bg, bb);
- }
-
- inline void get_block_colors(color_quad_u8* pBlock_colors)
- {
- int br, bg, bb;
- if (m_color4)
- {
- br = m_unscaled_color.r | (m_unscaled_color.r << 4);
- bg = m_unscaled_color.g | (m_unscaled_color.g << 4);
- bb = m_unscaled_color.b | (m_unscaled_color.b << 4);
- }
- else
- {
- br = (m_unscaled_color.r >> 2) | (m_unscaled_color.r << 3);
- bg = (m_unscaled_color.g >> 2) | (m_unscaled_color.g << 3);
- bb = (m_unscaled_color.b >> 2) | (m_unscaled_color.b << 3);
- }
- const int* pInten_table = g_etc1_inten_tables[m_inten_table];
- pBlock_colors[0].set(br + pInten_table[0], bg + pInten_table[0], bb + pInten_table[0]);
- pBlock_colors[1].set(br + pInten_table[1], bg + pInten_table[1], bb + pInten_table[1]);
- pBlock_colors[2].set(br + pInten_table[2], bg + pInten_table[2], bb + pInten_table[2]);
- pBlock_colors[3].set(br + pInten_table[3], bg + pInten_table[3], bb + pInten_table[3]);
- }
-
- color_quad_u8 m_unscaled_color;
- uint m_inten_table;
- bool m_color4;
- };
-
- class etc1_optimizer
- {
- etc1_optimizer(const etc1_optimizer&);
- etc1_optimizer& operator= (const etc1_optimizer&);
-
- public:
- etc1_optimizer()
- {
- clear();
- }
-
- void clear()
- {
- m_pParams = NULL;
- m_pResult = NULL;
- m_pSorted_luma = NULL;
- m_pSorted_luma_indices = NULL;
- }
-
- struct params : etc1_pack_params
- {
- params()
- {
- clear();
- }
-
- params(const etc1_pack_params& base_params) :
- etc1_pack_params(base_params)
- {
- clear_optimizer_params();
- }
-
- void clear()
- {
- etc1_pack_params::clear();
- clear_optimizer_params();
- }
-
- void clear_optimizer_params()
- {
- m_num_src_pixels = 0;
- m_pSrc_pixels = 0;
-
- m_use_color4 = false;
- static const int s_default_scan_delta[] = { 0 };
- m_pScan_deltas = s_default_scan_delta;
- m_scan_delta_size = 1;
-
- m_base_color5.clear();
- m_constrain_against_base_color5 = false;
- }
-
- uint m_num_src_pixels;
- const color_quad_u8* m_pSrc_pixels;
-
- bool m_use_color4;
- const int* m_pScan_deltas;
- uint m_scan_delta_size;
-
- color_quad_u8 m_base_color5;
- bool m_constrain_against_base_color5;
- };
-
- struct results
- {
- uint64 m_error;
- color_quad_u8 m_block_color_unscaled;
- uint m_block_inten_table;
- uint m_n;
- uint8* m_pSelectors;
- bool m_block_color4;
-
- inline results& operator= (const results& rhs)
- {
- m_block_color_unscaled = rhs.m_block_color_unscaled;
- m_block_color4 = rhs.m_block_color4;
- m_block_inten_table = rhs.m_block_inten_table;
- m_error = rhs.m_error;
- RG_ETC1_ASSERT(m_n == rhs.m_n);
- memcpy(m_pSelectors, rhs.m_pSelectors, rhs.m_n);
- return *this;
- }
- };
-
- void init(const params& params, results& result);
- bool compute();
-
- private:
- struct potential_solution
- {
- potential_solution() : m_coords(), m_error(cUINT64_MAX), m_valid(false)
- {
- }
-
- etc1_solution_coordinates m_coords;
- uint8 m_selectors[8];
- uint64 m_error;
- bool m_valid;
-
- void clear()
- {
- m_coords.clear();
- m_error = cUINT64_MAX;
- m_valid = false;
- }
- };
-
- const params* m_pParams;
- results* m_pResult;
-
- int m_limit;
-
- vec3F m_avg_color;
- int m_br, m_bg, m_bb;
- uint16 m_luma[8];
- uint32 m_sorted_luma[2][8];
- const uint32* m_pSorted_luma_indices;
- uint32* m_pSorted_luma;
-
- uint8 m_selectors[8];
- uint8 m_best_selectors[8];
-
- potential_solution m_best_solution;
- potential_solution m_trial_solution;
- uint8 m_temp_selectors[8];
-
- bool evaluate_solution(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution);
- bool evaluate_solution_fast(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution);
- };
-
- bool etc1_optimizer::compute()
- {
- const uint n = m_pParams->m_num_src_pixels;
- const int scan_delta_size = m_pParams->m_scan_delta_size;
-
- // Scan through a subset of the 3D lattice centered around the avg block color trying each 3D (555 or 444) lattice point as a potential block color.
- // Each time a better solution is found try to refine the current solution's block color based of the current selectors and intensity table index.
- for (int zdi = 0; zdi < scan_delta_size; zdi++)
- {
- const int zd = m_pParams->m_pScan_deltas[zdi];
- const int mbb = m_bb + zd;
- if (mbb < 0) continue; else if (mbb > m_limit) break;
-
- for (int ydi = 0; ydi < scan_delta_size; ydi++)
- {
- const int yd = m_pParams->m_pScan_deltas[ydi];
- const int mbg = m_bg + yd;
- if (mbg < 0) continue; else if (mbg > m_limit) break;
-
- for (int xdi = 0; xdi < scan_delta_size; xdi++)
- {
- const int xd = m_pParams->m_pScan_deltas[xdi];
- const int mbr = m_br + xd;
- if (mbr < 0) continue; else if (mbr > m_limit) break;
-
- etc1_solution_coordinates coords(mbr, mbg, mbb, 0, m_pParams->m_use_color4);
- if (m_pParams->m_quality == cHighQuality)
- {
- if (!evaluate_solution(coords, m_trial_solution, &m_best_solution))
- continue;
- }
- else
- {
- if (!evaluate_solution_fast(coords, m_trial_solution, &m_best_solution))
- continue;
- }
-
- // Now we have the input block, the avg. color of the input pixels, a set of trial selector indices, and the block color+intensity index.
- // Now, for each component, attempt to refine the current solution by solving a simple linear equation. For example, for 4 colors:
- // The goal is:
- // pixel0 - (block_color+inten_table[selector0]) + pixel1 - (block_color+inten_table[selector1]) + pixel2 - (block_color+inten_table[selector2]) + pixel3 - (block_color+inten_table[selector3]) = 0
- // Rearranging this:
- // (pixel0 + pixel1 + pixel2 + pixel3) - (block_color+inten_table[selector0]) - (block_color+inten_table[selector1]) - (block_color+inten_table[selector2]) - (block_color+inten_table[selector3]) = 0
- // (pixel0 + pixel1 + pixel2 + pixel3) - block_color - inten_table[selector0] - block_color-inten_table[selector1] - block_color-inten_table[selector2] - block_color-inten_table[selector3] = 0
- // (pixel0 + pixel1 + pixel2 + pixel3) - 4*block_color - inten_table[selector0] - inten_table[selector1] - inten_table[selector2] - inten_table[selector3] = 0
- // (pixel0 + pixel1 + pixel2 + pixel3) - 4*block_color - (inten_table[selector0] + inten_table[selector1] + inten_table[selector2] + inten_table[selector3]) = 0
- // (pixel0 + pixel1 + pixel2 + pixel3)/4 - block_color - (inten_table[selector0] + inten_table[selector1] + inten_table[selector2] + inten_table[selector3])/4 = 0
- // block_color = (pixel0 + pixel1 + pixel2 + pixel3)/4 - (inten_table[selector0] + inten_table[selector1] + inten_table[selector2] + inten_table[selector3])/4
- // So what this means:
- // optimal_block_color = avg_input - avg_inten_delta
- // So the optimal block color can be computed by taking the average block color and subtracting the current average of the intensity delta.
- // Unfortunately, optimal_block_color must then be quantized to 555 or 444 so it's not always possible to improve matters using this formula.
- // Also, the above formula is for unclamped intensity deltas. The actual implementation takes into account clamping.
-
- const uint max_refinement_trials = (m_pParams->m_quality == cLowQuality) ? 2 : (((xd | yd | zd) == 0) ? 4 : 2);
- for (uint refinement_trial = 0; refinement_trial < max_refinement_trials; refinement_trial++)
- {
- const uint8* pSelectors = m_best_solution.m_selectors;
- const int* pInten_table = g_etc1_inten_tables[m_best_solution.m_coords.m_inten_table];
-
- int delta_sum_r = 0, delta_sum_g = 0, delta_sum_b = 0;
- const color_quad_u8 base_color(m_best_solution.m_coords.get_scaled_color());
- for (uint r = 0; r < n; r++)
- {
- const uint s = *pSelectors++;
- const int yd = pInten_table[s];
- // Compute actual delta being applied to each pixel, taking into account clamping.
- delta_sum_r += rg_etc1::clamp<int>(base_color.r + yd, 0, 255) - base_color.r;
- delta_sum_g += rg_etc1::clamp<int>(base_color.g + yd, 0, 255) - base_color.g;
- delta_sum_b += rg_etc1::clamp<int>(base_color.b + yd, 0, 255) - base_color.b;
- }
- if ((!delta_sum_r) && (!delta_sum_g) && (!delta_sum_b))
- break;
- const float avg_delta_r_f = static_cast<float>(delta_sum_r) / n;
- const float avg_delta_g_f = static_cast<float>(delta_sum_g) / n;
- const float avg_delta_b_f = static_cast<float>(delta_sum_b) / n;
- const int br1 = rg_etc1::clamp<int>(static_cast<uint>((m_avg_color[0] - avg_delta_r_f) * m_limit / 255.0f + .5f), 0, m_limit);
- const int bg1 = rg_etc1::clamp<int>(static_cast<uint>((m_avg_color[1] - avg_delta_g_f) * m_limit / 255.0f + .5f), 0, m_limit);
- const int bb1 = rg_etc1::clamp<int>(static_cast<uint>((m_avg_color[2] - avg_delta_b_f) * m_limit / 255.0f + .5f), 0, m_limit);
-
- bool skip = false;
-
- if ((mbr == br1) && (mbg == bg1) && (mbb == bb1))
- skip = true;
- else if ((br1 == m_best_solution.m_coords.m_unscaled_color.r) && (bg1 == m_best_solution.m_coords.m_unscaled_color.g) && (bb1 == m_best_solution.m_coords.m_unscaled_color.b))
- skip = true;
- else if ((m_br == br1) && (m_bg == bg1) && (m_bb == bb1))
- skip = true;
-
- if (skip)
- break;
-
- etc1_solution_coordinates coords1(br1, bg1, bb1, 0, m_pParams->m_use_color4);
- if (m_pParams->m_quality == cHighQuality)
- {
- if (!evaluate_solution(coords1, m_trial_solution, &m_best_solution))
- break;
- }
- else
- {
- if (!evaluate_solution_fast(coords1, m_trial_solution, &m_best_solution))
- break;
- }
-
- } // refinement_trial
-
- } // xdi
- } // ydi
- } // zdi
-
- if (!m_best_solution.m_valid)
- {
- m_pResult->m_error = cUINT32_MAX;
- return false;
- }
-
- const uint8* pSelectors = m_best_solution.m_selectors;
-
-#ifdef RG_ETC1_BUILD_DEBUG
- {
- color_quad_u8 block_colors[4];
- m_best_solution.m_coords.get_block_colors(block_colors);
-
- const color_quad_u8* pSrc_pixels = m_pParams->m_pSrc_pixels;
- uint64 actual_error = 0;
- for (uint i = 0; i < n; i++)
- actual_error += pSrc_pixels[i].squared_distance_rgb(block_colors[pSelectors[i]]);
-
- RG_ETC1_ASSERT(actual_error == m_best_solution.m_error);
- }
-#endif
-
- m_pResult->m_error = m_best_solution.m_error;
-
- m_pResult->m_block_color_unscaled = m_best_solution.m_coords.m_unscaled_color;
- m_pResult->m_block_color4 = m_best_solution.m_coords.m_color4;
-
- m_pResult->m_block_inten_table = m_best_solution.m_coords.m_inten_table;
- memcpy(m_pResult->m_pSelectors, pSelectors, n);
- m_pResult->m_n = n;
-
- return true;
- }
-
- void etc1_optimizer::init(const params& p, results& r)
- {
- // This version is hardcoded for 8 pixel subblocks.
- RG_ETC1_ASSERT(p.m_num_src_pixels == 8);
-
- m_pParams = &p;
- m_pResult = &r;
-
- const uint n = 8;
-
- m_limit = m_pParams->m_use_color4 ? 15 : 31;
-
- vec3F avg_color(0.0f);
-
- for (uint i = 0; i < n; i++)
- {
- const color_quad_u8& c = m_pParams->m_pSrc_pixels[i];
- const vec3F fc(c.r, c.g, c.b);
-
- avg_color += fc;
-
- m_luma[i] = static_cast<uint16>(c.r + c.g + c.b);
- m_sorted_luma[0][i] = i;
- }
- avg_color *= (1.0f / static_cast<float>(n));
- m_avg_color = avg_color;
-
- m_br = rg_etc1::clamp<int>(static_cast<uint>(m_avg_color[0] * m_limit / 255.0f + .5f), 0, m_limit);
- m_bg = rg_etc1::clamp<int>(static_cast<uint>(m_avg_color[1] * m_limit / 255.0f + .5f), 0, m_limit);
- m_bb = rg_etc1::clamp<int>(static_cast<uint>(m_avg_color[2] * m_limit / 255.0f + .5f), 0, m_limit);
-
- if (m_pParams->m_quality <= cMediumQuality)
- {
- m_pSorted_luma_indices = indirect_radix_sort(n, m_sorted_luma[0], m_sorted_luma[1], m_luma, 0, sizeof(m_luma[0]), false);
- m_pSorted_luma = m_sorted_luma[0];
- if (m_pSorted_luma_indices == m_sorted_luma[0])
- m_pSorted_luma = m_sorted_luma[1];
-
- for (uint i = 0; i < n; i++)
- m_pSorted_luma[i] = m_luma[m_pSorted_luma_indices[i]];
- }
-
- m_best_solution.m_coords.clear();
- m_best_solution.m_valid = false;
- m_best_solution.m_error = cUINT64_MAX;
- }
-
- bool etc1_optimizer::evaluate_solution(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution)
- {
- trial_solution.m_valid = false;
-
- if (m_pParams->m_constrain_against_base_color5)
- {
- const int dr = coords.m_unscaled_color.r - m_pParams->m_base_color5.r;
- const int dg = coords.m_unscaled_color.g - m_pParams->m_base_color5.g;
- const int db = coords.m_unscaled_color.b - m_pParams->m_base_color5.b;
-
- if ((rg_etc1::minimum(dr, dg, db) < cETC1ColorDeltaMin) || (rg_etc1::maximum(dr, dg, db) > cETC1ColorDeltaMax))
- return false;
- }
-
- const color_quad_u8 base_color(coords.get_scaled_color());
-
- const uint n = 8;
-
- trial_solution.m_error = cUINT64_MAX;
-
- for (uint inten_table = 0; inten_table < cETC1IntenModifierValues; inten_table++)
- {
- const int* pInten_table = g_etc1_inten_tables[inten_table];
-
- color_quad_u8 block_colors[4];
- for (uint s = 0; s < 4; s++)
- {
- const int yd = pInten_table[s];
- block_colors[s].set(base_color.r + yd, base_color.g + yd, base_color.b + yd, 0);
- }
-
- uint64 total_error = 0;
-
- const color_quad_u8* pSrc_pixels = m_pParams->m_pSrc_pixels;
- for (uint c = 0; c < n; c++)
- {
- const color_quad_u8& src_pixel = *pSrc_pixels++;
-
- uint best_selector_index = 0;
- uint best_error = rg_etc1::square(src_pixel.r - block_colors[0].r) + rg_etc1::square(src_pixel.g - block_colors[0].g) + rg_etc1::square(src_pixel.b - block_colors[0].b);
-
- uint trial_error = rg_etc1::square(src_pixel.r - block_colors[1].r) + rg_etc1::square(src_pixel.g - block_colors[1].g) + rg_etc1::square(src_pixel.b - block_colors[1].b);
- if (trial_error < best_error)
- {
- best_error = trial_error;
- best_selector_index = 1;
- }
-
- trial_error = rg_etc1::square(src_pixel.r - block_colors[2].r) + rg_etc1::square(src_pixel.g - block_colors[2].g) + rg_etc1::square(src_pixel.b - block_colors[2].b);
- if (trial_error < best_error)
- {
- best_error = trial_error;
- best_selector_index = 2;
- }
-
- trial_error = rg_etc1::square(src_pixel.r - block_colors[3].r) + rg_etc1::square(src_pixel.g - block_colors[3].g) + rg_etc1::square(src_pixel.b - block_colors[3].b);
- if (trial_error < best_error)
- {
- best_error = trial_error;
- best_selector_index = 3;
- }
-
- m_temp_selectors[c] = static_cast<uint8>(best_selector_index);
-
- total_error += best_error;
- if (total_error >= trial_solution.m_error)
- break;
- }
-
- if (total_error < trial_solution.m_error)
- {
- trial_solution.m_error = total_error;
- trial_solution.m_coords.m_inten_table = inten_table;
- memcpy(trial_solution.m_selectors, m_temp_selectors, 8);
- trial_solution.m_valid = true;
- }
- }
- trial_solution.m_coords.m_unscaled_color = coords.m_unscaled_color;
- trial_solution.m_coords.m_color4 = m_pParams->m_use_color4;
-
- bool success = false;
- if (pBest_solution)
- {
- if (trial_solution.m_error < pBest_solution->m_error)
- {
- *pBest_solution = trial_solution;
- success = true;
- }
- }
-
- return success;
- }
-
- bool etc1_optimizer::evaluate_solution_fast(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution)
- {
- if (m_pParams->m_constrain_against_base_color5)
- {
- const int dr = coords.m_unscaled_color.r - m_pParams->m_base_color5.r;
- const int dg = coords.m_unscaled_color.g - m_pParams->m_base_color5.g;
- const int db = coords.m_unscaled_color.b - m_pParams->m_base_color5.b;
-
- if ((rg_etc1::minimum(dr, dg, db) < cETC1ColorDeltaMin) || (rg_etc1::maximum(dr, dg, db) > cETC1ColorDeltaMax))
- {
- trial_solution.m_valid = false;
- return false;
- }
- }
-
- const color_quad_u8 base_color(coords.get_scaled_color());
-
- const uint n = 8;
-
- trial_solution.m_error = cUINT64_MAX;
-
- for (int inten_table = cETC1IntenModifierValues - 1; inten_table >= 0; --inten_table)
- {
- const int* pInten_table = g_etc1_inten_tables[inten_table];
-
- uint block_inten[4];
- color_quad_u8 block_colors[4];
- for (uint s = 0; s < 4; s++)
- {
- const int yd = pInten_table[s];
- color_quad_u8 block_color(base_color.r + yd, base_color.g + yd, base_color.b + yd, 0);
- block_colors[s] = block_color;
- block_inten[s] = block_color.r + block_color.g + block_color.b;
- }
-
- // evaluate_solution_fast() enforces/assumesd a total ordering of the input colors along the intensity (1,1,1) axis to more quickly classify the inputs to selectors.
- // The inputs colors have been presorted along the projection onto this axis, and ETC1 block colors are always ordered along the intensity axis, so this classification is fast.
- // 0 1 2 3
- // 01 12 23
- const uint block_inten_midpoints[3] = { block_inten[0] + block_inten[1], block_inten[1] + block_inten[2], block_inten[2] + block_inten[3] };
-
- uint64 total_error = 0;
- const color_quad_u8* pSrc_pixels = m_pParams->m_pSrc_pixels;
- if ((m_pSorted_luma[n - 1] * 2) < block_inten_midpoints[0])
- {
- if (block_inten[0] > m_pSorted_luma[n - 1])
- {
- const uint min_error = intabs(block_inten[0] - m_pSorted_luma[n - 1]);
- if (min_error >= trial_solution.m_error)
- continue;
- }
-
- memset(&m_temp_selectors[0], 0, n);
-
- for (uint c = 0; c < n; c++)
- total_error += block_colors[0].squared_distance_rgb(pSrc_pixels[c]);
- }
- else if ((m_pSorted_luma[0] * 2) >= block_inten_midpoints[2])
- {
- if (m_pSorted_luma[0] > block_inten[3])
- {
- const uint min_error = intabs(m_pSorted_luma[0] - block_inten[3]);
- if (min_error >= trial_solution.m_error)
- continue;
- }
-
- memset(&m_temp_selectors[0], 3, n);
-
- for (uint c = 0; c < n; c++)
- total_error += block_colors[3].squared_distance_rgb(pSrc_pixels[c]);
- }
- else
- {
- uint cur_selector = 0, c;
- for (c = 0; c < n; c++)
- {
- const uint y = m_pSorted_luma[c];
- while ((y * 2) >= block_inten_midpoints[cur_selector])
- if (++cur_selector > 2)
- goto done;
- const uint sorted_pixel_index = m_pSorted_luma_indices[c];
- m_temp_selectors[sorted_pixel_index] = static_cast<uint8>(cur_selector);
- total_error += block_colors[cur_selector].squared_distance_rgb(pSrc_pixels[sorted_pixel_index]);
- }
-done:
- while (c < n)
- {
- const uint sorted_pixel_index = m_pSorted_luma_indices[c];
- m_temp_selectors[sorted_pixel_index] = 3;
- total_error += block_colors[3].squared_distance_rgb(pSrc_pixels[sorted_pixel_index]);
- ++c;
- }
- }
-
- if (total_error < trial_solution.m_error)
- {
- trial_solution.m_error = total_error;
- trial_solution.m_coords.m_inten_table = inten_table;
- memcpy(trial_solution.m_selectors, m_temp_selectors, n);
- trial_solution.m_valid = true;
- if (!total_error)
- break;
- }
- }
- trial_solution.m_coords.m_unscaled_color = coords.m_unscaled_color;
- trial_solution.m_coords.m_color4 = m_pParams->m_use_color4;
-
- bool success = false;
- if (pBest_solution)
- {
- if (trial_solution.m_error < pBest_solution->m_error)
- {
- *pBest_solution = trial_solution;
- success = true;
- }
- }
-
- return success;
- }
-
- static uint etc1_decode_value(uint diff, uint inten, uint selector, uint packed_c)
- {
- const uint limit = diff ? 32 : 16; limit;
- RG_ETC1_ASSERT((diff < 2) && (inten < 8) && (selector < 4) && (packed_c < limit));
- int c;
- if (diff)
- c = (packed_c >> 2) | (packed_c << 3);
- else
- c = packed_c | (packed_c << 4);
- c += g_etc1_inten_tables[inten][selector];
- c = rg_etc1::clamp<int>(c, 0, 255);
- return c;
- }
-
- static inline int mul_8bit(int a, int b) { int t = a*b + 128; return (t + (t >> 8)) >> 8; }
-
- void pack_etc1_block_init()
- {
- for (uint diff = 0; diff < 2; diff++)
- {
- const uint limit = diff ? 32 : 16;
-
- for (uint inten = 0; inten < 8; inten++)
- {
- for (uint selector = 0; selector < 4; selector++)
- {
- const uint inverse_table_index = diff + (inten << 1) + (selector << 4);
- for (uint color = 0; color < 256; color++)
- {
- uint best_error = cUINT32_MAX, best_packed_c = 0;
- for (uint packed_c = 0; packed_c < limit; packed_c++)
- {
- int v = etc1_decode_value(diff, inten, selector, packed_c);
- uint err = labs(v - static_cast<int>(color));
- //printf("err: %d - %u = %u\n",v,color,err);
- if (err < best_error)
- {
- best_error = err;
- best_packed_c = packed_c;
- if (!best_error)
- break;
- }
- }
- RG_ETC1_ASSERT(best_error <= 255);
- g_etc1_inverse_lookup[inverse_table_index][color] = static_cast<uint16>(best_packed_c | (best_error << 8));
- }
- }
- }
- }
-
- uint expand5[32];
- for(int i = 0; i < 32; i++)
- expand5[i] = (i << 3) | (i >> 2);
-
- for(int i = 0; i < 256 + 16; i++)
- {
- int v = clamp<int>(i - 8, 0, 255);
- g_quant5_tab[i] = static_cast<uint8>(expand5[mul_8bit(v,31)]);
- }
- }
-
- // Packs solid color blocks efficiently using a set of small precomputed tables.
- // For random 888 inputs, MSE results are better than Erricson's ETC1 packer in "slow" mode ~9.5% of the time, is slightly worse only ~.01% of the time, and is equal the rest of the time.
- static uint64 pack_etc1_block_solid_color(etc1_block& block, const uint8* pColor, etc1_pack_params& pack_params)
- {
- pack_params;
- RG_ETC1_ASSERT(g_etc1_inverse_lookup[0][255]);
-
- static uint s_next_comp[4] = { 1, 2, 0, 1 };
-
- uint best_error = cUINT32_MAX, best_i = 0;
- int best_x = 0, best_packed_c1 = 0, best_packed_c2 = 0;
-
- // For each possible 8-bit value, there is a precomputed list of diff/inten/selector configurations that allow that 8-bit value to be encoded with no error.
- for (uint i = 0; i < 3; i++)
- {
- const uint c1 = pColor[s_next_comp[i]], c2 = pColor[s_next_comp[i + 1]];
-
- const int delta_range = 1;
- for (int delta = -delta_range; delta <= delta_range; delta++)
- {
- const int c_plus_delta = rg_etc1::clamp<int>(pColor[i] + delta, 0, 255);
-
- const uint16* pTable;
- if (!c_plus_delta)
- pTable = g_color8_to_etc_block_config_0_255[0];
- else if (c_plus_delta == 255)
- pTable = g_color8_to_etc_block_config_0_255[1];
- else
- pTable = g_color8_to_etc_block_config_1_to_254[c_plus_delta - 1];
-
- do
- {
- const uint x = *pTable++;
-
-#ifdef RG_ETC1_BUILD_DEBUG
- const uint diff = x & 1;
- const uint inten = (x >> 1) & 7;
- const uint selector = (x >> 4) & 3;
- const uint p0 = (x >> 8) & 255;
- RG_ETC1_ASSERT(etc1_decode_value(diff, inten, selector, p0) == (uint)c_plus_delta);
-#endif
-
- const uint16* pInverse_table = g_etc1_inverse_lookup[x & 0xFF];
- uint16 p1 = pInverse_table[c1];
- uint16 p2 = pInverse_table[c2];
- const uint trial_error = rg_etc1::square(c_plus_delta - pColor[i]) + rg_etc1::square(p1 >> 8) + rg_etc1::square(p2 >> 8);
- if (trial_error < best_error)
- {
- best_error = trial_error;
- best_x = x;
- best_packed_c1 = p1 & 0xFF;
- best_packed_c2 = p2 & 0xFF;
- best_i = i;
- if (!best_error)
- goto found_perfect_match;
- }
- } while (*pTable != 0xFFFF);
- }
- }
-found_perfect_match:
-
- const uint diff = best_x & 1;
- const uint inten = (best_x >> 1) & 7;
-
- block.m_bytes[3] = static_cast<uint8>(((inten | (inten << 3)) << 2) | (diff << 1));
-
- const uint etc1_selector = g_selector_index_to_etc1[(best_x >> 4) & 3];
- *reinterpret_cast<uint16*>(&block.m_bytes[4]) = (etc1_selector & 2) ? 0xFFFF : 0;
- *reinterpret_cast<uint16*>(&block.m_bytes[6]) = (etc1_selector & 1) ? 0xFFFF : 0;
-
- const uint best_packed_c0 = (best_x >> 8) & 255;
- if (diff)
- {
- block.m_bytes[best_i] = static_cast<uint8>(best_packed_c0 << 3);
- block.m_bytes[s_next_comp[best_i]] = static_cast<uint8>(best_packed_c1 << 3);
- block.m_bytes[s_next_comp[best_i+1]] = static_cast<uint8>(best_packed_c2 << 3);
- }
- else
- {
- block.m_bytes[best_i] = static_cast<uint8>(best_packed_c0 | (best_packed_c0 << 4));
- block.m_bytes[s_next_comp[best_i]] = static_cast<uint8>(best_packed_c1 | (best_packed_c1 << 4));
- block.m_bytes[s_next_comp[best_i+1]] = static_cast<uint8>(best_packed_c2 | (best_packed_c2 << 4));
- }
-
- return best_error;
- }
-
- static uint pack_etc1_block_solid_color_constrained(
- etc1_optimizer::results& results,
- uint num_colors, const uint8* pColor,
- etc1_pack_params& pack_params,
- bool use_diff,
- const color_quad_u8* pBase_color5_unscaled)
- {
- RG_ETC1_ASSERT(g_etc1_inverse_lookup[0][255]);
-
- pack_params;
- static uint s_next_comp[4] = { 1, 2, 0, 1 };
-
- uint best_error = cUINT32_MAX, best_i = 0;
- int best_x = 0, best_packed_c1 = 0, best_packed_c2 = 0;
-
- // For each possible 8-bit value, there is a precomputed list of diff/inten/selector configurations that allow that 8-bit value to be encoded with no error.
- for (uint i = 0; i < 3; i++)
- {
- const uint c1 = pColor[s_next_comp[i]], c2 = pColor[s_next_comp[i + 1]];
-
- const int delta_range = 1;
- for (int delta = -delta_range; delta <= delta_range; delta++)
- {
- const int c_plus_delta = rg_etc1::clamp<int>(pColor[i] + delta, 0, 255);
-
- const uint16* pTable;
- if (!c_plus_delta)
- pTable = g_color8_to_etc_block_config_0_255[0];
- else if (c_plus_delta == 255)
- pTable = g_color8_to_etc_block_config_0_255[1];
- else
- pTable = g_color8_to_etc_block_config_1_to_254[c_plus_delta - 1];
-
- do
- {
- const uint x = *pTable++;
- const uint diff = x & 1;
- if (static_cast<uint>(use_diff) != diff)
- {
- if (*pTable == 0xFFFF)
- break;
- continue;
- }
-
- if ((diff) && (pBase_color5_unscaled))
- {
- const int p0 = (x >> 8) & 255;
- int delta = p0 - static_cast<int>(pBase_color5_unscaled->c[i]);
- if ((delta < cETC1ColorDeltaMin) || (delta > cETC1ColorDeltaMax))
- {
- if (*pTable == 0xFFFF)
- break;
- continue;
- }
- }
-
-#ifdef RG_ETC1_BUILD_DEBUG
- {
- const uint inten = (x >> 1) & 7;
- const uint selector = (x >> 4) & 3;
- const uint p0 = (x >> 8) & 255;
- RG_ETC1_ASSERT(etc1_decode_value(diff, inten, selector, p0) == (uint)c_plus_delta);
- }
-#endif
-
- const uint16* pInverse_table = g_etc1_inverse_lookup[x & 0xFF];
- uint16 p1 = pInverse_table[c1];
- uint16 p2 = pInverse_table[c2];
-
- if ((diff) && (pBase_color5_unscaled))
- {
- int delta1 = (p1 & 0xFF) - static_cast<int>(pBase_color5_unscaled->c[s_next_comp[i]]);
- int delta2 = (p2 & 0xFF) - static_cast<int>(pBase_color5_unscaled->c[s_next_comp[i + 1]]);
- if ((delta1 < cETC1ColorDeltaMin) || (delta1 > cETC1ColorDeltaMax) || (delta2 < cETC1ColorDeltaMin) || (delta2 > cETC1ColorDeltaMax))
- {
- if (*pTable == 0xFFFF)
- break;
- continue;
- }
- }
-
- const uint trial_error = rg_etc1::square(c_plus_delta - pColor[i]) + rg_etc1::square(p1 >> 8) + rg_etc1::square(p2 >> 8);
- if (trial_error < best_error)
- {
- best_error = trial_error;
- best_x = x;
- best_packed_c1 = p1 & 0xFF;
- best_packed_c2 = p2 & 0xFF;
- best_i = i;
- if (!best_error)
- goto found_perfect_match;
- }
- } while (*pTable != 0xFFFF);
- }
- }
-found_perfect_match:
-
- if (best_error == cUINT32_MAX)
- return best_error;
-
- best_error *= num_colors;
-
- results.m_n = num_colors;
- results.m_block_color4 = !(best_x & 1);
- results.m_block_inten_table = (best_x >> 1) & 7;
- memset(results.m_pSelectors, (best_x >> 4) & 3, num_colors);
-
- const uint best_packed_c0 = (best_x >> 8) & 255;
- results.m_block_color_unscaled[best_i] = static_cast<uint8>(best_packed_c0);
- results.m_block_color_unscaled[s_next_comp[best_i]] = static_cast<uint8>(best_packed_c1);
- results.m_block_color_unscaled[s_next_comp[best_i + 1]] = static_cast<uint8>(best_packed_c2);
- results.m_error = best_error;
-
- return best_error;
- }
-
- // Function originally from RYG's public domain real-time DXT1 compressor, modified for 555.
- static void dither_block_555(color_quad_u8* dest, const color_quad_u8* block)
- {
- int err[8],*ep1 = err,*ep2 = err+4;
- uint8 *quant = g_quant5_tab+8;
-
- memset(dest, 0xFF, sizeof(color_quad_u8)*16);
-
- // process channels seperately
- for(int ch=0;ch<3;ch++)
- {
- uint8* bp = (uint8*)block;
- uint8* dp = (uint8*)dest;
-
- bp += ch; dp += ch;
-
- memset(err,0, sizeof(err));
- for(int y = 0; y < 4; y++)
- {
- // pixel 0
- dp[ 0] = quant[bp[ 0] + ((3*ep2[1] + 5*ep2[0]) >> 4)];
- ep1[0] = bp[ 0] - dp[ 0];
-
- // pixel 1
- dp[ 4] = quant[bp[ 4] + ((7*ep1[0] + 3*ep2[2] + 5*ep2[1] + ep2[0]) >> 4)];
- ep1[1] = bp[ 4] - dp[ 4];
-
- // pixel 2
- dp[ 8] = quant[bp[ 8] + ((7*ep1[1] + 3*ep2[3] + 5*ep2[2] + ep2[1]) >> 4)];
- ep1[2] = bp[ 8] - dp[ 8];
-
- // pixel 3
- dp[12] = quant[bp[12] + ((7*ep1[2] + 5*ep2[3] + ep2[2]) >> 4)];
- ep1[3] = bp[12] - dp[12];
-
- // advance to next line
- int* tmp = ep1; ep1 = ep2; ep2 = tmp;
- bp += 16;
- dp += 16;
- }
- }
- }
-
- unsigned int pack_etc1_block(void* pETC1_block, const unsigned int* pSrc_pixels_rgba, etc1_pack_params& pack_params)
- {
- const color_quad_u8* pSrc_pixels = reinterpret_cast<const color_quad_u8*>(pSrc_pixels_rgba);
- etc1_block& dst_block = *static_cast<etc1_block*>(pETC1_block);
-
-#ifdef RG_ETC1_BUILD_DEBUG
- // Ensure all alpha values are 0xFF.
- for (uint i = 0; i < 16; i++)
- {
- RG_ETC1_ASSERT(pSrc_pixels[i].a == 255);
- }
-#endif
-
- color_quad_u8 src_pixel0(pSrc_pixels[0]);
-
- // Check for solid block.
- const uint32 first_pixel_u32 = pSrc_pixels->m_u32;
- int r;
- for (r = 15; r >= 1; --r)
- if (pSrc_pixels[r].m_u32 != first_pixel_u32)
- break;
- if (!r)
- return static_cast<unsigned int>(16 * pack_etc1_block_solid_color(dst_block, &pSrc_pixels[0].r, pack_params));
-
- color_quad_u8 dithered_pixels[16];
- if (pack_params.m_dithering)
- {
- dither_block_555(dithered_pixels, pSrc_pixels);
- pSrc_pixels = dithered_pixels;
- }
-
- etc1_optimizer optimizer;
-
- uint64 best_error = cUINT64_MAX;
- uint best_flip = false, best_use_color4 = false;
-
- uint8 best_selectors[2][8];
- etc1_optimizer::results best_results[2];
- for (uint i = 0; i < 2; i++)
- {
- best_results[i].m_n = 8;
- best_results[i].m_pSelectors = best_selectors[i];
- }
-
- uint8 selectors[3][8];
- etc1_optimizer::results results[3];
-
- for (uint i = 0; i < 3; i++)
- {
- results[i].m_n = 8;
- results[i].m_pSelectors = selectors[i];
- }
-
- color_quad_u8 subblock_pixels[8];
-
- etc1_optimizer::params params(pack_params);
- params.m_num_src_pixels = 8;
- params.m_pSrc_pixels = subblock_pixels;
-
- for (uint flip = 0; flip < 2; flip++)
- {
- for (uint use_color4 = 0; use_color4 < 2; use_color4++)
- {
- uint64 trial_error = 0;
-
- uint subblock;
- for (subblock = 0; subblock < 2; subblock++)
- {
- if (flip)
- memcpy(subblock_pixels, pSrc_pixels + subblock * 8, sizeof(color_quad_u8) * 8);
- else
- {
- const color_quad_u8* pSrc_col = pSrc_pixels + subblock * 2;
- subblock_pixels[0] = pSrc_col[0]; subblock_pixels[1] = pSrc_col[4]; subblock_pixels[2] = pSrc_col[8]; subblock_pixels[3] = pSrc_col[12];
- subblock_pixels[4] = pSrc_col[1]; subblock_pixels[5] = pSrc_col[5]; subblock_pixels[6] = pSrc_col[9]; subblock_pixels[7] = pSrc_col[13];
- }
-
- results[2].m_error = cUINT64_MAX;
- if ((params.m_quality >= cMediumQuality) && ((subblock) || (use_color4)))
- {
- const uint32 subblock_pixel0_u32 = subblock_pixels[0].m_u32;
- for (r = 7; r >= 1; --r)
- if (subblock_pixels[r].m_u32 != subblock_pixel0_u32)
- break;
- if (!r)
- {
- pack_etc1_block_solid_color_constrained(results[2], 8, &subblock_pixels[0].r, pack_params, !use_color4, (subblock && !use_color4) ? &results[0].m_block_color_unscaled : NULL);
- }
- }
-
- params.m_use_color4 = (use_color4 != 0);
- params.m_constrain_against_base_color5 = false;
-
- if ((!use_color4) && (subblock))
- {
- params.m_constrain_against_base_color5 = true;
- params.m_base_color5 = results[0].m_block_color_unscaled;
- }
-
- if (params.m_quality == cHighQuality)
- {
- static const int s_scan_delta_0_to_4[] = { -4, -3, -2, -1, 0, 1, 2, 3, 4 };
- params.m_scan_delta_size = RG_ETC1_ARRAY_SIZE(s_scan_delta_0_to_4);
- params.m_pScan_deltas = s_scan_delta_0_to_4;
- }
- else if (params.m_quality == cMediumQuality)
- {
- static const int s_scan_delta_0_to_1[] = { -1, 0, 1 };
- params.m_scan_delta_size = RG_ETC1_ARRAY_SIZE(s_scan_delta_0_to_1);
- params.m_pScan_deltas = s_scan_delta_0_to_1;
- }
- else
- {
- static const int s_scan_delta_0[] = { 0 };
- params.m_scan_delta_size = RG_ETC1_ARRAY_SIZE(s_scan_delta_0);
- params.m_pScan_deltas = s_scan_delta_0;
- }
-
- optimizer.init(params, results[subblock]);
- if (!optimizer.compute())
- break;
-
- if (params.m_quality >= cMediumQuality)
- {
- // TODO: Fix fairly arbitrary/unrefined thresholds that control how far away to scan for potentially better solutions.
- const uint refinement_error_thresh0 = 3000;
- const uint refinement_error_thresh1 = 6000;
- if (results[subblock].m_error > refinement_error_thresh0)
- {
- if (params.m_quality == cMediumQuality)
- {
- static const int s_scan_delta_2_to_3[] = { -3, -2, 2, 3 };
- params.m_scan_delta_size = RG_ETC1_ARRAY_SIZE(s_scan_delta_2_to_3);
- params.m_pScan_deltas = s_scan_delta_2_to_3;
- }
- else
- {
- static const int s_scan_delta_5_to_5[] = { -5, 5 };
- static const int s_scan_delta_5_to_8[] = { -8, -7, -6, -5, 5, 6, 7, 8 };
- if (results[subblock].m_error > refinement_error_thresh1)
- {
- params.m_scan_delta_size = RG_ETC1_ARRAY_SIZE(s_scan_delta_5_to_8);
- params.m_pScan_deltas = s_scan_delta_5_to_8;
- }
- else
- {
- params.m_scan_delta_size = RG_ETC1_ARRAY_SIZE(s_scan_delta_5_to_5);
- params.m_pScan_deltas = s_scan_delta_5_to_5;
- }
- }
-
- if (!optimizer.compute())
- break;
- }
-
- if (results[2].m_error < results[subblock].m_error)
- results[subblock] = results[2];
- }
-
- trial_error += results[subblock].m_error;
- if (trial_error >= best_error)
- break;
- }
-
- if (subblock < 2)
- continue;
-
- best_error = trial_error;
- best_results[0] = results[0];
- best_results[1] = results[1];
- best_flip = flip;
- best_use_color4 = use_color4;
-
- } // use_color4
-
- } // flip
-
- int dr = best_results[1].m_block_color_unscaled.r - best_results[0].m_block_color_unscaled.r;
- int dg = best_results[1].m_block_color_unscaled.g - best_results[0].m_block_color_unscaled.g;
- int db = best_results[1].m_block_color_unscaled.b - best_results[0].m_block_color_unscaled.b;
- RG_ETC1_ASSERT(best_use_color4 || ((rg_etc1::minimum(dr, dg, db) >= cETC1ColorDeltaMin) && (rg_etc1::maximum(dr, dg, db) <= cETC1ColorDeltaMax)));
-
- if (best_use_color4)
- {
- dst_block.m_bytes[0] = static_cast<uint8>(best_results[1].m_block_color_unscaled.r | (best_results[0].m_block_color_unscaled.r << 4));
- dst_block.m_bytes[1] = static_cast<uint8>(best_results[1].m_block_color_unscaled.g | (best_results[0].m_block_color_unscaled.g << 4));
- dst_block.m_bytes[2] = static_cast<uint8>(best_results[1].m_block_color_unscaled.b | (best_results[0].m_block_color_unscaled.b << 4));
- }
- else
- {
- if (dr < 0) dr += 8; dst_block.m_bytes[0] = static_cast<uint8>((best_results[0].m_block_color_unscaled.r << 3) | dr);
- if (dg < 0) dg += 8; dst_block.m_bytes[1] = static_cast<uint8>((best_results[0].m_block_color_unscaled.g << 3) | dg);
- if (db < 0) db += 8; dst_block.m_bytes[2] = static_cast<uint8>((best_results[0].m_block_color_unscaled.b << 3) | db);
- }
-
- dst_block.m_bytes[3] = static_cast<uint8>( (best_results[1].m_block_inten_table << 2) | (best_results[0].m_block_inten_table << 5) | ((~best_use_color4 & 1) << 1) | best_flip );
-
- uint selector0 = 0, selector1 = 0;
- if (best_flip)
- {
- // flipped:
- // { 0, 0 }, { 1, 0 }, { 2, 0 }, { 3, 0 },
- // { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 }
- //
- // { 0, 2 }, { 1, 2 }, { 2, 2 }, { 3, 2 },
- // { 0, 3 }, { 1, 3 }, { 2, 3 }, { 3, 3 }
- const uint8* pSelectors0 = best_results[0].m_pSelectors;
- const uint8* pSelectors1 = best_results[1].m_pSelectors;
- for (int x = 3; x >= 0; --x)
- {
- uint b;
- b = g_selector_index_to_etc1[pSelectors1[4 + x]];
- selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1);
-
- b = g_selector_index_to_etc1[pSelectors1[x]];
- selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1);
-
- b = g_selector_index_to_etc1[pSelectors0[4 + x]];
- selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1);
-
- b = g_selector_index_to_etc1[pSelectors0[x]];
- selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1);
- }
- }
- else
- {
- // non-flipped:
- // { 0, 0 }, { 0, 1 }, { 0, 2 }, { 0, 3 },
- // { 1, 0 }, { 1, 1 }, { 1, 2 }, { 1, 3 }
- //
- // { 2, 0 }, { 2, 1 }, { 2, 2 }, { 2, 3 },
- // { 3, 0 }, { 3, 1 }, { 3, 2 }, { 3, 3 }
- for (int subblock = 1; subblock >= 0; --subblock)
- {
- const uint8* pSelectors = best_results[subblock].m_pSelectors + 4;
- for (uint i = 0; i < 2; i++)
- {
- uint b;
- b = g_selector_index_to_etc1[pSelectors[3]];
- selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1);
-
- b = g_selector_index_to_etc1[pSelectors[2]];
- selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1);
-
- b = g_selector_index_to_etc1[pSelectors[1]];
- selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1);
-
- b = g_selector_index_to_etc1[pSelectors[0]];
- selector0 = (selector0 << 1) | (b & 1);selector1 = (selector1 << 1) | (b >> 1);
-
- pSelectors -= 4;
- }
- }
- }
-
- dst_block.m_bytes[4] = static_cast<uint8>(selector1 >> 8); dst_block.m_bytes[5] = static_cast<uint8>(selector1 & 0xFF);
- dst_block.m_bytes[6] = static_cast<uint8>(selector0 >> 8); dst_block.m_bytes[7] = static_cast<uint8>(selector0 & 0xFF);
-
- return static_cast<unsigned int>(best_error);
- }
-
-} // namespace rg_etc1
+// File: rg_etc1.cpp - Fast, high quality ETC1 block packer/unpacker - Rich Geldreich <richgel99@gmail.com>
+// Please see ZLIB license at the end of rg_etc1.h.
+//
+// For more information Ericsson Texture Compression (ETC/ETC1), see:
+// http://www.khronos.org/registry/gles/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt
+//
+// v1.03 - 5/12/13 - Initial public release
+#include "rg_etc1.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+//#include <stdio.h>
+#include <math.h>
+#include <stdio.h>
+#pragma warning (disable: 4201) // nonstandard extension used : nameless struct/union
+
+#if defined(_DEBUG) || defined(DEBUG)
+#define RG_ETC1_BUILD_DEBUG
+#endif
+
+#define RG_ETC1_ASSERT assert
+
+namespace rg_etc1
+{
+
+ inline long labs(long val) {
+ return val < 0 ? -val : val;
+ }
+
+ inline int intabs(int val) {
+
+ return val<0?-val:val;
+ }
+
+ typedef unsigned char uint8;
+ typedef unsigned short uint16;
+ typedef unsigned int uint;
+ typedef unsigned int uint32;
+ typedef long long int64;
+ typedef unsigned long long uint64;
+
+ const uint32 cUINT32_MAX = 0xFFFFFFFFU;
+ const uint64 cUINT64_MAX = 0xFFFFFFFFFFFFFFFFULL; //0xFFFFFFFFFFFFFFFFui64;
+
+ template<typename T> inline T minimum(T a, T b) { return (a < b) ? a : b; }
+ template<typename T> inline T minimum(T a, T b, T c) { return minimum(minimum(a, b), c); }
+ template<typename T> inline T maximum(T a, T b) { return (a > b) ? a : b; }
+ template<typename T> inline T maximum(T a, T b, T c) { return maximum(maximum(a, b), c); }
+ template<typename T> inline T clamp(T value, T low, T high) { return (value < low) ? low : ((value > high) ? high : value); }
+ template<typename T> inline T square(T value) { return value * value; }
+ template<typename T> inline void zero_object(T& obj) { memset((void*)&obj, 0, sizeof(obj)); }
+ template<typename T> inline void zero_this(T* pObj) { memset((void*)pObj, 0, sizeof(*pObj)); }
+
+ template<class T, size_t N> T decay_array_to_subtype(T (&a)[N]);
+
+#define RG_ETC1_ARRAY_SIZE(X) (sizeof(X) / sizeof(decay_array_to_subtype(X)))
+
+ enum eNoClamp { cNoClamp };
+
+ struct color_quad_u8
+ {
+ static inline int clamp(int v) { if (v & 0xFFFFFF00U) v = (~(static_cast<int>(v) >> 31)) & 0xFF; return v; }
+
+ struct component_traits { enum { cSigned = false, cFloat = false, cMin = 0U, cMax = 255U }; };
+
+ public:
+ typedef unsigned char component_t;
+ typedef int parameter_t;
+
+ enum { cNumComps = 4 };
+
+ union
+ {
+ struct
+ {
+ component_t r;
+ component_t g;
+ component_t b;
+ component_t a;
+ };
+
+ component_t c[cNumComps];
+
+ uint32 m_u32;
+ };
+
+ inline color_quad_u8()
+ {
+ }
+
+ inline color_quad_u8(const color_quad_u8& other) : m_u32(other.m_u32)
+ {
+ }
+
+ explicit inline color_quad_u8(parameter_t y, parameter_t alpha = component_traits::cMax)
+ {
+ set(y, alpha);
+ }
+
+ inline color_quad_u8(parameter_t red, parameter_t green, parameter_t blue, parameter_t alpha = component_traits::cMax)
+ {
+ set(red, green, blue, alpha);
+ }
+
+ explicit inline color_quad_u8(eNoClamp, parameter_t y, parameter_t alpha = component_traits::cMax)
+ {
+ set_noclamp_y_alpha(y, alpha);
+ }
+
+ inline color_quad_u8(eNoClamp, parameter_t red, parameter_t green, parameter_t blue, parameter_t alpha = component_traits::cMax)
+ {
+ set_noclamp_rgba(red, green, blue, alpha);
+ }
+
+ inline void clear()
+ {
+ m_u32 = 0;
+ }
+
+ inline color_quad_u8& operator= (const color_quad_u8& other)
+ {
+ m_u32 = other.m_u32;
+ return *this;
+ }
+
+ inline color_quad_u8& set_rgb(const color_quad_u8& other)
+ {
+ r = other.r;
+ g = other.g;
+ b = other.b;
+ return *this;
+ }
+
+ inline color_quad_u8& operator= (parameter_t y)
+ {
+ set(y, component_traits::cMax);
+ return *this;
+ }
+
+ inline color_quad_u8& set(parameter_t y, parameter_t alpha = component_traits::cMax)
+ {
+ y = clamp(y);
+ alpha = clamp(alpha);
+ r = static_cast<component_t>(y);
+ g = static_cast<component_t>(y);
+ b = static_cast<component_t>(y);
+ a = static_cast<component_t>(alpha);
+ return *this;
+ }
+
+ inline color_quad_u8& set_noclamp_y_alpha(parameter_t y, parameter_t alpha = component_traits::cMax)
+ {
+ RG_ETC1_ASSERT( (y >= component_traits::cMin) && (y <= component_traits::cMax) );
+ RG_ETC1_ASSERT( (alpha >= component_traits::cMin) && (alpha <= component_traits::cMax) );
+
+ r = static_cast<component_t>(y);
+ g = static_cast<component_t>(y);
+ b = static_cast<component_t>(y);
+ a = static_cast<component_t>(alpha);
+ return *this;
+ }
+
+ inline color_quad_u8& set(parameter_t red, parameter_t green, parameter_t blue, parameter_t alpha = component_traits::cMax)
+ {
+ r = static_cast<component_t>(clamp(red));
+ g = static_cast<component_t>(clamp(green));
+ b = static_cast<component_t>(clamp(blue));
+ a = static_cast<component_t>(clamp(alpha));
+ return *this;
+ }
+
+ inline color_quad_u8& set_noclamp_rgba(parameter_t red, parameter_t green, parameter_t blue, parameter_t alpha)
+ {
+ RG_ETC1_ASSERT( (red >= component_traits::cMin) && (red <= component_traits::cMax) );
+ RG_ETC1_ASSERT( (green >= component_traits::cMin) && (green <= component_traits::cMax) );
+ RG_ETC1_ASSERT( (blue >= component_traits::cMin) && (blue <= component_traits::cMax) );
+ RG_ETC1_ASSERT( (alpha >= component_traits::cMin) && (alpha <= component_traits::cMax) );
+
+ r = static_cast<component_t>(red);
+ g = static_cast<component_t>(green);
+ b = static_cast<component_t>(blue);
+ a = static_cast<component_t>(alpha);
+ return *this;
+ }
+
+ inline color_quad_u8& set_noclamp_rgb(parameter_t red, parameter_t green, parameter_t blue)
+ {
+ RG_ETC1_ASSERT( (red >= component_traits::cMin) && (red <= component_traits::cMax) );
+ RG_ETC1_ASSERT( (green >= component_traits::cMin) && (green <= component_traits::cMax) );
+ RG_ETC1_ASSERT( (blue >= component_traits::cMin) && (blue <= component_traits::cMax) );
+
+ r = static_cast<component_t>(red);
+ g = static_cast<component_t>(green);
+ b = static_cast<component_t>(blue);
+ return *this;
+ }
+
+ static inline parameter_t get_min_comp() { return component_traits::cMin; }
+ static inline parameter_t get_max_comp() { return component_traits::cMax; }
+ static inline bool get_comps_are_signed() { return component_traits::cSigned; }
+
+ inline component_t operator[] (uint i) const { RG_ETC1_ASSERT(i < cNumComps); return c[i]; }
+ inline component_t& operator[] (uint i) { RG_ETC1_ASSERT(i < cNumComps); return c[i]; }
+
+ inline color_quad_u8& set_component(uint i, parameter_t f)
+ {
+ RG_ETC1_ASSERT(i < cNumComps);
+
+ c[i] = static_cast<component_t>(clamp(f));
+
+ return *this;
+ }
+
+ inline color_quad_u8& set_grayscale(parameter_t l)
+ {
+ component_t x = static_cast<component_t>(clamp(l));
+ c[0] = x;
+ c[1] = x;
+ c[2] = x;
+ return *this;
+ }
+
+ inline color_quad_u8& clamp(const color_quad_u8& l, const color_quad_u8& h)
+ {
+ for (uint i = 0; i < cNumComps; i++)
+ c[i] = static_cast<component_t>(rg_etc1::clamp<parameter_t>(c[i], l[i], h[i]));
+ return *this;
+ }
+
+ inline color_quad_u8& clamp(parameter_t l, parameter_t h)
+ {
+ for (uint i = 0; i < cNumComps; i++)
+ c[i] = static_cast<component_t>(rg_etc1::clamp<parameter_t>(c[i], l, h));
+ return *this;
+ }
+
+ // Returns CCIR 601 luma (consistent with color_utils::RGB_To_Y).
+ inline parameter_t get_luma() const
+ {
+ return static_cast<parameter_t>((19595U * r + 38470U * g + 7471U * b + 32768U) >> 16U);
+ }
+
+ // Returns REC 709 luma.
+ inline parameter_t get_luma_rec709() const
+ {
+ return static_cast<parameter_t>((13938U * r + 46869U * g + 4729U * b + 32768U) >> 16U);
+ }
+
+ inline uint squared_distance_rgb(const color_quad_u8& c) const
+ {
+ return rg_etc1::square(r - c.r) + rg_etc1::square(g - c.g) + rg_etc1::square(b - c.b);
+ }
+
+ inline uint squared_distance_rgba(const color_quad_u8& c) const
+ {
+ return rg_etc1::square(r - c.r) + rg_etc1::square(g - c.g) + rg_etc1::square(b - c.b) + rg_etc1::square(a - c.a);
+ }
+
+ inline bool rgb_equals(const color_quad_u8& rhs) const
+ {
+ return (r == rhs.r) && (g == rhs.g) && (b == rhs.b);
+ }
+
+ inline bool operator== (const color_quad_u8& rhs) const
+ {
+ return m_u32 == rhs.m_u32;
+ }
+
+ color_quad_u8& operator+= (const color_quad_u8& other)
+ {
+ for (uint i = 0; i < 4; i++)
+ c[i] = static_cast<component_t>(clamp(c[i] + other.c[i]));
+ return *this;
+ }
+
+ color_quad_u8& operator-= (const color_quad_u8& other)
+ {
+ for (uint i = 0; i < 4; i++)
+ c[i] = static_cast<component_t>(clamp(c[i] - other.c[i]));
+ return *this;
+ }
+
+ friend color_quad_u8 operator+ (const color_quad_u8& lhs, const color_quad_u8& rhs)
+ {
+ color_quad_u8 result(lhs);
+ result += rhs;
+ return result;
+ }
+
+ friend color_quad_u8 operator- (const color_quad_u8& lhs, const color_quad_u8& rhs)
+ {
+ color_quad_u8 result(lhs);
+ result -= rhs;
+ return result;
+ }
+ }; // class color_quad_u8
+
+ struct vec3F
+ {
+ float m_s[3];
+
+ inline vec3F() { }
+ inline vec3F(float s) { m_s[0] = s; m_s[1] = s; m_s[2] = s; }
+ inline vec3F(float x, float y, float z) { m_s[0] = x; m_s[1] = y; m_s[2] = z; }
+
+ inline float operator[] (uint i) const { RG_ETC1_ASSERT(i < 3); return m_s[i]; }
+
+ inline vec3F& operator += (const vec3F& other) { for (uint i = 0; i < 3; i++) m_s[i] += other.m_s[i]; return *this; }
+
+ inline vec3F& operator *= (float s) { for (uint i = 0; i < 3; i++) m_s[i] *= s; return *this; }
+ };
+
+ enum etc_constants
+ {
+ cETC1BytesPerBlock = 8U,
+
+ cETC1SelectorBits = 2U,
+ cETC1SelectorValues = 1U << cETC1SelectorBits,
+ cETC1SelectorMask = cETC1SelectorValues - 1U,
+
+ cETC1BlockShift = 2U,
+ cETC1BlockSize = 1U << cETC1BlockShift,
+
+ cETC1LSBSelectorIndicesBitOffset = 0,
+ cETC1MSBSelectorIndicesBitOffset = 16,
+
+ cETC1FlipBitOffset = 32,
+ cETC1DiffBitOffset = 33,
+
+ cETC1IntenModifierNumBits = 3,
+ cETC1IntenModifierValues = 1 << cETC1IntenModifierNumBits,
+ cETC1RightIntenModifierTableBitOffset = 34,
+ cETC1LeftIntenModifierTableBitOffset = 37,
+
+ // Base+Delta encoding (5 bit bases, 3 bit delta)
+ cETC1BaseColorCompNumBits = 5,
+ cETC1BaseColorCompMax = 1 << cETC1BaseColorCompNumBits,
+
+ cETC1DeltaColorCompNumBits = 3,
+ cETC1DeltaColorComp = 1 << cETC1DeltaColorCompNumBits,
+ cETC1DeltaColorCompMax = 1 << cETC1DeltaColorCompNumBits,
+
+ cETC1BaseColor5RBitOffset = 59,
+ cETC1BaseColor5GBitOffset = 51,
+ cETC1BaseColor5BBitOffset = 43,
+
+ cETC1DeltaColor3RBitOffset = 56,
+ cETC1DeltaColor3GBitOffset = 48,
+ cETC1DeltaColor3BBitOffset = 40,
+
+ // Absolute (non-delta) encoding (two 4-bit per component bases)
+ cETC1AbsColorCompNumBits = 4,
+ cETC1AbsColorCompMax = 1 << cETC1AbsColorCompNumBits,
+
+ cETC1AbsColor4R1BitOffset = 60,
+ cETC1AbsColor4G1BitOffset = 52,
+ cETC1AbsColor4B1BitOffset = 44,
+
+ cETC1AbsColor4R2BitOffset = 56,
+ cETC1AbsColor4G2BitOffset = 48,
+ cETC1AbsColor4B2BitOffset = 40,
+
+ cETC1ColorDeltaMin = -4,
+ cETC1ColorDeltaMax = 3,
+
+ // Delta3:
+ // 0 1 2 3 4 5 6 7
+ // 000 001 010 011 100 101 110 111
+ // 0 1 2 3 -4 -3 -2 -1
+ };
+
+ static uint8 g_quant5_tab[256+16];
+
+
+ static const int g_etc1_inten_tables[cETC1IntenModifierValues][cETC1SelectorValues] =
+ {
+ { -8, -2, 2, 8 }, { -17, -5, 5, 17 }, { -29, -9, 9, 29 }, { -42, -13, 13, 42 },
+ { -60, -18, 18, 60 }, { -80, -24, 24, 80 }, { -106, -33, 33, 106 }, { -183, -47, 47, 183 }
+ };
+
+ static const uint8 g_etc1_to_selector_index[cETC1SelectorValues] = { 2, 3, 1, 0 };
+ static const uint8 g_selector_index_to_etc1[cETC1SelectorValues] = { 3, 2, 0, 1 };
+
+ // Given an ETC1 diff/inten_table/selector, and an 8-bit desired color, this table encodes the best packed_color in the low byte, and the abs error in the high byte.
+ static uint16 g_etc1_inverse_lookup[2*8*4][256]; // [diff/inten_table/selector][desired_color]
+
+ // g_color8_to_etc_block_config[color][table_index] = Supplies for each 8-bit color value a list of packed ETC1 diff/intensity table/selectors/packed_colors that map to that color.
+ // To pack: diff | (inten << 1) | (selector << 4) | (packed_c << 8)
+ static const uint16 g_color8_to_etc_block_config_0_255[2][33] =
+ {
+ { 0x0000, 0x0010, 0x0002, 0x0012, 0x0004, 0x0014, 0x0006, 0x0016, 0x0008, 0x0018, 0x000A, 0x001A, 0x000C, 0x001C, 0x000E, 0x001E,
+ 0x0001, 0x0011, 0x0003, 0x0013, 0x0005, 0x0015, 0x0007, 0x0017, 0x0009, 0x0019, 0x000B, 0x001B, 0x000D, 0x001D, 0x000F, 0x001F, 0xFFFF },
+ { 0x0F20, 0x0F30, 0x0E32, 0x0F22, 0x0E34, 0x0F24, 0x0D36, 0x0F26, 0x0C38, 0x0E28, 0x0B3A, 0x0E2A, 0x093C, 0x0E2C, 0x053E, 0x0D2E,
+ 0x1E31, 0x1F21, 0x1D33, 0x1F23, 0x1C35, 0x1E25, 0x1A37, 0x1E27, 0x1839, 0x1D29, 0x163B, 0x1C2B, 0x133D, 0x1B2D, 0x093F, 0x1A2F, 0xFFFF },
+ };
+
+ // Really only [254][11].
+ static const uint16 g_color8_to_etc_block_config_1_to_254[254][12] =
+ {
+ { 0x021C, 0x0D0D, 0xFFFF }, { 0x0020, 0x0021, 0x0A0B, 0x061F, 0xFFFF }, { 0x0113, 0x0217, 0xFFFF }, { 0x0116, 0x031E,
+ 0x0B0E, 0x0405, 0xFFFF }, { 0x0022, 0x0204, 0x050A, 0x0023, 0xFFFF }, { 0x0111, 0x0319, 0x0809, 0x170F, 0xFFFF }, {
+ 0x0303, 0x0215, 0x0607, 0xFFFF }, { 0x0030, 0x0114, 0x0408, 0x0031, 0x0201, 0x051D, 0xFFFF }, { 0x0100, 0x0024, 0x0306,
+ 0x0025, 0x041B, 0x0E0D, 0xFFFF }, { 0x021A, 0x0121, 0x0B0B, 0x071F, 0xFFFF }, { 0x0213, 0x0317, 0xFFFF }, { 0x0112,
+ 0x0505, 0xFFFF }, { 0x0026, 0x070C, 0x0123, 0x0027, 0xFFFF }, { 0x0211, 0x0909, 0xFFFF }, { 0x0110, 0x0315, 0x0707,
+ 0x0419, 0x180F, 0xFFFF }, { 0x0218, 0x0131, 0x0301, 0x0403, 0x061D, 0xFFFF }, { 0x0032, 0x0202, 0x0033, 0x0125, 0x051B,
+ 0x0F0D, 0xFFFF }, { 0x0028, 0x031C, 0x0221, 0x0029, 0xFFFF }, { 0x0120, 0x0313, 0x0C0B, 0x081F, 0xFFFF }, { 0x0605,
+ 0x0417, 0xFFFF }, { 0x0216, 0x041E, 0x0C0E, 0x0223, 0x0127, 0xFFFF }, { 0x0122, 0x0304, 0x060A, 0x0311, 0x0A09, 0xFFFF
+ }, { 0x0519, 0x190F, 0xFFFF }, { 0x002A, 0x0231, 0x0503, 0x0415, 0x0807, 0x002B, 0x071D, 0xFFFF }, { 0x0130, 0x0214,
+ 0x0508, 0x0401, 0x0133, 0x0225, 0x061B, 0xFFFF }, { 0x0200, 0x0124, 0x0406, 0x0321, 0x0129, 0x100D, 0xFFFF }, { 0x031A,
+ 0x0D0B, 0x091F, 0xFFFF }, { 0x0413, 0x0705, 0x0517, 0xFFFF }, { 0x0212, 0x0034, 0x0323, 0x0035, 0x0227, 0xFFFF }, {
+ 0x0126, 0x080C, 0x0B09, 0xFFFF }, { 0x0411, 0x0619, 0x1A0F, 0xFFFF }, { 0x0210, 0x0331, 0x0603, 0x0515, 0x0907, 0x012B,
+ 0xFFFF }, { 0x0318, 0x002C, 0x0501, 0x0233, 0x0325, 0x071B, 0x002D, 0x081D, 0xFFFF }, { 0x0132, 0x0302, 0x0229, 0x110D,
+ 0xFFFF }, { 0x0128, 0x041C, 0x0421, 0x0E0B, 0x0A1F, 0xFFFF }, { 0x0220, 0x0513, 0x0617, 0xFFFF }, { 0x0135, 0x0805,
+ 0x0327, 0xFFFF }, { 0x0316, 0x051E, 0x0D0E, 0x0423, 0xFFFF }, { 0x0222, 0x0404, 0x070A, 0x0511, 0x0719, 0x0C09, 0x1B0F,
+ 0xFFFF }, { 0x0703, 0x0615, 0x0A07, 0x022B, 0xFFFF }, { 0x012A, 0x0431, 0x0601, 0x0333, 0x012D, 0x091D, 0xFFFF }, {
+ 0x0230, 0x0314, 0x0036, 0x0608, 0x0425, 0x0037, 0x0329, 0x081B, 0x120D, 0xFFFF }, { 0x0300, 0x0224, 0x0506, 0x0521,
+ 0x0F0B, 0x0B1F, 0xFFFF }, { 0x041A, 0x0613, 0x0717, 0xFFFF }, { 0x0235, 0x0905, 0xFFFF }, { 0x0312, 0x0134, 0x0523,
+ 0x0427, 0xFFFF }, { 0x0226, 0x090C, 0x002E, 0x0611, 0x0D09, 0x002F, 0xFFFF }, { 0x0715, 0x0B07, 0x0819, 0x032B, 0x1C0F,
+ 0xFFFF }, { 0x0310, 0x0531, 0x0701, 0x0803, 0x022D, 0x0A1D, 0xFFFF }, { 0x0418, 0x012C, 0x0433, 0x0525, 0x0137, 0x091B,
+ 0x130D, 0xFFFF }, { 0x0232, 0x0402, 0x0621, 0x0429, 0xFFFF }, { 0x0228, 0x051C, 0x0713, 0x100B, 0x0C1F, 0xFFFF }, {
+ 0x0320, 0x0335, 0x0A05, 0x0817, 0xFFFF }, { 0x0623, 0x0527, 0xFFFF }, { 0x0416, 0x061E, 0x0E0E, 0x0711, 0x0E09, 0x012F,
+ 0xFFFF }, { 0x0322, 0x0504, 0x080A, 0x0919, 0x1D0F, 0xFFFF }, { 0x0631, 0x0903, 0x0815, 0x0C07, 0x042B, 0x032D, 0x0B1D,
+ 0xFFFF }, { 0x022A, 0x0801, 0x0533, 0x0625, 0x0237, 0x0A1B, 0xFFFF }, { 0x0330, 0x0414, 0x0136, 0x0708, 0x0721, 0x0529,
+ 0x140D, 0xFFFF }, { 0x0400, 0x0324, 0x0606, 0x0038, 0x0039, 0x110B, 0x0D1F, 0xFFFF }, { 0x051A, 0x0813, 0x0B05, 0x0917,
+ 0xFFFF }, { 0x0723, 0x0435, 0x0627, 0xFFFF }, { 0x0412, 0x0234, 0x0F09, 0x022F, 0xFFFF }, { 0x0326, 0x0A0C, 0x012E,
+ 0x0811, 0x0A19, 0x1E0F, 0xFFFF }, { 0x0731, 0x0A03, 0x0915, 0x0D07, 0x052B, 0xFFFF }, { 0x0410, 0x0901, 0x0633, 0x0725,
+ 0x0337, 0x0B1B, 0x042D, 0x0C1D, 0xFFFF }, { 0x0518, 0x022C, 0x0629, 0x150D, 0xFFFF }, { 0x0332, 0x0502, 0x0821, 0x0139,
+ 0x120B, 0x0E1F, 0xFFFF }, { 0x0328, 0x061C, 0x0913, 0x0A17, 0xFFFF }, { 0x0420, 0x0535, 0x0C05, 0x0727, 0xFFFF }, {
+ 0x0823, 0x032F, 0xFFFF }, { 0x0516, 0x071E, 0x0F0E, 0x0911, 0x0B19, 0x1009, 0x1F0F, 0xFFFF }, { 0x0422, 0x0604, 0x090A,
+ 0x0B03, 0x0A15, 0x0E07, 0x062B, 0xFFFF }, { 0x0831, 0x0A01, 0x0733, 0x052D, 0x0D1D, 0xFFFF }, { 0x032A, 0x0825, 0x0437,
+ 0x0729, 0x0C1B, 0x160D, 0xFFFF }, { 0x0430, 0x0514, 0x0236, 0x0808, 0x0921, 0x0239, 0x130B, 0x0F1F, 0xFFFF }, { 0x0500,
+ 0x0424, 0x0706, 0x0138, 0x0A13, 0x0B17, 0xFFFF }, { 0x061A, 0x0635, 0x0D05, 0xFFFF }, { 0x0923, 0x0827, 0xFFFF }, {
+ 0x0512, 0x0334, 0x003A, 0x0A11, 0x1109, 0x003B, 0x042F, 0xFFFF }, { 0x0426, 0x0B0C, 0x022E, 0x0B15, 0x0F07, 0x0C19,
+ 0x072B, 0xFFFF }, { 0x0931, 0x0B01, 0x0C03, 0x062D, 0x0E1D, 0xFFFF }, { 0x0510, 0x0833, 0x0925, 0x0537, 0x0D1B, 0x170D,
+ 0xFFFF }, { 0x0618, 0x032C, 0x0A21, 0x0339, 0x0829, 0xFFFF }, { 0x0432, 0x0602, 0x0B13, 0x140B, 0x101F, 0xFFFF }, {
+ 0x0428, 0x071C, 0x0735, 0x0E05, 0x0C17, 0xFFFF }, { 0x0520, 0x0A23, 0x0927, 0xFFFF }, { 0x0B11, 0x1209, 0x013B, 0x052F,
+ 0xFFFF }, { 0x0616, 0x081E, 0x0D19, 0xFFFF }, { 0x0522, 0x0704, 0x0A0A, 0x0A31, 0x0D03, 0x0C15, 0x1007, 0x082B, 0x072D,
+ 0x0F1D, 0xFFFF }, { 0x0C01, 0x0933, 0x0A25, 0x0637, 0x0E1B, 0xFFFF }, { 0x042A, 0x0B21, 0x0929, 0x180D, 0xFFFF }, {
+ 0x0530, 0x0614, 0x0336, 0x0908, 0x0439, 0x150B, 0x111F, 0xFFFF }, { 0x0600, 0x0524, 0x0806, 0x0238, 0x0C13, 0x0F05,
+ 0x0D17, 0xFFFF }, { 0x071A, 0x0B23, 0x0835, 0x0A27, 0xFFFF }, { 0x1309, 0x023B, 0x062F, 0xFFFF }, { 0x0612, 0x0434,
+ 0x013A, 0x0C11, 0x0E19, 0xFFFF }, { 0x0526, 0x0C0C, 0x032E, 0x0B31, 0x0E03, 0x0D15, 0x1107, 0x092B, 0xFFFF }, { 0x0D01,
+ 0x0A33, 0x0B25, 0x0737, 0x0F1B, 0x082D, 0x101D, 0xFFFF }, { 0x0610, 0x0A29, 0x190D, 0xFFFF }, { 0x0718, 0x042C, 0x0C21,
+ 0x0539, 0x160B, 0x121F, 0xFFFF }, { 0x0532, 0x0702, 0x0D13, 0x0E17, 0xFFFF }, { 0x0528, 0x081C, 0x0935, 0x1005, 0x0B27,
+ 0xFFFF }, { 0x0620, 0x0C23, 0x033B, 0x072F, 0xFFFF }, { 0x0D11, 0x0F19, 0x1409, 0xFFFF }, { 0x0716, 0x003C, 0x091E,
+ 0x0F03, 0x0E15, 0x1207, 0x0A2B, 0x003D, 0xFFFF }, { 0x0622, 0x0804, 0x0B0A, 0x0C31, 0x0E01, 0x0B33, 0x092D, 0x111D,
+ 0xFFFF }, { 0x0C25, 0x0837, 0x0B29, 0x101B, 0x1A0D, 0xFFFF }, { 0x052A, 0x0D21, 0x0639, 0x170B, 0x131F, 0xFFFF }, {
+ 0x0630, 0x0714, 0x0436, 0x0A08, 0x0E13, 0x0F17, 0xFFFF }, { 0x0700, 0x0624, 0x0906, 0x0338, 0x0A35, 0x1105, 0xFFFF }, {
+ 0x081A, 0x0D23, 0x0C27, 0xFFFF }, { 0x0E11, 0x1509, 0x043B, 0x082F, 0xFFFF }, { 0x0712, 0x0534, 0x023A, 0x0F15, 0x1307,
+ 0x1019, 0x0B2B, 0x013D, 0xFFFF }, { 0x0626, 0x0D0C, 0x042E, 0x0D31, 0x0F01, 0x1003, 0x0A2D, 0x121D, 0xFFFF }, { 0x0C33,
+ 0x0D25, 0x0937, 0x111B, 0x1B0D, 0xFFFF }, { 0x0710, 0x0E21, 0x0739, 0x0C29, 0xFFFF }, { 0x0818, 0x052C, 0x0F13, 0x180B,
+ 0x141F, 0xFFFF }, { 0x0632, 0x0802, 0x0B35, 0x1205, 0x1017, 0xFFFF }, { 0x0628, 0x091C, 0x0E23, 0x0D27, 0xFFFF }, {
+ 0x0720, 0x0F11, 0x1609, 0x053B, 0x092F, 0xFFFF }, { 0x1119, 0x023D, 0xFFFF }, { 0x0816, 0x013C, 0x0A1E, 0x0E31, 0x1103,
+ 0x1015, 0x1407, 0x0C2B, 0x0B2D, 0x131D, 0xFFFF }, { 0x0722, 0x0904, 0x0C0A, 0x1001, 0x0D33, 0x0E25, 0x0A37, 0x121B,
+ 0xFFFF }, { 0x0F21, 0x0D29, 0x1C0D, 0xFFFF }, { 0x062A, 0x0839, 0x190B, 0x151F, 0xFFFF }, { 0x0730, 0x0814, 0x0536,
+ 0x0B08, 0x1013, 0x1305, 0x1117, 0xFFFF }, { 0x0800, 0x0724, 0x0A06, 0x0438, 0x0F23, 0x0C35, 0x0E27, 0xFFFF }, { 0x091A,
+ 0x1709, 0x063B, 0x0A2F, 0xFFFF }, { 0x1011, 0x1219, 0x033D, 0xFFFF }, { 0x0812, 0x0634, 0x033A, 0x0F31, 0x1203, 0x1115,
+ 0x1507, 0x0D2B, 0xFFFF }, { 0x0726, 0x0E0C, 0x052E, 0x1101, 0x0E33, 0x0F25, 0x0B37, 0x131B, 0x0C2D, 0x141D, 0xFFFF }, {
+ 0x0E29, 0x1D0D, 0xFFFF }, { 0x0810, 0x1021, 0x0939, 0x1A0B, 0x161F, 0xFFFF }, { 0x0918, 0x062C, 0x1113, 0x1217, 0xFFFF
+ }, { 0x0732, 0x0902, 0x0D35, 0x1405, 0x0F27, 0xFFFF }, { 0x0728, 0x0A1C, 0x1023, 0x073B, 0x0B2F, 0xFFFF }, { 0x0820,
+ 0x1111, 0x1319, 0x1809, 0xFFFF }, { 0x1303, 0x1215, 0x1607, 0x0E2B, 0x043D, 0xFFFF }, { 0x0916, 0x023C, 0x0B1E, 0x1031,
+ 0x1201, 0x0F33, 0x0D2D, 0x151D, 0xFFFF }, { 0x0822, 0x0A04, 0x0D0A, 0x1025, 0x0C37, 0x0F29, 0x141B, 0x1E0D, 0xFFFF }, {
+ 0x1121, 0x0A39, 0x1B0B, 0x171F, 0xFFFF }, { 0x072A, 0x1213, 0x1317, 0xFFFF }, { 0x0830, 0x0914, 0x0636, 0x0C08, 0x0E35,
+ 0x1505, 0xFFFF }, { 0x0900, 0x0824, 0x0B06, 0x0538, 0x1123, 0x1027, 0xFFFF }, { 0x0A1A, 0x1211, 0x1909, 0x083B, 0x0C2F,
+ 0xFFFF }, { 0x1315, 0x1707, 0x1419, 0x0F2B, 0x053D, 0xFFFF }, { 0x0912, 0x0734, 0x043A, 0x1131, 0x1301, 0x1403, 0x0E2D,
+ 0x161D, 0xFFFF }, { 0x0826, 0x0F0C, 0x062E, 0x1033, 0x1125, 0x0D37, 0x151B, 0x1F0D, 0xFFFF }, { 0x1221, 0x0B39, 0x1029,
+ 0xFFFF }, { 0x0910, 0x1313, 0x1C0B, 0x181F, 0xFFFF }, { 0x0A18, 0x072C, 0x0F35, 0x1605, 0x1417, 0xFFFF }, { 0x0832,
+ 0x0A02, 0x1223, 0x1127, 0xFFFF }, { 0x0828, 0x0B1C, 0x1311, 0x1A09, 0x093B, 0x0D2F, 0xFFFF }, { 0x0920, 0x1519, 0x063D,
+ 0xFFFF }, { 0x1231, 0x1503, 0x1415, 0x1807, 0x102B, 0x0F2D, 0x171D, 0xFFFF }, { 0x0A16, 0x033C, 0x0C1E, 0x1401, 0x1133,
+ 0x1225, 0x0E37, 0x161B, 0xFFFF }, { 0x0922, 0x0B04, 0x0E0A, 0x1321, 0x1129, 0xFFFF }, { 0x0C39, 0x1D0B, 0x191F, 0xFFFF
+ }, { 0x082A, 0x1413, 0x1705, 0x1517, 0xFFFF }, { 0x0930, 0x0A14, 0x0736, 0x0D08, 0x1323, 0x1035, 0x1227, 0xFFFF }, {
+ 0x0A00, 0x0924, 0x0C06, 0x0638, 0x1B09, 0x0A3B, 0x0E2F, 0xFFFF }, { 0x0B1A, 0x1411, 0x1619, 0x073D, 0xFFFF }, { 0x1331,
+ 0x1603, 0x1515, 0x1907, 0x112B, 0xFFFF }, { 0x0A12, 0x0834, 0x053A, 0x1501, 0x1233, 0x1325, 0x0F37, 0x171B, 0x102D,
+ 0x181D, 0xFFFF }, { 0x0926, 0x072E, 0x1229, 0xFFFF }, { 0x1421, 0x0D39, 0x1E0B, 0x1A1F, 0xFFFF }, { 0x0A10, 0x1513,
+ 0x1617, 0xFFFF }, { 0x0B18, 0x082C, 0x1135, 0x1805, 0x1327, 0xFFFF }, { 0x0932, 0x0B02, 0x1423, 0x0B3B, 0x0F2F, 0xFFFF
+ }, { 0x0928, 0x0C1C, 0x1511, 0x1719, 0x1C09, 0xFFFF }, { 0x0A20, 0x1703, 0x1615, 0x1A07, 0x122B, 0x083D, 0xFFFF }, {
+ 0x1431, 0x1601, 0x1333, 0x112D, 0x191D, 0xFFFF }, { 0x0B16, 0x043C, 0x0D1E, 0x1425, 0x1037, 0x1329, 0x181B, 0xFFFF }, {
+ 0x0A22, 0x0C04, 0x0F0A, 0x1521, 0x0E39, 0x1F0B, 0x1B1F, 0xFFFF }, { 0x1613, 0x1717, 0xFFFF }, { 0x092A, 0x1235, 0x1905,
+ 0xFFFF }, { 0x0A30, 0x0B14, 0x0836, 0x0E08, 0x1523, 0x1427, 0xFFFF }, { 0x0B00, 0x0A24, 0x0D06, 0x0738, 0x1611, 0x1D09,
+ 0x0C3B, 0x102F, 0xFFFF }, { 0x0C1A, 0x1715, 0x1B07, 0x1819, 0x132B, 0x093D, 0xFFFF }, { 0x1531, 0x1701, 0x1803, 0x122D,
+ 0x1A1D, 0xFFFF }, { 0x0B12, 0x0934, 0x063A, 0x1433, 0x1525, 0x1137, 0x191B, 0xFFFF }, { 0x0A26, 0x003E, 0x082E, 0x1621,
+ 0x0F39, 0x1429, 0x003F, 0xFFFF }, { 0x1713, 0x1C1F, 0xFFFF }, { 0x0B10, 0x1335, 0x1A05, 0x1817, 0xFFFF }, { 0x0C18,
+ 0x092C, 0x1623, 0x1527, 0xFFFF }, { 0x0A32, 0x0C02, 0x1711, 0x1E09, 0x0D3B, 0x112F, 0xFFFF }, { 0x0A28, 0x0D1C, 0x1919,
+ 0x0A3D, 0xFFFF }, { 0x0B20, 0x1631, 0x1903, 0x1815, 0x1C07, 0x142B, 0x132D, 0x1B1D, 0xFFFF }, { 0x1801, 0x1533, 0x1625,
+ 0x1237, 0x1A1B, 0xFFFF }, { 0x0C16, 0x053C, 0x0E1E, 0x1721, 0x1529, 0x013F, 0xFFFF }, { 0x0B22, 0x0D04, 0x1039, 0x1D1F,
+ 0xFFFF }, { 0x1813, 0x1B05, 0x1917, 0xFFFF }, { 0x0A2A, 0x1723, 0x1435, 0x1627, 0xFFFF }, { 0x0B30, 0x0C14, 0x0936,
+ 0x0F08, 0x1F09, 0x0E3B, 0x122F, 0xFFFF }, { 0x0C00, 0x0B24, 0x0E06, 0x0838, 0x1811, 0x1A19, 0x0B3D, 0xFFFF }, { 0x0D1A,
+ 0x1731, 0x1A03, 0x1915, 0x1D07, 0x152B, 0xFFFF }, { 0x1901, 0x1633, 0x1725, 0x1337, 0x1B1B, 0x142D, 0x1C1D, 0xFFFF }, {
+ 0x0C12, 0x0A34, 0x073A, 0x1629, 0x023F, 0xFFFF }, { 0x0B26, 0x013E, 0x092E, 0x1821, 0x1139, 0x1E1F, 0xFFFF }, { 0x1913,
+ 0x1A17, 0xFFFF }, { 0x0C10, 0x1535, 0x1C05, 0x1727, 0xFFFF }, { 0x0D18, 0x0A2C, 0x1823, 0x0F3B, 0x132F, 0xFFFF }, {
+ 0x0B32, 0x0D02, 0x1911, 0x1B19, 0xFFFF }, { 0x0B28, 0x0E1C, 0x1B03, 0x1A15, 0x1E07, 0x162B, 0x0C3D, 0xFFFF }, { 0x0C20,
+ 0x1831, 0x1A01, 0x1733, 0x152D, 0x1D1D, 0xFFFF }, { 0x1825, 0x1437, 0x1729, 0x1C1B, 0x033F, 0xFFFF }, { 0x0D16, 0x063C,
+ 0x0F1E, 0x1921, 0x1239, 0x1F1F, 0xFFFF }, { 0x0C22, 0x0E04, 0x1A13, 0x1B17, 0xFFFF }, { 0x1635, 0x1D05, 0xFFFF }, {
+ 0x0B2A, 0x1923, 0x1827, 0xFFFF }, { 0x0C30, 0x0D14, 0x0A36, 0x1A11, 0x103B, 0x142F, 0xFFFF }, { 0x0D00, 0x0C24, 0x0F06,
+ 0x0938, 0x1B15, 0x1F07, 0x1C19, 0x172B, 0x0D3D, 0xFFFF }, { 0x0E1A, 0x1931, 0x1B01, 0x1C03, 0x162D, 0x1E1D, 0xFFFF }, {
+ 0x1833, 0x1925, 0x1537, 0x1D1B, 0xFFFF }, { 0x0D12, 0x0B34, 0x083A, 0x1A21, 0x1339, 0x1829, 0x043F, 0xFFFF }, { 0x0C26,
+ 0x023E, 0x0A2E, 0x1B13, 0xFFFF }, { 0x1735, 0x1E05, 0x1C17, 0xFFFF }, { 0x0D10, 0x1A23, 0x1927, 0xFFFF }, { 0x0E18,
+ 0x0B2C, 0x1B11, 0x113B, 0x152F, 0xFFFF }, { 0x0C32, 0x0E02, 0x1D19, 0x0E3D, 0xFFFF }, { 0x0C28, 0x0F1C, 0x1A31, 0x1D03,
+ 0x1C15, 0x182B, 0x172D, 0x1F1D, 0xFFFF }, { 0x0D20, 0x1C01, 0x1933, 0x1A25, 0x1637, 0x1E1B, 0xFFFF }, { 0x1B21, 0x1929,
+ 0x053F, 0xFFFF }, { 0x0E16, 0x073C, 0x1439, 0xFFFF }, { 0x0D22, 0x0F04, 0x1C13, 0x1F05, 0x1D17, 0xFFFF }, { 0x1B23,
+ 0x1835, 0x1A27, 0xFFFF }, { 0x0C2A, 0x123B, 0x162F, 0xFFFF }, { 0x0D30, 0x0E14, 0x0B36, 0x1C11, 0x1E19, 0x0F3D, 0xFFFF
+ }, { 0x0E00, 0x0D24, 0x0A38, 0x1B31, 0x1E03, 0x1D15, 0x192B, 0xFFFF }, { 0x0F1A, 0x1D01, 0x1A33, 0x1B25, 0x1737, 0x1F1B,
+ 0x182D, 0xFFFF }, { 0x1A29, 0x063F, 0xFFFF }, { 0x0E12, 0x0C34, 0x093A, 0x1C21, 0x1539, 0xFFFF }, { 0x0D26, 0x033E,
+ 0x0B2E, 0x1D13, 0x1E17, 0xFFFF }, { 0x1935, 0x1B27, 0xFFFF }, { 0x0E10, 0x1C23, 0x133B, 0x172F, 0xFFFF }, { 0x0F18,
+ 0x0C2C, 0x1D11, 0x1F19, 0xFFFF }, { 0x0D32, 0x0F02, 0x1F03, 0x1E15, 0x1A2B, 0x103D, 0xFFFF }, { 0x0D28, 0x1C31, 0x1E01,
+ 0x1B33, 0x192D, 0xFFFF }, { 0x0E20, 0x1C25, 0x1837, 0x1B29, 0x073F, 0xFFFF }, { 0x1D21, 0x1639, 0xFFFF }, { 0x0F16,
+ 0x083C, 0x1E13, 0x1F17, 0xFFFF }, { 0x0E22, 0x1A35, 0xFFFF }, { 0x1D23, 0x1C27, 0xFFFF }, { 0x0D2A, 0x1E11, 0x143B,
+ 0x182F, 0xFFFF }, { 0x0E30, 0x0F14, 0x0C36, 0x1F15, 0x1B2B, 0x113D, 0xFFFF }, { 0x0F00, 0x0E24, 0x0B38, 0x1D31, 0x1F01,
+ 0x1A2D, 0xFFFF }, { 0x1C33, 0x1D25, 0x1937, 0xFFFF }, { 0x1E21, 0x1739, 0x1C29, 0x083F, 0xFFFF }, { 0x0F12, 0x0D34,
+ 0x0A3A, 0x1F13, 0xFFFF }, { 0x0E26, 0x043E, 0x0C2E, 0x1B35, 0xFFFF }, { 0x1E23, 0x1D27, 0xFFFF }, { 0x0F10, 0x1F11,
+ 0x153B, 0x192F, 0xFFFF }, { 0x0D2C, 0x123D, 0xFFFF },
+ };
+
+ struct etc1_block
+ {
+ // big endian uint64:
+ // bit ofs: 56 48 40 32 24 16 8 0
+ // byte ofs: b0, b1, b2, b3, b4, b5, b6, b7
+ union
+ {
+ uint64 m_uint64;
+ uint8 m_bytes[8];
+ };
+
+ uint8 m_low_color[2];
+ uint8 m_high_color[2];
+
+ enum { cNumSelectorBytes = 4 };
+ uint8 m_selectors[cNumSelectorBytes];
+
+ inline void clear()
+ {
+ zero_this(this);
+ }
+
+ inline uint get_byte_bits(uint ofs, uint num) const
+ {
+ RG_ETC1_ASSERT((ofs + num) <= 64U);
+ RG_ETC1_ASSERT(num && (num <= 8U));
+ RG_ETC1_ASSERT((ofs >> 3) == ((ofs + num - 1) >> 3));
+ const uint byte_ofs = 7 - (ofs >> 3);
+ const uint byte_bit_ofs = ofs & 7;
+ return (m_bytes[byte_ofs] >> byte_bit_ofs) & ((1 << num) - 1);
+ }
+
+ inline void set_byte_bits(uint ofs, uint num, uint bits)
+ {
+ RG_ETC1_ASSERT((ofs + num) <= 64U);
+ RG_ETC1_ASSERT(num && (num < 32U));
+ RG_ETC1_ASSERT((ofs >> 3) == ((ofs + num - 1) >> 3));
+ RG_ETC1_ASSERT(bits < (1U << num));
+ const uint byte_ofs = 7 - (ofs >> 3);
+ const uint byte_bit_ofs = ofs & 7;
+ const uint mask = (1 << num) - 1;
+ m_bytes[byte_ofs] &= ~(mask << byte_bit_ofs);
+ m_bytes[byte_ofs] |= (bits << byte_bit_ofs);
+ }
+
+ // false = left/right subblocks
+ // true = upper/lower subblocks
+ inline bool get_flip_bit() const
+ {
+ return (m_bytes[3] & 1) != 0;
+ }
+
+ inline void set_flip_bit(bool flip)
+ {
+ m_bytes[3] &= ~1;
+ m_bytes[3] |= static_cast<uint8>(flip);
+ }
+
+ inline bool get_diff_bit() const
+ {
+ return (m_bytes[3] & 2) != 0;
+ }
+
+ inline void set_diff_bit(bool diff)
+ {
+ m_bytes[3] &= ~2;
+ m_bytes[3] |= (static_cast<uint>(diff) << 1);
+ }
+
+ // Returns intensity modifier table (0-7) used by subblock subblock_id.
+ // subblock_id=0 left/top (CW 1), 1=right/bottom (CW 2)
+ inline uint get_inten_table(uint subblock_id) const
+ {
+ RG_ETC1_ASSERT(subblock_id < 2);
+ const uint ofs = subblock_id ? 2 : 5;
+ return (m_bytes[3] >> ofs) & 7;
+ }
+
+ // Sets intensity modifier table (0-7) used by subblock subblock_id (0 or 1)
+ inline void set_inten_table(uint subblock_id, uint t)
+ {
+ RG_ETC1_ASSERT(subblock_id < 2);
+ RG_ETC1_ASSERT(t < 8);
+ const uint ofs = subblock_id ? 2 : 5;
+ m_bytes[3] &= ~(7 << ofs);
+ m_bytes[3] |= (t << ofs);
+ }
+
+ // Returned selector value ranges from 0-3 and is a direct index into g_etc1_inten_tables.
+ inline uint get_selector(uint x, uint y) const
+ {
+ RG_ETC1_ASSERT((x | y) < 4);
+
+ const uint bit_index = x * 4 + y;
+ const uint byte_bit_ofs = bit_index & 7;
+ const uint8 *p = &m_bytes[7 - (bit_index >> 3)];
+ const uint lsb = (p[0] >> byte_bit_ofs) & 1;
+ const uint msb = (p[-2] >> byte_bit_ofs) & 1;
+ const uint val = lsb | (msb << 1);
+
+ return g_etc1_to_selector_index[val];
+ }
+
+ // Selector "val" ranges from 0-3 and is a direct index into g_etc1_inten_tables.
+ inline void set_selector(uint x, uint y, uint val)
+ {
+ RG_ETC1_ASSERT((x | y | val) < 4);
+ const uint bit_index = x * 4 + y;
+
+ uint8 *p = &m_bytes[7 - (bit_index >> 3)];
+
+ const uint byte_bit_ofs = bit_index & 7;
+ const uint mask = 1 << byte_bit_ofs;
+
+ const uint etc1_val = g_selector_index_to_etc1[val];
+
+ const uint lsb = etc1_val & 1;
+ const uint msb = etc1_val >> 1;
+
+ p[0] &= ~mask;
+ p[0] |= (lsb << byte_bit_ofs);
+
+ p[-2] &= ~mask;
+ p[-2] |= (msb << byte_bit_ofs);
+ }
+
+ inline void set_base4_color(uint idx, uint16 c)
+ {
+ if (idx)
+ {
+ set_byte_bits(cETC1AbsColor4R2BitOffset, 4, (c >> 8) & 15);
+ set_byte_bits(cETC1AbsColor4G2BitOffset, 4, (c >> 4) & 15);
+ set_byte_bits(cETC1AbsColor4B2BitOffset, 4, c & 15);
+ }
+ else
+ {
+ set_byte_bits(cETC1AbsColor4R1BitOffset, 4, (c >> 8) & 15);
+ set_byte_bits(cETC1AbsColor4G1BitOffset, 4, (c >> 4) & 15);
+ set_byte_bits(cETC1AbsColor4B1BitOffset, 4, c & 15);
+ }
+ }
+
+ inline uint16 get_base4_color(uint idx) const
+ {
+ uint r, g, b;
+ if (idx)
+ {
+ r = get_byte_bits(cETC1AbsColor4R2BitOffset, 4);
+ g = get_byte_bits(cETC1AbsColor4G2BitOffset, 4);
+ b = get_byte_bits(cETC1AbsColor4B2BitOffset, 4);
+ }
+ else
+ {
+ r = get_byte_bits(cETC1AbsColor4R1BitOffset, 4);
+ g = get_byte_bits(cETC1AbsColor4G1BitOffset, 4);
+ b = get_byte_bits(cETC1AbsColor4B1BitOffset, 4);
+ }
+ return static_cast<uint16>(b | (g << 4U) | (r << 8U));
+ }
+
+ inline void set_base5_color(uint16 c)
+ {
+ set_byte_bits(cETC1BaseColor5RBitOffset, 5, (c >> 10) & 31);
+ set_byte_bits(cETC1BaseColor5GBitOffset, 5, (c >> 5) & 31);
+ set_byte_bits(cETC1BaseColor5BBitOffset, 5, c & 31);
+ }
+
+ inline uint16 get_base5_color() const
+ {
+ const uint r = get_byte_bits(cETC1BaseColor5RBitOffset, 5);
+ const uint g = get_byte_bits(cETC1BaseColor5GBitOffset, 5);
+ const uint b = get_byte_bits(cETC1BaseColor5BBitOffset, 5);
+ return static_cast<uint16>(b | (g << 5U) | (r << 10U));
+ }
+
+ void set_delta3_color(uint16 c)
+ {
+ set_byte_bits(cETC1DeltaColor3RBitOffset, 3, (c >> 6) & 7);
+ set_byte_bits(cETC1DeltaColor3GBitOffset, 3, (c >> 3) & 7);
+ set_byte_bits(cETC1DeltaColor3BBitOffset, 3, c & 7);
+ }
+
+ inline uint16 get_delta3_color() const
+ {
+ const uint r = get_byte_bits(cETC1DeltaColor3RBitOffset, 3);
+ const uint g = get_byte_bits(cETC1DeltaColor3GBitOffset, 3);
+ const uint b = get_byte_bits(cETC1DeltaColor3BBitOffset, 3);
+ return static_cast<uint16>(b | (g << 3U) | (r << 6U));
+ }
+
+ // Base color 5
+ static uint16 pack_color5(const color_quad_u8& color, bool scaled, uint bias = 127U);
+ static uint16 pack_color5(uint r, uint g, uint b, bool scaled, uint bias = 127U);
+
+ static color_quad_u8 unpack_color5(uint16 packed_color5, bool scaled, uint alpha = 255U);
+ static void unpack_color5(uint& r, uint& g, uint& b, uint16 packed_color, bool scaled);
+
+ static bool unpack_color5(color_quad_u8& result, uint16 packed_color5, uint16 packed_delta3, bool scaled, uint alpha = 255U);
+ static bool unpack_color5(uint& r, uint& g, uint& b, uint16 packed_color5, uint16 packed_delta3, bool scaled, uint alpha = 255U);
+
+ // Delta color 3
+ // Inputs range from -4 to 3 (cETC1ColorDeltaMin to cETC1ColorDeltaMax)
+ static uint16 pack_delta3(int r, int g, int b);
+
+ // Results range from -4 to 3 (cETC1ColorDeltaMin to cETC1ColorDeltaMax)
+ static void unpack_delta3(int& r, int& g, int& b, uint16 packed_delta3);
+
+ // Abs color 4
+ static uint16 pack_color4(const color_quad_u8& color, bool scaled, uint bias = 127U);
+ static uint16 pack_color4(uint r, uint g, uint b, bool scaled, uint bias = 127U);
+
+ static color_quad_u8 unpack_color4(uint16 packed_color4, bool scaled, uint alpha = 255U);
+ static void unpack_color4(uint& r, uint& g, uint& b, uint16 packed_color4, bool scaled);
+
+ // subblock colors
+ static void get_diff_subblock_colors(color_quad_u8* pDst, uint16 packed_color5, uint table_idx);
+ static bool get_diff_subblock_colors(color_quad_u8* pDst, uint16 packed_color5, uint16 packed_delta3, uint table_idx);
+ static void get_abs_subblock_colors(color_quad_u8* pDst, uint16 packed_color4, uint table_idx);
+
+ static inline void unscaled_to_scaled_color(color_quad_u8& dst, const color_quad_u8& src, bool color4)
+ {
+ if (color4)
+ {
+ dst.r = src.r | (src.r << 4);
+ dst.g = src.g | (src.g << 4);
+ dst.b = src.b | (src.b << 4);
+ }
+ else
+ {
+ dst.r = (src.r >> 2) | (src.r << 3);
+ dst.g = (src.g >> 2) | (src.g << 3);
+ dst.b = (src.b >> 2) | (src.b << 3);
+ }
+ dst.a = src.a;
+ }
+ };
+
+ // Returns pointer to sorted array.
+ template<typename T, typename Q>
+ T* indirect_radix_sort(uint num_indices, T* pIndices0, T* pIndices1, const Q* pKeys, uint key_ofs, uint key_size, bool init_indices)
+ {
+ RG_ETC1_ASSERT((key_ofs >= 0) && (key_ofs < sizeof(T)));
+ RG_ETC1_ASSERT((key_size >= 1) && (key_size <= 4));
+
+ if (init_indices)
+ {
+ T* p = pIndices0;
+ T* q = pIndices0 + (num_indices >> 1) * 2;
+ uint i;
+ for (i = 0; p != q; p += 2, i += 2)
+ {
+ p[0] = static_cast<T>(i);
+ p[1] = static_cast<T>(i + 1);
+ }
+
+ if (num_indices & 1)
+ *p = static_cast<T>(i);
+ }
+
+ uint hist[256 * 4];
+
+ memset(hist, 0, sizeof(hist[0]) * 256 * key_size);
+
+#define RG_ETC1_GET_KEY(p) (*(const uint*)((const uint8*)(pKeys + *(p)) + key_ofs))
+#define RG_ETC1_GET_KEY_FROM_INDEX(i) (*(const uint*)((const uint8*)(pKeys + (i)) + key_ofs))
+
+ if (key_size == 4)
+ {
+ T* p = pIndices0;
+ T* q = pIndices0 + num_indices;
+ for ( ; p != q; p++)
+ {
+ const uint key = RG_ETC1_GET_KEY(p);
+
+ hist[ key & 0xFF]++;
+ hist[256 + ((key >> 8) & 0xFF)]++;
+ hist[512 + ((key >> 16) & 0xFF)]++;
+ hist[768 + ((key >> 24) & 0xFF)]++;
+ }
+ }
+ else if (key_size == 3)
+ {
+ T* p = pIndices0;
+ T* q = pIndices0 + num_indices;
+ for ( ; p != q; p++)
+ {
+ const uint key = RG_ETC1_GET_KEY(p);
+
+ hist[ key & 0xFF]++;
+ hist[256 + ((key >> 8) & 0xFF)]++;
+ hist[512 + ((key >> 16) & 0xFF)]++;
+ }
+ }
+ else if (key_size == 2)
+ {
+ T* p = pIndices0;
+ T* q = pIndices0 + (num_indices >> 1) * 2;
+
+ for ( ; p != q; p += 2)
+ {
+ const uint key0 = RG_ETC1_GET_KEY(p);
+ const uint key1 = RG_ETC1_GET_KEY(p+1);
+
+ hist[ key0 & 0xFF]++;
+ hist[256 + ((key0 >> 8) & 0xFF)]++;
+
+ hist[ key1 & 0xFF]++;
+ hist[256 + ((key1 >> 8) & 0xFF)]++;
+ }
+
+ if (num_indices & 1)
+ {
+ const uint key = RG_ETC1_GET_KEY(p);
+
+ hist[ key & 0xFF]++;
+ hist[256 + ((key >> 8) & 0xFF)]++;
+ }
+ }
+ else
+ {
+ RG_ETC1_ASSERT(key_size == 1);
+ if (key_size != 1)
+ return NULL;
+
+ T* p = pIndices0;
+ T* q = pIndices0 + (num_indices >> 1) * 2;
+
+ for ( ; p != q; p += 2)
+ {
+ const uint key0 = RG_ETC1_GET_KEY(p);
+ const uint key1 = RG_ETC1_GET_KEY(p+1);
+
+ hist[key0 & 0xFF]++;
+ hist[key1 & 0xFF]++;
+ }
+
+ if (num_indices & 1)
+ {
+ const uint key = RG_ETC1_GET_KEY(p);
+
+ hist[key & 0xFF]++;
+ }
+ }
+
+ T* pCur = pIndices0;
+ T* pNew = pIndices1;
+
+ for (uint pass = 0; pass < key_size; pass++)
+ {
+ const uint* pHist = &hist[pass << 8];
+
+ uint offsets[256];
+
+ uint cur_ofs = 0;
+ for (uint i = 0; i < 256; i += 2)
+ {
+ offsets[i] = cur_ofs;
+ cur_ofs += pHist[i];
+
+ offsets[i+1] = cur_ofs;
+ cur_ofs += pHist[i+1];
+ }
+
+ const uint pass_shift = pass << 3;
+
+ T* p = pCur;
+ T* q = pCur + (num_indices >> 1) * 2;
+
+ for ( ; p != q; p += 2)
+ {
+ uint index0 = p[0];
+ uint index1 = p[1];
+
+ uint c0 = (RG_ETC1_GET_KEY_FROM_INDEX(index0) >> pass_shift) & 0xFF;
+ uint c1 = (RG_ETC1_GET_KEY_FROM_INDEX(index1) >> pass_shift) & 0xFF;
+
+ if (c0 == c1)
+ {
+ uint dst_offset0 = offsets[c0];
+
+ offsets[c0] = dst_offset0 + 2;
+
+ pNew[dst_offset0] = static_cast<T>(index0);
+ pNew[dst_offset0 + 1] = static_cast<T>(index1);
+ }
+ else
+ {
+ uint dst_offset0 = offsets[c0]++;
+ uint dst_offset1 = offsets[c1]++;
+
+ pNew[dst_offset0] = static_cast<T>(index0);
+ pNew[dst_offset1] = static_cast<T>(index1);
+ }
+ }
+
+ if (num_indices & 1)
+ {
+ uint index = *p;
+ uint c = (RG_ETC1_GET_KEY_FROM_INDEX(index) >> pass_shift) & 0xFF;
+
+ uint dst_offset = offsets[c];
+ offsets[c] = dst_offset + 1;
+
+ pNew[dst_offset] = static_cast<T>(index);
+ }
+
+ T* t = pCur;
+ pCur = pNew;
+ pNew = t;
+ }
+
+ return pCur;
+ }
+
+#undef RG_ETC1_GET_KEY
+#undef RG_ETC1_GET_KEY_FROM_INDEX
+
+ uint16 etc1_block::pack_color5(const color_quad_u8& color, bool scaled, uint bias)
+ {
+ return pack_color5(color.r, color.g, color.b, scaled, bias);
+ }
+
+ uint16 etc1_block::pack_color5(uint r, uint g, uint b, bool scaled, uint bias)
+ {
+ if (scaled)
+ {
+ r = (r * 31U + bias) / 255U;
+ g = (g * 31U + bias) / 255U;
+ b = (b * 31U + bias) / 255U;
+ }
+
+ r = rg_etc1::minimum(r, 31U);
+ g = rg_etc1::minimum(g, 31U);
+ b = rg_etc1::minimum(b, 31U);
+
+ return static_cast<uint16>(b | (g << 5U) | (r << 10U));
+ }
+
+ color_quad_u8 etc1_block::unpack_color5(uint16 packed_color5, bool scaled, uint alpha)
+ {
+ uint b = packed_color5 & 31U;
+ uint g = (packed_color5 >> 5U) & 31U;
+ uint r = (packed_color5 >> 10U) & 31U;
+
+ if (scaled)
+ {
+ b = (b << 3U) | (b >> 2U);
+ g = (g << 3U) | (g >> 2U);
+ r = (r << 3U) | (r >> 2U);
+ }
+
+ return color_quad_u8(cNoClamp, r, g, b, rg_etc1::minimum(alpha, 255U));
+ }
+
+ void etc1_block::unpack_color5(uint& r, uint& g, uint& b, uint16 packed_color5, bool scaled)
+ {
+ color_quad_u8 c(unpack_color5(packed_color5, scaled, 0));
+ r = c.r;
+ g = c.g;
+ b = c.b;
+ }
+
+ bool etc1_block::unpack_color5(color_quad_u8& result, uint16 packed_color5, uint16 packed_delta3, bool scaled, uint alpha)
+ {
+ int dc_r, dc_g, dc_b;
+ unpack_delta3(dc_r, dc_g, dc_b, packed_delta3);
+
+ int b = (packed_color5 & 31U) + dc_b;
+ int g = ((packed_color5 >> 5U) & 31U) + dc_g;
+ int r = ((packed_color5 >> 10U) & 31U) + dc_r;
+
+ bool success = true;
+ if (static_cast<uint>(r | g | b) > 31U)
+ {
+ success = false;
+ r = rg_etc1::clamp<int>(r, 0, 31);
+ g = rg_etc1::clamp<int>(g, 0, 31);
+ b = rg_etc1::clamp<int>(b, 0, 31);
+ }
+
+ if (scaled)
+ {
+ b = (b << 3U) | (b >> 2U);
+ g = (g << 3U) | (g >> 2U);
+ r = (r << 3U) | (r >> 2U);
+ }
+
+ result.set_noclamp_rgba(r, g, b, rg_etc1::minimum(alpha, 255U));
+ return success;
+ }
+
+ bool etc1_block::unpack_color5(uint& r, uint& g, uint& b, uint16 packed_color5, uint16 packed_delta3, bool scaled, uint alpha)
+ {
+ color_quad_u8 result;
+ const bool success = unpack_color5(result, packed_color5, packed_delta3, scaled, alpha);
+ r = result.r;
+ g = result.g;
+ b = result.b;
+ return success;
+ }
+
+ uint16 etc1_block::pack_delta3(int r, int g, int b)
+ {
+ RG_ETC1_ASSERT((r >= cETC1ColorDeltaMin) && (r <= cETC1ColorDeltaMax));
+ RG_ETC1_ASSERT((g >= cETC1ColorDeltaMin) && (g <= cETC1ColorDeltaMax));
+ RG_ETC1_ASSERT((b >= cETC1ColorDeltaMin) && (b <= cETC1ColorDeltaMax));
+ if (r < 0) r += 8;
+ if (g < 0) g += 8;
+ if (b < 0) b += 8;
+ return static_cast<uint16>(b | (g << 3) | (r << 6));
+ }
+
+ void etc1_block::unpack_delta3(int& r, int& g, int& b, uint16 packed_delta3)
+ {
+ r = (packed_delta3 >> 6) & 7;
+ g = (packed_delta3 >> 3) & 7;
+ b = packed_delta3 & 7;
+ if (r >= 4) r -= 8;
+ if (g >= 4) g -= 8;
+ if (b >= 4) b -= 8;
+ }
+
+ uint16 etc1_block::pack_color4(const color_quad_u8& color, bool scaled, uint bias)
+ {
+ return pack_color4(color.r, color.g, color.b, scaled, bias);
+ }
+
+ uint16 etc1_block::pack_color4(uint r, uint g, uint b, bool scaled, uint bias)
+ {
+ if (scaled)
+ {
+ r = (r * 15U + bias) / 255U;
+ g = (g * 15U + bias) / 255U;
+ b = (b * 15U + bias) / 255U;
+ }
+
+ r = rg_etc1::minimum(r, 15U);
+ g = rg_etc1::minimum(g, 15U);
+ b = rg_etc1::minimum(b, 15U);
+
+ return static_cast<uint16>(b | (g << 4U) | (r << 8U));
+ }
+
+ color_quad_u8 etc1_block::unpack_color4(uint16 packed_color4, bool scaled, uint alpha)
+ {
+ uint b = packed_color4 & 15U;
+ uint g = (packed_color4 >> 4U) & 15U;
+ uint r = (packed_color4 >> 8U) & 15U;
+
+ if (scaled)
+ {
+ b = (b << 4U) | b;
+ g = (g << 4U) | g;
+ r = (r << 4U) | r;
+ }
+
+ return color_quad_u8(cNoClamp, r, g, b, rg_etc1::minimum(alpha, 255U));
+ }
+
+ void etc1_block::unpack_color4(uint& r, uint& g, uint& b, uint16 packed_color4, bool scaled)
+ {
+ color_quad_u8 c(unpack_color4(packed_color4, scaled, 0));
+ r = c.r;
+ g = c.g;
+ b = c.b;
+ }
+
+ void etc1_block::get_diff_subblock_colors(color_quad_u8* pDst, uint16 packed_color5, uint table_idx)
+ {
+ RG_ETC1_ASSERT(table_idx < cETC1IntenModifierValues);
+ const int *pInten_modifer_table = &g_etc1_inten_tables[table_idx][0];
+
+ uint r, g, b;
+ unpack_color5(r, g, b, packed_color5, true);
+
+ const int ir = static_cast<int>(r), ig = static_cast<int>(g), ib = static_cast<int>(b);
+
+ const int y0 = pInten_modifer_table[0];
+ pDst[0].set(ir + y0, ig + y0, ib + y0);
+
+ const int y1 = pInten_modifer_table[1];
+ pDst[1].set(ir + y1, ig + y1, ib + y1);
+
+ const int y2 = pInten_modifer_table[2];
+ pDst[2].set(ir + y2, ig + y2, ib + y2);
+
+ const int y3 = pInten_modifer_table[3];
+ pDst[3].set(ir + y3, ig + y3, ib + y3);
+ }
+
+ bool etc1_block::get_diff_subblock_colors(color_quad_u8* pDst, uint16 packed_color5, uint16 packed_delta3, uint table_idx)
+ {
+ RG_ETC1_ASSERT(table_idx < cETC1IntenModifierValues);
+ const int *pInten_modifer_table = &g_etc1_inten_tables[table_idx][0];
+
+ uint r, g, b;
+ bool success = unpack_color5(r, g, b, packed_color5, packed_delta3, true);
+
+ const int ir = static_cast<int>(r), ig = static_cast<int>(g), ib = static_cast<int>(b);
+
+ const int y0 = pInten_modifer_table[0];
+ pDst[0].set(ir + y0, ig + y0, ib + y0);
+
+ const int y1 = pInten_modifer_table[1];
+ pDst[1].set(ir + y1, ig + y1, ib + y1);
+
+ const int y2 = pInten_modifer_table[2];
+ pDst[2].set(ir + y2, ig + y2, ib + y2);
+
+ const int y3 = pInten_modifer_table[3];
+ pDst[3].set(ir + y3, ig + y3, ib + y3);
+
+ return success;
+ }
+
+ void etc1_block::get_abs_subblock_colors(color_quad_u8* pDst, uint16 packed_color4, uint table_idx)
+ {
+ RG_ETC1_ASSERT(table_idx < cETC1IntenModifierValues);
+ const int *pInten_modifer_table = &g_etc1_inten_tables[table_idx][0];
+
+ uint r, g, b;
+ unpack_color4(r, g, b, packed_color4, true);
+
+ const int ir = static_cast<int>(r), ig = static_cast<int>(g), ib = static_cast<int>(b);
+
+ const int y0 = pInten_modifer_table[0];
+ pDst[0].set(ir + y0, ig + y0, ib + y0);
+
+ const int y1 = pInten_modifer_table[1];
+ pDst[1].set(ir + y1, ig + y1, ib + y1);
+
+ const int y2 = pInten_modifer_table[2];
+ pDst[2].set(ir + y2, ig + y2, ib + y2);
+
+ const int y3 = pInten_modifer_table[3];
+ pDst[3].set(ir + y3, ig + y3, ib + y3);
+ }
+
+ bool unpack_etc1_block(const void* pETC1_block, unsigned int* pDst_pixels_rgba, bool preserve_alpha)
+ {
+ color_quad_u8* pDst = reinterpret_cast<color_quad_u8*>(pDst_pixels_rgba);
+ const etc1_block& block = *static_cast<const etc1_block*>(pETC1_block);
+
+ const bool diff_flag = block.get_diff_bit();
+ const bool flip_flag = block.get_flip_bit();
+ const uint table_index0 = block.get_inten_table(0);
+ const uint table_index1 = block.get_inten_table(1);
+
+ color_quad_u8 subblock_colors0[4];
+ color_quad_u8 subblock_colors1[4];
+ bool success = true;
+
+ if (diff_flag)
+ {
+ const uint16 base_color5 = block.get_base5_color();
+ const uint16 delta_color3 = block.get_delta3_color();
+ etc1_block::get_diff_subblock_colors(subblock_colors0, base_color5, table_index0);
+
+ if (!etc1_block::get_diff_subblock_colors(subblock_colors1, base_color5, delta_color3, table_index1))
+ success = false;
+ }
+ else
+ {
+ const uint16 base_color4_0 = block.get_base4_color(0);
+ etc1_block::get_abs_subblock_colors(subblock_colors0, base_color4_0, table_index0);
+
+ const uint16 base_color4_1 = block.get_base4_color(1);
+ etc1_block::get_abs_subblock_colors(subblock_colors1, base_color4_1, table_index1);
+ }
+
+ if (preserve_alpha)
+ {
+ if (flip_flag)
+ {
+ for (uint y = 0; y < 2; y++)
+ {
+ pDst[0].set_rgb(subblock_colors0[block.get_selector(0, y)]);
+ pDst[1].set_rgb(subblock_colors0[block.get_selector(1, y)]);
+ pDst[2].set_rgb(subblock_colors0[block.get_selector(2, y)]);
+ pDst[3].set_rgb(subblock_colors0[block.get_selector(3, y)]);
+ pDst += 4;
+ }
+
+ for (uint y = 2; y < 4; y++)
+ {
+ pDst[0].set_rgb(subblock_colors1[block.get_selector(0, y)]);
+ pDst[1].set_rgb(subblock_colors1[block.get_selector(1, y)]);
+ pDst[2].set_rgb(subblock_colors1[block.get_selector(2, y)]);
+ pDst[3].set_rgb(subblock_colors1[block.get_selector(3, y)]);
+ pDst += 4;
+ }
+ }
+ else
+ {
+ for (uint y = 0; y < 4; y++)
+ {
+ pDst[0].set_rgb(subblock_colors0[block.get_selector(0, y)]);
+ pDst[1].set_rgb(subblock_colors0[block.get_selector(1, y)]);
+ pDst[2].set_rgb(subblock_colors1[block.get_selector(2, y)]);
+ pDst[3].set_rgb(subblock_colors1[block.get_selector(3, y)]);
+ pDst += 4;
+ }
+ }
+ }
+ else
+ {
+ if (flip_flag)
+ {
+ // 0000
+ // 0000
+ // 1111
+ // 1111
+ for (uint y = 0; y < 2; y++)
+ {
+ pDst[0] = subblock_colors0[block.get_selector(0, y)];
+ pDst[1] = subblock_colors0[block.get_selector(1, y)];
+ pDst[2] = subblock_colors0[block.get_selector(2, y)];
+ pDst[3] = subblock_colors0[block.get_selector(3, y)];
+ pDst += 4;
+ }
+
+ for (uint y = 2; y < 4; y++)
+ {
+ pDst[0] = subblock_colors1[block.get_selector(0, y)];
+ pDst[1] = subblock_colors1[block.get_selector(1, y)];
+ pDst[2] = subblock_colors1[block.get_selector(2, y)];
+ pDst[3] = subblock_colors1[block.get_selector(3, y)];
+ pDst += 4;
+ }
+ }
+ else
+ {
+ // 0011
+ // 0011
+ // 0011
+ // 0011
+ for (uint y = 0; y < 4; y++)
+ {
+ pDst[0] = subblock_colors0[block.get_selector(0, y)];
+ pDst[1] = subblock_colors0[block.get_selector(1, y)];
+ pDst[2] = subblock_colors1[block.get_selector(2, y)];
+ pDst[3] = subblock_colors1[block.get_selector(3, y)];
+ pDst += 4;
+ }
+ }
+ }
+
+ return success;
+ }
+
+ struct etc1_solution_coordinates
+ {
+ inline etc1_solution_coordinates() :
+ m_unscaled_color(0, 0, 0, 0),
+ m_inten_table(0),
+ m_color4(false)
+ {
+ }
+
+ inline etc1_solution_coordinates(uint r, uint g, uint b, uint inten_table, bool color4) :
+ m_unscaled_color(r, g, b, 255),
+ m_inten_table(inten_table),
+ m_color4(color4)
+ {
+ }
+
+ inline etc1_solution_coordinates(const color_quad_u8& c, uint inten_table, bool color4) :
+ m_unscaled_color(c),
+ m_inten_table(inten_table),
+ m_color4(color4)
+ {
+ }
+
+ inline etc1_solution_coordinates(const etc1_solution_coordinates& other)
+ {
+ *this = other;
+ }
+
+ inline etc1_solution_coordinates& operator= (const etc1_solution_coordinates& rhs)
+ {
+ m_unscaled_color = rhs.m_unscaled_color;
+ m_inten_table = rhs.m_inten_table;
+ m_color4 = rhs.m_color4;
+ return *this;
+ }
+
+ inline void clear()
+ {
+ m_unscaled_color.clear();
+ m_inten_table = 0;
+ m_color4 = false;
+ }
+
+ inline color_quad_u8 get_scaled_color() const
+ {
+ int br, bg, bb;
+ if (m_color4)
+ {
+ br = m_unscaled_color.r | (m_unscaled_color.r << 4);
+ bg = m_unscaled_color.g | (m_unscaled_color.g << 4);
+ bb = m_unscaled_color.b | (m_unscaled_color.b << 4);
+ }
+ else
+ {
+ br = (m_unscaled_color.r >> 2) | (m_unscaled_color.r << 3);
+ bg = (m_unscaled_color.g >> 2) | (m_unscaled_color.g << 3);
+ bb = (m_unscaled_color.b >> 2) | (m_unscaled_color.b << 3);
+ }
+ return color_quad_u8(br, bg, bb);
+ }
+
+ inline void get_block_colors(color_quad_u8* pBlock_colors)
+ {
+ int br, bg, bb;
+ if (m_color4)
+ {
+ br = m_unscaled_color.r | (m_unscaled_color.r << 4);
+ bg = m_unscaled_color.g | (m_unscaled_color.g << 4);
+ bb = m_unscaled_color.b | (m_unscaled_color.b << 4);
+ }
+ else
+ {
+ br = (m_unscaled_color.r >> 2) | (m_unscaled_color.r << 3);
+ bg = (m_unscaled_color.g >> 2) | (m_unscaled_color.g << 3);
+ bb = (m_unscaled_color.b >> 2) | (m_unscaled_color.b << 3);
+ }
+ const int* pInten_table = g_etc1_inten_tables[m_inten_table];
+ pBlock_colors[0].set(br + pInten_table[0], bg + pInten_table[0], bb + pInten_table[0]);
+ pBlock_colors[1].set(br + pInten_table[1], bg + pInten_table[1], bb + pInten_table[1]);
+ pBlock_colors[2].set(br + pInten_table[2], bg + pInten_table[2], bb + pInten_table[2]);
+ pBlock_colors[3].set(br + pInten_table[3], bg + pInten_table[3], bb + pInten_table[3]);
+ }
+
+ color_quad_u8 m_unscaled_color;
+ uint m_inten_table;
+ bool m_color4;
+ };
+
+ class etc1_optimizer
+ {
+ etc1_optimizer(const etc1_optimizer&);
+ etc1_optimizer& operator= (const etc1_optimizer&);
+
+ public:
+ etc1_optimizer()
+ {
+ clear();
+ }
+
+ void clear()
+ {
+ m_pParams = NULL;
+ m_pResult = NULL;
+ m_pSorted_luma = NULL;
+ m_pSorted_luma_indices = NULL;
+ }
+
+ struct params : etc1_pack_params
+ {
+ params()
+ {
+ clear();
+ }
+
+ params(const etc1_pack_params& base_params) :
+ etc1_pack_params(base_params)
+ {
+ clear_optimizer_params();
+ }
+
+ void clear()
+ {
+ etc1_pack_params::clear();
+ clear_optimizer_params();
+ }
+
+ void clear_optimizer_params()
+ {
+ m_num_src_pixels = 0;
+ m_pSrc_pixels = 0;
+
+ m_use_color4 = false;
+ static const int s_default_scan_delta[] = { 0 };
+ m_pScan_deltas = s_default_scan_delta;
+ m_scan_delta_size = 1;
+
+ m_base_color5.clear();
+ m_constrain_against_base_color5 = false;
+ }
+
+ uint m_num_src_pixels;
+ const color_quad_u8* m_pSrc_pixels;
+
+ bool m_use_color4;
+ const int* m_pScan_deltas;
+ uint m_scan_delta_size;
+
+ color_quad_u8 m_base_color5;
+ bool m_constrain_against_base_color5;
+ };
+
+ struct results
+ {
+ uint64 m_error;
+ color_quad_u8 m_block_color_unscaled;
+ uint m_block_inten_table;
+ uint m_n;
+ uint8* m_pSelectors;
+ bool m_block_color4;
+
+ inline results& operator= (const results& rhs)
+ {
+ m_block_color_unscaled = rhs.m_block_color_unscaled;
+ m_block_color4 = rhs.m_block_color4;
+ m_block_inten_table = rhs.m_block_inten_table;
+ m_error = rhs.m_error;
+ RG_ETC1_ASSERT(m_n == rhs.m_n);
+ memcpy(m_pSelectors, rhs.m_pSelectors, rhs.m_n);
+ return *this;
+ }
+ };
+
+ void init(const params& params, results& result);
+ bool compute();
+
+ private:
+ struct potential_solution
+ {
+ potential_solution() : m_coords(), m_error(cUINT64_MAX), m_valid(false)
+ {
+ }
+
+ etc1_solution_coordinates m_coords;
+ uint8 m_selectors[8];
+ uint64 m_error;
+ bool m_valid;
+
+ void clear()
+ {
+ m_coords.clear();
+ m_error = cUINT64_MAX;
+ m_valid = false;
+ }
+ };
+
+ const params* m_pParams;
+ results* m_pResult;
+
+ int m_limit;
+
+ vec3F m_avg_color;
+ int m_br, m_bg, m_bb;
+ uint16 m_luma[8];
+ uint32 m_sorted_luma[2][8];
+ const uint32* m_pSorted_luma_indices;
+ uint32* m_pSorted_luma;
+
+ uint8 m_selectors[8];
+ uint8 m_best_selectors[8];
+
+ potential_solution m_best_solution;
+ potential_solution m_trial_solution;
+ uint8 m_temp_selectors[8];
+
+ bool evaluate_solution(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution);
+ bool evaluate_solution_fast(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution);
+ };
+
+ bool etc1_optimizer::compute()
+ {
+ const uint n = m_pParams->m_num_src_pixels;
+ const int scan_delta_size = m_pParams->m_scan_delta_size;
+
+ // Scan through a subset of the 3D lattice centered around the avg block color trying each 3D (555 or 444) lattice point as a potential block color.
+ // Each time a better solution is found try to refine the current solution's block color based of the current selectors and intensity table index.
+ for (int zdi = 0; zdi < scan_delta_size; zdi++)
+ {
+ const int zd = m_pParams->m_pScan_deltas[zdi];
+ const int mbb = m_bb + zd;
+ if (mbb < 0) continue; else if (mbb > m_limit) break;
+
+ for (int ydi = 0; ydi < scan_delta_size; ydi++)
+ {
+ const int yd = m_pParams->m_pScan_deltas[ydi];
+ const int mbg = m_bg + yd;
+ if (mbg < 0) continue; else if (mbg > m_limit) break;
+
+ for (int xdi = 0; xdi < scan_delta_size; xdi++)
+ {
+ const int xd = m_pParams->m_pScan_deltas[xdi];
+ const int mbr = m_br + xd;
+ if (mbr < 0) continue; else if (mbr > m_limit) break;
+
+ etc1_solution_coordinates coords(mbr, mbg, mbb, 0, m_pParams->m_use_color4);
+ if (m_pParams->m_quality == cHighQuality)
+ {
+ if (!evaluate_solution(coords, m_trial_solution, &m_best_solution))
+ continue;
+ }
+ else
+ {
+ if (!evaluate_solution_fast(coords, m_trial_solution, &m_best_solution))
+ continue;
+ }
+
+ // Now we have the input block, the avg. color of the input pixels, a set of trial selector indices, and the block color+intensity index.
+ // Now, for each component, attempt to refine the current solution by solving a simple linear equation. For example, for 4 colors:
+ // The goal is:
+ // pixel0 - (block_color+inten_table[selector0]) + pixel1 - (block_color+inten_table[selector1]) + pixel2 - (block_color+inten_table[selector2]) + pixel3 - (block_color+inten_table[selector3]) = 0
+ // Rearranging this:
+ // (pixel0 + pixel1 + pixel2 + pixel3) - (block_color+inten_table[selector0]) - (block_color+inten_table[selector1]) - (block_color+inten_table[selector2]) - (block_color+inten_table[selector3]) = 0
+ // (pixel0 + pixel1 + pixel2 + pixel3) - block_color - inten_table[selector0] - block_color-inten_table[selector1] - block_color-inten_table[selector2] - block_color-inten_table[selector3] = 0
+ // (pixel0 + pixel1 + pixel2 + pixel3) - 4*block_color - inten_table[selector0] - inten_table[selector1] - inten_table[selector2] - inten_table[selector3] = 0
+ // (pixel0 + pixel1 + pixel2 + pixel3) - 4*block_color - (inten_table[selector0] + inten_table[selector1] + inten_table[selector2] + inten_table[selector3]) = 0
+ // (pixel0 + pixel1 + pixel2 + pixel3)/4 - block_color - (inten_table[selector0] + inten_table[selector1] + inten_table[selector2] + inten_table[selector3])/4 = 0
+ // block_color = (pixel0 + pixel1 + pixel2 + pixel3)/4 - (inten_table[selector0] + inten_table[selector1] + inten_table[selector2] + inten_table[selector3])/4
+ // So what this means:
+ // optimal_block_color = avg_input - avg_inten_delta
+ // So the optimal block color can be computed by taking the average block color and subtracting the current average of the intensity delta.
+ // Unfortunately, optimal_block_color must then be quantized to 555 or 444 so it's not always possible to improve matters using this formula.
+ // Also, the above formula is for unclamped intensity deltas. The actual implementation takes into account clamping.
+
+ const uint max_refinement_trials = (m_pParams->m_quality == cLowQuality) ? 2 : (((xd | yd | zd) == 0) ? 4 : 2);
+ for (uint refinement_trial = 0; refinement_trial < max_refinement_trials; refinement_trial++)
+ {
+ const uint8* pSelectors = m_best_solution.m_selectors;
+ const int* pInten_table = g_etc1_inten_tables[m_best_solution.m_coords.m_inten_table];
+
+ int delta_sum_r = 0, delta_sum_g = 0, delta_sum_b = 0;
+ const color_quad_u8 base_color(m_best_solution.m_coords.get_scaled_color());
+ for (uint r = 0; r < n; r++)
+ {
+ const uint s = *pSelectors++;
+ const int yd = pInten_table[s];
+ // Compute actual delta being applied to each pixel, taking into account clamping.
+ delta_sum_r += rg_etc1::clamp<int>(base_color.r + yd, 0, 255) - base_color.r;
+ delta_sum_g += rg_etc1::clamp<int>(base_color.g + yd, 0, 255) - base_color.g;
+ delta_sum_b += rg_etc1::clamp<int>(base_color.b + yd, 0, 255) - base_color.b;
+ }
+ if ((!delta_sum_r) && (!delta_sum_g) && (!delta_sum_b))
+ break;
+ const float avg_delta_r_f = static_cast<float>(delta_sum_r) / n;
+ const float avg_delta_g_f = static_cast<float>(delta_sum_g) / n;
+ const float avg_delta_b_f = static_cast<float>(delta_sum_b) / n;
+ const int br1 = rg_etc1::clamp<int>(static_cast<uint>((m_avg_color[0] - avg_delta_r_f) * m_limit / 255.0f + .5f), 0, m_limit);
+ const int bg1 = rg_etc1::clamp<int>(static_cast<uint>((m_avg_color[1] - avg_delta_g_f) * m_limit / 255.0f + .5f), 0, m_limit);
+ const int bb1 = rg_etc1::clamp<int>(static_cast<uint>((m_avg_color[2] - avg_delta_b_f) * m_limit / 255.0f + .5f), 0, m_limit);
+
+ bool skip = false;
+
+ if ((mbr == br1) && (mbg == bg1) && (mbb == bb1))
+ skip = true;
+ else if ((br1 == m_best_solution.m_coords.m_unscaled_color.r) && (bg1 == m_best_solution.m_coords.m_unscaled_color.g) && (bb1 == m_best_solution.m_coords.m_unscaled_color.b))
+ skip = true;
+ else if ((m_br == br1) && (m_bg == bg1) && (m_bb == bb1))
+ skip = true;
+
+ if (skip)
+ break;
+
+ etc1_solution_coordinates coords1(br1, bg1, bb1, 0, m_pParams->m_use_color4);
+ if (m_pParams->m_quality == cHighQuality)
+ {
+ if (!evaluate_solution(coords1, m_trial_solution, &m_best_solution))
+ break;
+ }
+ else
+ {
+ if (!evaluate_solution_fast(coords1, m_trial_solution, &m_best_solution))
+ break;
+ }
+
+ } // refinement_trial
+
+ } // xdi
+ } // ydi
+ } // zdi
+
+ if (!m_best_solution.m_valid)
+ {
+ m_pResult->m_error = cUINT32_MAX;
+ return false;
+ }
+
+ const uint8* pSelectors = m_best_solution.m_selectors;
+
+#ifdef RG_ETC1_BUILD_DEBUG
+ {
+ color_quad_u8 block_colors[4];
+ m_best_solution.m_coords.get_block_colors(block_colors);
+
+ const color_quad_u8* pSrc_pixels = m_pParams->m_pSrc_pixels;
+ uint64 actual_error = 0;
+ for (uint i = 0; i < n; i++)
+ actual_error += pSrc_pixels[i].squared_distance_rgb(block_colors[pSelectors[i]]);
+
+ RG_ETC1_ASSERT(actual_error == m_best_solution.m_error);
+ }
+#endif
+
+ m_pResult->m_error = m_best_solution.m_error;
+
+ m_pResult->m_block_color_unscaled = m_best_solution.m_coords.m_unscaled_color;
+ m_pResult->m_block_color4 = m_best_solution.m_coords.m_color4;
+
+ m_pResult->m_block_inten_table = m_best_solution.m_coords.m_inten_table;
+ memcpy(m_pResult->m_pSelectors, pSelectors, n);
+ m_pResult->m_n = n;
+
+ return true;
+ }
+
+ void etc1_optimizer::init(const params& p, results& r)
+ {
+ // This version is hardcoded for 8 pixel subblocks.
+ RG_ETC1_ASSERT(p.m_num_src_pixels == 8);
+
+ m_pParams = &p;
+ m_pResult = &r;
+
+ const uint n = 8;
+
+ m_limit = m_pParams->m_use_color4 ? 15 : 31;
+
+ vec3F avg_color(0.0f);
+
+ for (uint i = 0; i < n; i++)
+ {
+ const color_quad_u8& c = m_pParams->m_pSrc_pixels[i];
+ const vec3F fc(c.r, c.g, c.b);
+
+ avg_color += fc;
+
+ m_luma[i] = static_cast<uint16>(c.r + c.g + c.b);
+ m_sorted_luma[0][i] = i;
+ }
+ avg_color *= (1.0f / static_cast<float>(n));
+ m_avg_color = avg_color;
+
+ m_br = rg_etc1::clamp<int>(static_cast<uint>(m_avg_color[0] * m_limit / 255.0f + .5f), 0, m_limit);
+ m_bg = rg_etc1::clamp<int>(static_cast<uint>(m_avg_color[1] * m_limit / 255.0f + .5f), 0, m_limit);
+ m_bb = rg_etc1::clamp<int>(static_cast<uint>(m_avg_color[2] * m_limit / 255.0f + .5f), 0, m_limit);
+
+ if (m_pParams->m_quality <= cMediumQuality)
+ {
+ m_pSorted_luma_indices = indirect_radix_sort(n, m_sorted_luma[0], m_sorted_luma[1], m_luma, 0, sizeof(m_luma[0]), false);
+ m_pSorted_luma = m_sorted_luma[0];
+ if (m_pSorted_luma_indices == m_sorted_luma[0])
+ m_pSorted_luma = m_sorted_luma[1];
+
+ for (uint i = 0; i < n; i++)
+ m_pSorted_luma[i] = m_luma[m_pSorted_luma_indices[i]];
+ }
+
+ m_best_solution.m_coords.clear();
+ m_best_solution.m_valid = false;
+ m_best_solution.m_error = cUINT64_MAX;
+ }
+
+ bool etc1_optimizer::evaluate_solution(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution)
+ {
+ trial_solution.m_valid = false;
+
+ if (m_pParams->m_constrain_against_base_color5)
+ {
+ const int dr = coords.m_unscaled_color.r - m_pParams->m_base_color5.r;
+ const int dg = coords.m_unscaled_color.g - m_pParams->m_base_color5.g;
+ const int db = coords.m_unscaled_color.b - m_pParams->m_base_color5.b;
+
+ if ((rg_etc1::minimum(dr, dg, db) < cETC1ColorDeltaMin) || (rg_etc1::maximum(dr, dg, db) > cETC1ColorDeltaMax))
+ return false;
+ }
+
+ const color_quad_u8 base_color(coords.get_scaled_color());
+
+ const uint n = 8;
+
+ trial_solution.m_error = cUINT64_MAX;
+
+ for (uint inten_table = 0; inten_table < cETC1IntenModifierValues; inten_table++)
+ {
+ const int* pInten_table = g_etc1_inten_tables[inten_table];
+
+ color_quad_u8 block_colors[4];
+ for (uint s = 0; s < 4; s++)
+ {
+ const int yd = pInten_table[s];
+ block_colors[s].set(base_color.r + yd, base_color.g + yd, base_color.b + yd, 0);
+ }
+
+ uint64 total_error = 0;
+
+ const color_quad_u8* pSrc_pixels = m_pParams->m_pSrc_pixels;
+ for (uint c = 0; c < n; c++)
+ {
+ const color_quad_u8& src_pixel = *pSrc_pixels++;
+
+ uint best_selector_index = 0;
+ uint best_error = rg_etc1::square(src_pixel.r - block_colors[0].r) + rg_etc1::square(src_pixel.g - block_colors[0].g) + rg_etc1::square(src_pixel.b - block_colors[0].b);
+
+ uint trial_error = rg_etc1::square(src_pixel.r - block_colors[1].r) + rg_etc1::square(src_pixel.g - block_colors[1].g) + rg_etc1::square(src_pixel.b - block_colors[1].b);
+ if (trial_error < best_error)
+ {
+ best_error = trial_error;
+ best_selector_index = 1;
+ }
+
+ trial_error = rg_etc1::square(src_pixel.r - block_colors[2].r) + rg_etc1::square(src_pixel.g - block_colors[2].g) + rg_etc1::square(src_pixel.b - block_colors[2].b);
+ if (trial_error < best_error)
+ {
+ best_error = trial_error;
+ best_selector_index = 2;
+ }
+
+ trial_error = rg_etc1::square(src_pixel.r - block_colors[3].r) + rg_etc1::square(src_pixel.g - block_colors[3].g) + rg_etc1::square(src_pixel.b - block_colors[3].b);
+ if (trial_error < best_error)
+ {
+ best_error = trial_error;
+ best_selector_index = 3;
+ }
+
+ m_temp_selectors[c] = static_cast<uint8>(best_selector_index);
+
+ total_error += best_error;
+ if (total_error >= trial_solution.m_error)
+ break;
+ }
+
+ if (total_error < trial_solution.m_error)
+ {
+ trial_solution.m_error = total_error;
+ trial_solution.m_coords.m_inten_table = inten_table;
+ memcpy(trial_solution.m_selectors, m_temp_selectors, 8);
+ trial_solution.m_valid = true;
+ }
+ }
+ trial_solution.m_coords.m_unscaled_color = coords.m_unscaled_color;
+ trial_solution.m_coords.m_color4 = m_pParams->m_use_color4;
+
+ bool success = false;
+ if (pBest_solution)
+ {
+ if (trial_solution.m_error < pBest_solution->m_error)
+ {
+ *pBest_solution = trial_solution;
+ success = true;
+ }
+ }
+
+ return success;
+ }
+
+ bool etc1_optimizer::evaluate_solution_fast(const etc1_solution_coordinates& coords, potential_solution& trial_solution, potential_solution* pBest_solution)
+ {
+ if (m_pParams->m_constrain_against_base_color5)
+ {
+ const int dr = coords.m_unscaled_color.r - m_pParams->m_base_color5.r;
+ const int dg = coords.m_unscaled_color.g - m_pParams->m_base_color5.g;
+ const int db = coords.m_unscaled_color.b - m_pParams->m_base_color5.b;
+
+ if ((rg_etc1::minimum(dr, dg, db) < cETC1ColorDeltaMin) || (rg_etc1::maximum(dr, dg, db) > cETC1ColorDeltaMax))
+ {
+ trial_solution.m_valid = false;
+ return false;
+ }
+ }
+
+ const color_quad_u8 base_color(coords.get_scaled_color());
+
+ const uint n = 8;
+
+ trial_solution.m_error = cUINT64_MAX;
+
+ for (int inten_table = cETC1IntenModifierValues - 1; inten_table >= 0; --inten_table)
+ {
+ const int* pInten_table = g_etc1_inten_tables[inten_table];
+
+ uint block_inten[4];
+ color_quad_u8 block_colors[4];
+ for (uint s = 0; s < 4; s++)
+ {
+ const int yd = pInten_table[s];
+ color_quad_u8 block_color(base_color.r + yd, base_color.g + yd, base_color.b + yd, 0);
+ block_colors[s] = block_color;
+ block_inten[s] = block_color.r + block_color.g + block_color.b;
+ }
+
+ // evaluate_solution_fast() enforces/assumesd a total ordering of the input colors along the intensity (1,1,1) axis to more quickly classify the inputs to selectors.
+ // The inputs colors have been presorted along the projection onto this axis, and ETC1 block colors are always ordered along the intensity axis, so this classification is fast.
+ // 0 1 2 3
+ // 01 12 23
+ const uint block_inten_midpoints[3] = { block_inten[0] + block_inten[1], block_inten[1] + block_inten[2], block_inten[2] + block_inten[3] };
+
+ uint64 total_error = 0;
+ const color_quad_u8* pSrc_pixels = m_pParams->m_pSrc_pixels;
+ if ((m_pSorted_luma[n - 1] * 2) < block_inten_midpoints[0])
+ {
+ if (block_inten[0] > m_pSorted_luma[n - 1])
+ {
+ const uint min_error = intabs(block_inten[0] - m_pSorted_luma[n - 1]);
+ if (min_error >= trial_solution.m_error)
+ continue;
+ }
+
+ memset(&m_temp_selectors[0], 0, n);
+
+ for (uint c = 0; c < n; c++)
+ total_error += block_colors[0].squared_distance_rgb(pSrc_pixels[c]);
+ }
+ else if ((m_pSorted_luma[0] * 2) >= block_inten_midpoints[2])
+ {
+ if (m_pSorted_luma[0] > block_inten[3])
+ {
+ const uint min_error = intabs(m_pSorted_luma[0] - block_inten[3]);
+ if (min_error >= trial_solution.m_error)
+ continue;
+ }
+
+ memset(&m_temp_selectors[0], 3, n);
+
+ for (uint c = 0; c < n; c++)
+ total_error += block_colors[3].squared_distance_rgb(pSrc_pixels[c]);
+ }
+ else
+ {
+ uint cur_selector = 0, c;
+ for (c = 0; c < n; c++)
+ {
+ const uint y = m_pSorted_luma[c];
+ while ((y * 2) >= block_inten_midpoints[cur_selector])
+ if (++cur_selector > 2)
+ goto done;
+ const uint sorted_pixel_index = m_pSorted_luma_indices[c];
+ m_temp_selectors[sorted_pixel_index] = static_cast<uint8>(cur_selector);
+ total_error += block_colors[cur_selector].squared_distance_rgb(pSrc_pixels[sorted_pixel_index]);
+ }
+done:
+ while (c < n)
+ {
+ const uint sorted_pixel_index = m_pSorted_luma_indices[c];
+ m_temp_selectors[sorted_pixel_index] = 3;
+ total_error += block_colors[3].squared_distance_rgb(pSrc_pixels[sorted_pixel_index]);
+ ++c;
+ }
+ }
+
+ if (total_error < trial_solution.m_error)
+ {
+ trial_solution.m_error = total_error;
+ trial_solution.m_coords.m_inten_table = inten_table;
+ memcpy(trial_solution.m_selectors, m_temp_selectors, n);
+ trial_solution.m_valid = true;
+ if (!total_error)
+ break;
+ }
+ }
+ trial_solution.m_coords.m_unscaled_color = coords.m_unscaled_color;
+ trial_solution.m_coords.m_color4 = m_pParams->m_use_color4;
+
+ bool success = false;
+ if (pBest_solution)
+ {
+ if (trial_solution.m_error < pBest_solution->m_error)
+ {
+ *pBest_solution = trial_solution;
+ success = true;
+ }
+ }
+
+ return success;
+ }
+
+ static uint etc1_decode_value(uint diff, uint inten, uint selector, uint packed_c)
+ {
+ const uint limit = diff ? 32 : 16; limit;
+ RG_ETC1_ASSERT((diff < 2) && (inten < 8) && (selector < 4) && (packed_c < limit));
+ int c;
+ if (diff)
+ c = (packed_c >> 2) | (packed_c << 3);
+ else
+ c = packed_c | (packed_c << 4);
+ c += g_etc1_inten_tables[inten][selector];
+ c = rg_etc1::clamp<int>(c, 0, 255);
+ return c;
+ }
+
+ static inline int mul_8bit(int a, int b) { int t = a*b + 128; return (t + (t >> 8)) >> 8; }
+
+ void pack_etc1_block_init()
+ {
+ for (uint diff = 0; diff < 2; diff++)
+ {
+ const uint limit = diff ? 32 : 16;
+
+ for (uint inten = 0; inten < 8; inten++)
+ {
+ for (uint selector = 0; selector < 4; selector++)
+ {
+ const uint inverse_table_index = diff + (inten << 1) + (selector << 4);
+ for (uint color = 0; color < 256; color++)
+ {
+ uint best_error = cUINT32_MAX, best_packed_c = 0;
+ for (uint packed_c = 0; packed_c < limit; packed_c++)
+ {
+ int v = etc1_decode_value(diff, inten, selector, packed_c);
+ uint err = labs(v - static_cast<int>(color));
+ //printf("err: %d - %u = %u\n",v,color,err);
+ if (err < best_error)
+ {
+ best_error = err;
+ best_packed_c = packed_c;
+ if (!best_error)
+ break;
+ }
+ }
+ RG_ETC1_ASSERT(best_error <= 255);
+ g_etc1_inverse_lookup[inverse_table_index][color] = static_cast<uint16>(best_packed_c | (best_error << 8));
+ }
+ }
+ }
+ }
+
+ uint expand5[32];
+ for(int i = 0; i < 32; i++)
+ expand5[i] = (i << 3) | (i >> 2);
+
+ for(int i = 0; i < 256 + 16; i++)
+ {
+ int v = clamp<int>(i - 8, 0, 255);
+ g_quant5_tab[i] = static_cast<uint8>(expand5[mul_8bit(v,31)]);
+ }
+ }
+
+ // Packs solid color blocks efficiently using a set of small precomputed tables.
+ // For random 888 inputs, MSE results are better than Erricson's ETC1 packer in "slow" mode ~9.5% of the time, is slightly worse only ~.01% of the time, and is equal the rest of the time.
+ static uint64 pack_etc1_block_solid_color(etc1_block& block, const uint8* pColor, etc1_pack_params& pack_params)
+ {
+ pack_params;
+ RG_ETC1_ASSERT(g_etc1_inverse_lookup[0][255]);
+
+ static uint s_next_comp[4] = { 1, 2, 0, 1 };
+
+ uint best_error = cUINT32_MAX, best_i = 0;
+ int best_x = 0, best_packed_c1 = 0, best_packed_c2 = 0;
+
+ // For each possible 8-bit value, there is a precomputed list of diff/inten/selector configurations that allow that 8-bit value to be encoded with no error.
+ for (uint i = 0; i < 3; i++)
+ {
+ const uint c1 = pColor[s_next_comp[i]], c2 = pColor[s_next_comp[i + 1]];
+
+ const int delta_range = 1;
+ for (int delta = -delta_range; delta <= delta_range; delta++)
+ {
+ const int c_plus_delta = rg_etc1::clamp<int>(pColor[i] + delta, 0, 255);
+
+ const uint16* pTable;
+ if (!c_plus_delta)
+ pTable = g_color8_to_etc_block_config_0_255[0];
+ else if (c_plus_delta == 255)
+ pTable = g_color8_to_etc_block_config_0_255[1];
+ else
+ pTable = g_color8_to_etc_block_config_1_to_254[c_plus_delta - 1];
+
+ do
+ {
+ const uint x = *pTable++;
+
+#ifdef RG_ETC1_BUILD_DEBUG
+ const uint diff = x & 1;
+ const uint inten = (x >> 1) & 7;
+ const uint selector = (x >> 4) & 3;
+ const uint p0 = (x >> 8) & 255;
+ RG_ETC1_ASSERT(etc1_decode_value(diff, inten, selector, p0) == (uint)c_plus_delta);
+#endif
+
+ const uint16* pInverse_table = g_etc1_inverse_lookup[x & 0xFF];
+ uint16 p1 = pInverse_table[c1];
+ uint16 p2 = pInverse_table[c2];
+ const uint trial_error = rg_etc1::square(c_plus_delta - pColor[i]) + rg_etc1::square(p1 >> 8) + rg_etc1::square(p2 >> 8);
+ if (trial_error < best_error)
+ {
+ best_error = trial_error;
+ best_x = x;
+ best_packed_c1 = p1 & 0xFF;
+ best_packed_c2 = p2 & 0xFF;
+ best_i = i;
+ if (!best_error)
+ goto found_perfect_match;
+ }
+ } while (*pTable != 0xFFFF);
+ }
+ }
+found_perfect_match:
+
+ const uint diff = best_x & 1;
+ const uint inten = (best_x >> 1) & 7;
+
+ block.m_bytes[3] = static_cast<uint8>(((inten | (inten << 3)) << 2) | (diff << 1));
+
+ const uint etc1_selector = g_selector_index_to_etc1[(best_x >> 4) & 3];
+ *reinterpret_cast<uint16*>(&block.m_bytes[4]) = (etc1_selector & 2) ? 0xFFFF : 0;
+ *reinterpret_cast<uint16*>(&block.m_bytes[6]) = (etc1_selector & 1) ? 0xFFFF : 0;
+
+ const uint best_packed_c0 = (best_x >> 8) & 255;
+ if (diff)
+ {
+ block.m_bytes[best_i] = static_cast<uint8>(best_packed_c0 << 3);
+ block.m_bytes[s_next_comp[best_i]] = static_cast<uint8>(best_packed_c1 << 3);
+ block.m_bytes[s_next_comp[best_i+1]] = static_cast<uint8>(best_packed_c2 << 3);
+ }
+ else
+ {
+ block.m_bytes[best_i] = static_cast<uint8>(best_packed_c0 | (best_packed_c0 << 4));
+ block.m_bytes[s_next_comp[best_i]] = static_cast<uint8>(best_packed_c1 | (best_packed_c1 << 4));
+ block.m_bytes[s_next_comp[best_i+1]] = static_cast<uint8>(best_packed_c2 | (best_packed_c2 << 4));
+ }
+
+ return best_error;
+ }
+
+ static uint pack_etc1_block_solid_color_constrained(
+ etc1_optimizer::results& results,
+ uint num_colors, const uint8* pColor,
+ etc1_pack_params& pack_params,
+ bool use_diff,
+ const color_quad_u8* pBase_color5_unscaled)
+ {
+ RG_ETC1_ASSERT(g_etc1_inverse_lookup[0][255]);
+
+ pack_params;
+ static uint s_next_comp[4] = { 1, 2, 0, 1 };
+
+ uint best_error = cUINT32_MAX, best_i = 0;
+ int best_x = 0, best_packed_c1 = 0, best_packed_c2 = 0;
+
+ // For each possible 8-bit value, there is a precomputed list of diff/inten/selector configurations that allow that 8-bit value to be encoded with no error.
+ for (uint i = 0; i < 3; i++)
+ {
+ const uint c1 = pColor[s_next_comp[i]], c2 = pColor[s_next_comp[i + 1]];
+
+ const int delta_range = 1;
+ for (int delta = -delta_range; delta <= delta_range; delta++)
+ {
+ const int c_plus_delta = rg_etc1::clamp<int>(pColor[i] + delta, 0, 255);
+
+ const uint16* pTable;
+ if (!c_plus_delta)
+ pTable = g_color8_to_etc_block_config_0_255[0];
+ else if (c_plus_delta == 255)
+ pTable = g_color8_to_etc_block_config_0_255[1];
+ else
+ pTable = g_color8_to_etc_block_config_1_to_254[c_plus_delta - 1];
+
+ do
+ {
+ const uint x = *pTable++;
+ const uint diff = x & 1;
+ if (static_cast<uint>(use_diff) != diff)
+ {
+ if (*pTable == 0xFFFF)
+ break;
+ continue;
+ }
+
+ if ((diff) && (pBase_color5_unscaled))
+ {
+ const int p0 = (x >> 8) & 255;
+ int delta = p0 - static_cast<int>(pBase_color5_unscaled->c[i]);
+ if ((delta < cETC1ColorDeltaMin) || (delta > cETC1ColorDeltaMax))
+ {
+ if (*pTable == 0xFFFF)
+ break;
+ continue;
+ }
+ }
+
+#ifdef RG_ETC1_BUILD_DEBUG
+ {
+ const uint inten = (x >> 1) & 7;
+ const uint selector = (x >> 4) & 3;
+ const uint p0 = (x >> 8) & 255;
+ RG_ETC1_ASSERT(etc1_decode_value(diff, inten, selector, p0) == (uint)c_plus_delta);
+ }
+#endif
+
+ const uint16* pInverse_table = g_etc1_inverse_lookup[x & 0xFF];
+ uint16 p1 = pInverse_table[c1];
+ uint16 p2 = pInverse_table[c2];
+
+ if ((diff) && (pBase_color5_unscaled))
+ {
+ int delta1 = (p1 & 0xFF) - static_cast<int>(pBase_color5_unscaled->c[s_next_comp[i]]);
+ int delta2 = (p2 & 0xFF) - static_cast<int>(pBase_color5_unscaled->c[s_next_comp[i + 1]]);
+ if ((delta1 < cETC1ColorDeltaMin) || (delta1 > cETC1ColorDeltaMax) || (delta2 < cETC1ColorDeltaMin) || (delta2 > cETC1ColorDeltaMax))
+ {
+ if (*pTable == 0xFFFF)
+ break;
+ continue;
+ }
+ }
+
+ const uint trial_error = rg_etc1::square(c_plus_delta - pColor[i]) + rg_etc1::square(p1 >> 8) + rg_etc1::square(p2 >> 8);
+ if (trial_error < best_error)
+ {
+ best_error = trial_error;
+ best_x = x;
+ best_packed_c1 = p1 & 0xFF;
+ best_packed_c2 = p2 & 0xFF;
+ best_i = i;
+ if (!best_error)
+ goto found_perfect_match;
+ }
+ } while (*pTable != 0xFFFF);
+ }
+ }
+found_perfect_match:
+
+ if (best_error == cUINT32_MAX)
+ return best_error;
+
+ best_error *= num_colors;
+
+ results.m_n = num_colors;
+ results.m_block_color4 = !(best_x & 1);
+ results.m_block_inten_table = (best_x >> 1) & 7;
+ memset(results.m_pSelectors, (best_x >> 4) & 3, num_colors);
+
+ const uint best_packed_c0 = (best_x >> 8) & 255;
+ results.m_block_color_unscaled[best_i] = static_cast<uint8>(best_packed_c0);
+ results.m_block_color_unscaled[s_next_comp[best_i]] = static_cast<uint8>(best_packed_c1);
+ results.m_block_color_unscaled[s_next_comp[best_i + 1]] = static_cast<uint8>(best_packed_c2);
+ results.m_error = best_error;
+
+ return best_error;
+ }
+
+ // Function originally from RYG's public domain real-time DXT1 compressor, modified for 555.
+ static void dither_block_555(color_quad_u8* dest, const color_quad_u8* block)
+ {
+ int err[8],*ep1 = err,*ep2 = err+4;
+ uint8 *quant = g_quant5_tab+8;
+
+ memset(dest, 0xFF, sizeof(color_quad_u8)*16);
+
+ // process channels seperately
+ for(int ch=0;ch<3;ch++)
+ {
+ uint8* bp = (uint8*)block;
+ uint8* dp = (uint8*)dest;
+
+ bp += ch; dp += ch;
+
+ memset(err,0, sizeof(err));
+ for(int y = 0; y < 4; y++)
+ {
+ // pixel 0
+ dp[ 0] = quant[bp[ 0] + ((3*ep2[1] + 5*ep2[0]) >> 4)];
+ ep1[0] = bp[ 0] - dp[ 0];
+
+ // pixel 1
+ dp[ 4] = quant[bp[ 4] + ((7*ep1[0] + 3*ep2[2] + 5*ep2[1] + ep2[0]) >> 4)];
+ ep1[1] = bp[ 4] - dp[ 4];
+
+ // pixel 2
+ dp[ 8] = quant[bp[ 8] + ((7*ep1[1] + 3*ep2[3] + 5*ep2[2] + ep2[1]) >> 4)];
+ ep1[2] = bp[ 8] - dp[ 8];
+
+ // pixel 3
+ dp[12] = quant[bp[12] + ((7*ep1[2] + 5*ep2[3] + ep2[2]) >> 4)];
+ ep1[3] = bp[12] - dp[12];
+
+ // advance to next line
+ int* tmp = ep1; ep1 = ep2; ep2 = tmp;
+ bp += 16;
+ dp += 16;
+ }
+ }
+ }
+
+ unsigned int pack_etc1_block(void* pETC1_block, const unsigned int* pSrc_pixels_rgba, etc1_pack_params& pack_params)
+ {
+ const color_quad_u8* pSrc_pixels = reinterpret_cast<const color_quad_u8*>(pSrc_pixels_rgba);
+ etc1_block& dst_block = *static_cast<etc1_block*>(pETC1_block);
+
+#ifdef RG_ETC1_BUILD_DEBUG
+ // Ensure all alpha values are 0xFF.
+ for (uint i = 0; i < 16; i++)
+ {
+ RG_ETC1_ASSERT(pSrc_pixels[i].a == 255);
+ }
+#endif
+
+ color_quad_u8 src_pixel0(pSrc_pixels[0]);
+
+ // Check for solid block.
+ const uint32 first_pixel_u32 = pSrc_pixels->m_u32;
+ int r;
+ for (r = 15; r >= 1; --r)
+ if (pSrc_pixels[r].m_u32 != first_pixel_u32)
+ break;
+ if (!r)
+ return static_cast<unsigned int>(16 * pack_etc1_block_solid_color(dst_block, &pSrc_pixels[0].r, pack_params));
+
+ color_quad_u8 dithered_pixels[16];
+ if (pack_params.m_dithering)
+ {
+ dither_block_555(dithered_pixels, pSrc_pixels);
+ pSrc_pixels = dithered_pixels;
+ }
+
+ etc1_optimizer optimizer;
+
+ uint64 best_error = cUINT64_MAX;
+ uint best_flip = false, best_use_color4 = false;
+
+ uint8 best_selectors[2][8];
+ etc1_optimizer::results best_results[2];
+ for (uint i = 0; i < 2; i++)
+ {
+ best_results[i].m_n = 8;
+ best_results[i].m_pSelectors = best_selectors[i];
+ }
+
+ uint8 selectors[3][8];
+ etc1_optimizer::results results[3];
+
+ for (uint i = 0; i < 3; i++)
+ {
+ results[i].m_n = 8;
+ results[i].m_pSelectors = selectors[i];
+ }
+
+ color_quad_u8 subblock_pixels[8];
+
+ etc1_optimizer::params params(pack_params);
+ params.m_num_src_pixels = 8;
+ params.m_pSrc_pixels = subblock_pixels;
+
+ for (uint flip = 0; flip < 2; flip++)
+ {
+ for (uint use_color4 = 0; use_color4 < 2; use_color4++)
+ {
+ uint64 trial_error = 0;
+
+ uint subblock;
+ for (subblock = 0; subblock < 2; subblock++)
+ {
+ if (flip)
+ memcpy(subblock_pixels, pSrc_pixels + subblock * 8, sizeof(color_quad_u8) * 8);
+ else
+ {
+ const color_quad_u8* pSrc_col = pSrc_pixels + subblock * 2;
+ subblock_pixels[0] = pSrc_col[0]; subblock_pixels[1] = pSrc_col[4]; subblock_pixels[2] = pSrc_col[8]; subblock_pixels[3] = pSrc_col[12];
+ subblock_pixels[4] = pSrc_col[1]; subblock_pixels[5] = pSrc_col[5]; subblock_pixels[6] = pSrc_col[9]; subblock_pixels[7] = pSrc_col[13];
+ }
+
+ results[2].m_error = cUINT64_MAX;
+ if ((params.m_quality >= cMediumQuality) && ((subblock) || (use_color4)))
+ {
+ const uint32 subblock_pixel0_u32 = subblock_pixels[0].m_u32;
+ for (r = 7; r >= 1; --r)
+ if (subblock_pixels[r].m_u32 != subblock_pixel0_u32)
+ break;
+ if (!r)
+ {
+ pack_etc1_block_solid_color_constrained(results[2], 8, &subblock_pixels[0].r, pack_params, !use_color4, (subblock && !use_color4) ? &results[0].m_block_color_unscaled : NULL);
+ }
+ }
+
+ params.m_use_color4 = (use_color4 != 0);
+ params.m_constrain_against_base_color5 = false;
+
+ if ((!use_color4) && (subblock))
+ {
+ params.m_constrain_against_base_color5 = true;
+ params.m_base_color5 = results[0].m_block_color_unscaled;
+ }
+
+ if (params.m_quality == cHighQuality)
+ {
+ static const int s_scan_delta_0_to_4[] = { -4, -3, -2, -1, 0, 1, 2, 3, 4 };
+ params.m_scan_delta_size = RG_ETC1_ARRAY_SIZE(s_scan_delta_0_to_4);
+ params.m_pScan_deltas = s_scan_delta_0_to_4;
+ }
+ else if (params.m_quality == cMediumQuality)
+ {
+ static const int s_scan_delta_0_to_1[] = { -1, 0, 1 };
+ params.m_scan_delta_size = RG_ETC1_ARRAY_SIZE(s_scan_delta_0_to_1);
+ params.m_pScan_deltas = s_scan_delta_0_to_1;
+ }
+ else
+ {
+ static const int s_scan_delta_0[] = { 0 };
+ params.m_scan_delta_size = RG_ETC1_ARRAY_SIZE(s_scan_delta_0);
+ params.m_pScan_deltas = s_scan_delta_0;
+ }
+
+ optimizer.init(params, results[subblock]);
+ if (!optimizer.compute())
+ break;
+
+ if (params.m_quality >= cMediumQuality)
+ {
+ // TODO: Fix fairly arbitrary/unrefined thresholds that control how far away to scan for potentially better solutions.
+ const uint refinement_error_thresh0 = 3000;
+ const uint refinement_error_thresh1 = 6000;
+ if (results[subblock].m_error > refinement_error_thresh0)
+ {
+ if (params.m_quality == cMediumQuality)
+ {
+ static const int s_scan_delta_2_to_3[] = { -3, -2, 2, 3 };
+ params.m_scan_delta_size = RG_ETC1_ARRAY_SIZE(s_scan_delta_2_to_3);
+ params.m_pScan_deltas = s_scan_delta_2_to_3;
+ }
+ else
+ {
+ static const int s_scan_delta_5_to_5[] = { -5, 5 };
+ static const int s_scan_delta_5_to_8[] = { -8, -7, -6, -5, 5, 6, 7, 8 };
+ if (results[subblock].m_error > refinement_error_thresh1)
+ {
+ params.m_scan_delta_size = RG_ETC1_ARRAY_SIZE(s_scan_delta_5_to_8);
+ params.m_pScan_deltas = s_scan_delta_5_to_8;
+ }
+ else
+ {
+ params.m_scan_delta_size = RG_ETC1_ARRAY_SIZE(s_scan_delta_5_to_5);
+ params.m_pScan_deltas = s_scan_delta_5_to_5;
+ }
+ }
+
+ if (!optimizer.compute())
+ break;
+ }
+
+ if (results[2].m_error < results[subblock].m_error)
+ results[subblock] = results[2];
+ }
+
+ trial_error += results[subblock].m_error;
+ if (trial_error >= best_error)
+ break;
+ }
+
+ if (subblock < 2)
+ continue;
+
+ best_error = trial_error;
+ best_results[0] = results[0];
+ best_results[1] = results[1];
+ best_flip = flip;
+ best_use_color4 = use_color4;
+
+ } // use_color4
+
+ } // flip
+
+ int dr = best_results[1].m_block_color_unscaled.r - best_results[0].m_block_color_unscaled.r;
+ int dg = best_results[1].m_block_color_unscaled.g - best_results[0].m_block_color_unscaled.g;
+ int db = best_results[1].m_block_color_unscaled.b - best_results[0].m_block_color_unscaled.b;
+ RG_ETC1_ASSERT(best_use_color4 || ((rg_etc1::minimum(dr, dg, db) >= cETC1ColorDeltaMin) && (rg_etc1::maximum(dr, dg, db) <= cETC1ColorDeltaMax)));
+
+ if (best_use_color4)
+ {
+ dst_block.m_bytes[0] = static_cast<uint8>(best_results[1].m_block_color_unscaled.r | (best_results[0].m_block_color_unscaled.r << 4));
+ dst_block.m_bytes[1] = static_cast<uint8>(best_results[1].m_block_color_unscaled.g | (best_results[0].m_block_color_unscaled.g << 4));
+ dst_block.m_bytes[2] = static_cast<uint8>(best_results[1].m_block_color_unscaled.b | (best_results[0].m_block_color_unscaled.b << 4));
+ }
+ else
+ {
+ if (dr < 0) dr += 8; dst_block.m_bytes[0] = static_cast<uint8>((best_results[0].m_block_color_unscaled.r << 3) | dr);
+ if (dg < 0) dg += 8; dst_block.m_bytes[1] = static_cast<uint8>((best_results[0].m_block_color_unscaled.g << 3) | dg);
+ if (db < 0) db += 8; dst_block.m_bytes[2] = static_cast<uint8>((best_results[0].m_block_color_unscaled.b << 3) | db);
+ }
+
+ dst_block.m_bytes[3] = static_cast<uint8>( (best_results[1].m_block_inten_table << 2) | (best_results[0].m_block_inten_table << 5) | ((~best_use_color4 & 1) << 1) | best_flip );
+
+ uint selector0 = 0, selector1 = 0;
+ if (best_flip)
+ {
+ // flipped:
+ // { 0, 0 }, { 1, 0 }, { 2, 0 }, { 3, 0 },
+ // { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 }
+ //
+ // { 0, 2 }, { 1, 2 }, { 2, 2 }, { 3, 2 },
+ // { 0, 3 }, { 1, 3 }, { 2, 3 }, { 3, 3 }
+ const uint8* pSelectors0 = best_results[0].m_pSelectors;
+ const uint8* pSelectors1 = best_results[1].m_pSelectors;
+ for (int x = 3; x >= 0; --x)
+ {
+ uint b;
+ b = g_selector_index_to_etc1[pSelectors1[4 + x]];
+ selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1);
+
+ b = g_selector_index_to_etc1[pSelectors1[x]];
+ selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1);
+
+ b = g_selector_index_to_etc1[pSelectors0[4 + x]];
+ selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1);
+
+ b = g_selector_index_to_etc1[pSelectors0[x]];
+ selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1);
+ }
+ }
+ else
+ {
+ // non-flipped:
+ // { 0, 0 }, { 0, 1 }, { 0, 2 }, { 0, 3 },
+ // { 1, 0 }, { 1, 1 }, { 1, 2 }, { 1, 3 }
+ //
+ // { 2, 0 }, { 2, 1 }, { 2, 2 }, { 2, 3 },
+ // { 3, 0 }, { 3, 1 }, { 3, 2 }, { 3, 3 }
+ for (int subblock = 1; subblock >= 0; --subblock)
+ {
+ const uint8* pSelectors = best_results[subblock].m_pSelectors + 4;
+ for (uint i = 0; i < 2; i++)
+ {
+ uint b;
+ b = g_selector_index_to_etc1[pSelectors[3]];
+ selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1);
+
+ b = g_selector_index_to_etc1[pSelectors[2]];
+ selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1);
+
+ b = g_selector_index_to_etc1[pSelectors[1]];
+ selector0 = (selector0 << 1) | (b & 1); selector1 = (selector1 << 1) | (b >> 1);
+
+ b = g_selector_index_to_etc1[pSelectors[0]];
+ selector0 = (selector0 << 1) | (b & 1);selector1 = (selector1 << 1) | (b >> 1);
+
+ pSelectors -= 4;
+ }
+ }
+ }
+
+ dst_block.m_bytes[4] = static_cast<uint8>(selector1 >> 8); dst_block.m_bytes[5] = static_cast<uint8>(selector1 & 0xFF);
+ dst_block.m_bytes[6] = static_cast<uint8>(selector0 >> 8); dst_block.m_bytes[7] = static_cast<uint8>(selector0 & 0xFF);
+
+ return static_cast<unsigned int>(best_error);
+ }
+
+} // namespace rg_etc1
diff --git a/drivers/etc1/rg_etc1.h b/drivers/etc1/rg_etc1.h
index 9a701506fd..9ce89a6cc6 100644
--- a/drivers/etc1/rg_etc1.h
+++ b/drivers/etc1/rg_etc1.h
@@ -1,76 +1,76 @@
-// File: rg_etc1.h - Fast, high quality ETC1 block packer/unpacker - Rich Geldreich <richgel99@gmail.com>
-// Please see ZLIB license at the end of this file.
-#pragma once
-
-namespace rg_etc1
-{
- // Unpacks an 8-byte ETC1 compressed block to a block of 4x4 32bpp RGBA pixels.
- // Returns false if the block is invalid. Invalid blocks will still be unpacked with clamping.
- // This function is thread safe, and does not dynamically allocate any memory.
- // If preserve_alpha is true, the alpha channel of the destination pixels will not be overwritten. Otherwise, alpha will be set to 255.
- bool unpack_etc1_block(const void *pETC1_block, unsigned int* pDst_pixels_rgba, bool preserve_alpha = false);
-
- // Quality setting = the higher the quality, the slower.
- // To pack large textures, it is highly recommended to call pack_etc1_block() in parallel, on different blocks, from multiple threads (particularly when using cHighQuality).
- enum etc1_quality
- {
- cLowQuality,
- cMediumQuality,
- cHighQuality,
- };
-
- struct etc1_pack_params
- {
- etc1_quality m_quality;
- bool m_dithering;
-
- inline etc1_pack_params()
- {
- clear();
- }
-
- void clear()
- {
- m_quality = cHighQuality;
- m_dithering = false;
- }
- };
-
- // Important: pack_etc1_block_init() must be called before calling pack_etc1_block().
- void pack_etc1_block_init();
-
- // Packs a 4x4 block of 32bpp RGBA pixels to an 8-byte ETC1 block.
- // 32-bit RGBA pixels must always be arranged as (R,G,B,A) (R first, A last) in memory, independent of platform endianness. A should always be 255.
- // Returns squared error of result.
- // This function is thread safe, and does not dynamically allocate any memory.
- // pack_etc1_block() does not currently support "perceptual" colorspace metrics - it primarily optimizes for RGB RMSE.
- unsigned int pack_etc1_block(void* pETC1_block, const unsigned int* pSrc_pixels_rgba, etc1_pack_params& pack_params);
-
-} // namespace rg_etc1
-
-//------------------------------------------------------------------------------
-//
-// rg_etc1 uses the ZLIB license:
-// http://opensource.org/licenses/Zlib
-//
-// Copyright (c) 2012 Rich Geldreich
-//
-// This software is provided 'as-is', without any express or implied
-// warranty. In no event will the authors be held liable for any damages
-// arising from the use of this software.
-//
-// Permission is granted to anyone to use this software for any purpose,
-// including commercial applications, and to alter it and redistribute it
-// freely, subject to the following restrictions:
-//
-// 1. The origin of this software must not be misrepresented; you must not
-// claim that you wrote the original software. If you use this software
-// in a product, an acknowledgment in the product documentation would be
-// appreciated but is not required.
-//
-// 2. Altered source versions must be plainly marked as such, and must not be
-// misrepresented as being the original software.
-//
-// 3. This notice may not be removed or altered from any source distribution.
-//
-//------------------------------------------------------------------------------
+// File: rg_etc1.h - Fast, high quality ETC1 block packer/unpacker - Rich Geldreich <richgel99@gmail.com>
+// Please see ZLIB license at the end of this file.
+#pragma once
+
+namespace rg_etc1
+{
+ // Unpacks an 8-byte ETC1 compressed block to a block of 4x4 32bpp RGBA pixels.
+ // Returns false if the block is invalid. Invalid blocks will still be unpacked with clamping.
+ // This function is thread safe, and does not dynamically allocate any memory.
+ // If preserve_alpha is true, the alpha channel of the destination pixels will not be overwritten. Otherwise, alpha will be set to 255.
+ bool unpack_etc1_block(const void *pETC1_block, unsigned int* pDst_pixels_rgba, bool preserve_alpha = false);
+
+ // Quality setting = the higher the quality, the slower.
+ // To pack large textures, it is highly recommended to call pack_etc1_block() in parallel, on different blocks, from multiple threads (particularly when using cHighQuality).
+ enum etc1_quality
+ {
+ cLowQuality,
+ cMediumQuality,
+ cHighQuality,
+ };
+
+ struct etc1_pack_params
+ {
+ etc1_quality m_quality;
+ bool m_dithering;
+
+ inline etc1_pack_params()
+ {
+ clear();
+ }
+
+ void clear()
+ {
+ m_quality = cHighQuality;
+ m_dithering = false;
+ }
+ };
+
+ // Important: pack_etc1_block_init() must be called before calling pack_etc1_block().
+ void pack_etc1_block_init();
+
+ // Packs a 4x4 block of 32bpp RGBA pixels to an 8-byte ETC1 block.
+ // 32-bit RGBA pixels must always be arranged as (R,G,B,A) (R first, A last) in memory, independent of platform endianness. A should always be 255.
+ // Returns squared error of result.
+ // This function is thread safe, and does not dynamically allocate any memory.
+ // pack_etc1_block() does not currently support "perceptual" colorspace metrics - it primarily optimizes for RGB RMSE.
+ unsigned int pack_etc1_block(void* pETC1_block, const unsigned int* pSrc_pixels_rgba, etc1_pack_params& pack_params);
+
+} // namespace rg_etc1
+
+//------------------------------------------------------------------------------
+//
+// rg_etc1 uses the ZLIB license:
+// http://opensource.org/licenses/Zlib
+//
+// Copyright (c) 2012 Rich Geldreich
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+// claim that you wrote the original software. If you use this software
+// in a product, an acknowledgment in the product documentation would be
+// appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such, and must not be
+// misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source distribution.
+//
+//------------------------------------------------------------------------------
diff --git a/drivers/gl_context/SCsub b/drivers/gl_context/SCsub
index 0177eec6a2..7cf8629fe1 100644
--- a/drivers/gl_context/SCsub
+++ b/drivers/gl_context/SCsub
@@ -3,4 +3,3 @@ Export('env');
env.add_source_files(env.drivers_sources,"*.cpp")
env.add_source_files(env.drivers_sources,"*.c")
-
diff --git a/drivers/gl_context/context_gl.cpp b/drivers/gl_context/context_gl.cpp
index 82195cc6f6..c1bf6b38ea 100644
--- a/drivers/gl_context/context_gl.cpp
+++ b/drivers/gl_context/context_gl.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/*************************************************/
/* Source code within this file is: */
-/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
/* All Rights Reserved. */
/*************************************************/
diff --git a/drivers/gl_context/context_gl.h b/drivers/gl_context/context_gl.h
index 6b06ccdc37..1ea3662ada 100644
--- a/drivers/gl_context/context_gl.h
+++ b/drivers/gl_context/context_gl.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/gl_context/glew.c b/drivers/gl_context/glew.c
index fc0aa28a72..962e82b657 100644
--- a/drivers/gl_context/glew.c
+++ b/drivers/gl_context/glew.c
@@ -1,3 +1,7 @@
+#ifdef __HAIKU__
+ #undef GLEW_ENABLED
+#endif
+
#ifdef GLEW_ENABLED
/*
** The OpenGL Extension Wrangler Library
diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp
index 05ae85e096..f0978228ff 100644
--- a/drivers/gles2/rasterizer_gles2.cpp
+++ b/drivers/gles2/rasterizer_gles2.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -929,6 +929,7 @@ void RasterizerGLES2::texture_allocate(RID p_texture,int p_width, int p_height,I
texture->compressed=compressed;
texture->has_alpha=false; //by default it doesn't have alpha unless something with alpha is blitteds
texture->data_size=0;
+ texture->mipmaps=0;
glActiveTexture(GL_TEXTURE0);
@@ -1013,10 +1014,16 @@ void RasterizerGLES2::texture_set_data(RID p_texture,const Image& p_image,VS::Cu
bool force_clamp_to_edge = !(texture->flags&VS::TEXTURE_FLAG_MIPMAPS && !texture->ignore_mipmaps) && (nearest_power_of_2(texture->alloc_height)!=texture->alloc_height || nearest_power_of_2(texture->alloc_width)!=texture->alloc_width);
- if (!force_clamp_to_edge && texture->flags&VS::TEXTURE_FLAG_REPEAT && texture->target != GL_TEXTURE_CUBE_MAP) {
+ if (!force_clamp_to_edge && (texture->flags&VS::TEXTURE_FLAG_REPEAT || texture->flags&VS::TEXTURE_FLAG_MIRRORED_REPEAT) && texture->target != GL_TEXTURE_CUBE_MAP) {
- glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
- glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
+ if (texture->flags&VS::TEXTURE_FLAG_MIRRORED_REPEAT){
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT );
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT );
+ }
+ else{
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
+ }
} else {
//glTexParameterf( texture->target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE );
@@ -1080,6 +1087,7 @@ void RasterizerGLES2::texture_set_data(RID p_texture,const Image& p_image,VS::Cu
glGenerateMipmap(texture->target);
}
+ texture->mipmaps=mipmaps;
@@ -1263,17 +1271,26 @@ void RasterizerGLES2::texture_set_flags(RID p_texture,uint32_t p_flags) {
p_flags&=VS::TEXTURE_FLAG_FILTER;//can change only filter
}
+ bool had_mipmaps = texture->flags&VS::TEXTURE_FLAG_MIPMAPS;
+
glActiveTexture(GL_TEXTURE0);
glBindTexture(texture->target, texture->tex_id);
uint32_t cube = texture->flags & VS::TEXTURE_FLAG_CUBEMAP;
texture->flags=p_flags|cube; // can't remove a cube from being a cube
+
bool force_clamp_to_edge = !(p_flags&VS::TEXTURE_FLAG_MIPMAPS && !texture->ignore_mipmaps) && (nearest_power_of_2(texture->alloc_height)!=texture->alloc_height || nearest_power_of_2(texture->alloc_width)!=texture->alloc_width);
- if (!force_clamp_to_edge && texture->flags&VS::TEXTURE_FLAG_REPEAT && texture->target != GL_TEXTURE_CUBE_MAP) {
+ if (!force_clamp_to_edge && (texture->flags&VS::TEXTURE_FLAG_REPEAT || texture->flags&VS::TEXTURE_FLAG_MIRRORED_REPEAT) && texture->target != GL_TEXTURE_CUBE_MAP) {
- glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
- glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
+ if (texture->flags&VS::TEXTURE_FLAG_MIRRORED_REPEAT){
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT );
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT );
+ }
+ else {
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
+ }
} else {
//glTexParameterf( texture->target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE );
glTexParameterf( texture->target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
@@ -1292,9 +1309,13 @@ void RasterizerGLES2::texture_set_flags(RID p_texture,uint32_t p_flags) {
}
}
- if (texture->flags&VS::TEXTURE_FLAG_MIPMAPS && !texture->ignore_mipmaps)
+ if (texture->flags&VS::TEXTURE_FLAG_MIPMAPS && !texture->ignore_mipmaps) {
+ if (!had_mipmaps && texture->mipmaps==1) {
+ glGenerateMipmap(texture->target);
+ }
glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,use_fast_texture_filter?GL_LINEAR_MIPMAP_NEAREST:GL_LINEAR_MIPMAP_LINEAR);
- else{
+
+ } else{
if (texture->flags&VS::TEXTURE_FLAG_FILTER) {
glTexParameteri(texture->target,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
} else {
@@ -1396,6 +1417,40 @@ GLuint RasterizerGLES2::_texture_get_name(RID p_tex) {
return texture->tex_id;
};
+void RasterizerGLES2::texture_set_path(RID p_texture,const String& p_path) {
+ Texture * texture = texture_owner.get(p_texture);
+ ERR_FAIL_COND(!texture);
+
+ texture->path=p_path;
+
+}
+
+String RasterizerGLES2::texture_get_path(RID p_texture) const{
+
+ Texture * texture = texture_owner.get(p_texture);
+ ERR_FAIL_COND_V(!texture,String());
+ return texture->path;
+}
+void RasterizerGLES2::texture_debug_usage(List<VS::TextureInfo> *r_info){
+
+ List<RID> textures;
+ texture_owner.get_owned_list(&textures);
+
+ for (List<RID>::Element *E=textures.front();E;E=E->next()) {
+
+ Texture *t = texture_owner.get(E->get());
+ if (!t)
+ continue;
+ VS::TextureInfo tinfo;
+ tinfo.path=t->path;
+ tinfo.format=t->format;
+ tinfo.size.x=t->alloc_width;
+ tinfo.size.y=t->alloc_height;
+ tinfo.bytes=t->total_data_size;
+ r_info->push_back(tinfo);
+ }
+
+}
/* SHADER API */
@@ -4029,6 +4084,8 @@ void RasterizerGLES2::render_target_set_size(RID p_render_target,int p_width,int
glDeleteTextures(1,&rt->color);
rt->fbo=0;
+ rt->depth=0;
+ rt->color=0;
rt->width=0;
rt->height=0;
rt->texture_ptr->tex_id=0;
@@ -4048,12 +4105,14 @@ void RasterizerGLES2::render_target_set_size(RID p_render_target,int p_width,int
glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo);
//depth
- glGenRenderbuffers(1, &rt->depth);
- glBindRenderbuffer(GL_RENDERBUFFER, rt->depth );
+ if (!low_memory_2d) {
+ glGenRenderbuffers(1, &rt->depth);
+ glBindRenderbuffer(GL_RENDERBUFFER, rt->depth );
- glRenderbufferStorage(GL_RENDERBUFFER, use_depth24?_DEPTH_COMPONENT24_OES:GL_DEPTH_COMPONENT16, rt->width,rt->height);
+ glRenderbufferStorage(GL_RENDERBUFFER, use_depth24?_DEPTH_COMPONENT24_OES:GL_DEPTH_COMPONENT16, rt->width,rt->height);
- glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth);
+ }
//color
glGenTextures(1, &rt->color);
@@ -4133,7 +4192,7 @@ void RasterizerGLES2::begin_frame() {
//fragment_lighting=Globals::get_singleton()->get("rasterizer/use_fragment_lighting");
#ifdef TOOLS_ENABLED
- canvas_shader.set_conditional(CanvasShaderGLES2::USE_PIXEL_SNAP,GLOBAL_DEF("rasterizer/use_pixel_snap",false));
+ canvas_shader.set_conditional(CanvasShaderGLES2::USE_PIXEL_SNAP,GLOBAL_DEF("display/use_2d_pixel_snap",false));
shadow_filter=ShadowFilterTechnique(int(Globals::get_singleton()->get("rasterizer/shadow_filter")));
#endif
@@ -4148,7 +4207,6 @@ void RasterizerGLES2::begin_frame() {
time_delta=time-last_time;
last_time=time;
frame++;
- clear_viewport(Color(1,0,0.5));
_rinfo.vertex_count=0;
_rinfo.object_count=0;
@@ -4592,10 +4650,16 @@ void RasterizerGLES2::_update_shader( Shader* p_shader) const {
if (light_flags.uses_light) {
enablers.push_back("#define USE_LIGHT_SHADER_CODE\n");
}
+ if (light_flags.uses_shadow_color) {
+ enablers.push_back("#define USE_LIGHT_SHADOW_COLOR\n");
+ }
if (light_flags.uses_time || fragment_flags.uses_time || vertex_flags.uses_time) {
enablers.push_back("#define USE_TIME\n");
uses_time=true;
}
+ if (vertex_flags.vertex_code_writes_position) {
+ enablers.push_back("#define VERTEX_SHADER_WRITE_POSITION\n");
+ }
material_shader.set_custom_shader_code(p_shader->custom_code_id,vertex_code, vertex_globals,fragment_code, light_code, fragment_globals,uniform_names,enablers);
} else if (p_shader->mode==VS::SHADER_CANVAS_ITEM) {
@@ -5958,6 +6022,10 @@ void RasterizerGLES2::_render(const Geometry *p_geometry,const Material *p_mater
if (element_count==0)
return;
+ if (mm->visible>=0) {
+ element_count=MIN(element_count,mm->visible);
+ }
+
const MultiMesh::Element *elements=&mm->elements[0];
_rinfo.vertex_count+=s->array_len*element_count;
@@ -6477,80 +6545,84 @@ void RasterizerGLES2::_render_list_forward(RenderList *p_render_list,const Trans
material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_LIGHTMAP,false);
material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_DP_SAMPLER,false);
- if (e->instance->sampled_light.is_valid()) {
+ if (material->flags[VS::MATERIAL_FLAG_UNSHADED] == false && current_debug != VS::SCENARIO_DEBUG_SHADELESS) {
+
+ if (e->instance->sampled_light.is_valid()) {
- SampledLight *sl = sampled_light_owner.get(e->instance->sampled_light);
- if (sl) {
+ SampledLight *sl = sampled_light_owner.get(e->instance->sampled_light);
+ if (sl) {
- baked_light=NULL; //can't mix
- material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_DP_SAMPLER,true);
- glActiveTexture(GL_TEXTURE0+max_texture_units-3);
- glBindTexture(GL_TEXTURE_2D,sl->texture); //bind the texture
- sampled_light_dp_multiplier=sl->multiplier;
- bind_dp_sampler=true;
+ baked_light = NULL; //can't mix
+ material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_DP_SAMPLER, true);
+ glActiveTexture(GL_TEXTURE0 + max_texture_units - 3);
+ glBindTexture(GL_TEXTURE_2D, sl->texture); //bind the texture
+ sampled_light_dp_multiplier = sl->multiplier;
+ bind_dp_sampler = true;
+ }
}
- }
- if (!additive && baked_light) {
+ if (!additive && baked_light) {
- if (baked_light->mode==VS::BAKED_LIGHT_OCTREE && baked_light->octree_texture.is_valid() && e->instance->baked_light_octree_xform) {
- material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_OCTREE,true);
- bind_baked_light_octree=true;
- if (prev_baked_light!=baked_light) {
- Texture *tex=texture_owner.get(baked_light->octree_texture);
- if (tex) {
+ if (baked_light->mode == VS::BAKED_LIGHT_OCTREE && baked_light->octree_texture.is_valid() && e->instance->baked_light_octree_xform) {
+ material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_OCTREE, true);
+ bind_baked_light_octree = true;
+ if (prev_baked_light != baked_light) {
+ Texture *tex = texture_owner.get(baked_light->octree_texture);
+ if (tex) {
- glActiveTexture(GL_TEXTURE0+max_texture_units-3);
- glBindTexture(tex->target,tex->tex_id); //bind the texture
- }
- if (baked_light->light_texture.is_valid()) {
- Texture *texl=texture_owner.get(baked_light->light_texture);
- if (texl) {
- glActiveTexture(GL_TEXTURE0+max_texture_units-4);
- glBindTexture(texl->target,texl->tex_id); //bind the light texture
+ glActiveTexture(GL_TEXTURE0 + max_texture_units - 3);
+ glBindTexture(tex->target, tex->tex_id); //bind the texture
+ }
+ if (baked_light->light_texture.is_valid()) {
+ Texture *texl = texture_owner.get(baked_light->light_texture);
+ if (texl) {
+ glActiveTexture(GL_TEXTURE0 + max_texture_units - 4);
+ glBindTexture(texl->target, texl->tex_id); //bind the light texture
+ }
}
- }
+ }
}
- } else if (baked_light->mode==VS::BAKED_LIGHT_LIGHTMAPS) {
+ else if (baked_light->mode == VS::BAKED_LIGHT_LIGHTMAPS) {
- int lightmap_idx = e->instance->baked_lightmap_id;
+ int lightmap_idx = e->instance->baked_lightmap_id;
- material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_LIGHTMAP,false);
- bind_baked_lightmap=false;
+ material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_LIGHTMAP, false);
+ bind_baked_lightmap = false;
- if (baked_light->lightmaps.has(lightmap_idx)) {
+ if (baked_light->lightmaps.has(lightmap_idx)) {
- RID texid = baked_light->lightmaps[lightmap_idx];
+ RID texid = baked_light->lightmaps[lightmap_idx];
- if (prev_baked_light!=baked_light || texid!=prev_baked_light_texture) {
+ if (prev_baked_light != baked_light || texid != prev_baked_light_texture) {
- Texture *tex = texture_owner.get(texid);
- if (tex) {
+ Texture *tex = texture_owner.get(texid);
+ if (tex) {
+
+ glActiveTexture(GL_TEXTURE0 + max_texture_units - 3);
+ glBindTexture(tex->target, tex->tex_id); //bind the texture
+ }
- glActiveTexture(GL_TEXTURE0+max_texture_units-3);
- glBindTexture(tex->target,tex->tex_id); //bind the texture
+ prev_baked_light_texture = texid;
}
- prev_baked_light_texture=texid;
- }
+ if (texid.is_valid()) {
+ material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_LIGHTMAP, true);
+ bind_baked_lightmap = true;
+ }
- if (texid.is_valid()) {
- material_shader.set_conditional(MaterialShaderGLES2::ENABLE_AMBIENT_LIGHTMAP,true);
- bind_baked_lightmap=true;
}
-
}
}
- }
- if (int(prev_baked_light!=NULL) ^ int(baked_light!=NULL)) {
- rebind=true;
+ if (int(prev_baked_light != NULL) ^ int(baked_light != NULL)) {
+ rebind = true;
+ }
}
}
@@ -8273,6 +8345,14 @@ void RasterizerGLES2::canvas_draw_rect(const Rect2& p_rect, int p_flags, const R
if ( texture ) {
+ bool untile=false;
+
+ if (p_flags&CANVAS_RECT_TILE && !(texture->flags&VS::TEXTURE_FLAG_REPEAT)) {
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
+ untile=true;
+ }
+
if (!(p_flags&CANVAS_RECT_REGION)) {
Rect2 region = Rect2(0,0,texture->width,texture->height);
@@ -8283,6 +8363,12 @@ void RasterizerGLES2::canvas_draw_rect(const Rect2& p_rect, int p_flags, const R
_draw_textured_quad(p_rect, p_source, Size2(texture->width,texture->height),p_flags&CANVAS_RECT_FLIP_H,p_flags&CANVAS_RECT_FLIP_V,p_flags&CANVAS_RECT_TRANSPOSE);
}
+
+ if (untile) {
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
+ glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
+ }
+
} else {
//glDisable(GL_TEXTURE_2D);
@@ -9112,10 +9198,23 @@ void RasterizerGLES2::_canvas_item_render_commands(CanvasItem *p_item,CanvasItem
//glScissor(viewport.x+current_clip->final_clip_rect.pos.x,viewport.y+ (viewport.height-(current_clip->final_clip_rect.pos.y+current_clip->final_clip_rect.size.height)),
//current_clip->final_clip_rect.size.width,current_clip->final_clip_rect.size.height);
- int x = current_clip->final_clip_rect.pos.x;
- int y = window_size.height-(current_clip->final_clip_rect.pos.y+current_clip->final_clip_rect.size.y);
- int w = current_clip->final_clip_rect.size.x;
- int h = current_clip->final_clip_rect.size.y;
+ int x;
+ int y;
+ int w;
+ int h;
+
+ if (current_rt) {
+ x = current_clip->final_clip_rect.pos.x;
+ y = current_clip->final_clip_rect.pos.y;
+ w = current_clip->final_clip_rect.size.x;
+ h = current_clip->final_clip_rect.size.y;
+ }
+ else {
+ x = current_clip->final_clip_rect.pos.x;
+ y = window_size.height - (current_clip->final_clip_rect.pos.y + current_clip->final_clip_rect.size.y);
+ w = current_clip->final_clip_rect.size.x;
+ h = current_clip->final_clip_rect.size.y;
+ }
glScissor(x,y,w,h);
@@ -9155,7 +9254,11 @@ void RasterizerGLES2::_canvas_item_setup_shader_params(CanvasItemMaterial *mater
glBindTexture(GL_TEXTURE_2D,framebuffer.sample_color);
if (framebuffer.scale==1 && !canvas_texscreen_used) {
#ifdef GLEW_ENABLED
- glReadBuffer(GL_COLOR_ATTACHMENT0);
+ if (current_rt) {
+ glReadBuffer(GL_COLOR_ATTACHMENT0);
+ } else {
+ glReadBuffer(GL_BACK);
+ }
#endif
glCopyTexSubImage2D(GL_TEXTURE_2D,0,x,y,x,y,viewport.width,viewport.height);
// if (current_clip) {
@@ -9301,10 +9404,23 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
int w = current_clip->final_clip_rect.size.x;
int h = current_clip->final_clip_rect.size.y;
*/
- int x = current_clip->final_clip_rect.pos.x;
- int y = window_size.height-(current_clip->final_clip_rect.pos.y+current_clip->final_clip_rect.size.y);
- int w = current_clip->final_clip_rect.size.x;
- int h = current_clip->final_clip_rect.size.y;
+ int x;
+ int y;
+ int w;
+ int h;
+
+ if (current_rt) {
+ x = current_clip->final_clip_rect.pos.x;
+ y = current_clip->final_clip_rect.pos.y;
+ w = current_clip->final_clip_rect.size.x;
+ h = current_clip->final_clip_rect.size.y;
+ }
+ else {
+ x = current_clip->final_clip_rect.pos.x;
+ y = window_size.height - (current_clip->final_clip_rect.pos.y + current_clip->final_clip_rect.size.y);
+ w = current_clip->final_clip_rect.size.x;
+ h = current_clip->final_clip_rect.size.y;
+ }
glScissor(x,y,w,h);
@@ -9335,7 +9451,11 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
glBindTexture(GL_TEXTURE_2D,framebuffer.sample_color);
#ifdef GLEW_ENABLED
- glReadBuffer(GL_COLOR_ATTACHMENT0);
+ if (current_rt) {
+ glReadBuffer(GL_COLOR_ATTACHMENT0);
+ } else {
+ glReadBuffer(GL_BACK);
+ }
#endif
glCopyTexSubImage2D(GL_TEXTURE_2D,0,x,y,x,y,w,h);
// if (current_clip) {
@@ -9449,7 +9569,7 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
canvas_opacity = ci->final_opacity;
- if (unshaded || (p_modulate.a>0.001 && (!material || material->shading_mode!=VS::CANVAS_ITEM_SHADING_ONLY_LIGHT)))
+ if (unshaded || (p_modulate.a>0.001 && (!material || material->shading_mode!=VS::CANVAS_ITEM_SHADING_ONLY_LIGHT) && !ci->light_masked ))
_canvas_item_render_commands<false>(ci,current_clip,reclip);
if (canvas_blend_mode==VS::MATERIAL_BLEND_MODE_MIX && p_light && !unshaded) {
@@ -9481,7 +9601,8 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
glBlendFunc(GL_SRC_ALPHA,GL_ONE);
} break;
- case VS::CANVAS_LIGHT_MODE_MIX: {
+ case VS::CANVAS_LIGHT_MODE_MIX:
+ case VS::CANVAS_LIGHT_MODE_MASK: {
glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -9529,6 +9650,7 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_COLOR,Color(light->color.r*light->energy,light->color.g*light->energy,light->color.b*light->energy,light->color.a));
canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_HEIGHT,light->height);
canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_LOCAL_MATRIX,light->xform_cache.affine_inverse());
+ canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_OUTSIDE_ALPHA,light->mode==VS::CANVAS_LIGHT_MODE_MASK?1.0:0.0);
if (has_shadow) {
@@ -9542,6 +9664,7 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_TEXTURE,max_texture_units-3);
canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_MATRIX,light->shadow_matrix_cache);
canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_ESM_MULTIPLIER,light->shadow_esm_mult);
+ canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_SHADOW_COLOR,light->shadow_color);
}
@@ -9601,10 +9724,23 @@ void RasterizerGLES2::canvas_render_items(CanvasItem *p_item_list,int p_z,const
//glScissor(viewport.x+current_clip->final_clip_rect.pos.x,viewport.y+ (viewport.height-(current_clip->final_clip_rect.pos.y+current_clip->final_clip_rect.size.height)),
//current_clip->final_clip_rect.size.width,current_clip->final_clip_rect.size.height);
- int x = current_clip->final_clip_rect.pos.x;
- int y = window_size.height-(current_clip->final_clip_rect.pos.y+current_clip->final_clip_rect.size.y);
- int w = current_clip->final_clip_rect.size.x;
- int h = current_clip->final_clip_rect.size.y;
+ int x;
+ int y;
+ int w;
+ int h;
+
+ if (current_rt) {
+ x = current_clip->final_clip_rect.pos.x;
+ y = current_clip->final_clip_rect.pos.y;
+ w = current_clip->final_clip_rect.size.x;
+ h = current_clip->final_clip_rect.size.y;
+ }
+ else {
+ x = current_clip->final_clip_rect.pos.x;
+ y = window_size.height - (current_clip->final_clip_rect.pos.y + current_clip->final_clip_rect.size.y);
+ w = current_clip->final_clip_rect.size.x;
+ h = current_clip->final_clip_rect.size.y;
+ }
glScissor(x,y,w,h);
@@ -10199,6 +10335,8 @@ void RasterizerGLES2::_update_framebuffer() {
return;
int scale = GLOBAL_DEF("rasterizer/framebuffer_shrink",1);
+ if (scale<1)
+ scale=1;
int dwidth = OS::get_singleton()->get_video_mode().width/scale;
int dheight = OS::get_singleton()->get_video_mode().height/scale;
@@ -10241,7 +10379,11 @@ void RasterizerGLES2::_update_framebuffer() {
framebuffer.fbo=0;
}
+#ifdef TOOLS_ENABLED
framebuffer.active=use_fbo;
+#else
+ framebuffer.active=use_fbo && !low_memory_2d;
+#endif
framebuffer.width=dwidth;
framebuffer.height=dheight;
framebuffer.scale=scale;
@@ -10283,6 +10425,13 @@ void RasterizerGLES2::_update_framebuffer() {
GLuint format_rgba = GL_RGBA;
GLuint format_rgb = use_fp16_fb?_GL_RGB16F_EXT:GL_RGB;
GLuint format_type = use_fp16_fb?_GL_HALF_FLOAT_OES:GL_UNSIGNED_BYTE;
+ GLuint format_internal=GL_RGBA;
+
+ if (use_16bits_fbo) {
+ format_type=GL_UNSIGNED_SHORT_5_6_5;
+ format_rgba=GL_RGB;
+ format_internal=GL_RGB;
+ }
/*GLuint format_luminance = use_fp16_fb?GL_RGB16F:GL_RGBA;
GLuint format_luminance_type = use_fp16_fb?(use_fu_GL_HALF_FLOAT_OES):GL_UNSIGNED_BYTE;
GLuint format_luminance_components = use_fp16_fb?GL_RGB:GL_RGBA;*/
@@ -10296,7 +10445,7 @@ void RasterizerGLES2::_update_framebuffer() {
glGenTextures(1, &framebuffer.color);
glBindTexture(GL_TEXTURE_2D, framebuffer.color);
- glTexImage2D(GL_TEXTURE_2D, 0, format_rgba, framebuffer.width, framebuffer.height, 0, GL_RGBA, format_type, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, format_rgba, framebuffer.width, framebuffer.height, 0, format_internal, format_type, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -10321,7 +10470,7 @@ void RasterizerGLES2::_update_framebuffer() {
framebuffer.fbo=0;
framebuffer.active=false;
//print_line("**************** NO FAMEBUFFEEEERRRR????");
- WARN_PRINT("Could not create framebuffer!!");
+ WARN_PRINT(String("Could not create framebuffer!!, code: "+itos(status)).ascii().get_data());
}
//sample
@@ -10330,7 +10479,7 @@ void RasterizerGLES2::_update_framebuffer() {
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer.sample_fbo);
glGenTextures(1, &framebuffer.sample_color);
glBindTexture(GL_TEXTURE_2D, framebuffer.sample_color);
- glTexImage2D(GL_TEXTURE_2D, 0, format_rgba, framebuffer.width, framebuffer.height, 0, GL_RGBA, format_type, NULL);
+ glTexImage2D(GL_TEXTURE_2D, 0, format_rgba, framebuffer.width, framebuffer.height, 0, format_internal, format_type, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
@@ -10390,7 +10539,7 @@ void RasterizerGLES2::_update_framebuffer() {
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, format_rgba, size, size, 0,
- GL_RGBA, format_type, NULL);
+ format_internal, format_type, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, framebuffer.blur[i].color, 0);
@@ -10797,7 +10946,7 @@ void RasterizerGLES2::init() {
copy_shader.set_conditional(CopyShaderGLES2::USE_8BIT_HDR,!use_fp16_fb);
canvas_shader.set_conditional(CanvasShaderGLES2::USE_DEPTH_SHADOWS,read_depth_supported);
- canvas_shader.set_conditional(CanvasShaderGLES2::USE_PIXEL_SNAP,GLOBAL_DEF("rasterizer/use_pixel_snap",false));
+ canvas_shader.set_conditional(CanvasShaderGLES2::USE_PIXEL_SNAP,GLOBAL_DEF("display/use_2d_pixel_snap",false));
npo2_textures_available=true;
//fragment_lighting=false;
@@ -11119,6 +11268,11 @@ RasterizerGLES2* RasterizerGLES2::get_singleton() {
int RasterizerGLES2::RenderList::max_elements=RenderList::DEFAULT_MAX_ELEMENTS;
+void RasterizerGLES2::set_force_16_bits_fbo(bool p_force) {
+
+ use_16bits_fbo=p_force;
+}
+
RasterizerGLES2::RasterizerGLES2(bool p_compress_arrays,bool p_keep_ram_copy,bool p_default_fragment_lighting,bool p_use_reload_hooks) {
_singleton = this;
@@ -11151,6 +11305,7 @@ RasterizerGLES2::RasterizerGLES2(bool p_compress_arrays,bool p_keep_ram_copy,boo
use_fp16_fb=bool(GLOBAL_DEF("rasterizer/fp16_framebuffer",true));
use_shadow_mapping=true;
use_fast_texture_filter=!bool(GLOBAL_DEF("rasterizer/trilinear_mipmap_filter",true));
+ low_memory_2d=bool(GLOBAL_DEF("rasterizer/low_memory_2d_mode",false));
skel_default.resize(1024*4);
for(int i=0;i<1024/3;i++) {
@@ -11179,8 +11334,15 @@ RasterizerGLES2::RasterizerGLES2(bool p_compress_arrays,bool p_keep_ram_copy,boo
framebuffer.active=false;
tc0_id_cache=0;
tc0_idx=0;
+ use_16bits_fbo=false;
};
+void RasterizerGLES2::restore_framebuffer() {
+
+ glBindFramebuffer(GL_FRAMEBUFFER, base_framebuffer);
+
+}
+
RasterizerGLES2::~RasterizerGLES2() {
memdelete_arr(skinned_buffer);
diff --git a/drivers/gles2/rasterizer_gles2.h b/drivers/gles2/rasterizer_gles2.h
index d337ecfb64..0f70ceaa97 100644
--- a/drivers/gles2/rasterizer_gles2.h
+++ b/drivers/gles2/rasterizer_gles2.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -91,6 +91,7 @@ class RasterizerGLES2 : public Rasterizer {
bool srgb_supported;
bool float_supported;
bool float_linear_supported;
+ bool use_16bits_fbo;
ShadowFilterTechnique shadow_filter;
@@ -105,16 +106,17 @@ class RasterizerGLES2 : public Rasterizer {
float anisotropic_level;
bool use_half_float;
-
+ bool low_memory_2d;
Vector<float> skel_default;
Image _get_gl_image_and_format(const Image& p_image, Image::Format p_format, uint32_t p_flags,GLenum& r_gl_format,GLenum& r_gl_internal_format,int &r_gl_components,bool &r_has_alpha_cache,bool &r_compressed);
- class RenderTarget;
+ struct RenderTarget;
struct Texture {
+ String path;
uint32_t flags;
int width,height;
int alloc_width, alloc_height;
@@ -136,6 +138,8 @@ class RasterizerGLES2 : public Rasterizer {
StringName reloader_func;
Image image[6];
+ int mipmaps;
+
bool active;
GLuint tex_id;
@@ -157,6 +161,7 @@ class RasterizerGLES2 : public Rasterizer {
compressed=false;
total_data_size=0;
target=GL_TEXTURE_2D;
+ mipmaps=0;
reloader=0;
}
@@ -304,7 +309,7 @@ class RasterizerGLES2 : public Rasterizer {
virtual ~GeometryOwner() {}
};
- class Mesh;
+ struct Mesh;
struct Surface : public Geometry {
@@ -1325,6 +1330,10 @@ public:
virtual void texture_set_size_override(RID p_texture,int p_width, int p_height);
virtual void texture_set_reload_hook(RID p_texture,ObjectID p_owner,const StringName& p_function) const;
+ virtual void texture_set_path(RID p_texture,const String& p_path);
+ virtual String texture_get_path(RID p_texture) const;
+ virtual void texture_debug_usage(List<VS::TextureInfo> *r_info);
+
GLuint _texture_get_name(RID p_tex);
/* SHADER API */
@@ -1695,9 +1704,13 @@ public:
void reload_vram();
virtual bool has_feature(VS::Features p_feature) const;
+
+ virtual void restore_framebuffer();
static RasterizerGLES2* get_singleton();
+ virtual void set_force_16_bits_fbo(bool p_force);
+
RasterizerGLES2(bool p_compress_arrays=false,bool p_keep_ram_copy=true,bool p_default_fragment_lighting=true,bool p_use_reload_hooks=false);
virtual ~RasterizerGLES2();
};
diff --git a/drivers/gles2/rasterizer_instance_gles2.cpp b/drivers/gles2/rasterizer_instance_gles2.cpp
index a8d478c6e0..9d43ecb085 100644
--- a/drivers/gles2/rasterizer_instance_gles2.cpp
+++ b/drivers/gles2/rasterizer_instance_gles2.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/gles2/rasterizer_instance_gles2.h b/drivers/gles2/rasterizer_instance_gles2.h
index f5ac5f1fe2..c41bd71c15 100644
--- a/drivers/gles2/rasterizer_instance_gles2.h
+++ b/drivers/gles2/rasterizer_instance_gles2.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp
index 157f2e398b..3be0fdab17 100644
--- a/drivers/gles2/shader_compiler_gles2.cpp
+++ b/drivers/gles2/shader_compiler_gles2.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -132,18 +132,18 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a
SL::BlockNode *bnode=(SL::BlockNode*)p_node;
//variables
- code+="{"ENDL;
+ code+="{" ENDL;
for(Map<StringName,SL::DataType>::Element *E=bnode->variables.front();E;E=E->next()) {
- code+=_mktab(p_level)+_typestr(E->value())+" "+replace_string(E->key())+";"ENDL;
+ code+=_mktab(p_level)+_typestr(E->value())+" "+replace_string(E->key())+";" ENDL;
}
for(int i=0;i<bnode->statements.size();i++) {
- code+=_mktab(p_level)+dump_node_code(bnode->statements[i],p_level)+";"ENDL;
+ code+=_mktab(p_level)+dump_node_code(bnode->statements[i],p_level)+";" ENDL;
}
- code+="}"ENDL;
+ code+="}" ENDL;
} break;
case SL::Node::TYPE_VARIABLE: {
@@ -154,6 +154,9 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a
if (vnode->name==vname_vertex && p_assign_left) {
vertex_code_writes_vertex=true;
}
+ if (vnode->name == vname_position && p_assign_left) {
+ vertex_code_writes_position = true;
+ }
if (vnode->name==vname_color_interp) {
flags->use_color_interp=true;
}
@@ -218,6 +221,10 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a
uses_light=true;
}
+ if (vnode->name==vname_shadow) {
+ uses_shadow_color=true;
+ }
+
}
if (type==ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX) {
@@ -489,15 +496,15 @@ String ShaderCompilerGLES2::dump_node_code(SL::Node *p_node,int p_level,bool p_a
SL::ControlFlowNode *cfnode=(SL::ControlFlowNode*)p_node;
if (cfnode->flow_op==SL::FLOW_OP_IF) {
- code+="if ("+dump_node_code(cfnode->statements[0],p_level)+") {"ENDL;
+ code+="if ("+dump_node_code(cfnode->statements[0],p_level)+") {" ENDL;
code+=dump_node_code(cfnode->statements[1],p_level+1);
if (cfnode->statements.size()==3) {
- code+="} else {"ENDL;
+ code+="} else {" ENDL;
code+=dump_node_code(cfnode->statements[2],p_level+1);
}
- code+="}"ENDL;
+ code+="}" ENDL;
} else if (cfnode->flow_op==SL::FLOW_OP_RETURN) {
@@ -560,7 +567,7 @@ Error ShaderCompilerGLES2::compile_node(SL::ProgramNode *p_program) {
ubase=uniforms->size();
for(Map<StringName,SL::Uniform>::Element *E=p_program->uniforms.front();E;E=E->next()) {
- String uline="uniform "+_typestr(E->get().type)+" _"+E->key().operator String()+";"ENDL;
+ String uline="uniform "+_typestr(E->get().type)+" _"+E->key().operator String()+";" ENDL;
global_code+=uline;
if (uniforms) {
@@ -593,10 +600,10 @@ Error ShaderCompilerGLES2::compile_node(SL::ProgramNode *p_program) {
header+=_typestr(fnode->arguments[i].type)+" "+replace_string(fnode->arguments[i].name);
}
- header+=") {"ENDL;
+ header+=") {" ENDL;
String fcode=header;
fcode+=dump_node_code(fnode->body,1);
- fcode+="}"ENDL;
+ fcode+="}" ENDL;
global_code+=fcode;
}
@@ -605,7 +612,7 @@ Error ShaderCompilerGLES2::compile_node(SL::ProgramNode *p_program) {
StringName varname=E->key();
String newvarname=replace_string(varname);
- global_code+="uniform "+_typestr(E->get())+" "+newvarname+";"ENDL;
+ global_code+="uniform "+_typestr(E->get())+" "+newvarname+";" ENDL;
}*/
code=dump_node_code(p_program,0);
@@ -659,6 +666,7 @@ Error ShaderCompilerGLES2::compile(const String& p_code, ShaderLanguage::ShaderT
uses_texpixel_size=false;
uses_worldvec=false;
vertex_code_writes_vertex=false;
+ vertex_code_writes_position = false;
uses_shadow_color=false;
uniforms=r_uniforms;
flags=&r_flags;
@@ -690,6 +698,7 @@ Error ShaderCompilerGLES2::compile(const String& p_code, ShaderLanguage::ShaderT
r_flags.uses_texscreen=uses_texscreen;
r_flags.uses_texpos=uses_texpos;
r_flags.vertex_code_writes_vertex=vertex_code_writes_vertex;
+ r_flags.vertex_code_writes_position=vertex_code_writes_position;
r_flags.uses_discard=uses_discard;
r_flags.uses_screen_uv=uses_screen_uv;
r_flags.uses_light=uses_light;
@@ -778,125 +787,129 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
replace_table["texscreen"]= "texscreen";
replace_table["texpos"]= "texpos";
- mode_replace_table[0]["SRC_VERTEX"]="vertex_in.xyz";
- mode_replace_table[0]["SRC_NORMAL"]="normal_in";
- mode_replace_table[0]["SRC_TANGENT"]="tangent_in";
- mode_replace_table[0]["SRC_BINORMALF"]="binormalf";
-
- mode_replace_table[0]["VERTEX"]="vertex_interp";
- mode_replace_table[0]["NORMAL"]="normal_interp";
- mode_replace_table[0]["TANGENT"]="tangent_interp";
- mode_replace_table[0]["BINORMAL"]="binormal_interp";
- mode_replace_table[0]["UV"]="uv_interp.xy";
- mode_replace_table[0]["UV2"]="uv_interp.zw";
- mode_replace_table[0]["COLOR"]="color_interp";
+
+
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["SRC_VERTEX"] = "vertex_in.xyz";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["SRC_NORMAL"] = "normal_in";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["SRC_TANGENT"]="tangent_in";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["SRC_BINORMALF"]="binormalf";
+
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["POSITION"] = "gl_Position";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["VERTEX"]="vertex_interp";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["NORMAL"]="normal_interp";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["TANGENT"]="tangent_interp";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["BINORMAL"]="binormal_interp";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["UV"]="uv_interp.xy";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["UV2"]="uv_interp.zw";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["COLOR"]="color_interp";
//@TODO convert to glsl stuff
- mode_replace_table[0]["SPEC_EXP"]="vertex_specular_exp";
- mode_replace_table[0]["WORLD_MATRIX"]="world_transform";
- mode_replace_table[0]["INV_CAMERA_MATRIX"]="camera_inverse_transform";
- mode_replace_table[0]["PROJECTION_MATRIX"]="projection_transform";
- mode_replace_table[0]["MODELVIEW_MATRIX"]="modelview";
- mode_replace_table[0]["POINT_SIZE"]="gl_PointSize";
- mode_replace_table[0]["VAR1"]="var1_interp";
- mode_replace_table[0]["VAR2"]="var2_interp";
-
-// mode_replace_table[0]["SCREEN_POS"]="SCREEN_POS";
-// mode_replace_table[0]["SCREEN_SIZE"]="SCREEN_SIZE";
- mode_replace_table[0]["INSTANCE_ID"]="instance_id";
- mode_replace_table[0]["TIME"]="time";
-
- mode_replace_table[1]["VERTEX"]="vertex";
- //mode_replace_table[1]["POSITION"]="IN_POSITION";
- mode_replace_table[1]["NORMAL"]="normal";
- mode_replace_table[1]["TANGENT"]="tangent";
- mode_replace_table[1]["POSITION"]="gl_Position";
- mode_replace_table[1]["BINORMAL"]="binormal";
- mode_replace_table[1]["NORMALMAP"]="normalmap";
- mode_replace_table[1]["NORMALMAP_DEPTH"]="normaldepth";
- mode_replace_table[1]["VAR1"]="var1_interp";
- mode_replace_table[1]["VAR2"]="var2_interp";
- mode_replace_table[1]["UV"]="uv";
- mode_replace_table[1]["UV2"]="uv2";
- mode_replace_table[1]["SCREEN_UV"]="screen_uv";
- mode_replace_table[1]["VAR1"]="var1_interp";
- mode_replace_table[1]["VAR2"]="var2_interp";
- mode_replace_table[1]["COLOR"]="color";
- mode_replace_table[1]["DIFFUSE"]="diffuse.rgb";
- mode_replace_table[1]["DIFFUSE_ALPHA"]="diffuse";
- mode_replace_table[1]["SPECULAR"]="specular";
- mode_replace_table[1]["EMISSION"]="emission";
- mode_replace_table[1]["SHADE_PARAM"]="shade_param";
- mode_replace_table[1]["SPEC_EXP"]="specular_exp";
- mode_replace_table[1]["GLOW"]="glow";
- mode_replace_table[1]["DISCARD"]="discard_";
- mode_replace_table[1]["POINT_COORD"]="gl_PointCoord";
- mode_replace_table[1]["INV_CAMERA_MATRIX"]="camera_inverse_transform";
-
- //mode_replace_table[1]["SCREEN_POS"]="SCREEN_POS";
- //mode_replace_table[1]["SCREEN_TEXEL_SIZE"]="SCREEN_TEXEL_SIZE";
- mode_replace_table[1]["TIME"]="time";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["SPEC_EXP"]="vertex_specular_exp";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["WORLD_MATRIX"]="world_transform";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["INV_CAMERA_MATRIX"]="camera_inverse_transform";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["PROJECTION_MATRIX"]="projection_transform";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["MODELVIEW_MATRIX"]="modelview";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["POINT_SIZE"]="gl_PointSize";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["VAR1"]="var1_interp";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["VAR2"]="var2_interp";
+
+// mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["SCREEN_POS"]="SCREEN_POS";
+// mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["SCREEN_SIZE"]="SCREEN_SIZE";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["INSTANCE_ID"]="instance_id";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_VERTEX]["TIME"]="time";
+
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["VERTEX"]="vertex";
+ //mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["POSITION"]="IN_POSITION";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["NORMAL"]="normal";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["TANGENT"]="tangent";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["POSITION"]="gl_Position";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["BINORMAL"]="binormal";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["NORMALMAP"]="normalmap";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["NORMALMAP_DEPTH"]="normaldepth";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["VAR1"]="var1_interp";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["VAR2"]="var2_interp";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["UV"]="uv";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["UV2"]="uv2";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["SCREEN_UV"]="screen_uv";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["VAR1"]="var1_interp";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["VAR2"]="var2_interp";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["COLOR"]="color";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["DIFFUSE"]="diffuse.rgb";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["DIFFUSE_ALPHA"]="diffuse";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["SPECULAR"]="specular";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["EMISSION"]="emission";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["SHADE_PARAM"]="shade_param";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["SPEC_EXP"]="specular_exp";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["GLOW"]="glow";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["DISCARD"]="discard_";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["POINT_COORD"]="gl_PointCoord";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["INV_CAMERA_MATRIX"]="camera_inverse_transform";
+
+ //mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["SCREEN_POS"]="SCREEN_POS";
+ //mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["SCREEN_TEXEL_SIZE"]="SCREEN_TEXEL_SIZE";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_FRAGMENT]["TIME"]="time";
//////////////
- mode_replace_table[2]["NORMAL"]="normal";
- //mode_replace_table[2]["POSITION"]="IN_POSITION";
- mode_replace_table[2]["LIGHT_DIR"]="light_dir";
- mode_replace_table[2]["LIGHT_DIFFUSE"]="light_diffuse";
- mode_replace_table[2]["LIGHT_SPECULAR"]="light_specular";
- mode_replace_table[2]["EYE_VEC"]="eye_vec";
- mode_replace_table[2]["DIFFUSE"]="mdiffuse";
- mode_replace_table[2]["SPECULAR"]="specular";
- mode_replace_table[2]["SPECULAR_EXP"]="specular_exp";
- mode_replace_table[2]["SHADE_PARAM"]="shade_param";
- mode_replace_table[2]["LIGHT"]="light";
- mode_replace_table[2]["POINT_COORD"]="gl_PointCoord";
- mode_replace_table[2]["TIME"]="time";
-
- mode_replace_table[3]["SRC_VERTEX"]="src_vtx";
- mode_replace_table[3]["VERTEX"]="outvec.xy";
- mode_replace_table[3]["WORLD_VERTEX"]="outvec.xy";
- mode_replace_table[3]["UV"]="uv_interp";
- mode_replace_table[3]["COLOR"]="color_interp";
- mode_replace_table[3]["VAR1"]="var1_interp";
- mode_replace_table[3]["VAR2"]="var2_interp";
- mode_replace_table[3]["POINT_SIZE"]="gl_PointSize";
- mode_replace_table[3]["WORLD_MATRIX"]="modelview_matrix";
- mode_replace_table[3]["PROJECTION_MATRIX"]="projection_matrix";
- mode_replace_table[3]["EXTRA_MATRIX"]="extra_matrix";
- mode_replace_table[3]["TIME"]="time";
-
- mode_replace_table[4]["POSITION"]="gl_Position";
- mode_replace_table[4]["NORMAL"]="normal";
- mode_replace_table[4]["NORMALMAP"]="normal_map";
- mode_replace_table[4]["NORMALMAP_DEPTH"]="normal_depth";
- mode_replace_table[4]["UV"]="uv_interp";
- mode_replace_table[4]["SRC_COLOR"]="color_interp";
- mode_replace_table[4]["COLOR"]="color";
- mode_replace_table[4]["TEXTURE"]="texture";
- mode_replace_table[4]["TEXTURE_PIXEL_SIZE"]="texpixel_size";
- mode_replace_table[4]["VAR1"]="var1_interp";
- mode_replace_table[4]["VAR2"]="var2_interp";
- mode_replace_table[4]["SCREEN_UV"]="screen_uv";
- mode_replace_table[4]["POINT_COORD"]="gl_PointCoord";
- mode_replace_table[4]["TIME"]="time";
-
- mode_replace_table[5]["POSITION"]="gl_Position";
- mode_replace_table[5]["NORMAL"]="normal";
- mode_replace_table[5]["UV"]="uv_interp";
- mode_replace_table[5]["COLOR"]="color";
- mode_replace_table[5]["TEXTURE"]="texture";
- mode_replace_table[5]["TEXTURE_PIXEL_SIZE"]="texpixel_size";
- mode_replace_table[5]["VAR1"]="var1_interp";
- mode_replace_table[5]["VAR2"]="var2_interp";
- mode_replace_table[5]["LIGHT_VEC"]="light_vec";
- mode_replace_table[5]["LIGHT_HEIGHT"]="light_height";
- mode_replace_table[5]["LIGHT_COLOR"]="light";
- mode_replace_table[5]["LIGHT_UV"]="light_uv";
- mode_replace_table[5]["LIGHT"]="light_out";
- mode_replace_table[5]["SHADOW"]="shadow_color";
- mode_replace_table[5]["SCREEN_UV"]="screen_uv";
- mode_replace_table[5]["POINT_COORD"]="gl_PointCoord";
- mode_replace_table[5]["TIME"]="time";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_LIGHT]["NORMAL"]="normal";
+ //mode_replace_table[ShaderLanguage::SHADER_MATERIAL_LIGHT]["POSITION"]="IN_POSITION";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_LIGHT]["LIGHT_DIR"]="light_dir";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_LIGHT]["LIGHT_DIFFUSE"]="light_diffuse";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_LIGHT]["LIGHT_SPECULAR"]="light_specular";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_LIGHT]["EYE_VEC"]="eye_vec";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_LIGHT]["DIFFUSE"]="mdiffuse";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_LIGHT]["SPECULAR"]="specular";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_LIGHT]["SPECULAR_EXP"]="specular_exp";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_LIGHT]["SHADE_PARAM"]="shade_param";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_LIGHT]["LIGHT"]="light";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_LIGHT]["POINT_COORD"]="gl_PointCoord";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_LIGHT]["TIME"]="time";
+ mode_replace_table[ShaderLanguage::SHADER_MATERIAL_LIGHT]["SHADOW"]="shadow_color";
+
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX]["SRC_VERTEX"]="src_vtx";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX]["VERTEX"]="outvec.xy";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX]["WORLD_VERTEX"]="outvec.xy";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX]["UV"]="uv_interp";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX]["COLOR"]="color_interp";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX]["VAR1"]="var1_interp";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX]["VAR2"]="var2_interp";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX]["POINT_SIZE"]="gl_PointSize";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX]["WORLD_MATRIX"]="modelview_matrix";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX]["PROJECTION_MATRIX"]="projection_matrix";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX]["EXTRA_MATRIX"]="extra_matrix";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_VERTEX]["TIME"]="time";
+
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["POSITION"]="gl_Position";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["NORMAL"]="normal";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["NORMALMAP"]="normal_map";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["NORMALMAP_DEPTH"]="normal_depth";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["UV"]="uv_interp";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["SRC_COLOR"]="color_interp";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["COLOR"]="color";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["TEXTURE"]="texture";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["TEXTURE_PIXEL_SIZE"]="texpixel_size";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["VAR1"]="var1_interp";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["VAR2"]="var2_interp";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["SCREEN_UV"]="screen_uv";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["POINT_COORD"]="gl_PointCoord";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_FRAGMENT]["TIME"]="time";
+
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["POSITION"]="gl_Position";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["NORMAL"]="normal";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["UV"]="uv_interp";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["COLOR"]="color";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["TEXTURE"]="texture";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["TEXTURE_PIXEL_SIZE"]="texpixel_size";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["VAR1"]="var1_interp";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["VAR2"]="var2_interp";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["LIGHT_VEC"]="light_vec";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["LIGHT_HEIGHT"]="light_height";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["LIGHT_COLOR"]="light";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["LIGHT_UV"]="light_uv";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["LIGHT"]="light_out";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["SHADOW"]="shadow_color";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["SCREEN_UV"]="screen_uv";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["POINT_COORD"]="gl_PointCoord";
+ mode_replace_table[ShaderLanguage::SHADER_CANVAS_ITEM_LIGHT]["TIME"]="time";
@@ -917,6 +930,7 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
vname_var1_interp="VAR1";
vname_var2_interp="VAR2";
vname_vertex="VERTEX";
+ vname_position = "POSITION";
vname_light="LIGHT";
vname_time="TIME";
vname_normalmap="NORMALMAP";
diff --git a/drivers/gles2/shader_compiler_gles2.h b/drivers/gles2/shader_compiler_gles2.h
index 43902a7536..688003ecf6 100644
--- a/drivers/gles2/shader_compiler_gles2.h
+++ b/drivers/gles2/shader_compiler_gles2.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,7 +34,7 @@ class ShaderCompilerGLES2 {
class Uniform;
public:
- class Flags;
+ struct Flags;
private:
ShaderLanguage::ProgramNode *program_node;
@@ -55,6 +55,7 @@ private:
bool uses_texpixel_size;
bool uses_worldvec;
bool vertex_code_writes_vertex;
+ bool vertex_code_writes_position;
bool uses_shadow_color;
bool sinh_used;
@@ -76,6 +77,7 @@ private:
StringName vname_var1_interp;
StringName vname_var2_interp;
StringName vname_vertex;
+ StringName vname_position;
StringName vname_light;
StringName vname_time;
StringName vname_normalmap;
@@ -107,6 +109,7 @@ public:
bool uses_texpos;
bool uses_normalmap;
bool vertex_code_writes_vertex;
+ bool vertex_code_writes_position;
bool uses_discard;
bool uses_screen_uv;
bool use_color_interp;
diff --git a/drivers/gles2/shader_gles2.cpp b/drivers/gles2/shader_gles2.cpp
index e94930fffb..d397323171 100644
--- a/drivers/gles2/shader_gles2.cpp
+++ b/drivers/gles2/shader_gles2.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -739,12 +739,12 @@ void ShaderGLES2::set_custom_shader(uint32_t p_code_id) {
void ShaderGLES2::free_custom_shader(uint32_t p_code_id) {
- if (! custom_code_map.has( p_code_id )) {
+ /* if (! custom_code_map.has( p_code_id )) {
print_line("no code id "+itos(p_code_id));
} else {
print_line("freed code id "+itos(p_code_id));
- }
+ }*/
ERR_FAIL_COND(! custom_code_map.has( p_code_id ));
if (conditional_version.code_version==p_code_id)
diff --git a/drivers/gles2/shader_gles2.h b/drivers/gles2/shader_gles2.h
index 4604fd5501..68ae8af63f 100644
--- a/drivers/gles2/shader_gles2.h
+++ b/drivers/gles2/shader_gles2.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -205,6 +205,11 @@ private:
Plane val=p_value;
glUniform4f( p_uniform, val.normal.x,val.normal.y,val.normal.z,val.d );
} break;
+ case Variant::QUAT: {
+
+ Quat val=p_value;
+ glUniform4f( p_uniform, val.x,val.y,val.z,val.w );
+ } break;
case Variant::MATRIX32: {
diff --git a/drivers/gles2/shaders/SCsub b/drivers/gles2/shaders/SCsub
index 9679223b16..38177d725f 100644
--- a/drivers/gles2/shaders/SCsub
+++ b/drivers/gles2/shaders/SCsub
@@ -6,5 +6,3 @@ if env['BUILDERS'].has_key('GLSL120GLES'):
env.GLSL120GLES('canvas_shadow.glsl');
env.GLSL120GLES('blur.glsl');
env.GLSL120GLES('copy.glsl');
-
-
diff --git a/drivers/gles2/shaders/canvas.glsl b/drivers/gles2/shaders/canvas.glsl
index 669ae44621..285abd30ff 100644
--- a/drivers/gles2/shaders/canvas.glsl
+++ b/drivers/gles2/shaders/canvas.glsl
@@ -152,8 +152,10 @@ uniform vec4 modulate;
uniform sampler2D light_texture;
uniform vec4 light_color;
+uniform vec4 light_shadow_color;
uniform float light_height;
varying vec4 light_uv_interp;
+uniform float light_outside_alpha;
#if defined(NORMAL_USED)
varying vec4 local_rot;
@@ -194,7 +196,7 @@ void main() {
#ifdef USE_DISTANCE_FIELD
const float smoothing = 1.0/32.0;
float distance = texture2D(texture, uv_interp).a;
- color.a = smoothstep(0.5 - smoothing, 0.5 + smoothing, distance);
+ color.a = smoothstep(0.5 - smoothing, 0.5 + smoothing, distance) * color.a;
#else
color *= texture2D( texture, uv_interp );
@@ -246,22 +248,27 @@ FRAGMENT_SHADER_CODE
vec4 shadow_color=vec4(0.0,0.0,0.0,0.0);
#endif
+ if (any(lessThan(light_uv_interp.xy,vec2(0.0,0.0))) || any(greaterThanEqual(light_uv_interp.xy,vec2(1.0,1.0)))) {
+ color.a*=light_outside_alpha; //invisible
+
+ } else {
+
#if defined(USE_LIGHT_SHADER_CODE)
//light is written by the light shader
-{
- vec4 light_out=light*color;
+ {
+ vec4 light_out=light*color;
LIGHT_SHADER_CODE
- color=light_out;
-}
+ color=light_out;
+ }
#else
#if defined(NORMAL_USED)
- vec3 light_normal = normalize(vec3(light_vec,-light_height));
- light*=max(dot(-light_normal,normal),0.0);
+ vec3 light_normal = normalize(vec3(light_vec,-light_height));
+ light*=max(dot(-light_normal,normal),0.0);
#endif
- color*=light;
+ color*=light;
/*
#ifdef USE_NORMAL
color.xy=local_rot.xy;//normal.xy;
@@ -272,9 +279,6 @@ LIGHT_SHADER_CODE
//light shader code
#endif
- if (any(lessThan(light_uv_interp.xy,vec2(0.0,0.0))) || any(greaterThanEqual(light_uv_interp.xy,vec2(1.0,1.0)))) {
- color.a=0.0; //invisible
- } else {
#ifdef USE_SHADOWS
@@ -379,7 +383,8 @@ LIGHT_SHADER_CODE
#if defined(USE_LIGHT_SHADOW_COLOR)
color=mix(shadow_color,color,shadow_attenuation);
#else
- color*=shadow_attenuation;
+ //color*=shadow_attenuation;
+ color=mix(light_shadow_color,color,shadow_attenuation);
#endif
//use shadows
#endif
diff --git a/drivers/gles2/shaders/material.glsl b/drivers/gles2/shaders/material.glsl
index 38fb03ab5c..ccd80bf2f0 100644
--- a/drivers/gles2/shaders/material.glsl
+++ b/drivers/gles2/shaders/material.glsl
@@ -1175,6 +1175,10 @@ FRAGMENT_SHADER_CODE
vec3 mdiffuse = diffuse.rgb;
vec3 light;
+#if defined(USE_LIGHT_SHADOW_COLOR)
+ vec3 shadow_color=vec3(0.0,0.0,0.0);
+#endif
+
#if defined(USE_LIGHT_SHADER_CODE)
//light is written by the light shader
{
@@ -1195,6 +1199,10 @@ LIGHT_SHADER_CODE
#endif
diffuse.rgb = const_light_mult * ambient_light *diffuse.rgb + light * attenuation * shadow_attenuation;
+#if defined(USE_LIGHT_SHADOW_COLOR)
+ diffuse.rgb += light * shadow_color * attenuation * (1.0 - shadow_attenuation);
+#endif
+
#ifdef USE_FOG
diffuse.rgb = mix(diffuse.rgb,fog_interp.rgb,fog_interp.a);
diff --git a/drivers/jpegd/SCsub b/drivers/jpegd/SCsub
new file mode 100644
index 0000000000..dfdb19402e
--- /dev/null
+++ b/drivers/jpegd/SCsub
@@ -0,0 +1,11 @@
+Import('env')
+
+
+jpg_sources = [
+ "jpegd/jpgd.cpp",
+ "jpegd/image_loader_jpegd.cpp"
+ ]
+
+env.drivers_sources+=jpg_sources
+
+#env.add_source_files(env.drivers_sources, jpg_sources)
diff --git a/drivers/jpegd/image_loader_jpegd.cpp b/drivers/jpegd/image_loader_jpegd.cpp
new file mode 100644
index 0000000000..9d1263b81b
--- /dev/null
+++ b/drivers/jpegd/image_loader_jpegd.cpp
@@ -0,0 +1,108 @@
+/*************************************************/
+/* image_loader_jpg.cpp */
+/*************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/*************************************************/
+/* Source code within this file is: */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
+/* All Rights Reserved. */
+/*************************************************/
+
+#include "image_loader_jpegd.h"
+
+#include "print_string.h"
+#include "os/os.h"
+#include "jpgd.h"
+#include <string.h>
+
+
+Error ImageLoaderJPG::load_image(Image *p_image,FileAccess *f) {
+
+
+ DVector<uint8_t> src_image;
+ int src_image_len = f->get_len();
+ ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
+ src_image.resize(src_image_len);
+
+ DVector<uint8_t>::Write w = src_image.write();
+
+ f->get_buffer(&w[0],src_image_len);
+
+ f->close();
+
+
+
+ jpgd::jpeg_decoder_mem_stream mem_stream(w.ptr(),src_image_len);
+
+ jpgd::jpeg_decoder decoder(&mem_stream);
+
+ if (decoder.get_error_code() != jpgd::JPGD_SUCCESS) {
+ return ERR_CANT_OPEN;
+ }
+
+ const int image_width = decoder.get_width();
+ const int image_height = decoder.get_height();
+ int comps = decoder.get_num_components();
+ if (comps==3)
+ comps=4; //weird
+
+ if (decoder.begin_decoding() != jpgd::JPGD_SUCCESS)
+ return ERR_FILE_CORRUPT;
+
+ const int dst_bpl = image_width * comps;
+
+ DVector<uint8_t> data;
+
+ data.resize(dst_bpl * image_height);
+
+ DVector<uint8_t>::Write dw = data.write();
+
+ jpgd::uint8 *pImage_data = (jpgd::uint8*)dw.ptr();
+
+ for (int y = 0; y < image_height; y++)
+ {
+ const jpgd::uint8* pScan_line;
+ jpgd::uint scan_line_len;
+ if (decoder.decode((const void**)&pScan_line, &scan_line_len) != jpgd::JPGD_SUCCESS)
+ {
+ return ERR_FILE_CORRUPT;
+ }
+
+ jpgd::uint8 *pDst = pImage_data + y * dst_bpl;
+ memcpy(pDst, pScan_line, dst_bpl);
+
+
+ }
+
+
+ //all good
+
+ Image::Format fmt;
+ if (comps==1)
+ fmt=Image::FORMAT_GRAYSCALE;
+ else
+ fmt=Image::FORMAT_RGBA;
+
+ dw = DVector<uint8_t>::Write();
+ w = DVector<uint8_t>::Write();
+
+ p_image->create(image_width,image_height,0,fmt,data);
+
+ return OK;
+
+}
+
+void ImageLoaderJPG::get_recognized_extensions(List<String> *p_extensions) const {
+
+ p_extensions->push_back("jpg");
+ p_extensions->push_back("jpeg");
+}
+
+
+ImageLoaderJPG::ImageLoaderJPG() {
+
+
+}
+
+
diff --git a/drivers/jpegd/image_loader_jpegd.h b/drivers/jpegd/image_loader_jpegd.h
new file mode 100644
index 0000000000..1b2165ab47
--- /dev/null
+++ b/drivers/jpegd/image_loader_jpegd.h
@@ -0,0 +1,32 @@
+/*************************************************/
+/* image_loader_jpg.h */
+/*************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/*************************************************/
+/* Source code within this file is: */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
+/* All Rights Reserved. */
+/*************************************************/
+
+#ifndef IMAGE_LOADER_JPG_H
+#define IMAGE_LOADER_JPG_H
+
+#include "io/image_loader.h"
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+class ImageLoaderJPG : public ImageFormatLoader {
+
+
+public:
+
+ virtual Error load_image(Image *p_image,FileAccess *f);
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ ImageLoaderJPG();
+};
+
+
+
+#endif
diff --git a/drivers/jpegd/jpgd.cpp b/drivers/jpegd/jpgd.cpp
new file mode 100644
index 0000000000..fad9a37a9a
--- /dev/null
+++ b/drivers/jpegd/jpgd.cpp
@@ -0,0 +1,3172 @@
+// jpgd.cpp - C++ class for JPEG decompression.
+// Public domain, Rich Geldreich <richgel99@gmail.com>
+// Alex Evans: Linear memory allocator (taken from jpge.h).
+// v1.04, May. 19, 2012: Code tweaks to fix VS2008 static code analysis warnings (all looked harmless)
+//
+// Supports progressive and baseline sequential JPEG image files, and the most common chroma subsampling factors: Y, H1V1, H2V1, H1V2, and H2V2.
+//
+// Chroma upsampling quality: H2V2 is upsampled in the frequency domain, H2V1 and H1V2 are upsampled using point sampling.
+// Chroma upsampling reference: "Fast Scheme for Image Size Change in the Compressed Domain"
+// http://vision.ai.uiuc.edu/~dugad/research/dct/index.html
+
+#include "jpgd.h"
+#include <string.h>
+
+#include <assert.h>
+#define JPGD_ASSERT(x) assert(x)
+
+#ifdef _MSC_VER
+#pragma warning (disable : 4611) // warning C4611: interaction between '_setjmp' and C++ object destruction is non-portable
+#endif
+
+// Set to 1 to enable freq. domain chroma upsampling on images using H2V2 subsampling (0=faster nearest neighbor sampling).
+// This is slower, but results in higher quality on images with highly saturated colors.
+#define JPGD_SUPPORT_FREQ_DOMAIN_UPSAMPLING 1
+
+#define JPGD_TRUE (1)
+#define JPGD_FALSE (0)
+
+#define JPGD_MAX(a,b) (((a)>(b)) ? (a) : (b))
+#define JPGD_MIN(a,b) (((a)<(b)) ? (a) : (b))
+
+namespace jpgd {
+
+static inline void *jpgd_malloc(size_t nSize) { return malloc(nSize); }
+static inline void jpgd_free(void *p) { free(p); }
+
+// DCT coefficients are stored in this sequence.
+static int g_ZAG[64] = { 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 };
+
+enum JPEG_MARKER
+{
+ M_SOF0 = 0xC0, M_SOF1 = 0xC1, M_SOF2 = 0xC2, M_SOF3 = 0xC3, M_SOF5 = 0xC5, M_SOF6 = 0xC6, M_SOF7 = 0xC7, M_JPG = 0xC8,
+ M_SOF9 = 0xC9, M_SOF10 = 0xCA, M_SOF11 = 0xCB, M_SOF13 = 0xCD, M_SOF14 = 0xCE, M_SOF15 = 0xCF, M_DHT = 0xC4, M_DAC = 0xCC,
+ M_RST0 = 0xD0, M_RST1 = 0xD1, M_RST2 = 0xD2, M_RST3 = 0xD3, M_RST4 = 0xD4, M_RST5 = 0xD5, M_RST6 = 0xD6, M_RST7 = 0xD7,
+ M_SOI = 0xD8, M_EOI = 0xD9, M_SOS = 0xDA, M_DQT = 0xDB, M_DNL = 0xDC, M_DRI = 0xDD, M_DHP = 0xDE, M_EXP = 0xDF,
+ M_APP0 = 0xE0, M_APP15 = 0xEF, M_JPG0 = 0xF0, M_JPG13 = 0xFD, M_COM = 0xFE, M_TEM = 0x01, M_ERROR = 0x100, RST0 = 0xD0
+};
+
+enum JPEG_SUBSAMPLING { JPGD_GRAYSCALE = 0, JPGD_YH1V1, JPGD_YH2V1, JPGD_YH1V2, JPGD_YH2V2 };
+
+#define CONST_BITS 13
+#define PASS1_BITS 2
+#define SCALEDONE ((int32)1)
+
+#define FIX_0_298631336 ((int32)2446) /* FIX(0.298631336) */
+#define FIX_0_390180644 ((int32)3196) /* FIX(0.390180644) */
+#define FIX_0_541196100 ((int32)4433) /* FIX(0.541196100) */
+#define FIX_0_765366865 ((int32)6270) /* FIX(0.765366865) */
+#define FIX_0_899976223 ((int32)7373) /* FIX(0.899976223) */
+#define FIX_1_175875602 ((int32)9633) /* FIX(1.175875602) */
+#define FIX_1_501321110 ((int32)12299) /* FIX(1.501321110) */
+#define FIX_1_847759065 ((int32)15137) /* FIX(1.847759065) */
+#define FIX_1_961570560 ((int32)16069) /* FIX(1.961570560) */
+#define FIX_2_053119869 ((int32)16819) /* FIX(2.053119869) */
+#define FIX_2_562915447 ((int32)20995) /* FIX(2.562915447) */
+#define FIX_3_072711026 ((int32)25172) /* FIX(3.072711026) */
+
+#define DESCALE(x,n) (((x) + (SCALEDONE << ((n)-1))) >> (n))
+#define DESCALE_ZEROSHIFT(x,n) (((x) + (128 << (n)) + (SCALEDONE << ((n)-1))) >> (n))
+
+#define MULTIPLY(var, cnst) ((var) * (cnst))
+
+#define CLAMP(i) ((static_cast<uint>(i) > 255) ? (((~i) >> 31) & 0xFF) : (i))
+
+// Compiler creates a fast path 1D IDCT for X non-zero columns
+template <int NONZERO_COLS>
+struct Row
+{
+ static void idct(int* pTemp, const jpgd_block_t* pSrc)
+ {
+ // ACCESS_COL() will be optimized at compile time to either an array access, or 0.
+ #define ACCESS_COL(x) (((x) < NONZERO_COLS) ? (int)pSrc[x] : 0)
+
+ const int z2 = ACCESS_COL(2), z3 = ACCESS_COL(6);
+
+ const int z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
+ const int tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065);
+ const int tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865);
+
+ const int tmp0 = (ACCESS_COL(0) + ACCESS_COL(4)) << CONST_BITS;
+ const int tmp1 = (ACCESS_COL(0) - ACCESS_COL(4)) << CONST_BITS;
+
+ const int tmp10 = tmp0 + tmp3, tmp13 = tmp0 - tmp3, tmp11 = tmp1 + tmp2, tmp12 = tmp1 - tmp2;
+
+ const int atmp0 = ACCESS_COL(7), atmp1 = ACCESS_COL(5), atmp2 = ACCESS_COL(3), atmp3 = ACCESS_COL(1);
+
+ const int bz1 = atmp0 + atmp3, bz2 = atmp1 + atmp2, bz3 = atmp0 + atmp2, bz4 = atmp1 + atmp3;
+ const int bz5 = MULTIPLY(bz3 + bz4, FIX_1_175875602);
+
+ const int az1 = MULTIPLY(bz1, - FIX_0_899976223);
+ const int az2 = MULTIPLY(bz2, - FIX_2_562915447);
+ const int az3 = MULTIPLY(bz3, - FIX_1_961570560) + bz5;
+ const int az4 = MULTIPLY(bz4, - FIX_0_390180644) + bz5;
+
+ const int btmp0 = MULTIPLY(atmp0, FIX_0_298631336) + az1 + az3;
+ const int btmp1 = MULTIPLY(atmp1, FIX_2_053119869) + az2 + az4;
+ const int btmp2 = MULTIPLY(atmp2, FIX_3_072711026) + az2 + az3;
+ const int btmp3 = MULTIPLY(atmp3, FIX_1_501321110) + az1 + az4;
+
+ pTemp[0] = DESCALE(tmp10 + btmp3, CONST_BITS-PASS1_BITS);
+ pTemp[7] = DESCALE(tmp10 - btmp3, CONST_BITS-PASS1_BITS);
+ pTemp[1] = DESCALE(tmp11 + btmp2, CONST_BITS-PASS1_BITS);
+ pTemp[6] = DESCALE(tmp11 - btmp2, CONST_BITS-PASS1_BITS);
+ pTemp[2] = DESCALE(tmp12 + btmp1, CONST_BITS-PASS1_BITS);
+ pTemp[5] = DESCALE(tmp12 - btmp1, CONST_BITS-PASS1_BITS);
+ pTemp[3] = DESCALE(tmp13 + btmp0, CONST_BITS-PASS1_BITS);
+ pTemp[4] = DESCALE(tmp13 - btmp0, CONST_BITS-PASS1_BITS);
+ }
+};
+
+template <>
+struct Row<0>
+{
+ static void idct(int* pTemp, const jpgd_block_t* pSrc)
+ {
+#ifdef _MSC_VER
+ pTemp; pSrc;
+#endif
+ }
+};
+
+template <>
+struct Row<1>
+{
+ static void idct(int* pTemp, const jpgd_block_t* pSrc)
+ {
+ const int dcval = (pSrc[0] << PASS1_BITS);
+
+ pTemp[0] = dcval;
+ pTemp[1] = dcval;
+ pTemp[2] = dcval;
+ pTemp[3] = dcval;
+ pTemp[4] = dcval;
+ pTemp[5] = dcval;
+ pTemp[6] = dcval;
+ pTemp[7] = dcval;
+ }
+};
+
+// Compiler creates a fast path 1D IDCT for X non-zero rows
+template <int NONZERO_ROWS>
+struct Col
+{
+ static void idct(uint8* pDst_ptr, const int* pTemp)
+ {
+ // ACCESS_ROW() will be optimized at compile time to either an array access, or 0.
+ #define ACCESS_ROW(x) (((x) < NONZERO_ROWS) ? pTemp[x * 8] : 0)
+
+ const int z2 = ACCESS_ROW(2);
+ const int z3 = ACCESS_ROW(6);
+
+ const int z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
+ const int tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065);
+ const int tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865);
+
+ const int tmp0 = (ACCESS_ROW(0) + ACCESS_ROW(4)) << CONST_BITS;
+ const int tmp1 = (ACCESS_ROW(0) - ACCESS_ROW(4)) << CONST_BITS;
+
+ const int tmp10 = tmp0 + tmp3, tmp13 = tmp0 - tmp3, tmp11 = tmp1 + tmp2, tmp12 = tmp1 - tmp2;
+
+ const int atmp0 = ACCESS_ROW(7), atmp1 = ACCESS_ROW(5), atmp2 = ACCESS_ROW(3), atmp3 = ACCESS_ROW(1);
+
+ const int bz1 = atmp0 + atmp3, bz2 = atmp1 + atmp2, bz3 = atmp0 + atmp2, bz4 = atmp1 + atmp3;
+ const int bz5 = MULTIPLY(bz3 + bz4, FIX_1_175875602);
+
+ const int az1 = MULTIPLY(bz1, - FIX_0_899976223);
+ const int az2 = MULTIPLY(bz2, - FIX_2_562915447);
+ const int az3 = MULTIPLY(bz3, - FIX_1_961570560) + bz5;
+ const int az4 = MULTIPLY(bz4, - FIX_0_390180644) + bz5;
+
+ const int btmp0 = MULTIPLY(atmp0, FIX_0_298631336) + az1 + az3;
+ const int btmp1 = MULTIPLY(atmp1, FIX_2_053119869) + az2 + az4;
+ const int btmp2 = MULTIPLY(atmp2, FIX_3_072711026) + az2 + az3;
+ const int btmp3 = MULTIPLY(atmp3, FIX_1_501321110) + az1 + az4;
+
+ int i = DESCALE_ZEROSHIFT(tmp10 + btmp3, CONST_BITS+PASS1_BITS+3);
+ pDst_ptr[8*0] = (uint8)CLAMP(i);
+
+ i = DESCALE_ZEROSHIFT(tmp10 - btmp3, CONST_BITS+PASS1_BITS+3);
+ pDst_ptr[8*7] = (uint8)CLAMP(i);
+
+ i = DESCALE_ZEROSHIFT(tmp11 + btmp2, CONST_BITS+PASS1_BITS+3);
+ pDst_ptr[8*1] = (uint8)CLAMP(i);
+
+ i = DESCALE_ZEROSHIFT(tmp11 - btmp2, CONST_BITS+PASS1_BITS+3);
+ pDst_ptr[8*6] = (uint8)CLAMP(i);
+
+ i = DESCALE_ZEROSHIFT(tmp12 + btmp1, CONST_BITS+PASS1_BITS+3);
+ pDst_ptr[8*2] = (uint8)CLAMP(i);
+
+ i = DESCALE_ZEROSHIFT(tmp12 - btmp1, CONST_BITS+PASS1_BITS+3);
+ pDst_ptr[8*5] = (uint8)CLAMP(i);
+
+ i = DESCALE_ZEROSHIFT(tmp13 + btmp0, CONST_BITS+PASS1_BITS+3);
+ pDst_ptr[8*3] = (uint8)CLAMP(i);
+
+ i = DESCALE_ZEROSHIFT(tmp13 - btmp0, CONST_BITS+PASS1_BITS+3);
+ pDst_ptr[8*4] = (uint8)CLAMP(i);
+ }
+};
+
+template <>
+struct Col<1>
+{
+ static void idct(uint8* pDst_ptr, const int* pTemp)
+ {
+ int dcval = DESCALE_ZEROSHIFT(pTemp[0], PASS1_BITS+3);
+ const uint8 dcval_clamped = (uint8)CLAMP(dcval);
+ pDst_ptr[0*8] = dcval_clamped;
+ pDst_ptr[1*8] = dcval_clamped;
+ pDst_ptr[2*8] = dcval_clamped;
+ pDst_ptr[3*8] = dcval_clamped;
+ pDst_ptr[4*8] = dcval_clamped;
+ pDst_ptr[5*8] = dcval_clamped;
+ pDst_ptr[6*8] = dcval_clamped;
+ pDst_ptr[7*8] = dcval_clamped;
+ }
+};
+
+static const uint8 s_idct_row_table[] =
+{
+ 1,0,0,0,0,0,0,0, 2,0,0,0,0,0,0,0, 2,1,0,0,0,0,0,0, 2,1,1,0,0,0,0,0, 2,2,1,0,0,0,0,0, 3,2,1,0,0,0,0,0, 4,2,1,0,0,0,0,0, 4,3,1,0,0,0,0,0,
+ 4,3,2,0,0,0,0,0, 4,3,2,1,0,0,0,0, 4,3,2,1,1,0,0,0, 4,3,2,2,1,0,0,0, 4,3,3,2,1,0,0,0, 4,4,3,2,1,0,0,0, 5,4,3,2,1,0,0,0, 6,4,3,2,1,0,0,0,
+ 6,5,3,2,1,0,0,0, 6,5,4,2,1,0,0,0, 6,5,4,3,1,0,0,0, 6,5,4,3,2,0,0,0, 6,5,4,3,2,1,0,0, 6,5,4,3,2,1,1,0, 6,5,4,3,2,2,1,0, 6,5,4,3,3,2,1,0,
+ 6,5,4,4,3,2,1,0, 6,5,5,4,3,2,1,0, 6,6,5,4,3,2,1,0, 7,6,5,4,3,2,1,0, 8,6,5,4,3,2,1,0, 8,7,5,4,3,2,1,0, 8,7,6,4,3,2,1,0, 8,7,6,5,3,2,1,0,
+ 8,7,6,5,4,2,1,0, 8,7,6,5,4,3,1,0, 8,7,6,5,4,3,2,0, 8,7,6,5,4,3,2,1, 8,7,6,5,4,3,2,2, 8,7,6,5,4,3,3,2, 8,7,6,5,4,4,3,2, 8,7,6,5,5,4,3,2,
+ 8,7,6,6,5,4,3,2, 8,7,7,6,5,4,3,2, 8,8,7,6,5,4,3,2, 8,8,8,6,5,4,3,2, 8,8,8,7,5,4,3,2, 8,8,8,7,6,4,3,2, 8,8,8,7,6,5,3,2, 8,8,8,7,6,5,4,2,
+ 8,8,8,7,6,5,4,3, 8,8,8,7,6,5,4,4, 8,8,8,7,6,5,5,4, 8,8,8,7,6,6,5,4, 8,8,8,7,7,6,5,4, 8,8,8,8,7,6,5,4, 8,8,8,8,8,6,5,4, 8,8,8,8,8,7,5,4,
+ 8,8,8,8,8,7,6,4, 8,8,8,8,8,7,6,5, 8,8,8,8,8,7,6,6, 8,8,8,8,8,7,7,6, 8,8,8,8,8,8,7,6, 8,8,8,8,8,8,8,6, 8,8,8,8,8,8,8,7, 8,8,8,8,8,8,8,8,
+};
+
+static const uint8 s_idct_col_table[] = { 1, 1, 2, 3, 3, 3, 3, 3, 3, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 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 };
+
+void idct(const jpgd_block_t* pSrc_ptr, uint8* pDst_ptr, int block_max_zag)
+{
+ JPGD_ASSERT(block_max_zag >= 1);
+ JPGD_ASSERT(block_max_zag <= 64);
+
+ if (block_max_zag <= 1)
+ {
+ int k = ((pSrc_ptr[0] + 4) >> 3) + 128;
+ k = CLAMP(k);
+ k = k | (k<<8);
+ k = k | (k<<16);
+
+ for (int i = 8; i > 0; i--)
+ {
+ *(int*)&pDst_ptr[0] = k;
+ *(int*)&pDst_ptr[4] = k;
+ pDst_ptr += 8;
+ }
+ return;
+ }
+
+ int temp[64];
+
+ const jpgd_block_t* pSrc = pSrc_ptr;
+ int* pTemp = temp;
+
+ const uint8* pRow_tab = &s_idct_row_table[(block_max_zag - 1) * 8];
+ int i;
+ for (i = 8; i > 0; i--, pRow_tab++)
+ {
+ switch (*pRow_tab)
+ {
+ case 0: Row<0>::idct(pTemp, pSrc); break;
+ case 1: Row<1>::idct(pTemp, pSrc); break;
+ case 2: Row<2>::idct(pTemp, pSrc); break;
+ case 3: Row<3>::idct(pTemp, pSrc); break;
+ case 4: Row<4>::idct(pTemp, pSrc); break;
+ case 5: Row<5>::idct(pTemp, pSrc); break;
+ case 6: Row<6>::idct(pTemp, pSrc); break;
+ case 7: Row<7>::idct(pTemp, pSrc); break;
+ case 8: Row<8>::idct(pTemp, pSrc); break;
+ }
+
+ pSrc += 8;
+ pTemp += 8;
+ }
+
+ pTemp = temp;
+
+ const int nonzero_rows = s_idct_col_table[block_max_zag - 1];
+ for (i = 8; i > 0; i--)
+ {
+ switch (nonzero_rows)
+ {
+ case 1: Col<1>::idct(pDst_ptr, pTemp); break;
+ case 2: Col<2>::idct(pDst_ptr, pTemp); break;
+ case 3: Col<3>::idct(pDst_ptr, pTemp); break;
+ case 4: Col<4>::idct(pDst_ptr, pTemp); break;
+ case 5: Col<5>::idct(pDst_ptr, pTemp); break;
+ case 6: Col<6>::idct(pDst_ptr, pTemp); break;
+ case 7: Col<7>::idct(pDst_ptr, pTemp); break;
+ case 8: Col<8>::idct(pDst_ptr, pTemp); break;
+ }
+
+ pTemp++;
+ pDst_ptr++;
+ }
+}
+
+void idct_4x4(const jpgd_block_t* pSrc_ptr, uint8* pDst_ptr)
+{
+ int temp[64];
+ int* pTemp = temp;
+ const jpgd_block_t* pSrc = pSrc_ptr;
+
+ for (int i = 4; i > 0; i--)
+ {
+ Row<4>::idct(pTemp, pSrc);
+ pSrc += 8;
+ pTemp += 8;
+ }
+
+ pTemp = temp;
+ for (int i = 8; i > 0; i--)
+ {
+ Col<4>::idct(pDst_ptr, pTemp);
+ pTemp++;
+ pDst_ptr++;
+ }
+}
+
+// Retrieve one character from the input stream.
+inline uint jpeg_decoder::get_char()
+{
+ // Any bytes remaining in buffer?
+ if (!m_in_buf_left)
+ {
+ // Try to get more bytes.
+ prep_in_buffer();
+ // Still nothing to get?
+ if (!m_in_buf_left)
+ {
+ // Pad the end of the stream with 0xFF 0xD9 (EOI marker)
+ int t = m_tem_flag;
+ m_tem_flag ^= 1;
+ if (t)
+ return 0xD9;
+ else
+ return 0xFF;
+ }
+ }
+
+ uint c = *m_pIn_buf_ofs++;
+ m_in_buf_left--;
+
+ return c;
+}
+
+// Same as previous method, except can indicate if the character is a pad character or not.
+inline uint jpeg_decoder::get_char(bool *pPadding_flag)
+{
+ if (!m_in_buf_left)
+ {
+ prep_in_buffer();
+ if (!m_in_buf_left)
+ {
+ *pPadding_flag = true;
+ int t = m_tem_flag;
+ m_tem_flag ^= 1;
+ if (t)
+ return 0xD9;
+ else
+ return 0xFF;
+ }
+ }
+
+ *pPadding_flag = false;
+
+ uint c = *m_pIn_buf_ofs++;
+ m_in_buf_left--;
+
+ return c;
+}
+
+// Inserts a previously retrieved character back into the input buffer.
+inline void jpeg_decoder::stuff_char(uint8 q)
+{
+ *(--m_pIn_buf_ofs) = q;
+ m_in_buf_left++;
+}
+
+// Retrieves one character from the input stream, but does not read past markers. Will continue to return 0xFF when a marker is encountered.
+inline uint8 jpeg_decoder::get_octet()
+{
+ bool padding_flag;
+ int c = get_char(&padding_flag);
+
+ if (c == 0xFF)
+ {
+ if (padding_flag)
+ return 0xFF;
+
+ c = get_char(&padding_flag);
+ if (padding_flag)
+ {
+ stuff_char(0xFF);
+ return 0xFF;
+ }
+
+ if (c == 0x00)
+ return 0xFF;
+ else
+ {
+ stuff_char(static_cast<uint8>(c));
+ stuff_char(0xFF);
+ return 0xFF;
+ }
+ }
+
+ return static_cast<uint8>(c);
+}
+
+// Retrieves a variable number of bits from the input stream. Does not recognize markers.
+inline uint jpeg_decoder::get_bits(int num_bits)
+{
+ if (!num_bits)
+ return 0;
+
+ uint i = m_bit_buf >> (32 - num_bits);
+
+ if ((m_bits_left -= num_bits) <= 0)
+ {
+ m_bit_buf <<= (num_bits += m_bits_left);
+
+ uint c1 = get_char();
+ uint c2 = get_char();
+ m_bit_buf = (m_bit_buf & 0xFFFF0000) | (c1 << 8) | c2;
+
+ m_bit_buf <<= -m_bits_left;
+
+ m_bits_left += 16;
+
+ JPGD_ASSERT(m_bits_left >= 0);
+ }
+ else
+ m_bit_buf <<= num_bits;
+
+ return i;
+}
+
+// Retrieves a variable number of bits from the input stream. Markers will not be read into the input bit buffer. Instead, an infinite number of all 1's will be returned when a marker is encountered.
+inline uint jpeg_decoder::get_bits_no_markers(int num_bits)
+{
+ if (!num_bits)
+ return 0;
+
+ uint i = m_bit_buf >> (32 - num_bits);
+
+ if ((m_bits_left -= num_bits) <= 0)
+ {
+ m_bit_buf <<= (num_bits += m_bits_left);
+
+ if ((m_in_buf_left < 2) || (m_pIn_buf_ofs[0] == 0xFF) || (m_pIn_buf_ofs[1] == 0xFF))
+ {
+ uint c1 = get_octet();
+ uint c2 = get_octet();
+ m_bit_buf |= (c1 << 8) | c2;
+ }
+ else
+ {
+ m_bit_buf |= ((uint)m_pIn_buf_ofs[0] << 8) | m_pIn_buf_ofs[1];
+ m_in_buf_left -= 2;
+ m_pIn_buf_ofs += 2;
+ }
+
+ m_bit_buf <<= -m_bits_left;
+
+ m_bits_left += 16;
+
+ JPGD_ASSERT(m_bits_left >= 0);
+ }
+ else
+ m_bit_buf <<= num_bits;
+
+ return i;
+}
+
+// Decodes a Huffman encoded symbol.
+inline int jpeg_decoder::huff_decode(huff_tables *pH)
+{
+ int symbol;
+
+ // Check first 8-bits: do we have a complete symbol?
+ if ((symbol = pH->look_up[m_bit_buf >> 24]) < 0)
+ {
+ // Decode more bits, use a tree traversal to find symbol.
+ int ofs = 23;
+ do
+ {
+ symbol = pH->tree[-(int)(symbol + ((m_bit_buf >> ofs) & 1))];
+ ofs--;
+ } while (symbol < 0);
+
+ get_bits_no_markers(8 + (23 - ofs));
+ }
+ else
+ get_bits_no_markers(pH->code_size[symbol]);
+
+ return symbol;
+}
+
+// Decodes a Huffman encoded symbol.
+inline int jpeg_decoder::huff_decode(huff_tables *pH, int& extra_bits)
+{
+ int symbol;
+
+ // Check first 8-bits: do we have a complete symbol?
+ if ((symbol = pH->look_up2[m_bit_buf >> 24]) < 0)
+ {
+ // Use a tree traversal to find symbol.
+ int ofs = 23;
+ do
+ {
+ symbol = pH->tree[-(int)(symbol + ((m_bit_buf >> ofs) & 1))];
+ ofs--;
+ } while (symbol < 0);
+
+ get_bits_no_markers(8 + (23 - ofs));
+
+ extra_bits = get_bits_no_markers(symbol & 0xF);
+ }
+ else
+ {
+ JPGD_ASSERT(((symbol >> 8) & 31) == pH->code_size[symbol & 255] + ((symbol & 0x8000) ? (symbol & 15) : 0));
+
+ if (symbol & 0x8000)
+ {
+ get_bits_no_markers((symbol >> 8) & 31);
+ extra_bits = symbol >> 16;
+ }
+ else
+ {
+ int code_size = (symbol >> 8) & 31;
+ int num_extra_bits = symbol & 0xF;
+ int bits = code_size + num_extra_bits;
+ if (bits <= (m_bits_left + 16))
+ extra_bits = get_bits_no_markers(bits) & ((1 << num_extra_bits) - 1);
+ else
+ {
+ get_bits_no_markers(code_size);
+ extra_bits = get_bits_no_markers(num_extra_bits);
+ }
+ }
+
+ symbol &= 0xFF;
+ }
+
+ return symbol;
+}
+
+// Tables and macro used to fully decode the DPCM differences.
+static const int s_extend_test[16] = { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 };
+static const int s_extend_offset[16] = { 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1, ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1, ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1, ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 };
+static const int s_extend_mask[] = { 0, (1<<0), (1<<1), (1<<2), (1<<3), (1<<4), (1<<5), (1<<6), (1<<7), (1<<8), (1<<9), (1<<10), (1<<11), (1<<12), (1<<13), (1<<14), (1<<15), (1<<16) };
+// The logical AND's in this macro are to shut up static code analysis (aren't really necessary - couldn't find another way to do this)
+#define JPGD_HUFF_EXTEND(x, s) (((x) < s_extend_test[s & 15]) ? ((x) + s_extend_offset[s & 15]) : (x))
+
+// Clamps a value between 0-255.
+inline uint8 jpeg_decoder::clamp(int i)
+{
+ if (static_cast<uint>(i) > 255)
+ i = (((~i) >> 31) & 0xFF);
+
+ return static_cast<uint8>(i);
+}
+
+namespace DCT_Upsample
+{
+ struct Matrix44
+ {
+ typedef int Element_Type;
+ enum { NUM_ROWS = 4, NUM_COLS = 4 };
+
+ Element_Type v[NUM_ROWS][NUM_COLS];
+
+ inline int rows() const { return NUM_ROWS; }
+ inline int cols() const { return NUM_COLS; }
+
+ inline const Element_Type & at(int r, int c) const { return v[r][c]; }
+ inline Element_Type & at(int r, int c) { return v[r][c]; }
+
+ inline Matrix44() { }
+
+ inline Matrix44& operator += (const Matrix44& a)
+ {
+ for (int r = 0; r < NUM_ROWS; r++)
+ {
+ at(r, 0) += a.at(r, 0);
+ at(r, 1) += a.at(r, 1);
+ at(r, 2) += a.at(r, 2);
+ at(r, 3) += a.at(r, 3);
+ }
+ return *this;
+ }
+
+ inline Matrix44& operator -= (const Matrix44& a)
+ {
+ for (int r = 0; r < NUM_ROWS; r++)
+ {
+ at(r, 0) -= a.at(r, 0);
+ at(r, 1) -= a.at(r, 1);
+ at(r, 2) -= a.at(r, 2);
+ at(r, 3) -= a.at(r, 3);
+ }
+ return *this;
+ }
+
+ friend inline Matrix44 operator + (const Matrix44& a, const Matrix44& b)
+ {
+ Matrix44 ret;
+ for (int r = 0; r < NUM_ROWS; r++)
+ {
+ ret.at(r, 0) = a.at(r, 0) + b.at(r, 0);
+ ret.at(r, 1) = a.at(r, 1) + b.at(r, 1);
+ ret.at(r, 2) = a.at(r, 2) + b.at(r, 2);
+ ret.at(r, 3) = a.at(r, 3) + b.at(r, 3);
+ }
+ return ret;
+ }
+
+ friend inline Matrix44 operator - (const Matrix44& a, const Matrix44& b)
+ {
+ Matrix44 ret;
+ for (int r = 0; r < NUM_ROWS; r++)
+ {
+ ret.at(r, 0) = a.at(r, 0) - b.at(r, 0);
+ ret.at(r, 1) = a.at(r, 1) - b.at(r, 1);
+ ret.at(r, 2) = a.at(r, 2) - b.at(r, 2);
+ ret.at(r, 3) = a.at(r, 3) - b.at(r, 3);
+ }
+ return ret;
+ }
+
+ static inline void add_and_store(jpgd_block_t* pDst, const Matrix44& a, const Matrix44& b)
+ {
+ for (int r = 0; r < 4; r++)
+ {
+ pDst[0*8 + r] = static_cast<jpgd_block_t>(a.at(r, 0) + b.at(r, 0));
+ pDst[1*8 + r] = static_cast<jpgd_block_t>(a.at(r, 1) + b.at(r, 1));
+ pDst[2*8 + r] = static_cast<jpgd_block_t>(a.at(r, 2) + b.at(r, 2));
+ pDst[3*8 + r] = static_cast<jpgd_block_t>(a.at(r, 3) + b.at(r, 3));
+ }
+ }
+
+ static inline void sub_and_store(jpgd_block_t* pDst, const Matrix44& a, const Matrix44& b)
+ {
+ for (int r = 0; r < 4; r++)
+ {
+ pDst[0*8 + r] = static_cast<jpgd_block_t>(a.at(r, 0) - b.at(r, 0));
+ pDst[1*8 + r] = static_cast<jpgd_block_t>(a.at(r, 1) - b.at(r, 1));
+ pDst[2*8 + r] = static_cast<jpgd_block_t>(a.at(r, 2) - b.at(r, 2));
+ pDst[3*8 + r] = static_cast<jpgd_block_t>(a.at(r, 3) - b.at(r, 3));
+ }
+ }
+ };
+
+ const int FRACT_BITS = 10;
+ const int SCALE = 1 << FRACT_BITS;
+
+ typedef int Temp_Type;
+ #define D(i) (((i) + (SCALE >> 1)) >> FRACT_BITS)
+ #define F(i) ((int)((i) * SCALE + .5f))
+
+ // Any decent C++ compiler will optimize this at compile time to a 0, or an array access.
+ #define AT(c, r) ((((c)>=NUM_COLS)||((r)>=NUM_ROWS)) ? 0 : pSrc[(c)+(r)*8])
+
+ // NUM_ROWS/NUM_COLS = # of non-zero rows/cols in input matrix
+ template<int NUM_ROWS, int NUM_COLS>
+ struct P_Q
+ {
+ static void calc(Matrix44& P, Matrix44& Q, const jpgd_block_t* pSrc)
+ {
+ // 4x8 = 4x8 times 8x8, matrix 0 is constant
+ const Temp_Type X000 = AT(0, 0);
+ const Temp_Type X001 = AT(0, 1);
+ const Temp_Type X002 = AT(0, 2);
+ const Temp_Type X003 = AT(0, 3);
+ const Temp_Type X004 = AT(0, 4);
+ const Temp_Type X005 = AT(0, 5);
+ const Temp_Type X006 = AT(0, 6);
+ const Temp_Type X007 = AT(0, 7);
+ const Temp_Type X010 = D(F(0.415735f) * AT(1, 0) + F(0.791065f) * AT(3, 0) + F(-0.352443f) * AT(5, 0) + F(0.277785f) * AT(7, 0));
+ const Temp_Type X011 = D(F(0.415735f) * AT(1, 1) + F(0.791065f) * AT(3, 1) + F(-0.352443f) * AT(5, 1) + F(0.277785f) * AT(7, 1));
+ const Temp_Type X012 = D(F(0.415735f) * AT(1, 2) + F(0.791065f) * AT(3, 2) + F(-0.352443f) * AT(5, 2) + F(0.277785f) * AT(7, 2));
+ const Temp_Type X013 = D(F(0.415735f) * AT(1, 3) + F(0.791065f) * AT(3, 3) + F(-0.352443f) * AT(5, 3) + F(0.277785f) * AT(7, 3));
+ const Temp_Type X014 = D(F(0.415735f) * AT(1, 4) + F(0.791065f) * AT(3, 4) + F(-0.352443f) * AT(5, 4) + F(0.277785f) * AT(7, 4));
+ const Temp_Type X015 = D(F(0.415735f) * AT(1, 5) + F(0.791065f) * AT(3, 5) + F(-0.352443f) * AT(5, 5) + F(0.277785f) * AT(7, 5));
+ const Temp_Type X016 = D(F(0.415735f) * AT(1, 6) + F(0.791065f) * AT(3, 6) + F(-0.352443f) * AT(5, 6) + F(0.277785f) * AT(7, 6));
+ const Temp_Type X017 = D(F(0.415735f) * AT(1, 7) + F(0.791065f) * AT(3, 7) + F(-0.352443f) * AT(5, 7) + F(0.277785f) * AT(7, 7));
+ const Temp_Type X020 = AT(4, 0);
+ const Temp_Type X021 = AT(4, 1);
+ const Temp_Type X022 = AT(4, 2);
+ const Temp_Type X023 = AT(4, 3);
+ const Temp_Type X024 = AT(4, 4);
+ const Temp_Type X025 = AT(4, 5);
+ const Temp_Type X026 = AT(4, 6);
+ const Temp_Type X027 = AT(4, 7);
+ const Temp_Type X030 = D(F(0.022887f) * AT(1, 0) + F(-0.097545f) * AT(3, 0) + F(0.490393f) * AT(5, 0) + F(0.865723f) * AT(7, 0));
+ const Temp_Type X031 = D(F(0.022887f) * AT(1, 1) + F(-0.097545f) * AT(3, 1) + F(0.490393f) * AT(5, 1) + F(0.865723f) * AT(7, 1));
+ const Temp_Type X032 = D(F(0.022887f) * AT(1, 2) + F(-0.097545f) * AT(3, 2) + F(0.490393f) * AT(5, 2) + F(0.865723f) * AT(7, 2));
+ const Temp_Type X033 = D(F(0.022887f) * AT(1, 3) + F(-0.097545f) * AT(3, 3) + F(0.490393f) * AT(5, 3) + F(0.865723f) * AT(7, 3));
+ const Temp_Type X034 = D(F(0.022887f) * AT(1, 4) + F(-0.097545f) * AT(3, 4) + F(0.490393f) * AT(5, 4) + F(0.865723f) * AT(7, 4));
+ const Temp_Type X035 = D(F(0.022887f) * AT(1, 5) + F(-0.097545f) * AT(3, 5) + F(0.490393f) * AT(5, 5) + F(0.865723f) * AT(7, 5));
+ const Temp_Type X036 = D(F(0.022887f) * AT(1, 6) + F(-0.097545f) * AT(3, 6) + F(0.490393f) * AT(5, 6) + F(0.865723f) * AT(7, 6));
+ const Temp_Type X037 = D(F(0.022887f) * AT(1, 7) + F(-0.097545f) * AT(3, 7) + F(0.490393f) * AT(5, 7) + F(0.865723f) * AT(7, 7));
+
+ // 4x4 = 4x8 times 8x4, matrix 1 is constant
+ P.at(0, 0) = X000;
+ P.at(0, 1) = D(X001 * F(0.415735f) + X003 * F(0.791065f) + X005 * F(-0.352443f) + X007 * F(0.277785f));
+ P.at(0, 2) = X004;
+ P.at(0, 3) = D(X001 * F(0.022887f) + X003 * F(-0.097545f) + X005 * F(0.490393f) + X007 * F(0.865723f));
+ P.at(1, 0) = X010;
+ P.at(1, 1) = D(X011 * F(0.415735f) + X013 * F(0.791065f) + X015 * F(-0.352443f) + X017 * F(0.277785f));
+ P.at(1, 2) = X014;
+ P.at(1, 3) = D(X011 * F(0.022887f) + X013 * F(-0.097545f) + X015 * F(0.490393f) + X017 * F(0.865723f));
+ P.at(2, 0) = X020;
+ P.at(2, 1) = D(X021 * F(0.415735f) + X023 * F(0.791065f) + X025 * F(-0.352443f) + X027 * F(0.277785f));
+ P.at(2, 2) = X024;
+ P.at(2, 3) = D(X021 * F(0.022887f) + X023 * F(-0.097545f) + X025 * F(0.490393f) + X027 * F(0.865723f));
+ P.at(3, 0) = X030;
+ P.at(3, 1) = D(X031 * F(0.415735f) + X033 * F(0.791065f) + X035 * F(-0.352443f) + X037 * F(0.277785f));
+ P.at(3, 2) = X034;
+ P.at(3, 3) = D(X031 * F(0.022887f) + X033 * F(-0.097545f) + X035 * F(0.490393f) + X037 * F(0.865723f));
+ // 40 muls 24 adds
+
+ // 4x4 = 4x8 times 8x4, matrix 1 is constant
+ Q.at(0, 0) = D(X001 * F(0.906127f) + X003 * F(-0.318190f) + X005 * F(0.212608f) + X007 * F(-0.180240f));
+ Q.at(0, 1) = X002;
+ Q.at(0, 2) = D(X001 * F(-0.074658f) + X003 * F(0.513280f) + X005 * F(0.768178f) + X007 * F(-0.375330f));
+ Q.at(0, 3) = X006;
+ Q.at(1, 0) = D(X011 * F(0.906127f) + X013 * F(-0.318190f) + X015 * F(0.212608f) + X017 * F(-0.180240f));
+ Q.at(1, 1) = X012;
+ Q.at(1, 2) = D(X011 * F(-0.074658f) + X013 * F(0.513280f) + X015 * F(0.768178f) + X017 * F(-0.375330f));
+ Q.at(1, 3) = X016;
+ Q.at(2, 0) = D(X021 * F(0.906127f) + X023 * F(-0.318190f) + X025 * F(0.212608f) + X027 * F(-0.180240f));
+ Q.at(2, 1) = X022;
+ Q.at(2, 2) = D(X021 * F(-0.074658f) + X023 * F(0.513280f) + X025 * F(0.768178f) + X027 * F(-0.375330f));
+ Q.at(2, 3) = X026;
+ Q.at(3, 0) = D(X031 * F(0.906127f) + X033 * F(-0.318190f) + X035 * F(0.212608f) + X037 * F(-0.180240f));
+ Q.at(3, 1) = X032;
+ Q.at(3, 2) = D(X031 * F(-0.074658f) + X033 * F(0.513280f) + X035 * F(0.768178f) + X037 * F(-0.375330f));
+ Q.at(3, 3) = X036;
+ // 40 muls 24 adds
+ }
+ };
+
+ template<int NUM_ROWS, int NUM_COLS>
+ struct R_S
+ {
+ static void calc(Matrix44& R, Matrix44& S, const jpgd_block_t* pSrc)
+ {
+ // 4x8 = 4x8 times 8x8, matrix 0 is constant
+ const Temp_Type X100 = D(F(0.906127f) * AT(1, 0) + F(-0.318190f) * AT(3, 0) + F(0.212608f) * AT(5, 0) + F(-0.180240f) * AT(7, 0));
+ const Temp_Type X101 = D(F(0.906127f) * AT(1, 1) + F(-0.318190f) * AT(3, 1) + F(0.212608f) * AT(5, 1) + F(-0.180240f) * AT(7, 1));
+ const Temp_Type X102 = D(F(0.906127f) * AT(1, 2) + F(-0.318190f) * AT(3, 2) + F(0.212608f) * AT(5, 2) + F(-0.180240f) * AT(7, 2));
+ const Temp_Type X103 = D(F(0.906127f) * AT(1, 3) + F(-0.318190f) * AT(3, 3) + F(0.212608f) * AT(5, 3) + F(-0.180240f) * AT(7, 3));
+ const Temp_Type X104 = D(F(0.906127f) * AT(1, 4) + F(-0.318190f) * AT(3, 4) + F(0.212608f) * AT(5, 4) + F(-0.180240f) * AT(7, 4));
+ const Temp_Type X105 = D(F(0.906127f) * AT(1, 5) + F(-0.318190f) * AT(3, 5) + F(0.212608f) * AT(5, 5) + F(-0.180240f) * AT(7, 5));
+ const Temp_Type X106 = D(F(0.906127f) * AT(1, 6) + F(-0.318190f) * AT(3, 6) + F(0.212608f) * AT(5, 6) + F(-0.180240f) * AT(7, 6));
+ const Temp_Type X107 = D(F(0.906127f) * AT(1, 7) + F(-0.318190f) * AT(3, 7) + F(0.212608f) * AT(5, 7) + F(-0.180240f) * AT(7, 7));
+ const Temp_Type X110 = AT(2, 0);
+ const Temp_Type X111 = AT(2, 1);
+ const Temp_Type X112 = AT(2, 2);
+ const Temp_Type X113 = AT(2, 3);
+ const Temp_Type X114 = AT(2, 4);
+ const Temp_Type X115 = AT(2, 5);
+ const Temp_Type X116 = AT(2, 6);
+ const Temp_Type X117 = AT(2, 7);
+ const Temp_Type X120 = D(F(-0.074658f) * AT(1, 0) + F(0.513280f) * AT(3, 0) + F(0.768178f) * AT(5, 0) + F(-0.375330f) * AT(7, 0));
+ const Temp_Type X121 = D(F(-0.074658f) * AT(1, 1) + F(0.513280f) * AT(3, 1) + F(0.768178f) * AT(5, 1) + F(-0.375330f) * AT(7, 1));
+ const Temp_Type X122 = D(F(-0.074658f) * AT(1, 2) + F(0.513280f) * AT(3, 2) + F(0.768178f) * AT(5, 2) + F(-0.375330f) * AT(7, 2));
+ const Temp_Type X123 = D(F(-0.074658f) * AT(1, 3) + F(0.513280f) * AT(3, 3) + F(0.768178f) * AT(5, 3) + F(-0.375330f) * AT(7, 3));
+ const Temp_Type X124 = D(F(-0.074658f) * AT(1, 4) + F(0.513280f) * AT(3, 4) + F(0.768178f) * AT(5, 4) + F(-0.375330f) * AT(7, 4));
+ const Temp_Type X125 = D(F(-0.074658f) * AT(1, 5) + F(0.513280f) * AT(3, 5) + F(0.768178f) * AT(5, 5) + F(-0.375330f) * AT(7, 5));
+ const Temp_Type X126 = D(F(-0.074658f) * AT(1, 6) + F(0.513280f) * AT(3, 6) + F(0.768178f) * AT(5, 6) + F(-0.375330f) * AT(7, 6));
+ const Temp_Type X127 = D(F(-0.074658f) * AT(1, 7) + F(0.513280f) * AT(3, 7) + F(0.768178f) * AT(5, 7) + F(-0.375330f) * AT(7, 7));
+ const Temp_Type X130 = AT(6, 0);
+ const Temp_Type X131 = AT(6, 1);
+ const Temp_Type X132 = AT(6, 2);
+ const Temp_Type X133 = AT(6, 3);
+ const Temp_Type X134 = AT(6, 4);
+ const Temp_Type X135 = AT(6, 5);
+ const Temp_Type X136 = AT(6, 6);
+ const Temp_Type X137 = AT(6, 7);
+ // 80 muls 48 adds
+
+ // 4x4 = 4x8 times 8x4, matrix 1 is constant
+ R.at(0, 0) = X100;
+ R.at(0, 1) = D(X101 * F(0.415735f) + X103 * F(0.791065f) + X105 * F(-0.352443f) + X107 * F(0.277785f));
+ R.at(0, 2) = X104;
+ R.at(0, 3) = D(X101 * F(0.022887f) + X103 * F(-0.097545f) + X105 * F(0.490393f) + X107 * F(0.865723f));
+ R.at(1, 0) = X110;
+ R.at(1, 1) = D(X111 * F(0.415735f) + X113 * F(0.791065f) + X115 * F(-0.352443f) + X117 * F(0.277785f));
+ R.at(1, 2) = X114;
+ R.at(1, 3) = D(X111 * F(0.022887f) + X113 * F(-0.097545f) + X115 * F(0.490393f) + X117 * F(0.865723f));
+ R.at(2, 0) = X120;
+ R.at(2, 1) = D(X121 * F(0.415735f) + X123 * F(0.791065f) + X125 * F(-0.352443f) + X127 * F(0.277785f));
+ R.at(2, 2) = X124;
+ R.at(2, 3) = D(X121 * F(0.022887f) + X123 * F(-0.097545f) + X125 * F(0.490393f) + X127 * F(0.865723f));
+ R.at(3, 0) = X130;
+ R.at(3, 1) = D(X131 * F(0.415735f) + X133 * F(0.791065f) + X135 * F(-0.352443f) + X137 * F(0.277785f));
+ R.at(3, 2) = X134;
+ R.at(3, 3) = D(X131 * F(0.022887f) + X133 * F(-0.097545f) + X135 * F(0.490393f) + X137 * F(0.865723f));
+ // 40 muls 24 adds
+ // 4x4 = 4x8 times 8x4, matrix 1 is constant
+ S.at(0, 0) = D(X101 * F(0.906127f) + X103 * F(-0.318190f) + X105 * F(0.212608f) + X107 * F(-0.180240f));
+ S.at(0, 1) = X102;
+ S.at(0, 2) = D(X101 * F(-0.074658f) + X103 * F(0.513280f) + X105 * F(0.768178f) + X107 * F(-0.375330f));
+ S.at(0, 3) = X106;
+ S.at(1, 0) = D(X111 * F(0.906127f) + X113 * F(-0.318190f) + X115 * F(0.212608f) + X117 * F(-0.180240f));
+ S.at(1, 1) = X112;
+ S.at(1, 2) = D(X111 * F(-0.074658f) + X113 * F(0.513280f) + X115 * F(0.768178f) + X117 * F(-0.375330f));
+ S.at(1, 3) = X116;
+ S.at(2, 0) = D(X121 * F(0.906127f) + X123 * F(-0.318190f) + X125 * F(0.212608f) + X127 * F(-0.180240f));
+ S.at(2, 1) = X122;
+ S.at(2, 2) = D(X121 * F(-0.074658f) + X123 * F(0.513280f) + X125 * F(0.768178f) + X127 * F(-0.375330f));
+ S.at(2, 3) = X126;
+ S.at(3, 0) = D(X131 * F(0.906127f) + X133 * F(-0.318190f) + X135 * F(0.212608f) + X137 * F(-0.180240f));
+ S.at(3, 1) = X132;
+ S.at(3, 2) = D(X131 * F(-0.074658f) + X133 * F(0.513280f) + X135 * F(0.768178f) + X137 * F(-0.375330f));
+ S.at(3, 3) = X136;
+ // 40 muls 24 adds
+ }
+ };
+} // end namespace DCT_Upsample
+
+// Unconditionally frees all allocated m_blocks.
+void jpeg_decoder::free_all_blocks()
+{
+ m_pStream = NULL;
+ for (mem_block *b = m_pMem_blocks; b; )
+ {
+ mem_block *n = b->m_pNext;
+ jpgd_free(b);
+ b = n;
+ }
+ m_pMem_blocks = NULL;
+}
+
+// This method handles all errors. It will never return.
+// It could easily be changed to use C++ exceptions.
+JPGD_NORETURN void jpeg_decoder::stop_decoding(jpgd_status status)
+{
+ m_error_code = status;
+ free_all_blocks();
+ longjmp(m_jmp_state, status);
+}
+
+void *jpeg_decoder::alloc(size_t nSize, bool zero)
+{
+ nSize = (JPGD_MAX(nSize, 1) + 3) & ~3;
+ char *rv = NULL;
+ for (mem_block *b = m_pMem_blocks; b; b = b->m_pNext)
+ {
+ if ((b->m_used_count + nSize) <= b->m_size)
+ {
+ rv = b->m_data + b->m_used_count;
+ b->m_used_count += nSize;
+ break;
+ }
+ }
+ if (!rv)
+ {
+ int capacity = JPGD_MAX(32768 - 256, (nSize + 2047) & ~2047);
+ mem_block *b = (mem_block*)jpgd_malloc(sizeof(mem_block) + capacity);
+ if (!b) { stop_decoding(JPGD_NOTENOUGHMEM); }
+ b->m_pNext = m_pMem_blocks; m_pMem_blocks = b;
+ b->m_used_count = nSize;
+ b->m_size = capacity;
+ rv = b->m_data;
+ }
+ if (zero) memset(rv, 0, nSize);
+ return rv;
+}
+
+void jpeg_decoder::word_clear(void *p, uint16 c, uint n)
+{
+ uint8 *pD = (uint8*)p;
+ const uint8 l = c & 0xFF, h = (c >> 8) & 0xFF;
+ while (n)
+ {
+ pD[0] = l; pD[1] = h; pD += 2;
+ n--;
+ }
+}
+
+// Refill the input buffer.
+// This method will sit in a loop until (A) the buffer is full or (B)
+// the stream's read() method reports and end of file condition.
+void jpeg_decoder::prep_in_buffer()
+{
+ m_in_buf_left = 0;
+ m_pIn_buf_ofs = m_in_buf;
+
+ if (m_eof_flag)
+ return;
+
+ do
+ {
+ int bytes_read = m_pStream->read(m_in_buf + m_in_buf_left, JPGD_IN_BUF_SIZE - m_in_buf_left, &m_eof_flag);
+ if (bytes_read == -1)
+ stop_decoding(JPGD_STREAM_READ);
+
+ m_in_buf_left += bytes_read;
+ } while ((m_in_buf_left < JPGD_IN_BUF_SIZE) && (!m_eof_flag));
+
+ m_total_bytes_read += m_in_buf_left;
+
+ // Pad the end of the block with M_EOI (prevents the decompressor from going off the rails if the stream is invalid).
+ // (This dates way back to when this decompressor was written in C/asm, and the all-asm Huffman decoder did some fancy things to increase perf.)
+ word_clear(m_pIn_buf_ofs + m_in_buf_left, 0xD9FF, 64);
+}
+
+// Read a Huffman code table.
+void jpeg_decoder::read_dht_marker()
+{
+ int i, index, count;
+ uint8 huff_num[17];
+ uint8 huff_val[256];
+
+ uint num_left = get_bits(16);
+
+ if (num_left < 2)
+ stop_decoding(JPGD_BAD_DHT_MARKER);
+
+ num_left -= 2;
+
+ while (num_left)
+ {
+ index = get_bits(8);
+
+ huff_num[0] = 0;
+
+ count = 0;
+
+ for (i = 1; i <= 16; i++)
+ {
+ huff_num[i] = static_cast<uint8>(get_bits(8));
+ count += huff_num[i];
+ }
+
+ if (count > 255)
+ stop_decoding(JPGD_BAD_DHT_COUNTS);
+
+ for (i = 0; i < count; i++)
+ huff_val[i] = static_cast<uint8>(get_bits(8));
+
+ i = 1 + 16 + count;
+
+ if (num_left < (uint)i)
+ stop_decoding(JPGD_BAD_DHT_MARKER);
+
+ num_left -= i;
+
+ if ((index & 0x10) > 0x10)
+ stop_decoding(JPGD_BAD_DHT_INDEX);
+
+ index = (index & 0x0F) + ((index & 0x10) >> 4) * (JPGD_MAX_HUFF_TABLES >> 1);
+
+ if (index >= JPGD_MAX_HUFF_TABLES)
+ stop_decoding(JPGD_BAD_DHT_INDEX);
+
+ if (!m_huff_num[index])
+ m_huff_num[index] = (uint8 *)alloc(17);
+
+ if (!m_huff_val[index])
+ m_huff_val[index] = (uint8 *)alloc(256);
+
+ m_huff_ac[index] = (index & 0x10) != 0;
+ memcpy(m_huff_num[index], huff_num, 17);
+ memcpy(m_huff_val[index], huff_val, 256);
+ }
+}
+
+// Read a quantization table.
+void jpeg_decoder::read_dqt_marker()
+{
+ int n, i, prec;
+ uint num_left;
+ uint temp;
+
+ num_left = get_bits(16);
+
+ if (num_left < 2)
+ stop_decoding(JPGD_BAD_DQT_MARKER);
+
+ num_left -= 2;
+
+ while (num_left)
+ {
+ n = get_bits(8);
+ prec = n >> 4;
+ n &= 0x0F;
+
+ if (n >= JPGD_MAX_QUANT_TABLES)
+ stop_decoding(JPGD_BAD_DQT_TABLE);
+
+ if (!m_quant[n])
+ m_quant[n] = (jpgd_quant_t *)alloc(64 * sizeof(jpgd_quant_t));
+
+ // read quantization entries, in zag order
+ for (i = 0; i < 64; i++)
+ {
+ temp = get_bits(8);
+
+ if (prec)
+ temp = (temp << 8) + get_bits(8);
+
+ m_quant[n][i] = static_cast<jpgd_quant_t>(temp);
+ }
+
+ i = 64 + 1;
+
+ if (prec)
+ i += 64;
+
+ if (num_left < (uint)i)
+ stop_decoding(JPGD_BAD_DQT_LENGTH);
+
+ num_left -= i;
+ }
+}
+
+// Read the start of frame (SOF) marker.
+void jpeg_decoder::read_sof_marker()
+{
+ int i;
+ uint num_left;
+
+ num_left = get_bits(16);
+
+ if (get_bits(8) != 8) /* precision: sorry, only 8-bit precision is supported right now */
+ stop_decoding(JPGD_BAD_PRECISION);
+
+ m_image_y_size = get_bits(16);
+
+ if ((m_image_y_size < 1) || (m_image_y_size > JPGD_MAX_HEIGHT))
+ stop_decoding(JPGD_BAD_HEIGHT);
+
+ m_image_x_size = get_bits(16);
+
+ if ((m_image_x_size < 1) || (m_image_x_size > JPGD_MAX_WIDTH))
+ stop_decoding(JPGD_BAD_WIDTH);
+
+ m_comps_in_frame = get_bits(8);
+
+ if (m_comps_in_frame > JPGD_MAX_COMPONENTS)
+ stop_decoding(JPGD_TOO_MANY_COMPONENTS);
+
+ if (num_left != (uint)(m_comps_in_frame * 3 + 8))
+ stop_decoding(JPGD_BAD_SOF_LENGTH);
+
+ for (i = 0; i < m_comps_in_frame; i++)
+ {
+ m_comp_ident[i] = get_bits(8);
+ m_comp_h_samp[i] = get_bits(4);
+ m_comp_v_samp[i] = get_bits(4);
+ m_comp_quant[i] = get_bits(8);
+ }
+}
+
+// Used to skip unrecognized markers.
+void jpeg_decoder::skip_variable_marker()
+{
+ uint num_left;
+
+ num_left = get_bits(16);
+
+ if (num_left < 2)
+ stop_decoding(JPGD_BAD_VARIABLE_MARKER);
+
+ num_left -= 2;
+
+ while (num_left)
+ {
+ get_bits(8);
+ num_left--;
+ }
+}
+
+// Read a define restart interval (DRI) marker.
+void jpeg_decoder::read_dri_marker()
+{
+ if (get_bits(16) != 4)
+ stop_decoding(JPGD_BAD_DRI_LENGTH);
+
+ m_restart_interval = get_bits(16);
+}
+
+// Read a start of scan (SOS) marker.
+void jpeg_decoder::read_sos_marker()
+{
+ uint num_left;
+ int i, ci, n, c, cc;
+
+ num_left = get_bits(16);
+
+ n = get_bits(8);
+
+ m_comps_in_scan = n;
+
+ num_left -= 3;
+
+ if ( (num_left != (uint)(n * 2 + 3)) || (n < 1) || (n > JPGD_MAX_COMPS_IN_SCAN) )
+ stop_decoding(JPGD_BAD_SOS_LENGTH);
+
+ for (i = 0; i < n; i++)
+ {
+ cc = get_bits(8);
+ c = get_bits(8);
+ num_left -= 2;
+
+ for (ci = 0; ci < m_comps_in_frame; ci++)
+ if (cc == m_comp_ident[ci])
+ break;
+
+ if (ci >= m_comps_in_frame)
+ stop_decoding(JPGD_BAD_SOS_COMP_ID);
+
+ m_comp_list[i] = ci;
+ m_comp_dc_tab[ci] = (c >> 4) & 15;
+ m_comp_ac_tab[ci] = (c & 15) + (JPGD_MAX_HUFF_TABLES >> 1);
+ }
+
+ m_spectral_start = get_bits(8);
+ m_spectral_end = get_bits(8);
+ m_successive_high = get_bits(4);
+ m_successive_low = get_bits(4);
+
+ if (!m_progressive_flag)
+ {
+ m_spectral_start = 0;
+ m_spectral_end = 63;
+ }
+
+ num_left -= 3;
+
+ while (num_left) /* read past whatever is num_left */
+ {
+ get_bits(8);
+ num_left--;
+ }
+}
+
+// Finds the next marker.
+int jpeg_decoder::next_marker()
+{
+ uint c, bytes;
+
+ bytes = 0;
+
+ do
+ {
+ do
+ {
+ bytes++;
+ c = get_bits(8);
+ } while (c != 0xFF);
+
+ do
+ {
+ c = get_bits(8);
+ } while (c == 0xFF);
+
+ } while (c == 0);
+
+ // If bytes > 0 here, there where extra bytes before the marker (not good).
+
+ return c;
+}
+
+// Process markers. Returns when an SOFx, SOI, EOI, or SOS marker is
+// encountered.
+int jpeg_decoder::process_markers()
+{
+ int c;
+
+ for ( ; ; )
+ {
+ c = next_marker();
+
+ switch (c)
+ {
+ case M_SOF0:
+ case M_SOF1:
+ case M_SOF2:
+ case M_SOF3:
+ case M_SOF5:
+ case M_SOF6:
+ case M_SOF7:
+// case M_JPG:
+ case M_SOF9:
+ case M_SOF10:
+ case M_SOF11:
+ case M_SOF13:
+ case M_SOF14:
+ case M_SOF15:
+ case M_SOI:
+ case M_EOI:
+ case M_SOS:
+ {
+ return c;
+ }
+ case M_DHT:
+ {
+ read_dht_marker();
+ break;
+ }
+ // No arithmitic support - dumb patents!
+ case M_DAC:
+ {
+ stop_decoding(JPGD_NO_ARITHMITIC_SUPPORT);
+ break;
+ }
+ case M_DQT:
+ {
+ read_dqt_marker();
+ break;
+ }
+ case M_DRI:
+ {
+ read_dri_marker();
+ break;
+ }
+ //case M_APP0: /* no need to read the JFIF marker */
+
+ case M_JPG:
+ case M_RST0: /* no parameters */
+ case M_RST1:
+ case M_RST2:
+ case M_RST3:
+ case M_RST4:
+ case M_RST5:
+ case M_RST6:
+ case M_RST7:
+ case M_TEM:
+ {
+ stop_decoding(JPGD_UNEXPECTED_MARKER);
+ break;
+ }
+ default: /* must be DNL, DHP, EXP, APPn, JPGn, COM, or RESn or APP0 */
+ {
+ skip_variable_marker();
+ break;
+ }
+ }
+ }
+}
+
+// Finds the start of image (SOI) marker.
+// This code is rather defensive: it only checks the first 512 bytes to avoid
+// false positives.
+void jpeg_decoder::locate_soi_marker()
+{
+ uint lastchar, thischar;
+ uint bytesleft;
+
+ lastchar = get_bits(8);
+
+ thischar = get_bits(8);
+
+ /* ok if it's a normal JPEG file without a special header */
+
+ if ((lastchar == 0xFF) && (thischar == M_SOI))
+ return;
+
+ bytesleft = 4096; //512;
+
+ for ( ; ; )
+ {
+ if (--bytesleft == 0)
+ stop_decoding(JPGD_NOT_JPEG);
+
+ lastchar = thischar;
+
+ thischar = get_bits(8);
+
+ if (lastchar == 0xFF)
+ {
+ if (thischar == M_SOI)
+ break;
+ else if (thischar == M_EOI) // get_bits will keep returning M_EOI if we read past the end
+ stop_decoding(JPGD_NOT_JPEG);
+ }
+ }
+
+ // Check the next character after marker: if it's not 0xFF, it can't be the start of the next marker, so the file is bad.
+ thischar = (m_bit_buf >> 24) & 0xFF;
+
+ if (thischar != 0xFF)
+ stop_decoding(JPGD_NOT_JPEG);
+}
+
+// Find a start of frame (SOF) marker.
+void jpeg_decoder::locate_sof_marker()
+{
+ locate_soi_marker();
+
+ int c = process_markers();
+
+ switch (c)
+ {
+ case M_SOF2:
+ m_progressive_flag = JPGD_TRUE;
+ case M_SOF0: /* baseline DCT */
+ case M_SOF1: /* extended sequential DCT */
+ {
+ read_sof_marker();
+ break;
+ }
+ case M_SOF9: /* Arithmitic coding */
+ {
+ stop_decoding(JPGD_NO_ARITHMITIC_SUPPORT);
+ break;
+ }
+ default:
+ {
+ stop_decoding(JPGD_UNSUPPORTED_MARKER);
+ break;
+ }
+ }
+}
+
+// Find a start of scan (SOS) marker.
+int jpeg_decoder::locate_sos_marker()
+{
+ int c;
+
+ c = process_markers();
+
+ if (c == M_EOI)
+ return JPGD_FALSE;
+ else if (c != M_SOS)
+ stop_decoding(JPGD_UNEXPECTED_MARKER);
+
+ read_sos_marker();
+
+ return JPGD_TRUE;
+}
+
+// Reset everything to default/uninitialized state.
+void jpeg_decoder::init(jpeg_decoder_stream *pStream)
+{
+ m_pMem_blocks = NULL;
+ m_error_code = JPGD_SUCCESS;
+ m_ready_flag = false;
+ m_image_x_size = m_image_y_size = 0;
+ m_pStream = pStream;
+ m_progressive_flag = JPGD_FALSE;
+
+ memset(m_huff_ac, 0, sizeof(m_huff_ac));
+ memset(m_huff_num, 0, sizeof(m_huff_num));
+ memset(m_huff_val, 0, sizeof(m_huff_val));
+ memset(m_quant, 0, sizeof(m_quant));
+
+ m_scan_type = 0;
+ m_comps_in_frame = 0;
+
+ memset(m_comp_h_samp, 0, sizeof(m_comp_h_samp));
+ memset(m_comp_v_samp, 0, sizeof(m_comp_v_samp));
+ memset(m_comp_quant, 0, sizeof(m_comp_quant));
+ memset(m_comp_ident, 0, sizeof(m_comp_ident));
+ memset(m_comp_h_blocks, 0, sizeof(m_comp_h_blocks));
+ memset(m_comp_v_blocks, 0, sizeof(m_comp_v_blocks));
+
+ m_comps_in_scan = 0;
+ memset(m_comp_list, 0, sizeof(m_comp_list));
+ memset(m_comp_dc_tab, 0, sizeof(m_comp_dc_tab));
+ memset(m_comp_ac_tab, 0, sizeof(m_comp_ac_tab));
+
+ m_spectral_start = 0;
+ m_spectral_end = 0;
+ m_successive_low = 0;
+ m_successive_high = 0;
+ m_max_mcu_x_size = 0;
+ m_max_mcu_y_size = 0;
+ m_blocks_per_mcu = 0;
+ m_max_blocks_per_row = 0;
+ m_mcus_per_row = 0;
+ m_mcus_per_col = 0;
+ m_expanded_blocks_per_component = 0;
+ m_expanded_blocks_per_mcu = 0;
+ m_expanded_blocks_per_row = 0;
+ m_freq_domain_chroma_upsample = false;
+
+ memset(m_mcu_org, 0, sizeof(m_mcu_org));
+
+ m_total_lines_left = 0;
+ m_mcu_lines_left = 0;
+ m_real_dest_bytes_per_scan_line = 0;
+ m_dest_bytes_per_scan_line = 0;
+ m_dest_bytes_per_pixel = 0;
+
+ memset(m_pHuff_tabs, 0, sizeof(m_pHuff_tabs));
+
+ memset(m_dc_coeffs, 0, sizeof(m_dc_coeffs));
+ memset(m_ac_coeffs, 0, sizeof(m_ac_coeffs));
+ memset(m_block_y_mcu, 0, sizeof(m_block_y_mcu));
+
+ m_eob_run = 0;
+
+ memset(m_block_y_mcu, 0, sizeof(m_block_y_mcu));
+
+ m_pIn_buf_ofs = m_in_buf;
+ m_in_buf_left = 0;
+ m_eof_flag = false;
+ m_tem_flag = 0;
+
+ memset(m_in_buf_pad_start, 0, sizeof(m_in_buf_pad_start));
+ memset(m_in_buf, 0, sizeof(m_in_buf));
+ memset(m_in_buf_pad_end, 0, sizeof(m_in_buf_pad_end));
+
+ m_restart_interval = 0;
+ m_restarts_left = 0;
+ m_next_restart_num = 0;
+
+ m_max_mcus_per_row = 0;
+ m_max_blocks_per_mcu = 0;
+ m_max_mcus_per_col = 0;
+
+ memset(m_last_dc_val, 0, sizeof(m_last_dc_val));
+ m_pMCU_coefficients = NULL;
+ m_pSample_buf = NULL;
+
+ m_total_bytes_read = 0;
+
+ m_pScan_line_0 = NULL;
+ m_pScan_line_1 = NULL;
+
+ // Ready the input buffer.
+ prep_in_buffer();
+
+ // Prime the bit buffer.
+ m_bits_left = 16;
+ m_bit_buf = 0;
+
+ get_bits(16);
+ get_bits(16);
+
+ for (int i = 0; i < JPGD_MAX_BLOCKS_PER_MCU; i++)
+ m_mcu_block_max_zag[i] = 64;
+}
+
+#define SCALEBITS 16
+#define ONE_HALF ((int) 1 << (SCALEBITS-1))
+#define FIX(x) ((int) ((x) * (1L<<SCALEBITS) + 0.5f))
+
+// Create a few tables that allow us to quickly convert YCbCr to RGB.
+void jpeg_decoder::create_look_ups()
+{
+ for (int i = 0; i <= 255; i++)
+ {
+ int k = i - 128;
+ m_crr[i] = ( FIX(1.40200f) * k + ONE_HALF) >> SCALEBITS;
+ m_cbb[i] = ( FIX(1.77200f) * k + ONE_HALF) >> SCALEBITS;
+ m_crg[i] = (-FIX(0.71414f)) * k;
+ m_cbg[i] = (-FIX(0.34414f)) * k + ONE_HALF;
+ }
+}
+
+// This method throws back into the stream any bytes that where read
+// into the bit buffer during initial marker scanning.
+void jpeg_decoder::fix_in_buffer()
+{
+ // In case any 0xFF's where pulled into the buffer during marker scanning.
+ JPGD_ASSERT((m_bits_left & 7) == 0);
+
+ if (m_bits_left == 16)
+ stuff_char( (uint8)(m_bit_buf & 0xFF));
+
+ if (m_bits_left >= 8)
+ stuff_char( (uint8)((m_bit_buf >> 8) & 0xFF));
+
+ stuff_char((uint8)((m_bit_buf >> 16) & 0xFF));
+ stuff_char((uint8)((m_bit_buf >> 24) & 0xFF));
+
+ m_bits_left = 16;
+ get_bits_no_markers(16);
+ get_bits_no_markers(16);
+}
+
+void jpeg_decoder::transform_mcu(int mcu_row)
+{
+ jpgd_block_t* pSrc_ptr = m_pMCU_coefficients;
+ uint8* pDst_ptr = m_pSample_buf + mcu_row * m_blocks_per_mcu * 64;
+
+ for (int mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++)
+ {
+ idct(pSrc_ptr, pDst_ptr, m_mcu_block_max_zag[mcu_block]);
+ pSrc_ptr += 64;
+ pDst_ptr += 64;
+ }
+}
+
+static const uint8 s_max_rc[64] =
+{
+ 17, 18, 34, 50, 50, 51, 52, 52, 52, 68, 84, 84, 84, 84, 85, 86, 86, 86, 86, 86,
+ 102, 118, 118, 118, 118, 118, 118, 119, 120, 120, 120, 120, 120, 120, 120, 136,
+ 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+ 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136
+};
+
+void jpeg_decoder::transform_mcu_expand(int mcu_row)
+{
+ jpgd_block_t* pSrc_ptr = m_pMCU_coefficients;
+ uint8* pDst_ptr = m_pSample_buf + mcu_row * m_expanded_blocks_per_mcu * 64;
+
+ // Y IDCT
+ int mcu_block;
+ for (mcu_block = 0; mcu_block < m_expanded_blocks_per_component; mcu_block++)
+ {
+ idct(pSrc_ptr, pDst_ptr, m_mcu_block_max_zag[mcu_block]);
+ pSrc_ptr += 64;
+ pDst_ptr += 64;
+ }
+
+ // Chroma IDCT, with upsampling
+ jpgd_block_t temp_block[64];
+
+ for (int i = 0; i < 2; i++)
+ {
+ DCT_Upsample::Matrix44 P, Q, R, S;
+
+ JPGD_ASSERT(m_mcu_block_max_zag[mcu_block] >= 1);
+ JPGD_ASSERT(m_mcu_block_max_zag[mcu_block] <= 64);
+
+ int max_zag = m_mcu_block_max_zag[mcu_block++] - 1;
+ if (max_zag <= 0) max_zag = 0; // should never happen, only here to shut up static analysis
+ switch (s_max_rc[max_zag])
+ {
+ case 1*16+1:
+ DCT_Upsample::P_Q<1, 1>::calc(P, Q, pSrc_ptr);
+ DCT_Upsample::R_S<1, 1>::calc(R, S, pSrc_ptr);
+ break;
+ case 1*16+2:
+ DCT_Upsample::P_Q<1, 2>::calc(P, Q, pSrc_ptr);
+ DCT_Upsample::R_S<1, 2>::calc(R, S, pSrc_ptr);
+ break;
+ case 2*16+2:
+ DCT_Upsample::P_Q<2, 2>::calc(P, Q, pSrc_ptr);
+ DCT_Upsample::R_S<2, 2>::calc(R, S, pSrc_ptr);
+ break;
+ case 3*16+2:
+ DCT_Upsample::P_Q<3, 2>::calc(P, Q, pSrc_ptr);
+ DCT_Upsample::R_S<3, 2>::calc(R, S, pSrc_ptr);
+ break;
+ case 3*16+3:
+ DCT_Upsample::P_Q<3, 3>::calc(P, Q, pSrc_ptr);
+ DCT_Upsample::R_S<3, 3>::calc(R, S, pSrc_ptr);
+ break;
+ case 3*16+4:
+ DCT_Upsample::P_Q<3, 4>::calc(P, Q, pSrc_ptr);
+ DCT_Upsample::R_S<3, 4>::calc(R, S, pSrc_ptr);
+ break;
+ case 4*16+4:
+ DCT_Upsample::P_Q<4, 4>::calc(P, Q, pSrc_ptr);
+ DCT_Upsample::R_S<4, 4>::calc(R, S, pSrc_ptr);
+ break;
+ case 5*16+4:
+ DCT_Upsample::P_Q<5, 4>::calc(P, Q, pSrc_ptr);
+ DCT_Upsample::R_S<5, 4>::calc(R, S, pSrc_ptr);
+ break;
+ case 5*16+5:
+ DCT_Upsample::P_Q<5, 5>::calc(P, Q, pSrc_ptr);
+ DCT_Upsample::R_S<5, 5>::calc(R, S, pSrc_ptr);
+ break;
+ case 5*16+6:
+ DCT_Upsample::P_Q<5, 6>::calc(P, Q, pSrc_ptr);
+ DCT_Upsample::R_S<5, 6>::calc(R, S, pSrc_ptr);
+ break;
+ case 6*16+6:
+ DCT_Upsample::P_Q<6, 6>::calc(P, Q, pSrc_ptr);
+ DCT_Upsample::R_S<6, 6>::calc(R, S, pSrc_ptr);
+ break;
+ case 7*16+6:
+ DCT_Upsample::P_Q<7, 6>::calc(P, Q, pSrc_ptr);
+ DCT_Upsample::R_S<7, 6>::calc(R, S, pSrc_ptr);
+ break;
+ case 7*16+7:
+ DCT_Upsample::P_Q<7, 7>::calc(P, Q, pSrc_ptr);
+ DCT_Upsample::R_S<7, 7>::calc(R, S, pSrc_ptr);
+ break;
+ case 7*16+8:
+ DCT_Upsample::P_Q<7, 8>::calc(P, Q, pSrc_ptr);
+ DCT_Upsample::R_S<7, 8>::calc(R, S, pSrc_ptr);
+ break;
+ case 8*16+8:
+ DCT_Upsample::P_Q<8, 8>::calc(P, Q, pSrc_ptr);
+ DCT_Upsample::R_S<8, 8>::calc(R, S, pSrc_ptr);
+ break;
+ default:
+ JPGD_ASSERT(false);
+ }
+
+ DCT_Upsample::Matrix44 a(P + Q); P -= Q;
+ DCT_Upsample::Matrix44& b = P;
+ DCT_Upsample::Matrix44 c(R + S); R -= S;
+ DCT_Upsample::Matrix44& d = R;
+
+ DCT_Upsample::Matrix44::add_and_store(temp_block, a, c);
+ idct_4x4(temp_block, pDst_ptr);
+ pDst_ptr += 64;
+
+ DCT_Upsample::Matrix44::sub_and_store(temp_block, a, c);
+ idct_4x4(temp_block, pDst_ptr);
+ pDst_ptr += 64;
+
+ DCT_Upsample::Matrix44::add_and_store(temp_block, b, d);
+ idct_4x4(temp_block, pDst_ptr);
+ pDst_ptr += 64;
+
+ DCT_Upsample::Matrix44::sub_and_store(temp_block, b, d);
+ idct_4x4(temp_block, pDst_ptr);
+ pDst_ptr += 64;
+
+ pSrc_ptr += 64;
+ }
+}
+
+// Loads and dequantizes the next row of (already decoded) coefficients.
+// Progressive images only.
+void jpeg_decoder::load_next_row()
+{
+ int i;
+ jpgd_block_t *p;
+ jpgd_quant_t *q;
+ int mcu_row, mcu_block, row_block = 0;
+ int component_num, component_id;
+ int block_x_mcu[JPGD_MAX_COMPONENTS];
+
+ memset(block_x_mcu, 0, JPGD_MAX_COMPONENTS * sizeof(int));
+
+ for (mcu_row = 0; mcu_row < m_mcus_per_row; mcu_row++)
+ {
+ int block_x_mcu_ofs = 0, block_y_mcu_ofs = 0;
+
+ for (mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++)
+ {
+ component_id = m_mcu_org[mcu_block];
+ q = m_quant[m_comp_quant[component_id]];
+
+ p = m_pMCU_coefficients + 64 * mcu_block;
+
+ jpgd_block_t* pAC = coeff_buf_getp(m_ac_coeffs[component_id], block_x_mcu[component_id] + block_x_mcu_ofs, m_block_y_mcu[component_id] + block_y_mcu_ofs);
+ jpgd_block_t* pDC = coeff_buf_getp(m_dc_coeffs[component_id], block_x_mcu[component_id] + block_x_mcu_ofs, m_block_y_mcu[component_id] + block_y_mcu_ofs);
+ p[0] = pDC[0];
+ memcpy(&p[1], &pAC[1], 63 * sizeof(jpgd_block_t));
+
+ for (i = 63; i > 0; i--)
+ if (p[g_ZAG[i]])
+ break;
+
+ m_mcu_block_max_zag[mcu_block] = i + 1;
+
+ for ( ; i >= 0; i--)
+ if (p[g_ZAG[i]])
+ p[g_ZAG[i]] = static_cast<jpgd_block_t>(p[g_ZAG[i]] * q[i]);
+
+ row_block++;
+
+ if (m_comps_in_scan == 1)
+ block_x_mcu[component_id]++;
+ else
+ {
+ if (++block_x_mcu_ofs == m_comp_h_samp[component_id])
+ {
+ block_x_mcu_ofs = 0;
+
+ if (++block_y_mcu_ofs == m_comp_v_samp[component_id])
+ {
+ block_y_mcu_ofs = 0;
+
+ block_x_mcu[component_id] += m_comp_h_samp[component_id];
+ }
+ }
+ }
+ }
+
+ if (m_freq_domain_chroma_upsample)
+ transform_mcu_expand(mcu_row);
+ else
+ transform_mcu(mcu_row);
+ }
+
+ if (m_comps_in_scan == 1)
+ m_block_y_mcu[m_comp_list[0]]++;
+ else
+ {
+ for (component_num = 0; component_num < m_comps_in_scan; component_num++)
+ {
+ component_id = m_comp_list[component_num];
+
+ m_block_y_mcu[component_id] += m_comp_v_samp[component_id];
+ }
+ }
+}
+
+// Restart interval processing.
+void jpeg_decoder::process_restart()
+{
+ int i;
+ int c = 0;
+
+ // Align to a byte boundry
+ // FIXME: Is this really necessary? get_bits_no_markers() never reads in markers!
+ //get_bits_no_markers(m_bits_left & 7);
+
+ // Let's scan a little bit to find the marker, but not _too_ far.
+ // 1536 is a "fudge factor" that determines how much to scan.
+ for (i = 1536; i > 0; i--)
+ if (get_char() == 0xFF)
+ break;
+
+ if (i == 0)
+ stop_decoding(JPGD_BAD_RESTART_MARKER);
+
+ for ( ; i > 0; i--)
+ if ((c = get_char()) != 0xFF)
+ break;
+
+ if (i == 0)
+ stop_decoding(JPGD_BAD_RESTART_MARKER);
+
+ // Is it the expected marker? If not, something bad happened.
+ if (c != (m_next_restart_num + M_RST0))
+ stop_decoding(JPGD_BAD_RESTART_MARKER);
+
+ // Reset each component's DC prediction values.
+ memset(&m_last_dc_val, 0, m_comps_in_frame * sizeof(uint));
+
+ m_eob_run = 0;
+
+ m_restarts_left = m_restart_interval;
+
+ m_next_restart_num = (m_next_restart_num + 1) & 7;
+
+ // Get the bit buffer going again...
+
+ m_bits_left = 16;
+ get_bits_no_markers(16);
+ get_bits_no_markers(16);
+}
+
+static inline int dequantize_ac(int c, int q) { c *= q; return c; }
+
+// Decodes and dequantizes the next row of coefficients.
+void jpeg_decoder::decode_next_row()
+{
+ int row_block = 0;
+
+ for (int mcu_row = 0; mcu_row < m_mcus_per_row; mcu_row++)
+ {
+ if ((m_restart_interval) && (m_restarts_left == 0))
+ process_restart();
+
+ jpgd_block_t* p = m_pMCU_coefficients;
+ for (int mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++, p += 64)
+ {
+ int component_id = m_mcu_org[mcu_block];
+ jpgd_quant_t* q = m_quant[m_comp_quant[component_id]];
+
+ int r, s;
+ s = huff_decode(m_pHuff_tabs[m_comp_dc_tab[component_id]], r);
+ s = JPGD_HUFF_EXTEND(r, s);
+
+ m_last_dc_val[component_id] = (s += m_last_dc_val[component_id]);
+
+ p[0] = static_cast<jpgd_block_t>(s * q[0]);
+
+ int prev_num_set = m_mcu_block_max_zag[mcu_block];
+
+ huff_tables *pH = m_pHuff_tabs[m_comp_ac_tab[component_id]];
+
+ int k;
+ for (k = 1; k < 64; k++)
+ {
+ int extra_bits;
+ s = huff_decode(pH, extra_bits);
+
+ r = s >> 4;
+ s &= 15;
+
+ if (s)
+ {
+ if (r)
+ {
+ if ((k + r) > 63)
+ stop_decoding(JPGD_DECODE_ERROR);
+
+ if (k < prev_num_set)
+ {
+ int n = JPGD_MIN(r, prev_num_set - k);
+ int kt = k;
+ while (n--)
+ p[g_ZAG[kt++]] = 0;
+ }
+
+ k += r;
+ }
+
+ s = JPGD_HUFF_EXTEND(extra_bits, s);
+
+ JPGD_ASSERT(k < 64);
+
+ p[g_ZAG[k]] = static_cast<jpgd_block_t>(dequantize_ac(s, q[k])); //s * q[k];
+ }
+ else
+ {
+ if (r == 15)
+ {
+ if ((k + 16) > 64)
+ stop_decoding(JPGD_DECODE_ERROR);
+
+ if (k < prev_num_set)
+ {
+ int n = JPGD_MIN(16, prev_num_set - k);
+ int kt = k;
+ while (n--)
+ {
+ JPGD_ASSERT(kt <= 63);
+ p[g_ZAG[kt++]] = 0;
+ }
+ }
+
+ k += 16 - 1; // - 1 because the loop counter is k
+ JPGD_ASSERT(p[g_ZAG[k]] == 0);
+ }
+ else
+ break;
+ }
+ }
+
+ if (k < prev_num_set)
+ {
+ int kt = k;
+ while (kt < prev_num_set)
+ p[g_ZAG[kt++]] = 0;
+ }
+
+ m_mcu_block_max_zag[mcu_block] = k;
+
+ row_block++;
+ }
+
+ if (m_freq_domain_chroma_upsample)
+ transform_mcu_expand(mcu_row);
+ else
+ transform_mcu(mcu_row);
+
+ m_restarts_left--;
+ }
+}
+
+// YCbCr H1V1 (1x1:1:1, 3 m_blocks per MCU) to RGB
+void jpeg_decoder::H1V1Convert()
+{
+ int row = m_max_mcu_y_size - m_mcu_lines_left;
+ uint8 *d = m_pScan_line_0;
+ uint8 *s = m_pSample_buf + row * 8;
+
+ for (int i = m_max_mcus_per_row; i > 0; i--)
+ {
+ for (int j = 0; j < 8; j++)
+ {
+ int y = s[j];
+ int cb = s[64+j];
+ int cr = s[128+j];
+
+ d[0] = clamp(y + m_crr[cr]);
+ d[1] = clamp(y + ((m_crg[cr] + m_cbg[cb]) >> 16));
+ d[2] = clamp(y + m_cbb[cb]);
+ d[3] = 255;
+
+ d += 4;
+ }
+
+ s += 64*3;
+ }
+}
+
+// YCbCr H2V1 (2x1:1:1, 4 m_blocks per MCU) to RGB
+void jpeg_decoder::H2V1Convert()
+{
+ int row = m_max_mcu_y_size - m_mcu_lines_left;
+ uint8 *d0 = m_pScan_line_0;
+ uint8 *y = m_pSample_buf + row * 8;
+ uint8 *c = m_pSample_buf + 2*64 + row * 8;
+
+ for (int i = m_max_mcus_per_row; i > 0; i--)
+ {
+ for (int l = 0; l < 2; l++)
+ {
+ for (int j = 0; j < 4; j++)
+ {
+ int cb = c[0];
+ int cr = c[64];
+
+ int rc = m_crr[cr];
+ int gc = ((m_crg[cr] + m_cbg[cb]) >> 16);
+ int bc = m_cbb[cb];
+
+ int yy = y[j<<1];
+ d0[0] = clamp(yy+rc);
+ d0[1] = clamp(yy+gc);
+ d0[2] = clamp(yy+bc);
+ d0[3] = 255;
+
+ yy = y[(j<<1)+1];
+ d0[4] = clamp(yy+rc);
+ d0[5] = clamp(yy+gc);
+ d0[6] = clamp(yy+bc);
+ d0[7] = 255;
+
+ d0 += 8;
+
+ c++;
+ }
+ y += 64;
+ }
+
+ y += 64*4 - 64*2;
+ c += 64*4 - 8;
+ }
+}
+
+// YCbCr H2V1 (1x2:1:1, 4 m_blocks per MCU) to RGB
+void jpeg_decoder::H1V2Convert()
+{
+ int row = m_max_mcu_y_size - m_mcu_lines_left;
+ uint8 *d0 = m_pScan_line_0;
+ uint8 *d1 = m_pScan_line_1;
+ uint8 *y;
+ uint8 *c;
+
+ if (row < 8)
+ y = m_pSample_buf + row * 8;
+ else
+ y = m_pSample_buf + 64*1 + (row & 7) * 8;
+
+ c = m_pSample_buf + 64*2 + (row >> 1) * 8;
+
+ for (int i = m_max_mcus_per_row; i > 0; i--)
+ {
+ for (int j = 0; j < 8; j++)
+ {
+ int cb = c[0+j];
+ int cr = c[64+j];
+
+ int rc = m_crr[cr];
+ int gc = ((m_crg[cr] + m_cbg[cb]) >> 16);
+ int bc = m_cbb[cb];
+
+ int yy = y[j];
+ d0[0] = clamp(yy+rc);
+ d0[1] = clamp(yy+gc);
+ d0[2] = clamp(yy+bc);
+ d0[3] = 255;
+
+ yy = y[8+j];
+ d1[0] = clamp(yy+rc);
+ d1[1] = clamp(yy+gc);
+ d1[2] = clamp(yy+bc);
+ d1[3] = 255;
+
+ d0 += 4;
+ d1 += 4;
+ }
+
+ y += 64*4;
+ c += 64*4;
+ }
+}
+
+// YCbCr H2V2 (2x2:1:1, 6 m_blocks per MCU) to RGB
+void jpeg_decoder::H2V2Convert()
+{
+ int row = m_max_mcu_y_size - m_mcu_lines_left;
+ uint8 *d0 = m_pScan_line_0;
+ uint8 *d1 = m_pScan_line_1;
+ uint8 *y;
+ uint8 *c;
+
+ if (row < 8)
+ y = m_pSample_buf + row * 8;
+ else
+ y = m_pSample_buf + 64*2 + (row & 7) * 8;
+
+ c = m_pSample_buf + 64*4 + (row >> 1) * 8;
+
+ for (int i = m_max_mcus_per_row; i > 0; i--)
+ {
+ for (int l = 0; l < 2; l++)
+ {
+ for (int j = 0; j < 8; j += 2)
+ {
+ int cb = c[0];
+ int cr = c[64];
+
+ int rc = m_crr[cr];
+ int gc = ((m_crg[cr] + m_cbg[cb]) >> 16);
+ int bc = m_cbb[cb];
+
+ int yy = y[j];
+ d0[0] = clamp(yy+rc);
+ d0[1] = clamp(yy+gc);
+ d0[2] = clamp(yy+bc);
+ d0[3] = 255;
+
+ yy = y[j+1];
+ d0[4] = clamp(yy+rc);
+ d0[5] = clamp(yy+gc);
+ d0[6] = clamp(yy+bc);
+ d0[7] = 255;
+
+ yy = y[j+8];
+ d1[0] = clamp(yy+rc);
+ d1[1] = clamp(yy+gc);
+ d1[2] = clamp(yy+bc);
+ d1[3] = 255;
+
+ yy = y[j+8+1];
+ d1[4] = clamp(yy+rc);
+ d1[5] = clamp(yy+gc);
+ d1[6] = clamp(yy+bc);
+ d1[7] = 255;
+
+ d0 += 8;
+ d1 += 8;
+
+ c++;
+ }
+ y += 64;
+ }
+
+ y += 64*6 - 64*2;
+ c += 64*6 - 8;
+ }
+}
+
+// Y (1 block per MCU) to 8-bit grayscale
+void jpeg_decoder::gray_convert()
+{
+ int row = m_max_mcu_y_size - m_mcu_lines_left;
+ uint8 *d = m_pScan_line_0;
+ uint8 *s = m_pSample_buf + row * 8;
+
+ for (int i = m_max_mcus_per_row; i > 0; i--)
+ {
+ *(uint *)d = *(uint *)s;
+ *(uint *)(&d[4]) = *(uint *)(&s[4]);
+
+ s += 64;
+ d += 8;
+ }
+}
+
+void jpeg_decoder::expanded_convert()
+{
+ int row = m_max_mcu_y_size - m_mcu_lines_left;
+
+ uint8* Py = m_pSample_buf + (row / 8) * 64 * m_comp_h_samp[0] + (row & 7) * 8;
+
+ uint8* d = m_pScan_line_0;
+
+ for (int i = m_max_mcus_per_row; i > 0; i--)
+ {
+ for (int k = 0; k < m_max_mcu_x_size; k += 8)
+ {
+ const int Y_ofs = k * 8;
+ const int Cb_ofs = Y_ofs + 64 * m_expanded_blocks_per_component;
+ const int Cr_ofs = Y_ofs + 64 * m_expanded_blocks_per_component * 2;
+ for (int j = 0; j < 8; j++)
+ {
+ int y = Py[Y_ofs + j];
+ int cb = Py[Cb_ofs + j];
+ int cr = Py[Cr_ofs + j];
+
+ d[0] = clamp(y + m_crr[cr]);
+ d[1] = clamp(y + ((m_crg[cr] + m_cbg[cb]) >> 16));
+ d[2] = clamp(y + m_cbb[cb]);
+ d[3] = 255;
+
+ d += 4;
+ }
+ }
+
+ Py += 64 * m_expanded_blocks_per_mcu;
+ }
+}
+
+// Find end of image (EOI) marker, so we can return to the user the exact size of the input stream.
+void jpeg_decoder::find_eoi()
+{
+ if (!m_progressive_flag)
+ {
+ // Attempt to read the EOI marker.
+ //get_bits_no_markers(m_bits_left & 7);
+
+ // Prime the bit buffer
+ m_bits_left = 16;
+ get_bits(16);
+ get_bits(16);
+
+ // The next marker _should_ be EOI
+ process_markers();
+ }
+
+ m_total_bytes_read -= m_in_buf_left;
+}
+
+int jpeg_decoder::decode(const void** pScan_line, uint* pScan_line_len)
+{
+ if ((m_error_code) || (!m_ready_flag))
+ return JPGD_FAILED;
+
+ if (m_total_lines_left == 0)
+ return JPGD_DONE;
+
+ if (m_mcu_lines_left == 0)
+ {
+ if (setjmp(m_jmp_state))
+ return JPGD_FAILED;
+
+ if (m_progressive_flag)
+ load_next_row();
+ else
+ decode_next_row();
+
+ // Find the EOI marker if that was the last row.
+ if (m_total_lines_left <= m_max_mcu_y_size)
+ find_eoi();
+
+ m_mcu_lines_left = m_max_mcu_y_size;
+ }
+
+ if (m_freq_domain_chroma_upsample)
+ {
+ expanded_convert();
+ *pScan_line = m_pScan_line_0;
+ }
+ else
+ {
+ switch (m_scan_type)
+ {
+ case JPGD_YH2V2:
+ {
+ if ((m_mcu_lines_left & 1) == 0)
+ {
+ H2V2Convert();
+ *pScan_line = m_pScan_line_0;
+ }
+ else
+ *pScan_line = m_pScan_line_1;
+
+ break;
+ }
+ case JPGD_YH2V1:
+ {
+ H2V1Convert();
+ *pScan_line = m_pScan_line_0;
+ break;
+ }
+ case JPGD_YH1V2:
+ {
+ if ((m_mcu_lines_left & 1) == 0)
+ {
+ H1V2Convert();
+ *pScan_line = m_pScan_line_0;
+ }
+ else
+ *pScan_line = m_pScan_line_1;
+
+ break;
+ }
+ case JPGD_YH1V1:
+ {
+ H1V1Convert();
+ *pScan_line = m_pScan_line_0;
+ break;
+ }
+ case JPGD_GRAYSCALE:
+ {
+ gray_convert();
+ *pScan_line = m_pScan_line_0;
+
+ break;
+ }
+ }
+ }
+
+ *pScan_line_len = m_real_dest_bytes_per_scan_line;
+
+ m_mcu_lines_left--;
+ m_total_lines_left--;
+
+ return JPGD_SUCCESS;
+}
+
+// Creates the tables needed for efficient Huffman decoding.
+void jpeg_decoder::make_huff_table(int index, huff_tables *pH)
+{
+ int p, i, l, si;
+ uint8 huffsize[257];
+ uint huffcode[257];
+ uint code;
+ uint subtree;
+ int code_size;
+ int lastp;
+ int nextfreeentry;
+ int currententry;
+
+ pH->ac_table = m_huff_ac[index] != 0;
+
+ p = 0;
+
+ for (l = 1; l <= 16; l++)
+ {
+ for (i = 1; i <= m_huff_num[index][l]; i++)
+ huffsize[p++] = static_cast<uint8>(l);
+ }
+
+ huffsize[p] = 0;
+
+ lastp = p;
+
+ code = 0;
+ si = huffsize[0];
+ p = 0;
+
+ while (huffsize[p])
+ {
+ while (huffsize[p] == si)
+ {
+ huffcode[p++] = code;
+ code++;
+ }
+
+ code <<= 1;
+ si++;
+ }
+
+ memset(pH->look_up, 0, sizeof(pH->look_up));
+ memset(pH->look_up2, 0, sizeof(pH->look_up2));
+ memset(pH->tree, 0, sizeof(pH->tree));
+ memset(pH->code_size, 0, sizeof(pH->code_size));
+
+ nextfreeentry = -1;
+
+ p = 0;
+
+ while (p < lastp)
+ {
+ i = m_huff_val[index][p];
+ code = huffcode[p];
+ code_size = huffsize[p];
+
+ pH->code_size[i] = static_cast<uint8>(code_size);
+
+ if (code_size <= 8)
+ {
+ code <<= (8 - code_size);
+
+ for (l = 1 << (8 - code_size); l > 0; l--)
+ {
+ JPGD_ASSERT(i < 256);
+
+ pH->look_up[code] = i;
+
+ bool has_extrabits = false;
+ int extra_bits = 0;
+ int num_extra_bits = i & 15;
+
+ int bits_to_fetch = code_size;
+ if (num_extra_bits)
+ {
+ int total_codesize = code_size + num_extra_bits;
+ if (total_codesize <= 8)
+ {
+ has_extrabits = true;
+ extra_bits = ((1 << num_extra_bits) - 1) & (code >> (8 - total_codesize));
+ JPGD_ASSERT(extra_bits <= 0x7FFF);
+ bits_to_fetch += num_extra_bits;
+ }
+ }
+
+ if (!has_extrabits)
+ pH->look_up2[code] = i | (bits_to_fetch << 8);
+ else
+ pH->look_up2[code] = i | 0x8000 | (extra_bits << 16) | (bits_to_fetch << 8);
+
+ code++;
+ }
+ }
+ else
+ {
+ subtree = (code >> (code_size - 8)) & 0xFF;
+
+ currententry = pH->look_up[subtree];
+
+ if (currententry == 0)
+ {
+ pH->look_up[subtree] = currententry = nextfreeentry;
+ pH->look_up2[subtree] = currententry = nextfreeentry;
+
+ nextfreeentry -= 2;
+ }
+
+ code <<= (16 - (code_size - 8));
+
+ for (l = code_size; l > 9; l--)
+ {
+ if ((code & 0x8000) == 0)
+ currententry--;
+
+ if (pH->tree[-currententry - 1] == 0)
+ {
+ pH->tree[-currententry - 1] = nextfreeentry;
+
+ currententry = nextfreeentry;
+
+ nextfreeentry -= 2;
+ }
+ else
+ currententry = pH->tree[-currententry - 1];
+
+ code <<= 1;
+ }
+
+ if ((code & 0x8000) == 0)
+ currententry--;
+
+ pH->tree[-currententry - 1] = i;
+ }
+
+ p++;
+ }
+}
+
+// Verifies the quantization tables needed for this scan are available.
+void jpeg_decoder::check_quant_tables()
+{
+ for (int i = 0; i < m_comps_in_scan; i++)
+ if (m_quant[m_comp_quant[m_comp_list[i]]] == NULL)
+ stop_decoding(JPGD_UNDEFINED_QUANT_TABLE);
+}
+
+// Verifies that all the Huffman tables needed for this scan are available.
+void jpeg_decoder::check_huff_tables()
+{
+ for (int i = 0; i < m_comps_in_scan; i++)
+ {
+ if ((m_spectral_start == 0) && (m_huff_num[m_comp_dc_tab[m_comp_list[i]]] == NULL))
+ stop_decoding(JPGD_UNDEFINED_HUFF_TABLE);
+
+ if ((m_spectral_end > 0) && (m_huff_num[m_comp_ac_tab[m_comp_list[i]]] == NULL))
+ stop_decoding(JPGD_UNDEFINED_HUFF_TABLE);
+ }
+
+ for (int i = 0; i < JPGD_MAX_HUFF_TABLES; i++)
+ if (m_huff_num[i])
+ {
+ if (!m_pHuff_tabs[i])
+ m_pHuff_tabs[i] = (huff_tables *)alloc(sizeof(huff_tables));
+
+ make_huff_table(i, m_pHuff_tabs[i]);
+ }
+}
+
+// Determines the component order inside each MCU.
+// Also calcs how many MCU's are on each row, etc.
+void jpeg_decoder::calc_mcu_block_order()
+{
+ int component_num, component_id;
+ int max_h_samp = 0, max_v_samp = 0;
+
+ for (component_id = 0; component_id < m_comps_in_frame; component_id++)
+ {
+ if (m_comp_h_samp[component_id] > max_h_samp)
+ max_h_samp = m_comp_h_samp[component_id];
+
+ if (m_comp_v_samp[component_id] > max_v_samp)
+ max_v_samp = m_comp_v_samp[component_id];
+ }
+
+ for (component_id = 0; component_id < m_comps_in_frame; component_id++)
+ {
+ m_comp_h_blocks[component_id] = ((((m_image_x_size * m_comp_h_samp[component_id]) + (max_h_samp - 1)) / max_h_samp) + 7) / 8;
+ m_comp_v_blocks[component_id] = ((((m_image_y_size * m_comp_v_samp[component_id]) + (max_v_samp - 1)) / max_v_samp) + 7) / 8;
+ }
+
+ if (m_comps_in_scan == 1)
+ {
+ m_mcus_per_row = m_comp_h_blocks[m_comp_list[0]];
+ m_mcus_per_col = m_comp_v_blocks[m_comp_list[0]];
+ }
+ else
+ {
+ m_mcus_per_row = (((m_image_x_size + 7) / 8) + (max_h_samp - 1)) / max_h_samp;
+ m_mcus_per_col = (((m_image_y_size + 7) / 8) + (max_v_samp - 1)) / max_v_samp;
+ }
+
+ if (m_comps_in_scan == 1)
+ {
+ m_mcu_org[0] = m_comp_list[0];
+
+ m_blocks_per_mcu = 1;
+ }
+ else
+ {
+ m_blocks_per_mcu = 0;
+
+ for (component_num = 0; component_num < m_comps_in_scan; component_num++)
+ {
+ int num_blocks;
+
+ component_id = m_comp_list[component_num];
+
+ num_blocks = m_comp_h_samp[component_id] * m_comp_v_samp[component_id];
+
+ while (num_blocks--)
+ m_mcu_org[m_blocks_per_mcu++] = component_id;
+ }
+ }
+}
+
+// Starts a new scan.
+int jpeg_decoder::init_scan()
+{
+ if (!locate_sos_marker())
+ return JPGD_FALSE;
+
+ calc_mcu_block_order();
+
+ check_huff_tables();
+
+ check_quant_tables();
+
+ memset(m_last_dc_val, 0, m_comps_in_frame * sizeof(uint));
+
+ m_eob_run = 0;
+
+ if (m_restart_interval)
+ {
+ m_restarts_left = m_restart_interval;
+ m_next_restart_num = 0;
+ }
+
+ fix_in_buffer();
+
+ return JPGD_TRUE;
+}
+
+// Starts a frame. Determines if the number of components or sampling factors
+// are supported.
+void jpeg_decoder::init_frame()
+{
+ int i;
+
+ if (m_comps_in_frame == 1)
+ {
+ if ((m_comp_h_samp[0] != 1) || (m_comp_v_samp[0] != 1))
+ stop_decoding(JPGD_UNSUPPORTED_SAMP_FACTORS);
+
+ m_scan_type = JPGD_GRAYSCALE;
+ m_max_blocks_per_mcu = 1;
+ m_max_mcu_x_size = 8;
+ m_max_mcu_y_size = 8;
+ }
+ else if (m_comps_in_frame == 3)
+ {
+ if ( ((m_comp_h_samp[1] != 1) || (m_comp_v_samp[1] != 1)) ||
+ ((m_comp_h_samp[2] != 1) || (m_comp_v_samp[2] != 1)) )
+ stop_decoding(JPGD_UNSUPPORTED_SAMP_FACTORS);
+
+ if ((m_comp_h_samp[0] == 1) && (m_comp_v_samp[0] == 1))
+ {
+ m_scan_type = JPGD_YH1V1;
+
+ m_max_blocks_per_mcu = 3;
+ m_max_mcu_x_size = 8;
+ m_max_mcu_y_size = 8;
+ }
+ else if ((m_comp_h_samp[0] == 2) && (m_comp_v_samp[0] == 1))
+ {
+ m_scan_type = JPGD_YH2V1;
+ m_max_blocks_per_mcu = 4;
+ m_max_mcu_x_size = 16;
+ m_max_mcu_y_size = 8;
+ }
+ else if ((m_comp_h_samp[0] == 1) && (m_comp_v_samp[0] == 2))
+ {
+ m_scan_type = JPGD_YH1V2;
+ m_max_blocks_per_mcu = 4;
+ m_max_mcu_x_size = 8;
+ m_max_mcu_y_size = 16;
+ }
+ else if ((m_comp_h_samp[0] == 2) && (m_comp_v_samp[0] == 2))
+ {
+ m_scan_type = JPGD_YH2V2;
+ m_max_blocks_per_mcu = 6;
+ m_max_mcu_x_size = 16;
+ m_max_mcu_y_size = 16;
+ }
+ else
+ stop_decoding(JPGD_UNSUPPORTED_SAMP_FACTORS);
+ }
+ else
+ stop_decoding(JPGD_UNSUPPORTED_COLORSPACE);
+
+ m_max_mcus_per_row = (m_image_x_size + (m_max_mcu_x_size - 1)) / m_max_mcu_x_size;
+ m_max_mcus_per_col = (m_image_y_size + (m_max_mcu_y_size - 1)) / m_max_mcu_y_size;
+
+ // These values are for the *destination* pixels: after conversion.
+ if (m_scan_type == JPGD_GRAYSCALE)
+ m_dest_bytes_per_pixel = 1;
+ else
+ m_dest_bytes_per_pixel = 4;
+
+ m_dest_bytes_per_scan_line = ((m_image_x_size + 15) & 0xFFF0) * m_dest_bytes_per_pixel;
+
+ m_real_dest_bytes_per_scan_line = (m_image_x_size * m_dest_bytes_per_pixel);
+
+ // Initialize two scan line buffers.
+ m_pScan_line_0 = (uint8 *)alloc(m_dest_bytes_per_scan_line, true);
+ if ((m_scan_type == JPGD_YH1V2) || (m_scan_type == JPGD_YH2V2))
+ m_pScan_line_1 = (uint8 *)alloc(m_dest_bytes_per_scan_line, true);
+
+ m_max_blocks_per_row = m_max_mcus_per_row * m_max_blocks_per_mcu;
+
+ // Should never happen
+ if (m_max_blocks_per_row > JPGD_MAX_BLOCKS_PER_ROW)
+ stop_decoding(JPGD_ASSERTION_ERROR);
+
+ // Allocate the coefficient buffer, enough for one MCU
+ m_pMCU_coefficients = (jpgd_block_t*)alloc(m_max_blocks_per_mcu * 64 * sizeof(jpgd_block_t));
+
+ for (i = 0; i < m_max_blocks_per_mcu; i++)
+ m_mcu_block_max_zag[i] = 64;
+
+ m_expanded_blocks_per_component = m_comp_h_samp[0] * m_comp_v_samp[0];
+ m_expanded_blocks_per_mcu = m_expanded_blocks_per_component * m_comps_in_frame;
+ m_expanded_blocks_per_row = m_max_mcus_per_row * m_expanded_blocks_per_mcu;
+ // Freq. domain chroma upsampling is only supported for H2V2 subsampling factor (the most common one I've seen).
+ m_freq_domain_chroma_upsample = false;
+#if JPGD_SUPPORT_FREQ_DOMAIN_UPSAMPLING
+ m_freq_domain_chroma_upsample = (m_expanded_blocks_per_mcu == 4*3);
+#endif
+
+ if (m_freq_domain_chroma_upsample)
+ m_pSample_buf = (uint8 *)alloc(m_expanded_blocks_per_row * 64);
+ else
+ m_pSample_buf = (uint8 *)alloc(m_max_blocks_per_row * 64);
+
+ m_total_lines_left = m_image_y_size;
+
+ m_mcu_lines_left = 0;
+
+ create_look_ups();
+}
+
+// The coeff_buf series of methods originally stored the coefficients
+// into a "virtual" file which was located in EMS, XMS, or a disk file. A cache
+// was used to make this process more efficient. Now, we can store the entire
+// thing in RAM.
+jpeg_decoder::coeff_buf* jpeg_decoder::coeff_buf_open(int block_num_x, int block_num_y, int block_len_x, int block_len_y)
+{
+ coeff_buf* cb = (coeff_buf*)alloc(sizeof(coeff_buf));
+
+ cb->block_num_x = block_num_x;
+ cb->block_num_y = block_num_y;
+ cb->block_len_x = block_len_x;
+ cb->block_len_y = block_len_y;
+ cb->block_size = (block_len_x * block_len_y) * sizeof(jpgd_block_t);
+ cb->pData = (uint8 *)alloc(cb->block_size * block_num_x * block_num_y, true);
+ return cb;
+}
+
+inline jpgd_block_t *jpeg_decoder::coeff_buf_getp(coeff_buf *cb, int block_x, int block_y)
+{
+ JPGD_ASSERT((block_x < cb->block_num_x) && (block_y < cb->block_num_y));
+ return (jpgd_block_t *)(cb->pData + block_x * cb->block_size + block_y * (cb->block_size * cb->block_num_x));
+}
+
+// The following methods decode the various types of m_blocks encountered
+// in progressively encoded images.
+void jpeg_decoder::decode_block_dc_first(jpeg_decoder *pD, int component_id, int block_x, int block_y)
+{
+ int s, r;
+ jpgd_block_t *p = pD->coeff_buf_getp(pD->m_dc_coeffs[component_id], block_x, block_y);
+
+ if ((s = pD->huff_decode(pD->m_pHuff_tabs[pD->m_comp_dc_tab[component_id]])) != 0)
+ {
+ r = pD->get_bits_no_markers(s);
+ s = JPGD_HUFF_EXTEND(r, s);
+ }
+
+ pD->m_last_dc_val[component_id] = (s += pD->m_last_dc_val[component_id]);
+
+ p[0] = static_cast<jpgd_block_t>(s << pD->m_successive_low);
+}
+
+void jpeg_decoder::decode_block_dc_refine(jpeg_decoder *pD, int component_id, int block_x, int block_y)
+{
+ if (pD->get_bits_no_markers(1))
+ {
+ jpgd_block_t *p = pD->coeff_buf_getp(pD->m_dc_coeffs[component_id], block_x, block_y);
+
+ p[0] |= (1 << pD->m_successive_low);
+ }
+}
+
+void jpeg_decoder::decode_block_ac_first(jpeg_decoder *pD, int component_id, int block_x, int block_y)
+{
+ int k, s, r;
+
+ if (pD->m_eob_run)
+ {
+ pD->m_eob_run--;
+ return;
+ }
+
+ jpgd_block_t *p = pD->coeff_buf_getp(pD->m_ac_coeffs[component_id], block_x, block_y);
+
+ for (k = pD->m_spectral_start; k <= pD->m_spectral_end; k++)
+ {
+ s = pD->huff_decode(pD->m_pHuff_tabs[pD->m_comp_ac_tab[component_id]]);
+
+ r = s >> 4;
+ s &= 15;
+
+ if (s)
+ {
+ if ((k += r) > 63)
+ pD->stop_decoding(JPGD_DECODE_ERROR);
+
+ r = pD->get_bits_no_markers(s);
+ s = JPGD_HUFF_EXTEND(r, s);
+
+ p[g_ZAG[k]] = static_cast<jpgd_block_t>(s << pD->m_successive_low);
+ }
+ else
+ {
+ if (r == 15)
+ {
+ if ((k += 15) > 63)
+ pD->stop_decoding(JPGD_DECODE_ERROR);
+ }
+ else
+ {
+ pD->m_eob_run = 1 << r;
+
+ if (r)
+ pD->m_eob_run += pD->get_bits_no_markers(r);
+
+ pD->m_eob_run--;
+
+ break;
+ }
+ }
+ }
+}
+
+void jpeg_decoder::decode_block_ac_refine(jpeg_decoder *pD, int component_id, int block_x, int block_y)
+{
+ int s, k, r;
+ int p1 = 1 << pD->m_successive_low;
+ int m1 = (-1) << pD->m_successive_low;
+ jpgd_block_t *p = pD->coeff_buf_getp(pD->m_ac_coeffs[component_id], block_x, block_y);
+
+ JPGD_ASSERT(pD->m_spectral_end <= 63);
+
+ k = pD->m_spectral_start;
+
+ if (pD->m_eob_run == 0)
+ {
+ for ( ; k <= pD->m_spectral_end; k++)
+ {
+ s = pD->huff_decode(pD->m_pHuff_tabs[pD->m_comp_ac_tab[component_id]]);
+
+ r = s >> 4;
+ s &= 15;
+
+ if (s)
+ {
+ if (s != 1)
+ pD->stop_decoding(JPGD_DECODE_ERROR);
+
+ if (pD->get_bits_no_markers(1))
+ s = p1;
+ else
+ s = m1;
+ }
+ else
+ {
+ if (r != 15)
+ {
+ pD->m_eob_run = 1 << r;
+
+ if (r)
+ pD->m_eob_run += pD->get_bits_no_markers(r);
+
+ break;
+ }
+ }
+
+ do
+ {
+ jpgd_block_t *this_coef = p + g_ZAG[k & 63];
+
+ if (*this_coef != 0)
+ {
+ if (pD->get_bits_no_markers(1))
+ {
+ if ((*this_coef & p1) == 0)
+ {
+ if (*this_coef >= 0)
+ *this_coef = static_cast<jpgd_block_t>(*this_coef + p1);
+ else
+ *this_coef = static_cast<jpgd_block_t>(*this_coef + m1);
+ }
+ }
+ }
+ else
+ {
+ if (--r < 0)
+ break;
+ }
+
+ k++;
+
+ } while (k <= pD->m_spectral_end);
+
+ if ((s) && (k < 64))
+ {
+ p[g_ZAG[k]] = static_cast<jpgd_block_t>(s);
+ }
+ }
+ }
+
+ if (pD->m_eob_run > 0)
+ {
+ for ( ; k <= pD->m_spectral_end; k++)
+ {
+ jpgd_block_t *this_coef = p + g_ZAG[k & 63]; // logical AND to shut up static code analysis
+
+ if (*this_coef != 0)
+ {
+ if (pD->get_bits_no_markers(1))
+ {
+ if ((*this_coef & p1) == 0)
+ {
+ if (*this_coef >= 0)
+ *this_coef = static_cast<jpgd_block_t>(*this_coef + p1);
+ else
+ *this_coef = static_cast<jpgd_block_t>(*this_coef + m1);
+ }
+ }
+ }
+ }
+
+ pD->m_eob_run--;
+ }
+}
+
+// Decode a scan in a progressively encoded image.
+void jpeg_decoder::decode_scan(pDecode_block_func decode_block_func)
+{
+ int mcu_row, mcu_col, mcu_block;
+ int block_x_mcu[JPGD_MAX_COMPONENTS], m_block_y_mcu[JPGD_MAX_COMPONENTS];
+
+ memset(m_block_y_mcu, 0, sizeof(m_block_y_mcu));
+
+ for (mcu_col = 0; mcu_col < m_mcus_per_col; mcu_col++)
+ {
+ int component_num, component_id;
+
+ memset(block_x_mcu, 0, sizeof(block_x_mcu));
+
+ for (mcu_row = 0; mcu_row < m_mcus_per_row; mcu_row++)
+ {
+ int block_x_mcu_ofs = 0, block_y_mcu_ofs = 0;
+
+ if ((m_restart_interval) && (m_restarts_left == 0))
+ process_restart();
+
+ for (mcu_block = 0; mcu_block < m_blocks_per_mcu; mcu_block++)
+ {
+ component_id = m_mcu_org[mcu_block];
+
+ decode_block_func(this, component_id, block_x_mcu[component_id] + block_x_mcu_ofs, m_block_y_mcu[component_id] + block_y_mcu_ofs);
+
+ if (m_comps_in_scan == 1)
+ block_x_mcu[component_id]++;
+ else
+ {
+ if (++block_x_mcu_ofs == m_comp_h_samp[component_id])
+ {
+ block_x_mcu_ofs = 0;
+
+ if (++block_y_mcu_ofs == m_comp_v_samp[component_id])
+ {
+ block_y_mcu_ofs = 0;
+ block_x_mcu[component_id] += m_comp_h_samp[component_id];
+ }
+ }
+ }
+ }
+
+ m_restarts_left--;
+ }
+
+ if (m_comps_in_scan == 1)
+ m_block_y_mcu[m_comp_list[0]]++;
+ else
+ {
+ for (component_num = 0; component_num < m_comps_in_scan; component_num++)
+ {
+ component_id = m_comp_list[component_num];
+ m_block_y_mcu[component_id] += m_comp_v_samp[component_id];
+ }
+ }
+ }
+}
+
+// Decode a progressively encoded image.
+void jpeg_decoder::init_progressive()
+{
+ int i;
+
+ if (m_comps_in_frame == 4)
+ stop_decoding(JPGD_UNSUPPORTED_COLORSPACE);
+
+ // Allocate the coefficient buffers.
+ for (i = 0; i < m_comps_in_frame; i++)
+ {
+ m_dc_coeffs[i] = coeff_buf_open(m_max_mcus_per_row * m_comp_h_samp[i], m_max_mcus_per_col * m_comp_v_samp[i], 1, 1);
+ m_ac_coeffs[i] = coeff_buf_open(m_max_mcus_per_row * m_comp_h_samp[i], m_max_mcus_per_col * m_comp_v_samp[i], 8, 8);
+ }
+
+ for ( ; ; )
+ {
+ int dc_only_scan, refinement_scan;
+ pDecode_block_func decode_block_func;
+
+ if (!init_scan())
+ break;
+
+ dc_only_scan = (m_spectral_start == 0);
+ refinement_scan = (m_successive_high != 0);
+
+ if ((m_spectral_start > m_spectral_end) || (m_spectral_end > 63))
+ stop_decoding(JPGD_BAD_SOS_SPECTRAL);
+
+ if (dc_only_scan)
+ {
+ if (m_spectral_end)
+ stop_decoding(JPGD_BAD_SOS_SPECTRAL);
+ }
+ else if (m_comps_in_scan != 1) /* AC scans can only contain one component */
+ stop_decoding(JPGD_BAD_SOS_SPECTRAL);
+
+ if ((refinement_scan) && (m_successive_low != m_successive_high - 1))
+ stop_decoding(JPGD_BAD_SOS_SUCCESSIVE);
+
+ if (dc_only_scan)
+ {
+ if (refinement_scan)
+ decode_block_func = decode_block_dc_refine;
+ else
+ decode_block_func = decode_block_dc_first;
+ }
+ else
+ {
+ if (refinement_scan)
+ decode_block_func = decode_block_ac_refine;
+ else
+ decode_block_func = decode_block_ac_first;
+ }
+
+ decode_scan(decode_block_func);
+
+ m_bits_left = 16;
+ get_bits(16);
+ get_bits(16);
+ }
+
+ m_comps_in_scan = m_comps_in_frame;
+
+ for (i = 0; i < m_comps_in_frame; i++)
+ m_comp_list[i] = i;
+
+ calc_mcu_block_order();
+}
+
+void jpeg_decoder::init_sequential()
+{
+ if (!init_scan())
+ stop_decoding(JPGD_UNEXPECTED_MARKER);
+}
+
+void jpeg_decoder::decode_start()
+{
+ init_frame();
+
+ if (m_progressive_flag)
+ init_progressive();
+ else
+ init_sequential();
+}
+
+void jpeg_decoder::decode_init(jpeg_decoder_stream *pStream)
+{
+ init(pStream);
+ locate_sof_marker();
+}
+
+jpeg_decoder::jpeg_decoder(jpeg_decoder_stream *pStream)
+{
+ if (setjmp(m_jmp_state))
+ return;
+ decode_init(pStream);
+}
+
+int jpeg_decoder::begin_decoding()
+{
+ if (m_ready_flag)
+ return JPGD_SUCCESS;
+
+ if (m_error_code)
+ return JPGD_FAILED;
+
+ if (setjmp(m_jmp_state))
+ return JPGD_FAILED;
+
+ decode_start();
+
+ m_ready_flag = true;
+
+ return JPGD_SUCCESS;
+}
+
+jpeg_decoder::~jpeg_decoder()
+{
+ free_all_blocks();
+}
+
+jpeg_decoder_file_stream::jpeg_decoder_file_stream()
+{
+ m_pFile = NULL;
+ m_eof_flag = false;
+ m_error_flag = false;
+}
+
+void jpeg_decoder_file_stream::close()
+{
+ if (m_pFile)
+ {
+ fclose(m_pFile);
+ m_pFile = NULL;
+ }
+
+ m_eof_flag = false;
+ m_error_flag = false;
+}
+
+jpeg_decoder_file_stream::~jpeg_decoder_file_stream()
+{
+ close();
+}
+
+bool jpeg_decoder_file_stream::open(const char *Pfilename)
+{
+ close();
+
+ m_eof_flag = false;
+ m_error_flag = false;
+
+#if defined(_MSC_VER)
+ m_pFile = NULL;
+ fopen_s(&m_pFile, Pfilename, "rb");
+#else
+ m_pFile = fopen(Pfilename, "rb");
+#endif
+ return m_pFile != NULL;
+}
+
+int jpeg_decoder_file_stream::read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag)
+{
+ if (!m_pFile)
+ return -1;
+
+ if (m_eof_flag)
+ {
+ *pEOF_flag = true;
+ return 0;
+ }
+
+ if (m_error_flag)
+ return -1;
+
+ int bytes_read = static_cast<int>(fread(pBuf, 1, max_bytes_to_read, m_pFile));
+ if (bytes_read < max_bytes_to_read)
+ {
+ if (ferror(m_pFile))
+ {
+ m_error_flag = true;
+ return -1;
+ }
+
+ m_eof_flag = true;
+ *pEOF_flag = true;
+ }
+
+ return bytes_read;
+}
+
+bool jpeg_decoder_mem_stream::open(const uint8 *pSrc_data, uint size)
+{
+ close();
+ m_pSrc_data = pSrc_data;
+ m_ofs = 0;
+ m_size = size;
+ return true;
+}
+
+int jpeg_decoder_mem_stream::read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag)
+{
+ *pEOF_flag = false;
+
+ if (!m_pSrc_data)
+ return -1;
+
+ uint bytes_remaining = m_size - m_ofs;
+ if ((uint)max_bytes_to_read > bytes_remaining)
+ {
+ max_bytes_to_read = bytes_remaining;
+ *pEOF_flag = true;
+ }
+
+ memcpy(pBuf, m_pSrc_data + m_ofs, max_bytes_to_read);
+ m_ofs += max_bytes_to_read;
+
+ return max_bytes_to_read;
+}
+
+unsigned char *decompress_jpeg_image_from_stream(jpeg_decoder_stream *pStream, int *width, int *height, int *actual_comps, int req_comps)
+{
+ if (!actual_comps)
+ return NULL;
+ *actual_comps = 0;
+
+ if ((!pStream) || (!width) || (!height) || (!req_comps))
+ return NULL;
+
+ if ((req_comps != 1) && (req_comps != 3) && (req_comps != 4))
+ return NULL;
+
+ jpeg_decoder decoder(pStream);
+ if (decoder.get_error_code() != JPGD_SUCCESS)
+ return NULL;
+
+ const int image_width = decoder.get_width(), image_height = decoder.get_height();
+ *width = image_width;
+ *height = image_height;
+ *actual_comps = decoder.get_num_components();
+
+ if (decoder.begin_decoding() != JPGD_SUCCESS)
+ return NULL;
+
+ const int dst_bpl = image_width * req_comps;
+
+ uint8 *pImage_data = (uint8*)jpgd_malloc(dst_bpl * image_height);
+ if (!pImage_data)
+ return NULL;
+
+ for (int y = 0; y < image_height; y++)
+ {
+ const uint8* pScan_line;
+ uint scan_line_len;
+ if (decoder.decode((const void**)&pScan_line, &scan_line_len) != JPGD_SUCCESS)
+ {
+ jpgd_free(pImage_data);
+ return NULL;
+ }
+
+ uint8 *pDst = pImage_data + y * dst_bpl;
+
+ if (((req_comps == 1) && (decoder.get_num_components() == 1)) || ((req_comps == 4) && (decoder.get_num_components() == 3)))
+ memcpy(pDst, pScan_line, dst_bpl);
+ else if (decoder.get_num_components() == 1)
+ {
+ if (req_comps == 3)
+ {
+ for (int x = 0; x < image_width; x++)
+ {
+ uint8 luma = pScan_line[x];
+ pDst[0] = luma;
+ pDst[1] = luma;
+ pDst[2] = luma;
+ pDst += 3;
+ }
+ }
+ else
+ {
+ for (int x = 0; x < image_width; x++)
+ {
+ uint8 luma = pScan_line[x];
+ pDst[0] = luma;
+ pDst[1] = luma;
+ pDst[2] = luma;
+ pDst[3] = 255;
+ pDst += 4;
+ }
+ }
+ }
+ else if (decoder.get_num_components() == 3)
+ {
+ if (req_comps == 1)
+ {
+ const int YR = 19595, YG = 38470, YB = 7471;
+ for (int x = 0; x < image_width; x++)
+ {
+ int r = pScan_line[x*4+0];
+ int g = pScan_line[x*4+1];
+ int b = pScan_line[x*4+2];
+ *pDst++ = static_cast<uint8>((r * YR + g * YG + b * YB + 32768) >> 16);
+ }
+ }
+ else
+ {
+ for (int x = 0; x < image_width; x++)
+ {
+ pDst[0] = pScan_line[x*4+0];
+ pDst[1] = pScan_line[x*4+1];
+ pDst[2] = pScan_line[x*4+2];
+ pDst += 3;
+ }
+ }
+ }
+ }
+
+ return pImage_data;
+}
+
+unsigned char *decompress_jpeg_image_from_memory(const unsigned char *pSrc_data, int src_data_size, int *width, int *height, int *actual_comps, int req_comps)
+{
+ jpgd::jpeg_decoder_mem_stream mem_stream(pSrc_data, src_data_size);
+ return decompress_jpeg_image_from_stream(&mem_stream, width, height, actual_comps, req_comps);
+}
+
+unsigned char *decompress_jpeg_image_from_file(const char *pSrc_filename, int *width, int *height, int *actual_comps, int req_comps)
+{
+ jpgd::jpeg_decoder_file_stream file_stream;
+ if (!file_stream.open(pSrc_filename))
+ return NULL;
+ return decompress_jpeg_image_from_stream(&file_stream, width, height, actual_comps, req_comps);
+}
+
+} // namespace jpgd \ No newline at end of file
diff --git a/drivers/jpegd/jpgd.h b/drivers/jpegd/jpgd.h
new file mode 100644
index 0000000000..150b9a0b26
--- /dev/null
+++ b/drivers/jpegd/jpgd.h
@@ -0,0 +1,319 @@
+// jpgd.h - C++ class for JPEG decompression.
+// Public domain, Rich Geldreich <richgel99@gmail.com>
+#ifndef JPEG_DECODER_H
+#define JPEG_DECODER_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <setjmp.h>
+
+#ifdef _MSC_VER
+ #define JPGD_NORETURN __declspec(noreturn)
+#elif defined(__GNUC__)
+ #define JPGD_NORETURN __attribute__ ((noreturn))
+#else
+ #define JPGD_NORETURN
+#endif
+
+namespace jpgd
+{
+ typedef unsigned char uint8;
+ typedef signed short int16;
+ typedef unsigned short uint16;
+ typedef unsigned int uint;
+ typedef signed int int32;
+
+ // Loads a JPEG image from a memory buffer or a file.
+ // req_comps can be 1 (grayscale), 3 (RGB), or 4 (RGBA).
+ // On return, width/height will be set to the image's dimensions, and actual_comps will be set to the either 1 (grayscale) or 3 (RGB).
+ // Notes: For more control over where and how the source data is read, see the decompress_jpeg_image_from_stream() function below, or call the jpeg_decoder class directly.
+ // Requesting a 8 or 32bpp image is currently a little faster than 24bpp because the jpeg_decoder class itself currently always unpacks to either 8 or 32bpp.
+ unsigned char *decompress_jpeg_image_from_memory(const unsigned char *pSrc_data, int src_data_size, int *width, int *height, int *actual_comps, int req_comps);
+ unsigned char *decompress_jpeg_image_from_file(const char *pSrc_filename, int *width, int *height, int *actual_comps, int req_comps);
+
+ // Success/failure error codes.
+ enum jpgd_status
+ {
+ JPGD_SUCCESS = 0, JPGD_FAILED = -1, JPGD_DONE = 1,
+ JPGD_BAD_DHT_COUNTS = -256, JPGD_BAD_DHT_INDEX, JPGD_BAD_DHT_MARKER, JPGD_BAD_DQT_MARKER, JPGD_BAD_DQT_TABLE,
+ JPGD_BAD_PRECISION, JPGD_BAD_HEIGHT, JPGD_BAD_WIDTH, JPGD_TOO_MANY_COMPONENTS,
+ JPGD_BAD_SOF_LENGTH, JPGD_BAD_VARIABLE_MARKER, JPGD_BAD_DRI_LENGTH, JPGD_BAD_SOS_LENGTH,
+ JPGD_BAD_SOS_COMP_ID, JPGD_W_EXTRA_BYTES_BEFORE_MARKER, JPGD_NO_ARITHMITIC_SUPPORT, JPGD_UNEXPECTED_MARKER,
+ JPGD_NOT_JPEG, JPGD_UNSUPPORTED_MARKER, JPGD_BAD_DQT_LENGTH, JPGD_TOO_MANY_BLOCKS,
+ JPGD_UNDEFINED_QUANT_TABLE, JPGD_UNDEFINED_HUFF_TABLE, JPGD_NOT_SINGLE_SCAN, JPGD_UNSUPPORTED_COLORSPACE,
+ JPGD_UNSUPPORTED_SAMP_FACTORS, JPGD_DECODE_ERROR, JPGD_BAD_RESTART_MARKER, JPGD_ASSERTION_ERROR,
+ JPGD_BAD_SOS_SPECTRAL, JPGD_BAD_SOS_SUCCESSIVE, JPGD_STREAM_READ, JPGD_NOTENOUGHMEM
+ };
+
+ // Input stream interface.
+ // Derive from this class to read input data from sources other than files or memory. Set m_eof_flag to true when no more data is available.
+ // The decoder is rather greedy: it will keep on calling this method until its internal input buffer is full, or until the EOF flag is set.
+ // It the input stream contains data after the JPEG stream's EOI (end of image) marker it will probably be pulled into the internal buffer.
+ // Call the get_total_bytes_read() method to determine the actual size of the JPEG stream after successful decoding.
+ class jpeg_decoder_stream
+ {
+ public:
+ jpeg_decoder_stream() { }
+ virtual ~jpeg_decoder_stream() { }
+
+ // The read() method is called when the internal input buffer is empty.
+ // Parameters:
+ // pBuf - input buffer
+ // max_bytes_to_read - maximum bytes that can be written to pBuf
+ // pEOF_flag - set this to true if at end of stream (no more bytes remaining)
+ // Returns -1 on error, otherwise return the number of bytes actually written to the buffer (which may be 0).
+ // Notes: This method will be called in a loop until you set *pEOF_flag to true or the internal buffer is full.
+ virtual int read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag) = 0;
+ };
+
+ // stdio FILE stream class.
+ class jpeg_decoder_file_stream : public jpeg_decoder_stream
+ {
+ jpeg_decoder_file_stream(const jpeg_decoder_file_stream &);
+ jpeg_decoder_file_stream &operator =(const jpeg_decoder_file_stream &);
+
+ FILE *m_pFile;
+ bool m_eof_flag, m_error_flag;
+
+ public:
+ jpeg_decoder_file_stream();
+ virtual ~jpeg_decoder_file_stream();
+
+ bool open(const char *Pfilename);
+ void close();
+
+ virtual int read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag);
+ };
+
+ // Memory stream class.
+ class jpeg_decoder_mem_stream : public jpeg_decoder_stream
+ {
+ const uint8 *m_pSrc_data;
+ uint m_ofs, m_size;
+
+ public:
+ jpeg_decoder_mem_stream() : m_pSrc_data(NULL), m_ofs(0), m_size(0) { }
+ jpeg_decoder_mem_stream(const uint8 *pSrc_data, uint size) : m_pSrc_data(pSrc_data), m_ofs(0), m_size(size) { }
+
+ virtual ~jpeg_decoder_mem_stream() { }
+
+ bool open(const uint8 *pSrc_data, uint size);
+ void close() { m_pSrc_data = NULL; m_ofs = 0; m_size = 0; }
+
+ virtual int read(uint8 *pBuf, int max_bytes_to_read, bool *pEOF_flag);
+ };
+
+ // Loads JPEG file from a jpeg_decoder_stream.
+ unsigned char *decompress_jpeg_image_from_stream(jpeg_decoder_stream *pStream, int *width, int *height, int *actual_comps, int req_comps);
+
+ enum
+ {
+ JPGD_IN_BUF_SIZE = 8192, JPGD_MAX_BLOCKS_PER_MCU = 10, JPGD_MAX_HUFF_TABLES = 8, JPGD_MAX_QUANT_TABLES = 4,
+ JPGD_MAX_COMPONENTS = 4, JPGD_MAX_COMPS_IN_SCAN = 4, JPGD_MAX_BLOCKS_PER_ROW = 8192, JPGD_MAX_HEIGHT = 16384, JPGD_MAX_WIDTH = 16384
+ };
+
+ typedef int16 jpgd_quant_t;
+ typedef int16 jpgd_block_t;
+
+ class jpeg_decoder
+ {
+ public:
+ // Call get_error_code() after constructing to determine if the stream is valid or not. You may call the get_width(), get_height(), etc.
+ // methods after the constructor is called. You may then either destruct the object, or begin decoding the image by calling begin_decoding(), then decode() on each scanline.
+ jpeg_decoder(jpeg_decoder_stream *pStream);
+
+ ~jpeg_decoder();
+
+ // Call this method after constructing the object to begin decompression.
+ // If JPGD_SUCCESS is returned you may then call decode() on each scanline.
+ int begin_decoding();
+
+ // Returns the next scan line.
+ // For grayscale images, pScan_line will point to a buffer containing 8-bit pixels (get_bytes_per_pixel() will return 1).
+ // Otherwise, it will always point to a buffer containing 32-bit RGBA pixels (A will always be 255, and get_bytes_per_pixel() will return 4).
+ // Returns JPGD_SUCCESS if a scan line has been returned.
+ // Returns JPGD_DONE if all scan lines have been returned.
+ // Returns JPGD_FAILED if an error occurred. Call get_error_code() for a more info.
+ int decode(const void** pScan_line, uint* pScan_line_len);
+
+ inline jpgd_status get_error_code() const { return m_error_code; }
+
+ inline int get_width() const { return m_image_x_size; }
+ inline int get_height() const { return m_image_y_size; }
+
+ inline int get_num_components() const { return m_comps_in_frame; }
+
+ inline int get_bytes_per_pixel() const { return m_dest_bytes_per_pixel; }
+ inline int get_bytes_per_scan_line() const { return m_image_x_size * get_bytes_per_pixel(); }
+
+ // Returns the total number of bytes actually consumed by the decoder (which should equal the actual size of the JPEG file).
+ inline int get_total_bytes_read() const { return m_total_bytes_read; }
+
+ private:
+ jpeg_decoder(const jpeg_decoder &);
+ jpeg_decoder &operator =(const jpeg_decoder &);
+
+ typedef void (*pDecode_block_func)(jpeg_decoder *, int, int, int);
+
+ struct huff_tables
+ {
+ bool ac_table;
+ uint look_up[256];
+ uint look_up2[256];
+ uint8 code_size[256];
+ uint tree[512];
+ };
+
+ struct coeff_buf
+ {
+ uint8 *pData;
+ int block_num_x, block_num_y;
+ int block_len_x, block_len_y;
+ int block_size;
+ };
+
+ struct mem_block
+ {
+ mem_block *m_pNext;
+ size_t m_used_count;
+ size_t m_size;
+ char m_data[1];
+ };
+
+ jmp_buf m_jmp_state;
+ mem_block *m_pMem_blocks;
+ int m_image_x_size;
+ int m_image_y_size;
+ jpeg_decoder_stream *m_pStream;
+ int m_progressive_flag;
+ uint8 m_huff_ac[JPGD_MAX_HUFF_TABLES];
+ uint8* m_huff_num[JPGD_MAX_HUFF_TABLES]; // pointer to number of Huffman codes per bit size
+ uint8* m_huff_val[JPGD_MAX_HUFF_TABLES]; // pointer to Huffman codes per bit size
+ jpgd_quant_t* m_quant[JPGD_MAX_QUANT_TABLES]; // pointer to quantization tables
+ int m_scan_type; // Gray, Yh1v1, Yh1v2, Yh2v1, Yh2v2 (CMYK111, CMYK4114 no longer supported)
+ int m_comps_in_frame; // # of components in frame
+ int m_comp_h_samp[JPGD_MAX_COMPONENTS]; // component's horizontal sampling factor
+ int m_comp_v_samp[JPGD_MAX_COMPONENTS]; // component's vertical sampling factor
+ int m_comp_quant[JPGD_MAX_COMPONENTS]; // component's quantization table selector
+ int m_comp_ident[JPGD_MAX_COMPONENTS]; // component's ID
+ int m_comp_h_blocks[JPGD_MAX_COMPONENTS];
+ int m_comp_v_blocks[JPGD_MAX_COMPONENTS];
+ int m_comps_in_scan; // # of components in scan
+ int m_comp_list[JPGD_MAX_COMPS_IN_SCAN]; // components in this scan
+ int m_comp_dc_tab[JPGD_MAX_COMPONENTS]; // component's DC Huffman coding table selector
+ int m_comp_ac_tab[JPGD_MAX_COMPONENTS]; // component's AC Huffman coding table selector
+ int m_spectral_start; // spectral selection start
+ int m_spectral_end; // spectral selection end
+ int m_successive_low; // successive approximation low
+ int m_successive_high; // successive approximation high
+ int m_max_mcu_x_size; // MCU's max. X size in pixels
+ int m_max_mcu_y_size; // MCU's max. Y size in pixels
+ int m_blocks_per_mcu;
+ int m_max_blocks_per_row;
+ int m_mcus_per_row, m_mcus_per_col;
+ int m_mcu_org[JPGD_MAX_BLOCKS_PER_MCU];
+ int m_total_lines_left; // total # lines left in image
+ int m_mcu_lines_left; // total # lines left in this MCU
+ int m_real_dest_bytes_per_scan_line;
+ int m_dest_bytes_per_scan_line; // rounded up
+ int m_dest_bytes_per_pixel; // 4 (RGB) or 1 (Y)
+ huff_tables* m_pHuff_tabs[JPGD_MAX_HUFF_TABLES];
+ coeff_buf* m_dc_coeffs[JPGD_MAX_COMPONENTS];
+ coeff_buf* m_ac_coeffs[JPGD_MAX_COMPONENTS];
+ int m_eob_run;
+ int m_block_y_mcu[JPGD_MAX_COMPONENTS];
+ uint8* m_pIn_buf_ofs;
+ int m_in_buf_left;
+ int m_tem_flag;
+ bool m_eof_flag;
+ uint8 m_in_buf_pad_start[128];
+ uint8 m_in_buf[JPGD_IN_BUF_SIZE + 128];
+ uint8 m_in_buf_pad_end[128];
+ int m_bits_left;
+ uint m_bit_buf;
+ int m_restart_interval;
+ int m_restarts_left;
+ int m_next_restart_num;
+ int m_max_mcus_per_row;
+ int m_max_blocks_per_mcu;
+ int m_expanded_blocks_per_mcu;
+ int m_expanded_blocks_per_row;
+ int m_expanded_blocks_per_component;
+ bool m_freq_domain_chroma_upsample;
+ int m_max_mcus_per_col;
+ uint m_last_dc_val[JPGD_MAX_COMPONENTS];
+ jpgd_block_t* m_pMCU_coefficients;
+ int m_mcu_block_max_zag[JPGD_MAX_BLOCKS_PER_MCU];
+ uint8* m_pSample_buf;
+ int m_crr[256];
+ int m_cbb[256];
+ int m_crg[256];
+ int m_cbg[256];
+ uint8* m_pScan_line_0;
+ uint8* m_pScan_line_1;
+ jpgd_status m_error_code;
+ bool m_ready_flag;
+ int m_total_bytes_read;
+
+ void free_all_blocks();
+ JPGD_NORETURN void stop_decoding(jpgd_status status);
+ void *alloc(size_t n, bool zero = false);
+ void word_clear(void *p, uint16 c, uint n);
+ void prep_in_buffer();
+ void read_dht_marker();
+ void read_dqt_marker();
+ void read_sof_marker();
+ void skip_variable_marker();
+ void read_dri_marker();
+ void read_sos_marker();
+ int next_marker();
+ int process_markers();
+ void locate_soi_marker();
+ void locate_sof_marker();
+ int locate_sos_marker();
+ void init(jpeg_decoder_stream * pStream);
+ void create_look_ups();
+ void fix_in_buffer();
+ void transform_mcu(int mcu_row);
+ void transform_mcu_expand(int mcu_row);
+ coeff_buf* coeff_buf_open(int block_num_x, int block_num_y, int block_len_x, int block_len_y);
+ inline jpgd_block_t *coeff_buf_getp(coeff_buf *cb, int block_x, int block_y);
+ void load_next_row();
+ void decode_next_row();
+ void make_huff_table(int index, huff_tables *pH);
+ void check_quant_tables();
+ void check_huff_tables();
+ void calc_mcu_block_order();
+ int init_scan();
+ void init_frame();
+ void process_restart();
+ void decode_scan(pDecode_block_func decode_block_func);
+ void init_progressive();
+ void init_sequential();
+ void decode_start();
+ void decode_init(jpeg_decoder_stream * pStream);
+ void H2V2Convert();
+ void H2V1Convert();
+ void H1V2Convert();
+ void H1V1Convert();
+ void gray_convert();
+ void expanded_convert();
+ void find_eoi();
+ inline uint get_char();
+ inline uint get_char(bool *pPadding_flag);
+ inline void stuff_char(uint8 q);
+ inline uint8 get_octet();
+ inline uint get_bits(int num_bits);
+ inline uint get_bits_no_markers(int numbits);
+ inline int huff_decode(huff_tables *pH);
+ inline int huff_decode(huff_tables *pH, int& extrabits);
+ static inline uint8 clamp(int i);
+ static void decode_block_dc_first(jpeg_decoder *pD, int component_id, int block_x, int block_y);
+ static void decode_block_dc_refine(jpeg_decoder *pD, int component_id, int block_x, int block_y);
+ static void decode_block_ac_first(jpeg_decoder *pD, int component_id, int block_x, int block_y);
+ static void decode_block_ac_refine(jpeg_decoder *pD, int component_id, int block_x, int block_y);
+ };
+
+} // namespace jpgd
+
+#endif // JPEG_DECODER_H
diff --git a/drivers/jpg/SCsub b/drivers/jpg/SCsub
deleted file mode 100644
index e1fcc5ea89..0000000000
--- a/drivers/jpg/SCsub
+++ /dev/null
@@ -1,13 +0,0 @@
-Import('env')
-
-
-jpg_sources = [
- "jpg/tinyjpeg.c",
- "jpg/jidctflt.c",
- "jpg/image_loader_jpg.cpp"
- ]
-
-env.drivers_sources+=jpg_sources
-
-#env.add_source_files(env.drivers_sources, jpg_sources)
-
diff --git a/drivers/jpg/image_loader_jpg.cpp b/drivers/jpg/image_loader_jpg.cpp
deleted file mode 100644
index 76a8b25f62..0000000000
--- a/drivers/jpg/image_loader_jpg.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/*************************************************/
-/* image_loader_jpg.cpp */
-/*************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/*************************************************/
-/* Source code within this file is: */
-/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
-/* All Rights Reserved. */
-/*************************************************/
-
-#include "image_loader_jpg.h"
-
-#include "print_string.h"
-#include "os/os.h"
-#include "drivers/jpg/tinyjpeg.h"
-
-
-static void* _tinyjpg_alloc(unsigned int amount) {
-
- return memalloc(amount);
-}
-
-static void _tinyjpg_free(void *ptr) {
-
- memfree(ptr);
-}
-
-Error ImageLoaderJPG::load_image(Image *p_image,FileAccess *f) {
-
-
- DVector<uint8_t> src_image;
- int src_image_len = f->get_len();
- ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
- src_image.resize(src_image_len);
-
- DVector<uint8_t>::Write w = src_image.write();
-
- f->get_buffer(&w[0],src_image_len);
-
- f->close();
-
- jdec_private* jdec=tinyjpeg_init(_tinyjpg_alloc,_tinyjpg_free);
- ERR_FAIL_COND_V(!jdec,ERR_UNAVAILABLE);
-
- int ret = tinyjpeg_parse_header(jdec,&w[0],src_image_len);
-
- if (ret!=0) {
- tinyjpeg_free(jdec);
- }
-
- ERR_FAIL_COND_V(ret!=0,ERR_FILE_CORRUPT);
-
- unsigned int width,height;
-
-
- tinyjpeg_get_size(jdec,&width,&height);
-
-
-
- DVector<uint8_t> imgdata;
- imgdata.resize(width*height*3);
- DVector<uint8_t>::Write imgdataw = imgdata.write();
-
-
- unsigned char *components[1]={&imgdataw[0]};
- tinyjpeg_set_components(jdec,components,1);
- tinyjpeg_decode(jdec,TINYJPEG_FMT_RGB24);
- imgdataw = DVector<uint8_t>::Write();
-
- Image dst_image(width,height,0,Image::FORMAT_RGB,imgdata);
-
- tinyjpeg_free(jdec);
-
- *p_image=dst_image;
-
- return OK;
-
-}
-
-void ImageLoaderJPG::get_recognized_extensions(List<String> *p_extensions) const {
-
- p_extensions->push_back("jpg");
- p_extensions->push_back("jpeg");
-}
-
-
-ImageLoaderJPG::ImageLoaderJPG() {
-
-
-}
-
-
diff --git a/drivers/jpg/image_loader_jpg.h b/drivers/jpg/image_loader_jpg.h
deleted file mode 100644
index b1d5b8016f..0000000000
--- a/drivers/jpg/image_loader_jpg.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*************************************************/
-/* image_loader_jpg.h */
-/*************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/*************************************************/
-/* Source code within this file is: */
-/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
-/* All Rights Reserved. */
-/*************************************************/
-
-#ifndef IMAGE_LOADER_JPG_H
-#define IMAGE_LOADER_JPG_H
-
-#include "io/image_loader.h"
-
-/**
- @author Juan Linietsky <reduzio@gmail.com>
-*/
-class ImageLoaderJPG : public ImageFormatLoader {
-
-
-public:
-
- virtual Error load_image(Image *p_image,FileAccess *f);
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
- ImageLoaderJPG();
-};
-
-
-
-#endif
diff --git a/drivers/jpg/jidctflt.c b/drivers/jpg/jidctflt.c
deleted file mode 100644
index 40a9eab83e..0000000000
--- a/drivers/jpg/jidctflt.c
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * jidctflt.c
- *
- * Copyright (C) 1994-1998, Thomas G. Lane.
- * This file is part of the Independent JPEG Group's software.
- *
- * The authors make NO WARRANTY or representation, either express or implied,
- * with respect to this software, its quality, accuracy, merchantability, or
- * fitness for a particular purpose. This software is provided "AS IS", and you,
- * its user, assume the entire risk as to its quality and accuracy.
- *
- * This software is copyright (C) 1991-1998, Thomas G. Lane.
- * All Rights Reserved except as specified below.
- *
- * Permission is hereby granted to use, copy, modify, and distribute this
- * software (or portions thereof) for any purpose, without fee, subject to these
- * conditions:
- * (1) If any part of the source code for this software is distributed, then this
- * README file must be included, with this copyright and no-warranty notice
- * unaltered; and any additions, deletions, or changes to the original files
- * must be clearly indicated in accompanying documentation.
- * (2) If only executable code is distributed, then the accompanying
- * documentation must state that "this software is based in part on the work of
- * the Independent JPEG Group".
- * (3) Permission for use of this software is granted only if the user accepts
- * full responsibility for any undesirable consequences; the authors accept
- * NO LIABILITY for damages of any kind.
- *
- * These conditions apply to any software derived from or based on the IJG code,
- * not just to the unmodified library. If you use our work, you ought to
- * acknowledge us.
- *
- * Permission is NOT granted for the use of any IJG author's name or company name
- * in advertising or publicity relating to this software or products derived from
- * it. This software may be referred to only as "the Independent JPEG Group's
- * software".
- *
- * We specifically permit and encourage the use of this software as the basis of
- * commercial products, provided that all warranty or liability claims are
- * assumed by the product vendor.
- *
- *
- * This file contains a floating-point implementation of the
- * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine
- * must also perform dequantization of the input coefficients.
- *
- * This implementation should be more accurate than either of the integer
- * IDCT implementations. However, it may not give the same results on all
- * machines because of differences in roundoff behavior. Speed will depend
- * on the hardware's floating point capacity.
- *
- * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT
- * on each row (or vice versa, but it's more convenient to emit a row at
- * a time). Direct algorithms are also available, but they are much more
- * complex and seem not to be any faster when reduced to code.
- *
- * This implementation is based on Arai, Agui, and Nakajima's algorithm for
- * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in
- * Japanese, but the algorithm is described in the Pennebaker & Mitchell
- * JPEG textbook (see REFERENCES section in file README). The following code
- * is based directly on figure 4-8 in P&M.
- * While an 8-point DCT cannot be done in less than 11 multiplies, it is
- * possible to arrange the computation so that many of the multiplies are
- * simple scalings of the final outputs. These multiplies can then be
- * folded into the multiplications or divisions by the JPEG quantization
- * table entries. The AA&N method leaves only 5 multiplies and 29 adds
- * to be done in the DCT itself.
- * The primary disadvantage of this method is that with a fixed-point
- * implementation, accuracy is lost due to imprecise representation of the
- * scaled quantization values. However, that problem does not arise if
- * we use floating point arithmetic.
- */
-
-#include "tinyjpeg-internal.h"
-
-#define FAST_FLOAT float
-#define DCTSIZE 8
-#define DCTSIZE2 (DCTSIZE*DCTSIZE)
-
-#define DEQUANTIZE(coef,quantval) (((FAST_FLOAT) (coef)) * (quantval))
-
-#if 0 && defined(__GNUC__) && (defined(__i686__))
-// || defined(__x86_64__))
-
-static inline unsigned char descale_and_clamp(int x, int shift)
-{
- __asm__ (
- "add %3,%1\n"
- "\tsar %2,%1\n"
- "\tsub $-128,%1\n"
- "\tcmovl %5,%1\n" /* Use the sub to compare to 0 */
- "\tcmpl %4,%1\n"
- "\tcmovg %4,%1\n"
- : "=r"(x)
- : "0"(x), "Ir"(shift), "ir"(1UL<<(shift-1)), "r" (0xff), "r" (0)
- );
- return x;
-}
-
-#else
-static __inline unsigned char descale_and_clamp(int x, int shift)
-{
- x += (1UL<<(shift-1));
- if (x<0)
- x = (x >> shift) | ((~(0UL)) << (32-(shift)));
- else
- x >>= shift;
- x += 128;
- if (x>255)
- return 255;
- else if (x<0)
- return 0;
- else
- return x;
-}
-#endif
-
-/*
- * Perform dequantization and inverse DCT on one block of coefficients.
- */
-
-void
-tinyjpeg_idct_float (struct component *compptr, uint8_t *output_buf, int stride)
-{
- FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
- FAST_FLOAT tmp10, tmp11, tmp12, tmp13;
- FAST_FLOAT z5, z10, z11, z12, z13;
- int16_t *inptr;
- FAST_FLOAT *quantptr;
- FAST_FLOAT *wsptr;
- uint8_t *outptr;
- int ctr;
- FAST_FLOAT workspace[DCTSIZE2]; /* buffers data between passes */
-
- /* Pass 1: process columns from input, store into work array. */
-
- inptr = compptr->DCT;
- quantptr = compptr->Q_table;
- wsptr = workspace;
- for (ctr = DCTSIZE; ctr > 0; ctr--) {
- /* Due to quantization, we will usually find that many of the input
- * coefficients are zero, especially the AC terms. We can exploit this
- * by short-circuiting the IDCT calculation for any column in which all
- * the AC terms are zero. In that case each output is equal to the
- * DC coefficient (with scale factor as needed).
- * With typical images and quantization tables, half or more of the
- * column DCT calculations can be simplified this way.
- */
-
- if (inptr[DCTSIZE*1] == 0 && inptr[DCTSIZE*2] == 0 &&
- inptr[DCTSIZE*3] == 0 && inptr[DCTSIZE*4] == 0 &&
- inptr[DCTSIZE*5] == 0 && inptr[DCTSIZE*6] == 0 &&
- inptr[DCTSIZE*7] == 0) {
- /* AC terms all zero */
- FAST_FLOAT dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
-
- wsptr[DCTSIZE*0] = dcval;
- wsptr[DCTSIZE*1] = dcval;
- wsptr[DCTSIZE*2] = dcval;
- wsptr[DCTSIZE*3] = dcval;
- wsptr[DCTSIZE*4] = dcval;
- wsptr[DCTSIZE*5] = dcval;
- wsptr[DCTSIZE*6] = dcval;
- wsptr[DCTSIZE*7] = dcval;
-
- inptr++; /* advance pointers to next column */
- quantptr++;
- wsptr++;
- continue;
- }
-
- /* Even part */
-
- tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]);
- tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]);
- tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]);
- tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]);
-
- tmp10 = tmp0 + tmp2; /* phase 3 */
- tmp11 = tmp0 - tmp2;
-
- tmp13 = tmp1 + tmp3; /* phases 5-3 */
- tmp12 = (tmp1 - tmp3) * ((FAST_FLOAT) 1.414213562) - tmp13; /* 2*c4 */
-
- tmp0 = tmp10 + tmp13; /* phase 2 */
- tmp3 = tmp10 - tmp13;
- tmp1 = tmp11 + tmp12;
- tmp2 = tmp11 - tmp12;
-
- /* Odd part */
-
- tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]);
- tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]);
- tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]);
- tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]);
-
- z13 = tmp6 + tmp5; /* phase 6 */
- z10 = tmp6 - tmp5;
- z11 = tmp4 + tmp7;
- z12 = tmp4 - tmp7;
-
- tmp7 = z11 + z13; /* phase 5 */
- tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); /* 2*c4 */
-
- z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */
- tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */
- tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */
-
- tmp6 = tmp12 - tmp7; /* phase 2 */
- tmp5 = tmp11 - tmp6;
- tmp4 = tmp10 + tmp5;
-
- wsptr[DCTSIZE*0] = tmp0 + tmp7;
- wsptr[DCTSIZE*7] = tmp0 - tmp7;
- wsptr[DCTSIZE*1] = tmp1 + tmp6;
- wsptr[DCTSIZE*6] = tmp1 - tmp6;
- wsptr[DCTSIZE*2] = tmp2 + tmp5;
- wsptr[DCTSIZE*5] = tmp2 - tmp5;
- wsptr[DCTSIZE*4] = tmp3 + tmp4;
- wsptr[DCTSIZE*3] = tmp3 - tmp4;
-
- inptr++; /* advance pointers to next column */
- quantptr++;
- wsptr++;
- }
-
- /* Pass 2: process rows from work array, store into output array. */
- /* Note that we must descale the results by a factor of 8 == 2**3. */
-
- wsptr = workspace;
- outptr = output_buf;
- for (ctr = 0; ctr < DCTSIZE; ctr++) {
- /* Rows of zeroes can be exploited in the same way as we did with columns.
- * However, the column calculation has created many nonzero AC terms, so
- * the simplification applies less often (typically 5% to 10% of the time).
- * And testing floats for zero is relatively expensive, so we don't bother.
- */
-
- /* Even part */
-
- tmp10 = wsptr[0] + wsptr[4];
- tmp11 = wsptr[0] - wsptr[4];
-
- tmp13 = wsptr[2] + wsptr[6];
- tmp12 = (wsptr[2] - wsptr[6]) * ((FAST_FLOAT) 1.414213562) - tmp13;
-
- tmp0 = tmp10 + tmp13;
- tmp3 = tmp10 - tmp13;
- tmp1 = tmp11 + tmp12;
- tmp2 = tmp11 - tmp12;
-
- /* Odd part */
-
- z13 = wsptr[5] + wsptr[3];
- z10 = wsptr[5] - wsptr[3];
- z11 = wsptr[1] + wsptr[7];
- z12 = wsptr[1] - wsptr[7];
-
- tmp7 = z11 + z13;
- tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562);
-
- z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */
- tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */
- tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */
-
- tmp6 = tmp12 - tmp7;
- tmp5 = tmp11 - tmp6;
- tmp4 = tmp10 + tmp5;
-
- /* Final output stage: scale down by a factor of 8 and range-limit */
-
- outptr[0] = descale_and_clamp((int)(tmp0 + tmp7), 3);
- outptr[7] = descale_and_clamp((int)(tmp0 - tmp7), 3);
- outptr[1] = descale_and_clamp((int)(tmp1 + tmp6), 3);
- outptr[6] = descale_and_clamp((int)(tmp1 - tmp6), 3);
- outptr[2] = descale_and_clamp((int)(tmp2 + tmp5), 3);
- outptr[5] = descale_and_clamp((int)(tmp2 - tmp5), 3);
- outptr[4] = descale_and_clamp((int)(tmp3 + tmp4), 3);
- outptr[3] = descale_and_clamp((int)(tmp3 - tmp4), 3);
-
-
- wsptr += DCTSIZE; /* advance pointer to next row */
- outptr += stride;
- }
-}
-
diff --git a/drivers/jpg/loadjpeg.c b/drivers/jpg/loadjpeg.c
deleted file mode 100644
index 82072d4272..0000000000
--- a/drivers/jpg/loadjpeg.c
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * Small jpeg decoder library - testing application
- *
- * Copyright (c) 2006, Luc Saillard <luc@saillard.org>
- * All rights reserved.
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * - Neither the name of the author nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include "tinyjpeg.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#define snprintf(buf, size, fmt, ...) sprintf(buf, fmt, __VA_ARGS__)
-
-static void exitmessage(const char *message) __attribute__((noreturn));
-static void exitmessage(const char *message)
-{
- printf("%s\n", message);
- exit(0);
-}
-
-static int filesize(FILE *fp)
-{
- long pos;
- fseek(fp, 0, SEEK_END);
- pos = ftell(fp);
- fseek(fp, 0, SEEK_SET);
- return pos;
-}
-
-/**
- * Save a buffer in 24bits Targa format
- * (BGR byte order)
- */
-static void write_tga(const char *filename, int output_format, int width, int height, unsigned char **components)
-{
- unsigned char targaheader[18];
- FILE *F;
- char temp[1024];
- unsigned int bufferlen = width * height * 3;
- unsigned char *rgb_data = components[0];
-
- sprintf(temp, sizeof(temp), filename);
-
- memset(targaheader,0,sizeof(targaheader));
-
- targaheader[12] = (unsigned char) (width & 0xFF);
- targaheader[13] = (unsigned char) (width >> 8);
- targaheader[14] = (unsigned char) (height & 0xFF);
- targaheader[15] = (unsigned char) (height >> 8);
- targaheader[17] = 0x20; /* Top-down, non-interlaced */
- targaheader[2] = 2; /* image type = uncompressed RGB */
- targaheader[16] = 24;
-
- if (output_format == TINYJPEG_FMT_RGB24)
- {
- unsigned char *data = rgb_data + bufferlen - 3;
- do
- {
- unsigned char c = data[0];
- data[0] = data[2];
- data[2] = c;
- data-=3;
- }
- while (data > rgb_data);
- }
-
- F = fopen(temp, "wb");
- fwrite(targaheader, sizeof(targaheader), 1, F);
- fwrite(rgb_data, 1, bufferlen, F);
- fclose(F);
-}
-
-/**
- * Save a buffer in three files (.Y, .U, .V) useable by yuvsplittoppm
- */
-static void write_yuv(const char *filename, int width, int height, unsigned char **components)
-{
- FILE *F;
- char temp[1024];
-
- snprintf(temp, 1024, "%s.Y", filename);
- F = fopen(temp, "wb");
- fwrite(components[0], width, height, F);
- fclose(F);
- snprintf(temp, 1024, "%s.U", filename);
- F = fopen(temp, "wb");
- fwrite(components[1], width*height/4, 1, F);
- fclose(F);
- snprintf(temp, 1024, "%s.V", filename);
- F = fopen(temp, "wb");
- fwrite(components[2], width*height/4, 1, F);
- fclose(F);
-}
-
-/**
- * Save a buffer in grey image (pgm format)
- */
-static void write_pgm(const char *filename, int width, int height, unsigned char **components)
-{
- FILE *F;
- char temp[1024];
-
- snprintf(temp, 1024, "%s", filename);
- F = fopen(temp, "wb");
- fprintf(F, "P5\n%d %d\n255\n", width, height);
- fwrite(components[0], width, height, F);
- fclose(F);
-}
-
-/**
- * Load one jpeg image, and try to decompress 1000 times, and save the result.
- * This is mainly used for benchmarking the decoder, or to test if between each
- * called of the library the DCT is corrected reset (a bug was found).
- */
-int load_multiple_times(const char *filename, const char *outfilename, int output_format)
-{
- FILE *fp;
- int count, length_of_file;
- unsigned int width, height;
- unsigned char *buf;
- struct jdec_private *jdec;
- unsigned char *components[4];
-
- jdec = tinyjpeg_init();
- count = 0;
-
- /* Load the Jpeg into memory */
- fp = fopen(filename, "rb");
- if (fp == NULL)
- exitmessage("Cannot open filename\n");
- length_of_file = filesize(fp);
- buf = (unsigned char *)malloc(length_of_file + 4);
- fread(buf, length_of_file, 1, fp);
- fclose(fp);
-
- while (count<1000)
- {
- if (tinyjpeg_parse_header(jdec, buf, length_of_file)<0)
- exitmessage(tinyjpeg_get_errorstring(jdec));
-
- tinyjpeg_decode(jdec, output_format);
-
- count++;
- }
-
- /*
- * Get address for each plane (not only max 3 planes is supported), and
- * depending of the output mode, only some components will be filled
- * RGB: 1 plane, YUV420P: 3 planes, GREY: 1 plane
- */
- tinyjpeg_get_components(jdec, components);
- tinyjpeg_get_size(jdec, &width, &height);
-
- /* Save it */
- switch (output_format)
- {
- case TINYJPEG_FMT_RGB24:
- case TINYJPEG_FMT_BGR24:
- write_tga(outfilename, output_format, width, height, components);
- break;
- case TINYJPEG_FMT_YUV420P:
- write_yuv(outfilename, width, height, components);
- break;
- case TINYJPEG_FMT_GREY:
- write_pgm(outfilename, width, height, components);
- break;
- }
-
- free(buf);
- tinyjpeg_free(jdec);
- return 0;
-}
-
-/**
- * Load one jpeg image, and decompress it, and save the result.
- */
-int convert_one_image(const char *infilename, const char *outfilename, int output_format)
-{
- FILE *fp;
- unsigned int length_of_file;
- unsigned int width, height;
- unsigned char *buf;
- struct jdec_private *jdec;
- unsigned char *components[3];
-
- /* Load the Jpeg into memory */
- fp = fopen(infilename, "rb");
- if (fp == NULL)
- exitmessage("Cannot open filename\n");
- length_of_file = filesize(fp);
- buf = (unsigned char *)malloc(length_of_file + 4);
- if (buf == NULL)
- exitmessage("Not enough memory for loading file\n");
- fread(buf, length_of_file, 1, fp);
- fclose(fp);
-
- /* Decompress it */
- jdec = tinyjpeg_init();
- if (jdec == NULL)
- exitmessage("Not enough memory to alloc the structure need for decompressing\n");
-
- if (tinyjpeg_parse_header(jdec, buf, length_of_file)<0)
- exitmessage(tinyjpeg_get_errorstring(jdec));
-
- /* Get the size of the image */
- tinyjpeg_get_size(jdec, &width, &height);
-
- printf("Decoding JPEG image...\n");
- if (tinyjpeg_decode(jdec, output_format) < 0)
- exitmessage(tinyjpeg_get_errorstring(jdec));
-
- /*
- * Get address for each plane (not only max 3 planes is supported), and
- * depending of the output mode, only some components will be filled
- * RGB: 1 plane, YUV420P: 3 planes, GREY: 1 plane
- */
- tinyjpeg_get_components(jdec, components);
-
- /* Save it */
- switch (output_format)
- {
- case TINYJPEG_FMT_RGB24:
- case TINYJPEG_FMT_BGR24:
- write_tga(outfilename, output_format, width, height, components);
- break;
- case TINYJPEG_FMT_YUV420P:
- write_yuv(outfilename, width, height, components);
- break;
- case TINYJPEG_FMT_GREY:
- write_pgm(outfilename, width, height, components);
- break;
- }
-
- /* Only called this if the buffers were allocated by tinyjpeg_decode() */
- tinyjpeg_free(jdec);
- /* else called just free(jdec); */
-
- free(buf);
- return 0;
-}
-
-static void usage(void)
-{
- fprintf(stderr, "Usage: loadjpeg [options] <input_filename.jpeg> <format> <output_filename>\n");
- fprintf(stderr, "options:\n");
- fprintf(stderr, " --benchmark - Convert 1000 times the same image\n");
- fprintf(stderr, "format:\n");
- fprintf(stderr, " yuv420p - output 3 files .Y,.U,.V\n");
- fprintf(stderr, " rgb24 - output a .tga image\n");
- fprintf(stderr, " bgr24 - output a .tga image\n");
- fprintf(stderr, " gray - output a .pgm image\n");
- exit(1);
-}
-
-/**
- * main
- *
- */
-int main(int argc, char *argv[])
-{
- int output_format = TINYJPEG_FMT_YUV420P;
- char *output_filename, *input_filename;
- clock_t start_time, finish_time;
- unsigned int duration;
- int current_argument;
- int benchmark_mode = 0;
-
- if (argc < 3)
- usage();
-
- current_argument = 1;
- while (1)
- {
- if (strcmp(argv[current_argument], "--benchmark")==0)
- benchmark_mode = 1;
- else
- break;
- current_argument++;
- }
-
- if (argc < current_argument+2)
- usage();
-
- input_filename = argv[current_argument];
- if (strcmp(argv[current_argument+1],"yuv420p")==0)
- output_format = TINYJPEG_FMT_YUV420P;
- else if (strcmp(argv[current_argument+1],"rgb24")==0)
- output_format = TINYJPEG_FMT_RGB24;
- else if (strcmp(argv[current_argument+1],"bgr24")==0)
- output_format = TINYJPEG_FMT_BGR24;
- else if (strcmp(argv[current_argument+1],"grey")==0)
- output_format = TINYJPEG_FMT_GREY;
- else
- exitmessage("Bad format: need to be one of yuv420p, rgb24, bgr24, grey\n");
- output_filename = argv[current_argument+2];
-
- start_time = clock();
-
- if (benchmark_mode)
- load_multiple_times(input_filename, output_filename, output_format);
- else
- convert_one_image(input_filename, output_filename, output_format);
-
- finish_time = clock();
- duration = finish_time - start_time;
- printf("Decoding finished in %u ticks\n", duration);
-
- return 0;
-}
-
-
-
-
diff --git a/drivers/jpg/tinyjpeg-internal.h b/drivers/jpg/tinyjpeg-internal.h
deleted file mode 100644
index b2d5fe42aa..0000000000
--- a/drivers/jpg/tinyjpeg-internal.h
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Small jpeg decoder library (Internal header)
- *
- * Copyright (c) 2006, Luc Saillard <luc@saillard.org>
- * All rights reserved.
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * - Neither the name of the author nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#ifndef __TINYJPEG_INTERNAL_H_
-#define __TINYJPEG_INTERNAL_H_
-
-#ifdef _MSC_VER
-
-typedef signed __int8 int8_t;
-typedef unsigned __int8 uint8_t;
-typedef signed __int16 int16_t;
-typedef unsigned __int16 uint16_t;
-typedef signed __int32 int32_t;
-typedef unsigned __int32 uint32_t;
-typedef signed __int64 int64_t;
-typedef unsigned __int64 uint64_t;
-
-#else
-
-#ifdef NO_STDINT_H
-typedef unsigned char uint8_t;
-typedef signed char int8_t;
-typedef unsigned short uint16_t;
-typedef signed short int16_t;
-typedef unsigned int uint32_t;
-typedef signed int int32_t;
-typedef long long int64_t;
-typedef unsigned long long int64_t;
-#else
-#include <stdint.h>
-#endif
-#endif
-
-
-#include <setjmp.h>
-
-#define SANITY_CHECK 1
-
-struct jdec_private;
-
-#define HUFFMAN_BITS_SIZE 256
-#define HUFFMAN_HASH_NBITS 9
-#define HUFFMAN_HASH_SIZE (1UL<<HUFFMAN_HASH_NBITS)
-#define HUFFMAN_HASH_MASK (HUFFMAN_HASH_SIZE-1)
-
-#define HUFFMAN_TABLES 4
-#define COMPONENTS 3
-#define JPEG_MAX_WIDTH 4096
-#define JPEG_MAX_HEIGHT 4096
-
-struct huffman_table
-{
- /* Fast look up table, using HUFFMAN_HASH_NBITS bits we can have directly the symbol,
- * if the symbol is <0, then we need to look into the tree table */
- short int lookup[HUFFMAN_HASH_SIZE];
- /* code size: give the number of bits of a symbol is encoded */
- unsigned char code_size[HUFFMAN_HASH_SIZE];
- /* some place to store value that is not encoded in the lookup table
- * FIXME: Calculate if 256 value is enough to store all values
- */
- uint16_t slowtable[16-HUFFMAN_HASH_NBITS][256];
-};
-
-struct component
-{
- unsigned int Hfactor;
- unsigned int Vfactor;
- float *Q_table; /* Pointer to the quantisation table to use */
- struct huffman_table *AC_table;
- struct huffman_table *DC_table;
- short int previous_DC; /* Previous DC coefficient */
- short int DCT[64]; /* DCT coef */
-#if SANITY_CHECK
- unsigned int cid;
-#endif
-};
-
-
-typedef void (*decode_MCU_fct) (struct jdec_private *priv);
-typedef void (*convert_colorspace_fct) (struct jdec_private *priv);
-
-struct jdec_private
-{
- void *(*allocate_mem)(unsigned int amount);
- void (*free_mem)(void *mem);
-
- /* Public variables */
- uint8_t *components[COMPONENTS];
- unsigned int width, height; /* Size of the image */
- unsigned int flags;
-
- /* Private variables */
- const unsigned char *stream_begin, *stream_end;
- unsigned int stream_length;
-
- const unsigned char *stream; /* Pointer to the current stream */
- unsigned int reservoir, nbits_in_reservoir;
-
- struct component component_infos[COMPONENTS];
- float Q_tables[COMPONENTS][64]; /* quantization tables */
- struct huffman_table HTDC[HUFFMAN_TABLES]; /* DC huffman tables */
- struct huffman_table HTAC[HUFFMAN_TABLES]; /* AC huffman tables */
- int default_huffman_table_initialized;
- int restart_interval;
- int restarts_to_go; /* MCUs left in this restart interval */
- int last_rst_marker_seen; /* Rst marker is incremented each time */
-
- /* Temp space used after the IDCT to store each components */
- uint8_t Y[64*4], Cr[64], Cb[64];
-
- jmp_buf jump_state;
- /* Internal Pointer use for colorspace conversion, do not modify it !!! */
- uint8_t *plane[COMPONENTS];
-
- uint8_t decomp_block[16][16*3];
-
-};
-
-#if defined(__GNUC__) && (__GNUC__ > 3) && defined(__OPTIMIZE__)
-#define __likely(x) __builtin_expect(!!(x), 1)
-#define __unlikely(x) __builtin_expect(!!(x), 0)
-#else
-#define __likely(x) (x)
-#define __unlikely(x) (x)
-#endif
-
-#define IDCT tinyjpeg_idct_float
-void tinyjpeg_idct_float (struct component *compptr, uint8_t *output_buf, int stride);
-
-#endif
-
diff --git a/drivers/jpg/tinyjpeg.c b/drivers/jpg/tinyjpeg.c
deleted file mode 100644
index 8e3c934ce0..0000000000
--- a/drivers/jpg/tinyjpeg.c
+++ /dev/null
@@ -1,2202 +0,0 @@
-/*
- * Small jpeg decoder library
- *
- * Copyright (c) 2006, Luc Saillard <luc@saillard.org>
- * All rights reserved.
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * - Neither the name of the author nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <errno.h>
-
-#include "tinyjpeg.h"
-#include "tinyjpeg-internal.h"
-
-enum std_markers {
- DQT = 0xDB, /* Define Quantization Table */
- SOF = 0xC0, /* Start of Frame (size information) */
- DHT = 0xC4, /* Huffman Table */
- SOI = 0xD8, /* Start of Image */
- SOS = 0xDA, /* Start of Scan */
- RST = 0xD0, /* Reset Marker d0 -> .. */
- RST7 = 0xD7, /* Reset Marker .. -> d7 */
- EOI = 0xD9, /* End of Image */
- DRI = 0xDD, /* Define Restart Interval */
- APP0 = 0xE0,
-};
-
-#define cY 0
-#define cCb 1
-#define cCr 2
-
-#define BLACK_Y 0
-#define BLACK_U 127
-#define BLACK_V 127
-
-#if DEBUG
-#define trace(fmt, args...) do { \
- fprintf(stderr, fmt, ## args); \
- fflush(stderr); \
-} while(0)
-#else
-#define trace(fmt, ...) do { } while (0)
-#endif
-
-#define error(fmt, ...) do { \
- sprintf(error_string, fmt, ## __VA_ARGS__); \
- return -1; \
-} while(0)
-
-
-#if 0
-static char *print_bits(unsigned int value, char *bitstr)
-{
- int i, j;
- i=31;
- while (i>0)
- {
- if (value & (1UL<<i))
- break;
- i--;
- }
- j=0;
- while (i>=0)
- {
- bitstr[j++] = (value & (1UL<<i))?'1':'0';
- i--;
- }
- bitstr[j] = 0;
- return bitstr;
-}
-
-static void print_next_16bytes(int offset, const unsigned char *stream)
-{
- trace("%4.4x: %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
- offset,
- stream[0], stream[1], stream[2], stream[3],
- stream[4], stream[5], stream[6], stream[7],
- stream[8], stream[9], stream[10], stream[11],
- stream[12], stream[13], stream[14], stream[15]);
-}
-
-#endif
-
-/* Global variable to return the last error found while deconding */
-static char error_string[256];
-
-static const unsigned char zigzag[64] =
-{
- 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
-};
-
-/* Set up the standard Huffman tables (cf. JPEG standard section K.3) */
-/* IMPORTANT: these are only valid for 8-bit data precision! */
-static const unsigned char bits_dc_luminance[17] =
-{
- 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0
-};
-static const unsigned char val_dc_luminance[] =
-{
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
-};
-
-static const unsigned char bits_dc_chrominance[17] =
-{
- 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
-};
-static const unsigned char val_dc_chrominance[] =
-{
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
-};
-
-static const unsigned char bits_ac_luminance[17] =
-{
- 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d
-};
-static const unsigned char val_ac_luminance[] =
-{
- 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 bits_ac_chrominance[17] =
-{
- 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77
-};
-
-static const unsigned char val_ac_chrominance[] =
-{
- 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
-};
-
-
-/*
- * 4 functions to manage the stream
- *
- * fill_nbits: put at least nbits in the reservoir of bits.
- * But convert any 0xff,0x00 into 0xff
- * get_nbits: read nbits from the stream, and put it in result,
- * bits is removed from the stream and the reservoir is filled
- * automaticaly. The result is signed according to the number of
- * bits.
- * look_nbits: read nbits from the stream without marking as read.
- * skip_nbits: read nbits from the stream but do not return the result.
- *
- * stream: current pointer in the jpeg data (read bytes per bytes)
- * nbits_in_reservoir: number of bits filled into the reservoir
- * reservoir: register that contains bits information. Only nbits_in_reservoir
- * is valid.
- * nbits_in_reservoir
- * <-- 17 bits -->
- * Ex: 0000 0000 1010 0000 1111 0000 <== reservoir
- * ^
- * bit 1
- * To get two bits from this example
- * result = (reservoir >> 15) & 3
- *
- */
-#define fill_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) do { \
- while (nbits_in_reservoir<nbits_wanted) \
- { \
- unsigned char c; \
- if (stream >= priv->stream_end) \
- longjmp(priv->jump_state, -EIO); \
- c = *stream++; \
- reservoir <<= 8; \
- if (c == 0xff && *stream == 0x00) \
- stream++; \
- reservoir |= c; \
- nbits_in_reservoir+=8; \
- } \
-} while(0);
-
-/* Signed version !!!! */
-#define get_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted,result) do { \
- fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \
- result = ((reservoir)>>(nbits_in_reservoir-(nbits_wanted))); \
- nbits_in_reservoir -= (nbits_wanted); \
- reservoir &= ((1U<<nbits_in_reservoir)-1); \
- if ((unsigned int)result < (1UL<<((nbits_wanted)-1))) \
- result += (0xFFFFFFFFUL<<(nbits_wanted))+1; \
-} while(0);
-
-#define look_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted,result) do { \
- fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \
- result = ((reservoir)>>(nbits_in_reservoir-(nbits_wanted))); \
-} while(0);
-
-/* To speed up the decoding, we assume that the reservoir have enough bit
- * slow version:
- * #define skip_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) do { \
- * fill_nbits(reservoir,nbits_in_reservoir,stream,(nbits_wanted)); \
- * nbits_in_reservoir -= (nbits_wanted); \
- * reservoir &= ((1U<<nbits_in_reservoir)-1); \
- * } while(0);
- */
-#define skip_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) do { \
- nbits_in_reservoir -= (nbits_wanted); \
- reservoir &= ((1U<<nbits_in_reservoir)-1); \
-} while(0);
-
-
-#define be16_to_cpu(x) (((x)[0]<<8)|(x)[1])
-
-static void resync(struct jdec_private *priv);
-
-/**
- * Get the next (valid) huffman code in the stream.
- *
- * To speedup the procedure, we look HUFFMAN_HASH_NBITS bits and the code is
- * lower than HUFFMAN_HASH_NBITS we have automaticaly the length of the code
- * and the value by using two lookup table.
- * Else if the value is not found, just search (linear) into an array for each
- * bits is the code is present.
- *
- * If the code is not present for any reason, -1 is return.
- */
-static int get_next_huffman_code(struct jdec_private *priv, struct huffman_table *huffman_table)
-{
- int value, hcode;
- unsigned int extra_nbits, nbits;
- uint16_t *slowtable;
-
- look_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, HUFFMAN_HASH_NBITS, hcode);
- value = huffman_table->lookup[hcode];
- if (__likely(value >= 0))
- {
- unsigned int code_size = huffman_table->code_size[value];
- skip_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, code_size);
- return value;
- }
-
- /* Decode more bits each time ... */
- for (extra_nbits=0; extra_nbits<16-HUFFMAN_HASH_NBITS; extra_nbits++)
- {
- nbits = HUFFMAN_HASH_NBITS + 1 + extra_nbits;
-
- look_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, nbits, hcode);
- slowtable = huffman_table->slowtable[extra_nbits];
- /* Search if the code is in this array */
- while (slowtable[0]) {
- if (slowtable[0] == hcode) {
- skip_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, nbits);
- return slowtable[1];
- }
- slowtable+=2;
- }
- }
- return 0;
-}
-
-
-
-
-/**
- *
- * Decode a single block that contains the DCT coefficients.
- * The table coefficients is already dezigzaged at the end of the operation.
- *
- */
-static void process_Huffman_data_unit(struct jdec_private *priv, int component)
-{
- unsigned char j;
- unsigned int huff_code;
- unsigned char size_val, count_0;
-
- struct component *c = &priv->component_infos[component];
- short int DCT[64];
-
-
- /* Initialize the DCT coef table */
- memset(DCT, 0, sizeof(DCT));
-
- /* DC coefficient decoding */
- huff_code = get_next_huffman_code(priv, c->DC_table);
- //trace("+ %x\n", huff_code);
- if (huff_code) {
- get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, huff_code, DCT[0]);
- DCT[0] += c->previous_DC;
- c->previous_DC = DCT[0];
- } else {
- DCT[0] = c->previous_DC;
- }
-
- /* AC coefficient decoding */
- j = 1;
- while (j<64)
- {
- huff_code = get_next_huffman_code(priv, c->AC_table);
- //trace("- %x\n", huff_code);
-
- size_val = huff_code & 0xF;
- count_0 = huff_code >> 4;
-
- if (size_val == 0)
- { /* RLE */
- if (count_0 == 0)
- break; /* EOB found, go out */
- else if (count_0 == 0xF)
- j += 16; /* skip 16 zeros */
- }
- else
- {
- j += count_0; /* skip count_0 zeroes */
- if (__unlikely(j >= 64))
- {
- sprintf(error_string, "Bad huffman data (buffer overflow)");
- break;
- }
- get_nbits(priv->reservoir, priv->nbits_in_reservoir, priv->stream, size_val, DCT[j]);
- j++;
- }
- }
-
- for (j = 0; j < 64; j++)
- c->DCT[j] = DCT[zigzag[j]];
-}
-
-/*
- * Takes two array of bits, and build the huffman table for size, and code
- *
- * lookup will return the symbol if the code is less or equal than HUFFMAN_HASH_NBITS.
- * code_size will be used to known how many bits this symbol is encoded.
- * slowtable will be used when the first lookup didn't give the result.
- */
-static void build_huffman_table(const unsigned char *bits, const unsigned char *vals, struct huffman_table *table)
-{
- unsigned int i, j, code, code_size, val, nbits;
- unsigned char huffsize[HUFFMAN_BITS_SIZE+1], *hz;
- unsigned int huffcode[HUFFMAN_BITS_SIZE+1], *hc;
- int next_free_entry;
-
- /*
- * Build a temp array
- * huffsize[X] => numbers of bits to write vals[X]
- */
- hz = huffsize;
- for (i=1; i<=16; i++)
- {
- for (j=1; j<=bits[i]; j++)
- *hz++ = i;
- }
- *hz = 0;
-
- memset(table->lookup, 0xff, sizeof(table->lookup));
- for (i=0; i<(16-HUFFMAN_HASH_NBITS); i++)
- table->slowtable[i][0] = 0;
-
- /* Build a temp array
- * huffcode[X] => code used to write vals[X]
- */
- code = 0;
- hc = huffcode;
- hz = huffsize;
- nbits = *hz;
- while (*hz)
- {
- while (*hz == nbits)
- {
- *hc++ = code++;
- hz++;
- }
- code <<= 1;
- nbits++;
- }
-
- /*
- * Build the lookup table, and the slowtable if needed.
- */
- next_free_entry = -1;
- for (i=0; huffsize[i]; i++)
- {
- val = vals[i];
- code = huffcode[i];
- code_size = huffsize[i];
-
- trace("val=%2.2x code=%8.8x codesize=%2.2d\n", val, code, code_size);
-
- table->code_size[val] = code_size;
- if (code_size <= HUFFMAN_HASH_NBITS)
- {
- /*
- * Good: val can be put in the lookup table, so fill all value of this
- * column with value val
- */
- int repeat = 1UL<<(HUFFMAN_HASH_NBITS - code_size);
- code <<= HUFFMAN_HASH_NBITS - code_size;
- while ( repeat-- )
- table->lookup[code++] = val;
-
- }
- else
- {
- /* Perhaps sorting the array will be an optimization */
- uint16_t *slowtable = table->slowtable[code_size-HUFFMAN_HASH_NBITS-1];
- while(slowtable[0])
- slowtable+=2;
- slowtable[0] = code;
- slowtable[1] = val;
- slowtable[2] = 0;
- /* TODO: NEED TO CHECK FOR AN OVERFLOW OF THE TABLE */
- }
-
- }
-}
-
-static void build_default_huffman_tables(struct jdec_private *priv)
-{
- if ( (priv->flags & TINYJPEG_FLAGS_MJPEG_TABLE)
- && priv->default_huffman_table_initialized)
- return;
-
- build_huffman_table(bits_dc_luminance, val_dc_luminance, &priv->HTDC[0]);
- build_huffman_table(bits_ac_luminance, val_ac_luminance, &priv->HTAC[0]);
-
- build_huffman_table(bits_dc_chrominance, val_dc_chrominance, &priv->HTDC[1]);
- build_huffman_table(bits_ac_chrominance, val_ac_chrominance, &priv->HTAC[1]);
-
- priv->default_huffman_table_initialized = 1;
-}
-
-
-
-/*******************************************************************************
- *
- * Colorspace conversion routine
- *
- *
- * Note:
- * YCbCr is defined per CCIR 601-1, except that Cb and Cr are
- * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5.
- * The conversion equations to be implemented are therefore
- * R = Y + 1.40200 * Cr
- * G = Y - 0.34414 * Cb - 0.71414 * Cr
- * B = Y + 1.77200 * Cb
- *
- ******************************************************************************/
-
-static unsigned char clamp(int i)
-{
- if (i<0)
- return 0;
- else if (i>255)
- return 255;
- else
- return i;
-}
-
-
-/**
- * YCrCb -> YUV420P (1x1)
- * .---.
- * | 1 |
- * `---'
- */
-static void YCrCB_to_YUV420P_1x1(struct jdec_private *priv)
-{
- const unsigned char *s, *y;
- unsigned char *p;
- int i,j;
-
- p = priv->plane[0];
- y = priv->Y;
- for (i=0; i<8; i++)
- {
- memcpy(p, y, 8);
- p+=priv->width;
- y+=8;
- }
-
- p = priv->plane[1];
- s = priv->Cb;
- for (i=0; i<8; i+=2)
- {
- for (j=0; j<8; j+=2, s+=2)
- *p++ = *s;
- s += 8; /* Skip one line */
- p += priv->width/2 - 4;
- }
-
- p = priv->plane[2];
- s = priv->Cr;
- for (i=0; i<8; i+=2)
- {
- for (j=0; j<8; j+=2, s+=2)
- *p++ = *s;
- s += 8; /* Skip one line */
- p += priv->width/2 - 4;
- }
-}
-
-/**
- * YCrCb -> YUV420P (2x1)
- * .-------.
- * | 1 | 2 |
- * `-------'
- */
-static void YCrCB_to_YUV420P_2x1(struct jdec_private *priv)
-{
- unsigned char *p;
- const unsigned char *s, *y1;
- unsigned int i;
-
- p = priv->plane[0];
- y1 = priv->Y;
- for (i=0; i<8; i++)
- {
- memcpy(p, y1, 16);
- p += priv->width;
- y1 += 16;
- }
-
- p = priv->plane[1];
- s = priv->Cb;
- for (i=0; i<8; i+=2)
- {
- memcpy(p, s, 8);
- s += 16; /* Skip one line */
- p += priv->width/2;
- }
-
- p = priv->plane[2];
- s = priv->Cr;
- for (i=0; i<8; i+=2)
- {
- memcpy(p, s, 8);
- s += 16; /* Skip one line */
- p += priv->width/2;
- }
-}
-
-
-/**
- * YCrCb -> YUV420P (1x2)
- * .---.
- * | 1 |
- * |---|
- * | 2 |
- * `---'
- */
-static void YCrCB_to_YUV420P_1x2(struct jdec_private *priv)
-{
- const unsigned char *s, *y;
- unsigned char *p;
- int i,j;
-
- p = priv->plane[0];
- y = priv->Y;
- for (i=0; i<16; i++)
- {
- memcpy(p, y, 8);
- p+=priv->width;
- y+=8;
- }
-
- p = priv->plane[1];
- s = priv->Cb;
- for (i=0; i<8; i++)
- {
- for (j=0; j<8; j+=2, s+=2)
- *p++ = *s;
- p += priv->width/2 - 4;
- }
-
- p = priv->plane[2];
- s = priv->Cr;
- for (i=0; i<8; i++)
- {
- for (j=0; j<8; j+=2, s+=2)
- *p++ = *s;
- p += priv->width/2 - 4;
- }
-}
-
-/**
- * YCrCb -> YUV420P (2x2)
- * .-------.
- * | 1 | 2 |
- * |---+---|
- * | 3 | 4 |
- * `-------'
- */
-static void YCrCB_to_YUV420P_2x2(struct jdec_private *priv)
-{
- unsigned char *p;
- const unsigned char *s, *y1;
- unsigned int i;
-
- p = priv->plane[0];
- y1 = priv->Y;
- for (i=0; i<16; i++)
- {
- memcpy(p, y1, 16);
- p += priv->width;
- y1 += 16;
- }
-
- p = priv->plane[1];
- s = priv->Cb;
- for (i=0; i<8; i++)
- {
- memcpy(p, s, 8);
- s += 8;
- p += priv->width/2;
- }
-
- p = priv->plane[2];
- s = priv->Cr;
- for (i=0; i<8; i++)
- {
- memcpy(p, s, 8);
- s += 8;
- p += priv->width/2;
- }
-}
-
-/**
- * YCrCb -> RGB24 (1x1)
- * .---.
- * | 1 |
- * `---'
- */
-static void YCrCB_to_RGB24_1x1(struct jdec_private *priv)
-{
- const unsigned char *Y, *Cb, *Cr;
- unsigned char *p;
- int i,j;
- int offset_to_next_row;
-
-#define SCALEBITS 10
-#define ONE_HALF (1UL << (SCALEBITS-1))
-#define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5))
-
- p = priv->plane[0];
- Y = priv->Y;
- Cb = priv->Cb;
- Cr = priv->Cr;
- offset_to_next_row = priv->width*3 - 8*3;
- for (i=0; i<8; i++) {
-
- for (j=0; j<8; j++) {
-
- int y, cb, cr;
- int add_r, add_g, add_b;
- int r, g , b;
-
- y = (*Y++) << SCALEBITS;
- cb = *Cb++ - 128;
- cr = *Cr++ - 128;
- add_r = FIX(1.40200) * cr + ONE_HALF;
- add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF;
- add_b = FIX(1.77200) * cb + ONE_HALF;
-
-
- r = (y + add_r) >> SCALEBITS;
- g = (y + add_g) >> SCALEBITS;
- b = (y + add_b) >> SCALEBITS;
- priv->decomp_block[i][j*3+0]=clamp(r);
- priv->decomp_block[i][j*3+1]=clamp(g);
- priv->decomp_block[i][j*3+2]=clamp(b);
-
- }
-
-// p += offset_to_next_row;
- }
-
-#undef SCALEBITS
-#undef ONE_HALF
-#undef FIX
-
-}
-
-/**
- * YCrCb -> BGR24 (1x1)
- * .---.
- * | 1 |
- * `---'
- */
-static void YCrCB_to_BGR24_1x1(struct jdec_private *priv)
-{
- const unsigned char *Y, *Cb, *Cr;
- unsigned char *p;
- int i,j;
- int offset_to_next_row;
-
-#define SCALEBITS 10
-#define ONE_HALF (1UL << (SCALEBITS-1))
-#define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5))
-
- p = priv->plane[0];
- Y = priv->Y;
- Cb = priv->Cb;
- Cr = priv->Cr;
- offset_to_next_row = priv->width*3 - 8*3;
- for (i=0; i<8; i++) {
-
- for (j=0; j<8; j++) {
-
- int y, cb, cr;
- int add_r, add_g, add_b;
- int r, g , b;
-
- y = (*Y++) << SCALEBITS;
- cb = *Cb++ - 128;
- cr = *Cr++ - 128;
- add_r = FIX(1.40200) * cr + ONE_HALF;
- add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF;
- add_b = FIX(1.77200) * cb + ONE_HALF;
-
- b = (y + add_b) >> SCALEBITS;
- *p++ = clamp(b);
- g = (y + add_g) >> SCALEBITS;
- *p++ = clamp(g);
- r = (y + add_r) >> SCALEBITS;
- *p++ = clamp(r);
-
- }
-
- p += offset_to_next_row;
- }
-
-#undef SCALEBITS
-#undef ONE_HALF
-#undef FIX
-
-}
-
-
-/**
- * YCrCb -> RGB24 (2x1)
- * .-------.
- * | 1 | 2 |
- * `-------'
- */
-static void YCrCB_to_RGB24_2x1(struct jdec_private *priv)
-{
- const unsigned char *Y, *Cb, *Cr;
- unsigned char *p;
- int i,j;
- int offset_to_next_row;
-
-#define SCALEBITS 10
-#define ONE_HALF (1UL << (SCALEBITS-1))
-#define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5))
-
- p = priv->plane[0];
- Y = priv->Y;
- Cb = priv->Cb;
- Cr = priv->Cr;
- offset_to_next_row = priv->width*3 - 16*3;
- for (i=0; i<8; i++) {
-
- for (j=0; j<8; j++) {
-
- int y, cb, cr;
- int add_r, add_g, add_b;
- int r, g , b;
-
- y = (*Y++) << SCALEBITS;
- cb = *Cb++ - 128;
- cr = *Cr++ - 128;
- add_r = FIX(1.40200) * cr + ONE_HALF;
- add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF;
- add_b = FIX(1.77200) * cb + ONE_HALF;
-
- r = (y + add_r) >> SCALEBITS;
- g = (y + add_g) >> SCALEBITS;
- b = (y + add_b) >> SCALEBITS;
-
- priv->decomp_block[i][j*6+0]=clamp(r);
- priv->decomp_block[i][j*6+1]=clamp(g);
- priv->decomp_block[i][j*6+2]=clamp(b);
-
- y = (*Y++) << SCALEBITS;
-
- r = (y + add_r) >> SCALEBITS;
- g = (y + add_g) >> SCALEBITS;
- b = (y + add_b) >> SCALEBITS;
-
- priv->decomp_block[i][j*6+3]=clamp(r);
- priv->decomp_block[i][j*6+4]=clamp(g);
- priv->decomp_block[i][j*6+5]=clamp(b);
-
- }
-
- p += offset_to_next_row;
- }
-
-#undef SCALEBITS
-#undef ONE_HALF
-#undef FIX
-
-}
-
-/*
- * YCrCb -> BGR24 (2x1)
- * .-------.
- * | 1 | 2 |
- * `-------'
- */
-static void YCrCB_to_BGR24_2x1(struct jdec_private *priv)
-{
- const unsigned char *Y, *Cb, *Cr;
- unsigned char *p;
- int i,j;
- int offset_to_next_row;
-
-#define SCALEBITS 10
-#define ONE_HALF (1UL << (SCALEBITS-1))
-#define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5))
-
- p = priv->plane[0];
- Y = priv->Y;
- Cb = priv->Cb;
- Cr = priv->Cr;
- offset_to_next_row = priv->width*3 - 16*3;
- for (i=0; i<8; i++) {
-
- for (j=0; j<8; j++) {
-
- int y, cb, cr;
- int add_r, add_g, add_b;
- int r, g , b;
-
- cb = *Cb++ - 128;
- cr = *Cr++ - 128;
- add_r = FIX(1.40200) * cr + ONE_HALF;
- add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF;
- add_b = FIX(1.77200) * cb + ONE_HALF;
-
- y = (*Y++) << SCALEBITS;
- b = (y + add_b) >> SCALEBITS;
- *p++ = clamp(b);
- g = (y + add_g) >> SCALEBITS;
- *p++ = clamp(g);
- r = (y + add_r) >> SCALEBITS;
- *p++ = clamp(r);
-
- y = (*Y++) << SCALEBITS;
- b = (y + add_b) >> SCALEBITS;
- *p++ = clamp(b);
- g = (y + add_g) >> SCALEBITS;
- *p++ = clamp(g);
- r = (y + add_r) >> SCALEBITS;
- *p++ = clamp(r);
-
- }
-
- p += offset_to_next_row;
- }
-
-#undef SCALEBITS
-#undef ONE_HALF
-#undef FIX
-
-}
-
-/**
- * YCrCb -> RGB24 (1x2)
- * .---.
- * | 1 |
- * |---|
- * | 2 |
- * `---'
- */
-static void YCrCB_to_RGB24_1x2(struct jdec_private *priv)
-{
- const unsigned char *Y, *Cb, *Cr;
- unsigned char *p, *p2;
- int i,j;
- int offset_to_next_row;
-
-#define SCALEBITS 10
-#define ONE_HALF (1UL << (SCALEBITS-1))
-#define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5))
-
- p = priv->plane[0];
- p2 = priv->plane[0] + priv->width*3;
- Y = priv->Y;
- Cb = priv->Cb;
- Cr = priv->Cr;
- offset_to_next_row = 2*priv->width*3 - 8*3;
- for (i=0; i<8; i++) {
-
- for (j=0; j<8; j++) {
-
- int y, cb, cr;
- int add_r, add_g, add_b;
- int r, g , b;
-
- cb = *Cb++ - 128;
- cr = *Cr++ - 128;
- add_r = FIX(1.40200) * cr + ONE_HALF;
- add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF;
- add_b = FIX(1.77200) * cb + ONE_HALF;
-
- y = (*Y++) << SCALEBITS;
- r = (y + add_r) >> SCALEBITS;
- g = (y + add_g) >> SCALEBITS;
- b = (y + add_b) >> SCALEBITS;
-
- priv->decomp_block[i*2][j*3+0]=clamp(r);
- priv->decomp_block[i*2][j*3+1]=clamp(g);
- priv->decomp_block[i*2][j*3+2]=clamp(b);
-
- y = (Y[8-1]) << SCALEBITS;
- r = (y + add_r) >> SCALEBITS;
- g = (y + add_g) >> SCALEBITS;
- b = (y + add_b) >> SCALEBITS;
-
- priv->decomp_block[i*2+1][j*3+0]=clamp(r);
- priv->decomp_block[i*2+1][j*3+1]=clamp(g);
- priv->decomp_block[i*2+1][j*3+2]=clamp(b);
-
- }
- Y += 8;
- p += offset_to_next_row;
- p2 += offset_to_next_row;
- }
-
-#undef SCALEBITS
-#undef ONE_HALF
-#undef FIX
-
-}
-
-/*
- * YCrCb -> BGR24 (1x2)
- * .---.
- * | 1 |
- * |---|
- * | 2 |
- * `---'
- */
-static void YCrCB_to_BGR24_1x2(struct jdec_private *priv)
-{
- const unsigned char *Y, *Cb, *Cr;
- unsigned char *p, *p2;
- int i,j;
- int offset_to_next_row;
-
-#define SCALEBITS 10
-#define ONE_HALF (1UL << (SCALEBITS-1))
-#define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5))
-
- p = priv->plane[0];
- p2 = priv->plane[0] + priv->width*3;
- Y = priv->Y;
- Cb = priv->Cb;
- Cr = priv->Cr;
- offset_to_next_row = 2*priv->width*3 - 8*3;
- for (i=0; i<8; i++) {
-
- for (j=0; j<8; j++) {
-
- int y, cb, cr;
- int add_r, add_g, add_b;
- int r, g , b;
-
- cb = *Cb++ - 128;
- cr = *Cr++ - 128;
- add_r = FIX(1.40200) * cr + ONE_HALF;
- add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF;
- add_b = FIX(1.77200) * cb + ONE_HALF;
-
- y = (*Y++) << SCALEBITS;
- b = (y + add_b) >> SCALEBITS;
- *p++ = clamp(b);
- g = (y + add_g) >> SCALEBITS;
- *p++ = clamp(g);
- r = (y + add_r) >> SCALEBITS;
- *p++ = clamp(r);
-
- y = (Y[8-1]) << SCALEBITS;
- b = (y + add_b) >> SCALEBITS;
- *p2++ = clamp(b);
- g = (y + add_g) >> SCALEBITS;
- *p2++ = clamp(g);
- r = (y + add_r) >> SCALEBITS;
- *p2++ = clamp(r);
-
- }
- Y += 8;
- p += offset_to_next_row;
- p2 += offset_to_next_row;
- }
-
-#undef SCALEBITS
-#undef ONE_HALF
-#undef FIX
-
-}
-
-
-/**
- * YCrCb -> RGB24 (2x2)
- * .-------.
- * | 1 | 2 |
- * |---+---|
- * | 3 | 4 |
- * `-------'
- */
-static void YCrCB_to_RGB24_2x2(struct jdec_private *priv)
-{
- const unsigned char *Y, *Cb, *Cr;
- unsigned char *p, *p2;
- int i,j;
- int offset_to_next_row;
-
-#define SCALEBITS 10
-#define ONE_HALF (1UL << (SCALEBITS-1))
-#define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5))
-
- p = priv->plane[0];
- p2 = priv->plane[0] + priv->width*3;
- Y = priv->Y;
- Cb = priv->Cb;
- Cr = priv->Cr;
- offset_to_next_row = (priv->width*3*2) - 16*3;
- for (i=0; i<8; i++) {
-
- for (j=0; j<8; j++) {
-
- int y, cb, cr;
- int add_r, add_g, add_b;
- int r, g , b;
-
- cb = *Cb++ - 128;
- cr = *Cr++ - 128;
- add_r = FIX(1.40200) * cr + ONE_HALF;
- add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF;
- add_b = FIX(1.77200) * cb + ONE_HALF;
-
- y = (*Y++) << SCALEBITS;
- r = (y + add_r) >> SCALEBITS;
- g = (y + add_g) >> SCALEBITS;
- b = (y + add_b) >> SCALEBITS;
-
- priv->decomp_block[i*2][j*6+0]=clamp(r);
- priv->decomp_block[i*2][j*6+1]=clamp(g);
- priv->decomp_block[i*2][j*6+2]=clamp(b);
-
- y = (*Y++) << SCALEBITS;
- r = (y + add_r) >> SCALEBITS;
- g = (y + add_g) >> SCALEBITS;
- b = (y + add_b) >> SCALEBITS;
-
- priv->decomp_block[i*2][j*6+3]=clamp(r);
- priv->decomp_block[i*2][j*6+4]=clamp(g);
- priv->decomp_block[i*2][j*6+5]=clamp(b);
-
- y = (Y[16-2]) << SCALEBITS;
- r = (y + add_r) >> SCALEBITS;
- g = (y + add_g) >> SCALEBITS;
- b = (y + add_b) >> SCALEBITS;
-
- priv->decomp_block[i*2+1][j*6+0]=clamp(r);
- priv->decomp_block[i*2+1][j*6+1]=clamp(g);
- priv->decomp_block[i*2+1][j*6+2]=clamp(b);
-
- y = (Y[16-1]) << SCALEBITS;
- r = (y + add_r) >> SCALEBITS;
- g = (y + add_g) >> SCALEBITS;
- b = (y + add_b) >> SCALEBITS;
-
- priv->decomp_block[i*2+1][j*6+3]=clamp(r);
- priv->decomp_block[i*2+1][j*6+4]=clamp(g);
- priv->decomp_block[i*2+1][j*6+5]=clamp(b);
-
- }
- Y += 16;
- p += offset_to_next_row;
- p2 += offset_to_next_row;
- }
-
-#undef SCALEBITS
-#undef ONE_HALF
-#undef FIX
-
-}
-
-
-/*
- * YCrCb -> BGR24 (2x2)
- * .-------.
- * | 1 | 2 |
- * |---+---|
- * | 3 | 4 |
- * `-------'
- */
-static void YCrCB_to_BGR24_2x2(struct jdec_private *priv)
-{
- const unsigned char *Y, *Cb, *Cr;
- unsigned char *p, *p2;
- int i,j;
- int offset_to_next_row;
-
-#define SCALEBITS 10
-#define ONE_HALF (1UL << (SCALEBITS-1))
-#define FIX(x) ((int)((x) * (1UL<<SCALEBITS) + 0.5))
-
- p = priv->plane[0];
- p2 = priv->plane[0] + priv->width*3;
- Y = priv->Y;
- Cb = priv->Cb;
- Cr = priv->Cr;
- offset_to_next_row = (priv->width*3*2) - 16*3;
- for (i=0; i<8; i++) {
-
- for (j=0; j<8; j++) {
-
- int y, cb, cr;
- int add_r, add_g, add_b;
- int r, g , b;
-
- cb = *Cb++ - 128;
- cr = *Cr++ - 128;
- add_r = FIX(1.40200) * cr + ONE_HALF;
- add_g = - FIX(0.34414) * cb - FIX(0.71414) * cr + ONE_HALF;
- add_b = FIX(1.77200) * cb + ONE_HALF;
-
- y = (*Y++) << SCALEBITS;
- b = (y + add_b) >> SCALEBITS;
- *p++ = clamp(b);
- g = (y + add_g) >> SCALEBITS;
- *p++ = clamp(g);
- r = (y + add_r) >> SCALEBITS;
- *p++ = clamp(r);
-
- y = (*Y++) << SCALEBITS;
- b = (y + add_b) >> SCALEBITS;
- *p++ = clamp(b);
- g = (y + add_g) >> SCALEBITS;
- *p++ = clamp(g);
- r = (y + add_r) >> SCALEBITS;
- *p++ = clamp(r);
-
- y = (Y[16-2]) << SCALEBITS;
- b = (y + add_b) >> SCALEBITS;
- *p2++ = clamp(b);
- g = (y + add_g) >> SCALEBITS;
- *p2++ = clamp(g);
- r = (y + add_r) >> SCALEBITS;
- *p2++ = clamp(r);
-
- y = (Y[16-1]) << SCALEBITS;
- b = (y + add_b) >> SCALEBITS;
- *p2++ = clamp(b);
- g = (y + add_g) >> SCALEBITS;
- *p2++ = clamp(g);
- r = (y + add_r) >> SCALEBITS;
- *p2++ = clamp(r);
- }
- Y += 16;
- p += offset_to_next_row;
- p2 += offset_to_next_row;
- }
-
-#undef SCALEBITS
-#undef ONE_HALF
-#undef FIX
-
-}
-
-
-
-/**
- * YCrCb -> Grey (1x1)
- * .---.
- * | 1 |
- * `---'
- */
-static void YCrCB_to_Grey_1x1(struct jdec_private *priv)
-{
- const unsigned char *y;
- unsigned char *p;
- unsigned int i;
- int offset_to_next_row;
-
- p = priv->plane[0];
- y = priv->Y;
- offset_to_next_row = priv->width;
-
- for (i=0; i<8; i++) {
- memcpy(p, y, 8);
- y+=8;
- p += offset_to_next_row;
- }
-}
-
-/**
- * YCrCb -> Grey (2x1)
- * .-------.
- * | 1 | 2 |
- * `-------'
- */
-static void YCrCB_to_Grey_2x1(struct jdec_private *priv)
-{
- const unsigned char *y;
- unsigned char *p;
- unsigned int i;
-
- p = priv->plane[0];
- y = priv->Y;
-
- for (i=0; i<8; i++) {
- memcpy(p, y, 16);
- y += 16;
- p += priv->width;
- }
-}
-
-
-/**
- * YCrCb -> Grey (1x2)
- * .---.
- * | 1 |
- * |---|
- * | 2 |
- * `---'
- */
-static void YCrCB_to_Grey_1x2(struct jdec_private *priv)
-{
- const unsigned char *y;
- unsigned char *p;
- unsigned int i;
-
- p = priv->plane[0];
- y = priv->Y;
-
- for (i=0; i<16; i++) {
- memcpy(p, y, 8);
- y += 8;
- p += priv->width;
- }
-}
-
-/**
- * YCrCb -> Grey (2x2)
- * .-------.
- * | 1 | 2 |
- * |---+---|
- * | 3 | 4 |
- * `-------'
- */
-static void YCrCB_to_Grey_2x2(struct jdec_private *priv)
-{
- const unsigned char *y;
- unsigned char *p;
- unsigned int i;
-
- p = priv->plane[0];
- y = priv->Y;
-
- for (i=0; i<16; i++) {
- memcpy(p, y, 16);
- y += 16;
- p += priv->width;
- }
-}
-
-
-/*
- * Decode all the 3 components for 1x1
- */
-static void decode_MCU_1x1_3planes(struct jdec_private *priv)
-{
- // Y
- process_Huffman_data_unit(priv, cY);
- IDCT(&priv->component_infos[cY], priv->Y, 8);
-
- // Cb
- process_Huffman_data_unit(priv, cCb);
- IDCT(&priv->component_infos[cCb], priv->Cb, 8);
-
- // Cr
- process_Huffman_data_unit(priv, cCr);
- IDCT(&priv->component_infos[cCr], priv->Cr, 8);
-}
-
-/*
- * Decode a 1x1 directly in 1 color
- */
-static void decode_MCU_1x1_1plane(struct jdec_private *priv)
-{
- // Y
- process_Huffman_data_unit(priv, cY);
- IDCT(&priv->component_infos[cY], priv->Y, 8);
-
- // Cb
- process_Huffman_data_unit(priv, cCb);
- IDCT(&priv->component_infos[cCb], priv->Cb, 8);
-
- // Cr
- process_Huffman_data_unit(priv, cCr);
- IDCT(&priv->component_infos[cCr], priv->Cr, 8);
-}
-
-
-/*
- * Decode a 2x1
- * .-------.
- * | 1 | 2 |
- * `-------'
- */
-static void decode_MCU_2x1_3planes(struct jdec_private *priv)
-{
- // Y
- process_Huffman_data_unit(priv, cY);
- IDCT(&priv->component_infos[cY], priv->Y, 16);
- process_Huffman_data_unit(priv, cY);
- IDCT(&priv->component_infos[cY], priv->Y+8, 16);
-
- // Cb
- process_Huffman_data_unit(priv, cCb);
- IDCT(&priv->component_infos[cCb], priv->Cb, 8);
-
- // Cr
- process_Huffman_data_unit(priv, cCr);
- IDCT(&priv->component_infos[cCr], priv->Cr, 8);
-}
-
-/*
- * Decode a 2x1
- * .-------.
- * | 1 | 2 |
- * `-------'
- */
-static void decode_MCU_2x1_1plane(struct jdec_private *priv)
-{
- // Y
- process_Huffman_data_unit(priv, cY);
- IDCT(&priv->component_infos[cY], priv->Y, 16);
- process_Huffman_data_unit(priv, cY);
- IDCT(&priv->component_infos[cY], priv->Y+8, 16);
-
- // Cb
- process_Huffman_data_unit(priv, cCb);
-
- // Cr
- process_Huffman_data_unit(priv, cCr);
-}
-
-
-/*
- * Decode a 2x2
- * .-------.
- * | 1 | 2 |
- * |---+---|
- * | 3 | 4 |
- * `-------'
- */
-static void decode_MCU_2x2_3planes(struct jdec_private *priv)
-{
- // Y
- process_Huffman_data_unit(priv, cY);
- IDCT(&priv->component_infos[cY], priv->Y, 16);
- process_Huffman_data_unit(priv, cY);
- IDCT(&priv->component_infos[cY], priv->Y+8, 16);
- process_Huffman_data_unit(priv, cY);
- IDCT(&priv->component_infos[cY], priv->Y+64*2, 16);
- process_Huffman_data_unit(priv, cY);
- IDCT(&priv->component_infos[cY], priv->Y+64*2+8, 16);
-
- // Cb
- process_Huffman_data_unit(priv, cCb);
- IDCT(&priv->component_infos[cCb], priv->Cb, 8);
-
- // Cr
- process_Huffman_data_unit(priv, cCr);
- IDCT(&priv->component_infos[cCr], priv->Cr, 8);
-}
-
-/*
- * Decode a 2x2 directly in GREY format (8bits)
- * .-------.
- * | 1 | 2 |
- * |---+---|
- * | 3 | 4 |
- * `-------'
- */
-static void decode_MCU_2x2_1plane(struct jdec_private *priv)
-{
- // Y
- process_Huffman_data_unit(priv, cY);
- IDCT(&priv->component_infos[cY], priv->Y, 16);
- process_Huffman_data_unit(priv, cY);
- IDCT(&priv->component_infos[cY], priv->Y+8, 16);
- process_Huffman_data_unit(priv, cY);
- IDCT(&priv->component_infos[cY], priv->Y+64*2, 16);
- process_Huffman_data_unit(priv, cY);
- IDCT(&priv->component_infos[cY], priv->Y+64*2+8, 16);
-
- // Cb
- process_Huffman_data_unit(priv, cCb);
-
- // Cr
- process_Huffman_data_unit(priv, cCr);
-}
-
-/*
- * Decode a 1x2 mcu
- * .---.
- * | 1 |
- * |---|
- * | 2 |
- * `---'
- */
-static void decode_MCU_1x2_3planes(struct jdec_private *priv)
-{
- // Y
- process_Huffman_data_unit(priv, cY);
- IDCT(&priv->component_infos[cY], priv->Y, 8);
- process_Huffman_data_unit(priv, cY);
- IDCT(&priv->component_infos[cY], priv->Y+64, 8);
-
- // Cb
- process_Huffman_data_unit(priv, cCb);
- IDCT(&priv->component_infos[cCb], priv->Cb, 8);
-
- // Cr
- process_Huffman_data_unit(priv, cCr);
- IDCT(&priv->component_infos[cCr], priv->Cr, 8);
-}
-
-/*
- * Decode a 1x2 mcu
- * .---.
- * | 1 |
- * |---|
- * | 2 |
- * `---'
- */
-static void decode_MCU_1x2_1plane(struct jdec_private *priv)
-{
- // Y
- process_Huffman_data_unit(priv, cY);
- IDCT(&priv->component_infos[cY], priv->Y, 8);
- process_Huffman_data_unit(priv, cY);
- IDCT(&priv->component_infos[cY], priv->Y+64, 8);
-
- // Cb
- process_Huffman_data_unit(priv, cCb);
-
- // Cr
- process_Huffman_data_unit(priv, cCr);
-}
-
-static void print_SOF(const unsigned char *stream)
-{
- int width, height, nr_components, precision;
-#if DEBUG
- const char *nr_components_to_string[] = {
- "????",
- "Grayscale",
- "????",
- "YCbCr",
- "CYMK"
- };
-#endif
-
- precision = stream[2];
- height = be16_to_cpu(stream+3);
- width = be16_to_cpu(stream+5);
- nr_components = stream[7];
-
- trace("> SOF marker\n");
- trace("Size:%dx%d nr_components:%d (%s) precision:%d\n",
- width, height,
- nr_components, nr_components_to_string[nr_components],
- precision);
-}
-
-/*******************************************************************************
- *
- * JPEG/JFIF Parsing functions
- *
- * Note: only a small subset of the jpeg file format is supported. No markers,
- * nor progressive stream is supported.
- *
- ******************************************************************************/
-
-static void build_quantization_table(float *qtable, const unsigned char *ref_table)
-{
- /* Taken from libjpeg. Copyright Independent JPEG Group's LLM idct.
- * For float AA&N IDCT method, divisors are equal to quantization
- * coefficients scaled by scalefactor[row]*scalefactor[col], where
- * scalefactor[0] = 1
- * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7
- * We apply a further scale factor of 8.
- * What's actually stored is 1/divisor so that the inner loop can
- * use a multiplication rather than a division.
- */
- int i, j;
- static const double aanscalefactor[8] = {
- 1.0, 1.387039845, 1.306562965, 1.175875602,
- 1.0, 0.785694958, 0.541196100, 0.275899379
- };
- const unsigned char *zz = zigzag;
-
- for (i=0; i<8; i++) {
- for (j=0; j<8; j++) {
- *qtable++ = ref_table[*zz++] * aanscalefactor[i] * aanscalefactor[j];
- }
- }
-
-}
-
-static int parse_DQT(struct jdec_private *priv, const unsigned char *stream)
-{
- int qi;
- float *table;
- const unsigned char *dqt_block_end;
-
- trace("> DQT marker\n");
- dqt_block_end = stream + be16_to_cpu(stream);
- stream += 2; /* Skip length */
-
- while (stream < dqt_block_end)
- {
- qi = *stream++;
-#if SANITY_CHECK
- if (qi>>4)
- error("16 bits quantization table is not supported\n");
- if (qi>4)
- error("No more 4 quantization table is supported (got %d)\n", qi);
-#endif
- table = priv->Q_tables[qi];
- build_quantization_table(table, stream);
- stream += 64;
- }
- trace("< DQT marker\n");
- return 0;
-}
-
-static int parse_SOF(struct jdec_private *priv, const unsigned char *stream)
-{
- int i, width, height, nr_components, cid, sampling_factor;
- int Q_table;
- struct component *c;
-
- trace("> SOF marker\n");
- print_SOF(stream);
-
- height = be16_to_cpu(stream+3);
- width = be16_to_cpu(stream+5);
- nr_components = stream[7];
-#if SANITY_CHECK
- if (stream[2] != 8)
- error("Precision other than 8 is not supported\n");
- if (width>JPEG_MAX_WIDTH || height>JPEG_MAX_HEIGHT)
- error("Width and Height (%dx%d) seems suspicious\n", width, height);
- if (nr_components != 3)
- error("We only support YUV images\n");
- //if (height%16)
-// error("Height need to be a multiple of 16 (current height is %d)\n", height);
-// if (width%16)
- // error("Width need to be a multiple of 16 (current Width is %d)\n", width);
-#endif
- stream += 8;
- for (i=0; i<nr_components; i++) {
- cid = *stream++;
- sampling_factor = *stream++;
- Q_table = *stream++;
- c = &priv->component_infos[i];
-#if SANITY_CHECK
- c->cid = cid;
- if (Q_table >= COMPONENTS)
- error("Bad Quantization table index (got %d, max allowed %d)\n", Q_table, COMPONENTS-1);
-#endif
- c->Vfactor = sampling_factor&0xf;
- c->Hfactor = sampling_factor>>4;
- c->Q_table = priv->Q_tables[Q_table];
- trace("Component:%d factor:%dx%d Quantization table:%d\n",
- cid, c->Hfactor, c->Hfactor, Q_table );
-
- }
- priv->width = width;
- priv->height = height;
-
- trace("< SOF marker\n");
-
- return 0;
-}
-
-static int parse_SOS(struct jdec_private *priv, const unsigned char *stream)
-{
- unsigned int i, cid, table;
- unsigned int nr_components = stream[2];
-
- trace("> SOS marker\n");
-
-#if SANITY_CHECK
- if (nr_components != 3)
- error("We only support YCbCr image\n");
-#endif
-
- stream += 3;
- for (i=0;i<nr_components;i++) {
- cid = *stream++;
- table = *stream++;
-#if SANITY_CHECK
- if ((table&0xf)>=4)
- error("We do not support more than 2 AC Huffman table\n");
- if ((table>>4)>=4)
- error("We do not support more than 2 DC Huffman table\n");
- if (cid != priv->component_infos[i].cid)
- error("SOS cid order (%d:%d) isn't compatible with the SOF marker (%d:%d)\n",
- i, cid, i, priv->component_infos[i].cid);
- trace("ComponentId:%d tableAC:%d tableDC:%d\n", cid, table&0xf, table>>4);
-#endif
- priv->component_infos[i].AC_table = &priv->HTAC[table&0xf];
- priv->component_infos[i].DC_table = &priv->HTDC[table>>4];
- }
- priv->stream = stream+3;
- trace("< SOS marker\n");
- return 0;
-}
-
-static int parse_DHT(struct jdec_private *priv, const unsigned char *stream)
-{
- unsigned int count, i;
- unsigned char huff_bits[17];
- int length, index;
-
- length = be16_to_cpu(stream) - 2;
- stream += 2; /* Skip length */
-
- trace("> DHT marker (length=%d)\n", length);
-
- while (length>0) {
- index = *stream++;
-
- /* We need to calculate the number of bytes 'vals' will takes */
- huff_bits[0] = 0;
- count = 0;
- for (i=1; i<17; i++) {
- huff_bits[i] = *stream++;
- count += huff_bits[i];
- }
-#if SANITY_CHECK
- if (count >= HUFFMAN_BITS_SIZE)
- error("No more than %d bytes is allowed to describe a huffman table", HUFFMAN_BITS_SIZE);
- if ( (index &0xf) >= HUFFMAN_TABLES)
- error("No more than %d Huffman tables is supported (got %d)\n", HUFFMAN_TABLES, index&0xf);
- trace("Huffman table %s[%d] length=%d\n", (index&0xf0)?"AC":"DC", index&0xf, count);
-#endif
-
- if (index & 0xf0 )
- build_huffman_table(huff_bits, stream, &priv->HTAC[index&0xf]);
- else
- build_huffman_table(huff_bits, stream, &priv->HTDC[index&0xf]);
-
- length -= 1;
- length -= 16;
- length -= count;
- stream += count;
- }
- trace("< DHT marker\n");
- return 0;
-}
-
-static int parse_DRI(struct jdec_private *priv, const unsigned char *stream)
-{
- unsigned int length;
-
- trace("> DRI marker\n");
-
- length = be16_to_cpu(stream);
-
-#if SANITY_CHECK
- if (length != 4)
- error("Length of DRI marker need to be 4\n");
-#endif
-
- priv->restart_interval = be16_to_cpu(stream+2);
-
-#if DEBUG
- trace("Restart interval = %d\n", priv->restart_interval);
-#endif
-
- trace("< DRI marker\n");
-
- return 0;
-}
-
-
-
-static void resync(struct jdec_private *priv)
-{
- int i;
-
- /* Init DC coefficients */
- for (i=0; i<COMPONENTS; i++)
- priv->component_infos[i].previous_DC = 0;
-
- priv->reservoir = 0;
- priv->nbits_in_reservoir = 0;
- if (priv->restart_interval > 0)
- priv->restarts_to_go = priv->restart_interval;
- else
- priv->restarts_to_go = -1;
-}
-
-static int find_next_rst_marker(struct jdec_private *priv)
-{
- int rst_marker_found = 0;
- int marker;
- const unsigned char *stream = priv->stream;
-
- /* Parse marker */
- while (!rst_marker_found)
- {
- while (*stream++ != 0xff)
- {
- if (stream >= priv->stream_end)
- error("EOF while search for a RST marker.");
- }
- /* Skip any padding ff byte (this is normal) */
- while (*stream == 0xff)
- stream++;
-
- marker = *stream++;
- if ((RST+priv->last_rst_marker_seen) == marker)
- rst_marker_found = 1;
- else if (marker >= RST && marker <= RST7)
- error("Wrong Reset marker found, abording");
- else if (marker == EOI)
- return 0;
- }
- trace("RST Marker %d found at offset %d\n", priv->last_rst_marker_seen, stream - priv->stream_begin);
-
- priv->stream = stream;
- priv->last_rst_marker_seen++;
- priv->last_rst_marker_seen &= 7;
-
- return 0;
-}
-
-static int parse_JFIF(struct jdec_private *priv, const unsigned char *stream)
-{
- int chuck_len;
- int marker;
- int sos_marker_found = 0;
- int dht_marker_found = 0;
- const unsigned char *next_chunck;
-
- /* Parse marker */
- while (!sos_marker_found)
- {
- if (*stream++ != 0xff)
- goto bogus_jpeg_format;
- /* Skip any padding ff byte (this is normal) */
- while (*stream == 0xff)
- stream++;
-
- marker = *stream++;
- chuck_len = be16_to_cpu(stream);
- next_chunck = stream + chuck_len;
- switch (marker)
- {
- case SOF:
- if (parse_SOF(priv, stream) < 0)
- return -1;
- break;
- case DQT:
- if (parse_DQT(priv, stream) < 0)
- return -1;
- break;
- case SOS:
- if (parse_SOS(priv, stream) < 0)
- return -1;
- sos_marker_found = 1;
- break;
- case DHT:
- if (parse_DHT(priv, stream) < 0)
- return -1;
- dht_marker_found = 1;
- break;
- case DRI:
- if (parse_DRI(priv, stream) < 0)
- return -1;
- break;
- default:
- trace("> Unknown marker %2.2x\n", marker);
- break;
- }
-
- stream = next_chunck;
- }
-
- if (!dht_marker_found) {
- trace("No Huffman table loaded, using the default one\n");
- build_default_huffman_tables(priv);
- }
-
-#ifdef SANITY_CHECK
- if ( (priv->component_infos[cY].Hfactor < priv->component_infos[cCb].Hfactor)
- || (priv->component_infos[cY].Hfactor < priv->component_infos[cCr].Hfactor))
- error("Horizontal sampling factor for Y should be greater than horitontal sampling factor for Cb or Cr\n");
- if ( (priv->component_infos[cY].Vfactor < priv->component_infos[cCb].Vfactor)
- || (priv->component_infos[cY].Vfactor < priv->component_infos[cCr].Vfactor))
- error("Vertical sampling factor for Y should be greater than vertical sampling factor for Cb or Cr\n");
- if ( (priv->component_infos[cCb].Hfactor!=1)
- || (priv->component_infos[cCr].Hfactor!=1)
- || (priv->component_infos[cCb].Vfactor!=1)
- || (priv->component_infos[cCr].Vfactor!=1))
- error("Sampling other than 1x1 for Cr and Cb is not supported");
-#endif
-
- return 0;
-bogus_jpeg_format:
- trace("Bogus jpeg format\n");
- return -1;
-}
-
-/*******************************************************************************
- *
- * Functions exported of the library.
- *
- * Note: Some applications can access directly to internal pointer of the
- * structure. It's is not recommended, but if you have many images to
- * uncompress with the same parameters, some functions can be called to speedup
- * the decoding.
- *
- ******************************************************************************/
-
-/**
- * Allocate a new tinyjpeg decoder object.
- *
- * Before calling any other functions, an object need to be called.
- */
-struct jdec_private *tinyjpeg_init(void *(*allocate_mem)(unsigned int),void (*free_mem)(void *))
-{
- struct jdec_private *priv;
- unsigned int i;
-
- priv = (struct jdec_private *)allocate_mem(sizeof(struct jdec_private));
- for(i=0;i<sizeof(struct jdec_private);i++) {
- char *pzero = (char*)priv;
- pzero[i]=0;
- }
- priv->allocate_mem=allocate_mem;
- priv->free_mem=free_mem;
- if (priv == NULL)
- return NULL;
- return priv;
-}
-
-/**
- * Free a tinyjpeg object.
- *
- * No others function can be called after this one.
- */
-void tinyjpeg_free(struct jdec_private *priv)
-{
- int i;
- for (i=0; i<COMPONENTS; i++) {
- if (priv->components[i]) {
- // priv->free_mem(priv->components[i]);
- priv->components[i] = NULL;
- }
- }
- priv->free_mem(priv);
-}
-
-/**
- * Initialize the tinyjpeg object and prepare the decoding of the stream.
- *
- * Check if the jpeg can be decoded with this jpeg decoder.
- * Fill some table used for preprocessing.
- */
-int tinyjpeg_parse_header(struct jdec_private *priv, const unsigned char *buf, unsigned int size)
-{
- int ret;
-
- /* Identify the file */
- if ((buf[0] != 0xFF) || (buf[1] != SOI))
- error("Not a JPG file ?\n");
-
- priv->stream_begin = buf+2;
- priv->stream_length = size-2;
- priv->stream_end = priv->stream_begin + priv->stream_length;
-
- ret = parse_JFIF(priv, priv->stream_begin);
-
- return ret;
-}
-
-static const decode_MCU_fct decode_mcu_3comp_table[4] = {
- decode_MCU_1x1_3planes,
- decode_MCU_1x2_3planes,
- decode_MCU_2x1_3planes,
- decode_MCU_2x2_3planes,
-};
-
-static const decode_MCU_fct decode_mcu_1comp_table[4] = {
- decode_MCU_1x1_1plane,
- decode_MCU_1x2_1plane,
- decode_MCU_2x1_1plane,
- decode_MCU_2x2_1plane,
-};
-
-static const convert_colorspace_fct convert_colorspace_yuv420p[4] = {
- YCrCB_to_YUV420P_1x1,
- YCrCB_to_YUV420P_1x2,
- YCrCB_to_YUV420P_2x1,
- YCrCB_to_YUV420P_2x2,
-};
-
-static const convert_colorspace_fct convert_colorspace_rgb24[4] = {
- YCrCB_to_RGB24_1x1,
- YCrCB_to_RGB24_1x2,
- YCrCB_to_RGB24_2x1,
- YCrCB_to_RGB24_2x2,
-};
-
-static const convert_colorspace_fct convert_colorspace_bgr24[4] = {
- YCrCB_to_BGR24_1x1,
- YCrCB_to_BGR24_1x2,
- YCrCB_to_BGR24_2x1,
- YCrCB_to_BGR24_2x2,
-};
-
-static const convert_colorspace_fct convert_colorspace_grey[4] = {
- YCrCB_to_Grey_1x1,
- YCrCB_to_Grey_1x2,
- YCrCB_to_Grey_2x1,
- YCrCB_to_Grey_2x2,
-};
-
-/**
- * Decode and convert the jpeg image into @pixfmt@ image
- *
- * Note: components will be automaticaly allocated if no memory is attached.
- */
-int tinyjpeg_decode(struct jdec_private *priv, int pixfmt)
-{
- unsigned int x, y, xstride_by_mcu, ystride_by_mcu;
- unsigned int bytes_per_blocklines[3], bytes_per_mcu[3];
- decode_MCU_fct decode_MCU;
- const decode_MCU_fct *decode_mcu_table;
- const convert_colorspace_fct *colorspace_array_conv;
- convert_colorspace_fct convert_to_pixfmt;
-
- if (pixfmt!=TINYJPEG_FMT_RGB24)
- error("Only TINYJPEG_FMT_RGB24 is supported in this version");
-
- if (setjmp(priv->jump_state))
- return -1;
-
- /* To keep gcc happy initialize some array */
- bytes_per_mcu[1] = 0;
- bytes_per_mcu[2] = 0;
- bytes_per_blocklines[1] = 0;
- bytes_per_blocklines[2] = 0;
-
- decode_mcu_table = decode_mcu_3comp_table;
- switch (pixfmt) {
- case TINYJPEG_FMT_YUV420P:
- colorspace_array_conv = convert_colorspace_yuv420p;
- if (priv->components[0] == NULL)
- priv->components[0] = (uint8_t *)priv->allocate_mem(priv->width * priv->height);
- if (priv->components[1] == NULL)
- priv->components[1] = (uint8_t *)priv->allocate_mem(priv->width * priv->height/4);
- if (priv->components[2] == NULL)
- priv->components[2] = (uint8_t *)priv->allocate_mem(priv->width * priv->height/4);
- bytes_per_blocklines[0] = priv->width;
- bytes_per_blocklines[1] = priv->width/4;
- bytes_per_blocklines[2] = priv->width/4;
- bytes_per_mcu[0] = 8;
- bytes_per_mcu[1] = 4;
- bytes_per_mcu[2] = 4;
- break;
-
- case TINYJPEG_FMT_RGB24:
- colorspace_array_conv = convert_colorspace_rgb24;
- if (priv->components[0] == NULL)
- priv->components[0] = (uint8_t *)priv->allocate_mem(priv->width * priv->height * 3);
- bytes_per_blocklines[0] = priv->width * 3;
- bytes_per_mcu[0] = 3*8;
- break;
-
- case TINYJPEG_FMT_BGR24:
- colorspace_array_conv = convert_colorspace_bgr24;
- if (priv->components[0] == NULL)
- priv->components[0] = (uint8_t *)priv->allocate_mem(priv->width * priv->height * 3);
- bytes_per_blocklines[0] = priv->width * 3;
- bytes_per_mcu[0] = 3*8;
- break;
-
- case TINYJPEG_FMT_GREY:
- decode_mcu_table = decode_mcu_1comp_table;
- colorspace_array_conv = convert_colorspace_grey;
- if (priv->components[0] == NULL)
- priv->components[0] = (uint8_t *)priv->allocate_mem(priv->width * priv->height);
- bytes_per_blocklines[0] = priv->width;
- bytes_per_mcu[0] = 8;
- break;
-
- default:
- trace("Bad pixel format\n");
- return -1;
- }
-
- xstride_by_mcu = ystride_by_mcu = 8;
- if ((priv->component_infos[cY].Hfactor | priv->component_infos[cY].Vfactor) == 1) {
- decode_MCU = decode_mcu_table[0];
- convert_to_pixfmt = colorspace_array_conv[0];
- trace("Use decode 1x1 sampling\n");
- } else if (priv->component_infos[cY].Hfactor == 1) {
- decode_MCU = decode_mcu_table[1];
- convert_to_pixfmt = colorspace_array_conv[1];
- ystride_by_mcu = 16;
- trace("Use decode 1x2 sampling (not supported)\n");
- } else if (priv->component_infos[cY].Vfactor == 2) {
- decode_MCU = decode_mcu_table[3];
- convert_to_pixfmt = colorspace_array_conv[3];
- xstride_by_mcu = 16;
- ystride_by_mcu = 16;
- trace("Use decode 2x2 sampling\n");
- } else {
- decode_MCU = decode_mcu_table[2];
- convert_to_pixfmt = colorspace_array_conv[2];
- xstride_by_mcu = 16;
- trace("Use decode 2x1 sampling\n");
- }
-
- resync(priv);
-
- /* Don't forget to that block can be either 8 or 16 lines */
- bytes_per_blocklines[0] *= ystride_by_mcu;
- bytes_per_blocklines[1] *= ystride_by_mcu;
- bytes_per_blocklines[2] *= ystride_by_mcu;
-
- bytes_per_mcu[0] *= xstride_by_mcu/8;
- bytes_per_mcu[1] *= xstride_by_mcu/8;
- bytes_per_mcu[2] *= xstride_by_mcu/8;
-
- /* Just the decode the image by macroblock (size is 8x8, 8x16, or 16x16) */
-
-
-
- for (y=0; y < priv->height; y+=ystride_by_mcu)
- {
- //trace("Decoding row %d\n", y);
- /// priv->plane[0] = priv->components[0] + (y/ystride_by_mcu * bytes_per_blocklines[0]);
- /// priv->plane[1] = priv->components[1] + (y/ystride_by_mcu * bytes_per_blocklines[1]);
- /// priv->plane[2] = priv->components[2] + (y/ystride_by_mcu * bytes_per_blocklines[2]);
- for (x=0; x < priv->width; x+=xstride_by_mcu)
- {
- int i,copy_x,copy_y;
- decode_MCU(priv);
- convert_to_pixfmt(priv);
- //priv->plane[0] += bytes_per_mcu[0];
- //priv->plane[1] += bytes_per_mcu[1];
- //priv->plane[2] += bytes_per_mcu[2];
-
- copy_x=priv->width-x;
- if (copy_x>xstride_by_mcu)
- copy_x=xstride_by_mcu;
-
- copy_y=priv->height-y;
- if (copy_y>ystride_by_mcu)
- copy_y=ystride_by_mcu;
-
- for(i=0;i<copy_y;i++) {
- unsigned char *dst = &priv->components[0][((y+i)*priv->width+x)*3];
- memcpy(dst,&priv->decomp_block[i][0],copy_x*3);
- }
-
- if (priv->restarts_to_go>0)
- {
- priv->restarts_to_go--;
- if (priv->restarts_to_go == 0)
- {
- priv->stream -= (priv->nbits_in_reservoir/8);
- resync(priv);
- if (find_next_rst_marker(priv) < 0)
- return -1;
- }
- }
- }
- }
-
- trace("Input file size: %d\n", priv->stream_length+2);
- trace("Input bytes actually read: %d\n", priv->stream - priv->stream_begin + 2);
-
- return 0;
-}
-
-const char *tinyjpeg_get_errorstring(struct jdec_private *priv)
-{
- /* FIXME: the error string must be store in the context */
- priv = priv;
- return error_string;
-}
-
-void tinyjpeg_get_size(struct jdec_private *priv, unsigned int *width, unsigned int *height)
-{
- *width = priv->width;
- *height = priv->height;
-}
-
-int tinyjpeg_get_components(struct jdec_private *priv, unsigned char **components)
-{
- int i;
- for (i=0; priv->components[i] && i<COMPONENTS; i++)
- components[i] = priv->components[i];
- return 0;
-}
-
-int tinyjpeg_set_components(struct jdec_private *priv, unsigned char **components, unsigned int ncomponents)
-{
- unsigned int i;
- if (ncomponents > COMPONENTS)
- ncomponents = COMPONENTS;
- for (i=0; i<ncomponents; i++)
- priv->components[i] = components[i];
- return 0;
-}
-
-int tinyjpeg_set_flags(struct jdec_private *priv, int flags)
-{
- int oldflags = priv->flags;
- priv->flags = flags;
- return oldflags;
-}
-
diff --git a/drivers/jpg/tinyjpeg.h b/drivers/jpg/tinyjpeg.h
deleted file mode 100644
index fe4652360b..0000000000
--- a/drivers/jpg/tinyjpeg.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Small jpeg decoder library (header file)
- *
- * Copyright (c) 2006, Luc Saillard <luc@saillard.org>
- * All rights reserved.
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * - Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * - Neither the name of the author nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- */
-
-
-#ifndef __JPEGDEC_H__
-#define __JPEGDEC_H__
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct jdec_private;
-
-/* Flags that can be set by any applications */
-#define TINYJPEG_FLAGS_MJPEG_TABLE (1<<1)
-
-/* Format accepted in outout */
-enum tinyjpeg_fmt {
- TINYJPEG_FMT_GREY = 1,
- TINYJPEG_FMT_BGR24,
- TINYJPEG_FMT_RGB24,
- TINYJPEG_FMT_YUV420P,
-};
-
-struct jdec_private *tinyjpeg_init(void *(*allocate_mem)(unsigned int),void (*free_mem)(void *));
-
-void tinyjpeg_free(struct jdec_private *priv);
-
-int tinyjpeg_parse_header(struct jdec_private *priv, const unsigned char *buf, unsigned int size);
-int tinyjpeg_decode(struct jdec_private *priv, int pixel_format);
-const char *tinyjpeg_get_errorstring(struct jdec_private *priv);
-void tinyjpeg_get_size(struct jdec_private *priv, unsigned int *width, unsigned int *height);
-int tinyjpeg_get_components(struct jdec_private *priv, unsigned char **components);
-int tinyjpeg_set_components(struct jdec_private *priv, unsigned char **components, unsigned int ncomponents);
-int tinyjpeg_set_flags(struct jdec_private *priv, int flags);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
-
-
-
diff --git a/drivers/mpc/SCsub b/drivers/mpc/SCsub
index af61d95e4c..32ffdb863f 100644
--- a/drivers/mpc/SCsub
+++ b/drivers/mpc/SCsub
@@ -19,4 +19,3 @@ env.add_source_files(env.drivers_sources,"*.cpp")
#env.add_source_files(env.drivers_sources, mpc_sources)
Export('env')
-
diff --git a/drivers/mpc/audio_stream_mpc.cpp b/drivers/mpc/audio_stream_mpc.cpp
index cd8125c9af..fe6aa05d00 100644
--- a/drivers/mpc/audio_stream_mpc.cpp
+++ b/drivers/mpc/audio_stream_mpc.cpp
@@ -1,7 +1,7 @@
#include "audio_stream_mpc.h"
-Error AudioStreamMPC::_open_file() {
+Error AudioStreamPlaybackMPC::_open_file() {
if (f) {
memdelete(f);
@@ -41,7 +41,7 @@ Error AudioStreamMPC::_open_file() {
return OK;
}
-void AudioStreamMPC::_close_file() {
+void AudioStreamPlaybackMPC::_close_file() {
if (f) {
memdelete(f);
@@ -52,7 +52,7 @@ void AudioStreamMPC::_close_file() {
data_ofs=0;
}
-int AudioStreamMPC::_read_file(void *p_dst,int p_bytes) {
+int AudioStreamPlaybackMPC::_read_file(void *p_dst,int p_bytes) {
if (f)
return f->get_buffer((uint8_t*)p_dst,p_bytes);
@@ -68,7 +68,7 @@ int AudioStreamMPC::_read_file(void *p_dst,int p_bytes) {
return p_bytes;
}
-bool AudioStreamMPC::_seek_file(int p_pos){
+bool AudioStreamPlaybackMPC::_seek_file(int p_pos){
if (p_pos<0 || p_pos>streamlen)
return false;
@@ -83,7 +83,7 @@ bool AudioStreamMPC::_seek_file(int p_pos){
return true;
}
-int AudioStreamMPC::_tell_file() const{
+int AudioStreamPlaybackMPC::_tell_file() const{
if (f)
return f->get_pos();
@@ -93,13 +93,13 @@ int AudioStreamMPC::_tell_file() const{
}
-int AudioStreamMPC::_sizeof_file() const{
+int AudioStreamPlaybackMPC::_sizeof_file() const{
//print_line("sizeof file, get: "+itos(streamlen));
return streamlen;
}
-bool AudioStreamMPC::_canseek_file() const{
+bool AudioStreamPlaybackMPC::_canseek_file() const{
//print_line("canseek file, get true");
return true;
@@ -107,51 +107,46 @@ bool AudioStreamMPC::_canseek_file() const{
/////////////////////
-mpc_int32_t AudioStreamMPC::_mpc_read(mpc_reader *p_reader,void *p_dst, mpc_int32_t p_bytes) {
+mpc_int32_t AudioStreamPlaybackMPC::_mpc_read(mpc_reader *p_reader,void *p_dst, mpc_int32_t p_bytes) {
- AudioStreamMPC *smpc=(AudioStreamMPC *)p_reader->data;
+ AudioStreamPlaybackMPC *smpc=(AudioStreamPlaybackMPC *)p_reader->data;
return smpc->_read_file(p_dst,p_bytes);
}
-mpc_bool_t AudioStreamMPC::_mpc_seek(mpc_reader *p_reader,mpc_int32_t p_offset) {
+mpc_bool_t AudioStreamPlaybackMPC::_mpc_seek(mpc_reader *p_reader,mpc_int32_t p_offset) {
- AudioStreamMPC *smpc=(AudioStreamMPC *)p_reader->data;
+ AudioStreamPlaybackMPC *smpc=(AudioStreamPlaybackMPC *)p_reader->data;
return smpc->_seek_file(p_offset);
}
-mpc_int32_t AudioStreamMPC::_mpc_tell(mpc_reader *p_reader) {
+mpc_int32_t AudioStreamPlaybackMPC::_mpc_tell(mpc_reader *p_reader) {
- AudioStreamMPC *smpc=(AudioStreamMPC *)p_reader->data;
+ AudioStreamPlaybackMPC *smpc=(AudioStreamPlaybackMPC *)p_reader->data;
return smpc->_tell_file();
}
-mpc_int32_t AudioStreamMPC::_mpc_get_size(mpc_reader *p_reader) {
+mpc_int32_t AudioStreamPlaybackMPC::_mpc_get_size(mpc_reader *p_reader) {
- AudioStreamMPC *smpc=(AudioStreamMPC *)p_reader->data;
+ AudioStreamPlaybackMPC *smpc=(AudioStreamPlaybackMPC *)p_reader->data;
return smpc->_sizeof_file();
}
-mpc_bool_t AudioStreamMPC::_mpc_canseek(mpc_reader *p_reader) {
+mpc_bool_t AudioStreamPlaybackMPC::_mpc_canseek(mpc_reader *p_reader) {
- AudioStreamMPC *smpc=(AudioStreamMPC *)p_reader->data;
+ AudioStreamPlaybackMPC *smpc=(AudioStreamPlaybackMPC *)p_reader->data;
return smpc->_canseek_file();
}
-bool AudioStreamMPC::_can_mix() const {
- return /*active &&*/ !paused;
-}
-
-
-void AudioStreamMPC::update() {
+int AudioStreamPlaybackMPC::mix(int16_t* p_bufer,int p_frames) {
if (!active || paused)
- return;
+ return 0;
- int todo=get_todo();
+ int todo=p_frames;
while(todo>MPC_DECODER_BUFFER_LENGTH/si.channels) {
@@ -162,7 +157,7 @@ void AudioStreamMPC::update() {
mpc_status err = mpc_demux_decode(demux, &frame);
if (frame.bits!=-1) {
- int16_t *dst_buff = get_write_buffer();
+ int16_t *dst_buff = p_bufer;
#ifdef MPC_FIXED_POINT
@@ -185,21 +180,21 @@ void AudioStreamMPC::update() {
#endif
int frames = frame.samples;
- write(frames);
+ p_bufer+=si.channels*frames;
todo-=frames;
} else {
if (err != MPC_STATUS_OK) {
stop();
- ERR_EXPLAIN("Error decoding MPC");
- ERR_FAIL();
+ ERR_PRINT("Error decoding MPC");
+ break;
} else {
//finished
if (!loop) {
stop();
- return;
+ break;
} else {
@@ -213,9 +208,11 @@ void AudioStreamMPC::update() {
}
}
}
+
+ return p_frames-todo;
}
-Error AudioStreamMPC::_reload() {
+Error AudioStreamPlaybackMPC::_reload() {
ERR_FAIL_COND_V(demux!=NULL, ERR_FILE_ALREADY_IN_USE);
@@ -224,30 +221,39 @@ Error AudioStreamMPC::_reload() {
demux = mpc_demux_init(&reader);
ERR_FAIL_COND_V(!demux,ERR_CANT_CREATE);
-
mpc_demux_get_info(demux, &si);
- _setup(si.channels,si.sample_freq,MPC_DECODER_BUFFER_LENGTH*2/si.channels);
return OK;
}
-void AudioStreamMPC::set_file(const String& p_file) {
+void AudioStreamPlaybackMPC::set_file(const String& p_file) {
file=p_file;
+ Error err = _open_file();
+ ERR_FAIL_COND(err!=OK);
+ demux = mpc_demux_init(&reader);
+ ERR_FAIL_COND(!demux);
+ mpc_demux_get_info(demux, &si);
+ stream_min_size=MPC_DECODER_BUFFER_LENGTH*2/si.channels;
+ stream_rate=si.sample_freq;
+ stream_channels=si.channels;
+
+ mpc_demux_exit(demux);
+ demux=NULL;
+ _close_file();
+
}
-String AudioStreamMPC::get_file() const {
+String AudioStreamPlaybackMPC::get_file() const {
return file;
}
-void AudioStreamMPC::play() {
-
+void AudioStreamPlaybackMPC::play(float p_offset) {
- _THREAD_SAFE_METHOD_
if (active)
stop();
@@ -262,9 +268,9 @@ void AudioStreamMPC::play() {
}
-void AudioStreamMPC::stop() {
+void AudioStreamPlaybackMPC::stop() {
+
- _THREAD_SAFE_METHOD_
if (!active)
return;
if (demux) {
@@ -275,70 +281,58 @@ void AudioStreamMPC::stop() {
active=false;
}
-bool AudioStreamMPC::is_playing() const {
+bool AudioStreamPlaybackMPC::is_playing() const {
- return active || (get_total() - get_todo() -1 > 0);
+ return active;
}
-void AudioStreamMPC::set_paused(bool p_paused) {
- paused=p_paused;
-}
-bool AudioStreamMPC::is_paused(bool p_paused) const {
-
- return paused;
-}
-
-void AudioStreamMPC::set_loop(bool p_enable) {
+void AudioStreamPlaybackMPC::set_loop(bool p_enable) {
loop=p_enable;
}
-bool AudioStreamMPC::has_loop() const {
+bool AudioStreamPlaybackMPC::has_loop() const {
return loop;
}
-float AudioStreamMPC::get_length() const {
+float AudioStreamPlaybackMPC::get_length() const {
return 0;
}
-String AudioStreamMPC::get_stream_name() const {
+String AudioStreamPlaybackMPC::get_stream_name() const {
return "";
}
-int AudioStreamMPC::get_loop_count() const {
+int AudioStreamPlaybackMPC::get_loop_count() const {
return 0;
}
-float AudioStreamMPC::get_pos() const {
+float AudioStreamPlaybackMPC::get_pos() const {
return 0;
}
-void AudioStreamMPC::seek_pos(float p_time) {
+void AudioStreamPlaybackMPC::seek_pos(float p_time) {
}
-AudioStream::UpdateMode AudioStreamMPC::get_update_mode() const {
- return UPDATE_THREAD;
-}
+void AudioStreamPlaybackMPC::_bind_methods() {
-void AudioStreamMPC::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("set_file","name"),&AudioStreamMPC::set_file);
- ObjectTypeDB::bind_method(_MD("get_file"),&AudioStreamMPC::get_file);
+ ObjectTypeDB::bind_method(_MD("set_file","name"),&AudioStreamPlaybackMPC::set_file);
+ ObjectTypeDB::bind_method(_MD("get_file"),&AudioStreamPlaybackMPC::get_file);
ADD_PROPERTYNZ( PropertyInfo(Variant::STRING,"file",PROPERTY_HINT_FILE,"mpc"), _SCS("set_file"), _SCS("get_file"));
}
-AudioStreamMPC::AudioStreamMPC() {
+AudioStreamPlaybackMPC::AudioStreamPlaybackMPC() {
- preload=true;
+ preload=false;
f=NULL;
streamlen=0;
data_ofs=0;
@@ -356,7 +350,7 @@ AudioStreamMPC::AudioStreamMPC() {
}
-AudioStreamMPC::~AudioStreamMPC() {
+AudioStreamPlaybackMPC::~AudioStreamPlaybackMPC() {
stop();
@@ -366,8 +360,9 @@ AudioStreamMPC::~AudioStreamMPC() {
-RES ResourceFormatLoaderAudioStreamMPC::load(const String &p_path,const String& p_original_path) {
-
+RES ResourceFormatLoaderAudioStreamMPC::load(const String &p_path, const String& p_original_path, Error *r_error) {
+ if (r_error)
+ *r_error=OK; //streamed so it will always work..
AudioStreamMPC *mpc_stream = memnew(AudioStreamMPC);
mpc_stream->set_file(p_path);
return Ref<AudioStreamMPC>(mpc_stream);
diff --git a/drivers/mpc/audio_stream_mpc.h b/drivers/mpc/audio_stream_mpc.h
index fa949acd00..122d0d0bbb 100644
--- a/drivers/mpc/audio_stream_mpc.h
+++ b/drivers/mpc/audio_stream_mpc.h
@@ -1,18 +1,17 @@
#ifndef AUDIO_STREAM_MPC_H
#define AUDIO_STREAM_MPC_H
-#include "scene/resources/audio_stream_resampled.h"
+#include "scene/resources/audio_stream.h"
#include "os/file_access.h"
#include "mpc/mpcdec.h"
#include "os/thread_safe.h"
#include "io/resource_loader.h"
//#include "../libmpcdec/decoder.h"
//#include "../libmpcdec/internal.h"
-class AudioStreamMPC : public AudioStreamResampled {
- OBJ_TYPE( AudioStreamMPC, AudioStreamResampled );
+class AudioStreamPlaybackMPC : public AudioStreamPlayback {
- _THREAD_SAFE_CLASS_
+ OBJ_TYPE( AudioStreamPlaybackMPC, AudioStreamPlayback );
bool preload;
FileAccess *f;
@@ -39,7 +38,9 @@ class AudioStreamMPC : public AudioStreamResampled {
static mpc_int32_t _mpc_get_size(mpc_reader *p_reader);
static mpc_bool_t _mpc_canseek(mpc_reader *p_reader);
- virtual bool _can_mix() const ;
+ int stream_min_size;
+ int stream_rate;
+ int stream_channels;
protected:
Error _open_file();
@@ -59,12 +60,10 @@ public:
void set_file(const String& p_file);
String get_file() const;
- virtual void play();
+ virtual void play(float p_offset=0);
virtual void stop();
virtual bool is_playing() const;
- virtual void set_paused(bool p_paused);
- virtual bool is_paused(bool p_paused) const;
virtual void set_loop(bool p_enable);
virtual bool has_loop() const;
@@ -78,17 +77,39 @@ public:
virtual float get_pos() const;
virtual void seek_pos(float p_time);
- virtual UpdateMode get_update_mode() const;
- virtual void update();
+ virtual int get_channels() const { return stream_channels; }
+ virtual int get_mix_rate() const { return stream_rate; }
- AudioStreamMPC();
- ~AudioStreamMPC();
+ virtual int get_minimum_buffer_size() const { return stream_min_size; }
+ virtual int mix(int16_t* p_bufer,int p_frames);
+
+ virtual void set_loop_restart_time(float p_time) { }
+
+ AudioStreamPlaybackMPC();
+ ~AudioStreamPlaybackMPC();
};
+class AudioStreamMPC : public AudioStream {
+
+ OBJ_TYPE( AudioStreamMPC, AudioStream );
+
+ String file;
+public:
+
+ Ref<AudioStreamPlayback> instance_playback() {
+ Ref<AudioStreamPlaybackMPC> pb = memnew( AudioStreamPlaybackMPC );
+ pb->set_file(file);
+ return pb;
+ }
+
+ void set_file(const String& p_file) { file=p_file; }
+
+
+};
class ResourceFormatLoaderAudioStreamMPC : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path,const String& p_original_path="");
+ virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String& p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/drivers/nedmalloc/SCsub b/drivers/nedmalloc/SCsub
index 8c0028b41d..8e6edd1f96 100644
--- a/drivers/nedmalloc/SCsub
+++ b/drivers/nedmalloc/SCsub
@@ -3,4 +3,3 @@ Export('env');
env.add_source_files(env.drivers_sources,"*.cpp")
#env.add_source_files(env.drivers_sources,"*.c")
-
diff --git a/drivers/nedmalloc/malloc.c.h b/drivers/nedmalloc/malloc.c.h
index b9e65637d5..4fec5cc9d4 100644
--- a/drivers/nedmalloc/malloc.c.h
+++ b/drivers/nedmalloc/malloc.c.h
@@ -1,5814 +1,5814 @@
-#ifdef NEDMALLOC_ENABLED
-/*
- This is a version (aka dlmalloc) of malloc/free/realloc written by
- Doug Lea and released to the public domain, as explained at
- http://creativecommons.org/licenses/publicdomain. Send questions,
- comments, complaints, performance data, etc to dl@cs.oswego.edu
-
-* Version 2.8.4 Wed May 27 09:56:23 2009 Doug Lea (dl at gee)
-
- Note: There may be an updated version of this malloc obtainable at
- ftp://gee.cs.oswego.edu/pub/misc/malloc.c
- Check before installing!
-
-* Quickstart
-
- This library is all in one file to simplify the most common usage:
- ftp it, compile it (-O3), and link it into another program. All of
- the compile-time options default to reasonable values for use on
- most platforms. You might later want to step through various
- compile-time and dynamic tuning options.
-
- For convenience, an include file for code using this malloc is at:
- ftp://gee.cs.oswego.edu/pub/misc/malloc-2.8.4.h
- You don't really need this .h file unless you call functions not
- defined in your system include files. The .h file contains only the
- excerpts from this file needed for using this malloc on ANSI C/C++
- systems, so long as you haven't changed compile-time options about
- naming and tuning parameters. If you do, then you can create your
- own malloc.h that does include all settings by cutting at the point
- indicated below. Note that you may already by default be using a C
- library containing a malloc that is based on some version of this
- malloc (for example in linux). You might still want to use the one
- in this file to customize settings or to avoid overheads associated
- with library versions.
-
-* Vital statistics:
-
- Supported pointer/size_t representation: 4 or 8 bytes
- size_t MUST be an unsigned type of the same width as
- pointers. (If you are using an ancient system that declares
- size_t as a signed type, or need it to be a different width
- than pointers, you can use a previous release of this malloc
- (e.g. 2.7.2) supporting these.)
-
- Alignment: 8 bytes (default)
- This suffices for nearly all current machines and C compilers.
- However, you can define MALLOC_ALIGNMENT to be wider than this
- if necessary (up to 128bytes), at the expense of using more space.
-
- Minimum overhead per allocated chunk: 4 or 8 bytes (if 4byte sizes)
- 8 or 16 bytes (if 8byte sizes)
- Each malloced chunk has a hidden word of overhead holding size
- and status information, and additional cross-check word
- if FOOTERS is defined.
-
- Minimum allocated size: 4-byte ptrs: 16 bytes (including overhead)
- 8-byte ptrs: 32 bytes (including overhead)
-
- Even a request for zero bytes (i.e., malloc(0)) returns a
- pointer to something of the minimum allocatable size.
- The maximum overhead wastage (i.e., number of extra bytes
- allocated than were requested in malloc) is less than or equal
- to the minimum size, except for requests >= mmap_threshold that
- are serviced via mmap(), where the worst case wastage is about
- 32 bytes plus the remainder from a system page (the minimal
- mmap unit); typically 4096 or 8192 bytes.
-
- Security: static-safe; optionally more or less
- The "security" of malloc refers to the ability of malicious
- code to accentuate the effects of errors (for example, freeing
- space that is not currently malloc'ed or overwriting past the
- ends of chunks) in code that calls malloc. This malloc
- guarantees not to modify any memory locations below the base of
- heap, i.e., static variables, even in the presence of usage
- errors. The routines additionally detect most improper frees
- and reallocs. All this holds as long as the static bookkeeping
- for malloc itself is not corrupted by some other means. This
- is only one aspect of security -- these checks do not, and
- cannot, detect all possible programming errors.
-
- If FOOTERS is defined nonzero, then each allocated chunk
- carries an additional check word to verify that it was malloced
- from its space. These check words are the same within each
- execution of a program using malloc, but differ across
- executions, so externally crafted fake chunks cannot be
- freed. This improves security by rejecting frees/reallocs that
- could corrupt heap memory, in addition to the checks preventing
- writes to statics that are always on. This may further improve
- security at the expense of time and space overhead. (Note that
- FOOTERS may also be worth using with MSPACES.)
-
- By default detected errors cause the program to abort (calling
- "abort()"). You can override this to instead proceed past
- errors by defining PROCEED_ON_ERROR. In this case, a bad free
- has no effect, and a malloc that encounters a bad address
- caused by user overwrites will ignore the bad address by
- dropping pointers and indices to all known memory. This may
- be appropriate for programs that should continue if at all
- possible in the face of programming errors, although they may
- run out of memory because dropped memory is never reclaimed.
-
- If you don't like either of these options, you can define
- CORRUPTION_ERROR_ACTION and USAGE_ERROR_ACTION to do anything
- else. And if if you are sure that your program using malloc has
- no errors or vulnerabilities, you can define INSECURE to 1,
- which might (or might not) provide a small performance improvement.
-
- Thread-safety: NOT thread-safe unless USE_LOCKS defined
- When USE_LOCKS is defined, each public call to malloc, free,
- etc is surrounded with either a pthread mutex or a win32
- spinlock (depending on WIN32). This is not especially fast, and
- can be a major bottleneck. It is designed only to provide
- minimal protection in concurrent environments, and to provide a
- basis for extensions. If you are using malloc in a concurrent
- program, consider instead using nedmalloc
- (http://www.nedprod.com/programs/portable/nedmalloc/) or
- ptmalloc (See http://www.malloc.de), which are derived
- from versions of this malloc.
-
- System requirements: Any combination of MORECORE and/or MMAP/MUNMAP
- This malloc can use unix sbrk or any emulation (invoked using
- the CALL_MORECORE macro) and/or mmap/munmap or any emulation
- (invoked using CALL_MMAP/CALL_MUNMAP) to get and release system
- memory. On most unix systems, it tends to work best if both
- MORECORE and MMAP are enabled. On Win32, it uses emulations
- based on VirtualAlloc. It also uses common C library functions
- like memset.
-
- Compliance: I believe it is compliant with the Single Unix Specification
- (See http://www.unix.org). Also SVID/XPG, ANSI C, and probably
- others as well.
-
-* Overview of algorithms
-
- This is not the fastest, most space-conserving, most portable, or
- most tunable malloc ever written. However it is among the fastest
- while also being among the most space-conserving, portable and
- tunable. Consistent balance across these factors results in a good
- general-purpose allocator for malloc-intensive programs.
-
- In most ways, this malloc is a best-fit allocator. Generally, it
- chooses the best-fitting existing chunk for a request, with ties
- broken in approximately least-recently-used order. (This strategy
- normally maintains low fragmentation.) However, for requests less
- than 256bytes, it deviates from best-fit when there is not an
- exactly fitting available chunk by preferring to use space adjacent
- to that used for the previous small request, as well as by breaking
- ties in approximately most-recently-used order. (These enhance
- locality of series of small allocations.) And for very large requests
- (>= 256Kb by default), it relies on system memory mapping
- facilities, if supported. (This helps avoid carrying around and
- possibly fragmenting memory used only for large chunks.)
-
- All operations (except malloc_stats and mallinfo) have execution
- times that are bounded by a constant factor of the number of bits in
- a size_t, not counting any clearing in calloc or copying in realloc,
- or actions surrounding MORECORE and MMAP that have times
- proportional to the number of non-contiguous regions returned by
- system allocation routines, which is often just 1. In real-time
- applications, you can optionally suppress segment traversals using
- NO_SEGMENT_TRAVERSAL, which assures bounded execution even when
- system allocators return non-contiguous spaces, at the typical
- expense of carrying around more memory and increased fragmentation.
-
- The implementation is not very modular and seriously overuses
- macros. Perhaps someday all C compilers will do as good a job
- inlining modular code as can now be done by brute-force expansion,
- but now, enough of them seem not to.
-
- Some compilers issue a lot of warnings about code that is
- dead/unreachable only on some platforms, and also about intentional
- uses of negation on unsigned types. All known cases of each can be
- ignored.
-
- For a longer but out of date high-level description, see
- http://gee.cs.oswego.edu/dl/html/malloc.html
-
-* MSPACES
- If MSPACES is defined, then in addition to malloc, free, etc.,
- this file also defines mspace_malloc, mspace_free, etc. These
- are versions of malloc routines that take an "mspace" argument
- obtained using create_mspace, to control all internal bookkeeping.
- If ONLY_MSPACES is defined, only these versions are compiled.
- So if you would like to use this allocator for only some allocations,
- and your system malloc for others, you can compile with
- ONLY_MSPACES and then do something like...
- static mspace mymspace = create_mspace(0,0); // for example
- #define mymalloc(bytes) mspace_malloc(mymspace, bytes)
-
- (Note: If you only need one instance of an mspace, you can instead
- use "USE_DL_PREFIX" to relabel the global malloc.)
-
- You can similarly create thread-local allocators by storing
- mspaces as thread-locals. For example:
- static __thread mspace tlms = 0;
- void* tlmalloc(size_t bytes) {
- if (tlms == 0) tlms = create_mspace(0, 0);
- return mspace_malloc(tlms, bytes);
- }
- void tlfree(void* mem) { mspace_free(tlms, mem); }
-
- Unless FOOTERS is defined, each mspace is completely independent.
- You cannot allocate from one and free to another (although
- conformance is only weakly checked, so usage errors are not always
- caught). If FOOTERS is defined, then each chunk carries around a tag
- indicating its originating mspace, and frees are directed to their
- originating spaces.
-
- ------------------------- Compile-time options ---------------------------
-
-Be careful in setting #define values for numerical constants of type
-size_t. On some systems, literal values are not automatically extended
-to size_t precision unless they are explicitly casted. You can also
-use the symbolic values MAX_SIZE_T, SIZE_T_ONE, etc below.
-
-WIN32 default: defined if _WIN32 defined
- Defining WIN32 sets up defaults for MS environment and compilers.
- Otherwise defaults are for unix. Beware that there seem to be some
- cases where this malloc might not be a pure drop-in replacement for
- Win32 malloc: Random-looking failures from Win32 GDI API's (eg;
- SetDIBits()) may be due to bugs in some video driver implementations
- when pixel buffers are malloc()ed, and the region spans more than
- one VirtualAlloc()ed region. Because dlmalloc uses a small (64Kb)
- default granularity, pixel buffers may straddle virtual allocation
- regions more often than when using the Microsoft allocator. You can
- avoid this by using VirtualAlloc() and VirtualFree() for all pixel
- buffers rather than using malloc(). If this is not possible,
- recompile this malloc with a larger DEFAULT_GRANULARITY.
-
-MALLOC_ALIGNMENT default: (size_t)8
- Controls the minimum alignment for malloc'ed chunks. It must be a
- power of two and at least 8, even on machines for which smaller
- alignments would suffice. It may be defined as larger than this
- though. Note however that code and data structures are optimized for
- the case of 8-byte alignment.
-
-MSPACES default: 0 (false)
- If true, compile in support for independent allocation spaces.
- This is only supported if HAVE_MMAP is true.
-
-ONLY_MSPACES default: 0 (false)
- If true, only compile in mspace versions, not regular versions.
-
-USE_LOCKS default: 0 (false)
- Causes each call to each public routine to be surrounded with
- pthread or WIN32 mutex lock/unlock. (If set true, this can be
- overridden on a per-mspace basis for mspace versions.) If set to a
- non-zero value other than 1, locks are used, but their
- implementation is left out, so lock functions must be supplied manually,
- as described below.
-
-USE_SPIN_LOCKS default: 1 iff USE_LOCKS and on x86 using gcc or MSC
- If true, uses custom spin locks for locking. This is currently
- supported only for x86 platforms using gcc or recent MS compilers.
- Otherwise, posix locks or win32 critical sections are used.
-
-FOOTERS default: 0
- If true, provide extra checking and dispatching by placing
- information in the footers of allocated chunks. This adds
- space and time overhead.
-
-INSECURE default: 0
- If true, omit checks for usage errors and heap space overwrites.
-
-USE_DL_PREFIX default: NOT defined
- Causes compiler to prefix all public routines with the string 'dl'.
- This can be useful when you only want to use this malloc in one part
- of a program, using your regular system malloc elsewhere.
-
-ABORT default: defined as abort()
- Defines how to abort on failed checks. On most systems, a failed
- check cannot die with an "assert" or even print an informative
- message, because the underlying print routines in turn call malloc,
- which will fail again. Generally, the best policy is to simply call
- abort(). It's not very useful to do more than this because many
- errors due to overwriting will show up as address faults (null, odd
- addresses etc) rather than malloc-triggered checks, so will also
- abort. Also, most compilers know that abort() does not return, so
- can better optimize code conditionally calling it.
-
-PROCEED_ON_ERROR default: defined as 0 (false)
- Controls whether detected bad addresses cause them to bypassed
- rather than aborting. If set, detected bad arguments to free and
- realloc are ignored. And all bookkeeping information is zeroed out
- upon a detected overwrite of freed heap space, thus losing the
- ability to ever return it from malloc again, but enabling the
- application to proceed. If PROCEED_ON_ERROR is defined, the
- static variable malloc_corruption_error_count is compiled in
- and can be examined to see if errors have occurred. This option
- generates slower code than the default abort policy.
-
-DEBUG default: NOT defined
- The DEBUG setting is mainly intended for people trying to modify
- this code or diagnose problems when porting to new platforms.
- However, it may also be able to better isolate user errors than just
- using runtime checks. The assertions in the check routines spell
- out in more detail the assumptions and invariants underlying the
- algorithms. The checking is fairly extensive, and will slow down
- execution noticeably. Calling malloc_stats or mallinfo with DEBUG
- set will attempt to check every non-mmapped allocated and free chunk
- in the course of computing the summaries.
-
-ABORT_ON_ASSERT_FAILURE default: defined as 1 (true)
- Debugging assertion failures can be nearly impossible if your
- version of the assert macro causes malloc to be called, which will
- lead to a cascade of further failures, blowing the runtime stack.
- ABORT_ON_ASSERT_FAILURE cause assertions failures to call abort(),
- which will usually make debugging easier.
-
-MALLOC_FAILURE_ACTION default: sets errno to ENOMEM, or no-op on win32
- The action to take before "return 0" when malloc fails to be able to
- return memory because there is none available.
-
-HAVE_MORECORE default: 1 (true) unless win32 or ONLY_MSPACES
- True if this system supports sbrk or an emulation of it.
-
-MORECORE default: sbrk
- The name of the sbrk-style system routine to call to obtain more
- memory. See below for guidance on writing custom MORECORE
- functions. The type of the argument to sbrk/MORECORE varies across
- systems. It cannot be size_t, because it supports negative
- arguments, so it is normally the signed type of the same width as
- size_t (sometimes declared as "intptr_t"). It doesn't much matter
- though. Internally, we only call it with arguments less than half
- the max value of a size_t, which should work across all reasonable
- possibilities, although sometimes generating compiler warnings.
-
-MORECORE_CONTIGUOUS default: 1 (true) if HAVE_MORECORE
- If true, take advantage of fact that consecutive calls to MORECORE
- with positive arguments always return contiguous increasing
- addresses. This is true of unix sbrk. It does not hurt too much to
- set it true anyway, since malloc copes with non-contiguities.
- Setting it false when definitely non-contiguous saves time
- and possibly wasted space it would take to discover this though.
-
-MORECORE_CANNOT_TRIM default: NOT defined
- True if MORECORE cannot release space back to the system when given
- negative arguments. This is generally necessary only if you are
- using a hand-crafted MORECORE function that cannot handle negative
- arguments.
-
-NO_SEGMENT_TRAVERSAL default: 0
- If non-zero, suppresses traversals of memory segments
- returned by either MORECORE or CALL_MMAP. This disables
- merging of segments that are contiguous, and selectively
- releasing them to the OS if unused, but bounds execution times.
-
-HAVE_MMAP default: 1 (true)
- True if this system supports mmap or an emulation of it. If so, and
- HAVE_MORECORE is not true, MMAP is used for all system
- allocation. If set and HAVE_MORECORE is true as well, MMAP is
- primarily used to directly allocate very large blocks. It is also
- used as a backup strategy in cases where MORECORE fails to provide
- space from system. Note: A single call to MUNMAP is assumed to be
- able to unmap memory that may have be allocated using multiple calls
- to MMAP, so long as they are adjacent.
-
-HAVE_MREMAP default: 1 on linux, else 0
- If true realloc() uses mremap() to re-allocate large blocks and
- extend or shrink allocation spaces.
-
-MMAP_CLEARS default: 1 except on WINCE.
- True if mmap clears memory so calloc doesn't need to. This is true
- for standard unix mmap using /dev/zero and on WIN32 except for WINCE.
-
-USE_BUILTIN_FFS default: 0 (i.e., not used)
- Causes malloc to use the builtin ffs() function to compute indices.
- Some compilers may recognize and intrinsify ffs to be faster than the
- supplied C version. Also, the case of x86 using gcc is special-cased
- to an asm instruction, so is already as fast as it can be, and so
- this setting has no effect. Similarly for Win32 under recent MS compilers.
- (On most x86s, the asm version is only slightly faster than the C version.)
-
-malloc_getpagesize default: derive from system includes, or 4096.
- The system page size. To the extent possible, this malloc manages
- memory from the system in page-size units. This may be (and
- usually is) a function rather than a constant. This is ignored
- if WIN32, where page size is determined using getSystemInfo during
- initialization. This may be several megabytes if ENABLE_LARGE_PAGES
- is enabled.
-
-ENABLE_LARGE_PAGES default: NOT defined
- Causes the system page size to be the value of GetLargePageMinimum()
- if that function is available (Windows Server 2003/Vista or later).
- This allows the use of large page entries in the MMU which can
- significantly improve performance in large working set applications
- as TLB cache load is reduced by a factor of three. Note that enabling
- this option is equal to locking the process' memory in current
- implementations of Windows and requires the SE_LOCK_MEMORY_PRIVILEGE
- to be held by the process in order to succeed.
-
-USE_DEV_RANDOM default: 0 (i.e., not used)
- Causes malloc to use /dev/random to initialize secure magic seed for
- stamping footers. Otherwise, the current time is used.
-
-NO_MALLINFO default: 0
- If defined, don't compile "mallinfo". This can be a simple way
- of dealing with mismatches between system declarations and
- those in this file.
-
-MALLINFO_FIELD_TYPE default: size_t
- The type of the fields in the mallinfo struct. This was originally
- defined as "int" in SVID etc, but is more usefully defined as
- size_t. The value is used only if HAVE_USR_INCLUDE_MALLOC_H is not set
-
-REALLOC_ZERO_BYTES_FREES default: not defined
- This should be set if a call to realloc with zero bytes should
- be the same as a call to free. Some people think it should. Otherwise,
- since this malloc returns a unique pointer for malloc(0), so does
- realloc(p, 0).
-
-LACKS_UNISTD_H, LACKS_FCNTL_H, LACKS_SYS_PARAM_H, LACKS_SYS_MMAN_H
-LACKS_STRINGS_H, LACKS_STRING_H, LACKS_SYS_TYPES_H, LACKS_ERRNO_H
-LACKS_STDLIB_H default: NOT defined unless on WIN32
- Define these if your system does not have these header files.
- You might need to manually insert some of the declarations they provide.
-
-DEFAULT_GRANULARITY default: page size if MORECORE_CONTIGUOUS,
- system_info.dwAllocationGranularity in WIN32,
- GetLargePageMinimum() if ENABLE_LARGE_PAGES,
- otherwise 64K.
- Also settable using mallopt(M_GRANULARITY, x)
- The unit for allocating and deallocating memory from the system. On
- most systems with contiguous MORECORE, there is no reason to
- make this more than a page. However, systems with MMAP tend to
- either require or encourage larger granularities. You can increase
- this value to prevent system allocation functions to be called so
- often, especially if they are slow. The value must be at least one
- page and must be a power of two. Setting to 0 causes initialization
- to either page size or win32 region size. (Note: In previous
- versions of malloc, the equivalent of this option was called
- "TOP_PAD")
-
-DEFAULT_GRANULARITY_ALIGNED default: undefined (which means page size)
- Whether to enforce alignment when allocating and deallocating memory
- from the system i.e. the base address of all allocations will be
- aligned to DEFAULT_GRANULARITY if it is set. Note that enabling this carries
- some overhead as multiple calls must now be made when probing for a valid
- aligned value, however it does greatly ease the checking for whether
- a given memory pointer was allocated by this allocator rather than
- some other.
-
-DEFAULT_TRIM_THRESHOLD default: 2MB
- Also settable using mallopt(M_TRIM_THRESHOLD, x)
- The maximum amount of unused top-most memory to keep before
- releasing via malloc_trim in free(). Automatic trimming is mainly
- useful in long-lived programs using contiguous MORECORE. Because
- trimming via sbrk can be slow on some systems, and can sometimes be
- wasteful (in cases where programs immediately afterward allocate
- more large chunks) the value should be high enough so that your
- overall system performance would improve by releasing this much
- memory. As a rough guide, you might set to a value close to the
- average size of a process (program) running on your system.
- Releasing this much memory would allow such a process to run in
- memory. Generally, it is worth tuning trim thresholds when a
- program undergoes phases where several large chunks are allocated
- and released in ways that can reuse each other's storage, perhaps
- mixed with phases where there are no such chunks at all. The trim
- value must be greater than page size to have any useful effect. To
- disable trimming completely, you can set to MAX_SIZE_T. Note that the trick
- some people use of mallocing a huge space and then freeing it at
- program startup, in an attempt to reserve system memory, doesn't
- have the intended effect under automatic trimming, since that memory
- will immediately be returned to the system.
-
-DEFAULT_MMAP_THRESHOLD default: 256K
- Also settable using mallopt(M_MMAP_THRESHOLD, x)
- The request size threshold for using MMAP to directly service a
- request. Requests of at least this size that cannot be allocated
- using already-existing space will be serviced via mmap. (If enough
- normal freed space already exists it is used instead.) Using mmap
- segregates relatively large chunks of memory so that they can be
- individually obtained and released from the host system. A request
- serviced through mmap is never reused by any other request (at least
- not directly; the system may just so happen to remap successive
- requests to the same locations). Segregating space in this way has
- the benefits that: Mmapped space can always be individually released
- back to the system, which helps keep the system level memory demands
- of a long-lived program low. Also, mapped memory doesn't become
- `locked' between other chunks, as can happen with normally allocated
- chunks, which means that even trimming via malloc_trim would not
- release them. However, it has the disadvantage that the space
- cannot be reclaimed, consolidated, and then used to service later
- requests, as happens with normal chunks. The advantages of mmap
- nearly always outweigh disadvantages for "large" chunks, but the
- value of "large" may vary across systems. The default is an
- empirically derived value that works well in most systems. You can
- disable mmap by setting to MAX_SIZE_T.
-
-MAX_RELEASE_CHECK_RATE default: 4095 unless not HAVE_MMAP
- The number of consolidated frees between checks to release
- unused segments when freeing. When using non-contiguous segments,
- especially with multiple mspaces, checking only for topmost space
- doesn't always suffice to trigger trimming. To compensate for this,
- free() will, with a period of MAX_RELEASE_CHECK_RATE (or the
- current number of segments, if greater) try to release unused
- segments to the OS when freeing chunks that result in
- consolidation. The best value for this parameter is a compromise
- between slowing down frees with relatively costly checks that
- rarely trigger versus holding on to unused memory. To effectively
- disable, set to MAX_SIZE_T. This may lead to a very slight speed
- improvement at the expense of carrying around more memory.
-*/
-
-/* Version identifier to allow people to support multiple versions */
-#ifndef DLMALLOC_VERSION
-#define DLMALLOC_VERSION 20804
-#endif /* DLMALLOC_VERSION */
-
-#ifndef WIN32
-#ifdef _WIN32
-#define WIN32 1
-#endif /* _WIN32 */
-#ifdef _WIN32_WCE
-#define LACKS_FCNTL_H
-#define WIN32 1
-#endif /* _WIN32_WCE */
-#endif /* WIN32 */
-#ifdef WIN32
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <tchar.h>
-#define HAVE_MMAP 1
-#define HAVE_MORECORE 0
-#define LACKS_UNISTD_H
-#define LACKS_SYS_PARAM_H
-#define LACKS_SYS_MMAN_H
-#define LACKS_STRING_H
-#define LACKS_STRINGS_H
-#define LACKS_SYS_TYPES_H
-#define LACKS_ERRNO_H
-#ifndef MALLOC_FAILURE_ACTION
-#define MALLOC_FAILURE_ACTION
-#endif /* MALLOC_FAILURE_ACTION */
-#ifdef _WIN32_WCE /* WINCE reportedly does not clear */
-#define MMAP_CLEARS 0
-#else
-#define MMAP_CLEARS 1
-#endif /* _WIN32_WCE */
-#endif /* WIN32 */
-
-#if defined(DARWIN) || defined(_DARWIN)
-/* Mac OSX docs advise not to use sbrk; it seems better to use mmap */
-#ifndef HAVE_MORECORE
-#define HAVE_MORECORE 0
-#define HAVE_MMAP 1
-/* OSX allocators provide 16 byte alignment */
-#ifndef MALLOC_ALIGNMENT
-#define MALLOC_ALIGNMENT ((size_t)16U)
-#endif
-#endif /* HAVE_MORECORE */
-#endif /* DARWIN */
-
-#ifndef LACKS_SYS_TYPES_H
-#include <sys/types.h> /* For size_t */
-#endif /* LACKS_SYS_TYPES_H */
-
-#if (defined(__GNUC__) && ((defined(__i386__) || defined(__x86_64__)))) || (defined(_MSC_VER) && _MSC_VER>=1310)
-#define SPIN_LOCKS_AVAILABLE 1
-#else
-#define SPIN_LOCKS_AVAILABLE 0
-#endif
-
-/* The maximum possible size_t value has all bits set */
-#define MAX_SIZE_T (~(size_t)0)
-
-#ifndef ONLY_MSPACES
-#define ONLY_MSPACES 0 /* define to a value */
-#else
-#define ONLY_MSPACES 1
-#endif /* ONLY_MSPACES */
-#ifndef MSPACES
-#if ONLY_MSPACES
-#define MSPACES 1
-#else /* ONLY_MSPACES */
-#define MSPACES 0
-#endif /* ONLY_MSPACES */
-#endif /* MSPACES */
-#ifndef MALLOC_ALIGNMENT
-#define MALLOC_ALIGNMENT ((size_t)8U)
-#endif /* MALLOC_ALIGNMENT */
-#ifndef FOOTERS
-#define FOOTERS 0
-#endif /* FOOTERS */
-#ifndef ABORT
-#define ABORT abort()
-#endif /* ABORT */
-#ifndef ABORT_ON_ASSERT_FAILURE
-#define ABORT_ON_ASSERT_FAILURE 1
-#endif /* ABORT_ON_ASSERT_FAILURE */
-#ifndef PROCEED_ON_ERROR
-#define PROCEED_ON_ERROR 0
-#endif /* PROCEED_ON_ERROR */
-#ifndef USE_LOCKS
-#define USE_LOCKS 0
-#endif /* USE_LOCKS */
-#ifndef USE_SPIN_LOCKS
-#if USE_LOCKS && SPIN_LOCKS_AVAILABLE
-#define USE_SPIN_LOCKS 1
-#else
-#define USE_SPIN_LOCKS 0
-#endif /* USE_LOCKS && SPIN_LOCKS_AVAILABLE. */
-#endif /* USE_SPIN_LOCKS */
-#ifndef INSECURE
-#define INSECURE 0
-#endif /* INSECURE */
-#ifndef HAVE_MMAP
-#define HAVE_MMAP 1
-#endif /* HAVE_MMAP */
-#ifndef MMAP_CLEARS
-#define MMAP_CLEARS 1
-#endif /* MMAP_CLEARS */
-#ifndef HAVE_MREMAP
-#ifdef linux
-#define HAVE_MREMAP 1
-#else /* linux */
-#define HAVE_MREMAP 0
-#endif /* linux */
-#endif /* HAVE_MREMAP */
-#ifndef MALLOC_FAILURE_ACTION
-#define MALLOC_FAILURE_ACTION errno = ENOMEM;
-#endif /* MALLOC_FAILURE_ACTION */
-#ifndef HAVE_MORECORE
-#if ONLY_MSPACES
-#define HAVE_MORECORE 0
-#else /* ONLY_MSPACES */
-#define HAVE_MORECORE 1
-#endif /* ONLY_MSPACES */
-#endif /* HAVE_MORECORE */
-#if !HAVE_MORECORE
-#define MORECORE_CONTIGUOUS 0
-#else /* !HAVE_MORECORE */
-#define MORECORE_DEFAULT sbrk
-#ifndef MORECORE_CONTIGUOUS
-#define MORECORE_CONTIGUOUS 1
-#endif /* MORECORE_CONTIGUOUS */
-#endif /* HAVE_MORECORE */
-#ifndef DEFAULT_GRANULARITY
-#if (MORECORE_CONTIGUOUS || defined(WIN32))
-#define DEFAULT_GRANULARITY (0) /* 0 means to compute in init_mparams */
-#else /* MORECORE_CONTIGUOUS */
-#define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U)
-#endif /* MORECORE_CONTIGUOUS */
-#endif /* DEFAULT_GRANULARITY */
-#ifndef DEFAULT_TRIM_THRESHOLD
-#ifndef MORECORE_CANNOT_TRIM
-#define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U)
-#else /* MORECORE_CANNOT_TRIM */
-#define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T
-#endif /* MORECORE_CANNOT_TRIM */
-#endif /* DEFAULT_TRIM_THRESHOLD */
-#ifndef DEFAULT_MMAP_THRESHOLD
-#if HAVE_MMAP
-#define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U)
-#else /* HAVE_MMAP */
-#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T
-#endif /* HAVE_MMAP */
-#endif /* DEFAULT_MMAP_THRESHOLD */
-#ifndef MAX_RELEASE_CHECK_RATE
-#if HAVE_MMAP
-#define MAX_RELEASE_CHECK_RATE 4095
-#else
-#define MAX_RELEASE_CHECK_RATE MAX_SIZE_T
-#endif /* HAVE_MMAP */
-#endif /* MAX_RELEASE_CHECK_RATE */
-#ifndef USE_BUILTIN_FFS
-#define USE_BUILTIN_FFS 0
-#endif /* USE_BUILTIN_FFS */
-#ifndef USE_DEV_RANDOM
-#define USE_DEV_RANDOM 0
-#endif /* USE_DEV_RANDOM */
-#ifndef NO_MALLINFO
-#define NO_MALLINFO 0
-#endif /* NO_MALLINFO */
-#ifndef MALLINFO_FIELD_TYPE
-#define MALLINFO_FIELD_TYPE size_t
-#endif /* MALLINFO_FIELD_TYPE */
-#ifndef NO_SEGMENT_TRAVERSAL
-#define NO_SEGMENT_TRAVERSAL 0
-#endif /* NO_SEGMENT_TRAVERSAL */
-
-/*
- mallopt tuning options. SVID/XPG defines four standard parameter
- numbers for mallopt, normally defined in malloc.h. None of these
- are used in this malloc, so setting them has no effect. But this
- malloc does support the following options.
-*/
-
-#define M_TRIM_THRESHOLD (-1)
-#define M_GRANULARITY (-2)
-#define M_MMAP_THRESHOLD (-3)
-
-/* ------------------------ Mallinfo declarations ------------------------ */
-
-#if !NO_MALLINFO
-/*
- This version of malloc supports the standard SVID/XPG mallinfo
- routine that returns a struct containing usage properties and
- statistics. It should work on any system that has a
- /usr/include/malloc.h defining struct mallinfo. The main
- declaration needed is the mallinfo struct that is returned (by-copy)
- by mallinfo(). The malloinfo struct contains a bunch of fields that
- are not even meaningful in this version of malloc. These fields are
- are instead filled by mallinfo() with other numbers that might be of
- interest.
-
- HAVE_USR_INCLUDE_MALLOC_H should be set if you have a
- /usr/include/malloc.h file that includes a declaration of struct
- mallinfo. If so, it is included; else a compliant version is
- declared below. These must be precisely the same for mallinfo() to
- work. The original SVID version of this struct, defined on most
- systems with mallinfo, declares all fields as ints. But some others
- define as unsigned long. If your system defines the fields using a
- type of different width than listed here, you MUST #include your
- system version and #define HAVE_USR_INCLUDE_MALLOC_H.
-*/
-
-/* #define HAVE_USR_INCLUDE_MALLOC_H */
-
-#ifdef HAVE_USR_INCLUDE_MALLOC_H
-#include "/usr/include/malloc.h"
-#else /* HAVE_USR_INCLUDE_MALLOC_H */
-#ifndef STRUCT_MALLINFO_DECLARED
-#define STRUCT_MALLINFO_DECLARED 1
-struct mallinfo {
- MALLINFO_FIELD_TYPE arena; /* non-mmapped space allocated from system */
- MALLINFO_FIELD_TYPE ordblks; /* number of free chunks */
- MALLINFO_FIELD_TYPE smblks; /* always 0 */
- MALLINFO_FIELD_TYPE hblks; /* always 0 */
- MALLINFO_FIELD_TYPE hblkhd; /* space in mmapped regions */
- MALLINFO_FIELD_TYPE usmblks; /* maximum total allocated space */
- MALLINFO_FIELD_TYPE fsmblks; /* always 0 */
- MALLINFO_FIELD_TYPE uordblks; /* total allocated space */
- MALLINFO_FIELD_TYPE fordblks; /* total free space */
- MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */
-};
-#endif /* STRUCT_MALLINFO_DECLARED */
-#endif /* HAVE_USR_INCLUDE_MALLOC_H */
-#endif /* NO_MALLINFO */
-
-/*
- Try to persuade compilers to inline. The most critical functions for
- inlining are defined as macros, so these aren't used for them.
-*/
-
-#ifndef FORCEINLINE
- #if defined(__GNUC__)
-#define FORCEINLINE __inline __attribute__ ((always_inline))
- #elif defined(_MSC_VER)
- #define FORCEINLINE __forceinline
- #endif
-#endif
-#ifndef NOINLINE
- #if defined(__GNUC__)
- #define NOINLINE __attribute__ ((noinline))
- #elif defined(_MSC_VER)
- #define NOINLINE __declspec(noinline)
- #else
- #define NOINLINE
- #endif
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#ifndef FORCEINLINE
- #define FORCEINLINE inline
-#endif
-#endif /* __cplusplus */
-#ifndef FORCEINLINE
- #define FORCEINLINE
-#endif
-
-#if !ONLY_MSPACES
-
-/* ------------------- Declarations of public routines ------------------- */
-
-#ifndef USE_DL_PREFIX
-#define dlcalloc calloc
-#define dlfree free
-#define dlmalloc malloc
-#define dlmemalign memalign
-#define dlrealloc realloc
-#define dlvalloc valloc
-#define dlpvalloc pvalloc
-#define dlmallinfo mallinfo
-#define dlmallopt mallopt
-#define dlmalloc_trim malloc_trim
-#define dlmalloc_stats malloc_stats
-#define dlmalloc_usable_size malloc_usable_size
-#define dlmalloc_footprint malloc_footprint
-#define dlmalloc_max_footprint malloc_max_footprint
-#define dlindependent_calloc independent_calloc
-#define dlindependent_comalloc independent_comalloc
-#endif /* USE_DL_PREFIX */
-
-
-/*
- malloc(size_t n)
- Returns a pointer to a newly allocated chunk of at least n bytes, or
- null if no space is available, in which case errno is set to ENOMEM
- on ANSI C systems.
-
- If n is zero, malloc returns a minimum-sized chunk. (The minimum
- size is 16 bytes on most 32bit systems, and 32 bytes on 64bit
- systems.) Note that size_t is an unsigned type, so calls with
- arguments that would be negative if signed are interpreted as
- requests for huge amounts of space, which will often fail. The
- maximum supported value of n differs across systems, but is in all
- cases less than the maximum representable value of a size_t.
-*/
-void* dlmalloc(size_t);
-
-/*
- free(void* p)
- Releases the chunk of memory pointed to by p, that had been previously
- allocated using malloc or a related routine such as realloc.
- It has no effect if p is null. If p was not malloced or already
- freed, free(p) will by default cause the current program to abort.
-*/
-void dlfree(void*);
-
-/*
- calloc(size_t n_elements, size_t element_size);
- Returns a pointer to n_elements * element_size bytes, with all locations
- set to zero.
-*/
-void* dlcalloc(size_t, size_t);
-
-/*
- realloc(void* p, size_t n)
- Returns a pointer to a chunk of size n that contains the same data
- as does chunk p up to the minimum of (n, p's size) bytes, or null
- if no space is available.
-
- The returned pointer may or may not be the same as p. The algorithm
- prefers extending p in most cases when possible, otherwise it
- employs the equivalent of a malloc-copy-free sequence.
-
- If p is null, realloc is equivalent to malloc.
-
- If space is not available, realloc returns null, errno is set (if on
- ANSI) and p is NOT freed.
-
- if n is for fewer bytes than already held by p, the newly unused
- space is lopped off and freed if possible. realloc with a size
- argument of zero (re)allocates a minimum-sized chunk.
-
- The old unix realloc convention of allowing the last-free'd chunk
- to be used as an argument to realloc is not supported.
-*/
-
-void* dlrealloc(void*, size_t);
-
-/*
- memalign(size_t alignment, size_t n);
- Returns a pointer to a newly allocated chunk of n bytes, aligned
- in accord with the alignment argument.
-
- The alignment argument should be a power of two. If the argument is
- not a power of two, the nearest greater power is used.
- 8-byte alignment is guaranteed by normal malloc calls, so don't
- bother calling memalign with an argument of 8 or less.
-
- Overreliance on memalign is a sure way to fragment space.
-*/
-void* dlmemalign(size_t, size_t);
-
-/*
- valloc(size_t n);
- Equivalent to memalign(pagesize, n), where pagesize is the page
- size of the system. If the pagesize is unknown, 4096 is used.
-*/
-void* dlvalloc(size_t);
-
-/*
- mallopt(int parameter_number, int parameter_value)
- Sets tunable parameters The format is to provide a
- (parameter-number, parameter-value) pair. mallopt then sets the
- corresponding parameter to the argument value if it can (i.e., so
- long as the value is meaningful), and returns 1 if successful else
- 0. To workaround the fact that mallopt is specified to use int,
- not size_t parameters, the value -1 is specially treated as the
- maximum unsigned size_t value.
-
- SVID/XPG/ANSI defines four standard param numbers for mallopt,
- normally defined in malloc.h. None of these are use in this malloc,
- so setting them has no effect. But this malloc also supports other
- options in mallopt. See below for details. Briefly, supported
- parameters are as follows (listed defaults are for "typical"
- configurations).
-
- Symbol param # default allowed param values
- M_TRIM_THRESHOLD -1 2*1024*1024 any (-1 disables)
- M_GRANULARITY -2 page size any power of 2 >= page size
- M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support)
-*/
-int dlmallopt(int, int);
-
-/*
- malloc_footprint();
- Returns the number of bytes obtained from the system. The total
- number of bytes allocated by malloc, realloc etc., is less than this
- value. Unlike mallinfo, this function returns only a precomputed
- result, so can be called frequently to monitor memory consumption.
- Even if locks are otherwise defined, this function does not use them,
- so results might not be up to date.
-*/
-size_t dlmalloc_footprint(void);
-
-/*
- malloc_max_footprint();
- Returns the maximum number of bytes obtained from the system. This
- value will be greater than current footprint if deallocated space
- has been reclaimed by the system. The peak number of bytes allocated
- by malloc, realloc etc., is less than this value. Unlike mallinfo,
- this function returns only a precomputed result, so can be called
- frequently to monitor memory consumption. Even if locks are
- otherwise defined, this function does not use them, so results might
- not be up to date.
-*/
-size_t dlmalloc_max_footprint(void);
-
-#if !NO_MALLINFO
-/*
- mallinfo()
- Returns (by copy) a struct containing various summary statistics:
-
- arena: current total non-mmapped bytes allocated from system
- ordblks: the number of free chunks
- smblks: always zero.
- hblks: current number of mmapped regions
- hblkhd: total bytes held in mmapped regions
- usmblks: the maximum total allocated space. This will be greater
- than current total if trimming has occurred.
- fsmblks: always zero
- uordblks: current total allocated space (normal or mmapped)
- fordblks: total free space
- keepcost: the maximum number of bytes that could ideally be released
- back to system via malloc_trim. ("ideally" means that
- it ignores page restrictions etc.)
-
- Because these fields are ints, but internal bookkeeping may
- be kept as longs, the reported values may wrap around zero and
- thus be inaccurate.
-*/
-struct mallinfo dlmallinfo(void);
-#endif /* NO_MALLINFO */
-
-/*
- independent_calloc(size_t n_elements, size_t element_size, void* chunks[]);
-
- independent_calloc is similar to calloc, but instead of returning a
- single cleared space, it returns an array of pointers to n_elements
- independent elements that can hold contents of size elem_size, each
- of which starts out cleared, and can be independently freed,
- realloc'ed etc. The elements are guaranteed to be adjacently
- allocated (this is not guaranteed to occur with multiple callocs or
- mallocs), which may also improve cache locality in some
- applications.
-
- The "chunks" argument is optional (i.e., may be null, which is
- probably the most typical usage). If it is null, the returned array
- is itself dynamically allocated and should also be freed when it is
- no longer needed. Otherwise, the chunks array must be of at least
- n_elements in length. It is filled in with the pointers to the
- chunks.
-
- In either case, independent_calloc returns this pointer array, or
- null if the allocation failed. If n_elements is zero and "chunks"
- is null, it returns a chunk representing an array with zero elements
- (which should be freed if not wanted).
-
- Each element must be individually freed when it is no longer
- needed. If you'd like to instead be able to free all at once, you
- should instead use regular calloc and assign pointers into this
- space to represent elements. (In this case though, you cannot
- independently free elements.)
-
- independent_calloc simplifies and speeds up implementations of many
- kinds of pools. It may also be useful when constructing large data
- structures that initially have a fixed number of fixed-sized nodes,
- but the number is not known at compile time, and some of the nodes
- may later need to be freed. For example:
-
- struct Node { int item; struct Node* next; };
-
- struct Node* build_list() {
- struct Node** pool;
- int n = read_number_of_nodes_needed();
- if (n <= 0) return 0;
- pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);
- if (pool == 0) die();
- // organize into a linked list...
- struct Node* first = pool[0];
- for (i = 0; i < n-1; ++i)
- pool[i]->next = pool[i+1];
- free(pool); // Can now free the array (or not, if it is needed later)
- return first;
- }
-*/
-void** dlindependent_calloc(size_t, size_t, void**);
-
-/*
- independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);
-
- independent_comalloc allocates, all at once, a set of n_elements
- chunks with sizes indicated in the "sizes" array. It returns
- an array of pointers to these elements, each of which can be
- independently freed, realloc'ed etc. The elements are guaranteed to
- be adjacently allocated (this is not guaranteed to occur with
- multiple callocs or mallocs), which may also improve cache locality
- in some applications.
-
- The "chunks" argument is optional (i.e., may be null). If it is null
- the returned array is itself dynamically allocated and should also
- be freed when it is no longer needed. Otherwise, the chunks array
- must be of at least n_elements in length. It is filled in with the
- pointers to the chunks.
-
- In either case, independent_comalloc returns this pointer array, or
- null if the allocation failed. If n_elements is zero and chunks is
- null, it returns a chunk representing an array with zero elements
- (which should be freed if not wanted).
-
- Each element must be individually freed when it is no longer
- needed. If you'd like to instead be able to free all at once, you
- should instead use a single regular malloc, and assign pointers at
- particular offsets in the aggregate space. (In this case though, you
- cannot independently free elements.)
-
- independent_comallac differs from independent_calloc in that each
- element may have a different size, and also that it does not
- automatically clear elements.
-
- independent_comalloc can be used to speed up allocation in cases
- where several structs or objects must always be allocated at the
- same time. For example:
-
- struct Head { ... }
- struct Foot { ... }
-
- void send_message(char* msg) {
- int msglen = strlen(msg);
- size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };
- void* chunks[3];
- if (independent_comalloc(3, sizes, chunks) == 0)
- die();
- struct Head* head = (struct Head*)(chunks[0]);
- char* body = (char*)(chunks[1]);
- struct Foot* foot = (struct Foot*)(chunks[2]);
- // ...
- }
-
- In general though, independent_comalloc is worth using only for
- larger values of n_elements. For small values, you probably won't
- detect enough difference from series of malloc calls to bother.
-
- Overuse of independent_comalloc can increase overall memory usage,
- since it cannot reuse existing noncontiguous small chunks that
- might be available for some of the elements.
-*/
-void** dlindependent_comalloc(size_t, size_t*, void**);
-
-
-/*
- pvalloc(size_t n);
- Equivalent to valloc(minimum-page-that-holds(n)), that is,
- round up n to nearest pagesize.
- */
-void* dlpvalloc(size_t);
-
-/*
- malloc_trim(size_t pad);
-
- If possible, gives memory back to the system (via negative arguments
- to sbrk) if there is unused memory at the `high' end of the malloc
- pool or in unused MMAP segments. You can call this after freeing
- large blocks of memory to potentially reduce the system-level memory
- requirements of a program. However, it cannot guarantee to reduce
- memory. Under some allocation patterns, some large free blocks of
- memory will be locked between two used chunks, so they cannot be
- given back to the system.
-
- The `pad' argument to malloc_trim represents the amount of free
- trailing space to leave untrimmed. If this argument is zero, only
- the minimum amount of memory to maintain internal data structures
- will be left. Non-zero arguments can be supplied to maintain enough
- trailing space to service future expected allocations without having
- to re-obtain memory from the system.
-
- Malloc_trim returns 1 if it actually released any memory, else 0.
-*/
-int dlmalloc_trim(size_t);
-
-/*
- malloc_stats();
- Prints on stderr the amount of space obtained from the system (both
- via sbrk and mmap), the maximum amount (which may be more than
- current if malloc_trim and/or munmap got called), and the current
- number of bytes allocated via malloc (or realloc, etc) but not yet
- freed. Note that this is the number of bytes allocated, not the
- number requested. It will be larger than the number requested
- because of alignment and bookkeeping overhead. Because it includes
- alignment wastage as being in use, this figure may be greater than
- zero even when no user-level chunks are allocated.
-
- The reported current and maximum system memory can be inaccurate if
- a program makes other calls to system memory allocation functions
- (normally sbrk) outside of malloc.
-
- malloc_stats prints only the most commonly interesting statistics.
- More information can be obtained by calling mallinfo.
-*/
-void dlmalloc_stats(void);
-
-#endif /* ONLY_MSPACES */
-
-/*
- malloc_usable_size(void* p);
-
- Returns the number of bytes you can actually use in
- an allocated chunk, which may be more than you requested (although
- often not) due to alignment and minimum size constraints.
- You can use this many bytes without worrying about
- overwriting other allocated objects. This is not a particularly great
- programming practice. malloc_usable_size can be more useful in
- debugging and assertions, for example:
-
- p = malloc(n);
- assert(malloc_usable_size(p) >= 256);
-*/
-size_t dlmalloc_usable_size(void*);
-
-
-#if MSPACES
-
-/*
- mspace is an opaque type representing an independent
- region of space that supports mspace_malloc, etc.
-*/
-typedef void* mspace;
-
-/*
- create_mspace creates and returns a new independent space with the
- given initial capacity, or, if 0, the default granularity size. It
- returns null if there is no system memory available to create the
- space. If argument locked is non-zero, the space uses a separate
- lock to control access. The capacity of the space will grow
- dynamically as needed to service mspace_malloc requests. You can
- control the sizes of incremental increases of this space by
- compiling with a different DEFAULT_GRANULARITY or dynamically
- setting with mallopt(M_GRANULARITY, value).
-*/
-mspace create_mspace(size_t capacity, int locked);
-
-/*
- destroy_mspace destroys the given space, and attempts to return all
- of its memory back to the system, returning the total number of
- bytes freed. After destruction, the results of access to all memory
- used by the space become undefined.
-*/
-size_t destroy_mspace(mspace msp);
-
-/*
- create_mspace_with_base uses the memory supplied as the initial base
- of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this
- space is used for bookkeeping, so the capacity must be at least this
- large. (Otherwise 0 is returned.) When this initial space is
- exhausted, additional memory will be obtained from the system.
- Destroying this space will deallocate all additionally allocated
- space (if possible) but not the initial base.
-*/
-mspace create_mspace_with_base(void* base, size_t capacity, int locked);
-
-/*
- mspace_track_large_chunks controls whether requests for large chunks
- are allocated in their own untracked mmapped regions, separate from
- others in this mspace. By default large chunks are not tracked,
- which reduces fragmentation. However, such chunks are not
- necessarily released to the system upon destroy_mspace. Enabling
- tracking by setting to true may increase fragmentation, but avoids
- leakage when relying on destroy_mspace to release all memory
- allocated using this space. The function returns the previous
- setting.
-*/
-int mspace_track_large_chunks(mspace msp, int enable);
-
-
-/*
- mspace_malloc behaves as malloc, but operates within
- the given space.
-*/
-void* mspace_malloc(mspace msp, size_t bytes);
-
-/*
- mspace_free behaves as free, but operates within
- the given space.
-
- If compiled with FOOTERS==1, mspace_free is not actually needed.
- free may be called instead of mspace_free because freed chunks from
- any space are handled by their originating spaces.
-*/
-void mspace_free(mspace msp, void* mem);
-
-/*
- mspace_realloc behaves as realloc, but operates within
- the given space.
-
- If compiled with FOOTERS==1, mspace_realloc is not actually
- needed. realloc may be called instead of mspace_realloc because
- realloced chunks from any space are handled by their originating
- spaces.
-*/
-void* mspace_realloc(mspace msp, void* mem, size_t newsize);
-
-/*
- mspace_calloc behaves as calloc, but operates within
- the given space.
-*/
-void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size);
-
-/*
- mspace_memalign behaves as memalign, but operates within
- the given space.
-*/
-void* mspace_memalign(mspace msp, size_t alignment, size_t bytes);
-
-/*
- mspace_independent_calloc behaves as independent_calloc, but
- operates within the given space.
-*/
-void** mspace_independent_calloc(mspace msp, size_t n_elements,
- size_t elem_size, void* chunks[]);
-
-/*
- mspace_independent_comalloc behaves as independent_comalloc, but
- operates within the given space.
-*/
-void** mspace_independent_comalloc(mspace msp, size_t n_elements,
- size_t sizes[], void* chunks[]);
-
-/*
- mspace_footprint() returns the number of bytes obtained from the
- system for this space.
-*/
-size_t mspace_footprint(mspace msp);
-
-/*
- mspace_max_footprint() returns the peak number of bytes obtained from the
- system for this space.
-*/
-size_t mspace_max_footprint(mspace msp);
-
-
-#if !NO_MALLINFO
-/*
- mspace_mallinfo behaves as mallinfo, but reports properties of
- the given space.
-*/
-struct mallinfo mspace_mallinfo(mspace msp);
-#endif /* NO_MALLINFO */
-
-/*
- malloc_usable_size(void* p) behaves the same as malloc_usable_size;
-*/
- size_t mspace_usable_size(void* mem);
-
-/*
- mspace_malloc_stats behaves as malloc_stats, but reports
- properties of the given space.
-*/
-void mspace_malloc_stats(mspace msp);
-
-/*
- mspace_trim behaves as malloc_trim, but
- operates within the given space.
-*/
-int mspace_trim(mspace msp, size_t pad);
-
-/*
- An alias for mallopt.
-*/
-int mspace_mallopt(int, int);
-
-#endif /* MSPACES */
-
-#ifdef __cplusplus
-} /* end of extern "C" */
-#endif /* __cplusplus */
-
-/*
- ========================================================================
- To make a fully customizable malloc.h header file, cut everything
- above this line, put into file malloc.h, edit to suit, and #include it
- on the next line, as well as in programs that use this malloc.
- ========================================================================
-*/
-
-/* #include "malloc.h" */
-
-/*------------------------------ internal #includes ---------------------- */
-
-#ifdef WIN32
-#pragma warning( disable : 4146 ) /* no "unsigned" warnings */
-#endif /* WIN32 */
-
-#include <stdio.h> /* for printing in malloc_stats */
-
-#ifndef LACKS_ERRNO_H
-#include <errno.h> /* for MALLOC_FAILURE_ACTION */
-#endif /* LACKS_ERRNO_H */
-#if FOOTERS || DEBUG
-#include <time.h> /* for magic initialization */
-#endif /* FOOTERS */
-#ifndef LACKS_STDLIB_H
-#include <stdlib.h> /* for abort() */
-#endif /* LACKS_STDLIB_H */
-#ifdef DEBUG
-#if ABORT_ON_ASSERT_FAILURE
-#undef assert
-#define assert(x) if(!(x)) ABORT
-#else /* ABORT_ON_ASSERT_FAILURE */
-#include <assert.h>
-#endif /* ABORT_ON_ASSERT_FAILURE */
-#else /* DEBUG */
-#ifndef assert
-#define assert(x)
-#endif
-#define DEBUG 0
-#endif /* DEBUG */
-#ifndef LACKS_STRING_H
-#include <string.h> /* for memset etc */
-#endif /* LACKS_STRING_H */
-#if USE_BUILTIN_FFS
-#ifndef LACKS_STRINGS_H
-#include <strings.h> /* for ffs */
-#endif /* LACKS_STRINGS_H */
-#endif /* USE_BUILTIN_FFS */
-#if HAVE_MMAP
-#ifndef LACKS_SYS_MMAN_H
-/* On some versions of linux, mremap decl in mman.h needs __USE_GNU set */
-#if (defined(linux) && !defined(__USE_GNU))
-#define __USE_GNU 1
-#include <sys/mman.h> /* for mmap */
-#undef __USE_GNU
-#else
-#include <sys/mman.h> /* for mmap */
-#endif /* linux */
-#endif /* LACKS_SYS_MMAN_H */
-#ifndef LACKS_FCNTL_H
-#include <fcntl.h>
-#endif /* LACKS_FCNTL_H */
-#endif /* HAVE_MMAP */
-#ifndef LACKS_UNISTD_H
-#include <unistd.h> /* for sbrk, sysconf */
-#else /* LACKS_UNISTD_H */
-#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
-extern void* sbrk(ptrdiff_t);
-#endif /* FreeBSD etc */
-#endif /* LACKS_UNISTD_H */
-
-/* Declarations for locking */
-#if USE_LOCKS
-#ifndef WIN32
-#include <pthread.h>
-#if defined (__SVR4) && defined (__sun) /* solaris */
-#include <thread.h>
-#endif /* solaris */
-#else
-#ifndef _M_AMD64
-/* These are already defined on AMD64 builds */
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-LONG __cdecl _InterlockedCompareExchange(LONG volatile *Dest, LONG Exchange, LONG Comp);
-LONG __cdecl _InterlockedExchange(LONG volatile *Target, LONG Value);
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-#endif /* _M_AMD64 */
-#pragma intrinsic (_InterlockedCompareExchange)
-#pragma intrinsic (_InterlockedExchange)
-#define interlockedcompareexchange _InterlockedCompareExchange
-#define interlockedexchange _InterlockedExchange
-#endif /* Win32 */
-#endif /* USE_LOCKS */
-
-/* Declarations for bit scanning on win32 */
-#if defined(_MSC_VER) && _MSC_VER>=1300
-#ifndef BitScanForward /* Try to avoid pulling in WinNT.h */
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-unsigned char _BitScanForward(unsigned long *index, unsigned long mask);
-unsigned char _BitScanReverse(unsigned long *index, unsigned long mask);
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#define BitScanForward _BitScanForward
-#define BitScanReverse _BitScanReverse
-#pragma intrinsic(_BitScanForward)
-#pragma intrinsic(_BitScanReverse)
-#endif /* BitScanForward */
-#endif /* defined(_MSC_VER) && _MSC_VER>=1300 */
-
-#ifndef WIN32
-#ifndef malloc_getpagesize
-# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */
-# ifndef _SC_PAGE_SIZE
-# define _SC_PAGE_SIZE _SC_PAGESIZE
-# endif
-# endif
-# ifdef _SC_PAGE_SIZE
-# define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
-# else
-# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
- extern size_t getpagesize();
-# define malloc_getpagesize getpagesize()
-# else
-# ifdef WIN32 /* use supplied emulation of getpagesize */
-# define malloc_getpagesize getpagesize()
-# else
-# ifndef LACKS_SYS_PARAM_H
-# include <sys/param.h>
-# endif
-# ifdef EXEC_PAGESIZE
-# define malloc_getpagesize EXEC_PAGESIZE
-# else
-# ifdef NBPG
-# ifndef CLSIZE
-# define malloc_getpagesize NBPG
-# else
-# define malloc_getpagesize (NBPG * CLSIZE)
-# endif
-# else
-# ifdef NBPC
-# define malloc_getpagesize NBPC
-# else
-# ifdef PAGESIZE
-# define malloc_getpagesize PAGESIZE
-# else /* just guess */
-# define malloc_getpagesize ((size_t)4096U)
-# endif
-# endif
-# endif
-# endif
-# endif
-# endif
-# endif
-#endif
-#endif
-
-
-
-/* ------------------- size_t and alignment properties -------------------- */
-
-/* The byte and bit size of a size_t */
-#define SIZE_T_SIZE (sizeof(size_t))
-#define SIZE_T_BITSIZE (sizeof(size_t) << 3)
-
-/* Some constants coerced to size_t */
-/* Annoying but necessary to avoid errors on some platforms */
-#define SIZE_T_ZERO ((size_t)0)
-#define SIZE_T_ONE ((size_t)1)
-#define SIZE_T_TWO ((size_t)2)
-#define SIZE_T_FOUR ((size_t)4)
-#define TWO_SIZE_T_SIZES (SIZE_T_SIZE<<1)
-#define FOUR_SIZE_T_SIZES (SIZE_T_SIZE<<2)
-#define SIX_SIZE_T_SIZES (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES)
-#define HALF_MAX_SIZE_T (MAX_SIZE_T / 2U)
-
-/* The bit mask value corresponding to MALLOC_ALIGNMENT */
-#define CHUNK_ALIGN_MASK (MALLOC_ALIGNMENT - SIZE_T_ONE)
-
-/* True if address a has acceptable alignment */
-#define is_aligned(A) (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0)
-
-/* the number of bytes to offset an address to align it */
-#define align_offset(A)\
- ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\
- ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK))
-
-/*
- malloc_params holds global properties, including those that can be
- dynamically set using mallopt. There is a single instance, mparams,
- initialized in init_mparams. Note that the non-zeroness of "magic"
- also serves as an initialization flag.
-*/
-typedef unsigned int flag_t;
-struct malloc_params {
- volatile size_t magic;
- size_t page_size;
- size_t granularity;
- size_t mmap_threshold;
- size_t trim_threshold;
- flag_t default_mflags;
-};
-
-static struct malloc_params mparams;
-
-/* Ensure mparams initialized */
-#define ensure_initialization() (void)(mparams.magic != 0 || init_mparams())
-
-/* -------------------------- MMAP preliminaries ------------------------- */
-
-/*
- If HAVE_MORECORE or HAVE_MMAP are false, we just define calls and
- checks to fail so compiler optimizer can delete code rather than
- using so many "#if"s.
-*/
-
-
-/* MORECORE and MMAP must return MFAIL on failure */
-#define MFAIL ((void*)(MAX_SIZE_T))
-#define CMFAIL ((char*)(MFAIL)) /* defined for convenience */
-
-#if HAVE_MMAP
-
-#ifndef WIN32
-#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
-#define MAP_ANONYMOUS MAP_ANON
-#endif /* MAP_ANON */
-#ifdef DEFAULT_GRANULARITY_ALIGNED
-#define MMAP_IMPL mmap_aligned
-static void* lastAlignedmmap; /* Used as a hint */
-static void* mmap_aligned(void *start, size_t length, int prot, int flags, int fd, off_t offset) {
- void* baseaddress = 0;
- void* ptr = 0;
- if(!start) {
- baseaddress = lastAlignedmmap;
- for(;;) {
- if(baseaddress) flags|=MAP_FIXED;
- ptr = mmap(baseaddress, length, prot, flags, fd, offset);
- if(!ptr)
- baseaddress = (void*)((size_t)baseaddress + mparams.granularity);
- else if((size_t)ptr & (mparams.granularity - SIZE_T_ONE)) {
- munmap(ptr, length);
- baseaddress = (void*)(((size_t)ptr + mparams.granularity) & ~(mparams.granularity - SIZE_T_ONE));
- }
- else break;
- }
- }
- else ptr = mmap(start, length, prot, flags, fd, offset);
- if(ptr) lastAlignedmmap = (void*)((size_t) ptr + mparams.granularity);
- return ptr;
-}
-#else
-#define MMAP_IMPL mmap
-#endif /* DEFAULT_GRANULARITY_ALIGNED */
-#define MUNMAP_DEFAULT(a, s) munmap((a), (s))
-#define MMAP_PROT (PROT_READ|PROT_WRITE)
-#ifdef MAP_ANONYMOUS
-#define MMAP_FLAGS (MAP_PRIVATE|MAP_ANONYMOUS)
-#define MMAP_DEFAULT(s) MMAP_IMPL(0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0)
-#else /* MAP_ANONYMOUS */
-/*
- Nearly all versions of mmap support MAP_ANONYMOUS, so the following
- is unlikely to be needed, but is supplied just in case.
-*/
-#define MMAP_FLAGS (MAP_PRIVATE)
-static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */
-#define MMAP_DEFAULT(s) ((dev_zero_fd < 0) ? \
- (dev_zero_fd = open("/dev/zero", O_RDWR), \
- MMAP_IMPL(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \
- MMAP_IMPL(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0))
-#endif /* MAP_ANONYMOUS */
-
-#define DIRECT_MMAP_DEFAULT(s) MMAP_DEFAULT(s)
-
-#else /* WIN32 */
-
-/* Win32 MMAP via VirtualAlloc */
-#ifdef DEFAULT_GRANULARITY_ALIGNED
-static void* lastWin32mmap; /* Used as a hint */
-#endif /* DEFAULT_GRANULARITY_ALIGNED */
-#ifdef ENABLE_LARGE_PAGES
-static int largepagesavailable = 1;
-#endif /* ENABLE_LARGE_PAGES */
-static FORCEINLINE void* win32mmap(size_t size) {
- void* baseaddress = 0;
- void* ptr = 0;
-#ifdef ENABLE_LARGE_PAGES
- /* Note that large pages are *always* allocated on a large page boundary.
- If however granularity is small then don't waste a kernel call if size
- isn't around the size of a large page */
- if(largepagesavailable && size >= 1*1024*1024) {
- ptr = VirtualAlloc(baseaddress, size, MEM_RESERVE|MEM_COMMIT|MEM_LARGE_PAGES, PAGE_READWRITE);
- if(!ptr && ERROR_PRIVILEGE_NOT_HELD==GetLastError()) largepagesavailable=0;
- }
-#endif
- if(!ptr) {
-#ifdef DEFAULT_GRANULARITY_ALIGNED
- /* We try to avoid overhead by speculatively reserving at aligned
- addresses until we succeed */
- baseaddress = lastWin32mmap;
- for(;;) {
- void* reserveaddr = VirtualAlloc(baseaddress, size, MEM_RESERVE, PAGE_READWRITE);
- if(!reserveaddr)
- baseaddress = (void*)((size_t)baseaddress + mparams.granularity);
- else if((size_t)reserveaddr & (mparams.granularity - SIZE_T_ONE)) {
- VirtualFree(reserveaddr, 0, MEM_RELEASE);
- baseaddress = (void*)(((size_t)reserveaddr + mparams.granularity) & ~(mparams.granularity - SIZE_T_ONE));
- }
- else break;
- }
-#endif
- if(!ptr) ptr = VirtualAlloc(baseaddress, size, baseaddress ? MEM_COMMIT : MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
-#if DEBUG
- if(lastWin32mmap && ptr!=lastWin32mmap) printf("Non-contiguous VirtualAlloc between %p and %p\n", ptr, lastWin32mmap);
-#endif
-#ifdef DEFAULT_GRANULARITY_ALIGNED
- if(ptr) lastWin32mmap = (void*)((size_t) ptr + mparams.granularity);
-#endif
- }
-#if DEBUG
-#ifdef ENABLE_LARGE_PAGES
- printf("VirtualAlloc returns %p size %u. LargePagesAvailable=%d\n", ptr, size, largepagesavailable);
-#else
- printf("VirtualAlloc returns %p size %u\n", ptr, size);
-#endif
-#endif
- return (ptr != 0)? ptr: MFAIL;
-}
-
-/* For direct MMAP, use MEM_TOP_DOWN to minimize interference */
-static FORCEINLINE void* win32direct_mmap(size_t size) {
- void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN,
- PAGE_READWRITE);
- return (ptr != 0)? ptr: MFAIL;
-}
-
-/* This function supports releasing coalesed segments */
-static FORCEINLINE int win32munmap(void* ptr, size_t size) {
- MEMORY_BASIC_INFORMATION minfo;
- char* cptr = (char*)ptr;
- while (size) {
- if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0)
- return -1;
- if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr ||
- minfo.State != MEM_COMMIT || minfo.RegionSize > size)
- return -1;
- if (VirtualFree(cptr, 0, MEM_RELEASE) == 0)
- return -1;
- cptr += minfo.RegionSize;
- size -= minfo.RegionSize;
- }
- return 0;
-}
-
-#define MMAP_DEFAULT(s) win32mmap(s)
-#define MUNMAP_DEFAULT(a, s) win32munmap((a), (s))
-#define DIRECT_MMAP_DEFAULT(s) win32direct_mmap(s)
-#endif /* WIN32 */
-#endif /* HAVE_MMAP */
-
-#if HAVE_MREMAP
-#ifndef WIN32
-#define MREMAP_DEFAULT(addr, osz, nsz, mv) mremap((addr), (osz), (nsz), (mv))
-#endif /* WIN32 */
-#endif /* HAVE_MREMAP */
-
-
-/**
- * Define CALL_MORECORE
- */
-#if HAVE_MORECORE
- #ifdef MORECORE
- #define CALL_MORECORE(S) MORECORE(S)
- #else /* MORECORE */
- #define CALL_MORECORE(S) MORECORE_DEFAULT(S)
- #endif /* MORECORE */
-#else /* HAVE_MORECORE */
- #define CALL_MORECORE(S) MFAIL
-#endif /* HAVE_MORECORE */
-
-/**
- * Define CALL_MMAP/CALL_MUNMAP/CALL_DIRECT_MMAP
- */
-#if HAVE_MMAP
- #define USE_MMAP_BIT (SIZE_T_ONE)
-
- #ifdef MMAP
- #define CALL_MMAP(s) MMAP(s)
- #else /* MMAP */
- #define CALL_MMAP(s) MMAP_DEFAULT(s)
- #endif /* MMAP */
- #ifdef MUNMAP
- #define CALL_MUNMAP(a, s) MUNMAP((a), (s))
- #else /* MUNMAP */
- #define CALL_MUNMAP(a, s) MUNMAP_DEFAULT((a), (s))
- #endif /* MUNMAP */
- #ifdef DIRECT_MMAP
- #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s)
- #else /* DIRECT_MMAP */
- #define CALL_DIRECT_MMAP(s) DIRECT_MMAP_DEFAULT(s)
- #endif /* DIRECT_MMAP */
-#else /* HAVE_MMAP */
- #define USE_MMAP_BIT (SIZE_T_ZERO)
-
- #define MMAP(s) MFAIL
- #define MUNMAP(a, s) (-1)
- #define DIRECT_MMAP(s) MFAIL
- #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s)
- #define CALL_MMAP(s) MMAP(s)
- #define CALL_MUNMAP(a, s) MUNMAP((a), (s))
-#endif /* HAVE_MMAP */
-
-/**
- * Define CALL_MREMAP
- */
-#if HAVE_MMAP && HAVE_MREMAP
- #ifdef MREMAP
- #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP((addr), (osz), (nsz), (mv))
- #else /* MREMAP */
- #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP_DEFAULT((addr), (osz), (nsz), (mv))
- #endif /* MREMAP */
-#else /* HAVE_MMAP && HAVE_MREMAP */
- #define CALL_MREMAP(addr, osz, nsz, mv) MFAIL
-#endif /* HAVE_MMAP && HAVE_MREMAP */
-
-/* mstate bit set if continguous morecore disabled or failed */
-#define USE_NONCONTIGUOUS_BIT (4U)
-
-/* segment bit set in create_mspace_with_base */
-#define EXTERN_BIT (8U)
-
-
-/* --------------------------- Lock preliminaries ------------------------ */
-
-/*
- When locks are defined, there is one global lock, plus
- one per-mspace lock.
-
- The global lock_ensures that mparams.magic and other unique
- mparams values are initialized only once. It also protects
- sequences of calls to MORECORE. In many cases sys_alloc requires
- two calls, that should not be interleaved with calls by other
- threads. This does not protect against direct calls to MORECORE
- by other threads not using this lock, so there is still code to
- cope the best we can on interference.
-
- Per-mspace locks surround calls to malloc, free, etc. To enable use
- in layered extensions, per-mspace locks are reentrant.
-
- Because lock-protected regions generally have bounded times, it is
- OK to use the supplied simple spinlocks in the custom versions for
- x86. Spinlocks are likely to improve performance for lightly
- contended applications, but worsen performance under heavy
- contention.
-
- If USE_LOCKS is > 1, the definitions of lock routines here are
- bypassed, in which case you will need to define the type MLOCK_T,
- and at least INITIAL_LOCK, ACQUIRE_LOCK, RELEASE_LOCK and possibly
- TRY_LOCK (which is not used in this malloc, but commonly needed in
- extensions.) You must also declare a
- static MLOCK_T malloc_global_mutex = { initialization values };.
-
-*/
-
-#if USE_LOCKS == 1
-
-#if USE_SPIN_LOCKS && SPIN_LOCKS_AVAILABLE
-#ifndef WIN32
-
-/* Custom pthread-style spin locks on x86 and x64 for gcc */
-struct pthread_mlock_t {
- volatile unsigned int l;
- char cachelinepadding[64];
- unsigned int c;
- pthread_t threadid;
-};
-#define MLOCK_T struct pthread_mlock_t
-#define CURRENT_THREAD pthread_self()
-#define INITIAL_LOCK(sl) ((sl)->threadid = 0, (sl)->l = (sl)->c = 0, 0)
-#define ACQUIRE_LOCK(sl) pthread_acquire_lock(sl)
-#define RELEASE_LOCK(sl) pthread_release_lock(sl)
-#define TRY_LOCK(sl) pthread_try_lock(sl)
-#define SPINS_PER_YIELD 63
-
-static MLOCK_T malloc_global_mutex = { 0, "", 0, 0};
-
-static FORCEINLINE int pthread_acquire_lock (MLOCK_T *sl) {
- int spins = 0;
- volatile unsigned int* lp = &sl->l;
- for (;;) {
- if (*lp != 0) {
- if (sl->threadid == CURRENT_THREAD) {
- ++sl->c;
- return 0;
- }
- }
- else {
- /* place args to cmpxchgl in locals to evade oddities in some gccs */
- int cmp = 0;
- int val = 1;
- int ret;
- __asm__ __volatile__ ("lock; cmpxchgl %1, %2"
- : "=a" (ret)
- : "r" (val), "m" (*(lp)), "0"(cmp)
- : "memory", "cc");
- if (!ret) {
- assert(!sl->threadid);
- sl->threadid = CURRENT_THREAD;
- sl->c = 1;
- return 0;
- }
- }
- if ((++spins & SPINS_PER_YIELD) == 0) {
-#if defined (__SVR4) && defined (__sun) /* solaris */
- thr_yield();
-#else
-#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
- sched_yield();
-#else /* no-op yield on unknown systems */
- ;
-#endif /* __linux__ || __FreeBSD__ || __APPLE__ */
-#endif /* solaris */
- }
- }
-}
-
-static FORCEINLINE void pthread_release_lock (MLOCK_T *sl) {
- volatile unsigned int* lp = &sl->l;
- assert(*lp != 0);
- assert(sl->threadid == CURRENT_THREAD);
- if (--sl->c == 0) {
- sl->threadid = 0;
- int prev = 0;
- int ret;
- __asm__ __volatile__ ("lock; xchgl %0, %1"
- : "=r" (ret)
- : "m" (*(lp)), "0"(prev)
- : "memory");
- }
-}
-
-static FORCEINLINE int pthread_try_lock (MLOCK_T *sl) {
- volatile unsigned int* lp = &sl->l;
- if (*lp != 0) {
- if (sl->threadid == CURRENT_THREAD) {
- ++sl->c;
- return 1;
- }
- }
- else {
- int cmp = 0;
- int val = 1;
- int ret;
- __asm__ __volatile__ ("lock; cmpxchgl %1, %2"
- : "=a" (ret)
- : "r" (val), "m" (*(lp)), "0"(cmp)
- : "memory", "cc");
- if (!ret) {
- assert(!sl->threadid);
- sl->threadid = CURRENT_THREAD;
- sl->c = 1;
- return 1;
- }
- }
- return 0;
-}
-
-
-#else /* WIN32 */
-/* Custom win32-style spin locks on x86 and x64 for MSC */
-struct win32_mlock_t {
- volatile long l;
- char cachelinepadding[64];
- unsigned int c;
- long threadid;
-};
-
-#define MLOCK_T struct win32_mlock_t
-#define CURRENT_THREAD ((long)GetCurrentThreadId())
-#define INITIAL_LOCK(sl) ((sl)->threadid = 0, (sl)->l = (sl)->c = 0, 0)
-#define ACQUIRE_LOCK(sl) win32_acquire_lock(sl)
-#define RELEASE_LOCK(sl) win32_release_lock(sl)
-#define TRY_LOCK(sl) win32_try_lock(sl)
-#define SPINS_PER_YIELD 63
-
-static MLOCK_T malloc_global_mutex = { 0, 0, 0};
-
-static FORCEINLINE int win32_acquire_lock (MLOCK_T *sl) {
- int spins = 0;
- for (;;) {
- if (sl->l != 0) {
- if (sl->threadid == CURRENT_THREAD) {
- ++sl->c;
- return 0;
- }
- }
- else {
- if (!interlockedexchange(&sl->l, 1)) {
- assert(!sl->threadid);
- sl->threadid = CURRENT_THREAD;
- sl->c = 1;
- return 0;
- }
- }
- if ((++spins & SPINS_PER_YIELD) == 0)
- SleepEx(0, FALSE);
- }
-}
-
-static FORCEINLINE void win32_release_lock (MLOCK_T *sl) {
- assert(sl->threadid == CURRENT_THREAD);
- assert(sl->l != 0);
- if (--sl->c == 0) {
- sl->threadid = 0;
- interlockedexchange (&sl->l, 0);
- }
-}
-
-static FORCEINLINE int win32_try_lock (MLOCK_T *sl) {
- if (sl->l != 0) {
- if (sl->threadid == CURRENT_THREAD) {
- ++sl->c;
- return 1;
- }
- }
- else {
- if (!interlockedexchange(&sl->l, 1)){
- assert(!sl->threadid);
- sl->threadid = CURRENT_THREAD;
- sl->c = 1;
- return 1;
- }
- }
- return 0;
-}
-
-#endif /* WIN32 */
-#else /* USE_SPIN_LOCKS */
-
-#ifndef WIN32
-/* pthreads-based locks */
-
-#define MLOCK_T pthread_mutex_t
-#define CURRENT_THREAD pthread_self()
-#define INITIAL_LOCK(sl) pthread_init_lock(sl)
-#define ACQUIRE_LOCK(sl) pthread_mutex_lock(sl)
-#define RELEASE_LOCK(sl) pthread_mutex_unlock(sl)
-#define TRY_LOCK(sl) (!pthread_mutex_trylock(sl))
-
-static MLOCK_T malloc_global_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-/* Cope with old-style linux recursive lock initialization by adding */
-/* skipped internal declaration from pthread.h */
-#ifdef linux
-#ifndef PTHREAD_MUTEX_RECURSIVE
-extern int pthread_mutexattr_setkind_np __P ((pthread_mutexattr_t *__attr,
- int __kind));
-#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
-#define pthread_mutexattr_settype(x,y) pthread_mutexattr_setkind_np(x,y)
-#endif
-#endif
-
-static int pthread_init_lock (MLOCK_T *sl) {
- pthread_mutexattr_t attr;
- if (pthread_mutexattr_init(&attr)) return 1;
- if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) return 1;
- if (pthread_mutex_init(sl, &attr)) return 1;
- if (pthread_mutexattr_destroy(&attr)) return 1;
- return 0;
-}
-
-#else /* WIN32 */
-/* Win32 critical sections */
-#define MLOCK_T CRITICAL_SECTION
-#define CURRENT_THREAD GetCurrentThreadId()
-#define INITIAL_LOCK(s) (!InitializeCriticalSectionAndSpinCount((s), 0x80000000|4000))
-#define ACQUIRE_LOCK(s) (EnterCriticalSection(sl), 0)
-#define RELEASE_LOCK(s) LeaveCriticalSection(sl)
-#define TRY_LOCK(s) TryEnterCriticalSection(sl)
-#define NEED_GLOBAL_LOCK_INIT
-
-static MLOCK_T malloc_global_mutex;
-static volatile long malloc_global_mutex_status;
-
-/* Use spin loop to initialize global lock */
-static void init_malloc_global_mutex() {
- for (;;) {
- long stat = malloc_global_mutex_status;
- if (stat > 0)
- return;
- /* transition to < 0 while initializing, then to > 0) */
- if (stat == 0 &&
- interlockedcompareexchange(&malloc_global_mutex_status, -1, 0) == 0) {
- InitializeCriticalSection(&malloc_global_mutex);
- interlockedexchange(&malloc_global_mutex_status,1);
- return;
- }
- SleepEx(0, FALSE);
- }
-}
-
-#endif /* WIN32 */
-#endif /* USE_SPIN_LOCKS */
-#endif /* USE_LOCKS == 1 */
-
-/* ----------------------- User-defined locks ------------------------ */
-
-#if USE_LOCKS > 1
-/* Define your own lock implementation here */
-/* #define INITIAL_LOCK(sl) ... */
-/* #define ACQUIRE_LOCK(sl) ... */
-/* #define RELEASE_LOCK(sl) ... */
-/* #define TRY_LOCK(sl) ... */
-/* static MLOCK_T malloc_global_mutex = ... */
-#endif /* USE_LOCKS > 1 */
-
-/* ----------------------- Lock-based state ------------------------ */
-
-#if USE_LOCKS
-#define USE_LOCK_BIT (2U)
-#else /* USE_LOCKS */
-#define USE_LOCK_BIT (0U)
-#define INITIAL_LOCK(l)
-#endif /* USE_LOCKS */
-
-#if USE_LOCKS
-#ifndef ACQUIRE_MALLOC_GLOBAL_LOCK
-#define ACQUIRE_MALLOC_GLOBAL_LOCK() ACQUIRE_LOCK(&malloc_global_mutex);
-#endif
-#ifndef RELEASE_MALLOC_GLOBAL_LOCK
-#define RELEASE_MALLOC_GLOBAL_LOCK() RELEASE_LOCK(&malloc_global_mutex);
-#endif
-#else /* USE_LOCKS */
-#define ACQUIRE_MALLOC_GLOBAL_LOCK()
-#define RELEASE_MALLOC_GLOBAL_LOCK()
-#endif /* USE_LOCKS */
-
-
-/* ----------------------- Chunk representations ------------------------ */
-
-/*
- (The following includes lightly edited explanations by Colin Plumb.)
-
- The malloc_chunk declaration below is misleading (but accurate and
- necessary). It declares a "view" into memory allowing access to
- necessary fields at known offsets from a given base.
-
- Chunks of memory are maintained using a `boundary tag' method as
- originally described by Knuth. (See the paper by Paul Wilson
- ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such
- techniques.) Sizes of free chunks are stored both in the front of
- each chunk and at the end. This makes consolidating fragmented
- chunks into bigger chunks fast. The head fields also hold bits
- representing whether chunks are free or in use.
-
- Here are some pictures to make it clearer. They are "exploded" to
- show that the state of a chunk can be thought of as extending from
- the high 31 bits of the head field of its header through the
- prev_foot and PINUSE_BIT bit of the following chunk header.
-
- A chunk that's in use looks like:
-
- chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Size of previous chunk (if P = 0) |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|
- | Size of this chunk 1| +-+
- mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | |
- +- -+
- | |
- +- -+
- | :
- +- size - sizeof(size_t) available payload bytes -+
- : |
- chunk-> +- -+
- | |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1|
- | Size of next chunk (may or may not be in use) | +-+
- mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
- And if it's free, it looks like this:
-
- chunk-> +- -+
- | User payload (must be in use, or we would have merged!) |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|
- | Size of this chunk 0| +-+
- mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Next pointer |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Prev pointer |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | :
- +- size - sizeof(struct chunk) unused bytes -+
- : |
- chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Size of this chunk |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0|
- | Size of next chunk (must be in use, or we would have merged)| +-+
- mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | :
- +- User payload -+
- : |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- |0|
- +-+
- Note that since we always merge adjacent free chunks, the chunks
- adjacent to a free chunk must be in use.
-
- Given a pointer to a chunk (which can be derived trivially from the
- payload pointer) we can, in O(1) time, find out whether the adjacent
- chunks are free, and if so, unlink them from the lists that they
- are on and merge them with the current chunk.
-
- Chunks always begin on even word boundaries, so the mem portion
- (which is returned to the user) is also on an even word boundary, and
- thus at least double-word aligned.
-
- The P (PINUSE_BIT) bit, stored in the unused low-order bit of the
- chunk size (which is always a multiple of two words), is an in-use
- bit for the *previous* chunk. If that bit is *clear*, then the
- word before the current chunk size contains the previous chunk
- size, and can be used to find the front of the previous chunk.
- The very first chunk allocated always has this bit set, preventing
- access to non-existent (or non-owned) memory. If pinuse is set for
- any given chunk, then you CANNOT determine the size of the
- previous chunk, and might even get a memory addressing fault when
- trying to do so.
-
- The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of
- the chunk size redundantly records whether the current chunk is
- inuse (unless the chunk is mmapped). This redundancy enables usage
- checks within free and realloc, and reduces indirection when freeing
- and consolidating chunks.
-
- Each freshly allocated chunk must have both cinuse and pinuse set.
- That is, each allocated chunk borders either a previously allocated
- and still in-use chunk, or the base of its memory arena. This is
- ensured by making all allocations from the the `lowest' part of any
- found chunk. Further, no free chunk physically borders another one,
- so each free chunk is known to be preceded and followed by either
- inuse chunks or the ends of memory.
-
- Note that the `foot' of the current chunk is actually represented
- as the prev_foot of the NEXT chunk. This makes it easier to
- deal with alignments etc but can be very confusing when trying
- to extend or adapt this code.
-
- The exceptions to all this are
-
- 1. The special chunk `top' is the top-most available chunk (i.e.,
- the one bordering the end of available memory). It is treated
- specially. Top is never included in any bin, is used only if
- no other chunk is available, and is released back to the
- system if it is very large (see M_TRIM_THRESHOLD). In effect,
- the top chunk is treated as larger (and thus less well
- fitting) than any other available chunk. The top chunk
- doesn't update its trailing size field since there is no next
- contiguous chunk that would have to index off it. However,
- space is still allocated for it (TOP_FOOT_SIZE) to enable
- separation or merging when space is extended.
-
- 3. Chunks allocated via mmap, have both cinuse and pinuse bits
- cleared in their head fields. Because they are allocated
- one-by-one, each must carry its own prev_foot field, which is
- also used to hold the offset this chunk has within its mmapped
- region, which is needed to preserve alignment. Each mmapped
- chunk is trailed by the first two fields of a fake next-chunk
- for sake of usage checks.
-
-*/
-
-struct malloc_chunk {
- size_t prev_foot; /* Size of previous chunk (if free). */
- size_t head; /* Size and inuse bits. */
- struct malloc_chunk* fd; /* double links -- used only if free. */
- struct malloc_chunk* bk;
-};
-
-typedef struct malloc_chunk mchunk;
-typedef struct malloc_chunk* mchunkptr;
-typedef struct malloc_chunk* sbinptr; /* The type of bins of chunks */
-typedef unsigned int bindex_t; /* Described below */
-typedef unsigned int binmap_t; /* Described below */
-
-/* ------------------- Chunks sizes and alignments ----------------------- */
-
-#define MCHUNK_SIZE (sizeof(mchunk))
-
-#if FOOTERS
-#define CHUNK_OVERHEAD (TWO_SIZE_T_SIZES)
-#else /* FOOTERS */
-#define CHUNK_OVERHEAD (SIZE_T_SIZE)
-#endif /* FOOTERS */
-
-/* MMapped chunks need a second word of overhead ... */
-#define MMAP_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES)
-/* ... and additional padding for fake next-chunk at foot */
-#define MMAP_FOOT_PAD (FOUR_SIZE_T_SIZES)
-
-/* The smallest size we can malloc is an aligned minimal chunk */
-#define MIN_CHUNK_SIZE\
- ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)
-
-/* conversion from malloc headers to user pointers, and back */
-#define chunk2mem(p) ((void*)((char*)(p) + TWO_SIZE_T_SIZES))
-#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES))
-/* chunk associated with aligned address A */
-#define align_as_chunk(A) (mchunkptr)((A) + align_offset(chunk2mem(A)))
-
-/* Bounds on request (not chunk) sizes. */
-#define MAX_REQUEST ((-MIN_CHUNK_SIZE) << 2)
-#define MIN_REQUEST (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE)
-
-/* pad request bytes into a usable size */
-#define pad_request(req) \
- (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)
-
-/* pad request, checking for minimum (but not maximum) */
-#define request2size(req) \
- (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req))
-
-
-/* ------------------ Operations on head and foot fields ----------------- */
-
-/*
- The head field of a chunk is or'ed with PINUSE_BIT when previous
- adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in
- use, unless mmapped, in which case both bits are cleared.
-
- FLAG4_BIT is not used by this malloc, but might be useful in extensions.
-*/
-
-#define PINUSE_BIT (SIZE_T_ONE)
-#define CINUSE_BIT (SIZE_T_TWO)
-#define FLAG4_BIT (SIZE_T_FOUR)
-#define INUSE_BITS (PINUSE_BIT|CINUSE_BIT)
-#define FLAG_BITS (PINUSE_BIT|CINUSE_BIT|FLAG4_BIT)
-
-/* Head value for fenceposts */
-#define FENCEPOST_HEAD (INUSE_BITS|SIZE_T_SIZE)
-
-/* extraction of fields from head words */
-#define cinuse(p) ((p)->head & CINUSE_BIT)
-#define pinuse(p) ((p)->head & PINUSE_BIT)
-#define is_inuse(p) (((p)->head & INUSE_BITS) != PINUSE_BIT)
-#define is_mmapped(p) (((p)->head & INUSE_BITS) == 0)
-
-#define chunksize(p) ((p)->head & ~(FLAG_BITS))
-
-#define clear_pinuse(p) ((p)->head &= ~PINUSE_BIT)
-
-/* Treat space at ptr +/- offset as a chunk */
-#define chunk_plus_offset(p, s) ((mchunkptr)(((char*)(p)) + (s)))
-#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s)))
-
-/* Ptr to next or previous physical malloc_chunk. */
-#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~FLAG_BITS)))
-#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) ))
-
-/* extract next chunk's pinuse bit */
-#define next_pinuse(p) ((next_chunk(p)->head) & PINUSE_BIT)
-
-/* Get/set size at footer */
-#define get_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot)
-#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s))
-
-/* Set size, pinuse bit, and foot */
-#define set_size_and_pinuse_of_free_chunk(p, s)\
- ((p)->head = (s|PINUSE_BIT), set_foot(p, s))
-
-/* Set size, pinuse bit, foot, and clear next pinuse */
-#define set_free_with_pinuse(p, s, n)\
- (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s))
-
-/* Get the internal overhead associated with chunk p */
-#define overhead_for(p)\
- (is_mmapped(p)? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD)
-
-/* Return true if malloced space is not necessarily cleared */
-#if MMAP_CLEARS
-#define calloc_must_clear(p) (!is_mmapped(p))
-#else /* MMAP_CLEARS */
-#define calloc_must_clear(p) (1)
-#endif /* MMAP_CLEARS */
-
-/* ---------------------- Overlaid data structures ----------------------- */
-
-/*
- When chunks are not in use, they are treated as nodes of either
- lists or trees.
-
- "Small" chunks are stored in circular doubly-linked lists, and look
- like this:
-
- chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Size of previous chunk |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- `head:' | Size of chunk, in bytes |P|
- mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Forward pointer to next chunk in list |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Back pointer to previous chunk in list |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Unused space (may be 0 bytes long) .
- . .
- . |
-nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- `foot:' | Size of chunk, in bytes |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
- Larger chunks are kept in a form of bitwise digital trees (aka
- tries) keyed on chunksizes. Because malloc_tree_chunks are only for
- free chunks greater than 256 bytes, their size doesn't impose any
- constraints on user chunk sizes. Each node looks like:
-
- chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Size of previous chunk |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- `head:' | Size of chunk, in bytes |P|
- mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Forward pointer to next chunk of same size |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Back pointer to previous chunk of same size |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Pointer to left child (child[0]) |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Pointer to right child (child[1]) |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Pointer to parent |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | bin index of this chunk |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Unused space .
- . |
-nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- `foot:' | Size of chunk, in bytes |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-
- Each tree holding treenodes is a tree of unique chunk sizes. Chunks
- of the same size are arranged in a circularly-linked list, with only
- the oldest chunk (the next to be used, in our FIFO ordering)
- actually in the tree. (Tree members are distinguished by a non-null
- parent pointer.) If a chunk with the same size an an existing node
- is inserted, it is linked off the existing node using pointers that
- work in the same way as fd/bk pointers of small chunks.
-
- Each tree contains a power of 2 sized range of chunk sizes (the
- smallest is 0x100 <= x < 0x180), which is is divided in half at each
- tree level, with the chunks in the smaller half of the range (0x100
- <= x < 0x140 for the top nose) in the left subtree and the larger
- half (0x140 <= x < 0x180) in the right subtree. This is, of course,
- done by inspecting individual bits.
-
- Using these rules, each node's left subtree contains all smaller
- sizes than its right subtree. However, the node at the root of each
- subtree has no particular ordering relationship to either. (The
- dividing line between the subtree sizes is based on trie relation.)
- If we remove the last chunk of a given size from the interior of the
- tree, we need to replace it with a leaf node. The tree ordering
- rules permit a node to be replaced by any leaf below it.
-
- The smallest chunk in a tree (a common operation in a best-fit
- allocator) can be found by walking a path to the leftmost leaf in
- the tree. Unlike a usual binary tree, where we follow left child
- pointers until we reach a null, here we follow the right child
- pointer any time the left one is null, until we reach a leaf with
- both child pointers null. The smallest chunk in the tree will be
- somewhere along that path.
-
- The worst case number of steps to add, find, or remove a node is
- bounded by the number of bits differentiating chunks within
- bins. Under current bin calculations, this ranges from 6 up to 21
- (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case
- is of course much better.
-*/
-
-struct malloc_tree_chunk {
- /* The first four fields must be compatible with malloc_chunk */
- size_t prev_foot;
- size_t head;
- struct malloc_tree_chunk* fd;
- struct malloc_tree_chunk* bk;
-
- struct malloc_tree_chunk* child[2];
- struct malloc_tree_chunk* parent;
- bindex_t index;
-};
-
-typedef struct malloc_tree_chunk tchunk;
-typedef struct malloc_tree_chunk* tchunkptr;
-typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */
-
-/* A little helper macro for trees */
-#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1])
-
-/* ----------------------------- Segments -------------------------------- */
-
-/*
- Each malloc space may include non-contiguous segments, held in a
- list headed by an embedded malloc_segment record representing the
- top-most space. Segments also include flags holding properties of
- the space. Large chunks that are directly allocated by mmap are not
- included in this list. They are instead independently created and
- destroyed without otherwise keeping track of them.
-
- Segment management mainly comes into play for spaces allocated by
- MMAP. Any call to MMAP might or might not return memory that is
- adjacent to an existing segment. MORECORE normally contiguously
- extends the current space, so this space is almost always adjacent,
- which is simpler and faster to deal with. (This is why MORECORE is
- used preferentially to MMAP when both are available -- see
- sys_alloc.) When allocating using MMAP, we don't use any of the
- hinting mechanisms (inconsistently) supported in various
- implementations of unix mmap, or distinguish reserving from
- committing memory. Instead, we just ask for space, and exploit
- contiguity when we get it. It is probably possible to do
- better than this on some systems, but no general scheme seems
- to be significantly better.
-
- Management entails a simpler variant of the consolidation scheme
- used for chunks to reduce fragmentation -- new adjacent memory is
- normally prepended or appended to an existing segment. However,
- there are limitations compared to chunk consolidation that mostly
- reflect the fact that segment processing is relatively infrequent
- (occurring only when getting memory from system) and that we
- don't expect to have huge numbers of segments:
-
- * Segments are not indexed, so traversal requires linear scans. (It
- would be possible to index these, but is not worth the extra
- overhead and complexity for most programs on most platforms.)
- * New segments are only appended to old ones when holding top-most
- memory; if they cannot be prepended to others, they are held in
- different segments.
-
- Except for the top-most segment of an mstate, each segment record
- is kept at the tail of its segment. Segments are added by pushing
- segment records onto the list headed by &mstate.seg for the
- containing mstate.
-
- Segment flags control allocation/merge/deallocation policies:
- * If EXTERN_BIT set, then we did not allocate this segment,
- and so should not try to deallocate or merge with others.
- (This currently holds only for the initial segment passed
- into create_mspace_with_base.)
- * If USE_MMAP_BIT set, the segment may be merged with
- other surrounding mmapped segments and trimmed/de-allocated
- using munmap.
- * If neither bit is set, then the segment was obtained using
- MORECORE so can be merged with surrounding MORECORE'd segments
- and deallocated/trimmed using MORECORE with negative arguments.
-*/
-
-struct malloc_segment {
- char* base; /* base address */
- size_t size; /* allocated size */
- struct malloc_segment* next; /* ptr to next segment */
- flag_t sflags; /* mmap and extern flag */
-};
-
-#define is_mmapped_segment(S) ((S)->sflags & USE_MMAP_BIT)
-#define is_extern_segment(S) ((S)->sflags & EXTERN_BIT)
-
-typedef struct malloc_segment msegment;
-typedef struct malloc_segment* msegmentptr;
-
-/* ---------------------------- malloc_state ----------------------------- */
-
-/*
- A malloc_state holds all of the bookkeeping for a space.
- The main fields are:
-
- Top
- The topmost chunk of the currently active segment. Its size is
- cached in topsize. The actual size of topmost space is
- topsize+TOP_FOOT_SIZE, which includes space reserved for adding
- fenceposts and segment records if necessary when getting more
- space from the system. The size at which to autotrim top is
- cached from mparams in trim_check, except that it is disabled if
- an autotrim fails.
-
- Designated victim (dv)
- This is the preferred chunk for servicing small requests that
- don't have exact fits. It is normally the chunk split off most
- recently to service another small request. Its size is cached in
- dvsize. The link fields of this chunk are not maintained since it
- is not kept in a bin.
-
- SmallBins
- An array of bin headers for free chunks. These bins hold chunks
- with sizes less than MIN_LARGE_SIZE bytes. Each bin contains
- chunks of all the same size, spaced 8 bytes apart. To simplify
- use in double-linked lists, each bin header acts as a malloc_chunk
- pointing to the real first node, if it exists (else pointing to
- itself). This avoids special-casing for headers. But to avoid
- waste, we allocate only the fd/bk pointers of bins, and then use
- repositioning tricks to treat these as the fields of a chunk.
-
- TreeBins
- Treebins are pointers to the roots of trees holding a range of
- sizes. There are 2 equally spaced treebins for each power of two
- from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything
- larger.
-
- Bin maps
- There is one bit map for small bins ("smallmap") and one for
- treebins ("treemap). Each bin sets its bit when non-empty, and
- clears the bit when empty. Bit operations are then used to avoid
- bin-by-bin searching -- nearly all "search" is done without ever
- looking at bins that won't be selected. The bit maps
- conservatively use 32 bits per map word, even if on 64bit system.
- For a good description of some of the bit-based techniques used
- here, see Henry S. Warren Jr's book "Hacker's Delight" (and
- supplement at http://hackersdelight.org/). Many of these are
- intended to reduce the branchiness of paths through malloc etc, as
- well as to reduce the number of memory locations read or written.
-
- Segments
- A list of segments headed by an embedded malloc_segment record
- representing the initial space.
-
- Address check support
- The least_addr field is the least address ever obtained from
- MORECORE or MMAP. Attempted frees and reallocs of any address less
- than this are trapped (unless INSECURE is defined).
-
- Magic tag
- A cross-check field that should always hold same value as mparams.magic.
-
- Flags
- Bits recording whether to use MMAP, locks, or contiguous MORECORE
-
- Statistics
- Each space keeps track of current and maximum system memory
- obtained via MORECORE or MMAP.
-
- Trim support
- Fields holding the amount of unused topmost memory that should trigger
- timming, and a counter to force periodic scanning to release unused
- non-topmost segments.
-
- Locking
- If USE_LOCKS is defined, the "mutex" lock is acquired and released
- around every public call using this mspace.
-
- Extension support
- A void* pointer and a size_t field that can be used to help implement
- extensions to this malloc.
-*/
-
-/* Bin types, widths and sizes */
-#define NSMALLBINS (32U)
-#define NTREEBINS (32U)
-#define SMALLBIN_SHIFT (3U)
-#define SMALLBIN_WIDTH (SIZE_T_ONE << SMALLBIN_SHIFT)
-#define TREEBIN_SHIFT (8U)
-#define MIN_LARGE_SIZE (SIZE_T_ONE << TREEBIN_SHIFT)
-#define MAX_SMALL_SIZE (MIN_LARGE_SIZE - SIZE_T_ONE)
-#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD)
-
-struct malloc_state {
- binmap_t smallmap;
- binmap_t treemap;
- size_t dvsize;
- size_t topsize;
- char* least_addr;
- mchunkptr dv;
- mchunkptr top;
- size_t trim_check;
- size_t release_checks;
- size_t magic;
- mchunkptr smallbins[(NSMALLBINS+1)*2];
- tbinptr treebins[NTREEBINS];
- size_t footprint;
- size_t max_footprint;
- flag_t mflags;
- msegment seg;
-#if USE_LOCKS
- MLOCK_T mutex; /* locate lock among fields that rarely change */
-#endif /* USE_LOCKS */
- void* extp; /* Unused but available for extensions */
- size_t exts;
-};
-
-typedef struct malloc_state* mstate;
-
-/* ------------- Global malloc_state and malloc_params ------------------- */
-
-#if !ONLY_MSPACES
-
-/* The global malloc_state used for all non-"mspace" calls */
-static struct malloc_state _gm_;
-#define gm (&_gm_)
-#define is_global(M) ((M) == &_gm_)
-
-#endif /* !ONLY_MSPACES */
-
-#define is_initialized(M) ((M)->top != 0)
-
-/* -------------------------- system alloc setup ------------------------- */
-
-/* Operations on mflags */
-
-#define use_lock(M) ((M)->mflags & USE_LOCK_BIT)
-#define enable_lock(M) ((M)->mflags |= USE_LOCK_BIT)
-#define disable_lock(M) ((M)->mflags &= ~USE_LOCK_BIT)
-
-#define use_mmap(M) ((M)->mflags & USE_MMAP_BIT)
-#define enable_mmap(M) ((M)->mflags |= USE_MMAP_BIT)
-#define disable_mmap(M) ((M)->mflags &= ~USE_MMAP_BIT)
-
-#define use_noncontiguous(M) ((M)->mflags & USE_NONCONTIGUOUS_BIT)
-#define disable_contiguous(M) ((M)->mflags |= USE_NONCONTIGUOUS_BIT)
-
-#define set_lock(M,L)\
- ((M)->mflags = (L)?\
- ((M)->mflags | USE_LOCK_BIT) :\
- ((M)->mflags & ~USE_LOCK_BIT))
-
-/* page-align a size */
-#define page_align(S)\
- (((S) + (mparams.page_size - SIZE_T_ONE)) & ~(mparams.page_size - SIZE_T_ONE))
-
-/* granularity-align a size */
-#define granularity_align(S)\
- (((S) + (mparams.granularity - SIZE_T_ONE))\
- & ~(mparams.granularity - SIZE_T_ONE))
-
-
-/* For mmap, use granularity alignment on windows, else page-align */
-#ifdef WIN32
-#define mmap_align(S) granularity_align(S)
-#else
-#define mmap_align(S) page_align(S)
-#endif
-
-/* For sys_alloc, enough padding to ensure can malloc request on success */
-#define SYS_ALLOC_PADDING (TOP_FOOT_SIZE + MALLOC_ALIGNMENT)
-
-#define is_page_aligned(S)\
- (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0)
-#define is_granularity_aligned(S)\
- (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0)
-
-/* True if segment S holds address A */
-#define segment_holds(S, A)\
- ((char*)(A) >= S->base && (char*)(A) < S->base + S->size)
-
-/* Return segment holding given address */
-static msegmentptr segment_holding(mstate m, char* addr) {
- msegmentptr sp = &m->seg;
- for (;;) {
- if (addr >= sp->base && addr < sp->base + sp->size)
- return sp;
- if ((sp = sp->next) == 0)
- return 0;
- }
-}
-
-/* Return true if segment contains a segment link */
-static int has_segment_link(mstate m, msegmentptr ss) {
- msegmentptr sp = &m->seg;
- for (;;) {
- if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size)
- return 1;
- if ((sp = sp->next) == 0)
- return 0;
- }
-}
-
-#ifndef MORECORE_CANNOT_TRIM
-#define should_trim(M,s) ((s) > (M)->trim_check)
-#else /* MORECORE_CANNOT_TRIM */
-#define should_trim(M,s) (0)
-#endif /* MORECORE_CANNOT_TRIM */
-
-/*
- TOP_FOOT_SIZE is padding at the end of a segment, including space
- that may be needed to place segment records and fenceposts when new
- noncontiguous segments are added.
-*/
-#define TOP_FOOT_SIZE\
- (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE)
-
-
-/* ------------------------------- Hooks -------------------------------- */
-
-/*
- PREACTION should be defined to return 0 on success, and nonzero on
- failure. If you are not using locking, you can redefine these to do
- anything you like.
-*/
-
-#if USE_LOCKS
-
-#define PREACTION(M) ((use_lock(M))? ACQUIRE_LOCK(&(M)->mutex) : 0)
-#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); }
-#else /* USE_LOCKS */
-
-#ifndef PREACTION
-#define PREACTION(M) (0)
-#endif /* PREACTION */
-
-#ifndef POSTACTION
-#define POSTACTION(M)
-#endif /* POSTACTION */
-
-#endif /* USE_LOCKS */
-
-/*
- CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses.
- USAGE_ERROR_ACTION is triggered on detected bad frees and
- reallocs. The argument p is an address that might have triggered the
- fault. It is ignored by the two predefined actions, but might be
- useful in custom actions that try to help diagnose errors.
-*/
-
-#if PROCEED_ON_ERROR
-
-/* A count of the number of corruption errors causing resets */
-int malloc_corruption_error_count;
-
-/* default corruption action */
-static void reset_on_error(mstate m);
-
-#define CORRUPTION_ERROR_ACTION(m) reset_on_error(m)
-#define USAGE_ERROR_ACTION(m, p)
-
-#else /* PROCEED_ON_ERROR */
-
-#ifndef CORRUPTION_ERROR_ACTION
-#define CORRUPTION_ERROR_ACTION(m) ABORT
-#endif /* CORRUPTION_ERROR_ACTION */
-
-#ifndef USAGE_ERROR_ACTION
-#define USAGE_ERROR_ACTION(m,p) ABORT
-#endif /* USAGE_ERROR_ACTION */
-
-#endif /* PROCEED_ON_ERROR */
-
-/* -------------------------- Debugging setup ---------------------------- */
-
-#if ! DEBUG
-
-#define check_free_chunk(M,P)
-#define check_inuse_chunk(M,P)
-#define check_malloced_chunk(M,P,N)
-#define check_mmapped_chunk(M,P)
-#define check_malloc_state(M)
-#define check_top_chunk(M,P)
-
-#else /* DEBUG */
-#define check_free_chunk(M,P) do_check_free_chunk(M,P)
-#define check_inuse_chunk(M,P) do_check_inuse_chunk(M,P)
-#define check_top_chunk(M,P) do_check_top_chunk(M,P)
-#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N)
-#define check_mmapped_chunk(M,P) do_check_mmapped_chunk(M,P)
-#define check_malloc_state(M) do_check_malloc_state(M)
-
-static void do_check_any_chunk(mstate m, mchunkptr p);
-static void do_check_top_chunk(mstate m, mchunkptr p);
-static void do_check_mmapped_chunk(mstate m, mchunkptr p);
-static void do_check_inuse_chunk(mstate m, mchunkptr p);
-static void do_check_free_chunk(mstate m, mchunkptr p);
-static void do_check_malloced_chunk(mstate m, void* mem, size_t s);
-static void do_check_tree(mstate m, tchunkptr t);
-static void do_check_treebin(mstate m, bindex_t i);
-static void do_check_smallbin(mstate m, bindex_t i);
-static void do_check_malloc_state(mstate m);
-static int bin_find(mstate m, mchunkptr x);
-static size_t traverse_and_check(mstate m);
-#endif /* DEBUG */
-
-/* ---------------------------- Indexing Bins ---------------------------- */
-
-#define is_small(s) (((s) >> SMALLBIN_SHIFT) < NSMALLBINS)
-#define small_index(s) (bindex_t)((s) >> SMALLBIN_SHIFT)
-#define small_index2size(i) ((i) << SMALLBIN_SHIFT)
-#define MIN_SMALL_INDEX (small_index(MIN_CHUNK_SIZE))
-
-/* addressing by index. See above about smallbin repositioning */
-#define smallbin_at(M, i) ((sbinptr)((char*)&((M)->smallbins[(i)<<1])))
-#define treebin_at(M,i) (&((M)->treebins[i]))
-
-/* assign tree index for size S to variable I. Use x86 asm if possible */
-#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
-#define compute_tree_index(S, I)\
-{\
- unsigned int X = S >> TREEBIN_SHIFT;\
- if (X == 0)\
- I = 0;\
- else if (X > 0xFFFF)\
- I = NTREEBINS-1;\
- else {\
- unsigned int K;\
- __asm__("bsrl\t%1, %0\n\t" : "=r" (K) : "g" (X));\
- I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
- }\
-}
-
-#elif defined (__INTEL_COMPILER)
-#define compute_tree_index(S, I)\
-{\
- size_t X = S >> TREEBIN_SHIFT;\
- if (X == 0)\
- I = 0;\
- else if (X > 0xFFFF)\
- I = NTREEBINS-1;\
- else {\
- unsigned int K = _bit_scan_reverse (X); \
- I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
- }\
-}
-
-#elif defined(_MSC_VER) && _MSC_VER>=1300
-#define compute_tree_index(S, I)\
-{\
- size_t X = S >> TREEBIN_SHIFT;\
- if (X == 0)\
- I = 0;\
- else if (X > 0xFFFF)\
- I = NTREEBINS-1;\
- else {\
- unsigned int K;\
- _BitScanReverse((DWORD *) &K, (DWORD) X);\
- I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
- }\
-}
-
-#else /* GNUC */
-#define compute_tree_index(S, I)\
-{\
- size_t X = S >> TREEBIN_SHIFT;\
- if (X == 0)\
- I = 0;\
- else if (X > 0xFFFF)\
- I = NTREEBINS-1;\
- else {\
- unsigned int Y = (unsigned int)X;\
- unsigned int N = ((Y - 0x100) >> 16) & 8;\
- unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\
- N += K;\
- N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\
- K = 14 - N + ((Y <<= K) >> 15);\
- I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\
- }\
-}
-#endif /* GNUC */
-
-/* Bit representing maximum resolved size in a treebin at i */
-#define bit_for_tree_index(i) \
- (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2)
-
-/* Shift placing maximum resolved bit in a treebin at i as sign bit */
-#define leftshift_for_tree_index(i) \
- ((i == NTREEBINS-1)? 0 : \
- ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2)))
-
-/* The size of the smallest chunk held in bin with index i */
-#define minsize_for_tree_index(i) \
- ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) | \
- (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1)))
-
-
-/* ------------------------ Operations on bin maps ----------------------- */
-
-/* bit corresponding to given index */
-#define idx2bit(i) ((binmap_t)(1) << (i))
-
-/* Mark/Clear bits with given index */
-#define mark_smallmap(M,i) ((M)->smallmap |= idx2bit(i))
-#define clear_smallmap(M,i) ((M)->smallmap &= ~idx2bit(i))
-#define smallmap_is_marked(M,i) ((M)->smallmap & idx2bit(i))
-
-#define mark_treemap(M,i) ((M)->treemap |= idx2bit(i))
-#define clear_treemap(M,i) ((M)->treemap &= ~idx2bit(i))
-#define treemap_is_marked(M,i) ((M)->treemap & idx2bit(i))
-
-/* isolate the least set bit of a bitmap */
-#define least_bit(x) ((x) & -(x))
-
-/* mask with all bits to left of least bit of x on */
-#define left_bits(x) ((x<<1) | -(x<<1))
-
-/* mask with all bits to left of or equal to least bit of x on */
-#define same_or_left_bits(x) ((x) | -(x))
-
-/* index corresponding to given bit. Use x86 asm if possible */
-
-#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
-#define compute_bit2idx(X, I)\
-{\
- unsigned int J;\
- __asm__("bsfl\t%1, %0\n\t" : "=r" (J) : "g" (X));\
- I = (bindex_t)J;\
-}
-
-#elif defined (__INTEL_COMPILER)
-#define compute_bit2idx(X, I)\
-{\
- unsigned int J;\
- J = _bit_scan_forward (X); \
- I = (bindex_t)J;\
-}
-
-#elif defined(_MSC_VER) && _MSC_VER>=1300
-#define compute_bit2idx(X, I)\
-{\
- unsigned int J;\
- _BitScanForward((DWORD *) &J, X);\
- I = (bindex_t)J;\
-}
-
-#elif USE_BUILTIN_FFS
-#define compute_bit2idx(X, I) I = ffs(X)-1
-
-#else
-#define compute_bit2idx(X, I)\
-{\
- unsigned int Y = X - 1;\
- unsigned int K = Y >> (16-4) & 16;\
- unsigned int N = K; Y >>= K;\
- N += K = Y >> (8-3) & 8; Y >>= K;\
- N += K = Y >> (4-2) & 4; Y >>= K;\
- N += K = Y >> (2-1) & 2; Y >>= K;\
- N += K = Y >> (1-0) & 1; Y >>= K;\
- I = (bindex_t)(N + Y);\
-}
-#endif /* GNUC */
-
-
-/* ----------------------- Runtime Check Support ------------------------- */
-
-/*
- For security, the main invariant is that malloc/free/etc never
- writes to a static address other than malloc_state, unless static
- malloc_state itself has been corrupted, which cannot occur via
- malloc (because of these checks). In essence this means that we
- believe all pointers, sizes, maps etc held in malloc_state, but
- check all of those linked or offsetted from other embedded data
- structures. These checks are interspersed with main code in a way
- that tends to minimize their run-time cost.
-
- When FOOTERS is defined, in addition to range checking, we also
- verify footer fields of inuse chunks, which can be used guarantee
- that the mstate controlling malloc/free is intact. This is a
- streamlined version of the approach described by William Robertson
- et al in "Run-time Detection of Heap-based Overflows" LISA'03
- http://www.usenix.org/events/lisa03/tech/robertson.html The footer
- of an inuse chunk holds the xor of its mstate and a random seed,
- that is checked upon calls to free() and realloc(). This is
- (probablistically) unguessable from outside the program, but can be
- computed by any code successfully malloc'ing any chunk, so does not
- itself provide protection against code that has already broken
- security through some other means. Unlike Robertson et al, we
- always dynamically check addresses of all offset chunks (previous,
- next, etc). This turns out to be cheaper than relying on hashes.
-*/
-
-#if !INSECURE
-/* Check if address a is at least as high as any from MORECORE or MMAP */
-#define ok_address(M, a) ((char*)(a) >= (M)->least_addr)
-/* Check if address of next chunk n is higher than base chunk p */
-#define ok_next(p, n) ((char*)(p) < (char*)(n))
-/* Check if p has inuse status */
-#define ok_inuse(p) is_inuse(p)
-/* Check if p has its pinuse bit on */
-#define ok_pinuse(p) pinuse(p)
-
-#else /* !INSECURE */
-#define ok_address(M, a) (1)
-#define ok_next(b, n) (1)
-#define ok_inuse(p) (1)
-#define ok_pinuse(p) (1)
-#endif /* !INSECURE */
-
-#if (FOOTERS && !INSECURE)
-/* Check if (alleged) mstate m has expected magic field */
-#define ok_magic(M) ((M)->magic == mparams.magic)
-#else /* (FOOTERS && !INSECURE) */
-#define ok_magic(M) (1)
-#endif /* (FOOTERS && !INSECURE) */
-
-
-/* In gcc, use __builtin_expect to minimize impact of checks */
-#if !INSECURE
-#if defined(__GNUC__) && __GNUC__ >= 3
-#define RTCHECK(e) __builtin_expect(e, 1)
-#else /* GNUC */
-#define RTCHECK(e) (e)
-#endif /* GNUC */
-#else /* !INSECURE */
-#define RTCHECK(e) (1)
-#endif /* !INSECURE */
-
-/* macros to set up inuse chunks with or without footers */
-
-#if !FOOTERS
-
-#define mark_inuse_foot(M,p,s)
-
-/* Macros for setting head/foot of non-mmapped chunks */
-
-/* Set cinuse bit and pinuse bit of next chunk */
-#define set_inuse(M,p,s)\
- ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\
- ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)
-
-/* Set cinuse and pinuse of this chunk and pinuse of next chunk */
-#define set_inuse_and_pinuse(M,p,s)\
- ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
- ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)
-
-/* Set size, cinuse and pinuse bit of this chunk */
-#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\
- ((p)->head = (s|PINUSE_BIT|CINUSE_BIT))
-
-#else /* FOOTERS */
-
-/* Set foot of inuse chunk to be xor of mstate and seed */
-#define mark_inuse_foot(M,p,s)\
- (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic))
-
-#define get_mstate_for(p)\
- ((mstate)(((mchunkptr)((char*)(p) +\
- (chunksize(p))))->prev_foot ^ mparams.magic))
-
-#define set_inuse(M,p,s)\
- ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\
- (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \
- mark_inuse_foot(M,p,s))
-
-#define set_inuse_and_pinuse(M,p,s)\
- ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
- (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\
- mark_inuse_foot(M,p,s))
-
-#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\
- ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
- mark_inuse_foot(M, p, s))
-
-#endif /* !FOOTERS */
-
-/* ---------------------------- setting mparams -------------------------- */
-
-#ifdef ENABLE_LARGE_PAGES
-typedef size_t (WINAPI *GetLargePageMinimum_t)(void);
-#endif
-
-/* Initialize mparams */
-static int init_mparams(void) {
-#ifdef NEED_GLOBAL_LOCK_INIT
- if (malloc_global_mutex_status <= 0)
- init_malloc_global_mutex();
-#endif
-
- ACQUIRE_MALLOC_GLOBAL_LOCK();
- if (mparams.magic == 0) {
- size_t magic;
- size_t psize;
- size_t gsize;
-
-#ifndef WIN32
- psize = malloc_getpagesize;
- gsize = ((DEFAULT_GRANULARITY != 0)? DEFAULT_GRANULARITY : psize);
-#else /* WIN32 */
- {
- SYSTEM_INFO system_info;
- GetSystemInfo(&system_info);
- psize = system_info.dwPageSize;
- gsize = ((DEFAULT_GRANULARITY != 0)?
- DEFAULT_GRANULARITY : system_info.dwAllocationGranularity);
-#ifdef ENABLE_LARGE_PAGES
- {
- GetLargePageMinimum_t GetLargePageMinimum_ = (GetLargePageMinimum_t) GetProcAddress(GetModuleHandle(__T("kernel32.dll")), "GetLargePageMinimum");
- if(GetLargePageMinimum_) {
- size_t largepagesize = GetLargePageMinimum_();
- if(largepagesize) {
- psize = largepagesize;
- gsize = ((DEFAULT_GRANULARITY != 0)?
- DEFAULT_GRANULARITY : largepagesize);
- if(gsize < largepagesize) gsize = largepagesize;
- }
- }
- }
-#endif
- }
-#endif /* WIN32 */
-
- /* Sanity-check configuration:
- size_t must be unsigned and as wide as pointer type.
- ints must be at least 4 bytes.
- alignment must be at least 8.
- Alignment, min chunk size, and page size must all be powers of 2.
- */
- if ((sizeof(size_t) != sizeof(char*)) ||
- (MAX_SIZE_T < MIN_CHUNK_SIZE) ||
- (sizeof(int) < 4) ||
- (MALLOC_ALIGNMENT < (size_t)8U) ||
- ((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-SIZE_T_ONE)) != 0) ||
- ((MCHUNK_SIZE & (MCHUNK_SIZE-SIZE_T_ONE)) != 0) ||
- ((gsize & (gsize-SIZE_T_ONE)) != 0) ||
- ((psize & (psize-SIZE_T_ONE)) != 0))
- ABORT;
-
- mparams.granularity = gsize;
- mparams.page_size = psize;
- mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD;
- mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD;
-#if MORECORE_CONTIGUOUS
- mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT;
-#else /* MORECORE_CONTIGUOUS */
- mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT|USE_NONCONTIGUOUS_BIT;
-#endif /* MORECORE_CONTIGUOUS */
-
-#if !ONLY_MSPACES
- /* Set up lock for main malloc area */
- gm->mflags = mparams.default_mflags;
- INITIAL_LOCK(&gm->mutex);
-#endif
-
- {
-#if USE_DEV_RANDOM
- int fd;
- unsigned char buf[sizeof(size_t)];
- /* Try to use /dev/urandom, else fall back on using time */
- if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 &&
- read(fd, buf, sizeof(buf)) == sizeof(buf)) {
- magic = *((size_t *) buf);
- close(fd);
- }
- else
-#endif /* USE_DEV_RANDOM */
-#ifdef WIN32
- magic = (size_t)(GetTickCount() ^ (size_t)0x55555555U);
-#else
- magic = (size_t)(time(0) ^ (size_t)0x55555555U);
-#endif
- magic |= (size_t)8U; /* ensure nonzero */
- magic &= ~(size_t)7U; /* improve chances of fault for bad values */
- mparams.magic = magic;
- }
- }
-
- RELEASE_MALLOC_GLOBAL_LOCK();
- return 1;
-}
-
-/* support for mallopt */
-static int change_mparam(int param_number, int value) {
- size_t val;
- ensure_initialization();
- val = (value == -1)? MAX_SIZE_T : (size_t)value;
- switch(param_number) {
- case M_TRIM_THRESHOLD:
- mparams.trim_threshold = val;
- return 1;
- case M_GRANULARITY:
- if (val >= mparams.page_size && ((val & (val-1)) == 0)) {
- mparams.granularity = val;
- return 1;
- }
- else
- return 0;
- case M_MMAP_THRESHOLD:
- mparams.mmap_threshold = val;
- return 1;
- default:
- return 0;
- }
-}
-
-#if DEBUG
-/* ------------------------- Debugging Support --------------------------- */
-
-/* Check properties of any chunk, whether free, inuse, mmapped etc */
-static void do_check_any_chunk(mstate m, mchunkptr p) {
- assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
- assert(ok_address(m, p));
-}
-
-/* Check properties of top chunk */
-static void do_check_top_chunk(mstate m, mchunkptr p) {
- msegmentptr sp = segment_holding(m, (char*)p);
- size_t sz = p->head & ~INUSE_BITS; /* third-lowest bit can be set! */
- assert(sp != 0);
- assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
- assert(ok_address(m, p));
- assert(sz == m->topsize);
- assert(sz > 0);
- assert(sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE);
- assert(pinuse(p));
- assert(!pinuse(chunk_plus_offset(p, sz)));
-}
-
-/* Check properties of (inuse) mmapped chunks */
-static void do_check_mmapped_chunk(mstate m, mchunkptr p) {
- size_t sz = chunksize(p);
- size_t len = (sz + (p->prev_foot) + MMAP_FOOT_PAD);
- assert(is_mmapped(p));
- assert(use_mmap(m));
- assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
- assert(ok_address(m, p));
- assert(!is_small(sz));
- assert((len & (mparams.page_size-SIZE_T_ONE)) == 0);
- assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD);
- assert(chunk_plus_offset(p, sz+SIZE_T_SIZE)->head == 0);
-}
-
-/* Check properties of inuse chunks */
-static void do_check_inuse_chunk(mstate m, mchunkptr p) {
- do_check_any_chunk(m, p);
- assert(is_inuse(p));
- assert(next_pinuse(p));
- /* If not pinuse and not mmapped, previous chunk has OK offset */
- assert(is_mmapped(p) || pinuse(p) || next_chunk(prev_chunk(p)) == p);
- if (is_mmapped(p))
- do_check_mmapped_chunk(m, p);
-}
-
-/* Check properties of free chunks */
-static void do_check_free_chunk(mstate m, mchunkptr p) {
- size_t sz = chunksize(p);
- mchunkptr next = chunk_plus_offset(p, sz);
- do_check_any_chunk(m, p);
- assert(!is_inuse(p));
- assert(!next_pinuse(p));
- assert (!is_mmapped(p));
- if (p != m->dv && p != m->top) {
- if (sz >= MIN_CHUNK_SIZE) {
- assert((sz & CHUNK_ALIGN_MASK) == 0);
- assert(is_aligned(chunk2mem(p)));
- assert(next->prev_foot == sz);
- assert(pinuse(p));
- assert (next == m->top || is_inuse(next));
- assert(p->fd->bk == p);
- assert(p->bk->fd == p);
- }
- else /* markers are always of size SIZE_T_SIZE */
- assert(sz == SIZE_T_SIZE);
- }
-}
-
-/* Check properties of malloced chunks at the point they are malloced */
-static void do_check_malloced_chunk(mstate m, void* mem, size_t s) {
- if (mem != 0) {
- mchunkptr p = mem2chunk(mem);
- size_t sz = p->head & ~INUSE_BITS;
- do_check_inuse_chunk(m, p);
- assert((sz & CHUNK_ALIGN_MASK) == 0);
- assert(sz >= MIN_CHUNK_SIZE);
- assert(sz >= s);
- /* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */
- assert(is_mmapped(p) || sz < (s + MIN_CHUNK_SIZE));
- }
-}
-
-/* Check a tree and its subtrees. */
-static void do_check_tree(mstate m, tchunkptr t) {
- tchunkptr head = 0;
- tchunkptr u = t;
- bindex_t tindex = t->index;
- size_t tsize = chunksize(t);
- bindex_t idx;
- compute_tree_index(tsize, idx);
- assert(tindex == idx);
- assert(tsize >= MIN_LARGE_SIZE);
- assert(tsize >= minsize_for_tree_index(idx));
- assert((idx == NTREEBINS-1) || (tsize < minsize_for_tree_index((idx+1))));
-
- do { /* traverse through chain of same-sized nodes */
- do_check_any_chunk(m, ((mchunkptr)u));
- assert(u->index == tindex);
- assert(chunksize(u) == tsize);
- assert(!is_inuse(u));
- assert(!next_pinuse(u));
- assert(u->fd->bk == u);
- assert(u->bk->fd == u);
- if (u->parent == 0) {
- assert(u->child[0] == 0);
- assert(u->child[1] == 0);
- }
- else {
- assert(head == 0); /* only one node on chain has parent */
- head = u;
- assert(u->parent != u);
- assert (u->parent->child[0] == u ||
- u->parent->child[1] == u ||
- *((tbinptr*)(u->parent)) == u);
- if (u->child[0] != 0) {
- assert(u->child[0]->parent == u);
- assert(u->child[0] != u);
- do_check_tree(m, u->child[0]);
- }
- if (u->child[1] != 0) {
- assert(u->child[1]->parent == u);
- assert(u->child[1] != u);
- do_check_tree(m, u->child[1]);
- }
- if (u->child[0] != 0 && u->child[1] != 0) {
- assert(chunksize(u->child[0]) < chunksize(u->child[1]));
- }
- }
- u = u->fd;
- } while (u != t);
- assert(head != 0);
-}
-
-/* Check all the chunks in a treebin. */
-static void do_check_treebin(mstate m, bindex_t i) {
- tbinptr* tb = treebin_at(m, i);
- tchunkptr t = *tb;
- int empty = (m->treemap & (1U << i)) == 0;
- if (t == 0)
- assert(empty);
- if (!empty)
- do_check_tree(m, t);
-}
-
-/* Check all the chunks in a smallbin. */
-static void do_check_smallbin(mstate m, bindex_t i) {
- sbinptr b = smallbin_at(m, i);
- mchunkptr p = b->bk;
- unsigned int empty = (m->smallmap & (1U << i)) == 0;
- if (p == b)
- assert(empty);
- if (!empty) {
- for (; p != b; p = p->bk) {
- size_t size = chunksize(p);
- mchunkptr q;
- /* each chunk claims to be free */
- do_check_free_chunk(m, p);
- /* chunk belongs in bin */
- assert(small_index(size) == i);
- assert(p->bk == b || chunksize(p->bk) == chunksize(p));
- /* chunk is followed by an inuse chunk */
- q = next_chunk(p);
- if (q->head != FENCEPOST_HEAD)
- do_check_inuse_chunk(m, q);
- }
- }
-}
-
-/* Find x in a bin. Used in other check functions. */
-static int bin_find(mstate m, mchunkptr x) {
- size_t size = chunksize(x);
- if (is_small(size)) {
- bindex_t sidx = small_index(size);
- sbinptr b = smallbin_at(m, sidx);
- if (smallmap_is_marked(m, sidx)) {
- mchunkptr p = b;
- do {
- if (p == x)
- return 1;
- } while ((p = p->fd) != b);
- }
- }
- else {
- bindex_t tidx;
- compute_tree_index(size, tidx);
- if (treemap_is_marked(m, tidx)) {
- tchunkptr t = *treebin_at(m, tidx);
- size_t sizebits = size << leftshift_for_tree_index(tidx);
- while (t != 0 && chunksize(t) != size) {
- t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
- sizebits <<= 1;
- }
- if (t != 0) {
- tchunkptr u = t;
- do {
- if (u == (tchunkptr)x)
- return 1;
- } while ((u = u->fd) != t);
- }
- }
- }
- return 0;
-}
-
-/* Traverse each chunk and check it; return total */
-static size_t traverse_and_check(mstate m) {
- size_t sum = 0;
- if (is_initialized(m)) {
- msegmentptr s = &m->seg;
- sum += m->topsize + TOP_FOOT_SIZE;
- while (s != 0) {
- mchunkptr q = align_as_chunk(s->base);
- mchunkptr lastq = 0;
- assert(pinuse(q));
- while (segment_holds(s, q) &&
- q != m->top && q->head != FENCEPOST_HEAD) {
- sum += chunksize(q);
- if (is_inuse(q)) {
- assert(!bin_find(m, q));
- do_check_inuse_chunk(m, q);
- }
- else {
- assert(q == m->dv || bin_find(m, q));
- assert(lastq == 0 || is_inuse(lastq)); /* Not 2 consecutive free */
- do_check_free_chunk(m, q);
- }
- lastq = q;
- q = next_chunk(q);
- }
- s = s->next;
- }
- }
- return sum;
-}
-
-/* Check all properties of malloc_state. */
-static void do_check_malloc_state(mstate m) {
- bindex_t i;
- size_t total;
- /* check bins */
- for (i = 0; i < NSMALLBINS; ++i)
- do_check_smallbin(m, i);
- for (i = 0; i < NTREEBINS; ++i)
- do_check_treebin(m, i);
-
- if (m->dvsize != 0) { /* check dv chunk */
- do_check_any_chunk(m, m->dv);
- assert(m->dvsize == chunksize(m->dv));
- assert(m->dvsize >= MIN_CHUNK_SIZE);
- assert(bin_find(m, m->dv) == 0);
- }
-
- if (m->top != 0) { /* check top chunk */
- do_check_top_chunk(m, m->top);
- /*assert(m->topsize == chunksize(m->top)); redundant */
- assert(m->topsize > 0);
- assert(bin_find(m, m->top) == 0);
- }
-
- total = traverse_and_check(m);
- assert(total <= m->footprint);
- assert(m->footprint <= m->max_footprint);
-}
-#endif /* DEBUG */
-
-/* ----------------------------- statistics ------------------------------ */
-
-#if !NO_MALLINFO
-static struct mallinfo internal_mallinfo(mstate m) {
- struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- ensure_initialization();
- if (!PREACTION(m)) {
- check_malloc_state(m);
- if (is_initialized(m)) {
- size_t nfree = SIZE_T_ONE; /* top always free */
- size_t mfree = m->topsize + TOP_FOOT_SIZE;
- size_t sum = mfree;
- msegmentptr s = &m->seg;
- while (s != 0) {
- mchunkptr q = align_as_chunk(s->base);
- while (segment_holds(s, q) &&
- q != m->top && q->head != FENCEPOST_HEAD) {
- size_t sz = chunksize(q);
- sum += sz;
- if (!is_inuse(q)) {
- mfree += sz;
- ++nfree;
- }
- q = next_chunk(q);
- }
- s = s->next;
- }
-
- nm.arena = sum;
- nm.ordblks = nfree;
- nm.hblkhd = m->footprint - sum;
- nm.usmblks = m->max_footprint;
- nm.uordblks = m->footprint - mfree;
- nm.fordblks = mfree;
- nm.keepcost = m->topsize;
- }
-
- POSTACTION(m);
- }
- return nm;
-}
-#endif /* !NO_MALLINFO */
-
-static void internal_malloc_stats(mstate m) {
- ensure_initialization();
- if (!PREACTION(m)) {
- size_t maxfp = 0;
- size_t fp = 0;
- size_t used = 0;
- check_malloc_state(m);
- if (is_initialized(m)) {
- msegmentptr s = &m->seg;
- maxfp = m->max_footprint;
- fp = m->footprint;
- used = fp - (m->topsize + TOP_FOOT_SIZE);
-
- while (s != 0) {
- mchunkptr q = align_as_chunk(s->base);
- while (segment_holds(s, q) &&
- q != m->top && q->head != FENCEPOST_HEAD) {
- if (!is_inuse(q))
- used -= chunksize(q);
- q = next_chunk(q);
- }
- s = s->next;
- }
- }
-
- fprintf(stderr, "max system bytes = %10lu\n", (unsigned long)(maxfp));
- fprintf(stderr, "system bytes = %10lu\n", (unsigned long)(fp));
- fprintf(stderr, "in use bytes = %10lu\n", (unsigned long)(used));
-
- POSTACTION(m);
- }
-}
-
-/* ----------------------- Operations on smallbins ----------------------- */
-
-/*
- Various forms of linking and unlinking are defined as macros. Even
- the ones for trees, which are very long but have very short typical
- paths. This is ugly but reduces reliance on inlining support of
- compilers.
-*/
-
-/* Link a free chunk into a smallbin */
-#define insert_small_chunk(M, P, S) {\
- bindex_t I = small_index(S);\
- mchunkptr B = smallbin_at(M, I);\
- mchunkptr F = B;\
- assert(S >= MIN_CHUNK_SIZE);\
- if (!smallmap_is_marked(M, I))\
- mark_smallmap(M, I);\
- else if (RTCHECK(ok_address(M, B->fd)))\
- F = B->fd;\
- else {\
- CORRUPTION_ERROR_ACTION(M);\
- }\
- B->fd = P;\
- F->bk = P;\
- P->fd = F;\
- P->bk = B;\
-}
-
-/* Unlink a chunk from a smallbin */
-#define unlink_small_chunk(M, P, S) {\
- mchunkptr F = P->fd;\
- mchunkptr B = P->bk;\
- bindex_t I = small_index(S);\
- assert(P != B);\
- assert(P != F);\
- assert(chunksize(P) == small_index2size(I));\
- if (F == B)\
- clear_smallmap(M, I);\
- else if (RTCHECK((F == smallbin_at(M,I) || ok_address(M, F)) &&\
- (B == smallbin_at(M,I) || ok_address(M, B)))) {\
- F->bk = B;\
- B->fd = F;\
- }\
- else {\
- CORRUPTION_ERROR_ACTION(M);\
- }\
-}
-
-/* Unlink the first chunk from a smallbin */
-#define unlink_first_small_chunk(M, B, P, I) {\
- mchunkptr F = P->fd;\
- assert(P != B);\
- assert(P != F);\
- assert(chunksize(P) == small_index2size(I));\
- if (B == F)\
- clear_smallmap(M, I);\
- else if (RTCHECK(ok_address(M, F))) {\
- B->fd = F;\
- F->bk = B;\
- }\
- else {\
- CORRUPTION_ERROR_ACTION(M);\
- }\
-}
-
-
-
-/* Replace dv node, binning the old one */
-/* Used only when dvsize known to be small */
-#define replace_dv(M, P, S) {\
- size_t DVS = M->dvsize;\
- if (DVS != 0) {\
- mchunkptr DV = M->dv;\
- assert(is_small(DVS));\
- insert_small_chunk(M, DV, DVS);\
- }\
- M->dvsize = S;\
- M->dv = P;\
-}
-
-/* ------------------------- Operations on trees ------------------------- */
-
-/* Insert chunk into tree */
-#define insert_large_chunk(M, X, S) {\
- tbinptr* H;\
- bindex_t I;\
- compute_tree_index(S, I);\
- H = treebin_at(M, I);\
- X->index = I;\
- X->child[0] = X->child[1] = 0;\
- if (!treemap_is_marked(M, I)) {\
- mark_treemap(M, I);\
- *H = X;\
- X->parent = (tchunkptr)H;\
- X->fd = X->bk = X;\
- }\
- else {\
- tchunkptr T = *H;\
- size_t K = S << leftshift_for_tree_index(I);\
- for (;;) {\
- if (chunksize(T) != S) {\
- tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\
- K <<= 1;\
- if (*C != 0)\
- T = *C;\
- else if (RTCHECK(ok_address(M, C))) {\
- *C = X;\
- X->parent = T;\
- X->fd = X->bk = X;\
- break;\
- }\
- else {\
- CORRUPTION_ERROR_ACTION(M);\
- break;\
- }\
- }\
- else {\
- tchunkptr F = T->fd;\
- if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\
- T->fd = F->bk = X;\
- X->fd = F;\
- X->bk = T;\
- X->parent = 0;\
- break;\
- }\
- else {\
- CORRUPTION_ERROR_ACTION(M);\
- break;\
- }\
- }\
- }\
- }\
-}
-
-/*
- Unlink steps:
-
- 1. If x is a chained node, unlink it from its same-sized fd/bk links
- and choose its bk node as its replacement.
- 2. If x was the last node of its size, but not a leaf node, it must
- be replaced with a leaf node (not merely one with an open left or
- right), to make sure that lefts and rights of descendents
- correspond properly to bit masks. We use the rightmost descendent
- of x. We could use any other leaf, but this is easy to locate and
- tends to counteract removal of leftmosts elsewhere, and so keeps
- paths shorter than minimally guaranteed. This doesn't loop much
- because on average a node in a tree is near the bottom.
- 3. If x is the base of a chain (i.e., has parent links) relink
- x's parent and children to x's replacement (or null if none).
-*/
-
-#define unlink_large_chunk(M, X) {\
- tchunkptr XP = X->parent;\
- tchunkptr R;\
- if (X->bk != X) {\
- tchunkptr F = X->fd;\
- R = X->bk;\
- if (RTCHECK(ok_address(M, F))) {\
- F->bk = R;\
- R->fd = F;\
- }\
- else {\
- CORRUPTION_ERROR_ACTION(M);\
- }\
- }\
- else {\
- tchunkptr* RP;\
- if (((R = *(RP = &(X->child[1]))) != 0) ||\
- ((R = *(RP = &(X->child[0]))) != 0)) {\
- tchunkptr* CP;\
- while ((*(CP = &(R->child[1])) != 0) ||\
- (*(CP = &(R->child[0])) != 0)) {\
- R = *(RP = CP);\
- }\
- if (RTCHECK(ok_address(M, RP)))\
- *RP = 0;\
- else {\
- CORRUPTION_ERROR_ACTION(M);\
- }\
- }\
- }\
- if (XP != 0) {\
- tbinptr* H = treebin_at(M, X->index);\
- if (X == *H) {\
- if ((*H = R) == 0) \
- clear_treemap(M, X->index);\
- }\
- else if (RTCHECK(ok_address(M, XP))) {\
- if (XP->child[0] == X) \
- XP->child[0] = R;\
- else \
- XP->child[1] = R;\
- }\
- else\
- CORRUPTION_ERROR_ACTION(M);\
- if (R != 0) {\
- if (RTCHECK(ok_address(M, R))) {\
- tchunkptr C0, C1;\
- R->parent = XP;\
- if ((C0 = X->child[0]) != 0) {\
- if (RTCHECK(ok_address(M, C0))) {\
- R->child[0] = C0;\
- C0->parent = R;\
- }\
- else\
- CORRUPTION_ERROR_ACTION(M);\
- }\
- if ((C1 = X->child[1]) != 0) {\
- if (RTCHECK(ok_address(M, C1))) {\
- R->child[1] = C1;\
- C1->parent = R;\
- }\
- else\
- CORRUPTION_ERROR_ACTION(M);\
- }\
- }\
- else\
- CORRUPTION_ERROR_ACTION(M);\
- }\
- }\
-}
-
-/* Relays to large vs small bin operations */
-
-#define insert_chunk(M, P, S)\
- if (is_small(S)) insert_small_chunk(M, P, S)\
- else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); }
-
-#define unlink_chunk(M, P, S)\
- if (is_small(S)) unlink_small_chunk(M, P, S)\
- else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); }
-
-
-/* Relays to internal calls to malloc/free from realloc, memalign etc */
-
-#if ONLY_MSPACES
-#define internal_malloc(m, b) mspace_malloc(m, b)
-#define internal_free(m, mem) mspace_free(m,mem);
-#else /* ONLY_MSPACES */
-#if MSPACES
-#define internal_malloc(m, b)\
- (m == gm)? dlmalloc(b) : mspace_malloc(m, b)
-#define internal_free(m, mem)\
- if (m == gm) dlfree(mem); else mspace_free(m,mem);
-#else /* MSPACES */
-#define internal_malloc(m, b) dlmalloc(b)
-#define internal_free(m, mem) dlfree(mem)
-#endif /* MSPACES */
-#endif /* ONLY_MSPACES */
-
-/* ----------------------- Direct-mmapping chunks ----------------------- */
-
-/*
- Directly mmapped chunks are set up with an offset to the start of
- the mmapped region stored in the prev_foot field of the chunk. This
- allows reconstruction of the required argument to MUNMAP when freed,
- and also allows adjustment of the returned chunk to meet alignment
- requirements (especially in memalign).
-*/
-
-/* Malloc using mmap */
-static void* mmap_alloc(mstate m, size_t nb) {
- size_t mmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
- if (mmsize > nb) { /* Check for wrap around 0 */
- char* mm = (char*)(CALL_DIRECT_MMAP(mmsize));
- if (mm != CMFAIL) {
- size_t offset = align_offset(chunk2mem(mm));
- size_t psize = mmsize - offset - MMAP_FOOT_PAD;
- mchunkptr p = (mchunkptr)(mm + offset);
- p->prev_foot = offset;
- p->head = psize;
- mark_inuse_foot(m, p, psize);
- chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD;
- chunk_plus_offset(p, psize+SIZE_T_SIZE)->head = 0;
-
- if (m->least_addr == 0 || mm < m->least_addr)
- m->least_addr = mm;
- if ((m->footprint += mmsize) > m->max_footprint)
- m->max_footprint = m->footprint;
- assert(is_aligned(chunk2mem(p)));
- check_mmapped_chunk(m, p);
- return chunk2mem(p);
- }
- }
- return 0;
-}
-
-/* Realloc using mmap */
-static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb) {
- size_t oldsize = chunksize(oldp);
- if (is_small(nb)) /* Can't shrink mmap regions below small size */
- return 0;
- /* Keep old chunk if big enough but not too big */
- if (oldsize >= nb + SIZE_T_SIZE &&
- (oldsize - nb) <= (mparams.granularity << 1))
- return oldp;
- else {
- size_t offset = oldp->prev_foot;
- size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD;
- size_t newmmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
- char* cp = (char*)CALL_MREMAP((char*)oldp - offset,
- oldmmsize, newmmsize, 1);
- if (cp != CMFAIL) {
- mchunkptr newp = (mchunkptr)(cp + offset);
- size_t psize = newmmsize - offset - MMAP_FOOT_PAD;
- newp->head = psize;
- mark_inuse_foot(m, newp, psize);
- chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD;
- chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0;
-
- if (cp < m->least_addr)
- m->least_addr = cp;
- if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint)
- m->max_footprint = m->footprint;
- check_mmapped_chunk(m, newp);
- return newp;
- }
- }
- return 0;
-}
-
-/* -------------------------- mspace management -------------------------- */
-
-/* Initialize top chunk and its size */
-static void init_top(mstate m, mchunkptr p, size_t psize) {
- /* Ensure alignment */
- size_t offset = align_offset(chunk2mem(p));
- p = (mchunkptr)((char*)p + offset);
- psize -= offset;
-
- m->top = p;
- m->topsize = psize;
- p->head = psize | PINUSE_BIT;
- /* set size of fake trailing chunk holding overhead space only once */
- chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE;
- m->trim_check = mparams.trim_threshold; /* reset on each update */
-}
-
-/* Initialize bins for a new mstate that is otherwise zeroed out */
-static void init_bins(mstate m) {
- /* Establish circular links for smallbins */
- bindex_t i;
- for (i = 0; i < NSMALLBINS; ++i) {
- sbinptr bin = smallbin_at(m,i);
- bin->fd = bin->bk = bin;
- }
-}
-
-#if PROCEED_ON_ERROR
-
-/* default corruption action */
-static void reset_on_error(mstate m) {
- int i;
- ++malloc_corruption_error_count;
- /* Reinitialize fields to forget about all memory */
- m->smallbins = m->treebins = 0;
- m->dvsize = m->topsize = 0;
- m->seg.base = 0;
- m->seg.size = 0;
- m->seg.next = 0;
- m->top = m->dv = 0;
- for (i = 0; i < NTREEBINS; ++i)
- *treebin_at(m, i) = 0;
- init_bins(m);
-}
-#endif /* PROCEED_ON_ERROR */
-
-/* Allocate chunk and prepend remainder with chunk in successor base. */
-static void* prepend_alloc(mstate m, char* newbase, char* oldbase,
- size_t nb) {
- mchunkptr p = align_as_chunk(newbase);
- mchunkptr oldfirst = align_as_chunk(oldbase);
- size_t psize = (char*)oldfirst - (char*)p;
- mchunkptr q = chunk_plus_offset(p, nb);
- size_t qsize = psize - nb;
- set_size_and_pinuse_of_inuse_chunk(m, p, nb);
-
- assert((char*)oldfirst > (char*)q);
- assert(pinuse(oldfirst));
- assert(qsize >= MIN_CHUNK_SIZE);
-
- /* consolidate remainder with first chunk of old base */
- if (oldfirst == m->top) {
- size_t tsize = m->topsize += qsize;
- m->top = q;
- q->head = tsize | PINUSE_BIT;
- check_top_chunk(m, q);
- }
- else if (oldfirst == m->dv) {
- size_t dsize = m->dvsize += qsize;
- m->dv = q;
- set_size_and_pinuse_of_free_chunk(q, dsize);
- }
- else {
- if (!is_inuse(oldfirst)) {
- size_t nsize = chunksize(oldfirst);
- unlink_chunk(m, oldfirst, nsize);
- oldfirst = chunk_plus_offset(oldfirst, nsize);
- qsize += nsize;
- }
- set_free_with_pinuse(q, qsize, oldfirst);
- insert_chunk(m, q, qsize);
- check_free_chunk(m, q);
- }
-
- check_malloced_chunk(m, chunk2mem(p), nb);
- return chunk2mem(p);
-}
-
-/* Add a segment to hold a new noncontiguous region */
-static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) {
- /* Determine locations and sizes of segment, fenceposts, old top */
- char* old_top = (char*)m->top;
- msegmentptr oldsp = segment_holding(m, old_top);
- char* old_end = oldsp->base + oldsp->size;
- size_t ssize = pad_request(sizeof(struct malloc_segment));
- char* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
- size_t offset = align_offset(chunk2mem(rawsp));
- char* asp = rawsp + offset;
- char* csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp;
- mchunkptr sp = (mchunkptr)csp;
- msegmentptr ss = (msegmentptr)(chunk2mem(sp));
- mchunkptr tnext = chunk_plus_offset(sp, ssize);
- mchunkptr p = tnext;
- int nfences = 0;
-
- /* reset top to new space */
- init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);
-
- /* Set up segment record */
- assert(is_aligned(ss));
- set_size_and_pinuse_of_inuse_chunk(m, sp, ssize);
- *ss = m->seg; /* Push current record */
- m->seg.base = tbase;
- m->seg.size = tsize;
- m->seg.sflags = mmapped;
- m->seg.next = ss;
-
- /* Insert trailing fenceposts */
- for (;;) {
- mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE);
- p->head = FENCEPOST_HEAD;
- ++nfences;
- if ((char*)(&(nextp->head)) < old_end)
- p = nextp;
- else
- break;
- }
- assert(nfences >= 2);
-
- /* Insert the rest of old top into a bin as an ordinary free chunk */
- if (csp != old_top) {
- mchunkptr q = (mchunkptr)old_top;
- size_t psize = csp - old_top;
- mchunkptr tn = chunk_plus_offset(q, psize);
- set_free_with_pinuse(q, psize, tn);
- insert_chunk(m, q, psize);
- }
-
- check_top_chunk(m, m->top);
-}
-
-/* -------------------------- System allocation -------------------------- */
-
-/* Get memory from system using MORECORE or MMAP */
-static void* sys_alloc(mstate m, size_t nb) {
- char* tbase = CMFAIL;
- size_t tsize = 0;
- flag_t mmap_flag = 0;
-
- ensure_initialization();
-
- /* Directly map large chunks, but only if already initialized */
- if (use_mmap(m) && nb >= mparams.mmap_threshold && m->topsize != 0) {
- void* mem = mmap_alloc(m, nb);
- if (mem != 0)
- return mem;
- }
-
- /*
- Try getting memory in any of three ways (in most-preferred to
- least-preferred order):
- 1. A call to MORECORE that can normally contiguously extend memory.
- (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or
- or main space is mmapped or a previous contiguous call failed)
- 2. A call to MMAP new space (disabled if not HAVE_MMAP).
- Note that under the default settings, if MORECORE is unable to
- fulfill a request, and HAVE_MMAP is true, then mmap is
- used as a noncontiguous system allocator. This is a useful backup
- strategy for systems with holes in address spaces -- in this case
- sbrk cannot contiguously expand the heap, but mmap may be able to
- find space.
- 3. A call to MORECORE that cannot usually contiguously extend memory.
- (disabled if not HAVE_MORECORE)
-
- In all cases, we need to request enough bytes from system to ensure
- we can malloc nb bytes upon success, so pad with enough space for
- top_foot, plus alignment-pad to make sure we don't lose bytes if
- not on boundary, and round this up to a granularity unit.
- */
-
- if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) {
- char* br = CMFAIL;
- msegmentptr ss = (m->top == 0)? 0 : segment_holding(m, (char*)m->top);
- size_t asize = 0;
- ACQUIRE_MALLOC_GLOBAL_LOCK();
-
- if (ss == 0) { /* First time through or recovery */
- char* base = (char*)CALL_MORECORE(0);
- if (base != CMFAIL) {
- asize = granularity_align(nb + SYS_ALLOC_PADDING);
- /* Adjust to end on a page boundary */
- if (!is_page_aligned(base))
- asize += (page_align((size_t)base) - (size_t)base);
- /* Can't call MORECORE if size is negative when treated as signed */
- if (asize < HALF_MAX_SIZE_T &&
- (br = (char*)(CALL_MORECORE(asize))) == base) {
- tbase = base;
- tsize = asize;
- }
- }
- }
- else {
- /* Subtract out existing available top space from MORECORE request. */
- asize = granularity_align(nb - m->topsize + SYS_ALLOC_PADDING);
- /* Use mem here only if it did continuously extend old space */
- if (asize < HALF_MAX_SIZE_T &&
- (br = (char*)(CALL_MORECORE(asize))) == ss->base+ss->size) {
- tbase = br;
- tsize = asize;
- }
- }
-
- if (tbase == CMFAIL) { /* Cope with partial failure */
- if (br != CMFAIL) { /* Try to use/extend the space we did get */
- if (asize < HALF_MAX_SIZE_T &&
- asize < nb + SYS_ALLOC_PADDING) {
- size_t esize = granularity_align(nb + SYS_ALLOC_PADDING - asize);
- if (esize < HALF_MAX_SIZE_T) {
- char* end = (char*)CALL_MORECORE(esize);
- if (end != CMFAIL)
- asize += esize;
- else { /* Can't use; try to release */
- (void) CALL_MORECORE(-asize);
- br = CMFAIL;
- }
- }
- }
- }
- if (br != CMFAIL) { /* Use the space we did get */
- tbase = br;
- tsize = asize;
- }
- else
- disable_contiguous(m); /* Don't try contiguous path in the future */
- }
-
- RELEASE_MALLOC_GLOBAL_LOCK();
- }
-
- if (HAVE_MMAP && tbase == CMFAIL) { /* Try MMAP */
- size_t rsize = granularity_align(nb + SYS_ALLOC_PADDING);
- if (rsize > nb) { /* Fail if wraps around zero */
- char* mp = (char*)(CALL_MMAP(rsize));
- if (mp != CMFAIL) {
- tbase = mp;
- tsize = rsize;
- mmap_flag = USE_MMAP_BIT;
- }
- }
- }
-
- if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */
- size_t asize = granularity_align(nb + SYS_ALLOC_PADDING);
- if (asize < HALF_MAX_SIZE_T) {
- char* br = CMFAIL;
- char* end = CMFAIL;
- ACQUIRE_MALLOC_GLOBAL_LOCK();
- br = (char*)(CALL_MORECORE(asize));
- end = (char*)(CALL_MORECORE(0));
- RELEASE_MALLOC_GLOBAL_LOCK();
- if (br != CMFAIL && end != CMFAIL && br < end) {
- size_t ssize = end - br;
- if (ssize > nb + TOP_FOOT_SIZE) {
- tbase = br;
- tsize = ssize;
- }
- }
- }
- }
-
- if (tbase != CMFAIL) {
-
- if ((m->footprint += tsize) > m->max_footprint)
- m->max_footprint = m->footprint;
-
- if (!is_initialized(m)) { /* first-time initialization */
- if (m->least_addr == 0 || tbase < m->least_addr)
- m->least_addr = tbase;
- m->seg.base = tbase;
- m->seg.size = tsize;
- m->seg.sflags = mmap_flag;
- m->magic = mparams.magic;
- m->release_checks = MAX_RELEASE_CHECK_RATE;
- init_bins(m);
-#if !ONLY_MSPACES
- if (is_global(m))
- init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);
- else
-#endif
- {
- /* Offset top by embedded malloc_state */
- mchunkptr mn = next_chunk(mem2chunk(m));
- init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) -TOP_FOOT_SIZE);
- }
- }
-
- else {
- /* Try to merge with an existing segment */
- msegmentptr sp = &m->seg;
- /* Only consider most recent segment if traversal suppressed */
- while (sp != 0 && tbase != sp->base + sp->size)
- sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next;
- if (sp != 0 &&
- !is_extern_segment(sp) &&
- (sp->sflags & USE_MMAP_BIT) == mmap_flag &&
- segment_holds(sp, m->top)) { /* append */
- sp->size += tsize;
- init_top(m, m->top, m->topsize + tsize);
- }
- else {
- if (tbase < m->least_addr)
- m->least_addr = tbase;
- sp = &m->seg;
- while (sp != 0 && sp->base != tbase + tsize)
- sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next;
- if (sp != 0 &&
- !is_extern_segment(sp) &&
- (sp->sflags & USE_MMAP_BIT) == mmap_flag) {
- char* oldbase = sp->base;
- sp->base = tbase;
- sp->size += tsize;
- return prepend_alloc(m, tbase, oldbase, nb);
- }
- else
- add_segment(m, tbase, tsize, mmap_flag);
- }
- }
-
- if (nb < m->topsize) { /* Allocate from new or extended top space */
- size_t rsize = m->topsize -= nb;
- mchunkptr p = m->top;
- mchunkptr r = m->top = chunk_plus_offset(p, nb);
- r->head = rsize | PINUSE_BIT;
- set_size_and_pinuse_of_inuse_chunk(m, p, nb);
- check_top_chunk(m, m->top);
- check_malloced_chunk(m, chunk2mem(p), nb);
- return chunk2mem(p);
- }
- }
-
- MALLOC_FAILURE_ACTION;
- return 0;
-}
-
-/* ----------------------- system deallocation -------------------------- */
-
-/* Unmap and unlink any mmapped segments that don't contain used chunks */
-static size_t release_unused_segments(mstate m) {
- size_t released = 0;
- int nsegs = 0;
- msegmentptr pred = &m->seg;
- msegmentptr sp = pred->next;
- while (sp != 0) {
- char* base = sp->base;
- size_t size = sp->size;
- msegmentptr next = sp->next;
- ++nsegs;
- if (is_mmapped_segment(sp) && !is_extern_segment(sp)) {
- mchunkptr p = align_as_chunk(base);
- size_t psize = chunksize(p);
- /* Can unmap if first chunk holds entire segment and not pinned */
- if (!is_inuse(p) && (char*)p + psize >= base + size - TOP_FOOT_SIZE) {
- tchunkptr tp = (tchunkptr)p;
- assert(segment_holds(sp, (char*)sp));
- if (p == m->dv) {
- m->dv = 0;
- m->dvsize = 0;
- }
- else {
- unlink_large_chunk(m, tp);
- }
- if (CALL_MUNMAP(base, size) == 0) {
- released += size;
- m->footprint -= size;
- /* unlink obsoleted record */
- sp = pred;
- sp->next = next;
- }
- else { /* back out if cannot unmap */
- insert_large_chunk(m, tp, psize);
- }
- }
- }
- if (NO_SEGMENT_TRAVERSAL) /* scan only first segment */
- break;
- pred = sp;
- sp = next;
- }
- /* Reset check counter */
- m->release_checks = ((nsegs > MAX_RELEASE_CHECK_RATE)?
- nsegs : MAX_RELEASE_CHECK_RATE);
- return released;
-}
-
-static int sys_trim(mstate m, size_t pad) {
- size_t released = 0;
- ensure_initialization();
- if (pad < MAX_REQUEST && is_initialized(m)) {
- pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */
-
- if (m->topsize > pad) {
- /* Shrink top space in granularity-size units, keeping at least one */
- size_t unit = mparams.granularity;
- size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit -
- SIZE_T_ONE) * unit;
- msegmentptr sp = segment_holding(m, (char*)m->top);
-
- if (!is_extern_segment(sp)) {
- if (is_mmapped_segment(sp)) {
- if (HAVE_MMAP &&
- sp->size >= extra &&
- !has_segment_link(m, sp)) { /* can't shrink if pinned */
- size_t newsize = sp->size - extra;
- /* Prefer mremap, fall back to munmap */
- if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) ||
- (CALL_MUNMAP(sp->base + newsize, extra) == 0)) {
- released = extra;
- }
- }
- }
- else if (HAVE_MORECORE) {
- if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */
- extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit;
- ACQUIRE_MALLOC_GLOBAL_LOCK();
- {
- /* Make sure end of memory is where we last set it. */
- char* old_br = (char*)(CALL_MORECORE(0));
- if (old_br == sp->base + sp->size) {
- char* rel_br = (char*)(CALL_MORECORE(-extra));
- char* new_br = (char*)(CALL_MORECORE(0));
- if (rel_br != CMFAIL && new_br < old_br)
- released = old_br - new_br;
- }
- }
- RELEASE_MALLOC_GLOBAL_LOCK();
- }
- }
-
- if (released != 0) {
- sp->size -= released;
- m->footprint -= released;
- init_top(m, m->top, m->topsize - released);
- check_top_chunk(m, m->top);
- }
- }
-
- /* Unmap any unused mmapped segments */
- if (HAVE_MMAP)
- released += release_unused_segments(m);
-
- /* On failure, disable autotrim to avoid repeated failed future calls */
- if (released == 0 && m->topsize > m->trim_check)
- m->trim_check = MAX_SIZE_T;
- }
-
- return (released != 0)? 1 : 0;
-}
-
-
-/* ---------------------------- malloc support --------------------------- */
-
-/* allocate a large request from the best fitting chunk in a treebin */
-static void* tmalloc_large(mstate m, size_t nb) {
- tchunkptr v = 0;
- size_t rsize = -nb; /* Unsigned negation */
- tchunkptr t;
- bindex_t idx;
- compute_tree_index(nb, idx);
- if ((t = *treebin_at(m, idx)) != 0) {
- /* Traverse tree for this bin looking for node with size == nb */
- size_t sizebits = nb << leftshift_for_tree_index(idx);
- tchunkptr rst = 0; /* The deepest untaken right subtree */
- for (;;) {
- tchunkptr rt;
- size_t trem = chunksize(t) - nb;
- if (trem < rsize) {
- v = t;
- if ((rsize = trem) == 0)
- break;
- }
- rt = t->child[1];
- t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
- if (rt != 0 && rt != t)
- rst = rt;
- if (t == 0) {
- t = rst; /* set t to least subtree holding sizes > nb */
- break;
- }
- sizebits <<= 1;
- }
- }
- if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */
- binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap;
- if (leftbits != 0) {
- bindex_t i;
- binmap_t leastbit = least_bit(leftbits);
- compute_bit2idx(leastbit, i);
- t = *treebin_at(m, i);
- }
- }
-
- while (t != 0) { /* find smallest of tree or subtree */
- size_t trem = chunksize(t) - nb;
- if (trem < rsize) {
- rsize = trem;
- v = t;
- }
- t = leftmost_child(t);
- }
-
- /* If dv is a better fit, return 0 so malloc will use it */
- if (v != 0 && rsize < (size_t)(m->dvsize - nb)) {
- if (RTCHECK(ok_address(m, v))) { /* split */
- mchunkptr r = chunk_plus_offset(v, nb);
- assert(chunksize(v) == rsize + nb);
- if (RTCHECK(ok_next(v, r))) {
- unlink_large_chunk(m, v);
- if (rsize < MIN_CHUNK_SIZE)
- set_inuse_and_pinuse(m, v, (rsize + nb));
- else {
- set_size_and_pinuse_of_inuse_chunk(m, v, nb);
- set_size_and_pinuse_of_free_chunk(r, rsize);
- insert_chunk(m, r, rsize);
- }
- return chunk2mem(v);
- }
- }
- CORRUPTION_ERROR_ACTION(m);
- }
- return 0;
-}
-
-/* allocate a small request from the best fitting chunk in a treebin */
-static void* tmalloc_small(mstate m, size_t nb) {
- tchunkptr t, v;
- size_t rsize;
- bindex_t i;
- binmap_t leastbit = least_bit(m->treemap);
- compute_bit2idx(leastbit, i);
- v = t = *treebin_at(m, i);
- rsize = chunksize(t) - nb;
-
- while ((t = leftmost_child(t)) != 0) {
- size_t trem = chunksize(t) - nb;
- if (trem < rsize) {
- rsize = trem;
- v = t;
- }
- }
-
- if (RTCHECK(ok_address(m, v))) {
- mchunkptr r = chunk_plus_offset(v, nb);
- assert(chunksize(v) == rsize + nb);
- if (RTCHECK(ok_next(v, r))) {
- unlink_large_chunk(m, v);
- if (rsize < MIN_CHUNK_SIZE)
- set_inuse_and_pinuse(m, v, (rsize + nb));
- else {
- set_size_and_pinuse_of_inuse_chunk(m, v, nb);
- set_size_and_pinuse_of_free_chunk(r, rsize);
- replace_dv(m, r, rsize);
- }
- return chunk2mem(v);
- }
- }
-
- CORRUPTION_ERROR_ACTION(m);
- return 0;
-}
-
-/* --------------------------- realloc support --------------------------- */
-
-static void* internal_realloc(mstate m, void* oldmem, size_t bytes) {
- if (bytes >= MAX_REQUEST) {
- MALLOC_FAILURE_ACTION;
- return 0;
- }
- if (!PREACTION(m)) {
- mchunkptr oldp = mem2chunk(oldmem);
- size_t oldsize = chunksize(oldp);
- mchunkptr next = chunk_plus_offset(oldp, oldsize);
- mchunkptr newp = 0;
- void* extra = 0;
-
- /* Try to either shrink or extend into top. Else malloc-copy-free */
-
- if (RTCHECK(ok_address(m, oldp) && ok_inuse(oldp) &&
- ok_next(oldp, next) && ok_pinuse(next))) {
- size_t nb = request2size(bytes);
- if (is_mmapped(oldp))
- newp = mmap_resize(m, oldp, nb);
- else if (oldsize >= nb) { /* already big enough */
- size_t rsize = oldsize - nb;
- newp = oldp;
- if (rsize >= MIN_CHUNK_SIZE) {
- mchunkptr remainder = chunk_plus_offset(newp, nb);
- set_inuse(m, newp, nb);
- set_inuse_and_pinuse(m, remainder, rsize);
- extra = chunk2mem(remainder);
- }
- }
- else if (next == m->top && oldsize + m->topsize > nb) {
- /* Expand into top */
- size_t newsize = oldsize + m->topsize;
- size_t newtopsize = newsize - nb;
- mchunkptr newtop = chunk_plus_offset(oldp, nb);
- set_inuse(m, oldp, nb);
- newtop->head = newtopsize |PINUSE_BIT;
- m->top = newtop;
- m->topsize = newtopsize;
- newp = oldp;
- }
- }
- else {
- USAGE_ERROR_ACTION(m, oldmem);
- POSTACTION(m);
- return 0;
- }
-#if DEBUG
- if (newp != 0) {
- check_inuse_chunk(m, newp); /* Check requires lock */
- }
-#endif
-
- POSTACTION(m);
-
- if (newp != 0) {
- if (extra != 0) {
- internal_free(m, extra);
- }
- return chunk2mem(newp);
- }
- else {
- void* newmem = internal_malloc(m, bytes);
- if (newmem != 0) {
- size_t oc = oldsize - overhead_for(oldp);
- memcpy(newmem, oldmem, (oc < bytes)? oc : bytes);
- internal_free(m, oldmem);
- }
- return newmem;
- }
- }
- return 0;
-}
-
-/* --------------------------- memalign support -------------------------- */
-
-static void* internal_memalign(mstate m, size_t alignment, size_t bytes) {
- if (alignment <= MALLOC_ALIGNMENT) /* Can just use malloc */
- return internal_malloc(m, bytes);
- if (alignment < MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */
- alignment = MIN_CHUNK_SIZE;
- if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */
- size_t a = MALLOC_ALIGNMENT << 1;
- while (a < alignment) a <<= 1;
- alignment = a;
- }
-
- if (bytes >= MAX_REQUEST - alignment) {
- if (m != 0) { /* Test isn't needed but avoids compiler warning */
- MALLOC_FAILURE_ACTION;
- }
- }
- else {
- size_t nb = request2size(bytes);
- size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD;
- char* mem = (char*)internal_malloc(m, req);
- if (mem != 0) {
- void* leader = 0;
- void* trailer = 0;
- mchunkptr p = mem2chunk(mem);
-
- if (PREACTION(m)) return 0;
- if ((((size_t)(mem)) % alignment) != 0) { /* misaligned */
- /*
- Find an aligned spot inside chunk. Since we need to give
- back leading space in a chunk of at least MIN_CHUNK_SIZE, if
- the first calculation places us at a spot with less than
- MIN_CHUNK_SIZE leader, we can move to the next aligned spot.
- We've allocated enough total room so that this is always
- possible.
- */
- char* br = (char*)mem2chunk((size_t)(((size_t)(mem +
- alignment -
- SIZE_T_ONE)) &
- -alignment));
- char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)?
- br : br+alignment;
- mchunkptr newp = (mchunkptr)pos;
- size_t leadsize = pos - (char*)(p);
- size_t newsize = chunksize(p) - leadsize;
-
- if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */
- newp->prev_foot = p->prev_foot + leadsize;
- newp->head = newsize;
- }
- else { /* Otherwise, give back leader, use the rest */
- set_inuse(m, newp, newsize);
- set_inuse(m, p, leadsize);
- leader = chunk2mem(p);
- }
- p = newp;
- }
-
- /* Give back spare room at the end */
- if (!is_mmapped(p)) {
- size_t size = chunksize(p);
- if (size > nb + MIN_CHUNK_SIZE) {
- size_t remainder_size = size - nb;
- mchunkptr remainder = chunk_plus_offset(p, nb);
- set_inuse(m, p, nb);
- set_inuse(m, remainder, remainder_size);
- trailer = chunk2mem(remainder);
- }
- }
-
- assert (chunksize(p) >= nb);
- assert((((size_t)(chunk2mem(p))) % alignment) == 0);
- check_inuse_chunk(m, p);
- POSTACTION(m);
- if (leader != 0) {
- internal_free(m, leader);
- }
- if (trailer != 0) {
- internal_free(m, trailer);
- }
- return chunk2mem(p);
- }
- }
- return 0;
-}
-
-/* ------------------------ comalloc/coalloc support --------------------- */
-
-static void** ialloc(mstate m,
- size_t n_elements,
- size_t* sizes,
- int opts,
- void* chunks[]) {
- /*
- This provides common support for independent_X routines, handling
- all of the combinations that can result.
-
- The opts arg has:
- bit 0 set if all elements are same size (using sizes[0])
- bit 1 set if elements should be zeroed
- */
-
- size_t element_size; /* chunksize of each element, if all same */
- size_t contents_size; /* total size of elements */
- size_t array_size; /* request size of pointer array */
- void* mem; /* malloced aggregate space */
- mchunkptr p; /* corresponding chunk */
- size_t remainder_size; /* remaining bytes while splitting */
- void** marray; /* either "chunks" or malloced ptr array */
- mchunkptr array_chunk; /* chunk for malloced ptr array */
- flag_t was_enabled; /* to disable mmap */
- size_t size;
- size_t i;
-
- ensure_initialization();
- /* compute array length, if needed */
- if (chunks != 0) {
- if (n_elements == 0)
- return chunks; /* nothing to do */
- marray = chunks;
- array_size = 0;
- }
- else {
- /* if empty req, must still return chunk representing empty array */
- if (n_elements == 0)
- return (void**)internal_malloc(m, 0);
- marray = 0;
- array_size = request2size(n_elements * (sizeof(void*)));
- }
-
- /* compute total element size */
- if (opts & 0x1) { /* all-same-size */
- element_size = request2size(*sizes);
- contents_size = n_elements * element_size;
- }
- else { /* add up all the sizes */
- element_size = 0;
- contents_size = 0;
- for (i = 0; i != n_elements; ++i)
- contents_size += request2size(sizes[i]);
- }
-
- size = contents_size + array_size;
-
- /*
- Allocate the aggregate chunk. First disable direct-mmapping so
- malloc won't use it, since we would not be able to later
- free/realloc space internal to a segregated mmap region.
- */
- was_enabled = use_mmap(m);
- disable_mmap(m);
- mem = internal_malloc(m, size - CHUNK_OVERHEAD);
- if (was_enabled)
- enable_mmap(m);
- if (mem == 0)
- return 0;
-
- if (PREACTION(m)) return 0;
- p = mem2chunk(mem);
- remainder_size = chunksize(p);
-
- assert(!is_mmapped(p));
-
- if (opts & 0x2) { /* optionally clear the elements */
- memset((size_t*)mem, 0, remainder_size - SIZE_T_SIZE - array_size);
- }
-
- /* If not provided, allocate the pointer array as final part of chunk */
- if (marray == 0) {
- size_t array_chunk_size;
- array_chunk = chunk_plus_offset(p, contents_size);
- array_chunk_size = remainder_size - contents_size;
- marray = (void**) (chunk2mem(array_chunk));
- set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size);
- remainder_size = contents_size;
- }
-
- /* split out elements */
- for (i = 0; ; ++i) {
- marray[i] = chunk2mem(p);
- if (i != n_elements-1) {
- if (element_size != 0)
- size = element_size;
- else
- size = request2size(sizes[i]);
- remainder_size -= size;
- set_size_and_pinuse_of_inuse_chunk(m, p, size);
- p = chunk_plus_offset(p, size);
- }
- else { /* the final element absorbs any overallocation slop */
- set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size);
- break;
- }
- }
-
-#if DEBUG
- if (marray != chunks) {
- /* final element must have exactly exhausted chunk */
- if (element_size != 0) {
- assert(remainder_size == element_size);
- }
- else {
- assert(remainder_size == request2size(sizes[i]));
- }
- check_inuse_chunk(m, mem2chunk(marray));
- }
- for (i = 0; i != n_elements; ++i)
- check_inuse_chunk(m, mem2chunk(marray[i]));
-
-#endif /* DEBUG */
-
- POSTACTION(m);
- return marray;
-}
-
-
-/* -------------------------- public routines ---------------------------- */
-
-#if !ONLY_MSPACES
-
-void* dlmalloc(size_t bytes) {
- /*
- Basic algorithm:
- If a small request (< 256 bytes minus per-chunk overhead):
- 1. If one exists, use a remainderless chunk in associated smallbin.
- (Remainderless means that there are too few excess bytes to
- represent as a chunk.)
- 2. If it is big enough, use the dv chunk, which is normally the
- chunk adjacent to the one used for the most recent small request.
- 3. If one exists, split the smallest available chunk in a bin,
- saving remainder in dv.
- 4. If it is big enough, use the top chunk.
- 5. If available, get memory from system and use it
- Otherwise, for a large request:
- 1. Find the smallest available binned chunk that fits, and use it
- if it is better fitting than dv chunk, splitting if necessary.
- 2. If better fitting than any binned chunk, use the dv chunk.
- 3. If it is big enough, use the top chunk.
- 4. If request size >= mmap threshold, try to directly mmap this chunk.
- 5. If available, get memory from system and use it
-
- The ugly goto's here ensure that postaction occurs along all paths.
- */
-
-#if USE_LOCKS
- ensure_initialization(); /* initialize in sys_alloc if not using locks */
-#endif
-
- if (!PREACTION(gm)) {
- void* mem;
- size_t nb;
- if (bytes <= MAX_SMALL_REQUEST) {
- bindex_t idx;
- binmap_t smallbits;
- nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);
- idx = small_index(nb);
- smallbits = gm->smallmap >> idx;
-
- if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */
- mchunkptr b, p;
- idx += ~smallbits & 1; /* Uses next bin if idx empty */
- b = smallbin_at(gm, idx);
- p = b->fd;
- assert(chunksize(p) == small_index2size(idx));
- unlink_first_small_chunk(gm, b, p, idx);
- set_inuse_and_pinuse(gm, p, small_index2size(idx));
- mem = chunk2mem(p);
- check_malloced_chunk(gm, mem, nb);
- goto postaction;
- }
-
- else if (nb > gm->dvsize) {
- if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
- mchunkptr b, p, r;
- size_t rsize;
- bindex_t i;
- binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));
- binmap_t leastbit = least_bit(leftbits);
- compute_bit2idx(leastbit, i);
- b = smallbin_at(gm, i);
- p = b->fd;
- assert(chunksize(p) == small_index2size(i));
- unlink_first_small_chunk(gm, b, p, i);
- rsize = small_index2size(i) - nb;
- /* Fit here cannot be remainderless if 4byte sizes */
- if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
- set_inuse_and_pinuse(gm, p, small_index2size(i));
- else {
- set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
- r = chunk_plus_offset(p, nb);
- set_size_and_pinuse_of_free_chunk(r, rsize);
- replace_dv(gm, r, rsize);
- }
- mem = chunk2mem(p);
- check_malloced_chunk(gm, mem, nb);
- goto postaction;
- }
-
- else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) {
- check_malloced_chunk(gm, mem, nb);
- goto postaction;
- }
- }
- }
- else if (bytes >= MAX_REQUEST)
- nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
- else {
- nb = pad_request(bytes);
- if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) {
- check_malloced_chunk(gm, mem, nb);
- goto postaction;
- }
- }
-
- if (nb <= gm->dvsize) {
- size_t rsize = gm->dvsize - nb;
- mchunkptr p = gm->dv;
- if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
- mchunkptr r = gm->dv = chunk_plus_offset(p, nb);
- gm->dvsize = rsize;
- set_size_and_pinuse_of_free_chunk(r, rsize);
- set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
- }
- else { /* exhaust dv */
- size_t dvs = gm->dvsize;
- gm->dvsize = 0;
- gm->dv = 0;
- set_inuse_and_pinuse(gm, p, dvs);
- }
- mem = chunk2mem(p);
- check_malloced_chunk(gm, mem, nb);
- goto postaction;
- }
-
- else if (nb < gm->topsize) { /* Split top */
- size_t rsize = gm->topsize -= nb;
- mchunkptr p = gm->top;
- mchunkptr r = gm->top = chunk_plus_offset(p, nb);
- r->head = rsize | PINUSE_BIT;
- set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
- mem = chunk2mem(p);
- check_top_chunk(gm, gm->top);
- check_malloced_chunk(gm, mem, nb);
- goto postaction;
- }
-
- mem = sys_alloc(gm, nb);
-
- postaction:
- POSTACTION(gm);
- return mem;
- }
-
- return 0;
-}
-
-void dlfree(void* mem) {
- /*
- Consolidate freed chunks with preceeding or succeeding bordering
- free chunks, if they exist, and then place in a bin. Intermixed
- with special cases for top, dv, mmapped chunks, and usage errors.
- */
-
- if (mem != 0) {
- mchunkptr p = mem2chunk(mem);
-#if FOOTERS
- mstate fm = get_mstate_for(p);
- if (!ok_magic(fm)) {
- USAGE_ERROR_ACTION(fm, p);
- return;
- }
-#else /* FOOTERS */
-#define fm gm
-#endif /* FOOTERS */
- if (!PREACTION(fm)) {
- check_inuse_chunk(fm, p);
- if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) {
- size_t psize = chunksize(p);
- mchunkptr next = chunk_plus_offset(p, psize);
- if (!pinuse(p)) {
- size_t prevsize = p->prev_foot;
- if (is_mmapped(p)) {
- psize += prevsize + MMAP_FOOT_PAD;
- if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)
- fm->footprint -= psize;
- goto postaction;
- }
- else {
- mchunkptr prev = chunk_minus_offset(p, prevsize);
- psize += prevsize;
- p = prev;
- if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */
- if (p != fm->dv) {
- unlink_chunk(fm, p, prevsize);
- }
- else if ((next->head & INUSE_BITS) == INUSE_BITS) {
- fm->dvsize = psize;
- set_free_with_pinuse(p, psize, next);
- goto postaction;
- }
- }
- else
- goto erroraction;
- }
- }
-
- if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {
- if (!cinuse(next)) { /* consolidate forward */
- if (next == fm->top) {
- size_t tsize = fm->topsize += psize;
- fm->top = p;
- p->head = tsize | PINUSE_BIT;
- if (p == fm->dv) {
- fm->dv = 0;
- fm->dvsize = 0;
- }
- if (should_trim(fm, tsize))
- sys_trim(fm, 0);
- goto postaction;
- }
- else if (next == fm->dv) {
- size_t dsize = fm->dvsize += psize;
- fm->dv = p;
- set_size_and_pinuse_of_free_chunk(p, dsize);
- goto postaction;
- }
- else {
- size_t nsize = chunksize(next);
- psize += nsize;
- unlink_chunk(fm, next, nsize);
- set_size_and_pinuse_of_free_chunk(p, psize);
- if (p == fm->dv) {
- fm->dvsize = psize;
- goto postaction;
- }
- }
- }
- else
- set_free_with_pinuse(p, psize, next);
-
- if (is_small(psize)) {
- insert_small_chunk(fm, p, psize);
- check_free_chunk(fm, p);
- }
- else {
- tchunkptr tp = (tchunkptr)p;
- insert_large_chunk(fm, tp, psize);
- check_free_chunk(fm, p);
- if (--fm->release_checks == 0)
- release_unused_segments(fm);
- }
- goto postaction;
- }
- }
- erroraction:
- USAGE_ERROR_ACTION(fm, p);
- postaction:
- POSTACTION(fm);
- }
- }
-#if !FOOTERS
-#undef fm
-#endif /* FOOTERS */
-}
-
-void* dlcalloc(size_t n_elements, size_t elem_size) {
- void* mem;
- size_t req = 0;
- if (n_elements != 0) {
- req = n_elements * elem_size;
- if (((n_elements | elem_size) & ~(size_t)0xffff) &&
- (req / n_elements != elem_size))
- req = MAX_SIZE_T; /* force downstream failure on overflow */
- }
- mem = dlmalloc(req);
- if (mem != 0 && calloc_must_clear(mem2chunk(mem)))
- memset(mem, 0, req);
- return mem;
-}
-
-void* dlrealloc(void* oldmem, size_t bytes) {
- if (oldmem == 0)
- return dlmalloc(bytes);
-#ifdef REALLOC_ZERO_BYTES_FREES
- if (bytes == 0) {
- dlfree(oldmem);
- return 0;
- }
-#endif /* REALLOC_ZERO_BYTES_FREES */
- else {
-#if ! FOOTERS
- mstate m = gm;
-#else /* FOOTERS */
- mstate m = get_mstate_for(mem2chunk(oldmem));
- if (!ok_magic(m)) {
- USAGE_ERROR_ACTION(m, oldmem);
- return 0;
- }
-#endif /* FOOTERS */
- return internal_realloc(m, oldmem, bytes);
- }
-}
-
-void* dlmemalign(size_t alignment, size_t bytes) {
- return internal_memalign(gm, alignment, bytes);
-}
-
-void** dlindependent_calloc(size_t n_elements, size_t elem_size,
- void* chunks[]) {
- size_t sz = elem_size; /* serves as 1-element array */
- return ialloc(gm, n_elements, &sz, 3, chunks);
-}
-
-void** dlindependent_comalloc(size_t n_elements, size_t sizes[],
- void* chunks[]) {
- return ialloc(gm, n_elements, sizes, 0, chunks);
-}
-
-void* dlvalloc(size_t bytes) {
- size_t pagesz;
- ensure_initialization();
- pagesz = mparams.page_size;
- return dlmemalign(pagesz, bytes);
-}
-
-void* dlpvalloc(size_t bytes) {
- size_t pagesz;
- ensure_initialization();
- pagesz = mparams.page_size;
- return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE));
-}
-
-int dlmalloc_trim(size_t pad) {
- int result = 0;
- ensure_initialization();
- if (!PREACTION(gm)) {
- result = sys_trim(gm, pad);
- POSTACTION(gm);
- }
- return result;
-}
-
-size_t dlmalloc_footprint(void) {
- return gm->footprint;
-}
-
-size_t dlmalloc_max_footprint(void) {
- return gm->max_footprint;
-}
-
-#if !NO_MALLINFO
-struct mallinfo dlmallinfo(void) {
- return internal_mallinfo(gm);
-}
-#endif /* NO_MALLINFO */
-
-void dlmalloc_stats() {
- internal_malloc_stats(gm);
-}
-
-int dlmallopt(int param_number, int value) {
- return change_mparam(param_number, value);
-}
-
-#endif /* !ONLY_MSPACES */
-
-size_t dlmalloc_usable_size(void* mem) {
- if (mem != 0) {
- mchunkptr p = mem2chunk(mem);
- if (is_inuse(p))
- return chunksize(p) - overhead_for(p);
- }
- return 0;
-}
-
-/* ----------------------------- user mspaces ---------------------------- */
-
-#if MSPACES
-
-static mstate init_user_mstate(char* tbase, size_t tsize) {
- size_t msize = pad_request(sizeof(struct malloc_state));
- mchunkptr mn;
- mchunkptr msp = align_as_chunk(tbase);
- mstate m = (mstate)(chunk2mem(msp));
- memset(m, 0, msize);
- INITIAL_LOCK(&m->mutex);
- msp->head = (msize|INUSE_BITS);
- m->seg.base = m->least_addr = tbase;
- m->seg.size = m->footprint = m->max_footprint = tsize;
- m->magic = mparams.magic;
- m->release_checks = MAX_RELEASE_CHECK_RATE;
- m->mflags = mparams.default_mflags;
- m->extp = 0;
- m->exts = 0;
- disable_contiguous(m);
- init_bins(m);
- mn = next_chunk(mem2chunk(m));
- init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE);
- check_top_chunk(m, m->top);
- return m;
-}
-
-mspace create_mspace(size_t capacity, int locked) {
- mstate m = 0;
- size_t msize;
- ensure_initialization();
- msize = pad_request(sizeof(struct malloc_state));
- if (capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {
- size_t rs = ((capacity == 0)? mparams.granularity :
- (capacity + TOP_FOOT_SIZE + msize));
- size_t tsize = granularity_align(rs);
- char* tbase = (char*)(CALL_MMAP(tsize));
- if (tbase != CMFAIL) {
- m = init_user_mstate(tbase, tsize);
- m->seg.sflags = USE_MMAP_BIT;
- set_lock(m, locked);
- }
- }
- return (mspace)m;
-}
-
-mspace create_mspace_with_base(void* base, size_t capacity, int locked) {
- mstate m = 0;
- size_t msize;
- ensure_initialization();
- msize = pad_request(sizeof(struct malloc_state));
- if (capacity > msize + TOP_FOOT_SIZE &&
- capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {
- m = init_user_mstate((char*)base, capacity);
- m->seg.sflags = EXTERN_BIT;
- set_lock(m, locked);
- }
- return (mspace)m;
-}
-
-int mspace_track_large_chunks(mspace msp, int enable) {
- int ret = 0;
- mstate ms = (mstate)msp;
- if (!PREACTION(ms)) {
- if (!use_mmap(ms))
- ret = 1;
- if (!enable)
- enable_mmap(ms);
- else
- disable_mmap(ms);
- POSTACTION(ms);
- }
- return ret;
-}
-
-size_t destroy_mspace(mspace msp) {
- size_t freed = 0;
- mstate ms = (mstate)msp;
- if (ok_magic(ms)) {
- msegmentptr sp = &ms->seg;
- while (sp != 0) {
- char* base = sp->base;
- size_t size = sp->size;
- flag_t flag = sp->sflags;
- sp = sp->next;
- if ((flag & USE_MMAP_BIT) && !(flag & EXTERN_BIT) &&
- CALL_MUNMAP(base, size) == 0)
- freed += size;
- }
- }
- else {
- USAGE_ERROR_ACTION(ms,ms);
- }
- return freed;
-}
-
-/*
- mspace versions of routines are near-clones of the global
- versions. This is not so nice but better than the alternatives.
-*/
-
-
-void* mspace_malloc(mspace msp, size_t bytes) {
- mstate ms = (mstate)msp;
- if (!ok_magic(ms)) {
- USAGE_ERROR_ACTION(ms,ms);
- return 0;
- }
- if (!PREACTION(ms)) {
- void* mem;
- size_t nb;
- if (bytes <= MAX_SMALL_REQUEST) {
- bindex_t idx;
- binmap_t smallbits;
- nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);
- idx = small_index(nb);
- smallbits = ms->smallmap >> idx;
-
- if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */
- mchunkptr b, p;
- idx += ~smallbits & 1; /* Uses next bin if idx empty */
- b = smallbin_at(ms, idx);
- p = b->fd;
- assert(chunksize(p) == small_index2size(idx));
- unlink_first_small_chunk(ms, b, p, idx);
- set_inuse_and_pinuse(ms, p, small_index2size(idx));
- mem = chunk2mem(p);
- check_malloced_chunk(ms, mem, nb);
- goto postaction;
- }
-
- else if (nb > ms->dvsize) {
- if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
- mchunkptr b, p, r;
- size_t rsize;
- bindex_t i;
- binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));
- binmap_t leastbit = least_bit(leftbits);
- compute_bit2idx(leastbit, i);
- b = smallbin_at(ms, i);
- p = b->fd;
- assert(chunksize(p) == small_index2size(i));
- unlink_first_small_chunk(ms, b, p, i);
- rsize = small_index2size(i) - nb;
- /* Fit here cannot be remainderless if 4byte sizes */
- if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
- set_inuse_and_pinuse(ms, p, small_index2size(i));
- else {
- set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
- r = chunk_plus_offset(p, nb);
- set_size_and_pinuse_of_free_chunk(r, rsize);
- replace_dv(ms, r, rsize);
- }
- mem = chunk2mem(p);
- check_malloced_chunk(ms, mem, nb);
- goto postaction;
- }
-
- else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) {
- check_malloced_chunk(ms, mem, nb);
- goto postaction;
- }
- }
- }
- else if (bytes >= MAX_REQUEST)
- nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
- else {
- nb = pad_request(bytes);
- if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) {
- check_malloced_chunk(ms, mem, nb);
- goto postaction;
- }
- }
-
- if (nb <= ms->dvsize) {
- size_t rsize = ms->dvsize - nb;
- mchunkptr p = ms->dv;
- if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
- mchunkptr r = ms->dv = chunk_plus_offset(p, nb);
- ms->dvsize = rsize;
- set_size_and_pinuse_of_free_chunk(r, rsize);
- set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
- }
- else { /* exhaust dv */
- size_t dvs = ms->dvsize;
- ms->dvsize = 0;
- ms->dv = 0;
- set_inuse_and_pinuse(ms, p, dvs);
- }
- mem = chunk2mem(p);
- check_malloced_chunk(ms, mem, nb);
- goto postaction;
- }
-
- else if (nb < ms->topsize) { /* Split top */
- size_t rsize = ms->topsize -= nb;
- mchunkptr p = ms->top;
- mchunkptr r = ms->top = chunk_plus_offset(p, nb);
- r->head = rsize | PINUSE_BIT;
- set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
- mem = chunk2mem(p);
- check_top_chunk(ms, ms->top);
- check_malloced_chunk(ms, mem, nb);
- goto postaction;
- }
-
- mem = sys_alloc(ms, nb);
-
- postaction:
- POSTACTION(ms);
- return mem;
- }
-
- return 0;
-}
-
-void mspace_free(mspace msp, void* mem) {
- if (mem != 0) {
- mchunkptr p = mem2chunk(mem);
-#if FOOTERS
- mstate fm = get_mstate_for(p);
- msp = msp; /* placate people compiling -Wunused */
-#else /* FOOTERS */
- mstate fm = (mstate)msp;
-#endif /* FOOTERS */
- if (!ok_magic(fm)) {
- USAGE_ERROR_ACTION(fm, p);
- return;
- }
- if (!PREACTION(fm)) {
- check_inuse_chunk(fm, p);
- if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) {
- size_t psize = chunksize(p);
- mchunkptr next = chunk_plus_offset(p, psize);
- if (!pinuse(p)) {
- size_t prevsize = p->prev_foot;
- if (is_mmapped(p)) {
- psize += prevsize + MMAP_FOOT_PAD;
- if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)
- fm->footprint -= psize;
- goto postaction;
- }
- else {
- mchunkptr prev = chunk_minus_offset(p, prevsize);
- psize += prevsize;
- p = prev;
- if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */
- if (p != fm->dv) {
- unlink_chunk(fm, p, prevsize);
- }
- else if ((next->head & INUSE_BITS) == INUSE_BITS) {
- fm->dvsize = psize;
- set_free_with_pinuse(p, psize, next);
- goto postaction;
- }
- }
- else
- goto erroraction;
- }
- }
-
- if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {
- if (!cinuse(next)) { /* consolidate forward */
- if (next == fm->top) {
- size_t tsize = fm->topsize += psize;
- fm->top = p;
- p->head = tsize | PINUSE_BIT;
- if (p == fm->dv) {
- fm->dv = 0;
- fm->dvsize = 0;
- }
- if (should_trim(fm, tsize))
- sys_trim(fm, 0);
- goto postaction;
- }
- else if (next == fm->dv) {
- size_t dsize = fm->dvsize += psize;
- fm->dv = p;
- set_size_and_pinuse_of_free_chunk(p, dsize);
- goto postaction;
- }
- else {
- size_t nsize = chunksize(next);
- psize += nsize;
- unlink_chunk(fm, next, nsize);
- set_size_and_pinuse_of_free_chunk(p, psize);
- if (p == fm->dv) {
- fm->dvsize = psize;
- goto postaction;
- }
- }
- }
- else
- set_free_with_pinuse(p, psize, next);
-
- if (is_small(psize)) {
- insert_small_chunk(fm, p, psize);
- check_free_chunk(fm, p);
- }
- else {
- tchunkptr tp = (tchunkptr)p;
- insert_large_chunk(fm, tp, psize);
- check_free_chunk(fm, p);
- if (--fm->release_checks == 0)
- release_unused_segments(fm);
- }
- goto postaction;
- }
- }
- erroraction:
- USAGE_ERROR_ACTION(fm, p);
- postaction:
- POSTACTION(fm);
- }
- }
-}
-
-void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) {
- void* mem;
- size_t req = 0;
- mstate ms = (mstate)msp;
- if (!ok_magic(ms)) {
- USAGE_ERROR_ACTION(ms,ms);
- return 0;
- }
- if (n_elements != 0) {
- req = n_elements * elem_size;
- if (((n_elements | elem_size) & ~(size_t)0xffff) &&
- (req / n_elements != elem_size))
- req = MAX_SIZE_T; /* force downstream failure on overflow */
- }
- mem = internal_malloc(ms, req);
- if (mem != 0 && calloc_must_clear(mem2chunk(mem)))
- memset(mem, 0, req);
- return mem;
-}
-
-void* mspace_realloc(mspace msp, void* oldmem, size_t bytes) {
- if (oldmem == 0)
- return mspace_malloc(msp, bytes);
-#ifdef REALLOC_ZERO_BYTES_FREES
- if (bytes == 0) {
- mspace_free(msp, oldmem);
- return 0;
- }
-#endif /* REALLOC_ZERO_BYTES_FREES */
- else {
-#if FOOTERS
- mchunkptr p = mem2chunk(oldmem);
- mstate ms = get_mstate_for(p);
-#else /* FOOTERS */
- mstate ms = (mstate)msp;
-#endif /* FOOTERS */
- if (!ok_magic(ms)) {
- USAGE_ERROR_ACTION(ms,ms);
- return 0;
- }
- return internal_realloc(ms, oldmem, bytes);
- }
-}
-
-void* mspace_memalign(mspace msp, size_t alignment, size_t bytes) {
- mstate ms = (mstate)msp;
- if (!ok_magic(ms)) {
- USAGE_ERROR_ACTION(ms,ms);
- return 0;
- }
- return internal_memalign(ms, alignment, bytes);
-}
-
-void** mspace_independent_calloc(mspace msp, size_t n_elements,
- size_t elem_size, void* chunks[]) {
- size_t sz = elem_size; /* serves as 1-element array */
- mstate ms = (mstate)msp;
- if (!ok_magic(ms)) {
- USAGE_ERROR_ACTION(ms,ms);
- return 0;
- }
- return ialloc(ms, n_elements, &sz, 3, chunks);
-}
-
-void** mspace_independent_comalloc(mspace msp, size_t n_elements,
- size_t sizes[], void* chunks[]) {
- mstate ms = (mstate)msp;
- if (!ok_magic(ms)) {
- USAGE_ERROR_ACTION(ms,ms);
- return 0;
- }
- return ialloc(ms, n_elements, sizes, 0, chunks);
-}
-
-int mspace_trim(mspace msp, size_t pad) {
- int result = 0;
- mstate ms = (mstate)msp;
- if (ok_magic(ms)) {
- if (!PREACTION(ms)) {
- result = sys_trim(ms, pad);
- POSTACTION(ms);
- }
- }
- else {
- USAGE_ERROR_ACTION(ms,ms);
- }
- return result;
-}
-
-void mspace_malloc_stats(mspace msp) {
- mstate ms = (mstate)msp;
- if (ok_magic(ms)) {
- internal_malloc_stats(ms);
- }
- else {
- USAGE_ERROR_ACTION(ms,ms);
- }
-}
-
-size_t mspace_footprint(mspace msp) {
- size_t result = 0;
- mstate ms = (mstate)msp;
- if (ok_magic(ms)) {
- result = ms->footprint;
- }
- else {
- USAGE_ERROR_ACTION(ms,ms);
- }
- return result;
-}
-
-
-size_t mspace_max_footprint(mspace msp) {
- size_t result = 0;
- mstate ms = (mstate)msp;
- if (ok_magic(ms)) {
- result = ms->max_footprint;
- }
- else {
- USAGE_ERROR_ACTION(ms,ms);
- }
- return result;
-}
-
-
-#if !NO_MALLINFO
-struct mallinfo mspace_mallinfo(mspace msp) {
- mstate ms = (mstate)msp;
- if (!ok_magic(ms)) {
- USAGE_ERROR_ACTION(ms,ms);
- }
- return internal_mallinfo(ms);
-}
-#endif /* NO_MALLINFO */
-
-size_t mspace_usable_size(void* mem) {
- if (mem != 0) {
- mchunkptr p = mem2chunk(mem);
- if (is_inuse(p))
- return chunksize(p) - overhead_for(p);
- }
- return 0;
-}
-
-int mspace_mallopt(int param_number, int value) {
- return change_mparam(param_number, value);
-}
-
-#endif /* MSPACES */
-
-
-/* -------------------- Alternative MORECORE functions ------------------- */
-
-/*
- Guidelines for creating a custom version of MORECORE:
-
- * For best performance, MORECORE should allocate in multiples of pagesize.
- * MORECORE may allocate more memory than requested. (Or even less,
- but this will usually result in a malloc failure.)
- * MORECORE must not allocate memory when given argument zero, but
- instead return one past the end address of memory from previous
- nonzero call.
- * For best performance, consecutive calls to MORECORE with positive
- arguments should return increasing addresses, indicating that
- space has been contiguously extended.
- * Even though consecutive calls to MORECORE need not return contiguous
- addresses, it must be OK for malloc'ed chunks to span multiple
- regions in those cases where they do happen to be contiguous.
- * MORECORE need not handle negative arguments -- it may instead
- just return MFAIL when given negative arguments.
- Negative arguments are always multiples of pagesize. MORECORE
- must not misinterpret negative args as large positive unsigned
- args. You can suppress all such calls from even occurring by defining
- MORECORE_CANNOT_TRIM,
-
- As an example alternative MORECORE, here is a custom allocator
- kindly contributed for pre-OSX macOS. It uses virtually but not
- necessarily physically contiguous non-paged memory (locked in,
- present and won't get swapped out). You can use it by uncommenting
- this section, adding some #includes, and setting up the appropriate
- defines above:
-
- #define MORECORE osMoreCore
-
- There is also a shutdown routine that should somehow be called for
- cleanup upon program exit.
-
- #define MAX_POOL_ENTRIES 100
- #define MINIMUM_MORECORE_SIZE (64 * 1024U)
- static int next_os_pool;
- void *our_os_pools[MAX_POOL_ENTRIES];
-
- void *osMoreCore(int size)
- {
- void *ptr = 0;
- static void *sbrk_top = 0;
-
- if (size > 0)
- {
- if (size < MINIMUM_MORECORE_SIZE)
- size = MINIMUM_MORECORE_SIZE;
- if (CurrentExecutionLevel() == kTaskLevel)
- ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0);
- if (ptr == 0)
- {
- return (void *) MFAIL;
- }
- // save ptrs so they can be freed during cleanup
- our_os_pools[next_os_pool] = ptr;
- next_os_pool++;
- ptr = (void *) ((((size_t) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK);
- sbrk_top = (char *) ptr + size;
- return ptr;
- }
- else if (size < 0)
- {
- // we don't currently support shrink behavior
- return (void *) MFAIL;
- }
- else
- {
- return sbrk_top;
- }
- }
-
- // cleanup any allocated memory pools
- // called as last thing before shutting down driver
-
- void osCleanupMem(void)
- {
- void **ptr;
-
- for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++)
- if (*ptr)
- {
- PoolDeallocate(*ptr);
- *ptr = 0;
- }
- }
-
-*/
-
-
-/* -----------------------------------------------------------------------
-History:
- V2.8.4 Wed May 27 09:56:23 2009 Doug Lea (dl at gee)
- * Use zeros instead of prev foot for is_mmapped
- * Add mspace_track_large_chunks; thanks to Jean Brouwers
- * Fix set_inuse in internal_realloc; thanks to Jean Brouwers
- * Fix insufficient sys_alloc padding when using 16byte alignment
- * Fix bad error check in mspace_footprint
- * Adaptations for ptmalloc; thanks to Wolfram Gloger.
- * Reentrant spin locks; thanks to Earl Chew and others
- * Win32 improvements; thanks to Niall Douglas and Earl Chew
- * Add NO_SEGMENT_TRAVERSAL and MAX_RELEASE_CHECK_RATE options
- * Extension hook in malloc_state
- * Various small adjustments to reduce warnings on some compilers
- * Various configuration extensions/changes for more platforms. Thanks
- to all who contributed these.
-
- V2.8.3 Thu Sep 22 11:16:32 2005 Doug Lea (dl at gee)
- * Add max_footprint functions
- * Ensure all appropriate literals are size_t
- * Fix conditional compilation problem for some #define settings
- * Avoid concatenating segments with the one provided
- in create_mspace_with_base
- * Rename some variables to avoid compiler shadowing warnings
- * Use explicit lock initialization.
- * Better handling of sbrk interference.
- * Simplify and fix segment insertion, trimming and mspace_destroy
- * Reinstate REALLOC_ZERO_BYTES_FREES option from 2.7.x
- * Thanks especially to Dennis Flanagan for help on these.
-
- V2.8.2 Sun Jun 12 16:01:10 2005 Doug Lea (dl at gee)
- * Fix memalign brace error.
-
- V2.8.1 Wed Jun 8 16:11:46 2005 Doug Lea (dl at gee)
- * Fix improper #endif nesting in C++
- * Add explicit casts needed for C++
-
- V2.8.0 Mon May 30 14:09:02 2005 Doug Lea (dl at gee)
- * Use trees for large bins
- * Support mspaces
- * Use segments to unify sbrk-based and mmap-based system allocation,
- removing need for emulation on most platforms without sbrk.
- * Default safety checks
- * Optional footer checks. Thanks to William Robertson for the idea.
- * Internal code refactoring
- * Incorporate suggestions and platform-specific changes.
- Thanks to Dennis Flanagan, Colin Plumb, Niall Douglas,
- Aaron Bachmann, Emery Berger, and others.
- * Speed up non-fastbin processing enough to remove fastbins.
- * Remove useless cfree() to avoid conflicts with other apps.
- * Remove internal memcpy, memset. Compilers handle builtins better.
- * Remove some options that no one ever used and rename others.
-
- V2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee)
- * Fix malloc_state bitmap array misdeclaration
-
- V2.7.1 Thu Jul 25 10:58:03 2002 Doug Lea (dl at gee)
- * Allow tuning of FIRST_SORTED_BIN_SIZE
- * Use PTR_UINT as type for all ptr->int casts. Thanks to John Belmonte.
- * Better detection and support for non-contiguousness of MORECORE.
- Thanks to Andreas Mueller, Conal Walsh, and Wolfram Gloger
- * Bypass most of malloc if no frees. Thanks To Emery Berger.
- * Fix freeing of old top non-contiguous chunk im sysmalloc.
- * Raised default trim and map thresholds to 256K.
- * Fix mmap-related #defines. Thanks to Lubos Lunak.
- * Fix copy macros; added LACKS_FCNTL_H. Thanks to Neal Walfield.
- * Branch-free bin calculation
- * Default trim and mmap thresholds now 256K.
-
- V2.7.0 Sun Mar 11 14:14:06 2001 Doug Lea (dl at gee)
- * Introduce independent_comalloc and independent_calloc.
- Thanks to Michael Pachos for motivation and help.
- * Make optional .h file available
- * Allow > 2GB requests on 32bit systems.
- * new WIN32 sbrk, mmap, munmap, lock code from <Walter@GeNeSys-e.de>.
- Thanks also to Andreas Mueller <a.mueller at paradatec.de>,
- and Anonymous.
- * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for
- helping test this.)
- * memalign: check alignment arg
- * realloc: don't try to shift chunks backwards, since this
- leads to more fragmentation in some programs and doesn't
- seem to help in any others.
- * Collect all cases in malloc requiring system memory into sysmalloc
- * Use mmap as backup to sbrk
- * Place all internal state in malloc_state
- * Introduce fastbins (although similar to 2.5.1)
- * Many minor tunings and cosmetic improvements
- * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK
- * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS
- Thanks to Tony E. Bennett <tbennett@nvidia.com> and others.
- * Include errno.h to support default failure action.
-
- V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee)
- * return null for negative arguments
- * Added Several WIN32 cleanups from Martin C. Fong <mcfong at yahoo.com>
- * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h'
- (e.g. WIN32 platforms)
- * Cleanup header file inclusion for WIN32 platforms
- * Cleanup code to avoid Microsoft Visual C++ compiler complaints
- * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing
- memory allocation routines
- * Set 'malloc_getpagesize' for WIN32 platforms (needs more work)
- * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to
- usage of 'assert' in non-WIN32 code
- * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to
- avoid infinite loop
- * Always call 'fREe()' rather than 'free()'
-
- V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee)
- * Fixed ordering problem with boundary-stamping
-
- V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee)
- * Added pvalloc, as recommended by H.J. Liu
- * Added 64bit pointer support mainly from Wolfram Gloger
- * Added anonymously donated WIN32 sbrk emulation
- * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen
- * malloc_extend_top: fix mask error that caused wastage after
- foreign sbrks
- * Add linux mremap support code from HJ Liu
-
- V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee)
- * Integrated most documentation with the code.
- * Add support for mmap, with help from
- Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
- * Use last_remainder in more cases.
- * Pack bins using idea from colin@nyx10.cs.du.edu
- * Use ordered bins instead of best-fit threshhold
- * Eliminate block-local decls to simplify tracing and debugging.
- * Support another case of realloc via move into top
- * Fix error occuring when initial sbrk_base not word-aligned.
- * Rely on page size for units instead of SBRK_UNIT to
- avoid surprises about sbrk alignment conventions.
- * Add mallinfo, mallopt. Thanks to Raymond Nijssen
- (raymond@es.ele.tue.nl) for the suggestion.
- * Add `pad' argument to malloc_trim and top_pad mallopt parameter.
- * More precautions for cases where other routines call sbrk,
- courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
- * Added macros etc., allowing use in linux libc from
- H.J. Lu (hjl@gnu.ai.mit.edu)
- * Inverted this history list
-
- V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee)
- * Re-tuned and fixed to behave more nicely with V2.6.0 changes.
- * Removed all preallocation code since under current scheme
- the work required to undo bad preallocations exceeds
- the work saved in good cases for most test programs.
- * No longer use return list or unconsolidated bins since
- no scheme using them consistently outperforms those that don't
- given above changes.
- * Use best fit for very large chunks to prevent some worst-cases.
- * Added some support for debugging
-
- V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee)
- * Removed footers when chunks are in use. Thanks to
- Paul Wilson (wilson@cs.texas.edu) for the suggestion.
-
- V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee)
- * Added malloc_trim, with help from Wolfram Gloger
- (wmglo@Dent.MED.Uni-Muenchen.DE).
-
- V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g)
-
- V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g)
- * realloc: try to expand in both directions
- * malloc: swap order of clean-bin strategy;
- * realloc: only conditionally expand backwards
- * Try not to scavenge used bins
- * Use bin counts as a guide to preallocation
- * Occasionally bin return list chunks in first scan
- * Add a few optimizations from colin@nyx10.cs.du.edu
-
- V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g)
- * faster bin computation & slightly different binning
- * merged all consolidations to one part of malloc proper
- (eliminating old malloc_find_space & malloc_clean_bin)
- * Scan 2 returns chunks (not just 1)
- * Propagate failure in realloc if malloc returns 0
- * Add stuff to allow compilation on non-ANSI compilers
- from kpv@research.att.com
-
- V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu)
- * removed potential for odd address access in prev_chunk
- * removed dependency on getpagesize.h
- * misc cosmetics and a bit more internal documentation
- * anticosmetics: mangled names in macros to evade debugger strangeness
- * tested on sparc, hp-700, dec-mips, rs6000
- with gcc & native cc (hp, dec only) allowing
- Detlefs & Zorn comparison study (in SIGPLAN Notices.)
-
- Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu)
- * Based loosely on libg++-1.2X malloc. (It retains some of the overall
- structure of old version, but most details differ.)
-
-*/
-
-#endif
+#ifdef NEDMALLOC_ENABLED
+/*
+ This is a version (aka dlmalloc) of malloc/free/realloc written by
+ Doug Lea and released to the public domain, as explained at
+ http://creativecommons.org/licenses/publicdomain. Send questions,
+ comments, complaints, performance data, etc to dl@cs.oswego.edu
+
+* Version 2.8.4 Wed May 27 09:56:23 2009 Doug Lea (dl at gee)
+
+ Note: There may be an updated version of this malloc obtainable at
+ ftp://gee.cs.oswego.edu/pub/misc/malloc.c
+ Check before installing!
+
+* Quickstart
+
+ This library is all in one file to simplify the most common usage:
+ ftp it, compile it (-O3), and link it into another program. All of
+ the compile-time options default to reasonable values for use on
+ most platforms. You might later want to step through various
+ compile-time and dynamic tuning options.
+
+ For convenience, an include file for code using this malloc is at:
+ ftp://gee.cs.oswego.edu/pub/misc/malloc-2.8.4.h
+ You don't really need this .h file unless you call functions not
+ defined in your system include files. The .h file contains only the
+ excerpts from this file needed for using this malloc on ANSI C/C++
+ systems, so long as you haven't changed compile-time options about
+ naming and tuning parameters. If you do, then you can create your
+ own malloc.h that does include all settings by cutting at the point
+ indicated below. Note that you may already by default be using a C
+ library containing a malloc that is based on some version of this
+ malloc (for example in linux). You might still want to use the one
+ in this file to customize settings or to avoid overheads associated
+ with library versions.
+
+* Vital statistics:
+
+ Supported pointer/size_t representation: 4 or 8 bytes
+ size_t MUST be an unsigned type of the same width as
+ pointers. (If you are using an ancient system that declares
+ size_t as a signed type, or need it to be a different width
+ than pointers, you can use a previous release of this malloc
+ (e.g. 2.7.2) supporting these.)
+
+ Alignment: 8 bytes (default)
+ This suffices for nearly all current machines and C compilers.
+ However, you can define MALLOC_ALIGNMENT to be wider than this
+ if necessary (up to 128bytes), at the expense of using more space.
+
+ Minimum overhead per allocated chunk: 4 or 8 bytes (if 4byte sizes)
+ 8 or 16 bytes (if 8byte sizes)
+ Each malloced chunk has a hidden word of overhead holding size
+ and status information, and additional cross-check word
+ if FOOTERS is defined.
+
+ Minimum allocated size: 4-byte ptrs: 16 bytes (including overhead)
+ 8-byte ptrs: 32 bytes (including overhead)
+
+ Even a request for zero bytes (i.e., malloc(0)) returns a
+ pointer to something of the minimum allocatable size.
+ The maximum overhead wastage (i.e., number of extra bytes
+ allocated than were requested in malloc) is less than or equal
+ to the minimum size, except for requests >= mmap_threshold that
+ are serviced via mmap(), where the worst case wastage is about
+ 32 bytes plus the remainder from a system page (the minimal
+ mmap unit); typically 4096 or 8192 bytes.
+
+ Security: static-safe; optionally more or less
+ The "security" of malloc refers to the ability of malicious
+ code to accentuate the effects of errors (for example, freeing
+ space that is not currently malloc'ed or overwriting past the
+ ends of chunks) in code that calls malloc. This malloc
+ guarantees not to modify any memory locations below the base of
+ heap, i.e., static variables, even in the presence of usage
+ errors. The routines additionally detect most improper frees
+ and reallocs. All this holds as long as the static bookkeeping
+ for malloc itself is not corrupted by some other means. This
+ is only one aspect of security -- these checks do not, and
+ cannot, detect all possible programming errors.
+
+ If FOOTERS is defined nonzero, then each allocated chunk
+ carries an additional check word to verify that it was malloced
+ from its space. These check words are the same within each
+ execution of a program using malloc, but differ across
+ executions, so externally crafted fake chunks cannot be
+ freed. This improves security by rejecting frees/reallocs that
+ could corrupt heap memory, in addition to the checks preventing
+ writes to statics that are always on. This may further improve
+ security at the expense of time and space overhead. (Note that
+ FOOTERS may also be worth using with MSPACES.)
+
+ By default detected errors cause the program to abort (calling
+ "abort()"). You can override this to instead proceed past
+ errors by defining PROCEED_ON_ERROR. In this case, a bad free
+ has no effect, and a malloc that encounters a bad address
+ caused by user overwrites will ignore the bad address by
+ dropping pointers and indices to all known memory. This may
+ be appropriate for programs that should continue if at all
+ possible in the face of programming errors, although they may
+ run out of memory because dropped memory is never reclaimed.
+
+ If you don't like either of these options, you can define
+ CORRUPTION_ERROR_ACTION and USAGE_ERROR_ACTION to do anything
+ else. And if if you are sure that your program using malloc has
+ no errors or vulnerabilities, you can define INSECURE to 1,
+ which might (or might not) provide a small performance improvement.
+
+ Thread-safety: NOT thread-safe unless USE_LOCKS defined
+ When USE_LOCKS is defined, each public call to malloc, free,
+ etc is surrounded with either a pthread mutex or a win32
+ spinlock (depending on WIN32). This is not especially fast, and
+ can be a major bottleneck. It is designed only to provide
+ minimal protection in concurrent environments, and to provide a
+ basis for extensions. If you are using malloc in a concurrent
+ program, consider instead using nedmalloc
+ (http://www.nedprod.com/programs/portable/nedmalloc/) or
+ ptmalloc (See http://www.malloc.de), which are derived
+ from versions of this malloc.
+
+ System requirements: Any combination of MORECORE and/or MMAP/MUNMAP
+ This malloc can use unix sbrk or any emulation (invoked using
+ the CALL_MORECORE macro) and/or mmap/munmap or any emulation
+ (invoked using CALL_MMAP/CALL_MUNMAP) to get and release system
+ memory. On most unix systems, it tends to work best if both
+ MORECORE and MMAP are enabled. On Win32, it uses emulations
+ based on VirtualAlloc. It also uses common C library functions
+ like memset.
+
+ Compliance: I believe it is compliant with the Single Unix Specification
+ (See http://www.unix.org). Also SVID/XPG, ANSI C, and probably
+ others as well.
+
+* Overview of algorithms
+
+ This is not the fastest, most space-conserving, most portable, or
+ most tunable malloc ever written. However it is among the fastest
+ while also being among the most space-conserving, portable and
+ tunable. Consistent balance across these factors results in a good
+ general-purpose allocator for malloc-intensive programs.
+
+ In most ways, this malloc is a best-fit allocator. Generally, it
+ chooses the best-fitting existing chunk for a request, with ties
+ broken in approximately least-recently-used order. (This strategy
+ normally maintains low fragmentation.) However, for requests less
+ than 256bytes, it deviates from best-fit when there is not an
+ exactly fitting available chunk by preferring to use space adjacent
+ to that used for the previous small request, as well as by breaking
+ ties in approximately most-recently-used order. (These enhance
+ locality of series of small allocations.) And for very large requests
+ (>= 256Kb by default), it relies on system memory mapping
+ facilities, if supported. (This helps avoid carrying around and
+ possibly fragmenting memory used only for large chunks.)
+
+ All operations (except malloc_stats and mallinfo) have execution
+ times that are bounded by a constant factor of the number of bits in
+ a size_t, not counting any clearing in calloc or copying in realloc,
+ or actions surrounding MORECORE and MMAP that have times
+ proportional to the number of non-contiguous regions returned by
+ system allocation routines, which is often just 1. In real-time
+ applications, you can optionally suppress segment traversals using
+ NO_SEGMENT_TRAVERSAL, which assures bounded execution even when
+ system allocators return non-contiguous spaces, at the typical
+ expense of carrying around more memory and increased fragmentation.
+
+ The implementation is not very modular and seriously overuses
+ macros. Perhaps someday all C compilers will do as good a job
+ inlining modular code as can now be done by brute-force expansion,
+ but now, enough of them seem not to.
+
+ Some compilers issue a lot of warnings about code that is
+ dead/unreachable only on some platforms, and also about intentional
+ uses of negation on unsigned types. All known cases of each can be
+ ignored.
+
+ For a longer but out of date high-level description, see
+ http://gee.cs.oswego.edu/dl/html/malloc.html
+
+* MSPACES
+ If MSPACES is defined, then in addition to malloc, free, etc.,
+ this file also defines mspace_malloc, mspace_free, etc. These
+ are versions of malloc routines that take an "mspace" argument
+ obtained using create_mspace, to control all internal bookkeeping.
+ If ONLY_MSPACES is defined, only these versions are compiled.
+ So if you would like to use this allocator for only some allocations,
+ and your system malloc for others, you can compile with
+ ONLY_MSPACES and then do something like...
+ static mspace mymspace = create_mspace(0,0); // for example
+ #define mymalloc(bytes) mspace_malloc(mymspace, bytes)
+
+ (Note: If you only need one instance of an mspace, you can instead
+ use "USE_DL_PREFIX" to relabel the global malloc.)
+
+ You can similarly create thread-local allocators by storing
+ mspaces as thread-locals. For example:
+ static __thread mspace tlms = 0;
+ void* tlmalloc(size_t bytes) {
+ if (tlms == 0) tlms = create_mspace(0, 0);
+ return mspace_malloc(tlms, bytes);
+ }
+ void tlfree(void* mem) { mspace_free(tlms, mem); }
+
+ Unless FOOTERS is defined, each mspace is completely independent.
+ You cannot allocate from one and free to another (although
+ conformance is only weakly checked, so usage errors are not always
+ caught). If FOOTERS is defined, then each chunk carries around a tag
+ indicating its originating mspace, and frees are directed to their
+ originating spaces.
+
+ ------------------------- Compile-time options ---------------------------
+
+Be careful in setting #define values for numerical constants of type
+size_t. On some systems, literal values are not automatically extended
+to size_t precision unless they are explicitly casted. You can also
+use the symbolic values MAX_SIZE_T, SIZE_T_ONE, etc below.
+
+WIN32 default: defined if _WIN32 defined
+ Defining WIN32 sets up defaults for MS environment and compilers.
+ Otherwise defaults are for unix. Beware that there seem to be some
+ cases where this malloc might not be a pure drop-in replacement for
+ Win32 malloc: Random-looking failures from Win32 GDI API's (eg;
+ SetDIBits()) may be due to bugs in some video driver implementations
+ when pixel buffers are malloc()ed, and the region spans more than
+ one VirtualAlloc()ed region. Because dlmalloc uses a small (64Kb)
+ default granularity, pixel buffers may straddle virtual allocation
+ regions more often than when using the Microsoft allocator. You can
+ avoid this by using VirtualAlloc() and VirtualFree() for all pixel
+ buffers rather than using malloc(). If this is not possible,
+ recompile this malloc with a larger DEFAULT_GRANULARITY.
+
+MALLOC_ALIGNMENT default: (size_t)8
+ Controls the minimum alignment for malloc'ed chunks. It must be a
+ power of two and at least 8, even on machines for which smaller
+ alignments would suffice. It may be defined as larger than this
+ though. Note however that code and data structures are optimized for
+ the case of 8-byte alignment.
+
+MSPACES default: 0 (false)
+ If true, compile in support for independent allocation spaces.
+ This is only supported if HAVE_MMAP is true.
+
+ONLY_MSPACES default: 0 (false)
+ If true, only compile in mspace versions, not regular versions.
+
+USE_LOCKS default: 0 (false)
+ Causes each call to each public routine to be surrounded with
+ pthread or WIN32 mutex lock/unlock. (If set true, this can be
+ overridden on a per-mspace basis for mspace versions.) If set to a
+ non-zero value other than 1, locks are used, but their
+ implementation is left out, so lock functions must be supplied manually,
+ as described below.
+
+USE_SPIN_LOCKS default: 1 iff USE_LOCKS and on x86 using gcc or MSC
+ If true, uses custom spin locks for locking. This is currently
+ supported only for x86 platforms using gcc or recent MS compilers.
+ Otherwise, posix locks or win32 critical sections are used.
+
+FOOTERS default: 0
+ If true, provide extra checking and dispatching by placing
+ information in the footers of allocated chunks. This adds
+ space and time overhead.
+
+INSECURE default: 0
+ If true, omit checks for usage errors and heap space overwrites.
+
+USE_DL_PREFIX default: NOT defined
+ Causes compiler to prefix all public routines with the string 'dl'.
+ This can be useful when you only want to use this malloc in one part
+ of a program, using your regular system malloc elsewhere.
+
+ABORT default: defined as abort()
+ Defines how to abort on failed checks. On most systems, a failed
+ check cannot die with an "assert" or even print an informative
+ message, because the underlying print routines in turn call malloc,
+ which will fail again. Generally, the best policy is to simply call
+ abort(). It's not very useful to do more than this because many
+ errors due to overwriting will show up as address faults (null, odd
+ addresses etc) rather than malloc-triggered checks, so will also
+ abort. Also, most compilers know that abort() does not return, so
+ can better optimize code conditionally calling it.
+
+PROCEED_ON_ERROR default: defined as 0 (false)
+ Controls whether detected bad addresses cause them to bypassed
+ rather than aborting. If set, detected bad arguments to free and
+ realloc are ignored. And all bookkeeping information is zeroed out
+ upon a detected overwrite of freed heap space, thus losing the
+ ability to ever return it from malloc again, but enabling the
+ application to proceed. If PROCEED_ON_ERROR is defined, the
+ static variable malloc_corruption_error_count is compiled in
+ and can be examined to see if errors have occurred. This option
+ generates slower code than the default abort policy.
+
+DEBUG default: NOT defined
+ The DEBUG setting is mainly intended for people trying to modify
+ this code or diagnose problems when porting to new platforms.
+ However, it may also be able to better isolate user errors than just
+ using runtime checks. The assertions in the check routines spell
+ out in more detail the assumptions and invariants underlying the
+ algorithms. The checking is fairly extensive, and will slow down
+ execution noticeably. Calling malloc_stats or mallinfo with DEBUG
+ set will attempt to check every non-mmapped allocated and free chunk
+ in the course of computing the summaries.
+
+ABORT_ON_ASSERT_FAILURE default: defined as 1 (true)
+ Debugging assertion failures can be nearly impossible if your
+ version of the assert macro causes malloc to be called, which will
+ lead to a cascade of further failures, blowing the runtime stack.
+ ABORT_ON_ASSERT_FAILURE cause assertions failures to call abort(),
+ which will usually make debugging easier.
+
+MALLOC_FAILURE_ACTION default: sets errno to ENOMEM, or no-op on win32
+ The action to take before "return 0" when malloc fails to be able to
+ return memory because there is none available.
+
+HAVE_MORECORE default: 1 (true) unless win32 or ONLY_MSPACES
+ True if this system supports sbrk or an emulation of it.
+
+MORECORE default: sbrk
+ The name of the sbrk-style system routine to call to obtain more
+ memory. See below for guidance on writing custom MORECORE
+ functions. The type of the argument to sbrk/MORECORE varies across
+ systems. It cannot be size_t, because it supports negative
+ arguments, so it is normally the signed type of the same width as
+ size_t (sometimes declared as "intptr_t"). It doesn't much matter
+ though. Internally, we only call it with arguments less than half
+ the max value of a size_t, which should work across all reasonable
+ possibilities, although sometimes generating compiler warnings.
+
+MORECORE_CONTIGUOUS default: 1 (true) if HAVE_MORECORE
+ If true, take advantage of fact that consecutive calls to MORECORE
+ with positive arguments always return contiguous increasing
+ addresses. This is true of unix sbrk. It does not hurt too much to
+ set it true anyway, since malloc copes with non-contiguities.
+ Setting it false when definitely non-contiguous saves time
+ and possibly wasted space it would take to discover this though.
+
+MORECORE_CANNOT_TRIM default: NOT defined
+ True if MORECORE cannot release space back to the system when given
+ negative arguments. This is generally necessary only if you are
+ using a hand-crafted MORECORE function that cannot handle negative
+ arguments.
+
+NO_SEGMENT_TRAVERSAL default: 0
+ If non-zero, suppresses traversals of memory segments
+ returned by either MORECORE or CALL_MMAP. This disables
+ merging of segments that are contiguous, and selectively
+ releasing them to the OS if unused, but bounds execution times.
+
+HAVE_MMAP default: 1 (true)
+ True if this system supports mmap or an emulation of it. If so, and
+ HAVE_MORECORE is not true, MMAP is used for all system
+ allocation. If set and HAVE_MORECORE is true as well, MMAP is
+ primarily used to directly allocate very large blocks. It is also
+ used as a backup strategy in cases where MORECORE fails to provide
+ space from system. Note: A single call to MUNMAP is assumed to be
+ able to unmap memory that may have be allocated using multiple calls
+ to MMAP, so long as they are adjacent.
+
+HAVE_MREMAP default: 1 on linux, else 0
+ If true realloc() uses mremap() to re-allocate large blocks and
+ extend or shrink allocation spaces.
+
+MMAP_CLEARS default: 1 except on WINCE.
+ True if mmap clears memory so calloc doesn't need to. This is true
+ for standard unix mmap using /dev/zero and on WIN32 except for WINCE.
+
+USE_BUILTIN_FFS default: 0 (i.e., not used)
+ Causes malloc to use the builtin ffs() function to compute indices.
+ Some compilers may recognize and intrinsify ffs to be faster than the
+ supplied C version. Also, the case of x86 using gcc is special-cased
+ to an asm instruction, so is already as fast as it can be, and so
+ this setting has no effect. Similarly for Win32 under recent MS compilers.
+ (On most x86s, the asm version is only slightly faster than the C version.)
+
+malloc_getpagesize default: derive from system includes, or 4096.
+ The system page size. To the extent possible, this malloc manages
+ memory from the system in page-size units. This may be (and
+ usually is) a function rather than a constant. This is ignored
+ if WIN32, where page size is determined using getSystemInfo during
+ initialization. This may be several megabytes if ENABLE_LARGE_PAGES
+ is enabled.
+
+ENABLE_LARGE_PAGES default: NOT defined
+ Causes the system page size to be the value of GetLargePageMinimum()
+ if that function is available (Windows Server 2003/Vista or later).
+ This allows the use of large page entries in the MMU which can
+ significantly improve performance in large working set applications
+ as TLB cache load is reduced by a factor of three. Note that enabling
+ this option is equal to locking the process' memory in current
+ implementations of Windows and requires the SE_LOCK_MEMORY_PRIVILEGE
+ to be held by the process in order to succeed.
+
+USE_DEV_RANDOM default: 0 (i.e., not used)
+ Causes malloc to use /dev/random to initialize secure magic seed for
+ stamping footers. Otherwise, the current time is used.
+
+NO_MALLINFO default: 0
+ If defined, don't compile "mallinfo". This can be a simple way
+ of dealing with mismatches between system declarations and
+ those in this file.
+
+MALLINFO_FIELD_TYPE default: size_t
+ The type of the fields in the mallinfo struct. This was originally
+ defined as "int" in SVID etc, but is more usefully defined as
+ size_t. The value is used only if HAVE_USR_INCLUDE_MALLOC_H is not set
+
+REALLOC_ZERO_BYTES_FREES default: not defined
+ This should be set if a call to realloc with zero bytes should
+ be the same as a call to free. Some people think it should. Otherwise,
+ since this malloc returns a unique pointer for malloc(0), so does
+ realloc(p, 0).
+
+LACKS_UNISTD_H, LACKS_FCNTL_H, LACKS_SYS_PARAM_H, LACKS_SYS_MMAN_H
+LACKS_STRINGS_H, LACKS_STRING_H, LACKS_SYS_TYPES_H, LACKS_ERRNO_H
+LACKS_STDLIB_H default: NOT defined unless on WIN32
+ Define these if your system does not have these header files.
+ You might need to manually insert some of the declarations they provide.
+
+DEFAULT_GRANULARITY default: page size if MORECORE_CONTIGUOUS,
+ system_info.dwAllocationGranularity in WIN32,
+ GetLargePageMinimum() if ENABLE_LARGE_PAGES,
+ otherwise 64K.
+ Also settable using mallopt(M_GRANULARITY, x)
+ The unit for allocating and deallocating memory from the system. On
+ most systems with contiguous MORECORE, there is no reason to
+ make this more than a page. However, systems with MMAP tend to
+ either require or encourage larger granularities. You can increase
+ this value to prevent system allocation functions to be called so
+ often, especially if they are slow. The value must be at least one
+ page and must be a power of two. Setting to 0 causes initialization
+ to either page size or win32 region size. (Note: In previous
+ versions of malloc, the equivalent of this option was called
+ "TOP_PAD")
+
+DEFAULT_GRANULARITY_ALIGNED default: undefined (which means page size)
+ Whether to enforce alignment when allocating and deallocating memory
+ from the system i.e. the base address of all allocations will be
+ aligned to DEFAULT_GRANULARITY if it is set. Note that enabling this carries
+ some overhead as multiple calls must now be made when probing for a valid
+ aligned value, however it does greatly ease the checking for whether
+ a given memory pointer was allocated by this allocator rather than
+ some other.
+
+DEFAULT_TRIM_THRESHOLD default: 2MB
+ Also settable using mallopt(M_TRIM_THRESHOLD, x)
+ The maximum amount of unused top-most memory to keep before
+ releasing via malloc_trim in free(). Automatic trimming is mainly
+ useful in long-lived programs using contiguous MORECORE. Because
+ trimming via sbrk can be slow on some systems, and can sometimes be
+ wasteful (in cases where programs immediately afterward allocate
+ more large chunks) the value should be high enough so that your
+ overall system performance would improve by releasing this much
+ memory. As a rough guide, you might set to a value close to the
+ average size of a process (program) running on your system.
+ Releasing this much memory would allow such a process to run in
+ memory. Generally, it is worth tuning trim thresholds when a
+ program undergoes phases where several large chunks are allocated
+ and released in ways that can reuse each other's storage, perhaps
+ mixed with phases where there are no such chunks at all. The trim
+ value must be greater than page size to have any useful effect. To
+ disable trimming completely, you can set to MAX_SIZE_T. Note that the trick
+ some people use of mallocing a huge space and then freeing it at
+ program startup, in an attempt to reserve system memory, doesn't
+ have the intended effect under automatic trimming, since that memory
+ will immediately be returned to the system.
+
+DEFAULT_MMAP_THRESHOLD default: 256K
+ Also settable using mallopt(M_MMAP_THRESHOLD, x)
+ The request size threshold for using MMAP to directly service a
+ request. Requests of at least this size that cannot be allocated
+ using already-existing space will be serviced via mmap. (If enough
+ normal freed space already exists it is used instead.) Using mmap
+ segregates relatively large chunks of memory so that they can be
+ individually obtained and released from the host system. A request
+ serviced through mmap is never reused by any other request (at least
+ not directly; the system may just so happen to remap successive
+ requests to the same locations). Segregating space in this way has
+ the benefits that: Mmapped space can always be individually released
+ back to the system, which helps keep the system level memory demands
+ of a long-lived program low. Also, mapped memory doesn't become
+ `locked' between other chunks, as can happen with normally allocated
+ chunks, which means that even trimming via malloc_trim would not
+ release them. However, it has the disadvantage that the space
+ cannot be reclaimed, consolidated, and then used to service later
+ requests, as happens with normal chunks. The advantages of mmap
+ nearly always outweigh disadvantages for "large" chunks, but the
+ value of "large" may vary across systems. The default is an
+ empirically derived value that works well in most systems. You can
+ disable mmap by setting to MAX_SIZE_T.
+
+MAX_RELEASE_CHECK_RATE default: 4095 unless not HAVE_MMAP
+ The number of consolidated frees between checks to release
+ unused segments when freeing. When using non-contiguous segments,
+ especially with multiple mspaces, checking only for topmost space
+ doesn't always suffice to trigger trimming. To compensate for this,
+ free() will, with a period of MAX_RELEASE_CHECK_RATE (or the
+ current number of segments, if greater) try to release unused
+ segments to the OS when freeing chunks that result in
+ consolidation. The best value for this parameter is a compromise
+ between slowing down frees with relatively costly checks that
+ rarely trigger versus holding on to unused memory. To effectively
+ disable, set to MAX_SIZE_T. This may lead to a very slight speed
+ improvement at the expense of carrying around more memory.
+*/
+
+/* Version identifier to allow people to support multiple versions */
+#ifndef DLMALLOC_VERSION
+#define DLMALLOC_VERSION 20804
+#endif /* DLMALLOC_VERSION */
+
+#ifndef WIN32
+#ifdef _WIN32
+#define WIN32 1
+#endif /* _WIN32 */
+#ifdef _WIN32_WCE
+#define LACKS_FCNTL_H
+#define WIN32 1
+#endif /* _WIN32_WCE */
+#endif /* WIN32 */
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <tchar.h>
+#define HAVE_MMAP 1
+#define HAVE_MORECORE 0
+#define LACKS_UNISTD_H
+#define LACKS_SYS_PARAM_H
+#define LACKS_SYS_MMAN_H
+#define LACKS_STRING_H
+#define LACKS_STRINGS_H
+#define LACKS_SYS_TYPES_H
+#define LACKS_ERRNO_H
+#ifndef MALLOC_FAILURE_ACTION
+#define MALLOC_FAILURE_ACTION
+#endif /* MALLOC_FAILURE_ACTION */
+#ifdef _WIN32_WCE /* WINCE reportedly does not clear */
+#define MMAP_CLEARS 0
+#else
+#define MMAP_CLEARS 1
+#endif /* _WIN32_WCE */
+#endif /* WIN32 */
+
+#if defined(DARWIN) || defined(_DARWIN)
+/* Mac OSX docs advise not to use sbrk; it seems better to use mmap */
+#ifndef HAVE_MORECORE
+#define HAVE_MORECORE 0
+#define HAVE_MMAP 1
+/* OSX allocators provide 16 byte alignment */
+#ifndef MALLOC_ALIGNMENT
+#define MALLOC_ALIGNMENT ((size_t)16U)
+#endif
+#endif /* HAVE_MORECORE */
+#endif /* DARWIN */
+
+#ifndef LACKS_SYS_TYPES_H
+#include <sys/types.h> /* For size_t */
+#endif /* LACKS_SYS_TYPES_H */
+
+#if (defined(__GNUC__) && ((defined(__i386__) || defined(__x86_64__)))) || (defined(_MSC_VER) && _MSC_VER>=1310)
+#define SPIN_LOCKS_AVAILABLE 1
+#else
+#define SPIN_LOCKS_AVAILABLE 0
+#endif
+
+/* The maximum possible size_t value has all bits set */
+#define MAX_SIZE_T (~(size_t)0)
+
+#ifndef ONLY_MSPACES
+#define ONLY_MSPACES 0 /* define to a value */
+#else
+#define ONLY_MSPACES 1
+#endif /* ONLY_MSPACES */
+#ifndef MSPACES
+#if ONLY_MSPACES
+#define MSPACES 1
+#else /* ONLY_MSPACES */
+#define MSPACES 0
+#endif /* ONLY_MSPACES */
+#endif /* MSPACES */
+#ifndef MALLOC_ALIGNMENT
+#define MALLOC_ALIGNMENT ((size_t)8U)
+#endif /* MALLOC_ALIGNMENT */
+#ifndef FOOTERS
+#define FOOTERS 0
+#endif /* FOOTERS */
+#ifndef ABORT
+#define ABORT abort()
+#endif /* ABORT */
+#ifndef ABORT_ON_ASSERT_FAILURE
+#define ABORT_ON_ASSERT_FAILURE 1
+#endif /* ABORT_ON_ASSERT_FAILURE */
+#ifndef PROCEED_ON_ERROR
+#define PROCEED_ON_ERROR 0
+#endif /* PROCEED_ON_ERROR */
+#ifndef USE_LOCKS
+#define USE_LOCKS 0
+#endif /* USE_LOCKS */
+#ifndef USE_SPIN_LOCKS
+#if USE_LOCKS && SPIN_LOCKS_AVAILABLE
+#define USE_SPIN_LOCKS 1
+#else
+#define USE_SPIN_LOCKS 0
+#endif /* USE_LOCKS && SPIN_LOCKS_AVAILABLE. */
+#endif /* USE_SPIN_LOCKS */
+#ifndef INSECURE
+#define INSECURE 0
+#endif /* INSECURE */
+#ifndef HAVE_MMAP
+#define HAVE_MMAP 1
+#endif /* HAVE_MMAP */
+#ifndef MMAP_CLEARS
+#define MMAP_CLEARS 1
+#endif /* MMAP_CLEARS */
+#ifndef HAVE_MREMAP
+#ifdef linux
+#define HAVE_MREMAP 1
+#else /* linux */
+#define HAVE_MREMAP 0
+#endif /* linux */
+#endif /* HAVE_MREMAP */
+#ifndef MALLOC_FAILURE_ACTION
+#define MALLOC_FAILURE_ACTION errno = ENOMEM;
+#endif /* MALLOC_FAILURE_ACTION */
+#ifndef HAVE_MORECORE
+#if ONLY_MSPACES
+#define HAVE_MORECORE 0
+#else /* ONLY_MSPACES */
+#define HAVE_MORECORE 1
+#endif /* ONLY_MSPACES */
+#endif /* HAVE_MORECORE */
+#if !HAVE_MORECORE
+#define MORECORE_CONTIGUOUS 0
+#else /* !HAVE_MORECORE */
+#define MORECORE_DEFAULT sbrk
+#ifndef MORECORE_CONTIGUOUS
+#define MORECORE_CONTIGUOUS 1
+#endif /* MORECORE_CONTIGUOUS */
+#endif /* HAVE_MORECORE */
+#ifndef DEFAULT_GRANULARITY
+#if (MORECORE_CONTIGUOUS || defined(WIN32))
+#define DEFAULT_GRANULARITY (0) /* 0 means to compute in init_mparams */
+#else /* MORECORE_CONTIGUOUS */
+#define DEFAULT_GRANULARITY ((size_t)64U * (size_t)1024U)
+#endif /* MORECORE_CONTIGUOUS */
+#endif /* DEFAULT_GRANULARITY */
+#ifndef DEFAULT_TRIM_THRESHOLD
+#ifndef MORECORE_CANNOT_TRIM
+#define DEFAULT_TRIM_THRESHOLD ((size_t)2U * (size_t)1024U * (size_t)1024U)
+#else /* MORECORE_CANNOT_TRIM */
+#define DEFAULT_TRIM_THRESHOLD MAX_SIZE_T
+#endif /* MORECORE_CANNOT_TRIM */
+#endif /* DEFAULT_TRIM_THRESHOLD */
+#ifndef DEFAULT_MMAP_THRESHOLD
+#if HAVE_MMAP
+#define DEFAULT_MMAP_THRESHOLD ((size_t)256U * (size_t)1024U)
+#else /* HAVE_MMAP */
+#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T
+#endif /* HAVE_MMAP */
+#endif /* DEFAULT_MMAP_THRESHOLD */
+#ifndef MAX_RELEASE_CHECK_RATE
+#if HAVE_MMAP
+#define MAX_RELEASE_CHECK_RATE 4095
+#else
+#define MAX_RELEASE_CHECK_RATE MAX_SIZE_T
+#endif /* HAVE_MMAP */
+#endif /* MAX_RELEASE_CHECK_RATE */
+#ifndef USE_BUILTIN_FFS
+#define USE_BUILTIN_FFS 0
+#endif /* USE_BUILTIN_FFS */
+#ifndef USE_DEV_RANDOM
+#define USE_DEV_RANDOM 0
+#endif /* USE_DEV_RANDOM */
+#ifndef NO_MALLINFO
+#define NO_MALLINFO 0
+#endif /* NO_MALLINFO */
+#ifndef MALLINFO_FIELD_TYPE
+#define MALLINFO_FIELD_TYPE size_t
+#endif /* MALLINFO_FIELD_TYPE */
+#ifndef NO_SEGMENT_TRAVERSAL
+#define NO_SEGMENT_TRAVERSAL 0
+#endif /* NO_SEGMENT_TRAVERSAL */
+
+/*
+ mallopt tuning options. SVID/XPG defines four standard parameter
+ numbers for mallopt, normally defined in malloc.h. None of these
+ are used in this malloc, so setting them has no effect. But this
+ malloc does support the following options.
+*/
+
+#define M_TRIM_THRESHOLD (-1)
+#define M_GRANULARITY (-2)
+#define M_MMAP_THRESHOLD (-3)
+
+/* ------------------------ Mallinfo declarations ------------------------ */
+
+#if !NO_MALLINFO
+/*
+ This version of malloc supports the standard SVID/XPG mallinfo
+ routine that returns a struct containing usage properties and
+ statistics. It should work on any system that has a
+ /usr/include/malloc.h defining struct mallinfo. The main
+ declaration needed is the mallinfo struct that is returned (by-copy)
+ by mallinfo(). The malloinfo struct contains a bunch of fields that
+ are not even meaningful in this version of malloc. These fields are
+ are instead filled by mallinfo() with other numbers that might be of
+ interest.
+
+ HAVE_USR_INCLUDE_MALLOC_H should be set if you have a
+ /usr/include/malloc.h file that includes a declaration of struct
+ mallinfo. If so, it is included; else a compliant version is
+ declared below. These must be precisely the same for mallinfo() to
+ work. The original SVID version of this struct, defined on most
+ systems with mallinfo, declares all fields as ints. But some others
+ define as unsigned long. If your system defines the fields using a
+ type of different width than listed here, you MUST #include your
+ system version and #define HAVE_USR_INCLUDE_MALLOC_H.
+*/
+
+/* #define HAVE_USR_INCLUDE_MALLOC_H */
+
+#ifdef HAVE_USR_INCLUDE_MALLOC_H
+#include "/usr/include/malloc.h"
+#else /* HAVE_USR_INCLUDE_MALLOC_H */
+#ifndef STRUCT_MALLINFO_DECLARED
+#define STRUCT_MALLINFO_DECLARED 1
+struct mallinfo {
+ MALLINFO_FIELD_TYPE arena; /* non-mmapped space allocated from system */
+ MALLINFO_FIELD_TYPE ordblks; /* number of free chunks */
+ MALLINFO_FIELD_TYPE smblks; /* always 0 */
+ MALLINFO_FIELD_TYPE hblks; /* always 0 */
+ MALLINFO_FIELD_TYPE hblkhd; /* space in mmapped regions */
+ MALLINFO_FIELD_TYPE usmblks; /* maximum total allocated space */
+ MALLINFO_FIELD_TYPE fsmblks; /* always 0 */
+ MALLINFO_FIELD_TYPE uordblks; /* total allocated space */
+ MALLINFO_FIELD_TYPE fordblks; /* total free space */
+ MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */
+};
+#endif /* STRUCT_MALLINFO_DECLARED */
+#endif /* HAVE_USR_INCLUDE_MALLOC_H */
+#endif /* NO_MALLINFO */
+
+/*
+ Try to persuade compilers to inline. The most critical functions for
+ inlining are defined as macros, so these aren't used for them.
+*/
+
+#ifndef FORCEINLINE
+ #if defined(__GNUC__)
+#define FORCEINLINE __inline __attribute__ ((always_inline))
+ #elif defined(_MSC_VER)
+ #define FORCEINLINE __forceinline
+ #endif
+#endif
+#ifndef NOINLINE
+ #if defined(__GNUC__)
+ #define NOINLINE __attribute__ ((noinline))
+ #elif defined(_MSC_VER)
+ #define NOINLINE __declspec(noinline)
+ #else
+ #define NOINLINE
+ #endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#ifndef FORCEINLINE
+ #define FORCEINLINE inline
+#endif
+#endif /* __cplusplus */
+#ifndef FORCEINLINE
+ #define FORCEINLINE
+#endif
+
+#if !ONLY_MSPACES
+
+/* ------------------- Declarations of public routines ------------------- */
+
+#ifndef USE_DL_PREFIX
+#define dlcalloc calloc
+#define dlfree free
+#define dlmalloc malloc
+#define dlmemalign memalign
+#define dlrealloc realloc
+#define dlvalloc valloc
+#define dlpvalloc pvalloc
+#define dlmallinfo mallinfo
+#define dlmallopt mallopt
+#define dlmalloc_trim malloc_trim
+#define dlmalloc_stats malloc_stats
+#define dlmalloc_usable_size malloc_usable_size
+#define dlmalloc_footprint malloc_footprint
+#define dlmalloc_max_footprint malloc_max_footprint
+#define dlindependent_calloc independent_calloc
+#define dlindependent_comalloc independent_comalloc
+#endif /* USE_DL_PREFIX */
+
+
+/*
+ malloc(size_t n)
+ Returns a pointer to a newly allocated chunk of at least n bytes, or
+ null if no space is available, in which case errno is set to ENOMEM
+ on ANSI C systems.
+
+ If n is zero, malloc returns a minimum-sized chunk. (The minimum
+ size is 16 bytes on most 32bit systems, and 32 bytes on 64bit
+ systems.) Note that size_t is an unsigned type, so calls with
+ arguments that would be negative if signed are interpreted as
+ requests for huge amounts of space, which will often fail. The
+ maximum supported value of n differs across systems, but is in all
+ cases less than the maximum representable value of a size_t.
+*/
+void* dlmalloc(size_t);
+
+/*
+ free(void* p)
+ Releases the chunk of memory pointed to by p, that had been previously
+ allocated using malloc or a related routine such as realloc.
+ It has no effect if p is null. If p was not malloced or already
+ freed, free(p) will by default cause the current program to abort.
+*/
+void dlfree(void*);
+
+/*
+ calloc(size_t n_elements, size_t element_size);
+ Returns a pointer to n_elements * element_size bytes, with all locations
+ set to zero.
+*/
+void* dlcalloc(size_t, size_t);
+
+/*
+ realloc(void* p, size_t n)
+ Returns a pointer to a chunk of size n that contains the same data
+ as does chunk p up to the minimum of (n, p's size) bytes, or null
+ if no space is available.
+
+ The returned pointer may or may not be the same as p. The algorithm
+ prefers extending p in most cases when possible, otherwise it
+ employs the equivalent of a malloc-copy-free sequence.
+
+ If p is null, realloc is equivalent to malloc.
+
+ If space is not available, realloc returns null, errno is set (if on
+ ANSI) and p is NOT freed.
+
+ if n is for fewer bytes than already held by p, the newly unused
+ space is lopped off and freed if possible. realloc with a size
+ argument of zero (re)allocates a minimum-sized chunk.
+
+ The old unix realloc convention of allowing the last-free'd chunk
+ to be used as an argument to realloc is not supported.
+*/
+
+void* dlrealloc(void*, size_t);
+
+/*
+ memalign(size_t alignment, size_t n);
+ Returns a pointer to a newly allocated chunk of n bytes, aligned
+ in accord with the alignment argument.
+
+ The alignment argument should be a power of two. If the argument is
+ not a power of two, the nearest greater power is used.
+ 8-byte alignment is guaranteed by normal malloc calls, so don't
+ bother calling memalign with an argument of 8 or less.
+
+ Overreliance on memalign is a sure way to fragment space.
+*/
+void* dlmemalign(size_t, size_t);
+
+/*
+ valloc(size_t n);
+ Equivalent to memalign(pagesize, n), where pagesize is the page
+ size of the system. If the pagesize is unknown, 4096 is used.
+*/
+void* dlvalloc(size_t);
+
+/*
+ mallopt(int parameter_number, int parameter_value)
+ Sets tunable parameters The format is to provide a
+ (parameter-number, parameter-value) pair. mallopt then sets the
+ corresponding parameter to the argument value if it can (i.e., so
+ long as the value is meaningful), and returns 1 if successful else
+ 0. To workaround the fact that mallopt is specified to use int,
+ not size_t parameters, the value -1 is specially treated as the
+ maximum unsigned size_t value.
+
+ SVID/XPG/ANSI defines four standard param numbers for mallopt,
+ normally defined in malloc.h. None of these are use in this malloc,
+ so setting them has no effect. But this malloc also supports other
+ options in mallopt. See below for details. Briefly, supported
+ parameters are as follows (listed defaults are for "typical"
+ configurations).
+
+ Symbol param # default allowed param values
+ M_TRIM_THRESHOLD -1 2*1024*1024 any (-1 disables)
+ M_GRANULARITY -2 page size any power of 2 >= page size
+ M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support)
+*/
+int dlmallopt(int, int);
+
+/*
+ malloc_footprint();
+ Returns the number of bytes obtained from the system. The total
+ number of bytes allocated by malloc, realloc etc., is less than this
+ value. Unlike mallinfo, this function returns only a precomputed
+ result, so can be called frequently to monitor memory consumption.
+ Even if locks are otherwise defined, this function does not use them,
+ so results might not be up to date.
+*/
+size_t dlmalloc_footprint(void);
+
+/*
+ malloc_max_footprint();
+ Returns the maximum number of bytes obtained from the system. This
+ value will be greater than current footprint if deallocated space
+ has been reclaimed by the system. The peak number of bytes allocated
+ by malloc, realloc etc., is less than this value. Unlike mallinfo,
+ this function returns only a precomputed result, so can be called
+ frequently to monitor memory consumption. Even if locks are
+ otherwise defined, this function does not use them, so results might
+ not be up to date.
+*/
+size_t dlmalloc_max_footprint(void);
+
+#if !NO_MALLINFO
+/*
+ mallinfo()
+ Returns (by copy) a struct containing various summary statistics:
+
+ arena: current total non-mmapped bytes allocated from system
+ ordblks: the number of free chunks
+ smblks: always zero.
+ hblks: current number of mmapped regions
+ hblkhd: total bytes held in mmapped regions
+ usmblks: the maximum total allocated space. This will be greater
+ than current total if trimming has occurred.
+ fsmblks: always zero
+ uordblks: current total allocated space (normal or mmapped)
+ fordblks: total free space
+ keepcost: the maximum number of bytes that could ideally be released
+ back to system via malloc_trim. ("ideally" means that
+ it ignores page restrictions etc.)
+
+ Because these fields are ints, but internal bookkeeping may
+ be kept as longs, the reported values may wrap around zero and
+ thus be inaccurate.
+*/
+struct mallinfo dlmallinfo(void);
+#endif /* NO_MALLINFO */
+
+/*
+ independent_calloc(size_t n_elements, size_t element_size, void* chunks[]);
+
+ independent_calloc is similar to calloc, but instead of returning a
+ single cleared space, it returns an array of pointers to n_elements
+ independent elements that can hold contents of size elem_size, each
+ of which starts out cleared, and can be independently freed,
+ realloc'ed etc. The elements are guaranteed to be adjacently
+ allocated (this is not guaranteed to occur with multiple callocs or
+ mallocs), which may also improve cache locality in some
+ applications.
+
+ The "chunks" argument is optional (i.e., may be null, which is
+ probably the most typical usage). If it is null, the returned array
+ is itself dynamically allocated and should also be freed when it is
+ no longer needed. Otherwise, the chunks array must be of at least
+ n_elements in length. It is filled in with the pointers to the
+ chunks.
+
+ In either case, independent_calloc returns this pointer array, or
+ null if the allocation failed. If n_elements is zero and "chunks"
+ is null, it returns a chunk representing an array with zero elements
+ (which should be freed if not wanted).
+
+ Each element must be individually freed when it is no longer
+ needed. If you'd like to instead be able to free all at once, you
+ should instead use regular calloc and assign pointers into this
+ space to represent elements. (In this case though, you cannot
+ independently free elements.)
+
+ independent_calloc simplifies and speeds up implementations of many
+ kinds of pools. It may also be useful when constructing large data
+ structures that initially have a fixed number of fixed-sized nodes,
+ but the number is not known at compile time, and some of the nodes
+ may later need to be freed. For example:
+
+ struct Node { int item; struct Node* next; };
+
+ struct Node* build_list() {
+ struct Node** pool;
+ int n = read_number_of_nodes_needed();
+ if (n <= 0) return 0;
+ pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);
+ if (pool == 0) die();
+ // organize into a linked list...
+ struct Node* first = pool[0];
+ for (i = 0; i < n-1; ++i)
+ pool[i]->next = pool[i+1];
+ free(pool); // Can now free the array (or not, if it is needed later)
+ return first;
+ }
+*/
+void** dlindependent_calloc(size_t, size_t, void**);
+
+/*
+ independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);
+
+ independent_comalloc allocates, all at once, a set of n_elements
+ chunks with sizes indicated in the "sizes" array. It returns
+ an array of pointers to these elements, each of which can be
+ independently freed, realloc'ed etc. The elements are guaranteed to
+ be adjacently allocated (this is not guaranteed to occur with
+ multiple callocs or mallocs), which may also improve cache locality
+ in some applications.
+
+ The "chunks" argument is optional (i.e., may be null). If it is null
+ the returned array is itself dynamically allocated and should also
+ be freed when it is no longer needed. Otherwise, the chunks array
+ must be of at least n_elements in length. It is filled in with the
+ pointers to the chunks.
+
+ In either case, independent_comalloc returns this pointer array, or
+ null if the allocation failed. If n_elements is zero and chunks is
+ null, it returns a chunk representing an array with zero elements
+ (which should be freed if not wanted).
+
+ Each element must be individually freed when it is no longer
+ needed. If you'd like to instead be able to free all at once, you
+ should instead use a single regular malloc, and assign pointers at
+ particular offsets in the aggregate space. (In this case though, you
+ cannot independently free elements.)
+
+ independent_comallac differs from independent_calloc in that each
+ element may have a different size, and also that it does not
+ automatically clear elements.
+
+ independent_comalloc can be used to speed up allocation in cases
+ where several structs or objects must always be allocated at the
+ same time. For example:
+
+ struct Head { ... }
+ struct Foot { ... }
+
+ void send_message(char* msg) {
+ int msglen = strlen(msg);
+ size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };
+ void* chunks[3];
+ if (independent_comalloc(3, sizes, chunks) == 0)
+ die();
+ struct Head* head = (struct Head*)(chunks[0]);
+ char* body = (char*)(chunks[1]);
+ struct Foot* foot = (struct Foot*)(chunks[2]);
+ // ...
+ }
+
+ In general though, independent_comalloc is worth using only for
+ larger values of n_elements. For small values, you probably won't
+ detect enough difference from series of malloc calls to bother.
+
+ Overuse of independent_comalloc can increase overall memory usage,
+ since it cannot reuse existing noncontiguous small chunks that
+ might be available for some of the elements.
+*/
+void** dlindependent_comalloc(size_t, size_t*, void**);
+
+
+/*
+ pvalloc(size_t n);
+ Equivalent to valloc(minimum-page-that-holds(n)), that is,
+ round up n to nearest pagesize.
+ */
+void* dlpvalloc(size_t);
+
+/*
+ malloc_trim(size_t pad);
+
+ If possible, gives memory back to the system (via negative arguments
+ to sbrk) if there is unused memory at the `high' end of the malloc
+ pool or in unused MMAP segments. You can call this after freeing
+ large blocks of memory to potentially reduce the system-level memory
+ requirements of a program. However, it cannot guarantee to reduce
+ memory. Under some allocation patterns, some large free blocks of
+ memory will be locked between two used chunks, so they cannot be
+ given back to the system.
+
+ The `pad' argument to malloc_trim represents the amount of free
+ trailing space to leave untrimmed. If this argument is zero, only
+ the minimum amount of memory to maintain internal data structures
+ will be left. Non-zero arguments can be supplied to maintain enough
+ trailing space to service future expected allocations without having
+ to re-obtain memory from the system.
+
+ Malloc_trim returns 1 if it actually released any memory, else 0.
+*/
+int dlmalloc_trim(size_t);
+
+/*
+ malloc_stats();
+ Prints on stderr the amount of space obtained from the system (both
+ via sbrk and mmap), the maximum amount (which may be more than
+ current if malloc_trim and/or munmap got called), and the current
+ number of bytes allocated via malloc (or realloc, etc) but not yet
+ freed. Note that this is the number of bytes allocated, not the
+ number requested. It will be larger than the number requested
+ because of alignment and bookkeeping overhead. Because it includes
+ alignment wastage as being in use, this figure may be greater than
+ zero even when no user-level chunks are allocated.
+
+ The reported current and maximum system memory can be inaccurate if
+ a program makes other calls to system memory allocation functions
+ (normally sbrk) outside of malloc.
+
+ malloc_stats prints only the most commonly interesting statistics.
+ More information can be obtained by calling mallinfo.
+*/
+void dlmalloc_stats(void);
+
+#endif /* ONLY_MSPACES */
+
+/*
+ malloc_usable_size(void* p);
+
+ Returns the number of bytes you can actually use in
+ an allocated chunk, which may be more than you requested (although
+ often not) due to alignment and minimum size constraints.
+ You can use this many bytes without worrying about
+ overwriting other allocated objects. This is not a particularly great
+ programming practice. malloc_usable_size can be more useful in
+ debugging and assertions, for example:
+
+ p = malloc(n);
+ assert(malloc_usable_size(p) >= 256);
+*/
+size_t dlmalloc_usable_size(void*);
+
+
+#if MSPACES
+
+/*
+ mspace is an opaque type representing an independent
+ region of space that supports mspace_malloc, etc.
+*/
+typedef void* mspace;
+
+/*
+ create_mspace creates and returns a new independent space with the
+ given initial capacity, or, if 0, the default granularity size. It
+ returns null if there is no system memory available to create the
+ space. If argument locked is non-zero, the space uses a separate
+ lock to control access. The capacity of the space will grow
+ dynamically as needed to service mspace_malloc requests. You can
+ control the sizes of incremental increases of this space by
+ compiling with a different DEFAULT_GRANULARITY or dynamically
+ setting with mallopt(M_GRANULARITY, value).
+*/
+mspace create_mspace(size_t capacity, int locked);
+
+/*
+ destroy_mspace destroys the given space, and attempts to return all
+ of its memory back to the system, returning the total number of
+ bytes freed. After destruction, the results of access to all memory
+ used by the space become undefined.
+*/
+size_t destroy_mspace(mspace msp);
+
+/*
+ create_mspace_with_base uses the memory supplied as the initial base
+ of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this
+ space is used for bookkeeping, so the capacity must be at least this
+ large. (Otherwise 0 is returned.) When this initial space is
+ exhausted, additional memory will be obtained from the system.
+ Destroying this space will deallocate all additionally allocated
+ space (if possible) but not the initial base.
+*/
+mspace create_mspace_with_base(void* base, size_t capacity, int locked);
+
+/*
+ mspace_track_large_chunks controls whether requests for large chunks
+ are allocated in their own untracked mmapped regions, separate from
+ others in this mspace. By default large chunks are not tracked,
+ which reduces fragmentation. However, such chunks are not
+ necessarily released to the system upon destroy_mspace. Enabling
+ tracking by setting to true may increase fragmentation, but avoids
+ leakage when relying on destroy_mspace to release all memory
+ allocated using this space. The function returns the previous
+ setting.
+*/
+int mspace_track_large_chunks(mspace msp, int enable);
+
+
+/*
+ mspace_malloc behaves as malloc, but operates within
+ the given space.
+*/
+void* mspace_malloc(mspace msp, size_t bytes);
+
+/*
+ mspace_free behaves as free, but operates within
+ the given space.
+
+ If compiled with FOOTERS==1, mspace_free is not actually needed.
+ free may be called instead of mspace_free because freed chunks from
+ any space are handled by their originating spaces.
+*/
+void mspace_free(mspace msp, void* mem);
+
+/*
+ mspace_realloc behaves as realloc, but operates within
+ the given space.
+
+ If compiled with FOOTERS==1, mspace_realloc is not actually
+ needed. realloc may be called instead of mspace_realloc because
+ realloced chunks from any space are handled by their originating
+ spaces.
+*/
+void* mspace_realloc(mspace msp, void* mem, size_t newsize);
+
+/*
+ mspace_calloc behaves as calloc, but operates within
+ the given space.
+*/
+void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size);
+
+/*
+ mspace_memalign behaves as memalign, but operates within
+ the given space.
+*/
+void* mspace_memalign(mspace msp, size_t alignment, size_t bytes);
+
+/*
+ mspace_independent_calloc behaves as independent_calloc, but
+ operates within the given space.
+*/
+void** mspace_independent_calloc(mspace msp, size_t n_elements,
+ size_t elem_size, void* chunks[]);
+
+/*
+ mspace_independent_comalloc behaves as independent_comalloc, but
+ operates within the given space.
+*/
+void** mspace_independent_comalloc(mspace msp, size_t n_elements,
+ size_t sizes[], void* chunks[]);
+
+/*
+ mspace_footprint() returns the number of bytes obtained from the
+ system for this space.
+*/
+size_t mspace_footprint(mspace msp);
+
+/*
+ mspace_max_footprint() returns the peak number of bytes obtained from the
+ system for this space.
+*/
+size_t mspace_max_footprint(mspace msp);
+
+
+#if !NO_MALLINFO
+/*
+ mspace_mallinfo behaves as mallinfo, but reports properties of
+ the given space.
+*/
+struct mallinfo mspace_mallinfo(mspace msp);
+#endif /* NO_MALLINFO */
+
+/*
+ malloc_usable_size(void* p) behaves the same as malloc_usable_size;
+*/
+ size_t mspace_usable_size(void* mem);
+
+/*
+ mspace_malloc_stats behaves as malloc_stats, but reports
+ properties of the given space.
+*/
+void mspace_malloc_stats(mspace msp);
+
+/*
+ mspace_trim behaves as malloc_trim, but
+ operates within the given space.
+*/
+int mspace_trim(mspace msp, size_t pad);
+
+/*
+ An alias for mallopt.
+*/
+int mspace_mallopt(int, int);
+
+#endif /* MSPACES */
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif /* __cplusplus */
+
+/*
+ ========================================================================
+ To make a fully customizable malloc.h header file, cut everything
+ above this line, put into file malloc.h, edit to suit, and #include it
+ on the next line, as well as in programs that use this malloc.
+ ========================================================================
+*/
+
+/* #include "malloc.h" */
+
+/*------------------------------ internal #includes ---------------------- */
+
+#ifdef WIN32
+#pragma warning( disable : 4146 ) /* no "unsigned" warnings */
+#endif /* WIN32 */
+
+#include <stdio.h> /* for printing in malloc_stats */
+
+#ifndef LACKS_ERRNO_H
+#include <errno.h> /* for MALLOC_FAILURE_ACTION */
+#endif /* LACKS_ERRNO_H */
+#if FOOTERS || DEBUG
+#include <time.h> /* for magic initialization */
+#endif /* FOOTERS */
+#ifndef LACKS_STDLIB_H
+#include <stdlib.h> /* for abort() */
+#endif /* LACKS_STDLIB_H */
+#ifdef DEBUG
+#if ABORT_ON_ASSERT_FAILURE
+#undef assert
+#define assert(x) if(!(x)) ABORT
+#else /* ABORT_ON_ASSERT_FAILURE */
+#include <assert.h>
+#endif /* ABORT_ON_ASSERT_FAILURE */
+#else /* DEBUG */
+#ifndef assert
+#define assert(x)
+#endif
+#define DEBUG 0
+#endif /* DEBUG */
+#ifndef LACKS_STRING_H
+#include <string.h> /* for memset etc */
+#endif /* LACKS_STRING_H */
+#if USE_BUILTIN_FFS
+#ifndef LACKS_STRINGS_H
+#include <strings.h> /* for ffs */
+#endif /* LACKS_STRINGS_H */
+#endif /* USE_BUILTIN_FFS */
+#if HAVE_MMAP
+#ifndef LACKS_SYS_MMAN_H
+/* On some versions of linux, mremap decl in mman.h needs __USE_GNU set */
+#if (defined(linux) && !defined(__USE_GNU))
+#define __USE_GNU 1
+#include <sys/mman.h> /* for mmap */
+#undef __USE_GNU
+#else
+#include <sys/mman.h> /* for mmap */
+#endif /* linux */
+#endif /* LACKS_SYS_MMAN_H */
+#ifndef LACKS_FCNTL_H
+#include <fcntl.h>
+#endif /* LACKS_FCNTL_H */
+#endif /* HAVE_MMAP */
+#ifndef LACKS_UNISTD_H
+#include <unistd.h> /* for sbrk, sysconf */
+#else /* LACKS_UNISTD_H */
+#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__)
+extern void* sbrk(ptrdiff_t);
+#endif /* FreeBSD etc */
+#endif /* LACKS_UNISTD_H */
+
+/* Declarations for locking */
+#if USE_LOCKS
+#ifndef WIN32
+#include <pthread.h>
+#if defined (__SVR4) && defined (__sun) /* solaris */
+#include <thread.h>
+#endif /* solaris */
+#else
+#ifndef _M_AMD64
+/* These are already defined on AMD64 builds */
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+LONG __cdecl _InterlockedCompareExchange(LONG volatile *Dest, LONG Exchange, LONG Comp);
+LONG __cdecl _InterlockedExchange(LONG volatile *Target, LONG Value);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* _M_AMD64 */
+#pragma intrinsic (_InterlockedCompareExchange)
+#pragma intrinsic (_InterlockedExchange)
+#define interlockedcompareexchange _InterlockedCompareExchange
+#define interlockedexchange _InterlockedExchange
+#endif /* Win32 */
+#endif /* USE_LOCKS */
+
+/* Declarations for bit scanning on win32 */
+#if defined(_MSC_VER) && _MSC_VER>=1300
+#ifndef BitScanForward /* Try to avoid pulling in WinNT.h */
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+unsigned char _BitScanForward(unsigned long *index, unsigned long mask);
+unsigned char _BitScanReverse(unsigned long *index, unsigned long mask);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#define BitScanForward _BitScanForward
+#define BitScanReverse _BitScanReverse
+#pragma intrinsic(_BitScanForward)
+#pragma intrinsic(_BitScanReverse)
+#endif /* BitScanForward */
+#endif /* defined(_MSC_VER) && _MSC_VER>=1300 */
+
+#ifndef WIN32
+#ifndef malloc_getpagesize
+# ifdef _SC_PAGESIZE /* some SVR4 systems omit an underscore */
+# ifndef _SC_PAGE_SIZE
+# define _SC_PAGE_SIZE _SC_PAGESIZE
+# endif
+# endif
+# ifdef _SC_PAGE_SIZE
+# define malloc_getpagesize sysconf(_SC_PAGE_SIZE)
+# else
+# if defined(BSD) || defined(DGUX) || defined(HAVE_GETPAGESIZE)
+ extern size_t getpagesize();
+# define malloc_getpagesize getpagesize()
+# else
+# ifdef WIN32 /* use supplied emulation of getpagesize */
+# define malloc_getpagesize getpagesize()
+# else
+# ifndef LACKS_SYS_PARAM_H
+# include <sys/param.h>
+# endif
+# ifdef EXEC_PAGESIZE
+# define malloc_getpagesize EXEC_PAGESIZE
+# else
+# ifdef NBPG
+# ifndef CLSIZE
+# define malloc_getpagesize NBPG
+# else
+# define malloc_getpagesize (NBPG * CLSIZE)
+# endif
+# else
+# ifdef NBPC
+# define malloc_getpagesize NBPC
+# else
+# ifdef PAGESIZE
+# define malloc_getpagesize PAGESIZE
+# else /* just guess */
+# define malloc_getpagesize ((size_t)4096U)
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+# endif
+#endif
+#endif
+
+
+
+/* ------------------- size_t and alignment properties -------------------- */
+
+/* The byte and bit size of a size_t */
+#define SIZE_T_SIZE (sizeof(size_t))
+#define SIZE_T_BITSIZE (sizeof(size_t) << 3)
+
+/* Some constants coerced to size_t */
+/* Annoying but necessary to avoid errors on some platforms */
+#define SIZE_T_ZERO ((size_t)0)
+#define SIZE_T_ONE ((size_t)1)
+#define SIZE_T_TWO ((size_t)2)
+#define SIZE_T_FOUR ((size_t)4)
+#define TWO_SIZE_T_SIZES (SIZE_T_SIZE<<1)
+#define FOUR_SIZE_T_SIZES (SIZE_T_SIZE<<2)
+#define SIX_SIZE_T_SIZES (FOUR_SIZE_T_SIZES+TWO_SIZE_T_SIZES)
+#define HALF_MAX_SIZE_T (MAX_SIZE_T / 2U)
+
+/* The bit mask value corresponding to MALLOC_ALIGNMENT */
+#define CHUNK_ALIGN_MASK (MALLOC_ALIGNMENT - SIZE_T_ONE)
+
+/* True if address a has acceptable alignment */
+#define is_aligned(A) (((size_t)((A)) & (CHUNK_ALIGN_MASK)) == 0)
+
+/* the number of bytes to offset an address to align it */
+#define align_offset(A)\
+ ((((size_t)(A) & CHUNK_ALIGN_MASK) == 0)? 0 :\
+ ((MALLOC_ALIGNMENT - ((size_t)(A) & CHUNK_ALIGN_MASK)) & CHUNK_ALIGN_MASK))
+
+/*
+ malloc_params holds global properties, including those that can be
+ dynamically set using mallopt. There is a single instance, mparams,
+ initialized in init_mparams. Note that the non-zeroness of "magic"
+ also serves as an initialization flag.
+*/
+typedef unsigned int flag_t;
+struct malloc_params {
+ volatile size_t magic;
+ size_t page_size;
+ size_t granularity;
+ size_t mmap_threshold;
+ size_t trim_threshold;
+ flag_t default_mflags;
+};
+
+static struct malloc_params mparams;
+
+/* Ensure mparams initialized */
+#define ensure_initialization() (void)(mparams.magic != 0 || init_mparams())
+
+/* -------------------------- MMAP preliminaries ------------------------- */
+
+/*
+ If HAVE_MORECORE or HAVE_MMAP are false, we just define calls and
+ checks to fail so compiler optimizer can delete code rather than
+ using so many "#if"s.
+*/
+
+
+/* MORECORE and MMAP must return MFAIL on failure */
+#define MFAIL ((void*)(MAX_SIZE_T))
+#define CMFAIL ((char*)(MFAIL)) /* defined for convenience */
+
+#if HAVE_MMAP
+
+#ifndef WIN32
+#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
+#define MAP_ANONYMOUS MAP_ANON
+#endif /* MAP_ANON */
+#ifdef DEFAULT_GRANULARITY_ALIGNED
+#define MMAP_IMPL mmap_aligned
+static void* lastAlignedmmap; /* Used as a hint */
+static void* mmap_aligned(void *start, size_t length, int prot, int flags, int fd, off_t offset) {
+ void* baseaddress = 0;
+ void* ptr = 0;
+ if(!start) {
+ baseaddress = lastAlignedmmap;
+ for(;;) {
+ if(baseaddress) flags|=MAP_FIXED;
+ ptr = mmap(baseaddress, length, prot, flags, fd, offset);
+ if(!ptr)
+ baseaddress = (void*)((size_t)baseaddress + mparams.granularity);
+ else if((size_t)ptr & (mparams.granularity - SIZE_T_ONE)) {
+ munmap(ptr, length);
+ baseaddress = (void*)(((size_t)ptr + mparams.granularity) & ~(mparams.granularity - SIZE_T_ONE));
+ }
+ else break;
+ }
+ }
+ else ptr = mmap(start, length, prot, flags, fd, offset);
+ if(ptr) lastAlignedmmap = (void*)((size_t) ptr + mparams.granularity);
+ return ptr;
+}
+#else
+#define MMAP_IMPL mmap
+#endif /* DEFAULT_GRANULARITY_ALIGNED */
+#define MUNMAP_DEFAULT(a, s) munmap((a), (s))
+#define MMAP_PROT (PROT_READ|PROT_WRITE)
+#ifdef MAP_ANONYMOUS
+#define MMAP_FLAGS (MAP_PRIVATE|MAP_ANONYMOUS)
+#define MMAP_DEFAULT(s) MMAP_IMPL(0, (s), MMAP_PROT, MMAP_FLAGS, -1, 0)
+#else /* MAP_ANONYMOUS */
+/*
+ Nearly all versions of mmap support MAP_ANONYMOUS, so the following
+ is unlikely to be needed, but is supplied just in case.
+*/
+#define MMAP_FLAGS (MAP_PRIVATE)
+static int dev_zero_fd = -1; /* Cached file descriptor for /dev/zero. */
+#define MMAP_DEFAULT(s) ((dev_zero_fd < 0) ? \
+ (dev_zero_fd = open("/dev/zero", O_RDWR), \
+ MMAP_IMPL(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0)) : \
+ MMAP_IMPL(0, (s), MMAP_PROT, MMAP_FLAGS, dev_zero_fd, 0))
+#endif /* MAP_ANONYMOUS */
+
+#define DIRECT_MMAP_DEFAULT(s) MMAP_DEFAULT(s)
+
+#else /* WIN32 */
+
+/* Win32 MMAP via VirtualAlloc */
+#ifdef DEFAULT_GRANULARITY_ALIGNED
+static void* lastWin32mmap; /* Used as a hint */
+#endif /* DEFAULT_GRANULARITY_ALIGNED */
+#ifdef ENABLE_LARGE_PAGES
+static int largepagesavailable = 1;
+#endif /* ENABLE_LARGE_PAGES */
+static FORCEINLINE void* win32mmap(size_t size) {
+ void* baseaddress = 0;
+ void* ptr = 0;
+#ifdef ENABLE_LARGE_PAGES
+ /* Note that large pages are *always* allocated on a large page boundary.
+ If however granularity is small then don't waste a kernel call if size
+ isn't around the size of a large page */
+ if(largepagesavailable && size >= 1*1024*1024) {
+ ptr = VirtualAlloc(baseaddress, size, MEM_RESERVE|MEM_COMMIT|MEM_LARGE_PAGES, PAGE_READWRITE);
+ if(!ptr && ERROR_PRIVILEGE_NOT_HELD==GetLastError()) largepagesavailable=0;
+ }
+#endif
+ if(!ptr) {
+#ifdef DEFAULT_GRANULARITY_ALIGNED
+ /* We try to avoid overhead by speculatively reserving at aligned
+ addresses until we succeed */
+ baseaddress = lastWin32mmap;
+ for(;;) {
+ void* reserveaddr = VirtualAlloc(baseaddress, size, MEM_RESERVE, PAGE_READWRITE);
+ if(!reserveaddr)
+ baseaddress = (void*)((size_t)baseaddress + mparams.granularity);
+ else if((size_t)reserveaddr & (mparams.granularity - SIZE_T_ONE)) {
+ VirtualFree(reserveaddr, 0, MEM_RELEASE);
+ baseaddress = (void*)(((size_t)reserveaddr + mparams.granularity) & ~(mparams.granularity - SIZE_T_ONE));
+ }
+ else break;
+ }
+#endif
+ if(!ptr) ptr = VirtualAlloc(baseaddress, size, baseaddress ? MEM_COMMIT : MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
+#if DEBUG
+ if(lastWin32mmap && ptr!=lastWin32mmap) printf("Non-contiguous VirtualAlloc between %p and %p\n", ptr, lastWin32mmap);
+#endif
+#ifdef DEFAULT_GRANULARITY_ALIGNED
+ if(ptr) lastWin32mmap = (void*)((size_t) ptr + mparams.granularity);
+#endif
+ }
+#if DEBUG
+#ifdef ENABLE_LARGE_PAGES
+ printf("VirtualAlloc returns %p size %u. LargePagesAvailable=%d\n", ptr, size, largepagesavailable);
+#else
+ printf("VirtualAlloc returns %p size %u\n", ptr, size);
+#endif
+#endif
+ return (ptr != 0)? ptr: MFAIL;
+}
+
+/* For direct MMAP, use MEM_TOP_DOWN to minimize interference */
+static FORCEINLINE void* win32direct_mmap(size_t size) {
+ void* ptr = VirtualAlloc(0, size, MEM_RESERVE|MEM_COMMIT|MEM_TOP_DOWN,
+ PAGE_READWRITE);
+ return (ptr != 0)? ptr: MFAIL;
+}
+
+/* This function supports releasing coalesed segments */
+static FORCEINLINE int win32munmap(void* ptr, size_t size) {
+ MEMORY_BASIC_INFORMATION minfo;
+ char* cptr = (char*)ptr;
+ while (size) {
+ if (VirtualQuery(cptr, &minfo, sizeof(minfo)) == 0)
+ return -1;
+ if (minfo.BaseAddress != cptr || minfo.AllocationBase != cptr ||
+ minfo.State != MEM_COMMIT || minfo.RegionSize > size)
+ return -1;
+ if (VirtualFree(cptr, 0, MEM_RELEASE) == 0)
+ return -1;
+ cptr += minfo.RegionSize;
+ size -= minfo.RegionSize;
+ }
+ return 0;
+}
+
+#define MMAP_DEFAULT(s) win32mmap(s)
+#define MUNMAP_DEFAULT(a, s) win32munmap((a), (s))
+#define DIRECT_MMAP_DEFAULT(s) win32direct_mmap(s)
+#endif /* WIN32 */
+#endif /* HAVE_MMAP */
+
+#if HAVE_MREMAP
+#ifndef WIN32
+#define MREMAP_DEFAULT(addr, osz, nsz, mv) mremap((addr), (osz), (nsz), (mv))
+#endif /* WIN32 */
+#endif /* HAVE_MREMAP */
+
+
+/**
+ * Define CALL_MORECORE
+ */
+#if HAVE_MORECORE
+ #ifdef MORECORE
+ #define CALL_MORECORE(S) MORECORE(S)
+ #else /* MORECORE */
+ #define CALL_MORECORE(S) MORECORE_DEFAULT(S)
+ #endif /* MORECORE */
+#else /* HAVE_MORECORE */
+ #define CALL_MORECORE(S) MFAIL
+#endif /* HAVE_MORECORE */
+
+/**
+ * Define CALL_MMAP/CALL_MUNMAP/CALL_DIRECT_MMAP
+ */
+#if HAVE_MMAP
+ #define USE_MMAP_BIT (SIZE_T_ONE)
+
+ #ifdef MMAP
+ #define CALL_MMAP(s) MMAP(s)
+ #else /* MMAP */
+ #define CALL_MMAP(s) MMAP_DEFAULT(s)
+ #endif /* MMAP */
+ #ifdef MUNMAP
+ #define CALL_MUNMAP(a, s) MUNMAP((a), (s))
+ #else /* MUNMAP */
+ #define CALL_MUNMAP(a, s) MUNMAP_DEFAULT((a), (s))
+ #endif /* MUNMAP */
+ #ifdef DIRECT_MMAP
+ #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s)
+ #else /* DIRECT_MMAP */
+ #define CALL_DIRECT_MMAP(s) DIRECT_MMAP_DEFAULT(s)
+ #endif /* DIRECT_MMAP */
+#else /* HAVE_MMAP */
+ #define USE_MMAP_BIT (SIZE_T_ZERO)
+
+ #define MMAP(s) MFAIL
+ #define MUNMAP(a, s) (-1)
+ #define DIRECT_MMAP(s) MFAIL
+ #define CALL_DIRECT_MMAP(s) DIRECT_MMAP(s)
+ #define CALL_MMAP(s) MMAP(s)
+ #define CALL_MUNMAP(a, s) MUNMAP((a), (s))
+#endif /* HAVE_MMAP */
+
+/**
+ * Define CALL_MREMAP
+ */
+#if HAVE_MMAP && HAVE_MREMAP
+ #ifdef MREMAP
+ #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP((addr), (osz), (nsz), (mv))
+ #else /* MREMAP */
+ #define CALL_MREMAP(addr, osz, nsz, mv) MREMAP_DEFAULT((addr), (osz), (nsz), (mv))
+ #endif /* MREMAP */
+#else /* HAVE_MMAP && HAVE_MREMAP */
+ #define CALL_MREMAP(addr, osz, nsz, mv) MFAIL
+#endif /* HAVE_MMAP && HAVE_MREMAP */
+
+/* mstate bit set if continguous morecore disabled or failed */
+#define USE_NONCONTIGUOUS_BIT (4U)
+
+/* segment bit set in create_mspace_with_base */
+#define EXTERN_BIT (8U)
+
+
+/* --------------------------- Lock preliminaries ------------------------ */
+
+/*
+ When locks are defined, there is one global lock, plus
+ one per-mspace lock.
+
+ The global lock_ensures that mparams.magic and other unique
+ mparams values are initialized only once. It also protects
+ sequences of calls to MORECORE. In many cases sys_alloc requires
+ two calls, that should not be interleaved with calls by other
+ threads. This does not protect against direct calls to MORECORE
+ by other threads not using this lock, so there is still code to
+ cope the best we can on interference.
+
+ Per-mspace locks surround calls to malloc, free, etc. To enable use
+ in layered extensions, per-mspace locks are reentrant.
+
+ Because lock-protected regions generally have bounded times, it is
+ OK to use the supplied simple spinlocks in the custom versions for
+ x86. Spinlocks are likely to improve performance for lightly
+ contended applications, but worsen performance under heavy
+ contention.
+
+ If USE_LOCKS is > 1, the definitions of lock routines here are
+ bypassed, in which case you will need to define the type MLOCK_T,
+ and at least INITIAL_LOCK, ACQUIRE_LOCK, RELEASE_LOCK and possibly
+ TRY_LOCK (which is not used in this malloc, but commonly needed in
+ extensions.) You must also declare a
+ static MLOCK_T malloc_global_mutex = { initialization values };.
+
+*/
+
+#if USE_LOCKS == 1
+
+#if USE_SPIN_LOCKS && SPIN_LOCKS_AVAILABLE
+#ifndef WIN32
+
+/* Custom pthread-style spin locks on x86 and x64 for gcc */
+struct pthread_mlock_t {
+ volatile unsigned int l;
+ char cachelinepadding[64];
+ unsigned int c;
+ pthread_t threadid;
+};
+#define MLOCK_T struct pthread_mlock_t
+#define CURRENT_THREAD pthread_self()
+#define INITIAL_LOCK(sl) ((sl)->threadid = 0, (sl)->l = (sl)->c = 0, 0)
+#define ACQUIRE_LOCK(sl) pthread_acquire_lock(sl)
+#define RELEASE_LOCK(sl) pthread_release_lock(sl)
+#define TRY_LOCK(sl) pthread_try_lock(sl)
+#define SPINS_PER_YIELD 63
+
+static MLOCK_T malloc_global_mutex = { 0, "", 0, 0};
+
+static FORCEINLINE int pthread_acquire_lock (MLOCK_T *sl) {
+ int spins = 0;
+ volatile unsigned int* lp = &sl->l;
+ for (;;) {
+ if (*lp != 0) {
+ if (sl->threadid == CURRENT_THREAD) {
+ ++sl->c;
+ return 0;
+ }
+ }
+ else {
+ /* place args to cmpxchgl in locals to evade oddities in some gccs */
+ int cmp = 0;
+ int val = 1;
+ int ret;
+ __asm__ __volatile__ ("lock; cmpxchgl %1, %2"
+ : "=a" (ret)
+ : "r" (val), "m" (*(lp)), "0"(cmp)
+ : "memory", "cc");
+ if (!ret) {
+ assert(!sl->threadid);
+ sl->threadid = CURRENT_THREAD;
+ sl->c = 1;
+ return 0;
+ }
+ }
+ if ((++spins & SPINS_PER_YIELD) == 0) {
+#if defined (__SVR4) && defined (__sun) /* solaris */
+ thr_yield();
+#else
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
+ sched_yield();
+#else /* no-op yield on unknown systems */
+ ;
+#endif /* __linux__ || __FreeBSD__ || __APPLE__ */
+#endif /* solaris */
+ }
+ }
+}
+
+static FORCEINLINE void pthread_release_lock (MLOCK_T *sl) {
+ volatile unsigned int* lp = &sl->l;
+ assert(*lp != 0);
+ assert(sl->threadid == CURRENT_THREAD);
+ if (--sl->c == 0) {
+ sl->threadid = 0;
+ int prev = 0;
+ int ret;
+ __asm__ __volatile__ ("lock; xchgl %0, %1"
+ : "=r" (ret)
+ : "m" (*(lp)), "0"(prev)
+ : "memory");
+ }
+}
+
+static FORCEINLINE int pthread_try_lock (MLOCK_T *sl) {
+ volatile unsigned int* lp = &sl->l;
+ if (*lp != 0) {
+ if (sl->threadid == CURRENT_THREAD) {
+ ++sl->c;
+ return 1;
+ }
+ }
+ else {
+ int cmp = 0;
+ int val = 1;
+ int ret;
+ __asm__ __volatile__ ("lock; cmpxchgl %1, %2"
+ : "=a" (ret)
+ : "r" (val), "m" (*(lp)), "0"(cmp)
+ : "memory", "cc");
+ if (!ret) {
+ assert(!sl->threadid);
+ sl->threadid = CURRENT_THREAD;
+ sl->c = 1;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+#else /* WIN32 */
+/* Custom win32-style spin locks on x86 and x64 for MSC */
+struct win32_mlock_t {
+ volatile long l;
+ char cachelinepadding[64];
+ unsigned int c;
+ long threadid;
+};
+
+#define MLOCK_T struct win32_mlock_t
+#define CURRENT_THREAD ((long)GetCurrentThreadId())
+#define INITIAL_LOCK(sl) ((sl)->threadid = 0, (sl)->l = (sl)->c = 0, 0)
+#define ACQUIRE_LOCK(sl) win32_acquire_lock(sl)
+#define RELEASE_LOCK(sl) win32_release_lock(sl)
+#define TRY_LOCK(sl) win32_try_lock(sl)
+#define SPINS_PER_YIELD 63
+
+static MLOCK_T malloc_global_mutex = { 0, 0, 0};
+
+static FORCEINLINE int win32_acquire_lock (MLOCK_T *sl) {
+ int spins = 0;
+ for (;;) {
+ if (sl->l != 0) {
+ if (sl->threadid == CURRENT_THREAD) {
+ ++sl->c;
+ return 0;
+ }
+ }
+ else {
+ if (!interlockedexchange(&sl->l, 1)) {
+ assert(!sl->threadid);
+ sl->threadid = CURRENT_THREAD;
+ sl->c = 1;
+ return 0;
+ }
+ }
+ if ((++spins & SPINS_PER_YIELD) == 0)
+ SleepEx(0, FALSE);
+ }
+}
+
+static FORCEINLINE void win32_release_lock (MLOCK_T *sl) {
+ assert(sl->threadid == CURRENT_THREAD);
+ assert(sl->l != 0);
+ if (--sl->c == 0) {
+ sl->threadid = 0;
+ interlockedexchange (&sl->l, 0);
+ }
+}
+
+static FORCEINLINE int win32_try_lock (MLOCK_T *sl) {
+ if (sl->l != 0) {
+ if (sl->threadid == CURRENT_THREAD) {
+ ++sl->c;
+ return 1;
+ }
+ }
+ else {
+ if (!interlockedexchange(&sl->l, 1)){
+ assert(!sl->threadid);
+ sl->threadid = CURRENT_THREAD;
+ sl->c = 1;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+#endif /* WIN32 */
+#else /* USE_SPIN_LOCKS */
+
+#ifndef WIN32
+/* pthreads-based locks */
+
+#define MLOCK_T pthread_mutex_t
+#define CURRENT_THREAD pthread_self()
+#define INITIAL_LOCK(sl) pthread_init_lock(sl)
+#define ACQUIRE_LOCK(sl) pthread_mutex_lock(sl)
+#define RELEASE_LOCK(sl) pthread_mutex_unlock(sl)
+#define TRY_LOCK(sl) (!pthread_mutex_trylock(sl))
+
+static MLOCK_T malloc_global_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* Cope with old-style linux recursive lock initialization by adding */
+/* skipped internal declaration from pthread.h */
+#ifdef linux
+#ifndef PTHREAD_MUTEX_RECURSIVE
+extern int pthread_mutexattr_setkind_np __P ((pthread_mutexattr_t *__attr,
+ int __kind));
+#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
+#define pthread_mutexattr_settype(x,y) pthread_mutexattr_setkind_np(x,y)
+#endif
+#endif
+
+static int pthread_init_lock (MLOCK_T *sl) {
+ pthread_mutexattr_t attr;
+ if (pthread_mutexattr_init(&attr)) return 1;
+ if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) return 1;
+ if (pthread_mutex_init(sl, &attr)) return 1;
+ if (pthread_mutexattr_destroy(&attr)) return 1;
+ return 0;
+}
+
+#else /* WIN32 */
+/* Win32 critical sections */
+#define MLOCK_T CRITICAL_SECTION
+#define CURRENT_THREAD GetCurrentThreadId()
+#define INITIAL_LOCK(s) (!InitializeCriticalSectionAndSpinCount((s), 0x80000000|4000))
+#define ACQUIRE_LOCK(s) (EnterCriticalSection(sl), 0)
+#define RELEASE_LOCK(s) LeaveCriticalSection(sl)
+#define TRY_LOCK(s) TryEnterCriticalSection(sl)
+#define NEED_GLOBAL_LOCK_INIT
+
+static MLOCK_T malloc_global_mutex;
+static volatile long malloc_global_mutex_status;
+
+/* Use spin loop to initialize global lock */
+static void init_malloc_global_mutex() {
+ for (;;) {
+ long stat = malloc_global_mutex_status;
+ if (stat > 0)
+ return;
+ /* transition to < 0 while initializing, then to > 0) */
+ if (stat == 0 &&
+ interlockedcompareexchange(&malloc_global_mutex_status, -1, 0) == 0) {
+ InitializeCriticalSection(&malloc_global_mutex);
+ interlockedexchange(&malloc_global_mutex_status,1);
+ return;
+ }
+ SleepEx(0, FALSE);
+ }
+}
+
+#endif /* WIN32 */
+#endif /* USE_SPIN_LOCKS */
+#endif /* USE_LOCKS == 1 */
+
+/* ----------------------- User-defined locks ------------------------ */
+
+#if USE_LOCKS > 1
+/* Define your own lock implementation here */
+/* #define INITIAL_LOCK(sl) ... */
+/* #define ACQUIRE_LOCK(sl) ... */
+/* #define RELEASE_LOCK(sl) ... */
+/* #define TRY_LOCK(sl) ... */
+/* static MLOCK_T malloc_global_mutex = ... */
+#endif /* USE_LOCKS > 1 */
+
+/* ----------------------- Lock-based state ------------------------ */
+
+#if USE_LOCKS
+#define USE_LOCK_BIT (2U)
+#else /* USE_LOCKS */
+#define USE_LOCK_BIT (0U)
+#define INITIAL_LOCK(l)
+#endif /* USE_LOCKS */
+
+#if USE_LOCKS
+#ifndef ACQUIRE_MALLOC_GLOBAL_LOCK
+#define ACQUIRE_MALLOC_GLOBAL_LOCK() ACQUIRE_LOCK(&malloc_global_mutex);
+#endif
+#ifndef RELEASE_MALLOC_GLOBAL_LOCK
+#define RELEASE_MALLOC_GLOBAL_LOCK() RELEASE_LOCK(&malloc_global_mutex);
+#endif
+#else /* USE_LOCKS */
+#define ACQUIRE_MALLOC_GLOBAL_LOCK()
+#define RELEASE_MALLOC_GLOBAL_LOCK()
+#endif /* USE_LOCKS */
+
+
+/* ----------------------- Chunk representations ------------------------ */
+
+/*
+ (The following includes lightly edited explanations by Colin Plumb.)
+
+ The malloc_chunk declaration below is misleading (but accurate and
+ necessary). It declares a "view" into memory allowing access to
+ necessary fields at known offsets from a given base.
+
+ Chunks of memory are maintained using a `boundary tag' method as
+ originally described by Knuth. (See the paper by Paul Wilson
+ ftp://ftp.cs.utexas.edu/pub/garbage/allocsrv.ps for a survey of such
+ techniques.) Sizes of free chunks are stored both in the front of
+ each chunk and at the end. This makes consolidating fragmented
+ chunks into bigger chunks fast. The head fields also hold bits
+ representing whether chunks are free or in use.
+
+ Here are some pictures to make it clearer. They are "exploded" to
+ show that the state of a chunk can be thought of as extending from
+ the high 31 bits of the head field of its header through the
+ prev_foot and PINUSE_BIT bit of the following chunk header.
+
+ A chunk that's in use looks like:
+
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of previous chunk (if P = 0) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|
+ | Size of this chunk 1| +-+
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ +- -+
+ | |
+ +- -+
+ | :
+ +- size - sizeof(size_t) available payload bytes -+
+ : |
+ chunk-> +- -+
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |1|
+ | Size of next chunk (may or may not be in use) | +-+
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ And if it's free, it looks like this:
+
+ chunk-> +- -+
+ | User payload (must be in use, or we would have merged!) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |P|
+ | Size of this chunk 0| +-+
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Next pointer |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Prev pointer |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | :
+ +- size - sizeof(struct chunk) unused bytes -+
+ : |
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of this chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |0|
+ | Size of next chunk (must be in use, or we would have merged)| +-+
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | :
+ +- User payload -+
+ : |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |0|
+ +-+
+ Note that since we always merge adjacent free chunks, the chunks
+ adjacent to a free chunk must be in use.
+
+ Given a pointer to a chunk (which can be derived trivially from the
+ payload pointer) we can, in O(1) time, find out whether the adjacent
+ chunks are free, and if so, unlink them from the lists that they
+ are on and merge them with the current chunk.
+
+ Chunks always begin on even word boundaries, so the mem portion
+ (which is returned to the user) is also on an even word boundary, and
+ thus at least double-word aligned.
+
+ The P (PINUSE_BIT) bit, stored in the unused low-order bit of the
+ chunk size (which is always a multiple of two words), is an in-use
+ bit for the *previous* chunk. If that bit is *clear*, then the
+ word before the current chunk size contains the previous chunk
+ size, and can be used to find the front of the previous chunk.
+ The very first chunk allocated always has this bit set, preventing
+ access to non-existent (or non-owned) memory. If pinuse is set for
+ any given chunk, then you CANNOT determine the size of the
+ previous chunk, and might even get a memory addressing fault when
+ trying to do so.
+
+ The C (CINUSE_BIT) bit, stored in the unused second-lowest bit of
+ the chunk size redundantly records whether the current chunk is
+ inuse (unless the chunk is mmapped). This redundancy enables usage
+ checks within free and realloc, and reduces indirection when freeing
+ and consolidating chunks.
+
+ Each freshly allocated chunk must have both cinuse and pinuse set.
+ That is, each allocated chunk borders either a previously allocated
+ and still in-use chunk, or the base of its memory arena. This is
+ ensured by making all allocations from the the `lowest' part of any
+ found chunk. Further, no free chunk physically borders another one,
+ so each free chunk is known to be preceded and followed by either
+ inuse chunks or the ends of memory.
+
+ Note that the `foot' of the current chunk is actually represented
+ as the prev_foot of the NEXT chunk. This makes it easier to
+ deal with alignments etc but can be very confusing when trying
+ to extend or adapt this code.
+
+ The exceptions to all this are
+
+ 1. The special chunk `top' is the top-most available chunk (i.e.,
+ the one bordering the end of available memory). It is treated
+ specially. Top is never included in any bin, is used only if
+ no other chunk is available, and is released back to the
+ system if it is very large (see M_TRIM_THRESHOLD). In effect,
+ the top chunk is treated as larger (and thus less well
+ fitting) than any other available chunk. The top chunk
+ doesn't update its trailing size field since there is no next
+ contiguous chunk that would have to index off it. However,
+ space is still allocated for it (TOP_FOOT_SIZE) to enable
+ separation or merging when space is extended.
+
+ 3. Chunks allocated via mmap, have both cinuse and pinuse bits
+ cleared in their head fields. Because they are allocated
+ one-by-one, each must carry its own prev_foot field, which is
+ also used to hold the offset this chunk has within its mmapped
+ region, which is needed to preserve alignment. Each mmapped
+ chunk is trailed by the first two fields of a fake next-chunk
+ for sake of usage checks.
+
+*/
+
+struct malloc_chunk {
+ size_t prev_foot; /* Size of previous chunk (if free). */
+ size_t head; /* Size and inuse bits. */
+ struct malloc_chunk* fd; /* double links -- used only if free. */
+ struct malloc_chunk* bk;
+};
+
+typedef struct malloc_chunk mchunk;
+typedef struct malloc_chunk* mchunkptr;
+typedef struct malloc_chunk* sbinptr; /* The type of bins of chunks */
+typedef unsigned int bindex_t; /* Described below */
+typedef unsigned int binmap_t; /* Described below */
+
+/* ------------------- Chunks sizes and alignments ----------------------- */
+
+#define MCHUNK_SIZE (sizeof(mchunk))
+
+#if FOOTERS
+#define CHUNK_OVERHEAD (TWO_SIZE_T_SIZES)
+#else /* FOOTERS */
+#define CHUNK_OVERHEAD (SIZE_T_SIZE)
+#endif /* FOOTERS */
+
+/* MMapped chunks need a second word of overhead ... */
+#define MMAP_CHUNK_OVERHEAD (TWO_SIZE_T_SIZES)
+/* ... and additional padding for fake next-chunk at foot */
+#define MMAP_FOOT_PAD (FOUR_SIZE_T_SIZES)
+
+/* The smallest size we can malloc is an aligned minimal chunk */
+#define MIN_CHUNK_SIZE\
+ ((MCHUNK_SIZE + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)
+
+/* conversion from malloc headers to user pointers, and back */
+#define chunk2mem(p) ((void*)((char*)(p) + TWO_SIZE_T_SIZES))
+#define mem2chunk(mem) ((mchunkptr)((char*)(mem) - TWO_SIZE_T_SIZES))
+/* chunk associated with aligned address A */
+#define align_as_chunk(A) (mchunkptr)((A) + align_offset(chunk2mem(A)))
+
+/* Bounds on request (not chunk) sizes. */
+#define MAX_REQUEST ((-MIN_CHUNK_SIZE) << 2)
+#define MIN_REQUEST (MIN_CHUNK_SIZE - CHUNK_OVERHEAD - SIZE_T_ONE)
+
+/* pad request bytes into a usable size */
+#define pad_request(req) \
+ (((req) + CHUNK_OVERHEAD + CHUNK_ALIGN_MASK) & ~CHUNK_ALIGN_MASK)
+
+/* pad request, checking for minimum (but not maximum) */
+#define request2size(req) \
+ (((req) < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(req))
+
+
+/* ------------------ Operations on head and foot fields ----------------- */
+
+/*
+ The head field of a chunk is or'ed with PINUSE_BIT when previous
+ adjacent chunk in use, and or'ed with CINUSE_BIT if this chunk is in
+ use, unless mmapped, in which case both bits are cleared.
+
+ FLAG4_BIT is not used by this malloc, but might be useful in extensions.
+*/
+
+#define PINUSE_BIT (SIZE_T_ONE)
+#define CINUSE_BIT (SIZE_T_TWO)
+#define FLAG4_BIT (SIZE_T_FOUR)
+#define INUSE_BITS (PINUSE_BIT|CINUSE_BIT)
+#define FLAG_BITS (PINUSE_BIT|CINUSE_BIT|FLAG4_BIT)
+
+/* Head value for fenceposts */
+#define FENCEPOST_HEAD (INUSE_BITS|SIZE_T_SIZE)
+
+/* extraction of fields from head words */
+#define cinuse(p) ((p)->head & CINUSE_BIT)
+#define pinuse(p) ((p)->head & PINUSE_BIT)
+#define is_inuse(p) (((p)->head & INUSE_BITS) != PINUSE_BIT)
+#define is_mmapped(p) (((p)->head & INUSE_BITS) == 0)
+
+#define chunksize(p) ((p)->head & ~(FLAG_BITS))
+
+#define clear_pinuse(p) ((p)->head &= ~PINUSE_BIT)
+
+/* Treat space at ptr +/- offset as a chunk */
+#define chunk_plus_offset(p, s) ((mchunkptr)(((char*)(p)) + (s)))
+#define chunk_minus_offset(p, s) ((mchunkptr)(((char*)(p)) - (s)))
+
+/* Ptr to next or previous physical malloc_chunk. */
+#define next_chunk(p) ((mchunkptr)( ((char*)(p)) + ((p)->head & ~FLAG_BITS)))
+#define prev_chunk(p) ((mchunkptr)( ((char*)(p)) - ((p)->prev_foot) ))
+
+/* extract next chunk's pinuse bit */
+#define next_pinuse(p) ((next_chunk(p)->head) & PINUSE_BIT)
+
+/* Get/set size at footer */
+#define get_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot)
+#define set_foot(p, s) (((mchunkptr)((char*)(p) + (s)))->prev_foot = (s))
+
+/* Set size, pinuse bit, and foot */
+#define set_size_and_pinuse_of_free_chunk(p, s)\
+ ((p)->head = (s|PINUSE_BIT), set_foot(p, s))
+
+/* Set size, pinuse bit, foot, and clear next pinuse */
+#define set_free_with_pinuse(p, s, n)\
+ (clear_pinuse(n), set_size_and_pinuse_of_free_chunk(p, s))
+
+/* Get the internal overhead associated with chunk p */
+#define overhead_for(p)\
+ (is_mmapped(p)? MMAP_CHUNK_OVERHEAD : CHUNK_OVERHEAD)
+
+/* Return true if malloced space is not necessarily cleared */
+#if MMAP_CLEARS
+#define calloc_must_clear(p) (!is_mmapped(p))
+#else /* MMAP_CLEARS */
+#define calloc_must_clear(p) (1)
+#endif /* MMAP_CLEARS */
+
+/* ---------------------- Overlaid data structures ----------------------- */
+
+/*
+ When chunks are not in use, they are treated as nodes of either
+ lists or trees.
+
+ "Small" chunks are stored in circular doubly-linked lists, and look
+ like this:
+
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of previous chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `head:' | Size of chunk, in bytes |P|
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Forward pointer to next chunk in list |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Back pointer to previous chunk in list |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Unused space (may be 0 bytes long) .
+ . .
+ . |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `foot:' | Size of chunk, in bytes |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ Larger chunks are kept in a form of bitwise digital trees (aka
+ tries) keyed on chunksizes. Because malloc_tree_chunks are only for
+ free chunks greater than 256 bytes, their size doesn't impose any
+ constraints on user chunk sizes. Each node looks like:
+
+ chunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Size of previous chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `head:' | Size of chunk, in bytes |P|
+ mem-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Forward pointer to next chunk of same size |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Back pointer to previous chunk of same size |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Pointer to left child (child[0]) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Pointer to right child (child[1]) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Pointer to parent |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | bin index of this chunk |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Unused space .
+ . |
+nextchunk-> +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ `foot:' | Size of chunk, in bytes |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+ Each tree holding treenodes is a tree of unique chunk sizes. Chunks
+ of the same size are arranged in a circularly-linked list, with only
+ the oldest chunk (the next to be used, in our FIFO ordering)
+ actually in the tree. (Tree members are distinguished by a non-null
+ parent pointer.) If a chunk with the same size an an existing node
+ is inserted, it is linked off the existing node using pointers that
+ work in the same way as fd/bk pointers of small chunks.
+
+ Each tree contains a power of 2 sized range of chunk sizes (the
+ smallest is 0x100 <= x < 0x180), which is is divided in half at each
+ tree level, with the chunks in the smaller half of the range (0x100
+ <= x < 0x140 for the top nose) in the left subtree and the larger
+ half (0x140 <= x < 0x180) in the right subtree. This is, of course,
+ done by inspecting individual bits.
+
+ Using these rules, each node's left subtree contains all smaller
+ sizes than its right subtree. However, the node at the root of each
+ subtree has no particular ordering relationship to either. (The
+ dividing line between the subtree sizes is based on trie relation.)
+ If we remove the last chunk of a given size from the interior of the
+ tree, we need to replace it with a leaf node. The tree ordering
+ rules permit a node to be replaced by any leaf below it.
+
+ The smallest chunk in a tree (a common operation in a best-fit
+ allocator) can be found by walking a path to the leftmost leaf in
+ the tree. Unlike a usual binary tree, where we follow left child
+ pointers until we reach a null, here we follow the right child
+ pointer any time the left one is null, until we reach a leaf with
+ both child pointers null. The smallest chunk in the tree will be
+ somewhere along that path.
+
+ The worst case number of steps to add, find, or remove a node is
+ bounded by the number of bits differentiating chunks within
+ bins. Under current bin calculations, this ranges from 6 up to 21
+ (for 32 bit sizes) or up to 53 (for 64 bit sizes). The typical case
+ is of course much better.
+*/
+
+struct malloc_tree_chunk {
+ /* The first four fields must be compatible with malloc_chunk */
+ size_t prev_foot;
+ size_t head;
+ struct malloc_tree_chunk* fd;
+ struct malloc_tree_chunk* bk;
+
+ struct malloc_tree_chunk* child[2];
+ struct malloc_tree_chunk* parent;
+ bindex_t index;
+};
+
+typedef struct malloc_tree_chunk tchunk;
+typedef struct malloc_tree_chunk* tchunkptr;
+typedef struct malloc_tree_chunk* tbinptr; /* The type of bins of trees */
+
+/* A little helper macro for trees */
+#define leftmost_child(t) ((t)->child[0] != 0? (t)->child[0] : (t)->child[1])
+
+/* ----------------------------- Segments -------------------------------- */
+
+/*
+ Each malloc space may include non-contiguous segments, held in a
+ list headed by an embedded malloc_segment record representing the
+ top-most space. Segments also include flags holding properties of
+ the space. Large chunks that are directly allocated by mmap are not
+ included in this list. They are instead independently created and
+ destroyed without otherwise keeping track of them.
+
+ Segment management mainly comes into play for spaces allocated by
+ MMAP. Any call to MMAP might or might not return memory that is
+ adjacent to an existing segment. MORECORE normally contiguously
+ extends the current space, so this space is almost always adjacent,
+ which is simpler and faster to deal with. (This is why MORECORE is
+ used preferentially to MMAP when both are available -- see
+ sys_alloc.) When allocating using MMAP, we don't use any of the
+ hinting mechanisms (inconsistently) supported in various
+ implementations of unix mmap, or distinguish reserving from
+ committing memory. Instead, we just ask for space, and exploit
+ contiguity when we get it. It is probably possible to do
+ better than this on some systems, but no general scheme seems
+ to be significantly better.
+
+ Management entails a simpler variant of the consolidation scheme
+ used for chunks to reduce fragmentation -- new adjacent memory is
+ normally prepended or appended to an existing segment. However,
+ there are limitations compared to chunk consolidation that mostly
+ reflect the fact that segment processing is relatively infrequent
+ (occurring only when getting memory from system) and that we
+ don't expect to have huge numbers of segments:
+
+ * Segments are not indexed, so traversal requires linear scans. (It
+ would be possible to index these, but is not worth the extra
+ overhead and complexity for most programs on most platforms.)
+ * New segments are only appended to old ones when holding top-most
+ memory; if they cannot be prepended to others, they are held in
+ different segments.
+
+ Except for the top-most segment of an mstate, each segment record
+ is kept at the tail of its segment. Segments are added by pushing
+ segment records onto the list headed by &mstate.seg for the
+ containing mstate.
+
+ Segment flags control allocation/merge/deallocation policies:
+ * If EXTERN_BIT set, then we did not allocate this segment,
+ and so should not try to deallocate or merge with others.
+ (This currently holds only for the initial segment passed
+ into create_mspace_with_base.)
+ * If USE_MMAP_BIT set, the segment may be merged with
+ other surrounding mmapped segments and trimmed/de-allocated
+ using munmap.
+ * If neither bit is set, then the segment was obtained using
+ MORECORE so can be merged with surrounding MORECORE'd segments
+ and deallocated/trimmed using MORECORE with negative arguments.
+*/
+
+struct malloc_segment {
+ char* base; /* base address */
+ size_t size; /* allocated size */
+ struct malloc_segment* next; /* ptr to next segment */
+ flag_t sflags; /* mmap and extern flag */
+};
+
+#define is_mmapped_segment(S) ((S)->sflags & USE_MMAP_BIT)
+#define is_extern_segment(S) ((S)->sflags & EXTERN_BIT)
+
+typedef struct malloc_segment msegment;
+typedef struct malloc_segment* msegmentptr;
+
+/* ---------------------------- malloc_state ----------------------------- */
+
+/*
+ A malloc_state holds all of the bookkeeping for a space.
+ The main fields are:
+
+ Top
+ The topmost chunk of the currently active segment. Its size is
+ cached in topsize. The actual size of topmost space is
+ topsize+TOP_FOOT_SIZE, which includes space reserved for adding
+ fenceposts and segment records if necessary when getting more
+ space from the system. The size at which to autotrim top is
+ cached from mparams in trim_check, except that it is disabled if
+ an autotrim fails.
+
+ Designated victim (dv)
+ This is the preferred chunk for servicing small requests that
+ don't have exact fits. It is normally the chunk split off most
+ recently to service another small request. Its size is cached in
+ dvsize. The link fields of this chunk are not maintained since it
+ is not kept in a bin.
+
+ SmallBins
+ An array of bin headers for free chunks. These bins hold chunks
+ with sizes less than MIN_LARGE_SIZE bytes. Each bin contains
+ chunks of all the same size, spaced 8 bytes apart. To simplify
+ use in double-linked lists, each bin header acts as a malloc_chunk
+ pointing to the real first node, if it exists (else pointing to
+ itself). This avoids special-casing for headers. But to avoid
+ waste, we allocate only the fd/bk pointers of bins, and then use
+ repositioning tricks to treat these as the fields of a chunk.
+
+ TreeBins
+ Treebins are pointers to the roots of trees holding a range of
+ sizes. There are 2 equally spaced treebins for each power of two
+ from TREE_SHIFT to TREE_SHIFT+16. The last bin holds anything
+ larger.
+
+ Bin maps
+ There is one bit map for small bins ("smallmap") and one for
+ treebins ("treemap). Each bin sets its bit when non-empty, and
+ clears the bit when empty. Bit operations are then used to avoid
+ bin-by-bin searching -- nearly all "search" is done without ever
+ looking at bins that won't be selected. The bit maps
+ conservatively use 32 bits per map word, even if on 64bit system.
+ For a good description of some of the bit-based techniques used
+ here, see Henry S. Warren Jr's book "Hacker's Delight" (and
+ supplement at http://hackersdelight.org/). Many of these are
+ intended to reduce the branchiness of paths through malloc etc, as
+ well as to reduce the number of memory locations read or written.
+
+ Segments
+ A list of segments headed by an embedded malloc_segment record
+ representing the initial space.
+
+ Address check support
+ The least_addr field is the least address ever obtained from
+ MORECORE or MMAP. Attempted frees and reallocs of any address less
+ than this are trapped (unless INSECURE is defined).
+
+ Magic tag
+ A cross-check field that should always hold same value as mparams.magic.
+
+ Flags
+ Bits recording whether to use MMAP, locks, or contiguous MORECORE
+
+ Statistics
+ Each space keeps track of current and maximum system memory
+ obtained via MORECORE or MMAP.
+
+ Trim support
+ Fields holding the amount of unused topmost memory that should trigger
+ timming, and a counter to force periodic scanning to release unused
+ non-topmost segments.
+
+ Locking
+ If USE_LOCKS is defined, the "mutex" lock is acquired and released
+ around every public call using this mspace.
+
+ Extension support
+ A void* pointer and a size_t field that can be used to help implement
+ extensions to this malloc.
+*/
+
+/* Bin types, widths and sizes */
+#define NSMALLBINS (32U)
+#define NTREEBINS (32U)
+#define SMALLBIN_SHIFT (3U)
+#define SMALLBIN_WIDTH (SIZE_T_ONE << SMALLBIN_SHIFT)
+#define TREEBIN_SHIFT (8U)
+#define MIN_LARGE_SIZE (SIZE_T_ONE << TREEBIN_SHIFT)
+#define MAX_SMALL_SIZE (MIN_LARGE_SIZE - SIZE_T_ONE)
+#define MAX_SMALL_REQUEST (MAX_SMALL_SIZE - CHUNK_ALIGN_MASK - CHUNK_OVERHEAD)
+
+struct malloc_state {
+ binmap_t smallmap;
+ binmap_t treemap;
+ size_t dvsize;
+ size_t topsize;
+ char* least_addr;
+ mchunkptr dv;
+ mchunkptr top;
+ size_t trim_check;
+ size_t release_checks;
+ size_t magic;
+ mchunkptr smallbins[(NSMALLBINS+1)*2];
+ tbinptr treebins[NTREEBINS];
+ size_t footprint;
+ size_t max_footprint;
+ flag_t mflags;
+ msegment seg;
+#if USE_LOCKS
+ MLOCK_T mutex; /* locate lock among fields that rarely change */
+#endif /* USE_LOCKS */
+ void* extp; /* Unused but available for extensions */
+ size_t exts;
+};
+
+typedef struct malloc_state* mstate;
+
+/* ------------- Global malloc_state and malloc_params ------------------- */
+
+#if !ONLY_MSPACES
+
+/* The global malloc_state used for all non-"mspace" calls */
+static struct malloc_state _gm_;
+#define gm (&_gm_)
+#define is_global(M) ((M) == &_gm_)
+
+#endif /* !ONLY_MSPACES */
+
+#define is_initialized(M) ((M)->top != 0)
+
+/* -------------------------- system alloc setup ------------------------- */
+
+/* Operations on mflags */
+
+#define use_lock(M) ((M)->mflags & USE_LOCK_BIT)
+#define enable_lock(M) ((M)->mflags |= USE_LOCK_BIT)
+#define disable_lock(M) ((M)->mflags &= ~USE_LOCK_BIT)
+
+#define use_mmap(M) ((M)->mflags & USE_MMAP_BIT)
+#define enable_mmap(M) ((M)->mflags |= USE_MMAP_BIT)
+#define disable_mmap(M) ((M)->mflags &= ~USE_MMAP_BIT)
+
+#define use_noncontiguous(M) ((M)->mflags & USE_NONCONTIGUOUS_BIT)
+#define disable_contiguous(M) ((M)->mflags |= USE_NONCONTIGUOUS_BIT)
+
+#define set_lock(M,L)\
+ ((M)->mflags = (L)?\
+ ((M)->mflags | USE_LOCK_BIT) :\
+ ((M)->mflags & ~USE_LOCK_BIT))
+
+/* page-align a size */
+#define page_align(S)\
+ (((S) + (mparams.page_size - SIZE_T_ONE)) & ~(mparams.page_size - SIZE_T_ONE))
+
+/* granularity-align a size */
+#define granularity_align(S)\
+ (((S) + (mparams.granularity - SIZE_T_ONE))\
+ & ~(mparams.granularity - SIZE_T_ONE))
+
+
+/* For mmap, use granularity alignment on windows, else page-align */
+#ifdef WIN32
+#define mmap_align(S) granularity_align(S)
+#else
+#define mmap_align(S) page_align(S)
+#endif
+
+/* For sys_alloc, enough padding to ensure can malloc request on success */
+#define SYS_ALLOC_PADDING (TOP_FOOT_SIZE + MALLOC_ALIGNMENT)
+
+#define is_page_aligned(S)\
+ (((size_t)(S) & (mparams.page_size - SIZE_T_ONE)) == 0)
+#define is_granularity_aligned(S)\
+ (((size_t)(S) & (mparams.granularity - SIZE_T_ONE)) == 0)
+
+/* True if segment S holds address A */
+#define segment_holds(S, A)\
+ ((char*)(A) >= S->base && (char*)(A) < S->base + S->size)
+
+/* Return segment holding given address */
+static msegmentptr segment_holding(mstate m, char* addr) {
+ msegmentptr sp = &m->seg;
+ for (;;) {
+ if (addr >= sp->base && addr < sp->base + sp->size)
+ return sp;
+ if ((sp = sp->next) == 0)
+ return 0;
+ }
+}
+
+/* Return true if segment contains a segment link */
+static int has_segment_link(mstate m, msegmentptr ss) {
+ msegmentptr sp = &m->seg;
+ for (;;) {
+ if ((char*)sp >= ss->base && (char*)sp < ss->base + ss->size)
+ return 1;
+ if ((sp = sp->next) == 0)
+ return 0;
+ }
+}
+
+#ifndef MORECORE_CANNOT_TRIM
+#define should_trim(M,s) ((s) > (M)->trim_check)
+#else /* MORECORE_CANNOT_TRIM */
+#define should_trim(M,s) (0)
+#endif /* MORECORE_CANNOT_TRIM */
+
+/*
+ TOP_FOOT_SIZE is padding at the end of a segment, including space
+ that may be needed to place segment records and fenceposts when new
+ noncontiguous segments are added.
+*/
+#define TOP_FOOT_SIZE\
+ (align_offset(chunk2mem(0))+pad_request(sizeof(struct malloc_segment))+MIN_CHUNK_SIZE)
+
+
+/* ------------------------------- Hooks -------------------------------- */
+
+/*
+ PREACTION should be defined to return 0 on success, and nonzero on
+ failure. If you are not using locking, you can redefine these to do
+ anything you like.
+*/
+
+#if USE_LOCKS
+
+#define PREACTION(M) ((use_lock(M))? ACQUIRE_LOCK(&(M)->mutex) : 0)
+#define POSTACTION(M) { if (use_lock(M)) RELEASE_LOCK(&(M)->mutex); }
+#else /* USE_LOCKS */
+
+#ifndef PREACTION
+#define PREACTION(M) (0)
+#endif /* PREACTION */
+
+#ifndef POSTACTION
+#define POSTACTION(M)
+#endif /* POSTACTION */
+
+#endif /* USE_LOCKS */
+
+/*
+ CORRUPTION_ERROR_ACTION is triggered upon detected bad addresses.
+ USAGE_ERROR_ACTION is triggered on detected bad frees and
+ reallocs. The argument p is an address that might have triggered the
+ fault. It is ignored by the two predefined actions, but might be
+ useful in custom actions that try to help diagnose errors.
+*/
+
+#if PROCEED_ON_ERROR
+
+/* A count of the number of corruption errors causing resets */
+int malloc_corruption_error_count;
+
+/* default corruption action */
+static void reset_on_error(mstate m);
+
+#define CORRUPTION_ERROR_ACTION(m) reset_on_error(m)
+#define USAGE_ERROR_ACTION(m, p)
+
+#else /* PROCEED_ON_ERROR */
+
+#ifndef CORRUPTION_ERROR_ACTION
+#define CORRUPTION_ERROR_ACTION(m) ABORT
+#endif /* CORRUPTION_ERROR_ACTION */
+
+#ifndef USAGE_ERROR_ACTION
+#define USAGE_ERROR_ACTION(m,p) ABORT
+#endif /* USAGE_ERROR_ACTION */
+
+#endif /* PROCEED_ON_ERROR */
+
+/* -------------------------- Debugging setup ---------------------------- */
+
+#if ! DEBUG
+
+#define check_free_chunk(M,P)
+#define check_inuse_chunk(M,P)
+#define check_malloced_chunk(M,P,N)
+#define check_mmapped_chunk(M,P)
+#define check_malloc_state(M)
+#define check_top_chunk(M,P)
+
+#else /* DEBUG */
+#define check_free_chunk(M,P) do_check_free_chunk(M,P)
+#define check_inuse_chunk(M,P) do_check_inuse_chunk(M,P)
+#define check_top_chunk(M,P) do_check_top_chunk(M,P)
+#define check_malloced_chunk(M,P,N) do_check_malloced_chunk(M,P,N)
+#define check_mmapped_chunk(M,P) do_check_mmapped_chunk(M,P)
+#define check_malloc_state(M) do_check_malloc_state(M)
+
+static void do_check_any_chunk(mstate m, mchunkptr p);
+static void do_check_top_chunk(mstate m, mchunkptr p);
+static void do_check_mmapped_chunk(mstate m, mchunkptr p);
+static void do_check_inuse_chunk(mstate m, mchunkptr p);
+static void do_check_free_chunk(mstate m, mchunkptr p);
+static void do_check_malloced_chunk(mstate m, void* mem, size_t s);
+static void do_check_tree(mstate m, tchunkptr t);
+static void do_check_treebin(mstate m, bindex_t i);
+static void do_check_smallbin(mstate m, bindex_t i);
+static void do_check_malloc_state(mstate m);
+static int bin_find(mstate m, mchunkptr x);
+static size_t traverse_and_check(mstate m);
+#endif /* DEBUG */
+
+/* ---------------------------- Indexing Bins ---------------------------- */
+
+#define is_small(s) (((s) >> SMALLBIN_SHIFT) < NSMALLBINS)
+#define small_index(s) (bindex_t)((s) >> SMALLBIN_SHIFT)
+#define small_index2size(i) ((i) << SMALLBIN_SHIFT)
+#define MIN_SMALL_INDEX (small_index(MIN_CHUNK_SIZE))
+
+/* addressing by index. See above about smallbin repositioning */
+#define smallbin_at(M, i) ((sbinptr)((char*)&((M)->smallbins[(i)<<1])))
+#define treebin_at(M,i) (&((M)->treebins[i]))
+
+/* assign tree index for size S to variable I. Use x86 asm if possible */
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+#define compute_tree_index(S, I)\
+{\
+ unsigned int X = S >> TREEBIN_SHIFT;\
+ if (X == 0)\
+ I = 0;\
+ else if (X > 0xFFFF)\
+ I = NTREEBINS-1;\
+ else {\
+ unsigned int K;\
+ __asm__("bsrl\t%1, %0\n\t" : "=r" (K) : "g" (X));\
+ I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
+ }\
+}
+
+#elif defined (__INTEL_COMPILER)
+#define compute_tree_index(S, I)\
+{\
+ size_t X = S >> TREEBIN_SHIFT;\
+ if (X == 0)\
+ I = 0;\
+ else if (X > 0xFFFF)\
+ I = NTREEBINS-1;\
+ else {\
+ unsigned int K = _bit_scan_reverse (X); \
+ I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
+ }\
+}
+
+#elif defined(_MSC_VER) && _MSC_VER>=1300
+#define compute_tree_index(S, I)\
+{\
+ size_t X = S >> TREEBIN_SHIFT;\
+ if (X == 0)\
+ I = 0;\
+ else if (X > 0xFFFF)\
+ I = NTREEBINS-1;\
+ else {\
+ unsigned int K;\
+ _BitScanReverse((DWORD *) &K, (DWORD) X);\
+ I = (bindex_t)((K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1)));\
+ }\
+}
+
+#else /* GNUC */
+#define compute_tree_index(S, I)\
+{\
+ size_t X = S >> TREEBIN_SHIFT;\
+ if (X == 0)\
+ I = 0;\
+ else if (X > 0xFFFF)\
+ I = NTREEBINS-1;\
+ else {\
+ unsigned int Y = (unsigned int)X;\
+ unsigned int N = ((Y - 0x100) >> 16) & 8;\
+ unsigned int K = (((Y <<= N) - 0x1000) >> 16) & 4;\
+ N += K;\
+ N += K = (((Y <<= K) - 0x4000) >> 16) & 2;\
+ K = 14 - N + ((Y <<= K) >> 15);\
+ I = (K << 1) + ((S >> (K + (TREEBIN_SHIFT-1)) & 1));\
+ }\
+}
+#endif /* GNUC */
+
+/* Bit representing maximum resolved size in a treebin at i */
+#define bit_for_tree_index(i) \
+ (i == NTREEBINS-1)? (SIZE_T_BITSIZE-1) : (((i) >> 1) + TREEBIN_SHIFT - 2)
+
+/* Shift placing maximum resolved bit in a treebin at i as sign bit */
+#define leftshift_for_tree_index(i) \
+ ((i == NTREEBINS-1)? 0 : \
+ ((SIZE_T_BITSIZE-SIZE_T_ONE) - (((i) >> 1) + TREEBIN_SHIFT - 2)))
+
+/* The size of the smallest chunk held in bin with index i */
+#define minsize_for_tree_index(i) \
+ ((SIZE_T_ONE << (((i) >> 1) + TREEBIN_SHIFT)) | \
+ (((size_t)((i) & SIZE_T_ONE)) << (((i) >> 1) + TREEBIN_SHIFT - 1)))
+
+
+/* ------------------------ Operations on bin maps ----------------------- */
+
+/* bit corresponding to given index */
+#define idx2bit(i) ((binmap_t)(1) << (i))
+
+/* Mark/Clear bits with given index */
+#define mark_smallmap(M,i) ((M)->smallmap |= idx2bit(i))
+#define clear_smallmap(M,i) ((M)->smallmap &= ~idx2bit(i))
+#define smallmap_is_marked(M,i) ((M)->smallmap & idx2bit(i))
+
+#define mark_treemap(M,i) ((M)->treemap |= idx2bit(i))
+#define clear_treemap(M,i) ((M)->treemap &= ~idx2bit(i))
+#define treemap_is_marked(M,i) ((M)->treemap & idx2bit(i))
+
+/* isolate the least set bit of a bitmap */
+#define least_bit(x) ((x) & -(x))
+
+/* mask with all bits to left of least bit of x on */
+#define left_bits(x) ((x<<1) | -(x<<1))
+
+/* mask with all bits to left of or equal to least bit of x on */
+#define same_or_left_bits(x) ((x) | -(x))
+
+/* index corresponding to given bit. Use x86 asm if possible */
+
+#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+#define compute_bit2idx(X, I)\
+{\
+ unsigned int J;\
+ __asm__("bsfl\t%1, %0\n\t" : "=r" (J) : "g" (X));\
+ I = (bindex_t)J;\
+}
+
+#elif defined (__INTEL_COMPILER)
+#define compute_bit2idx(X, I)\
+{\
+ unsigned int J;\
+ J = _bit_scan_forward (X); \
+ I = (bindex_t)J;\
+}
+
+#elif defined(_MSC_VER) && _MSC_VER>=1300
+#define compute_bit2idx(X, I)\
+{\
+ unsigned int J;\
+ _BitScanForward((DWORD *) &J, X);\
+ I = (bindex_t)J;\
+}
+
+#elif USE_BUILTIN_FFS
+#define compute_bit2idx(X, I) I = ffs(X)-1
+
+#else
+#define compute_bit2idx(X, I)\
+{\
+ unsigned int Y = X - 1;\
+ unsigned int K = Y >> (16-4) & 16;\
+ unsigned int N = K; Y >>= K;\
+ N += K = Y >> (8-3) & 8; Y >>= K;\
+ N += K = Y >> (4-2) & 4; Y >>= K;\
+ N += K = Y >> (2-1) & 2; Y >>= K;\
+ N += K = Y >> (1-0) & 1; Y >>= K;\
+ I = (bindex_t)(N + Y);\
+}
+#endif /* GNUC */
+
+
+/* ----------------------- Runtime Check Support ------------------------- */
+
+/*
+ For security, the main invariant is that malloc/free/etc never
+ writes to a static address other than malloc_state, unless static
+ malloc_state itself has been corrupted, which cannot occur via
+ malloc (because of these checks). In essence this means that we
+ believe all pointers, sizes, maps etc held in malloc_state, but
+ check all of those linked or offsetted from other embedded data
+ structures. These checks are interspersed with main code in a way
+ that tends to minimize their run-time cost.
+
+ When FOOTERS is defined, in addition to range checking, we also
+ verify footer fields of inuse chunks, which can be used guarantee
+ that the mstate controlling malloc/free is intact. This is a
+ streamlined version of the approach described by William Robertson
+ et al in "Run-time Detection of Heap-based Overflows" LISA'03
+ http://www.usenix.org/events/lisa03/tech/robertson.html The footer
+ of an inuse chunk holds the xor of its mstate and a random seed,
+ that is checked upon calls to free() and realloc(). This is
+ (probablistically) unguessable from outside the program, but can be
+ computed by any code successfully malloc'ing any chunk, so does not
+ itself provide protection against code that has already broken
+ security through some other means. Unlike Robertson et al, we
+ always dynamically check addresses of all offset chunks (previous,
+ next, etc). This turns out to be cheaper than relying on hashes.
+*/
+
+#if !INSECURE
+/* Check if address a is at least as high as any from MORECORE or MMAP */
+#define ok_address(M, a) ((char*)(a) >= (M)->least_addr)
+/* Check if address of next chunk n is higher than base chunk p */
+#define ok_next(p, n) ((char*)(p) < (char*)(n))
+/* Check if p has inuse status */
+#define ok_inuse(p) is_inuse(p)
+/* Check if p has its pinuse bit on */
+#define ok_pinuse(p) pinuse(p)
+
+#else /* !INSECURE */
+#define ok_address(M, a) (1)
+#define ok_next(b, n) (1)
+#define ok_inuse(p) (1)
+#define ok_pinuse(p) (1)
+#endif /* !INSECURE */
+
+#if (FOOTERS && !INSECURE)
+/* Check if (alleged) mstate m has expected magic field */
+#define ok_magic(M) ((M)->magic == mparams.magic)
+#else /* (FOOTERS && !INSECURE) */
+#define ok_magic(M) (1)
+#endif /* (FOOTERS && !INSECURE) */
+
+
+/* In gcc, use __builtin_expect to minimize impact of checks */
+#if !INSECURE
+#if defined(__GNUC__) && __GNUC__ >= 3
+#define RTCHECK(e) __builtin_expect(e, 1)
+#else /* GNUC */
+#define RTCHECK(e) (e)
+#endif /* GNUC */
+#else /* !INSECURE */
+#define RTCHECK(e) (1)
+#endif /* !INSECURE */
+
+/* macros to set up inuse chunks with or without footers */
+
+#if !FOOTERS
+
+#define mark_inuse_foot(M,p,s)
+
+/* Macros for setting head/foot of non-mmapped chunks */
+
+/* Set cinuse bit and pinuse bit of next chunk */
+#define set_inuse(M,p,s)\
+ ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\
+ ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)
+
+/* Set cinuse and pinuse of this chunk and pinuse of next chunk */
+#define set_inuse_and_pinuse(M,p,s)\
+ ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
+ ((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT)
+
+/* Set size, cinuse and pinuse bit of this chunk */
+#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\
+ ((p)->head = (s|PINUSE_BIT|CINUSE_BIT))
+
+#else /* FOOTERS */
+
+/* Set foot of inuse chunk to be xor of mstate and seed */
+#define mark_inuse_foot(M,p,s)\
+ (((mchunkptr)((char*)(p) + (s)))->prev_foot = ((size_t)(M) ^ mparams.magic))
+
+#define get_mstate_for(p)\
+ ((mstate)(((mchunkptr)((char*)(p) +\
+ (chunksize(p))))->prev_foot ^ mparams.magic))
+
+#define set_inuse(M,p,s)\
+ ((p)->head = (((p)->head & PINUSE_BIT)|s|CINUSE_BIT),\
+ (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT), \
+ mark_inuse_foot(M,p,s))
+
+#define set_inuse_and_pinuse(M,p,s)\
+ ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
+ (((mchunkptr)(((char*)(p)) + (s)))->head |= PINUSE_BIT),\
+ mark_inuse_foot(M,p,s))
+
+#define set_size_and_pinuse_of_inuse_chunk(M, p, s)\
+ ((p)->head = (s|PINUSE_BIT|CINUSE_BIT),\
+ mark_inuse_foot(M, p, s))
+
+#endif /* !FOOTERS */
+
+/* ---------------------------- setting mparams -------------------------- */
+
+#ifdef ENABLE_LARGE_PAGES
+typedef size_t (WINAPI *GetLargePageMinimum_t)(void);
+#endif
+
+/* Initialize mparams */
+static int init_mparams(void) {
+#ifdef NEED_GLOBAL_LOCK_INIT
+ if (malloc_global_mutex_status <= 0)
+ init_malloc_global_mutex();
+#endif
+
+ ACQUIRE_MALLOC_GLOBAL_LOCK();
+ if (mparams.magic == 0) {
+ size_t magic;
+ size_t psize;
+ size_t gsize;
+
+#ifndef WIN32
+ psize = malloc_getpagesize;
+ gsize = ((DEFAULT_GRANULARITY != 0)? DEFAULT_GRANULARITY : psize);
+#else /* WIN32 */
+ {
+ SYSTEM_INFO system_info;
+ GetSystemInfo(&system_info);
+ psize = system_info.dwPageSize;
+ gsize = ((DEFAULT_GRANULARITY != 0)?
+ DEFAULT_GRANULARITY : system_info.dwAllocationGranularity);
+#ifdef ENABLE_LARGE_PAGES
+ {
+ GetLargePageMinimum_t GetLargePageMinimum_ = (GetLargePageMinimum_t) GetProcAddress(GetModuleHandle(__T("kernel32.dll")), "GetLargePageMinimum");
+ if(GetLargePageMinimum_) {
+ size_t largepagesize = GetLargePageMinimum_();
+ if(largepagesize) {
+ psize = largepagesize;
+ gsize = ((DEFAULT_GRANULARITY != 0)?
+ DEFAULT_GRANULARITY : largepagesize);
+ if(gsize < largepagesize) gsize = largepagesize;
+ }
+ }
+ }
+#endif
+ }
+#endif /* WIN32 */
+
+ /* Sanity-check configuration:
+ size_t must be unsigned and as wide as pointer type.
+ ints must be at least 4 bytes.
+ alignment must be at least 8.
+ Alignment, min chunk size, and page size must all be powers of 2.
+ */
+ if ((sizeof(size_t) != sizeof(char*)) ||
+ (MAX_SIZE_T < MIN_CHUNK_SIZE) ||
+ (sizeof(int) < 4) ||
+ (MALLOC_ALIGNMENT < (size_t)8U) ||
+ ((MALLOC_ALIGNMENT & (MALLOC_ALIGNMENT-SIZE_T_ONE)) != 0) ||
+ ((MCHUNK_SIZE & (MCHUNK_SIZE-SIZE_T_ONE)) != 0) ||
+ ((gsize & (gsize-SIZE_T_ONE)) != 0) ||
+ ((psize & (psize-SIZE_T_ONE)) != 0))
+ ABORT;
+
+ mparams.granularity = gsize;
+ mparams.page_size = psize;
+ mparams.mmap_threshold = DEFAULT_MMAP_THRESHOLD;
+ mparams.trim_threshold = DEFAULT_TRIM_THRESHOLD;
+#if MORECORE_CONTIGUOUS
+ mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT;
+#else /* MORECORE_CONTIGUOUS */
+ mparams.default_mflags = USE_LOCK_BIT|USE_MMAP_BIT|USE_NONCONTIGUOUS_BIT;
+#endif /* MORECORE_CONTIGUOUS */
+
+#if !ONLY_MSPACES
+ /* Set up lock for main malloc area */
+ gm->mflags = mparams.default_mflags;
+ INITIAL_LOCK(&gm->mutex);
+#endif
+
+ {
+#if USE_DEV_RANDOM
+ int fd;
+ unsigned char buf[sizeof(size_t)];
+ /* Try to use /dev/urandom, else fall back on using time */
+ if ((fd = open("/dev/urandom", O_RDONLY)) >= 0 &&
+ read(fd, buf, sizeof(buf)) == sizeof(buf)) {
+ magic = *((size_t *) buf);
+ close(fd);
+ }
+ else
+#endif /* USE_DEV_RANDOM */
+#ifdef WIN32
+ magic = (size_t)(GetTickCount() ^ (size_t)0x55555555U);
+#else
+ magic = (size_t)(time(0) ^ (size_t)0x55555555U);
+#endif
+ magic |= (size_t)8U; /* ensure nonzero */
+ magic &= ~(size_t)7U; /* improve chances of fault for bad values */
+ mparams.magic = magic;
+ }
+ }
+
+ RELEASE_MALLOC_GLOBAL_LOCK();
+ return 1;
+}
+
+/* support for mallopt */
+static int change_mparam(int param_number, int value) {
+ size_t val;
+ ensure_initialization();
+ val = (value == -1)? MAX_SIZE_T : (size_t)value;
+ switch(param_number) {
+ case M_TRIM_THRESHOLD:
+ mparams.trim_threshold = val;
+ return 1;
+ case M_GRANULARITY:
+ if (val >= mparams.page_size && ((val & (val-1)) == 0)) {
+ mparams.granularity = val;
+ return 1;
+ }
+ else
+ return 0;
+ case M_MMAP_THRESHOLD:
+ mparams.mmap_threshold = val;
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+#if DEBUG
+/* ------------------------- Debugging Support --------------------------- */
+
+/* Check properties of any chunk, whether free, inuse, mmapped etc */
+static void do_check_any_chunk(mstate m, mchunkptr p) {
+ assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
+ assert(ok_address(m, p));
+}
+
+/* Check properties of top chunk */
+static void do_check_top_chunk(mstate m, mchunkptr p) {
+ msegmentptr sp = segment_holding(m, (char*)p);
+ size_t sz = p->head & ~INUSE_BITS; /* third-lowest bit can be set! */
+ assert(sp != 0);
+ assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
+ assert(ok_address(m, p));
+ assert(sz == m->topsize);
+ assert(sz > 0);
+ assert(sz == ((sp->base + sp->size) - (char*)p) - TOP_FOOT_SIZE);
+ assert(pinuse(p));
+ assert(!pinuse(chunk_plus_offset(p, sz)));
+}
+
+/* Check properties of (inuse) mmapped chunks */
+static void do_check_mmapped_chunk(mstate m, mchunkptr p) {
+ size_t sz = chunksize(p);
+ size_t len = (sz + (p->prev_foot) + MMAP_FOOT_PAD);
+ assert(is_mmapped(p));
+ assert(use_mmap(m));
+ assert((is_aligned(chunk2mem(p))) || (p->head == FENCEPOST_HEAD));
+ assert(ok_address(m, p));
+ assert(!is_small(sz));
+ assert((len & (mparams.page_size-SIZE_T_ONE)) == 0);
+ assert(chunk_plus_offset(p, sz)->head == FENCEPOST_HEAD);
+ assert(chunk_plus_offset(p, sz+SIZE_T_SIZE)->head == 0);
+}
+
+/* Check properties of inuse chunks */
+static void do_check_inuse_chunk(mstate m, mchunkptr p) {
+ do_check_any_chunk(m, p);
+ assert(is_inuse(p));
+ assert(next_pinuse(p));
+ /* If not pinuse and not mmapped, previous chunk has OK offset */
+ assert(is_mmapped(p) || pinuse(p) || next_chunk(prev_chunk(p)) == p);
+ if (is_mmapped(p))
+ do_check_mmapped_chunk(m, p);
+}
+
+/* Check properties of free chunks */
+static void do_check_free_chunk(mstate m, mchunkptr p) {
+ size_t sz = chunksize(p);
+ mchunkptr next = chunk_plus_offset(p, sz);
+ do_check_any_chunk(m, p);
+ assert(!is_inuse(p));
+ assert(!next_pinuse(p));
+ assert (!is_mmapped(p));
+ if (p != m->dv && p != m->top) {
+ if (sz >= MIN_CHUNK_SIZE) {
+ assert((sz & CHUNK_ALIGN_MASK) == 0);
+ assert(is_aligned(chunk2mem(p)));
+ assert(next->prev_foot == sz);
+ assert(pinuse(p));
+ assert (next == m->top || is_inuse(next));
+ assert(p->fd->bk == p);
+ assert(p->bk->fd == p);
+ }
+ else /* markers are always of size SIZE_T_SIZE */
+ assert(sz == SIZE_T_SIZE);
+ }
+}
+
+/* Check properties of malloced chunks at the point they are malloced */
+static void do_check_malloced_chunk(mstate m, void* mem, size_t s) {
+ if (mem != 0) {
+ mchunkptr p = mem2chunk(mem);
+ size_t sz = p->head & ~INUSE_BITS;
+ do_check_inuse_chunk(m, p);
+ assert((sz & CHUNK_ALIGN_MASK) == 0);
+ assert(sz >= MIN_CHUNK_SIZE);
+ assert(sz >= s);
+ /* unless mmapped, size is less than MIN_CHUNK_SIZE more than request */
+ assert(is_mmapped(p) || sz < (s + MIN_CHUNK_SIZE));
+ }
+}
+
+/* Check a tree and its subtrees. */
+static void do_check_tree(mstate m, tchunkptr t) {
+ tchunkptr head = 0;
+ tchunkptr u = t;
+ bindex_t tindex = t->index;
+ size_t tsize = chunksize(t);
+ bindex_t idx;
+ compute_tree_index(tsize, idx);
+ assert(tindex == idx);
+ assert(tsize >= MIN_LARGE_SIZE);
+ assert(tsize >= minsize_for_tree_index(idx));
+ assert((idx == NTREEBINS-1) || (tsize < minsize_for_tree_index((idx+1))));
+
+ do { /* traverse through chain of same-sized nodes */
+ do_check_any_chunk(m, ((mchunkptr)u));
+ assert(u->index == tindex);
+ assert(chunksize(u) == tsize);
+ assert(!is_inuse(u));
+ assert(!next_pinuse(u));
+ assert(u->fd->bk == u);
+ assert(u->bk->fd == u);
+ if (u->parent == 0) {
+ assert(u->child[0] == 0);
+ assert(u->child[1] == 0);
+ }
+ else {
+ assert(head == 0); /* only one node on chain has parent */
+ head = u;
+ assert(u->parent != u);
+ assert (u->parent->child[0] == u ||
+ u->parent->child[1] == u ||
+ *((tbinptr*)(u->parent)) == u);
+ if (u->child[0] != 0) {
+ assert(u->child[0]->parent == u);
+ assert(u->child[0] != u);
+ do_check_tree(m, u->child[0]);
+ }
+ if (u->child[1] != 0) {
+ assert(u->child[1]->parent == u);
+ assert(u->child[1] != u);
+ do_check_tree(m, u->child[1]);
+ }
+ if (u->child[0] != 0 && u->child[1] != 0) {
+ assert(chunksize(u->child[0]) < chunksize(u->child[1]));
+ }
+ }
+ u = u->fd;
+ } while (u != t);
+ assert(head != 0);
+}
+
+/* Check all the chunks in a treebin. */
+static void do_check_treebin(mstate m, bindex_t i) {
+ tbinptr* tb = treebin_at(m, i);
+ tchunkptr t = *tb;
+ int empty = (m->treemap & (1U << i)) == 0;
+ if (t == 0)
+ assert(empty);
+ if (!empty)
+ do_check_tree(m, t);
+}
+
+/* Check all the chunks in a smallbin. */
+static void do_check_smallbin(mstate m, bindex_t i) {
+ sbinptr b = smallbin_at(m, i);
+ mchunkptr p = b->bk;
+ unsigned int empty = (m->smallmap & (1U << i)) == 0;
+ if (p == b)
+ assert(empty);
+ if (!empty) {
+ for (; p != b; p = p->bk) {
+ size_t size = chunksize(p);
+ mchunkptr q;
+ /* each chunk claims to be free */
+ do_check_free_chunk(m, p);
+ /* chunk belongs in bin */
+ assert(small_index(size) == i);
+ assert(p->bk == b || chunksize(p->bk) == chunksize(p));
+ /* chunk is followed by an inuse chunk */
+ q = next_chunk(p);
+ if (q->head != FENCEPOST_HEAD)
+ do_check_inuse_chunk(m, q);
+ }
+ }
+}
+
+/* Find x in a bin. Used in other check functions. */
+static int bin_find(mstate m, mchunkptr x) {
+ size_t size = chunksize(x);
+ if (is_small(size)) {
+ bindex_t sidx = small_index(size);
+ sbinptr b = smallbin_at(m, sidx);
+ if (smallmap_is_marked(m, sidx)) {
+ mchunkptr p = b;
+ do {
+ if (p == x)
+ return 1;
+ } while ((p = p->fd) != b);
+ }
+ }
+ else {
+ bindex_t tidx;
+ compute_tree_index(size, tidx);
+ if (treemap_is_marked(m, tidx)) {
+ tchunkptr t = *treebin_at(m, tidx);
+ size_t sizebits = size << leftshift_for_tree_index(tidx);
+ while (t != 0 && chunksize(t) != size) {
+ t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
+ sizebits <<= 1;
+ }
+ if (t != 0) {
+ tchunkptr u = t;
+ do {
+ if (u == (tchunkptr)x)
+ return 1;
+ } while ((u = u->fd) != t);
+ }
+ }
+ }
+ return 0;
+}
+
+/* Traverse each chunk and check it; return total */
+static size_t traverse_and_check(mstate m) {
+ size_t sum = 0;
+ if (is_initialized(m)) {
+ msegmentptr s = &m->seg;
+ sum += m->topsize + TOP_FOOT_SIZE;
+ while (s != 0) {
+ mchunkptr q = align_as_chunk(s->base);
+ mchunkptr lastq = 0;
+ assert(pinuse(q));
+ while (segment_holds(s, q) &&
+ q != m->top && q->head != FENCEPOST_HEAD) {
+ sum += chunksize(q);
+ if (is_inuse(q)) {
+ assert(!bin_find(m, q));
+ do_check_inuse_chunk(m, q);
+ }
+ else {
+ assert(q == m->dv || bin_find(m, q));
+ assert(lastq == 0 || is_inuse(lastq)); /* Not 2 consecutive free */
+ do_check_free_chunk(m, q);
+ }
+ lastq = q;
+ q = next_chunk(q);
+ }
+ s = s->next;
+ }
+ }
+ return sum;
+}
+
+/* Check all properties of malloc_state. */
+static void do_check_malloc_state(mstate m) {
+ bindex_t i;
+ size_t total;
+ /* check bins */
+ for (i = 0; i < NSMALLBINS; ++i)
+ do_check_smallbin(m, i);
+ for (i = 0; i < NTREEBINS; ++i)
+ do_check_treebin(m, i);
+
+ if (m->dvsize != 0) { /* check dv chunk */
+ do_check_any_chunk(m, m->dv);
+ assert(m->dvsize == chunksize(m->dv));
+ assert(m->dvsize >= MIN_CHUNK_SIZE);
+ assert(bin_find(m, m->dv) == 0);
+ }
+
+ if (m->top != 0) { /* check top chunk */
+ do_check_top_chunk(m, m->top);
+ /*assert(m->topsize == chunksize(m->top)); redundant */
+ assert(m->topsize > 0);
+ assert(bin_find(m, m->top) == 0);
+ }
+
+ total = traverse_and_check(m);
+ assert(total <= m->footprint);
+ assert(m->footprint <= m->max_footprint);
+}
+#endif /* DEBUG */
+
+/* ----------------------------- statistics ------------------------------ */
+
+#if !NO_MALLINFO
+static struct mallinfo internal_mallinfo(mstate m) {
+ struct mallinfo nm = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ ensure_initialization();
+ if (!PREACTION(m)) {
+ check_malloc_state(m);
+ if (is_initialized(m)) {
+ size_t nfree = SIZE_T_ONE; /* top always free */
+ size_t mfree = m->topsize + TOP_FOOT_SIZE;
+ size_t sum = mfree;
+ msegmentptr s = &m->seg;
+ while (s != 0) {
+ mchunkptr q = align_as_chunk(s->base);
+ while (segment_holds(s, q) &&
+ q != m->top && q->head != FENCEPOST_HEAD) {
+ size_t sz = chunksize(q);
+ sum += sz;
+ if (!is_inuse(q)) {
+ mfree += sz;
+ ++nfree;
+ }
+ q = next_chunk(q);
+ }
+ s = s->next;
+ }
+
+ nm.arena = sum;
+ nm.ordblks = nfree;
+ nm.hblkhd = m->footprint - sum;
+ nm.usmblks = m->max_footprint;
+ nm.uordblks = m->footprint - mfree;
+ nm.fordblks = mfree;
+ nm.keepcost = m->topsize;
+ }
+
+ POSTACTION(m);
+ }
+ return nm;
+}
+#endif /* !NO_MALLINFO */
+
+static void internal_malloc_stats(mstate m) {
+ ensure_initialization();
+ if (!PREACTION(m)) {
+ size_t maxfp = 0;
+ size_t fp = 0;
+ size_t used = 0;
+ check_malloc_state(m);
+ if (is_initialized(m)) {
+ msegmentptr s = &m->seg;
+ maxfp = m->max_footprint;
+ fp = m->footprint;
+ used = fp - (m->topsize + TOP_FOOT_SIZE);
+
+ while (s != 0) {
+ mchunkptr q = align_as_chunk(s->base);
+ while (segment_holds(s, q) &&
+ q != m->top && q->head != FENCEPOST_HEAD) {
+ if (!is_inuse(q))
+ used -= chunksize(q);
+ q = next_chunk(q);
+ }
+ s = s->next;
+ }
+ }
+
+ fprintf(stderr, "max system bytes = %10lu\n", (unsigned long)(maxfp));
+ fprintf(stderr, "system bytes = %10lu\n", (unsigned long)(fp));
+ fprintf(stderr, "in use bytes = %10lu\n", (unsigned long)(used));
+
+ POSTACTION(m);
+ }
+}
+
+/* ----------------------- Operations on smallbins ----------------------- */
+
+/*
+ Various forms of linking and unlinking are defined as macros. Even
+ the ones for trees, which are very long but have very short typical
+ paths. This is ugly but reduces reliance on inlining support of
+ compilers.
+*/
+
+/* Link a free chunk into a smallbin */
+#define insert_small_chunk(M, P, S) {\
+ bindex_t I = small_index(S);\
+ mchunkptr B = smallbin_at(M, I);\
+ mchunkptr F = B;\
+ assert(S >= MIN_CHUNK_SIZE);\
+ if (!smallmap_is_marked(M, I))\
+ mark_smallmap(M, I);\
+ else if (RTCHECK(ok_address(M, B->fd)))\
+ F = B->fd;\
+ else {\
+ CORRUPTION_ERROR_ACTION(M);\
+ }\
+ B->fd = P;\
+ F->bk = P;\
+ P->fd = F;\
+ P->bk = B;\
+}
+
+/* Unlink a chunk from a smallbin */
+#define unlink_small_chunk(M, P, S) {\
+ mchunkptr F = P->fd;\
+ mchunkptr B = P->bk;\
+ bindex_t I = small_index(S);\
+ assert(P != B);\
+ assert(P != F);\
+ assert(chunksize(P) == small_index2size(I));\
+ if (F == B)\
+ clear_smallmap(M, I);\
+ else if (RTCHECK((F == smallbin_at(M,I) || ok_address(M, F)) &&\
+ (B == smallbin_at(M,I) || ok_address(M, B)))) {\
+ F->bk = B;\
+ B->fd = F;\
+ }\
+ else {\
+ CORRUPTION_ERROR_ACTION(M);\
+ }\
+}
+
+/* Unlink the first chunk from a smallbin */
+#define unlink_first_small_chunk(M, B, P, I) {\
+ mchunkptr F = P->fd;\
+ assert(P != B);\
+ assert(P != F);\
+ assert(chunksize(P) == small_index2size(I));\
+ if (B == F)\
+ clear_smallmap(M, I);\
+ else if (RTCHECK(ok_address(M, F))) {\
+ B->fd = F;\
+ F->bk = B;\
+ }\
+ else {\
+ CORRUPTION_ERROR_ACTION(M);\
+ }\
+}
+
+
+
+/* Replace dv node, binning the old one */
+/* Used only when dvsize known to be small */
+#define replace_dv(M, P, S) {\
+ size_t DVS = M->dvsize;\
+ if (DVS != 0) {\
+ mchunkptr DV = M->dv;\
+ assert(is_small(DVS));\
+ insert_small_chunk(M, DV, DVS);\
+ }\
+ M->dvsize = S;\
+ M->dv = P;\
+}
+
+/* ------------------------- Operations on trees ------------------------- */
+
+/* Insert chunk into tree */
+#define insert_large_chunk(M, X, S) {\
+ tbinptr* H;\
+ bindex_t I;\
+ compute_tree_index(S, I);\
+ H = treebin_at(M, I);\
+ X->index = I;\
+ X->child[0] = X->child[1] = 0;\
+ if (!treemap_is_marked(M, I)) {\
+ mark_treemap(M, I);\
+ *H = X;\
+ X->parent = (tchunkptr)H;\
+ X->fd = X->bk = X;\
+ }\
+ else {\
+ tchunkptr T = *H;\
+ size_t K = S << leftshift_for_tree_index(I);\
+ for (;;) {\
+ if (chunksize(T) != S) {\
+ tchunkptr* C = &(T->child[(K >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1]);\
+ K <<= 1;\
+ if (*C != 0)\
+ T = *C;\
+ else if (RTCHECK(ok_address(M, C))) {\
+ *C = X;\
+ X->parent = T;\
+ X->fd = X->bk = X;\
+ break;\
+ }\
+ else {\
+ CORRUPTION_ERROR_ACTION(M);\
+ break;\
+ }\
+ }\
+ else {\
+ tchunkptr F = T->fd;\
+ if (RTCHECK(ok_address(M, T) && ok_address(M, F))) {\
+ T->fd = F->bk = X;\
+ X->fd = F;\
+ X->bk = T;\
+ X->parent = 0;\
+ break;\
+ }\
+ else {\
+ CORRUPTION_ERROR_ACTION(M);\
+ break;\
+ }\
+ }\
+ }\
+ }\
+}
+
+/*
+ Unlink steps:
+
+ 1. If x is a chained node, unlink it from its same-sized fd/bk links
+ and choose its bk node as its replacement.
+ 2. If x was the last node of its size, but not a leaf node, it must
+ be replaced with a leaf node (not merely one with an open left or
+ right), to make sure that lefts and rights of descendents
+ correspond properly to bit masks. We use the rightmost descendent
+ of x. We could use any other leaf, but this is easy to locate and
+ tends to counteract removal of leftmosts elsewhere, and so keeps
+ paths shorter than minimally guaranteed. This doesn't loop much
+ because on average a node in a tree is near the bottom.
+ 3. If x is the base of a chain (i.e., has parent links) relink
+ x's parent and children to x's replacement (or null if none).
+*/
+
+#define unlink_large_chunk(M, X) {\
+ tchunkptr XP = X->parent;\
+ tchunkptr R;\
+ if (X->bk != X) {\
+ tchunkptr F = X->fd;\
+ R = X->bk;\
+ if (RTCHECK(ok_address(M, F))) {\
+ F->bk = R;\
+ R->fd = F;\
+ }\
+ else {\
+ CORRUPTION_ERROR_ACTION(M);\
+ }\
+ }\
+ else {\
+ tchunkptr* RP;\
+ if (((R = *(RP = &(X->child[1]))) != 0) ||\
+ ((R = *(RP = &(X->child[0]))) != 0)) {\
+ tchunkptr* CP;\
+ while ((*(CP = &(R->child[1])) != 0) ||\
+ (*(CP = &(R->child[0])) != 0)) {\
+ R = *(RP = CP);\
+ }\
+ if (RTCHECK(ok_address(M, RP)))\
+ *RP = 0;\
+ else {\
+ CORRUPTION_ERROR_ACTION(M);\
+ }\
+ }\
+ }\
+ if (XP != 0) {\
+ tbinptr* H = treebin_at(M, X->index);\
+ if (X == *H) {\
+ if ((*H = R) == 0) \
+ clear_treemap(M, X->index);\
+ }\
+ else if (RTCHECK(ok_address(M, XP))) {\
+ if (XP->child[0] == X) \
+ XP->child[0] = R;\
+ else \
+ XP->child[1] = R;\
+ }\
+ else\
+ CORRUPTION_ERROR_ACTION(M);\
+ if (R != 0) {\
+ if (RTCHECK(ok_address(M, R))) {\
+ tchunkptr C0, C1;\
+ R->parent = XP;\
+ if ((C0 = X->child[0]) != 0) {\
+ if (RTCHECK(ok_address(M, C0))) {\
+ R->child[0] = C0;\
+ C0->parent = R;\
+ }\
+ else\
+ CORRUPTION_ERROR_ACTION(M);\
+ }\
+ if ((C1 = X->child[1]) != 0) {\
+ if (RTCHECK(ok_address(M, C1))) {\
+ R->child[1] = C1;\
+ C1->parent = R;\
+ }\
+ else\
+ CORRUPTION_ERROR_ACTION(M);\
+ }\
+ }\
+ else\
+ CORRUPTION_ERROR_ACTION(M);\
+ }\
+ }\
+}
+
+/* Relays to large vs small bin operations */
+
+#define insert_chunk(M, P, S)\
+ if (is_small(S)) insert_small_chunk(M, P, S)\
+ else { tchunkptr TP = (tchunkptr)(P); insert_large_chunk(M, TP, S); }
+
+#define unlink_chunk(M, P, S)\
+ if (is_small(S)) unlink_small_chunk(M, P, S)\
+ else { tchunkptr TP = (tchunkptr)(P); unlink_large_chunk(M, TP); }
+
+
+/* Relays to internal calls to malloc/free from realloc, memalign etc */
+
+#if ONLY_MSPACES
+#define internal_malloc(m, b) mspace_malloc(m, b)
+#define internal_free(m, mem) mspace_free(m,mem);
+#else /* ONLY_MSPACES */
+#if MSPACES
+#define internal_malloc(m, b)\
+ (m == gm)? dlmalloc(b) : mspace_malloc(m, b)
+#define internal_free(m, mem)\
+ if (m == gm) dlfree(mem); else mspace_free(m,mem);
+#else /* MSPACES */
+#define internal_malloc(m, b) dlmalloc(b)
+#define internal_free(m, mem) dlfree(mem)
+#endif /* MSPACES */
+#endif /* ONLY_MSPACES */
+
+/* ----------------------- Direct-mmapping chunks ----------------------- */
+
+/*
+ Directly mmapped chunks are set up with an offset to the start of
+ the mmapped region stored in the prev_foot field of the chunk. This
+ allows reconstruction of the required argument to MUNMAP when freed,
+ and also allows adjustment of the returned chunk to meet alignment
+ requirements (especially in memalign).
+*/
+
+/* Malloc using mmap */
+static void* mmap_alloc(mstate m, size_t nb) {
+ size_t mmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
+ if (mmsize > nb) { /* Check for wrap around 0 */
+ char* mm = (char*)(CALL_DIRECT_MMAP(mmsize));
+ if (mm != CMFAIL) {
+ size_t offset = align_offset(chunk2mem(mm));
+ size_t psize = mmsize - offset - MMAP_FOOT_PAD;
+ mchunkptr p = (mchunkptr)(mm + offset);
+ p->prev_foot = offset;
+ p->head = psize;
+ mark_inuse_foot(m, p, psize);
+ chunk_plus_offset(p, psize)->head = FENCEPOST_HEAD;
+ chunk_plus_offset(p, psize+SIZE_T_SIZE)->head = 0;
+
+ if (m->least_addr == 0 || mm < m->least_addr)
+ m->least_addr = mm;
+ if ((m->footprint += mmsize) > m->max_footprint)
+ m->max_footprint = m->footprint;
+ assert(is_aligned(chunk2mem(p)));
+ check_mmapped_chunk(m, p);
+ return chunk2mem(p);
+ }
+ }
+ return 0;
+}
+
+/* Realloc using mmap */
+static mchunkptr mmap_resize(mstate m, mchunkptr oldp, size_t nb) {
+ size_t oldsize = chunksize(oldp);
+ if (is_small(nb)) /* Can't shrink mmap regions below small size */
+ return 0;
+ /* Keep old chunk if big enough but not too big */
+ if (oldsize >= nb + SIZE_T_SIZE &&
+ (oldsize - nb) <= (mparams.granularity << 1))
+ return oldp;
+ else {
+ size_t offset = oldp->prev_foot;
+ size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD;
+ size_t newmmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
+ char* cp = (char*)CALL_MREMAP((char*)oldp - offset,
+ oldmmsize, newmmsize, 1);
+ if (cp != CMFAIL) {
+ mchunkptr newp = (mchunkptr)(cp + offset);
+ size_t psize = newmmsize - offset - MMAP_FOOT_PAD;
+ newp->head = psize;
+ mark_inuse_foot(m, newp, psize);
+ chunk_plus_offset(newp, psize)->head = FENCEPOST_HEAD;
+ chunk_plus_offset(newp, psize+SIZE_T_SIZE)->head = 0;
+
+ if (cp < m->least_addr)
+ m->least_addr = cp;
+ if ((m->footprint += newmmsize - oldmmsize) > m->max_footprint)
+ m->max_footprint = m->footprint;
+ check_mmapped_chunk(m, newp);
+ return newp;
+ }
+ }
+ return 0;
+}
+
+/* -------------------------- mspace management -------------------------- */
+
+/* Initialize top chunk and its size */
+static void init_top(mstate m, mchunkptr p, size_t psize) {
+ /* Ensure alignment */
+ size_t offset = align_offset(chunk2mem(p));
+ p = (mchunkptr)((char*)p + offset);
+ psize -= offset;
+
+ m->top = p;
+ m->topsize = psize;
+ p->head = psize | PINUSE_BIT;
+ /* set size of fake trailing chunk holding overhead space only once */
+ chunk_plus_offset(p, psize)->head = TOP_FOOT_SIZE;
+ m->trim_check = mparams.trim_threshold; /* reset on each update */
+}
+
+/* Initialize bins for a new mstate that is otherwise zeroed out */
+static void init_bins(mstate m) {
+ /* Establish circular links for smallbins */
+ bindex_t i;
+ for (i = 0; i < NSMALLBINS; ++i) {
+ sbinptr bin = smallbin_at(m,i);
+ bin->fd = bin->bk = bin;
+ }
+}
+
+#if PROCEED_ON_ERROR
+
+/* default corruption action */
+static void reset_on_error(mstate m) {
+ int i;
+ ++malloc_corruption_error_count;
+ /* Reinitialize fields to forget about all memory */
+ m->smallbins = m->treebins = 0;
+ m->dvsize = m->topsize = 0;
+ m->seg.base = 0;
+ m->seg.size = 0;
+ m->seg.next = 0;
+ m->top = m->dv = 0;
+ for (i = 0; i < NTREEBINS; ++i)
+ *treebin_at(m, i) = 0;
+ init_bins(m);
+}
+#endif /* PROCEED_ON_ERROR */
+
+/* Allocate chunk and prepend remainder with chunk in successor base. */
+static void* prepend_alloc(mstate m, char* newbase, char* oldbase,
+ size_t nb) {
+ mchunkptr p = align_as_chunk(newbase);
+ mchunkptr oldfirst = align_as_chunk(oldbase);
+ size_t psize = (char*)oldfirst - (char*)p;
+ mchunkptr q = chunk_plus_offset(p, nb);
+ size_t qsize = psize - nb;
+ set_size_and_pinuse_of_inuse_chunk(m, p, nb);
+
+ assert((char*)oldfirst > (char*)q);
+ assert(pinuse(oldfirst));
+ assert(qsize >= MIN_CHUNK_SIZE);
+
+ /* consolidate remainder with first chunk of old base */
+ if (oldfirst == m->top) {
+ size_t tsize = m->topsize += qsize;
+ m->top = q;
+ q->head = tsize | PINUSE_BIT;
+ check_top_chunk(m, q);
+ }
+ else if (oldfirst == m->dv) {
+ size_t dsize = m->dvsize += qsize;
+ m->dv = q;
+ set_size_and_pinuse_of_free_chunk(q, dsize);
+ }
+ else {
+ if (!is_inuse(oldfirst)) {
+ size_t nsize = chunksize(oldfirst);
+ unlink_chunk(m, oldfirst, nsize);
+ oldfirst = chunk_plus_offset(oldfirst, nsize);
+ qsize += nsize;
+ }
+ set_free_with_pinuse(q, qsize, oldfirst);
+ insert_chunk(m, q, qsize);
+ check_free_chunk(m, q);
+ }
+
+ check_malloced_chunk(m, chunk2mem(p), nb);
+ return chunk2mem(p);
+}
+
+/* Add a segment to hold a new noncontiguous region */
+static void add_segment(mstate m, char* tbase, size_t tsize, flag_t mmapped) {
+ /* Determine locations and sizes of segment, fenceposts, old top */
+ char* old_top = (char*)m->top;
+ msegmentptr oldsp = segment_holding(m, old_top);
+ char* old_end = oldsp->base + oldsp->size;
+ size_t ssize = pad_request(sizeof(struct malloc_segment));
+ char* rawsp = old_end - (ssize + FOUR_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
+ size_t offset = align_offset(chunk2mem(rawsp));
+ char* asp = rawsp + offset;
+ char* csp = (asp < (old_top + MIN_CHUNK_SIZE))? old_top : asp;
+ mchunkptr sp = (mchunkptr)csp;
+ msegmentptr ss = (msegmentptr)(chunk2mem(sp));
+ mchunkptr tnext = chunk_plus_offset(sp, ssize);
+ mchunkptr p = tnext;
+ int nfences = 0;
+
+ /* reset top to new space */
+ init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);
+
+ /* Set up segment record */
+ assert(is_aligned(ss));
+ set_size_and_pinuse_of_inuse_chunk(m, sp, ssize);
+ *ss = m->seg; /* Push current record */
+ m->seg.base = tbase;
+ m->seg.size = tsize;
+ m->seg.sflags = mmapped;
+ m->seg.next = ss;
+
+ /* Insert trailing fenceposts */
+ for (;;) {
+ mchunkptr nextp = chunk_plus_offset(p, SIZE_T_SIZE);
+ p->head = FENCEPOST_HEAD;
+ ++nfences;
+ if ((char*)(&(nextp->head)) < old_end)
+ p = nextp;
+ else
+ break;
+ }
+ assert(nfences >= 2);
+
+ /* Insert the rest of old top into a bin as an ordinary free chunk */
+ if (csp != old_top) {
+ mchunkptr q = (mchunkptr)old_top;
+ size_t psize = csp - old_top;
+ mchunkptr tn = chunk_plus_offset(q, psize);
+ set_free_with_pinuse(q, psize, tn);
+ insert_chunk(m, q, psize);
+ }
+
+ check_top_chunk(m, m->top);
+}
+
+/* -------------------------- System allocation -------------------------- */
+
+/* Get memory from system using MORECORE or MMAP */
+static void* sys_alloc(mstate m, size_t nb) {
+ char* tbase = CMFAIL;
+ size_t tsize = 0;
+ flag_t mmap_flag = 0;
+
+ ensure_initialization();
+
+ /* Directly map large chunks, but only if already initialized */
+ if (use_mmap(m) && nb >= mparams.mmap_threshold && m->topsize != 0) {
+ void* mem = mmap_alloc(m, nb);
+ if (mem != 0)
+ return mem;
+ }
+
+ /*
+ Try getting memory in any of three ways (in most-preferred to
+ least-preferred order):
+ 1. A call to MORECORE that can normally contiguously extend memory.
+ (disabled if not MORECORE_CONTIGUOUS or not HAVE_MORECORE or
+ or main space is mmapped or a previous contiguous call failed)
+ 2. A call to MMAP new space (disabled if not HAVE_MMAP).
+ Note that under the default settings, if MORECORE is unable to
+ fulfill a request, and HAVE_MMAP is true, then mmap is
+ used as a noncontiguous system allocator. This is a useful backup
+ strategy for systems with holes in address spaces -- in this case
+ sbrk cannot contiguously expand the heap, but mmap may be able to
+ find space.
+ 3. A call to MORECORE that cannot usually contiguously extend memory.
+ (disabled if not HAVE_MORECORE)
+
+ In all cases, we need to request enough bytes from system to ensure
+ we can malloc nb bytes upon success, so pad with enough space for
+ top_foot, plus alignment-pad to make sure we don't lose bytes if
+ not on boundary, and round this up to a granularity unit.
+ */
+
+ if (MORECORE_CONTIGUOUS && !use_noncontiguous(m)) {
+ char* br = CMFAIL;
+ msegmentptr ss = (m->top == 0)? 0 : segment_holding(m, (char*)m->top);
+ size_t asize = 0;
+ ACQUIRE_MALLOC_GLOBAL_LOCK();
+
+ if (ss == 0) { /* First time through or recovery */
+ char* base = (char*)CALL_MORECORE(0);
+ if (base != CMFAIL) {
+ asize = granularity_align(nb + SYS_ALLOC_PADDING);
+ /* Adjust to end on a page boundary */
+ if (!is_page_aligned(base))
+ asize += (page_align((size_t)base) - (size_t)base);
+ /* Can't call MORECORE if size is negative when treated as signed */
+ if (asize < HALF_MAX_SIZE_T &&
+ (br = (char*)(CALL_MORECORE(asize))) == base) {
+ tbase = base;
+ tsize = asize;
+ }
+ }
+ }
+ else {
+ /* Subtract out existing available top space from MORECORE request. */
+ asize = granularity_align(nb - m->topsize + SYS_ALLOC_PADDING);
+ /* Use mem here only if it did continuously extend old space */
+ if (asize < HALF_MAX_SIZE_T &&
+ (br = (char*)(CALL_MORECORE(asize))) == ss->base+ss->size) {
+ tbase = br;
+ tsize = asize;
+ }
+ }
+
+ if (tbase == CMFAIL) { /* Cope with partial failure */
+ if (br != CMFAIL) { /* Try to use/extend the space we did get */
+ if (asize < HALF_MAX_SIZE_T &&
+ asize < nb + SYS_ALLOC_PADDING) {
+ size_t esize = granularity_align(nb + SYS_ALLOC_PADDING - asize);
+ if (esize < HALF_MAX_SIZE_T) {
+ char* end = (char*)CALL_MORECORE(esize);
+ if (end != CMFAIL)
+ asize += esize;
+ else { /* Can't use; try to release */
+ (void) CALL_MORECORE(-asize);
+ br = CMFAIL;
+ }
+ }
+ }
+ }
+ if (br != CMFAIL) { /* Use the space we did get */
+ tbase = br;
+ tsize = asize;
+ }
+ else
+ disable_contiguous(m); /* Don't try contiguous path in the future */
+ }
+
+ RELEASE_MALLOC_GLOBAL_LOCK();
+ }
+
+ if (HAVE_MMAP && tbase == CMFAIL) { /* Try MMAP */
+ size_t rsize = granularity_align(nb + SYS_ALLOC_PADDING);
+ if (rsize > nb) { /* Fail if wraps around zero */
+ char* mp = (char*)(CALL_MMAP(rsize));
+ if (mp != CMFAIL) {
+ tbase = mp;
+ tsize = rsize;
+ mmap_flag = USE_MMAP_BIT;
+ }
+ }
+ }
+
+ if (HAVE_MORECORE && tbase == CMFAIL) { /* Try noncontiguous MORECORE */
+ size_t asize = granularity_align(nb + SYS_ALLOC_PADDING);
+ if (asize < HALF_MAX_SIZE_T) {
+ char* br = CMFAIL;
+ char* end = CMFAIL;
+ ACQUIRE_MALLOC_GLOBAL_LOCK();
+ br = (char*)(CALL_MORECORE(asize));
+ end = (char*)(CALL_MORECORE(0));
+ RELEASE_MALLOC_GLOBAL_LOCK();
+ if (br != CMFAIL && end != CMFAIL && br < end) {
+ size_t ssize = end - br;
+ if (ssize > nb + TOP_FOOT_SIZE) {
+ tbase = br;
+ tsize = ssize;
+ }
+ }
+ }
+ }
+
+ if (tbase != CMFAIL) {
+
+ if ((m->footprint += tsize) > m->max_footprint)
+ m->max_footprint = m->footprint;
+
+ if (!is_initialized(m)) { /* first-time initialization */
+ if (m->least_addr == 0 || tbase < m->least_addr)
+ m->least_addr = tbase;
+ m->seg.base = tbase;
+ m->seg.size = tsize;
+ m->seg.sflags = mmap_flag;
+ m->magic = mparams.magic;
+ m->release_checks = MAX_RELEASE_CHECK_RATE;
+ init_bins(m);
+#if !ONLY_MSPACES
+ if (is_global(m))
+ init_top(m, (mchunkptr)tbase, tsize - TOP_FOOT_SIZE);
+ else
+#endif
+ {
+ /* Offset top by embedded malloc_state */
+ mchunkptr mn = next_chunk(mem2chunk(m));
+ init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) -TOP_FOOT_SIZE);
+ }
+ }
+
+ else {
+ /* Try to merge with an existing segment */
+ msegmentptr sp = &m->seg;
+ /* Only consider most recent segment if traversal suppressed */
+ while (sp != 0 && tbase != sp->base + sp->size)
+ sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next;
+ if (sp != 0 &&
+ !is_extern_segment(sp) &&
+ (sp->sflags & USE_MMAP_BIT) == mmap_flag &&
+ segment_holds(sp, m->top)) { /* append */
+ sp->size += tsize;
+ init_top(m, m->top, m->topsize + tsize);
+ }
+ else {
+ if (tbase < m->least_addr)
+ m->least_addr = tbase;
+ sp = &m->seg;
+ while (sp != 0 && sp->base != tbase + tsize)
+ sp = (NO_SEGMENT_TRAVERSAL) ? 0 : sp->next;
+ if (sp != 0 &&
+ !is_extern_segment(sp) &&
+ (sp->sflags & USE_MMAP_BIT) == mmap_flag) {
+ char* oldbase = sp->base;
+ sp->base = tbase;
+ sp->size += tsize;
+ return prepend_alloc(m, tbase, oldbase, nb);
+ }
+ else
+ add_segment(m, tbase, tsize, mmap_flag);
+ }
+ }
+
+ if (nb < m->topsize) { /* Allocate from new or extended top space */
+ size_t rsize = m->topsize -= nb;
+ mchunkptr p = m->top;
+ mchunkptr r = m->top = chunk_plus_offset(p, nb);
+ r->head = rsize | PINUSE_BIT;
+ set_size_and_pinuse_of_inuse_chunk(m, p, nb);
+ check_top_chunk(m, m->top);
+ check_malloced_chunk(m, chunk2mem(p), nb);
+ return chunk2mem(p);
+ }
+ }
+
+ MALLOC_FAILURE_ACTION;
+ return 0;
+}
+
+/* ----------------------- system deallocation -------------------------- */
+
+/* Unmap and unlink any mmapped segments that don't contain used chunks */
+static size_t release_unused_segments(mstate m) {
+ size_t released = 0;
+ int nsegs = 0;
+ msegmentptr pred = &m->seg;
+ msegmentptr sp = pred->next;
+ while (sp != 0) {
+ char* base = sp->base;
+ size_t size = sp->size;
+ msegmentptr next = sp->next;
+ ++nsegs;
+ if (is_mmapped_segment(sp) && !is_extern_segment(sp)) {
+ mchunkptr p = align_as_chunk(base);
+ size_t psize = chunksize(p);
+ /* Can unmap if first chunk holds entire segment and not pinned */
+ if (!is_inuse(p) && (char*)p + psize >= base + size - TOP_FOOT_SIZE) {
+ tchunkptr tp = (tchunkptr)p;
+ assert(segment_holds(sp, (char*)sp));
+ if (p == m->dv) {
+ m->dv = 0;
+ m->dvsize = 0;
+ }
+ else {
+ unlink_large_chunk(m, tp);
+ }
+ if (CALL_MUNMAP(base, size) == 0) {
+ released += size;
+ m->footprint -= size;
+ /* unlink obsoleted record */
+ sp = pred;
+ sp->next = next;
+ }
+ else { /* back out if cannot unmap */
+ insert_large_chunk(m, tp, psize);
+ }
+ }
+ }
+ if (NO_SEGMENT_TRAVERSAL) /* scan only first segment */
+ break;
+ pred = sp;
+ sp = next;
+ }
+ /* Reset check counter */
+ m->release_checks = ((nsegs > MAX_RELEASE_CHECK_RATE)?
+ nsegs : MAX_RELEASE_CHECK_RATE);
+ return released;
+}
+
+static int sys_trim(mstate m, size_t pad) {
+ size_t released = 0;
+ ensure_initialization();
+ if (pad < MAX_REQUEST && is_initialized(m)) {
+ pad += TOP_FOOT_SIZE; /* ensure enough room for segment overhead */
+
+ if (m->topsize > pad) {
+ /* Shrink top space in granularity-size units, keeping at least one */
+ size_t unit = mparams.granularity;
+ size_t extra = ((m->topsize - pad + (unit - SIZE_T_ONE)) / unit -
+ SIZE_T_ONE) * unit;
+ msegmentptr sp = segment_holding(m, (char*)m->top);
+
+ if (!is_extern_segment(sp)) {
+ if (is_mmapped_segment(sp)) {
+ if (HAVE_MMAP &&
+ sp->size >= extra &&
+ !has_segment_link(m, sp)) { /* can't shrink if pinned */
+ size_t newsize = sp->size - extra;
+ /* Prefer mremap, fall back to munmap */
+ if ((CALL_MREMAP(sp->base, sp->size, newsize, 0) != MFAIL) ||
+ (CALL_MUNMAP(sp->base + newsize, extra) == 0)) {
+ released = extra;
+ }
+ }
+ }
+ else if (HAVE_MORECORE) {
+ if (extra >= HALF_MAX_SIZE_T) /* Avoid wrapping negative */
+ extra = (HALF_MAX_SIZE_T) + SIZE_T_ONE - unit;
+ ACQUIRE_MALLOC_GLOBAL_LOCK();
+ {
+ /* Make sure end of memory is where we last set it. */
+ char* old_br = (char*)(CALL_MORECORE(0));
+ if (old_br == sp->base + sp->size) {
+ char* rel_br = (char*)(CALL_MORECORE(-extra));
+ char* new_br = (char*)(CALL_MORECORE(0));
+ if (rel_br != CMFAIL && new_br < old_br)
+ released = old_br - new_br;
+ }
+ }
+ RELEASE_MALLOC_GLOBAL_LOCK();
+ }
+ }
+
+ if (released != 0) {
+ sp->size -= released;
+ m->footprint -= released;
+ init_top(m, m->top, m->topsize - released);
+ check_top_chunk(m, m->top);
+ }
+ }
+
+ /* Unmap any unused mmapped segments */
+ if (HAVE_MMAP)
+ released += release_unused_segments(m);
+
+ /* On failure, disable autotrim to avoid repeated failed future calls */
+ if (released == 0 && m->topsize > m->trim_check)
+ m->trim_check = MAX_SIZE_T;
+ }
+
+ return (released != 0)? 1 : 0;
+}
+
+
+/* ---------------------------- malloc support --------------------------- */
+
+/* allocate a large request from the best fitting chunk in a treebin */
+static void* tmalloc_large(mstate m, size_t nb) {
+ tchunkptr v = 0;
+ size_t rsize = -nb; /* Unsigned negation */
+ tchunkptr t;
+ bindex_t idx;
+ compute_tree_index(nb, idx);
+ if ((t = *treebin_at(m, idx)) != 0) {
+ /* Traverse tree for this bin looking for node with size == nb */
+ size_t sizebits = nb << leftshift_for_tree_index(idx);
+ tchunkptr rst = 0; /* The deepest untaken right subtree */
+ for (;;) {
+ tchunkptr rt;
+ size_t trem = chunksize(t) - nb;
+ if (trem < rsize) {
+ v = t;
+ if ((rsize = trem) == 0)
+ break;
+ }
+ rt = t->child[1];
+ t = t->child[(sizebits >> (SIZE_T_BITSIZE-SIZE_T_ONE)) & 1];
+ if (rt != 0 && rt != t)
+ rst = rt;
+ if (t == 0) {
+ t = rst; /* set t to least subtree holding sizes > nb */
+ break;
+ }
+ sizebits <<= 1;
+ }
+ }
+ if (t == 0 && v == 0) { /* set t to root of next non-empty treebin */
+ binmap_t leftbits = left_bits(idx2bit(idx)) & m->treemap;
+ if (leftbits != 0) {
+ bindex_t i;
+ binmap_t leastbit = least_bit(leftbits);
+ compute_bit2idx(leastbit, i);
+ t = *treebin_at(m, i);
+ }
+ }
+
+ while (t != 0) { /* find smallest of tree or subtree */
+ size_t trem = chunksize(t) - nb;
+ if (trem < rsize) {
+ rsize = trem;
+ v = t;
+ }
+ t = leftmost_child(t);
+ }
+
+ /* If dv is a better fit, return 0 so malloc will use it */
+ if (v != 0 && rsize < (size_t)(m->dvsize - nb)) {
+ if (RTCHECK(ok_address(m, v))) { /* split */
+ mchunkptr r = chunk_plus_offset(v, nb);
+ assert(chunksize(v) == rsize + nb);
+ if (RTCHECK(ok_next(v, r))) {
+ unlink_large_chunk(m, v);
+ if (rsize < MIN_CHUNK_SIZE)
+ set_inuse_and_pinuse(m, v, (rsize + nb));
+ else {
+ set_size_and_pinuse_of_inuse_chunk(m, v, nb);
+ set_size_and_pinuse_of_free_chunk(r, rsize);
+ insert_chunk(m, r, rsize);
+ }
+ return chunk2mem(v);
+ }
+ }
+ CORRUPTION_ERROR_ACTION(m);
+ }
+ return 0;
+}
+
+/* allocate a small request from the best fitting chunk in a treebin */
+static void* tmalloc_small(mstate m, size_t nb) {
+ tchunkptr t, v;
+ size_t rsize;
+ bindex_t i;
+ binmap_t leastbit = least_bit(m->treemap);
+ compute_bit2idx(leastbit, i);
+ v = t = *treebin_at(m, i);
+ rsize = chunksize(t) - nb;
+
+ while ((t = leftmost_child(t)) != 0) {
+ size_t trem = chunksize(t) - nb;
+ if (trem < rsize) {
+ rsize = trem;
+ v = t;
+ }
+ }
+
+ if (RTCHECK(ok_address(m, v))) {
+ mchunkptr r = chunk_plus_offset(v, nb);
+ assert(chunksize(v) == rsize + nb);
+ if (RTCHECK(ok_next(v, r))) {
+ unlink_large_chunk(m, v);
+ if (rsize < MIN_CHUNK_SIZE)
+ set_inuse_and_pinuse(m, v, (rsize + nb));
+ else {
+ set_size_and_pinuse_of_inuse_chunk(m, v, nb);
+ set_size_and_pinuse_of_free_chunk(r, rsize);
+ replace_dv(m, r, rsize);
+ }
+ return chunk2mem(v);
+ }
+ }
+
+ CORRUPTION_ERROR_ACTION(m);
+ return 0;
+}
+
+/* --------------------------- realloc support --------------------------- */
+
+static void* internal_realloc(mstate m, void* oldmem, size_t bytes) {
+ if (bytes >= MAX_REQUEST) {
+ MALLOC_FAILURE_ACTION;
+ return 0;
+ }
+ if (!PREACTION(m)) {
+ mchunkptr oldp = mem2chunk(oldmem);
+ size_t oldsize = chunksize(oldp);
+ mchunkptr next = chunk_plus_offset(oldp, oldsize);
+ mchunkptr newp = 0;
+ void* extra = 0;
+
+ /* Try to either shrink or extend into top. Else malloc-copy-free */
+
+ if (RTCHECK(ok_address(m, oldp) && ok_inuse(oldp) &&
+ ok_next(oldp, next) && ok_pinuse(next))) {
+ size_t nb = request2size(bytes);
+ if (is_mmapped(oldp))
+ newp = mmap_resize(m, oldp, nb);
+ else if (oldsize >= nb) { /* already big enough */
+ size_t rsize = oldsize - nb;
+ newp = oldp;
+ if (rsize >= MIN_CHUNK_SIZE) {
+ mchunkptr remainder = chunk_plus_offset(newp, nb);
+ set_inuse(m, newp, nb);
+ set_inuse_and_pinuse(m, remainder, rsize);
+ extra = chunk2mem(remainder);
+ }
+ }
+ else if (next == m->top && oldsize + m->topsize > nb) {
+ /* Expand into top */
+ size_t newsize = oldsize + m->topsize;
+ size_t newtopsize = newsize - nb;
+ mchunkptr newtop = chunk_plus_offset(oldp, nb);
+ set_inuse(m, oldp, nb);
+ newtop->head = newtopsize |PINUSE_BIT;
+ m->top = newtop;
+ m->topsize = newtopsize;
+ newp = oldp;
+ }
+ }
+ else {
+ USAGE_ERROR_ACTION(m, oldmem);
+ POSTACTION(m);
+ return 0;
+ }
+#if DEBUG
+ if (newp != 0) {
+ check_inuse_chunk(m, newp); /* Check requires lock */
+ }
+#endif
+
+ POSTACTION(m);
+
+ if (newp != 0) {
+ if (extra != 0) {
+ internal_free(m, extra);
+ }
+ return chunk2mem(newp);
+ }
+ else {
+ void* newmem = internal_malloc(m, bytes);
+ if (newmem != 0) {
+ size_t oc = oldsize - overhead_for(oldp);
+ memcpy(newmem, oldmem, (oc < bytes)? oc : bytes);
+ internal_free(m, oldmem);
+ }
+ return newmem;
+ }
+ }
+ return 0;
+}
+
+/* --------------------------- memalign support -------------------------- */
+
+static void* internal_memalign(mstate m, size_t alignment, size_t bytes) {
+ if (alignment <= MALLOC_ALIGNMENT) /* Can just use malloc */
+ return internal_malloc(m, bytes);
+ if (alignment < MIN_CHUNK_SIZE) /* must be at least a minimum chunk size */
+ alignment = MIN_CHUNK_SIZE;
+ if ((alignment & (alignment-SIZE_T_ONE)) != 0) {/* Ensure a power of 2 */
+ size_t a = MALLOC_ALIGNMENT << 1;
+ while (a < alignment) a <<= 1;
+ alignment = a;
+ }
+
+ if (bytes >= MAX_REQUEST - alignment) {
+ if (m != 0) { /* Test isn't needed but avoids compiler warning */
+ MALLOC_FAILURE_ACTION;
+ }
+ }
+ else {
+ size_t nb = request2size(bytes);
+ size_t req = nb + alignment + MIN_CHUNK_SIZE - CHUNK_OVERHEAD;
+ char* mem = (char*)internal_malloc(m, req);
+ if (mem != 0) {
+ void* leader = 0;
+ void* trailer = 0;
+ mchunkptr p = mem2chunk(mem);
+
+ if (PREACTION(m)) return 0;
+ if ((((size_t)(mem)) % alignment) != 0) { /* misaligned */
+ /*
+ Find an aligned spot inside chunk. Since we need to give
+ back leading space in a chunk of at least MIN_CHUNK_SIZE, if
+ the first calculation places us at a spot with less than
+ MIN_CHUNK_SIZE leader, we can move to the next aligned spot.
+ We've allocated enough total room so that this is always
+ possible.
+ */
+ char* br = (char*)mem2chunk((size_t)(((size_t)(mem +
+ alignment -
+ SIZE_T_ONE)) &
+ -alignment));
+ char* pos = ((size_t)(br - (char*)(p)) >= MIN_CHUNK_SIZE)?
+ br : br+alignment;
+ mchunkptr newp = (mchunkptr)pos;
+ size_t leadsize = pos - (char*)(p);
+ size_t newsize = chunksize(p) - leadsize;
+
+ if (is_mmapped(p)) { /* For mmapped chunks, just adjust offset */
+ newp->prev_foot = p->prev_foot + leadsize;
+ newp->head = newsize;
+ }
+ else { /* Otherwise, give back leader, use the rest */
+ set_inuse(m, newp, newsize);
+ set_inuse(m, p, leadsize);
+ leader = chunk2mem(p);
+ }
+ p = newp;
+ }
+
+ /* Give back spare room at the end */
+ if (!is_mmapped(p)) {
+ size_t size = chunksize(p);
+ if (size > nb + MIN_CHUNK_SIZE) {
+ size_t remainder_size = size - nb;
+ mchunkptr remainder = chunk_plus_offset(p, nb);
+ set_inuse(m, p, nb);
+ set_inuse(m, remainder, remainder_size);
+ trailer = chunk2mem(remainder);
+ }
+ }
+
+ assert (chunksize(p) >= nb);
+ assert((((size_t)(chunk2mem(p))) % alignment) == 0);
+ check_inuse_chunk(m, p);
+ POSTACTION(m);
+ if (leader != 0) {
+ internal_free(m, leader);
+ }
+ if (trailer != 0) {
+ internal_free(m, trailer);
+ }
+ return chunk2mem(p);
+ }
+ }
+ return 0;
+}
+
+/* ------------------------ comalloc/coalloc support --------------------- */
+
+static void** ialloc(mstate m,
+ size_t n_elements,
+ size_t* sizes,
+ int opts,
+ void* chunks[]) {
+ /*
+ This provides common support for independent_X routines, handling
+ all of the combinations that can result.
+
+ The opts arg has:
+ bit 0 set if all elements are same size (using sizes[0])
+ bit 1 set if elements should be zeroed
+ */
+
+ size_t element_size; /* chunksize of each element, if all same */
+ size_t contents_size; /* total size of elements */
+ size_t array_size; /* request size of pointer array */
+ void* mem; /* malloced aggregate space */
+ mchunkptr p; /* corresponding chunk */
+ size_t remainder_size; /* remaining bytes while splitting */
+ void** marray; /* either "chunks" or malloced ptr array */
+ mchunkptr array_chunk; /* chunk for malloced ptr array */
+ flag_t was_enabled; /* to disable mmap */
+ size_t size;
+ size_t i;
+
+ ensure_initialization();
+ /* compute array length, if needed */
+ if (chunks != 0) {
+ if (n_elements == 0)
+ return chunks; /* nothing to do */
+ marray = chunks;
+ array_size = 0;
+ }
+ else {
+ /* if empty req, must still return chunk representing empty array */
+ if (n_elements == 0)
+ return (void**)internal_malloc(m, 0);
+ marray = 0;
+ array_size = request2size(n_elements * (sizeof(void*)));
+ }
+
+ /* compute total element size */
+ if (opts & 0x1) { /* all-same-size */
+ element_size = request2size(*sizes);
+ contents_size = n_elements * element_size;
+ }
+ else { /* add up all the sizes */
+ element_size = 0;
+ contents_size = 0;
+ for (i = 0; i != n_elements; ++i)
+ contents_size += request2size(sizes[i]);
+ }
+
+ size = contents_size + array_size;
+
+ /*
+ Allocate the aggregate chunk. First disable direct-mmapping so
+ malloc won't use it, since we would not be able to later
+ free/realloc space internal to a segregated mmap region.
+ */
+ was_enabled = use_mmap(m);
+ disable_mmap(m);
+ mem = internal_malloc(m, size - CHUNK_OVERHEAD);
+ if (was_enabled)
+ enable_mmap(m);
+ if (mem == 0)
+ return 0;
+
+ if (PREACTION(m)) return 0;
+ p = mem2chunk(mem);
+ remainder_size = chunksize(p);
+
+ assert(!is_mmapped(p));
+
+ if (opts & 0x2) { /* optionally clear the elements */
+ memset((size_t*)mem, 0, remainder_size - SIZE_T_SIZE - array_size);
+ }
+
+ /* If not provided, allocate the pointer array as final part of chunk */
+ if (marray == 0) {
+ size_t array_chunk_size;
+ array_chunk = chunk_plus_offset(p, contents_size);
+ array_chunk_size = remainder_size - contents_size;
+ marray = (void**) (chunk2mem(array_chunk));
+ set_size_and_pinuse_of_inuse_chunk(m, array_chunk, array_chunk_size);
+ remainder_size = contents_size;
+ }
+
+ /* split out elements */
+ for (i = 0; ; ++i) {
+ marray[i] = chunk2mem(p);
+ if (i != n_elements-1) {
+ if (element_size != 0)
+ size = element_size;
+ else
+ size = request2size(sizes[i]);
+ remainder_size -= size;
+ set_size_and_pinuse_of_inuse_chunk(m, p, size);
+ p = chunk_plus_offset(p, size);
+ }
+ else { /* the final element absorbs any overallocation slop */
+ set_size_and_pinuse_of_inuse_chunk(m, p, remainder_size);
+ break;
+ }
+ }
+
+#if DEBUG
+ if (marray != chunks) {
+ /* final element must have exactly exhausted chunk */
+ if (element_size != 0) {
+ assert(remainder_size == element_size);
+ }
+ else {
+ assert(remainder_size == request2size(sizes[i]));
+ }
+ check_inuse_chunk(m, mem2chunk(marray));
+ }
+ for (i = 0; i != n_elements; ++i)
+ check_inuse_chunk(m, mem2chunk(marray[i]));
+
+#endif /* DEBUG */
+
+ POSTACTION(m);
+ return marray;
+}
+
+
+/* -------------------------- public routines ---------------------------- */
+
+#if !ONLY_MSPACES
+
+void* dlmalloc(size_t bytes) {
+ /*
+ Basic algorithm:
+ If a small request (< 256 bytes minus per-chunk overhead):
+ 1. If one exists, use a remainderless chunk in associated smallbin.
+ (Remainderless means that there are too few excess bytes to
+ represent as a chunk.)
+ 2. If it is big enough, use the dv chunk, which is normally the
+ chunk adjacent to the one used for the most recent small request.
+ 3. If one exists, split the smallest available chunk in a bin,
+ saving remainder in dv.
+ 4. If it is big enough, use the top chunk.
+ 5. If available, get memory from system and use it
+ Otherwise, for a large request:
+ 1. Find the smallest available binned chunk that fits, and use it
+ if it is better fitting than dv chunk, splitting if necessary.
+ 2. If better fitting than any binned chunk, use the dv chunk.
+ 3. If it is big enough, use the top chunk.
+ 4. If request size >= mmap threshold, try to directly mmap this chunk.
+ 5. If available, get memory from system and use it
+
+ The ugly goto's here ensure that postaction occurs along all paths.
+ */
+
+#if USE_LOCKS
+ ensure_initialization(); /* initialize in sys_alloc if not using locks */
+#endif
+
+ if (!PREACTION(gm)) {
+ void* mem;
+ size_t nb;
+ if (bytes <= MAX_SMALL_REQUEST) {
+ bindex_t idx;
+ binmap_t smallbits;
+ nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);
+ idx = small_index(nb);
+ smallbits = gm->smallmap >> idx;
+
+ if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */
+ mchunkptr b, p;
+ idx += ~smallbits & 1; /* Uses next bin if idx empty */
+ b = smallbin_at(gm, idx);
+ p = b->fd;
+ assert(chunksize(p) == small_index2size(idx));
+ unlink_first_small_chunk(gm, b, p, idx);
+ set_inuse_and_pinuse(gm, p, small_index2size(idx));
+ mem = chunk2mem(p);
+ check_malloced_chunk(gm, mem, nb);
+ goto postaction;
+ }
+
+ else if (nb > gm->dvsize) {
+ if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
+ mchunkptr b, p, r;
+ size_t rsize;
+ bindex_t i;
+ binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));
+ binmap_t leastbit = least_bit(leftbits);
+ compute_bit2idx(leastbit, i);
+ b = smallbin_at(gm, i);
+ p = b->fd;
+ assert(chunksize(p) == small_index2size(i));
+ unlink_first_small_chunk(gm, b, p, i);
+ rsize = small_index2size(i) - nb;
+ /* Fit here cannot be remainderless if 4byte sizes */
+ if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
+ set_inuse_and_pinuse(gm, p, small_index2size(i));
+ else {
+ set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
+ r = chunk_plus_offset(p, nb);
+ set_size_and_pinuse_of_free_chunk(r, rsize);
+ replace_dv(gm, r, rsize);
+ }
+ mem = chunk2mem(p);
+ check_malloced_chunk(gm, mem, nb);
+ goto postaction;
+ }
+
+ else if (gm->treemap != 0 && (mem = tmalloc_small(gm, nb)) != 0) {
+ check_malloced_chunk(gm, mem, nb);
+ goto postaction;
+ }
+ }
+ }
+ else if (bytes >= MAX_REQUEST)
+ nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
+ else {
+ nb = pad_request(bytes);
+ if (gm->treemap != 0 && (mem = tmalloc_large(gm, nb)) != 0) {
+ check_malloced_chunk(gm, mem, nb);
+ goto postaction;
+ }
+ }
+
+ if (nb <= gm->dvsize) {
+ size_t rsize = gm->dvsize - nb;
+ mchunkptr p = gm->dv;
+ if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
+ mchunkptr r = gm->dv = chunk_plus_offset(p, nb);
+ gm->dvsize = rsize;
+ set_size_and_pinuse_of_free_chunk(r, rsize);
+ set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
+ }
+ else { /* exhaust dv */
+ size_t dvs = gm->dvsize;
+ gm->dvsize = 0;
+ gm->dv = 0;
+ set_inuse_and_pinuse(gm, p, dvs);
+ }
+ mem = chunk2mem(p);
+ check_malloced_chunk(gm, mem, nb);
+ goto postaction;
+ }
+
+ else if (nb < gm->topsize) { /* Split top */
+ size_t rsize = gm->topsize -= nb;
+ mchunkptr p = gm->top;
+ mchunkptr r = gm->top = chunk_plus_offset(p, nb);
+ r->head = rsize | PINUSE_BIT;
+ set_size_and_pinuse_of_inuse_chunk(gm, p, nb);
+ mem = chunk2mem(p);
+ check_top_chunk(gm, gm->top);
+ check_malloced_chunk(gm, mem, nb);
+ goto postaction;
+ }
+
+ mem = sys_alloc(gm, nb);
+
+ postaction:
+ POSTACTION(gm);
+ return mem;
+ }
+
+ return 0;
+}
+
+void dlfree(void* mem) {
+ /*
+ Consolidate freed chunks with preceeding or succeeding bordering
+ free chunks, if they exist, and then place in a bin. Intermixed
+ with special cases for top, dv, mmapped chunks, and usage errors.
+ */
+
+ if (mem != 0) {
+ mchunkptr p = mem2chunk(mem);
+#if FOOTERS
+ mstate fm = get_mstate_for(p);
+ if (!ok_magic(fm)) {
+ USAGE_ERROR_ACTION(fm, p);
+ return;
+ }
+#else /* FOOTERS */
+#define fm gm
+#endif /* FOOTERS */
+ if (!PREACTION(fm)) {
+ check_inuse_chunk(fm, p);
+ if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) {
+ size_t psize = chunksize(p);
+ mchunkptr next = chunk_plus_offset(p, psize);
+ if (!pinuse(p)) {
+ size_t prevsize = p->prev_foot;
+ if (is_mmapped(p)) {
+ psize += prevsize + MMAP_FOOT_PAD;
+ if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)
+ fm->footprint -= psize;
+ goto postaction;
+ }
+ else {
+ mchunkptr prev = chunk_minus_offset(p, prevsize);
+ psize += prevsize;
+ p = prev;
+ if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */
+ if (p != fm->dv) {
+ unlink_chunk(fm, p, prevsize);
+ }
+ else if ((next->head & INUSE_BITS) == INUSE_BITS) {
+ fm->dvsize = psize;
+ set_free_with_pinuse(p, psize, next);
+ goto postaction;
+ }
+ }
+ else
+ goto erroraction;
+ }
+ }
+
+ if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {
+ if (!cinuse(next)) { /* consolidate forward */
+ if (next == fm->top) {
+ size_t tsize = fm->topsize += psize;
+ fm->top = p;
+ p->head = tsize | PINUSE_BIT;
+ if (p == fm->dv) {
+ fm->dv = 0;
+ fm->dvsize = 0;
+ }
+ if (should_trim(fm, tsize))
+ sys_trim(fm, 0);
+ goto postaction;
+ }
+ else if (next == fm->dv) {
+ size_t dsize = fm->dvsize += psize;
+ fm->dv = p;
+ set_size_and_pinuse_of_free_chunk(p, dsize);
+ goto postaction;
+ }
+ else {
+ size_t nsize = chunksize(next);
+ psize += nsize;
+ unlink_chunk(fm, next, nsize);
+ set_size_and_pinuse_of_free_chunk(p, psize);
+ if (p == fm->dv) {
+ fm->dvsize = psize;
+ goto postaction;
+ }
+ }
+ }
+ else
+ set_free_with_pinuse(p, psize, next);
+
+ if (is_small(psize)) {
+ insert_small_chunk(fm, p, psize);
+ check_free_chunk(fm, p);
+ }
+ else {
+ tchunkptr tp = (tchunkptr)p;
+ insert_large_chunk(fm, tp, psize);
+ check_free_chunk(fm, p);
+ if (--fm->release_checks == 0)
+ release_unused_segments(fm);
+ }
+ goto postaction;
+ }
+ }
+ erroraction:
+ USAGE_ERROR_ACTION(fm, p);
+ postaction:
+ POSTACTION(fm);
+ }
+ }
+#if !FOOTERS
+#undef fm
+#endif /* FOOTERS */
+}
+
+void* dlcalloc(size_t n_elements, size_t elem_size) {
+ void* mem;
+ size_t req = 0;
+ if (n_elements != 0) {
+ req = n_elements * elem_size;
+ if (((n_elements | elem_size) & ~(size_t)0xffff) &&
+ (req / n_elements != elem_size))
+ req = MAX_SIZE_T; /* force downstream failure on overflow */
+ }
+ mem = dlmalloc(req);
+ if (mem != 0 && calloc_must_clear(mem2chunk(mem)))
+ memset(mem, 0, req);
+ return mem;
+}
+
+void* dlrealloc(void* oldmem, size_t bytes) {
+ if (oldmem == 0)
+ return dlmalloc(bytes);
+#ifdef REALLOC_ZERO_BYTES_FREES
+ if (bytes == 0) {
+ dlfree(oldmem);
+ return 0;
+ }
+#endif /* REALLOC_ZERO_BYTES_FREES */
+ else {
+#if ! FOOTERS
+ mstate m = gm;
+#else /* FOOTERS */
+ mstate m = get_mstate_for(mem2chunk(oldmem));
+ if (!ok_magic(m)) {
+ USAGE_ERROR_ACTION(m, oldmem);
+ return 0;
+ }
+#endif /* FOOTERS */
+ return internal_realloc(m, oldmem, bytes);
+ }
+}
+
+void* dlmemalign(size_t alignment, size_t bytes) {
+ return internal_memalign(gm, alignment, bytes);
+}
+
+void** dlindependent_calloc(size_t n_elements, size_t elem_size,
+ void* chunks[]) {
+ size_t sz = elem_size; /* serves as 1-element array */
+ return ialloc(gm, n_elements, &sz, 3, chunks);
+}
+
+void** dlindependent_comalloc(size_t n_elements, size_t sizes[],
+ void* chunks[]) {
+ return ialloc(gm, n_elements, sizes, 0, chunks);
+}
+
+void* dlvalloc(size_t bytes) {
+ size_t pagesz;
+ ensure_initialization();
+ pagesz = mparams.page_size;
+ return dlmemalign(pagesz, bytes);
+}
+
+void* dlpvalloc(size_t bytes) {
+ size_t pagesz;
+ ensure_initialization();
+ pagesz = mparams.page_size;
+ return dlmemalign(pagesz, (bytes + pagesz - SIZE_T_ONE) & ~(pagesz - SIZE_T_ONE));
+}
+
+int dlmalloc_trim(size_t pad) {
+ int result = 0;
+ ensure_initialization();
+ if (!PREACTION(gm)) {
+ result = sys_trim(gm, pad);
+ POSTACTION(gm);
+ }
+ return result;
+}
+
+size_t dlmalloc_footprint(void) {
+ return gm->footprint;
+}
+
+size_t dlmalloc_max_footprint(void) {
+ return gm->max_footprint;
+}
+
+#if !NO_MALLINFO
+struct mallinfo dlmallinfo(void) {
+ return internal_mallinfo(gm);
+}
+#endif /* NO_MALLINFO */
+
+void dlmalloc_stats() {
+ internal_malloc_stats(gm);
+}
+
+int dlmallopt(int param_number, int value) {
+ return change_mparam(param_number, value);
+}
+
+#endif /* !ONLY_MSPACES */
+
+size_t dlmalloc_usable_size(void* mem) {
+ if (mem != 0) {
+ mchunkptr p = mem2chunk(mem);
+ if (is_inuse(p))
+ return chunksize(p) - overhead_for(p);
+ }
+ return 0;
+}
+
+/* ----------------------------- user mspaces ---------------------------- */
+
+#if MSPACES
+
+static mstate init_user_mstate(char* tbase, size_t tsize) {
+ size_t msize = pad_request(sizeof(struct malloc_state));
+ mchunkptr mn;
+ mchunkptr msp = align_as_chunk(tbase);
+ mstate m = (mstate)(chunk2mem(msp));
+ memset(m, 0, msize);
+ INITIAL_LOCK(&m->mutex);
+ msp->head = (msize|INUSE_BITS);
+ m->seg.base = m->least_addr = tbase;
+ m->seg.size = m->footprint = m->max_footprint = tsize;
+ m->magic = mparams.magic;
+ m->release_checks = MAX_RELEASE_CHECK_RATE;
+ m->mflags = mparams.default_mflags;
+ m->extp = 0;
+ m->exts = 0;
+ disable_contiguous(m);
+ init_bins(m);
+ mn = next_chunk(mem2chunk(m));
+ init_top(m, mn, (size_t)((tbase + tsize) - (char*)mn) - TOP_FOOT_SIZE);
+ check_top_chunk(m, m->top);
+ return m;
+}
+
+mspace create_mspace(size_t capacity, int locked) {
+ mstate m = 0;
+ size_t msize;
+ ensure_initialization();
+ msize = pad_request(sizeof(struct malloc_state));
+ if (capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {
+ size_t rs = ((capacity == 0)? mparams.granularity :
+ (capacity + TOP_FOOT_SIZE + msize));
+ size_t tsize = granularity_align(rs);
+ char* tbase = (char*)(CALL_MMAP(tsize));
+ if (tbase != CMFAIL) {
+ m = init_user_mstate(tbase, tsize);
+ m->seg.sflags = USE_MMAP_BIT;
+ set_lock(m, locked);
+ }
+ }
+ return (mspace)m;
+}
+
+mspace create_mspace_with_base(void* base, size_t capacity, int locked) {
+ mstate m = 0;
+ size_t msize;
+ ensure_initialization();
+ msize = pad_request(sizeof(struct malloc_state));
+ if (capacity > msize + TOP_FOOT_SIZE &&
+ capacity < (size_t) -(msize + TOP_FOOT_SIZE + mparams.page_size)) {
+ m = init_user_mstate((char*)base, capacity);
+ m->seg.sflags = EXTERN_BIT;
+ set_lock(m, locked);
+ }
+ return (mspace)m;
+}
+
+int mspace_track_large_chunks(mspace msp, int enable) {
+ int ret = 0;
+ mstate ms = (mstate)msp;
+ if (!PREACTION(ms)) {
+ if (!use_mmap(ms))
+ ret = 1;
+ if (!enable)
+ enable_mmap(ms);
+ else
+ disable_mmap(ms);
+ POSTACTION(ms);
+ }
+ return ret;
+}
+
+size_t destroy_mspace(mspace msp) {
+ size_t freed = 0;
+ mstate ms = (mstate)msp;
+ if (ok_magic(ms)) {
+ msegmentptr sp = &ms->seg;
+ while (sp != 0) {
+ char* base = sp->base;
+ size_t size = sp->size;
+ flag_t flag = sp->sflags;
+ sp = sp->next;
+ if ((flag & USE_MMAP_BIT) && !(flag & EXTERN_BIT) &&
+ CALL_MUNMAP(base, size) == 0)
+ freed += size;
+ }
+ }
+ else {
+ USAGE_ERROR_ACTION(ms,ms);
+ }
+ return freed;
+}
+
+/*
+ mspace versions of routines are near-clones of the global
+ versions. This is not so nice but better than the alternatives.
+*/
+
+
+void* mspace_malloc(mspace msp, size_t bytes) {
+ mstate ms = (mstate)msp;
+ if (!ok_magic(ms)) {
+ USAGE_ERROR_ACTION(ms,ms);
+ return 0;
+ }
+ if (!PREACTION(ms)) {
+ void* mem;
+ size_t nb;
+ if (bytes <= MAX_SMALL_REQUEST) {
+ bindex_t idx;
+ binmap_t smallbits;
+ nb = (bytes < MIN_REQUEST)? MIN_CHUNK_SIZE : pad_request(bytes);
+ idx = small_index(nb);
+ smallbits = ms->smallmap >> idx;
+
+ if ((smallbits & 0x3U) != 0) { /* Remainderless fit to a smallbin. */
+ mchunkptr b, p;
+ idx += ~smallbits & 1; /* Uses next bin if idx empty */
+ b = smallbin_at(ms, idx);
+ p = b->fd;
+ assert(chunksize(p) == small_index2size(idx));
+ unlink_first_small_chunk(ms, b, p, idx);
+ set_inuse_and_pinuse(ms, p, small_index2size(idx));
+ mem = chunk2mem(p);
+ check_malloced_chunk(ms, mem, nb);
+ goto postaction;
+ }
+
+ else if (nb > ms->dvsize) {
+ if (smallbits != 0) { /* Use chunk in next nonempty smallbin */
+ mchunkptr b, p, r;
+ size_t rsize;
+ bindex_t i;
+ binmap_t leftbits = (smallbits << idx) & left_bits(idx2bit(idx));
+ binmap_t leastbit = least_bit(leftbits);
+ compute_bit2idx(leastbit, i);
+ b = smallbin_at(ms, i);
+ p = b->fd;
+ assert(chunksize(p) == small_index2size(i));
+ unlink_first_small_chunk(ms, b, p, i);
+ rsize = small_index2size(i) - nb;
+ /* Fit here cannot be remainderless if 4byte sizes */
+ if (SIZE_T_SIZE != 4 && rsize < MIN_CHUNK_SIZE)
+ set_inuse_and_pinuse(ms, p, small_index2size(i));
+ else {
+ set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
+ r = chunk_plus_offset(p, nb);
+ set_size_and_pinuse_of_free_chunk(r, rsize);
+ replace_dv(ms, r, rsize);
+ }
+ mem = chunk2mem(p);
+ check_malloced_chunk(ms, mem, nb);
+ goto postaction;
+ }
+
+ else if (ms->treemap != 0 && (mem = tmalloc_small(ms, nb)) != 0) {
+ check_malloced_chunk(ms, mem, nb);
+ goto postaction;
+ }
+ }
+ }
+ else if (bytes >= MAX_REQUEST)
+ nb = MAX_SIZE_T; /* Too big to allocate. Force failure (in sys alloc) */
+ else {
+ nb = pad_request(bytes);
+ if (ms->treemap != 0 && (mem = tmalloc_large(ms, nb)) != 0) {
+ check_malloced_chunk(ms, mem, nb);
+ goto postaction;
+ }
+ }
+
+ if (nb <= ms->dvsize) {
+ size_t rsize = ms->dvsize - nb;
+ mchunkptr p = ms->dv;
+ if (rsize >= MIN_CHUNK_SIZE) { /* split dv */
+ mchunkptr r = ms->dv = chunk_plus_offset(p, nb);
+ ms->dvsize = rsize;
+ set_size_and_pinuse_of_free_chunk(r, rsize);
+ set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
+ }
+ else { /* exhaust dv */
+ size_t dvs = ms->dvsize;
+ ms->dvsize = 0;
+ ms->dv = 0;
+ set_inuse_and_pinuse(ms, p, dvs);
+ }
+ mem = chunk2mem(p);
+ check_malloced_chunk(ms, mem, nb);
+ goto postaction;
+ }
+
+ else if (nb < ms->topsize) { /* Split top */
+ size_t rsize = ms->topsize -= nb;
+ mchunkptr p = ms->top;
+ mchunkptr r = ms->top = chunk_plus_offset(p, nb);
+ r->head = rsize | PINUSE_BIT;
+ set_size_and_pinuse_of_inuse_chunk(ms, p, nb);
+ mem = chunk2mem(p);
+ check_top_chunk(ms, ms->top);
+ check_malloced_chunk(ms, mem, nb);
+ goto postaction;
+ }
+
+ mem = sys_alloc(ms, nb);
+
+ postaction:
+ POSTACTION(ms);
+ return mem;
+ }
+
+ return 0;
+}
+
+void mspace_free(mspace msp, void* mem) {
+ if (mem != 0) {
+ mchunkptr p = mem2chunk(mem);
+#if FOOTERS
+ mstate fm = get_mstate_for(p);
+ msp = msp; /* placate people compiling -Wunused */
+#else /* FOOTERS */
+ mstate fm = (mstate)msp;
+#endif /* FOOTERS */
+ if (!ok_magic(fm)) {
+ USAGE_ERROR_ACTION(fm, p);
+ return;
+ }
+ if (!PREACTION(fm)) {
+ check_inuse_chunk(fm, p);
+ if (RTCHECK(ok_address(fm, p) && ok_inuse(p))) {
+ size_t psize = chunksize(p);
+ mchunkptr next = chunk_plus_offset(p, psize);
+ if (!pinuse(p)) {
+ size_t prevsize = p->prev_foot;
+ if (is_mmapped(p)) {
+ psize += prevsize + MMAP_FOOT_PAD;
+ if (CALL_MUNMAP((char*)p - prevsize, psize) == 0)
+ fm->footprint -= psize;
+ goto postaction;
+ }
+ else {
+ mchunkptr prev = chunk_minus_offset(p, prevsize);
+ psize += prevsize;
+ p = prev;
+ if (RTCHECK(ok_address(fm, prev))) { /* consolidate backward */
+ if (p != fm->dv) {
+ unlink_chunk(fm, p, prevsize);
+ }
+ else if ((next->head & INUSE_BITS) == INUSE_BITS) {
+ fm->dvsize = psize;
+ set_free_with_pinuse(p, psize, next);
+ goto postaction;
+ }
+ }
+ else
+ goto erroraction;
+ }
+ }
+
+ if (RTCHECK(ok_next(p, next) && ok_pinuse(next))) {
+ if (!cinuse(next)) { /* consolidate forward */
+ if (next == fm->top) {
+ size_t tsize = fm->topsize += psize;
+ fm->top = p;
+ p->head = tsize | PINUSE_BIT;
+ if (p == fm->dv) {
+ fm->dv = 0;
+ fm->dvsize = 0;
+ }
+ if (should_trim(fm, tsize))
+ sys_trim(fm, 0);
+ goto postaction;
+ }
+ else if (next == fm->dv) {
+ size_t dsize = fm->dvsize += psize;
+ fm->dv = p;
+ set_size_and_pinuse_of_free_chunk(p, dsize);
+ goto postaction;
+ }
+ else {
+ size_t nsize = chunksize(next);
+ psize += nsize;
+ unlink_chunk(fm, next, nsize);
+ set_size_and_pinuse_of_free_chunk(p, psize);
+ if (p == fm->dv) {
+ fm->dvsize = psize;
+ goto postaction;
+ }
+ }
+ }
+ else
+ set_free_with_pinuse(p, psize, next);
+
+ if (is_small(psize)) {
+ insert_small_chunk(fm, p, psize);
+ check_free_chunk(fm, p);
+ }
+ else {
+ tchunkptr tp = (tchunkptr)p;
+ insert_large_chunk(fm, tp, psize);
+ check_free_chunk(fm, p);
+ if (--fm->release_checks == 0)
+ release_unused_segments(fm);
+ }
+ goto postaction;
+ }
+ }
+ erroraction:
+ USAGE_ERROR_ACTION(fm, p);
+ postaction:
+ POSTACTION(fm);
+ }
+ }
+}
+
+void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size) {
+ void* mem;
+ size_t req = 0;
+ mstate ms = (mstate)msp;
+ if (!ok_magic(ms)) {
+ USAGE_ERROR_ACTION(ms,ms);
+ return 0;
+ }
+ if (n_elements != 0) {
+ req = n_elements * elem_size;
+ if (((n_elements | elem_size) & ~(size_t)0xffff) &&
+ (req / n_elements != elem_size))
+ req = MAX_SIZE_T; /* force downstream failure on overflow */
+ }
+ mem = internal_malloc(ms, req);
+ if (mem != 0 && calloc_must_clear(mem2chunk(mem)))
+ memset(mem, 0, req);
+ return mem;
+}
+
+void* mspace_realloc(mspace msp, void* oldmem, size_t bytes) {
+ if (oldmem == 0)
+ return mspace_malloc(msp, bytes);
+#ifdef REALLOC_ZERO_BYTES_FREES
+ if (bytes == 0) {
+ mspace_free(msp, oldmem);
+ return 0;
+ }
+#endif /* REALLOC_ZERO_BYTES_FREES */
+ else {
+#if FOOTERS
+ mchunkptr p = mem2chunk(oldmem);
+ mstate ms = get_mstate_for(p);
+#else /* FOOTERS */
+ mstate ms = (mstate)msp;
+#endif /* FOOTERS */
+ if (!ok_magic(ms)) {
+ USAGE_ERROR_ACTION(ms,ms);
+ return 0;
+ }
+ return internal_realloc(ms, oldmem, bytes);
+ }
+}
+
+void* mspace_memalign(mspace msp, size_t alignment, size_t bytes) {
+ mstate ms = (mstate)msp;
+ if (!ok_magic(ms)) {
+ USAGE_ERROR_ACTION(ms,ms);
+ return 0;
+ }
+ return internal_memalign(ms, alignment, bytes);
+}
+
+void** mspace_independent_calloc(mspace msp, size_t n_elements,
+ size_t elem_size, void* chunks[]) {
+ size_t sz = elem_size; /* serves as 1-element array */
+ mstate ms = (mstate)msp;
+ if (!ok_magic(ms)) {
+ USAGE_ERROR_ACTION(ms,ms);
+ return 0;
+ }
+ return ialloc(ms, n_elements, &sz, 3, chunks);
+}
+
+void** mspace_independent_comalloc(mspace msp, size_t n_elements,
+ size_t sizes[], void* chunks[]) {
+ mstate ms = (mstate)msp;
+ if (!ok_magic(ms)) {
+ USAGE_ERROR_ACTION(ms,ms);
+ return 0;
+ }
+ return ialloc(ms, n_elements, sizes, 0, chunks);
+}
+
+int mspace_trim(mspace msp, size_t pad) {
+ int result = 0;
+ mstate ms = (mstate)msp;
+ if (ok_magic(ms)) {
+ if (!PREACTION(ms)) {
+ result = sys_trim(ms, pad);
+ POSTACTION(ms);
+ }
+ }
+ else {
+ USAGE_ERROR_ACTION(ms,ms);
+ }
+ return result;
+}
+
+void mspace_malloc_stats(mspace msp) {
+ mstate ms = (mstate)msp;
+ if (ok_magic(ms)) {
+ internal_malloc_stats(ms);
+ }
+ else {
+ USAGE_ERROR_ACTION(ms,ms);
+ }
+}
+
+size_t mspace_footprint(mspace msp) {
+ size_t result = 0;
+ mstate ms = (mstate)msp;
+ if (ok_magic(ms)) {
+ result = ms->footprint;
+ }
+ else {
+ USAGE_ERROR_ACTION(ms,ms);
+ }
+ return result;
+}
+
+
+size_t mspace_max_footprint(mspace msp) {
+ size_t result = 0;
+ mstate ms = (mstate)msp;
+ if (ok_magic(ms)) {
+ result = ms->max_footprint;
+ }
+ else {
+ USAGE_ERROR_ACTION(ms,ms);
+ }
+ return result;
+}
+
+
+#if !NO_MALLINFO
+struct mallinfo mspace_mallinfo(mspace msp) {
+ mstate ms = (mstate)msp;
+ if (!ok_magic(ms)) {
+ USAGE_ERROR_ACTION(ms,ms);
+ }
+ return internal_mallinfo(ms);
+}
+#endif /* NO_MALLINFO */
+
+size_t mspace_usable_size(void* mem) {
+ if (mem != 0) {
+ mchunkptr p = mem2chunk(mem);
+ if (is_inuse(p))
+ return chunksize(p) - overhead_for(p);
+ }
+ return 0;
+}
+
+int mspace_mallopt(int param_number, int value) {
+ return change_mparam(param_number, value);
+}
+
+#endif /* MSPACES */
+
+
+/* -------------------- Alternative MORECORE functions ------------------- */
+
+/*
+ Guidelines for creating a custom version of MORECORE:
+
+ * For best performance, MORECORE should allocate in multiples of pagesize.
+ * MORECORE may allocate more memory than requested. (Or even less,
+ but this will usually result in a malloc failure.)
+ * MORECORE must not allocate memory when given argument zero, but
+ instead return one past the end address of memory from previous
+ nonzero call.
+ * For best performance, consecutive calls to MORECORE with positive
+ arguments should return increasing addresses, indicating that
+ space has been contiguously extended.
+ * Even though consecutive calls to MORECORE need not return contiguous
+ addresses, it must be OK for malloc'ed chunks to span multiple
+ regions in those cases where they do happen to be contiguous.
+ * MORECORE need not handle negative arguments -- it may instead
+ just return MFAIL when given negative arguments.
+ Negative arguments are always multiples of pagesize. MORECORE
+ must not misinterpret negative args as large positive unsigned
+ args. You can suppress all such calls from even occurring by defining
+ MORECORE_CANNOT_TRIM,
+
+ As an example alternative MORECORE, here is a custom allocator
+ kindly contributed for pre-OSX macOS. It uses virtually but not
+ necessarily physically contiguous non-paged memory (locked in,
+ present and won't get swapped out). You can use it by uncommenting
+ this section, adding some #includes, and setting up the appropriate
+ defines above:
+
+ #define MORECORE osMoreCore
+
+ There is also a shutdown routine that should somehow be called for
+ cleanup upon program exit.
+
+ #define MAX_POOL_ENTRIES 100
+ #define MINIMUM_MORECORE_SIZE (64 * 1024U)
+ static int next_os_pool;
+ void *our_os_pools[MAX_POOL_ENTRIES];
+
+ void *osMoreCore(int size)
+ {
+ void *ptr = 0;
+ static void *sbrk_top = 0;
+
+ if (size > 0)
+ {
+ if (size < MINIMUM_MORECORE_SIZE)
+ size = MINIMUM_MORECORE_SIZE;
+ if (CurrentExecutionLevel() == kTaskLevel)
+ ptr = PoolAllocateResident(size + RM_PAGE_SIZE, 0);
+ if (ptr == 0)
+ {
+ return (void *) MFAIL;
+ }
+ // save ptrs so they can be freed during cleanup
+ our_os_pools[next_os_pool] = ptr;
+ next_os_pool++;
+ ptr = (void *) ((((size_t) ptr) + RM_PAGE_MASK) & ~RM_PAGE_MASK);
+ sbrk_top = (char *) ptr + size;
+ return ptr;
+ }
+ else if (size < 0)
+ {
+ // we don't currently support shrink behavior
+ return (void *) MFAIL;
+ }
+ else
+ {
+ return sbrk_top;
+ }
+ }
+
+ // cleanup any allocated memory pools
+ // called as last thing before shutting down driver
+
+ void osCleanupMem(void)
+ {
+ void **ptr;
+
+ for (ptr = our_os_pools; ptr < &our_os_pools[MAX_POOL_ENTRIES]; ptr++)
+ if (*ptr)
+ {
+ PoolDeallocate(*ptr);
+ *ptr = 0;
+ }
+ }
+
+*/
+
+
+/* -----------------------------------------------------------------------
+History:
+ V2.8.4 Wed May 27 09:56:23 2009 Doug Lea (dl at gee)
+ * Use zeros instead of prev foot for is_mmapped
+ * Add mspace_track_large_chunks; thanks to Jean Brouwers
+ * Fix set_inuse in internal_realloc; thanks to Jean Brouwers
+ * Fix insufficient sys_alloc padding when using 16byte alignment
+ * Fix bad error check in mspace_footprint
+ * Adaptations for ptmalloc; thanks to Wolfram Gloger.
+ * Reentrant spin locks; thanks to Earl Chew and others
+ * Win32 improvements; thanks to Niall Douglas and Earl Chew
+ * Add NO_SEGMENT_TRAVERSAL and MAX_RELEASE_CHECK_RATE options
+ * Extension hook in malloc_state
+ * Various small adjustments to reduce warnings on some compilers
+ * Various configuration extensions/changes for more platforms. Thanks
+ to all who contributed these.
+
+ V2.8.3 Thu Sep 22 11:16:32 2005 Doug Lea (dl at gee)
+ * Add max_footprint functions
+ * Ensure all appropriate literals are size_t
+ * Fix conditional compilation problem for some #define settings
+ * Avoid concatenating segments with the one provided
+ in create_mspace_with_base
+ * Rename some variables to avoid compiler shadowing warnings
+ * Use explicit lock initialization.
+ * Better handling of sbrk interference.
+ * Simplify and fix segment insertion, trimming and mspace_destroy
+ * Reinstate REALLOC_ZERO_BYTES_FREES option from 2.7.x
+ * Thanks especially to Dennis Flanagan for help on these.
+
+ V2.8.2 Sun Jun 12 16:01:10 2005 Doug Lea (dl at gee)
+ * Fix memalign brace error.
+
+ V2.8.1 Wed Jun 8 16:11:46 2005 Doug Lea (dl at gee)
+ * Fix improper #endif nesting in C++
+ * Add explicit casts needed for C++
+
+ V2.8.0 Mon May 30 14:09:02 2005 Doug Lea (dl at gee)
+ * Use trees for large bins
+ * Support mspaces
+ * Use segments to unify sbrk-based and mmap-based system allocation,
+ removing need for emulation on most platforms without sbrk.
+ * Default safety checks
+ * Optional footer checks. Thanks to William Robertson for the idea.
+ * Internal code refactoring
+ * Incorporate suggestions and platform-specific changes.
+ Thanks to Dennis Flanagan, Colin Plumb, Niall Douglas,
+ Aaron Bachmann, Emery Berger, and others.
+ * Speed up non-fastbin processing enough to remove fastbins.
+ * Remove useless cfree() to avoid conflicts with other apps.
+ * Remove internal memcpy, memset. Compilers handle builtins better.
+ * Remove some options that no one ever used and rename others.
+
+ V2.7.2 Sat Aug 17 09:07:30 2002 Doug Lea (dl at gee)
+ * Fix malloc_state bitmap array misdeclaration
+
+ V2.7.1 Thu Jul 25 10:58:03 2002 Doug Lea (dl at gee)
+ * Allow tuning of FIRST_SORTED_BIN_SIZE
+ * Use PTR_UINT as type for all ptr->int casts. Thanks to John Belmonte.
+ * Better detection and support for non-contiguousness of MORECORE.
+ Thanks to Andreas Mueller, Conal Walsh, and Wolfram Gloger
+ * Bypass most of malloc if no frees. Thanks To Emery Berger.
+ * Fix freeing of old top non-contiguous chunk im sysmalloc.
+ * Raised default trim and map thresholds to 256K.
+ * Fix mmap-related #defines. Thanks to Lubos Lunak.
+ * Fix copy macros; added LACKS_FCNTL_H. Thanks to Neal Walfield.
+ * Branch-free bin calculation
+ * Default trim and mmap thresholds now 256K.
+
+ V2.7.0 Sun Mar 11 14:14:06 2001 Doug Lea (dl at gee)
+ * Introduce independent_comalloc and independent_calloc.
+ Thanks to Michael Pachos for motivation and help.
+ * Make optional .h file available
+ * Allow > 2GB requests on 32bit systems.
+ * new WIN32 sbrk, mmap, munmap, lock code from <Walter@GeNeSys-e.de>.
+ Thanks also to Andreas Mueller <a.mueller at paradatec.de>,
+ and Anonymous.
+ * Allow override of MALLOC_ALIGNMENT (Thanks to Ruud Waij for
+ helping test this.)
+ * memalign: check alignment arg
+ * realloc: don't try to shift chunks backwards, since this
+ leads to more fragmentation in some programs and doesn't
+ seem to help in any others.
+ * Collect all cases in malloc requiring system memory into sysmalloc
+ * Use mmap as backup to sbrk
+ * Place all internal state in malloc_state
+ * Introduce fastbins (although similar to 2.5.1)
+ * Many minor tunings and cosmetic improvements
+ * Introduce USE_PUBLIC_MALLOC_WRAPPERS, USE_MALLOC_LOCK
+ * Introduce MALLOC_FAILURE_ACTION, MORECORE_CONTIGUOUS
+ Thanks to Tony E. Bennett <tbennett@nvidia.com> and others.
+ * Include errno.h to support default failure action.
+
+ V2.6.6 Sun Dec 5 07:42:19 1999 Doug Lea (dl at gee)
+ * return null for negative arguments
+ * Added Several WIN32 cleanups from Martin C. Fong <mcfong at yahoo.com>
+ * Add 'LACKS_SYS_PARAM_H' for those systems without 'sys/param.h'
+ (e.g. WIN32 platforms)
+ * Cleanup header file inclusion for WIN32 platforms
+ * Cleanup code to avoid Microsoft Visual C++ compiler complaints
+ * Add 'USE_DL_PREFIX' to quickly allow co-existence with existing
+ memory allocation routines
+ * Set 'malloc_getpagesize' for WIN32 platforms (needs more work)
+ * Use 'assert' rather than 'ASSERT' in WIN32 code to conform to
+ usage of 'assert' in non-WIN32 code
+ * Improve WIN32 'sbrk()' emulation's 'findRegion()' routine to
+ avoid infinite loop
+ * Always call 'fREe()' rather than 'free()'
+
+ V2.6.5 Wed Jun 17 15:57:31 1998 Doug Lea (dl at gee)
+ * Fixed ordering problem with boundary-stamping
+
+ V2.6.3 Sun May 19 08:17:58 1996 Doug Lea (dl at gee)
+ * Added pvalloc, as recommended by H.J. Liu
+ * Added 64bit pointer support mainly from Wolfram Gloger
+ * Added anonymously donated WIN32 sbrk emulation
+ * Malloc, calloc, getpagesize: add optimizations from Raymond Nijssen
+ * malloc_extend_top: fix mask error that caused wastage after
+ foreign sbrks
+ * Add linux mremap support code from HJ Liu
+
+ V2.6.2 Tue Dec 5 06:52:55 1995 Doug Lea (dl at gee)
+ * Integrated most documentation with the code.
+ * Add support for mmap, with help from
+ Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+ * Use last_remainder in more cases.
+ * Pack bins using idea from colin@nyx10.cs.du.edu
+ * Use ordered bins instead of best-fit threshhold
+ * Eliminate block-local decls to simplify tracing and debugging.
+ * Support another case of realloc via move into top
+ * Fix error occuring when initial sbrk_base not word-aligned.
+ * Rely on page size for units instead of SBRK_UNIT to
+ avoid surprises about sbrk alignment conventions.
+ * Add mallinfo, mallopt. Thanks to Raymond Nijssen
+ (raymond@es.ele.tue.nl) for the suggestion.
+ * Add `pad' argument to malloc_trim and top_pad mallopt parameter.
+ * More precautions for cases where other routines call sbrk,
+ courtesy of Wolfram Gloger (Gloger@lrz.uni-muenchen.de).
+ * Added macros etc., allowing use in linux libc from
+ H.J. Lu (hjl@gnu.ai.mit.edu)
+ * Inverted this history list
+
+ V2.6.1 Sat Dec 2 14:10:57 1995 Doug Lea (dl at gee)
+ * Re-tuned and fixed to behave more nicely with V2.6.0 changes.
+ * Removed all preallocation code since under current scheme
+ the work required to undo bad preallocations exceeds
+ the work saved in good cases for most test programs.
+ * No longer use return list or unconsolidated bins since
+ no scheme using them consistently outperforms those that don't
+ given above changes.
+ * Use best fit for very large chunks to prevent some worst-cases.
+ * Added some support for debugging
+
+ V2.6.0 Sat Nov 4 07:05:23 1995 Doug Lea (dl at gee)
+ * Removed footers when chunks are in use. Thanks to
+ Paul Wilson (wilson@cs.texas.edu) for the suggestion.
+
+ V2.5.4 Wed Nov 1 07:54:51 1995 Doug Lea (dl at gee)
+ * Added malloc_trim, with help from Wolfram Gloger
+ (wmglo@Dent.MED.Uni-Muenchen.DE).
+
+ V2.5.3 Tue Apr 26 10:16:01 1994 Doug Lea (dl at g)
+
+ V2.5.2 Tue Apr 5 16:20:40 1994 Doug Lea (dl at g)
+ * realloc: try to expand in both directions
+ * malloc: swap order of clean-bin strategy;
+ * realloc: only conditionally expand backwards
+ * Try not to scavenge used bins
+ * Use bin counts as a guide to preallocation
+ * Occasionally bin return list chunks in first scan
+ * Add a few optimizations from colin@nyx10.cs.du.edu
+
+ V2.5.1 Sat Aug 14 15:40:43 1993 Doug Lea (dl at g)
+ * faster bin computation & slightly different binning
+ * merged all consolidations to one part of malloc proper
+ (eliminating old malloc_find_space & malloc_clean_bin)
+ * Scan 2 returns chunks (not just 1)
+ * Propagate failure in realloc if malloc returns 0
+ * Add stuff to allow compilation on non-ANSI compilers
+ from kpv@research.att.com
+
+ V2.5 Sat Aug 7 07:41:59 1993 Doug Lea (dl at g.oswego.edu)
+ * removed potential for odd address access in prev_chunk
+ * removed dependency on getpagesize.h
+ * misc cosmetics and a bit more internal documentation
+ * anticosmetics: mangled names in macros to evade debugger strangeness
+ * tested on sparc, hp-700, dec-mips, rs6000
+ with gcc & native cc (hp, dec only) allowing
+ Detlefs & Zorn comparison study (in SIGPLAN Notices.)
+
+ Trial version Fri Aug 28 13:14:29 1992 Doug Lea (dl at g.oswego.edu)
+ * Based loosely on libg++-1.2X malloc. (It retains some of the overall
+ structure of old version, but most details differ.)
+
+*/
+
+#endif
diff --git a/drivers/nedmalloc/memory_pool_static_nedmalloc.cpp b/drivers/nedmalloc/memory_pool_static_nedmalloc.cpp
index 76090844fe..301e94bb7b 100644
--- a/drivers/nedmalloc/memory_pool_static_nedmalloc.cpp
+++ b/drivers/nedmalloc/memory_pool_static_nedmalloc.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/*************************************************/
/* Source code within this file is: */
-/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
/* All Rights Reserved. */
/*************************************************/
diff --git a/drivers/nedmalloc/memory_pool_static_nedmalloc.h b/drivers/nedmalloc/memory_pool_static_nedmalloc.h
index 49f648a37b..20b060537c 100644
--- a/drivers/nedmalloc/memory_pool_static_nedmalloc.h
+++ b/drivers/nedmalloc/memory_pool_static_nedmalloc.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/*************************************************/
/* Source code within this file is: */
-/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
/* All Rights Reserved. */
/*************************************************/
diff --git a/drivers/nedmalloc/nedmalloc.cpp b/drivers/nedmalloc/nedmalloc.cpp
index 8845d96549..9aac277a2a 100644
--- a/drivers/nedmalloc/nedmalloc.cpp
+++ b/drivers/nedmalloc/nedmalloc.cpp
@@ -1,1467 +1,1467 @@
-#ifdef NEDMALLOC_ENABLED
-/* Alternative malloc implementation for multiple threads without
-lock contention based on dlmalloc. (C) 2005-2009 Niall Douglas
-
-Boost Software License - Version 1.0 - August 17th, 2003
-
-Permission is hereby granted, free of charge, to any person or organization
-obtaining a copy of the software and accompanying documentation covered by
-this license (the "Software") to use, reproduce, display, distribute,
-execute, and transmit the Software, and to prepare derivative works of the
-Software, and to permit third-parties to whom the Software is furnished to
-do so, all subject to the following:
-
-The copyright notices in the Software and this entire statement, including
-the above license grant, this restriction and the following disclaimer,
-must be included in all copies of the Software, in whole or in part, and
-all derivative works of the Software, unless such copies or derivative
-works are solely in the form of machine-executable object code generated by
-a source language processor.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
-SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
-FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
-ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
-*/
-
-#ifdef _MSC_VER
-/* Enable full aliasing on MSVC */
-/*#pragma optimize("a", on)*/
-#pragma warning(push)
-#pragma warning(disable:4100) /* unreferenced formal parameter */
-#pragma warning(disable:4127) /* conditional expression is constant */
-#pragma warning(disable:4706) /* assignment within conditional expression */
-#endif
-
-/*#define ENABLE_TOLERANT_NEDMALLOC 1*/
-/*#define ENABLE_FAST_HEAP_DETECTION 1*/
-/*#define NEDMALLOC_DEBUG 1*/
-
-/*#define FULLSANITYCHECKS*/
-/* If link time code generation is on, don't force or prevent inlining */
-#if defined(_MSC_VER) && defined(NEDMALLOC_DLL_EXPORTS)
-#define FORCEINLINE
-#define NOINLINE
-#endif
-
-
-#include "nedmalloc.h"
-#ifdef WIN32
- #include <malloc.h>
- #include <stddef.h>
-#endif
-#if USE_ALLOCATOR==1
- #define MSPACES 1
- #define ONLY_MSPACES 1
-#endif
-#define USE_DL_PREFIX 1
-#ifndef USE_LOCKS
- #define USE_LOCKS 1
-#endif
-#define FOOTERS 1 /* Need to enable footers so frees lock the right mspace */
-#ifndef NEDMALLOC_DEBUG
- #if defined(DEBUG) || defined(_DEBUG)
- #define NEDMALLOC_DEBUG 1
- #else
- #define NEDMALLOC_DEBUG 0
- #endif
-#endif
-/* We need to consistently define DEBUG=0|1, _DEBUG and NDEBUG for dlmalloc */
-#undef DEBUG
-#undef _DEBUG
-#if NEDMALLOC_DEBUG
- #define _DEBUG
- #define DEBUG 1
-#else
- #define DEBUG 0
-#endif
-#ifdef NDEBUG /* Disable assert checking on release builds */
- #undef DEBUG
- #undef _DEBUG
-#endif
-/* The default of 64Kb means we spend too much time kernel-side */
-#ifndef DEFAULT_GRANULARITY
-#define DEFAULT_GRANULARITY (1*1024*1024)
-#if DEBUG
-#define DEFAULT_GRANULARITY_ALIGNED
-#endif
-#endif
-/*#define USE_SPIN_LOCKS 0*/
-
-
-#include "malloc.c.h"
-#ifdef NDEBUG /* Disable assert checking on release builds */
- #undef DEBUG
-#elif !NEDMALLOC_DEBUG
- #ifdef __GNUC__
- #warning DEBUG is defined so allocator will run with assert checking! Define NDEBUG to run at full speed.
- #elif defined(_MSC_VER)
- #pragma message(__FILE__ ": WARNING: DEBUG is defined so allocator will run with assert checking! Define NDEBUG to run at full speed.")
- #endif
-#endif
-
-/* The maximum concurrent threads in a pool possible */
-#ifndef MAXTHREADSINPOOL
-#define MAXTHREADSINPOOL 16
-#endif
-/* The maximum number of threadcaches which can be allocated */
-#ifndef THREADCACHEMAXCACHES
-#define THREADCACHEMAXCACHES 256
-#endif
-/* The maximum size to be allocated from the thread cache */
-#ifndef THREADCACHEMAX
-#define THREADCACHEMAX 8192
-#endif
-#if 0
-/* The number of cache entries for finer grained bins. This is (topbitpos(THREADCACHEMAX)-4)*2 */
-#define THREADCACHEMAXBINS ((13-4)*2)
-#else
-/* The number of cache entries. This is (topbitpos(THREADCACHEMAX)-4) */
-#define THREADCACHEMAXBINS (13-4)
-#endif
-/* Point at which the free space in a thread cache is garbage collected */
-#ifndef THREADCACHEMAXFREESPACE
-#define THREADCACHEMAXFREESPACE (512*1024)
-#endif
-
-
-#ifdef WIN32
- #define TLSVAR DWORD
- #define TLSALLOC(k) (*(k)=TlsAlloc(), TLS_OUT_OF_INDEXES==*(k))
- #define TLSFREE(k) (!TlsFree(k))
- #define TLSGET(k) TlsGetValue(k)
- #define TLSSET(k, a) (!TlsSetValue(k, a))
- #ifdef DEBUG
-static LPVOID ChkedTlsGetValue(DWORD idx)
-{
- LPVOID ret=TlsGetValue(idx);
- assert(S_OK==GetLastError());
- return ret;
-}
- #undef TLSGET
- #define TLSGET(k) ChkedTlsGetValue(k)
- #endif
-#else
- #define TLSVAR pthread_key_t
- #define TLSALLOC(k) pthread_key_create(k, 0)
- #define TLSFREE(k) pthread_key_delete(k)
- #define TLSGET(k) pthread_getspecific(k)
- #define TLSSET(k, a) pthread_setspecific(k, a)
-#endif
-
-#if defined(__cplusplus)
-#if !defined(NO_NED_NAMESPACE)
-namespace nedalloc {
-#else
-extern "C" {
-#endif
-#endif
-
-#if USE_ALLOCATOR==0
-static void *unsupported_operation(const char *opname) THROWSPEC
-{
- fprintf(stderr, "nedmalloc: The operation %s is not supported under this build configuration\n", opname);
- abort();
- return 0;
-}
-static size_t mspacecounter=(size_t) 0xdeadbeef;
-#endif
-#ifndef ENABLE_FAST_HEAP_DETECTION
-static void *RESTRICT leastusedaddress;
-static size_t largestusedblock;
-#endif
-
-static FORCEINLINE void *CallMalloc(void *RESTRICT mspace, size_t size, size_t alignment) THROWSPEC
-{
- void *RESTRICT ret=0;
- size_t _alignment=alignment;
-#if USE_MAGIC_HEADERS
- size_t *_ret=0;
- size+=alignment+3*sizeof(size_t);
- _alignment=0;
-#endif
-#if USE_ALLOCATOR==0
- ret=_alignment ?
-#ifdef _MSC_VER
- /* This is the MSVCRT equivalent */
- _aligned_malloc(size, _alignment)
-#elif defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
- /* This is the glibc/ptmalloc2/dlmalloc/BSD libc equivalent. */
- memalign(_alignment, size)
-#else
-#error Cannot aligned allocate with the memory allocator of an unknown system!
-#endif
- : malloc(size);
-#elif USE_ALLOCATOR==1
- ret=_alignment ? mspace_memalign((mstate) mspace, _alignment, size) : mspace_malloc((mstate) mspace, size);
-#ifndef ENABLE_FAST_HEAP_DETECTION
- if(ret)
- {
- size_t truesize=chunksize(mem2chunk(ret));
- if(!leastusedaddress || (void *)((mstate) mspace)->least_addr<leastusedaddress) leastusedaddress=(void *)((mstate) mspace)->least_addr;
- if(!largestusedblock || truesize>largestusedblock) largestusedblock=(truesize+mparams.page_size) & ~(mparams.page_size-1);
- }
-#endif
-#endif
- if(!ret) return 0;
-#if USE_MAGIC_HEADERS
- _ret=(size_t *) ret;
- ret=(void *)(_ret+3);
- if(alignment) ret=(void *)(((size_t) ret+alignment-1)&~(alignment-1));
- for(; _ret<(size_t *)ret-2; _ret++) *_ret=*(size_t *)"NEDMALOC";
- _ret[0]=(size_t) mspace;
- _ret[1]=size-3*sizeof(size_t);
-#endif
- return ret;
-}
-
-static FORCEINLINE void *CallCalloc(void *RESTRICT mspace, size_t size, size_t alignment) THROWSPEC
-{
- void *RESTRICT ret=0;
-#if USE_MAGIC_HEADERS
- size_t *_ret=0;
- size+=alignment+3*sizeof(size_t);
-#endif
-#if USE_ALLOCATOR==0
- ret=calloc(1, size);
-#elif USE_ALLOCATOR==1
- ret=mspace_calloc((mstate) mspace, 1, size);
-#ifndef ENABLE_FAST_HEAP_DETECTION
- if(ret)
- {
- size_t truesize=chunksize(mem2chunk(ret));
- if(!leastusedaddress || (void *)((mstate) mspace)->least_addr<leastusedaddress) leastusedaddress=(void *)((mstate) mspace)->least_addr;
- if(!largestusedblock || truesize>largestusedblock) largestusedblock=(truesize+mparams.page_size) & ~(mparams.page_size-1);
- }
-#endif
-#endif
- if(!ret) return 0;
-#if USE_MAGIC_HEADERS
- _ret=(size_t *) ret;
- ret=(void *)(_ret+3);
- if(alignment) ret=(void *)(((size_t) ret+alignment-1)&~(alignment-1));
- for(; _ret<(size_t *)ret-2; _ret++) *_ret=*(size_t *) "NEDMALOC";
- _ret[0]=(size_t) mspace;
- _ret[1]=size-3*sizeof(size_t);
-#endif
- return ret;
-}
-
-static FORCEINLINE void *CallRealloc(void *RESTRICT mspace, void *RESTRICT mem, int isforeign, size_t oldsize, size_t newsize) THROWSPEC
-{
- void *RESTRICT ret=0;
-#if USE_MAGIC_HEADERS
- mstate oldmspace=0;
- size_t *_ret=0, *_mem=(size_t *) mem-3;
-#endif
- if(isforeign)
- { /* Transfer */
-#if USE_MAGIC_HEADERS
- assert(_mem[0]!=*(size_t *) "NEDMALOC");
-#endif
- if((ret=CallMalloc(mspace, newsize, 0)))
- {
-#if defined(DEBUG)
- printf("*** nedmalloc frees system allocated block %p\n", mem);
-#endif
- memcpy(ret, mem, oldsize<newsize ? oldsize : newsize);
- free(mem);
- }
- return ret;
- }
-#if USE_MAGIC_HEADERS
- assert(_mem[0]==*(size_t *) "NEDMALOC");
- newsize+=3*sizeof(size_t);
- oldmspace=(mstate) _mem[1];
- assert(oldsize>=_mem[2]);
- for(; *_mem==*(size_t *) "NEDMALOC"; *_mem--=*(size_t *) "nedmaloc");
- mem=(void *)(++_mem);
-#endif
-#if USE_ALLOCATOR==0
- ret=realloc(mem, newsize);
-#elif USE_ALLOCATOR==1
- ret=mspace_realloc((mstate) mspace, mem, newsize);
-#ifndef ENABLE_FAST_HEAP_DETECTION
- if(ret)
- {
- size_t truesize=chunksize(mem2chunk(ret));
- if(!largestusedblock || truesize>largestusedblock) largestusedblock=(truesize+mparams.page_size) & ~(mparams.page_size-1);
- }
-#endif
-#endif
- if(!ret)
- { /* Put it back the way it was */
-#if USE_MAGIC_HEADERS
- for(; *_mem==0; *_mem++=*(size_t *) "NEDMALOC");
-#endif
- return 0;
- }
-#if USE_MAGIC_HEADERS
- _ret=(size_t *) ret;
- ret=(void *)(_ret+3);
- for(; _ret<(size_t *)ret-2; _ret++) *_ret=*(size_t *) "NEDMALOC";
- _ret[0]=(size_t) mspace;
- _ret[1]=newsize-3*sizeof(size_t);
-#endif
- return ret;
-}
-
-static FORCEINLINE void CallFree(void *RESTRICT mspace, void *RESTRICT mem, int isforeign) THROWSPEC
-{
-#if USE_MAGIC_HEADERS
- mstate oldmspace=0;
- size_t *_mem=(size_t *) mem-3, oldsize=0;
-#endif
- if(isforeign)
- {
-#if USE_MAGIC_HEADERS
- assert(_mem[0]!=*(size_t *) "NEDMALOC");
-#endif
-#if defined(DEBUG)
- printf("*** nedmalloc frees system allocated block %p\n", mem);
-#endif
- free(mem);
- return;
- }
-#if USE_MAGIC_HEADERS
- assert(_mem[0]==*(size_t *) "NEDMALOC");
- oldmspace=(mstate) _mem[1];
- oldsize=_mem[2];
- for(; *_mem==*(size_t *) "NEDMALOC"; *_mem--=*(size_t *) "nedmaloc");
- mem=(void *)(++_mem);
-#endif
-#if USE_ALLOCATOR==0
- free(mem);
-#elif USE_ALLOCATOR==1
- mspace_free((mstate) mspace, mem);
-#endif
-}
-
-static NEDMALLOCNOALIASATTR mstate nedblkmstate(void *RESTRICT mem) THROWSPEC
-{
- if(mem)
- {
-#if USE_MAGIC_HEADERS
- size_t *_mem=(size_t *) mem-3;
- if(_mem[0]==*(size_t *) "NEDMALOC")
- {
- return (mstate) _mem[1];
- }
- else return 0;
-#else
-#if USE_ALLOCATOR==0
- /* Fail everything */
- return 0;
-#elif USE_ALLOCATOR==1
-#ifdef ENABLE_FAST_HEAP_DETECTION
-#ifdef WIN32
- /* On Windows for RELEASE both x86 and x64 the NT heap precedes each block with an eight byte header
- which looks like:
- normal: 4 bytes of size, 4 bytes of [char < 64, char < 64, char < 64 bit 0 always set, char random ]
- mmaped: 4 bytes of size 4 bytes of [zero, zero, 0xb, zero ]
-
- On Windows for DEBUG both x86 and x64 the preceding four bytes is always 0xfdfdfdfd (no man's land).
- */
-#pragma pack(push, 1)
- struct _HEAP_ENTRY
- {
- USHORT Size;
- USHORT PreviousSize;
- UCHAR Cookie; /* SegmentIndex */
- UCHAR Flags; /* always bit 0 (HEAP_ENTRY_BUSY). bit 1=(HEAP_ENTRY_EXTRA_PRESENT), bit 2=normal block (HEAP_ENTRY_FILL_PATTERN), bit 3=mmap block (HEAP_ENTRY_VIRTUAL_ALLOC). Bit 4 (HEAP_ENTRY_LAST_ENTRY) could be set */
- UCHAR UnusedBytes;
- UCHAR SmallTagIndex; /* fastbin index. Always one of 0x02, 0x03, 0x04 < 0x80 */
- } *RESTRICT he=((struct _HEAP_ENTRY *) mem)-1;
-#pragma pack(pop)
- unsigned int header=((unsigned int *)mem)[-1], mask1=0x8080E100, result1, mask2=0xFFFFFF06, result2;
- result1=header & mask1; /* Positive testing for NT heap */
- result2=header & mask2; /* Positive testing for dlmalloc */
- if(result1==0x00000100 && result2!=0x00000102)
- { /* This is likely a NT heap block */
- return 0;
- }
-#endif
-#ifdef __linux__
- /* On Linux glibc uses ptmalloc2 (really dlmalloc) just as we do, but prev_foot contains rubbish
- when the preceding block is allocated because ptmalloc2 finds the local mstate by rounding the ptr
- down to the nearest megabyte. It's like dlmalloc with FOOTERS disabled. */
- mchunkptr p=mem2chunk(mem);
- mstate fm=get_mstate_for(p);
- /* If it's a ptmalloc2 block, fm is likely to be some crazy value */
- if(!is_aligned(fm)) return 0;
- if((size_t)mem-(size_t)fm>=(size_t)1<<(SIZE_T_BITSIZE-1)) return 0;
- if(ok_magic(fm))
- return fm;
- else
- return 0;
- if(1) { }
-#endif
- else
- {
- mchunkptr p=mem2chunk(mem);
- mstate fm=get_mstate_for(p);
- assert(ok_magic(fm)); /* If this fails, someone tried to free a block twice */
- if(ok_magic(fm))
- return fm;
- }
-#else
-//#ifdef WIN32
-// __try
-//#endif
- {
- /* We try to return zero here if it isn't one of our own blocks, however
- the current block annotation scheme used by dlmalloc makes it impossible
- to be absolutely sure of avoiding a segfault.
-
- mchunkptr->prev_foot = mem-(2*size_t) = mstate ^ mparams.magic for PRECEDING block;
- mchunkptr->head = mem-(1*size_t) = 8 multiple size of this block with bottom three bits = FLAG_BITS
- FLAG_BITS = bit 0 is CINUSE (currently in use unless is mmap), bit 1 is PINUSE (previous block currently
- in use unless mmap), bit 2 is UNUSED and currently is always zero.
- */
- register void *RESTRICT leastusedaddress_=leastusedaddress; /* Cache these to avoid register reloading */
- register size_t largestusedblock_=largestusedblock;
- if(!is_aligned(mem)) return 0; /* Would fail very rarely as all allocators return aligned blocks */
- if(mem<leastusedaddress_) return 0; /* Simple but effective */
- {
- mchunkptr p=mem2chunk(mem);
- mstate fm=0;
- int ismmapped=is_mmapped(p);
- if((!ismmapped && !is_inuse(p)) || (p->head & FLAG4_BIT)) return 0;
- /* Reduced uncertainty by 0.5^2 = 25.0% */
- /* size should never exceed largestusedblock */
- if(chunksize(p)>largestusedblock_) return 0;
- /* Reduced uncertainty by a minimum of 0.5^3 = 12.5%, maximum 0.5^16 = 0.0015% */
- /* Having sanity checked prev_foot and head, check next block */
- if(!ismmapped && (!next_pinuse(p) || (next_chunk(p)->head & FLAG4_BIT))) return 0;
- /* Reduced uncertainty by 0.5^5 = 3.13% or 0.5^18 = 0.00038% */
- #if 0
- /* If previous block is free, check that its next block pointer equals us */
- if(!ismmapped && !pinuse(p))
- if(next_chunk(prev_chunk(p))!=p) return 0;
- /* We could start comparing prev_foot's for similarity but it starts getting slow. */
- #endif
- fm = get_mstate_for(p);
- if(!is_aligned(fm) || (void *)fm<leastusedaddress_) return 0;
- if((size_t)mem-(size_t)fm>=(size_t)1<<(SIZE_T_BITSIZE-1)) return 0;
- assert(ok_magic(fm)); /* If this fails, someone tried to free a block twice */
- if(ok_magic(fm))
- return fm;
- }
- }
-//#ifdef WIN32
-// __except(1) { }
-//#endif
-#endif
-#endif
-#endif
- }
- return 0;
-}
-NEDMALLOCNOALIASATTR size_t nedblksize(int *RESTRICT isforeign, void *RESTRICT mem) THROWSPEC
-{
- if(mem)
- {
- if(isforeign) *isforeign=1;
-#if USE_MAGIC_HEADERS
- {
- size_t *_mem=(size_t *) mem-3;
- if(_mem[0]==*(size_t *) "NEDMALOC")
- {
- mstate mspace=(mstate) _mem[1];
- size_t size=_mem[2];
- if(isforeign) *isforeign=0;
- return size;
- }
- }
-#elif USE_ALLOCATOR==1
- if(nedblkmstate(mem))
- {
- mchunkptr p=mem2chunk(mem);
- if(isforeign) *isforeign=0;
- return chunksize(p)-overhead_for(p);
- }
-#ifdef DEBUG
- else
- {
- int a=1; /* Set breakpoints here if needed */
- }
-#endif
-#endif
-#if defined(ENABLE_TOLERANT_NEDMALLOC) || USE_ALLOCATOR==0
-#ifdef _MSC_VER
- /* This is the MSVCRT equivalent */
- return _msize(mem);
-#elif defined(__linux__)
- /* This is the glibc/ptmalloc2/dlmalloc equivalent. */
- return malloc_usable_size(mem);
-#elif defined(__FreeBSD__) || defined(__APPLE__)
- /* This is the BSD libc equivalent. */
- return malloc_size(mem);
-#else
-#error Cannot tolerate the memory allocator of an unknown system!
-#endif
-#endif
- }
- return 0;
-}
-
-NEDMALLOCNOALIASATTR void nedsetvalue(void *v) THROWSPEC { nedpsetvalue((nedpool *) 0, v); }
-NEDMALLOCNOALIASATTR NEDMALLOCPTRATTR void * nedmalloc(size_t size) THROWSPEC { return nedpmalloc((nedpool *) 0, size); }
-NEDMALLOCNOALIASATTR NEDMALLOCPTRATTR void * nedcalloc(size_t no, size_t size) THROWSPEC { return nedpcalloc((nedpool *) 0, no, size); }
-NEDMALLOCNOALIASATTR NEDMALLOCPTRATTR void * nedrealloc(void *mem, size_t size) THROWSPEC { return nedprealloc((nedpool *) 0, mem, size); }
-NEDMALLOCNOALIASATTR void nedfree(void *mem) THROWSPEC { nedpfree((nedpool *) 0, mem); }
-NEDMALLOCNOALIASATTR NEDMALLOCPTRATTR void * nedmemalign(size_t alignment, size_t bytes) THROWSPEC { return nedpmemalign((nedpool *) 0, alignment, bytes); }
-NEDMALLOCNOALIASATTR struct nedmallinfo nedmallinfo(void) THROWSPEC { return nedpmallinfo((nedpool *) 0); }
-NEDMALLOCNOALIASATTR int nedmallopt(int parno, int value) THROWSPEC { return nedpmallopt((nedpool *) 0, parno, value); }
-NEDMALLOCNOALIASATTR int nedmalloc_trim(size_t pad) THROWSPEC { return nedpmalloc_trim((nedpool *) 0, pad); }
-void nedmalloc_stats() THROWSPEC { nedpmalloc_stats((nedpool *) 0); }
-NEDMALLOCNOALIASATTR size_t nedmalloc_footprint() THROWSPEC { return nedpmalloc_footprint((nedpool *) 0); }
-NEDMALLOCNOALIASATTR NEDMALLOCPTRATTR void **nedindependent_calloc(size_t elemsno, size_t elemsize, void **chunks) THROWSPEC { return nedpindependent_calloc((nedpool *) 0, elemsno, elemsize, chunks); }
-NEDMALLOCNOALIASATTR NEDMALLOCPTRATTR void **nedindependent_comalloc(size_t elems, size_t *sizes, void **chunks) THROWSPEC { return nedpindependent_comalloc((nedpool *) 0, elems, sizes, chunks); }
-
-struct threadcacheblk_t;
-typedef struct threadcacheblk_t threadcacheblk;
-struct threadcacheblk_t
-{ /* Keep less than 16 bytes on 32 bit systems and 32 bytes on 64 bit systems */
-#ifdef FULLSANITYCHECKS
- unsigned int magic;
-#endif
- unsigned int lastUsed, size;
- threadcacheblk *next, *prev;
-};
-typedef struct threadcache_t
-{
-#ifdef FULLSANITYCHECKS
- unsigned int magic1;
-#endif
- int mymspace; /* Last mspace entry this thread used */
- long threadid;
- unsigned int mallocs, frees, successes;
- size_t freeInCache; /* How much free space is stored in this cache */
- threadcacheblk *bins[(THREADCACHEMAXBINS+1)*2];
-#ifdef FULLSANITYCHECKS
- unsigned int magic2;
-#endif
-} threadcache;
-struct nedpool_t
-{
- MLOCK_T mutex;
- void *uservalue;
- int threads; /* Max entries in m to use */
- threadcache *caches[THREADCACHEMAXCACHES];
- TLSVAR mycache; /* Thread cache for this thread. 0 for unset, negative for use mspace-1 directly, otherwise is cache-1 */
- mstate m[MAXTHREADSINPOOL+1]; /* mspace entries for this pool */
-};
-static nedpool syspool;
-
-static FORCEINLINE NEDMALLOCNOALIASATTR unsigned int size2binidx(size_t _size) THROWSPEC
-{ /* 8=1000 16=10000 20=10100 24=11000 32=100000 48=110000 4096=1000000000000 */
- unsigned int topbit, size=(unsigned int)(_size>>4);
- /* 16=1 20=1 24=1 32=10 48=11 64=100 96=110 128=1000 4096=100000000 */
-
-#if defined(__GNUC__)
- topbit = sizeof(size)*__CHAR_BIT__ - 1 - __builtin_clz(size);
-#elif defined(_MSC_VER) && _MSC_VER>=1300
- {
- unsigned long bsrTopBit;
-
- _BitScanReverse(&bsrTopBit, size);
-
- topbit = bsrTopBit;
- }
-#else
-#if 0
- union {
- unsigned asInt[2];
- double asDouble;
- };
- int n;
-
- asDouble = (double)size + 0.5;
- topbit = (asInt[!FOX_BIGENDIAN] >> 20) - 1023;
-#else
- {
- unsigned int x=size;
- x = x | (x >> 1);
- x = x | (x >> 2);
- x = x | (x >> 4);
- x = x | (x >> 8);
- x = x | (x >>16);
- x = ~x;
- x = x - ((x >> 1) & 0x55555555);
- x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
- x = (x + (x >> 4)) & 0x0F0F0F0F;
- x = x + (x << 8);
- x = x + (x << 16);
- topbit=31 - (x >> 24);
- }
-#endif
-#endif
- return topbit;
-}
-
-
-#ifdef FULLSANITYCHECKS
-static void tcsanitycheck(threadcacheblk **ptr) THROWSPEC
-{
- assert((ptr[0] && ptr[1]) || (!ptr[0] && !ptr[1]));
- if(ptr[0] && ptr[1])
- {
- assert(nedblksize(ptr[0])>=sizeof(threadcacheblk));
- assert(nedblksize(ptr[1])>=sizeof(threadcacheblk));
- assert(*(unsigned int *) "NEDN"==ptr[0]->magic);
- assert(*(unsigned int *) "NEDN"==ptr[1]->magic);
- assert(!ptr[0]->prev);
- assert(!ptr[1]->next);
- if(ptr[0]==ptr[1])
- {
- assert(!ptr[0]->next);
- assert(!ptr[1]->prev);
- }
- }
-}
-static void tcfullsanitycheck(threadcache *tc) THROWSPEC
-{
- threadcacheblk **tcbptr=tc->bins;
- int n;
- for(n=0; n<=THREADCACHEMAXBINS; n++, tcbptr+=2)
- {
- threadcacheblk *b, *ob=0;
- tcsanitycheck(tcbptr);
- for(b=tcbptr[0]; b; ob=b, b=b->next)
- {
- assert(*(unsigned int *) "NEDN"==b->magic);
- assert(!ob || ob->next==b);
- assert(!ob || b->prev==ob);
- }
- }
-}
-#endif
-
-static NOINLINE void RemoveCacheEntries(nedpool *RESTRICT p, threadcache *RESTRICT tc, unsigned int age) THROWSPEC
-{
-#ifdef FULLSANITYCHECKS
- tcfullsanitycheck(tc);
-#endif
- if(tc->freeInCache)
- {
- threadcacheblk **tcbptr=tc->bins;
- int n;
- for(n=0; n<=THREADCACHEMAXBINS; n++, tcbptr+=2)
- {
- threadcacheblk **tcb=tcbptr+1; /* come from oldest end of list */
- /*tcsanitycheck(tcbptr);*/
- for(; *tcb && tc->frees-(*tcb)->lastUsed>=age; )
- {
- threadcacheblk *f=*tcb;
- size_t blksize=f->size; /*nedblksize(f);*/
- assert(blksize<=nedblksize(0, f));
- assert(blksize);
-#ifdef FULLSANITYCHECKS
- assert(*(unsigned int *) "NEDN"==(*tcb)->magic);
-#endif
- *tcb=(*tcb)->prev;
- if(*tcb)
- (*tcb)->next=0;
- else
- *tcbptr=0;
- tc->freeInCache-=blksize;
- assert((long) tc->freeInCache>=0);
- CallFree(0, f, 0);
- /*tcsanitycheck(tcbptr);*/
- }
- }
- }
-#ifdef FULLSANITYCHECKS
- tcfullsanitycheck(tc);
-#endif
-}
-static void DestroyCaches(nedpool *RESTRICT p) THROWSPEC
-{
- if(p->caches)
- {
- threadcache *tc;
- int n;
- for(n=0; n<THREADCACHEMAXCACHES; n++)
- {
- if((tc=p->caches[n]))
- {
- tc->frees++;
- RemoveCacheEntries(p, tc, 0);
- assert(!tc->freeInCache);
- tc->mymspace=-1;
- tc->threadid=0;
- CallFree(0, tc, 0);
- p->caches[n]=0;
- }
- }
- }
-}
-
-static NOINLINE threadcache *AllocCache(nedpool *RESTRICT p) THROWSPEC
-{
- threadcache *tc=0;
- int n, end;
- ACQUIRE_LOCK(&p->mutex);
- for(n=0; n<THREADCACHEMAXCACHES && p->caches[n]; n++);
- if(THREADCACHEMAXCACHES==n)
- { /* List exhausted, so disable for this thread */
- RELEASE_LOCK(&p->mutex);
- return 0;
- }
- tc=p->caches[n]=(threadcache *) CallCalloc(p->m[0], sizeof(threadcache), 0);
- if(!tc)
- {
- RELEASE_LOCK(&p->mutex);
- return 0;
- }
-#ifdef FULLSANITYCHECKS
- tc->magic1=*(unsigned int *)"NEDMALC1";
- tc->magic2=*(unsigned int *)"NEDMALC2";
-#endif
- tc->threadid=(long)(size_t)CURRENT_THREAD;
- for(end=0; p->m[end]; end++);
- tc->mymspace=abs(tc->threadid) % end;
- RELEASE_LOCK(&p->mutex);
- if(TLSSET(p->mycache, (void *)(size_t)(n+1))) abort();
- return tc;
-}
-
-static void *threadcache_malloc(nedpool *RESTRICT p, threadcache *RESTRICT tc, size_t *RESTRICT _size) THROWSPEC
-{
- void *RESTRICT ret=0;
- size_t size=*_size, blksize=0;
- unsigned int bestsize;
- unsigned int idx=size2binidx(size);
- threadcacheblk *RESTRICT blk, **RESTRICT binsptr;
-#ifdef FULLSANITYCHECKS
- tcfullsanitycheck(tc);
-#endif
- /* Calculate best fit bin size */
- bestsize=1<<(idx+4);
-#if 0
- /* Finer grained bin fit */
- idx<<=1;
- if(size>bestsize)
- {
- idx++;
- bestsize+=bestsize>>1;
- }
- if(size>bestsize)
- {
- idx++;
- bestsize=1<<(4+(idx>>1));
- }
-#else
- if(size>bestsize)
- {
- idx++;
- bestsize<<=1;
- }
-#endif
- assert(bestsize>=size);
- if(size<bestsize) size=bestsize;
- assert(size<=THREADCACHEMAX);
- assert(idx<=THREADCACHEMAXBINS);
- binsptr=&tc->bins[idx*2];
- /* Try to match close, but move up a bin if necessary */
- blk=*binsptr;
- if(!blk || blk->size<size)
- { /* Bump it up a bin */
- if(idx<THREADCACHEMAXBINS)
- {
- idx++;
- binsptr+=2;
- blk=*binsptr;
- }
- }
- if(blk)
- {
- blksize=blk->size; /*nedblksize(blk);*/
- assert(nedblksize(0, blk)>=blksize);
- assert(blksize>=size);
- if(blk->next)
- blk->next->prev=0;
- *binsptr=blk->next;
- if(!*binsptr)
- binsptr[1]=0;
-#ifdef FULLSANITYCHECKS
- blk->magic=0;
-#endif
- assert(binsptr[0]!=blk && binsptr[1]!=blk);
- assert(nedblksize(0, blk)>=sizeof(threadcacheblk) && nedblksize(0, blk)<=THREADCACHEMAX+CHUNK_OVERHEAD);
- /*printf("malloc: %p, %p, %p, %lu\n", p, tc, blk, (long) _size);*/
- ret=(void *) blk;
- }
- ++tc->mallocs;
- if(ret)
- {
- assert(blksize>=size);
- ++tc->successes;
- tc->freeInCache-=blksize;
- assert((long) tc->freeInCache>=0);
- }
-#if defined(DEBUG) && 0
- if(!(tc->mallocs & 0xfff))
- {
- printf("*** threadcache=%u, mallocs=%u (%f), free=%u (%f), freeInCache=%u\n", (unsigned int) tc->threadid, tc->mallocs,
- (float) tc->successes/tc->mallocs, tc->frees, (float) tc->successes/tc->frees, (unsigned int) tc->freeInCache);
- }
-#endif
-#ifdef FULLSANITYCHECKS
- tcfullsanitycheck(tc);
-#endif
- *_size=size;
- return ret;
-}
-static NOINLINE void ReleaseFreeInCache(nedpool *RESTRICT p, threadcache *RESTRICT tc, int mymspace) THROWSPEC
-{
- unsigned int age=THREADCACHEMAXFREESPACE/8192;
- /*ACQUIRE_LOCK(&p->m[mymspace]->mutex);*/
- while(age && tc->freeInCache>=THREADCACHEMAXFREESPACE)
- {
- RemoveCacheEntries(p, tc, age);
- /*printf("*** Removing cache entries older than %u (%u)\n", age, (unsigned int) tc->freeInCache);*/
- age>>=1;
- }
- /*RELEASE_LOCK(&p->m[mymspace]->mutex);*/
-}
-static void threadcache_free(nedpool *RESTRICT p, threadcache *RESTRICT tc, int mymspace, void *RESTRICT mem, size_t size) THROWSPEC
-{
- unsigned int bestsize;
- unsigned int idx=size2binidx(size);
- threadcacheblk **RESTRICT binsptr, *RESTRICT tck=(threadcacheblk *) mem;
- assert(size>=sizeof(threadcacheblk) && size<=THREADCACHEMAX+CHUNK_OVERHEAD);
-#ifdef DEBUG
- /* Make sure this is a valid memory block */
- assert(nedblksize(0, mem));
-#endif
-#ifdef FULLSANITYCHECKS
- tcfullsanitycheck(tc);
-#endif
- /* Calculate best fit bin size */
- bestsize=1<<(idx+4);
-#if 0
- /* Finer grained bin fit */
- idx<<=1;
- if(size>bestsize)
- {
- unsigned int biggerbestsize=bestsize+bestsize<<1;
- if(size>=biggerbestsize)
- {
- idx++;
- bestsize=biggerbestsize;
- }
- }
-#endif
- if(bestsize!=size) /* dlmalloc can round up, so we round down to preserve indexing */
- size=bestsize;
- binsptr=&tc->bins[idx*2];
- assert(idx<=THREADCACHEMAXBINS);
- if(tck==*binsptr)
- {
- fprintf(stderr, "nedmalloc: Attempt to free already freed memory block %p - aborting!\n", tck);
- abort();
- }
-#ifdef FULLSANITYCHECKS
- tck->magic=*(unsigned int *) "NEDN";
-#endif
- tck->lastUsed=++tc->frees;
- tck->size=(unsigned int) size;
- tck->next=*binsptr;
- tck->prev=0;
- if(tck->next)
- tck->next->prev=tck;
- else
- binsptr[1]=tck;
- assert(!*binsptr || (*binsptr)->size==tck->size);
- *binsptr=tck;
- assert(tck==tc->bins[idx*2]);
- assert(tc->bins[idx*2+1]==tck || binsptr[0]->next->prev==tck);
- /*printf("free: %p, %p, %p, %lu\n", p, tc, mem, (long) size);*/
- tc->freeInCache+=size;
-#ifdef FULLSANITYCHECKS
- tcfullsanitycheck(tc);
-#endif
-#if 1
- if(tc->freeInCache>=THREADCACHEMAXFREESPACE)
- ReleaseFreeInCache(p, tc, mymspace);
-#endif
-}
-
-
-
-
-static NOINLINE int InitPool(nedpool *RESTRICT p, size_t capacity, int threads) THROWSPEC
-{ /* threads is -1 for system pool */
- ensure_initialization();
- ACQUIRE_MALLOC_GLOBAL_LOCK();
- if(p->threads) goto done;
- if(INITIAL_LOCK(&p->mutex)) goto err;
- if(TLSALLOC(&p->mycache)) goto err;
-#if USE_ALLOCATOR==0
- p->m[0]=(mstate) mspacecounter++;
-#elif USE_ALLOCATOR==1
- if(!(p->m[0]=(mstate) create_mspace(capacity, 1))) goto err;
- p->m[0]->extp=p;
-#endif
- p->threads=(threads<1 || threads>MAXTHREADSINPOOL) ? MAXTHREADSINPOOL : threads;
-done:
- RELEASE_MALLOC_GLOBAL_LOCK();
- return 1;
-err:
- if(threads<0)
- abort(); /* If you can't allocate for system pool, we're screwed */
- DestroyCaches(p);
- if(p->m[0])
- {
-#if USE_ALLOCATOR==1
- destroy_mspace(p->m[0]);
-#endif
- p->m[0]=0;
- }
- if(p->mycache)
- {
- if(TLSFREE(p->mycache)) abort();
- p->mycache=0;
- }
- RELEASE_MALLOC_GLOBAL_LOCK();
- return 0;
-}
-static NOINLINE mstate FindMSpace(nedpool *RESTRICT p, threadcache *RESTRICT tc, int *RESTRICT lastUsed, size_t size) THROWSPEC
-{ /* Gets called when thread's last used mspace is in use. The strategy
- is to run through the list of all available mspaces looking for an
- unlocked one and if we fail, we create a new one so long as we don't
- exceed p->threads */
- int n, end;
- for(n=end=*lastUsed+1; p->m[n]; end=++n)
- {
- if(TRY_LOCK(&p->m[n]->mutex)) goto found;
- }
- for(n=0; n<*lastUsed && p->m[n]; n++)
- {
- if(TRY_LOCK(&p->m[n]->mutex)) goto found;
- }
- if(end<p->threads)
- {
- mstate temp;
-#if USE_ALLOCATOR==0
- temp=(mstate) mspacecounter++;
-#elif USE_ALLOCATOR==1
- if(!(temp=(mstate) create_mspace(size, 1)))
- goto badexit;
-#endif
- /* Now we're ready to modify the lists, we lock */
- ACQUIRE_LOCK(&p->mutex);
- while(p->m[end] && end<p->threads)
- end++;
- if(end>=p->threads)
- { /* Drat, must destroy it now */
- RELEASE_LOCK(&p->mutex);
-#if USE_ALLOCATOR==1
- destroy_mspace((mstate) temp);
-#endif
- goto badexit;
- }
- /* We really want to make sure this goes into memory now but we
- have to be careful of breaking aliasing rules, so write it twice */
- *((volatile struct malloc_state **) &p->m[end])=p->m[end]=temp;
- ACQUIRE_LOCK(&p->m[end]->mutex);
- /*printf("Created mspace idx %d\n", end);*/
- RELEASE_LOCK(&p->mutex);
- n=end;
- goto found;
- }
- /* Let it lock on the last one it used */
-badexit:
- ACQUIRE_LOCK(&p->m[*lastUsed]->mutex);
- return p->m[*lastUsed];
-found:
- *lastUsed=n;
- if(tc)
- tc->mymspace=n;
- else
- {
- if(TLSSET(p->mycache, (void *)(size_t)(-(n+1)))) abort();
- }
- return p->m[n];
-}
-
-typedef struct PoolList_t
-{
- size_t size; /* Size of list */
- size_t length; /* Actual entries in list */
-#ifdef DEBUG
- nedpool *list[1]; /* Force testing of list expansion */
-#else
- nedpool *list[16];
-#endif
-} PoolList;
-static MLOCK_T poollistlock;
-static PoolList *poollist;
-NEDMALLOCPTRATTR nedpool *nedcreatepool(size_t capacity, int threads) THROWSPEC
-{
- nedpool *ret=0;
- if(!poollist)
- {
- PoolList *newpoollist=0;
- if(!(newpoollist=(PoolList *) nedpcalloc(0, 1, sizeof(PoolList)+sizeof(nedpool *)))) return 0;
- INITIAL_LOCK(&poollistlock);
- ACQUIRE_LOCK(&poollistlock);
- poollist=newpoollist;
- poollist->size=sizeof(poollist->list)/sizeof(nedpool *);
- }
- else
- ACQUIRE_LOCK(&poollistlock);
- if(poollist->length==poollist->size)
- {
- PoolList *newpoollist=0;
- size_t newsize=0;
- newsize=sizeof(PoolList)+(poollist->size+1)*sizeof(nedpool *);
- if(!(newpoollist=(PoolList *) nedprealloc(0, poollist, newsize))) goto badexit;
- poollist=newpoollist;
- memset(&poollist->list[poollist->size], 0, newsize-((size_t)&poollist->list[poollist->size]-(size_t)&poollist->list[0]));
- poollist->size=((newsize-((char *)&poollist->list[0]-(char *)poollist))/sizeof(nedpool *))-1;
- assert(poollist->size>poollist->length);
- }
- if(!(ret=(nedpool *) nedpcalloc(0, 1, sizeof(nedpool)))) goto badexit;
- if(!InitPool(ret, capacity, threads))
- {
- nedpfree(0, ret);
- goto badexit;
- }
- poollist->list[poollist->length++]=ret;
-badexit:
- RELEASE_LOCK(&poollistlock);
- return ret;
-}
-void neddestroypool(nedpool *p) THROWSPEC
-{
- unsigned int n;
- ACQUIRE_LOCK(&p->mutex);
- DestroyCaches(p);
- for(n=0; p->m[n]; n++)
- {
-#if USE_ALLOCATOR==1
- destroy_mspace(p->m[n]);
-#endif
- p->m[n]=0;
- }
- RELEASE_LOCK(&p->mutex);
- if(TLSFREE(p->mycache)) abort();
- nedpfree(0, p);
- ACQUIRE_LOCK(&poollistlock);
- assert(poollist);
- for(n=0; n<poollist->length && poollist->list[n]!=p; n++);
- assert(n!=poollist->length);
- memmove(&poollist->list[n], &poollist->list[n+1], (size_t)&poollist->list[poollist->length]-(size_t)&poollist->list[n]);
- if(!--poollist->length)
- {
- assert(!poollist->list[0]);
- nedpfree(0, poollist);
- poollist=0;
- }
- RELEASE_LOCK(&poollistlock);
-}
-void neddestroysyspool() THROWSPEC
-{
- nedpool *p=&syspool;
- int n;
- ACQUIRE_LOCK(&p->mutex);
- DestroyCaches(p);
- for(n=0; p->m[n]; n++)
- {
-#if USE_ALLOCATOR==1
- destroy_mspace(p->m[n]);
-#endif
- p->m[n]=0;
- }
- /* Render syspool unusable */
- for(n=0; n<THREADCACHEMAXCACHES; n++)
- p->caches[n]=(threadcache *)(size_t)(sizeof(size_t)>4 ? 0xdeadbeefdeadbeefULL : 0xdeadbeefUL);
- for(n=0; n<MAXTHREADSINPOOL+1; n++)
- p->m[n]=(mstate)(size_t)(sizeof(size_t)>4 ? 0xdeadbeefdeadbeefULL : 0xdeadbeefUL);
- if(TLSFREE(p->mycache)) abort();
- RELEASE_LOCK(&p->mutex);
-}
-nedpool **nedpoollist() THROWSPEC
-{
- nedpool **ret=0;
- if(poollist)
- {
- ACQUIRE_LOCK(&poollistlock);
- if(!(ret=(nedpool **) nedmalloc((poollist->length+1)*sizeof(nedpool *)))) goto badexit;
- memcpy(ret, poollist->list, (poollist->length+1)*sizeof(nedpool *));
-badexit:
- RELEASE_LOCK(&poollistlock);
- }
- return ret;
-}
-
-void nedpsetvalue(nedpool *p, void *v) THROWSPEC
-{
- if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
- p->uservalue=v;
-}
-void *nedgetvalue(nedpool **p, void *mem) THROWSPEC
-{
- nedpool *np=0;
- mstate fm=nedblkmstate(mem);
- if(!fm || !fm->extp) return 0;
- np=(nedpool *) fm->extp;
- if(p) *p=np;
- return np->uservalue;
-}
-
-void nedtrimthreadcache(nedpool *p, int disable) THROWSPEC
-{
- int mycache;
- if(!p)
- {
- p=&syspool;
- if(!syspool.threads) InitPool(&syspool, 0, -1);
- }
- mycache=(int)(size_t) TLSGET(p->mycache);
- if(!mycache)
- { /* Set to mspace 0 */
- if(disable && TLSSET(p->mycache, (void *)(size_t)-1)) abort();
- }
- else if(mycache>0)
- { /* Set to last used mspace */
- threadcache *tc=p->caches[mycache-1];
-#if defined(DEBUG)
- printf("Threadcache utilisation: %lf%% in cache with %lf%% lost to other threads\n",
- 100.0*tc->successes/tc->mallocs, 100.0*((double) tc->mallocs-tc->frees)/tc->mallocs);
-#endif
- if(disable && TLSSET(p->mycache, (void *)(size_t)(-tc->mymspace))) abort();
- tc->frees++;
- RemoveCacheEntries(p, tc, 0);
- assert(!tc->freeInCache);
- if(disable)
- {
- tc->mymspace=-1;
- tc->threadid=0;
- CallFree(0, p->caches[mycache-1], 0);
- p->caches[mycache-1]=0;
- }
- }
-}
-void neddisablethreadcache(nedpool *p) THROWSPEC
-{
- nedtrimthreadcache(p, 1);
-}
-
-#define GETMSPACE(m,p,tc,ms,s,action) \
- do \
- { \
- mstate m = GetMSpace((p),(tc),(ms),(s)); \
- action; \
- if(USE_ALLOCATOR==1) { RELEASE_LOCK(&m->mutex); } \
- } while (0)
-
-static FORCEINLINE mstate GetMSpace(nedpool *RESTRICT p, threadcache *RESTRICT tc, int mymspace, size_t size) THROWSPEC
-{ /* Returns a locked and ready for use mspace */
- mstate m=p->m[mymspace];
- assert(m);
-#if USE_ALLOCATOR==1
- if(!TRY_LOCK(&p->m[mymspace]->mutex)) m=FindMSpace(p, tc, &mymspace, size);
- /*assert(IS_LOCKED(&p->m[mymspace]->mutex));*/
-#endif
- return m;
-}
-static NOINLINE void GetThreadCache_cold1(nedpool *RESTRICT *RESTRICT p) THROWSPEC
-{
- *p=&syspool;
- if(!syspool.threads) InitPool(&syspool, 0, -1);
-}
-static NOINLINE void GetThreadCache_cold2(nedpool *RESTRICT *RESTRICT p, threadcache *RESTRICT *RESTRICT tc, int *RESTRICT mymspace, int mycache) THROWSPEC
-{
- if(!mycache)
- { /* Need to allocate a new cache */
- *tc=AllocCache(*p);
- if(!*tc)
- { /* Disable */
- if(TLSSET((*p)->mycache, (void *)(size_t)-1)) abort();
- *mymspace=0;
- }
- else
- *mymspace=(*tc)->mymspace;
- }
- else
- { /* Cache disabled, but we do have an assigned thread pool */
- *tc=0;
- *mymspace=-mycache-1;
- }
-}
-static FORCEINLINE void GetThreadCache(nedpool *RESTRICT *RESTRICT p, threadcache *RESTRICT *RESTRICT tc, int *RESTRICT mymspace, size_t *RESTRICT size) THROWSPEC
-{
- int mycache;
- if(size && *size<sizeof(threadcacheblk)) *size=sizeof(threadcacheblk);
- if(!*p)
- GetThreadCache_cold1(p);
- mycache=(int)(size_t) TLSGET((*p)->mycache);
- if(mycache>0)
- { /* Already have a cache */
- *tc=(*p)->caches[mycache-1];
- *mymspace=(*tc)->mymspace;
- }
- else GetThreadCache_cold2(p, tc, mymspace, mycache);
- assert(*mymspace>=0);
- assert(!(*tc) || (long)(size_t)CURRENT_THREAD==(*tc)->threadid);
-#ifdef FULLSANITYCHECKS
- if(*tc)
- {
- if(*(unsigned int *)"NEDMALC1"!=(*tc)->magic1 || *(unsigned int *)"NEDMALC2"!=(*tc)->magic2)
- {
- abort();
- }
- }
-#endif
-}
-
-NEDMALLOCPTRATTR void * nedpmalloc(nedpool *p, size_t size) THROWSPEC
-{
- void *ret=0;
- threadcache *tc;
- int mymspace;
- GetThreadCache(&p, &tc, &mymspace, &size);
-#if THREADCACHEMAX
- if(tc && size<=THREADCACHEMAX)
- { /* Use the thread cache */
- ret=threadcache_malloc(p, tc, &size);
- }
-#endif
- if(!ret)
- { /* Use this thread's mspace */
- GETMSPACE(m, p, tc, mymspace, size,
- ret=CallMalloc(m, size, 0));
- }
- return ret;
-}
-NEDMALLOCPTRATTR void * nedpcalloc(nedpool *p, size_t no, size_t size) THROWSPEC
-{
- size_t rsize=size*no;
- void *ret=0;
- threadcache *tc;
- int mymspace;
- GetThreadCache(&p, &tc, &mymspace, &rsize);
-#if THREADCACHEMAX
- if(tc && rsize<=THREADCACHEMAX)
- { /* Use the thread cache */
- if((ret=threadcache_malloc(p, tc, &rsize)))
- memset(ret, 0, rsize);
- }
-#endif
- if(!ret)
- { /* Use this thread's mspace */
- GETMSPACE(m, p, tc, mymspace, rsize,
- ret=CallCalloc(m, rsize, 0));
- }
- return ret;
-}
-NEDMALLOCPTRATTR void * nedprealloc(nedpool *p, void *mem, size_t size) THROWSPEC
-{
- void *ret=0;
- threadcache *tc;
- int mymspace, isforeign=1;
- size_t memsize;
- if(!mem) return nedpmalloc(p, size);
- memsize=nedblksize(&isforeign, mem);
- assert(memsize);
- if(!memsize)
- {
- fprintf(stderr, "nedmalloc: nedprealloc() called with a block not created by nedmalloc!\n");
- abort();
- }
- else if(size<=memsize && memsize-size<
-#ifdef DEBUG
- 32
-#else
- 1024
-#endif
- ) /* If realloc size is within 1Kb smaller than existing, noop it */
- return mem;
- GetThreadCache(&p, &tc, &mymspace, &size);
-#if THREADCACHEMAX
- if(tc && size && size<=THREADCACHEMAX)
- { /* Use the thread cache */
- if((ret=threadcache_malloc(p, tc, &size)))
- {
- memcpy(ret, mem, memsize<size ? memsize : size);
- if(memsize>=sizeof(threadcacheblk) && memsize<=(THREADCACHEMAX+CHUNK_OVERHEAD))
- threadcache_free(p, tc, mymspace, mem, memsize);
- else
- CallFree(0, mem, isforeign);
- }
- }
-#endif
- if(!ret)
- { /* Reallocs always happen in the mspace they happened in, so skip
- locking the preferred mspace for this thread */
- ret=CallRealloc(p->m[mymspace], mem, isforeign, memsize, size);
- }
- return ret;
-}
-void nedpfree(nedpool *p, void *mem) THROWSPEC
-{ /* Frees always happen in the mspace they happened in, so skip
- locking the preferred mspace for this thread */
- threadcache *tc;
- int mymspace, isforeign=1;
- size_t memsize;
- if(!mem)
- { /* If you tried this on FreeBSD you'd be sorry! */
-#ifdef DEBUG
- fprintf(stderr, "nedmalloc: WARNING nedpfree() called with zero. This is not portable behaviour!\n");
-#endif
- return;
- }
- memsize=nedblksize(&isforeign, mem);
- assert(memsize);
- if(!memsize)
- {
- fprintf(stderr, "nedmalloc: nedpfree() called with a block not created by nedmalloc!\n");
- abort();
- }
- GetThreadCache(&p, &tc, &mymspace, 0);
-#if THREADCACHEMAX
- if(mem && tc && memsize>=sizeof(threadcacheblk) && memsize<=(THREADCACHEMAX+CHUNK_OVERHEAD))
- threadcache_free(p, tc, mymspace, mem, memsize);
- else
-#endif
- CallFree(0, mem, isforeign);
-}
-NEDMALLOCPTRATTR void * nedpmemalign(nedpool *p, size_t alignment, size_t bytes) THROWSPEC
-{
- void *ret;
- threadcache *tc;
- int mymspace;
- GetThreadCache(&p, &tc, &mymspace, &bytes);
- { /* Use this thread's mspace */
- GETMSPACE(m, p, tc, mymspace, bytes,
- ret=CallMalloc(m, bytes, alignment));
- }
- return ret;
-}
-struct nedmallinfo nedpmallinfo(nedpool *p) THROWSPEC
-{
- int n;
- struct nedmallinfo ret={0};
- if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
- for(n=0; p->m[n]; n++)
- {
-#if USE_ALLOCATOR==1 && !NO_MALLINFO
- struct mallinfo t=mspace_mallinfo(p->m[n]);
- ret.arena+=t.arena;
- ret.ordblks+=t.ordblks;
- ret.hblkhd+=t.hblkhd;
- ret.usmblks+=t.usmblks;
- ret.uordblks+=t.uordblks;
- ret.fordblks+=t.fordblks;
- ret.keepcost+=t.keepcost;
-#endif
- }
- return ret;
-}
-int nedpmallopt(nedpool *p, int parno, int value) THROWSPEC
-{
-#if USE_ALLOCATOR==1
- return mspace_mallopt(parno, value);
-#else
- return 0;
-#endif
-}
-NEDMALLOCNOALIASATTR void* nedmalloc_internals(size_t *granularity, size_t *magic) THROWSPEC
-{
-#if USE_ALLOCATOR==1
- if(granularity) *granularity=mparams.granularity;
- if(magic) *magic=mparams.magic;
- return (void *) &syspool;
-#else
- if(granularity) *granularity=0;
- if(magic) *magic=0;
- return 0;
-#endif
-}
-int nedpmalloc_trim(nedpool *p, size_t pad) THROWSPEC
-{
- int n, ret=0;
- if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
- for(n=0; p->m[n]; n++)
- {
-#if USE_ALLOCATOR==1
- ret+=mspace_trim(p->m[n], pad);
-#endif
- }
- return ret;
-}
-void nedpmalloc_stats(nedpool *p) THROWSPEC
-{
- int n;
- if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
- for(n=0; p->m[n]; n++)
- {
-#if USE_ALLOCATOR==1
- mspace_malloc_stats(p->m[n]);
-#endif
- }
-}
-size_t nedpmalloc_footprint(nedpool *p) THROWSPEC
-{
- size_t ret=0;
- int n;
- if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
- for(n=0; p->m[n]; n++)
- {
-#if USE_ALLOCATOR==1
- ret+=mspace_footprint(p->m[n]);
-#endif
- }
- return ret;
-}
-NEDMALLOCPTRATTR void **nedpindependent_calloc(nedpool *p, size_t elemsno, size_t elemsize, void **chunks) THROWSPEC
-{
- void **ret;
- threadcache *tc;
- int mymspace;
- GetThreadCache(&p, &tc, &mymspace, &elemsize);
-#if USE_ALLOCATOR==0
- GETMSPACE(m, p, tc, mymspace, elemsno*elemsize,
- ret=unsupported_operation("independent_calloc"));
-#elif USE_ALLOCATOR==1
- GETMSPACE(m, p, tc, mymspace, elemsno*elemsize,
- ret=mspace_independent_calloc(m, elemsno, elemsize, chunks));
-#endif
- return ret;
-}
-NEDMALLOCPTRATTR void **nedpindependent_comalloc(nedpool *p, size_t elems, size_t *sizes, void **chunks) THROWSPEC
-{
- void **ret;
- threadcache *tc;
- int mymspace;
- size_t i, *adjustedsizes=(size_t *) alloca(elems*sizeof(size_t));
- if(!adjustedsizes) return 0;
- for(i=0; i<elems; i++)
- adjustedsizes[i]=sizes[i]<sizeof(threadcacheblk) ? sizeof(threadcacheblk) : sizes[i];
- GetThreadCache(&p, &tc, &mymspace, 0);
-#if USE_ALLOCATOR==0
- GETMSPACE(m, p, tc, mymspace, 0,
- ret=unsupported_operation("independent_comalloc"));
-#elif USE_ALLOCATOR==1
- GETMSPACE(m, p, tc, mymspace, 0,
- ret=mspace_independent_comalloc(m, elems, adjustedsizes, chunks));
-#endif
- return ret;
-}
-
-#if defined(__cplusplus)
-}
-#endif
-
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif
-
-#endif
+#ifdef NEDMALLOC_ENABLED
+/* Alternative malloc implementation for multiple threads without
+lock contention based on dlmalloc. (C) 2005-2009 Niall Douglas
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+#ifdef _MSC_VER
+/* Enable full aliasing on MSVC */
+/*#pragma optimize("a", on)*/
+#pragma warning(push)
+#pragma warning(disable:4100) /* unreferenced formal parameter */
+#pragma warning(disable:4127) /* conditional expression is constant */
+#pragma warning(disable:4706) /* assignment within conditional expression */
+#endif
+
+/*#define ENABLE_TOLERANT_NEDMALLOC 1*/
+/*#define ENABLE_FAST_HEAP_DETECTION 1*/
+/*#define NEDMALLOC_DEBUG 1*/
+
+/*#define FULLSANITYCHECKS*/
+/* If link time code generation is on, don't force or prevent inlining */
+#if defined(_MSC_VER) && defined(NEDMALLOC_DLL_EXPORTS)
+#define FORCEINLINE
+#define NOINLINE
+#endif
+
+
+#include "nedmalloc.h"
+#ifdef WIN32
+ #include <malloc.h>
+ #include <stddef.h>
+#endif
+#if USE_ALLOCATOR==1
+ #define MSPACES 1
+ #define ONLY_MSPACES 1
+#endif
+#define USE_DL_PREFIX 1
+#ifndef USE_LOCKS
+ #define USE_LOCKS 1
+#endif
+#define FOOTERS 1 /* Need to enable footers so frees lock the right mspace */
+#ifndef NEDMALLOC_DEBUG
+ #if defined(DEBUG) || defined(_DEBUG)
+ #define NEDMALLOC_DEBUG 1
+ #else
+ #define NEDMALLOC_DEBUG 0
+ #endif
+#endif
+/* We need to consistently define DEBUG=0|1, _DEBUG and NDEBUG for dlmalloc */
+#undef DEBUG
+#undef _DEBUG
+#if NEDMALLOC_DEBUG
+ #define _DEBUG
+ #define DEBUG 1
+#else
+ #define DEBUG 0
+#endif
+#ifdef NDEBUG /* Disable assert checking on release builds */
+ #undef DEBUG
+ #undef _DEBUG
+#endif
+/* The default of 64Kb means we spend too much time kernel-side */
+#ifndef DEFAULT_GRANULARITY
+#define DEFAULT_GRANULARITY (1*1024*1024)
+#if DEBUG
+#define DEFAULT_GRANULARITY_ALIGNED
+#endif
+#endif
+/*#define USE_SPIN_LOCKS 0*/
+
+
+#include "malloc.c.h"
+#ifdef NDEBUG /* Disable assert checking on release builds */
+ #undef DEBUG
+#elif !NEDMALLOC_DEBUG
+ #ifdef __GNUC__
+ #warning DEBUG is defined so allocator will run with assert checking! Define NDEBUG to run at full speed.
+ #elif defined(_MSC_VER)
+ #pragma message(__FILE__ ": WARNING: DEBUG is defined so allocator will run with assert checking! Define NDEBUG to run at full speed.")
+ #endif
+#endif
+
+/* The maximum concurrent threads in a pool possible */
+#ifndef MAXTHREADSINPOOL
+#define MAXTHREADSINPOOL 16
+#endif
+/* The maximum number of threadcaches which can be allocated */
+#ifndef THREADCACHEMAXCACHES
+#define THREADCACHEMAXCACHES 256
+#endif
+/* The maximum size to be allocated from the thread cache */
+#ifndef THREADCACHEMAX
+#define THREADCACHEMAX 8192
+#endif
+#if 0
+/* The number of cache entries for finer grained bins. This is (topbitpos(THREADCACHEMAX)-4)*2 */
+#define THREADCACHEMAXBINS ((13-4)*2)
+#else
+/* The number of cache entries. This is (topbitpos(THREADCACHEMAX)-4) */
+#define THREADCACHEMAXBINS (13-4)
+#endif
+/* Point at which the free space in a thread cache is garbage collected */
+#ifndef THREADCACHEMAXFREESPACE
+#define THREADCACHEMAXFREESPACE (512*1024)
+#endif
+
+
+#ifdef WIN32
+ #define TLSVAR DWORD
+ #define TLSALLOC(k) (*(k)=TlsAlloc(), TLS_OUT_OF_INDEXES==*(k))
+ #define TLSFREE(k) (!TlsFree(k))
+ #define TLSGET(k) TlsGetValue(k)
+ #define TLSSET(k, a) (!TlsSetValue(k, a))
+ #ifdef DEBUG
+static LPVOID ChkedTlsGetValue(DWORD idx)
+{
+ LPVOID ret=TlsGetValue(idx);
+ assert(S_OK==GetLastError());
+ return ret;
+}
+ #undef TLSGET
+ #define TLSGET(k) ChkedTlsGetValue(k)
+ #endif
+#else
+ #define TLSVAR pthread_key_t
+ #define TLSALLOC(k) pthread_key_create(k, 0)
+ #define TLSFREE(k) pthread_key_delete(k)
+ #define TLSGET(k) pthread_getspecific(k)
+ #define TLSSET(k, a) pthread_setspecific(k, a)
+#endif
+
+#if defined(__cplusplus)
+#if !defined(NO_NED_NAMESPACE)
+namespace nedalloc {
+#else
+extern "C" {
+#endif
+#endif
+
+#if USE_ALLOCATOR==0
+static void *unsupported_operation(const char *opname) THROWSPEC
+{
+ fprintf(stderr, "nedmalloc: The operation %s is not supported under this build configuration\n", opname);
+ abort();
+ return 0;
+}
+static size_t mspacecounter=(size_t) 0xdeadbeef;
+#endif
+#ifndef ENABLE_FAST_HEAP_DETECTION
+static void *RESTRICT leastusedaddress;
+static size_t largestusedblock;
+#endif
+
+static FORCEINLINE void *CallMalloc(void *RESTRICT mspace, size_t size, size_t alignment) THROWSPEC
+{
+ void *RESTRICT ret=0;
+ size_t _alignment=alignment;
+#if USE_MAGIC_HEADERS
+ size_t *_ret=0;
+ size+=alignment+3*sizeof(size_t);
+ _alignment=0;
+#endif
+#if USE_ALLOCATOR==0
+ ret=_alignment ?
+#ifdef _MSC_VER
+ /* This is the MSVCRT equivalent */
+ _aligned_malloc(size, _alignment)
+#elif defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)
+ /* This is the glibc/ptmalloc2/dlmalloc/BSD libc equivalent. */
+ memalign(_alignment, size)
+#else
+#error Cannot aligned allocate with the memory allocator of an unknown system!
+#endif
+ : malloc(size);
+#elif USE_ALLOCATOR==1
+ ret=_alignment ? mspace_memalign((mstate) mspace, _alignment, size) : mspace_malloc((mstate) mspace, size);
+#ifndef ENABLE_FAST_HEAP_DETECTION
+ if(ret)
+ {
+ size_t truesize=chunksize(mem2chunk(ret));
+ if(!leastusedaddress || (void *)((mstate) mspace)->least_addr<leastusedaddress) leastusedaddress=(void *)((mstate) mspace)->least_addr;
+ if(!largestusedblock || truesize>largestusedblock) largestusedblock=(truesize+mparams.page_size) & ~(mparams.page_size-1);
+ }
+#endif
+#endif
+ if(!ret) return 0;
+#if USE_MAGIC_HEADERS
+ _ret=(size_t *) ret;
+ ret=(void *)(_ret+3);
+ if(alignment) ret=(void *)(((size_t) ret+alignment-1)&~(alignment-1));
+ for(; _ret<(size_t *)ret-2; _ret++) *_ret=*(size_t *)"NEDMALOC";
+ _ret[0]=(size_t) mspace;
+ _ret[1]=size-3*sizeof(size_t);
+#endif
+ return ret;
+}
+
+static FORCEINLINE void *CallCalloc(void *RESTRICT mspace, size_t size, size_t alignment) THROWSPEC
+{
+ void *RESTRICT ret=0;
+#if USE_MAGIC_HEADERS
+ size_t *_ret=0;
+ size+=alignment+3*sizeof(size_t);
+#endif
+#if USE_ALLOCATOR==0
+ ret=calloc(1, size);
+#elif USE_ALLOCATOR==1
+ ret=mspace_calloc((mstate) mspace, 1, size);
+#ifndef ENABLE_FAST_HEAP_DETECTION
+ if(ret)
+ {
+ size_t truesize=chunksize(mem2chunk(ret));
+ if(!leastusedaddress || (void *)((mstate) mspace)->least_addr<leastusedaddress) leastusedaddress=(void *)((mstate) mspace)->least_addr;
+ if(!largestusedblock || truesize>largestusedblock) largestusedblock=(truesize+mparams.page_size) & ~(mparams.page_size-1);
+ }
+#endif
+#endif
+ if(!ret) return 0;
+#if USE_MAGIC_HEADERS
+ _ret=(size_t *) ret;
+ ret=(void *)(_ret+3);
+ if(alignment) ret=(void *)(((size_t) ret+alignment-1)&~(alignment-1));
+ for(; _ret<(size_t *)ret-2; _ret++) *_ret=*(size_t *) "NEDMALOC";
+ _ret[0]=(size_t) mspace;
+ _ret[1]=size-3*sizeof(size_t);
+#endif
+ return ret;
+}
+
+static FORCEINLINE void *CallRealloc(void *RESTRICT mspace, void *RESTRICT mem, int isforeign, size_t oldsize, size_t newsize) THROWSPEC
+{
+ void *RESTRICT ret=0;
+#if USE_MAGIC_HEADERS
+ mstate oldmspace=0;
+ size_t *_ret=0, *_mem=(size_t *) mem-3;
+#endif
+ if(isforeign)
+ { /* Transfer */
+#if USE_MAGIC_HEADERS
+ assert(_mem[0]!=*(size_t *) "NEDMALOC");
+#endif
+ if((ret=CallMalloc(mspace, newsize, 0)))
+ {
+#if defined(DEBUG)
+ printf("*** nedmalloc frees system allocated block %p\n", mem);
+#endif
+ memcpy(ret, mem, oldsize<newsize ? oldsize : newsize);
+ free(mem);
+ }
+ return ret;
+ }
+#if USE_MAGIC_HEADERS
+ assert(_mem[0]==*(size_t *) "NEDMALOC");
+ newsize+=3*sizeof(size_t);
+ oldmspace=(mstate) _mem[1];
+ assert(oldsize>=_mem[2]);
+ for(; *_mem==*(size_t *) "NEDMALOC"; *_mem--=*(size_t *) "nedmaloc");
+ mem=(void *)(++_mem);
+#endif
+#if USE_ALLOCATOR==0
+ ret=realloc(mem, newsize);
+#elif USE_ALLOCATOR==1
+ ret=mspace_realloc((mstate) mspace, mem, newsize);
+#ifndef ENABLE_FAST_HEAP_DETECTION
+ if(ret)
+ {
+ size_t truesize=chunksize(mem2chunk(ret));
+ if(!largestusedblock || truesize>largestusedblock) largestusedblock=(truesize+mparams.page_size) & ~(mparams.page_size-1);
+ }
+#endif
+#endif
+ if(!ret)
+ { /* Put it back the way it was */
+#if USE_MAGIC_HEADERS
+ for(; *_mem==0; *_mem++=*(size_t *) "NEDMALOC");
+#endif
+ return 0;
+ }
+#if USE_MAGIC_HEADERS
+ _ret=(size_t *) ret;
+ ret=(void *)(_ret+3);
+ for(; _ret<(size_t *)ret-2; _ret++) *_ret=*(size_t *) "NEDMALOC";
+ _ret[0]=(size_t) mspace;
+ _ret[1]=newsize-3*sizeof(size_t);
+#endif
+ return ret;
+}
+
+static FORCEINLINE void CallFree(void *RESTRICT mspace, void *RESTRICT mem, int isforeign) THROWSPEC
+{
+#if USE_MAGIC_HEADERS
+ mstate oldmspace=0;
+ size_t *_mem=(size_t *) mem-3, oldsize=0;
+#endif
+ if(isforeign)
+ {
+#if USE_MAGIC_HEADERS
+ assert(_mem[0]!=*(size_t *) "NEDMALOC");
+#endif
+#if defined(DEBUG)
+ printf("*** nedmalloc frees system allocated block %p\n", mem);
+#endif
+ free(mem);
+ return;
+ }
+#if USE_MAGIC_HEADERS
+ assert(_mem[0]==*(size_t *) "NEDMALOC");
+ oldmspace=(mstate) _mem[1];
+ oldsize=_mem[2];
+ for(; *_mem==*(size_t *) "NEDMALOC"; *_mem--=*(size_t *) "nedmaloc");
+ mem=(void *)(++_mem);
+#endif
+#if USE_ALLOCATOR==0
+ free(mem);
+#elif USE_ALLOCATOR==1
+ mspace_free((mstate) mspace, mem);
+#endif
+}
+
+static NEDMALLOCNOALIASATTR mstate nedblkmstate(void *RESTRICT mem) THROWSPEC
+{
+ if(mem)
+ {
+#if USE_MAGIC_HEADERS
+ size_t *_mem=(size_t *) mem-3;
+ if(_mem[0]==*(size_t *) "NEDMALOC")
+ {
+ return (mstate) _mem[1];
+ }
+ else return 0;
+#else
+#if USE_ALLOCATOR==0
+ /* Fail everything */
+ return 0;
+#elif USE_ALLOCATOR==1
+#ifdef ENABLE_FAST_HEAP_DETECTION
+#ifdef WIN32
+ /* On Windows for RELEASE both x86 and x64 the NT heap precedes each block with an eight byte header
+ which looks like:
+ normal: 4 bytes of size, 4 bytes of [char < 64, char < 64, char < 64 bit 0 always set, char random ]
+ mmaped: 4 bytes of size 4 bytes of [zero, zero, 0xb, zero ]
+
+ On Windows for DEBUG both x86 and x64 the preceding four bytes is always 0xfdfdfdfd (no man's land).
+ */
+#pragma pack(push, 1)
+ struct _HEAP_ENTRY
+ {
+ USHORT Size;
+ USHORT PreviousSize;
+ UCHAR Cookie; /* SegmentIndex */
+ UCHAR Flags; /* always bit 0 (HEAP_ENTRY_BUSY). bit 1=(HEAP_ENTRY_EXTRA_PRESENT), bit 2=normal block (HEAP_ENTRY_FILL_PATTERN), bit 3=mmap block (HEAP_ENTRY_VIRTUAL_ALLOC). Bit 4 (HEAP_ENTRY_LAST_ENTRY) could be set */
+ UCHAR UnusedBytes;
+ UCHAR SmallTagIndex; /* fastbin index. Always one of 0x02, 0x03, 0x04 < 0x80 */
+ } *RESTRICT he=((struct _HEAP_ENTRY *) mem)-1;
+#pragma pack(pop)
+ unsigned int header=((unsigned int *)mem)[-1], mask1=0x8080E100, result1, mask2=0xFFFFFF06, result2;
+ result1=header & mask1; /* Positive testing for NT heap */
+ result2=header & mask2; /* Positive testing for dlmalloc */
+ if(result1==0x00000100 && result2!=0x00000102)
+ { /* This is likely a NT heap block */
+ return 0;
+ }
+#endif
+#ifdef __linux__
+ /* On Linux glibc uses ptmalloc2 (really dlmalloc) just as we do, but prev_foot contains rubbish
+ when the preceding block is allocated because ptmalloc2 finds the local mstate by rounding the ptr
+ down to the nearest megabyte. It's like dlmalloc with FOOTERS disabled. */
+ mchunkptr p=mem2chunk(mem);
+ mstate fm=get_mstate_for(p);
+ /* If it's a ptmalloc2 block, fm is likely to be some crazy value */
+ if(!is_aligned(fm)) return 0;
+ if((size_t)mem-(size_t)fm>=(size_t)1<<(SIZE_T_BITSIZE-1)) return 0;
+ if(ok_magic(fm))
+ return fm;
+ else
+ return 0;
+ if(1) { }
+#endif
+ else
+ {
+ mchunkptr p=mem2chunk(mem);
+ mstate fm=get_mstate_for(p);
+ assert(ok_magic(fm)); /* If this fails, someone tried to free a block twice */
+ if(ok_magic(fm))
+ return fm;
+ }
+#else
+//#ifdef WIN32
+// __try
+//#endif
+ {
+ /* We try to return zero here if it isn't one of our own blocks, however
+ the current block annotation scheme used by dlmalloc makes it impossible
+ to be absolutely sure of avoiding a segfault.
+
+ mchunkptr->prev_foot = mem-(2*size_t) = mstate ^ mparams.magic for PRECEDING block;
+ mchunkptr->head = mem-(1*size_t) = 8 multiple size of this block with bottom three bits = FLAG_BITS
+ FLAG_BITS = bit 0 is CINUSE (currently in use unless is mmap), bit 1 is PINUSE (previous block currently
+ in use unless mmap), bit 2 is UNUSED and currently is always zero.
+ */
+ register void *RESTRICT leastusedaddress_=leastusedaddress; /* Cache these to avoid register reloading */
+ register size_t largestusedblock_=largestusedblock;
+ if(!is_aligned(mem)) return 0; /* Would fail very rarely as all allocators return aligned blocks */
+ if(mem<leastusedaddress_) return 0; /* Simple but effective */
+ {
+ mchunkptr p=mem2chunk(mem);
+ mstate fm=0;
+ int ismmapped=is_mmapped(p);
+ if((!ismmapped && !is_inuse(p)) || (p->head & FLAG4_BIT)) return 0;
+ /* Reduced uncertainty by 0.5^2 = 25.0% */
+ /* size should never exceed largestusedblock */
+ if(chunksize(p)>largestusedblock_) return 0;
+ /* Reduced uncertainty by a minimum of 0.5^3 = 12.5%, maximum 0.5^16 = 0.0015% */
+ /* Having sanity checked prev_foot and head, check next block */
+ if(!ismmapped && (!next_pinuse(p) || (next_chunk(p)->head & FLAG4_BIT))) return 0;
+ /* Reduced uncertainty by 0.5^5 = 3.13% or 0.5^18 = 0.00038% */
+ #if 0
+ /* If previous block is free, check that its next block pointer equals us */
+ if(!ismmapped && !pinuse(p))
+ if(next_chunk(prev_chunk(p))!=p) return 0;
+ /* We could start comparing prev_foot's for similarity but it starts getting slow. */
+ #endif
+ fm = get_mstate_for(p);
+ if(!is_aligned(fm) || (void *)fm<leastusedaddress_) return 0;
+ if((size_t)mem-(size_t)fm>=(size_t)1<<(SIZE_T_BITSIZE-1)) return 0;
+ assert(ok_magic(fm)); /* If this fails, someone tried to free a block twice */
+ if(ok_magic(fm))
+ return fm;
+ }
+ }
+//#ifdef WIN32
+// __except(1) { }
+//#endif
+#endif
+#endif
+#endif
+ }
+ return 0;
+}
+NEDMALLOCNOALIASATTR size_t nedblksize(int *RESTRICT isforeign, void *RESTRICT mem) THROWSPEC
+{
+ if(mem)
+ {
+ if(isforeign) *isforeign=1;
+#if USE_MAGIC_HEADERS
+ {
+ size_t *_mem=(size_t *) mem-3;
+ if(_mem[0]==*(size_t *) "NEDMALOC")
+ {
+ mstate mspace=(mstate) _mem[1];
+ size_t size=_mem[2];
+ if(isforeign) *isforeign=0;
+ return size;
+ }
+ }
+#elif USE_ALLOCATOR==1
+ if(nedblkmstate(mem))
+ {
+ mchunkptr p=mem2chunk(mem);
+ if(isforeign) *isforeign=0;
+ return chunksize(p)-overhead_for(p);
+ }
+#ifdef DEBUG
+ else
+ {
+ int a=1; /* Set breakpoints here if needed */
+ }
+#endif
+#endif
+#if defined(ENABLE_TOLERANT_NEDMALLOC) || USE_ALLOCATOR==0
+#ifdef _MSC_VER
+ /* This is the MSVCRT equivalent */
+ return _msize(mem);
+#elif defined(__linux__)
+ /* This is the glibc/ptmalloc2/dlmalloc equivalent. */
+ return malloc_usable_size(mem);
+#elif defined(__FreeBSD__) || defined(__APPLE__)
+ /* This is the BSD libc equivalent. */
+ return malloc_size(mem);
+#else
+#error Cannot tolerate the memory allocator of an unknown system!
+#endif
+#endif
+ }
+ return 0;
+}
+
+NEDMALLOCNOALIASATTR void nedsetvalue(void *v) THROWSPEC { nedpsetvalue((nedpool *) 0, v); }
+NEDMALLOCNOALIASATTR NEDMALLOCPTRATTR void * nedmalloc(size_t size) THROWSPEC { return nedpmalloc((nedpool *) 0, size); }
+NEDMALLOCNOALIASATTR NEDMALLOCPTRATTR void * nedcalloc(size_t no, size_t size) THROWSPEC { return nedpcalloc((nedpool *) 0, no, size); }
+NEDMALLOCNOALIASATTR NEDMALLOCPTRATTR void * nedrealloc(void *mem, size_t size) THROWSPEC { return nedprealloc((nedpool *) 0, mem, size); }
+NEDMALLOCNOALIASATTR void nedfree(void *mem) THROWSPEC { nedpfree((nedpool *) 0, mem); }
+NEDMALLOCNOALIASATTR NEDMALLOCPTRATTR void * nedmemalign(size_t alignment, size_t bytes) THROWSPEC { return nedpmemalign((nedpool *) 0, alignment, bytes); }
+NEDMALLOCNOALIASATTR struct nedmallinfo nedmallinfo(void) THROWSPEC { return nedpmallinfo((nedpool *) 0); }
+NEDMALLOCNOALIASATTR int nedmallopt(int parno, int value) THROWSPEC { return nedpmallopt((nedpool *) 0, parno, value); }
+NEDMALLOCNOALIASATTR int nedmalloc_trim(size_t pad) THROWSPEC { return nedpmalloc_trim((nedpool *) 0, pad); }
+void nedmalloc_stats() THROWSPEC { nedpmalloc_stats((nedpool *) 0); }
+NEDMALLOCNOALIASATTR size_t nedmalloc_footprint() THROWSPEC { return nedpmalloc_footprint((nedpool *) 0); }
+NEDMALLOCNOALIASATTR NEDMALLOCPTRATTR void **nedindependent_calloc(size_t elemsno, size_t elemsize, void **chunks) THROWSPEC { return nedpindependent_calloc((nedpool *) 0, elemsno, elemsize, chunks); }
+NEDMALLOCNOALIASATTR NEDMALLOCPTRATTR void **nedindependent_comalloc(size_t elems, size_t *sizes, void **chunks) THROWSPEC { return nedpindependent_comalloc((nedpool *) 0, elems, sizes, chunks); }
+
+struct threadcacheblk_t;
+typedef struct threadcacheblk_t threadcacheblk;
+struct threadcacheblk_t
+{ /* Keep less than 16 bytes on 32 bit systems and 32 bytes on 64 bit systems */
+#ifdef FULLSANITYCHECKS
+ unsigned int magic;
+#endif
+ unsigned int lastUsed, size;
+ threadcacheblk *next, *prev;
+};
+typedef struct threadcache_t
+{
+#ifdef FULLSANITYCHECKS
+ unsigned int magic1;
+#endif
+ int mymspace; /* Last mspace entry this thread used */
+ long threadid;
+ unsigned int mallocs, frees, successes;
+ size_t freeInCache; /* How much free space is stored in this cache */
+ threadcacheblk *bins[(THREADCACHEMAXBINS+1)*2];
+#ifdef FULLSANITYCHECKS
+ unsigned int magic2;
+#endif
+} threadcache;
+struct nedpool_t
+{
+ MLOCK_T mutex;
+ void *uservalue;
+ int threads; /* Max entries in m to use */
+ threadcache *caches[THREADCACHEMAXCACHES];
+ TLSVAR mycache; /* Thread cache for this thread. 0 for unset, negative for use mspace-1 directly, otherwise is cache-1 */
+ mstate m[MAXTHREADSINPOOL+1]; /* mspace entries for this pool */
+};
+static nedpool syspool;
+
+static FORCEINLINE NEDMALLOCNOALIASATTR unsigned int size2binidx(size_t _size) THROWSPEC
+{ /* 8=1000 16=10000 20=10100 24=11000 32=100000 48=110000 4096=1000000000000 */
+ unsigned int topbit, size=(unsigned int)(_size>>4);
+ /* 16=1 20=1 24=1 32=10 48=11 64=100 96=110 128=1000 4096=100000000 */
+
+#if defined(__GNUC__)
+ topbit = sizeof(size)*__CHAR_BIT__ - 1 - __builtin_clz(size);
+#elif defined(_MSC_VER) && _MSC_VER>=1300
+ {
+ unsigned long bsrTopBit;
+
+ _BitScanReverse(&bsrTopBit, size);
+
+ topbit = bsrTopBit;
+ }
+#else
+#if 0
+ union {
+ unsigned asInt[2];
+ double asDouble;
+ };
+ int n;
+
+ asDouble = (double)size + 0.5;
+ topbit = (asInt[!FOX_BIGENDIAN] >> 20) - 1023;
+#else
+ {
+ unsigned int x=size;
+ x = x | (x >> 1);
+ x = x | (x >> 2);
+ x = x | (x >> 4);
+ x = x | (x >> 8);
+ x = x | (x >>16);
+ x = ~x;
+ x = x - ((x >> 1) & 0x55555555);
+ x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
+ x = (x + (x >> 4)) & 0x0F0F0F0F;
+ x = x + (x << 8);
+ x = x + (x << 16);
+ topbit=31 - (x >> 24);
+ }
+#endif
+#endif
+ return topbit;
+}
+
+
+#ifdef FULLSANITYCHECKS
+static void tcsanitycheck(threadcacheblk **ptr) THROWSPEC
+{
+ assert((ptr[0] && ptr[1]) || (!ptr[0] && !ptr[1]));
+ if(ptr[0] && ptr[1])
+ {
+ assert(nedblksize(ptr[0])>=sizeof(threadcacheblk));
+ assert(nedblksize(ptr[1])>=sizeof(threadcacheblk));
+ assert(*(unsigned int *) "NEDN"==ptr[0]->magic);
+ assert(*(unsigned int *) "NEDN"==ptr[1]->magic);
+ assert(!ptr[0]->prev);
+ assert(!ptr[1]->next);
+ if(ptr[0]==ptr[1])
+ {
+ assert(!ptr[0]->next);
+ assert(!ptr[1]->prev);
+ }
+ }
+}
+static void tcfullsanitycheck(threadcache *tc) THROWSPEC
+{
+ threadcacheblk **tcbptr=tc->bins;
+ int n;
+ for(n=0; n<=THREADCACHEMAXBINS; n++, tcbptr+=2)
+ {
+ threadcacheblk *b, *ob=0;
+ tcsanitycheck(tcbptr);
+ for(b=tcbptr[0]; b; ob=b, b=b->next)
+ {
+ assert(*(unsigned int *) "NEDN"==b->magic);
+ assert(!ob || ob->next==b);
+ assert(!ob || b->prev==ob);
+ }
+ }
+}
+#endif
+
+static NOINLINE void RemoveCacheEntries(nedpool *RESTRICT p, threadcache *RESTRICT tc, unsigned int age) THROWSPEC
+{
+#ifdef FULLSANITYCHECKS
+ tcfullsanitycheck(tc);
+#endif
+ if(tc->freeInCache)
+ {
+ threadcacheblk **tcbptr=tc->bins;
+ int n;
+ for(n=0; n<=THREADCACHEMAXBINS; n++, tcbptr+=2)
+ {
+ threadcacheblk **tcb=tcbptr+1; /* come from oldest end of list */
+ /*tcsanitycheck(tcbptr);*/
+ for(; *tcb && tc->frees-(*tcb)->lastUsed>=age; )
+ {
+ threadcacheblk *f=*tcb;
+ size_t blksize=f->size; /*nedblksize(f);*/
+ assert(blksize<=nedblksize(0, f));
+ assert(blksize);
+#ifdef FULLSANITYCHECKS
+ assert(*(unsigned int *) "NEDN"==(*tcb)->magic);
+#endif
+ *tcb=(*tcb)->prev;
+ if(*tcb)
+ (*tcb)->next=0;
+ else
+ *tcbptr=0;
+ tc->freeInCache-=blksize;
+ assert((long) tc->freeInCache>=0);
+ CallFree(0, f, 0);
+ /*tcsanitycheck(tcbptr);*/
+ }
+ }
+ }
+#ifdef FULLSANITYCHECKS
+ tcfullsanitycheck(tc);
+#endif
+}
+static void DestroyCaches(nedpool *RESTRICT p) THROWSPEC
+{
+ if(p->caches)
+ {
+ threadcache *tc;
+ int n;
+ for(n=0; n<THREADCACHEMAXCACHES; n++)
+ {
+ if((tc=p->caches[n]))
+ {
+ tc->frees++;
+ RemoveCacheEntries(p, tc, 0);
+ assert(!tc->freeInCache);
+ tc->mymspace=-1;
+ tc->threadid=0;
+ CallFree(0, tc, 0);
+ p->caches[n]=0;
+ }
+ }
+ }
+}
+
+static NOINLINE threadcache *AllocCache(nedpool *RESTRICT p) THROWSPEC
+{
+ threadcache *tc=0;
+ int n, end;
+ ACQUIRE_LOCK(&p->mutex);
+ for(n=0; n<THREADCACHEMAXCACHES && p->caches[n]; n++);
+ if(THREADCACHEMAXCACHES==n)
+ { /* List exhausted, so disable for this thread */
+ RELEASE_LOCK(&p->mutex);
+ return 0;
+ }
+ tc=p->caches[n]=(threadcache *) CallCalloc(p->m[0], sizeof(threadcache), 0);
+ if(!tc)
+ {
+ RELEASE_LOCK(&p->mutex);
+ return 0;
+ }
+#ifdef FULLSANITYCHECKS
+ tc->magic1=*(unsigned int *)"NEDMALC1";
+ tc->magic2=*(unsigned int *)"NEDMALC2";
+#endif
+ tc->threadid=(long)(size_t)CURRENT_THREAD;
+ for(end=0; p->m[end]; end++);
+ tc->mymspace=abs(tc->threadid) % end;
+ RELEASE_LOCK(&p->mutex);
+ if(TLSSET(p->mycache, (void *)(size_t)(n+1))) abort();
+ return tc;
+}
+
+static void *threadcache_malloc(nedpool *RESTRICT p, threadcache *RESTRICT tc, size_t *RESTRICT _size) THROWSPEC
+{
+ void *RESTRICT ret=0;
+ size_t size=*_size, blksize=0;
+ unsigned int bestsize;
+ unsigned int idx=size2binidx(size);
+ threadcacheblk *RESTRICT blk, **RESTRICT binsptr;
+#ifdef FULLSANITYCHECKS
+ tcfullsanitycheck(tc);
+#endif
+ /* Calculate best fit bin size */
+ bestsize=1<<(idx+4);
+#if 0
+ /* Finer grained bin fit */
+ idx<<=1;
+ if(size>bestsize)
+ {
+ idx++;
+ bestsize+=bestsize>>1;
+ }
+ if(size>bestsize)
+ {
+ idx++;
+ bestsize=1<<(4+(idx>>1));
+ }
+#else
+ if(size>bestsize)
+ {
+ idx++;
+ bestsize<<=1;
+ }
+#endif
+ assert(bestsize>=size);
+ if(size<bestsize) size=bestsize;
+ assert(size<=THREADCACHEMAX);
+ assert(idx<=THREADCACHEMAXBINS);
+ binsptr=&tc->bins[idx*2];
+ /* Try to match close, but move up a bin if necessary */
+ blk=*binsptr;
+ if(!blk || blk->size<size)
+ { /* Bump it up a bin */
+ if(idx<THREADCACHEMAXBINS)
+ {
+ idx++;
+ binsptr+=2;
+ blk=*binsptr;
+ }
+ }
+ if(blk)
+ {
+ blksize=blk->size; /*nedblksize(blk);*/
+ assert(nedblksize(0, blk)>=blksize);
+ assert(blksize>=size);
+ if(blk->next)
+ blk->next->prev=0;
+ *binsptr=blk->next;
+ if(!*binsptr)
+ binsptr[1]=0;
+#ifdef FULLSANITYCHECKS
+ blk->magic=0;
+#endif
+ assert(binsptr[0]!=blk && binsptr[1]!=blk);
+ assert(nedblksize(0, blk)>=sizeof(threadcacheblk) && nedblksize(0, blk)<=THREADCACHEMAX+CHUNK_OVERHEAD);
+ /*printf("malloc: %p, %p, %p, %lu\n", p, tc, blk, (long) _size);*/
+ ret=(void *) blk;
+ }
+ ++tc->mallocs;
+ if(ret)
+ {
+ assert(blksize>=size);
+ ++tc->successes;
+ tc->freeInCache-=blksize;
+ assert((long) tc->freeInCache>=0);
+ }
+#if defined(DEBUG) && 0
+ if(!(tc->mallocs & 0xfff))
+ {
+ printf("*** threadcache=%u, mallocs=%u (%f), free=%u (%f), freeInCache=%u\n", (unsigned int) tc->threadid, tc->mallocs,
+ (float) tc->successes/tc->mallocs, tc->frees, (float) tc->successes/tc->frees, (unsigned int) tc->freeInCache);
+ }
+#endif
+#ifdef FULLSANITYCHECKS
+ tcfullsanitycheck(tc);
+#endif
+ *_size=size;
+ return ret;
+}
+static NOINLINE void ReleaseFreeInCache(nedpool *RESTRICT p, threadcache *RESTRICT tc, int mymspace) THROWSPEC
+{
+ unsigned int age=THREADCACHEMAXFREESPACE/8192;
+ /*ACQUIRE_LOCK(&p->m[mymspace]->mutex);*/
+ while(age && tc->freeInCache>=THREADCACHEMAXFREESPACE)
+ {
+ RemoveCacheEntries(p, tc, age);
+ /*printf("*** Removing cache entries older than %u (%u)\n", age, (unsigned int) tc->freeInCache);*/
+ age>>=1;
+ }
+ /*RELEASE_LOCK(&p->m[mymspace]->mutex);*/
+}
+static void threadcache_free(nedpool *RESTRICT p, threadcache *RESTRICT tc, int mymspace, void *RESTRICT mem, size_t size) THROWSPEC
+{
+ unsigned int bestsize;
+ unsigned int idx=size2binidx(size);
+ threadcacheblk **RESTRICT binsptr, *RESTRICT tck=(threadcacheblk *) mem;
+ assert(size>=sizeof(threadcacheblk) && size<=THREADCACHEMAX+CHUNK_OVERHEAD);
+#ifdef DEBUG
+ /* Make sure this is a valid memory block */
+ assert(nedblksize(0, mem));
+#endif
+#ifdef FULLSANITYCHECKS
+ tcfullsanitycheck(tc);
+#endif
+ /* Calculate best fit bin size */
+ bestsize=1<<(idx+4);
+#if 0
+ /* Finer grained bin fit */
+ idx<<=1;
+ if(size>bestsize)
+ {
+ unsigned int biggerbestsize=bestsize+bestsize<<1;
+ if(size>=biggerbestsize)
+ {
+ idx++;
+ bestsize=biggerbestsize;
+ }
+ }
+#endif
+ if(bestsize!=size) /* dlmalloc can round up, so we round down to preserve indexing */
+ size=bestsize;
+ binsptr=&tc->bins[idx*2];
+ assert(idx<=THREADCACHEMAXBINS);
+ if(tck==*binsptr)
+ {
+ fprintf(stderr, "nedmalloc: Attempt to free already freed memory block %p - aborting!\n", tck);
+ abort();
+ }
+#ifdef FULLSANITYCHECKS
+ tck->magic=*(unsigned int *) "NEDN";
+#endif
+ tck->lastUsed=++tc->frees;
+ tck->size=(unsigned int) size;
+ tck->next=*binsptr;
+ tck->prev=0;
+ if(tck->next)
+ tck->next->prev=tck;
+ else
+ binsptr[1]=tck;
+ assert(!*binsptr || (*binsptr)->size==tck->size);
+ *binsptr=tck;
+ assert(tck==tc->bins[idx*2]);
+ assert(tc->bins[idx*2+1]==tck || binsptr[0]->next->prev==tck);
+ /*printf("free: %p, %p, %p, %lu\n", p, tc, mem, (long) size);*/
+ tc->freeInCache+=size;
+#ifdef FULLSANITYCHECKS
+ tcfullsanitycheck(tc);
+#endif
+#if 1
+ if(tc->freeInCache>=THREADCACHEMAXFREESPACE)
+ ReleaseFreeInCache(p, tc, mymspace);
+#endif
+}
+
+
+
+
+static NOINLINE int InitPool(nedpool *RESTRICT p, size_t capacity, int threads) THROWSPEC
+{ /* threads is -1 for system pool */
+ ensure_initialization();
+ ACQUIRE_MALLOC_GLOBAL_LOCK();
+ if(p->threads) goto done;
+ if(INITIAL_LOCK(&p->mutex)) goto err;
+ if(TLSALLOC(&p->mycache)) goto err;
+#if USE_ALLOCATOR==0
+ p->m[0]=(mstate) mspacecounter++;
+#elif USE_ALLOCATOR==1
+ if(!(p->m[0]=(mstate) create_mspace(capacity, 1))) goto err;
+ p->m[0]->extp=p;
+#endif
+ p->threads=(threads<1 || threads>MAXTHREADSINPOOL) ? MAXTHREADSINPOOL : threads;
+done:
+ RELEASE_MALLOC_GLOBAL_LOCK();
+ return 1;
+err:
+ if(threads<0)
+ abort(); /* If you can't allocate for system pool, we're screwed */
+ DestroyCaches(p);
+ if(p->m[0])
+ {
+#if USE_ALLOCATOR==1
+ destroy_mspace(p->m[0]);
+#endif
+ p->m[0]=0;
+ }
+ if(p->mycache)
+ {
+ if(TLSFREE(p->mycache)) abort();
+ p->mycache=0;
+ }
+ RELEASE_MALLOC_GLOBAL_LOCK();
+ return 0;
+}
+static NOINLINE mstate FindMSpace(nedpool *RESTRICT p, threadcache *RESTRICT tc, int *RESTRICT lastUsed, size_t size) THROWSPEC
+{ /* Gets called when thread's last used mspace is in use. The strategy
+ is to run through the list of all available mspaces looking for an
+ unlocked one and if we fail, we create a new one so long as we don't
+ exceed p->threads */
+ int n, end;
+ for(n=end=*lastUsed+1; p->m[n]; end=++n)
+ {
+ if(TRY_LOCK(&p->m[n]->mutex)) goto found;
+ }
+ for(n=0; n<*lastUsed && p->m[n]; n++)
+ {
+ if(TRY_LOCK(&p->m[n]->mutex)) goto found;
+ }
+ if(end<p->threads)
+ {
+ mstate temp;
+#if USE_ALLOCATOR==0
+ temp=(mstate) mspacecounter++;
+#elif USE_ALLOCATOR==1
+ if(!(temp=(mstate) create_mspace(size, 1)))
+ goto badexit;
+#endif
+ /* Now we're ready to modify the lists, we lock */
+ ACQUIRE_LOCK(&p->mutex);
+ while(p->m[end] && end<p->threads)
+ end++;
+ if(end>=p->threads)
+ { /* Drat, must destroy it now */
+ RELEASE_LOCK(&p->mutex);
+#if USE_ALLOCATOR==1
+ destroy_mspace((mstate) temp);
+#endif
+ goto badexit;
+ }
+ /* We really want to make sure this goes into memory now but we
+ have to be careful of breaking aliasing rules, so write it twice */
+ *((volatile struct malloc_state **) &p->m[end])=p->m[end]=temp;
+ ACQUIRE_LOCK(&p->m[end]->mutex);
+ /*printf("Created mspace idx %d\n", end);*/
+ RELEASE_LOCK(&p->mutex);
+ n=end;
+ goto found;
+ }
+ /* Let it lock on the last one it used */
+badexit:
+ ACQUIRE_LOCK(&p->m[*lastUsed]->mutex);
+ return p->m[*lastUsed];
+found:
+ *lastUsed=n;
+ if(tc)
+ tc->mymspace=n;
+ else
+ {
+ if(TLSSET(p->mycache, (void *)(size_t)(-(n+1)))) abort();
+ }
+ return p->m[n];
+}
+
+typedef struct PoolList_t
+{
+ size_t size; /* Size of list */
+ size_t length; /* Actual entries in list */
+#ifdef DEBUG
+ nedpool *list[1]; /* Force testing of list expansion */
+#else
+ nedpool *list[16];
+#endif
+} PoolList;
+static MLOCK_T poollistlock;
+static PoolList *poollist;
+NEDMALLOCPTRATTR nedpool *nedcreatepool(size_t capacity, int threads) THROWSPEC
+{
+ nedpool *ret=0;
+ if(!poollist)
+ {
+ PoolList *newpoollist=0;
+ if(!(newpoollist=(PoolList *) nedpcalloc(0, 1, sizeof(PoolList)+sizeof(nedpool *)))) return 0;
+ INITIAL_LOCK(&poollistlock);
+ ACQUIRE_LOCK(&poollistlock);
+ poollist=newpoollist;
+ poollist->size=sizeof(poollist->list)/sizeof(nedpool *);
+ }
+ else
+ ACQUIRE_LOCK(&poollistlock);
+ if(poollist->length==poollist->size)
+ {
+ PoolList *newpoollist=0;
+ size_t newsize=0;
+ newsize=sizeof(PoolList)+(poollist->size+1)*sizeof(nedpool *);
+ if(!(newpoollist=(PoolList *) nedprealloc(0, poollist, newsize))) goto badexit;
+ poollist=newpoollist;
+ memset(&poollist->list[poollist->size], 0, newsize-((size_t)&poollist->list[poollist->size]-(size_t)&poollist->list[0]));
+ poollist->size=((newsize-((char *)&poollist->list[0]-(char *)poollist))/sizeof(nedpool *))-1;
+ assert(poollist->size>poollist->length);
+ }
+ if(!(ret=(nedpool *) nedpcalloc(0, 1, sizeof(nedpool)))) goto badexit;
+ if(!InitPool(ret, capacity, threads))
+ {
+ nedpfree(0, ret);
+ goto badexit;
+ }
+ poollist->list[poollist->length++]=ret;
+badexit:
+ RELEASE_LOCK(&poollistlock);
+ return ret;
+}
+void neddestroypool(nedpool *p) THROWSPEC
+{
+ unsigned int n;
+ ACQUIRE_LOCK(&p->mutex);
+ DestroyCaches(p);
+ for(n=0; p->m[n]; n++)
+ {
+#if USE_ALLOCATOR==1
+ destroy_mspace(p->m[n]);
+#endif
+ p->m[n]=0;
+ }
+ RELEASE_LOCK(&p->mutex);
+ if(TLSFREE(p->mycache)) abort();
+ nedpfree(0, p);
+ ACQUIRE_LOCK(&poollistlock);
+ assert(poollist);
+ for(n=0; n<poollist->length && poollist->list[n]!=p; n++);
+ assert(n!=poollist->length);
+ memmove(&poollist->list[n], &poollist->list[n+1], (size_t)&poollist->list[poollist->length]-(size_t)&poollist->list[n]);
+ if(!--poollist->length)
+ {
+ assert(!poollist->list[0]);
+ nedpfree(0, poollist);
+ poollist=0;
+ }
+ RELEASE_LOCK(&poollistlock);
+}
+void neddestroysyspool() THROWSPEC
+{
+ nedpool *p=&syspool;
+ int n;
+ ACQUIRE_LOCK(&p->mutex);
+ DestroyCaches(p);
+ for(n=0; p->m[n]; n++)
+ {
+#if USE_ALLOCATOR==1
+ destroy_mspace(p->m[n]);
+#endif
+ p->m[n]=0;
+ }
+ /* Render syspool unusable */
+ for(n=0; n<THREADCACHEMAXCACHES; n++)
+ p->caches[n]=(threadcache *)(size_t)(sizeof(size_t)>4 ? 0xdeadbeefdeadbeefULL : 0xdeadbeefUL);
+ for(n=0; n<MAXTHREADSINPOOL+1; n++)
+ p->m[n]=(mstate)(size_t)(sizeof(size_t)>4 ? 0xdeadbeefdeadbeefULL : 0xdeadbeefUL);
+ if(TLSFREE(p->mycache)) abort();
+ RELEASE_LOCK(&p->mutex);
+}
+nedpool **nedpoollist() THROWSPEC
+{
+ nedpool **ret=0;
+ if(poollist)
+ {
+ ACQUIRE_LOCK(&poollistlock);
+ if(!(ret=(nedpool **) nedmalloc((poollist->length+1)*sizeof(nedpool *)))) goto badexit;
+ memcpy(ret, poollist->list, (poollist->length+1)*sizeof(nedpool *));
+badexit:
+ RELEASE_LOCK(&poollistlock);
+ }
+ return ret;
+}
+
+void nedpsetvalue(nedpool *p, void *v) THROWSPEC
+{
+ if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
+ p->uservalue=v;
+}
+void *nedgetvalue(nedpool **p, void *mem) THROWSPEC
+{
+ nedpool *np=0;
+ mstate fm=nedblkmstate(mem);
+ if(!fm || !fm->extp) return 0;
+ np=(nedpool *) fm->extp;
+ if(p) *p=np;
+ return np->uservalue;
+}
+
+void nedtrimthreadcache(nedpool *p, int disable) THROWSPEC
+{
+ int mycache;
+ if(!p)
+ {
+ p=&syspool;
+ if(!syspool.threads) InitPool(&syspool, 0, -1);
+ }
+ mycache=(int)(size_t) TLSGET(p->mycache);
+ if(!mycache)
+ { /* Set to mspace 0 */
+ if(disable && TLSSET(p->mycache, (void *)(size_t)-1)) abort();
+ }
+ else if(mycache>0)
+ { /* Set to last used mspace */
+ threadcache *tc=p->caches[mycache-1];
+#if defined(DEBUG)
+ printf("Threadcache utilisation: %lf%% in cache with %lf%% lost to other threads\n",
+ 100.0*tc->successes/tc->mallocs, 100.0*((double) tc->mallocs-tc->frees)/tc->mallocs);
+#endif
+ if(disable && TLSSET(p->mycache, (void *)(size_t)(-tc->mymspace))) abort();
+ tc->frees++;
+ RemoveCacheEntries(p, tc, 0);
+ assert(!tc->freeInCache);
+ if(disable)
+ {
+ tc->mymspace=-1;
+ tc->threadid=0;
+ CallFree(0, p->caches[mycache-1], 0);
+ p->caches[mycache-1]=0;
+ }
+ }
+}
+void neddisablethreadcache(nedpool *p) THROWSPEC
+{
+ nedtrimthreadcache(p, 1);
+}
+
+#define GETMSPACE(m,p,tc,ms,s,action) \
+ do \
+ { \
+ mstate m = GetMSpace((p),(tc),(ms),(s)); \
+ action; \
+ if(USE_ALLOCATOR==1) { RELEASE_LOCK(&m->mutex); } \
+ } while (0)
+
+static FORCEINLINE mstate GetMSpace(nedpool *RESTRICT p, threadcache *RESTRICT tc, int mymspace, size_t size) THROWSPEC
+{ /* Returns a locked and ready for use mspace */
+ mstate m=p->m[mymspace];
+ assert(m);
+#if USE_ALLOCATOR==1
+ if(!TRY_LOCK(&p->m[mymspace]->mutex)) m=FindMSpace(p, tc, &mymspace, size);
+ /*assert(IS_LOCKED(&p->m[mymspace]->mutex));*/
+#endif
+ return m;
+}
+static NOINLINE void GetThreadCache_cold1(nedpool *RESTRICT *RESTRICT p) THROWSPEC
+{
+ *p=&syspool;
+ if(!syspool.threads) InitPool(&syspool, 0, -1);
+}
+static NOINLINE void GetThreadCache_cold2(nedpool *RESTRICT *RESTRICT p, threadcache *RESTRICT *RESTRICT tc, int *RESTRICT mymspace, int mycache) THROWSPEC
+{
+ if(!mycache)
+ { /* Need to allocate a new cache */
+ *tc=AllocCache(*p);
+ if(!*tc)
+ { /* Disable */
+ if(TLSSET((*p)->mycache, (void *)(size_t)-1)) abort();
+ *mymspace=0;
+ }
+ else
+ *mymspace=(*tc)->mymspace;
+ }
+ else
+ { /* Cache disabled, but we do have an assigned thread pool */
+ *tc=0;
+ *mymspace=-mycache-1;
+ }
+}
+static FORCEINLINE void GetThreadCache(nedpool *RESTRICT *RESTRICT p, threadcache *RESTRICT *RESTRICT tc, int *RESTRICT mymspace, size_t *RESTRICT size) THROWSPEC
+{
+ int mycache;
+ if(size && *size<sizeof(threadcacheblk)) *size=sizeof(threadcacheblk);
+ if(!*p)
+ GetThreadCache_cold1(p);
+ mycache=(int)(size_t) TLSGET((*p)->mycache);
+ if(mycache>0)
+ { /* Already have a cache */
+ *tc=(*p)->caches[mycache-1];
+ *mymspace=(*tc)->mymspace;
+ }
+ else GetThreadCache_cold2(p, tc, mymspace, mycache);
+ assert(*mymspace>=0);
+ assert(!(*tc) || (long)(size_t)CURRENT_THREAD==(*tc)->threadid);
+#ifdef FULLSANITYCHECKS
+ if(*tc)
+ {
+ if(*(unsigned int *)"NEDMALC1"!=(*tc)->magic1 || *(unsigned int *)"NEDMALC2"!=(*tc)->magic2)
+ {
+ abort();
+ }
+ }
+#endif
+}
+
+NEDMALLOCPTRATTR void * nedpmalloc(nedpool *p, size_t size) THROWSPEC
+{
+ void *ret=0;
+ threadcache *tc;
+ int mymspace;
+ GetThreadCache(&p, &tc, &mymspace, &size);
+#if THREADCACHEMAX
+ if(tc && size<=THREADCACHEMAX)
+ { /* Use the thread cache */
+ ret=threadcache_malloc(p, tc, &size);
+ }
+#endif
+ if(!ret)
+ { /* Use this thread's mspace */
+ GETMSPACE(m, p, tc, mymspace, size,
+ ret=CallMalloc(m, size, 0));
+ }
+ return ret;
+}
+NEDMALLOCPTRATTR void * nedpcalloc(nedpool *p, size_t no, size_t size) THROWSPEC
+{
+ size_t rsize=size*no;
+ void *ret=0;
+ threadcache *tc;
+ int mymspace;
+ GetThreadCache(&p, &tc, &mymspace, &rsize);
+#if THREADCACHEMAX
+ if(tc && rsize<=THREADCACHEMAX)
+ { /* Use the thread cache */
+ if((ret=threadcache_malloc(p, tc, &rsize)))
+ memset(ret, 0, rsize);
+ }
+#endif
+ if(!ret)
+ { /* Use this thread's mspace */
+ GETMSPACE(m, p, tc, mymspace, rsize,
+ ret=CallCalloc(m, rsize, 0));
+ }
+ return ret;
+}
+NEDMALLOCPTRATTR void * nedprealloc(nedpool *p, void *mem, size_t size) THROWSPEC
+{
+ void *ret=0;
+ threadcache *tc;
+ int mymspace, isforeign=1;
+ size_t memsize;
+ if(!mem) return nedpmalloc(p, size);
+ memsize=nedblksize(&isforeign, mem);
+ assert(memsize);
+ if(!memsize)
+ {
+ fprintf(stderr, "nedmalloc: nedprealloc() called with a block not created by nedmalloc!\n");
+ abort();
+ }
+ else if(size<=memsize && memsize-size<
+#ifdef DEBUG
+ 32
+#else
+ 1024
+#endif
+ ) /* If realloc size is within 1Kb smaller than existing, noop it */
+ return mem;
+ GetThreadCache(&p, &tc, &mymspace, &size);
+#if THREADCACHEMAX
+ if(tc && size && size<=THREADCACHEMAX)
+ { /* Use the thread cache */
+ if((ret=threadcache_malloc(p, tc, &size)))
+ {
+ memcpy(ret, mem, memsize<size ? memsize : size);
+ if(memsize>=sizeof(threadcacheblk) && memsize<=(THREADCACHEMAX+CHUNK_OVERHEAD))
+ threadcache_free(p, tc, mymspace, mem, memsize);
+ else
+ CallFree(0, mem, isforeign);
+ }
+ }
+#endif
+ if(!ret)
+ { /* Reallocs always happen in the mspace they happened in, so skip
+ locking the preferred mspace for this thread */
+ ret=CallRealloc(p->m[mymspace], mem, isforeign, memsize, size);
+ }
+ return ret;
+}
+void nedpfree(nedpool *p, void *mem) THROWSPEC
+{ /* Frees always happen in the mspace they happened in, so skip
+ locking the preferred mspace for this thread */
+ threadcache *tc;
+ int mymspace, isforeign=1;
+ size_t memsize;
+ if(!mem)
+ { /* If you tried this on FreeBSD you'd be sorry! */
+#ifdef DEBUG
+ fprintf(stderr, "nedmalloc: WARNING nedpfree() called with zero. This is not portable behaviour!\n");
+#endif
+ return;
+ }
+ memsize=nedblksize(&isforeign, mem);
+ assert(memsize);
+ if(!memsize)
+ {
+ fprintf(stderr, "nedmalloc: nedpfree() called with a block not created by nedmalloc!\n");
+ abort();
+ }
+ GetThreadCache(&p, &tc, &mymspace, 0);
+#if THREADCACHEMAX
+ if(mem && tc && memsize>=sizeof(threadcacheblk) && memsize<=(THREADCACHEMAX+CHUNK_OVERHEAD))
+ threadcache_free(p, tc, mymspace, mem, memsize);
+ else
+#endif
+ CallFree(0, mem, isforeign);
+}
+NEDMALLOCPTRATTR void * nedpmemalign(nedpool *p, size_t alignment, size_t bytes) THROWSPEC
+{
+ void *ret;
+ threadcache *tc;
+ int mymspace;
+ GetThreadCache(&p, &tc, &mymspace, &bytes);
+ { /* Use this thread's mspace */
+ GETMSPACE(m, p, tc, mymspace, bytes,
+ ret=CallMalloc(m, bytes, alignment));
+ }
+ return ret;
+}
+struct nedmallinfo nedpmallinfo(nedpool *p) THROWSPEC
+{
+ int n;
+ struct nedmallinfo ret={0};
+ if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
+ for(n=0; p->m[n]; n++)
+ {
+#if USE_ALLOCATOR==1 && !NO_MALLINFO
+ struct mallinfo t=mspace_mallinfo(p->m[n]);
+ ret.arena+=t.arena;
+ ret.ordblks+=t.ordblks;
+ ret.hblkhd+=t.hblkhd;
+ ret.usmblks+=t.usmblks;
+ ret.uordblks+=t.uordblks;
+ ret.fordblks+=t.fordblks;
+ ret.keepcost+=t.keepcost;
+#endif
+ }
+ return ret;
+}
+int nedpmallopt(nedpool *p, int parno, int value) THROWSPEC
+{
+#if USE_ALLOCATOR==1
+ return mspace_mallopt(parno, value);
+#else
+ return 0;
+#endif
+}
+NEDMALLOCNOALIASATTR void* nedmalloc_internals(size_t *granularity, size_t *magic) THROWSPEC
+{
+#if USE_ALLOCATOR==1
+ if(granularity) *granularity=mparams.granularity;
+ if(magic) *magic=mparams.magic;
+ return (void *) &syspool;
+#else
+ if(granularity) *granularity=0;
+ if(magic) *magic=0;
+ return 0;
+#endif
+}
+int nedpmalloc_trim(nedpool *p, size_t pad) THROWSPEC
+{
+ int n, ret=0;
+ if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
+ for(n=0; p->m[n]; n++)
+ {
+#if USE_ALLOCATOR==1
+ ret+=mspace_trim(p->m[n], pad);
+#endif
+ }
+ return ret;
+}
+void nedpmalloc_stats(nedpool *p) THROWSPEC
+{
+ int n;
+ if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
+ for(n=0; p->m[n]; n++)
+ {
+#if USE_ALLOCATOR==1
+ mspace_malloc_stats(p->m[n]);
+#endif
+ }
+}
+size_t nedpmalloc_footprint(nedpool *p) THROWSPEC
+{
+ size_t ret=0;
+ int n;
+ if(!p) { p=&syspool; if(!syspool.threads) InitPool(&syspool, 0, -1); }
+ for(n=0; p->m[n]; n++)
+ {
+#if USE_ALLOCATOR==1
+ ret+=mspace_footprint(p->m[n]);
+#endif
+ }
+ return ret;
+}
+NEDMALLOCPTRATTR void **nedpindependent_calloc(nedpool *p, size_t elemsno, size_t elemsize, void **chunks) THROWSPEC
+{
+ void **ret;
+ threadcache *tc;
+ int mymspace;
+ GetThreadCache(&p, &tc, &mymspace, &elemsize);
+#if USE_ALLOCATOR==0
+ GETMSPACE(m, p, tc, mymspace, elemsno*elemsize,
+ ret=unsupported_operation("independent_calloc"));
+#elif USE_ALLOCATOR==1
+ GETMSPACE(m, p, tc, mymspace, elemsno*elemsize,
+ ret=mspace_independent_calloc(m, elemsno, elemsize, chunks));
+#endif
+ return ret;
+}
+NEDMALLOCPTRATTR void **nedpindependent_comalloc(nedpool *p, size_t elems, size_t *sizes, void **chunks) THROWSPEC
+{
+ void **ret;
+ threadcache *tc;
+ int mymspace;
+ size_t i, *adjustedsizes=(size_t *) alloca(elems*sizeof(size_t));
+ if(!adjustedsizes) return 0;
+ for(i=0; i<elems; i++)
+ adjustedsizes[i]=sizes[i]<sizeof(threadcacheblk) ? sizeof(threadcacheblk) : sizes[i];
+ GetThreadCache(&p, &tc, &mymspace, 0);
+#if USE_ALLOCATOR==0
+ GETMSPACE(m, p, tc, mymspace, 0,
+ ret=unsupported_operation("independent_comalloc"));
+#elif USE_ALLOCATOR==1
+ GETMSPACE(m, p, tc, mymspace, 0,
+ ret=mspace_independent_comalloc(m, elems, adjustedsizes, chunks));
+#endif
+ return ret;
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#endif
diff --git a/drivers/nedmalloc/nedmalloc.h b/drivers/nedmalloc/nedmalloc.h
index b9add1683a..7ec65849fc 100644
--- a/drivers/nedmalloc/nedmalloc.h
+++ b/drivers/nedmalloc/nedmalloc.h
@@ -1,302 +1,302 @@
-#ifdef NEDMALLOC_ENABLED
-
-/* nedalloc, an alternative malloc implementation for multiple threads without
-lock contention based on dlmalloc v2.8.3. (C) 2005-2009 Niall Douglas
-
-Boost Software License - Version 1.0 - August 17th, 2003
-
-Permission is hereby granted, free of charge, to any person or organization
-obtaining a copy of the software and accompanying documentation covered by
-this license (the "Software") to use, reproduce, display, distribute,
-execute, and transmit the Software, and to prepare derivative works of the
-Software, and to permit third-parties to whom the Software is furnished to
-do so, all subject to the following:
-
-The copyright notices in the Software and this entire statement, including
-the above license grant, this restriction and the following disclaimer,
-must be included in all copies of the Software, in whole or in part, and
-all derivative works of the Software, unless such copies or derivative
-works are solely in the form of machine-executable object code generated by
-a source language processor.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
-SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
-FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
-ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
-*/
-
-#ifndef NEDMALLOC_H
-#define NEDMALLOC_H
-
-#include "typedefs.h"
-#define MALLOC_ALIGNMENT DEFAULT_ALIGNMENT
-
-#ifdef PSP_ENABLED
-#define USE_LOCKS 0
-#define HAVE_MMAP 0
-#endif
-
-/* See malloc.c.h for what each function does.
-
-REPLACE_SYSTEM_ALLOCATOR on POSIX causes nedalloc's functions to be called
-malloc, free etc. instead of nedmalloc, nedfree etc. You may or may not want
-this. On Windows it causes nedmalloc to patch all loaded DLLs and binaries
-to replace usage of the system allocator.
-
-NO_NED_NAMESPACE prevents the functions from being defined in the nedalloc
-namespace when in C++ (uses the global namespace instead).
-
-NEDMALLOCEXTSPEC can be defined to be __declspec(dllexport) or
-__attribute__ ((visibility("default"))) or whatever you like. It defaults
-to extern unless NEDMALLOC_DLL_EXPORTS is set as it would be when building
-nedmalloc.dll.
-
-USE_LOCKS can be 2 if you want to define your own MLOCK_T, INITIAL_LOCK,
-ACQUIRE_LOCK, RELEASE_LOCK, TRY_LOCK, IS_LOCKED and NULL_LOCK_INITIALIZER.
-
-NEDMALLOC_DEBUG can be defined to cause DEBUG to be set differently for nedmalloc
-than for the rest of the build. Remember to set NDEBUG to disable all assertion
-checking too.
-
-USE_MAGIC_HEADERS causes nedalloc to allocate an extra three sizeof(size_t)
-to each block. nedpfree() and nedprealloc() can then automagically know when
-to free a system allocated block. Enabling this typically adds 20-50% to
-application memory usage.
-
-ENABLE_TOLERANT_NEDMALLOC is automatically turned on if REPLACE_SYSTEM_ALLOCATOR
-is set or the Windows DLL is being built. This causes nedmalloc to detect when a
-system allocator block is passed to it and to handle it appropriately. Note that
-without USE_MAGIC_HEADERS there is a very tiny chance that nedmalloc will segfault
-on non-Windows builds (it uses Win32 SEH to trap segfaults on Windows and there
-is no comparable system on POSIX).
-
-USE_ALLOCATOR can be one of these settings (it defaults to 1):
- 0: System allocator (nedmalloc now simply acts as a threadcache).
- WARNING: Intended for DEBUG USE ONLY - not all functions work correctly.
- 1: dlmalloc
-
-ENABLE_LARGE_PAGES enables support for requesting memory from the system in large
-(typically >=2Mb) pages if the host OS supports this. These occupy just a single
-TLB entry and can significantly improve performance in large working set applications.
-
-ENABLE_FAST_HEAP_DETECTION enables special logic to detect blocks allocated
-by the system heap. This avoids 1.5%-2% overhead when checking for non-nedmalloc
-blocks, but it assumes that the NT and glibc heaps function in a very specific
-fashion which may not hold true across OS upgrades.
-*/
-
-#include <stddef.h> /* for size_t */
-
-#ifndef NEDMALLOCEXTSPEC
- #ifdef NEDMALLOC_DLL_EXPORTS
- #ifdef WIN32
- #define NEDMALLOCEXTSPEC extern __declspec(dllexport)
- #elif defined(__GNUC__)
- #define NEDMALLOCEXTSPEC extern __attribute__ ((visibility("default")))
- #endif
- #ifndef ENABLE_TOLERANT_NEDMALLOC
- #define ENABLE_TOLERANT_NEDMALLOC 1
- #endif
- #else
- #define NEDMALLOCEXTSPEC extern
- #endif
-#endif
-
-#if __STDC_VERSION__ >= 199901L /* C99 or better */
- #define RESTRICT restrict
-#else
- #if defined(_MSC_VER) && _MSC_VER>=1400
- #define RESTRICT __restrict
- #endif
- #ifdef __GNUC__
- #define RESTRICT __restrict
- #endif
-#endif
-#ifndef RESTRICT
- #define RESTRICT
-#endif
-
-#if defined(_MSC_VER) && _MSC_VER>=1400
- #define NEDMALLOCPTRATTR __declspec(restrict)
- #define NEDMALLOCNOALIASATTR __declspec(noalias)
-#endif
-#ifdef __GNUC__
- #define NEDMALLOCPTRATTR __attribute__ ((malloc))
-#endif
-#ifndef NEDMALLOCPTRATTR
- #define NEDMALLOCPTRATTR
-#endif
-#ifndef NEDMALLOCNOALIASATTR
- #define NEDMALLOCNOALIASATTR
-#endif
-
-#ifndef USE_MAGIC_HEADERS
- #define USE_MAGIC_HEADERS 0
-#endif
-
-#ifndef USE_ALLOCATOR
- #define USE_ALLOCATOR 1 /* dlmalloc */
-#endif
-
-#if !USE_ALLOCATOR && !USE_MAGIC_HEADERS
-#error If you are using the system allocator then you MUST use magic headers
-#endif
-
-#ifdef REPLACE_SYSTEM_ALLOCATOR
- #if USE_ALLOCATOR==0
- #error Cannot combine using the system allocator with replacing the system allocator
- #endif
- #ifndef ENABLE_TOLERANT_NEDMALLOC
- #define ENABLE_TOLERANT_NEDMALLOC 1
- #endif
- #ifndef WIN32 /* We have a dedicated patcher for Windows */
- #define nedmalloc malloc
- #define nedcalloc calloc
- #define nedrealloc realloc
- #define nedfree free
- #define nedmemalign memalign
- #define nedmallinfo mallinfo
- #define nedmallopt mallopt
- #define nedmalloc_trim malloc_trim
- #define nedmalloc_stats malloc_stats
- #define nedmalloc_footprint malloc_footprint
- #define nedindependent_calloc independent_calloc
- #define nedindependent_comalloc independent_comalloc
- #ifdef _MSC_VER
- #define nedblksize _msize
- #endif
- #endif
-#endif
-
-#if defined(__cplusplus)
-extern "C" {
-#endif
-struct nedmallinfo {
- size_t arena; /* non-mmapped space allocated from system */
- size_t ordblks; /* number of free chunks */
- size_t smblks; /* always 0 */
- size_t hblks; /* always 0 */
- size_t hblkhd; /* space in mmapped regions */
- size_t usmblks; /* maximum total allocated space */
- size_t fsmblks; /* always 0 */
- size_t uordblks; /* total allocated space */
- size_t fordblks; /* total free space */
- size_t keepcost; /* releasable (via malloc_trim) space */
-};
-#if defined(__cplusplus)
-}
-#endif
-
-#if defined(__cplusplus)
- #if !defined(NO_NED_NAMESPACE)
-namespace nedalloc {
- #else
-extern "C" {
- #endif
- #define THROWSPEC throw()
-#else
- #define THROWSPEC
-#endif
-
-/* These are the global functions */
-
-/* Gets the usable size of an allocated block. Note this will always be bigger than what was
-asked for due to rounding etc. Optionally returns 1 in isforeign if the block came from the
-system allocator - note that there is a small (>0.01%) but real chance of segfault on non-Windows
-systems when passing non-nedmalloc blocks if you don't use USE_MAGIC_HEADERS.
-*/
-NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR size_t nedblksize(int *RESTRICT isforeign, void *RESTRICT mem) THROWSPEC;
-
-NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR void nedsetvalue(void *v) THROWSPEC;
-
-NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR NEDMALLOCPTRATTR void * nedmalloc(size_t size) THROWSPEC;
-NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR NEDMALLOCPTRATTR void * nedcalloc(size_t no, size_t size) THROWSPEC;
-NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR NEDMALLOCPTRATTR void * nedrealloc(void *mem, size_t size) THROWSPEC;
-NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR void nedfree(void *mem) THROWSPEC;
-NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR NEDMALLOCPTRATTR void * nedmemalign(size_t alignment, size_t bytes) THROWSPEC;
-NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR struct nedmallinfo nedmallinfo(void) THROWSPEC;
-NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR int nedmallopt(int parno, int value) THROWSPEC;
-NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR void* nedmalloc_internals(size_t *granularity, size_t *magic) THROWSPEC;
-NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR int nedmalloc_trim(size_t pad) THROWSPEC;
-NEDMALLOCEXTSPEC void nedmalloc_stats(void) THROWSPEC;
-NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR size_t nedmalloc_footprint(void) THROWSPEC;
-NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR NEDMALLOCPTRATTR void **nedindependent_calloc(size_t elemsno, size_t elemsize, void **chunks) THROWSPEC;
-NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR NEDMALLOCPTRATTR void **nedindependent_comalloc(size_t elems, size_t *sizes, void **chunks) THROWSPEC;
-
-/* Destroys the system memory pool used by the functions above.
-Useful for when you have nedmalloc in a DLL you're about to unload.
-If you call ANY nedmalloc functions after calling this you will
-get a fatal exception!
-*/
-NEDMALLOCEXTSPEC void neddestroysyspool() THROWSPEC;
-
-/* These are the pool functions */
-struct nedpool_t;
-typedef struct nedpool_t nedpool;
-
-/* Creates a memory pool for use with the nedp* functions below.
-Capacity is how much to allocate immediately (if you know you'll be allocating a lot
-of memory very soon) which you can leave at zero. Threads specifies how many threads
-will *normally* be accessing the pool concurrently. Setting this to zero means it
-extends on demand, but be careful of this as it can rapidly consume system resources
-where bursts of concurrent threads use a pool at once.
-*/
-NEDMALLOCEXTSPEC NEDMALLOCPTRATTR nedpool *nedcreatepool(size_t capacity, int threads) THROWSPEC;
-
-/* Destroys a memory pool previously created by nedcreatepool().
-*/
-NEDMALLOCEXTSPEC void neddestroypool(nedpool *p) THROWSPEC;
-
-/* Returns a zero terminated snapshot of threadpools existing at the time of call. Call
-nedfree() on the returned list when you are done. Returns zero if there is only the
-system pool in existence.
-*/
-NEDMALLOCEXTSPEC nedpool **nedpoollist() THROWSPEC;
-
-/* Sets a value to be associated with a pool. You can retrieve this value by passing
-any memory block allocated from that pool.
-*/
-NEDMALLOCEXTSPEC void nedpsetvalue(nedpool *p, void *v) THROWSPEC;
-
-/* Gets a previously set value using nedpsetvalue() or zero if memory is unknown.
-Optionally can also retrieve pool. You can detect an unknown block by the return
-being zero and *p being unmodifed.
-*/
-NEDMALLOCEXTSPEC void *nedgetvalue(nedpool **p, void *mem) THROWSPEC;
-
-/* Trims the thread cache for the calling thread, returning any existing cache
-data to the central pool. Remember to ALWAYS call with zero if you used the
-system pool. Setting disable to non-zero replicates neddisablethreadcache().
-*/
-NEDMALLOCEXTSPEC void nedtrimthreadcache(nedpool *p, int disable) THROWSPEC;
-
-/* Disables the thread cache for the calling thread, returning any existing cache
-data to the central pool. Remember to ALWAYS call with zero if you used the
-system pool.
-*/
-NEDMALLOCEXTSPEC void neddisablethreadcache(nedpool *p) THROWSPEC;
-
-
-NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedpmalloc(nedpool *p, size_t size) THROWSPEC;
-NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedpcalloc(nedpool *p, size_t no, size_t size) THROWSPEC;
-NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedprealloc(nedpool *p, void *mem, size_t size) THROWSPEC;
-NEDMALLOCEXTSPEC void nedpfree(nedpool *p, void *mem) THROWSPEC;
-NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedpmemalign(nedpool *p, size_t alignment, size_t bytes) THROWSPEC;
-NEDMALLOCEXTSPEC struct nedmallinfo nedpmallinfo(nedpool *p) THROWSPEC;
-NEDMALLOCEXTSPEC int nedpmallopt(nedpool *p, int parno, int value) THROWSPEC;
-NEDMALLOCEXTSPEC int nedpmalloc_trim(nedpool *p, size_t pad) THROWSPEC;
-NEDMALLOCEXTSPEC void nedpmalloc_stats(nedpool *p) THROWSPEC;
-NEDMALLOCEXTSPEC size_t nedpmalloc_footprint(nedpool *p) THROWSPEC;
-NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void **nedpindependent_calloc(nedpool *p, size_t elemsno, size_t elemsize, void **chunks) THROWSPEC;
-NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void **nedpindependent_comalloc(nedpool *p, size_t elems, size_t *sizes, void **chunks) THROWSPEC;
-
-#if defined(__cplusplus)
-}
-#endif
-
-#endif
-
-#endif
+#ifdef NEDMALLOC_ENABLED
+
+/* nedalloc, an alternative malloc implementation for multiple threads without
+lock contention based on dlmalloc v2.8.3. (C) 2005-2009 Niall Douglas
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef NEDMALLOC_H
+#define NEDMALLOC_H
+
+#include "typedefs.h"
+#define MALLOC_ALIGNMENT DEFAULT_ALIGNMENT
+
+#ifdef PSP_ENABLED
+#define USE_LOCKS 0
+#define HAVE_MMAP 0
+#endif
+
+/* See malloc.c.h for what each function does.
+
+REPLACE_SYSTEM_ALLOCATOR on POSIX causes nedalloc's functions to be called
+malloc, free etc. instead of nedmalloc, nedfree etc. You may or may not want
+this. On Windows it causes nedmalloc to patch all loaded DLLs and binaries
+to replace usage of the system allocator.
+
+NO_NED_NAMESPACE prevents the functions from being defined in the nedalloc
+namespace when in C++ (uses the global namespace instead).
+
+NEDMALLOCEXTSPEC can be defined to be __declspec(dllexport) or
+__attribute__ ((visibility("default"))) or whatever you like. It defaults
+to extern unless NEDMALLOC_DLL_EXPORTS is set as it would be when building
+nedmalloc.dll.
+
+USE_LOCKS can be 2 if you want to define your own MLOCK_T, INITIAL_LOCK,
+ACQUIRE_LOCK, RELEASE_LOCK, TRY_LOCK, IS_LOCKED and NULL_LOCK_INITIALIZER.
+
+NEDMALLOC_DEBUG can be defined to cause DEBUG to be set differently for nedmalloc
+than for the rest of the build. Remember to set NDEBUG to disable all assertion
+checking too.
+
+USE_MAGIC_HEADERS causes nedalloc to allocate an extra three sizeof(size_t)
+to each block. nedpfree() and nedprealloc() can then automagically know when
+to free a system allocated block. Enabling this typically adds 20-50% to
+application memory usage.
+
+ENABLE_TOLERANT_NEDMALLOC is automatically turned on if REPLACE_SYSTEM_ALLOCATOR
+is set or the Windows DLL is being built. This causes nedmalloc to detect when a
+system allocator block is passed to it and to handle it appropriately. Note that
+without USE_MAGIC_HEADERS there is a very tiny chance that nedmalloc will segfault
+on non-Windows builds (it uses Win32 SEH to trap segfaults on Windows and there
+is no comparable system on POSIX).
+
+USE_ALLOCATOR can be one of these settings (it defaults to 1):
+ 0: System allocator (nedmalloc now simply acts as a threadcache).
+ WARNING: Intended for DEBUG USE ONLY - not all functions work correctly.
+ 1: dlmalloc
+
+ENABLE_LARGE_PAGES enables support for requesting memory from the system in large
+(typically >=2Mb) pages if the host OS supports this. These occupy just a single
+TLB entry and can significantly improve performance in large working set applications.
+
+ENABLE_FAST_HEAP_DETECTION enables special logic to detect blocks allocated
+by the system heap. This avoids 1.5%-2% overhead when checking for non-nedmalloc
+blocks, but it assumes that the NT and glibc heaps function in a very specific
+fashion which may not hold true across OS upgrades.
+*/
+
+#include <stddef.h> /* for size_t */
+
+#ifndef NEDMALLOCEXTSPEC
+ #ifdef NEDMALLOC_DLL_EXPORTS
+ #ifdef WIN32
+ #define NEDMALLOCEXTSPEC extern __declspec(dllexport)
+ #elif defined(__GNUC__)
+ #define NEDMALLOCEXTSPEC extern __attribute__ ((visibility("default")))
+ #endif
+ #ifndef ENABLE_TOLERANT_NEDMALLOC
+ #define ENABLE_TOLERANT_NEDMALLOC 1
+ #endif
+ #else
+ #define NEDMALLOCEXTSPEC extern
+ #endif
+#endif
+
+#if __STDC_VERSION__ >= 199901L /* C99 or better */
+ #define RESTRICT restrict
+#else
+ #if defined(_MSC_VER) && _MSC_VER>=1400
+ #define RESTRICT __restrict
+ #endif
+ #ifdef __GNUC__
+ #define RESTRICT __restrict
+ #endif
+#endif
+#ifndef RESTRICT
+ #define RESTRICT
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER>=1400
+ #define NEDMALLOCPTRATTR __declspec(restrict)
+ #define NEDMALLOCNOALIASATTR __declspec(noalias)
+#endif
+#ifdef __GNUC__
+ #define NEDMALLOCPTRATTR __attribute__ ((malloc))
+#endif
+#ifndef NEDMALLOCPTRATTR
+ #define NEDMALLOCPTRATTR
+#endif
+#ifndef NEDMALLOCNOALIASATTR
+ #define NEDMALLOCNOALIASATTR
+#endif
+
+#ifndef USE_MAGIC_HEADERS
+ #define USE_MAGIC_HEADERS 0
+#endif
+
+#ifndef USE_ALLOCATOR
+ #define USE_ALLOCATOR 1 /* dlmalloc */
+#endif
+
+#if !USE_ALLOCATOR && !USE_MAGIC_HEADERS
+#error If you are using the system allocator then you MUST use magic headers
+#endif
+
+#ifdef REPLACE_SYSTEM_ALLOCATOR
+ #if USE_ALLOCATOR==0
+ #error Cannot combine using the system allocator with replacing the system allocator
+ #endif
+ #ifndef ENABLE_TOLERANT_NEDMALLOC
+ #define ENABLE_TOLERANT_NEDMALLOC 1
+ #endif
+ #ifndef WIN32 /* We have a dedicated patcher for Windows */
+ #define nedmalloc malloc
+ #define nedcalloc calloc
+ #define nedrealloc realloc
+ #define nedfree free
+ #define nedmemalign memalign
+ #define nedmallinfo mallinfo
+ #define nedmallopt mallopt
+ #define nedmalloc_trim malloc_trim
+ #define nedmalloc_stats malloc_stats
+ #define nedmalloc_footprint malloc_footprint
+ #define nedindependent_calloc independent_calloc
+ #define nedindependent_comalloc independent_comalloc
+ #ifdef _MSC_VER
+ #define nedblksize _msize
+ #endif
+ #endif
+#endif
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+struct nedmallinfo {
+ size_t arena; /* non-mmapped space allocated from system */
+ size_t ordblks; /* number of free chunks */
+ size_t smblks; /* always 0 */
+ size_t hblks; /* always 0 */
+ size_t hblkhd; /* space in mmapped regions */
+ size_t usmblks; /* maximum total allocated space */
+ size_t fsmblks; /* always 0 */
+ size_t uordblks; /* total allocated space */
+ size_t fordblks; /* total free space */
+ size_t keepcost; /* releasable (via malloc_trim) space */
+};
+#if defined(__cplusplus)
+}
+#endif
+
+#if defined(__cplusplus)
+ #if !defined(NO_NED_NAMESPACE)
+namespace nedalloc {
+ #else
+extern "C" {
+ #endif
+ #define THROWSPEC throw()
+#else
+ #define THROWSPEC
+#endif
+
+/* These are the global functions */
+
+/* Gets the usable size of an allocated block. Note this will always be bigger than what was
+asked for due to rounding etc. Optionally returns 1 in isforeign if the block came from the
+system allocator - note that there is a small (>0.01%) but real chance of segfault on non-Windows
+systems when passing non-nedmalloc blocks if you don't use USE_MAGIC_HEADERS.
+*/
+NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR size_t nedblksize(int *RESTRICT isforeign, void *RESTRICT mem) THROWSPEC;
+
+NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR void nedsetvalue(void *v) THROWSPEC;
+
+NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR NEDMALLOCPTRATTR void * nedmalloc(size_t size) THROWSPEC;
+NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR NEDMALLOCPTRATTR void * nedcalloc(size_t no, size_t size) THROWSPEC;
+NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR NEDMALLOCPTRATTR void * nedrealloc(void *mem, size_t size) THROWSPEC;
+NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR void nedfree(void *mem) THROWSPEC;
+NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR NEDMALLOCPTRATTR void * nedmemalign(size_t alignment, size_t bytes) THROWSPEC;
+NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR struct nedmallinfo nedmallinfo(void) THROWSPEC;
+NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR int nedmallopt(int parno, int value) THROWSPEC;
+NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR void* nedmalloc_internals(size_t *granularity, size_t *magic) THROWSPEC;
+NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR int nedmalloc_trim(size_t pad) THROWSPEC;
+NEDMALLOCEXTSPEC void nedmalloc_stats(void) THROWSPEC;
+NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR size_t nedmalloc_footprint(void) THROWSPEC;
+NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR NEDMALLOCPTRATTR void **nedindependent_calloc(size_t elemsno, size_t elemsize, void **chunks) THROWSPEC;
+NEDMALLOCEXTSPEC NEDMALLOCNOALIASATTR NEDMALLOCPTRATTR void **nedindependent_comalloc(size_t elems, size_t *sizes, void **chunks) THROWSPEC;
+
+/* Destroys the system memory pool used by the functions above.
+Useful for when you have nedmalloc in a DLL you're about to unload.
+If you call ANY nedmalloc functions after calling this you will
+get a fatal exception!
+*/
+NEDMALLOCEXTSPEC void neddestroysyspool() THROWSPEC;
+
+/* These are the pool functions */
+struct nedpool_t;
+typedef struct nedpool_t nedpool;
+
+/* Creates a memory pool for use with the nedp* functions below.
+Capacity is how much to allocate immediately (if you know you'll be allocating a lot
+of memory very soon) which you can leave at zero. Threads specifies how many threads
+will *normally* be accessing the pool concurrently. Setting this to zero means it
+extends on demand, but be careful of this as it can rapidly consume system resources
+where bursts of concurrent threads use a pool at once.
+*/
+NEDMALLOCEXTSPEC NEDMALLOCPTRATTR nedpool *nedcreatepool(size_t capacity, int threads) THROWSPEC;
+
+/* Destroys a memory pool previously created by nedcreatepool().
+*/
+NEDMALLOCEXTSPEC void neddestroypool(nedpool *p) THROWSPEC;
+
+/* Returns a zero terminated snapshot of threadpools existing at the time of call. Call
+nedfree() on the returned list when you are done. Returns zero if there is only the
+system pool in existence.
+*/
+NEDMALLOCEXTSPEC nedpool **nedpoollist() THROWSPEC;
+
+/* Sets a value to be associated with a pool. You can retrieve this value by passing
+any memory block allocated from that pool.
+*/
+NEDMALLOCEXTSPEC void nedpsetvalue(nedpool *p, void *v) THROWSPEC;
+
+/* Gets a previously set value using nedpsetvalue() or zero if memory is unknown.
+Optionally can also retrieve pool. You can detect an unknown block by the return
+being zero and *p being unmodifed.
+*/
+NEDMALLOCEXTSPEC void *nedgetvalue(nedpool **p, void *mem) THROWSPEC;
+
+/* Trims the thread cache for the calling thread, returning any existing cache
+data to the central pool. Remember to ALWAYS call with zero if you used the
+system pool. Setting disable to non-zero replicates neddisablethreadcache().
+*/
+NEDMALLOCEXTSPEC void nedtrimthreadcache(nedpool *p, int disable) THROWSPEC;
+
+/* Disables the thread cache for the calling thread, returning any existing cache
+data to the central pool. Remember to ALWAYS call with zero if you used the
+system pool.
+*/
+NEDMALLOCEXTSPEC void neddisablethreadcache(nedpool *p) THROWSPEC;
+
+
+NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedpmalloc(nedpool *p, size_t size) THROWSPEC;
+NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedpcalloc(nedpool *p, size_t no, size_t size) THROWSPEC;
+NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedprealloc(nedpool *p, void *mem, size_t size) THROWSPEC;
+NEDMALLOCEXTSPEC void nedpfree(nedpool *p, void *mem) THROWSPEC;
+NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void * nedpmemalign(nedpool *p, size_t alignment, size_t bytes) THROWSPEC;
+NEDMALLOCEXTSPEC struct nedmallinfo nedpmallinfo(nedpool *p) THROWSPEC;
+NEDMALLOCEXTSPEC int nedpmallopt(nedpool *p, int parno, int value) THROWSPEC;
+NEDMALLOCEXTSPEC int nedpmalloc_trim(nedpool *p, size_t pad) THROWSPEC;
+NEDMALLOCEXTSPEC void nedpmalloc_stats(nedpool *p) THROWSPEC;
+NEDMALLOCEXTSPEC size_t nedpmalloc_footprint(nedpool *p) THROWSPEC;
+NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void **nedpindependent_calloc(nedpool *p, size_t elemsno, size_t elemsize, void **chunks) THROWSPEC;
+NEDMALLOCEXTSPEC NEDMALLOCPTRATTR void **nedpindependent_comalloc(nedpool *p, size_t elems, size_t *sizes, void **chunks) THROWSPEC;
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif
+
+#endif
diff --git a/drivers/nrex/README.md b/drivers/nrex/README.md
new file mode 100644
index 0000000000..9ff67992dc
--- /dev/null
+++ b/drivers/nrex/README.md
@@ -0,0 +1,61 @@
+# NREX: Node RegEx
+
+Version 0.1
+
+Small node-based regular expression library. It only does text pattern
+matchhing, not replacement. To use add the files `nrex.hpp`, `nrex.cpp`
+and `nrex_config.h` to your project and follow the example:
+
+ nrex regex;
+ regex.compile("^(fo+)bar$");
+
+ nrex_result captures[regex.capture_size()];
+ if (regex.match("foobar", captures))
+ {
+ std::cout << captures[0].start << std::endl;
+ std::cout << captures[0].length << std::endl;
+ }
+
+More details about its use is documented in `nrex.hpp`
+
+Currently supported features:
+ * Capturing `()` and non-capturing `(?:)` groups
+ * Any character `.` (includes newlines)
+ * Shorthand caracter classes `\w\W\s\S\d\D`
+ * POSIX character classes such as `[[:alnum:]]`
+ * Bracket expressions such as `[A-Za-z]`
+ * Simple quantifiers `?`, `*` and `+`
+ * Range quantifiers `{0,1}`
+ * Lazy (non-greedy) quantifiers `*?`
+ * Begining `^` and end `$` anchors
+ * Word boundaries `\b`
+ * Alternation `|`
+ * ASCII `\xFF` code points
+ * Unicode `\uFFFF` code points
+ * Positive `(?=)` and negative `(?!)` lookahead
+ * Positive `(?<=)` and negative `(?<!)` lookbehind (fixed length and no alternations)
+ * Backreferences `\1` and `\g{1}` (limited by default to 9 - can be unlimited)
+
+## License
+
+Copyright (c) 2015, Zher Huei Lee
+All rights reserved.
+
+This software is provided 'as-is', without any express or implied
+warranty. In no event will the authors be held liable for any damages
+arising from the use of this software.
+
+Permission is granted to anyone to use this software for any purpose,
+including commercial applications, and to alter it and redistribute it
+freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would
+ be appreciated but is not required.
+
+ 2. Altered source versions must be plainly marked as such, and must not
+ be misrepresented as being the original software.
+
+ 3. This notice may not be removed or altered from any source
+ distribution.
diff --git a/drivers/nrex/SCsub b/drivers/nrex/SCsub
new file mode 100644
index 0000000000..a00c7b86f4
--- /dev/null
+++ b/drivers/nrex/SCsub
@@ -0,0 +1,7 @@
+Import('env')
+
+sources = [
+ 'nrex.cpp',
+ 'regex.cpp',
+]
+env.add_source_files(env.drivers_sources, sources)
diff --git a/drivers/nrex/nrex.cpp b/drivers/nrex/nrex.cpp
new file mode 100644
index 0000000000..1eb9ec38c8
--- /dev/null
+++ b/drivers/nrex/nrex.cpp
@@ -0,0 +1,1435 @@
+// NREX: Node RegEx
+// Version 0.1
+//
+// Copyright (c) 2015, Zher Huei Lee
+// All rights reserved.
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+// claim that you wrote the original software. If you use this software
+// in a product, an acknowledgment in the product documentation would
+// be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such, and must not
+// be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source
+// distribution.
+//
+
+#include "nrex.hpp"
+
+#ifdef NREX_UNICODE
+#include <wctype.h>
+#include <wchar.h>
+#define NREX_ISALPHANUM iswalnum
+#define NREX_ISSPACE iswspace
+#define NREX_STRLEN wcslen
+#else
+#include <ctype.h>
+#include <string.h>
+#define NREX_ISALPHANUM isalnum
+#define NREX_ISSPACE isspace
+#define NREX_STRLEN strlen
+#endif
+
+#ifdef NREX_THROW_ERROR
+#define NREX_COMPILE_ERROR(M) throw nrex_compile_error(M)
+#else
+#define NREX_COMPILE_ERROR(M) reset(); return false
+#endif
+
+#ifndef NREX_NEW
+#define NREX_NEW(X) new X
+#define NREX_NEW_ARRAY(X, N) new X[N]
+#define NREX_DELETE(X) delete X
+#define NREX_DELETE_ARRAY(X) delete[] X
+#endif
+
+template<typename T>
+class nrex_array
+{
+ private:
+ T* _data;
+ unsigned int _reserved;
+ unsigned int _size;
+ public:
+ nrex_array()
+ : _data(NREX_NEW_ARRAY(T, 2))
+ , _reserved(2)
+ , _size(0)
+ {
+ }
+
+ ~nrex_array()
+ {
+ NREX_DELETE_ARRAY(_data);
+ }
+
+ unsigned int size() const
+ {
+ return _size;
+ }
+
+ void reserve(unsigned int size)
+ {
+ T* old = _data;
+ _data = NREX_NEW_ARRAY(T, size);
+ _reserved = size;
+ for (unsigned int i = 0; i < _size; ++i)
+ {
+ _data[i] = old[i];
+ }
+ NREX_DELETE_ARRAY(old);
+ }
+
+ void push(T item)
+ {
+ if (_size == _reserved)
+ {
+ reserve(_reserved * 2);
+ }
+ _data[_size] = item;
+ _size++;
+ }
+
+ T& top()
+ {
+ return _data[_size - 1];
+ }
+
+ const T& operator[] (unsigned int i) const
+ {
+ return _data[i];
+ }
+
+ void pop()
+ {
+ if (_size > 0)
+ {
+ --_size;
+ }
+ }
+};
+
+static int nrex_parse_hex(nrex_char c)
+{
+ if ('0' <= c && c <= '9')
+ {
+ return int(c - '0');
+ }
+ else if ('a' <= c && c <= 'f')
+ {
+ return int(c - 'a') + 10;
+ }
+ else if ('A' <= c && c <= 'F')
+ {
+ return int(c - 'A') + 10;
+ }
+ return -1;
+}
+
+static nrex_char nrex_unescape(const nrex_char*& c)
+{
+ switch (c[1])
+ {
+ case '0': ++c; return '\0';
+ case 'a': ++c; return '\a';
+ case 'e': ++c; return '\e';
+ case 'f': ++c; return '\f';
+ case 'n': ++c; return '\n';
+ case 'r': ++c; return '\r';
+ case 't': ++c; return '\t';
+ case 'v': ++c; return '\v';
+ case 'b': ++c; return '\b';
+ case 'x':
+ {
+ int point = 0;
+ for (int i = 2; i <= 3; ++i)
+ {
+ int res = nrex_parse_hex(c[i]);
+ if (res == -1)
+ {
+ return '\0';
+ }
+ point = (point << 4) + res;
+ }
+ c = &c[3];
+ return nrex_char(point);
+ }
+ case 'u':
+ {
+ int point = 0;
+ for (int i = 2; i <= 5; ++i)
+ {
+ int res = nrex_parse_hex(c[i]);
+ if (res == -1)
+ {
+ return '\0';
+ }
+ point = (point << 4) + res;
+ }
+ c = &c[5];
+ return nrex_char(point);
+ }
+ }
+ return (++c)[0];
+}
+
+struct nrex_search
+{
+ const nrex_char* str;
+ nrex_result* captures;
+ int end;
+ bool complete;
+
+ nrex_char at(int pos)
+ {
+ return str[pos];
+ }
+
+ nrex_search(const nrex_char* str, nrex_result* captures)
+ : str(str)
+ , captures(captures)
+ , end(0)
+ {
+ }
+};
+
+struct nrex_node
+{
+ nrex_node* next;
+ nrex_node* previous;
+ nrex_node* parent;
+ bool quantifiable;
+ int length;
+
+ nrex_node(bool quantify = false)
+ : next(NULL)
+ , previous(NULL)
+ , parent(NULL)
+ , quantifiable(quantify)
+ , length(-1)
+ {
+ }
+
+ virtual ~nrex_node()
+ {
+ if (next)
+ {
+ NREX_DELETE(next);
+ }
+ }
+
+ virtual int test(nrex_search* s, int pos) const
+ {
+ return next ? next->test(s, pos) : -1;
+ }
+
+ virtual int test_parent(nrex_search* s, int pos) const
+ {
+ if (next)
+ {
+ pos = next->test(s, pos);
+ }
+ if (parent && pos >= 0)
+ {
+ pos = parent->test_parent(s, pos);
+ }
+ if (pos >= 0)
+ {
+ s->complete = true;
+ }
+ return pos;
+ }
+
+ void increment_length(int amount, bool subtract = false)
+ {
+ if (amount >= 0 && length >= 0)
+ {
+ if (!subtract)
+ {
+ length += amount;
+ }
+ else
+ {
+ length -= amount;
+ }
+ }
+ else
+ {
+ length = -1;
+ }
+ if (parent)
+ {
+ parent->increment_length(amount, subtract);
+ }
+ }
+};
+
+struct nrex_node_group : public nrex_node
+{
+ static const int NonCapture = -1;
+ static const int Bracket = -2;
+ static const int LookAhead = -3;
+ static const int LookBehind = -4;
+
+ int mode;
+ bool negate;
+ nrex_array<nrex_node*> childset;
+ nrex_node* back;
+
+ nrex_node_group(int mode)
+ : nrex_node(true)
+ , mode(mode)
+ , negate(false)
+ , back(NULL)
+ {
+ if (mode != Bracket)
+ {
+ length = 0;
+ }
+ else
+ {
+ length = 1;
+ }
+ if (mode == LookAhead || mode == LookBehind)
+ {
+ quantifiable = false;
+ }
+ }
+
+ virtual ~nrex_node_group()
+ {
+ for (unsigned int i = 0; i < childset.size(); ++i)
+ {
+ NREX_DELETE(childset[i]);
+ }
+
+ }
+
+ int test(nrex_search* s, int pos) const
+ {
+ if (mode >= 0)
+ {
+ s->captures[mode].start = pos;
+ }
+ for (unsigned int i = 0; i < childset.size(); ++i)
+ {
+ s->complete = false;
+ int offset = 0;
+ if (mode == LookBehind)
+ {
+ if (pos < length)
+ {
+ return -1;
+ }
+ offset = length;
+ }
+ int res = childset[i]->test(s, pos - offset);
+ if (s->complete)
+ {
+ return res;
+ }
+ if (negate)
+ {
+ if (res < 0)
+ {
+ res = pos + 1;
+ }
+ else
+ {
+ return -1;
+ }
+ if (i + 1 < childset.size())
+ {
+ continue;
+ }
+ }
+ if (res >= 0)
+ {
+ if (mode >= 0)
+ {
+ s->captures[mode].length = res - pos;
+ }
+ else if (mode == LookAhead || mode == LookBehind)
+ {
+ res = pos;
+ }
+ return next ? next->test(s, res) : res;
+ }
+ }
+ return -1;
+ }
+
+ virtual int test_parent(nrex_search* s, int pos) const
+ {
+ if (mode >= 0)
+ {
+ s->captures[mode].length = pos - s->captures[mode].start;
+ }
+ return nrex_node::test_parent(s, pos);
+ }
+
+ void add_childset()
+ {
+ if (childset.size() > 0 && mode != Bracket)
+ {
+ length = -1;
+ }
+ back = NULL;
+ }
+
+ void add_child(nrex_node* node)
+ {
+ node->parent = this;
+ node->previous = back;
+ if (back && mode != Bracket)
+ {
+ back->next = node;
+ }
+ else
+ {
+ childset.push(node);
+ }
+ if (mode != Bracket)
+ {
+ increment_length(node->length);
+ }
+ back = node;
+ }
+
+ nrex_node* swap_back(nrex_node* node)
+ {
+ if (!back)
+ {
+ add_child(node);
+ return NULL;
+ }
+ nrex_node* old = back;
+ if (!old->previous)
+ {
+ childset.pop();
+ }
+ if (mode != Bracket)
+ {
+ increment_length(old->length, true);
+ }
+ back = old->previous;
+ add_child(node);
+ return old;
+ }
+
+ void pop_back()
+ {
+ if (back)
+ {
+ nrex_node* old = back;
+ if (!old->previous)
+ {
+ childset.pop();
+ }
+ if (mode != Bracket)
+ {
+ increment_length(old->length, true);
+ }
+ back = old->previous;
+ NREX_DELETE(old);
+ }
+ }
+};
+
+struct nrex_node_char : public nrex_node
+{
+ nrex_char ch;
+
+ nrex_node_char(nrex_char c)
+ : nrex_node(true)
+ , ch(c)
+ {
+ length = 1;
+ }
+
+ int test(nrex_search* s, int pos) const
+ {
+ if (s->end <= pos || 0 > pos || s->at(pos) != ch)
+ {
+ return -1;
+ }
+ return next ? next->test(s, pos + 1) : pos + 1;
+ }
+};
+
+struct nrex_node_range : public nrex_node
+{
+ nrex_char start;
+ nrex_char end;
+
+ nrex_node_range(nrex_char s, nrex_char e)
+ : nrex_node(true)
+ , start(s)
+ , end(e)
+ {
+ length = 1;
+ }
+
+ int test(nrex_search* s, int pos) const
+ {
+ if (s->end <= pos || 0 > pos)
+ {
+ return -1;
+ }
+ nrex_char c = s->at(pos);
+ if (c < start || end < c)
+ {
+ return -1;
+ }
+ return next ? next->test(s, pos + 1) : pos + 1;
+ }
+};
+
+enum nrex_class_type
+{
+ nrex_class_none,
+ nrex_class_alnum,
+ nrex_class_alpha,
+ nrex_class_blank,
+ nrex_class_cntrl,
+ nrex_class_digit,
+ nrex_class_graph,
+ nrex_class_lower,
+ nrex_class_print,
+ nrex_class_punct,
+ nrex_class_space,
+ nrex_class_upper,
+ nrex_class_xdigit,
+ nrex_class_word
+};
+
+static bool nrex_compare_class(const nrex_char** pos, const char* text)
+{
+ unsigned int i = 0;
+ for (i = 0; text[i] != '\0'; ++i)
+ {
+ if ((*pos)[i] != text[i])
+ {
+ return false;
+ }
+ }
+ if ((*pos)[i++] != ':' || (*pos)[i] != ']')
+ {
+ return false;
+ }
+ *pos = &(*pos)[i];
+ return true;
+}
+
+#define NREX_COMPARE_CLASS(POS, NAME) if (nrex_compare_class(POS, #NAME)) return nrex_class_ ## NAME
+
+static nrex_class_type nrex_parse_class(const nrex_char** pos)
+{
+ NREX_COMPARE_CLASS(pos, alnum);
+ NREX_COMPARE_CLASS(pos, alpha);
+ NREX_COMPARE_CLASS(pos, blank);
+ NREX_COMPARE_CLASS(pos, cntrl);
+ NREX_COMPARE_CLASS(pos, digit);
+ NREX_COMPARE_CLASS(pos, graph);
+ NREX_COMPARE_CLASS(pos, lower);
+ NREX_COMPARE_CLASS(pos, print);
+ NREX_COMPARE_CLASS(pos, punct);
+ NREX_COMPARE_CLASS(pos, space);
+ NREX_COMPARE_CLASS(pos, upper);
+ NREX_COMPARE_CLASS(pos, xdigit);
+ NREX_COMPARE_CLASS(pos, word);
+ return nrex_class_none;
+}
+
+struct nrex_node_class : public nrex_node
+{
+ nrex_class_type type;
+
+ nrex_node_class(nrex_class_type t)
+ : nrex_node(true)
+ , type(t)
+ {
+ length = 1;
+ }
+
+ int test(nrex_search* s, int pos) const
+ {
+ if (s->end <= pos || 0 > pos)
+ {
+ return -1;
+ }
+ if (!test_class(s->at(pos)))
+ {
+ return -1;
+ }
+ return next ? next->test(s, pos + 1) : pos + 1;
+ }
+
+ bool test_class(nrex_char c) const
+ {
+ if ((0 <= c && c <= 0x1F) || c == 0x7F)
+ {
+ if (type == nrex_class_cntrl)
+ {
+ return true;
+ }
+ }
+ else if (c < 0x7F)
+ {
+ if (type == nrex_class_print)
+ {
+ return true;
+ }
+ else if (type == nrex_class_graph && c != ' ')
+ {
+ return true;
+ }
+ else if ('0' <= c && c <= '9')
+ {
+ switch (type)
+ {
+ case nrex_class_alnum:
+ case nrex_class_digit:
+ case nrex_class_xdigit:
+ case nrex_class_word:
+ return true;
+ default:
+ break;
+ }
+ }
+ else if ('A' <= c && c <= 'Z')
+ {
+ switch (type)
+ {
+ case nrex_class_alnum:
+ case nrex_class_alpha:
+ case nrex_class_upper:
+ case nrex_class_word:
+ return true;
+ case nrex_class_xdigit:
+ if (c <= 'F')
+ {
+ return true;
+ }
+ default:
+ break;
+ }
+ }
+ else if ('a' <= c && c <= 'z')
+ {
+ switch (type)
+ {
+ case nrex_class_alnum:
+ case nrex_class_alpha:
+ case nrex_class_lower:
+ case nrex_class_word:
+ return true;
+ case nrex_class_xdigit:
+ if (c <= 'f')
+ {
+ return true;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ switch (c)
+ {
+ case ' ':
+ case '\t':
+ if (type == nrex_class_blank)
+ {
+ return true;
+ }
+ case '\r':
+ case '\n':
+ case '\f':
+ if (type == nrex_class_space)
+ {
+ return true;
+ }
+ break;
+ case '_':
+ if (type == nrex_class_word)
+ {
+ return true;
+ }
+ case ']':
+ case '[':
+ case '!':
+ case '"':
+ case '#':
+ case '$':
+ case '%':
+ case '&':
+ case '\'':
+ case '(':
+ case ')':
+ case '*':
+ case '+':
+ case ',':
+ case '.':
+ case '/':
+ case ':':
+ case ';':
+ case '<':
+ case '=':
+ case '>':
+ case '?':
+ case '@':
+ case '\\':
+ case '^':
+ case '`':
+ case '{':
+ case '|':
+ case '}':
+ case '~':
+ case '-':
+ if (type == nrex_class_punct)
+ {
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ return false;
+ }
+};
+
+static bool nrex_is_shorthand(nrex_char repr)
+{
+ switch (repr)
+ {
+ case 'W':
+ case 'w':
+ case 'D':
+ case 'd':
+ case 'S':
+ case 's':
+ return true;
+ }
+ return false;
+}
+
+struct nrex_node_shorthand : public nrex_node
+{
+ nrex_char repr;
+
+ nrex_node_shorthand(nrex_char c)
+ : nrex_node(true)
+ , repr(c)
+ {
+ length = 1;
+ }
+
+ int test(nrex_search* s, int pos) const
+ {
+ if (s->end <= pos || 0 > pos)
+ {
+ return -1;
+ }
+ bool found = false;
+ bool invert = false;
+ nrex_char c = s->at(pos);
+ switch (repr)
+ {
+ case '.':
+ found = true;
+ break;
+ case 'W':
+ invert = true;
+ case 'w':
+ if (c == '_' || NREX_ISALPHANUM(c))
+ {
+ found = true;
+ }
+ break;
+ case 'D':
+ invert = true;
+ case 'd':
+ if ('0' <= c && c <= '9')
+ {
+ found = true;
+ }
+ break;
+ case 'S':
+ invert = true;
+ case 's':
+ if (NREX_ISSPACE(c))
+ {
+ found = true;
+ }
+ break;
+ }
+ if (found == invert)
+ {
+ return -1;
+ }
+ return next ? next->test(s, pos + 1) : pos + 1;
+ }
+};
+
+static bool nrex_is_quantifier(nrex_char repr)
+{
+ switch (repr)
+ {
+ case '?':
+ case '*':
+ case '+':
+ case '{':
+ return true;
+ }
+ return false;
+}
+
+struct nrex_node_quantifier : public nrex_node
+{
+ int min;
+ int max;
+ bool greedy;
+ nrex_node* child;
+
+ nrex_node_quantifier(int min, int max)
+ : nrex_node()
+ , min(min)
+ , max(max)
+ , greedy(true)
+ , child(NULL)
+ {
+ }
+
+ virtual ~nrex_node_quantifier()
+ {
+ if (child)
+ {
+ NREX_DELETE(child);
+ }
+ }
+
+ int test(nrex_search* s, int pos) const
+ {
+ return test_step(s, pos, 0, pos);
+ }
+
+ int test_step(nrex_search* s, int pos, int level, int start) const
+ {
+ if (pos > s->end)
+ {
+ return -1;
+ }
+ if (!greedy && level > min)
+ {
+ int res = pos;
+ if (next)
+ {
+ res = next->test(s, res);
+ }
+ if (s->complete)
+ {
+ return res;
+ }
+ if (res >= 0 && parent->test_parent(s, res) >= 0)
+ {
+ return res;
+ }
+ }
+ if (max >= 0 && level > max)
+ {
+ return -1;
+ }
+ if (level > 1 && level > min + 1 && pos == start)
+ {
+ return -1;
+ }
+ int res = pos;
+ if (level >= 1)
+ {
+ res = child->test(s, pos);
+ if (s->complete)
+ {
+ return res;
+ }
+ }
+ if (res >= 0)
+ {
+ int res_step = test_step(s, res, level + 1, start);
+ if (res_step >= 0)
+ {
+ return res_step;
+ }
+ else if (greedy && level >= min)
+ {
+ if (next)
+ {
+ res = next->test(s, res);
+ }
+ if (s->complete)
+ {
+ return res;
+ }
+ if (res >= 0 && parent->test_parent(s, res) >= 0)
+ {
+ return res;
+ }
+ }
+ }
+ return -1;
+ }
+};
+
+struct nrex_node_anchor : public nrex_node
+{
+ bool end;
+
+ nrex_node_anchor(bool end)
+ : nrex_node()
+ , end(end)
+ {
+ length = 0;
+ }
+
+ int test(nrex_search* s, int pos) const
+ {
+ if (!end && pos != 0)
+ {
+ return -1;
+ }
+ else if (end && pos != s->end)
+ {
+ return -1;
+ }
+ return next ? next->test(s, pos) : pos;
+ }
+};
+
+struct nrex_node_word_boundary : public nrex_node
+{
+ bool inverse;
+
+ nrex_node_word_boundary(bool inverse)
+ : nrex_node()
+ , inverse(inverse)
+ {
+ length = 0;
+ }
+
+ int test(nrex_search* s, int pos) const
+ {
+ bool left = false;
+ bool right = false;
+ if (pos != 0)
+ {
+ nrex_char c = s->at(pos - 1);
+ if (c == '_' || NREX_ISALPHANUM(c))
+ {
+ left = true;
+ }
+ }
+ if (pos != s->end)
+ {
+ nrex_char c = s->at(pos);
+ if (c == '_' || NREX_ISALPHANUM(c))
+ {
+ right = true;
+ }
+ }
+ if ((left != right) == inverse)
+ {
+ return -1;
+ }
+ return next ? next->test(s, pos) : pos;
+ }
+};
+
+struct nrex_node_backreference : public nrex_node
+{
+ int ref;
+
+ nrex_node_backreference(int ref)
+ : nrex_node(true)
+ , ref(ref)
+ {
+ length = -1;
+ }
+
+ int test(nrex_search* s, int pos) const
+ {
+ nrex_result& r = s->captures[ref];
+ for (int i = 0; i < r.length; ++i)
+ {
+ if (pos + i >= s->end)
+ {
+ return -1;
+ }
+ if (s->at(r.start + i) != s->at(pos + i))
+ {
+ return -1;
+ }
+ }
+ return next ? next->test(s, pos + r.length) : pos + r.length;
+ }
+};
+
+bool nrex_has_lookbehind(nrex_array<nrex_node_group*>& stack)
+{
+ for (unsigned int i = 0; i < stack.size(); i++)
+ {
+ if (stack[i]->mode == nrex_node_group::LookBehind)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+nrex::nrex()
+ : _capturing(0)
+ , _root(NULL)
+{
+}
+
+nrex::nrex(const nrex_char* pattern, int captures)
+ : _capturing(0)
+ , _root(NULL)
+{
+ compile(pattern, captures);
+}
+
+nrex::~nrex()
+{
+ if (_root)
+ {
+ NREX_DELETE(_root);
+ }
+}
+
+bool nrex::valid() const
+{
+ return (_root != NULL);
+}
+
+void nrex::reset()
+{
+ _capturing = 0;
+ if (_root)
+ {
+ NREX_DELETE(_root);
+ }
+ _root = NULL;
+}
+
+int nrex::capture_size() const
+{
+ if (_root)
+ {
+ return _capturing + 1;
+ }
+ return 0;
+}
+
+bool nrex::compile(const nrex_char* pattern, int captures)
+{
+ reset();
+ nrex_node_group* root = NREX_NEW(nrex_node_group(_capturing));
+ nrex_array<nrex_node_group*> stack;
+ stack.push(root);
+ _root = root;
+
+ for (const nrex_char* c = pattern; c[0] != '\0'; ++c)
+ {
+ if (c[0] == '(')
+ {
+ if (c[1] == '?')
+ {
+ if (c[2] == ':')
+ {
+ c = &c[2];
+ nrex_node_group* group = NREX_NEW(nrex_node_group(nrex_node_group::NonCapture));
+ stack.top()->add_child(group);
+ stack.push(group);
+ }
+ else if (c[2] == '!' || c[2] == '=')
+ {
+ c = &c[2];
+ nrex_node_group* group = NREX_NEW(nrex_node_group(nrex_node_group::LookAhead));
+ group->negate = (c[0] == '!');
+ stack.top()->add_child(group);
+ stack.push(group);
+ }
+ else if (c[2] == '<' && (c[3] == '!' || c[3] == '='))
+ {
+ c = &c[3];
+ nrex_node_group* group = NREX_NEW(nrex_node_group(nrex_node_group::LookBehind));
+ group->negate = (c[0] == '!');
+ stack.top()->add_child(group);
+ stack.push(group);
+ }
+ else
+ {
+ NREX_COMPILE_ERROR("unrecognised qualifier for group");
+ }
+ }
+ else if (captures >= 0 && _capturing < captures)
+ {
+ nrex_node_group* group = NREX_NEW(nrex_node_group(++_capturing));
+ stack.top()->add_child(group);
+ stack.push(group);
+ }
+ else
+ {
+ nrex_node_group* group = NREX_NEW(nrex_node_group(nrex_node_group::NonCapture));
+ stack.top()->add_child(group);
+ stack.push(group);
+ }
+ }
+ else if (c[0] == ')')
+ {
+ if (stack.size() > 1)
+ {
+ stack.pop();
+ }
+ else
+ {
+ NREX_COMPILE_ERROR("unexpected ')'");
+ }
+ }
+ else if (c[0] == '[')
+ {
+ nrex_node_group* group = NREX_NEW(nrex_node_group(nrex_node_group::Bracket));
+ stack.top()->add_child(group);
+ if (c[1] == '^')
+ {
+ group->negate = true;
+ ++c;
+ }
+ bool first_child = true;
+ nrex_char previous_child;
+ bool previous_child_single = false;
+ while (true)
+ {
+ group->add_childset();
+ ++c;
+ if (c[0] == '\0')
+ {
+ NREX_COMPILE_ERROR("unclosed bracket expression '['");
+ }
+ if (c[0] == '[' && c[1] == ':')
+ {
+ const nrex_char* d = &c[2];
+ nrex_class_type cls = nrex_parse_class(&d);
+ if (cls != nrex_class_none)
+ {
+ c = d;
+ group->add_child(NREX_NEW(nrex_node_class(cls)));
+ previous_child_single = false;
+ }
+ else
+ {
+ group->add_child(NREX_NEW(nrex_node_char('[')));
+ previous_child = '[';
+ previous_child_single = true;
+ }
+ }
+ else if (c[0] == ']' && !first_child)
+ {
+ break;
+ }
+ else if (c[0] == '\\')
+ {
+ if (nrex_is_shorthand(c[1]))
+ {
+ group->add_child(NREX_NEW(nrex_node_shorthand(c[1])));
+ ++c;
+ previous_child_single = false;
+ }
+ else
+ {
+ const nrex_char* d = c;
+ nrex_char unescaped = nrex_unescape(d);
+ if (c == d)
+ {
+ NREX_COMPILE_ERROR("invalid escape token");
+ }
+ group->add_child(NREX_NEW(nrex_node_char(unescaped)));
+ c = d;
+ previous_child = unescaped;
+ previous_child_single = true;
+ }
+ }
+ else if (previous_child_single && c[0] == '-')
+ {
+ bool is_range = false;
+ nrex_char next;
+ if (c[1] != '\0' && c[1] != ']')
+ {
+ if (c[1] == '\\')
+ {
+ const nrex_char* d = ++c;
+ next = nrex_unescape(d);
+ if (c == d)
+ {
+ NREX_COMPILE_ERROR("invalid escape token in range");
+ }
+ }
+ else
+ {
+ next = c[1];
+ ++c;
+ }
+ is_range = true;
+ }
+ if (is_range)
+ {
+ if (next < previous_child)
+ {
+ NREX_COMPILE_ERROR("text range out of order");
+ }
+ group->pop_back();
+ group->add_child(NREX_NEW(nrex_node_range(previous_child, next)));
+ previous_child_single = false;
+ }
+ else
+ {
+ group->add_child(NREX_NEW(nrex_node_char(c[0])));
+ previous_child = c[0];
+ previous_child_single = true;
+ }
+ }
+ else
+ {
+ group->add_child(NREX_NEW(nrex_node_char(c[0])));
+ previous_child = c[0];
+ previous_child_single = true;
+ }
+ first_child = false;
+ }
+ }
+ else if (nrex_is_quantifier(c[0]))
+ {
+ int min = 0;
+ int max = -1;
+ bool valid_quantifier = true;
+ if (c[0] == '?')
+ {
+ min = 0;
+ max = 1;
+ }
+ else if (c[0] == '+')
+ {
+ min = 1;
+ max = -1;
+ }
+ else if (c[0] == '*')
+ {
+ min = 0;
+ max = -1;
+ }
+ else if (c[0] == '{')
+ {
+ bool max_set = false;
+ const nrex_char* d = c;
+ while (true)
+ {
+ ++d;
+ if (d[0] == '\0')
+ {
+ valid_quantifier = false;
+ break;
+ }
+ else if (d[0] == '}')
+ {
+ break;
+ }
+ else if (d[0] == ',')
+ {
+ max_set = true;
+ continue;
+ }
+ else if (d[0] < '0' || '9' < d[0])
+ {
+ valid_quantifier = false;
+ break;
+ }
+ if (max_set)
+ {
+ if (max < 0)
+ {
+ max = int(d[0] - '0');
+ }
+ else
+ {
+ max = max * 10 + int(d[0] - '0');
+ }
+ }
+ else
+ {
+ min = min * 10 + int(d[0] - '0');
+ }
+ }
+ if (!max_set)
+ {
+ max = min;
+ }
+ if (valid_quantifier)
+ {
+ c = d;
+ }
+ }
+ if (valid_quantifier)
+ {
+ if (stack.top()->back == NULL || !stack.top()->back->quantifiable)
+ {
+ NREX_COMPILE_ERROR("element not quantifiable");
+ }
+ nrex_node_quantifier* quant = NREX_NEW(nrex_node_quantifier(min, max));
+ if (min == max)
+ {
+ if (stack.top()->back->length >= 0)
+ {
+ quant->length = max * stack.top()->back->length;
+ }
+ }
+ else
+ {
+ if (nrex_has_lookbehind(stack))
+ {
+ NREX_COMPILE_ERROR("variable length quantifiers inside lookbehind not supported");
+ }
+ }
+ quant->child = stack.top()->swap_back(quant);
+ quant->child->previous = NULL;
+ quant->child->next = NULL;
+ quant->child->parent = quant;
+ if (c[1] == '?')
+ {
+ quant->greedy = false;
+ ++c;
+ }
+ }
+ else
+ {
+ stack.top()->add_child(NREX_NEW(nrex_node_char(c[0])));
+ }
+ }
+ else if (c[0] == '|')
+ {
+ if (nrex_has_lookbehind(stack))
+ {
+ NREX_COMPILE_ERROR("alternations inside lookbehind not supported");
+ }
+ stack.top()->add_childset();
+ }
+ else if (c[0] == '^' || c[0] == '$')
+ {
+ stack.top()->add_child(NREX_NEW(nrex_node_anchor((c[0] == '$'))));
+ }
+ else if (c[0] == '.')
+ {
+ stack.top()->add_child(NREX_NEW(nrex_node_shorthand('.')));
+ }
+ else if (c[0] == '\\')
+ {
+ if (nrex_is_shorthand(c[1]))
+ {
+ stack.top()->add_child(NREX_NEW(nrex_node_shorthand(c[1])));
+ ++c;
+ }
+ else if (('1' <= c[1] && c[1] <= '9') || (c[1] == 'g' && c[2] == '{'))
+ {
+ int ref = 0;
+ bool unclosed = false;
+ if (c[1] == 'g')
+ {
+ unclosed = true;
+ c = &c[2];
+ }
+ while ('0' <= c[1] && c[1] <= '9')
+ {
+ ref = ref * 10 + int(c[1] - '0');
+ ++c;
+ }
+ if (c[1] == '}')
+ {
+ unclosed = false;
+ ++c;
+ }
+ if (ref > _capturing || ref <= 0 || unclosed)
+ {
+ NREX_COMPILE_ERROR("backreference to non-existent capture");
+ }
+ if (nrex_has_lookbehind(stack))
+ {
+ NREX_COMPILE_ERROR("backreferences inside lookbehind not supported");
+ }
+ stack.top()->add_child(NREX_NEW(nrex_node_backreference(ref)));
+ }
+ else if (c[1] == 'b' || c[1] == 'B')
+ {
+ stack.top()->add_child(NREX_NEW(nrex_node_word_boundary(c[1] == 'B')));
+ ++c;
+ }
+ else
+ {
+ const nrex_char* d = c;
+ nrex_char unescaped = nrex_unescape(d);
+ if (c == d)
+ {
+ NREX_COMPILE_ERROR("invalid escape token");
+ }
+ stack.top()->add_child(NREX_NEW(nrex_node_char(unescaped)));
+ c = d;
+ }
+ }
+ else
+ {
+ stack.top()->add_child(NREX_NEW(nrex_node_char(c[0])));
+ }
+ }
+ if (stack.size() > 1)
+ {
+ NREX_COMPILE_ERROR("unclosed group '('");
+ }
+ return true;
+}
+
+bool nrex::match(const nrex_char* str, nrex_result* captures, int offset, int end) const
+{
+ if (!_root)
+ {
+ return false;
+ }
+ nrex_search s(str, captures);
+ if (end >= offset)
+ {
+ s.end = end;
+ }
+ else
+ {
+ s.end = NREX_STRLEN(str);
+ }
+ for (int i = offset; i <= s.end; ++i)
+ {
+ for (int c = 0; c <= _capturing; ++c)
+ {
+ captures[c].start = 0;
+ captures[c].length = 0;
+ }
+ if (_root->test(&s, i) >= 0)
+ {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/drivers/nrex/nrex.hpp b/drivers/nrex/nrex.hpp
new file mode 100644
index 0000000000..44e950c517
--- /dev/null
+++ b/drivers/nrex/nrex.hpp
@@ -0,0 +1,175 @@
+// NREX: Node RegEx
+// Version 0.1
+//
+// Copyright (c) 2015, Zher Huei Lee
+// All rights reserved.
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+// claim that you wrote the original software. If you use this software
+// in a product, an acknowledgment in the product documentation would
+// be appreciated but is not required.
+//
+// 2. Altered source versions must be plainly marked as such, and must not
+// be misrepresented as being the original software.
+//
+// 3. This notice may not be removed or altered from any source
+// distribution.
+//
+
+#ifndef NREX_HPP
+#define NREX_HPP
+
+#include "nrex_config.h"
+
+#ifdef NREX_UNICODE
+typedef wchar_t nrex_char;
+#else
+typedef char nrex_char;
+#endif
+
+/*!
+ * \brief Struct to contain the range of a capture result
+ *
+ * The range provided is relative to the begining of the searched string.
+ *
+ * \see nrex_node::match()
+ */
+struct nrex_result
+{
+ public:
+ int start; /*!< Start of text range */
+ int length; /*!< Length of text range */
+};
+
+class nrex_node;
+
+/*!
+ * \brief Holds the compiled regex pattern
+ */
+class nrex
+{
+ private:
+ int _capturing;
+ nrex_node* _root;
+ public:
+
+ /*!
+ * \brief Initialises an empty regex container
+ */
+ nrex();
+
+ /*!
+ * \brief Initialises and compiles the regex pattern
+ *
+ * This calls nrex::compile() with the same arguments. To check whether
+ * the compilation was successfull, use nrex::valid().
+ *
+ * If the NREX_THROW_ERROR was defined it would automatically throw a
+ * runtime error nrex_compile_error if it encounters a problem when
+ * parsing the pattern.
+ *
+ * \param pattern The regex pattern
+ * \param captures The maximum number of capture groups to allow. Any
+ * extra would be converted to non-capturing groups.
+ * If negative, no limit would be imposed. Defaults
+ * to 9.
+ *
+ * \see nrex::compile()
+ */
+ nrex(const nrex_char* pattern, int captures = 9);
+
+ ~nrex();
+
+ /*!
+ * \brief Removes the compiled regex and frees up the memory
+ */
+ void reset();
+
+ /*!
+ * \brief Checks if there is a compiled regex being stored
+ * \return True if present, False if not present
+ */
+ bool valid() const;
+
+ /*!
+ * \brief Provides number of captures the compiled regex uses
+ *
+ * This is used to provide the array size of the captures needed for
+ * nrex::match() to work. The size is actually the number of capture
+ * groups + one for the matching of the entire pattern. This can be
+ * capped using the extra argument given in nrex::compile()
+ * (default 10).
+ *
+ * \return The number of captures
+ */
+ int capture_size() const;
+
+ /*!
+ * \brief Compiles the provided regex pattern
+ *
+ * This automatically removes the existing compiled regex if already
+ * present.
+ *
+ * If the NREX_THROW_ERROR was defined it would automatically throw a
+ * runtime error nrex_compile_error if it encounters a problem when
+ * parsing the pattern.
+ *
+ * \param pattern The regex pattern
+ * \param captures The maximum number of capture groups to allow. Any
+ * extra would be converted to non-capturing groups.
+ * If negative, no limit would be imposed. Defaults
+ * to 9.
+ * \return True if the pattern was succesfully compiled
+ */
+ bool compile(const nrex_char* pattern, int captures = 9);
+
+ /*!
+ * \brief Uses the pattern to search through the provided string
+ * \param str The text to search through. It only needs to be
+ * null terminated if the end point is not provided.
+ * This also determines the starting anchor.
+ * \param captures The array of results to store the capture results.
+ * The size of that array needs to be the same as the
+ * size given in nrex::capture_size(). As it matches
+ * the function fills the array with the results. 0 is
+ * the result for the entire pattern, 1 and above
+ * corresponds to the regex capture group if present.
+ * \param offset The starting point of the search. This does not move
+ * the starting anchor. Defaults to 0.
+ * \param end The end point of the search. This also determines
+ * the ending anchor. If a number less than the offset
+ * is provided, the search would be done until null
+ * termination. Defaults to -1.
+ * \return True if a match was found. False otherwise.
+ */
+ bool match(const nrex_char* str, nrex_result* captures, int offset = 0, int end = -1) const;
+};
+
+#ifdef NREX_THROW_ERROR
+
+#include <stdexcept>
+
+class nrex_compile_error : std::runtime_error
+{
+ public:
+ nrex_compile_error(const char* message)
+ : std::runtime_error(message)
+ {
+ }
+
+ ~nrex_compile_error() throw()
+ {
+ }
+};
+
+#endif
+
+#endif // NREX_HPP
diff --git a/drivers/nrex/nrex_config.h b/drivers/nrex/nrex_config.h
new file mode 100644
index 0000000000..540f34f8b4
--- /dev/null
+++ b/drivers/nrex/nrex_config.h
@@ -0,0 +1,12 @@
+// Godot-specific configuration
+// To use this, replace nrex_config.h
+
+#include "core/os/memory.h"
+
+#define NREX_UNICODE
+//#define NREX_THROW_ERROR
+
+#define NREX_NEW(X) memnew(X)
+#define NREX_NEW_ARRAY(X, N) memnew_arr(X, N)
+#define NREX_DELETE(X) memdelete(X)
+#define NREX_DELETE_ARRAY(X) memdelete_arr(X)
diff --git a/drivers/nrex/regex.cpp b/drivers/nrex/regex.cpp
new file mode 100644
index 0000000000..459cf28e1e
--- /dev/null
+++ b/drivers/nrex/regex.cpp
@@ -0,0 +1,116 @@
+/*************************************************/
+/* regex.cpp */
+/*************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/*************************************************/
+/* Source code within this file is: */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
+/* All Rights Reserved. */
+/*************************************************/
+
+#include "regex.h"
+#include "nrex.hpp"
+#include "core/os/memory.h"
+
+void RegEx::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("compile","pattern", "capture"),&RegEx::compile, DEFVAL(9));
+ ObjectTypeDB::bind_method(_MD("find","text","start","end"),&RegEx::find, DEFVAL(0), DEFVAL(-1));
+ ObjectTypeDB::bind_method(_MD("clear"),&RegEx::clear);
+ ObjectTypeDB::bind_method(_MD("is_valid"),&RegEx::is_valid);
+ ObjectTypeDB::bind_method(_MD("get_capture_count"),&RegEx::get_capture_count);
+ ObjectTypeDB::bind_method(_MD("get_capture","capture"),&RegEx::get_capture);
+ ObjectTypeDB::bind_method(_MD("get_captures"),&RegEx::_bind_get_captures);
+
+};
+
+StringArray RegEx::_bind_get_captures() const {
+
+ StringArray ret;
+ int count = get_capture_count();
+ for (int i=0; i<count; i++) {
+
+ String c = get_capture(i);
+ ret.push_back(c);
+ };
+
+ return ret;
+
+};
+
+void RegEx::clear() {
+
+ text.clear();
+ captures.clear();
+ exp.reset();
+
+};
+
+bool RegEx::is_valid() const {
+
+ return exp.valid();
+
+};
+
+int RegEx::get_capture_count() const {
+
+ ERR_FAIL_COND_V( !exp.valid(), 0 );
+
+ return exp.capture_size();
+}
+
+String RegEx::get_capture(int capture) const {
+
+ ERR_FAIL_COND_V( get_capture_count() <= capture, String() );
+
+ return text.substr(captures[capture].start, captures[capture].length);
+
+}
+
+Error RegEx::compile(const String& p_pattern, int capture) {
+
+ clear();
+
+ exp.compile(p_pattern.c_str(), capture);
+
+ ERR_FAIL_COND_V( !exp.valid(), FAILED );
+
+ captures.resize(exp.capture_size());
+
+ return OK;
+
+};
+
+int RegEx::find(const String& p_text, int p_start, int p_end) const {
+
+ ERR_FAIL_COND_V( !exp.valid(), -1 );
+ ERR_FAIL_COND_V( p_text.length() < p_start, -1 );
+ ERR_FAIL_COND_V( p_text.length() < p_end, -1 );
+
+ bool res = exp.match(p_text.c_str(), &captures[0], p_start, p_end);
+
+ if (res) {
+ text = p_text;
+ return captures[0].start;
+ }
+ text.clear();
+ return -1;
+
+};
+
+RegEx::RegEx(const String& p_pattern) {
+
+ compile(p_pattern);
+
+};
+
+RegEx::RegEx() {
+
+};
+
+RegEx::~RegEx() {
+
+ clear();
+
+};
diff --git a/drivers/nrex/regex.h b/drivers/nrex/regex.h
new file mode 100644
index 0000000000..ae8d40ceab
--- /dev/null
+++ b/drivers/nrex/regex.h
@@ -0,0 +1,47 @@
+/*************************************************/
+/* regex.h */
+/*************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/*************************************************/
+/* Source code within this file is: */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
+/* All Rights Reserved. */
+/*************************************************/
+
+#ifndef REGEX_H
+#define REGEX_H
+
+#include "ustring.h"
+#include "vector.h"
+#include "core/reference.h"
+#include "nrex.hpp"
+
+class RegEx : public Reference {
+
+ OBJ_TYPE(RegEx, Reference);
+
+ mutable String text;
+ mutable Vector<nrex_result> captures;
+ nrex exp;
+
+protected:
+
+ static void _bind_methods();
+ StringArray _bind_get_captures() const;
+
+public:
+
+ void clear();
+ bool is_valid() const;
+ int get_capture_count() const;
+ String get_capture(int capture) const;
+ Error compile(const String& p_pattern, int capture = 9);
+ int find(const String& p_text, int p_start = 0, int p_end = -1) const;
+
+ RegEx();
+ RegEx(const String& p_pattern);
+ ~RegEx();
+};
+
+#endif // REGEX_H
diff --git a/drivers/ogg/SCsub b/drivers/ogg/SCsub
index dd59890064..3ee1bb6408 100644
--- a/drivers/ogg/SCsub
+++ b/drivers/ogg/SCsub
@@ -6,6 +6,4 @@ ogg_sources = [
"ogg/framing.c",
]
-if env['theora'] != "yes" or env['use_theoraplayer_binary'] != "yes":
- env.drivers_sources+=ogg_sources
-
+env.drivers_sources+=ogg_sources
diff --git a/drivers/openssl/SCsub b/drivers/openssl/SCsub
index 7197364e01..6d3e7e6732 100644
--- a/drivers/openssl/SCsub
+++ b/drivers/openssl/SCsub
@@ -4,5 +4,3 @@ env.add_source_files(env.drivers_sources,"*.cpp")
env.add_source_files(env.drivers_sources,"*.c")
Export('env')
-
-
diff --git a/drivers/openssl/register_openssl.cpp b/drivers/openssl/register_openssl.cpp
index a4a60813b6..ed2150bef5 100644
--- a/drivers/openssl/register_openssl.cpp
+++ b/drivers/openssl/register_openssl.cpp
@@ -1,19 +1,19 @@
-#include "register_openssl.h"
-
-#include "stream_peer_openssl.h"
-#ifdef OPENSSL_ENABLED
-
-void register_openssl() {
-
- ObjectTypeDB::register_type<StreamPeerOpenSSL>();
- StreamPeerOpenSSL::initialize_ssl();
-
-}
-
-void unregister_openssl() {
-
- StreamPeerOpenSSL::finalize_ssl();
-
-}
-#endif
-
+#include "register_openssl.h"
+
+#include "stream_peer_openssl.h"
+#ifdef OPENSSL_ENABLED
+
+void register_openssl() {
+
+ ObjectTypeDB::register_type<StreamPeerOpenSSL>();
+ StreamPeerOpenSSL::initialize_ssl();
+
+}
+
+void unregister_openssl() {
+
+ StreamPeerOpenSSL::finalize_ssl();
+
+}
+#endif
+
diff --git a/drivers/openssl/register_openssl.h b/drivers/openssl/register_openssl.h
index e1c554ca4a..e547a2b750 100644
--- a/drivers/openssl/register_openssl.h
+++ b/drivers/openssl/register_openssl.h
@@ -1,11 +1,11 @@
-#ifndef REGISTER_OPENSSL_H
-#define REGISTER_OPENSSL_H
-
-#ifdef OPENSSL_ENABLED
-
-void register_openssl();
-void unregister_openssl();
-
-#endif
-
-#endif // REGISTER_OPENSSL_H
+#ifndef REGISTER_OPENSSL_H
+#define REGISTER_OPENSSL_H
+
+#ifdef OPENSSL_ENABLED
+
+void register_openssl();
+void unregister_openssl();
+
+#endif
+
+#endif // REGISTER_OPENSSL_H
diff --git a/drivers/openssl/stream_peer_openssl.cpp b/drivers/openssl/stream_peer_openssl.cpp
index ef07f11334..81795fdc60 100644
--- a/drivers/openssl/stream_peer_openssl.cpp
+++ b/drivers/openssl/stream_peer_openssl.cpp
@@ -479,6 +479,13 @@ Error StreamPeerOpenSSL::get_partial_data(uint8_t* p_buffer, int p_bytes,int &r_
return OK;
}
+int StreamPeerOpenSSL::get_available_bytes() const {
+
+ ERR_FAIL_COND_V(!connected,0);
+
+ return SSL_pending(ssl);
+
+}
StreamPeerOpenSSL::StreamPeerOpenSSL() {
ctx=NULL;
diff --git a/drivers/openssl/stream_peer_openssl.h b/drivers/openssl/stream_peer_openssl.h
index a66b641dd4..64f5a1d7ac 100644
--- a/drivers/openssl/stream_peer_openssl.h
+++ b/drivers/openssl/stream_peer_openssl.h
@@ -71,6 +71,8 @@ public:
virtual Error get_data(uint8_t* p_buffer, int p_bytes);
virtual Error get_partial_data(uint8_t* p_buffer, int p_bytes,int &r_received);
+ virtual int get_available_bytes() const;
+
static void initialize_ssl();
static void finalize_ssl();
diff --git a/drivers/opus/SCsub b/drivers/opus/SCsub
new file mode 100644
index 0000000000..59c746209b
--- /dev/null
+++ b/drivers/opus/SCsub
@@ -0,0 +1,195 @@
+Import('env')
+
+opus_sources = [
+ "opus/audio_stream_opus.cpp",
+]
+
+opus_sources_silk=[]
+
+opus_sources_lib = [
+ "opus/celt/bands.c",
+ "opus/celt/celt_lpc.c",
+ "opus/celt/entenc.c",
+ "opus/celt/mdct.c",
+ "opus/celt/quant_bands.c",
+ "opus/celt/celt.c",
+ "opus/celt/cwrs.c",
+ "opus/celt/kiss_fft.c",
+ "opus/celt/modes.c",
+ "opus/celt/rate.c",
+ "opus/celt/celt_decoder.c",
+ "opus/celt/entcode.c",
+ "opus/celt/laplace.c",
+ #opus/celt/opus_custom_demo.c",
+ "opus/celt/vq.c",
+ "opus/celt/celt_encoder.c",
+ "opus/celt/entdec.c",
+ "opus/celt/mathops.c",
+ "opus/celt/pitch.c",
+ "opus/silk/A2NLSF.c",
+ "opus/silk/decoder_set_fs.c",
+ "opus/silk/NLSF_stabilize.c",
+ "opus/silk/sigm_Q15.c",
+ "opus/silk/ana_filt_bank_1.c",
+ "opus/silk/enc_API.c",
+ "opus/silk/NLSF_unpack.c",
+ "opus/silk/sort.c",
+ "opus/silk/biquad_alt.c",
+ "opus/silk/encode_indices.c",
+ "opus/silk/NLSF_VQ.c",
+ "opus/silk/stereo_decode_pred.c",
+ "opus/silk/bwexpander_32.c",
+ "opus/silk/encode_pulses.c",
+ "opus/silk/NLSF_VQ_weights_laroia.c",
+ "opus/silk/stereo_encode_pred.c",
+ "opus/silk/bwexpander.c",
+ "opus/silk/gain_quant.c",
+ "opus/silk/NSQ.c",
+ "opus/silk/stereo_find_predictor.c",
+ "opus/silk/check_control_input.c",
+ "opus/silk/HP_variable_cutoff.c",
+ "opus/silk/NSQ_del_dec.c",
+ "opus/silk/stereo_LR_to_MS.c",
+ "opus/silk/CNG.c",
+ "opus/silk/init_decoder.c",
+ "opus/silk/pitch_est_tables.c",
+ "opus/silk/stereo_MS_to_LR.c",
+ "opus/silk/code_signs.c",
+ "opus/silk/init_encoder.c",
+ "opus/silk/PLC.c",
+ "opus/silk/stereo_quant_pred.c",
+ "opus/silk/control_audio_bandwidth.c",
+ "opus/silk/inner_prod_aligned.c",
+ "opus/silk/process_NLSFs.c",
+ "opus/silk/sum_sqr_shift.c",
+ "opus/silk/control_codec.c",
+ "opus/silk/interpolate.c",
+ "opus/silk/quant_LTP_gains.c",
+ "opus/silk/table_LSF_cos.c",
+ "opus/silk/control_SNR.c",
+ "opus/silk/lin2log.c",
+ "opus/silk/resampler.c",
+ "opus/silk/tables_gain.c",
+ "opus/silk/debug.c",
+ "opus/silk/log2lin.c",
+ "opus/silk/resampler_down2_3.c",
+ "opus/silk/tables_LTP.c",
+ "opus/silk/dec_API.c",
+ "opus/silk/LPC_analysis_filter.c",
+ "opus/silk/resampler_down2.c",
+ "opus/silk/tables_NLSF_CB_NB_MB.c",
+ "opus/silk/decode_core.c",
+ "opus/silk/LPC_inv_pred_gain.c",
+ "opus/silk/resampler_private_AR2.c",
+ "opus/silk/tables_NLSF_CB_WB.c",
+ "opus/silk/decode_frame.c",
+ "opus/silk/LP_variable_cutoff.c",
+ "opus/silk/resampler_private_down_FIR.c",
+ "opus/silk/tables_other.c",
+ "opus/silk/decode_indices.c",
+ "opus/silk/NLSF2A.c",
+ "opus/silk/resampler_private_IIR_FIR.c",
+ "opus/silk/tables_pitch_lag.c",
+ "opus/silk/decode_parameters.c",
+ "opus/silk/NLSF_decode.c",
+ "opus/silk/resampler_private_up2_HQ.c",
+ "opus/silk/tables_pulses_per_block.c",
+ "opus/silk/decode_pitch.c",
+ "opus/silk/NLSF_del_dec_quant.c",
+ "opus/silk/resampler_rom.c",
+ "opus/silk/VAD.c",
+ "opus/silk/decode_pulses.c",
+ "opus/silk/NLSF_encode.c",
+ "opus/silk/shell_coder.c",
+ "opus/silk/VQ_WMat_EC.c",
+ "opus/analysis.c",
+ "opus/internal.c",
+ "opus/opus.c",
+ #"opus/opus_demo.c",
+ "opus/opus_multistream.c",
+ "opus/repacketizer.c",
+ "opus/wincerts.c",
+ "opus/http.c",
+ "opus/mlp.c",
+ #"opus/opus_compare.c",
+ "opus/opus_encoder.c",
+ "opus/opus_multistream_decoder.c",
+ #"opus/repacketizer_demo.c",
+ "opus/info.c",
+ "opus/mlp_data.c",
+ "opus/opus_decoder.c",
+ "opus/opusfile.c",
+ "opus/opus_multistream_encoder.c",
+ "opus/stream.c"
+]
+
+if("opus_fixed_point" in env and env.opus_fixed_point=="yes"):
+ env.Append(CFLAGS=["-DOPUS_FIXED_POINT"])
+ opus_sources_silk = [
+ "opus/silk/fixed/apply_sine_window_FIX.c",
+ "opus/silk/fixed/k2a_FIX.c",
+ "opus/silk/fixed/residual_energy16_FIX.c",
+ "opus/silk/fixed/autocorr_FIX.c",
+ "opus/silk/fixed/k2a_Q16_FIX.c",
+ "opus/silk/fixed/residual_energy_FIX.c",
+ "opus/silk/fixed/burg_modified_FIX.c",
+ "opus/silk/fixed/LTP_analysis_filter_FIX.c",
+ "opus/silk/fixed/schur64_FIX.c",
+ "opus/silk/fixed/corrMatrix_FIX.c",
+ "opus/silk/fixed/LTP_scale_ctrl_FIX.c",
+ "opus/silk/fixed/schur_FIX.c",
+ "opus/silk/fixed/encode_frame_FIX.c",
+ "opus/silk/fixed/noise_shape_analysis_FIX.c",
+ "opus/silk/fixed/solve_LS_FIX.c",
+ "opus/silk/fixed/find_LPC_FIX.c",
+ "opus/silk/fixed/pitch_analysis_core_FIX.c",
+ "opus/silk/fixed/vector_ops_FIX.c",
+ "opus/silk/fixed/find_LTP_FIX.c",
+ "opus/silk/fixed/prefilter_FIX.c",
+ "opus/silk/fixed/warped_autocorrelation_FIX.c",
+ "opus/silk/fixed/find_pitch_lags_FIX.c",
+ "opus/silk/fixed/process_gains_FIX.c",
+ "opus/silk/fixed/find_pred_coefs_FIX.c",
+ "opus/silk/fixed/regularize_correlations_FIX.c"
+ ]
+else:
+ opus_sources_silk = [
+ "opus/silk/float/apply_sine_window_FLP.c",
+ "opus/silk/float/inner_product_FLP.c",
+ "opus/silk/float/regularize_correlations_FLP.c",
+ "opus/silk/float/autocorrelation_FLP.c",
+ "opus/silk/float/k2a_FLP.c",
+ "opus/silk/float/residual_energy_FLP.c",
+ "opus/silk/float/burg_modified_FLP.c",
+ "opus/silk/float/levinsondurbin_FLP.c",
+ "opus/silk/float/scale_copy_vector_FLP.c",
+ "opus/silk/float/bwexpander_FLP.c",
+ "opus/silk/float/LPC_analysis_filter_FLP.c",
+ "opus/silk/float/scale_vector_FLP.c",
+ "opus/silk/float/corrMatrix_FLP.c",
+ "opus/silk/float/LPC_inv_pred_gain_FLP.c",
+ "opus/silk/float/schur_FLP.c",
+ "opus/silk/float/encode_frame_FLP.c",
+ "opus/silk/float/LTP_analysis_filter_FLP.c",
+ "opus/silk/float/solve_LS_FLP.c",
+ "opus/silk/float/energy_FLP.c",
+ "opus/silk/float/LTP_scale_ctrl_FLP.c",
+ "opus/silk/float/sort_FLP.c",
+ "opus/silk/float/find_LPC_FLP.c",
+ "opus/silk/float/noise_shape_analysis_FLP.c",
+ "opus/silk/float/warped_autocorrelation_FLP.c",
+ "opus/silk/float/find_LTP_FLP.c",
+ "opus/silk/float/pitch_analysis_core_FLP.c",
+ "opus/silk/float/wrappers_FLP.c",
+ "opus/silk/float/find_pitch_lags_FLP.c",
+ "opus/silk/float/prefilter_FLP.c",
+ "opus/silk/float/find_pred_coefs_FLP.c",
+ "opus/silk/float/process_gains_FLP.c"
+ ]
+
+
+opus_sources_lib+=opus_sources_silk
+env.drivers_sources+=opus_sources_lib
+env.drivers_sources+=opus_sources
+
+Export('env')
diff --git a/drivers/opus/analysis.c b/drivers/opus/analysis.c
new file mode 100644
index 0000000000..e27e948178
--- /dev/null
+++ b/drivers/opus/analysis.c
@@ -0,0 +1,645 @@
+/* Copyright (c) 2011 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/celt/kiss_fft.h"
+#include "opus/celt/celt.h"
+#include "opus/celt/opus_modes.h"
+#include "opus/celt/arch.h"
+#include "opus/celt/quant_bands.h"
+#include <stdio.h>
+#include "opus/analysis.h"
+#include "opus/mlp.h"
+#include "opus/celt/stack_alloc.h"
+
+extern const MLP net;
+
+#ifndef M_PI
+#define M_PI 3.141592653
+#endif
+
+static const float dct_table[128] = {
+ 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f,
+ 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f,
+ 0.351851f, 0.338330f, 0.311806f, 0.273300f, 0.224292f, 0.166664f, 0.102631f, 0.034654f,
+ -0.034654f,-0.102631f,-0.166664f,-0.224292f,-0.273300f,-0.311806f,-0.338330f,-0.351851f,
+ 0.346760f, 0.293969f, 0.196424f, 0.068975f,-0.068975f,-0.196424f,-0.293969f,-0.346760f,
+ -0.346760f,-0.293969f,-0.196424f,-0.068975f, 0.068975f, 0.196424f, 0.293969f, 0.346760f,
+ 0.338330f, 0.224292f, 0.034654f,-0.166664f,-0.311806f,-0.351851f,-0.273300f,-0.102631f,
+ 0.102631f, 0.273300f, 0.351851f, 0.311806f, 0.166664f,-0.034654f,-0.224292f,-0.338330f,
+ 0.326641f, 0.135299f,-0.135299f,-0.326641f,-0.326641f,-0.135299f, 0.135299f, 0.326641f,
+ 0.326641f, 0.135299f,-0.135299f,-0.326641f,-0.326641f,-0.135299f, 0.135299f, 0.326641f,
+ 0.311806f, 0.034654f,-0.273300f,-0.338330f,-0.102631f, 0.224292f, 0.351851f, 0.166664f,
+ -0.166664f,-0.351851f,-0.224292f, 0.102631f, 0.338330f, 0.273300f,-0.034654f,-0.311806f,
+ 0.293969f,-0.068975f,-0.346760f,-0.196424f, 0.196424f, 0.346760f, 0.068975f,-0.293969f,
+ -0.293969f, 0.068975f, 0.346760f, 0.196424f,-0.196424f,-0.346760f,-0.068975f, 0.293969f,
+ 0.273300f,-0.166664f,-0.338330f, 0.034654f, 0.351851f, 0.102631f,-0.311806f,-0.224292f,
+ 0.224292f, 0.311806f,-0.102631f,-0.351851f,-0.034654f, 0.338330f, 0.166664f,-0.273300f,
+};
+
+static const float analysis_window[240] = {
+ 0.000043f, 0.000171f, 0.000385f, 0.000685f, 0.001071f, 0.001541f, 0.002098f, 0.002739f,
+ 0.003466f, 0.004278f, 0.005174f, 0.006156f, 0.007222f, 0.008373f, 0.009607f, 0.010926f,
+ 0.012329f, 0.013815f, 0.015385f, 0.017037f, 0.018772f, 0.020590f, 0.022490f, 0.024472f,
+ 0.026535f, 0.028679f, 0.030904f, 0.033210f, 0.035595f, 0.038060f, 0.040604f, 0.043227f,
+ 0.045928f, 0.048707f, 0.051564f, 0.054497f, 0.057506f, 0.060591f, 0.063752f, 0.066987f,
+ 0.070297f, 0.073680f, 0.077136f, 0.080665f, 0.084265f, 0.087937f, 0.091679f, 0.095492f,
+ 0.099373f, 0.103323f, 0.107342f, 0.111427f, 0.115579f, 0.119797f, 0.124080f, 0.128428f,
+ 0.132839f, 0.137313f, 0.141849f, 0.146447f, 0.151105f, 0.155823f, 0.160600f, 0.165435f,
+ 0.170327f, 0.175276f, 0.180280f, 0.185340f, 0.190453f, 0.195619f, 0.200838f, 0.206107f,
+ 0.211427f, 0.216797f, 0.222215f, 0.227680f, 0.233193f, 0.238751f, 0.244353f, 0.250000f,
+ 0.255689f, 0.261421f, 0.267193f, 0.273005f, 0.278856f, 0.284744f, 0.290670f, 0.296632f,
+ 0.302628f, 0.308658f, 0.314721f, 0.320816f, 0.326941f, 0.333097f, 0.339280f, 0.345492f,
+ 0.351729f, 0.357992f, 0.364280f, 0.370590f, 0.376923f, 0.383277f, 0.389651f, 0.396044f,
+ 0.402455f, 0.408882f, 0.415325f, 0.421783f, 0.428254f, 0.434737f, 0.441231f, 0.447736f,
+ 0.454249f, 0.460770f, 0.467298f, 0.473832f, 0.480370f, 0.486912f, 0.493455f, 0.500000f,
+ 0.506545f, 0.513088f, 0.519630f, 0.526168f, 0.532702f, 0.539230f, 0.545751f, 0.552264f,
+ 0.558769f, 0.565263f, 0.571746f, 0.578217f, 0.584675f, 0.591118f, 0.597545f, 0.603956f,
+ 0.610349f, 0.616723f, 0.623077f, 0.629410f, 0.635720f, 0.642008f, 0.648271f, 0.654508f,
+ 0.660720f, 0.666903f, 0.673059f, 0.679184f, 0.685279f, 0.691342f, 0.697372f, 0.703368f,
+ 0.709330f, 0.715256f, 0.721144f, 0.726995f, 0.732807f, 0.738579f, 0.744311f, 0.750000f,
+ 0.755647f, 0.761249f, 0.766807f, 0.772320f, 0.777785f, 0.783203f, 0.788573f, 0.793893f,
+ 0.799162f, 0.804381f, 0.809547f, 0.814660f, 0.819720f, 0.824724f, 0.829673f, 0.834565f,
+ 0.839400f, 0.844177f, 0.848895f, 0.853553f, 0.858151f, 0.862687f, 0.867161f, 0.871572f,
+ 0.875920f, 0.880203f, 0.884421f, 0.888573f, 0.892658f, 0.896677f, 0.900627f, 0.904508f,
+ 0.908321f, 0.912063f, 0.915735f, 0.919335f, 0.922864f, 0.926320f, 0.929703f, 0.933013f,
+ 0.936248f, 0.939409f, 0.942494f, 0.945503f, 0.948436f, 0.951293f, 0.954072f, 0.956773f,
+ 0.959396f, 0.961940f, 0.964405f, 0.966790f, 0.969096f, 0.971321f, 0.973465f, 0.975528f,
+ 0.977510f, 0.979410f, 0.981228f, 0.982963f, 0.984615f, 0.986185f, 0.987671f, 0.989074f,
+ 0.990393f, 0.991627f, 0.992778f, 0.993844f, 0.994826f, 0.995722f, 0.996534f, 0.997261f,
+ 0.997902f, 0.998459f, 0.998929f, 0.999315f, 0.999615f, 0.999829f, 0.999957f, 1.000000f,
+};
+
+static const int tbands[NB_TBANDS+1] = {
+ 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 68, 80, 96, 120
+};
+
+static const int extra_bands[NB_TOT_BANDS+1] = {
+ 1, 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 68, 80, 96, 120, 160, 200
+};
+
+/*static const float tweight[NB_TBANDS+1] = {
+ .3, .4, .5, .6, .7, .8, .9, 1., 1., 1., 1., 1., 1., 1., .8, .7, .6, .5
+};*/
+
+#define NB_TONAL_SKIP_BANDS 9
+
+#define cA 0.43157974f
+#define cB 0.67848403f
+#define cC 0.08595542f
+#define cE ((float)M_PI/2)
+static OPUS_INLINE float fast_atan2f(float y, float x) {
+ float x2, y2;
+ /* Should avoid underflow on the values we'll get */
+ if (ABS16(x)+ABS16(y)<1e-9f)
+ {
+ x*=1e12f;
+ y*=1e12f;
+ }
+ x2 = x*x;
+ y2 = y*y;
+ if(x2<y2){
+ float den = (y2 + cB*x2) * (y2 + cC*x2);
+ if (den!=0)
+ return -x*y*(y2 + cA*x2) / den + (y<0 ? -cE : cE);
+ else
+ return (y<0 ? -cE : cE);
+ }else{
+ float den = (x2 + cB*y2) * (x2 + cC*y2);
+ if (den!=0)
+ return x*y*(x2 + cA*y2) / den + (y<0 ? -cE : cE) - (x*y<0 ? -cE : cE);
+ else
+ return (y<0 ? -cE : cE) - (x*y<0 ? -cE : cE);
+ }
+}
+
+void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int len)
+{
+ int pos;
+ int curr_lookahead;
+ float psum;
+ int i;
+
+ pos = tonal->read_pos;
+ curr_lookahead = tonal->write_pos-tonal->read_pos;
+ if (curr_lookahead<0)
+ curr_lookahead += DETECT_SIZE;
+
+ if (len > 480 && pos != tonal->write_pos)
+ {
+ pos++;
+ if (pos==DETECT_SIZE)
+ pos=0;
+ }
+ if (pos == tonal->write_pos)
+ pos--;
+ if (pos<0)
+ pos = DETECT_SIZE-1;
+ OPUS_COPY(info_out, &tonal->info[pos], 1);
+ tonal->read_subframe += len/120;
+ while (tonal->read_subframe>=4)
+ {
+ tonal->read_subframe -= 4;
+ tonal->read_pos++;
+ }
+ if (tonal->read_pos>=DETECT_SIZE)
+ tonal->read_pos-=DETECT_SIZE;
+
+ /* Compensate for the delay in the features themselves.
+ FIXME: Need a better estimate the 10 I just made up */
+ curr_lookahead = IMAX(curr_lookahead-10, 0);
+
+ psum=0;
+ /* Summing the probability of transition patterns that involve music at
+ time (DETECT_SIZE-curr_lookahead-1) */
+ for (i=0;i<DETECT_SIZE-curr_lookahead;i++)
+ psum += tonal->pmusic[i];
+ for (;i<DETECT_SIZE;i++)
+ psum += tonal->pspeech[i];
+ psum = psum*tonal->music_confidence + (1-psum)*tonal->speech_confidence;
+ /*printf("%f %f %f\n", psum, info_out->music_prob, info_out->tonality);*/
+
+ info_out->music_prob = psum;
+}
+
+void tonality_analysis(TonalityAnalysisState *tonal, AnalysisInfo *info_out, const CELTMode *celt_mode, const void *x, int len, int offset, int c1, int c2, int C, int lsb_depth, downmix_func downmix)
+{
+ int i, b;
+ const kiss_fft_state *kfft;
+ VARDECL(kiss_fft_cpx, in);
+ VARDECL(kiss_fft_cpx, out);
+ int N = 480, N2=240;
+ float * OPUS_RESTRICT A = tonal->angle;
+ float * OPUS_RESTRICT dA = tonal->d_angle;
+ float * OPUS_RESTRICT d2A = tonal->d2_angle;
+ VARDECL(float, tonality);
+ VARDECL(float, noisiness);
+ float band_tonality[NB_TBANDS];
+ float logE[NB_TBANDS];
+ float BFCC[8];
+ float features[25];
+ float frame_tonality;
+ float max_frame_tonality;
+ /*float tw_sum=0;*/
+ float frame_noisiness;
+ const float pi4 = (float)(M_PI*M_PI*M_PI*M_PI);
+ float slope=0;
+ float frame_stationarity;
+ float relativeE;
+ float frame_probs[2];
+ float alpha, alphaE, alphaE2;
+ float frame_loudness;
+ float bandwidth_mask;
+ int bandwidth=0;
+ float maxE = 0;
+ float noise_floor;
+ int remaining;
+ AnalysisInfo *info;
+ SAVE_STACK;
+
+ tonal->last_transition++;
+ alpha = 1.f/IMIN(20, 1+tonal->count);
+ alphaE = 1.f/IMIN(50, 1+tonal->count);
+ alphaE2 = 1.f/IMIN(1000, 1+tonal->count);
+
+ if (tonal->count<4)
+ tonal->music_prob = .5;
+ kfft = celt_mode->mdct.kfft[0];
+ if (tonal->count==0)
+ tonal->mem_fill = 240;
+ downmix(x, &tonal->inmem[tonal->mem_fill], IMIN(len, ANALYSIS_BUF_SIZE-tonal->mem_fill), offset, c1, c2, C);
+ if (tonal->mem_fill+len < ANALYSIS_BUF_SIZE)
+ {
+ tonal->mem_fill += len;
+ /* Don't have enough to update the analysis */
+ RESTORE_STACK;
+ return;
+ }
+ info = &tonal->info[tonal->write_pos++];
+ if (tonal->write_pos>=DETECT_SIZE)
+ tonal->write_pos-=DETECT_SIZE;
+
+ ALLOC(in, 480, kiss_fft_cpx);
+ ALLOC(out, 480, kiss_fft_cpx);
+ ALLOC(tonality, 240, float);
+ ALLOC(noisiness, 240, float);
+ for (i=0;i<N2;i++)
+ {
+ float w = analysis_window[i];
+ in[i].r = (kiss_fft_scalar)(w*tonal->inmem[i]);
+ in[i].i = (kiss_fft_scalar)(w*tonal->inmem[N2+i]);
+ in[N-i-1].r = (kiss_fft_scalar)(w*tonal->inmem[N-i-1]);
+ in[N-i-1].i = (kiss_fft_scalar)(w*tonal->inmem[N+N2-i-1]);
+ }
+ OPUS_MOVE(tonal->inmem, tonal->inmem+ANALYSIS_BUF_SIZE-240, 240);
+ remaining = len - (ANALYSIS_BUF_SIZE-tonal->mem_fill);
+ downmix(x, &tonal->inmem[240], remaining, offset+ANALYSIS_BUF_SIZE-tonal->mem_fill, c1, c2, C);
+ tonal->mem_fill = 240 + remaining;
+ opus_fft(kfft, in, out);
+
+ for (i=1;i<N2;i++)
+ {
+ float X1r, X2r, X1i, X2i;
+ float angle, d_angle, d2_angle;
+ float angle2, d_angle2, d2_angle2;
+ float mod1, mod2, avg_mod;
+ X1r = (float)out[i].r+out[N-i].r;
+ X1i = (float)out[i].i-out[N-i].i;
+ X2r = (float)out[i].i+out[N-i].i;
+ X2i = (float)out[N-i].r-out[i].r;
+
+ angle = (float)(.5f/M_PI)*fast_atan2f(X1i, X1r);
+ d_angle = angle - A[i];
+ d2_angle = d_angle - dA[i];
+
+ angle2 = (float)(.5f/M_PI)*fast_atan2f(X2i, X2r);
+ d_angle2 = angle2 - angle;
+ d2_angle2 = d_angle2 - d_angle;
+
+ mod1 = d2_angle - (float)floor(.5+d2_angle);
+ noisiness[i] = ABS16(mod1);
+ mod1 *= mod1;
+ mod1 *= mod1;
+
+ mod2 = d2_angle2 - (float)floor(.5+d2_angle2);
+ noisiness[i] += ABS16(mod2);
+ mod2 *= mod2;
+ mod2 *= mod2;
+
+ avg_mod = .25f*(d2A[i]+2.f*mod1+mod2);
+ tonality[i] = 1.f/(1.f+40.f*16.f*pi4*avg_mod)-.015f;
+
+ A[i] = angle2;
+ dA[i] = d_angle2;
+ d2A[i] = mod2;
+ }
+
+ frame_tonality = 0;
+ max_frame_tonality = 0;
+ /*tw_sum = 0;*/
+ info->activity = 0;
+ frame_noisiness = 0;
+ frame_stationarity = 0;
+ if (!tonal->count)
+ {
+ for (b=0;b<NB_TBANDS;b++)
+ {
+ tonal->lowE[b] = 1e10;
+ tonal->highE[b] = -1e10;
+ }
+ }
+ relativeE = 0;
+ frame_loudness = 0;
+ for (b=0;b<NB_TBANDS;b++)
+ {
+ float E=0, tE=0, nE=0;
+ float L1, L2;
+ float stationarity;
+ for (i=tbands[b];i<tbands[b+1];i++)
+ {
+ float binE = out[i].r*(float)out[i].r + out[N-i].r*(float)out[N-i].r
+ + out[i].i*(float)out[i].i + out[N-i].i*(float)out[N-i].i;
+#ifdef OPUS_FIXED_POINT
+ /* FIXME: It's probably best to change the BFCC filter initial state instead */
+ binE *= 5.55e-17f;
+#endif
+ E += binE;
+ tE += binE*tonality[i];
+ nE += binE*2.f*(.5f-noisiness[i]);
+ }
+ tonal->E[tonal->E_count][b] = E;
+ frame_noisiness += nE/(1e-15f+E);
+
+ frame_loudness += (float)sqrt(E+1e-10f);
+ logE[b] = (float)log(E+1e-10f);
+ tonal->lowE[b] = MIN32(logE[b], tonal->lowE[b]+.01f);
+ tonal->highE[b] = MAX32(logE[b], tonal->highE[b]-.1f);
+ if (tonal->highE[b] < tonal->lowE[b]+1.f)
+ {
+ tonal->highE[b]+=.5f;
+ tonal->lowE[b]-=.5f;
+ }
+ relativeE += (logE[b]-tonal->lowE[b])/(1e-15f+tonal->highE[b]-tonal->lowE[b]);
+
+ L1=L2=0;
+ for (i=0;i<NB_FRAMES;i++)
+ {
+ L1 += (float)sqrt(tonal->E[i][b]);
+ L2 += tonal->E[i][b];
+ }
+
+ stationarity = MIN16(0.99f,L1/(float)sqrt(1e-15+NB_FRAMES*L2));
+ stationarity *= stationarity;
+ stationarity *= stationarity;
+ frame_stationarity += stationarity;
+ /*band_tonality[b] = tE/(1e-15+E)*/;
+ band_tonality[b] = MAX16(tE/(1e-15f+E), stationarity*tonal->prev_band_tonality[b]);
+#if 0
+ if (b>=NB_TONAL_SKIP_BANDS)
+ {
+ frame_tonality += tweight[b]*band_tonality[b];
+ tw_sum += tweight[b];
+ }
+#else
+ frame_tonality += band_tonality[b];
+ if (b>=NB_TBANDS-NB_TONAL_SKIP_BANDS)
+ frame_tonality -= band_tonality[b-NB_TBANDS+NB_TONAL_SKIP_BANDS];
+#endif
+ max_frame_tonality = MAX16(max_frame_tonality, (1.f+.03f*(b-NB_TBANDS))*frame_tonality);
+ slope += band_tonality[b]*(b-8);
+ /*printf("%f %f ", band_tonality[b], stationarity);*/
+ tonal->prev_band_tonality[b] = band_tonality[b];
+ }
+
+ bandwidth_mask = 0;
+ bandwidth = 0;
+ maxE = 0;
+ noise_floor = 5.7e-4f/(1<<(IMAX(0,lsb_depth-8)));
+#ifdef OPUS_FIXED_POINT
+ noise_floor *= 1<<(15+SIG_SHIFT);
+#endif
+ noise_floor *= noise_floor;
+ for (b=0;b<NB_TOT_BANDS;b++)
+ {
+ float E=0;
+ int band_start, band_end;
+ /* Keep a margin of 300 Hz for aliasing */
+ band_start = extra_bands[b];
+ band_end = extra_bands[b+1];
+ for (i=band_start;i<band_end;i++)
+ {
+ float binE = out[i].r*(float)out[i].r + out[N-i].r*(float)out[N-i].r
+ + out[i].i*(float)out[i].i + out[N-i].i*(float)out[N-i].i;
+ E += binE;
+ }
+ maxE = MAX32(maxE, E);
+ tonal->meanE[b] = MAX32((1-alphaE2)*tonal->meanE[b], E);
+ E = MAX32(E, tonal->meanE[b]);
+ /* Use a simple follower with 13 dB/Bark slope for spreading function */
+ bandwidth_mask = MAX32(.05f*bandwidth_mask, E);
+ /* Consider the band "active" only if all these conditions are met:
+ 1) less than 10 dB below the simple follower
+ 2) less than 90 dB below the peak band (maximal masking possible considering
+ both the ATH and the loudness-dependent slope of the spreading function)
+ 3) above the PCM quantization noise floor
+ */
+ if (E>.1*bandwidth_mask && E*1e9f > maxE && E > noise_floor*(band_end-band_start))
+ bandwidth = b;
+ }
+ if (tonal->count<=2)
+ bandwidth = 20;
+ frame_loudness = 20*(float)log10(frame_loudness);
+ tonal->Etracker = MAX32(tonal->Etracker-.03f, frame_loudness);
+ tonal->lowECount *= (1-alphaE);
+ if (frame_loudness < tonal->Etracker-30)
+ tonal->lowECount += alphaE;
+
+ for (i=0;i<8;i++)
+ {
+ float sum=0;
+ for (b=0;b<16;b++)
+ sum += dct_table[i*16+b]*logE[b];
+ BFCC[i] = sum;
+ }
+
+ frame_stationarity /= NB_TBANDS;
+ relativeE /= NB_TBANDS;
+ if (tonal->count<10)
+ relativeE = .5;
+ frame_noisiness /= NB_TBANDS;
+#if 1
+ info->activity = frame_noisiness + (1-frame_noisiness)*relativeE;
+#else
+ info->activity = .5*(1+frame_noisiness-frame_stationarity);
+#endif
+ frame_tonality = (max_frame_tonality/(NB_TBANDS-NB_TONAL_SKIP_BANDS));
+ frame_tonality = MAX16(frame_tonality, tonal->prev_tonality*.8f);
+ tonal->prev_tonality = frame_tonality;
+
+ slope /= 8*8;
+ info->tonality_slope = slope;
+
+ tonal->E_count = (tonal->E_count+1)%NB_FRAMES;
+ tonal->count++;
+ info->tonality = frame_tonality;
+
+ for (i=0;i<4;i++)
+ features[i] = -0.12299f*(BFCC[i]+tonal->mem[i+24]) + 0.49195f*(tonal->mem[i]+tonal->mem[i+16]) + 0.69693f*tonal->mem[i+8] - 1.4349f*tonal->cmean[i];
+
+ for (i=0;i<4;i++)
+ tonal->cmean[i] = (1-alpha)*tonal->cmean[i] + alpha*BFCC[i];
+
+ for (i=0;i<4;i++)
+ features[4+i] = 0.63246f*(BFCC[i]-tonal->mem[i+24]) + 0.31623f*(tonal->mem[i]-tonal->mem[i+16]);
+ for (i=0;i<3;i++)
+ features[8+i] = 0.53452f*(BFCC[i]+tonal->mem[i+24]) - 0.26726f*(tonal->mem[i]+tonal->mem[i+16]) -0.53452f*tonal->mem[i+8];
+
+ if (tonal->count > 5)
+ {
+ for (i=0;i<9;i++)
+ tonal->std[i] = (1-alpha)*tonal->std[i] + alpha*features[i]*features[i];
+ }
+
+ for (i=0;i<8;i++)
+ {
+ tonal->mem[i+24] = tonal->mem[i+16];
+ tonal->mem[i+16] = tonal->mem[i+8];
+ tonal->mem[i+8] = tonal->mem[i];
+ tonal->mem[i] = BFCC[i];
+ }
+ for (i=0;i<9;i++)
+ features[11+i] = (float)sqrt(tonal->std[i]);
+ features[20] = info->tonality;
+ features[21] = info->activity;
+ features[22] = frame_stationarity;
+ features[23] = info->tonality_slope;
+ features[24] = tonal->lowECount;
+
+#ifndef DISABLE_FLOAT_API
+ mlp_process(&net, features, frame_probs);
+ frame_probs[0] = .5f*(frame_probs[0]+1);
+ /* Curve fitting between the MLP probability and the actual probability */
+ frame_probs[0] = .01f + 1.21f*frame_probs[0]*frame_probs[0] - .23f*(float)pow(frame_probs[0], 10);
+ /* Probability of active audio (as opposed to silence) */
+ frame_probs[1] = .5f*frame_probs[1]+.5f;
+ /* Consider that silence has a 50-50 probability. */
+ frame_probs[0] = frame_probs[1]*frame_probs[0] + (1-frame_probs[1])*.5f;
+
+ /*printf("%f %f ", frame_probs[0], frame_probs[1]);*/
+ {
+ /* Probability of state transition */
+ float tau;
+ /* Represents independence of the MLP probabilities, where
+ beta=1 means fully independent. */
+ float beta;
+ /* Denormalized probability of speech (p0) and music (p1) after update */
+ float p0, p1;
+ /* Probabilities for "all speech" and "all music" */
+ float s0, m0;
+ /* Probability sum for renormalisation */
+ float psum;
+ /* Instantaneous probability of speech and music, with beta pre-applied. */
+ float speech0;
+ float music0;
+
+ /* One transition every 3 minutes of active audio */
+ tau = .00005f*frame_probs[1];
+ beta = .05f;
+ if (1) {
+ /* Adapt beta based on how "unexpected" the new prob is */
+ float p, q;
+ p = MAX16(.05f,MIN16(.95f,frame_probs[0]));
+ q = MAX16(.05f,MIN16(.95f,tonal->music_prob));
+ beta = .01f+.05f*ABS16(p-q)/(p*(1-q)+q*(1-p));
+ }
+ /* p0 and p1 are the probabilities of speech and music at this frame
+ using only information from previous frame and applying the
+ state transition model */
+ p0 = (1-tonal->music_prob)*(1-tau) + tonal->music_prob *tau;
+ p1 = tonal->music_prob *(1-tau) + (1-tonal->music_prob)*tau;
+ /* We apply the current probability with exponent beta to work around
+ the fact that the probability estimates aren't independent. */
+ p0 *= (float)pow(1-frame_probs[0], beta);
+ p1 *= (float)pow(frame_probs[0], beta);
+ /* Normalise the probabilities to get the Marokv probability of music. */
+ tonal->music_prob = p1/(p0+p1);
+ info->music_prob = tonal->music_prob;
+
+ /* This chunk of code deals with delayed decision. */
+ psum=1e-20f;
+ /* Instantaneous probability of speech and music, with beta pre-applied. */
+ speech0 = (float)pow(1-frame_probs[0], beta);
+ music0 = (float)pow(frame_probs[0], beta);
+ if (tonal->count==1)
+ {
+ tonal->pspeech[0]=.5;
+ tonal->pmusic [0]=.5;
+ }
+ /* Updated probability of having only speech (s0) or only music (m0),
+ before considering the new observation. */
+ s0 = tonal->pspeech[0] + tonal->pspeech[1];
+ m0 = tonal->pmusic [0] + tonal->pmusic [1];
+ /* Updates s0 and m0 with instantaneous probability. */
+ tonal->pspeech[0] = s0*(1-tau)*speech0;
+ tonal->pmusic [0] = m0*(1-tau)*music0;
+ /* Propagate the transition probabilities */
+ for (i=1;i<DETECT_SIZE-1;i++)
+ {
+ tonal->pspeech[i] = tonal->pspeech[i+1]*speech0;
+ tonal->pmusic [i] = tonal->pmusic [i+1]*music0;
+ }
+ /* Probability that the latest frame is speech, when all the previous ones were music. */
+ tonal->pspeech[DETECT_SIZE-1] = m0*tau*speech0;
+ /* Probability that the latest frame is music, when all the previous ones were speech. */
+ tonal->pmusic [DETECT_SIZE-1] = s0*tau*music0;
+
+ /* Renormalise probabilities to 1 */
+ for (i=0;i<DETECT_SIZE;i++)
+ psum += tonal->pspeech[i] + tonal->pmusic[i];
+ psum = 1.f/psum;
+ for (i=0;i<DETECT_SIZE;i++)
+ {
+ tonal->pspeech[i] *= psum;
+ tonal->pmusic [i] *= psum;
+ }
+ psum = tonal->pmusic[0];
+ for (i=1;i<DETECT_SIZE;i++)
+ psum += tonal->pspeech[i];
+
+ /* Estimate our confidence in the speech/music decisions */
+ if (frame_probs[1]>.75)
+ {
+ if (tonal->music_prob>.9)
+ {
+ float adapt;
+ adapt = 1.f/(++tonal->music_confidence_count);
+ tonal->music_confidence_count = IMIN(tonal->music_confidence_count, 500);
+ tonal->music_confidence += adapt*MAX16(-.2f,frame_probs[0]-tonal->music_confidence);
+ }
+ if (tonal->music_prob<.1)
+ {
+ float adapt;
+ adapt = 1.f/(++tonal->speech_confidence_count);
+ tonal->speech_confidence_count = IMIN(tonal->speech_confidence_count, 500);
+ tonal->speech_confidence += adapt*MIN16(.2f,frame_probs[0]-tonal->speech_confidence);
+ }
+ } else {
+ if (tonal->music_confidence_count==0)
+ tonal->music_confidence = .9f;
+ if (tonal->speech_confidence_count==0)
+ tonal->speech_confidence = .1f;
+ }
+ }
+ if (tonal->last_music != (tonal->music_prob>.5f))
+ tonal->last_transition=0;
+ tonal->last_music = tonal->music_prob>.5f;
+#else
+ info->music_prob = 0;
+#endif
+ /*for (i=0;i<25;i++)
+ printf("%f ", features[i]);
+ printf("\n");*/
+
+ info->bandwidth = bandwidth;
+ /*printf("%d %d\n", info->bandwidth, info->opus_bandwidth);*/
+ info->noisiness = frame_noisiness;
+ info->valid = 1;
+ if (info_out!=NULL)
+ OPUS_COPY(info_out, info, 1);
+ RESTORE_STACK;
+}
+
+void run_analysis(TonalityAnalysisState *analysis, const CELTMode *celt_mode, const void *analysis_pcm,
+ int analysis_frame_size, int frame_size, int c1, int c2, int C, opus_int32 Fs,
+ int lsb_depth, downmix_func downmix, AnalysisInfo *analysis_info)
+{
+ int offset;
+ int pcm_len;
+
+ if (analysis_pcm != NULL)
+ {
+ /* Avoid overflow/wrap-around of the analysis buffer */
+ analysis_frame_size = IMIN((DETECT_SIZE-5)*Fs/100, analysis_frame_size);
+
+ pcm_len = analysis_frame_size - analysis->analysis_offset;
+ offset = analysis->analysis_offset;
+ do {
+ tonality_analysis(analysis, NULL, celt_mode, analysis_pcm, IMIN(480, pcm_len), offset, c1, c2, C, lsb_depth, downmix);
+ offset += 480;
+ pcm_len -= 480;
+ } while (pcm_len>0);
+ analysis->analysis_offset = analysis_frame_size;
+
+ analysis->analysis_offset -= frame_size;
+ }
+
+ analysis_info->valid = 0;
+ tonality_get_info(analysis, analysis_info, frame_size);
+}
diff --git a/drivers/opus/analysis.h b/drivers/opus/analysis.h
new file mode 100644
index 0000000000..548614d529
--- /dev/null
+++ b/drivers/opus/analysis.h
@@ -0,0 +1,90 @@
+/* Copyright (c) 2011 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef ANALYSIS_H
+#define ANALYSIS_H
+
+#include "opus/celt/celt.h"
+#include "opus/opus_private.h"
+
+#define NB_FRAMES 8
+#define NB_TBANDS 18
+#define NB_TOT_BANDS 21
+#define ANALYSIS_BUF_SIZE 720 /* 15 ms at 48 kHz */
+
+#define DETECT_SIZE 200
+
+typedef struct {
+ float angle[240];
+ float d_angle[240];
+ float d2_angle[240];
+ opus_val32 inmem[ANALYSIS_BUF_SIZE];
+ int mem_fill; /* number of usable samples in the buffer */
+ float prev_band_tonality[NB_TBANDS];
+ float prev_tonality;
+ float E[NB_FRAMES][NB_TBANDS];
+ float lowE[NB_TBANDS];
+ float highE[NB_TBANDS];
+ float meanE[NB_TOT_BANDS];
+ float mem[32];
+ float cmean[8];
+ float std[9];
+ float music_prob;
+ float Etracker;
+ float lowECount;
+ int E_count;
+ int last_music;
+ int last_transition;
+ int count;
+ float subframe_mem[3];
+ int analysis_offset;
+ /** Probability of having speech for time i to DETECT_SIZE-1 (and music before).
+ pspeech[0] is the probability that all frames in the window are speech. */
+ float pspeech[DETECT_SIZE];
+ /** Probability of having music for time i to DETECT_SIZE-1 (and speech before).
+ pmusic[0] is the probability that all frames in the window are music. */
+ float pmusic[DETECT_SIZE];
+ float speech_confidence;
+ float music_confidence;
+ int speech_confidence_count;
+ int music_confidence_count;
+ int write_pos;
+ int read_pos;
+ int read_subframe;
+ AnalysisInfo info[DETECT_SIZE];
+} TonalityAnalysisState;
+
+void tonality_analysis(TonalityAnalysisState *tonal, AnalysisInfo *info,
+ const CELTMode *celt_mode, const void *x, int len, int offset, int c1, int c2, int C, int lsb_depth, downmix_func downmix);
+
+void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int len);
+
+void run_analysis(TonalityAnalysisState *analysis, const CELTMode *celt_mode, const void *analysis_pcm,
+ int analysis_frame_size, int frame_size, int c1, int c2, int C, opus_int32 Fs,
+ int lsb_depth, downmix_func downmix, AnalysisInfo *analysis_info);
+
+#endif
diff --git a/drivers/opus/audio_stream_opus.cpp b/drivers/opus/audio_stream_opus.cpp
new file mode 100644
index 0000000000..ab53fee0c9
--- /dev/null
+++ b/drivers/opus/audio_stream_opus.cpp
@@ -0,0 +1,376 @@
+/*************************************************************************/
+/* audio_stream_opus.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Author: George Marques <george@gmarqu.es> */
+/* */
+/* 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. */
+/*************************************************************************/
+#include "audio_stream_opus.h"
+
+const float AudioStreamPlaybackOpus::osrate=48000.0f;
+
+int AudioStreamPlaybackOpus::_op_read_func(void *_stream, unsigned char *_ptr, int _nbytes) {
+ FileAccess *fa=(FileAccess*)_stream;
+
+ if(fa->eof_reached())
+ return 0;
+
+ uint8_t *dst = (uint8_t*)_ptr;
+
+ int read = fa->get_buffer(dst, _nbytes);
+
+ return read;
+}
+
+int AudioStreamPlaybackOpus::_op_seek_func(void *_stream, opus_int64 _offset, int _whence){
+
+#ifdef SEEK_SET
+ FileAccess *fa=(FileAccess*)_stream;
+
+ switch (_whence) {
+ case SEEK_SET: {
+ fa->seek(_offset);
+ } break;
+ case SEEK_CUR: {
+ fa->seek(fa->get_pos()+_offset);
+ } break;
+ case SEEK_END: {
+ fa->seek_end(_offset);
+ } break;
+ default: {
+ ERR_PRINT("BUG, wtf was whence set to?\n");
+ }
+ }
+ int ret=fa->eof_reached()?-1:0;
+ return ret;
+#else
+ return -1; // no seeking
+#endif
+}
+
+int AudioStreamPlaybackOpus::_op_close_func(void *_stream) {
+ if (!_stream)
+ return 0;
+ FileAccess *fa=(FileAccess*)_stream;
+ if (fa->is_open())
+ fa->close();
+ return 0;
+}
+
+opus_int64 AudioStreamPlaybackOpus::_op_tell_func(void *_stream) {
+ FileAccess *_fa = (FileAccess*)_stream;
+ return (opus_int64)_fa->get_pos();
+}
+
+void AudioStreamPlaybackOpus::_clear_stream() {
+ if(!stream_loaded)
+ return;
+
+ op_free(opus_file);
+ _close_file();
+
+ stream_loaded=false;
+ stream_channels=1;
+ playing=false;
+}
+
+void AudioStreamPlaybackOpus::_close_file() {
+ if (f) {
+ memdelete(f);
+ f=NULL;
+ }
+}
+
+Error AudioStreamPlaybackOpus::_load_stream() {
+
+ ERR_FAIL_COND_V(!stream_valid,ERR_UNCONFIGURED);
+
+ _clear_stream();
+ if (file=="")
+ return ERR_INVALID_DATA;
+
+ Error err;
+ f=FileAccess::open(file,FileAccess::READ,&err);
+
+ if (err) {
+ ERR_FAIL_COND_V( err, err );
+ }
+
+ int _err = 0;
+
+ opus_file = op_open_callbacks(f,&_op_callbacks,NULL,0,&_err);
+
+ switch (_err) {
+ case OP_EREAD: { // - Can't read the file.
+ memdelete(f); f=NULL;
+ ERR_FAIL_V( ERR_FILE_CANT_READ );
+ } break;
+ case OP_EVERSION: // - Unrecognized version number.
+ case OP_ENOTFORMAT: // - Stream is not Opus data.
+ case OP_EIMPL : { // - Stream used non-implemented feature.
+ memdelete(f); f=NULL;
+ ERR_FAIL_V( ERR_FILE_UNRECOGNIZED );
+ } break;
+ case OP_EBADLINK: // - Failed to find old data after seeking.
+ case OP_EBADTIMESTAMP: // - Timestamp failed the validity checks.
+ case OP_EBADHEADER: { // - Invalid or mising Opus bitstream header.
+ memdelete(f); f=NULL;
+ ERR_FAIL_V( ERR_FILE_CORRUPT );
+ } break;
+ case OP_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption.
+ memdelete(f); f=NULL;
+ ERR_FAIL_V( ERR_BUG );
+ } break;
+ }
+ repeats=0;
+ stream_loaded=true;
+
+
+ return OK;
+}
+
+AudioStreamPlaybackOpus::AudioStreamPlaybackOpus() {
+ loops=false;
+ playing=false;
+ f = NULL;
+ stream_loaded=false;
+ stream_valid=false;
+ repeats=0;
+ paused=true;
+ stream_channels=0;
+ current_section=0;
+ length=0;
+ loop_restart_time=0;
+ pre_skip=0;
+
+ _op_callbacks.read = _op_read_func;
+ _op_callbacks.seek = _op_seek_func;
+ _op_callbacks.tell = _op_tell_func;
+ _op_callbacks.close = _op_close_func;
+}
+
+Error AudioStreamPlaybackOpus::set_file(const String &p_file) {
+ file=p_file;
+ stream_valid=false;
+ Error err;
+ f=FileAccess::open(file,FileAccess::READ,&err);
+
+ if (err) {
+ ERR_FAIL_COND_V( err, err );
+ }
+
+ int _err;
+
+ opus_file = op_open_callbacks(f,&_op_callbacks,NULL,0,&_err);
+
+ switch (_err) {
+ case OP_EREAD: { // - Can't read the file.
+ memdelete(f); f=NULL;
+ ERR_FAIL_V( ERR_FILE_CANT_READ );
+ } break;
+ case OP_EVERSION: // - Unrecognized version number.
+ case OP_ENOTFORMAT: // - Stream is not Opus data.
+ case OP_EIMPL : { // - Stream used non-implemented feature.
+ memdelete(f); f=NULL;
+ ERR_FAIL_V( ERR_FILE_UNRECOGNIZED );
+ } break;
+ case OP_EBADLINK: // - Failed to find old data after seeking.
+ case OP_EBADTIMESTAMP: // - Timestamp failed the validity checks.
+ case OP_EBADHEADER: { // - Invalid or mising Opus bitstream header.
+ memdelete(f); f=NULL;
+ ERR_FAIL_V( ERR_FILE_CORRUPT );
+ } break;
+ case OP_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption.
+ memdelete(f); f=NULL;
+ ERR_FAIL_V( ERR_BUG );
+ } break;
+ }
+
+ const OpusHead *oinfo = op_head(opus_file,-1);
+
+ stream_channels=oinfo->channel_count;
+ pre_skip=oinfo->pre_skip;
+ frames_mixed=pre_skip;
+ ogg_int64_t len = op_pcm_total(opus_file,-1);
+ if(len < 0) {
+ length = 0;
+ } else {
+ length=(len/osrate);
+ }
+
+ op_free(opus_file);
+ memdelete(f);
+ f=NULL;
+ stream_valid=true;
+
+
+ return OK;
+}
+
+void AudioStreamPlaybackOpus::play(float p_from) {
+ if (playing)
+ stop();
+
+ if (_load_stream()!=OK)
+ return;
+
+ frames_mixed=pre_skip;
+ playing=true;
+ if (p_from>0) {
+ seek_pos(p_from);
+ }
+}
+
+void AudioStreamPlaybackOpus::stop() {
+ _clear_stream();
+ playing=false;
+}
+
+void AudioStreamPlaybackOpus::seek_pos(float p_time) {
+ if(!playing) return;
+ ogg_int64_t pcm_offset = (ogg_int64_t)(p_time * osrate);
+ bool ok = op_pcm_seek(opus_file,pcm_offset)==0;
+ if(!ok) {
+ ERR_PRINT("Seek time over stream size.");
+ return;
+ }
+ frames_mixed=osrate*p_time;
+}
+
+int AudioStreamPlaybackOpus::mix(int16_t* p_bufer,int p_frames) {
+ if (!playing)
+ return 0;
+
+ int total=p_frames;
+
+ while (true) {
+
+ int todo = p_frames;
+
+ if (todo==0 || todo<MIN_MIX) {
+ break;
+ }
+
+ int ret=op_read(opus_file,(opus_int16*)p_bufer,todo*stream_channels,&current_section);
+ if (ret<0) {
+ playing = false;
+ ERR_EXPLAIN("Error reading Opus File: "+file);
+ ERR_BREAK(ret<0);
+ } else if (ret==0) { // end of song, reload?
+ op_free(opus_file);
+
+ _close_file();
+
+ f=FileAccess::open(file,FileAccess::READ);
+
+ int errv = 0;
+ opus_file = op_open_callbacks(f,&_op_callbacks,NULL,0,&errv);
+ if (errv!=0) {
+ playing=false;
+ break; // :(
+ }
+
+ if (!has_loop()) {
+ playing=false;
+ repeats=1;
+ break;
+ }
+
+ if (loop_restart_time) {
+ bool ok = op_pcm_seek(opus_file, (loop_restart_time*osrate)+pre_skip)==0;
+ if (!ok) {
+ playing=false;
+ ERR_PRINT("loop restart time rejected")
+ }
+
+ frames_mixed=(loop_restart_time*osrate)+pre_skip;
+ } else {
+ frames_mixed=pre_skip;
+ }
+ repeats++;
+ continue;
+
+ }
+
+ stream_channels=op_head(opus_file,current_section)->channel_count;
+
+ frames_mixed+=ret;
+
+ p_bufer+=ret*stream_channels;
+ p_frames-=ret;
+
+ }
+
+ return total-p_frames;
+}
+
+float AudioStreamPlaybackOpus::get_length() const {
+ if(!stream_loaded) {
+ if(const_cast<AudioStreamPlaybackOpus*>(this)->_load_stream() != OK)
+ return 0;
+ }
+ return length;
+}
+
+float AudioStreamPlaybackOpus::get_pos() const {
+
+ int32_t frames = int32_t(frames_mixed);
+ if (frames < 0)
+ frames=0;
+ return double(frames) / osrate;
+}
+
+int AudioStreamPlaybackOpus::get_minimum_buffer_size() const {
+ return MIN_MIX;
+}
+
+AudioStreamPlaybackOpus::~AudioStreamPlaybackOpus() {
+ _clear_stream();
+}
+
+RES ResourceFormatLoaderAudioStreamOpus::load(const String &p_path, const String& p_original_path, Error *r_error) {
+ if (r_error)
+ *r_error=OK;
+
+ AudioStreamOpus *opus_stream = memnew(AudioStreamOpus);
+ opus_stream->set_file(p_path);
+ return Ref<AudioStreamOpus>(opus_stream);
+}
+
+void ResourceFormatLoaderAudioStreamOpus::get_recognized_extensions(List<String> *p_extensions) const {
+
+ p_extensions->push_back("opus");
+}
+String ResourceFormatLoaderAudioStreamOpus::get_resource_type(const String &p_path) const {
+
+ if (p_path.extension().to_lower()=="opus")
+ return "AudioStreamOpus";
+ return "";
+}
+
+bool ResourceFormatLoaderAudioStreamOpus::handles_type(const String& p_type) const {
+ return (p_type=="AudioStream" || p_type=="AudioStreamOpus");
+}
diff --git a/drivers/opus/audio_stream_opus.h b/drivers/opus/audio_stream_opus.h
new file mode 100644
index 0000000000..fc5531470d
--- /dev/null
+++ b/drivers/opus/audio_stream_opus.h
@@ -0,0 +1,141 @@
+/*************************************************************************/
+/* audio_stream_opus.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Author: George Marques <george@gmarqu.es> */
+/* */
+/* 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. */
+/*************************************************************************/
+
+#ifndef AUDIO_STREAM_OPUS_H
+#define AUDIO_STREAM_OPUS_H
+
+#include "scene/resources/audio_stream.h"
+#include "opus/opusfile.h"
+#include "opus/internal.h"
+#include "os/file_access.h"
+#include "io/resource_loader.h"
+
+class AudioStreamPlaybackOpus : public AudioStreamPlayback {
+
+ OBJ_TYPE(AudioStreamPlaybackOpus,AudioStreamPlayback)
+
+ enum {
+ MIN_MIX=1024
+ };
+
+ FileAccess *f;
+
+ OpusFileCallbacks _op_callbacks;
+ float length;
+ static int _op_read_func(void *_stream, unsigned char *_ptr, int _nbytes);
+ static int _op_seek_func(void *_stream, opus_int64 _offset, int _whence);
+ static int _op_close_func(void *_stream);
+ static opus_int64 _op_tell_func(void *_stream);
+ static const float osrate;
+
+ String file;
+ int64_t frames_mixed;
+
+ bool stream_loaded;
+ volatile bool playing;
+ OggOpusFile *opus_file;
+ int stream_channels;
+ int current_section;
+ int pre_skip;
+
+ bool paused;
+ bool loops;
+ int repeats;
+
+ Error _load_stream();
+ void _clear_stream();
+ void _close_file();
+
+ bool stream_valid;
+ float loop_restart_time;
+
+public:
+ Error set_file(const String& p_file);
+
+ virtual void play(float p_from=0);
+ virtual void stop();
+ virtual bool is_playing() const { return playing; }
+
+ virtual void set_loop_restart_time(float p_time) { loop_restart_time=p_time; }
+
+ virtual void set_paused(bool p_paused) { paused=p_paused; }
+ virtual bool is_paused() const { return paused; }
+
+ virtual void set_loop(bool p_enable) { loops=p_enable; }
+ virtual bool has_loop() const {return loops; }
+
+ virtual float get_length() const;
+
+ virtual String get_stream_name() const { return ""; }
+
+ virtual int get_loop_count() const { return repeats; }
+
+ virtual float get_pos() const;
+ virtual void seek_pos(float p_time);
+
+ virtual int get_channels() const { return stream_channels; }
+ virtual int get_mix_rate() const { return osrate; }
+
+ virtual int get_minimum_buffer_size() const;
+
+ virtual int mix(int16_t* p_bufer,int p_frames);
+
+ AudioStreamPlaybackOpus();
+ ~AudioStreamPlaybackOpus();
+};
+
+
+class AudioStreamOpus: public AudioStream {
+
+ OBJ_TYPE(AudioStreamOpus,AudioStream)
+
+ String file;
+public:
+
+ Ref<AudioStreamPlayback> instance_playback() {
+ Ref<AudioStreamPlaybackOpus> pb = memnew( AudioStreamPlaybackOpus );
+ pb->set_file(file);
+ return pb;
+ }
+
+ void set_file(const String& p_file) { file=p_file; }
+
+};
+
+class ResourceFormatLoaderAudioStreamOpus: public ResourceFormatLoader {
+public:
+ virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL);
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual bool handles_type(const String& p_type) const;
+ virtual String get_resource_type(const String &p_path) const;
+};
+
+#endif // AUDIO_STREAM_OPUS_H
diff --git a/drivers/opus/celt/_kiss_fft_guts.h b/drivers/opus/celt/_kiss_fft_guts.h
new file mode 100644
index 0000000000..2a4ee744ef
--- /dev/null
+++ b/drivers/opus/celt/_kiss_fft_guts.h
@@ -0,0 +1,183 @@
+/*Copyright (c) 2003-2004, Mark Borgerding
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.*/
+
+#ifndef KISS_FFT_GUTS_H
+#define KISS_FFT_GUTS_H
+
+#define MIN(a,b) ((a)<(b) ? (a):(b))
+#define MAX(a,b) ((a)>(b) ? (a):(b))
+
+/* kiss_fft.h
+ defines kiss_fft_scalar as either short or a float type
+ and defines
+ typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */
+#include "opus/celt/kiss_fft.h"
+
+/*
+ Explanation of macros dealing with complex math:
+
+ C_MUL(m,a,b) : m = a*b
+ C_FIXDIV( c , div ) : if a fixed point impl., c /= div. noop otherwise
+ C_SUB( res, a,b) : res = a - b
+ C_SUBFROM( res , a) : res -= a
+ C_ADDTO( res , a) : res += a
+ * */
+#ifdef OPUS_FIXED_POINT
+#include "opus/celt/arch.h"
+
+
+#define SAMP_MAX 2147483647
+#define TWID_MAX 32767
+#define TRIG_UPSCALE 1
+
+#define SAMP_MIN -SAMP_MAX
+
+
+# define S_MUL(a,b) MULT16_32_Q15(b, a)
+
+# define C_MUL(m,a,b) \
+ do{ (m).r = SUB32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \
+ (m).i = ADD32(S_MUL((a).r,(b).i) , S_MUL((a).i,(b).r)); }while(0)
+
+# define C_MULC(m,a,b) \
+ do{ (m).r = ADD32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \
+ (m).i = SUB32(S_MUL((a).i,(b).r) , S_MUL((a).r,(b).i)); }while(0)
+
+# define C_MUL4(m,a,b) \
+ do{ (m).r = SHR32(SUB32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)),2); \
+ (m).i = SHR32(ADD32(S_MUL((a).r,(b).i) , S_MUL((a).i,(b).r)),2); }while(0)
+
+# define C_MULBYSCALAR( c, s ) \
+ do{ (c).r = S_MUL( (c).r , s ) ;\
+ (c).i = S_MUL( (c).i , s ) ; }while(0)
+
+# define DIVSCALAR(x,k) \
+ (x) = S_MUL( x, (TWID_MAX-((k)>>1))/(k)+1 )
+
+# define C_FIXDIV(c,div) \
+ do { DIVSCALAR( (c).r , div); \
+ DIVSCALAR( (c).i , div); }while (0)
+
+#define C_ADD( res, a,b)\
+ do {(res).r=ADD32((a).r,(b).r); (res).i=ADD32((a).i,(b).i); \
+ }while(0)
+#define C_SUB( res, a,b)\
+ do {(res).r=SUB32((a).r,(b).r); (res).i=SUB32((a).i,(b).i); \
+ }while(0)
+#define C_ADDTO( res , a)\
+ do {(res).r = ADD32((res).r, (a).r); (res).i = ADD32((res).i,(a).i);\
+ }while(0)
+
+#define C_SUBFROM( res , a)\
+ do {(res).r = ADD32((res).r,(a).r); (res).i = SUB32((res).i,(a).i); \
+ }while(0)
+
+#if defined(OPUS_ARM_INLINE_ASM)
+#include "arm/kiss_fft_armv4.h"
+#endif
+
+#if defined(OPUS_ARM_INLINE_EDSP)
+#include "arm/kiss_fft_armv5e.h"
+#endif
+
+#else /* not OPUS_FIXED_POINT*/
+
+# define S_MUL(a,b) ( (a)*(b) )
+#define C_MUL(m,a,b) \
+ do{ (m).r = (a).r*(b).r - (a).i*(b).i;\
+ (m).i = (a).r*(b).i + (a).i*(b).r; }while(0)
+#define C_MULC(m,a,b) \
+ do{ (m).r = (a).r*(b).r + (a).i*(b).i;\
+ (m).i = (a).i*(b).r - (a).r*(b).i; }while(0)
+
+#define C_MUL4(m,a,b) C_MUL(m,a,b)
+
+# define C_FIXDIV(c,div) /* NOOP */
+# define C_MULBYSCALAR( c, s ) \
+ do{ (c).r *= (s);\
+ (c).i *= (s); }while(0)
+#endif
+
+#ifndef CHECK_OVERFLOW_OP
+# define CHECK_OVERFLOW_OP(a,op,b) /* noop */
+#endif
+
+#ifndef C_ADD
+#define C_ADD( res, a,b)\
+ do { \
+ CHECK_OVERFLOW_OP((a).r,+,(b).r)\
+ CHECK_OVERFLOW_OP((a).i,+,(b).i)\
+ (res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \
+ }while(0)
+#define C_SUB( res, a,b)\
+ do { \
+ CHECK_OVERFLOW_OP((a).r,-,(b).r)\
+ CHECK_OVERFLOW_OP((a).i,-,(b).i)\
+ (res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \
+ }while(0)
+#define C_ADDTO( res , a)\
+ do { \
+ CHECK_OVERFLOW_OP((res).r,+,(a).r)\
+ CHECK_OVERFLOW_OP((res).i,+,(a).i)\
+ (res).r += (a).r; (res).i += (a).i;\
+ }while(0)
+
+#define C_SUBFROM( res , a)\
+ do {\
+ CHECK_OVERFLOW_OP((res).r,-,(a).r)\
+ CHECK_OVERFLOW_OP((res).i,-,(a).i)\
+ (res).r -= (a).r; (res).i -= (a).i; \
+ }while(0)
+#endif /* C_ADD defined */
+
+#ifdef OPUS_FIXED_POINT
+# define KISS_FFT_COS(phase) TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * cos (phase))))
+# define KISS_FFT_SIN(phase) TRIG_UPSCALE*floor(MIN(32767,MAX(-32767,.5+32768 * sin (phase))))
+# define KISS_FFT_COS(phase) floor(.5+TWID_MAX*cos (phase))
+# define KISS_FFT_SIN(phase) floor(.5+TWID_MAX*sin (phase))
+# define HALF_OF(x) ((x)>>1)
+#elif defined(USE_SIMD)
+# define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) )
+# define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) )
+# define HALF_OF(x) ((x)*_mm_set1_ps(.5f))
+#else
+# define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase)
+# define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase)
+# define HALF_OF(x) ((x)*.5f)
+#endif
+
+#define kf_cexp(x,phase) \
+ do{ \
+ (x)->r = KISS_FFT_COS(phase);\
+ (x)->i = KISS_FFT_SIN(phase);\
+ }while(0)
+
+#define kf_cexp2(x,phase) \
+ do{ \
+ (x)->r = TRIG_UPSCALE*celt_cos_norm((phase));\
+ (x)->i = TRIG_UPSCALE*celt_cos_norm((phase)-32768);\
+}while(0)
+
+#endif /* KISS_FFT_GUTS_H */
diff --git a/drivers/opus/celt/arch.h b/drivers/opus/celt/arch.h
new file mode 100644
index 0000000000..d964f8d90c
--- /dev/null
+++ b/drivers/opus/celt/arch.h
@@ -0,0 +1,214 @@
+/* Copyright (c) 2003-2008 Jean-Marc Valin
+ Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/**
+ @file arch.h
+ @brief Various architecture definitions for CELT
+*/
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef ARCH_H
+#define ARCH_H
+
+#include "opus/opus_types.h"
+#include "opus/opus_defines.h"
+
+# if !defined(__GNUC_PREREQ)
+# if defined(__GNUC__)&&defined(__GNUC_MINOR__)
+# define __GNUC_PREREQ(_maj,_min) \
+ ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min))
+# else
+# define __GNUC_PREREQ(_maj,_min) 0
+# endif
+# endif
+
+#define CELT_SIG_SCALE 32768.f
+
+#define celt_fatal(str) _celt_fatal(str, __FILE__, __LINE__);
+#ifdef ENABLE_ASSERTIONS
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef __GNUC__
+__attribute__((noreturn))
+#endif
+static OPUS_INLINE void _celt_fatal(const char *str, const char *file, int line)
+{
+ fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str);
+ abort();
+}
+#define celt_assert(cond) {if (!(cond)) {celt_fatal("assertion failed: " #cond);}}
+#define celt_assert2(cond, message) {if (!(cond)) {celt_fatal("assertion failed: " #cond "\n" message);}}
+#else
+#define celt_assert(cond)
+#define celt_assert2(cond, message)
+#endif
+
+#define IMUL32(a,b) ((a)*(b))
+
+#define ABS(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute integer value. */
+#define ABS16(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 16-bit value. */
+#define MIN16(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum 16-bit value. */
+#define MAX16(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 16-bit value. */
+#define ABS32(x) ((x) < 0 ? (-(x)) : (x)) /**< Absolute 32-bit value. */
+#define MIN32(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum 32-bit value. */
+#define MAX32(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum 32-bit value. */
+#define IMIN(a,b) ((a) < (b) ? (a) : (b)) /**< Minimum int value. */
+#define IMAX(a,b) ((a) > (b) ? (a) : (b)) /**< Maximum int value. */
+#define UADD32(a,b) ((a)+(b))
+#define USUB32(a,b) ((a)-(b))
+
+#define PRINT_MIPS(file)
+
+#ifdef OPUS_FIXED_POINT
+
+typedef opus_int16 opus_val16;
+typedef opus_int32 opus_val32;
+
+typedef opus_val32 celt_sig;
+typedef opus_val16 celt_norm;
+typedef opus_val32 celt_ener;
+
+#define Q15ONE 32767
+
+#define SIG_SHIFT 12
+
+#define NORM_SCALING 16384
+
+#define DB_SHIFT 10
+
+#define EPSILON 1
+#define VERY_SMALL 0
+#define VERY_LARGE16 ((opus_val16)32767)
+#define Q15_ONE ((opus_val16)32767)
+
+#define SCALEIN(a) (a)
+#define SCALEOUT(a) (a)
+
+#ifdef FIXED_DEBUG
+#include "opus/celt/fixed_debug.h"
+#else
+
+#include "opus/celt/fixed_generic.h"
+
+#ifdef OPUS_ARM_INLINE_EDSP
+#include "arm/fixed_armv5e.h"
+#elif defined (OPUS_ARM_INLINE_ASM)
+#include "arm/fixed_armv4.h"
+#elif defined (BFIN_ASM)
+#include "fixed_bfin.h"
+#elif defined (TI_C5X_ASM)
+#include "fixed_c5x.h"
+#elif defined (TI_C6X_ASM)
+#include "fixed_c6x.h"
+#endif
+
+#endif
+
+#else /* OPUS_FIXED_POINT */
+
+typedef float opus_val16;
+typedef float opus_val32;
+
+typedef float celt_sig;
+typedef float celt_norm;
+typedef float celt_ener;
+
+#define Q15ONE 1.0f
+
+#define NORM_SCALING 1.f
+
+#define EPSILON 1e-15f
+#define VERY_SMALL 1e-30f
+#define VERY_LARGE16 1e15f
+#define Q15_ONE ((opus_val16)1.f)
+
+#define QCONST16(x,bits) (x)
+#define QCONST32(x,bits) (x)
+
+#define NEG16(x) (-(x))
+#define NEG32(x) (-(x))
+#define EXTRACT16(x) (x)
+#define EXTEND32(x) (x)
+#define SHR16(a,shift) (a)
+#define SHL16(a,shift) (a)
+#define SHR32(a,shift) (a)
+#define SHL32(a,shift) (a)
+#define PSHR32(a,shift) (a)
+#define VSHR32(a,shift) (a)
+
+#define PSHR(a,shift) (a)
+#define SHR(a,shift) (a)
+#define SHL(a,shift) (a)
+#define SATURATE(x,a) (x)
+#define SATURATE16(x) (x)
+
+#define ROUND16(a,shift) (a)
+#define HALF16(x) (.5f*(x))
+#define HALF32(x) (.5f*(x))
+
+#define ADD16(a,b) ((a)+(b))
+#define SUB16(a,b) ((a)-(b))
+#define ADD32(a,b) ((a)+(b))
+#define SUB32(a,b) ((a)-(b))
+#define MULT16_16_16(a,b) ((a)*(b))
+#define MULT16_16(a,b) ((opus_val32)(a)*(opus_val32)(b))
+#define MAC16_16(c,a,b) ((c)+(opus_val32)(a)*(opus_val32)(b))
+
+#define MULT16_32_Q15(a,b) ((a)*(b))
+#define MULT16_32_Q16(a,b) ((a)*(b))
+
+#define MULT32_32_Q31(a,b) ((a)*(b))
+
+#define MAC16_32_Q15(c,a,b) ((c)+(a)*(b))
+
+#define MULT16_16_Q11_32(a,b) ((a)*(b))
+#define MULT16_16_Q11(a,b) ((a)*(b))
+#define MULT16_16_Q13(a,b) ((a)*(b))
+#define MULT16_16_Q14(a,b) ((a)*(b))
+#define MULT16_16_Q15(a,b) ((a)*(b))
+#define MULT16_16_P15(a,b) ((a)*(b))
+#define MULT16_16_P13(a,b) ((a)*(b))
+#define MULT16_16_P14(a,b) ((a)*(b))
+#define MULT16_32_P16(a,b) ((a)*(b))
+
+#define DIV32_16(a,b) (((opus_val32)(a))/(opus_val16)(b))
+#define DIV32(a,b) (((opus_val32)(a))/(opus_val32)(b))
+
+#define SCALEIN(a) ((a)*CELT_SIG_SCALE)
+#define SCALEOUT(a) ((a)*(1/CELT_SIG_SCALE))
+
+#endif /* !OPUS_FIXED_POINT */
+
+#ifndef GLOBAL_STACK_SIZE
+#ifdef OPUS_FIXED_POINT
+#define GLOBAL_STACK_SIZE 100000
+#else
+#define GLOBAL_STACK_SIZE 100000
+#endif
+#endif
+
+#endif /* ARCH_H */
diff --git a/drivers/opus/celt/arm/arm2gnu.pl b/drivers/opus/celt/arm/arm2gnu.pl
new file mode 100755
index 0000000000..eab42efa2b
--- /dev/null
+++ b/drivers/opus/celt/arm/arm2gnu.pl
@@ -0,0 +1,316 @@
+#!/usr/bin/perl
+
+my $bigend; # little/big endian
+my $nxstack;
+
+$nxstack = 0;
+
+eval 'exec /usr/local/bin/perl -S $0 ${1+"$@"}'
+ if $running_under_some_shell;
+
+while ($ARGV[0] =~ /^-/) {
+ $_ = shift;
+ last if /^--/;
+ if (/^-n/) {
+ $nflag++;
+ next;
+ }
+ die "I don't recognize this switch: $_\\n";
+}
+$printit++ unless $nflag;
+
+$\ = "\n"; # automatically add newline on print
+$n=0;
+
+$thumb = 0; # ARM mode by default, not Thumb.
+@proc_stack = ();
+
+LINE:
+while (<>) {
+
+ # For ADRLs we need to add a new line after the substituted one.
+ $addPadding = 0;
+
+ # First, we do not dare to touch *anything* inside double quotes, do we?
+ # Second, if you want a dollar character in the string,
+ # insert two of them -- that's how ARM C and assembler treat strings.
+ s/^([A-Za-z_]\w*)[ \t]+DCB[ \t]*\"/$1: .ascii \"/ && do { s/\$\$/\$/g; next };
+ s/\bDCB\b[ \t]*\"/.ascii \"/ && do { s/\$\$/\$/g; next };
+ s/^(\S+)\s+RN\s+(\S+)/$1 .req r$2/ && do { s/\$\$/\$/g; next };
+ # If there's nothing on a line but a comment, don't try to apply any further
+ # substitutions (this is a cheap hack to avoid mucking up the license header)
+ s/^([ \t]*);/$1@/ && do { s/\$\$/\$/g; next };
+ # If substituted -- leave immediately !
+
+ s/@/,:/;
+ s/;/@/;
+ while ( /@.*'/ ) {
+ s/(@.*)'/$1/g;
+ }
+ s/\{FALSE\}/0/g;
+ s/\{TRUE\}/1/g;
+ s/\{(\w\w\w\w+)\}/$1/g;
+ s/\bINCLUDE[ \t]*([^ \t\n]+)/.include \"$1\"/;
+ s/\bGET[ \t]*([^ \t\n]+)/.include \"${ my $x=$1; $x =~ s|\.s|-gnu.S|; \$x }\"/;
+ s/\bIMPORT\b/.extern/;
+ s/\bEXPORT\b/.global/;
+ s/^(\s+)\[/$1IF/;
+ s/^(\s+)\|/$1ELSE/;
+ s/^(\s+)\]/$1ENDIF/;
+ s/IF *:DEF:/ .ifdef/;
+ s/IF *:LNOT: *:DEF:/ .ifndef/;
+ s/ELSE/ .else/;
+ s/ENDIF/ .endif/;
+
+ if( /\bIF\b/ ) {
+ s/\bIF\b/ .if/;
+ s/=/==/;
+ }
+ if ( $n == 2) {
+ s/\$/\\/g;
+ }
+ if ($n == 1) {
+ s/\$//g;
+ s/label//g;
+ $n = 2;
+ }
+ if ( /MACRO/ ) {
+ s/MACRO *\n/.macro/;
+ $n=1;
+ }
+ if ( /\bMEND\b/ ) {
+ s/\bMEND\b/.endm/;
+ $n=0;
+ }
+
+ # ".rdata" doesn't work in 'as' version 2.13.2, as it is ".rodata" there.
+ #
+ if ( /\bAREA\b/ ) {
+ my $align;
+ $align = "2";
+ if ( /ALIGN=(\d+)/ ) {
+ $align = $1;
+ }
+ if ( /CODE/ ) {
+ $nxstack = 1;
+ }
+ s/^(.+)CODE(.+)READONLY(.*)/ .text/;
+ s/^(.+)DATA(.+)READONLY(.*)/ .section .rdata/;
+ s/^(.+)\|\|\.data\|\|(.+)/ .data/;
+ s/^(.+)\|\|\.bss\|\|(.+)/ .bss/;
+ s/$/; .p2align $align/;
+ # Enable NEON instructions but don't produce a binary that requires
+ # ARMv7. RVCT does not have equivalent directives, so we just do this
+ # for all CODE areas.
+ if ( /.text/ ) {
+ # Separating .arch, .fpu, etc., by semicolons does not work (gas
+ # thinks the semicolon is part of the arch name, even when there's
+ # whitespace separating them). Sadly this means our line numbers
+ # won't match the original source file (we could use the .line
+ # directive, which is documented to be obsolete, but then gdb will
+ # show the wrong line in the translated source file).
+ s/$/; .arch armv7-a\n .fpu neon\n .object_arch armv4t/;
+ }
+ }
+
+ s/\|\|\.constdata\$(\d+)\|\|/.L_CONST$1/; # ||.constdata$3||
+ s/\|\|\.bss\$(\d+)\|\|/.L_BSS$1/; # ||.bss$2||
+ s/\|\|\.data\$(\d+)\|\|/.L_DATA$1/; # ||.data$2||
+ s/\|\|([a-zA-Z0-9_]+)\@([a-zA-Z0-9_]+)\|\|/@ $&/;
+ s/^(\s+)\%(\s)/ .space $1/;
+
+ s/\|(.+)\.(\d+)\|/\.$1_$2/; # |L80.123| -> .L80_123
+ s/\bCODE32\b/.code 32/ && do {$thumb = 0};
+ s/\bCODE16\b/.code 16/ && do {$thumb = 1};
+ if (/\bPROC\b/)
+ {
+ my $prefix;
+ my $proc;
+ /^([A-Za-z_\.]\w+)\b/;
+ $proc = $1;
+ $prefix = "";
+ if ($proc)
+ {
+ $prefix = $prefix.sprintf("\t.type\t%s, %%function; ",$proc);
+ push(@proc_stack, $proc);
+ s/^[A-Za-z_\.]\w+/$&:/;
+ }
+ $prefix = $prefix."\t.thumb_func; " if ($thumb);
+ s/\bPROC\b/@ $&/;
+ $_ = $prefix.$_;
+ }
+ s/^(\s*)(S|Q|SH|U|UQ|UH)ASX\b/$1$2ADDSUBX/;
+ s/^(\s*)(S|Q|SH|U|UQ|UH)SAX\b/$1$2SUBADDX/;
+ if (/\bENDP\b/)
+ {
+ my $proc;
+ s/\bENDP\b/@ $&/;
+ $proc = pop(@proc_stack);
+ $_ = "\t.size $proc, .-$proc".$_ if ($proc);
+ }
+ s/\bSUBT\b/@ $&/;
+ s/\bDATA\b/@ $&/; # DATA directive is deprecated -- Asm guide, p.7-25
+ s/\bKEEP\b/@ $&/;
+ s/\bEXPORTAS\b/@ $&/;
+ s/\|\|(.)+\bEQU\b/@ $&/;
+ s/\|\|([\w\$]+)\|\|/$1/;
+ s/\bENTRY\b/@ $&/;
+ s/\bASSERT\b/@ $&/;
+ s/\bGBLL\b/@ $&/;
+ s/\bGBLA\b/@ $&/;
+ s/^\W+OPT\b/@ $&/;
+ s/:OR:/|/g;
+ s/:SHL:/<</g;
+ s/:SHR:/>>/g;
+ s/:AND:/&/g;
+ s/:LAND:/&&/g;
+ s/CPSR/cpsr/;
+ s/SPSR/spsr/;
+ s/ALIGN$/.balign 4/;
+ s/ALIGN\s+([0-9x]+)$/.balign $1/;
+ s/psr_cxsf/psr_all/;
+ s/LTORG/.ltorg/;
+ s/^([A-Za-z_]\w*)[ \t]+EQU/ .set $1,/;
+ s/^([A-Za-z_]\w*)[ \t]+SETL/ .set $1,/;
+ s/^([A-Za-z_]\w*)[ \t]+SETA/ .set $1,/;
+ s/^([A-Za-z_]\w*)[ \t]+\*/ .set $1,/;
+
+ # {PC} + 0xdeadfeed --> . + 0xdeadfeed
+ s/\{PC\} \+/ \. +/;
+
+ # Single hex constant on the line !
+ #
+ # >>> NOTE <<<
+ # Double-precision floats in gcc are always mixed-endian, which means
+ # bytes in two words are little-endian, but words are big-endian.
+ # So, 0x0000deadfeed0000 would be stored as 0x0000dead at low address
+ # and 0xfeed0000 at high address.
+ #
+ s/\bDCFD\b[ \t]+0x([a-fA-F0-9]{8})([a-fA-F0-9]{8})/.long 0x$1, 0x$2/;
+ # Only decimal constants on the line, no hex !
+ s/\bDCFD\b[ \t]+([0-9\.\-]+)/.double $1/;
+
+ # Single hex constant on the line !
+# s/\bDCFS\b[ \t]+0x([a-f0-9]{8})([a-f0-9]{8})/.long 0x$1, 0x$2/;
+ # Only decimal constants on the line, no hex !
+# s/\bDCFS\b[ \t]+([0-9\.\-]+)/.double $1/;
+ s/\bDCFS[ \t]+0x/.word 0x/;
+ s/\bDCFS\b/.float/;
+
+ s/^([A-Za-z_]\w*)[ \t]+DCD/$1 .word/;
+ s/\bDCD\b/.word/;
+ s/^([A-Za-z_]\w*)[ \t]+DCW/$1 .short/;
+ s/\bDCW\b/.short/;
+ s/^([A-Za-z_]\w*)[ \t]+DCB/$1 .byte/;
+ s/\bDCB\b/.byte/;
+ s/^([A-Za-z_]\w*)[ \t]+\%/.comm $1,/;
+ s/^[A-Za-z_\.]\w+/$&:/;
+ s/^(\d+)/$1:/;
+ s/\%(\d+)/$1b_or_f/;
+ s/\%[Bb](\d+)/$1b/;
+ s/\%[Ff](\d+)/$1f/;
+ s/\%[Ff][Tt](\d+)/$1f/;
+ s/&([\dA-Fa-f]+)/0x$1/;
+ if ( /\b2_[01]+\b/ ) {
+ s/\b2_([01]+)\b/conv$1&&&&/g;
+ while ( /[01][01][01][01]&&&&/ ) {
+ s/0000&&&&/&&&&0/g;
+ s/0001&&&&/&&&&1/g;
+ s/0010&&&&/&&&&2/g;
+ s/0011&&&&/&&&&3/g;
+ s/0100&&&&/&&&&4/g;
+ s/0101&&&&/&&&&5/g;
+ s/0110&&&&/&&&&6/g;
+ s/0111&&&&/&&&&7/g;
+ s/1000&&&&/&&&&8/g;
+ s/1001&&&&/&&&&9/g;
+ s/1010&&&&/&&&&A/g;
+ s/1011&&&&/&&&&B/g;
+ s/1100&&&&/&&&&C/g;
+ s/1101&&&&/&&&&D/g;
+ s/1110&&&&/&&&&E/g;
+ s/1111&&&&/&&&&F/g;
+ }
+ s/000&&&&/&&&&0/g;
+ s/001&&&&/&&&&1/g;
+ s/010&&&&/&&&&2/g;
+ s/011&&&&/&&&&3/g;
+ s/100&&&&/&&&&4/g;
+ s/101&&&&/&&&&5/g;
+ s/110&&&&/&&&&6/g;
+ s/111&&&&/&&&&7/g;
+ s/00&&&&/&&&&0/g;
+ s/01&&&&/&&&&1/g;
+ s/10&&&&/&&&&2/g;
+ s/11&&&&/&&&&3/g;
+ s/0&&&&/&&&&0/g;
+ s/1&&&&/&&&&1/g;
+ s/conv&&&&/0x/g;
+ }
+
+ if ( /commandline/)
+ {
+ if( /-bigend/)
+ {
+ $bigend=1;
+ }
+ }
+
+ if ( /\bDCDU\b/ )
+ {
+ my $cmd=$_;
+ my $value;
+ my $prefix;
+ my $w1;
+ my $w2;
+ my $w3;
+ my $w4;
+
+ s/\s+DCDU\b/@ $&/;
+
+ $cmd =~ /\bDCDU\b\s+0x(\d+)/;
+ $value = $1;
+ $value =~ /(\w\w)(\w\w)(\w\w)(\w\w)/;
+ $w1 = $1;
+ $w2 = $2;
+ $w3 = $3;
+ $w4 = $4;
+
+ if( $bigend ne "")
+ {
+ # big endian
+ $prefix = "\t.byte\t0x".$w1.";".
+ "\t.byte\t0x".$w2.";".
+ "\t.byte\t0x".$w3.";".
+ "\t.byte\t0x".$w4."; ";
+ }
+ else
+ {
+ # little endian
+ $prefix = "\t.byte\t0x".$w4.";".
+ "\t.byte\t0x".$w3.";".
+ "\t.byte\t0x".$w2.";".
+ "\t.byte\t0x".$w1."; ";
+ }
+ $_=$prefix.$_;
+ }
+
+ if ( /\badrl\b/i )
+ {
+ s/\badrl\s+(\w+)\s*,\s*(\w+)/ldr $1,=$2/i;
+ $addPadding = 1;
+ }
+ s/\bEND\b/@ END/;
+} continue {
+ printf ("%s", $_) if $printit;
+ if ($addPadding != 0)
+ {
+ printf (" mov r0,r0\n");
+ $addPadding = 0;
+ }
+}
+#If we had a code section, mark that this object doesn't need an executable
+# stack.
+if ($nxstack) {
+ printf (" .section\t.note.GNU-stack,\"\",\%\%progbits\n");
+}
diff --git a/drivers/opus/celt/arm/arm_celt_map.c b/drivers/opus/celt/arm/arm_celt_map.c
new file mode 100644
index 0000000000..31e7d5b319
--- /dev/null
+++ b/drivers/opus/celt/arm/arm_celt_map.c
@@ -0,0 +1,49 @@
+/* Copyright (c) 2010 Xiph.Org Foundation
+ * Copyright (c) 2013 Parrot */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/celt/pitch.h"
+
+#if defined(OPUS_HAVE_RTCD)
+
+# if defined(OPUS_FIXED_POINT)
+opus_val32 (*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *,
+ const opus_val16 *, opus_val32 *, int , int) = {
+ celt_pitch_xcorr_c, /* ARMv4 */
+ MAY_HAVE_EDSP(celt_pitch_xcorr), /* EDSP */
+ MAY_HAVE_MEDIA(celt_pitch_xcorr), /* Media */
+ MAY_HAVE_NEON(celt_pitch_xcorr) /* NEON */
+};
+# else
+# error "Floating-point implementation is not supported by ARM asm yet." \
+ "Reconfigure with --disable-rtcd or send patches."
+# endif
+
+#endif
diff --git a/drivers/opus/celt/arm/armcpu.c b/drivers/opus/celt/arm/armcpu.c
new file mode 100644
index 0000000000..fb7f2421fe
--- /dev/null
+++ b/drivers/opus/celt/arm/armcpu.c
@@ -0,0 +1,174 @@
+/* Copyright (c) 2010 Xiph.Org Foundation
+ * Copyright (c) 2013 Parrot */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* Original code from libtheora modified to suit to Opus */
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#ifdef OPUS_HAVE_RTCD
+
+#include "opus/celt/arm/armcpu.h"
+#include "opus/celt/cpu_support.h"
+#include "opus/celt/os_support.h"
+#include "opus/opus_types.h"
+
+#define OPUS_CPU_ARM_V4 (1)
+#define OPUS_CPU_ARM_EDSP (1<<1)
+#define OPUS_CPU_ARM_MEDIA (1<<2)
+#define OPUS_CPU_ARM_NEON (1<<3)
+
+#if defined(_MSC_VER)
+/*For GetExceptionCode() and EXCEPTION_ILLEGAL_INSTRUCTION.*/
+# define WIN32_LEAN_AND_MEAN
+# define WIN32_EXTRA_LEAN
+# include <windows.h>
+
+static OPUS_INLINE opus_uint32 opus_cpu_capabilities(void){
+ opus_uint32 flags;
+ flags=0;
+ /* MSVC has no OPUS_INLINE __asm support for ARM, but it does let you __emit
+ * instructions via their assembled hex code.
+ * All of these instructions should be essentially nops. */
+# if defined(OPUS_ARM_MAY_HAVE_EDSP)
+ __try{
+ /*PLD [r13]*/
+ __emit(0xF5DDF000);
+ flags|=OPUS_CPU_ARM_EDSP;
+ }
+ __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){
+ /*Ignore exception.*/
+ }
+# if defined(OPUS_ARM_MAY_HAVE_MEDIA)
+ __try{
+ /*SHADD8 r3,r3,r3*/
+ __emit(0xE6333F93);
+ flags|=OPUS_CPU_ARM_MEDIA;
+ }
+ __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){
+ /*Ignore exception.*/
+ }
+# if defined(OPUS_ARM_MAY_HAVE_NEON)
+ __try{
+ /*VORR q0,q0,q0*/
+ __emit(0xF2200150);
+ flags|=OPUS_CPU_ARM_NEON;
+ }
+ __except(GetExceptionCode()==EXCEPTION_ILLEGAL_INSTRUCTION){
+ /*Ignore exception.*/
+ }
+# endif
+# endif
+# endif
+ return flags;
+}
+
+#elif defined(__linux__)
+/* Linux based */
+opus_uint32 opus_cpu_capabilities(void)
+{
+ opus_uint32 flags = 0;
+ FILE *cpuinfo;
+
+ /* Reading /proc/self/auxv would be easier, but that doesn't work reliably on
+ * Android */
+ cpuinfo = fopen("/proc/cpuinfo", "r");
+
+ if(cpuinfo != NULL)
+ {
+ /* 512 should be enough for anybody (it's even enough for all the flags that
+ * x86 has accumulated... so far). */
+ char buf[512];
+
+ while(fgets(buf, 512, cpuinfo) != NULL)
+ {
+# if defined(OPUS_ARM_MAY_HAVE_EDSP) || defined(OPUS_ARM_MAY_HAVE_NEON)
+ /* Search for edsp and neon flag */
+ if(memcmp(buf, "Features", 8) == 0)
+ {
+ char *p;
+# if defined(OPUS_ARM_MAY_HAVE_EDSP)
+ p = strstr(buf, " edsp");
+ if(p != NULL && (p[5] == ' ' || p[5] == '\n'))
+ flags |= OPUS_CPU_ARM_EDSP;
+# endif
+
+# if defined(OPUS_ARM_MAY_HAVE_NEON)
+ p = strstr(buf, " neon");
+ if(p != NULL && (p[5] == ' ' || p[5] == '\n'))
+ flags |= OPUS_CPU_ARM_NEON;
+# endif
+ }
+# endif
+
+# if defined(OPUS_ARM_MAY_HAVE_MEDIA)
+ /* Search for media capabilities (>= ARMv6) */
+ if(memcmp(buf, "CPU architecture:", 17) == 0)
+ {
+ int version;
+ version = atoi(buf+17);
+
+ if(version >= 6)
+ flags |= OPUS_CPU_ARM_MEDIA;
+ }
+# endif
+ }
+
+ fclose(cpuinfo);
+ }
+ return flags;
+}
+#else
+/* The feature registers which can tell us what the processor supports are
+ * accessible in priveleged modes only, so we can't have a general user-space
+ * detection method like on x86.*/
+# error "Configured to use ARM asm but no CPU detection method available for " \
+ "your platform. Reconfigure with --disable-rtcd (or send patches)."
+#endif
+
+int opus_select_arch(void)
+{
+ opus_uint32 flags = opus_cpu_capabilities();
+ int arch = 0;
+
+ if(!(flags & OPUS_CPU_ARM_EDSP))
+ return arch;
+ arch++;
+
+ if(!(flags & OPUS_CPU_ARM_MEDIA))
+ return arch;
+ arch++;
+
+ if(!(flags & OPUS_CPU_ARM_NEON))
+ return arch;
+ arch++;
+
+ return arch;
+}
+
+#endif
diff --git a/drivers/opus/celt/arm/armcpu.h b/drivers/opus/celt/arm/armcpu.h
new file mode 100644
index 0000000000..ac5744606e
--- /dev/null
+++ b/drivers/opus/celt/arm/armcpu.h
@@ -0,0 +1,71 @@
+/* Copyright (c) 2010 Xiph.Org Foundation
+ * Copyright (c) 2013 Parrot */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if !defined(ARMCPU_H)
+# define ARMCPU_H
+
+# if defined(OPUS_ARM_MAY_HAVE_EDSP)
+# define MAY_HAVE_EDSP(name) name ## _edsp
+# else
+# define MAY_HAVE_EDSP(name) name ## _c
+# endif
+
+# if defined(OPUS_ARM_MAY_HAVE_MEDIA)
+# define MAY_HAVE_MEDIA(name) name ## _media
+# else
+# define MAY_HAVE_MEDIA(name) MAY_HAVE_EDSP(name)
+# endif
+
+# if defined(OPUS_ARM_MAY_HAVE_NEON)
+# define MAY_HAVE_NEON(name) name ## _neon
+# else
+# define MAY_HAVE_NEON(name) MAY_HAVE_MEDIA(name)
+# endif
+
+# if defined(OPUS_ARM_PRESUME_EDSP)
+# define PRESUME_EDSP(name) name ## _edsp
+# else
+# define PRESUME_EDSP(name) name ## _c
+# endif
+
+# if defined(OPUS_ARM_PRESUME_MEDIA)
+# define PRESUME_MEDIA(name) name ## _media
+# else
+# define PRESUME_MEDIA(name) PRESUME_EDSP(name)
+# endif
+
+# if defined(OPUS_ARM_PRESUME_NEON)
+# define PRESUME_NEON(name) name ## _neon
+# else
+# define PRESUME_NEON(name) PRESUME_MEDIA(name)
+# endif
+
+# if defined(OPUS_HAVE_RTCD)
+int opus_select_arch(void);
+# endif
+
+#endif
diff --git a/drivers/opus/celt/arm/armopts.s b/drivers/opus/celt/arm/armopts.s
new file mode 100644
index 0000000000..fb9196072a
--- /dev/null
+++ b/drivers/opus/celt/arm/armopts.s
@@ -0,0 +1,37 @@
+/* Copyright (C) 2013 Mozilla Corporation */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+; Set the following to 1 if we have EDSP instructions
+; (LDRD/STRD, etc., ARMv5E and later).
+OPUS_ARM_MAY_HAVE_EDSP *
+
+; Set the following to 1 if we have ARMv6 media instructions.
+OPUS_ARM_MAY_HAVE_MEDIA *
+
+; Set the following to 1 if we have NEON (some ARMv7)
+OPUS_ARM_MAY_HAVE_NEON *
+
+END
diff --git a/drivers/opus/celt/arm/armopts.s.in b/drivers/opus/celt/arm/armopts.s.in
new file mode 100644
index 0000000000..3d8aaf2754
--- /dev/null
+++ b/drivers/opus/celt/arm/armopts.s.in
@@ -0,0 +1,37 @@
+/* Copyright (C) 2013 Mozilla Corporation */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+; Set the following to 1 if we have EDSP instructions
+; (LDRD/STRD, etc., ARMv5E and later).
+OPUS_ARM_MAY_HAVE_EDSP * @OPUS_ARM_MAY_HAVE_EDSP@
+
+; Set the following to 1 if we have ARMv6 media instructions.
+OPUS_ARM_MAY_HAVE_MEDIA * @OPUS_ARM_MAY_HAVE_MEDIA@
+
+; Set the following to 1 if we have NEON (some ARMv7)
+OPUS_ARM_MAY_HAVE_NEON * @OPUS_ARM_MAY_HAVE_NEON@
+
+END
diff --git a/drivers/opus/celt/arm/celt_pitch_xcorr_arm.s b/drivers/opus/celt/arm/celt_pitch_xcorr_arm.s
new file mode 100644
index 0000000000..09917b16bf
--- /dev/null
+++ b/drivers/opus/celt/arm/celt_pitch_xcorr_arm.s
@@ -0,0 +1,545 @@
+; Copyright (c) 2007-2008 CSIRO
+; Copyright (c) 2007-2009 Xiph.Org Foundation
+; Copyright (c) 2013 Parrot
+; Written by Aurélien Zanelli
+;
+; Redistribution and use in source and binary forms, with or without
+; modification, are permitted provided that the following conditions
+; are met:
+;
+; - Redistributions of source code must retain the above copyright
+; notice, this list of conditions and the following disclaimer.
+;
+; - Redistributions in binary form must reproduce the above copyright
+; notice, this list of conditions and the following disclaimer in the
+; documentation and/or other materials provided with the distribution.
+;
+; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+; ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+; OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+; EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+; PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+; LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ AREA |.text|, CODE, READONLY
+
+ GET celt/arm/armopts.s
+
+IF OPUS_ARM_MAY_HAVE_EDSP
+ EXPORT celt_pitch_xcorr_edsp
+ENDIF
+
+IF OPUS_ARM_MAY_HAVE_NEON
+ EXPORT celt_pitch_xcorr_neon
+ENDIF
+
+IF OPUS_ARM_MAY_HAVE_NEON
+
+; Compute sum[k]=sum(x[j]*y[j+k],j=0...len-1), k=0...3
+xcorr_kernel_neon PROC
+ ; input:
+ ; r3 = int len
+ ; r4 = opus_val16 *x
+ ; r5 = opus_val16 *y
+ ; q0 = opus_val32 sum[4]
+ ; output:
+ ; q0 = opus_val32 sum[4]
+ ; preserved: r0-r3, r6-r11, d2, q4-q7, q9-q15
+ ; internal usage:
+ ; r12 = int j
+ ; d3 = y_3|y_2|y_1|y_0
+ ; q2 = y_B|y_A|y_9|y_8|y_7|y_6|y_5|y_4
+ ; q3 = x_7|x_6|x_5|x_4|x_3|x_2|x_1|x_0
+ ; q8 = scratch
+ ;
+ ; Load y[0...3]
+ ; This requires len>0 to always be valid (which we assert in the C code).
+ VLD1.16 {d5}, [r5]!
+ SUBS r12, r3, #8
+ BLE xcorr_kernel_neon_process4
+; Process 8 samples at a time.
+; This loop loads one y value more than we actually need. Therefore we have to
+; stop as soon as there are 8 or fewer samples left (instead of 7), to avoid
+; reading past the end of the array.
+xcorr_kernel_neon_process8
+ ; This loop has 19 total instructions (10 cycles to issue, minimum), with
+ ; - 2 cycles of ARM insrtuctions,
+ ; - 10 cycles of load/store/byte permute instructions, and
+ ; - 9 cycles of data processing instructions.
+ ; On a Cortex A8, we dual-issue the maximum amount (9 cycles) between the
+ ; latter two categories, meaning the whole loop should run in 10 cycles per
+ ; iteration, barring cache misses.
+ ;
+ ; Load x[0...7]
+ VLD1.16 {d6, d7}, [r4]!
+ ; Unlike VMOV, VAND is a data processsing instruction (and doesn't get
+ ; assembled to VMOV, like VORR would), so it dual-issues with the prior VLD1.
+ VAND d3, d5, d5
+ SUBS r12, r12, #8
+ ; Load y[4...11]
+ VLD1.16 {d4, d5}, [r5]!
+ VMLAL.S16 q0, d3, d6[0]
+ VEXT.16 d16, d3, d4, #1
+ VMLAL.S16 q0, d4, d7[0]
+ VEXT.16 d17, d4, d5, #1
+ VMLAL.S16 q0, d16, d6[1]
+ VEXT.16 d16, d3, d4, #2
+ VMLAL.S16 q0, d17, d7[1]
+ VEXT.16 d17, d4, d5, #2
+ VMLAL.S16 q0, d16, d6[2]
+ VEXT.16 d16, d3, d4, #3
+ VMLAL.S16 q0, d17, d7[2]
+ VEXT.16 d17, d4, d5, #3
+ VMLAL.S16 q0, d16, d6[3]
+ VMLAL.S16 q0, d17, d7[3]
+ BGT xcorr_kernel_neon_process8
+; Process 4 samples here if we have > 4 left (still reading one extra y value).
+xcorr_kernel_neon_process4
+ ADDS r12, r12, #4
+ BLE xcorr_kernel_neon_process2
+ ; Load x[0...3]
+ VLD1.16 d6, [r4]!
+ ; Use VAND since it's a data processing instruction again.
+ VAND d4, d5, d5
+ SUB r12, r12, #4
+ ; Load y[4...7]
+ VLD1.16 d5, [r5]!
+ VMLAL.S16 q0, d4, d6[0]
+ VEXT.16 d16, d4, d5, #1
+ VMLAL.S16 q0, d16, d6[1]
+ VEXT.16 d16, d4, d5, #2
+ VMLAL.S16 q0, d16, d6[2]
+ VEXT.16 d16, d4, d5, #3
+ VMLAL.S16 q0, d16, d6[3]
+; Process 2 samples here if we have > 2 left (still reading one extra y value).
+xcorr_kernel_neon_process2
+ ADDS r12, r12, #2
+ BLE xcorr_kernel_neon_process1
+ ; Load x[0...1]
+ VLD2.16 {d6[],d7[]}, [r4]!
+ ; Use VAND since it's a data processing instruction again.
+ VAND d4, d5, d5
+ SUB r12, r12, #2
+ ; Load y[4...5]
+ VLD1.32 {d5[]}, [r5]!
+ VMLAL.S16 q0, d4, d6
+ VEXT.16 d16, d4, d5, #1
+ ; Replace bottom copy of {y5,y4} in d5 with {y3,y2} from d4, using VSRI
+ ; instead of VEXT, since it's a data-processing instruction.
+ VSRI.64 d5, d4, #32
+ VMLAL.S16 q0, d16, d7
+; Process 1 sample using the extra y value we loaded above.
+xcorr_kernel_neon_process1
+ ; Load next *x
+ VLD1.16 {d6[]}, [r4]!
+ ADDS r12, r12, #1
+ ; y[0...3] are left in d5 from prior iteration(s) (if any)
+ VMLAL.S16 q0, d5, d6
+ MOVLE pc, lr
+; Now process 1 last sample, not reading ahead.
+ ; Load last *y
+ VLD1.16 {d4[]}, [r5]!
+ VSRI.64 d4, d5, #16
+ ; Load last *x
+ VLD1.16 {d6[]}, [r4]!
+ VMLAL.S16 q0, d4, d6
+ MOV pc, lr
+ ENDP
+
+; opus_val32 celt_pitch_xcorr_neon(opus_val16 *_x, opus_val16 *_y,
+; opus_val32 *xcorr, int len, int max_pitch)
+celt_pitch_xcorr_neon PROC
+ ; input:
+ ; r0 = opus_val16 *_x
+ ; r1 = opus_val16 *_y
+ ; r2 = opus_val32 *xcorr
+ ; r3 = int len
+ ; output:
+ ; r0 = int maxcorr
+ ; internal usage:
+ ; r4 = opus_val16 *x (for xcorr_kernel_neon())
+ ; r5 = opus_val16 *y (for xcorr_kernel_neon())
+ ; r6 = int max_pitch
+ ; r12 = int j
+ ; q15 = int maxcorr[4] (q15 is not used by xcorr_kernel_neon())
+ STMFD sp!, {r4-r6, lr}
+ LDR r6, [sp, #16]
+ VMOV.S32 q15, #1
+ ; if (max_pitch < 4) goto celt_pitch_xcorr_neon_process4_done
+ SUBS r6, r6, #4
+ BLT celt_pitch_xcorr_neon_process4_done
+celt_pitch_xcorr_neon_process4
+ ; xcorr_kernel_neon parameters:
+ ; r3 = len, r4 = _x, r5 = _y, q0 = {0, 0, 0, 0}
+ MOV r4, r0
+ MOV r5, r1
+ VEOR q0, q0, q0
+ ; xcorr_kernel_neon only modifies r4, r5, r12, and q0...q3.
+ ; So we don't save/restore any other registers.
+ BL xcorr_kernel_neon
+ SUBS r6, r6, #4
+ VST1.32 {q0}, [r2]!
+ ; _y += 4
+ ADD r1, r1, #8
+ VMAX.S32 q15, q15, q0
+ ; if (max_pitch < 4) goto celt_pitch_xcorr_neon_process4_done
+ BGE celt_pitch_xcorr_neon_process4
+; We have less than 4 sums left to compute.
+celt_pitch_xcorr_neon_process4_done
+ ADDS r6, r6, #4
+ ; Reduce maxcorr to a single value
+ VMAX.S32 d30, d30, d31
+ VPMAX.S32 d30, d30, d30
+ ; if (max_pitch <= 0) goto celt_pitch_xcorr_neon_done
+ BLE celt_pitch_xcorr_neon_done
+; Now compute each remaining sum one at a time.
+celt_pitch_xcorr_neon_process_remaining
+ MOV r4, r0
+ MOV r5, r1
+ VMOV.I32 q0, #0
+ SUBS r12, r3, #8
+ BLT celt_pitch_xcorr_neon_process_remaining4
+; Sum terms 8 at a time.
+celt_pitch_xcorr_neon_process_remaining_loop8
+ ; Load x[0...7]
+ VLD1.16 {q1}, [r4]!
+ ; Load y[0...7]
+ VLD1.16 {q2}, [r5]!
+ SUBS r12, r12, #8
+ VMLAL.S16 q0, d4, d2
+ VMLAL.S16 q0, d5, d3
+ BGE celt_pitch_xcorr_neon_process_remaining_loop8
+; Sum terms 4 at a time.
+celt_pitch_xcorr_neon_process_remaining4
+ ADDS r12, r12, #4
+ BLT celt_pitch_xcorr_neon_process_remaining4_done
+ ; Load x[0...3]
+ VLD1.16 {d2}, [r4]!
+ ; Load y[0...3]
+ VLD1.16 {d3}, [r5]!
+ SUB r12, r12, #4
+ VMLAL.S16 q0, d3, d2
+celt_pitch_xcorr_neon_process_remaining4_done
+ ; Reduce the sum to a single value.
+ VADD.S32 d0, d0, d1
+ VPADDL.S32 d0, d0
+ ADDS r12, r12, #4
+ BLE celt_pitch_xcorr_neon_process_remaining_loop_done
+; Sum terms 1 at a time.
+celt_pitch_xcorr_neon_process_remaining_loop1
+ VLD1.16 {d2[]}, [r4]!
+ VLD1.16 {d3[]}, [r5]!
+ SUBS r12, r12, #1
+ VMLAL.S16 q0, d2, d3
+ BGT celt_pitch_xcorr_neon_process_remaining_loop1
+celt_pitch_xcorr_neon_process_remaining_loop_done
+ VST1.32 {d0[0]}, [r2]!
+ VMAX.S32 d30, d30, d0
+ SUBS r6, r6, #1
+ ; _y++
+ ADD r1, r1, #2
+ ; if (--max_pitch > 0) goto celt_pitch_xcorr_neon_process_remaining
+ BGT celt_pitch_xcorr_neon_process_remaining
+celt_pitch_xcorr_neon_done
+ VMOV.32 r0, d30[0]
+ LDMFD sp!, {r4-r6, pc}
+ ENDP
+
+ENDIF
+
+IF OPUS_ARM_MAY_HAVE_EDSP
+
+; This will get used on ARMv7 devices without NEON, so it has been optimized
+; to take advantage of dual-issuing where possible.
+xcorr_kernel_edsp PROC
+ ; input:
+ ; r3 = int len
+ ; r4 = opus_val16 *_x (must be 32-bit aligned)
+ ; r5 = opus_val16 *_y (must be 32-bit aligned)
+ ; r6...r9 = opus_val32 sum[4]
+ ; output:
+ ; r6...r9 = opus_val32 sum[4]
+ ; preserved: r0-r5
+ ; internal usage
+ ; r2 = int j
+ ; r12,r14 = opus_val16 x[4]
+ ; r10,r11 = opus_val16 y[4]
+ STMFD sp!, {r2,r4,r5,lr}
+ LDR r10, [r5], #4 ; Load y[0...1]
+ SUBS r2, r3, #4 ; j = len-4
+ LDR r11, [r5], #4 ; Load y[2...3]
+ BLE xcorr_kernel_edsp_process4_done
+ LDR r12, [r4], #4 ; Load x[0...1]
+ ; Stall
+xcorr_kernel_edsp_process4
+ ; The multiplies must issue from pipeline 0, and can't dual-issue with each
+ ; other. Every other instruction here dual-issues with a multiply, and is
+ ; thus "free". There should be no stalls in the body of the loop.
+ SMLABB r6, r12, r10, r6 ; sum[0] = MAC16_16(sum[0],x_0,y_0)
+ LDR r14, [r4], #4 ; Load x[2...3]
+ SMLABT r7, r12, r10, r7 ; sum[1] = MAC16_16(sum[1],x_0,y_1)
+ SUBS r2, r2, #4 ; j-=4
+ SMLABB r8, r12, r11, r8 ; sum[2] = MAC16_16(sum[2],x_0,y_2)
+ SMLABT r9, r12, r11, r9 ; sum[3] = MAC16_16(sum[3],x_0,y_3)
+ SMLATT r6, r12, r10, r6 ; sum[0] = MAC16_16(sum[0],x_1,y_1)
+ LDR r10, [r5], #4 ; Load y[4...5]
+ SMLATB r7, r12, r11, r7 ; sum[1] = MAC16_16(sum[1],x_1,y_2)
+ SMLATT r8, r12, r11, r8 ; sum[2] = MAC16_16(sum[2],x_1,y_3)
+ SMLATB r9, r12, r10, r9 ; sum[3] = MAC16_16(sum[3],x_1,y_4)
+ LDRGT r12, [r4], #4 ; Load x[0...1]
+ SMLABB r6, r14, r11, r6 ; sum[0] = MAC16_16(sum[0],x_2,y_2)
+ SMLABT r7, r14, r11, r7 ; sum[1] = MAC16_16(sum[1],x_2,y_3)
+ SMLABB r8, r14, r10, r8 ; sum[2] = MAC16_16(sum[2],x_2,y_4)
+ SMLABT r9, r14, r10, r9 ; sum[3] = MAC16_16(sum[3],x_2,y_5)
+ SMLATT r6, r14, r11, r6 ; sum[0] = MAC16_16(sum[0],x_3,y_3)
+ LDR r11, [r5], #4 ; Load y[6...7]
+ SMLATB r7, r14, r10, r7 ; sum[1] = MAC16_16(sum[1],x_3,y_4)
+ SMLATT r8, r14, r10, r8 ; sum[2] = MAC16_16(sum[2],x_3,y_5)
+ SMLATB r9, r14, r11, r9 ; sum[3] = MAC16_16(sum[3],x_3,y_6)
+ BGT xcorr_kernel_edsp_process4
+xcorr_kernel_edsp_process4_done
+ ADDS r2, r2, #4
+ BLE xcorr_kernel_edsp_done
+ LDRH r12, [r4], #2 ; r12 = *x++
+ SUBS r2, r2, #1 ; j--
+ ; Stall
+ SMLABB r6, r12, r10, r6 ; sum[0] = MAC16_16(sum[0],x,y_0)
+ LDRGTH r14, [r4], #2 ; r14 = *x++
+ SMLABT r7, r12, r10, r7 ; sum[1] = MAC16_16(sum[1],x,y_1)
+ SMLABB r8, r12, r11, r8 ; sum[2] = MAC16_16(sum[2],x,y_2)
+ SMLABT r9, r12, r11, r9 ; sum[3] = MAC16_16(sum[3],x,y_3)
+ BLE xcorr_kernel_edsp_done
+ SMLABT r6, r14, r10, r6 ; sum[0] = MAC16_16(sum[0],x,y_1)
+ SUBS r2, r2, #1 ; j--
+ SMLABB r7, r14, r11, r7 ; sum[1] = MAC16_16(sum[1],x,y_2)
+ LDRH r10, [r5], #2 ; r10 = y_4 = *y++
+ SMLABT r8, r14, r11, r8 ; sum[2] = MAC16_16(sum[2],x,y_3)
+ LDRGTH r12, [r4], #2 ; r12 = *x++
+ SMLABB r9, r14, r10, r9 ; sum[3] = MAC16_16(sum[3],x,y_4)
+ BLE xcorr_kernel_edsp_done
+ SMLABB r6, r12, r11, r6 ; sum[0] = MAC16_16(sum[0],tmp,y_2)
+ CMP r2, #1 ; j--
+ SMLABT r7, r12, r11, r7 ; sum[1] = MAC16_16(sum[1],tmp,y_3)
+ LDRH r2, [r5], #2 ; r2 = y_5 = *y++
+ SMLABB r8, r12, r10, r8 ; sum[2] = MAC16_16(sum[2],tmp,y_4)
+ LDRGTH r14, [r4] ; r14 = *x
+ SMLABB r9, r12, r2, r9 ; sum[3] = MAC16_16(sum[3],tmp,y_5)
+ BLE xcorr_kernel_edsp_done
+ SMLABT r6, r14, r11, r6 ; sum[0] = MAC16_16(sum[0],tmp,y_3)
+ LDRH r11, [r5] ; r11 = y_6 = *y
+ SMLABB r7, r14, r10, r7 ; sum[1] = MAC16_16(sum[1],tmp,y_4)
+ SMLABB r8, r14, r2, r8 ; sum[2] = MAC16_16(sum[2],tmp,y_5)
+ SMLABB r9, r14, r11, r9 ; sum[3] = MAC16_16(sum[3],tmp,y_6)
+xcorr_kernel_edsp_done
+ LDMFD sp!, {r2,r4,r5,pc}
+ ENDP
+
+celt_pitch_xcorr_edsp PROC
+ ; input:
+ ; r0 = opus_val16 *_x (must be 32-bit aligned)
+ ; r1 = opus_val16 *_y (only needs to be 16-bit aligned)
+ ; r2 = opus_val32 *xcorr
+ ; r3 = int len
+ ; output:
+ ; r0 = maxcorr
+ ; internal usage
+ ; r4 = opus_val16 *x
+ ; r5 = opus_val16 *y
+ ; r6 = opus_val32 sum0
+ ; r7 = opus_val32 sum1
+ ; r8 = opus_val32 sum2
+ ; r9 = opus_val32 sum3
+ ; r1 = int max_pitch
+ ; r12 = int j
+ STMFD sp!, {r4-r11, lr}
+ MOV r5, r1
+ LDR r1, [sp, #36]
+ MOV r4, r0
+ TST r5, #3
+ ; maxcorr = 1
+ MOV r0, #1
+ BEQ celt_pitch_xcorr_edsp_process1u_done
+; Compute one sum at the start to make y 32-bit aligned.
+ SUBS r12, r3, #4
+ ; r14 = sum = 0
+ MOV r14, #0
+ LDRH r8, [r5], #2
+ BLE celt_pitch_xcorr_edsp_process1u_loop4_done
+ LDR r6, [r4], #4
+ MOV r8, r8, LSL #16
+celt_pitch_xcorr_edsp_process1u_loop4
+ LDR r9, [r5], #4
+ SMLABT r14, r6, r8, r14 ; sum = MAC16_16(sum, x_0, y_0)
+ LDR r7, [r4], #4
+ SMLATB r14, r6, r9, r14 ; sum = MAC16_16(sum, x_1, y_1)
+ LDR r8, [r5], #4
+ SMLABT r14, r7, r9, r14 ; sum = MAC16_16(sum, x_2, y_2)
+ SUBS r12, r12, #4 ; j-=4
+ SMLATB r14, r7, r8, r14 ; sum = MAC16_16(sum, x_3, y_3)
+ LDRGT r6, [r4], #4
+ BGT celt_pitch_xcorr_edsp_process1u_loop4
+ MOV r8, r8, LSR #16
+celt_pitch_xcorr_edsp_process1u_loop4_done
+ ADDS r12, r12, #4
+celt_pitch_xcorr_edsp_process1u_loop1
+ LDRGEH r6, [r4], #2
+ ; Stall
+ SMLABBGE r14, r6, r8, r14 ; sum = MAC16_16(sum, *x, *y)
+ SUBGES r12, r12, #1
+ LDRGTH r8, [r5], #2
+ BGT celt_pitch_xcorr_edsp_process1u_loop1
+ ; Restore _x
+ SUB r4, r4, r3, LSL #1
+ ; Restore and advance _y
+ SUB r5, r5, r3, LSL #1
+ ; maxcorr = max(maxcorr, sum)
+ CMP r0, r14
+ ADD r5, r5, #2
+ MOVLT r0, r14
+ SUBS r1, r1, #1
+ ; xcorr[i] = sum
+ STR r14, [r2], #4
+ BLE celt_pitch_xcorr_edsp_done
+celt_pitch_xcorr_edsp_process1u_done
+ ; if (max_pitch < 4) goto celt_pitch_xcorr_edsp_process2
+ SUBS r1, r1, #4
+ BLT celt_pitch_xcorr_edsp_process2
+celt_pitch_xcorr_edsp_process4
+ ; xcorr_kernel_edsp parameters:
+ ; r3 = len, r4 = _x, r5 = _y, r6...r9 = sum[4] = {0, 0, 0, 0}
+ MOV r6, #0
+ MOV r7, #0
+ MOV r8, #0
+ MOV r9, #0
+ BL xcorr_kernel_edsp ; xcorr_kernel_edsp(_x, _y+i, xcorr+i, len)
+ ; maxcorr = max(maxcorr, sum0, sum1, sum2, sum3)
+ CMP r0, r6
+ ; _y+=4
+ ADD r5, r5, #8
+ MOVLT r0, r6
+ CMP r0, r7
+ MOVLT r0, r7
+ CMP r0, r8
+ MOVLT r0, r8
+ CMP r0, r9
+ MOVLT r0, r9
+ STMIA r2!, {r6-r9}
+ SUBS r1, r1, #4
+ BGE celt_pitch_xcorr_edsp_process4
+celt_pitch_xcorr_edsp_process2
+ ADDS r1, r1, #2
+ BLT celt_pitch_xcorr_edsp_process1a
+ SUBS r12, r3, #4
+ ; {r10, r11} = {sum0, sum1} = {0, 0}
+ MOV r10, #0
+ MOV r11, #0
+ LDR r8, [r5], #4
+ BLE celt_pitch_xcorr_edsp_process2_loop_done
+ LDR r6, [r4], #4
+ LDR r9, [r5], #4
+celt_pitch_xcorr_edsp_process2_loop4
+ SMLABB r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_0, y_0)
+ LDR r7, [r4], #4
+ SMLABT r11, r6, r8, r11 ; sum1 = MAC16_16(sum1, x_0, y_1)
+ SUBS r12, r12, #4 ; j-=4
+ SMLATT r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_1, y_1)
+ LDR r8, [r5], #4
+ SMLATB r11, r6, r9, r11 ; sum1 = MAC16_16(sum1, x_1, y_2)
+ LDRGT r6, [r4], #4
+ SMLABB r10, r7, r9, r10 ; sum0 = MAC16_16(sum0, x_2, y_2)
+ SMLABT r11, r7, r9, r11 ; sum1 = MAC16_16(sum1, x_2, y_3)
+ SMLATT r10, r7, r9, r10 ; sum0 = MAC16_16(sum0, x_3, y_3)
+ LDRGT r9, [r5], #4
+ SMLATB r11, r7, r8, r11 ; sum1 = MAC16_16(sum1, x_3, y_4)
+ BGT celt_pitch_xcorr_edsp_process2_loop4
+celt_pitch_xcorr_edsp_process2_loop_done
+ ADDS r12, r12, #2
+ BLE celt_pitch_xcorr_edsp_process2_1
+ LDR r6, [r4], #4
+ ; Stall
+ SMLABB r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_0, y_0)
+ LDR r9, [r5], #4
+ SMLABT r11, r6, r8, r11 ; sum1 = MAC16_16(sum1, x_0, y_1)
+ SUB r12, r12, #2
+ SMLATT r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_1, y_1)
+ MOV r8, r9
+ SMLATB r11, r6, r9, r11 ; sum1 = MAC16_16(sum1, x_1, y_2)
+celt_pitch_xcorr_edsp_process2_1
+ LDRH r6, [r4], #2
+ ADDS r12, r12, #1
+ ; Stall
+ SMLABB r10, r6, r8, r10 ; sum0 = MAC16_16(sum0, x_0, y_0)
+ LDRGTH r7, [r4], #2
+ SMLABT r11, r6, r8, r11 ; sum1 = MAC16_16(sum1, x_0, y_1)
+ BLE celt_pitch_xcorr_edsp_process2_done
+ LDRH r9, [r5], #2
+ SMLABT r10, r7, r8, r10 ; sum0 = MAC16_16(sum0, x_0, y_1)
+ SMLABB r11, r7, r9, r11 ; sum1 = MAC16_16(sum1, x_0, y_2)
+celt_pitch_xcorr_edsp_process2_done
+ ; Restore _x
+ SUB r4, r4, r3, LSL #1
+ ; Restore and advance _y
+ SUB r5, r5, r3, LSL #1
+ ; maxcorr = max(maxcorr, sum0)
+ CMP r0, r10
+ ADD r5, r5, #2
+ MOVLT r0, r10
+ SUB r1, r1, #2
+ ; maxcorr = max(maxcorr, sum1)
+ CMP r0, r11
+ ; xcorr[i] = sum
+ STR r10, [r2], #4
+ MOVLT r0, r11
+ STR r11, [r2], #4
+celt_pitch_xcorr_edsp_process1a
+ ADDS r1, r1, #1
+ BLT celt_pitch_xcorr_edsp_done
+ SUBS r12, r3, #4
+ ; r14 = sum = 0
+ MOV r14, #0
+ BLT celt_pitch_xcorr_edsp_process1a_loop_done
+ LDR r6, [r4], #4
+ LDR r8, [r5], #4
+ LDR r7, [r4], #4
+ LDR r9, [r5], #4
+celt_pitch_xcorr_edsp_process1a_loop4
+ SMLABB r14, r6, r8, r14 ; sum = MAC16_16(sum, x_0, y_0)
+ SUBS r12, r12, #4 ; j-=4
+ SMLATT r14, r6, r8, r14 ; sum = MAC16_16(sum, x_1, y_1)
+ LDRGE r6, [r4], #4
+ SMLABB r14, r7, r9, r14 ; sum = MAC16_16(sum, x_2, y_2)
+ LDRGE r8, [r5], #4
+ SMLATT r14, r7, r9, r14 ; sum = MAC16_16(sum, x_3, y_3)
+ LDRGE r7, [r4], #4
+ LDRGE r9, [r5], #4
+ BGE celt_pitch_xcorr_edsp_process1a_loop4
+celt_pitch_xcorr_edsp_process1a_loop_done
+ ADDS r12, r12, #2
+ LDRGE r6, [r4], #4
+ LDRGE r8, [r5], #4
+ ; Stall
+ SMLABBGE r14, r6, r8, r14 ; sum = MAC16_16(sum, x_0, y_0)
+ SUBGE r12, r12, #2
+ SMLATTGE r14, r6, r8, r14 ; sum = MAC16_16(sum, x_1, y_1)
+ ADDS r12, r12, #1
+ LDRGEH r6, [r4], #2
+ LDRGEH r8, [r5], #2
+ ; Stall
+ SMLABBGE r14, r6, r8, r14 ; sum = MAC16_16(sum, *x, *y)
+ ; maxcorr = max(maxcorr, sum)
+ CMP r0, r14
+ ; xcorr[i] = sum
+ STR r14, [r2], #4
+ MOVLT r0, r14
+celt_pitch_xcorr_edsp_done
+ LDMFD sp!, {r4-r11, pc}
+ ENDP
+
+ENDIF
+
+END
diff --git a/drivers/opus/celt/arm/fixed_armv4.h b/drivers/opus/celt/arm/fixed_armv4.h
new file mode 100644
index 0000000000..b690bc8cea
--- /dev/null
+++ b/drivers/opus/celt/arm/fixed_armv4.h
@@ -0,0 +1,76 @@
+/* Copyright (C) 2013 Xiph.Org Foundation and contributors */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef FIXED_ARMv4_H
+#define FIXED_ARMv4_H
+
+/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */
+#undef MULT16_32_Q16
+static OPUS_INLINE opus_val32 MULT16_32_Q16_armv4(opus_val16 a, opus_val32 b)
+{
+ unsigned rd_lo;
+ int rd_hi;
+ __asm__(
+ "#MULT16_32_Q16\n\t"
+ "smull %0, %1, %2, %3\n\t"
+ : "=&r"(rd_lo), "=&r"(rd_hi)
+ : "%r"(b),"r"(a<<16)
+ );
+ return rd_hi;
+}
+#define MULT16_32_Q16(a, b) (MULT16_32_Q16_armv4(a, b))
+
+
+/** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */
+#undef MULT16_32_Q15
+static OPUS_INLINE opus_val32 MULT16_32_Q15_armv4(opus_val16 a, opus_val32 b)
+{
+ unsigned rd_lo;
+ int rd_hi;
+ __asm__(
+ "#MULT16_32_Q15\n\t"
+ "smull %0, %1, %2, %3\n\t"
+ : "=&r"(rd_lo), "=&r"(rd_hi)
+ : "%r"(b), "r"(a<<16)
+ );
+ /*We intentionally don't OR in the high bit of rd_lo for speed.*/
+ return rd_hi<<1;
+}
+#define MULT16_32_Q15(a, b) (MULT16_32_Q15_armv4(a, b))
+
+
+/** 16x32 multiply, followed by a 15-bit shift right and 32-bit add.
+ b must fit in 31 bits.
+ Result fits in 32 bits. */
+#undef MAC16_32_Q15
+#define MAC16_32_Q15(c, a, b) ADD32(c, MULT16_32_Q15(a, b))
+
+
+/** 32x32 multiplication, followed by a 31-bit shift right. Results fits in 32 bits */
+#undef MULT32_32_Q31
+#define MULT32_32_Q31(a,b) (opus_val32)((((opus_int64)(a)) * ((opus_int64)(b)))>>31)
+
+#endif
diff --git a/drivers/opus/celt/arm/fixed_armv5e.h b/drivers/opus/celt/arm/fixed_armv5e.h
new file mode 100644
index 0000000000..cb6e4c1da9
--- /dev/null
+++ b/drivers/opus/celt/arm/fixed_armv5e.h
@@ -0,0 +1,116 @@
+/* Copyright (C) 2007-2009 Xiph.Org Foundation
+ Copyright (C) 2003-2008 Jean-Marc Valin
+ Copyright (C) 2007-2008 CSIRO
+ Copyright (C) 2013 Parrot */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef FIXED_ARMv5E_H
+#define FIXED_ARMv5E_H
+
+#include "opus/celt/arm/fixed_armv4.h"
+
+/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */
+#undef MULT16_32_Q16
+static OPUS_INLINE opus_val32 MULT16_32_Q16_armv5e(opus_val16 a, opus_val32 b)
+{
+ int res;
+ __asm__(
+ "#MULT16_32_Q16\n\t"
+ "smulwb %0, %1, %2\n\t"
+ : "=r"(res)
+ : "r"(b),"r"(a)
+ );
+ return res;
+}
+#define MULT16_32_Q16(a, b) (MULT16_32_Q16_armv5e(a, b))
+
+
+/** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */
+#undef MULT16_32_Q15
+static OPUS_INLINE opus_val32 MULT16_32_Q15_armv5e(opus_val16 a, opus_val32 b)
+{
+ int res;
+ __asm__(
+ "#MULT16_32_Q15\n\t"
+ "smulwb %0, %1, %2\n\t"
+ : "=r"(res)
+ : "r"(b), "r"(a)
+ );
+ return res<<1;
+}
+#define MULT16_32_Q15(a, b) (MULT16_32_Q15_armv5e(a, b))
+
+
+/** 16x32 multiply, followed by a 15-bit shift right and 32-bit add.
+ b must fit in 31 bits.
+ Result fits in 32 bits. */
+#undef MAC16_32_Q15
+static OPUS_INLINE opus_val32 MAC16_32_Q15_armv5e(opus_val32 c, opus_val16 a,
+ opus_val32 b)
+{
+ int res;
+ __asm__(
+ "#MAC16_32_Q15\n\t"
+ "smlawb %0, %1, %2, %3;\n"
+ : "=r"(res)
+ : "r"(b<<1), "r"(a), "r"(c)
+ );
+ return res;
+}
+#define MAC16_32_Q15(c, a, b) (MAC16_32_Q15_armv5e(c, a, b))
+
+/** 16x16 multiply-add where the result fits in 32 bits */
+#undef MAC16_16
+static OPUS_INLINE opus_val32 MAC16_16_armv5e(opus_val32 c, opus_val16 a,
+ opus_val16 b)
+{
+ int res;
+ __asm__(
+ "#MAC16_16\n\t"
+ "smlabb %0, %1, %2, %3;\n"
+ : "=r"(res)
+ : "r"(a), "r"(b), "r"(c)
+ );
+ return res;
+}
+#define MAC16_16(c, a, b) (MAC16_16_armv5e(c, a, b))
+
+/** 16x16 multiplication where the result fits in 32 bits */
+#undef MULT16_16
+static OPUS_INLINE opus_val32 MULT16_16_armv5e(opus_val16 a, opus_val16 b)
+{
+ int res;
+ __asm__(
+ "#MULT16_16\n\t"
+ "smulbb %0, %1, %2;\n"
+ : "=r"(res)
+ : "r"(a), "r"(b)
+ );
+ return res;
+}
+#define MULT16_16(a, b) (MULT16_16_armv5e(a, b))
+
+#endif
diff --git a/drivers/opus/celt/arm/kiss_fft_armv4.h b/drivers/opus/celt/arm/kiss_fft_armv4.h
new file mode 100644
index 0000000000..773464628b
--- /dev/null
+++ b/drivers/opus/celt/arm/kiss_fft_armv4.h
@@ -0,0 +1,121 @@
+/*Copyright (c) 2013, Xiph.Org Foundation and contributors.
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.*/
+
+#ifndef KISS_FFT_ARMv4_H
+#define KISS_FFT_ARMv4_H
+
+#if !defined(KISS_FFT_GUTS_H)
+#error "This file should only be included from _kiss_fft_guts.h"
+#endif
+
+#ifdef OPUS_FIXED_POINT
+
+#undef C_MUL
+#define C_MUL(m,a,b) \
+ do{ \
+ int br__; \
+ int bi__; \
+ int tt__; \
+ __asm__ __volatile__( \
+ "#C_MUL\n\t" \
+ "ldrsh %[br], [%[bp], #0]\n\t" \
+ "ldm %[ap], {r0,r1}\n\t" \
+ "ldrsh %[bi], [%[bp], #2]\n\t" \
+ "smull %[tt], %[mi], r1, %[br]\n\t" \
+ "smlal %[tt], %[mi], r0, %[bi]\n\t" \
+ "rsb %[bi], %[bi], #0\n\t" \
+ "smull %[br], %[mr], r0, %[br]\n\t" \
+ "mov %[tt], %[tt], lsr #15\n\t" \
+ "smlal %[br], %[mr], r1, %[bi]\n\t" \
+ "orr %[mi], %[tt], %[mi], lsl #17\n\t" \
+ "mov %[br], %[br], lsr #15\n\t" \
+ "orr %[mr], %[br], %[mr], lsl #17\n\t" \
+ : [mr]"=r"((m).r), [mi]"=r"((m).i), \
+ [br]"=&r"(br__), [bi]"=r"(bi__), [tt]"=r"(tt__) \
+ : [ap]"r"(&(a)), [bp]"r"(&(b)) \
+ : "r0", "r1" \
+ ); \
+ } \
+ while(0)
+
+#undef C_MUL4
+#define C_MUL4(m,a,b) \
+ do{ \
+ int br__; \
+ int bi__; \
+ int tt__; \
+ __asm__ __volatile__( \
+ "#C_MUL4\n\t" \
+ "ldrsh %[br], [%[bp], #0]\n\t" \
+ "ldm %[ap], {r0,r1}\n\t" \
+ "ldrsh %[bi], [%[bp], #2]\n\t" \
+ "smull %[tt], %[mi], r1, %[br]\n\t" \
+ "smlal %[tt], %[mi], r0, %[bi]\n\t" \
+ "rsb %[bi], %[bi], #0\n\t" \
+ "smull %[br], %[mr], r0, %[br]\n\t" \
+ "mov %[tt], %[tt], lsr #17\n\t" \
+ "smlal %[br], %[mr], r1, %[bi]\n\t" \
+ "orr %[mi], %[tt], %[mi], lsl #15\n\t" \
+ "mov %[br], %[br], lsr #17\n\t" \
+ "orr %[mr], %[br], %[mr], lsl #15\n\t" \
+ : [mr]"=r"((m).r), [mi]"=r"((m).i), \
+ [br]"=&r"(br__), [bi]"=r"(bi__), [tt]"=r"(tt__) \
+ : [ap]"r"(&(a)), [bp]"r"(&(b)) \
+ : "r0", "r1" \
+ ); \
+ } \
+ while(0)
+
+#undef C_MULC
+#define C_MULC(m,a,b) \
+ do{ \
+ int br__; \
+ int bi__; \
+ int tt__; \
+ __asm__ __volatile__( \
+ "#C_MULC\n\t" \
+ "ldrsh %[br], [%[bp], #0]\n\t" \
+ "ldm %[ap], {r0,r1}\n\t" \
+ "ldrsh %[bi], [%[bp], #2]\n\t" \
+ "smull %[tt], %[mr], r0, %[br]\n\t" \
+ "smlal %[tt], %[mr], r1, %[bi]\n\t" \
+ "rsb %[bi], %[bi], #0\n\t" \
+ "smull %[br], %[mi], r1, %[br]\n\t" \
+ "mov %[tt], %[tt], lsr #15\n\t" \
+ "smlal %[br], %[mi], r0, %[bi]\n\t" \
+ "orr %[mr], %[tt], %[mr], lsl #17\n\t" \
+ "mov %[br], %[br], lsr #15\n\t" \
+ "orr %[mi], %[br], %[mi], lsl #17\n\t" \
+ : [mr]"=r"((m).r), [mi]"=r"((m).i), \
+ [br]"=&r"(br__), [bi]"=r"(bi__), [tt]"=r"(tt__) \
+ : [ap]"r"(&(a)), [bp]"r"(&(b)) \
+ : "r0", "r1" \
+ ); \
+ } \
+ while(0)
+
+#endif /* OPUS_FIXED_POINT */
+
+#endif /* KISS_FFT_ARMv4_H */
diff --git a/drivers/opus/celt/arm/kiss_fft_armv5e.h b/drivers/opus/celt/arm/kiss_fft_armv5e.h
new file mode 100644
index 0000000000..1eff56a66a
--- /dev/null
+++ b/drivers/opus/celt/arm/kiss_fft_armv5e.h
@@ -0,0 +1,118 @@
+/*Copyright (c) 2013, Xiph.Org Foundation and contributors.
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.*/
+
+#ifndef KISS_FFT_ARMv5E_H
+#define KISS_FFT_ARMv5E_H
+
+#if !defined(KISS_FFT_GUTS_H)
+#error "This file should only be included from _kiss_fft_guts.h"
+#endif
+
+#ifdef OPUS_FIXED_POINT
+
+#if defined(__thumb__)||defined(__thumb2__)
+#define LDRD_CONS "Q"
+#else
+#define LDRD_CONS "Uq"
+#endif
+
+#undef C_MUL
+#define C_MUL(m,a,b) \
+ do{ \
+ int mr1__; \
+ int mr2__; \
+ int mi__; \
+ long long aval__; \
+ int bval__; \
+ __asm__( \
+ "#C_MUL\n\t" \
+ "ldrd %[aval], %H[aval], %[ap]\n\t" \
+ "ldr %[bval], %[bp]\n\t" \
+ "smulwb %[mi], %H[aval], %[bval]\n\t" \
+ "smulwb %[mr1], %[aval], %[bval]\n\t" \
+ "smulwt %[mr2], %H[aval], %[bval]\n\t" \
+ "smlawt %[mi], %[aval], %[bval], %[mi]\n\t" \
+ : [mr1]"=r"(mr1__), [mr2]"=r"(mr2__), [mi]"=r"(mi__), \
+ [aval]"=&r"(aval__), [bval]"=r"(bval__) \
+ : [ap]LDRD_CONS(a), [bp]"m"(b) \
+ ); \
+ (m).r = SHL32(SUB32(mr1__, mr2__), 1); \
+ (m).i = SHL32(mi__, 1); \
+ } \
+ while(0)
+
+#undef C_MUL4
+#define C_MUL4(m,a,b) \
+ do{ \
+ int mr1__; \
+ int mr2__; \
+ int mi__; \
+ long long aval__; \
+ int bval__; \
+ __asm__( \
+ "#C_MUL4\n\t" \
+ "ldrd %[aval], %H[aval], %[ap]\n\t" \
+ "ldr %[bval], %[bp]\n\t" \
+ "smulwb %[mi], %H[aval], %[bval]\n\t" \
+ "smulwb %[mr1], %[aval], %[bval]\n\t" \
+ "smulwt %[mr2], %H[aval], %[bval]\n\t" \
+ "smlawt %[mi], %[aval], %[bval], %[mi]\n\t" \
+ : [mr1]"=r"(mr1__), [mr2]"=r"(mr2__), [mi]"=r"(mi__), \
+ [aval]"=&r"(aval__), [bval]"=r"(bval__) \
+ : [ap]LDRD_CONS(a), [bp]"m"(b) \
+ ); \
+ (m).r = SHR32(SUB32(mr1__, mr2__), 1); \
+ (m).i = SHR32(mi__, 1); \
+ } \
+ while(0)
+
+#undef C_MULC
+#define C_MULC(m,a,b) \
+ do{ \
+ int mr__; \
+ int mi1__; \
+ int mi2__; \
+ long long aval__; \
+ int bval__; \
+ __asm__( \
+ "#C_MULC\n\t" \
+ "ldrd %[aval], %H[aval], %[ap]\n\t" \
+ "ldr %[bval], %[bp]\n\t" \
+ "smulwb %[mr], %[aval], %[bval]\n\t" \
+ "smulwb %[mi1], %H[aval], %[bval]\n\t" \
+ "smulwt %[mi2], %[aval], %[bval]\n\t" \
+ "smlawt %[mr], %H[aval], %[bval], %[mr]\n\t" \
+ : [mr]"=r"(mr__), [mi1]"=r"(mi1__), [mi2]"=r"(mi2__), \
+ [aval]"=&r"(aval__), [bval]"=r"(bval__) \
+ : [ap]LDRD_CONS(a), [bp]"m"(b) \
+ ); \
+ (m).r = SHL32(mr__, 1); \
+ (m).i = SHL32(SUB32(mi1__, mi2__), 1); \
+ } \
+ while(0)
+
+#endif /* OPUS_FIXED_POINT */
+
+#endif /* KISS_FFT_GUTS_H */
diff --git a/drivers/opus/celt/arm/pitch_arm.h b/drivers/opus/celt/arm/pitch_arm.h
new file mode 100644
index 0000000000..18d1f2e75e
--- /dev/null
+++ b/drivers/opus/celt/arm/pitch_arm.h
@@ -0,0 +1,57 @@
+/* Copyright (c) 2010 Xiph.Org Foundation
+ * Copyright (c) 2013 Parrot */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if !defined(PITCH_ARM_H)
+# define PITCH_ARM_H
+
+# include "opus/celt/arm/armcpu.h"
+
+# if defined(OPUS_FIXED_POINT)
+
+# if defined(OPUS_ARM_MAY_HAVE_NEON)
+opus_val32 celt_pitch_xcorr_neon(const opus_val16 *_x, const opus_val16 *_y,
+ opus_val32 *xcorr, int len, int max_pitch);
+# endif
+
+# if defined(OPUS_ARM_MAY_HAVE_MEDIA)
+# define celt_pitch_xcorr_media MAY_HAVE_EDSP(celt_pitch_xcorr)
+# endif
+
+# if defined(OPUS_ARM_MAY_HAVE_EDSP)
+opus_val32 celt_pitch_xcorr_edsp(const opus_val16 *_x, const opus_val16 *_y,
+ opus_val32 *xcorr, int len, int max_pitch);
+# endif
+
+# if !defined(OPUS_HAVE_RTCD)
+# define OVERRIDE_PITCH_XCORR (1)
+# define celt_pitch_xcorr(_x, _y, xcorr, len, max_pitch, arch) \
+ ((void)(arch),PRESUME_NEON(celt_pitch_xcorr)(_x, _y, xcorr, len, max_pitch))
+# endif
+
+# endif
+
+#endif
diff --git a/drivers/opus/celt/bands.c b/drivers/opus/celt/bands.c
new file mode 100644
index 0000000000..5a6b23d87f
--- /dev/null
+++ b/drivers/opus/celt/bands.c
@@ -0,0 +1,1518 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Copyright (c) 2008-2009 Gregory Maxwell
+ Written by Jean-Marc Valin and Gregory Maxwell */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include <math.h>
+#include "opus/celt/bands.h"
+#include "opus/celt/opus_modes.h"
+#include "opus/celt/vq.h"
+#include "opus/celt/cwrs.h"
+#include "opus/celt/stack_alloc.h"
+#include "opus/celt/os_support.h"
+#include "opus/celt/mathops.h"
+#include "opus/celt/rate.h"
+#include "opus/celt/quant_bands.h"
+#include "opus/celt/pitch.h"
+
+int hysteresis_decision(opus_val16 val, const opus_val16 *thresholds, const opus_val16 *hysteresis, int N, int prev)
+{
+ int i;
+ for (i=0;i<N;i++)
+ {
+ if (val < thresholds[i])
+ break;
+ }
+ if (i>prev && val < thresholds[prev]+hysteresis[prev])
+ i=prev;
+ if (i<prev && val > thresholds[prev-1]-hysteresis[prev-1])
+ i=prev;
+ return i;
+}
+
+opus_uint32 celt_lcg_rand(opus_uint32 seed)
+{
+ return 1664525 * seed + 1013904223;
+}
+
+/* This is a cos() approximation designed to be bit-exact on any platform. Bit exactness
+ with this approximation is important because it has an impact on the bit allocation */
+static opus_int16 bitexact_cos(opus_int16 x)
+{
+ opus_int32 tmp;
+ opus_int16 x2;
+ tmp = (4096+((opus_int32)(x)*(x)))>>13;
+ celt_assert(tmp<=32767);
+ x2 = tmp;
+ x2 = (32767-x2) + FRAC_MUL16(x2, (-7651 + FRAC_MUL16(x2, (8277 + FRAC_MUL16(-626, x2)))));
+ celt_assert(x2<=32766);
+ return 1+x2;
+}
+
+static int bitexact_log2tan(int isin,int icos)
+{
+ int lc;
+ int ls;
+ lc=EC_ILOG(icos);
+ ls=EC_ILOG(isin);
+ icos<<=15-lc;
+ isin<<=15-ls;
+ return (ls-lc)*(1<<11)
+ +FRAC_MUL16(isin, FRAC_MUL16(isin, -2597) + 7932)
+ -FRAC_MUL16(icos, FRAC_MUL16(icos, -2597) + 7932);
+}
+
+#ifdef OPUS_FIXED_POINT
+/* Compute the amplitude (sqrt energy) in each of the bands */
+void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *bandE, int end, int C, int M)
+{
+ int i, c, N;
+ const opus_int16 *eBands = m->eBands;
+ N = M*m->shortMdctSize;
+ c=0; do {
+ for (i=0;i<end;i++)
+ {
+ int j;
+ opus_val32 maxval=0;
+ opus_val32 sum = 0;
+
+ j=M*eBands[i]; do {
+ maxval = MAX32(maxval, X[j+c*N]);
+ maxval = MAX32(maxval, -X[j+c*N]);
+ } while (++j<M*eBands[i+1]);
+
+ if (maxval > 0)
+ {
+ int shift = celt_ilog2(maxval)-10;
+ j=M*eBands[i]; do {
+ sum = MAC16_16(sum, EXTRACT16(VSHR32(X[j+c*N],shift)),
+ EXTRACT16(VSHR32(X[j+c*N],shift)));
+ } while (++j<M*eBands[i+1]);
+ /* We're adding one here to ensure the normalized band isn't larger than unity norm */
+ bandE[i+c*m->nbEBands] = EPSILON+VSHR32(EXTEND32(celt_sqrt(sum)),-shift);
+ } else {
+ bandE[i+c*m->nbEBands] = EPSILON;
+ }
+ /*printf ("%f ", bandE[i+c*m->nbEBands]);*/
+ }
+ } while (++c<C);
+ /*printf ("\n");*/
+}
+
+/* Normalise each band such that the energy is one. */
+void normalise_bands(const CELTMode *m, const celt_sig * OPUS_RESTRICT freq, celt_norm * OPUS_RESTRICT X, const celt_ener *bandE, int end, int C, int M)
+{
+ int i, c, N;
+ const opus_int16 *eBands = m->eBands;
+ N = M*m->shortMdctSize;
+ c=0; do {
+ i=0; do {
+ opus_val16 g;
+ int j,shift;
+ opus_val16 E;
+ shift = celt_zlog2(bandE[i+c*m->nbEBands])-13;
+ E = VSHR32(bandE[i+c*m->nbEBands], shift);
+ g = EXTRACT16(celt_rcp(SHL32(E,3)));
+ j=M*eBands[i]; do {
+ X[j+c*N] = MULT16_16_Q15(VSHR32(freq[j+c*N],shift-1),g);
+ } while (++j<M*eBands[i+1]);
+ } while (++i<end);
+ } while (++c<C);
+}
+
+#else /* OPUS_FIXED_POINT */
+/* Compute the amplitude (sqrt energy) in each of the bands */
+void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *bandE, int end, int C, int M)
+{
+ int i, c, N;
+ const opus_int16 *eBands = m->eBands;
+ N = M*m->shortMdctSize;
+ c=0; do {
+ for (i=0;i<end;i++)
+ {
+ int j;
+ opus_val32 sum = 1e-27f;
+ for (j=M*eBands[i];j<M*eBands[i+1];j++)
+ sum += X[j+c*N]*X[j+c*N];
+ bandE[i+c*m->nbEBands] = celt_sqrt(sum);
+ /*printf ("%f ", bandE[i+c*m->nbEBands]);*/
+ }
+ } while (++c<C);
+ /*printf ("\n");*/
+}
+
+/* Normalise each band such that the energy is one. */
+void normalise_bands(const CELTMode *m, const celt_sig * OPUS_RESTRICT freq, celt_norm * OPUS_RESTRICT X, const celt_ener *bandE, int end, int C, int M)
+{
+ int i, c, N;
+ const opus_int16 *eBands = m->eBands;
+ N = M*m->shortMdctSize;
+ c=0; do {
+ for (i=0;i<end;i++)
+ {
+ int j;
+ opus_val16 g = 1.f/(1e-27f+bandE[i+c*m->nbEBands]);
+ for (j=M*eBands[i];j<M*eBands[i+1];j++)
+ X[j+c*N] = freq[j+c*N]*g;
+ }
+ } while (++c<C);
+}
+
+#endif /* OPUS_FIXED_POINT */
+
+/* De-normalise the energy to produce the synthesis from the unit-energy bands */
+void denormalise_bands(const CELTMode *m, const celt_norm * OPUS_RESTRICT X,
+ celt_sig * OPUS_RESTRICT freq, const opus_val16 *bandLogE, int start, int end, int C, int M)
+{
+ int i, c, N;
+ const opus_int16 *eBands = m->eBands;
+ N = M*m->shortMdctSize;
+ celt_assert2(C<=2, "denormalise_bands() not implemented for >2 channels");
+ c=0; do {
+ celt_sig * OPUS_RESTRICT f;
+ const celt_norm * OPUS_RESTRICT x;
+ f = freq+c*N;
+ x = X+c*N+M*eBands[start];
+ for (i=0;i<M*eBands[start];i++)
+ *f++ = 0;
+ for (i=start;i<end;i++)
+ {
+ int j, band_end;
+ opus_val16 g;
+ opus_val16 lg;
+#ifdef OPUS_FIXED_POINT
+ int shift;
+#endif
+ j=M*eBands[i];
+ band_end = M*eBands[i+1];
+ lg = ADD16(bandLogE[i+c*m->nbEBands], SHL16((opus_val16)eMeans[i],6));
+#ifndef OPUS_FIXED_POINT
+ g = celt_exp2(lg);
+#else
+ /* Handle the integer part of the log energy */
+ shift = 16-(lg>>DB_SHIFT);
+ if (shift>31)
+ {
+ shift=0;
+ g=0;
+ } else {
+ /* Handle the fractional part. */
+ g = celt_exp2_frac(lg&((1<<DB_SHIFT)-1));
+ }
+ /* Handle extreme gains with negative shift. */
+ if (shift<0)
+ {
+ /* For shift < -2 we'd be likely to overflow, so we're capping
+ the gain here. This shouldn't happen unless the bitstream is
+ already corrupted. */
+ if (shift < -2)
+ {
+ g = 32767;
+ shift = -2;
+ }
+ do {
+ *f++ = SHL32(MULT16_16(*x++, g), -shift);
+ } while (++j<band_end);
+ } else
+#endif
+ /* Be careful of the fixed-point "else" just above when changing this code */
+ do {
+ *f++ = SHR32(MULT16_16(*x++, g), shift);
+ } while (++j<band_end);
+ }
+ celt_assert(start <= end);
+ for (i=M*eBands[end];i<N;i++)
+ *f++ = 0;
+ } while (++c<C);
+}
+
+/* This prevents energy collapse for transients with multiple short MDCTs */
+void anti_collapse(const CELTMode *m, celt_norm *X_, unsigned char *collapse_masks, int LM, int C, int size,
+ int start, int end, opus_val16 *logE, opus_val16 *prev1logE,
+ opus_val16 *prev2logE, int *pulses, opus_uint32 seed)
+{
+ int c, i, j, k;
+ for (i=start;i<end;i++)
+ {
+ int N0;
+ opus_val16 thresh, sqrt_1;
+ int depth;
+#ifdef OPUS_FIXED_POINT
+ int shift;
+ opus_val32 thresh32;
+#endif
+
+ N0 = m->eBands[i+1]-m->eBands[i];
+ /* depth in 1/8 bits */
+ depth = (1+pulses[i])/((m->eBands[i+1]-m->eBands[i])<<LM);
+
+#ifdef OPUS_FIXED_POINT
+ thresh32 = SHR32(celt_exp2(-SHL16(depth, 10-BITRES)),1);
+ thresh = MULT16_32_Q15(QCONST16(0.5f, 15), MIN32(32767,thresh32));
+ {
+ opus_val32 t;
+ t = N0<<LM;
+ shift = celt_ilog2(t)>>1;
+ t = SHL32(t, (7-shift)<<1);
+ sqrt_1 = celt_rsqrt_norm(t);
+ }
+#else
+ thresh = .5f*celt_exp2(-.125f*depth);
+ sqrt_1 = celt_rsqrt(N0<<LM);
+#endif
+
+ c=0; do
+ {
+ celt_norm *X;
+ opus_val16 prev1;
+ opus_val16 prev2;
+ opus_val32 Ediff;
+ opus_val16 r;
+ int renormalize=0;
+ prev1 = prev1logE[c*m->nbEBands+i];
+ prev2 = prev2logE[c*m->nbEBands+i];
+ if (C==1)
+ {
+ prev1 = MAX16(prev1,prev1logE[m->nbEBands+i]);
+ prev2 = MAX16(prev2,prev2logE[m->nbEBands+i]);
+ }
+ Ediff = EXTEND32(logE[c*m->nbEBands+i])-EXTEND32(MIN16(prev1,prev2));
+ Ediff = MAX32(0, Ediff);
+
+#ifdef OPUS_FIXED_POINT
+ if (Ediff < 16384)
+ {
+ opus_val32 r32 = SHR32(celt_exp2(-EXTRACT16(Ediff)),1);
+ r = 2*MIN16(16383,r32);
+ } else {
+ r = 0;
+ }
+ if (LM==3)
+ r = MULT16_16_Q14(23170, MIN32(23169, r));
+ r = SHR16(MIN16(thresh, r),1);
+ r = SHR32(MULT16_16_Q15(sqrt_1, r),shift);
+#else
+ /* r needs to be multiplied by 2 or 2*sqrt(2) depending on LM because
+ short blocks don't have the same energy as long */
+ r = 2.f*celt_exp2(-Ediff);
+ if (LM==3)
+ r *= 1.41421356f;
+ r = MIN16(thresh, r);
+ r = r*sqrt_1;
+#endif
+ X = X_+c*size+(m->eBands[i]<<LM);
+ for (k=0;k<1<<LM;k++)
+ {
+ /* Detect collapse */
+ if (!(collapse_masks[i*C+c]&1<<k))
+ {
+ /* Fill with noise */
+ for (j=0;j<N0;j++)
+ {
+ seed = celt_lcg_rand(seed);
+ X[(j<<LM)+k] = (seed&0x8000 ? r : -r);
+ }
+ renormalize = 1;
+ }
+ }
+ /* We just added some energy, so we need to renormalise */
+ if (renormalize)
+ renormalise_vector(X, N0<<LM, Q15ONE);
+ } while (++c<C);
+ }
+}
+
+static void intensity_stereo(const CELTMode *m, celt_norm *X, celt_norm *Y, const celt_ener *bandE, int bandID, int N)
+{
+ int i = bandID;
+ int j;
+ opus_val16 a1, a2;
+ opus_val16 left, right;
+ opus_val16 norm;
+#ifdef OPUS_FIXED_POINT
+ int shift = celt_zlog2(MAX32(bandE[i], bandE[i+m->nbEBands]))-13;
+#endif
+ left = VSHR32(bandE[i],shift);
+ right = VSHR32(bandE[i+m->nbEBands],shift);
+ norm = EPSILON + celt_sqrt(EPSILON+MULT16_16(left,left)+MULT16_16(right,right));
+ a1 = DIV32_16(SHL32(EXTEND32(left),14),norm);
+ a2 = DIV32_16(SHL32(EXTEND32(right),14),norm);
+ for (j=0;j<N;j++)
+ {
+ celt_norm r, l;
+ l = X[j];
+ r = Y[j];
+ X[j] = MULT16_16_Q14(a1,l) + MULT16_16_Q14(a2,r);
+ /* Side is not encoded, no need to calculate */
+ }
+}
+
+static void stereo_split(celt_norm *X, celt_norm *Y, int N)
+{
+ int j;
+ for (j=0;j<N;j++)
+ {
+ celt_norm r, l;
+ l = MULT16_16_Q15(QCONST16(.70710678f,15), X[j]);
+ r = MULT16_16_Q15(QCONST16(.70710678f,15), Y[j]);
+ X[j] = l+r;
+ Y[j] = r-l;
+ }
+}
+
+static void stereo_merge(celt_norm *X, celt_norm *Y, opus_val16 mid, int N)
+{
+ int j;
+ opus_val32 xp=0, side=0;
+ opus_val32 El, Er;
+ opus_val16 mid2;
+#ifdef OPUS_FIXED_POINT
+ int kl, kr;
+#endif
+ opus_val32 t, lgain, rgain;
+
+ /* Compute the norm of X+Y and X-Y as |X|^2 + |Y|^2 +/- sum(xy) */
+ dual_inner_prod(Y, X, Y, N, &xp, &side);
+ /* Compensating for the mid normalization */
+ xp = MULT16_32_Q15(mid, xp);
+ /* mid and side are in Q15, not Q14 like X and Y */
+ mid2 = SHR32(mid, 1);
+ El = MULT16_16(mid2, mid2) + side - 2*xp;
+ Er = MULT16_16(mid2, mid2) + side + 2*xp;
+ if (Er < QCONST32(6e-4f, 28) || El < QCONST32(6e-4f, 28))
+ {
+ for (j=0;j<N;j++)
+ Y[j] = X[j];
+ return;
+ }
+
+#ifdef OPUS_FIXED_POINT
+ kl = celt_ilog2(El)>>1;
+ kr = celt_ilog2(Er)>>1;
+#endif
+ t = VSHR32(El, (kl-7)<<1);
+ lgain = celt_rsqrt_norm(t);
+ t = VSHR32(Er, (kr-7)<<1);
+ rgain = celt_rsqrt_norm(t);
+
+#ifdef OPUS_FIXED_POINT
+ if (kl < 7)
+ kl = 7;
+ if (kr < 7)
+ kr = 7;
+#endif
+
+ for (j=0;j<N;j++)
+ {
+ celt_norm r, l;
+ /* Apply mid scaling (side is already scaled) */
+ l = MULT16_16_Q15(mid, X[j]);
+ r = Y[j];
+ X[j] = EXTRACT16(PSHR32(MULT16_16(lgain, SUB16(l,r)), kl+1));
+ Y[j] = EXTRACT16(PSHR32(MULT16_16(rgain, ADD16(l,r)), kr+1));
+ }
+}
+
+/* Decide whether we should spread the pulses in the current frame */
+int spreading_decision(const CELTMode *m, celt_norm *X, int *average,
+ int last_decision, int *hf_average, int *tapset_decision, int update_hf,
+ int end, int C, int M)
+{
+ int i, c, N0;
+ int sum = 0, nbBands=0;
+ const opus_int16 * OPUS_RESTRICT eBands = m->eBands;
+ int decision;
+ int hf_sum=0;
+
+ celt_assert(end>0);
+
+ N0 = M*m->shortMdctSize;
+
+ if (M*(eBands[end]-eBands[end-1]) <= 8)
+ return SPREAD_NONE;
+ c=0; do {
+ for (i=0;i<end;i++)
+ {
+ int j, N, tmp=0;
+ int tcount[3] = {0,0,0};
+ celt_norm * OPUS_RESTRICT x = X+M*eBands[i]+c*N0;
+ N = M*(eBands[i+1]-eBands[i]);
+ if (N<=8)
+ continue;
+ /* Compute rough CDF of |x[j]| */
+ for (j=0;j<N;j++)
+ {
+ opus_val32 x2N; /* Q13 */
+
+ x2N = MULT16_16(MULT16_16_Q15(x[j], x[j]), N);
+ if (x2N < QCONST16(0.25f,13))
+ tcount[0]++;
+ if (x2N < QCONST16(0.0625f,13))
+ tcount[1]++;
+ if (x2N < QCONST16(0.015625f,13))
+ tcount[2]++;
+ }
+
+ /* Only include four last bands (8 kHz and up) */
+ if (i>m->nbEBands-4)
+ hf_sum += 32*(tcount[1]+tcount[0])/N;
+ tmp = (2*tcount[2] >= N) + (2*tcount[1] >= N) + (2*tcount[0] >= N);
+ sum += tmp*256;
+ nbBands++;
+ }
+ } while (++c<C);
+
+ if (update_hf)
+ {
+ if (hf_sum)
+ hf_sum /= C*(4-m->nbEBands+end);
+ *hf_average = (*hf_average+hf_sum)>>1;
+ hf_sum = *hf_average;
+ if (*tapset_decision==2)
+ hf_sum += 4;
+ else if (*tapset_decision==0)
+ hf_sum -= 4;
+ if (hf_sum > 22)
+ *tapset_decision=2;
+ else if (hf_sum > 18)
+ *tapset_decision=1;
+ else
+ *tapset_decision=0;
+ }
+ /*printf("%d %d %d\n", hf_sum, *hf_average, *tapset_decision);*/
+ celt_assert(nbBands>0); /* end has to be non-zero */
+ sum /= nbBands;
+ /* Recursive averaging */
+ sum = (sum+*average)>>1;
+ *average = sum;
+ /* Hysteresis */
+ sum = (3*sum + (((3-last_decision)<<7) + 64) + 2)>>2;
+ if (sum < 80)
+ {
+ decision = SPREAD_AGGRESSIVE;
+ } else if (sum < 256)
+ {
+ decision = SPREAD_NORMAL;
+ } else if (sum < 384)
+ {
+ decision = SPREAD_LIGHT;
+ } else {
+ decision = SPREAD_NONE;
+ }
+#ifdef FUZZING
+ decision = rand()&0x3;
+ *tapset_decision=rand()%3;
+#endif
+ return decision;
+}
+
+/* Indexing table for converting from natural Hadamard to ordery Hadamard
+ This is essentially a bit-reversed Gray, on top of which we've added
+ an inversion of the order because we want the DC at the end rather than
+ the beginning. The lines are for N=2, 4, 8, 16 */
+static const int ordery_table[] = {
+ 1, 0,
+ 3, 0, 2, 1,
+ 7, 0, 4, 3, 6, 1, 5, 2,
+ 15, 0, 8, 7, 12, 3, 11, 4, 14, 1, 9, 6, 13, 2, 10, 5,
+};
+
+static void deinterleave_hadamard(celt_norm *X, int N0, int stride, int hadamard)
+{
+ int i,j;
+ VARDECL(celt_norm, tmp);
+ int N;
+ SAVE_STACK;
+ N = N0*stride;
+ ALLOC(tmp, N, celt_norm);
+ celt_assert(stride>0);
+ if (hadamard)
+ {
+ const int *ordery = ordery_table+stride-2;
+ for (i=0;i<stride;i++)
+ {
+ for (j=0;j<N0;j++)
+ tmp[ordery[i]*N0+j] = X[j*stride+i];
+ }
+ } else {
+ for (i=0;i<stride;i++)
+ for (j=0;j<N0;j++)
+ tmp[i*N0+j] = X[j*stride+i];
+ }
+ for (j=0;j<N;j++)
+ X[j] = tmp[j];
+ RESTORE_STACK;
+}
+
+static void interleave_hadamard(celt_norm *X, int N0, int stride, int hadamard)
+{
+ int i,j;
+ VARDECL(celt_norm, tmp);
+ int N;
+ SAVE_STACK;
+ N = N0*stride;
+ ALLOC(tmp, N, celt_norm);
+ if (hadamard)
+ {
+ const int *ordery = ordery_table+stride-2;
+ for (i=0;i<stride;i++)
+ for (j=0;j<N0;j++)
+ tmp[j*stride+i] = X[ordery[i]*N0+j];
+ } else {
+ for (i=0;i<stride;i++)
+ for (j=0;j<N0;j++)
+ tmp[j*stride+i] = X[i*N0+j];
+ }
+ for (j=0;j<N;j++)
+ X[j] = tmp[j];
+ RESTORE_STACK;
+}
+
+void haar1(celt_norm *X, int N0, int stride)
+{
+ int i, j;
+ N0 >>= 1;
+ for (i=0;i<stride;i++)
+ for (j=0;j<N0;j++)
+ {
+ celt_norm tmp1, tmp2;
+ tmp1 = MULT16_16_Q15(QCONST16(.70710678f,15), X[stride*2*j+i]);
+ tmp2 = MULT16_16_Q15(QCONST16(.70710678f,15), X[stride*(2*j+1)+i]);
+ X[stride*2*j+i] = tmp1 + tmp2;
+ X[stride*(2*j+1)+i] = tmp1 - tmp2;
+ }
+}
+
+static int compute_qn(int N, int b, int offset, int pulse_cap, int stereo)
+{
+ static const opus_int16 exp2_table8[8] =
+ {16384, 17866, 19483, 21247, 23170, 25267, 27554, 30048};
+ int qn, qb;
+ int N2 = 2*N-1;
+ if (stereo && N==2)
+ N2--;
+ /* The upper limit ensures that in a stereo split with itheta==16384, we'll
+ always have enough bits left over to code at least one pulse in the
+ side; otherwise it would collapse, since it doesn't get folded. */
+ qb = IMIN(b-pulse_cap-(4<<BITRES), (b+N2*offset)/N2);
+
+ qb = IMIN(8<<BITRES, qb);
+
+ if (qb<(1<<BITRES>>1)) {
+ qn = 1;
+ } else {
+ qn = exp2_table8[qb&0x7]>>(14-(qb>>BITRES));
+ qn = (qn+1)>>1<<1;
+ }
+ celt_assert(qn <= 256);
+ return qn;
+}
+
+struct band_ctx {
+ int encode;
+ const CELTMode *m;
+ int i;
+ int intensity;
+ int spread;
+ int tf_change;
+ ec_ctx *ec;
+ opus_int32 remaining_bits;
+ const celt_ener *bandE;
+ opus_uint32 seed;
+};
+
+struct split_ctx {
+ int inv;
+ int imid;
+ int iside;
+ int delta;
+ int itheta;
+ int qalloc;
+};
+
+static void compute_theta(struct band_ctx *ctx, struct split_ctx *sctx,
+ celt_norm *X, celt_norm *Y, int N, int *b, int B, int B0,
+ int LM,
+ int stereo, int *fill)
+{
+ int qn;
+ int itheta=0;
+ int delta;
+ int imid, iside;
+ int qalloc;
+ int pulse_cap;
+ int offset;
+ opus_int32 tell;
+ int inv=0;
+ int encode;
+ const CELTMode *m;
+ int i;
+ int intensity;
+ ec_ctx *ec;
+ const celt_ener *bandE;
+
+ encode = ctx->encode;
+ m = ctx->m;
+ i = ctx->i;
+ intensity = ctx->intensity;
+ ec = ctx->ec;
+ bandE = ctx->bandE;
+
+ /* Decide on the resolution to give to the split parameter theta */
+ pulse_cap = m->logN[i]+LM*(1<<BITRES);
+ offset = (pulse_cap>>1) - (stereo&&N==2 ? QTHETA_OFFSET_TWOPHASE : QTHETA_OFFSET);
+ qn = compute_qn(N, *b, offset, pulse_cap, stereo);
+ if (stereo && i>=intensity)
+ qn = 1;
+ if (encode)
+ {
+ /* theta is the atan() of the ratio between the (normalized)
+ side and mid. With just that parameter, we can re-scale both
+ mid and side because we know that 1) they have unit norm and
+ 2) they are orthogonal. */
+ itheta = stereo_itheta(X, Y, stereo, N);
+ }
+ tell = ec_tell_frac(ec);
+ if (qn!=1)
+ {
+ if (encode)
+ itheta = (itheta*qn+8192)>>14;
+
+ /* Entropy coding of the angle. We use a uniform pdf for the
+ time split, a step for stereo, and a triangular one for the rest. */
+ if (stereo && N>2)
+ {
+ int p0 = 3;
+ int x = itheta;
+ int x0 = qn/2;
+ int ft = p0*(x0+1) + x0;
+ /* Use a probability of p0 up to itheta=8192 and then use 1 after */
+ if (encode)
+ {
+ ec_encode(ec,x<=x0?p0*x:(x-1-x0)+(x0+1)*p0,x<=x0?p0*(x+1):(x-x0)+(x0+1)*p0,ft);
+ } else {
+ int fs;
+ fs=ec_decode(ec,ft);
+ if (fs<(x0+1)*p0)
+ x=fs/p0;
+ else
+ x=x0+1+(fs-(x0+1)*p0);
+ ec_dec_update(ec,x<=x0?p0*x:(x-1-x0)+(x0+1)*p0,x<=x0?p0*(x+1):(x-x0)+(x0+1)*p0,ft);
+ itheta = x;
+ }
+ } else if (B0>1 || stereo) {
+ /* Uniform pdf */
+ if (encode)
+ ec_enc_uint(ec, itheta, qn+1);
+ else
+ itheta = ec_dec_uint(ec, qn+1);
+ } else {
+ int fs=1, ft;
+ ft = ((qn>>1)+1)*((qn>>1)+1);
+ if (encode)
+ {
+ int fl;
+
+ fs = itheta <= (qn>>1) ? itheta + 1 : qn + 1 - itheta;
+ fl = itheta <= (qn>>1) ? itheta*(itheta + 1)>>1 :
+ ft - ((qn + 1 - itheta)*(qn + 2 - itheta)>>1);
+
+ ec_encode(ec, fl, fl+fs, ft);
+ } else {
+ /* Triangular pdf */
+ int fl=0;
+ int fm;
+ fm = ec_decode(ec, ft);
+
+ if (fm < ((qn>>1)*((qn>>1) + 1)>>1))
+ {
+ itheta = (isqrt32(8*(opus_uint32)fm + 1) - 1)>>1;
+ fs = itheta + 1;
+ fl = itheta*(itheta + 1)>>1;
+ }
+ else
+ {
+ itheta = (2*(qn + 1)
+ - isqrt32(8*(opus_uint32)(ft - fm - 1) + 1))>>1;
+ fs = qn + 1 - itheta;
+ fl = ft - ((qn + 1 - itheta)*(qn + 2 - itheta)>>1);
+ }
+
+ ec_dec_update(ec, fl, fl+fs, ft);
+ }
+ }
+ itheta = (opus_int32)itheta*16384/qn;
+ if (encode && stereo)
+ {
+ if (itheta==0)
+ intensity_stereo(m, X, Y, bandE, i, N);
+ else
+ stereo_split(X, Y, N);
+ }
+ /* NOTE: Renormalising X and Y *may* help fixed-point a bit at very high rate.
+ Let's do that at higher complexity */
+ } else if (stereo) {
+ if (encode)
+ {
+ inv = itheta > 8192;
+ if (inv)
+ {
+ int j;
+ for (j=0;j<N;j++)
+ Y[j] = -Y[j];
+ }
+ intensity_stereo(m, X, Y, bandE, i, N);
+ }
+ if (*b>2<<BITRES && ctx->remaining_bits > 2<<BITRES)
+ {
+ if (encode)
+ ec_enc_bit_logp(ec, inv, 2);
+ else
+ inv = ec_dec_bit_logp(ec, 2);
+ } else
+ inv = 0;
+ itheta = 0;
+ }
+ qalloc = ec_tell_frac(ec) - tell;
+ *b -= qalloc;
+
+ if (itheta == 0)
+ {
+ imid = 32767;
+ iside = 0;
+ *fill &= (1<<B)-1;
+ delta = -16384;
+ } else if (itheta == 16384)
+ {
+ imid = 0;
+ iside = 32767;
+ *fill &= ((1<<B)-1)<<B;
+ delta = 16384;
+ } else {
+ imid = bitexact_cos((opus_int16)itheta);
+ iside = bitexact_cos((opus_int16)(16384-itheta));
+ /* This is the mid vs side allocation that minimizes squared error
+ in that band. */
+ delta = FRAC_MUL16((N-1)<<7,bitexact_log2tan(iside,imid));
+ }
+
+ sctx->inv = inv;
+ sctx->imid = imid;
+ sctx->iside = iside;
+ sctx->delta = delta;
+ sctx->itheta = itheta;
+ sctx->qalloc = qalloc;
+}
+static unsigned quant_band_n1(struct band_ctx *ctx, celt_norm *X, celt_norm *Y, int b,
+ celt_norm *lowband_out)
+{
+#ifdef RESYNTH
+ int resynth = 1;
+#else
+ int resynth = !ctx->encode;
+#endif
+ int c;
+ int stereo;
+ celt_norm *x = X;
+ int encode;
+ ec_ctx *ec;
+
+ encode = ctx->encode;
+ ec = ctx->ec;
+
+ stereo = Y != NULL;
+ c=0; do {
+ int sign=0;
+ if (ctx->remaining_bits>=1<<BITRES)
+ {
+ if (encode)
+ {
+ sign = x[0]<0;
+ ec_enc_bits(ec, sign, 1);
+ } else {
+ sign = ec_dec_bits(ec, 1);
+ }
+ ctx->remaining_bits -= 1<<BITRES;
+ b-=1<<BITRES;
+ }
+ if (resynth)
+ x[0] = sign ? -NORM_SCALING : NORM_SCALING;
+ x = Y;
+ } while (++c<1+stereo);
+ if (lowband_out)
+ lowband_out[0] = SHR16(X[0],4);
+ return 1;
+}
+
+/* This function is responsible for encoding and decoding a mono partition.
+ It can split the band in two and transmit the energy difference with
+ the two half-bands. It can be called recursively so bands can end up being
+ split in 8 parts. */
+static unsigned quant_partition(struct band_ctx *ctx, celt_norm *X,
+ int N, int b, int B, celt_norm *lowband,
+ int LM,
+ opus_val16 gain, int fill)
+{
+ const unsigned char *cache;
+ int q;
+ int curr_bits;
+ int imid=0, iside=0;
+ int B0=B;
+ opus_val16 mid=0, side=0;
+ unsigned cm=0;
+#ifdef RESYNTH
+ int resynth = 1;
+#else
+ int resynth = !ctx->encode;
+#endif
+ celt_norm *Y=NULL;
+ int encode;
+ const CELTMode *m;
+ int i;
+ int spread;
+ ec_ctx *ec;
+
+ encode = ctx->encode;
+ m = ctx->m;
+ i = ctx->i;
+ spread = ctx->spread;
+ ec = ctx->ec;
+
+ /* If we need 1.5 more bit than we can produce, split the band in two. */
+ cache = m->cache.bits + m->cache.index[(LM+1)*m->nbEBands+i];
+ if (LM != -1 && b > cache[cache[0]]+12 && N>2)
+ {
+ int mbits, sbits, delta;
+ int itheta;
+ int qalloc;
+ struct split_ctx sctx;
+ celt_norm *next_lowband2=NULL;
+ opus_int32 rebalance;
+
+ N >>= 1;
+ Y = X+N;
+ LM -= 1;
+ if (B==1)
+ fill = (fill&1)|(fill<<1);
+ B = (B+1)>>1;
+
+ compute_theta(ctx, &sctx, X, Y, N, &b, B, B0,
+ LM, 0, &fill);
+ imid = sctx.imid;
+ iside = sctx.iside;
+ delta = sctx.delta;
+ itheta = sctx.itheta;
+ qalloc = sctx.qalloc;
+#ifdef OPUS_FIXED_POINT
+ mid = imid;
+ side = iside;
+#else
+ mid = (1.f/32768)*imid;
+ side = (1.f/32768)*iside;
+#endif
+
+ /* Give more bits to low-energy MDCTs than they would otherwise deserve */
+ if (B0>1 && (itheta&0x3fff))
+ {
+ if (itheta > 8192)
+ /* Rough approximation for pre-echo masking */
+ delta -= delta>>(4-LM);
+ else
+ /* Corresponds to a forward-masking slope of 1.5 dB per 10 ms */
+ delta = IMIN(0, delta + (N<<BITRES>>(5-LM)));
+ }
+ mbits = IMAX(0, IMIN(b, (b-delta)/2));
+ sbits = b-mbits;
+ ctx->remaining_bits -= qalloc;
+
+ if (lowband)
+ next_lowband2 = lowband+N; /* >32-bit split case */
+
+ rebalance = ctx->remaining_bits;
+ if (mbits >= sbits)
+ {
+ cm = quant_partition(ctx, X, N, mbits, B,
+ lowband, LM,
+ MULT16_16_P15(gain,mid), fill);
+ rebalance = mbits - (rebalance-ctx->remaining_bits);
+ if (rebalance > 3<<BITRES && itheta!=0)
+ sbits += rebalance - (3<<BITRES);
+ cm |= quant_partition(ctx, Y, N, sbits, B,
+ next_lowband2, LM,
+ MULT16_16_P15(gain,side), fill>>B)<<(B0>>1);
+ } else {
+ cm = quant_partition(ctx, Y, N, sbits, B,
+ next_lowband2, LM,
+ MULT16_16_P15(gain,side), fill>>B)<<(B0>>1);
+ rebalance = sbits - (rebalance-ctx->remaining_bits);
+ if (rebalance > 3<<BITRES && itheta!=16384)
+ mbits += rebalance - (3<<BITRES);
+ cm |= quant_partition(ctx, X, N, mbits, B,
+ lowband, LM,
+ MULT16_16_P15(gain,mid), fill);
+ }
+ } else {
+ /* This is the basic no-split case */
+ q = bits2pulses(m, i, LM, b);
+ curr_bits = pulses2bits(m, i, LM, q);
+ ctx->remaining_bits -= curr_bits;
+
+ /* Ensures we can never bust the budget */
+ while (ctx->remaining_bits < 0 && q > 0)
+ {
+ ctx->remaining_bits += curr_bits;
+ q--;
+ curr_bits = pulses2bits(m, i, LM, q);
+ ctx->remaining_bits -= curr_bits;
+ }
+
+ if (q!=0)
+ {
+ int K = get_pulses(q);
+
+ /* Finally do the actual quantization */
+ if (encode)
+ {
+ cm = alg_quant(X, N, K, spread, B, ec
+#ifdef RESYNTH
+ , gain
+#endif
+ );
+ } else {
+ cm = alg_unquant(X, N, K, spread, B, ec, gain);
+ }
+ } else {
+ /* If there's no pulse, fill the band anyway */
+ int j;
+ if (resynth)
+ {
+ unsigned cm_mask;
+ /* B can be as large as 16, so this shift might overflow an int on a
+ 16-bit platform; use a long to get defined behavior.*/
+ cm_mask = (unsigned)(1UL<<B)-1;
+ fill &= cm_mask;
+ if (!fill)
+ {
+ for (j=0;j<N;j++)
+ X[j] = 0;
+ } else {
+ if (lowband == NULL)
+ {
+ /* Noise */
+ for (j=0;j<N;j++)
+ {
+ ctx->seed = celt_lcg_rand(ctx->seed);
+ X[j] = (celt_norm)((opus_int32)ctx->seed>>20);
+ }
+ cm = cm_mask;
+ } else {
+ /* Folded spectrum */
+ for (j=0;j<N;j++)
+ {
+ opus_val16 tmp;
+ ctx->seed = celt_lcg_rand(ctx->seed);
+ /* About 48 dB below the "normal" folding level */
+ tmp = QCONST16(1.0f/256, 10);
+ tmp = (ctx->seed)&0x8000 ? tmp : -tmp;
+ X[j] = lowband[j]+tmp;
+ }
+ cm = fill;
+ }
+ renormalise_vector(X, N, gain);
+ }
+ }
+ }
+ }
+
+ return cm;
+}
+
+
+/* This function is responsible for encoding and decoding a band for the mono case. */
+static unsigned quant_band(struct band_ctx *ctx, celt_norm *X,
+ int N, int b, int B, celt_norm *lowband,
+ int LM, celt_norm *lowband_out,
+ opus_val16 gain, celt_norm *lowband_scratch, int fill)
+{
+ int N0=N;
+ int N_B=N;
+ int N_B0;
+ int B0=B;
+ int time_divide=0;
+ int recombine=0;
+ int longBlocks;
+ unsigned cm=0;
+#ifdef RESYNTH
+ int resynth = 1;
+#else
+ int resynth = !ctx->encode;
+#endif
+ int k;
+ int encode;
+ int tf_change;
+
+ encode = ctx->encode;
+ tf_change = ctx->tf_change;
+
+ longBlocks = B0==1;
+
+ N_B /= B;
+
+ /* Special case for one sample */
+ if (N==1)
+ {
+ return quant_band_n1(ctx, X, NULL, b, lowband_out);
+ }
+
+ if (tf_change>0)
+ recombine = tf_change;
+ /* Band recombining to increase frequency resolution */
+
+ if (lowband_scratch && lowband && (recombine || ((N_B&1) == 0 && tf_change<0) || B0>1))
+ {
+ int j;
+ for (j=0;j<N;j++)
+ lowband_scratch[j] = lowband[j];
+ lowband = lowband_scratch;
+ }
+
+ for (k=0;k<recombine;k++)
+ {
+ static const unsigned char bit_interleave_table[16]={
+ 0,1,1,1,2,3,3,3,2,3,3,3,2,3,3,3
+ };
+ if (encode)
+ haar1(X, N>>k, 1<<k);
+ if (lowband)
+ haar1(lowband, N>>k, 1<<k);
+ fill = bit_interleave_table[fill&0xF]|bit_interleave_table[fill>>4]<<2;
+ }
+ B>>=recombine;
+ N_B<<=recombine;
+
+ /* Increasing the time resolution */
+ while ((N_B&1) == 0 && tf_change<0)
+ {
+ if (encode)
+ haar1(X, N_B, B);
+ if (lowband)
+ haar1(lowband, N_B, B);
+ fill |= fill<<B;
+ B <<= 1;
+ N_B >>= 1;
+ time_divide++;
+ tf_change++;
+ }
+ B0=B;
+ N_B0 = N_B;
+
+ /* Reorganize the samples in time order instead of frequency order */
+ if (B0>1)
+ {
+ if (encode)
+ deinterleave_hadamard(X, N_B>>recombine, B0<<recombine, longBlocks);
+ if (lowband)
+ deinterleave_hadamard(lowband, N_B>>recombine, B0<<recombine, longBlocks);
+ }
+
+ cm = quant_partition(ctx, X, N, b, B, lowband,
+ LM, gain, fill);
+
+ /* This code is used by the decoder and by the resynthesis-enabled encoder */
+ if (resynth)
+ {
+ /* Undo the sample reorganization going from time order to frequency order */
+ if (B0>1)
+ interleave_hadamard(X, N_B>>recombine, B0<<recombine, longBlocks);
+
+ /* Undo time-freq changes that we did earlier */
+ N_B = N_B0;
+ B = B0;
+ for (k=0;k<time_divide;k++)
+ {
+ B >>= 1;
+ N_B <<= 1;
+ cm |= cm>>B;
+ haar1(X, N_B, B);
+ }
+
+ for (k=0;k<recombine;k++)
+ {
+ static const unsigned char bit_deinterleave_table[16]={
+ 0x00,0x03,0x0C,0x0F,0x30,0x33,0x3C,0x3F,
+ 0xC0,0xC3,0xCC,0xCF,0xF0,0xF3,0xFC,0xFF
+ };
+ cm = bit_deinterleave_table[cm];
+ haar1(X, N0>>k, 1<<k);
+ }
+ B<<=recombine;
+
+ /* Scale output for later folding */
+ if (lowband_out)
+ {
+ int j;
+ opus_val16 n;
+ n = celt_sqrt(SHL32(EXTEND32(N0),22));
+ for (j=0;j<N0;j++)
+ lowband_out[j] = MULT16_16_Q15(n,X[j]);
+ }
+ cm &= (1<<B)-1;
+ }
+ return cm;
+}
+
+
+/* This function is responsible for encoding and decoding a band for the stereo case. */
+static unsigned quant_band_stereo(struct band_ctx *ctx, celt_norm *X, celt_norm *Y,
+ int N, int b, int B, celt_norm *lowband,
+ int LM, celt_norm *lowband_out,
+ celt_norm *lowband_scratch, int fill)
+{
+ int imid=0, iside=0;
+ int inv = 0;
+ opus_val16 mid=0, side=0;
+ unsigned cm=0;
+#ifdef RESYNTH
+ int resynth = 1;
+#else
+ int resynth = !ctx->encode;
+#endif
+ int mbits, sbits, delta;
+ int itheta;
+ int qalloc;
+ struct split_ctx sctx;
+ int orig_fill;
+ int encode;
+ ec_ctx *ec;
+
+ encode = ctx->encode;
+ ec = ctx->ec;
+
+ /* Special case for one sample */
+ if (N==1)
+ {
+ return quant_band_n1(ctx, X, Y, b, lowband_out);
+ }
+
+ orig_fill = fill;
+
+ compute_theta(ctx, &sctx, X, Y, N, &b, B, B,
+ LM, 1, &fill);
+ inv = sctx.inv;
+ imid = sctx.imid;
+ iside = sctx.iside;
+ delta = sctx.delta;
+ itheta = sctx.itheta;
+ qalloc = sctx.qalloc;
+#ifdef OPUS_FIXED_POINT
+ mid = imid;
+ side = iside;
+#else
+ mid = (1.f/32768)*imid;
+ side = (1.f/32768)*iside;
+#endif
+
+ /* This is a special case for N=2 that only works for stereo and takes
+ advantage of the fact that mid and side are orthogonal to encode
+ the side with just one bit. */
+ if (N==2)
+ {
+ int c;
+ int sign=0;
+ celt_norm *x2, *y2;
+ mbits = b;
+ sbits = 0;
+ /* Only need one bit for the side. */
+ if (itheta != 0 && itheta != 16384)
+ sbits = 1<<BITRES;
+ mbits -= sbits;
+ c = itheta > 8192;
+ ctx->remaining_bits -= qalloc+sbits;
+
+ x2 = c ? Y : X;
+ y2 = c ? X : Y;
+ if (sbits)
+ {
+ if (encode)
+ {
+ /* Here we only need to encode a sign for the side. */
+ sign = x2[0]*y2[1] - x2[1]*y2[0] < 0;
+ ec_enc_bits(ec, sign, 1);
+ } else {
+ sign = ec_dec_bits(ec, 1);
+ }
+ }
+ sign = 1-2*sign;
+ /* We use orig_fill here because we want to fold the side, but if
+ itheta==16384, we'll have cleared the low bits of fill. */
+ cm = quant_band(ctx, x2, N, mbits, B, lowband,
+ LM, lowband_out, Q15ONE, lowband_scratch, orig_fill);
+ /* We don't split N=2 bands, so cm is either 1 or 0 (for a fold-collapse),
+ and there's no need to worry about mixing with the other channel. */
+ y2[0] = -sign*x2[1];
+ y2[1] = sign*x2[0];
+ if (resynth)
+ {
+ celt_norm tmp;
+ X[0] = MULT16_16_Q15(mid, X[0]);
+ X[1] = MULT16_16_Q15(mid, X[1]);
+ Y[0] = MULT16_16_Q15(side, Y[0]);
+ Y[1] = MULT16_16_Q15(side, Y[1]);
+ tmp = X[0];
+ X[0] = SUB16(tmp,Y[0]);
+ Y[0] = ADD16(tmp,Y[0]);
+ tmp = X[1];
+ X[1] = SUB16(tmp,Y[1]);
+ Y[1] = ADD16(tmp,Y[1]);
+ }
+ } else {
+ /* "Normal" split code */
+ opus_int32 rebalance;
+
+ mbits = IMAX(0, IMIN(b, (b-delta)/2));
+ sbits = b-mbits;
+ ctx->remaining_bits -= qalloc;
+
+ rebalance = ctx->remaining_bits;
+ if (mbits >= sbits)
+ {
+ /* In stereo mode, we do not apply a scaling to the mid because we need the normalized
+ mid for folding later. */
+ cm = quant_band(ctx, X, N, mbits, B,
+ lowband, LM, lowband_out,
+ Q15ONE, lowband_scratch, fill);
+ rebalance = mbits - (rebalance-ctx->remaining_bits);
+ if (rebalance > 3<<BITRES && itheta!=0)
+ sbits += rebalance - (3<<BITRES);
+
+ /* For a stereo split, the high bits of fill are always zero, so no
+ folding will be done to the side. */
+ cm |= quant_band(ctx, Y, N, sbits, B,
+ NULL, LM, NULL,
+ side, NULL, fill>>B);
+ } else {
+ /* For a stereo split, the high bits of fill are always zero, so no
+ folding will be done to the side. */
+ cm = quant_band(ctx, Y, N, sbits, B,
+ NULL, LM, NULL,
+ side, NULL, fill>>B);
+ rebalance = sbits - (rebalance-ctx->remaining_bits);
+ if (rebalance > 3<<BITRES && itheta!=16384)
+ mbits += rebalance - (3<<BITRES);
+ /* In stereo mode, we do not apply a scaling to the mid because we need the normalized
+ mid for folding later. */
+ cm |= quant_band(ctx, X, N, mbits, B,
+ lowband, LM, lowband_out,
+ Q15ONE, lowband_scratch, fill);
+ }
+ }
+
+
+ /* This code is used by the decoder and by the resynthesis-enabled encoder */
+ if (resynth)
+ {
+ if (N!=2)
+ stereo_merge(X, Y, mid, N);
+ if (inv)
+ {
+ int j;
+ for (j=0;j<N;j++)
+ Y[j] = -Y[j];
+ }
+ }
+ return cm;
+}
+
+
+void quant_all_bands(int encode, const CELTMode *m, int start, int end,
+ celt_norm *X_, celt_norm *Y_, unsigned char *collapse_masks, const celt_ener *bandE, int *pulses,
+ int shortBlocks, int spread, int dual_stereo, int intensity, int *tf_res,
+ opus_int32 total_bits, opus_int32 balance, ec_ctx *ec, int LM, int codedBands, opus_uint32 *seed)
+{
+ int i;
+ opus_int32 remaining_bits;
+ const opus_int16 * OPUS_RESTRICT eBands = m->eBands;
+ celt_norm * OPUS_RESTRICT norm, * OPUS_RESTRICT norm2;
+ VARDECL(celt_norm, _norm);
+ celt_norm *lowband_scratch;
+ int B;
+ int M;
+ int lowband_offset;
+ int update_lowband = 1;
+ int C = Y_ != NULL ? 2 : 1;
+ int norm_offset;
+#ifdef RESYNTH
+ int resynth = 1;
+#else
+ int resynth = !encode;
+#endif
+ struct band_ctx ctx;
+ SAVE_STACK;
+
+ M = 1<<LM;
+ B = shortBlocks ? M : 1;
+ norm_offset = M*eBands[start];
+ /* No need to allocate norm for the last band because we don't need an
+ output in that band. */
+ ALLOC(_norm, C*(M*eBands[m->nbEBands-1]-norm_offset), celt_norm);
+ norm = _norm;
+ norm2 = norm + M*eBands[m->nbEBands-1]-norm_offset;
+ /* We can use the last band as scratch space because we don't need that
+ scratch space for the last band. */
+ lowband_scratch = X_+M*eBands[m->nbEBands-1];
+
+ lowband_offset = 0;
+ ctx.bandE = bandE;
+ ctx.ec = ec;
+ ctx.encode = encode;
+ ctx.intensity = intensity;
+ ctx.m = m;
+ ctx.seed = *seed;
+ ctx.spread = spread;
+ for (i=start;i<end;i++)
+ {
+ opus_int32 tell;
+ int b;
+ int N;
+ opus_int32 curr_balance;
+ int effective_lowband=-1;
+ celt_norm * OPUS_RESTRICT X, * OPUS_RESTRICT Y;
+ int tf_change=0;
+ unsigned x_cm;
+ unsigned y_cm;
+ int last;
+
+ ctx.i = i;
+ last = (i==end-1);
+
+ X = X_+M*eBands[i];
+ if (Y_!=NULL)
+ Y = Y_+M*eBands[i];
+ else
+ Y = NULL;
+ N = M*eBands[i+1]-M*eBands[i];
+ tell = ec_tell_frac(ec);
+
+ /* Compute how many bits we want to allocate to this band */
+ if (i != start)
+ balance -= tell;
+ remaining_bits = total_bits-tell-1;
+ ctx.remaining_bits = remaining_bits;
+ if (i <= codedBands-1)
+ {
+ curr_balance = balance / IMIN(3, codedBands-i);
+ b = IMAX(0, IMIN(16383, IMIN(remaining_bits+1,pulses[i]+curr_balance)));
+ } else {
+ b = 0;
+ }
+
+ if (resynth && M*eBands[i]-N >= M*eBands[start] && (update_lowband || lowband_offset==0))
+ lowband_offset = i;
+
+ tf_change = tf_res[i];
+ ctx.tf_change = tf_change;
+ if (i>=m->effEBands)
+ {
+ X=norm;
+ if (Y_!=NULL)
+ Y = norm;
+ lowband_scratch = NULL;
+ }
+ if (i==end-1)
+ lowband_scratch = NULL;
+
+ /* Get a conservative estimate of the collapse_mask's for the bands we're
+ going to be folding from. */
+ if (lowband_offset != 0 && (spread!=SPREAD_AGGRESSIVE || B>1 || tf_change<0))
+ {
+ int fold_start;
+ int fold_end;
+ int fold_i;
+ /* This ensures we never repeat spectral content within one band */
+ effective_lowband = IMAX(0, M*eBands[lowband_offset]-norm_offset-N);
+ fold_start = lowband_offset;
+ while(M*eBands[--fold_start] > effective_lowband+norm_offset);
+ fold_end = lowband_offset-1;
+ while(M*eBands[++fold_end] < effective_lowband+norm_offset+N);
+ x_cm = y_cm = 0;
+ fold_i = fold_start; do {
+ x_cm |= collapse_masks[fold_i*C+0];
+ y_cm |= collapse_masks[fold_i*C+C-1];
+ } while (++fold_i<fold_end);
+ }
+ /* Otherwise, we'll be using the LCG to fold, so all blocks will (almost
+ always) be non-zero. */
+ else
+ x_cm = y_cm = (1<<B)-1;
+
+ if (dual_stereo && i==intensity)
+ {
+ int j;
+
+ /* Switch off dual stereo to do intensity. */
+ dual_stereo = 0;
+ if (resynth)
+ for (j=0;j<M*eBands[i]-norm_offset;j++)
+ norm[j] = HALF32(norm[j]+norm2[j]);
+ }
+ if (dual_stereo)
+ {
+ x_cm = quant_band(&ctx, X, N, b/2, B,
+ effective_lowband != -1 ? norm+effective_lowband : NULL, LM,
+ last?NULL:norm+M*eBands[i]-norm_offset, Q15ONE, lowband_scratch, x_cm);
+ y_cm = quant_band(&ctx, Y, N, b/2, B,
+ effective_lowband != -1 ? norm2+effective_lowband : NULL, LM,
+ last?NULL:norm2+M*eBands[i]-norm_offset, Q15ONE, lowband_scratch, y_cm);
+ } else {
+ if (Y!=NULL)
+ {
+ x_cm = quant_band_stereo(&ctx, X, Y, N, b, B,
+ effective_lowband != -1 ? norm+effective_lowband : NULL, LM,
+ last?NULL:norm+M*eBands[i]-norm_offset, lowband_scratch, x_cm|y_cm);
+ } else {
+ x_cm = quant_band(&ctx, X, N, b, B,
+ effective_lowband != -1 ? norm+effective_lowband : NULL, LM,
+ last?NULL:norm+M*eBands[i]-norm_offset, Q15ONE, lowband_scratch, x_cm|y_cm);
+ }
+ y_cm = x_cm;
+ }
+ collapse_masks[i*C+0] = (unsigned char)x_cm;
+ collapse_masks[i*C+C-1] = (unsigned char)y_cm;
+ balance += pulses[i] + tell;
+
+ /* Update the folding position only as long as we have 1 bit/sample depth. */
+ update_lowband = b>(N<<BITRES);
+ }
+ *seed = ctx.seed;
+
+ RESTORE_STACK;
+}
+
diff --git a/drivers/opus/celt/bands.h b/drivers/opus/celt/bands.h
new file mode 100644
index 0000000000..1ef7cbc8ee
--- /dev/null
+++ b/drivers/opus/celt/bands.h
@@ -0,0 +1,114 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Copyright (c) 2008-2009 Gregory Maxwell
+ Written by Jean-Marc Valin and Gregory Maxwell */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef BANDS_H
+#define BANDS_H
+
+#include "opus/celt/arch.h"
+#include "opus/celt/opus_modes.h"
+#include "opus/celt/entenc.h"
+#include "opus/celt/entdec.h"
+#include "opus/celt/rate.h"
+
+/** Compute the amplitude (sqrt energy) in each of the bands
+ * @param m Mode data
+ * @param X Spectrum
+ * @param bandE Square root of the energy for each band (returned)
+ */
+void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *bandE, int end, int C, int M);
+
+/*void compute_noise_energies(const CELTMode *m, const celt_sig *X, const opus_val16 *tonality, celt_ener *bandE);*/
+
+/** Normalise each band of X such that the energy in each band is
+ equal to 1
+ * @param m Mode data
+ * @param X Spectrum (returned normalised)
+ * @param bandE Square root of the energy for each band
+ */
+void normalise_bands(const CELTMode *m, const celt_sig * OPUS_RESTRICT freq, celt_norm * OPUS_RESTRICT X, const celt_ener *bandE, int end, int C, int M);
+
+/** Denormalise each band of X to restore full amplitude
+ * @param m Mode data
+ * @param X Spectrum (returned de-normalised)
+ * @param bandE Square root of the energy for each band
+ */
+void denormalise_bands(const CELTMode *m, const celt_norm * OPUS_RESTRICT X,
+ celt_sig * OPUS_RESTRICT freq, const opus_val16 *bandE, int start, int end, int C, int M);
+
+#define SPREAD_NONE (0)
+#define SPREAD_LIGHT (1)
+#define SPREAD_NORMAL (2)
+#define SPREAD_AGGRESSIVE (3)
+
+int spreading_decision(const CELTMode *m, celt_norm *X, int *average,
+ int last_decision, int *hf_average, int *tapset_decision, int update_hf,
+ int end, int C, int M);
+
+#ifdef MEASURE_NORM_MSE
+void measure_norm_mse(const CELTMode *m, float *X, float *X0, float *bandE, float *bandE0, int M, int N, int C);
+#endif
+
+void haar1(celt_norm *X, int N0, int stride);
+
+/** Quantisation/encoding of the residual spectrum
+ * @param encode flag that indicates whether we're encoding (1) or decoding (0)
+ * @param m Mode data
+ * @param start First band to process
+ * @param end Last band to process + 1
+ * @param X Residual (normalised)
+ * @param Y Residual (normalised) for second channel (or NULL for mono)
+ * @param collapse_masks Anti-collapse tracking mask
+ * @param bandE Square root of the energy for each band
+ * @param pulses Bit allocation (per band) for PVQ
+ * @param shortBlocks Zero for long blocks, non-zero for short blocks
+ * @param spread Amount of spreading to use
+ * @param dual_stereo Zero for MS stereo, non-zero for dual stereo
+ * @param intensity First band to use intensity stereo
+ * @param tf_res Time-frequency resolution change
+ * @param total_bits Total number of bits that can be used for the frame (including the ones already spent)
+ * @param balance Number of unallocated bits
+ * @param en Entropy coder state
+ * @param LM log2() of the number of 2.5 subframes in the frame
+ * @param codedBands Last band to receive bits + 1
+ * @param seed Random generator seed
+ */
+void quant_all_bands(int encode, const CELTMode *m, int start, int end,
+ celt_norm * X, celt_norm * Y, unsigned char *collapse_masks, const celt_ener *bandE, int *pulses,
+ int shortBlocks, int spread, int dual_stereo, int intensity, int *tf_res,
+ opus_int32 total_bits, opus_int32 balance, ec_ctx *ec, int M, int codedBands, opus_uint32 *seed);
+
+void anti_collapse(const CELTMode *m, celt_norm *X_, unsigned char *collapse_masks, int LM, int C, int size,
+ int start, int end, opus_val16 *logE, opus_val16 *prev1logE,
+ opus_val16 *prev2logE, int *pulses, opus_uint32 seed);
+
+opus_uint32 celt_lcg_rand(opus_uint32 seed);
+
+int hysteresis_decision(opus_val16 val, const opus_val16 *thresholds, const opus_val16 *hysteresis, int N, int prev);
+
+#endif /* BANDS_H */
diff --git a/drivers/opus/celt/celt.c b/drivers/opus/celt/celt.c
new file mode 100644
index 0000000000..d99a91ba29
--- /dev/null
+++ b/drivers/opus/celt/celt.c
@@ -0,0 +1,223 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2010 Xiph.Org Foundation
+ Copyright (c) 2008 Gregory Maxwell
+ Written by Jean-Marc Valin and Gregory Maxwell */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#define CELT_C
+
+#include "opus/celt/os_support.h"
+#include "opus/celt/mdct.h"
+#include <math.h>
+#include "opus/celt/celt.h"
+#include "opus/celt/pitch.h"
+#include "opus/celt/bands.h"
+#include "opus/celt/opus_modes.h"
+#include "opus/celt/entcode.h"
+#include "opus/celt/quant_bands.h"
+#include "opus/celt/rate.h"
+#include "opus/celt/stack_alloc.h"
+#include "opus/celt/mathops.h"
+#include "opus/celt/float_cast.h"
+#include <stdarg.h>
+#include "opus/celt/celt_lpc.h"
+#include "opus/celt/vq.h"
+
+#ifndef PACKAGE_VERSION
+#define PACKAGE_VERSION "unknown"
+#endif
+
+
+int resampling_factor(opus_int32 rate)
+{
+ int ret;
+ switch (rate)
+ {
+ case 48000:
+ ret = 1;
+ break;
+ case 24000:
+ ret = 2;
+ break;
+ case 16000:
+ ret = 3;
+ break;
+ case 12000:
+ ret = 4;
+ break;
+ case 8000:
+ ret = 6;
+ break;
+ default:
+#ifndef CUSTOM_MODES
+ celt_assert(0);
+#endif
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+#ifndef OVERRIDE_COMB_FILTER_CONST
+static void comb_filter_const(opus_val32 *y, opus_val32 *x, int T, int N,
+ opus_val16 g10, opus_val16 g11, opus_val16 g12)
+{
+ opus_val32 x0, x1, x2, x3, x4;
+ int i;
+ x4 = x[-T-2];
+ x3 = x[-T-1];
+ x2 = x[-T];
+ x1 = x[-T+1];
+ for (i=0;i<N;i++)
+ {
+ x0=x[i-T+2];
+ y[i] = x[i]
+ + MULT16_32_Q15(g10,x2)
+ + MULT16_32_Q15(g11,ADD32(x1,x3))
+ + MULT16_32_Q15(g12,ADD32(x0,x4));
+ x4=x3;
+ x3=x2;
+ x2=x1;
+ x1=x0;
+ }
+
+}
+#endif
+
+void comb_filter(opus_val32 *y, opus_val32 *x, int T0, int T1, int N,
+ opus_val16 g0, opus_val16 g1, int tapset0, int tapset1,
+ const opus_val16 *window, int overlap)
+{
+ int i;
+ /* printf ("%d %d %f %f\n", T0, T1, g0, g1); */
+ opus_val16 g00, g01, g02, g10, g11, g12;
+ opus_val32 x0, x1, x2, x3, x4;
+ static const opus_val16 gains[3][3] = {
+ {QCONST16(0.3066406250f, 15), QCONST16(0.2170410156f, 15), QCONST16(0.1296386719f, 15)},
+ {QCONST16(0.4638671875f, 15), QCONST16(0.2680664062f, 15), QCONST16(0.f, 15)},
+ {QCONST16(0.7998046875f, 15), QCONST16(0.1000976562f, 15), QCONST16(0.f, 15)}};
+
+ if (g0==0 && g1==0)
+ {
+ /* OPT: Happens to work without the OPUS_MOVE(), but only because the current encoder already copies x to y */
+ if (x!=y)
+ OPUS_MOVE(y, x, N);
+ return;
+ }
+ g00 = MULT16_16_Q15(g0, gains[tapset0][0]);
+ g01 = MULT16_16_Q15(g0, gains[tapset0][1]);
+ g02 = MULT16_16_Q15(g0, gains[tapset0][2]);
+ g10 = MULT16_16_Q15(g1, gains[tapset1][0]);
+ g11 = MULT16_16_Q15(g1, gains[tapset1][1]);
+ g12 = MULT16_16_Q15(g1, gains[tapset1][2]);
+ x1 = x[-T1+1];
+ x2 = x[-T1 ];
+ x3 = x[-T1-1];
+ x4 = x[-T1-2];
+ for (i=0;i<overlap;i++)
+ {
+ opus_val16 f;
+ x0=x[i-T1+2];
+ f = MULT16_16_Q15(window[i],window[i]);
+ y[i] = x[i]
+ + MULT16_32_Q15(MULT16_16_Q15((Q15ONE-f),g00),x[i-T0])
+ + MULT16_32_Q15(MULT16_16_Q15((Q15ONE-f),g01),ADD32(x[i-T0+1],x[i-T0-1]))
+ + MULT16_32_Q15(MULT16_16_Q15((Q15ONE-f),g02),ADD32(x[i-T0+2],x[i-T0-2]))
+ + MULT16_32_Q15(MULT16_16_Q15(f,g10),x2)
+ + MULT16_32_Q15(MULT16_16_Q15(f,g11),ADD32(x1,x3))
+ + MULT16_32_Q15(MULT16_16_Q15(f,g12),ADD32(x0,x4));
+ x4=x3;
+ x3=x2;
+ x2=x1;
+ x1=x0;
+
+ }
+ if (g1==0)
+ {
+ /* OPT: Happens to work without the OPUS_MOVE(), but only because the current encoder already copies x to y */
+ if (x!=y)
+ OPUS_MOVE(y+overlap, x+overlap, N-overlap);
+ return;
+ }
+
+ /* Compute the part with the constant filter. */
+ comb_filter_const(y+i, x+i, T1, N-i, g10, g11, g12);
+}
+
+const signed char tf_select_table[4][8] = {
+ {0, -1, 0, -1, 0,-1, 0,-1},
+ {0, -1, 0, -2, 1, 0, 1,-1},
+ {0, -2, 0, -3, 2, 0, 1,-1},
+ {0, -2, 0, -3, 3, 0, 1,-1},
+};
+
+
+void init_caps(const CELTMode *m,int *cap,int LM,int C)
+{
+ int i;
+ for (i=0;i<m->nbEBands;i++)
+ {
+ int N;
+ N=(m->eBands[i+1]-m->eBands[i])<<LM;
+ cap[i] = (m->cache.caps[m->nbEBands*(2*LM+C-1)+i]+64)*C*N>>2;
+ }
+}
+
+
+
+const char *opus_strerror(int error)
+{
+ static const char * const error_strings[8] = {
+ "success",
+ "invalid argument",
+ "buffer too small",
+ "internal error",
+ "corrupted stream",
+ "request not implemented",
+ "invalid state",
+ "memory allocation failed"
+ };
+ if (error > 0 || error < -7)
+ return "unknown error";
+ else
+ return error_strings[-error];
+}
+
+const char *opus_get_version_string(void)
+{
+ return "libopus " PACKAGE_VERSION
+#ifdef OPUS_FIXED_POINT
+ "-fixed"
+#endif
+#ifdef FUZZING
+ "-fuzzing"
+#endif
+ ;
+}
diff --git a/drivers/opus/celt/celt.h b/drivers/opus/celt/celt.h
new file mode 100644
index 0000000000..2b7dc3fa72
--- /dev/null
+++ b/drivers/opus/celt/celt.h
@@ -0,0 +1,218 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Copyright (c) 2008 Gregory Maxwell
+ Written by Jean-Marc Valin and Gregory Maxwell */
+/**
+ @file celt.h
+ @brief Contains all the functions for encoding and decoding audio
+ */
+
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CELT_H
+#define CELT_H
+
+#include "opus/opus_types.h"
+#include "opus/opus_defines.h"
+#include "opus/opus_custom.h"
+#include "opus/celt/entenc.h"
+#include "opus/celt/entdec.h"
+#include "opus/celt/arch.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define CELTEncoder OpusCustomEncoder
+#define CELTDecoder OpusCustomDecoder
+#define CELTMode OpusCustomMode
+
+typedef struct {
+ int valid;
+ float tonality;
+ float tonality_slope;
+ float noisiness;
+ float activity;
+ float music_prob;
+ int bandwidth;
+}AnalysisInfo;
+
+#define __celt_check_mode_ptr_ptr(ptr) ((ptr) + ((ptr) - (const CELTMode**)(ptr)))
+
+#define __celt_check_analysis_ptr(ptr) ((ptr) + ((ptr) - (const AnalysisInfo*)(ptr)))
+
+/* Encoder/decoder Requests */
+
+/* Expose this option again when variable framesize actually works */
+#define OPUS_FRAMESIZE_VARIABLE 5010 /**< Optimize the frame size dynamically */
+
+
+#define CELT_SET_PREDICTION_REQUEST 10002
+/** Controls the use of interframe prediction.
+ 0=Independent frames
+ 1=Short term interframe prediction allowed
+ 2=Long term prediction allowed
+ */
+#define CELT_SET_PREDICTION(x) CELT_SET_PREDICTION_REQUEST, __opus_check_int(x)
+
+#define CELT_SET_INPUT_CLIPPING_REQUEST 10004
+#define CELT_SET_INPUT_CLIPPING(x) CELT_SET_INPUT_CLIPPING_REQUEST, __opus_check_int(x)
+
+#define CELT_GET_AND_CLEAR_ERROR_REQUEST 10007
+#define CELT_GET_AND_CLEAR_ERROR(x) CELT_GET_AND_CLEAR_ERROR_REQUEST, __opus_check_int_ptr(x)
+
+#define CELT_SET_CHANNELS_REQUEST 10008
+#define CELT_SET_CHANNELS(x) CELT_SET_CHANNELS_REQUEST, __opus_check_int(x)
+
+
+/* Internal */
+#define CELT_SET_START_BAND_REQUEST 10010
+#define CELT_SET_START_BAND(x) CELT_SET_START_BAND_REQUEST, __opus_check_int(x)
+
+#define CELT_SET_END_BAND_REQUEST 10012
+#define CELT_SET_END_BAND(x) CELT_SET_END_BAND_REQUEST, __opus_check_int(x)
+
+#define CELT_GET_MODE_REQUEST 10015
+/** Get the CELTMode used by an encoder or decoder */
+#define CELT_GET_MODE(x) CELT_GET_MODE_REQUEST, __celt_check_mode_ptr_ptr(x)
+
+#define CELT_SET_SIGNALLING_REQUEST 10016
+#define CELT_SET_SIGNALLING(x) CELT_SET_SIGNALLING_REQUEST, __opus_check_int(x)
+
+#define CELT_SET_TONALITY_REQUEST 10018
+#define CELT_SET_TONALITY(x) CELT_SET_TONALITY_REQUEST, __opus_check_int(x)
+#define CELT_SET_TONALITY_SLOPE_REQUEST 10020
+#define CELT_SET_TONALITY_SLOPE(x) CELT_SET_TONALITY_SLOPE_REQUEST, __opus_check_int(x)
+
+#define CELT_SET_ANALYSIS_REQUEST 10022
+#define CELT_SET_ANALYSIS(x) CELT_SET_ANALYSIS_REQUEST, __celt_check_analysis_ptr(x)
+
+#define OPUS_SET_LFE_REQUEST 10024
+#define OPUS_SET_LFE(x) OPUS_SET_LFE_REQUEST, __opus_check_int(x)
+
+#define OPUS_SET_ENERGY_MASK_REQUEST 10026
+#define OPUS_SET_ENERGY_MASK(x) OPUS_SET_ENERGY_MASK_REQUEST, __opus_check_val16_ptr(x)
+
+/* Encoder stuff */
+
+int celt_encoder_get_size(int channels);
+
+int celt_encode_with_ec(OpusCustomEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc);
+
+int celt_encoder_init(CELTEncoder *st, opus_int32 sampling_rate, int channels,
+ int arch);
+
+
+
+/* Decoder stuff */
+
+int celt_decoder_get_size(int channels);
+
+
+int celt_decoder_init(CELTDecoder *st, opus_int32 sampling_rate, int channels);
+
+int celt_decode_with_ec(OpusCustomDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, opus_val16 * OPUS_RESTRICT pcm, int frame_size, ec_dec *dec);
+
+#define celt_encoder_ctl opus_custom_encoder_ctl
+#define celt_decoder_ctl opus_custom_decoder_ctl
+
+
+#ifdef CUSTOM_MODES
+#define OPUS_CUSTOM_NOSTATIC
+#else
+#define OPUS_CUSTOM_NOSTATIC static OPUS_INLINE
+#endif
+
+static const unsigned char trim_icdf[11] = {126, 124, 119, 109, 87, 41, 19, 9, 4, 2, 0};
+/* Probs: NONE: 21.875%, LIGHT: 6.25%, NORMAL: 65.625%, AGGRESSIVE: 6.25% */
+static const unsigned char spread_icdf[4] = {25, 23, 2, 0};
+
+static const unsigned char tapset_icdf[3]={2,1,0};
+
+#ifdef CUSTOM_MODES
+static const unsigned char toOpusTable[20] = {
+ 0xE0, 0xE8, 0xF0, 0xF8,
+ 0xC0, 0xC8, 0xD0, 0xD8,
+ 0xA0, 0xA8, 0xB0, 0xB8,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x88, 0x90, 0x98,
+};
+
+static const unsigned char fromOpusTable[16] = {
+ 0x80, 0x88, 0x90, 0x98,
+ 0x40, 0x48, 0x50, 0x58,
+ 0x20, 0x28, 0x30, 0x38,
+ 0x00, 0x08, 0x10, 0x18
+};
+
+static OPUS_INLINE int toOpus(unsigned char c)
+{
+ int ret=0;
+ if (c<0xA0)
+ ret = toOpusTable[c>>3];
+ if (ret == 0)
+ return -1;
+ else
+ return ret|(c&0x7);
+}
+
+static OPUS_INLINE int fromOpus(unsigned char c)
+{
+ if (c<0x80)
+ return -1;
+ else
+ return fromOpusTable[(c>>3)-16] | (c&0x7);
+}
+#endif /* CUSTOM_MODES */
+
+#define COMBFILTER_MAXPERIOD 1024
+#define COMBFILTER_MINPERIOD 15
+
+extern const signed char tf_select_table[4][8];
+
+int resampling_factor(opus_int32 rate);
+
+void celt_preemphasis(const opus_val16 * OPUS_RESTRICT pcmp, celt_sig * OPUS_RESTRICT inp,
+ int N, int CC, int upsample, const opus_val16 *coef, celt_sig *mem, int clip);
+
+void comb_filter(opus_val32 *y, opus_val32 *x, int T0, int T1, int N,
+ opus_val16 g0, opus_val16 g1, int tapset0, int tapset1,
+ const opus_val16 *window, int overlap);
+
+void init_caps(const CELTMode *m,int *cap,int LM,int C);
+
+#ifdef RESYNTH
+void deemphasis(celt_sig *in[], opus_val16 *pcm, int N, int C, int downsample, const opus_val16 *coef, celt_sig *mem, celt_sig * OPUS_RESTRICT scratch);
+
+void compute_inv_mdcts(const CELTMode *mode, int shortBlocks, celt_sig *X,
+ celt_sig * OPUS_RESTRICT out_mem[], int C, int LM);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* CELT_H */
diff --git a/drivers/opus/celt/celt_decoder.c b/drivers/opus/celt/celt_decoder.c
new file mode 100644
index 0000000000..67c3789439
--- /dev/null
+++ b/drivers/opus/celt/celt_decoder.c
@@ -0,0 +1,1195 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2010 Xiph.Org Foundation
+ Copyright (c) 2008 Gregory Maxwell
+ Written by Jean-Marc Valin and Gregory Maxwell */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#define CELT_DECODER_C
+
+#include "opus/celt/cpu_support.h"
+#include "opus/celt/os_support.h"
+#include "opus/celt/mdct.h"
+#include <math.h>
+#include "opus/celt/celt.h"
+#include "opus/celt/pitch.h"
+#include "opus/celt/bands.h"
+#include "opus/celt/opus_modes.h"
+#include "opus/celt/entcode.h"
+#include "opus/celt/quant_bands.h"
+#include "opus/celt/rate.h"
+#include "opus/celt/stack_alloc.h"
+#include "opus/celt/mathops.h"
+#include "opus/celt/float_cast.h"
+#include <stdarg.h>
+#include "opus/celt/celt_lpc.h"
+#include "opus/celt/vq.h"
+
+/**********************************************************************/
+/* */
+/* DECODER */
+/* */
+/**********************************************************************/
+#define DECODE_BUFFER_SIZE 2048
+
+/** Decoder state
+ @brief Decoder state
+ */
+struct OpusCustomDecoder {
+ const OpusCustomMode *mode;
+ int overlap;
+ int channels;
+ int stream_channels;
+
+ int downsample;
+ int start, end;
+ int signalling;
+ int arch;
+
+ /* Everything beyond this point gets cleared on a reset */
+#define DECODER_RESET_START rng
+
+ opus_uint32 rng;
+ int error;
+ int last_pitch_index;
+ int loss_count;
+ int postfilter_period;
+ int postfilter_period_old;
+ opus_val16 postfilter_gain;
+ opus_val16 postfilter_gain_old;
+ int postfilter_tapset;
+ int postfilter_tapset_old;
+
+ celt_sig preemph_memD[2];
+
+ celt_sig _decode_mem[1]; /* Size = channels*(DECODE_BUFFER_SIZE+mode->overlap) */
+ /* opus_val16 lpc[], Size = channels*LPC_ORDER */
+ /* opus_val16 oldEBands[], Size = 2*mode->nbEBands */
+ /* opus_val16 oldLogE[], Size = 2*mode->nbEBands */
+ /* opus_val16 oldLogE2[], Size = 2*mode->nbEBands */
+ /* opus_val16 backgroundLogE[], Size = 2*mode->nbEBands */
+};
+
+int celt_decoder_get_size(int channels)
+{
+ const CELTMode *mode = opus_custom_mode_create(48000, 960, NULL);
+ return opus_custom_decoder_get_size(mode, channels);
+}
+
+OPUS_CUSTOM_NOSTATIC int opus_custom_decoder_get_size(const CELTMode *mode, int channels)
+{
+ int size = sizeof(struct CELTDecoder)
+ + (channels*(DECODE_BUFFER_SIZE+mode->overlap)-1)*sizeof(celt_sig)
+ + channels*LPC_ORDER*sizeof(opus_val16)
+ + 4*2*mode->nbEBands*sizeof(opus_val16);
+ return size;
+}
+
+#ifdef CUSTOM_MODES
+CELTDecoder *opus_custom_decoder_create(const CELTMode *mode, int channels, int *error)
+{
+ int ret;
+ CELTDecoder *st = (CELTDecoder *)opus_alloc(opus_custom_decoder_get_size(mode, channels));
+ ret = opus_custom_decoder_init(st, mode, channels);
+ if (ret != OPUS_OK)
+ {
+ opus_custom_decoder_destroy(st);
+ st = NULL;
+ }
+ if (error)
+ *error = ret;
+ return st;
+}
+#endif /* CUSTOM_MODES */
+
+int celt_decoder_init(CELTDecoder *st, opus_int32 sampling_rate, int channels)
+{
+ int ret;
+ ret = opus_custom_decoder_init(st, opus_custom_mode_create(48000, 960, NULL), channels);
+ if (ret != OPUS_OK)
+ return ret;
+ st->downsample = resampling_factor(sampling_rate);
+ if (st->downsample==0)
+ return OPUS_BAD_ARG;
+ else
+ return OPUS_OK;
+}
+
+OPUS_CUSTOM_NOSTATIC int opus_custom_decoder_init(CELTDecoder *st, const CELTMode *mode, int channels)
+{
+ if (channels < 0 || channels > 2)
+ return OPUS_BAD_ARG;
+
+ if (st==NULL)
+ return OPUS_ALLOC_FAIL;
+
+ OPUS_CLEAR((char*)st, opus_custom_decoder_get_size(mode, channels));
+
+ st->mode = mode;
+ st->overlap = mode->overlap;
+ st->stream_channels = st->channels = channels;
+
+ st->downsample = 1;
+ st->start = 0;
+ st->end = st->mode->effEBands;
+ st->signalling = 1;
+ st->arch = opus_select_arch();
+
+ st->loss_count = 0;
+
+ opus_custom_decoder_ctl(st, OPUS_RESET_STATE);
+
+ return OPUS_OK;
+}
+
+#ifdef CUSTOM_MODES
+void opus_custom_decoder_destroy(CELTDecoder *st)
+{
+ opus_free(st);
+}
+#endif /* CUSTOM_MODES */
+
+static OPUS_INLINE opus_val16 SIG2WORD16(celt_sig x)
+{
+#ifdef OPUS_FIXED_POINT
+ x = PSHR32(x, SIG_SHIFT);
+ x = MAX32(x, -32768);
+ x = MIN32(x, 32767);
+ return EXTRACT16(x);
+#else
+ return (opus_val16)x;
+#endif
+}
+
+#ifndef RESYNTH
+static
+#endif
+void deemphasis(celt_sig *in[], opus_val16 *pcm, int N, int C, int downsample, const opus_val16 *coef, celt_sig *mem, celt_sig * OPUS_RESTRICT scratch)
+{
+ int c;
+ int Nd;
+ int apply_downsampling=0;
+ opus_val16 coef0;
+
+ coef0 = coef[0];
+ Nd = N/downsample;
+ c=0; do {
+ int j;
+ celt_sig * OPUS_RESTRICT x;
+ opus_val16 * OPUS_RESTRICT y;
+ celt_sig m = mem[c];
+ x =in[c];
+ y = pcm+c;
+#ifdef CUSTOM_MODES
+ if (coef[1] != 0)
+ {
+ opus_val16 coef1 = coef[1];
+ opus_val16 coef3 = coef[3];
+ for (j=0;j<N;j++)
+ {
+ celt_sig tmp = x[j] + m + VERY_SMALL;
+ m = MULT16_32_Q15(coef0, tmp)
+ - MULT16_32_Q15(coef1, x[j]);
+ tmp = SHL32(MULT16_32_Q15(coef3, tmp), 2);
+ scratch[j] = tmp;
+ }
+ apply_downsampling=1;
+ } else
+#endif
+ if (downsample>1)
+ {
+ /* Shortcut for the standard (non-custom modes) case */
+ for (j=0;j<N;j++)
+ {
+ celt_sig tmp = x[j] + m + VERY_SMALL;
+ m = MULT16_32_Q15(coef0, tmp);
+ scratch[j] = tmp;
+ }
+ apply_downsampling=1;
+ } else {
+ /* Shortcut for the standard (non-custom modes) case */
+ for (j=0;j<N;j++)
+ {
+ celt_sig tmp = x[j] + m + VERY_SMALL;
+ m = MULT16_32_Q15(coef0, tmp);
+ y[j*C] = SCALEOUT(SIG2WORD16(tmp));
+ }
+ }
+ mem[c] = m;
+
+ if (apply_downsampling)
+ {
+ /* Perform down-sampling */
+ for (j=0;j<Nd;j++)
+ y[j*C] = SCALEOUT(SIG2WORD16(scratch[j*downsample]));
+ }
+ } while (++c<C);
+}
+
+/** Compute the IMDCT and apply window for all sub-frames and
+ all channels in a frame */
+#ifndef RESYNTH
+static
+#endif
+void compute_inv_mdcts(const CELTMode *mode, int shortBlocks, celt_sig *X,
+ celt_sig * OPUS_RESTRICT out_mem[], int C, int LM)
+{
+ int b, c;
+ int B;
+ int N;
+ int shift;
+ const int overlap = OVERLAP(mode);
+
+ if (shortBlocks)
+ {
+ B = shortBlocks;
+ N = mode->shortMdctSize;
+ shift = mode->maxLM;
+ } else {
+ B = 1;
+ N = mode->shortMdctSize<<LM;
+ shift = mode->maxLM-LM;
+ }
+ c=0; do {
+ /* IMDCT on the interleaved the sub-frames, overlap-add is performed by the IMDCT */
+ for (b=0;b<B;b++)
+ clt_mdct_backward(&mode->mdct, &X[b+c*N*B], out_mem[c]+N*b, mode->window, overlap, shift, B);
+ } while (++c<C);
+}
+
+static void tf_decode(int start, int end, int isTransient, int *tf_res, int LM, ec_dec *dec)
+{
+ int i, curr, tf_select;
+ int tf_select_rsv;
+ int tf_changed;
+ int logp;
+ opus_uint32 budget;
+ opus_uint32 tell;
+
+ budget = dec->storage*8;
+ tell = ec_tell(dec);
+ logp = isTransient ? 2 : 4;
+ tf_select_rsv = LM>0 && tell+logp+1<=budget;
+ budget -= tf_select_rsv;
+ tf_changed = curr = 0;
+ for (i=start;i<end;i++)
+ {
+ if (tell+logp<=budget)
+ {
+ curr ^= ec_dec_bit_logp(dec, logp);
+ tell = ec_tell(dec);
+ tf_changed |= curr;
+ }
+ tf_res[i] = curr;
+ logp = isTransient ? 4 : 5;
+ }
+ tf_select = 0;
+ if (tf_select_rsv &&
+ tf_select_table[LM][4*isTransient+0+tf_changed] !=
+ tf_select_table[LM][4*isTransient+2+tf_changed])
+ {
+ tf_select = ec_dec_bit_logp(dec, 1);
+ }
+ for (i=start;i<end;i++)
+ {
+ tf_res[i] = tf_select_table[LM][4*isTransient+2*tf_select+tf_res[i]];
+ }
+}
+
+/* The maximum pitch lag to allow in the pitch-based PLC. It's possible to save
+ CPU time in the PLC pitch search by making this smaller than MAX_PERIOD. The
+ current value corresponds to a pitch of 66.67 Hz. */
+#define PLC_PITCH_LAG_MAX (720)
+/* The minimum pitch lag to allow in the pitch-based PLC. This corresponds to a
+ pitch of 480 Hz. */
+#define PLC_PITCH_LAG_MIN (100)
+
+static void celt_decode_lost(CELTDecoder * OPUS_RESTRICT st, opus_val16 * OPUS_RESTRICT pcm, int N, int LM)
+{
+ int c;
+ int i;
+ const int C = st->channels;
+ celt_sig *decode_mem[2];
+ celt_sig *out_syn[2];
+ opus_val16 *lpc;
+ opus_val16 *oldBandE, *oldLogE, *oldLogE2, *backgroundLogE;
+ const OpusCustomMode *mode;
+ int nbEBands;
+ int overlap;
+ int start;
+ int downsample;
+ int loss_count;
+ int noise_based;
+ const opus_int16 *eBands;
+ VARDECL(celt_sig, scratch);
+ SAVE_STACK;
+
+ mode = st->mode;
+ nbEBands = mode->nbEBands;
+ overlap = mode->overlap;
+ eBands = mode->eBands;
+
+ c=0; do {
+ decode_mem[c] = st->_decode_mem + c*(DECODE_BUFFER_SIZE+overlap);
+ out_syn[c] = decode_mem[c]+DECODE_BUFFER_SIZE-N;
+ } while (++c<C);
+ lpc = (opus_val16*)(st->_decode_mem+(DECODE_BUFFER_SIZE+overlap)*C);
+ oldBandE = lpc+C*LPC_ORDER;
+ oldLogE = oldBandE + 2*nbEBands;
+ oldLogE2 = oldLogE + 2*nbEBands;
+ backgroundLogE = oldLogE2 + 2*nbEBands;
+
+ loss_count = st->loss_count;
+ start = st->start;
+ downsample = st->downsample;
+ noise_based = loss_count >= 5 || start != 0;
+ ALLOC(scratch, noise_based?N*C:N, celt_sig);
+ if (noise_based)
+ {
+ /* Noise-based PLC/CNG */
+ celt_sig *freq;
+ VARDECL(celt_norm, X);
+ opus_uint32 seed;
+ opus_val16 *plcLogE;
+ int end;
+ int effEnd;
+
+ end = st->end;
+ effEnd = IMAX(start, IMIN(end, mode->effEBands));
+
+ /* Share the interleaved signal MDCT coefficient buffer with the
+ deemphasis scratch buffer. */
+ freq = scratch;
+ ALLOC(X, C*N, celt_norm); /**< Interleaved normalised MDCTs */
+
+ if (loss_count >= 5)
+ plcLogE = backgroundLogE;
+ else {
+ /* Energy decay */
+ opus_val16 decay = loss_count==0 ?
+ QCONST16(1.5f, DB_SHIFT) : QCONST16(.5f, DB_SHIFT);
+ c=0; do
+ {
+ for (i=start;i<end;i++)
+ oldBandE[c*nbEBands+i] -= decay;
+ } while (++c<C);
+ plcLogE = oldBandE;
+ }
+ seed = st->rng;
+ for (c=0;c<C;c++)
+ {
+ for (i=start;i<effEnd;i++)
+ {
+ int j;
+ int boffs;
+ int blen;
+ boffs = N*c+(eBands[i]<<LM);
+ blen = (eBands[i+1]-eBands[i])<<LM;
+ for (j=0;j<blen;j++)
+ {
+ seed = celt_lcg_rand(seed);
+ X[boffs+j] = (celt_norm)((opus_int32)seed>>20);
+ }
+ renormalise_vector(X+boffs, blen, Q15ONE);
+ }
+ }
+ st->rng = seed;
+
+ denormalise_bands(mode, X, freq, plcLogE, start, effEnd, C, 1<<LM);
+
+ c=0; do {
+ int bound = eBands[effEnd]<<LM;
+ if (downsample!=1)
+ bound = IMIN(bound, N/downsample);
+ for (i=bound;i<N;i++)
+ freq[c*N+i] = 0;
+ } while (++c<C);
+ c=0; do {
+ OPUS_MOVE(decode_mem[c], decode_mem[c]+N,
+ DECODE_BUFFER_SIZE-N+(overlap>>1));
+ } while (++c<C);
+ compute_inv_mdcts(mode, 0, freq, out_syn, C, LM);
+ } else {
+ /* Pitch-based PLC */
+ const opus_val16 *window;
+ opus_val16 fade = Q15ONE;
+ int pitch_index;
+ VARDECL(opus_val32, etmp);
+ VARDECL(opus_val16, exc);
+
+ if (loss_count == 0)
+ {
+ VARDECL( opus_val16, lp_pitch_buf );
+ ALLOC( lp_pitch_buf, DECODE_BUFFER_SIZE>>1, opus_val16 );
+ pitch_downsample(decode_mem, lp_pitch_buf,
+ DECODE_BUFFER_SIZE, C, st->arch);
+ pitch_search(lp_pitch_buf+(PLC_PITCH_LAG_MAX>>1), lp_pitch_buf,
+ DECODE_BUFFER_SIZE-PLC_PITCH_LAG_MAX,
+ PLC_PITCH_LAG_MAX-PLC_PITCH_LAG_MIN, &pitch_index, st->arch);
+ pitch_index = PLC_PITCH_LAG_MAX-pitch_index;
+ st->last_pitch_index = pitch_index;
+ } else {
+ pitch_index = st->last_pitch_index;
+ fade = QCONST16(.8f,15);
+ }
+
+ ALLOC(etmp, overlap, opus_val32);
+ ALLOC(exc, MAX_PERIOD, opus_val16);
+ window = mode->window;
+ c=0; do {
+ opus_val16 decay;
+ opus_val16 attenuation;
+ opus_val32 S1=0;
+ celt_sig *buf;
+ int extrapolation_offset;
+ int extrapolation_len;
+ int exc_length;
+ int j;
+
+ buf = decode_mem[c];
+ for (i=0;i<MAX_PERIOD;i++) {
+ exc[i] = ROUND16(buf[DECODE_BUFFER_SIZE-MAX_PERIOD+i], SIG_SHIFT);
+ }
+
+ if (loss_count == 0)
+ {
+ opus_val32 ac[LPC_ORDER+1];
+ /* Compute LPC coefficients for the last MAX_PERIOD samples before
+ the first loss so we can work in the excitation-filter domain. */
+ _celt_autocorr(exc, ac, window, overlap,
+ LPC_ORDER, MAX_PERIOD, st->arch);
+ /* Add a noise floor of -40 dB. */
+#ifdef OPUS_FIXED_POINT
+ ac[0] += SHR32(ac[0],13);
+#else
+ ac[0] *= 1.0001f;
+#endif
+ /* Use lag windowing to stabilize the Levinson-Durbin recursion. */
+ for (i=1;i<=LPC_ORDER;i++)
+ {
+ /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/
+#ifdef OPUS_FIXED_POINT
+ ac[i] -= MULT16_32_Q15(2*i*i, ac[i]);
+#else
+ ac[i] -= ac[i]*(0.008f*0.008f)*i*i;
+#endif
+ }
+ _celt_lpc(lpc+c*LPC_ORDER, ac, LPC_ORDER);
+ }
+ /* We want the excitation for 2 pitch periods in order to look for a
+ decaying signal, but we can't get more than MAX_PERIOD. */
+ exc_length = IMIN(2*pitch_index, MAX_PERIOD);
+ /* Initialize the LPC history with the samples just before the start
+ of the region for which we're computing the excitation. */
+ {
+ opus_val16 lpc_mem[LPC_ORDER];
+ for (i=0;i<LPC_ORDER;i++)
+ {
+ lpc_mem[i] =
+ ROUND16(buf[DECODE_BUFFER_SIZE-exc_length-1-i], SIG_SHIFT);
+ }
+ /* Compute the excitation for exc_length samples before the loss. */
+ celt_fir(exc+MAX_PERIOD-exc_length, lpc+c*LPC_ORDER,
+ exc+MAX_PERIOD-exc_length, exc_length, LPC_ORDER, lpc_mem);
+ }
+
+ /* Check if the waveform is decaying, and if so how fast.
+ We do this to avoid adding energy when concealing in a segment
+ with decaying energy. */
+ {
+ opus_val32 E1=1, E2=1;
+ int decay_length;
+#ifdef OPUS_FIXED_POINT
+ int shift = IMAX(0,2*celt_zlog2(celt_maxabs16(&exc[MAX_PERIOD-exc_length], exc_length))-20);
+#endif
+ decay_length = exc_length>>1;
+ for (i=0;i<decay_length;i++)
+ {
+ opus_val16 e;
+ e = exc[MAX_PERIOD-decay_length+i];
+ E1 += SHR32(MULT16_16(e, e), shift);
+ e = exc[MAX_PERIOD-2*decay_length+i];
+ E2 += SHR32(MULT16_16(e, e), shift);
+ }
+ E1 = MIN32(E1, E2);
+ decay = celt_sqrt(frac_div32(SHR32(E1, 1), E2));
+ }
+
+ /* Move the decoder memory one frame to the left to give us room to
+ add the data for the new frame. We ignore the overlap that extends
+ past the end of the buffer, because we aren't going to use it. */
+ OPUS_MOVE(buf, buf+N, DECODE_BUFFER_SIZE-N);
+
+ /* Extrapolate from the end of the excitation with a period of
+ "pitch_index", scaling down each period by an additional factor of
+ "decay". */
+ extrapolation_offset = MAX_PERIOD-pitch_index;
+ /* We need to extrapolate enough samples to cover a complete MDCT
+ window (including overlap/2 samples on both sides). */
+ extrapolation_len = N+overlap;
+ /* We also apply fading if this is not the first loss. */
+ attenuation = MULT16_16_Q15(fade, decay);
+ for (i=j=0;i<extrapolation_len;i++,j++)
+ {
+ opus_val16 tmp;
+ if (j >= pitch_index) {
+ j -= pitch_index;
+ attenuation = MULT16_16_Q15(attenuation, decay);
+ }
+ buf[DECODE_BUFFER_SIZE-N+i] =
+ SHL32(EXTEND32(MULT16_16_Q15(attenuation,
+ exc[extrapolation_offset+j])), SIG_SHIFT);
+ /* Compute the energy of the previously decoded signal whose
+ excitation we're copying. */
+ tmp = ROUND16(
+ buf[DECODE_BUFFER_SIZE-MAX_PERIOD-N+extrapolation_offset+j],
+ SIG_SHIFT);
+ S1 += SHR32(MULT16_16(tmp, tmp), 8);
+ }
+
+ {
+ opus_val16 lpc_mem[LPC_ORDER];
+ /* Copy the last decoded samples (prior to the overlap region) to
+ synthesis filter memory so we can have a continuous signal. */
+ for (i=0;i<LPC_ORDER;i++)
+ lpc_mem[i] = ROUND16(buf[DECODE_BUFFER_SIZE-N-1-i], SIG_SHIFT);
+ /* Apply the synthesis filter to convert the excitation back into
+ the signal domain. */
+ celt_iir(buf+DECODE_BUFFER_SIZE-N, lpc+c*LPC_ORDER,
+ buf+DECODE_BUFFER_SIZE-N, extrapolation_len, LPC_ORDER,
+ lpc_mem);
+ }
+
+ /* Check if the synthesis energy is higher than expected, which can
+ happen with the signal changes during our window. If so,
+ attenuate. */
+ {
+ opus_val32 S2=0;
+ for (i=0;i<extrapolation_len;i++)
+ {
+ opus_val16 tmp = ROUND16(buf[DECODE_BUFFER_SIZE-N+i], SIG_SHIFT);
+ S2 += SHR32(MULT16_16(tmp, tmp), 8);
+ }
+ /* This checks for an "explosion" in the synthesis. */
+#ifdef OPUS_FIXED_POINT
+ if (!(S1 > SHR32(S2,2)))
+#else
+ /* The float test is written this way to catch NaNs in the output
+ of the IIR filter at the same time. */
+ if (!(S1 > 0.2f*S2))
+#endif
+ {
+ for (i=0;i<extrapolation_len;i++)
+ buf[DECODE_BUFFER_SIZE-N+i] = 0;
+ } else if (S1 < S2)
+ {
+ opus_val16 ratio = celt_sqrt(frac_div32(SHR32(S1,1)+1,S2+1));
+ for (i=0;i<overlap;i++)
+ {
+ opus_val16 tmp_g = Q15ONE
+ - MULT16_16_Q15(window[i], Q15ONE-ratio);
+ buf[DECODE_BUFFER_SIZE-N+i] =
+ MULT16_32_Q15(tmp_g, buf[DECODE_BUFFER_SIZE-N+i]);
+ }
+ for (i=overlap;i<extrapolation_len;i++)
+ {
+ buf[DECODE_BUFFER_SIZE-N+i] =
+ MULT16_32_Q15(ratio, buf[DECODE_BUFFER_SIZE-N+i]);
+ }
+ }
+ }
+
+ /* Apply the pre-filter to the MDCT overlap for the next frame because
+ the post-filter will be re-applied in the decoder after the MDCT
+ overlap. */
+ comb_filter(etmp, buf+DECODE_BUFFER_SIZE,
+ st->postfilter_period, st->postfilter_period, overlap,
+ -st->postfilter_gain, -st->postfilter_gain,
+ st->postfilter_tapset, st->postfilter_tapset, NULL, 0);
+
+ /* Simulate TDAC on the concealed audio so that it blends with the
+ MDCT of the next frame. */
+ for (i=0;i<overlap/2;i++)
+ {
+ buf[DECODE_BUFFER_SIZE+i] =
+ MULT16_32_Q15(window[i], etmp[overlap-1-i])
+ + MULT16_32_Q15(window[overlap-i-1], etmp[i]);
+ }
+ } while (++c<C);
+ }
+
+ deemphasis(out_syn, pcm, N, C, downsample,
+ mode->preemph, st->preemph_memD, scratch);
+
+ st->loss_count = loss_count+1;
+
+ RESTORE_STACK;
+}
+
+int celt_decode_with_ec(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, opus_val16 * OPUS_RESTRICT pcm, int frame_size, ec_dec *dec)
+{
+ int c, i, N;
+ int spread_decision;
+ opus_int32 bits;
+ ec_dec _dec;
+ VARDECL(celt_sig, freq);
+ VARDECL(celt_norm, X);
+ VARDECL(int, fine_quant);
+ VARDECL(int, pulses);
+ VARDECL(int, cap);
+ VARDECL(int, offsets);
+ VARDECL(int, fine_priority);
+ VARDECL(int, tf_res);
+ VARDECL(unsigned char, collapse_masks);
+ celt_sig *decode_mem[2];
+ celt_sig *out_syn[2];
+ opus_val16 *lpc;
+ opus_val16 *oldBandE, *oldLogE, *oldLogE2, *backgroundLogE;
+
+ int shortBlocks;
+ int isTransient;
+ int intra_ener;
+ const int CC = st->channels;
+ int LM, M;
+ int effEnd;
+ int codedBands;
+ int alloc_trim;
+ int postfilter_pitch;
+ opus_val16 postfilter_gain;
+ int intensity=0;
+ int dual_stereo=0;
+ opus_int32 total_bits;
+ opus_int32 balance;
+ opus_int32 tell;
+ int dynalloc_logp;
+ int postfilter_tapset;
+ int anti_collapse_rsv;
+ int anti_collapse_on=0;
+ int silence;
+ int C = st->stream_channels;
+ const OpusCustomMode *mode;
+ int nbEBands;
+ int overlap;
+ const opus_int16 *eBands;
+ ALLOC_STACK;
+
+ mode = st->mode;
+ nbEBands = mode->nbEBands;
+ overlap = mode->overlap;
+ eBands = mode->eBands;
+ frame_size *= st->downsample;
+
+ c=0; do {
+ decode_mem[c] = st->_decode_mem + c*(DECODE_BUFFER_SIZE+overlap);
+ } while (++c<CC);
+ lpc = (opus_val16*)(st->_decode_mem+(DECODE_BUFFER_SIZE+overlap)*CC);
+ oldBandE = lpc+CC*LPC_ORDER;
+ oldLogE = oldBandE + 2*nbEBands;
+ oldLogE2 = oldLogE + 2*nbEBands;
+ backgroundLogE = oldLogE2 + 2*nbEBands;
+
+#ifdef CUSTOM_MODES
+ if (st->signalling && data!=NULL)
+ {
+ int data0=data[0];
+ /* Convert "standard mode" to Opus header */
+ if (mode->Fs==48000 && mode->shortMdctSize==120)
+ {
+ data0 = fromOpus(data0);
+ if (data0<0)
+ return OPUS_INVALID_PACKET;
+ }
+ st->end = IMAX(1, mode->effEBands-2*(data0>>5));
+ LM = (data0>>3)&0x3;
+ C = 1 + ((data0>>2)&0x1);
+ data++;
+ len--;
+ if (LM>mode->maxLM)
+ return OPUS_INVALID_PACKET;
+ if (frame_size < mode->shortMdctSize<<LM)
+ return OPUS_BUFFER_TOO_SMALL;
+ else
+ frame_size = mode->shortMdctSize<<LM;
+ } else {
+#else
+ {
+#endif
+ for (LM=0;LM<=mode->maxLM;LM++)
+ if (mode->shortMdctSize<<LM==frame_size)
+ break;
+ if (LM>mode->maxLM)
+ return OPUS_BAD_ARG;
+ }
+ M=1<<LM;
+
+ if (len<0 || len>1275 || pcm==NULL)
+ return OPUS_BAD_ARG;
+
+ N = M*mode->shortMdctSize;
+
+ effEnd = st->end;
+ if (effEnd > mode->effEBands)
+ effEnd = mode->effEBands;
+
+ if (data == NULL || len<=1)
+ {
+ celt_decode_lost(st, pcm, N, LM);
+ RESTORE_STACK;
+ return frame_size/st->downsample;
+ }
+
+ if (dec == NULL)
+ {
+ ec_dec_init(&_dec,(unsigned char*)data,len);
+ dec = &_dec;
+ }
+
+ if (C==1)
+ {
+ for (i=0;i<nbEBands;i++)
+ oldBandE[i]=MAX16(oldBandE[i],oldBandE[nbEBands+i]);
+ }
+
+ total_bits = len*8;
+ tell = ec_tell(dec);
+
+ if (tell >= total_bits)
+ silence = 1;
+ else if (tell==1)
+ silence = ec_dec_bit_logp(dec, 15);
+ else
+ silence = 0;
+ if (silence)
+ {
+ /* Pretend we've read all the remaining bits */
+ tell = len*8;
+ dec->nbits_total+=tell-ec_tell(dec);
+ }
+
+ postfilter_gain = 0;
+ postfilter_pitch = 0;
+ postfilter_tapset = 0;
+ if (st->start==0 && tell+16 <= total_bits)
+ {
+ if(ec_dec_bit_logp(dec, 1))
+ {
+ int qg, octave;
+ octave = ec_dec_uint(dec, 6);
+ postfilter_pitch = (16<<octave)+ec_dec_bits(dec, 4+octave)-1;
+ qg = ec_dec_bits(dec, 3);
+ if (ec_tell(dec)+2<=total_bits)
+ postfilter_tapset = ec_dec_icdf(dec, tapset_icdf, 2);
+ postfilter_gain = QCONST16(.09375f,15)*(qg+1);
+ }
+ tell = ec_tell(dec);
+ }
+
+ if (LM > 0 && tell+3 <= total_bits)
+ {
+ isTransient = ec_dec_bit_logp(dec, 3);
+ tell = ec_tell(dec);
+ }
+ else
+ isTransient = 0;
+
+ if (isTransient)
+ shortBlocks = M;
+ else
+ shortBlocks = 0;
+
+ /* Decode the global flags (first symbols in the stream) */
+ intra_ener = tell+3<=total_bits ? ec_dec_bit_logp(dec, 3) : 0;
+ /* Get band energies */
+ unquant_coarse_energy(mode, st->start, st->end, oldBandE,
+ intra_ener, dec, C, LM);
+
+ ALLOC(tf_res, nbEBands, int);
+ tf_decode(st->start, st->end, isTransient, tf_res, LM, dec);
+
+ tell = ec_tell(dec);
+ spread_decision = SPREAD_NORMAL;
+ if (tell+4 <= total_bits)
+ spread_decision = ec_dec_icdf(dec, spread_icdf, 5);
+
+ ALLOC(cap, nbEBands, int);
+
+ init_caps(mode,cap,LM,C);
+
+ ALLOC(offsets, nbEBands, int);
+
+ dynalloc_logp = 6;
+ total_bits<<=BITRES;
+ tell = ec_tell_frac(dec);
+ for (i=st->start;i<st->end;i++)
+ {
+ int width, quanta;
+ int dynalloc_loop_logp;
+ int boost;
+ width = C*(eBands[i+1]-eBands[i])<<LM;
+ /* quanta is 6 bits, but no more than 1 bit/sample
+ and no less than 1/8 bit/sample */
+ quanta = IMIN(width<<BITRES, IMAX(6<<BITRES, width));
+ dynalloc_loop_logp = dynalloc_logp;
+ boost = 0;
+ while (tell+(dynalloc_loop_logp<<BITRES) < total_bits && boost < cap[i])
+ {
+ int flag;
+ flag = ec_dec_bit_logp(dec, dynalloc_loop_logp);
+ tell = ec_tell_frac(dec);
+ if (!flag)
+ break;
+ boost += quanta;
+ total_bits -= quanta;
+ dynalloc_loop_logp = 1;
+ }
+ offsets[i] = boost;
+ /* Making dynalloc more likely */
+ if (boost>0)
+ dynalloc_logp = IMAX(2, dynalloc_logp-1);
+ }
+
+ ALLOC(fine_quant, nbEBands, int);
+ alloc_trim = tell+(6<<BITRES) <= total_bits ?
+ ec_dec_icdf(dec, trim_icdf, 7) : 5;
+
+ bits = (((opus_int32)len*8)<<BITRES) - ec_tell_frac(dec) - 1;
+ anti_collapse_rsv = isTransient&&LM>=2&&bits>=((LM+2)<<BITRES) ? (1<<BITRES) : 0;
+ bits -= anti_collapse_rsv;
+
+ ALLOC(pulses, nbEBands, int);
+ ALLOC(fine_priority, nbEBands, int);
+
+ codedBands = compute_allocation(mode, st->start, st->end, offsets, cap,
+ alloc_trim, &intensity, &dual_stereo, bits, &balance, pulses,
+ fine_quant, fine_priority, C, LM, dec, 0, 0, 0);
+
+ unquant_fine_energy(mode, st->start, st->end, oldBandE, fine_quant, dec, C);
+
+ /* Decode fixed codebook */
+ ALLOC(collapse_masks, C*nbEBands, unsigned char);
+ ALLOC(X, C*N, celt_norm); /**< Interleaved normalised MDCTs */
+
+ quant_all_bands(0, mode, st->start, st->end, X, C==2 ? X+N : NULL, collapse_masks,
+ NULL, pulses, shortBlocks, spread_decision, dual_stereo, intensity, tf_res,
+ len*(8<<BITRES)-anti_collapse_rsv, balance, dec, LM, codedBands, &st->rng);
+
+ if (anti_collapse_rsv > 0)
+ {
+ anti_collapse_on = ec_dec_bits(dec, 1);
+ }
+
+ unquant_energy_finalise(mode, st->start, st->end, oldBandE,
+ fine_quant, fine_priority, len*8-ec_tell(dec), dec, C);
+
+ if (anti_collapse_on)
+ anti_collapse(mode, X, collapse_masks, LM, C, N,
+ st->start, st->end, oldBandE, oldLogE, oldLogE2, pulses, st->rng);
+
+ ALLOC(freq, IMAX(CC,C)*N, celt_sig); /**< Interleaved signal MDCTs */
+
+ if (silence)
+ {
+ for (i=0;i<C*nbEBands;i++)
+ oldBandE[i] = -QCONST16(28.f,DB_SHIFT);
+ for (i=0;i<C*N;i++)
+ freq[i] = 0;
+ } else {
+ /* Synthesis */
+ denormalise_bands(mode, X, freq, oldBandE, st->start, effEnd, C, M);
+ }
+ c=0; do {
+ OPUS_MOVE(decode_mem[c], decode_mem[c]+N, DECODE_BUFFER_SIZE-N+overlap/2);
+ } while (++c<CC);
+
+ c=0; do {
+ int bound = M*eBands[effEnd];
+ if (st->downsample!=1)
+ bound = IMIN(bound, N/st->downsample);
+ for (i=bound;i<N;i++)
+ freq[c*N+i] = 0;
+ } while (++c<C);
+
+ c=0; do {
+ out_syn[c] = decode_mem[c]+DECODE_BUFFER_SIZE-N;
+ } while (++c<CC);
+
+ if (CC==2&&C==1)
+ {
+ for (i=0;i<N;i++)
+ freq[N+i] = freq[i];
+ }
+ if (CC==1&&C==2)
+ {
+ for (i=0;i<N;i++)
+ freq[i] = HALF32(ADD32(freq[i],freq[N+i]));
+ }
+
+ /* Compute inverse MDCTs */
+ compute_inv_mdcts(mode, shortBlocks, freq, out_syn, CC, LM);
+
+ c=0; do {
+ st->postfilter_period=IMAX(st->postfilter_period, COMBFILTER_MINPERIOD);
+ st->postfilter_period_old=IMAX(st->postfilter_period_old, COMBFILTER_MINPERIOD);
+ comb_filter(out_syn[c], out_syn[c], st->postfilter_period_old, st->postfilter_period, mode->shortMdctSize,
+ st->postfilter_gain_old, st->postfilter_gain, st->postfilter_tapset_old, st->postfilter_tapset,
+ mode->window, overlap);
+ if (LM!=0)
+ comb_filter(out_syn[c]+mode->shortMdctSize, out_syn[c]+mode->shortMdctSize, st->postfilter_period, postfilter_pitch, N-mode->shortMdctSize,
+ st->postfilter_gain, postfilter_gain, st->postfilter_tapset, postfilter_tapset,
+ mode->window, overlap);
+
+ } while (++c<CC);
+ st->postfilter_period_old = st->postfilter_period;
+ st->postfilter_gain_old = st->postfilter_gain;
+ st->postfilter_tapset_old = st->postfilter_tapset;
+ st->postfilter_period = postfilter_pitch;
+ st->postfilter_gain = postfilter_gain;
+ st->postfilter_tapset = postfilter_tapset;
+ if (LM!=0)
+ {
+ st->postfilter_period_old = st->postfilter_period;
+ st->postfilter_gain_old = st->postfilter_gain;
+ st->postfilter_tapset_old = st->postfilter_tapset;
+ }
+
+ if (C==1) {
+ for (i=0;i<nbEBands;i++)
+ oldBandE[nbEBands+i]=oldBandE[i];
+ }
+
+ /* In case start or end were to change */
+ if (!isTransient)
+ {
+ for (i=0;i<2*nbEBands;i++)
+ oldLogE2[i] = oldLogE[i];
+ for (i=0;i<2*nbEBands;i++)
+ oldLogE[i] = oldBandE[i];
+ for (i=0;i<2*nbEBands;i++)
+ backgroundLogE[i] = MIN16(backgroundLogE[i] + M*QCONST16(0.001f,DB_SHIFT), oldBandE[i]);
+ } else {
+ for (i=0;i<2*nbEBands;i++)
+ oldLogE[i] = MIN16(oldLogE[i], oldBandE[i]);
+ }
+ c=0; do
+ {
+ for (i=0;i<st->start;i++)
+ {
+ oldBandE[c*nbEBands+i]=0;
+ oldLogE[c*nbEBands+i]=oldLogE2[c*nbEBands+i]=-QCONST16(28.f,DB_SHIFT);
+ }
+ for (i=st->end;i<nbEBands;i++)
+ {
+ oldBandE[c*nbEBands+i]=0;
+ oldLogE[c*nbEBands+i]=oldLogE2[c*nbEBands+i]=-QCONST16(28.f,DB_SHIFT);
+ }
+ } while (++c<2);
+ st->rng = dec->rng;
+
+ /* We reuse freq[] as scratch space for the de-emphasis */
+ deemphasis(out_syn, pcm, N, CC, st->downsample, mode->preemph, st->preemph_memD, freq);
+ st->loss_count = 0;
+ RESTORE_STACK;
+ if (ec_tell(dec) > 8*len)
+ return OPUS_INTERNAL_ERROR;
+ if(ec_get_error(dec))
+ st->error = 1;
+ return frame_size/st->downsample;
+}
+
+
+#ifdef CUSTOM_MODES
+
+#ifdef OPUS_FIXED_POINT
+int opus_custom_decode(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, opus_int16 * OPUS_RESTRICT pcm, int frame_size)
+{
+ return celt_decode_with_ec(st, data, len, pcm, frame_size, NULL);
+}
+
+#ifndef DISABLE_FLOAT_API
+int opus_custom_decode_float(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, float * OPUS_RESTRICT pcm, int frame_size)
+{
+ int j, ret, C, N;
+ VARDECL(opus_int16, out);
+ ALLOC_STACK;
+
+ if (pcm==NULL)
+ return OPUS_BAD_ARG;
+
+ C = st->channels;
+ N = frame_size;
+
+ ALLOC(out, C*N, opus_int16);
+ ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL);
+ if (ret>0)
+ for (j=0;j<C*ret;j++)
+ pcm[j]=out[j]*(1.f/32768.f);
+
+ RESTORE_STACK;
+ return ret;
+}
+#endif /* DISABLE_FLOAT_API */
+
+#else
+
+int opus_custom_decode_float(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, float * OPUS_RESTRICT pcm, int frame_size)
+{
+ return celt_decode_with_ec(st, data, len, pcm, frame_size, NULL);
+}
+
+int opus_custom_decode(CELTDecoder * OPUS_RESTRICT st, const unsigned char *data, int len, opus_int16 * OPUS_RESTRICT pcm, int frame_size)
+{
+ int j, ret, C, N;
+ VARDECL(celt_sig, out);
+ ALLOC_STACK;
+
+ if (pcm==NULL)
+ return OPUS_BAD_ARG;
+
+ C = st->channels;
+ N = frame_size;
+ ALLOC(out, C*N, celt_sig);
+
+ ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL);
+
+ if (ret>0)
+ for (j=0;j<C*ret;j++)
+ pcm[j] = FLOAT2INT16 (out[j]);
+
+ RESTORE_STACK;
+ return ret;
+}
+
+#endif
+#endif /* CUSTOM_MODES */
+
+int opus_custom_decoder_ctl(CELTDecoder * OPUS_RESTRICT st, int request, ...)
+{
+ va_list ap;
+
+ va_start(ap, request);
+ switch (request)
+ {
+ case CELT_SET_START_BAND_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<0 || value>=st->mode->nbEBands)
+ goto bad_arg;
+ st->start = value;
+ }
+ break;
+ case CELT_SET_END_BAND_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<1 || value>st->mode->nbEBands)
+ goto bad_arg;
+ st->end = value;
+ }
+ break;
+ case CELT_SET_CHANNELS_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<1 || value>2)
+ goto bad_arg;
+ st->stream_channels = value;
+ }
+ break;
+ case CELT_GET_AND_CLEAR_ERROR_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (value==NULL)
+ goto bad_arg;
+ *value=st->error;
+ st->error = 0;
+ }
+ break;
+ case OPUS_GET_LOOKAHEAD_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (value==NULL)
+ goto bad_arg;
+ *value = st->overlap/st->downsample;
+ }
+ break;
+ case OPUS_RESET_STATE:
+ {
+ int i;
+ opus_val16 *lpc, *oldBandE, *oldLogE, *oldLogE2;
+ lpc = (opus_val16*)(st->_decode_mem+(DECODE_BUFFER_SIZE+st->overlap)*st->channels);
+ oldBandE = lpc+st->channels*LPC_ORDER;
+ oldLogE = oldBandE + 2*st->mode->nbEBands;
+ oldLogE2 = oldLogE + 2*st->mode->nbEBands;
+ OPUS_CLEAR((char*)&st->DECODER_RESET_START,
+ opus_custom_decoder_get_size(st->mode, st->channels)-
+ ((char*)&st->DECODER_RESET_START - (char*)st));
+ for (i=0;i<2*st->mode->nbEBands;i++)
+ oldLogE[i]=oldLogE2[i]=-QCONST16(28.f,DB_SHIFT);
+ }
+ break;
+ case OPUS_GET_PITCH_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (value==NULL)
+ goto bad_arg;
+ *value = st->postfilter_period;
+ }
+ break;
+ case CELT_GET_MODE_REQUEST:
+ {
+ const CELTMode ** value = va_arg(ap, const CELTMode**);
+ if (value==0)
+ goto bad_arg;
+ *value=st->mode;
+ }
+ break;
+ case CELT_SET_SIGNALLING_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ st->signalling = value;
+ }
+ break;
+ case OPUS_GET_FINAL_RANGE_REQUEST:
+ {
+ opus_uint32 * value = va_arg(ap, opus_uint32 *);
+ if (value==0)
+ goto bad_arg;
+ *value=st->rng;
+ }
+ break;
+ default:
+ goto bad_request;
+ }
+ va_end(ap);
+ return OPUS_OK;
+bad_arg:
+ va_end(ap);
+ return OPUS_BAD_ARG;
+bad_request:
+ va_end(ap);
+ return OPUS_UNIMPLEMENTED;
+}
diff --git a/drivers/opus/celt/celt_encoder.c b/drivers/opus/celt/celt_encoder.c
new file mode 100644
index 0000000000..810ee5d743
--- /dev/null
+++ b/drivers/opus/celt/celt_encoder.c
@@ -0,0 +1,2353 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2010 Xiph.Org Foundation
+ Copyright (c) 2008 Gregory Maxwell
+ Written by Jean-Marc Valin and Gregory Maxwell */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#define CELT_ENCODER_C
+
+#include "opus/celt/cpu_support.h"
+#include "opus/celt/os_support.h"
+#include "opus/celt/mdct.h"
+#include <math.h>
+#include "opus/celt/celt.h"
+#include "opus/celt/pitch.h"
+#include "opus/celt/bands.h"
+#include "opus/celt/opus_modes.h"
+#include "opus/celt/entcode.h"
+#include "opus/celt/quant_bands.h"
+#include "opus/celt/rate.h"
+#include "opus/celt/stack_alloc.h"
+#include "opus/celt/mathops.h"
+#include "opus/celt/float_cast.h"
+#include <stdarg.h>
+#include "opus/celt/celt_lpc.h"
+#include "opus/celt/vq.h"
+
+
+/** Encoder state
+ @brief Encoder state
+ */
+struct OpusCustomEncoder {
+ const OpusCustomMode *mode; /**< Mode used by the encoder */
+ int overlap;
+ int channels;
+ int stream_channels;
+
+ int force_intra;
+ int clip;
+ int disable_pf;
+ int complexity;
+ int upsample;
+ int start, end;
+
+ opus_int32 bitrate;
+ int vbr;
+ int signalling;
+ int constrained_vbr; /* If zero, VBR can do whatever it likes with the rate */
+ int loss_rate;
+ int lsb_depth;
+ int variable_duration;
+ int lfe;
+ int arch;
+
+ /* Everything beyond this point gets cleared on a reset */
+#define ENCODER_RESET_START rng
+
+ opus_uint32 rng;
+ int spread_decision;
+ opus_val32 delayedIntra;
+ int tonal_average;
+ int lastCodedBands;
+ int hf_average;
+ int tapset_decision;
+
+ int prefilter_period;
+ opus_val16 prefilter_gain;
+ int prefilter_tapset;
+#ifdef RESYNTH
+ int prefilter_period_old;
+ opus_val16 prefilter_gain_old;
+ int prefilter_tapset_old;
+#endif
+ int consec_transient;
+ AnalysisInfo analysis;
+
+ opus_val32 preemph_memE[2];
+ opus_val32 preemph_memD[2];
+
+ /* VBR-related parameters */
+ opus_int32 vbr_reservoir;
+ opus_int32 vbr_drift;
+ opus_int32 vbr_offset;
+ opus_int32 vbr_count;
+ opus_val32 overlap_max;
+ opus_val16 stereo_saving;
+ int intensity;
+ opus_val16 *energy_mask;
+ opus_val16 spec_avg;
+
+#ifdef RESYNTH
+ /* +MAX_PERIOD/2 to make space for overlap */
+ celt_sig syn_mem[2][2*MAX_PERIOD+MAX_PERIOD/2];
+#endif
+
+ celt_sig in_mem[1]; /* Size = channels*mode->overlap */
+ /* celt_sig prefilter_mem[], Size = channels*COMBFILTER_MAXPERIOD */
+ /* opus_val16 oldBandE[], Size = channels*mode->nbEBands */
+ /* opus_val16 oldLogE[], Size = channels*mode->nbEBands */
+ /* opus_val16 oldLogE2[], Size = channels*mode->nbEBands */
+};
+
+int celt_encoder_get_size(int channels)
+{
+ CELTMode *mode = opus_custom_mode_create(48000, 960, NULL);
+ return opus_custom_encoder_get_size(mode, channels);
+}
+
+OPUS_CUSTOM_NOSTATIC int opus_custom_encoder_get_size(const CELTMode *mode, int channels)
+{
+ int size = sizeof(struct CELTEncoder)
+ + (channels*mode->overlap-1)*sizeof(celt_sig) /* celt_sig in_mem[channels*mode->overlap]; */
+ + channels*COMBFILTER_MAXPERIOD*sizeof(celt_sig) /* celt_sig prefilter_mem[channels*COMBFILTER_MAXPERIOD]; */
+ + 3*channels*mode->nbEBands*sizeof(opus_val16); /* opus_val16 oldBandE[channels*mode->nbEBands]; */
+ /* opus_val16 oldLogE[channels*mode->nbEBands]; */
+ /* opus_val16 oldLogE2[channels*mode->nbEBands]; */
+ return size;
+}
+
+#ifdef CUSTOM_MODES
+CELTEncoder *opus_custom_encoder_create(const CELTMode *mode, int channels, int *error)
+{
+ int ret;
+ CELTEncoder *st = (CELTEncoder *)opus_alloc(opus_custom_encoder_get_size(mode, channels));
+ /* init will handle the NULL case */
+ ret = opus_custom_encoder_init(st, mode, channels);
+ if (ret != OPUS_OK)
+ {
+ opus_custom_encoder_destroy(st);
+ st = NULL;
+ }
+ if (error)
+ *error = ret;
+ return st;
+}
+#endif /* CUSTOM_MODES */
+
+static int opus_custom_encoder_init_arch(CELTEncoder *st, const CELTMode *mode,
+ int channels, int arch)
+{
+ if (channels < 0 || channels > 2)
+ return OPUS_BAD_ARG;
+
+ if (st==NULL || mode==NULL)
+ return OPUS_ALLOC_FAIL;
+
+ OPUS_CLEAR((char*)st, opus_custom_encoder_get_size(mode, channels));
+
+ st->mode = mode;
+ st->overlap = mode->overlap;
+ st->stream_channels = st->channels = channels;
+
+ st->upsample = 1;
+ st->start = 0;
+ st->end = st->mode->effEBands;
+ st->signalling = 1;
+
+ st->arch = arch;
+
+ st->constrained_vbr = 1;
+ st->clip = 1;
+
+ st->bitrate = OPUS_BITRATE_MAX;
+ st->vbr = 0;
+ st->force_intra = 0;
+ st->complexity = 5;
+ st->lsb_depth=24;
+
+ opus_custom_encoder_ctl(st, OPUS_RESET_STATE);
+
+ return OPUS_OK;
+}
+
+#ifdef CUSTOM_MODES
+int opus_custom_encoder_init(CELTEncoder *st, const CELTMode *mode, int channels)
+{
+ return opus_custom_encoder_init_arch(st, mode, channels, opus_select_arch());
+}
+#endif
+
+int celt_encoder_init(CELTEncoder *st, opus_int32 sampling_rate, int channels,
+ int arch)
+{
+ int ret;
+ ret = opus_custom_encoder_init_arch(st,
+ opus_custom_mode_create(48000, 960, NULL), channels, arch);
+ if (ret != OPUS_OK)
+ return ret;
+ st->upsample = resampling_factor(sampling_rate);
+ return OPUS_OK;
+}
+
+#ifdef CUSTOM_MODES
+void opus_custom_encoder_destroy(CELTEncoder *st)
+{
+ opus_free(st);
+}
+#endif /* CUSTOM_MODES */
+
+
+static int transient_analysis(const opus_val32 * OPUS_RESTRICT in, int len, int C,
+ opus_val16 *tf_estimate, int *tf_chan)
+{
+ int i;
+ VARDECL(opus_val16, tmp);
+ opus_val32 mem0,mem1;
+ int is_transient = 0;
+ opus_int32 mask_metric = 0;
+ int c;
+ opus_val16 tf_max;
+ int len2;
+ /* Table of 6*64/x, trained on real data to minimize the average error */
+ static const unsigned char inv_table[128] = {
+ 255,255,156,110, 86, 70, 59, 51, 45, 40, 37, 33, 31, 28, 26, 25,
+ 23, 22, 21, 20, 19, 18, 17, 16, 16, 15, 15, 14, 13, 13, 12, 12,
+ 12, 12, 11, 11, 11, 10, 10, 10, 9, 9, 9, 9, 9, 9, 8, 8,
+ 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2,
+ };
+ SAVE_STACK;
+ ALLOC(tmp, len, opus_val16);
+
+ len2=len/2;
+ for (c=0;c<C;c++)
+ {
+ opus_val32 mean;
+ opus_int32 unmask=0;
+ opus_val32 norm;
+ opus_val16 maxE;
+ mem0=0;
+ mem1=0;
+ /* High-pass filter: (1 - 2*z^-1 + z^-2) / (1 - z^-1 + .5*z^-2) */
+ for (i=0;i<len;i++)
+ {
+ opus_val32 x,y;
+ x = SHR32(in[i+c*len],SIG_SHIFT);
+ y = ADD32(mem0, x);
+#ifdef OPUS_FIXED_POINT
+ mem0 = mem1 + y - SHL32(x,1);
+ mem1 = x - SHR32(y,1);
+#else
+ mem0 = mem1 + y - 2*x;
+ mem1 = x - .5f*y;
+#endif
+ tmp[i] = EXTRACT16(SHR32(y,2));
+ /*printf("%f ", tmp[i]);*/
+ }
+ /*printf("\n");*/
+ /* First few samples are bad because we don't propagate the memory */
+ for (i=0;i<12;i++)
+ tmp[i] = 0;
+
+#ifdef OPUS_FIXED_POINT
+ /* Normalize tmp to max range */
+ {
+ int shift=0;
+ shift = 14-celt_ilog2(1+celt_maxabs16(tmp, len));
+ if (shift!=0)
+ {
+ for (i=0;i<len;i++)
+ tmp[i] = SHL16(tmp[i], shift);
+ }
+ }
+#endif
+
+ mean=0;
+ mem0=0;
+ /* Grouping by two to reduce complexity */
+ /* Forward pass to compute the post-echo threshold*/
+ for (i=0;i<len2;i++)
+ {
+ opus_val16 x2 = PSHR32(MULT16_16(tmp[2*i],tmp[2*i]) + MULT16_16(tmp[2*i+1],tmp[2*i+1]),16);
+ mean += x2;
+#ifdef OPUS_FIXED_POINT
+ /* FIXME: Use PSHR16() instead */
+ tmp[i] = mem0 + PSHR32(x2-mem0,4);
+#else
+ tmp[i] = mem0 + MULT16_16_P15(QCONST16(.0625f,15),x2-mem0);
+#endif
+ mem0 = tmp[i];
+ }
+
+ mem0=0;
+ maxE=0;
+ /* Backward pass to compute the pre-echo threshold */
+ for (i=len2-1;i>=0;i--)
+ {
+#ifdef OPUS_FIXED_POINT
+ /* FIXME: Use PSHR16() instead */
+ tmp[i] = mem0 + PSHR32(tmp[i]-mem0,3);
+#else
+ tmp[i] = mem0 + MULT16_16_P15(QCONST16(0.125f,15),tmp[i]-mem0);
+#endif
+ mem0 = tmp[i];
+ maxE = MAX16(maxE, mem0);
+ }
+ /*for (i=0;i<len2;i++)printf("%f ", tmp[i]/mean);printf("\n");*/
+
+ /* Compute the ratio of the "frame energy" over the harmonic mean of the energy.
+ This essentially corresponds to a bitrate-normalized temporal noise-to-mask
+ ratio */
+
+ /* As a compromise with the old transient detector, frame energy is the
+ geometric mean of the energy and half the max */
+#ifdef OPUS_FIXED_POINT
+ /* Costs two sqrt() to avoid overflows */
+ mean = MULT16_16(celt_sqrt(mean), celt_sqrt(MULT16_16(maxE,len2>>1)));
+#else
+ mean = celt_sqrt(mean * maxE*.5*len2);
+#endif
+ /* Inverse of the mean energy in Q15+6 */
+ norm = SHL32(EXTEND32(len2),6+14)/ADD32(EPSILON,SHR32(mean,1));
+ /* Compute harmonic mean discarding the unreliable boundaries
+ The data is smooth, so we only take 1/4th of the samples */
+ unmask=0;
+ for (i=12;i<len2-5;i+=4)
+ {
+ int id;
+#ifdef OPUS_FIXED_POINT
+ id = IMAX(0,IMIN(127,MULT16_32_Q15(tmp[i],norm))); /* Do not round to nearest */
+#else
+ id = IMAX(0,IMIN(127,(int)floor(64*norm*tmp[i]))); /* Do not round to nearest */
+#endif
+ unmask += inv_table[id];
+ }
+ /*printf("%d\n", unmask);*/
+ /* Normalize, compensate for the 1/4th of the sample and the factor of 6 in the inverse table */
+ unmask = 64*unmask*4/(6*(len2-17));
+ if (unmask>mask_metric)
+ {
+ *tf_chan = c;
+ mask_metric = unmask;
+ }
+ }
+ is_transient = mask_metric>200;
+
+ /* Arbitrary metric for VBR boost */
+ tf_max = MAX16(0,celt_sqrt(27*mask_metric)-42);
+ /* *tf_estimate = 1 + MIN16(1, sqrt(MAX16(0, tf_max-30))/20); */
+ *tf_estimate = celt_sqrt(MAX16(0, SHL32(MULT16_16(QCONST16(0.0069,14),MIN16(163,tf_max)),14)-QCONST32(0.139,28)));
+ /*printf("%d %f\n", tf_max, mask_metric);*/
+ RESTORE_STACK;
+#ifdef FUZZING
+ is_transient = rand()&0x1;
+#endif
+ /*printf("%d %f %d\n", is_transient, (float)*tf_estimate, tf_max);*/
+ return is_transient;
+}
+
+/* Looks for sudden increases of energy to decide whether we need to patch
+ the transient decision */
+int patch_transient_decision(opus_val16 *newE, opus_val16 *oldE, int nbEBands,
+ int end, int C)
+{
+ int i, c;
+ opus_val32 mean_diff=0;
+ opus_val16 spread_old[26];
+ /* Apply an aggressive (-6 dB/Bark) spreading function to the old frame to
+ avoid false detection caused by irrelevant bands */
+ if (C==1)
+ {
+ spread_old[0] = oldE[0];
+ for (i=1;i<end;i++)
+ spread_old[i] = MAX16(spread_old[i-1]-QCONST16(1.0f, DB_SHIFT), oldE[i]);
+ } else {
+ spread_old[0] = MAX16(oldE[0],oldE[nbEBands]);
+ for (i=1;i<end;i++)
+ spread_old[i] = MAX16(spread_old[i-1]-QCONST16(1.0f, DB_SHIFT),
+ MAX16(oldE[i],oldE[i+nbEBands]));
+ }
+ for (i=end-2;i>=0;i--)
+ spread_old[i] = MAX16(spread_old[i], spread_old[i+1]-QCONST16(1.0f, DB_SHIFT));
+ /* Compute mean increase */
+ c=0; do {
+ for (i=2;i<end-1;i++)
+ {
+ opus_val16 x1, x2;
+ x1 = MAX16(0, newE[i]);
+ x2 = MAX16(0, spread_old[i]);
+ mean_diff = ADD32(mean_diff, EXTEND32(MAX16(0, SUB16(x1, x2))));
+ }
+ } while (++c<C);
+ mean_diff = DIV32(mean_diff, C*(end-3));
+ /*printf("%f %f %d\n", mean_diff, max_diff, count);*/
+ return mean_diff > QCONST16(1.f, DB_SHIFT);
+}
+
+/** Apply window and compute the MDCT for all sub-frames and
+ all channels in a frame */
+static void compute_mdcts(const CELTMode *mode, int shortBlocks, celt_sig * OPUS_RESTRICT in,
+ celt_sig * OPUS_RESTRICT out, int C, int CC, int LM, int upsample)
+{
+ const int overlap = OVERLAP(mode);
+ int N;
+ int B;
+ int shift;
+ int i, b, c;
+ if (shortBlocks)
+ {
+ B = shortBlocks;
+ N = mode->shortMdctSize;
+ shift = mode->maxLM;
+ } else {
+ B = 1;
+ N = mode->shortMdctSize<<LM;
+ shift = mode->maxLM-LM;
+ }
+ c=0; do {
+ for (b=0;b<B;b++)
+ {
+ /* Interleaving the sub-frames while doing the MDCTs */
+ clt_mdct_forward(&mode->mdct, in+c*(B*N+overlap)+b*N, &out[b+c*N*B], mode->window, overlap, shift, B);
+ }
+ } while (++c<CC);
+ if (CC==2&&C==1)
+ {
+ for (i=0;i<B*N;i++)
+ out[i] = ADD32(HALF32(out[i]), HALF32(out[B*N+i]));
+ }
+ if (upsample != 1)
+ {
+ c=0; do
+ {
+ int bound = B*N/upsample;
+ for (i=0;i<bound;i++)
+ out[c*B*N+i] *= upsample;
+ for (;i<B*N;i++)
+ out[c*B*N+i] = 0;
+ } while (++c<C);
+ }
+}
+
+
+void celt_preemphasis(const opus_val16 * OPUS_RESTRICT pcmp, celt_sig * OPUS_RESTRICT inp,
+ int N, int CC, int upsample, const opus_val16 *coef, celt_sig *mem, int clip)
+{
+ int i;
+ opus_val16 coef0;
+ celt_sig m;
+ int Nu;
+
+ coef0 = coef[0];
+
+
+ Nu = N/upsample;
+ if (upsample!=1)
+ {
+ for (i=0;i<N;i++)
+ inp[i] = 0;
+ }
+ for (i=0;i<Nu;i++)
+ {
+ celt_sig x;
+
+ x = SCALEIN(pcmp[CC*i]);
+#ifndef OPUS_FIXED_POINT
+ /* Replace NaNs with zeros */
+ if (!(x==x))
+ x = 0;
+#endif
+ inp[i*upsample] = x;
+ }
+
+#ifndef OPUS_FIXED_POINT
+ if (clip)
+ {
+ /* Clip input to avoid encoding non-portable files */
+ for (i=0;i<Nu;i++)
+ inp[i*upsample] = MAX32(-65536.f, MIN32(65536.f,inp[i*upsample]));
+ }
+#else
+ (void)clip; /* Avoids a warning about clip being unused. */
+#endif
+ m = *mem;
+#ifdef CUSTOM_MODES
+ if (coef[1] != 0)
+ {
+ opus_val16 coef1 = coef[1];
+ opus_val16 coef2 = coef[2];
+ for (i=0;i<N;i++)
+ {
+ celt_sig x, tmp;
+ x = inp[i];
+ /* Apply pre-emphasis */
+ tmp = MULT16_16(coef2, x);
+ inp[i] = tmp + m;
+ m = MULT16_32_Q15(coef1, inp[i]) - MULT16_32_Q15(coef0, tmp);
+ }
+ } else
+#endif
+ {
+ for (i=0;i<N;i++)
+ {
+ celt_sig x;
+ x = SHL32(inp[i], SIG_SHIFT);
+ /* Apply pre-emphasis */
+ inp[i] = x + m;
+ m = - MULT16_32_Q15(coef0, x);
+ }
+ }
+ *mem = m;
+}
+
+
+
+static opus_val32 l1_metric(const celt_norm *tmp, int N, int LM, opus_val16 bias)
+{
+ int i;
+ opus_val32 L1;
+ L1 = 0;
+ for (i=0;i<N;i++)
+ L1 += EXTEND32(ABS16(tmp[i]));
+ /* When in doubt, prefer good freq resolution */
+ L1 = MAC16_32_Q15(L1, LM*bias, L1);
+ return L1;
+
+}
+
+static int tf_analysis(const CELTMode *m, int len, int isTransient,
+ int *tf_res, int lambda, celt_norm *X, int N0, int LM,
+ int *tf_sum, opus_val16 tf_estimate, int tf_chan)
+{
+ int i;
+ VARDECL(int, metric);
+ int cost0;
+ int cost1;
+ VARDECL(int, path0);
+ VARDECL(int, path1);
+ VARDECL(celt_norm, tmp);
+ VARDECL(celt_norm, tmp_1);
+ int sel;
+ int selcost[2];
+ int tf_select=0;
+ opus_val16 bias;
+
+ SAVE_STACK;
+ bias = MULT16_16_Q14(QCONST16(.04f,15), MAX16(-QCONST16(.25f,14), QCONST16(.5f,14)-tf_estimate));
+ /*printf("%f ", bias);*/
+
+ ALLOC(metric, len, int);
+ ALLOC(tmp, (m->eBands[len]-m->eBands[len-1])<<LM, celt_norm);
+ ALLOC(tmp_1, (m->eBands[len]-m->eBands[len-1])<<LM, celt_norm);
+ ALLOC(path0, len, int);
+ ALLOC(path1, len, int);
+
+ *tf_sum = 0;
+ for (i=0;i<len;i++)
+ {
+ int j, k, N;
+ int narrow;
+ opus_val32 L1, best_L1;
+ int best_level=0;
+ N = (m->eBands[i+1]-m->eBands[i])<<LM;
+ /* band is too narrow to be split down to LM=-1 */
+ narrow = (m->eBands[i+1]-m->eBands[i])==1;
+ for (j=0;j<N;j++)
+ tmp[j] = X[tf_chan*N0 + j+(m->eBands[i]<<LM)];
+ /* Just add the right channel if we're in stereo */
+ /*if (C==2)
+ for (j=0;j<N;j++)
+ tmp[j] = ADD16(SHR16(tmp[j], 1),SHR16(X[N0+j+(m->eBands[i]<<LM)], 1));*/
+ L1 = l1_metric(tmp, N, isTransient ? LM : 0, bias);
+ best_L1 = L1;
+ /* Check the -1 case for transients */
+ if (isTransient && !narrow)
+ {
+ for (j=0;j<N;j++)
+ tmp_1[j] = tmp[j];
+ haar1(tmp_1, N>>LM, 1<<LM);
+ L1 = l1_metric(tmp_1, N, LM+1, bias);
+ if (L1<best_L1)
+ {
+ best_L1 = L1;
+ best_level = -1;
+ }
+ }
+ /*printf ("%f ", L1);*/
+ for (k=0;k<LM+!(isTransient||narrow);k++)
+ {
+ int B;
+
+ if (isTransient)
+ B = (LM-k-1);
+ else
+ B = k+1;
+
+ haar1(tmp, N>>k, 1<<k);
+
+ L1 = l1_metric(tmp, N, B, bias);
+
+ if (L1 < best_L1)
+ {
+ best_L1 = L1;
+ best_level = k+1;
+ }
+ }
+ /*printf ("%d ", isTransient ? LM-best_level : best_level);*/
+ /* metric is in Q1 to be able to select the mid-point (-0.5) for narrower bands */
+ if (isTransient)
+ metric[i] = 2*best_level;
+ else
+ metric[i] = -2*best_level;
+ *tf_sum += (isTransient ? LM : 0) - metric[i]/2;
+ /* For bands that can't be split to -1, set the metric to the half-way point to avoid
+ biasing the decision */
+ if (narrow && (metric[i]==0 || metric[i]==-2*LM))
+ metric[i]-=1;
+ /*printf("%d ", metric[i]);*/
+ }
+ /*printf("\n");*/
+ /* Search for the optimal tf resolution, including tf_select */
+ tf_select = 0;
+ for (sel=0;sel<2;sel++)
+ {
+ cost0 = 0;
+ cost1 = isTransient ? 0 : lambda;
+ for (i=1;i<len;i++)
+ {
+ int curr0, curr1;
+ curr0 = IMIN(cost0, cost1 + lambda);
+ curr1 = IMIN(cost0 + lambda, cost1);
+ cost0 = curr0 + abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*sel+0]);
+ cost1 = curr1 + abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*sel+1]);
+ }
+ cost0 = IMIN(cost0, cost1);
+ selcost[sel]=cost0;
+ }
+ /* For now, we're conservative and only allow tf_select=1 for transients.
+ * If tests confirm it's useful for non-transients, we could allow it. */
+ if (selcost[1]<selcost[0] && isTransient)
+ tf_select=1;
+ cost0 = 0;
+ cost1 = isTransient ? 0 : lambda;
+ /* Viterbi forward pass */
+ for (i=1;i<len;i++)
+ {
+ int curr0, curr1;
+ int from0, from1;
+
+ from0 = cost0;
+ from1 = cost1 + lambda;
+ if (from0 < from1)
+ {
+ curr0 = from0;
+ path0[i]= 0;
+ } else {
+ curr0 = from1;
+ path0[i]= 1;
+ }
+
+ from0 = cost0 + lambda;
+ from1 = cost1;
+ if (from0 < from1)
+ {
+ curr1 = from0;
+ path1[i]= 0;
+ } else {
+ curr1 = from1;
+ path1[i]= 1;
+ }
+ cost0 = curr0 + abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*tf_select+0]);
+ cost1 = curr1 + abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*tf_select+1]);
+ }
+ tf_res[len-1] = cost0 < cost1 ? 0 : 1;
+ /* Viterbi backward pass to check the decisions */
+ for (i=len-2;i>=0;i--)
+ {
+ if (tf_res[i+1] == 1)
+ tf_res[i] = path1[i+1];
+ else
+ tf_res[i] = path0[i+1];
+ }
+ /*printf("%d %f\n", *tf_sum, tf_estimate);*/
+ RESTORE_STACK;
+#ifdef FUZZING
+ tf_select = rand()&0x1;
+ tf_res[0] = rand()&0x1;
+ for (i=1;i<len;i++)
+ tf_res[i] = tf_res[i-1] ^ ((rand()&0xF) == 0);
+#endif
+ return tf_select;
+}
+
+static void tf_encode(int start, int end, int isTransient, int *tf_res, int LM, int tf_select, ec_enc *enc)
+{
+ int curr, i;
+ int tf_select_rsv;
+ int tf_changed;
+ int logp;
+ opus_uint32 budget;
+ opus_uint32 tell;
+ budget = enc->storage*8;
+ tell = ec_tell(enc);
+ logp = isTransient ? 2 : 4;
+ /* Reserve space to code the tf_select decision. */
+ tf_select_rsv = LM>0 && tell+logp+1 <= budget;
+ budget -= tf_select_rsv;
+ curr = tf_changed = 0;
+ for (i=start;i<end;i++)
+ {
+ if (tell+logp<=budget)
+ {
+ ec_enc_bit_logp(enc, tf_res[i] ^ curr, logp);
+ tell = ec_tell(enc);
+ curr = tf_res[i];
+ tf_changed |= curr;
+ }
+ else
+ tf_res[i] = curr;
+ logp = isTransient ? 4 : 5;
+ }
+ /* Only code tf_select if it would actually make a difference. */
+ if (tf_select_rsv &&
+ tf_select_table[LM][4*isTransient+0+tf_changed]!=
+ tf_select_table[LM][4*isTransient+2+tf_changed])
+ ec_enc_bit_logp(enc, tf_select, 1);
+ else
+ tf_select = 0;
+ for (i=start;i<end;i++)
+ tf_res[i] = tf_select_table[LM][4*isTransient+2*tf_select+tf_res[i]];
+ /*for(i=0;i<end;i++)printf("%d ", isTransient ? tf_res[i] : LM+tf_res[i]);printf("\n");*/
+}
+
+
+static int alloc_trim_analysis(const CELTMode *m, const celt_norm *X,
+ const opus_val16 *bandLogE, int end, int LM, int C, int N0,
+ AnalysisInfo *analysis, opus_val16 *stereo_saving, opus_val16 tf_estimate,
+ int intensity, opus_val16 surround_trim)
+{
+ int i;
+ opus_val32 diff=0;
+ int c;
+ int trim_index = 5;
+ opus_val16 trim = QCONST16(5.f, 8);
+ opus_val16 logXC, logXC2;
+ if (C==2)
+ {
+ opus_val16 sum = 0; /* Q10 */
+ opus_val16 minXC; /* Q10 */
+ /* Compute inter-channel correlation for low frequencies */
+ for (i=0;i<8;i++)
+ {
+ int j;
+ opus_val32 partial = 0;
+ for (j=m->eBands[i]<<LM;j<m->eBands[i+1]<<LM;j++)
+ partial = MAC16_16(partial, X[j], X[N0+j]);
+ sum = ADD16(sum, EXTRACT16(SHR32(partial, 18)));
+ }
+ sum = MULT16_16_Q15(QCONST16(1.f/8, 15), sum);
+ sum = MIN16(QCONST16(1.f, 10), ABS16(sum));
+ minXC = sum;
+ for (i=8;i<intensity;i++)
+ {
+ int j;
+ opus_val32 partial = 0;
+ for (j=m->eBands[i]<<LM;j<m->eBands[i+1]<<LM;j++)
+ partial = MAC16_16(partial, X[j], X[N0+j]);
+ minXC = MIN16(minXC, ABS16(EXTRACT16(SHR32(partial, 18))));
+ }
+ minXC = MIN16(QCONST16(1.f, 10), ABS16(minXC));
+ /*printf ("%f\n", sum);*/
+ if (sum > QCONST16(.995f,10))
+ trim_index-=4;
+ else if (sum > QCONST16(.92f,10))
+ trim_index-=3;
+ else if (sum > QCONST16(.85f,10))
+ trim_index-=2;
+ else if (sum > QCONST16(.8f,10))
+ trim_index-=1;
+ /* mid-side savings estimations based on the LF average*/
+ logXC = celt_log2(QCONST32(1.001f, 20)-MULT16_16(sum, sum));
+ /* mid-side savings estimations based on min correlation */
+ logXC2 = MAX16(HALF16(logXC), celt_log2(QCONST32(1.001f, 20)-MULT16_16(minXC, minXC)));
+#ifdef OPUS_FIXED_POINT
+ /* Compensate for Q20 vs Q14 input and convert output to Q8 */
+ logXC = PSHR32(logXC-QCONST16(6.f, DB_SHIFT),DB_SHIFT-8);
+ logXC2 = PSHR32(logXC2-QCONST16(6.f, DB_SHIFT),DB_SHIFT-8);
+#endif
+
+ trim += MAX16(-QCONST16(4.f, 8), MULT16_16_Q15(QCONST16(.75f,15),logXC));
+ *stereo_saving = MIN16(*stereo_saving + QCONST16(0.25f, 8), -HALF16(logXC2));
+ }
+
+ /* Estimate spectral tilt */
+ c=0; do {
+ for (i=0;i<end-1;i++)
+ {
+ diff += bandLogE[i+c*m->nbEBands]*(opus_int32)(2+2*i-end);
+ }
+ } while (++c<C);
+ diff /= C*(end-1);
+ /*printf("%f\n", diff);*/
+ if (diff > QCONST16(2.f, DB_SHIFT))
+ trim_index--;
+ if (diff > QCONST16(8.f, DB_SHIFT))
+ trim_index--;
+ if (diff < -QCONST16(4.f, DB_SHIFT))
+ trim_index++;
+ if (diff < -QCONST16(10.f, DB_SHIFT))
+ trim_index++;
+ trim -= MAX16(-QCONST16(2.f, 8), MIN16(QCONST16(2.f, 8), SHR16(diff+QCONST16(1.f, DB_SHIFT),DB_SHIFT-8)/6 ));
+ trim -= SHR16(surround_trim, DB_SHIFT-8);
+ trim -= 2*SHR16(tf_estimate, 14-8);
+#ifndef DISABLE_FLOAT_API
+ if (analysis->valid)
+ {
+ trim -= MAX16(-QCONST16(2.f, 8), MIN16(QCONST16(2.f, 8),
+ (opus_val16)(QCONST16(2.f, 8)*(analysis->tonality_slope+.05f))));
+ }
+#endif
+
+#ifdef OPUS_FIXED_POINT
+ trim_index = PSHR32(trim, 8);
+#else
+ trim_index = (int)floor(.5f+trim);
+#endif
+ if (trim_index<0)
+ trim_index = 0;
+ if (trim_index>10)
+ trim_index = 10;
+ /*printf("%d\n", trim_index);*/
+#ifdef FUZZING
+ trim_index = rand()%11;
+#endif
+ return trim_index;
+}
+
+static int stereo_analysis(const CELTMode *m, const celt_norm *X,
+ int LM, int N0)
+{
+ int i;
+ int thetas;
+ opus_val32 sumLR = EPSILON, sumMS = EPSILON;
+
+ /* Use the L1 norm to model the entropy of the L/R signal vs the M/S signal */
+ for (i=0;i<13;i++)
+ {
+ int j;
+ for (j=m->eBands[i]<<LM;j<m->eBands[i+1]<<LM;j++)
+ {
+ opus_val32 L, R, M, S;
+ /* We cast to 32-bit first because of the -32768 case */
+ L = EXTEND32(X[j]);
+ R = EXTEND32(X[N0+j]);
+ M = ADD32(L, R);
+ S = SUB32(L, R);
+ sumLR = ADD32(sumLR, ADD32(ABS32(L), ABS32(R)));
+ sumMS = ADD32(sumMS, ADD32(ABS32(M), ABS32(S)));
+ }
+ }
+ sumMS = MULT16_32_Q15(QCONST16(0.707107f, 15), sumMS);
+ thetas = 13;
+ /* We don't need thetas for lower bands with LM<=1 */
+ if (LM<=1)
+ thetas -= 8;
+ return MULT16_32_Q15((m->eBands[13]<<(LM+1))+thetas, sumMS)
+ > MULT16_32_Q15(m->eBands[13]<<(LM+1), sumLR);
+}
+
+static opus_val16 dynalloc_analysis(const opus_val16 *bandLogE, const opus_val16 *bandLogE2,
+ int nbEBands, int start, int end, int C, int *offsets, int lsb_depth, const opus_int16 *logN,
+ int isTransient, int vbr, int constrained_vbr, const opus_int16 *eBands, int LM,
+ int effectiveBytes, opus_int32 *tot_boost_, int lfe, opus_val16 *surround_dynalloc)
+{
+ int i, c;
+ opus_int32 tot_boost=0;
+ opus_val16 maxDepth;
+ VARDECL(opus_val16, follower);
+ VARDECL(opus_val16, noise_floor);
+ SAVE_STACK;
+ ALLOC(follower, C*nbEBands, opus_val16);
+ ALLOC(noise_floor, C*nbEBands, opus_val16);
+ for (i=0;i<nbEBands;i++)
+ offsets[i] = 0;
+ /* Dynamic allocation code */
+ maxDepth=-QCONST16(31.9f, DB_SHIFT);
+ for (i=0;i<end;i++)
+ {
+ /* Noise floor must take into account eMeans, the depth, the width of the bands
+ and the preemphasis filter (approx. square of bark band ID) */
+ noise_floor[i] = MULT16_16(QCONST16(0.0625f, DB_SHIFT),logN[i])
+ +QCONST16(.5f,DB_SHIFT)+SHL16(9-lsb_depth,DB_SHIFT)-SHL16(eMeans[i],6)
+ +MULT16_16(QCONST16(.0062,DB_SHIFT),(i+5)*(i+5));
+ }
+ c=0;do
+ {
+ for (i=0;i<end;i++)
+ maxDepth = MAX16(maxDepth, bandLogE[c*nbEBands+i]-noise_floor[i]);
+ } while (++c<C);
+ /* Make sure that dynamic allocation can't make us bust the budget */
+ if (effectiveBytes > 50 && LM>=1 && !lfe)
+ {
+ int last=0;
+ c=0;do
+ {
+ follower[c*nbEBands] = bandLogE2[c*nbEBands];
+ for (i=1;i<end;i++)
+ {
+ /* The last band to be at least 3 dB higher than the previous one
+ is the last we'll consider. Otherwise, we run into problems on
+ bandlimited signals. */
+ if (bandLogE2[c*nbEBands+i] > bandLogE2[c*nbEBands+i-1]+QCONST16(.5f,DB_SHIFT))
+ last=i;
+ follower[c*nbEBands+i] = MIN16(follower[c*nbEBands+i-1]+QCONST16(1.5f,DB_SHIFT), bandLogE2[c*nbEBands+i]);
+ }
+ for (i=last-1;i>=0;i--)
+ follower[c*nbEBands+i] = MIN16(follower[c*nbEBands+i], MIN16(follower[c*nbEBands+i+1]+QCONST16(2.f,DB_SHIFT), bandLogE2[c*nbEBands+i]));
+ for (i=0;i<end;i++)
+ follower[c*nbEBands+i] = MAX16(follower[c*nbEBands+i], noise_floor[i]);
+ } while (++c<C);
+ if (C==2)
+ {
+ for (i=start;i<end;i++)
+ {
+ /* Consider 24 dB "cross-talk" */
+ follower[nbEBands+i] = MAX16(follower[nbEBands+i], follower[ i]-QCONST16(4.f,DB_SHIFT));
+ follower[ i] = MAX16(follower[ i], follower[nbEBands+i]-QCONST16(4.f,DB_SHIFT));
+ follower[i] = HALF16(MAX16(0, bandLogE[i]-follower[i]) + MAX16(0, bandLogE[nbEBands+i]-follower[nbEBands+i]));
+ }
+ } else {
+ for (i=start;i<end;i++)
+ {
+ follower[i] = MAX16(0, bandLogE[i]-follower[i]);
+ }
+ }
+ for (i=start;i<end;i++)
+ follower[i] = MAX16(follower[i], surround_dynalloc[i]);
+ /* For non-transient CBR/CVBR frames, halve the dynalloc contribution */
+ if ((!vbr || constrained_vbr)&&!isTransient)
+ {
+ for (i=start;i<end;i++)
+ follower[i] = HALF16(follower[i]);
+ }
+ for (i=start;i<end;i++)
+ {
+ int width;
+ int boost;
+ int boost_bits;
+
+ if (i<8)
+ follower[i] *= 2;
+ if (i>=12)
+ follower[i] = HALF16(follower[i]);
+ follower[i] = MIN16(follower[i], QCONST16(4, DB_SHIFT));
+
+ width = C*(eBands[i+1]-eBands[i])<<LM;
+ if (width<6)
+ {
+ boost = (int)SHR32(EXTEND32(follower[i]),DB_SHIFT);
+ boost_bits = boost*width<<BITRES;
+ } else if (width > 48) {
+ boost = (int)SHR32(EXTEND32(follower[i])*8,DB_SHIFT);
+ boost_bits = (boost*width<<BITRES)/8;
+ } else {
+ boost = (int)SHR32(EXTEND32(follower[i])*width/6,DB_SHIFT);
+ boost_bits = boost*6<<BITRES;
+ }
+ /* For CBR and non-transient CVBR frames, limit dynalloc to 1/4 of the bits */
+ if ((!vbr || (constrained_vbr&&!isTransient))
+ && (tot_boost+boost_bits)>>BITRES>>3 > effectiveBytes/4)
+ {
+ opus_int32 cap = ((effectiveBytes/4)<<BITRES<<3);
+ offsets[i] = cap-tot_boost;
+ tot_boost = cap;
+ break;
+ } else {
+ offsets[i] = boost;
+ tot_boost += boost_bits;
+ }
+ }
+ }
+ *tot_boost_ = tot_boost;
+ RESTORE_STACK;
+ return maxDepth;
+}
+
+
+static int run_prefilter(CELTEncoder *st, celt_sig *in, celt_sig *prefilter_mem, int CC, int N,
+ int prefilter_tapset, int *pitch, opus_val16 *gain, int *qgain, int enabled, int nbAvailableBytes)
+{
+ int c;
+ VARDECL(celt_sig, _pre);
+ celt_sig *pre[2];
+ const CELTMode *mode;
+ int pitch_index;
+ opus_val16 gain1;
+ opus_val16 pf_threshold;
+ int pf_on;
+ int qg;
+ SAVE_STACK;
+
+ mode = st->mode;
+ ALLOC(_pre, CC*(N+COMBFILTER_MAXPERIOD), celt_sig);
+
+ pre[0] = _pre;
+ pre[1] = _pre + (N+COMBFILTER_MAXPERIOD);
+
+
+ c=0; do {
+ OPUS_COPY(pre[c], prefilter_mem+c*COMBFILTER_MAXPERIOD, COMBFILTER_MAXPERIOD);
+ OPUS_COPY(pre[c]+COMBFILTER_MAXPERIOD, in+c*(N+st->overlap)+st->overlap, N);
+ } while (++c<CC);
+
+ if (enabled)
+ {
+ VARDECL(opus_val16, pitch_buf);
+ ALLOC(pitch_buf, (COMBFILTER_MAXPERIOD+N)>>1, opus_val16);
+
+ pitch_downsample(pre, pitch_buf, COMBFILTER_MAXPERIOD+N, CC, st->arch);
+ /* Don't search for the fir last 1.5 octave of the range because
+ there's too many false-positives due to short-term correlation */
+ pitch_search(pitch_buf+(COMBFILTER_MAXPERIOD>>1), pitch_buf, N,
+ COMBFILTER_MAXPERIOD-3*COMBFILTER_MINPERIOD, &pitch_index,
+ st->arch);
+ pitch_index = COMBFILTER_MAXPERIOD-pitch_index;
+
+ gain1 = remove_doubling(pitch_buf, COMBFILTER_MAXPERIOD, COMBFILTER_MINPERIOD,
+ N, &pitch_index, st->prefilter_period, st->prefilter_gain);
+ if (pitch_index > COMBFILTER_MAXPERIOD-2)
+ pitch_index = COMBFILTER_MAXPERIOD-2;
+ gain1 = MULT16_16_Q15(QCONST16(.7f,15),gain1);
+ /*printf("%d %d %f %f\n", pitch_change, pitch_index, gain1, st->analysis.tonality);*/
+ if (st->loss_rate>2)
+ gain1 = HALF32(gain1);
+ if (st->loss_rate>4)
+ gain1 = HALF32(gain1);
+ if (st->loss_rate>8)
+ gain1 = 0;
+ } else {
+ gain1 = 0;
+ pitch_index = COMBFILTER_MINPERIOD;
+ }
+
+ /* Gain threshold for enabling the prefilter/postfilter */
+ pf_threshold = QCONST16(.2f,15);
+
+ /* Adjusting the threshold based on rate and continuity */
+ if (abs(pitch_index-st->prefilter_period)*10>pitch_index)
+ pf_threshold += QCONST16(.2f,15);
+ if (nbAvailableBytes<25)
+ pf_threshold += QCONST16(.1f,15);
+ if (nbAvailableBytes<35)
+ pf_threshold += QCONST16(.1f,15);
+ if (st->prefilter_gain > QCONST16(.4f,15))
+ pf_threshold -= QCONST16(.1f,15);
+ if (st->prefilter_gain > QCONST16(.55f,15))
+ pf_threshold -= QCONST16(.1f,15);
+
+ /* Hard threshold at 0.2 */
+ pf_threshold = MAX16(pf_threshold, QCONST16(.2f,15));
+ if (gain1<pf_threshold)
+ {
+ gain1 = 0;
+ pf_on = 0;
+ qg = 0;
+ } else {
+ /*This block is not gated by a total bits check only because
+ of the nbAvailableBytes check above.*/
+ if (ABS16(gain1-st->prefilter_gain)<QCONST16(.1f,15))
+ gain1=st->prefilter_gain;
+
+#ifdef OPUS_FIXED_POINT
+ qg = ((gain1+1536)>>10)/3-1;
+#else
+ qg = (int)floor(.5f+gain1*32/3)-1;
+#endif
+ qg = IMAX(0, IMIN(7, qg));
+ gain1 = QCONST16(0.09375f,15)*(qg+1);
+ pf_on = 1;
+ }
+ /*printf("%d %f\n", pitch_index, gain1);*/
+
+ c=0; do {
+ int offset = mode->shortMdctSize-st->overlap;
+ st->prefilter_period=IMAX(st->prefilter_period, COMBFILTER_MINPERIOD);
+ OPUS_COPY(in+c*(N+st->overlap), st->in_mem+c*(st->overlap), st->overlap);
+ if (offset)
+ comb_filter(in+c*(N+st->overlap)+st->overlap, pre[c]+COMBFILTER_MAXPERIOD,
+ st->prefilter_period, st->prefilter_period, offset, -st->prefilter_gain, -st->prefilter_gain,
+ st->prefilter_tapset, st->prefilter_tapset, NULL, 0);
+
+ comb_filter(in+c*(N+st->overlap)+st->overlap+offset, pre[c]+COMBFILTER_MAXPERIOD+offset,
+ st->prefilter_period, pitch_index, N-offset, -st->prefilter_gain, -gain1,
+ st->prefilter_tapset, prefilter_tapset, mode->window, st->overlap);
+ OPUS_COPY(st->in_mem+c*(st->overlap), in+c*(N+st->overlap)+N, st->overlap);
+
+ if (N>COMBFILTER_MAXPERIOD)
+ {
+ OPUS_MOVE(prefilter_mem+c*COMBFILTER_MAXPERIOD, pre[c]+N, COMBFILTER_MAXPERIOD);
+ } else {
+ OPUS_MOVE(prefilter_mem+c*COMBFILTER_MAXPERIOD, prefilter_mem+c*COMBFILTER_MAXPERIOD+N, COMBFILTER_MAXPERIOD-N);
+ OPUS_MOVE(prefilter_mem+c*COMBFILTER_MAXPERIOD+COMBFILTER_MAXPERIOD-N, pre[c]+COMBFILTER_MAXPERIOD, N);
+ }
+ } while (++c<CC);
+
+ RESTORE_STACK;
+ *gain = gain1;
+ *pitch = pitch_index;
+ *qgain = qg;
+ return pf_on;
+}
+
+static int compute_vbr(const CELTMode *mode, AnalysisInfo *analysis, opus_int32 base_target,
+ int LM, opus_int32 bitrate, int lastCodedBands, int C, int intensity,
+ int constrained_vbr, opus_val16 stereo_saving, int tot_boost,
+ opus_val16 tf_estimate, int pitch_change, opus_val16 maxDepth,
+ int variable_duration, int lfe, int has_surround_mask, opus_val16 surround_masking,
+ opus_val16 temporal_vbr)
+{
+ /* The target rate in 8th bits per frame */
+ opus_int32 target;
+ int coded_bins;
+ int coded_bands;
+ opus_val16 tf_calibration;
+ int nbEBands;
+ const opus_int16 *eBands;
+
+ nbEBands = mode->nbEBands;
+ eBands = mode->eBands;
+
+ coded_bands = lastCodedBands ? lastCodedBands : nbEBands;
+ coded_bins = eBands[coded_bands]<<LM;
+ if (C==2)
+ coded_bins += eBands[IMIN(intensity, coded_bands)]<<LM;
+
+ target = base_target;
+
+ /*printf("%f %f %f %f %d %d ", st->analysis.activity, st->analysis.tonality, tf_estimate, st->stereo_saving, tot_boost, coded_bands);*/
+#ifndef DISABLE_FLOAT_API
+ if (analysis->valid && analysis->activity<.4)
+ target -= (opus_int32)((coded_bins<<BITRES)*(.4f-analysis->activity));
+#endif
+ /* Stereo savings */
+ if (C==2)
+ {
+ int coded_stereo_bands;
+ int coded_stereo_dof;
+ opus_val16 max_frac;
+ coded_stereo_bands = IMIN(intensity, coded_bands);
+ coded_stereo_dof = (eBands[coded_stereo_bands]<<LM)-coded_stereo_bands;
+ /* Maximum fraction of the bits we can save if the signal is mono. */
+ max_frac = DIV32_16(MULT16_16(QCONST16(0.8f, 15), coded_stereo_dof), coded_bins);
+ stereo_saving = MIN16(stereo_saving, QCONST16(1.f, 8));
+ /*printf("%d %d %d ", coded_stereo_dof, coded_bins, tot_boost);*/
+ target -= (opus_int32)MIN32(MULT16_32_Q15(max_frac,target),
+ SHR32(MULT16_16(stereo_saving-QCONST16(0.1f,8),(coded_stereo_dof<<BITRES)),8));
+ }
+ /* Boost the rate according to dynalloc (minus the dynalloc average for calibration). */
+ target += tot_boost-(16<<LM);
+ /* Apply transient boost, compensating for average boost. */
+ tf_calibration = variable_duration==OPUS_FRAMESIZE_VARIABLE ?
+ QCONST16(0.02f,14) : QCONST16(0.04f,14);
+ target += (opus_int32)SHL32(MULT16_32_Q15(tf_estimate-tf_calibration, target),1);
+
+#ifndef DISABLE_FLOAT_API
+ /* Apply tonality boost */
+ if (analysis->valid && !lfe)
+ {
+ opus_int32 tonal_target;
+ float tonal;
+
+ /* Tonality boost (compensating for the average). */
+ tonal = MAX16(0.f,analysis->tonality-.15f)-0.09f;
+ tonal_target = target + (opus_int32)((coded_bins<<BITRES)*1.2f*tonal);
+ if (pitch_change)
+ tonal_target += (opus_int32)((coded_bins<<BITRES)*.8f);
+ /*printf("%f %f ", analysis->tonality, tonal);*/
+ target = tonal_target;
+ }
+#endif
+
+ if (has_surround_mask&&!lfe)
+ {
+ opus_int32 surround_target = target + (opus_int32)SHR32(MULT16_16(surround_masking,coded_bins<<BITRES), DB_SHIFT);
+ /*printf("%f %d %d %d %d %d %d ", surround_masking, coded_bins, st->end, st->intensity, surround_target, target, st->bitrate);*/
+ target = IMAX(target/4, surround_target);
+ }
+
+ {
+ opus_int32 floor_depth;
+ int bins;
+ bins = eBands[nbEBands-2]<<LM;
+ /*floor_depth = SHR32(MULT16_16((C*bins<<BITRES),celt_log2(SHL32(MAX16(1,sample_max),13))), DB_SHIFT);*/
+ floor_depth = (opus_int32)SHR32(MULT16_16((C*bins<<BITRES),maxDepth), DB_SHIFT);
+ floor_depth = IMAX(floor_depth, target>>2);
+ target = IMIN(target, floor_depth);
+ /*printf("%f %d\n", maxDepth, floor_depth);*/
+ }
+
+ if ((!has_surround_mask||lfe) && (constrained_vbr || bitrate<64000))
+ {
+ opus_val16 rate_factor;
+#ifdef OPUS_FIXED_POINT
+ rate_factor = MAX16(0,(bitrate-32000));
+#else
+ rate_factor = MAX16(0,(1.f/32768)*(bitrate-32000));
+#endif
+ if (constrained_vbr)
+ rate_factor = MIN16(rate_factor, QCONST16(0.67f, 15));
+ target = base_target + (opus_int32)MULT16_32_Q15(rate_factor, target-base_target);
+
+ }
+
+ if (!has_surround_mask && tf_estimate < QCONST16(.2f, 14))
+ {
+ opus_val16 amount;
+ opus_val16 tvbr_factor;
+ amount = MULT16_16_Q15(QCONST16(.0000031f, 30), IMAX(0, IMIN(32000, 96000-bitrate)));
+ tvbr_factor = SHR32(MULT16_16(temporal_vbr, amount), DB_SHIFT);
+ target += (opus_int32)MULT16_32_Q15(tvbr_factor, target);
+ }
+
+ /* Don't allow more than doubling the rate */
+ target = IMIN(2*base_target, target);
+
+ return target;
+}
+
+int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc)
+{
+ int i, c, N;
+ opus_int32 bits;
+ ec_enc _enc;
+ VARDECL(celt_sig, in);
+ VARDECL(celt_sig, freq);
+ VARDECL(celt_norm, X);
+ VARDECL(celt_ener, bandE);
+ VARDECL(opus_val16, bandLogE);
+ VARDECL(opus_val16, bandLogE2);
+ VARDECL(int, fine_quant);
+ VARDECL(opus_val16, error);
+ VARDECL(int, pulses);
+ VARDECL(int, cap);
+ VARDECL(int, offsets);
+ VARDECL(int, fine_priority);
+ VARDECL(int, tf_res);
+ VARDECL(unsigned char, collapse_masks);
+ celt_sig *prefilter_mem;
+ opus_val16 *oldBandE, *oldLogE, *oldLogE2;
+ int shortBlocks=0;
+ int isTransient=0;
+ const int CC = st->channels;
+ const int C = st->stream_channels;
+ int LM, M;
+ int tf_select;
+ int nbFilledBytes, nbAvailableBytes;
+ int effEnd;
+ int codedBands;
+ int tf_sum;
+ int alloc_trim;
+ int pitch_index=COMBFILTER_MINPERIOD;
+ opus_val16 gain1 = 0;
+ int dual_stereo=0;
+ int effectiveBytes;
+ int dynalloc_logp;
+ opus_int32 vbr_rate;
+ opus_int32 total_bits;
+ opus_int32 total_boost;
+ opus_int32 balance;
+ opus_int32 tell;
+ int prefilter_tapset=0;
+ int pf_on;
+ int anti_collapse_rsv;
+ int anti_collapse_on=0;
+ int silence=0;
+ int tf_chan = 0;
+ opus_val16 tf_estimate;
+ int pitch_change=0;
+ opus_int32 tot_boost;
+ opus_val32 sample_max;
+ opus_val16 maxDepth;
+ const OpusCustomMode *mode;
+ int nbEBands;
+ int overlap;
+ const opus_int16 *eBands;
+ int secondMdct;
+ int signalBandwidth;
+ int transient_got_disabled=0;
+ opus_val16 surround_masking=0;
+ opus_val16 temporal_vbr=0;
+ opus_val16 surround_trim = 0;
+ opus_int32 equiv_rate = 510000;
+ VARDECL(opus_val16, surround_dynalloc);
+ ALLOC_STACK;
+
+ mode = st->mode;
+ nbEBands = mode->nbEBands;
+ overlap = mode->overlap;
+ eBands = mode->eBands;
+ tf_estimate = 0;
+ if (nbCompressedBytes<2 || pcm==NULL)
+ {
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ }
+
+ frame_size *= st->upsample;
+ for (LM=0;LM<=mode->maxLM;LM++)
+ if (mode->shortMdctSize<<LM==frame_size)
+ break;
+ if (LM>mode->maxLM)
+ {
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ }
+ M=1<<LM;
+ N = M*mode->shortMdctSize;
+
+ prefilter_mem = st->in_mem+CC*(st->overlap);
+ oldBandE = (opus_val16*)(st->in_mem+CC*(st->overlap+COMBFILTER_MAXPERIOD));
+ oldLogE = oldBandE + CC*nbEBands;
+ oldLogE2 = oldLogE + CC*nbEBands;
+
+ if (enc==NULL)
+ {
+ tell=1;
+ nbFilledBytes=0;
+ } else {
+ tell=ec_tell(enc);
+ nbFilledBytes=(tell+4)>>3;
+ }
+
+#ifdef CUSTOM_MODES
+ if (st->signalling && enc==NULL)
+ {
+ int tmp = (mode->effEBands-st->end)>>1;
+ st->end = IMAX(1, mode->effEBands-tmp);
+ compressed[0] = tmp<<5;
+ compressed[0] |= LM<<3;
+ compressed[0] |= (C==2)<<2;
+ /* Convert "standard mode" to Opus header */
+ if (mode->Fs==48000 && mode->shortMdctSize==120)
+ {
+ int c0 = toOpus(compressed[0]);
+ if (c0<0)
+ {
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ }
+ compressed[0] = c0;
+ }
+ compressed++;
+ nbCompressedBytes--;
+ }
+#else
+ celt_assert(st->signalling==0);
+#endif
+
+ /* Can't produce more than 1275 output bytes */
+ nbCompressedBytes = IMIN(nbCompressedBytes,1275);
+ nbAvailableBytes = nbCompressedBytes - nbFilledBytes;
+
+ if (st->vbr && st->bitrate!=OPUS_BITRATE_MAX)
+ {
+ opus_int32 den=mode->Fs>>BITRES;
+ vbr_rate=(st->bitrate*frame_size+(den>>1))/den;
+#ifdef CUSTOM_MODES
+ if (st->signalling)
+ vbr_rate -= 8<<BITRES;
+#endif
+ effectiveBytes = vbr_rate>>(3+BITRES);
+ } else {
+ opus_int32 tmp;
+ vbr_rate = 0;
+ tmp = st->bitrate*frame_size;
+ if (tell>1)
+ tmp += tell;
+ if (st->bitrate!=OPUS_BITRATE_MAX)
+ nbCompressedBytes = IMAX(2, IMIN(nbCompressedBytes,
+ (tmp+4*mode->Fs)/(8*mode->Fs)-!!st->signalling));
+ effectiveBytes = nbCompressedBytes;
+ }
+ if (st->bitrate != OPUS_BITRATE_MAX)
+ equiv_rate = st->bitrate - (40*C+20)*((400>>LM) - 50);
+
+ if (enc==NULL)
+ {
+ ec_enc_init(&_enc, compressed, nbCompressedBytes);
+ enc = &_enc;
+ }
+
+ if (vbr_rate>0)
+ {
+ /* Computes the max bit-rate allowed in VBR mode to avoid violating the
+ target rate and buffering.
+ We must do this up front so that bust-prevention logic triggers
+ correctly if we don't have enough bits. */
+ if (st->constrained_vbr)
+ {
+ opus_int32 vbr_bound;
+ opus_int32 max_allowed;
+ /* We could use any multiple of vbr_rate as bound (depending on the
+ delay).
+ This is clamped to ensure we use at least two bytes if the encoder
+ was entirely empty, but to allow 0 in hybrid mode. */
+ vbr_bound = vbr_rate;
+ max_allowed = IMIN(IMAX(tell==1?2:0,
+ (vbr_rate+vbr_bound-st->vbr_reservoir)>>(BITRES+3)),
+ nbAvailableBytes);
+ if(max_allowed < nbAvailableBytes)
+ {
+ nbCompressedBytes = nbFilledBytes+max_allowed;
+ nbAvailableBytes = max_allowed;
+ ec_enc_shrink(enc, nbCompressedBytes);
+ }
+ }
+ }
+ total_bits = nbCompressedBytes*8;
+
+ effEnd = st->end;
+ if (effEnd > mode->effEBands)
+ effEnd = mode->effEBands;
+
+ ALLOC(in, CC*(N+st->overlap), celt_sig);
+
+ sample_max=MAX32(st->overlap_max, celt_maxabs16(pcm, C*(N-overlap)/st->upsample));
+ st->overlap_max=celt_maxabs16(pcm+C*(N-overlap)/st->upsample, C*overlap/st->upsample);
+ sample_max=MAX32(sample_max, st->overlap_max);
+#ifdef OPUS_FIXED_POINT
+ silence = (sample_max==0);
+#else
+ silence = (sample_max <= (opus_val16)1/(1<<st->lsb_depth));
+#endif
+#ifdef FUZZING
+ if ((rand()&0x3F)==0)
+ silence = 1;
+#endif
+ if (tell==1)
+ ec_enc_bit_logp(enc, silence, 15);
+ else
+ silence=0;
+ if (silence)
+ {
+ /*In VBR mode there is no need to send more than the minimum. */
+ if (vbr_rate>0)
+ {
+ effectiveBytes=nbCompressedBytes=IMIN(nbCompressedBytes, nbFilledBytes+2);
+ total_bits=nbCompressedBytes*8;
+ nbAvailableBytes=2;
+ ec_enc_shrink(enc, nbCompressedBytes);
+ }
+ /* Pretend we've filled all the remaining bits with zeros
+ (that's what the initialiser did anyway) */
+ tell = nbCompressedBytes*8;
+ enc->nbits_total+=tell-ec_tell(enc);
+ }
+ c=0; do {
+ celt_preemphasis(pcm+c, in+c*(N+st->overlap)+st->overlap, N, CC, st->upsample,
+ mode->preemph, st->preemph_memE+c, st->clip);
+ } while (++c<CC);
+
+
+
+ /* Find pitch period and gain */
+ {
+ int enabled;
+ int qg;
+ enabled = ((st->lfe&&nbAvailableBytes>3) || nbAvailableBytes>12*C) && st->start==0 && !silence && !st->disable_pf
+ && st->complexity >= 5 && !(st->consec_transient && LM!=3 && st->variable_duration==OPUS_FRAMESIZE_VARIABLE);
+
+ prefilter_tapset = st->tapset_decision;
+ pf_on = run_prefilter(st, in, prefilter_mem, CC, N, prefilter_tapset, &pitch_index, &gain1, &qg, enabled, nbAvailableBytes);
+ if ((gain1 > QCONST16(.4f,15) || st->prefilter_gain > QCONST16(.4f,15)) && (!st->analysis.valid || st->analysis.tonality > .3)
+ && (pitch_index > 1.26*st->prefilter_period || pitch_index < .79*st->prefilter_period))
+ pitch_change = 1;
+ if (pf_on==0)
+ {
+ if(st->start==0 && tell+16<=total_bits)
+ ec_enc_bit_logp(enc, 0, 1);
+ } else {
+ /*This block is not gated by a total bits check only because
+ of the nbAvailableBytes check above.*/
+ int octave;
+ ec_enc_bit_logp(enc, 1, 1);
+ pitch_index += 1;
+ octave = EC_ILOG(pitch_index)-5;
+ ec_enc_uint(enc, octave, 6);
+ ec_enc_bits(enc, pitch_index-(16<<octave), 4+octave);
+ pitch_index -= 1;
+ ec_enc_bits(enc, qg, 3);
+ ec_enc_icdf(enc, prefilter_tapset, tapset_icdf, 2);
+ }
+ }
+
+ isTransient = 0;
+ shortBlocks = 0;
+ if (st->complexity >= 1 && !st->lfe)
+ {
+ isTransient = transient_analysis(in, N+st->overlap, CC,
+ &tf_estimate, &tf_chan);
+ }
+ if (LM>0 && ec_tell(enc)+3<=total_bits)
+ {
+ if (isTransient)
+ shortBlocks = M;
+ } else {
+ isTransient = 0;
+ transient_got_disabled=1;
+ }
+
+ ALLOC(freq, CC*N, celt_sig); /**< Interleaved signal MDCTs */
+ ALLOC(bandE,nbEBands*CC, celt_ener);
+ ALLOC(bandLogE,nbEBands*CC, opus_val16);
+
+ secondMdct = shortBlocks && st->complexity>=8;
+ ALLOC(bandLogE2, C*nbEBands, opus_val16);
+ if (secondMdct)
+ {
+ compute_mdcts(mode, 0, in, freq, C, CC, LM, st->upsample);
+ compute_band_energies(mode, freq, bandE, effEnd, C, M);
+ amp2Log2(mode, effEnd, st->end, bandE, bandLogE2, C);
+ for (i=0;i<C*nbEBands;i++)
+ bandLogE2[i] += HALF16(SHL16(LM, DB_SHIFT));
+ }
+
+ compute_mdcts(mode, shortBlocks, in, freq, C, CC, LM, st->upsample);
+ if (CC==2&&C==1)
+ tf_chan = 0;
+ compute_band_energies(mode, freq, bandE, effEnd, C, M);
+
+ if (st->lfe)
+ {
+ for (i=2;i<st->end;i++)
+ {
+ bandE[i] = IMIN(bandE[i], MULT16_32_Q15(QCONST16(1e-4f,15),bandE[0]));
+ bandE[i] = MAX32(bandE[i], EPSILON);
+ }
+ }
+ amp2Log2(mode, effEnd, st->end, bandE, bandLogE, C);
+
+ ALLOC(surround_dynalloc, C*nbEBands, opus_val16);
+ for(i=0;i<st->end;i++)
+ surround_dynalloc[i] = 0;
+ /* This computes how much masking takes place between surround channels */
+ if (st->start==0&&st->energy_mask&&!st->lfe)
+ {
+ int mask_end;
+ int midband;
+ int count_dynalloc;
+ opus_val32 mask_avg=0;
+ opus_val32 diff=0;
+ int count=0;
+ mask_end = IMAX(2,st->lastCodedBands);
+ for (c=0;c<C;c++)
+ {
+ for(i=0;i<mask_end;i++)
+ {
+ opus_val16 mask;
+ mask = MAX16(MIN16(st->energy_mask[nbEBands*c+i],
+ QCONST16(.25f, DB_SHIFT)), -QCONST16(2.0f, DB_SHIFT));
+ if (mask > 0)
+ mask = HALF16(mask);
+ mask_avg += MULT16_16(mask, eBands[i+1]-eBands[i]);
+ count += eBands[i+1]-eBands[i];
+ diff += MULT16_16(mask, 1+2*i-mask_end);
+ }
+ }
+ mask_avg = DIV32_16(mask_avg,count);
+ mask_avg += QCONST16(.2f, DB_SHIFT);
+ diff = diff*6/(C*(mask_end-1)*(mask_end+1)*mask_end);
+ /* Again, being conservative */
+ diff = HALF32(diff);
+ diff = MAX32(MIN32(diff, QCONST32(.031f, DB_SHIFT)), -QCONST32(.031f, DB_SHIFT));
+ /* Find the band that's in the middle of the coded spectrum */
+ for (midband=0;eBands[midband+1] < eBands[mask_end]/2;midband++);
+ count_dynalloc=0;
+ for(i=0;i<mask_end;i++)
+ {
+ opus_val32 lin;
+ opus_val16 unmask;
+ lin = mask_avg + diff*(i-midband);
+ if (C==2)
+ unmask = MAX16(st->energy_mask[i], st->energy_mask[nbEBands+i]);
+ else
+ unmask = st->energy_mask[i];
+ unmask = MIN16(unmask, QCONST16(.0f, DB_SHIFT));
+ unmask -= lin;
+ if (unmask > QCONST16(.25f, DB_SHIFT))
+ {
+ surround_dynalloc[i] = unmask - QCONST16(.25f, DB_SHIFT);
+ count_dynalloc++;
+ }
+ }
+ if (count_dynalloc>=3)
+ {
+ /* If we need dynalloc in many bands, it's probably because our
+ initial masking rate was too low. */
+ mask_avg += QCONST16(.25f, DB_SHIFT);
+ if (mask_avg>0)
+ {
+ /* Something went really wrong in the original calculations,
+ disabling masking. */
+ mask_avg = 0;
+ diff = 0;
+ for(i=0;i<mask_end;i++)
+ surround_dynalloc[i] = 0;
+ } else {
+ for(i=0;i<mask_end;i++)
+ surround_dynalloc[i] = MAX16(0, surround_dynalloc[i]-QCONST16(.25f, DB_SHIFT));
+ }
+ }
+ mask_avg += QCONST16(.2f, DB_SHIFT);
+ /* Convert to 1/64th units used for the trim */
+ surround_trim = 64*diff;
+ /*printf("%d %d ", mask_avg, surround_trim);*/
+ surround_masking = mask_avg;
+ }
+ /* Temporal VBR (but not for LFE) */
+ if (!st->lfe)
+ {
+ opus_val16 follow=-QCONST16(10.0f,DB_SHIFT);
+ opus_val32 frame_avg=0;
+ opus_val16 offset = shortBlocks?HALF16(SHL16(LM, DB_SHIFT)):0;
+ for(i=st->start;i<st->end;i++)
+ {
+ follow = MAX16(follow-QCONST16(1.f, DB_SHIFT), bandLogE[i]-offset);
+ if (C==2)
+ follow = MAX16(follow, bandLogE[i+nbEBands]-offset);
+ frame_avg += follow;
+ }
+ frame_avg /= (st->end-st->start);
+ temporal_vbr = SUB16(frame_avg,st->spec_avg);
+ temporal_vbr = MIN16(QCONST16(3.f, DB_SHIFT), MAX16(-QCONST16(1.5f, DB_SHIFT), temporal_vbr));
+ st->spec_avg += MULT16_16_Q15(QCONST16(.02f, 15), temporal_vbr);
+ }
+ /*for (i=0;i<21;i++)
+ printf("%f ", bandLogE[i]);
+ printf("\n");*/
+
+ if (!secondMdct)
+ {
+ for (i=0;i<C*nbEBands;i++)
+ bandLogE2[i] = bandLogE[i];
+ }
+
+ /* Last chance to catch any transient we might have missed in the
+ time-domain analysis */
+ if (LM>0 && ec_tell(enc)+3<=total_bits && !isTransient && st->complexity>=5 && !st->lfe)
+ {
+ if (patch_transient_decision(bandLogE, oldBandE, nbEBands, st->end, C))
+ {
+ isTransient = 1;
+ shortBlocks = M;
+ compute_mdcts(mode, shortBlocks, in, freq, C, CC, LM, st->upsample);
+ compute_band_energies(mode, freq, bandE, effEnd, C, M);
+ amp2Log2(mode, effEnd, st->end, bandE, bandLogE, C);
+ /* Compensate for the scaling of short vs long mdcts */
+ for (i=0;i<C*nbEBands;i++)
+ bandLogE2[i] += HALF16(SHL16(LM, DB_SHIFT));
+ tf_estimate = QCONST16(.2f,14);
+ }
+ }
+
+ if (LM>0 && ec_tell(enc)+3<=total_bits)
+ ec_enc_bit_logp(enc, isTransient, 3);
+
+ ALLOC(X, C*N, celt_norm); /**< Interleaved normalised MDCTs */
+
+ /* Band normalisation */
+ normalise_bands(mode, freq, X, bandE, effEnd, C, M);
+
+ ALLOC(tf_res, nbEBands, int);
+ /* Disable variable tf resolution for hybrid and at very low bitrate */
+ if (effectiveBytes>=15*C && st->start==0 && st->complexity>=2 && !st->lfe)
+ {
+ int lambda;
+ if (effectiveBytes<40)
+ lambda = 12;
+ else if (effectiveBytes<60)
+ lambda = 6;
+ else if (effectiveBytes<100)
+ lambda = 4;
+ else
+ lambda = 3;
+ lambda*=2;
+ tf_select = tf_analysis(mode, effEnd, isTransient, tf_res, lambda, X, N, LM, &tf_sum, tf_estimate, tf_chan);
+ for (i=effEnd;i<st->end;i++)
+ tf_res[i] = tf_res[effEnd-1];
+ } else {
+ tf_sum = 0;
+ for (i=0;i<st->end;i++)
+ tf_res[i] = isTransient;
+ tf_select=0;
+ }
+
+ ALLOC(error, C*nbEBands, opus_val16);
+ quant_coarse_energy(mode, st->start, st->end, effEnd, bandLogE,
+ oldBandE, total_bits, error, enc,
+ C, LM, nbAvailableBytes, st->force_intra,
+ &st->delayedIntra, st->complexity >= 4, st->loss_rate, st->lfe);
+
+ tf_encode(st->start, st->end, isTransient, tf_res, LM, tf_select, enc);
+
+ if (ec_tell(enc)+4<=total_bits)
+ {
+ if (st->lfe)
+ {
+ st->tapset_decision = 0;
+ st->spread_decision = SPREAD_NORMAL;
+ } else if (shortBlocks || st->complexity < 3 || nbAvailableBytes < 10*C || st->start != 0)
+ {
+ if (st->complexity == 0)
+ st->spread_decision = SPREAD_NONE;
+ else
+ st->spread_decision = SPREAD_NORMAL;
+ } else {
+ /* Disable new spreading+tapset estimator until we can show it works
+ better than the old one. So far it seems like spreading_decision()
+ works best. */
+#if 0
+ if (st->analysis.valid)
+ {
+ static const opus_val16 spread_thresholds[3] = {-QCONST16(.6f, 15), -QCONST16(.2f, 15), -QCONST16(.07f, 15)};
+ static const opus_val16 spread_histeresis[3] = {QCONST16(.15f, 15), QCONST16(.07f, 15), QCONST16(.02f, 15)};
+ static const opus_val16 tapset_thresholds[2] = {QCONST16(.0f, 15), QCONST16(.15f, 15)};
+ static const opus_val16 tapset_histeresis[2] = {QCONST16(.1f, 15), QCONST16(.05f, 15)};
+ st->spread_decision = hysteresis_decision(-st->analysis.tonality, spread_thresholds, spread_histeresis, 3, st->spread_decision);
+ st->tapset_decision = hysteresis_decision(st->analysis.tonality_slope, tapset_thresholds, tapset_histeresis, 2, st->tapset_decision);
+ } else
+#endif
+ {
+ st->spread_decision = spreading_decision(mode, X,
+ &st->tonal_average, st->spread_decision, &st->hf_average,
+ &st->tapset_decision, pf_on&&!shortBlocks, effEnd, C, M);
+ }
+ /*printf("%d %d\n", st->tapset_decision, st->spread_decision);*/
+ /*printf("%f %d %f %d\n\n", st->analysis.tonality, st->spread_decision, st->analysis.tonality_slope, st->tapset_decision);*/
+ }
+ ec_enc_icdf(enc, st->spread_decision, spread_icdf, 5);
+ }
+
+ ALLOC(offsets, nbEBands, int);
+
+ maxDepth = dynalloc_analysis(bandLogE, bandLogE2, nbEBands, st->start, st->end, C, offsets,
+ st->lsb_depth, mode->logN, isTransient, st->vbr, st->constrained_vbr,
+ eBands, LM, effectiveBytes, &tot_boost, st->lfe, surround_dynalloc);
+ /* For LFE, everything interesting is in the first band */
+ if (st->lfe)
+ offsets[0] = IMIN(8, effectiveBytes/3);
+ ALLOC(cap, nbEBands, int);
+ init_caps(mode,cap,LM,C);
+
+ dynalloc_logp = 6;
+ total_bits<<=BITRES;
+ total_boost = 0;
+ tell = ec_tell_frac(enc);
+ for (i=st->start;i<st->end;i++)
+ {
+ int width, quanta;
+ int dynalloc_loop_logp;
+ int boost;
+ int j;
+ width = C*(eBands[i+1]-eBands[i])<<LM;
+ /* quanta is 6 bits, but no more than 1 bit/sample
+ and no less than 1/8 bit/sample */
+ quanta = IMIN(width<<BITRES, IMAX(6<<BITRES, width));
+ dynalloc_loop_logp = dynalloc_logp;
+ boost = 0;
+ for (j = 0; tell+(dynalloc_loop_logp<<BITRES) < total_bits-total_boost
+ && boost < cap[i]; j++)
+ {
+ int flag;
+ flag = j<offsets[i];
+ ec_enc_bit_logp(enc, flag, dynalloc_loop_logp);
+ tell = ec_tell_frac(enc);
+ if (!flag)
+ break;
+ boost += quanta;
+ total_boost += quanta;
+ dynalloc_loop_logp = 1;
+ }
+ /* Making dynalloc more likely */
+ if (j)
+ dynalloc_logp = IMAX(2, dynalloc_logp-1);
+ offsets[i] = boost;
+ }
+
+ if (C==2)
+ {
+ static const opus_val16 intensity_thresholds[21]=
+ /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 off*/
+ { 1, 2, 3, 4, 5, 6, 7, 8,16,24,36,44,50,56,62,67,72,79,88,106,134};
+ static const opus_val16 intensity_histeresis[21]=
+ { 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4, 5, 6, 8, 8};
+
+ /* Always use MS for 2.5 ms frames until we can do a better analysis */
+ if (LM!=0)
+ dual_stereo = stereo_analysis(mode, X, LM, N);
+
+ st->intensity = hysteresis_decision((opus_val16)(equiv_rate/1000),
+ intensity_thresholds, intensity_histeresis, 21, st->intensity);
+ st->intensity = IMIN(st->end,IMAX(st->start, st->intensity));
+ }
+
+ alloc_trim = 5;
+ if (tell+(6<<BITRES) <= total_bits - total_boost)
+ {
+ if (st->lfe)
+ alloc_trim = 5;
+ else
+ alloc_trim = alloc_trim_analysis(mode, X, bandLogE,
+ st->end, LM, C, N, &st->analysis, &st->stereo_saving, tf_estimate, st->intensity, surround_trim);
+ ec_enc_icdf(enc, alloc_trim, trim_icdf, 7);
+ tell = ec_tell_frac(enc);
+ }
+
+ /* Variable bitrate */
+ if (vbr_rate>0)
+ {
+ opus_val16 alpha;
+ opus_int32 delta;
+ /* The target rate in 8th bits per frame */
+ opus_int32 target, base_target;
+ opus_int32 min_allowed;
+ int lm_diff = mode->maxLM - LM;
+
+ /* Don't attempt to use more than 510 kb/s, even for frames smaller than 20 ms.
+ The CELT allocator will just not be able to use more than that anyway. */
+ nbCompressedBytes = IMIN(nbCompressedBytes,1275>>(3-LM));
+ base_target = vbr_rate - ((40*C+20)<<BITRES);
+
+ if (st->constrained_vbr)
+ base_target += (st->vbr_offset>>lm_diff);
+
+ target = compute_vbr(mode, &st->analysis, base_target, LM, equiv_rate,
+ st->lastCodedBands, C, st->intensity, st->constrained_vbr,
+ st->stereo_saving, tot_boost, tf_estimate, pitch_change, maxDepth,
+ st->variable_duration, st->lfe, st->energy_mask!=NULL, surround_masking,
+ temporal_vbr);
+
+ /* The current offset is removed from the target and the space used
+ so far is added*/
+ target=target+tell;
+ /* In VBR mode the frame size must not be reduced so much that it would
+ result in the encoder running out of bits.
+ The margin of 2 bytes ensures that none of the bust-prevention logic
+ in the decoder will have triggered so far. */
+ min_allowed = ((tell+total_boost+(1<<(BITRES+3))-1)>>(BITRES+3)) + 2 - nbFilledBytes;
+
+ nbAvailableBytes = (target+(1<<(BITRES+2)))>>(BITRES+3);
+ nbAvailableBytes = IMAX(min_allowed,nbAvailableBytes);
+ nbAvailableBytes = IMIN(nbCompressedBytes,nbAvailableBytes+nbFilledBytes) - nbFilledBytes;
+
+ /* By how much did we "miss" the target on that frame */
+ delta = target - vbr_rate;
+
+ target=nbAvailableBytes<<(BITRES+3);
+
+ /*If the frame is silent we don't adjust our drift, otherwise
+ the encoder will shoot to very high rates after hitting a
+ span of silence, but we do allow the bitres to refill.
+ This means that we'll undershoot our target in CVBR/VBR modes
+ on files with lots of silence. */
+ if(silence)
+ {
+ nbAvailableBytes = 2;
+ target = 2*8<<BITRES;
+ delta = 0;
+ }
+
+ if (st->vbr_count < 970)
+ {
+ st->vbr_count++;
+ alpha = celt_rcp(SHL32(EXTEND32(st->vbr_count+20),16));
+ } else
+ alpha = QCONST16(.001f,15);
+ /* How many bits have we used in excess of what we're allowed */
+ if (st->constrained_vbr)
+ st->vbr_reservoir += target - vbr_rate;
+ /*printf ("%d\n", st->vbr_reservoir);*/
+
+ /* Compute the offset we need to apply in order to reach the target */
+ if (st->constrained_vbr)
+ {
+ st->vbr_drift += (opus_int32)MULT16_32_Q15(alpha,(delta*(1<<lm_diff))-st->vbr_offset-st->vbr_drift);
+ st->vbr_offset = -st->vbr_drift;
+ }
+ /*printf ("%d\n", st->vbr_drift);*/
+
+ if (st->constrained_vbr && st->vbr_reservoir < 0)
+ {
+ /* We're under the min value -- increase rate */
+ int adjust = (-st->vbr_reservoir)/(8<<BITRES);
+ /* Unless we're just coding silence */
+ nbAvailableBytes += silence?0:adjust;
+ st->vbr_reservoir = 0;
+ /*printf ("+%d\n", adjust);*/
+ }
+ nbCompressedBytes = IMIN(nbCompressedBytes,nbAvailableBytes+nbFilledBytes);
+ /*printf("%d\n", nbCompressedBytes*50*8);*/
+ /* This moves the raw bits to take into account the new compressed size */
+ ec_enc_shrink(enc, nbCompressedBytes);
+ }
+
+ /* Bit allocation */
+ ALLOC(fine_quant, nbEBands, int);
+ ALLOC(pulses, nbEBands, int);
+ ALLOC(fine_priority, nbEBands, int);
+
+ /* bits = packet size - where we are - safety*/
+ bits = (((opus_int32)nbCompressedBytes*8)<<BITRES) - ec_tell_frac(enc) - 1;
+ anti_collapse_rsv = isTransient&&LM>=2&&bits>=((LM+2)<<BITRES) ? (1<<BITRES) : 0;
+ bits -= anti_collapse_rsv;
+ signalBandwidth = st->end-1;
+#ifndef DISABLE_FLOAT_API
+ if (st->analysis.valid)
+ {
+ int min_bandwidth;
+ if (equiv_rate < (opus_int32)32000*C)
+ min_bandwidth = 13;
+ else if (equiv_rate < (opus_int32)48000*C)
+ min_bandwidth = 16;
+ else if (equiv_rate < (opus_int32)60000*C)
+ min_bandwidth = 18;
+ else if (equiv_rate < (opus_int32)80000*C)
+ min_bandwidth = 19;
+ else
+ min_bandwidth = 20;
+ signalBandwidth = IMAX(st->analysis.bandwidth, min_bandwidth);
+ }
+#endif
+ if (st->lfe)
+ signalBandwidth = 1;
+ codedBands = compute_allocation(mode, st->start, st->end, offsets, cap,
+ alloc_trim, &st->intensity, &dual_stereo, bits, &balance, pulses,
+ fine_quant, fine_priority, C, LM, enc, 1, st->lastCodedBands, signalBandwidth);
+ if (st->lastCodedBands)
+ st->lastCodedBands = IMIN(st->lastCodedBands+1,IMAX(st->lastCodedBands-1,codedBands));
+ else
+ st->lastCodedBands = codedBands;
+
+ quant_fine_energy(mode, st->start, st->end, oldBandE, error, fine_quant, enc, C);
+
+ /* Residual quantisation */
+ ALLOC(collapse_masks, C*nbEBands, unsigned char);
+ quant_all_bands(1, mode, st->start, st->end, X, C==2 ? X+N : NULL, collapse_masks,
+ bandE, pulses, shortBlocks, st->spread_decision, dual_stereo, st->intensity, tf_res,
+ nbCompressedBytes*(8<<BITRES)-anti_collapse_rsv, balance, enc, LM, codedBands, &st->rng);
+
+ if (anti_collapse_rsv > 0)
+ {
+ anti_collapse_on = st->consec_transient<2;
+#ifdef FUZZING
+ anti_collapse_on = rand()&0x1;
+#endif
+ ec_enc_bits(enc, anti_collapse_on, 1);
+ }
+ quant_energy_finalise(mode, st->start, st->end, oldBandE, error, fine_quant, fine_priority, nbCompressedBytes*8-ec_tell(enc), enc, C);
+
+ if (silence)
+ {
+ for (i=0;i<C*nbEBands;i++)
+ oldBandE[i] = -QCONST16(28.f,DB_SHIFT);
+ }
+
+#ifdef RESYNTH
+ /* Re-synthesis of the coded audio if required */
+ {
+ celt_sig *out_mem[2];
+
+ if (anti_collapse_on)
+ {
+ anti_collapse(mode, X, collapse_masks, LM, C, N,
+ st->start, st->end, oldBandE, oldLogE, oldLogE2, pulses, st->rng);
+ }
+
+ if (silence)
+ {
+ for (i=0;i<C*N;i++)
+ freq[i] = 0;
+ } else {
+ /* Synthesis */
+ denormalise_bands(mode, X, freq, oldBandE, st->start, effEnd, C, M);
+ }
+
+ c=0; do {
+ OPUS_MOVE(st->syn_mem[c], st->syn_mem[c]+N, 2*MAX_PERIOD-N+overlap/2);
+ } while (++c<CC);
+
+ if (CC==2&&C==1)
+ {
+ for (i=0;i<N;i++)
+ freq[N+i] = freq[i];
+ }
+
+ c=0; do {
+ out_mem[c] = st->syn_mem[c]+2*MAX_PERIOD-N;
+ } while (++c<CC);
+
+ compute_inv_mdcts(mode, shortBlocks, freq, out_mem, CC, LM);
+
+ c=0; do {
+ st->prefilter_period=IMAX(st->prefilter_period, COMBFILTER_MINPERIOD);
+ st->prefilter_period_old=IMAX(st->prefilter_period_old, COMBFILTER_MINPERIOD);
+ comb_filter(out_mem[c], out_mem[c], st->prefilter_period_old, st->prefilter_period, mode->shortMdctSize,
+ st->prefilter_gain_old, st->prefilter_gain, st->prefilter_tapset_old, st->prefilter_tapset,
+ mode->window, st->overlap);
+ if (LM!=0)
+ comb_filter(out_mem[c]+mode->shortMdctSize, out_mem[c]+mode->shortMdctSize, st->prefilter_period, pitch_index, N-mode->shortMdctSize,
+ st->prefilter_gain, gain1, st->prefilter_tapset, prefilter_tapset,
+ mode->window, overlap);
+ } while (++c<CC);
+
+ /* We reuse freq[] as scratch space for the de-emphasis */
+ deemphasis(out_mem, (opus_val16*)pcm, N, CC, st->upsample, mode->preemph, st->preemph_memD, freq);
+ st->prefilter_period_old = st->prefilter_period;
+ st->prefilter_gain_old = st->prefilter_gain;
+ st->prefilter_tapset_old = st->prefilter_tapset;
+ }
+#endif
+
+ st->prefilter_period = pitch_index;
+ st->prefilter_gain = gain1;
+ st->prefilter_tapset = prefilter_tapset;
+#ifdef RESYNTH
+ if (LM!=0)
+ {
+ st->prefilter_period_old = st->prefilter_period;
+ st->prefilter_gain_old = st->prefilter_gain;
+ st->prefilter_tapset_old = st->prefilter_tapset;
+ }
+#endif
+
+ if (CC==2&&C==1) {
+ for (i=0;i<nbEBands;i++)
+ oldBandE[nbEBands+i]=oldBandE[i];
+ }
+
+ if (!isTransient)
+ {
+ for (i=0;i<CC*nbEBands;i++)
+ oldLogE2[i] = oldLogE[i];
+ for (i=0;i<CC*nbEBands;i++)
+ oldLogE[i] = oldBandE[i];
+ } else {
+ for (i=0;i<CC*nbEBands;i++)
+ oldLogE[i] = MIN16(oldLogE[i], oldBandE[i]);
+ }
+ /* In case start or end were to change */
+ c=0; do
+ {
+ for (i=0;i<st->start;i++)
+ {
+ oldBandE[c*nbEBands+i]=0;
+ oldLogE[c*nbEBands+i]=oldLogE2[c*nbEBands+i]=-QCONST16(28.f,DB_SHIFT);
+ }
+ for (i=st->end;i<nbEBands;i++)
+ {
+ oldBandE[c*nbEBands+i]=0;
+ oldLogE[c*nbEBands+i]=oldLogE2[c*nbEBands+i]=-QCONST16(28.f,DB_SHIFT);
+ }
+ } while (++c<CC);
+
+ if (isTransient || transient_got_disabled)
+ st->consec_transient++;
+ else
+ st->consec_transient=0;
+ st->rng = enc->rng;
+
+ /* If there's any room left (can only happen for very high rates),
+ it's already filled with zeros */
+ ec_enc_done(enc);
+
+#ifdef CUSTOM_MODES
+ if (st->signalling)
+ nbCompressedBytes++;
+#endif
+
+ RESTORE_STACK;
+ if (ec_get_error(enc))
+ return OPUS_INTERNAL_ERROR;
+ else
+ return nbCompressedBytes;
+}
+
+
+#ifdef CUSTOM_MODES
+
+#ifdef OPUS_FIXED_POINT
+int opus_custom_encode(CELTEncoder * OPUS_RESTRICT st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
+{
+ return celt_encode_with_ec(st, pcm, frame_size, compressed, nbCompressedBytes, NULL);
+}
+
+#ifndef DISABLE_FLOAT_API
+int opus_custom_encode_float(CELTEncoder * OPUS_RESTRICT st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
+{
+ int j, ret, C, N;
+ VARDECL(opus_int16, in);
+ ALLOC_STACK;
+
+ if (pcm==NULL)
+ return OPUS_BAD_ARG;
+
+ C = st->channels;
+ N = frame_size;
+ ALLOC(in, C*N, opus_int16);
+
+ for (j=0;j<C*N;j++)
+ in[j] = FLOAT2INT16(pcm[j]);
+
+ ret=celt_encode_with_ec(st,in,frame_size,compressed,nbCompressedBytes, NULL);
+#ifdef RESYNTH
+ for (j=0;j<C*N;j++)
+ ((float*)pcm)[j]=in[j]*(1.f/32768.f);
+#endif
+ RESTORE_STACK;
+ return ret;
+}
+#endif /* DISABLE_FLOAT_API */
+#else
+
+int opus_custom_encode(CELTEncoder * OPUS_RESTRICT st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
+{
+ int j, ret, C, N;
+ VARDECL(celt_sig, in);
+ ALLOC_STACK;
+
+ if (pcm==NULL)
+ return OPUS_BAD_ARG;
+
+ C=st->channels;
+ N=frame_size;
+ ALLOC(in, C*N, celt_sig);
+ for (j=0;j<C*N;j++) {
+ in[j] = SCALEOUT(pcm[j]);
+ }
+
+ ret = celt_encode_with_ec(st,in,frame_size,compressed,nbCompressedBytes, NULL);
+#ifdef RESYNTH
+ for (j=0;j<C*N;j++)
+ ((opus_int16*)pcm)[j] = FLOAT2INT16(in[j]);
+#endif
+ RESTORE_STACK;
+ return ret;
+}
+
+int opus_custom_encode_float(CELTEncoder * OPUS_RESTRICT st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
+{
+ return celt_encode_with_ec(st, pcm, frame_size, compressed, nbCompressedBytes, NULL);
+}
+
+#endif
+
+#endif /* CUSTOM_MODES */
+
+int opus_custom_encoder_ctl(CELTEncoder * OPUS_RESTRICT st, int request, ...)
+{
+ va_list ap;
+
+ va_start(ap, request);
+ switch (request)
+ {
+ case OPUS_SET_COMPLEXITY_REQUEST:
+ {
+ int value = va_arg(ap, opus_int32);
+ if (value<0 || value>10)
+ goto bad_arg;
+ st->complexity = value;
+ }
+ break;
+ case CELT_SET_START_BAND_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<0 || value>=st->mode->nbEBands)
+ goto bad_arg;
+ st->start = value;
+ }
+ break;
+ case CELT_SET_END_BAND_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<1 || value>st->mode->nbEBands)
+ goto bad_arg;
+ st->end = value;
+ }
+ break;
+ case CELT_SET_PREDICTION_REQUEST:
+ {
+ int value = va_arg(ap, opus_int32);
+ if (value<0 || value>2)
+ goto bad_arg;
+ st->disable_pf = value<=1;
+ st->force_intra = value==0;
+ }
+ break;
+ case OPUS_SET_PACKET_LOSS_PERC_REQUEST:
+ {
+ int value = va_arg(ap, opus_int32);
+ if (value<0 || value>100)
+ goto bad_arg;
+ st->loss_rate = value;
+ }
+ break;
+ case OPUS_SET_VBR_CONSTRAINT_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ st->constrained_vbr = value;
+ }
+ break;
+ case OPUS_SET_VBR_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ st->vbr = value;
+ }
+ break;
+ case OPUS_SET_BITRATE_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<=500 && value!=OPUS_BITRATE_MAX)
+ goto bad_arg;
+ value = IMIN(value, 260000*st->channels);
+ st->bitrate = value;
+ }
+ break;
+ case CELT_SET_CHANNELS_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<1 || value>2)
+ goto bad_arg;
+ st->stream_channels = value;
+ }
+ break;
+ case OPUS_SET_LSB_DEPTH_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<8 || value>24)
+ goto bad_arg;
+ st->lsb_depth=value;
+ }
+ break;
+ case OPUS_GET_LSB_DEPTH_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ *value=st->lsb_depth;
+ }
+ break;
+ case OPUS_SET_EXPERT_FRAME_DURATION_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ st->variable_duration = value;
+ }
+ break;
+ case OPUS_RESET_STATE:
+ {
+ int i;
+ opus_val16 *oldBandE, *oldLogE, *oldLogE2;
+ oldBandE = (opus_val16*)(st->in_mem+st->channels*(st->overlap+COMBFILTER_MAXPERIOD));
+ oldLogE = oldBandE + st->channels*st->mode->nbEBands;
+ oldLogE2 = oldLogE + st->channels*st->mode->nbEBands;
+ OPUS_CLEAR((char*)&st->ENCODER_RESET_START,
+ opus_custom_encoder_get_size(st->mode, st->channels)-
+ ((char*)&st->ENCODER_RESET_START - (char*)st));
+ for (i=0;i<st->channels*st->mode->nbEBands;i++)
+ oldLogE[i]=oldLogE2[i]=-QCONST16(28.f,DB_SHIFT);
+ st->vbr_offset = 0;
+ st->delayedIntra = 1;
+ st->spread_decision = SPREAD_NORMAL;
+ st->tonal_average = 256;
+ st->hf_average = 0;
+ st->tapset_decision = 0;
+ }
+ break;
+#ifdef CUSTOM_MODES
+ case CELT_SET_INPUT_CLIPPING_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ st->clip = value;
+ }
+ break;
+#endif
+ case CELT_SET_SIGNALLING_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ st->signalling = value;
+ }
+ break;
+ case CELT_SET_ANALYSIS_REQUEST:
+ {
+ AnalysisInfo *info = va_arg(ap, AnalysisInfo *);
+ if (info)
+ OPUS_COPY(&st->analysis, info, 1);
+ }
+ break;
+ case CELT_GET_MODE_REQUEST:
+ {
+ const CELTMode ** value = va_arg(ap, const CELTMode**);
+ if (value==0)
+ goto bad_arg;
+ *value=st->mode;
+ }
+ break;
+ case OPUS_GET_FINAL_RANGE_REQUEST:
+ {
+ opus_uint32 * value = va_arg(ap, opus_uint32 *);
+ if (value==0)
+ goto bad_arg;
+ *value=st->rng;
+ }
+ break;
+ case OPUS_SET_LFE_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ st->lfe = value;
+ }
+ break;
+ case OPUS_SET_ENERGY_MASK_REQUEST:
+ {
+ opus_val16 *value = va_arg(ap, opus_val16*);
+ st->energy_mask = value;
+ }
+ break;
+ default:
+ goto bad_request;
+ }
+ va_end(ap);
+ return OPUS_OK;
+bad_arg:
+ va_end(ap);
+ return OPUS_BAD_ARG;
+bad_request:
+ va_end(ap);
+ return OPUS_UNIMPLEMENTED;
+}
diff --git a/drivers/opus/celt/celt_lpc.c b/drivers/opus/celt/celt_lpc.c
new file mode 100644
index 0000000000..ad0a6dfd43
--- /dev/null
+++ b/drivers/opus/celt/celt_lpc.c
@@ -0,0 +1,309 @@
+/* Copyright (c) 2009-2010 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/celt/celt_lpc.h"
+#include "opus/celt/stack_alloc.h"
+#include "opus/celt/mathops.h"
+#include "opus/celt/pitch.h"
+
+void _celt_lpc(
+ opus_val16 *_lpc, /* out: [0...p-1] LPC coefficients */
+const opus_val32 *ac, /* in: [0...p] autocorrelation values */
+int p
+)
+{
+ int i, j;
+ opus_val32 r;
+ opus_val32 error = ac[0];
+#ifdef OPUS_FIXED_POINT
+ opus_val32 lpc[LPC_ORDER];
+#else
+ float *lpc = _lpc;
+#endif
+
+ for (i = 0; i < p; i++)
+ lpc[i] = 0;
+ if (ac[0] != 0)
+ {
+ for (i = 0; i < p; i++) {
+ /* Sum up this iteration's reflection coefficient */
+ opus_val32 rr = 0;
+ for (j = 0; j < i; j++)
+ rr += MULT32_32_Q31(lpc[j],ac[i - j]);
+ rr += SHR32(ac[i + 1],3);
+ r = -frac_div32(SHL32(rr,3), error);
+ /* Update LPC coefficients and total error */
+ lpc[i] = SHR32(r,3);
+ for (j = 0; j < (i+1)>>1; j++)
+ {
+ opus_val32 tmp1, tmp2;
+ tmp1 = lpc[j];
+ tmp2 = lpc[i-1-j];
+ lpc[j] = tmp1 + MULT32_32_Q31(r,tmp2);
+ lpc[i-1-j] = tmp2 + MULT32_32_Q31(r,tmp1);
+ }
+
+ error = error - MULT32_32_Q31(MULT32_32_Q31(r,r),error);
+ /* Bail out once we get 30 dB gain */
+#ifdef OPUS_FIXED_POINT
+ if (error<SHR32(ac[0],10))
+ break;
+#else
+ if (error<.001f*ac[0])
+ break;
+#endif
+ }
+ }
+#ifdef OPUS_FIXED_POINT
+ for (i=0;i<p;i++)
+ _lpc[i] = ROUND16(lpc[i],16);
+#endif
+}
+
+void celt_fir(const opus_val16 *_x,
+ const opus_val16 *num,
+ opus_val16 *_y,
+ int N,
+ int ord,
+ opus_val16 *mem)
+{
+ int i,j;
+ VARDECL(opus_val16, rnum);
+ VARDECL(opus_val16, x);
+ SAVE_STACK;
+
+ ALLOC(rnum, ord, opus_val16);
+ ALLOC(x, N+ord, opus_val16);
+ for(i=0;i<ord;i++)
+ rnum[i] = num[ord-i-1];
+ for(i=0;i<ord;i++)
+ x[i] = mem[ord-i-1];
+ for (i=0;i<N;i++)
+ x[i+ord]=_x[i];
+ for(i=0;i<ord;i++)
+ mem[i] = _x[N-i-1];
+#ifdef SMALL_FOOTPRINT
+ for (i=0;i<N;i++)
+ {
+ opus_val32 sum = SHL32(EXTEND32(_x[i]), SIG_SHIFT);
+ for (j=0;j<ord;j++)
+ {
+ sum = MAC16_16(sum,rnum[j],x[i+j]);
+ }
+ _y[i] = SATURATE16(PSHR32(sum, SIG_SHIFT));
+ }
+#else
+ for (i=0;i<N-3;i+=4)
+ {
+ opus_val32 sum[4]={0,0,0,0};
+ xcorr_kernel(rnum, x+i, sum, ord);
+ _y[i ] = SATURATE16(ADD32(EXTEND32(_x[i ]), PSHR32(sum[0], SIG_SHIFT)));
+ _y[i+1] = SATURATE16(ADD32(EXTEND32(_x[i+1]), PSHR32(sum[1], SIG_SHIFT)));
+ _y[i+2] = SATURATE16(ADD32(EXTEND32(_x[i+2]), PSHR32(sum[2], SIG_SHIFT)));
+ _y[i+3] = SATURATE16(ADD32(EXTEND32(_x[i+3]), PSHR32(sum[3], SIG_SHIFT)));
+ }
+ for (;i<N;i++)
+ {
+ opus_val32 sum = 0;
+ for (j=0;j<ord;j++)
+ sum = MAC16_16(sum,rnum[j],x[i+j]);
+ _y[i] = SATURATE16(ADD32(EXTEND32(_x[i]), PSHR32(sum, SIG_SHIFT)));
+ }
+#endif
+ RESTORE_STACK;
+}
+
+void celt_iir(const opus_val32 *_x,
+ const opus_val16 *den,
+ opus_val32 *_y,
+ int N,
+ int ord,
+ opus_val16 *mem)
+{
+#ifdef SMALL_FOOTPRINT
+ int i,j;
+ for (i=0;i<N;i++)
+ {
+ opus_val32 sum = _x[i];
+ for (j=0;j<ord;j++)
+ {
+ sum -= MULT16_16(den[j],mem[j]);
+ }
+ for (j=ord-1;j>=1;j--)
+ {
+ mem[j]=mem[j-1];
+ }
+ mem[0] = ROUND16(sum,SIG_SHIFT);
+ _y[i] = sum;
+ }
+#else
+ int i,j;
+ VARDECL(opus_val16, rden);
+ VARDECL(opus_val16, y);
+ SAVE_STACK;
+
+ celt_assert((ord&3)==0);
+ ALLOC(rden, ord, opus_val16);
+ ALLOC(y, N+ord, opus_val16);
+ for(i=0;i<ord;i++)
+ rden[i] = den[ord-i-1];
+ for(i=0;i<ord;i++)
+ y[i] = -mem[ord-i-1];
+ for(;i<N+ord;i++)
+ y[i]=0;
+ for (i=0;i<N-3;i+=4)
+ {
+ /* Unroll by 4 as if it were an FIR filter */
+ opus_val32 sum[4];
+ sum[0]=_x[i];
+ sum[1]=_x[i+1];
+ sum[2]=_x[i+2];
+ sum[3]=_x[i+3];
+ xcorr_kernel(rden, y+i, sum, ord);
+
+ /* Patch up the result to compensate for the fact that this is an IIR */
+ y[i+ord ] = -ROUND16(sum[0],SIG_SHIFT);
+ _y[i ] = sum[0];
+ sum[1] = MAC16_16(sum[1], y[i+ord ], den[0]);
+ y[i+ord+1] = -ROUND16(sum[1],SIG_SHIFT);
+ _y[i+1] = sum[1];
+ sum[2] = MAC16_16(sum[2], y[i+ord+1], den[0]);
+ sum[2] = MAC16_16(sum[2], y[i+ord ], den[1]);
+ y[i+ord+2] = -ROUND16(sum[2],SIG_SHIFT);
+ _y[i+2] = sum[2];
+
+ sum[3] = MAC16_16(sum[3], y[i+ord+2], den[0]);
+ sum[3] = MAC16_16(sum[3], y[i+ord+1], den[1]);
+ sum[3] = MAC16_16(sum[3], y[i+ord ], den[2]);
+ y[i+ord+3] = -ROUND16(sum[3],SIG_SHIFT);
+ _y[i+3] = sum[3];
+ }
+ for (;i<N;i++)
+ {
+ opus_val32 sum = _x[i];
+ for (j=0;j<ord;j++)
+ sum -= MULT16_16(rden[j],y[i+j]);
+ y[i+ord] = ROUND16(sum,SIG_SHIFT);
+ _y[i] = sum;
+ }
+ for(i=0;i<ord;i++)
+ mem[i] = _y[N-i-1];
+ RESTORE_STACK;
+#endif
+}
+
+int _celt_autocorr(
+ const opus_val16 *x, /* in: [0...n-1] samples x */
+ opus_val32 *ac, /* out: [0...lag-1] ac values */
+ const opus_val16 *window,
+ int overlap,
+ int lag,
+ int n,
+ int arch
+ )
+{
+ opus_val32 d;
+ int i, k;
+ int fastN=n-lag;
+ int shift;
+ const opus_val16 *xptr;
+ VARDECL(opus_val16, xx);
+ SAVE_STACK;
+ ALLOC(xx, n, opus_val16);
+ celt_assert(n>0);
+ celt_assert(overlap>=0);
+ if (overlap == 0)
+ {
+ xptr = x;
+ } else {
+ for (i=0;i<n;i++)
+ xx[i] = x[i];
+ for (i=0;i<overlap;i++)
+ {
+ xx[i] = MULT16_16_Q15(x[i],window[i]);
+ xx[n-i-1] = MULT16_16_Q15(x[n-i-1],window[i]);
+ }
+ xptr = xx;
+ }
+ shift=0;
+#ifdef OPUS_FIXED_POINT
+ {
+ opus_val32 ac0;
+ ac0 = 1+(n<<7);
+ if (n&1) ac0 += SHR32(MULT16_16(xptr[0],xptr[0]),9);
+ for(i=(n&1);i<n;i+=2)
+ {
+ ac0 += SHR32(MULT16_16(xptr[i],xptr[i]),9);
+ ac0 += SHR32(MULT16_16(xptr[i+1],xptr[i+1]),9);
+ }
+
+ shift = celt_ilog2(ac0)-30+10;
+ shift = (shift)/2;
+ if (shift>0)
+ {
+ for(i=0;i<n;i++)
+ xx[i] = PSHR32(xptr[i], shift);
+ xptr = xx;
+ } else
+ shift = 0;
+ }
+#endif
+ celt_pitch_xcorr(xptr, xptr, ac, fastN, lag+1, arch);
+ for (k=0;k<=lag;k++)
+ {
+ for (i = k+fastN, d = 0; i < n; i++)
+ d = MAC16_16(d, xptr[i], xptr[i-k]);
+ ac[k] += d;
+ }
+#ifdef OPUS_FIXED_POINT
+ shift = 2*shift;
+ if (shift<=0)
+ ac[0] += SHL32((opus_int32)1, -shift);
+ if (ac[0] < 268435456)
+ {
+ int shift2 = 29 - EC_ILOG(ac[0]);
+ for (i=0;i<=lag;i++)
+ ac[i] = SHL32(ac[i], shift2);
+ shift -= shift2;
+ } else if (ac[0] >= 536870912)
+ {
+ int shift2=1;
+ if (ac[0] >= 1073741824)
+ shift2++;
+ for (i=0;i<=lag;i++)
+ ac[i] = SHR32(ac[i], shift2);
+ shift += shift2;
+ }
+#endif
+
+ RESTORE_STACK;
+ return shift;
+}
diff --git a/drivers/opus/celt/celt_lpc.h b/drivers/opus/celt/celt_lpc.h
new file mode 100644
index 0000000000..12bb78a6fd
--- /dev/null
+++ b/drivers/opus/celt/celt_lpc.h
@@ -0,0 +1,54 @@
+/* Copyright (c) 2009-2010 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef PLC_H
+#define PLC_H
+
+#include "opus/celt/arch.h"
+
+#define LPC_ORDER 24
+
+void _celt_lpc(opus_val16 *_lpc, const opus_val32 *ac, int p);
+
+void celt_fir(const opus_val16 *x,
+ const opus_val16 *num,
+ opus_val16 *y,
+ int N,
+ int ord,
+ opus_val16 *mem);
+
+void celt_iir(const opus_val32 *x,
+ const opus_val16 *den,
+ opus_val32 *y,
+ int N,
+ int ord,
+ opus_val16 *mem);
+
+int _celt_autocorr(const opus_val16 *x, opus_val32 *ac,
+ const opus_val16 *window, int overlap, int lag, int n, int arch);
+
+#endif /* PLC_H */
diff --git a/drivers/opus/celt/cpu_support.h b/drivers/opus/celt/cpu_support.h
new file mode 100644
index 0000000000..f682a1d19e
--- /dev/null
+++ b/drivers/opus/celt/cpu_support.h
@@ -0,0 +1,54 @@
+/* Copyright (c) 2010 Xiph.Org Foundation
+ * Copyright (c) 2013 Parrot */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CPU_SUPPORT_H
+#define CPU_SUPPORT_H
+
+#include "opus/opus_types.h"
+#include "opus/opus_defines.h"
+
+#if defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_ASM)
+#include "arm/armcpu.h"
+
+/* We currently support 4 ARM variants:
+ * arch[0] -> ARMv4
+ * arch[1] -> ARMv5E
+ * arch[2] -> ARMv6
+ * arch[3] -> NEON
+ */
+#define OPUS_ARCHMASK 3
+
+#else
+#define OPUS_ARCHMASK 0
+
+static OPUS_INLINE int opus_select_arch(void)
+{
+ return 0;
+}
+#endif
+
+#endif
diff --git a/drivers/opus/celt/cwrs.c b/drivers/opus/celt/cwrs.c
new file mode 100644
index 0000000000..bae9d21b97
--- /dev/null
+++ b/drivers/opus/celt/cwrs.c
@@ -0,0 +1,697 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Copyright (c) 2007-2009 Timothy B. Terriberry
+ Written by Timothy B. Terriberry and Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/celt/os_support.h"
+#include "opus/celt/cwrs.h"
+#include "opus/celt/mathops.h"
+#include "opus/celt/arch.h"
+
+#ifdef CUSTOM_MODES
+
+/*Guaranteed to return a conservatively large estimate of the binary logarithm
+ with frac bits of fractional precision.
+ Tested for all possible 32-bit inputs with frac=4, where the maximum
+ overestimation is 0.06254243 bits.*/
+int log2_frac(opus_uint32 val, int frac)
+{
+ int l;
+ l=EC_ILOG(val);
+ if(val&(val-1)){
+ /*This is (val>>l-16), but guaranteed to round up, even if adding a bias
+ before the shift would cause overflow (e.g., for 0xFFFFxxxx).
+ Doesn't work for val=0, but that case fails the test above.*/
+ if(l>16)val=((val-1)>>(l-16))+1;
+ else val<<=16-l;
+ l=(l-1)<<frac;
+ /*Note that we always need one iteration, since the rounding up above means
+ that we might need to adjust the integer part of the logarithm.*/
+ do{
+ int b;
+ b=(int)(val>>16);
+ l+=b<<frac;
+ val=(val+b)>>b;
+ val=(val*val+0x7FFF)>>15;
+ }
+ while(frac-->0);
+ /*If val is not exactly 0x8000, then we have to round up the remainder.*/
+ return l+(val>0x8000);
+ }
+ /*Exact powers of two require no rounding.*/
+ else return (l-1)<<frac;
+}
+#endif
+
+/*Although derived separately, the pulse vector coding scheme is equivalent to
+ a Pyramid Vector Quantizer \cite{Fis86}.
+ Some additional notes about an early version appear at
+ http://people.xiph.org/~tterribe/notes/cwrs.html, but the codebook ordering
+ and the definitions of some terms have evolved since that was written.
+
+ The conversion from a pulse vector to an integer index (encoding) and back
+ (decoding) is governed by two related functions, V(N,K) and U(N,K).
+
+ V(N,K) = the number of combinations, with replacement, of N items, taken K
+ at a time, when a sign bit is added to each item taken at least once (i.e.,
+ the number of N-dimensional unit pulse vectors with K pulses).
+ One way to compute this is via
+ V(N,K) = K>0 ? sum(k=1...K,2**k*choose(N,k)*choose(K-1,k-1)) : 1,
+ where choose() is the binomial function.
+ A table of values for N<10 and K<10 looks like:
+ V[10][10] = {
+ {1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {1, 2, 2, 2, 2, 2, 2, 2, 2, 2},
+ {1, 4, 8, 12, 16, 20, 24, 28, 32, 36},
+ {1, 6, 18, 38, 66, 102, 146, 198, 258, 326},
+ {1, 8, 32, 88, 192, 360, 608, 952, 1408, 1992},
+ {1, 10, 50, 170, 450, 1002, 1970, 3530, 5890, 9290},
+ {1, 12, 72, 292, 912, 2364, 5336, 10836, 20256, 35436},
+ {1, 14, 98, 462, 1666, 4942, 12642, 28814, 59906, 115598},
+ {1, 16, 128, 688, 2816, 9424, 27008, 68464, 157184, 332688},
+ {1, 18, 162, 978, 4482, 16722, 53154, 148626, 374274, 864146}
+ };
+
+ U(N,K) = the number of such combinations wherein N-1 objects are taken at
+ most K-1 at a time.
+ This is given by
+ U(N,K) = sum(k=0...K-1,V(N-1,k))
+ = K>0 ? (V(N-1,K-1) + V(N,K-1))/2 : 0.
+ The latter expression also makes clear that U(N,K) is half the number of such
+ combinations wherein the first object is taken at least once.
+ Although it may not be clear from either of these definitions, U(N,K) is the
+ natural function to work with when enumerating the pulse vector codebooks,
+ not V(N,K).
+ U(N,K) is not well-defined for N=0, but with the extension
+ U(0,K) = K>0 ? 0 : 1,
+ the function becomes symmetric: U(N,K) = U(K,N), with a similar table:
+ U[10][10] = {
+ {1, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {0, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {0, 1, 3, 5, 7, 9, 11, 13, 15, 17},
+ {0, 1, 5, 13, 25, 41, 61, 85, 113, 145},
+ {0, 1, 7, 25, 63, 129, 231, 377, 575, 833},
+ {0, 1, 9, 41, 129, 321, 681, 1289, 2241, 3649},
+ {0, 1, 11, 61, 231, 681, 1683, 3653, 7183, 13073},
+ {0, 1, 13, 85, 377, 1289, 3653, 8989, 19825, 40081},
+ {0, 1, 15, 113, 575, 2241, 7183, 19825, 48639, 108545},
+ {0, 1, 17, 145, 833, 3649, 13073, 40081, 108545, 265729}
+ };
+
+ With this extension, V(N,K) may be written in terms of U(N,K):
+ V(N,K) = U(N,K) + U(N,K+1)
+ for all N>=0, K>=0.
+ Thus U(N,K+1) represents the number of combinations where the first element
+ is positive or zero, and U(N,K) represents the number of combinations where
+ it is negative.
+ With a large enough table of U(N,K) values, we could write O(N) encoding
+ and O(min(N*log(K),N+K)) decoding routines, but such a table would be
+ prohibitively large for small embedded devices (K may be as large as 32767
+ for small N, and N may be as large as 200).
+
+ Both functions obey the same recurrence relation:
+ V(N,K) = V(N-1,K) + V(N,K-1) + V(N-1,K-1),
+ U(N,K) = U(N-1,K) + U(N,K-1) + U(N-1,K-1),
+ for all N>0, K>0, with different initial conditions at N=0 or K=0.
+ This allows us to construct a row of one of the tables above given the
+ previous row or the next row.
+ Thus we can derive O(NK) encoding and decoding routines with O(K) memory
+ using only addition and subtraction.
+
+ When encoding, we build up from the U(2,K) row and work our way forwards.
+ When decoding, we need to start at the U(N,K) row and work our way backwards,
+ which requires a means of computing U(N,K).
+ U(N,K) may be computed from two previous values with the same N:
+ U(N,K) = ((2*N-1)*U(N,K-1) - U(N,K-2))/(K-1) + U(N,K-2)
+ for all N>1, and since U(N,K) is symmetric, a similar relation holds for two
+ previous values with the same K:
+ U(N,K>1) = ((2*K-1)*U(N-1,K) - U(N-2,K))/(N-1) + U(N-2,K)
+ for all K>1.
+ This allows us to construct an arbitrary row of the U(N,K) table by starting
+ with the first two values, which are constants.
+ This saves roughly 2/3 the work in our O(NK) decoding routine, but costs O(K)
+ multiplications.
+ Similar relations can be derived for V(N,K), but are not used here.
+
+ For N>0 and K>0, U(N,K) and V(N,K) take on the form of an (N-1)-degree
+ polynomial for fixed N.
+ The first few are
+ U(1,K) = 1,
+ U(2,K) = 2*K-1,
+ U(3,K) = (2*K-2)*K+1,
+ U(4,K) = (((4*K-6)*K+8)*K-3)/3,
+ U(5,K) = ((((2*K-4)*K+10)*K-8)*K+3)/3,
+ and
+ V(1,K) = 2,
+ V(2,K) = 4*K,
+ V(3,K) = 4*K*K+2,
+ V(4,K) = 8*(K*K+2)*K/3,
+ V(5,K) = ((4*K*K+20)*K*K+6)/3,
+ for all K>0.
+ This allows us to derive O(N) encoding and O(N*log(K)) decoding routines for
+ small N (and indeed decoding is also O(N) for N<3).
+
+ @ARTICLE{Fis86,
+ author="Thomas R. Fischer",
+ title="A Pyramid Vector Quantizer",
+ journal="IEEE Transactions on Information Theory",
+ volume="IT-32",
+ number=4,
+ pages="568--583",
+ month=Jul,
+ year=1986
+ }*/
+
+#if !defined(SMALL_FOOTPRINT)
+
+/*U(N,K) = U(K,N) := N>0?K>0?U(N-1,K)+U(N,K-1)+U(N-1,K-1):0:K>0?1:0*/
+# define CELT_PVQ_U(_n,_k) (CELT_PVQ_U_ROW[IMIN(_n,_k)][IMAX(_n,_k)])
+/*V(N,K) := U(N,K)+U(N,K+1) = the number of PVQ codewords for a band of size N
+ with K pulses allocated to it.*/
+# define CELT_PVQ_V(_n,_k) (CELT_PVQ_U(_n,_k)+CELT_PVQ_U(_n,(_k)+1))
+
+/*For each V(N,K) supported, we will access element U(min(N,K+1),max(N,K+1)).
+ Thus, the number of entries in row I is the larger of the maximum number of
+ pulses we will ever allocate for a given N=I (K=128, or however many fit in
+ 32 bits, whichever is smaller), plus one, and the maximum N for which
+ K=I-1 pulses fit in 32 bits.
+ The largest band size in an Opus Custom mode is 208.
+ Otherwise, we can limit things to the set of N which can be achieved by
+ splitting a band from a standard Opus mode: 176, 144, 96, 88, 72, 64, 48,
+ 44, 36, 32, 24, 22, 18, 16, 8, 4, 2).*/
+#if defined(CUSTOM_MODES)
+static const opus_uint32 CELT_PVQ_U_DATA[1488]={
+#else
+static const opus_uint32 CELT_PVQ_U_DATA[1272]={
+#endif
+ /*N=0, K=0...176:*/
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+#if defined(CUSTOM_MODES)
+ /*...208:*/
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+#endif
+ /*N=1, K=1...176:*/
+ 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, 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, 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, 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, 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, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+#if defined(CUSTOM_MODES)
+ /*...208:*/
+ 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,
+#endif
+ /*N=2, K=2...176:*/
+ 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41,
+ 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79,
+ 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 107, 109, 111, 113,
+ 115, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143,
+ 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173,
+ 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203,
+ 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233,
+ 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255, 257, 259, 261, 263,
+ 265, 267, 269, 271, 273, 275, 277, 279, 281, 283, 285, 287, 289, 291, 293,
+ 295, 297, 299, 301, 303, 305, 307, 309, 311, 313, 315, 317, 319, 321, 323,
+ 325, 327, 329, 331, 333, 335, 337, 339, 341, 343, 345, 347, 349, 351,
+#if defined(CUSTOM_MODES)
+ /*...208:*/
+ 353, 355, 357, 359, 361, 363, 365, 367, 369, 371, 373, 375, 377, 379, 381,
+ 383, 385, 387, 389, 391, 393, 395, 397, 399, 401, 403, 405, 407, 409, 411,
+ 413, 415,
+#endif
+ /*N=3, K=3...176:*/
+ 13, 25, 41, 61, 85, 113, 145, 181, 221, 265, 313, 365, 421, 481, 545, 613,
+ 685, 761, 841, 925, 1013, 1105, 1201, 1301, 1405, 1513, 1625, 1741, 1861,
+ 1985, 2113, 2245, 2381, 2521, 2665, 2813, 2965, 3121, 3281, 3445, 3613, 3785,
+ 3961, 4141, 4325, 4513, 4705, 4901, 5101, 5305, 5513, 5725, 5941, 6161, 6385,
+ 6613, 6845, 7081, 7321, 7565, 7813, 8065, 8321, 8581, 8845, 9113, 9385, 9661,
+ 9941, 10225, 10513, 10805, 11101, 11401, 11705, 12013, 12325, 12641, 12961,
+ 13285, 13613, 13945, 14281, 14621, 14965, 15313, 15665, 16021, 16381, 16745,
+ 17113, 17485, 17861, 18241, 18625, 19013, 19405, 19801, 20201, 20605, 21013,
+ 21425, 21841, 22261, 22685, 23113, 23545, 23981, 24421, 24865, 25313, 25765,
+ 26221, 26681, 27145, 27613, 28085, 28561, 29041, 29525, 30013, 30505, 31001,
+ 31501, 32005, 32513, 33025, 33541, 34061, 34585, 35113, 35645, 36181, 36721,
+ 37265, 37813, 38365, 38921, 39481, 40045, 40613, 41185, 41761, 42341, 42925,
+ 43513, 44105, 44701, 45301, 45905, 46513, 47125, 47741, 48361, 48985, 49613,
+ 50245, 50881, 51521, 52165, 52813, 53465, 54121, 54781, 55445, 56113, 56785,
+ 57461, 58141, 58825, 59513, 60205, 60901, 61601,
+#if defined(CUSTOM_MODES)
+ /*...208:*/
+ 62305, 63013, 63725, 64441, 65161, 65885, 66613, 67345, 68081, 68821, 69565,
+ 70313, 71065, 71821, 72581, 73345, 74113, 74885, 75661, 76441, 77225, 78013,
+ 78805, 79601, 80401, 81205, 82013, 82825, 83641, 84461, 85285, 86113,
+#endif
+ /*N=4, K=4...176:*/
+ 63, 129, 231, 377, 575, 833, 1159, 1561, 2047, 2625, 3303, 4089, 4991, 6017,
+ 7175, 8473, 9919, 11521, 13287, 15225, 17343, 19649, 22151, 24857, 27775,
+ 30913, 34279, 37881, 41727, 45825, 50183, 54809, 59711, 64897, 70375, 76153,
+ 82239, 88641, 95367, 102425, 109823, 117569, 125671, 134137, 142975, 152193,
+ 161799, 171801, 182207, 193025, 204263, 215929, 228031, 240577, 253575,
+ 267033, 280959, 295361, 310247, 325625, 341503, 357889, 374791, 392217,
+ 410175, 428673, 447719, 467321, 487487, 508225, 529543, 551449, 573951,
+ 597057, 620775, 645113, 670079, 695681, 721927, 748825, 776383, 804609,
+ 833511, 863097, 893375, 924353, 956039, 988441, 1021567, 1055425, 1090023,
+ 1125369, 1161471, 1198337, 1235975, 1274393, 1313599, 1353601, 1394407,
+ 1436025, 1478463, 1521729, 1565831, 1610777, 1656575, 1703233, 1750759,
+ 1799161, 1848447, 1898625, 1949703, 2001689, 2054591, 2108417, 2163175,
+ 2218873, 2275519, 2333121, 2391687, 2451225, 2511743, 2573249, 2635751,
+ 2699257, 2763775, 2829313, 2895879, 2963481, 3032127, 3101825, 3172583,
+ 3244409, 3317311, 3391297, 3466375, 3542553, 3619839, 3698241, 3777767,
+ 3858425, 3940223, 4023169, 4107271, 4192537, 4278975, 4366593, 4455399,
+ 4545401, 4636607, 4729025, 4822663, 4917529, 5013631, 5110977, 5209575,
+ 5309433, 5410559, 5512961, 5616647, 5721625, 5827903, 5935489, 6044391,
+ 6154617, 6266175, 6379073, 6493319, 6608921, 6725887, 6844225, 6963943,
+ 7085049, 7207551,
+#if defined(CUSTOM_MODES)
+ /*...208:*/
+ 7331457, 7456775, 7583513, 7711679, 7841281, 7972327, 8104825, 8238783,
+ 8374209, 8511111, 8649497, 8789375, 8930753, 9073639, 9218041, 9363967,
+ 9511425, 9660423, 9810969, 9963071, 10116737, 10271975, 10428793, 10587199,
+ 10747201, 10908807, 11072025, 11236863, 11403329, 11571431, 11741177,
+ 11912575,
+#endif
+ /*N=5, K=5...176:*/
+ 321, 681, 1289, 2241, 3649, 5641, 8361, 11969, 16641, 22569, 29961, 39041,
+ 50049, 63241, 78889, 97281, 118721, 143529, 172041, 204609, 241601, 283401,
+ 330409, 383041, 441729, 506921, 579081, 658689, 746241, 842249, 947241,
+ 1061761, 1186369, 1321641, 1468169, 1626561, 1797441, 1981449, 2179241,
+ 2391489, 2618881, 2862121, 3121929, 3399041, 3694209, 4008201, 4341801,
+ 4695809, 5071041, 5468329, 5888521, 6332481, 6801089, 7295241, 7815849,
+ 8363841, 8940161, 9545769, 10181641, 10848769, 11548161, 12280841, 13047849,
+ 13850241, 14689089, 15565481, 16480521, 17435329, 18431041, 19468809,
+ 20549801, 21675201, 22846209, 24064041, 25329929, 26645121, 28010881,
+ 29428489, 30899241, 32424449, 34005441, 35643561, 37340169, 39096641,
+ 40914369, 42794761, 44739241, 46749249, 48826241, 50971689, 53187081,
+ 55473921, 57833729, 60268041, 62778409, 65366401, 68033601, 70781609,
+ 73612041, 76526529, 79526721, 82614281, 85790889, 89058241, 92418049,
+ 95872041, 99421961, 103069569, 106816641, 110664969, 114616361, 118672641,
+ 122835649, 127107241, 131489289, 135983681, 140592321, 145317129, 150160041,
+ 155123009, 160208001, 165417001, 170752009, 176215041, 181808129, 187533321,
+ 193392681, 199388289, 205522241, 211796649, 218213641, 224775361, 231483969,
+ 238341641, 245350569, 252512961, 259831041, 267307049, 274943241, 282741889,
+ 290705281, 298835721, 307135529, 315607041, 324252609, 333074601, 342075401,
+ 351257409, 360623041, 370174729, 379914921, 389846081, 399970689, 410291241,
+ 420810249, 431530241, 442453761, 453583369, 464921641, 476471169, 488234561,
+ 500214441, 512413449, 524834241, 537479489, 550351881, 563454121, 576788929,
+ 590359041, 604167209, 618216201, 632508801,
+#if defined(CUSTOM_MODES)
+ /*...208:*/
+ 647047809, 661836041, 676876329, 692171521, 707724481, 723538089, 739615241,
+ 755958849, 772571841, 789457161, 806617769, 824056641, 841776769, 859781161,
+ 878072841, 896654849, 915530241, 934702089, 954173481, 973947521, 994027329,
+ 1014416041, 1035116809, 1056132801, 1077467201, 1099123209, 1121104041,
+ 1143412929, 1166053121, 1189027881, 1212340489, 1235994241,
+#endif
+ /*N=6, K=6...96:*/
+ 1683, 3653, 7183, 13073, 22363, 36365, 56695, 85305, 124515, 177045, 246047,
+ 335137, 448427, 590557, 766727, 982729, 1244979, 1560549, 1937199, 2383409,
+ 2908411, 3522221, 4235671, 5060441, 6009091, 7095093, 8332863, 9737793,
+ 11326283, 13115773, 15124775, 17372905, 19880915, 22670725, 25765455,
+ 29189457, 32968347, 37129037, 41699767, 46710137, 52191139, 58175189,
+ 64696159, 71789409, 79491819, 87841821, 96879431, 106646281, 117185651,
+ 128542501, 140763503, 153897073, 167993403, 183104493, 199284183, 216588185,
+ 235074115, 254801525, 275831935, 298228865, 322057867, 347386557, 374284647,
+ 402823977, 433078547, 465124549, 499040399, 534906769, 572806619, 612825229,
+ 655050231, 699571641, 746481891, 795875861, 847850911, 902506913, 959946283,
+ 1020274013, 1083597703, 1150027593, 1219676595, 1292660325, 1369097135,
+ 1449108145, 1532817275, 1620351277, 1711839767, 1807415257, 1907213187,
+ 2011371957, 2120032959,
+#if defined(CUSTOM_MODES)
+ /*...109:*/
+ 2233340609U, 2351442379U, 2474488829U, 2602633639U, 2736033641U, 2874848851U,
+ 3019242501U, 3169381071U, 3325434321U, 3487575323U, 3655980493U, 3830829623U,
+ 4012305913U,
+#endif
+ /*N=7, K=7...54*/
+ 8989, 19825, 40081, 75517, 134245, 227305, 369305, 579125, 880685, 1303777,
+ 1884961, 2668525, 3707509, 5064793, 6814249, 9041957, 11847485, 15345233,
+ 19665841, 24957661, 31388293, 39146185, 48442297, 59511829, 72616013,
+ 88043969, 106114625, 127178701, 151620757, 179861305, 212358985, 249612805,
+ 292164445, 340600625, 395555537, 457713341, 527810725, 606639529, 695049433,
+ 793950709, 904317037, 1027188385, 1163673953, 1314955181, 1482288821,
+ 1667010073, 1870535785, 2094367717,
+#if defined(CUSTOM_MODES)
+ /*...60:*/
+ 2340095869U, 2609401873U, 2904062449U, 3225952925U, 3577050821U, 3959439497U,
+#endif
+ /*N=8, K=8...37*/
+ 48639, 108545, 224143, 433905, 795455, 1392065, 2340495, 3800305, 5984767,
+ 9173505, 13726991, 20103025, 28875327, 40754369, 56610575, 77500017,
+ 104692735, 139703809, 184327311, 240673265, 311207743, 398796225, 506750351,
+ 638878193, 799538175, 993696769, 1226990095, 1505789553, 1837271615,
+ 2229491905U,
+#if defined(CUSTOM_MODES)
+ /*...40:*/
+ 2691463695U, 3233240945U, 3866006015U,
+#endif
+ /*N=9, K=9...28:*/
+ 265729, 598417, 1256465, 2485825, 4673345, 8405905, 14546705, 24331777,
+ 39490049, 62390545, 96220561, 145198913, 214828609, 312193553, 446304145,
+ 628496897, 872893441, 1196924561, 1621925137, 2173806145U,
+#if defined(CUSTOM_MODES)
+ /*...29:*/
+ 2883810113U,
+#endif
+ /*N=10, K=10...24:*/
+ 1462563, 3317445, 7059735, 14218905, 27298155, 50250765, 89129247, 152951073,
+ 254831667, 413442773, 654862247, 1014889769, 1541911931, 2300409629U,
+ 3375210671U,
+ /*N=11, K=11...19:*/
+ 8097453, 18474633, 39753273, 81270333, 158819253, 298199265, 540279585,
+ 948062325, 1616336765,
+#if defined(CUSTOM_MODES)
+ /*...20:*/
+ 2684641785U,
+#endif
+ /*N=12, K=12...18:*/
+ 45046719, 103274625, 224298231, 464387817, 921406335, 1759885185,
+ 3248227095U,
+ /*N=13, K=13...16:*/
+ 251595969, 579168825, 1267854873, 2653649025U,
+ /*N=14, K=14:*/
+ 1409933619
+};
+
+#if defined(CUSTOM_MODES)
+static const opus_uint32 *const CELT_PVQ_U_ROW[15]={
+ CELT_PVQ_U_DATA+ 0,CELT_PVQ_U_DATA+ 208,CELT_PVQ_U_DATA+ 415,
+ CELT_PVQ_U_DATA+ 621,CELT_PVQ_U_DATA+ 826,CELT_PVQ_U_DATA+1030,
+ CELT_PVQ_U_DATA+1233,CELT_PVQ_U_DATA+1336,CELT_PVQ_U_DATA+1389,
+ CELT_PVQ_U_DATA+1421,CELT_PVQ_U_DATA+1441,CELT_PVQ_U_DATA+1455,
+ CELT_PVQ_U_DATA+1464,CELT_PVQ_U_DATA+1470,CELT_PVQ_U_DATA+1473
+};
+#else
+static const opus_uint32 *const CELT_PVQ_U_ROW[15]={
+ CELT_PVQ_U_DATA+ 0,CELT_PVQ_U_DATA+ 176,CELT_PVQ_U_DATA+ 351,
+ CELT_PVQ_U_DATA+ 525,CELT_PVQ_U_DATA+ 698,CELT_PVQ_U_DATA+ 870,
+ CELT_PVQ_U_DATA+1041,CELT_PVQ_U_DATA+1131,CELT_PVQ_U_DATA+1178,
+ CELT_PVQ_U_DATA+1207,CELT_PVQ_U_DATA+1226,CELT_PVQ_U_DATA+1240,
+ CELT_PVQ_U_DATA+1248,CELT_PVQ_U_DATA+1254,CELT_PVQ_U_DATA+1257
+};
+#endif
+
+#if defined(CUSTOM_MODES)
+void get_required_bits(opus_int16 *_bits,int _n,int _maxk,int _frac){
+ int k;
+ /*_maxk==0 => there's nothing to do.*/
+ celt_assert(_maxk>0);
+ _bits[0]=0;
+ for(k=1;k<=_maxk;k++)_bits[k]=log2_frac(CELT_PVQ_V(_n,k),_frac);
+}
+#endif
+
+static opus_uint32 icwrs(int _n,const int *_y){
+ opus_uint32 i;
+ int j;
+ int k;
+ celt_assert(_n>=2);
+ j=_n-1;
+ i=_y[j]<0;
+ k=abs(_y[j]);
+ do{
+ j--;
+ i+=CELT_PVQ_U(_n-j,k);
+ k+=abs(_y[j]);
+ if(_y[j]<0)i+=CELT_PVQ_U(_n-j,k+1);
+ }
+ while(j>0);
+ return i;
+}
+
+void encode_pulses(const int *_y,int _n,int _k,ec_enc *_enc){
+ celt_assert(_k>0);
+ ec_enc_uint(_enc,icwrs(_n,_y),CELT_PVQ_V(_n,_k));
+}
+
+static void cwrsi(int _n,int _k,opus_uint32 _i,int *_y){
+ opus_uint32 p;
+ int s;
+ int k0;
+ celt_assert(_k>0);
+ celt_assert(_n>1);
+ while(_n>2){
+ opus_uint32 q;
+ /*Lots of pulses case:*/
+ if(_k>=_n){
+ const opus_uint32 *row;
+ row=CELT_PVQ_U_ROW[_n];
+ /*Are the pulses in this dimension negative?*/
+ p=row[_k+1];
+ s=-(_i>=p);
+ _i-=p&s;
+ /*Count how many pulses were placed in this dimension.*/
+ k0=_k;
+ q=row[_n];
+ if(q>_i){
+ celt_assert(p>q);
+ _k=_n;
+ do p=CELT_PVQ_U_ROW[--_k][_n];
+ while(p>_i);
+ }
+ else for(p=row[_k];p>_i;p=row[_k])_k--;
+ _i-=p;
+ *_y++=(k0-_k+s)^s;
+ }
+ /*Lots of dimensions case:*/
+ else{
+ /*Are there any pulses in this dimension at all?*/
+ p=CELT_PVQ_U_ROW[_k][_n];
+ q=CELT_PVQ_U_ROW[_k+1][_n];
+ if(p<=_i&&_i<q){
+ _i-=p;
+ *_y++=0;
+ }
+ else{
+ /*Are the pulses in this dimension negative?*/
+ s=-(_i>=q);
+ _i-=q&s;
+ /*Count how many pulses were placed in this dimension.*/
+ k0=_k;
+ do p=CELT_PVQ_U_ROW[--_k][_n];
+ while(p>_i);
+ _i-=p;
+ *_y++=(k0-_k+s)^s;
+ }
+ }
+ _n--;
+ }
+ /*_n==2*/
+ p=2*_k+1;
+ s=-(_i>=p);
+ _i-=p&s;
+ k0=_k;
+ _k=(_i+1)>>1;
+ if(_k)_i-=2*_k-1;
+ *_y++=(k0-_k+s)^s;
+ /*_n==1*/
+ s=-(int)_i;
+ *_y=(_k+s)^s;
+}
+
+void decode_pulses(int *_y,int _n,int _k,ec_dec *_dec){
+ cwrsi(_n,_k,ec_dec_uint(_dec,CELT_PVQ_V(_n,_k)),_y);
+}
+
+#else /* SMALL_FOOTPRINT */
+
+/*Computes the next row/column of any recurrence that obeys the relation
+ u[i][j]=u[i-1][j]+u[i][j-1]+u[i-1][j-1].
+ _ui0 is the base case for the new row/column.*/
+static OPUS_INLINE void unext(opus_uint32 *_ui,unsigned _len,opus_uint32 _ui0){
+ opus_uint32 ui1;
+ unsigned j;
+ /*This do-while will overrun the array if we don't have storage for at least
+ 2 values.*/
+ j=1; do {
+ ui1=UADD32(UADD32(_ui[j],_ui[j-1]),_ui0);
+ _ui[j-1]=_ui0;
+ _ui0=ui1;
+ } while (++j<_len);
+ _ui[j-1]=_ui0;
+}
+
+/*Computes the previous row/column of any recurrence that obeys the relation
+ u[i-1][j]=u[i][j]-u[i][j-1]-u[i-1][j-1].
+ _ui0 is the base case for the new row/column.*/
+static OPUS_INLINE void uprev(opus_uint32 *_ui,unsigned _n,opus_uint32 _ui0){
+ opus_uint32 ui1;
+ unsigned j;
+ /*This do-while will overrun the array if we don't have storage for at least
+ 2 values.*/
+ j=1; do {
+ ui1=USUB32(USUB32(_ui[j],_ui[j-1]),_ui0);
+ _ui[j-1]=_ui0;
+ _ui0=ui1;
+ } while (++j<_n);
+ _ui[j-1]=_ui0;
+}
+
+/*Compute V(_n,_k), as well as U(_n,0..._k+1).
+ _u: On exit, _u[i] contains U(_n,i) for i in [0..._k+1].*/
+static opus_uint32 ncwrs_urow(unsigned _n,unsigned _k,opus_uint32 *_u){
+ opus_uint32 um2;
+ unsigned len;
+ unsigned k;
+ len=_k+2;
+ /*We require storage at least 3 values (e.g., _k>0).*/
+ celt_assert(len>=3);
+ _u[0]=0;
+ _u[1]=um2=1;
+ /*If _n==0, _u[0] should be 1 and the rest should be 0.*/
+ /*If _n==1, _u[i] should be 1 for i>1.*/
+ celt_assert(_n>=2);
+ /*If _k==0, the following do-while loop will overflow the buffer.*/
+ celt_assert(_k>0);
+ k=2;
+ do _u[k]=(k<<1)-1;
+ while(++k<len);
+ for(k=2;k<_n;k++)unext(_u+1,_k+1,1);
+ return _u[_k]+_u[_k+1];
+}
+
+/*Returns the _i'th combination of _k elements chosen from a set of size _n
+ with associated sign bits.
+ _y: Returns the vector of pulses.
+ _u: Must contain entries [0..._k+1] of row _n of U() on input.
+ Its contents will be destructively modified.*/
+static void cwrsi(int _n,int _k,opus_uint32 _i,int *_y,opus_uint32 *_u){
+ int j;
+ celt_assert(_n>0);
+ j=0;
+ do{
+ opus_uint32 p;
+ int s;
+ int yj;
+ p=_u[_k+1];
+ s=-(_i>=p);
+ _i-=p&s;
+ yj=_k;
+ p=_u[_k];
+ while(p>_i)p=_u[--_k];
+ _i-=p;
+ yj-=_k;
+ _y[j]=(yj+s)^s;
+ uprev(_u,_k+2,0);
+ }
+ while(++j<_n);
+}
+
+/*Returns the index of the given combination of K elements chosen from a set
+ of size 1 with associated sign bits.
+ _y: The vector of pulses, whose sum of absolute values is K.
+ _k: Returns K.*/
+static OPUS_INLINE opus_uint32 icwrs1(const int *_y,int *_k){
+ *_k=abs(_y[0]);
+ return _y[0]<0;
+}
+
+/*Returns the index of the given combination of K elements chosen from a set
+ of size _n with associated sign bits.
+ _y: The vector of pulses, whose sum of absolute values must be _k.
+ _nc: Returns V(_n,_k).*/
+static OPUS_INLINE opus_uint32 icwrs(int _n,int _k,opus_uint32 *_nc,const int *_y,
+ opus_uint32 *_u){
+ opus_uint32 i;
+ int j;
+ int k;
+ /*We can't unroll the first two iterations of the loop unless _n>=2.*/
+ celt_assert(_n>=2);
+ _u[0]=0;
+ for(k=1;k<=_k+1;k++)_u[k]=(k<<1)-1;
+ i=icwrs1(_y+_n-1,&k);
+ j=_n-2;
+ i+=_u[k];
+ k+=abs(_y[j]);
+ if(_y[j]<0)i+=_u[k+1];
+ while(j-->0){
+ unext(_u,_k+2,0);
+ i+=_u[k];
+ k+=abs(_y[j]);
+ if(_y[j]<0)i+=_u[k+1];
+ }
+ *_nc=_u[k]+_u[k+1];
+ return i;
+}
+
+#ifdef CUSTOM_MODES
+void get_required_bits(opus_int16 *_bits,int _n,int _maxk,int _frac){
+ int k;
+ /*_maxk==0 => there's nothing to do.*/
+ celt_assert(_maxk>0);
+ _bits[0]=0;
+ if (_n==1)
+ {
+ for (k=1;k<=_maxk;k++)
+ _bits[k] = 1<<_frac;
+ }
+ else {
+ VARDECL(opus_uint32,u);
+ SAVE_STACK;
+ ALLOC(u,_maxk+2U,opus_uint32);
+ ncwrs_urow(_n,_maxk,u);
+ for(k=1;k<=_maxk;k++)
+ _bits[k]=log2_frac(u[k]+u[k+1],_frac);
+ RESTORE_STACK;
+ }
+}
+#endif /* CUSTOM_MODES */
+
+void encode_pulses(const int *_y,int _n,int _k,ec_enc *_enc){
+ opus_uint32 i;
+ VARDECL(opus_uint32,u);
+ opus_uint32 nc;
+ SAVE_STACK;
+ celt_assert(_k>0);
+ ALLOC(u,_k+2U,opus_uint32);
+ i=icwrs(_n,_k,&nc,_y,u);
+ ec_enc_uint(_enc,i,nc);
+ RESTORE_STACK;
+}
+
+void decode_pulses(int *_y,int _n,int _k,ec_dec *_dec){
+ VARDECL(opus_uint32,u);
+ SAVE_STACK;
+ celt_assert(_k>0);
+ ALLOC(u,_k+2U,opus_uint32);
+ cwrsi(_n,_k,ec_dec_uint(_dec,ncwrs_urow(_n,_k,u)),_y,u);
+ RESTORE_STACK;
+}
+
+#endif /* SMALL_FOOTPRINT */
diff --git a/drivers/opus/celt/cwrs.h b/drivers/opus/celt/cwrs.h
new file mode 100644
index 0000000000..5400afa6a4
--- /dev/null
+++ b/drivers/opus/celt/cwrs.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Copyright (c) 2007-2009 Timothy B. Terriberry
+ Written by Timothy B. Terriberry and Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CWRS_H
+#define CWRS_H
+
+#include "opus/celt/arch.h"
+#include "opus/celt/stack_alloc.h"
+#include "opus/celt/entenc.h"
+#include "opus/celt/entdec.h"
+
+#ifdef CUSTOM_MODES
+int log2_frac(opus_uint32 val, int frac);
+#endif
+
+void get_required_bits(opus_int16 *bits, int N, int K, int frac);
+
+void encode_pulses(const int *_y, int N, int K, ec_enc *enc);
+
+void decode_pulses(int *_y, int N, int K, ec_dec *dec);
+
+#endif /* CWRS_H */
diff --git a/drivers/opus/celt/ecintrin.h b/drivers/opus/celt/ecintrin.h
new file mode 100644
index 0000000000..6ed8fb280e
--- /dev/null
+++ b/drivers/opus/celt/ecintrin.h
@@ -0,0 +1,87 @@
+/* Copyright (c) 2003-2008 Timothy B. Terriberry
+ Copyright (c) 2008 Xiph.Org Foundation */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*Some common macros for potential platform-specific optimization.*/
+#include "opus/opus_types.h"
+#include <math.h>
+#include <limits.h>
+#include "opus/celt/arch.h"
+#if !defined(_ecintrin_H)
+# define _ecintrin_H (1)
+
+/*Some specific platforms may have optimized intrinsic or OPUS_INLINE assembly
+ versions of these functions which can substantially improve performance.
+ We define macros for them to allow easy incorporation of these non-ANSI
+ features.*/
+
+/*Modern gcc (4.x) can compile the naive versions of min and max with cmov if
+ given an appropriate architecture, but the branchless bit-twiddling versions
+ are just as fast, and do not require any special target architecture.
+ Earlier gcc versions (3.x) compiled both code to the same assembly
+ instructions, because of the way they represented ((_b)>(_a)) internally.*/
+# define EC_MINI(_a,_b) ((_a)+(((_b)-(_a))&-((_b)<(_a))))
+
+/*Count leading zeros.
+ This macro should only be used for implementing ec_ilog(), if it is defined.
+ All other code should use EC_ILOG() instead.*/
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+# include <intrin.h>
+/*In _DEBUG mode this is not an intrinsic by default.*/
+# pragma intrinsic(_BitScanReverse)
+
+static __inline int ec_bsr(unsigned long _x){
+ unsigned long ret;
+ _BitScanReverse(&ret,_x);
+ return (int)ret;
+}
+# define EC_CLZ0 (1)
+# define EC_CLZ(_x) (-ec_bsr(_x))
+#elif defined(ENABLE_TI_DSPLIB)
+# include "dsplib.h"
+# define EC_CLZ0 (31)
+# define EC_CLZ(_x) (_lnorm(_x))
+#elif __GNUC_PREREQ(3,4)
+# if INT_MAX>=2147483647
+# define EC_CLZ0 ((int)sizeof(unsigned)*CHAR_BIT)
+# define EC_CLZ(_x) (__builtin_clz(_x))
+# elif LONG_MAX>=2147483647L
+# define EC_CLZ0 ((int)sizeof(unsigned long)*CHAR_BIT)
+# define EC_CLZ(_x) (__builtin_clzl(_x))
+# endif
+#endif
+
+#if defined(EC_CLZ)
+/*Note that __builtin_clz is not defined when _x==0, according to the gcc
+ documentation (and that of the BSR instruction that implements it on x86).
+ The majority of the time we can never pass it zero.
+ When we need to, it can be special cased.*/
+# define EC_ILOG(_x) (EC_CLZ0-EC_CLZ(_x))
+#else
+int ec_ilog(opus_uint32 _v);
+# define EC_ILOG(_x) (ec_ilog(_x))
+#endif
+#endif
diff --git a/drivers/opus/celt/entcode.c b/drivers/opus/celt/entcode.c
new file mode 100644
index 0000000000..5c9874908d
--- /dev/null
+++ b/drivers/opus/celt/entcode.c
@@ -0,0 +1,93 @@
+/* Copyright (c) 2001-2011 Timothy B. Terriberry
+*/
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/celt/entcode.h"
+#include "opus/celt/arch.h"
+
+#if !defined(EC_CLZ)
+/*This is a fallback for systems where we don't know how to access
+ a BSR or CLZ instruction (see ecintrin.h).
+ If you are optimizing Opus on a new platform and it has a native CLZ or
+ BZR (e.g. cell, MIPS, x86, etc) then making it available to Opus will be
+ an easy performance win.*/
+int ec_ilog(opus_uint32 _v){
+ /*On a Pentium M, this branchless version tested as the fastest on
+ 1,000,000,000 random 32-bit integers, edging out a similar version with
+ branches, and a 256-entry LUT version.*/
+ int ret;
+ int m;
+ ret=!!_v;
+ m=!!(_v&0xFFFF0000)<<4;
+ _v>>=m;
+ ret|=m;
+ m=!!(_v&0xFF00)<<3;
+ _v>>=m;
+ ret|=m;
+ m=!!(_v&0xF0)<<2;
+ _v>>=m;
+ ret|=m;
+ m=!!(_v&0xC)<<1;
+ _v>>=m;
+ ret|=m;
+ ret+=!!(_v&0x2);
+ return ret;
+}
+#endif
+
+opus_uint32 ec_tell_frac(ec_ctx *_this){
+ opus_uint32 nbits;
+ opus_uint32 r;
+ int l;
+ int i;
+ /*To handle the non-integral number of bits still left in the encoder/decoder
+ state, we compute the worst-case number of bits of val that must be
+ encoded to ensure that the value is inside the range for any possible
+ subsequent bits.
+ The computation here is independent of val itself (the decoder does not
+ even track that value), even though the real number of bits used after
+ ec_enc_done() may be 1 smaller if rng is a power of two and the
+ corresponding trailing bits of val are all zeros.
+ If we did try to track that special case, then coding a value with a
+ probability of 1/(1<<n) might sometimes appear to use more than n bits.
+ This may help explain the surprising result that a newly initialized
+ encoder or decoder claims to have used 1 bit.*/
+ nbits=_this->nbits_total<<BITRES;
+ l=EC_ILOG(_this->rng);
+ r=_this->rng>>(l-16);
+ for(i=BITRES;i-->0;){
+ int b;
+ r=r*r>>15;
+ b=(int)(r>>16);
+ l=l<<1|b;
+ r>>=b;
+ }
+ return nbits-l;
+}
diff --git a/drivers/opus/celt/entcode.h b/drivers/opus/celt/entcode.h
new file mode 100644
index 0000000000..c129f9b7d9
--- /dev/null
+++ b/drivers/opus/celt/entcode.h
@@ -0,0 +1,117 @@
+/* Copyright (c) 2001-2011 Timothy B. Terriberry
+ Copyright (c) 2008-2009 Xiph.Org Foundation */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "opus/opus_types.h"
+#include "opus/opus_defines.h"
+
+#if !defined(_entcode_H)
+# define _entcode_H (1)
+# include <limits.h>
+# include <stddef.h>
+# include "opus/celt/ecintrin.h"
+
+/*OPT: ec_window must be at least 32 bits, but if you have fast arithmetic on a
+ larger type, you can speed up the decoder by using it here.*/
+typedef opus_uint32 ec_window;
+typedef struct ec_ctx ec_ctx;
+typedef struct ec_ctx ec_enc;
+typedef struct ec_ctx ec_dec;
+
+# define EC_WINDOW_SIZE ((int)sizeof(ec_window)*CHAR_BIT)
+
+/*The number of bits to use for the range-coded part of unsigned integers.*/
+# define EC_UINT_BITS (8)
+
+/*The resolution of fractional-precision bit usage measurements, i.e.,
+ 3 => 1/8th bits.*/
+# define BITRES 3
+
+/*The entropy encoder/decoder context.
+ We use the same structure for both, so that common functions like ec_tell()
+ can be used on either one.*/
+struct ec_ctx{
+ /*Buffered input/output.*/
+ unsigned char *buf;
+ /*The size of the buffer.*/
+ opus_uint32 storage;
+ /*The offset at which the last byte containing raw bits was read/written.*/
+ opus_uint32 end_offs;
+ /*Bits that will be read from/written at the end.*/
+ ec_window end_window;
+ /*Number of valid bits in end_window.*/
+ int nend_bits;
+ /*The total number of whole bits read/written.
+ This does not include partial bits currently in the range coder.*/
+ int nbits_total;
+ /*The offset at which the next range coder byte will be read/written.*/
+ opus_uint32 offs;
+ /*The number of values in the current range.*/
+ opus_uint32 rng;
+ /*In the decoder: the difference between the top of the current range and
+ the input value, minus one.
+ In the encoder: the low end of the current range.*/
+ opus_uint32 val;
+ /*In the decoder: the saved normalization factor from ec_decode().
+ In the encoder: the number of oustanding carry propagating symbols.*/
+ opus_uint32 ext;
+ /*A buffered input/output symbol, awaiting carry propagation.*/
+ int rem;
+ /*Nonzero if an error occurred.*/
+ int error;
+};
+
+static OPUS_INLINE opus_uint32 ec_range_bytes(ec_ctx *_this){
+ return _this->offs;
+}
+
+static OPUS_INLINE unsigned char *ec_get_buffer(ec_ctx *_this){
+ return _this->buf;
+}
+
+static OPUS_INLINE int ec_get_error(ec_ctx *_this){
+ return _this->error;
+}
+
+/*Returns the number of bits "used" by the encoded or decoded symbols so far.
+ This same number can be computed in either the encoder or the decoder, and is
+ suitable for making coding decisions.
+ Return: The number of bits.
+ This will always be slightly larger than the exact value (e.g., all
+ rounding error is in the positive direction).*/
+static OPUS_INLINE int ec_tell(ec_ctx *_this){
+ return _this->nbits_total-EC_ILOG(_this->rng);
+}
+
+/*Returns the number of bits "used" by the encoded or decoded symbols so far.
+ This same number can be computed in either the encoder or the decoder, and is
+ suitable for making coding decisions.
+ Return: The number of bits scaled by 2**BITRES.
+ This will always be slightly larger than the exact value (e.g., all
+ rounding error is in the positive direction).*/
+opus_uint32 ec_tell_frac(ec_ctx *_this);
+
+#endif
diff --git a/drivers/opus/celt/entdec.c b/drivers/opus/celt/entdec.c
new file mode 100644
index 0000000000..0ec4d460d2
--- /dev/null
+++ b/drivers/opus/celt/entdec.c
@@ -0,0 +1,245 @@
+/* Copyright (c) 2001-2011 Timothy B. Terriberry
+ Copyright (c) 2008-2009 Xiph.Org Foundation */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include <stddef.h>
+#include "opus/celt/os_support.h"
+#include "opus/celt/arch.h"
+#include "opus/celt/entdec.h"
+#include "opus/celt/mfrngcod.h"
+
+/*A range decoder.
+ This is an entropy decoder based upon \cite{Mar79}, which is itself a
+ rediscovery of the FIFO arithmetic code introduced by \cite{Pas76}.
+ It is very similar to arithmetic encoding, except that encoding is done with
+ digits in any base, instead of with bits, and so it is faster when using
+ larger bases (i.e.: a byte).
+ The author claims an average waste of $\frac{1}{2}\log_b(2b)$ bits, where $b$
+ is the base, longer than the theoretical optimum, but to my knowledge there
+ is no published justification for this claim.
+ This only seems true when using near-infinite precision arithmetic so that
+ the process is carried out with no rounding errors.
+
+ An excellent description of implementation details is available at
+ http://www.arturocampos.com/ac_range.html
+ A recent work \cite{MNW98} which proposes several changes to arithmetic
+ encoding for efficiency actually re-discovers many of the principles
+ behind range encoding, and presents a good theoretical analysis of them.
+
+ End of stream is handled by writing out the smallest number of bits that
+ ensures that the stream will be correctly decoded regardless of the value of
+ any subsequent bits.
+ ec_tell() can be used to determine how many bits were needed to decode
+ all the symbols thus far; other data can be packed in the remaining bits of
+ the input buffer.
+ @PHDTHESIS{Pas76,
+ author="Richard Clark Pasco",
+ title="Source coding algorithms for fast data compression",
+ school="Dept. of Electrical Engineering, Stanford University",
+ address="Stanford, CA",
+ month=May,
+ year=1976
+ }
+ @INPROCEEDINGS{Mar79,
+ author="Martin, G.N.N.",
+ title="Range encoding: an algorithm for removing redundancy from a digitised
+ message",
+ booktitle="Video & Data Recording Conference",
+ year=1979,
+ address="Southampton",
+ month=Jul
+ }
+ @ARTICLE{MNW98,
+ author="Alistair Moffat and Radford Neal and Ian H. Witten",
+ title="Arithmetic Coding Revisited",
+ journal="{ACM} Transactions on Information Systems",
+ year=1998,
+ volume=16,
+ number=3,
+ pages="256--294",
+ month=Jul,
+ URL="http://www.stanford.edu/class/ee398a/handouts/papers/Moffat98ArithmCoding.pdf"
+ }*/
+
+static int ec_read_byte(ec_dec *_this){
+ return _this->offs<_this->storage?_this->buf[_this->offs++]:0;
+}
+
+static int ec_read_byte_from_end(ec_dec *_this){
+ return _this->end_offs<_this->storage?
+ _this->buf[_this->storage-++(_this->end_offs)]:0;
+}
+
+/*Normalizes the contents of val and rng so that rng lies entirely in the
+ high-order symbol.*/
+static void ec_dec_normalize(ec_dec *_this){
+ /*If the range is too small, rescale it and input some bits.*/
+ while(_this->rng<=EC_CODE_BOT){
+ int sym;
+ _this->nbits_total+=EC_SYM_BITS;
+ _this->rng<<=EC_SYM_BITS;
+ /*Use up the remaining bits from our last symbol.*/
+ sym=_this->rem;
+ /*Read the next value from the input.*/
+ _this->rem=ec_read_byte(_this);
+ /*Take the rest of the bits we need from this new symbol.*/
+ sym=(sym<<EC_SYM_BITS|_this->rem)>>(EC_SYM_BITS-EC_CODE_EXTRA);
+ /*And subtract them from val, capped to be less than EC_CODE_TOP.*/
+ _this->val=((_this->val<<EC_SYM_BITS)+(EC_SYM_MAX&~sym))&(EC_CODE_TOP-1);
+ }
+}
+
+void ec_dec_init(ec_dec *_this,unsigned char *_buf,opus_uint32 _storage){
+ _this->buf=_buf;
+ _this->storage=_storage;
+ _this->end_offs=0;
+ _this->end_window=0;
+ _this->nend_bits=0;
+ /*This is the offset from which ec_tell() will subtract partial bits.
+ The final value after the ec_dec_normalize() call will be the same as in
+ the encoder, but we have to compensate for the bits that are added there.*/
+ _this->nbits_total=EC_CODE_BITS+1
+ -((EC_CODE_BITS-EC_CODE_EXTRA)/EC_SYM_BITS)*EC_SYM_BITS;
+ _this->offs=0;
+ _this->rng=1U<<EC_CODE_EXTRA;
+ _this->rem=ec_read_byte(_this);
+ _this->val=_this->rng-1-(_this->rem>>(EC_SYM_BITS-EC_CODE_EXTRA));
+ _this->error=0;
+ /*Normalize the interval.*/
+ ec_dec_normalize(_this);
+}
+
+unsigned ec_decode(ec_dec *_this,unsigned _ft){
+ unsigned s;
+ _this->ext=_this->rng/_ft;
+ s=(unsigned)(_this->val/_this->ext);
+ return _ft-EC_MINI(s+1,_ft);
+}
+
+unsigned ec_decode_bin(ec_dec *_this,unsigned _bits){
+ unsigned s;
+ _this->ext=_this->rng>>_bits;
+ s=(unsigned)(_this->val/_this->ext);
+ return (1U<<_bits)-EC_MINI(s+1U,1U<<_bits);
+}
+
+void ec_dec_update(ec_dec *_this,unsigned _fl,unsigned _fh,unsigned _ft){
+ opus_uint32 s;
+ s=IMUL32(_this->ext,_ft-_fh);
+ _this->val-=s;
+ _this->rng=_fl>0?IMUL32(_this->ext,_fh-_fl):_this->rng-s;
+ ec_dec_normalize(_this);
+}
+
+/*The probability of having a "one" is 1/(1<<_logp).*/
+int ec_dec_bit_logp(ec_dec *_this,unsigned _logp){
+ opus_uint32 r;
+ opus_uint32 d;
+ opus_uint32 s;
+ int ret;
+ r=_this->rng;
+ d=_this->val;
+ s=r>>_logp;
+ ret=d<s;
+ if(!ret)_this->val=d-s;
+ _this->rng=ret?s:r-s;
+ ec_dec_normalize(_this);
+ return ret;
+}
+
+int ec_dec_icdf(ec_dec *_this,const unsigned char *_icdf,unsigned _ftb){
+ opus_uint32 r;
+ opus_uint32 d;
+ opus_uint32 s;
+ opus_uint32 t;
+ int ret;
+ s=_this->rng;
+ d=_this->val;
+ r=s>>_ftb;
+ ret=-1;
+ do{
+ t=s;
+ s=IMUL32(r,_icdf[++ret]);
+ }
+ while(d<s);
+ _this->val=d-s;
+ _this->rng=t-s;
+ ec_dec_normalize(_this);
+ return ret;
+}
+
+opus_uint32 ec_dec_uint(ec_dec *_this,opus_uint32 _ft){
+ unsigned ft;
+ unsigned s;
+ int ftb;
+ /*In order to optimize EC_ILOG(), it is undefined for the value 0.*/
+ celt_assert(_ft>1);
+ _ft--;
+ ftb=EC_ILOG(_ft);
+ if(ftb>EC_UINT_BITS){
+ opus_uint32 t;
+ ftb-=EC_UINT_BITS;
+ ft=(unsigned)(_ft>>ftb)+1;
+ s=ec_decode(_this,ft);
+ ec_dec_update(_this,s,s+1,ft);
+ t=(opus_uint32)s<<ftb|ec_dec_bits(_this,ftb);
+ if(t<=_ft)return t;
+ _this->error=1;
+ return _ft;
+ }
+ else{
+ _ft++;
+ s=ec_decode(_this,(unsigned)_ft);
+ ec_dec_update(_this,s,s+1,(unsigned)_ft);
+ return s;
+ }
+}
+
+opus_uint32 ec_dec_bits(ec_dec *_this,unsigned _bits){
+ ec_window window;
+ int available;
+ opus_uint32 ret;
+ window=_this->end_window;
+ available=_this->nend_bits;
+ if((unsigned)available<_bits){
+ do{
+ window|=(ec_window)ec_read_byte_from_end(_this)<<available;
+ available+=EC_SYM_BITS;
+ }
+ while(available<=EC_WINDOW_SIZE-EC_SYM_BITS);
+ }
+ ret=(opus_uint32)window&(((opus_uint32)1<<_bits)-1U);
+ window>>=_bits;
+ available-=_bits;
+ _this->end_window=window;
+ _this->nend_bits=available;
+ _this->nbits_total+=_bits;
+ return ret;
+}
diff --git a/drivers/opus/celt/entdec.h b/drivers/opus/celt/entdec.h
new file mode 100644
index 0000000000..fda60ab326
--- /dev/null
+++ b/drivers/opus/celt/entdec.h
@@ -0,0 +1,100 @@
+/* Copyright (c) 2001-2011 Timothy B. Terriberry
+ Copyright (c) 2008-2009 Xiph.Org Foundation */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if !defined(_entdec_H)
+# define _entdec_H (1)
+# include <limits.h>
+# include "opus/celt/entcode.h"
+
+/*Initializes the decoder.
+ _buf: The input buffer to use.
+ Return: 0 on success, or a negative value on error.*/
+void ec_dec_init(ec_dec *_this,unsigned char *_buf,opus_uint32 _storage);
+
+/*Calculates the cumulative frequency for the next symbol.
+ This can then be fed into the probability model to determine what that
+ symbol is, and the additional frequency information required to advance to
+ the next symbol.
+ This function cannot be called more than once without a corresponding call to
+ ec_dec_update(), or decoding will not proceed correctly.
+ _ft: The total frequency of the symbols in the alphabet the next symbol was
+ encoded with.
+ Return: A cumulative frequency representing the encoded symbol.
+ If the cumulative frequency of all the symbols before the one that
+ was encoded was fl, and the cumulative frequency of all the symbols
+ up to and including the one encoded is fh, then the returned value
+ will fall in the range [fl,fh).*/
+unsigned ec_decode(ec_dec *_this,unsigned _ft);
+
+/*Equivalent to ec_decode() with _ft==1<<_bits.*/
+unsigned ec_decode_bin(ec_dec *_this,unsigned _bits);
+
+/*Advance the decoder past the next symbol using the frequency information the
+ symbol was encoded with.
+ Exactly one call to ec_decode() must have been made so that all necessary
+ intermediate calculations are performed.
+ _fl: The cumulative frequency of all symbols that come before the symbol
+ decoded.
+ _fh: The cumulative frequency of all symbols up to and including the symbol
+ decoded.
+ Together with _fl, this defines the range [_fl,_fh) in which the value
+ returned above must fall.
+ _ft: The total frequency of the symbols in the alphabet the symbol decoded
+ was encoded in.
+ This must be the same as passed to the preceding call to ec_decode().*/
+void ec_dec_update(ec_dec *_this,unsigned _fl,unsigned _fh,unsigned _ft);
+
+/* Decode a bit that has a 1/(1<<_logp) probability of being a one */
+int ec_dec_bit_logp(ec_dec *_this,unsigned _logp);
+
+/*Decodes a symbol given an "inverse" CDF table.
+ No call to ec_dec_update() is necessary after this call.
+ _icdf: The "inverse" CDF, such that symbol s falls in the range
+ [s>0?ft-_icdf[s-1]:0,ft-_icdf[s]), where ft=1<<_ftb.
+ The values must be monotonically non-increasing, and the last value
+ must be 0.
+ _ftb: The number of bits of precision in the cumulative distribution.
+ Return: The decoded symbol s.*/
+int ec_dec_icdf(ec_dec *_this,const unsigned char *_icdf,unsigned _ftb);
+
+/*Extracts a raw unsigned integer with a non-power-of-2 range from the stream.
+ The bits must have been encoded with ec_enc_uint().
+ No call to ec_dec_update() is necessary after this call.
+ _ft: The number of integers that can be decoded (one more than the max).
+ This must be at least one, and no more than 2**32-1.
+ Return: The decoded bits.*/
+opus_uint32 ec_dec_uint(ec_dec *_this,opus_uint32 _ft);
+
+/*Extracts a sequence of raw bits from the stream.
+ The bits must have been encoded with ec_enc_bits().
+ No call to ec_dec_update() is necessary after this call.
+ _ftb: The number of bits to extract.
+ This must be between 0 and 25, inclusive.
+ Return: The decoded bits.*/
+opus_uint32 ec_dec_bits(ec_dec *_this,unsigned _ftb);
+
+#endif
diff --git a/drivers/opus/celt/entenc.c b/drivers/opus/celt/entenc.c
new file mode 100644
index 0000000000..085b2b2816
--- /dev/null
+++ b/drivers/opus/celt/entenc.c
@@ -0,0 +1,294 @@
+/* Copyright (c) 2001-2011 Timothy B. Terriberry
+ Copyright (c) 2008-2009 Xiph.Org Foundation */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if defined(OPUS_ENABLED)
+# include "opus/opus_config.h"
+#endif
+#include "opus/celt/os_support.h"
+#include "opus/celt/arch.h"
+#include "opus/celt/entenc.h"
+#include "opus/celt/mfrngcod.h"
+
+/*A range encoder.
+ See entdec.c and the references for implementation details \cite{Mar79,MNW98}.
+
+ @INPROCEEDINGS{Mar79,
+ author="Martin, G.N.N.",
+ title="Range encoding: an algorithm for removing redundancy from a digitised
+ message",
+ booktitle="Video \& Data Recording Conference",
+ year=1979,
+ address="Southampton",
+ month=Jul
+ }
+ @ARTICLE{MNW98,
+ author="Alistair Moffat and Radford Neal and Ian H. Witten",
+ title="Arithmetic Coding Revisited",
+ journal="{ACM} Transactions on Information Systems",
+ year=1998,
+ volume=16,
+ number=3,
+ pages="256--294",
+ month=Jul,
+ URL="http://www.stanford.edu/class/ee398/handouts/papers/Moffat98ArithmCoding.pdf"
+ }*/
+
+static int ec_write_byte(ec_enc *_this,unsigned _value){
+ if(_this->offs+_this->end_offs>=_this->storage)return -1;
+ _this->buf[_this->offs++]=(unsigned char)_value;
+ return 0;
+}
+
+static int ec_write_byte_at_end(ec_enc *_this,unsigned _value){
+ if(_this->offs+_this->end_offs>=_this->storage)return -1;
+ _this->buf[_this->storage-++(_this->end_offs)]=(unsigned char)_value;
+ return 0;
+}
+
+/*Outputs a symbol, with a carry bit.
+ If there is a potential to propagate a carry over several symbols, they are
+ buffered until it can be determined whether or not an actual carry will
+ occur.
+ If the counter for the buffered symbols overflows, then the stream becomes
+ undecodable.
+ This gives a theoretical limit of a few billion symbols in a single packet on
+ 32-bit systems.
+ The alternative is to truncate the range in order to force a carry, but
+ requires similar carry tracking in the decoder, needlessly slowing it down.*/
+static void ec_enc_carry_out(ec_enc *_this,int _c){
+ if(_c!=EC_SYM_MAX){
+ /*No further carry propagation possible, flush buffer.*/
+ int carry;
+ carry=_c>>EC_SYM_BITS;
+ /*Don't output a byte on the first write.
+ This compare should be taken care of by branch-prediction thereafter.*/
+ if(_this->rem>=0)_this->error|=ec_write_byte(_this,_this->rem+carry);
+ if(_this->ext>0){
+ unsigned sym;
+ sym=(EC_SYM_MAX+carry)&EC_SYM_MAX;
+ do _this->error|=ec_write_byte(_this,sym);
+ while(--(_this->ext)>0);
+ }
+ _this->rem=_c&EC_SYM_MAX;
+ }
+ else _this->ext++;
+}
+
+static void ec_enc_normalize(ec_enc *_this){
+ /*If the range is too small, output some bits and rescale it.*/
+ while(_this->rng<=EC_CODE_BOT){
+ ec_enc_carry_out(_this,(int)(_this->val>>EC_CODE_SHIFT));
+ /*Move the next-to-high-order symbol into the high-order position.*/
+ _this->val=(_this->val<<EC_SYM_BITS)&(EC_CODE_TOP-1);
+ _this->rng<<=EC_SYM_BITS;
+ _this->nbits_total+=EC_SYM_BITS;
+ }
+}
+
+void ec_enc_init(ec_enc *_this,unsigned char *_buf,opus_uint32 _size){
+ _this->buf=_buf;
+ _this->end_offs=0;
+ _this->end_window=0;
+ _this->nend_bits=0;
+ /*This is the offset from which ec_tell() will subtract partial bits.*/
+ _this->nbits_total=EC_CODE_BITS+1;
+ _this->offs=0;
+ _this->rng=EC_CODE_TOP;
+ _this->rem=-1;
+ _this->val=0;
+ _this->ext=0;
+ _this->storage=_size;
+ _this->error=0;
+}
+
+void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft){
+ opus_uint32 r;
+ r=_this->rng/_ft;
+ if(_fl>0){
+ _this->val+=_this->rng-IMUL32(r,(_ft-_fl));
+ _this->rng=IMUL32(r,(_fh-_fl));
+ }
+ else _this->rng-=IMUL32(r,(_ft-_fh));
+ ec_enc_normalize(_this);
+}
+
+void ec_encode_bin(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _bits){
+ opus_uint32 r;
+ r=_this->rng>>_bits;
+ if(_fl>0){
+ _this->val+=_this->rng-IMUL32(r,((1U<<_bits)-_fl));
+ _this->rng=IMUL32(r,(_fh-_fl));
+ }
+ else _this->rng-=IMUL32(r,((1U<<_bits)-_fh));
+ ec_enc_normalize(_this);
+}
+
+/*The probability of having a "one" is 1/(1<<_logp).*/
+void ec_enc_bit_logp(ec_enc *_this,int _val,unsigned _logp){
+ opus_uint32 r;
+ opus_uint32 s;
+ opus_uint32 l;
+ r=_this->rng;
+ l=_this->val;
+ s=r>>_logp;
+ r-=s;
+ if(_val)_this->val=l+r;
+ _this->rng=_val?s:r;
+ ec_enc_normalize(_this);
+}
+
+void ec_enc_icdf(ec_enc *_this,int _s,const unsigned char *_icdf,unsigned _ftb){
+ opus_uint32 r;
+ r=_this->rng>>_ftb;
+ if(_s>0){
+ _this->val+=_this->rng-IMUL32(r,_icdf[_s-1]);
+ _this->rng=IMUL32(r,_icdf[_s-1]-_icdf[_s]);
+ }
+ else _this->rng-=IMUL32(r,_icdf[_s]);
+ ec_enc_normalize(_this);
+}
+
+void ec_enc_uint(ec_enc *_this,opus_uint32 _fl,opus_uint32 _ft){
+ unsigned ft;
+ unsigned fl;
+ int ftb;
+ /*In order to optimize EC_ILOG(), it is undefined for the value 0.*/
+ celt_assert(_ft>1);
+ _ft--;
+ ftb=EC_ILOG(_ft);
+ if(ftb>EC_UINT_BITS){
+ ftb-=EC_UINT_BITS;
+ ft=(_ft>>ftb)+1;
+ fl=(unsigned)(_fl>>ftb);
+ ec_encode(_this,fl,fl+1,ft);
+ ec_enc_bits(_this,_fl&(((opus_uint32)1<<ftb)-1U),ftb);
+ }
+ else ec_encode(_this,_fl,_fl+1,_ft+1);
+}
+
+void ec_enc_bits(ec_enc *_this,opus_uint32 _fl,unsigned _bits){
+ ec_window window;
+ int used;
+ window=_this->end_window;
+ used=_this->nend_bits;
+ celt_assert(_bits>0);
+ if(used+_bits>EC_WINDOW_SIZE){
+ do{
+ _this->error|=ec_write_byte_at_end(_this,(unsigned)window&EC_SYM_MAX);
+ window>>=EC_SYM_BITS;
+ used-=EC_SYM_BITS;
+ }
+ while(used>=EC_SYM_BITS);
+ }
+ window|=(ec_window)_fl<<used;
+ used+=_bits;
+ _this->end_window=window;
+ _this->nend_bits=used;
+ _this->nbits_total+=_bits;
+}
+
+void ec_enc_patch_initial_bits(ec_enc *_this,unsigned _val,unsigned _nbits){
+ int shift;
+ unsigned mask;
+ celt_assert(_nbits<=EC_SYM_BITS);
+ shift=EC_SYM_BITS-_nbits;
+ mask=((1<<_nbits)-1)<<shift;
+ if(_this->offs>0){
+ /*The first byte has been finalized.*/
+ _this->buf[0]=(unsigned char)((_this->buf[0]&~mask)|_val<<shift);
+ }
+ else if(_this->rem>=0){
+ /*The first byte is still awaiting carry propagation.*/
+ _this->rem=(_this->rem&~mask)|_val<<shift;
+ }
+ else if(_this->rng<=(EC_CODE_TOP>>_nbits)){
+ /*The renormalization loop has never been run.*/
+ _this->val=(_this->val&~((opus_uint32)mask<<EC_CODE_SHIFT))|
+ (opus_uint32)_val<<(EC_CODE_SHIFT+shift);
+ }
+ /*The encoder hasn't even encoded _nbits of data yet.*/
+ else _this->error=-1;
+}
+
+void ec_enc_shrink(ec_enc *_this,opus_uint32 _size){
+ celt_assert(_this->offs+_this->end_offs<=_size);
+ OPUS_MOVE(_this->buf+_size-_this->end_offs,
+ _this->buf+_this->storage-_this->end_offs,_this->end_offs);
+ _this->storage=_size;
+}
+
+void ec_enc_done(ec_enc *_this){
+ ec_window window;
+ int used;
+ opus_uint32 msk;
+ opus_uint32 end;
+ int l;
+ /*We output the minimum number of bits that ensures that the symbols encoded
+ thus far will be decoded correctly regardless of the bits that follow.*/
+ l=EC_CODE_BITS-EC_ILOG(_this->rng);
+ msk=(EC_CODE_TOP-1)>>l;
+ end=(_this->val+msk)&~msk;
+ if((end|msk)>=_this->val+_this->rng){
+ l++;
+ msk>>=1;
+ end=(_this->val+msk)&~msk;
+ }
+ while(l>0){
+ ec_enc_carry_out(_this,(int)(end>>EC_CODE_SHIFT));
+ end=(end<<EC_SYM_BITS)&(EC_CODE_TOP-1);
+ l-=EC_SYM_BITS;
+ }
+ /*If we have a buffered byte flush it into the output buffer.*/
+ if(_this->rem>=0||_this->ext>0)ec_enc_carry_out(_this,0);
+ /*If we have buffered extra bits, flush them as well.*/
+ window=_this->end_window;
+ used=_this->nend_bits;
+ while(used>=EC_SYM_BITS){
+ _this->error|=ec_write_byte_at_end(_this,(unsigned)window&EC_SYM_MAX);
+ window>>=EC_SYM_BITS;
+ used-=EC_SYM_BITS;
+ }
+ /*Clear any excess space and add any remaining extra bits to the last byte.*/
+ if(!_this->error){
+ OPUS_CLEAR(_this->buf+_this->offs,
+ _this->storage-_this->offs-_this->end_offs);
+ if(used>0){
+ /*If there's no range coder data at all, give up.*/
+ if(_this->end_offs>=_this->storage)_this->error=-1;
+ else{
+ l=-l;
+ /*If we've busted, don't add too many extra bits to the last byte; it
+ would corrupt the range coder data, and that's more important.*/
+ if(_this->offs+_this->end_offs>=_this->storage&&l<used){
+ window&=(1<<l)-1;
+ _this->error=-1;
+ }
+ _this->buf[_this->storage-_this->end_offs-1]|=(unsigned char)window;
+ }
+ }
+ }
+}
diff --git a/drivers/opus/celt/entenc.h b/drivers/opus/celt/entenc.h
new file mode 100644
index 0000000000..3f4a3acc93
--- /dev/null
+++ b/drivers/opus/celt/entenc.h
@@ -0,0 +1,110 @@
+/* Copyright (c) 2001-2011 Timothy B. Terriberry
+ Copyright (c) 2008-2009 Xiph.Org Foundation */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if !defined(_entenc_H)
+# define _entenc_H (1)
+# include <stddef.h>
+# include "opus/celt/entcode.h"
+
+/*Initializes the encoder.
+ _buf: The buffer to store output bytes in.
+ _size: The size of the buffer, in chars.*/
+void ec_enc_init(ec_enc *_this,unsigned char *_buf,opus_uint32 _size);
+/*Encodes a symbol given its frequency information.
+ The frequency information must be discernable by the decoder, assuming it
+ has read only the previous symbols from the stream.
+ It is allowable to change the frequency information, or even the entire
+ source alphabet, so long as the decoder can tell from the context of the
+ previously encoded information that it is supposed to do so as well.
+ _fl: The cumulative frequency of all symbols that come before the one to be
+ encoded.
+ _fh: The cumulative frequency of all symbols up to and including the one to
+ be encoded.
+ Together with _fl, this defines the range [_fl,_fh) in which the
+ decoded value will fall.
+ _ft: The sum of the frequencies of all the symbols*/
+void ec_encode(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _ft);
+
+/*Equivalent to ec_encode() with _ft==1<<_bits.*/
+void ec_encode_bin(ec_enc *_this,unsigned _fl,unsigned _fh,unsigned _bits);
+
+/* Encode a bit that has a 1/(1<<_logp) probability of being a one */
+void ec_enc_bit_logp(ec_enc *_this,int _val,unsigned _logp);
+
+/*Encodes a symbol given an "inverse" CDF table.
+ _s: The index of the symbol to encode.
+ _icdf: The "inverse" CDF, such that symbol _s falls in the range
+ [_s>0?ft-_icdf[_s-1]:0,ft-_icdf[_s]), where ft=1<<_ftb.
+ The values must be monotonically non-increasing, and the last value
+ must be 0.
+ _ftb: The number of bits of precision in the cumulative distribution.*/
+void ec_enc_icdf(ec_enc *_this,int _s,const unsigned char *_icdf,unsigned _ftb);
+
+/*Encodes a raw unsigned integer in the stream.
+ _fl: The integer to encode.
+ _ft: The number of integers that can be encoded (one more than the max).
+ This must be at least one, and no more than 2**32-1.*/
+void ec_enc_uint(ec_enc *_this,opus_uint32 _fl,opus_uint32 _ft);
+
+/*Encodes a sequence of raw bits in the stream.
+ _fl: The bits to encode.
+ _ftb: The number of bits to encode.
+ This must be between 1 and 25, inclusive.*/
+void ec_enc_bits(ec_enc *_this,opus_uint32 _fl,unsigned _ftb);
+
+/*Overwrites a few bits at the very start of an existing stream, after they
+ have already been encoded.
+ This makes it possible to have a few flags up front, where it is easy for
+ decoders to access them without parsing the whole stream, even if their
+ values are not determined until late in the encoding process, without having
+ to buffer all the intermediate symbols in the encoder.
+ In order for this to work, at least _nbits bits must have already been
+ encoded using probabilities that are an exact power of two.
+ The encoder can verify the number of encoded bits is sufficient, but cannot
+ check this latter condition.
+ _val: The bits to encode (in the least _nbits significant bits).
+ They will be decoded in order from most-significant to least.
+ _nbits: The number of bits to overwrite.
+ This must be no more than 8.*/
+void ec_enc_patch_initial_bits(ec_enc *_this,unsigned _val,unsigned _nbits);
+
+/*Compacts the data to fit in the target size.
+ This moves up the raw bits at the end of the current buffer so they are at
+ the end of the new buffer size.
+ The caller must ensure that the amount of data that's already been written
+ will fit in the new size.
+ _size: The number of bytes in the new buffer.
+ This must be large enough to contain the bits already written, and
+ must be no larger than the existing size.*/
+void ec_enc_shrink(ec_enc *_this,opus_uint32 _size);
+
+/*Indicates that there are no more symbols to encode.
+ All reamining output bytes are flushed to the output buffer.
+ ec_enc_init() must be called before the encoder can be used again.*/
+void ec_enc_done(ec_enc *_this);
+
+#endif
diff --git a/drivers/opus/celt/fixed_debug.h b/drivers/opus/celt/fixed_debug.h
new file mode 100644
index 0000000000..0ed16baa17
--- /dev/null
+++ b/drivers/opus/celt/fixed_debug.h
@@ -0,0 +1,773 @@
+/* Copyright (C) 2003-2008 Jean-Marc Valin
+ Copyright (C) 2007-2012 Xiph.Org Foundation */
+/**
+ @file fixed_debug.h
+ @brief Fixed-point operations with debugging
+*/
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef FIXED_DEBUG_H
+#define FIXED_DEBUG_H
+
+#include <stdio.h>
+#include "opus/opus_defines.h"
+
+#ifdef CELT_C
+OPUS_EXPORT opus_int64 celt_mips=0;
+#else
+extern opus_int64 celt_mips;
+#endif
+
+#define MULT16_16SU(a,b) ((opus_val32)(opus_val16)(a)*(opus_val32)(opus_uint16)(b))
+#define MULT32_32_Q31(a,b) ADD32(ADD32(SHL32(MULT16_16(SHR32((a),16),SHR((b),16)),1), SHR32(MULT16_16SU(SHR32((a),16),((b)&0x0000ffff)),15)), SHR32(MULT16_16SU(SHR32((b),16),((a)&0x0000ffff)),15))
+
+/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */
+#define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR32((b),16)), SHR32(MULT16_16SU((a),((b)&0x0000ffff)),16))
+
+#define MULT16_32_P16(a,b) MULT16_32_PX(a,b,16)
+
+#define QCONST16(x,bits) ((opus_val16)(.5+(x)*(((opus_val32)1)<<(bits))))
+#define QCONST32(x,bits) ((opus_val32)(.5+(x)*(((opus_val32)1)<<(bits))))
+
+#define VERIFY_SHORT(x) ((x)<=32767&&(x)>=-32768)
+#define VERIFY_INT(x) ((x)<=2147483647LL&&(x)>=-2147483648LL)
+#define VERIFY_UINT(x) ((x)<=(2147483647LLU<<1))
+
+#define SHR(a,b) SHR32(a,b)
+#define PSHR(a,b) PSHR32(a,b)
+
+static OPUS_INLINE short NEG16(int x)
+{
+ int res;
+ if (!VERIFY_SHORT(x))
+ {
+ fprintf (stderr, "NEG16: input is not short: %d\n", (int)x);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = -x;
+ if (!VERIFY_SHORT(res))
+ {
+ fprintf (stderr, "NEG16: output is not short: %d\n", (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips++;
+ return res;
+}
+static OPUS_INLINE int NEG32(opus_int64 x)
+{
+ opus_int64 res;
+ if (!VERIFY_INT(x))
+ {
+ fprintf (stderr, "NEG16: input is not int: %d\n", (int)x);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = -x;
+ if (!VERIFY_INT(res))
+ {
+ fprintf (stderr, "NEG16: output is not int: %d\n", (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=2;
+ return res;
+}
+
+#define EXTRACT16(x) EXTRACT16_(x, __FILE__, __LINE__)
+static OPUS_INLINE short EXTRACT16_(int x, char *file, int line)
+{
+ int res;
+ if (!VERIFY_SHORT(x))
+ {
+ fprintf (stderr, "EXTRACT16: input is not short: %d in %s: line %d\n", x, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = x;
+ celt_mips++;
+ return res;
+}
+
+#define EXTEND32(x) EXTEND32_(x, __FILE__, __LINE__)
+static OPUS_INLINE int EXTEND32_(int x, char *file, int line)
+{
+ int res;
+ if (!VERIFY_SHORT(x))
+ {
+ fprintf (stderr, "EXTEND32: input is not short: %d in %s: line %d\n", x, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = x;
+ celt_mips++;
+ return res;
+}
+
+#define SHR16(a, shift) SHR16_(a, shift, __FILE__, __LINE__)
+static OPUS_INLINE short SHR16_(int a, int shift, char *file, int line)
+{
+ int res;
+ if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift))
+ {
+ fprintf (stderr, "SHR16: inputs are not short: %d >> %d in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = a>>shift;
+ if (!VERIFY_SHORT(res))
+ {
+ fprintf (stderr, "SHR16: output is not short: %d in %s: line %d\n", res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips++;
+ return res;
+}
+#define SHL16(a, shift) SHL16_(a, shift, __FILE__, __LINE__)
+static OPUS_INLINE short SHL16_(int a, int shift, char *file, int line)
+{
+ int res;
+ if (!VERIFY_SHORT(a) || !VERIFY_SHORT(shift))
+ {
+ fprintf (stderr, "SHL16: inputs are not short: %d %d in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = a<<shift;
+ if (!VERIFY_SHORT(res))
+ {
+ fprintf (stderr, "SHL16: output is not short: %d in %s: line %d\n", res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips++;
+ return res;
+}
+
+static OPUS_INLINE int SHR32(opus_int64 a, int shift)
+{
+ opus_int64 res;
+ if (!VERIFY_INT(a) || !VERIFY_SHORT(shift))
+ {
+ fprintf (stderr, "SHR32: inputs are not int: %d %d\n", (int)a, shift);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = a>>shift;
+ if (!VERIFY_INT(res))
+ {
+ fprintf (stderr, "SHR32: output is not int: %d\n", (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=2;
+ return res;
+}
+#define SHL32(a, shift) SHL32_(a, shift, __FILE__, __LINE__)
+static OPUS_INLINE int SHL32_(opus_int64 a, int shift, char *file, int line)
+{
+ opus_int64 res;
+ if (!VERIFY_INT(a) || !VERIFY_SHORT(shift))
+ {
+ fprintf (stderr, "SHL32: inputs are not int: %lld %d in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = a<<shift;
+ if (!VERIFY_INT(res))
+ {
+ fprintf (stderr, "SHL32: output is not int: %lld<<%d = %lld in %s: line %d\n", a, shift, res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=2;
+ return res;
+}
+
+#define PSHR32(a,shift) (celt_mips--,SHR32(ADD32((a),(((opus_val32)(1)<<((shift))>>1))),shift))
+#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift)))
+
+#define ROUND16(x,a) (celt_mips--,EXTRACT16(PSHR32((x),(a))))
+#define HALF16(x) (SHR16(x,1))
+#define HALF32(x) (SHR32(x,1))
+
+//#define SHR(a,shift) ((a) >> (shift))
+//#define SHL(a,shift) ((a) << (shift))
+
+#define ADD16(a, b) ADD16_(a, b, __FILE__, __LINE__)
+static OPUS_INLINE short ADD16_(int a, int b, char *file, int line)
+{
+ int res;
+ if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+ {
+ fprintf (stderr, "ADD16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = a+b;
+ if (!VERIFY_SHORT(res))
+ {
+ fprintf (stderr, "ADD16: output is not short: %d+%d=%d in %s: line %d\n", a,b,res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips++;
+ return res;
+}
+
+#define SUB16(a, b) SUB16_(a, b, __FILE__, __LINE__)
+static OPUS_INLINE short SUB16_(int a, int b, char *file, int line)
+{
+ int res;
+ if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+ {
+ fprintf (stderr, "SUB16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = a-b;
+ if (!VERIFY_SHORT(res))
+ {
+ fprintf (stderr, "SUB16: output is not short: %d in %s: line %d\n", res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips++;
+ return res;
+}
+
+#define ADD32(a, b) ADD32_(a, b, __FILE__, __LINE__)
+static OPUS_INLINE int ADD32_(opus_int64 a, opus_int64 b, char *file, int line)
+{
+ opus_int64 res;
+ if (!VERIFY_INT(a) || !VERIFY_INT(b))
+ {
+ fprintf (stderr, "ADD32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = a+b;
+ if (!VERIFY_INT(res))
+ {
+ fprintf (stderr, "ADD32: output is not int: %d in %s: line %d\n", (int)res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=2;
+ return res;
+}
+
+#define SUB32(a, b) SUB32_(a, b, __FILE__, __LINE__)
+static OPUS_INLINE int SUB32_(opus_int64 a, opus_int64 b, char *file, int line)
+{
+ opus_int64 res;
+ if (!VERIFY_INT(a) || !VERIFY_INT(b))
+ {
+ fprintf (stderr, "SUB32: inputs are not int: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = a-b;
+ if (!VERIFY_INT(res))
+ {
+ fprintf (stderr, "SUB32: output is not int: %d in %s: line %d\n", (int)res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=2;
+ return res;
+}
+
+#undef UADD32
+#define UADD32(a, b) UADD32_(a, b, __FILE__, __LINE__)
+static OPUS_INLINE unsigned int UADD32_(opus_uint64 a, opus_uint64 b, char *file, int line)
+{
+ opus_uint64 res;
+ if (!VERIFY_UINT(a) || !VERIFY_UINT(b))
+ {
+ fprintf (stderr, "UADD32: inputs are not uint32: %llu %llu in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = a+b;
+ if (!VERIFY_UINT(res))
+ {
+ fprintf (stderr, "UADD32: output is not uint32: %llu in %s: line %d\n", res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=2;
+ return res;
+}
+
+#undef USUB32
+#define USUB32(a, b) USUB32_(a, b, __FILE__, __LINE__)
+static OPUS_INLINE unsigned int USUB32_(opus_uint64 a, opus_uint64 b, char *file, int line)
+{
+ opus_uint64 res;
+ if (!VERIFY_UINT(a) || !VERIFY_UINT(b))
+ {
+ fprintf (stderr, "USUB32: inputs are not uint32: %llu %llu in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ if (a<b)
+ {
+ fprintf (stderr, "USUB32: inputs underflow: %llu < %llu in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = a-b;
+ if (!VERIFY_UINT(res))
+ {
+ fprintf (stderr, "USUB32: output is not uint32: %llu - %llu = %llu in %s: line %d\n", a, b, res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=2;
+ return res;
+}
+
+/* result fits in 16 bits */
+static OPUS_INLINE short MULT16_16_16(int a, int b)
+{
+ int res;
+ if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+ {
+ fprintf (stderr, "MULT16_16_16: inputs are not short: %d %d\n", a, b);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = a*b;
+ if (!VERIFY_SHORT(res))
+ {
+ fprintf (stderr, "MULT16_16_16: output is not short: %d\n", res);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips++;
+ return res;
+}
+
+#define MULT16_16(a, b) MULT16_16_(a, b, __FILE__, __LINE__)
+static OPUS_INLINE int MULT16_16_(int a, int b, char *file, int line)
+{
+ opus_int64 res;
+ if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+ {
+ fprintf (stderr, "MULT16_16: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = ((opus_int64)a)*b;
+ if (!VERIFY_INT(res))
+ {
+ fprintf (stderr, "MULT16_16: output is not int: %d in %s: line %d\n", (int)res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips++;
+ return res;
+}
+
+#define MAC16_16(c,a,b) (celt_mips-=2,ADD32((c),MULT16_16((a),(b))))
+
+#define MULT16_32_QX(a, b, Q) MULT16_32_QX_(a, b, Q, __FILE__, __LINE__)
+static OPUS_INLINE int MULT16_32_QX_(int a, opus_int64 b, int Q, char *file, int line)
+{
+ opus_int64 res;
+ if (!VERIFY_SHORT(a) || !VERIFY_INT(b))
+ {
+ fprintf (stderr, "MULT16_32_Q%d: inputs are not short+int: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ if (ABS32(b)>=((opus_val32)(1)<<(15+Q)))
+ {
+ fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n", Q, (int)a, (int)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = (((opus_int64)a)*(opus_int64)b) >> Q;
+ if (!VERIFY_INT(res))
+ {
+ fprintf (stderr, "MULT16_32_Q%d: output is not int: %d*%d=%d in %s: line %d\n", Q, (int)a, (int)b,(int)res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ if (Q==15)
+ celt_mips+=3;
+ else
+ celt_mips+=4;
+ return res;
+}
+
+#define MULT16_32_PX(a, b, Q) MULT16_32_PX_(a, b, Q, __FILE__, __LINE__)
+static OPUS_INLINE int MULT16_32_PX_(int a, opus_int64 b, int Q, char *file, int line)
+{
+ opus_int64 res;
+ if (!VERIFY_SHORT(a) || !VERIFY_INT(b))
+ {
+ fprintf (stderr, "MULT16_32_P%d: inputs are not short+int: %d %d in %s: line %d\n\n", Q, (int)a, (int)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ if (ABS32(b)>=((opus_int64)(1)<<(15+Q)))
+ {
+ fprintf (stderr, "MULT16_32_Q%d: second operand too large: %d %d in %s: line %d\n\n", Q, (int)a, (int)b,file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = ((((opus_int64)a)*(opus_int64)b) + (((opus_val32)(1)<<Q)>>1))>> Q;
+ if (!VERIFY_INT(res))
+ {
+ fprintf (stderr, "MULT16_32_P%d: output is not int: %d*%d=%d in %s: line %d\n\n", Q, (int)a, (int)b,(int)res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ if (Q==15)
+ celt_mips+=4;
+ else
+ celt_mips+=5;
+ return res;
+}
+
+#define MULT16_32_Q15(a,b) MULT16_32_QX(a,b,15)
+#define MAC16_32_Q15(c,a,b) (celt_mips-=2,ADD32((c),MULT16_32_Q15((a),(b))))
+
+static OPUS_INLINE int SATURATE(int a, int b)
+{
+ if (a>b)
+ a=b;
+ if (a<-b)
+ a = -b;
+ celt_mips+=3;
+ return a;
+}
+
+static OPUS_INLINE opus_int16 SATURATE16(opus_int32 a)
+{
+ celt_mips+=3;
+ if (a>32767)
+ return 32767;
+ else if (a<-32768)
+ return -32768;
+ else return a;
+}
+
+static OPUS_INLINE int MULT16_16_Q11_32(int a, int b)
+{
+ opus_int64 res;
+ if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+ {
+ fprintf (stderr, "MULT16_16_Q11: inputs are not short: %d %d\n", a, b);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = ((opus_int64)a)*b;
+ res >>= 11;
+ if (!VERIFY_INT(res))
+ {
+ fprintf (stderr, "MULT16_16_Q11: output is not short: %d*%d=%d\n", (int)a, (int)b, (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=3;
+ return res;
+}
+static OPUS_INLINE short MULT16_16_Q13(int a, int b)
+{
+ opus_int64 res;
+ if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+ {
+ fprintf (stderr, "MULT16_16_Q13: inputs are not short: %d %d\n", a, b);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = ((opus_int64)a)*b;
+ res >>= 13;
+ if (!VERIFY_SHORT(res))
+ {
+ fprintf (stderr, "MULT16_16_Q13: output is not short: %d*%d=%d\n", a, b, (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=3;
+ return res;
+}
+static OPUS_INLINE short MULT16_16_Q14(int a, int b)
+{
+ opus_int64 res;
+ if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+ {
+ fprintf (stderr, "MULT16_16_Q14: inputs are not short: %d %d\n", a, b);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = ((opus_int64)a)*b;
+ res >>= 14;
+ if (!VERIFY_SHORT(res))
+ {
+ fprintf (stderr, "MULT16_16_Q14: output is not short: %d\n", (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=3;
+ return res;
+}
+
+#define MULT16_16_Q15(a, b) MULT16_16_Q15_(a, b, __FILE__, __LINE__)
+static OPUS_INLINE short MULT16_16_Q15_(int a, int b, char *file, int line)
+{
+ opus_int64 res;
+ if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+ {
+ fprintf (stderr, "MULT16_16_Q15: inputs are not short: %d %d in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = ((opus_int64)a)*b;
+ res >>= 15;
+ if (!VERIFY_SHORT(res))
+ {
+ fprintf (stderr, "MULT16_16_Q15: output is not short: %d in %s: line %d\n", (int)res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=1;
+ return res;
+}
+
+static OPUS_INLINE short MULT16_16_P13(int a, int b)
+{
+ opus_int64 res;
+ if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+ {
+ fprintf (stderr, "MULT16_16_P13: inputs are not short: %d %d\n", a, b);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = ((opus_int64)a)*b;
+ res += 4096;
+ if (!VERIFY_INT(res))
+ {
+ fprintf (stderr, "MULT16_16_P13: overflow: %d*%d=%d\n", a, b, (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res >>= 13;
+ if (!VERIFY_SHORT(res))
+ {
+ fprintf (stderr, "MULT16_16_P13: output is not short: %d*%d=%d\n", a, b, (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=4;
+ return res;
+}
+static OPUS_INLINE short MULT16_16_P14(int a, int b)
+{
+ opus_int64 res;
+ if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+ {
+ fprintf (stderr, "MULT16_16_P14: inputs are not short: %d %d\n", a, b);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = ((opus_int64)a)*b;
+ res += 8192;
+ if (!VERIFY_INT(res))
+ {
+ fprintf (stderr, "MULT16_16_P14: overflow: %d*%d=%d\n", a, b, (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res >>= 14;
+ if (!VERIFY_SHORT(res))
+ {
+ fprintf (stderr, "MULT16_16_P14: output is not short: %d*%d=%d\n", a, b, (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=4;
+ return res;
+}
+static OPUS_INLINE short MULT16_16_P15(int a, int b)
+{
+ opus_int64 res;
+ if (!VERIFY_SHORT(a) || !VERIFY_SHORT(b))
+ {
+ fprintf (stderr, "MULT16_16_P15: inputs are not short: %d %d\n", a, b);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = ((opus_int64)a)*b;
+ res += 16384;
+ if (!VERIFY_INT(res))
+ {
+ fprintf (stderr, "MULT16_16_P15: overflow: %d*%d=%d\n", a, b, (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res >>= 15;
+ if (!VERIFY_SHORT(res))
+ {
+ fprintf (stderr, "MULT16_16_P15: output is not short: %d*%d=%d\n", a, b, (int)res);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=2;
+ return res;
+}
+
+#define DIV32_16(a, b) DIV32_16_(a, b, __FILE__, __LINE__)
+
+static OPUS_INLINE int DIV32_16_(opus_int64 a, opus_int64 b, char *file, int line)
+{
+ opus_int64 res;
+ if (b==0)
+ {
+ fprintf(stderr, "DIV32_16: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ return 0;
+ }
+ if (!VERIFY_INT(a) || !VERIFY_SHORT(b))
+ {
+ fprintf (stderr, "DIV32_16: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = a/b;
+ if (!VERIFY_SHORT(res))
+ {
+ fprintf (stderr, "DIV32_16: output is not short: %d / %d = %d in %s: line %d\n", (int)a,(int)b,(int)res, file, line);
+ if (res>32767)
+ res = 32767;
+ if (res<-32768)
+ res = -32768;
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=35;
+ return res;
+}
+
+#define DIV32(a, b) DIV32_(a, b, __FILE__, __LINE__)
+static OPUS_INLINE int DIV32_(opus_int64 a, opus_int64 b, char *file, int line)
+{
+ opus_int64 res;
+ if (b==0)
+ {
+ fprintf(stderr, "DIV32: divide by zero: %d/%d in %s: line %d\n", (int)a, (int)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ return 0;
+ }
+
+ if (!VERIFY_INT(a) || !VERIFY_INT(b))
+ {
+ fprintf (stderr, "DIV32: inputs are not int/short: %d %d in %s: line %d\n", (int)a, (int)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ res = a/b;
+ if (!VERIFY_INT(res))
+ {
+ fprintf (stderr, "DIV32: output is not int: %d in %s: line %d\n", (int)res, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ celt_assert(0);
+#endif
+ }
+ celt_mips+=70;
+ return res;
+}
+
+#undef PRINT_MIPS
+#define PRINT_MIPS(file) do {fprintf (file, "total complexity = %llu MIPS\n", celt_mips);} while (0);
+
+#endif
diff --git a/drivers/opus/celt/fixed_generic.h b/drivers/opus/celt/fixed_generic.h
new file mode 100644
index 0000000000..ecf018a244
--- /dev/null
+++ b/drivers/opus/celt/fixed_generic.h
@@ -0,0 +1,134 @@
+/* Copyright (C) 2007-2009 Xiph.Org Foundation
+ Copyright (C) 2003-2008 Jean-Marc Valin
+ Copyright (C) 2007-2008 CSIRO */
+/**
+ @file fixed_generic.h
+ @brief Generic fixed-point operations
+*/
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef FIXED_GENERIC_H
+#define FIXED_GENERIC_H
+
+/** Multiply a 16-bit signed value by a 16-bit unsigned value. The result is a 32-bit signed value */
+#define MULT16_16SU(a,b) ((opus_val32)(opus_val16)(a)*(opus_val32)(opus_uint16)(b))
+
+/** 16x32 multiplication, followed by a 16-bit shift right. Results fits in 32 bits */
+#define MULT16_32_Q16(a,b) ADD32(MULT16_16((a),SHR((b),16)), SHR(MULT16_16SU((a),((b)&0x0000ffff)),16))
+
+/** 16x32 multiplication, followed by a 16-bit shift right (round-to-nearest). Results fits in 32 bits */
+#define MULT16_32_P16(a,b) ADD32(MULT16_16((a),SHR((b),16)), PSHR(MULT16_16SU((a),((b)&0x0000ffff)),16))
+
+/** 16x32 multiplication, followed by a 15-bit shift right. Results fits in 32 bits */
+#define MULT16_32_Q15(a,b) ADD32(SHL(MULT16_16((a),SHR((b),16)),1), SHR(MULT16_16SU((a),((b)&0x0000ffff)),15))
+
+/** 32x32 multiplication, followed by a 31-bit shift right. Results fits in 32 bits */
+#define MULT32_32_Q31(a,b) ADD32(ADD32(SHL(MULT16_16(SHR((a),16),SHR((b),16)),1), SHR(MULT16_16SU(SHR((a),16),((b)&0x0000ffff)),15)), SHR(MULT16_16SU(SHR((b),16),((a)&0x0000ffff)),15))
+
+/** Compile-time conversion of float constant to 16-bit value */
+#define QCONST16(x,bits) ((opus_val16)(.5+(x)*(((opus_val32)1)<<(bits))))
+
+/** Compile-time conversion of float constant to 32-bit value */
+#define QCONST32(x,bits) ((opus_val32)(.5+(x)*(((opus_val32)1)<<(bits))))
+
+/** Negate a 16-bit value */
+#define NEG16(x) (-(x))
+/** Negate a 32-bit value */
+#define NEG32(x) (-(x))
+
+/** Change a 32-bit value into a 16-bit value. The value is assumed to fit in 16-bit, otherwise the result is undefined */
+#define EXTRACT16(x) ((opus_val16)(x))
+/** Change a 16-bit value into a 32-bit value */
+#define EXTEND32(x) ((opus_val32)(x))
+
+/** Arithmetic shift-right of a 16-bit value */
+#define SHR16(a,shift) ((a) >> (shift))
+/** Arithmetic shift-left of a 16-bit value */
+#define SHL16(a,shift) ((opus_int16)((opus_uint16)(a)<<(shift)))
+/** Arithmetic shift-right of a 32-bit value */
+#define SHR32(a,shift) ((a) >> (shift))
+/** Arithmetic shift-left of a 32-bit value */
+#define SHL32(a,shift) ((opus_int32)((opus_uint32)(a)<<(shift)))
+
+/** 32-bit arithmetic shift right with rounding-to-nearest instead of rounding down */
+#define PSHR32(a,shift) (SHR32((a)+((EXTEND32(1)<<((shift))>>1)),shift))
+/** 32-bit arithmetic shift right where the argument can be negative */
+#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift)))
+
+/** "RAW" macros, should not be used outside of this header file */
+#define SHR(a,shift) ((a) >> (shift))
+#define SHL(a,shift) SHL32(a,shift)
+#define PSHR(a,shift) (SHR((a)+((EXTEND32(1)<<((shift))>>1)),shift))
+#define SATURATE(x,a) (((x)>(a) ? (a) : (x)<-(a) ? -(a) : (x)))
+
+#define SATURATE16(x) (EXTRACT16((x)>32767 ? 32767 : (x)<-32768 ? -32768 : (x)))
+
+/** Shift by a and round-to-neareast 32-bit value. Result is a 16-bit value */
+#define ROUND16(x,a) (EXTRACT16(PSHR32((x),(a))))
+/** Divide by two */
+#define HALF16(x) (SHR16(x,1))
+#define HALF32(x) (SHR32(x,1))
+
+/** Add two 16-bit values */
+#define ADD16(a,b) ((opus_val16)((opus_val16)(a)+(opus_val16)(b)))
+/** Subtract two 16-bit values */
+#define SUB16(a,b) ((opus_val16)(a)-(opus_val16)(b))
+/** Add two 32-bit values */
+#define ADD32(a,b) ((opus_val32)(a)+(opus_val32)(b))
+/** Subtract two 32-bit values */
+#define SUB32(a,b) ((opus_val32)(a)-(opus_val32)(b))
+
+/** 16x16 multiplication where the result fits in 16 bits */
+#define MULT16_16_16(a,b) ((((opus_val16)(a))*((opus_val16)(b))))
+
+/* (opus_val32)(opus_val16) gives TI compiler a hint that it's 16x16->32 multiply */
+/** 16x16 multiplication where the result fits in 32 bits */
+#define MULT16_16(a,b) (((opus_val32)(opus_val16)(a))*((opus_val32)(opus_val16)(b)))
+
+/** 16x16 multiply-add where the result fits in 32 bits */
+#define MAC16_16(c,a,b) (ADD32((c),MULT16_16((a),(b))))
+/** 16x32 multiply, followed by a 15-bit shift right and 32-bit add.
+ b must fit in 31 bits.
+ Result fits in 32 bits. */
+#define MAC16_32_Q15(c,a,b) ADD32(c,ADD32(MULT16_16((a),SHR((b),15)), SHR(MULT16_16((a),((b)&0x00007fff)),15)))
+
+#define MULT16_16_Q11_32(a,b) (SHR(MULT16_16((a),(b)),11))
+#define MULT16_16_Q11(a,b) (SHR(MULT16_16((a),(b)),11))
+#define MULT16_16_Q13(a,b) (SHR(MULT16_16((a),(b)),13))
+#define MULT16_16_Q14(a,b) (SHR(MULT16_16((a),(b)),14))
+#define MULT16_16_Q15(a,b) (SHR(MULT16_16((a),(b)),15))
+
+#define MULT16_16_P13(a,b) (SHR(ADD32(4096,MULT16_16((a),(b))),13))
+#define MULT16_16_P14(a,b) (SHR(ADD32(8192,MULT16_16((a),(b))),14))
+#define MULT16_16_P15(a,b) (SHR(ADD32(16384,MULT16_16((a),(b))),15))
+
+/** Divide a 32-bit value by a 16-bit value. Result fits in 16 bits */
+#define DIV32_16(a,b) ((opus_val16)(((opus_val32)(a))/((opus_val16)(b))))
+
+/** Divide a 32-bit value by a 32-bit value. Result fits in 32 bits */
+#define DIV32(a,b) (((opus_val32)(a))/((opus_val32)(b)))
+
+#endif
diff --git a/drivers/opus/celt/float_cast.h b/drivers/opus/celt/float_cast.h
new file mode 100644
index 0000000000..86e80a93ff
--- /dev/null
+++ b/drivers/opus/celt/float_cast.h
@@ -0,0 +1,140 @@
+/* Copyright (C) 2001 Erik de Castro Lopo <erikd AT mega-nerd DOT com> */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* Version 1.1 */
+
+#ifndef FLOAT_CAST_H
+#define FLOAT_CAST_H
+
+
+#include "opus/celt/arch.h"
+
+/*============================================================================
+** On Intel Pentium processors (especially PIII and probably P4), converting
+** from float to int is very slow. To meet the C specs, the code produced by
+** most C compilers targeting Pentium needs to change the FPU rounding mode
+** before the float to int conversion is performed.
+**
+** Changing the FPU rounding mode causes the FPU pipeline to be flushed. It
+** is this flushing of the pipeline which is so slow.
+**
+** Fortunately the ISO C99 specifications define the functions lrint, lrintf,
+** llrint and llrintf which fix this problem as a side effect.
+**
+** On Unix-like systems, the configure process should have detected the
+** presence of these functions. If they weren't found we have to replace them
+** here with a standard C cast.
+*/
+
+/*
+** The C99 prototypes for lrint and lrintf are as follows:
+**
+** long int lrintf (float x) ;
+** long int lrint (double x) ;
+*/
+
+/* The presence of the required functions are detected during the configure
+** process and the values HAVE_LRINT and HAVE_LRINTF are set accordingly in
+** the config.h file.
+*/
+
+#if (HAVE_LRINTF)
+
+/* These defines enable functionality introduced with the 1999 ISO C
+** standard. They must be defined before the inclusion of math.h to
+** engage them. If optimisation is enabled, these functions will be
+** inlined. With optimisation switched off, you have to link in the
+** maths library using -lm.
+*/
+
+#define _ISOC9X_SOURCE 1
+#define _ISOC99_SOURCE 1
+
+#define __USE_ISOC9X 1
+#define __USE_ISOC99 1
+
+#include <math.h>
+#define float2int(x) lrintf(x)
+
+#elif (defined(HAVE_LRINT))
+
+#define _ISOC9X_SOURCE 1
+#define _ISOC99_SOURCE 1
+
+#define __USE_ISOC9X 1
+#define __USE_ISOC99 1
+
+#include <math.h>
+#define float2int(x) lrint(x)
+
+#elif (defined(_MSC_VER) && _MSC_VER >= 1400) && (defined (WIN64) || defined (_WIN64))
+ #include <xmmintrin.h>
+
+ __inline long int float2int(float value)
+ {
+ return _mm_cvtss_si32(_mm_load_ss(&value));
+ }
+#elif (defined(_MSC_VER) && _MSC_VER >= 1400) && (defined (WIN32) || defined (_WIN32))
+ #include <math.h>
+
+ /* Win32 doesn't seem to have these functions.
+ ** Therefore implement OPUS_INLINE versions of these functions here.
+ */
+
+ __inline long int
+ float2int (float flt)
+ { int intgr;
+
+ _asm
+ { fld flt
+ fistp intgr
+ } ;
+
+ return intgr ;
+ }
+
+#else
+
+#if (defined(__GNUC__) && defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L)
+ /* supported by gcc in C99 mode, but not by all other compilers */
+ #warning "Don't have the functions lrint() and lrintf ()."
+ #warning "Replacing these functions with a standard C cast."
+#endif /* __STDC_VERSION__ >= 199901L */
+ #include <math.h>
+ #define float2int(flt) ((int)(floor(.5+flt)))
+#endif
+
+#ifndef DISABLE_FLOAT_API
+static OPUS_INLINE opus_int16 FLOAT2INT16(float x)
+{
+ x = x*CELT_SIG_SCALE;
+ x = MAX32(x, -32768);
+ x = MIN32(x, 32767);
+ return (opus_int16)float2int(x);
+}
+#endif /* DISABLE_FLOAT_API */
+
+#endif /* FLOAT_CAST_H */
diff --git a/drivers/opus/celt/kiss_fft.c b/drivers/opus/celt/kiss_fft.c
new file mode 100644
index 0000000000..89a1790b24
--- /dev/null
+++ b/drivers/opus/celt/kiss_fft.c
@@ -0,0 +1,719 @@
+/*Copyright (c) 2003-2004, Mark Borgerding
+ Lots of modifications by Jean-Marc Valin
+ Copyright (c) 2005-2007, Xiph.Org Foundation
+ Copyright (c) 2008, Xiph.Org Foundation, CSIRO
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.*/
+
+/* This code is originally from Mark Borgerding's KISS-FFT but has been
+ heavily modified to better suit Opus */
+
+#ifndef SKIP_CONFIG_H
+# ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+# endif
+#endif
+
+#include "opus/celt/_kiss_fft_guts.h"
+#include "opus/celt/arch.h"
+#include "opus/celt/os_support.h"
+#include "opus/celt/mathops.h"
+#include "opus/celt/stack_alloc.h"
+
+/* The guts header contains all the multiplication and addition macros that are defined for
+ complex numbers. It also delares the kf_ internal functions.
+*/
+
+static void kf_bfly2(
+ kiss_fft_cpx * Fout,
+ const size_t fstride,
+ const kiss_fft_state *st,
+ int m,
+ int N,
+ int mm
+ )
+{
+ kiss_fft_cpx * Fout2;
+ const kiss_twiddle_cpx * tw1;
+ int i,j;
+ kiss_fft_cpx * Fout_beg = Fout;
+ for (i=0;i<N;i++)
+ {
+ Fout = Fout_beg + i*mm;
+ Fout2 = Fout + m;
+ tw1 = st->twiddles;
+ for(j=0;j<m;j++)
+ {
+ kiss_fft_cpx t;
+ Fout->r = SHR32(Fout->r, 1);Fout->i = SHR32(Fout->i, 1);
+ Fout2->r = SHR32(Fout2->r, 1);Fout2->i = SHR32(Fout2->i, 1);
+ C_MUL (t, *Fout2 , *tw1);
+ tw1 += fstride;
+ C_SUB( *Fout2 , *Fout , t );
+ C_ADDTO( *Fout , t );
+ ++Fout2;
+ ++Fout;
+ }
+ }
+}
+
+static void ki_bfly2(
+ kiss_fft_cpx * Fout,
+ const size_t fstride,
+ const kiss_fft_state *st,
+ int m,
+ int N,
+ int mm
+ )
+{
+ kiss_fft_cpx * Fout2;
+ const kiss_twiddle_cpx * tw1;
+ kiss_fft_cpx t;
+ int i,j;
+ kiss_fft_cpx * Fout_beg = Fout;
+ for (i=0;i<N;i++)
+ {
+ Fout = Fout_beg + i*mm;
+ Fout2 = Fout + m;
+ tw1 = st->twiddles;
+ for(j=0;j<m;j++)
+ {
+ C_MULC (t, *Fout2 , *tw1);
+ tw1 += fstride;
+ C_SUB( *Fout2 , *Fout , t );
+ C_ADDTO( *Fout , t );
+ ++Fout2;
+ ++Fout;
+ }
+ }
+}
+
+static void kf_bfly4(
+ kiss_fft_cpx * Fout,
+ const size_t fstride,
+ const kiss_fft_state *st,
+ int m,
+ int N,
+ int mm
+ )
+{
+ const kiss_twiddle_cpx *tw1,*tw2,*tw3;
+ kiss_fft_cpx scratch[6];
+ const size_t m2=2*m;
+ const size_t m3=3*m;
+ int i, j;
+
+ kiss_fft_cpx * Fout_beg = Fout;
+ for (i=0;i<N;i++)
+ {
+ Fout = Fout_beg + i*mm;
+ tw3 = tw2 = tw1 = st->twiddles;
+ for (j=0;j<m;j++)
+ {
+ C_MUL4(scratch[0],Fout[m] , *tw1 );
+ C_MUL4(scratch[1],Fout[m2] , *tw2 );
+ C_MUL4(scratch[2],Fout[m3] , *tw3 );
+
+ Fout->r = PSHR32(Fout->r, 2);
+ Fout->i = PSHR32(Fout->i, 2);
+ C_SUB( scratch[5] , *Fout, scratch[1] );
+ C_ADDTO(*Fout, scratch[1]);
+ C_ADD( scratch[3] , scratch[0] , scratch[2] );
+ C_SUB( scratch[4] , scratch[0] , scratch[2] );
+ C_SUB( Fout[m2], *Fout, scratch[3] );
+ tw1 += fstride;
+ tw2 += fstride*2;
+ tw3 += fstride*3;
+ C_ADDTO( *Fout , scratch[3] );
+
+ Fout[m].r = scratch[5].r + scratch[4].i;
+ Fout[m].i = scratch[5].i - scratch[4].r;
+ Fout[m3].r = scratch[5].r - scratch[4].i;
+ Fout[m3].i = scratch[5].i + scratch[4].r;
+ ++Fout;
+ }
+ }
+}
+
+static void ki_bfly4(
+ kiss_fft_cpx * Fout,
+ const size_t fstride,
+ const kiss_fft_state *st,
+ int m,
+ int N,
+ int mm
+ )
+{
+ const kiss_twiddle_cpx *tw1,*tw2,*tw3;
+ kiss_fft_cpx scratch[6];
+ const size_t m2=2*m;
+ const size_t m3=3*m;
+ int i, j;
+
+ kiss_fft_cpx * Fout_beg = Fout;
+ for (i=0;i<N;i++)
+ {
+ Fout = Fout_beg + i*mm;
+ tw3 = tw2 = tw1 = st->twiddles;
+ for (j=0;j<m;j++)
+ {
+ C_MULC(scratch[0],Fout[m] , *tw1 );
+ C_MULC(scratch[1],Fout[m2] , *tw2 );
+ C_MULC(scratch[2],Fout[m3] , *tw3 );
+
+ C_SUB( scratch[5] , *Fout, scratch[1] );
+ C_ADDTO(*Fout, scratch[1]);
+ C_ADD( scratch[3] , scratch[0] , scratch[2] );
+ C_SUB( scratch[4] , scratch[0] , scratch[2] );
+ C_SUB( Fout[m2], *Fout, scratch[3] );
+ tw1 += fstride;
+ tw2 += fstride*2;
+ tw3 += fstride*3;
+ C_ADDTO( *Fout , scratch[3] );
+
+ Fout[m].r = scratch[5].r - scratch[4].i;
+ Fout[m].i = scratch[5].i + scratch[4].r;
+ Fout[m3].r = scratch[5].r + scratch[4].i;
+ Fout[m3].i = scratch[5].i - scratch[4].r;
+ ++Fout;
+ }
+ }
+}
+
+#ifndef RADIX_TWO_ONLY
+
+static void kf_bfly3(
+ kiss_fft_cpx * Fout,
+ const size_t fstride,
+ const kiss_fft_state *st,
+ int m,
+ int N,
+ int mm
+ )
+{
+ int i;
+ size_t k;
+ const size_t m2 = 2*m;
+ const kiss_twiddle_cpx *tw1,*tw2;
+ kiss_fft_cpx scratch[5];
+ kiss_twiddle_cpx epi3;
+
+ kiss_fft_cpx * Fout_beg = Fout;
+ epi3 = st->twiddles[fstride*m];
+ for (i=0;i<N;i++)
+ {
+ Fout = Fout_beg + i*mm;
+ tw1=tw2=st->twiddles;
+ k=m;
+ do {
+ C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3);
+
+ C_MUL(scratch[1],Fout[m] , *tw1);
+ C_MUL(scratch[2],Fout[m2] , *tw2);
+
+ C_ADD(scratch[3],scratch[1],scratch[2]);
+ C_SUB(scratch[0],scratch[1],scratch[2]);
+ tw1 += fstride;
+ tw2 += fstride*2;
+
+ Fout[m].r = Fout->r - HALF_OF(scratch[3].r);
+ Fout[m].i = Fout->i - HALF_OF(scratch[3].i);
+
+ C_MULBYSCALAR( scratch[0] , epi3.i );
+
+ C_ADDTO(*Fout,scratch[3]);
+
+ Fout[m2].r = Fout[m].r + scratch[0].i;
+ Fout[m2].i = Fout[m].i - scratch[0].r;
+
+ Fout[m].r -= scratch[0].i;
+ Fout[m].i += scratch[0].r;
+
+ ++Fout;
+ } while(--k);
+ }
+}
+
+static void ki_bfly3(
+ kiss_fft_cpx * Fout,
+ const size_t fstride,
+ const kiss_fft_state *st,
+ int m,
+ int N,
+ int mm
+ )
+{
+ int i, k;
+ const size_t m2 = 2*m;
+ const kiss_twiddle_cpx *tw1,*tw2;
+ kiss_fft_cpx scratch[5];
+ kiss_twiddle_cpx epi3;
+
+ kiss_fft_cpx * Fout_beg = Fout;
+ epi3 = st->twiddles[fstride*m];
+ for (i=0;i<N;i++)
+ {
+ Fout = Fout_beg + i*mm;
+ tw1=tw2=st->twiddles;
+ k=m;
+ do{
+
+ C_MULC(scratch[1],Fout[m] , *tw1);
+ C_MULC(scratch[2],Fout[m2] , *tw2);
+
+ C_ADD(scratch[3],scratch[1],scratch[2]);
+ C_SUB(scratch[0],scratch[1],scratch[2]);
+ tw1 += fstride;
+ tw2 += fstride*2;
+
+ Fout[m].r = Fout->r - HALF_OF(scratch[3].r);
+ Fout[m].i = Fout->i - HALF_OF(scratch[3].i);
+
+ C_MULBYSCALAR( scratch[0] , -epi3.i );
+
+ C_ADDTO(*Fout,scratch[3]);
+
+ Fout[m2].r = Fout[m].r + scratch[0].i;
+ Fout[m2].i = Fout[m].i - scratch[0].r;
+
+ Fout[m].r -= scratch[0].i;
+ Fout[m].i += scratch[0].r;
+
+ ++Fout;
+ }while(--k);
+ }
+}
+
+static void kf_bfly5(
+ kiss_fft_cpx * Fout,
+ const size_t fstride,
+ const kiss_fft_state *st,
+ int m,
+ int N,
+ int mm
+ )
+{
+ kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4;
+ int i, u;
+ kiss_fft_cpx scratch[13];
+ const kiss_twiddle_cpx * twiddles = st->twiddles;
+ const kiss_twiddle_cpx *tw;
+ kiss_twiddle_cpx ya,yb;
+ kiss_fft_cpx * Fout_beg = Fout;
+
+ ya = twiddles[fstride*m];
+ yb = twiddles[fstride*2*m];
+ tw=st->twiddles;
+
+ for (i=0;i<N;i++)
+ {
+ Fout = Fout_beg + i*mm;
+ Fout0=Fout;
+ Fout1=Fout0+m;
+ Fout2=Fout0+2*m;
+ Fout3=Fout0+3*m;
+ Fout4=Fout0+4*m;
+
+ for ( u=0; u<m; ++u ) {
+ C_FIXDIV( *Fout0,5); C_FIXDIV( *Fout1,5); C_FIXDIV( *Fout2,5); C_FIXDIV( *Fout3,5); C_FIXDIV( *Fout4,5);
+ scratch[0] = *Fout0;
+
+ C_MUL(scratch[1] ,*Fout1, tw[u*fstride]);
+ C_MUL(scratch[2] ,*Fout2, tw[2*u*fstride]);
+ C_MUL(scratch[3] ,*Fout3, tw[3*u*fstride]);
+ C_MUL(scratch[4] ,*Fout4, tw[4*u*fstride]);
+
+ C_ADD( scratch[7],scratch[1],scratch[4]);
+ C_SUB( scratch[10],scratch[1],scratch[4]);
+ C_ADD( scratch[8],scratch[2],scratch[3]);
+ C_SUB( scratch[9],scratch[2],scratch[3]);
+
+ Fout0->r += scratch[7].r + scratch[8].r;
+ Fout0->i += scratch[7].i + scratch[8].i;
+
+ scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r);
+ scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r);
+
+ scratch[6].r = S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i);
+ scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i);
+
+ C_SUB(*Fout1,scratch[5],scratch[6]);
+ C_ADD(*Fout4,scratch[5],scratch[6]);
+
+ scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r);
+ scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r);
+ scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i);
+ scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i);
+
+ C_ADD(*Fout2,scratch[11],scratch[12]);
+ C_SUB(*Fout3,scratch[11],scratch[12]);
+
+ ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4;
+ }
+ }
+}
+
+static void ki_bfly5(
+ kiss_fft_cpx * Fout,
+ const size_t fstride,
+ const kiss_fft_state *st,
+ int m,
+ int N,
+ int mm
+ )
+{
+ kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4;
+ int i, u;
+ kiss_fft_cpx scratch[13];
+ const kiss_twiddle_cpx * twiddles = st->twiddles;
+ const kiss_twiddle_cpx *tw;
+ kiss_twiddle_cpx ya,yb;
+ kiss_fft_cpx * Fout_beg = Fout;
+
+ ya = twiddles[fstride*m];
+ yb = twiddles[fstride*2*m];
+ tw=st->twiddles;
+
+ for (i=0;i<N;i++)
+ {
+ Fout = Fout_beg + i*mm;
+ Fout0=Fout;
+ Fout1=Fout0+m;
+ Fout2=Fout0+2*m;
+ Fout3=Fout0+3*m;
+ Fout4=Fout0+4*m;
+
+ for ( u=0; u<m; ++u ) {
+ scratch[0] = *Fout0;
+
+ C_MULC(scratch[1] ,*Fout1, tw[u*fstride]);
+ C_MULC(scratch[2] ,*Fout2, tw[2*u*fstride]);
+ C_MULC(scratch[3] ,*Fout3, tw[3*u*fstride]);
+ C_MULC(scratch[4] ,*Fout4, tw[4*u*fstride]);
+
+ C_ADD( scratch[7],scratch[1],scratch[4]);
+ C_SUB( scratch[10],scratch[1],scratch[4]);
+ C_ADD( scratch[8],scratch[2],scratch[3]);
+ C_SUB( scratch[9],scratch[2],scratch[3]);
+
+ Fout0->r += scratch[7].r + scratch[8].r;
+ Fout0->i += scratch[7].i + scratch[8].i;
+
+ scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r);
+ scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r);
+
+ scratch[6].r = -S_MUL(scratch[10].i,ya.i) - S_MUL(scratch[9].i,yb.i);
+ scratch[6].i = S_MUL(scratch[10].r,ya.i) + S_MUL(scratch[9].r,yb.i);
+
+ C_SUB(*Fout1,scratch[5],scratch[6]);
+ C_ADD(*Fout4,scratch[5],scratch[6]);
+
+ scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r);
+ scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r);
+ scratch[12].r = S_MUL(scratch[10].i,yb.i) - S_MUL(scratch[9].i,ya.i);
+ scratch[12].i = -S_MUL(scratch[10].r,yb.i) + S_MUL(scratch[9].r,ya.i);
+
+ C_ADD(*Fout2,scratch[11],scratch[12]);
+ C_SUB(*Fout3,scratch[11],scratch[12]);
+
+ ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4;
+ }
+ }
+}
+
+#endif
+
+
+#ifdef CUSTOM_MODES
+
+static
+void compute_bitrev_table(
+ int Fout,
+ opus_int16 *f,
+ const size_t fstride,
+ int in_stride,
+ opus_int16 * factors,
+ const kiss_fft_state *st
+ )
+{
+ const int p=*factors++; /* the radix */
+ const int m=*factors++; /* stage's fft length/p */
+
+ /*printf ("fft %d %d %d %d %d %d\n", p*m, m, p, s2, fstride*in_stride, N);*/
+ if (m==1)
+ {
+ int j;
+ for (j=0;j<p;j++)
+ {
+ *f = Fout+j;
+ f += fstride*in_stride;
+ }
+ } else {
+ int j;
+ for (j=0;j<p;j++)
+ {
+ compute_bitrev_table( Fout , f, fstride*p, in_stride, factors,st);
+ f += fstride*in_stride;
+ Fout += m;
+ }
+ }
+}
+
+/* facbuf is populated by p1,m1,p2,m2, ...
+ where
+ p[i] * m[i] = m[i-1]
+ m0 = n */
+static
+int kf_factor(int n,opus_int16 * facbuf)
+{
+ int p=4;
+
+ /*factor out powers of 4, powers of 2, then any remaining primes */
+ do {
+ while (n % p) {
+ switch (p) {
+ case 4: p = 2; break;
+ case 2: p = 3; break;
+ default: p += 2; break;
+ }
+ if (p>32000 || (opus_int32)p*(opus_int32)p > n)
+ p = n; /* no more factors, skip to end */
+ }
+ n /= p;
+#ifdef RADIX_TWO_ONLY
+ if (p!=2 && p != 4)
+#else
+ if (p>5)
+#endif
+ {
+ return 0;
+ }
+ *facbuf++ = p;
+ *facbuf++ = n;
+ } while (n > 1);
+ return 1;
+}
+
+static void compute_twiddles(kiss_twiddle_cpx *twiddles, int nfft)
+{
+ int i;
+#ifdef OPUS_FIXED_POINT
+ for (i=0;i<nfft;++i) {
+ opus_val32 phase = -i;
+ kf_cexp2(twiddles+i, DIV32(SHL32(phase,17),nfft));
+ }
+#else
+ for (i=0;i<nfft;++i) {
+ const double pi=3.14159265358979323846264338327;
+ double phase = ( -2*pi /nfft ) * i;
+ kf_cexp(twiddles+i, phase );
+ }
+#endif
+}
+
+/*
+ *
+ * Allocates all necessary storage space for the fft and ifft.
+ * The return value is a contiguous block of memory. As such,
+ * It can be freed with free().
+ * */
+kiss_fft_state *opus_fft_alloc_twiddles(int nfft,void * mem,size_t * lenmem, const kiss_fft_state *base)
+{
+ kiss_fft_state *st=NULL;
+ size_t memneeded = sizeof(struct kiss_fft_state); /* twiddle factors*/
+
+ if ( lenmem==NULL ) {
+ st = ( kiss_fft_state*)KISS_FFT_MALLOC( memneeded );
+ }else{
+ if (mem != NULL && *lenmem >= memneeded)
+ st = (kiss_fft_state*)mem;
+ *lenmem = memneeded;
+ }
+ if (st) {
+ opus_int16 *bitrev;
+ kiss_twiddle_cpx *twiddles;
+
+ st->nfft=nfft;
+#ifndef OPUS_FIXED_POINT
+ st->scale = 1.f/nfft;
+#endif
+ if (base != NULL)
+ {
+ st->twiddles = base->twiddles;
+ st->shift = 0;
+ while (nfft<<st->shift != base->nfft && st->shift < 32)
+ st->shift++;
+ if (st->shift>=32)
+ goto fail;
+ } else {
+ st->twiddles = twiddles = (kiss_twiddle_cpx*)KISS_FFT_MALLOC(sizeof(kiss_twiddle_cpx)*nfft);
+ compute_twiddles(twiddles, nfft);
+ st->shift = -1;
+ }
+ if (!kf_factor(nfft,st->factors))
+ {
+ goto fail;
+ }
+
+ /* bitrev */
+ st->bitrev = bitrev = (opus_int16*)KISS_FFT_MALLOC(sizeof(opus_int16)*nfft);
+ if (st->bitrev==NULL)
+ goto fail;
+ compute_bitrev_table(0, bitrev, 1,1, st->factors,st);
+ }
+ return st;
+fail:
+ opus_fft_free(st);
+ return NULL;
+}
+
+kiss_fft_state *opus_fft_alloc(int nfft,void * mem,size_t * lenmem )
+{
+ return opus_fft_alloc_twiddles(nfft, mem, lenmem, NULL);
+}
+
+void opus_fft_free(const kiss_fft_state *cfg)
+{
+ if (cfg)
+ {
+ opus_free((opus_int16*)cfg->bitrev);
+ if (cfg->shift < 0)
+ opus_free((kiss_twiddle_cpx*)cfg->twiddles);
+ opus_free((kiss_fft_state*)cfg);
+ }
+}
+
+#endif /* CUSTOM_MODES */
+
+void opus_fft(const kiss_fft_state *st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout)
+{
+ int m2, m;
+ int p;
+ int L;
+ int fstride[MAXFACTORS];
+ int i;
+ int shift;
+
+ /* st->shift can be -1 */
+ shift = st->shift>0 ? st->shift : 0;
+
+ celt_assert2 (fin != fout, "In-place FFT not supported");
+ /* Bit-reverse the input */
+ for (i=0;i<st->nfft;i++)
+ {
+ fout[st->bitrev[i]] = fin[i];
+#ifndef OPUS_FIXED_POINT
+ fout[st->bitrev[i]].r *= st->scale;
+ fout[st->bitrev[i]].i *= st->scale;
+#endif
+ }
+
+ fstride[0] = 1;
+ L=0;
+ do {
+ p = st->factors[2*L];
+ m = st->factors[2*L+1];
+ fstride[L+1] = fstride[L]*p;
+ L++;
+ } while(m!=1);
+ m = st->factors[2*L-1];
+ for (i=L-1;i>=0;i--)
+ {
+ if (i!=0)
+ m2 = st->factors[2*i-1];
+ else
+ m2 = 1;
+ switch (st->factors[2*i])
+ {
+ case 2:
+ kf_bfly2(fout,fstride[i]<<shift,st,m, fstride[i], m2);
+ break;
+ case 4:
+ kf_bfly4(fout,fstride[i]<<shift,st,m, fstride[i], m2);
+ break;
+ #ifndef RADIX_TWO_ONLY
+ case 3:
+ kf_bfly3(fout,fstride[i]<<shift,st,m, fstride[i], m2);
+ break;
+ case 5:
+ kf_bfly5(fout,fstride[i]<<shift,st,m, fstride[i], m2);
+ break;
+ #endif
+ }
+ m = m2;
+ }
+}
+
+void opus_ifft(const kiss_fft_state *st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout)
+{
+ int m2, m;
+ int p;
+ int L;
+ int fstride[MAXFACTORS];
+ int i;
+ int shift;
+
+ /* st->shift can be -1 */
+ shift = st->shift>0 ? st->shift : 0;
+ celt_assert2 (fin != fout, "In-place FFT not supported");
+ /* Bit-reverse the input */
+ for (i=0;i<st->nfft;i++)
+ fout[st->bitrev[i]] = fin[i];
+
+ fstride[0] = 1;
+ L=0;
+ do {
+ p = st->factors[2*L];
+ m = st->factors[2*L+1];
+ fstride[L+1] = fstride[L]*p;
+ L++;
+ } while(m!=1);
+ m = st->factors[2*L-1];
+ for (i=L-1;i>=0;i--)
+ {
+ if (i!=0)
+ m2 = st->factors[2*i-1];
+ else
+ m2 = 1;
+ switch (st->factors[2*i])
+ {
+ case 2:
+ ki_bfly2(fout,fstride[i]<<shift,st,m, fstride[i], m2);
+ break;
+ case 4:
+ ki_bfly4(fout,fstride[i]<<shift,st,m, fstride[i], m2);
+ break;
+#ifndef RADIX_TWO_ONLY
+ case 3:
+ ki_bfly3(fout,fstride[i]<<shift,st,m, fstride[i], m2);
+ break;
+ case 5:
+ ki_bfly5(fout,fstride[i]<<shift,st,m, fstride[i], m2);
+ break;
+#endif
+ }
+ m = m2;
+ }
+}
+
diff --git a/drivers/opus/celt/kiss_fft.h b/drivers/opus/celt/kiss_fft.h
new file mode 100644
index 0000000000..db2532c692
--- /dev/null
+++ b/drivers/opus/celt/kiss_fft.h
@@ -0,0 +1,139 @@
+/*Copyright (c) 2003-2004, Mark Borgerding
+ Lots of modifications by Jean-Marc Valin
+ Copyright (c) 2005-2007, Xiph.Org Foundation
+ Copyright (c) 2008, Xiph.Org Foundation, CSIRO
+
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.*/
+
+#ifndef KISS_FFT_H
+#define KISS_FFT_H
+
+#include <stdlib.h>
+#include <math.h>
+#include "opus/celt/arch.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef USE_SIMD
+# include <xmmintrin.h>
+# define kiss_fft_scalar __m128
+#define KISS_FFT_MALLOC(nbytes) memalign(16,nbytes)
+#else
+#define KISS_FFT_MALLOC opus_alloc
+#endif
+
+#ifdef OPUS_FIXED_POINT
+#include "opus/celt/arch.h"
+
+# define kiss_fft_scalar opus_int32
+# define kiss_twiddle_scalar opus_int16
+
+
+#else
+# ifndef kiss_fft_scalar
+/* default is float */
+# define kiss_fft_scalar float
+# define kiss_twiddle_scalar float
+# define KF_SUFFIX _celt_single
+# endif
+#endif
+
+typedef struct {
+ kiss_fft_scalar r;
+ kiss_fft_scalar i;
+}kiss_fft_cpx;
+
+typedef struct {
+ kiss_twiddle_scalar r;
+ kiss_twiddle_scalar i;
+}kiss_twiddle_cpx;
+
+#define MAXFACTORS 8
+/* e.g. an fft of length 128 has 4 factors
+ as far as kissfft is concerned
+ 4*4*4*2
+ */
+
+typedef struct kiss_fft_state{
+ int nfft;
+#ifndef OPUS_FIXED_POINT
+ kiss_fft_scalar scale;
+#endif
+ int shift;
+ opus_int16 factors[2*MAXFACTORS];
+ const opus_int16 *bitrev;
+ const kiss_twiddle_cpx *twiddles;
+} kiss_fft_state;
+
+/*typedef struct kiss_fft_state* kiss_fft_cfg;*/
+
+/**
+ * opus_fft_alloc
+ *
+ * Initialize a FFT (or IFFT) algorithm's cfg/state buffer.
+ *
+ * typical usage: kiss_fft_cfg mycfg=opus_fft_alloc(1024,0,NULL,NULL);
+ *
+ * The return value from fft_alloc is a cfg buffer used internally
+ * by the fft routine or NULL.
+ *
+ * If lenmem is NULL, then opus_fft_alloc will allocate a cfg buffer using malloc.
+ * The returned value should be free()d when done to avoid memory leaks.
+ *
+ * The state can be placed in a user supplied buffer 'mem':
+ * If lenmem is not NULL and mem is not NULL and *lenmem is large enough,
+ * then the function places the cfg in mem and the size used in *lenmem
+ * and returns mem.
+ *
+ * If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough),
+ * then the function returns NULL and places the minimum cfg
+ * buffer size in *lenmem.
+ * */
+
+kiss_fft_state *opus_fft_alloc_twiddles(int nfft,void * mem,size_t * lenmem, const kiss_fft_state *base);
+
+kiss_fft_state *opus_fft_alloc(int nfft,void * mem,size_t * lenmem);
+
+/**
+ * opus_fft(cfg,in_out_buf)
+ *
+ * Perform an FFT on a complex input buffer.
+ * for a forward FFT,
+ * fin should be f[0] , f[1] , ... ,f[nfft-1]
+ * fout will be F[0] , F[1] , ... ,F[nfft-1]
+ * Note that each element is complex and can be accessed like
+ f[k].r and f[k].i
+ * */
+void opus_fft(const kiss_fft_state *cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout);
+void opus_ifft(const kiss_fft_state *cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout);
+
+void opus_fft_free(const kiss_fft_state *cfg);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/opus/celt/laplace.c b/drivers/opus/celt/laplace.c
new file mode 100644
index 0000000000..9dc4d94d24
--- /dev/null
+++ b/drivers/opus/celt/laplace.c
@@ -0,0 +1,134 @@
+/* Copyright (c) 2007 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/celt/laplace.h"
+#include "opus/celt/mathops.h"
+
+/* The minimum probability of an energy delta (out of 32768). */
+#define LAPLACE_LOG_MINP (0)
+#define LAPLACE_MINP (1<<LAPLACE_LOG_MINP)
+/* The minimum number of guaranteed representable energy deltas (in one
+ direction). */
+#define LAPLACE_NMIN (16)
+
+/* When called, decay is positive and at most 11456. */
+static unsigned ec_laplace_get_freq1(unsigned fs0, int decay)
+{
+ unsigned ft;
+ ft = 32768 - LAPLACE_MINP*(2*LAPLACE_NMIN) - fs0;
+ return ft*(opus_int32)(16384-decay)>>15;
+}
+
+void ec_laplace_encode(ec_enc *enc, int *value, unsigned fs, int decay)
+{
+ unsigned fl;
+ int val = *value;
+ fl = 0;
+ if (val)
+ {
+ int s;
+ int i;
+ s = -(val<0);
+ val = (val+s)^s;
+ fl = fs;
+ fs = ec_laplace_get_freq1(fs, decay);
+ /* Search the decaying part of the PDF.*/
+ for (i=1; fs > 0 && i < val; i++)
+ {
+ fs *= 2;
+ fl += fs+2*LAPLACE_MINP;
+ fs = (fs*(opus_int32)decay)>>15;
+ }
+ /* Everything beyond that has probability LAPLACE_MINP. */
+ if (!fs)
+ {
+ int di;
+ int ndi_max;
+ ndi_max = (32768-fl+LAPLACE_MINP-1)>>LAPLACE_LOG_MINP;
+ ndi_max = (ndi_max-s)>>1;
+ di = IMIN(val - i, ndi_max - 1);
+ fl += (2*di+1+s)*LAPLACE_MINP;
+ fs = IMIN(LAPLACE_MINP, 32768-fl);
+ *value = (i+di+s)^s;
+ }
+ else
+ {
+ fs += LAPLACE_MINP;
+ fl += fs&~s;
+ }
+ celt_assert(fl+fs<=32768);
+ celt_assert(fs>0);
+ }
+ ec_encode_bin(enc, fl, fl+fs, 15);
+}
+
+int ec_laplace_decode(ec_dec *dec, unsigned fs, int decay)
+{
+ int val=0;
+ unsigned fl;
+ unsigned fm;
+ fm = ec_decode_bin(dec, 15);
+ fl = 0;
+ if (fm >= fs)
+ {
+ val++;
+ fl = fs;
+ fs = ec_laplace_get_freq1(fs, decay)+LAPLACE_MINP;
+ /* Search the decaying part of the PDF.*/
+ while(fs > LAPLACE_MINP && fm >= fl+2*fs)
+ {
+ fs *= 2;
+ fl += fs;
+ fs = ((fs-2*LAPLACE_MINP)*(opus_int32)decay)>>15;
+ fs += LAPLACE_MINP;
+ val++;
+ }
+ /* Everything beyond that has probability LAPLACE_MINP. */
+ if (fs <= LAPLACE_MINP)
+ {
+ int di;
+ di = (fm-fl)>>(LAPLACE_LOG_MINP+1);
+ val += di;
+ fl += 2*di*LAPLACE_MINP;
+ }
+ if (fm < fl+fs)
+ val = -val;
+ else
+ fl += fs;
+ }
+ celt_assert(fl<32768);
+ celt_assert(fs>0);
+ celt_assert(fl<=fm);
+ celt_assert(fm<IMIN(fl+fs,32768));
+ ec_dec_update(dec, fl, IMIN(fl+fs,32768), 32768);
+ return val;
+}
diff --git a/drivers/opus/celt/laplace.h b/drivers/opus/celt/laplace.h
new file mode 100644
index 0000000000..9efcc73aa2
--- /dev/null
+++ b/drivers/opus/celt/laplace.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2007 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "opus/celt/entenc.h"
+#include "opus/celt/entdec.h"
+
+/** Encode a value that is assumed to be the realisation of a
+ Laplace-distributed random process
+ @param enc Entropy encoder state
+ @param value Value to encode
+ @param fs Probability of 0, multiplied by 32768
+ @param decay Probability of the value +/- 1, multiplied by 16384
+*/
+void ec_laplace_encode(ec_enc *enc, int *value, unsigned fs, int decay);
+
+/** Decode a value that is assumed to be the realisation of a
+ Laplace-distributed random process
+ @param dec Entropy decoder state
+ @param fs Probability of 0, multiplied by 32768
+ @param decay Probability of the value +/- 1, multiplied by 16384
+ @return Value decoded
+ */
+int ec_laplace_decode(ec_dec *dec, unsigned fs, int decay);
diff --git a/drivers/opus/celt/mathops.c b/drivers/opus/celt/mathops.c
new file mode 100644
index 0000000000..88e5aea129
--- /dev/null
+++ b/drivers/opus/celt/mathops.c
@@ -0,0 +1,208 @@
+/* Copyright (c) 2002-2008 Jean-Marc Valin
+ Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/**
+ @file mathops.h
+ @brief Various math functions
+*/
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/celt/mathops.h"
+
+/*Compute floor(sqrt(_val)) with exact arithmetic.
+ This has been tested on all possible 32-bit inputs.*/
+unsigned isqrt32(opus_uint32 _val){
+ unsigned b;
+ unsigned g;
+ int bshift;
+ /*Uses the second method from
+ http://www.azillionmonkeys.com/qed/sqroot.html
+ The main idea is to search for the largest binary digit b such that
+ (g+b)*(g+b) <= _val, and add it to the solution g.*/
+ g=0;
+ bshift=(EC_ILOG(_val)-1)>>1;
+ b=1U<<bshift;
+ do{
+ opus_uint32 t;
+ t=(((opus_uint32)g<<1)+b)<<bshift;
+ if(t<=_val){
+ g+=b;
+ _val-=t;
+ }
+ b>>=1;
+ bshift--;
+ }
+ while(bshift>=0);
+ return g;
+}
+
+#ifdef OPUS_FIXED_POINT
+
+opus_val32 frac_div32(opus_val32 a, opus_val32 b)
+{
+ opus_val16 rcp;
+ opus_val32 result, rem;
+ int shift = celt_ilog2(b)-29;
+ a = VSHR32(a,shift);
+ b = VSHR32(b,shift);
+ /* 16-bit reciprocal */
+ rcp = ROUND16(celt_rcp(ROUND16(b,16)),3);
+ result = MULT16_32_Q15(rcp, a);
+ rem = PSHR32(a,2)-MULT32_32_Q31(result, b);
+ result = ADD32(result, SHL32(MULT16_32_Q15(rcp, rem),2));
+ if (result >= 536870912) /* 2^29 */
+ return 2147483647; /* 2^31 - 1 */
+ else if (result <= -536870912) /* -2^29 */
+ return -2147483647; /* -2^31 */
+ else
+ return SHL32(result, 2);
+}
+
+/** Reciprocal sqrt approximation in the range [0.25,1) (Q16 in, Q14 out) */
+opus_val16 celt_rsqrt_norm(opus_val32 x)
+{
+ opus_val16 n;
+ opus_val16 r;
+ opus_val16 r2;
+ opus_val16 y;
+ /* Range of n is [-16384,32767] ([-0.5,1) in Q15). */
+ n = x-32768;
+ /* Get a rough initial guess for the root.
+ The optimal minimax quadratic approximation (using relative error) is
+ r = 1.437799046117536+n*(-0.823394375837328+n*0.4096419668459485).
+ Coefficients here, and the final result r, are Q14.*/
+ r = ADD16(23557, MULT16_16_Q15(n, ADD16(-13490, MULT16_16_Q15(n, 6713))));
+ /* We want y = x*r*r-1 in Q15, but x is 32-bit Q16 and r is Q14.
+ We can compute the result from n and r using Q15 multiplies with some
+ adjustment, carefully done to avoid overflow.
+ Range of y is [-1564,1594]. */
+ r2 = MULT16_16_Q15(r, r);
+ y = SHL16(SUB16(ADD16(MULT16_16_Q15(r2, n), r2), 16384), 1);
+ /* Apply a 2nd-order Householder iteration: r += r*y*(y*0.375-0.5).
+ This yields the Q14 reciprocal square root of the Q16 x, with a maximum
+ relative error of 1.04956E-4, a (relative) RMSE of 2.80979E-5, and a
+ peak absolute error of 2.26591/16384. */
+ return ADD16(r, MULT16_16_Q15(r, MULT16_16_Q15(y,
+ SUB16(MULT16_16_Q15(y, 12288), 16384))));
+}
+
+/** Sqrt approximation (QX input, QX/2 output) */
+opus_val32 celt_sqrt(opus_val32 x)
+{
+ int k;
+ opus_val16 n;
+ opus_val32 rt;
+ static const opus_val16 C[5] = {23175, 11561, -3011, 1699, -664};
+ if (x==0)
+ return 0;
+ else if (x>=1073741824)
+ return 32767;
+ k = (celt_ilog2(x)>>1)-7;
+ x = VSHR32(x, 2*k);
+ n = x-32768;
+ rt = ADD16(C[0], MULT16_16_Q15(n, ADD16(C[1], MULT16_16_Q15(n, ADD16(C[2],
+ MULT16_16_Q15(n, ADD16(C[3], MULT16_16_Q15(n, (C[4])))))))));
+ rt = VSHR32(rt,7-k);
+ return rt;
+}
+
+#define L1 32767
+#define L2 -7651
+#define L3 8277
+#define L4 -626
+
+static OPUS_INLINE opus_val16 _celt_cos_pi_2(opus_val16 x)
+{
+ opus_val16 x2;
+
+ x2 = MULT16_16_P15(x,x);
+ return ADD16(1,MIN16(32766,ADD32(SUB16(L1,x2), MULT16_16_P15(x2, ADD32(L2, MULT16_16_P15(x2, ADD32(L3, MULT16_16_P15(L4, x2
+ ))))))));
+}
+
+#undef L1
+#undef L2
+#undef L3
+#undef L4
+
+opus_val16 celt_cos_norm(opus_val32 x)
+{
+ x = x&0x0001ffff;
+ if (x>SHL32(EXTEND32(1), 16))
+ x = SUB32(SHL32(EXTEND32(1), 17),x);
+ if (x&0x00007fff)
+ {
+ if (x<SHL32(EXTEND32(1), 15))
+ {
+ return _celt_cos_pi_2(EXTRACT16(x));
+ } else {
+ return NEG32(_celt_cos_pi_2(EXTRACT16(65536-x)));
+ }
+ } else {
+ if (x&0x0000ffff)
+ return 0;
+ else if (x&0x0001ffff)
+ return -32767;
+ else
+ return 32767;
+ }
+}
+
+/** Reciprocal approximation (Q15 input, Q16 output) */
+opus_val32 celt_rcp(opus_val32 x)
+{
+ int i;
+ opus_val16 n;
+ opus_val16 r;
+ celt_assert2(x>0, "celt_rcp() only defined for positive values");
+ i = celt_ilog2(x);
+ /* n is Q15 with range [0,1). */
+ n = VSHR32(x,i-15)-32768;
+ /* Start with a linear approximation:
+ r = 1.8823529411764706-0.9411764705882353*n.
+ The coefficients and the result are Q14 in the range [15420,30840].*/
+ r = ADD16(30840, MULT16_16_Q15(-15420, n));
+ /* Perform two Newton iterations:
+ r -= r*((r*n)-1.Q15)
+ = r*((r*n)+(r-1.Q15)). */
+ r = SUB16(r, MULT16_16_Q15(r,
+ ADD16(MULT16_16_Q15(r, n), ADD16(r, -32768))));
+ /* We subtract an extra 1 in the second iteration to avoid overflow; it also
+ neatly compensates for truncation error in the rest of the process. */
+ r = SUB16(r, ADD16(1, MULT16_16_Q15(r,
+ ADD16(MULT16_16_Q15(r, n), ADD16(r, -32768)))));
+ /* r is now the Q15 solution to 2/(n+1), with a maximum relative error
+ of 7.05346E-5, a (relative) RMSE of 2.14418E-5, and a peak absolute
+ error of 1.24665/32768. */
+ return VSHR32(EXTEND32(r),i-16);
+}
+
+#endif
diff --git a/drivers/opus/celt/mathops.h b/drivers/opus/celt/mathops.h
new file mode 100644
index 0000000000..759f58d1b7
--- /dev/null
+++ b/drivers/opus/celt/mathops.h
@@ -0,0 +1,258 @@
+/* Copyright (c) 2002-2008 Jean-Marc Valin
+ Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/**
+ @file mathops.h
+ @brief Various math functions
+*/
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MATHOPS_H
+#define MATHOPS_H
+
+#include "opus/celt/arch.h"
+#include "opus/celt/entcode.h"
+#include "opus/celt/os_support.h"
+
+/* Multiplies two 16-bit fractional values. Bit-exactness of this macro is important */
+#define FRAC_MUL16(a,b) ((16384+((opus_int32)(opus_int16)(a)*(opus_int16)(b)))>>15)
+
+unsigned isqrt32(opus_uint32 _val);
+
+#ifndef OVERRIDE_CELT_MAXABS16
+static OPUS_INLINE opus_val32 celt_maxabs16(const opus_val16 *x, int len)
+{
+ int i;
+ opus_val16 maxval = 0;
+ opus_val16 minval = 0;
+ for (i=0;i<len;i++)
+ {
+ maxval = MAX16(maxval, x[i]);
+ minval = MIN16(minval, x[i]);
+ }
+ return MAX32(EXTEND32(maxval),-EXTEND32(minval));
+}
+#endif
+
+#ifndef OVERRIDE_CELT_MAXABS32
+#ifdef OPUS_FIXED_POINT
+static OPUS_INLINE opus_val32 celt_maxabs32(const opus_val32 *x, int len)
+{
+ int i;
+ opus_val32 maxval = 0;
+ opus_val32 minval = 0;
+ for (i=0;i<len;i++)
+ {
+ maxval = MAX32(maxval, x[i]);
+ minval = MIN32(minval, x[i]);
+ }
+ return MAX32(maxval, -minval);
+}
+#else
+#define celt_maxabs32(x,len) celt_maxabs16(x,len)
+#endif
+#endif
+
+
+#ifndef OPUS_FIXED_POINT
+
+#define PI 3.141592653f
+#define celt_sqrt(x) ((float)sqrt(x))
+#define celt_rsqrt(x) (1.f/celt_sqrt(x))
+#define celt_rsqrt_norm(x) (celt_rsqrt(x))
+#define celt_cos_norm(x) ((float)cos((.5f*PI)*(x)))
+#define celt_rcp(x) (1.f/(x))
+#define celt_div(a,b) ((a)/(b))
+#define frac_div32(a,b) ((float)(a)/(b))
+
+#ifdef FLOAT_APPROX
+
+/* Note: This assumes radix-2 floating point with the exponent at bits 23..30 and an offset of 127
+ denorm, +/- inf and NaN are *not* handled */
+
+/** Base-2 log approximation (log2(x)). */
+static OPUS_INLINE float celt_log2(float x)
+{
+ int integer;
+ float frac;
+ union {
+ float f;
+ opus_uint32 i;
+ } in;
+ in.f = x;
+ integer = (in.i>>23)-127;
+ in.i -= integer<<23;
+ frac = in.f - 1.5f;
+ frac = -0.41445418f + frac*(0.95909232f
+ + frac*(-0.33951290f + frac*0.16541097f));
+ return 1+integer+frac;
+}
+
+/** Base-2 exponential approximation (2^x). */
+static OPUS_INLINE float celt_exp2(float x)
+{
+ int integer;
+ float frac;
+ union {
+ float f;
+ opus_uint32 i;
+ } res;
+ integer = floor(x);
+ if (integer < -50)
+ return 0;
+ frac = x-integer;
+ /* K0 = 1, K1 = log(2), K2 = 3-4*log(2), K3 = 3*log(2) - 2 */
+ res.f = 0.99992522f + frac * (0.69583354f
+ + frac * (0.22606716f + 0.078024523f*frac));
+ res.i = (res.i + (integer<<23)) & 0x7fffffff;
+ return res.f;
+}
+
+#else
+#define celt_log2(x) ((float)(1.442695040888963387*log(x)))
+#define celt_exp2(x) ((float)exp(0.6931471805599453094*(x)))
+#endif
+
+#endif
+
+#ifdef OPUS_FIXED_POINT
+
+#include "opus/celt/os_support.h"
+
+#ifndef OVERRIDE_CELT_ILOG2
+/** Integer log in base2. Undefined for zero and negative numbers */
+static OPUS_INLINE opus_int16 celt_ilog2(opus_int32 x)
+{
+ celt_assert2(x>0, "celt_ilog2() only defined for strictly positive numbers");
+ return EC_ILOG(x)-1;
+}
+#endif
+
+
+/** Integer log in base2. Defined for zero, but not for negative numbers */
+static OPUS_INLINE opus_int16 celt_zlog2(opus_val32 x)
+{
+ return x <= 0 ? 0 : celt_ilog2(x);
+}
+
+opus_val16 celt_rsqrt_norm(opus_val32 x);
+
+opus_val32 celt_sqrt(opus_val32 x);
+
+opus_val16 celt_cos_norm(opus_val32 x);
+
+/** Base-2 logarithm approximation (log2(x)). (Q14 input, Q10 output) */
+static OPUS_INLINE opus_val16 celt_log2(opus_val32 x)
+{
+ int i;
+ opus_val16 n, frac;
+ /* -0.41509302963303146, 0.9609890551383969, -0.31836011537636605,
+ 0.15530808010959576, -0.08556153059057618 */
+ static const opus_val16 C[5] = {-6801+(1<<(13-DB_SHIFT)), 15746, -5217, 2545, -1401};
+ if (x==0)
+ return -32767;
+ i = celt_ilog2(x);
+ n = VSHR32(x,i-15)-32768-16384;
+ frac = ADD16(C[0], MULT16_16_Q15(n, ADD16(C[1], MULT16_16_Q15(n, ADD16(C[2], MULT16_16_Q15(n, ADD16(C[3], MULT16_16_Q15(n, C[4]))))))));
+ return SHL16(i-13,DB_SHIFT)+SHR16(frac,14-DB_SHIFT);
+}
+
+/*
+ K0 = 1
+ K1 = log(2)
+ K2 = 3-4*log(2)
+ K3 = 3*log(2) - 2
+*/
+#define D0 16383
+#define D1 22804
+#define D2 14819
+#define D3 10204
+
+static OPUS_INLINE opus_val32 celt_exp2_frac(opus_val16 x)
+{
+ opus_val16 frac;
+ frac = SHL16(x, 4);
+ return ADD16(D0, MULT16_16_Q15(frac, ADD16(D1, MULT16_16_Q15(frac, ADD16(D2 , MULT16_16_Q15(D3,frac))))));
+}
+/** Base-2 exponential approximation (2^x). (Q10 input, Q16 output) */
+static OPUS_INLINE opus_val32 celt_exp2(opus_val16 x)
+{
+ int integer;
+ opus_val16 frac;
+ integer = SHR16(x,10);
+ if (integer>14)
+ return 0x7f000000;
+ else if (integer < -15)
+ return 0;
+ frac = celt_exp2_frac(x-SHL16(integer,10));
+ return VSHR32(EXTEND32(frac), -integer-2);
+}
+
+opus_val32 celt_rcp(opus_val32 x);
+
+#define celt_div(a,b) MULT32_32_Q31((opus_val32)(a),celt_rcp(b))
+
+opus_val32 frac_div32(opus_val32 a, opus_val32 b);
+
+#define M1 32767
+#define M2 -21
+#define M3 -11943
+#define M4 4936
+
+/* Atan approximation using a 4th order polynomial. Input is in Q15 format
+ and normalized by pi/4. Output is in Q15 format */
+static OPUS_INLINE opus_val16 celt_atan01(opus_val16 x)
+{
+ return MULT16_16_P15(x, ADD32(M1, MULT16_16_P15(x, ADD32(M2, MULT16_16_P15(x, ADD32(M3, MULT16_16_P15(M4, x)))))));
+}
+
+#undef M1
+#undef M2
+#undef M3
+#undef M4
+
+/* atan2() approximation valid for positive input values */
+static OPUS_INLINE opus_val16 celt_atan2p(opus_val16 y, opus_val16 x)
+{
+ if (y < x)
+ {
+ opus_val32 arg;
+ arg = celt_div(SHL32(EXTEND32(y),15),x);
+ if (arg >= 32767)
+ arg = 32767;
+ return SHR16(celt_atan01(EXTRACT16(arg)),1);
+ } else {
+ opus_val32 arg;
+ arg = celt_div(SHL32(EXTEND32(x),15),y);
+ if (arg >= 32767)
+ arg = 32767;
+ return 25736-SHR16(celt_atan01(EXTRACT16(arg)),1);
+ }
+}
+
+#endif /* OPUS_FIXED_POINT */
+#endif /* MATHOPS_H */
diff --git a/drivers/opus/celt/mdct.c b/drivers/opus/celt/mdct.c
new file mode 100644
index 0000000000..ae34538d6c
--- /dev/null
+++ b/drivers/opus/celt/mdct.c
@@ -0,0 +1,311 @@
+ /* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2008 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* This is a simple MDCT implementation that uses a N/4 complex FFT
+ to do most of the work. It should be relatively straightforward to
+ plug in pretty much and FFT here.
+
+ This replaces the Vorbis FFT (and uses the exact same API), which
+ was a bit too messy and that was ending up duplicating code
+ (might as well use the same FFT everywhere).
+
+ The algorithm is similar to (and inspired from) Fabrice Bellard's
+ MDCT implementation in FFMPEG, but has differences in signs, ordering
+ and scaling in many places.
+*/
+
+#ifndef SKIP_CONFIG_H
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+#endif
+
+#include "opus/celt/mdct.h"
+#include "opus/celt/kiss_fft.h"
+#include "opus/celt/_kiss_fft_guts.h"
+#include <math.h>
+#include "opus/celt/os_support.h"
+#include "opus/celt/mathops.h"
+#include "opus/celt/stack_alloc.h"
+
+#ifdef CUSTOM_MODES
+
+int clt_mdct_init(celt_mdct_lookup *l,int N, int maxshift)
+{
+ int i;
+ int N4;
+ kiss_twiddle_scalar *trig;
+#if defined(OPUS_FIXED_POINT)
+ int N2=N>>1;
+#endif
+ l->n = N;
+ N4 = N>>2;
+ l->maxshift = maxshift;
+ for (i=0;i<=maxshift;i++)
+ {
+ if (i==0)
+ l->kfft[i] = opus_fft_alloc(N>>2>>i, 0, 0);
+ else
+ l->kfft[i] = opus_fft_alloc_twiddles(N>>2>>i, 0, 0, l->kfft[0]);
+#ifndef ENABLE_TI_DSPLIB55
+ if (l->kfft[i]==NULL)
+ return 0;
+#endif
+ }
+ l->trig = trig = (kiss_twiddle_scalar*)opus_alloc((N4+1)*sizeof(kiss_twiddle_scalar));
+ if (l->trig==NULL)
+ return 0;
+ /* We have enough points that sine isn't necessary */
+#if defined(OPUS_FIXED_POINT)
+ for (i=0;i<=N4;i++)
+ trig[i] = TRIG_UPSCALE*celt_cos_norm(DIV32(ADD32(SHL32(EXTEND32(i),17),N2),N));
+#else
+ for (i=0;i<=N4;i++)
+ trig[i] = (kiss_twiddle_scalar)cos(2*PI*i/N);
+#endif
+ return 1;
+}
+
+void clt_mdct_clear(celt_mdct_lookup *l)
+{
+ int i;
+ for (i=0;i<=l->maxshift;i++)
+ opus_fft_free(l->kfft[i]);
+ opus_free((kiss_twiddle_scalar*)l->trig);
+}
+
+#endif /* CUSTOM_MODES */
+
+/* Forward MDCT trashes the input array */
+void clt_mdct_forward(const celt_mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out,
+ const opus_val16 *window, int overlap, int shift, int stride)
+{
+ int i;
+ int N, N2, N4;
+ kiss_twiddle_scalar sine;
+ VARDECL(kiss_fft_scalar, f);
+ VARDECL(kiss_fft_scalar, f2);
+ SAVE_STACK;
+ N = l->n;
+ N >>= shift;
+ N2 = N>>1;
+ N4 = N>>2;
+ ALLOC(f, N2, kiss_fft_scalar);
+ ALLOC(f2, N2, kiss_fft_scalar);
+ /* sin(x) ~= x here */
+#ifdef OPUS_FIXED_POINT
+ sine = TRIG_UPSCALE*(QCONST16(0.7853981f, 15)+N2)/N;
+#else
+ sine = (kiss_twiddle_scalar)2*PI*(.125f)/N;
+#endif
+
+ /* Consider the input to be composed of four blocks: [a, b, c, d] */
+ /* Window, shuffle, fold */
+ {
+ /* Temp pointers to make it really clear to the compiler what we're doing */
+ const kiss_fft_scalar * OPUS_RESTRICT xp1 = in+(overlap>>1);
+ const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+N2-1+(overlap>>1);
+ kiss_fft_scalar * OPUS_RESTRICT yp = f;
+ const opus_val16 * OPUS_RESTRICT wp1 = window+(overlap>>1);
+ const opus_val16 * OPUS_RESTRICT wp2 = window+(overlap>>1)-1;
+ for(i=0;i<((overlap+3)>>2);i++)
+ {
+ /* Real part arranged as -d-cR, Imag part arranged as -b+aR*/
+ *yp++ = MULT16_32_Q15(*wp2, xp1[N2]) + MULT16_32_Q15(*wp1,*xp2);
+ *yp++ = MULT16_32_Q15(*wp1, *xp1) - MULT16_32_Q15(*wp2, xp2[-N2]);
+ xp1+=2;
+ xp2-=2;
+ wp1+=2;
+ wp2-=2;
+ }
+ wp1 = window;
+ wp2 = window+overlap-1;
+ for(;i<N4-((overlap+3)>>2);i++)
+ {
+ /* Real part arranged as a-bR, Imag part arranged as -c-dR */
+ *yp++ = *xp2;
+ *yp++ = *xp1;
+ xp1+=2;
+ xp2-=2;
+ }
+ for(;i<N4;i++)
+ {
+ /* Real part arranged as a-bR, Imag part arranged as -c-dR */
+ *yp++ = -MULT16_32_Q15(*wp1, xp1[-N2]) + MULT16_32_Q15(*wp2, *xp2);
+ *yp++ = MULT16_32_Q15(*wp2, *xp1) + MULT16_32_Q15(*wp1, xp2[N2]);
+ xp1+=2;
+ xp2-=2;
+ wp1+=2;
+ wp2-=2;
+ }
+ }
+ /* Pre-rotation */
+ {
+ kiss_fft_scalar * OPUS_RESTRICT yp = f;
+ const kiss_twiddle_scalar *t = &l->trig[0];
+ for(i=0;i<N4;i++)
+ {
+ kiss_fft_scalar re, im, yr, yi;
+ re = yp[0];
+ im = yp[1];
+ yr = -S_MUL(re,t[i<<shift]) - S_MUL(im,t[(N4-i)<<shift]);
+ yi = -S_MUL(im,t[i<<shift]) + S_MUL(re,t[(N4-i)<<shift]);
+ /* works because the cos is nearly one */
+ *yp++ = yr + S_MUL(yi,sine);
+ *yp++ = yi - S_MUL(yr,sine);
+ }
+ }
+
+ /* N/4 complex FFT, down-scales by 4/N */
+ opus_fft(l->kfft[shift], (kiss_fft_cpx *)f, (kiss_fft_cpx *)f2);
+
+ /* Post-rotate */
+ {
+ /* Temp pointers to make it really clear to the compiler what we're doing */
+ const kiss_fft_scalar * OPUS_RESTRICT fp = f2;
+ kiss_fft_scalar * OPUS_RESTRICT yp1 = out;
+ kiss_fft_scalar * OPUS_RESTRICT yp2 = out+stride*(N2-1);
+ const kiss_twiddle_scalar *t = &l->trig[0];
+ /* Temp pointers to make it really clear to the compiler what we're doing */
+ for(i=0;i<N4;i++)
+ {
+ kiss_fft_scalar yr, yi;
+ yr = S_MUL(fp[1],t[(N4-i)<<shift]) + S_MUL(fp[0],t[i<<shift]);
+ yi = S_MUL(fp[0],t[(N4-i)<<shift]) - S_MUL(fp[1],t[i<<shift]);
+ /* works because the cos is nearly one */
+ *yp1 = yr - S_MUL(yi,sine);
+ *yp2 = yi + S_MUL(yr,sine);;
+ fp += 2;
+ yp1 += 2*stride;
+ yp2 -= 2*stride;
+ }
+ }
+ RESTORE_STACK;
+}
+
+void clt_mdct_backward(const celt_mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_scalar * OPUS_RESTRICT out,
+ const opus_val16 * OPUS_RESTRICT window, int overlap, int shift, int stride)
+{
+ int i;
+ int N, N2, N4;
+ kiss_twiddle_scalar sine;
+ VARDECL(kiss_fft_scalar, f2);
+ SAVE_STACK;
+ N = l->n;
+ N >>= shift;
+ N2 = N>>1;
+ N4 = N>>2;
+ ALLOC(f2, N2, kiss_fft_scalar);
+ /* sin(x) ~= x here */
+#ifdef OPUS_FIXED_POINT
+ sine = TRIG_UPSCALE*(QCONST16(0.7853981f, 15)+N2)/N;
+#else
+ sine = (kiss_twiddle_scalar)2*PI*(.125f)/N;
+#endif
+
+ /* Pre-rotate */
+ {
+ /* Temp pointers to make it really clear to the compiler what we're doing */
+ const kiss_fft_scalar * OPUS_RESTRICT xp1 = in;
+ const kiss_fft_scalar * OPUS_RESTRICT xp2 = in+stride*(N2-1);
+ kiss_fft_scalar * OPUS_RESTRICT yp = f2;
+ const kiss_twiddle_scalar *t = &l->trig[0];
+ for(i=0;i<N4;i++)
+ {
+ kiss_fft_scalar yr, yi;
+ yr = -S_MUL(*xp2, t[i<<shift]) + S_MUL(*xp1,t[(N4-i)<<shift]);
+ yi = -S_MUL(*xp2, t[(N4-i)<<shift]) - S_MUL(*xp1,t[i<<shift]);
+ /* works because the cos is nearly one */
+ *yp++ = yr - S_MUL(yi,sine);
+ *yp++ = yi + S_MUL(yr,sine);
+ xp1+=2*stride;
+ xp2-=2*stride;
+ }
+ }
+
+ /* Inverse N/4 complex FFT. This one should *not* downscale even in fixed-point */
+ opus_ifft(l->kfft[shift], (kiss_fft_cpx *)f2, (kiss_fft_cpx *)(out+(overlap>>1)));
+
+ /* Post-rotate and de-shuffle from both ends of the buffer at once to make
+ it in-place. */
+ {
+ kiss_fft_scalar * OPUS_RESTRICT yp0 = out+(overlap>>1);
+ kiss_fft_scalar * OPUS_RESTRICT yp1 = out+(overlap>>1)+N2-2;
+ const kiss_twiddle_scalar *t = &l->trig[0];
+ /* Loop to (N4+1)>>1 to handle odd N4. When N4 is odd, the
+ middle pair will be computed twice. */
+ for(i=0;i<(N4+1)>>1;i++)
+ {
+ kiss_fft_scalar re, im, yr, yi;
+ kiss_twiddle_scalar t0, t1;
+ re = yp0[0];
+ im = yp0[1];
+ t0 = t[i<<shift];
+ t1 = t[(N4-i)<<shift];
+ /* We'd scale up by 2 here, but instead it's done when mixing the windows */
+ yr = S_MUL(re,t0) - S_MUL(im,t1);
+ yi = S_MUL(im,t0) + S_MUL(re,t1);
+ re = yp1[0];
+ im = yp1[1];
+ /* works because the cos is nearly one */
+ yp0[0] = -(yr - S_MUL(yi,sine));
+ yp1[1] = yi + S_MUL(yr,sine);
+
+ t0 = t[(N4-i-1)<<shift];
+ t1 = t[(i+1)<<shift];
+ /* We'd scale up by 2 here, but instead it's done when mixing the windows */
+ yr = S_MUL(re,t0) - S_MUL(im,t1);
+ yi = S_MUL(im,t0) + S_MUL(re,t1);
+ /* works because the cos is nearly one */
+ yp1[0] = -(yr - S_MUL(yi,sine));
+ yp0[1] = yi + S_MUL(yr,sine);
+ yp0 += 2;
+ yp1 -= 2;
+ }
+ }
+
+ /* Mirror on both sides for TDAC */
+ {
+ kiss_fft_scalar * OPUS_RESTRICT xp1 = out+overlap-1;
+ kiss_fft_scalar * OPUS_RESTRICT yp1 = out;
+ const opus_val16 * OPUS_RESTRICT wp1 = window;
+ const opus_val16 * OPUS_RESTRICT wp2 = window+overlap-1;
+
+ for(i = 0; i < overlap/2; i++)
+ {
+ kiss_fft_scalar x1, x2;
+ x1 = *xp1;
+ x2 = *yp1;
+ *yp1++ = MULT16_32_Q15(*wp2, x2) - MULT16_32_Q15(*wp1, x1);
+ *xp1-- = MULT16_32_Q15(*wp1, x2) + MULT16_32_Q15(*wp2, x1);
+ wp1++;
+ wp2--;
+ }
+ }
+ RESTORE_STACK;
+}
diff --git a/drivers/opus/celt/mdct.h b/drivers/opus/celt/mdct.h
new file mode 100644
index 0000000000..492afeae1e
--- /dev/null
+++ b/drivers/opus/celt/mdct.h
@@ -0,0 +1,70 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2008 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* This is a simple MDCT implementation that uses a N/4 complex FFT
+ to do most of the work. It should be relatively straightforward to
+ plug in pretty much and FFT here.
+
+ This replaces the Vorbis FFT (and uses the exact same API), which
+ was a bit too messy and that was ending up duplicating code
+ (might as well use the same FFT everywhere).
+
+ The algorithm is similar to (and inspired from) Fabrice Bellard's
+ MDCT implementation in FFMPEG, but has differences in signs, ordering
+ and scaling in many places.
+*/
+
+#ifndef MDCT_H
+#define MDCT_H
+
+#include "opus/opus_defines.h"
+#include "opus/celt/kiss_fft.h"
+#include "opus/celt/arch.h"
+
+typedef struct {
+ int n;
+ int maxshift;
+ const kiss_fft_state *kfft[4];
+ const kiss_twiddle_scalar * OPUS_RESTRICT trig;
+} celt_mdct_lookup;
+
+int clt_mdct_init(celt_mdct_lookup *l,int N, int maxshift);
+void clt_mdct_clear(celt_mdct_lookup *l);
+
+/** Compute a forward MDCT and scale by 4/N, trashes the input array */
+void clt_mdct_forward(const celt_mdct_lookup *l, kiss_fft_scalar *in,
+ kiss_fft_scalar * OPUS_RESTRICT out,
+ const opus_val16 *window, int overlap, int shift, int stride);
+
+/** Compute a backward MDCT (no scaling) and performs weighted overlap-add
+ (scales implicitly by 1/2) */
+void clt_mdct_backward(const celt_mdct_lookup *l, kiss_fft_scalar *in,
+ kiss_fft_scalar * OPUS_RESTRICT out,
+ const opus_val16 * OPUS_RESTRICT window, int overlap, int shift, int stride);
+
+#endif
diff --git a/drivers/opus/celt/mfrngcod.h b/drivers/opus/celt/mfrngcod.h
new file mode 100644
index 0000000000..c24d98cde2
--- /dev/null
+++ b/drivers/opus/celt/mfrngcod.h
@@ -0,0 +1,48 @@
+/* Copyright (c) 2001-2008 Timothy B. Terriberry
+ Copyright (c) 2008-2009 Xiph.Org Foundation */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if !defined(_mfrngcode_H)
+# define _mfrngcode_H (1)
+# include "opus/celt/entcode.h"
+
+/*Constants used by the entropy encoder/decoder.*/
+
+/*The number of bits to output at a time.*/
+# define EC_SYM_BITS (8)
+/*The total number of bits in each of the state registers.*/
+# define EC_CODE_BITS (32)
+/*The maximum symbol value.*/
+# define EC_SYM_MAX ((1U<<EC_SYM_BITS)-1)
+/*Bits to shift by to move a symbol into the high-order position.*/
+# define EC_CODE_SHIFT (EC_CODE_BITS-EC_SYM_BITS-1)
+/*Carry bit of the high-order range symbol.*/
+# define EC_CODE_TOP (((opus_uint32)1U)<<(EC_CODE_BITS-1))
+/*Low-order bit of the high-order range symbol.*/
+# define EC_CODE_BOT (EC_CODE_TOP>>EC_SYM_BITS)
+/*The number of bits available for the last, partial symbol in the code field.*/
+# define EC_CODE_EXTRA ((EC_CODE_BITS-2)%EC_SYM_BITS+1)
+#endif
diff --git a/drivers/opus/celt/modes.c b/drivers/opus/celt/modes.c
new file mode 100644
index 0000000000..aef2681443
--- /dev/null
+++ b/drivers/opus/celt/modes.c
@@ -0,0 +1,438 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Copyright (c) 2008 Gregory Maxwell
+ Written by Jean-Marc Valin and Gregory Maxwell */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/celt/celt.h"
+#include "opus/celt/opus_modes.h"
+#include "opus/celt/rate.h"
+#include "opus/celt/os_support.h"
+#include "opus/celt/stack_alloc.h"
+#include "opus/celt/quant_bands.h"
+
+static const opus_int16 eband5ms[] = {
+/*0 200 400 600 800 1k 1.2 1.4 1.6 2k 2.4 2.8 3.2 4k 4.8 5.6 6.8 8k 9.6 12k 15.6 */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 34, 40, 48, 60, 78, 100
+};
+
+/* Alternate tuning (partially derived from Vorbis) */
+#define BITALLOC_SIZE 11
+/* Bit allocation table in units of 1/32 bit/sample (0.1875 dB SNR) */
+static const unsigned char band_allocation[] = {
+/*0 200 400 600 800 1k 1.2 1.4 1.6 2k 2.4 2.8 3.2 4k 4.8 5.6 6.8 8k 9.6 12k 15.6 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 90, 80, 75, 69, 63, 56, 49, 40, 34, 29, 20, 18, 10, 0, 0, 0, 0, 0, 0, 0, 0,
+110,100, 90, 84, 78, 71, 65, 58, 51, 45, 39, 32, 26, 20, 12, 0, 0, 0, 0, 0, 0,
+118,110,103, 93, 86, 80, 75, 70, 65, 59, 53, 47, 40, 31, 23, 15, 4, 0, 0, 0, 0,
+126,119,112,104, 95, 89, 83, 78, 72, 66, 60, 54, 47, 39, 32, 25, 17, 12, 1, 0, 0,
+134,127,120,114,103, 97, 91, 85, 78, 72, 66, 60, 54, 47, 41, 35, 29, 23, 16, 10, 1,
+144,137,130,124,113,107,101, 95, 88, 82, 76, 70, 64, 57, 51, 45, 39, 33, 26, 15, 1,
+152,145,138,132,123,117,111,105, 98, 92, 86, 80, 74, 67, 61, 55, 49, 43, 36, 20, 1,
+162,155,148,142,133,127,121,115,108,102, 96, 90, 84, 77, 71, 65, 59, 53, 46, 30, 1,
+172,165,158,152,143,137,131,125,118,112,106,100, 94, 87, 81, 75, 69, 63, 56, 45, 20,
+200,200,200,200,200,200,200,200,198,193,188,183,178,173,168,163,158,153,148,129,104,
+};
+
+#ifndef CUSTOM_MODES_ONLY
+ #ifdef OPUS_FIXED_POINT
+ #include "opus/celt/static_modes_fixed.h"
+ #else
+ #include "opus/celt/static_modes_float.h"
+ #endif
+#endif /* CUSTOM_MODES_ONLY */
+
+#ifndef M_PI
+#define M_PI 3.141592653
+#endif
+
+#ifdef CUSTOM_MODES
+
+/* Defining 25 critical bands for the full 0-20 kHz audio bandwidth
+ Taken from http://ccrma.stanford.edu/~jos/bbt/Bark_Frequency_Scale.html */
+#define BARK_BANDS 25
+static const opus_int16 bark_freq[BARK_BANDS+1] = {
+ 0, 100, 200, 300, 400,
+ 510, 630, 770, 920, 1080,
+ 1270, 1480, 1720, 2000, 2320,
+ 2700, 3150, 3700, 4400, 5300,
+ 6400, 7700, 9500, 12000, 15500,
+ 20000};
+
+static opus_int16 *compute_ebands(opus_int32 Fs, int frame_size, int res, int *nbEBands)
+{
+ opus_int16 *eBands;
+ int i, j, lin, low, high, nBark, offset=0;
+
+ /* All modes that have 2.5 ms short blocks use the same definition */
+ if (Fs == 400*(opus_int32)frame_size)
+ {
+ *nbEBands = sizeof(eband5ms)/sizeof(eband5ms[0])-1;
+ eBands = opus_alloc(sizeof(opus_int16)*(*nbEBands+1));
+ for (i=0;i<*nbEBands+1;i++)
+ eBands[i] = eband5ms[i];
+ return eBands;
+ }
+ /* Find the number of critical bands supported by our sampling rate */
+ for (nBark=1;nBark<BARK_BANDS;nBark++)
+ if (bark_freq[nBark+1]*2 >= Fs)
+ break;
+
+ /* Find where the linear part ends (i.e. where the spacing is more than min_width */
+ for (lin=0;lin<nBark;lin++)
+ if (bark_freq[lin+1]-bark_freq[lin] >= res)
+ break;
+
+ low = (bark_freq[lin]+res/2)/res;
+ high = nBark-lin;
+ *nbEBands = low+high;
+ eBands = opus_alloc(sizeof(opus_int16)*(*nbEBands+2));
+
+ if (eBands==NULL)
+ return NULL;
+
+ /* Linear spacing (min_width) */
+ for (i=0;i<low;i++)
+ eBands[i] = i;
+ if (low>0)
+ offset = eBands[low-1]*res - bark_freq[lin-1];
+ /* Spacing follows critical bands */
+ for (i=0;i<high;i++)
+ {
+ int target = bark_freq[lin+i];
+ /* Round to an even value */
+ eBands[i+low] = (target+offset/2+res)/(2*res)*2;
+ offset = eBands[i+low]*res - target;
+ }
+ /* Enforce the minimum spacing at the boundary */
+ for (i=0;i<*nbEBands;i++)
+ if (eBands[i] < i)
+ eBands[i] = i;
+ /* Round to an even value */
+ eBands[*nbEBands] = (bark_freq[nBark]+res)/(2*res)*2;
+ if (eBands[*nbEBands] > frame_size)
+ eBands[*nbEBands] = frame_size;
+ for (i=1;i<*nbEBands-1;i++)
+ {
+ if (eBands[i+1]-eBands[i] < eBands[i]-eBands[i-1])
+ {
+ eBands[i] -= (2*eBands[i]-eBands[i-1]-eBands[i+1])/2;
+ }
+ }
+ /* Remove any empty bands. */
+ for (i=j=0;i<*nbEBands;i++)
+ if(eBands[i+1]>eBands[j])
+ eBands[++j]=eBands[i+1];
+ *nbEBands=j;
+
+ for (i=1;i<*nbEBands;i++)
+ {
+ /* Every band must be smaller than the last band. */
+ celt_assert(eBands[i]-eBands[i-1]<=eBands[*nbEBands]-eBands[*nbEBands-1]);
+ /* Each band must be no larger than twice the size of the previous one. */
+ celt_assert(eBands[i+1]-eBands[i]<=2*(eBands[i]-eBands[i-1]));
+ }
+
+ return eBands;
+}
+
+static void compute_allocation_table(CELTMode *mode)
+{
+ int i, j;
+ unsigned char *allocVectors;
+ int maxBands = sizeof(eband5ms)/sizeof(eband5ms[0])-1;
+
+ mode->nbAllocVectors = BITALLOC_SIZE;
+ allocVectors = opus_alloc(sizeof(unsigned char)*(BITALLOC_SIZE*mode->nbEBands));
+ if (allocVectors==NULL)
+ return;
+
+ /* Check for standard mode */
+ if (mode->Fs == 400*(opus_int32)mode->shortMdctSize)
+ {
+ for (i=0;i<BITALLOC_SIZE*mode->nbEBands;i++)
+ allocVectors[i] = band_allocation[i];
+ mode->allocVectors = allocVectors;
+ return;
+ }
+ /* If not the standard mode, interpolate */
+ /* Compute per-codec-band allocation from per-critical-band matrix */
+ for (i=0;i<BITALLOC_SIZE;i++)
+ {
+ for (j=0;j<mode->nbEBands;j++)
+ {
+ int k;
+ for (k=0;k<maxBands;k++)
+ {
+ if (400*(opus_int32)eband5ms[k] > mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize)
+ break;
+ }
+ if (k>maxBands-1)
+ allocVectors[i*mode->nbEBands+j] = band_allocation[i*maxBands + maxBands-1];
+ else {
+ opus_int32 a0, a1;
+ a1 = mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize - 400*(opus_int32)eband5ms[k-1];
+ a0 = 400*(opus_int32)eband5ms[k] - mode->eBands[j]*(opus_int32)mode->Fs/mode->shortMdctSize;
+ allocVectors[i*mode->nbEBands+j] = (a0*band_allocation[i*maxBands+k-1]
+ + a1*band_allocation[i*maxBands+k])/(a0+a1);
+ }
+ }
+ }
+
+ /*printf ("\n");
+ for (i=0;i<BITALLOC_SIZE;i++)
+ {
+ for (j=0;j<mode->nbEBands;j++)
+ printf ("%d ", allocVectors[i*mode->nbEBands+j]);
+ printf ("\n");
+ }
+ exit(0);*/
+
+ mode->allocVectors = allocVectors;
+}
+
+#endif /* CUSTOM_MODES */
+
+CELTMode *opus_custom_mode_create(opus_int32 Fs, int frame_size, int *error)
+{
+ int i;
+#ifdef CUSTOM_MODES
+ CELTMode *mode=NULL;
+ int res;
+ opus_val16 *window;
+ opus_int16 *logN;
+ int LM;
+ ALLOC_STACK;
+#if !defined(VAR_ARRAYS) && !defined(USE_ALLOCA)
+ if (global_stack==NULL)
+ goto failure;
+#endif
+#endif
+
+#ifndef CUSTOM_MODES_ONLY
+ for (i=0;i<TOTAL_MODES;i++)
+ {
+ int j;
+ for (j=0;j<4;j++)
+ {
+ if (Fs == static_mode_list[i]->Fs &&
+ (frame_size<<j) == static_mode_list[i]->shortMdctSize*static_mode_list[i]->nbShortMdcts)
+ {
+ if (error)
+ *error = OPUS_OK;
+ return (CELTMode*)static_mode_list[i];
+ }
+ }
+ }
+#endif /* CUSTOM_MODES_ONLY */
+
+#ifndef CUSTOM_MODES
+ if (error)
+ *error = OPUS_BAD_ARG;
+ return NULL;
+#else
+
+ /* The good thing here is that permutation of the arguments will automatically be invalid */
+
+ if (Fs < 8000 || Fs > 96000)
+ {
+ if (error)
+ *error = OPUS_BAD_ARG;
+ return NULL;
+ }
+ if (frame_size < 40 || frame_size > 1024 || frame_size%2!=0)
+ {
+ if (error)
+ *error = OPUS_BAD_ARG;
+ return NULL;
+ }
+ /* Frames of less than 1ms are not supported. */
+ if ((opus_int32)frame_size*1000 < Fs)
+ {
+ if (error)
+ *error = OPUS_BAD_ARG;
+ return NULL;
+ }
+
+ if ((opus_int32)frame_size*75 >= Fs && (frame_size%16)==0)
+ {
+ LM = 3;
+ } else if ((opus_int32)frame_size*150 >= Fs && (frame_size%8)==0)
+ {
+ LM = 2;
+ } else if ((opus_int32)frame_size*300 >= Fs && (frame_size%4)==0)
+ {
+ LM = 1;
+ } else
+ {
+ LM = 0;
+ }
+
+ /* Shorts longer than 3.3ms are not supported. */
+ if ((opus_int32)(frame_size>>LM)*300 > Fs)
+ {
+ if (error)
+ *error = OPUS_BAD_ARG;
+ return NULL;
+ }
+
+ mode = opus_alloc(sizeof(CELTMode));
+ if (mode==NULL)
+ goto failure;
+ mode->Fs = Fs;
+
+ /* Pre/de-emphasis depends on sampling rate. The "standard" pre-emphasis
+ is defined as A(z) = 1 - 0.85*z^-1 at 48 kHz. Other rates should
+ approximate that. */
+ if(Fs < 12000) /* 8 kHz */
+ {
+ mode->preemph[0] = QCONST16(0.3500061035f, 15);
+ mode->preemph[1] = -QCONST16(0.1799926758f, 15);
+ mode->preemph[2] = QCONST16(0.2719968125f, SIG_SHIFT); /* exact 1/preemph[3] */
+ mode->preemph[3] = QCONST16(3.6765136719f, 13);
+ } else if(Fs < 24000) /* 16 kHz */
+ {
+ mode->preemph[0] = QCONST16(0.6000061035f, 15);
+ mode->preemph[1] = -QCONST16(0.1799926758f, 15);
+ mode->preemph[2] = QCONST16(0.4424998650f, SIG_SHIFT); /* exact 1/preemph[3] */
+ mode->preemph[3] = QCONST16(2.2598876953f, 13);
+ } else if(Fs < 40000) /* 32 kHz */
+ {
+ mode->preemph[0] = QCONST16(0.7799987793f, 15);
+ mode->preemph[1] = -QCONST16(0.1000061035f, 15);
+ mode->preemph[2] = QCONST16(0.7499771125f, SIG_SHIFT); /* exact 1/preemph[3] */
+ mode->preemph[3] = QCONST16(1.3333740234f, 13);
+ } else /* 48 kHz */
+ {
+ mode->preemph[0] = QCONST16(0.8500061035f, 15);
+ mode->preemph[1] = QCONST16(0.0f, 15);
+ mode->preemph[2] = QCONST16(1.f, SIG_SHIFT);
+ mode->preemph[3] = QCONST16(1.f, 13);
+ }
+
+ mode->maxLM = LM;
+ mode->nbShortMdcts = 1<<LM;
+ mode->shortMdctSize = frame_size/mode->nbShortMdcts;
+ res = (mode->Fs+mode->shortMdctSize)/(2*mode->shortMdctSize);
+
+ mode->eBands = compute_ebands(Fs, mode->shortMdctSize, res, &mode->nbEBands);
+ if (mode->eBands==NULL)
+ goto failure;
+#if !defined(SMALL_FOOTPRINT)
+ /* Make sure we don't allocate a band larger than our PVQ table.
+ 208 should be enough, but let's be paranoid. */
+ if ((mode->eBands[mode->nbEBands] - mode->eBands[mode->nbEBands-1])<<LM >
+ 208) {
+ goto failure;
+ }
+#endif
+
+ mode->effEBands = mode->nbEBands;
+ while (mode->eBands[mode->effEBands] > mode->shortMdctSize)
+ mode->effEBands--;
+
+ /* Overlap must be divisible by 4 */
+ mode->overlap = ((mode->shortMdctSize>>2)<<2);
+
+ compute_allocation_table(mode);
+ if (mode->allocVectors==NULL)
+ goto failure;
+
+ window = (opus_val16*)opus_alloc(mode->overlap*sizeof(opus_val16));
+ if (window==NULL)
+ goto failure;
+
+#ifndef OPUS_FIXED_POINT
+ for (i=0;i<mode->overlap;i++)
+ window[i] = Q15ONE*sin(.5*M_PI* sin(.5*M_PI*(i+.5)/mode->overlap) * sin(.5*M_PI*(i+.5)/mode->overlap));
+#else
+ for (i=0;i<mode->overlap;i++)
+ window[i] = MIN32(32767,floor(.5+32768.*sin(.5*M_PI* sin(.5*M_PI*(i+.5)/mode->overlap) * sin(.5*M_PI*(i+.5)/mode->overlap))));
+#endif
+ mode->window = window;
+
+ logN = (opus_int16*)opus_alloc(mode->nbEBands*sizeof(opus_int16));
+ if (logN==NULL)
+ goto failure;
+
+ for (i=0;i<mode->nbEBands;i++)
+ logN[i] = log2_frac(mode->eBands[i+1]-mode->eBands[i], BITRES);
+ mode->logN = logN;
+
+ compute_pulse_cache(mode, mode->maxLM);
+
+ if (clt_mdct_init(&mode->mdct, 2*mode->shortMdctSize*mode->nbShortMdcts,
+ mode->maxLM) == 0)
+ goto failure;
+
+ if (error)
+ *error = OPUS_OK;
+
+ return mode;
+failure:
+ if (error)
+ *error = OPUS_ALLOC_FAIL;
+ if (mode!=NULL)
+ opus_custom_mode_destroy(mode);
+ return NULL;
+#endif /* !CUSTOM_MODES */
+}
+
+#ifdef CUSTOM_MODES
+void opus_custom_mode_destroy(CELTMode *mode)
+{
+ if (mode == NULL)
+ return;
+#ifndef CUSTOM_MODES_ONLY
+ {
+ int i;
+ for (i=0;i<TOTAL_MODES;i++)
+ {
+ if (mode == static_mode_list[i])
+ {
+ return;
+ }
+ }
+ }
+#endif /* CUSTOM_MODES_ONLY */
+ opus_free((opus_int16*)mode->eBands);
+ opus_free((opus_int16*)mode->allocVectors);
+
+ opus_free((opus_val16*)mode->window);
+ opus_free((opus_int16*)mode->logN);
+
+ opus_free((opus_int16*)mode->cache.index);
+ opus_free((unsigned char*)mode->cache.bits);
+ opus_free((unsigned char*)mode->cache.caps);
+ clt_mdct_clear(&mode->mdct);
+
+ opus_free((CELTMode *)mode);
+}
+#endif
diff --git a/drivers/opus/celt/opus_custom_demo.c b/drivers/opus/celt/opus_custom_demo.c
new file mode 100644
index 0000000000..b3129de779
--- /dev/null
+++ b/drivers/opus/celt/opus_custom_demo.c
@@ -0,0 +1,210 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/opus_custom.h"
+#include "opus/celt/arch.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+#define MAX_PACKET 1275
+
+int main(int argc, char *argv[])
+{
+ int err;
+ char *inFile, *outFile;
+ FILE *fin, *fout;
+ OpusCustomMode *mode=NULL;
+ OpusCustomEncoder *enc;
+ OpusCustomDecoder *dec;
+ int len;
+ opus_int32 frame_size, channels, rate;
+ int bytes_per_packet;
+ unsigned char data[MAX_PACKET];
+ int complexity;
+#if !(defined (OPUS_FIXED_POINT) && !defined(CUSTOM_MODES)) && defined(RESYNTH)
+ int i;
+ double rmsd = 0;
+#endif
+ int count = 0;
+ opus_int32 skip;
+ opus_int16 *in, *out;
+ if (argc != 9 && argc != 8 && argc != 7)
+ {
+ fprintf (stderr, "Usage: test_opus_custom <rate> <channels> <frame size> "
+ " <bytes per packet> [<complexity> [packet loss rate]] "
+ "<input> <output>\n");
+ return 1;
+ }
+
+ rate = (opus_int32)atol(argv[1]);
+ channels = atoi(argv[2]);
+ frame_size = atoi(argv[3]);
+ mode = opus_custom_mode_create(rate, frame_size, NULL);
+ if (mode == NULL)
+ {
+ fprintf(stderr, "failed to create a mode\n");
+ return 1;
+ }
+
+ bytes_per_packet = atoi(argv[4]);
+ if (bytes_per_packet < 0 || bytes_per_packet > MAX_PACKET)
+ {
+ fprintf (stderr, "bytes per packet must be between 0 and %d\n",
+ MAX_PACKET);
+ return 1;
+ }
+
+ inFile = argv[argc-2];
+ fin = fopen(inFile, "rb");
+ if (!fin)
+ {
+ fprintf (stderr, "Could not open input file %s\n", argv[argc-2]);
+ return 1;
+ }
+ outFile = argv[argc-1];
+ fout = fopen(outFile, "wb+");
+ if (!fout)
+ {
+ fprintf (stderr, "Could not open output file %s\n", argv[argc-1]);
+ fclose(fin);
+ return 1;
+ }
+
+ enc = opus_custom_encoder_create(mode, channels, &err);
+ if (err != 0)
+ {
+ fprintf(stderr, "Failed to create the encoder: %s\n", opus_strerror(err));
+ fclose(fin);
+ fclose(fout);
+ return 1;
+ }
+ dec = opus_custom_decoder_create(mode, channels, &err);
+ if (err != 0)
+ {
+ fprintf(stderr, "Failed to create the decoder: %s\n", opus_strerror(err));
+ fclose(fin);
+ fclose(fout);
+ return 1;
+ }
+ opus_custom_decoder_ctl(dec, OPUS_GET_LOOKAHEAD(&skip));
+
+ if (argc>7)
+ {
+ complexity=atoi(argv[5]);
+ opus_custom_encoder_ctl(enc,OPUS_SET_COMPLEXITY(complexity));
+ }
+
+ in = (opus_int16*)malloc(frame_size*channels*sizeof(opus_int16));
+ out = (opus_int16*)malloc(frame_size*channels*sizeof(opus_int16));
+
+ while (!feof(fin))
+ {
+ int ret;
+ err = fread(in, sizeof(short), frame_size*channels, fin);
+ if (feof(fin))
+ break;
+ len = opus_custom_encode(enc, in, frame_size, data, bytes_per_packet);
+ if (len <= 0)
+ fprintf (stderr, "opus_custom_encode() failed: %s\n", opus_strerror(len));
+
+ /* This is for simulating bit errors */
+#if 0
+ int errors = 0;
+ int eid = 0;
+ /* This simulates random bit error */
+ for (i=0;i<len*8;i++)
+ {
+ if (rand()%atoi(argv[8])==0)
+ {
+ if (i<64)
+ {
+ errors++;
+ eid = i;
+ }
+ data[i/8] ^= 1<<(7-(i%8));
+ }
+ }
+ if (errors == 1)
+ data[eid/8] ^= 1<<(7-(eid%8));
+ else if (errors%2 == 1)
+ data[rand()%8] ^= 1<<rand()%8;
+#endif
+
+#if 1 /* Set to zero to use the encoder's output instead */
+ /* This is to simulate packet loss */
+ if (argc==9 && rand()%1000<atoi(argv[argc-3]))
+ /*if (errors && (errors%2==0))*/
+ ret = opus_custom_decode(dec, NULL, len, out, frame_size);
+ else
+ ret = opus_custom_decode(dec, data, len, out, frame_size);
+ if (ret < 0)
+ fprintf(stderr, "opus_custom_decode() failed: %s\n", opus_strerror(ret));
+#else
+ for (i=0;i<ret*channels;i++)
+ out[i] = in[i];
+#endif
+#if !(defined (OPUS_FIXED_POINT) && !defined(CUSTOM_MODES)) && defined(RESYNTH)
+ for (i=0;i<ret*channels;i++)
+ {
+ rmsd += (in[i]-out[i])*1.0*(in[i]-out[i]);
+ /*out[i] -= in[i];*/
+ }
+#endif
+ count++;
+ fwrite(out+skip*channels, sizeof(short), (ret-skip)*channels, fout);
+ skip = 0;
+ }
+ PRINT_MIPS(stderr);
+
+ opus_custom_encoder_destroy(enc);
+ opus_custom_decoder_destroy(dec);
+ fclose(fin);
+ fclose(fout);
+ opus_custom_mode_destroy(mode);
+ free(in);
+ free(out);
+#if !(defined (OPUS_FIXED_POINT) && !defined(CUSTOM_MODES)) && defined(RESYNTH)
+ if (rmsd > 0)
+ {
+ rmsd = sqrt(rmsd/(1.0*frame_size*channels*count));
+ fprintf (stderr, "Error: encoder doesn't match decoder\n");
+ fprintf (stderr, "RMS mismatch is %f\n", rmsd);
+ return 1;
+ } else {
+ fprintf (stderr, "Encoder matches decoder!!\n");
+ }
+#endif
+ return 0;
+}
+
diff --git a/drivers/opus/celt/opus_modes.h b/drivers/opus/celt/opus_modes.h
new file mode 100644
index 0000000000..38e5844535
--- /dev/null
+++ b/drivers/opus/celt/opus_modes.h
@@ -0,0 +1,83 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Copyright (c) 2008 Gregory Maxwell
+ Written by Jean-Marc Valin and Gregory Maxwell */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef OPUS_MODES_H
+#define OPUS_MODES_H
+
+#include "opus/opus_types.h"
+#include "opus/celt/celt.h"
+#include "opus/celt/arch.h"
+#include "opus/celt/mdct.h"
+#include "opus/celt/entenc.h"
+#include "opus/celt/entdec.h"
+
+#define MAX_PERIOD 1024
+
+#ifndef OVERLAP
+#define OVERLAP(mode) ((mode)->overlap)
+#endif
+
+#ifndef FRAMESIZE
+#define FRAMESIZE(mode) ((mode)->mdctSize)
+#endif
+
+typedef struct {
+ int size;
+ const opus_int16 *index;
+ const unsigned char *bits;
+ const unsigned char *caps;
+} PulseCache;
+
+/** Mode definition (opaque)
+ @brief Mode definition
+ */
+struct OpusCustomMode {
+ opus_int32 Fs;
+ int overlap;
+
+ int nbEBands;
+ int effEBands;
+ opus_val16 preemph[4];
+ const opus_int16 *eBands; /**< Definition for each "pseudo-critical band" */
+
+ int maxLM;
+ int nbShortMdcts;
+ int shortMdctSize;
+
+ int nbAllocVectors; /**< Number of lines in the matrix below */
+ const unsigned char *allocVectors; /**< Number of bits in each band for several rates */
+ const opus_int16 *logN;
+
+ const opus_val16 *window;
+ celt_mdct_lookup mdct;
+ PulseCache cache;
+};
+
+
+#endif
diff --git a/drivers/opus/celt/os_support.h b/drivers/opus/celt/os_support.h
new file mode 100644
index 0000000000..e1cf884467
--- /dev/null
+++ b/drivers/opus/celt/os_support.h
@@ -0,0 +1,92 @@
+/* Copyright (C) 2007 Jean-Marc Valin
+
+ File: os_support.h
+ This is the (tiny) OS abstraction layer. Aside from math.h, this is the
+ only place where system headers are allowed.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef OS_SUPPORT_H
+#define OS_SUPPORT_H
+
+#ifdef CUSTOM_SUPPORT
+# include "custom_support.h"
+#endif
+
+#include "opus/opus_types.h"
+#include "opus/opus_defines.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/** Opus wrapper for malloc(). To do your own dynamic allocation, all you need to do is replace this function and opus_free */
+#ifndef OVERRIDE_OPUS_ALLOC
+static OPUS_INLINE void *opus_alloc (size_t size)
+{
+ return malloc(size);
+}
+#endif
+
+/** Same as celt_alloc(), except that the area is only needed inside a CELT call (might cause problem with wideband though) */
+#ifndef OVERRIDE_OPUS_ALLOC_SCRATCH
+static OPUS_INLINE void *opus_alloc_scratch (size_t size)
+{
+ /* Scratch space doesn't need to be cleared */
+ return opus_alloc(size);
+}
+#endif
+
+/** Opus wrapper for free(). To do your own dynamic allocation, all you need to do is replace this function and opus_alloc */
+#ifndef OVERRIDE_OPUS_FREE
+static OPUS_INLINE void opus_free (void *ptr)
+{
+ free(ptr);
+}
+#endif
+
+/** Copy n bytes of memory from src to dst. The 0* term provides compile-time type checking */
+#ifndef OVERRIDE_OPUS_COPY
+#define OPUS_COPY(dst, src, n) (memcpy((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) ))
+#endif
+
+/** Copy n bytes of memory from src to dst, allowing overlapping regions. The 0* term
+ provides compile-time type checking */
+#ifndef OVERRIDE_OPUS_MOVE
+#define OPUS_MOVE(dst, src, n) (memmove((dst), (src), (n)*sizeof(*(dst)) + 0*((dst)-(src)) ))
+#endif
+
+/** Set n elements of dst to zero, starting at address s */
+#ifndef OVERRIDE_OPUS_CLEAR
+#define OPUS_CLEAR(dst, n) (memset((dst), 0, (n)*sizeof(*(dst))))
+#endif
+
+/*#ifdef __GNUC__
+#pragma GCC poison printf sprintf
+#pragma GCC poison malloc free realloc calloc
+#endif*/
+
+#endif /* OS_SUPPORT_H */
+
diff --git a/drivers/opus/celt/pitch.c b/drivers/opus/celt/pitch.c
new file mode 100644
index 0000000000..c7c2b98c00
--- /dev/null
+++ b/drivers/opus/celt/pitch.c
@@ -0,0 +1,537 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/**
+ @file pitch.c
+ @brief Pitch analysis
+ */
+
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/celt/pitch.h"
+#include "opus/celt/os_support.h"
+#include "opus/celt/opus_modes.h"
+#include "opus/celt/stack_alloc.h"
+#include "opus/celt/mathops.h"
+#include "opus/celt/celt_lpc.h"
+
+static void find_best_pitch(opus_val32 *xcorr, opus_val16 *y, int len,
+ int max_pitch, int *best_pitch
+#ifdef OPUS_FIXED_POINT
+ , int yshift, opus_val32 maxcorr
+#endif
+ )
+{
+ int i, j;
+ opus_val32 Syy=1;
+ opus_val16 best_num[2];
+ opus_val32 best_den[2];
+#ifdef OPUS_FIXED_POINT
+ int xshift;
+
+ xshift = celt_ilog2(maxcorr)-14;
+#endif
+
+ best_num[0] = -1;
+ best_num[1] = -1;
+ best_den[0] = 0;
+ best_den[1] = 0;
+ best_pitch[0] = 0;
+ best_pitch[1] = 1;
+ for (j=0;j<len;j++)
+ Syy = ADD32(Syy, SHR32(MULT16_16(y[j],y[j]), yshift));
+ for (i=0;i<max_pitch;i++)
+ {
+ if (xcorr[i]>0)
+ {
+ opus_val16 num;
+ opus_val32 xcorr16;
+ xcorr16 = EXTRACT16(VSHR32(xcorr[i], xshift));
+#ifndef OPUS_FIXED_POINT
+ /* Considering the range of xcorr16, this should avoid both underflows
+ and overflows (inf) when squaring xcorr16 */
+ xcorr16 *= 1e-12f;
+#endif
+ num = MULT16_16_Q15(xcorr16,xcorr16);
+ if (MULT16_32_Q15(num,best_den[1]) > MULT16_32_Q15(best_num[1],Syy))
+ {
+ if (MULT16_32_Q15(num,best_den[0]) > MULT16_32_Q15(best_num[0],Syy))
+ {
+ best_num[1] = best_num[0];
+ best_den[1] = best_den[0];
+ best_pitch[1] = best_pitch[0];
+ best_num[0] = num;
+ best_den[0] = Syy;
+ best_pitch[0] = i;
+ } else {
+ best_num[1] = num;
+ best_den[1] = Syy;
+ best_pitch[1] = i;
+ }
+ }
+ }
+ Syy += SHR32(MULT16_16(y[i+len],y[i+len]),yshift) - SHR32(MULT16_16(y[i],y[i]),yshift);
+ Syy = MAX32(1, Syy);
+ }
+}
+
+static void celt_fir5(const opus_val16 *x,
+ const opus_val16 *num,
+ opus_val16 *y,
+ int N,
+ opus_val16 *mem)
+{
+ int i;
+ opus_val16 num0, num1, num2, num3, num4;
+ opus_val32 mem0, mem1, mem2, mem3, mem4;
+ num0=num[0];
+ num1=num[1];
+ num2=num[2];
+ num3=num[3];
+ num4=num[4];
+ mem0=mem[0];
+ mem1=mem[1];
+ mem2=mem[2];
+ mem3=mem[3];
+ mem4=mem[4];
+ for (i=0;i<N;i++)
+ {
+ opus_val32 sum = SHL32(EXTEND32(x[i]), SIG_SHIFT);
+ sum = MAC16_16(sum,num0,mem0);
+ sum = MAC16_16(sum,num1,mem1);
+ sum = MAC16_16(sum,num2,mem2);
+ sum = MAC16_16(sum,num3,mem3);
+ sum = MAC16_16(sum,num4,mem4);
+ mem4 = mem3;
+ mem3 = mem2;
+ mem2 = mem1;
+ mem1 = mem0;
+ mem0 = x[i];
+ y[i] = ROUND16(sum, SIG_SHIFT);
+ }
+ mem[0]=mem0;
+ mem[1]=mem1;
+ mem[2]=mem2;
+ mem[3]=mem3;
+ mem[4]=mem4;
+}
+
+
+void pitch_downsample(celt_sig * OPUS_RESTRICT x[], opus_val16 * OPUS_RESTRICT x_lp,
+ int len, int C, int arch)
+{
+ int i;
+ opus_val32 ac[5];
+ opus_val16 tmp=Q15ONE;
+ opus_val16 lpc[4], mem[5]={0,0,0,0,0};
+ opus_val16 lpc2[5];
+ opus_val16 c1 = QCONST16(.8f,15);
+#ifdef OPUS_FIXED_POINT
+ int shift;
+ opus_val32 maxabs = celt_maxabs32(x[0], len);
+ if (C==2)
+ {
+ opus_val32 maxabs_1 = celt_maxabs32(x[1], len);
+ maxabs = MAX32(maxabs, maxabs_1);
+ }
+ if (maxabs<1)
+ maxabs=1;
+ shift = celt_ilog2(maxabs)-10;
+ if (shift<0)
+ shift=0;
+ if (C==2)
+ shift++;
+#endif
+ for (i=1;i<len>>1;i++)
+ x_lp[i] = SHR32(HALF32(HALF32(x[0][(2*i-1)]+x[0][(2*i+1)])+x[0][2*i]), shift);
+ x_lp[0] = SHR32(HALF32(HALF32(x[0][1])+x[0][0]), shift);
+ if (C==2)
+ {
+ for (i=1;i<len>>1;i++)
+ x_lp[i] += SHR32(HALF32(HALF32(x[1][(2*i-1)]+x[1][(2*i+1)])+x[1][2*i]), shift);
+ x_lp[0] += SHR32(HALF32(HALF32(x[1][1])+x[1][0]), shift);
+ }
+
+ _celt_autocorr(x_lp, ac, NULL, 0,
+ 4, len>>1, arch);
+
+ /* Noise floor -40 dB */
+#ifdef OPUS_FIXED_POINT
+ ac[0] += SHR32(ac[0],13);
+#else
+ ac[0] *= 1.0001f;
+#endif
+ /* Lag windowing */
+ for (i=1;i<=4;i++)
+ {
+ /*ac[i] *= exp(-.5*(2*M_PI*.002*i)*(2*M_PI*.002*i));*/
+#ifdef OPUS_FIXED_POINT
+ ac[i] -= MULT16_32_Q15(2*i*i, ac[i]);
+#else
+ ac[i] -= ac[i]*(.008f*i)*(.008f*i);
+#endif
+ }
+
+ _celt_lpc(lpc, ac, 4);
+ for (i=0;i<4;i++)
+ {
+ tmp = MULT16_16_Q15(QCONST16(.9f,15), tmp);
+ lpc[i] = MULT16_16_Q15(lpc[i], tmp);
+ }
+ /* Add a zero */
+ lpc2[0] = lpc[0] + QCONST16(.8f,SIG_SHIFT);
+ lpc2[1] = lpc[1] + MULT16_16_Q15(c1,lpc[0]);
+ lpc2[2] = lpc[2] + MULT16_16_Q15(c1,lpc[1]);
+ lpc2[3] = lpc[3] + MULT16_16_Q15(c1,lpc[2]);
+ lpc2[4] = MULT16_16_Q15(c1,lpc[3]);
+ celt_fir5(x_lp, lpc2, x_lp, len>>1, mem);
+}
+
+#if 0 /* This is a simple version of the pitch correlation that should work
+ well on DSPs like Blackfin and TI C5x/C6x */
+
+#ifdef OPUS_FIXED_POINT
+opus_val32
+#else
+void
+#endif
+celt_pitch_xcorr(opus_val16 *x, opus_val16 *y, opus_val32 *xcorr, int len, int max_pitch)
+{
+ int i, j;
+#ifdef OPUS_FIXED_POINT
+ opus_val32 maxcorr=1;
+#endif
+ for (i=0;i<max_pitch;i++)
+ {
+ opus_val32 sum = 0;
+ for (j=0;j<len;j++)
+ sum = MAC16_16(sum, x[j],y[i+j]);
+ xcorr[i] = sum;
+#ifdef OPUS_FIXED_POINT
+ maxcorr = MAX32(maxcorr, sum);
+#endif
+ }
+#ifdef OPUS_FIXED_POINT
+ return maxcorr;
+#endif
+}
+
+#else /* Unrolled version of the pitch correlation -- runs faster on x86 and ARM */
+
+#ifdef OPUS_FIXED_POINT
+opus_val32
+#else
+void
+#endif
+celt_pitch_xcorr_c(const opus_val16 *_x, const opus_val16 *_y, opus_val32 *xcorr, int len, int max_pitch)
+{
+ int i,j;
+ /*The EDSP version requires that max_pitch is at least 1, and that _x is
+ 32-bit aligned.
+ Since it's hard to put asserts in assembly, put them here.*/
+ celt_assert(max_pitch>0);
+ celt_assert((((unsigned char *)_x-(unsigned char *)NULL)&3)==0);
+#ifdef OPUS_FIXED_POINT
+ opus_val32 maxcorr=1;
+#endif
+ for (i=0;i<max_pitch-3;i+=4)
+ {
+ opus_val32 sum[4]={0,0,0,0};
+ xcorr_kernel(_x, _y+i, sum, len);
+ xcorr[i]=sum[0];
+ xcorr[i+1]=sum[1];
+ xcorr[i+2]=sum[2];
+ xcorr[i+3]=sum[3];
+#ifdef OPUS_FIXED_POINT
+ sum[0] = MAX32(sum[0], sum[1]);
+ sum[2] = MAX32(sum[2], sum[3]);
+ sum[0] = MAX32(sum[0], sum[2]);
+ maxcorr = MAX32(maxcorr, sum[0]);
+#endif
+ }
+ /* In case max_pitch isn't a multiple of 4, do non-unrolled version. */
+ for (;i<max_pitch;i++)
+ {
+ opus_val32 sum = 0;
+ for (j=0;j<len;j++)
+ sum = MAC16_16(sum, _x[j],_y[i+j]);
+ xcorr[i] = sum;
+#ifdef OPUS_FIXED_POINT
+ maxcorr = MAX32(maxcorr, sum);
+#endif
+ }
+#ifdef OPUS_FIXED_POINT
+ return maxcorr;
+#endif
+}
+
+#endif
+void pitch_search(const opus_val16 * OPUS_RESTRICT x_lp, opus_val16 * OPUS_RESTRICT y,
+ int len, int max_pitch, int *pitch, int arch)
+{
+ int i, j;
+ int lag;
+ int best_pitch[2]={0,0};
+ VARDECL(opus_val16, x_lp4);
+ VARDECL(opus_val16, y_lp4);
+ VARDECL(opus_val32, xcorr);
+#ifdef OPUS_FIXED_POINT
+ opus_val32 maxcorr;
+ opus_val32 xmax, ymax;
+ int shift=0;
+#endif
+ int offset;
+
+ SAVE_STACK;
+
+ celt_assert(len>0);
+ celt_assert(max_pitch>0);
+ lag = len+max_pitch;
+
+ ALLOC(x_lp4, len>>2, opus_val16);
+ ALLOC(y_lp4, lag>>2, opus_val16);
+ ALLOC(xcorr, max_pitch>>1, opus_val32);
+
+ /* Downsample by 2 again */
+ for (j=0;j<len>>2;j++)
+ x_lp4[j] = x_lp[2*j];
+ for (j=0;j<lag>>2;j++)
+ y_lp4[j] = y[2*j];
+
+#ifdef OPUS_FIXED_POINT
+ xmax = celt_maxabs16(x_lp4, len>>2);
+ ymax = celt_maxabs16(y_lp4, lag>>2);
+ shift = celt_ilog2(MAX32(1, MAX32(xmax, ymax)))-11;
+ if (shift>0)
+ {
+ for (j=0;j<len>>2;j++)
+ x_lp4[j] = SHR16(x_lp4[j], shift);
+ for (j=0;j<lag>>2;j++)
+ y_lp4[j] = SHR16(y_lp4[j], shift);
+ /* Use double the shift for a MAC */
+ shift *= 2;
+ } else {
+ shift = 0;
+ }
+#endif
+
+ /* Coarse search with 4x decimation */
+
+#ifdef OPUS_FIXED_POINT
+ maxcorr =
+#endif
+ celt_pitch_xcorr(x_lp4, y_lp4, xcorr, len>>2, max_pitch>>2, arch);
+
+ find_best_pitch(xcorr, y_lp4, len>>2, max_pitch>>2, best_pitch
+#ifdef OPUS_FIXED_POINT
+ , 0, maxcorr
+#endif
+ );
+
+ /* Finer search with 2x decimation */
+#ifdef OPUS_FIXED_POINT
+ maxcorr=1;
+#endif
+ for (i=0;i<max_pitch>>1;i++)
+ {
+ opus_val32 sum=0;
+ xcorr[i] = 0;
+ if (abs(i-2*best_pitch[0])>2 && abs(i-2*best_pitch[1])>2)
+ continue;
+ for (j=0;j<len>>1;j++)
+ sum += SHR32(MULT16_16(x_lp[j],y[i+j]), shift);
+ xcorr[i] = MAX32(-1, sum);
+#ifdef OPUS_FIXED_POINT
+ maxcorr = MAX32(maxcorr, sum);
+#endif
+ }
+ find_best_pitch(xcorr, y, len>>1, max_pitch>>1, best_pitch
+#ifdef OPUS_FIXED_POINT
+ , shift+1, maxcorr
+#endif
+ );
+
+ /* Refine by pseudo-interpolation */
+ if (best_pitch[0]>0 && best_pitch[0]<(max_pitch>>1)-1)
+ {
+ opus_val32 a, b, c;
+ a = xcorr[best_pitch[0]-1];
+ b = xcorr[best_pitch[0]];
+ c = xcorr[best_pitch[0]+1];
+ if ((c-a) > MULT16_32_Q15(QCONST16(.7f,15),b-a))
+ offset = 1;
+ else if ((a-c) > MULT16_32_Q15(QCONST16(.7f,15),b-c))
+ offset = -1;
+ else
+ offset = 0;
+ } else {
+ offset = 0;
+ }
+ *pitch = 2*best_pitch[0]-offset;
+
+ RESTORE_STACK;
+}
+
+static const int second_check[16] = {0, 0, 3, 2, 3, 2, 5, 2, 3, 2, 3, 2, 5, 2, 3, 2};
+opus_val16 remove_doubling(opus_val16 *x, int maxperiod, int minperiod,
+ int N, int *T0_, int prev_period, opus_val16 prev_gain)
+{
+ int k, i, T, T0;
+ opus_val16 g, g0;
+ opus_val16 pg;
+ opus_val32 xy,xx,yy,xy2;
+ opus_val32 xcorr[3];
+ opus_val32 best_xy, best_yy;
+ int offset;
+ int minperiod0;
+ VARDECL(opus_val32, yy_lookup);
+ SAVE_STACK;
+
+ minperiod0 = minperiod;
+ maxperiod /= 2;
+ minperiod /= 2;
+ *T0_ /= 2;
+ prev_period /= 2;
+ N /= 2;
+ x += maxperiod;
+ if (*T0_>=maxperiod)
+ *T0_=maxperiod-1;
+
+ T = T0 = *T0_;
+ ALLOC(yy_lookup, maxperiod+1, opus_val32);
+ dual_inner_prod(x, x, x-T0, N, &xx, &xy);
+ yy_lookup[0] = xx;
+ yy=xx;
+ for (i=1;i<=maxperiod;i++)
+ {
+ yy = yy+MULT16_16(x[-i],x[-i])-MULT16_16(x[N-i],x[N-i]);
+ yy_lookup[i] = MAX32(0, yy);
+ }
+ yy = yy_lookup[T0];
+ best_xy = xy;
+ best_yy = yy;
+#ifdef OPUS_FIXED_POINT
+ {
+ opus_val32 x2y2;
+ int sh, t;
+ x2y2 = 1+HALF32(MULT32_32_Q31(xx,yy));
+ sh = celt_ilog2(x2y2)>>1;
+ t = VSHR32(x2y2, 2*(sh-7));
+ g = g0 = VSHR32(MULT16_32_Q15(celt_rsqrt_norm(t), xy),sh+1);
+ }
+#else
+ g = g0 = xy/celt_sqrt(1+xx*yy);
+#endif
+ /* Look for any pitch at T/k */
+ for (k=2;k<=15;k++)
+ {
+ int T1, T1b;
+ opus_val16 g1;
+ opus_val16 cont=0;
+ opus_val16 thresh;
+ T1 = (2*T0+k)/(2*k);
+ if (T1 < minperiod)
+ break;
+ /* Look for another strong correlation at T1b */
+ if (k==2)
+ {
+ if (T1+T0>maxperiod)
+ T1b = T0;
+ else
+ T1b = T0+T1;
+ } else
+ {
+ T1b = (2*second_check[k]*T0+k)/(2*k);
+ }
+ dual_inner_prod(x, &x[-T1], &x[-T1b], N, &xy, &xy2);
+ xy += xy2;
+ yy = yy_lookup[T1] + yy_lookup[T1b];
+#ifdef OPUS_FIXED_POINT
+ {
+ opus_val32 x2y2;
+ int sh, t;
+ x2y2 = 1+MULT32_32_Q31(xx,yy);
+ sh = celt_ilog2(x2y2)>>1;
+ t = VSHR32(x2y2, 2*(sh-7));
+ g1 = VSHR32(MULT16_32_Q15(celt_rsqrt_norm(t), xy),sh+1);
+ }
+#else
+ g1 = xy/celt_sqrt(1+2.f*xx*1.f*yy);
+#endif
+ if (abs(T1-prev_period)<=1)
+ cont = prev_gain;
+ else if (abs(T1-prev_period)<=2 && 5*k*k < T0)
+ cont = HALF32(prev_gain);
+ else
+ cont = 0;
+ thresh = MAX16(QCONST16(.3f,15), MULT16_16_Q15(QCONST16(.7f,15),g0)-cont);
+ /* Bias against very high pitch (very short period) to avoid false-positives
+ due to short-term correlation */
+ if (T1<3*minperiod)
+ thresh = MAX16(QCONST16(.4f,15), MULT16_16_Q15(QCONST16(.85f,15),g0)-cont);
+ else if (T1<2*minperiod)
+ thresh = MAX16(QCONST16(.5f,15), MULT16_16_Q15(QCONST16(.9f,15),g0)-cont);
+ if (g1 > thresh)
+ {
+ best_xy = xy;
+ best_yy = yy;
+ T = T1;
+ g = g1;
+ }
+ }
+ best_xy = MAX32(0, best_xy);
+ if (best_yy <= best_xy)
+ pg = Q15ONE;
+ else
+ pg = SHR32(frac_div32(best_xy,best_yy+1),16);
+
+ for (k=0;k<3;k++)
+ {
+ int T1 = T+k-1;
+ xy = 0;
+ for (i=0;i<N;i++)
+ xy = MAC16_16(xy, x[i], x[i-T1]);
+ xcorr[k] = xy;
+ }
+ if ((xcorr[2]-xcorr[0]) > MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[0]))
+ offset = 1;
+ else if ((xcorr[0]-xcorr[2]) > MULT16_32_Q15(QCONST16(.7f,15),xcorr[1]-xcorr[2]))
+ offset = -1;
+ else
+ offset = 0;
+ if (pg > g)
+ pg = g;
+ *T0_ = 2*T+offset;
+
+ if (*T0_<minperiod0)
+ *T0_=minperiod0;
+ RESTORE_STACK;
+ return pg;
+}
diff --git a/drivers/opus/celt/pitch.h b/drivers/opus/celt/pitch.h
new file mode 100644
index 0000000000..f599f5fc76
--- /dev/null
+++ b/drivers/opus/celt/pitch.h
@@ -0,0 +1,173 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/**
+ @file pitch.h
+ @brief Pitch analysis
+ */
+
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef PITCH_H
+#define PITCH_H
+
+#include "opus/celt/opus_modes.h"
+#include "opus/celt/cpu_support.h"
+
+#if defined(__SSE__) && !defined(OPUS_FIXED_POINT)
+#include "x86/pitch_sse.h"
+#endif
+
+#if defined(OPUS_ARM_ASM) && defined(OPUS_FIXED_POINT)
+# include "arm/pitch_arm.h"
+#endif
+
+void pitch_downsample(celt_sig * OPUS_RESTRICT x[], opus_val16 * OPUS_RESTRICT x_lp,
+ int len, int C, int arch);
+
+void pitch_search(const opus_val16 * OPUS_RESTRICT x_lp, opus_val16 * OPUS_RESTRICT y,
+ int len, int max_pitch, int *pitch, int arch);
+
+opus_val16 remove_doubling(opus_val16 *x, int maxperiod, int minperiod,
+ int N, int *T0, int prev_period, opus_val16 prev_gain);
+
+/* OPT: This is the kernel you really want to optimize. It gets used a lot
+ by the prefilter and by the PLC. */
+#ifndef OVERRIDE_XCORR_KERNEL
+static OPUS_INLINE void xcorr_kernel(const opus_val16 * x, const opus_val16 * y, opus_val32 sum[4], int len)
+{
+ int j;
+ opus_val16 y_0, y_1, y_2, y_3;
+ celt_assert(len>=3);
+ y_3=0; /* gcc doesn't realize that y_3 can't be used uninitialized */
+ y_0=*y++;
+ y_1=*y++;
+ y_2=*y++;
+ for (j=0;j<len-3;j+=4)
+ {
+ opus_val16 tmp;
+ tmp = *x++;
+ y_3=*y++;
+ sum[0] = MAC16_16(sum[0],tmp,y_0);
+ sum[1] = MAC16_16(sum[1],tmp,y_1);
+ sum[2] = MAC16_16(sum[2],tmp,y_2);
+ sum[3] = MAC16_16(sum[3],tmp,y_3);
+ tmp=*x++;
+ y_0=*y++;
+ sum[0] = MAC16_16(sum[0],tmp,y_1);
+ sum[1] = MAC16_16(sum[1],tmp,y_2);
+ sum[2] = MAC16_16(sum[2],tmp,y_3);
+ sum[3] = MAC16_16(sum[3],tmp,y_0);
+ tmp=*x++;
+ y_1=*y++;
+ sum[0] = MAC16_16(sum[0],tmp,y_2);
+ sum[1] = MAC16_16(sum[1],tmp,y_3);
+ sum[2] = MAC16_16(sum[2],tmp,y_0);
+ sum[3] = MAC16_16(sum[3],tmp,y_1);
+ tmp=*x++;
+ y_2=*y++;
+ sum[0] = MAC16_16(sum[0],tmp,y_3);
+ sum[1] = MAC16_16(sum[1],tmp,y_0);
+ sum[2] = MAC16_16(sum[2],tmp,y_1);
+ sum[3] = MAC16_16(sum[3],tmp,y_2);
+ }
+ if (j++<len)
+ {
+ opus_val16 tmp = *x++;
+ y_3=*y++;
+ sum[0] = MAC16_16(sum[0],tmp,y_0);
+ sum[1] = MAC16_16(sum[1],tmp,y_1);
+ sum[2] = MAC16_16(sum[2],tmp,y_2);
+ sum[3] = MAC16_16(sum[3],tmp,y_3);
+ }
+ if (j++<len)
+ {
+ opus_val16 tmp=*x++;
+ y_0=*y++;
+ sum[0] = MAC16_16(sum[0],tmp,y_1);
+ sum[1] = MAC16_16(sum[1],tmp,y_2);
+ sum[2] = MAC16_16(sum[2],tmp,y_3);
+ sum[3] = MAC16_16(sum[3],tmp,y_0);
+ }
+ if (j<len)
+ {
+ opus_val16 tmp=*x++;
+ y_1=*y++;
+ sum[0] = MAC16_16(sum[0],tmp,y_2);
+ sum[1] = MAC16_16(sum[1],tmp,y_3);
+ sum[2] = MAC16_16(sum[2],tmp,y_0);
+ sum[3] = MAC16_16(sum[3],tmp,y_1);
+ }
+}
+#endif /* OVERRIDE_XCORR_KERNEL */
+
+#ifndef OVERRIDE_DUAL_INNER_PROD
+static OPUS_INLINE void dual_inner_prod(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02,
+ int N, opus_val32 *xy1, opus_val32 *xy2)
+{
+ int i;
+ opus_val32 xy01=0;
+ opus_val32 xy02=0;
+ for (i=0;i<N;i++)
+ {
+ xy01 = MAC16_16(xy01, x[i], y01[i]);
+ xy02 = MAC16_16(xy02, x[i], y02[i]);
+ }
+ *xy1 = xy01;
+ *xy2 = xy02;
+}
+#endif
+
+#ifdef OPUS_FIXED_POINT
+opus_val32
+#else
+void
+#endif
+celt_pitch_xcorr_c(const opus_val16 *_x, const opus_val16 *_y,
+ opus_val32 *xcorr, int len, int max_pitch);
+
+#if !defined(OVERRIDE_PITCH_XCORR)
+/*Is run-time CPU detection enabled on this platform?*/
+# if defined(OPUS_HAVE_RTCD)
+extern
+# if defined(OPUS_FIXED_POINT)
+opus_val32
+# else
+void
+# endif
+(*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *,
+ const opus_val16 *, opus_val32 *, int, int);
+
+# define celt_pitch_xcorr(_x, _y, xcorr, len, max_pitch, arch) \
+ ((*CELT_PITCH_XCORR_IMPL[(arch)&OPUS_ARCHMASK])(_x, _y, \
+ xcorr, len, max_pitch))
+# else
+# define celt_pitch_xcorr(_x, _y, xcorr, len, max_pitch, arch) \
+ ((void)(arch),celt_pitch_xcorr_c(_x, _y, xcorr, len, max_pitch))
+# endif
+#endif
+
+#endif
diff --git a/drivers/opus/celt/quant_bands.c b/drivers/opus/celt/quant_bands.c
new file mode 100644
index 0000000000..e64ed28f22
--- /dev/null
+++ b/drivers/opus/celt/quant_bands.c
@@ -0,0 +1,556 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/celt/quant_bands.h"
+#include "opus/celt/laplace.h"
+#include <math.h>
+#include "opus/celt/os_support.h"
+#include "opus/celt/arch.h"
+#include "opus/celt/mathops.h"
+#include "opus/celt/stack_alloc.h"
+#include "opus/celt/rate.h"
+
+#ifdef OPUS_FIXED_POINT
+/* Mean energy in each band quantized in Q4 */
+const signed char eMeans[25] = {
+ 103,100, 92, 85, 81,
+ 77, 72, 70, 78, 75,
+ 73, 71, 78, 74, 69,
+ 72, 70, 74, 76, 71,
+ 60, 60, 60, 60, 60
+};
+#else
+/* Mean energy in each band quantized in Q4 and converted back to float */
+const opus_val16 eMeans[25] = {
+ 6.437500f, 6.250000f, 5.750000f, 5.312500f, 5.062500f,
+ 4.812500f, 4.500000f, 4.375000f, 4.875000f, 4.687500f,
+ 4.562500f, 4.437500f, 4.875000f, 4.625000f, 4.312500f,
+ 4.500000f, 4.375000f, 4.625000f, 4.750000f, 4.437500f,
+ 3.750000f, 3.750000f, 3.750000f, 3.750000f, 3.750000f
+};
+#endif
+/* prediction coefficients: 0.9, 0.8, 0.65, 0.5 */
+#ifdef OPUS_FIXED_POINT
+static const opus_val16 pred_coef[4] = {29440, 26112, 21248, 16384};
+static const opus_val16 beta_coef[4] = {30147, 22282, 12124, 6554};
+static const opus_val16 beta_intra = 4915;
+#else
+static const opus_val16 pred_coef[4] = {29440/32768., 26112/32768., 21248/32768., 16384/32768.};
+static const opus_val16 beta_coef[4] = {30147/32768., 22282/32768., 12124/32768., 6554/32768.};
+static const opus_val16 beta_intra = 4915/32768.;
+#endif
+
+/*Parameters of the Laplace-like probability models used for the coarse energy.
+ There is one pair of parameters for each frame size, prediction type
+ (inter/intra), and band number.
+ The first number of each pair is the probability of 0, and the second is the
+ decay rate, both in Q8 precision.*/
+static const unsigned char e_prob_model[4][2][42] = {
+ /*120 sample frames.*/
+ {
+ /*Inter*/
+ {
+ 72, 127, 65, 129, 66, 128, 65, 128, 64, 128, 62, 128, 64, 128,
+ 64, 128, 92, 78, 92, 79, 92, 78, 90, 79, 116, 41, 115, 40,
+ 114, 40, 132, 26, 132, 26, 145, 17, 161, 12, 176, 10, 177, 11
+ },
+ /*Intra*/
+ {
+ 24, 179, 48, 138, 54, 135, 54, 132, 53, 134, 56, 133, 55, 132,
+ 55, 132, 61, 114, 70, 96, 74, 88, 75, 88, 87, 74, 89, 66,
+ 91, 67, 100, 59, 108, 50, 120, 40, 122, 37, 97, 43, 78, 50
+ }
+ },
+ /*240 sample frames.*/
+ {
+ /*Inter*/
+ {
+ 83, 78, 84, 81, 88, 75, 86, 74, 87, 71, 90, 73, 93, 74,
+ 93, 74, 109, 40, 114, 36, 117, 34, 117, 34, 143, 17, 145, 18,
+ 146, 19, 162, 12, 165, 10, 178, 7, 189, 6, 190, 8, 177, 9
+ },
+ /*Intra*/
+ {
+ 23, 178, 54, 115, 63, 102, 66, 98, 69, 99, 74, 89, 71, 91,
+ 73, 91, 78, 89, 86, 80, 92, 66, 93, 64, 102, 59, 103, 60,
+ 104, 60, 117, 52, 123, 44, 138, 35, 133, 31, 97, 38, 77, 45
+ }
+ },
+ /*480 sample frames.*/
+ {
+ /*Inter*/
+ {
+ 61, 90, 93, 60, 105, 42, 107, 41, 110, 45, 116, 38, 113, 38,
+ 112, 38, 124, 26, 132, 27, 136, 19, 140, 20, 155, 14, 159, 16,
+ 158, 18, 170, 13, 177, 10, 187, 8, 192, 6, 175, 9, 159, 10
+ },
+ /*Intra*/
+ {
+ 21, 178, 59, 110, 71, 86, 75, 85, 84, 83, 91, 66, 88, 73,
+ 87, 72, 92, 75, 98, 72, 105, 58, 107, 54, 115, 52, 114, 55,
+ 112, 56, 129, 51, 132, 40, 150, 33, 140, 29, 98, 35, 77, 42
+ }
+ },
+ /*960 sample frames.*/
+ {
+ /*Inter*/
+ {
+ 42, 121, 96, 66, 108, 43, 111, 40, 117, 44, 123, 32, 120, 36,
+ 119, 33, 127, 33, 134, 34, 139, 21, 147, 23, 152, 20, 158, 25,
+ 154, 26, 166, 21, 173, 16, 184, 13, 184, 10, 150, 13, 139, 15
+ },
+ /*Intra*/
+ {
+ 22, 178, 63, 114, 74, 82, 84, 83, 92, 82, 103, 62, 96, 72,
+ 96, 67, 101, 73, 107, 72, 113, 55, 118, 52, 125, 52, 118, 52,
+ 117, 55, 135, 49, 137, 39, 157, 32, 145, 29, 97, 33, 77, 40
+ }
+ }
+};
+
+static const unsigned char small_energy_icdf[3]={2,1,0};
+
+static opus_val32 loss_distortion(const opus_val16 *eBands, opus_val16 *oldEBands, int start, int end, int len, int C)
+{
+ int c, i;
+ opus_val32 dist = 0;
+ c=0; do {
+ for (i=start;i<end;i++)
+ {
+ opus_val16 d = SUB16(SHR16(eBands[i+c*len], 3), SHR16(oldEBands[i+c*len], 3));
+ dist = MAC16_16(dist, d,d);
+ }
+ } while (++c<C);
+ return MIN32(200,SHR32(dist,2*DB_SHIFT-6));
+}
+
+static int quant_coarse_energy_impl(const CELTMode *m, int start, int end,
+ const opus_val16 *eBands, opus_val16 *oldEBands,
+ opus_int32 budget, opus_int32 tell,
+ const unsigned char *prob_model, opus_val16 *error, ec_enc *enc,
+ int C, int LM, int intra, opus_val16 max_decay, int lfe)
+{
+ int i, c;
+ int badness = 0;
+ opus_val32 prev[2] = {0,0};
+ opus_val16 coef;
+ opus_val16 beta;
+
+ if (tell+3 <= budget)
+ ec_enc_bit_logp(enc, intra, 3);
+ if (intra)
+ {
+ coef = 0;
+ beta = beta_intra;
+ } else {
+ beta = beta_coef[LM];
+ coef = pred_coef[LM];
+ }
+
+ /* Encode at a fixed coarse resolution */
+ for (i=start;i<end;i++)
+ {
+ c=0;
+ do {
+ int bits_left;
+ int qi, qi0;
+ opus_val32 q;
+ opus_val16 x;
+ opus_val32 f, tmp;
+ opus_val16 oldE;
+ opus_val16 decay_bound;
+ x = eBands[i+c*m->nbEBands];
+ oldE = MAX16(-QCONST16(9.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]);
+#ifdef OPUS_FIXED_POINT
+ f = SHL32(EXTEND32(x),7) - PSHR32(MULT16_16(coef,oldE), 8) - prev[c];
+ /* Rounding to nearest integer here is really important! */
+ qi = (f+QCONST32(.5f,DB_SHIFT+7))>>(DB_SHIFT+7);
+ decay_bound = EXTRACT16(MAX32(-QCONST16(28.f,DB_SHIFT),
+ SUB32((opus_val32)oldEBands[i+c*m->nbEBands],max_decay)));
+#else
+ f = x-coef*oldE-prev[c];
+ /* Rounding to nearest integer here is really important! */
+ qi = (int)floor(.5f+f);
+ decay_bound = MAX16(-QCONST16(28.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]) - max_decay;
+#endif
+ /* Prevent the energy from going down too quickly (e.g. for bands
+ that have just one bin) */
+ if (qi < 0 && x < decay_bound)
+ {
+ qi += (int)SHR16(SUB16(decay_bound,x), DB_SHIFT);
+ if (qi > 0)
+ qi = 0;
+ }
+ qi0 = qi;
+ /* If we don't have enough bits to encode all the energy, just assume
+ something safe. */
+ tell = ec_tell(enc);
+ bits_left = budget-tell-3*C*(end-i);
+ if (i!=start && bits_left < 30)
+ {
+ if (bits_left < 24)
+ qi = IMIN(1, qi);
+ if (bits_left < 16)
+ qi = IMAX(-1, qi);
+ }
+ if (lfe && i>=2)
+ qi = IMIN(qi, 0);
+ if (budget-tell >= 15)
+ {
+ int pi;
+ pi = 2*IMIN(i,20);
+ ec_laplace_encode(enc, &qi,
+ prob_model[pi]<<7, prob_model[pi+1]<<6);
+ }
+ else if(budget-tell >= 2)
+ {
+ qi = IMAX(-1, IMIN(qi, 1));
+ ec_enc_icdf(enc, 2*qi^-(qi<0), small_energy_icdf, 2);
+ }
+ else if(budget-tell >= 1)
+ {
+ qi = IMIN(0, qi);
+ ec_enc_bit_logp(enc, -qi, 1);
+ }
+ else
+ qi = -1;
+ error[i+c*m->nbEBands] = PSHR32(f,7) - SHL16(qi,DB_SHIFT);
+ badness += abs(qi0-qi);
+ q = (opus_val32)SHL32(EXTEND32(qi),DB_SHIFT);
+
+ tmp = PSHR32(MULT16_16(coef,oldE),8) + prev[c] + SHL32(q,7);
+#ifdef OPUS_FIXED_POINT
+ tmp = MAX32(-QCONST32(28.f, DB_SHIFT+7), tmp);
+#endif
+ oldEBands[i+c*m->nbEBands] = PSHR32(tmp, 7);
+ prev[c] = prev[c] + SHL32(q,7) - MULT16_16(beta,PSHR32(q,8));
+ } while (++c < C);
+ }
+ return lfe ? 0 : badness;
+}
+
+void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd,
+ const opus_val16 *eBands, opus_val16 *oldEBands, opus_uint32 budget,
+ opus_val16 *error, ec_enc *enc, int C, int LM, int nbAvailableBytes,
+ int force_intra, opus_val32 *delayedIntra, int two_pass, int loss_rate, int lfe)
+{
+ int intra;
+ opus_val16 max_decay;
+ VARDECL(opus_val16, oldEBands_intra);
+ VARDECL(opus_val16, error_intra);
+ ec_enc enc_start_state;
+ opus_uint32 tell;
+ int badness1=0;
+ opus_int32 intra_bias;
+ opus_val32 new_distortion;
+ SAVE_STACK;
+
+ intra = force_intra || (!two_pass && *delayedIntra>2*C*(end-start) && nbAvailableBytes > (end-start)*C);
+ intra_bias = (opus_int32)((budget**delayedIntra*loss_rate)/(C*512));
+ new_distortion = loss_distortion(eBands, oldEBands, start, effEnd, m->nbEBands, C);
+
+ tell = ec_tell(enc);
+ if (tell+3 > budget)
+ two_pass = intra = 0;
+
+ max_decay = QCONST16(16.f,DB_SHIFT);
+ if (end-start>10)
+ {
+#ifdef OPUS_FIXED_POINT
+ max_decay = MIN32(max_decay, SHL32(EXTEND32(nbAvailableBytes),DB_SHIFT-3));
+#else
+ max_decay = MIN32(max_decay, .125f*nbAvailableBytes);
+#endif
+ }
+ if (lfe)
+ max_decay=3;
+ enc_start_state = *enc;
+
+ ALLOC(oldEBands_intra, C*m->nbEBands, opus_val16);
+ ALLOC(error_intra, C*m->nbEBands, opus_val16);
+ OPUS_COPY(oldEBands_intra, oldEBands, C*m->nbEBands);
+
+ if (two_pass || intra)
+ {
+ badness1 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands_intra, budget,
+ tell, e_prob_model[LM][1], error_intra, enc, C, LM, 1, max_decay, lfe);
+ }
+
+ if (!intra)
+ {
+ unsigned char *intra_buf;
+ ec_enc enc_intra_state;
+ opus_int32 tell_intra;
+ opus_uint32 nstart_bytes;
+ opus_uint32 nintra_bytes;
+ opus_uint32 save_bytes;
+ int badness2;
+ VARDECL(unsigned char, intra_bits);
+
+ tell_intra = ec_tell_frac(enc);
+
+ enc_intra_state = *enc;
+
+ nstart_bytes = ec_range_bytes(&enc_start_state);
+ nintra_bytes = ec_range_bytes(&enc_intra_state);
+ intra_buf = ec_get_buffer(&enc_intra_state) + nstart_bytes;
+ save_bytes = nintra_bytes-nstart_bytes;
+ if (save_bytes == 0)
+ save_bytes = ALLOC_NONE;
+ ALLOC(intra_bits, save_bytes, unsigned char);
+ /* Copy bits from intra bit-stream */
+ OPUS_COPY(intra_bits, intra_buf, nintra_bytes - nstart_bytes);
+
+ *enc = enc_start_state;
+
+ badness2 = quant_coarse_energy_impl(m, start, end, eBands, oldEBands, budget,
+ tell, e_prob_model[LM][intra], error, enc, C, LM, 0, max_decay, lfe);
+
+ if (two_pass && (badness1 < badness2 || (badness1 == badness2 && ((opus_int32)ec_tell_frac(enc))+intra_bias > tell_intra)))
+ {
+ *enc = enc_intra_state;
+ /* Copy intra bits to bit-stream */
+ OPUS_COPY(intra_buf, intra_bits, nintra_bytes - nstart_bytes);
+ OPUS_COPY(oldEBands, oldEBands_intra, C*m->nbEBands);
+ OPUS_COPY(error, error_intra, C*m->nbEBands);
+ intra = 1;
+ }
+ } else {
+ OPUS_COPY(oldEBands, oldEBands_intra, C*m->nbEBands);
+ OPUS_COPY(error, error_intra, C*m->nbEBands);
+ }
+
+ if (intra)
+ *delayedIntra = new_distortion;
+ else
+ *delayedIntra = ADD32(MULT16_32_Q15(MULT16_16_Q15(pred_coef[LM], pred_coef[LM]),*delayedIntra),
+ new_distortion);
+
+ RESTORE_STACK;
+}
+
+void quant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, ec_enc *enc, int C)
+{
+ int i, c;
+
+ /* Encode finer resolution */
+ for (i=start;i<end;i++)
+ {
+ opus_int16 frac = 1<<fine_quant[i];
+ if (fine_quant[i] <= 0)
+ continue;
+ c=0;
+ do {
+ int q2;
+ opus_val16 offset;
+#ifdef OPUS_FIXED_POINT
+ /* Has to be without rounding */
+ q2 = (error[i+c*m->nbEBands]+QCONST16(.5f,DB_SHIFT))>>(DB_SHIFT-fine_quant[i]);
+#else
+ q2 = (int)floor((error[i+c*m->nbEBands]+.5f)*frac);
+#endif
+ if (q2 > frac-1)
+ q2 = frac-1;
+ if (q2<0)
+ q2 = 0;
+ ec_enc_bits(enc, q2, fine_quant[i]);
+#ifdef OPUS_FIXED_POINT
+ offset = SUB16(SHR32(SHL32(EXTEND32(q2),DB_SHIFT)+QCONST16(.5f,DB_SHIFT),fine_quant[i]),QCONST16(.5f,DB_SHIFT));
+#else
+ offset = (q2+.5f)*(1<<(14-fine_quant[i]))*(1.f/16384) - .5f;
+#endif
+ oldEBands[i+c*m->nbEBands] += offset;
+ error[i+c*m->nbEBands] -= offset;
+ /*printf ("%f ", error[i] - offset);*/
+ } while (++c < C);
+ }
+}
+
+void quant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, int *fine_priority, int bits_left, ec_enc *enc, int C)
+{
+ int i, prio, c;
+
+ /* Use up the remaining bits */
+ for (prio=0;prio<2;prio++)
+ {
+ for (i=start;i<end && bits_left>=C ;i++)
+ {
+ if (fine_quant[i] >= MAX_FINE_BITS || fine_priority[i]!=prio)
+ continue;
+ c=0;
+ do {
+ int q2;
+ opus_val16 offset;
+ q2 = error[i+c*m->nbEBands]<0 ? 0 : 1;
+ ec_enc_bits(enc, q2, 1);
+#ifdef OPUS_FIXED_POINT
+ offset = SHR16(SHL16(q2,DB_SHIFT)-QCONST16(.5f,DB_SHIFT),fine_quant[i]+1);
+#else
+ offset = (q2-.5f)*(1<<(14-fine_quant[i]-1))*(1.f/16384);
+#endif
+ oldEBands[i+c*m->nbEBands] += offset;
+ bits_left--;
+ } while (++c < C);
+ }
+ }
+}
+
+void unquant_coarse_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int intra, ec_dec *dec, int C, int LM)
+{
+ const unsigned char *prob_model = e_prob_model[LM][intra];
+ int i, c;
+ opus_val32 prev[2] = {0, 0};
+ opus_val16 coef;
+ opus_val16 beta;
+ opus_int32 budget;
+ opus_int32 tell;
+
+ if (intra)
+ {
+ coef = 0;
+ beta = beta_intra;
+ } else {
+ beta = beta_coef[LM];
+ coef = pred_coef[LM];
+ }
+
+ budget = dec->storage*8;
+
+ /* Decode at a fixed coarse resolution */
+ for (i=start;i<end;i++)
+ {
+ c=0;
+ do {
+ int qi;
+ opus_val32 q;
+ opus_val32 tmp;
+ /* It would be better to express this invariant as a
+ test on C at function entry, but that isn't enough
+ to make the static analyzer happy. */
+ celt_assert(c<2);
+ tell = ec_tell(dec);
+ if(budget-tell>=15)
+ {
+ int pi;
+ pi = 2*IMIN(i,20);
+ qi = ec_laplace_decode(dec,
+ prob_model[pi]<<7, prob_model[pi+1]<<6);
+ }
+ else if(budget-tell>=2)
+ {
+ qi = ec_dec_icdf(dec, small_energy_icdf, 2);
+ qi = (qi>>1)^-(qi&1);
+ }
+ else if(budget-tell>=1)
+ {
+ qi = -ec_dec_bit_logp(dec, 1);
+ }
+ else
+ qi = -1;
+ q = (opus_val32)SHL32(EXTEND32(qi),DB_SHIFT);
+
+ oldEBands[i+c*m->nbEBands] = MAX16(-QCONST16(9.f,DB_SHIFT), oldEBands[i+c*m->nbEBands]);
+ tmp = PSHR32(MULT16_16(coef,oldEBands[i+c*m->nbEBands]),8) + prev[c] + SHL32(q,7);
+#ifdef OPUS_FIXED_POINT
+ tmp = MAX32(-QCONST32(28.f, DB_SHIFT+7), tmp);
+#endif
+ oldEBands[i+c*m->nbEBands] = PSHR32(tmp, 7);
+ prev[c] = prev[c] + SHL32(q,7) - MULT16_16(beta,PSHR32(q,8));
+ } while (++c < C);
+ }
+}
+
+void unquant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, ec_dec *dec, int C)
+{
+ int i, c;
+ /* Decode finer resolution */
+ for (i=start;i<end;i++)
+ {
+ if (fine_quant[i] <= 0)
+ continue;
+ c=0;
+ do {
+ int q2;
+ opus_val16 offset;
+ q2 = ec_dec_bits(dec, fine_quant[i]);
+#ifdef OPUS_FIXED_POINT
+ offset = SUB16(SHR32(SHL32(EXTEND32(q2),DB_SHIFT)+QCONST16(.5f,DB_SHIFT),fine_quant[i]),QCONST16(.5f,DB_SHIFT));
+#else
+ offset = (q2+.5f)*(1<<(14-fine_quant[i]))*(1.f/16384) - .5f;
+#endif
+ oldEBands[i+c*m->nbEBands] += offset;
+ } while (++c < C);
+ }
+}
+
+void unquant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, int *fine_priority, int bits_left, ec_dec *dec, int C)
+{
+ int i, prio, c;
+
+ /* Use up the remaining bits */
+ for (prio=0;prio<2;prio++)
+ {
+ for (i=start;i<end && bits_left>=C ;i++)
+ {
+ if (fine_quant[i] >= MAX_FINE_BITS || fine_priority[i]!=prio)
+ continue;
+ c=0;
+ do {
+ int q2;
+ opus_val16 offset;
+ q2 = ec_dec_bits(dec, 1);
+#ifdef OPUS_FIXED_POINT
+ offset = SHR16(SHL16(q2,DB_SHIFT)-QCONST16(.5f,DB_SHIFT),fine_quant[i]+1);
+#else
+ offset = (q2-.5f)*(1<<(14-fine_quant[i]-1))*(1.f/16384);
+#endif
+ oldEBands[i+c*m->nbEBands] += offset;
+ bits_left--;
+ } while (++c < C);
+ }
+ }
+}
+
+void amp2Log2(const CELTMode *m, int effEnd, int end,
+ celt_ener *bandE, opus_val16 *bandLogE, int C)
+{
+ int c, i;
+ c=0;
+ do {
+ for (i=0;i<effEnd;i++)
+ bandLogE[i+c*m->nbEBands] =
+ celt_log2(SHL32(bandE[i+c*m->nbEBands],2))
+ - SHL16((opus_val16)eMeans[i],6);
+ for (i=effEnd;i<end;i++)
+ bandLogE[c*m->nbEBands+i] = -QCONST16(14.f,DB_SHIFT);
+ } while (++c < C);
+}
diff --git a/drivers/opus/celt/quant_bands.h b/drivers/opus/celt/quant_bands.h
new file mode 100644
index 0000000000..85d011e6e0
--- /dev/null
+++ b/drivers/opus/celt/quant_bands.h
@@ -0,0 +1,66 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef QUANT_BANDS
+#define QUANT_BANDS
+
+#include "opus/celt/arch.h"
+#include "opus/celt/opus_modes.h"
+#include "opus/celt/entenc.h"
+#include "opus/celt/entdec.h"
+#include "opus/celt/mathops.h"
+
+#ifdef OPUS_FIXED_POINT
+extern const signed char eMeans[25];
+#else
+extern const opus_val16 eMeans[25];
+#endif
+
+void amp2Log2(const CELTMode *m, int effEnd, int end,
+ celt_ener *bandE, opus_val16 *bandLogE, int C);
+
+void log2Amp(const CELTMode *m, int start, int end,
+ celt_ener *eBands, const opus_val16 *oldEBands, int C);
+
+void quant_coarse_energy(const CELTMode *m, int start, int end, int effEnd,
+ const opus_val16 *eBands, opus_val16 *oldEBands, opus_uint32 budget,
+ opus_val16 *error, ec_enc *enc, int C, int LM,
+ int nbAvailableBytes, int force_intra, opus_val32 *delayedIntra,
+ int two_pass, int loss_rate, int lfe);
+
+void quant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, ec_enc *enc, int C);
+
+void quant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, opus_val16 *error, int *fine_quant, int *fine_priority, int bits_left, ec_enc *enc, int C);
+
+void unquant_coarse_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int intra, ec_dec *dec, int C, int LM);
+
+void unquant_fine_energy(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, ec_dec *dec, int C);
+
+void unquant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *oldEBands, int *fine_quant, int *fine_priority, int bits_left, ec_dec *dec, int C);
+
+#endif /* QUANT_BANDS */
diff --git a/drivers/opus/celt/rate.c b/drivers/opus/celt/rate.c
new file mode 100644
index 0000000000..ecc0ab2a4f
--- /dev/null
+++ b/drivers/opus/celt/rate.c
@@ -0,0 +1,638 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include <math.h>
+#include "opus/celt/opus_modes.h"
+#include "opus/celt/cwrs.h"
+#include "opus/celt/arch.h"
+#include "opus/celt/os_support.h"
+
+#include "opus/celt/entcode.h"
+#include "opus/celt/rate.h"
+
+static const unsigned char LOG2_FRAC_TABLE[24]={
+ 0,
+ 8,13,
+ 16,19,21,23,
+ 24,26,27,28,29,30,31,32,
+ 32,33,34,34,35,36,36,37,37
+};
+
+#ifdef CUSTOM_MODES
+
+/*Determines if V(N,K) fits in a 32-bit unsigned integer.
+ N and K are themselves limited to 15 bits.*/
+static int fits_in32(int _n, int _k)
+{
+ static const opus_int16 maxN[15] = {
+ 32767, 32767, 32767, 1476, 283, 109, 60, 40,
+ 29, 24, 20, 18, 16, 14, 13};
+ static const opus_int16 maxK[15] = {
+ 32767, 32767, 32767, 32767, 1172, 238, 95, 53,
+ 36, 27, 22, 18, 16, 15, 13};
+ if (_n>=14)
+ {
+ if (_k>=14)
+ return 0;
+ else
+ return _n <= maxN[_k];
+ } else {
+ return _k <= maxK[_n];
+ }
+}
+
+void compute_pulse_cache(CELTMode *m, int LM)
+{
+ int C;
+ int i;
+ int j;
+ int curr=0;
+ int nbEntries=0;
+ int entryN[100], entryK[100], entryI[100];
+ const opus_int16 *eBands = m->eBands;
+ PulseCache *cache = &m->cache;
+ opus_int16 *cindex;
+ unsigned char *bits;
+ unsigned char *cap;
+
+ cindex = (opus_int16 *)opus_alloc(sizeof(cache->index[0])*m->nbEBands*(LM+2));
+ cache->index = cindex;
+
+ /* Scan for all unique band sizes */
+ for (i=0;i<=LM+1;i++)
+ {
+ for (j=0;j<m->nbEBands;j++)
+ {
+ int k;
+ int N = (eBands[j+1]-eBands[j])<<i>>1;
+ cindex[i*m->nbEBands+j] = -1;
+ /* Find other bands that have the same size */
+ for (k=0;k<=i;k++)
+ {
+ int n;
+ for (n=0;n<m->nbEBands && (k!=i || n<j);n++)
+ {
+ if (N == (eBands[n+1]-eBands[n])<<k>>1)
+ {
+ cindex[i*m->nbEBands+j] = cindex[k*m->nbEBands+n];
+ break;
+ }
+ }
+ }
+ if (cache->index[i*m->nbEBands+j] == -1 && N!=0)
+ {
+ int K;
+ entryN[nbEntries] = N;
+ K = 0;
+ while (fits_in32(N,get_pulses(K+1)) && K<MAX_PSEUDO)
+ K++;
+ entryK[nbEntries] = K;
+ cindex[i*m->nbEBands+j] = curr;
+ entryI[nbEntries] = curr;
+
+ curr += K+1;
+ nbEntries++;
+ }
+ }
+ }
+ bits = (unsigned char *)opus_alloc(sizeof(unsigned char)*curr);
+ cache->bits = bits;
+ cache->size = curr;
+ /* Compute the cache for all unique sizes */
+ for (i=0;i<nbEntries;i++)
+ {
+ unsigned char *ptr = bits+entryI[i];
+ opus_int16 tmp[MAX_PULSES+1];
+ get_required_bits(tmp, entryN[i], get_pulses(entryK[i]), BITRES);
+ for (j=1;j<=entryK[i];j++)
+ ptr[j] = tmp[get_pulses(j)]-1;
+ ptr[0] = entryK[i];
+ }
+
+ /* Compute the maximum rate for each band at which we'll reliably use as
+ many bits as we ask for. */
+ cache->caps = cap = (unsigned char *)opus_alloc(sizeof(cache->caps[0])*(LM+1)*2*m->nbEBands);
+ for (i=0;i<=LM;i++)
+ {
+ for (C=1;C<=2;C++)
+ {
+ for (j=0;j<m->nbEBands;j++)
+ {
+ int N0;
+ int max_bits;
+ N0 = m->eBands[j+1]-m->eBands[j];
+ /* N=1 bands only have a sign bit and fine bits. */
+ if (N0<<i == 1)
+ max_bits = C*(1+MAX_FINE_BITS)<<BITRES;
+ else
+ {
+ const unsigned char *pcache;
+ opus_int32 num;
+ opus_int32 den;
+ int LM0;
+ int N;
+ int offset;
+ int ndof;
+ int qb;
+ int k;
+ LM0 = 0;
+ /* Even-sized bands bigger than N=2 can be split one more time.
+ As of commit 44203907 all bands >1 are even, including custom modes.*/
+ if (N0 > 2)
+ {
+ N0>>=1;
+ LM0--;
+ }
+ /* N0=1 bands can't be split down to N<2. */
+ else if (N0 <= 1)
+ {
+ LM0=IMIN(i,1);
+ N0<<=LM0;
+ }
+ /* Compute the cost for the lowest-level PVQ of a fully split
+ band. */
+ pcache = bits + cindex[(LM0+1)*m->nbEBands+j];
+ max_bits = pcache[pcache[0]]+1;
+ /* Add in the cost of coding regular splits. */
+ N = N0;
+ for(k=0;k<i-LM0;k++){
+ max_bits <<= 1;
+ /* Offset the number of qtheta bits by log2(N)/2
+ + QTHETA_OFFSET compared to their "fair share" of
+ total/N */
+ offset = ((m->logN[j]+((LM0+k)<<BITRES))>>1)-QTHETA_OFFSET;
+ /* The number of qtheta bits we'll allocate if the remainder
+ is to be max_bits.
+ The average measured cost for theta is 0.89701 times qb,
+ approximated here as 459/512. */
+ num=459*(opus_int32)((2*N-1)*offset+max_bits);
+ den=((opus_int32)(2*N-1)<<9)-459;
+ qb = IMIN((num+(den>>1))/den, 57);
+ celt_assert(qb >= 0);
+ max_bits += qb;
+ N <<= 1;
+ }
+ /* Add in the cost of a stereo split, if necessary. */
+ if (C==2)
+ {
+ max_bits <<= 1;
+ offset = ((m->logN[j]+(i<<BITRES))>>1)-(N==2?QTHETA_OFFSET_TWOPHASE:QTHETA_OFFSET);
+ ndof = 2*N-1-(N==2);
+ /* The average measured cost for theta with the step PDF is
+ 0.95164 times qb, approximated here as 487/512. */
+ num = (N==2?512:487)*(opus_int32)(max_bits+ndof*offset);
+ den = ((opus_int32)ndof<<9)-(N==2?512:487);
+ qb = IMIN((num+(den>>1))/den, (N==2?64:61));
+ celt_assert(qb >= 0);
+ max_bits += qb;
+ }
+ /* Add the fine bits we'll use. */
+ /* Compensate for the extra DoF in stereo */
+ ndof = C*N + ((C==2 && N>2) ? 1 : 0);
+ /* Offset the number of fine bits by log2(N)/2 + FINE_OFFSET
+ compared to their "fair share" of total/N */
+ offset = ((m->logN[j] + (i<<BITRES))>>1)-FINE_OFFSET;
+ /* N=2 is the only point that doesn't match the curve */
+ if (N==2)
+ offset += 1<<BITRES>>2;
+ /* The number of fine bits we'll allocate if the remainder is
+ to be max_bits. */
+ num = max_bits+ndof*offset;
+ den = (ndof-1)<<BITRES;
+ qb = IMIN((num+(den>>1))/den, MAX_FINE_BITS);
+ celt_assert(qb >= 0);
+ max_bits += C*qb<<BITRES;
+ }
+ max_bits = (4*max_bits/(C*((m->eBands[j+1]-m->eBands[j])<<i)))-64;
+ celt_assert(max_bits >= 0);
+ celt_assert(max_bits < 256);
+ *cap++ = (unsigned char)max_bits;
+ }
+ }
+ }
+}
+
+#endif /* CUSTOM_MODES */
+
+#define ALLOC_STEPS 6
+
+static OPUS_INLINE int interp_bits2pulses(const CELTMode *m, int start, int end, int skip_start,
+ const int *bits1, const int *bits2, const int *thresh, const int *cap, opus_int32 total, opus_int32 *_balance,
+ int skip_rsv, int *intensity, int intensity_rsv, int *dual_stereo, int dual_stereo_rsv, int *bits,
+ int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev, int signalBandwidth)
+{
+ opus_int32 psum;
+ int lo, hi;
+ int i, j;
+ int logM;
+ int stereo;
+ int codedBands=-1;
+ int alloc_floor;
+ opus_int32 left, percoeff;
+ int done;
+ opus_int32 balance;
+ SAVE_STACK;
+
+ alloc_floor = C<<BITRES;
+ stereo = C>1;
+
+ logM = LM<<BITRES;
+ lo = 0;
+ hi = 1<<ALLOC_STEPS;
+ for (i=0;i<ALLOC_STEPS;i++)
+ {
+ int mid = (lo+hi)>>1;
+ psum = 0;
+ done = 0;
+ for (j=end;j-->start;)
+ {
+ int tmp = bits1[j] + (mid*(opus_int32)bits2[j]>>ALLOC_STEPS);
+ if (tmp >= thresh[j] || done)
+ {
+ done = 1;
+ /* Don't allocate more than we can actually use */
+ psum += IMIN(tmp, cap[j]);
+ } else {
+ if (tmp >= alloc_floor)
+ psum += alloc_floor;
+ }
+ }
+ if (psum > total)
+ hi = mid;
+ else
+ lo = mid;
+ }
+ psum = 0;
+ /*printf ("interp bisection gave %d\n", lo);*/
+ done = 0;
+ for (j=end;j-->start;)
+ {
+ int tmp = bits1[j] + (lo*bits2[j]>>ALLOC_STEPS);
+ if (tmp < thresh[j] && !done)
+ {
+ if (tmp >= alloc_floor)
+ tmp = alloc_floor;
+ else
+ tmp = 0;
+ } else
+ done = 1;
+ /* Don't allocate more than we can actually use */
+ tmp = IMIN(tmp, cap[j]);
+ bits[j] = tmp;
+ psum += tmp;
+ }
+
+ /* Decide which bands to skip, working backwards from the end. */
+ for (codedBands=end;;codedBands--)
+ {
+ int band_width;
+ int band_bits;
+ int rem;
+ j = codedBands-1;
+ /* Never skip the first band, nor a band that has been boosted by
+ dynalloc.
+ In the first case, we'd be coding a bit to signal we're going to waste
+ all the other bits.
+ In the second case, we'd be coding a bit to redistribute all the bits
+ we just signaled should be cocentrated in this band. */
+ if (j<=skip_start)
+ {
+ /* Give the bit we reserved to end skipping back. */
+ total += skip_rsv;
+ break;
+ }
+ /*Figure out how many left-over bits we would be adding to this band.
+ This can include bits we've stolen back from higher, skipped bands.*/
+ left = total-psum;
+ percoeff = left/(m->eBands[codedBands]-m->eBands[start]);
+ left -= (m->eBands[codedBands]-m->eBands[start])*percoeff;
+ rem = IMAX(left-(m->eBands[j]-m->eBands[start]),0);
+ band_width = m->eBands[codedBands]-m->eBands[j];
+ band_bits = (int)(bits[j] + percoeff*band_width + rem);
+ /*Only code a skip decision if we're above the threshold for this band.
+ Otherwise it is force-skipped.
+ This ensures that we have enough bits to code the skip flag.*/
+ if (band_bits >= IMAX(thresh[j], alloc_floor+(1<<BITRES)))
+ {
+ if (encode)
+ {
+ /*This if() block is the only part of the allocation function that
+ is not a mandatory part of the bitstream: any bands we choose to
+ skip here must be explicitly signaled.*/
+ /*Choose a threshold with some hysteresis to keep bands from
+ fluctuating in and out.*/
+#ifdef FUZZING
+ if ((rand()&0x1) == 0)
+#else
+ if (codedBands<=start+2 || (band_bits > ((j<prev?7:9)*band_width<<LM<<BITRES)>>4 && j<=signalBandwidth))
+#endif
+ {
+ ec_enc_bit_logp(ec, 1, 1);
+ break;
+ }
+ ec_enc_bit_logp(ec, 0, 1);
+ } else if (ec_dec_bit_logp(ec, 1)) {
+ break;
+ }
+ /*We used a bit to skip this band.*/
+ psum += 1<<BITRES;
+ band_bits -= 1<<BITRES;
+ }
+ /*Reclaim the bits originally allocated to this band.*/
+ psum -= bits[j]+intensity_rsv;
+ if (intensity_rsv > 0)
+ intensity_rsv = LOG2_FRAC_TABLE[j-start];
+ psum += intensity_rsv;
+ if (band_bits >= alloc_floor)
+ {
+ /*If we have enough for a fine energy bit per channel, use it.*/
+ psum += alloc_floor;
+ bits[j] = alloc_floor;
+ } else {
+ /*Otherwise this band gets nothing at all.*/
+ bits[j] = 0;
+ }
+ }
+
+ celt_assert(codedBands > start);
+ /* Code the intensity and dual stereo parameters. */
+ if (intensity_rsv > 0)
+ {
+ if (encode)
+ {
+ *intensity = IMIN(*intensity, codedBands);
+ ec_enc_uint(ec, *intensity-start, codedBands+1-start);
+ }
+ else
+ *intensity = start+ec_dec_uint(ec, codedBands+1-start);
+ }
+ else
+ *intensity = 0;
+ if (*intensity <= start)
+ {
+ total += dual_stereo_rsv;
+ dual_stereo_rsv = 0;
+ }
+ if (dual_stereo_rsv > 0)
+ {
+ if (encode)
+ ec_enc_bit_logp(ec, *dual_stereo, 1);
+ else
+ *dual_stereo = ec_dec_bit_logp(ec, 1);
+ }
+ else
+ *dual_stereo = 0;
+
+ /* Allocate the remaining bits */
+ left = total-psum;
+ percoeff = left/(m->eBands[codedBands]-m->eBands[start]);
+ left -= (m->eBands[codedBands]-m->eBands[start])*percoeff;
+ for (j=start;j<codedBands;j++)
+ bits[j] += ((int)percoeff*(m->eBands[j+1]-m->eBands[j]));
+ for (j=start;j<codedBands;j++)
+ {
+ int tmp = (int)IMIN(left, m->eBands[j+1]-m->eBands[j]);
+ bits[j] += tmp;
+ left -= tmp;
+ }
+ /*for (j=0;j<end;j++)printf("%d ", bits[j]);printf("\n");*/
+
+ balance = 0;
+ for (j=start;j<codedBands;j++)
+ {
+ int N0, N, den;
+ int offset;
+ int NClogN;
+ opus_int32 excess, bit;
+
+ celt_assert(bits[j] >= 0);
+ N0 = m->eBands[j+1]-m->eBands[j];
+ N=N0<<LM;
+ bit = (opus_int32)bits[j]+balance;
+
+ if (N>1)
+ {
+ excess = MAX32(bit-cap[j],0);
+ bits[j] = bit-excess;
+
+ /* Compensate for the extra DoF in stereo */
+ den=(C*N+ ((C==2 && N>2 && !*dual_stereo && j<*intensity) ? 1 : 0));
+
+ NClogN = den*(m->logN[j] + logM);
+
+ /* Offset for the number of fine bits by log2(N)/2 + FINE_OFFSET
+ compared to their "fair share" of total/N */
+ offset = (NClogN>>1)-den*FINE_OFFSET;
+
+ /* N=2 is the only point that doesn't match the curve */
+ if (N==2)
+ offset += den<<BITRES>>2;
+
+ /* Changing the offset for allocating the second and third
+ fine energy bit */
+ if (bits[j] + offset < den*2<<BITRES)
+ offset += NClogN>>2;
+ else if (bits[j] + offset < den*3<<BITRES)
+ offset += NClogN>>3;
+
+ /* Divide with rounding */
+ ebits[j] = IMAX(0, (bits[j] + offset + (den<<(BITRES-1))) / (den<<BITRES));
+
+ /* Make sure not to bust */
+ if (C*ebits[j] > (bits[j]>>BITRES))
+ ebits[j] = bits[j] >> stereo >> BITRES;
+
+ /* More than that is useless because that's about as far as PVQ can go */
+ ebits[j] = IMIN(ebits[j], MAX_FINE_BITS);
+
+ /* If we rounded down or capped this band, make it a candidate for the
+ final fine energy pass */
+ fine_priority[j] = ebits[j]*(den<<BITRES) >= bits[j]+offset;
+
+ /* Remove the allocated fine bits; the rest are assigned to PVQ */
+ bits[j] -= C*ebits[j]<<BITRES;
+
+ } else {
+ /* For N=1, all bits go to fine energy except for a single sign bit */
+ excess = MAX32(0,bit-(C<<BITRES));
+ bits[j] = bit-excess;
+ ebits[j] = 0;
+ fine_priority[j] = 1;
+ }
+
+ /* Fine energy can't take advantage of the re-balancing in
+ quant_all_bands().
+ Instead, do the re-balancing here.*/
+ if(excess > 0)
+ {
+ int extra_fine;
+ int extra_bits;
+ extra_fine = IMIN(excess>>(stereo+BITRES),MAX_FINE_BITS-ebits[j]);
+ ebits[j] += extra_fine;
+ extra_bits = extra_fine*C<<BITRES;
+ fine_priority[j] = extra_bits >= excess-balance;
+ excess -= extra_bits;
+ }
+ balance = excess;
+
+ celt_assert(bits[j] >= 0);
+ celt_assert(ebits[j] >= 0);
+ }
+ /* Save any remaining bits over the cap for the rebalancing in
+ quant_all_bands(). */
+ *_balance = balance;
+
+ /* The skipped bands use all their bits for fine energy. */
+ for (;j<end;j++)
+ {
+ ebits[j] = bits[j] >> stereo >> BITRES;
+ celt_assert(C*ebits[j]<<BITRES == bits[j]);
+ bits[j] = 0;
+ fine_priority[j] = ebits[j]<1;
+ }
+ RESTORE_STACK;
+ return codedBands;
+}
+
+int compute_allocation(const CELTMode *m, int start, int end, const int *offsets, const int *cap, int alloc_trim, int *intensity, int *dual_stereo,
+ opus_int32 total, opus_int32 *balance, int *pulses, int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev, int signalBandwidth)
+{
+ int lo, hi, len, j;
+ int codedBands;
+ int skip_start;
+ int skip_rsv;
+ int intensity_rsv;
+ int dual_stereo_rsv;
+ VARDECL(int, bits1);
+ VARDECL(int, bits2);
+ VARDECL(int, thresh);
+ VARDECL(int, trim_offset);
+ SAVE_STACK;
+
+ total = IMAX(total, 0);
+ len = m->nbEBands;
+ skip_start = start;
+ /* Reserve a bit to signal the end of manually skipped bands. */
+ skip_rsv = total >= 1<<BITRES ? 1<<BITRES : 0;
+ total -= skip_rsv;
+ /* Reserve bits for the intensity and dual stereo parameters. */
+ intensity_rsv = dual_stereo_rsv = 0;
+ if (C==2)
+ {
+ intensity_rsv = LOG2_FRAC_TABLE[end-start];
+ if (intensity_rsv>total)
+ intensity_rsv = 0;
+ else
+ {
+ total -= intensity_rsv;
+ dual_stereo_rsv = total>=1<<BITRES ? 1<<BITRES : 0;
+ total -= dual_stereo_rsv;
+ }
+ }
+ ALLOC(bits1, len, int);
+ ALLOC(bits2, len, int);
+ ALLOC(thresh, len, int);
+ ALLOC(trim_offset, len, int);
+
+ for (j=start;j<end;j++)
+ {
+ /* Below this threshold, we're sure not to allocate any PVQ bits */
+ thresh[j] = IMAX((C)<<BITRES, (3*(m->eBands[j+1]-m->eBands[j])<<LM<<BITRES)>>4);
+ /* Tilt of the allocation curve */
+ trim_offset[j] = C*(m->eBands[j+1]-m->eBands[j])*(alloc_trim-5-LM)*(end-j-1)
+ *(1<<(LM+BITRES))>>6;
+ /* Giving less resolution to single-coefficient bands because they get
+ more benefit from having one coarse value per coefficient*/
+ if ((m->eBands[j+1]-m->eBands[j])<<LM==1)
+ trim_offset[j] -= C<<BITRES;
+ }
+ lo = 1;
+ hi = m->nbAllocVectors - 1;
+ do
+ {
+ int done = 0;
+ int psum = 0;
+ int mid = (lo+hi) >> 1;
+ for (j=end;j-->start;)
+ {
+ int bitsj;
+ int N = m->eBands[j+1]-m->eBands[j];
+ bitsj = C*N*m->allocVectors[mid*len+j]<<LM>>2;
+ if (bitsj > 0)
+ bitsj = IMAX(0, bitsj + trim_offset[j]);
+ bitsj += offsets[j];
+ if (bitsj >= thresh[j] || done)
+ {
+ done = 1;
+ /* Don't allocate more than we can actually use */
+ psum += IMIN(bitsj, cap[j]);
+ } else {
+ if (bitsj >= C<<BITRES)
+ psum += C<<BITRES;
+ }
+ }
+ if (psum > total)
+ hi = mid - 1;
+ else
+ lo = mid + 1;
+ /*printf ("lo = %d, hi = %d\n", lo, hi);*/
+ }
+ while (lo <= hi);
+ hi = lo--;
+ /*printf ("interp between %d and %d\n", lo, hi);*/
+ for (j=start;j<end;j++)
+ {
+ int bits1j, bits2j;
+ int N = m->eBands[j+1]-m->eBands[j];
+ bits1j = C*N*m->allocVectors[lo*len+j]<<LM>>2;
+ bits2j = hi>=m->nbAllocVectors ?
+ cap[j] : C*N*m->allocVectors[hi*len+j]<<LM>>2;
+ if (bits1j > 0)
+ bits1j = IMAX(0, bits1j + trim_offset[j]);
+ if (bits2j > 0)
+ bits2j = IMAX(0, bits2j + trim_offset[j]);
+ if (lo > 0)
+ bits1j += offsets[j];
+ bits2j += offsets[j];
+ if (offsets[j]>0)
+ skip_start = j;
+ bits2j = IMAX(0,bits2j-bits1j);
+ bits1[j] = bits1j;
+ bits2[j] = bits2j;
+ }
+ codedBands = interp_bits2pulses(m, start, end, skip_start, bits1, bits2, thresh, cap,
+ total, balance, skip_rsv, intensity, intensity_rsv, dual_stereo, dual_stereo_rsv,
+ pulses, ebits, fine_priority, C, LM, ec, encode, prev, signalBandwidth);
+ RESTORE_STACK;
+ return codedBands;
+}
+
diff --git a/drivers/opus/celt/rate.h b/drivers/opus/celt/rate.h
new file mode 100644
index 0000000000..e12dd29db8
--- /dev/null
+++ b/drivers/opus/celt/rate.h
@@ -0,0 +1,101 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef RATE_H
+#define RATE_H
+
+#define MAX_PSEUDO 40
+#define LOG_MAX_PSEUDO 6
+
+#define MAX_PULSES 128
+
+#define MAX_FINE_BITS 8
+
+#define FINE_OFFSET 21
+#define QTHETA_OFFSET 4
+#define QTHETA_OFFSET_TWOPHASE 16
+
+#include "opus/celt/cwrs.h"
+#include "opus/celt/opus_modes.h"
+
+void compute_pulse_cache(CELTMode *m, int LM);
+
+static OPUS_INLINE int get_pulses(int i)
+{
+ return i<8 ? i : (8 + (i&7)) << ((i>>3)-1);
+}
+
+static OPUS_INLINE int bits2pulses(const CELTMode *m, int band, int LM, int bits)
+{
+ int i;
+ int lo, hi;
+ const unsigned char *cache;
+
+ LM++;
+ cache = m->cache.bits + m->cache.index[LM*m->nbEBands+band];
+
+ lo = 0;
+ hi = cache[0];
+ bits--;
+ for (i=0;i<LOG_MAX_PSEUDO;i++)
+ {
+ int mid = (lo+hi+1)>>1;
+ /* OPT: Make sure this is implemented with a conditional move */
+ if ((int)cache[mid] >= bits)
+ hi = mid;
+ else
+ lo = mid;
+ }
+ if (bits- (lo == 0 ? -1 : (int)cache[lo]) <= (int)cache[hi]-bits)
+ return lo;
+ else
+ return hi;
+}
+
+static OPUS_INLINE int pulses2bits(const CELTMode *m, int band, int LM, int pulses)
+{
+ const unsigned char *cache;
+
+ LM++;
+ cache = m->cache.bits + m->cache.index[LM*m->nbEBands+band];
+ return pulses == 0 ? 0 : cache[pulses]+1;
+}
+
+/** Compute the pulse allocation, i.e. how many pulses will go in each
+ * band.
+ @param m mode
+ @param offsets Requested increase or decrease in the number of bits for
+ each band
+ @param total Number of bands
+ @param pulses Number of pulses per band (returned)
+ @return Total number of bits allocated
+*/
+int compute_allocation(const CELTMode *m, int start, int end, const int *offsets, const int *cap, int alloc_trim, int *intensity, int *dual_stero,
+ opus_int32 total, opus_int32 *balance, int *pulses, int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev, int signalBandwidth);
+
+#endif
diff --git a/drivers/opus/celt/stack_alloc.h b/drivers/opus/celt/stack_alloc.h
new file mode 100644
index 0000000000..464a6d0b7f
--- /dev/null
+++ b/drivers/opus/celt/stack_alloc.h
@@ -0,0 +1,182 @@
+/* Copyright (C) 2002-2003 Jean-Marc Valin
+ Copyright (C) 2007-2009 Xiph.Org Foundation */
+/**
+ @file stack_alloc.h
+ @brief Temporary memory allocation on stack
+*/
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef STACK_ALLOC_H
+#define STACK_ALLOC_H
+
+#include "opus/opus_types.h"
+#include "opus/opus_defines.h"
+
+#if (!defined (VAR_ARRAYS) && !defined (USE_ALLOCA) && !defined (NONTHREADSAFE_PSEUDOSTACK))
+#define VAR_ARRAYS
+#endif
+
+#ifdef USE_ALLOCA
+# ifdef WIN32
+# include <malloc.h>
+# else
+# ifdef OPUS_HAVE_ALLOCA_H
+# include <alloca.h>
+# else
+# ifdef __linux__
+# include <alloca.h>
+# else
+# include <stdlib.h>
+# endif
+# endif
+# endif
+#endif
+
+/**
+ * @def ALIGN(stack, size)
+ *
+ * Aligns the stack to a 'size' boundary
+ *
+ * @param stack Stack
+ * @param size New size boundary
+ */
+
+/**
+ * @def PUSH(stack, size, type)
+ *
+ * Allocates 'size' elements of type 'type' on the stack
+ *
+ * @param stack Stack
+ * @param size Number of elements
+ * @param type Type of element
+ */
+
+/**
+ * @def VARDECL(var)
+ *
+ * Declare variable on stack
+ *
+ * @param var Variable to declare
+ */
+
+/**
+ * @def ALLOC(var, size, type)
+ *
+ * Allocate 'size' elements of 'type' on stack
+ *
+ * @param var Name of variable to allocate
+ * @param size Number of elements
+ * @param type Type of element
+ */
+
+#if defined(VAR_ARRAYS)
+
+#define VARDECL(type, var)
+#define ALLOC(var, size, type) type var[size]
+#define SAVE_STACK
+#define RESTORE_STACK
+#define ALLOC_STACK
+/* C99 does not allow VLAs of size zero */
+#define ALLOC_NONE 1
+
+#elif defined(USE_ALLOCA)
+
+#define VARDECL(type, var) type *var
+
+# ifdef WIN32
+# define ALLOC(var, size, type) var = ((type*)_alloca(sizeof(type)*(size)))
+# else
+# define ALLOC(var, size, type) var = ((type*)alloca(sizeof(type)*(size)))
+# endif
+
+#define SAVE_STACK
+#define RESTORE_STACK
+#define ALLOC_STACK
+#define ALLOC_NONE 0
+
+#else
+
+#ifdef CELT_C
+char *global_stack=0;
+#else
+extern char *global_stack;
+#endif /* CELT_C */
+
+#ifdef ENABLE_VALGRIND
+
+#include <valgrind/memcheck.h>
+
+#ifdef CELT_C
+char *global_stack_top=0;
+#else
+extern char *global_stack_top;
+#endif /* CELT_C */
+
+#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1))
+#define PUSH(stack, size, type) (VALGRIND_MAKE_MEM_NOACCESS(stack, global_stack_top-stack),ALIGN((stack),sizeof(type)/sizeof(char)),VALGRIND_MAKE_MEM_UNDEFINED(stack, ((size)*sizeof(type)/sizeof(char))),(stack)+=(2*(size)*sizeof(type)/sizeof(char)),(type*)((stack)-(2*(size)*sizeof(type)/sizeof(char))))
+#define RESTORE_STACK ((global_stack = _saved_stack),VALGRIND_MAKE_MEM_NOACCESS(global_stack, global_stack_top-global_stack))
+#define ALLOC_STACK char *_saved_stack; ((global_stack = (global_stack==0) ? ((global_stack_top=opus_alloc_scratch(GLOBAL_STACK_SIZE*2)+(GLOBAL_STACK_SIZE*2))-(GLOBAL_STACK_SIZE*2)) : global_stack),VALGRIND_MAKE_MEM_NOACCESS(global_stack, global_stack_top-global_stack)); _saved_stack = global_stack;
+
+#else
+
+#define ALIGN(stack, size) ((stack) += ((size) - (long)(stack)) & ((size) - 1))
+#define PUSH(stack, size, type) (ALIGN((stack),sizeof(type)/sizeof(char)),(stack)+=(size)*(sizeof(type)/sizeof(char)),(type*)((stack)-(size)*(sizeof(type)/sizeof(char))))
+#define RESTORE_STACK (global_stack = _saved_stack)
+#define ALLOC_STACK char *_saved_stack; (global_stack = (global_stack==0) ? opus_alloc_scratch(GLOBAL_STACK_SIZE) : global_stack); _saved_stack = global_stack;
+
+#endif /* ENABLE_VALGRIND */
+
+#include "opus/celt/os_support.h"
+#define VARDECL(type, var) type *var
+#define ALLOC(var, size, type) var = PUSH(global_stack, size, type)
+#define SAVE_STACK char *_saved_stack = global_stack;
+#define ALLOC_NONE 0
+
+#endif /* VAR_ARRAYS */
+
+
+#ifdef ENABLE_VALGRIND
+
+#include <valgrind/memcheck.h>
+#define OPUS_CHECK_ARRAY(ptr, len) VALGRIND_CHECK_MEM_IS_DEFINED(ptr, len*sizeof(*ptr))
+#define OPUS_CHECK_VALUE(value) VALGRIND_CHECK_VALUE_IS_DEFINED(value)
+#define OPUS_CHECK_ARRAY_COND(ptr, len) VALGRIND_CHECK_MEM_IS_DEFINED(ptr, len*sizeof(*ptr))
+#define OPUS_CHECK_VALUE_COND(value) VALGRIND_CHECK_VALUE_IS_DEFINED(value)
+#define OPUS_PRINT_INT(value) do {fprintf(stderr, #value " = %d at %s:%d\n", value, __FILE__, __LINE__);}while(0)
+#define OPUS_FPRINTF fprintf
+
+#else
+
+static OPUS_INLINE int _opus_false(void) {return 0;}
+#define OPUS_CHECK_ARRAY(ptr, len) _opus_false()
+#define OPUS_CHECK_VALUE(value) _opus_false()
+#define OPUS_PRINT_INT(value) do{}while(0)
+#define OPUS_FPRINTF (void)
+
+#endif
+
+
+#endif /* STACK_ALLOC_H */
diff --git a/drivers/opus/celt/static_modes_fixed.h b/drivers/opus/celt/static_modes_fixed.h
new file mode 100644
index 0000000000..1d92fc4b27
--- /dev/null
+++ b/drivers/opus/celt/static_modes_fixed.h
@@ -0,0 +1,595 @@
+/* The contents of this file was automatically generated by dump_modes.c
+ with arguments: 48000 960
+ It contains static definitions for some pre-defined modes. */
+#include "opus/celt/opus_modes.h"
+#include "opus/celt/rate.h"
+
+#ifndef DEF_WINDOW120
+#define DEF_WINDOW120
+static const opus_val16 window120[120] = {
+2, 20, 55, 108, 178,
+266, 372, 494, 635, 792,
+966, 1157, 1365, 1590, 1831,
+2089, 2362, 2651, 2956, 3276,
+3611, 3961, 4325, 4703, 5094,
+5499, 5916, 6346, 6788, 7241,
+7705, 8179, 8663, 9156, 9657,
+10167, 10684, 11207, 11736, 12271,
+12810, 13353, 13899, 14447, 14997,
+15547, 16098, 16648, 17197, 17744,
+18287, 18827, 19363, 19893, 20418,
+20936, 21447, 21950, 22445, 22931,
+23407, 23874, 24330, 24774, 25208,
+25629, 26039, 26435, 26819, 27190,
+27548, 27893, 28224, 28541, 28845,
+29135, 29411, 29674, 29924, 30160,
+30384, 30594, 30792, 30977, 31151,
+31313, 31463, 31602, 31731, 31849,
+31958, 32057, 32148, 32229, 32303,
+32370, 32429, 32481, 32528, 32568,
+32604, 32634, 32661, 32683, 32701,
+32717, 32729, 32740, 32748, 32754,
+32758, 32762, 32764, 32766, 32767,
+32767, 32767, 32767, 32767, 32767,
+};
+#endif
+
+#ifndef DEF_LOGN400
+#define DEF_LOGN400
+static const opus_int16 logN400[21] = {
+0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 21, 21, 24, 29, 34, 36, };
+#endif
+
+#ifndef DEF_PULSE_CACHE50
+#define DEF_PULSE_CACHE50
+static const opus_int16 cache_index50[105] = {
+-1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 41, 41, 41,
+82, 82, 123, 164, 200, 222, 0, 0, 0, 0, 0, 0, 0, 0, 41,
+41, 41, 41, 123, 123, 123, 164, 164, 240, 266, 283, 295, 41, 41, 41,
+41, 41, 41, 41, 41, 123, 123, 123, 123, 240, 240, 240, 266, 266, 305,
+318, 328, 336, 123, 123, 123, 123, 123, 123, 123, 123, 240, 240, 240, 240,
+305, 305, 305, 318, 318, 343, 351, 358, 364, 240, 240, 240, 240, 240, 240,
+240, 240, 305, 305, 305, 305, 343, 343, 343, 351, 351, 370, 376, 382, 387,
+};
+static const unsigned char cache_bits50[392] = {
+40, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 40, 15, 23, 28,
+31, 34, 36, 38, 39, 41, 42, 43, 44, 45, 46, 47, 47, 49, 50,
+51, 52, 53, 54, 55, 55, 57, 58, 59, 60, 61, 62, 63, 63, 65,
+66, 67, 68, 69, 70, 71, 71, 40, 20, 33, 41, 48, 53, 57, 61,
+64, 66, 69, 71, 73, 75, 76, 78, 80, 82, 85, 87, 89, 91, 92,
+94, 96, 98, 101, 103, 105, 107, 108, 110, 112, 114, 117, 119, 121, 123,
+124, 126, 128, 40, 23, 39, 51, 60, 67, 73, 79, 83, 87, 91, 94,
+97, 100, 102, 105, 107, 111, 115, 118, 121, 124, 126, 129, 131, 135, 139,
+142, 145, 148, 150, 153, 155, 159, 163, 166, 169, 172, 174, 177, 179, 35,
+28, 49, 65, 78, 89, 99, 107, 114, 120, 126, 132, 136, 141, 145, 149,
+153, 159, 165, 171, 176, 180, 185, 189, 192, 199, 205, 211, 216, 220, 225,
+229, 232, 239, 245, 251, 21, 33, 58, 79, 97, 112, 125, 137, 148, 157,
+166, 174, 182, 189, 195, 201, 207, 217, 227, 235, 243, 251, 17, 35, 63,
+86, 106, 123, 139, 152, 165, 177, 187, 197, 206, 214, 222, 230, 237, 250,
+25, 31, 55, 75, 91, 105, 117, 128, 138, 146, 154, 161, 168, 174, 180,
+185, 190, 200, 208, 215, 222, 229, 235, 240, 245, 255, 16, 36, 65, 89,
+110, 128, 144, 159, 173, 185, 196, 207, 217, 226, 234, 242, 250, 11, 41,
+74, 103, 128, 151, 172, 191, 209, 225, 241, 255, 9, 43, 79, 110, 138,
+163, 186, 207, 227, 246, 12, 39, 71, 99, 123, 144, 164, 182, 198, 214,
+228, 241, 253, 9, 44, 81, 113, 142, 168, 192, 214, 235, 255, 7, 49,
+90, 127, 160, 191, 220, 247, 6, 51, 95, 134, 170, 203, 234, 7, 47,
+87, 123, 155, 184, 212, 237, 6, 52, 97, 137, 174, 208, 240, 5, 57,
+106, 151, 192, 231, 5, 59, 111, 158, 202, 243, 5, 55, 103, 147, 187,
+224, 5, 60, 113, 161, 206, 248, 4, 65, 122, 175, 224, 4, 67, 127,
+182, 234, };
+static const unsigned char cache_caps50[168] = {
+224, 224, 224, 224, 224, 224, 224, 224, 160, 160, 160, 160, 185, 185, 185,
+178, 178, 168, 134, 61, 37, 224, 224, 224, 224, 224, 224, 224, 224, 240,
+240, 240, 240, 207, 207, 207, 198, 198, 183, 144, 66, 40, 160, 160, 160,
+160, 160, 160, 160, 160, 185, 185, 185, 185, 193, 193, 193, 183, 183, 172,
+138, 64, 38, 240, 240, 240, 240, 240, 240, 240, 240, 207, 207, 207, 207,
+204, 204, 204, 193, 193, 180, 143, 66, 40, 185, 185, 185, 185, 185, 185,
+185, 185, 193, 193, 193, 193, 193, 193, 193, 183, 183, 172, 138, 65, 39,
+207, 207, 207, 207, 207, 207, 207, 207, 204, 204, 204, 204, 201, 201, 201,
+188, 188, 176, 141, 66, 40, 193, 193, 193, 193, 193, 193, 193, 193, 193,
+193, 193, 193, 194, 194, 194, 184, 184, 173, 139, 65, 39, 204, 204, 204,
+204, 204, 204, 204, 204, 201, 201, 201, 201, 198, 198, 198, 187, 187, 175,
+140, 66, 40, };
+#endif
+
+#ifndef FFT_TWIDDLES48000_960
+#define FFT_TWIDDLES48000_960
+static const kiss_twiddle_cpx fft_twiddles48000_960[480] = {
+{32767, 0}, {32766, -429},
+{32757, -858}, {32743, -1287},
+{32724, -1715}, {32698, -2143},
+{32667, -2570}, {32631, -2998},
+{32588, -3425}, {32541, -3851},
+{32488, -4277}, {32429, -4701},
+{32364, -5125}, {32295, -5548},
+{32219, -5971}, {32138, -6393},
+{32051, -6813}, {31960, -7231},
+{31863, -7650}, {31760, -8067},
+{31652, -8481}, {31539, -8895},
+{31419, -9306}, {31294, -9716},
+{31165, -10126}, {31030, -10532},
+{30889, -10937}, {30743, -11340},
+{30592, -11741}, {30436, -12141},
+{30274, -12540}, {30107, -12935},
+{29936, -13328}, {29758, -13718},
+{29577, -14107}, {29390, -14493},
+{29197, -14875}, {29000, -15257},
+{28797, -15635}, {28590, -16010},
+{28379, -16384}, {28162, -16753},
+{27940, -17119}, {27714, -17484},
+{27482, -17845}, {27246, -18205},
+{27006, -18560}, {26760, -18911},
+{26510, -19260}, {26257, -19606},
+{25997, -19947}, {25734, -20286},
+{25466, -20621}, {25194, -20952},
+{24918, -21281}, {24637, -21605},
+{24353, -21926}, {24063, -22242},
+{23770, -22555}, {23473, -22865},
+{23171, -23171}, {22866, -23472},
+{22557, -23769}, {22244, -24063},
+{21927, -24352}, {21606, -24636},
+{21282, -24917}, {20954, -25194},
+{20622, -25465}, {20288, -25733},
+{19949, -25997}, {19607, -26255},
+{19261, -26509}, {18914, -26760},
+{18561, -27004}, {18205, -27246},
+{17846, -27481}, {17485, -27713},
+{17122, -27940}, {16755, -28162},
+{16385, -28378}, {16012, -28590},
+{15636, -28797}, {15258, -28999},
+{14878, -29197}, {14494, -29389},
+{14108, -29576}, {13720, -29757},
+{13329, -29934}, {12937, -30107},
+{12540, -30274}, {12142, -30435},
+{11744, -30592}, {11342, -30743},
+{10939, -30889}, {10534, -31030},
+{10127, -31164}, {9718, -31294},
+{9307, -31418}, {8895, -31537},
+{8482, -31652}, {8067, -31759},
+{7650, -31862}, {7233, -31960},
+{6815, -32051}, {6393, -32138},
+{5973, -32219}, {5549, -32294},
+{5127, -32364}, {4703, -32429},
+{4278, -32487}, {3852, -32541},
+{3426, -32588}, {2999, -32630},
+{2572, -32667}, {2144, -32698},
+{1716, -32724}, {1287, -32742},
+{860, -32757}, {430, -32766},
+{0, -32767}, {-429, -32766},
+{-858, -32757}, {-1287, -32743},
+{-1715, -32724}, {-2143, -32698},
+{-2570, -32667}, {-2998, -32631},
+{-3425, -32588}, {-3851, -32541},
+{-4277, -32488}, {-4701, -32429},
+{-5125, -32364}, {-5548, -32295},
+{-5971, -32219}, {-6393, -32138},
+{-6813, -32051}, {-7231, -31960},
+{-7650, -31863}, {-8067, -31760},
+{-8481, -31652}, {-8895, -31539},
+{-9306, -31419}, {-9716, -31294},
+{-10126, -31165}, {-10532, -31030},
+{-10937, -30889}, {-11340, -30743},
+{-11741, -30592}, {-12141, -30436},
+{-12540, -30274}, {-12935, -30107},
+{-13328, -29936}, {-13718, -29758},
+{-14107, -29577}, {-14493, -29390},
+{-14875, -29197}, {-15257, -29000},
+{-15635, -28797}, {-16010, -28590},
+{-16384, -28379}, {-16753, -28162},
+{-17119, -27940}, {-17484, -27714},
+{-17845, -27482}, {-18205, -27246},
+{-18560, -27006}, {-18911, -26760},
+{-19260, -26510}, {-19606, -26257},
+{-19947, -25997}, {-20286, -25734},
+{-20621, -25466}, {-20952, -25194},
+{-21281, -24918}, {-21605, -24637},
+{-21926, -24353}, {-22242, -24063},
+{-22555, -23770}, {-22865, -23473},
+{-23171, -23171}, {-23472, -22866},
+{-23769, -22557}, {-24063, -22244},
+{-24352, -21927}, {-24636, -21606},
+{-24917, -21282}, {-25194, -20954},
+{-25465, -20622}, {-25733, -20288},
+{-25997, -19949}, {-26255, -19607},
+{-26509, -19261}, {-26760, -18914},
+{-27004, -18561}, {-27246, -18205},
+{-27481, -17846}, {-27713, -17485},
+{-27940, -17122}, {-28162, -16755},
+{-28378, -16385}, {-28590, -16012},
+{-28797, -15636}, {-28999, -15258},
+{-29197, -14878}, {-29389, -14494},
+{-29576, -14108}, {-29757, -13720},
+{-29934, -13329}, {-30107, -12937},
+{-30274, -12540}, {-30435, -12142},
+{-30592, -11744}, {-30743, -11342},
+{-30889, -10939}, {-31030, -10534},
+{-31164, -10127}, {-31294, -9718},
+{-31418, -9307}, {-31537, -8895},
+{-31652, -8482}, {-31759, -8067},
+{-31862, -7650}, {-31960, -7233},
+{-32051, -6815}, {-32138, -6393},
+{-32219, -5973}, {-32294, -5549},
+{-32364, -5127}, {-32429, -4703},
+{-32487, -4278}, {-32541, -3852},
+{-32588, -3426}, {-32630, -2999},
+{-32667, -2572}, {-32698, -2144},
+{-32724, -1716}, {-32742, -1287},
+{-32757, -860}, {-32766, -430},
+{-32767, 0}, {-32766, 429},
+{-32757, 858}, {-32743, 1287},
+{-32724, 1715}, {-32698, 2143},
+{-32667, 2570}, {-32631, 2998},
+{-32588, 3425}, {-32541, 3851},
+{-32488, 4277}, {-32429, 4701},
+{-32364, 5125}, {-32295, 5548},
+{-32219, 5971}, {-32138, 6393},
+{-32051, 6813}, {-31960, 7231},
+{-31863, 7650}, {-31760, 8067},
+{-31652, 8481}, {-31539, 8895},
+{-31419, 9306}, {-31294, 9716},
+{-31165, 10126}, {-31030, 10532},
+{-30889, 10937}, {-30743, 11340},
+{-30592, 11741}, {-30436, 12141},
+{-30274, 12540}, {-30107, 12935},
+{-29936, 13328}, {-29758, 13718},
+{-29577, 14107}, {-29390, 14493},
+{-29197, 14875}, {-29000, 15257},
+{-28797, 15635}, {-28590, 16010},
+{-28379, 16384}, {-28162, 16753},
+{-27940, 17119}, {-27714, 17484},
+{-27482, 17845}, {-27246, 18205},
+{-27006, 18560}, {-26760, 18911},
+{-26510, 19260}, {-26257, 19606},
+{-25997, 19947}, {-25734, 20286},
+{-25466, 20621}, {-25194, 20952},
+{-24918, 21281}, {-24637, 21605},
+{-24353, 21926}, {-24063, 22242},
+{-23770, 22555}, {-23473, 22865},
+{-23171, 23171}, {-22866, 23472},
+{-22557, 23769}, {-22244, 24063},
+{-21927, 24352}, {-21606, 24636},
+{-21282, 24917}, {-20954, 25194},
+{-20622, 25465}, {-20288, 25733},
+{-19949, 25997}, {-19607, 26255},
+{-19261, 26509}, {-18914, 26760},
+{-18561, 27004}, {-18205, 27246},
+{-17846, 27481}, {-17485, 27713},
+{-17122, 27940}, {-16755, 28162},
+{-16385, 28378}, {-16012, 28590},
+{-15636, 28797}, {-15258, 28999},
+{-14878, 29197}, {-14494, 29389},
+{-14108, 29576}, {-13720, 29757},
+{-13329, 29934}, {-12937, 30107},
+{-12540, 30274}, {-12142, 30435},
+{-11744, 30592}, {-11342, 30743},
+{-10939, 30889}, {-10534, 31030},
+{-10127, 31164}, {-9718, 31294},
+{-9307, 31418}, {-8895, 31537},
+{-8482, 31652}, {-8067, 31759},
+{-7650, 31862}, {-7233, 31960},
+{-6815, 32051}, {-6393, 32138},
+{-5973, 32219}, {-5549, 32294},
+{-5127, 32364}, {-4703, 32429},
+{-4278, 32487}, {-3852, 32541},
+{-3426, 32588}, {-2999, 32630},
+{-2572, 32667}, {-2144, 32698},
+{-1716, 32724}, {-1287, 32742},
+{-860, 32757}, {-430, 32766},
+{0, 32767}, {429, 32766},
+{858, 32757}, {1287, 32743},
+{1715, 32724}, {2143, 32698},
+{2570, 32667}, {2998, 32631},
+{3425, 32588}, {3851, 32541},
+{4277, 32488}, {4701, 32429},
+{5125, 32364}, {5548, 32295},
+{5971, 32219}, {6393, 32138},
+{6813, 32051}, {7231, 31960},
+{7650, 31863}, {8067, 31760},
+{8481, 31652}, {8895, 31539},
+{9306, 31419}, {9716, 31294},
+{10126, 31165}, {10532, 31030},
+{10937, 30889}, {11340, 30743},
+{11741, 30592}, {12141, 30436},
+{12540, 30274}, {12935, 30107},
+{13328, 29936}, {13718, 29758},
+{14107, 29577}, {14493, 29390},
+{14875, 29197}, {15257, 29000},
+{15635, 28797}, {16010, 28590},
+{16384, 28379}, {16753, 28162},
+{17119, 27940}, {17484, 27714},
+{17845, 27482}, {18205, 27246},
+{18560, 27006}, {18911, 26760},
+{19260, 26510}, {19606, 26257},
+{19947, 25997}, {20286, 25734},
+{20621, 25466}, {20952, 25194},
+{21281, 24918}, {21605, 24637},
+{21926, 24353}, {22242, 24063},
+{22555, 23770}, {22865, 23473},
+{23171, 23171}, {23472, 22866},
+{23769, 22557}, {24063, 22244},
+{24352, 21927}, {24636, 21606},
+{24917, 21282}, {25194, 20954},
+{25465, 20622}, {25733, 20288},
+{25997, 19949}, {26255, 19607},
+{26509, 19261}, {26760, 18914},
+{27004, 18561}, {27246, 18205},
+{27481, 17846}, {27713, 17485},
+{27940, 17122}, {28162, 16755},
+{28378, 16385}, {28590, 16012},
+{28797, 15636}, {28999, 15258},
+{29197, 14878}, {29389, 14494},
+{29576, 14108}, {29757, 13720},
+{29934, 13329}, {30107, 12937},
+{30274, 12540}, {30435, 12142},
+{30592, 11744}, {30743, 11342},
+{30889, 10939}, {31030, 10534},
+{31164, 10127}, {31294, 9718},
+{31418, 9307}, {31537, 8895},
+{31652, 8482}, {31759, 8067},
+{31862, 7650}, {31960, 7233},
+{32051, 6815}, {32138, 6393},
+{32219, 5973}, {32294, 5549},
+{32364, 5127}, {32429, 4703},
+{32487, 4278}, {32541, 3852},
+{32588, 3426}, {32630, 2999},
+{32667, 2572}, {32698, 2144},
+{32724, 1716}, {32742, 1287},
+{32757, 860}, {32766, 430},
+};
+#ifndef FFT_BITREV480
+#define FFT_BITREV480
+static const opus_int16 fft_bitrev480[480] = {
+0, 120, 240, 360, 30, 150, 270, 390, 60, 180, 300, 420, 90, 210, 330,
+450, 15, 135, 255, 375, 45, 165, 285, 405, 75, 195, 315, 435, 105, 225,
+345, 465, 5, 125, 245, 365, 35, 155, 275, 395, 65, 185, 305, 425, 95,
+215, 335, 455, 20, 140, 260, 380, 50, 170, 290, 410, 80, 200, 320, 440,
+110, 230, 350, 470, 10, 130, 250, 370, 40, 160, 280, 400, 70, 190, 310,
+430, 100, 220, 340, 460, 25, 145, 265, 385, 55, 175, 295, 415, 85, 205,
+325, 445, 115, 235, 355, 475, 1, 121, 241, 361, 31, 151, 271, 391, 61,
+181, 301, 421, 91, 211, 331, 451, 16, 136, 256, 376, 46, 166, 286, 406,
+76, 196, 316, 436, 106, 226, 346, 466, 6, 126, 246, 366, 36, 156, 276,
+396, 66, 186, 306, 426, 96, 216, 336, 456, 21, 141, 261, 381, 51, 171,
+291, 411, 81, 201, 321, 441, 111, 231, 351, 471, 11, 131, 251, 371, 41,
+161, 281, 401, 71, 191, 311, 431, 101, 221, 341, 461, 26, 146, 266, 386,
+56, 176, 296, 416, 86, 206, 326, 446, 116, 236, 356, 476, 2, 122, 242,
+362, 32, 152, 272, 392, 62, 182, 302, 422, 92, 212, 332, 452, 17, 137,
+257, 377, 47, 167, 287, 407, 77, 197, 317, 437, 107, 227, 347, 467, 7,
+127, 247, 367, 37, 157, 277, 397, 67, 187, 307, 427, 97, 217, 337, 457,
+22, 142, 262, 382, 52, 172, 292, 412, 82, 202, 322, 442, 112, 232, 352,
+472, 12, 132, 252, 372, 42, 162, 282, 402, 72, 192, 312, 432, 102, 222,
+342, 462, 27, 147, 267, 387, 57, 177, 297, 417, 87, 207, 327, 447, 117,
+237, 357, 477, 3, 123, 243, 363, 33, 153, 273, 393, 63, 183, 303, 423,
+93, 213, 333, 453, 18, 138, 258, 378, 48, 168, 288, 408, 78, 198, 318,
+438, 108, 228, 348, 468, 8, 128, 248, 368, 38, 158, 278, 398, 68, 188,
+308, 428, 98, 218, 338, 458, 23, 143, 263, 383, 53, 173, 293, 413, 83,
+203, 323, 443, 113, 233, 353, 473, 13, 133, 253, 373, 43, 163, 283, 403,
+73, 193, 313, 433, 103, 223, 343, 463, 28, 148, 268, 388, 58, 178, 298,
+418, 88, 208, 328, 448, 118, 238, 358, 478, 4, 124, 244, 364, 34, 154,
+274, 394, 64, 184, 304, 424, 94, 214, 334, 454, 19, 139, 259, 379, 49,
+169, 289, 409, 79, 199, 319, 439, 109, 229, 349, 469, 9, 129, 249, 369,
+39, 159, 279, 399, 69, 189, 309, 429, 99, 219, 339, 459, 24, 144, 264,
+384, 54, 174, 294, 414, 84, 204, 324, 444, 114, 234, 354, 474, 14, 134,
+254, 374, 44, 164, 284, 404, 74, 194, 314, 434, 104, 224, 344, 464, 29,
+149, 269, 389, 59, 179, 299, 419, 89, 209, 329, 449, 119, 239, 359, 479,
+};
+#endif
+
+#ifndef FFT_BITREV240
+#define FFT_BITREV240
+static const opus_int16 fft_bitrev240[240] = {
+0, 60, 120, 180, 15, 75, 135, 195, 30, 90, 150, 210, 45, 105, 165,
+225, 5, 65, 125, 185, 20, 80, 140, 200, 35, 95, 155, 215, 50, 110,
+170, 230, 10, 70, 130, 190, 25, 85, 145, 205, 40, 100, 160, 220, 55,
+115, 175, 235, 1, 61, 121, 181, 16, 76, 136, 196, 31, 91, 151, 211,
+46, 106, 166, 226, 6, 66, 126, 186, 21, 81, 141, 201, 36, 96, 156,
+216, 51, 111, 171, 231, 11, 71, 131, 191, 26, 86, 146, 206, 41, 101,
+161, 221, 56, 116, 176, 236, 2, 62, 122, 182, 17, 77, 137, 197, 32,
+92, 152, 212, 47, 107, 167, 227, 7, 67, 127, 187, 22, 82, 142, 202,
+37, 97, 157, 217, 52, 112, 172, 232, 12, 72, 132, 192, 27, 87, 147,
+207, 42, 102, 162, 222, 57, 117, 177, 237, 3, 63, 123, 183, 18, 78,
+138, 198, 33, 93, 153, 213, 48, 108, 168, 228, 8, 68, 128, 188, 23,
+83, 143, 203, 38, 98, 158, 218, 53, 113, 173, 233, 13, 73, 133, 193,
+28, 88, 148, 208, 43, 103, 163, 223, 58, 118, 178, 238, 4, 64, 124,
+184, 19, 79, 139, 199, 34, 94, 154, 214, 49, 109, 169, 229, 9, 69,
+129, 189, 24, 84, 144, 204, 39, 99, 159, 219, 54, 114, 174, 234, 14,
+74, 134, 194, 29, 89, 149, 209, 44, 104, 164, 224, 59, 119, 179, 239,
+};
+#endif
+
+#ifndef FFT_BITREV120
+#define FFT_BITREV120
+static const opus_int16 fft_bitrev120[120] = {
+0, 30, 60, 90, 15, 45, 75, 105, 5, 35, 65, 95, 20, 50, 80,
+110, 10, 40, 70, 100, 25, 55, 85, 115, 1, 31, 61, 91, 16, 46,
+76, 106, 6, 36, 66, 96, 21, 51, 81, 111, 11, 41, 71, 101, 26,
+56, 86, 116, 2, 32, 62, 92, 17, 47, 77, 107, 7, 37, 67, 97,
+22, 52, 82, 112, 12, 42, 72, 102, 27, 57, 87, 117, 3, 33, 63,
+93, 18, 48, 78, 108, 8, 38, 68, 98, 23, 53, 83, 113, 13, 43,
+73, 103, 28, 58, 88, 118, 4, 34, 64, 94, 19, 49, 79, 109, 9,
+39, 69, 99, 24, 54, 84, 114, 14, 44, 74, 104, 29, 59, 89, 119,
+};
+#endif
+
+#ifndef FFT_BITREV60
+#define FFT_BITREV60
+static const opus_int16 fft_bitrev60[60] = {
+0, 15, 30, 45, 5, 20, 35, 50, 10, 25, 40, 55, 1, 16, 31,
+46, 6, 21, 36, 51, 11, 26, 41, 56, 2, 17, 32, 47, 7, 22,
+37, 52, 12, 27, 42, 57, 3, 18, 33, 48, 8, 23, 38, 53, 13,
+28, 43, 58, 4, 19, 34, 49, 9, 24, 39, 54, 14, 29, 44, 59,
+};
+#endif
+
+#ifndef FFT_STATE48000_960_0
+#define FFT_STATE48000_960_0
+static const kiss_fft_state fft_state48000_960_0 = {
+480, /* nfft */
+-1, /* shift */
+{4, 120, 4, 30, 2, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, }, /* factors */
+fft_bitrev480, /* bitrev */
+fft_twiddles48000_960, /* bitrev */
+};
+#endif
+
+#ifndef FFT_STATE48000_960_1
+#define FFT_STATE48000_960_1
+static const kiss_fft_state fft_state48000_960_1 = {
+240, /* nfft */
+1, /* shift */
+{4, 60, 4, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */
+fft_bitrev240, /* bitrev */
+fft_twiddles48000_960, /* bitrev */
+};
+#endif
+
+#ifndef FFT_STATE48000_960_2
+#define FFT_STATE48000_960_2
+static const kiss_fft_state fft_state48000_960_2 = {
+120, /* nfft */
+2, /* shift */
+{4, 30, 2, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */
+fft_bitrev120, /* bitrev */
+fft_twiddles48000_960, /* bitrev */
+};
+#endif
+
+#ifndef FFT_STATE48000_960_3
+#define FFT_STATE48000_960_3
+static const kiss_fft_state fft_state48000_960_3 = {
+60, /* nfft */
+3, /* shift */
+{4, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */
+fft_bitrev60, /* bitrev */
+fft_twiddles48000_960, /* bitrev */
+};
+#endif
+
+#endif
+
+#ifndef MDCT_TWIDDLES960
+#define MDCT_TWIDDLES960
+static const opus_val16 mdct_twiddles960[481] = {
+32767, 32767, 32767, 32767, 32766,
+32763, 32762, 32759, 32757, 32753,
+32751, 32747, 32743, 32738, 32733,
+32729, 32724, 32717, 32711, 32705,
+32698, 32690, 32683, 32676, 32667,
+32658, 32650, 32640, 32631, 32620,
+32610, 32599, 32588, 32577, 32566,
+32554, 32541, 32528, 32515, 32502,
+32487, 32474, 32459, 32444, 32429,
+32413, 32397, 32381, 32364, 32348,
+32331, 32313, 32294, 32277, 32257,
+32239, 32219, 32200, 32180, 32159,
+32138, 32118, 32096, 32074, 32051,
+32029, 32006, 31984, 31960, 31936,
+31912, 31888, 31863, 31837, 31812,
+31786, 31760, 31734, 31707, 31679,
+31652, 31624, 31596, 31567, 31539,
+31508, 31479, 31450, 31419, 31388,
+31357, 31326, 31294, 31262, 31230,
+31198, 31164, 31131, 31097, 31063,
+31030, 30994, 30959, 30924, 30889,
+30853, 30816, 30779, 30743, 30705,
+30668, 30629, 30592, 30553, 30515,
+30475, 30435, 30396, 30356, 30315,
+30274, 30233, 30191, 30149, 30107,
+30065, 30022, 29979, 29936, 29891,
+29847, 29803, 29758, 29713, 29668,
+29622, 29577, 29529, 29483, 29436,
+29390, 29341, 29293, 29246, 29197,
+29148, 29098, 29050, 29000, 28949,
+28899, 28848, 28797, 28746, 28694,
+28642, 28590, 28537, 28485, 28432,
+28378, 28324, 28271, 28217, 28162,
+28106, 28051, 27995, 27940, 27884,
+27827, 27770, 27713, 27657, 27598,
+27540, 27481, 27423, 27365, 27305,
+27246, 27187, 27126, 27066, 27006,
+26945, 26883, 26822, 26760, 26698,
+26636, 26574, 26510, 26448, 26383,
+26320, 26257, 26191, 26127, 26062,
+25997, 25931, 25866, 25800, 25734,
+25667, 25601, 25533, 25466, 25398,
+25330, 25262, 25194, 25125, 25056,
+24987, 24917, 24848, 24778, 24707,
+24636, 24566, 24495, 24424, 24352,
+24280, 24208, 24135, 24063, 23990,
+23917, 23842, 23769, 23695, 23622,
+23546, 23472, 23398, 23322, 23246,
+23171, 23095, 23018, 22942, 22866,
+22788, 22711, 22634, 22557, 22478,
+22400, 22322, 22244, 22165, 22085,
+22006, 21927, 21846, 21766, 21687,
+21606, 21524, 21443, 21363, 21282,
+21199, 21118, 21035, 20954, 20870,
+20788, 20705, 20621, 20538, 20455,
+20371, 20286, 20202, 20118, 20034,
+19947, 19863, 19777, 19692, 19606,
+19520, 19434, 19347, 19260, 19174,
+19088, 18999, 18911, 18825, 18737,
+18648, 18560, 18472, 18384, 18294,
+18205, 18116, 18025, 17936, 17846,
+17757, 17666, 17576, 17485, 17395,
+17303, 17212, 17122, 17030, 16937,
+16846, 16755, 16662, 16569, 16477,
+16385, 16291, 16198, 16105, 16012,
+15917, 15824, 15730, 15636, 15541,
+15447, 15352, 15257, 15162, 15067,
+14973, 14875, 14781, 14685, 14589,
+14493, 14396, 14300, 14204, 14107,
+14010, 13914, 13815, 13718, 13621,
+13524, 13425, 13328, 13230, 13133,
+13033, 12935, 12836, 12738, 12638,
+12540, 12441, 12341, 12241, 12142,
+12044, 11943, 11843, 11744, 11643,
+11542, 11442, 11342, 11241, 11139,
+11039, 10939, 10836, 10736, 10635,
+10534, 10431, 10330, 10228, 10127,
+10024, 9921, 9820, 9718, 9614,
+9512, 9410, 9306, 9204, 9101,
+8998, 8895, 8791, 8689, 8585,
+8481, 8377, 8274, 8171, 8067,
+7962, 7858, 7753, 7650, 7545,
+7441, 7336, 7231, 7129, 7023,
+6917, 6813, 6709, 6604, 6498,
+6393, 6288, 6182, 6077, 5973,
+5867, 5760, 5656, 5549, 5445,
+5339, 5232, 5127, 5022, 4914,
+4809, 4703, 4596, 4490, 4384,
+4278, 4171, 4065, 3958, 3852,
+3745, 3640, 3532, 3426, 3318,
+3212, 3106, 2998, 2891, 2786,
+2679, 2570, 2465, 2358, 2251,
+2143, 2037, 1929, 1823, 1715,
+1609, 1501, 1393, 1287, 1180,
+1073, 964, 858, 751, 644,
+535, 429, 322, 214, 107,
+0, };
+#endif
+
+static const CELTMode mode48000_960_120 = {
+48000, /* Fs */
+120, /* overlap */
+21, /* nbEBands */
+21, /* effEBands */
+{27853, 0, 4096, 8192, }, /* preemph */
+eband5ms, /* eBands */
+3, /* maxLM */
+8, /* nbShortMdcts */
+120, /* shortMdctSize */
+11, /* nbAllocVectors */
+band_allocation, /* allocVectors */
+logN400, /* logN */
+window120, /* window */
+{1920, 3, {&fft_state48000_960_0, &fft_state48000_960_1, &fft_state48000_960_2, &fft_state48000_960_3, }, mdct_twiddles960}, /* mdct */
+{392, cache_index50, cache_bits50, cache_caps50}, /* cache */
+};
+
+/* List of all the available modes */
+#define TOTAL_MODES 1
+static const CELTMode * const static_mode_list[TOTAL_MODES] = {
+&mode48000_960_120,
+};
diff --git a/drivers/opus/celt/static_modes_float.h b/drivers/opus/celt/static_modes_float.h
new file mode 100644
index 0000000000..362be6cca8
--- /dev/null
+++ b/drivers/opus/celt/static_modes_float.h
@@ -0,0 +1,599 @@
+/* The contents of this file was automatically generated by dump_modes.c
+ with arguments: 48000 960
+ It contains static definitions for some pre-defined modes. */
+#include "opus/celt/opus_modes.h"
+#include "opus/celt/rate.h"
+
+#ifndef DEF_WINDOW120
+#define DEF_WINDOW120
+static const opus_val16 window120[120] = {
+6.7286966e-05f, 0.00060551348f, 0.0016815970f, 0.0032947962f, 0.0054439943f,
+0.0081276923f, 0.011344001f, 0.015090633f, 0.019364886f, 0.024163635f,
+0.029483315f, 0.035319905f, 0.041668911f, 0.048525347f, 0.055883718f,
+0.063737999f, 0.072081616f, 0.080907428f, 0.090207705f, 0.099974111f,
+0.11019769f, 0.12086883f, 0.13197729f, 0.14351214f, 0.15546177f,
+0.16781389f, 0.18055550f, 0.19367290f, 0.20715171f, 0.22097682f,
+0.23513243f, 0.24960208f, 0.26436860f, 0.27941419f, 0.29472040f,
+0.31026818f, 0.32603788f, 0.34200931f, 0.35816177f, 0.37447407f,
+0.39092462f, 0.40749142f, 0.42415215f, 0.44088423f, 0.45766484f,
+0.47447104f, 0.49127978f, 0.50806798f, 0.52481261f, 0.54149077f,
+0.55807973f, 0.57455701f, 0.59090049f, 0.60708841f, 0.62309951f,
+0.63891306f, 0.65450896f, 0.66986776f, 0.68497077f, 0.69980010f,
+0.71433873f, 0.72857055f, 0.74248043f, 0.75605424f, 0.76927895f,
+0.78214257f, 0.79463430f, 0.80674445f, 0.81846456f, 0.82978733f,
+0.84070669f, 0.85121779f, 0.86131698f, 0.87100183f, 0.88027111f,
+0.88912479f, 0.89756398f, 0.90559094f, 0.91320904f, 0.92042270f,
+0.92723738f, 0.93365955f, 0.93969656f, 0.94535671f, 0.95064907f,
+0.95558353f, 0.96017067f, 0.96442171f, 0.96834849f, 0.97196334f,
+0.97527906f, 0.97830883f, 0.98106616f, 0.98356480f, 0.98581869f,
+0.98784191f, 0.98964856f, 0.99125274f, 0.99266849f, 0.99390969f,
+0.99499004f, 0.99592297f, 0.99672162f, 0.99739874f, 0.99796667f,
+0.99843728f, 0.99882195f, 0.99913147f, 0.99937606f, 0.99956527f,
+0.99970802f, 0.99981248f, 0.99988613f, 0.99993565f, 0.99996697f,
+0.99998518f, 0.99999457f, 0.99999859f, 0.99999982f, 1.0000000f,
+};
+#endif
+
+#ifndef DEF_LOGN400
+#define DEF_LOGN400
+static const opus_int16 logN400[21] = {
+0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 16, 16, 16, 21, 21, 24, 29, 34, 36, };
+#endif
+
+#ifndef DEF_PULSE_CACHE50
+#define DEF_PULSE_CACHE50
+static const opus_int16 cache_index50[105] = {
+-1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 41, 41, 41,
+82, 82, 123, 164, 200, 222, 0, 0, 0, 0, 0, 0, 0, 0, 41,
+41, 41, 41, 123, 123, 123, 164, 164, 240, 266, 283, 295, 41, 41, 41,
+41, 41, 41, 41, 41, 123, 123, 123, 123, 240, 240, 240, 266, 266, 305,
+318, 328, 336, 123, 123, 123, 123, 123, 123, 123, 123, 240, 240, 240, 240,
+305, 305, 305, 318, 318, 343, 351, 358, 364, 240, 240, 240, 240, 240, 240,
+240, 240, 305, 305, 305, 305, 343, 343, 343, 351, 351, 370, 376, 382, 387,
+};
+static const unsigned char cache_bits50[392] = {
+40, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 40, 15, 23, 28,
+31, 34, 36, 38, 39, 41, 42, 43, 44, 45, 46, 47, 47, 49, 50,
+51, 52, 53, 54, 55, 55, 57, 58, 59, 60, 61, 62, 63, 63, 65,
+66, 67, 68, 69, 70, 71, 71, 40, 20, 33, 41, 48, 53, 57, 61,
+64, 66, 69, 71, 73, 75, 76, 78, 80, 82, 85, 87, 89, 91, 92,
+94, 96, 98, 101, 103, 105, 107, 108, 110, 112, 114, 117, 119, 121, 123,
+124, 126, 128, 40, 23, 39, 51, 60, 67, 73, 79, 83, 87, 91, 94,
+97, 100, 102, 105, 107, 111, 115, 118, 121, 124, 126, 129, 131, 135, 139,
+142, 145, 148, 150, 153, 155, 159, 163, 166, 169, 172, 174, 177, 179, 35,
+28, 49, 65, 78, 89, 99, 107, 114, 120, 126, 132, 136, 141, 145, 149,
+153, 159, 165, 171, 176, 180, 185, 189, 192, 199, 205, 211, 216, 220, 225,
+229, 232, 239, 245, 251, 21, 33, 58, 79, 97, 112, 125, 137, 148, 157,
+166, 174, 182, 189, 195, 201, 207, 217, 227, 235, 243, 251, 17, 35, 63,
+86, 106, 123, 139, 152, 165, 177, 187, 197, 206, 214, 222, 230, 237, 250,
+25, 31, 55, 75, 91, 105, 117, 128, 138, 146, 154, 161, 168, 174, 180,
+185, 190, 200, 208, 215, 222, 229, 235, 240, 245, 255, 16, 36, 65, 89,
+110, 128, 144, 159, 173, 185, 196, 207, 217, 226, 234, 242, 250, 11, 41,
+74, 103, 128, 151, 172, 191, 209, 225, 241, 255, 9, 43, 79, 110, 138,
+163, 186, 207, 227, 246, 12, 39, 71, 99, 123, 144, 164, 182, 198, 214,
+228, 241, 253, 9, 44, 81, 113, 142, 168, 192, 214, 235, 255, 7, 49,
+90, 127, 160, 191, 220, 247, 6, 51, 95, 134, 170, 203, 234, 7, 47,
+87, 123, 155, 184, 212, 237, 6, 52, 97, 137, 174, 208, 240, 5, 57,
+106, 151, 192, 231, 5, 59, 111, 158, 202, 243, 5, 55, 103, 147, 187,
+224, 5, 60, 113, 161, 206, 248, 4, 65, 122, 175, 224, 4, 67, 127,
+182, 234, };
+static const unsigned char cache_caps50[168] = {
+224, 224, 224, 224, 224, 224, 224, 224, 160, 160, 160, 160, 185, 185, 185,
+178, 178, 168, 134, 61, 37, 224, 224, 224, 224, 224, 224, 224, 224, 240,
+240, 240, 240, 207, 207, 207, 198, 198, 183, 144, 66, 40, 160, 160, 160,
+160, 160, 160, 160, 160, 185, 185, 185, 185, 193, 193, 193, 183, 183, 172,
+138, 64, 38, 240, 240, 240, 240, 240, 240, 240, 240, 207, 207, 207, 207,
+204, 204, 204, 193, 193, 180, 143, 66, 40, 185, 185, 185, 185, 185, 185,
+185, 185, 193, 193, 193, 193, 193, 193, 193, 183, 183, 172, 138, 65, 39,
+207, 207, 207, 207, 207, 207, 207, 207, 204, 204, 204, 204, 201, 201, 201,
+188, 188, 176, 141, 66, 40, 193, 193, 193, 193, 193, 193, 193, 193, 193,
+193, 193, 193, 194, 194, 194, 184, 184, 173, 139, 65, 39, 204, 204, 204,
+204, 204, 204, 204, 204, 201, 201, 201, 201, 198, 198, 198, 187, 187, 175,
+140, 66, 40, };
+#endif
+
+#ifndef FFT_TWIDDLES48000_960
+#define FFT_TWIDDLES48000_960
+static const kiss_twiddle_cpx fft_twiddles48000_960[480] = {
+{1.0000000f, -0.0000000f}, {0.99991433f, -0.013089596f},
+{0.99965732f, -0.026176948f}, {0.99922904f, -0.039259816f},
+{0.99862953f, -0.052335956f}, {0.99785892f, -0.065403129f},
+{0.99691733f, -0.078459096f}, {0.99580493f, -0.091501619f},
+{0.99452190f, -0.10452846f}, {0.99306846f, -0.11753740f},
+{0.99144486f, -0.13052619f}, {0.98965139f, -0.14349262f},
+{0.98768834f, -0.15643447f}, {0.98555606f, -0.16934950f},
+{0.98325491f, -0.18223553f}, {0.98078528f, -0.19509032f},
+{0.97814760f, -0.20791169f}, {0.97534232f, -0.22069744f},
+{0.97236992f, -0.23344536f}, {0.96923091f, -0.24615329f},
+{0.96592583f, -0.25881905f}, {0.96245524f, -0.27144045f},
+{0.95881973f, -0.28401534f}, {0.95501994f, -0.29654157f},
+{0.95105652f, -0.30901699f}, {0.94693013f, -0.32143947f},
+{0.94264149f, -0.33380686f}, {0.93819134f, -0.34611706f},
+{0.93358043f, -0.35836795f}, {0.92880955f, -0.37055744f},
+{0.92387953f, -0.38268343f}, {0.91879121f, -0.39474386f},
+{0.91354546f, -0.40673664f}, {0.90814317f, -0.41865974f},
+{0.90258528f, -0.43051110f}, {0.89687274f, -0.44228869f},
+{0.89100652f, -0.45399050f}, {0.88498764f, -0.46561452f},
+{0.87881711f, -0.47715876f}, {0.87249601f, -0.48862124f},
+{0.86602540f, -0.50000000f}, {0.85940641f, -0.51129309f},
+{0.85264016f, -0.52249856f}, {0.84572782f, -0.53361452f},
+{0.83867057f, -0.54463904f}, {0.83146961f, -0.55557023f},
+{0.82412619f, -0.56640624f}, {0.81664156f, -0.57714519f},
+{0.80901699f, -0.58778525f}, {0.80125381f, -0.59832460f},
+{0.79335334f, -0.60876143f}, {0.78531693f, -0.61909395f},
+{0.77714596f, -0.62932039f}, {0.76884183f, -0.63943900f},
+{0.76040597f, -0.64944805f}, {0.75183981f, -0.65934582f},
+{0.74314483f, -0.66913061f}, {0.73432251f, -0.67880075f},
+{0.72537437f, -0.68835458f}, {0.71630194f, -0.69779046f},
+{0.70710678f, -0.70710678f}, {0.69779046f, -0.71630194f},
+{0.68835458f, -0.72537437f}, {0.67880075f, -0.73432251f},
+{0.66913061f, -0.74314483f}, {0.65934582f, -0.75183981f},
+{0.64944805f, -0.76040597f}, {0.63943900f, -0.76884183f},
+{0.62932039f, -0.77714596f}, {0.61909395f, -0.78531693f},
+{0.60876143f, -0.79335334f}, {0.59832460f, -0.80125381f},
+{0.58778525f, -0.80901699f}, {0.57714519f, -0.81664156f},
+{0.56640624f, -0.82412619f}, {0.55557023f, -0.83146961f},
+{0.54463904f, -0.83867057f}, {0.53361452f, -0.84572782f},
+{0.52249856f, -0.85264016f}, {0.51129309f, -0.85940641f},
+{0.50000000f, -0.86602540f}, {0.48862124f, -0.87249601f},
+{0.47715876f, -0.87881711f}, {0.46561452f, -0.88498764f},
+{0.45399050f, -0.89100652f}, {0.44228869f, -0.89687274f},
+{0.43051110f, -0.90258528f}, {0.41865974f, -0.90814317f},
+{0.40673664f, -0.91354546f}, {0.39474386f, -0.91879121f},
+{0.38268343f, -0.92387953f}, {0.37055744f, -0.92880955f},
+{0.35836795f, -0.93358043f}, {0.34611706f, -0.93819134f},
+{0.33380686f, -0.94264149f}, {0.32143947f, -0.94693013f},
+{0.30901699f, -0.95105652f}, {0.29654157f, -0.95501994f},
+{0.28401534f, -0.95881973f}, {0.27144045f, -0.96245524f},
+{0.25881905f, -0.96592583f}, {0.24615329f, -0.96923091f},
+{0.23344536f, -0.97236992f}, {0.22069744f, -0.97534232f},
+{0.20791169f, -0.97814760f}, {0.19509032f, -0.98078528f},
+{0.18223553f, -0.98325491f}, {0.16934950f, -0.98555606f},
+{0.15643447f, -0.98768834f}, {0.14349262f, -0.98965139f},
+{0.13052619f, -0.99144486f}, {0.11753740f, -0.99306846f},
+{0.10452846f, -0.99452190f}, {0.091501619f, -0.99580493f},
+{0.078459096f, -0.99691733f}, {0.065403129f, -0.99785892f},
+{0.052335956f, -0.99862953f}, {0.039259816f, -0.99922904f},
+{0.026176948f, -0.99965732f}, {0.013089596f, -0.99991433f},
+{6.1230318e-17f, -1.0000000f}, {-0.013089596f, -0.99991433f},
+{-0.026176948f, -0.99965732f}, {-0.039259816f, -0.99922904f},
+{-0.052335956f, -0.99862953f}, {-0.065403129f, -0.99785892f},
+{-0.078459096f, -0.99691733f}, {-0.091501619f, -0.99580493f},
+{-0.10452846f, -0.99452190f}, {-0.11753740f, -0.99306846f},
+{-0.13052619f, -0.99144486f}, {-0.14349262f, -0.98965139f},
+{-0.15643447f, -0.98768834f}, {-0.16934950f, -0.98555606f},
+{-0.18223553f, -0.98325491f}, {-0.19509032f, -0.98078528f},
+{-0.20791169f, -0.97814760f}, {-0.22069744f, -0.97534232f},
+{-0.23344536f, -0.97236992f}, {-0.24615329f, -0.96923091f},
+{-0.25881905f, -0.96592583f}, {-0.27144045f, -0.96245524f},
+{-0.28401534f, -0.95881973f}, {-0.29654157f, -0.95501994f},
+{-0.30901699f, -0.95105652f}, {-0.32143947f, -0.94693013f},
+{-0.33380686f, -0.94264149f}, {-0.34611706f, -0.93819134f},
+{-0.35836795f, -0.93358043f}, {-0.37055744f, -0.92880955f},
+{-0.38268343f, -0.92387953f}, {-0.39474386f, -0.91879121f},
+{-0.40673664f, -0.91354546f}, {-0.41865974f, -0.90814317f},
+{-0.43051110f, -0.90258528f}, {-0.44228869f, -0.89687274f},
+{-0.45399050f, -0.89100652f}, {-0.46561452f, -0.88498764f},
+{-0.47715876f, -0.87881711f}, {-0.48862124f, -0.87249601f},
+{-0.50000000f, -0.86602540f}, {-0.51129309f, -0.85940641f},
+{-0.52249856f, -0.85264016f}, {-0.53361452f, -0.84572782f},
+{-0.54463904f, -0.83867057f}, {-0.55557023f, -0.83146961f},
+{-0.56640624f, -0.82412619f}, {-0.57714519f, -0.81664156f},
+{-0.58778525f, -0.80901699f}, {-0.59832460f, -0.80125381f},
+{-0.60876143f, -0.79335334f}, {-0.61909395f, -0.78531693f},
+{-0.62932039f, -0.77714596f}, {-0.63943900f, -0.76884183f},
+{-0.64944805f, -0.76040597f}, {-0.65934582f, -0.75183981f},
+{-0.66913061f, -0.74314483f}, {-0.67880075f, -0.73432251f},
+{-0.68835458f, -0.72537437f}, {-0.69779046f, -0.71630194f},
+{-0.70710678f, -0.70710678f}, {-0.71630194f, -0.69779046f},
+{-0.72537437f, -0.68835458f}, {-0.73432251f, -0.67880075f},
+{-0.74314483f, -0.66913061f}, {-0.75183981f, -0.65934582f},
+{-0.76040597f, -0.64944805f}, {-0.76884183f, -0.63943900f},
+{-0.77714596f, -0.62932039f}, {-0.78531693f, -0.61909395f},
+{-0.79335334f, -0.60876143f}, {-0.80125381f, -0.59832460f},
+{-0.80901699f, -0.58778525f}, {-0.81664156f, -0.57714519f},
+{-0.82412619f, -0.56640624f}, {-0.83146961f, -0.55557023f},
+{-0.83867057f, -0.54463904f}, {-0.84572782f, -0.53361452f},
+{-0.85264016f, -0.52249856f}, {-0.85940641f, -0.51129309f},
+{-0.86602540f, -0.50000000f}, {-0.87249601f, -0.48862124f},
+{-0.87881711f, -0.47715876f}, {-0.88498764f, -0.46561452f},
+{-0.89100652f, -0.45399050f}, {-0.89687274f, -0.44228869f},
+{-0.90258528f, -0.43051110f}, {-0.90814317f, -0.41865974f},
+{-0.91354546f, -0.40673664f}, {-0.91879121f, -0.39474386f},
+{-0.92387953f, -0.38268343f}, {-0.92880955f, -0.37055744f},
+{-0.93358043f, -0.35836795f}, {-0.93819134f, -0.34611706f},
+{-0.94264149f, -0.33380686f}, {-0.94693013f, -0.32143947f},
+{-0.95105652f, -0.30901699f}, {-0.95501994f, -0.29654157f},
+{-0.95881973f, -0.28401534f}, {-0.96245524f, -0.27144045f},
+{-0.96592583f, -0.25881905f}, {-0.96923091f, -0.24615329f},
+{-0.97236992f, -0.23344536f}, {-0.97534232f, -0.22069744f},
+{-0.97814760f, -0.20791169f}, {-0.98078528f, -0.19509032f},
+{-0.98325491f, -0.18223553f}, {-0.98555606f, -0.16934950f},
+{-0.98768834f, -0.15643447f}, {-0.98965139f, -0.14349262f},
+{-0.99144486f, -0.13052619f}, {-0.99306846f, -0.11753740f},
+{-0.99452190f, -0.10452846f}, {-0.99580493f, -0.091501619f},
+{-0.99691733f, -0.078459096f}, {-0.99785892f, -0.065403129f},
+{-0.99862953f, -0.052335956f}, {-0.99922904f, -0.039259816f},
+{-0.99965732f, -0.026176948f}, {-0.99991433f, -0.013089596f},
+{-1.0000000f, -1.2246064e-16f}, {-0.99991433f, 0.013089596f},
+{-0.99965732f, 0.026176948f}, {-0.99922904f, 0.039259816f},
+{-0.99862953f, 0.052335956f}, {-0.99785892f, 0.065403129f},
+{-0.99691733f, 0.078459096f}, {-0.99580493f, 0.091501619f},
+{-0.99452190f, 0.10452846f}, {-0.99306846f, 0.11753740f},
+{-0.99144486f, 0.13052619f}, {-0.98965139f, 0.14349262f},
+{-0.98768834f, 0.15643447f}, {-0.98555606f, 0.16934950f},
+{-0.98325491f, 0.18223553f}, {-0.98078528f, 0.19509032f},
+{-0.97814760f, 0.20791169f}, {-0.97534232f, 0.22069744f},
+{-0.97236992f, 0.23344536f}, {-0.96923091f, 0.24615329f},
+{-0.96592583f, 0.25881905f}, {-0.96245524f, 0.27144045f},
+{-0.95881973f, 0.28401534f}, {-0.95501994f, 0.29654157f},
+{-0.95105652f, 0.30901699f}, {-0.94693013f, 0.32143947f},
+{-0.94264149f, 0.33380686f}, {-0.93819134f, 0.34611706f},
+{-0.93358043f, 0.35836795f}, {-0.92880955f, 0.37055744f},
+{-0.92387953f, 0.38268343f}, {-0.91879121f, 0.39474386f},
+{-0.91354546f, 0.40673664f}, {-0.90814317f, 0.41865974f},
+{-0.90258528f, 0.43051110f}, {-0.89687274f, 0.44228869f},
+{-0.89100652f, 0.45399050f}, {-0.88498764f, 0.46561452f},
+{-0.87881711f, 0.47715876f}, {-0.87249601f, 0.48862124f},
+{-0.86602540f, 0.50000000f}, {-0.85940641f, 0.51129309f},
+{-0.85264016f, 0.52249856f}, {-0.84572782f, 0.53361452f},
+{-0.83867057f, 0.54463904f}, {-0.83146961f, 0.55557023f},
+{-0.82412619f, 0.56640624f}, {-0.81664156f, 0.57714519f},
+{-0.80901699f, 0.58778525f}, {-0.80125381f, 0.59832460f},
+{-0.79335334f, 0.60876143f}, {-0.78531693f, 0.61909395f},
+{-0.77714596f, 0.62932039f}, {-0.76884183f, 0.63943900f},
+{-0.76040597f, 0.64944805f}, {-0.75183981f, 0.65934582f},
+{-0.74314483f, 0.66913061f}, {-0.73432251f, 0.67880075f},
+{-0.72537437f, 0.68835458f}, {-0.71630194f, 0.69779046f},
+{-0.70710678f, 0.70710678f}, {-0.69779046f, 0.71630194f},
+{-0.68835458f, 0.72537437f}, {-0.67880075f, 0.73432251f},
+{-0.66913061f, 0.74314483f}, {-0.65934582f, 0.75183981f},
+{-0.64944805f, 0.76040597f}, {-0.63943900f, 0.76884183f},
+{-0.62932039f, 0.77714596f}, {-0.61909395f, 0.78531693f},
+{-0.60876143f, 0.79335334f}, {-0.59832460f, 0.80125381f},
+{-0.58778525f, 0.80901699f}, {-0.57714519f, 0.81664156f},
+{-0.56640624f, 0.82412619f}, {-0.55557023f, 0.83146961f},
+{-0.54463904f, 0.83867057f}, {-0.53361452f, 0.84572782f},
+{-0.52249856f, 0.85264016f}, {-0.51129309f, 0.85940641f},
+{-0.50000000f, 0.86602540f}, {-0.48862124f, 0.87249601f},
+{-0.47715876f, 0.87881711f}, {-0.46561452f, 0.88498764f},
+{-0.45399050f, 0.89100652f}, {-0.44228869f, 0.89687274f},
+{-0.43051110f, 0.90258528f}, {-0.41865974f, 0.90814317f},
+{-0.40673664f, 0.91354546f}, {-0.39474386f, 0.91879121f},
+{-0.38268343f, 0.92387953f}, {-0.37055744f, 0.92880955f},
+{-0.35836795f, 0.93358043f}, {-0.34611706f, 0.93819134f},
+{-0.33380686f, 0.94264149f}, {-0.32143947f, 0.94693013f},
+{-0.30901699f, 0.95105652f}, {-0.29654157f, 0.95501994f},
+{-0.28401534f, 0.95881973f}, {-0.27144045f, 0.96245524f},
+{-0.25881905f, 0.96592583f}, {-0.24615329f, 0.96923091f},
+{-0.23344536f, 0.97236992f}, {-0.22069744f, 0.97534232f},
+{-0.20791169f, 0.97814760f}, {-0.19509032f, 0.98078528f},
+{-0.18223553f, 0.98325491f}, {-0.16934950f, 0.98555606f},
+{-0.15643447f, 0.98768834f}, {-0.14349262f, 0.98965139f},
+{-0.13052619f, 0.99144486f}, {-0.11753740f, 0.99306846f},
+{-0.10452846f, 0.99452190f}, {-0.091501619f, 0.99580493f},
+{-0.078459096f, 0.99691733f}, {-0.065403129f, 0.99785892f},
+{-0.052335956f, 0.99862953f}, {-0.039259816f, 0.99922904f},
+{-0.026176948f, 0.99965732f}, {-0.013089596f, 0.99991433f},
+{-1.8369095e-16f, 1.0000000f}, {0.013089596f, 0.99991433f},
+{0.026176948f, 0.99965732f}, {0.039259816f, 0.99922904f},
+{0.052335956f, 0.99862953f}, {0.065403129f, 0.99785892f},
+{0.078459096f, 0.99691733f}, {0.091501619f, 0.99580493f},
+{0.10452846f, 0.99452190f}, {0.11753740f, 0.99306846f},
+{0.13052619f, 0.99144486f}, {0.14349262f, 0.98965139f},
+{0.15643447f, 0.98768834f}, {0.16934950f, 0.98555606f},
+{0.18223553f, 0.98325491f}, {0.19509032f, 0.98078528f},
+{0.20791169f, 0.97814760f}, {0.22069744f, 0.97534232f},
+{0.23344536f, 0.97236992f}, {0.24615329f, 0.96923091f},
+{0.25881905f, 0.96592583f}, {0.27144045f, 0.96245524f},
+{0.28401534f, 0.95881973f}, {0.29654157f, 0.95501994f},
+{0.30901699f, 0.95105652f}, {0.32143947f, 0.94693013f},
+{0.33380686f, 0.94264149f}, {0.34611706f, 0.93819134f},
+{0.35836795f, 0.93358043f}, {0.37055744f, 0.92880955f},
+{0.38268343f, 0.92387953f}, {0.39474386f, 0.91879121f},
+{0.40673664f, 0.91354546f}, {0.41865974f, 0.90814317f},
+{0.43051110f, 0.90258528f}, {0.44228869f, 0.89687274f},
+{0.45399050f, 0.89100652f}, {0.46561452f, 0.88498764f},
+{0.47715876f, 0.87881711f}, {0.48862124f, 0.87249601f},
+{0.50000000f, 0.86602540f}, {0.51129309f, 0.85940641f},
+{0.52249856f, 0.85264016f}, {0.53361452f, 0.84572782f},
+{0.54463904f, 0.83867057f}, {0.55557023f, 0.83146961f},
+{0.56640624f, 0.82412619f}, {0.57714519f, 0.81664156f},
+{0.58778525f, 0.80901699f}, {0.59832460f, 0.80125381f},
+{0.60876143f, 0.79335334f}, {0.61909395f, 0.78531693f},
+{0.62932039f, 0.77714596f}, {0.63943900f, 0.76884183f},
+{0.64944805f, 0.76040597f}, {0.65934582f, 0.75183981f},
+{0.66913061f, 0.74314483f}, {0.67880075f, 0.73432251f},
+{0.68835458f, 0.72537437f}, {0.69779046f, 0.71630194f},
+{0.70710678f, 0.70710678f}, {0.71630194f, 0.69779046f},
+{0.72537437f, 0.68835458f}, {0.73432251f, 0.67880075f},
+{0.74314483f, 0.66913061f}, {0.75183981f, 0.65934582f},
+{0.76040597f, 0.64944805f}, {0.76884183f, 0.63943900f},
+{0.77714596f, 0.62932039f}, {0.78531693f, 0.61909395f},
+{0.79335334f, 0.60876143f}, {0.80125381f, 0.59832460f},
+{0.80901699f, 0.58778525f}, {0.81664156f, 0.57714519f},
+{0.82412619f, 0.56640624f}, {0.83146961f, 0.55557023f},
+{0.83867057f, 0.54463904f}, {0.84572782f, 0.53361452f},
+{0.85264016f, 0.52249856f}, {0.85940641f, 0.51129309f},
+{0.86602540f, 0.50000000f}, {0.87249601f, 0.48862124f},
+{0.87881711f, 0.47715876f}, {0.88498764f, 0.46561452f},
+{0.89100652f, 0.45399050f}, {0.89687274f, 0.44228869f},
+{0.90258528f, 0.43051110f}, {0.90814317f, 0.41865974f},
+{0.91354546f, 0.40673664f}, {0.91879121f, 0.39474386f},
+{0.92387953f, 0.38268343f}, {0.92880955f, 0.37055744f},
+{0.93358043f, 0.35836795f}, {0.93819134f, 0.34611706f},
+{0.94264149f, 0.33380686f}, {0.94693013f, 0.32143947f},
+{0.95105652f, 0.30901699f}, {0.95501994f, 0.29654157f},
+{0.95881973f, 0.28401534f}, {0.96245524f, 0.27144045f},
+{0.96592583f, 0.25881905f}, {0.96923091f, 0.24615329f},
+{0.97236992f, 0.23344536f}, {0.97534232f, 0.22069744f},
+{0.97814760f, 0.20791169f}, {0.98078528f, 0.19509032f},
+{0.98325491f, 0.18223553f}, {0.98555606f, 0.16934950f},
+{0.98768834f, 0.15643447f}, {0.98965139f, 0.14349262f},
+{0.99144486f, 0.13052619f}, {0.99306846f, 0.11753740f},
+{0.99452190f, 0.10452846f}, {0.99580493f, 0.091501619f},
+{0.99691733f, 0.078459096f}, {0.99785892f, 0.065403129f},
+{0.99862953f, 0.052335956f}, {0.99922904f, 0.039259816f},
+{0.99965732f, 0.026176948f}, {0.99991433f, 0.013089596f},
+};
+#ifndef FFT_BITREV480
+#define FFT_BITREV480
+static const opus_int16 fft_bitrev480[480] = {
+0, 120, 240, 360, 30, 150, 270, 390, 60, 180, 300, 420, 90, 210, 330,
+450, 15, 135, 255, 375, 45, 165, 285, 405, 75, 195, 315, 435, 105, 225,
+345, 465, 5, 125, 245, 365, 35, 155, 275, 395, 65, 185, 305, 425, 95,
+215, 335, 455, 20, 140, 260, 380, 50, 170, 290, 410, 80, 200, 320, 440,
+110, 230, 350, 470, 10, 130, 250, 370, 40, 160, 280, 400, 70, 190, 310,
+430, 100, 220, 340, 460, 25, 145, 265, 385, 55, 175, 295, 415, 85, 205,
+325, 445, 115, 235, 355, 475, 1, 121, 241, 361, 31, 151, 271, 391, 61,
+181, 301, 421, 91, 211, 331, 451, 16, 136, 256, 376, 46, 166, 286, 406,
+76, 196, 316, 436, 106, 226, 346, 466, 6, 126, 246, 366, 36, 156, 276,
+396, 66, 186, 306, 426, 96, 216, 336, 456, 21, 141, 261, 381, 51, 171,
+291, 411, 81, 201, 321, 441, 111, 231, 351, 471, 11, 131, 251, 371, 41,
+161, 281, 401, 71, 191, 311, 431, 101, 221, 341, 461, 26, 146, 266, 386,
+56, 176, 296, 416, 86, 206, 326, 446, 116, 236, 356, 476, 2, 122, 242,
+362, 32, 152, 272, 392, 62, 182, 302, 422, 92, 212, 332, 452, 17, 137,
+257, 377, 47, 167, 287, 407, 77, 197, 317, 437, 107, 227, 347, 467, 7,
+127, 247, 367, 37, 157, 277, 397, 67, 187, 307, 427, 97, 217, 337, 457,
+22, 142, 262, 382, 52, 172, 292, 412, 82, 202, 322, 442, 112, 232, 352,
+472, 12, 132, 252, 372, 42, 162, 282, 402, 72, 192, 312, 432, 102, 222,
+342, 462, 27, 147, 267, 387, 57, 177, 297, 417, 87, 207, 327, 447, 117,
+237, 357, 477, 3, 123, 243, 363, 33, 153, 273, 393, 63, 183, 303, 423,
+93, 213, 333, 453, 18, 138, 258, 378, 48, 168, 288, 408, 78, 198, 318,
+438, 108, 228, 348, 468, 8, 128, 248, 368, 38, 158, 278, 398, 68, 188,
+308, 428, 98, 218, 338, 458, 23, 143, 263, 383, 53, 173, 293, 413, 83,
+203, 323, 443, 113, 233, 353, 473, 13, 133, 253, 373, 43, 163, 283, 403,
+73, 193, 313, 433, 103, 223, 343, 463, 28, 148, 268, 388, 58, 178, 298,
+418, 88, 208, 328, 448, 118, 238, 358, 478, 4, 124, 244, 364, 34, 154,
+274, 394, 64, 184, 304, 424, 94, 214, 334, 454, 19, 139, 259, 379, 49,
+169, 289, 409, 79, 199, 319, 439, 109, 229, 349, 469, 9, 129, 249, 369,
+39, 159, 279, 399, 69, 189, 309, 429, 99, 219, 339, 459, 24, 144, 264,
+384, 54, 174, 294, 414, 84, 204, 324, 444, 114, 234, 354, 474, 14, 134,
+254, 374, 44, 164, 284, 404, 74, 194, 314, 434, 104, 224, 344, 464, 29,
+149, 269, 389, 59, 179, 299, 419, 89, 209, 329, 449, 119, 239, 359, 479,
+};
+#endif
+
+#ifndef FFT_BITREV240
+#define FFT_BITREV240
+static const opus_int16 fft_bitrev240[240] = {
+0, 60, 120, 180, 15, 75, 135, 195, 30, 90, 150, 210, 45, 105, 165,
+225, 5, 65, 125, 185, 20, 80, 140, 200, 35, 95, 155, 215, 50, 110,
+170, 230, 10, 70, 130, 190, 25, 85, 145, 205, 40, 100, 160, 220, 55,
+115, 175, 235, 1, 61, 121, 181, 16, 76, 136, 196, 31, 91, 151, 211,
+46, 106, 166, 226, 6, 66, 126, 186, 21, 81, 141, 201, 36, 96, 156,
+216, 51, 111, 171, 231, 11, 71, 131, 191, 26, 86, 146, 206, 41, 101,
+161, 221, 56, 116, 176, 236, 2, 62, 122, 182, 17, 77, 137, 197, 32,
+92, 152, 212, 47, 107, 167, 227, 7, 67, 127, 187, 22, 82, 142, 202,
+37, 97, 157, 217, 52, 112, 172, 232, 12, 72, 132, 192, 27, 87, 147,
+207, 42, 102, 162, 222, 57, 117, 177, 237, 3, 63, 123, 183, 18, 78,
+138, 198, 33, 93, 153, 213, 48, 108, 168, 228, 8, 68, 128, 188, 23,
+83, 143, 203, 38, 98, 158, 218, 53, 113, 173, 233, 13, 73, 133, 193,
+28, 88, 148, 208, 43, 103, 163, 223, 58, 118, 178, 238, 4, 64, 124,
+184, 19, 79, 139, 199, 34, 94, 154, 214, 49, 109, 169, 229, 9, 69,
+129, 189, 24, 84, 144, 204, 39, 99, 159, 219, 54, 114, 174, 234, 14,
+74, 134, 194, 29, 89, 149, 209, 44, 104, 164, 224, 59, 119, 179, 239,
+};
+#endif
+
+#ifndef FFT_BITREV120
+#define FFT_BITREV120
+static const opus_int16 fft_bitrev120[120] = {
+0, 30, 60, 90, 15, 45, 75, 105, 5, 35, 65, 95, 20, 50, 80,
+110, 10, 40, 70, 100, 25, 55, 85, 115, 1, 31, 61, 91, 16, 46,
+76, 106, 6, 36, 66, 96, 21, 51, 81, 111, 11, 41, 71, 101, 26,
+56, 86, 116, 2, 32, 62, 92, 17, 47, 77, 107, 7, 37, 67, 97,
+22, 52, 82, 112, 12, 42, 72, 102, 27, 57, 87, 117, 3, 33, 63,
+93, 18, 48, 78, 108, 8, 38, 68, 98, 23, 53, 83, 113, 13, 43,
+73, 103, 28, 58, 88, 118, 4, 34, 64, 94, 19, 49, 79, 109, 9,
+39, 69, 99, 24, 54, 84, 114, 14, 44, 74, 104, 29, 59, 89, 119,
+};
+#endif
+
+#ifndef FFT_BITREV60
+#define FFT_BITREV60
+static const opus_int16 fft_bitrev60[60] = {
+0, 15, 30, 45, 5, 20, 35, 50, 10, 25, 40, 55, 1, 16, 31,
+46, 6, 21, 36, 51, 11, 26, 41, 56, 2, 17, 32, 47, 7, 22,
+37, 52, 12, 27, 42, 57, 3, 18, 33, 48, 8, 23, 38, 53, 13,
+28, 43, 58, 4, 19, 34, 49, 9, 24, 39, 54, 14, 29, 44, 59,
+};
+#endif
+
+#ifndef FFT_STATE48000_960_0
+#define FFT_STATE48000_960_0
+static const kiss_fft_state fft_state48000_960_0 = {
+480, /* nfft */
+0.002083333f, /* scale */
+-1, /* shift */
+{4, 120, 4, 30, 2, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, }, /* factors */
+fft_bitrev480, /* bitrev */
+fft_twiddles48000_960, /* bitrev */
+};
+#endif
+
+#ifndef FFT_STATE48000_960_1
+#define FFT_STATE48000_960_1
+static const kiss_fft_state fft_state48000_960_1 = {
+240, /* nfft */
+0.004166667f, /* scale */
+1, /* shift */
+{4, 60, 4, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */
+fft_bitrev240, /* bitrev */
+fft_twiddles48000_960, /* bitrev */
+};
+#endif
+
+#ifndef FFT_STATE48000_960_2
+#define FFT_STATE48000_960_2
+static const kiss_fft_state fft_state48000_960_2 = {
+120, /* nfft */
+0.008333333f, /* scale */
+2, /* shift */
+{4, 30, 2, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */
+fft_bitrev120, /* bitrev */
+fft_twiddles48000_960, /* bitrev */
+};
+#endif
+
+#ifndef FFT_STATE48000_960_3
+#define FFT_STATE48000_960_3
+static const kiss_fft_state fft_state48000_960_3 = {
+60, /* nfft */
+0.016666667f, /* scale */
+3, /* shift */
+{4, 15, 3, 5, 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, /* factors */
+fft_bitrev60, /* bitrev */
+fft_twiddles48000_960, /* bitrev */
+};
+#endif
+
+#endif
+
+#ifndef MDCT_TWIDDLES960
+#define MDCT_TWIDDLES960
+static const opus_val16 mdct_twiddles960[481] = {
+1.0000000f, 0.99999465f, 0.99997858f, 0.99995181f, 0.99991433f,
+0.99986614f, 0.99980724f, 0.99973764f, 0.99965732f, 0.99956631f,
+0.99946459f, 0.99935216f, 0.99922904f, 0.99909521f, 0.99895068f,
+0.99879546f, 0.99862953f, 0.99845292f, 0.99826561f, 0.99806761f,
+0.99785892f, 0.99763955f, 0.99740949f, 0.99716875f, 0.99691733f,
+0.99665524f, 0.99638247f, 0.99609903f, 0.99580493f, 0.99550016f,
+0.99518473f, 0.99485864f, 0.99452190f, 0.99417450f, 0.99381646f,
+0.99344778f, 0.99306846f, 0.99267850f, 0.99227791f, 0.99186670f,
+0.99144486f, 0.99101241f, 0.99056934f, 0.99011566f, 0.98965139f,
+0.98917651f, 0.98869104f, 0.98819498f, 0.98768834f, 0.98717112f,
+0.98664333f, 0.98610497f, 0.98555606f, 0.98499659f, 0.98442657f,
+0.98384600f, 0.98325491f, 0.98265328f, 0.98204113f, 0.98141846f,
+0.98078528f, 0.98014159f, 0.97948742f, 0.97882275f, 0.97814760f,
+0.97746197f, 0.97676588f, 0.97605933f, 0.97534232f, 0.97461487f,
+0.97387698f, 0.97312866f, 0.97236992f, 0.97160077f, 0.97082121f,
+0.97003125f, 0.96923091f, 0.96842019f, 0.96759909f, 0.96676764f,
+0.96592582f, 0.96507367f, 0.96421118f, 0.96333837f, 0.96245523f,
+0.96156180f, 0.96065806f, 0.95974403f, 0.95881973f, 0.95788517f,
+0.95694034f, 0.95598526f, 0.95501995f, 0.95404440f, 0.95305864f,
+0.95206267f, 0.95105651f, 0.95004016f, 0.94901364f, 0.94797697f,
+0.94693013f, 0.94587315f, 0.94480604f, 0.94372882f, 0.94264149f,
+0.94154406f, 0.94043656f, 0.93931897f, 0.93819133f, 0.93705365f,
+0.93590592f, 0.93474818f, 0.93358042f, 0.93240268f, 0.93121493f,
+0.93001722f, 0.92880955f, 0.92759193f, 0.92636438f, 0.92512690f,
+0.92387953f, 0.92262225f, 0.92135509f, 0.92007809f, 0.91879121f,
+0.91749449f, 0.91618795f, 0.91487161f, 0.91354545f, 0.91220952f,
+0.91086382f, 0.90950836f, 0.90814316f, 0.90676824f, 0.90538363f,
+0.90398929f, 0.90258528f, 0.90117161f, 0.89974828f, 0.89831532f,
+0.89687273f, 0.89542055f, 0.89395877f, 0.89248742f, 0.89100652f,
+0.88951606f, 0.88801610f, 0.88650661f, 0.88498764f, 0.88345918f,
+0.88192125f, 0.88037390f, 0.87881711f, 0.87725090f, 0.87567531f,
+0.87409035f, 0.87249599f, 0.87089232f, 0.86927933f, 0.86765699f,
+0.86602540f, 0.86438453f, 0.86273437f, 0.86107503f, 0.85940641f,
+0.85772862f, 0.85604161f, 0.85434547f, 0.85264014f, 0.85092572f,
+0.84920218f, 0.84746955f, 0.84572781f, 0.84397704f, 0.84221721f,
+0.84044838f, 0.83867056f, 0.83688375f, 0.83508799f, 0.83328325f,
+0.83146961f, 0.82964704f, 0.82781562f, 0.82597530f, 0.82412620f,
+0.82226820f, 0.82040144f, 0.81852589f, 0.81664154f, 0.81474847f,
+0.81284665f, 0.81093620f, 0.80901698f, 0.80708914f, 0.80515262f,
+0.80320752f, 0.80125378f, 0.79929149f, 0.79732067f, 0.79534125f,
+0.79335335f, 0.79135691f, 0.78935204f, 0.78733867f, 0.78531691f,
+0.78328674f, 0.78124818f, 0.77920122f, 0.77714595f, 0.77508232f,
+0.77301043f, 0.77093026f, 0.76884183f, 0.76674517f, 0.76464026f,
+0.76252720f, 0.76040593f, 0.75827656f, 0.75613907f, 0.75399349f,
+0.75183978f, 0.74967807f, 0.74750833f, 0.74533054f, 0.74314481f,
+0.74095112f, 0.73874950f, 0.73653993f, 0.73432251f, 0.73209718f,
+0.72986405f, 0.72762307f, 0.72537438f, 0.72311787f, 0.72085359f,
+0.71858162f, 0.71630192f, 0.71401459f, 0.71171956f, 0.70941701f,
+0.70710677f, 0.70478900f, 0.70246363f, 0.70013079f, 0.69779041f,
+0.69544260f, 0.69308738f, 0.69072466f, 0.68835458f, 0.68597709f,
+0.68359229f, 0.68120013f, 0.67880072f, 0.67639404f, 0.67398011f,
+0.67155892f, 0.66913059f, 0.66669509f, 0.66425240f, 0.66180265f,
+0.65934581f, 0.65688191f, 0.65441092f, 0.65193298f, 0.64944801f,
+0.64695613f, 0.64445727f, 0.64195160f, 0.63943902f, 0.63691954f,
+0.63439328f, 0.63186019f, 0.62932037f, 0.62677377f, 0.62422055f,
+0.62166055f, 0.61909394f, 0.61652065f, 0.61394081f, 0.61135435f,
+0.60876139f, 0.60616195f, 0.60355593f, 0.60094349f, 0.59832457f,
+0.59569929f, 0.59306758f, 0.59042957f, 0.58778523f, 0.58513460f,
+0.58247766f, 0.57981452f, 0.57714518f, 0.57446961f, 0.57178793f,
+0.56910013f, 0.56640624f, 0.56370623f, 0.56100023f, 0.55828818f,
+0.55557020f, 0.55284627f, 0.55011641f, 0.54738067f, 0.54463901f,
+0.54189157f, 0.53913828f, 0.53637921f, 0.53361450f, 0.53084398f,
+0.52806787f, 0.52528601f, 0.52249852f, 0.51970543f, 0.51690688f,
+0.51410279f, 0.51129310f, 0.50847793f, 0.50565732f, 0.50283139f,
+0.49999997f, 0.49716321f, 0.49432122f, 0.49147383f, 0.48862118f,
+0.48576340f, 0.48290042f, 0.48003216f, 0.47715876f, 0.47428025f,
+0.47139677f, 0.46850813f, 0.46561448f, 0.46271584f, 0.45981235f,
+0.45690383f, 0.45399042f, 0.45107214f, 0.44814915f, 0.44522124f,
+0.44228868f, 0.43935137f, 0.43640926f, 0.43346247f, 0.43051104f,
+0.42755511f, 0.42459449f, 0.42162932f, 0.41865964f, 0.41568558f,
+0.41270697f, 0.40972393f, 0.40673661f, 0.40374494f, 0.40074884f,
+0.39774844f, 0.39474390f, 0.39173501f, 0.38872193f, 0.38570469f,
+0.38268343f, 0.37965796f, 0.37662842f, 0.37359496f, 0.37055739f,
+0.36751585f, 0.36447038f, 0.36142122f, 0.35836797f, 0.35531089f,
+0.35225000f, 0.34918544f, 0.34611704f, 0.34304493f, 0.33996926f,
+0.33688983f, 0.33380680f, 0.33072019f, 0.32763015f, 0.32453650f,
+0.32143936f, 0.31833890f, 0.31523503f, 0.31212767f, 0.30901696f,
+0.30590306f, 0.30278577f, 0.29966524f, 0.29654150f, 0.29341470f,
+0.29028464f, 0.28715147f, 0.28401522f, 0.28087605f, 0.27773376f,
+0.27458861f, 0.27144052f, 0.26828940f, 0.26513541f, 0.26197859f,
+0.25881907f, 0.25565666f, 0.25249152f, 0.24932367f, 0.24615327f,
+0.24298012f, 0.23980436f, 0.23662604f, 0.23344530f, 0.23026206f,
+0.22707623f, 0.22388809f, 0.22069744f, 0.21750443f, 0.21430908f,
+0.21111156f, 0.20791165f, 0.20470953f, 0.20150520f, 0.19829884f,
+0.19509024f, 0.19187955f, 0.18866692f, 0.18545227f, 0.18223552f,
+0.17901681f, 0.17579631f, 0.17257380f, 0.16934945f, 0.16612328f,
+0.16289546f, 0.15966577f, 0.15643437f, 0.15320141f, 0.14996669f,
+0.14673037f, 0.14349260f, 0.14025329f, 0.13701235f, 0.13376995f,
+0.13052612f, 0.12728101f, 0.12403442f, 0.12078650f, 0.11753740f,
+0.11428693f, 0.11103523f, 0.10778234f, 0.10452842f, 0.10127326f,
+0.098017137f, 0.094759842f, 0.091501652f, 0.088242363f, 0.084982129f,
+0.081721103f, 0.078459084f, 0.075196224f, 0.071932560f, 0.068668243f,
+0.065403073f, 0.062137201f, 0.058870665f, 0.055603617f, 0.052335974f,
+0.049067651f, 0.045798921f, 0.042529582f, 0.039259788f, 0.035989573f,
+0.032719092f, 0.029448142f, 0.026176876f, 0.022905329f, 0.019633657f,
+0.016361655f, 0.013089478f, 0.0098171604f, 0.0065449764f, 0.0032724839f,
+-4.3711390e-08f, };
+#endif
+
+static const CELTMode mode48000_960_120 = {
+48000, /* Fs */
+120, /* overlap */
+21, /* nbEBands */
+21, /* effEBands */
+{0.85000610f, 0.0000000f, 1.0000000f, 1.0000000f, }, /* preemph */
+eband5ms, /* eBands */
+3, /* maxLM */
+8, /* nbShortMdcts */
+120, /* shortMdctSize */
+11, /* nbAllocVectors */
+band_allocation, /* allocVectors */
+logN400, /* logN */
+window120, /* window */
+{1920, 3, {&fft_state48000_960_0, &fft_state48000_960_1, &fft_state48000_960_2, &fft_state48000_960_3, }, mdct_twiddles960}, /* mdct */
+{392, cache_index50, cache_bits50, cache_caps50}, /* cache */
+};
+
+/* List of all the available modes */
+#define TOTAL_MODES 1
+static const CELTMode * const static_mode_list[TOTAL_MODES] = {
+&mode48000_960_120,
+};
diff --git a/drivers/opus/celt/tests/test_unit_cwrs32.c b/drivers/opus/celt/tests/test_unit_cwrs32.c
new file mode 100644
index 0000000000..db43e3392b
--- /dev/null
+++ b/drivers/opus/celt/tests/test_unit_cwrs32.c
@@ -0,0 +1,161 @@
+/* Copyright (c) 2008-2011 Xiph.Org Foundation, Mozilla Corporation,
+ Gregory Maxwell
+ Written by Jean-Marc Valin, Gregory Maxwell, and Timothy B. Terriberry */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#ifndef CUSTOM_MODES
+#define CUSTOM_MODES
+#else
+#define TEST_CUSTOM_MODES
+#endif
+
+#define CELT_C
+#include "opus/celt/stack_alloc.h"
+#include "opus/celt/entenc.c"
+#include "opus/celt/entdec.c"
+#include "opus/celt/entcode.c"
+#include "opus/celt/cwrs.c"
+#include "opus/celt/mathops.c"
+#include "opus/celt/rate.h"
+
+#define NMAX (240)
+#define KMAX (128)
+
+#ifdef TEST_CUSTOM_MODES
+
+#define NDIMS (44)
+static const int pn[NDIMS]={
+ 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 11, 12, 13, 14, 15, 16, 18, 20, 22,
+ 24, 26, 28, 30, 32, 36, 40, 44, 48,
+ 52, 56, 60, 64, 72, 80, 88, 96, 104,
+ 112, 120, 128, 144, 160, 176, 192, 208
+};
+static const int pkmax[NDIMS]={
+ 128, 128, 128, 128, 88, 52, 36, 26, 22,
+ 18, 16, 15, 13, 12, 12, 11, 10, 9,
+ 9, 8, 8, 7, 7, 7, 7, 6, 6,
+ 6, 6, 6, 5, 5, 5, 5, 5, 5,
+ 4, 4, 4, 4, 4, 4, 4, 4
+};
+
+#else /* TEST_CUSTOM_MODES */
+
+#define NDIMS (22)
+static const int pn[NDIMS]={
+ 2, 3, 4, 6, 8, 9, 11, 12, 16,
+ 18, 22, 24, 32, 36, 44, 48, 64, 72,
+ 88, 96, 144, 176
+};
+static const int pkmax[NDIMS]={
+ 128, 128, 128, 88, 36, 26, 18, 16, 12,
+ 11, 9, 9, 7, 7, 6, 6, 5, 5,
+ 5, 5, 4, 4
+};
+
+#endif
+
+int main(void){
+ int t;
+ int n;
+ ALLOC_STACK;
+ for(t=0;t<NDIMS;t++){
+ int pseudo;
+ n=pn[t];
+ for(pseudo=1;pseudo<41;pseudo++)
+ {
+ int k;
+#if defined(SMALL_FOOTPRINT)
+ opus_uint32 uu[KMAX+2U];
+#endif
+ opus_uint32 inc;
+ opus_uint32 nc;
+ opus_uint32 i;
+ k=get_pulses(pseudo);
+ if (k>pkmax[t])break;
+ printf("Testing CWRS with N=%i, K=%i...\n",n,k);
+#if defined(SMALL_FOOTPRINT)
+ nc=ncwrs_urow(n,k,uu);
+#else
+ nc=CELT_PVQ_V(n,k);
+#endif
+ inc=nc/20000;
+ if(inc<1)inc=1;
+ for(i=0;i<nc;i+=inc){
+#if defined(SMALL_FOOTPRINT)
+ opus_uint32 u[KMAX+2U];
+#endif
+ int y[NMAX];
+ int sy;
+ opus_uint32 v;
+ opus_uint32 ii;
+ int j;
+#if defined(SMALL_FOOTPRINT)
+ memcpy(u,uu,(k+2U)*sizeof(*u));
+ cwrsi(n,k,i,y,u);
+#else
+ cwrsi(n,k,i,y);
+#endif
+ sy=0;
+ for(j=0;j<n;j++)sy+=ABS(y[j]);
+ if(sy!=k){
+ fprintf(stderr,"N=%d Pulse count mismatch in cwrsi (%d!=%d).\n",
+ n,sy,k);
+ return 99;
+ }
+ /*printf("%6u of %u:",i,nc);
+ for(j=0;j<n;j++)printf(" %+3i",y[j]);
+ printf(" ->");*/
+#if defined(SMALL_FOOTPRINT)
+ ii=icwrs(n,k,&v,y,u);
+#else
+ ii=icwrs(n,y);
+ v=CELT_PVQ_V(n,k);
+#endif
+ if(ii!=i){
+ fprintf(stderr,"Combination-index mismatch (%lu!=%lu).\n",
+ (long)ii,(long)i);
+ return 1;
+ }
+ if(v!=nc){
+ fprintf(stderr,"Combination count mismatch (%lu!=%lu).\n",
+ (long)v,(long)nc);
+ return 2;
+ }
+ /*printf(" %6u\n",i);*/
+ }
+ /*printf("\n");*/
+ }
+ }
+ return 0;
+}
diff --git a/drivers/opus/celt/tests/test_unit_dft.c b/drivers/opus/celt/tests/test_unit_dft.c
new file mode 100644
index 0000000000..9c0db3e9ac
--- /dev/null
+++ b/drivers/opus/celt/tests/test_unit_dft.c
@@ -0,0 +1,164 @@
+/* Copyright (c) 2008 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#define SKIP_CONFIG_H
+
+#ifndef CUSTOM_MODES
+#define CUSTOM_MODES
+#endif
+
+#include <stdio.h>
+
+#define CELT_C
+#include "opus/celt/stack_alloc.h"
+#include "opus/celt/kiss_fft.h"
+#include "opus/celt/kiss_fft.c"
+#include "opus/celt/mathops.c"
+#include "opus/celt/entcode.c"
+
+
+#ifndef M_PI
+#define M_PI 3.141592653
+#endif
+
+int ret = 0;
+
+void check(kiss_fft_cpx * in,kiss_fft_cpx * out,int nfft,int isinverse)
+{
+ int bin,k;
+ double errpow=0,sigpow=0, snr;
+
+ for (bin=0;bin<nfft;++bin) {
+ double ansr = 0;
+ double ansi = 0;
+ double difr;
+ double difi;
+
+ for (k=0;k<nfft;++k) {
+ double phase = -2*M_PI*bin*k/nfft;
+ double re = cos(phase);
+ double im = sin(phase);
+ if (isinverse)
+ im = -im;
+
+ if (!isinverse)
+ {
+ re /= nfft;
+ im /= nfft;
+ }
+
+ ansr += in[k].r * re - in[k].i * im;
+ ansi += in[k].r * im + in[k].i * re;
+ }
+ /*printf ("%d %d ", (int)ansr, (int)ansi);*/
+ difr = ansr - out[bin].r;
+ difi = ansi - out[bin].i;
+ errpow += difr*difr + difi*difi;
+ sigpow += ansr*ansr+ansi*ansi;
+ }
+ snr = 10*log10(sigpow/errpow);
+ printf("nfft=%d inverse=%d,snr = %f\n",nfft,isinverse,snr );
+ if (snr<60) {
+ printf( "** poor snr: %f ** \n", snr);
+ ret = 1;
+ }
+}
+
+void test1d(int nfft,int isinverse)
+{
+ size_t buflen = sizeof(kiss_fft_cpx)*nfft;
+
+ kiss_fft_cpx * in = (kiss_fft_cpx*)malloc(buflen);
+ kiss_fft_cpx * out= (kiss_fft_cpx*)malloc(buflen);
+ kiss_fft_state *cfg = opus_fft_alloc(nfft,0,0);
+ int k;
+
+ for (k=0;k<nfft;++k) {
+ in[k].r = (rand() % 32767) - 16384;
+ in[k].i = (rand() % 32767) - 16384;
+ }
+
+ for (k=0;k<nfft;++k) {
+ in[k].r *= 32768;
+ in[k].i *= 32768;
+ }
+
+ if (isinverse)
+ {
+ for (k=0;k<nfft;++k) {
+ in[k].r /= nfft;
+ in[k].i /= nfft;
+ }
+ }
+
+ /*for (k=0;k<nfft;++k) printf("%d %d ", in[k].r, in[k].i);printf("\n");*/
+
+ if (isinverse)
+ opus_ifft(cfg,in,out);
+ else
+ opus_fft(cfg,in,out);
+
+ /*for (k=0;k<nfft;++k) printf("%d %d ", out[k].r, out[k].i);printf("\n");*/
+
+ check(in,out,nfft,isinverse);
+
+ free(in);
+ free(out);
+ free(cfg);
+}
+
+int main(int argc,char ** argv)
+{
+ ALLOC_STACK;
+ if (argc>1) {
+ int k;
+ for (k=1;k<argc;++k) {
+ test1d(atoi(argv[k]),0);
+ test1d(atoi(argv[k]),1);
+ }
+ }else{
+ test1d(32,0);
+ test1d(32,1);
+ test1d(128,0);
+ test1d(128,1);
+ test1d(256,0);
+ test1d(256,1);
+#ifndef RADIX_TWO_ONLY
+ test1d(36,0);
+ test1d(36,1);
+ test1d(50,0);
+ test1d(50,1);
+ test1d(120,0);
+ test1d(120,1);
+#endif
+ }
+ return ret;
+}
diff --git a/drivers/opus/celt/tests/test_unit_entropy.c b/drivers/opus/celt/tests/test_unit_entropy.c
new file mode 100644
index 0000000000..8c2defa8b3
--- /dev/null
+++ b/drivers/opus/celt/tests/test_unit_entropy.c
@@ -0,0 +1,382 @@
+/* Copyright (c) 2007-2011 Xiph.Org Foundation, Mozilla Corporation,
+ Gregory Maxwell
+ Written by Jean-Marc Valin, Gregory Maxwell, and Timothy B. Terriberry */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <time.h>
+#include "opus/celt/entcode.h"
+#include "opus/celt/entenc.h"
+#include "opus/celt/entdec.h"
+#include <string.h>
+
+#include "opus/celt/entenc.c"
+#include "opus/celt/entdec.c"
+#include "opus/celt/entcode.c"
+
+#ifndef M_LOG2E
+# define M_LOG2E 1.4426950408889634074
+#endif
+#define DATA_SIZE 10000000
+#define DATA_SIZE2 10000
+
+int main(int _argc,char **_argv){
+ ec_enc enc;
+ ec_dec dec;
+ long nbits;
+ long nbits2;
+ double entropy;
+ int ft;
+ int ftb;
+ int sz;
+ int i;
+ int ret;
+ unsigned int sym;
+ unsigned int seed;
+ unsigned char *ptr;
+ const char *env_seed;
+ ret=0;
+ entropy=0;
+ if (_argc > 2) {
+ fprintf(stderr, "Usage: %s [<seed>]\n", _argv[0]);
+ return 1;
+ }
+ env_seed = getenv("SEED");
+ if (_argc > 1)
+ seed = atoi(_argv[1]);
+ else if (env_seed)
+ seed = atoi(env_seed);
+ else
+ seed = time(NULL);
+ /*Testing encoding of raw bit values.*/
+ ptr = (unsigned char *)malloc(DATA_SIZE);
+ ec_enc_init(&enc,ptr, DATA_SIZE);
+ for(ft=2;ft<1024;ft++){
+ for(i=0;i<ft;i++){
+ entropy+=log(ft)*M_LOG2E;
+ ec_enc_uint(&enc,i,ft);
+ }
+ }
+ /*Testing encoding of raw bit values.*/
+ for(ftb=1;ftb<16;ftb++){
+ for(i=0;i<(1<<ftb);i++){
+ entropy+=ftb;
+ nbits=ec_tell(&enc);
+ ec_enc_bits(&enc,i,ftb);
+ nbits2=ec_tell(&enc);
+ if(nbits2-nbits!=ftb){
+ fprintf(stderr,"Used %li bits to encode %i bits directly.\n",
+ nbits2-nbits,ftb);
+ ret=-1;
+ }
+ }
+ }
+ nbits=ec_tell_frac(&enc);
+ ec_enc_done(&enc);
+ fprintf(stderr,
+ "Encoded %0.2lf bits of entropy to %0.2lf bits (%0.3lf%% wasted).\n",
+ entropy,ldexp(nbits,-3),100*(nbits-ldexp(entropy,3))/nbits);
+ fprintf(stderr,"Packed to %li bytes.\n",(long)ec_range_bytes(&enc));
+ ec_dec_init(&dec,ptr,DATA_SIZE);
+ for(ft=2;ft<1024;ft++){
+ for(i=0;i<ft;i++){
+ sym=ec_dec_uint(&dec,ft);
+ if(sym!=(unsigned)i){
+ fprintf(stderr,"Decoded %i instead of %i with ft of %i.\n",sym,i,ft);
+ ret=-1;
+ }
+ }
+ }
+ for(ftb=1;ftb<16;ftb++){
+ for(i=0;i<(1<<ftb);i++){
+ sym=ec_dec_bits(&dec,ftb);
+ if(sym!=(unsigned)i){
+ fprintf(stderr,"Decoded %i instead of %i with ftb of %i.\n",sym,i,ftb);
+ ret=-1;
+ }
+ }
+ }
+ nbits2=ec_tell_frac(&dec);
+ if(nbits!=nbits2){
+ fprintf(stderr,
+ "Reported number of bits used was %0.2lf, should be %0.2lf.\n",
+ ldexp(nbits2,-3),ldexp(nbits,-3));
+ ret=-1;
+ }
+ /*Testing an encoder bust prefers range coder data over raw bits.
+ This isn't a general guarantee, will only work for data that is buffered in
+ the encoder state and not yet stored in the user buffer, and should never
+ get used in practice.
+ It's mostly here for code coverage completeness.*/
+ /*Start with a 16-bit buffer.*/
+ ec_enc_init(&enc,ptr,2);
+ /*Write 7 raw bits.*/
+ ec_enc_bits(&enc,0x55,7);
+ /*Write 12.3 bits of range coder data.*/
+ ec_enc_uint(&enc,1,2);
+ ec_enc_uint(&enc,1,3);
+ ec_enc_uint(&enc,1,4);
+ ec_enc_uint(&enc,1,5);
+ ec_enc_uint(&enc,2,6);
+ ec_enc_uint(&enc,6,7);
+ ec_enc_done(&enc);
+ ec_dec_init(&dec,ptr,2);
+ if(!enc.error
+ /*The raw bits should have been overwritten by the range coder data.*/
+ ||ec_dec_bits(&dec,7)!=0x05
+ /*And all the range coder data should have been encoded correctly.*/
+ ||ec_dec_uint(&dec,2)!=1
+ ||ec_dec_uint(&dec,3)!=1
+ ||ec_dec_uint(&dec,4)!=1
+ ||ec_dec_uint(&dec,5)!=1
+ ||ec_dec_uint(&dec,6)!=2
+ ||ec_dec_uint(&dec,7)!=6){
+ fprintf(stderr,"Encoder bust overwrote range coder data with raw bits.\n");
+ ret=-1;
+ }
+ srand(seed);
+ fprintf(stderr,"Testing random streams... Random seed: %u (%.4X)\n", seed, rand() % 65536);
+ for(i=0;i<409600;i++){
+ unsigned *data;
+ unsigned *tell;
+ unsigned tell_bits;
+ int j;
+ int zeros;
+ ft=rand()/((RAND_MAX>>(rand()%11U))+1U)+10;
+ sz=rand()/((RAND_MAX>>(rand()%9U))+1U);
+ data=(unsigned *)malloc(sz*sizeof(*data));
+ tell=(unsigned *)malloc((sz+1)*sizeof(*tell));
+ ec_enc_init(&enc,ptr,DATA_SIZE2);
+ zeros = rand()%13==0;
+ tell[0]=ec_tell_frac(&enc);
+ for(j=0;j<sz;j++){
+ if (zeros)
+ data[j]=0;
+ else
+ data[j]=rand()%ft;
+ ec_enc_uint(&enc,data[j],ft);
+ tell[j+1]=ec_tell_frac(&enc);
+ }
+ if (rand()%2==0)
+ while(ec_tell(&enc)%8 != 0)
+ ec_enc_uint(&enc, rand()%2, 2);
+ tell_bits = ec_tell(&enc);
+ ec_enc_done(&enc);
+ if(tell_bits!=(unsigned)ec_tell(&enc)){
+ fprintf(stderr,"ec_tell() changed after ec_enc_done(): %i instead of %i (Random seed: %u)\n",
+ ec_tell(&enc),tell_bits,seed);
+ ret=-1;
+ }
+ if ((tell_bits+7)/8 < ec_range_bytes(&enc))
+ {
+ fprintf (stderr, "ec_tell() lied, there's %i bytes instead of %d (Random seed: %u)\n",
+ ec_range_bytes(&enc), (tell_bits+7)/8,seed);
+ ret=-1;
+ }
+ ec_dec_init(&dec,ptr,DATA_SIZE2);
+ if(ec_tell_frac(&dec)!=tell[0]){
+ fprintf(stderr,
+ "Tell mismatch between encoder and decoder at symbol %i: %i instead of %i (Random seed: %u).\n",
+ 0,ec_tell_frac(&dec),tell[0],seed);
+ }
+ for(j=0;j<sz;j++){
+ sym=ec_dec_uint(&dec,ft);
+ if(sym!=data[j]){
+ fprintf(stderr,
+ "Decoded %i instead of %i with ft of %i at position %i of %i (Random seed: %u).\n",
+ sym,data[j],ft,j,sz,seed);
+ ret=-1;
+ }
+ if(ec_tell_frac(&dec)!=tell[j+1]){
+ fprintf(stderr,
+ "Tell mismatch between encoder and decoder at symbol %i: %i instead of %i (Random seed: %u).\n",
+ j+1,ec_tell_frac(&dec),tell[j+1],seed);
+ }
+ }
+ free(tell);
+ free(data);
+ }
+ /*Test compatibility between multiple different encode/decode routines.*/
+ for(i=0;i<409600;i++){
+ unsigned *logp1;
+ unsigned *data;
+ unsigned *tell;
+ unsigned *enc_method;
+ int j;
+ sz=rand()/((RAND_MAX>>(rand()%9U))+1U);
+ logp1=(unsigned *)malloc(sz*sizeof(*logp1));
+ data=(unsigned *)malloc(sz*sizeof(*data));
+ tell=(unsigned *)malloc((sz+1)*sizeof(*tell));
+ enc_method=(unsigned *)malloc(sz*sizeof(*enc_method));
+ ec_enc_init(&enc,ptr,DATA_SIZE2);
+ tell[0]=ec_tell_frac(&enc);
+ for(j=0;j<sz;j++){
+ data[j]=rand()/((RAND_MAX>>1)+1);
+ logp1[j]=(rand()%15)+1;
+ enc_method[j]=rand()/((RAND_MAX>>2)+1);
+ switch(enc_method[j]){
+ case 0:{
+ ec_encode(&enc,data[j]?(1<<logp1[j])-1:0,
+ (1<<logp1[j])-(data[j]?0:1),1<<logp1[j]);
+ }break;
+ case 1:{
+ ec_encode_bin(&enc,data[j]?(1<<logp1[j])-1:0,
+ (1<<logp1[j])-(data[j]?0:1),logp1[j]);
+ }break;
+ case 2:{
+ ec_enc_bit_logp(&enc,data[j],logp1[j]);
+ }break;
+ case 3:{
+ unsigned char icdf[2];
+ icdf[0]=1;
+ icdf[1]=0;
+ ec_enc_icdf(&enc,data[j],icdf,logp1[j]);
+ }break;
+ }
+ tell[j+1]=ec_tell_frac(&enc);
+ }
+ ec_enc_done(&enc);
+ if((ec_tell(&enc)+7U)/8U<ec_range_bytes(&enc)){
+ fprintf(stderr,"tell() lied, there's %i bytes instead of %d (Random seed: %u)\n",
+ ec_range_bytes(&enc),(ec_tell(&enc)+7)/8,seed);
+ ret=-1;
+ }
+ ec_dec_init(&dec,ptr,DATA_SIZE2);
+ if(ec_tell_frac(&dec)!=tell[0]){
+ fprintf(stderr,
+ "Tell mismatch between encoder and decoder at symbol %i: %i instead of %i (Random seed: %u).\n",
+ 0,ec_tell_frac(&dec),tell[0],seed);
+ }
+ for(j=0;j<sz;j++){
+ int fs;
+ int dec_method;
+ dec_method=rand()/((RAND_MAX>>2)+1);
+ switch(dec_method){
+ case 0:{
+ fs=ec_decode(&dec,1<<logp1[j]);
+ sym=fs>=(1<<logp1[j])-1;
+ ec_dec_update(&dec,sym?(1<<logp1[j])-1:0,
+ (1<<logp1[j])-(sym?0:1),1<<logp1[j]);
+ }break;
+ case 1:{
+ fs=ec_decode_bin(&dec,logp1[j]);
+ sym=fs>=(1<<logp1[j])-1;
+ ec_dec_update(&dec,sym?(1<<logp1[j])-1:0,
+ (1<<logp1[j])-(sym?0:1),1<<logp1[j]);
+ }break;
+ case 2:{
+ sym=ec_dec_bit_logp(&dec,logp1[j]);
+ }break;
+ case 3:{
+ unsigned char icdf[2];
+ icdf[0]=1;
+ icdf[1]=0;
+ sym=ec_dec_icdf(&dec,icdf,logp1[j]);
+ }break;
+ }
+ if(sym!=data[j]){
+ fprintf(stderr,
+ "Decoded %i instead of %i with logp1 of %i at position %i of %i (Random seed: %u).\n",
+ sym,data[j],logp1[j],j,sz,seed);
+ fprintf(stderr,"Encoding method: %i, decoding method: %i\n",
+ enc_method[j],dec_method);
+ ret=-1;
+ }
+ if(ec_tell_frac(&dec)!=tell[j+1]){
+ fprintf(stderr,
+ "Tell mismatch between encoder and decoder at symbol %i: %i instead of %i (Random seed: %u).\n",
+ j+1,ec_tell_frac(&dec),tell[j+1],seed);
+ }
+ }
+ free(enc_method);
+ free(tell);
+ free(data);
+ free(logp1);
+ }
+ ec_enc_init(&enc,ptr,DATA_SIZE2);
+ ec_enc_bit_logp(&enc,0,1);
+ ec_enc_bit_logp(&enc,0,1);
+ ec_enc_bit_logp(&enc,0,1);
+ ec_enc_bit_logp(&enc,0,1);
+ ec_enc_bit_logp(&enc,0,2);
+ ec_enc_patch_initial_bits(&enc,3,2);
+ if(enc.error){
+ fprintf(stderr,"patch_initial_bits failed");
+ ret=-1;
+ }
+ ec_enc_patch_initial_bits(&enc,0,5);
+ if(!enc.error){
+ fprintf(stderr,"patch_initial_bits didn't fail when it should have");
+ ret=-1;
+ }
+ ec_enc_done(&enc);
+ if(ec_range_bytes(&enc)!=1||ptr[0]!=192){
+ fprintf(stderr,"Got %d when expecting 192 for patch_initial_bits",ptr[0]);
+ ret=-1;
+ }
+ ec_enc_init(&enc,ptr,DATA_SIZE2);
+ ec_enc_bit_logp(&enc,0,1);
+ ec_enc_bit_logp(&enc,0,1);
+ ec_enc_bit_logp(&enc,1,6);
+ ec_enc_bit_logp(&enc,0,2);
+ ec_enc_patch_initial_bits(&enc,0,2);
+ if(enc.error){
+ fprintf(stderr,"patch_initial_bits failed");
+ ret=-1;
+ }
+ ec_enc_done(&enc);
+ if(ec_range_bytes(&enc)!=2||ptr[0]!=63){
+ fprintf(stderr,"Got %d when expecting 63 for patch_initial_bits",ptr[0]);
+ ret=-1;
+ }
+ ec_enc_init(&enc,ptr,2);
+ ec_enc_bit_logp(&enc,0,2);
+ for(i=0;i<48;i++){
+ ec_enc_bits(&enc,0,1);
+ }
+ ec_enc_done(&enc);
+ if(!enc.error){
+ fprintf(stderr,"Raw bits overfill didn't fail when it should have");
+ ret=-1;
+ }
+ ec_enc_init(&enc,ptr,2);
+ for(i=0;i<17;i++){
+ ec_enc_bits(&enc,0,1);
+ }
+ ec_enc_done(&enc);
+ if(!enc.error){
+ fprintf(stderr,"17 raw bits encoded in two bytes");
+ ret=-1;
+ }
+ free(ptr);
+ return ret;
+}
diff --git a/drivers/opus/celt/tests/test_unit_laplace.c b/drivers/opus/celt/tests/test_unit_laplace.c
new file mode 100644
index 0000000000..e4fe83c4d6
--- /dev/null
+++ b/drivers/opus/celt/tests/test_unit_laplace.c
@@ -0,0 +1,92 @@
+/* Copyright (c) 2008-2011 Xiph.Org Foundation, Mozilla Corporation
+ Written by Jean-Marc Valin and Timothy B. Terriberry */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "opus/celt/laplace.h"
+#define CELT_C
+#include "opus/celt/stack_alloc.h"
+
+#include "opus/celt/entenc.c"
+#include "opus/celt/entdec.c"
+#include "opus/celt/entcode.c"
+#include "opus/celt/laplace.c"
+
+#define DATA_SIZE 40000
+
+int ec_laplace_get_start_freq(int decay)
+{
+ opus_uint32 ft = 32768 - LAPLACE_MINP*(2*LAPLACE_NMIN+1);
+ int fs = (ft*(16384-decay))/(16384+decay);
+ return fs+LAPLACE_MINP;
+}
+
+int main(void)
+{
+ int i;
+ int ret = 0;
+ ec_enc enc;
+ ec_dec dec;
+ unsigned char *ptr;
+ int val[10000], decay[10000];
+ ALLOC_STACK;
+ ptr = (unsigned char *)malloc(DATA_SIZE);
+ ec_enc_init(&enc,ptr,DATA_SIZE);
+
+ val[0] = 3; decay[0] = 6000;
+ val[1] = 0; decay[1] = 5800;
+ val[2] = -1; decay[2] = 5600;
+ for (i=3;i<10000;i++)
+ {
+ val[i] = rand()%15-7;
+ decay[i] = rand()%11000+5000;
+ }
+ for (i=0;i<10000;i++)
+ ec_laplace_encode(&enc, &val[i],
+ ec_laplace_get_start_freq(decay[i]), decay[i]);
+
+ ec_enc_done(&enc);
+
+ ec_dec_init(&dec,ec_get_buffer(&enc),ec_range_bytes(&enc));
+
+ for (i=0;i<10000;i++)
+ {
+ int d = ec_laplace_decode(&dec,
+ ec_laplace_get_start_freq(decay[i]), decay[i]);
+ if (d != val[i])
+ {
+ fprintf (stderr, "Got %d instead of %d\n", d, val[i]);
+ ret = 1;
+ }
+ }
+
+ return ret;
+}
diff --git a/drivers/opus/celt/tests/test_unit_mathops.c b/drivers/opus/celt/tests/test_unit_mathops.c
new file mode 100644
index 0000000000..0e3f300d40
--- /dev/null
+++ b/drivers/opus/celt/tests/test_unit_mathops.c
@@ -0,0 +1,275 @@
+/* Copyright (c) 2008-2011 Xiph.Org Foundation, Mozilla Corporation,
+ Gregory Maxwell
+ Written by Jean-Marc Valin, Gregory Maxwell, and Timothy B. Terriberry */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#ifndef CUSTOM_MODES
+#define CUSTOM_MODES
+#endif
+
+#define CELT_C
+
+#include "opus/celt/mathops.c"
+#include "opus/celt/entenc.c"
+#include "opus/celt/entdec.c"
+#include "opus/celt/entcode.c"
+#include "opus/celt/bands.c"
+#include "opus/celt/quant_bands.c"
+#include "opus/celt/laplace.c"
+#include "opus/celt/vq.c"
+#include "opus/celt/cwrs.c"
+#include <stdio.h>
+#include <math.h>
+
+#ifdef OPUS_FIXED_POINT
+#define WORD "%d"
+#else
+#define WORD "%f"
+#endif
+
+int ret = 0;
+
+void testdiv(void)
+{
+ opus_int32 i;
+ for (i=1;i<=327670;i++)
+ {
+ double prod;
+ opus_val32 val;
+ val = celt_rcp(i);
+#ifdef OPUS_FIXED_POINT
+ prod = (1./32768./65526.)*val*i;
+#else
+ prod = val*i;
+#endif
+ if (fabs(prod-1) > .00025)
+ {
+ fprintf (stderr, "div failed: 1/%d="WORD" (product = %f)\n", i, val, prod);
+ ret = 1;
+ }
+ }
+}
+
+void testsqrt(void)
+{
+ opus_int32 i;
+ for (i=1;i<=1000000000;i++)
+ {
+ double ratio;
+ opus_val16 val;
+ val = celt_sqrt(i);
+ ratio = val/sqrt(i);
+ if (fabs(ratio - 1) > .0005 && fabs(val-sqrt(i)) > 2)
+ {
+ fprintf (stderr, "sqrt failed: sqrt(%d)="WORD" (ratio = %f)\n", i, val, ratio);
+ ret = 1;
+ }
+ i+= i>>10;
+ }
+}
+
+void testbitexactcos(void)
+{
+ int i;
+ opus_int32 min_d,max_d,last,chk;
+ chk=max_d=0;
+ last=min_d=32767;
+ for(i=64;i<=16320;i++)
+ {
+ opus_int32 d;
+ opus_int32 q=bitexact_cos(i);
+ chk ^= q*i;
+ d = last - q;
+ if (d>max_d)max_d=d;
+ if (d<min_d)min_d=d;
+ last = q;
+ }
+ if ((chk!=89408644)||(max_d!=5)||(min_d!=0)||(bitexact_cos(64)!=32767)||
+ (bitexact_cos(16320)!=200)||(bitexact_cos(8192)!=23171))
+ {
+ fprintf (stderr, "bitexact_cos failed\n");
+ ret = 1;
+ }
+}
+
+void testbitexactlog2tan(void)
+{
+ int i,fail;
+ opus_int32 min_d,max_d,last,chk;
+ fail=chk=max_d=0;
+ last=min_d=15059;
+ for(i=64;i<8193;i++)
+ {
+ opus_int32 d;
+ opus_int32 mid=bitexact_cos(i);
+ opus_int32 side=bitexact_cos(16384-i);
+ opus_int32 q=bitexact_log2tan(mid,side);
+ chk ^= q*i;
+ d = last - q;
+ if (q!=-1*bitexact_log2tan(side,mid))
+ fail = 1;
+ if (d>max_d)max_d=d;
+ if (d<min_d)min_d=d;
+ last = q;
+ }
+ if ((chk!=15821257)||(max_d!=61)||(min_d!=-2)||fail||
+ (bitexact_log2tan(32767,200)!=15059)||(bitexact_log2tan(30274,12540)!=2611)||
+ (bitexact_log2tan(23171,23171)!=0))
+ {
+ fprintf (stderr, "bitexact_log2tan failed\n");
+ ret = 1;
+ }
+}
+
+#ifndef OPUS_FIXED_POINT
+void testlog2(void)
+{
+ float x;
+ for (x=0.001;x<1677700.0;x+=(x/8.0))
+ {
+ float error = fabs((1.442695040888963387*log(x))-celt_log2(x));
+ if (error>0.0009)
+ {
+ fprintf (stderr, "celt_log2 failed: fabs((1.442695040888963387*log(x))-celt_log2(x))>0.001 (x = %f, error = %f)\n", x,error);
+ ret = 1;
+ }
+ }
+}
+
+void testexp2(void)
+{
+ float x;
+ for (x=-11.0;x<24.0;x+=0.0007)
+ {
+ float error = fabs(x-(1.442695040888963387*log(celt_exp2(x))));
+ if (error>0.0002)
+ {
+ fprintf (stderr, "celt_exp2 failed: fabs(x-(1.442695040888963387*log(celt_exp2(x))))>0.0005 (x = %f, error = %f)\n", x,error);
+ ret = 1;
+ }
+ }
+}
+
+void testexp2log2(void)
+{
+ float x;
+ for (x=-11.0;x<24.0;x+=0.0007)
+ {
+ float error = fabs(x-(celt_log2(celt_exp2(x))));
+ if (error>0.001)
+ {
+ fprintf (stderr, "celt_log2/celt_exp2 failed: fabs(x-(celt_log2(celt_exp2(x))))>0.001 (x = %f, error = %f)\n", x,error);
+ ret = 1;
+ }
+ }
+}
+#else
+void testlog2(void)
+{
+ opus_val32 x;
+ for (x=8;x<1073741824;x+=(x>>3))
+ {
+ float error = fabs((1.442695040888963387*log(x/16384.0))-celt_log2(x)/1024.0);
+ if (error>0.003)
+ {
+ fprintf (stderr, "celt_log2 failed: x = %ld, error = %f\n", (long)x,error);
+ ret = 1;
+ }
+ }
+}
+
+void testexp2(void)
+{
+ opus_val16 x;
+ for (x=-32768;x<15360;x++)
+ {
+ float error1 = fabs(x/1024.0-(1.442695040888963387*log(celt_exp2(x)/65536.0)));
+ float error2 = fabs(exp(0.6931471805599453094*x/1024.0)-celt_exp2(x)/65536.0);
+ if (error1>0.0002&&error2>0.00004)
+ {
+ fprintf (stderr, "celt_exp2 failed: x = "WORD", error1 = %f, error2 = %f\n", x,error1,error2);
+ ret = 1;
+ }
+ }
+}
+
+void testexp2log2(void)
+{
+ opus_val32 x;
+ for (x=8;x<65536;x+=(x>>3))
+ {
+ float error = fabs(x-0.25*celt_exp2(celt_log2(x)))/16384;
+ if (error>0.004)
+ {
+ fprintf (stderr, "celt_log2/celt_exp2 failed: fabs(x-(celt_exp2(celt_log2(x))))>0.001 (x = %ld, error = %f)\n", (long)x,error);
+ ret = 1;
+ }
+ }
+}
+
+void testilog2(void)
+{
+ opus_val32 x;
+ for (x=1;x<=268435455;x+=127)
+ {
+ opus_val32 lg;
+ opus_val32 y;
+
+ lg = celt_ilog2(x);
+ if (lg<0 || lg>=31)
+ {
+ printf("celt_ilog2 failed: 0<=celt_ilog2(x)<31 (x = %d, celt_ilog2(x) = %d)\n",x,lg);
+ ret = 1;
+ }
+ y = 1<<lg;
+
+ if (x<y || (x>>1)>=y)
+ {
+ printf("celt_ilog2 failed: 2**celt_ilog2(x)<=x<2**(celt_ilog2(x)+1) (x = %d, 2**celt_ilog2(x) = %d)\n",x,y);
+ ret = 1;
+ }
+ }
+}
+#endif
+
+int main(void)
+{
+ testbitexactcos();
+ testbitexactlog2tan();
+ testdiv();
+ testsqrt();
+ testlog2();
+ testexp2();
+ testexp2log2();
+#ifdef OPUS_FIXED_POINT
+ testilog2();
+#endif
+ return ret;
+}
diff --git a/drivers/opus/celt/tests/test_unit_mdct.c b/drivers/opus/celt/tests/test_unit_mdct.c
new file mode 100644
index 0000000000..0be03db2e8
--- /dev/null
+++ b/drivers/opus/celt/tests/test_unit_mdct.c
@@ -0,0 +1,210 @@
+/* Copyright (c) 2008-2011 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#define SKIP_CONFIG_H
+
+#ifndef CUSTOM_MODES
+#define CUSTOM_MODES
+#endif
+
+#include <stdio.h>
+
+#define CELT_C
+#include "opus/celt/mdct.h"
+#include "opus/celt/stack_alloc.h"
+
+#include "opus/celt/kiss_fft.c"
+#include "opus/celt/mdct.c"
+#include "opus/celt/mathops.c"
+#include "opus/celt/entcode.c"
+
+#ifndef M_PI
+#define M_PI 3.141592653
+#endif
+
+int ret = 0;
+void check(kiss_fft_scalar * in,kiss_fft_scalar * out,int nfft,int isinverse)
+{
+ int bin,k;
+ double errpow=0,sigpow=0;
+ double snr;
+ for (bin=0;bin<nfft/2;++bin) {
+ double ansr = 0;
+ double difr;
+
+ for (k=0;k<nfft;++k) {
+ double phase = 2*M_PI*(k+.5+.25*nfft)*(bin+.5)/nfft;
+ double re = cos(phase);
+
+ re /= nfft/4;
+
+ ansr += in[k] * re;
+ }
+ /*printf ("%f %f\n", ansr, out[bin]);*/
+ difr = ansr - out[bin];
+ errpow += difr*difr;
+ sigpow += ansr*ansr;
+ }
+ snr = 10*log10(sigpow/errpow);
+ printf("nfft=%d inverse=%d,snr = %f\n",nfft,isinverse,snr );
+ if (snr<60) {
+ printf( "** poor snr: %f **\n", snr);
+ ret = 1;
+ }
+}
+
+void check_inv(kiss_fft_scalar * in,kiss_fft_scalar * out,int nfft,int isinverse)
+{
+ int bin,k;
+ double errpow=0,sigpow=0;
+ double snr;
+ for (bin=0;bin<nfft;++bin) {
+ double ansr = 0;
+ double difr;
+
+ for (k=0;k<nfft/2;++k) {
+ double phase = 2*M_PI*(bin+.5+.25*nfft)*(k+.5)/nfft;
+ double re = cos(phase);
+
+ /*re *= 2;*/
+
+ ansr += in[k] * re;
+ }
+ /*printf ("%f %f\n", ansr, out[bin]);*/
+ difr = ansr - out[bin];
+ errpow += difr*difr;
+ sigpow += ansr*ansr;
+ }
+ snr = 10*log10(sigpow/errpow);
+ printf("nfft=%d inverse=%d,snr = %f\n",nfft,isinverse,snr );
+ if (snr<60) {
+ printf( "** poor snr: %f **\n", snr);
+ ret = 1;
+ }
+}
+
+
+void test1d(int nfft,int isinverse)
+{
+ celt_mdct_lookup cfg;
+ size_t buflen = sizeof(kiss_fft_scalar)*nfft;
+
+ kiss_fft_scalar * in = (kiss_fft_scalar*)malloc(buflen);
+ kiss_fft_scalar * in_copy = (kiss_fft_scalar*)malloc(buflen);
+ kiss_fft_scalar * out= (kiss_fft_scalar*)malloc(buflen);
+ opus_val16 * window= (opus_val16*)malloc(sizeof(opus_val16)*nfft/2);
+ int k;
+
+ clt_mdct_init(&cfg, nfft, 0);
+ for (k=0;k<nfft;++k) {
+ in[k] = (rand() % 32768) - 16384;
+ }
+
+ for (k=0;k<nfft/2;++k) {
+ window[k] = Q15ONE;
+ }
+ for (k=0;k<nfft;++k) {
+ in[k] *= 32768;
+ }
+
+ if (isinverse)
+ {
+ for (k=0;k<nfft;++k) {
+ in[k] /= nfft;
+ }
+ }
+
+ for (k=0;k<nfft;++k)
+ in_copy[k] = in[k];
+ /*for (k=0;k<nfft;++k) printf("%d %d ", in[k].r, in[k].i);printf("\n");*/
+
+ if (isinverse)
+ {
+ for (k=0;k<nfft;++k)
+ out[k] = 0;
+ clt_mdct_backward(&cfg,in,out, window, nfft/2, 0, 1);
+ /* apply TDAC because clt_mdct_backward() no longer does that */
+ for (k=0;k<nfft/4;++k)
+ out[nfft-k-1] = out[nfft/2+k];
+ check_inv(in,out,nfft,isinverse);
+ } else {
+ clt_mdct_forward(&cfg,in,out,window, nfft/2, 0, 1);
+ check(in_copy,out,nfft,isinverse);
+ }
+ /*for (k=0;k<nfft;++k) printf("%d %d ", out[k].r, out[k].i);printf("\n");*/
+
+
+ free(in);
+ free(out);
+ clt_mdct_clear(&cfg);
+}
+
+int main(int argc,char ** argv)
+{
+ ALLOC_STACK;
+ if (argc>1) {
+ int k;
+ for (k=1;k<argc;++k) {
+ test1d(atoi(argv[k]),0);
+ test1d(atoi(argv[k]),1);
+ }
+ }else{
+ test1d(32,0);
+ test1d(32,1);
+ test1d(256,0);
+ test1d(256,1);
+ test1d(512,0);
+ test1d(512,1);
+ test1d(1024,0);
+ test1d(1024,1);
+ test1d(2048,0);
+ test1d(2048,1);
+#ifndef RADIX_TWO_ONLY
+ test1d(36,0);
+ test1d(36,1);
+ test1d(40,0);
+ test1d(40,1);
+ test1d(60,0);
+ test1d(60,1);
+ test1d(120,0);
+ test1d(120,1);
+ test1d(240,0);
+ test1d(240,1);
+ test1d(480,0);
+ test1d(480,1);
+ test1d(960,0);
+ test1d(960,1);
+ test1d(1920,0);
+ test1d(1920,1);
+#endif
+ }
+ return ret;
+}
diff --git a/drivers/opus/celt/tests/test_unit_rotation.c b/drivers/opus/celt/tests/test_unit_rotation.c
new file mode 100644
index 0000000000..a57bf11e79
--- /dev/null
+++ b/drivers/opus/celt/tests/test_unit_rotation.c
@@ -0,0 +1,90 @@
+/* Copyright (c) 2008-2011 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#ifndef CUSTOM_MODES
+#define CUSTOM_MODES
+#endif
+
+#define CELT_C
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "opus/celt/vq.c"
+#include "opus/celt/cwrs.c"
+#include "opus/celt/entcode.c"
+#include "opus/celt/entenc.c"
+#include "opus/celt/entdec.c"
+#include "opus/celt/mathops.c"
+#include "opus/celt/bands.h"
+#include <math.h>
+#define MAX_SIZE 100
+
+int ret=0;
+void test_rotation(int N, int K)
+{
+ int i;
+ double err = 0, ener = 0, snr, snr0;
+ opus_val16 x0[MAX_SIZE];
+ opus_val16 x1[MAX_SIZE];
+ for (i=0;i<N;i++)
+ x1[i] = x0[i] = rand()%32767-16384;
+ exp_rotation(x1, N, 1, 1, K, SPREAD_NORMAL);
+ for (i=0;i<N;i++)
+ {
+ err += (x0[i]-(double)x1[i])*(x0[i]-(double)x1[i]);
+ ener += x0[i]*(double)x0[i];
+ }
+ snr0 = 20*log10(ener/err);
+ err = ener = 0;
+ exp_rotation(x1, N, -1, 1, K, SPREAD_NORMAL);
+ for (i=0;i<N;i++)
+ {
+ err += (x0[i]-(double)x1[i])*(x0[i]-(double)x1[i]);
+ ener += x0[i]*(double)x0[i];
+ }
+ snr = 20*log10(ener/err);
+ printf ("SNR for size %d (%d pulses) is %f (was %f without inverse)\n", N, K, snr, snr0);
+ if (snr < 60 || snr0 > 20)
+ {
+ fprintf(stderr, "FAIL!\n");
+ ret = 1;
+ }
+}
+
+int main(void)
+{
+ ALLOC_STACK;
+ test_rotation(15, 3);
+ test_rotation(23, 5);
+ test_rotation(50, 3);
+ test_rotation(80, 1);
+ return ret;
+}
diff --git a/drivers/opus/celt/tests/test_unit_types.c b/drivers/opus/celt/tests/test_unit_types.c
new file mode 100644
index 0000000000..12d5ca72f8
--- /dev/null
+++ b/drivers/opus/celt/tests/test_unit_types.c
@@ -0,0 +1,50 @@
+/* Copyright (c) 2008-2011 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/opus_types.h"
+#include <stdio.h>
+
+int main(void)
+{
+ opus_int16 i = 1;
+ i <<= 14;
+ if (i>>14 != 1)
+ {
+ fprintf(stderr, "opus_int16 isn't 16 bits\n");
+ return 1;
+ }
+ if (sizeof(opus_int16)*2 != sizeof(opus_int32))
+ {
+ fprintf(stderr, "16*2 != 32\n");
+ return 1;
+ }
+ return 0;
+}
diff --git a/drivers/opus/celt/vq.c b/drivers/opus/celt/vq.c
new file mode 100644
index 0000000000..29a98a3a63
--- /dev/null
+++ b/drivers/opus/celt/vq.c
@@ -0,0 +1,415 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/celt/mathops.h"
+#include "opus/celt/cwrs.h"
+#include "opus/celt/vq.h"
+#include "opus/celt/arch.h"
+#include "opus/celt/os_support.h"
+#include "opus/celt/bands.h"
+#include "opus/celt/rate.h"
+
+static void exp_rotation1(celt_norm *X, int len, int stride, opus_val16 c, opus_val16 s)
+{
+ int i;
+ celt_norm *Xptr;
+ Xptr = X;
+ for (i=0;i<len-stride;i++)
+ {
+ celt_norm x1, x2;
+ x1 = Xptr[0];
+ x2 = Xptr[stride];
+ Xptr[stride] = EXTRACT16(SHR32(MULT16_16(c,x2) + MULT16_16(s,x1), 15));
+ *Xptr++ = EXTRACT16(SHR32(MULT16_16(c,x1) - MULT16_16(s,x2), 15));
+ }
+ Xptr = &X[len-2*stride-1];
+ for (i=len-2*stride-1;i>=0;i--)
+ {
+ celt_norm x1, x2;
+ x1 = Xptr[0];
+ x2 = Xptr[stride];
+ Xptr[stride] = EXTRACT16(SHR32(MULT16_16(c,x2) + MULT16_16(s,x1), 15));
+ *Xptr-- = EXTRACT16(SHR32(MULT16_16(c,x1) - MULT16_16(s,x2), 15));
+ }
+}
+
+static void exp_rotation(celt_norm *X, int len, int dir, int stride, int K, int spread)
+{
+ static const int SPREAD_FACTOR[3]={15,10,5};
+ int i;
+ opus_val16 c, s;
+ opus_val16 gain, theta;
+ int stride2=0;
+ int factor;
+
+ if (2*K>=len || spread==SPREAD_NONE)
+ return;
+ factor = SPREAD_FACTOR[spread-1];
+
+ gain = celt_div((opus_val32)MULT16_16(Q15_ONE,len),(opus_val32)(len+factor*K));
+ theta = HALF16(MULT16_16_Q15(gain,gain));
+
+ c = celt_cos_norm(EXTEND32(theta));
+ s = celt_cos_norm(EXTEND32(SUB16(Q15ONE,theta))); /* sin(theta) */
+
+ if (len>=8*stride)
+ {
+ stride2 = 1;
+ /* This is just a simple (equivalent) way of computing sqrt(len/stride) with rounding.
+ It's basically incrementing long as (stride2+0.5)^2 < len/stride. */
+ while ((stride2*stride2+stride2)*stride + (stride>>2) < len)
+ stride2++;
+ }
+ /*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for
+ extract_collapse_mask().*/
+ len /= stride;
+ for (i=0;i<stride;i++)
+ {
+ if (dir < 0)
+ {
+ if (stride2)
+ exp_rotation1(X+i*len, len, stride2, s, c);
+ exp_rotation1(X+i*len, len, 1, c, s);
+ } else {
+ exp_rotation1(X+i*len, len, 1, c, -s);
+ if (stride2)
+ exp_rotation1(X+i*len, len, stride2, s, -c);
+ }
+ }
+}
+
+/** Takes the pitch vector and the decoded residual vector, computes the gain
+ that will give ||p+g*y||=1 and mixes the residual with the pitch. */
+static void normalise_residual(int * OPUS_RESTRICT iy, celt_norm * OPUS_RESTRICT X,
+ int N, opus_val32 Ryy, opus_val16 gain)
+{
+ int i;
+#ifdef OPUS_FIXED_POINT
+ int k;
+#endif
+ opus_val32 t;
+ opus_val16 g;
+
+#ifdef OPUS_FIXED_POINT
+ k = celt_ilog2(Ryy)>>1;
+#endif
+ t = VSHR32(Ryy, 2*(k-7));
+ g = MULT16_16_P15(celt_rsqrt_norm(t),gain);
+
+ i=0;
+ do
+ X[i] = EXTRACT16(PSHR32(MULT16_16(g, iy[i]), k+1));
+ while (++i < N);
+}
+
+static unsigned extract_collapse_mask(int *iy, int N, int B)
+{
+ unsigned collapse_mask;
+ int N0;
+ int i;
+ if (B<=1)
+ return 1;
+ /*NOTE: As a minor optimization, we could be passing around log2(B), not B, for both this and for
+ exp_rotation().*/
+ N0 = N/B;
+ collapse_mask = 0;
+ i=0; do {
+ int j;
+ j=0; do {
+ collapse_mask |= (iy[i*N0+j]!=0)<<i;
+ } while (++j<N0);
+ } while (++i<B);
+ return collapse_mask;
+}
+
+unsigned alg_quant(celt_norm *X, int N, int K, int spread, int B, ec_enc *enc
+#ifdef RESYNTH
+ , opus_val16 gain
+#endif
+ )
+{
+ VARDECL(celt_norm, y);
+ VARDECL(int, iy);
+ VARDECL(opus_val16, signx);
+ int i, j;
+ opus_val16 s;
+ int pulsesLeft;
+ opus_val32 sum;
+ opus_val32 xy;
+ opus_val16 yy;
+ unsigned collapse_mask;
+ SAVE_STACK;
+
+ celt_assert2(K>0, "alg_quant() needs at least one pulse");
+ celt_assert2(N>1, "alg_quant() needs at least two dimensions");
+
+ ALLOC(y, N, celt_norm);
+ ALLOC(iy, N, int);
+ ALLOC(signx, N, opus_val16);
+
+ exp_rotation(X, N, 1, B, K, spread);
+
+ /* Get rid of the sign */
+ sum = 0;
+ j=0; do {
+ if (X[j]>0)
+ signx[j]=1;
+ else {
+ signx[j]=-1;
+ X[j]=-X[j];
+ }
+ iy[j] = 0;
+ y[j] = 0;
+ } while (++j<N);
+
+ xy = yy = 0;
+
+ pulsesLeft = K;
+
+ /* Do a pre-search by projecting on the pyramid */
+ if (K > (N>>1))
+ {
+ opus_val16 rcp;
+ j=0; do {
+ sum += X[j];
+ } while (++j<N);
+
+ /* If X is too small, just replace it with a pulse at 0 */
+#ifdef OPUS_FIXED_POINT
+ if (sum <= K)
+#else
+ /* Prevents infinities and NaNs from causing too many pulses
+ to be allocated. 64 is an approximation of infinity here. */
+ if (!(sum > EPSILON && sum < 64))
+#endif
+ {
+ X[0] = QCONST16(1.f,14);
+ j=1; do
+ X[j]=0;
+ while (++j<N);
+ sum = QCONST16(1.f,14);
+ }
+ rcp = EXTRACT16(MULT16_32_Q16(K-1, celt_rcp(sum)));
+ j=0; do {
+#ifdef OPUS_FIXED_POINT
+ /* It's really important to round *towards zero* here */
+ iy[j] = MULT16_16_Q15(X[j],rcp);
+#else
+ iy[j] = (int)floor(rcp*X[j]);
+#endif
+ y[j] = (celt_norm)iy[j];
+ yy = MAC16_16(yy, y[j],y[j]);
+ xy = MAC16_16(xy, X[j],y[j]);
+ y[j] *= 2;
+ pulsesLeft -= iy[j];
+ } while (++j<N);
+ }
+ celt_assert2(pulsesLeft>=1, "Allocated too many pulses in the quick pass");
+
+ /* This should never happen, but just in case it does (e.g. on silence)
+ we fill the first bin with pulses. */
+#ifdef OPUS_FIXED_POINT_DEBUG
+ celt_assert2(pulsesLeft<=N+3, "Not enough pulses in the quick pass");
+#endif
+ if (pulsesLeft > N+3)
+ {
+ opus_val16 tmp = (opus_val16)pulsesLeft;
+ yy = MAC16_16(yy, tmp, tmp);
+ yy = MAC16_16(yy, tmp, y[0]);
+ iy[0] += pulsesLeft;
+ pulsesLeft=0;
+ }
+
+ s = 1;
+ for (i=0;i<pulsesLeft;i++)
+ {
+ int best_id;
+ opus_val32 best_num = -VERY_LARGE16;
+ opus_val16 best_den = 0;
+#ifdef OPUS_FIXED_POINT
+ int rshift;
+#endif
+#ifdef OPUS_FIXED_POINT
+ rshift = 1+celt_ilog2(K-pulsesLeft+i+1);
+#endif
+ best_id = 0;
+ /* The squared magnitude term gets added anyway, so we might as well
+ add it outside the loop */
+ yy = ADD32(yy, 1);
+ j=0;
+ do {
+ opus_val16 Rxy, Ryy;
+ /* Temporary sums of the new pulse(s) */
+ Rxy = EXTRACT16(SHR32(ADD32(xy, EXTEND32(X[j])),rshift));
+ /* We're multiplying y[j] by two so we don't have to do it here */
+ Ryy = ADD16(yy, y[j]);
+
+ /* Approximate score: we maximise Rxy/sqrt(Ryy) (we're guaranteed that
+ Rxy is positive because the sign is pre-computed) */
+ Rxy = MULT16_16_Q15(Rxy,Rxy);
+ /* The idea is to check for num/den >= best_num/best_den, but that way
+ we can do it without any division */
+ /* OPT: Make sure to use conditional moves here */
+ if (MULT16_16(best_den, Rxy) > MULT16_16(Ryy, best_num))
+ {
+ best_den = Ryy;
+ best_num = Rxy;
+ best_id = j;
+ }
+ } while (++j<N);
+
+ /* Updating the sums of the new pulse(s) */
+ xy = ADD32(xy, EXTEND32(X[best_id]));
+ /* We're multiplying y[j] by two so we don't have to do it here */
+ yy = ADD16(yy, y[best_id]);
+
+ /* Only now that we've made the final choice, update y/iy */
+ /* Multiplying y[j] by 2 so we don't have to do it everywhere else */
+ y[best_id] += 2*s;
+ iy[best_id]++;
+ }
+
+ /* Put the original sign back */
+ j=0;
+ do {
+ X[j] = MULT16_16(signx[j],X[j]);
+ if (signx[j] < 0)
+ iy[j] = -iy[j];
+ } while (++j<N);
+ encode_pulses(iy, N, K, enc);
+
+#ifdef RESYNTH
+ normalise_residual(iy, X, N, yy, gain);
+ exp_rotation(X, N, -1, B, K, spread);
+#endif
+
+ collapse_mask = extract_collapse_mask(iy, N, B);
+ RESTORE_STACK;
+ return collapse_mask;
+}
+
+/** Decode pulse vector and combine the result with the pitch vector to produce
+ the final normalised signal in the current band. */
+unsigned alg_unquant(celt_norm *X, int N, int K, int spread, int B,
+ ec_dec *dec, opus_val16 gain)
+{
+ int i;
+ opus_val32 Ryy;
+ unsigned collapse_mask;
+ VARDECL(int, iy);
+ SAVE_STACK;
+
+ celt_assert2(K>0, "alg_unquant() needs at least one pulse");
+ celt_assert2(N>1, "alg_unquant() needs at least two dimensions");
+ ALLOC(iy, N, int);
+ decode_pulses(iy, N, K, dec);
+ Ryy = 0;
+ i=0;
+ do {
+ Ryy = MAC16_16(Ryy, iy[i], iy[i]);
+ } while (++i < N);
+ normalise_residual(iy, X, N, Ryy, gain);
+ exp_rotation(X, N, -1, B, K, spread);
+ collapse_mask = extract_collapse_mask(iy, N, B);
+ RESTORE_STACK;
+ return collapse_mask;
+}
+
+void renormalise_vector(celt_norm *X, int N, opus_val16 gain)
+{
+ int i;
+#ifdef OPUS_FIXED_POINT
+ int k;
+#endif
+ opus_val32 E = EPSILON;
+ opus_val16 g;
+ opus_val32 t;
+ celt_norm *xptr = X;
+ for (i=0;i<N;i++)
+ {
+ E = MAC16_16(E, *xptr, *xptr);
+ xptr++;
+ }
+#ifdef OPUS_FIXED_POINT
+ k = celt_ilog2(E)>>1;
+#endif
+ t = VSHR32(E, 2*(k-7));
+ g = MULT16_16_P15(celt_rsqrt_norm(t),gain);
+
+ xptr = X;
+ for (i=0;i<N;i++)
+ {
+ *xptr = EXTRACT16(PSHR32(MULT16_16(g, *xptr), k+1));
+ xptr++;
+ }
+ /*return celt_sqrt(E);*/
+}
+
+int stereo_itheta(celt_norm *X, celt_norm *Y, int stereo, int N)
+{
+ int i;
+ int itheta;
+ opus_val16 mid, side;
+ opus_val32 Emid, Eside;
+
+ Emid = Eside = EPSILON;
+ if (stereo)
+ {
+ for (i=0;i<N;i++)
+ {
+ celt_norm m, s;
+ m = ADD16(SHR16(X[i],1),SHR16(Y[i],1));
+ s = SUB16(SHR16(X[i],1),SHR16(Y[i],1));
+ Emid = MAC16_16(Emid, m, m);
+ Eside = MAC16_16(Eside, s, s);
+ }
+ } else {
+ for (i=0;i<N;i++)
+ {
+ celt_norm m, s;
+ m = X[i];
+ s = Y[i];
+ Emid = MAC16_16(Emid, m, m);
+ Eside = MAC16_16(Eside, s, s);
+ }
+ }
+ mid = celt_sqrt(Emid);
+ side = celt_sqrt(Eside);
+#ifdef OPUS_FIXED_POINT
+ /* 0.63662 = 2/pi */
+ itheta = MULT16_16_Q15(QCONST16(0.63662f,15),celt_atan2p(side, mid));
+#else
+ itheta = (int)floor(.5f+16384*0.63662f*atan2(side,mid));
+#endif
+
+ return itheta;
+}
diff --git a/drivers/opus/celt/vq.h b/drivers/opus/celt/vq.h
new file mode 100644
index 0000000000..b52b1a0982
--- /dev/null
+++ b/drivers/opus/celt/vq.h
@@ -0,0 +1,70 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/**
+ @file vq.h
+ @brief Vector quantisation of the residual
+ */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VQ_H
+#define VQ_H
+
+#include "opus/celt/entenc.h"
+#include "opus/celt/entdec.h"
+#include "opus/celt/opus_modes.h"
+
+/** Algebraic pulse-vector quantiser. The signal x is replaced by the sum of
+ * the pitch and a combination of pulses such that its norm is still equal
+ * to 1. This is the function that will typically require the most CPU.
+ * @param X Residual signal to quantise/encode (returns quantised version)
+ * @param N Number of samples to encode
+ * @param K Number of pulses to use
+ * @param enc Entropy encoder state
+ * @ret A mask indicating which blocks in the band received pulses
+*/
+unsigned alg_quant(celt_norm *X, int N, int K, int spread, int B,
+ ec_enc *enc
+#ifdef RESYNTH
+ , opus_val16 gain
+#endif
+ );
+
+/** Algebraic pulse decoder
+ * @param X Decoded normalised spectrum (returned)
+ * @param N Number of samples to decode
+ * @param K Number of pulses to use
+ * @param dec Entropy decoder state
+ * @ret A mask indicating which blocks in the band received pulses
+ */
+unsigned alg_unquant(celt_norm *X, int N, int K, int spread, int B,
+ ec_dec *dec, opus_val16 gain);
+
+void renormalise_vector(celt_norm *X, int N, opus_val16 gain);
+
+int stereo_itheta(celt_norm *X, celt_norm *Y, int stereo, int N);
+
+#endif /* VQ_H */
diff --git a/drivers/opus/celt/x86/pitch_sse.h b/drivers/opus/celt/x86/pitch_sse.h
new file mode 100644
index 0000000000..1542b87232
--- /dev/null
+++ b/drivers/opus/celt/x86/pitch_sse.h
@@ -0,0 +1,156 @@
+/* Copyright (c) 2013 Jean-Marc Valin and John Ridges */
+/**
+ @file pitch_sse.h
+ @brief Pitch analysis
+ */
+
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef PITCH_SSE_H
+#define PITCH_SSE_H
+
+#include <xmmintrin.h>
+#include "opus/celt/arch.h"
+
+#define OVERRIDE_XCORR_KERNEL
+static OPUS_INLINE void xcorr_kernel(const opus_val16 *x, const opus_val16 *y, opus_val32 sum[4], int len)
+{
+ int j;
+ __m128 xsum1, xsum2;
+ xsum1 = _mm_loadu_ps(sum);
+ xsum2 = _mm_setzero_ps();
+
+ for (j = 0; j < len-3; j += 4)
+ {
+ __m128 x0 = _mm_loadu_ps(x+j);
+ __m128 yj = _mm_loadu_ps(y+j);
+ __m128 y3 = _mm_loadu_ps(y+j+3);
+
+ xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0x00),yj));
+ xsum2 = _mm_add_ps(xsum2,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0x55),
+ _mm_shuffle_ps(yj,y3,0x49)));
+ xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0xaa),
+ _mm_shuffle_ps(yj,y3,0x9e)));
+ xsum2 = _mm_add_ps(xsum2,_mm_mul_ps(_mm_shuffle_ps(x0,x0,0xff),y3));
+ }
+ if (j < len)
+ {
+ xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_load1_ps(x+j),_mm_loadu_ps(y+j)));
+ if (++j < len)
+ {
+ xsum2 = _mm_add_ps(xsum2,_mm_mul_ps(_mm_load1_ps(x+j),_mm_loadu_ps(y+j)));
+ if (++j < len)
+ {
+ xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(_mm_load1_ps(x+j),_mm_loadu_ps(y+j)));
+ }
+ }
+ }
+ _mm_storeu_ps(sum,_mm_add_ps(xsum1,xsum2));
+}
+
+#define OVERRIDE_DUAL_INNER_PROD
+static OPUS_INLINE void dual_inner_prod(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02,
+ int N, opus_val32 *xy1, opus_val32 *xy2)
+{
+ int i;
+ __m128 xsum1, xsum2;
+ xsum1 = _mm_setzero_ps();
+ xsum2 = _mm_setzero_ps();
+ for (i=0;i<N-3;i+=4)
+ {
+ __m128 xi = _mm_loadu_ps(x+i);
+ __m128 y1i = _mm_loadu_ps(y01+i);
+ __m128 y2i = _mm_loadu_ps(y02+i);
+ xsum1 = _mm_add_ps(xsum1,_mm_mul_ps(xi, y1i));
+ xsum2 = _mm_add_ps(xsum2,_mm_mul_ps(xi, y2i));
+ }
+ /* Horizontal sum */
+ xsum1 = _mm_add_ps(xsum1, _mm_movehl_ps(xsum1, xsum1));
+ xsum1 = _mm_add_ss(xsum1, _mm_shuffle_ps(xsum1, xsum1, 0x55));
+ _mm_store_ss(xy1, xsum1);
+ xsum2 = _mm_add_ps(xsum2, _mm_movehl_ps(xsum2, xsum2));
+ xsum2 = _mm_add_ss(xsum2, _mm_shuffle_ps(xsum2, xsum2, 0x55));
+ _mm_store_ss(xy2, xsum2);
+ for (;i<N;i++)
+ {
+ *xy1 = MAC16_16(*xy1, x[i], y01[i]);
+ *xy2 = MAC16_16(*xy2, x[i], y02[i]);
+ }
+}
+
+#define OVERRIDE_COMB_FILTER_CONST
+static OPUS_INLINE void comb_filter_const(opus_val32 *y, opus_val32 *x, int T, int N,
+ opus_val16 g10, opus_val16 g11, opus_val16 g12)
+{
+ int i;
+ __m128 x0v;
+ __m128 g10v, g11v, g12v;
+ g10v = _mm_load1_ps(&g10);
+ g11v = _mm_load1_ps(&g11);
+ g12v = _mm_load1_ps(&g12);
+ x0v = _mm_loadu_ps(&x[-T-2]);
+ for (i=0;i<N-3;i+=4)
+ {
+ __m128 yi, yi2, x1v, x2v, x3v, x4v;
+ const opus_val32 *xp = &x[i-T-2];
+ yi = _mm_loadu_ps(x+i);
+ x4v = _mm_loadu_ps(xp+4);
+#if 0
+ /* Slower version with all loads */
+ x1v = _mm_loadu_ps(xp+1);
+ x2v = _mm_loadu_ps(xp+2);
+ x3v = _mm_loadu_ps(xp+3);
+#else
+ x2v = _mm_shuffle_ps(x0v, x4v, 0x4e);
+ x1v = _mm_shuffle_ps(x0v, x2v, 0x99);
+ x3v = _mm_shuffle_ps(x2v, x4v, 0x99);
+#endif
+
+ yi = _mm_add_ps(yi, _mm_mul_ps(g10v,x2v));
+#if 0 /* Set to 1 to make it bit-exact with the non-SSE version */
+ yi = _mm_add_ps(yi, _mm_mul_ps(g11v,_mm_add_ps(x3v,x1v)));
+ yi = _mm_add_ps(yi, _mm_mul_ps(g12v,_mm_add_ps(x4v,x0v)));
+#else
+ /* Use partial sums */
+ yi2 = _mm_add_ps(_mm_mul_ps(g11v,_mm_add_ps(x3v,x1v)),
+ _mm_mul_ps(g12v,_mm_add_ps(x4v,x0v)));
+ yi = _mm_add_ps(yi, yi2);
+#endif
+ x0v=x4v;
+ _mm_storeu_ps(y+i, yi);
+ }
+#ifdef CUSTOM_MODES
+ for (;i<N;i++)
+ {
+ y[i] = x[i]
+ + MULT16_32_Q15(g10,x[i-T])
+ + MULT16_32_Q15(g11,ADD32(x[i-T+1],x[i-T-1]))
+ + MULT16_32_Q15(g12,ADD32(x[i-T+2],x[i-T-2]));
+ }
+#endif
+}
+
+#endif
diff --git a/drivers/opus/http.c b/drivers/opus/http.c
new file mode 100644
index 0000000000..24991b0401
--- /dev/null
+++ b/drivers/opus/http.c
@@ -0,0 +1,3391 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012 *
+ * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
+ * *
+ ********************************************************************/
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/internal.h"
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <string.h>
+
+/*RFCs referenced in this file:
+ RFC 761: DOD Standard Transmission Control Protocol
+ RFC 1535: A Security Problem and Proposed Correction With Widely Deployed DNS
+ Software
+ RFC 1738: Uniform Resource Locators (URL)
+ RFC 1945: Hypertext Transfer Protocol -- HTTP/1.0
+ RFC 2068: Hypertext Transfer Protocol -- HTTP/1.1
+ RFC 2145: Use and Interpretation of HTTP Version Numbers
+ RFC 2246: The TLS Protocol Version 1.0
+ RFC 2459: Internet X.509 Public Key Infrastructure Certificate and
+ Certificate Revocation List (CRL) Profile
+ RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1
+ RFC 2617: HTTP Authentication: Basic and Digest Access Authentication
+ RFC 2817: Upgrading to TLS Within HTTP/1.1
+ RFC 2818: HTTP Over TLS
+ RFC 3492: Punycode: A Bootstring encoding of Unicode for Internationalized
+ Domain Names in Applications (IDNA)
+ RFC 3986: Uniform Resource Identifier (URI): Generic Syntax
+ RFC 3987: Internationalized Resource Identifiers (IRIs)
+ RFC 4343: Domain Name System (DNS) Case Insensitivity Clarification
+ RFC 5894: Internationalized Domain Names for Applications (IDNA):
+ Background, Explanation, and Rationale
+ RFC 6066: Transport Layer Security (TLS) Extensions: Extension Definitions
+ RFC 6125: Representation and Verification of Domain-Based Application Service
+ Identity within Internet Public Key Infrastructure Using X.509 (PKIX)
+ Certificates in the Context of Transport Layer Security (TLS)
+ RFC 6555: Happy Eyeballs: Success with Dual-Stack Hosts*/
+
+typedef struct OpusParsedURL OpusParsedURL;
+typedef struct OpusStringBuf OpusStringBuf;
+typedef struct OpusHTTPConn OpusHTTPConn;
+typedef struct OpusHTTPStream OpusHTTPStream;
+
+static char *op_string_range_dup(const char *_start,const char *_end){
+ size_t len;
+ char *ret;
+ OP_ASSERT(_start<=_end);
+ len=_end-_start;
+ /*This is to help avoid overflow elsewhere, later.*/
+ if(OP_UNLIKELY(len>=INT_MAX))return NULL;
+ ret=(char *)_ogg_malloc(sizeof(*ret)*(len+1));
+ if(OP_LIKELY(ret!=NULL)){
+ ret=(char *)memcpy(ret,_start,sizeof(*ret)*(len));
+ ret[len]='\0';
+ }
+ return ret;
+}
+
+static char *op_string_dup(const char *_s){
+ return op_string_range_dup(_s,_s+strlen(_s));
+}
+
+static char *op_string_tolower(char *_s){
+ int i;
+ for(i=0;_s[i]!='\0';i++){
+ int c;
+ c=_s[i];
+ if(c>='A'&&c<='Z')c+='a'-'A';
+ _s[i]=(char)c;
+ }
+ return _s;
+}
+
+/*URI character classes (from RFC 3986).*/
+#define OP_URL_ALPHA \
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+#define OP_URL_DIGIT "0123456789"
+#define OP_URL_HEXDIGIT "0123456789ABCDEFabcdef"
+/*Not a character class, but the characters allowed in <scheme>.*/
+#define OP_URL_SCHEME OP_URL_ALPHA OP_URL_DIGIT "+-."
+#define OP_URL_GEN_DELIMS "#/:?@[]"
+#define OP_URL_SUB_DELIMS "!$&'()*+,;="
+#define OP_URL_RESERVED OP_URL_GEN_DELIMS OP_URL_SUB_DELIMS
+#define OP_URL_UNRESERVED OP_URL_ALPHA OP_URL_DIGIT "-._~"
+/*Not a character class, but the characters allowed in <pct-encoded>.*/
+#define OP_URL_PCT_ENCODED "%"
+/*Not a character class or production rule, but for convenience.*/
+#define OP_URL_PCHAR_BASE \
+ OP_URL_UNRESERVED OP_URL_PCT_ENCODED OP_URL_SUB_DELIMS
+#define OP_URL_PCHAR OP_URL_PCHAR_BASE ":@"
+/*Not a character class, but the characters allowed in <userinfo> and
+ <IP-literal>.*/
+#define OP_URL_PCHAR_NA OP_URL_PCHAR_BASE ":"
+/*Not a character class, but the characters allowed in <segment-nz-nc>.*/
+#define OP_URL_PCHAR_NC OP_URL_PCHAR_BASE "@"
+/*Not a character clsss, but the characters allowed in <path>.*/
+#define OP_URL_PATH OP_URL_PCHAR "/"
+/*Not a character class, but the characters allowed in <query> / <fragment>.*/
+#define OP_URL_QUERY_FRAG OP_URL_PCHAR "/?"
+
+/*Check the <% HEXDIG HEXDIG> escapes of a URL for validity.
+ Return: 0 if valid, or a negative value on failure.*/
+static int op_validate_url_escapes(const char *_s){
+ int i;
+ for(i=0;_s[i];i++){
+ if(_s[i]=='%'){
+ if(OP_UNLIKELY(!isxdigit(_s[i+1]))
+ ||OP_UNLIKELY(!isxdigit(_s[i+2]))
+ /*RFC 3986 says %00 "should be rejected if the application is not
+ expecting to receive raw data within a component."*/
+ ||OP_UNLIKELY(_s[i+1]=='0'&&_s[i+2]=='0')){
+ return OP_FALSE;
+ }
+ i+=2;
+ }
+ }
+ return 0;
+}
+
+/*Convert a hex digit to its actual value.
+ _c: The hex digit to convert.
+ Presumed to be valid ('0'...'9', 'A'...'F', or 'a'...'f').
+ Return: The value of the digit, in the range [0,15].*/
+static int op_hex_value(int _c){
+ return _c>='a'?_c-'a'+10:_c>='A'?_c-'A'+10:_c-'0';
+}
+
+/*Unescape all the <% HEXDIG HEXDIG> sequences in a string in-place.
+ This does no validity checking.*/
+static char *op_unescape_url_component(char *_s){
+ int i;
+ int j;
+ for(i=j=0;_s[i];i++,j++){
+ if(_s[i]=='%'){
+ _s[i]=(char)(op_hex_value(_s[i+1])<<4|op_hex_value(_s[i+2]));
+ i+=2;
+ }
+ }
+ return _s;
+}
+
+/*Parse a file: URL.
+ This code is not meant to be fast: strspn() with large sets is likely to be
+ slow, but it is very convenient.
+ It is meant to be RFC 1738-compliant (as updated by RFC 3986).*/
+static const char *op_parse_file_url(const char *_src){
+ const char *scheme_end;
+ const char *path;
+ const char *path_end;
+ scheme_end=_src+strspn(_src,OP_URL_SCHEME);
+ if(OP_UNLIKELY(*scheme_end!=':')
+ ||scheme_end-_src!=4||op_strncasecmp(_src,"file",4)!=0){
+ /*Unsupported protocol.*/
+ return NULL;
+ }
+ /*Make sure all escape sequences are valid to simplify unescaping later.*/
+ if(OP_UNLIKELY(op_validate_url_escapes(scheme_end+1)<0))return NULL;
+ if(scheme_end[1]=='/'&&scheme_end[2]=='/'){
+ const char *host;
+ /*file: URLs can have a host!
+ Yeah, I was surprised, too, but that's what RFC 1738 says.
+ It also says, "The file URL scheme is unusual in that it does not specify
+ an Internet protocol or access method for such files; as such, its
+ utility in network protocols between hosts is limited," which is a mild
+ understatement.*/
+ host=scheme_end+3;
+ /*The empty host is what we expect.*/
+ if(OP_LIKELY(*host=='/'))path=host;
+ else{
+ const char *host_end;
+ char host_buf[28];
+ /*RFC 1738 says localhost "is interpreted as `the machine from which the
+ URL is being interpreted,'" so let's check for it.*/
+ host_end=host+strspn(host,OP_URL_PCHAR_BASE);
+ /*No <port> allowed.
+ This also rejects IP-Literals.*/
+ if(*host_end!='/')return NULL;
+ /*An escaped "localhost" can take at most 27 characters.*/
+ if(OP_UNLIKELY(host_end-host>27))return NULL;
+ memcpy(host_buf,host,sizeof(*host_buf)*(host_end-host));
+ host_buf[host_end-host]='\0';
+ op_unescape_url_component(host_buf);
+ op_string_tolower(host_buf);
+ /*Some other host: give up.*/
+ if(OP_UNLIKELY(strcmp(host_buf,"localhost")!=0))return NULL;
+ path=host_end;
+ }
+ }
+ else path=scheme_end+1;
+ path_end=path+strspn(path,OP_URL_PATH);
+ /*This will reject a <query> or <fragment> component, too.
+ I don't know what to do with queries, but a temporal fragment would at
+ least make sense.
+ RFC 1738 pretty clearly defines a <searchpart> that's equivalent to the
+ RFC 3986 <query> component for other schemes, but not the file: scheme,
+ so I'm going to just reject it.*/
+ if(*path_end!='\0')return NULL;
+ return path;
+}
+
+#if defined(OP_ENABLE_HTTP)
+# if defined(_WIN32)
+# include <winsock2.h>
+# include <ws2tcpip.h>
+# include <openssl/ssl.h>
+# include "opus/winerrno.h"
+
+typedef SOCKET op_sock;
+
+# define OP_INVALID_SOCKET (INVALID_SOCKET)
+
+/*Vista and later support WSAPoll(), but we don't want to rely on that.
+ Instead we re-implement it badly using select().
+ Unfortunately, they define a conflicting struct pollfd, so we only define our
+ own if it looks like that one has not already been defined.*/
+# if !defined(POLLIN)
+/*Equivalent to POLLIN.*/
+# define POLLRDNORM (0x0100)
+/*Priority band data can be read.*/
+# define POLLRDBAND (0x0200)
+/*There is data to read.*/
+# define POLLIN (POLLRDNORM|POLLRDBAND)
+/* There is urgent data to read.*/
+# define POLLPRI (0x0400)
+/*Equivalent to POLLOUT.*/
+# define POLLWRNORM (0x0010)
+/*Writing now will not block.*/
+# define POLLOUT (POLLWRNORM)
+/*Priority data may be written.*/
+# define POLLWRBAND (0x0020)
+/*Error condition (output only).*/
+# define POLLERR (0x0001)
+/*Hang up (output only).*/
+# define POLLHUP (0x0002)
+/*Invalid request: fd not open (output only).*/
+# define POLLNVAL (0x0004)
+
+struct pollfd{
+ /*File descriptor.*/
+ op_sock fd;
+ /*Requested events.*/
+ short events;
+ /*Returned events.*/
+ short revents;
+};
+# endif
+
+/*But Winsock never defines nfds_t (it's simply hard-coded to ULONG).*/
+typedef unsigned long nfds_t;
+
+/*The usage of FD_SET() below is O(N^2).
+ This is okay because select() is limited to 64 sockets in Winsock, anyway.
+ In practice, we only ever call it with one or two sockets.*/
+static int op_poll_win32(struct pollfd *_fds,nfds_t _nfds,int _timeout){
+ struct timeval tv;
+ fd_set ifds;
+ fd_set ofds;
+ fd_set efds;
+ nfds_t i;
+ int ret;
+ FD_ZERO(&ifds);
+ FD_ZERO(&ofds);
+ FD_ZERO(&efds);
+ for(i=0;i<_nfds;i++){
+ _fds[i].revents=0;
+ if(_fds[i].events&POLLIN)FD_SET(_fds[i].fd,&ifds);
+ if(_fds[i].events&POLLOUT)FD_SET(_fds[i].fd,&ofds);
+ FD_SET(_fds[i].fd,&efds);
+ }
+ if(_timeout>=0){
+ tv.tv_sec=_timeout/1000;
+ tv.tv_usec=(_timeout%1000)*1000;
+ }
+ ret=select(-1,&ifds,&ofds,&efds,_timeout<0?NULL:&tv);
+ if(ret>0){
+ for(i=0;i<_nfds;i++){
+ if(FD_ISSET(_fds[i].fd,&ifds))_fds[i].revents|=POLLIN;
+ if(FD_ISSET(_fds[i].fd,&ofds))_fds[i].revents|=POLLOUT;
+ /*This isn't correct: there are several different things that might have
+ happened to a fd in efds, but I don't know a good way to distinguish
+ them without more context from the caller.
+ It's okay, because we don't actually check any of these bits, we just
+ need _some_ bit set.*/
+ if(FD_ISSET(_fds[i].fd,&efds))_fds[i].revents|=POLLHUP;
+ }
+ }
+ return ret;
+}
+
+/*We define op_errno() to make it clear that it's not an l-value like normal
+ errno is.*/
+# define op_errno() (WSAGetLastError()?WSAGetLastError()-WSABASEERR:0)
+# define op_reset_errno() (WSASetLastError(0))
+
+/*The remaining functions don't get an op_ prefix even though they only
+ operate on sockets, because we don't use non-socket I/O here, and this
+ minimizes the changes needed to deal with Winsock.*/
+# define close(_fd) closesocket(_fd)
+/*This relies on sizeof(u_long)==sizeof(int), which is always true on both
+ Win32 and Win64.*/
+# define ioctl(_fd,_req,_arg) ioctlsocket(_fd,_req,(u_long *)(_arg))
+# define getsockopt(_fd,_level,_name,_val,_len) \
+ getsockopt(_fd,_level,_name,(char *)(_val),_len)
+# define setsockopt(_fd,_level,_name,_val,_len) \
+ setsockopt(_fd,_level,_name,(const char *)(_val),_len)
+# define poll(_fds,_nfds,_timeout) op_poll_win32(_fds,_nfds,_timeout)
+
+# if defined(_MSC_VER)
+typedef ptrdiff_t ssize_t;
+# endif
+
+/*Load certificates from the built-in certificate store.*/
+int SSL_CTX_set_default_verify_paths_win32(SSL_CTX *_ssl_ctx);
+# define SSL_CTX_set_default_verify_paths \
+ SSL_CTX_set_default_verify_paths_win32
+
+# else
+/*Normal Berkeley sockets.*/
+# include <sys/ioctl.h>
+# include <sys/types.h>
+# include <sys/socket.h>
+# include <arpa/inet.h>
+# include <netinet/in.h>
+# include <netinet/tcp.h>
+# include <fcntl.h>
+# include <netdb.h>
+# include <poll.h>
+# include <unistd.h>
+# include <openssl/ssl.h>
+
+typedef int op_sock;
+
+# define OP_INVALID_SOCKET (-1)
+
+# define op_errno() (errno)
+# define op_reset_errno() (errno=0)
+
+# endif
+# include <sys/timeb.h>
+# include <openssl/x509v3.h>
+
+/*The maximum number of simultaneous connections.
+ RFC 2616 says this SHOULD NOT be more than 2, but everyone on the modern web
+ ignores that (e.g., IE 8 bumped theirs up from 2 to 6, Firefox uses 15).
+ If it makes you feel better, we'll only ever actively read from one of these
+ at a time.
+ The others are kept around mainly to avoid slow-starting a new connection
+ when seeking, and time out rapidly.*/
+# define OP_NCONNS_MAX (4)
+
+/*The amount of time before we attempt to re-resolve the host.
+ This is 10 minutes, as recommended in RFC 6555 for expiring cached connection
+ results for dual-stack hosts.*/
+# define OP_RESOLVE_CACHE_TIMEOUT_MS (10*60*(opus_int32)1000)
+
+/*The number of redirections at which we give up.
+ The value here is the current default in Firefox.
+ RFC 2068 mandated a maximum of 5, but RFC 2616 relaxed that to "a client
+ SHOULD detect infinite redirection loops."
+ Fortunately, 20 is less than infinity.*/
+# define OP_REDIRECT_LIMIT (20)
+
+/*The initial size of the buffer used to read a response message (before the
+ body).*/
+# define OP_RESPONSE_SIZE_MIN (510)
+/*The maximum size of a response message (before the body).
+ Responses larger than this will be discarded.
+ I've seen a real server return 20 kB of data for a 302 Found response.
+ Increasing this beyond 32kB will cause problems on platforms with a 16-bit
+ int.*/
+# define OP_RESPONSE_SIZE_MAX (32766)
+
+/*The number of milliseconds we will allow a connection to sit idle before we
+ refuse to resurrect it.
+ Apache as of 2.2 has reduced its default timeout to 5 seconds (from 15), so
+ that's what we'll use here.*/
+# define OP_CONNECTION_IDLE_TIMEOUT_MS (5*1000)
+
+/*The number of milliseconds we will wait to send or receive data before giving
+ up.*/
+# define OP_POLL_TIMEOUT_MS (30*1000)
+
+/*We will always attempt to read ahead at least this much in preference to
+ opening a new connection.*/
+# define OP_READAHEAD_THRESH_MIN (32*(opus_int32)1024)
+
+/*The amount of data to request after a seek.
+ This is a trade-off between read throughput after a seek vs. the the ability
+ to quickly perform another seek with the same connection.*/
+# define OP_PIPELINE_CHUNK_SIZE (32*(opus_int32)1024)
+/*Subsequent chunks are requested with larger and larger sizes until they pass
+ this threshold, after which we just ask for the rest of the resource.*/
+# define OP_PIPELINE_CHUNK_SIZE_MAX (1024*(opus_int32)1024)
+/*This is the maximum number of requests we'll make with a single connection.
+ Many servers will simply disconnect after we attempt some number of requests,
+ possibly without sending a Connection: close header, meaning we won't
+ discover it until we try to read beyond the end of the current chunk.
+ We can reconnect when that happens, but this is slow.
+ Instead, we impose a limit ourselves (set to the default for Apache
+ installations and thus likely the most common value in use).*/
+# define OP_PIPELINE_MAX_REQUESTS (100)
+/*This should be the number of requests, starting from a chunk size of
+ OP_PIPELINE_CHUNK_SIZE and doubling each time, until we exceed
+ OP_PIPELINE_CHUNK_SIZE_MAX and just request the rest of the file.
+ We won't reuse a connection when seeking unless it has at least this many
+ requests left, to reduce the chances we'll have to open a new connection
+ while reading forward afterwards.*/
+# define OP_PIPELINE_MIN_REQUESTS (7)
+
+/*Is this an https URL?
+ For now we can simply check the last letter of the scheme.*/
+# define OP_URL_IS_SSL(_url) ((_url)->scheme[4]=='s')
+
+/*Does this URL use the default port for its scheme?*/
+# define OP_URL_IS_DEFAULT_PORT(_url) \
+ (!OP_URL_IS_SSL(_url)&&(_url)->port==80 \
+ ||OP_URL_IS_SSL(_url)&&(_url)->port==443)
+
+struct OpusParsedURL{
+ /*Either "http" or "https".*/
+ char *scheme;
+ /*The user name from the <userinfo> component, or NULL.*/
+ char *user;
+ /*The password from the <userinfo> component, or NULL.*/
+ char *pass;
+ /*The <host> component.
+ This may not be NULL.*/
+ char *host;
+ /*The <path> and <query> components.
+ This may not be NULL.*/
+ char *path;
+ /*The <port> component.
+ This is set to the default port if the URL did not contain one.*/
+ unsigned port;
+};
+
+/*Parse a URL.
+ This code is not meant to be fast: strspn() with large sets is likely to be
+ slow, but it is very convenient.
+ It is meant to be RFC 3986-compliant.
+ We currently do not support IRIs (Internationalized Resource Identifiers,
+ RFC 3987).
+ Callers should translate them to URIs first.*/
+static int op_parse_url_impl(OpusParsedURL *_dst,const char *_src){
+ const char *scheme_end;
+ const char *authority;
+ const char *userinfo_end;
+ const char *user;
+ const char *user_end;
+ const char *pass;
+ const char *hostport;
+ const char *hostport_end;
+ const char *host_end;
+ const char *port;
+ opus_int32 port_num;
+ const char *port_end;
+ const char *path;
+ const char *path_end;
+ const char *uri_end;
+ scheme_end=_src+strspn(_src,OP_URL_SCHEME);
+ if(OP_UNLIKELY(*scheme_end!=':')
+ ||OP_UNLIKELY(scheme_end-_src<4)||OP_UNLIKELY(scheme_end-_src>5)
+ ||OP_UNLIKELY(op_strncasecmp(_src,"https",scheme_end-_src)!=0)){
+ /*Unsupported protocol.*/
+ return OP_EIMPL;
+ }
+ if(OP_UNLIKELY(scheme_end[1]!='/')||OP_UNLIKELY(scheme_end[2]!='/')){
+ /*We require an <authority> component.*/
+ return OP_EINVAL;
+ }
+ authority=scheme_end+3;
+ /*Make sure all escape sequences are valid to simplify unescaping later.*/
+ if(OP_UNLIKELY(op_validate_url_escapes(authority)<0))return OP_EINVAL;
+ /*Look for a <userinfo> component.*/
+ userinfo_end=authority+strspn(authority,OP_URL_PCHAR_NA);
+ if(*userinfo_end=='@'){
+ /*Found one.*/
+ user=authority;
+ /*Look for a password (yes, clear-text passwords are deprecated, I know,
+ but what else are people supposed to use? use SSL if you care).*/
+ user_end=authority+strspn(authority,OP_URL_PCHAR_BASE);
+ if(*user_end==':')pass=user_end+1;
+ else pass=NULL;
+ hostport=userinfo_end+1;
+ }
+ else{
+ /*We shouldn't have to initialize user_end, but gcc is too dumb to figure
+ out that user!=NULL below means we didn't take this else branch.*/
+ user=user_end=NULL;
+ pass=NULL;
+ hostport=authority;
+ }
+ /*Try to figure out where the <host> component ends.*/
+ if(hostport[0]=='['){
+ hostport++;
+ /*We have an <IP-literal>, which can contain colons.*/
+ hostport_end=host_end=hostport+strspn(hostport,OP_URL_PCHAR_NA);
+ if(OP_UNLIKELY(*hostport_end++!=']'))return OP_EINVAL;
+ }
+ /*Currently we don't support IDNA (RFC 5894), because I don't want to deal
+ with the policy about which domains should not be internationalized to
+ avoid confusing similarities.
+ Give this API Punycode (RFC 3492) domain names instead.*/
+ else hostport_end=host_end=hostport+strspn(hostport,OP_URL_PCHAR_BASE);
+ /*TODO: Validate host.*/
+ /*Is there a port number?*/
+ port_num=-1;
+ if(*hostport_end==':'){
+ int i;
+ port=hostport_end+1;
+ port_end=port+strspn(port,OP_URL_DIGIT);
+ path=port_end;
+ /*Not part of RFC 3986, but require port numbers in the range 0...65535.*/
+ if(OP_LIKELY(port_end-port>0)){
+ while(*port=='0')port++;
+ if(OP_UNLIKELY(port_end-port>5))return OP_EINVAL;
+ port_num=0;
+ for(i=0;i<port_end-port;i++)port_num=port_num*10+port[i]-'0';
+ if(OP_UNLIKELY(port_num>65535))return OP_EINVAL;
+ }
+ }
+ else path=hostport_end;
+ path_end=path+strspn(path,OP_URL_PATH);
+ /*If the path is not empty, it must begin with a '/'.*/
+ if(OP_LIKELY(path_end>path)&&OP_UNLIKELY(path[0]!='/'))return OP_EINVAL;
+ /*Consume the <query> component, if any (right now we don't split this out
+ from the <path> component).*/
+ if(*path_end=='?')path_end=path_end+strspn(path_end,OP_URL_QUERY_FRAG);
+ /*Discard the <fragment> component, if any.
+ This doesn't get sent to the server.
+ Some day we should add support for Media Fragment URIs
+ <http://www.w3.org/TR/media-frags/>.*/
+ if(*path_end=='#')uri_end=path_end+1+strspn(path_end+1,OP_URL_QUERY_FRAG);
+ else uri_end=path_end;
+ /*If there's anything left, this was not a valid URL.*/
+ if(OP_UNLIKELY(*uri_end!='\0'))return OP_EINVAL;
+ _dst->scheme=op_string_range_dup(_src,scheme_end);
+ if(OP_UNLIKELY(_dst->scheme==NULL))return OP_EFAULT;
+ op_string_tolower(_dst->scheme);
+ if(user!=NULL){
+ _dst->user=op_string_range_dup(user,user_end);
+ if(OP_UNLIKELY(_dst->user==NULL))return OP_EFAULT;
+ op_unescape_url_component(_dst->user);
+ /*Unescaping might have created a ':' in the username.
+ That's not allowed by RFC 2617's Basic Authentication Scheme.*/
+ if(OP_UNLIKELY(strchr(_dst->user,':')!=NULL))return OP_EINVAL;
+ }
+ else _dst->user=NULL;
+ if(pass!=NULL){
+ _dst->pass=op_string_range_dup(pass,userinfo_end);
+ if(OP_UNLIKELY(_dst->pass==NULL))return OP_EFAULT;
+ op_unescape_url_component(_dst->pass);
+ }
+ else _dst->pass=NULL;
+ _dst->host=op_string_range_dup(hostport,host_end);
+ if(OP_UNLIKELY(_dst->host==NULL))return OP_EFAULT;
+ if(port_num<0){
+ if(_src[4]=='s')port_num=443;
+ else port_num=80;
+ }
+ _dst->port=(unsigned)port_num;
+ /*RFC 2616 says an empty <abs-path> component is equivalent to "/", and we
+ MUST use the latter in the Request-URI.
+ Reserve space for the slash here.*/
+ if(path==path_end||path[0]=='?')path--;
+ _dst->path=op_string_range_dup(path,path_end);
+ if(OP_UNLIKELY(_dst->path==NULL))return OP_EFAULT;
+ /*And force-set it here.*/
+ _dst->path[0]='/';
+ return 0;
+}
+
+static void op_parsed_url_init(OpusParsedURL *_url){
+ memset(_url,0,sizeof(*_url));
+}
+
+static void op_parsed_url_clear(OpusParsedURL *_url){
+ _ogg_free(_url->scheme);
+ _ogg_free(_url->user);
+ _ogg_free(_url->pass);
+ _ogg_free(_url->host);
+ _ogg_free(_url->path);
+}
+
+static int op_parse_url(OpusParsedURL *_dst,const char *_src){
+ OpusParsedURL url;
+ int ret;
+ op_parsed_url_init(&url);
+ ret=op_parse_url_impl(&url,_src);
+ if(OP_UNLIKELY(ret<0))op_parsed_url_clear(&url);
+ else *_dst=*&url;
+ return ret;
+}
+
+/*A buffer to hold growing strings.
+ The main purpose of this is to consolidate allocation checks and simplify
+ cleanup on a failed allocation.*/
+struct OpusStringBuf{
+ char *buf;
+ int nbuf;
+ int cbuf;
+};
+
+static void op_sb_init(OpusStringBuf *_sb){
+ _sb->buf=NULL;
+ _sb->nbuf=0;
+ _sb->cbuf=0;
+}
+
+static void op_sb_clear(OpusStringBuf *_sb){
+ _ogg_free(_sb->buf);
+}
+
+/*Make sure we have room for at least _capacity characters (plus 1 more for the
+ terminating NUL).*/
+static int op_sb_ensure_capacity(OpusStringBuf *_sb,int _capacity){
+ char *buf;
+ int cbuf;
+ buf=_sb->buf;
+ cbuf=_sb->cbuf;
+ if(_capacity>=cbuf-1){
+ if(OP_UNLIKELY(cbuf>INT_MAX-1>>1))return OP_EFAULT;
+ if(OP_UNLIKELY(_capacity>=INT_MAX-1))return OP_EFAULT;
+ cbuf=OP_MAX(2*cbuf+1,_capacity+1);
+ buf=_ogg_realloc(buf,sizeof(*buf)*cbuf);
+ if(OP_UNLIKELY(buf==NULL))return OP_EFAULT;
+ _sb->buf=buf;
+ _sb->cbuf=cbuf;
+ }
+ return 0;
+}
+
+/*Increase the capacity of the buffer, but not to more than _max_size
+ characters (plus 1 more for the terminating NUL).*/
+static int op_sb_grow(OpusStringBuf *_sb,int _max_size){
+ char *buf;
+ int cbuf;
+ buf=_sb->buf;
+ cbuf=_sb->cbuf;
+ OP_ASSERT(_max_size<=INT_MAX-1);
+ cbuf=cbuf<=_max_size-1>>1?2*cbuf+1:_max_size+1;
+ buf=_ogg_realloc(buf,sizeof(*buf)*cbuf);
+ if(OP_UNLIKELY(buf==NULL))return OP_EFAULT;
+ _sb->buf=buf;
+ _sb->cbuf=cbuf;
+ return 0;
+}
+
+static int op_sb_append(OpusStringBuf *_sb,const char *_s,int _len){
+ char *buf;
+ int nbuf;
+ int ret;
+ nbuf=_sb->nbuf;
+ if(OP_UNLIKELY(nbuf>INT_MAX-_len))return OP_EFAULT;
+ ret=op_sb_ensure_capacity(_sb,nbuf+_len);
+ if(OP_UNLIKELY(ret<0))return ret;
+ buf=_sb->buf;
+ memcpy(buf+nbuf,_s,sizeof(*buf)*_len);
+ nbuf+=_len;
+ buf[nbuf]='\0';
+ _sb->nbuf=nbuf;
+ return 0;
+}
+
+static int op_sb_append_string(OpusStringBuf *_sb,const char *_s){
+ return op_sb_append(_sb,_s,strlen(_s));
+}
+
+static int op_sb_append_port(OpusStringBuf *_sb,unsigned _port){
+ char port_buf[7];
+ OP_ASSERT(_port<=65535U);
+ sprintf(port_buf,":%u",_port);
+ return op_sb_append_string(_sb,port_buf);
+}
+
+static int op_sb_append_nonnegative_int64(OpusStringBuf *_sb,opus_int64 _i){
+ char digit;
+ int nbuf_start;
+ int ret;
+ OP_ASSERT(_i>=0);
+ nbuf_start=_sb->nbuf;
+ ret=0;
+ do{
+ digit='0'+_i%10;
+ ret|=op_sb_append(_sb,&digit,1);
+ _i/=10;
+ }
+ while(_i>0);
+ if(OP_LIKELY(ret>=0)){
+ char *buf;
+ int nbuf_end;
+ buf=_sb->buf;
+ nbuf_end=_sb->nbuf-1;
+ /*We've added the digits backwards.
+ Reverse them.*/
+ while(nbuf_start<nbuf_end){
+ digit=buf[nbuf_start];
+ buf[nbuf_start]=buf[nbuf_end];
+ buf[nbuf_end]=digit;
+ nbuf_start++;
+ nbuf_end--;
+ }
+ }
+ return ret;
+}
+
+static struct addrinfo *op_resolve(const char *_host,unsigned _port){
+ struct addrinfo *addrs;
+ struct addrinfo hints;
+ char service[6];
+ memset(&hints,0,sizeof(hints));
+ hints.ai_socktype=SOCK_STREAM;
+#if !defined(_WIN32)
+ hints.ai_flags=AI_NUMERICSERV;
+#endif
+ OP_ASSERT(_port<=65535U);
+ sprintf(service,"%u",_port);
+ if(OP_LIKELY(!getaddrinfo(_host,service,&hints,&addrs)))return addrs;
+ return NULL;
+}
+
+static int op_sock_set_nonblocking(op_sock _fd,int _nonblocking){
+#if !defined(_WIN32)
+ int flags;
+ flags=fcntl(_fd,F_GETFL);
+ if(OP_UNLIKELY(flags<0))return flags;
+ if(_nonblocking)flags|=O_NONBLOCK;
+ else flags&=~O_NONBLOCK;
+ return fcntl(_fd,F_SETFL,flags);
+#else
+ return ioctl(_fd,FIONBIO,&_nonblocking);
+#endif
+}
+
+/*Disable/enable write coalescing if we can.
+ We always send whole requests at once and always parse the response headers
+ before sending another one, so normally write coalescing just causes added
+ delay.*/
+static void op_sock_set_tcp_nodelay(op_sock _fd,int _nodelay){
+# if defined(TCP_NODELAY)&&(defined(IPPROTO_TCP)||defined(SOL_TCP))
+# if defined(IPPROTO_TCP)
+# define OP_SO_LEVEL IPPROTO_TCP
+# else
+# define OP_SO_LEVEL SOL_TCP
+# endif
+ /*It doesn't really matter if this call fails, but it would be interesting
+ to hit a case where it does.*/
+ OP_ALWAYS_TRUE(!setsockopt(_fd,OP_SO_LEVEL,TCP_NODELAY,
+ &_nodelay,sizeof(_nodelay)));
+# endif
+}
+
+#if defined(_WIN32)
+static void op_init_winsock(){
+ static LONG count;
+ static WSADATA wsadata;
+ if(InterlockedIncrement(&count)==1)WSAStartup(0x0202,&wsadata);
+}
+#endif
+
+/*A single physical connection to an HTTP server.
+ We may have several of these open at once.*/
+struct OpusHTTPConn{
+ /*The current position indicator for this connection.*/
+ opus_int64 pos;
+ /*The position where the current request will end, or -1 if we're reading
+ until EOF (an unseekable stream or the initial HTTP/1.0 request).*/
+ opus_int64 end_pos;
+ /*The position where next request we've sent will start, or -1 if we haven't
+ sent the next request yet.*/
+ opus_int64 next_pos;
+ /*The end of the next request or -1 if we requested the rest of the resource.
+ This is only set to a meaningful value if next_pos is not -1.*/
+ opus_int64 next_end;
+ /*The SSL connection, if this is https.*/
+ SSL *ssl_conn;
+ /*The next connection in either the LRU or free list.*/
+ OpusHTTPConn *next;
+ /*The last time we blocked for reading from this connection.*/
+ struct timeb read_time;
+ /*The number of bytes we've read since the last time we blocked.*/
+ opus_int64 read_bytes;
+ /*The estimated throughput of this connection, in bytes/s.*/
+ opus_int64 read_rate;
+ /*The socket we're reading from.*/
+ op_sock fd;
+ /*The number of remaining requests we are allowed on this connection.*/
+ int nrequests_left;
+ /*The chunk size to use for pipelining requests.*/
+ opus_int32 chunk_size;
+};
+
+static void op_http_conn_init(OpusHTTPConn *_conn){
+ _conn->next_pos=-1;
+ _conn->ssl_conn=NULL;
+ _conn->next=NULL;
+ _conn->fd=OP_INVALID_SOCKET;
+}
+
+static void op_http_conn_clear(OpusHTTPConn *_conn){
+ if(_conn->ssl_conn!=NULL)SSL_free(_conn->ssl_conn);
+ /*SSL frees the BIO for us.*/
+ if(_conn->fd!=OP_INVALID_SOCKET)close(_conn->fd);
+}
+
+/*The global stream state.*/
+struct OpusHTTPStream{
+ /*The list of connections.*/
+ OpusHTTPConn conns[OP_NCONNS_MAX];
+ /*The context object used as a framework for TLS/SSL functions.*/
+ SSL_CTX *ssl_ctx;
+ /*The cached session to reuse for future connections.*/
+ SSL_SESSION *ssl_session;
+ /*The LRU list (ordered from MRU to LRU) of currently connected
+ connections.*/
+ OpusHTTPConn *lru_head;
+ /*The free list.*/
+ OpusHTTPConn *free_head;
+ /*The URL to connect to.*/
+ OpusParsedURL url;
+ /*Information about the address we connected to.*/
+ struct addrinfo addr_info;
+ /*The address we connected to.*/
+ union{
+ struct sockaddr s;
+ struct sockaddr_in v4;
+ struct sockaddr_in6 v6;
+ } addr;
+ /*The last time we re-resolved the host.*/
+ struct timeb resolve_time;
+ /*A buffer used to build HTTP requests.*/
+ OpusStringBuf request;
+ /*A buffer used to build proxy CONNECT requests.*/
+ OpusStringBuf proxy_connect;
+ /*A buffer used to receive the response headers.*/
+ OpusStringBuf response;
+ /*The Content-Length, if specified, or -1 otherwise.
+ This will always be specified for seekable streams.*/
+ opus_int64 content_length;
+ /*The position indicator used when no connection is active.*/
+ opus_int64 pos;
+ /*The host we actually connected to.*/
+ char *connect_host;
+ /*The port we actually connected to.*/
+ unsigned connect_port;
+ /*The connection we're currently reading from.
+ This can be -1 if no connection is active.*/
+ int cur_conni;
+ /*Whether or not the server supports range requests.*/
+ int seekable;
+ /*Whether or not the server supports HTTP/1.1 with persistent connections.*/
+ int pipeline;
+ /*Whether or not we should skip certificate checks.*/
+ int skip_certificate_check;
+ /*The offset of the tail of the request.
+ Only the offset in the Range: header appears after this, allowing us to
+ quickly edit the request to ask for a new range.*/
+ int request_tail;
+ /*The estimated time required to open a new connection, in milliseconds.*/
+ opus_int32 connect_rate;
+};
+
+static void op_http_stream_init(OpusHTTPStream *_stream){
+ OpusHTTPConn **pnext;
+ int ci;
+ pnext=&_stream->free_head;
+ for(ci=0;ci<OP_NCONNS_MAX;ci++){
+ op_http_conn_init(_stream->conns+ci);
+ *pnext=_stream->conns+ci;
+ pnext=&_stream->conns[ci].next;
+ }
+ _stream->ssl_ctx=NULL;
+ _stream->ssl_session=NULL;
+ _stream->lru_head=NULL;
+ op_parsed_url_init(&_stream->url);
+ op_sb_init(&_stream->request);
+ op_sb_init(&_stream->proxy_connect);
+ op_sb_init(&_stream->response);
+ _stream->connect_host=NULL;
+ _stream->seekable=0;
+}
+
+/*Close the connection and move it to the free list.
+ _stream: The stream containing the free list.
+ _conn: The connection to close.
+ _penxt: The linked-list pointer currently pointing to this connection.
+ _gracefully: Whether or not to shut down cleanly.*/
+static void op_http_conn_close(OpusHTTPStream *_stream,OpusHTTPConn *_conn,
+ OpusHTTPConn **_pnext,int _gracefully){
+ /*If we don't shut down gracefully, the server MUST NOT re-use our session
+ according to RFC 2246, because it can't tell the difference between an
+ abrupt close and a truncation attack.
+ So we shut down gracefully if we can.
+ However, we will not wait if this would block (it's not worth the savings
+ from session resumption to do so).
+ Clients (that's us) MAY resume a TLS session that ended with an incomplete
+ close, according to RFC 2818, so there's no reason to make sure the server
+ shut things down gracefully.*/
+ if(_gracefully&&_conn->ssl_conn!=NULL)SSL_shutdown(_conn->ssl_conn);
+ op_http_conn_clear(_conn);
+ _conn->next_pos=-1;
+ _conn->ssl_conn=NULL;
+ _conn->fd=OP_INVALID_SOCKET;
+ OP_ASSERT(*_pnext==_conn);
+ *_pnext=_conn->next;
+ _conn->next=_stream->free_head;
+ _stream->free_head=_conn;
+}
+
+static void op_http_stream_clear(OpusHTTPStream *_stream){
+ while(_stream->lru_head!=NULL){
+ op_http_conn_close(_stream,_stream->lru_head,&_stream->lru_head,0);
+ }
+ if(_stream->ssl_session!=NULL)SSL_SESSION_free(_stream->ssl_session);
+ if(_stream->ssl_ctx!=NULL)SSL_CTX_free(_stream->ssl_ctx);
+ op_sb_clear(&_stream->response);
+ op_sb_clear(&_stream->proxy_connect);
+ op_sb_clear(&_stream->request);
+ if(_stream->connect_host!=_stream->url.host)_ogg_free(_stream->connect_host);
+ op_parsed_url_clear(&_stream->url);
+}
+
+static int op_http_conn_write_fully(OpusHTTPConn *_conn,
+ const char *_buf,int _buf_size){
+ struct pollfd fd;
+ SSL *ssl_conn;
+ fd.fd=_conn->fd;
+ ssl_conn=_conn->ssl_conn;
+ while(_buf_size>0){
+ int err;
+ if(ssl_conn!=NULL){
+ int ret;
+ ret=SSL_write(ssl_conn,_buf,_buf_size);
+ if(ret>0){
+ /*Wrote some data.*/
+ _buf+=ret;
+ _buf_size-=ret;
+ continue;
+ }
+ /*Connection closed.*/
+ else if(ret==0)return OP_FALSE;
+ err=SSL_get_error(ssl_conn,ret);
+ /*Yes, renegotiations can cause SSL_write() to block for reading.*/
+ if(err==SSL_ERROR_WANT_READ)fd.events=POLLIN;
+ else if(err==SSL_ERROR_WANT_WRITE)fd.events=POLLOUT;
+ else return OP_FALSE;
+ }
+ else{
+ ssize_t ret;
+ op_reset_errno();
+ ret=send(fd.fd,_buf,_buf_size,0);
+ if(ret>0){
+ _buf+=ret;
+ _buf_size-=ret;
+ continue;
+ }
+ err=op_errno();
+ if(err!=EAGAIN&&err!=EWOULDBLOCK)return OP_FALSE;
+ fd.events=POLLOUT;
+ }
+ if(poll(&fd,1,OP_POLL_TIMEOUT_MS)<=0)return OP_FALSE;
+ }
+ return 0;
+}
+
+static int op_http_conn_estimate_available(OpusHTTPConn *_conn){
+ int available;
+ int ret;
+ ret=ioctl(_conn->fd,FIONREAD,&available);
+ if(ret<0)available=0;
+ /*This requires the SSL read_ahead flag to be unset to work.
+ We ignore partial records as well as the protocol overhead for any pending
+ bytes.
+ This means we might return somewhat less than can truly be read without
+ blocking (if there's a partial record).
+ This is okay, because we're using this value to estimate network transfer
+ time, and we _have_ already received those bytes.
+ We also might return slightly more (due to protocol overhead), but that's
+ small enough that it probably doesn't matter.*/
+ if(_conn->ssl_conn!=NULL)available+=SSL_pending(_conn->ssl_conn);
+ return available;
+}
+
+static opus_int32 op_time_diff_ms(const struct timeb *_end,
+ const struct timeb *_start){
+ opus_int64 dtime;
+ dtime=_end->time-(opus_int64)_start->time;
+ OP_ASSERT(_end->millitm<1000);
+ OP_ASSERT(_start->millitm<1000);
+ if(OP_UNLIKELY(dtime>(OP_INT32_MAX-1000)/1000))return OP_INT32_MAX;
+ if(OP_UNLIKELY(dtime<(OP_INT32_MIN+1000)/1000))return OP_INT32_MIN;
+ return (opus_int32)dtime*1000+_end->millitm-_start->millitm;
+}
+
+/*Update the read rate estimate for this connection.*/
+static void op_http_conn_read_rate_update(OpusHTTPConn *_conn){
+ struct timeb read_time;
+ opus_int32 read_delta_ms;
+ opus_int64 read_delta_bytes;
+ opus_int64 read_rate;
+ read_delta_bytes=_conn->read_bytes;
+ if(read_delta_bytes<=0)return;
+ ftime(&read_time);
+ read_delta_ms=op_time_diff_ms(&read_time,&_conn->read_time);
+ read_rate=_conn->read_rate;
+ read_delta_ms=OP_MAX(read_delta_ms,1);
+ read_rate+=read_delta_bytes*1000/read_delta_ms-read_rate+4>>3;
+ *&_conn->read_time=*&read_time;
+ _conn->read_bytes=0;
+ _conn->read_rate=read_rate;
+}
+
+/*Tries to read from the given connection.
+ [out] _buf: Returns the data read.
+ _buf_size: The size of the buffer.
+ _blocking: Whether or not to block until some data is retrieved.
+ Return: A positive number of bytes read on success.
+ 0: The read would block, or the connection was closed.
+ OP_EREAD: There was a fatal read error.*/
+static int op_http_conn_read(OpusHTTPConn *_conn,
+ char *_buf,int _buf_size,int _blocking){
+ struct pollfd fd;
+ SSL *ssl_conn;
+ int nread;
+ int nread_unblocked;
+ fd.fd=_conn->fd;
+ ssl_conn=_conn->ssl_conn;
+ nread=nread_unblocked=0;
+ /*RFC 2818 says "client implementations MUST treat any premature closes as
+ errors and the data received as potentially truncated," so we make very
+ sure to report read errors upwards.*/
+ do{
+ int err;
+ if(ssl_conn!=NULL){
+ int ret;
+ ret=SSL_read(ssl_conn,_buf+nread,_buf_size-nread);
+ OP_ASSERT(ret<=_buf_size-nread);
+ if(ret>0){
+ /*Read some data.
+ Keep going to see if there's more.*/
+ nread+=ret;
+ nread_unblocked+=ret;
+ continue;
+ }
+ /*If we already read some data, return it right now.*/
+ if(nread>0)break;
+ err=SSL_get_error(ssl_conn,ret);
+ if(ret==0){
+ /*Connection close.
+ Check for a clean shutdown to prevent truncation attacks.
+ This check always succeeds for SSLv2, as it has no "close notify"
+ message and thus can't verify an orderly shutdown.*/
+ return err==SSL_ERROR_ZERO_RETURN?0:OP_EREAD;
+ }
+ if(err==SSL_ERROR_WANT_READ)fd.events=POLLIN;
+ /*Yes, renegotiations can cause SSL_read() to block for writing.*/
+ else if(err==SSL_ERROR_WANT_WRITE)fd.events=POLLOUT;
+ /*Some other error.*/
+ else return OP_EREAD;
+ }
+ else{
+ ssize_t ret;
+ op_reset_errno();
+ ret=recv(fd.fd,_buf+nread,_buf_size-nread,0);
+ OP_ASSERT(ret<=_buf_size-nread);
+ if(ret>0){
+ /*Read some data.
+ Keep going to see if there's more.*/
+ nread+=ret;
+ nread_unblocked+=ret;
+ continue;
+ }
+ /*If we already read some data or the connection was closed, return
+ right now.*/
+ if(ret==0||nread>0)break;
+ err=op_errno();
+ if(err!=EAGAIN&&err!=EWOULDBLOCK)return OP_EREAD;
+ fd.events=POLLIN;
+ }
+ _conn->read_bytes+=nread_unblocked;
+ op_http_conn_read_rate_update(_conn);
+ nread_unblocked=0;
+ if(!_blocking)break;
+ /*Need to wait to get any data at all.*/
+ if(poll(&fd,1,OP_POLL_TIMEOUT_MS)<=0)return OP_EREAD;
+ }
+ while(nread<_buf_size);
+ _conn->read_bytes+=nread_unblocked;
+ return nread;
+}
+
+/*Tries to look at the pending data for a connection without consuming it.
+ [out] _buf: Returns the data at which we're peeking.
+ _buf_size: The size of the buffer.*/
+static int op_http_conn_peek(OpusHTTPConn *_conn,char *_buf,int _buf_size){
+ struct pollfd fd;
+ SSL *ssl_conn;
+ int ret;
+ fd.fd=_conn->fd;
+ ssl_conn=_conn->ssl_conn;
+ for(;;){
+ int err;
+ if(ssl_conn!=NULL){
+ ret=SSL_peek(ssl_conn,_buf,_buf_size);
+ /*Either saw some data or the connection was closed.*/
+ if(ret>=0)return ret;
+ err=SSL_get_error(ssl_conn,ret);
+ if(err==SSL_ERROR_WANT_READ)fd.events=POLLIN;
+ /*Yes, renegotiations can cause SSL_peek() to block for writing.*/
+ else if(err==SSL_ERROR_WANT_WRITE)fd.events=POLLOUT;
+ else return 0;
+ }
+ else{
+ op_reset_errno();
+ ret=(int)recv(fd.fd,_buf,_buf_size,MSG_PEEK);
+ /*Either saw some data or the connection was closed.*/
+ if(ret>=0)return ret;
+ err=op_errno();
+ if(err!=EAGAIN&&err!=EWOULDBLOCK)return 0;
+ fd.events=POLLIN;
+ }
+ /*Need to wait to get any data at all.*/
+ if(poll(&fd,1,OP_POLL_TIMEOUT_MS)<=0)return 0;
+ }
+}
+
+/*When parsing response headers, RFC 2616 mandates that all lines end in CR LF.
+ However, even in the year 2012, I have seen broken servers use just a LF.
+ This is the evil that Postel's advice from RFC 761 breeds.*/
+
+/*Reads the entirety of a response to an HTTP request into the response buffer.
+ Actual parsing and validation is done later.
+ Return: The number of bytes in the response on success, OP_EREAD if the
+ connection was closed before reading any data, or another negative
+ value on any other error.*/
+static int op_http_conn_read_response(OpusHTTPConn *_conn,
+ OpusStringBuf *_response){
+ int ret;
+ _response->nbuf=0;
+ ret=op_sb_ensure_capacity(_response,OP_RESPONSE_SIZE_MIN);
+ if(OP_UNLIKELY(ret<0))return ret;
+ for(;;){
+ char *buf;
+ int size;
+ int capacity;
+ int read_limit;
+ int terminated;
+ size=_response->nbuf;
+ capacity=_response->cbuf-1;
+ if(OP_UNLIKELY(size>=capacity)){
+ ret=op_sb_grow(_response,OP_RESPONSE_SIZE_MAX);
+ if(OP_UNLIKELY(ret<0))return ret;
+ capacity=_response->cbuf-1;
+ /*The response was too large.
+ This prevents a bad server from running us out of memory.*/
+ if(OP_UNLIKELY(size>=capacity))return OP_EIMPL;
+ }
+ buf=_response->buf;
+ ret=op_http_conn_peek(_conn,buf+size,capacity-size);
+ if(OP_UNLIKELY(ret<=0))return size<=0?OP_EREAD:OP_FALSE;
+ /*We read some data.*/
+ /*Make sure the starting characters are "HTTP".
+ Otherwise we could wind up waiting forever for a response from
+ something that is not an HTTP server.*/
+ if(size<4&&op_strncasecmp(buf,"HTTP",OP_MIN(size+ret,4))!=0){
+ return OP_FALSE;
+ }
+ /*How far can we read without passing the "\r\n\r\n" terminator?*/
+ buf[size+ret]='\0';
+ terminated=0;
+ for(read_limit=OP_MAX(size-3,0);read_limit<size+ret;read_limit++){
+ /*We don't look for the leading '\r' thanks to broken servers.*/
+ if(buf[read_limit]=='\n'){
+ if(buf[read_limit+1]=='\r'&&OP_LIKELY(buf[read_limit+2]=='\n')){
+ terminated=3;
+ break;
+ }
+ /*This case is for broken servers.*/
+ else if(OP_UNLIKELY(buf[read_limit+1]=='\n')){
+ terminated=2;
+ break;
+ }
+ }
+ }
+ read_limit+=terminated;
+ OP_ASSERT(size<=read_limit);
+ OP_ASSERT(read_limit<=size+ret);
+ /*Actually consume that data.*/
+ ret=op_http_conn_read(_conn,buf+size,read_limit-size,1);
+ if(OP_UNLIKELY(ret<=0))return OP_FALSE;
+ size+=ret;
+ buf[size]='\0';
+ _response->nbuf=size;
+ /*We found the terminator and read all the data up to and including it.*/
+ if(terminated&&OP_LIKELY(size>=read_limit))return size;
+ }
+ return OP_EIMPL;
+}
+
+# define OP_HTTP_DIGIT "0123456789"
+
+/*The Reason-Phrase is not allowed to contain control characters, except
+ horizontal tab (HT: \011).*/
+# define OP_HTTP_CREASON_PHRASE \
+ "\001\002\003\004\005\006\007\010\012\013\014\015\016\017\020\021" \
+ "\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177"
+
+# define OP_HTTP_CTLS \
+ "\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020" \
+ "\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037\177"
+
+/*This also includes '\t', but we get that from OP_HTTP_CTLS.*/
+# define OP_HTTP_SEPARATORS " \"(),/:;<=>?@[\\]{}"
+
+/*TEXT can also include LWS, but that has structure, so we parse it
+ separately.*/
+# define OP_HTTP_CTOKEN OP_HTTP_CTLS OP_HTTP_SEPARATORS
+
+/*Return: The amount of linear white space (LWS) at the start of _s.*/
+static int op_http_lwsspn(const char *_s){
+ int i;
+ for(i=0;;){
+ if(_s[0]=='\r'&&_s[1]=='\n'&&(_s[2]=='\t'||_s[2]==' '))i+=3;
+ /*This case is for broken servers.*/
+ else if(_s[0]=='\n'&&(_s[1]=='\t'||_s[1]==' '))i+=2;
+ else if(_s[i]=='\t'||_s[i]==' ')i++;
+ else return i;
+ }
+}
+
+static char *op_http_parse_status_line(int *_v1_1_compat,
+ char **_status_code,char *_response){
+ char *next;
+ char *status_code;
+ int v1_1_compat;
+ size_t d;
+ /*RFC 2616 Section 6.1 does not say that the tokens in the Status-Line cannot
+ be separated by optional LWS, but since it specifically calls out where
+ spaces are to be placed and that CR and LF are not allowed except at the
+ end, I am assuming this to be true.*/
+ /*We already validated that this starts with "HTTP"*/
+ OP_ASSERT(op_strncasecmp(_response,"HTTP",4)==0);
+ next=_response+4;
+ if(OP_UNLIKELY(*next++!='/'))return NULL;
+ d=strspn(next,OP_HTTP_DIGIT);
+ /*"Leading zeros MUST be ignored by recipients."*/
+ while(*next=='0'){
+ next++;
+ OP_ASSERT(d>0);
+ d--;
+ }
+ /*We only support version 1.x*/
+ if(OP_UNLIKELY(d!=1)||OP_UNLIKELY(*next++!='1'))return NULL;
+ if(OP_UNLIKELY(*next++!='.'))return NULL;
+ d=strspn(next,OP_HTTP_DIGIT);
+ if(OP_UNLIKELY(d<=0))return NULL;
+ /*"Leading zeros MUST be ignored by recipients."*/
+ while(*next=='0'){
+ next++;
+ OP_ASSERT(d>0);
+ d--;
+ }
+ /*We don't need to parse the version number.
+ Any non-zero digit means it's greater than 1.*/
+ v1_1_compat=d>0;
+ next+=d;
+ if(OP_UNLIKELY(*next++!=' '))return NULL;
+ status_code=next;
+ d=strspn(next,OP_HTTP_DIGIT);
+ if(OP_UNLIKELY(d!=3))return NULL;
+ next+=d;
+ /*The Reason-Phrase can be empty, but the space must be here.*/
+ if(OP_UNLIKELY(*next++!=' '))return NULL;
+ next+=strcspn(next,OP_HTTP_CREASON_PHRASE);
+ /*We are not mandating this be present thanks to broken servers.*/
+ if(OP_LIKELY(*next=='\r'))next++;
+ if(OP_UNLIKELY(*next++!='\n'))return NULL;
+ if(_v1_1_compat!=NULL)*_v1_1_compat=v1_1_compat;
+ *_status_code=status_code;
+ return next;
+}
+
+/*Get the next response header.
+ [out] _header: The header token, NUL-terminated, with leading and trailing
+ whitespace stripped, and converted to lower case (to simplify
+ case-insensitive comparisons), or NULL if there are no more
+ response headers.
+ [out] _cdr: The remaining contents of the header, excluding the initial
+ colon (':') and the terminating CRLF ("\r\n"),
+ NUL-terminated, and with leading and trailing whitespace
+ stripped, or NULL if there are no more response headers.
+ [inout] _s: On input, this points to the start of the current line of the
+ response headers.
+ On output, it points to the start of the first line following
+ this header, or NULL if there are no more response headers.
+ Return: 0 on success, or a negative value on failure.*/
+static int op_http_get_next_header(char **_header,char **_cdr,char **_s){
+ char *header;
+ char *header_end;
+ char *cdr;
+ char *cdr_end;
+ char *next;
+ size_t d;
+ next=*_s;
+ /*The second case is for broken servers.*/
+ if(next[0]=='\r'&&next[1]=='\n'||OP_UNLIKELY(next[0]=='\n')){
+ /*No more headers.*/
+ *_header=NULL;
+ *_cdr=NULL;
+ *_s=NULL;
+ return 0;
+ }
+ header=next+op_http_lwsspn(next);
+ d=strcspn(header,OP_HTTP_CTOKEN);
+ if(OP_UNLIKELY(d<=0))return OP_FALSE;
+ header_end=header+d;
+ next=header_end+op_http_lwsspn(header_end);
+ if(OP_UNLIKELY(*next++!=':'))return OP_FALSE;
+ next+=op_http_lwsspn(next);
+ cdr=next;
+ do{
+ cdr_end=next+strcspn(next,OP_HTTP_CTLS);
+ next=cdr_end+op_http_lwsspn(cdr_end);
+ }
+ while(next>cdr_end);
+ /*We are not mandating this be present thanks to broken servers.*/
+ if(OP_LIKELY(*next=='\r'))next++;
+ if(OP_UNLIKELY(*next++!='\n'))return OP_FALSE;
+ *header_end='\0';
+ *cdr_end='\0';
+ /*Field names are case-insensitive.*/
+ op_string_tolower(header);
+ *_header=header;
+ *_cdr=cdr;
+ *_s=next;
+ return 0;
+}
+
+static opus_int64 op_http_parse_nonnegative_int64(const char **_next,
+ const char *_cdr){
+ const char *next;
+ opus_int64 ret;
+ int i;
+ next=_cdr+strspn(_cdr,OP_HTTP_DIGIT);
+ *_next=next;
+ if(OP_UNLIKELY(next<=_cdr))return OP_FALSE;
+ while(*_cdr=='0')_cdr++;
+ if(OP_UNLIKELY(next-_cdr>19))return OP_EIMPL;
+ ret=0;
+ for(i=0;i<next-_cdr;i++){
+ int digit;
+ digit=_cdr[i]-'0';
+ /*Check for overflow.*/
+ if(OP_UNLIKELY(ret>(OP_INT64_MAX-9)/10+(digit<=7)))return OP_EIMPL;
+ ret=ret*10+digit;
+ }
+ return ret;
+}
+
+static opus_int64 op_http_parse_content_length(const char *_cdr){
+ const char *next;
+ opus_int64 content_length;
+ content_length=op_http_parse_nonnegative_int64(&next,_cdr);
+ if(OP_UNLIKELY(*next!='\0'))return OP_FALSE;
+ return content_length;
+}
+
+static int op_http_parse_content_range(opus_int64 *_first,opus_int64 *_last,
+ opus_int64 *_length,const char *_cdr){
+ opus_int64 first;
+ opus_int64 last;
+ opus_int64 length;
+ size_t d;
+ if(OP_UNLIKELY(op_strncasecmp(_cdr,"bytes",5)!=0))return OP_FALSE;
+ _cdr+=5;
+ d=op_http_lwsspn(_cdr);
+ if(OP_UNLIKELY(d<=0))return OP_FALSE;
+ _cdr+=d;
+ if(*_cdr!='*'){
+ first=op_http_parse_nonnegative_int64(&_cdr,_cdr);
+ if(OP_UNLIKELY(first<0))return (int)first;
+ _cdr+=op_http_lwsspn(_cdr);
+ if(*_cdr++!='-')return OP_FALSE;
+ _cdr+=op_http_lwsspn(_cdr);
+ last=op_http_parse_nonnegative_int64(&_cdr,_cdr);
+ if(OP_UNLIKELY(last<0))return (int)last;
+ _cdr+=op_http_lwsspn(_cdr);
+ }
+ else{
+ /*This is for a 416 response (Requested range not satisfiable).*/
+ first=last=-1;
+ _cdr++;
+ }
+ if(OP_UNLIKELY(*_cdr++!='/'))return OP_FALSE;
+ if(*_cdr!='*'){
+ length=op_http_parse_nonnegative_int64(&_cdr,_cdr);
+ if(OP_UNLIKELY(length<0))return (int)length;
+ }
+ else{
+ /*The total length is unspecified.*/
+ _cdr++;
+ length=-1;
+ }
+ if(OP_UNLIKELY(*_cdr!='\0'))return OP_FALSE;
+ if(OP_UNLIKELY(last<first))return OP_FALSE;
+ if(length>=0&&OP_UNLIKELY(last>=length))return OP_FALSE;
+ *_first=first;
+ *_last=last;
+ *_length=length;
+ return 0;
+}
+
+/*Parse the Connection response header and look for a "close" token.
+ Return: 1 if a "close" token is found, 0 if it's not found, and a negative
+ value on error.*/
+static int op_http_parse_connection(char *_cdr){
+ size_t d;
+ int ret;
+ ret=0;
+ for(;;){
+ d=strcspn(_cdr,OP_HTTP_CTOKEN);
+ if(OP_UNLIKELY(d<=0))return OP_FALSE;
+ if(op_strncasecmp(_cdr,"close",(int)d)==0)ret=1;
+ /*We're supposed to strip and ignore any headers mentioned in the
+ Connection header if this response is from an HTTP/1.0 server (to
+ work around forwarding of hop-by-hop headers by old proxies), but the
+ only hop-by-hop header we look at is Connection itself.
+ Everything else is a well-defined end-to-end header, and going back and
+ undoing the things we did based on already-examined headers would be
+ hard (since we only scan them once, in a destructive manner).
+ Therefore we just ignore all the other tokens.*/
+ _cdr+=d;
+ d=op_http_lwsspn(_cdr);
+ if(d<=0)break;
+ _cdr+=d;
+ }
+ return OP_UNLIKELY(*_cdr!='\0')?OP_FALSE:ret;
+}
+
+typedef int (*op_ssl_step_func)(SSL *_ssl_conn);
+
+/*Try to run an SSL function to completion (blocking if necessary).*/
+static int op_do_ssl_step(SSL *_ssl_conn,op_sock _fd,op_ssl_step_func _step){
+ struct pollfd fd;
+ fd.fd=_fd;
+ for(;;){
+ int ret;
+ int err;
+ ret=(*_step)(_ssl_conn);
+ if(ret>=0)return ret;
+ err=SSL_get_error(_ssl_conn,ret);
+ if(err==SSL_ERROR_WANT_READ)fd.events=POLLIN;
+ else if(err==SSL_ERROR_WANT_WRITE)fd.events=POLLOUT;
+ else return OP_FALSE;
+ if(poll(&fd,1,OP_POLL_TIMEOUT_MS)<=0)return OP_FALSE;
+ }
+}
+
+/*Implement a BIO type that just indicates every operation should be retried.
+ We use this when initializing an SSL connection via a proxy to allow the
+ initial handshake to proceed all the way up to the first read attempt, and
+ then return.
+ This allows the TLS client hello message to be pipelined with the HTTP
+ CONNECT request.*/
+
+static int op_bio_retry_write(BIO *_b,const char *_buf,int _num){
+ (void)_buf;
+ (void)_num;
+ BIO_clear_retry_flags(_b);
+ BIO_set_retry_write(_b);
+ return -1;
+}
+
+static int op_bio_retry_read(BIO *_b,char *_buf,int _num){
+ (void)_buf;
+ (void)_num;
+ BIO_clear_retry_flags(_b);
+ BIO_set_retry_read(_b);
+ return -1;
+}
+
+static int op_bio_retry_puts(BIO *_b,const char *_str){
+ return op_bio_retry_write(_b,_str,0);
+}
+
+static long op_bio_retry_ctrl(BIO *_b,int _cmd,long _num,void *_ptr){
+ long ret;
+ (void)_b;
+ (void)_num;
+ (void)_ptr;
+ ret=0;
+ switch(_cmd){
+ case BIO_CTRL_RESET:
+ case BIO_C_RESET_READ_REQUEST:{
+ BIO_clear_retry_flags(_b);
+ /*Fall through.*/
+ }
+ case BIO_CTRL_EOF:
+ case BIO_CTRL_SET:
+ case BIO_CTRL_SET_CLOSE:
+ case BIO_CTRL_FLUSH:
+ case BIO_CTRL_DUP:{
+ ret=1;
+ }break;
+ }
+ return ret;
+}
+
+static int op_bio_retry_new(BIO *_b){
+ _b->init=1;
+ _b->num=0;
+ _b->ptr=NULL;
+ return 1;
+}
+
+static int op_bio_retry_free(BIO *_b){
+ return _b!=NULL;
+}
+
+/*This is not const because OpenSSL doesn't allow it, even though it won't
+ write to it.*/
+static BIO_METHOD op_bio_retry_method={
+ BIO_TYPE_NULL,
+ "retry",
+ op_bio_retry_write,
+ op_bio_retry_read,
+ op_bio_retry_puts,
+ NULL,
+ op_bio_retry_ctrl,
+ op_bio_retry_new,
+ op_bio_retry_free,
+ NULL
+};
+
+/*Establish a CONNECT tunnel and pipeline the start of the TLS handshake for
+ proxying https URL requests.*/
+static int op_http_conn_establish_tunnel(OpusHTTPStream *_stream,
+ OpusHTTPConn *_conn,op_sock _fd,SSL *_ssl_conn,BIO *_ssl_bio){
+ BIO *retry_bio;
+ char *status_code;
+ char *next;
+ int ret;
+ _conn->ssl_conn=NULL;
+ _conn->fd=_fd;
+ OP_ASSERT(_stream->proxy_connect.nbuf>0);
+ ret=op_http_conn_write_fully(_conn,
+ _stream->proxy_connect.buf,_stream->proxy_connect.nbuf);
+ if(OP_UNLIKELY(ret<0))return ret;
+ retry_bio=BIO_new(&op_bio_retry_method);
+ if(OP_UNLIKELY(retry_bio==NULL))return OP_EFAULT;
+ SSL_set_bio(_ssl_conn,retry_bio,_ssl_bio);
+ SSL_set_connect_state(_ssl_conn);
+ /*This shouldn't succeed, since we can't read yet.*/
+ OP_ALWAYS_TRUE(SSL_connect(_ssl_conn)<0);
+ SSL_set_bio(_ssl_conn,_ssl_bio,_ssl_bio);
+ /*Only now do we disable write coalescing, to allow the CONNECT
+ request and the start of the TLS handshake to be combined.*/
+ op_sock_set_tcp_nodelay(_fd,1);
+ ret=op_http_conn_read_response(_conn,&_stream->response);
+ if(OP_UNLIKELY(ret<0))return ret;
+ next=op_http_parse_status_line(NULL,&status_code,_stream->response.buf);
+ /*According to RFC 2817, "Any successful (2xx) response to a
+ CONNECT request indicates that the proxy has established a
+ connection to the requested host and port.*/
+ if(OP_UNLIKELY(next==NULL)||OP_UNLIKELY(status_code[0]!='2'))return OP_FALSE;
+ return 0;
+}
+
+/*Match a host name against a host with a possible wildcard pattern according
+ to the rules of RFC 6125 Section 6.4.3.
+ Return: 0 if the pattern doesn't match, and a non-zero value if it does.*/
+static int op_http_hostname_match(const char *_host,size_t _host_len,
+ ASN1_STRING *_pattern){
+ const char *pattern;
+ size_t host_label_len;
+ size_t host_suffix_len;
+ size_t pattern_len;
+ size_t pattern_label_len;
+ size_t pattern_prefix_len;
+ size_t pattern_suffix_len;
+ pattern=(const char *)ASN1_STRING_data(_pattern);
+ pattern_len=strlen(pattern);
+ /*Check the pattern for embedded NULs.*/
+ if(OP_UNLIKELY(pattern_len!=(size_t)ASN1_STRING_length(_pattern)))return 0;
+ pattern_label_len=strcspn(pattern,".");
+ OP_ASSERT(pattern_label_len<=pattern_len);
+ pattern_prefix_len=strcspn(pattern,"*");
+ if(pattern_prefix_len>=pattern_label_len){
+ /*"The client SHOULD NOT attempt to match a presented identifier in which
+ the wildcard character comprises a label other than the left-most label
+ (e.g., do not match bar.*.example.net)." [RFC 6125 Section 6.4.3]*/
+ if(pattern_prefix_len<pattern_len)return 0;
+ /*If the pattern does not contain a wildcard in the first element, do an
+ exact match.
+ Don't use the system strcasecmp here, as that uses the locale and
+ RFC 4343 makes clear that DNS's case-insensitivity only applies to
+ the ASCII range.*/
+ return _host_len==pattern_len&&op_strncasecmp(_host,pattern,_host_len)==0;
+ }
+ /*"However, the client SHOULD NOT attempt to match a presented identifier
+ where the wildcard character is embedded within an A-label or U-label of
+ an internationalized domain name." [RFC 6125 Section 6.4.3]*/
+ if(op_strncasecmp(pattern,"xn--",4)==0)return 0;
+ host_label_len=strcspn(_host,".");
+ /*Make sure the host has at least two dots, to prevent the wildcard match
+ from being ridiculously wide.
+ We should have already checked to ensure it had at least one.*/
+ if(OP_UNLIKELY(_host[host_label_len]!='.')
+ ||strchr(_host+host_label_len+1,'.')==NULL){
+ return 0;
+ }
+ OP_ASSERT(host_label_len<_host_len);
+ /*"If the wildcard character is the only character of the left-most label in
+ the presented identifier, the client SHOULD NOT compare against anything
+ but the left-most label of the reference identifier (e.g., *.example.com
+ would match foo.example.com but not bar.foo.example.com)." [RFC 6125
+ Section 6.4.3]
+ This is really confusingly worded, as we check this by actually comparing
+ the rest of the pattern for an exact match.
+ We also use the fact that the wildcard must match at least one character,
+ so the left-most label of the hostname must be at least as large as the
+ left-most label of the pattern.*/
+ if(host_label_len<pattern_label_len)return 0;
+ OP_ASSERT(pattern[pattern_prefix_len]=='*');
+ /*"The client MAY match a presented identifier in which the wildcard
+ character is not the only character of the label (e.g., baz*.example.net
+ and *baz.example.net and b*z.example.net would be taken to match
+ baz1.example.net and foobaz.example.net and buzz.example.net,
+ respectively)." [RFC 6125 Section 6.4.3]*/
+ pattern_suffix_len=pattern_len-pattern_prefix_len-1;
+ host_suffix_len=_host_len-host_label_len
+ +pattern_label_len-pattern_prefix_len-1;
+ return pattern_suffix_len==host_suffix_len
+ &&op_strncasecmp(_host,pattern,pattern_prefix_len)==0
+ &&op_strncasecmp(_host+_host_len-host_suffix_len,
+ pattern+pattern_prefix_len+1,host_suffix_len)==0;
+}
+
+/*Convert a host to a numeric address, if possible.
+ Return: A struct addrinfo containing the address, if it was numeric, and NULL
+ otherise.*/
+static struct addrinfo *op_inet_pton(const char *_host){
+ struct addrinfo *addrs;
+ struct addrinfo hints;
+ memset(&hints,0,sizeof(hints));
+ hints.ai_socktype=SOCK_STREAM;
+ hints.ai_flags=AI_NUMERICHOST;
+ if(!getaddrinfo(_host,NULL,&hints,&addrs))return addrs;
+ return NULL;
+}
+
+/*Verify the server's hostname matches the certificate they presented using
+ the procedure from Section 6 of RFC 6125.
+ Return: 0 if the certificate doesn't match, and a non-zero value if it does.*/
+static int op_http_verify_hostname(OpusHTTPStream *_stream,SSL *_ssl_conn){
+ X509 *peer_cert;
+ STACK_OF(GENERAL_NAME) *san_names;
+ char *host;
+ size_t host_len;
+ int ret;
+ host=_stream->url.host;
+ host_len=strlen(host);
+ peer_cert=SSL_get_peer_certificate(_ssl_conn);
+ /*We set VERIFY_PEER, so we shouldn't get here without a certificate.*/
+ if(OP_UNLIKELY(peer_cert==NULL))return 0;
+ ret=0;
+ OP_ASSERT(host_len<INT_MAX);
+ /*RFC 2818 says (after correcting for Eratta 1077): "If a subjectAltName
+ extension of type dNSName is present, that MUST be used as the identity.
+ Otherwise, the (most specific) Common Name field in the Subject field of
+ the certificate MUST be used.
+ Although the use of the Common Name is existing practice, it is deprecated
+ and Certification Authorities are encouraged to use the dNSName
+ instead."
+ "Matching is performed using the matching rules specified by RFC 2459.
+ If more than one identity of a given type is present in the certificate
+ (e.g., more than one dNSName name), a match in any one of the set is
+ considered acceptable.
+ Names may contain the wildcard character * which is condered to match any
+ single domain name component or component fragment.
+ E.g., *.a.com matches foo.a.com but not bar.foo.a.com.
+ f*.com matches foo.com but not bar.com."
+ "In some cases, the URI is specified as an IP address rather than a
+ hostname.
+ In this case, the iPAddress subjectAltName must be present in the
+ certificate and must exactly match the IP in the URI."*/
+ san_names=X509_get_ext_d2i(peer_cert,NID_subject_alt_name,NULL,NULL);
+ if(san_names!=NULL){
+ struct addrinfo *addr;
+ unsigned char *ip;
+ int ip_len;
+ int nsan_names;
+ int sni;
+ /*Check to see if the host was specified as a simple IP address.*/
+ addr=op_inet_pton(host);
+ ip=NULL;
+ ip_len=0;
+ if(addr!=NULL){
+ switch(addr->ai_family){
+ case AF_INET:{
+ struct sockaddr_in *s;
+ s=(struct sockaddr_in *)addr->ai_addr;
+ OP_ASSERT(addr->ai_addrlen>=sizeof(*s));
+ ip=(unsigned char *)&s->sin_addr;
+ ip_len=sizeof(s->sin_addr);
+ }break;
+ case AF_INET6:{
+ struct sockaddr_in6 *s;
+ s=(struct sockaddr_in6 *)addr->ai_addr;
+ OP_ASSERT(addr->ai_addrlen>=sizeof(*s));
+ ip=(unsigned char *)&s->sin6_addr;
+ ip_len=sizeof(s->sin6_addr);
+ }break;
+ }
+ }
+ /*We can only verify fully-qualified domain names.
+ To quote RFC 6125: "The extracted data MUST include only information that
+ can be securely parsed out of the inputs (e.g., parsing the fully
+ qualified DNS domain name out of the "host" component (or its
+ equivalent) of a URI or deriving the application service type from the
+ scheme of a URI) ..."
+ We don't have a way to check (without relying on DNS records, which might
+ be subverted) if this address is fully-qualified.
+ This is particularly problematic when using a CONNECT tunnel, as it is
+ the server that does DNS lookup, not us.
+ However, we are certain that if the hostname has no '.', it is definitely
+ not a fully-qualified domain name (with the exception of crazy TLDs that
+ actually resolve, like "uz", but I am willing to ignore those).
+ RFC 1535 says "...in any event where a '.' exists in a specified name it
+ should be assumed to be a fully qualified domain name (FQDN) and SHOULD
+ be tried as a rooted name first."
+ That doesn't give us any security guarantees, of course (a subverted DNS
+ could fail the original query and our resolver might still retry with a
+ local domain appended).
+ If we don't have a FQDN, just set the number of names to 0, so we'll fail
+ and clean up any resources we allocated.*/
+ if(ip==NULL&&strchr(host,'.')==NULL)nsan_names=0;
+ /*RFC 2459 says there MUST be at least one, but we don't depend on it.*/
+ else nsan_names=sk_GENERAL_NAME_num(san_names);
+ for(sni=0;sni<nsan_names;sni++){
+ const GENERAL_NAME *name;
+ name=sk_GENERAL_NAME_value(san_names,sni);
+ if(ip==NULL){
+ if(name->type==GEN_DNS
+ &&op_http_hostname_match(host,host_len,name->d.dNSName)){
+ ret=1;
+ break;
+ }
+ }
+ else if(name->type==GEN_IPADD){
+ unsigned char *cert_ip;
+ /*If we do have an IP address, compare it directly.
+ RFC 6125: "When the reference identity is an IP address, the identity
+ MUST be converted to the 'network byte order' octet string
+ representation.
+ For IP Version 4, as specified in RFC 791, the octet string will
+ contain exactly four octets.
+ For IP Version 6, as specified in RFC 2460, the octet string will
+ contain exactly sixteen octets.
+ This octet string is then compared against subjectAltName values of
+ type iPAddress.
+ A match occurs if the reference identity octet string and the value
+ octet strings are identical."*/
+ cert_ip=ASN1_STRING_data(name->d.iPAddress);
+ if(ip_len==ASN1_STRING_length(name->d.iPAddress)
+ &&memcmp(ip,cert_ip,ip_len)==0){
+ ret=1;
+ break;
+ }
+ }
+ }
+ sk_GENERAL_NAME_pop_free(san_names,GENERAL_NAME_free);
+ if(addr!=NULL)freeaddrinfo(addr);
+ }
+ /*Do the same FQDN check we did above.
+ We don't do this once in advance for both cases, because in the
+ subjectAltName case we might have an IPv6 address without a dot.*/
+ else if(strchr(host,'.')!=NULL){
+ int last_cn_loc;
+ int cn_loc;
+ /*If there is no subjectAltName, match against commonName.
+ RFC 6125 says that at least one significant CA is known to issue certs
+ with multiple CNs, although it SHOULD NOT.
+ It also says: "The server's identity may also be verified by comparing
+ the reference identity to the Common Name (CN) value in the last
+ Relative Distinguished Name (RDN) of the subject field of the server's
+ certificate (where "last" refers to the DER-encoded order...)."
+ So find the last one and check it.*/
+ cn_loc=-1;
+ do{
+ last_cn_loc=cn_loc;
+ cn_loc=X509_NAME_get_index_by_NID(X509_get_subject_name(peer_cert),
+ NID_commonName,last_cn_loc);
+ }
+ while(cn_loc>=0);
+ ret=last_cn_loc>=0
+ &&op_http_hostname_match(host,host_len,
+ X509_NAME_ENTRY_get_data(
+ X509_NAME_get_entry(X509_get_subject_name(peer_cert),last_cn_loc)));
+ }
+ X509_free(peer_cert);
+ return ret;
+}
+
+/*Perform the TLS handshake on a new connection.*/
+static int op_http_conn_start_tls(OpusHTTPStream *_stream,OpusHTTPConn *_conn,
+ op_sock _fd,SSL *_ssl_conn){
+ SSL_SESSION *ssl_session;
+ BIO *ssl_bio;
+ int skip_certificate_check;
+ int ret;
+ ssl_bio=BIO_new_socket(_fd,BIO_NOCLOSE);
+ if(OP_LIKELY(ssl_bio==NULL))return OP_FALSE;
+# if !defined(OPENSSL_NO_TLSEXT)
+ /*Support for RFC 6066 Server Name Indication.*/
+ SSL_set_tlsext_host_name(_ssl_conn,_stream->url.host);
+# endif
+ /*Resume a previous session if available.*/
+ if(_stream->ssl_session!=NULL){
+ SSL_set_session(_ssl_conn,_stream->ssl_session);
+ }
+ /*If we're proxying, establish the CONNECT tunnel.*/
+ if(_stream->proxy_connect.nbuf>0){
+ ret=op_http_conn_establish_tunnel(_stream,_conn,
+ _fd,_ssl_conn,ssl_bio);
+ if(OP_UNLIKELY(ret<0))return ret;
+ }
+ else{
+ /*Otherwise, just use this socket directly.*/
+ op_sock_set_tcp_nodelay(_fd,1);
+ SSL_set_bio(_ssl_conn,ssl_bio,ssl_bio);
+ SSL_set_connect_state(_ssl_conn);
+ }
+ ret=op_do_ssl_step(_ssl_conn,_fd,SSL_connect);
+ if(OP_UNLIKELY(ret<=0))return OP_FALSE;
+ ssl_session=_stream->ssl_session;
+ skip_certificate_check=_stream->skip_certificate_check;
+ if(ssl_session==NULL||!skip_certificate_check){
+ ret=op_do_ssl_step(_ssl_conn,_fd,SSL_do_handshake);
+ if(OP_UNLIKELY(ret<=0))return OP_FALSE;
+ /*OpenSSL does not do hostname verification, despite the fact that we just
+ passed it the hostname above in the call to SSL_set_tlsext_host_name(),
+ because they are morons.
+ Do it for them.*/
+ if(!skip_certificate_check&&!op_http_verify_hostname(_stream,_ssl_conn)){
+ return OP_FALSE;
+ }
+ if(ssl_session==NULL){
+ /*Save the session for later resumption.*/
+ _stream->ssl_session=SSL_get1_session(_ssl_conn);
+ }
+ }
+ _conn->ssl_conn=_ssl_conn;
+ _conn->fd=_fd;
+ _conn->nrequests_left=OP_PIPELINE_MAX_REQUESTS;
+ return 0;
+}
+
+/*Try to start a connection to the next address in the given list of a given
+ type.
+ _fd: The socket to connect with.
+ [inout] _addr: A pointer to the list of addresses.
+ This will be advanced to the first one that matches the given
+ address family (possibly the current one).
+ _ai_family: The address family to connect to.
+ Return: 1 If the connection was successful.
+ 0 If the connection is in progress.
+ OP_FALSE If the connection failed and there were no more addresses
+ left to try.
+ *_addr will be set to NULL in this case.*/
+static int op_sock_connect_next(op_sock _fd,
+ const struct addrinfo **_addr,int _ai_family){
+ const struct addrinfo *addr;
+ int err;
+ addr=*_addr;
+ for(;;){
+ /*Move to the next address of the requested type.*/
+ for(;addr!=NULL&&addr->ai_family!=_ai_family;addr=addr->ai_next);
+ *_addr=addr;
+ /*No more: failure.*/
+ if(addr==NULL)return OP_FALSE;
+ if(connect(_fd,addr->ai_addr,addr->ai_addrlen)>=0)return 1;
+ err=op_errno();
+ /*Winsock will set WSAEWOULDBLOCK.*/
+ if(OP_LIKELY(err==EINPROGRESS||err==EWOULDBLOCK))return 0;
+ addr=addr->ai_next;
+ }
+}
+
+/*The number of address families to try connecting to simultaneously.*/
+# define OP_NPROTOS (2)
+
+static int op_http_connect_impl(OpusHTTPStream *_stream,OpusHTTPConn *_conn,
+ const struct addrinfo *_addrs,struct timeb *_start_time){
+ const struct addrinfo *addr;
+ const struct addrinfo *addrs[OP_NPROTOS];
+ struct pollfd fds[OP_NPROTOS];
+ int ai_family;
+ int nprotos;
+ int ret;
+ int pi;
+ int pj;
+ for(pi=0;pi<OP_NPROTOS;pi++)addrs[pi]=NULL;
+ /*Try connecting via both IPv4 and IPv6 simultaneously, and keep the first
+ one that succeeds.
+ Start by finding the first address from each family.
+ We order the first connection attempts in the same order the address
+ families were returned in the DNS records in accordance with RFC 6555.*/
+ for(addr=_addrs,nprotos=0;addr!=NULL&&nprotos<OP_NPROTOS;addr=addr->ai_next){
+ if(addr->ai_family==AF_INET6||addr->ai_family==AF_INET){
+ OP_ASSERT(addr->ai_addrlen<=sizeof(struct sockaddr_in6));
+ OP_ASSERT(addr->ai_addrlen<=sizeof(struct sockaddr_in));
+ /*If we've seen this address family before, skip this address for now.*/
+ for(pi=0;pi<nprotos;pi++)if(addrs[pi]->ai_family==addr->ai_family)break;
+ if(pi<nprotos)continue;
+ addrs[nprotos++]=addr;
+ }
+ }
+ /*Pop the connection off the free list and put it on the LRU list.*/
+ OP_ASSERT(_stream->free_head==_conn);
+ _stream->free_head=_conn->next;
+ _conn->next=_stream->lru_head;
+ _stream->lru_head=_conn;
+ ftime(_start_time);
+ *&_conn->read_time=*_start_time;
+ _conn->read_bytes=0;
+ _conn->read_rate=0;
+ /*Try to start a connection to each protocol.
+ RFC 6555 says it is RECOMMENDED that connection attempts be paced
+ 150...250 ms apart "to balance human factors against network load", but
+ that "stateful algorithms" (that's us) "are expected to be more
+ aggressive".
+ We are definitely more aggressive: we don't pace at all.*/
+ for(pi=0;pi<nprotos;pi++){
+ ai_family=addrs[pi]->ai_family;
+ fds[pi].fd=socket(ai_family,SOCK_STREAM,addrs[pi]->ai_protocol);
+ fds[pi].events=POLLOUT;
+ if(OP_LIKELY(fds[pi].fd!=OP_INVALID_SOCKET)){
+ if(OP_LIKELY(op_sock_set_nonblocking(fds[pi].fd,1)>=0)){
+ ret=op_sock_connect_next(fds[pi].fd,addrs+pi,ai_family);
+ if(OP_UNLIKELY(ret>0)){
+ /*It succeeded right away (technically possible), so stop.*/
+ nprotos=pi+1;
+ break;
+ }
+ /*Otherwise go on to the next protocol, and skip the clean-up below.*/
+ else if(ret==0)continue;
+ /*Tried all the addresses for this protocol.*/
+ }
+ /*Clean up the socket.*/
+ close(fds[pi].fd);
+ }
+ /*Remove this protocol from the list.*/
+ memmove(addrs+pi,addrs+pi+1,sizeof(*addrs)*(nprotos-pi-1));
+ nprotos--;
+ pi--;
+ }
+ /*Wait for one of the connections to finish.*/
+ while(pi>=nprotos&&nprotos>0&&poll(fds,nprotos,OP_POLL_TIMEOUT_MS)>0){
+ for(pi=0;pi<nprotos;pi++){
+ socklen_t errlen;
+ int err;
+ /*Still waiting...*/
+ if(!fds[pi].revents)continue;
+ errlen=sizeof(err);
+ /*Some platforms will return the pending error in &err and return 0.
+ Others will put it in errno and return -1.*/
+ ret=getsockopt(fds[pi].fd,SOL_SOCKET,SO_ERROR,&err,&errlen);
+ if(ret<0)err=op_errno();
+ /*Success!*/
+ if(err==0||err==EISCONN)break;
+ /*Move on to the next address for this protocol.*/
+ ai_family=addrs[pi]->ai_family;
+ addrs[pi]=addrs[pi]->ai_next;
+ ret=op_sock_connect_next(fds[pi].fd,addrs+pi,ai_family);
+ /*It succeeded right away, so stop.*/
+ if(ret>0)break;
+ /*Otherwise go on to the next protocol, and skip the clean-up below.*/
+ else if(ret==0)continue;
+ /*Tried all the addresses for this protocol.
+ Remove it from the list.*/
+ close(fds[pi].fd);
+ memmove(fds+pi,fds+pi+1,sizeof(*fds)*(nprotos-pi-1));
+ memmove(addrs+pi,addrs+pi+1,sizeof(*addrs)*(nprotos-pi-1));
+ nprotos--;
+ pi--;
+ }
+ }
+ /*Close all the other sockets.*/
+ for(pj=0;pj<nprotos;pj++)if(pi!=pj)close(fds[pj].fd);
+ /*If none of them succeeded, we're done.*/
+ if(pi>=nprotos)return OP_FALSE;
+ /*Save this address for future connection attempts.*/
+ if(addrs[pi]!=&_stream->addr_info){
+ memcpy(&_stream->addr_info,addrs[pi],sizeof(_stream->addr_info));
+ _stream->addr_info.ai_addr=&_stream->addr.s;
+ _stream->addr_info.ai_next=NULL;
+ memcpy(&_stream->addr,addrs[pi]->ai_addr,addrs[pi]->ai_addrlen);
+ }
+ if(OP_URL_IS_SSL(&_stream->url)){
+ SSL *ssl_conn;
+ /*Start the SSL connection.*/
+ OP_ASSERT(_stream->ssl_ctx!=NULL);
+ ssl_conn=SSL_new(_stream->ssl_ctx);
+ if(OP_LIKELY(ssl_conn!=NULL)){
+ ret=op_http_conn_start_tls(_stream,_conn,fds[pi].fd,ssl_conn);
+ if(OP_LIKELY(ret>=0))return ret;
+ SSL_free(ssl_conn);
+ }
+ close(fds[pi].fd);
+ _conn->fd=OP_INVALID_SOCKET;
+ return OP_FALSE;
+ }
+ /*Just a normal non-SSL connection.*/
+ _conn->ssl_conn=NULL;
+ _conn->fd=fds[pi].fd;
+ _conn->nrequests_left=OP_PIPELINE_MAX_REQUESTS;
+ /*Disable write coalescing.
+ We always send whole requests at once and always parse the response headers
+ before sending another one.*/
+ op_sock_set_tcp_nodelay(fds[pi].fd,1);
+ return 0;
+}
+
+static int op_http_connect(OpusHTTPStream *_stream,OpusHTTPConn *_conn,
+ const struct addrinfo *_addrs,struct timeb *_start_time){
+ struct timeb resolve_time;
+ struct addrinfo *new_addrs;
+ int ret;
+ /*Re-resolve the host if we need to (RFC 6555 says we MUST do so
+ occasionally).*/
+ new_addrs=NULL;
+ ftime(&resolve_time);
+ if(_addrs!=&_stream->addr_info||op_time_diff_ms(&resolve_time,
+ &_stream->resolve_time)>=OP_RESOLVE_CACHE_TIMEOUT_MS){
+ new_addrs=op_resolve(_stream->connect_host,_stream->connect_port);
+ if(OP_LIKELY(new_addrs!=NULL)){
+ _addrs=new_addrs;
+ *&_stream->resolve_time=*&resolve_time;
+ }
+ else if(OP_LIKELY(_addrs==NULL))return OP_FALSE;
+ }
+ ret=op_http_connect_impl(_stream,_conn,_addrs,_start_time);
+ if(new_addrs!=NULL)freeaddrinfo(new_addrs);
+ return ret;
+}
+
+# define OP_BASE64_LENGTH(_len) (((_len)+2)/3*4)
+
+static const char BASE64_TABLE[64]={
+ 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
+ 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
+ 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
+ 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
+};
+
+static char *op_base64_encode(char *_dst,const char *_src,int _len){
+ unsigned s0;
+ unsigned s1;
+ unsigned s2;
+ int ngroups;
+ int i;
+ ngroups=_len/3;
+ for(i=0;i<ngroups;i++){
+ s0=_src[3*i+0];
+ s1=_src[3*i+1];
+ s2=_src[3*i+2];
+ _dst[4*i+0]=BASE64_TABLE[s0>>2];
+ _dst[4*i+1]=BASE64_TABLE[(s0&3)<<4|s1>>4];
+ _dst[4*i+2]=BASE64_TABLE[(s1&15)<<2|s2>>6];
+ _dst[4*i+3]=BASE64_TABLE[s2&63];
+ }
+ _len-=3*i;
+ if(_len==1){
+ s0=_src[3*i+0];
+ _dst[4*i+0]=BASE64_TABLE[s0>>2];
+ _dst[4*i+1]=BASE64_TABLE[(s0&3)<<4];
+ _dst[4*i+2]='=';
+ _dst[4*i+3]='=';
+ i++;
+ }
+ else if(_len==2){
+ s0=_src[3*i+0];
+ s1=_src[3*i+1];
+ _dst[4*i+0]=BASE64_TABLE[s0>>2];
+ _dst[4*i+1]=BASE64_TABLE[(s0&3)<<4|s1>>4];
+ _dst[4*i+2]=BASE64_TABLE[(s1&15)<<2];
+ _dst[4*i+3]='=';
+ i++;
+ }
+ _dst[4*i]='\0';
+ return _dst+4*i;
+}
+
+/*Construct an HTTP authorization header using RFC 2617's Basic Authentication
+ Scheme and append it to the given string buffer.*/
+static int op_sb_append_basic_auth_header(OpusStringBuf *_sb,
+ const char *_header,const char *_user,const char *_pass){
+ int user_len;
+ int pass_len;
+ int user_pass_len;
+ int base64_len;
+ int nbuf_total;
+ int ret;
+ ret=op_sb_append_string(_sb,_header);
+ ret|=op_sb_append(_sb,": Basic ",8);
+ user_len=strlen(_user);
+ pass_len=strlen(_pass);
+ if(OP_UNLIKELY(pass_len>INT_MAX-user_len))return OP_EFAULT;
+ if(OP_UNLIKELY(user_len+pass_len>(INT_MAX>>2)*3-3))return OP_EFAULT;
+ user_pass_len=user_len+1+pass_len;
+ base64_len=OP_BASE64_LENGTH(user_pass_len);
+ /*Stick "user:pass" at the end of the buffer so we can Base64 encode it
+ in-place.*/
+ nbuf_total=_sb->nbuf;
+ if(OP_UNLIKELY(base64_len>INT_MAX-nbuf_total))return OP_EFAULT;
+ nbuf_total+=base64_len;
+ ret|=op_sb_ensure_capacity(_sb,nbuf_total);
+ if(OP_UNLIKELY(ret<0))return ret;
+ _sb->nbuf=nbuf_total-user_pass_len;
+ OP_ALWAYS_TRUE(!op_sb_append(_sb,_user,user_len));
+ OP_ALWAYS_TRUE(!op_sb_append(_sb,":",1));
+ OP_ALWAYS_TRUE(!op_sb_append(_sb,_pass,pass_len));
+ op_base64_encode(_sb->buf+nbuf_total-base64_len,
+ _sb->buf+nbuf_total-user_pass_len,user_pass_len);
+ return op_sb_append(_sb,"\r\n",2);
+}
+
+static int op_http_allow_pipelining(const char *_server){
+ /*Servers known to do bad things with pipelined requests.
+ This list is taken from Gecko's nsHttpConnection::SupportsPipelining() (in
+ netwerk/protocol/http/nsHttpConnection.cpp).*/
+ static const char *BAD_SERVERS[]={
+ "EFAServer/",
+ "Microsoft-IIS/4.",
+ "Microsoft-IIS/5.",
+ "Netscape-Enterprise/3.",
+ "Netscape-Enterprise/4.",
+ "Netscape-Enterprise/5.",
+ "Netscape-Enterprise/6.",
+ "WebLogic 3.",
+ "WebLogic 4.",
+ "WebLogic 5.",
+ "WebLogic 6.",
+ "Winstone Servlet Engine v0."
+ };
+# define NBAD_SERVERS ((int)(sizeof(BAD_SERVERS)/sizeof(*BAD_SERVERS)))
+ if(*_server>='E'&&*_server<='W'){
+ int si;
+ for(si=0;si<NBAD_SERVERS;si++){
+ if(strncmp(_server,BAD_SERVERS[si],strlen(BAD_SERVERS[si]))==0){
+ return 0;
+ }
+ }
+ }
+ return 1;
+# undef NBAD_SERVERS
+}
+
+static int op_http_stream_open(OpusHTTPStream *_stream,const char *_url,
+ int _skip_certificate_check,const char *_proxy_host,unsigned _proxy_port,
+ const char *_proxy_user,const char *_proxy_pass,OpusServerInfo *_info){
+ struct addrinfo *addrs;
+ int nredirs;
+ int ret;
+#if defined(_WIN32)
+ op_init_winsock();
+#endif
+ ret=op_parse_url(&_stream->url,_url);
+ if(OP_UNLIKELY(ret<0))return ret;
+ if(_proxy_host!=NULL){
+ if(OP_UNLIKELY(_proxy_port>65535U))return OP_EINVAL;
+ _stream->connect_host=op_string_dup(_proxy_host);
+ _stream->connect_port=_proxy_port;
+ }
+ else{
+ _stream->connect_host=_stream->url.host;
+ _stream->connect_port=_stream->url.port;
+ }
+ addrs=NULL;
+ for(nredirs=0;nredirs<OP_REDIRECT_LIMIT;nredirs++){
+ OpusParsedURL next_url;
+ struct timeb start_time;
+ struct timeb end_time;
+ char *next;
+ char *status_code;
+ int minor_version_pos;
+ int v1_1_compat;
+ /*Initialize the SSL library if necessary.*/
+ if(OP_URL_IS_SSL(&_stream->url)&&_stream->ssl_ctx==NULL){
+ SSL_CTX *ssl_ctx;
+# if !defined(OPENSSL_NO_LOCKING)
+ /*The documentation says SSL_library_init() is not reentrant.
+ We don't want to add our own depenencies on a threading library, and it
+ appears that it's safe to call OpenSSL's locking functions before the
+ library is initialized, so that's what we'll do (really OpenSSL should
+ do this for us).
+ This doesn't guarantee that _other_ threads in the application aren't
+ calling SSL_library_init() at the same time, but there's not much we
+ can do about that.*/
+ CRYPTO_w_lock(CRYPTO_LOCK_SSL);
+# endif
+ SSL_library_init();
+ /*Needed to get SHA2 algorithms with old OpenSSL versions.*/
+ OpenSSL_add_ssl_algorithms();
+# if !defined(OPENSSL_NO_LOCKING)
+ CRYPTO_w_unlock(CRYPTO_LOCK_SSL);
+# endif
+ ssl_ctx=SSL_CTX_new(SSLv23_client_method());
+ if(ssl_ctx==NULL)return OP_EFAULT;
+ if(!_skip_certificate_check){
+ /*We don't do anything if this fails, since it just means we won't load
+ any certificates (and thus all checks will fail).
+ However, as that is probably the result of a system
+ mis-configuration, assert here to make it easier to identify.*/
+ OP_ALWAYS_TRUE(SSL_CTX_set_default_verify_paths(ssl_ctx));
+ SSL_CTX_set_verify(ssl_ctx,SSL_VERIFY_PEER,NULL);
+ }
+ _stream->ssl_ctx=ssl_ctx;
+ _stream->skip_certificate_check=_skip_certificate_check;
+ if(_proxy_host!=NULL){
+ /*We need to establish a CONNECT tunnel to handle https proxying.
+ Build the request we'll send to do so.*/
+ _stream->proxy_connect.nbuf=0;
+ ret=op_sb_append(&_stream->proxy_connect,"CONNECT ",8);
+ ret|=op_sb_append_string(&_stream->proxy_connect,_stream->url.host);
+ ret|=op_sb_append_port(&_stream->proxy_connect,_stream->url.port);
+ /*CONNECT requires at least HTTP 1.1.*/
+ ret|=op_sb_append(&_stream->proxy_connect," HTTP/1.1\r\n",11);
+ ret|=op_sb_append(&_stream->proxy_connect,"Host: ",6);
+ ret|=op_sb_append_string(&_stream->proxy_connect,_stream->url.host);
+ /*The example in RFC 2817 Section 5.2 specifies an explicit port even
+ when connecting to the default port.
+ Given that the proxy doesn't know whether we're trying to connect to
+ an http or an https URL except by the port number, this seems like a
+ good idea.*/
+ ret|=op_sb_append_port(&_stream->proxy_connect,_stream->url.port);
+ ret|=op_sb_append(&_stream->proxy_connect,"\r\n",2);
+ ret|=op_sb_append(&_stream->proxy_connect,"User-Agent: .\r\n",15);
+ if(_proxy_user!=NULL&&_proxy_pass!=NULL){
+ ret|=op_sb_append_basic_auth_header(&_stream->proxy_connect,
+ "Proxy-Authorization",_proxy_user,_proxy_pass);
+ }
+ /*For backwards compatibility.*/
+ ret|=op_sb_append(&_stream->proxy_connect,
+ "Proxy-Connection: keep-alive\r\n",30);
+ ret|=op_sb_append(&_stream->proxy_connect,"\r\n",2);
+ if(OP_UNLIKELY(ret<0))return ret;
+ }
+ }
+ /*Actually make the connection.*/
+ ret=op_http_connect(_stream,_stream->conns+0,addrs,&start_time);
+ if(OP_UNLIKELY(ret<0))return ret;
+ /*Build the request to send.*/
+ _stream->request.nbuf=0;
+ ret=op_sb_append(&_stream->request,"GET ",4);
+ ret|=op_sb_append_string(&_stream->request,
+ _proxy_host!=NULL?_url:_stream->url.path);
+ /*Send HTTP/1.0 by default for maximum compatibility (so we don't have to
+ re-try if HTTP/1.1 fails, though it shouldn't, even for a 1.0 server).
+ This means we aren't conditionally compliant with RFC 2145, because we
+ violate the requirement that "An HTTP client SHOULD send a request
+ version equal to the highest version for which the client is at least
+ conditionally compliant...".
+ According to RFC 2145, that means we can't claim any compliance with any
+ IETF HTTP specification.*/
+ ret|=op_sb_append(&_stream->request," HTTP/1.0\r\n",11);
+ /*Remember where this is so we can upgrade to HTTP/1.1 if the server
+ supports it.*/
+ minor_version_pos=_stream->request.nbuf-3;
+ ret|=op_sb_append(&_stream->request,"Host: ",6);
+ ret|=op_sb_append_string(&_stream->request,_stream->url.host);
+ if(!OP_URL_IS_DEFAULT_PORT(&_stream->url)){
+ ret|=op_sb_append_port(&_stream->request,_stream->url.port);
+ }
+ ret|=op_sb_append(&_stream->request,"\r\n",2);
+ /*User-Agents have been a bad idea, so send as little as possible.
+ RFC 2616 requires at least one token in the User-Agent, which must have
+ at least one character.*/
+ ret|=op_sb_append(&_stream->request,"User-Agent: .\r\n",15);
+ if(_proxy_host!=NULL&&!OP_URL_IS_SSL(&_stream->url)
+ &&_proxy_user!=NULL&&_proxy_pass!=NULL){
+ ret|=op_sb_append_basic_auth_header(&_stream->request,
+ "Proxy-Authorization",_proxy_user,_proxy_pass);
+ }
+ if(_stream->url.user!=NULL&&_stream->url.pass!=NULL){
+ ret|=op_sb_append_basic_auth_header(&_stream->request,
+ "Authorization",_stream->url.user,_stream->url.pass);
+ }
+ /*Always send a Referer [sic] header.
+ It's common to refuse to serve a resource unless one is present.
+ We just use the relative "/" URI to suggest we came from the same domain,
+ as this is the most common check.
+ This might violate RFC 2616's mandate that the field "MUST NOT be sent if
+ the Request-URI was obtained from a source that does not have its own
+ URI, such as input from the user keyboard," but we don't really have any
+ way to know.*/
+ /*TODO: Should we update this on redirects?*/
+ ret|=op_sb_append(&_stream->request,"Referer: /\r\n",12);
+ /*Always send a Range request header to find out if we're seekable.
+ This requires an HTTP/1.1 server to succeed, but we'll still get what we
+ want with an HTTP/1.0 server that ignores this request header.*/
+ ret|=op_sb_append(&_stream->request,"Range: bytes=0-\r\n",17);
+ /*Remember where this is so we can append offsets to it later.*/
+ _stream->request_tail=_stream->request.nbuf-4;
+ ret|=op_sb_append(&_stream->request,"\r\n",2);
+ if(OP_UNLIKELY(ret<0))return ret;
+ ret=op_http_conn_write_fully(_stream->conns+0,
+ _stream->request.buf,_stream->request.nbuf);
+ if(OP_UNLIKELY(ret<0))return ret;
+ ret=op_http_conn_read_response(_stream->conns+0,&_stream->response);
+ if(OP_UNLIKELY(ret<0))return ret;
+ ftime(&end_time);
+ next=op_http_parse_status_line(&v1_1_compat,&status_code,
+ _stream->response.buf);
+ if(OP_UNLIKELY(next==NULL))return OP_FALSE;
+ if(status_code[0]=='2'){
+ opus_int64 content_length;
+ opus_int64 range_length;
+ int pipeline_supported;
+ int pipeline_disabled;
+ /*We only understand 20x codes.*/
+ if(status_code[1]!='0')return OP_FALSE;
+ content_length=-1;
+ range_length=-1;
+ /*Pipelining must be explicitly enabled.*/
+ pipeline_supported=0;
+ pipeline_disabled=0;
+ for(;;){
+ char *header;
+ char *cdr;
+ ret=op_http_get_next_header(&header,&cdr,&next);
+ if(OP_UNLIKELY(ret<0))return ret;
+ if(header==NULL)break;
+ if(strcmp(header,"content-length")==0){
+ /*Two Content-Length headers?*/
+ if(OP_UNLIKELY(content_length>=0))return OP_FALSE;
+ content_length=op_http_parse_content_length(cdr);
+ if(OP_UNLIKELY(content_length<0))return (int)content_length;
+ /*Make sure the Content-Length and Content-Range headers match.*/
+ if(range_length>=0&&OP_UNLIKELY(content_length!=range_length)){
+ return OP_FALSE;
+ }
+ }
+ else if(strcmp(header,"content-range")==0){
+ opus_int64 range_first;
+ opus_int64 range_last;
+ /*Two Content-Range headers?*/
+ if(OP_UNLIKELY(range_length>=0))return OP_FALSE;
+ ret=op_http_parse_content_range(&range_first,&range_last,
+ &range_length,cdr);
+ if(OP_UNLIKELY(ret<0))return ret;
+ /*"A response with satus code 206 (Partial Content) MUST NOT
+ include a Content-Range field with a byte-range-resp-spec of
+ '*'."*/
+ if(status_code[2]=='6'
+ &&(OP_UNLIKELY(range_first<0)||OP_UNLIKELY(range_last<0))){
+ return OP_FALSE;
+ }
+ /*We asked for the entire resource.*/
+ if(range_length>=0){
+ /*Quit if we didn't get it.*/
+ if(range_last>=0&&OP_UNLIKELY(range_last!=range_length-1)){
+ return OP_FALSE;
+ }
+ }
+ /*If there was no length, use the end of the range.*/
+ else if(range_last>=0)range_length=range_last+1;
+ /*Make sure the Content-Length and Content-Range headers match.*/
+ if(content_length>=0&&OP_UNLIKELY(content_length!=range_length)){
+ return OP_FALSE;
+ }
+ }
+ else if(strcmp(header,"connection")==0){
+ /*According to RFC 2616, if an HTTP/1.1 application does not support
+ pipelining, it "MUST include the 'close' connection option in
+ every message."
+ Therefore, if we receive one in the initial response, disable
+ pipelining entirely.
+ The server still might support it (e.g., we might just have hit the
+ request limit for a temporary child process), but if it doesn't
+ and we assume it does, every time we cross a chunk boundary we'll
+ error out and reconnect, adding lots of latency.*/
+ ret=op_http_parse_connection(cdr);
+ if(OP_UNLIKELY(ret<0))return ret;
+ pipeline_disabled|=ret;
+ }
+ else if(strcmp(header,"server")==0){
+ /*If we got a Server response header, and it wasn't from a known-bad
+ server, enable pipelining, as long as it's at least HTTP/1.1.
+ According to RFC 2145, the server is supposed to respond with the
+ highest minor version number it supports unless it is known or
+ suspected that we incorrectly implement the HTTP specification.
+ So it should send back at least HTTP/1.1, despite our HTTP/1.0
+ request.*/
+ pipeline_supported=v1_1_compat;
+ if(v1_1_compat)pipeline_disabled|=!op_http_allow_pipelining(cdr);
+ if(_info!=NULL&&_info->server==NULL)_info->server=op_string_dup(cdr);
+ }
+ /*Collect station information headers if the caller requested it.
+ If there's more than one copy of a header, the first one wins.*/
+ else if(_info!=NULL){
+ if(strcmp(header,"content-type")==0){
+ if(_info->content_type==NULL){
+ _info->content_type=op_string_dup(cdr);
+ }
+ }
+ else if(header[0]=='i'&&header[1]=='c'
+ &&(header[2]=='e'||header[2]=='y')&&header[3]=='-'){
+ if(strcmp(header+4,"name")==0){
+ if(_info->name==NULL)_info->name=op_string_dup(cdr);
+ }
+ else if(strcmp(header+4,"description")==0){
+ if(_info->description==NULL)_info->description=op_string_dup(cdr);
+ }
+ else if(strcmp(header+4,"genre")==0){
+ if(_info->genre==NULL)_info->genre=op_string_dup(cdr);
+ }
+ else if(strcmp(header+4,"url")==0){
+ if(_info->url==NULL)_info->url=op_string_dup(cdr);
+ }
+ else if(strcmp(header,"icy-br")==0
+ ||strcmp(header,"ice-bitrate")==0){
+ if(_info->bitrate_kbps<0){
+ opus_int64 bitrate_kbps;
+ /*Just re-using this function to parse a random unsigned
+ integer field.*/
+ bitrate_kbps=op_http_parse_content_length(cdr);
+ if(bitrate_kbps>=0&&bitrate_kbps<=OP_INT32_MAX){
+ _info->bitrate_kbps=(opus_int32)bitrate_kbps;
+ }
+ }
+ }
+ else if(strcmp(header,"icy-pub")==0
+ ||strcmp(header,"ice-public")==0){
+ if(_info->is_public<0&&(cdr[0]=='0'||cdr[0]=='1')&&cdr[1]=='\0'){
+ _info->is_public=cdr[0]-'0';
+ }
+ }
+ }
+ }
+ }
+ switch(status_code[2]){
+ /*200 OK*/
+ case '0':break;
+ /*203 Non-Authoritative Information*/
+ case '3':break;
+ /*204 No Content*/
+ case '4':{
+ if(content_length>=0&&OP_UNLIKELY(content_length!=0)){
+ return OP_FALSE;
+ }
+ }break;
+ /*206 Partial Content*/
+ case '6':{
+ /*No Content-Range header.*/
+ if(OP_UNLIKELY(range_length<0))return OP_FALSE;
+ content_length=range_length;
+ /*The server supports range requests for this resource.
+ We can seek.*/
+ _stream->seekable=1;
+ }break;
+ /*201 Created: the response "SHOULD include an entity containing a list
+ of resource characteristics and location(s)," but not an Opus file.
+ 202 Accepted: the response "SHOULD include an indication of request's
+ current status and either a pointer to a status monitor or some
+ estimate of when the user can expect the request to be fulfilled,"
+ but not an Opus file.
+ 205 Reset Content: this "MUST NOT include an entity," meaning no Opus
+ file.
+ 207...209 are not yet defined, so we don't know how to handle them.*/
+ default:return OP_FALSE;
+ }
+ _stream->content_length=content_length;
+ _stream->pipeline=pipeline_supported&&!pipeline_disabled;
+ /*Pipelining requires HTTP/1.1 persistent connections.*/
+ if(_stream->pipeline)_stream->request.buf[minor_version_pos]='1';
+ _stream->conns[0].pos=0;
+ _stream->conns[0].end_pos=_stream->seekable?content_length:-1;
+ _stream->conns[0].chunk_size=-1;
+ _stream->cur_conni=0;
+ _stream->connect_rate=op_time_diff_ms(&end_time,&start_time);
+ _stream->connect_rate=OP_MAX(_stream->connect_rate,1);
+ if(_info!=NULL)_info->is_ssl=OP_URL_IS_SSL(&_stream->url);
+ /*The URL has been successfully opened.*/
+ return 0;
+ }
+ /*Shouldn't get 1xx; 4xx and 5xx are both failures (and we don't retry).
+ Everything else is undefined.*/
+ else if(status_code[0]!='3')return OP_FALSE;
+ /*We have some form of redirect request.*/
+ /*We only understand 30x codes.*/
+ if(status_code[1]!='0')return OP_FALSE;
+ switch(status_code[2]){
+ /*300 Multiple Choices: "If the server has a preferred choice of
+ representation, it SHOULD include the specific URI for that
+ representation in the Location field," otherwise we'll fail.*/
+ case '0':
+ /*301 Moved Permanently*/
+ case '1':
+ /*302 Found*/
+ case '2':
+ /*307 Temporary Redirect*/
+ case '7':
+ /*308 Permanent Redirect (defined by draft-reschke-http-status-308-07).*/
+ case '8':break;
+ /*305 Use Proxy: "The Location field gives the URI of the proxy."
+ TODO: This shouldn't actually be that hard to do.*/
+ case '5':return OP_EIMPL;
+ /*303 See Other: "The new URI is not a substitute reference for the
+ originally requested resource."
+ 304 Not Modified: "The 304 response MUST NOT contain a message-body."
+ 306 (Unused)
+ 309 is not yet defined, so we don't know how to handle it.*/
+ default:return OP_FALSE;
+ }
+ _url=NULL;
+ for(;;){
+ char *header;
+ char *cdr;
+ ret=op_http_get_next_header(&header,&cdr,&next);
+ if(OP_UNLIKELY(ret<0))return ret;
+ if(header==NULL)break;
+ if(strcmp(header,"location")==0&&OP_LIKELY(_url==NULL))_url=cdr;
+ }
+ if(OP_UNLIKELY(_url==NULL))return OP_FALSE;
+ ret=op_parse_url(&next_url,_url);
+ if(OP_UNLIKELY(ret<0))return ret;
+ if(_proxy_host==NULL||_stream->ssl_session!=NULL){
+ if(strcmp(_stream->url.host,next_url.host)==0
+ &&_stream->url.port==next_url.port){
+ /*Try to skip re-resolve when connecting to the same host.*/
+ addrs=&_stream->addr_info;
+ }
+ else{
+ if(_stream->ssl_session!=NULL){
+ /*Forget any cached SSL session from the last host.*/
+ SSL_SESSION_free(_stream->ssl_session);
+ _stream->ssl_session=NULL;
+ }
+ }
+ }
+ if(_proxy_host==NULL){
+ OP_ASSERT(_stream->connect_host==_stream->url.host);
+ _stream->connect_host=next_url.host;
+ _stream->connect_port=next_url.port;
+ }
+ /*Always try to skip re-resolve for proxy connections.*/
+ else addrs=&_stream->addr_info;
+ op_parsed_url_clear(&_stream->url);
+ *&_stream->url=*&next_url;
+ /*TODO: On servers/proxies that support pipelining, we might be able to
+ re-use this connection.*/
+ op_http_conn_close(_stream,_stream->conns+0,&_stream->lru_head,1);
+ }
+ /*Redirection limit reached.*/
+ return OP_FALSE;
+}
+
+static int op_http_conn_send_request(OpusHTTPStream *_stream,
+ OpusHTTPConn *_conn,opus_int64 _pos,opus_int32 _chunk_size,
+ int _try_not_to_block){
+ opus_int64 next_end;
+ int ret;
+ /*We shouldn't have another request outstanding.*/
+ OP_ASSERT(_conn->next_pos<0);
+ /*Build the request to send.*/
+ OP_ASSERT(_stream->request.nbuf>=_stream->request_tail);
+ _stream->request.nbuf=_stream->request_tail;
+ ret=op_sb_append_nonnegative_int64(&_stream->request,_pos);
+ ret|=op_sb_append(&_stream->request,"-",1);
+ if(_chunk_size>0&&OP_ADV_OFFSET(_pos,2*_chunk_size)<_stream->content_length){
+ /*We shouldn't be pipelining requests with non-HTTP/1.1 servers.*/
+ OP_ASSERT(_stream->pipeline);
+ next_end=_pos+_chunk_size;
+ ret|=op_sb_append_nonnegative_int64(&_stream->request,next_end-1);
+ /*Use a larger chunk size for our next request.*/
+ _chunk_size<<=1;
+ /*But after a while, just request the rest of the resource.*/
+ if(_chunk_size>OP_PIPELINE_CHUNK_SIZE_MAX)_chunk_size=-1;
+ }
+ else{
+ /*Either this was a non-pipelined request or we were close enough to the
+ end to just ask for the rest.*/
+ next_end=-1;
+ _chunk_size=-1;
+ }
+ ret|=op_sb_append(&_stream->request,"\r\n\r\n",4);
+ if(OP_UNLIKELY(ret<0))return ret;
+ /*If we don't want to block, check to see if there's enough space in the send
+ queue.
+ There's still a chance we might block, even if there is enough space, but
+ it's a much slimmer one.
+ Blocking at all is pretty unlikely, as we won't have any requests queued
+ when _try_not_to_block is set, so if FIONSPACE isn't available (e.g., on
+ Linux), just skip the test.*/
+ if(_try_not_to_block){
+# if defined(FIONSPACE)
+ int available;
+ ret=ioctl(_conn->fd,FIONSPACE,&available);
+ if(ret<0||available<_stream->request.nbuf)return 1;
+# endif
+ }
+ ret=op_http_conn_write_fully(_conn,
+ _stream->request.buf,_stream->request.nbuf);
+ if(OP_UNLIKELY(ret<0))return ret;
+ _conn->next_pos=_pos;
+ _conn->next_end=next_end;
+ /*Save the chunk size to use for the next request.*/
+ _conn->chunk_size=_chunk_size;
+ _conn->nrequests_left--;
+ return ret;
+}
+
+/*Handles the response to all requests after the first one.
+ Return: 1 if the connection was closed or timed out, 0 on success, or a
+ negative value on any other error.*/
+static int op_http_conn_handle_response(OpusHTTPStream *_stream,
+ OpusHTTPConn *_conn){
+ char *next;
+ char *status_code;
+ opus_int64 range_length;
+ opus_int64 next_pos;
+ opus_int64 next_end;
+ int ret;
+ ret=op_http_conn_read_response(_conn,&_stream->response);
+ /*If the server just closed the connection on us, we may have just hit a
+ connection re-use limit, so we might want to retry.*/
+ if(OP_UNLIKELY(ret<0))return ret==OP_EREAD?1:ret;
+ next=op_http_parse_status_line(NULL,&status_code,_stream->response.buf);
+ if(OP_UNLIKELY(next==NULL))return OP_FALSE;
+ /*We _need_ a 206 Partial Content response.
+ Nothing else will do.*/
+ if(strncmp(status_code,"206",3)!=0){
+ /*But on a 408 Request Timeout, we might want to re-try.*/
+ return strncmp(status_code,"408",3)==0?1:OP_FALSE;
+ }
+ next_pos=_conn->next_pos;
+ next_end=_conn->next_end;
+ range_length=-1;
+ for(;;){
+ char *header;
+ char *cdr;
+ ret=op_http_get_next_header(&header,&cdr,&next);
+ if(OP_UNLIKELY(ret<0))return ret;
+ if(header==NULL)break;
+ if(strcmp(header,"content-range")==0){
+ opus_int64 range_first;
+ opus_int64 range_last;
+ /*Two Content-Range headers?*/
+ if(OP_UNLIKELY(range_length>=0))return OP_FALSE;
+ ret=op_http_parse_content_range(&range_first,&range_last,
+ &range_length,cdr);
+ if(OP_UNLIKELY(ret<0))return ret;
+ /*"A response with satus code 206 (Partial Content) MUST NOT
+ include a Content-Range field with a byte-range-resp-spec of
+ '*'."*/
+ if(OP_UNLIKELY(range_first<0)||OP_UNLIKELY(range_last<0))return OP_FALSE;
+ /*We also don't want range_last to overflow.*/
+ if(OP_UNLIKELY(range_last>=OP_INT64_MAX))return OP_FALSE;
+ range_last++;
+ /*Quit if we didn't get the offset we asked for.*/
+ if(range_first!=next_pos)return OP_FALSE;
+ if(next_end<0){
+ /*We asked for the rest of the resource.*/
+ if(range_length>=0){
+ /*Quit if we didn't get it.*/
+ if(OP_UNLIKELY(range_last!=range_length))return OP_FALSE;
+ }
+ /*If there was no length, use the end of the range.*/
+ else range_length=range_last;
+ next_end=range_last;
+ }
+ else{
+ if(range_last!=next_end)return OP_FALSE;
+ /*If there was no length, use the larger of the content length or the
+ end of this chunk.*/
+ if(range_length<0){
+ range_length=OP_MAX(range_last,_stream->content_length);
+ }
+ }
+ }
+ else if(strcmp(header,"content-length")==0){
+ opus_int64 content_length;
+ /*Validate the Content-Length header, if present, against the request we
+ made.*/
+ content_length=op_http_parse_content_length(cdr);
+ if(OP_UNLIKELY(content_length<0))return (int)content_length;
+ if(next_end<0){
+ /*If we haven't seen the Content-Range header yet and we asked for the
+ rest of the resource, set next_end, so we can make sure they match
+ when we do find the Content-Range header.*/
+ if(OP_UNLIKELY(next_pos>OP_INT64_MAX-content_length))return OP_FALSE;
+ next_end=next_pos+content_length;
+ }
+ /*Otherwise, make sure they match now.*/
+ else if(OP_UNLIKELY(next_end-next_pos!=content_length))return OP_FALSE;
+ }
+ else if(strcmp(header,"connection")==0){
+ ret=op_http_parse_connection(cdr);
+ if(OP_UNLIKELY(ret<0))return ret;
+ /*If the server told us it was going to close the connection, don't make
+ any more requests.*/
+ if(OP_UNLIKELY(ret>0))_conn->nrequests_left=0;
+ }
+ }
+ /*No Content-Range header.*/
+ if(OP_UNLIKELY(range_length<0))return OP_FALSE;
+ /*Update the content_length if necessary.*/
+ _stream->content_length=range_length;
+ _conn->pos=next_pos;
+ _conn->end_pos=next_end;
+ _conn->next_pos=-1;
+ return 0;
+}
+
+/*Open a new connection that will start reading at byte offset _pos.
+ _pos: The byte offset to start reading from.
+ _chunk_size: The number of bytes to ask for in the initial request, or -1 to
+ request the rest of the resource.
+ This may be more bytes than remain, in which case it will be
+ converted into a request for the rest.*/
+static int op_http_conn_open_pos(OpusHTTPStream *_stream,
+ OpusHTTPConn *_conn,opus_int64 _pos,opus_int32 _chunk_size){
+ struct timeb start_time;
+ struct timeb end_time;
+ opus_int32 connect_rate;
+ opus_int32 connect_time;
+ int ret;
+ ret=op_http_connect(_stream,_conn,&_stream->addr_info,&start_time);
+ if(OP_UNLIKELY(ret<0))return ret;
+ ret=op_http_conn_send_request(_stream,_conn,_pos,_chunk_size,0);
+ if(OP_UNLIKELY(ret<0))return ret;
+ ret=op_http_conn_handle_response(_stream,_conn);
+ if(OP_UNLIKELY(ret!=0))return OP_FALSE;
+ ftime(&end_time);
+ _stream->cur_conni=_conn-_stream->conns;
+ OP_ASSERT(_stream->cur_conni>=0&&_stream->cur_conni<OP_NCONNS_MAX);
+ /*The connection has been successfully opened.
+ Update the connection time estimate.*/
+ connect_time=op_time_diff_ms(&end_time,&start_time);
+ connect_rate=_stream->connect_rate;
+ connect_rate+=OP_MAX(connect_time,1)-connect_rate+8>>4;
+ _stream->connect_rate=connect_rate;
+ return 0;
+}
+
+/*Read data from the current response body.
+ If we're pipelining and we get close to the end of this response, queue
+ another request.
+ If we've reached the end of this response body, parse the next response and
+ keep going.
+ [out] _buf: Returns the data read.
+ _buf_size: The size of the buffer.
+ Return: A positive number of bytes read on success.
+ 0: The connection was closed.
+ OP_EREAD: There was a fatal read error.*/
+static int op_http_conn_read_body(OpusHTTPStream *_stream,
+ OpusHTTPConn *_conn,unsigned char *_buf,int _buf_size){
+ opus_int64 pos;
+ opus_int64 end_pos;
+ opus_int64 next_pos;
+ opus_int64 content_length;
+ int nread;
+ int pipeline;
+ int ret;
+ /*Currently this function can only be called on the LRU head.
+ Otherwise, we'd need a _pnext pointer if we needed to close the connection,
+ and re-opening it would re-organize the lists.*/
+ OP_ASSERT(_stream->lru_head==_conn);
+ /*We should have filterd out empty reads by this point.*/
+ OP_ASSERT(_buf_size>0);
+ pos=_conn->pos;
+ end_pos=_conn->end_pos;
+ next_pos=_conn->next_pos;
+ pipeline=_stream->pipeline;
+ content_length=_stream->content_length;
+ if(end_pos>=0){
+ /*Have we reached the end of the current response body?*/
+ if(pos>=end_pos){
+ OP_ASSERT(content_length>=0);
+ /*If this was the end of the stream, we're done.
+ Also return early if a non-blocking read was requested (regardless of
+ whether we might be able to parse the next response without
+ blocking).*/
+ if(content_length<=end_pos)return 0;
+ /*Otherwise, start on the next response.*/
+ if(next_pos<0){
+ /*We haven't issued another request yet.*/
+ if(!pipeline||_conn->nrequests_left<=0){
+ /*There are two ways to get here: either the server told us it was
+ going to close the connection after the last request, or we
+ thought we were reading the whole resource, but it grew while we
+ were reading it.
+ The only way the latter could have happened is if content_length
+ changed while seeking.
+ Open a new request to read the rest.*/
+ OP_ASSERT(_stream->seekable);
+ /*Try to open a new connection to read another chunk.*/
+ op_http_conn_close(_stream,_conn,&_stream->lru_head,1);
+ /*If we're not pipelining, we should be requesting the rest.*/
+ OP_ASSERT(pipeline||_conn->chunk_size==-1);
+ ret=op_http_conn_open_pos(_stream,_conn,end_pos,_conn->chunk_size);
+ if(OP_UNLIKELY(ret<0))return OP_EREAD;
+ }
+ else{
+ /*Issue the request now (better late than never).*/
+ ret=op_http_conn_send_request(_stream,_conn,pos,_conn->chunk_size,0);
+ if(OP_UNLIKELY(ret<0))return OP_EREAD;
+ next_pos=_conn->next_pos;
+ OP_ASSERT(next_pos>=0);
+ }
+ }
+ if(next_pos>=0){
+ /*We shouldn't be trying to read past the current request body if we're
+ seeking somewhere else.*/
+ OP_ASSERT(next_pos==end_pos);
+ ret=op_http_conn_handle_response(_stream,_conn);
+ if(OP_UNLIKELY(ret<0))return OP_EREAD;
+ if(OP_UNLIKELY(ret>0)&&pipeline){
+ opus_int64 next_end;
+ next_end=_conn->next_end;
+ /*Our request timed out or the server closed the connection.
+ Try re-connecting.*/
+ op_http_conn_close(_stream,_conn,&_stream->lru_head,1);
+ /*Unless there's a bug, we should be able to convert
+ (next_pos,next_end) into valid (_pos,_chunk_size) parameters.*/
+ OP_ASSERT(next_end<0
+ ||next_end-next_pos>=0&&next_end-next_pos<=OP_INT32_MAX);
+ ret=op_http_conn_open_pos(_stream,_conn,next_pos,
+ next_end<0?-1:(opus_int32)(next_end-next_pos));
+ if(OP_UNLIKELY(ret<0))return OP_EREAD;
+ }
+ else if(OP_UNLIKELY(ret!=0))return OP_EREAD;
+ }
+ pos=_conn->pos;
+ end_pos=_conn->end_pos;
+ content_length=_stream->content_length;
+ }
+ OP_ASSERT(end_pos>pos);
+ _buf_size=OP_MIN(_buf_size,end_pos-pos);
+ }
+ nread=op_http_conn_read(_conn,(char *)_buf,_buf_size,1);
+ if(OP_UNLIKELY(nread<0))return nread;
+ pos+=nread;
+ _conn->pos=pos;
+ OP_ASSERT(end_pos<0||content_length>=0);
+ /*TODO: If nrequests_left<=0, we can't make a new request, and there will be
+ a big pause after we hit the end of the chunk while we open a new
+ connection.
+ It would be nice to be able to start that process now, but we have no way
+ to do it in the background without blocking (even if we could start it, we
+ have no guarantee the application will return control to us in a
+ sufficiently timely manner to allow us to complete it, and this is
+ uncommon enough that it's not worth using threads just for this).*/
+ if(end_pos>=0&&end_pos<content_length&&next_pos<0
+ &&pipeline&&OP_LIKELY(_conn->nrequests_left>0)){
+ opus_int64 request_thresh;
+ opus_int32 chunk_size;
+ /*Are we getting close to the end of the current response body?
+ If so, we should request more data.*/
+ request_thresh=_stream->connect_rate*_conn->read_rate>>12;
+ /*But don't commit ourselves too quickly.*/
+ chunk_size=_conn->chunk_size;
+ if(chunk_size>=0)request_thresh=OP_MIN(chunk_size>>2,request_thresh);
+ if(end_pos-pos<request_thresh){
+ ret=op_http_conn_send_request(_stream,_conn,end_pos,_conn->chunk_size,1);
+ if(OP_UNLIKELY(ret<0))return OP_EREAD;
+ }
+ }
+ return nread;
+}
+
+static int op_http_stream_read(void *_stream,
+ unsigned char *_ptr,int _buf_size){
+ OpusHTTPStream *stream;
+ ptrdiff_t nread;
+ opus_int64 size;
+ opus_int64 pos;
+ int ci;
+ stream=(OpusHTTPStream *)_stream;
+ /*Check for an empty read.*/
+ if(_buf_size<=0)return 0;
+ ci=stream->cur_conni;
+ /*No current connection => EOF.*/
+ if(ci<0)return 0;
+ pos=stream->conns[ci].pos;
+ size=stream->content_length;
+ /*Check for EOF.*/
+ if(size>=0){
+ if(pos>=size)return 0;
+ /*Check for a short read.*/
+ if(_buf_size>size-pos)_buf_size=(int)(size-pos);
+ }
+ nread=op_http_conn_read_body(stream,stream->conns+ci,_ptr,_buf_size);
+ if(OP_UNLIKELY(nread<=0)){
+ /*We hit an error or EOF.
+ Either way, we're done with this connection.*/
+ op_http_conn_close(stream,stream->conns+ci,&stream->lru_head,1);
+ stream->cur_conni=-1;
+ stream->pos=pos;
+ }
+ return nread;
+}
+
+/*Discard data until we reach the _target position.
+ This destroys the contents of _stream->response.buf, as we need somewhere to
+ read this data, and that is a convenient place.
+ _just_read_ahead: Whether or not this is a plain fast-forward.
+ If 0, we need to issue a new request for a chunk at _target
+ and discard all the data from our current request(s).
+ Otherwise, we should be able to reach _target without
+ issuing any new requests.
+ _target: The stream position to which to read ahead.*/
+static int op_http_conn_read_ahead(OpusHTTPStream *_stream,
+ OpusHTTPConn *_conn,int _just_read_ahead,opus_int64 _target){
+ opus_int64 pos;
+ opus_int64 end_pos;
+ opus_int64 next_pos;
+ opus_int64 next_end;
+ ptrdiff_t nread;
+ int ret;
+ pos=_conn->pos;
+ end_pos=_conn->end_pos;
+ next_pos=_conn->next_pos;
+ next_end=_conn->next_end;
+ if(!_just_read_ahead){
+ /*We need to issue a new pipelined request.
+ This is the only case where we allow more than one outstanding request
+ at a time, so we need to reset next_pos (we'll restore it below if we
+ did have an outstanding request).*/
+ OP_ASSERT(_stream->pipeline);
+ _conn->next_pos=-1;
+ ret=op_http_conn_send_request(_stream,_conn,_target,
+ OP_PIPELINE_CHUNK_SIZE,0);
+ if(OP_UNLIKELY(ret<0))return ret;
+ }
+ /*We can reach the target position by reading forward in the current chunk.*/
+ if(_just_read_ahead&&(end_pos<0||_target<end_pos))end_pos=_target;
+ else if(next_pos>=0){
+ opus_int64 next_next_pos;
+ opus_int64 next_next_end;
+ /*We already have a request outstanding.
+ Finish off the current chunk.*/
+ while(pos<end_pos){
+ nread=op_http_conn_read(_conn,_stream->response.buf,
+ (int)OP_MIN(end_pos-pos,_stream->response.cbuf),1);
+ /*We failed to read ahead.*/
+ if(nread<=0)return OP_FALSE;
+ pos+=nread;
+ }
+ OP_ASSERT(pos==end_pos);
+ if(_just_read_ahead){
+ next_next_pos=next_next_end=-1;
+ end_pos=_target;
+ }
+ else{
+ OP_ASSERT(_conn->next_pos==_target);
+ next_next_pos=_target;
+ next_next_end=_conn->next_end;
+ _conn->next_pos=next_pos;
+ _conn->next_end=next_end;
+ end_pos=next_end;
+ }
+ ret=op_http_conn_handle_response(_stream,_conn);
+ if(OP_UNLIKELY(ret!=0))return OP_FALSE;
+ _conn->next_pos=next_next_pos;
+ _conn->next_end=next_next_end;
+ }
+ while(pos<end_pos){
+ nread=op_http_conn_read(_conn,_stream->response.buf,
+ (int)OP_MIN(end_pos-pos,_stream->response.cbuf),1);
+ /*We failed to read ahead.*/
+ if(nread<=0)return OP_FALSE;
+ pos+=nread;
+ }
+ OP_ASSERT(pos==end_pos);
+ if(!_just_read_ahead){
+ ret=op_http_conn_handle_response(_stream,_conn);
+ if(OP_UNLIKELY(ret!=0))return OP_FALSE;
+ }
+ else _conn->pos=end_pos;
+ OP_ASSERT(_conn->pos==_target);
+ return 0;
+}
+
+static int op_http_stream_seek(void *_stream,opus_int64 _offset,int _whence){
+ struct timeb seek_time;
+ OpusHTTPStream *stream;
+ OpusHTTPConn *conn;
+ OpusHTTPConn **pnext;
+ OpusHTTPConn *close_conn;
+ OpusHTTPConn **close_pnext;
+ opus_int64 content_length;
+ opus_int64 pos;
+ int pipeline;
+ int ci;
+ int ret;
+ stream=(OpusHTTPStream *)_stream;
+ if(!stream->seekable)return -1;
+ content_length=stream->content_length;
+ /*If we're seekable, we should have gotten a Content-Length.*/
+ OP_ASSERT(content_length>=0);
+ ci=stream->cur_conni;
+ pos=ci<0?content_length:stream->conns[ci].pos;
+ switch(_whence){
+ case SEEK_SET:{
+ /*Check for overflow:*/
+ if(_offset<0)return -1;
+ pos=_offset;
+ }break;
+ case SEEK_CUR:{
+ /*Check for overflow:*/
+ if(_offset<-pos||_offset>OP_INT64_MAX-pos)return -1;
+ pos+=_offset;
+ }break;
+ case SEEK_END:{
+ /*Check for overflow:*/
+ if(_offset>content_length||_offset<content_length-OP_INT64_MAX)return -1;
+ pos=content_length-_offset;
+ }break;
+ default:return -1;
+ }
+ /*Mark when we deactivated the active connection.*/
+ if(ci>=0){
+ op_http_conn_read_rate_update(stream->conns+ci);
+ *&seek_time=*&stream->conns[ci].read_time;
+ }
+ else ftime(&seek_time);
+ /*If we seeked past the end of the stream, just disable the active
+ connection.*/
+ if(pos>=content_length){
+ stream->cur_conni=-1;
+ stream->pos=pos;
+ return 0;
+ }
+ /*First try to find a connection we can use without waiting.*/
+ pnext=&stream->lru_head;
+ conn=stream->lru_head;
+ while(conn!=NULL){
+ opus_int64 conn_pos;
+ opus_int64 end_pos;
+ int available;
+ /*If this connection has been dormant too long or has made too many
+ requests, close it.
+ This is to prevent us from hitting server limits/firewall timeouts.*/
+ if(op_time_diff_ms(&seek_time,&conn->read_time)>
+ OP_CONNECTION_IDLE_TIMEOUT_MS
+ ||conn->nrequests_left<OP_PIPELINE_MIN_REQUESTS){
+ op_http_conn_close(stream,conn,pnext,1);
+ conn=*pnext;
+ continue;
+ }
+ available=op_http_conn_estimate_available(conn);
+ conn_pos=conn->pos;
+ end_pos=conn->end_pos;
+ if(conn->next_pos>=0){
+ OP_ASSERT(end_pos>=0);
+ OP_ASSERT(conn->next_pos==end_pos);
+ end_pos=conn->next_end;
+ }
+ OP_ASSERT(end_pos<0||conn_pos<=end_pos);
+ /*Can we quickly read ahead without issuing a new request or waiting for
+ any more data?
+ If we have an oustanding request, we'll over-estimate the amount of data
+ it has available (because we'll count the response headers, too), but
+ that probably doesn't matter.*/
+ if(conn_pos<=pos&&pos-conn_pos<=available&&(end_pos<0||pos<end_pos)){
+ /*Found a suitable connection to re-use.*/
+ ret=op_http_conn_read_ahead(stream,conn,1,pos);
+ if(OP_UNLIKELY(ret<0)){
+ /*The connection might have become stale, so close it and keep going.*/
+ op_http_conn_close(stream,conn,pnext,1);
+ conn=*pnext;
+ continue;
+ }
+ /*Sucessfully resurrected this connection.*/
+ *pnext=conn->next;
+ conn->next=stream->lru_head;
+ stream->lru_head=conn;
+ stream->cur_conni=conn-stream->conns;
+ return 0;
+ }
+ pnext=&conn->next;
+ conn=conn->next;
+ }
+ /*Chances are that didn't work, so now try to find one we can use by reading
+ ahead a reasonable amount and/or by issuing a new request.*/
+ close_pnext=NULL;
+ close_conn=NULL;
+ pnext=&stream->lru_head;
+ conn=stream->lru_head;
+ pipeline=stream->pipeline;
+ while(conn!=NULL){
+ opus_int64 conn_pos;
+ opus_int64 end_pos;
+ opus_int64 read_ahead_thresh;
+ int available;
+ int just_read_ahead;
+ /*Dividing by 2048 instead of 1000 scales this by nearly 1/2, biasing away
+ from connection re-use (and roughly compensating for the lag required to
+ reopen the TCP window of a connection that's been idle).
+ There's no overflow checking here, because it's vanishingly unlikely, and
+ all it would do is cause us to make poor decisions.*/
+ read_ahead_thresh=OP_MAX(OP_READAHEAD_THRESH_MIN,
+ stream->connect_rate*conn->read_rate>>11);
+ available=op_http_conn_estimate_available(conn);
+ conn_pos=conn->pos;
+ end_pos=conn->end_pos;
+ if(conn->next_pos>=0){
+ OP_ASSERT(end_pos>=0);
+ OP_ASSERT(conn->next_pos==end_pos);
+ end_pos=conn->next_end;
+ }
+ OP_ASSERT(end_pos<0||conn_pos<=end_pos);
+ /*Can we quickly read ahead without issuing a new request?*/
+ just_read_ahead=conn_pos<=pos&&pos-conn_pos-available<=read_ahead_thresh
+ &&(end_pos<0||pos<end_pos);
+ if(just_read_ahead||pipeline&&end_pos>=0
+ &&end_pos-conn_pos-available<=read_ahead_thresh){
+ /*Found a suitable connection to re-use.*/
+ ret=op_http_conn_read_ahead(stream,conn,just_read_ahead,pos);
+ if(OP_UNLIKELY(ret<0)){
+ /*The connection might have become stale, so close it and keep going.*/
+ op_http_conn_close(stream,conn,pnext,1);
+ conn=*pnext;
+ continue;
+ }
+ /*Sucessfully resurrected this connection.*/
+ *pnext=conn->next;
+ conn->next=stream->lru_head;
+ stream->lru_head=conn;
+ stream->cur_conni=conn-stream->conns;
+ return 0;
+ }
+ close_pnext=pnext;
+ close_conn=conn;
+ pnext=&conn->next;
+ conn=conn->next;
+ }
+ /*No suitable connections.
+ Open a new one.*/
+ if(stream->free_head==NULL){
+ /*All connections in use.
+ Expire one of them (we should have already picked which one when scanning
+ the list).*/
+ OP_ASSERT(close_conn!=NULL);
+ OP_ASSERT(close_pnext!=NULL);
+ op_http_conn_close(stream,close_conn,close_pnext,1);
+ }
+ OP_ASSERT(stream->free_head!=NULL);
+ conn=stream->free_head;
+ /*If we can pipeline, only request a chunk of data.
+ If we're seeking now, there's a good chance we will want to seek again
+ soon, and this avoids committing this connection to reading the rest of
+ the stream.
+ Particularly with SSL or proxies, issuing a new request on the same
+ connection can be substantially faster than opening a new one.
+ This also limits the amount of data the server will blast at us on this
+ connection if we later seek elsewhere and start reading from a different
+ connection.*/
+ ret=op_http_conn_open_pos(stream,conn,pos,
+ pipeline?OP_PIPELINE_CHUNK_SIZE:-1);
+ if(OP_UNLIKELY(ret<0)){
+ op_http_conn_close(stream,conn,&stream->lru_head,1);
+ return -1;
+ }
+ return 0;
+}
+
+static opus_int64 op_http_stream_tell(void *_stream){
+ OpusHTTPStream *stream;
+ int ci;
+ stream=(OpusHTTPStream *)_stream;
+ ci=stream->cur_conni;
+ return ci<0?stream->pos:stream->conns[ci].pos;
+}
+
+static int op_http_stream_close(void *_stream){
+ OpusHTTPStream *stream;
+ stream=(OpusHTTPStream *)_stream;
+ if(OP_LIKELY(stream!=NULL)){
+ op_http_stream_clear(stream);
+ _ogg_free(stream);
+ }
+ return 0;
+}
+
+static const OpusFileCallbacks OP_HTTP_CALLBACKS={
+ op_http_stream_read,
+ op_http_stream_seek,
+ op_http_stream_tell,
+ op_http_stream_close
+};
+#endif
+
+void opus_server_info_init(OpusServerInfo *_info){
+ _info->name=NULL;
+ _info->description=NULL;
+ _info->genre=NULL;
+ _info->url=NULL;
+ _info->server=NULL;
+ _info->content_type=NULL;
+ _info->bitrate_kbps=-1;
+ _info->is_public=-1;
+ _info->is_ssl=0;
+}
+
+void opus_server_info_clear(OpusServerInfo *_info){
+ _ogg_free(_info->content_type);
+ _ogg_free(_info->server);
+ _ogg_free(_info->url);
+ _ogg_free(_info->genre);
+ _ogg_free(_info->description);
+ _ogg_free(_info->name);
+}
+
+/*The actual URL stream creation function.
+ This one isn't extensible like the application-level interface, but because
+ it isn't public, we're free to change it in the future.*/
+static void *op_url_stream_create_impl(OpusFileCallbacks *_cb,const char *_url,
+ int _skip_certificate_check,const char *_proxy_host,unsigned _proxy_port,
+ const char *_proxy_user,const char *_proxy_pass,OpusServerInfo *_info){
+ const char *path;
+ /*Check to see if this is a valid file: URL.*/
+ path=op_parse_file_url(_url);
+ if(path!=NULL){
+ char *unescaped_path;
+ void *ret;
+ unescaped_path=op_string_dup(path);
+ if(OP_UNLIKELY(unescaped_path==NULL))return NULL;
+ ret=op_fopen(_cb,op_unescape_url_component(unescaped_path),"rb");
+ _ogg_free(unescaped_path);
+ return ret;
+ }
+#if defined(OP_ENABLE_HTTP)
+ /*If not, try http/https.*/
+ else{
+ OpusHTTPStream *stream;
+ int ret;
+ stream=(OpusHTTPStream *)_ogg_malloc(sizeof(*stream));
+ if(OP_UNLIKELY(stream==NULL))return NULL;
+ op_http_stream_init(stream);
+ ret=op_http_stream_open(stream,_url,_skip_certificate_check,
+ _proxy_host,_proxy_port,_proxy_user,_proxy_pass,_info);
+ if(OP_UNLIKELY(ret<0)){
+ op_http_stream_clear(stream);
+ _ogg_free(stream);
+ return NULL;
+ }
+ *_cb=*&OP_HTTP_CALLBACKS;
+ return stream;
+ }
+#else
+ (void)_skip_certificate_check;
+ (void)_proxy_host;
+ (void)_proxy_port;
+ (void)_proxy_user;
+ (void)_proxy_pass;
+ (void)_info;
+ return NULL;
+#endif
+}
+
+void *op_url_stream_vcreate(OpusFileCallbacks *_cb,
+ const char *_url,va_list _ap){
+ int skip_certificate_check;
+ const char *proxy_host;
+ opus_int32 proxy_port;
+ const char *proxy_user;
+ const char *proxy_pass;
+ OpusServerInfo *pinfo;
+ skip_certificate_check=0;
+ proxy_host=NULL;
+ proxy_port=8080;
+ proxy_user=NULL;
+ proxy_pass=NULL;
+ pinfo=NULL;
+ for(;;){
+ ptrdiff_t request;
+ request=va_arg(_ap,char *)-(char *)NULL;
+ /*If we hit NULL, we're done processing options.*/
+ if(!request)break;
+ switch(request){
+ case OP_SSL_SKIP_CERTIFICATE_CHECK_REQUEST:{
+ skip_certificate_check=!!va_arg(_ap,opus_int32);
+ }break;
+ case OP_HTTP_PROXY_HOST_REQUEST:{
+ proxy_host=va_arg(_ap,const char *);
+ }break;
+ case OP_HTTP_PROXY_PORT_REQUEST:{
+ proxy_port=va_arg(_ap,opus_int32);
+ if(proxy_port<0||proxy_port>(opus_int32)65535)return NULL;
+ }break;
+ case OP_HTTP_PROXY_USER_REQUEST:{
+ proxy_user=va_arg(_ap,const char *);
+ }break;
+ case OP_HTTP_PROXY_PASS_REQUEST:{
+ proxy_pass=va_arg(_ap,const char *);
+ }break;
+ case OP_GET_SERVER_INFO_REQUEST:{
+ pinfo=va_arg(_ap,OpusServerInfo *);
+ }break;
+ /*Some unknown option.*/
+ default:return NULL;
+ }
+ }
+ /*If the caller has requested server information, proxy it to a local copy to
+ simplify error handling.*/
+ if(pinfo!=NULL){
+ OpusServerInfo info;
+ void *ret;
+ opus_server_info_init(&info);
+ ret=op_url_stream_create_impl(_cb,_url,skip_certificate_check,
+ proxy_host,proxy_port,proxy_user,proxy_pass,&info);
+ if(ret!=NULL)*pinfo=*&info;
+ else opus_server_info_clear(&info);
+ return ret;
+ }
+ return op_url_stream_create_impl(_cb,_url,skip_certificate_check,
+ proxy_host,proxy_port,proxy_user,proxy_pass,NULL);
+}
+
+void *op_url_stream_create(OpusFileCallbacks *_cb,
+ const char *_url,...){
+ va_list ap;
+ void *ret;
+ va_start(ap,_url);
+ ret=op_url_stream_vcreate(_cb,_url,ap);
+ va_end(ap);
+ return ret;
+}
+
+/*Convenience routines to open/test URLs in a single step.*/
+
+OggOpusFile *op_vopen_url(const char *_url,int *_error,va_list _ap){
+ OpusFileCallbacks cb;
+ OggOpusFile *of;
+ void *source;
+ source=op_url_stream_vcreate(&cb,_url,_ap);
+ if(OP_UNLIKELY(source==NULL)){
+ if(_error!=NULL)*_error=OP_EFAULT;
+ return NULL;
+ }
+ of=op_open_callbacks(source,&cb,NULL,0,_error);
+ if(OP_UNLIKELY(of==NULL))(*cb.close)(source);
+ return of;
+}
+
+OggOpusFile *op_open_url(const char *_url,int *_error,...){
+ OggOpusFile *ret;
+ va_list ap;
+ va_start(ap,_error);
+ ret=op_vopen_url(_url,_error,ap);
+ va_end(ap);
+ return ret;
+}
+
+OggOpusFile *op_vtest_url(const char *_url,int *_error,va_list _ap){
+ OpusFileCallbacks cb;
+ OggOpusFile *of;
+ void *source;
+ source=op_url_stream_vcreate(&cb,_url,_ap);
+ if(OP_UNLIKELY(source==NULL)){
+ if(_error!=NULL)*_error=OP_EFAULT;
+ return NULL;
+ }
+ of=op_test_callbacks(source,&cb,NULL,0,_error);
+ if(OP_UNLIKELY(of==NULL))(*cb.close)(source);
+ return of;
+}
+
+OggOpusFile *op_test_url(const char *_url,int *_error,...){
+ OggOpusFile *ret;
+ va_list ap;
+ va_start(ap,_error);
+ ret=op_vtest_url(_url,_error,ap);
+ va_end(ap);
+ return ret;
+}
diff --git a/drivers/opus/info.c b/drivers/opus/info.c
new file mode 100644
index 0000000000..8175a013ac
--- /dev/null
+++ b/drivers/opus/info.c
@@ -0,0 +1,687 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012 *
+ * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
+ * *
+ ********************************************************************/
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/internal.h"
+#include <limits.h>
+#include <string.h>
+
+static unsigned op_parse_uint16le(const unsigned char *_data){
+ return _data[0]|_data[1]<<8;
+}
+
+static int op_parse_int16le(const unsigned char *_data){
+ int ret;
+ ret=_data[0]|_data[1]<<8;
+ return (ret^0x8000)-0x8000;
+}
+
+static opus_uint32 op_parse_uint32le(const unsigned char *_data){
+ return _data[0]|(opus_uint32)_data[1]<<8|
+ (opus_uint32)_data[2]<<16|(opus_uint32)_data[3]<<24;
+}
+
+static opus_uint32 op_parse_uint32be(const unsigned char *_data){
+ return _data[3]|(opus_uint32)_data[2]<<8|
+ (opus_uint32)_data[1]<<16|(opus_uint32)_data[0]<<24;
+}
+
+int opus_head_parse(OpusHead *_head,const unsigned char *_data,size_t _len){
+ OpusHead head;
+ if(_len<8)return OP_ENOTFORMAT;
+ if(memcmp(_data,"OpusHead",8)!=0)return OP_ENOTFORMAT;
+ if(_len<9)return OP_EBADHEADER;
+ head.version=_data[8];
+ if(head.version>15)return OP_EVERSION;
+ if(_len<19)return OP_EBADHEADER;
+ head.channel_count=_data[9];
+ head.pre_skip=op_parse_uint16le(_data+10);
+ head.input_sample_rate=op_parse_uint32le(_data+12);
+ head.output_gain=op_parse_int16le(_data+16);
+ head.mapping_family=_data[18];
+ if(head.mapping_family==0){
+ if(head.channel_count<1||head.channel_count>2)return OP_EBADHEADER;
+ if(head.version<=1&&_len>19)return OP_EBADHEADER;
+ head.stream_count=1;
+ head.coupled_count=head.channel_count-1;
+ if(_head!=NULL){
+ _head->mapping[0]=0;
+ _head->mapping[1]=1;
+ }
+ }
+ else if(head.mapping_family==1){
+ size_t size;
+ int ci;
+ if(head.channel_count<1||head.channel_count>8)return OP_EBADHEADER;
+ size=21+head.channel_count;
+ if(_len<size||head.version<=1&&_len>size)return OP_EBADHEADER;
+ head.stream_count=_data[19];
+ if(head.stream_count<1)return OP_EBADHEADER;
+ head.coupled_count=_data[20];
+ if(head.coupled_count>head.stream_count)return OP_EBADHEADER;
+ for(ci=0;ci<head.channel_count;ci++){
+ if(_data[21+ci]>=head.stream_count+head.coupled_count
+ &&_data[21+ci]!=255){
+ return OP_EBADHEADER;
+ }
+ }
+ if(_head!=NULL)memcpy(_head->mapping,_data+21,head.channel_count);
+ }
+ /*General purpose players should not attempt to play back content with
+ channel mapping family 255.*/
+ else if(head.mapping_family==255)return OP_EIMPL;
+ /*No other channel mapping families are currently defined.*/
+ else return OP_EBADHEADER;
+ if(_head!=NULL)memcpy(_head,&head,head.mapping-(unsigned char *)&head);
+ return 0;
+}
+
+void opus_tags_init(OpusTags *_tags){
+ memset(_tags,0,sizeof(*_tags));
+}
+
+void opus_tags_clear(OpusTags *_tags){
+ int ci;
+ for(ci=_tags->comments;ci-->0;)_ogg_free(_tags->user_comments[ci]);
+ _ogg_free(_tags->user_comments);
+ _ogg_free(_tags->comment_lengths);
+ _ogg_free(_tags->vendor);
+}
+
+/*Ensure there's room for up to _ncomments comments.*/
+static int op_tags_ensure_capacity(OpusTags *_tags,size_t _ncomments){
+ char **user_comments;
+ int *comment_lengths;
+ size_t size;
+ if(OP_UNLIKELY(_ncomments>=(size_t)INT_MAX))return OP_EFAULT;
+ size=sizeof(*_tags->comment_lengths)*(_ncomments+1);
+ if(size/sizeof(*_tags->comment_lengths)!=_ncomments+1)return OP_EFAULT;
+ comment_lengths=(int *)_ogg_realloc(_tags->comment_lengths,size);
+ if(OP_UNLIKELY(comment_lengths==NULL))return OP_EFAULT;
+ comment_lengths[_ncomments]=0;
+ _tags->comment_lengths=comment_lengths;
+ size=sizeof(*_tags->user_comments)*(_ncomments+1);
+ if(size/sizeof(*_tags->user_comments)!=_ncomments+1)return OP_EFAULT;
+ user_comments=(char **)_ogg_realloc(_tags->user_comments,size);
+ if(OP_UNLIKELY(user_comments==NULL))return OP_EFAULT;
+ user_comments[_ncomments]=NULL;
+ _tags->user_comments=user_comments;
+ return 0;
+}
+
+/*Duplicate a (possibly non-NUL terminated) string with a known length.*/
+static char *op_strdup_with_len(const char *_s,size_t _len){
+ size_t size;
+ char *ret;
+ size=sizeof(*ret)*(_len+1);
+ if(OP_UNLIKELY(size<_len))return NULL;
+ ret=(char *)_ogg_malloc(size);
+ if(OP_LIKELY(ret!=NULL)){
+ ret=(char *)memcpy(ret,_s,sizeof(*ret)*_len);
+ ret[_len]='\0';
+ }
+ return ret;
+}
+
+/*The actual implementation of opus_tags_parse().
+ Unlike the public API, this function requires _tags to already be
+ initialized, modifies its contents before success is guaranteed, and assumes
+ the caller will clear it on error.*/
+static int opus_tags_parse_impl(OpusTags *_tags,
+ const unsigned char *_data,size_t _len){
+ opus_uint32 count;
+ size_t len;
+ int ncomments;
+ int ci;
+ len=_len;
+ if(len<8)return OP_ENOTFORMAT;
+ if(memcmp(_data,"OpusTags",8)!=0)return OP_ENOTFORMAT;
+ if(len<16)return OP_EBADHEADER;
+ _data+=8;
+ len-=8;
+ count=op_parse_uint32le(_data);
+ _data+=4;
+ len-=4;
+ if(count>len)return OP_EBADHEADER;
+ if(_tags!=NULL){
+ _tags->vendor=op_strdup_with_len((char *)_data,count);
+ if(_tags->vendor==NULL)return OP_EFAULT;
+ }
+ _data+=count;
+ len-=count;
+ if(len<4)return OP_EBADHEADER;
+ count=op_parse_uint32le(_data);
+ _data+=4;
+ len-=4;
+ /*Check to make sure there's minimally sufficient data left in the packet.*/
+ if(count>len>>2)return OP_EBADHEADER;
+ /*Check for overflow (the API limits this to an int).*/
+ if(count>(opus_uint32)INT_MAX-1)return OP_EFAULT;
+ if(_tags!=NULL){
+ int ret;
+ ret=op_tags_ensure_capacity(_tags,count);
+ if(ret<0)return ret;
+ }
+ ncomments=(int)count;
+ for(ci=0;ci<ncomments;ci++){
+ /*Check to make sure there's minimally sufficient data left in the packet.*/
+ if((size_t)(ncomments-ci)>len>>2)return OP_EBADHEADER;
+ count=op_parse_uint32le(_data);
+ _data+=4;
+ len-=4;
+ if(count>len)return OP_EBADHEADER;
+ /*Check for overflow (the API limits this to an int).*/
+ if(count>(opus_uint32)INT_MAX)return OP_EFAULT;
+ if(_tags!=NULL){
+ _tags->user_comments[ci]=op_strdup_with_len((char *)_data,count);
+ if(_tags->user_comments[ci]==NULL)return OP_EFAULT;
+ _tags->comment_lengths[ci]=(int)count;
+ _tags->comments=ci+1;
+ }
+ _data+=count;
+ len-=count;
+ }
+ return 0;
+}
+
+int opus_tags_parse(OpusTags *_tags,const unsigned char *_data,size_t _len){
+ if(_tags!=NULL){
+ OpusTags tags;
+ int ret;
+ opus_tags_init(&tags);
+ ret=opus_tags_parse_impl(&tags,_data,_len);
+ if(ret<0)opus_tags_clear(&tags);
+ else *_tags=*&tags;
+ return ret;
+ }
+ else return opus_tags_parse_impl(NULL,_data,_len);
+}
+
+/*The actual implementation of opus_tags_copy().
+ Unlike the public API, this function requires _dst to already be
+ initialized, modifies its contents before success is guaranteed, and assumes
+ the caller will clear it on error.*/
+static int opus_tags_copy_impl(OpusTags *_dst,const OpusTags *_src){
+ char *vendor;
+ int ncomments;
+ int ret;
+ int ci;
+ vendor=_src->vendor;
+ _dst->vendor=op_strdup_with_len(vendor,strlen(vendor));
+ if(OP_UNLIKELY(_dst->vendor==NULL))return OP_EFAULT;
+ ncomments=_src->comments;
+ ret=op_tags_ensure_capacity(_dst,ncomments);
+ if(OP_UNLIKELY(ret<0))return ret;
+ for(ci=0;ci<ncomments;ci++){
+ int len;
+ len=_src->comment_lengths[ci];
+ OP_ASSERT(len>=0);
+ _dst->user_comments[ci]=op_strdup_with_len(_src->user_comments[ci],len);
+ if(OP_UNLIKELY(_dst->user_comments[ci]==NULL))return OP_EFAULT;
+ _dst->comment_lengths[ci]=len;
+ _dst->comments=ci+1;
+ }
+ return 0;
+}
+
+int opus_tags_copy(OpusTags *_dst,const OpusTags *_src){
+ OpusTags dst;
+ int ret;
+ opus_tags_init(&dst);
+ ret=opus_tags_copy_impl(&dst,_src);
+ if(OP_UNLIKELY(ret<0))opus_tags_clear(&dst);
+ else *_dst=*&dst;
+ return 0;
+}
+
+int opus_tags_add(OpusTags *_tags,const char *_tag,const char *_value){
+ char *comment;
+ int tag_len;
+ int value_len;
+ int ncomments;
+ int ret;
+ ncomments=_tags->comments;
+ ret=op_tags_ensure_capacity(_tags,ncomments+1);
+ if(OP_UNLIKELY(ret<0))return ret;
+ tag_len=strlen(_tag);
+ value_len=strlen(_value);
+ /*+2 for '=' and '\0'.*/
+ _tags->comment_lengths[ncomments]=0;
+ _tags->user_comments[ncomments]=comment=
+ (char *)_ogg_malloc(sizeof(*comment)*(tag_len+value_len+2));
+ if(OP_UNLIKELY(comment==NULL))return OP_EFAULT;
+ memcpy(comment,_tag,sizeof(*comment)*tag_len);
+ comment[tag_len]='=';
+ memcpy(comment+tag_len+1,_value,sizeof(*comment)*(value_len+1));
+ _tags->comment_lengths[ncomments]=tag_len+value_len+1;
+ _tags->comments=ncomments+1;
+ return 0;
+}
+
+int opus_tags_add_comment(OpusTags *_tags,const char *_comment){
+ int comment_len;
+ int ncomments;
+ int ret;
+ ncomments=_tags->comments;
+ ret=op_tags_ensure_capacity(_tags,ncomments+1);
+ if(OP_UNLIKELY(ret<0))return ret;
+ comment_len=(int)strlen(_comment);
+ _tags->comment_lengths[ncomments]=0;
+ _tags->user_comments[ncomments]=op_strdup_with_len(_comment,comment_len);
+ if(OP_UNLIKELY(_tags->user_comments[ncomments]==NULL))return OP_EFAULT;
+ _tags->comment_lengths[ncomments]=comment_len;
+ _tags->comments=ncomments+1;
+ return 0;
+}
+
+int opus_tagcompare(const char *_tag_name,const char *_comment){
+ return opus_tagncompare(_tag_name,strlen(_tag_name),_comment);
+}
+
+int opus_tagncompare(const char *_tag_name,int _tag_len,const char *_comment){
+ int ret;
+ OP_ASSERT(_tag_len>=0);
+ ret=op_strncasecmp(_tag_name,_comment,_tag_len);
+ return ret?ret:'='-_comment[_tag_len];
+}
+
+const char *opus_tags_query(const OpusTags *_tags,const char *_tag,int _count){
+ char **user_comments;
+ int tag_len;
+ int found;
+ int ncomments;
+ int ci;
+ tag_len=strlen(_tag);
+ ncomments=_tags->comments;
+ user_comments=_tags->user_comments;
+ found=0;
+ for(ci=0;ci<ncomments;ci++){
+ if(!opus_tagncompare(_tag,tag_len,user_comments[ci])){
+ /*We return a pointer to the data, not a copy.*/
+ if(_count==found++)return user_comments[ci]+tag_len+1;
+ }
+ }
+ /*Didn't find anything.*/
+ return NULL;
+}
+
+int opus_tags_query_count(const OpusTags *_tags,const char *_tag){
+ char **user_comments;
+ int tag_len;
+ int found;
+ int ncomments;
+ int ci;
+ tag_len=strlen(_tag);
+ ncomments=_tags->comments;
+ user_comments=_tags->user_comments;
+ found=0;
+ for(ci=0;ci<ncomments;ci++){
+ if(!opus_tagncompare(_tag,tag_len,user_comments[ci]))found++;
+ }
+ return found;
+}
+
+int opus_tags_get_track_gain(const OpusTags *_tags,int *_gain_q8){
+ char **comments;
+ int ncomments;
+ int ci;
+ comments=_tags->user_comments;
+ ncomments=_tags->comments;
+ /*Look for the first valid R128_TRACK_GAIN tag and use that.*/
+ for(ci=0;ci<ncomments;ci++){
+ if(opus_tagncompare("R128_TRACK_GAIN",15,comments[ci])==0){
+ char *p;
+ opus_int32 gain_q8;
+ int negative;
+ p=comments[ci]+16;
+ negative=0;
+ if(*p=='-'){
+ negative=-1;
+ p++;
+ }
+ else if(*p=='+')p++;
+ gain_q8=0;
+ while(*p>='0'&&*p<='9'){
+ gain_q8=10*gain_q8+*p-'0';
+ if(gain_q8>32767-negative)break;
+ p++;
+ }
+ /*This didn't look like a signed 16-bit decimal integer.
+ Not a valid R128_TRACK_GAIN tag.*/
+ if(*p!='\0')continue;
+ *_gain_q8=(int)(gain_q8+negative^negative);
+ return 0;
+ }
+ }
+ return OP_FALSE;
+}
+
+static int op_is_jpeg(const unsigned char *_buf,size_t _buf_sz){
+ return _buf_sz>=11&&memcmp(_buf,"\xFF\xD8\xFF\xE0",4)==0
+ &&(_buf[4]<<8|_buf[5])>=16&&memcmp(_buf+6,"JFIF",5)==0;
+}
+
+/*Tries to extract the width, height, bits per pixel, and palette size of a
+ JPEG.
+ On failure, simply leaves its outputs unmodified.*/
+static void op_extract_jpeg_params(const unsigned char *_buf,size_t _buf_sz,
+ opus_uint32 *_width,opus_uint32 *_height,
+ opus_uint32 *_depth,opus_uint32 *_colors,int *_has_palette){
+ if(op_is_jpeg(_buf,_buf_sz)){
+ size_t offs;
+ offs=2;
+ for(;;){
+ size_t segment_len;
+ int marker;
+ while(offs<_buf_sz&&_buf[offs]!=0xFF)offs++;
+ while(offs<_buf_sz&&_buf[offs]==0xFF)offs++;
+ marker=_buf[offs];
+ offs++;
+ /*If we hit EOI* (end of image), or another SOI* (start of image),
+ or SOS (start of scan), then stop now.*/
+ if(offs>=_buf_sz||(marker>=0xD8&&marker<=0xDA))break;
+ /*RST* (restart markers): skip (no segment length).*/
+ else if(marker>=0xD0&&marker<=0xD7)continue;
+ /*Read the length of the marker segment.*/
+ if(_buf_sz-offs<2)break;
+ segment_len=_buf[offs]<<8|_buf[offs+1];
+ if(segment_len<2||_buf_sz-offs<segment_len)break;
+ if(marker==0xC0||(marker>0xC0&&marker<0xD0&&(marker&3)!=0)){
+ /*Found a SOFn (start of frame) marker segment:*/
+ if(segment_len>=8){
+ *_height=_buf[offs+3]<<8|_buf[offs+4];
+ *_width=_buf[offs+5]<<8|_buf[offs+6];
+ *_depth=_buf[offs+2]*_buf[offs+7];
+ *_colors=0;
+ *_has_palette=0;
+ }
+ break;
+ }
+ /*Other markers: skip the whole marker segment.*/
+ offs+=segment_len;
+ }
+ }
+}
+
+static int op_is_png(const unsigned char *_buf,size_t _buf_sz){
+ return _buf_sz>=8&&memcmp(_buf,"\x89PNG\x0D\x0A\x1A\x0A",8)==0;
+}
+
+/*Tries to extract the width, height, bits per pixel, and palette size of a
+ PNG.
+ On failure, simply leaves its outputs unmodified.*/
+static void op_extract_png_params(const unsigned char *_buf,size_t _buf_sz,
+ opus_uint32 *_width,opus_uint32 *_height,
+ opus_uint32 *_depth,opus_uint32 *_colors,int *_has_palette){
+ if(op_is_png(_buf,_buf_sz)){
+ size_t offs;
+ offs=8;
+ while(_buf_sz-offs>=12){
+ ogg_uint32_t chunk_len;
+ chunk_len=op_parse_uint32be(_buf+offs);
+ if(chunk_len>_buf_sz-(offs+12))break;
+ else if(chunk_len==13&&memcmp(_buf+offs+4,"IHDR",4)==0){
+ int color_type;
+ *_width=op_parse_uint32be(_buf+offs+8);
+ *_height=op_parse_uint32be(_buf+offs+12);
+ color_type=_buf[offs+17];
+ if(color_type==3){
+ *_depth=24;
+ *_has_palette=1;
+ }
+ else{
+ int sample_depth;
+ sample_depth=_buf[offs+16];
+ if(color_type==0)*_depth=sample_depth;
+ else if(color_type==2)*_depth=sample_depth*3;
+ else if(color_type==4)*_depth=sample_depth*2;
+ else if(color_type==6)*_depth=sample_depth*4;
+ *_colors=0;
+ *_has_palette=0;
+ break;
+ }
+ }
+ else if(*_has_palette>0&&memcmp(_buf+offs+4,"PLTE",4)==0){
+ *_colors=chunk_len/3;
+ break;
+ }
+ offs+=12+chunk_len;
+ }
+ }
+}
+
+static int op_is_gif(const unsigned char *_buf,size_t _buf_sz){
+ return _buf_sz>=6&&(memcmp(_buf,"GIF87a",6)==0||memcmp(_buf,"GIF89a",6)==0);
+}
+
+/*Tries to extract the width, height, bits per pixel, and palette size of a
+ GIF.
+ On failure, simply leaves its outputs unmodified.*/
+static void op_extract_gif_params(const unsigned char *_buf,size_t _buf_sz,
+ opus_uint32 *_width,opus_uint32 *_height,
+ opus_uint32 *_depth,opus_uint32 *_colors,int *_has_palette){
+ if(op_is_gif(_buf,_buf_sz)&&_buf_sz>=14){
+ *_width=_buf[6]|_buf[7]<<8;
+ *_height=_buf[8]|_buf[9]<<8;
+ /*libFLAC hard-codes the depth to 24.*/
+ *_depth=24;
+ *_colors=1<<((_buf[10]&7)+1);
+ *_has_palette=1;
+ }
+}
+
+/*The actual implementation of opus_picture_tag_parse().
+ Unlike the public API, this function requires _pic to already be
+ initialized, modifies its contents before success is guaranteed, and assumes
+ the caller will clear it on error.*/
+static int opus_picture_tag_parse_impl(OpusPictureTag *_pic,const char *_tag,
+ unsigned char *_buf,size_t _buf_sz,size_t _base64_sz){
+ opus_int32 picture_type;
+ opus_uint32 mime_type_length;
+ char *mime_type;
+ opus_uint32 description_length;
+ char *description;
+ opus_uint32 width;
+ opus_uint32 height;
+ opus_uint32 depth;
+ opus_uint32 colors;
+ opus_uint32 data_length;
+ opus_uint32 file_width;
+ opus_uint32 file_height;
+ opus_uint32 file_depth;
+ opus_uint32 file_colors;
+ int format;
+ int has_palette;
+ int colors_set;
+ size_t i;
+ /*Decode the BASE64 data.*/
+ for(i=0;i<_base64_sz;i++){
+ opus_uint32 value;
+ int j;
+ value=0;
+ for(j=0;j<4;j++){
+ unsigned c;
+ unsigned d;
+ c=(unsigned char)_tag[4*i+j];
+ if(c=='+')d=62;
+ else if(c=='/')d=63;
+ else if(c>='0'&&c<='9')d=52+c-'0';
+ else if(c>='a'&&c<='z')d=26+c-'a';
+ else if(c>='A'&&c<='Z')d=c-'A';
+ else if(c=='='&&3*i+j>_buf_sz)d=0;
+ else return OP_ENOTFORMAT;
+ value=value<<6|d;
+ }
+ _buf[3*i]=(unsigned char)(value>>16);
+ if(3*i+1<_buf_sz){
+ _buf[3*i+1]=(unsigned char)(value>>8);
+ if(3*i+2<_buf_sz)_buf[3*i+2]=(unsigned char)value;
+ }
+ }
+ i=0;
+ picture_type=op_parse_uint32be(_buf+i);
+ i+=4;
+ /*Extract the MIME type.*/
+ mime_type_length=op_parse_uint32be(_buf+i);
+ i+=4;
+ if(mime_type_length>_buf_sz-32)return OP_ENOTFORMAT;
+ mime_type=(char *)_ogg_malloc(sizeof(*_pic->mime_type)*(mime_type_length+1));
+ if(mime_type==NULL)return OP_EFAULT;
+ memcpy(mime_type,_buf+i,sizeof(*mime_type)*mime_type_length);
+ mime_type[mime_type_length]='\0';
+ _pic->mime_type=mime_type;
+ i+=mime_type_length;
+ /*Extract the description string.*/
+ description_length=op_parse_uint32be(_buf+i);
+ i+=4;
+ if(description_length>_buf_sz-mime_type_length-32)return OP_ENOTFORMAT;
+ description=
+ (char *)_ogg_malloc(sizeof(*_pic->mime_type)*(description_length+1));
+ if(description==NULL)return OP_EFAULT;
+ memcpy(description,_buf+i,sizeof(*description)*description_length);
+ description[description_length]='\0';
+ _pic->description=description;
+ i+=description_length;
+ /*Extract the remaining fields.*/
+ width=op_parse_uint32be(_buf+i);
+ i+=4;
+ height=op_parse_uint32be(_buf+i);
+ i+=4;
+ depth=op_parse_uint32be(_buf+i);
+ i+=4;
+ colors=op_parse_uint32be(_buf+i);
+ i+=4;
+ /*If one of these is set, they all must be, but colors==0 is a valid value.*/
+ colors_set=width!=0||height!=0||depth!=0||colors!=0;
+ if((width==0||height==0||depth==0)&&colors_set)return OP_ENOTFORMAT;
+ data_length=op_parse_uint32be(_buf+i);
+ i+=4;
+ if(data_length>_buf_sz-i)return OP_ENOTFORMAT;
+ /*Trim extraneous data so we don't copy it below.*/
+ _buf_sz=i+data_length;
+ /*Attempt to determine the image format.*/
+ format=OP_PIC_FORMAT_UNKNOWN;
+ if(mime_type_length==3&&strcmp(mime_type,"-->")==0){
+ format=OP_PIC_FORMAT_URL;
+ /*Picture type 1 must be a 32x32 PNG.*/
+ if(picture_type==1&&(width!=0||height!=0)&&(width!=32||height!=32)){
+ return OP_ENOTFORMAT;
+ }
+ /*Append a terminating NUL for the convenience of our callers.*/
+ _buf[_buf_sz++]='\0';
+ }
+ else{
+ if(mime_type_length==10
+ &&op_strncasecmp(mime_type,"image/jpeg",mime_type_length)==0){
+ if(op_is_jpeg(_buf+i,data_length))format=OP_PIC_FORMAT_JPEG;
+ }
+ else if(mime_type_length==9
+ &&op_strncasecmp(mime_type,"image/png",mime_type_length)==0){
+ if(op_is_png(_buf+i,data_length))format=OP_PIC_FORMAT_PNG;
+ }
+ else if(mime_type_length==9
+ &&op_strncasecmp(mime_type,"image/gif",mime_type_length)==0){
+ if(op_is_gif(_buf+i,data_length))format=OP_PIC_FORMAT_GIF;
+ }
+ else if(mime_type_length==0||(mime_type_length==6
+ &&op_strncasecmp(mime_type,"image/",mime_type_length)==0)){
+ if(op_is_jpeg(_buf+i,data_length))format=OP_PIC_FORMAT_JPEG;
+ else if(op_is_png(_buf+i,data_length))format=OP_PIC_FORMAT_PNG;
+ else if(op_is_gif(_buf+i,data_length))format=OP_PIC_FORMAT_GIF;
+ }
+ file_width=file_height=file_depth=file_colors=0;
+ has_palette=-1;
+ switch(format){
+ case OP_PIC_FORMAT_JPEG:{
+ op_extract_jpeg_params(_buf+i,data_length,
+ &file_width,&file_height,&file_depth,&file_colors,&has_palette);
+ }break;
+ case OP_PIC_FORMAT_PNG:{
+ op_extract_png_params(_buf+i,data_length,
+ &file_width,&file_height,&file_depth,&file_colors,&has_palette);
+ }break;
+ case OP_PIC_FORMAT_GIF:{
+ op_extract_gif_params(_buf+i,data_length,
+ &file_width,&file_height,&file_depth,&file_colors,&has_palette);
+ }break;
+ }
+ if(has_palette>=0){
+ /*If we successfully extracted these parameters from the image, override
+ any declared values.*/
+ width=file_width;
+ height=file_height;
+ depth=file_depth;
+ colors=file_colors;
+ }
+ /*Picture type 1 must be a 32x32 PNG.*/
+ if(picture_type==1&&(format!=OP_PIC_FORMAT_PNG||width!=32||height!=32)){
+ return OP_ENOTFORMAT;
+ }
+ }
+ /*Adjust _buf_sz instead of using data_length to capture the terminating NUL
+ for URLs.*/
+ _buf_sz-=i;
+ memmove(_buf,_buf+i,sizeof(*_buf)*_buf_sz);
+ _buf=(unsigned char *)_ogg_realloc(_buf,_buf_sz);
+ if(_buf_sz>0&&_buf==NULL)return OP_EFAULT;
+ _pic->type=picture_type;
+ _pic->width=width;
+ _pic->height=height;
+ _pic->depth=depth;
+ _pic->colors=colors;
+ _pic->data_length=data_length;
+ _pic->data=_buf;
+ _pic->format=format;
+ return 0;
+}
+
+int opus_picture_tag_parse(OpusPictureTag *_pic,const char *_tag){
+ OpusPictureTag pic;
+ unsigned char *buf;
+ size_t base64_sz;
+ size_t buf_sz;
+ size_t tag_length;
+ int ret;
+ if(opus_tagncompare("METADATA_BLOCK_PICTURE",22,_tag)==0)_tag+=23;
+ /*Figure out how much BASE64-encoded data we have.*/
+ tag_length=strlen(_tag);
+ if(tag_length&3)return OP_ENOTFORMAT;
+ base64_sz=tag_length>>2;
+ buf_sz=3*base64_sz;
+ if(buf_sz<32)return OP_ENOTFORMAT;
+ if(_tag[tag_length-1]=='=')buf_sz--;
+ if(_tag[tag_length-2]=='=')buf_sz--;
+ if(buf_sz<32)return OP_ENOTFORMAT;
+ /*Allocate an extra byte to allow appending a terminating NUL to URL data.*/
+ buf=(unsigned char *)_ogg_malloc(sizeof(*buf)*(buf_sz+1));
+ if(buf==NULL)return OP_EFAULT;
+ opus_picture_tag_init(&pic);
+ ret=opus_picture_tag_parse_impl(&pic,_tag,buf,buf_sz,base64_sz);
+ if(ret<0){
+ opus_picture_tag_clear(&pic);
+ _ogg_free(buf);
+ }
+ else *_pic=*&pic;
+ return ret;
+}
+
+void opus_picture_tag_init(OpusPictureTag *_pic){
+ memset(_pic,0,sizeof(*_pic));
+}
+
+void opus_picture_tag_clear(OpusPictureTag *_pic){
+ _ogg_free(_pic->description);
+ _ogg_free(_pic->mime_type);
+ _ogg_free(_pic->data);
+}
diff --git a/drivers/opus/internal.c b/drivers/opus/internal.c
new file mode 100644
index 0000000000..d73628ec53
--- /dev/null
+++ b/drivers/opus/internal.c
@@ -0,0 +1,42 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012 *
+ * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
+ * *
+ ********************************************************************/
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/internal.h"
+
+#if defined(OP_ENABLE_ASSERTIONS)
+void op_fatal_impl(const char *_str,const char *_file,int _line){
+ fprintf(stderr,"Fatal (internal) error in %s, line %i: %s\n",
+ _file,_line,_str);
+ abort();
+}
+#endif
+
+/*A version of strncasecmp() that is guaranteed to only ignore the case of
+ ASCII characters.*/
+int op_strncasecmp(const char *_a,const char *_b,int _n){
+ int i;
+ for(i=0;i<_n;i++){
+ int a;
+ int b;
+ int d;
+ a=_a[i];
+ b=_b[i];
+ if(a>='a'&&a<='z')a-='a'-'A';
+ if(b>='a'&&b<='z')b-='a'-'A';
+ d=a-b;
+ if(d)return d;
+ }
+ return 0;
+}
diff --git a/drivers/opus/internal.h b/drivers/opus/internal.h
new file mode 100644
index 0000000000..cb4089fd4d
--- /dev/null
+++ b/drivers/opus/internal.h
@@ -0,0 +1,249 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012 *
+ * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
+ * *
+ ********************************************************************/
+#if !defined(_opusfile_internal_h)
+# define _opusfile_internal_h (1)
+
+# if !defined(_REENTRANT)
+# define _REENTRANT
+# endif
+# if !defined(_GNU_SOURCE)
+# define _GNU_SOURCE
+# endif
+# if !defined(_LARGEFILE_SOURCE)
+# define _LARGEFILE_SOURCE
+# endif
+# if !defined(_LARGEFILE64_SOURCE)
+# define _LARGEFILE64_SOURCE
+# endif
+# if !defined(_FILE_OFFSET_BITS)
+# define _FILE_OFFSET_BITS 64
+# endif
+
+# include <stdlib.h>
+# include <opus/opusfile.h>
+
+typedef struct OggOpusLink OggOpusLink;
+
+# if defined(OPUS_FIXED_POINT)
+
+typedef opus_int16 op_sample;
+
+# else
+
+typedef float op_sample;
+
+/*We're using this define to test for libopus 1.1 or later until libopus
+ provides a better mechanism.*/
+# if defined(OPUS_GET_EXPERT_FRAME_DURATION_REQUEST)
+/*Enable soft clipping prevention in 16-bit decodes.*/
+# define OP_SOFT_CLIP (1)
+# endif
+
+# endif
+
+# if OP_GNUC_PREREQ(4,2)
+/*Disable excessive warnings about the order of operations.*/
+# pragma GCC diagnostic ignored "-Wparentheses"
+# elif defined(_MSC_VER)
+/*Disable excessive warnings about the order of operations.*/
+# pragma warning(disable:4554)
+/*Disable warnings about "deprecated" POSIX functions.*/
+# pragma warning(disable:4996)
+# endif
+
+# if OP_GNUC_PREREQ(3,0)
+/*Another alternative is
+ (__builtin_constant_p(_x)?!!(_x):__builtin_expect(!!(_x),1))
+ but that evaluates _x multiple times, which may be bad.*/
+# define OP_LIKELY(_x) (__builtin_expect(!!(_x),1))
+# define OP_UNLIKELY(_x) (__builtin_expect(!!(_x),0))
+# else
+# define OP_LIKELY(_x) (!!(_x))
+# define OP_UNLIKELY(_x) (!!(_x))
+# endif
+
+# if defined(OP_ENABLE_ASSERTIONS)
+# if OP_GNUC_PREREQ(2,5)||__SUNPRO_C>=0x590
+__attribute__((noreturn))
+# endif
+void op_fatal_impl(const char *_str,const char *_file,int _line);
+
+# define OP_FATAL(_str) (op_fatal_impl(_str,__FILE__,__LINE__))
+
+# define OP_ASSERT(_cond) \
+ do{ \
+ if(OP_UNLIKELY(!(_cond)))OP_FATAL("assertion failed: " #_cond); \
+ } \
+ while(0)
+# define OP_ALWAYS_TRUE(_cond) OP_ASSERT(_cond)
+
+# else
+# define OP_FATAL(_str) abort()
+# define OP_ASSERT(_cond)
+# define OP_ALWAYS_TRUE(_cond) ((void)(_cond))
+# endif
+
+# define OP_INT64_MAX (2*(((ogg_int64_t)1<<62)-1)|1)
+# define OP_INT64_MIN (-OP_INT64_MAX-1)
+# define OP_INT32_MAX (2*(((ogg_int32_t)1<<30)-1)|1)
+# define OP_INT32_MIN (-OP_INT32_MAX-1)
+
+# define OP_MIN(_a,_b) ((_a)<(_b)?(_a):(_b))
+# define OP_MAX(_a,_b) ((_a)>(_b)?(_a):(_b))
+# define OP_CLAMP(_lo,_x,_hi) (OP_MAX(_lo,OP_MIN(_x,_hi)))
+
+/*Advance a file offset by the given amount, clamping against OP_INT64_MAX.
+ This is used to advance a known offset by things like OP_CHUNK_SIZE or
+ OP_PAGE_SIZE_MAX, while making sure to avoid signed overflow.
+ It assumes that both _offset and _amount are non-negative.*/
+#define OP_ADV_OFFSET(_offset,_amount) \
+ (OP_MIN(_offset,OP_INT64_MAX-(_amount))+(_amount))
+
+/*The maximum channel count for any mapping we'll actually decode.*/
+# define OP_NCHANNELS_MAX (8)
+
+/*Initial state.*/
+# define OP_NOTOPEN (0)
+/*We've found the first Opus stream in the first link.*/
+# define OP_PARTOPEN (1)
+# define OP_OPENED (2)
+/*We've found the first Opus stream in the current link.*/
+# define OP_STREAMSET (3)
+/*We've initialized the decoder for the chosen Opus stream in the current
+ link.*/
+# define OP_INITSET (4)
+
+/*Information cached for a single link in a chained Ogg Opus file.
+ We choose the first Opus stream encountered in each link to play back (and
+ require at least one).*/
+struct OggOpusLink{
+ /*The byte offset of the first header page in this link.*/
+ opus_int64 offset;
+ /*The byte offset of the first data page from the chosen Opus stream in this
+ link (after the headers).*/
+ opus_int64 data_offset;
+ /*The byte offset of the last page from the chosen Opus stream in this link.
+ This is used when seeking to ensure we find a page before the last one, so
+ that end-trimming calculations work properly.
+ This is only valid for seekable sources.*/
+ opus_int64 end_offset;
+ /*The granule position of the last sample.
+ This is only valid for seekable sources.*/
+ ogg_int64_t pcm_end;
+ /*The granule position before the first sample.*/
+ ogg_int64_t pcm_start;
+ /*The serial number.*/
+ ogg_uint32_t serialno;
+ /*The contents of the info header.*/
+ OpusHead head;
+ /*The contents of the comment header.*/
+ OpusTags tags;
+};
+
+struct OggOpusFile{
+ /*The callbacks used to access the data source.*/
+ OpusFileCallbacks callbacks;
+ /*A FILE *, memory bufer, etc.*/
+ void *source;
+ /*Whether or not we can seek with this data source.*/
+ int seekable;
+ /*The number of links in this chained Ogg Opus file.*/
+ int nlinks;
+ /*The cached information from each link in a chained Ogg Opus file.
+ If source isn't seekable (e.g., it's a pipe), only the current link
+ appears.*/
+ OggOpusLink *links;
+ /*The number of serial numbers from a single link.*/
+ int nserialnos;
+ /*The capacity of the list of serial numbers from a single link.*/
+ int cserialnos;
+ /*Storage for the list of serial numbers from a single link.*/
+ ogg_uint32_t *serialnos;
+ /*This is the current offset of the data processed by the ogg_sync_state.
+ After a seek, this should be set to the target offset so that we can track
+ the byte offsets of subsequent pages.
+ After a call to op_get_next_page(), this will point to the first byte after
+ that page.*/
+ opus_int64 offset;
+ /*The total size of this data source, or -1 if it's unseekable.*/
+ opus_int64 end;
+ /*Used to locate pages in the data source.*/
+ ogg_sync_state oy;
+ /*One of OP_NOTOPEN, OP_PARTOPEN, OP_OPENED, OP_STREAMSET, OP_INITSET.*/
+ int ready_state;
+ /*The current link being played back.*/
+ int cur_link;
+ /*The number of decoded samples to discard from the start of decoding.*/
+ opus_int32 cur_discard_count;
+ /*The granule position of the previous packet (current packet start time).*/
+ ogg_int64_t prev_packet_gp;
+ /*The number of bytes read since the last bitrate query, including framing.*/
+ opus_int64 bytes_tracked;
+ /*The number of samples decoded since the last bitrate query.*/
+ ogg_int64_t samples_tracked;
+ /*Takes physical pages and welds them into a logical stream of packets.*/
+ ogg_stream_state os;
+ /*Re-timestamped packets from a single page.
+ Buffering these relies on the undocumented libogg behavior that ogg_packet
+ pointers remain valid until the next page is submitted to the
+ ogg_stream_state they came from.*/
+ ogg_packet op[255];
+ /*The index of the next packet to return.*/
+ int op_pos;
+ /*The total number of packets available.*/
+ int op_count;
+ /*Central working state for the packet-to-PCM decoder.*/
+ OpusMSDecoder *od;
+ /*The application-provided packet decode callback.*/
+ op_decode_cb_func decode_cb;
+ /*The application-provided packet decode callback context.*/
+ void *decode_cb_ctx;
+ /*The stream count used to initialize the decoder.*/
+ int od_stream_count;
+ /*The coupled stream count used to initialize the decoder.*/
+ int od_coupled_count;
+ /*The channel count used to initialize the decoder.*/
+ int od_channel_count;
+ /*The channel mapping used to initialize the decoder.*/
+ unsigned char od_mapping[OP_NCHANNELS_MAX];
+ /*The buffered data for one decoded packet.*/
+ op_sample *od_buffer;
+ /*The current position in the decoded buffer.*/
+ int od_buffer_pos;
+ /*The number of valid samples in the decoded buffer.*/
+ int od_buffer_size;
+ /*The type of gain offset to apply.
+ One of OP_HEADER_GAIN, OP_TRACK_GAIN, or OP_ABSOLUTE_GAIN.*/
+ int gain_type;
+ /*The offset to apply to the gain.*/
+ opus_int32 gain_offset_q8;
+ /*Internal state for soft clipping and dithering float->short output.*/
+#if !defined(OPUS_FIXED_POINT)
+# if defined(OP_SOFT_CLIP)
+ float clip_state[OP_NCHANNELS_MAX];
+# endif
+ float dither_a[OP_NCHANNELS_MAX*4];
+ float dither_b[OP_NCHANNELS_MAX*4];
+ opus_uint32 dither_seed;
+ int dither_mute;
+ int dither_disabled;
+ /*The number of channels represented by the internal state.
+ This gets set to 0 whenever anything that would prevent state propagation
+ occurs (switching between the float/short APIs, or between the
+ stereo/multistream APIs).*/
+ int state_channel_count;
+#endif
+};
+
+int op_strncasecmp(const char *_a,const char *_b,int _n);
+
+#endif
diff --git a/drivers/opus/mlp.c b/drivers/opus/mlp.c
new file mode 100644
index 0000000000..d4d4971796
--- /dev/null
+++ b/drivers/opus/mlp.c
@@ -0,0 +1,140 @@
+/* Copyright (c) 2008-2011 Octasic Inc.
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/opus_types.h"
+#include "opus/opus_defines.h"
+
+#include <math.h>
+#include "opus/mlp.h"
+#include "opus/celt/arch.h"
+#include "opus/tansig_table.h"
+#define MAX_NEURONS 100
+
+#if 0
+static OPUS_INLINE opus_val16 tansig_approx(opus_val32 _x) /* Q19 */
+{
+ int i;
+ opus_val16 xx; /* Q11 */
+ /*double x, y;*/
+ opus_val16 dy, yy; /* Q14 */
+ /*x = 1.9073e-06*_x;*/
+ if (_x>=QCONST32(8,19))
+ return QCONST32(1.,14);
+ if (_x<=-QCONST32(8,19))
+ return -QCONST32(1.,14);
+ xx = EXTRACT16(SHR32(_x, 8));
+ /*i = lrint(25*x);*/
+ i = SHR32(ADD32(1024,MULT16_16(25, xx)),11);
+ /*x -= .04*i;*/
+ xx -= EXTRACT16(SHR32(MULT16_16(20972,i),8));
+ /*x = xx*(1./2048);*/
+ /*y = tansig_table[250+i];*/
+ yy = tansig_table[250+i];
+ /*y = yy*(1./16384);*/
+ dy = 16384-MULT16_16_Q14(yy,yy);
+ yy = yy + MULT16_16_Q14(MULT16_16_Q11(xx,dy),(16384 - MULT16_16_Q11(yy,xx)));
+ return yy;
+}
+#else
+/*extern const float tansig_table[501];*/
+static OPUS_INLINE float tansig_approx(float x)
+{
+ int i;
+ float y, dy;
+ float sign=1;
+ /* Tests are reversed to catch NaNs */
+ if (!(x<8))
+ return 1;
+ if (!(x>-8))
+ return -1;
+ if (x<0)
+ {
+ x=-x;
+ sign=-1;
+ }
+ i = (int)floor(.5f+25*x);
+ x -= .04f*i;
+ y = tansig_table[i];
+ dy = 1-y*y;
+ y = y + x*dy*(1 - y*x);
+ return sign*y;
+}
+#endif
+
+#if 0
+void mlp_process(const MLP *m, const opus_val16 *in, opus_val16 *out)
+{
+ int j;
+ opus_val16 hidden[MAX_NEURONS];
+ const opus_val16 *W = m->weights;
+ /* Copy to tmp_in */
+ for (j=0;j<m->topo[1];j++)
+ {
+ int k;
+ opus_val32 sum = SHL32(EXTEND32(*W++),8);
+ for (k=0;k<m->topo[0];k++)
+ sum = MAC16_16(sum, in[k],*W++);
+ hidden[j] = tansig_approx(sum);
+ }
+ for (j=0;j<m->topo[2];j++)
+ {
+ int k;
+ opus_val32 sum = SHL32(EXTEND32(*W++),14);
+ for (k=0;k<m->topo[1];k++)
+ sum = MAC16_16(sum, hidden[k], *W++);
+ out[j] = tansig_approx(EXTRACT16(PSHR32(sum,17)));
+ }
+}
+#else
+void mlp_process(const MLP *m, const float *in, float *out)
+{
+ int j;
+ float hidden[MAX_NEURONS];
+ const float *W = m->weights;
+ /* Copy to tmp_in */
+ for (j=0;j<m->topo[1];j++)
+ {
+ int k;
+ float sum = *W++;
+ for (k=0;k<m->topo[0];k++)
+ sum = sum + in[k]**W++;
+ hidden[j] = tansig_approx(sum);
+ }
+ for (j=0;j<m->topo[2];j++)
+ {
+ int k;
+ float sum = *W++;
+ for (k=0;k<m->topo[1];k++)
+ sum = sum + hidden[k]**W++;
+ out[j] = tansig_approx(sum);
+ }
+}
+#endif
diff --git a/drivers/opus/mlp.h b/drivers/opus/mlp.h
new file mode 100644
index 0000000000..3f9ca73bb0
--- /dev/null
+++ b/drivers/opus/mlp.h
@@ -0,0 +1,41 @@
+/* Copyright (c) 2008-2011 Octasic Inc.
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _MLP_H_
+#define _MLP_H_
+
+#include "opus/celt/arch.h"
+
+typedef struct {
+ int layers;
+ const int *topo;
+ const float *weights;
+} MLP;
+
+void mlp_process(const MLP *m, const float *in, float *out);
+
+#endif /* _MLP_H_ */
diff --git a/drivers/opus/mlp_data.c b/drivers/opus/mlp_data.c
new file mode 100644
index 0000000000..127c62ce8c
--- /dev/null
+++ b/drivers/opus/mlp_data.c
@@ -0,0 +1,105 @@
+/* The contents of this file was automatically generated by mlp_train.c
+ It contains multi-layer perceptron (MLP) weights. */
+
+#include "opus/mlp.h"
+
+/* RMS error was 0.138320, seed was 1361535663 */
+
+static const float weights[422] = {
+
+/* hidden layer */
+-0.0941125f, -0.302976f, -0.603555f, -0.19393f, -0.185983f,
+-0.601617f, -0.0465317f, -0.114563f, -0.103599f, -0.618938f,
+-0.317859f, -0.169949f, -0.0702885f, 0.148065f, 0.409524f,
+0.548432f, 0.367649f, -0.494393f, 0.764306f, -1.83957f,
+0.170849f, 12.786f, -1.08848f, -1.27284f, -16.2606f,
+24.1773f, -5.57454f, -0.17276f, -0.163388f, -0.224421f,
+-0.0948944f, -0.0728695f, -0.26557f, -0.100283f, -0.0515459f,
+-0.146142f, -0.120674f, -0.180655f, 0.12857f, 0.442138f,
+-0.493735f, 0.167767f, 0.206699f, -0.197567f, 0.417999f,
+1.50364f, -0.773341f, -10.0401f, 0.401872f, 2.97966f,
+15.2165f, -1.88905f, -1.19254f, 0.0285397f, -0.00405139f,
+0.0707565f, 0.00825699f, -0.0927269f, -0.010393f, -0.00428882f,
+-0.00489743f, -0.0709731f, -0.00255992f, 0.0395619f, 0.226424f,
+0.0325231f, 0.162175f, -0.100118f, 0.485789f, 0.12697f,
+0.285937f, 0.0155637f, 0.10546f, 3.05558f, 1.15059f,
+-1.00904f, -1.83088f, 3.31766f, -3.42516f, -0.119135f,
+-0.0405654f, 0.00690068f, 0.0179877f, -0.0382487f, 0.00597941f,
+-0.0183611f, 0.00190395f, -0.144322f, -0.0435671f, 0.000990594f,
+0.221087f, 0.142405f, 0.484066f, 0.404395f, 0.511955f,
+-0.237255f, 0.241742f, 0.35045f, -0.699428f, 10.3993f,
+2.6507f, -2.43459f, -4.18838f, 1.05928f, 1.71067f,
+0.00667811f, -0.0721335f, -0.0397346f, 0.0362704f, -0.11496f,
+-0.0235776f, 0.0082161f, -0.0141741f, -0.0329699f, -0.0354253f,
+0.00277404f, -0.290654f, -1.14767f, -0.319157f, -0.686544f,
+0.36897f, 0.478899f, 0.182579f, -0.411069f, 0.881104f,
+-4.60683f, 1.4697f, 0.335845f, -1.81905f, -30.1699f,
+5.55225f, 0.0019508f, -0.123576f, -0.0727332f, -0.0641597f,
+-0.0534458f, -0.108166f, -0.0937368f, -0.0697883f, -0.0275475f,
+-0.192309f, -0.110074f, 0.285375f, -0.405597f, 0.0926724f,
+-0.287881f, -0.851193f, -0.099493f, -0.233764f, -1.2852f,
+1.13611f, 3.12168f, -0.0699f, -1.86216f, 2.65292f,
+-7.31036f, 2.44776f, -0.00111802f, -0.0632786f, -0.0376296f,
+-0.149851f, 0.142963f, 0.184368f, 0.123433f, 0.0756158f,
+0.117312f, 0.0933395f, 0.0692163f, 0.0842592f, 0.0704683f,
+0.0589963f, 0.0942205f, -0.448862f, 0.0262677f, 0.270352f,
+-0.262317f, 0.172586f, 2.00227f, -0.159216f, 0.038422f,
+10.2073f, 4.15536f, -2.3407f, -0.0550265f, 0.00964792f,
+-0.141336f, 0.0274501f, 0.0343921f, -0.0487428f, 0.0950172f,
+-0.00775017f, -0.0372492f, -0.00548121f, -0.0663695f, 0.0960506f,
+-0.200008f, -0.0412827f, 0.58728f, 0.0515787f, 0.337254f,
+0.855024f, 0.668371f, -0.114904f, -3.62962f, -0.467477f,
+-0.215472f, 2.61537f, 0.406117f, -1.36373f, 0.0425394f,
+0.12208f, 0.0934502f, 0.123055f, 0.0340935f, -0.142466f,
+0.035037f, -0.0490666f, 0.0733208f, 0.0576672f, 0.123984f,
+-0.0517194f, -0.253018f, 0.590565f, 0.145849f, 0.315185f,
+0.221534f, -0.149081f, 0.216161f, -0.349575f, 24.5664f,
+-0.994196f, 0.614289f, -18.7905f, -2.83277f, -0.716801f,
+-0.347201f, 0.479515f, -0.246027f, 0.0758683f, 0.137293f,
+-0.17781f, 0.118751f, -0.00108329f, -0.237334f, 0.355732f,
+-0.12991f, -0.0547627f, -0.318576f, -0.325524f, 0.180494f,
+-0.0625604f, 0.141219f, 0.344064f, 0.37658f, -0.591772f,
+5.8427f, -0.38075f, 0.221894f, -1.41934f, -1.87943e+06f,
+1.34114f, 0.0283355f, -0.0447856f, -0.0211466f, -0.0256927f,
+0.0139618f, 0.0207934f, -0.0107666f, 0.0110969f, 0.0586069f,
+-0.0253545f, -0.0328433f, 0.11872f, -0.216943f, 0.145748f,
+0.119808f, -0.0915211f, -0.120647f, -0.0787719f, -0.143644f,
+-0.595116f, -1.152f, -1.25335f, -1.17092f, 4.34023f,
+-975268.f, -1.37033f, -0.0401123f, 0.210602f, -0.136656f,
+0.135962f, -0.0523293f, 0.0444604f, 0.0143928f, 0.00412666f,
+-0.0193003f, 0.218452f, -0.110204f, -2.02563f, 0.918238f,
+-2.45362f, 1.19542f, -0.061362f, -1.92243f, 0.308111f,
+0.49764f, 0.912356f, 0.209272f, -2.34525f, 2.19326f,
+-6.47121f, 1.69771f, -0.725123f, 0.0118929f, 0.0377944f,
+0.0554003f, 0.0226452f, -0.0704421f, -0.0300309f, 0.0122978f,
+-0.0041782f, -0.0686612f, 0.0313115f, 0.039111f, 0.364111f,
+-0.0945548f, 0.0229876f, -0.17414f, 0.329795f, 0.114714f,
+0.30022f, 0.106997f, 0.132355f, 5.79932f, 0.908058f,
+-0.905324f, -3.3561f, 0.190647f, 0.184211f, -0.673648f,
+0.231807f, -0.0586222f, 0.230752f, -0.438277f, 0.245857f,
+-0.17215f, 0.0876383f, -0.720512f, 0.162515f, 0.0170571f,
+0.101781f, 0.388477f, 1.32931f, 1.08548f, -0.936301f,
+-2.36958f, -6.71988f, -3.44376f, 2.13818f, 14.2318f,
+4.91459f, -3.09052f, -9.69191f, -0.768234f, 1.79604f,
+0.0549653f, 0.163399f, 0.0797025f, 0.0343933f, -0.0555876f,
+-0.00505673f, 0.0187258f, 0.0326628f, 0.0231486f, 0.15573f,
+0.0476223f, -0.254824f, 1.60155f, -0.801221f, 2.55496f,
+0.737629f, -1.36249f, -0.695463f, -2.44301f, -1.73188f,
+3.95279f, 1.89068f, 0.486087f, -11.3343f, 3.9416e+06f,
+
+/* output layer */
+-0.381439f, 0.12115f, -0.906927f, 2.93878f, 1.6388f,
+0.882811f, 0.874344f, 1.21726f, -0.874545f, 0.321706f,
+0.785055f, 0.946558f, -0.575066f, -3.46553f, 0.884905f,
+0.0924047f, -9.90712f, 0.391338f, 0.160103f, -2.04954f,
+4.1455f, 0.0684029f, -0.144761f, -0.285282f, 0.379244f,
+-1.1584f, -0.0277241f, -9.85f, -4.82386f, 3.71333f,
+3.87308f, 3.52558f};
+
+static const int topo[3] = {25, 15, 2};
+
+const MLP net = {
+ 3,
+ topo,
+ weights
+};
diff --git a/drivers/opus/opus.c b/drivers/opus/opus.c
new file mode 100644
index 0000000000..5af71b478d
--- /dev/null
+++ b/drivers/opus/opus.c
@@ -0,0 +1,329 @@
+/* Copyright (c) 2011 Xiph.Org Foundation, Skype Limited
+ Written by Jean-Marc Valin and Koen Vos */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/opus.h"
+#include "opus/opus_private.h"
+
+#ifndef DISABLE_FLOAT_API
+OPUS_EXPORT void opus_pcm_soft_clip(float *_x, int N, int C, float *declip_mem)
+{
+ int c;
+ int i;
+ float *x;
+
+ if (C<1 || N<1 || !_x || !declip_mem) return;
+
+ /* First thing: saturate everything to +/- 2 which is the highest level our
+ non-linearity can handle. At the point where the signal reaches +/-2,
+ the derivative will be zero anyway, so this doesn't introduce any
+ discontinuity in the derivative. */
+ for (i=0;i<N*C;i++)
+ _x[i] = MAX16(-2.f, MIN16(2.f, _x[i]));
+ for (c=0;c<C;c++)
+ {
+ float a;
+ float x0;
+ int curr;
+
+ x = _x+c;
+ a = declip_mem[c];
+ /* Continue applying the non-linearity from the previous frame to avoid
+ any discontinuity. */
+ for (i=0;i<N;i++)
+ {
+ if (x[i*C]*a>=0)
+ break;
+ x[i*C] = x[i*C]+a*x[i*C]*x[i*C];
+ }
+
+ curr=0;
+ x0 = x[0];
+ while(1)
+ {
+ int start, end;
+ float maxval;
+ int special=0;
+ int peak_pos;
+ for (i=curr;i<N;i++)
+ {
+ if (x[i*C]>1 || x[i*C]<-1)
+ break;
+ }
+ if (i==N)
+ {
+ a=0;
+ break;
+ }
+ peak_pos = i;
+ start=end=i;
+ maxval=ABS16(x[i*C]);
+ /* Look for first zero crossing before clipping */
+ while (start>0 && x[i*C]*x[(start-1)*C]>=0)
+ start--;
+ /* Look for first zero crossing after clipping */
+ while (end<N && x[i*C]*x[end*C]>=0)
+ {
+ /* Look for other peaks until the next zero-crossing. */
+ if (ABS16(x[end*C])>maxval)
+ {
+ maxval = ABS16(x[end*C]);
+ peak_pos = end;
+ }
+ end++;
+ }
+ /* Detect the special case where we clip before the first zero crossing */
+ special = (start==0 && x[i*C]*x[0]>=0);
+
+ /* Compute a such that maxval + a*maxval^2 = 1 */
+ a=(maxval-1)/(maxval*maxval);
+ if (x[i*C]>0)
+ a = -a;
+ /* Apply soft clipping */
+ for (i=start;i<end;i++)
+ x[i*C] = x[i*C]+a*x[i*C]*x[i*C];
+
+ if (special && peak_pos>=2)
+ {
+ /* Add a linear ramp from the first sample to the signal peak.
+ This avoids a discontinuity at the beginning of the frame. */
+ float delta;
+ float offset = x0-x[0];
+ delta = offset / peak_pos;
+ for (i=curr;i<peak_pos;i++)
+ {
+ offset -= delta;
+ x[i*C] += offset;
+ x[i*C] = MAX16(-1.f, MIN16(1.f, x[i*C]));
+ }
+ }
+ curr = end;
+ if (curr==N)
+ break;
+ }
+ declip_mem[c] = a;
+ }
+}
+#endif
+
+int encode_size(int size, unsigned char *data)
+{
+ if (size < 252)
+ {
+ data[0] = size;
+ return 1;
+ } else {
+ data[0] = 252+(size&0x3);
+ data[1] = (size-(int)data[0])>>2;
+ return 2;
+ }
+}
+
+static int parse_size(const unsigned char *data, opus_int32 len, opus_int16 *size)
+{
+ if (len<1)
+ {
+ *size = -1;
+ return -1;
+ } else if (data[0]<252)
+ {
+ *size = data[0];
+ return 1;
+ } else if (len<2)
+ {
+ *size = -1;
+ return -1;
+ } else {
+ *size = 4*data[1] + data[0];
+ return 2;
+ }
+}
+
+int opus_packet_parse_impl(const unsigned char *data, opus_int32 len,
+ int self_delimited, unsigned char *out_toc,
+ const unsigned char *frames[48], opus_int16 size[48],
+ int *payload_offset, opus_int32 *packet_offset)
+{
+ int i, bytes;
+ int count;
+ int cbr;
+ unsigned char ch, toc;
+ int framesize;
+ opus_int32 last_size;
+ opus_int32 pad = 0;
+ const unsigned char *data0 = data;
+
+ if (size==NULL)
+ return OPUS_BAD_ARG;
+
+ framesize = opus_packet_get_samples_per_frame(data, 48000);
+
+ cbr = 0;
+ toc = *data++;
+ len--;
+ last_size = len;
+ switch (toc&0x3)
+ {
+ /* One frame */
+ case 0:
+ count=1;
+ break;
+ /* Two CBR frames */
+ case 1:
+ count=2;
+ cbr = 1;
+ if (!self_delimited)
+ {
+ if (len&0x1)
+ return OPUS_INVALID_PACKET;
+ last_size = len/2;
+ /* If last_size doesn't fit in size[0], we'll catch it later */
+ size[0] = (opus_int16)last_size;
+ }
+ break;
+ /* Two VBR frames */
+ case 2:
+ count = 2;
+ bytes = parse_size(data, len, size);
+ len -= bytes;
+ if (size[0]<0 || size[0] > len)
+ return OPUS_INVALID_PACKET;
+ data += bytes;
+ last_size = len-size[0];
+ break;
+ /* Multiple CBR/VBR frames (from 0 to 120 ms) */
+ default: /*case 3:*/
+ if (len<1)
+ return OPUS_INVALID_PACKET;
+ /* Number of frames encoded in bits 0 to 5 */
+ ch = *data++;
+ count = ch&0x3F;
+ if (count <= 0 || framesize*count > 5760)
+ return OPUS_INVALID_PACKET;
+ len--;
+ /* Padding flag is bit 6 */
+ if (ch&0x40)
+ {
+ int p;
+ do {
+ int tmp;
+ if (len<=0)
+ return OPUS_INVALID_PACKET;
+ p = *data++;
+ len--;
+ tmp = p==255 ? 254: p;
+ len -= tmp;
+ pad += tmp;
+ } while (p==255);
+ }
+ if (len<0)
+ return OPUS_INVALID_PACKET;
+ /* VBR flag is bit 7 */
+ cbr = !(ch&0x80);
+ if (!cbr)
+ {
+ /* VBR case */
+ last_size = len;
+ for (i=0;i<count-1;i++)
+ {
+ bytes = parse_size(data, len, size+i);
+ len -= bytes;
+ if (size[i]<0 || size[i] > len)
+ return OPUS_INVALID_PACKET;
+ data += bytes;
+ last_size -= bytes+size[i];
+ }
+ if (last_size<0)
+ return OPUS_INVALID_PACKET;
+ } else if (!self_delimited)
+ {
+ /* CBR case */
+ last_size = len/count;
+ if (last_size*count!=len)
+ return OPUS_INVALID_PACKET;
+ for (i=0;i<count-1;i++)
+ size[i] = (opus_int16)last_size;
+ }
+ break;
+ }
+ /* Self-delimited framing has an extra size for the last frame. */
+ if (self_delimited)
+ {
+ bytes = parse_size(data, len, size+count-1);
+ len -= bytes;
+ if (size[count-1]<0 || size[count-1] > len)
+ return OPUS_INVALID_PACKET;
+ data += bytes;
+ /* For CBR packets, apply the size to all the frames. */
+ if (cbr)
+ {
+ if (size[count-1]*count > len)
+ return OPUS_INVALID_PACKET;
+ for (i=0;i<count-1;i++)
+ size[i] = size[count-1];
+ } else if (bytes+size[count-1] > last_size)
+ return OPUS_INVALID_PACKET;
+ } else
+ {
+ /* Because it's not encoded explicitly, it's possible the size of the
+ last packet (or all the packets, for the CBR case) is larger than
+ 1275. Reject them here.*/
+ if (last_size > 1275)
+ return OPUS_INVALID_PACKET;
+ size[count-1] = (opus_int16)last_size;
+ }
+
+ if (payload_offset)
+ *payload_offset = (int)(data-data0);
+
+ for (i=0;i<count;i++)
+ {
+ if (frames)
+ frames[i] = data;
+ data += size[i];
+ }
+
+ if (packet_offset)
+ *packet_offset = pad+(opus_int32)(data-data0);
+
+ if (out_toc)
+ *out_toc = toc;
+
+ return count;
+}
+
+int opus_packet_parse(const unsigned char *data, opus_int32 len,
+ unsigned char *out_toc, const unsigned char *frames[48],
+ opus_int16 size[48], int *payload_offset)
+{
+ return opus_packet_parse_impl(data, len, 0, out_toc,
+ frames, size, payload_offset, NULL);
+}
+
diff --git a/drivers/opus/opus.h b/drivers/opus/opus.h
new file mode 100644
index 0000000000..b99f553016
--- /dev/null
+++ b/drivers/opus/opus.h
@@ -0,0 +1,978 @@
+/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited
+ Written by Jean-Marc Valin and Koen Vos */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ * @file opus.h
+ * @brief Opus reference implementation API
+ */
+
+#ifndef OPUS_H
+#define OPUS_H
+
+#include "opus/opus_types.h"
+#include "opus/opus_defines.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @mainpage Opus
+ *
+ * The Opus codec is designed for interactive speech and audio transmission over the Internet.
+ * It is designed by the IETF Codec Working Group and incorporates technology from
+ * Skype's SILK codec and Xiph.Org's CELT codec.
+ *
+ * The Opus codec is designed to handle a wide range of interactive audio applications,
+ * including Voice over IP, videoconferencing, in-game chat, and even remote live music
+ * performances. It can scale from low bit-rate narrowband speech to very high quality
+ * stereo music. Its main features are:
+
+ * @li Sampling rates from 8 to 48 kHz
+ * @li Bit-rates from 6 kb/s to 510 kb/s
+ * @li Support for both constant bit-rate (CBR) and variable bit-rate (VBR)
+ * @li Audio bandwidth from narrowband to full-band
+ * @li Support for speech and music
+ * @li Support for mono and stereo
+ * @li Support for multichannel (up to 255 channels)
+ * @li Frame sizes from 2.5 ms to 60 ms
+ * @li Good loss robustness and packet loss concealment (PLC)
+ * @li Floating point and fixed-point implementation
+ *
+ * Documentation sections:
+ * @li @ref opus_encoder
+ * @li @ref opus_decoder
+ * @li @ref opus_repacketizer
+ * @li @ref opus_multistream
+ * @li @ref opus_libinfo
+ * @li @ref opus_custom
+ */
+
+/** @defgroup opus_encoder Opus Encoder
+ * @{
+ *
+ * @brief This page describes the process and functions used to encode Opus.
+ *
+ * Since Opus is a stateful codec, the encoding process starts with creating an encoder
+ * state. This can be done with:
+ *
+ * @code
+ * int error;
+ * OpusEncoder *enc;
+ * enc = opus_encoder_create(Fs, channels, application, &error);
+ * @endcode
+ *
+ * From this point, @c enc can be used for encoding an audio stream. An encoder state
+ * @b must @b not be used for more than one stream at the same time. Similarly, the encoder
+ * state @b must @b not be re-initialized for each frame.
+ *
+ * While opus_encoder_create() allocates memory for the state, it's also possible
+ * to initialize pre-allocated memory:
+ *
+ * @code
+ * int size;
+ * int error;
+ * OpusEncoder *enc;
+ * size = opus_encoder_get_size(channels);
+ * enc = malloc(size);
+ * error = opus_encoder_init(enc, Fs, channels, application);
+ * @endcode
+ *
+ * where opus_encoder_get_size() returns the required size for the encoder state. Note that
+ * future versions of this code may change the size, so no assuptions should be made about it.
+ *
+ * The encoder state is always continuous in memory and only a shallow copy is sufficient
+ * to copy it (e.g. memcpy())
+ *
+ * It is possible to change some of the encoder's settings using the opus_encoder_ctl()
+ * interface. All these settings already default to the recommended value, so they should
+ * only be changed when necessary. The most common settings one may want to change are:
+ *
+ * @code
+ * opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate));
+ * opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity));
+ * opus_encoder_ctl(enc, OPUS_SET_SIGNAL(signal_type));
+ * @endcode
+ *
+ * where
+ *
+ * @arg bitrate is in bits per second (b/s)
+ * @arg complexity is a value from 1 to 10, where 1 is the lowest complexity and 10 is the highest
+ * @arg signal_type is either OPUS_AUTO (default), OPUS_SIGNAL_VOICE, or OPUS_SIGNAL_MUSIC
+ *
+ * See @ref opus_encoderctls and @ref opus_genericctls for a complete list of parameters that can be set or queried. Most parameters can be set or changed at any time during a stream.
+ *
+ * To encode a frame, opus_encode() or opus_encode_float() must be called with exactly one frame (2.5, 5, 10, 20, 40 or 60 ms) of audio data:
+ * @code
+ * len = opus_encode(enc, audio_frame, frame_size, packet, max_packet);
+ * @endcode
+ *
+ * where
+ * <ul>
+ * <li>audio_frame is the audio data in opus_int16 (or float for opus_encode_float())</li>
+ * <li>frame_size is the duration of the frame in samples (per channel)</li>
+ * <li>packet is the byte array to which the compressed data is written</li>
+ * <li>max_packet is the maximum number of bytes that can be written in the packet (4000 bytes is recommended).
+ * Do not use max_packet to control VBR target bitrate, instead use the #OPUS_SET_BITRATE CTL.</li>
+ * </ul>
+ *
+ * opus_encode() and opus_encode_float() return the number of bytes actually written to the packet.
+ * The return value <b>can be negative</b>, which indicates that an error has occurred. If the return value
+ * is 1 byte, then the packet does not need to be transmitted (DTX).
+ *
+ * Once the encoder state if no longer needed, it can be destroyed with
+ *
+ * @code
+ * opus_encoder_destroy(enc);
+ * @endcode
+ *
+ * If the encoder was created with opus_encoder_init() rather than opus_encoder_create(),
+ * then no action is required aside from potentially freeing the memory that was manually
+ * allocated for it (calling free(enc) for the example above)
+ *
+ */
+
+/** Opus encoder state.
+ * This contains the complete state of an Opus encoder.
+ * It is position independent and can be freely copied.
+ * @see opus_encoder_create,opus_encoder_init
+ */
+typedef struct OpusEncoder OpusEncoder;
+
+/** Gets the size of an <code>OpusEncoder</code> structure.
+ * @param[in] channels <tt>int</tt>: Number of channels.
+ * This must be 1 or 2.
+ * @returns The size in bytes.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_encoder_get_size(int channels);
+
+/**
+ */
+
+/** Allocates and initializes an encoder state.
+ * There are three coding modes:
+ *
+ * @ref OPUS_APPLICATION_VOIP gives best quality at a given bitrate for voice
+ * signals. It enhances the input signal by high-pass filtering and
+ * emphasizing formants and harmonics. Optionally it includes in-band
+ * forward error correction to protect against packet loss. Use this
+ * mode for typical VoIP applications. Because of the enhancement,
+ * even at high bitrates the output may sound different from the input.
+ *
+ * @ref OPUS_APPLICATION_AUDIO gives best quality at a given bitrate for most
+ * non-voice signals like music. Use this mode for music and mixed
+ * (music/voice) content, broadcast, and applications requiring less
+ * than 15 ms of coding delay.
+ *
+ * @ref OPUS_APPLICATION_RESTRICTED_LOWDELAY configures low-delay mode that
+ * disables the speech-optimized mode in exchange for slightly reduced delay.
+ * This mode can only be set on an newly initialized or freshly reset encoder
+ * because it changes the codec delay.
+ *
+ * This is useful when the caller knows that the speech-optimized modes will not be needed (use with caution).
+ * @param [in] Fs <tt>opus_int32</tt>: Sampling rate of input signal (Hz)
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param [in] channels <tt>int</tt>: Number of channels (1 or 2) in input signal
+ * @param [in] application <tt>int</tt>: Coding mode (@ref OPUS_APPLICATION_VOIP/@ref OPUS_APPLICATION_AUDIO/@ref OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ * @param [out] error <tt>int*</tt>: @ref opus_errorcodes
+ * @note Regardless of the sampling rate and number channels selected, the Opus encoder
+ * can switch to a lower audio bandwidth or number of channels if the bitrate
+ * selected is too low. This also means that it is safe to always use 48 kHz stereo input
+ * and let the encoder optimize the encoding.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusEncoder *opus_encoder_create(
+ opus_int32 Fs,
+ int channels,
+ int application,
+ int *error
+);
+
+/** Initializes a previously allocated encoder state
+ * The memory pointed to by st must be at least the size returned by opus_encoder_get_size().
+ * This is intended for applications which use their own allocator instead of malloc.
+ * @see opus_encoder_create(),opus_encoder_get_size()
+ * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.
+ * @param [in] st <tt>OpusEncoder*</tt>: Encoder state
+ * @param [in] Fs <tt>opus_int32</tt>: Sampling rate of input signal (Hz)
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param [in] channels <tt>int</tt>: Number of channels (1 or 2) in input signal
+ * @param [in] application <tt>int</tt>: Coding mode (OPUS_APPLICATION_VOIP/OPUS_APPLICATION_AUDIO/OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ * @retval #OPUS_OK Success or @ref opus_errorcodes
+ */
+OPUS_EXPORT int opus_encoder_init(
+ OpusEncoder *st,
+ opus_int32 Fs,
+ int channels,
+ int application
+) OPUS_ARG_NONNULL(1);
+
+/** Encodes an Opus frame.
+ * @param [in] st <tt>OpusEncoder*</tt>: Encoder state
+ * @param [in] pcm <tt>opus_int16*</tt>: Input signal (interleaved if 2 channels). length is frame_size*channels*sizeof(opus_int16)
+ * @param [in] frame_size <tt>int</tt>: Number of samples per channel in the
+ * input signal.
+ * This must be an Opus frame size for
+ * the encoder's sampling rate.
+ * For example, at 48 kHz the permitted
+ * values are 120, 240, 480, 960, 1920,
+ * and 2880.
+ * Passing in a duration of less than
+ * 10 ms (480 samples at 48 kHz) will
+ * prevent the encoder from using the LPC
+ * or hybrid modes.
+ * @param [out] data <tt>unsigned char*</tt>: Output payload.
+ * This must contain storage for at
+ * least \a max_data_bytes.
+ * @param [in] max_data_bytes <tt>opus_int32</tt>: Size of the allocated
+ * memory for the output
+ * payload. This may be
+ * used to impose an upper limit on
+ * the instant bitrate, but should
+ * not be used as the only bitrate
+ * control. Use #OPUS_SET_BITRATE to
+ * control the bitrate.
+ * @returns The length of the encoded packet (in bytes) on success or a
+ * negative error code (see @ref opus_errorcodes) on failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode(
+ OpusEncoder *st,
+ const opus_int16 *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
+
+/** Encodes an Opus frame from floating point input.
+ * @param [in] st <tt>OpusEncoder*</tt>: Encoder state
+ * @param [in] pcm <tt>float*</tt>: Input in float format (interleaved if 2 channels), with a normal range of +/-1.0.
+ * Samples with a range beyond +/-1.0 are supported but will
+ * be clipped by decoders using the integer API and should
+ * only be used if it is known that the far end supports
+ * extended dynamic range.
+ * length is frame_size*channels*sizeof(float)
+ * @param [in] frame_size <tt>int</tt>: Number of samples per channel in the
+ * input signal.
+ * This must be an Opus frame size for
+ * the encoder's sampling rate.
+ * For example, at 48 kHz the permitted
+ * values are 120, 240, 480, 960, 1920,
+ * and 2880.
+ * Passing in a duration of less than
+ * 10 ms (480 samples at 48 kHz) will
+ * prevent the encoder from using the LPC
+ * or hybrid modes.
+ * @param [out] data <tt>unsigned char*</tt>: Output payload.
+ * This must contain storage for at
+ * least \a max_data_bytes.
+ * @param [in] max_data_bytes <tt>opus_int32</tt>: Size of the allocated
+ * memory for the output
+ * payload. This may be
+ * used to impose an upper limit on
+ * the instant bitrate, but should
+ * not be used as the only bitrate
+ * control. Use #OPUS_SET_BITRATE to
+ * control the bitrate.
+ * @returns The length of the encoded packet (in bytes) on success or a
+ * negative error code (see @ref opus_errorcodes) on failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_encode_float(
+ OpusEncoder *st,
+ const float *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
+
+/** Frees an <code>OpusEncoder</code> allocated by opus_encoder_create().
+ * @param[in] st <tt>OpusEncoder*</tt>: State to be freed.
+ */
+OPUS_EXPORT void opus_encoder_destroy(OpusEncoder *st);
+
+/** Perform a CTL function on an Opus encoder.
+ *
+ * Generally the request and subsequent arguments are generated
+ * by a convenience macro.
+ * @param st <tt>OpusEncoder*</tt>: Encoder state.
+ * @param request This and all remaining parameters should be replaced by one
+ * of the convenience macros in @ref opus_genericctls or
+ * @ref opus_encoderctls.
+ * @see opus_genericctls
+ * @see opus_encoderctls
+ */
+OPUS_EXPORT int opus_encoder_ctl(OpusEncoder *st, int request, ...) OPUS_ARG_NONNULL(1);
+/**@}*/
+
+/** @defgroup opus_decoder Opus Decoder
+ * @{
+ *
+ * @brief This page describes the process and functions used to decode Opus.
+ *
+ * The decoding process also starts with creating a decoder
+ * state. This can be done with:
+ * @code
+ * int error;
+ * OpusDecoder *dec;
+ * dec = opus_decoder_create(Fs, channels, &error);
+ * @endcode
+ * where
+ * @li Fs is the sampling rate and must be 8000, 12000, 16000, 24000, or 48000
+ * @li channels is the number of channels (1 or 2)
+ * @li error will hold the error code in case of failure (or #OPUS_OK on success)
+ * @li the return value is a newly created decoder state to be used for decoding
+ *
+ * While opus_decoder_create() allocates memory for the state, it's also possible
+ * to initialize pre-allocated memory:
+ * @code
+ * int size;
+ * int error;
+ * OpusDecoder *dec;
+ * size = opus_decoder_get_size(channels);
+ * dec = malloc(size);
+ * error = opus_decoder_init(dec, Fs, channels);
+ * @endcode
+ * where opus_decoder_get_size() returns the required size for the decoder state. Note that
+ * future versions of this code may change the size, so no assuptions should be made about it.
+ *
+ * The decoder state is always continuous in memory and only a shallow copy is sufficient
+ * to copy it (e.g. memcpy())
+ *
+ * To decode a frame, opus_decode() or opus_decode_float() must be called with a packet of compressed audio data:
+ * @code
+ * frame_size = opus_decode(dec, packet, len, decoded, max_size, 0);
+ * @endcode
+ * where
+ *
+ * @li packet is the byte array containing the compressed data
+ * @li len is the exact number of bytes contained in the packet
+ * @li decoded is the decoded audio data in opus_int16 (or float for opus_decode_float())
+ * @li max_size is the max duration of the frame in samples (per channel) that can fit into the decoded_frame array
+ *
+ * opus_decode() and opus_decode_float() return the number of samples (per channel) decoded from the packet.
+ * If that value is negative, then an error has occurred. This can occur if the packet is corrupted or if the audio
+ * buffer is too small to hold the decoded audio.
+ *
+ * Opus is a stateful codec with overlapping blocks and as a result Opus
+ * packets are not coded independently of each other. Packets must be
+ * passed into the decoder serially and in the correct order for a correct
+ * decode. Lost packets can be replaced with loss concealment by calling
+ * the decoder with a null pointer and zero length for the missing packet.
+ *
+ * A single codec state may only be accessed from a single thread at
+ * a time and any required locking must be performed by the caller. Separate
+ * streams must be decoded with separate decoder states and can be decoded
+ * in parallel unless the library was compiled with NONTHREADSAFE_PSEUDOSTACK
+ * defined.
+ *
+ */
+
+/** Opus decoder state.
+ * This contains the complete state of an Opus decoder.
+ * It is position independent and can be freely copied.
+ * @see opus_decoder_create,opus_decoder_init
+ */
+typedef struct OpusDecoder OpusDecoder;
+
+/** Gets the size of an <code>OpusDecoder</code> structure.
+ * @param [in] channels <tt>int</tt>: Number of channels.
+ * This must be 1 or 2.
+ * @returns The size in bytes.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_size(int channels);
+
+/** Allocates and initializes a decoder state.
+ * @param [in] Fs <tt>opus_int32</tt>: Sample rate to decode at (Hz).
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param [in] channels <tt>int</tt>: Number of channels (1 or 2) to decode
+ * @param [out] error <tt>int*</tt>: #OPUS_OK Success or @ref opus_errorcodes
+ *
+ * Internally Opus stores data at 48000 Hz, so that should be the default
+ * value for Fs. However, the decoder can efficiently decode to buffers
+ * at 8, 12, 16, and 24 kHz so if for some reason the caller cannot use
+ * data at the full sample rate, or knows the compressed data doesn't
+ * use the full frequency range, it can request decoding at a reduced
+ * rate. Likewise, the decoder is capable of filling in either mono or
+ * interleaved stereo pcm buffers, at the caller's request.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusDecoder *opus_decoder_create(
+ opus_int32 Fs,
+ int channels,
+ int *error
+);
+
+/** Initializes a previously allocated decoder state.
+ * The state must be at least the size returned by opus_decoder_get_size().
+ * This is intended for applications which use their own allocator instead of malloc. @see opus_decoder_create,opus_decoder_get_size
+ * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.
+ * @param [in] st <tt>OpusDecoder*</tt>: Decoder state.
+ * @param [in] Fs <tt>opus_int32</tt>: Sampling rate to decode to (Hz).
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param [in] channels <tt>int</tt>: Number of channels (1 or 2) to decode
+ * @retval #OPUS_OK Success or @ref opus_errorcodes
+ */
+OPUS_EXPORT int opus_decoder_init(
+ OpusDecoder *st,
+ opus_int32 Fs,
+ int channels
+) OPUS_ARG_NONNULL(1);
+
+/** Decode an Opus packet.
+ * @param [in] st <tt>OpusDecoder*</tt>: Decoder state
+ * @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss
+ * @param [in] len <tt>opus_int32</tt>: Number of bytes in payload*
+ * @param [out] pcm <tt>opus_int16*</tt>: Output signal (interleaved if 2 channels). length
+ * is frame_size*channels*sizeof(opus_int16)
+ * @param [in] frame_size Number of samples per channel of available space in \a pcm.
+ * If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will
+ * not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1),
+ * then frame_size needs to be exactly the duration of audio that is missing, otherwise the
+ * decoder will not be in the optimal state to decode the next incoming packet. For the PLC and
+ * FEC cases, frame_size <b>must</b> be a multiple of 2.5 ms.
+ * @param [in] decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band forward error correction data be
+ * decoded. If no such data is available, the frame is decoded as if it were lost.
+ * @returns Number of decoded samples or @ref opus_errorcodes
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode(
+ OpusDecoder *st,
+ const unsigned char *data,
+ opus_int32 len,
+ opus_int16 *pcm,
+ int frame_size,
+ int decode_fec
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Decode an Opus packet with floating point output.
+ * @param [in] st <tt>OpusDecoder*</tt>: Decoder state
+ * @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss
+ * @param [in] len <tt>opus_int32</tt>: Number of bytes in payload
+ * @param [out] pcm <tt>float*</tt>: Output signal (interleaved if 2 channels). length
+ * is frame_size*channels*sizeof(float)
+ * @param [in] frame_size Number of samples per channel of available space in \a pcm.
+ * If this is less than the maximum packet duration (120ms; 5760 for 48kHz), this function will
+ * not be capable of decoding some packets. In the case of PLC (data==NULL) or FEC (decode_fec=1),
+ * then frame_size needs to be exactly the duration of audio that is missing, otherwise the
+ * decoder will not be in the optimal state to decode the next incoming packet. For the PLC and
+ * FEC cases, frame_size <b>must</b> be a multiple of 2.5 ms.
+ * @param [in] decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band forward error correction data be
+ * decoded. If no such data is available the frame is decoded as if it were lost.
+ * @returns Number of decoded samples or @ref opus_errorcodes
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decode_float(
+ OpusDecoder *st,
+ const unsigned char *data,
+ opus_int32 len,
+ float *pcm,
+ int frame_size,
+ int decode_fec
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Perform a CTL function on an Opus decoder.
+ *
+ * Generally the request and subsequent arguments are generated
+ * by a convenience macro.
+ * @param st <tt>OpusDecoder*</tt>: Decoder state.
+ * @param request This and all remaining parameters should be replaced by one
+ * of the convenience macros in @ref opus_genericctls or
+ * @ref opus_decoderctls.
+ * @see opus_genericctls
+ * @see opus_decoderctls
+ */
+OPUS_EXPORT int opus_decoder_ctl(OpusDecoder *st, int request, ...) OPUS_ARG_NONNULL(1);
+
+/** Frees an <code>OpusDecoder</code> allocated by opus_decoder_create().
+ * @param[in] st <tt>OpusDecoder*</tt>: State to be freed.
+ */
+OPUS_EXPORT void opus_decoder_destroy(OpusDecoder *st);
+
+/** Parse an opus packet into one or more frames.
+ * Opus_decode will perform this operation internally so most applications do
+ * not need to use this function.
+ * This function does not copy the frames, the returned pointers are pointers into
+ * the input packet.
+ * @param [in] data <tt>char*</tt>: Opus packet to be parsed
+ * @param [in] len <tt>opus_int32</tt>: size of data
+ * @param [out] out_toc <tt>char*</tt>: TOC pointer
+ * @param [out] frames <tt>char*[48]</tt> encapsulated frames
+ * @param [out] size <tt>opus_int16[48]</tt> sizes of the encapsulated frames
+ * @param [out] payload_offset <tt>int*</tt>: returns the position of the payload within the packet (in bytes)
+ * @returns number of frames
+ */
+OPUS_EXPORT int opus_packet_parse(
+ const unsigned char *data,
+ opus_int32 len,
+ unsigned char *out_toc,
+ const unsigned char *frames[48],
+ opus_int16 size[48],
+ int *payload_offset
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Gets the bandwidth of an Opus packet.
+ * @param [in] data <tt>char*</tt>: Opus packet
+ * @retval OPUS_BANDWIDTH_NARROWBAND Narrowband (4kHz bandpass)
+ * @retval OPUS_BANDWIDTH_MEDIUMBAND Mediumband (6kHz bandpass)
+ * @retval OPUS_BANDWIDTH_WIDEBAND Wideband (8kHz bandpass)
+ * @retval OPUS_BANDWIDTH_SUPERWIDEBAND Superwideband (12kHz bandpass)
+ * @retval OPUS_BANDWIDTH_FULLBAND Fullband (20kHz bandpass)
+ * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_bandwidth(const unsigned char *data) OPUS_ARG_NONNULL(1);
+
+/** Gets the number of samples per frame from an Opus packet.
+ * @param [in] data <tt>char*</tt>: Opus packet.
+ * This must contain at least one byte of
+ * data.
+ * @param [in] Fs <tt>opus_int32</tt>: Sampling rate in Hz.
+ * This must be a multiple of 400, or
+ * inaccurate results will be returned.
+ * @returns Number of samples per frame.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_samples_per_frame(const unsigned char *data, opus_int32 Fs) OPUS_ARG_NONNULL(1);
+
+/** Gets the number of channels from an Opus packet.
+ * @param [in] data <tt>char*</tt>: Opus packet
+ * @returns Number of channels
+ * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_channels(const unsigned char *data) OPUS_ARG_NONNULL(1);
+
+/** Gets the number of frames in an Opus packet.
+ * @param [in] packet <tt>char*</tt>: Opus packet
+ * @param [in] len <tt>opus_int32</tt>: Length of packet
+ * @returns Number of frames
+ * @retval OPUS_BAD_ARG Insufficient data was passed to the function
+ * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_frames(const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1);
+
+/** Gets the number of samples of an Opus packet.
+ * @param [in] packet <tt>char*</tt>: Opus packet
+ * @param [in] len <tt>opus_int32</tt>: Length of packet
+ * @param [in] Fs <tt>opus_int32</tt>: Sampling rate in Hz.
+ * This must be a multiple of 400, or
+ * inaccurate results will be returned.
+ * @returns Number of samples
+ * @retval OPUS_BAD_ARG Insufficient data was passed to the function
+ * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len, opus_int32 Fs) OPUS_ARG_NONNULL(1);
+
+/** Gets the number of samples of an Opus packet.
+ * @param [in] dec <tt>OpusDecoder*</tt>: Decoder state
+ * @param [in] packet <tt>char*</tt>: Opus packet
+ * @param [in] len <tt>opus_int32</tt>: Length of packet
+ * @returns Number of samples
+ * @retval OPUS_BAD_ARG Insufficient data was passed to the function
+ * @retval OPUS_INVALID_PACKET The compressed data passed is corrupted or of an unsupported type
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_decoder_get_nb_samples(const OpusDecoder *dec, const unsigned char packet[], opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
+
+/** Applies soft-clipping to bring a float signal within the [-1,1] range. If
+ * the signal is already in that range, nothing is done. If there are values
+ * outside of [-1,1], then the signal is clipped as smoothly as possible to
+ * both fit in the range and avoid creating excessive distortion in the
+ * process.
+ * @param [in,out] pcm <tt>float*</tt>: Input PCM and modified PCM
+ * @param [in] frame_size <tt>int</tt> Number of samples per channel to process
+ * @param [in] channels <tt>int</tt>: Number of channels
+ * @param [in,out] softclip_mem <tt>float*</tt>: State memory for the soft clipping process (one float per channel, initialized to zero)
+ */
+OPUS_EXPORT void opus_pcm_soft_clip(float *pcm, int frame_size, int channels, float *softclip_mem);
+
+
+/**@}*/
+
+/** @defgroup opus_repacketizer Repacketizer
+ * @{
+ *
+ * The repacketizer can be used to merge multiple Opus packets into a single
+ * packet or alternatively to split Opus packets that have previously been
+ * merged. Splitting valid Opus packets is always guaranteed to succeed,
+ * whereas merging valid packets only succeeds if all frames have the same
+ * mode, bandwidth, and frame size, and when the total duration of the merged
+ * packet is no more than 120 ms.
+ * The repacketizer currently only operates on elementary Opus
+ * streams. It will not manipualte multistream packets successfully, except in
+ * the degenerate case where they consist of data from a single stream.
+ *
+ * The repacketizing process starts with creating a repacketizer state, either
+ * by calling opus_repacketizer_create() or by allocating the memory yourself,
+ * e.g.,
+ * @code
+ * OpusRepacketizer *rp;
+ * rp = (OpusRepacketizer*)malloc(opus_repacketizer_get_size());
+ * if (rp != NULL)
+ * opus_repacketizer_init(rp);
+ * @endcode
+ *
+ * Then the application should submit packets with opus_repacketizer_cat(),
+ * extract new packets with opus_repacketizer_out() or
+ * opus_repacketizer_out_range(), and then reset the state for the next set of
+ * input packets via opus_repacketizer_init().
+ *
+ * For example, to split a sequence of packets into individual frames:
+ * @code
+ * unsigned char *data;
+ * int len;
+ * while (get_next_packet(&data, &len))
+ * {
+ * unsigned char out[1276];
+ * opus_int32 out_len;
+ * int nb_frames;
+ * int err;
+ * int i;
+ * err = opus_repacketizer_cat(rp, data, len);
+ * if (err != OPUS_OK)
+ * {
+ * release_packet(data);
+ * return err;
+ * }
+ * nb_frames = opus_repacketizer_get_nb_frames(rp);
+ * for (i = 0; i < nb_frames; i++)
+ * {
+ * out_len = opus_repacketizer_out_range(rp, i, i+1, out, sizeof(out));
+ * if (out_len < 0)
+ * {
+ * release_packet(data);
+ * return (int)out_len;
+ * }
+ * output_next_packet(out, out_len);
+ * }
+ * opus_repacketizer_init(rp);
+ * release_packet(data);
+ * }
+ * @endcode
+ *
+ * Alternatively, to combine a sequence of frames into packets that each
+ * contain up to <code>TARGET_DURATION_MS</code> milliseconds of data:
+ * @code
+ * // The maximum number of packets with duration TARGET_DURATION_MS occurs
+ * // when the frame size is 2.5 ms, for a total of (TARGET_DURATION_MS*2/5)
+ * // packets.
+ * unsigned char *data[(TARGET_DURATION_MS*2/5)+1];
+ * opus_int32 len[(TARGET_DURATION_MS*2/5)+1];
+ * int nb_packets;
+ * unsigned char out[1277*(TARGET_DURATION_MS*2/2)];
+ * opus_int32 out_len;
+ * int prev_toc;
+ * nb_packets = 0;
+ * while (get_next_packet(data+nb_packets, len+nb_packets))
+ * {
+ * int nb_frames;
+ * int err;
+ * nb_frames = opus_packet_get_nb_frames(data[nb_packets], len[nb_packets]);
+ * if (nb_frames < 1)
+ * {
+ * release_packets(data, nb_packets+1);
+ * return nb_frames;
+ * }
+ * nb_frames += opus_repacketizer_get_nb_frames(rp);
+ * // If adding the next packet would exceed our target, or it has an
+ * // incompatible TOC sequence, output the packets we already have before
+ * // submitting it.
+ * // N.B., The nb_packets > 0 check ensures we've submitted at least one
+ * // packet since the last call to opus_repacketizer_init(). Otherwise a
+ * // single packet longer than TARGET_DURATION_MS would cause us to try to
+ * // output an (invalid) empty packet. It also ensures that prev_toc has
+ * // been set to a valid value. Additionally, len[nb_packets] > 0 is
+ * // guaranteed by the call to opus_packet_get_nb_frames() above, so the
+ * // reference to data[nb_packets][0] should be valid.
+ * if (nb_packets > 0 && (
+ * ((prev_toc & 0xFC) != (data[nb_packets][0] & 0xFC)) ||
+ * opus_packet_get_samples_per_frame(data[nb_packets], 48000)*nb_frames >
+ * TARGET_DURATION_MS*48))
+ * {
+ * out_len = opus_repacketizer_out(rp, out, sizeof(out));
+ * if (out_len < 0)
+ * {
+ * release_packets(data, nb_packets+1);
+ * return (int)out_len;
+ * }
+ * output_next_packet(out, out_len);
+ * opus_repacketizer_init(rp);
+ * release_packets(data, nb_packets);
+ * data[0] = data[nb_packets];
+ * len[0] = len[nb_packets];
+ * nb_packets = 0;
+ * }
+ * err = opus_repacketizer_cat(rp, data[nb_packets], len[nb_packets]);
+ * if (err != OPUS_OK)
+ * {
+ * release_packets(data, nb_packets+1);
+ * return err;
+ * }
+ * prev_toc = data[nb_packets][0];
+ * nb_packets++;
+ * }
+ * // Output the final, partial packet.
+ * if (nb_packets > 0)
+ * {
+ * out_len = opus_repacketizer_out(rp, out, sizeof(out));
+ * release_packets(data, nb_packets);
+ * if (out_len < 0)
+ * return (int)out_len;
+ * output_next_packet(out, out_len);
+ * }
+ * @endcode
+ *
+ * An alternate way of merging packets is to simply call opus_repacketizer_cat()
+ * unconditionally until it fails. At that point, the merged packet can be
+ * obtained with opus_repacketizer_out() and the input packet for which
+ * opus_repacketizer_cat() needs to be re-added to a newly reinitialized
+ * repacketizer state.
+ */
+
+typedef struct OpusRepacketizer OpusRepacketizer;
+
+/** Gets the size of an <code>OpusRepacketizer</code> structure.
+ * @returns The size in bytes.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_size(void);
+
+/** (Re)initializes a previously allocated repacketizer state.
+ * The state must be at least the size returned by opus_repacketizer_get_size().
+ * This can be used for applications which use their own allocator instead of
+ * malloc().
+ * It must also be called to reset the queue of packets waiting to be
+ * repacketized, which is necessary if the maximum packet duration of 120 ms
+ * is reached or if you wish to submit packets with a different Opus
+ * configuration (coding mode, audio bandwidth, frame size, or channel count).
+ * Failure to do so will prevent a new packet from being added with
+ * opus_repacketizer_cat().
+ * @see opus_repacketizer_create
+ * @see opus_repacketizer_get_size
+ * @see opus_repacketizer_cat
+ * @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state to
+ * (re)initialize.
+ * @returns A pointer to the same repacketizer state that was passed in.
+ */
+OPUS_EXPORT OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1);
+
+/** Allocates memory and initializes the new repacketizer with
+ * opus_repacketizer_init().
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusRepacketizer *opus_repacketizer_create(void);
+
+/** Frees an <code>OpusRepacketizer</code> allocated by
+ * opus_repacketizer_create().
+ * @param[in] rp <tt>OpusRepacketizer*</tt>: State to be freed.
+ */
+OPUS_EXPORT void opus_repacketizer_destroy(OpusRepacketizer *rp);
+
+/** Add a packet to the current repacketizer state.
+ * This packet must match the configuration of any packets already submitted
+ * for repacketization since the last call to opus_repacketizer_init().
+ * This means that it must have the same coding mode, audio bandwidth, frame
+ * size, and channel count.
+ * This can be checked in advance by examining the top 6 bits of the first
+ * byte of the packet, and ensuring they match the top 6 bits of the first
+ * byte of any previously submitted packet.
+ * The total duration of audio in the repacketizer state also must not exceed
+ * 120 ms, the maximum duration of a single packet, after adding this packet.
+ *
+ * The contents of the current repacketizer state can be extracted into new
+ * packets using opus_repacketizer_out() or opus_repacketizer_out_range().
+ *
+ * In order to add a packet with a different configuration or to add more
+ * audio beyond 120 ms, you must clear the repacketizer state by calling
+ * opus_repacketizer_init().
+ * If a packet is too large to add to the current repacketizer state, no part
+ * of it is added, even if it contains multiple frames, some of which might
+ * fit.
+ * If you wish to be able to add parts of such packets, you should first use
+ * another repacketizer to split the packet into pieces and add them
+ * individually.
+ * @see opus_repacketizer_out_range
+ * @see opus_repacketizer_out
+ * @see opus_repacketizer_init
+ * @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state to which to
+ * add the packet.
+ * @param[in] data <tt>const unsigned char*</tt>: The packet data.
+ * The application must ensure
+ * this pointer remains valid
+ * until the next call to
+ * opus_repacketizer_init() or
+ * opus_repacketizer_destroy().
+ * @param len <tt>opus_int32</tt>: The number of bytes in the packet data.
+ * @returns An error code indicating whether or not the operation succeeded.
+ * @retval #OPUS_OK The packet's contents have been added to the repacketizer
+ * state.
+ * @retval #OPUS_INVALID_PACKET The packet did not have a valid TOC sequence,
+ * the packet's TOC sequence was not compatible
+ * with previously submitted packets (because
+ * the coding mode, audio bandwidth, frame size,
+ * or channel count did not match), or adding
+ * this packet would increase the total amount of
+ * audio stored in the repacketizer state to more
+ * than 120 ms.
+ */
+OPUS_EXPORT int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
+
+
+/** Construct a new packet from data previously submitted to the repacketizer
+ * state via opus_repacketizer_cat().
+ * @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state from which to
+ * construct the new packet.
+ * @param begin <tt>int</tt>: The index of the first frame in the current
+ * repacketizer state to include in the output.
+ * @param end <tt>int</tt>: One past the index of the last frame in the
+ * current repacketizer state to include in the
+ * output.
+ * @param[out] data <tt>const unsigned char*</tt>: The buffer in which to
+ * store the output packet.
+ * @param maxlen <tt>opus_int32</tt>: The maximum number of bytes to store in
+ * the output buffer. In order to guarantee
+ * success, this should be at least
+ * <code>1276</code> for a single frame,
+ * or for multiple frames,
+ * <code>1277*(end-begin)</code>.
+ * However, <code>1*(end-begin)</code> plus
+ * the size of all packet data submitted to
+ * the repacketizer since the last call to
+ * opus_repacketizer_init() or
+ * opus_repacketizer_create() is also
+ * sufficient, and possibly much smaller.
+ * @returns The total size of the output packet on success, or an error code
+ * on failure.
+ * @retval #OPUS_BAD_ARG <code>[begin,end)</code> was an invalid range of
+ * frames (begin < 0, begin >= end, or end >
+ * opus_repacketizer_get_nb_frames()).
+ * @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the
+ * complete output packet.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Return the total number of frames contained in packet data submitted to
+ * the repacketizer state so far via opus_repacketizer_cat() since the last
+ * call to opus_repacketizer_init() or opus_repacketizer_create().
+ * This defines the valid range of packets that can be extracted with
+ * opus_repacketizer_out_range() or opus_repacketizer_out().
+ * @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state containing the
+ * frames.
+ * @returns The total number of frames contained in the packet data submitted
+ * to the repacketizer state.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp) OPUS_ARG_NONNULL(1);
+
+/** Construct a new packet from data previously submitted to the repacketizer
+ * state via opus_repacketizer_cat().
+ * This is a convenience routine that returns all the data submitted so far
+ * in a single packet.
+ * It is equivalent to calling
+ * @code
+ * opus_repacketizer_out_range(rp, 0, opus_repacketizer_get_nb_frames(rp),
+ * data, maxlen)
+ * @endcode
+ * @param rp <tt>OpusRepacketizer*</tt>: The repacketizer state from which to
+ * construct the new packet.
+ * @param[out] data <tt>const unsigned char*</tt>: The buffer in which to
+ * store the output packet.
+ * @param maxlen <tt>opus_int32</tt>: The maximum number of bytes to store in
+ * the output buffer. In order to guarantee
+ * success, this should be at least
+ * <code>1277*opus_repacketizer_get_nb_frames(rp)</code>.
+ * However,
+ * <code>1*opus_repacketizer_get_nb_frames(rp)</code>
+ * plus the size of all packet data
+ * submitted to the repacketizer since the
+ * last call to opus_repacketizer_init() or
+ * opus_repacketizer_create() is also
+ * sufficient, and possibly much smaller.
+ * @returns The total size of the output packet on success, or an error code
+ * on failure.
+ * @retval #OPUS_BUFFER_TOO_SMALL \a maxlen was insufficient to contain the
+ * complete output packet.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus_int32 maxlen) OPUS_ARG_NONNULL(1);
+
+/** Pads a given Opus packet to a larger size (possibly changing the TOC sequence).
+ * @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
+ * packet to pad.
+ * @param len <tt>opus_int32</tt>: The size of the packet.
+ * This must be at least 1.
+ * @param new_len <tt>opus_int32</tt>: The desired size of the packet after padding.
+ * This must be at least as large as len.
+ * @returns an error code
+ * @retval #OPUS_OK \a on success.
+ * @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len.
+ * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
+ */
+OPUS_EXPORT int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len);
+
+/** Remove all padding from a given Opus packet and rewrite the TOC sequence to
+ * minimize space usage.
+ * @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
+ * packet to strip.
+ * @param len <tt>opus_int32</tt>: The size of the packet.
+ * This must be at least 1.
+ * @returns The new size of the output packet on success, or an error code
+ * on failure.
+ * @retval #OPUS_BAD_ARG \a len was less than 1.
+ * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len);
+
+/** Pads a given Opus multi-stream packet to a larger size (possibly changing the TOC sequence).
+ * @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
+ * packet to pad.
+ * @param len <tt>opus_int32</tt>: The size of the packet.
+ * This must be at least 1.
+ * @param new_len <tt>opus_int32</tt>: The desired size of the packet after padding.
+ * This must be at least 1.
+ * @param nb_streams <tt>opus_int32</tt>: The number of streams (not channels) in the packet.
+ * This must be at least as large as len.
+ * @returns an error code
+ * @retval #OPUS_OK \a on success.
+ * @retval #OPUS_BAD_ARG \a len was less than 1.
+ * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
+ */
+OPUS_EXPORT int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len, int nb_streams);
+
+/** Remove all padding from a given Opus multi-stream packet and rewrite the TOC sequence to
+ * minimize space usage.
+ * @param[in,out] data <tt>const unsigned char*</tt>: The buffer containing the
+ * packet to strip.
+ * @param len <tt>opus_int32</tt>: The size of the packet.
+ * This must be at least 1.
+ * @param nb_streams <tt>opus_int32</tt>: The number of streams (not channels) in the packet.
+ * This must be at least 1.
+ * @returns The new size of the output packet on success, or an error code
+ * on failure.
+ * @retval #OPUS_BAD_ARG \a len was less than 1 or new_len was less than len.
+ * @retval #OPUS_INVALID_PACKET \a data did not contain a valid Opus packet.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, int nb_streams);
+
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* OPUS_H */
diff --git a/drivers/opus/opus_compare.c b/drivers/opus/opus_compare.c
new file mode 100644
index 0000000000..06c67d752f
--- /dev/null
+++ b/drivers/opus/opus_compare.c
@@ -0,0 +1,379 @@
+/* Copyright (c) 2011-2012 Xiph.Org Foundation, Mozilla Corporation
+ Written by Jean-Marc Valin and Timothy B. Terriberry */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+#define OPUS_PI (3.14159265F)
+
+#define OPUS_COSF(_x) ((float)cos(_x))
+#define OPUS_SINF(_x) ((float)sin(_x))
+
+static void *check_alloc(void *_ptr){
+ if(_ptr==NULL){
+ fprintf(stderr,"Out of memory.\n");
+ exit(EXIT_FAILURE);
+ }
+ return _ptr;
+}
+
+static void *opus_malloc(size_t _size){
+ return check_alloc(malloc(_size));
+}
+
+static void *opus_realloc(void *_ptr,size_t _size){
+ return check_alloc(realloc(_ptr,_size));
+}
+
+static size_t read_pcm16(float **_samples,FILE *_fin,int _nchannels){
+ unsigned char buf[1024];
+ float *samples;
+ size_t nsamples;
+ size_t csamples;
+ size_t xi;
+ size_t nread;
+ samples=NULL;
+ nsamples=csamples=0;
+ for(;;){
+ nread=fread(buf,2*_nchannels,1024/(2*_nchannels),_fin);
+ if(nread<=0)break;
+ if(nsamples+nread>csamples){
+ do csamples=csamples<<1|1;
+ while(nsamples+nread>csamples);
+ samples=(float *)opus_realloc(samples,
+ _nchannels*csamples*sizeof(*samples));
+ }
+ for(xi=0;xi<nread;xi++){
+ int ci;
+ for(ci=0;ci<_nchannels;ci++){
+ int s;
+ s=buf[2*(xi*_nchannels+ci)+1]<<8|buf[2*(xi*_nchannels+ci)];
+ s=((s&0xFFFF)^0x8000)-0x8000;
+ samples[(nsamples+xi)*_nchannels+ci]=s;
+ }
+ }
+ nsamples+=nread;
+ }
+ *_samples=(float *)opus_realloc(samples,
+ _nchannels*nsamples*sizeof(*samples));
+ return nsamples;
+}
+
+static void band_energy(float *_out,float *_ps,const int *_bands,int _nbands,
+ const float *_in,int _nchannels,size_t _nframes,int _window_sz,
+ int _step,int _downsample){
+ float *window;
+ float *x;
+ float *c;
+ float *s;
+ size_t xi;
+ int xj;
+ int ps_sz;
+ window=(float *)opus_malloc((3+_nchannels)*_window_sz*sizeof(*window));
+ c=window+_window_sz;
+ s=c+_window_sz;
+ x=s+_window_sz;
+ ps_sz=_window_sz/2;
+ for(xj=0;xj<_window_sz;xj++){
+ window[xj]=0.5F-0.5F*OPUS_COSF((2*OPUS_PI/(_window_sz-1))*xj);
+ }
+ for(xj=0;xj<_window_sz;xj++){
+ c[xj]=OPUS_COSF((2*OPUS_PI/_window_sz)*xj);
+ }
+ for(xj=0;xj<_window_sz;xj++){
+ s[xj]=OPUS_SINF((2*OPUS_PI/_window_sz)*xj);
+ }
+ for(xi=0;xi<_nframes;xi++){
+ int ci;
+ int xk;
+ int bi;
+ for(ci=0;ci<_nchannels;ci++){
+ for(xk=0;xk<_window_sz;xk++){
+ x[ci*_window_sz+xk]=window[xk]*_in[(xi*_step+xk)*_nchannels+ci];
+ }
+ }
+ for(bi=xj=0;bi<_nbands;bi++){
+ float p[2]={0};
+ for(;xj<_bands[bi+1];xj++){
+ for(ci=0;ci<_nchannels;ci++){
+ float re;
+ float im;
+ int ti;
+ ti=0;
+ re=im=0;
+ for(xk=0;xk<_window_sz;xk++){
+ re+=c[ti]*x[ci*_window_sz+xk];
+ im-=s[ti]*x[ci*_window_sz+xk];
+ ti+=xj;
+ if(ti>=_window_sz)ti-=_window_sz;
+ }
+ re*=_downsample;
+ im*=_downsample;
+ _ps[(xi*ps_sz+xj)*_nchannels+ci]=re*re+im*im+100000;
+ p[ci]+=_ps[(xi*ps_sz+xj)*_nchannels+ci];
+ }
+ }
+ if(_out){
+ _out[(xi*_nbands+bi)*_nchannels]=p[0]/(_bands[bi+1]-_bands[bi]);
+ if(_nchannels==2){
+ _out[(xi*_nbands+bi)*_nchannels+1]=p[1]/(_bands[bi+1]-_bands[bi]);
+ }
+ }
+ }
+ }
+ free(window);
+}
+
+#define NBANDS (21)
+#define NFREQS (240)
+
+/*Bands on which we compute the pseudo-NMR (Bark-derived
+ CELT bands).*/
+static const int BANDS[NBANDS+1]={
+ 0,2,4,6,8,10,12,14,16,20,24,28,32,40,48,56,68,80,96,120,156,200
+};
+
+#define TEST_WIN_SIZE (480)
+#define TEST_WIN_STEP (120)
+
+int main(int _argc,const char **_argv){
+ FILE *fin1;
+ FILE *fin2;
+ float *x;
+ float *y;
+ float *xb;
+ float *X;
+ float *Y;
+ double err;
+ float Q;
+ size_t xlength;
+ size_t ylength;
+ size_t nframes;
+ size_t xi;
+ int ci;
+ int xj;
+ int bi;
+ int nchannels;
+ unsigned rate;
+ int downsample;
+ int ybands;
+ int yfreqs;
+ int max_compare;
+ if(_argc<3||_argc>6){
+ fprintf(stderr,"Usage: %s [-s] [-r rate2] <file1.sw> <file2.sw>\n",
+ _argv[0]);
+ return EXIT_FAILURE;
+ }
+ nchannels=1;
+ if(strcmp(_argv[1],"-s")==0){
+ nchannels=2;
+ _argv++;
+ }
+ rate=48000;
+ ybands=NBANDS;
+ yfreqs=NFREQS;
+ downsample=1;
+ if(strcmp(_argv[1],"-r")==0){
+ rate=atoi(_argv[2]);
+ if(rate!=8000&&rate!=12000&&rate!=16000&&rate!=24000&&rate!=48000){
+ fprintf(stderr,
+ "Sampling rate must be 8000, 12000, 16000, 24000, or 48000\n");
+ return EXIT_FAILURE;
+ }
+ downsample=48000/rate;
+ switch(rate){
+ case 8000:ybands=13;break;
+ case 12000:ybands=15;break;
+ case 16000:ybands=17;break;
+ case 24000:ybands=19;break;
+ }
+ yfreqs=NFREQS/downsample;
+ _argv+=2;
+ }
+ fin1=fopen(_argv[1],"rb");
+ if(fin1==NULL){
+ fprintf(stderr,"Error opening '%s'.\n",_argv[1]);
+ return EXIT_FAILURE;
+ }
+ fin2=fopen(_argv[2],"rb");
+ if(fin2==NULL){
+ fprintf(stderr,"Error opening '%s'.\n",_argv[2]);
+ fclose(fin1);
+ return EXIT_FAILURE;
+ }
+ /*Read in the data and allocate scratch space.*/
+ xlength=read_pcm16(&x,fin1,2);
+ if(nchannels==1){
+ for(xi=0;xi<xlength;xi++)x[xi]=.5*(x[2*xi]+x[2*xi+1]);
+ }
+ fclose(fin1);
+ ylength=read_pcm16(&y,fin2,nchannels);
+ fclose(fin2);
+ if(xlength!=ylength*downsample){
+ fprintf(stderr,"Sample counts do not match (%lu!=%lu).\n",
+ (unsigned long)xlength,(unsigned long)ylength*downsample);
+ return EXIT_FAILURE;
+ }
+ if(xlength<TEST_WIN_SIZE){
+ fprintf(stderr,"Insufficient sample data (%lu<%i).\n",
+ (unsigned long)xlength,TEST_WIN_SIZE);
+ return EXIT_FAILURE;
+ }
+ nframes=(xlength-TEST_WIN_SIZE+TEST_WIN_STEP)/TEST_WIN_STEP;
+ xb=(float *)opus_malloc(nframes*NBANDS*nchannels*sizeof(*xb));
+ X=(float *)opus_malloc(nframes*NFREQS*nchannels*sizeof(*X));
+ Y=(float *)opus_malloc(nframes*yfreqs*nchannels*sizeof(*Y));
+ /*Compute the per-band spectral energy of the original signal
+ and the error.*/
+ band_energy(xb,X,BANDS,NBANDS,x,nchannels,nframes,
+ TEST_WIN_SIZE,TEST_WIN_STEP,1);
+ free(x);
+ band_energy(NULL,Y,BANDS,ybands,y,nchannels,nframes,
+ TEST_WIN_SIZE/downsample,TEST_WIN_STEP/downsample,downsample);
+ free(y);
+ for(xi=0;xi<nframes;xi++){
+ /*Frequency masking (low to high): 10 dB/Bark slope.*/
+ for(bi=1;bi<NBANDS;bi++){
+ for(ci=0;ci<nchannels;ci++){
+ xb[(xi*NBANDS+bi)*nchannels+ci]+=
+ 0.1F*xb[(xi*NBANDS+bi-1)*nchannels+ci];
+ }
+ }
+ /*Frequency masking (high to low): 15 dB/Bark slope.*/
+ for(bi=NBANDS-1;bi-->0;){
+ for(ci=0;ci<nchannels;ci++){
+ xb[(xi*NBANDS+bi)*nchannels+ci]+=
+ 0.03F*xb[(xi*NBANDS+bi+1)*nchannels+ci];
+ }
+ }
+ if(xi>0){
+ /*Temporal masking: -3 dB/2.5ms slope.*/
+ for(bi=0;bi<NBANDS;bi++){
+ for(ci=0;ci<nchannels;ci++){
+ xb[(xi*NBANDS+bi)*nchannels+ci]+=
+ 0.5F*xb[((xi-1)*NBANDS+bi)*nchannels+ci];
+ }
+ }
+ }
+ /* Allowing some cross-talk */
+ if(nchannels==2){
+ for(bi=0;bi<NBANDS;bi++){
+ float l,r;
+ l=xb[(xi*NBANDS+bi)*nchannels+0];
+ r=xb[(xi*NBANDS+bi)*nchannels+1];
+ xb[(xi*NBANDS+bi)*nchannels+0]+=0.01F*r;
+ xb[(xi*NBANDS+bi)*nchannels+1]+=0.01F*l;
+ }
+ }
+
+ /* Apply masking */
+ for(bi=0;bi<ybands;bi++){
+ for(xj=BANDS[bi];xj<BANDS[bi+1];xj++){
+ for(ci=0;ci<nchannels;ci++){
+ X[(xi*NFREQS+xj)*nchannels+ci]+=
+ 0.1F*xb[(xi*NBANDS+bi)*nchannels+ci];
+ Y[(xi*yfreqs+xj)*nchannels+ci]+=
+ 0.1F*xb[(xi*NBANDS+bi)*nchannels+ci];
+ }
+ }
+ }
+ }
+
+ /* Average of consecutive frames to make comparison slightly less sensitive */
+ for(bi=0;bi<ybands;bi++){
+ for(xj=BANDS[bi];xj<BANDS[bi+1];xj++){
+ for(ci=0;ci<nchannels;ci++){
+ float xtmp;
+ float ytmp;
+ xtmp = X[xj*nchannels+ci];
+ ytmp = Y[xj*nchannels+ci];
+ for(xi=1;xi<nframes;xi++){
+ float xtmp2;
+ float ytmp2;
+ xtmp2 = X[(xi*NFREQS+xj)*nchannels+ci];
+ ytmp2 = Y[(xi*yfreqs+xj)*nchannels+ci];
+ X[(xi*NFREQS+xj)*nchannels+ci] += xtmp;
+ Y[(xi*yfreqs+xj)*nchannels+ci] += ytmp;
+ xtmp = xtmp2;
+ ytmp = ytmp2;
+ }
+ }
+ }
+ }
+
+ /*If working at a lower sampling rate, don't take into account the last
+ 300 Hz to allow for different transition bands.
+ For 12 kHz, we don't skip anything, because the last band already skips
+ 400 Hz.*/
+ if(rate==48000)max_compare=BANDS[NBANDS];
+ else if(rate==12000)max_compare=BANDS[ybands];
+ else max_compare=BANDS[ybands]-3;
+ err=0;
+ for(xi=0;xi<nframes;xi++){
+ double Ef;
+ Ef=0;
+ for(bi=0;bi<ybands;bi++){
+ double Eb;
+ Eb=0;
+ for(xj=BANDS[bi];xj<BANDS[bi+1]&&xj<max_compare;xj++){
+ for(ci=0;ci<nchannels;ci++){
+ float re;
+ float im;
+ re=Y[(xi*yfreqs+xj)*nchannels+ci]/X[(xi*NFREQS+xj)*nchannels+ci];
+ im=re-log(re)-1;
+ /*Make comparison less sensitive around the SILK/CELT cross-over to
+ allow for mode freedom in the filters.*/
+ if(xj>=79&&xj<=81)im*=0.1F;
+ if(xj==80)im*=0.1F;
+ Eb+=im;
+ }
+ }
+ Eb /= (BANDS[bi+1]-BANDS[bi])*nchannels;
+ Ef += Eb*Eb;
+ }
+ /*Using a fixed normalization value means we're willing to accept slightly
+ lower quality for lower sampling rates.*/
+ Ef/=NBANDS;
+ Ef*=Ef;
+ err+=Ef*Ef;
+ }
+ err=pow(err/nframes,1.0/16);
+ Q=100*(1-0.5*log(1+err)/log(1.13));
+ if(Q<0){
+ fprintf(stderr,"Test vector FAILS\n");
+ fprintf(stderr,"Internal weighted error is %f\n",err);
+ return EXIT_FAILURE;
+ }
+ else{
+ fprintf(stderr,"Test vector PASSES\n");
+ fprintf(stderr,
+ "Opus quality metric: %.1f %% (internal weighted error is %f)\n",Q,err);
+ return EXIT_SUCCESS;
+ }
+}
diff --git a/drivers/opus/opus_config.h b/drivers/opus/opus_config.h
new file mode 100644
index 0000000000..98c3e87cc6
--- /dev/null
+++ b/drivers/opus/opus_config.h
@@ -0,0 +1,129 @@
+/* Opus configuration header */
+/* Based on the output of libopus configure script */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+#if (!defined( _MSC_VER ) || ( _MSC_VER >= 1800 ))
+
+/* Define to 1 if you have the `lrint' function. */
+#define HAVE_LRINT 1
+
+/* Define to 1 if you have the `lrintf' function. */
+#define HAVE_LRINTF 1
+
+#endif
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#define LT_OBJDIR ".libs/"
+
+#ifdef OPUS_ARM_OPT
+/* Make use of ARM asm optimization */
+#define OPUS_ARM_ASM 1
+
+/* Use generic ARMv4 inline asm optimizations */
+#define OPUS_ARM_INLINE_ASM 1
+
+/* Use ARMv5E inline asm optimizations */
+#define OPUS_ARM_INLINE_EDSP 1
+
+/* Use ARMv6 inline asm optimizations */
+#define OPUS_ARM_INLINE_MEDIA 1
+
+/* Use ARM NEON inline asm optimizations */
+#define OPUS_ARM_INLINE_NEON 1
+
+/* Define if assembler supports EDSP instructions */
+#define OPUS_ARM_MAY_HAVE_EDSP 1
+
+/* Define if assembler supports ARMv6 media instructions */
+#define OPUS_ARM_MAY_HAVE_MEDIA 1
+
+/* Define if compiler supports NEON instructions */
+#define OPUS_ARM_MAY_HAVE_NEON 1
+#endif // OPUS_ARM_OPT
+
+#ifdef OPUS_ARM64_OPT
+/* Make use of ARM asm optimization */
+#define OPUS_ARM_ASM 1
+
+/* Use ARMv6 inline asm optimizations */
+#define OPUS_ARM_INLINE_MEDIA 1 // work
+
+/* Use ARM NEON inline asm optimizations */
+#define OPUS_ARM_INLINE_NEON 1 // work
+
+/* Define if assembler supports EDSP instructions */
+#define OPUS_ARM_MAY_HAVE_EDSP 1 // work
+
+/* Define if assembler supports ARMv6 media instructions */
+#define OPUS_ARM_MAY_HAVE_MEDIA 1 // work
+
+/* Define if compiler supports NEON instructions */
+#define OPUS_ARM_MAY_HAVE_NEON 1
+
+#endif // OPUS_ARM64_OPT
+
+/* This is a build of OPUS */
+#define OPUS_BUILD /**/
+
+#ifndef WIN32
+ /* Use C99 variable-size arrays */
+ #define VAR_ARRAYS 1
+#else
+ /* Fixes VS 2013 compile error */
+ #define USE_ALLOCA 1
+#endif
+
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to the equivalent of the C99 'restrict' keyword, or to
+ nothing if this is not supported. Do not define if restrict is
+ supported directly. */
+#if (!defined( _MSC_VER ) || ( _MSC_VER >= 1800 ))
+#define restrict __restrict
+#else
+#undef restrict
+#endif
+/* Work around a bug in Sun C++: it does not support _Restrict or
+ __restrict__, even though the corresponding Sun C compiler ends up with
+ "#define restrict _Restrict" or "#define restrict __restrict__" in the
+ previous line. Perhaps some future version of Sun C++ will work with
+ restrict; if so, hopefully it defines __RESTRICT like Sun C does. */
+#if defined __SUNPRO_CC && !defined __RESTRICT
+# define _Restrict
+# define __restrict__
+#endif
diff --git a/drivers/opus/opus_custom.h b/drivers/opus/opus_custom.h
new file mode 100644
index 0000000000..32fcb81ac7
--- /dev/null
+++ b/drivers/opus/opus_custom.h
@@ -0,0 +1,342 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Copyright (c) 2008-2012 Gregory Maxwell
+ Written by Jean-Marc Valin and Gregory Maxwell */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ @file opus_custom.h
+ @brief Opus-Custom reference implementation API
+ */
+
+#ifndef OPUS_CUSTOM_H
+#define OPUS_CUSTOM_H
+
+#include "opus/opus_defines.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef CUSTOM_MODES
+# define OPUS_CUSTOM_EXPORT OPUS_EXPORT
+# define OPUS_CUSTOM_EXPORT_STATIC OPUS_EXPORT
+#else
+# define OPUS_CUSTOM_EXPORT
+# ifdef OPUS_BUILD
+# define OPUS_CUSTOM_EXPORT_STATIC static OPUS_INLINE
+# else
+# define OPUS_CUSTOM_EXPORT_STATIC
+# endif
+#endif
+
+/** @defgroup opus_custom Opus Custom
+ * @{
+ * Opus Custom is an optional part of the Opus specification and
+ * reference implementation which uses a distinct API from the regular
+ * API and supports frame sizes that are not normally supported.\ Use
+ * of Opus Custom is discouraged for all but very special applications
+ * for which a frame size different from 2.5, 5, 10, or 20 ms is needed
+ * (for either complexity or latency reasons) and where interoperability
+ * is less important.
+ *
+ * In addition to the interoperability limitations the use of Opus custom
+ * disables a substantial chunk of the codec and generally lowers the
+ * quality available at a given bitrate. Normally when an application needs
+ * a different frame size from the codec it should buffer to match the
+ * sizes but this adds a small amount of delay which may be important
+ * in some very low latency applications. Some transports (especially
+ * constant rate RF transports) may also work best with frames of
+ * particular durations.
+ *
+ * Libopus only supports custom modes if they are enabled at compile time.
+ *
+ * The Opus Custom API is similar to the regular API but the
+ * @ref opus_encoder_create and @ref opus_decoder_create calls take
+ * an additional mode parameter which is a structure produced by
+ * a call to @ref opus_custom_mode_create. Both the encoder and decoder
+ * must create a mode using the same sample rate (fs) and frame size
+ * (frame size) so these parameters must either be signaled out of band
+ * or fixed in a particular implementation.
+ *
+ * Similar to regular Opus the custom modes support on the fly frame size
+ * switching, but the sizes available depend on the particular frame size in
+ * use. For some initial frame sizes on a single on the fly size is available.
+ */
+
+/** Contains the state of an encoder. One encoder state is needed
+ for each stream. It is initialized once at the beginning of the
+ stream. Do *not* re-initialize the state for every frame.
+ @brief Encoder state
+ */
+typedef struct OpusCustomEncoder OpusCustomEncoder;
+
+/** State of the decoder. One decoder state is needed for each stream.
+ It is initialized once at the beginning of the stream. Do *not*
+ re-initialize the state for every frame.
+ @brief Decoder state
+ */
+typedef struct OpusCustomDecoder OpusCustomDecoder;
+
+/** The mode contains all the information necessary to create an
+ encoder. Both the encoder and decoder need to be initialized
+ with exactly the same mode, otherwise the output will be
+ corrupted.
+ @brief Mode configuration
+ */
+typedef struct OpusCustomMode OpusCustomMode;
+
+/** Creates a new mode struct. This will be passed to an encoder or
+ * decoder. The mode MUST NOT BE DESTROYED until the encoders and
+ * decoders that use it are destroyed as well.
+ * @param [in] Fs <tt>int</tt>: Sampling rate (8000 to 96000 Hz)
+ * @param [in] frame_size <tt>int</tt>: Number of samples (per channel) to encode in each
+ * packet (64 - 1024, prime factorization must contain zero or more 2s, 3s, or 5s and no other primes)
+ * @param [out] error <tt>int*</tt>: Returned error code (if NULL, no error will be returned)
+ * @return A newly created mode
+ */
+OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomMode *opus_custom_mode_create(opus_int32 Fs, int frame_size, int *error);
+
+/** Destroys a mode struct. Only call this after all encoders and
+ * decoders using this mode are destroyed as well.
+ * @param [in] mode <tt>OpusCustomMode*</tt>: Mode to be freed.
+ */
+OPUS_CUSTOM_EXPORT void opus_custom_mode_destroy(OpusCustomMode *mode);
+
+
+#if !defined(OPUS_BUILD) || defined(CELT_ENCODER_C)
+
+/* Encoder */
+/** Gets the size of an OpusCustomEncoder structure.
+ * @param [in] mode <tt>OpusCustomMode *</tt>: Mode configuration
+ * @param [in] channels <tt>int</tt>: Number of channels
+ * @returns size
+ */
+OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_encoder_get_size(
+ const OpusCustomMode *mode,
+ int channels
+) OPUS_ARG_NONNULL(1);
+
+# ifdef CUSTOM_MODES
+/** Initializes a previously allocated encoder state
+ * The memory pointed to by st must be the size returned by opus_custom_encoder_get_size.
+ * This is intended for applications which use their own allocator instead of malloc.
+ * @see opus_custom_encoder_create(),opus_custom_encoder_get_size()
+ * To reset a previously initialized state use the OPUS_RESET_STATE CTL.
+ * @param [in] st <tt>OpusCustomEncoder*</tt>: Encoder state
+ * @param [in] mode <tt>OpusCustomMode *</tt>: Contains all the information about the characteristics of
+ * the stream (must be the same characteristics as used for the
+ * decoder)
+ * @param [in] channels <tt>int</tt>: Number of channels
+ * @return OPUS_OK Success or @ref opus_errorcodes
+ */
+OPUS_CUSTOM_EXPORT int opus_custom_encoder_init(
+ OpusCustomEncoder *st,
+ const OpusCustomMode *mode,
+ int channels
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
+# endif
+#endif
+
+
+/** Creates a new encoder state. Each stream needs its own encoder
+ * state (can't be shared across simultaneous streams).
+ * @param [in] mode <tt>OpusCustomMode*</tt>: Contains all the information about the characteristics of
+ * the stream (must be the same characteristics as used for the
+ * decoder)
+ * @param [in] channels <tt>int</tt>: Number of channels
+ * @param [out] error <tt>int*</tt>: Returns an error code
+ * @return Newly created encoder state.
+*/
+OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomEncoder *opus_custom_encoder_create(
+ const OpusCustomMode *mode,
+ int channels,
+ int *error
+) OPUS_ARG_NONNULL(1);
+
+
+/** Destroys a an encoder state.
+ * @param[in] st <tt>OpusCustomEncoder*</tt>: State to be freed.
+ */
+OPUS_CUSTOM_EXPORT void opus_custom_encoder_destroy(OpusCustomEncoder *st);
+
+/** Encodes a frame of audio.
+ * @param [in] st <tt>OpusCustomEncoder*</tt>: Encoder state
+ * @param [in] pcm <tt>float*</tt>: PCM audio in float format, with a normal range of +/-1.0.
+ * Samples with a range beyond +/-1.0 are supported but will
+ * be clipped by decoders using the integer API and should
+ * only be used if it is known that the far end supports
+ * extended dynamic range. There must be exactly
+ * frame_size samples per channel.
+ * @param [in] frame_size <tt>int</tt>: Number of samples per frame of input signal
+ * @param [out] compressed <tt>char *</tt>: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long.
+ * @param [in] maxCompressedBytes <tt>int</tt>: Maximum number of bytes to use for compressing the frame
+ * (can change from one frame to another)
+ * @return Number of bytes written to "compressed".
+ * If negative, an error has occurred (see error codes). It is IMPORTANT that
+ * the length returned be somehow transmitted to the decoder. Otherwise, no
+ * decoding is possible.
+ */
+OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode_float(
+ OpusCustomEncoder *st,
+ const float *pcm,
+ int frame_size,
+ unsigned char *compressed,
+ int maxCompressedBytes
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
+
+/** Encodes a frame of audio.
+ * @param [in] st <tt>OpusCustomEncoder*</tt>: Encoder state
+ * @param [in] pcm <tt>opus_int16*</tt>: PCM audio in signed 16-bit format (native endian).
+ * There must be exactly frame_size samples per channel.
+ * @param [in] frame_size <tt>int</tt>: Number of samples per frame of input signal
+ * @param [out] compressed <tt>char *</tt>: The compressed data is written here. This may not alias pcm and must be at least maxCompressedBytes long.
+ * @param [in] maxCompressedBytes <tt>int</tt>: Maximum number of bytes to use for compressing the frame
+ * (can change from one frame to another)
+ * @return Number of bytes written to "compressed".
+ * If negative, an error has occurred (see error codes). It is IMPORTANT that
+ * the length returned be somehow transmitted to the decoder. Otherwise, no
+ * decoding is possible.
+ */
+OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_encode(
+ OpusCustomEncoder *st,
+ const opus_int16 *pcm,
+ int frame_size,
+ unsigned char *compressed,
+ int maxCompressedBytes
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
+
+/** Perform a CTL function on an Opus custom encoder.
+ *
+ * Generally the request and subsequent arguments are generated
+ * by a convenience macro.
+ * @see opus_encoderctls
+ */
+OPUS_CUSTOM_EXPORT int opus_custom_encoder_ctl(OpusCustomEncoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1);
+
+
+#if !defined(OPUS_BUILD) || defined(CELT_DECODER_C)
+/* Decoder */
+
+/** Gets the size of an OpusCustomDecoder structure.
+ * @param [in] mode <tt>OpusCustomMode *</tt>: Mode configuration
+ * @param [in] channels <tt>int</tt>: Number of channels
+ * @returns size
+ */
+OPUS_CUSTOM_EXPORT_STATIC OPUS_WARN_UNUSED_RESULT int opus_custom_decoder_get_size(
+ const OpusCustomMode *mode,
+ int channels
+) OPUS_ARG_NONNULL(1);
+
+/** Initializes a previously allocated decoder state
+ * The memory pointed to by st must be the size returned by opus_custom_decoder_get_size.
+ * This is intended for applications which use their own allocator instead of malloc.
+ * @see opus_custom_decoder_create(),opus_custom_decoder_get_size()
+ * To reset a previously initialized state use the OPUS_RESET_STATE CTL.
+ * @param [in] st <tt>OpusCustomDecoder*</tt>: Decoder state
+ * @param [in] mode <tt>OpusCustomMode *</tt>: Contains all the information about the characteristics of
+ * the stream (must be the same characteristics as used for the
+ * encoder)
+ * @param [in] channels <tt>int</tt>: Number of channels
+ * @return OPUS_OK Success or @ref opus_errorcodes
+ */
+OPUS_CUSTOM_EXPORT_STATIC int opus_custom_decoder_init(
+ OpusCustomDecoder *st,
+ const OpusCustomMode *mode,
+ int channels
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2);
+
+#endif
+
+
+/** Creates a new decoder state. Each stream needs its own decoder state (can't
+ * be shared across simultaneous streams).
+ * @param [in] mode <tt>OpusCustomMode</tt>: Contains all the information about the characteristics of the
+ * stream (must be the same characteristics as used for the encoder)
+ * @param [in] channels <tt>int</tt>: Number of channels
+ * @param [out] error <tt>int*</tt>: Returns an error code
+ * @return Newly created decoder state.
+ */
+OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT OpusCustomDecoder *opus_custom_decoder_create(
+ const OpusCustomMode *mode,
+ int channels,
+ int *error
+) OPUS_ARG_NONNULL(1);
+
+/** Destroys a an decoder state.
+ * @param[in] st <tt>OpusCustomDecoder*</tt>: State to be freed.
+ */
+OPUS_CUSTOM_EXPORT void opus_custom_decoder_destroy(OpusCustomDecoder *st);
+
+/** Decode an opus custom frame with floating point output
+ * @param [in] st <tt>OpusCustomDecoder*</tt>: Decoder state
+ * @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss
+ * @param [in] len <tt>int</tt>: Number of bytes in payload
+ * @param [out] pcm <tt>float*</tt>: Output signal (interleaved if 2 channels). length
+ * is frame_size*channels*sizeof(float)
+ * @param [in] frame_size Number of samples per channel of available space in *pcm.
+ * @returns Number of decoded samples or @ref opus_errorcodes
+ */
+OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode_float(
+ OpusCustomDecoder *st,
+ const unsigned char *data,
+ int len,
+ float *pcm,
+ int frame_size
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Decode an opus custom frame
+ * @param [in] st <tt>OpusCustomDecoder*</tt>: Decoder state
+ * @param [in] data <tt>char*</tt>: Input payload. Use a NULL pointer to indicate packet loss
+ * @param [in] len <tt>int</tt>: Number of bytes in payload
+ * @param [out] pcm <tt>opus_int16*</tt>: Output signal (interleaved if 2 channels). length
+ * is frame_size*channels*sizeof(opus_int16)
+ * @param [in] frame_size Number of samples per channel of available space in *pcm.
+ * @returns Number of decoded samples or @ref opus_errorcodes
+ */
+OPUS_CUSTOM_EXPORT OPUS_WARN_UNUSED_RESULT int opus_custom_decode(
+ OpusCustomDecoder *st,
+ const unsigned char *data,
+ int len,
+ opus_int16 *pcm,
+ int frame_size
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Perform a CTL function on an Opus custom decoder.
+ *
+ * Generally the request and subsequent arguments are generated
+ * by a convenience macro.
+ * @see opus_genericctls
+ */
+OPUS_CUSTOM_EXPORT int opus_custom_decoder_ctl(OpusCustomDecoder * OPUS_RESTRICT st, int request, ...) OPUS_ARG_NONNULL(1);
+
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* OPUS_CUSTOM_H */
diff --git a/drivers/opus/opus_decoder.c b/drivers/opus/opus_decoder.c
new file mode 100644
index 0000000000..dea56015ce
--- /dev/null
+++ b/drivers/opus/opus_decoder.c
@@ -0,0 +1,970 @@
+/* Copyright (c) 2010 Xiph.Org Foundation, Skype Limited
+ Written by Jean-Marc Valin and Koen Vos */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+# include "opus/opus_config.h"
+#endif
+
+#ifndef OPUS_BUILD
+# error "OPUS_BUILD _MUST_ be defined to build Opus. This probably means you need other defines as well, as in a config.h. See the included build files for details."
+#endif
+
+#if defined(__GNUC__) && (__GNUC__ >= 2) && !defined(__OPTIMIZE__)
+# pragma message "You appear to be compiling without optimization, if so opus will be very slow."
+#endif
+
+#include <stdarg.h>
+#include "opus/celt/celt.h"
+#include "opus/opus.h"
+#include "opus/celt/entdec.h"
+#include "opus/celt/opus_modes.h"
+#include "opus/silk/API.h"
+#include "opus/celt/stack_alloc.h"
+#include "opus/celt/float_cast.h"
+#include "opus/opus_private.h"
+#include "opus/celt/os_support.h"
+#include "opus/silk/structs.h"
+#include "opus/silk/define.h"
+#include "opus/celt/mathops.h"
+#include "opus/celt/cpu_support.h"
+
+struct OpusDecoder {
+ int celt_dec_offset;
+ int silk_dec_offset;
+ int channels;
+ opus_int32 Fs; /** Sampling rate (at the API level) */
+ silk_DecControlStruct DecControl;
+ int decode_gain;
+
+ /* Everything beyond this point gets cleared on a reset */
+#define OPUS_DECODER_RESET_START stream_channels
+ int stream_channels;
+
+ int bandwidth;
+ int mode;
+ int prev_mode;
+ int frame_size;
+ int prev_redundancy;
+ int last_packet_duration;
+#ifndef OPUS_FIXED_POINT
+ opus_val16 softclip_mem[2];
+#endif
+
+ opus_uint32 rangeFinal;
+};
+
+#ifdef OPUS_FIXED_POINT
+static OPUS_INLINE opus_int16 SAT16(opus_int32 x) {
+ return x > 32767 ? 32767 : x < -32768 ? -32768 : (opus_int16)x;
+}
+#endif
+
+
+int opus_decoder_get_size(int channels)
+{
+ int silkDecSizeBytes, celtDecSizeBytes;
+ int ret;
+ if (channels<1 || channels > 2)
+ return 0;
+ ret = silk_Get_Decoder_Size( &silkDecSizeBytes );
+ if(ret)
+ return 0;
+ silkDecSizeBytes = align(silkDecSizeBytes);
+ celtDecSizeBytes = celt_decoder_get_size(channels);
+ return align(sizeof(OpusDecoder))+silkDecSizeBytes+celtDecSizeBytes;
+}
+
+int opus_decoder_init(OpusDecoder *st, opus_int32 Fs, int channels)
+{
+ void *silk_dec;
+ CELTDecoder *celt_dec;
+ int ret, silkDecSizeBytes;
+
+ if ((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000)
+ || (channels!=1&&channels!=2))
+ return OPUS_BAD_ARG;
+
+ OPUS_CLEAR((char*)st, opus_decoder_get_size(channels));
+ /* Initialize SILK encoder */
+ ret = silk_Get_Decoder_Size(&silkDecSizeBytes);
+ if (ret)
+ return OPUS_INTERNAL_ERROR;
+
+ silkDecSizeBytes = align(silkDecSizeBytes);
+ st->silk_dec_offset = align(sizeof(OpusDecoder));
+ st->celt_dec_offset = st->silk_dec_offset+silkDecSizeBytes;
+ silk_dec = (char*)st+st->silk_dec_offset;
+ celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset);
+ st->stream_channels = st->channels = channels;
+
+ st->Fs = Fs;
+ st->DecControl.API_sampleRate = st->Fs;
+ st->DecControl.nChannelsAPI = st->channels;
+
+ /* Reset decoder */
+ ret = silk_InitDecoder( silk_dec );
+ if(ret)return OPUS_INTERNAL_ERROR;
+
+ /* Initialize CELT decoder */
+ ret = celt_decoder_init(celt_dec, Fs, channels);
+ if(ret!=OPUS_OK)return OPUS_INTERNAL_ERROR;
+
+ celt_decoder_ctl(celt_dec, CELT_SET_SIGNALLING(0));
+
+ st->prev_mode = 0;
+ st->frame_size = Fs/400;
+ return OPUS_OK;
+}
+
+OpusDecoder *opus_decoder_create(opus_int32 Fs, int channels, int *error)
+{
+ int ret;
+ OpusDecoder *st;
+ if ((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000)
+ || (channels!=1&&channels!=2))
+ {
+ if (error)
+ *error = OPUS_BAD_ARG;
+ return NULL;
+ }
+ st = (OpusDecoder *)opus_alloc(opus_decoder_get_size(channels));
+ if (st == NULL)
+ {
+ if (error)
+ *error = OPUS_ALLOC_FAIL;
+ return NULL;
+ }
+ ret = opus_decoder_init(st, Fs, channels);
+ if (error)
+ *error = ret;
+ if (ret != OPUS_OK)
+ {
+ opus_free(st);
+ st = NULL;
+ }
+ return st;
+}
+
+static void smooth_fade(const opus_val16 *in1, const opus_val16 *in2,
+ opus_val16 *out, int overlap, int channels,
+ const opus_val16 *window, opus_int32 Fs)
+{
+ int i, c;
+ int inc = 48000/Fs;
+ for (c=0;c<channels;c++)
+ {
+ for (i=0;i<overlap;i++)
+ {
+ opus_val16 w = MULT16_16_Q15(window[i*inc], window[i*inc]);
+ out[i*channels+c] = SHR32(MAC16_16(MULT16_16(w,in2[i*channels+c]),
+ Q15ONE-w, in1[i*channels+c]), 15);
+ }
+ }
+}
+
+static int opus_packet_get_mode(const unsigned char *data)
+{
+ int mode;
+ if (data[0]&0x80)
+ {
+ mode = MODE_CELT_ONLY;
+ } else if ((data[0]&0x60) == 0x60)
+ {
+ mode = MODE_HYBRID;
+ } else {
+ mode = MODE_SILK_ONLY;
+ }
+ return mode;
+}
+
+static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
+ opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec)
+{
+ void *silk_dec;
+ CELTDecoder *celt_dec;
+ int i, silk_ret=0, celt_ret=0;
+ ec_dec dec;
+ opus_int32 silk_frame_size;
+ int pcm_silk_size;
+ VARDECL(opus_int16, pcm_silk);
+ int pcm_transition_silk_size;
+ VARDECL(opus_val16, pcm_transition_silk);
+ int pcm_transition_celt_size;
+ VARDECL(opus_val16, pcm_transition_celt);
+ opus_val16 *pcm_transition;
+ int redundant_audio_size;
+ VARDECL(opus_val16, redundant_audio);
+
+ int audiosize;
+ int mode;
+ int transition=0;
+ int start_band;
+ int redundancy=0;
+ int redundancy_bytes = 0;
+ int celt_to_silk=0;
+ int c;
+ int F2_5, F5, F10, F20;
+ const opus_val16 *window;
+ opus_uint32 redundant_rng = 0;
+ ALLOC_STACK;
+
+ silk_dec = (char*)st+st->silk_dec_offset;
+ celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset);
+ F20 = st->Fs/50;
+ F10 = F20>>1;
+ F5 = F10>>1;
+ F2_5 = F5>>1;
+ if (frame_size < F2_5)
+ {
+ RESTORE_STACK;
+ return OPUS_BUFFER_TOO_SMALL;
+ }
+ /* Limit frame_size to avoid excessive stack allocations. */
+ frame_size = IMIN(frame_size, st->Fs/25*3);
+ /* Payloads of 1 (2 including ToC) or 0 trigger the PLC/DTX */
+ if (len<=1)
+ {
+ data = NULL;
+ /* In that case, don't conceal more than what the ToC says */
+ frame_size = IMIN(frame_size, st->frame_size);
+ }
+ if (data != NULL)
+ {
+ audiosize = st->frame_size;
+ mode = st->mode;
+ ec_dec_init(&dec,(unsigned char*)data,len);
+ } else {
+ audiosize = frame_size;
+ mode = st->prev_mode;
+
+ if (mode == 0)
+ {
+ /* If we haven't got any packet yet, all we can do is return zeros */
+ for (i=0;i<audiosize*st->channels;i++)
+ pcm[i] = 0;
+ RESTORE_STACK;
+ return audiosize;
+ }
+
+ /* Avoids trying to run the PLC on sizes other than 2.5 (CELT), 5 (CELT),
+ 10, or 20 (e.g. 12.5 or 30 ms). */
+ if (audiosize > F20)
+ {
+ do {
+ int ret = opus_decode_frame(st, NULL, 0, pcm, IMIN(audiosize, F20), 0);
+ if (ret<0)
+ {
+ RESTORE_STACK;
+ return ret;
+ }
+ pcm += ret*st->channels;
+ audiosize -= ret;
+ } while (audiosize > 0);
+ RESTORE_STACK;
+ return frame_size;
+ } else if (audiosize < F20)
+ {
+ if (audiosize > F10)
+ audiosize = F10;
+ else if (mode != MODE_SILK_ONLY && audiosize > F5 && audiosize < F10)
+ audiosize = F5;
+ }
+ }
+
+ pcm_transition_silk_size = ALLOC_NONE;
+ pcm_transition_celt_size = ALLOC_NONE;
+ if (data!=NULL && st->prev_mode > 0 && (
+ (mode == MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY && !st->prev_redundancy)
+ || (mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) )
+ )
+ {
+ transition = 1;
+ /* Decide where to allocate the stack memory for pcm_transition */
+ if (mode == MODE_CELT_ONLY)
+ pcm_transition_celt_size = F5*st->channels;
+ else
+ pcm_transition_silk_size = F5*st->channels;
+ }
+ ALLOC(pcm_transition_celt, pcm_transition_celt_size, opus_val16);
+ if (transition && mode == MODE_CELT_ONLY)
+ {
+ pcm_transition = pcm_transition_celt;
+ opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0);
+ }
+ if (audiosize > frame_size)
+ {
+ /*fprintf(stderr, "PCM buffer too small: %d vs %d (mode = %d)\n", audiosize, frame_size, mode);*/
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ } else {
+ frame_size = audiosize;
+ }
+
+ /* Don't allocate any memory when in CELT-only mode */
+ pcm_silk_size = (mode != MODE_CELT_ONLY) ? IMAX(F10, frame_size)*st->channels : ALLOC_NONE;
+ ALLOC(pcm_silk, pcm_silk_size, opus_int16);
+
+ /* SILK processing */
+ if (mode != MODE_CELT_ONLY)
+ {
+ int lost_flag, decoded_samples;
+ opus_int16 *pcm_ptr = pcm_silk;
+
+ if (st->prev_mode==MODE_CELT_ONLY)
+ silk_InitDecoder( silk_dec );
+
+ /* The SILK PLC cannot produce frames of less than 10 ms */
+ st->DecControl.payloadSize_ms = IMAX(10, 1000 * audiosize / st->Fs);
+
+ if (data != NULL)
+ {
+ st->DecControl.nChannelsInternal = st->stream_channels;
+ if( mode == MODE_SILK_ONLY ) {
+ if( st->bandwidth == OPUS_BANDWIDTH_NARROWBAND ) {
+ st->DecControl.internalSampleRate = 8000;
+ } else if( st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND ) {
+ st->DecControl.internalSampleRate = 12000;
+ } else if( st->bandwidth == OPUS_BANDWIDTH_WIDEBAND ) {
+ st->DecControl.internalSampleRate = 16000;
+ } else {
+ st->DecControl.internalSampleRate = 16000;
+ silk_assert( 0 );
+ }
+ } else {
+ /* Hybrid mode */
+ st->DecControl.internalSampleRate = 16000;
+ }
+ }
+
+ lost_flag = data == NULL ? 1 : 2 * decode_fec;
+ decoded_samples = 0;
+ do {
+ /* Call SILK decoder */
+ int first_frame = decoded_samples == 0;
+ silk_ret = silk_Decode( silk_dec, &st->DecControl,
+ lost_flag, first_frame, &dec, pcm_ptr, &silk_frame_size );
+ if( silk_ret ) {
+ if (lost_flag) {
+ /* PLC failure should not be fatal */
+ silk_frame_size = frame_size;
+ for (i=0;i<frame_size*st->channels;i++)
+ pcm_ptr[i] = 0;
+ } else {
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ }
+ pcm_ptr += silk_frame_size * st->channels;
+ decoded_samples += silk_frame_size;
+ } while( decoded_samples < frame_size );
+ }
+
+ start_band = 0;
+ if (!decode_fec && mode != MODE_CELT_ONLY && data != NULL
+ && ec_tell(&dec)+17+20*(st->mode == MODE_HYBRID) <= 8*len)
+ {
+ /* Check if we have a redundant 0-8 kHz band */
+ if (mode == MODE_HYBRID)
+ redundancy = ec_dec_bit_logp(&dec, 12);
+ else
+ redundancy = 1;
+ if (redundancy)
+ {
+ celt_to_silk = ec_dec_bit_logp(&dec, 1);
+ /* redundancy_bytes will be at least two, in the non-hybrid
+ case due to the ec_tell() check above */
+ redundancy_bytes = mode==MODE_HYBRID ?
+ (opus_int32)ec_dec_uint(&dec, 256)+2 :
+ len-((ec_tell(&dec)+7)>>3);
+ len -= redundancy_bytes;
+ /* This is a sanity check. It should never happen for a valid
+ packet, so the exact behaviour is not normative. */
+ if (len*8 < ec_tell(&dec))
+ {
+ len = 0;
+ redundancy_bytes = 0;
+ redundancy = 0;
+ }
+ /* Shrink decoder because of raw bits */
+ dec.storage -= redundancy_bytes;
+ }
+ }
+ if (mode != MODE_CELT_ONLY)
+ start_band = 17;
+
+ {
+ int endband=21;
+
+ switch(st->bandwidth)
+ {
+ case OPUS_BANDWIDTH_NARROWBAND:
+ endband = 13;
+ break;
+ case OPUS_BANDWIDTH_MEDIUMBAND:
+ case OPUS_BANDWIDTH_WIDEBAND:
+ endband = 17;
+ break;
+ case OPUS_BANDWIDTH_SUPERWIDEBAND:
+ endband = 19;
+ break;
+ case OPUS_BANDWIDTH_FULLBAND:
+ endband = 21;
+ break;
+ }
+ celt_decoder_ctl(celt_dec, CELT_SET_END_BAND(endband));
+ celt_decoder_ctl(celt_dec, CELT_SET_CHANNELS(st->stream_channels));
+ }
+
+ if (redundancy)
+ {
+ transition = 0;
+ pcm_transition_silk_size=ALLOC_NONE;
+ }
+
+ ALLOC(pcm_transition_silk, pcm_transition_silk_size, opus_val16);
+
+ if (transition && mode != MODE_CELT_ONLY)
+ {
+ pcm_transition = pcm_transition_silk;
+ opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0);
+ }
+
+ /* Only allocation memory for redundancy if/when needed */
+ redundant_audio_size = redundancy ? F5*st->channels : ALLOC_NONE;
+ ALLOC(redundant_audio, redundant_audio_size, opus_val16);
+
+ /* 5 ms redundant frame for CELT->SILK*/
+ if (redundancy && celt_to_silk)
+ {
+ celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
+ celt_decode_with_ec(celt_dec, data+len, redundancy_bytes,
+ redundant_audio, F5, NULL);
+ celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng));
+ }
+
+ /* MUST be after PLC */
+ celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(start_band));
+
+ if (mode != MODE_SILK_ONLY)
+ {
+ int celt_frame_size = IMIN(F20, frame_size);
+ /* Make sure to discard any previous CELT state */
+ if (mode != st->prev_mode && st->prev_mode > 0 && !st->prev_redundancy)
+ celt_decoder_ctl(celt_dec, OPUS_RESET_STATE);
+ /* Decode CELT */
+ celt_ret = celt_decode_with_ec(celt_dec, decode_fec ? NULL : data,
+ len, pcm, celt_frame_size, &dec);
+ } else {
+ unsigned char silence[2] = {0xFF, 0xFF};
+ for (i=0;i<frame_size*st->channels;i++)
+ pcm[i] = 0;
+ /* For hybrid -> SILK transitions, we let the CELT MDCT
+ do a fade-out by decoding a silence frame */
+ if (st->prev_mode == MODE_HYBRID && !(redundancy && celt_to_silk && st->prev_redundancy) )
+ {
+ celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
+ celt_decode_with_ec(celt_dec, silence, 2, pcm, F2_5, NULL);
+ }
+ }
+
+ if (mode != MODE_CELT_ONLY)
+ {
+#ifdef OPUS_FIXED_POINT
+ for (i=0;i<frame_size*st->channels;i++)
+ pcm[i] = SAT16(pcm[i] + pcm_silk[i]);
+#else
+ for (i=0;i<frame_size*st->channels;i++)
+ pcm[i] = pcm[i] + (opus_val16)((1.f/32768.f)*pcm_silk[i]);
+#endif
+ }
+
+ {
+ const CELTMode *celt_mode;
+ celt_decoder_ctl(celt_dec, CELT_GET_MODE(&celt_mode));
+ window = celt_mode->window;
+ }
+
+ /* 5 ms redundant frame for SILK->CELT */
+ if (redundancy && !celt_to_silk)
+ {
+ celt_decoder_ctl(celt_dec, OPUS_RESET_STATE);
+ celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
+
+ celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, redundant_audio, F5, NULL);
+ celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng));
+ smooth_fade(pcm+st->channels*(frame_size-F2_5), redundant_audio+st->channels*F2_5,
+ pcm+st->channels*(frame_size-F2_5), F2_5, st->channels, window, st->Fs);
+ }
+ if (redundancy && celt_to_silk)
+ {
+ for (c=0;c<st->channels;c++)
+ {
+ for (i=0;i<F2_5;i++)
+ pcm[st->channels*i+c] = redundant_audio[st->channels*i+c];
+ }
+ smooth_fade(redundant_audio+st->channels*F2_5, pcm+st->channels*F2_5,
+ pcm+st->channels*F2_5, F2_5, st->channels, window, st->Fs);
+ }
+ if (transition)
+ {
+ if (audiosize >= F5)
+ {
+ for (i=0;i<st->channels*F2_5;i++)
+ pcm[i] = pcm_transition[i];
+ smooth_fade(pcm_transition+st->channels*F2_5, pcm+st->channels*F2_5,
+ pcm+st->channels*F2_5, F2_5,
+ st->channels, window, st->Fs);
+ } else {
+ /* Not enough time to do a clean transition, but we do it anyway
+ This will not preserve amplitude perfectly and may introduce
+ a bit of temporal aliasing, but it shouldn't be too bad and
+ that's pretty much the best we can do. In any case, generating this
+ transition it pretty silly in the first place */
+ smooth_fade(pcm_transition, pcm,
+ pcm, F2_5,
+ st->channels, window, st->Fs);
+ }
+ }
+
+ if(st->decode_gain)
+ {
+ opus_val32 gain;
+ gain = celt_exp2(MULT16_16_P15(QCONST16(6.48814081e-4f, 25), st->decode_gain));
+ for (i=0;i<frame_size*st->channels;i++)
+ {
+ opus_val32 x;
+ x = MULT16_32_P16(pcm[i],gain);
+ pcm[i] = SATURATE(x, 32767);
+ }
+ }
+
+ if (len <= 1)
+ st->rangeFinal = 0;
+ else
+ st->rangeFinal = dec.rng ^ redundant_rng;
+
+ st->prev_mode = mode;
+ st->prev_redundancy = redundancy && !celt_to_silk;
+
+ if (celt_ret>=0)
+ {
+ if (OPUS_CHECK_ARRAY(pcm, audiosize*st->channels))
+ OPUS_PRINT_INT(audiosize);
+ }
+
+ RESTORE_STACK;
+ return celt_ret < 0 ? celt_ret : audiosize;
+
+}
+
+int opus_decode_native(OpusDecoder *st, const unsigned char *data,
+ opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec,
+ int self_delimited, opus_int32 *packet_offset, int soft_clip)
+{
+ int i, nb_samples;
+ int count, offset;
+ unsigned char toc;
+ int packet_frame_size, packet_bandwidth, packet_mode, packet_stream_channels;
+ /* 48 x 2.5 ms = 120 ms */
+ opus_int16 size[48];
+ if (decode_fec<0 || decode_fec>1)
+ return OPUS_BAD_ARG;
+ /* For FEC/PLC, frame_size has to be to have a multiple of 2.5 ms */
+ if ((decode_fec || len==0 || data==NULL) && frame_size%(st->Fs/400)!=0)
+ return OPUS_BAD_ARG;
+ if (len==0 || data==NULL)
+ {
+ int pcm_count=0;
+ do {
+ int ret;
+ ret = opus_decode_frame(st, NULL, 0, pcm+pcm_count*st->channels, frame_size-pcm_count, 0);
+ if (ret<0)
+ return ret;
+ pcm_count += ret;
+ } while (pcm_count < frame_size);
+ celt_assert(pcm_count == frame_size);
+ if (OPUS_CHECK_ARRAY(pcm, pcm_count*st->channels))
+ OPUS_PRINT_INT(pcm_count);
+ st->last_packet_duration = pcm_count;
+ return pcm_count;
+ } else if (len<0)
+ return OPUS_BAD_ARG;
+
+ packet_mode = opus_packet_get_mode(data);
+ packet_bandwidth = opus_packet_get_bandwidth(data);
+ packet_frame_size = opus_packet_get_samples_per_frame(data, st->Fs);
+ packet_stream_channels = opus_packet_get_nb_channels(data);
+
+ count = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL,
+ size, &offset, packet_offset);
+ if (count<0)
+ return count;
+
+ data += offset;
+
+ if (decode_fec)
+ {
+ int duration_copy;
+ int ret;
+ /* If no FEC can be present, run the PLC (recursive call) */
+ if (frame_size < packet_frame_size || packet_mode == MODE_CELT_ONLY || st->mode == MODE_CELT_ONLY)
+ return opus_decode_native(st, NULL, 0, pcm, frame_size, 0, 0, NULL, soft_clip);
+ /* Otherwise, run the PLC on everything except the size for which we might have FEC */
+ duration_copy = st->last_packet_duration;
+ if (frame_size-packet_frame_size!=0)
+ {
+ ret = opus_decode_native(st, NULL, 0, pcm, frame_size-packet_frame_size, 0, 0, NULL, soft_clip);
+ if (ret<0)
+ {
+ st->last_packet_duration = duration_copy;
+ return ret;
+ }
+ celt_assert(ret==frame_size-packet_frame_size);
+ }
+ /* Complete with FEC */
+ st->mode = packet_mode;
+ st->bandwidth = packet_bandwidth;
+ st->frame_size = packet_frame_size;
+ st->stream_channels = packet_stream_channels;
+ ret = opus_decode_frame(st, data, size[0], pcm+st->channels*(frame_size-packet_frame_size),
+ packet_frame_size, 1);
+ if (ret<0)
+ return ret;
+ else {
+ if (OPUS_CHECK_ARRAY(pcm, frame_size*st->channels))
+ OPUS_PRINT_INT(frame_size);
+ st->last_packet_duration = frame_size;
+ return frame_size;
+ }
+ }
+
+ if (count*packet_frame_size > frame_size)
+ return OPUS_BUFFER_TOO_SMALL;
+
+ /* Update the state as the last step to avoid updating it on an invalid packet */
+ st->mode = packet_mode;
+ st->bandwidth = packet_bandwidth;
+ st->frame_size = packet_frame_size;
+ st->stream_channels = packet_stream_channels;
+
+ nb_samples=0;
+ for (i=0;i<count;i++)
+ {
+ int ret;
+ ret = opus_decode_frame(st, data, size[i], pcm+nb_samples*st->channels, frame_size-nb_samples, 0);
+ if (ret<0)
+ return ret;
+ celt_assert(ret==packet_frame_size);
+ data += size[i];
+ nb_samples += ret;
+ }
+ st->last_packet_duration = nb_samples;
+ if (OPUS_CHECK_ARRAY(pcm, nb_samples*st->channels))
+ OPUS_PRINT_INT(nb_samples);
+#ifndef OPUS_FIXED_POINT
+ if (soft_clip)
+ opus_pcm_soft_clip(pcm, nb_samples, st->channels, st->softclip_mem);
+ else
+ st->softclip_mem[0]=st->softclip_mem[1]=0;
+#endif
+ return nb_samples;
+}
+
+#ifdef OPUS_FIXED_POINT
+
+int opus_decode(OpusDecoder *st, const unsigned char *data,
+ opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec)
+{
+ if(frame_size<=0)
+ return OPUS_BAD_ARG;
+ return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0);
+}
+
+#ifndef DISABLE_FLOAT_API
+int opus_decode_float(OpusDecoder *st, const unsigned char *data,
+ opus_int32 len, float *pcm, int frame_size, int decode_fec)
+{
+ VARDECL(opus_int16, out);
+ int ret, i;
+ ALLOC_STACK;
+
+ if(frame_size<=0)
+ {
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ }
+ ALLOC(out, frame_size*st->channels, opus_int16);
+
+ ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 0);
+ if (ret > 0)
+ {
+ for (i=0;i<ret*st->channels;i++)
+ pcm[i] = (1.f/32768.f)*(out[i]);
+ }
+ RESTORE_STACK;
+ return ret;
+}
+#endif
+
+
+#else
+int opus_decode(OpusDecoder *st, const unsigned char *data,
+ opus_int32 len, opus_int16 *pcm, int frame_size, int decode_fec)
+{
+ VARDECL(float, out);
+ int ret, i;
+ ALLOC_STACK;
+
+ if(frame_size<=0)
+ {
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ }
+
+ ALLOC(out, frame_size*st->channels, float);
+
+ ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 1);
+ if (ret > 0)
+ {
+ for (i=0;i<ret*st->channels;i++)
+ pcm[i] = FLOAT2INT16(out[i]);
+ }
+ RESTORE_STACK;
+ return ret;
+}
+
+int opus_decode_float(OpusDecoder *st, const unsigned char *data,
+ opus_int32 len, opus_val16 *pcm, int frame_size, int decode_fec)
+{
+ if(frame_size<=0)
+ return OPUS_BAD_ARG;
+ return opus_decode_native(st, data, len, pcm, frame_size, decode_fec, 0, NULL, 0);
+}
+
+#endif
+
+int opus_decoder_ctl(OpusDecoder *st, int request, ...)
+{
+ int ret = OPUS_OK;
+ va_list ap;
+ void *silk_dec;
+ CELTDecoder *celt_dec;
+
+ silk_dec = (char*)st+st->silk_dec_offset;
+ celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset);
+
+
+ va_start(ap, request);
+
+ switch (request)
+ {
+ case OPUS_GET_BANDWIDTH_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->bandwidth;
+ }
+ break;
+ case OPUS_GET_FINAL_RANGE_REQUEST:
+ {
+ opus_uint32 *value = va_arg(ap, opus_uint32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->rangeFinal;
+ }
+ break;
+ case OPUS_RESET_STATE:
+ {
+ OPUS_CLEAR((char*)&st->OPUS_DECODER_RESET_START,
+ sizeof(OpusDecoder)-
+ ((char*)&st->OPUS_DECODER_RESET_START - (char*)st));
+
+ celt_decoder_ctl(celt_dec, OPUS_RESET_STATE);
+ silk_InitDecoder( silk_dec );
+ st->stream_channels = st->channels;
+ st->frame_size = st->Fs/400;
+ }
+ break;
+ case OPUS_GET_SAMPLE_RATE_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->Fs;
+ }
+ break;
+ case OPUS_GET_PITCH_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ if (st->prev_mode == MODE_CELT_ONLY)
+ celt_decoder_ctl(celt_dec, OPUS_GET_PITCH(value));
+ else
+ *value = st->DecControl.prevPitchLag;
+ }
+ break;
+ case OPUS_GET_GAIN_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->decode_gain;
+ }
+ break;
+ case OPUS_SET_GAIN_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<-32768 || value>32767)
+ {
+ goto bad_arg;
+ }
+ st->decode_gain = value;
+ }
+ break;
+ case OPUS_GET_LAST_PACKET_DURATION_REQUEST:
+ {
+ opus_uint32 *value = va_arg(ap, opus_uint32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->last_packet_duration;
+ }
+ break;
+ default:
+ /*fprintf(stderr, "unknown opus_decoder_ctl() request: %d", request);*/
+ ret = OPUS_UNIMPLEMENTED;
+ break;
+ }
+
+ va_end(ap);
+ return ret;
+bad_arg:
+ va_end(ap);
+ return OPUS_BAD_ARG;
+}
+
+void opus_decoder_destroy(OpusDecoder *st)
+{
+ opus_free(st);
+}
+
+
+int opus_packet_get_bandwidth(const unsigned char *data)
+{
+ int bandwidth;
+ if (data[0]&0x80)
+ {
+ bandwidth = OPUS_BANDWIDTH_MEDIUMBAND + ((data[0]>>5)&0x3);
+ if (bandwidth == OPUS_BANDWIDTH_MEDIUMBAND)
+ bandwidth = OPUS_BANDWIDTH_NARROWBAND;
+ } else if ((data[0]&0x60) == 0x60)
+ {
+ bandwidth = (data[0]&0x10) ? OPUS_BANDWIDTH_FULLBAND :
+ OPUS_BANDWIDTH_SUPERWIDEBAND;
+ } else {
+ bandwidth = OPUS_BANDWIDTH_NARROWBAND + ((data[0]>>5)&0x3);
+ }
+ return bandwidth;
+}
+
+int opus_packet_get_samples_per_frame(const unsigned char *data,
+ opus_int32 Fs)
+{
+ int audiosize;
+ if (data[0]&0x80)
+ {
+ audiosize = ((data[0]>>3)&0x3);
+ audiosize = (Fs<<audiosize)/400;
+ } else if ((data[0]&0x60) == 0x60)
+ {
+ audiosize = (data[0]&0x08) ? Fs/50 : Fs/100;
+ } else {
+ audiosize = ((data[0]>>3)&0x3);
+ if (audiosize == 3)
+ audiosize = Fs*60/1000;
+ else
+ audiosize = (Fs<<audiosize)/100;
+ }
+ return audiosize;
+}
+
+int opus_packet_get_nb_channels(const unsigned char *data)
+{
+ return (data[0]&0x4) ? 2 : 1;
+}
+
+int opus_packet_get_nb_frames(const unsigned char packet[], opus_int32 len)
+{
+ int count;
+ if (len<1)
+ return OPUS_BAD_ARG;
+ count = packet[0]&0x3;
+ if (count==0)
+ return 1;
+ else if (count!=3)
+ return 2;
+ else if (len<2)
+ return OPUS_INVALID_PACKET;
+ else
+ return packet[1]&0x3F;
+}
+
+int opus_packet_get_nb_samples(const unsigned char packet[], opus_int32 len,
+ opus_int32 Fs)
+{
+ int samples;
+ int count = opus_packet_get_nb_frames(packet, len);
+
+ if (count<0)
+ return count;
+
+ samples = count*opus_packet_get_samples_per_frame(packet, Fs);
+ /* Can't have more than 120 ms */
+ if (samples*25 > Fs*3)
+ return OPUS_INVALID_PACKET;
+ else
+ return samples;
+}
+
+int opus_decoder_get_nb_samples(const OpusDecoder *dec,
+ const unsigned char packet[], opus_int32 len)
+{
+ return opus_packet_get_nb_samples(packet, len, dec->Fs);
+}
diff --git a/drivers/opus/opus_defines.h b/drivers/opus/opus_defines.h
new file mode 100644
index 0000000000..9d089d8391
--- /dev/null
+++ b/drivers/opus/opus_defines.h
@@ -0,0 +1,726 @@
+/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited
+ Written by Jean-Marc Valin and Koen Vos */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ * @file opus_defines.h
+ * @brief Opus reference implementation constants
+ */
+
+#ifndef OPUS_DEFINES_H
+#define OPUS_DEFINES_H
+
+#include "opus/opus_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @defgroup opus_errorcodes Error codes
+ * @{
+ */
+/** No error @hideinitializer*/
+#define OPUS_OK 0
+/** One or more invalid/out of range arguments @hideinitializer*/
+#define OPUS_BAD_ARG -1
+/** The mode struct passed is invalid @hideinitializer*/
+#define OPUS_BUFFER_TOO_SMALL -2
+/** An internal error was detected @hideinitializer*/
+#define OPUS_INTERNAL_ERROR -3
+/** The compressed data passed is corrupted @hideinitializer*/
+#define OPUS_INVALID_PACKET -4
+/** Invalid/unsupported request number @hideinitializer*/
+#define OPUS_UNIMPLEMENTED -5
+/** An encoder or decoder structure is invalid or already freed @hideinitializer*/
+#define OPUS_INVALID_STATE -6
+/** Memory allocation has failed @hideinitializer*/
+#define OPUS_ALLOC_FAIL -7
+/**@}*/
+
+/** @cond OPUS_INTERNAL_DOC */
+/**Export control for opus functions */
+
+#ifndef OPUS_EXPORT
+# if defined(WIN32)
+# ifdef OPUS_BUILD
+# define OPUS_EXPORT __declspec(dllexport)
+# else
+# define OPUS_EXPORT
+# endif
+# elif defined(__GNUC__) && defined(OPUS_BUILD)
+# define OPUS_EXPORT __attribute__ ((visibility ("default")))
+# else
+# define OPUS_EXPORT
+# endif
+#endif
+
+# if !defined(OPUS_GNUC_PREREQ)
+# if defined(__GNUC__)&&defined(__GNUC_MINOR__)
+# define OPUS_GNUC_PREREQ(_maj,_min) \
+ ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min))
+# else
+# define OPUS_GNUC_PREREQ(_maj,_min) 0
+# endif
+# endif
+
+#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )
+# if OPUS_GNUC_PREREQ(3,0)
+# define OPUS_RESTRICT __restrict__
+# elif (defined(_MSC_VER) && _MSC_VER >= 1400)
+# define OPUS_RESTRICT __restrict
+# else
+# define OPUS_RESTRICT
+# endif
+#else
+# define OPUS_RESTRICT restrict
+#endif
+
+#if (!defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L) )
+# if OPUS_GNUC_PREREQ(2,7)
+# define OPUS_INLINE __inline__
+# elif (defined(_MSC_VER))
+# define OPUS_INLINE __inline
+# else
+# define OPUS_INLINE
+# endif
+#else
+# define OPUS_INLINE inline
+#endif
+
+/**Warning attributes for opus functions
+ * NONNULL is not used in OPUS_BUILD to avoid the compiler optimizing out
+ * some paranoid null checks. */
+#if defined(__GNUC__) && OPUS_GNUC_PREREQ(3, 4)
+# define OPUS_WARN_UNUSED_RESULT __attribute__ ((__warn_unused_result__))
+#else
+# define OPUS_WARN_UNUSED_RESULT
+#endif
+#if !defined(OPUS_BUILD) && defined(__GNUC__) && OPUS_GNUC_PREREQ(3, 4)
+# define OPUS_ARG_NONNULL(_x) __attribute__ ((__nonnull__(_x)))
+#else
+# define OPUS_ARG_NONNULL(_x)
+#endif
+
+/** These are the actual Encoder CTL ID numbers.
+ * They should not be used directly by applications.
+ * In general, SETs should be even and GETs should be odd.*/
+#define OPUS_SET_APPLICATION_REQUEST 4000
+#define OPUS_GET_APPLICATION_REQUEST 4001
+#define OPUS_SET_BITRATE_REQUEST 4002
+#define OPUS_GET_BITRATE_REQUEST 4003
+#define OPUS_SET_MAX_BANDWIDTH_REQUEST 4004
+#define OPUS_GET_MAX_BANDWIDTH_REQUEST 4005
+#define OPUS_SET_VBR_REQUEST 4006
+#define OPUS_GET_VBR_REQUEST 4007
+#define OPUS_SET_BANDWIDTH_REQUEST 4008
+#define OPUS_GET_BANDWIDTH_REQUEST 4009
+#define OPUS_SET_COMPLEXITY_REQUEST 4010
+#define OPUS_GET_COMPLEXITY_REQUEST 4011
+#define OPUS_SET_INBAND_FEC_REQUEST 4012
+#define OPUS_GET_INBAND_FEC_REQUEST 4013
+#define OPUS_SET_PACKET_LOSS_PERC_REQUEST 4014
+#define OPUS_GET_PACKET_LOSS_PERC_REQUEST 4015
+#define OPUS_SET_DTX_REQUEST 4016
+#define OPUS_GET_DTX_REQUEST 4017
+#define OPUS_SET_VBR_CONSTRAINT_REQUEST 4020
+#define OPUS_GET_VBR_CONSTRAINT_REQUEST 4021
+#define OPUS_SET_FORCE_CHANNELS_REQUEST 4022
+#define OPUS_GET_FORCE_CHANNELS_REQUEST 4023
+#define OPUS_SET_SIGNAL_REQUEST 4024
+#define OPUS_GET_SIGNAL_REQUEST 4025
+#define OPUS_GET_LOOKAHEAD_REQUEST 4027
+/* #define OPUS_RESET_STATE 4028 */
+#define OPUS_GET_SAMPLE_RATE_REQUEST 4029
+#define OPUS_GET_FINAL_RANGE_REQUEST 4031
+#define OPUS_GET_PITCH_REQUEST 4033
+#define OPUS_SET_GAIN_REQUEST 4034
+#define OPUS_GET_GAIN_REQUEST 4045 /* Should have been 4035 */
+#define OPUS_SET_LSB_DEPTH_REQUEST 4036
+#define OPUS_GET_LSB_DEPTH_REQUEST 4037
+#define OPUS_GET_LAST_PACKET_DURATION_REQUEST 4039
+#define OPUS_SET_EXPERT_FRAME_DURATION_REQUEST 4040
+#define OPUS_GET_EXPERT_FRAME_DURATION_REQUEST 4041
+#define OPUS_SET_PREDICTION_DISABLED_REQUEST 4042
+#define OPUS_GET_PREDICTION_DISABLED_REQUEST 4043
+
+/* Don't use 4045, it's already taken by OPUS_GET_GAIN_REQUEST */
+
+/* Macros to trigger compilation errors when the wrong types are provided to a CTL */
+#define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x))
+#define __opus_check_int_ptr(ptr) ((ptr) + ((ptr) - (opus_int32*)(ptr)))
+#define __opus_check_uint_ptr(ptr) ((ptr) + ((ptr) - (opus_uint32*)(ptr)))
+#define __opus_check_val16_ptr(ptr) ((ptr) + ((ptr) - (opus_val16*)(ptr)))
+/** @endcond */
+
+/** @defgroup opus_ctlvalues Pre-defined values for CTL interface
+ * @see opus_genericctls, opus_encoderctls
+ * @{
+ */
+/* Values for the various encoder CTLs */
+#define OPUS_AUTO -1000 /**<Auto/default setting @hideinitializer*/
+#define OPUS_BITRATE_MAX -1 /**<Maximum bitrate @hideinitializer*/
+
+/** Best for most VoIP/videoconference applications where listening quality and intelligibility matter most
+ * @hideinitializer */
+#define OPUS_APPLICATION_VOIP 2048
+/** Best for broadcast/high-fidelity application where the decoded audio should be as close as possible to the input
+ * @hideinitializer */
+#define OPUS_APPLICATION_AUDIO 2049
+/** Only use when lowest-achievable latency is what matters most. Voice-optimized modes cannot be used.
+ * @hideinitializer */
+#define OPUS_APPLICATION_RESTRICTED_LOWDELAY 2051
+
+#define OPUS_SIGNAL_VOICE 3001 /**< Signal being encoded is voice */
+#define OPUS_SIGNAL_MUSIC 3002 /**< Signal being encoded is music */
+#define OPUS_BANDWIDTH_NARROWBAND 1101 /**< 4 kHz bandpass @hideinitializer*/
+#define OPUS_BANDWIDTH_MEDIUMBAND 1102 /**< 6 kHz bandpass @hideinitializer*/
+#define OPUS_BANDWIDTH_WIDEBAND 1103 /**< 8 kHz bandpass @hideinitializer*/
+#define OPUS_BANDWIDTH_SUPERWIDEBAND 1104 /**<12 kHz bandpass @hideinitializer*/
+#define OPUS_BANDWIDTH_FULLBAND 1105 /**<20 kHz bandpass @hideinitializer*/
+
+#define OPUS_FRAMESIZE_ARG 5000 /**< Select frame size from the argument (default) */
+#define OPUS_FRAMESIZE_2_5_MS 5001 /**< Use 2.5 ms frames */
+#define OPUS_FRAMESIZE_5_MS 5002 /**< Use 5 ms frames */
+#define OPUS_FRAMESIZE_10_MS 5003 /**< Use 10 ms frames */
+#define OPUS_FRAMESIZE_20_MS 5004 /**< Use 20 ms frames */
+#define OPUS_FRAMESIZE_40_MS 5005 /**< Use 40 ms frames */
+#define OPUS_FRAMESIZE_60_MS 5006 /**< Use 60 ms frames */
+
+/**@}*/
+
+
+/** @defgroup opus_encoderctls Encoder related CTLs
+ *
+ * These are convenience macros for use with the \c opus_encode_ctl
+ * interface. They are used to generate the appropriate series of
+ * arguments for that call, passing the correct type, size and so
+ * on as expected for each particular request.
+ *
+ * Some usage examples:
+ *
+ * @code
+ * int ret;
+ * ret = opus_encoder_ctl(enc_ctx, OPUS_SET_BANDWIDTH(OPUS_AUTO));
+ * if (ret != OPUS_OK) return ret;
+ *
+ * opus_int32 rate;
+ * opus_encoder_ctl(enc_ctx, OPUS_GET_BANDWIDTH(&rate));
+ *
+ * opus_encoder_ctl(enc_ctx, OPUS_RESET_STATE);
+ * @endcode
+ *
+ * @see opus_genericctls, opus_encoder
+ * @{
+ */
+
+/** Configures the encoder's computational complexity.
+ * The supported range is 0-10 inclusive with 10 representing the highest complexity.
+ * @see OPUS_GET_COMPLEXITY
+ * @param[in] x <tt>opus_int32</tt>: Allowed values: 0-10, inclusive.
+ *
+ * @hideinitializer */
+#define OPUS_SET_COMPLEXITY(x) OPUS_SET_COMPLEXITY_REQUEST, __opus_check_int(x)
+/** Gets the encoder's complexity configuration.
+ * @see OPUS_SET_COMPLEXITY
+ * @param[out] x <tt>opus_int32 *</tt>: Returns a value in the range 0-10,
+ * inclusive.
+ * @hideinitializer */
+#define OPUS_GET_COMPLEXITY(x) OPUS_GET_COMPLEXITY_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the bitrate in the encoder.
+ * Rates from 500 to 512000 bits per second are meaningful, as well as the
+ * special values #OPUS_AUTO and #OPUS_BITRATE_MAX.
+ * The value #OPUS_BITRATE_MAX can be used to cause the codec to use as much
+ * rate as it can, which is useful for controlling the rate by adjusting the
+ * output buffer size.
+ * @see OPUS_GET_BITRATE
+ * @param[in] x <tt>opus_int32</tt>: Bitrate in bits per second. The default
+ * is determined based on the number of
+ * channels and the input sampling rate.
+ * @hideinitializer */
+#define OPUS_SET_BITRATE(x) OPUS_SET_BITRATE_REQUEST, __opus_check_int(x)
+/** Gets the encoder's bitrate configuration.
+ * @see OPUS_SET_BITRATE
+ * @param[out] x <tt>opus_int32 *</tt>: Returns the bitrate in bits per second.
+ * The default is determined based on the
+ * number of channels and the input
+ * sampling rate.
+ * @hideinitializer */
+#define OPUS_GET_BITRATE(x) OPUS_GET_BITRATE_REQUEST, __opus_check_int_ptr(x)
+
+/** Enables or disables variable bitrate (VBR) in the encoder.
+ * The configured bitrate may not be met exactly because frames must
+ * be an integer number of bytes in length.
+ * @warning Only the MDCT mode of Opus can provide hard CBR behavior.
+ * @see OPUS_GET_VBR
+ * @see OPUS_SET_VBR_CONSTRAINT
+ * @param[in] x <tt>opus_int32</tt>: Allowed values:
+ * <dl>
+ * <dt>0</dt><dd>Hard CBR. For LPC/hybrid modes at very low bit-rate, this can
+ * cause noticeable quality degradation.</dd>
+ * <dt>1</dt><dd>VBR (default). The exact type of VBR is controlled by
+ * #OPUS_SET_VBR_CONSTRAINT.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_SET_VBR(x) OPUS_SET_VBR_REQUEST, __opus_check_int(x)
+/** Determine if variable bitrate (VBR) is enabled in the encoder.
+ * @see OPUS_SET_VBR
+ * @see OPUS_GET_VBR_CONSTRAINT
+ * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+ * <dl>
+ * <dt>0</dt><dd>Hard CBR.</dd>
+ * <dt>1</dt><dd>VBR (default). The exact type of VBR may be retrieved via
+ * #OPUS_GET_VBR_CONSTRAINT.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_GET_VBR(x) OPUS_GET_VBR_REQUEST, __opus_check_int_ptr(x)
+
+/** Enables or disables constrained VBR in the encoder.
+ * This setting is ignored when the encoder is in CBR mode.
+ * @warning Only the MDCT mode of Opus currently heeds the constraint.
+ * Speech mode ignores it completely, hybrid mode may fail to obey it
+ * if the LPC layer uses more bitrate than the constraint would have
+ * permitted.
+ * @see OPUS_GET_VBR_CONSTRAINT
+ * @see OPUS_SET_VBR
+ * @param[in] x <tt>opus_int32</tt>: Allowed values:
+ * <dl>
+ * <dt>0</dt><dd>Unconstrained VBR.</dd>
+ * <dt>1</dt><dd>Constrained VBR (default). This creates a maximum of one
+ * frame of buffering delay assuming a transport with a
+ * serialization speed of the nominal bitrate.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_SET_VBR_CONSTRAINT(x) OPUS_SET_VBR_CONSTRAINT_REQUEST, __opus_check_int(x)
+/** Determine if constrained VBR is enabled in the encoder.
+ * @see OPUS_SET_VBR_CONSTRAINT
+ * @see OPUS_GET_VBR
+ * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+ * <dl>
+ * <dt>0</dt><dd>Unconstrained VBR.</dd>
+ * <dt>1</dt><dd>Constrained VBR (default).</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_GET_VBR_CONSTRAINT(x) OPUS_GET_VBR_CONSTRAINT_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures mono/stereo forcing in the encoder.
+ * This can force the encoder to produce packets encoded as either mono or
+ * stereo, regardless of the format of the input audio. This is useful when
+ * the caller knows that the input signal is currently a mono source embedded
+ * in a stereo stream.
+ * @see OPUS_GET_FORCE_CHANNELS
+ * @param[in] x <tt>opus_int32</tt>: Allowed values:
+ * <dl>
+ * <dt>#OPUS_AUTO</dt><dd>Not forced (default)</dd>
+ * <dt>1</dt> <dd>Forced mono</dd>
+ * <dt>2</dt> <dd>Forced stereo</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_SET_FORCE_CHANNELS(x) OPUS_SET_FORCE_CHANNELS_REQUEST, __opus_check_int(x)
+/** Gets the encoder's forced channel configuration.
+ * @see OPUS_SET_FORCE_CHANNELS
+ * @param[out] x <tt>opus_int32 *</tt>:
+ * <dl>
+ * <dt>#OPUS_AUTO</dt><dd>Not forced (default)</dd>
+ * <dt>1</dt> <dd>Forced mono</dd>
+ * <dt>2</dt> <dd>Forced stereo</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_GET_FORCE_CHANNELS(x) OPUS_GET_FORCE_CHANNELS_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the maximum bandpass that the encoder will select automatically.
+ * Applications should normally use this instead of #OPUS_SET_BANDWIDTH
+ * (leaving that set to the default, #OPUS_AUTO). This allows the
+ * application to set an upper bound based on the type of input it is
+ * providing, but still gives the encoder the freedom to reduce the bandpass
+ * when the bitrate becomes too low, for better overall quality.
+ * @see OPUS_GET_MAX_BANDWIDTH
+ * @param[in] x <tt>opus_int32</tt>: Allowed values:
+ * <dl>
+ * <dt>OPUS_BANDWIDTH_NARROWBAND</dt> <dd>4 kHz passband</dd>
+ * <dt>OPUS_BANDWIDTH_MEDIUMBAND</dt> <dd>6 kHz passband</dd>
+ * <dt>OPUS_BANDWIDTH_WIDEBAND</dt> <dd>8 kHz passband</dd>
+ * <dt>OPUS_BANDWIDTH_SUPERWIDEBAND</dt><dd>12 kHz passband</dd>
+ * <dt>OPUS_BANDWIDTH_FULLBAND</dt> <dd>20 kHz passband (default)</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_SET_MAX_BANDWIDTH(x) OPUS_SET_MAX_BANDWIDTH_REQUEST, __opus_check_int(x)
+
+/** Gets the encoder's configured maximum allowed bandpass.
+ * @see OPUS_SET_MAX_BANDWIDTH
+ * @param[out] x <tt>opus_int32 *</tt>: Allowed values:
+ * <dl>
+ * <dt>#OPUS_BANDWIDTH_NARROWBAND</dt> <dd>4 kHz passband</dd>
+ * <dt>#OPUS_BANDWIDTH_MEDIUMBAND</dt> <dd>6 kHz passband</dd>
+ * <dt>#OPUS_BANDWIDTH_WIDEBAND</dt> <dd>8 kHz passband</dd>
+ * <dt>#OPUS_BANDWIDTH_SUPERWIDEBAND</dt><dd>12 kHz passband</dd>
+ * <dt>#OPUS_BANDWIDTH_FULLBAND</dt> <dd>20 kHz passband (default)</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_GET_MAX_BANDWIDTH(x) OPUS_GET_MAX_BANDWIDTH_REQUEST, __opus_check_int_ptr(x)
+
+/** Sets the encoder's bandpass to a specific value.
+ * This prevents the encoder from automatically selecting the bandpass based
+ * on the available bitrate. If an application knows the bandpass of the input
+ * audio it is providing, it should normally use #OPUS_SET_MAX_BANDWIDTH
+ * instead, which still gives the encoder the freedom to reduce the bandpass
+ * when the bitrate becomes too low, for better overall quality.
+ * @see OPUS_GET_BANDWIDTH
+ * @param[in] x <tt>opus_int32</tt>: Allowed values:
+ * <dl>
+ * <dt>#OPUS_AUTO</dt> <dd>(default)</dd>
+ * <dt>#OPUS_BANDWIDTH_NARROWBAND</dt> <dd>4 kHz passband</dd>
+ * <dt>#OPUS_BANDWIDTH_MEDIUMBAND</dt> <dd>6 kHz passband</dd>
+ * <dt>#OPUS_BANDWIDTH_WIDEBAND</dt> <dd>8 kHz passband</dd>
+ * <dt>#OPUS_BANDWIDTH_SUPERWIDEBAND</dt><dd>12 kHz passband</dd>
+ * <dt>#OPUS_BANDWIDTH_FULLBAND</dt> <dd>20 kHz passband</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_SET_BANDWIDTH(x) OPUS_SET_BANDWIDTH_REQUEST, __opus_check_int(x)
+
+/** Configures the type of signal being encoded.
+ * This is a hint which helps the encoder's mode selection.
+ * @see OPUS_GET_SIGNAL
+ * @param[in] x <tt>opus_int32</tt>: Allowed values:
+ * <dl>
+ * <dt>#OPUS_AUTO</dt> <dd>(default)</dd>
+ * <dt>#OPUS_SIGNAL_VOICE</dt><dd>Bias thresholds towards choosing LPC or Hybrid modes.</dd>
+ * <dt>#OPUS_SIGNAL_MUSIC</dt><dd>Bias thresholds towards choosing MDCT modes.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_SET_SIGNAL(x) OPUS_SET_SIGNAL_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured signal type.
+ * @see OPUS_SET_SIGNAL
+ * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+ * <dl>
+ * <dt>#OPUS_AUTO</dt> <dd>(default)</dd>
+ * <dt>#OPUS_SIGNAL_VOICE</dt><dd>Bias thresholds towards choosing LPC or Hybrid modes.</dd>
+ * <dt>#OPUS_SIGNAL_MUSIC</dt><dd>Bias thresholds towards choosing MDCT modes.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_GET_SIGNAL(x) OPUS_GET_SIGNAL_REQUEST, __opus_check_int_ptr(x)
+
+
+/** Configures the encoder's intended application.
+ * The initial value is a mandatory argument to the encoder_create function.
+ * @see OPUS_GET_APPLICATION
+ * @param[in] x <tt>opus_int32</tt>: Returns one of the following values:
+ * <dl>
+ * <dt>#OPUS_APPLICATION_VOIP</dt>
+ * <dd>Process signal for improved speech intelligibility.</dd>
+ * <dt>#OPUS_APPLICATION_AUDIO</dt>
+ * <dd>Favor faithfulness to the original input.</dd>
+ * <dt>#OPUS_APPLICATION_RESTRICTED_LOWDELAY</dt>
+ * <dd>Configure the minimum possible coding delay by disabling certain modes
+ * of operation.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_SET_APPLICATION(x) OPUS_SET_APPLICATION_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured application.
+ * @see OPUS_SET_APPLICATION
+ * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+ * <dl>
+ * <dt>#OPUS_APPLICATION_VOIP</dt>
+ * <dd>Process signal for improved speech intelligibility.</dd>
+ * <dt>#OPUS_APPLICATION_AUDIO</dt>
+ * <dd>Favor faithfulness to the original input.</dd>
+ * <dt>#OPUS_APPLICATION_RESTRICTED_LOWDELAY</dt>
+ * <dd>Configure the minimum possible coding delay by disabling certain modes
+ * of operation.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_GET_APPLICATION(x) OPUS_GET_APPLICATION_REQUEST, __opus_check_int_ptr(x)
+
+/** Gets the sampling rate the encoder or decoder was initialized with.
+ * This simply returns the <code>Fs</code> value passed to opus_encoder_init()
+ * or opus_decoder_init().
+ * @param[out] x <tt>opus_int32 *</tt>: Sampling rate of encoder or decoder.
+ * @hideinitializer
+ */
+#define OPUS_GET_SAMPLE_RATE(x) OPUS_GET_SAMPLE_RATE_REQUEST, __opus_check_int_ptr(x)
+
+/** Gets the total samples of delay added by the entire codec.
+ * This can be queried by the encoder and then the provided number of samples can be
+ * skipped on from the start of the decoder's output to provide time aligned input
+ * and output. From the perspective of a decoding application the real data begins this many
+ * samples late.
+ *
+ * The decoder contribution to this delay is identical for all decoders, but the
+ * encoder portion of the delay may vary from implementation to implementation,
+ * version to version, or even depend on the encoder's initial configuration.
+ * Applications needing delay compensation should call this CTL rather than
+ * hard-coding a value.
+ * @param[out] x <tt>opus_int32 *</tt>: Number of lookahead samples
+ * @hideinitializer */
+#define OPUS_GET_LOOKAHEAD(x) OPUS_GET_LOOKAHEAD_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the encoder's use of inband forward error correction (FEC).
+ * @note This is only applicable to the LPC layer
+ * @see OPUS_GET_INBAND_FEC
+ * @param[in] x <tt>opus_int32</tt>: Allowed values:
+ * <dl>
+ * <dt>0</dt><dd>Disable inband FEC (default).</dd>
+ * <dt>1</dt><dd>Enable inband FEC.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_SET_INBAND_FEC(x) OPUS_SET_INBAND_FEC_REQUEST, __opus_check_int(x)
+/** Gets encoder's configured use of inband forward error correction.
+ * @see OPUS_SET_INBAND_FEC
+ * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+ * <dl>
+ * <dt>0</dt><dd>Inband FEC disabled (default).</dd>
+ * <dt>1</dt><dd>Inband FEC enabled.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_GET_INBAND_FEC(x) OPUS_GET_INBAND_FEC_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the encoder's expected packet loss percentage.
+ * Higher values with trigger progressively more loss resistant behavior in the encoder
+ * at the expense of quality at a given bitrate in the lossless case, but greater quality
+ * under loss.
+ * @see OPUS_GET_PACKET_LOSS_PERC
+ * @param[in] x <tt>opus_int32</tt>: Loss percentage in the range 0-100, inclusive (default: 0).
+ * @hideinitializer */
+#define OPUS_SET_PACKET_LOSS_PERC(x) OPUS_SET_PACKET_LOSS_PERC_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured packet loss percentage.
+ * @see OPUS_SET_PACKET_LOSS_PERC
+ * @param[out] x <tt>opus_int32 *</tt>: Returns the configured loss percentage
+ * in the range 0-100, inclusive (default: 0).
+ * @hideinitializer */
+#define OPUS_GET_PACKET_LOSS_PERC(x) OPUS_GET_PACKET_LOSS_PERC_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the encoder's use of discontinuous transmission (DTX).
+ * @note This is only applicable to the LPC layer
+ * @see OPUS_GET_DTX
+ * @param[in] x <tt>opus_int32</tt>: Allowed values:
+ * <dl>
+ * <dt>0</dt><dd>Disable DTX (default).</dd>
+ * <dt>1</dt><dd>Enabled DTX.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_SET_DTX(x) OPUS_SET_DTX_REQUEST, __opus_check_int(x)
+/** Gets encoder's configured use of discontinuous transmission.
+ * @see OPUS_SET_DTX
+ * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+ * <dl>
+ * <dt>0</dt><dd>DTX disabled (default).</dd>
+ * <dt>1</dt><dd>DTX enabled.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_GET_DTX(x) OPUS_GET_DTX_REQUEST, __opus_check_int_ptr(x)
+/** Configures the depth of signal being encoded.
+ * This is a hint which helps the encoder identify silence and near-silence.
+ * @see OPUS_GET_LSB_DEPTH
+ * @param[in] x <tt>opus_int32</tt>: Input precision in bits, between 8 and 24
+ * (default: 24).
+ * @hideinitializer */
+#define OPUS_SET_LSB_DEPTH(x) OPUS_SET_LSB_DEPTH_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured signal depth.
+ * @see OPUS_SET_LSB_DEPTH
+ * @param[out] x <tt>opus_int32 *</tt>: Input precision in bits, between 8 and
+ * 24 (default: 24).
+ * @hideinitializer */
+#define OPUS_GET_LSB_DEPTH(x) OPUS_GET_LSB_DEPTH_REQUEST, __opus_check_int_ptr(x)
+
+/** Gets the duration (in samples) of the last packet successfully decoded or concealed.
+ * @param[out] x <tt>opus_int32 *</tt>: Number of samples (at current sampling rate).
+ * @hideinitializer */
+#define OPUS_GET_LAST_PACKET_DURATION(x) OPUS_GET_LAST_PACKET_DURATION_REQUEST, __opus_check_int_ptr(x)
+
+/** Configures the encoder's use of variable duration frames.
+ * When variable duration is enabled, the encoder is free to use a shorter frame
+ * size than the one requested in the opus_encode*() call.
+ * It is then the user's responsibility
+ * to verify how much audio was encoded by checking the ToC byte of the encoded
+ * packet. The part of the audio that was not encoded needs to be resent to the
+ * encoder for the next call. Do not use this option unless you <b>really</b>
+ * know what you are doing.
+ * @see OPUS_GET_EXPERT_VARIABLE_DURATION
+ * @param[in] x <tt>opus_int32</tt>: Allowed values:
+ * <dl>
+ * <dt>OPUS_FRAMESIZE_ARG</dt><dd>Select frame size from the argument (default).</dd>
+ * <dt>OPUS_FRAMESIZE_2_5_MS</dt><dd>Use 2.5 ms frames.</dd>
+ * <dt>OPUS_FRAMESIZE_5_MS</dt><dd>Use 2.5 ms frames.</dd>
+ * <dt>OPUS_FRAMESIZE_10_MS</dt><dd>Use 10 ms frames.</dd>
+ * <dt>OPUS_FRAMESIZE_20_MS</dt><dd>Use 20 ms frames.</dd>
+ * <dt>OPUS_FRAMESIZE_40_MS</dt><dd>Use 40 ms frames.</dd>
+ * <dt>OPUS_FRAMESIZE_60_MS</dt><dd>Use 60 ms frames.</dd>
+ * <dt>OPUS_FRAMESIZE_VARIABLE</dt><dd>Optimize the frame size dynamically.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_SET_EXPERT_FRAME_DURATION(x) OPUS_SET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured use of variable duration frames.
+ * @see OPUS_SET_EXPERT_VARIABLE_DURATION
+ * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+ * <dl>
+ * <dt>OPUS_FRAMESIZE_ARG</dt><dd>Select frame size from the argument (default).</dd>
+ * <dt>OPUS_FRAMESIZE_2_5_MS</dt><dd>Use 2.5 ms frames.</dd>
+ * <dt>OPUS_FRAMESIZE_5_MS</dt><dd>Use 2.5 ms frames.</dd>
+ * <dt>OPUS_FRAMESIZE_10_MS</dt><dd>Use 10 ms frames.</dd>
+ * <dt>OPUS_FRAMESIZE_20_MS</dt><dd>Use 20 ms frames.</dd>
+ * <dt>OPUS_FRAMESIZE_40_MS</dt><dd>Use 40 ms frames.</dd>
+ * <dt>OPUS_FRAMESIZE_60_MS</dt><dd>Use 60 ms frames.</dd>
+ * <dt>OPUS_FRAMESIZE_VARIABLE</dt><dd>Optimize the frame size dynamically.</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_GET_EXPERT_FRAME_DURATION(x) OPUS_GET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int_ptr(x)
+
+/** If set to 1, disables almost all use of prediction, making frames almost
+ completely independent. This reduces quality. (default : 0)
+ * @hideinitializer */
+#define OPUS_SET_PREDICTION_DISABLED(x) OPUS_SET_PREDICTION_DISABLED_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured prediction status.
+ * @hideinitializer */
+#define OPUS_GET_PREDICTION_DISABLED(x) OPUS_GET_PREDICTION_DISABLED_REQUEST, __opus_check_int_ptr(x)
+
+/**@}*/
+
+/** @defgroup opus_genericctls Generic CTLs
+ *
+ * These macros are used with the \c opus_decoder_ctl and
+ * \c opus_encoder_ctl calls to generate a particular
+ * request.
+ *
+ * When called on an \c OpusDecoder they apply to that
+ * particular decoder instance. When called on an
+ * \c OpusEncoder they apply to the corresponding setting
+ * on that encoder instance, if present.
+ *
+ * Some usage examples:
+ *
+ * @code
+ * int ret;
+ * opus_int32 pitch;
+ * ret = opus_decoder_ctl(dec_ctx, OPUS_GET_PITCH(&pitch));
+ * if (ret == OPUS_OK) return ret;
+ *
+ * opus_encoder_ctl(enc_ctx, OPUS_RESET_STATE);
+ * opus_decoder_ctl(dec_ctx, OPUS_RESET_STATE);
+ *
+ * opus_int32 enc_bw, dec_bw;
+ * opus_encoder_ctl(enc_ctx, OPUS_GET_BANDWIDTH(&enc_bw));
+ * opus_decoder_ctl(dec_ctx, OPUS_GET_BANDWIDTH(&dec_bw));
+ * if (enc_bw != dec_bw) {
+ * printf("packet bandwidth mismatch!\n");
+ * }
+ * @endcode
+ *
+ * @see opus_encoder, opus_decoder_ctl, opus_encoder_ctl, opus_decoderctls, opus_encoderctls
+ * @{
+ */
+
+/** Resets the codec state to be equivalent to a freshly initialized state.
+ * This should be called when switching streams in order to prevent
+ * the back to back decoding from giving different results from
+ * one at a time decoding.
+ * @hideinitializer */
+#define OPUS_RESET_STATE 4028
+
+/** Gets the final state of the codec's entropy coder.
+ * This is used for testing purposes,
+ * The encoder and decoder state should be identical after coding a payload
+ * (assuming no data corruption or software bugs)
+ *
+ * @param[out] x <tt>opus_uint32 *</tt>: Entropy coder state
+ *
+ * @hideinitializer */
+#define OPUS_GET_FINAL_RANGE(x) OPUS_GET_FINAL_RANGE_REQUEST, __opus_check_uint_ptr(x)
+
+/** Gets the pitch of the last decoded frame, if available.
+ * This can be used for any post-processing algorithm requiring the use of pitch,
+ * e.g. time stretching/shortening. If the last frame was not voiced, or if the
+ * pitch was not coded in the frame, then zero is returned.
+ *
+ * This CTL is only implemented for decoder instances.
+ *
+ * @param[out] x <tt>opus_int32 *</tt>: pitch period at 48 kHz (or 0 if not available)
+ *
+ * @hideinitializer */
+#define OPUS_GET_PITCH(x) OPUS_GET_PITCH_REQUEST, __opus_check_int_ptr(x)
+
+/** Gets the encoder's configured bandpass or the decoder's last bandpass.
+ * @see OPUS_SET_BANDWIDTH
+ * @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
+ * <dl>
+ * <dt>#OPUS_AUTO</dt> <dd>(default)</dd>
+ * <dt>#OPUS_BANDWIDTH_NARROWBAND</dt> <dd>4 kHz passband</dd>
+ * <dt>#OPUS_BANDWIDTH_MEDIUMBAND</dt> <dd>6 kHz passband</dd>
+ * <dt>#OPUS_BANDWIDTH_WIDEBAND</dt> <dd>8 kHz passband</dd>
+ * <dt>#OPUS_BANDWIDTH_SUPERWIDEBAND</dt><dd>12 kHz passband</dd>
+ * <dt>#OPUS_BANDWIDTH_FULLBAND</dt> <dd>20 kHz passband</dd>
+ * </dl>
+ * @hideinitializer */
+#define OPUS_GET_BANDWIDTH(x) OPUS_GET_BANDWIDTH_REQUEST, __opus_check_int_ptr(x)
+
+/**@}*/
+
+/** @defgroup opus_decoderctls Decoder related CTLs
+ * @see opus_genericctls, opus_encoderctls, opus_decoder
+ * @{
+ */
+
+/** Configures decoder gain adjustment.
+ * Scales the decoded output by a factor specified in Q8 dB units.
+ * This has a maximum range of -32768 to 32767 inclusive, and returns
+ * OPUS_BAD_ARG otherwise. The default is zero indicating no adjustment.
+ * This setting survives decoder reset.
+ *
+ * gain = pow(10, x/(20.0*256))
+ *
+ * @param[in] x <tt>opus_int32</tt>: Amount to scale PCM signal by in Q8 dB units.
+ * @hideinitializer */
+#define OPUS_SET_GAIN(x) OPUS_SET_GAIN_REQUEST, __opus_check_int(x)
+/** Gets the decoder's configured gain adjustment. @see OPUS_SET_GAIN
+ *
+ * @param[out] x <tt>opus_int32 *</tt>: Amount to scale PCM signal by in Q8 dB units.
+ * @hideinitializer */
+#define OPUS_GET_GAIN(x) OPUS_GET_GAIN_REQUEST, __opus_check_int_ptr(x)
+
+/**@}*/
+
+/** @defgroup opus_libinfo Opus library information functions
+ * @{
+ */
+
+/** Converts an opus error code into a human readable string.
+ *
+ * @param[in] error <tt>int</tt>: Error number
+ * @returns Error string
+ */
+OPUS_EXPORT const char *opus_strerror(int error);
+
+/** Gets the libopus version string.
+ *
+ * @returns Version string
+ */
+OPUS_EXPORT const char *opus_get_version_string(void);
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* OPUS_DEFINES_H */
diff --git a/drivers/opus/opus_demo.c b/drivers/opus/opus_demo.c
new file mode 100644
index 0000000000..a0c5a5f862
--- /dev/null
+++ b/drivers/opus/opus_demo.c
@@ -0,0 +1,885 @@
+/* Copyright (c) 2007-2008 CSIRO
+ Copyright (c) 2007-2009 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+#include "opus/opus.h"
+#include "opus/silk/debug.h"
+#include "opus/opus_types.h"
+#include "opus/opus_private.h"
+#include "opus/opus_multistream.h"
+
+#define MAX_PACKET 1500
+
+void print_usage( char* argv[] )
+{
+ fprintf(stderr, "Usage: %s [-e] <application> <sampling rate (Hz)> <channels (1/2)> "
+ "<bits per second> [options] <input> <output>\n", argv[0]);
+ fprintf(stderr, " %s -d <sampling rate (Hz)> <channels (1/2)> "
+ "[options] <input> <output>\n\n", argv[0]);
+ fprintf(stderr, "mode: voip | audio | restricted-lowdelay\n" );
+ fprintf(stderr, "options:\n" );
+ fprintf(stderr, "-e : only runs the encoder (output the bit-stream)\n" );
+ fprintf(stderr, "-d : only runs the decoder (reads the bit-stream as input)\n" );
+ fprintf(stderr, "-cbr : enable constant bitrate; default: variable bitrate\n" );
+ fprintf(stderr, "-cvbr : enable constrained variable bitrate; default: unconstrained\n" );
+ fprintf(stderr, "-variable-duration : enable frames of variable duration (experts only); default: disabled\n" );
+ fprintf(stderr, "-bandwidth <NB|MB|WB|SWB|FB> : audio bandwidth (from narrowband to fullband); default: sampling rate\n" );
+ fprintf(stderr, "-framesize <2.5|5|10|20|40|60> : frame size in ms; default: 20 \n" );
+ fprintf(stderr, "-max_payload <bytes> : maximum payload size in bytes, default: 1024\n" );
+ fprintf(stderr, "-complexity <comp> : complexity, 0 (lowest) ... 10 (highest); default: 10\n" );
+ fprintf(stderr, "-inbandfec : enable SILK inband FEC\n" );
+ fprintf(stderr, "-forcemono : force mono encoding, even for stereo input\n" );
+ fprintf(stderr, "-dtx : enable SILK DTX\n" );
+ fprintf(stderr, "-loss <perc> : simulate packet loss, in percent (0-100); default: 0\n" );
+}
+
+static void int_to_char(opus_uint32 i, unsigned char ch[4])
+{
+ ch[0] = i>>24;
+ ch[1] = (i>>16)&0xFF;
+ ch[2] = (i>>8)&0xFF;
+ ch[3] = i&0xFF;
+}
+
+static opus_uint32 char_to_int(unsigned char ch[4])
+{
+ return ((opus_uint32)ch[0]<<24) | ((opus_uint32)ch[1]<<16)
+ | ((opus_uint32)ch[2]<< 8) | (opus_uint32)ch[3];
+}
+
+static void check_encoder_option(int decode_only, const char *opt)
+{
+ if (decode_only)
+ {
+ fprintf(stderr, "option %s is only for encoding\n", opt);
+ exit(EXIT_FAILURE);
+ }
+}
+
+static const int silk8_test[][4] = {
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960*3, 1},
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960*2, 1},
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960, 1},
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 480, 1},
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960*3, 2},
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960*2, 2},
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960, 2},
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 480, 2}
+};
+
+static const int silk12_test[][4] = {
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960*3, 1},
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960*2, 1},
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960, 1},
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 480, 1},
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960*3, 2},
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960*2, 2},
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960, 2},
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 480, 2}
+};
+
+static const int silk16_test[][4] = {
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960*3, 1},
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960*2, 1},
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960, 1},
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 480, 1},
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960*3, 2},
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960*2, 2},
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960, 2},
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 480, 2}
+};
+
+static const int hybrid24_test[][4] = {
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 960, 1},
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 480, 1},
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 960, 2},
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 480, 2}
+};
+
+static const int hybrid48_test[][4] = {
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_FULLBAND, 960, 1},
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_FULLBAND, 480, 1},
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_FULLBAND, 960, 2},
+ {MODE_SILK_ONLY, OPUS_BANDWIDTH_FULLBAND, 480, 2}
+};
+
+static const int celt_test[][4] = {
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 960, 1},
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 960, 1},
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960, 1},
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960, 1},
+
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 480, 1},
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 480, 1},
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 480, 1},
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 480, 1},
+
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 240, 1},
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 240, 1},
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 240, 1},
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 240, 1},
+
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 120, 1},
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 120, 1},
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 120, 1},
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 120, 1},
+
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 960, 2},
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 960, 2},
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960, 2},
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960, 2},
+
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 480, 2},
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 480, 2},
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 480, 2},
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 480, 2},
+
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 240, 2},
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 240, 2},
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 240, 2},
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 240, 2},
+
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 120, 2},
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 120, 2},
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 120, 2},
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 120, 2},
+
+};
+
+static const int celt_hq_test[][4] = {
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 960, 2},
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 480, 2},
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 240, 2},
+ {MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 120, 2},
+};
+
+#if 0 /* This is a hack that replaces the normal encoder/decoder with the multistream version */
+#define OpusEncoder OpusMSEncoder
+#define OpusDecoder OpusMSDecoder
+#define opus_encode opus_multistream_encode
+#define opus_decode opus_multistream_decode
+#define opus_encoder_ctl opus_multistream_encoder_ctl
+#define opus_decoder_ctl opus_multistream_decoder_ctl
+#define opus_encoder_create ms_opus_encoder_create
+#define opus_decoder_create ms_opus_decoder_create
+#define opus_encoder_destroy opus_multistream_encoder_destroy
+#define opus_decoder_destroy opus_multistream_decoder_destroy
+
+static OpusEncoder *ms_opus_encoder_create(opus_int32 Fs, int channels, int application, int *error)
+{
+ int streams, coupled_streams;
+ unsigned char mapping[256];
+ return (OpusEncoder *)opus_multistream_surround_encoder_create(Fs, channels, 1, &streams, &coupled_streams, mapping, application, error);
+}
+static OpusDecoder *ms_opus_decoder_create(opus_int32 Fs, int channels, int *error)
+{
+ int streams;
+ int coupled_streams;
+ unsigned char mapping[256]={0,1};
+ streams = 1;
+ coupled_streams = channels==2;
+ return (OpusDecoder *)opus_multistream_decoder_create(Fs, channels, streams, coupled_streams, mapping, error);
+}
+#endif
+
+int main(int argc, char *argv[])
+{
+ int err;
+ char *inFile, *outFile;
+ FILE *fin, *fout;
+ OpusEncoder *enc=NULL;
+ OpusDecoder *dec=NULL;
+ int args;
+ int len[2];
+ int frame_size, channels;
+ opus_int32 bitrate_bps=0;
+ unsigned char *data[2];
+ unsigned char *fbytes;
+ opus_int32 sampling_rate;
+ int use_vbr;
+ int max_payload_bytes;
+ int complexity;
+ int use_inbandfec;
+ int use_dtx;
+ int forcechannels;
+ int cvbr = 0;
+ int packet_loss_perc;
+ opus_int32 count=0, count_act=0;
+ int k;
+ opus_int32 skip=0;
+ int stop=0;
+ short *in, *out;
+ int application=OPUS_APPLICATION_AUDIO;
+ double bits=0.0, bits_max=0.0, bits_act=0.0, bits2=0.0, nrg;
+ double tot_samples=0;
+ opus_uint64 tot_in, tot_out;
+ int bandwidth=-1;
+ const char *bandwidth_string;
+ int lost = 0, lost_prev = 1;
+ int toggle = 0;
+ opus_uint32 enc_final_range[2];
+ opus_uint32 dec_final_range;
+ int encode_only=0, decode_only=0;
+ int max_frame_size = 960*6;
+ int curr_read=0;
+ int sweep_bps = 0;
+ int random_framesize=0, newsize=0, delayed_celt=0;
+ int sweep_max=0, sweep_min=0;
+ int random_fec=0;
+ const int (*mode_list)[4]=NULL;
+ int nb_modes_in_list=0;
+ int curr_mode=0;
+ int curr_mode_count=0;
+ int mode_switch_time = 48000;
+ int nb_encoded=0;
+ int remaining=0;
+ int variable_duration=OPUS_FRAMESIZE_ARG;
+ int delayed_decision=0;
+
+ if (argc < 5 )
+ {
+ print_usage( argv );
+ return EXIT_FAILURE;
+ }
+
+ tot_in=tot_out=0;
+ fprintf(stderr, "%s\n", opus_get_version_string());
+
+ args = 1;
+ if (strcmp(argv[args], "-e")==0)
+ {
+ encode_only = 1;
+ args++;
+ } else if (strcmp(argv[args], "-d")==0)
+ {
+ decode_only = 1;
+ args++;
+ }
+ if (!decode_only && argc < 7 )
+ {
+ print_usage( argv );
+ return EXIT_FAILURE;
+ }
+
+ if (!decode_only)
+ {
+ if (strcmp(argv[args], "voip")==0)
+ application = OPUS_APPLICATION_VOIP;
+ else if (strcmp(argv[args], "restricted-lowdelay")==0)
+ application = OPUS_APPLICATION_RESTRICTED_LOWDELAY;
+ else if (strcmp(argv[args], "audio")!=0) {
+ fprintf(stderr, "unknown application: %s\n", argv[args]);
+ print_usage(argv);
+ return EXIT_FAILURE;
+ }
+ args++;
+ }
+ sampling_rate = (opus_int32)atol(argv[args]);
+ args++;
+
+ if (sampling_rate != 8000 && sampling_rate != 12000
+ && sampling_rate != 16000 && sampling_rate != 24000
+ && sampling_rate != 48000)
+ {
+ fprintf(stderr, "Supported sampling rates are 8000, 12000, "
+ "16000, 24000 and 48000.\n");
+ return EXIT_FAILURE;
+ }
+ frame_size = sampling_rate/50;
+
+ channels = atoi(argv[args]);
+ args++;
+
+ if (channels < 1 || channels > 2)
+ {
+ fprintf(stderr, "Opus_demo supports only 1 or 2 channels.\n");
+ return EXIT_FAILURE;
+ }
+
+ if (!decode_only)
+ {
+ bitrate_bps = (opus_int32)atol(argv[args]);
+ args++;
+ }
+
+ /* defaults: */
+ use_vbr = 1;
+ bandwidth = OPUS_AUTO;
+ max_payload_bytes = MAX_PACKET;
+ complexity = 10;
+ use_inbandfec = 0;
+ forcechannels = OPUS_AUTO;
+ use_dtx = 0;
+ packet_loss_perc = 0;
+ max_frame_size = 2*48000;
+ curr_read=0;
+
+ while( args < argc - 2 ) {
+ /* process command line options */
+ if( strcmp( argv[ args ], "-cbr" ) == 0 ) {
+ check_encoder_option(decode_only, "-cbr");
+ use_vbr = 0;
+ args++;
+ } else if( strcmp( argv[ args ], "-bandwidth" ) == 0 ) {
+ check_encoder_option(decode_only, "-bandwidth");
+ if (strcmp(argv[ args + 1 ], "NB")==0)
+ bandwidth = OPUS_BANDWIDTH_NARROWBAND;
+ else if (strcmp(argv[ args + 1 ], "MB")==0)
+ bandwidth = OPUS_BANDWIDTH_MEDIUMBAND;
+ else if (strcmp(argv[ args + 1 ], "WB")==0)
+ bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+ else if (strcmp(argv[ args + 1 ], "SWB")==0)
+ bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND;
+ else if (strcmp(argv[ args + 1 ], "FB")==0)
+ bandwidth = OPUS_BANDWIDTH_FULLBAND;
+ else {
+ fprintf(stderr, "Unknown bandwidth %s. "
+ "Supported are NB, MB, WB, SWB, FB.\n",
+ argv[ args + 1 ]);
+ return EXIT_FAILURE;
+ }
+ args += 2;
+ } else if( strcmp( argv[ args ], "-framesize" ) == 0 ) {
+ check_encoder_option(decode_only, "-framesize");
+ if (strcmp(argv[ args + 1 ], "2.5")==0)
+ frame_size = sampling_rate/400;
+ else if (strcmp(argv[ args + 1 ], "5")==0)
+ frame_size = sampling_rate/200;
+ else if (strcmp(argv[ args + 1 ], "10")==0)
+ frame_size = sampling_rate/100;
+ else if (strcmp(argv[ args + 1 ], "20")==0)
+ frame_size = sampling_rate/50;
+ else if (strcmp(argv[ args + 1 ], "40")==0)
+ frame_size = sampling_rate/25;
+ else if (strcmp(argv[ args + 1 ], "60")==0)
+ frame_size = 3*sampling_rate/50;
+ else {
+ fprintf(stderr, "Unsupported frame size: %s ms. "
+ "Supported are 2.5, 5, 10, 20, 40, 60.\n",
+ argv[ args + 1 ]);
+ return EXIT_FAILURE;
+ }
+ args += 2;
+ } else if( strcmp( argv[ args ], "-max_payload" ) == 0 ) {
+ check_encoder_option(decode_only, "-max_payload");
+ max_payload_bytes = atoi( argv[ args + 1 ] );
+ args += 2;
+ } else if( strcmp( argv[ args ], "-complexity" ) == 0 ) {
+ check_encoder_option(decode_only, "-complexity");
+ complexity = atoi( argv[ args + 1 ] );
+ args += 2;
+ } else if( strcmp( argv[ args ], "-inbandfec" ) == 0 ) {
+ use_inbandfec = 1;
+ args++;
+ } else if( strcmp( argv[ args ], "-forcemono" ) == 0 ) {
+ check_encoder_option(decode_only, "-forcemono");
+ forcechannels = 1;
+ args++;
+ } else if( strcmp( argv[ args ], "-cvbr" ) == 0 ) {
+ check_encoder_option(decode_only, "-cvbr");
+ cvbr = 1;
+ args++;
+ } else if( strcmp( argv[ args ], "-variable-duration" ) == 0 ) {
+ check_encoder_option(decode_only, "-variable-duration");
+ variable_duration = OPUS_FRAMESIZE_VARIABLE;
+ args++;
+ } else if( strcmp( argv[ args ], "-delayed-decision" ) == 0 ) {
+ check_encoder_option(decode_only, "-delayed-decision");
+ delayed_decision = 1;
+ args++;
+ } else if( strcmp( argv[ args ], "-dtx") == 0 ) {
+ check_encoder_option(decode_only, "-dtx");
+ use_dtx = 1;
+ args++;
+ } else if( strcmp( argv[ args ], "-loss" ) == 0 ) {
+ packet_loss_perc = atoi( argv[ args + 1 ] );
+ args += 2;
+ } else if( strcmp( argv[ args ], "-sweep" ) == 0 ) {
+ check_encoder_option(decode_only, "-sweep");
+ sweep_bps = atoi( argv[ args + 1 ] );
+ args += 2;
+ } else if( strcmp( argv[ args ], "-random_framesize" ) == 0 ) {
+ check_encoder_option(decode_only, "-random_framesize");
+ random_framesize = 1;
+ args++;
+ } else if( strcmp( argv[ args ], "-sweep_max" ) == 0 ) {
+ check_encoder_option(decode_only, "-sweep_max");
+ sweep_max = atoi( argv[ args + 1 ] );
+ args += 2;
+ } else if( strcmp( argv[ args ], "-random_fec" ) == 0 ) {
+ check_encoder_option(decode_only, "-random_fec");
+ random_fec = 1;
+ args++;
+ } else if( strcmp( argv[ args ], "-silk8k_test" ) == 0 ) {
+ check_encoder_option(decode_only, "-silk8k_test");
+ mode_list = silk8_test;
+ nb_modes_in_list = 8;
+ args++;
+ } else if( strcmp( argv[ args ], "-silk12k_test" ) == 0 ) {
+ check_encoder_option(decode_only, "-silk12k_test");
+ mode_list = silk12_test;
+ nb_modes_in_list = 8;
+ args++;
+ } else if( strcmp( argv[ args ], "-silk16k_test" ) == 0 ) {
+ check_encoder_option(decode_only, "-silk16k_test");
+ mode_list = silk16_test;
+ nb_modes_in_list = 8;
+ args++;
+ } else if( strcmp( argv[ args ], "-hybrid24k_test" ) == 0 ) {
+ check_encoder_option(decode_only, "-hybrid24k_test");
+ mode_list = hybrid24_test;
+ nb_modes_in_list = 4;
+ args++;
+ } else if( strcmp( argv[ args ], "-hybrid48k_test" ) == 0 ) {
+ check_encoder_option(decode_only, "-hybrid48k_test");
+ mode_list = hybrid48_test;
+ nb_modes_in_list = 4;
+ args++;
+ } else if( strcmp( argv[ args ], "-celt_test" ) == 0 ) {
+ check_encoder_option(decode_only, "-celt_test");
+ mode_list = celt_test;
+ nb_modes_in_list = 32;
+ args++;
+ } else if( strcmp( argv[ args ], "-celt_hq_test" ) == 0 ) {
+ check_encoder_option(decode_only, "-celt_hq_test");
+ mode_list = celt_hq_test;
+ nb_modes_in_list = 4;
+ args++;
+ } else {
+ printf( "Error: unrecognized setting: %s\n\n", argv[ args ] );
+ print_usage( argv );
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (sweep_max)
+ sweep_min = bitrate_bps;
+
+ if (max_payload_bytes < 0 || max_payload_bytes > MAX_PACKET)
+ {
+ fprintf (stderr, "max_payload_bytes must be between 0 and %d\n",
+ MAX_PACKET);
+ return EXIT_FAILURE;
+ }
+
+ inFile = argv[argc-2];
+ fin = fopen(inFile, "rb");
+ if (!fin)
+ {
+ fprintf (stderr, "Could not open input file %s\n", argv[argc-2]);
+ return EXIT_FAILURE;
+ }
+ if (mode_list)
+ {
+ int size;
+ fseek(fin, 0, SEEK_END);
+ size = ftell(fin);
+ fprintf(stderr, "File size is %d bytes\n", size);
+ fseek(fin, 0, SEEK_SET);
+ mode_switch_time = size/sizeof(short)/channels/nb_modes_in_list;
+ fprintf(stderr, "Switching mode every %d samples\n", mode_switch_time);
+ }
+
+ outFile = argv[argc-1];
+ fout = fopen(outFile, "wb+");
+ if (!fout)
+ {
+ fprintf (stderr, "Could not open output file %s\n", argv[argc-1]);
+ fclose(fin);
+ return EXIT_FAILURE;
+ }
+
+ if (!decode_only)
+ {
+ enc = opus_encoder_create(sampling_rate, channels, application, &err);
+ if (err != OPUS_OK)
+ {
+ fprintf(stderr, "Cannot create encoder: %s\n", opus_strerror(err));
+ fclose(fin);
+ fclose(fout);
+ return EXIT_FAILURE;
+ }
+ opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps));
+ opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(bandwidth));
+ opus_encoder_ctl(enc, OPUS_SET_VBR(use_vbr));
+ opus_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(cvbr));
+ opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity));
+ opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(use_inbandfec));
+ opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(forcechannels));
+ opus_encoder_ctl(enc, OPUS_SET_DTX(use_dtx));
+ opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(packet_loss_perc));
+
+ opus_encoder_ctl(enc, OPUS_GET_LOOKAHEAD(&skip));
+ opus_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(16));
+ opus_encoder_ctl(enc, OPUS_SET_EXPERT_FRAME_DURATION(variable_duration));
+ }
+ if (!encode_only)
+ {
+ dec = opus_decoder_create(sampling_rate, channels, &err);
+ if (err != OPUS_OK)
+ {
+ fprintf(stderr, "Cannot create decoder: %s\n", opus_strerror(err));
+ fclose(fin);
+ fclose(fout);
+ return EXIT_FAILURE;
+ }
+ }
+
+
+ switch(bandwidth)
+ {
+ case OPUS_BANDWIDTH_NARROWBAND:
+ bandwidth_string = "narrowband";
+ break;
+ case OPUS_BANDWIDTH_MEDIUMBAND:
+ bandwidth_string = "mediumband";
+ break;
+ case OPUS_BANDWIDTH_WIDEBAND:
+ bandwidth_string = "wideband";
+ break;
+ case OPUS_BANDWIDTH_SUPERWIDEBAND:
+ bandwidth_string = "superwideband";
+ break;
+ case OPUS_BANDWIDTH_FULLBAND:
+ bandwidth_string = "fullband";
+ break;
+ case OPUS_AUTO:
+ bandwidth_string = "auto";
+ break;
+ default:
+ bandwidth_string = "unknown";
+ break;
+ }
+
+ if (decode_only)
+ fprintf(stderr, "Decoding with %ld Hz output (%d channels)\n",
+ (long)sampling_rate, channels);
+ else
+ fprintf(stderr, "Encoding %ld Hz input at %.3f kb/s "
+ "in %s mode with %d-sample frames.\n",
+ (long)sampling_rate, bitrate_bps*0.001,
+ bandwidth_string, frame_size);
+
+ in = (short*)malloc(max_frame_size*channels*sizeof(short));
+ out = (short*)malloc(max_frame_size*channels*sizeof(short));
+ fbytes = (unsigned char*)malloc(max_frame_size*channels*sizeof(short));
+ data[0] = (unsigned char*)calloc(max_payload_bytes,sizeof(char));
+ if ( use_inbandfec ) {
+ data[1] = (unsigned char*)calloc(max_payload_bytes,sizeof(char));
+ }
+ if(delayed_decision)
+ {
+ if (variable_duration!=OPUS_FRAMESIZE_VARIABLE)
+ {
+ if (frame_size==sampling_rate/400)
+ variable_duration = OPUS_FRAMESIZE_2_5_MS;
+ else if (frame_size==sampling_rate/200)
+ variable_duration = OPUS_FRAMESIZE_5_MS;
+ else if (frame_size==sampling_rate/100)
+ variable_duration = OPUS_FRAMESIZE_10_MS;
+ else if (frame_size==sampling_rate/50)
+ variable_duration = OPUS_FRAMESIZE_20_MS;
+ else if (frame_size==sampling_rate/25)
+ variable_duration = OPUS_FRAMESIZE_40_MS;
+ else
+ variable_duration = OPUS_FRAMESIZE_60_MS;
+ opus_encoder_ctl(enc, OPUS_SET_EXPERT_FRAME_DURATION(variable_duration));
+ }
+ frame_size = 2*48000;
+ }
+ while (!stop)
+ {
+ if (delayed_celt)
+ {
+ frame_size = newsize;
+ delayed_celt = 0;
+ } else if (random_framesize && rand()%20==0)
+ {
+ newsize = rand()%6;
+ switch(newsize)
+ {
+ case 0: newsize=sampling_rate/400; break;
+ case 1: newsize=sampling_rate/200; break;
+ case 2: newsize=sampling_rate/100; break;
+ case 3: newsize=sampling_rate/50; break;
+ case 4: newsize=sampling_rate/25; break;
+ case 5: newsize=3*sampling_rate/50; break;
+ }
+ while (newsize < sampling_rate/25 && bitrate_bps-fabs(sweep_bps) <= 3*12*sampling_rate/newsize)
+ newsize*=2;
+ if (newsize < sampling_rate/100 && frame_size >= sampling_rate/100)
+ {
+ opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY));
+ delayed_celt=1;
+ } else {
+ frame_size = newsize;
+ }
+ }
+ if (random_fec && rand()%30==0)
+ {
+ opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(rand()%4==0));
+ }
+ if (decode_only)
+ {
+ unsigned char ch[4];
+ err = fread(ch, 1, 4, fin);
+ if (feof(fin))
+ break;
+ len[toggle] = char_to_int(ch);
+ if (len[toggle]>max_payload_bytes || len[toggle]<0)
+ {
+ fprintf(stderr, "Invalid payload length: %d\n",len[toggle]);
+ break;
+ }
+ err = fread(ch, 1, 4, fin);
+ enc_final_range[toggle] = char_to_int(ch);
+ err = fread(data[toggle], 1, len[toggle], fin);
+ if (err<len[toggle])
+ {
+ fprintf(stderr, "Ran out of input, "
+ "expecting %d bytes got %d\n",
+ len[toggle],err);
+ break;
+ }
+ } else {
+ int i;
+ if (mode_list!=NULL)
+ {
+ opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(mode_list[curr_mode][1]));
+ opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(mode_list[curr_mode][0]));
+ opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(mode_list[curr_mode][3]));
+ frame_size = mode_list[curr_mode][2];
+ }
+ err = fread(fbytes, sizeof(short)*channels, frame_size-remaining, fin);
+ curr_read = err;
+ tot_in += curr_read;
+ for(i=0;i<curr_read*channels;i++)
+ {
+ opus_int32 s;
+ s=fbytes[2*i+1]<<8|fbytes[2*i];
+ s=((s&0xFFFF)^0x8000)-0x8000;
+ in[i+remaining*channels]=s;
+ }
+ if (curr_read+remaining < frame_size)
+ {
+ for (i=(curr_read+remaining)*channels;i<frame_size*channels;i++)
+ in[i] = 0;
+ if (encode_only || decode_only)
+ stop = 1;
+ }
+ len[toggle] = opus_encode(enc, in, frame_size, data[toggle], max_payload_bytes);
+ nb_encoded = opus_packet_get_samples_per_frame(data[toggle], sampling_rate)*opus_packet_get_nb_frames(data[toggle], len[toggle]);
+ remaining = frame_size-nb_encoded;
+ for(i=0;i<remaining*channels;i++)
+ in[i] = in[nb_encoded*channels+i];
+ if (sweep_bps!=0)
+ {
+ bitrate_bps += sweep_bps;
+ if (sweep_max)
+ {
+ if (bitrate_bps > sweep_max)
+ sweep_bps = -sweep_bps;
+ else if (bitrate_bps < sweep_min)
+ sweep_bps = -sweep_bps;
+ }
+ /* safety */
+ if (bitrate_bps<1000)
+ bitrate_bps = 1000;
+ opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps));
+ }
+ opus_encoder_ctl(enc, OPUS_GET_FINAL_RANGE(&enc_final_range[toggle]));
+ if (len[toggle] < 0)
+ {
+ fprintf (stderr, "opus_encode() returned %d\n", len[toggle]);
+ fclose(fin);
+ fclose(fout);
+ return EXIT_FAILURE;
+ }
+ curr_mode_count += frame_size;
+ if (curr_mode_count > mode_switch_time && curr_mode < nb_modes_in_list-1)
+ {
+ curr_mode++;
+ curr_mode_count = 0;
+ }
+ }
+
+#if 0 /* This is for testing the padding code, do not enable by default */
+ if (len[toggle]<1275)
+ {
+ int new_len = len[toggle]+rand()%(max_payload_bytes-len[toggle]);
+ if ((err = opus_packet_pad(data[toggle], len[toggle], new_len)) != OPUS_OK)
+ {
+ fprintf(stderr, "padding failed: %s\n", opus_strerror(err));
+ return EXIT_FAILURE;
+ }
+ len[toggle] = new_len;
+ }
+#endif
+ if (encode_only)
+ {
+ unsigned char int_field[4];
+ int_to_char(len[toggle], int_field);
+ if (fwrite(int_field, 1, 4, fout) != 4) {
+ fprintf(stderr, "Error writing.\n");
+ return EXIT_FAILURE;
+ }
+ int_to_char(enc_final_range[toggle], int_field);
+ if (fwrite(int_field, 1, 4, fout) != 4) {
+ fprintf(stderr, "Error writing.\n");
+ return EXIT_FAILURE;
+ }
+ if (fwrite(data[toggle], 1, len[toggle], fout) != (unsigned)len[toggle]) {
+ fprintf(stderr, "Error writing.\n");
+ return EXIT_FAILURE;
+ }
+ tot_samples += nb_encoded;
+ } else {
+ int output_samples;
+ lost = len[toggle]==0 || (packet_loss_perc>0 && rand()%100 < packet_loss_perc);
+ if (lost)
+ opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&output_samples));
+ else
+ output_samples = max_frame_size;
+ if( count >= use_inbandfec ) {
+ /* delay by one packet when using in-band FEC */
+ if( use_inbandfec ) {
+ if( lost_prev ) {
+ /* attempt to decode with in-band FEC from next packet */
+ opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&output_samples));
+ output_samples = opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, output_samples, 1);
+ } else {
+ /* regular decode */
+ output_samples = max_frame_size;
+ output_samples = opus_decode(dec, data[1-toggle], len[1-toggle], out, output_samples, 0);
+ }
+ } else {
+ output_samples = opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, output_samples, 0);
+ }
+ if (output_samples>0)
+ {
+ if (!decode_only && tot_out + output_samples > tot_in)
+ {
+ stop=1;
+ output_samples = tot_in-tot_out;
+ }
+ if (output_samples>skip) {
+ int i;
+ for(i=0;i<(output_samples-skip)*channels;i++)
+ {
+ short s;
+ s=out[i+(skip*channels)];
+ fbytes[2*i]=s&0xFF;
+ fbytes[2*i+1]=(s>>8)&0xFF;
+ }
+ if (fwrite(fbytes, sizeof(short)*channels, output_samples-skip, fout) != (unsigned)(output_samples-skip)){
+ fprintf(stderr, "Error writing.\n");
+ return EXIT_FAILURE;
+ }
+ tot_out += output_samples-skip;
+ }
+ if (output_samples<skip) skip -= output_samples;
+ else skip = 0;
+ } else {
+ fprintf(stderr, "error decoding frame: %s\n",
+ opus_strerror(output_samples));
+ }
+ tot_samples += output_samples;
+ }
+ }
+
+ if (!encode_only)
+ opus_decoder_ctl(dec, OPUS_GET_FINAL_RANGE(&dec_final_range));
+ /* compare final range encoder rng values of encoder and decoder */
+ if( enc_final_range[toggle^use_inbandfec]!=0 && !encode_only
+ && !lost && !lost_prev
+ && dec_final_range != enc_final_range[toggle^use_inbandfec] ) {
+ fprintf (stderr, "Error: Range coder state mismatch "
+ "between encoder and decoder "
+ "in frame %ld: 0x%8lx vs 0x%8lx\n",
+ (long)count,
+ (unsigned long)enc_final_range[toggle^use_inbandfec],
+ (unsigned long)dec_final_range);
+ fclose(fin);
+ fclose(fout);
+ return EXIT_FAILURE;
+ }
+
+ lost_prev = lost;
+
+ /* count bits */
+ bits += len[toggle]*8;
+ bits_max = ( len[toggle]*8 > bits_max ) ? len[toggle]*8 : bits_max;
+ if( count >= use_inbandfec ) {
+ nrg = 0.0;
+ if (!decode_only)
+ {
+ for ( k = 0; k < frame_size * channels; k++ ) {
+ nrg += in[ k ] * (double)in[ k ];
+ }
+ }
+ if ( ( nrg / ( frame_size * channels ) ) > 1e5 ) {
+ bits_act += len[toggle]*8;
+ count_act++;
+ }
+ /* Variance */
+ bits2 += len[toggle]*len[toggle]*64;
+ }
+ count++;
+ toggle = (toggle + use_inbandfec) & 1;
+ }
+ fprintf (stderr, "average bitrate: %7.3f kb/s\n",
+ 1e-3*bits*sampling_rate/tot_samples);
+ fprintf (stderr, "maximum bitrate: %7.3f kb/s\n",
+ 1e-3*bits_max*sampling_rate/frame_size);
+ if (!decode_only)
+ fprintf (stderr, "active bitrate: %7.3f kb/s\n",
+ 1e-3*bits_act*sampling_rate/(frame_size*(double)count_act));
+ fprintf (stderr, "bitrate standard deviation: %7.3f kb/s\n",
+ 1e-3*sqrt(bits2/count - bits*bits/(count*(double)count))*sampling_rate/frame_size);
+ /* Close any files to which intermediate results were stored */
+ SILK_DEBUG_STORE_CLOSE_FILES
+ silk_TimerSave("opus_timing.txt");
+ opus_encoder_destroy(enc);
+ opus_decoder_destroy(dec);
+ free(data[0]);
+ if (use_inbandfec)
+ free(data[1]);
+ fclose(fin);
+ fclose(fout);
+ free(in);
+ free(out);
+ free(fbytes);
+ return EXIT_SUCCESS;
+}
diff --git a/drivers/opus/opus_encoder.c b/drivers/opus/opus_encoder.c
new file mode 100644
index 0000000000..890a2514de
--- /dev/null
+++ b/drivers/opus/opus_encoder.c
@@ -0,0 +1,2488 @@
+/* Copyright (c) 2010-2011 Xiph.Org Foundation, Skype Limited
+ Written by Jean-Marc Valin and Koen Vos */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include <stdarg.h>
+#include "opus/celt/celt.h"
+#include "opus/celt/entenc.h"
+#include "opus/celt/opus_modes.h"
+#include "opus/silk/API.h"
+#include "opus/celt/stack_alloc.h"
+#include "opus/celt/float_cast.h"
+#include "opus/opus.h"
+#include "opus/celt/arch.h"
+#include "opus/opus_private.h"
+#include "opus/celt/os_support.h"
+#include "opus/celt/cpu_support.h"
+#include "opus/analysis.h"
+#include "opus/celt/mathops.h"
+#include "opus/silk/tuning_parameters.h"
+#ifdef OPUS_FIXED_POINT
+#include "opus/silk/fixed/structs_FIX.h"
+#else
+#include "opus/silk/float/structs_FLP.h"
+#endif
+
+#define MAX_ENCODER_BUFFER 480
+
+typedef struct {
+ opus_val32 XX, XY, YY;
+ opus_val16 smoothed_width;
+ opus_val16 max_follower;
+} StereoWidthState;
+
+struct OpusEncoder {
+ int celt_enc_offset;
+ int silk_enc_offset;
+ silk_EncControlStruct silk_mode;
+ int application;
+ int channels;
+ int delay_compensation;
+ int force_channels;
+ int signal_type;
+ int user_bandwidth;
+ int max_bandwidth;
+ int user_forced_mode;
+ int voice_ratio;
+ opus_int32 Fs;
+ int use_vbr;
+ int vbr_constraint;
+ int variable_duration;
+ opus_int32 bitrate_bps;
+ opus_int32 user_bitrate_bps;
+ int lsb_depth;
+ int encoder_buffer;
+ int lfe;
+
+#define OPUS_ENCODER_RESET_START stream_channels
+ int stream_channels;
+ opus_int16 hybrid_stereo_width_Q14;
+ opus_int32 variable_HP_smth2_Q15;
+ opus_val16 prev_HB_gain;
+ opus_val32 hp_mem[4];
+ int mode;
+ int prev_mode;
+ int prev_channels;
+ int prev_framesize;
+ int bandwidth;
+ int silk_bw_switch;
+ /* Sampling rate (at the API level) */
+ int first;
+ opus_val16 * energy_masking;
+ StereoWidthState width_mem;
+ opus_val16 delay_buffer[MAX_ENCODER_BUFFER*2];
+#ifndef DISABLE_FLOAT_API
+ TonalityAnalysisState analysis;
+ int detected_bandwidth;
+ int analysis_offset;
+#endif
+ opus_uint32 rangeFinal;
+ int arch;
+};
+
+/* Transition tables for the voice and music. First column is the
+ middle (memoriless) threshold. The second column is the hysteresis
+ (difference with the middle) */
+static const opus_int32 mono_voice_bandwidth_thresholds[8] = {
+ 11000, 1000, /* NB<->MB */
+ 14000, 1000, /* MB<->WB */
+ 17000, 1000, /* WB<->SWB */
+ 21000, 2000, /* SWB<->FB */
+};
+static const opus_int32 mono_music_bandwidth_thresholds[8] = {
+ 12000, 1000, /* NB<->MB */
+ 15000, 1000, /* MB<->WB */
+ 18000, 2000, /* WB<->SWB */
+ 22000, 2000, /* SWB<->FB */
+};
+static const opus_int32 stereo_voice_bandwidth_thresholds[8] = {
+ 11000, 1000, /* NB<->MB */
+ 14000, 1000, /* MB<->WB */
+ 21000, 2000, /* WB<->SWB */
+ 28000, 2000, /* SWB<->FB */
+};
+static const opus_int32 stereo_music_bandwidth_thresholds[8] = {
+ 12000, 1000, /* NB<->MB */
+ 18000, 2000, /* MB<->WB */
+ 21000, 2000, /* WB<->SWB */
+ 30000, 2000, /* SWB<->FB */
+};
+/* Threshold bit-rates for switching between mono and stereo */
+static const opus_int32 stereo_voice_threshold = 30000;
+static const opus_int32 stereo_music_threshold = 30000;
+
+/* Threshold bit-rate for switching between SILK/hybrid and CELT-only */
+static const opus_int32 mode_thresholds[2][2] = {
+ /* voice */ /* music */
+ { 64000, 16000}, /* mono */
+ { 36000, 16000}, /* stereo */
+};
+
+int opus_encoder_get_size(int channels)
+{
+ int silkEncSizeBytes, celtEncSizeBytes;
+ int ret;
+ if (channels<1 || channels > 2)
+ return 0;
+ ret = silk_Get_Encoder_Size( &silkEncSizeBytes );
+ if (ret)
+ return 0;
+ silkEncSizeBytes = align(silkEncSizeBytes);
+ celtEncSizeBytes = celt_encoder_get_size(channels);
+ return align(sizeof(OpusEncoder))+silkEncSizeBytes+celtEncSizeBytes;
+}
+
+int opus_encoder_init(OpusEncoder* st, opus_int32 Fs, int channels, int application)
+{
+ void *silk_enc;
+ CELTEncoder *celt_enc;
+ int err;
+ int ret, silkEncSizeBytes;
+
+ if((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000)||(channels!=1&&channels!=2)||
+ (application != OPUS_APPLICATION_VOIP && application != OPUS_APPLICATION_AUDIO
+ && application != OPUS_APPLICATION_RESTRICTED_LOWDELAY))
+ return OPUS_BAD_ARG;
+
+ OPUS_CLEAR((char*)st, opus_encoder_get_size(channels));
+ /* Create SILK encoder */
+ ret = silk_Get_Encoder_Size( &silkEncSizeBytes );
+ if (ret)
+ return OPUS_BAD_ARG;
+ silkEncSizeBytes = align(silkEncSizeBytes);
+ st->silk_enc_offset = align(sizeof(OpusEncoder));
+ st->celt_enc_offset = st->silk_enc_offset+silkEncSizeBytes;
+ silk_enc = (char*)st+st->silk_enc_offset;
+ celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset);
+
+ st->stream_channels = st->channels = channels;
+
+ st->Fs = Fs;
+
+ st->arch = opus_select_arch();
+
+ ret = silk_InitEncoder( silk_enc, st->arch, &st->silk_mode );
+ if(ret)return OPUS_INTERNAL_ERROR;
+
+ /* default SILK parameters */
+ st->silk_mode.nChannelsAPI = channels;
+ st->silk_mode.nChannelsInternal = channels;
+ st->silk_mode.API_sampleRate = st->Fs;
+ st->silk_mode.maxInternalSampleRate = 16000;
+ st->silk_mode.minInternalSampleRate = 8000;
+ st->silk_mode.desiredInternalSampleRate = 16000;
+ st->silk_mode.payloadSize_ms = 20;
+ st->silk_mode.bitRate = 25000;
+ st->silk_mode.packetLossPercentage = 0;
+ st->silk_mode.complexity = 9;
+ st->silk_mode.useInBandFEC = 0;
+ st->silk_mode.useDTX = 0;
+ st->silk_mode.useCBR = 0;
+ st->silk_mode.reducedDependency = 0;
+
+ /* Create CELT encoder */
+ /* Initialize CELT encoder */
+ err = celt_encoder_init(celt_enc, Fs, channels, st->arch);
+ if(err!=OPUS_OK)return OPUS_INTERNAL_ERROR;
+
+ celt_encoder_ctl(celt_enc, CELT_SET_SIGNALLING(0));
+ celt_encoder_ctl(celt_enc, OPUS_SET_COMPLEXITY(st->silk_mode.complexity));
+
+ st->use_vbr = 1;
+ /* Makes constrained VBR the default (safer for real-time use) */
+ st->vbr_constraint = 1;
+ st->user_bitrate_bps = OPUS_AUTO;
+ st->bitrate_bps = 3000+Fs*channels;
+ st->application = application;
+ st->signal_type = OPUS_AUTO;
+ st->user_bandwidth = OPUS_AUTO;
+ st->max_bandwidth = OPUS_BANDWIDTH_FULLBAND;
+ st->force_channels = OPUS_AUTO;
+ st->user_forced_mode = OPUS_AUTO;
+ st->voice_ratio = -1;
+ st->encoder_buffer = st->Fs/100;
+ st->lsb_depth = 24;
+ st->variable_duration = OPUS_FRAMESIZE_ARG;
+
+ /* Delay compensation of 4 ms (2.5 ms for SILK's extra look-ahead
+ + 1.5 ms for SILK resamplers and stereo prediction) */
+ st->delay_compensation = st->Fs/250;
+
+ st->hybrid_stereo_width_Q14 = 1 << 14;
+ st->prev_HB_gain = Q15ONE;
+ st->variable_HP_smth2_Q15 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 );
+ st->first = 1;
+ st->mode = MODE_HYBRID;
+ st->bandwidth = OPUS_BANDWIDTH_FULLBAND;
+
+ return OPUS_OK;
+}
+
+static unsigned char gen_toc(int mode, int framerate, int bandwidth, int channels)
+{
+ int period;
+ unsigned char toc;
+ period = 0;
+ while (framerate < 400)
+ {
+ framerate <<= 1;
+ period++;
+ }
+ if (mode == MODE_SILK_ONLY)
+ {
+ toc = (bandwidth-OPUS_BANDWIDTH_NARROWBAND)<<5;
+ toc |= (period-2)<<3;
+ } else if (mode == MODE_CELT_ONLY)
+ {
+ int tmp = bandwidth-OPUS_BANDWIDTH_MEDIUMBAND;
+ if (tmp < 0)
+ tmp = 0;
+ toc = 0x80;
+ toc |= tmp << 5;
+ toc |= period<<3;
+ } else /* Hybrid */
+ {
+ toc = 0x60;
+ toc |= (bandwidth-OPUS_BANDWIDTH_SUPERWIDEBAND)<<4;
+ toc |= (period-2)<<3;
+ }
+ toc |= (channels==2)<<2;
+ return toc;
+}
+
+#ifndef OPUS_FIXED_POINT
+static void silk_biquad_float(
+ const opus_val16 *in, /* I: Input signal */
+ const opus_int32 *B_Q28, /* I: MA coefficients [3] */
+ const opus_int32 *A_Q28, /* I: AR coefficients [2] */
+ opus_val32 *S, /* I/O: State vector [2] */
+ opus_val16 *out, /* O: Output signal */
+ const opus_int32 len, /* I: Signal length (must be even) */
+ int stride
+)
+{
+ /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */
+ opus_int k;
+ opus_val32 vout;
+ opus_val32 inval;
+ opus_val32 A[2], B[3];
+
+ A[0] = (opus_val32)(A_Q28[0] * (1.f/((opus_int32)1<<28)));
+ A[1] = (opus_val32)(A_Q28[1] * (1.f/((opus_int32)1<<28)));
+ B[0] = (opus_val32)(B_Q28[0] * (1.f/((opus_int32)1<<28)));
+ B[1] = (opus_val32)(B_Q28[1] * (1.f/((opus_int32)1<<28)));
+ B[2] = (opus_val32)(B_Q28[2] * (1.f/((opus_int32)1<<28)));
+
+ /* Negate A_Q28 values and split in two parts */
+
+ for( k = 0; k < len; k++ ) {
+ /* S[ 0 ], S[ 1 ]: Q12 */
+ inval = in[ k*stride ];
+ vout = S[ 0 ] + B[0]*inval;
+
+ S[ 0 ] = S[1] - vout*A[0] + B[1]*inval;
+
+ S[ 1 ] = - vout*A[1] + B[2]*inval + VERY_SMALL;
+
+ /* Scale back to Q0 and saturate */
+ out[ k*stride ] = vout;
+ }
+}
+#endif
+
+static void hp_cutoff(const opus_val16 *in, opus_int32 cutoff_Hz, opus_val16 *out, opus_val32 *hp_mem, int len, int channels, opus_int32 Fs)
+{
+ opus_int32 B_Q28[ 3 ], A_Q28[ 2 ];
+ opus_int32 Fc_Q19, r_Q28, r_Q22;
+
+ silk_assert( cutoff_Hz <= silk_int32_MAX / SILK_FIX_CONST( 1.5 * 3.14159 / 1000, 19 ) );
+ Fc_Q19 = silk_DIV32_16( silk_SMULBB( SILK_FIX_CONST( 1.5 * 3.14159 / 1000, 19 ), cutoff_Hz ), Fs/1000 );
+ silk_assert( Fc_Q19 > 0 && Fc_Q19 < 32768 );
+
+ r_Q28 = SILK_FIX_CONST( 1.0, 28 ) - silk_MUL( SILK_FIX_CONST( 0.92, 9 ), Fc_Q19 );
+
+ /* b = r * [ 1; -2; 1 ]; */
+ /* a = [ 1; -2 * r * ( 1 - 0.5 * Fc^2 ); r^2 ]; */
+ B_Q28[ 0 ] = r_Q28;
+ B_Q28[ 1 ] = silk_LSHIFT( -r_Q28, 1 );
+ B_Q28[ 2 ] = r_Q28;
+
+ /* -r * ( 2 - Fc * Fc ); */
+ r_Q22 = silk_RSHIFT( r_Q28, 6 );
+ A_Q28[ 0 ] = silk_SMULWW( r_Q22, silk_SMULWW( Fc_Q19, Fc_Q19 ) - SILK_FIX_CONST( 2.0, 22 ) );
+ A_Q28[ 1 ] = silk_SMULWW( r_Q22, r_Q22 );
+
+#ifdef OPUS_FIXED_POINT
+ silk_biquad_alt( in, B_Q28, A_Q28, hp_mem, out, len, channels );
+ if( channels == 2 ) {
+ silk_biquad_alt( in+1, B_Q28, A_Q28, hp_mem+2, out+1, len, channels );
+ }
+#else
+ silk_biquad_float( in, B_Q28, A_Q28, hp_mem, out, len, channels );
+ if( channels == 2 ) {
+ silk_biquad_float( in+1, B_Q28, A_Q28, hp_mem+2, out+1, len, channels );
+ }
+#endif
+}
+
+#ifdef OPUS_FIXED_POINT
+static void dc_reject(const opus_val16 *in, opus_int32 cutoff_Hz, opus_val16 *out, opus_val32 *hp_mem, int len, int channels, opus_int32 Fs)
+{
+ int c, i;
+ int shift;
+
+ /* Approximates -round(log2(4.*cutoff_Hz/Fs)) */
+ shift=celt_ilog2(Fs/(cutoff_Hz*3));
+ for (c=0;c<channels;c++)
+ {
+ for (i=0;i<len;i++)
+ {
+ opus_val32 x, tmp, y;
+ x = SHL32(EXTEND32(in[channels*i+c]), 15);
+ /* First stage */
+ tmp = x-hp_mem[2*c];
+ hp_mem[2*c] = hp_mem[2*c] + PSHR32(x - hp_mem[2*c], shift);
+ /* Second stage */
+ y = tmp - hp_mem[2*c+1];
+ hp_mem[2*c+1] = hp_mem[2*c+1] + PSHR32(tmp - hp_mem[2*c+1], shift);
+ out[channels*i+c] = EXTRACT16(SATURATE(PSHR32(y, 15), 32767));
+ }
+ }
+}
+
+#else
+static void dc_reject(const opus_val16 *in, opus_int32 cutoff_Hz, opus_val16 *out, opus_val32 *hp_mem, int len, int channels, opus_int32 Fs)
+{
+ int c, i;
+ float coef;
+
+ coef = 4.0f*cutoff_Hz/Fs;
+ for (c=0;c<channels;c++)
+ {
+ for (i=0;i<len;i++)
+ {
+ opus_val32 x, tmp, y;
+ x = in[channels*i+c];
+ /* First stage */
+ tmp = x-hp_mem[2*c];
+ hp_mem[2*c] = hp_mem[2*c] + coef*(x - hp_mem[2*c]) + VERY_SMALL;
+ /* Second stage */
+ y = tmp - hp_mem[2*c+1];
+ hp_mem[2*c+1] = hp_mem[2*c+1] + coef*(tmp - hp_mem[2*c+1]) + VERY_SMALL;
+ out[channels*i+c] = y;
+ }
+ }
+}
+#endif
+
+static void stereo_fade(const opus_val16 *in, opus_val16 *out, opus_val16 g1, opus_val16 g2,
+ int overlap48, int frame_size, int channels, const opus_val16 *window, opus_int32 Fs)
+{
+ int i;
+ int overlap;
+ int inc;
+ inc = 48000/Fs;
+ overlap=overlap48/inc;
+ g1 = Q15ONE-g1;
+ g2 = Q15ONE-g2;
+ for (i=0;i<overlap;i++)
+ {
+ opus_val32 diff;
+ opus_val16 g, w;
+ w = MULT16_16_Q15(window[i*inc], window[i*inc]);
+ g = SHR32(MAC16_16(MULT16_16(w,g2),
+ Q15ONE-w, g1), 15);
+ diff = EXTRACT16(HALF32((opus_val32)in[i*channels] - (opus_val32)in[i*channels+1]));
+ diff = MULT16_16_Q15(g, diff);
+ out[i*channels] = out[i*channels] - diff;
+ out[i*channels+1] = out[i*channels+1] + diff;
+ }
+ for (;i<frame_size;i++)
+ {
+ opus_val32 diff;
+ diff = EXTRACT16(HALF32((opus_val32)in[i*channels] - (opus_val32)in[i*channels+1]));
+ diff = MULT16_16_Q15(g2, diff);
+ out[i*channels] = out[i*channels] - diff;
+ out[i*channels+1] = out[i*channels+1] + diff;
+ }
+}
+
+static void gain_fade(const opus_val16 *in, opus_val16 *out, opus_val16 g1, opus_val16 g2,
+ int overlap48, int frame_size, int channels, const opus_val16 *window, opus_int32 Fs)
+{
+ int i;
+ int inc;
+ int overlap;
+ int c;
+ inc = 48000/Fs;
+ overlap=overlap48/inc;
+ if (channels==1)
+ {
+ for (i=0;i<overlap;i++)
+ {
+ opus_val16 g, w;
+ w = MULT16_16_Q15(window[i*inc], window[i*inc]);
+ g = SHR32(MAC16_16(MULT16_16(w,g2),
+ Q15ONE-w, g1), 15);
+ out[i] = MULT16_16_Q15(g, in[i]);
+ }
+ } else {
+ for (i=0;i<overlap;i++)
+ {
+ opus_val16 g, w;
+ w = MULT16_16_Q15(window[i*inc], window[i*inc]);
+ g = SHR32(MAC16_16(MULT16_16(w,g2),
+ Q15ONE-w, g1), 15);
+ out[i*2] = MULT16_16_Q15(g, in[i*2]);
+ out[i*2+1] = MULT16_16_Q15(g, in[i*2+1]);
+ }
+ }
+ c=0;do {
+ for (i=overlap;i<frame_size;i++)
+ {
+ out[i*channels+c] = MULT16_16_Q15(g2, in[i*channels+c]);
+ }
+ }
+ while (++c<channels);
+}
+
+OpusEncoder *opus_encoder_create(opus_int32 Fs, int channels, int application, int *error)
+{
+ int ret;
+ OpusEncoder *st;
+ if((Fs!=48000&&Fs!=24000&&Fs!=16000&&Fs!=12000&&Fs!=8000)||(channels!=1&&channels!=2)||
+ (application != OPUS_APPLICATION_VOIP && application != OPUS_APPLICATION_AUDIO
+ && application != OPUS_APPLICATION_RESTRICTED_LOWDELAY))
+ {
+ if (error)
+ *error = OPUS_BAD_ARG;
+ return NULL;
+ }
+ st = (OpusEncoder *)opus_alloc(opus_encoder_get_size(channels));
+ if (st == NULL)
+ {
+ if (error)
+ *error = OPUS_ALLOC_FAIL;
+ return NULL;
+ }
+ ret = opus_encoder_init(st, Fs, channels, application);
+ if (error)
+ *error = ret;
+ if (ret != OPUS_OK)
+ {
+ opus_free(st);
+ st = NULL;
+ }
+ return st;
+}
+
+static opus_int32 user_bitrate_to_bitrate(OpusEncoder *st, int frame_size, int max_data_bytes)
+{
+ if(!frame_size)frame_size=st->Fs/400;
+ if (st->user_bitrate_bps==OPUS_AUTO)
+ return 60*st->Fs/frame_size + st->Fs*st->channels;
+ else if (st->user_bitrate_bps==OPUS_BITRATE_MAX)
+ return max_data_bytes*8*st->Fs/frame_size;
+ else
+ return st->user_bitrate_bps;
+}
+
+#ifndef DISABLE_FLOAT_API
+/* Don't use more than 60 ms for the frame size analysis */
+#define MAX_DYNAMIC_FRAMESIZE 24
+/* Estimates how much the bitrate will be boosted based on the sub-frame energy */
+static float transient_boost(const float *E, const float *E_1, int LM, int maxM)
+{
+ int i;
+ int M;
+ float sumE=0, sumE_1=0;
+ float metric;
+
+ M = IMIN(maxM, (1<<LM)+1);
+ for (i=0;i<M;i++)
+ {
+ sumE += E[i];
+ sumE_1 += E_1[i];
+ }
+ metric = sumE*sumE_1/(M*M);
+ /*if (LM==3)
+ printf("%f\n", metric);*/
+ /*return metric>10 ? 1 : 0;*/
+ /*return MAX16(0,1-exp(-.25*(metric-2.)));*/
+ return MIN16(1,(float)sqrt(MAX16(0,.05f*(metric-2))));
+}
+
+/* Viterbi decoding trying to find the best frame size combination using look-ahead
+
+ State numbering:
+ 0: unused
+ 1: 2.5 ms
+ 2: 5 ms (#1)
+ 3: 5 ms (#2)
+ 4: 10 ms (#1)
+ 5: 10 ms (#2)
+ 6: 10 ms (#3)
+ 7: 10 ms (#4)
+ 8: 20 ms (#1)
+ 9: 20 ms (#2)
+ 10: 20 ms (#3)
+ 11: 20 ms (#4)
+ 12: 20 ms (#5)
+ 13: 20 ms (#6)
+ 14: 20 ms (#7)
+ 15: 20 ms (#8)
+*/
+static int transient_viterbi(const float *E, const float *E_1, int N, int frame_cost, int rate)
+{
+ int i;
+ float cost[MAX_DYNAMIC_FRAMESIZE][16];
+ int states[MAX_DYNAMIC_FRAMESIZE][16];
+ float best_cost;
+ int best_state;
+ float factor;
+ /* Take into account that we damp VBR in the 32 kb/s to 64 kb/s range. */
+ if (rate<80)
+ factor=0;
+ else if (rate>160)
+ factor=1;
+ else
+ factor = (rate-80.f)/80.f;
+ /* Makes variable framesize less aggressive at lower bitrates, but I can't
+ find any valid theoretical justification for this (other than it seems
+ to help) */
+ for (i=0;i<16;i++)
+ {
+ /* Impossible state */
+ states[0][i] = -1;
+ cost[0][i] = 1e10;
+ }
+ for (i=0;i<4;i++)
+ {
+ cost[0][1<<i] = (frame_cost + rate*(1<<i))*(1+factor*transient_boost(E, E_1, i, N+1));
+ states[0][1<<i] = i;
+ }
+ for (i=1;i<N;i++)
+ {
+ int j;
+
+ /* Follow continuations */
+ for (j=2;j<16;j++)
+ {
+ cost[i][j] = cost[i-1][j-1];
+ states[i][j] = j-1;
+ }
+
+ /* New frames */
+ for(j=0;j<4;j++)
+ {
+ int k;
+ float min_cost;
+ float curr_cost;
+ states[i][1<<j] = 1;
+ min_cost = cost[i-1][1];
+ for(k=1;k<4;k++)
+ {
+ float tmp = cost[i-1][(1<<(k+1))-1];
+ if (tmp < min_cost)
+ {
+ states[i][1<<j] = (1<<(k+1))-1;
+ min_cost = tmp;
+ }
+ }
+ curr_cost = (frame_cost + rate*(1<<j))*(1+factor*transient_boost(E+i, E_1+i, j, N-i+1));
+ cost[i][1<<j] = min_cost;
+ /* If part of the frame is outside the analysis window, only count part of the cost */
+ if (N-i < (1<<j))
+ cost[i][1<<j] += curr_cost*(float)(N-i)/(1<<j);
+ else
+ cost[i][1<<j] += curr_cost;
+ }
+ }
+
+ best_state=1;
+ best_cost = cost[N-1][1];
+ /* Find best end state (doesn't force a frame to end at N-1) */
+ for (i=2;i<16;i++)
+ {
+ if (cost[N-1][i]<best_cost)
+ {
+ best_cost = cost[N-1][i];
+ best_state = i;
+ }
+ }
+
+ /* Follow transitions back */
+ for (i=N-1;i>=0;i--)
+ {
+ /*printf("%d ", best_state);*/
+ best_state = states[i][best_state];
+ }
+ /*printf("%d\n", best_state);*/
+ return best_state;
+}
+
+int optimize_framesize(const opus_val16 *x, int len, int C, opus_int32 Fs,
+ int bitrate, opus_val16 tonality, float *mem, int buffering,
+ downmix_func downmix)
+{
+ int N;
+ int i;
+ float e[MAX_DYNAMIC_FRAMESIZE+4];
+ float e_1[MAX_DYNAMIC_FRAMESIZE+3];
+ opus_val32 memx;
+ int bestLM=0;
+ int subframe;
+ int pos;
+ VARDECL(opus_val32, sub);
+
+ subframe = Fs/400;
+ ALLOC(sub, subframe, opus_val32);
+ e[0]=mem[0];
+ e_1[0]=1.f/(EPSILON+mem[0]);
+ if (buffering)
+ {
+ /* Consider the CELT delay when not in restricted-lowdelay */
+ /* We assume the buffering is between 2.5 and 5 ms */
+ int offset = 2*subframe - buffering;
+ celt_assert(offset>=0 && offset <= subframe);
+ x += C*offset;
+ len -= offset;
+ e[1]=mem[1];
+ e_1[1]=1.f/(EPSILON+mem[1]);
+ e[2]=mem[2];
+ e_1[2]=1.f/(EPSILON+mem[2]);
+ pos = 3;
+ } else {
+ pos=1;
+ }
+ N=IMIN(len/subframe, MAX_DYNAMIC_FRAMESIZE);
+ /* Just silencing a warning, it's really initialized later */
+ memx = 0;
+ for (i=0;i<N;i++)
+ {
+ float tmp;
+ opus_val32 tmpx;
+ int j;
+ tmp=EPSILON;
+
+ downmix(x, sub, subframe, i*subframe, 0, -2, C);
+ if (i==0)
+ memx = sub[0];
+ for (j=0;j<subframe;j++)
+ {
+ tmpx = sub[j];
+ tmp += (tmpx-memx)*(float)(tmpx-memx);
+ memx = tmpx;
+ }
+ e[i+pos] = tmp;
+ e_1[i+pos] = 1.f/tmp;
+ }
+ /* Hack to get 20 ms working with APPLICATION_AUDIO
+ The real problem is that the corresponding memory needs to use 1.5 ms
+ from this frame and 1 ms from the next frame */
+ e[i+pos] = e[i+pos-1];
+ if (buffering)
+ N=IMIN(MAX_DYNAMIC_FRAMESIZE, N+2);
+ bestLM = transient_viterbi(e, e_1, N, (int)((1.f+.5f*tonality)*(60*C+40)), bitrate/400);
+ mem[0] = e[1<<bestLM];
+ if (buffering)
+ {
+ mem[1] = e[(1<<bestLM)+1];
+ mem[2] = e[(1<<bestLM)+2];
+ }
+ return bestLM;
+}
+
+#endif
+
+#ifndef DISABLE_FLOAT_API
+#ifdef OPUS_FIXED_POINT
+#define PCM2VAL(x) FLOAT2INT16(x)
+#else
+#define PCM2VAL(x) SCALEIN(x)
+#endif
+void downmix_float(const void *_x, opus_val32 *sub, int subframe, int offset, int c1, int c2, int C)
+{
+ const float *x;
+ opus_val32 scale;
+ int j;
+ x = (const float *)_x;
+ for (j=0;j<subframe;j++)
+ sub[j] = PCM2VAL(x[(j+offset)*C+c1]);
+ if (c2>-1)
+ {
+ for (j=0;j<subframe;j++)
+ sub[j] += PCM2VAL(x[(j+offset)*C+c2]);
+ } else if (c2==-2)
+ {
+ int c;
+ for (c=1;c<C;c++)
+ {
+ for (j=0;j<subframe;j++)
+ sub[j] += PCM2VAL(x[(j+offset)*C+c]);
+ }
+ }
+#ifdef OPUS_FIXED_POINT
+ scale = (1<<SIG_SHIFT);
+#else
+ scale = 1.f;
+#endif
+ if (C==-2)
+ scale /= C;
+ else
+ scale /= 2;
+ for (j=0;j<subframe;j++)
+ sub[j] *= scale;
+}
+#endif
+
+void downmix_int(const void *_x, opus_val32 *sub, int subframe, int offset, int c1, int c2, int C)
+{
+ const opus_int16 *x;
+ opus_val32 scale;
+ int j;
+ x = (const opus_int16 *)_x;
+ for (j=0;j<subframe;j++)
+ sub[j] = x[(j+offset)*C+c1];
+ if (c2>-1)
+ {
+ for (j=0;j<subframe;j++)
+ sub[j] += x[(j+offset)*C+c2];
+ } else if (c2==-2)
+ {
+ int c;
+ for (c=1;c<C;c++)
+ {
+ for (j=0;j<subframe;j++)
+ sub[j] += x[(j+offset)*C+c];
+ }
+ }
+#ifdef OPUS_FIXED_POINT
+ scale = (1<<SIG_SHIFT);
+#else
+ scale = 1.f/32768;
+#endif
+ if (C==-2)
+ scale /= C;
+ else
+ scale /= 2;
+ for (j=0;j<subframe;j++)
+ sub[j] *= scale;
+}
+
+opus_int32 frame_size_select(opus_int32 frame_size, int variable_duration, opus_int32 Fs)
+{
+ int new_size;
+ if (frame_size<Fs/400)
+ return -1;
+ if (variable_duration == OPUS_FRAMESIZE_ARG)
+ new_size = frame_size;
+ else if (variable_duration == OPUS_FRAMESIZE_VARIABLE)
+ new_size = Fs/50;
+ else if (variable_duration >= OPUS_FRAMESIZE_2_5_MS && variable_duration <= OPUS_FRAMESIZE_60_MS)
+ new_size = IMIN(3*Fs/50, (Fs/400)<<(variable_duration-OPUS_FRAMESIZE_2_5_MS));
+ else
+ return -1;
+ if (new_size>frame_size)
+ return -1;
+ if (400*new_size!=Fs && 200*new_size!=Fs && 100*new_size!=Fs &&
+ 50*new_size!=Fs && 25*new_size!=Fs && 50*new_size!=3*Fs)
+ return -1;
+ return new_size;
+}
+
+opus_int32 compute_frame_size(const void *analysis_pcm, int frame_size,
+ int variable_duration, int C, opus_int32 Fs, int bitrate_bps,
+ int delay_compensation, downmix_func downmix
+#ifndef DISABLE_FLOAT_API
+ , float *subframe_mem
+#endif
+ )
+{
+#ifndef DISABLE_FLOAT_API
+ if (variable_duration == OPUS_FRAMESIZE_VARIABLE && frame_size >= Fs/200)
+ {
+ int LM = 3;
+ LM = optimize_framesize(analysis_pcm, frame_size, C, Fs, bitrate_bps,
+ 0, subframe_mem, delay_compensation, downmix);
+ while ((Fs/400<<LM)>frame_size)
+ LM--;
+ frame_size = (Fs/400<<LM);
+ } else
+#endif
+ {
+ frame_size = frame_size_select(frame_size, variable_duration, Fs);
+ }
+ if (frame_size<0)
+ return -1;
+ return frame_size;
+}
+
+opus_val16 compute_stereo_width(const opus_val16 *pcm, int frame_size, opus_int32 Fs, StereoWidthState *mem)
+{
+ opus_val16 corr;
+ opus_val16 ldiff;
+ opus_val16 width;
+ opus_val32 xx, xy, yy;
+ opus_val16 sqrt_xx, sqrt_yy;
+ opus_val16 qrrt_xx, qrrt_yy;
+ int frame_rate;
+ int i;
+ opus_val16 short_alpha;
+
+ frame_rate = Fs/frame_size;
+ short_alpha = Q15ONE - 25*Q15ONE/IMAX(50,frame_rate);
+ xx=xy=yy=0;
+ for (i=0;i<frame_size;i+=4)
+ {
+ opus_val32 pxx=0;
+ opus_val32 pxy=0;
+ opus_val32 pyy=0;
+ opus_val16 x, y;
+ x = pcm[2*i];
+ y = pcm[2*i+1];
+ pxx = SHR32(MULT16_16(x,x),2);
+ pxy = SHR32(MULT16_16(x,y),2);
+ pyy = SHR32(MULT16_16(y,y),2);
+ x = pcm[2*i+2];
+ y = pcm[2*i+3];
+ pxx += SHR32(MULT16_16(x,x),2);
+ pxy += SHR32(MULT16_16(x,y),2);
+ pyy += SHR32(MULT16_16(y,y),2);
+ x = pcm[2*i+4];
+ y = pcm[2*i+5];
+ pxx += SHR32(MULT16_16(x,x),2);
+ pxy += SHR32(MULT16_16(x,y),2);
+ pyy += SHR32(MULT16_16(y,y),2);
+ x = pcm[2*i+6];
+ y = pcm[2*i+7];
+ pxx += SHR32(MULT16_16(x,x),2);
+ pxy += SHR32(MULT16_16(x,y),2);
+ pyy += SHR32(MULT16_16(y,y),2);
+
+ xx += SHR32(pxx, 10);
+ xy += SHR32(pxy, 10);
+ yy += SHR32(pyy, 10);
+ }
+ mem->XX += MULT16_32_Q15(short_alpha, xx-mem->XX);
+ mem->XY += MULT16_32_Q15(short_alpha, xy-mem->XY);
+ mem->YY += MULT16_32_Q15(short_alpha, yy-mem->YY);
+ mem->XX = MAX32(0, mem->XX);
+ mem->XY = MAX32(0, mem->XY);
+ mem->YY = MAX32(0, mem->YY);
+ if (MAX32(mem->XX, mem->YY)>QCONST16(8e-4f, 18))
+ {
+ sqrt_xx = celt_sqrt(mem->XX);
+ sqrt_yy = celt_sqrt(mem->YY);
+ qrrt_xx = celt_sqrt(sqrt_xx);
+ qrrt_yy = celt_sqrt(sqrt_yy);
+ /* Inter-channel correlation */
+ mem->XY = MIN32(mem->XY, sqrt_xx*sqrt_yy);
+ corr = SHR32(frac_div32(mem->XY,EPSILON+MULT16_16(sqrt_xx,sqrt_yy)),16);
+ /* Approximate loudness difference */
+ ldiff = Q15ONE*ABS16(qrrt_xx-qrrt_yy)/(EPSILON+qrrt_xx+qrrt_yy);
+ width = MULT16_16_Q15(celt_sqrt(QCONST32(1.f,30)-MULT16_16(corr,corr)), ldiff);
+ /* Smoothing over one second */
+ mem->smoothed_width += (width-mem->smoothed_width)/frame_rate;
+ /* Peak follower */
+ mem->max_follower = MAX16(mem->max_follower-QCONST16(.02f,15)/frame_rate, mem->smoothed_width);
+ } else {
+ width = 0;
+ corr=Q15ONE;
+ ldiff=0;
+ }
+ /*printf("%f %f %f %f %f ", corr/(float)Q15ONE, ldiff/(float)Q15ONE, width/(float)Q15ONE, mem->smoothed_width/(float)Q15ONE, mem->max_follower/(float)Q15ONE);*/
+ return EXTRACT16(MIN32(Q15ONE,20*mem->max_follower));
+}
+
+opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
+ unsigned char *data, opus_int32 out_data_bytes, int lsb_depth,
+ const void *analysis_pcm, opus_int32 analysis_size, int c1, int c2, int analysis_channels, downmix_func downmix)
+{
+ void *silk_enc;
+ CELTEncoder *celt_enc;
+ int i;
+ int ret=0;
+ opus_int32 nBytes;
+ ec_enc enc;
+ int bytes_target;
+ int prefill=0;
+ int start_band = 0;
+ int redundancy = 0;
+ int redundancy_bytes = 0; /* Number of bytes to use for redundancy frame */
+ int celt_to_silk = 0;
+ VARDECL(opus_val16, pcm_buf);
+ int nb_compr_bytes;
+ int to_celt = 0;
+ opus_uint32 redundant_rng = 0;
+ int cutoff_Hz, hp_freq_smth1;
+ int voice_est; /* Probability of voice in Q7 */
+ opus_int32 equiv_rate;
+ int delay_compensation;
+ int frame_rate;
+ opus_int32 max_rate; /* Max bitrate we're allowed to use */
+ int curr_bandwidth;
+ opus_val16 HB_gain;
+ opus_int32 max_data_bytes; /* Max number of bytes we're allowed to use */
+ int total_buffer;
+ opus_val16 stereo_width;
+ const CELTMode *celt_mode;
+ AnalysisInfo analysis_info;
+ int analysis_read_pos_bak=-1;
+ int analysis_read_subframe_bak=-1;
+ VARDECL(opus_val16, tmp_prefill);
+
+ ALLOC_STACK;
+
+ max_data_bytes = IMIN(1276, out_data_bytes);
+
+ st->rangeFinal = 0;
+ if ((!st->variable_duration && 400*frame_size != st->Fs && 200*frame_size != st->Fs && 100*frame_size != st->Fs &&
+ 50*frame_size != st->Fs && 25*frame_size != st->Fs && 50*frame_size != 3*st->Fs)
+ || (400*frame_size < st->Fs)
+ || max_data_bytes<=0
+ )
+ {
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ }
+ silk_enc = (char*)st+st->silk_enc_offset;
+ celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset);
+ if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ delay_compensation = 0;
+ else
+ delay_compensation = st->delay_compensation;
+
+ lsb_depth = IMIN(lsb_depth, st->lsb_depth);
+
+ analysis_info.valid = 0;
+ celt_encoder_ctl(celt_enc, CELT_GET_MODE(&celt_mode));
+#ifndef DISABLE_FLOAT_API
+#ifdef OPUS_FIXED_POINT
+ if (st->silk_mode.complexity >= 10 && st->Fs==48000)
+#else
+ if (st->silk_mode.complexity >= 7 && st->Fs==48000)
+#endif
+ {
+ analysis_read_pos_bak = st->analysis.read_pos;
+ analysis_read_subframe_bak = st->analysis.read_subframe;
+ run_analysis(&st->analysis, celt_mode, analysis_pcm, analysis_size, frame_size,
+ c1, c2, analysis_channels, st->Fs,
+ lsb_depth, downmix, &analysis_info);
+ }
+#endif
+
+ st->voice_ratio = -1;
+
+#ifndef DISABLE_FLOAT_API
+ st->detected_bandwidth = 0;
+ if (analysis_info.valid)
+ {
+ int analysis_bandwidth;
+ if (st->signal_type == OPUS_AUTO)
+ st->voice_ratio = (int)floor(.5+100*(1-analysis_info.music_prob));
+
+ analysis_bandwidth = analysis_info.bandwidth;
+ if (analysis_bandwidth<=12)
+ st->detected_bandwidth = OPUS_BANDWIDTH_NARROWBAND;
+ else if (analysis_bandwidth<=14)
+ st->detected_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND;
+ else if (analysis_bandwidth<=16)
+ st->detected_bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+ else if (analysis_bandwidth<=18)
+ st->detected_bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND;
+ else
+ st->detected_bandwidth = OPUS_BANDWIDTH_FULLBAND;
+ }
+#endif
+
+ if (st->channels==2 && st->force_channels!=1)
+ stereo_width = compute_stereo_width(pcm, frame_size, st->Fs, &st->width_mem);
+ else
+ stereo_width = 0;
+ total_buffer = delay_compensation;
+ st->bitrate_bps = user_bitrate_to_bitrate(st, frame_size, max_data_bytes);
+
+ frame_rate = st->Fs/frame_size;
+ if (max_data_bytes<3 || st->bitrate_bps < 3*frame_rate*8
+ || (frame_rate<50 && (max_data_bytes*frame_rate<300 || st->bitrate_bps < 2400)))
+ {
+ /*If the space is too low to do something useful, emit 'PLC' frames.*/
+ int tocmode = st->mode;
+ int bw = st->bandwidth == 0 ? OPUS_BANDWIDTH_NARROWBAND : st->bandwidth;
+ if (tocmode==0)
+ tocmode = MODE_SILK_ONLY;
+ if (frame_rate>100)
+ tocmode = MODE_CELT_ONLY;
+ if (frame_rate < 50)
+ tocmode = MODE_SILK_ONLY;
+ if(tocmode==MODE_SILK_ONLY&&bw>OPUS_BANDWIDTH_WIDEBAND)
+ bw=OPUS_BANDWIDTH_WIDEBAND;
+ else if (tocmode==MODE_CELT_ONLY&&bw==OPUS_BANDWIDTH_MEDIUMBAND)
+ bw=OPUS_BANDWIDTH_NARROWBAND;
+ else if (bw<=OPUS_BANDWIDTH_SUPERWIDEBAND)
+ bw=OPUS_BANDWIDTH_SUPERWIDEBAND;
+ data[0] = gen_toc(tocmode, frame_rate, bw, st->stream_channels);
+ RESTORE_STACK;
+ return 1;
+ }
+ if (!st->use_vbr)
+ {
+ int cbrBytes;
+ cbrBytes = IMIN( (st->bitrate_bps + 4*frame_rate)/(8*frame_rate) , max_data_bytes);
+ st->bitrate_bps = cbrBytes * (8*frame_rate);
+ max_data_bytes = cbrBytes;
+ }
+ max_rate = frame_rate*max_data_bytes*8;
+
+ /* Equivalent 20-ms rate for mode/channel/bandwidth decisions */
+ equiv_rate = st->bitrate_bps - (40*st->channels+20)*(st->Fs/frame_size - 50);
+
+ if (st->signal_type == OPUS_SIGNAL_VOICE)
+ voice_est = 127;
+ else if (st->signal_type == OPUS_SIGNAL_MUSIC)
+ voice_est = 0;
+ else if (st->voice_ratio >= 0)
+ {
+ voice_est = st->voice_ratio*327>>8;
+ /* For AUDIO, never be more than 90% confident of having speech */
+ if (st->application == OPUS_APPLICATION_AUDIO)
+ voice_est = IMIN(voice_est, 115);
+ } else if (st->application == OPUS_APPLICATION_VOIP)
+ voice_est = 115;
+ else
+ voice_est = 48;
+
+ if (st->force_channels!=OPUS_AUTO && st->channels == 2)
+ {
+ st->stream_channels = st->force_channels;
+ } else {
+#ifdef FUZZING
+ /* Random mono/stereo decision */
+ if (st->channels == 2 && (rand()&0x1F)==0)
+ st->stream_channels = 3-st->stream_channels;
+#else
+ /* Rate-dependent mono-stereo decision */
+ if (st->channels == 2)
+ {
+ opus_int32 stereo_threshold;
+ stereo_threshold = stereo_music_threshold + ((voice_est*voice_est*(stereo_voice_threshold-stereo_music_threshold))>>14);
+ if (st->stream_channels == 2)
+ stereo_threshold -= 1000;
+ else
+ stereo_threshold += 1000;
+ st->stream_channels = (equiv_rate > stereo_threshold) ? 2 : 1;
+ } else {
+ st->stream_channels = st->channels;
+ }
+#endif
+ }
+ equiv_rate = st->bitrate_bps - (40*st->stream_channels+20)*(st->Fs/frame_size - 50);
+
+ /* Mode selection depending on application and signal type */
+ if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ {
+ st->mode = MODE_CELT_ONLY;
+ } else if (st->user_forced_mode == OPUS_AUTO)
+ {
+#ifdef FUZZING
+ /* Random mode switching */
+ if ((rand()&0xF)==0)
+ {
+ if ((rand()&0x1)==0)
+ st->mode = MODE_CELT_ONLY;
+ else
+ st->mode = MODE_SILK_ONLY;
+ } else {
+ if (st->prev_mode==MODE_CELT_ONLY)
+ st->mode = MODE_CELT_ONLY;
+ else
+ st->mode = MODE_SILK_ONLY;
+ }
+#else
+ opus_int32 mode_voice, mode_music;
+ opus_int32 threshold;
+
+ /* Interpolate based on stereo width */
+ mode_voice = (opus_int32)(MULT16_32_Q15(Q15ONE-stereo_width,mode_thresholds[0][0])
+ + MULT16_32_Q15(stereo_width,mode_thresholds[1][0]));
+ mode_music = (opus_int32)(MULT16_32_Q15(Q15ONE-stereo_width,mode_thresholds[1][1])
+ + MULT16_32_Q15(stereo_width,mode_thresholds[1][1]));
+ /* Interpolate based on speech/music probability */
+ threshold = mode_music + ((voice_est*voice_est*(mode_voice-mode_music))>>14);
+ /* Bias towards SILK for VoIP because of some useful features */
+ if (st->application == OPUS_APPLICATION_VOIP)
+ threshold += 8000;
+
+ /*printf("%f %d\n", stereo_width/(float)Q15ONE, threshold);*/
+ /* Hysteresis */
+ if (st->prev_mode == MODE_CELT_ONLY)
+ threshold -= 4000;
+ else if (st->prev_mode>0)
+ threshold += 4000;
+
+ st->mode = (equiv_rate >= threshold) ? MODE_CELT_ONLY: MODE_SILK_ONLY;
+
+ /* When FEC is enabled and there's enough packet loss, use SILK */
+ if (st->silk_mode.useInBandFEC && st->silk_mode.packetLossPercentage > (128-voice_est)>>4)
+ st->mode = MODE_SILK_ONLY;
+ /* When encoding voice and DTX is enabled, set the encoder to SILK mode (at least for now) */
+ if (st->silk_mode.useDTX && voice_est > 100)
+ st->mode = MODE_SILK_ONLY;
+#endif
+ } else {
+ st->mode = st->user_forced_mode;
+ }
+
+ /* Override the chosen mode to make sure we meet the requested frame size */
+ if (st->mode != MODE_CELT_ONLY && frame_size < st->Fs/100)
+ st->mode = MODE_CELT_ONLY;
+ if (st->lfe)
+ st->mode = MODE_CELT_ONLY;
+ /* If max_data_bytes represents less than 8 kb/s, switch to CELT-only mode */
+ if (max_data_bytes < (frame_rate > 50 ? 12000 : 8000)*frame_size / (st->Fs * 8))
+ st->mode = MODE_CELT_ONLY;
+
+ if (st->stream_channels == 1 && st->prev_channels ==2 && st->silk_mode.toMono==0
+ && st->mode != MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY)
+ {
+ /* Delay stereo->mono transition by two frames so that SILK can do a smooth downmix */
+ st->silk_mode.toMono = 1;
+ st->stream_channels = 2;
+ } else {
+ st->silk_mode.toMono = 0;
+ }
+
+ if (st->prev_mode > 0 &&
+ ((st->mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY) ||
+ (st->mode == MODE_CELT_ONLY && st->prev_mode != MODE_CELT_ONLY)))
+ {
+ redundancy = 1;
+ celt_to_silk = (st->mode != MODE_CELT_ONLY);
+ if (!celt_to_silk)
+ {
+ /* Switch to SILK/hybrid if frame size is 10 ms or more*/
+ if (frame_size >= st->Fs/100)
+ {
+ st->mode = st->prev_mode;
+ to_celt = 1;
+ } else {
+ redundancy=0;
+ }
+ }
+ }
+ /* For the first frame at a new SILK bandwidth */
+ if (st->silk_bw_switch)
+ {
+ redundancy = 1;
+ celt_to_silk = 1;
+ st->silk_bw_switch = 0;
+ prefill=1;
+ }
+
+ if (redundancy)
+ {
+ /* Fair share of the max size allowed */
+ redundancy_bytes = IMIN(257, max_data_bytes*(opus_int32)(st->Fs/200)/(frame_size+st->Fs/200));
+ /* For VBR, target the actual bitrate (subject to the limit above) */
+ if (st->use_vbr)
+ redundancy_bytes = IMIN(redundancy_bytes, st->bitrate_bps/1600);
+ }
+
+ if (st->mode != MODE_CELT_ONLY && st->prev_mode == MODE_CELT_ONLY)
+ {
+ silk_EncControlStruct dummy;
+ silk_InitEncoder( silk_enc, st->arch, &dummy);
+ prefill=1;
+ }
+
+ /* Automatic (rate-dependent) bandwidth selection */
+ if (st->mode == MODE_CELT_ONLY || st->first || st->silk_mode.allowBandwidthSwitch)
+ {
+ const opus_int32 *voice_bandwidth_thresholds, *music_bandwidth_thresholds;
+ opus_int32 bandwidth_thresholds[8];
+ int bandwidth = OPUS_BANDWIDTH_FULLBAND;
+ opus_int32 equiv_rate2;
+
+ equiv_rate2 = equiv_rate;
+ if (st->mode != MODE_CELT_ONLY)
+ {
+ /* Adjust the threshold +/- 10% depending on complexity */
+ equiv_rate2 = equiv_rate2 * (45+st->silk_mode.complexity)/50;
+ /* CBR is less efficient by ~1 kb/s */
+ if (!st->use_vbr)
+ equiv_rate2 -= 1000;
+ }
+ if (st->channels==2 && st->force_channels!=1)
+ {
+ voice_bandwidth_thresholds = stereo_voice_bandwidth_thresholds;
+ music_bandwidth_thresholds = stereo_music_bandwidth_thresholds;
+ } else {
+ voice_bandwidth_thresholds = mono_voice_bandwidth_thresholds;
+ music_bandwidth_thresholds = mono_music_bandwidth_thresholds;
+ }
+ /* Interpolate bandwidth thresholds depending on voice estimation */
+ for (i=0;i<8;i++)
+ {
+ bandwidth_thresholds[i] = music_bandwidth_thresholds[i]
+ + ((voice_est*voice_est*(voice_bandwidth_thresholds[i]-music_bandwidth_thresholds[i]))>>14);
+ }
+ do {
+ int threshold, hysteresis;
+ threshold = bandwidth_thresholds[2*(bandwidth-OPUS_BANDWIDTH_MEDIUMBAND)];
+ hysteresis = bandwidth_thresholds[2*(bandwidth-OPUS_BANDWIDTH_MEDIUMBAND)+1];
+ if (!st->first)
+ {
+ if (st->bandwidth >= bandwidth)
+ threshold -= hysteresis;
+ else
+ threshold += hysteresis;
+ }
+ if (equiv_rate2 >= threshold)
+ break;
+ } while (--bandwidth>OPUS_BANDWIDTH_NARROWBAND);
+ st->bandwidth = bandwidth;
+ /* Prevents any transition to SWB/FB until the SILK layer has fully
+ switched to WB mode and turned the variable LP filter off */
+ if (!st->first && st->mode != MODE_CELT_ONLY && !st->silk_mode.inWBmodeWithoutVariableLP && st->bandwidth > OPUS_BANDWIDTH_WIDEBAND)
+ st->bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+ }
+
+ if (st->bandwidth>st->max_bandwidth)
+ st->bandwidth = st->max_bandwidth;
+
+ if (st->user_bandwidth != OPUS_AUTO)
+ st->bandwidth = st->user_bandwidth;
+
+ /* This prevents us from using hybrid at unsafe CBR/max rates */
+ if (st->mode != MODE_CELT_ONLY && max_rate < 15000)
+ {
+ st->bandwidth = IMIN(st->bandwidth, OPUS_BANDWIDTH_WIDEBAND);
+ }
+
+ /* Prevents Opus from wasting bits on frequencies that are above
+ the Nyquist rate of the input signal */
+ if (st->Fs <= 24000 && st->bandwidth > OPUS_BANDWIDTH_SUPERWIDEBAND)
+ st->bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND;
+ if (st->Fs <= 16000 && st->bandwidth > OPUS_BANDWIDTH_WIDEBAND)
+ st->bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+ if (st->Fs <= 12000 && st->bandwidth > OPUS_BANDWIDTH_MEDIUMBAND)
+ st->bandwidth = OPUS_BANDWIDTH_MEDIUMBAND;
+ if (st->Fs <= 8000 && st->bandwidth > OPUS_BANDWIDTH_NARROWBAND)
+ st->bandwidth = OPUS_BANDWIDTH_NARROWBAND;
+#ifndef DISABLE_FLOAT_API
+ /* Use detected bandwidth to reduce the encoded bandwidth. */
+ if (st->detected_bandwidth && st->user_bandwidth == OPUS_AUTO)
+ {
+ int min_detected_bandwidth;
+ /* Makes bandwidth detection more conservative just in case the detector
+ gets it wrong when we could have coded a high bandwidth transparently.
+ When operating in SILK/hybrid mode, we don't go below wideband to avoid
+ more complicated switches that require redundancy. */
+ if (equiv_rate <= 18000*st->stream_channels && st->mode == MODE_CELT_ONLY)
+ min_detected_bandwidth = OPUS_BANDWIDTH_NARROWBAND;
+ else if (equiv_rate <= 24000*st->stream_channels && st->mode == MODE_CELT_ONLY)
+ min_detected_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND;
+ else if (equiv_rate <= 30000*st->stream_channels)
+ min_detected_bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+ else if (equiv_rate <= 44000*st->stream_channels)
+ min_detected_bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND;
+ else
+ min_detected_bandwidth = OPUS_BANDWIDTH_FULLBAND;
+
+ st->detected_bandwidth = IMAX(st->detected_bandwidth, min_detected_bandwidth);
+ st->bandwidth = IMIN(st->bandwidth, st->detected_bandwidth);
+ }
+#endif
+ celt_encoder_ctl(celt_enc, OPUS_SET_LSB_DEPTH(lsb_depth));
+
+ /* CELT mode doesn't support mediumband, use wideband instead */
+ if (st->mode == MODE_CELT_ONLY && st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND)
+ st->bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+ if (st->lfe)
+ st->bandwidth = OPUS_BANDWIDTH_NARROWBAND;
+
+ /* Can't support higher than wideband for >20 ms frames */
+ if (frame_size > st->Fs/50 && (st->mode == MODE_CELT_ONLY || st->bandwidth > OPUS_BANDWIDTH_WIDEBAND))
+ {
+ VARDECL(unsigned char, tmp_data);
+ int nb_frames;
+ int bak_mode, bak_bandwidth, bak_channels, bak_to_mono;
+ VARDECL(OpusRepacketizer, rp);
+ opus_int32 bytes_per_frame;
+ opus_int32 repacketize_len;
+
+#ifndef DISABLE_FLOAT_API
+ if (analysis_read_pos_bak!= -1)
+ {
+ st->analysis.read_pos = analysis_read_pos_bak;
+ st->analysis.read_subframe = analysis_read_subframe_bak;
+ }
+#endif
+
+ nb_frames = frame_size > st->Fs/25 ? 3 : 2;
+ bytes_per_frame = IMIN(1276,(out_data_bytes-3)/nb_frames);
+
+ ALLOC(tmp_data, nb_frames*bytes_per_frame, unsigned char);
+
+ ALLOC(rp, 1, OpusRepacketizer);
+ opus_repacketizer_init(rp);
+
+ bak_mode = st->user_forced_mode;
+ bak_bandwidth = st->user_bandwidth;
+ bak_channels = st->force_channels;
+
+ st->user_forced_mode = st->mode;
+ st->user_bandwidth = st->bandwidth;
+ st->force_channels = st->stream_channels;
+ bak_to_mono = st->silk_mode.toMono;
+
+ if (bak_to_mono)
+ st->force_channels = 1;
+ else
+ st->prev_channels = st->stream_channels;
+ for (i=0;i<nb_frames;i++)
+ {
+ int tmp_len;
+ st->silk_mode.toMono = 0;
+ /* When switching from SILK/Hybrid to CELT, only ask for a switch at the last frame */
+ if (to_celt && i==nb_frames-1)
+ st->user_forced_mode = MODE_CELT_ONLY;
+ tmp_len = opus_encode_native(st, pcm+i*(st->channels*st->Fs/50), st->Fs/50,
+ tmp_data+i*bytes_per_frame, bytes_per_frame, lsb_depth,
+ NULL, 0, c1, c2, analysis_channels, downmix);
+ if (tmp_len<0)
+ {
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ ret = opus_repacketizer_cat(rp, tmp_data+i*bytes_per_frame, tmp_len);
+ if (ret<0)
+ {
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ }
+ if (st->use_vbr)
+ repacketize_len = out_data_bytes;
+ else
+ repacketize_len = IMIN(3*st->bitrate_bps/(3*8*50/nb_frames), out_data_bytes);
+ ret = opus_repacketizer_out_range_impl(rp, 0, nb_frames, data, repacketize_len, 0, !st->use_vbr);
+ if (ret<0)
+ {
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ st->user_forced_mode = bak_mode;
+ st->user_bandwidth = bak_bandwidth;
+ st->force_channels = bak_channels;
+ st->silk_mode.toMono = bak_to_mono;
+ RESTORE_STACK;
+ return ret;
+ }
+ curr_bandwidth = st->bandwidth;
+
+ /* Chooses the appropriate mode for speech
+ *NEVER* switch to/from CELT-only mode here as this will invalidate some assumptions */
+ if (st->mode == MODE_SILK_ONLY && curr_bandwidth > OPUS_BANDWIDTH_WIDEBAND)
+ st->mode = MODE_HYBRID;
+ if (st->mode == MODE_HYBRID && curr_bandwidth <= OPUS_BANDWIDTH_WIDEBAND)
+ st->mode = MODE_SILK_ONLY;
+
+ /* printf("%d %d %d %d\n", st->bitrate_bps, st->stream_channels, st->mode, curr_bandwidth); */
+ bytes_target = IMIN(max_data_bytes-redundancy_bytes, st->bitrate_bps * frame_size / (st->Fs * 8)) - 1;
+
+ data += 1;
+
+ ec_enc_init(&enc, data, max_data_bytes-1);
+
+ ALLOC(pcm_buf, (total_buffer+frame_size)*st->channels, opus_val16);
+ for (i=0;i<total_buffer*st->channels;i++)
+ pcm_buf[i] = st->delay_buffer[(st->encoder_buffer-total_buffer)*st->channels+i];
+
+ if (st->mode == MODE_CELT_ONLY)
+ hp_freq_smth1 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 );
+ else
+ hp_freq_smth1 = ((silk_encoder*)silk_enc)->state_Fxx[0].sCmn.variable_HP_smth1_Q15;
+
+ st->variable_HP_smth2_Q15 = silk_SMLAWB( st->variable_HP_smth2_Q15,
+ hp_freq_smth1 - st->variable_HP_smth2_Q15, SILK_FIX_CONST( VARIABLE_HP_SMTH_COEF2, 16 ) );
+
+ /* convert from log scale to Hertz */
+ cutoff_Hz = silk_log2lin( silk_RSHIFT( st->variable_HP_smth2_Q15, 8 ) );
+
+ if (st->application == OPUS_APPLICATION_VOIP)
+ {
+ hp_cutoff(pcm, cutoff_Hz, &pcm_buf[total_buffer*st->channels], st->hp_mem, frame_size, st->channels, st->Fs);
+ } else {
+ dc_reject(pcm, 3, &pcm_buf[total_buffer*st->channels], st->hp_mem, frame_size, st->channels, st->Fs);
+ }
+
+
+
+ /* SILK processing */
+ HB_gain = Q15ONE;
+ if (st->mode != MODE_CELT_ONLY)
+ {
+ opus_int32 total_bitRate, celt_rate;
+#ifdef OPUS_FIXED_POINT
+ const opus_int16 *pcm_silk;
+#else
+ VARDECL(opus_int16, pcm_silk);
+ ALLOC(pcm_silk, st->channels*frame_size, opus_int16);
+#endif
+
+ /* Distribute bits between SILK and CELT */
+ total_bitRate = 8 * bytes_target * frame_rate;
+ if( st->mode == MODE_HYBRID ) {
+ int HB_gain_ref;
+ /* Base rate for SILK */
+ st->silk_mode.bitRate = st->stream_channels * ( 5000 + 1000 * ( st->Fs == 100 * frame_size ) );
+ if( curr_bandwidth == OPUS_BANDWIDTH_SUPERWIDEBAND ) {
+ /* SILK gets 2/3 of the remaining bits */
+ st->silk_mode.bitRate += ( total_bitRate - st->silk_mode.bitRate ) * 2 / 3;
+ } else { /* FULLBAND */
+ /* SILK gets 3/5 of the remaining bits */
+ st->silk_mode.bitRate += ( total_bitRate - st->silk_mode.bitRate ) * 3 / 5;
+ }
+ /* Don't let SILK use more than 80% */
+ if( st->silk_mode.bitRate > total_bitRate * 4/5 ) {
+ st->silk_mode.bitRate = total_bitRate * 4/5;
+ }
+ if (!st->energy_masking)
+ {
+ /* Increasingly attenuate high band when it gets allocated fewer bits */
+ celt_rate = total_bitRate - st->silk_mode.bitRate;
+ HB_gain_ref = (curr_bandwidth == OPUS_BANDWIDTH_SUPERWIDEBAND) ? 3000 : 3600;
+ HB_gain = SHL32((opus_val32)celt_rate, 9) / SHR32((opus_val32)celt_rate + st->stream_channels * HB_gain_ref, 6);
+ HB_gain = HB_gain < Q15ONE*6/7 ? HB_gain + Q15ONE/7 : Q15ONE;
+ }
+ } else {
+ /* SILK gets all bits */
+ st->silk_mode.bitRate = total_bitRate;
+ }
+
+ /* Surround masking for SILK */
+ if (st->energy_masking && st->use_vbr && !st->lfe)
+ {
+ opus_val32 mask_sum=0;
+ opus_val16 masking_depth;
+ opus_int32 rate_offset;
+ int c;
+ int end = 17;
+ opus_int16 srate = 16000;
+ if (st->bandwidth == OPUS_BANDWIDTH_NARROWBAND)
+ {
+ end = 13;
+ srate = 8000;
+ } else if (st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND)
+ {
+ end = 15;
+ srate = 12000;
+ }
+ for (c=0;c<st->channels;c++)
+ {
+ for(i=0;i<end;i++)
+ {
+ opus_val16 mask;
+ mask = MAX16(MIN16(st->energy_masking[21*c+i],
+ QCONST16(.5f, DB_SHIFT)), -QCONST16(2.0f, DB_SHIFT));
+ if (mask > 0)
+ mask = HALF16(mask);
+ mask_sum += mask;
+ }
+ }
+ /* Conservative rate reduction, we cut the masking in half */
+ masking_depth = mask_sum / end*st->channels;
+ masking_depth += QCONST16(.2f, DB_SHIFT);
+ rate_offset = (opus_int32)PSHR32(MULT16_16(srate, masking_depth), DB_SHIFT);
+ rate_offset = MAX32(rate_offset, -2*st->silk_mode.bitRate/3);
+ /* Split the rate change between the SILK and CELT part for hybrid. */
+ if (st->bandwidth==OPUS_BANDWIDTH_SUPERWIDEBAND || st->bandwidth==OPUS_BANDWIDTH_FULLBAND)
+ st->silk_mode.bitRate += 3*rate_offset/5;
+ else
+ st->silk_mode.bitRate += rate_offset;
+ bytes_target += rate_offset * frame_size / (8 * st->Fs);
+ }
+
+ st->silk_mode.payloadSize_ms = 1000 * frame_size / st->Fs;
+ st->silk_mode.nChannelsAPI = st->channels;
+ st->silk_mode.nChannelsInternal = st->stream_channels;
+ if (curr_bandwidth == OPUS_BANDWIDTH_NARROWBAND) {
+ st->silk_mode.desiredInternalSampleRate = 8000;
+ } else if (curr_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) {
+ st->silk_mode.desiredInternalSampleRate = 12000;
+ } else {
+ silk_assert( st->mode == MODE_HYBRID || curr_bandwidth == OPUS_BANDWIDTH_WIDEBAND );
+ st->silk_mode.desiredInternalSampleRate = 16000;
+ }
+ if( st->mode == MODE_HYBRID ) {
+ /* Don't allow bandwidth reduction at lowest bitrates in hybrid mode */
+ st->silk_mode.minInternalSampleRate = 16000;
+ } else {
+ st->silk_mode.minInternalSampleRate = 8000;
+ }
+
+ if (st->mode == MODE_SILK_ONLY)
+ {
+ opus_int32 effective_max_rate = max_rate;
+ st->silk_mode.maxInternalSampleRate = 16000;
+ if (frame_rate > 50)
+ effective_max_rate = effective_max_rate*2/3;
+ if (effective_max_rate < 13000)
+ {
+ st->silk_mode.maxInternalSampleRate = 12000;
+ st->silk_mode.desiredInternalSampleRate = IMIN(12000, st->silk_mode.desiredInternalSampleRate);
+ }
+ if (effective_max_rate < 9600)
+ {
+ st->silk_mode.maxInternalSampleRate = 8000;
+ st->silk_mode.desiredInternalSampleRate = IMIN(8000, st->silk_mode.desiredInternalSampleRate);
+ }
+ } else {
+ st->silk_mode.maxInternalSampleRate = 16000;
+ }
+
+ st->silk_mode.useCBR = !st->use_vbr;
+
+ /* Call SILK encoder for the low band */
+ nBytes = IMIN(1275, max_data_bytes-1-redundancy_bytes);
+
+ st->silk_mode.maxBits = nBytes*8;
+ /* Only allow up to 90% of the bits for hybrid mode*/
+ if (st->mode == MODE_HYBRID)
+ st->silk_mode.maxBits = (opus_int32)st->silk_mode.maxBits*9/10;
+ if (st->silk_mode.useCBR)
+ {
+ st->silk_mode.maxBits = (st->silk_mode.bitRate * frame_size / (st->Fs * 8))*8;
+ /* Reduce the initial target to make it easier to reach the CBR rate */
+ st->silk_mode.bitRate = IMAX(1, st->silk_mode.bitRate-2000);
+ }
+
+ if (prefill)
+ {
+ opus_int32 zero=0;
+ int prefill_offset;
+ /* Use a smooth onset for the SILK prefill to avoid the encoder trying to encode
+ a discontinuity. The exact location is what we need to avoid leaving any "gap"
+ in the audio when mixing with the redundant CELT frame. Here we can afford to
+ overwrite st->delay_buffer because the only thing that uses it before it gets
+ rewritten is tmp_prefill[] and even then only the part after the ramp really
+ gets used (rather than sent to the encoder and discarded) */
+ prefill_offset = st->channels*(st->encoder_buffer-st->delay_compensation-st->Fs/400);
+ gain_fade(st->delay_buffer+prefill_offset, st->delay_buffer+prefill_offset,
+ 0, Q15ONE, celt_mode->overlap, st->Fs/400, st->channels, celt_mode->window, st->Fs);
+ for(i=0;i<prefill_offset;i++)
+ st->delay_buffer[i]=0;
+#ifdef OPUS_FIXED_POINT
+ pcm_silk = st->delay_buffer;
+#else
+ for (i=0;i<st->encoder_buffer*st->channels;i++)
+ pcm_silk[i] = FLOAT2INT16(st->delay_buffer[i]);
+#endif
+ silk_Encode( silk_enc, &st->silk_mode, pcm_silk, st->encoder_buffer, NULL, &zero, 1 );
+ }
+
+#ifdef OPUS_FIXED_POINT
+ pcm_silk = pcm_buf+total_buffer*st->channels;
+#else
+ for (i=0;i<frame_size*st->channels;i++)
+ pcm_silk[i] = FLOAT2INT16(pcm_buf[total_buffer*st->channels + i]);
+#endif
+ ret = silk_Encode( silk_enc, &st->silk_mode, pcm_silk, frame_size, &enc, &nBytes, 0 );
+ if( ret ) {
+ /*fprintf (stderr, "SILK encode error: %d\n", ret);*/
+ /* Handle error */
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ if (nBytes==0)
+ {
+ st->rangeFinal = 0;
+ data[-1] = gen_toc(st->mode, st->Fs/frame_size, curr_bandwidth, st->stream_channels);
+ RESTORE_STACK;
+ return 1;
+ }
+ /* Extract SILK internal bandwidth for signaling in first byte */
+ if( st->mode == MODE_SILK_ONLY ) {
+ if( st->silk_mode.internalSampleRate == 8000 ) {
+ curr_bandwidth = OPUS_BANDWIDTH_NARROWBAND;
+ } else if( st->silk_mode.internalSampleRate == 12000 ) {
+ curr_bandwidth = OPUS_BANDWIDTH_MEDIUMBAND;
+ } else if( st->silk_mode.internalSampleRate == 16000 ) {
+ curr_bandwidth = OPUS_BANDWIDTH_WIDEBAND;
+ }
+ } else {
+ silk_assert( st->silk_mode.internalSampleRate == 16000 );
+ }
+
+ st->silk_mode.opusCanSwitch = st->silk_mode.switchReady;
+ /* FIXME: How do we allocate the redundancy for CBR? */
+ if (st->silk_mode.opusCanSwitch)
+ {
+ redundancy = 1;
+ celt_to_silk = 0;
+ st->silk_bw_switch = 1;
+ }
+ }
+
+ /* CELT processing */
+ {
+ int endband=21;
+
+ switch(curr_bandwidth)
+ {
+ case OPUS_BANDWIDTH_NARROWBAND:
+ endband = 13;
+ break;
+ case OPUS_BANDWIDTH_MEDIUMBAND:
+ case OPUS_BANDWIDTH_WIDEBAND:
+ endband = 17;
+ break;
+ case OPUS_BANDWIDTH_SUPERWIDEBAND:
+ endband = 19;
+ break;
+ case OPUS_BANDWIDTH_FULLBAND:
+ endband = 21;
+ break;
+ }
+ celt_encoder_ctl(celt_enc, CELT_SET_END_BAND(endband));
+ celt_encoder_ctl(celt_enc, CELT_SET_CHANNELS(st->stream_channels));
+ }
+ celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(OPUS_BITRATE_MAX));
+ if (st->mode != MODE_SILK_ONLY)
+ {
+ opus_val32 celt_pred=2;
+ celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0));
+ /* We may still decide to disable prediction later */
+ if (st->silk_mode.reducedDependency)
+ celt_pred = 0;
+ celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(celt_pred));
+
+ if (st->mode == MODE_HYBRID)
+ {
+ int len;
+
+ len = (ec_tell(&enc)+7)>>3;
+ if (redundancy)
+ len += st->mode == MODE_HYBRID ? 3 : 1;
+ if( st->use_vbr ) {
+ nb_compr_bytes = len + bytes_target - (st->silk_mode.bitRate * frame_size) / (8 * st->Fs);
+ } else {
+ /* check if SILK used up too much */
+ nb_compr_bytes = len > bytes_target ? len : bytes_target;
+ }
+ } else {
+ if (st->use_vbr)
+ {
+ opus_int32 bonus=0;
+#ifndef DISABLE_FLOAT_API
+ if (st->variable_duration==OPUS_FRAMESIZE_VARIABLE && frame_size != st->Fs/50)
+ {
+ bonus = (60*st->stream_channels+40)*(st->Fs/frame_size-50);
+ if (analysis_info.valid)
+ bonus = (opus_int32)(bonus*(1.f+.5f*analysis_info.tonality));
+ }
+#endif
+ celt_encoder_ctl(celt_enc, OPUS_SET_VBR(1));
+ celt_encoder_ctl(celt_enc, OPUS_SET_VBR_CONSTRAINT(st->vbr_constraint));
+ celt_encoder_ctl(celt_enc, OPUS_SET_BITRATE(st->bitrate_bps+bonus));
+ nb_compr_bytes = max_data_bytes-1-redundancy_bytes;
+ } else {
+ nb_compr_bytes = bytes_target;
+ }
+ }
+
+ } else {
+ nb_compr_bytes = 0;
+ }
+
+ ALLOC(tmp_prefill, st->channels*st->Fs/400, opus_val16);
+ if (st->mode != MODE_SILK_ONLY && st->mode != st->prev_mode && st->prev_mode > 0)
+ {
+ for (i=0;i<st->channels*st->Fs/400;i++)
+ tmp_prefill[i] = st->delay_buffer[(st->encoder_buffer-total_buffer-st->Fs/400)*st->channels + i];
+ }
+
+ for (i=0;i<st->channels*(st->encoder_buffer-(frame_size+total_buffer));i++)
+ st->delay_buffer[i] = st->delay_buffer[i+st->channels*frame_size];
+ for (;i<st->encoder_buffer*st->channels;i++)
+ st->delay_buffer[i] = pcm_buf[(frame_size+total_buffer-st->encoder_buffer)*st->channels+i];
+
+ /* gain_fade() and stereo_fade() need to be after the buffer copying
+ because we don't want any of this to affect the SILK part */
+ if( st->prev_HB_gain < Q15ONE || HB_gain < Q15ONE ) {
+ gain_fade(pcm_buf, pcm_buf,
+ st->prev_HB_gain, HB_gain, celt_mode->overlap, frame_size, st->channels, celt_mode->window, st->Fs);
+ }
+ st->prev_HB_gain = HB_gain;
+ if (st->mode != MODE_HYBRID || st->stream_channels==1)
+ st->silk_mode.stereoWidth_Q14 = IMIN((1<<14),2*IMAX(0,equiv_rate-30000));
+ if( !st->energy_masking && st->channels == 2 ) {
+ /* Apply stereo width reduction (at low bitrates) */
+ if( st->hybrid_stereo_width_Q14 < (1 << 14) || st->silk_mode.stereoWidth_Q14 < (1 << 14) ) {
+ opus_val16 g1, g2;
+ g1 = st->hybrid_stereo_width_Q14;
+ g2 = (opus_val16)(st->silk_mode.stereoWidth_Q14);
+#ifdef OPUS_FIXED_POINT
+ g1 = g1==16384 ? Q15ONE : SHL16(g1,1);
+ g2 = g2==16384 ? Q15ONE : SHL16(g2,1);
+#else
+ g1 *= (1.f/16384);
+ g2 *= (1.f/16384);
+#endif
+ stereo_fade(pcm_buf, pcm_buf, g1, g2, celt_mode->overlap,
+ frame_size, st->channels, celt_mode->window, st->Fs);
+ st->hybrid_stereo_width_Q14 = st->silk_mode.stereoWidth_Q14;
+ }
+ }
+
+ if ( st->mode != MODE_CELT_ONLY && ec_tell(&enc)+17+20*(st->mode == MODE_HYBRID) <= 8*(max_data_bytes-1))
+ {
+ /* For SILK mode, the redundancy is inferred from the length */
+ if (st->mode == MODE_HYBRID && (redundancy || ec_tell(&enc)+37 <= 8*nb_compr_bytes))
+ ec_enc_bit_logp(&enc, redundancy, 12);
+ if (redundancy)
+ {
+ int max_redundancy;
+ ec_enc_bit_logp(&enc, celt_to_silk, 1);
+ if (st->mode == MODE_HYBRID)
+ max_redundancy = (max_data_bytes-1)-nb_compr_bytes;
+ else
+ max_redundancy = (max_data_bytes-1)-((ec_tell(&enc)+7)>>3);
+ /* Target the same bit-rate for redundancy as for the rest,
+ up to a max of 257 bytes */
+ redundancy_bytes = IMIN(max_redundancy, st->bitrate_bps/1600);
+ redundancy_bytes = IMIN(257, IMAX(2, redundancy_bytes));
+ if (st->mode == MODE_HYBRID)
+ ec_enc_uint(&enc, redundancy_bytes-2, 256);
+ }
+ } else {
+ redundancy = 0;
+ }
+
+ if (!redundancy)
+ {
+ st->silk_bw_switch = 0;
+ redundancy_bytes = 0;
+ }
+ if (st->mode != MODE_CELT_ONLY)start_band=17;
+
+ if (st->mode == MODE_SILK_ONLY)
+ {
+ ret = (ec_tell(&enc)+7)>>3;
+ ec_enc_done(&enc);
+ nb_compr_bytes = ret;
+ } else {
+ nb_compr_bytes = IMIN((max_data_bytes-1)-redundancy_bytes, nb_compr_bytes);
+ ec_enc_shrink(&enc, nb_compr_bytes);
+ }
+
+#ifndef DISABLE_FLOAT_API
+ if (redundancy || st->mode != MODE_SILK_ONLY)
+ celt_encoder_ctl(celt_enc, CELT_SET_ANALYSIS(&analysis_info));
+#endif
+
+ /* 5 ms redundant frame for CELT->SILK */
+ if (redundancy && celt_to_silk)
+ {
+ int err;
+ celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0));
+ celt_encoder_ctl(celt_enc, OPUS_SET_VBR(0));
+ err = celt_encode_with_ec(celt_enc, pcm_buf, st->Fs/200, data+nb_compr_bytes, redundancy_bytes, NULL);
+ if (err < 0)
+ {
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ celt_encoder_ctl(celt_enc, OPUS_GET_FINAL_RANGE(&redundant_rng));
+ celt_encoder_ctl(celt_enc, OPUS_RESET_STATE);
+ }
+
+ celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(start_band));
+
+ if (st->mode != MODE_SILK_ONLY)
+ {
+ if (st->mode != st->prev_mode && st->prev_mode > 0)
+ {
+ unsigned char dummy[2];
+ celt_encoder_ctl(celt_enc, OPUS_RESET_STATE);
+
+ /* Prefilling */
+ celt_encode_with_ec(celt_enc, tmp_prefill, st->Fs/400, dummy, 2, NULL);
+ celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0));
+ }
+ /* If false, we already busted the budget and we'll end up with a "PLC packet" */
+ if (ec_tell(&enc) <= 8*nb_compr_bytes)
+ {
+ ret = celt_encode_with_ec(celt_enc, pcm_buf, frame_size, NULL, nb_compr_bytes, &enc);
+ if (ret < 0)
+ {
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ }
+ }
+
+ /* 5 ms redundant frame for SILK->CELT */
+ if (redundancy && !celt_to_silk)
+ {
+ int err;
+ unsigned char dummy[2];
+ int N2, N4;
+ N2 = st->Fs/200;
+ N4 = st->Fs/400;
+
+ celt_encoder_ctl(celt_enc, OPUS_RESET_STATE);
+ celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0));
+ celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0));
+
+ /* NOTE: We could speed this up slightly (at the expense of code size) by just adding a function that prefills the buffer */
+ celt_encode_with_ec(celt_enc, pcm_buf+st->channels*(frame_size-N2-N4), N4, dummy, 2, NULL);
+
+ err = celt_encode_with_ec(celt_enc, pcm_buf+st->channels*(frame_size-N2), N2, data+nb_compr_bytes, redundancy_bytes, NULL);
+ if (err < 0)
+ {
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ celt_encoder_ctl(celt_enc, OPUS_GET_FINAL_RANGE(&redundant_rng));
+ }
+
+
+
+ /* Signalling the mode in the first byte */
+ data--;
+ data[0] = gen_toc(st->mode, st->Fs/frame_size, curr_bandwidth, st->stream_channels);
+
+ st->rangeFinal = enc.rng ^ redundant_rng;
+
+ if (to_celt)
+ st->prev_mode = MODE_CELT_ONLY;
+ else
+ st->prev_mode = st->mode;
+ st->prev_channels = st->stream_channels;
+ st->prev_framesize = frame_size;
+
+ st->first = 0;
+
+ /* In the unlikely case that the SILK encoder busted its target, tell
+ the decoder to call the PLC */
+ if (ec_tell(&enc) > (max_data_bytes-1)*8)
+ {
+ if (max_data_bytes < 2)
+ {
+ RESTORE_STACK;
+ return OPUS_BUFFER_TOO_SMALL;
+ }
+ data[1] = 0;
+ ret = 1;
+ st->rangeFinal = 0;
+ } else if (st->mode==MODE_SILK_ONLY&&!redundancy)
+ {
+ /*When in LPC only mode it's perfectly
+ reasonable to strip off trailing zero bytes as
+ the required range decoder behavior is to
+ fill these in. This can't be done when the MDCT
+ modes are used because the decoder needs to know
+ the actual length for allocation purposes.*/
+ while(ret>2&&data[ret]==0)ret--;
+ }
+ /* Count ToC and redundancy */
+ ret += 1+redundancy_bytes;
+ if (!st->use_vbr)
+ {
+ if (opus_packet_pad(data, ret, max_data_bytes) != OPUS_OK)
+
+ {
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ ret = max_data_bytes;
+ }
+ RESTORE_STACK;
+ return ret;
+}
+
+#ifdef OPUS_FIXED_POINT
+
+#ifndef DISABLE_FLOAT_API
+opus_int32 opus_encode_float(OpusEncoder *st, const float *pcm, int analysis_frame_size,
+ unsigned char *data, opus_int32 max_data_bytes)
+{
+ int i, ret;
+ int frame_size;
+ int delay_compensation;
+ VARDECL(opus_int16, in);
+ ALLOC_STACK;
+
+ if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ delay_compensation = 0;
+ else
+ delay_compensation = st->delay_compensation;
+ frame_size = compute_frame_size(pcm, analysis_frame_size,
+ st->variable_duration, st->channels, st->Fs, st->bitrate_bps,
+ delay_compensation, downmix_float, st->analysis.subframe_mem);
+
+ ALLOC(in, frame_size*st->channels, opus_int16);
+
+ for (i=0;i<frame_size*st->channels;i++)
+ in[i] = FLOAT2INT16(pcm[i]);
+ ret = opus_encode_native(st, in, frame_size, data, max_data_bytes, 16, pcm, analysis_frame_size, 0, -2, st->channels, downmix_float);
+ RESTORE_STACK;
+ return ret;
+}
+#endif
+
+opus_int32 opus_encode(OpusEncoder *st, const opus_int16 *pcm, int analysis_frame_size,
+ unsigned char *data, opus_int32 out_data_bytes)
+{
+ int frame_size;
+ int delay_compensation;
+ if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ delay_compensation = 0;
+ else
+ delay_compensation = st->delay_compensation;
+ frame_size = compute_frame_size(pcm, analysis_frame_size,
+ st->variable_duration, st->channels, st->Fs, st->bitrate_bps,
+ delay_compensation, downmix_int
+#ifndef DISABLE_FLOAT_API
+ , st->analysis.subframe_mem
+#endif
+ );
+ return opus_encode_native(st, pcm, frame_size, data, out_data_bytes, 16, pcm, analysis_frame_size, 0, -2, st->channels, downmix_int);
+}
+
+#else
+opus_int32 opus_encode(OpusEncoder *st, const opus_int16 *pcm, int analysis_frame_size,
+ unsigned char *data, opus_int32 max_data_bytes)
+{
+ int i, ret;
+ int frame_size;
+ int delay_compensation;
+ VARDECL(float, in);
+ ALLOC_STACK;
+
+ if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ delay_compensation = 0;
+ else
+ delay_compensation = st->delay_compensation;
+ frame_size = compute_frame_size(pcm, analysis_frame_size,
+ st->variable_duration, st->channels, st->Fs, st->bitrate_bps,
+ delay_compensation, downmix_int, st->analysis.subframe_mem);
+
+ ALLOC(in, frame_size*st->channels, float);
+
+ for (i=0;i<frame_size*st->channels;i++)
+ in[i] = (1.0f/32768)*pcm[i];
+ ret = opus_encode_native(st, in, frame_size, data, max_data_bytes, 16, pcm, analysis_frame_size, 0, -2, st->channels, downmix_int);
+ RESTORE_STACK;
+ return ret;
+}
+opus_int32 opus_encode_float(OpusEncoder *st, const float *pcm, int analysis_frame_size,
+ unsigned char *data, opus_int32 out_data_bytes)
+{
+ int frame_size;
+ int delay_compensation;
+ if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ delay_compensation = 0;
+ else
+ delay_compensation = st->delay_compensation;
+ frame_size = compute_frame_size(pcm, analysis_frame_size,
+ st->variable_duration, st->channels, st->Fs, st->bitrate_bps,
+ delay_compensation, downmix_float, st->analysis.subframe_mem);
+ return opus_encode_native(st, pcm, frame_size, data, out_data_bytes, 24,
+ pcm, analysis_frame_size, 0, -2, st->channels, downmix_float);
+}
+#endif
+
+
+int opus_encoder_ctl(OpusEncoder *st, int request, ...)
+{
+ int ret;
+ CELTEncoder *celt_enc;
+ va_list ap;
+
+ ret = OPUS_OK;
+ va_start(ap, request);
+
+ celt_enc = (CELTEncoder*)((char*)st+st->celt_enc_offset);
+
+ switch (request)
+ {
+ case OPUS_SET_APPLICATION_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if ( (value != OPUS_APPLICATION_VOIP && value != OPUS_APPLICATION_AUDIO
+ && value != OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ || (!st->first && st->application != value))
+ {
+ ret = OPUS_BAD_ARG;
+ break;
+ }
+ st->application = value;
+ }
+ break;
+ case OPUS_GET_APPLICATION_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->application;
+ }
+ break;
+ case OPUS_SET_BITRATE_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value != OPUS_AUTO && value != OPUS_BITRATE_MAX)
+ {
+ if (value <= 0)
+ goto bad_arg;
+ else if (value <= 500)
+ value = 500;
+ else if (value > (opus_int32)300000*st->channels)
+ value = (opus_int32)300000*st->channels;
+ }
+ st->user_bitrate_bps = value;
+ }
+ break;
+ case OPUS_GET_BITRATE_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = user_bitrate_to_bitrate(st, st->prev_framesize, 1276);
+ }
+ break;
+ case OPUS_SET_FORCE_CHANNELS_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if((value<1 || value>st->channels) && value != OPUS_AUTO)
+ {
+ goto bad_arg;
+ }
+ st->force_channels = value;
+ }
+ break;
+ case OPUS_GET_FORCE_CHANNELS_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->force_channels;
+ }
+ break;
+ case OPUS_SET_MAX_BANDWIDTH_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value < OPUS_BANDWIDTH_NARROWBAND || value > OPUS_BANDWIDTH_FULLBAND)
+ {
+ goto bad_arg;
+ }
+ st->max_bandwidth = value;
+ if (st->max_bandwidth == OPUS_BANDWIDTH_NARROWBAND) {
+ st->silk_mode.maxInternalSampleRate = 8000;
+ } else if (st->max_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) {
+ st->silk_mode.maxInternalSampleRate = 12000;
+ } else {
+ st->silk_mode.maxInternalSampleRate = 16000;
+ }
+ }
+ break;
+ case OPUS_GET_MAX_BANDWIDTH_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->max_bandwidth;
+ }
+ break;
+ case OPUS_SET_BANDWIDTH_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if ((value < OPUS_BANDWIDTH_NARROWBAND || value > OPUS_BANDWIDTH_FULLBAND) && value != OPUS_AUTO)
+ {
+ goto bad_arg;
+ }
+ st->user_bandwidth = value;
+ if (st->user_bandwidth == OPUS_BANDWIDTH_NARROWBAND) {
+ st->silk_mode.maxInternalSampleRate = 8000;
+ } else if (st->user_bandwidth == OPUS_BANDWIDTH_MEDIUMBAND) {
+ st->silk_mode.maxInternalSampleRate = 12000;
+ } else {
+ st->silk_mode.maxInternalSampleRate = 16000;
+ }
+ }
+ break;
+ case OPUS_GET_BANDWIDTH_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->bandwidth;
+ }
+ break;
+ case OPUS_SET_DTX_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>1)
+ {
+ goto bad_arg;
+ }
+ st->silk_mode.useDTX = value;
+ }
+ break;
+ case OPUS_GET_DTX_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->silk_mode.useDTX;
+ }
+ break;
+ case OPUS_SET_COMPLEXITY_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>10)
+ {
+ goto bad_arg;
+ }
+ st->silk_mode.complexity = value;
+ celt_encoder_ctl(celt_enc, OPUS_SET_COMPLEXITY(value));
+ }
+ break;
+ case OPUS_GET_COMPLEXITY_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->silk_mode.complexity;
+ }
+ break;
+ case OPUS_SET_INBAND_FEC_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>1)
+ {
+ goto bad_arg;
+ }
+ st->silk_mode.useInBandFEC = value;
+ }
+ break;
+ case OPUS_GET_INBAND_FEC_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->silk_mode.useInBandFEC;
+ }
+ break;
+ case OPUS_SET_PACKET_LOSS_PERC_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value < 0 || value > 100)
+ {
+ goto bad_arg;
+ }
+ st->silk_mode.packetLossPercentage = value;
+ celt_encoder_ctl(celt_enc, OPUS_SET_PACKET_LOSS_PERC(value));
+ }
+ break;
+ case OPUS_GET_PACKET_LOSS_PERC_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->silk_mode.packetLossPercentage;
+ }
+ break;
+ case OPUS_SET_VBR_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>1)
+ {
+ goto bad_arg;
+ }
+ st->use_vbr = value;
+ st->silk_mode.useCBR = 1-value;
+ }
+ break;
+ case OPUS_GET_VBR_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->use_vbr;
+ }
+ break;
+ case OPUS_SET_VOICE_RATIO_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<-1 || value>100)
+ {
+ goto bad_arg;
+ }
+ st->voice_ratio = value;
+ }
+ break;
+ case OPUS_GET_VOICE_RATIO_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->voice_ratio;
+ }
+ break;
+ case OPUS_SET_VBR_CONSTRAINT_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value<0 || value>1)
+ {
+ goto bad_arg;
+ }
+ st->vbr_constraint = value;
+ }
+ break;
+ case OPUS_GET_VBR_CONSTRAINT_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->vbr_constraint;
+ }
+ break;
+ case OPUS_SET_SIGNAL_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if(value!=OPUS_AUTO && value!=OPUS_SIGNAL_VOICE && value!=OPUS_SIGNAL_MUSIC)
+ {
+ goto bad_arg;
+ }
+ st->signal_type = value;
+ }
+ break;
+ case OPUS_GET_SIGNAL_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->signal_type;
+ }
+ break;
+ case OPUS_GET_LOOKAHEAD_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->Fs/400;
+ if (st->application != OPUS_APPLICATION_RESTRICTED_LOWDELAY)
+ *value += st->delay_compensation;
+ }
+ break;
+ case OPUS_GET_SAMPLE_RATE_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->Fs;
+ }
+ break;
+ case OPUS_GET_FINAL_RANGE_REQUEST:
+ {
+ opus_uint32 *value = va_arg(ap, opus_uint32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->rangeFinal;
+ }
+ break;
+ case OPUS_SET_LSB_DEPTH_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<8 || value>24)
+ {
+ goto bad_arg;
+ }
+ st->lsb_depth=value;
+ }
+ break;
+ case OPUS_GET_LSB_DEPTH_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->lsb_depth;
+ }
+ break;
+ case OPUS_SET_EXPERT_FRAME_DURATION_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value != OPUS_FRAMESIZE_ARG && value != OPUS_FRAMESIZE_2_5_MS &&
+ value != OPUS_FRAMESIZE_5_MS && value != OPUS_FRAMESIZE_10_MS &&
+ value != OPUS_FRAMESIZE_20_MS && value != OPUS_FRAMESIZE_40_MS &&
+ value != OPUS_FRAMESIZE_60_MS && value != OPUS_FRAMESIZE_VARIABLE)
+ {
+ goto bad_arg;
+ }
+ st->variable_duration = value;
+ celt_encoder_ctl(celt_enc, OPUS_SET_EXPERT_FRAME_DURATION(value));
+ }
+ break;
+ case OPUS_GET_EXPERT_FRAME_DURATION_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->variable_duration;
+ }
+ break;
+ case OPUS_SET_PREDICTION_DISABLED_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value > 1 || value < 0)
+ goto bad_arg;
+ st->silk_mode.reducedDependency = value;
+ }
+ break;
+ case OPUS_GET_PREDICTION_DISABLED_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ goto bad_arg;
+ *value = st->silk_mode.reducedDependency;
+ }
+ break;
+ case OPUS_RESET_STATE:
+ {
+ void *silk_enc;
+ silk_EncControlStruct dummy;
+ silk_enc = (char*)st+st->silk_enc_offset;
+
+ OPUS_CLEAR((char*)&st->OPUS_ENCODER_RESET_START,
+ sizeof(OpusEncoder)-
+ ((char*)&st->OPUS_ENCODER_RESET_START - (char*)st));
+
+ celt_encoder_ctl(celt_enc, OPUS_RESET_STATE);
+ silk_InitEncoder( silk_enc, st->arch, &dummy );
+ st->stream_channels = st->channels;
+ st->hybrid_stereo_width_Q14 = 1 << 14;
+ st->prev_HB_gain = Q15ONE;
+ st->first = 1;
+ st->mode = MODE_HYBRID;
+ st->bandwidth = OPUS_BANDWIDTH_FULLBAND;
+ st->variable_HP_smth2_Q15 = silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 );
+ }
+ break;
+ case OPUS_SET_FORCE_MODE_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if ((value < MODE_SILK_ONLY || value > MODE_CELT_ONLY) && value != OPUS_AUTO)
+ {
+ goto bad_arg;
+ }
+ st->user_forced_mode = value;
+ }
+ break;
+ case OPUS_SET_LFE_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ st->lfe = value;
+ ret = celt_encoder_ctl(celt_enc, OPUS_SET_LFE(value));
+ }
+ break;
+ case OPUS_SET_ENERGY_MASK_REQUEST:
+ {
+ opus_val16 *value = va_arg(ap, opus_val16*);
+ st->energy_masking = value;
+ ret = celt_encoder_ctl(celt_enc, OPUS_SET_ENERGY_MASK(value));
+ }
+ break;
+
+ case CELT_GET_MODE_REQUEST:
+ {
+ const CELTMode ** value = va_arg(ap, const CELTMode**);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ ret = celt_encoder_ctl(celt_enc, CELT_GET_MODE(value));
+ }
+ break;
+ default:
+ /* fprintf(stderr, "unknown opus_encoder_ctl() request: %d", request);*/
+ ret = OPUS_UNIMPLEMENTED;
+ break;
+ }
+ va_end(ap);
+ return ret;
+bad_arg:
+ va_end(ap);
+ return OPUS_BAD_ARG;
+}
+
+void opus_encoder_destroy(OpusEncoder *st)
+{
+ opus_free(st);
+}
diff --git a/drivers/opus/opus_multistream.c b/drivers/opus/opus_multistream.c
new file mode 100644
index 0000000000..10c42dd56d
--- /dev/null
+++ b/drivers/opus/opus_multistream.c
@@ -0,0 +1,92 @@
+/* Copyright (c) 2011 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/opus_multistream.h"
+#include "opus/opus.h"
+#include "opus/opus_private.h"
+#include "opus/celt/stack_alloc.h"
+#include <stdarg.h>
+#include "opus/celt/float_cast.h"
+#include "opus/celt/os_support.h"
+
+
+int validate_layout(const ChannelLayout *layout)
+{
+ int i, max_channel;
+
+ max_channel = layout->nb_streams+layout->nb_coupled_streams;
+ if (max_channel>255)
+ return 0;
+ for (i=0;i<layout->nb_channels;i++)
+ {
+ if (layout->mapping[i] >= max_channel && layout->mapping[i] != 255)
+ return 0;
+ }
+ return 1;
+}
+
+
+int get_left_channel(const ChannelLayout *layout, int stream_id, int prev)
+{
+ int i;
+ i = (prev<0) ? 0 : prev+1;
+ for (;i<layout->nb_channels;i++)
+ {
+ if (layout->mapping[i]==stream_id*2)
+ return i;
+ }
+ return -1;
+}
+
+int get_right_channel(const ChannelLayout *layout, int stream_id, int prev)
+{
+ int i;
+ i = (prev<0) ? 0 : prev+1;
+ for (;i<layout->nb_channels;i++)
+ {
+ if (layout->mapping[i]==stream_id*2+1)
+ return i;
+ }
+ return -1;
+}
+
+int get_mono_channel(const ChannelLayout *layout, int stream_id, int prev)
+{
+ int i;
+ i = (prev<0) ? 0 : prev+1;
+ for (;i<layout->nb_channels;i++)
+ {
+ if (layout->mapping[i]==stream_id+layout->nb_coupled_streams)
+ return i;
+ }
+ return -1;
+}
+
diff --git a/drivers/opus/opus_multistream.h b/drivers/opus/opus_multistream.h
new file mode 100644
index 0000000000..f736c99c88
--- /dev/null
+++ b/drivers/opus/opus_multistream.h
@@ -0,0 +1,660 @@
+/* Copyright (c) 2011 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ * @file opus_multistream.h
+ * @brief Opus reference implementation multistream API
+ */
+
+#ifndef OPUS_MULTISTREAM_H
+#define OPUS_MULTISTREAM_H
+
+#include "opus/opus.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @cond OPUS_INTERNAL_DOC */
+
+/** Macros to trigger compilation errors when the wrong types are provided to a
+ * CTL. */
+/**@{*/
+#define __opus_check_encstate_ptr(ptr) ((ptr) + ((ptr) - (OpusEncoder**)(ptr)))
+#define __opus_check_decstate_ptr(ptr) ((ptr) + ((ptr) - (OpusDecoder**)(ptr)))
+/**@}*/
+
+/** These are the actual encoder and decoder CTL ID numbers.
+ * They should not be used directly by applications.
+ * In general, SETs should be even and GETs should be odd.*/
+/**@{*/
+#define OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST 5120
+#define OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST 5122
+/**@}*/
+
+/** @endcond */
+
+/** @defgroup opus_multistream_ctls Multistream specific encoder and decoder CTLs
+ *
+ * These are convenience macros that are specific to the
+ * opus_multistream_encoder_ctl() and opus_multistream_decoder_ctl()
+ * interface.
+ * The CTLs from @ref opus_genericctls, @ref opus_encoderctls, and
+ * @ref opus_decoderctls may be applied to a multistream encoder or decoder as
+ * well.
+ * In addition, you may retrieve the encoder or decoder state for an specific
+ * stream via #OPUS_MULTISTREAM_GET_ENCODER_STATE or
+ * #OPUS_MULTISTREAM_GET_DECODER_STATE and apply CTLs to it individually.
+ */
+/**@{*/
+
+/** Gets the encoder state for an individual stream of a multistream encoder.
+ * @param[in] x <tt>opus_int32</tt>: The index of the stream whose encoder you
+ * wish to retrieve.
+ * This must be non-negative and less than
+ * the <code>streams</code> parameter used
+ * to initialize the encoder.
+ * @param[out] y <tt>OpusEncoder**</tt>: Returns a pointer to the given
+ * encoder state.
+ * @retval OPUS_BAD_ARG The index of the requested stream was out of range.
+ * @hideinitializer
+ */
+#define OPUS_MULTISTREAM_GET_ENCODER_STATE(x,y) OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST, __opus_check_int(x), __opus_check_encstate_ptr(y)
+
+/** Gets the decoder state for an individual stream of a multistream decoder.
+ * @param[in] x <tt>opus_int32</tt>: The index of the stream whose decoder you
+ * wish to retrieve.
+ * This must be non-negative and less than
+ * the <code>streams</code> parameter used
+ * to initialize the decoder.
+ * @param[out] y <tt>OpusDecoder**</tt>: Returns a pointer to the given
+ * decoder state.
+ * @retval OPUS_BAD_ARG The index of the requested stream was out of range.
+ * @hideinitializer
+ */
+#define OPUS_MULTISTREAM_GET_DECODER_STATE(x,y) OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST, __opus_check_int(x), __opus_check_decstate_ptr(y)
+
+/**@}*/
+
+/** @defgroup opus_multistream Opus Multistream API
+ * @{
+ *
+ * The multistream API allows individual Opus streams to be combined into a
+ * single packet, enabling support for up to 255 channels. Unlike an
+ * elementary Opus stream, the encoder and decoder must negotiate the channel
+ * configuration before the decoder can successfully interpret the data in the
+ * packets produced by the encoder. Some basic information, such as packet
+ * duration, can be computed without any special negotiation.
+ *
+ * The format for multistream Opus packets is defined in the
+ * <a href="http://tools.ietf.org/html/draft-terriberry-oggopus">Ogg
+ * encapsulation specification</a> and is based on the self-delimited Opus
+ * framing described in Appendix B of <a href="http://tools.ietf.org/html/rfc6716">RFC 6716</a>.
+ * Normal Opus packets are just a degenerate case of multistream Opus packets,
+ * and can be encoded or decoded with the multistream API by setting
+ * <code>streams</code> to <code>1</code> when initializing the encoder or
+ * decoder.
+ *
+ * Multistream Opus streams can contain up to 255 elementary Opus streams.
+ * These may be either "uncoupled" or "coupled", indicating that the decoder
+ * is configured to decode them to either 1 or 2 channels, respectively.
+ * The streams are ordered so that all coupled streams appear at the
+ * beginning.
+ *
+ * A <code>mapping</code> table defines which decoded channel <code>i</code>
+ * should be used for each input/output (I/O) channel <code>j</code>. This table is
+ * typically provided as an unsigned char array.
+ * Let <code>i = mapping[j]</code> be the index for I/O channel <code>j</code>.
+ * If <code>i < 2*coupled_streams</code>, then I/O channel <code>j</code> is
+ * encoded as the left channel of stream <code>(i/2)</code> if <code>i</code>
+ * is even, or as the right channel of stream <code>(i/2)</code> if
+ * <code>i</code> is odd. Otherwise, I/O channel <code>j</code> is encoded as
+ * mono in stream <code>(i - coupled_streams)</code>, unless it has the special
+ * value 255, in which case it is omitted from the encoding entirely (the
+ * decoder will reproduce it as silence). Each value <code>i</code> must either
+ * be the special value 255 or be less than <code>streams + coupled_streams</code>.
+ *
+ * The output channels specified by the encoder
+ * should use the
+ * <a href="http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9">Vorbis
+ * channel ordering</a>. A decoder may wish to apply an additional permutation
+ * to the mapping the encoder used to achieve a different output channel
+ * order (e.g. for outputing in WAV order).
+ *
+ * Each multistream packet contains an Opus packet for each stream, and all of
+ * the Opus packets in a single multistream packet must have the same
+ * duration. Therefore the duration of a multistream packet can be extracted
+ * from the TOC sequence of the first stream, which is located at the
+ * beginning of the packet, just like an elementary Opus stream:
+ *
+ * @code
+ * int nb_samples;
+ * int nb_frames;
+ * nb_frames = opus_packet_get_nb_frames(data, len);
+ * if (nb_frames < 1)
+ * return nb_frames;
+ * nb_samples = opus_packet_get_samples_per_frame(data, 48000) * nb_frames;
+ * @endcode
+ *
+ * The general encoding and decoding process proceeds exactly the same as in
+ * the normal @ref opus_encoder and @ref opus_decoder APIs.
+ * See their documentation for an overview of how to use the corresponding
+ * multistream functions.
+ */
+
+/** Opus multistream encoder state.
+ * This contains the complete state of a multistream Opus encoder.
+ * It is position independent and can be freely copied.
+ * @see opus_multistream_encoder_create
+ * @see opus_multistream_encoder_init
+ */
+typedef struct OpusMSEncoder OpusMSEncoder;
+
+/** Opus multistream decoder state.
+ * This contains the complete state of a multistream Opus decoder.
+ * It is position independent and can be freely copied.
+ * @see opus_multistream_decoder_create
+ * @see opus_multistream_decoder_init
+ */
+typedef struct OpusMSDecoder OpusMSDecoder;
+
+/**\name Multistream encoder functions */
+/**@{*/
+
+/** Gets the size of an OpusMSEncoder structure.
+ * @param streams <tt>int</tt>: The total number of streams to encode from the
+ * input.
+ * This must be no more than 255.
+ * @param coupled_streams <tt>int</tt>: Number of coupled (2 channel) streams
+ * to encode.
+ * This must be no larger than the total
+ * number of streams.
+ * Additionally, The total number of
+ * encoded channels (<code>streams +
+ * coupled_streams</code>) must be no
+ * more than 255.
+ * @returns The size in bytes on success, or a negative error code
+ * (see @ref opus_errorcodes) on error.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_encoder_get_size(
+ int streams,
+ int coupled_streams
+);
+
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_surround_encoder_get_size(
+ int channels,
+ int mapping_family
+);
+
+
+/** Allocates and initializes a multistream encoder state.
+ * Call opus_multistream_encoder_destroy() to release
+ * this object when finished.
+ * @param Fs <tt>opus_int32</tt>: Sampling rate of the input signal (in Hz).
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param channels <tt>int</tt>: Number of channels in the input signal.
+ * This must be at most 255.
+ * It may be greater than the number of
+ * coded channels (<code>streams +
+ * coupled_streams</code>).
+ * @param streams <tt>int</tt>: The total number of streams to encode from the
+ * input.
+ * This must be no more than the number of channels.
+ * @param coupled_streams <tt>int</tt>: Number of coupled (2 channel) streams
+ * to encode.
+ * This must be no larger than the total
+ * number of streams.
+ * Additionally, The total number of
+ * encoded channels (<code>streams +
+ * coupled_streams</code>) must be no
+ * more than the number of input channels.
+ * @param[in] mapping <code>const unsigned char[channels]</code>: Mapping from
+ * encoded channels to input channels, as described in
+ * @ref opus_multistream. As an extra constraint, the
+ * multistream encoder does not allow encoding coupled
+ * streams for which one channel is unused since this
+ * is never a good idea.
+ * @param application <tt>int</tt>: The target encoder application.
+ * This must be one of the following:
+ * <dl>
+ * <dt>#OPUS_APPLICATION_VOIP</dt>
+ * <dd>Process signal for improved speech intelligibility.</dd>
+ * <dt>#OPUS_APPLICATION_AUDIO</dt>
+ * <dd>Favor faithfulness to the original input.</dd>
+ * <dt>#OPUS_APPLICATION_RESTRICTED_LOWDELAY</dt>
+ * <dd>Configure the minimum possible coding delay by disabling certain modes
+ * of operation.</dd>
+ * </dl>
+ * @param[out] error <tt>int *</tt>: Returns #OPUS_OK on success, or an error
+ * code (see @ref opus_errorcodes) on
+ * failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSEncoder *opus_multistream_encoder_create(
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping,
+ int application,
+ int *error
+) OPUS_ARG_NONNULL(5);
+
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSEncoder *opus_multistream_surround_encoder_create(
+ opus_int32 Fs,
+ int channels,
+ int mapping_family,
+ int *streams,
+ int *coupled_streams,
+ unsigned char *mapping,
+ int application,
+ int *error
+) OPUS_ARG_NONNULL(5);
+
+/** Initialize a previously allocated multistream encoder state.
+ * The memory pointed to by \a st must be at least the size returned by
+ * opus_multistream_encoder_get_size().
+ * This is intended for applications which use their own allocator instead of
+ * malloc.
+ * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.
+ * @see opus_multistream_encoder_create
+ * @see opus_multistream_encoder_get_size
+ * @param st <tt>OpusMSEncoder*</tt>: Multistream encoder state to initialize.
+ * @param Fs <tt>opus_int32</tt>: Sampling rate of the input signal (in Hz).
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param channels <tt>int</tt>: Number of channels in the input signal.
+ * This must be at most 255.
+ * It may be greater than the number of
+ * coded channels (<code>streams +
+ * coupled_streams</code>).
+ * @param streams <tt>int</tt>: The total number of streams to encode from the
+ * input.
+ * This must be no more than the number of channels.
+ * @param coupled_streams <tt>int</tt>: Number of coupled (2 channel) streams
+ * to encode.
+ * This must be no larger than the total
+ * number of streams.
+ * Additionally, The total number of
+ * encoded channels (<code>streams +
+ * coupled_streams</code>) must be no
+ * more than the number of input channels.
+ * @param[in] mapping <code>const unsigned char[channels]</code>: Mapping from
+ * encoded channels to input channels, as described in
+ * @ref opus_multistream. As an extra constraint, the
+ * multistream encoder does not allow encoding coupled
+ * streams for which one channel is unused since this
+ * is never a good idea.
+ * @param application <tt>int</tt>: The target encoder application.
+ * This must be one of the following:
+ * <dl>
+ * <dt>#OPUS_APPLICATION_VOIP</dt>
+ * <dd>Process signal for improved speech intelligibility.</dd>
+ * <dt>#OPUS_APPLICATION_AUDIO</dt>
+ * <dd>Favor faithfulness to the original input.</dd>
+ * <dt>#OPUS_APPLICATION_RESTRICTED_LOWDELAY</dt>
+ * <dd>Configure the minimum possible coding delay by disabling certain modes
+ * of operation.</dd>
+ * </dl>
+ * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes)
+ * on failure.
+ */
+OPUS_EXPORT int opus_multistream_encoder_init(
+ OpusMSEncoder *st,
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping,
+ int application
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6);
+
+OPUS_EXPORT int opus_multistream_surround_encoder_init(
+ OpusMSEncoder *st,
+ opus_int32 Fs,
+ int channels,
+ int mapping_family,
+ int *streams,
+ int *coupled_streams,
+ unsigned char *mapping,
+ int application
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6);
+
+/** Encodes a multistream Opus frame.
+ * @param st <tt>OpusMSEncoder*</tt>: Multistream encoder state.
+ * @param[in] pcm <tt>const opus_int16*</tt>: The input signal as interleaved
+ * samples.
+ * This must contain
+ * <code>frame_size*channels</code>
+ * samples.
+ * @param frame_size <tt>int</tt>: Number of samples per channel in the input
+ * signal.
+ * This must be an Opus frame size for the
+ * encoder's sampling rate.
+ * For example, at 48 kHz the permitted values
+ * are 120, 240, 480, 960, 1920, and 2880.
+ * Passing in a duration of less than 10 ms
+ * (480 samples at 48 kHz) will prevent the
+ * encoder from using the LPC or hybrid modes.
+ * @param[out] data <tt>unsigned char*</tt>: Output payload.
+ * This must contain storage for at
+ * least \a max_data_bytes.
+ * @param [in] max_data_bytes <tt>opus_int32</tt>: Size of the allocated
+ * memory for the output
+ * payload. This may be
+ * used to impose an upper limit on
+ * the instant bitrate, but should
+ * not be used as the only bitrate
+ * control. Use #OPUS_SET_BITRATE to
+ * control the bitrate.
+ * @returns The length of the encoded packet (in bytes) on success or a
+ * negative error code (see @ref opus_errorcodes) on failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_encode(
+ OpusMSEncoder *st,
+ const opus_int16 *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
+
+/** Encodes a multistream Opus frame from floating point input.
+ * @param st <tt>OpusMSEncoder*</tt>: Multistream encoder state.
+ * @param[in] pcm <tt>const float*</tt>: The input signal as interleaved
+ * samples with a normal range of
+ * +/-1.0.
+ * Samples with a range beyond +/-1.0
+ * are supported but will be clipped by
+ * decoders using the integer API and
+ * should only be used if it is known
+ * that the far end supports extended
+ * dynamic range.
+ * This must contain
+ * <code>frame_size*channels</code>
+ * samples.
+ * @param frame_size <tt>int</tt>: Number of samples per channel in the input
+ * signal.
+ * This must be an Opus frame size for the
+ * encoder's sampling rate.
+ * For example, at 48 kHz the permitted values
+ * are 120, 240, 480, 960, 1920, and 2880.
+ * Passing in a duration of less than 10 ms
+ * (480 samples at 48 kHz) will prevent the
+ * encoder from using the LPC or hybrid modes.
+ * @param[out] data <tt>unsigned char*</tt>: Output payload.
+ * This must contain storage for at
+ * least \a max_data_bytes.
+ * @param [in] max_data_bytes <tt>opus_int32</tt>: Size of the allocated
+ * memory for the output
+ * payload. This may be
+ * used to impose an upper limit on
+ * the instant bitrate, but should
+ * not be used as the only bitrate
+ * control. Use #OPUS_SET_BITRATE to
+ * control the bitrate.
+ * @returns The length of the encoded packet (in bytes) on success or a
+ * negative error code (see @ref opus_errorcodes) on failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_encode_float(
+ OpusMSEncoder *st,
+ const float *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
+
+/** Frees an <code>OpusMSEncoder</code> allocated by
+ * opus_multistream_encoder_create().
+ * @param st <tt>OpusMSEncoder*</tt>: Multistream encoder state to be freed.
+ */
+OPUS_EXPORT void opus_multistream_encoder_destroy(OpusMSEncoder *st);
+
+/** Perform a CTL function on a multistream Opus encoder.
+ *
+ * Generally the request and subsequent arguments are generated by a
+ * convenience macro.
+ * @param st <tt>OpusMSEncoder*</tt>: Multistream encoder state.
+ * @param request This and all remaining parameters should be replaced by one
+ * of the convenience macros in @ref opus_genericctls,
+ * @ref opus_encoderctls, or @ref opus_multistream_ctls.
+ * @see opus_genericctls
+ * @see opus_encoderctls
+ * @see opus_multistream_ctls
+ */
+OPUS_EXPORT int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...) OPUS_ARG_NONNULL(1);
+
+/**@}*/
+
+/**\name Multistream decoder functions */
+/**@{*/
+
+/** Gets the size of an <code>OpusMSDecoder</code> structure.
+ * @param streams <tt>int</tt>: The total number of streams coded in the
+ * input.
+ * This must be no more than 255.
+ * @param coupled_streams <tt>int</tt>: Number streams to decode as coupled
+ * (2 channel) streams.
+ * This must be no larger than the total
+ * number of streams.
+ * Additionally, The total number of
+ * coded channels (<code>streams +
+ * coupled_streams</code>) must be no
+ * more than 255.
+ * @returns The size in bytes on success, or a negative error code
+ * (see @ref opus_errorcodes) on error.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_multistream_decoder_get_size(
+ int streams,
+ int coupled_streams
+);
+
+/** Allocates and initializes a multistream decoder state.
+ * Call opus_multistream_decoder_destroy() to release
+ * this object when finished.
+ * @param Fs <tt>opus_int32</tt>: Sampling rate to decode at (in Hz).
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param channels <tt>int</tt>: Number of channels to output.
+ * This must be at most 255.
+ * It may be different from the number of coded
+ * channels (<code>streams +
+ * coupled_streams</code>).
+ * @param streams <tt>int</tt>: The total number of streams coded in the
+ * input.
+ * This must be no more than 255.
+ * @param coupled_streams <tt>int</tt>: Number of streams to decode as coupled
+ * (2 channel) streams.
+ * This must be no larger than the total
+ * number of streams.
+ * Additionally, The total number of
+ * coded channels (<code>streams +
+ * coupled_streams</code>) must be no
+ * more than 255.
+ * @param[in] mapping <code>const unsigned char[channels]</code>: Mapping from
+ * coded channels to output channels, as described in
+ * @ref opus_multistream.
+ * @param[out] error <tt>int *</tt>: Returns #OPUS_OK on success, or an error
+ * code (see @ref opus_errorcodes) on
+ * failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSDecoder *opus_multistream_decoder_create(
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping,
+ int *error
+) OPUS_ARG_NONNULL(5);
+
+/** Intialize a previously allocated decoder state object.
+ * The memory pointed to by \a st must be at least the size returned by
+ * opus_multistream_encoder_get_size().
+ * This is intended for applications which use their own allocator instead of
+ * malloc.
+ * To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.
+ * @see opus_multistream_decoder_create
+ * @see opus_multistream_deocder_get_size
+ * @param st <tt>OpusMSEncoder*</tt>: Multistream encoder state to initialize.
+ * @param Fs <tt>opus_int32</tt>: Sampling rate to decode at (in Hz).
+ * This must be one of 8000, 12000, 16000,
+ * 24000, or 48000.
+ * @param channels <tt>int</tt>: Number of channels to output.
+ * This must be at most 255.
+ * It may be different from the number of coded
+ * channels (<code>streams +
+ * coupled_streams</code>).
+ * @param streams <tt>int</tt>: The total number of streams coded in the
+ * input.
+ * This must be no more than 255.
+ * @param coupled_streams <tt>int</tt>: Number of streams to decode as coupled
+ * (2 channel) streams.
+ * This must be no larger than the total
+ * number of streams.
+ * Additionally, The total number of
+ * coded channels (<code>streams +
+ * coupled_streams</code>) must be no
+ * more than 255.
+ * @param[in] mapping <code>const unsigned char[channels]</code>: Mapping from
+ * coded channels to output channels, as described in
+ * @ref opus_multistream.
+ * @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes)
+ * on failure.
+ */
+OPUS_EXPORT int opus_multistream_decoder_init(
+ OpusMSDecoder *st,
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6);
+
+/** Decode a multistream Opus packet.
+ * @param st <tt>OpusMSDecoder*</tt>: Multistream decoder state.
+ * @param[in] data <tt>const unsigned char*</tt>: Input payload.
+ * Use a <code>NULL</code>
+ * pointer to indicate packet
+ * loss.
+ * @param len <tt>opus_int32</tt>: Number of bytes in payload.
+ * @param[out] pcm <tt>opus_int16*</tt>: Output signal, with interleaved
+ * samples.
+ * This must contain room for
+ * <code>frame_size*channels</code>
+ * samples.
+ * @param frame_size <tt>int</tt>: The number of samples per channel of
+ * available space in \a pcm.
+ * If this is less than the maximum packet duration
+ * (120 ms; 5760 for 48kHz), this function will not be capable
+ * of decoding some packets. In the case of PLC (data==NULL)
+ * or FEC (decode_fec=1), then frame_size needs to be exactly
+ * the duration of audio that is missing, otherwise the
+ * decoder will not be in the optimal state to decode the
+ * next incoming packet. For the PLC and FEC cases, frame_size
+ * <b>must</b> be a multiple of 2.5 ms.
+ * @param decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band
+ * forward error correction data be decoded.
+ * If no such data is available, the frame is
+ * decoded as if it were lost.
+ * @returns Number of samples decoded on success or a negative error code
+ * (see @ref opus_errorcodes) on failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_decode(
+ OpusMSDecoder *st,
+ const unsigned char *data,
+ opus_int32 len,
+ opus_int16 *pcm,
+ int frame_size,
+ int decode_fec
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Decode a multistream Opus packet with floating point output.
+ * @param st <tt>OpusMSDecoder*</tt>: Multistream decoder state.
+ * @param[in] data <tt>const unsigned char*</tt>: Input payload.
+ * Use a <code>NULL</code>
+ * pointer to indicate packet
+ * loss.
+ * @param len <tt>opus_int32</tt>: Number of bytes in payload.
+ * @param[out] pcm <tt>opus_int16*</tt>: Output signal, with interleaved
+ * samples.
+ * This must contain room for
+ * <code>frame_size*channels</code>
+ * samples.
+ * @param frame_size <tt>int</tt>: The number of samples per channel of
+ * available space in \a pcm.
+ * If this is less than the maximum packet duration
+ * (120 ms; 5760 for 48kHz), this function will not be capable
+ * of decoding some packets. In the case of PLC (data==NULL)
+ * or FEC (decode_fec=1), then frame_size needs to be exactly
+ * the duration of audio that is missing, otherwise the
+ * decoder will not be in the optimal state to decode the
+ * next incoming packet. For the PLC and FEC cases, frame_size
+ * <b>must</b> be a multiple of 2.5 ms.
+ * @param decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band
+ * forward error correction data be decoded.
+ * If no such data is available, the frame is
+ * decoded as if it were lost.
+ * @returns Number of samples decoded on success or a negative error code
+ * (see @ref opus_errorcodes) on failure.
+ */
+OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_multistream_decode_float(
+ OpusMSDecoder *st,
+ const unsigned char *data,
+ opus_int32 len,
+ float *pcm,
+ int frame_size,
+ int decode_fec
+) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
+
+/** Perform a CTL function on a multistream Opus decoder.
+ *
+ * Generally the request and subsequent arguments are generated by a
+ * convenience macro.
+ * @param st <tt>OpusMSDecoder*</tt>: Multistream decoder state.
+ * @param request This and all remaining parameters should be replaced by one
+ * of the convenience macros in @ref opus_genericctls,
+ * @ref opus_decoderctls, or @ref opus_multistream_ctls.
+ * @see opus_genericctls
+ * @see opus_decoderctls
+ * @see opus_multistream_ctls
+ */
+OPUS_EXPORT int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...) OPUS_ARG_NONNULL(1);
+
+/** Frees an <code>OpusMSDecoder</code> allocated by
+ * opus_multistream_decoder_create().
+ * @param st <tt>OpusMSDecoder</tt>: Multistream decoder state to be freed.
+ */
+OPUS_EXPORT void opus_multistream_decoder_destroy(OpusMSDecoder *st);
+
+/**@}*/
+
+/**@}*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* OPUS_MULTISTREAM_H */
diff --git a/drivers/opus/opus_multistream_decoder.c b/drivers/opus/opus_multistream_decoder.c
new file mode 100644
index 0000000000..43c695d815
--- /dev/null
+++ b/drivers/opus/opus_multistream_decoder.c
@@ -0,0 +1,537 @@
+/* Copyright (c) 2011 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/opus_multistream.h"
+#include "opus/opus.h"
+#include "opus/opus_private.h"
+#include "opus/celt/stack_alloc.h"
+#include <stdarg.h>
+#include "opus/celt/float_cast.h"
+#include "opus/celt/os_support.h"
+
+struct OpusMSDecoder {
+ ChannelLayout layout;
+ /* Decoder states go here */
+};
+
+
+
+
+/* DECODER */
+
+opus_int32 opus_multistream_decoder_get_size(int nb_streams, int nb_coupled_streams)
+{
+ int coupled_size;
+ int mono_size;
+
+ if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0;
+ coupled_size = opus_decoder_get_size(2);
+ mono_size = opus_decoder_get_size(1);
+ return align(sizeof(OpusMSDecoder))
+ + nb_coupled_streams * align(coupled_size)
+ + (nb_streams-nb_coupled_streams) * align(mono_size);
+}
+
+int opus_multistream_decoder_init(
+ OpusMSDecoder *st,
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping
+)
+{
+ int coupled_size;
+ int mono_size;
+ int i, ret;
+ char *ptr;
+
+ if ((channels>255) || (channels<1) || (coupled_streams>streams) ||
+ (coupled_streams+streams>255) || (streams<1) || (coupled_streams<0))
+ return OPUS_BAD_ARG;
+
+ st->layout.nb_channels = channels;
+ st->layout.nb_streams = streams;
+ st->layout.nb_coupled_streams = coupled_streams;
+
+ for (i=0;i<st->layout.nb_channels;i++)
+ st->layout.mapping[i] = mapping[i];
+ if (!validate_layout(&st->layout))
+ return OPUS_BAD_ARG;
+
+ ptr = (char*)st + align(sizeof(OpusMSDecoder));
+ coupled_size = opus_decoder_get_size(2);
+ mono_size = opus_decoder_get_size(1);
+
+ for (i=0;i<st->layout.nb_coupled_streams;i++)
+ {
+ ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 2);
+ if(ret!=OPUS_OK)return ret;
+ ptr += align(coupled_size);
+ }
+ for (;i<st->layout.nb_streams;i++)
+ {
+ ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 1);
+ if(ret!=OPUS_OK)return ret;
+ ptr += align(mono_size);
+ }
+ return OPUS_OK;
+}
+
+
+OpusMSDecoder *opus_multistream_decoder_create(
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping,
+ int *error
+)
+{
+ int ret;
+ OpusMSDecoder *st;
+ if ((channels>255) || (channels<1) || (coupled_streams>streams) ||
+ (coupled_streams+streams>255) || (streams<1) || (coupled_streams<0))
+ {
+ if (error)
+ *error = OPUS_BAD_ARG;
+ return NULL;
+ }
+ st = (OpusMSDecoder *)opus_alloc(opus_multistream_decoder_get_size(streams, coupled_streams));
+ if (st==NULL)
+ {
+ if (error)
+ *error = OPUS_ALLOC_FAIL;
+ return NULL;
+ }
+ ret = opus_multistream_decoder_init(st, Fs, channels, streams, coupled_streams, mapping);
+ if (error)
+ *error = ret;
+ if (ret != OPUS_OK)
+ {
+ opus_free(st);
+ st = NULL;
+ }
+ return st;
+}
+
+typedef void (*opus_copy_channel_out_func)(
+ void *dst,
+ int dst_stride,
+ int dst_channel,
+ const opus_val16 *src,
+ int src_stride,
+ int frame_size
+);
+
+static int opus_multistream_packet_validate(const unsigned char *data,
+ opus_int32 len, int nb_streams, opus_int32 Fs)
+{
+ int s;
+ int count;
+ unsigned char toc;
+ opus_int16 size[48];
+ int samples=0;
+ opus_int32 packet_offset;
+
+ for (s=0;s<nb_streams;s++)
+ {
+ int tmp_samples;
+ if (len<=0)
+ return OPUS_INVALID_PACKET;
+ count = opus_packet_parse_impl(data, len, s!=nb_streams-1, &toc, NULL,
+ size, NULL, &packet_offset);
+ if (count<0)
+ return count;
+ tmp_samples = opus_packet_get_nb_samples(data, packet_offset, Fs);
+ if (s!=0 && samples != tmp_samples)
+ return OPUS_INVALID_PACKET;
+ samples = tmp_samples;
+ data += packet_offset;
+ len -= packet_offset;
+ }
+ return samples;
+}
+
+static int opus_multistream_decode_native(
+ OpusMSDecoder *st,
+ const unsigned char *data,
+ opus_int32 len,
+ void *pcm,
+ opus_copy_channel_out_func copy_channel_out,
+ int frame_size,
+ int decode_fec,
+ int soft_clip
+)
+{
+ opus_int32 Fs;
+ int coupled_size;
+ int mono_size;
+ int s, c;
+ char *ptr;
+ int do_plc=0;
+ VARDECL(opus_val16, buf);
+ ALLOC_STACK;
+
+ /* Limit frame_size to avoid excessive stack allocations. */
+ opus_multistream_decoder_ctl(st, OPUS_GET_SAMPLE_RATE(&Fs));
+ frame_size = IMIN(frame_size, Fs/25*3);
+ ALLOC(buf, 2*frame_size, opus_val16);
+ ptr = (char*)st + align(sizeof(OpusMSDecoder));
+ coupled_size = opus_decoder_get_size(2);
+ mono_size = opus_decoder_get_size(1);
+
+ if (len==0)
+ do_plc = 1;
+ if (len < 0)
+ {
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ }
+ if (!do_plc && len < 2*st->layout.nb_streams-1)
+ {
+ RESTORE_STACK;
+ return OPUS_INVALID_PACKET;
+ }
+ if (!do_plc)
+ {
+ int ret = opus_multistream_packet_validate(data, len, st->layout.nb_streams, Fs);
+ if (ret < 0)
+ {
+ RESTORE_STACK;
+ return ret;
+ } else if (ret > frame_size)
+ {
+ RESTORE_STACK;
+ return OPUS_BUFFER_TOO_SMALL;
+ }
+ }
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ OpusDecoder *dec;
+ int packet_offset, ret;
+
+ dec = (OpusDecoder*)ptr;
+ ptr += (s < st->layout.nb_coupled_streams) ? align(coupled_size) : align(mono_size);
+
+ if (!do_plc && len<=0)
+ {
+ RESTORE_STACK;
+ return OPUS_INTERNAL_ERROR;
+ }
+ packet_offset = 0;
+ ret = opus_decode_native(dec, data, len, buf, frame_size, decode_fec, s!=st->layout.nb_streams-1, &packet_offset, soft_clip);
+ data += packet_offset;
+ len -= packet_offset;
+ if (ret <= 0)
+ {
+ RESTORE_STACK;
+ return ret;
+ }
+ frame_size = ret;
+ if (s < st->layout.nb_coupled_streams)
+ {
+ int chan, prev;
+ prev = -1;
+ /* Copy "left" audio to the channel(s) where it belongs */
+ while ( (chan = get_left_channel(&st->layout, s, prev)) != -1)
+ {
+ (*copy_channel_out)(pcm, st->layout.nb_channels, chan,
+ buf, 2, frame_size);
+ prev = chan;
+ }
+ prev = -1;
+ /* Copy "right" audio to the channel(s) where it belongs */
+ while ( (chan = get_right_channel(&st->layout, s, prev)) != -1)
+ {
+ (*copy_channel_out)(pcm, st->layout.nb_channels, chan,
+ buf+1, 2, frame_size);
+ prev = chan;
+ }
+ } else {
+ int chan, prev;
+ prev = -1;
+ /* Copy audio to the channel(s) where it belongs */
+ while ( (chan = get_mono_channel(&st->layout, s, prev)) != -1)
+ {
+ (*copy_channel_out)(pcm, st->layout.nb_channels, chan,
+ buf, 1, frame_size);
+ prev = chan;
+ }
+ }
+ }
+ /* Handle muted channels */
+ for (c=0;c<st->layout.nb_channels;c++)
+ {
+ if (st->layout.mapping[c] == 255)
+ {
+ (*copy_channel_out)(pcm, st->layout.nb_channels, c,
+ NULL, 0, frame_size);
+ }
+ }
+ RESTORE_STACK;
+ return frame_size;
+}
+
+#if !defined(DISABLE_FLOAT_API)
+static void opus_copy_channel_out_float(
+ void *dst,
+ int dst_stride,
+ int dst_channel,
+ const opus_val16 *src,
+ int src_stride,
+ int frame_size
+)
+{
+ float *float_dst;
+ opus_int32 i;
+ float_dst = (float*)dst;
+ if (src != NULL)
+ {
+ for (i=0;i<frame_size;i++)
+#if defined(OPUS_FIXED_POINT)
+ float_dst[i*dst_stride+dst_channel] = (1/32768.f)*src[i*src_stride];
+#else
+ float_dst[i*dst_stride+dst_channel] = src[i*src_stride];
+#endif
+ }
+ else
+ {
+ for (i=0;i<frame_size;i++)
+ float_dst[i*dst_stride+dst_channel] = 0;
+ }
+}
+#endif
+
+static void opus_copy_channel_out_short(
+ void *dst,
+ int dst_stride,
+ int dst_channel,
+ const opus_val16 *src,
+ int src_stride,
+ int frame_size
+)
+{
+ opus_int16 *short_dst;
+ opus_int32 i;
+ short_dst = (opus_int16*)dst;
+ if (src != NULL)
+ {
+ for (i=0;i<frame_size;i++)
+#if defined(OPUS_FIXED_POINT)
+ short_dst[i*dst_stride+dst_channel] = src[i*src_stride];
+#else
+ short_dst[i*dst_stride+dst_channel] = FLOAT2INT16(src[i*src_stride]);
+#endif
+ }
+ else
+ {
+ for (i=0;i<frame_size;i++)
+ short_dst[i*dst_stride+dst_channel] = 0;
+ }
+}
+
+
+
+#ifdef OPUS_FIXED_POINT
+int opus_multistream_decode(
+ OpusMSDecoder *st,
+ const unsigned char *data,
+ opus_int32 len,
+ opus_int16 *pcm,
+ int frame_size,
+ int decode_fec
+)
+{
+ return opus_multistream_decode_native(st, data, len,
+ pcm, opus_copy_channel_out_short, frame_size, decode_fec, 0);
+}
+
+#ifndef DISABLE_FLOAT_API
+int opus_multistream_decode_float(OpusMSDecoder *st, const unsigned char *data,
+ opus_int32 len, float *pcm, int frame_size, int decode_fec)
+{
+ return opus_multistream_decode_native(st, data, len,
+ pcm, opus_copy_channel_out_float, frame_size, decode_fec, 0);
+}
+#endif
+
+#else
+
+int opus_multistream_decode(OpusMSDecoder *st, const unsigned char *data,
+ opus_int32 len, opus_int16 *pcm, int frame_size, int decode_fec)
+{
+ return opus_multistream_decode_native(st, data, len,
+ pcm, opus_copy_channel_out_short, frame_size, decode_fec, 1);
+}
+
+int opus_multistream_decode_float(
+ OpusMSDecoder *st,
+ const unsigned char *data,
+ opus_int32 len,
+ float *pcm,
+ int frame_size,
+ int decode_fec
+)
+{
+ return opus_multistream_decode_native(st, data, len,
+ pcm, opus_copy_channel_out_float, frame_size, decode_fec, 0);
+}
+#endif
+
+int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...)
+{
+ va_list ap;
+ int coupled_size, mono_size;
+ char *ptr;
+ int ret = OPUS_OK;
+
+ va_start(ap, request);
+
+ coupled_size = opus_decoder_get_size(2);
+ mono_size = opus_decoder_get_size(1);
+ ptr = (char*)st + align(sizeof(OpusMSDecoder));
+ switch (request)
+ {
+ case OPUS_GET_BANDWIDTH_REQUEST:
+ case OPUS_GET_SAMPLE_RATE_REQUEST:
+ case OPUS_GET_GAIN_REQUEST:
+ case OPUS_GET_LAST_PACKET_DURATION_REQUEST:
+ {
+ OpusDecoder *dec;
+ /* For int32* GET params, just query the first stream */
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ dec = (OpusDecoder*)ptr;
+ ret = opus_decoder_ctl(dec, request, value);
+ }
+ break;
+ case OPUS_GET_FINAL_RANGE_REQUEST:
+ {
+ int s;
+ opus_uint32 *value = va_arg(ap, opus_uint32*);
+ opus_uint32 tmp;
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = 0;
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ OpusDecoder *dec;
+ dec = (OpusDecoder*)ptr;
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ ret = opus_decoder_ctl(dec, request, &tmp);
+ if (ret != OPUS_OK) break;
+ *value ^= tmp;
+ }
+ }
+ break;
+ case OPUS_RESET_STATE:
+ {
+ int s;
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ OpusDecoder *dec;
+
+ dec = (OpusDecoder*)ptr;
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ ret = opus_decoder_ctl(dec, OPUS_RESET_STATE);
+ if (ret != OPUS_OK)
+ break;
+ }
+ }
+ break;
+ case OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST:
+ {
+ int s;
+ opus_int32 stream_id;
+ OpusDecoder **value;
+ stream_id = va_arg(ap, opus_int32);
+ if (stream_id<0 || stream_id >= st->layout.nb_streams)
+ ret = OPUS_BAD_ARG;
+ value = va_arg(ap, OpusDecoder**);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ for (s=0;s<stream_id;s++)
+ {
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ }
+ *value = (OpusDecoder*)ptr;
+ }
+ break;
+ case OPUS_SET_GAIN_REQUEST:
+ {
+ int s;
+ /* This works for int32 params */
+ opus_int32 value = va_arg(ap, opus_int32);
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ OpusDecoder *dec;
+
+ dec = (OpusDecoder*)ptr;
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ ret = opus_decoder_ctl(dec, request, value);
+ if (ret != OPUS_OK)
+ break;
+ }
+ }
+ break;
+ default:
+ ret = OPUS_UNIMPLEMENTED;
+ break;
+ }
+
+ va_end(ap);
+ return ret;
+bad_arg:
+ va_end(ap);
+ return OPUS_BAD_ARG;
+}
+
+
+void opus_multistream_decoder_destroy(OpusMSDecoder *st)
+{
+ opus_free(st);
+}
diff --git a/drivers/opus/opus_multistream_encoder.c b/drivers/opus/opus_multistream_encoder.c
new file mode 100644
index 0000000000..685d2de277
--- /dev/null
+++ b/drivers/opus/opus_multistream_encoder.c
@@ -0,0 +1,1174 @@
+/* Copyright (c) 2011 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/opus_multistream.h"
+#include "opus/opus.h"
+#include "opus/opus_private.h"
+#include "opus/celt/stack_alloc.h"
+#include <stdarg.h>
+#include "opus/celt/float_cast.h"
+#include "opus/celt/os_support.h"
+#include "opus/celt/mathops.h"
+#include "opus/celt/mdct.h"
+#include "opus/celt/opus_modes.h"
+#include "opus/celt/bands.h"
+#include "opus/celt/quant_bands.h"
+
+typedef struct {
+ int nb_streams;
+ int nb_coupled_streams;
+ unsigned char mapping[8];
+} VorbisLayout;
+
+/* Index is nb_channel-1*/
+static const VorbisLayout vorbis_mappings[8] = {
+ {1, 0, {0}}, /* 1: mono */
+ {1, 1, {0, 1}}, /* 2: stereo */
+ {2, 1, {0, 2, 1}}, /* 3: 1-d surround */
+ {2, 2, {0, 1, 2, 3}}, /* 4: quadraphonic surround */
+ {3, 2, {0, 4, 1, 2, 3}}, /* 5: 5-channel surround */
+ {4, 2, {0, 4, 1, 2, 3, 5}}, /* 6: 5.1 surround */
+ {4, 3, {0, 4, 1, 2, 3, 5, 6}}, /* 7: 6.1 surround */
+ {5, 3, {0, 6, 1, 2, 3, 4, 5, 7}}, /* 8: 7.1 surround */
+};
+
+typedef void (*opus_copy_channel_in_func)(
+ opus_val16 *dst,
+ int dst_stride,
+ const void *src,
+ int src_stride,
+ int src_channel,
+ int frame_size
+);
+
+struct OpusMSEncoder {
+ ChannelLayout layout;
+ int lfe_stream;
+ int application;
+ int variable_duration;
+ int surround;
+ opus_int32 bitrate_bps;
+ float subframe_mem[3];
+ /* Encoder states go here */
+ /* then opus_val32 window_mem[channels*120]; */
+ /* then opus_val32 preemph_mem[channels]; */
+};
+
+static opus_val32 *ms_get_preemph_mem(OpusMSEncoder *st)
+{
+ int s;
+ char *ptr;
+ int coupled_size, mono_size;
+
+ coupled_size = opus_encoder_get_size(2);
+ mono_size = opus_encoder_get_size(1);
+ ptr = (char*)st + align(sizeof(OpusMSEncoder));
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ }
+ return (opus_val32*)(ptr+st->layout.nb_channels*120*sizeof(opus_val32));
+}
+
+static opus_val32 *ms_get_window_mem(OpusMSEncoder *st)
+{
+ int s;
+ char *ptr;
+ int coupled_size, mono_size;
+
+ coupled_size = opus_encoder_get_size(2);
+ mono_size = opus_encoder_get_size(1);
+ ptr = (char*)st + align(sizeof(OpusMSEncoder));
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ }
+ return (opus_val32*)ptr;
+}
+
+static int validate_encoder_layout(const ChannelLayout *layout)
+{
+ int s;
+ for (s=0;s<layout->nb_streams;s++)
+ {
+ if (s < layout->nb_coupled_streams)
+ {
+ if (get_left_channel(layout, s, -1)==-1)
+ return 0;
+ if (get_right_channel(layout, s, -1)==-1)
+ return 0;
+ } else {
+ if (get_mono_channel(layout, s, -1)==-1)
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static void channel_pos(int channels, int pos[8])
+{
+ /* Position in the mix: 0 don't mix, 1: left, 2: center, 3:right */
+ if (channels==4)
+ {
+ pos[0]=1;
+ pos[1]=3;
+ pos[2]=1;
+ pos[3]=3;
+ } else if (channels==3||channels==5||channels==6)
+ {
+ pos[0]=1;
+ pos[1]=2;
+ pos[2]=3;
+ pos[3]=1;
+ pos[4]=3;
+ pos[5]=0;
+ } else if (channels==7)
+ {
+ pos[0]=1;
+ pos[1]=2;
+ pos[2]=3;
+ pos[3]=1;
+ pos[4]=3;
+ pos[5]=2;
+ pos[6]=0;
+ } else if (channels==8)
+ {
+ pos[0]=1;
+ pos[1]=2;
+ pos[2]=3;
+ pos[3]=1;
+ pos[4]=3;
+ pos[5]=1;
+ pos[6]=3;
+ pos[7]=0;
+ }
+}
+
+#if 1
+/* Computes a rough approximation of log2(2^a + 2^b) */
+static opus_val16 logSum(opus_val16 a, opus_val16 b)
+{
+ opus_val16 max;
+ opus_val32 diff;
+ opus_val16 frac;
+ static const opus_val16 diff_table[17] = {
+ QCONST16(0.5000000f, DB_SHIFT), QCONST16(0.2924813f, DB_SHIFT), QCONST16(0.1609640f, DB_SHIFT), QCONST16(0.0849625f, DB_SHIFT),
+ QCONST16(0.0437314f, DB_SHIFT), QCONST16(0.0221971f, DB_SHIFT), QCONST16(0.0111839f, DB_SHIFT), QCONST16(0.0056136f, DB_SHIFT),
+ QCONST16(0.0028123f, DB_SHIFT)
+ };
+ int low;
+ if (a>b)
+ {
+ max = a;
+ diff = SUB32(EXTEND32(a),EXTEND32(b));
+ } else {
+ max = b;
+ diff = SUB32(EXTEND32(b),EXTEND32(a));
+ }
+ if (diff >= QCONST16(8.f, DB_SHIFT))
+ return max;
+#ifdef OPUS_FIXED_POINT
+ low = SHR32(diff, DB_SHIFT-1);
+ frac = SHL16(diff - SHL16(low, DB_SHIFT-1), 16-DB_SHIFT);
+#else
+ low = (int)floor(2*diff);
+ frac = 2*diff - low;
+#endif
+ return max + diff_table[low] + MULT16_16_Q15(frac, SUB16(diff_table[low+1], diff_table[low]));
+}
+#else
+opus_val16 logSum(opus_val16 a, opus_val16 b)
+{
+ return log2(pow(4, a)+ pow(4, b))/2;
+}
+#endif
+
+void surround_analysis(const CELTMode *celt_mode, const void *pcm, opus_val16 *bandLogE, opus_val32 *mem, opus_val32 *preemph_mem,
+ int len, int overlap, int channels, int rate, opus_copy_channel_in_func copy_channel_in
+)
+{
+ int c;
+ int i;
+ int LM;
+ int pos[8] = {0};
+ int upsample;
+ int frame_size;
+ opus_val16 channel_offset;
+ opus_val32 bandE[21];
+ opus_val16 maskLogE[3][21];
+ VARDECL(opus_val32, in);
+ VARDECL(opus_val16, x);
+ VARDECL(opus_val32, freq);
+ SAVE_STACK;
+
+ upsample = resampling_factor(rate);
+ frame_size = len*upsample;
+
+ for (LM=0;LM<celt_mode->maxLM;LM++)
+ if (celt_mode->shortMdctSize<<LM==frame_size)
+ break;
+
+ ALLOC(in, frame_size+overlap, opus_val32);
+ ALLOC(x, len, opus_val16);
+ ALLOC(freq, frame_size, opus_val32);
+
+ channel_pos(channels, pos);
+
+ for (c=0;c<3;c++)
+ for (i=0;i<21;i++)
+ maskLogE[c][i] = -QCONST16(28.f, DB_SHIFT);
+
+ for (c=0;c<channels;c++)
+ {
+ OPUS_COPY(in, mem+c*overlap, overlap);
+ (*copy_channel_in)(x, 1, pcm, channels, c, len);
+ celt_preemphasis(x, in+overlap, frame_size, 1, upsample, celt_mode->preemph, preemph_mem+c, 0);
+ clt_mdct_forward(&celt_mode->mdct, in, freq, celt_mode->window, overlap, celt_mode->maxLM-LM, 1);
+ if (upsample != 1)
+ {
+ int bound = len;
+ for (i=0;i<bound;i++)
+ freq[i] *= upsample;
+ for (;i<frame_size;i++)
+ freq[i] = 0;
+ }
+
+ compute_band_energies(celt_mode, freq, bandE, 21, 1, 1<<LM);
+ amp2Log2(celt_mode, 21, 21, bandE, bandLogE+21*c, 1);
+ /* Apply spreading function with -6 dB/band going up and -12 dB/band going down. */
+ for (i=1;i<21;i++)
+ bandLogE[21*c+i] = MAX16(bandLogE[21*c+i], bandLogE[21*c+i-1]-QCONST16(1.f, DB_SHIFT));
+ for (i=19;i>=0;i--)
+ bandLogE[21*c+i] = MAX16(bandLogE[21*c+i], bandLogE[21*c+i+1]-QCONST16(2.f, DB_SHIFT));
+ if (pos[c]==1)
+ {
+ for (i=0;i<21;i++)
+ maskLogE[0][i] = logSum(maskLogE[0][i], bandLogE[21*c+i]);
+ } else if (pos[c]==3)
+ {
+ for (i=0;i<21;i++)
+ maskLogE[2][i] = logSum(maskLogE[2][i], bandLogE[21*c+i]);
+ } else if (pos[c]==2)
+ {
+ for (i=0;i<21;i++)
+ {
+ maskLogE[0][i] = logSum(maskLogE[0][i], bandLogE[21*c+i]-QCONST16(.5f, DB_SHIFT));
+ maskLogE[2][i] = logSum(maskLogE[2][i], bandLogE[21*c+i]-QCONST16(.5f, DB_SHIFT));
+ }
+ }
+#if 0
+ for (i=0;i<21;i++)
+ printf("%f ", bandLogE[21*c+i]);
+ float sum=0;
+ for (i=0;i<21;i++)
+ sum += bandLogE[21*c+i];
+ printf("%f ", sum/21);
+#endif
+ OPUS_COPY(mem+c*overlap, in+frame_size, overlap);
+ }
+ for (i=0;i<21;i++)
+ maskLogE[1][i] = MIN32(maskLogE[0][i],maskLogE[2][i]);
+ channel_offset = HALF16(celt_log2(QCONST32(2.f,14)/(channels-1)));
+ for (c=0;c<3;c++)
+ for (i=0;i<21;i++)
+ maskLogE[c][i] += channel_offset;
+#if 0
+ for (c=0;c<3;c++)
+ {
+ for (i=0;i<21;i++)
+ printf("%f ", maskLogE[c][i]);
+ }
+#endif
+ for (c=0;c<channels;c++)
+ {
+ opus_val16 *mask;
+ if (pos[c]!=0)
+ {
+ mask = &maskLogE[pos[c]-1][0];
+ for (i=0;i<21;i++)
+ bandLogE[21*c+i] = bandLogE[21*c+i] - mask[i];
+ } else {
+ for (i=0;i<21;i++)
+ bandLogE[21*c+i] = 0;
+ }
+#if 0
+ for (i=0;i<21;i++)
+ printf("%f ", bandLogE[21*c+i]);
+ printf("\n");
+#endif
+#if 0
+ float sum=0;
+ for (i=0;i<21;i++)
+ sum += bandLogE[21*c+i];
+ printf("%f ", sum/(float)QCONST32(21.f, DB_SHIFT));
+ printf("\n");
+#endif
+ }
+ RESTORE_STACK;
+}
+
+opus_int32 opus_multistream_encoder_get_size(int nb_streams, int nb_coupled_streams)
+{
+ int coupled_size;
+ int mono_size;
+
+ if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0;
+ coupled_size = opus_encoder_get_size(2);
+ mono_size = opus_encoder_get_size(1);
+ return align(sizeof(OpusMSEncoder))
+ + nb_coupled_streams * align(coupled_size)
+ + (nb_streams-nb_coupled_streams) * align(mono_size);
+}
+
+opus_int32 opus_multistream_surround_encoder_get_size(int channels, int mapping_family)
+{
+ int nb_streams;
+ int nb_coupled_streams;
+ opus_int32 size;
+
+ if (mapping_family==0)
+ {
+ if (channels==1)
+ {
+ nb_streams=1;
+ nb_coupled_streams=0;
+ } else if (channels==2)
+ {
+ nb_streams=1;
+ nb_coupled_streams=1;
+ } else
+ return 0;
+ } else if (mapping_family==1 && channels<=8 && channels>=1)
+ {
+ nb_streams=vorbis_mappings[channels-1].nb_streams;
+ nb_coupled_streams=vorbis_mappings[channels-1].nb_coupled_streams;
+ } else if (mapping_family==255)
+ {
+ nb_streams=channels;
+ nb_coupled_streams=0;
+ } else
+ return 0;
+ size = opus_multistream_encoder_get_size(nb_streams, nb_coupled_streams);
+ if (channels>2)
+ {
+ size += channels*(120*sizeof(opus_val32) + sizeof(opus_val32));
+ }
+ return size;
+}
+
+
+static int opus_multistream_encoder_init_impl(
+ OpusMSEncoder *st,
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping,
+ int application,
+ int surround
+)
+{
+ int coupled_size;
+ int mono_size;
+ int i, ret;
+ char *ptr;
+
+ if ((channels>255) || (channels<1) || (coupled_streams>streams) ||
+ (coupled_streams+streams>255) || (streams<1) || (coupled_streams<0))
+ return OPUS_BAD_ARG;
+
+ st->layout.nb_channels = channels;
+ st->layout.nb_streams = streams;
+ st->layout.nb_coupled_streams = coupled_streams;
+ st->subframe_mem[0]=st->subframe_mem[1]=st->subframe_mem[2]=0;
+ if (!surround)
+ st->lfe_stream = -1;
+ st->bitrate_bps = OPUS_AUTO;
+ st->application = application;
+ st->variable_duration = OPUS_FRAMESIZE_ARG;
+ for (i=0;i<st->layout.nb_channels;i++)
+ st->layout.mapping[i] = mapping[i];
+ if (!validate_layout(&st->layout) || !validate_encoder_layout(&st->layout))
+ return OPUS_BAD_ARG;
+ ptr = (char*)st + align(sizeof(OpusMSEncoder));
+ coupled_size = opus_encoder_get_size(2);
+ mono_size = opus_encoder_get_size(1);
+
+ for (i=0;i<st->layout.nb_coupled_streams;i++)
+ {
+ ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 2, application);
+ if(ret!=OPUS_OK)return ret;
+ if (i==st->lfe_stream)
+ opus_encoder_ctl((OpusEncoder*)ptr, OPUS_SET_LFE(1));
+ ptr += align(coupled_size);
+ }
+ for (;i<st->layout.nb_streams;i++)
+ {
+ ret = opus_encoder_init((OpusEncoder*)ptr, Fs, 1, application);
+ if (i==st->lfe_stream)
+ opus_encoder_ctl((OpusEncoder*)ptr, OPUS_SET_LFE(1));
+ if(ret!=OPUS_OK)return ret;
+ ptr += align(mono_size);
+ }
+ if (surround)
+ {
+ OPUS_CLEAR(ms_get_preemph_mem(st), channels);
+ OPUS_CLEAR(ms_get_window_mem(st), channels*120);
+ }
+ st->surround = surround;
+ return OPUS_OK;
+}
+
+int opus_multistream_encoder_init(
+ OpusMSEncoder *st,
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping,
+ int application
+)
+{
+ return opus_multistream_encoder_init_impl(st, Fs, channels, streams, coupled_streams, mapping, application, 0);
+}
+
+int opus_multistream_surround_encoder_init(
+ OpusMSEncoder *st,
+ opus_int32 Fs,
+ int channels,
+ int mapping_family,
+ int *streams,
+ int *coupled_streams,
+ unsigned char *mapping,
+ int application
+)
+{
+ if ((channels>255) || (channels<1))
+ return OPUS_BAD_ARG;
+ st->lfe_stream = -1;
+ if (mapping_family==0)
+ {
+ if (channels==1)
+ {
+ *streams=1;
+ *coupled_streams=0;
+ mapping[0]=0;
+ } else if (channels==2)
+ {
+ *streams=1;
+ *coupled_streams=1;
+ mapping[0]=0;
+ mapping[1]=1;
+ } else
+ return OPUS_UNIMPLEMENTED;
+ } else if (mapping_family==1 && channels<=8 && channels>=1)
+ {
+ int i;
+ *streams=vorbis_mappings[channels-1].nb_streams;
+ *coupled_streams=vorbis_mappings[channels-1].nb_coupled_streams;
+ for (i=0;i<channels;i++)
+ mapping[i] = vorbis_mappings[channels-1].mapping[i];
+ if (channels>=6)
+ st->lfe_stream = *streams-1;
+ } else if (mapping_family==255)
+ {
+ int i;
+ *streams=channels;
+ *coupled_streams=0;
+ for(i=0;i<channels;i++)
+ mapping[i] = i;
+ } else
+ return OPUS_UNIMPLEMENTED;
+ return opus_multistream_encoder_init_impl(st, Fs, channels, *streams, *coupled_streams,
+ mapping, application, channels>2&&mapping_family==1);
+}
+
+OpusMSEncoder *opus_multistream_encoder_create(
+ opus_int32 Fs,
+ int channels,
+ int streams,
+ int coupled_streams,
+ const unsigned char *mapping,
+ int application,
+ int *error
+)
+{
+ int ret;
+ OpusMSEncoder *st;
+ if ((channels>255) || (channels<1) || (coupled_streams>streams) ||
+ (coupled_streams+streams>255) || (streams<1) || (coupled_streams<0))
+ {
+ if (error)
+ *error = OPUS_BAD_ARG;
+ return NULL;
+ }
+ st = (OpusMSEncoder *)opus_alloc(opus_multistream_encoder_get_size(streams, coupled_streams));
+ if (st==NULL)
+ {
+ if (error)
+ *error = OPUS_ALLOC_FAIL;
+ return NULL;
+ }
+ ret = opus_multistream_encoder_init(st, Fs, channels, streams, coupled_streams, mapping, application);
+ if (ret != OPUS_OK)
+ {
+ opus_free(st);
+ st = NULL;
+ }
+ if (error)
+ *error = ret;
+ return st;
+}
+
+OpusMSEncoder *opus_multistream_surround_encoder_create(
+ opus_int32 Fs,
+ int channels,
+ int mapping_family,
+ int *streams,
+ int *coupled_streams,
+ unsigned char *mapping,
+ int application,
+ int *error
+)
+{
+ int ret;
+ OpusMSEncoder *st;
+ if ((channels>255) || (channels<1))
+ {
+ if (error)
+ *error = OPUS_BAD_ARG;
+ return NULL;
+ }
+ st = (OpusMSEncoder *)opus_alloc(opus_multistream_surround_encoder_get_size(channels, mapping_family));
+ if (st==NULL)
+ {
+ if (error)
+ *error = OPUS_ALLOC_FAIL;
+ return NULL;
+ }
+ ret = opus_multistream_surround_encoder_init(st, Fs, channels, mapping_family, streams, coupled_streams, mapping, application);
+ if (ret != OPUS_OK)
+ {
+ opus_free(st);
+ st = NULL;
+ }
+ if (error)
+ *error = ret;
+ return st;
+}
+
+static void surround_rate_allocation(
+ OpusMSEncoder *st,
+ opus_int32 *rate,
+ int frame_size
+ )
+{
+ int i;
+ opus_int32 channel_rate;
+ opus_int32 Fs;
+ char *ptr;
+ int stream_offset;
+ int lfe_offset;
+ int coupled_ratio; /* Q8 */
+ int lfe_ratio; /* Q8 */
+
+ ptr = (char*)st + align(sizeof(OpusMSEncoder));
+ opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs));
+
+ if (st->bitrate_bps > st->layout.nb_channels*40000)
+ stream_offset = 20000;
+ else
+ stream_offset = st->bitrate_bps/st->layout.nb_channels/2;
+ stream_offset += 60*(Fs/frame_size-50);
+ /* We start by giving each stream (coupled or uncoupled) the same bitrate.
+ This models the main saving of coupled channels over uncoupled. */
+ /* The LFE stream is an exception to the above and gets fewer bits. */
+ lfe_offset = 3500 + 60*(Fs/frame_size-50);
+ /* Coupled streams get twice the mono rate after the first 20 kb/s. */
+ coupled_ratio = 512;
+ /* Should depend on the bitrate, for now we assume LFE gets 1/8 the bits of mono */
+ lfe_ratio = 32;
+
+ /* Compute bitrate allocation between streams */
+ if (st->bitrate_bps==OPUS_AUTO)
+ {
+ channel_rate = Fs+60*Fs/frame_size;
+ } else if (st->bitrate_bps==OPUS_BITRATE_MAX)
+ {
+ channel_rate = 300000;
+ } else {
+ int nb_lfe;
+ int nb_uncoupled;
+ int nb_coupled;
+ int total;
+ nb_lfe = (st->lfe_stream!=-1);
+ nb_coupled = st->layout.nb_coupled_streams;
+ nb_uncoupled = st->layout.nb_streams-nb_coupled-nb_lfe;
+ total = (nb_uncoupled<<8) /* mono */
+ + coupled_ratio*nb_coupled /* stereo */
+ + nb_lfe*lfe_ratio;
+ channel_rate = 256*(st->bitrate_bps-lfe_offset*nb_lfe-stream_offset*(nb_coupled+nb_uncoupled))/total;
+ }
+#ifndef OPUS_FIXED_POINT
+ if (st->variable_duration==OPUS_FRAMESIZE_VARIABLE && frame_size != Fs/50)
+ {
+ opus_int32 bonus;
+ bonus = 60*(Fs/frame_size-50);
+ channel_rate += bonus;
+ }
+#endif
+
+ for (i=0;i<st->layout.nb_streams;i++)
+ {
+ if (i<st->layout.nb_coupled_streams)
+ rate[i] = stream_offset+(channel_rate*coupled_ratio>>8);
+ else if (i!=st->lfe_stream)
+ rate[i] = stream_offset+channel_rate;
+ else
+ rate[i] = lfe_offset+(channel_rate*lfe_ratio>>8);
+ }
+}
+
+/* Max size in case the encoder decides to return three frames */
+#define MS_FRAME_TMP (3*1275+7)
+static int opus_multistream_encode_native
+(
+ OpusMSEncoder *st,
+ opus_copy_channel_in_func copy_channel_in,
+ const void *pcm,
+ int analysis_frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes,
+ int lsb_depth,
+ downmix_func downmix
+)
+{
+ opus_int32 Fs;
+ int coupled_size;
+ int mono_size;
+ int s;
+ char *ptr;
+ int tot_size;
+ VARDECL(opus_val16, buf);
+ VARDECL(opus_val16, bandSMR);
+ unsigned char tmp_data[MS_FRAME_TMP];
+ OpusRepacketizer rp;
+ opus_int32 vbr;
+ const CELTMode *celt_mode;
+ opus_int32 bitrates[256];
+ opus_val16 bandLogE[42];
+ opus_val32 *mem = NULL;
+ opus_val32 *preemph_mem=NULL;
+ int frame_size;
+ ALLOC_STACK;
+
+ if (st->surround)
+ {
+ preemph_mem = ms_get_preemph_mem(st);
+ mem = ms_get_window_mem(st);
+ }
+
+ ptr = (char*)st + align(sizeof(OpusMSEncoder));
+ opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs));
+ opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_VBR(&vbr));
+ opus_encoder_ctl((OpusEncoder*)ptr, CELT_GET_MODE(&celt_mode));
+
+ {
+ opus_int32 delay_compensation;
+ int channels;
+
+ channels = st->layout.nb_streams + st->layout.nb_coupled_streams;
+ opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_LOOKAHEAD(&delay_compensation));
+ delay_compensation -= Fs/400;
+ frame_size = compute_frame_size(pcm, analysis_frame_size,
+ st->variable_duration, channels, Fs, st->bitrate_bps,
+ delay_compensation, downmix
+#ifndef DISABLE_FLOAT_API
+ , st->subframe_mem
+#endif
+ );
+ }
+
+ if (400*frame_size < Fs)
+ {
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ }
+ /* Validate frame_size before using it to allocate stack space.
+ This mirrors the checks in opus_encode[_float](). */
+ if (400*frame_size != Fs && 200*frame_size != Fs &&
+ 100*frame_size != Fs && 50*frame_size != Fs &&
+ 25*frame_size != Fs && 50*frame_size != 3*Fs)
+ {
+ RESTORE_STACK;
+ return OPUS_BAD_ARG;
+ }
+ ALLOC(buf, 2*frame_size, opus_val16);
+ coupled_size = opus_encoder_get_size(2);
+ mono_size = opus_encoder_get_size(1);
+
+ ALLOC(bandSMR, 21*st->layout.nb_channels, opus_val16);
+ if (st->surround)
+ {
+ surround_analysis(celt_mode, pcm, bandSMR, mem, preemph_mem, frame_size, 120, st->layout.nb_channels, Fs, copy_channel_in);
+ }
+
+ if (max_data_bytes < 4*st->layout.nb_streams-1)
+ {
+ RESTORE_STACK;
+ return OPUS_BUFFER_TOO_SMALL;
+ }
+
+ /* Compute bitrate allocation between streams (this could be a lot better) */
+ surround_rate_allocation(st, bitrates, frame_size);
+
+ if (!vbr)
+ max_data_bytes = IMIN(max_data_bytes, 3*st->bitrate_bps/(3*8*Fs/frame_size));
+
+ ptr = (char*)st + align(sizeof(OpusMSEncoder));
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ OpusEncoder *enc;
+ enc = (OpusEncoder*)ptr;
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrates[s]));
+ if (st->surround)
+ {
+ opus_int32 equiv_rate;
+ equiv_rate = st->bitrate_bps;
+ if (frame_size*50 < Fs)
+ equiv_rate -= 60*(Fs/frame_size - 50)*st->layout.nb_channels;
+ if (equiv_rate > 10000*st->layout.nb_channels)
+ opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_FULLBAND));
+ else if (equiv_rate > 7000*st->layout.nb_channels)
+ opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_SUPERWIDEBAND));
+ else if (equiv_rate > 5000*st->layout.nb_channels)
+ opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_WIDEBAND));
+ else
+ opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(OPUS_BANDWIDTH_NARROWBAND));
+ if (s < st->layout.nb_coupled_streams)
+ {
+ /* To preserve the spatial image, force stereo CELT on coupled streams */
+ opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY));
+ opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(2));
+ }
+ }
+ }
+
+ ptr = (char*)st + align(sizeof(OpusMSEncoder));
+ /* Counting ToC */
+ tot_size = 0;
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ OpusEncoder *enc;
+ int len;
+ int curr_max;
+ int c1, c2;
+
+ opus_repacketizer_init(&rp);
+ enc = (OpusEncoder*)ptr;
+ if (s < st->layout.nb_coupled_streams)
+ {
+ int i;
+ int left, right;
+ left = get_left_channel(&st->layout, s, -1);
+ right = get_right_channel(&st->layout, s, -1);
+ (*copy_channel_in)(buf, 2,
+ pcm, st->layout.nb_channels, left, frame_size);
+ (*copy_channel_in)(buf+1, 2,
+ pcm, st->layout.nb_channels, right, frame_size);
+ ptr += align(coupled_size);
+ if (st->surround)
+ {
+ for (i=0;i<21;i++)
+ {
+ bandLogE[i] = bandSMR[21*left+i];
+ bandLogE[21+i] = bandSMR[21*right+i];
+ }
+ }
+ c1 = left;
+ c2 = right;
+ } else {
+ int i;
+ int chan = get_mono_channel(&st->layout, s, -1);
+ (*copy_channel_in)(buf, 1,
+ pcm, st->layout.nb_channels, chan, frame_size);
+ ptr += align(mono_size);
+ if (st->surround)
+ {
+ for (i=0;i<21;i++)
+ bandLogE[i] = bandSMR[21*chan+i];
+ }
+ c1 = chan;
+ c2 = -1;
+ }
+ if (st->surround)
+ opus_encoder_ctl(enc, OPUS_SET_ENERGY_MASK(bandLogE));
+ /* number of bytes left (+Toc) */
+ curr_max = max_data_bytes - tot_size;
+ /* Reserve three bytes for the last stream and four for the others */
+ curr_max -= IMAX(0,4*(st->layout.nb_streams-s-1)-1);
+ curr_max = IMIN(curr_max,MS_FRAME_TMP);
+ if (!vbr && s == st->layout.nb_streams-1)
+ opus_encoder_ctl(enc, OPUS_SET_BITRATE(curr_max*(8*Fs/frame_size)));
+ len = opus_encode_native(enc, buf, frame_size, tmp_data, curr_max, lsb_depth,
+ pcm, analysis_frame_size, c1, c2, st->layout.nb_channels, downmix);
+ if (len<0)
+ {
+ RESTORE_STACK;
+ return len;
+ }
+ /* We need to use the repacketizer to add the self-delimiting lengths
+ while taking into account the fact that the encoder can now return
+ more than one frame at a time (e.g. 60 ms CELT-only) */
+ opus_repacketizer_cat(&rp, tmp_data, len);
+ len = opus_repacketizer_out_range_impl(&rp, 0, opus_repacketizer_get_nb_frames(&rp),
+ data, max_data_bytes-tot_size, s != st->layout.nb_streams-1, !vbr && s == st->layout.nb_streams-1);
+ data += len;
+ tot_size += len;
+ }
+ /*printf("\n");*/
+ RESTORE_STACK;
+ return tot_size;
+}
+
+#if !defined(DISABLE_FLOAT_API)
+static void opus_copy_channel_in_float(
+ opus_val16 *dst,
+ int dst_stride,
+ const void *src,
+ int src_stride,
+ int src_channel,
+ int frame_size
+)
+{
+ const float *float_src;
+ opus_int32 i;
+ float_src = (const float *)src;
+ for (i=0;i<frame_size;i++)
+#if defined(OPUS_FIXED_POINT)
+ dst[i*dst_stride] = FLOAT2INT16(float_src[i*src_stride+src_channel]);
+#else
+ dst[i*dst_stride] = float_src[i*src_stride+src_channel];
+#endif
+}
+#endif
+
+static void opus_copy_channel_in_short(
+ opus_val16 *dst,
+ int dst_stride,
+ const void *src,
+ int src_stride,
+ int src_channel,
+ int frame_size
+)
+{
+ const opus_int16 *short_src;
+ opus_int32 i;
+ short_src = (const opus_int16 *)src;
+ for (i=0;i<frame_size;i++)
+#if defined(OPUS_FIXED_POINT)
+ dst[i*dst_stride] = short_src[i*src_stride+src_channel];
+#else
+ dst[i*dst_stride] = (1/32768.f)*short_src[i*src_stride+src_channel];
+#endif
+}
+
+
+#ifdef OPUS_FIXED_POINT
+int opus_multistream_encode(
+ OpusMSEncoder *st,
+ const opus_val16 *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+)
+{
+ return opus_multistream_encode_native(st, opus_copy_channel_in_short,
+ pcm, frame_size, data, max_data_bytes, 16, downmix_int);
+}
+
+#ifndef DISABLE_FLOAT_API
+int opus_multistream_encode_float(
+ OpusMSEncoder *st,
+ const float *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+)
+{
+ return opus_multistream_encode_native(st, opus_copy_channel_in_float,
+ pcm, frame_size, data, max_data_bytes, 16, downmix_float);
+}
+#endif
+
+#else
+
+int opus_multistream_encode_float
+(
+ OpusMSEncoder *st,
+ const opus_val16 *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+)
+{
+ return opus_multistream_encode_native(st, opus_copy_channel_in_float,
+ pcm, frame_size, data, max_data_bytes, 24, downmix_float);
+}
+
+int opus_multistream_encode(
+ OpusMSEncoder *st,
+ const opus_int16 *pcm,
+ int frame_size,
+ unsigned char *data,
+ opus_int32 max_data_bytes
+)
+{
+ return opus_multistream_encode_native(st, opus_copy_channel_in_short,
+ pcm, frame_size, data, max_data_bytes, 16, downmix_int);
+}
+#endif
+
+int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...)
+{
+ va_list ap;
+ int coupled_size, mono_size;
+ char *ptr;
+ int ret = OPUS_OK;
+
+ va_start(ap, request);
+
+ coupled_size = opus_encoder_get_size(2);
+ mono_size = opus_encoder_get_size(1);
+ ptr = (char*)st + align(sizeof(OpusMSEncoder));
+ switch (request)
+ {
+ case OPUS_SET_BITRATE_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ if (value<0 && value!=OPUS_AUTO && value!=OPUS_BITRATE_MAX)
+ {
+ goto bad_arg;
+ }
+ st->bitrate_bps = value;
+ }
+ break;
+ case OPUS_GET_BITRATE_REQUEST:
+ {
+ int s;
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = 0;
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ opus_int32 rate;
+ OpusEncoder *enc;
+ enc = (OpusEncoder*)ptr;
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ opus_encoder_ctl(enc, request, &rate);
+ *value += rate;
+ }
+ }
+ break;
+ case OPUS_GET_LSB_DEPTH_REQUEST:
+ case OPUS_GET_VBR_REQUEST:
+ case OPUS_GET_APPLICATION_REQUEST:
+ case OPUS_GET_BANDWIDTH_REQUEST:
+ case OPUS_GET_COMPLEXITY_REQUEST:
+ case OPUS_GET_PACKET_LOSS_PERC_REQUEST:
+ case OPUS_GET_DTX_REQUEST:
+ case OPUS_GET_VOICE_RATIO_REQUEST:
+ case OPUS_GET_VBR_CONSTRAINT_REQUEST:
+ case OPUS_GET_SIGNAL_REQUEST:
+ case OPUS_GET_LOOKAHEAD_REQUEST:
+ case OPUS_GET_SAMPLE_RATE_REQUEST:
+ case OPUS_GET_INBAND_FEC_REQUEST:
+ case OPUS_GET_FORCE_CHANNELS_REQUEST:
+ case OPUS_GET_PREDICTION_DISABLED_REQUEST:
+ {
+ OpusEncoder *enc;
+ /* For int32* GET params, just query the first stream */
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ enc = (OpusEncoder*)ptr;
+ ret = opus_encoder_ctl(enc, request, value);
+ }
+ break;
+ case OPUS_GET_FINAL_RANGE_REQUEST:
+ {
+ int s;
+ opus_uint32 *value = va_arg(ap, opus_uint32*);
+ opus_uint32 tmp;
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value=0;
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ OpusEncoder *enc;
+ enc = (OpusEncoder*)ptr;
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ ret = opus_encoder_ctl(enc, request, &tmp);
+ if (ret != OPUS_OK) break;
+ *value ^= tmp;
+ }
+ }
+ break;
+ case OPUS_SET_LSB_DEPTH_REQUEST:
+ case OPUS_SET_COMPLEXITY_REQUEST:
+ case OPUS_SET_VBR_REQUEST:
+ case OPUS_SET_VBR_CONSTRAINT_REQUEST:
+ case OPUS_SET_MAX_BANDWIDTH_REQUEST:
+ case OPUS_SET_BANDWIDTH_REQUEST:
+ case OPUS_SET_SIGNAL_REQUEST:
+ case OPUS_SET_APPLICATION_REQUEST:
+ case OPUS_SET_INBAND_FEC_REQUEST:
+ case OPUS_SET_PACKET_LOSS_PERC_REQUEST:
+ case OPUS_SET_DTX_REQUEST:
+ case OPUS_SET_FORCE_MODE_REQUEST:
+ case OPUS_SET_FORCE_CHANNELS_REQUEST:
+ case OPUS_SET_PREDICTION_DISABLED_REQUEST:
+ {
+ int s;
+ /* This works for int32 params */
+ opus_int32 value = va_arg(ap, opus_int32);
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ OpusEncoder *enc;
+
+ enc = (OpusEncoder*)ptr;
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ ret = opus_encoder_ctl(enc, request, value);
+ if (ret != OPUS_OK)
+ break;
+ }
+ }
+ break;
+ case OPUS_MULTISTREAM_GET_ENCODER_STATE_REQUEST:
+ {
+ int s;
+ opus_int32 stream_id;
+ OpusEncoder **value;
+ stream_id = va_arg(ap, opus_int32);
+ if (stream_id<0 || stream_id >= st->layout.nb_streams)
+ ret = OPUS_BAD_ARG;
+ value = va_arg(ap, OpusEncoder**);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ for (s=0;s<stream_id;s++)
+ {
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ }
+ *value = (OpusEncoder*)ptr;
+ }
+ break;
+ case OPUS_SET_EXPERT_FRAME_DURATION_REQUEST:
+ {
+ opus_int32 value = va_arg(ap, opus_int32);
+ st->variable_duration = value;
+ }
+ break;
+ case OPUS_GET_EXPERT_FRAME_DURATION_REQUEST:
+ {
+ opus_int32 *value = va_arg(ap, opus_int32*);
+ if (!value)
+ {
+ goto bad_arg;
+ }
+ *value = st->variable_duration;
+ }
+ break;
+ case OPUS_RESET_STATE:
+ {
+ int s;
+ st->subframe_mem[0] = st->subframe_mem[1] = st->subframe_mem[2] = 0;
+ if (st->surround)
+ {
+ OPUS_CLEAR(ms_get_preemph_mem(st), st->layout.nb_channels);
+ OPUS_CLEAR(ms_get_window_mem(st), st->layout.nb_channels*120);
+ }
+ for (s=0;s<st->layout.nb_streams;s++)
+ {
+ OpusEncoder *enc;
+ enc = (OpusEncoder*)ptr;
+ if (s < st->layout.nb_coupled_streams)
+ ptr += align(coupled_size);
+ else
+ ptr += align(mono_size);
+ ret = opus_encoder_ctl(enc, OPUS_RESET_STATE);
+ if (ret != OPUS_OK)
+ break;
+ }
+ }
+ break;
+ default:
+ ret = OPUS_UNIMPLEMENTED;
+ break;
+ }
+
+ va_end(ap);
+ return ret;
+bad_arg:
+ va_end(ap);
+ return OPUS_BAD_ARG;
+}
+
+void opus_multistream_encoder_destroy(OpusMSEncoder *st)
+{
+ opus_free(st);
+}
diff --git a/drivers/opus/opus_private.h b/drivers/opus/opus_private.h
new file mode 100644
index 0000000000..d63ed4f051
--- /dev/null
+++ b/drivers/opus/opus_private.h
@@ -0,0 +1,129 @@
+/* Copyright (c) 2012 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef OPUS_PRIVATE_H
+#define OPUS_PRIVATE_H
+
+#include "opus/celt/arch.h"
+#include "opus/opus.h"
+#include "opus/celt/celt.h"
+
+struct OpusRepacketizer {
+ unsigned char toc;
+ int nb_frames;
+ const unsigned char *frames[48];
+ opus_int16 len[48];
+ int framesize;
+};
+
+typedef struct ChannelLayout {
+ int nb_channels;
+ int nb_streams;
+ int nb_coupled_streams;
+ unsigned char mapping[256];
+} ChannelLayout;
+
+int validate_layout(const ChannelLayout *layout);
+int get_left_channel(const ChannelLayout *layout, int stream_id, int prev);
+int get_right_channel(const ChannelLayout *layout, int stream_id, int prev);
+int get_mono_channel(const ChannelLayout *layout, int stream_id, int prev);
+
+
+
+#define MODE_SILK_ONLY 1000
+#define MODE_HYBRID 1001
+#define MODE_CELT_ONLY 1002
+
+#define OPUS_SET_VOICE_RATIO_REQUEST 11018
+#define OPUS_GET_VOICE_RATIO_REQUEST 11019
+
+/** Configures the encoder's expected percentage of voice
+ * opposed to music or other signals.
+ *
+ * @note This interface is currently more aspiration than actuality. It's
+ * ultimately expected to bias an automatic signal classifier, but it currently
+ * just shifts the static bitrate to mode mapping around a little bit.
+ *
+ * @param[in] x <tt>int</tt>: Voice percentage in the range 0-100, inclusive.
+ * @hideinitializer */
+#define OPUS_SET_VOICE_RATIO(x) OPUS_SET_VOICE_RATIO_REQUEST, __opus_check_int(x)
+/** Gets the encoder's configured voice ratio value, @see OPUS_SET_VOICE_RATIO
+ *
+ * @param[out] x <tt>int*</tt>: Voice percentage in the range 0-100, inclusive.
+ * @hideinitializer */
+#define OPUS_GET_VOICE_RATIO(x) OPUS_GET_VOICE_RATIO_REQUEST, __opus_check_int_ptr(x)
+
+
+#define OPUS_SET_FORCE_MODE_REQUEST 11002
+#define OPUS_SET_FORCE_MODE(x) OPUS_SET_FORCE_MODE_REQUEST, __opus_check_int(x)
+
+typedef void (*downmix_func)(const void *, opus_val32 *, int, int, int, int, int);
+void downmix_float(const void *_x, opus_val32 *sub, int subframe, int offset, int c1, int c2, int C);
+void downmix_int(const void *_x, opus_val32 *sub, int subframe, int offset, int c1, int c2, int C);
+
+int optimize_framesize(const opus_val16 *x, int len, int C, opus_int32 Fs,
+ int bitrate, opus_val16 tonality, float *mem, int buffering,
+ downmix_func downmix);
+
+int encode_size(int size, unsigned char *data);
+
+opus_int32 frame_size_select(opus_int32 frame_size, int variable_duration, opus_int32 Fs);
+
+opus_int32 compute_frame_size(const void *analysis_pcm, int frame_size,
+ int variable_duration, int C, opus_int32 Fs, int bitrate_bps,
+ int delay_compensation, downmix_func downmix
+#ifndef DISABLE_FLOAT_API
+ , float *subframe_mem
+#endif
+ );
+
+opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
+ unsigned char *data, opus_int32 out_data_bytes, int lsb_depth,
+ const void *analysis_pcm, opus_int32 analysis_size, int c1, int c2, int analysis_channels, downmix_func downmix);
+
+int opus_decode_native(OpusDecoder *st, const unsigned char *data, opus_int32 len,
+ opus_val16 *pcm, int frame_size, int decode_fec, int self_delimited,
+ opus_int32 *packet_offset, int soft_clip);
+
+/* Make sure everything's aligned to sizeof(void *) bytes */
+static OPUS_INLINE int align(int i)
+{
+ return (i+(int)sizeof(void *)-1)&-(int)sizeof(void *);
+}
+
+int opus_packet_parse_impl(const unsigned char *data, opus_int32 len,
+ int self_delimited, unsigned char *out_toc,
+ const unsigned char *frames[48], opus_int16 size[48],
+ int *payload_offset, opus_int32 *packet_offset);
+
+opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end,
+ unsigned char *data, opus_int32 maxlen, int self_delimited, int pad);
+
+int pad_frame(unsigned char *data, opus_int32 len, opus_int32 new_len);
+
+#endif /* OPUS_PRIVATE_H */
diff --git a/drivers/opus/opus_types.h b/drivers/opus/opus_types.h
new file mode 100644
index 0000000000..b28e03aea2
--- /dev/null
+++ b/drivers/opus/opus_types.h
@@ -0,0 +1,159 @@
+/* (C) COPYRIGHT 1994-2002 Xiph.Org Foundation */
+/* Modified by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/* opus_types.h based on ogg_types.h from libogg */
+
+/**
+ @file opus_types.h
+ @brief Opus reference implementation types
+*/
+#ifndef OPUS_TYPES_H
+#define OPUS_TYPES_H
+
+/* Use the real stdint.h if it's there (taken from Paul Hsieh's pstdint.h) */
+#if (defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) || defined (HAVE_STDINT_H))
+#include <stdint.h>
+
+ typedef int16_t opus_int16;
+ typedef uint16_t opus_uint16;
+ typedef int32_t opus_int32;
+ typedef uint32_t opus_uint32;
+#elif defined(_WIN32)
+
+# if defined(__CYGWIN__)
+# include <_G_config.h>
+ typedef _G_int32_t opus_int32;
+ typedef _G_uint32_t opus_uint32;
+ typedef _G_int16 opus_int16;
+ typedef _G_uint16 opus_uint16;
+# elif defined(__MINGW32__)
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef int opus_int32;
+ typedef unsigned int opus_uint32;
+# elif defined(__MWERKS__)
+ typedef int opus_int32;
+ typedef unsigned int opus_uint32;
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+# else
+ /* MSVC/Borland */
+ typedef __int32 opus_int32;
+ typedef unsigned __int32 opus_uint32;
+ typedef __int16 opus_int16;
+ typedef unsigned __int16 opus_uint16;
+# endif
+
+#elif defined(__MACOS__)
+
+# include <sys/types.h>
+ typedef SInt16 opus_int16;
+ typedef UInt16 opus_uint16;
+ typedef SInt32 opus_int32;
+ typedef UInt32 opus_uint32;
+
+#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */
+
+# include <sys/types.h>
+ typedef int16_t opus_int16;
+ typedef u_int16_t opus_uint16;
+ typedef int32_t opus_int32;
+ typedef u_int32_t opus_uint32;
+
+#elif defined(__BEOS__)
+
+ /* Be */
+# include <inttypes.h>
+ typedef int16 opus_int16;
+ typedef u_int16 opus_uint16;
+ typedef int32_t opus_int32;
+ typedef u_int32_t opus_uint32;
+
+#elif defined (__EMX__)
+
+ /* OS/2 GCC */
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef int opus_int32;
+ typedef unsigned int opus_uint32;
+
+#elif defined (DJGPP)
+
+ /* DJGPP */
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef int opus_int32;
+ typedef unsigned int opus_uint32;
+
+#elif defined(R5900)
+
+ /* PS2 EE */
+ typedef int opus_int32;
+ typedef unsigned opus_uint32;
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+
+#elif defined(__SYMBIAN32__)
+
+ /* Symbian GCC */
+ typedef signed short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef signed int opus_int32;
+ typedef unsigned int opus_uint32;
+
+#elif defined(CONFIG_TI_C54X) || defined (CONFIG_TI_C55X)
+
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef long opus_int32;
+ typedef unsigned long opus_uint32;
+
+#elif defined(CONFIG_TI_C6X)
+
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef int opus_int32;
+ typedef unsigned int opus_uint32;
+
+#else
+
+ /* Give up, take a reasonable guess */
+ typedef short opus_int16;
+ typedef unsigned short opus_uint16;
+ typedef int opus_int32;
+ typedef unsigned int opus_uint32;
+
+#endif
+
+#define opus_int int /* used for counters etc; at least 16 bits */
+#define opus_int64 long long
+#define opus_int8 signed char
+
+#define opus_uint unsigned int /* used for counters etc; at least 16 bits */
+#define opus_uint64 unsigned long long
+#define opus_uint8 unsigned char
+
+#endif /* OPUS_TYPES_H */
diff --git a/drivers/opus/opusfile.c b/drivers/opus/opusfile.c
new file mode 100644
index 0000000000..a38e8cd5ad
--- /dev/null
+++ b/drivers/opus/opusfile.c
@@ -0,0 +1,3158 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2012 *
+ * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: stdio-based convenience library for opening/seeking/decoding
+ last mod: $Id: vorbisfile.c 17573 2010-10-27 14:53:59Z xiphmont $
+
+ ********************************************************************/
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/internal.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <string.h>
+#include <math.h>
+
+#include "opus/opusfile.h"
+
+/*This implementation is largely based off of libvorbisfile.
+ All of the Ogg bits work roughly the same, though I have made some
+ "improvements" that have not been folded back there, yet.*/
+
+/*A 'chained bitstream' is an Ogg Opus bitstream that contains more than one
+ logical bitstream arranged end to end (the only form of Ogg multiplexing
+ supported by this library.
+ Grouping (parallel multiplexing) is not supported, except to the extent that
+ if there are multiple logical Ogg streams in a single link of the chain, we
+ will ignore all but the first Opus stream we find.*/
+
+/*An Ogg Opus file can be played beginning to end (streamed) without worrying
+ ahead of time about chaining (see opusdec from the opus-tools package).
+ If we have the whole file, however, and want random access
+ (seeking/scrubbing) or desire to know the total length/time of a file, we
+ need to account for the possibility of chaining.*/
+
+/*We can handle things a number of ways.
+ We can determine the entire bitstream structure right off the bat, or find
+ pieces on demand.
+ This library determines and caches structure for the entire bitstream, but
+ builds a virtual decoder on the fly when moving between links in the chain.*/
+
+/*There are also different ways to implement seeking.
+ Enough information exists in an Ogg bitstream to seek to sample-granularity
+ positions in the output.
+ Or, one can seek by picking some portion of the stream roughly in the desired
+ area if we only want coarse navigation through the stream.
+ We implement and expose both strategies.*/
+
+/*The maximum number of bytes in a page (including the page headers).*/
+#define OP_PAGE_SIZE_MAX (65307)
+/*The default amount to seek backwards per step when trying to find the
+ previous page.
+ This must be at least as large as the maximum size of a page.*/
+#define OP_CHUNK_SIZE (65536)
+/*The maximum amount to seek backwards per step when trying to find the
+ previous page.*/
+#define OP_CHUNK_SIZE_MAX (1024*(opus_int32)1024)
+/*A smaller read size is needed for low-rate streaming.*/
+#define OP_READ_SIZE (2048)
+
+int op_test(OpusHead *_head,
+ const unsigned char *_initial_data,size_t _initial_bytes){
+ ogg_sync_state oy;
+ char *data;
+ int err;
+ /*The first page of a normal Opus file will be at most 57 bytes (27 Ogg
+ page header bytes + 1 lacing value + 21 Opus header bytes + 8 channel
+ mapping bytes).
+ It will be at least 47 bytes (27 Ogg page header bytes + 1 lacing value +
+ 19 Opus header bytes using channel mapping family 0).
+ If we don't have at least that much data, give up now.*/
+ if(_initial_bytes<47)return OP_FALSE;
+ /*Only proceed if we start with the magic OggS string.
+ This is to prevent us spending a lot of time allocating memory and looking
+ for Ogg pages in non-Ogg files.*/
+ if(memcmp(_initial_data,"OggS",4)!=0)return OP_ENOTFORMAT;
+ ogg_sync_init(&oy);
+ data=ogg_sync_buffer(&oy,_initial_bytes);
+ if(data!=NULL){
+ ogg_stream_state os;
+ ogg_page og;
+ int ret;
+ memcpy(data,_initial_data,_initial_bytes);
+ ogg_sync_wrote(&oy,_initial_bytes);
+ ogg_stream_init(&os,-1);
+ err=OP_FALSE;
+ do{
+ ogg_packet op;
+ ret=ogg_sync_pageout(&oy,&og);
+ /*Ignore holes.*/
+ if(ret<0)continue;
+ /*Stop if we run out of data.*/
+ if(!ret)break;
+ ogg_stream_reset_serialno(&os,ogg_page_serialno(&og));
+ ogg_stream_pagein(&os,&og);
+ /*Only process the first packet on this page (if it's a BOS packet,
+ it's required to be the only one).*/
+ if(ogg_stream_packetout(&os,&op)==1){
+ if(op.b_o_s){
+ ret=opus_head_parse(_head,op.packet,op.bytes);
+ /*If this didn't look like Opus, keep going.*/
+ if(ret==OP_ENOTFORMAT)continue;
+ /*Otherwise we're done, one way or another.*/
+ err=ret;
+ }
+ /*We finished parsing the headers.
+ There is no Opus to be found.*/
+ else err=OP_ENOTFORMAT;
+ }
+ }
+ while(err==OP_FALSE);
+ ogg_stream_clear(&os);
+ }
+ else err=OP_EFAULT;
+ ogg_sync_clear(&oy);
+ return err;
+}
+
+/*Many, many internal helpers.
+ The intention is not to be confusing.
+ Rampant duplication and monolithic function implementation (though we do have
+ some large, omnibus functions still) would be harder to understand anyway.
+ The high level functions are last.
+ Begin grokking near the end of the file if you prefer to read things
+ top-down.*/
+
+/*The read/seek functions track absolute position within the stream.*/
+
+/*Read a little more data from the file/pipe into the ogg_sync framer.
+ _nbytes: The maximum number of bytes to read.
+ Return: A positive number of bytes read on success, 0 on end-of-file, or a
+ negative value on failure.*/
+static int op_get_data(OggOpusFile *_of,int _nbytes){
+ unsigned char *buffer;
+ int nbytes;
+ OP_ASSERT(_nbytes>0);
+ buffer=(unsigned char *)ogg_sync_buffer(&_of->oy,_nbytes);
+ nbytes=(int)(*_of->callbacks.read)(_of->source,buffer,_nbytes);
+ OP_ASSERT(nbytes<=_nbytes);
+ if(OP_LIKELY(nbytes>0))ogg_sync_wrote(&_of->oy,nbytes);
+ return nbytes;
+}
+
+/*Save a tiny smidge of verbosity to make the code more readable.*/
+static int op_seek_helper(OggOpusFile *_of,opus_int64 _offset){
+ if(_offset==_of->offset)return 0;
+ if(_of->callbacks.seek==NULL
+ ||(*_of->callbacks.seek)(_of->source,_offset,SEEK_SET)){
+ return OP_EREAD;
+ }
+ _of->offset=_offset;
+ ogg_sync_reset(&_of->oy);
+ return 0;
+}
+
+/*Get the current position indicator of the underlying source.
+ This should be the same as the value reported by tell().*/
+static opus_int64 op_position(const OggOpusFile *_of){
+ /*The current position indicator is _not_ simply offset.
+ We may also have unprocessed, buffered data in the sync state.*/
+ return _of->offset+_of->oy.fill-_of->oy.returned;
+}
+
+/*From the head of the stream, get the next page.
+ _boundary specifies if the function is allowed to fetch more data from the
+ stream (and how much) or only use internally buffered data.
+ _boundary: -1: Unbounded search.
+ 0: Read no additional data.
+ Use only cached data.
+ n: Search for the start of a new page up to file position n.
+ Return: n>=0: Found a page at absolute offset n.
+ OP_FALSE: Hit the _boundary limit.
+ OP_EREAD: An underlying read operation failed.
+ OP_BADLINK: We hit end-of-file before reaching _boundary.*/
+static opus_int64 op_get_next_page(OggOpusFile *_of,ogg_page *_og,
+ opus_int64 _boundary){
+ while(_boundary<=0||_of->offset<_boundary){
+ int more;
+ more=ogg_sync_pageseek(&_of->oy,_og);
+ /*Skipped (-more) bytes.*/
+ if(OP_UNLIKELY(more<0))_of->offset-=more;
+ else if(more==0){
+ int read_nbytes;
+ int ret;
+ /*Send more paramedics.*/
+ if(!_boundary)return OP_FALSE;
+ if(_boundary<0)read_nbytes=OP_READ_SIZE;
+ else{
+ opus_int64 position;
+ position=op_position(_of);
+ if(position>=_boundary)return OP_FALSE;
+ read_nbytes=(int)OP_MIN(_boundary-position,OP_READ_SIZE);
+ }
+ ret=op_get_data(_of,read_nbytes);
+ if(OP_UNLIKELY(ret<0))return OP_EREAD;
+ if(OP_UNLIKELY(ret==0)){
+ /*Only fail cleanly on EOF if we didn't have a known boundary.
+ Otherwise, we should have been able to reach that boundary, and this
+ is a fatal error.*/
+ return OP_UNLIKELY(_boundary<0)?OP_FALSE:OP_EBADLINK;
+ }
+ }
+ else{
+ /*Got a page.
+ Return the page start offset and advance the internal offset past the
+ page end.*/
+ opus_int64 page_offset;
+ page_offset=_of->offset;
+ _of->offset+=more;
+ OP_ASSERT(page_offset>=0);
+ return page_offset;
+ }
+ }
+ return OP_FALSE;
+}
+
+static int op_add_serialno(const ogg_page *_og,
+ ogg_uint32_t **_serialnos,int *_nserialnos,int *_cserialnos){
+ ogg_uint32_t *serialnos;
+ int nserialnos;
+ int cserialnos;
+ ogg_uint32_t s;
+ s=ogg_page_serialno(_og);
+ serialnos=*_serialnos;
+ nserialnos=*_nserialnos;
+ cserialnos=*_cserialnos;
+ if(OP_UNLIKELY(nserialnos>=cserialnos)){
+ if(OP_UNLIKELY(cserialnos>INT_MAX-1>>1))return OP_EFAULT;
+ cserialnos=2*cserialnos+1;
+ OP_ASSERT(nserialnos<cserialnos);
+ serialnos=(ogg_uint32_t *)_ogg_realloc(serialnos,
+ sizeof(*serialnos)*cserialnos);
+ if(OP_UNLIKELY(serialnos==NULL))return OP_EFAULT;
+ }
+ serialnos[nserialnos++]=s;
+ *_serialnos=serialnos;
+ *_nserialnos=nserialnos;
+ *_cserialnos=cserialnos;
+ return 0;
+}
+
+/*Returns nonzero if found.*/
+static int op_lookup_serialno(ogg_uint32_t _s,
+ const ogg_uint32_t *_serialnos,int _nserialnos){
+ int i;
+ for(i=0;i<_nserialnos&&_serialnos[i]!=_s;i++);
+ return i<_nserialnos;
+}
+
+static int op_lookup_page_serialno(const ogg_page *_og,
+ const ogg_uint32_t *_serialnos,int _nserialnos){
+ return op_lookup_serialno(ogg_page_serialno(_og),_serialnos,_nserialnos);
+}
+
+typedef struct OpusSeekRecord OpusSeekRecord;
+
+/*We use this to remember the pages we found while enumerating the links of a
+ chained stream.
+ We keep track of the starting and ending offsets, as well as the point we
+ started searching from, so we know where to bisect.
+ We also keep the serial number, so we can tell if the page belonged to the
+ current link or not, as well as the granule position, to aid in estimating
+ the start of the link.*/
+struct OpusSeekRecord{
+ /*The earliest byte we know of such that reading forward from it causes
+ capture to be regained at this page.*/
+ opus_int64 search_start;
+ /*The offset of this page.*/
+ opus_int64 offset;
+ /*The size of this page.*/
+ opus_int32 size;
+ /*The serial number of this page.*/
+ ogg_uint32_t serialno;
+ /*The granule position of this page.*/
+ ogg_int64_t gp;
+};
+
+/*Find the last page beginning before _offset with a valid granule position.
+ There is no '_boundary' parameter as it will always have to read more data.
+ This is much dirtier than the above, as Ogg doesn't have any backward search
+ linkage.
+ This search prefers pages of the specified serial number.
+ If a page of the specified serial number is spotted during the
+ seek-back-and-read-forward, it will return the info of last page of the
+ matching serial number, instead of the very last page, unless the very last
+ page belongs to a different link than preferred serial number.
+ If no page of the specified serial number is seen, it will return the info of
+ the last page.
+ [out] _sr: Returns information about the page that was found on success.
+ _offset: The _offset before which to find a page.
+ Any page returned will consist of data entirely before _offset.
+ _serialno: The preferred serial number.
+ If a page with this serial number is found, it will be returned
+ even if another page in the same link is found closer to
+ _offset.
+ This is purely opportunistic: there is no guarantee such a page
+ will be found if it exists.
+ _serialnos: The list of serial numbers in the link that contains the
+ preferred serial number.
+ _nserialnos: The number of serial numbers in the current link.
+ Return: 0 on success, or a negative value on failure.
+ OP_EREAD: Failed to read more data (error or EOF).
+ OP_EBADLINK: We couldn't find a page even after seeking back to the
+ start of the stream.*/
+static int op_get_prev_page_serial(OggOpusFile *_of,OpusSeekRecord *_sr,
+ opus_int64 _offset,ogg_uint32_t _serialno,
+ const ogg_uint32_t *_serialnos,int _nserialnos){
+ OpusSeekRecord preferred_sr;
+ ogg_page og;
+ opus_int64 begin;
+ opus_int64 end;
+ opus_int64 original_end;
+ opus_int32 chunk_size;
+ int preferred_found;
+ original_end=end=begin=_offset;
+ preferred_found=0;
+ _offset=-1;
+ chunk_size=OP_CHUNK_SIZE;
+ do{
+ opus_int64 search_start;
+ int ret;
+ OP_ASSERT(chunk_size>=OP_PAGE_SIZE_MAX);
+ begin=OP_MAX(begin-chunk_size,0);
+ ret=op_seek_helper(_of,begin);
+ if(OP_UNLIKELY(ret<0))return ret;
+ search_start=begin;
+ while(_of->offset<end){
+ opus_int64 llret;
+ ogg_uint32_t serialno;
+ llret=op_get_next_page(_of,&og,end);
+ if(OP_UNLIKELY(llret<OP_FALSE))return (int)llret;
+ else if(llret==OP_FALSE)break;
+ serialno=ogg_page_serialno(&og);
+ /*Save the information for this page.
+ We're not interested in the page itself... just the serial number, byte
+ offset, page size, and granule position.*/
+ _sr->search_start=search_start;
+ _sr->offset=_offset=llret;
+ _sr->serialno=serialno;
+ OP_ASSERT(_of->offset-_offset>=0);
+ OP_ASSERT(_of->offset-_offset<=OP_PAGE_SIZE_MAX);
+ _sr->size=(opus_int32)(_of->offset-_offset);
+ _sr->gp=ogg_page_granulepos(&og);
+ /*If this page is from the stream we're looking for, remember it.*/
+ if(serialno==_serialno){
+ preferred_found=1;
+ *&preferred_sr=*_sr;
+ }
+ if(!op_lookup_serialno(serialno,_serialnos,_nserialnos)){
+ /*We fell off the end of the link, which means we seeked back too far
+ and shouldn't have been looking in that link to begin with.
+ If we found the preferred serial number, forget that we saw it.*/
+ preferred_found=0;
+ }
+ search_start=llret+1;
+ }
+ /*We started from the beginning of the stream and found nothing.
+ This should be impossible unless the contents of the source changed out
+ from under us after we read from it.*/
+ if(OP_UNLIKELY(!begin)&&OP_UNLIKELY(_offset<0))return OP_EBADLINK;
+ /*Bump up the chunk size.
+ This is mildly helpful when seeks are very expensive (http).*/
+ chunk_size=OP_MIN(2*chunk_size,OP_CHUNK_SIZE_MAX);
+ /*Avoid quadratic complexity if we hit an invalid patch of the file.*/
+ end=OP_MIN(begin+OP_PAGE_SIZE_MAX-1,original_end);
+ }
+ while(_offset<0);
+ if(preferred_found)*_sr=*&preferred_sr;
+ return 0;
+}
+
+/*Find the last page beginning before _offset with the given serial number and
+ a valid granule position.
+ Unlike the above search, this continues until it finds such a page, but does
+ not stray outside the current link.
+ We could implement it (inefficiently) by calling op_get_prev_page_serial()
+ repeatedly until it returned a page that had both our preferred serial
+ number and a valid granule position, but doing it with a separate function
+ allows us to avoid repeatedly re-scanning valid pages from other streams as
+ we seek-back-and-read-forward.
+ [out] _gp: Returns the granule position of the page that was found on
+ success.
+ _offset: The _offset before which to find a page.
+ Any page returned will consist of data entirely before _offset.
+ _serialno: The target serial number.
+ _serialnos: The list of serial numbers in the link that contains the
+ preferred serial number.
+ _nserialnos: The number of serial numbers in the current link.
+ Return: The offset of the page on success, or a negative value on failure.
+ OP_EREAD: Failed to read more data (error or EOF).
+ OP_EBADLINK: We couldn't find a page even after seeking back past the
+ beginning of the link.*/
+static opus_int64 op_get_last_page(OggOpusFile *_of,ogg_int64_t *_gp,
+ opus_int64 _offset,ogg_uint32_t _serialno,
+ const ogg_uint32_t *_serialnos,int _nserialnos){
+ ogg_page og;
+ ogg_int64_t gp;
+ opus_int64 begin;
+ opus_int64 end;
+ opus_int64 original_end;
+ opus_int32 chunk_size;
+ /*The target serial number must belong to the current link.*/
+ OP_ASSERT(op_lookup_serialno(_serialno,_serialnos,_nserialnos));
+ original_end=end=begin=_offset;
+ _offset=-1;
+ /*We shouldn't have to initialize gp, but gcc is too dumb to figure out that
+ ret>=0 implies we entered the if(page_gp!=-1) block at least once.*/
+ gp=-1;
+ chunk_size=OP_CHUNK_SIZE;
+ do{
+ int left_link;
+ int ret;
+ OP_ASSERT(chunk_size>=OP_PAGE_SIZE_MAX);
+ begin=OP_MAX(begin-chunk_size,0);
+ ret=op_seek_helper(_of,begin);
+ if(OP_UNLIKELY(ret<0))return ret;
+ left_link=0;
+ while(_of->offset<end){
+ opus_int64 llret;
+ ogg_uint32_t serialno;
+ llret=op_get_next_page(_of,&og,end);
+ if(OP_UNLIKELY(llret<OP_FALSE))return llret;
+ else if(llret==OP_FALSE)break;
+ serialno=ogg_page_serialno(&og);
+ if(serialno==_serialno){
+ ogg_int64_t page_gp;
+ /*The page is from the right stream...*/
+ page_gp=ogg_page_granulepos(&og);
+ if(page_gp!=-1){
+ /*And has a valid granule position.
+ Let's remember it.*/
+ _offset=llret;
+ gp=page_gp;
+ }
+ }
+ else if(OP_UNLIKELY(!op_lookup_serialno(serialno,
+ _serialnos,_nserialnos))){
+ /*We fell off the start of the link, which means we don't need to keep
+ seeking any farther back.*/
+ left_link=1;
+ }
+ }
+ /*We started from at or before the beginning of the link and found nothing.
+ This should be impossible unless the contents of the source changed out
+ from under us after we read from it.*/
+ if((OP_UNLIKELY(left_link)||OP_UNLIKELY(!begin))&&OP_UNLIKELY(_offset<0)){
+ return OP_EBADLINK;
+ }
+ /*Bump up the chunk size.
+ This is mildly helpful when seeks are very expensive (http).*/
+ chunk_size=OP_MIN(2*chunk_size,OP_CHUNK_SIZE_MAX);
+ /*Avoid quadratic complexity if we hit an invalid patch of the file.*/
+ end=OP_MIN(begin+OP_PAGE_SIZE_MAX-1,original_end);
+ }
+ while(_offset<0);
+ *_gp=gp;
+ return _offset;
+}
+
+/*Uses the local ogg_stream storage in _of.
+ This is important for non-streaming input sources.*/
+static int op_fetch_headers_impl(OggOpusFile *_of,OpusHead *_head,
+ OpusTags *_tags,ogg_uint32_t **_serialnos,int *_nserialnos,
+ int *_cserialnos,ogg_page *_og){
+ ogg_packet op;
+ int ret;
+ if(_serialnos!=NULL)*_nserialnos=0;
+ /*Extract the serialnos of all BOS pages plus the first set of Opus headers
+ we see in the link.*/
+ while(ogg_page_bos(_og)){
+ if(_serialnos!=NULL){
+ if(OP_UNLIKELY(op_lookup_page_serialno(_og,*_serialnos,*_nserialnos))){
+ /*A dupe serialnumber in an initial header packet set==invalid stream.*/
+ return OP_EBADHEADER;
+ }
+ ret=op_add_serialno(_og,_serialnos,_nserialnos,_cserialnos);
+ if(OP_UNLIKELY(ret<0))return ret;
+ }
+ if(_of->ready_state<OP_STREAMSET){
+ /*We don't have an Opus stream in this link yet, so begin prospective
+ stream setup.
+ We need a stream to get packets.*/
+ ogg_stream_reset_serialno(&_of->os,ogg_page_serialno(_og));
+ ogg_stream_pagein(&_of->os,_og);
+ if(OP_LIKELY(ogg_stream_packetout(&_of->os,&op)>0)){
+ ret=opus_head_parse(_head,op.packet,op.bytes);
+ /*Found a valid Opus header.
+ Continue setup.*/
+ if(OP_LIKELY(ret>=0))_of->ready_state=OP_STREAMSET;
+ /*If it's just a stream type we don't recognize, ignore it.
+ Everything else is fatal.*/
+ else if(ret!=OP_ENOTFORMAT)return ret;
+ }
+ }
+ /*Get the next page.
+ No need to clamp the boundary offset against _of->end, as all errors
+ become OP_ENOTFORMAT or OP_EBADHEADER.*/
+ if(OP_UNLIKELY(op_get_next_page(_of,_og,
+ OP_ADV_OFFSET(_of->offset,OP_CHUNK_SIZE))<0)){
+ return _of->ready_state<OP_STREAMSET?OP_ENOTFORMAT:OP_EBADHEADER;
+ }
+ }
+ if(OP_UNLIKELY(_of->ready_state!=OP_STREAMSET))return OP_ENOTFORMAT;
+ /*If the first non-header page belonged to our Opus stream, submit it.*/
+ if(_of->os.serialno==ogg_page_serialno(_og))ogg_stream_pagein(&_of->os,_og);
+ /*Loop getting packets.*/
+ for(;;){
+ switch(ogg_stream_packetout(&_of->os,&op)){
+ case 0:{
+ /*Loop getting pages.*/
+ for(;;){
+ /*No need to clamp the boundary offset against _of->end, as all
+ errors become OP_EBADHEADER.*/
+ if(OP_UNLIKELY(op_get_next_page(_of,_og,
+ OP_ADV_OFFSET(_of->offset,OP_CHUNK_SIZE))<0)){
+ return OP_EBADHEADER;
+ }
+ /*If this page belongs to the correct stream, go parse it.*/
+ if(_of->os.serialno==ogg_page_serialno(_og)){
+ ogg_stream_pagein(&_of->os,_og);
+ break;
+ }
+ /*If the link ends before we see the Opus comment header, abort.*/
+ if(OP_UNLIKELY(ogg_page_bos(_og)))return OP_EBADHEADER;
+ /*Otherwise, keep looking.*/
+ }
+ }break;
+ /*We shouldn't get a hole in the headers!*/
+ case -1:return OP_EBADHEADER;
+ default:{
+ /*Got a packet.
+ It should be the comment header.*/
+ ret=opus_tags_parse(_tags,op.packet,op.bytes);
+ if(OP_UNLIKELY(ret<0))return ret;
+ /*Make sure the page terminated at the end of the comment header.
+ If there is another packet on the page, or part of a packet, then
+ reject the stream.
+ Otherwise seekable sources won't be able to seek back to the start
+ properly.*/
+ ret=ogg_stream_packetout(&_of->os,&op);
+ if(OP_UNLIKELY(ret!=0)
+ ||OP_UNLIKELY(_og->header[_og->header_len-1]==255)){
+ /*If we fail, the caller assumes our tags are uninitialized.*/
+ opus_tags_clear(_tags);
+ return OP_EBADHEADER;
+ }
+ return 0;
+ }
+ }
+ }
+}
+
+static int op_fetch_headers(OggOpusFile *_of,OpusHead *_head,
+ OpusTags *_tags,ogg_uint32_t **_serialnos,int *_nserialnos,
+ int *_cserialnos,ogg_page *_og){
+ ogg_page og;
+ int ret;
+ if(!_og){
+ /*No need to clamp the boundary offset against _of->end, as all errors
+ become OP_ENOTFORMAT.*/
+ if(OP_UNLIKELY(op_get_next_page(_of,&og,
+ OP_ADV_OFFSET(_of->offset,OP_CHUNK_SIZE))<0)){
+ return OP_ENOTFORMAT;
+ }
+ _og=&og;
+ }
+ _of->ready_state=OP_OPENED;
+ ret=op_fetch_headers_impl(_of,_head,_tags,_serialnos,_nserialnos,
+ _cserialnos,_og);
+ /*Revert back from OP_STREAMSET to OP_OPENED on failure, to prevent
+ double-free of the tags in an unseekable stream.*/
+ if(OP_UNLIKELY(ret<0))_of->ready_state=OP_OPENED;
+ return ret;
+}
+
+/*Granule position manipulation routines.
+ A granule position is defined to be an unsigned 64-bit integer, with the
+ special value -1 in two's complement indicating an unset or invalid granule
+ position.
+ We are not guaranteed to have an unsigned 64-bit type, so we construct the
+ following routines that
+ a) Properly order negative numbers as larger than positive numbers, and
+ b) Check for underflow or overflow past the special -1 value.
+ This lets us operate on the full, valid range of granule positions in a
+ consistent and safe manner.
+ This full range is organized into distinct regions:
+ [ -1 (invalid) ][ 0 ... OP_INT64_MAX ][ OP_INT64_MIN ... -2 ][-1 (invalid) ]
+
+ No one should actually use granule positions so large that they're negative,
+ even if they are technically valid, as very little software handles them
+ correctly (including most of Xiph.Org's).
+ This library also refuses to support durations so large they won't fit in a
+ signed 64-bit integer (to avoid exposing this mess to the application, and
+ to simplify a good deal of internal arithmetic), so the only way to use them
+ successfully is if pcm_start is very large.
+ This means there isn't anything you can do with negative granule positions
+ that you couldn't have done with purely non-negative ones.
+ The main purpose of these routines is to allow us to think very explicitly
+ about the possible failure cases of all granule position manipulations.*/
+
+/*Safely adds a small signed integer to a valid (not -1) granule position.
+ The result can use the full 64-bit range of values (both positive and
+ negative), but will fail on overflow (wrapping past -1; wrapping past
+ OP_INT64_MAX is explicitly okay).
+ [out] _dst_gp: The resulting granule position.
+ Only modified on success.
+ _src_gp: The granule position to add to.
+ This must not be -1.
+ _delta: The amount to add.
+ This is allowed to be up to 32 bits to support the maximum
+ duration of a single Ogg page (255 packets * 120 ms per
+ packet == 1,468,800 samples at 48 kHz).
+ Return: 0 on success, or OP_EINVAL if the result would wrap around past -1.*/
+static int op_granpos_add(ogg_int64_t *_dst_gp,ogg_int64_t _src_gp,
+ opus_int32 _delta){
+ /*The code below handles this case correctly, but there's no reason we
+ should ever be called with these values, so make sure we aren't.*/
+ OP_ASSERT(_src_gp!=-1);
+ if(_delta>0){
+ /*Adding this amount to the granule position would overflow its 64-bit
+ range.*/
+ if(OP_UNLIKELY(_src_gp<0)&&OP_UNLIKELY(_src_gp>=-1-_delta))return OP_EINVAL;
+ if(OP_UNLIKELY(_src_gp>OP_INT64_MAX-_delta)){
+ /*Adding this amount to the granule position would overflow the positive
+ half of its 64-bit range.
+ Since signed overflow is undefined in C, do it in a way the compiler
+ isn't allowed to screw up.*/
+ _delta-=(opus_int32)(OP_INT64_MAX-_src_gp)+1;
+ _src_gp=OP_INT64_MIN;
+ }
+ }
+ else if(_delta<0){
+ /*Subtracting this amount from the granule position would underflow its
+ 64-bit range.*/
+ if(_src_gp>=0&&OP_UNLIKELY(_src_gp<-_delta))return OP_EINVAL;
+ if(OP_UNLIKELY(_src_gp<OP_INT64_MIN-_delta)){
+ /*Subtracting this amount from the granule position would underflow the
+ negative half of its 64-bit range.
+ Since signed underflow is undefined in C, do it in a way the compiler
+ isn't allowed to screw up.*/
+ _delta+=(opus_int32)(_src_gp-OP_INT64_MIN)+1;
+ _src_gp=OP_INT64_MAX;
+ }
+ }
+ *_dst_gp=_src_gp+_delta;
+ return 0;
+}
+
+/*Safely computes the difference between two granule positions.
+ The difference must fit in a signed 64-bit integer, or the function fails.
+ It correctly handles the case where the granule position has wrapped around
+ from positive values to negative ones.
+ [out] _delta: The difference between the granule positions.
+ Only modified on success.
+ _gp_a: The granule position to subtract from.
+ This must not be -1.
+ _gp_b: The granule position to subtract.
+ This must not be -1.
+ Return: 0 on success, or OP_EINVAL if the result would not fit in a signed
+ 64-bit integer.*/
+static int op_granpos_diff(ogg_int64_t *_delta,
+ ogg_int64_t _gp_a,ogg_int64_t _gp_b){
+ int gp_a_negative;
+ int gp_b_negative;
+ /*The code below handles these cases correctly, but there's no reason we
+ should ever be called with these values, so make sure we aren't.*/
+ OP_ASSERT(_gp_a!=-1);
+ OP_ASSERT(_gp_b!=-1);
+ gp_a_negative=OP_UNLIKELY(_gp_a<0);
+ gp_b_negative=OP_UNLIKELY(_gp_b<0);
+ if(OP_UNLIKELY(gp_a_negative^gp_b_negative)){
+ ogg_int64_t da;
+ ogg_int64_t db;
+ if(gp_a_negative){
+ /*_gp_a has wrapped to a negative value but _gp_b hasn't: the difference
+ should be positive.*/
+ /*Step 1: Handle wrapping.*/
+ /*_gp_a < 0 => da < 0.*/
+ da=(OP_INT64_MIN-_gp_a)-1;
+ /*_gp_b >= 0 => db >= 0.*/
+ db=OP_INT64_MAX-_gp_b;
+ /*Step 2: Check for overflow.*/
+ if(OP_UNLIKELY(OP_INT64_MAX+da<db))return OP_EINVAL;
+ *_delta=db-da;
+ }
+ else{
+ /*_gp_b has wrapped to a negative value but _gp_a hasn't: the difference
+ should be negative.*/
+ /*Step 1: Handle wrapping.*/
+ /*_gp_a >= 0 => da <= 0*/
+ da=_gp_a+OP_INT64_MIN;
+ /*_gp_b < 0 => db <= 0*/
+ db=OP_INT64_MIN-_gp_b;
+ /*Step 2: Check for overflow.*/
+ if(OP_UNLIKELY(da<OP_INT64_MIN-db))return OP_EINVAL;
+ *_delta=da+db;
+ }
+ }
+ else *_delta=_gp_a-_gp_b;
+ return 0;
+}
+
+static int op_granpos_cmp(ogg_int64_t _gp_a,ogg_int64_t _gp_b){
+ /*The invalid granule position -1 should behave like NaN: neither greater
+ than nor less than any other granule position, nor equal to any other
+ granule position, including itself.
+ However, that means there isn't anything we could sensibly return from this
+ function for it.*/
+ OP_ASSERT(_gp_a!=-1);
+ OP_ASSERT(_gp_b!=-1);
+ /*Handle the wrapping cases.*/
+ if(OP_UNLIKELY(_gp_a<0)){
+ if(_gp_b>=0)return 1;
+ /*Else fall through.*/
+ }
+ else if(OP_UNLIKELY(_gp_b<0))return -1;
+ /*No wrapping case.*/
+ return (_gp_a>_gp_b)-(_gp_b>_gp_a);
+}
+
+/*Returns the duration of the packet (in samples at 48 kHz), or a negative
+ value on error.*/
+static int op_get_packet_duration(const unsigned char *_data,int _len){
+ int nframes;
+ int frame_size;
+ int nsamples;
+ nframes=opus_packet_get_nb_frames(_data,_len);
+ if(OP_UNLIKELY(nframes<0))return OP_EBADPACKET;
+ frame_size=opus_packet_get_samples_per_frame(_data,48000);
+ nsamples=nframes*frame_size;
+ if(OP_UNLIKELY(nsamples>120*48))return OP_EBADPACKET;
+ return nsamples;
+}
+
+/*This function more properly belongs in info.c, but we define it here to allow
+ the static granule position manipulation functions to remain static.*/
+ogg_int64_t opus_granule_sample(const OpusHead *_head,ogg_int64_t _gp){
+ opus_int32 pre_skip;
+ pre_skip=_head->pre_skip;
+ if(_gp!=-1&&op_granpos_add(&_gp,_gp,-pre_skip))_gp=-1;
+ return _gp;
+}
+
+/*Grab all the packets currently in the stream state, and compute their
+ durations.
+ _of->op_count is set to the number of packets collected.
+ [out] _durations: Returns the durations of the individual packets.
+ Return: The total duration of all packets, or OP_HOLE if there was a hole.*/
+static opus_int32 op_collect_audio_packets(OggOpusFile *_of,
+ int _durations[255]){
+ opus_int32 total_duration;
+ int op_count;
+ /*Count the durations of all packets in the page.*/
+ op_count=0;
+ total_duration=0;
+ for(;;){
+ int ret;
+ /*This takes advantage of undocumented libogg behavior that returned
+ ogg_packet buffers are valid at least until the next page is
+ submitted.
+ Relying on this is not too terrible, as _none_ of the Ogg memory
+ ownership/lifetime rules are well-documented.
+ But I can read its code and know this will work.*/
+ ret=ogg_stream_packetout(&_of->os,_of->op+op_count);
+ if(!ret)break;
+ if(OP_UNLIKELY(ret<0)){
+ /*We shouldn't get holes in the middle of pages.*/
+ OP_ASSERT(op_count==0);
+ /*Set the return value and break out of the loop.
+ We want to make sure op_count gets set to 0, because we've ingested a
+ page, so any previously loaded packets are now invalid.*/
+ total_duration=OP_HOLE;
+ break;
+ }
+ /*Unless libogg is broken, we can't get more than 255 packets from a
+ single page.*/
+ OP_ASSERT(op_count<255);
+ _durations[op_count]=op_get_packet_duration(_of->op[op_count].packet,
+ _of->op[op_count].bytes);
+ if(OP_LIKELY(_durations[op_count]>0)){
+ /*With at most 255 packets on a page, this can't overflow.*/
+ total_duration+=_durations[op_count++];
+ }
+ /*Ignore packets with an invalid TOC sequence.*/
+ else if(op_count>0){
+ /*But save the granule position, if there was one.*/
+ _of->op[op_count-1].granulepos=_of->op[op_count].granulepos;
+ }
+ }
+ _of->op_pos=0;
+ _of->op_count=op_count;
+ return total_duration;
+}
+
+/*Starting from current cursor position, get the initial PCM offset of the next
+ page.
+ This also validates the granule position on the first page with a completed
+ audio data packet, as required by the spec.
+ If this link is completely empty (no pages with completed packets), then this
+ function sets pcm_start=pcm_end=0 and returns the BOS page of the next link
+ (if any).
+ In the seekable case, we initialize pcm_end=-1 before calling this function,
+ so that later we can detect that the link was empty before calling
+ op_find_final_pcm_offset().
+ [inout] _link: The link for which to find pcm_start.
+ [out] _og: Returns the BOS page of the next link if this link was empty.
+ In the unseekable case, we can then feed this to
+ op_fetch_headers() to start the next link.
+ The caller may pass NULL (e.g., for seekable streams), in
+ which case this page will be discarded.
+ Return: 0 on success, 1 if there is a buffered BOS page available, or a
+ negative value on unrecoverable error.*/
+static int op_find_initial_pcm_offset(OggOpusFile *_of,
+ OggOpusLink *_link,ogg_page *_og){
+ ogg_page og;
+ ogg_int64_t pcm_start;
+ ogg_int64_t prev_packet_gp;
+ ogg_int64_t cur_page_gp;
+ ogg_uint32_t serialno;
+ opus_int32 total_duration;
+ int durations[255];
+ int cur_page_eos;
+ int op_count;
+ int pi;
+ if(_og==NULL)_og=&og;
+ serialno=_of->os.serialno;
+ op_count=0;
+ /*We shouldn't have to initialize total_duration, but gcc is too dumb to
+ figure out that op_count>0 implies we've been through the whole loop at
+ least once.*/
+ total_duration=0;
+ do{
+ opus_int64 llret;
+ llret=op_get_next_page(_of,_og,_of->end);
+ /*We should get a page unless the file is truncated or mangled.
+ Otherwise there are no audio data packets in the whole logical stream.*/
+ if(OP_UNLIKELY(llret<0)){
+ /*Fail if there was a read error.*/
+ if(llret<OP_FALSE)return (int)llret;
+ /*Fail if the pre-skip is non-zero, since it's asking us to skip more
+ samples than exist.*/
+ if(_link->head.pre_skip>0)return OP_EBADTIMESTAMP;
+ /*Set pcm_end and end_offset so we can skip the call to
+ op_find_final_pcm_offset().*/
+ _link->pcm_start=_link->pcm_end=0;
+ _link->end_offset=_link->data_offset;
+ return 0;
+ }
+ /*Similarly, if we hit the next link in the chain, we've gone too far.*/
+ if(OP_UNLIKELY(ogg_page_bos(_og))){
+ if(_link->head.pre_skip>0)return OP_EBADTIMESTAMP;
+ /*Set pcm_end and end_offset so we can skip the call to
+ op_find_final_pcm_offset().*/
+ _link->pcm_end=_link->pcm_start=0;
+ _link->end_offset=_link->data_offset;
+ /*Tell the caller we've got a buffered page for them.*/
+ return 1;
+ }
+ /*Ignore pages from other streams (not strictly necessary, because of the
+ checks in ogg_stream_pagein(), but saves some work).*/
+ if(serialno!=(ogg_uint32_t)ogg_page_serialno(_og))continue;
+ ogg_stream_pagein(&_of->os,_og);
+ /*Bitrate tracking: add the header's bytes here.
+ The body bytes are counted when we consume the packets.*/
+ _of->bytes_tracked+=_og->header_len;
+ /*Count the durations of all packets in the page.*/
+ do total_duration=op_collect_audio_packets(_of,durations);
+ /*Ignore holes.*/
+ while(OP_UNLIKELY(total_duration<0));
+ op_count=_of->op_count;
+ }
+ while(op_count<=0);
+ /*We found the first page with a completed audio data packet: actually look
+ at the granule position.
+ RFC 3533 says, "A special value of -1 (in two's complement) indicates that
+ no packets finish on this page," which does not say that a granule
+ position that is NOT -1 indicates that some packets DO finish on that page
+ (even though this was the intention, libogg itself violated this intention
+ for years before we fixed it).
+ The Ogg Opus specification only imposes its start-time requirements
+ on the granule position of the first page with completed packets,
+ so we ignore any set granule positions until then.*/
+ cur_page_gp=_of->op[op_count-1].granulepos;
+ /*But getting a packet without a valid granule position on the page is not
+ okay.*/
+ if(cur_page_gp==-1)return OP_EBADTIMESTAMP;
+ cur_page_eos=_of->op[op_count-1].e_o_s;
+ if(OP_LIKELY(!cur_page_eos)){
+ /*The EOS flag wasn't set.
+ Work backwards from the provided granule position to get the starting PCM
+ offset.*/
+ if(OP_UNLIKELY(op_granpos_add(&pcm_start,cur_page_gp,-total_duration)<0)){
+ /*The starting granule position MUST not be smaller than the amount of
+ audio on the first page with completed packets.*/
+ return OP_EBADTIMESTAMP;
+ }
+ }
+ else{
+ /*The first page with completed packets was also the last.*/
+ if(OP_LIKELY(op_granpos_add(&pcm_start,cur_page_gp,-total_duration)<0)){
+ /*If there's less audio on the page than indicated by the granule
+ position, then we're doing end-trimming, and the starting PCM offset
+ is zero by spec mandate.*/
+ pcm_start=0;
+ /*However, the end-trimming MUST not ask us to trim more samples than
+ exist after applying the pre-skip.*/
+ if(OP_UNLIKELY(op_granpos_cmp(cur_page_gp,_link->head.pre_skip)<0)){
+ return OP_EBADTIMESTAMP;
+ }
+ }
+ }
+ /*Timestamp the individual packets.*/
+ prev_packet_gp=pcm_start;
+ for(pi=0;pi<op_count;pi++){
+ if(cur_page_eos){
+ ogg_int64_t diff;
+ OP_ALWAYS_TRUE(!op_granpos_diff(&diff,cur_page_gp,prev_packet_gp));
+ diff=durations[pi]-diff;
+ /*If we have samples to trim...*/
+ if(diff>0){
+ /*If we trimmed the entire packet, stop (the spec says encoders
+ shouldn't do this, but we support it anyway).*/
+ if(OP_UNLIKELY(diff>durations[pi]))break;
+ _of->op[pi].granulepos=prev_packet_gp=cur_page_gp;
+ /*Move the EOS flag to this packet, if necessary, so we'll trim the
+ samples.*/
+ _of->op[pi].e_o_s=1;
+ continue;
+ }
+ }
+ /*Update the granule position as normal.*/
+ OP_ALWAYS_TRUE(!op_granpos_add(&_of->op[pi].granulepos,
+ prev_packet_gp,durations[pi]));
+ prev_packet_gp=_of->op[pi].granulepos;
+ }
+ /*Update the packet count after end-trimming.*/
+ _of->op_count=pi;
+ _of->cur_discard_count=_link->head.pre_skip;
+ _of->prev_packet_gp=_link->pcm_start=pcm_start;
+ return 0;
+}
+
+/*Starting from current cursor position, get the final PCM offset of the
+ previous page.
+ This also validates the duration of the link, which, while not strictly
+ required by the spec, we need to ensure duration calculations don't
+ overflow.
+ This is only done for seekable sources.
+ We must validate that op_find_initial_pcm_offset() succeeded for this link
+ before calling this function, otherwise it will scan the entire stream
+ backwards until it reaches the start, and then fail.*/
+static int op_find_final_pcm_offset(OggOpusFile *_of,
+ const ogg_uint32_t *_serialnos,int _nserialnos,OggOpusLink *_link,
+ opus_int64 _offset,ogg_uint32_t _end_serialno,ogg_int64_t _end_gp,
+ ogg_int64_t *_total_duration){
+ ogg_int64_t total_duration;
+ ogg_int64_t duration;
+ ogg_uint32_t cur_serialno;
+ /*For the time being, fetch end PCM offset the simple way.*/
+ cur_serialno=_link->serialno;
+ if(_end_serialno!=cur_serialno||_end_gp==-1){
+ _offset=op_get_last_page(_of,&_end_gp,_offset,
+ cur_serialno,_serialnos,_nserialnos);
+ if(OP_UNLIKELY(_offset<0))return (int)_offset;
+ }
+ /*At worst we should have found the first page with completed packets.*/
+ if(OP_UNLIKELY(_offset<_link->data_offset))return OP_EBADLINK;
+ /*This implementation requires that the difference between the first and last
+ granule positions in each link be representable in a signed, 64-bit
+ number, and that each link also have at least as many samples as the
+ pre-skip requires.*/
+ if(OP_UNLIKELY(op_granpos_diff(&duration,_end_gp,_link->pcm_start)<0)
+ ||OP_UNLIKELY(duration<_link->head.pre_skip)){
+ return OP_EBADTIMESTAMP;
+ }
+ /*We also require that the total duration be representable in a signed,
+ 64-bit number.*/
+ duration-=_link->head.pre_skip;
+ total_duration=*_total_duration;
+ if(OP_UNLIKELY(OP_INT64_MAX-duration<total_duration))return OP_EBADTIMESTAMP;
+ *_total_duration=total_duration+duration;
+ _link->pcm_end=_end_gp;
+ _link->end_offset=_offset;
+ return 0;
+}
+
+/*Rescale the number _x from the range [0,_from] to [0,_to].
+ _from and _to must be positive.*/
+static opus_int64 op_rescale64(opus_int64 _x,opus_int64 _from,opus_int64 _to){
+ opus_int64 frac;
+ opus_int64 ret;
+ int i;
+ if(_x>=_from)return _to;
+ if(_x<=0)return 0;
+ frac=0;
+ for(i=0;i<63;i++){
+ frac<<=1;
+ OP_ASSERT(_x<=_from);
+ if(_x>=_from>>1){
+ _x-=_from-_x;
+ frac|=1;
+ }
+ else _x<<=1;
+ }
+ ret=0;
+ for(i=0;i<63;i++){
+ if(frac&1)ret=(ret&_to&1)+(ret>>1)+(_to>>1);
+ else ret>>=1;
+ frac>>=1;
+ }
+ return ret;
+}
+
+/*The minimum granule position spacing allowed for making predictions.
+ This corresponds to about 1 second of audio at 48 kHz for both Opus and
+ Vorbis, or one keyframe interval in Theora with the default keyframe spacing
+ of 256.*/
+#define OP_GP_SPACING_MIN (48000)
+
+/*Try to estimate the location of the next link using the current seek
+ records, assuming the initial granule position of any streams we've found is
+ 0.*/
+static opus_int64 op_predict_link_start(const OpusSeekRecord *_sr,int _nsr,
+ opus_int64 _searched,opus_int64 _end_searched,opus_int32 _bias){
+ opus_int64 bisect;
+ int sri;
+ int srj;
+ /*Require that we be at least OP_CHUNK_SIZE from the end.
+ We don't require that we be at least OP_CHUNK_SIZE from the beginning,
+ because if we are we'll just scan forward without seeking.*/
+ _end_searched-=OP_CHUNK_SIZE;
+ if(_searched>=_end_searched)return -1;
+ bisect=_end_searched;
+ for(sri=0;sri<_nsr;sri++){
+ ogg_int64_t gp1;
+ ogg_int64_t gp2_min;
+ ogg_uint32_t serialno1;
+ opus_int64 offset1;
+ /*If the granule position is negative, either it's invalid or we'd cause
+ overflow.*/
+ gp1=_sr[sri].gp;
+ if(gp1<0)continue;
+ /*We require some minimum distance between granule positions to make an
+ estimate.
+ We don't actually know what granule position scheme is being used,
+ because we have no idea what kind of stream these came from.
+ Therefore we require a minimum spacing between them, with the
+ expectation that while bitrates and granule position increments might
+ vary locally in quite complex ways, they are globally smooth.*/
+ if(OP_UNLIKELY(op_granpos_add(&gp2_min,gp1,OP_GP_SPACING_MIN)<0)){
+ /*No granule position would satisfy us.*/
+ continue;
+ }
+ offset1=_sr[sri].offset;
+ serialno1=_sr[sri].serialno;
+ for(srj=sri;srj-->0;){
+ ogg_int64_t gp2;
+ opus_int64 offset2;
+ opus_int64 num;
+ ogg_int64_t den;
+ ogg_int64_t ipart;
+ gp2=_sr[srj].gp;
+ if(gp2<gp2_min)continue;
+ /*Oh, and also make sure these came from the same stream.*/
+ if(_sr[srj].serialno!=serialno1)continue;
+ offset2=_sr[srj].offset;
+ /*For once, we can subtract with impunity.*/
+ den=gp2-gp1;
+ ipart=gp2/den;
+ num=offset2-offset1;
+ OP_ASSERT(num>0);
+ if(ipart>0&&(offset2-_searched)/ipart<num)continue;
+ offset2-=ipart*num;
+ gp2-=ipart*den;
+ offset2-=op_rescale64(gp2,den,num)-_bias;
+ if(offset2<_searched)continue;
+ bisect=OP_MIN(bisect,offset2);
+ break;
+ }
+ }
+ return bisect>=_end_searched?-1:bisect;
+}
+
+/*Finds each bitstream link, one at a time, using a bisection search.
+ This has to begin by knowing the offset of the first link's initial page.*/
+static int op_bisect_forward_serialno(OggOpusFile *_of,
+ opus_int64 _searched,OpusSeekRecord *_sr,int _csr,
+ ogg_uint32_t **_serialnos,int *_nserialnos,int *_cserialnos){
+ ogg_page og;
+ OggOpusLink *links;
+ int nlinks;
+ int clinks;
+ ogg_uint32_t *serialnos;
+ int nserialnos;
+ ogg_int64_t total_duration;
+ int nsr;
+ int ret;
+ links=_of->links;
+ nlinks=clinks=_of->nlinks;
+ total_duration=0;
+ /*We start with one seek record, for the last page in the file.
+ We build up a list of records for places we seek to during link
+ enumeration.
+ This list is kept sorted in reverse order.
+ We only care about seek locations that were _not_ in the current link,
+ therefore we can add them one at a time to the end of the list as we
+ improve the lower bound on the location where the next link starts.*/
+ nsr=1;
+ for(;;){
+ opus_int64 end_searched;
+ opus_int64 bisect;
+ opus_int64 next;
+ opus_int64 last;
+ ogg_int64_t end_offset;
+ ogg_int64_t end_gp;
+ int sri;
+ serialnos=*_serialnos;
+ nserialnos=*_nserialnos;
+ if(OP_UNLIKELY(nlinks>=clinks)){
+ if(OP_UNLIKELY(clinks>INT_MAX-1>>1))return OP_EFAULT;
+ clinks=2*clinks+1;
+ OP_ASSERT(nlinks<clinks);
+ links=(OggOpusLink *)_ogg_realloc(links,sizeof(*links)*clinks);
+ if(OP_UNLIKELY(links==NULL))return OP_EFAULT;
+ _of->links=links;
+ }
+ /*Invariants:
+ We have the headers and serial numbers for the link beginning at 'begin'.
+ We have the offset and granule position of the last page in the file
+ (potentially not a page we care about).*/
+ /*Scan the seek records we already have to save us some bisection.*/
+ for(sri=0;sri<nsr;sri++){
+ if(op_lookup_serialno(_sr[sri].serialno,serialnos,nserialnos))break;
+ }
+ /*Is the last page in our current list of serial numbers?*/
+ if(sri<=0)break;
+ /*Last page wasn't found.
+ We have at least one more link.*/
+ last=-1;
+ end_searched=_sr[sri-1].search_start;
+ next=_sr[sri-1].offset;
+ end_gp=-1;
+ if(sri<nsr){
+ _searched=_sr[sri].offset+_sr[sri].size;
+ if(_sr[sri].serialno==links[nlinks-1].serialno){
+ end_gp=_sr[sri].gp;
+ end_offset=_sr[sri].offset;
+ }
+ }
+ nsr=sri;
+ bisect=-1;
+ /*If we've already found the end of at least one link, try to pick the
+ first bisection point at twice the average link size.
+ This is a good choice for files with lots of links that are all about the
+ same size.*/
+ if(nlinks>1){
+ opus_int64 last_offset;
+ opus_int64 avg_link_size;
+ opus_int64 upper_limit;
+ last_offset=links[nlinks-1].offset;
+ avg_link_size=last_offset/(nlinks-1);
+ upper_limit=end_searched-OP_CHUNK_SIZE-avg_link_size;
+ if(OP_LIKELY(last_offset>_searched-avg_link_size)
+ &&OP_LIKELY(last_offset<upper_limit)){
+ bisect=last_offset+avg_link_size;
+ if(OP_LIKELY(bisect<upper_limit))bisect+=avg_link_size;
+ }
+ }
+ /*We guard against garbage separating the last and first pages of two
+ links below.*/
+ while(_searched<end_searched){
+ opus_int32 next_bias;
+ /*If we don't have a better estimate, use simple bisection.*/
+ if(bisect==-1)bisect=_searched+(end_searched-_searched>>1);
+ /*If we're within OP_CHUNK_SIZE of the start, scan forward.*/
+ if(bisect-_searched<OP_CHUNK_SIZE)bisect=_searched;
+ /*Otherwise we're skipping data.
+ Forget the end page, if we saw one, as we might miss a later one.*/
+ else end_gp=-1;
+ ret=op_seek_helper(_of,bisect);
+ if(OP_UNLIKELY(ret<0))return ret;
+ last=op_get_next_page(_of,&og,_sr[nsr-1].offset);
+ if(OP_UNLIKELY(last<OP_FALSE))return (int)last;
+ next_bias=0;
+ if(last==OP_FALSE)end_searched=bisect;
+ else{
+ ogg_uint32_t serialno;
+ ogg_int64_t gp;
+ serialno=ogg_page_serialno(&og);
+ gp=ogg_page_granulepos(&og);
+ if(!op_lookup_serialno(serialno,serialnos,nserialnos)){
+ end_searched=bisect;
+ next=last;
+ /*In reality we should always have enough room, but be paranoid.*/
+ if(OP_LIKELY(nsr<_csr)){
+ _sr[nsr].search_start=bisect;
+ _sr[nsr].offset=last;
+ OP_ASSERT(_of->offset-last>=0);
+ OP_ASSERT(_of->offset-last<=OP_PAGE_SIZE_MAX);
+ _sr[nsr].size=(opus_int32)(_of->offset-last);
+ _sr[nsr].serialno=serialno;
+ _sr[nsr].gp=gp;
+ nsr++;
+ }
+ }
+ else{
+ _searched=_of->offset;
+ next_bias=OP_CHUNK_SIZE;
+ if(serialno==links[nlinks-1].serialno){
+ /*This page was from the stream we want, remember it.
+ If it's the last such page in the link, we won't have to go back
+ looking for it later.*/
+ end_gp=gp;
+ end_offset=last;
+ }
+ }
+ }
+ bisect=op_predict_link_start(_sr,nsr,_searched,end_searched,next_bias);
+ }
+ /*Bisection point found.
+ Get the final granule position of the previous link, assuming
+ op_find_initial_pcm_offset() didn't already determine the link was
+ empty.*/
+ if(OP_LIKELY(links[nlinks-1].pcm_end==-1)){
+ if(end_gp==-1){
+ /*If we don't know where the end page is, we'll have to seek back and
+ look for it, starting from the end of the link.*/
+ end_offset=next;
+ /*Also forget the last page we read.
+ It won't be available after the seek.*/
+ last=-1;
+ }
+ ret=op_find_final_pcm_offset(_of,serialnos,nserialnos,
+ links+nlinks-1,end_offset,links[nlinks-1].serialno,end_gp,
+ &total_duration);
+ if(OP_UNLIKELY(ret<0))return ret;
+ }
+ if(last!=next){
+ /*The last page we read was not the first page the next link.
+ Move the cursor position to the offset of that first page.
+ This only performs an actual seek if the first page of the next link
+ does not start at the end of the last page from the current Opus
+ stream with a valid granule position.*/
+ ret=op_seek_helper(_of,next);
+ if(OP_UNLIKELY(ret<0))return ret;
+ }
+ ret=op_fetch_headers(_of,&links[nlinks].head,&links[nlinks].tags,
+ _serialnos,_nserialnos,_cserialnos,last!=next?NULL:&og);
+ if(OP_UNLIKELY(ret<0))return ret;
+ links[nlinks].offset=next;
+ links[nlinks].data_offset=_of->offset;
+ links[nlinks].serialno=_of->os.serialno;
+ links[nlinks].pcm_end=-1;
+ /*This might consume a page from the next link, however the next bisection
+ always starts with a seek.*/
+ ret=op_find_initial_pcm_offset(_of,links+nlinks,NULL);
+ if(OP_UNLIKELY(ret<0))return ret;
+ _searched=_of->offset;
+ /*Mark the current link count so it can be cleaned up on error.*/
+ _of->nlinks=++nlinks;
+ }
+ /*Last page is in the starting serialno list, so we've reached the last link.
+ Now find the last granule position for it (if we didn't the first time we
+ looked at the end of the stream, and if op_find_initial_pcm_offset()
+ didn't already determine the link was empty).*/
+ if(OP_LIKELY(links[nlinks-1].pcm_end==-1)){
+ ret=op_find_final_pcm_offset(_of,serialnos,nserialnos,
+ links+nlinks-1,_sr[0].offset,_sr[0].serialno,_sr[0].gp,&total_duration);
+ if(OP_UNLIKELY(ret<0))return ret;
+ }
+ /*Trim back the links array if necessary.*/
+ links=(OggOpusLink *)_ogg_realloc(links,sizeof(*links)*nlinks);
+ if(OP_LIKELY(links!=NULL))_of->links=links;
+ /*We also don't need these anymore.*/
+ _ogg_free(*_serialnos);
+ *_serialnos=NULL;
+ *_cserialnos=*_nserialnos=0;
+ return 0;
+}
+
+static void op_update_gain(OggOpusFile *_of){
+ OpusHead *head;
+ opus_int32 gain_q8;
+ int li;
+ /*If decode isn't ready, then we'll apply the gain when we initialize the
+ decoder.*/
+ if(_of->ready_state<OP_INITSET)return;
+ gain_q8=_of->gain_offset_q8;
+ li=_of->seekable?_of->cur_link:0;
+ head=&_of->links[li].head;
+ /*We don't have to worry about overflow here because the header gain and
+ track gain must lie in the range [-32768,32767], and the user-supplied
+ offset has been pre-clamped to [-98302,98303].*/
+ switch(_of->gain_type){
+ case OP_TRACK_GAIN:{
+ int track_gain_q8;
+ track_gain_q8=0;
+ opus_tags_get_track_gain(&_of->links[li].tags,&track_gain_q8);
+ gain_q8+=track_gain_q8;
+ }
+ /*Fall through.*/
+ case OP_HEADER_GAIN:gain_q8+=head->output_gain;break;
+ case OP_ABSOLUTE_GAIN:break;
+ default:OP_ASSERT(0);
+ }
+ gain_q8=OP_CLAMP(-32768,gain_q8,32767);
+ OP_ASSERT(_of->od!=NULL);
+#if defined(OPUS_SET_GAIN)
+ opus_multistream_decoder_ctl(_of->od,OPUS_SET_GAIN(gain_q8));
+#else
+/*A fallback that works with both float and fixed-point is a bunch of work,
+ so just force people to use a sufficiently new version.
+ This is deployed well enough at this point that this shouldn't be a burden.*/
+# error "libopus 1.0.1 or later required"
+#endif
+}
+
+static int op_make_decode_ready(OggOpusFile *_of){
+ const OpusHead *head;
+ int li;
+ int stream_count;
+ int coupled_count;
+ int channel_count;
+ if(_of->ready_state>OP_STREAMSET)return 0;
+ if(OP_UNLIKELY(_of->ready_state<OP_STREAMSET))return OP_EFAULT;
+ li=_of->seekable?_of->cur_link:0;
+ head=&_of->links[li].head;
+ stream_count=head->stream_count;
+ coupled_count=head->coupled_count;
+ channel_count=head->channel_count;
+ /*Check to see if the current decoder is compatible with the current link.*/
+ if(_of->od!=NULL&&_of->od_stream_count==stream_count
+ &&_of->od_coupled_count==coupled_count&&_of->od_channel_count==channel_count
+ &&memcmp(_of->od_mapping,head->mapping,
+ sizeof(*head->mapping)*channel_count)==0){
+ opus_multistream_decoder_ctl(_of->od,OPUS_RESET_STATE);
+ }
+ else{
+ int err;
+ opus_multistream_decoder_destroy(_of->od);
+ _of->od=opus_multistream_decoder_create(48000,channel_count,
+ stream_count,coupled_count,head->mapping,&err);
+ if(_of->od==NULL)return OP_EFAULT;
+ _of->od_stream_count=stream_count;
+ _of->od_coupled_count=coupled_count;
+ _of->od_channel_count=channel_count;
+ memcpy(_of->od_mapping,head->mapping,sizeof(*head->mapping)*channel_count);
+ }
+ _of->ready_state=OP_INITSET;
+ _of->bytes_tracked=0;
+ _of->samples_tracked=0;
+#if !defined(OPUS_FIXED_POINT)
+ _of->state_channel_count=0;
+ /*Use the serial number for the PRNG seed to get repeatable output for
+ straight play-throughs.*/
+ _of->dither_seed=_of->links[li].serialno;
+#endif
+ op_update_gain(_of);
+ return 0;
+}
+
+static int op_open_seekable2_impl(OggOpusFile *_of){
+ /*64 seek records should be enough for anybody.
+ Actually, with a bisection search in a 63-bit range down to OP_CHUNK_SIZE
+ granularity, much more than enough.*/
+ OpusSeekRecord sr[64];
+ opus_int64 data_offset;
+ int ret;
+ /*We can seek, so set out learning all about this file.*/
+ (*_of->callbacks.seek)(_of->source,0,SEEK_END);
+ _of->offset=_of->end=(*_of->callbacks.tell)(_of->source);
+ if(OP_UNLIKELY(_of->end<0))return OP_EREAD;
+ data_offset=_of->links[0].data_offset;
+ if(OP_UNLIKELY(_of->end<data_offset))return OP_EBADLINK;
+ /*Get the offset of the last page of the physical bitstream, or, if we're
+ lucky, the last Opus page of the first link, as most Ogg Opus files will
+ contain a single logical bitstream.*/
+ ret=op_get_prev_page_serial(_of,sr,_of->end,
+ _of->links[0].serialno,_of->serialnos,_of->nserialnos);
+ if(OP_UNLIKELY(ret<0))return ret;
+ /*If there's any trailing junk, forget about it.*/
+ _of->end=sr[0].offset+sr[0].size;
+ if(OP_UNLIKELY(_of->end<data_offset))return OP_EBADLINK;
+ /*Now enumerate the bitstream structure.*/
+ return op_bisect_forward_serialno(_of,data_offset,sr,sizeof(sr)/sizeof(*sr),
+ &_of->serialnos,&_of->nserialnos,&_of->cserialnos);
+}
+
+static int op_open_seekable2(OggOpusFile *_of){
+ ogg_sync_state oy_start;
+ ogg_stream_state os_start;
+ ogg_packet *op_start;
+ opus_int64 start_offset;
+ int start_op_count;
+ int ret;
+ /*We're partially open and have a first link header state in storage in _of.
+ Save off that stream state so we can come back to it.
+ It would be simpler to just dump all this state and seek back to
+ links[0].data_offset when we're done.
+ But we do the extra work to allow us to seek back to _exactly_ the same
+ stream position we're at now.
+ This allows, e.g., the HTTP backend to continue reading from the original
+ connection (if it's still available), instead of opening a new one.
+ This means we can open and start playing a normal Opus file with a single
+ link and reasonable packet sizes using only two HTTP requests.*/
+ start_op_count=_of->op_count;
+ /*This is a bit too large to put on the stack unconditionally.*/
+ op_start=(ogg_packet *)_ogg_malloc(sizeof(*op_start)*start_op_count);
+ if(op_start==NULL)return OP_EFAULT;
+ *&oy_start=_of->oy;
+ *&os_start=_of->os;
+ start_offset=_of->offset;
+ memcpy(op_start,_of->op,sizeof(*op_start)*start_op_count);
+ OP_ASSERT((*_of->callbacks.tell)(_of->source)==op_position(_of));
+ ogg_sync_init(&_of->oy);
+ ogg_stream_init(&_of->os,-1);
+ ret=op_open_seekable2_impl(_of);
+ /*Restore the old stream state.*/
+ ogg_stream_clear(&_of->os);
+ ogg_sync_clear(&_of->oy);
+ *&_of->oy=*&oy_start;
+ *&_of->os=*&os_start;
+ _of->offset=start_offset;
+ _of->op_count=start_op_count;
+ memcpy(_of->op,op_start,sizeof(*_of->op)*start_op_count);
+ _ogg_free(op_start);
+ _of->prev_packet_gp=_of->links[0].pcm_start;
+ _of->cur_discard_count=_of->links[0].head.pre_skip;
+ if(OP_UNLIKELY(ret<0))return ret;
+ /*And restore the position indicator.*/
+ ret=(*_of->callbacks.seek)(_of->source,op_position(_of),SEEK_SET);
+ return OP_UNLIKELY(ret<0)?OP_EREAD:0;
+}
+
+/*Clear out the current logical bitstream decoder.*/
+static void op_decode_clear(OggOpusFile *_of){
+ /*We don't actually free the decoder.
+ We might be able to re-use it for the next link.*/
+ _of->op_count=0;
+ _of->od_buffer_size=0;
+ _of->prev_packet_gp=-1;
+ if(!_of->seekable){
+ OP_ASSERT(_of->ready_state>=OP_INITSET);
+ opus_tags_clear(&_of->links[0].tags);
+ }
+ _of->ready_state=OP_OPENED;
+}
+
+static void op_clear(OggOpusFile *_of){
+ OggOpusLink *links;
+ _ogg_free(_of->od_buffer);
+ if(_of->od!=NULL)opus_multistream_decoder_destroy(_of->od);
+ links=_of->links;
+ if(!_of->seekable){
+ if(_of->ready_state>OP_OPENED||_of->ready_state==OP_PARTOPEN){
+ opus_tags_clear(&links[0].tags);
+ }
+ }
+ else if(OP_LIKELY(links!=NULL)){
+ int nlinks;
+ int link;
+ nlinks=_of->nlinks;
+ for(link=0;link<nlinks;link++)opus_tags_clear(&links[link].tags);
+ }
+ _ogg_free(links);
+ _ogg_free(_of->serialnos);
+ ogg_stream_clear(&_of->os);
+ ogg_sync_clear(&_of->oy);
+ if(_of->callbacks.close!=NULL)(*_of->callbacks.close)(_of->source);
+}
+
+static int op_open1(OggOpusFile *_of,
+ void *_source,const OpusFileCallbacks *_cb,
+ const unsigned char *_initial_data,size_t _initial_bytes){
+ ogg_page og;
+ ogg_page *pog;
+ int seekable;
+ int ret;
+ memset(_of,0,sizeof(*_of));
+ _of->end=-1;
+ _of->source=_source;
+ *&_of->callbacks=*_cb;
+ /*At a minimum, we need to be able to read data.*/
+ if(OP_UNLIKELY(_of->callbacks.read==NULL))return OP_EREAD;
+ /*Initialize the framing state.*/
+ ogg_sync_init(&_of->oy);
+ /*Perhaps some data was previously read into a buffer for testing against
+ other stream types.
+ Allow initialization from this previously read data (especially as we may
+ be reading from a non-seekable stream).
+ This requires copying it into a buffer allocated by ogg_sync_buffer() and
+ doesn't support seeking, so this is not a good mechanism to use for
+ decoding entire files from RAM.*/
+ if(_initial_bytes>0){
+ char *buffer;
+ buffer=ogg_sync_buffer(&_of->oy,_initial_bytes);
+ memcpy(buffer,_initial_data,_initial_bytes*sizeof(*buffer));
+ ogg_sync_wrote(&_of->oy,_initial_bytes);
+ }
+ /*Can we seek?
+ Stevens suggests the seek test is portable.*/
+ seekable=_cb->seek!=NULL&&(*_cb->seek)(_source,0,SEEK_CUR)!=-1;
+ /*If seek is implemented, tell must also be implemented.*/
+ if(seekable){
+ opus_int64 pos;
+ if(OP_UNLIKELY(_of->callbacks.tell==NULL))return OP_EINVAL;
+ pos=(*_of->callbacks.tell)(_of->source);
+ /*If the current position is not equal to the initial bytes consumed,
+ absolute seeking will not work.*/
+ if(OP_UNLIKELY(pos!=(opus_int64)_initial_bytes))return OP_EINVAL;
+ }
+ _of->seekable=seekable;
+ /*Don't seek yet.
+ Set up a 'single' (current) logical bitstream entry for partial open.*/
+ _of->links=(OggOpusLink *)_ogg_malloc(sizeof(*_of->links));
+ /*The serialno gets filled in later by op_fetch_headers().*/
+ ogg_stream_init(&_of->os,-1);
+ pog=NULL;
+ for(;;){
+ /*Fetch all BOS pages, store the Opus header and all seen serial numbers,
+ and load subsequent Opus setup headers.*/
+ ret=op_fetch_headers(_of,&_of->links[0].head,&_of->links[0].tags,
+ &_of->serialnos,&_of->nserialnos,&_of->cserialnos,pog);
+ if(OP_UNLIKELY(ret<0))break;
+ _of->nlinks=1;
+ _of->links[0].offset=0;
+ _of->links[0].data_offset=_of->offset;
+ _of->links[0].pcm_end=-1;
+ _of->links[0].serialno=_of->os.serialno;
+ /*Fetch the initial PCM offset.*/
+ ret=op_find_initial_pcm_offset(_of,_of->links,&og);
+ if(seekable||OP_LIKELY(ret<=0))break;
+ /*This link was empty, but we already have the BOS page for the next one in
+ og.
+ We can't seek, so start processing the next link right now.*/
+ opus_tags_clear(&_of->links[0].tags);
+ _of->nlinks=0;
+ if(!seekable)_of->cur_link++;
+ pog=&og;
+ }
+ if(OP_LIKELY(ret>=0))_of->ready_state=OP_PARTOPEN;
+ return ret;
+}
+
+static int op_open2(OggOpusFile *_of){
+ int ret;
+ OP_ASSERT(_of->ready_state==OP_PARTOPEN);
+ if(_of->seekable){
+ _of->ready_state=OP_OPENED;
+ ret=op_open_seekable2(_of);
+ }
+ else ret=0;
+ if(OP_LIKELY(ret>=0)){
+ /*We have buffered packets from op_find_initial_pcm_offset().
+ Move to OP_INITSET so we can use them.*/
+ _of->ready_state=OP_STREAMSET;
+ ret=op_make_decode_ready(_of);
+ if(OP_LIKELY(ret>=0))return 0;
+ }
+ /*Don't auto-close the stream on failure.*/
+ _of->callbacks.close=NULL;
+ op_clear(_of);
+ return ret;
+}
+
+OggOpusFile *op_test_callbacks(void *_source,const OpusFileCallbacks *_cb,
+ const unsigned char *_initial_data,size_t _initial_bytes,int *_error){
+ OggOpusFile *of;
+ int ret;
+ of=(OggOpusFile *)_ogg_malloc(sizeof(*of));
+ ret=OP_EFAULT;
+ if(OP_LIKELY(of!=NULL)){
+ ret=op_open1(of,_source,_cb,_initial_data,_initial_bytes);
+ if(OP_LIKELY(ret>=0)){
+ if(_error!=NULL)*_error=0;
+ return of;
+ }
+ /*Don't auto-close the stream on failure.*/
+ of->callbacks.close=NULL;
+ op_clear(of);
+ _ogg_free(of);
+ }
+ if(_error!=NULL)*_error=ret;
+ return NULL;
+}
+
+OggOpusFile *op_open_callbacks(void *_source,const OpusFileCallbacks *_cb,
+ const unsigned char *_initial_data,size_t _initial_bytes,int *_error){
+ OggOpusFile *of;
+ of=op_test_callbacks(_source,_cb,_initial_data,_initial_bytes,_error);
+ if(OP_LIKELY(of!=NULL)){
+ int ret;
+ ret=op_open2(of);
+ if(OP_LIKELY(ret>=0))return of;
+ if(_error!=NULL)*_error=ret;
+ _ogg_free(of);
+ }
+ return NULL;
+}
+
+/*Convenience routine to clean up from failure for the open functions that
+ create their own streams.*/
+static OggOpusFile *op_open_close_on_failure(void *_source,
+ const OpusFileCallbacks *_cb,int *_error){
+ OggOpusFile *of;
+ if(OP_UNLIKELY(_source==NULL)){
+ if(_error!=NULL)*_error=OP_EFAULT;
+ return NULL;
+ }
+ of=op_open_callbacks(_source,_cb,NULL,0,_error);
+ if(OP_UNLIKELY(of==NULL))(*_cb->close)(_source);
+ return of;
+}
+
+OggOpusFile *op_open_file(const char *_path,int *_error){
+ OpusFileCallbacks cb;
+ return op_open_close_on_failure(op_fopen(&cb,_path,"rb"),&cb,_error);
+}
+
+OggOpusFile *op_open_memory(const unsigned char *_data,size_t _size,
+ int *_error){
+ OpusFileCallbacks cb;
+ return op_open_close_on_failure(op_mem_stream_create(&cb,_data,_size),&cb,
+ _error);
+}
+
+/*Convenience routine to clean up from failure for the open functions that
+ create their own streams.*/
+static OggOpusFile *op_test_close_on_failure(void *_source,
+ const OpusFileCallbacks *_cb,int *_error){
+ OggOpusFile *of;
+ if(OP_UNLIKELY(_source==NULL)){
+ if(_error!=NULL)*_error=OP_EFAULT;
+ return NULL;
+ }
+ of=op_test_callbacks(_source,_cb,NULL,0,_error);
+ if(OP_UNLIKELY(of==NULL))(*_cb->close)(_source);
+ return of;
+}
+
+OggOpusFile *op_test_file(const char *_path,int *_error){
+ OpusFileCallbacks cb;
+ return op_test_close_on_failure(op_fopen(&cb,_path,"rb"),&cb,_error);
+}
+
+OggOpusFile *op_test_memory(const unsigned char *_data,size_t _size,
+ int *_error){
+ OpusFileCallbacks cb;
+ return op_test_close_on_failure(op_mem_stream_create(&cb,_data,_size),&cb,
+ _error);
+}
+
+int op_test_open(OggOpusFile *_of){
+ int ret;
+ if(OP_UNLIKELY(_of->ready_state!=OP_PARTOPEN))return OP_EINVAL;
+ ret=op_open2(_of);
+ /*op_open2() will clear this structure on failure.
+ Reset its contents to prevent double-frees in op_free().*/
+ if(OP_UNLIKELY(ret<0))memset(_of,0,sizeof(*_of));
+ return ret;
+}
+
+void op_free(OggOpusFile *_of){
+ if(OP_LIKELY(_of!=NULL)){
+ op_clear(_of);
+ _ogg_free(_of);
+ }
+}
+
+int op_seekable(const OggOpusFile *_of){
+ return _of->seekable;
+}
+
+int op_link_count(const OggOpusFile *_of){
+ return _of->nlinks;
+}
+
+ogg_uint32_t op_serialno(const OggOpusFile *_of,int _li){
+ if(OP_UNLIKELY(_li>=_of->nlinks))_li=_of->nlinks-1;
+ if(!_of->seekable)_li=0;
+ return _of->links[_li<0?_of->cur_link:_li].serialno;
+}
+
+int op_channel_count(const OggOpusFile *_of,int _li){
+ return op_head(_of,_li)->channel_count;
+}
+
+opus_int64 op_raw_total(const OggOpusFile *_of,int _li){
+ if(OP_UNLIKELY(_of->ready_state<OP_OPENED)
+ ||OP_UNLIKELY(!_of->seekable)
+ ||OP_UNLIKELY(_li>=_of->nlinks)){
+ return OP_EINVAL;
+ }
+ if(_li<0)return _of->end-_of->links[0].offset;
+ return (_li+1>=_of->nlinks?_of->end:_of->links[_li+1].offset)
+ -_of->links[_li].offset;
+}
+
+ogg_int64_t op_pcm_total(const OggOpusFile *_of,int _li){
+ OggOpusLink *links;
+ ogg_int64_t diff;
+ int nlinks;
+ nlinks=_of->nlinks;
+ if(OP_UNLIKELY(_of->ready_state<OP_OPENED)
+ ||OP_UNLIKELY(!_of->seekable)
+ ||OP_UNLIKELY(_li>=nlinks)){
+ return OP_EINVAL;
+ }
+ links=_of->links;
+ /*We verify that the granule position differences are larger than the
+ pre-skip and that the total duration does not overflow during link
+ enumeration, so we don't have to check here.*/
+ if(_li<0){
+ ogg_int64_t pcm_total;
+ int li;
+ pcm_total=0;
+ for(li=0;li<nlinks;li++){
+ OP_ALWAYS_TRUE(!op_granpos_diff(&diff,
+ links[li].pcm_end,links[li].pcm_start));
+ pcm_total+=diff-links[li].head.pre_skip;
+ }
+ return pcm_total;
+ }
+ OP_ALWAYS_TRUE(!op_granpos_diff(&diff,
+ links[_li].pcm_end,links[_li].pcm_start));
+ return diff-links[_li].head.pre_skip;
+}
+
+const OpusHead *op_head(const OggOpusFile *_of,int _li){
+ if(OP_UNLIKELY(_li>=_of->nlinks))_li=_of->nlinks-1;
+ if(!_of->seekable)_li=0;
+ return &_of->links[_li<0?_of->cur_link:_li].head;
+}
+
+const OpusTags *op_tags(const OggOpusFile *_of,int _li){
+ if(OP_UNLIKELY(_li>=_of->nlinks))_li=_of->nlinks-1;
+ if(!_of->seekable){
+ if(_of->ready_state<OP_STREAMSET&&_of->ready_state!=OP_PARTOPEN){
+ return NULL;
+ }
+ _li=0;
+ }
+ else if(_li<0)_li=_of->ready_state>=OP_STREAMSET?_of->cur_link:0;
+ return &_of->links[_li].tags;
+}
+
+int op_current_link(const OggOpusFile *_of){
+ if(OP_UNLIKELY(_of->ready_state<OP_OPENED))return OP_EINVAL;
+ return _of->cur_link;
+}
+
+/*Compute an average bitrate given a byte and sample count.
+ Return: The bitrate in bits per second.*/
+static opus_int32 op_calc_bitrate(opus_int64 _bytes,ogg_int64_t _samples){
+ /*These rates are absurd, but let's handle them anyway.*/
+ if(OP_UNLIKELY(_bytes>(OP_INT64_MAX-(_samples>>1))/(48000*8))){
+ ogg_int64_t den;
+ if(OP_UNLIKELY(_bytes/(OP_INT32_MAX/(48000*8))>=_samples)){
+ return OP_INT32_MAX;
+ }
+ den=_samples/(48000*8);
+ return (opus_int32)((_bytes+(den>>1))/den);
+ }
+ if(OP_UNLIKELY(_samples<=0))return OP_INT32_MAX;
+ /*This can't actually overflow in normal operation: even with a pre-skip of
+ 545 2.5 ms frames with 8 streams running at 1282*8+1 bytes per packet
+ (1275 byte frames + Opus framing overhead + Ogg lacing values), that all
+ produce a single sample of decoded output, we still don't top 45 Mbps.
+ The only way to get bitrates larger than that is with excessive Opus
+ padding, more encoded streams than output channels, or lots and lots of
+ Ogg pages with no packets on them.*/
+ return (opus_int32)OP_MIN((_bytes*48000*8+(_samples>>1))/_samples,
+ OP_INT32_MAX);
+}
+
+opus_int32 op_bitrate(const OggOpusFile *_of,int _li){
+ if(OP_UNLIKELY(_of->ready_state<OP_OPENED)||OP_UNLIKELY(!_of->seekable)
+ ||OP_UNLIKELY(_li>=_of->nlinks)){
+ return OP_EINVAL;
+ }
+ return op_calc_bitrate(op_raw_total(_of,_li),op_pcm_total(_of,_li));
+}
+
+opus_int32 op_bitrate_instant(OggOpusFile *_of){
+ ogg_int64_t samples_tracked;
+ opus_int32 ret;
+ if(OP_UNLIKELY(_of->ready_state<OP_OPENED))return OP_EINVAL;
+ samples_tracked=_of->samples_tracked;
+ if(OP_UNLIKELY(samples_tracked==0))return OP_FALSE;
+ ret=op_calc_bitrate(_of->bytes_tracked,samples_tracked);
+ _of->bytes_tracked=0;
+ _of->samples_tracked=0;
+ return ret;
+}
+
+/*Fetch and process a page.
+ This handles the case where we're at a bitstream boundary and dumps the
+ decoding machine.
+ If the decoding machine is unloaded, it loads it.
+ It also keeps prev_packet_gp up to date (seek and read both use this; seek
+ uses a special hack with _readp).
+ Return: <0) Error, OP_HOLE (lost packet), or OP_EOF.
+ 0) Need more data (only if _readp==0).
+ 1) Got at least one audio data packet.*/
+static int op_fetch_and_process_page(OggOpusFile *_of,
+ ogg_page *_og,opus_int64 _page_pos,int _readp,int _spanp,int _ignore_holes){
+ OggOpusLink *links;
+ ogg_uint32_t cur_serialno;
+ int seekable;
+ int cur_link;
+ int ret;
+ /*We shouldn't get here if we have unprocessed packets.*/
+ OP_ASSERT(_of->ready_state<OP_INITSET||_of->op_pos>=_of->op_count);
+ if(!_readp)return 0;
+ seekable=_of->seekable;
+ links=_of->links;
+ cur_link=seekable?_of->cur_link:0;
+ cur_serialno=links[cur_link].serialno;
+ /*Handle one page.*/
+ for(;;){
+ ogg_page og;
+ OP_ASSERT(_of->ready_state>=OP_OPENED);
+ /*This loop is not strictly necessary, but there's no sense in doing the
+ extra checks of the larger loop for the common case in a multiplexed
+ bistream where the page is simply part of a different logical
+ bitstream.*/
+ do{
+ /*If we were given a page to use, use it.*/
+ if(_og!=NULL){
+ *&og=*_og;
+ _og=NULL;
+ }
+ /*Keep reading until we get a page with the correct serialno.*/
+ else _page_pos=op_get_next_page(_of,&og,_of->end);
+ /*EOF: Leave uninitialized.*/
+ if(_page_pos<0)return _page_pos<OP_FALSE?(int)_page_pos:OP_EOF;
+ if(OP_LIKELY(_of->ready_state>=OP_STREAMSET)){
+ if(cur_serialno!=(ogg_uint32_t)ogg_page_serialno(&og)){
+ /*Two possibilities:
+ 1) Another stream is multiplexed into this logical section, or*/
+ if(OP_LIKELY(!ogg_page_bos(&og)))continue;
+ /* 2) Our decoding just traversed a bitstream boundary.*/
+ if(!_spanp)return OP_EOF;
+ if(OP_LIKELY(_of->ready_state>=OP_INITSET))op_decode_clear(_of);
+ break;
+ }
+ }
+ /*Bitrate tracking: add the header's bytes here.
+ The body bytes are counted when we consume the packets.*/
+ _of->bytes_tracked+=og.header_len;
+ }
+ while(0);
+ /*Do we need to load a new machine before submitting the page?
+ This is different in the seekable and non-seekable cases.
+ In the seekable case, we already have all the header information loaded
+ and cached.
+ We just initialize the machine with it and continue on our merry way.
+ In the non-seekable (streaming) case, we'll only be at a boundary if we
+ just left the previous logical bitstream, and we're now nominally at the
+ header of the next bitstream.*/
+ if(OP_UNLIKELY(_of->ready_state<OP_STREAMSET)){
+ if(seekable){
+ ogg_uint32_t serialno;
+ int nlinks;
+ int li;
+ serialno=ogg_page_serialno(&og);
+ /*Match the serialno to bitstream section.
+ We use this rather than offset positions to avoid problems near
+ logical bitstream boundaries.*/
+ nlinks=_of->nlinks;
+ for(li=0;li<nlinks&&links[li].serialno!=serialno;li++);
+ /*Not a desired Opus bitstream section.
+ Keep trying.*/
+ if(li>=nlinks)continue;
+ cur_serialno=serialno;
+ _of->cur_link=cur_link=li;
+ ogg_stream_reset_serialno(&_of->os,serialno);
+ _of->ready_state=OP_STREAMSET;
+ /*If we're at the start of this link, initialize the granule position
+ and pre-skip tracking.*/
+ if(_page_pos<=links[cur_link].data_offset){
+ _of->prev_packet_gp=links[cur_link].pcm_start;
+ _of->cur_discard_count=links[cur_link].head.pre_skip;
+ /*Ignore a hole at the start of a new link (this is common for
+ streams joined in the middle) or after seeking.*/
+ _ignore_holes=1;
+ }
+ }
+ else{
+ do{
+ /*We're streaming.
+ Fetch the two header packets, build the info struct.*/
+ ret=op_fetch_headers(_of,&links[0].head,&links[0].tags,
+ NULL,NULL,NULL,&og);
+ if(OP_UNLIKELY(ret<0))return ret;
+ /*op_find_initial_pcm_offset() will suppress any initial hole for us,
+ so no need to set _ignore_holes.*/
+ ret=op_find_initial_pcm_offset(_of,links,&og);
+ if(OP_UNLIKELY(ret<0))return ret;
+ _of->links[0].serialno=cur_serialno=_of->os.serialno;
+ _of->cur_link++;
+ }
+ /*If the link was empty, keep going, because we already have the
+ BOS page of the next one in og.*/
+ while(OP_UNLIKELY(ret>0));
+ /*If we didn't get any packets out of op_find_initial_pcm_offset(),
+ keep going (this is possible if end-trimming trimmed them all).*/
+ if(_of->op_count<=0)continue;
+ /*Otherwise, we're done.*/
+ ret=op_make_decode_ready(_of);
+ if(OP_UNLIKELY(ret<0))return ret;
+ return 1;
+ }
+ }
+ /*The buffered page is the data we want, and we're ready for it.
+ Add it to the stream state.*/
+ if(OP_UNLIKELY(_of->ready_state==OP_STREAMSET)){
+ ret=op_make_decode_ready(_of);
+ if(OP_UNLIKELY(ret<0))return ret;
+ }
+ /*Extract all the packets from the current page.*/
+ ogg_stream_pagein(&_of->os,&og);
+ if(OP_LIKELY(_of->ready_state>=OP_INITSET)){
+ opus_int32 total_duration;
+ int durations[255];
+ int op_count;
+ total_duration=op_collect_audio_packets(_of,durations);
+ if(OP_UNLIKELY(total_duration<0)){
+ /*Drain the packets from the page anyway.*/
+ total_duration=op_collect_audio_packets(_of,durations);
+ OP_ASSERT(total_duration>=0);
+ /*Report holes to the caller.*/
+ if(!_ignore_holes)return OP_HOLE;
+ }
+ op_count=_of->op_count;
+ /*If we found at least one audio data packet, compute per-packet granule
+ positions for them.*/
+ if(op_count>0){
+ ogg_int64_t diff;
+ ogg_int64_t prev_packet_gp;
+ ogg_int64_t cur_packet_gp;
+ ogg_int64_t cur_page_gp;
+ int cur_page_eos;
+ int pi;
+ cur_page_gp=_of->op[op_count-1].granulepos;
+ cur_page_eos=_of->op[op_count-1].e_o_s;
+ prev_packet_gp=_of->prev_packet_gp;
+ if(OP_UNLIKELY(prev_packet_gp==-1)){
+ opus_int32 cur_discard_count;
+ /*This is the first call after a raw seek.
+ Try to reconstruct prev_packet_gp from scratch.*/
+ OP_ASSERT(seekable);
+ if(OP_UNLIKELY(cur_page_eos)){
+ /*If the first page we hit after our seek was the EOS page, and
+ we didn't start from data_offset or before, we don't have
+ enough information to do end-trimming.
+ Proceed to the next link, rather than risk playing back some
+ samples that shouldn't have been played.*/
+ _of->op_count=0;
+ continue;
+ }
+ /*By default discard 80 ms of data after a seek, unless we seek
+ into the pre-skip region.*/
+ cur_discard_count=80*48;
+ cur_page_gp=_of->op[op_count-1].granulepos;
+ /*Try to initialize prev_packet_gp.
+ If the current page had packets but didn't have a granule
+ position, or the granule position it had was too small (both
+ illegal), just use the starting granule position for the link.*/
+ prev_packet_gp=links[cur_link].pcm_start;
+ if(OP_LIKELY(cur_page_gp!=-1)){
+ op_granpos_add(&prev_packet_gp,cur_page_gp,-total_duration);
+ }
+ if(OP_LIKELY(!op_granpos_diff(&diff,
+ prev_packet_gp,links[cur_link].pcm_start))){
+ opus_int32 pre_skip;
+ /*If we start at the beginning of the pre-skip region, or we're
+ at least 80 ms from the end of the pre-skip region, we discard
+ to the end of the pre-skip region.
+ Otherwise, we still use the 80 ms default, which will discard
+ past the end of the pre-skip region.*/
+ pre_skip=links[cur_link].head.pre_skip;
+ if(diff>=0&&diff<=OP_MAX(0,pre_skip-80*48)){
+ cur_discard_count=pre_skip-(int)diff;
+ }
+ }
+ _of->cur_discard_count=cur_discard_count;
+ }
+ if(OP_UNLIKELY(cur_page_gp==-1)){
+ /*This page had completed packets but didn't have a valid granule
+ position.
+ This is illegal, but we'll try to handle it by continuing to count
+ forwards from the previous page.*/
+ if(op_granpos_add(&cur_page_gp,prev_packet_gp,total_duration)<0){
+ /*The timestamp for this page overflowed.*/
+ cur_page_gp=links[cur_link].pcm_end;
+ }
+ }
+ /*If we hit the last page, handle end-trimming.*/
+ if(OP_UNLIKELY(cur_page_eos)
+ &&OP_LIKELY(!op_granpos_diff(&diff,cur_page_gp,prev_packet_gp))
+ &&OP_LIKELY(diff<total_duration)){
+ cur_packet_gp=prev_packet_gp;
+ for(pi=0;pi<op_count;pi++){
+ diff=durations[pi]-diff;
+ /*If we have samples to trim...*/
+ if(diff>0){
+ /*If we trimmed the entire packet, stop (the spec says encoders
+ shouldn't do this, but we support it anyway).*/
+ if(OP_UNLIKELY(diff>durations[pi]))break;
+ cur_packet_gp=cur_page_gp;
+ /*Move the EOS flag to this packet, if necessary, so we'll trim
+ the samples during decode.*/
+ _of->op[pi].e_o_s=1;
+ }
+ else{
+ /*Update the granule position as normal.*/
+ OP_ALWAYS_TRUE(!op_granpos_add(&cur_packet_gp,
+ cur_packet_gp,durations[pi]));
+ }
+ _of->op[pi].granulepos=cur_packet_gp;
+ OP_ALWAYS_TRUE(!op_granpos_diff(&diff,cur_page_gp,cur_packet_gp));
+ }
+ }
+ else{
+ /*Propagate timestamps to earlier packets.
+ op_granpos_add(&prev_packet_gp,prev_packet_gp,total_duration)
+ should succeed and give prev_packet_gp==cur_page_gp.
+ But we don't bother to check that, as there isn't much we can do
+ if it's not true.
+ The only thing we guarantee is that the start and end granule
+ positions of the packets are valid, and that they are monotonic
+ within a page.
+ They might be completely out of range for this link (we'll check
+ that elsewhere), or non-monotonic between pages.*/
+ if(OP_UNLIKELY(op_granpos_add(&prev_packet_gp,
+ cur_page_gp,-total_duration)<0)){
+ /*The starting timestamp for the first packet on this page
+ underflowed.
+ This is illegal, but we ignore it.*/
+ prev_packet_gp=0;
+ }
+ for(pi=0;pi<op_count;pi++){
+ if(OP_UNLIKELY(op_granpos_add(&cur_packet_gp,
+ cur_page_gp,-total_duration)<0)){
+ /*The start timestamp for this packet underflowed.
+ This is illegal, but we ignore it.*/
+ cur_packet_gp=0;
+ }
+ total_duration-=durations[pi];
+ OP_ASSERT(total_duration>=0);
+ OP_ALWAYS_TRUE(!op_granpos_add(&cur_packet_gp,
+ cur_packet_gp,durations[pi]));
+ _of->op[pi].granulepos=cur_packet_gp;
+ }
+ OP_ASSERT(total_duration==0);
+ }
+ _of->prev_packet_gp=prev_packet_gp;
+ _of->op_count=pi;
+ /*If end-trimming didn't trim all the packets, we're done.*/
+ if(OP_LIKELY(pi>0))return 1;
+ }
+ }
+ }
+}
+
+int op_raw_seek(OggOpusFile *_of,opus_int64 _pos){
+ int ret;
+ if(OP_UNLIKELY(_of->ready_state<OP_OPENED))return OP_EINVAL;
+ /*Don't dump the decoder state if we can't seek.*/
+ if(OP_UNLIKELY(!_of->seekable))return OP_ENOSEEK;
+ if(OP_UNLIKELY(_pos<0)||OP_UNLIKELY(_pos>_of->end))return OP_EINVAL;
+ /*Clear out any buffered, decoded data.*/
+ op_decode_clear(_of);
+ _of->bytes_tracked=0;
+ _of->samples_tracked=0;
+ ret=op_seek_helper(_of,_pos);
+ if(OP_UNLIKELY(ret<0))return OP_EREAD;
+ ret=op_fetch_and_process_page(_of,NULL,-1,1,1,1);
+ /*If we hit EOF, op_fetch_and_process_page() leaves us uninitialized.
+ Instead, jump to the end.*/
+ if(ret==OP_EOF){
+ int cur_link;
+ op_decode_clear(_of);
+ cur_link=_of->nlinks-1;
+ _of->cur_link=cur_link;
+ _of->prev_packet_gp=_of->links[cur_link].pcm_end;
+ _of->cur_discard_count=0;
+ ret=0;
+ }
+ else if(ret>0)ret=0;
+ return ret;
+}
+
+/*Convert a PCM offset relative to the start of the whole stream to a granule
+ position in an individual link.*/
+static ogg_int64_t op_get_granulepos(const OggOpusFile *_of,
+ ogg_int64_t _pcm_offset,int *_li){
+ const OggOpusLink *links;
+ ogg_int64_t duration;
+ int nlinks;
+ int li;
+ OP_ASSERT(_pcm_offset>=0);
+ nlinks=_of->nlinks;
+ links=_of->links;
+ for(li=0;OP_LIKELY(li<nlinks);li++){
+ ogg_int64_t pcm_start;
+ opus_int32 pre_skip;
+ pcm_start=links[li].pcm_start;
+ pre_skip=links[li].head.pre_skip;
+ OP_ALWAYS_TRUE(!op_granpos_diff(&duration,links[li].pcm_end,pcm_start));
+ duration-=pre_skip;
+ if(_pcm_offset<duration){
+ _pcm_offset+=pre_skip;
+ if(OP_UNLIKELY(pcm_start>OP_INT64_MAX-_pcm_offset)){
+ /*Adding this amount to the granule position would overflow the positive
+ half of its 64-bit range.
+ Since signed overflow is undefined in C, do it in a way the compiler
+ isn't allowed to screw up.*/
+ _pcm_offset-=OP_INT64_MAX-pcm_start+1;
+ pcm_start=OP_INT64_MIN;
+ }
+ pcm_start+=_pcm_offset;
+ *_li=li;
+ return pcm_start;
+ }
+ _pcm_offset-=duration;
+ }
+ return -1;
+}
+
+/*This controls how close the target has to be to use the current stream
+ position to subdivide the initial range.
+ Two minutes seems to be a good default.*/
+#define OP_CUR_TIME_THRESH (120*48*(opus_int32)1000)
+
+/*Note: The OP_SMALL_FOOTPRINT #define doesn't (currently) save much code size,
+ but it's meant to serve as documentation for portions of the seeking
+ algorithm that are purely optional, to aid others learning from/porting this
+ code to other contexts.*/
+/*#define OP_SMALL_FOOTPRINT (1)*/
+
+/*Search within link _li for the page with the highest granule position
+ preceding (or equal to) _target_gp.
+ There is a danger here: missing pages or incorrect frame number information
+ in the bitstream could make our task impossible.
+ Account for that (and report it as an error condition).*/
+static int op_pcm_seek_page(OggOpusFile *_of,
+ ogg_int64_t _target_gp,int _li){
+ const OggOpusLink *link;
+ ogg_page og;
+ ogg_int64_t pcm_pre_skip;
+ ogg_int64_t pcm_start;
+ ogg_int64_t pcm_end;
+ ogg_int64_t best_gp;
+ ogg_int64_t diff;
+ ogg_uint32_t serialno;
+ opus_int32 pre_skip;
+ opus_int64 begin;
+ opus_int64 end;
+ opus_int64 boundary;
+ opus_int64 best;
+ opus_int64 page_offset;
+ opus_int64 d0;
+ opus_int64 d1;
+ opus_int64 d2;
+ int force_bisect;
+ int ret;
+ _of->bytes_tracked=0;
+ _of->samples_tracked=0;
+ link=_of->links+_li;
+ best_gp=pcm_start=link->pcm_start;
+ pcm_end=link->pcm_end;
+ serialno=link->serialno;
+ best=begin=link->data_offset;
+ page_offset=-1;
+ /*We discard the first 80 ms of data after a seek, so seek back that much
+ farther.
+ If we can't, simply seek to the beginning of the link.*/
+ if(OP_UNLIKELY(op_granpos_add(&_target_gp,_target_gp,-80*48)<0)
+ ||OP_UNLIKELY(op_granpos_cmp(_target_gp,pcm_start)<0)){
+ _target_gp=pcm_start;
+ }
+ /*Special case seeking to the start of the link.*/
+ pre_skip=link->head.pre_skip;
+ OP_ALWAYS_TRUE(!op_granpos_add(&pcm_pre_skip,pcm_start,pre_skip));
+ if(op_granpos_cmp(_target_gp,pcm_pre_skip)<0)end=boundary=begin;
+ else{
+ end=boundary=link->end_offset;
+#if !defined(OP_SMALL_FOOTPRINT)
+ /*If we were decoding from this link, we can narrow the range a bit.*/
+ if(_li==_of->cur_link&&_of->ready_state>=OP_INITSET){
+ opus_int64 offset;
+ int op_count;
+ op_count=_of->op_count;
+ /*The only way the offset can be invalid _and_ we can fail the granule
+ position checks below is if someone changed the contents of the last
+ page since we read it.
+ We'd be within our rights to just return OP_EBADLINK in that case, but
+ we'll simply ignore the current position instead.*/
+ offset=_of->offset;
+ if(op_count>0&&OP_LIKELY(offset<=end)){
+ ogg_int64_t gp;
+ /*Make sure the timestamp is valid.
+ The granule position might be -1 if we collected the packets from a
+ page without a granule position after reporting a hole.*/
+ gp=_of->op[op_count-1].granulepos;
+ if(OP_LIKELY(gp!=-1)&&OP_LIKELY(op_granpos_cmp(pcm_start,gp)<0)
+ &&OP_LIKELY(op_granpos_cmp(pcm_end,gp)>0)){
+ OP_ALWAYS_TRUE(!op_granpos_diff(&diff,gp,_target_gp));
+ /*We only actually use the current time if either
+ a) We can cut off at least half the range, or
+ b) We're seeking sufficiently close to the current position that
+ it's likely to be informative.
+ Otherwise it appears using the whole link range to estimate the
+ first seek location gives better results, on average.*/
+ if(diff<0){
+ OP_ASSERT(offset>=begin);
+ if(offset-begin>=end-begin>>1||diff>-OP_CUR_TIME_THRESH){
+ best=begin=offset;
+ best_gp=pcm_start=gp;
+ }
+ }
+ else{
+ ogg_int64_t prev_page_gp;
+ /*We might get lucky and already have the packet with the target
+ buffered.
+ Worth checking.
+ For very small files (with all of the data in a single page,
+ generally 1 second or less), we can loop them continuously
+ without seeking at all.*/
+ OP_ALWAYS_TRUE(!op_granpos_add(&prev_page_gp,_of->op[0].granulepos,
+ op_get_packet_duration(_of->op[0].packet,_of->op[0].bytes)));
+ if(op_granpos_cmp(prev_page_gp,_target_gp)<=0){
+ /*Don't call op_decode_clear(), because it will dump our
+ packets.*/
+ _of->op_pos=0;
+ _of->od_buffer_size=0;
+ _of->prev_packet_gp=prev_page_gp;
+ _of->ready_state=OP_STREAMSET;
+ return op_make_decode_ready(_of);
+ }
+ /*No such luck.
+ Check if we can cut off at least half the range, though.*/
+ if(offset-begin<=end-begin>>1||diff<OP_CUR_TIME_THRESH){
+ /*We really want the page start here, but this will do.*/
+ end=boundary=offset;
+ pcm_end=gp;
+ }
+ }
+ }
+ }
+ }
+#endif
+ }
+ /*This code was originally based on the "new search algorithm by HB (Nicholas
+ Vinen)" from libvorbisfile.
+ It has been modified substantially since.*/
+ op_decode_clear(_of);
+ /*Initialize the interval size history.*/
+ d2=d1=d0=end-begin;
+ force_bisect=0;
+ while(begin<end){
+ opus_int64 bisect;
+ opus_int64 next_boundary;
+ opus_int32 chunk_size;
+ if(end-begin<OP_CHUNK_SIZE)bisect=begin;
+ else{
+ /*Update the interval size history.*/
+ d0=d1>>1;
+ d1=d2>>1;
+ d2=end-begin>>1;
+ if(force_bisect)bisect=begin+(end-begin>>1);
+ else{
+ ogg_int64_t diff2;
+ OP_ALWAYS_TRUE(!op_granpos_diff(&diff,_target_gp,pcm_start));
+ OP_ALWAYS_TRUE(!op_granpos_diff(&diff2,pcm_end,pcm_start));
+ /*Take a (pretty decent) guess.*/
+ bisect=begin+op_rescale64(diff,diff2,end-begin)-OP_CHUNK_SIZE;
+ }
+ if(bisect-OP_CHUNK_SIZE<begin)bisect=begin;
+ force_bisect=0;
+ }
+ if(bisect!=_of->offset){
+ page_offset=-1;
+ ret=op_seek_helper(_of,bisect);
+ if(OP_UNLIKELY(ret<0))return ret;
+ }
+ chunk_size=OP_CHUNK_SIZE;
+ next_boundary=boundary;
+ while(begin<end){
+ page_offset=op_get_next_page(_of,&og,boundary);
+ if(page_offset<0){
+ if(page_offset<OP_FALSE)return (int)page_offset;
+ /*There are no more pages in our interval from our stream with a valid
+ timestamp that start at position bisect or later.*/
+ /*If we scanned the whole interval, we're done.*/
+ if(bisect<=begin+1)end=begin;
+ else{
+ /*Otherwise, back up one chunk.*/
+ bisect=OP_MAX(bisect-chunk_size,begin);
+ ret=op_seek_helper(_of,bisect);
+ if(OP_UNLIKELY(ret<0))return ret;
+ /*Bump up the chunk size.*/
+ chunk_size=OP_MIN(2*chunk_size,OP_CHUNK_SIZE_MAX);
+ /*If we did find a page from another stream or without a timestamp,
+ don't read past it.*/
+ boundary=next_boundary;
+ }
+ }
+ else{
+ ogg_int64_t gp;
+ /*Save the offset of the first page we found after the seek, regardless
+ of the stream it came from or whether or not it has a timestamp.*/
+ next_boundary=OP_MIN(page_offset,next_boundary);
+ if(serialno!=(ogg_uint32_t)ogg_page_serialno(&og))continue;
+ gp=ogg_page_granulepos(&og);
+ if(gp==-1)continue;
+ if(op_granpos_cmp(gp,_target_gp)<0){
+ /*We found a page that ends before our target.
+ Advance to the raw offset of the next page.*/
+ begin=_of->offset;
+ if(OP_UNLIKELY(op_granpos_cmp(pcm_start,gp)>0)
+ ||OP_UNLIKELY(op_granpos_cmp(pcm_end,gp)<0)){
+ /*Don't let pcm_start get out of range!
+ That could happen with an invalid timestamp.*/
+ break;
+ }
+ /*Save the byte offset of the end of the page with this granule
+ position.*/
+ best=begin;
+ best_gp=pcm_start=gp;
+ OP_ALWAYS_TRUE(!op_granpos_diff(&diff,_target_gp,pcm_start));
+ /*If we're more than a second away from our target, break out and
+ do another bisection.*/
+ if(diff>48000)break;
+ /*Otherwise, keep scanning forward (do NOT use begin+1).*/
+ bisect=begin;
+ }
+ else{
+ /*We found a page that ends after our target.*/
+ /*If we scanned the whole interval before we found it, we're done.*/
+ if(bisect<=begin+1)end=begin;
+ else{
+ end=bisect;
+ /*In later iterations, don't read past the first page we found.*/
+ boundary=next_boundary;
+ /*If we're not making much progress shrinking the interval size,
+ start forcing straight bisection to limit the worst case.*/
+ force_bisect=end-begin>d0*2;
+ /*Don't let pcm_end get out of range!
+ That could happen with an invalid timestamp.*/
+ if(OP_LIKELY(op_granpos_cmp(pcm_end,gp)>0)
+ &&OP_LIKELY(op_granpos_cmp(pcm_start,gp)<=0)){
+ pcm_end=gp;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ /*Found our page.
+ Seek to the end of it and update prev_packet_gp.
+ Our caller will set cur_discard_count.
+ This is an easier case than op_raw_seek(), as we don't need to keep any
+ packets from the page we found.*/
+ /*Seek, if necessary.*/
+ if(best!=page_offset){
+ page_offset=-1;
+ ret=op_seek_helper(_of,best);
+ if(OP_UNLIKELY(ret<0))return ret;
+ }
+ OP_ASSERT(op_granpos_cmp(best_gp,pcm_start)>=0);
+ _of->cur_link=_li;
+ _of->ready_state=OP_STREAMSET;
+ _of->prev_packet_gp=best_gp;
+ ogg_stream_reset_serialno(&_of->os,serialno);
+ ret=op_fetch_and_process_page(_of,page_offset<0?NULL:&og,page_offset,1,0,1);
+ if(OP_UNLIKELY(ret<=0))return OP_EBADLINK;
+ /*Verify result.*/
+ if(OP_UNLIKELY(op_granpos_cmp(_of->prev_packet_gp,_target_gp)>0)){
+ return OP_EBADLINK;
+ }
+ return 0;
+}
+
+int op_pcm_seek(OggOpusFile *_of,ogg_int64_t _pcm_offset){
+ const OggOpusLink *link;
+ ogg_int64_t pcm_start;
+ ogg_int64_t target_gp;
+ ogg_int64_t prev_packet_gp;
+ ogg_int64_t skip;
+ ogg_int64_t diff;
+ int op_count;
+ int op_pos;
+ int ret;
+ int li;
+ if(OP_UNLIKELY(_of->ready_state<OP_OPENED))return OP_EINVAL;
+ if(OP_UNLIKELY(!_of->seekable))return OP_ENOSEEK;
+ if(OP_UNLIKELY(_pcm_offset<0))return OP_EINVAL;
+ target_gp=op_get_granulepos(_of,_pcm_offset,&li);
+ if(OP_UNLIKELY(target_gp==-1))return OP_EINVAL;
+ link=_of->links+li;
+ pcm_start=link->pcm_start;
+ OP_ALWAYS_TRUE(!op_granpos_diff(&_pcm_offset,target_gp,pcm_start));
+#if !defined(OP_SMALL_FOOTPRINT)
+ /*For small (90 ms or less) forward seeks within the same link, just decode
+ forward.
+ This also optimizes the case of seeking to the current position.*/
+ if(li==_of->cur_link&&_of->ready_state>=OP_INITSET){
+ ogg_int64_t gp;
+ gp=_of->prev_packet_gp;
+ if(OP_LIKELY(gp!=-1)){
+ int nbuffered;
+ nbuffered=OP_MAX(_of->od_buffer_size-_of->od_buffer_pos,0);
+ OP_ALWAYS_TRUE(!op_granpos_add(&gp,gp,-nbuffered));
+ /*We do _not_ add cur_discard_count to gp.
+ Otherwise the total amount to discard could grow without bound, and it
+ would be better just to do a full seek.*/
+ if(OP_LIKELY(!op_granpos_diff(&diff,gp,pcm_start))){
+ ogg_int64_t discard_count;
+ discard_count=_pcm_offset-diff;
+ /*We use a threshold of 90 ms instead of 80, since 80 ms is the
+ _minimum_ we would have discarded after a full seek.
+ Assuming 20 ms frames (the default), we'd discard 90 ms on average.*/
+ if(discard_count>=0&&OP_UNLIKELY(discard_count<90*48)){
+ _of->cur_discard_count=(opus_int32)discard_count;
+ return 0;
+ }
+ }
+ }
+ }
+#endif
+ ret=op_pcm_seek_page(_of,target_gp,li);
+ if(OP_UNLIKELY(ret<0))return ret;
+ /*Now skip samples until we actually get to our target.*/
+ /*Figure out where we should skip to.*/
+ if(_pcm_offset<=link->head.pre_skip)skip=0;
+ else skip=OP_MAX(_pcm_offset-80*48,0);
+ OP_ASSERT(_pcm_offset-skip>=0);
+ OP_ASSERT(_pcm_offset-skip<OP_INT32_MAX-120*48);
+ /*Skip packets until we find one with samples past our skip target.*/
+ for(;;){
+ op_count=_of->op_count;
+ prev_packet_gp=_of->prev_packet_gp;
+ for(op_pos=_of->op_pos;op_pos<op_count;op_pos++){
+ ogg_int64_t cur_packet_gp;
+ cur_packet_gp=_of->op[op_pos].granulepos;
+ if(OP_LIKELY(!op_granpos_diff(&diff,cur_packet_gp,pcm_start))
+ &&diff>skip){
+ break;
+ }
+ prev_packet_gp=cur_packet_gp;
+ }
+ _of->prev_packet_gp=prev_packet_gp;
+ _of->op_pos=op_pos;
+ if(op_pos<op_count)break;
+ /*We skipped all the packets on this page.
+ Fetch another.*/
+ ret=op_fetch_and_process_page(_of,NULL,-1,1,0,1);
+ if(OP_UNLIKELY(ret<=0))return OP_EBADLINK;
+ }
+ OP_ALWAYS_TRUE(!op_granpos_diff(&diff,prev_packet_gp,pcm_start));
+ /*We skipped too far.
+ Either the timestamps were illegal or there was a hole in the data.*/
+ if(diff>skip)return OP_EBADLINK;
+ OP_ASSERT(_pcm_offset-diff<OP_INT32_MAX);
+ /*TODO: If there are further holes/illegal timestamps, we still won't decode
+ to the correct sample.
+ However, at least op_pcm_tell() will report the correct value immediately
+ after returning.*/
+ _of->cur_discard_count=(opus_int32)(_pcm_offset-diff);
+ return 0;
+}
+
+opus_int64 op_raw_tell(const OggOpusFile *_of){
+ if(OP_UNLIKELY(_of->ready_state<OP_OPENED))return OP_EINVAL;
+ return _of->offset;
+}
+
+/*Convert a granule position from a given link to a PCM offset relative to the
+ start of the whole stream.
+ For unseekable sources, this gets reset to 0 at the beginning of each link.*/
+static ogg_int64_t op_get_pcm_offset(const OggOpusFile *_of,
+ ogg_int64_t _gp,int _li){
+ const OggOpusLink *links;
+ ogg_int64_t pcm_offset;
+ ogg_int64_t delta;
+ int li;
+ links=_of->links;
+ pcm_offset=0;
+ OP_ASSERT(_li<_of->nlinks);
+ for(li=0;li<_li;li++){
+ OP_ALWAYS_TRUE(!op_granpos_diff(&delta,
+ links[li].pcm_end,links[li].pcm_start));
+ delta-=links[li].head.pre_skip;
+ pcm_offset+=delta;
+ }
+ OP_ASSERT(_li>=0);
+ if(_of->seekable&&OP_UNLIKELY(op_granpos_cmp(_gp,links[_li].pcm_end)>0)){
+ _gp=links[_li].pcm_end;
+ }
+ if(OP_LIKELY(op_granpos_cmp(_gp,links[_li].pcm_start)>0)){
+ if(OP_UNLIKELY(op_granpos_diff(&delta,_gp,links[_li].pcm_start)<0)){
+ /*This means an unseekable stream claimed to have a page from more than
+ 2 billion days after we joined.*/
+ OP_ASSERT(!_of->seekable);
+ return OP_INT64_MAX;
+ }
+ if(delta<links[_li].head.pre_skip)delta=0;
+ else delta-=links[_li].head.pre_skip;
+ /*In the seekable case, _gp was limited by pcm_end.
+ In the unseekable case, pcm_offset should be 0.*/
+ OP_ASSERT(pcm_offset<=OP_INT64_MAX-delta);
+ pcm_offset+=delta;
+ }
+ return pcm_offset;
+}
+
+ogg_int64_t op_pcm_tell(const OggOpusFile *_of){
+ ogg_int64_t gp;
+ int nbuffered;
+ int li;
+ if(OP_UNLIKELY(_of->ready_state<OP_OPENED))return OP_EINVAL;
+ gp=_of->prev_packet_gp;
+ if(gp==-1)return 0;
+ nbuffered=OP_MAX(_of->od_buffer_size-_of->od_buffer_pos,0);
+ OP_ALWAYS_TRUE(!op_granpos_add(&gp,gp,-nbuffered));
+ li=_of->seekable?_of->cur_link:0;
+ if(op_granpos_add(&gp,gp,_of->cur_discard_count)<0){
+ gp=_of->links[li].pcm_end;
+ }
+ return op_get_pcm_offset(_of,gp,li);
+}
+
+void op_set_decode_callback(OggOpusFile *_of,
+ op_decode_cb_func _decode_cb,void *_ctx){
+ _of->decode_cb=_decode_cb;
+ _of->decode_cb_ctx=_ctx;
+}
+
+int op_set_gain_offset(OggOpusFile *_of,
+ int _gain_type,opus_int32 _gain_offset_q8){
+ if(_gain_type!=OP_HEADER_GAIN&&_gain_type!=OP_TRACK_GAIN
+ &&_gain_type!=OP_ABSOLUTE_GAIN){
+ return OP_EINVAL;
+ }
+ _of->gain_type=_gain_type;
+ /*The sum of header gain and track gain lies in the range [-65536,65534].
+ These bounds allow the offset to set the final value to anywhere in the
+ range [-32768,32767], which is what we'll clamp it to before applying.*/
+ _of->gain_offset_q8=OP_CLAMP(-98302,_gain_offset_q8,98303);
+ op_update_gain(_of);
+ return 0;
+}
+
+void op_set_dither_enabled(OggOpusFile *_of,int _enabled){
+#if !defined(OPUS_FIXED_POINT)
+ _of->dither_disabled=!_enabled;
+ if(!_enabled)_of->dither_mute=65;
+#endif
+}
+
+/*Allocate the decoder scratch buffer.
+ This is done lazily, since if the user provides large enough buffers, we'll
+ never need it.*/
+static int op_init_buffer(OggOpusFile *_of){
+ int nchannels_max;
+ if(_of->seekable){
+ const OggOpusLink *links;
+ int nlinks;
+ int li;
+ links=_of->links;
+ nlinks=_of->nlinks;
+ nchannels_max=1;
+ for(li=0;li<nlinks;li++){
+ nchannels_max=OP_MAX(nchannels_max,links[li].head.channel_count);
+ }
+ }
+ else nchannels_max=OP_NCHANNELS_MAX;
+ _of->od_buffer=(op_sample *)_ogg_malloc(
+ sizeof(*_of->od_buffer)*nchannels_max*120*48);
+ if(_of->od_buffer==NULL)return OP_EFAULT;
+ return 0;
+}
+
+/*Decode a single packet into the target buffer.*/
+static int op_decode(OggOpusFile *_of,op_sample *_pcm,
+ const ogg_packet *_op,int _nsamples,int _nchannels){
+ int ret;
+ /*First we try using the application-provided decode callback.*/
+ if(_of->decode_cb!=NULL){
+#if defined(OPUS_FIXED_POINT)
+ ret=(*_of->decode_cb)(_of->decode_cb_ctx,_of->od,_pcm,_op,
+ _nsamples,_nchannels,OP_DEC_FORMAT_SHORT,_of->cur_link);
+#else
+ ret=(*_of->decode_cb)(_of->decode_cb_ctx,_of->od,_pcm,_op,
+ _nsamples,_nchannels,OP_DEC_FORMAT_FLOAT,_of->cur_link);
+#endif
+ }
+ else ret=OP_DEC_USE_DEFAULT;
+ /*If the application didn't want to handle decoding, do it ourselves.*/
+ if(ret==OP_DEC_USE_DEFAULT){
+#if defined(OPUS_FIXED_POINT)
+ ret=opus_multistream_decode(_of->od,
+ _op->packet,_op->bytes,_pcm,_nsamples,0);
+#else
+ ret=opus_multistream_decode_float(_of->od,
+ _op->packet,_op->bytes,_pcm,_nsamples,0);
+#endif
+ OP_ASSERT(ret<0||ret==_nsamples);
+ }
+ /*If the application returned a positive value other than 0 or
+ OP_DEC_USE_DEFAULT, fail.*/
+ else if(OP_UNLIKELY(ret>0))return OP_EBADPACKET;
+ if(OP_UNLIKELY(ret<0))return OP_EBADPACKET;
+ return ret;
+}
+
+/*Read more samples from the stream, using the same API as op_read() or
+ op_read_float().*/
+static int op_read_native(OggOpusFile *_of,
+ op_sample *_pcm,int _buf_size,int *_li){
+ if(OP_UNLIKELY(_of->ready_state<OP_OPENED))return OP_EINVAL;
+ for(;;){
+ int ret;
+ if(OP_LIKELY(_of->ready_state>=OP_INITSET)){
+ int nchannels;
+ int od_buffer_pos;
+ int nsamples;
+ int op_pos;
+ nchannels=_of->links[_of->seekable?_of->cur_link:0].head.channel_count;
+ od_buffer_pos=_of->od_buffer_pos;
+ nsamples=_of->od_buffer_size-od_buffer_pos;
+ /*If we have buffered samples, return them.*/
+ if(nsamples>0){
+ if(nsamples*nchannels>_buf_size)nsamples=_buf_size/nchannels;
+ memcpy(_pcm,_of->od_buffer+nchannels*od_buffer_pos,
+ sizeof(*_pcm)*nchannels*nsamples);
+ od_buffer_pos+=nsamples;
+ _of->od_buffer_pos=od_buffer_pos;
+ if(_li!=NULL)*_li=_of->cur_link;
+ return nsamples;
+ }
+ /*If we have buffered packets, decode one.*/
+ op_pos=_of->op_pos;
+ if(OP_LIKELY(op_pos<_of->op_count)){
+ const ogg_packet *pop;
+ ogg_int64_t diff;
+ opus_int32 cur_discard_count;
+ int duration;
+ int trimmed_duration;
+ pop=_of->op+op_pos++;
+ _of->op_pos=op_pos;
+ cur_discard_count=_of->cur_discard_count;
+ duration=op_get_packet_duration(pop->packet,pop->bytes);
+ /*We don't buffer packets with an invalid TOC sequence.*/
+ OP_ASSERT(duration>0);
+ trimmed_duration=duration;
+ /*Perform end-trimming.*/
+ if(OP_UNLIKELY(pop->e_o_s)){
+ if(OP_UNLIKELY(op_granpos_cmp(pop->granulepos,
+ _of->prev_packet_gp)<=0)){
+ trimmed_duration=0;
+ }
+ else if(OP_LIKELY(!op_granpos_diff(&diff,
+ pop->granulepos,_of->prev_packet_gp))){
+ trimmed_duration=(int)OP_MIN(diff,trimmed_duration);
+ }
+ }
+ _of->prev_packet_gp=pop->granulepos;
+ if(OP_UNLIKELY(duration*nchannels>_buf_size)){
+ op_sample *buf;
+ /*If the user's buffer is too small, decode into a scratch buffer.*/
+ buf=_of->od_buffer;
+ if(OP_UNLIKELY(buf==NULL)){
+ ret=op_init_buffer(_of);
+ if(OP_UNLIKELY(ret<0))return ret;
+ buf=_of->od_buffer;
+ }
+ ret=op_decode(_of,buf,pop,duration,nchannels);
+ if(OP_UNLIKELY(ret<0))return ret;
+ /*Perform pre-skip/pre-roll.*/
+ od_buffer_pos=(int)OP_MIN(trimmed_duration,cur_discard_count);
+ cur_discard_count-=od_buffer_pos;
+ _of->cur_discard_count=cur_discard_count;
+ _of->od_buffer_pos=od_buffer_pos;
+ _of->od_buffer_size=trimmed_duration;
+ /*Update bitrate tracking based on the actual samples we used from
+ what was decoded.*/
+ _of->bytes_tracked+=pop->bytes;
+ _of->samples_tracked+=trimmed_duration-od_buffer_pos;
+ }
+ else{
+ /*Otherwise decode directly into the user's buffer.*/
+ ret=op_decode(_of,_pcm,pop,duration,nchannels);
+ if(OP_UNLIKELY(ret<0))return ret;
+ if(OP_LIKELY(trimmed_duration>0)){
+ /*Perform pre-skip/pre-roll.*/
+ od_buffer_pos=(int)OP_MIN(trimmed_duration,cur_discard_count);
+ cur_discard_count-=od_buffer_pos;
+ _of->cur_discard_count=cur_discard_count;
+ trimmed_duration-=od_buffer_pos;
+ if(OP_LIKELY(trimmed_duration>0)
+ &&OP_UNLIKELY(od_buffer_pos>0)){
+ memmove(_pcm,_pcm+od_buffer_pos*nchannels,
+ sizeof(*_pcm)*trimmed_duration*nchannels);
+ }
+ /*Update bitrate tracking based on the actual samples we used from
+ what was decoded.*/
+ _of->bytes_tracked+=pop->bytes;
+ _of->samples_tracked+=trimmed_duration;
+ if(OP_LIKELY(trimmed_duration>0)){
+ if(_li!=NULL)*_li=_of->cur_link;
+ return trimmed_duration;
+ }
+ }
+ }
+ /*Don't grab another page yet.
+ This one might have more packets, or might have buffered data now.*/
+ continue;
+ }
+ }
+ /*Suck in another page.*/
+ ret=op_fetch_and_process_page(_of,NULL,-1,1,1,0);
+ if(OP_UNLIKELY(ret==OP_EOF)){
+ if(_li!=NULL)*_li=_of->cur_link;
+ return 0;
+ }
+ if(OP_UNLIKELY(ret<0))return ret;
+ }
+}
+
+/*A generic filter to apply to the decoded audio data.
+ _src is non-const because we will destructively modify the contents of the
+ source buffer that we consume in some cases.*/
+typedef int (*op_read_filter_func)(OggOpusFile *_of,void *_dst,int _dst_sz,
+ op_sample *_src,int _nsamples,int _nchannels);
+
+/*Decode some samples and then apply a custom filter to them.
+ This is used to convert to different output formats.*/
+static int op_filter_read_native(OggOpusFile *_of,void *_dst,int _dst_sz,
+ op_read_filter_func _filter,int *_li){
+ int ret;
+ /*Ensure we have some decoded samples in our buffer.*/
+ ret=op_read_native(_of,NULL,0,_li);
+ /*Now apply the filter to them.*/
+ if(OP_LIKELY(ret>=0)&&OP_LIKELY(_of->ready_state>=OP_INITSET)){
+ int od_buffer_pos;
+ od_buffer_pos=_of->od_buffer_pos;
+ ret=_of->od_buffer_size-od_buffer_pos;
+ if(OP_LIKELY(ret>0)){
+ int nchannels;
+ nchannels=_of->links[_of->seekable?_of->cur_link:0].head.channel_count;
+ ret=(*_filter)(_of,_dst,_dst_sz,
+ _of->od_buffer+nchannels*od_buffer_pos,ret,nchannels);
+ OP_ASSERT(ret>=0);
+ OP_ASSERT(ret<=_of->od_buffer_size-od_buffer_pos);
+ od_buffer_pos+=ret;
+ _of->od_buffer_pos=od_buffer_pos;
+ }
+ }
+ return ret;
+}
+
+#if !defined(OPUS_FIXED_POINT)||!defined(OP_DISABLE_FLOAT_API)
+
+/*Matrices for downmixing from the supported channel counts to stereo.
+ The matrices with 5 or more channels are normalized to a total volume of 2.0,
+ since most mixes sound too quiet if normalized to 1.0 (as there is generally
+ little volume in the side/rear channels).*/
+static const float OP_STEREO_DOWNMIX[OP_NCHANNELS_MAX-2][OP_NCHANNELS_MAX][2]={
+ /*3.0*/
+ {
+ {0.5858F,0.0F},{0.4142F,0.4142F},{0.0F,0.5858F}
+ },
+ /*quadrophonic*/
+ {
+ {0.4226F,0.0F},{0.0F,0.4226F},{0.366F,0.2114F},{0.2114F,0.336F}
+ },
+ /*5.0*/
+ {
+ {0.651F,0.0F},{0.46F,0.46F},{0.0F,0.651F},{0.5636F,0.3254F},
+ {0.3254F,0.5636F}
+ },
+ /*5.1*/
+ {
+ {0.529F,0.0F},{0.3741F,0.3741F},{0.0F,0.529F},{0.4582F,0.2645F},
+ {0.2645F,0.4582F},{0.3741F,0.3741F}
+ },
+ /*6.1*/
+ {
+ {0.4553F,0.0F},{0.322F,0.322F},{0.0F,0.4553F},{0.3943F,0.2277F},
+ {0.2277F,0.3943F},{0.2788F,0.2788F},{0.322F,0.322F}
+ },
+ /*7.1*/
+ {
+ {0.3886F,0.0F},{0.2748F,0.2748F},{0.0F,0.3886F},{0.3366F,0.1943F},
+ {0.1943F,0.3366F},{0.3366F,0.1943F},{0.1943F,0.3366F},{0.2748F,0.2748F}
+ }
+};
+
+#endif
+
+#if defined(OPUS_FIXED_POINT)
+
+/*Matrices for downmixing from the supported channel counts to stereo.
+ The matrices with 5 or more channels are normalized to a total volume of 2.0,
+ since most mixes sound too quiet if normalized to 1.0 (as there is generally
+ little volume in the side/rear channels).
+ Hence we keep the coefficients in Q14, so the downmix values won't overflow a
+ 32-bit number.*/
+static const opus_int16 OP_STEREO_DOWNMIX_Q14
+ [OP_NCHANNELS_MAX-2][OP_NCHANNELS_MAX][2]={
+ /*3.0*/
+ {
+ {9598,0},{6786,6786},{0,9598}
+ },
+ /*quadrophonic*/
+ {
+ {6924,0},{0,6924},{5996,3464},{3464,5996}
+ },
+ /*5.0*/
+ {
+ {10666,0},{7537,7537},{0,10666},{9234,5331},{5331,9234}
+ },
+ /*5.1*/
+ {
+ {8668,0},{6129,6129},{0,8668},{7507,4335},{4335,7507},{6129,6129}
+ },
+ /*6.1*/
+ {
+ {7459,0},{5275,5275},{0,7459},{6460,3731},{3731,6460},{4568,4568},
+ {5275,5275}
+ },
+ /*7.1*/
+ {
+ {6368,0},{4502,4502},{0,6368},{5515,3183},{3183,5515},{5515,3183},
+ {3183,5515},{4502,4502}
+ }
+};
+
+int op_read(OggOpusFile *_of,opus_int16 *_pcm,int _buf_size,int *_li){
+ return op_read_native(_of,_pcm,_buf_size,_li);
+}
+
+static int op_stereo_filter(OggOpusFile *_of,void *_dst,int _dst_sz,
+ op_sample *_src,int _nsamples,int _nchannels){
+ (void)_of;
+ _nsamples=OP_MIN(_nsamples,_dst_sz>>1);
+ if(_nchannels==2)memcpy(_dst,_src,_nsamples*2*sizeof(*_src));
+ else{
+ opus_int16 *dst;
+ int i;
+ dst=(opus_int16 *)_dst;
+ if(_nchannels==1){
+ for(i=0;i<_nsamples;i++)dst[2*i+0]=dst[2*i+1]=_src[i];
+ }
+ else{
+ for(i=0;i<_nsamples;i++){
+ opus_int32 l;
+ opus_int32 r;
+ int ci;
+ l=r=0;
+ for(ci=0;ci<_nchannels;ci++){
+ opus_int32 s;
+ s=_src[_nchannels*i+ci];
+ l+=OP_STEREO_DOWNMIX_Q14[_nchannels-3][ci][0]*s;
+ r+=OP_STEREO_DOWNMIX_Q14[_nchannels-3][ci][1]*s;
+ }
+ /*TODO: For 5 or more channels, we should do soft clipping here.*/
+ dst[2*i+0]=(opus_int16)OP_CLAMP(-32768,l+8192>>14,32767);
+ dst[2*i+1]=(opus_int16)OP_CLAMP(-32768,r+8192>>14,32767);
+ }
+ }
+ }
+ return _nsamples;
+}
+
+int op_read_stereo(OggOpusFile *_of,opus_int16 *_pcm,int _buf_size){
+ return op_filter_read_native(_of,_pcm,_buf_size,op_stereo_filter,NULL);
+}
+
+# if !defined(OP_DISABLE_FLOAT_API)
+
+static int op_short2float_filter(OggOpusFile *_of,void *_dst,int _dst_sz,
+ op_sample *_src,int _nsamples,int _nchannels){
+ float *dst;
+ int i;
+ (void)_of;
+ dst=(float *)_dst;
+ if(OP_UNLIKELY(_nsamples*_nchannels>_dst_sz))_nsamples=_dst_sz/_nchannels;
+ _dst_sz=_nsamples*_nchannels;
+ for(i=0;i<_dst_sz;i++)dst[i]=(1.0F/32768)*_src[i];
+ return _nsamples;
+}
+
+int op_read_float(OggOpusFile *_of,float *_pcm,int _buf_size,int *_li){
+ return op_filter_read_native(_of,_pcm,_buf_size,op_short2float_filter,_li);
+}
+
+static int op_short2float_stereo_filter(OggOpusFile *_of,
+ void *_dst,int _dst_sz,op_sample *_src,int _nsamples,int _nchannels){
+ float *dst;
+ int i;
+ dst=(float *)_dst;
+ _nsamples=OP_MIN(_nsamples,_dst_sz>>1);
+ if(_nchannels==1){
+ _nsamples=op_short2float_filter(_of,dst,_nsamples,_src,_nsamples,1);
+ for(i=_nsamples;i-->0;)dst[2*i+0]=dst[2*i+1]=dst[i];
+ }
+ else if(_nchannels<5){
+ /*For 3 or 4 channels, we can downmix in fixed point without risk of
+ clipping.*/
+ if(_nchannels>2){
+ _nsamples=op_stereo_filter(_of,_src,_nsamples*2,
+ _src,_nsamples,_nchannels);
+ }
+ return op_short2float_filter(_of,dst,_dst_sz,_src,_nsamples,2);
+ }
+ else{
+ /*For 5 or more channels, we convert to floats and then downmix (so that we
+ don't risk clipping).*/
+ for(i=0;i<_nsamples;i++){
+ float l;
+ float r;
+ int ci;
+ l=r=0;
+ for(ci=0;ci<_nchannels;ci++){
+ float s;
+ s=(1.0F/32768)*_src[_nchannels*i+ci];
+ l+=OP_STEREO_DOWNMIX[_nchannels-3][ci][0]*s;
+ r+=OP_STEREO_DOWNMIX[_nchannels-3][ci][1]*s;
+ }
+ dst[2*i+0]=l;
+ dst[2*i+1]=r;
+ }
+ }
+ return _nsamples;
+}
+
+int op_read_float_stereo(OggOpusFile *_of,float *_pcm,int _buf_size){
+ return op_filter_read_native(_of,_pcm,_buf_size,
+ op_short2float_stereo_filter,NULL);
+}
+
+# endif
+
+#else
+
+# if defined(OP_HAVE_LRINTF)
+# include <math.h>
+# define op_float2int(_x) (lrintf(_x))
+# else
+# define op_float2int(_x) ((int)((_x)+((_x)<0?-0.5F:0.5F)))
+# endif
+
+/*The dithering code here is adapted from opusdec, part of opus-tools.
+ It was originally written by Greg Maxwell.*/
+
+static opus_uint32 op_rand(opus_uint32 _seed){
+ return _seed*96314165+907633515&0xFFFFFFFFU;
+}
+
+/*This implements 16-bit quantization with full triangular dither and IIR noise
+ shaping.
+ The noise shaping filters were designed by Sebastian Gesemann, and are based
+ on the LAME ATH curves with flattening to limit their peak gain to 20 dB.
+ Everyone else's noise shaping filters are mildly crazy.
+ The 48 kHz version of this filter is just a warped version of the 44.1 kHz
+ filter and probably could be improved by shifting the HF shelf up in
+ frequency a little bit, since 48 kHz has a bit more room and being more
+ conservative against bat-ears is probably more important than more noise
+ suppression.
+ This process can increase the peak level of the signal (in theory by the peak
+ error of 1.5 +20 dB, though that is unobservably rare).
+ To avoid clipping, the signal is attenuated by a couple thousandths of a dB.
+ Initially, the approach taken here was to only attenuate by the 99.9th
+ percentile, making clipping rare but not impossible (like SoX), but the
+ limited gain of the filter means that the worst case was only two
+ thousandths of a dB more, so this just uses the worst case.
+ The attenuation is probably also helpful to prevent clipping in the DAC
+ reconstruction filters or downstream resampling, in any case.*/
+
+# define OP_GAIN (32753.0F)
+
+# define OP_PRNG_GAIN (1.0F/0xFFFFFFFF)
+
+/*48 kHz noise shaping filter, sd=2.34.*/
+
+static const float OP_FCOEF_B[4]={
+ 2.2374F,-0.7339F,-0.1251F,-0.6033F
+};
+
+static const float OP_FCOEF_A[4]={
+ 0.9030F,0.0116F,-0.5853F,-0.2571F
+};
+
+static int op_float2short_filter(OggOpusFile *_of,void *_dst,int _dst_sz,
+ float *_src,int _nsamples,int _nchannels){
+ opus_int16 *dst;
+ int ci;
+ int i;
+ dst=(opus_int16 *)_dst;
+ if(OP_UNLIKELY(_nsamples*_nchannels>_dst_sz))_nsamples=_dst_sz/_nchannels;
+# if defined(OP_SOFT_CLIP)
+ if(_of->state_channel_count!=_nchannels){
+ for(ci=0;ci<_nchannels;ci++)_of->clip_state[ci]=0;
+ }
+ opus_pcm_soft_clip(_src,_nsamples,_nchannels,_of->clip_state);
+# endif
+ if(_of->dither_disabled){
+ for(i=0;i<_nchannels*_nsamples;i++){
+ dst[i]=op_float2int(OP_CLAMP(-32768,32768.0F*_src[i],32767));
+ }
+ }
+ else{
+ opus_uint32 seed;
+ int mute;
+ seed=_of->dither_seed;
+ mute=_of->dither_mute;
+ if(_of->state_channel_count!=_nchannels)mute=65;
+ /*In order to avoid replacing digital silence with quiet dither noise, we
+ mute if the output has been silent for a while.*/
+ if(mute>64)memset(_of->dither_a,0,sizeof(*_of->dither_a)*4*_nchannels);
+ for(i=0;i<_nsamples;i++){
+ int silent;
+ silent=1;
+ for(ci=0;ci<_nchannels;ci++){
+ float r;
+ float s;
+ float err;
+ int si;
+ int j;
+ s=_src[_nchannels*i+ci];
+ silent&=s==0;
+ s*=OP_GAIN;
+ err=0;
+ for(j=0;j<4;j++){
+ err+=OP_FCOEF_B[j]*_of->dither_b[ci*4+j]
+ -OP_FCOEF_A[j]*_of->dither_a[ci*4+j];
+ }
+ for(j=3;j-->0;)_of->dither_a[ci*4+j+1]=_of->dither_a[ci*4+j];
+ for(j=3;j-->0;)_of->dither_b[ci*4+j+1]=_of->dither_b[ci*4+j];
+ _of->dither_a[ci*4]=err;
+ s-=err;
+ if(mute>16)r=0;
+ else{
+ seed=op_rand(seed);
+ r=seed*OP_PRNG_GAIN;
+ seed=op_rand(seed);
+ r-=seed*OP_PRNG_GAIN;
+ }
+ /*Clamp in float out of paranoia that the input will be > 96 dBFS and
+ wrap if the integer is clamped.*/
+ si=op_float2int(OP_CLAMP(-32768,s+r,32767));
+ dst[_nchannels*i+ci]=(opus_int16)si;
+ /*Including clipping in the noise shaping is generally disastrous: the
+ futile effort to restore the clipped energy results in more clipping.
+ However, small amounts---at the level which could normally be created
+ by dither and rounding---are harmless and can even reduce clipping
+ somewhat due to the clipping sometimes reducing the dither + rounding
+ error.*/
+ _of->dither_b[ci*4]=mute>16?0:OP_CLAMP(-1.5F,si-s,1.5F);
+ }
+ mute++;
+ if(!silent)mute=0;
+ }
+ _of->dither_mute=OP_MIN(mute,65);
+ _of->dither_seed=seed;
+ }
+ _of->state_channel_count=_nchannels;
+ return _nsamples;
+}
+
+int op_read(OggOpusFile *_of,opus_int16 *_pcm,int _buf_size,int *_li){
+ return op_filter_read_native(_of,_pcm,_buf_size,op_float2short_filter,_li);
+}
+
+int op_read_float(OggOpusFile *_of,float *_pcm,int _buf_size,int *_li){
+ _of->state_channel_count=0;
+ return op_read_native(_of,_pcm,_buf_size,_li);
+}
+
+static int op_stereo_filter(OggOpusFile *_of,void *_dst,int _dst_sz,
+ op_sample *_src,int _nsamples,int _nchannels){
+ (void)_of;
+ _nsamples=OP_MIN(_nsamples,_dst_sz>>1);
+ if(_nchannels==2)memcpy(_dst,_src,_nsamples*2*sizeof(*_src));
+ else{
+ float *dst;
+ int i;
+ dst=(float *)_dst;
+ if(_nchannels==1){
+ for(i=0;i<_nsamples;i++)dst[2*i+0]=dst[2*i+1]=_src[i];
+ }
+ else{
+ for(i=0;i<_nsamples;i++){
+ float l;
+ float r;
+ int ci;
+ l=r=0;
+ for(ci=0;ci<_nchannels;ci++){
+ l+=OP_STEREO_DOWNMIX[_nchannels-3][ci][0]*_src[_nchannels*i+ci];
+ r+=OP_STEREO_DOWNMIX[_nchannels-3][ci][1]*_src[_nchannels*i+ci];
+ }
+ dst[2*i+0]=l;
+ dst[2*i+1]=r;
+ }
+ }
+ }
+ return _nsamples;
+}
+
+static int op_float2short_stereo_filter(OggOpusFile *_of,
+ void *_dst,int _dst_sz,op_sample *_src,int _nsamples,int _nchannels){
+ opus_int16 *dst;
+ dst=(opus_int16 *)_dst;
+ if(_nchannels==1){
+ int i;
+ _nsamples=op_float2short_filter(_of,dst,_dst_sz>>1,_src,_nsamples,1);
+ for(i=_nsamples;i-->0;)dst[2*i+0]=dst[2*i+1]=dst[i];
+ }
+ else{
+ if(_nchannels>2){
+ _nsamples=OP_MIN(_nsamples,_dst_sz>>1);
+ _nsamples=op_stereo_filter(_of,_src,_nsamples*2,
+ _src,_nsamples,_nchannels);
+ }
+ _nsamples=op_float2short_filter(_of,dst,_dst_sz,_src,_nsamples,2);
+ }
+ return _nsamples;
+}
+
+int op_read_stereo(OggOpusFile *_of,opus_int16 *_pcm,int _buf_size){
+ return op_filter_read_native(_of,_pcm,_buf_size,
+ op_float2short_stereo_filter,NULL);
+}
+
+int op_read_float_stereo(OggOpusFile *_of,float *_pcm,int _buf_size){
+ _of->state_channel_count=0;
+ return op_filter_read_native(_of,_pcm,_buf_size,op_stereo_filter,NULL);
+}
+
+#endif
diff --git a/drivers/opus/opusfile.h b/drivers/opus/opusfile.h
new file mode 100644
index 0000000000..91d06aa9ba
--- /dev/null
+++ b/drivers/opus/opusfile.h
@@ -0,0 +1,2102 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2012 *
+ * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: stdio-based convenience library for opening/seeking/decoding
+ last mod: $Id: vorbisfile.h 17182 2010-04-29 03:48:32Z xiphmont $
+
+ ********************************************************************/
+#if !defined(_opusfile_h)
+# define _opusfile_h (1)
+
+/**\mainpage
+ \section Introduction
+
+ This is the documentation for the <tt>libopusfile</tt> C API.
+
+ The <tt>libopusfile</tt> package provides a convenient high-level API for
+ decoding and basic manipulation of all Ogg Opus audio streams.
+ <tt>libopusfile</tt> is implemented as a layer on top of Xiph.Org's
+ reference
+ <tt><a href="https://www.xiph.org/ogg/doc/libogg/reference.html">libogg</a></tt>
+ and
+ <tt><a href="https://mf4.xiph.org/jenkins/view/opus/job/opus/ws/doc/html/index.html">libopus</a></tt>
+ libraries.
+
+ <tt>libopusfile</tt> provides several sets of built-in routines for
+ file/stream access, and may also use custom stream I/O routines provided by
+ the embedded environment.
+ There are built-in I/O routines provided for ANSI-compliant
+ <code>stdio</code> (<code>FILE *</code>), memory buffers, and URLs
+ (including <file:> URLs, plus optionally <http:> and <https:> URLs).
+
+ \section Organization
+
+ The main API is divided into several sections:
+ - \ref stream_open_close
+ - \ref stream_info
+ - \ref stream_decoding
+ - \ref stream_seeking
+
+ Several additional sections are not tied to the main API.
+ - \ref stream_callbacks
+ - \ref header_info
+ - \ref error_codes
+
+ \section Overview
+
+ The <tt>libopusfile</tt> API always decodes files to 48&nbsp;kHz.
+ The original sample rate is not preserved by the lossy compression, though
+ it is stored in the header to allow you to resample to it after decoding
+ (the <tt>libopusfile</tt> API does not currently provide a resampler,
+ but the
+ <a href="http://www.speex.org/docs/manual/speex-manual/node7.html#SECTION00760000000000000000">the
+ Speex resampler</a> is a good choice if you need one).
+ In general, if you are playing back the audio, you should leave it at
+ 48&nbsp;kHz, provided your audio hardware supports it.
+ When decoding to a file, it may be worth resampling back to the original
+ sample rate, so as not to surprise users who might not expect the sample
+ rate to change after encoding to Opus and decoding.
+
+ Opus files can contain anywhere from 1 to 255 channels of audio.
+ The channel mappings for up to 8 channels are the same as the
+ <a href="http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9">Vorbis
+ mappings</a>.
+ A special stereo API can convert everything to 2 channels, making it simple
+ to support multichannel files in an application which only has stereo
+ output.
+ Although the <tt>libopusfile</tt> ABI provides support for the theoretical
+ maximum number of channels, the current implementation does not support
+ files with more than 8 channels, as they do not have well-defined channel
+ mappings.
+
+ Like all Ogg files, Opus files may be "chained".
+ That is, multiple Opus files may be combined into a single, longer file just
+ by concatenating the original files.
+ This is commonly done in internet radio streaming, as it allows the title
+ and artist to be updated each time the song changes, since each link in the
+ chain includes its own set of metadata.
+
+ <tt>libopusfile</tt> fully supports chained files.
+ It will decode the first Opus stream found in each link of a chained file
+ (ignoring any other streams that might be concurrently multiplexed with it,
+ such as a video stream).
+
+ The channel count can also change between links.
+ If your application is not prepared to deal with this, it can use the stereo
+ API to ensure the audio from all links will always get decoded into a
+ common format.
+ Since <tt>libopusfile</tt> always decodes to 48&nbsp;kHz, you do not have to
+ worry about the sample rate changing between links (as was possible with
+ Vorbis).
+ This makes application support for chained files with <tt>libopusfile</tt>
+ very easy.*/
+
+# if defined(__cplusplus)
+extern "C" {
+# endif
+
+# include <stdarg.h>
+# include <stdio.h>
+# include <ogg/ogg.h>
+# include <opus/opus_multistream.h>
+
+/**@cond PRIVATE*/
+
+/*Enable special features for gcc and gcc-compatible compilers.*/
+# if !defined(OP_GNUC_PREREQ)
+# if defined(__GNUC__)&&defined(__GNUC_MINOR__)
+# define OP_GNUC_PREREQ(_maj,_min) \
+ ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min))
+# else
+# define OP_GNUC_PREREQ(_maj,_min) 0
+# endif
+# endif
+
+# if OP_GNUC_PREREQ(4,0)
+# pragma GCC visibility push(default)
+# endif
+
+typedef struct OpusHead OpusHead;
+typedef struct OpusTags OpusTags;
+typedef struct OpusPictureTag OpusPictureTag;
+typedef struct OpusServerInfo OpusServerInfo;
+typedef struct OpusFileCallbacks OpusFileCallbacks;
+typedef struct OggOpusFile OggOpusFile;
+
+/*Warning attributes for libopusfile functions.*/
+# if OP_GNUC_PREREQ(3,4)
+# define OP_WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
+# else
+# define OP_WARN_UNUSED_RESULT
+# endif
+# if OP_GNUC_PREREQ(3,4)
+# define OP_ARG_NONNULL(_x) __attribute__((__nonnull__(_x)))
+# else
+# define OP_ARG_NONNULL(_x)
+# endif
+
+/**@endcond*/
+
+/**\defgroup error_codes Error Codes*/
+/*@{*/
+/**\name List of possible error codes
+ Many of the functions in this library return a negative error code when a
+ function fails.
+ This list provides a brief explanation of the common errors.
+ See each individual function for more details on what a specific error code
+ means in that context.*/
+/*@{*/
+
+/**A request did not succeed.*/
+#define OP_FALSE (-1)
+/*Currently not used externally.*/
+#define OP_EOF (-2)
+/**There was a hole in the page sequence numbers (e.g., a page was corrupt or
+ missing).*/
+#define OP_HOLE (-3)
+/**An underlying read, seek, or tell operation failed when it should have
+ succeeded.*/
+#define OP_EREAD (-128)
+/**A <code>NULL</code> pointer was passed where one was unexpected, or an
+ internal memory allocation failed, or an internal library error was
+ encountered.*/
+#define OP_EFAULT (-129)
+/**The stream used a feature that is not implemented, such as an unsupported
+ channel family.*/
+#define OP_EIMPL (-130)
+/**One or more parameters to a function were invalid.*/
+#define OP_EINVAL (-131)
+/**A purported Ogg Opus stream did not begin with an Ogg page, a purported
+ header packet did not start with one of the required strings, "OpusHead" or
+ "OpusTags", or a link in a chained file was encountered that did not
+ contain any logical Opus streams.*/
+#define OP_ENOTFORMAT (-132)
+/**A required header packet was not properly formatted, contained illegal
+ values, or was missing altogether.*/
+#define OP_EBADHEADER (-133)
+/**The ID header contained an unrecognized version number.*/
+#define OP_EVERSION (-134)
+/*Currently not used at all.*/
+#define OP_ENOTAUDIO (-135)
+/**An audio packet failed to decode properly.
+ This is usually caused by a multistream Ogg packet where the durations of
+ the individual Opus packets contained in it are not all the same.*/
+#define OP_EBADPACKET (-136)
+/**We failed to find data we had seen before, or the bitstream structure was
+ sufficiently malformed that seeking to the target destination was
+ impossible.*/
+#define OP_EBADLINK (-137)
+/**An operation that requires seeking was requested on an unseekable stream.*/
+#define OP_ENOSEEK (-138)
+/**The first or last granule position of a link failed basic validity checks.*/
+#define OP_EBADTIMESTAMP (-139)
+
+/*@}*/
+/*@}*/
+
+/**\defgroup header_info Header Information*/
+/*@{*/
+
+/**The maximum number of channels in an Ogg Opus stream.*/
+#define OPUS_CHANNEL_COUNT_MAX (255)
+
+/**Ogg Opus bitstream information.
+ This contains the basic playback parameters for a stream, and corresponds to
+ the initial ID header packet of an Ogg Opus stream.*/
+struct OpusHead{
+ /**The Ogg Opus format version, in the range 0...255.
+ The top 4 bits represent a "major" version, and the bottom four bits
+ represent backwards-compatible "minor" revisions.
+ The current specification describes version 1.
+ This library will recognize versions up through 15 as backwards compatible
+ with the current specification.
+ An earlier draft of the specification described a version 0, but the only
+ difference between version 1 and version 0 is that version 0 did
+ not specify the semantics for handling the version field.*/
+ int version;
+ /**The number of channels, in the range 1...255.*/
+ int channel_count;
+ /**The number of samples that should be discarded from the beginning of the
+ stream.*/
+ unsigned pre_skip;
+ /**The sampling rate of the original input.
+ All Opus audio is coded at 48 kHz, and should also be decoded at 48 kHz
+ for playback (unless the target hardware does not support this sampling
+ rate).
+ However, this field may be used to resample the audio back to the original
+ sampling rate, for example, when saving the output to a file.*/
+ opus_uint32 input_sample_rate;
+ /**The gain to apply to the decoded output, in dB, as a Q8 value in the range
+ -32768...32767.
+ The <tt>libopusfile</tt> API will automatically apply this gain to the
+ decoded output before returning it, scaling it by
+ <code>pow(10,output_gain/(20.0*256))</code>.*/
+ int output_gain;
+ /**The channel mapping family, in the range 0...255.
+ Channel mapping family 0 covers mono or stereo in a single stream.
+ Channel mapping family 1 covers 1 to 8 channels in one or more streams,
+ using the Vorbis speaker assignments.
+ Channel mapping family 255 covers 1 to 255 channels in one or more
+ streams, but without any defined speaker assignment.*/
+ int mapping_family;
+ /**The number of Opus streams in each Ogg packet, in the range 1...255.*/
+ int stream_count;
+ /**The number of coupled Opus streams in each Ogg packet, in the range
+ 0...127.
+ This must satisfy <code>0 <= coupled_count <= stream_count</code> and
+ <code>coupled_count + stream_count <= 255</code>.
+ The coupled streams appear first, before all uncoupled streams, in an Ogg
+ Opus packet.*/
+ int coupled_count;
+ /**The mapping from coded stream channels to output channels.
+ Let <code>index=mapping[k]</code> be the value for channel <code>k</code>.
+ If <code>index<2*coupled_count</code>, then it refers to the left channel
+ from stream <code>(index/2)</code> if even, and the right channel from
+ stream <code>(index/2)</code> if odd.
+ Otherwise, it refers to the output of the uncoupled stream
+ <code>(index-coupled_count)</code>.*/
+ unsigned char mapping[OPUS_CHANNEL_COUNT_MAX];
+};
+
+/**The metadata from an Ogg Opus stream.
+
+ This structure holds the in-stream metadata corresponding to the 'comment'
+ header packet of an Ogg Opus stream.
+ The comment header is meant to be used much like someone jotting a quick
+ note on the label of a CD.
+ It should be a short, to the point text note that can be more than a couple
+ words, but not more than a short paragraph.
+
+ The metadata is stored as a series of (tag, value) pairs, in length-encoded
+ string vectors, using the same format as Vorbis (without the final "framing
+ bit"), Theora, and Speex, except for the packet header.
+ The first occurrence of the '=' character delimits the tag and value.
+ A particular tag may occur more than once, and order is significant.
+ The character set encoding for the strings is always UTF-8, but the tag
+ names are limited to ASCII, and treated as case-insensitive.
+ See <a href="http://www.xiph.org/vorbis/doc/v-comment.html">the Vorbis
+ comment header specification</a> for details.
+
+ In filling in this structure, <tt>libopusfile</tt> will null-terminate the
+ #user_comments strings for safety.
+ However, the bitstream format itself treats them as 8-bit clean vectors,
+ possibly containing NUL characters, so the #comment_lengths array should be
+ treated as their authoritative length.
+
+ This structure is binary and source-compatible with a
+ <code>vorbis_comment</code>, and pointers to it may be freely cast to
+ <code>vorbis_comment</code> pointers, and vice versa.
+ It is provided as a separate type to avoid introducing a compile-time
+ dependency on the libvorbis headers.*/
+struct OpusTags{
+ /**The array of comment string vectors.*/
+ char **user_comments;
+ /**An array of the corresponding length of each vector, in bytes.*/
+ int *comment_lengths;
+ /**The total number of comment streams.*/
+ int comments;
+ /**The null-terminated vendor string.
+ This identifies the software used to encode the stream.*/
+ char *vendor;
+};
+
+/**\name Picture tag image formats*/
+/*@{*/
+
+/**The MIME type was not recognized, or the image data did not match the
+ declared MIME type.*/
+#define OP_PIC_FORMAT_UNKNOWN (-1)
+/**The MIME type indicates the image data is really a URL.*/
+#define OP_PIC_FORMAT_URL (0)
+/**The image is a JPEG.*/
+#define OP_PIC_FORMAT_JPEG (1)
+/**The image is a PNG.*/
+#define OP_PIC_FORMAT_PNG (2)
+/**The image is a GIF.*/
+#define OP_PIC_FORMAT_GIF (3)
+
+/*@}*/
+
+/**The contents of a METADATA_BLOCK_PICTURE tag.*/
+struct OpusPictureTag{
+ /**The picture type according to the ID3v2 APIC frame:
+ <ol start="0">
+ <li>Other</li>
+ <li>32x32 pixels 'file icon' (PNG only)</li>
+ <li>Other file icon</li>
+ <li>Cover (front)</li>
+ <li>Cover (back)</li>
+ <li>Leaflet page</li>
+ <li>Media (e.g. label side of CD)</li>
+ <li>Lead artist/lead performer/soloist</li>
+ <li>Artist/performer</li>
+ <li>Conductor</li>
+ <li>Band/Orchestra</li>
+ <li>Composer</li>
+ <li>Lyricist/text writer</li>
+ <li>Recording Location</li>
+ <li>During recording</li>
+ <li>During performance</li>
+ <li>Movie/video screen capture</li>
+ <li>A bright colored fish</li>
+ <li>Illustration</li>
+ <li>Band/artist logotype</li>
+ <li>Publisher/Studio logotype</li>
+ </ol>
+ Others are reserved and should not be used.
+ There may only be one each of picture type 1 and 2 in a file.*/
+ opus_int32 type;
+ /**The MIME type of the picture, in printable ASCII characters 0x20-0x7E.
+ The MIME type may also be <code>"-->"</code> to signify that the data part
+ is a URL pointing to the picture instead of the picture data itself.
+ In this case, a terminating NUL is appended to the URL string in #data,
+ but #data_length is set to the length of the string excluding that
+ terminating NUL.*/
+ char *mime_type;
+ /**The description of the picture, in UTF-8.*/
+ char *description;
+ /**The width of the picture in pixels.*/
+ opus_uint32 width;
+ /**The height of the picture in pixels.*/
+ opus_uint32 height;
+ /**The color depth of the picture in bits-per-pixel (<em>not</em>
+ bits-per-channel).*/
+ opus_uint32 depth;
+ /**For indexed-color pictures (e.g., GIF), the number of colors used, or 0
+ for non-indexed pictures.*/
+ opus_uint32 colors;
+ /**The length of the picture data in bytes.*/
+ opus_uint32 data_length;
+ /**The binary picture data.*/
+ unsigned char *data;
+ /**The format of the picture data, if known.
+ One of
+ <ul>
+ <li>#OP_PIC_FORMAT_UNKNOWN,</li>
+ <li>#OP_PIC_FORMAT_URL,</li>
+ <li>#OP_PIC_FORMAT_JPEG,</li>
+ <li>#OP_PIC_FORMAT_PNG, or</li>
+ <li>#OP_PIC_FORMAT_GIF.</li>
+ </ul>*/
+ int format;
+};
+
+/**\name Functions for manipulating header data
+
+ These functions manipulate the #OpusHead and #OpusTags structures,
+ which describe the audio parameters and tag-value metadata, respectively.
+ These can be used to query the headers returned by <tt>libopusfile</tt>, or
+ to parse Opus headers from sources other than an Ogg Opus stream, provided
+ they use the same format.*/
+/*@{*/
+
+/**Parses the contents of the ID header packet of an Ogg Opus stream.
+ \param[out] _head Returns the contents of the parsed packet.
+ The contents of this structure are untouched on error.
+ This may be <code>NULL</code> to merely test the header
+ for validity.
+ \param[in] _data The contents of the ID header packet.
+ \param _len The number of bytes of data in the ID header packet.
+ \return 0 on success or a negative value on error.
+ \retval #OP_ENOTFORMAT If the data does not start with the "OpusHead"
+ string.
+ \retval #OP_EVERSION If the version field signaled a version this library
+ does not know how to parse.
+ \retval #OP_EIMPL If the channel mapping family was 255, which general
+ purpose players should not attempt to play.
+ \retval #OP_EBADHEADER If the contents of the packet otherwise violate the
+ Ogg Opus specification:
+ <ul>
+ <li>Insufficient data,</li>
+ <li>Too much data for the known minor versions,</li>
+ <li>An unrecognized channel mapping family,</li>
+ <li>Zero channels or too many channels,</li>
+ <li>Zero coded streams,</li>
+ <li>Too many coupled streams, or</li>
+ <li>An invalid channel mapping index.</li>
+ </ul>*/
+OP_WARN_UNUSED_RESULT int opus_head_parse(OpusHead *_head,
+ const unsigned char *_data,size_t _len) OP_ARG_NONNULL(2);
+
+/**Converts a granule position to a sample offset for a given Ogg Opus stream.
+ The sample offset is simply <code>_gp-_head->pre_skip</code>.
+ Granule position values smaller than OpusHead#pre_skip correspond to audio
+ that should never be played, and thus have no associated sample offset.
+ This function returns -1 for such values.
+ This function also correctly handles extremely large granule positions,
+ which may have wrapped around to a negative number when stored in a signed
+ ogg_int64_t value.
+ \param _head The #OpusHead information from the ID header of the stream.
+ \param _gp The granule position to convert.
+ \return The sample offset associated with the given granule position
+ (counting at a 48 kHz sampling rate), or the special value -1 on
+ error (i.e., the granule position was smaller than the pre-skip
+ amount).*/
+ogg_int64_t opus_granule_sample(const OpusHead *_head,ogg_int64_t _gp)
+ OP_ARG_NONNULL(1);
+
+/**Parses the contents of the 'comment' header packet of an Ogg Opus stream.
+ \param[out] _tags An uninitialized #OpusTags structure.
+ This returns the contents of the parsed packet.
+ The contents of this structure are untouched on error.
+ This may be <code>NULL</code> to merely test the header
+ for validity.
+ \param[in] _data The contents of the 'comment' header packet.
+ \param _len The number of bytes of data in the 'info' header packet.
+ \retval 0 Success.
+ \retval #OP_ENOTFORMAT If the data does not start with the "OpusTags"
+ string.
+ \retval #OP_EBADHEADER If the contents of the packet otherwise violate the
+ Ogg Opus specification.
+ \retval #OP_EFAULT If there wasn't enough memory to store the tags.*/
+OP_WARN_UNUSED_RESULT int opus_tags_parse(OpusTags *_tags,
+ const unsigned char *_data,size_t _len) OP_ARG_NONNULL(2);
+
+/**Performs a deep copy of an #OpusTags structure.
+ \param _dst The #OpusTags structure to copy into.
+ If this function fails, the contents of this structure remain
+ untouched.
+ \param _src The #OpusTags structure to copy from.
+ \retval 0 Success.
+ \retval #OP_EFAULT If there wasn't enough memory to copy the tags.*/
+int opus_tags_copy(OpusTags *_dst,const OpusTags *_src) OP_ARG_NONNULL(1);
+
+/**Initializes an #OpusTags structure.
+ This should be called on a freshly allocated #OpusTags structure before
+ attempting to use it.
+ \param _tags The #OpusTags structure to initialize.*/
+void opus_tags_init(OpusTags *_tags) OP_ARG_NONNULL(1);
+
+/**Add a (tag, value) pair to an initialized #OpusTags structure.
+ \note Neither opus_tags_add() nor opus_tags_add_comment() support values
+ containing embedded NULs, although the bitstream format does support them.
+ To add such tags, you will need to manipulate the #OpusTags structure
+ directly.
+ \param _tags The #OpusTags structure to add the (tag, value) pair to.
+ \param _tag A NUL-terminated, case-insensitive, ASCII string containing
+ the tag to add (without an '=' character).
+ \param _value A NUL-terminated UTF-8 containing the corresponding value.
+ \return 0 on success, or a negative value on failure.
+ \retval #OP_EFAULT An internal memory allocation failed.*/
+int opus_tags_add(OpusTags *_tags,const char *_tag,const char *_value)
+ OP_ARG_NONNULL(1) OP_ARG_NONNULL(2) OP_ARG_NONNULL(3);
+
+/**Add a comment to an initialized #OpusTags structure.
+ \note Neither opus_tags_add_comment() nor opus_tags_add() support comments
+ containing embedded NULs, although the bitstream format does support them.
+ To add such tags, you will need to manipulate the #OpusTags structure
+ directly.
+ \param _tags The #OpusTags structure to add the comment to.
+ \param _comment A NUL-terminated UTF-8 string containing the comment in
+ "TAG=value" form.
+ \return 0 on success, or a negative value on failure.
+ \retval #OP_EFAULT An internal memory allocation failed.*/
+int opus_tags_add_comment(OpusTags *_tags,const char *_comment)
+ OP_ARG_NONNULL(1) OP_ARG_NONNULL(2);
+
+/**Look up a comment value by its tag.
+ \param _tags An initialized #OpusTags structure.
+ \param _tag The tag to look up.
+ \param _count The instance of the tag.
+ The same tag can appear multiple times, each with a distinct
+ value, so an index is required to retrieve them all.
+ The order in which these values appear is significant and
+ should be preserved.
+ Use opus_tags_query_count() to get the legal range for the
+ \a _count parameter.
+ \return A pointer to the queried tag's value.
+ This points directly to data in the #OpusTags structure.
+ It should not be modified or freed by the application, and
+ modifications to the structure may invalidate the pointer.
+ \retval NULL If no matching tag is found.*/
+const char *opus_tags_query(const OpusTags *_tags,const char *_tag,int _count)
+ OP_ARG_NONNULL(1) OP_ARG_NONNULL(2);
+
+/**Look up the number of instances of a tag.
+ Call this first when querying for a specific tag and then iterate over the
+ number of instances with separate calls to opus_tags_query() to retrieve
+ all the values for that tag in order.
+ \param _tags An initialized #OpusTags structure.
+ \param _tag The tag to look up.
+ \return The number of instances of this particular tag.*/
+int opus_tags_query_count(const OpusTags *_tags,const char *_tag)
+ OP_ARG_NONNULL(1) OP_ARG_NONNULL(2);
+
+/**Get the track gain from an R128_TRACK_GAIN tag, if one was specified.
+ This searches for the first R128_TRACK_GAIN tag with a valid signed,
+ 16-bit decimal integer value and returns the value.
+ This routine is exposed merely for convenience for applications which wish
+ to do something special with the track gain (i.e., display it).
+ If you simply wish to apply the track gain instead of the header gain, you
+ can use op_set_gain_offset() with an #OP_TRACK_GAIN type and no offset.
+ \param _tags An initialized #OpusTags structure.
+ \param[out] _gain_q8 The track gain, in 1/256ths of a dB.
+ This will lie in the range [-32768,32767], and should
+ be applied in <em>addition</em> to the header gain.
+ On error, no value is returned, and the previous
+ contents remain unchanged.
+ \return 0 on success, or a negative value on error.
+ \retval #OP_FALSE There was no track gain available in the given tags.*/
+int opus_tags_get_track_gain(const OpusTags *_tags,int *_gain_q8)
+ OP_ARG_NONNULL(1) OP_ARG_NONNULL(2);
+
+/**Clears the #OpusTags structure.
+ This should be called on an #OpusTags structure after it is no longer
+ needed.
+ It will free all memory used by the structure members.
+ \param _tags The #OpusTags structure to clear.*/
+void opus_tags_clear(OpusTags *_tags) OP_ARG_NONNULL(1);
+
+/**Check if \a _comment is an instance of a \a _tag_name tag.
+ \see opus_tagncompare
+ \param _tag_name A NUL-terminated, case-insensitive, ASCII string containing
+ the name of the tag to check for (without the terminating
+ '=' character).
+ \param _comment The comment string to check.
+ \return An integer less than, equal to, or greater than zero if \a _comment
+ is found respectively, to be less than, to match, or be greater
+ than a "tag=value" string whose tag matches \a _tag_name.*/
+int opus_tagcompare(const char *_tag_name,const char *_comment);
+
+/**Check if \a _comment is an instance of a \a _tag_name tag.
+ This version is slightly more efficient than opus_tagcompare() if the length
+ of the tag name is already known (e.g., because it is a constant).
+ \see opus_tagcompare
+ \param _tag_name A case-insensitive ASCII string containing the name of the
+ tag to check for (without the terminating '=' character).
+ \param _tag_len The number of characters in the tag name.
+ This must be non-negative.
+ \param _comment The comment string to check.
+ \return An integer less than, equal to, or greater than zero if \a _comment
+ is found respectively, to be less than, to match, or be greater
+ than a "tag=value" string whose tag matches the first \a _tag_len
+ characters of \a _tag_name.*/
+int opus_tagncompare(const char *_tag_name,int _tag_len,const char *_comment);
+
+/**Parse a single METADATA_BLOCK_PICTURE tag.
+ This decodes the BASE64-encoded content of the tag and returns a structure
+ with the MIME type, description, image parameters (if known), and the
+ compressed image data.
+ If the MIME type indicates the presence of an image format we recognize
+ (JPEG, PNG, or GIF) and the actual image data contains the magic signature
+ associated with that format, then the OpusPictureTag::format field will be
+ set to the corresponding format.
+ This is provided as a convenience to avoid requiring applications to parse
+ the MIME type and/or do their own format detection for the commonly used
+ formats.
+ In this case, we also attempt to extract the image parameters directly from
+ the image data (overriding any that were present in the tag, which the
+ specification says applications are not meant to rely on).
+ The application must still provide its own support for actually decoding the
+ image data and, if applicable, retrieving that data from URLs.
+ \param[out] _pic Returns the parsed picture data.
+ No sanitation is done on the type, MIME type, or
+ description fields, so these might return invalid values.
+ The contents of this structure are left unmodified on
+ failure.
+ \param _tag The METADATA_BLOCK_PICTURE tag contents.
+ The leading "METADATA_BLOCK_PICTURE=" portion is optional,
+ to allow the function to be used on either directly on the
+ values in OpusTags::user_comments or on the return value
+ of opus_tags_query().
+ \return 0 on success or a negative value on error.
+ \retval #OP_ENOTFORMAT The METADATA_BLOCK_PICTURE contents were not valid.
+ \retval #OP_EFAULT There was not enough memory to store the picture tag
+ contents.*/
+OP_WARN_UNUSED_RESULT int opus_picture_tag_parse(OpusPictureTag *_pic,
+ const char *_tag) OP_ARG_NONNULL(1) OP_ARG_NONNULL(2);
+
+/**Initializes an #OpusPictureTag structure.
+ This should be called on a freshly allocated #OpusPictureTag structure
+ before attempting to use it.
+ \param _pic The #OpusPictureTag structure to initialize.*/
+void opus_picture_tag_init(OpusPictureTag *_pic) OP_ARG_NONNULL(1);
+
+/**Clears the #OpusPictureTag structure.
+ This should be called on an #OpusPictureTag structure after it is no longer
+ needed.
+ It will free all memory used by the structure members.
+ \param _pic The #OpusPictureTag structure to clear.*/
+void opus_picture_tag_clear(OpusPictureTag *_pic) OP_ARG_NONNULL(1);
+
+/*@}*/
+
+/*@}*/
+
+/**\defgroup url_options URL Reading Options*/
+/*@{*/
+/**\name URL reading options
+ Options for op_url_stream_create() and associated functions.
+ These allow you to provide proxy configuration parameters, skip SSL
+ certificate checks, etc.
+ Options are processed in order, and if the same option is passed multiple
+ times, only the value specified by the last occurrence has an effect
+ (unless otherwise specified).
+ They may be expanded in the future.*/
+/*@{*/
+
+/**@cond PRIVATE*/
+
+/*These are the raw numbers used to define the request codes.
+ They should not be used directly.*/
+#define OP_SSL_SKIP_CERTIFICATE_CHECK_REQUEST (6464)
+#define OP_HTTP_PROXY_HOST_REQUEST (6528)
+#define OP_HTTP_PROXY_PORT_REQUEST (6592)
+#define OP_HTTP_PROXY_USER_REQUEST (6656)
+#define OP_HTTP_PROXY_PASS_REQUEST (6720)
+#define OP_GET_SERVER_INFO_REQUEST (6784)
+
+#define OP_URL_OPT(_request) ((_request)+(char *)0)
+
+/*These macros trigger compilation errors or warnings if the wrong types are
+ provided to one of the URL options.*/
+#define OP_CHECK_INT(_x) ((void)((_x)==(opus_int32)0),(opus_int32)(_x))
+#define OP_CHECK_CONST_CHAR_PTR(_x) ((_x)+((_x)-(const char *)(_x)))
+#define OP_CHECK_SERVER_INFO_PTR(_x) ((_x)+((_x)-(OpusServerInfo *)(_x)))
+
+/**@endcond*/
+
+/**HTTP/Shoutcast/Icecast server information associated with a URL.*/
+struct OpusServerInfo{
+ /**The name of the server (icy-name/ice-name).
+ This is <code>NULL</code> if there was no <code>icy-name</code> or
+ <code>ice-name</code> header.*/
+ char *name;
+ /**A short description of the server (icy-description/ice-description).
+ This is <code>NULL</code> if there was no <code>icy-description</code> or
+ <code>ice-description</code> header.*/
+ char *description;
+ /**The genre the server falls under (icy-genre/ice-genre).
+ This is <code>NULL</code> if there was no <code>icy-genre</code> or
+ <code>ice-genre</code> header.*/
+ char *genre;
+ /**The homepage for the server (icy-url/ice-url).
+ This is <code>NULL</code> if there was no <code>icy-url</code> or
+ <code>ice-url</code> header.*/
+ char *url;
+ /**The software used by the origin server (Server).
+ This is <code>NULL</code> if there was no <code>Server</code> header.*/
+ char *server;
+ /**The media type of the entity sent to the recepient (Content-Type).
+ This is <code>NULL</code> if there was no <code>Content-Type</code>
+ header.*/
+ char *content_type;
+ /**The nominal stream bitrate in kbps (icy-br/ice-bitrate).
+ This is <code>-1</code> if there was no <code>icy-br</code> or
+ <code>ice-bitrate</code> header.*/
+ opus_int32 bitrate_kbps;
+ /**Flag indicating whether the server is public (<code>1</code>) or not
+ (<code>0</code>) (icy-pub/ice-public).
+ This is <code>-1</code> if there was no <code>icy-pub</code> or
+ <code>ice-public</code> header.*/
+ int is_public;
+ /**Flag indicating whether the server is using HTTPS instead of HTTP.
+ This is <code>0</code> unless HTTPS is being used.
+ This may not match the protocol used in the original URL if there were
+ redirections.*/
+ int is_ssl;
+};
+
+/**Initializes an #OpusServerInfo structure.
+ All fields are set as if the corresponding header was not available.
+ \param _info The #OpusServerInfo structure to initialize.
+ \note If you use this function, you must link against <tt>libopusurl</tt>.*/
+void opus_server_info_init(OpusServerInfo *_info) OP_ARG_NONNULL(1);
+
+/**Clears the #OpusServerInfo structure.
+ This should be called on an #OpusServerInfo structure after it is no longer
+ needed.
+ It will free all memory used by the structure members.
+ \param _info The #OpusServerInfo structure to clear.
+ \note If you use this function, you must link against <tt>libopusurl</tt>.*/
+void opus_server_info_clear(OpusServerInfo *_info) OP_ARG_NONNULL(1);
+
+/**Skip the certificate check when connecting via TLS/SSL (https).
+ \param _b <code>opus_int32</code>: Whether or not to skip the certificate
+ check.
+ The check will be skipped if \a _b is non-zero, and will not be
+ skipped if \a _b is zero.
+ \hideinitializer*/
+#define OP_SSL_SKIP_CERTIFICATE_CHECK(_b) \
+ OP_URL_OPT(OP_SSL_SKIP_CERTIFICATE_CHECK_REQUEST),OP_CHECK_INT(_b)
+
+/**Proxy connections through the given host.
+ If no port is specified via #OP_HTTP_PROXY_PORT, the port number defaults
+ to 8080 (http-alt).
+ All proxy parameters are ignored for non-http and non-https URLs.
+ \param _host <code>const char *</code>: The proxy server hostname.
+ This may be <code>NULL</code> to disable the use of a proxy
+ server.
+ \hideinitializer*/
+#define OP_HTTP_PROXY_HOST(_host) \
+ OP_URL_OPT(OP_HTTP_PROXY_HOST_REQUEST),OP_CHECK_CONST_CHAR_PTR(_host)
+
+/**Use the given port when proxying connections.
+ This option only has an effect if #OP_HTTP_PROXY_HOST is specified with a
+ non-<code>NULL</code> \a _host.
+ If this option is not provided, the proxy port number defaults to 8080
+ (http-alt).
+ All proxy parameters are ignored for non-http and non-https URLs.
+ \param _port <code>opus_int32</code>: The proxy server port.
+ This must be in the range 0...65535 (inclusive), or the
+ URL function this is passed to will fail.
+ \hideinitializer*/
+#define OP_HTTP_PROXY_PORT(_port) \
+ OP_URL_OPT(OP_HTTP_PROXY_PORT_REQUEST),OP_CHECK_INT(_port)
+
+/**Use the given user name for authentication when proxying connections.
+ All proxy parameters are ignored for non-http and non-https URLs.
+ \param _user const char *: The proxy server user name.
+ This may be <code>NULL</code> to disable proxy
+ authentication.
+ A non-<code>NULL</code> value only has an effect
+ if #OP_HTTP_PROXY_HOST and #OP_HTTP_PROXY_PASS
+ are also specified with non-<code>NULL</code>
+ arguments.
+ \hideinitializer*/
+#define OP_HTTP_PROXY_USER(_user) \
+ OP_URL_OPT(OP_HTTP_PROXY_USER_REQUEST),OP_CHECK_CONST_CHAR_PTR(_user)
+
+/**Use the given password for authentication when proxying connections.
+ All proxy parameters are ignored for non-http and non-https URLs.
+ \param _pass const char *: The proxy server password.
+ This may be <code>NULL</code> to disable proxy
+ authentication.
+ A non-<code>NULL</code> value only has an effect
+ if #OP_HTTP_PROXY_HOST and #OP_HTTP_PROXY_USER
+ are also specified with non-<code>NULL</code>
+ arguments.
+ \hideinitializer*/
+#define OP_HTTP_PROXY_PASS(_pass) \
+ OP_URL_OPT(OP_HTTP_PROXY_PASS_REQUEST),OP_CHECK_CONST_CHAR_PTR(_pass)
+
+/**Parse information about the streaming server (if any) and return it.
+ Very little validation is done.
+ In particular, OpusServerInfo::url may not be a valid URL,
+ OpusServerInfo::bitrate_kbps may not really be in kbps, and
+ OpusServerInfo::content_type may not be a valid MIME type.
+ The character set of the string fields is not specified anywhere, and should
+ not be assumed to be valid UTF-8.
+ \param _info OpusServerInfo *: Returns information about the server.
+ If there is any error opening the stream, the
+ contents of this structure remain
+ unmodified.
+ On success, fills in the structure with the
+ server information that was available, if
+ any.
+ After a successful return, the contents of
+ this structure should be freed by calling
+ opus_server_info_clear().
+ \hideinitializer*/
+#define OP_GET_SERVER_INFO(_info) \
+ OP_URL_OPT(OP_GET_SERVER_INFO_REQUEST),OP_CHECK_SERVER_INFO_PTR(_info)
+
+/*@}*/
+/*@}*/
+
+/**\defgroup stream_callbacks Abstract Stream Reading Interface*/
+/*@{*/
+/**\name Functions for reading from streams
+ These functions define the interface used to read from and seek in a stream
+ of data.
+ A stream does not need to implement seeking, but the decoder will not be
+ able to seek if it does not do so.
+ These functions also include some convenience routines for working with
+ standard <code>FILE</code> pointers, complete streams stored in a single
+ block of memory, or URLs.*/
+/*@{*/
+
+/**Reads up to \a _nbytes bytes of data from \a _stream.
+ \param _stream The stream to read from.
+ \param[out] _ptr The buffer to store the data in.
+ \param _nbytes The maximum number of bytes to read.
+ This function may return fewer, though it will not
+ return zero unless it reaches end-of-file.
+ \return The number of bytes successfully read, or a negative value on
+ error.*/
+typedef int (*op_read_func)(void *_stream,unsigned char *_ptr,int _nbytes);
+
+/**Sets the position indicator for \a _stream.
+ The new position, measured in bytes, is obtained by adding \a _offset
+ bytes to the position specified by \a _whence.
+ If \a _whence is set to <code>SEEK_SET</code>, <code>SEEK_CUR</code>, or
+ <code>SEEK_END</code>, the offset is relative to the start of the stream,
+ the current position indicator, or end-of-file, respectively.
+ \retval 0 Success.
+ \retval -1 Seeking is not supported or an error occurred.
+ <code>errno</code> need not be set.*/
+typedef int (*op_seek_func)(void *_stream,opus_int64 _offset,int _whence);
+
+/**Obtains the current value of the position indicator for \a _stream.
+ \return The current position indicator.*/
+typedef opus_int64 (*op_tell_func)(void *_stream);
+
+/**Closes the underlying stream.
+ \retval 0 Success.
+ \retval EOF An error occurred.
+ <code>errno</code> need not be set.*/
+typedef int (*op_close_func)(void *_stream);
+
+/**The callbacks used to access non-<code>FILE</code> stream resources.
+ The function prototypes are basically the same as for the stdio functions
+ <code>fread()</code>, <code>fseek()</code>, <code>ftell()</code>, and
+ <code>fclose()</code>.
+ The differences are that the <code>FILE *</code> arguments have been
+ replaced with a <code>void *</code>, which is to be used as a pointer to
+ whatever internal data these functions might need, that #seek and #tell
+ take and return 64-bit offsets, and that #seek <em>must</em> return -1 if
+ the stream is unseekable.*/
+struct OpusFileCallbacks{
+ /**Used to read data from the stream.
+ This must not be <code>NULL</code>.*/
+ op_read_func read;
+ /**Used to seek in the stream.
+ This may be <code>NULL</code> if seeking is not implemented.*/
+ op_seek_func seek;
+ /**Used to return the current read position in the stream.
+ This may be <code>NULL</code> if seeking is not implemented.*/
+ op_tell_func tell;
+ /**Used to close the stream when the decoder is freed.
+ This may be <code>NULL</code> to leave the stream open.*/
+ op_close_func close;
+};
+
+/**Opens a stream with <code>fopen()</code> and fills in a set of callbacks
+ that can be used to access it.
+ This is useful to avoid writing your own portable 64-bit seeking wrappers,
+ and also avoids cross-module linking issues on Windows, where a
+ <code>FILE *</code> must be accessed by routines defined in the same module
+ that opened it.
+ \param[out] _cb The callbacks to use for this file.
+ If there is an error opening the file, nothing will be
+ filled in here.
+ \param _path The path to the file to open.
+ On Windows, this string must be UTF-8 (to allow access to
+ files whose names cannot be represented in the current
+ MBCS code page).
+ All other systems use the native character encoding.
+ \param _mode The mode to open the file in.
+ \return A stream handle to use with the callbacks, or <code>NULL</code> on
+ error.*/
+OP_WARN_UNUSED_RESULT void *op_fopen(OpusFileCallbacks *_cb,
+ const char *_path,const char *_mode) OP_ARG_NONNULL(1) OP_ARG_NONNULL(2)
+ OP_ARG_NONNULL(3);
+
+/**Opens a stream with <code>fdopen()</code> and fills in a set of callbacks
+ that can be used to access it.
+ This is useful to avoid writing your own portable 64-bit seeking wrappers,
+ and also avoids cross-module linking issues on Windows, where a
+ <code>FILE *</code> must be accessed by routines defined in the same module
+ that opened it.
+ \param[out] _cb The callbacks to use for this file.
+ If there is an error opening the file, nothing will be
+ filled in here.
+ \param _fd The file descriptor to open.
+ \param _mode The mode to open the file in.
+ \return A stream handle to use with the callbacks, or <code>NULL</code> on
+ error.*/
+OP_WARN_UNUSED_RESULT void *op_fdopen(OpusFileCallbacks *_cb,
+ int _fd,const char *_mode) OP_ARG_NONNULL(1) OP_ARG_NONNULL(3);
+
+/**Opens a stream with <code>freopen()</code> and fills in a set of callbacks
+ that can be used to access it.
+ This is useful to avoid writing your own portable 64-bit seeking wrappers,
+ and also avoids cross-module linking issues on Windows, where a
+ <code>FILE *</code> must be accessed by routines defined in the same module
+ that opened it.
+ \param[out] _cb The callbacks to use for this file.
+ If there is an error opening the file, nothing will be
+ filled in here.
+ \param _path The path to the file to open.
+ On Windows, this string must be UTF-8 (to allow access
+ to files whose names cannot be represented in the
+ current MBCS code page).
+ All other systems use the native character encoding.
+ \param _mode The mode to open the file in.
+ \param _stream A stream previously returned by op_fopen(), op_fdopen(),
+ or op_freopen().
+ \return A stream handle to use with the callbacks, or <code>NULL</code> on
+ error.*/
+OP_WARN_UNUSED_RESULT void *op_freopen(OpusFileCallbacks *_cb,
+ const char *_path,const char *_mode,void *_stream) OP_ARG_NONNULL(1)
+ OP_ARG_NONNULL(2) OP_ARG_NONNULL(3) OP_ARG_NONNULL(4);
+
+/**Creates a stream that reads from the given block of memory.
+ This block of memory must contain the complete stream to decode.
+ This is useful for caching small streams (e.g., sound effects) in RAM.
+ \param[out] _cb The callbacks to use for this stream.
+ If there is an error creating the stream, nothing will be
+ filled in here.
+ \param _data The block of memory to read from.
+ \param _size The size of the block of memory.
+ \return A stream handle to use with the callbacks, or <code>NULL</code> on
+ error.*/
+OP_WARN_UNUSED_RESULT void *op_mem_stream_create(OpusFileCallbacks *_cb,
+ const unsigned char *_data,size_t _size) OP_ARG_NONNULL(1);
+
+/**Creates a stream that reads from the given URL.
+ This function behaves identically to op_url_stream_create(), except that it
+ takes a va_list instead of a variable number of arguments.
+ It does not call the <code>va_end</code> macro, and because it invokes the
+ <code>va_arg</code> macro, the value of \a _ap is undefined after the call.
+ \note If you use this function, you must link against <tt>libopusurl</tt>.
+ \param[out] _cb The callbacks to use for this stream.
+ If there is an error creating the stream, nothing will
+ be filled in here.
+ \param _url The URL to read from.
+ Currently only the <file:>, <http:>, and <https:>
+ schemes are supported.
+ Both <http:> and <https:> may be disabled at compile
+ time, in which case opening such URLs will always fail.
+ Currently this only supports URIs.
+ IRIs should be converted to UTF-8 and URL-escaped, with
+ internationalized domain names encoded in punycode,
+ before passing them to this function.
+ \param[in,out] _ap A list of the \ref url_options "optional flags" to use.
+ This is a variable-length list of options terminated
+ with <code>NULL</code>.
+ \return A stream handle to use with the callbacks, or <code>NULL</code> on
+ error.*/
+OP_WARN_UNUSED_RESULT void *op_url_stream_vcreate(OpusFileCallbacks *_cb,
+ const char *_url,va_list _ap) OP_ARG_NONNULL(1) OP_ARG_NONNULL(2);
+
+/**Creates a stream that reads from the given URL.
+ \note If you use this function, you must link against <tt>libopusurl</tt>.
+ \param[out] _cb The callbacks to use for this stream.
+ If there is an error creating the stream, nothing will be
+ filled in here.
+ \param _url The URL to read from.
+ Currently only the <file:>, <http:>, and <https:> schemes
+ are supported.
+ Both <http:> and <https:> may be disabled at compile time,
+ in which case opening such URLs will always fail.
+ Currently this only supports URIs.
+ IRIs should be converted to UTF-8 and URL-escaped, with
+ internationalized domain names encoded in punycode, before
+ passing them to this function.
+ \param ... The \ref url_options "optional flags" to use.
+ This is a variable-length list of options terminated with
+ <code>NULL</code>.
+ \return A stream handle to use with the callbacks, or <code>NULL</code> on
+ error.*/
+OP_WARN_UNUSED_RESULT void *op_url_stream_create(OpusFileCallbacks *_cb,
+ const char *_url,...) OP_ARG_NONNULL(1) OP_ARG_NONNULL(2);
+
+/*@}*/
+/*@}*/
+
+/**\defgroup stream_open_close Opening and Closing*/
+/*@{*/
+/**\name Functions for opening and closing streams
+
+ These functions allow you to test a stream to see if it is Opus, open it,
+ and close it.
+ Several flavors are provided for each of the built-in stream types, plus a
+ more general version which takes a set of application-provided callbacks.*/
+/*@{*/
+
+/**Test to see if this is an Opus stream.
+ For good results, you will need at least 57 bytes (for a pure Opus-only
+ stream).
+ Something like 512 bytes will give more reliable results for multiplexed
+ streams.
+ This function is meant to be a quick-rejection filter.
+ Its purpose is not to guarantee that a stream is a valid Opus stream, but to
+ ensure that it looks enough like Opus that it isn't going to be recognized
+ as some other format (except possibly an Opus stream that is also
+ multiplexed with other codecs, such as video).
+ \param[out] _head The parsed ID header contents.
+ You may pass <code>NULL</code> if you do not need
+ this information.
+ If the function fails, the contents of this structure
+ remain untouched.
+ \param _initial_data An initial buffer of data from the start of the
+ stream.
+ \param _initial_bytes The number of bytes in \a _initial_data.
+ \return 0 if the data appears to be Opus, or a negative value on error.
+ \retval #OP_FALSE There was not enough data to tell if this was an Opus
+ stream or not.
+ \retval #OP_EFAULT An internal memory allocation failed.
+ \retval #OP_EIMPL The stream used a feature that is not implemented,
+ such as an unsupported channel family.
+ \retval #OP_ENOTFORMAT If the data did not contain a recognizable ID
+ header for an Opus stream.
+ \retval #OP_EVERSION If the version field signaled a version this library
+ does not know how to parse.
+ \retval #OP_EBADHEADER The ID header was not properly formatted or contained
+ illegal values.*/
+int op_test(OpusHead *_head,
+ const unsigned char *_initial_data,size_t _initial_bytes);
+
+/**Open a stream from the given file path.
+ \param _path The path to the file to open.
+ \param[out] _error Returns 0 on success, or a failure code on error.
+ You may pass in <code>NULL</code> if you don't want the
+ failure code.
+ The failure code will be #OP_EFAULT if the file could not
+ be opened, or one of the other failure codes from
+ op_open_callbacks() otherwise.
+ \return A freshly opened \c OggOpusFile, or <code>NULL</code> on error.*/
+OP_WARN_UNUSED_RESULT OggOpusFile *op_open_file(const char *_path,int *_error)
+ OP_ARG_NONNULL(1);
+
+/**Open a stream from a memory buffer.
+ \param _data The memory buffer to open.
+ \param _size The number of bytes in the buffer.
+ \param[out] _error Returns 0 on success, or a failure code on error.
+ You may pass in <code>NULL</code> if you don't want the
+ failure code.
+ See op_open_callbacks() for a full list of failure codes.
+ \return A freshly opened \c OggOpusFile, or <code>NULL</code> on error.*/
+OP_WARN_UNUSED_RESULT OggOpusFile *op_open_memory(const unsigned char *_data,
+ size_t _size,int *_error);
+
+/**Open a stream from a URL.
+ This function behaves identically to op_open_url(), except that it
+ takes a va_list instead of a variable number of arguments.
+ It does not call the <code>va_end</code> macro, and because it invokes the
+ <code>va_arg</code> macro, the value of \a _ap is undefined after the call.
+ \note If you use this function, you must link against <tt>libopusurl</tt>.
+ \param _url The URL to open.
+ Currently only the <file:>, <http:>, and <https:>
+ schemes are supported.
+ Both <http:> and <https:> may be disabled at compile
+ time, in which case opening such URLs will always
+ fail.
+ Currently this only supports URIs.
+ IRIs should be converted to UTF-8 and URL-escaped,
+ with internationalized domain names encoded in
+ punycode, before passing them to this function.
+ \param[out] _error Returns 0 on success, or a failure code on error.
+ You may pass in <code>NULL</code> if you don't want
+ the failure code.
+ See op_open_callbacks() for a full list of failure
+ codes.
+ \param[in,out] _ap A list of the \ref url_options "optional flags" to
+ use.
+ This is a variable-length list of options terminated
+ with <code>NULL</code>.
+ \return A freshly opened \c OggOpusFile, or <code>NULL</code> on error.*/
+OP_WARN_UNUSED_RESULT OggOpusFile *op_vopen_url(const char *_url,
+ int *_error,va_list _ap) OP_ARG_NONNULL(1);
+
+/**Open a stream from a URL.
+ \note If you use this function, you must link against <tt>libopusurl</tt>.
+ \param _url The URL to open.
+ Currently only the <file:>, <http:>, and <https:> schemes
+ are supported.
+ Both <http:> and <https:> may be disabled at compile
+ time, in which case opening such URLs will always fail.
+ Currently this only supports URIs.
+ IRIs should be converted to UTF-8 and URL-escaped, with
+ internationalized domain names encoded in punycode,
+ before passing them to this function.
+ \param[out] _error Returns 0 on success, or a failure code on error.
+ You may pass in <code>NULL</code> if you don't want the
+ failure code.
+ See op_open_callbacks() for a full list of failure codes.
+ \param ... The \ref url_options "optional flags" to use.
+ This is a variable-length list of options terminated with
+ <code>NULL</code>.
+ \return A freshly opened \c OggOpusFile, or <code>NULL</code> on error.*/
+OP_WARN_UNUSED_RESULT OggOpusFile *op_open_url(const char *_url,
+ int *_error,...) OP_ARG_NONNULL(1);
+
+/**Open a stream using the given set of callbacks to access it.
+ \param _source The stream to read from (e.g., a <code>FILE *</code>).
+ \param _cb The callbacks with which to access the stream.
+ <code><a href="#op_read_func">read()</a></code> must
+ be implemented.
+ <code><a href="#op_seek_func">seek()</a></code> and
+ <code><a href="#op_tell_func">tell()</a></code> may
+ be <code>NULL</code>, or may always return -1 to
+ indicate a source is unseekable, but if
+ <code><a href="#op_seek_func">seek()</a></code> is
+ implemented and succeeds on a particular source, then
+ <code><a href="#op_tell_func">tell()</a></code> must
+ also.
+ <code><a href="#op_close_func">close()</a></code> may
+ be <code>NULL</code>, but if it is not, it will be
+ called when the \c OggOpusFile is destroyed by
+ op_free().
+ It will not be called if op_open_callbacks() fails
+ with an error.
+ \param _initial_data An initial buffer of data from the start of the
+ stream.
+ Applications can read some number of bytes from the
+ start of the stream to help identify this as an Opus
+ stream, and then provide them here to allow the
+ stream to be opened, even if it is unseekable.
+ \param _initial_bytes The number of bytes in \a _initial_data.
+ If the stream is seekable, its current position (as
+ reported by
+ <code><a href="#opus_tell_func">tell()</a></code>
+ at the start of this function) must be equal to
+ \a _initial_bytes.
+ Otherwise, seeking to absolute positions will
+ generate inconsistent results.
+ \param[out] _error Returns 0 on success, or a failure code on error.
+ You may pass in <code>NULL</code> if you don't want
+ the failure code.
+ The failure code will be one of
+ <dl>
+ <dt>#OP_EREAD</dt>
+ <dd>An underlying read, seek, or tell operation
+ failed when it should have succeeded, or we failed
+ to find data in the stream we had seen before.</dd>
+ <dt>#OP_EFAULT</dt>
+ <dd>There was a memory allocation failure, or an
+ internal library error.</dd>
+ <dt>#OP_EIMPL</dt>
+ <dd>The stream used a feature that is not
+ implemented, such as an unsupported channel
+ family.</dd>
+ <dt>#OP_EINVAL</dt>
+ <dd><code><a href="#op_seek_func">seek()</a></code>
+ was implemented and succeeded on this source, but
+ <code><a href="#op_tell_func">tell()</a></code>
+ did not, or the starting position indicator was
+ not equal to \a _initial_bytes.</dd>
+ <dt>#OP_ENOTFORMAT</dt>
+ <dd>The stream contained a link that did not have
+ any logical Opus streams in it.</dd>
+ <dt>#OP_EBADHEADER</dt>
+ <dd>A required header packet was not properly
+ formatted, contained illegal values, or was missing
+ altogether.</dd>
+ <dt>#OP_EVERSION</dt>
+ <dd>An ID header contained an unrecognized version
+ number.</dd>
+ <dt>#OP_EBADLINK</dt>
+ <dd>We failed to find data we had seen before after
+ seeking.</dd>
+ <dt>#OP_EBADTIMESTAMP</dt>
+ <dd>The first or last timestamp in a link failed
+ basic validity checks.</dd>
+ </dl>
+ \return A freshly opened \c OggOpusFile, or <code>NULL</code> on error.
+ <tt>libopusfile</tt> does <em>not</em> take ownership of the source
+ if the call fails.
+ The calling application is responsible for closing the source if
+ this call returns an error.*/
+OP_WARN_UNUSED_RESULT OggOpusFile *op_open_callbacks(void *_source,
+ const OpusFileCallbacks *_cb,const unsigned char *_initial_data,
+ size_t _initial_bytes,int *_error) OP_ARG_NONNULL(2);
+
+/**Partially open a stream from the given file path.
+ \see op_test_callbacks
+ \param _path The path to the file to open.
+ \param[out] _error Returns 0 on success, or a failure code on error.
+ You may pass in <code>NULL</code> if you don't want the
+ failure code.
+ The failure code will be #OP_EFAULT if the file could not
+ be opened, or one of the other failure codes from
+ op_open_callbacks() otherwise.
+ \return A partially opened \c OggOpusFile, or <code>NULL</code> on error.*/
+OP_WARN_UNUSED_RESULT OggOpusFile *op_test_file(const char *_path,int *_error)
+ OP_ARG_NONNULL(1);
+
+/**Partially open a stream from a memory buffer.
+ \see op_test_callbacks
+ \param _data The memory buffer to open.
+ \param _size The number of bytes in the buffer.
+ \param[out] _error Returns 0 on success, or a failure code on error.
+ You may pass in <code>NULL</code> if you don't want the
+ failure code.
+ See op_open_callbacks() for a full list of failure codes.
+ \return A partially opened \c OggOpusFile, or <code>NULL</code> on error.*/
+OP_WARN_UNUSED_RESULT OggOpusFile *op_test_memory(const unsigned char *_data,
+ size_t _size,int *_error);
+
+/**Partially open a stream from a URL.
+ This function behaves identically to op_test_url(), except that it
+ takes a va_list instead of a variable number of arguments.
+ It does not call the <code>va_end</code> macro, and because it invokes the
+ <code>va_arg</code> macro, the value of \a _ap is undefined after the call.
+ \note If you use this function, you must link against <tt>libopusurl</tt>.
+ \see op_test_url
+ \see op_test_callbacks
+ \param _url The URL to open.
+ Currently only the <file:>, <http:>, and <https:>
+ schemes are supported.
+ Both <http:> and <https:> may be disabled at compile
+ time, in which case opening such URLs will always
+ fail.
+ Currently this only supports URIs.
+ IRIs should be converted to UTF-8 and URL-escaped,
+ with internationalized domain names encoded in
+ punycode, before passing them to this function.
+ \param[out] _error Returns 0 on success, or a failure code on error.
+ You may pass in <code>NULL</code> if you don't want
+ the failure code.
+ See op_open_callbacks() for a full list of failure
+ codes.
+ \param[in,out] _ap A list of the \ref url_options "optional flags" to
+ use.
+ This is a variable-length list of options terminated
+ with <code>NULL</code>.
+ \return A partially opened \c OggOpusFile, or <code>NULL</code> on error.*/
+OP_WARN_UNUSED_RESULT OggOpusFile *op_vtest_url(const char *_url,
+ int *_error,va_list _ap) OP_ARG_NONNULL(1);
+
+/**Partially open a stream from a URL.
+ \note If you use this function, you must link against <tt>libopusurl</tt>.
+ \see op_test_callbacks
+ \param _url The URL to open.
+ Currently only the <file:>, <http:>, and <https:>
+ schemes are supported.
+ Both <http:> and <https:> may be disabled at compile
+ time, in which case opening such URLs will always fail.
+ Currently this only supports URIs.
+ IRIs should be converted to UTF-8 and URL-escaped, with
+ internationalized domain names encoded in punycode,
+ before passing them to this function.
+ \param[out] _error Returns 0 on success, or a failure code on error.
+ You may pass in <code>NULL</code> if you don't want the
+ failure code.
+ See op_open_callbacks() for a full list of failure
+ codes.
+ \param ... The \ref url_options "optional flags" to use.
+ This is a variable-length list of options terminated
+ with <code>NULL</code>.
+ \return A partially opened \c OggOpusFile, or <code>NULL</code> on error.*/
+OP_WARN_UNUSED_RESULT OggOpusFile *op_test_url(const char *_url,
+ int *_error,...) OP_ARG_NONNULL(1);
+
+/**Partially open a stream using the given set of callbacks to access it.
+ This tests for Opusness and loads the headers for the first link.
+ It does not seek (although it tests for seekability).
+ You can query a partially open stream for the few pieces of basic
+ information returned by op_serialno(), op_channel_count(), op_head(), and
+ op_tags() (but only for the first link).
+ You may also determine if it is seekable via a call to op_seekable().
+ You cannot read audio from the stream, seek, get the size or duration,
+ get information from links other than the first one, or even get the total
+ number of links until you finish opening the stream with op_test_open().
+ If you do not need to do any of these things, you can dispose of it with
+ op_free() instead.
+
+ This function is provided mostly to simplify porting existing code that used
+ <tt>libvorbisfile</tt>.
+ For new code, you are likely better off using op_test() instead, which
+ is less resource-intensive, requires less data to succeed, and imposes a
+ hard limit on the amount of data it examines (important for unseekable
+ sources, where all such data must be buffered until you are sure of the
+ stream type).
+ \param _source The stream to read from (e.g., a <code>FILE *</code>).
+ \param _cb The callbacks with which to access the stream.
+ <code><a href="#op_read_func">read()</a></code> must
+ be implemented.
+ <code><a href="#op_seek_func">seek()</a></code> and
+ <code><a href="#op_tell_func">tell()</a></code> may
+ be <code>NULL</code>, or may always return -1 to
+ indicate a source is unseekable, but if
+ <code><a href="#op_seek_func">seek()</a></code> is
+ implemented and succeeds on a particular source, then
+ <code><a href="#op_tell_func">tell()</a></code> must
+ also.
+ <code><a href="#op_close_func">close()</a></code> may
+ be <code>NULL</code>, but if it is not, it will be
+ called when the \c OggOpusFile is destroyed by
+ op_free().
+ It will not be called if op_open_callbacks() fails
+ with an error.
+ \param _initial_data An initial buffer of data from the start of the
+ stream.
+ Applications can read some number of bytes from the
+ start of the stream to help identify this as an Opus
+ stream, and then provide them here to allow the
+ stream to be tested more thoroughly, even if it is
+ unseekable.
+ \param _initial_bytes The number of bytes in \a _initial_data.
+ If the stream is seekable, its current position (as
+ reported by
+ <code><a href="#opus_tell_func">tell()</a></code>
+ at the start of this function) must be equal to
+ \a _initial_bytes.
+ Otherwise, seeking to absolute positions will
+ generate inconsistent results.
+ \param[out] _error Returns 0 on success, or a failure code on error.
+ You may pass in <code>NULL</code> if you don't want
+ the failure code.
+ See op_open_callbacks() for a full list of failure
+ codes.
+ \return A partially opened \c OggOpusFile, or <code>NULL</code> on error.
+ <tt>libopusfile</tt> does <em>not</em> take ownership of the source
+ if the call fails.
+ The calling application is responsible for closing the source if
+ this call returns an error.*/
+OP_WARN_UNUSED_RESULT OggOpusFile *op_test_callbacks(void *_source,
+ const OpusFileCallbacks *_cb,const unsigned char *_initial_data,
+ size_t _initial_bytes,int *_error) OP_ARG_NONNULL(2);
+
+/**Finish opening a stream partially opened with op_test_callbacks() or one of
+ the associated convenience functions.
+ If this function fails, you are still responsible for freeing the
+ \c OggOpusFile with op_free().
+ \param _of The \c OggOpusFile to finish opening.
+ \return 0 on success, or a negative value on error.
+ \retval #OP_EREAD An underlying read, seek, or tell operation failed
+ when it should have succeeded.
+ \retval #OP_EFAULT There was a memory allocation failure, or an
+ internal library error.
+ \retval #OP_EIMPL The stream used a feature that is not implemented,
+ such as an unsupported channel family.
+ \retval #OP_EINVAL The stream was not partially opened with
+ op_test_callbacks() or one of the associated
+ convenience functions.
+ \retval #OP_ENOTFORMAT The stream contained a link that did not have any
+ logical Opus streams in it.
+ \retval #OP_EBADHEADER A required header packet was not properly
+ formatted, contained illegal values, or was
+ missing altogether.
+ \retval #OP_EVERSION An ID header contained an unrecognized version
+ number.
+ \retval #OP_EBADLINK We failed to find data we had seen before after
+ seeking.
+ \retval #OP_EBADTIMESTAMP The first or last timestamp in a link failed basic
+ validity checks.*/
+int op_test_open(OggOpusFile *_of) OP_ARG_NONNULL(1);
+
+/**Release all memory used by an \c OggOpusFile.
+ \param _of The \c OggOpusFile to free.*/
+void op_free(OggOpusFile *_of);
+
+/*@}*/
+/*@}*/
+
+/**\defgroup stream_info Stream Information*/
+/*@{*/
+/**\name Functions for obtaining information about streams
+
+ These functions allow you to get basic information about a stream, including
+ seekability, the number of links (for chained streams), plus the size,
+ duration, bitrate, header parameters, and meta information for each link
+ (or, where available, the stream as a whole).
+ Some of these (size, duration) are only available for seekable streams.
+ You can also query the current stream position, link, and playback time,
+ and instantaneous bitrate during playback.
+
+ Some of these functions may be used successfully on the partially open
+ streams returned by op_test_callbacks() or one of the associated
+ convenience functions.
+ Their documention will indicate so explicitly.*/
+/*@{*/
+
+/**Returns whether or not the data source being read is seekable.
+ This is true if
+ <ol>
+ <li>The <code><a href="#op_seek_func">seek()</a></code> and
+ <code><a href="#op_tell_func">tell()</a></code> callbacks are both
+ non-<code>NULL</code>,</li>
+ <li>The <code><a href="#op_seek_func">seek()</a></code> callback was
+ successfully executed at least once, and</li>
+ <li>The <code><a href="#op_tell_func">tell()</a></code> callback was
+ successfully able to report the position indicator afterwards.</li>
+ </ol>
+ This function may be called on partially-opened streams.
+ \param _of The \c OggOpusFile whose seekable status is to be returned.
+ \return A non-zero value if seekable, and 0 if unseekable.*/
+int op_seekable(const OggOpusFile *_of) OP_ARG_NONNULL(1);
+
+/**Returns the number of links in this chained stream.
+ This function may be called on partially-opened streams, but it will always
+ return 1.
+ The actual number of links is not known until the stream is fully opened.
+ \param _of The \c OggOpusFile from which to retrieve the link count.
+ \return For fully-open seekable sources, this returns the total number of
+ links in the whole stream, which will be at least 1.
+ For partially-open or unseekable sources, this always returns 1.*/
+int op_link_count(const OggOpusFile *_of) OP_ARG_NONNULL(1);
+
+/**Get the serial number of the given link in a (possibly-chained) Ogg Opus
+ stream.
+ This function may be called on partially-opened streams, but it will always
+ return the serial number of the Opus stream in the first link.
+ \param _of The \c OggOpusFile from which to retrieve the serial number.
+ \param _li The index of the link whose serial number should be retrieved.
+ Use a negative number to get the serial number of the current
+ link.
+ \return The serial number of the given link.
+ If \a _li is greater than the total number of links, this returns
+ the serial number of the last link.
+ If the source is not seekable, this always returns the serial number
+ of the current link.*/
+opus_uint32 op_serialno(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
+
+/**Get the channel count of the given link in a (possibly-chained) Ogg Opus
+ stream.
+ This is equivalent to <code>op_head(_of,_li)->channel_count</code>, but
+ is provided for convenience.
+ This function may be called on partially-opened streams, but it will always
+ return the channel count of the Opus stream in the first link.
+ \param _of The \c OggOpusFile from which to retrieve the channel count.
+ \param _li The index of the link whose channel count should be retrieved.
+ Use a negative number to get the channel count of the current
+ link.
+ \return The channel count of the given link.
+ If \a _li is greater than the total number of links, this returns
+ the channel count of the last link.
+ If the source is not seekable, this always returns the channel count
+ of the current link.*/
+int op_channel_count(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
+
+/**Get the total (compressed) size of the stream, or of an individual link in
+ a (possibly-chained) Ogg Opus stream, including all headers and Ogg muxing
+ overhead.
+ \warning If the Opus stream (or link) is concurrently multiplexed with other
+ logical streams (e.g., video), this returns the size of the entire stream
+ (or link), not just the number of bytes in the first logical Opus stream.
+ Returning the latter would require scanning the entire file.
+ \param _of The \c OggOpusFile from which to retrieve the compressed size.
+ \param _li The index of the link whose compressed size should be computed.
+ Use a negative number to get the compressed size of the entire
+ stream.
+ \return The compressed size of the entire stream if \a _li is negative, the
+ compressed size of link \a _li if it is non-negative, or a negative
+ value on error.
+ The compressed size of the entire stream may be smaller than that
+ of the underlying source if trailing garbage was detected in the
+ file.
+ \retval #OP_EINVAL The source is not seekable (so we can't know the length),
+ \a _li wasn't less than the total number of links in
+ the stream, or the stream was only partially open.*/
+opus_int64 op_raw_total(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
+
+/**Get the total PCM length (number of samples at 48 kHz) of the stream, or of
+ an individual link in a (possibly-chained) Ogg Opus stream.
+ Users looking for <code>op_time_total()</code> should use op_pcm_total()
+ instead.
+ Because timestamps in Opus are fixed at 48 kHz, there is no need for a
+ separate function to convert this to seconds (and leaving it out avoids
+ introducing floating point to the API, for those that wish to avoid it).
+ \param _of The \c OggOpusFile from which to retrieve the PCM offset.
+ \param _li The index of the link whose PCM length should be computed.
+ Use a negative number to get the PCM length of the entire stream.
+ \return The PCM length of the entire stream if \a _li is negative, the PCM
+ length of link \a _li if it is non-negative, or a negative value on
+ error.
+ \retval #OP_EINVAL The source is not seekable (so we can't know the length),
+ \a _li wasn't less than the total number of links in
+ the stream, or the stream was only partially open.*/
+ogg_int64_t op_pcm_total(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
+
+/**Get the ID header information for the given link in a (possibly chained) Ogg
+ Opus stream.
+ This function may be called on partially-opened streams, but it will always
+ return the ID header information of the Opus stream in the first link.
+ \param _of The \c OggOpusFile from which to retrieve the ID header
+ information.
+ \param _li The index of the link whose ID header information should be
+ retrieved.
+ Use a negative number to get the ID header information of the
+ current link.
+ For an unseekable stream, \a _li is ignored, and the ID header
+ information for the current link is always returned, if
+ available.
+ \return The contents of the ID header for the given link.*/
+const OpusHead *op_head(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
+
+/**Get the comment header information for the given link in a (possibly
+ chained) Ogg Opus stream.
+ This function may be called on partially-opened streams, but it will always
+ return the tags from the Opus stream in the first link.
+ \param _of The \c OggOpusFile from which to retrieve the comment header
+ information.
+ \param _li The index of the link whose comment header information should be
+ retrieved.
+ Use a negative number to get the comment header information of
+ the current link.
+ For an unseekable stream, \a _li is ignored, and the comment
+ header information for the current link is always returned, if
+ available.
+ \return The contents of the comment header for the given link, or
+ <code>NULL</code> if this is an unseekable stream that encountered
+ an invalid link.*/
+const OpusTags *op_tags(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
+
+/**Retrieve the index of the current link.
+ This is the link that produced the data most recently read by
+ op_read_float() or its associated functions, or, after a seek, the link
+ that the seek target landed in.
+ Reading more data may advance the link index (even on the first read after a
+ seek).
+ \param _of The \c OggOpusFile from which to retrieve the current link index.
+ \return The index of the current link on success, or a negative value on
+ failure.
+ For seekable streams, this is a number between 0 and the value
+ returned by op_link_count().
+ For unseekable streams, this value starts at 0 and increments by one
+ each time a new link is encountered (even though op_link_count()
+ always returns 1).
+ \retval #OP_EINVAL The stream was only partially open.*/
+int op_current_link(const OggOpusFile *_of) OP_ARG_NONNULL(1);
+
+/**Computes the bitrate of the stream, or of an individual link in a
+ (possibly-chained) Ogg Opus stream.
+ The stream must be seekable to compute the bitrate.
+ For unseekable streams, use op_bitrate_instant() to get periodic estimates.
+ \warning If the Opus stream (or link) is concurrently multiplexed with other
+ logical streams (e.g., video), this uses the size of the entire stream (or
+ link) to compute the bitrate, not just the number of bytes in the first
+ logical Opus stream.
+ Returning the latter requires scanning the entire file, but this may be done
+ by decoding the whole file and calling op_bitrate_instant() once at the
+ end.
+ Install a trivial decoding callback with op_set_decode_callback() if you
+ wish to skip actual decoding during this process.
+ \param _of The \c OggOpusFile from which to retrieve the bitrate.
+ \param _li The index of the link whose bitrate should be computed.
+ Use a negative number to get the bitrate of the whole stream.
+ \return The bitrate on success, or a negative value on error.
+ \retval #OP_EINVAL The stream was only partially open, the stream was not
+ seekable, or \a _li was larger than the number of
+ links.*/
+opus_int32 op_bitrate(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
+
+/**Compute the instantaneous bitrate, measured as the ratio of bits to playable
+ samples decoded since a) the last call to op_bitrate_instant(), b) the last
+ seek, or c) the start of playback, whichever was most recent.
+ This will spike somewhat after a seek or at the start/end of a chain
+ boundary, as pre-skip, pre-roll, and end-trimming causes samples to be
+ decoded but not played.
+ \param _of The \c OggOpusFile from which to retrieve the bitrate.
+ \return The bitrate, in bits per second, or a negative value on error.
+ \retval #OP_FALSE No data has been decoded since any of the events
+ described above.
+ \retval #OP_EINVAL The stream was only partially open.*/
+opus_int32 op_bitrate_instant(OggOpusFile *_of) OP_ARG_NONNULL(1);
+
+/**Obtain the current value of the position indicator for \a _of.
+ \param _of The \c OggOpusFile from which to retrieve the position indicator.
+ \return The byte position that is currently being read from.
+ \retval #OP_EINVAL The stream was only partially open.*/
+opus_int64 op_raw_tell(const OggOpusFile *_of) OP_ARG_NONNULL(1);
+
+/**Obtain the PCM offset of the next sample to be read.
+ If the stream is not properly timestamped, this might not increment by the
+ proper amount between reads, or even return monotonically increasing
+ values.
+ \param _of The \c OggOpusFile from which to retrieve the PCM offset.
+ \return The PCM offset of the next sample to be read.
+ \retval #OP_EINVAL The stream was only partially open.*/
+ogg_int64_t op_pcm_tell(const OggOpusFile *_of) OP_ARG_NONNULL(1);
+
+/*@}*/
+/*@}*/
+
+/**\defgroup stream_seeking Seeking*/
+/*@{*/
+/**\name Functions for seeking in Opus streams
+
+ These functions let you seek in Opus streams, if the underlying source
+ support it.
+ Seeking is implemented for all built-in stream I/O routines, though some
+ individual sources may not be seekable (pipes, live HTTP streams, or HTTP
+ streams from a server that does not support <code>Range</code> requests).
+
+ op_raw_seek() is the fastest: it is guaranteed to perform at most one
+ physical seek, but, since the target is a byte position, makes no guarantee
+ how close to a given time it will come.
+ op_pcm_seek() provides sample-accurate seeking.
+ The number of physical seeks it requires is still quite small (often 1 or
+ 2, even in highly variable bitrate streams).
+
+ Seeking in Opus requires decoding some pre-roll amount before playback to
+ allow the internal state to converge (as if recovering from packet loss).
+ This is handled internally by <tt>libopusfile</tt>, but means there is
+ little extra overhead for decoding up to the exact position requested
+ (since it must decode some amount of audio anyway).
+ It also means that decoding after seeking may not return exactly the same
+ values as would be obtained by decoding the stream straight through.
+ However, such differences are expected to be smaller than the loss
+ introduced by Opus's lossy compression.*/
+/*@{*/
+
+/**Seek to a byte offset relative to the <b>compressed</b> data.
+ This also scans packets to update the PCM cursor.
+ It will cross a logical bitstream boundary, but only if it can't get any
+ packets out of the tail of the link to which it seeks.
+ \param _of The \c OggOpusFile in which to seek.
+ \param _byte_offset The byte position to seek to.
+ \return 0 on success, or a negative error code on failure.
+ \retval #OP_EREAD The underlying seek operation failed.
+ \retval #OP_EINVAL The stream was only partially open, or the target was
+ outside the valid range for the stream.
+ \retval #OP_ENOSEEK This stream is not seekable.
+ \retval #OP_EBADLINK Failed to initialize a decoder for a stream for an
+ unknown reason.*/
+int op_raw_seek(OggOpusFile *_of,opus_int64 _byte_offset) OP_ARG_NONNULL(1);
+
+/**Seek to the specified PCM offset, such that decoding will begin at exactly
+ the requested position.
+ \param _of The \c OggOpusFile in which to seek.
+ \param _pcm_offset The PCM offset to seek to.
+ This is in samples at 48 kHz relative to the start of the
+ stream.
+ \return 0 on success, or a negative value on error.
+ \retval #OP_EREAD An underlying read or seek operation failed.
+ \retval #OP_EINVAL The stream was only partially open, or the target was
+ outside the valid range for the stream.
+ \retval #OP_ENOSEEK This stream is not seekable.
+ \retval #OP_EBADLINK We failed to find data we had seen before, or the
+ bitstream structure was sufficiently malformed that
+ seeking to the target destination was impossible.*/
+int op_pcm_seek(OggOpusFile *_of,ogg_int64_t _pcm_offset) OP_ARG_NONNULL(1);
+
+/*@}*/
+/*@}*/
+
+/**\defgroup stream_decoding Decoding*/
+/*@{*/
+/**\name Functions for decoding audio data
+
+ These functions retrieve actual decoded audio data from the stream.
+ The general functions, op_read() and op_read_float() return 16-bit or
+ floating-point output, both using native endian ordering.
+ The number of channels returned can change from link to link in a chained
+ stream.
+ There are special functions, op_read_stereo() and op_read_float_stereo(),
+ which always output two channels, to simplify applications which do not
+ wish to handle multichannel audio.
+ These downmix multichannel files to two channels, so they can always return
+ samples in the same format for every link in a chained file.
+
+ If the rest of your audio processing chain can handle floating point, those
+ routines should be preferred, as floating point output avoids introducing
+ clipping and other issues which might be avoided entirely if, e.g., you
+ scale down the volume at some other stage.
+ However, if you intend to direct consume 16-bit samples, the conversion in
+ <tt>libopusfile</tt> provides noise-shaping dithering and, if compiled
+ against <tt>libopus</tt>&nbsp;1.1 or later, soft-clipping prevention.
+
+ <tt>libopusfile</tt> can also be configured at compile time to use the
+ fixed-point <tt>libopus</tt> API.
+ If so, <tt>libopusfile</tt>'s floating-point API may also be disabled.
+ In that configuration, nothing in <tt>libopusfile</tt> will use any
+ floating-point operations, to simplify support on devices without an
+ adequate FPU.
+
+ \warning HTTPS streams may be be vulnerable to truncation attacks if you do
+ not check the error return code from op_read_float() or its associated
+ functions.
+ If the remote peer does not close the connection gracefully (with a TLS
+ "close notify" message), these functions will return #OP_EREAD instead of 0
+ when they reach the end of the file.
+ If you are reading from an <https:> URL (particularly if seeking is not
+ supported), you should make sure to check for this error and warn the user
+ appropriately.*/
+/*@{*/
+
+/**Indicates that the decoding callback should produce signed 16-bit
+ native-endian output samples.*/
+#define OP_DEC_FORMAT_SHORT (7008)
+/**Indicates that the decoding callback should produce 32-bit native-endian
+ float samples.*/
+#define OP_DEC_FORMAT_FLOAT (7040)
+
+/**Indicates that the decoding callback did not decode anything, and that
+ <tt>libopusfile</tt> should decode normally instead.*/
+#define OP_DEC_USE_DEFAULT (6720)
+
+/**Called to decode an Opus packet.
+ This should invoke the functional equivalent of opus_multistream_decode() or
+ opus_multistream_decode_float(), except that it returns 0 on success
+ instead of the number of decoded samples (which is known a priori).
+ \param _ctx The application-provided callback context.
+ \param _decoder The decoder to use to decode the packet.
+ \param[out] _pcm The buffer to decode into.
+ This will always have enough room for \a _nchannels of
+ \a _nsamples samples, which should be placed into this
+ buffer interleaved.
+ \param _op The packet to decode.
+ This will always have its granule position set to a valid
+ value.
+ \param _nsamples The number of samples expected from the packet.
+ \param _nchannels The number of channels expected from the packet.
+ \param _format The desired sample output format.
+ This is either #OP_DEC_FORMAT_SHORT or
+ #OP_DEC_FORMAT_FLOAT.
+ \param _li The index of the link from which this packet was decoded.
+ \return A non-negative value on success, or a negative value on error.
+ The error codes should be the same as those returned by
+ opus_multistream_decode() or opus_multistream_decode_float().
+ \retval 0 Decoding was successful.
+ The application has filled the buffer with
+ exactly <code>\a _nsamples*\a
+ _nchannels</code> samples in the requested
+ format.
+ \retval #OP_DEC_USE_DEFAULT No decoding was done.
+ <tt>libopusfile</tt> should decode normally
+ instead.*/
+typedef int (*op_decode_cb_func)(void *_ctx,OpusMSDecoder *_decoder,void *_pcm,
+ const ogg_packet *_op,int _nsamples,int _nchannels,int _format,int _li);
+
+/**Sets the packet decode callback function.
+ This is called once for each packet that needs to be decoded.
+ A call to this function is no guarantee that the audio will eventually be
+ delivered to the application.
+ Some or all of the data from the packet may be discarded (i.e., at the
+ beginning or end of a link, or after a seek), however the callback is
+ required to provide all of it.
+ \param _of The \c OggOpusFile on which to set the decode callback.
+ \param _decode_cb The callback function to call.
+ This may be <code>NULL</code> to disable calling the
+ callback.
+ \param _ctx The application-provided context pointer to pass to the
+ callback on each call.*/
+void op_set_decode_callback(OggOpusFile *_of,
+ op_decode_cb_func _decode_cb,void *_ctx) OP_ARG_NONNULL(1);
+
+/**Gain offset type that indicates that the provided offset is relative to the
+ header gain.
+ This is the default.*/
+#define OP_HEADER_GAIN (0)
+
+/**Gain offset type that indicates that the provided offset is relative to the
+ R128_TRACK_GAIN value (if any), in addition to the header gain.*/
+#define OP_TRACK_GAIN (3008)
+
+/**Gain offset type that indicates that the provided offset should be used as
+ the gain directly, without applying any the header or track gains.*/
+#define OP_ABSOLUTE_GAIN (3009)
+
+/**Sets the gain to be used for decoded output.
+ By default, the gain in the header is applied with no additional offset.
+ The total gain (including header gain and/or track gain, if applicable, and
+ this offset), will be clamped to [-32768,32767]/256 dB.
+ This is more than enough to saturate or underflow 16-bit PCM.
+ \note The new gain will not be applied to any already buffered, decoded
+ output.
+ This means you cannot change it sample-by-sample, as at best it will be
+ updated packet-by-packet.
+ It is meant for setting a target volume level, rather than applying smooth
+ fades, etc.
+ \param _of The \c OggOpusFile on which to set the gain offset.
+ \param _gain_type One of #OP_HEADER_GAIN, #OP_TRACK_GAIN, or
+ #OP_ABSOLUTE_GAIN.
+ \param _gain_offset_q8 The gain offset to apply, in 1/256ths of a dB.
+ \return 0 on success or a negative value on error.
+ \retval #OP_EINVAL The \a _gain_type was unrecognized.*/
+int op_set_gain_offset(OggOpusFile *_of,
+ int _gain_type,opus_int32 _gain_offset_q8) OP_ARG_NONNULL(1);
+
+/**Sets whether or not dithering is enabled for 16-bit decoding.
+ By default, when <tt>libopusfile</tt> is compiled to use floating-point
+ internally, calling op_read() or op_read_stereo() will first decode to
+ float, and then convert to fixed-point using noise-shaping dithering.
+ This flag can be used to disable that dithering.
+ When the application uses op_read_float() or op_read_float_stereo(), or when
+ the library has been compiled to decode directly to fixed point, this flag
+ has no effect.
+ \param _of The \c OggOpusFile on which to enable or disable dithering.
+ \param _enabled A non-zero value to enable dithering, or 0 to disable it.*/
+void op_set_dither_enabled(OggOpusFile *_of,int _enabled) OP_ARG_NONNULL(1);
+
+/**Reads more samples from the stream.
+ \note Although \a _buf_size must indicate the total number of values that
+ can be stored in \a _pcm, the return value is the number of samples
+ <em>per channel</em>.
+ This is done because
+ <ol>
+ <li>The channel count cannot be known a priori (reading more samples might
+ advance us into the next link, with a different channel count), so
+ \a _buf_size cannot also be in units of samples per channel,</li>
+ <li>Returning the samples per channel matches the <code>libopus</code> API
+ as closely as we're able,</li>
+ <li>Returning the total number of values instead of samples per channel
+ would mean the caller would need a division to compute the samples per
+ channel, and might worry about the possibility of getting back samples
+ for some channels and not others, and</li>
+ <li>This approach is relatively fool-proof: if an application passes too
+ small a value to \a _buf_size, they will simply get fewer samples back,
+ and if they assume the return value is the total number of values, then
+ they will simply read too few (rather than reading too many and going
+ off the end of the buffer).</li>
+ </ol>
+ \param _of The \c OggOpusFile from which to read.
+ \param[out] _pcm A buffer in which to store the output PCM samples, as
+ signed native-endian 16-bit values at 48&nbsp;kHz
+ with a nominal range of <code>[-32768,32767)</code>.
+ Multiple channels are interleaved using the
+ <a href="http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9">Vorbis
+ channel ordering</a>.
+ This must have room for at least \a _buf_size values.
+ \param _buf_size The number of values that can be stored in \a _pcm.
+ It is recommended that this be large enough for at
+ least 120 ms of data at 48 kHz per channel (5760
+ values per channel).
+ Smaller buffers will simply return less data, possibly
+ consuming more memory to buffer the data internally.
+ <tt>libopusfile</tt> may return less data than
+ requested.
+ If so, there is no guarantee that the remaining data
+ in \a _pcm will be unmodified.
+ \param[out] _li The index of the link this data was decoded from.
+ You may pass <code>NULL</code> if you do not need this
+ information.
+ If this function fails (returning a negative value),
+ this parameter is left unset.
+ \return The number of samples read per channel on success, or a negative
+ value on failure.
+ The channel count can be retrieved on success by calling
+ <code>op_head(_of,*_li)</code>.
+ The number of samples returned may be 0 if the buffer was too small
+ to store even a single sample for all channels, or if end-of-file
+ was reached.
+ The list of possible failure codes follows.
+ Most of them can only be returned by unseekable, chained streams
+ that encounter a new link.
+ \retval #OP_HOLE There was a hole in the data, and some samples
+ may have been skipped.
+ Call this function again to continue decoding
+ past the hole.
+ \retval #OP_EREAD An underlying read operation failed.
+ This may signal a truncation attack from an
+ <https:> source.
+ \retval #OP_EFAULT An internal memory allocation failed.
+ \retval #OP_EIMPL An unseekable stream encountered a new link that
+ used a feature that is not implemented, such as
+ an unsupported channel family.
+ \retval #OP_EINVAL The stream was only partially open.
+ \retval #OP_ENOTFORMAT An unseekable stream encountered a new link that
+ did not have any logical Opus streams in it.
+ \retval #OP_EBADHEADER An unseekable stream encountered a new link with a
+ required header packet that was not properly
+ formatted, contained illegal values, or was
+ missing altogether.
+ \retval #OP_EVERSION An unseekable stream encountered a new link with
+ an ID header that contained an unrecognized
+ version number.
+ \retval #OP_EBADPACKET Failed to properly decode the next packet.
+ \retval #OP_EBADLINK We failed to find data we had seen before.
+ \retval #OP_EBADTIMESTAMP An unseekable stream encountered a new link with
+ a starting timestamp that failed basic validity
+ checks.*/
+OP_WARN_UNUSED_RESULT int op_read(OggOpusFile *_of,
+ opus_int16 *_pcm,int _buf_size,int *_li) OP_ARG_NONNULL(1);
+
+/**Reads more samples from the stream.
+ \note Although \a _buf_size must indicate the total number of values that
+ can be stored in \a _pcm, the return value is the number of samples
+ <em>per channel</em>.
+ <ol>
+ <li>The channel count cannot be known a priori (reading more samples might
+ advance us into the next link, with a different channel count), so
+ \a _buf_size cannot also be in units of samples per channel,</li>
+ <li>Returning the samples per channel matches the <code>libopus</code> API
+ as closely as we're able,</li>
+ <li>Returning the total number of values instead of samples per channel
+ would mean the caller would need a division to compute the samples per
+ channel, and might worry about the possibility of getting back samples
+ for some channels and not others, and</li>
+ <li>This approach is relatively fool-proof: if an application passes too
+ small a value to \a _buf_size, they will simply get fewer samples back,
+ and if they assume the return value is the total number of values, then
+ they will simply read too few (rather than reading too many and going
+ off the end of the buffer).</li>
+ </ol>
+ \param _of The \c OggOpusFile from which to read.
+ \param[out] _pcm A buffer in which to store the output PCM samples as
+ signed floats at 48&nbsp;kHz with a nominal range of
+ <code>[-1.0,1.0]</code>.
+ Multiple channels are interleaved using the
+ <a href="http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-800004.3.9">Vorbis
+ channel ordering</a>.
+ This must have room for at least \a _buf_size floats.
+ \param _buf_size The number of floats that can be stored in \a _pcm.
+ It is recommended that this be large enough for at
+ least 120 ms of data at 48 kHz per channel (5760
+ samples per channel).
+ Smaller buffers will simply return less data, possibly
+ consuming more memory to buffer the data internally.
+ If less than \a _buf_size values are returned,
+ <tt>libopusfile</tt> makes no guarantee that the
+ remaining data in \a _pcm will be unmodified.
+ \param[out] _li The index of the link this data was decoded from.
+ You may pass <code>NULL</code> if you do not need this
+ information.
+ If this function fails (returning a negative value),
+ this parameter is left unset.
+ \return The number of samples read per channel on success, or a negative
+ value on failure.
+ The channel count can be retrieved on success by calling
+ <code>op_head(_of,*_li)</code>.
+ The number of samples returned may be 0 if the buffer was too small
+ to store even a single sample for all channels, or if end-of-file
+ was reached.
+ The list of possible failure codes follows.
+ Most of them can only be returned by unseekable, chained streams
+ that encounter a new link.
+ \retval #OP_HOLE There was a hole in the data, and some samples
+ may have been skipped.
+ Call this function again to continue decoding
+ past the hole.
+ \retval #OP_EREAD An underlying read operation failed.
+ This may signal a truncation attack from an
+ <https:> source.
+ \retval #OP_EFAULT An internal memory allocation failed.
+ \retval #OP_EIMPL An unseekable stream encountered a new link that
+ used a feature that is not implemented, such as
+ an unsupported channel family.
+ \retval #OP_EINVAL The stream was only partially open.
+ \retval #OP_ENOTFORMAT An unseekable stream encountered a new link that
+ did not have any logical Opus streams in it.
+ \retval #OP_EBADHEADER An unseekable stream encountered a new link with a
+ required header packet that was not properly
+ formatted, contained illegal values, or was
+ missing altogether.
+ \retval #OP_EVERSION An unseekable stream encountered a new link with
+ an ID header that contained an unrecognized
+ version number.
+ \retval #OP_EBADPACKET Failed to properly decode the next packet.
+ \retval #OP_EBADLINK We failed to find data we had seen before.
+ \retval #OP_EBADTIMESTAMP An unseekable stream encountered a new link with
+ a starting timestamp that failed basic validity
+ checks.*/
+OP_WARN_UNUSED_RESULT int op_read_float(OggOpusFile *_of,
+ float *_pcm,int _buf_size,int *_li) OP_ARG_NONNULL(1);
+
+/**Reads more samples from the stream and downmixes to stereo, if necessary.
+ This function is intended for simple players that want a uniform output
+ format, even if the channel count changes between links in a chained
+ stream.
+ \note \a _buf_size indicates the total number of values that can be stored
+ in \a _pcm, while the return value is the number of samples <em>per
+ channel</em>, even though the channel count is known, for consistency with
+ op_read().
+ \param _of The \c OggOpusFile from which to read.
+ \param[out] _pcm A buffer in which to store the output PCM samples, as
+ signed native-endian 16-bit values at 48&nbsp;kHz
+ with a nominal range of <code>[-32768,32767)</code>.
+ The left and right channels are interleaved in the
+ buffer.
+ This must have room for at least \a _buf_size values.
+ \param _buf_size The number of values that can be stored in \a _pcm.
+ It is recommended that this be large enough for at
+ least 120 ms of data at 48 kHz per channel (11520
+ values total).
+ Smaller buffers will simply return less data, possibly
+ consuming more memory to buffer the data internally.
+ If less than \a _buf_size values are returned,
+ <tt>libopusfile</tt> makes no guarantee that the
+ remaining data in \a _pcm will be unmodified.
+ \return The number of samples read per channel on success, or a negative
+ value on failure.
+ The number of samples returned may be 0 if the buffer was too small
+ to store even a single sample for both channels, or if end-of-file
+ was reached.
+ The list of possible failure codes follows.
+ Most of them can only be returned by unseekable, chained streams
+ that encounter a new link.
+ \retval #OP_HOLE There was a hole in the data, and some samples
+ may have been skipped.
+ Call this function again to continue decoding
+ past the hole.
+ \retval #OP_EREAD An underlying read operation failed.
+ This may signal a truncation attack from an
+ <https:> source.
+ \retval #OP_EFAULT An internal memory allocation failed.
+ \retval #OP_EIMPL An unseekable stream encountered a new link that
+ used a feature that is not implemented, such as
+ an unsupported channel family.
+ \retval #OP_EINVAL The stream was only partially open.
+ \retval #OP_ENOTFORMAT An unseekable stream encountered a new link that
+ did not have any logical Opus streams in it.
+ \retval #OP_EBADHEADER An unseekable stream encountered a new link with a
+ required header packet that was not properly
+ formatted, contained illegal values, or was
+ missing altogether.
+ \retval #OP_EVERSION An unseekable stream encountered a new link with
+ an ID header that contained an unrecognized
+ version number.
+ \retval #OP_EBADPACKET Failed to properly decode the next packet.
+ \retval #OP_EBADLINK We failed to find data we had seen before.
+ \retval #OP_EBADTIMESTAMP An unseekable stream encountered a new link with
+ a starting timestamp that failed basic validity
+ checks.*/
+OP_WARN_UNUSED_RESULT int op_read_stereo(OggOpusFile *_of,
+ opus_int16 *_pcm,int _buf_size) OP_ARG_NONNULL(1);
+
+/**Reads more samples from the stream and downmixes to stereo, if necessary.
+ This function is intended for simple players that want a uniform output
+ format, even if the channel count changes between links in a chained
+ stream.
+ \note \a _buf_size indicates the total number of values that can be stored
+ in \a _pcm, while the return value is the number of samples <em>per
+ channel</em>, even though the channel count is known, for consistency with
+ op_read_float().
+ \param _of The \c OggOpusFile from which to read.
+ \param[out] _pcm A buffer in which to store the output PCM samples, as
+ signed floats at 48&nbsp;kHz with a nominal range of
+ <code>[-1.0,1.0]</code>.
+ The left and right channels are interleaved in the
+ buffer.
+ This must have room for at least \a _buf_size values.
+ \param _buf_size The number of values that can be stored in \a _pcm.
+ It is recommended that this be large enough for at
+ least 120 ms of data at 48 kHz per channel (11520
+ values total).
+ Smaller buffers will simply return less data, possibly
+ consuming more memory to buffer the data internally.
+ If less than \a _buf_size values are returned,
+ <tt>libopusfile</tt> makes no guarantee that the
+ remaining data in \a _pcm will be unmodified.
+ \return The number of samples read per channel on success, or a negative
+ value on failure.
+ The number of samples returned may be 0 if the buffer was too small
+ to store even a single sample for both channels, or if end-of-file
+ was reached.
+ The list of possible failure codes follows.
+ Most of them can only be returned by unseekable, chained streams
+ that encounter a new link.
+ \retval #OP_HOLE There was a hole in the data, and some samples
+ may have been skipped.
+ Call this function again to continue decoding
+ past the hole.
+ \retval #OP_EREAD An underlying read operation failed.
+ This may signal a truncation attack from an
+ <https:> source.
+ \retval #OP_EFAULT An internal memory allocation failed.
+ \retval #OP_EIMPL An unseekable stream encountered a new link that
+ used a feature that is not implemented, such as
+ an unsupported channel family.
+ \retval #OP_EINVAL The stream was only partially open.
+ \retval #OP_ENOTFORMAT An unseekable stream encountered a new link that
+ that did not have any logical Opus streams in it.
+ \retval #OP_EBADHEADER An unseekable stream encountered a new link with a
+ required header packet that was not properly
+ formatted, contained illegal values, or was
+ missing altogether.
+ \retval #OP_EVERSION An unseekable stream encountered a new link with
+ an ID header that contained an unrecognized
+ version number.
+ \retval #OP_EBADPACKET Failed to properly decode the next packet.
+ \retval #OP_EBADLINK We failed to find data we had seen before.
+ \retval #OP_EBADTIMESTAMP An unseekable stream encountered a new link with
+ a starting timestamp that failed basic validity
+ checks.*/
+OP_WARN_UNUSED_RESULT int op_read_float_stereo(OggOpusFile *_of,
+ float *_pcm,int _buf_size) OP_ARG_NONNULL(1);
+
+/*@}*/
+/*@}*/
+
+# if OP_GNUC_PREREQ(4,0)
+# pragma GCC visibility pop
+# endif
+
+# if defined(__cplusplus)
+}
+# endif
+
+#endif
diff --git a/drivers/opus/repacketizer.c b/drivers/opus/repacketizer.c
new file mode 100644
index 0000000000..eb0c0c7376
--- /dev/null
+++ b/drivers/opus/repacketizer.c
@@ -0,0 +1,345 @@
+/* Copyright (c) 2011 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/opus.h"
+#include "opus/opus_private.h"
+#include "opus/celt/os_support.h"
+
+
+int opus_repacketizer_get_size(void)
+{
+ return sizeof(OpusRepacketizer);
+}
+
+OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp)
+{
+ rp->nb_frames = 0;
+ return rp;
+}
+
+OpusRepacketizer *opus_repacketizer_create(void)
+{
+ OpusRepacketizer *rp;
+ rp=(OpusRepacketizer *)opus_alloc(opus_repacketizer_get_size());
+ if(rp==NULL)return NULL;
+ return opus_repacketizer_init(rp);
+}
+
+void opus_repacketizer_destroy(OpusRepacketizer *rp)
+{
+ opus_free(rp);
+}
+
+static int opus_repacketizer_cat_impl(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len, int self_delimited)
+{
+ unsigned char tmp_toc;
+ int curr_nb_frames,ret;
+ /* Set of check ToC */
+ if (len<1) return OPUS_INVALID_PACKET;
+ if (rp->nb_frames == 0)
+ {
+ rp->toc = data[0];
+ rp->framesize = opus_packet_get_samples_per_frame(data, 8000);
+ } else if ((rp->toc&0xFC) != (data[0]&0xFC))
+ {
+ /*fprintf(stderr, "toc mismatch: 0x%x vs 0x%x\n", rp->toc, data[0]);*/
+ return OPUS_INVALID_PACKET;
+ }
+ curr_nb_frames = opus_packet_get_nb_frames(data, len);
+ if(curr_nb_frames<1) return OPUS_INVALID_PACKET;
+
+ /* Check the 120 ms maximum packet size */
+ if ((curr_nb_frames+rp->nb_frames)*rp->framesize > 960)
+ {
+ return OPUS_INVALID_PACKET;
+ }
+
+ ret=opus_packet_parse_impl(data, len, self_delimited, &tmp_toc, &rp->frames[rp->nb_frames], &rp->len[rp->nb_frames], NULL, NULL);
+ if(ret<1)return ret;
+
+ rp->nb_frames += curr_nb_frames;
+ return OPUS_OK;
+}
+
+int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len)
+{
+ return opus_repacketizer_cat_impl(rp, data, len, 0);
+}
+
+int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp)
+{
+ return rp->nb_frames;
+}
+
+opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end,
+ unsigned char *data, opus_int32 maxlen, int self_delimited, int pad)
+{
+ int i, count;
+ opus_int32 tot_size;
+ opus_int16 *len;
+ const unsigned char **frames;
+ unsigned char * ptr;
+
+ if (begin<0 || begin>=end || end>rp->nb_frames)
+ {
+ /*fprintf(stderr, "%d %d %d\n", begin, end, rp->nb_frames);*/
+ return OPUS_BAD_ARG;
+ }
+ count = end-begin;
+
+ len = rp->len+begin;
+ frames = rp->frames+begin;
+ if (self_delimited)
+ tot_size = 1 + (len[count-1]>=252);
+ else
+ tot_size = 0;
+
+ ptr = data;
+ if (count==1)
+ {
+ /* Code 0 */
+ tot_size += len[0]+1;
+ if (tot_size > maxlen)
+ return OPUS_BUFFER_TOO_SMALL;
+ *ptr++ = rp->toc&0xFC;
+ } else if (count==2)
+ {
+ if (len[1] == len[0])
+ {
+ /* Code 1 */
+ tot_size += 2*len[0]+1;
+ if (tot_size > maxlen)
+ return OPUS_BUFFER_TOO_SMALL;
+ *ptr++ = (rp->toc&0xFC) | 0x1;
+ } else {
+ /* Code 2 */
+ tot_size += len[0]+len[1]+2+(len[0]>=252);
+ if (tot_size > maxlen)
+ return OPUS_BUFFER_TOO_SMALL;
+ *ptr++ = (rp->toc&0xFC) | 0x2;
+ ptr += encode_size(len[0], ptr);
+ }
+ }
+ if (count > 2 || (pad && tot_size < maxlen))
+ {
+ /* Code 3 */
+ int vbr;
+ int pad_amount=0;
+
+ /* Restart the process for the padding case */
+ ptr = data;
+ if (self_delimited)
+ tot_size = 1 + (len[count-1]>=252);
+ else
+ tot_size = 0;
+ vbr = 0;
+ for (i=1;i<count;i++)
+ {
+ if (len[i] != len[0])
+ {
+ vbr=1;
+ break;
+ }
+ }
+ if (vbr)
+ {
+ tot_size += 2;
+ for (i=0;i<count-1;i++)
+ tot_size += 1 + (len[i]>=252) + len[i];
+ tot_size += len[count-1];
+
+ if (tot_size > maxlen)
+ return OPUS_BUFFER_TOO_SMALL;
+ *ptr++ = (rp->toc&0xFC) | 0x3;
+ *ptr++ = count | 0x80;
+ } else {
+ tot_size += count*len[0]+2;
+ if (tot_size > maxlen)
+ return OPUS_BUFFER_TOO_SMALL;
+ *ptr++ = (rp->toc&0xFC) | 0x3;
+ *ptr++ = count;
+ }
+ pad_amount = pad ? (maxlen-tot_size) : 0;
+ if (pad_amount != 0)
+ {
+ int nb_255s;
+ data[1] |= 0x40;
+ nb_255s = (pad_amount-1)/255;
+ for (i=0;i<nb_255s;i++)
+ *ptr++ = 255;
+ *ptr++ = pad_amount-255*nb_255s-1;
+ tot_size += pad_amount;
+ }
+ if (vbr)
+ {
+ for (i=0;i<count-1;i++)
+ ptr += encode_size(len[i], ptr);
+ }
+ }
+ if (self_delimited) {
+ int sdlen = encode_size(len[count-1], ptr);
+ ptr += sdlen;
+ }
+ /* Copy the actual data */
+ for (i=0;i<count;i++)
+ {
+ /* Using OPUS_MOVE() instead of OPUS_COPY() in case we're doing in-place
+ padding from opus_packet_pad or opus_packet_unpad(). */
+ celt_assert(frames[i] + len[i] <= data || ptr <= frames[i]);
+ OPUS_MOVE(ptr, frames[i], len[i]);
+ ptr += len[i];
+ }
+ if (pad)
+ {
+ for (i=ptr-data;i<maxlen;i++)
+ data[i] = 0;
+ }
+ return tot_size;
+}
+
+opus_int32 opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen)
+{
+ return opus_repacketizer_out_range_impl(rp, begin, end, data, maxlen, 0, 0);
+}
+
+opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus_int32 maxlen)
+{
+ return opus_repacketizer_out_range_impl(rp, 0, rp->nb_frames, data, maxlen, 0, 0);
+}
+
+int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len)
+{
+ OpusRepacketizer rp;
+ opus_int32 ret;
+ if (len < 1)
+ return OPUS_BAD_ARG;
+ if (len==new_len)
+ return OPUS_OK;
+ else if (len > new_len)
+ return OPUS_BAD_ARG;
+ opus_repacketizer_init(&rp);
+ /* Moving payload to the end of the packet so we can do in-place padding */
+ OPUS_MOVE(data+new_len-len, data, len);
+ opus_repacketizer_cat(&rp, data+new_len-len, len);
+ ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, new_len, 0, 1);
+ if (ret > 0)
+ return OPUS_OK;
+ else
+ return ret;
+}
+
+opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len)
+{
+ OpusRepacketizer rp;
+ opus_int32 ret;
+ if (len < 1)
+ return OPUS_BAD_ARG;
+ opus_repacketizer_init(&rp);
+ ret = opus_repacketizer_cat(&rp, data, len);
+ if (ret < 0)
+ return ret;
+ ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, len, 0, 0);
+ celt_assert(ret > 0 && ret <= len);
+ return ret;
+}
+
+int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len, int nb_streams)
+{
+ int s;
+ int count;
+ unsigned char toc;
+ opus_int16 size[48];
+ opus_int32 packet_offset;
+ opus_int32 amount;
+
+ if (len < 1)
+ return OPUS_BAD_ARG;
+ if (len==new_len)
+ return OPUS_OK;
+ else if (len > new_len)
+ return OPUS_BAD_ARG;
+ amount = new_len - len;
+ /* Seek to last stream */
+ for (s=0;s<nb_streams-1;s++)
+ {
+ if (len<=0)
+ return OPUS_INVALID_PACKET;
+ count = opus_packet_parse_impl(data, len, 1, &toc, NULL,
+ size, NULL, &packet_offset);
+ if (count<0)
+ return count;
+ data += packet_offset;
+ len -= packet_offset;
+ }
+ return opus_packet_pad(data, len, len+amount);
+}
+
+opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, int nb_streams)
+{
+ int s;
+ unsigned char toc;
+ opus_int16 size[48];
+ opus_int32 packet_offset;
+ OpusRepacketizer rp;
+ unsigned char *dst;
+ opus_int32 dst_len;
+
+ if (len < 1)
+ return OPUS_BAD_ARG;
+ dst = data;
+ dst_len = 0;
+ /* Unpad all frames */
+ for (s=0;s<nb_streams;s++)
+ {
+ opus_int32 ret;
+ int self_delimited = s!=nb_streams-1;
+ if (len<=0)
+ return OPUS_INVALID_PACKET;
+ opus_repacketizer_init(&rp);
+ ret = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL,
+ size, NULL, &packet_offset);
+ if (ret<0)
+ return ret;
+ ret = opus_repacketizer_cat_impl(&rp, data, packet_offset, self_delimited);
+ if (ret < 0)
+ return ret;
+ ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, dst, len, self_delimited, 0);
+ if (ret < 0)
+ return ret;
+ else
+ dst_len += ret;
+ dst += ret;
+ data += packet_offset;
+ len -= packet_offset;
+ }
+ return dst_len;
+}
+
diff --git a/drivers/opus/repacketizer_demo.c b/drivers/opus/repacketizer_demo.c
new file mode 100644
index 0000000000..5df4f26958
--- /dev/null
+++ b/drivers/opus/repacketizer_demo.c
@@ -0,0 +1,217 @@
+/* Copyright (c) 2011 Xiph.Org Foundation
+ Written by Jean-Marc Valin */
+/*
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/opus.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define MAX_PACKETOUT 32000
+
+void usage(char *argv0)
+{
+ fprintf(stderr, "usage: %s [options] input_file output_file\n", argv0);
+}
+
+static void int_to_char(opus_uint32 i, unsigned char ch[4])
+{
+ ch[0] = i>>24;
+ ch[1] = (i>>16)&0xFF;
+ ch[2] = (i>>8)&0xFF;
+ ch[3] = i&0xFF;
+}
+
+static opus_uint32 char_to_int(unsigned char ch[4])
+{
+ return ((opus_uint32)ch[0]<<24) | ((opus_uint32)ch[1]<<16)
+ | ((opus_uint32)ch[2]<< 8) | (opus_uint32)ch[3];
+}
+
+int main(int argc, char *argv[])
+{
+ int i, eof=0;
+ FILE *fin, *fout;
+ unsigned char packets[48][1500];
+ int len[48];
+ int rng[48];
+ OpusRepacketizer *rp;
+ unsigned char output_packet[MAX_PACKETOUT];
+ int merge = 1, split=0;
+
+ if (argc < 3)
+ {
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+ for (i=1;i<argc-2;i++)
+ {
+ if (strcmp(argv[i], "-merge")==0)
+ {
+ merge = atoi(argv[i+1]);
+ if(merge<1)
+ {
+ fprintf(stderr, "-merge parameter must be at least 1.\n");
+ return EXIT_FAILURE;
+ }
+ if(merge>48)
+ {
+ fprintf(stderr, "-merge parameter must be less than 48.\n");
+ return EXIT_FAILURE;
+ }
+ i++;
+ } else if (strcmp(argv[i], "-split")==0)
+ split = 1;
+ else
+ {
+ fprintf(stderr, "Unknown option: %s\n", argv[i]);
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+ }
+ fin = fopen(argv[argc-2], "r");
+ if(fin==NULL)
+ {
+ fprintf(stderr, "Error opening input file: %s\n", argv[argc-2]);
+ return EXIT_FAILURE;
+ }
+ fout = fopen(argv[argc-1], "w");
+ if(fout==NULL)
+ {
+ fprintf(stderr, "Error opening output file: %s\n", argv[argc-1]);
+ fclose(fin);
+ return EXIT_FAILURE;
+ }
+
+ rp = opus_repacketizer_create();
+ while (!eof)
+ {
+ int err;
+ int nb_packets=merge;
+ opus_repacketizer_init(rp);
+ for (i=0;i<nb_packets;i++)
+ {
+ unsigned char ch[4];
+ err = fread(ch, 1, 4, fin);
+ len[i] = char_to_int(ch);
+ /*fprintf(stderr, "in len = %d\n", len[i]);*/
+ if (len[i]>1500 || len[i]<0)
+ {
+ if (feof(fin))
+ {
+ eof = 1;
+ } else {
+ fprintf(stderr, "Invalid payload length\n");
+ fclose(fin);
+ fclose(fout);
+ return EXIT_FAILURE;
+ }
+ break;
+ }
+ err = fread(ch, 1, 4, fin);
+ rng[i] = char_to_int(ch);
+ err = fread(packets[i], 1, len[i], fin);
+ if (feof(fin))
+ {
+ eof = 1;
+ break;
+ }
+ err = opus_repacketizer_cat(rp, packets[i], len[i]);
+ if (err!=OPUS_OK)
+ {
+ fprintf(stderr, "opus_repacketizer_cat() failed: %s\n", opus_strerror(err));
+ break;
+ }
+ }
+ nb_packets = i;
+
+ if (eof)
+ break;
+
+ if (!split)
+ {
+ err = opus_repacketizer_out(rp, output_packet, MAX_PACKETOUT);
+ if (err>0) {
+ unsigned char int_field[4];
+ int_to_char(err, int_field);
+ if(fwrite(int_field, 1, 4, fout)!=4){
+ fprintf(stderr, "Error writing.\n");
+ return EXIT_FAILURE;
+ }
+ int_to_char(rng[nb_packets-1], int_field);
+ if (fwrite(int_field, 1, 4, fout)!=4) {
+ fprintf(stderr, "Error writing.\n");
+ return EXIT_FAILURE;
+ }
+ if (fwrite(output_packet, 1, err, fout)!=(unsigned)err) {
+ fprintf(stderr, "Error writing.\n");
+ return EXIT_FAILURE;
+ }
+ /*fprintf(stderr, "out len = %d\n", err);*/
+ } else {
+ fprintf(stderr, "opus_repacketizer_out() failed: %s\n", opus_strerror(err));
+ }
+ } else {
+ int nb_frames = opus_repacketizer_get_nb_frames(rp);
+ for (i=0;i<nb_frames;i++)
+ {
+ err = opus_repacketizer_out_range(rp, i, i+1, output_packet, MAX_PACKETOUT);
+ if (err>0) {
+ unsigned char int_field[4];
+ int_to_char(err, int_field);
+ if (fwrite(int_field, 1, 4, fout)!=4) {
+ fprintf(stderr, "Error writing.\n");
+ return EXIT_FAILURE;
+ }
+ if (i==nb_frames-1)
+ int_to_char(rng[nb_packets-1], int_field);
+ else
+ int_to_char(0, int_field);
+ if (fwrite(int_field, 1, 4, fout)!=4) {
+ fprintf(stderr, "Error writing.\n");
+ return EXIT_FAILURE;
+ }
+ if (fwrite(output_packet, 1, err, fout)!=(unsigned)err) {
+ fprintf(stderr, "Error writing.\n");
+ return EXIT_FAILURE;
+ }
+ /*fprintf(stderr, "out len = %d\n", err);*/
+ } else {
+ fprintf(stderr, "opus_repacketizer_out() failed: %s\n", opus_strerror(err));
+ }
+
+ }
+ }
+ }
+
+ fclose(fin);
+ fclose(fout);
+ return EXIT_SUCCESS;
+}
diff --git a/drivers/opus/silk/A2NLSF.c b/drivers/opus/silk/A2NLSF.c
new file mode 100644
index 0000000000..18b0e3092d
--- /dev/null
+++ b/drivers/opus/silk/A2NLSF.c
@@ -0,0 +1,252 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+/* Conversion between prediction filter coefficients and NLSFs */
+/* Requires the order to be an even number */
+/* A piecewise linear approximation maps LSF <-> cos(LSF) */
+/* Therefore the result is not accurate NLSFs, but the two */
+/* functions are accurate inverses of each other */
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/SigProc_FIX.h"
+#include "opus/silk/tables.h"
+
+/* Number of binary divisions, when not in low complexity mode */
+#define BIN_DIV_STEPS_A2NLSF_FIX 3 /* must be no higher than 16 - log2( LSF_COS_TAB_SZ_FIX ) */
+#define MAX_ITERATIONS_A2NLSF_FIX 30
+
+/* Helper function for A2NLSF(..) */
+/* Transforms polynomials from cos(n*f) to cos(f)^n */
+static OPUS_INLINE void silk_A2NLSF_trans_poly(
+ opus_int32 *p, /* I/O Polynomial */
+ const opus_int dd /* I Polynomial order (= filter order / 2 ) */
+)
+{
+ opus_int k, n;
+
+ for( k = 2; k <= dd; k++ ) {
+ for( n = dd; n > k; n-- ) {
+ p[ n - 2 ] -= p[ n ];
+ }
+ p[ k - 2 ] -= silk_LSHIFT( p[ k ], 1 );
+ }
+}
+/* Helper function for A2NLSF(..) */
+/* Polynomial evaluation */
+static OPUS_INLINE opus_int32 silk_A2NLSF_eval_poly( /* return the polynomial evaluation, in Q16 */
+ opus_int32 *p, /* I Polynomial, Q16 */
+ const opus_int32 x, /* I Evaluation point, Q12 */
+ const opus_int dd /* I Order */
+)
+{
+ opus_int n;
+ opus_int32 x_Q16, y32;
+
+ y32 = p[ dd ]; /* Q16 */
+ x_Q16 = silk_LSHIFT( x, 4 );
+ for( n = dd - 1; n >= 0; n-- ) {
+ y32 = silk_SMLAWW( p[ n ], y32, x_Q16 ); /* Q16 */
+ }
+ return y32;
+}
+
+static OPUS_INLINE void silk_A2NLSF_init(
+ const opus_int32 *a_Q16,
+ opus_int32 *P,
+ opus_int32 *Q,
+ const opus_int dd
+)
+{
+ opus_int k;
+
+ /* Convert filter coefs to even and odd polynomials */
+ P[dd] = silk_LSHIFT( 1, 16 );
+ Q[dd] = silk_LSHIFT( 1, 16 );
+ for( k = 0; k < dd; k++ ) {
+ P[ k ] = -a_Q16[ dd - k - 1 ] - a_Q16[ dd + k ]; /* Q16 */
+ Q[ k ] = -a_Q16[ dd - k - 1 ] + a_Q16[ dd + k ]; /* Q16 */
+ }
+
+ /* Divide out zeros as we have that for even filter orders, */
+ /* z = 1 is always a root in Q, and */
+ /* z = -1 is always a root in P */
+ for( k = dd; k > 0; k-- ) {
+ P[ k - 1 ] -= P[ k ];
+ Q[ k - 1 ] += Q[ k ];
+ }
+
+ /* Transform polynomials from cos(n*f) to cos(f)^n */
+ silk_A2NLSF_trans_poly( P, dd );
+ silk_A2NLSF_trans_poly( Q, dd );
+}
+
+/* Compute Normalized Line Spectral Frequencies (NLSFs) from whitening filter coefficients */
+/* If not all roots are found, the a_Q16 coefficients are bandwidth expanded until convergence. */
+void silk_A2NLSF(
+ opus_int16 *NLSF, /* O Normalized Line Spectral Frequencies in Q15 (0..2^15-1) [d] */
+ opus_int32 *a_Q16, /* I/O Monic whitening filter coefficients in Q16 [d] */
+ const opus_int d /* I Filter order (must be even) */
+)
+{
+ opus_int i, k, m, dd, root_ix, ffrac;
+ opus_int32 xlo, xhi, xmid;
+ opus_int32 ylo, yhi, ymid, thr;
+ opus_int32 nom, den;
+ opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ];
+ opus_int32 Q[ SILK_MAX_ORDER_LPC / 2 + 1 ];
+ opus_int32 *PQ[ 2 ];
+ opus_int32 *p;
+
+ /* Store pointers to array */
+ PQ[ 0 ] = P;
+ PQ[ 1 ] = Q;
+
+ dd = silk_RSHIFT( d, 1 );
+
+ silk_A2NLSF_init( a_Q16, P, Q, dd );
+
+ /* Find roots, alternating between P and Q */
+ p = P; /* Pointer to polynomial */
+
+ xlo = silk_LSFCosTab_FIX_Q12[ 0 ]; /* Q12*/
+ ylo = silk_A2NLSF_eval_poly( p, xlo, dd );
+
+ if( ylo < 0 ) {
+ /* Set the first NLSF to zero and move on to the next */
+ NLSF[ 0 ] = 0;
+ p = Q; /* Pointer to polynomial */
+ ylo = silk_A2NLSF_eval_poly( p, xlo, dd );
+ root_ix = 1; /* Index of current root */
+ } else {
+ root_ix = 0; /* Index of current root */
+ }
+ k = 1; /* Loop counter */
+ i = 0; /* Counter for bandwidth expansions applied */
+ thr = 0;
+ while( 1 ) {
+ /* Evaluate polynomial */
+ xhi = silk_LSFCosTab_FIX_Q12[ k ]; /* Q12 */
+ yhi = silk_A2NLSF_eval_poly( p, xhi, dd );
+
+ /* Detect zero crossing */
+ if( ( ylo <= 0 && yhi >= thr ) || ( ylo >= 0 && yhi <= -thr ) ) {
+ if( yhi == 0 ) {
+ /* If the root lies exactly at the end of the current */
+ /* interval, look for the next root in the next interval */
+ thr = 1;
+ } else {
+ thr = 0;
+ }
+ /* Binary division */
+ ffrac = -256;
+ for( m = 0; m < BIN_DIV_STEPS_A2NLSF_FIX; m++ ) {
+ /* Evaluate polynomial */
+ xmid = silk_RSHIFT_ROUND( xlo + xhi, 1 );
+ ymid = silk_A2NLSF_eval_poly( p, xmid, dd );
+
+ /* Detect zero crossing */
+ if( ( ylo <= 0 && ymid >= 0 ) || ( ylo >= 0 && ymid <= 0 ) ) {
+ /* Reduce frequency */
+ xhi = xmid;
+ yhi = ymid;
+ } else {
+ /* Increase frequency */
+ xlo = xmid;
+ ylo = ymid;
+ ffrac = silk_ADD_RSHIFT( ffrac, 128, m );
+ }
+ }
+
+ /* Interpolate */
+ if( silk_abs( ylo ) < 65536 ) {
+ /* Avoid dividing by zero */
+ den = ylo - yhi;
+ nom = silk_LSHIFT( ylo, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) + silk_RSHIFT( den, 1 );
+ if( den != 0 ) {
+ ffrac += silk_DIV32( nom, den );
+ }
+ } else {
+ /* No risk of dividing by zero because abs(ylo - yhi) >= abs(ylo) >= 65536 */
+ ffrac += silk_DIV32( ylo, silk_RSHIFT( ylo - yhi, 8 - BIN_DIV_STEPS_A2NLSF_FIX ) );
+ }
+ NLSF[ root_ix ] = (opus_int16)silk_min_32( silk_LSHIFT( (opus_int32)k, 8 ) + ffrac, silk_int16_MAX );
+
+ silk_assert( NLSF[ root_ix ] >= 0 );
+
+ root_ix++; /* Next root */
+ if( root_ix >= d ) {
+ /* Found all roots */
+ break;
+ }
+ /* Alternate pointer to polynomial */
+ p = PQ[ root_ix & 1 ];
+
+ /* Evaluate polynomial */
+ xlo = silk_LSFCosTab_FIX_Q12[ k - 1 ]; /* Q12*/
+ ylo = silk_LSHIFT( 1 - ( root_ix & 2 ), 12 );
+ } else {
+ /* Increment loop counter */
+ k++;
+ xlo = xhi;
+ ylo = yhi;
+ thr = 0;
+
+ if( k > LSF_COS_TAB_SZ_FIX ) {
+ i++;
+ if( i > MAX_ITERATIONS_A2NLSF_FIX ) {
+ /* Set NLSFs to white spectrum and exit */
+ NLSF[ 0 ] = (opus_int16)silk_DIV32_16( 1 << 15, d + 1 );
+ for( k = 1; k < d; k++ ) {
+ NLSF[ k ] = (opus_int16)silk_SMULBB( k + 1, NLSF[ 0 ] );
+ }
+ return;
+ }
+
+ /* Error: Apply progressively more bandwidth expansion and run again */
+ silk_bwexpander_32( a_Q16, d, 65536 - silk_SMULBB( 10 + i, i ) ); /* 10_Q16 = 0.00015*/
+
+ silk_A2NLSF_init( a_Q16, P, Q, dd );
+ p = P; /* Pointer to polynomial */
+ xlo = silk_LSFCosTab_FIX_Q12[ 0 ]; /* Q12*/
+ ylo = silk_A2NLSF_eval_poly( p, xlo, dd );
+ if( ylo < 0 ) {
+ /* Set the first NLSF to zero and move on to the next */
+ NLSF[ 0 ] = 0;
+ p = Q; /* Pointer to polynomial */
+ ylo = silk_A2NLSF_eval_poly( p, xlo, dd );
+ root_ix = 1; /* Index of current root */
+ } else {
+ root_ix = 0; /* Index of current root */
+ }
+ k = 1; /* Reset loop counter */
+ }
+ }
+ }
+}
diff --git a/drivers/opus/silk/API.h b/drivers/opus/silk/API.h
new file mode 100644
index 0000000000..70f81a0c44
--- /dev/null
+++ b/drivers/opus/silk/API.h
@@ -0,0 +1,133 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_API_H
+#define SILK_API_H
+
+#include "opus/silk/control.h"
+#include "opus/silk/typedef.h"
+#include "opus/silk/errors.h"
+#include "opus/celt/entenc.h"
+#include "opus/celt/entdec.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define SILK_MAX_FRAMES_PER_PACKET 3
+
+/* Struct for TOC (Table of Contents) */
+typedef struct {
+ opus_int VADFlag; /* Voice activity for packet */
+ opus_int VADFlags[ SILK_MAX_FRAMES_PER_PACKET ]; /* Voice activity for each frame in packet */
+ opus_int inbandFECFlag; /* Flag indicating if packet contains in-band FEC */
+} silk_TOC_struct;
+
+/****************************************/
+/* Encoder functions */
+/****************************************/
+
+/***********************************************/
+/* Get size in bytes of the Silk encoder state */
+/***********************************************/
+opus_int silk_Get_Encoder_Size( /* O Returns error code */
+ opus_int *encSizeBytes /* O Number of bytes in SILK encoder state */
+);
+
+/*************************/
+/* Init or reset encoder */
+/*************************/
+opus_int silk_InitEncoder( /* O Returns error code */
+ void *encState, /* I/O State */
+ int arch, /* I Run-time architecture */
+ silk_EncControlStruct *encStatus /* O Encoder Status */
+);
+
+/**************************/
+/* Encode frame with Silk */
+/**************************/
+/* Note: if prefillFlag is set, the input must contain 10 ms of audio, irrespective of what */
+/* encControl->payloadSize_ms is set to */
+opus_int silk_Encode( /* O Returns error code */
+ void *encState, /* I/O State */
+ silk_EncControlStruct *encControl, /* I Control status */
+ const opus_int16 *samplesIn, /* I Speech sample input vector */
+ opus_int nSamplesIn, /* I Number of samples in input vector */
+ ec_enc *psRangeEnc, /* I/O Compressor data structure */
+ opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */
+ const opus_int prefillFlag /* I Flag to indicate prefilling buffers no coding */
+);
+
+/****************************************/
+/* Decoder functions */
+/****************************************/
+
+/***********************************************/
+/* Get size in bytes of the Silk decoder state */
+/***********************************************/
+opus_int silk_Get_Decoder_Size( /* O Returns error code */
+ opus_int *decSizeBytes /* O Number of bytes in SILK decoder state */
+);
+
+/*************************/
+/* Init or Reset decoder */
+/*************************/
+opus_int silk_InitDecoder( /* O Returns error code */
+ void *decState /* I/O State */
+);
+
+/******************/
+/* Decode a frame */
+/******************/
+opus_int silk_Decode( /* O Returns error code */
+ void* decState, /* I/O State */
+ silk_DecControlStruct* decControl, /* I/O Control Structure */
+ opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */
+ opus_int newPacketFlag, /* I Indicates first decoder call for this packet */
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int16 *samplesOut, /* O Decoded output speech vector */
+ opus_int32 *nSamplesOut /* O Number of samples decoded */
+);
+
+#if 0
+/**************************************/
+/* Get table of contents for a packet */
+/**************************************/
+opus_int silk_get_TOC(
+ const opus_uint8 *payload, /* I Payload data */
+ const opus_int nBytesIn, /* I Number of input bytes */
+ const opus_int nFramesPerPayload, /* I Number of SILK frames per payload */
+ silk_TOC_struct *Silk_TOC /* O Type of content */
+);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/opus/silk/CNG.c b/drivers/opus/silk/CNG.c
new file mode 100644
index 0000000000..253ae7db4c
--- /dev/null
+++ b/drivers/opus/silk/CNG.c
@@ -0,0 +1,172 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+#include "opus/celt/stack_alloc.h"
+
+/* Generates excitation for CNG LPC synthesis */
+static OPUS_INLINE void silk_CNG_exc(
+ opus_int32 residual_Q10[], /* O CNG residual signal Q10 */
+ opus_int32 exc_buf_Q14[], /* I Random samples buffer Q10 */
+ opus_int32 Gain_Q16, /* I Gain to apply */
+ opus_int length, /* I Length */
+ opus_int32 *rand_seed /* I/O Seed to random index generator */
+)
+{
+ opus_int32 seed;
+ opus_int i, idx, exc_mask;
+
+ exc_mask = CNG_BUF_MASK_MAX;
+ while( exc_mask > length ) {
+ exc_mask = silk_RSHIFT( exc_mask, 1 );
+ }
+
+ seed = *rand_seed;
+ for( i = 0; i < length; i++ ) {
+ seed = silk_RAND( seed );
+ idx = (opus_int)( silk_RSHIFT( seed, 24 ) & exc_mask );
+ silk_assert( idx >= 0 );
+ silk_assert( idx <= CNG_BUF_MASK_MAX );
+ residual_Q10[ i ] = (opus_int16)silk_SAT16( silk_SMULWW( exc_buf_Q14[ idx ], Gain_Q16 >> 4 ) );
+ }
+ *rand_seed = seed;
+}
+
+void silk_CNG_Reset(
+ silk_decoder_state *psDec /* I/O Decoder state */
+)
+{
+ opus_int i, NLSF_step_Q15, NLSF_acc_Q15;
+
+ NLSF_step_Q15 = silk_DIV32_16( silk_int16_MAX, psDec->LPC_order + 1 );
+ NLSF_acc_Q15 = 0;
+ for( i = 0; i < psDec->LPC_order; i++ ) {
+ NLSF_acc_Q15 += NLSF_step_Q15;
+ psDec->sCNG.CNG_smth_NLSF_Q15[ i ] = NLSF_acc_Q15;
+ }
+ psDec->sCNG.CNG_smth_Gain_Q16 = 0;
+ psDec->sCNG.rand_seed = 3176576;
+}
+
+/* Updates CNG estimate, and applies the CNG when packet was lost */
+void silk_CNG(
+ silk_decoder_state *psDec, /* I/O Decoder state */
+ silk_decoder_control *psDecCtrl, /* I/O Decoder control */
+ opus_int16 frame[], /* I/O Signal */
+ opus_int length /* I Length of residual */
+)
+{
+ opus_int i, subfr;
+ opus_int32 sum_Q6, max_Gain_Q16;
+ opus_int16 A_Q12[ MAX_LPC_ORDER ];
+ silk_CNG_struct *psCNG = &psDec->sCNG;
+ SAVE_STACK;
+
+ if( psDec->fs_kHz != psCNG->fs_kHz ) {
+ /* Reset state */
+ silk_CNG_Reset( psDec );
+
+ psCNG->fs_kHz = psDec->fs_kHz;
+ }
+ if( psDec->lossCnt == 0 && psDec->prevSignalType == TYPE_NO_VOICE_ACTIVITY ) {
+ /* Update CNG parameters */
+
+ /* Smoothing of LSF's */
+ for( i = 0; i < psDec->LPC_order; i++ ) {
+ psCNG->CNG_smth_NLSF_Q15[ i ] += silk_SMULWB( (opus_int32)psDec->prevNLSF_Q15[ i ] - (opus_int32)psCNG->CNG_smth_NLSF_Q15[ i ], CNG_NLSF_SMTH_Q16 );
+ }
+ /* Find the subframe with the highest gain */
+ max_Gain_Q16 = 0;
+ subfr = 0;
+ for( i = 0; i < psDec->nb_subfr; i++ ) {
+ if( psDecCtrl->Gains_Q16[ i ] > max_Gain_Q16 ) {
+ max_Gain_Q16 = psDecCtrl->Gains_Q16[ i ];
+ subfr = i;
+ }
+ }
+ /* Update CNG excitation buffer with excitation from this subframe */
+ silk_memmove( &psCNG->CNG_exc_buf_Q14[ psDec->subfr_length ], psCNG->CNG_exc_buf_Q14, ( psDec->nb_subfr - 1 ) * psDec->subfr_length * sizeof( opus_int32 ) );
+ silk_memcpy( psCNG->CNG_exc_buf_Q14, &psDec->exc_Q14[ subfr * psDec->subfr_length ], psDec->subfr_length * sizeof( opus_int32 ) );
+
+ /* Smooth gains */
+ for( i = 0; i < psDec->nb_subfr; i++ ) {
+ psCNG->CNG_smth_Gain_Q16 += silk_SMULWB( psDecCtrl->Gains_Q16[ i ] - psCNG->CNG_smth_Gain_Q16, CNG_GAIN_SMTH_Q16 );
+ }
+ }
+
+ /* Add CNG when packet is lost or during DTX */
+ if( psDec->lossCnt ) {
+ VARDECL( opus_int32, CNG_sig_Q10 );
+
+ ALLOC( CNG_sig_Q10, length + MAX_LPC_ORDER, opus_int32 );
+
+ /* Generate CNG excitation */
+ silk_CNG_exc( CNG_sig_Q10 + MAX_LPC_ORDER, psCNG->CNG_exc_buf_Q14, psCNG->CNG_smth_Gain_Q16, length, &psCNG->rand_seed );
+
+ /* Convert CNG NLSF to filter representation */
+ silk_NLSF2A( A_Q12, psCNG->CNG_smth_NLSF_Q15, psDec->LPC_order );
+
+ /* Generate CNG signal, by synthesis filtering */
+ silk_memcpy( CNG_sig_Q10, psCNG->CNG_synth_state, MAX_LPC_ORDER * sizeof( opus_int32 ) );
+ for( i = 0; i < length; i++ ) {
+ silk_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 );
+ /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+ sum_Q6 = silk_RSHIFT( psDec->LPC_order, 1 );
+ sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] );
+ sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] );
+ sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] );
+ sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] );
+ sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] );
+ sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] );
+ sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] );
+ sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] );
+ sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] );
+ sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] );
+ if( psDec->LPC_order == 16 ) {
+ sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 11 ], A_Q12[ 10 ] );
+ sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 12 ], A_Q12[ 11 ] );
+ sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 13 ], A_Q12[ 12 ] );
+ sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 14 ], A_Q12[ 13 ] );
+ sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 15 ], A_Q12[ 14 ] );
+ sum_Q6 = silk_SMLAWB( sum_Q6, CNG_sig_Q10[ MAX_LPC_ORDER + i - 16 ], A_Q12[ 15 ] );
+ }
+
+ /* Update states */
+ CNG_sig_Q10[ MAX_LPC_ORDER + i ] = silk_ADD_LSHIFT( CNG_sig_Q10[ MAX_LPC_ORDER + i ], sum_Q6, 4 );
+
+ frame[ i ] = silk_ADD_SAT16( frame[ i ], silk_RSHIFT_ROUND( sum_Q6, 6 ) );
+ }
+ silk_memcpy( psCNG->CNG_synth_state, &CNG_sig_Q10[ length ], MAX_LPC_ORDER * sizeof( opus_int32 ) );
+ } else {
+ silk_memset( psCNG->CNG_synth_state, 0, psDec->LPC_order * sizeof( opus_int32 ) );
+ }
+ RESTORE_STACK;
+}
diff --git a/drivers/opus/silk/HP_variable_cutoff.c b/drivers/opus/silk/HP_variable_cutoff.c
new file mode 100644
index 0000000000..9da2032869
--- /dev/null
+++ b/drivers/opus/silk/HP_variable_cutoff.c
@@ -0,0 +1,77 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+#ifdef OPUS_FIXED_POINT
+#include "opus/silk/fixed/main_FIX.h"
+#else
+#include "opus/silk/float/main_FLP.h"
+#endif
+#include "opus/silk/tuning_parameters.h"
+
+/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */
+void silk_HP_variable_cutoff(
+ silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */
+)
+{
+ opus_int quality_Q15;
+ opus_int32 pitch_freq_Hz_Q16, pitch_freq_log_Q7, delta_freq_Q7;
+ silk_encoder_state *psEncC1 = &state_Fxx[ 0 ].sCmn;
+
+ /* Adaptive cutoff frequency: estimate low end of pitch frequency range */
+ if( psEncC1->prevSignalType == TYPE_VOICED ) {
+ /* difference, in log domain */
+ pitch_freq_Hz_Q16 = silk_DIV32_16( silk_LSHIFT( silk_MUL( psEncC1->fs_kHz, 1000 ), 16 ), psEncC1->prevLag );
+ pitch_freq_log_Q7 = silk_lin2log( pitch_freq_Hz_Q16 ) - ( 16 << 7 );
+
+ /* adjustment based on quality */
+ quality_Q15 = psEncC1->input_quality_bands_Q15[ 0 ];
+ pitch_freq_log_Q7 = silk_SMLAWB( pitch_freq_log_Q7, silk_SMULWB( silk_LSHIFT( -quality_Q15, 2 ), quality_Q15 ),
+ pitch_freq_log_Q7 - ( silk_lin2log( SILK_FIX_CONST( VARIABLE_HP_MIN_CUTOFF_HZ, 16 ) ) - ( 16 << 7 ) ) );
+
+ /* delta_freq = pitch_freq_log - psEnc->variable_HP_smth1; */
+ delta_freq_Q7 = pitch_freq_log_Q7 - silk_RSHIFT( psEncC1->variable_HP_smth1_Q15, 8 );
+ if( delta_freq_Q7 < 0 ) {
+ /* less smoothing for decreasing pitch frequency, to track something close to the minimum */
+ delta_freq_Q7 = silk_MUL( delta_freq_Q7, 3 );
+ }
+
+ /* limit delta, to reduce impact of outliers in pitch estimation */
+ delta_freq_Q7 = silk_LIMIT_32( delta_freq_Q7, -SILK_FIX_CONST( VARIABLE_HP_MAX_DELTA_FREQ, 7 ), SILK_FIX_CONST( VARIABLE_HP_MAX_DELTA_FREQ, 7 ) );
+
+ /* update smoother */
+ psEncC1->variable_HP_smth1_Q15 = silk_SMLAWB( psEncC1->variable_HP_smth1_Q15,
+ silk_SMULBB( psEncC1->speech_activity_Q8, delta_freq_Q7 ), SILK_FIX_CONST( VARIABLE_HP_SMTH_COEF1, 16 ) );
+
+ /* limit frequency range */
+ psEncC1->variable_HP_smth1_Q15 = silk_LIMIT_32( psEncC1->variable_HP_smth1_Q15,
+ silk_LSHIFT( silk_lin2log( VARIABLE_HP_MIN_CUTOFF_HZ ), 8 ),
+ silk_LSHIFT( silk_lin2log( VARIABLE_HP_MAX_CUTOFF_HZ ), 8 ) );
+ }
+}
diff --git a/drivers/opus/silk/Inlines.h b/drivers/opus/silk/Inlines.h
new file mode 100644
index 0000000000..ec986cdfdd
--- /dev/null
+++ b/drivers/opus/silk/Inlines.h
@@ -0,0 +1,188 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+/*! \file silk_Inlines.h
+ * \brief silk_Inlines.h defines OPUS_INLINE signal processing functions.
+ */
+
+#ifndef SILK_FIX_INLINES_H
+#define SILK_FIX_INLINES_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* count leading zeros of opus_int64 */
+static OPUS_INLINE opus_int32 silk_CLZ64( opus_int64 in )
+{
+ opus_int32 in_upper;
+
+ in_upper = (opus_int32)silk_RSHIFT64(in, 32);
+ if (in_upper == 0) {
+ /* Search in the lower 32 bits */
+ return 32 + silk_CLZ32( (opus_int32) in );
+ } else {
+ /* Search in the upper 32 bits */
+ return silk_CLZ32( in_upper );
+ }
+}
+
+/* get number of leading zeros and fractional part (the bits right after the leading one */
+static OPUS_INLINE void silk_CLZ_FRAC(
+ opus_int32 in, /* I input */
+ opus_int32 *lz, /* O number of leading zeros */
+ opus_int32 *frac_Q7 /* O the 7 bits right after the leading one */
+)
+{
+ opus_int32 lzeros = silk_CLZ32(in);
+
+ * lz = lzeros;
+ * frac_Q7 = silk_ROR32(in, 24 - lzeros) & 0x7f;
+}
+
+/* Approximation of square root */
+/* Accuracy: < +/- 10% for output values > 15 */
+/* < +/- 2.5% for output values > 120 */
+static OPUS_INLINE opus_int32 silk_SQRT_APPROX( opus_int32 x )
+{
+ opus_int32 y, lz, frac_Q7;
+
+ if( x <= 0 ) {
+ return 0;
+ }
+
+ silk_CLZ_FRAC(x, &lz, &frac_Q7);
+
+ if( lz & 1 ) {
+ y = 32768;
+ } else {
+ y = 46214; /* 46214 = sqrt(2) * 32768 */
+ }
+
+ /* get scaling right */
+ y >>= silk_RSHIFT(lz, 1);
+
+ /* increment using fractional part of input */
+ y = silk_SMLAWB(y, y, silk_SMULBB(213, frac_Q7));
+
+ return y;
+}
+
+/* Divide two int32 values and return result as int32 in a given Q-domain */
+static OPUS_INLINE opus_int32 silk_DIV32_varQ( /* O returns a good approximation of "(a32 << Qres) / b32" */
+ const opus_int32 a32, /* I numerator (Q0) */
+ const opus_int32 b32, /* I denominator (Q0) */
+ const opus_int Qres /* I Q-domain of result (>= 0) */
+)
+{
+ opus_int a_headrm, b_headrm, lshift;
+ opus_int32 b32_inv, a32_nrm, b32_nrm, result;
+
+ silk_assert( b32 != 0 );
+ silk_assert( Qres >= 0 );
+
+ /* Compute number of bits head room and normalize inputs */
+ a_headrm = silk_CLZ32( silk_abs(a32) ) - 1;
+ a32_nrm = silk_LSHIFT(a32, a_headrm); /* Q: a_headrm */
+ b_headrm = silk_CLZ32( silk_abs(b32) ) - 1;
+ b32_nrm = silk_LSHIFT(b32, b_headrm); /* Q: b_headrm */
+
+ /* Inverse of b32, with 14 bits of precision */
+ b32_inv = silk_DIV32_16( silk_int32_MAX >> 2, silk_RSHIFT(b32_nrm, 16) ); /* Q: 29 + 16 - b_headrm */
+
+ /* First approximation */
+ result = silk_SMULWB(a32_nrm, b32_inv); /* Q: 29 + a_headrm - b_headrm */
+
+ /* Compute residual by subtracting product of denominator and first approximation */
+ /* It's OK to overflow because the final value of a32_nrm should always be small */
+ a32_nrm = silk_SUB32_ovflw(a32_nrm, silk_LSHIFT_ovflw( silk_SMMUL(b32_nrm, result), 3 )); /* Q: a_headrm */
+
+ /* Refinement */
+ result = silk_SMLAWB(result, a32_nrm, b32_inv); /* Q: 29 + a_headrm - b_headrm */
+
+ /* Convert to Qres domain */
+ lshift = 29 + a_headrm - b_headrm - Qres;
+ if( lshift < 0 ) {
+ return silk_LSHIFT_SAT32(result, -lshift);
+ } else {
+ if( lshift < 32){
+ return silk_RSHIFT(result, lshift);
+ } else {
+ /* Avoid undefined result */
+ return 0;
+ }
+ }
+}
+
+/* Invert int32 value and return result as int32 in a given Q-domain */
+static OPUS_INLINE opus_int32 silk_INVERSE32_varQ( /* O returns a good approximation of "(1 << Qres) / b32" */
+ const opus_int32 b32, /* I denominator (Q0) */
+ const opus_int Qres /* I Q-domain of result (> 0) */
+)
+{
+ opus_int b_headrm, lshift;
+ opus_int32 b32_inv, b32_nrm, err_Q32, result;
+
+ silk_assert( b32 != 0 );
+ silk_assert( Qres > 0 );
+
+ /* Compute number of bits head room and normalize input */
+ b_headrm = silk_CLZ32( silk_abs(b32) ) - 1;
+ b32_nrm = silk_LSHIFT(b32, b_headrm); /* Q: b_headrm */
+
+ /* Inverse of b32, with 14 bits of precision */
+ b32_inv = silk_DIV32_16( silk_int32_MAX >> 2, silk_RSHIFT(b32_nrm, 16) ); /* Q: 29 + 16 - b_headrm */
+
+ /* First approximation */
+ result = silk_LSHIFT(b32_inv, 16); /* Q: 61 - b_headrm */
+
+ /* Compute residual by subtracting product of denominator and first approximation from one */
+ err_Q32 = silk_LSHIFT( ((opus_int32)1<<29) - silk_SMULWB(b32_nrm, b32_inv), 3 ); /* Q32 */
+
+ /* Refinement */
+ result = silk_SMLAWW(result, err_Q32, b32_inv); /* Q: 61 - b_headrm */
+
+ /* Convert to Qres domain */
+ lshift = 61 - b_headrm - Qres;
+ if( lshift <= 0 ) {
+ return silk_LSHIFT_SAT32(result, -lshift);
+ } else {
+ if( lshift < 32){
+ return silk_RSHIFT(result, lshift);
+ }else{
+ /* Avoid undefined result */
+ return 0;
+ }
+ }
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SILK_FIX_INLINES_H */
diff --git a/drivers/opus/silk/LPC_analysis_filter.c b/drivers/opus/silk/LPC_analysis_filter.c
new file mode 100644
index 0000000000..4976d9d3c5
--- /dev/null
+++ b/drivers/opus/silk/LPC_analysis_filter.c
@@ -0,0 +1,106 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/SigProc_FIX.h"
+#include "opus/celt/celt_lpc.h"
+
+/*******************************************/
+/* LPC analysis filter */
+/* NB! State is kept internally and the */
+/* filter always starts with zero state */
+/* first d output samples are set to zero */
+/*******************************************/
+
+void silk_LPC_analysis_filter(
+ opus_int16 *out, /* O Output signal */
+ const opus_int16 *in, /* I Input signal */
+ const opus_int16 *B, /* I MA prediction coefficients, Q12 [order] */
+ const opus_int32 len, /* I Signal length */
+ const opus_int32 d /* I Filter order */
+)
+{
+ opus_int j;
+#ifdef OPUS_FIXED_POINT
+ opus_int16 mem[SILK_MAX_ORDER_LPC];
+ opus_int16 num[SILK_MAX_ORDER_LPC];
+#else
+ int ix;
+ opus_int32 out32_Q12, out32;
+ const opus_int16 *in_ptr;
+#endif
+
+ silk_assert( d >= 6 );
+ silk_assert( (d & 1) == 0 );
+ silk_assert( d <= len );
+
+#ifdef OPUS_FIXED_POINT
+ silk_assert( d <= SILK_MAX_ORDER_LPC );
+ for ( j = 0; j < d; j++ ) {
+ num[ j ] = -B[ j ];
+ }
+ for (j=0;j<d;j++) {
+ mem[ j ] = in[ d - j - 1 ];
+ }
+ celt_fir( in + d, num, out + d, len - d, d, mem );
+ for ( j = 0; j < d; j++ ) {
+ out[ j ] = 0;
+ }
+#else
+ for( ix = d; ix < len; ix++ ) {
+ in_ptr = &in[ ix - 1 ];
+
+ out32_Q12 = silk_SMULBB( in_ptr[ 0 ], B[ 0 ] );
+ /* Allowing wrap around so that two wraps can cancel each other. The rare
+ cases where the result wraps around can only be triggered by invalid streams*/
+ out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -1 ], B[ 1 ] );
+ out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -2 ], B[ 2 ] );
+ out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -3 ], B[ 3 ] );
+ out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -4 ], B[ 4 ] );
+ out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -5 ], B[ 5 ] );
+ for( j = 6; j < d; j += 2 ) {
+ out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -j ], B[ j ] );
+ out32_Q12 = silk_SMLABB_ovflw( out32_Q12, in_ptr[ -j - 1 ], B[ j + 1 ] );
+ }
+
+ /* Subtract prediction */
+ out32_Q12 = silk_SUB32_ovflw( silk_LSHIFT( (opus_int32)in_ptr[ 1 ], 12 ), out32_Q12 );
+
+ /* Scale to Q0 */
+ out32 = silk_RSHIFT_ROUND( out32_Q12, 12 );
+
+ /* Saturate output */
+ out[ ix ] = (opus_int16)silk_SAT16( out32 );
+ }
+
+ /* Set first d output samples to zero */
+ silk_memset( out, 0, d * sizeof( opus_int16 ) );
+#endif
+}
diff --git a/drivers/opus/silk/LPC_inv_pred_gain.c b/drivers/opus/silk/LPC_inv_pred_gain.c
new file mode 100644
index 0000000000..aa67875759
--- /dev/null
+++ b/drivers/opus/silk/LPC_inv_pred_gain.c
@@ -0,0 +1,154 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/SigProc_FIX.h"
+
+#define QA 24
+#define A_LIMIT SILK_FIX_CONST( 0.99975, QA )
+
+#define MUL32_FRAC_Q(a32, b32, Q) ((opus_int32)(silk_RSHIFT_ROUND64(silk_SMULL(a32, b32), Q)))
+
+/* Compute inverse of LPC prediction gain, and */
+/* test if LPC coefficients are stable (all poles within unit circle) */
+static opus_int32 LPC_inverse_pred_gain_QA( /* O Returns inverse prediction gain in energy domain, Q30 */
+ opus_int32 A_QA[ 2 ][ SILK_MAX_ORDER_LPC ], /* I Prediction coefficients */
+ const opus_int order /* I Prediction order */
+)
+{
+ opus_int k, n, mult2Q;
+ opus_int32 invGain_Q30, rc_Q31, rc_mult1_Q30, rc_mult2, tmp_QA;
+ opus_int32 *Aold_QA, *Anew_QA;
+
+ Anew_QA = A_QA[ order & 1 ];
+
+ invGain_Q30 = (opus_int32)1 << 30;
+ for( k = order - 1; k > 0; k-- ) {
+ /* Check for stability */
+ if( ( Anew_QA[ k ] > A_LIMIT ) || ( Anew_QA[ k ] < -A_LIMIT ) ) {
+ return 0;
+ }
+
+ /* Set RC equal to negated AR coef */
+ rc_Q31 = -silk_LSHIFT( Anew_QA[ k ], 31 - QA );
+
+ /* rc_mult1_Q30 range: [ 1 : 2^30 ] */
+ rc_mult1_Q30 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 );
+ silk_assert( rc_mult1_Q30 > ( 1 << 15 ) ); /* reduce A_LIMIT if fails */
+ silk_assert( rc_mult1_Q30 <= ( 1 << 30 ) );
+
+ /* rc_mult2 range: [ 2^30 : silk_int32_MAX ] */
+ mult2Q = 32 - silk_CLZ32( silk_abs( rc_mult1_Q30 ) );
+ rc_mult2 = silk_INVERSE32_varQ( rc_mult1_Q30, mult2Q + 30 );
+
+ /* Update inverse gain */
+ /* invGain_Q30 range: [ 0 : 2^30 ] */
+ invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 );
+ silk_assert( invGain_Q30 >= 0 );
+ silk_assert( invGain_Q30 <= ( 1 << 30 ) );
+
+ /* Swap pointers */
+ Aold_QA = Anew_QA;
+ Anew_QA = A_QA[ k & 1 ];
+
+ /* Update AR coefficient */
+ for( n = 0; n < k; n++ ) {
+ tmp_QA = Aold_QA[ n ] - MUL32_FRAC_Q( Aold_QA[ k - n - 1 ], rc_Q31, 31 );
+ Anew_QA[ n ] = MUL32_FRAC_Q( tmp_QA, rc_mult2 , mult2Q );
+ }
+ }
+
+ /* Check for stability */
+ if( ( Anew_QA[ 0 ] > A_LIMIT ) || ( Anew_QA[ 0 ] < -A_LIMIT ) ) {
+ return 0;
+ }
+
+ /* Set RC equal to negated AR coef */
+ rc_Q31 = -silk_LSHIFT( Anew_QA[ 0 ], 31 - QA );
+
+ /* Range: [ 1 : 2^30 ] */
+ rc_mult1_Q30 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 );
+
+ /* Update inverse gain */
+ /* Range: [ 0 : 2^30 ] */
+ invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 );
+ silk_assert( invGain_Q30 >= 0 );
+ silk_assert( invGain_Q30 <= 1<<30 );
+
+ return invGain_Q30;
+}
+
+/* For input in Q12 domain */
+opus_int32 silk_LPC_inverse_pred_gain( /* O Returns inverse prediction gain in energy domain, Q30 */
+ const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */
+ const opus_int order /* I Prediction order */
+)
+{
+ opus_int k;
+ opus_int32 Atmp_QA[ 2 ][ SILK_MAX_ORDER_LPC ];
+ opus_int32 *Anew_QA;
+ opus_int32 DC_resp = 0;
+
+ Anew_QA = Atmp_QA[ order & 1 ];
+
+ /* Increase Q domain of the AR coefficients */
+ for( k = 0; k < order; k++ ) {
+ DC_resp += (opus_int32)A_Q12[ k ];
+ Anew_QA[ k ] = silk_LSHIFT32( (opus_int32)A_Q12[ k ], QA - 12 );
+ }
+ /* If the DC is unstable, we don't even need to do the full calculations */
+ if( DC_resp >= 4096 ) {
+ return 0;
+ }
+ return LPC_inverse_pred_gain_QA( Atmp_QA, order );
+}
+
+#ifdef OPUS_FIXED_POINT
+
+/* For input in Q24 domain */
+opus_int32 silk_LPC_inverse_pred_gain_Q24( /* O Returns inverse prediction gain in energy domain, Q30 */
+ const opus_int32 *A_Q24, /* I Prediction coefficients [order] */
+ const opus_int order /* I Prediction order */
+)
+{
+ opus_int k;
+ opus_int32 Atmp_QA[ 2 ][ SILK_MAX_ORDER_LPC ];
+ opus_int32 *Anew_QA;
+
+ Anew_QA = Atmp_QA[ order & 1 ];
+
+ /* Increase Q domain of the AR coefficients */
+ for( k = 0; k < order; k++ ) {
+ Anew_QA[ k ] = silk_RSHIFT32( A_Q24[ k ], 24 - QA );
+ }
+
+ return LPC_inverse_pred_gain_QA( Atmp_QA, order );
+}
+#endif
diff --git a/drivers/opus/silk/LP_variable_cutoff.c b/drivers/opus/silk/LP_variable_cutoff.c
new file mode 100644
index 0000000000..65c4a6b06a
--- /dev/null
+++ b/drivers/opus/silk/LP_variable_cutoff.c
@@ -0,0 +1,135 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+/*
+ Elliptic/Cauer filters designed with 0.1 dB passband ripple,
+ 80 dB minimum stopband attenuation, and
+ [0.95 : 0.15 : 0.35] normalized cut off frequencies.
+*/
+
+#include "opus/silk/silk_main.h"
+
+/* Helper function, interpolates the filter taps */
+static OPUS_INLINE void silk_LP_interpolate_filter_taps(
+ opus_int32 B_Q28[ TRANSITION_NB ],
+ opus_int32 A_Q28[ TRANSITION_NA ],
+ const opus_int ind,
+ const opus_int32 fac_Q16
+)
+{
+ opus_int nb, na;
+
+ if( ind < TRANSITION_INT_NUM - 1 ) {
+ if( fac_Q16 > 0 ) {
+ if( fac_Q16 < 32768 ) { /* fac_Q16 is in range of a 16-bit int */
+ /* Piece-wise linear interpolation of B and A */
+ for( nb = 0; nb < TRANSITION_NB; nb++ ) {
+ B_Q28[ nb ] = silk_SMLAWB(
+ silk_Transition_LP_B_Q28[ ind ][ nb ],
+ silk_Transition_LP_B_Q28[ ind + 1 ][ nb ] -
+ silk_Transition_LP_B_Q28[ ind ][ nb ],
+ fac_Q16 );
+ }
+ for( na = 0; na < TRANSITION_NA; na++ ) {
+ A_Q28[ na ] = silk_SMLAWB(
+ silk_Transition_LP_A_Q28[ ind ][ na ],
+ silk_Transition_LP_A_Q28[ ind + 1 ][ na ] -
+ silk_Transition_LP_A_Q28[ ind ][ na ],
+ fac_Q16 );
+ }
+ } else { /* ( fac_Q16 - ( 1 << 16 ) ) is in range of a 16-bit int */
+ silk_assert( fac_Q16 - ( 1 << 16 ) == silk_SAT16( fac_Q16 - ( 1 << 16 ) ) );
+ /* Piece-wise linear interpolation of B and A */
+ for( nb = 0; nb < TRANSITION_NB; nb++ ) {
+ B_Q28[ nb ] = silk_SMLAWB(
+ silk_Transition_LP_B_Q28[ ind + 1 ][ nb ],
+ silk_Transition_LP_B_Q28[ ind + 1 ][ nb ] -
+ silk_Transition_LP_B_Q28[ ind ][ nb ],
+ fac_Q16 - ( (opus_int32)1 << 16 ) );
+ }
+ for( na = 0; na < TRANSITION_NA; na++ ) {
+ A_Q28[ na ] = silk_SMLAWB(
+ silk_Transition_LP_A_Q28[ ind + 1 ][ na ],
+ silk_Transition_LP_A_Q28[ ind + 1 ][ na ] -
+ silk_Transition_LP_A_Q28[ ind ][ na ],
+ fac_Q16 - ( (opus_int32)1 << 16 ) );
+ }
+ }
+ } else {
+ silk_memcpy( B_Q28, silk_Transition_LP_B_Q28[ ind ], TRANSITION_NB * sizeof( opus_int32 ) );
+ silk_memcpy( A_Q28, silk_Transition_LP_A_Q28[ ind ], TRANSITION_NA * sizeof( opus_int32 ) );
+ }
+ } else {
+ silk_memcpy( B_Q28, silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM - 1 ], TRANSITION_NB * sizeof( opus_int32 ) );
+ silk_memcpy( A_Q28, silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM - 1 ], TRANSITION_NA * sizeof( opus_int32 ) );
+ }
+}
+
+/* Low-pass filter with variable cutoff frequency based on */
+/* piece-wise linear interpolation between elliptic filters */
+/* Start by setting psEncC->mode <> 0; */
+/* Deactivate by setting psEncC->mode = 0; */
+void silk_LP_variable_cutoff(
+ silk_LP_state *psLP, /* I/O LP filter state */
+ opus_int16 *frame, /* I/O Low-pass filtered output signal */
+ const opus_int frame_length /* I Frame length */
+)
+{
+ opus_int32 B_Q28[ TRANSITION_NB ], A_Q28[ TRANSITION_NA ], fac_Q16 = 0;
+ opus_int ind = 0;
+
+ silk_assert( psLP->transition_frame_no >= 0 && psLP->transition_frame_no <= TRANSITION_FRAMES );
+
+ /* Run filter if needed */
+ if( psLP->mode != 0 ) {
+ /* Calculate index and interpolation factor for interpolation */
+#if( TRANSITION_INT_STEPS == 64 )
+ fac_Q16 = silk_LSHIFT( TRANSITION_FRAMES - psLP->transition_frame_no, 16 - 6 );
+#else
+ fac_Q16 = silk_DIV32_16( silk_LSHIFT( TRANSITION_FRAMES - psLP->transition_frame_no, 16 ), TRANSITION_FRAMES );
+#endif
+ ind = silk_RSHIFT( fac_Q16, 16 );
+ fac_Q16 -= silk_LSHIFT( ind, 16 );
+
+ silk_assert( ind >= 0 );
+ silk_assert( ind < TRANSITION_INT_NUM );
+
+ /* Interpolate filter coefficients */
+ silk_LP_interpolate_filter_taps( B_Q28, A_Q28, ind, fac_Q16 );
+
+ /* Update transition frame number for next frame */
+ psLP->transition_frame_no = silk_LIMIT( psLP->transition_frame_no + psLP->mode, 0, TRANSITION_FRAMES );
+
+ /* ARMA low-pass filtering */
+ silk_assert( TRANSITION_NB == 3 && TRANSITION_NA == 2 );
+ silk_biquad_alt( frame, B_Q28, A_Q28, psLP->In_LP_State, frame, frame_length, 1);
+ }
+}
diff --git a/drivers/opus/silk/MacroCount.h b/drivers/opus/silk/MacroCount.h
new file mode 100644
index 0000000000..834817d058
--- /dev/null
+++ b/drivers/opus/silk/MacroCount.h
@@ -0,0 +1,718 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SIGPROCFIX_API_MACROCOUNT_H
+#define SIGPROCFIX_API_MACROCOUNT_H
+#include <stdio.h>
+
+#ifdef silk_MACRO_COUNT
+#define varDefine opus_int64 ops_count = 0;
+
+extern opus_int64 ops_count;
+
+static OPUS_INLINE opus_int64 silk_SaveCount(){
+ return(ops_count);
+}
+
+static OPUS_INLINE opus_int64 silk_SaveResetCount(){
+ opus_int64 ret;
+
+ ret = ops_count;
+ ops_count = 0;
+ return(ret);
+}
+
+static OPUS_INLINE silk_PrintCount(){
+ printf("ops_count = %d \n ", (opus_int32)ops_count);
+}
+
+#undef silk_MUL
+static OPUS_INLINE opus_int32 silk_MUL(opus_int32 a32, opus_int32 b32){
+ opus_int32 ret;
+ ops_count += 4;
+ ret = a32 * b32;
+ return ret;
+}
+
+#undef silk_MUL_uint
+static OPUS_INLINE opus_uint32 silk_MUL_uint(opus_uint32 a32, opus_uint32 b32){
+ opus_uint32 ret;
+ ops_count += 4;
+ ret = a32 * b32;
+ return ret;
+}
+#undef silk_MLA
+static OPUS_INLINE opus_int32 silk_MLA(opus_int32 a32, opus_int32 b32, opus_int32 c32){
+ opus_int32 ret;
+ ops_count += 4;
+ ret = a32 + b32 * c32;
+ return ret;
+}
+
+#undef silk_MLA_uint
+static OPUS_INLINE opus_int32 silk_MLA_uint(opus_uint32 a32, opus_uint32 b32, opus_uint32 c32){
+ opus_uint32 ret;
+ ops_count += 4;
+ ret = a32 + b32 * c32;
+ return ret;
+}
+
+#undef silk_SMULWB
+static OPUS_INLINE opus_int32 silk_SMULWB(opus_int32 a32, opus_int32 b32){
+ opus_int32 ret;
+ ops_count += 5;
+ ret = (a32 >> 16) * (opus_int32)((opus_int16)b32) + (((a32 & 0x0000FFFF) * (opus_int32)((opus_int16)b32)) >> 16);
+ return ret;
+}
+#undef silk_SMLAWB
+static OPUS_INLINE opus_int32 silk_SMLAWB(opus_int32 a32, opus_int32 b32, opus_int32 c32){
+ opus_int32 ret;
+ ops_count += 5;
+ ret = ((a32) + ((((b32) >> 16) * (opus_int32)((opus_int16)(c32))) + ((((b32) & 0x0000FFFF) * (opus_int32)((opus_int16)(c32))) >> 16)));
+ return ret;
+}
+
+#undef silk_SMULWT
+static OPUS_INLINE opus_int32 silk_SMULWT(opus_int32 a32, opus_int32 b32){
+ opus_int32 ret;
+ ops_count += 4;
+ ret = (a32 >> 16) * (b32 >> 16) + (((a32 & 0x0000FFFF) * (b32 >> 16)) >> 16);
+ return ret;
+}
+#undef silk_SMLAWT
+static OPUS_INLINE opus_int32 silk_SMLAWT(opus_int32 a32, opus_int32 b32, opus_int32 c32){
+ opus_int32 ret;
+ ops_count += 4;
+ ret = a32 + ((b32 >> 16) * (c32 >> 16)) + (((b32 & 0x0000FFFF) * ((c32 >> 16)) >> 16));
+ return ret;
+}
+
+#undef silk_SMULBB
+static OPUS_INLINE opus_int32 silk_SMULBB(opus_int32 a32, opus_int32 b32){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = (opus_int32)((opus_int16)a32) * (opus_int32)((opus_int16)b32);
+ return ret;
+}
+#undef silk_SMLABB
+static OPUS_INLINE opus_int32 silk_SMLABB(opus_int32 a32, opus_int32 b32, opus_int32 c32){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = a32 + (opus_int32)((opus_int16)b32) * (opus_int32)((opus_int16)c32);
+ return ret;
+}
+
+#undef silk_SMULBT
+static OPUS_INLINE opus_int32 silk_SMULBT(opus_int32 a32, opus_int32 b32 ){
+ opus_int32 ret;
+ ops_count += 4;
+ ret = ((opus_int32)((opus_int16)a32)) * (b32 >> 16);
+ return ret;
+}
+
+#undef silk_SMLABT
+static OPUS_INLINE opus_int32 silk_SMLABT(opus_int32 a32, opus_int32 b32, opus_int32 c32){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = a32 + ((opus_int32)((opus_int16)b32)) * (c32 >> 16);
+ return ret;
+}
+
+#undef silk_SMULTT
+static OPUS_INLINE opus_int32 silk_SMULTT(opus_int32 a32, opus_int32 b32){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = (a32 >> 16) * (b32 >> 16);
+ return ret;
+}
+
+#undef silk_SMLATT
+static OPUS_INLINE opus_int32 silk_SMLATT(opus_int32 a32, opus_int32 b32, opus_int32 c32){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = a32 + (b32 >> 16) * (c32 >> 16);
+ return ret;
+}
+
+
+/* multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode)*/
+#undef silk_MLA_ovflw
+#define silk_MLA_ovflw silk_MLA
+
+#undef silk_SMLABB_ovflw
+#define silk_SMLABB_ovflw silk_SMLABB
+
+#undef silk_SMLABT_ovflw
+#define silk_SMLABT_ovflw silk_SMLABT
+
+#undef silk_SMLATT_ovflw
+#define silk_SMLATT_ovflw silk_SMLATT
+
+#undef silk_SMLAWB_ovflw
+#define silk_SMLAWB_ovflw silk_SMLAWB
+
+#undef silk_SMLAWT_ovflw
+#define silk_SMLAWT_ovflw silk_SMLAWT
+
+#undef silk_SMULL
+static OPUS_INLINE opus_int64 silk_SMULL(opus_int32 a32, opus_int32 b32){
+ opus_int64 ret;
+ ops_count += 8;
+ ret = ((opus_int64)(a32) * /*(opus_int64)*/(b32));
+ return ret;
+}
+
+#undef silk_SMLAL
+static OPUS_INLINE opus_int64 silk_SMLAL(opus_int64 a64, opus_int32 b32, opus_int32 c32){
+ opus_int64 ret;
+ ops_count += 8;
+ ret = a64 + ((opus_int64)(b32) * /*(opus_int64)*/(c32));
+ return ret;
+}
+#undef silk_SMLALBB
+static OPUS_INLINE opus_int64 silk_SMLALBB(opus_int64 a64, opus_int16 b16, opus_int16 c16){
+ opus_int64 ret;
+ ops_count += 4;
+ ret = a64 + ((opus_int64)(b16) * /*(opus_int64)*/(c16));
+ return ret;
+}
+
+#undef SigProcFIX_CLZ16
+static OPUS_INLINE opus_int32 SigProcFIX_CLZ16(opus_int16 in16)
+{
+ opus_int32 out32 = 0;
+ ops_count += 10;
+ if( in16 == 0 ) {
+ return 16;
+ }
+ /* test nibbles */
+ if( in16 & 0xFF00 ) {
+ if( in16 & 0xF000 ) {
+ in16 >>= 12;
+ } else {
+ out32 += 4;
+ in16 >>= 8;
+ }
+ } else {
+ if( in16 & 0xFFF0 ) {
+ out32 += 8;
+ in16 >>= 4;
+ } else {
+ out32 += 12;
+ }
+ }
+ /* test bits and return */
+ if( in16 & 0xC ) {
+ if( in16 & 0x8 )
+ return out32 + 0;
+ else
+ return out32 + 1;
+ } else {
+ if( in16 & 0xE )
+ return out32 + 2;
+ else
+ return out32 + 3;
+ }
+}
+
+#undef SigProcFIX_CLZ32
+static OPUS_INLINE opus_int32 SigProcFIX_CLZ32(opus_int32 in32)
+{
+ /* test highest 16 bits and convert to opus_int16 */
+ ops_count += 2;
+ if( in32 & 0xFFFF0000 ) {
+ return SigProcFIX_CLZ16((opus_int16)(in32 >> 16));
+ } else {
+ return SigProcFIX_CLZ16((opus_int16)in32) + 16;
+ }
+}
+
+#undef silk_DIV32
+static OPUS_INLINE opus_int32 silk_DIV32(opus_int32 a32, opus_int32 b32){
+ ops_count += 64;
+ return a32 / b32;
+}
+
+#undef silk_DIV32_16
+static OPUS_INLINE opus_int32 silk_DIV32_16(opus_int32 a32, opus_int32 b32){
+ ops_count += 32;
+ return a32 / b32;
+}
+
+#undef silk_SAT8
+static OPUS_INLINE opus_int8 silk_SAT8(opus_int64 a){
+ opus_int8 tmp;
+ ops_count += 1;
+ tmp = (opus_int8)((a) > silk_int8_MAX ? silk_int8_MAX : \
+ ((a) < silk_int8_MIN ? silk_int8_MIN : (a)));
+ return(tmp);
+}
+
+#undef silk_SAT16
+static OPUS_INLINE opus_int16 silk_SAT16(opus_int64 a){
+ opus_int16 tmp;
+ ops_count += 1;
+ tmp = (opus_int16)((a) > silk_int16_MAX ? silk_int16_MAX : \
+ ((a) < silk_int16_MIN ? silk_int16_MIN : (a)));
+ return(tmp);
+}
+#undef silk_SAT32
+static OPUS_INLINE opus_int32 silk_SAT32(opus_int64 a){
+ opus_int32 tmp;
+ ops_count += 1;
+ tmp = (opus_int32)((a) > silk_int32_MAX ? silk_int32_MAX : \
+ ((a) < silk_int32_MIN ? silk_int32_MIN : (a)));
+ return(tmp);
+}
+#undef silk_POS_SAT32
+static OPUS_INLINE opus_int32 silk_POS_SAT32(opus_int64 a){
+ opus_int32 tmp;
+ ops_count += 1;
+ tmp = (opus_int32)((a) > silk_int32_MAX ? silk_int32_MAX : (a));
+ return(tmp);
+}
+
+#undef silk_ADD_POS_SAT8
+static OPUS_INLINE opus_int8 silk_ADD_POS_SAT8(opus_int64 a, opus_int64 b){
+ opus_int8 tmp;
+ ops_count += 1;
+ tmp = (opus_int8)((((a)+(b)) & 0x80) ? silk_int8_MAX : ((a)+(b)));
+ return(tmp);
+}
+#undef silk_ADD_POS_SAT16
+static OPUS_INLINE opus_int16 silk_ADD_POS_SAT16(opus_int64 a, opus_int64 b){
+ opus_int16 tmp;
+ ops_count += 1;
+ tmp = (opus_int16)((((a)+(b)) & 0x8000) ? silk_int16_MAX : ((a)+(b)));
+ return(tmp);
+}
+
+#undef silk_ADD_POS_SAT32
+static OPUS_INLINE opus_int32 silk_ADD_POS_SAT32(opus_int64 a, opus_int64 b){
+ opus_int32 tmp;
+ ops_count += 1;
+ tmp = (opus_int32)((((a)+(b)) & 0x80000000) ? silk_int32_MAX : ((a)+(b)));
+ return(tmp);
+}
+
+#undef silk_ADD_POS_SAT64
+static OPUS_INLINE opus_int64 silk_ADD_POS_SAT64(opus_int64 a, opus_int64 b){
+ opus_int64 tmp;
+ ops_count += 1;
+ tmp = ((((a)+(b)) & 0x8000000000000000LL) ? silk_int64_MAX : ((a)+(b)));
+ return(tmp);
+}
+
+#undef silk_LSHIFT8
+static OPUS_INLINE opus_int8 silk_LSHIFT8(opus_int8 a, opus_int32 shift){
+ opus_int8 ret;
+ ops_count += 1;
+ ret = a << shift;
+ return ret;
+}
+#undef silk_LSHIFT16
+static OPUS_INLINE opus_int16 silk_LSHIFT16(opus_int16 a, opus_int32 shift){
+ opus_int16 ret;
+ ops_count += 1;
+ ret = a << shift;
+ return ret;
+}
+#undef silk_LSHIFT32
+static OPUS_INLINE opus_int32 silk_LSHIFT32(opus_int32 a, opus_int32 shift){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = a << shift;
+ return ret;
+}
+#undef silk_LSHIFT64
+static OPUS_INLINE opus_int64 silk_LSHIFT64(opus_int64 a, opus_int shift){
+ ops_count += 1;
+ return a << shift;
+}
+
+#undef silk_LSHIFT_ovflw
+static OPUS_INLINE opus_int32 silk_LSHIFT_ovflw(opus_int32 a, opus_int32 shift){
+ ops_count += 1;
+ return a << shift;
+}
+
+#undef silk_LSHIFT_uint
+static OPUS_INLINE opus_uint32 silk_LSHIFT_uint(opus_uint32 a, opus_int32 shift){
+ opus_uint32 ret;
+ ops_count += 1;
+ ret = a << shift;
+ return ret;
+}
+
+#undef silk_RSHIFT8
+static OPUS_INLINE opus_int8 silk_RSHIFT8(opus_int8 a, opus_int32 shift){
+ ops_count += 1;
+ return a >> shift;
+}
+#undef silk_RSHIFT16
+static OPUS_INLINE opus_int16 silk_RSHIFT16(opus_int16 a, opus_int32 shift){
+ ops_count += 1;
+ return a >> shift;
+}
+#undef silk_RSHIFT32
+static OPUS_INLINE opus_int32 silk_RSHIFT32(opus_int32 a, opus_int32 shift){
+ ops_count += 1;
+ return a >> shift;
+}
+#undef silk_RSHIFT64
+static OPUS_INLINE opus_int64 silk_RSHIFT64(opus_int64 a, opus_int64 shift){
+ ops_count += 1;
+ return a >> shift;
+}
+
+#undef silk_RSHIFT_uint
+static OPUS_INLINE opus_uint32 silk_RSHIFT_uint(opus_uint32 a, opus_int32 shift){
+ ops_count += 1;
+ return a >> shift;
+}
+
+#undef silk_ADD_LSHIFT
+static OPUS_INLINE opus_int32 silk_ADD_LSHIFT(opus_int32 a, opus_int32 b, opus_int32 shift){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = a + (b << shift);
+ return ret; /* shift >= 0*/
+}
+#undef silk_ADD_LSHIFT32
+static OPUS_INLINE opus_int32 silk_ADD_LSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = a + (b << shift);
+ return ret; /* shift >= 0*/
+}
+#undef silk_ADD_LSHIFT_uint
+static OPUS_INLINE opus_uint32 silk_ADD_LSHIFT_uint(opus_uint32 a, opus_uint32 b, opus_int32 shift){
+ opus_uint32 ret;
+ ops_count += 1;
+ ret = a + (b << shift);
+ return ret; /* shift >= 0*/
+}
+#undef silk_ADD_RSHIFT
+static OPUS_INLINE opus_int32 silk_ADD_RSHIFT(opus_int32 a, opus_int32 b, opus_int32 shift){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = a + (b >> shift);
+ return ret; /* shift > 0*/
+}
+#undef silk_ADD_RSHIFT32
+static OPUS_INLINE opus_int32 silk_ADD_RSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = a + (b >> shift);
+ return ret; /* shift > 0*/
+}
+#undef silk_ADD_RSHIFT_uint
+static OPUS_INLINE opus_uint32 silk_ADD_RSHIFT_uint(opus_uint32 a, opus_uint32 b, opus_int32 shift){
+ opus_uint32 ret;
+ ops_count += 1;
+ ret = a + (b >> shift);
+ return ret; /* shift > 0*/
+}
+#undef silk_SUB_LSHIFT32
+static OPUS_INLINE opus_int32 silk_SUB_LSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = a - (b << shift);
+ return ret; /* shift >= 0*/
+}
+#undef silk_SUB_RSHIFT32
+static OPUS_INLINE opus_int32 silk_SUB_RSHIFT32(opus_int32 a, opus_int32 b, opus_int32 shift){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = a - (b >> shift);
+ return ret; /* shift > 0*/
+}
+
+#undef silk_RSHIFT_ROUND
+static OPUS_INLINE opus_int32 silk_RSHIFT_ROUND(opus_int32 a, opus_int32 shift){
+ opus_int32 ret;
+ ops_count += 3;
+ ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1;
+ return ret;
+}
+
+#undef silk_RSHIFT_ROUND64
+static OPUS_INLINE opus_int64 silk_RSHIFT_ROUND64(opus_int64 a, opus_int32 shift){
+ opus_int64 ret;
+ ops_count += 6;
+ ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1;
+ return ret;
+}
+
+#undef silk_abs_int64
+static OPUS_INLINE opus_int64 silk_abs_int64(opus_int64 a){
+ ops_count += 1;
+ return (((a) > 0) ? (a) : -(a)); /* Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN*/
+}
+
+#undef silk_abs_int32
+static OPUS_INLINE opus_int32 silk_abs_int32(opus_int32 a){
+ ops_count += 1;
+ return silk_abs(a);
+}
+
+
+#undef silk_min
+static silk_min(a, b){
+ ops_count += 1;
+ return (((a) < (b)) ? (a) : (b));
+}
+#undef silk_max
+static silk_max(a, b){
+ ops_count += 1;
+ return (((a) > (b)) ? (a) : (b));
+}
+#undef silk_sign
+static silk_sign(a){
+ ops_count += 1;
+ return ((a) > 0 ? 1 : ( (a) < 0 ? -1 : 0 ));
+}
+
+#undef silk_ADD16
+static OPUS_INLINE opus_int16 silk_ADD16(opus_int16 a, opus_int16 b){
+ opus_int16 ret;
+ ops_count += 1;
+ ret = a + b;
+ return ret;
+}
+
+#undef silk_ADD32
+static OPUS_INLINE opus_int32 silk_ADD32(opus_int32 a, opus_int32 b){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = a + b;
+ return ret;
+}
+
+#undef silk_ADD64
+static OPUS_INLINE opus_int64 silk_ADD64(opus_int64 a, opus_int64 b){
+ opus_int64 ret;
+ ops_count += 2;
+ ret = a + b;
+ return ret;
+}
+
+#undef silk_SUB16
+static OPUS_INLINE opus_int16 silk_SUB16(opus_int16 a, opus_int16 b){
+ opus_int16 ret;
+ ops_count += 1;
+ ret = a - b;
+ return ret;
+}
+
+#undef silk_SUB32
+static OPUS_INLINE opus_int32 silk_SUB32(opus_int32 a, opus_int32 b){
+ opus_int32 ret;
+ ops_count += 1;
+ ret = a - b;
+ return ret;
+}
+
+#undef silk_SUB64
+static OPUS_INLINE opus_int64 silk_SUB64(opus_int64 a, opus_int64 b){
+ opus_int64 ret;
+ ops_count += 2;
+ ret = a - b;
+ return ret;
+}
+
+#undef silk_ADD_SAT16
+static OPUS_INLINE opus_int16 silk_ADD_SAT16( opus_int16 a16, opus_int16 b16 ) {
+ opus_int16 res;
+ /* Nb will be counted in AKP_add32 and silk_SAT16*/
+ res = (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a16), (b16) ) );
+ return res;
+}
+
+#undef silk_ADD_SAT32
+static OPUS_INLINE opus_int32 silk_ADD_SAT32(opus_int32 a32, opus_int32 b32){
+ opus_int32 res;
+ ops_count += 1;
+ res = ((((a32) + (b32)) & 0x80000000) == 0 ? \
+ ((((a32) & (b32)) & 0x80000000) != 0 ? silk_int32_MIN : (a32)+(b32)) : \
+ ((((a32) | (b32)) & 0x80000000) == 0 ? silk_int32_MAX : (a32)+(b32)) );
+ return res;
+}
+
+#undef silk_ADD_SAT64
+static OPUS_INLINE opus_int64 silk_ADD_SAT64( opus_int64 a64, opus_int64 b64 ) {
+ opus_int64 res;
+ ops_count += 1;
+ res = ((((a64) + (b64)) & 0x8000000000000000LL) == 0 ? \
+ ((((a64) & (b64)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a64)+(b64)) : \
+ ((((a64) | (b64)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a64)+(b64)) );
+ return res;
+}
+
+#undef silk_SUB_SAT16
+static OPUS_INLINE opus_int16 silk_SUB_SAT16( opus_int16 a16, opus_int16 b16 ) {
+ opus_int16 res;
+ silk_assert(0);
+ /* Nb will be counted in sub-macros*/
+ res = (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a16), (b16) ) );
+ return res;
+}
+
+#undef silk_SUB_SAT32
+static OPUS_INLINE opus_int32 silk_SUB_SAT32( opus_int32 a32, opus_int32 b32 ) {
+ opus_int32 res;
+ ops_count += 1;
+ res = ((((a32)-(b32)) & 0x80000000) == 0 ? \
+ (( (a32) & ((b32)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a32)-(b32)) : \
+ ((((a32)^0x80000000) & (b32) & 0x80000000) ? silk_int32_MAX : (a32)-(b32)) );
+ return res;
+}
+
+#undef silk_SUB_SAT64
+static OPUS_INLINE opus_int64 silk_SUB_SAT64( opus_int64 a64, opus_int64 b64 ) {
+ opus_int64 res;
+ ops_count += 1;
+ res = ((((a64)-(b64)) & 0x8000000000000000LL) == 0 ? \
+ (( (a64) & ((b64)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a64)-(b64)) : \
+ ((((a64)^0x8000000000000000LL) & (b64) & 0x8000000000000000LL) ? silk_int64_MAX : (a64)-(b64)) );
+
+ return res;
+}
+
+#undef silk_SMULWW
+static OPUS_INLINE opus_int32 silk_SMULWW(opus_int32 a32, opus_int32 b32){
+ opus_int32 ret;
+ /* Nb will be counted in sub-macros*/
+ ret = silk_MLA(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16));
+ return ret;
+}
+
+#undef silk_SMLAWW
+static OPUS_INLINE opus_int32 silk_SMLAWW(opus_int32 a32, opus_int32 b32, opus_int32 c32){
+ opus_int32 ret;
+ /* Nb will be counted in sub-macros*/
+ ret = silk_MLA(silk_SMLAWB((a32), (b32), (c32)), (b32), silk_RSHIFT_ROUND((c32), 16));
+ return ret;
+}
+
+#undef silk_min_int
+static OPUS_INLINE opus_int silk_min_int(opus_int a, opus_int b)
+{
+ ops_count += 1;
+ return (((a) < (b)) ? (a) : (b));
+}
+
+#undef silk_min_16
+static OPUS_INLINE opus_int16 silk_min_16(opus_int16 a, opus_int16 b)
+{
+ ops_count += 1;
+ return (((a) < (b)) ? (a) : (b));
+}
+#undef silk_min_32
+static OPUS_INLINE opus_int32 silk_min_32(opus_int32 a, opus_int32 b)
+{
+ ops_count += 1;
+ return (((a) < (b)) ? (a) : (b));
+}
+#undef silk_min_64
+static OPUS_INLINE opus_int64 silk_min_64(opus_int64 a, opus_int64 b)
+{
+ ops_count += 1;
+ return (((a) < (b)) ? (a) : (b));
+}
+
+/* silk_min() versions with typecast in the function call */
+#undef silk_max_int
+static OPUS_INLINE opus_int silk_max_int(opus_int a, opus_int b)
+{
+ ops_count += 1;
+ return (((a) > (b)) ? (a) : (b));
+}
+#undef silk_max_16
+static OPUS_INLINE opus_int16 silk_max_16(opus_int16 a, opus_int16 b)
+{
+ ops_count += 1;
+ return (((a) > (b)) ? (a) : (b));
+}
+#undef silk_max_32
+static OPUS_INLINE opus_int32 silk_max_32(opus_int32 a, opus_int32 b)
+{
+ ops_count += 1;
+ return (((a) > (b)) ? (a) : (b));
+}
+
+#undef silk_max_64
+static OPUS_INLINE opus_int64 silk_max_64(opus_int64 a, opus_int64 b)
+{
+ ops_count += 1;
+ return (((a) > (b)) ? (a) : (b));
+}
+
+
+#undef silk_LIMIT_int
+static OPUS_INLINE opus_int silk_LIMIT_int(opus_int a, opus_int limit1, opus_int limit2)
+{
+ opus_int ret;
+ ops_count += 6;
+
+ ret = ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \
+ : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a))));
+
+ return(ret);
+}
+
+#undef silk_LIMIT_16
+static OPUS_INLINE opus_int16 silk_LIMIT_16(opus_int16 a, opus_int16 limit1, opus_int16 limit2)
+{
+ opus_int16 ret;
+ ops_count += 6;
+
+ ret = ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \
+ : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a))));
+
+return(ret);
+}
+
+
+#undef silk_LIMIT_32
+static OPUS_INLINE opus_int silk_LIMIT_32(opus_int32 a, opus_int32 limit1, opus_int32 limit2)
+{
+ opus_int32 ret;
+ ops_count += 6;
+
+ ret = ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \
+ : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a))));
+ return(ret);
+}
+
+#else
+#define varDefine
+#define silk_SaveCount()
+
+#endif
+#endif
+
diff --git a/drivers/opus/silk/MacroDebug.h b/drivers/opus/silk/MacroDebug.h
new file mode 100644
index 0000000000..35aedc5c5f
--- /dev/null
+++ b/drivers/opus/silk/MacroDebug.h
@@ -0,0 +1,952 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Copyright (C) 2012 Xiph.Org Foundation
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef MACRO_DEBUG_H
+#define MACRO_DEBUG_H
+
+/* Redefine macro functions with extensive assertion in DEBUG mode.
+ As functions can't be undefined, this file can't work with SigProcFIX_MacroCount.h */
+
+#if ( defined (FIXED_DEBUG) || ( 0 && defined (_DEBUG) ) ) && !defined (silk_MACRO_COUNT)
+
+#undef silk_ADD16
+#define silk_ADD16(a,b) silk_ADD16_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int16 silk_ADD16_(opus_int16 a, opus_int16 b, char *file, int line){
+ opus_int16 ret;
+
+ ret = a + b;
+ if ( ret != silk_ADD_SAT16( a, b ) )
+ {
+ fprintf (stderr, "silk_ADD16(%d, %d) in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_ADD32
+#define silk_ADD32(a,b) silk_ADD32_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_ADD32_(opus_int32 a, opus_int32 b, char *file, int line){
+ opus_int32 ret;
+
+ ret = a + b;
+ if ( ret != silk_ADD_SAT32( a, b ) )
+ {
+ fprintf (stderr, "silk_ADD32(%d, %d) in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_ADD64
+#define silk_ADD64(a,b) silk_ADD64_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int64 silk_ADD64_(opus_int64 a, opus_int64 b, char *file, int line){
+ opus_int64 ret;
+
+ ret = a + b;
+ if ( ret != silk_ADD_SAT64( a, b ) )
+ {
+ fprintf (stderr, "silk_ADD64(%lld, %lld) in %s: line %d\n", (long long)a, (long long)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_SUB16
+#define silk_SUB16(a,b) silk_SUB16_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int16 silk_SUB16_(opus_int16 a, opus_int16 b, char *file, int line){
+ opus_int16 ret;
+
+ ret = a - b;
+ if ( ret != silk_SUB_SAT16( a, b ) )
+ {
+ fprintf (stderr, "silk_SUB16(%d, %d) in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_SUB32
+#define silk_SUB32(a,b) silk_SUB32_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SUB32_(opus_int32 a, opus_int32 b, char *file, int line){
+ opus_int32 ret;
+
+ ret = a - b;
+ if ( ret != silk_SUB_SAT32( a, b ) )
+ {
+ fprintf (stderr, "silk_SUB32(%d, %d) in %s: line %d\n", a, b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_SUB64
+#define silk_SUB64(a,b) silk_SUB64_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int64 silk_SUB64_(opus_int64 a, opus_int64 b, char *file, int line){
+ opus_int64 ret;
+
+ ret = a - b;
+ if ( ret != silk_SUB_SAT64( a, b ) )
+ {
+ fprintf (stderr, "silk_SUB64(%lld, %lld) in %s: line %d\n", (long long)a, (long long)b, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_ADD_SAT16
+#define silk_ADD_SAT16(a,b) silk_ADD_SAT16_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int16 silk_ADD_SAT16_( opus_int16 a16, opus_int16 b16, char *file, int line) {
+ opus_int16 res;
+ res = (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a16), (b16) ) );
+ if ( res != silk_SAT16( (opus_int32)a16 + (opus_int32)b16 ) )
+ {
+ fprintf (stderr, "silk_ADD_SAT16(%d, %d) in %s: line %d\n", a16, b16, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return res;
+}
+
+#undef silk_ADD_SAT32
+#define silk_ADD_SAT32(a,b) silk_ADD_SAT32_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_ADD_SAT32_(opus_int32 a32, opus_int32 b32, char *file, int line){
+ opus_int32 res;
+ res = ((((opus_uint32)(a32) + (opus_uint32)(b32)) & 0x80000000) == 0 ? \
+ ((((a32) & (b32)) & 0x80000000) != 0 ? silk_int32_MIN : (a32)+(b32)) : \
+ ((((a32) | (b32)) & 0x80000000) == 0 ? silk_int32_MAX : (a32)+(b32)) );
+ if ( res != silk_SAT32( (opus_int64)a32 + (opus_int64)b32 ) )
+ {
+ fprintf (stderr, "silk_ADD_SAT32(%d, %d) in %s: line %d\n", a32, b32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return res;
+}
+
+#undef silk_ADD_SAT64
+#define silk_ADD_SAT64(a,b) silk_ADD_SAT64_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int64 silk_ADD_SAT64_( opus_int64 a64, opus_int64 b64, char *file, int line) {
+ opus_int64 res;
+ int fail = 0;
+ res = ((((a64) + (b64)) & 0x8000000000000000LL) == 0 ? \
+ ((((a64) & (b64)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a64)+(b64)) : \
+ ((((a64) | (b64)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a64)+(b64)) );
+ if( res != a64 + b64 ) {
+ /* Check that we saturated to the correct extreme value */
+ if ( !(( res == silk_int64_MAX && ( ( a64 >> 1 ) + ( b64 >> 1 ) > ( silk_int64_MAX >> 3 ) ) ) ||
+ ( res == silk_int64_MIN && ( ( a64 >> 1 ) + ( b64 >> 1 ) < ( silk_int64_MIN >> 3 ) ) ) ) )
+ {
+ fail = 1;
+ }
+ } else {
+ /* Saturation not necessary */
+ fail = res != a64 + b64;
+ }
+ if ( fail )
+ {
+ fprintf (stderr, "silk_ADD_SAT64(%lld, %lld) in %s: line %d\n", (long long)a64, (long long)b64, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return res;
+}
+
+#undef silk_SUB_SAT16
+#define silk_SUB_SAT16(a,b) silk_SUB_SAT16_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int16 silk_SUB_SAT16_( opus_int16 a16, opus_int16 b16, char *file, int line ) {
+ opus_int16 res;
+ res = (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a16), (b16) ) );
+ if ( res != silk_SAT16( (opus_int32)a16 - (opus_int32)b16 ) )
+ {
+ fprintf (stderr, "silk_SUB_SAT16(%d, %d) in %s: line %d\n", a16, b16, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return res;
+}
+
+#undef silk_SUB_SAT32
+#define silk_SUB_SAT32(a,b) silk_SUB_SAT32_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SUB_SAT32_( opus_int32 a32, opus_int32 b32, char *file, int line ) {
+ opus_int32 res;
+ res = ((((opus_uint32)(a32)-(opus_uint32)(b32)) & 0x80000000) == 0 ? \
+ (( (a32) & ((b32)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a32)-(b32)) : \
+ ((((a32)^0x80000000) & (b32) & 0x80000000) ? silk_int32_MAX : (a32)-(b32)) );
+ if ( res != silk_SAT32( (opus_int64)a32 - (opus_int64)b32 ) )
+ {
+ fprintf (stderr, "silk_SUB_SAT32(%d, %d) in %s: line %d\n", a32, b32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return res;
+}
+
+#undef silk_SUB_SAT64
+#define silk_SUB_SAT64(a,b) silk_SUB_SAT64_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int64 silk_SUB_SAT64_( opus_int64 a64, opus_int64 b64, char *file, int line ) {
+ opus_int64 res;
+ int fail = 0;
+ res = ((((a64)-(b64)) & 0x8000000000000000LL) == 0 ? \
+ (( (a64) & ((b64)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a64)-(b64)) : \
+ ((((a64)^0x8000000000000000LL) & (b64) & 0x8000000000000000LL) ? silk_int64_MAX : (a64)-(b64)) );
+ if( res != a64 - b64 ) {
+ /* Check that we saturated to the correct extreme value */
+ if( !(( res == silk_int64_MAX && ( ( a64 >> 1 ) + ( b64 >> 1 ) > ( silk_int64_MAX >> 3 ) ) ) ||
+ ( res == silk_int64_MIN && ( ( a64 >> 1 ) + ( b64 >> 1 ) < ( silk_int64_MIN >> 3 ) ) ) ))
+ {
+ fail = 1;
+ }
+ } else {
+ /* Saturation not necessary */
+ fail = res != a64 - b64;
+ }
+ if ( fail )
+ {
+ fprintf (stderr, "silk_SUB_SAT64(%lld, %lld) in %s: line %d\n", (long long)a64, (long long)b64, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return res;
+}
+
+#undef silk_MUL
+#define silk_MUL(a,b) silk_MUL_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_MUL_(opus_int32 a32, opus_int32 b32, char *file, int line){
+ opus_int32 ret;
+ opus_int64 ret64;
+ ret = a32 * b32;
+ ret64 = (opus_int64)a32 * (opus_int64)b32;
+ if ( (opus_int64)ret != ret64 )
+ {
+ fprintf (stderr, "silk_MUL(%d, %d) in %s: line %d\n", a32, b32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_MUL_uint
+#define silk_MUL_uint(a,b) silk_MUL_uint_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_uint32 silk_MUL_uint_(opus_uint32 a32, opus_uint32 b32, char *file, int line){
+ opus_uint32 ret;
+ ret = a32 * b32;
+ if ( (opus_uint64)ret != (opus_uint64)a32 * (opus_uint64)b32 )
+ {
+ fprintf (stderr, "silk_MUL_uint(%u, %u) in %s: line %d\n", a32, b32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_MLA
+#define silk_MLA(a,b,c) silk_MLA_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_MLA_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){
+ opus_int32 ret;
+ ret = a32 + b32 * c32;
+ if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (opus_int64)c32 )
+ {
+ fprintf (stderr, "silk_MLA(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_MLA_uint
+#define silk_MLA_uint(a,b,c) silk_MLA_uint_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_MLA_uint_(opus_uint32 a32, opus_uint32 b32, opus_uint32 c32, char *file, int line){
+ opus_uint32 ret;
+ ret = a32 + b32 * c32;
+ if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (opus_int64)c32 )
+ {
+ fprintf (stderr, "silk_MLA_uint(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_SMULWB
+#define silk_SMULWB(a,b) silk_SMULWB_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SMULWB_(opus_int32 a32, opus_int32 b32, char *file, int line){
+ opus_int32 ret;
+ ret = (a32 >> 16) * (opus_int32)((opus_int16)b32) + (((a32 & 0x0000FFFF) * (opus_int32)((opus_int16)b32)) >> 16);
+ if ( (opus_int64)ret != ((opus_int64)a32 * (opus_int16)b32) >> 16 )
+ {
+ fprintf (stderr, "silk_SMULWB(%d, %d) in %s: line %d\n", a32, b32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_SMLAWB
+#define silk_SMLAWB(a,b,c) silk_SMLAWB_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SMLAWB_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){
+ opus_int32 ret;
+ ret = silk_ADD32( a32, silk_SMULWB( b32, c32 ) );
+ if ( silk_ADD32( a32, silk_SMULWB( b32, c32 ) ) != silk_ADD_SAT32( a32, silk_SMULWB( b32, c32 ) ) )
+ {
+ fprintf (stderr, "silk_SMLAWB(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_SMULWT
+#define silk_SMULWT(a,b) silk_SMULWT_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SMULWT_(opus_int32 a32, opus_int32 b32, char *file, int line){
+ opus_int32 ret;
+ ret = (a32 >> 16) * (b32 >> 16) + (((a32 & 0x0000FFFF) * (b32 >> 16)) >> 16);
+ if ( (opus_int64)ret != ((opus_int64)a32 * (b32 >> 16)) >> 16 )
+ {
+ fprintf (stderr, "silk_SMULWT(%d, %d) in %s: line %d\n", a32, b32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_SMLAWT
+#define silk_SMLAWT(a,b,c) silk_SMLAWT_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SMLAWT_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){
+ opus_int32 ret;
+ ret = a32 + ((b32 >> 16) * (c32 >> 16)) + (((b32 & 0x0000FFFF) * ((c32 >> 16)) >> 16));
+ if ( (opus_int64)ret != (opus_int64)a32 + (((opus_int64)b32 * (c32 >> 16)) >> 16) )
+ {
+ fprintf (stderr, "silk_SMLAWT(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_SMULL
+#define silk_SMULL(a,b) silk_SMULL_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int64 silk_SMULL_(opus_int64 a64, opus_int64 b64, char *file, int line){
+ opus_int64 ret64;
+ int fail = 0;
+ ret64 = a64 * b64;
+ if( b64 != 0 ) {
+ fail = a64 != (ret64 / b64);
+ } else if( a64 != 0 ) {
+ fail = b64 != (ret64 / a64);
+ }
+ if ( fail )
+ {
+ fprintf (stderr, "silk_SMULL(%lld, %lld) in %s: line %d\n", (long long)a64, (long long)b64, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret64;
+}
+
+/* no checking needed for silk_SMULBB */
+#undef silk_SMLABB
+#define silk_SMLABB(a,b,c) silk_SMLABB_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SMLABB_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){
+ opus_int32 ret;
+ ret = a32 + (opus_int32)((opus_int16)b32) * (opus_int32)((opus_int16)c32);
+ if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (opus_int16)c32 )
+ {
+ fprintf (stderr, "silk_SMLABB(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+/* no checking needed for silk_SMULBT */
+#undef silk_SMLABT
+#define silk_SMLABT(a,b,c) silk_SMLABT_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SMLABT_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){
+ opus_int32 ret;
+ ret = a32 + ((opus_int32)((opus_int16)b32)) * (c32 >> 16);
+ if ( (opus_int64)ret != (opus_int64)a32 + (opus_int64)b32 * (c32 >> 16) )
+ {
+ fprintf (stderr, "silk_SMLABT(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+/* no checking needed for silk_SMULTT */
+#undef silk_SMLATT
+#define silk_SMLATT(a,b,c) silk_SMLATT_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SMLATT_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){
+ opus_int32 ret;
+ ret = a32 + (b32 >> 16) * (c32 >> 16);
+ if ( (opus_int64)ret != (opus_int64)a32 + (b32 >> 16) * (c32 >> 16) )
+ {
+ fprintf (stderr, "silk_SMLATT(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_SMULWW
+#define silk_SMULWW(a,b) silk_SMULWW_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SMULWW_(opus_int32 a32, opus_int32 b32, char *file, int line){
+ opus_int32 ret, tmp1, tmp2;
+ opus_int64 ret64;
+ int fail = 0;
+
+ ret = silk_SMULWB( a32, b32 );
+ tmp1 = silk_RSHIFT_ROUND( b32, 16 );
+ tmp2 = silk_MUL( a32, tmp1 );
+
+ fail |= (opus_int64)tmp2 != (opus_int64) a32 * (opus_int64) tmp1;
+
+ tmp1 = ret;
+ ret = silk_ADD32( tmp1, tmp2 );
+ fail |= silk_ADD32( tmp1, tmp2 ) != silk_ADD_SAT32( tmp1, tmp2 );
+
+ ret64 = silk_RSHIFT64( silk_SMULL( a32, b32 ), 16 );
+ fail |= (opus_int64)ret != ret64;
+
+ if ( fail )
+ {
+ fprintf (stderr, "silk_SMULWT(%d, %d) in %s: line %d\n", a32, b32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+
+ return ret;
+}
+
+#undef silk_SMLAWW
+#define silk_SMLAWW(a,b,c) silk_SMLAWW_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SMLAWW_(opus_int32 a32, opus_int32 b32, opus_int32 c32, char *file, int line){
+ opus_int32 ret, tmp;
+
+ tmp = silk_SMULWW( b32, c32 );
+ ret = silk_ADD32( a32, tmp );
+ if ( ret != silk_ADD_SAT32( a32, tmp ) )
+ {
+ fprintf (stderr, "silk_SMLAWW(%d, %d, %d) in %s: line %d\n", a32, b32, c32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+/* Multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode) */
+#undef silk_MLA_ovflw
+#define silk_MLA_ovflw(a32, b32, c32) ((a32) + ((b32) * (c32)))
+#undef silk_SMLABB_ovflw
+#define silk_SMLABB_ovflw(a32, b32, c32) ((a32) + ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32)))
+
+/* no checking needed for silk_SMULL
+ no checking needed for silk_SMLAL
+ no checking needed for silk_SMLALBB
+ no checking needed for SigProcFIX_CLZ16
+ no checking needed for SigProcFIX_CLZ32*/
+
+#undef silk_DIV32
+#define silk_DIV32(a,b) silk_DIV32_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_DIV32_(opus_int32 a32, opus_int32 b32, char *file, int line){
+ if ( b32 == 0 )
+ {
+ fprintf (stderr, "silk_DIV32(%d, %d) in %s: line %d\n", a32, b32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return a32 / b32;
+}
+
+#undef silk_DIV32_16
+#define silk_DIV32_16(a,b) silk_DIV32_16_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_DIV32_16_(opus_int32 a32, opus_int32 b32, char *file, int line){
+ int fail = 0;
+ fail |= b32 == 0;
+ fail |= b32 > silk_int16_MAX;
+ fail |= b32 < silk_int16_MIN;
+ if ( fail )
+ {
+ fprintf (stderr, "silk_DIV32_16(%d, %d) in %s: line %d\n", a32, b32, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return a32 / b32;
+}
+
+/* no checking needed for silk_SAT8
+ no checking needed for silk_SAT16
+ no checking needed for silk_SAT32
+ no checking needed for silk_POS_SAT32
+ no checking needed for silk_ADD_POS_SAT8
+ no checking needed for silk_ADD_POS_SAT16
+ no checking needed for silk_ADD_POS_SAT32
+ no checking needed for silk_ADD_POS_SAT64 */
+
+#undef silk_LSHIFT8
+#define silk_LSHIFT8(a,b) silk_LSHIFT8_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int8 silk_LSHIFT8_(opus_int8 a, opus_int32 shift, char *file, int line){
+ opus_int8 ret;
+ int fail = 0;
+ ret = a << shift;
+ fail |= shift < 0;
+ fail |= shift >= 8;
+ fail |= (opus_int64)ret != ((opus_int64)a) << shift;
+ if ( fail )
+ {
+ fprintf (stderr, "silk_LSHIFT8(%d, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_LSHIFT16
+#define silk_LSHIFT16(a,b) silk_LSHIFT16_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int16 silk_LSHIFT16_(opus_int16 a, opus_int32 shift, char *file, int line){
+ opus_int16 ret;
+ int fail = 0;
+ ret = a << shift;
+ fail |= shift < 0;
+ fail |= shift >= 16;
+ fail |= (opus_int64)ret != ((opus_int64)a) << shift;
+ if ( fail )
+ {
+ fprintf (stderr, "silk_LSHIFT16(%d, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_LSHIFT32
+#define silk_LSHIFT32(a,b) silk_LSHIFT32_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_LSHIFT32_(opus_int32 a, opus_int32 shift, char *file, int line){
+ opus_int32 ret;
+ int fail = 0;
+ ret = a << shift;
+ fail |= shift < 0;
+ fail |= shift >= 32;
+ fail |= (opus_int64)ret != ((opus_int64)a) << shift;
+ if ( fail )
+ {
+ fprintf (stderr, "silk_LSHIFT32(%d, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_LSHIFT64
+#define silk_LSHIFT64(a,b) silk_LSHIFT64_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int64 silk_LSHIFT64_(opus_int64 a, opus_int shift, char *file, int line){
+ opus_int64 ret;
+ int fail = 0;
+ ret = a << shift;
+ fail |= shift < 0;
+ fail |= shift >= 64;
+ fail |= (ret>>shift) != ((opus_int64)a);
+ if ( fail )
+ {
+ fprintf (stderr, "silk_LSHIFT64(%lld, %d) in %s: line %d\n", (long long)a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_LSHIFT_ovflw
+#define silk_LSHIFT_ovflw(a,b) silk_LSHIFT_ovflw_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_LSHIFT_ovflw_(opus_int32 a, opus_int32 shift, char *file, int line){
+ if ( (shift < 0) || (shift >= 32) ) /* no check for overflow */
+ {
+ fprintf (stderr, "silk_LSHIFT_ovflw(%d, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return a << shift;
+}
+
+#undef silk_LSHIFT_uint
+#define silk_LSHIFT_uint(a,b) silk_LSHIFT_uint_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_uint32 silk_LSHIFT_uint_(opus_uint32 a, opus_int32 shift, char *file, int line){
+ opus_uint32 ret;
+ ret = a << shift;
+ if ( (shift < 0) || ((opus_int64)ret != ((opus_int64)a) << shift))
+ {
+ fprintf (stderr, "silk_LSHIFT_uint(%u, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_RSHIFT8
+#define silk_RSHITF8(a,b) silk_RSHIFT8_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int8 silk_RSHIFT8_(opus_int8 a, opus_int32 shift, char *file, int line){
+ if ( (shift < 0) || (shift>=8) )
+ {
+ fprintf (stderr, "silk_RSHITF8(%d, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return a >> shift;
+}
+
+#undef silk_RSHIFT16
+#define silk_RSHITF16(a,b) silk_RSHIFT16_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int16 silk_RSHIFT16_(opus_int16 a, opus_int32 shift, char *file, int line){
+ if ( (shift < 0) || (shift>=16) )
+ {
+ fprintf (stderr, "silk_RSHITF16(%d, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return a >> shift;
+}
+
+#undef silk_RSHIFT32
+#define silk_RSHIFT32(a,b) silk_RSHIFT32_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_RSHIFT32_(opus_int32 a, opus_int32 shift, char *file, int line){
+ if ( (shift < 0) || (shift>=32) )
+ {
+ fprintf (stderr, "silk_RSHITF32(%d, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return a >> shift;
+}
+
+#undef silk_RSHIFT64
+#define silk_RSHIFT64(a,b) silk_RSHIFT64_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int64 silk_RSHIFT64_(opus_int64 a, opus_int64 shift, char *file, int line){
+ if ( (shift < 0) || (shift>=64) )
+ {
+ fprintf (stderr, "silk_RSHITF64(%lld, %lld) in %s: line %d\n", (long long)a, (long long)shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return a >> shift;
+}
+
+#undef silk_RSHIFT_uint
+#define silk_RSHIFT_uint(a,b) silk_RSHIFT_uint_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_uint32 silk_RSHIFT_uint_(opus_uint32 a, opus_int32 shift, char *file, int line){
+ if ( (shift < 0) || (shift>32) )
+ {
+ fprintf (stderr, "silk_RSHIFT_uint(%u, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return a >> shift;
+}
+
+#undef silk_ADD_LSHIFT
+#define silk_ADD_LSHIFT(a,b,c) silk_ADD_LSHIFT_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE int silk_ADD_LSHIFT_(int a, int b, int shift, char *file, int line){
+ opus_int16 ret;
+ ret = a + (b << shift);
+ if ( (shift < 0) || (shift>15) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) << shift)) )
+ {
+ fprintf (stderr, "silk_ADD_LSHIFT(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret; /* shift >= 0 */
+}
+
+#undef silk_ADD_LSHIFT32
+#define silk_ADD_LSHIFT32(a,b,c) silk_ADD_LSHIFT32_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_ADD_LSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){
+ opus_int32 ret;
+ ret = a + (b << shift);
+ if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) << shift)) )
+ {
+ fprintf (stderr, "silk_ADD_LSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret; /* shift >= 0 */
+}
+
+#undef silk_ADD_LSHIFT_uint
+#define silk_ADD_LSHIFT_uint(a,b,c) silk_ADD_LSHIFT_uint_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_uint32 silk_ADD_LSHIFT_uint_(opus_uint32 a, opus_uint32 b, opus_int32 shift, char *file, int line){
+ opus_uint32 ret;
+ ret = a + (b << shift);
+ if ( (shift < 0) || (shift>32) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) << shift)) )
+ {
+ fprintf (stderr, "silk_ADD_LSHIFT_uint(%u, %u, %d) in %s: line %d\n", a, b, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret; /* shift >= 0 */
+}
+
+#undef silk_ADD_RSHIFT
+#define silk_ADD_RSHIFT(a,b,c) silk_ADD_RSHIFT_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE int silk_ADD_RSHIFT_(int a, int b, int shift, char *file, int line){
+ opus_int16 ret;
+ ret = a + (b >> shift);
+ if ( (shift < 0) || (shift>15) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) >> shift)) )
+ {
+ fprintf (stderr, "silk_ADD_RSHIFT(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret; /* shift > 0 */
+}
+
+#undef silk_ADD_RSHIFT32
+#define silk_ADD_RSHIFT32(a,b,c) silk_ADD_RSHIFT32_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_ADD_RSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){
+ opus_int32 ret;
+ ret = a + (b >> shift);
+ if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) >> shift)) )
+ {
+ fprintf (stderr, "silk_ADD_RSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret; /* shift > 0 */
+}
+
+#undef silk_ADD_RSHIFT_uint
+#define silk_ADD_RSHIFT_uint(a,b,c) silk_ADD_RSHIFT_uint_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_uint32 silk_ADD_RSHIFT_uint_(opus_uint32 a, opus_uint32 b, opus_int32 shift, char *file, int line){
+ opus_uint32 ret;
+ ret = a + (b >> shift);
+ if ( (shift < 0) || (shift>32) || ((opus_int64)ret != (opus_int64)a + (((opus_int64)b) >> shift)) )
+ {
+ fprintf (stderr, "silk_ADD_RSHIFT_uint(%u, %u, %d) in %s: line %d\n", a, b, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret; /* shift > 0 */
+}
+
+#undef silk_SUB_LSHIFT32
+#define silk_SUB_LSHIFT32(a,b,c) silk_SUB_LSHIFT32_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SUB_LSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){
+ opus_int32 ret;
+ ret = a - (b << shift);
+ if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a - (((opus_int64)b) << shift)) )
+ {
+ fprintf (stderr, "silk_SUB_LSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret; /* shift >= 0 */
+}
+
+#undef silk_SUB_RSHIFT32
+#define silk_SUB_RSHIFT32(a,b,c) silk_SUB_RSHIFT32_((a), (b), (c), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_SUB_RSHIFT32_(opus_int32 a, opus_int32 b, opus_int32 shift, char *file, int line){
+ opus_int32 ret;
+ ret = a - (b >> shift);
+ if ( (shift < 0) || (shift>31) || ((opus_int64)ret != (opus_int64)a - (((opus_int64)b) >> shift)) )
+ {
+ fprintf (stderr, "silk_SUB_RSHIFT32(%d, %d, %d) in %s: line %d\n", a, b, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret; /* shift > 0 */
+}
+
+#undef silk_RSHIFT_ROUND
+#define silk_RSHIFT_ROUND(a,b) silk_RSHIFT_ROUND_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_RSHIFT_ROUND_(opus_int32 a, opus_int32 shift, char *file, int line){
+ opus_int32 ret;
+ ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1;
+ /* the marco definition can't handle a shift of zero */
+ if ( (shift <= 0) || (shift>31) || ((opus_int64)ret != ((opus_int64)a + ((opus_int64)1 << (shift - 1))) >> shift) )
+ {
+ fprintf (stderr, "silk_RSHIFT_ROUND(%d, %d) in %s: line %d\n", a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return ret;
+}
+
+#undef silk_RSHIFT_ROUND64
+#define silk_RSHIFT_ROUND64(a,b) silk_RSHIFT_ROUND64_((a), (b), __FILE__, __LINE__)
+static OPUS_INLINE opus_int64 silk_RSHIFT_ROUND64_(opus_int64 a, opus_int32 shift, char *file, int line){
+ opus_int64 ret;
+ /* the marco definition can't handle a shift of zero */
+ if ( (shift <= 0) || (shift>=64) )
+ {
+ fprintf (stderr, "silk_RSHIFT_ROUND64(%lld, %d) in %s: line %d\n", (long long)a, shift, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ ret = shift == 1 ? (a >> 1) + (a & 1) : ((a >> (shift - 1)) + 1) >> 1;
+ return ret;
+}
+
+/* silk_abs is used on floats also, so doesn't work... */
+/*#undef silk_abs
+static OPUS_INLINE opus_int32 silk_abs(opus_int32 a){
+ silk_assert(a != 0x80000000);
+ return (((a) > 0) ? (a) : -(a)); // Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN
+}*/
+
+#undef silk_abs_int64
+#define silk_abs_int64(a) silk_abs_int64_((a), __FILE__, __LINE__)
+static OPUS_INLINE opus_int64 silk_abs_int64_(opus_int64 a, char *file, int line){
+ if ( a == silk_int64_MIN )
+ {
+ fprintf (stderr, "silk_abs_int64(%lld) in %s: line %d\n", (long long)a, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return (((a) > 0) ? (a) : -(a)); /* Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN */
+}
+
+#undef silk_abs_int32
+#define silk_abs_int32(a) silk_abs_int32_((a), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_abs_int32_(opus_int32 a, char *file, int line){
+ if ( a == silk_int32_MIN )
+ {
+ fprintf (stderr, "silk_abs_int32(%d) in %s: line %d\n", a, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return silk_abs(a);
+}
+
+#undef silk_CHECK_FIT8
+#define silk_CHECK_FIT8(a) silk_CHECK_FIT8_((a), __FILE__, __LINE__)
+static OPUS_INLINE opus_int8 silk_CHECK_FIT8_( opus_int64 a, char *file, int line ){
+ opus_int8 ret;
+ ret = (opus_int8)a;
+ if ( (opus_int64)ret != a )
+ {
+ fprintf (stderr, "silk_CHECK_FIT8(%lld) in %s: line %d\n", (long long)a, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return( ret );
+}
+
+#undef silk_CHECK_FIT16
+#define silk_CHECK_FIT16(a) silk_CHECK_FIT16_((a), __FILE__, __LINE__)
+static OPUS_INLINE opus_int16 silk_CHECK_FIT16_( opus_int64 a, char *file, int line ){
+ opus_int16 ret;
+ ret = (opus_int16)a;
+ if ( (opus_int64)ret != a )
+ {
+ fprintf (stderr, "silk_CHECK_FIT16(%lld) in %s: line %d\n", (long long)a, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return( ret );
+}
+
+#undef silk_CHECK_FIT32
+#define silk_CHECK_FIT32(a) silk_CHECK_FIT32_((a), __FILE__, __LINE__)
+static OPUS_INLINE opus_int32 silk_CHECK_FIT32_( opus_int64 a, char *file, int line ){
+ opus_int32 ret;
+ ret = (opus_int32)a;
+ if ( (opus_int64)ret != a )
+ {
+ fprintf (stderr, "silk_CHECK_FIT32(%lld) in %s: line %d\n", (long long)a, file, line);
+#ifdef FIXED_DEBUG_ASSERT
+ silk_assert( 0 );
+#endif
+ }
+ return( ret );
+}
+
+/* no checking for silk_NSHIFT_MUL_32_32
+ no checking for silk_NSHIFT_MUL_16_16
+ no checking needed for silk_min
+ no checking needed for silk_max
+ no checking needed for silk_sign
+*/
+
+#endif
+#endif /* MACRO_DEBUG_H */
diff --git a/drivers/opus/silk/NLSF2A.c b/drivers/opus/silk/NLSF2A.c
new file mode 100644
index 0000000000..c3b8568a0c
--- /dev/null
+++ b/drivers/opus/silk/NLSF2A.c
@@ -0,0 +1,178 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+/* conversion between prediction filter coefficients and LSFs */
+/* order should be even */
+/* a piecewise linear approximation maps LSF <-> cos(LSF) */
+/* therefore the result is not accurate LSFs, but the two */
+/* functions are accurate inverses of each other */
+
+#include "opus/silk/SigProc_FIX.h"
+#include "opus/silk/tables.h"
+
+#define QA 16
+
+/* helper function for NLSF2A(..) */
+static OPUS_INLINE void silk_NLSF2A_find_poly(
+ opus_int32 *out, /* O intermediate polynomial, QA [dd+1] */
+ const opus_int32 *cLSF, /* I vector of interleaved 2*cos(LSFs), QA [d] */
+ opus_int dd /* I polynomial order (= 1/2 * filter order) */
+)
+{
+ opus_int k, n;
+ opus_int32 ftmp;
+
+ out[0] = silk_LSHIFT( 1, QA );
+ out[1] = -cLSF[0];
+ for( k = 1; k < dd; k++ ) {
+ ftmp = cLSF[2*k]; /* QA*/
+ out[k+1] = silk_LSHIFT( out[k-1], 1 ) - (opus_int32)silk_RSHIFT_ROUND64( silk_SMULL( ftmp, out[k] ), QA );
+ for( n = k; n > 1; n-- ) {
+ out[n] += out[n-2] - (opus_int32)silk_RSHIFT_ROUND64( silk_SMULL( ftmp, out[n-1] ), QA );
+ }
+ out[1] -= ftmp;
+ }
+}
+
+/* compute whitening filter coefficients from normalized line spectral frequencies */
+void silk_NLSF2A(
+ opus_int16 *a_Q12, /* O monic whitening filter coefficients in Q12, [ d ] */
+ const opus_int16 *NLSF, /* I normalized line spectral frequencies in Q15, [ d ] */
+ const opus_int d /* I filter order (should be even) */
+)
+{
+ /* This ordering was found to maximize quality. It improves numerical accuracy of
+ silk_NLSF2A_find_poly() compared to "standard" ordering. */
+ static const unsigned char ordering16[16] = {
+ 0, 15, 8, 7, 4, 11, 12, 3, 2, 13, 10, 5, 6, 9, 14, 1
+ };
+ static const unsigned char ordering10[10] = {
+ 0, 9, 6, 3, 4, 5, 8, 1, 2, 7
+ };
+ const unsigned char *ordering;
+ opus_int k, i, dd;
+ opus_int32 cos_LSF_QA[ SILK_MAX_ORDER_LPC ];
+ opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ], Q[ SILK_MAX_ORDER_LPC / 2 + 1 ];
+ opus_int32 Ptmp, Qtmp, f_int, f_frac, cos_val, delta;
+ opus_int32 a32_QA1[ SILK_MAX_ORDER_LPC ];
+ opus_int32 maxabs, absval, idx=0, sc_Q16;
+
+ silk_assert( LSF_COS_TAB_SZ_FIX == 128 );
+ silk_assert( d==10||d==16 );
+
+ /* convert LSFs to 2*cos(LSF), using piecewise linear curve from table */
+ ordering = d == 16 ? ordering16 : ordering10;
+ for( k = 0; k < d; k++ ) {
+ silk_assert(NLSF[k] >= 0 );
+
+ /* f_int on a scale 0-127 (rounded down) */
+ f_int = silk_RSHIFT( NLSF[k], 15 - 7 );
+
+ /* f_frac, range: 0..255 */
+ f_frac = NLSF[k] - silk_LSHIFT( f_int, 15 - 7 );
+
+ silk_assert(f_int >= 0);
+ silk_assert(f_int < LSF_COS_TAB_SZ_FIX );
+
+ /* Read start and end value from table */
+ cos_val = silk_LSFCosTab_FIX_Q12[ f_int ]; /* Q12 */
+ delta = silk_LSFCosTab_FIX_Q12[ f_int + 1 ] - cos_val; /* Q12, with a range of 0..200 */
+
+ /* Linear interpolation */
+ cos_LSF_QA[ordering[k]] = silk_RSHIFT_ROUND( silk_LSHIFT( cos_val, 8 ) + silk_MUL( delta, f_frac ), 20 - QA ); /* QA */
+ }
+
+ dd = silk_RSHIFT( d, 1 );
+
+ /* generate even and odd polynomials using convolution */
+ silk_NLSF2A_find_poly( P, &cos_LSF_QA[ 0 ], dd );
+ silk_NLSF2A_find_poly( Q, &cos_LSF_QA[ 1 ], dd );
+
+ /* convert even and odd polynomials to opus_int32 Q12 filter coefs */
+ for( k = 0; k < dd; k++ ) {
+ Ptmp = P[ k+1 ] + P[ k ];
+ Qtmp = Q[ k+1 ] - Q[ k ];
+
+ /* the Ptmp and Qtmp values at this stage need to fit in int32 */
+ a32_QA1[ k ] = -Qtmp - Ptmp; /* QA+1 */
+ a32_QA1[ d-k-1 ] = Qtmp - Ptmp; /* QA+1 */
+ }
+
+ /* Limit the maximum absolute value of the prediction coefficients, so that they'll fit in int16 */
+ for( i = 0; i < 10; i++ ) {
+ /* Find maximum absolute value and its index */
+ maxabs = 0;
+ for( k = 0; k < d; k++ ) {
+ absval = silk_abs( a32_QA1[k] );
+ if( absval > maxabs ) {
+ maxabs = absval;
+ idx = k;
+ }
+ }
+ maxabs = silk_RSHIFT_ROUND( maxabs, QA + 1 - 12 ); /* QA+1 -> Q12 */
+
+ if( maxabs > silk_int16_MAX ) {
+ /* Reduce magnitude of prediction coefficients */
+ maxabs = silk_min( maxabs, 163838 ); /* ( silk_int32_MAX >> 14 ) + silk_int16_MAX = 163838 */
+ sc_Q16 = SILK_FIX_CONST( 0.999, 16 ) - silk_DIV32( silk_LSHIFT( maxabs - silk_int16_MAX, 14 ),
+ silk_RSHIFT32( silk_MUL( maxabs, idx + 1), 2 ) );
+ silk_bwexpander_32( a32_QA1, d, sc_Q16 );
+ } else {
+ break;
+ }
+ }
+
+ if( i == 10 ) {
+ /* Reached the last iteration, clip the coefficients */
+ for( k = 0; k < d; k++ ) {
+ a_Q12[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ) ); /* QA+1 -> Q12 */
+ a32_QA1[ k ] = silk_LSHIFT( (opus_int32)a_Q12[ k ], QA + 1 - 12 );
+ }
+ } else {
+ for( k = 0; k < d; k++ ) {
+ a_Q12[ k ] = (opus_int16)silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ); /* QA+1 -> Q12 */
+ }
+ }
+
+ for( i = 0; i < MAX_LPC_STABILIZE_ITERATIONS; i++ ) {
+ if( silk_LPC_inverse_pred_gain( a_Q12, d ) < SILK_FIX_CONST( 1.0 / MAX_PREDICTION_POWER_GAIN, 30 ) ) {
+ /* Prediction coefficients are (too close to) unstable; apply bandwidth expansion */
+ /* on the unscaled coefficients, convert to Q12 and measure again */
+ silk_bwexpander_32( a32_QA1, d, 65536 - silk_LSHIFT( 2, i ) );
+ for( k = 0; k < d; k++ ) {
+ a_Q12[ k ] = (opus_int16)silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ); /* QA+1 -> Q12 */
+ }
+ } else {
+ break;
+ }
+ }
+}
+
diff --git a/drivers/opus/silk/NLSF_VQ.c b/drivers/opus/silk/NLSF_VQ.c
new file mode 100644
index 0000000000..9420f5bfb9
--- /dev/null
+++ b/drivers/opus/silk/NLSF_VQ.c
@@ -0,0 +1,68 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+
+/* Compute quantization errors for an LPC_order element input vector for a VQ codebook */
+void silk_NLSF_VQ(
+ opus_int32 err_Q26[], /* O Quantization errors [K] */
+ const opus_int16 in_Q15[], /* I Input vectors to be quantized [LPC_order] */
+ const opus_uint8 pCB_Q8[], /* I Codebook vectors [K*LPC_order] */
+ const opus_int K, /* I Number of codebook vectors */
+ const opus_int LPC_order /* I Number of LPCs */
+)
+{
+ opus_int i, m;
+ opus_int32 diff_Q15, sum_error_Q30, sum_error_Q26;
+
+ silk_assert( LPC_order <= 16 );
+ silk_assert( ( LPC_order & 1 ) == 0 );
+
+ /* Loop over codebook */
+ for( i = 0; i < K; i++ ) {
+ sum_error_Q26 = 0;
+ for( m = 0; m < LPC_order; m += 2 ) {
+ /* Compute weighted squared quantization error for index m */
+ diff_Q15 = silk_SUB_LSHIFT32( in_Q15[ m ], (opus_int32)*pCB_Q8++, 7 ); /* range: [ -32767 : 32767 ]*/
+ sum_error_Q30 = silk_SMULBB( diff_Q15, diff_Q15 );
+
+ /* Compute weighted squared quantization error for index m + 1 */
+ diff_Q15 = silk_SUB_LSHIFT32( in_Q15[m + 1], (opus_int32)*pCB_Q8++, 7 ); /* range: [ -32767 : 32767 ]*/
+ sum_error_Q30 = silk_SMLABB( sum_error_Q30, diff_Q15, diff_Q15 );
+
+ sum_error_Q26 = silk_ADD_RSHIFT32( sum_error_Q26, sum_error_Q30, 4 );
+
+ silk_assert( sum_error_Q26 >= 0 );
+ silk_assert( sum_error_Q30 >= 0 );
+ }
+ err_Q26[ i ] = sum_error_Q26;
+ }
+}
diff --git a/drivers/opus/silk/NLSF_VQ_weights_laroia.c b/drivers/opus/silk/NLSF_VQ_weights_laroia.c
new file mode 100644
index 0000000000..d3b4fd6401
--- /dev/null
+++ b/drivers/opus/silk/NLSF_VQ_weights_laroia.c
@@ -0,0 +1,80 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/define.h"
+#include "opus/silk/SigProc_FIX.h"
+
+/*
+R. Laroia, N. Phamdo and N. Farvardin, "Robust and Efficient Quantization of Speech LSP
+Parameters Using Structured Vector Quantization", Proc. IEEE Int. Conf. Acoust., Speech,
+Signal Processing, pp. 641-644, 1991.
+*/
+
+/* Laroia low complexity NLSF weights */
+void silk_NLSF_VQ_weights_laroia(
+ opus_int16 *pNLSFW_Q_OUT, /* O Pointer to input vector weights [D] */
+ const opus_int16 *pNLSF_Q15, /* I Pointer to input vector [D] */
+ const opus_int D /* I Input vector dimension (even) */
+)
+{
+ opus_int k;
+ opus_int32 tmp1_int, tmp2_int;
+
+ silk_assert( D > 0 );
+ silk_assert( ( D & 1 ) == 0 );
+
+ /* First value */
+ tmp1_int = silk_max_int( pNLSF_Q15[ 0 ], 1 );
+ tmp1_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp1_int );
+ tmp2_int = silk_max_int( pNLSF_Q15[ 1 ] - pNLSF_Q15[ 0 ], 1 );
+ tmp2_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp2_int );
+ pNLSFW_Q_OUT[ 0 ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX );
+ silk_assert( pNLSFW_Q_OUT[ 0 ] > 0 );
+
+ /* Main loop */
+ for( k = 1; k < D - 1; k += 2 ) {
+ tmp1_int = silk_max_int( pNLSF_Q15[ k + 1 ] - pNLSF_Q15[ k ], 1 );
+ tmp1_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp1_int );
+ pNLSFW_Q_OUT[ k ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX );
+ silk_assert( pNLSFW_Q_OUT[ k ] > 0 );
+
+ tmp2_int = silk_max_int( pNLSF_Q15[ k + 2 ] - pNLSF_Q15[ k + 1 ], 1 );
+ tmp2_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp2_int );
+ pNLSFW_Q_OUT[ k + 1 ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX );
+ silk_assert( pNLSFW_Q_OUT[ k + 1 ] > 0 );
+ }
+
+ /* Last value */
+ tmp1_int = silk_max_int( ( 1 << 15 ) - pNLSF_Q15[ D - 1 ], 1 );
+ tmp1_int = silk_DIV32_16( (opus_int32)1 << ( 15 + NLSF_W_Q ), tmp1_int );
+ pNLSFW_Q_OUT[ D - 1 ] = (opus_int16)silk_min_int( tmp1_int + tmp2_int, silk_int16_MAX );
+ silk_assert( pNLSFW_Q_OUT[ D - 1 ] > 0 );
+}
diff --git a/drivers/opus/silk/NLSF_decode.c b/drivers/opus/silk/NLSF_decode.c
new file mode 100644
index 0000000000..6868a93858
--- /dev/null
+++ b/drivers/opus/silk/NLSF_decode.c
@@ -0,0 +1,101 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+
+/* Predictive dequantizer for NLSF residuals */
+static OPUS_INLINE void silk_NLSF_residual_dequant( /* O Returns RD value in Q30 */
+ opus_int16 x_Q10[], /* O Output [ order ] */
+ const opus_int8 indices[], /* I Quantization indices [ order ] */
+ const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */
+ const opus_int quant_step_size_Q16, /* I Quantization step size */
+ const opus_int16 order /* I Number of input values */
+)
+{
+ opus_int i, out_Q10, pred_Q10;
+
+ out_Q10 = 0;
+ for( i = order-1; i >= 0; i-- ) {
+ pred_Q10 = silk_RSHIFT( silk_SMULBB( out_Q10, (opus_int16)pred_coef_Q8[ i ] ), 8 );
+ out_Q10 = silk_LSHIFT( indices[ i ], 10 );
+ if( out_Q10 > 0 ) {
+ out_Q10 = silk_SUB16( out_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+ } else if( out_Q10 < 0 ) {
+ out_Q10 = silk_ADD16( out_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+ }
+ out_Q10 = silk_SMLAWB( pred_Q10, (opus_int32)out_Q10, quant_step_size_Q16 );
+ x_Q10[ i ] = out_Q10;
+ }
+}
+
+
+/***********************/
+/* NLSF vector decoder */
+/***********************/
+void silk_NLSF_decode(
+ opus_int16 *pNLSF_Q15, /* O Quantized NLSF vector [ LPC_ORDER ] */
+ opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */
+ const silk_NLSF_CB_struct *psNLSF_CB /* I Codebook object */
+)
+{
+ opus_int i;
+ opus_uint8 pred_Q8[ MAX_LPC_ORDER ];
+ opus_int16 ec_ix[ MAX_LPC_ORDER ];
+ opus_int16 res_Q10[ MAX_LPC_ORDER ];
+ opus_int16 W_tmp_QW[ MAX_LPC_ORDER ];
+ opus_int32 W_tmp_Q9, NLSF_Q15_tmp;
+ const opus_uint8 *pCB_element;
+
+ /* Decode first stage */
+ pCB_element = &psNLSF_CB->CB1_NLSF_Q8[ NLSFIndices[ 0 ] * psNLSF_CB->order ];
+ for( i = 0; i < psNLSF_CB->order; i++ ) {
+ pNLSF_Q15[ i ] = silk_LSHIFT( (opus_int16)pCB_element[ i ], 7 );
+ }
+
+ /* Unpack entropy table indices and predictor for current CB1 index */
+ silk_NLSF_unpack( ec_ix, pred_Q8, psNLSF_CB, NLSFIndices[ 0 ] );
+
+ /* Predictive residual dequantizer */
+ silk_NLSF_residual_dequant( res_Q10, &NLSFIndices[ 1 ], pred_Q8, psNLSF_CB->quantStepSize_Q16, psNLSF_CB->order );
+
+ /* Weights from codebook vector */
+ silk_NLSF_VQ_weights_laroia( W_tmp_QW, pNLSF_Q15, psNLSF_CB->order );
+
+ /* Apply inverse square-rooted weights and add to output */
+ for( i = 0; i < psNLSF_CB->order; i++ ) {
+ W_tmp_Q9 = silk_SQRT_APPROX( silk_LSHIFT( (opus_int32)W_tmp_QW[ i ], 18 - NLSF_W_Q ) );
+ NLSF_Q15_tmp = silk_ADD32( pNLSF_Q15[ i ], silk_DIV32_16( silk_LSHIFT( (opus_int32)res_Q10[ i ], 14 ), W_tmp_Q9 ) );
+ pNLSF_Q15[ i ] = (opus_int16)silk_LIMIT( NLSF_Q15_tmp, 0, 32767 );
+ }
+
+ /* NLSF stabilization */
+ silk_NLSF_stabilize( pNLSF_Q15, psNLSF_CB->deltaMin_Q15, psNLSF_CB->order );
+}
diff --git a/drivers/opus/silk/NLSF_del_dec_quant.c b/drivers/opus/silk/NLSF_del_dec_quant.c
new file mode 100644
index 0000000000..9caeb0a23b
--- /dev/null
+++ b/drivers/opus/silk/NLSF_del_dec_quant.c
@@ -0,0 +1,207 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+
+/* Delayed-decision quantizer for NLSF residuals */
+opus_int32 silk_NLSF_del_dec_quant( /* O Returns RD value in Q25 */
+ opus_int8 indices[], /* O Quantization indices [ order ] */
+ const opus_int16 x_Q10[], /* I Input [ order ] */
+ const opus_int16 w_Q5[], /* I Weights [ order ] */
+ const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */
+ const opus_int16 ec_ix[], /* I Indices to entropy coding tables [ order ] */
+ const opus_uint8 ec_rates_Q5[], /* I Rates [] */
+ const opus_int quant_step_size_Q16, /* I Quantization step size */
+ const opus_int16 inv_quant_step_size_Q6, /* I Inverse quantization step size */
+ const opus_int32 mu_Q20, /* I R/D tradeoff */
+ const opus_int16 order /* I Number of input values */
+)
+{
+ opus_int i, j, nStates, ind_tmp, ind_min_max, ind_max_min, in_Q10, res_Q10;
+ opus_int pred_Q10, diff_Q10, out0_Q10, out1_Q10, rate0_Q5, rate1_Q5;
+ opus_int32 RD_tmp_Q25, min_Q25, min_max_Q25, max_min_Q25, pred_coef_Q16;
+ opus_int ind_sort[ NLSF_QUANT_DEL_DEC_STATES ];
+ opus_int8 ind[ NLSF_QUANT_DEL_DEC_STATES ][ MAX_LPC_ORDER ];
+ opus_int16 prev_out_Q10[ 2 * NLSF_QUANT_DEL_DEC_STATES ];
+ opus_int32 RD_Q25[ 2 * NLSF_QUANT_DEL_DEC_STATES ];
+ opus_int32 RD_min_Q25[ NLSF_QUANT_DEL_DEC_STATES ];
+ opus_int32 RD_max_Q25[ NLSF_QUANT_DEL_DEC_STATES ];
+ const opus_uint8 *rates_Q5;
+
+ silk_assert( (NLSF_QUANT_DEL_DEC_STATES & (NLSF_QUANT_DEL_DEC_STATES-1)) == 0 ); /* must be power of two */
+
+ nStates = 1;
+ RD_Q25[ 0 ] = 0;
+ prev_out_Q10[ 0 ] = 0;
+ for( i = order - 1; ; i-- ) {
+ rates_Q5 = &ec_rates_Q5[ ec_ix[ i ] ];
+ pred_coef_Q16 = silk_LSHIFT( (opus_int32)pred_coef_Q8[ i ], 8 );
+ in_Q10 = x_Q10[ i ];
+ for( j = 0; j < nStates; j++ ) {
+ pred_Q10 = silk_SMULWB( pred_coef_Q16, prev_out_Q10[ j ] );
+ res_Q10 = silk_SUB16( in_Q10, pred_Q10 );
+ ind_tmp = silk_SMULWB( (opus_int32)inv_quant_step_size_Q6, res_Q10 );
+ ind_tmp = silk_LIMIT( ind_tmp, -NLSF_QUANT_MAX_AMPLITUDE_EXT, NLSF_QUANT_MAX_AMPLITUDE_EXT-1 );
+ ind[ j ][ i ] = (opus_int8)ind_tmp;
+
+ /* compute outputs for ind_tmp and ind_tmp + 1 */
+ out0_Q10 = silk_LSHIFT( ind_tmp, 10 );
+ out1_Q10 = silk_ADD16( out0_Q10, 1024 );
+ if( ind_tmp > 0 ) {
+ out0_Q10 = silk_SUB16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+ out1_Q10 = silk_SUB16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+ } else if( ind_tmp == 0 ) {
+ out1_Q10 = silk_SUB16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+ } else if( ind_tmp == -1 ) {
+ out0_Q10 = silk_ADD16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+ } else {
+ out0_Q10 = silk_ADD16( out0_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+ out1_Q10 = silk_ADD16( out1_Q10, SILK_FIX_CONST( NLSF_QUANT_LEVEL_ADJ, 10 ) );
+ }
+ out0_Q10 = silk_SMULWB( (opus_int32)out0_Q10, quant_step_size_Q16 );
+ out1_Q10 = silk_SMULWB( (opus_int32)out1_Q10, quant_step_size_Q16 );
+ out0_Q10 = silk_ADD16( out0_Q10, pred_Q10 );
+ out1_Q10 = silk_ADD16( out1_Q10, pred_Q10 );
+ prev_out_Q10[ j ] = out0_Q10;
+ prev_out_Q10[ j + nStates ] = out1_Q10;
+
+ /* compute RD for ind_tmp and ind_tmp + 1 */
+ if( ind_tmp + 1 >= NLSF_QUANT_MAX_AMPLITUDE ) {
+ if( ind_tmp + 1 == NLSF_QUANT_MAX_AMPLITUDE ) {
+ rate0_Q5 = rates_Q5[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE ];
+ rate1_Q5 = 280;
+ } else {
+ rate0_Q5 = silk_SMLABB( 280 - 43 * NLSF_QUANT_MAX_AMPLITUDE, 43, ind_tmp );
+ rate1_Q5 = silk_ADD16( rate0_Q5, 43 );
+ }
+ } else if( ind_tmp <= -NLSF_QUANT_MAX_AMPLITUDE ) {
+ if( ind_tmp == -NLSF_QUANT_MAX_AMPLITUDE ) {
+ rate0_Q5 = 280;
+ rate1_Q5 = rates_Q5[ ind_tmp + 1 + NLSF_QUANT_MAX_AMPLITUDE ];
+ } else {
+ rate0_Q5 = silk_SMLABB( 280 - 43 * NLSF_QUANT_MAX_AMPLITUDE, -43, ind_tmp );
+ rate1_Q5 = silk_SUB16( rate0_Q5, 43 );
+ }
+ } else {
+ rate0_Q5 = rates_Q5[ ind_tmp + NLSF_QUANT_MAX_AMPLITUDE ];
+ rate1_Q5 = rates_Q5[ ind_tmp + 1 + NLSF_QUANT_MAX_AMPLITUDE ];
+ }
+ RD_tmp_Q25 = RD_Q25[ j ];
+ diff_Q10 = silk_SUB16( in_Q10, out0_Q10 );
+ RD_Q25[ j ] = silk_SMLABB( silk_MLA( RD_tmp_Q25, silk_SMULBB( diff_Q10, diff_Q10 ), w_Q5[ i ] ), mu_Q20, rate0_Q5 );
+ diff_Q10 = silk_SUB16( in_Q10, out1_Q10 );
+ RD_Q25[ j + nStates ] = silk_SMLABB( silk_MLA( RD_tmp_Q25, silk_SMULBB( diff_Q10, diff_Q10 ), w_Q5[ i ] ), mu_Q20, rate1_Q5 );
+ }
+
+ if( nStates <= ( NLSF_QUANT_DEL_DEC_STATES >> 1 ) ) {
+ /* double number of states and copy */
+ for( j = 0; j < nStates; j++ ) {
+ ind[ j + nStates ][ i ] = ind[ j ][ i ] + 1;
+ }
+ nStates = silk_LSHIFT( nStates, 1 );
+ for( j = nStates; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) {
+ ind[ j ][ i ] = ind[ j - nStates ][ i ];
+ }
+ } else if( i > 0 ) {
+ /* sort lower and upper half of RD_Q25, pairwise */
+ for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) {
+ if( RD_Q25[ j ] > RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ] ) {
+ RD_max_Q25[ j ] = RD_Q25[ j ];
+ RD_min_Q25[ j ] = RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ];
+ RD_Q25[ j ] = RD_min_Q25[ j ];
+ RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ] = RD_max_Q25[ j ];
+ /* swap prev_out values */
+ out0_Q10 = prev_out_Q10[ j ];
+ prev_out_Q10[ j ] = prev_out_Q10[ j + NLSF_QUANT_DEL_DEC_STATES ];
+ prev_out_Q10[ j + NLSF_QUANT_DEL_DEC_STATES ] = out0_Q10;
+ ind_sort[ j ] = j + NLSF_QUANT_DEL_DEC_STATES;
+ } else {
+ RD_min_Q25[ j ] = RD_Q25[ j ];
+ RD_max_Q25[ j ] = RD_Q25[ j + NLSF_QUANT_DEL_DEC_STATES ];
+ ind_sort[ j ] = j;
+ }
+ }
+ /* compare the highest RD values of the winning half with the lowest one in the losing half, and copy if necessary */
+ /* afterwards ind_sort[] will contain the indices of the NLSF_QUANT_DEL_DEC_STATES winning RD values */
+ while( 1 ) {
+ min_max_Q25 = silk_int32_MAX;
+ max_min_Q25 = 0;
+ ind_min_max = 0;
+ ind_max_min = 0;
+ for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) {
+ if( min_max_Q25 > RD_max_Q25[ j ] ) {
+ min_max_Q25 = RD_max_Q25[ j ];
+ ind_min_max = j;
+ }
+ if( max_min_Q25 < RD_min_Q25[ j ] ) {
+ max_min_Q25 = RD_min_Q25[ j ];
+ ind_max_min = j;
+ }
+ }
+ if( min_max_Q25 >= max_min_Q25 ) {
+ break;
+ }
+ /* copy ind_min_max to ind_max_min */
+ ind_sort[ ind_max_min ] = ind_sort[ ind_min_max ] ^ NLSF_QUANT_DEL_DEC_STATES;
+ RD_Q25[ ind_max_min ] = RD_Q25[ ind_min_max + NLSF_QUANT_DEL_DEC_STATES ];
+ prev_out_Q10[ ind_max_min ] = prev_out_Q10[ ind_min_max + NLSF_QUANT_DEL_DEC_STATES ];
+ RD_min_Q25[ ind_max_min ] = 0;
+ RD_max_Q25[ ind_min_max ] = silk_int32_MAX;
+ silk_memcpy( ind[ ind_max_min ], ind[ ind_min_max ], MAX_LPC_ORDER * sizeof( opus_int8 ) );
+ }
+ /* increment index if it comes from the upper half */
+ for( j = 0; j < NLSF_QUANT_DEL_DEC_STATES; j++ ) {
+ ind[ j ][ i ] += silk_RSHIFT( ind_sort[ j ], NLSF_QUANT_DEL_DEC_STATES_LOG2 );
+ }
+ } else { /* i == 0 */
+ break;
+ }
+ }
+
+ /* last sample: find winner, copy indices and return RD value */
+ ind_tmp = 0;
+ min_Q25 = silk_int32_MAX;
+ for( j = 0; j < 2 * NLSF_QUANT_DEL_DEC_STATES; j++ ) {
+ if( min_Q25 > RD_Q25[ j ] ) {
+ min_Q25 = RD_Q25[ j ];
+ ind_tmp = j;
+ }
+ }
+ for( j = 0; j < order; j++ ) {
+ indices[ j ] = ind[ ind_tmp & ( NLSF_QUANT_DEL_DEC_STATES - 1 ) ][ j ];
+ silk_assert( indices[ j ] >= -NLSF_QUANT_MAX_AMPLITUDE_EXT );
+ silk_assert( indices[ j ] <= NLSF_QUANT_MAX_AMPLITUDE_EXT );
+ }
+ indices[ 0 ] += silk_RSHIFT( ind_tmp, NLSF_QUANT_DEL_DEC_STATES_LOG2 );
+ silk_assert( indices[ 0 ] <= NLSF_QUANT_MAX_AMPLITUDE_EXT );
+ silk_assert( min_Q25 >= 0 );
+ return min_Q25;
+}
diff --git a/drivers/opus/silk/NLSF_encode.c b/drivers/opus/silk/NLSF_encode.c
new file mode 100644
index 0000000000..157c0c8ff6
--- /dev/null
+++ b/drivers/opus/silk/NLSF_encode.c
@@ -0,0 +1,136 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+#include "opus/celt/stack_alloc.h"
+
+/***********************/
+/* NLSF vector encoder */
+/***********************/
+opus_int32 silk_NLSF_encode( /* O Returns RD value in Q25 */
+ opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */
+ opus_int16 *pNLSF_Q15, /* I/O Quantized NLSF vector [ LPC_ORDER ] */
+ const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */
+ const opus_int16 *pW_QW, /* I NLSF weight vector [ LPC_ORDER ] */
+ const opus_int NLSF_mu_Q20, /* I Rate weight for the RD optimization */
+ const opus_int nSurvivors, /* I Max survivors after first stage */
+ const opus_int signalType /* I Signal type: 0/1/2 */
+)
+{
+ opus_int i, s, ind1, bestIndex, prob_Q8, bits_q7;
+ opus_int32 W_tmp_Q9;
+ VARDECL( opus_int32, err_Q26 );
+ VARDECL( opus_int32, RD_Q25 );
+ VARDECL( opus_int, tempIndices1 );
+ VARDECL( opus_int8, tempIndices2 );
+ opus_int16 res_Q15[ MAX_LPC_ORDER ];
+ opus_int16 res_Q10[ MAX_LPC_ORDER ];
+ opus_int16 NLSF_tmp_Q15[ MAX_LPC_ORDER ];
+ opus_int16 W_tmp_QW[ MAX_LPC_ORDER ];
+ opus_int16 W_adj_Q5[ MAX_LPC_ORDER ];
+ opus_uint8 pred_Q8[ MAX_LPC_ORDER ];
+ opus_int16 ec_ix[ MAX_LPC_ORDER ];
+ const opus_uint8 *pCB_element, *iCDF_ptr;
+ SAVE_STACK;
+
+ silk_assert( nSurvivors <= NLSF_VQ_MAX_SURVIVORS );
+ silk_assert( signalType >= 0 && signalType <= 2 );
+ silk_assert( NLSF_mu_Q20 <= 32767 && NLSF_mu_Q20 >= 0 );
+
+ /* NLSF stabilization */
+ silk_NLSF_stabilize( pNLSF_Q15, psNLSF_CB->deltaMin_Q15, psNLSF_CB->order );
+
+ /* First stage: VQ */
+ ALLOC( err_Q26, psNLSF_CB->nVectors, opus_int32 );
+ silk_NLSF_VQ( err_Q26, pNLSF_Q15, psNLSF_CB->CB1_NLSF_Q8, psNLSF_CB->nVectors, psNLSF_CB->order );
+
+ /* Sort the quantization errors */
+ ALLOC( tempIndices1, nSurvivors, opus_int );
+ silk_insertion_sort_increasing( err_Q26, tempIndices1, psNLSF_CB->nVectors, nSurvivors );
+
+ ALLOC( RD_Q25, nSurvivors, opus_int32 );
+ ALLOC( tempIndices2, nSurvivors * MAX_LPC_ORDER, opus_int8 );
+
+ /* Loop over survivors */
+ for( s = 0; s < nSurvivors; s++ ) {
+ ind1 = tempIndices1[ s ];
+
+ /* Residual after first stage */
+ pCB_element = &psNLSF_CB->CB1_NLSF_Q8[ ind1 * psNLSF_CB->order ];
+ for( i = 0; i < psNLSF_CB->order; i++ ) {
+ NLSF_tmp_Q15[ i ] = silk_LSHIFT16( (opus_int16)pCB_element[ i ], 7 );
+ res_Q15[ i ] = pNLSF_Q15[ i ] - NLSF_tmp_Q15[ i ];
+ }
+
+ /* Weights from codebook vector */
+ silk_NLSF_VQ_weights_laroia( W_tmp_QW, NLSF_tmp_Q15, psNLSF_CB->order );
+
+ /* Apply square-rooted weights */
+ for( i = 0; i < psNLSF_CB->order; i++ ) {
+ W_tmp_Q9 = silk_SQRT_APPROX( silk_LSHIFT( (opus_int32)W_tmp_QW[ i ], 18 - NLSF_W_Q ) );
+ res_Q10[ i ] = (opus_int16)silk_RSHIFT( silk_SMULBB( res_Q15[ i ], W_tmp_Q9 ), 14 );
+ }
+
+ /* Modify input weights accordingly */
+ for( i = 0; i < psNLSF_CB->order; i++ ) {
+ W_adj_Q5[ i ] = silk_DIV32_16( silk_LSHIFT( (opus_int32)pW_QW[ i ], 5 ), W_tmp_QW[ i ] );
+ }
+
+ /* Unpack entropy table indices and predictor for current CB1 index */
+ silk_NLSF_unpack( ec_ix, pred_Q8, psNLSF_CB, ind1 );
+
+ /* Trellis quantizer */
+ RD_Q25[ s ] = silk_NLSF_del_dec_quant( &tempIndices2[ s * MAX_LPC_ORDER ], res_Q10, W_adj_Q5, pred_Q8, ec_ix,
+ psNLSF_CB->ec_Rates_Q5, psNLSF_CB->quantStepSize_Q16, psNLSF_CB->invQuantStepSize_Q6, NLSF_mu_Q20, psNLSF_CB->order );
+
+ /* Add rate for first stage */
+ iCDF_ptr = &psNLSF_CB->CB1_iCDF[ ( signalType >> 1 ) * psNLSF_CB->nVectors ];
+ if( ind1 == 0 ) {
+ prob_Q8 = 256 - iCDF_ptr[ ind1 ];
+ } else {
+ prob_Q8 = iCDF_ptr[ ind1 - 1 ] - iCDF_ptr[ ind1 ];
+ }
+ bits_q7 = ( 8 << 7 ) - silk_lin2log( prob_Q8 );
+ RD_Q25[ s ] = silk_SMLABB( RD_Q25[ s ], bits_q7, silk_RSHIFT( NLSF_mu_Q20, 2 ) );
+ }
+
+ /* Find the lowest rate-distortion error */
+ silk_insertion_sort_increasing( RD_Q25, &bestIndex, nSurvivors, 1 );
+
+ NLSFIndices[ 0 ] = (opus_int8)tempIndices1[ bestIndex ];
+ silk_memcpy( &NLSFIndices[ 1 ], &tempIndices2[ bestIndex * MAX_LPC_ORDER ], psNLSF_CB->order * sizeof( opus_int8 ) );
+
+ /* Decode */
+ silk_NLSF_decode( pNLSF_Q15, NLSFIndices, psNLSF_CB );
+
+ RESTORE_STACK;
+ return RD_Q25[ 0 ];
+}
diff --git a/drivers/opus/silk/NLSF_stabilize.c b/drivers/opus/silk/NLSF_stabilize.c
new file mode 100644
index 0000000000..caeeed9754
--- /dev/null
+++ b/drivers/opus/silk/NLSF_stabilize.c
@@ -0,0 +1,142 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+/* NLSF stabilizer: */
+/* */
+/* - Moves NLSFs further apart if they are too close */
+/* - Moves NLSFs away from borders if they are too close */
+/* - High effort to achieve a modification with minimum */
+/* Euclidean distance to input vector */
+/* - Output are sorted NLSF coefficients */
+/* */
+
+#include "opus/silk/SigProc_FIX.h"
+
+/* Constant Definitions */
+#define MAX_LOOPS 20
+
+/* NLSF stabilizer, for a single input data vector */
+void silk_NLSF_stabilize(
+ opus_int16 *NLSF_Q15, /* I/O Unstable/stabilized normalized LSF vector in Q15 [L] */
+ const opus_int16 *NDeltaMin_Q15, /* I Min distance vector, NDeltaMin_Q15[L] must be >= 1 [L+1] */
+ const opus_int L /* I Number of NLSF parameters in the input vector */
+)
+{
+ opus_int i, I=0, k, loops;
+ opus_int16 center_freq_Q15;
+ opus_int32 diff_Q15, min_diff_Q15, min_center_Q15, max_center_Q15;
+
+ /* This is necessary to ensure an output within range of a opus_int16 */
+ silk_assert( NDeltaMin_Q15[L] >= 1 );
+
+ for( loops = 0; loops < MAX_LOOPS; loops++ ) {
+ /**************************/
+ /* Find smallest distance */
+ /**************************/
+ /* First element */
+ min_diff_Q15 = NLSF_Q15[0] - NDeltaMin_Q15[0];
+ I = 0;
+ /* Middle elements */
+ for( i = 1; i <= L-1; i++ ) {
+ diff_Q15 = NLSF_Q15[i] - ( NLSF_Q15[i-1] + NDeltaMin_Q15[i] );
+ if( diff_Q15 < min_diff_Q15 ) {
+ min_diff_Q15 = diff_Q15;
+ I = i;
+ }
+ }
+ /* Last element */
+ diff_Q15 = ( 1 << 15 ) - ( NLSF_Q15[L-1] + NDeltaMin_Q15[L] );
+ if( diff_Q15 < min_diff_Q15 ) {
+ min_diff_Q15 = diff_Q15;
+ I = L;
+ }
+
+ /***************************************************/
+ /* Now check if the smallest distance non-negative */
+ /***************************************************/
+ if( min_diff_Q15 >= 0 ) {
+ return;
+ }
+
+ if( I == 0 ) {
+ /* Move away from lower limit */
+ NLSF_Q15[0] = NDeltaMin_Q15[0];
+
+ } else if( I == L) {
+ /* Move away from higher limit */
+ NLSF_Q15[L-1] = ( 1 << 15 ) - NDeltaMin_Q15[L];
+
+ } else {
+ /* Find the lower extreme for the location of the current center frequency */
+ min_center_Q15 = 0;
+ for( k = 0; k < I; k++ ) {
+ min_center_Q15 += NDeltaMin_Q15[k];
+ }
+ min_center_Q15 += silk_RSHIFT( NDeltaMin_Q15[I], 1 );
+
+ /* Find the upper extreme for the location of the current center frequency */
+ max_center_Q15 = 1 << 15;
+ for( k = L; k > I; k-- ) {
+ max_center_Q15 -= NDeltaMin_Q15[k];
+ }
+ max_center_Q15 -= silk_RSHIFT( NDeltaMin_Q15[I], 1 );
+
+ /* Move apart, sorted by value, keeping the same center frequency */
+ center_freq_Q15 = (opus_int16)silk_LIMIT_32( silk_RSHIFT_ROUND( (opus_int32)NLSF_Q15[I-1] + (opus_int32)NLSF_Q15[I], 1 ),
+ min_center_Q15, max_center_Q15 );
+ NLSF_Q15[I-1] = center_freq_Q15 - silk_RSHIFT( NDeltaMin_Q15[I], 1 );
+ NLSF_Q15[I] = NLSF_Q15[I-1] + NDeltaMin_Q15[I];
+ }
+ }
+
+ /* Safe and simple fall back method, which is less ideal than the above */
+ if( loops == MAX_LOOPS )
+ {
+ /* Insertion sort (fast for already almost sorted arrays): */
+ /* Best case: O(n) for an already sorted array */
+ /* Worst case: O(n^2) for an inversely sorted array */
+ silk_insertion_sort_increasing_all_values_int16( &NLSF_Q15[0], L );
+
+ /* First NLSF should be no less than NDeltaMin[0] */
+ NLSF_Q15[0] = silk_max_int( NLSF_Q15[0], NDeltaMin_Q15[0] );
+
+ /* Keep delta_min distance between the NLSFs */
+ for( i = 1; i < L; i++ )
+ NLSF_Q15[i] = silk_max_int( NLSF_Q15[i], NLSF_Q15[i-1] + NDeltaMin_Q15[i] );
+
+ /* Last NLSF should be no higher than 1 - NDeltaMin[L] */
+ NLSF_Q15[L-1] = silk_min_int( NLSF_Q15[L-1], (1<<15) - NDeltaMin_Q15[L] );
+
+ /* Keep NDeltaMin distance between the NLSFs */
+ for( i = L-2; i >= 0; i-- )
+ NLSF_Q15[i] = silk_min_int( NLSF_Q15[i], NLSF_Q15[i+1] - NDeltaMin_Q15[i+1] );
+ }
+}
diff --git a/drivers/opus/silk/NLSF_unpack.c b/drivers/opus/silk/NLSF_unpack.c
new file mode 100644
index 0000000000..20d3020f9b
--- /dev/null
+++ b/drivers/opus/silk/NLSF_unpack.c
@@ -0,0 +1,55 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+
+/* Unpack predictor values and indices for entropy coding tables */
+void silk_NLSF_unpack(
+ opus_int16 ec_ix[], /* O Indices to entropy tables [ LPC_ORDER ] */
+ opus_uint8 pred_Q8[], /* O LSF predictor [ LPC_ORDER ] */
+ const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */
+ const opus_int CB1_index /* I Index of vector in first LSF codebook */
+)
+{
+ opus_int i;
+ opus_uint8 entry;
+ const opus_uint8 *ec_sel_ptr;
+
+ ec_sel_ptr = &psNLSF_CB->ec_sel[ CB1_index * psNLSF_CB->order / 2 ];
+ for( i = 0; i < psNLSF_CB->order; i += 2 ) {
+ entry = *ec_sel_ptr++;
+ ec_ix [ i ] = silk_SMULBB( silk_RSHIFT( entry, 1 ) & 7, 2 * NLSF_QUANT_MAX_AMPLITUDE + 1 );
+ pred_Q8[ i ] = psNLSF_CB->pred_Q8[ i + ( entry & 1 ) * ( psNLSF_CB->order - 1 ) ];
+ ec_ix [ i + 1 ] = silk_SMULBB( silk_RSHIFT( entry, 5 ) & 7, 2 * NLSF_QUANT_MAX_AMPLITUDE + 1 );
+ pred_Q8[ i + 1 ] = psNLSF_CB->pred_Q8[ i + ( silk_RSHIFT( entry, 4 ) & 1 ) * ( psNLSF_CB->order - 1 ) + 1 ];
+ }
+}
+
diff --git a/drivers/opus/silk/NSQ.c b/drivers/opus/silk/NSQ.c
new file mode 100644
index 0000000000..6092498a1b
--- /dev/null
+++ b/drivers/opus/silk/NSQ.c
@@ -0,0 +1,446 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+#include "opus/celt/stack_alloc.h"
+
+static OPUS_INLINE void silk_nsq_scale_states(
+ const silk_encoder_state *psEncC, /* I Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ const opus_int32 x_Q3[], /* I input in Q3 */
+ opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */
+ const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */
+ opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */
+ opus_int subfr, /* I subframe number */
+ const opus_int LTP_scale_Q14, /* I */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */
+ const opus_int signal_type /* I Signal type */
+);
+
+static OPUS_INLINE void silk_noise_shape_quantizer(
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ opus_int signalType, /* I Signal type */
+ const opus_int32 x_sc_Q10[], /* I */
+ opus_int8 pulses[], /* O */
+ opus_int16 xq[], /* O */
+ opus_int32 sLTP_Q15[], /* I/O LTP state */
+ const opus_int16 a_Q12[], /* I Short term prediction coefs */
+ const opus_int16 b_Q14[], /* I Long term prediction coefs */
+ const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */
+ opus_int lag, /* I Pitch lag */
+ opus_int32 HarmShapeFIRPacked_Q14, /* I */
+ opus_int Tilt_Q14, /* I Spectral tilt */
+ opus_int32 LF_shp_Q14, /* I */
+ opus_int32 Gain_Q16, /* I */
+ opus_int Lambda_Q10, /* I */
+ opus_int offset_Q10, /* I */
+ opus_int length, /* I Input length */
+ opus_int shapingLPCOrder, /* I Noise shaping AR filter order */
+ opus_int predictLPCOrder /* I Prediction filter order */
+);
+
+void silk_NSQ(
+ const silk_encoder_state *psEncC, /* I/O Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ SideInfoIndices *psIndices, /* I/O Quantization Indices */
+ const opus_int32 x_Q3[], /* I Prefiltered input signal */
+ opus_int8 pulses[], /* O Quantized pulse signal */
+ const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */
+ const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */
+ const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */
+ const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */
+ const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */
+ const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */
+ const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */
+ const opus_int LTP_scale_Q14 /* I LTP state scaling */
+)
+{
+ opus_int k, lag, start_idx, LSF_interpolation_flag;
+ const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13;
+ opus_int16 *pxq;
+ VARDECL( opus_int32, sLTP_Q15 );
+ VARDECL( opus_int16, sLTP );
+ opus_int32 HarmShapeFIRPacked_Q14;
+ opus_int offset_Q10;
+ VARDECL( opus_int32, x_sc_Q10 );
+ SAVE_STACK;
+
+ NSQ->rand_seed = psIndices->Seed;
+
+ /* Set unvoiced lag to the previous one, overwrite later for voiced */
+ lag = NSQ->lagPrev;
+
+ silk_assert( NSQ->prev_gain_Q16 != 0 );
+
+ offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ];
+
+ if( psIndices->NLSFInterpCoef_Q2 == 4 ) {
+ LSF_interpolation_flag = 0;
+ } else {
+ LSF_interpolation_flag = 1;
+ }
+
+ ALLOC( sLTP_Q15,
+ psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 );
+ ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 );
+ ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 );
+ /* Set up pointers to start of sub frame */
+ NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length;
+ NSQ->sLTP_buf_idx = psEncC->ltp_mem_length;
+ pxq = &NSQ->xq[ psEncC->ltp_mem_length ];
+ for( k = 0; k < psEncC->nb_subfr; k++ ) {
+ A_Q12 = &PredCoef_Q12[ (( k >> 1 ) | ( 1 - LSF_interpolation_flag )) * MAX_LPC_ORDER ];
+ B_Q14 = &LTPCoef_Q14[ k * LTP_ORDER ];
+ AR_shp_Q13 = &AR2_Q13[ k * MAX_SHAPE_LPC_ORDER ];
+
+ /* Noise shape parameters */
+ silk_assert( HarmShapeGain_Q14[ k ] >= 0 );
+ HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 );
+ HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 );
+
+ NSQ->rewhite_flag = 0;
+ if( psIndices->signalType == TYPE_VOICED ) {
+ /* Voiced */
+ lag = pitchL[ k ];
+
+ /* Re-whitening */
+ if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) {
+ /* Rewhiten with new A coefs */
+ start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2;
+ silk_assert( start_idx > 0 );
+
+ silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ],
+ A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder );
+
+ NSQ->rewhite_flag = 1;
+ NSQ->sLTP_buf_idx = psEncC->ltp_mem_length;
+ }
+ }
+
+ silk_nsq_scale_states( psEncC, NSQ, x_Q3, x_sc_Q10, sLTP, sLTP_Q15, k, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType );
+
+ silk_noise_shape_quantizer( NSQ, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15, A_Q12, B_Q14,
+ AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ], Gains_Q16[ k ], Lambda_Q10,
+ offset_Q10, psEncC->subfr_length, psEncC->shapingLPCOrder, psEncC->predictLPCOrder );
+
+ x_Q3 += psEncC->subfr_length;
+ pulses += psEncC->subfr_length;
+ pxq += psEncC->subfr_length;
+ }
+
+ /* Update lagPrev for next frame */
+ NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ];
+
+ /* Save quantized speech and noise shaping signals */
+ /* DEBUG_STORE_DATA( enc.pcm, &NSQ->xq[ psEncC->ltp_mem_length ], psEncC->frame_length * sizeof( opus_int16 ) ) */
+ silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) );
+ silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) );
+ RESTORE_STACK;
+}
+
+/***********************************/
+/* silk_noise_shape_quantizer */
+/***********************************/
+static OPUS_INLINE void silk_noise_shape_quantizer(
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ opus_int signalType, /* I Signal type */
+ const opus_int32 x_sc_Q10[], /* I */
+ opus_int8 pulses[], /* O */
+ opus_int16 xq[], /* O */
+ opus_int32 sLTP_Q15[], /* I/O LTP state */
+ const opus_int16 a_Q12[], /* I Short term prediction coefs */
+ const opus_int16 b_Q14[], /* I Long term prediction coefs */
+ const opus_int16 AR_shp_Q13[], /* I Noise shaping AR coefs */
+ opus_int lag, /* I Pitch lag */
+ opus_int32 HarmShapeFIRPacked_Q14, /* I */
+ opus_int Tilt_Q14, /* I Spectral tilt */
+ opus_int32 LF_shp_Q14, /* I */
+ opus_int32 Gain_Q16, /* I */
+ opus_int Lambda_Q10, /* I */
+ opus_int offset_Q10, /* I */
+ opus_int length, /* I Input length */
+ opus_int shapingLPCOrder, /* I Noise shaping AR filter order */
+ opus_int predictLPCOrder /* I Prediction filter order */
+)
+{
+ opus_int i, j;
+ opus_int32 LTP_pred_Q13, LPC_pred_Q10, n_AR_Q12, n_LTP_Q13;
+ opus_int32 n_LF_Q12, r_Q10, rr_Q10, q1_Q0, q1_Q10, q2_Q10, rd1_Q20, rd2_Q20;
+ opus_int32 exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10;
+ opus_int32 tmp1, tmp2, sLF_AR_shp_Q14;
+ opus_int32 *psLPC_Q14, *shp_lag_ptr, *pred_lag_ptr;
+
+ shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ];
+ pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ];
+ Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 );
+
+ /* Set up short term AR state */
+ psLPC_Q14 = &NSQ->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 ];
+
+ for( i = 0; i < length; i++ ) {
+ /* Generate dither */
+ NSQ->rand_seed = silk_RAND( NSQ->rand_seed );
+
+ /* Short-term prediction */
+ silk_assert( predictLPCOrder == 10 || predictLPCOrder == 16 );
+ /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+ LPC_pred_Q10 = silk_RSHIFT( predictLPCOrder, 1 );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ 0 ], a_Q12[ 0 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -1 ], a_Q12[ 1 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -2 ], a_Q12[ 2 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -3 ], a_Q12[ 3 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -4 ], a_Q12[ 4 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -5 ], a_Q12[ 5 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -6 ], a_Q12[ 6 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -7 ], a_Q12[ 7 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -8 ], a_Q12[ 8 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -9 ], a_Q12[ 9 ] );
+ if( predictLPCOrder == 16 ) {
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -10 ], a_Q12[ 10 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -11 ], a_Q12[ 11 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -12 ], a_Q12[ 12 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -13 ], a_Q12[ 13 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -14 ], a_Q12[ 14 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, psLPC_Q14[ -15 ], a_Q12[ 15 ] );
+ }
+
+ /* Long-term prediction */
+ if( signalType == TYPE_VOICED ) {
+ /* Unrolled loop */
+ /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+ LTP_pred_Q13 = 2;
+ LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ 0 ], b_Q14[ 0 ] );
+ LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -1 ], b_Q14[ 1 ] );
+ LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -2 ], b_Q14[ 2 ] );
+ LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -3 ], b_Q14[ 3 ] );
+ LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -4 ], b_Q14[ 4 ] );
+ pred_lag_ptr++;
+ } else {
+ LTP_pred_Q13 = 0;
+ }
+
+ /* Noise shape feedback */
+ silk_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */
+ tmp2 = psLPC_Q14[ 0 ];
+ tmp1 = NSQ->sAR2_Q14[ 0 ];
+ NSQ->sAR2_Q14[ 0 ] = tmp2;
+ n_AR_Q12 = silk_RSHIFT( shapingLPCOrder, 1 );
+ n_AR_Q12 = silk_SMLAWB( n_AR_Q12, tmp2, AR_shp_Q13[ 0 ] );
+ for( j = 2; j < shapingLPCOrder; j += 2 ) {
+ tmp2 = NSQ->sAR2_Q14[ j - 1 ];
+ NSQ->sAR2_Q14[ j - 1 ] = tmp1;
+ n_AR_Q12 = silk_SMLAWB( n_AR_Q12, tmp1, AR_shp_Q13[ j - 1 ] );
+ tmp1 = NSQ->sAR2_Q14[ j + 0 ];
+ NSQ->sAR2_Q14[ j + 0 ] = tmp2;
+ n_AR_Q12 = silk_SMLAWB( n_AR_Q12, tmp2, AR_shp_Q13[ j ] );
+ }
+ NSQ->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1;
+ n_AR_Q12 = silk_SMLAWB( n_AR_Q12, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] );
+
+ n_AR_Q12 = silk_LSHIFT32( n_AR_Q12, 1 ); /* Q11 -> Q12 */
+ n_AR_Q12 = silk_SMLAWB( n_AR_Q12, NSQ->sLF_AR_shp_Q14, Tilt_Q14 );
+
+ n_LF_Q12 = silk_SMULWB( NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - 1 ], LF_shp_Q14 );
+ n_LF_Q12 = silk_SMLAWT( n_LF_Q12, NSQ->sLF_AR_shp_Q14, LF_shp_Q14 );
+
+ silk_assert( lag > 0 || signalType != TYPE_VOICED );
+
+ /* Combine prediction and noise shaping signals */
+ tmp1 = silk_SUB32( silk_LSHIFT32( LPC_pred_Q10, 2 ), n_AR_Q12 ); /* Q12 */
+ tmp1 = silk_SUB32( tmp1, n_LF_Q12 ); /* Q12 */
+ if( lag > 0 ) {
+ /* Symmetric, packed FIR coefficients */
+ n_LTP_Q13 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 );
+ n_LTP_Q13 = silk_SMLAWT( n_LTP_Q13, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 );
+ n_LTP_Q13 = silk_LSHIFT( n_LTP_Q13, 1 );
+ shp_lag_ptr++;
+
+ tmp2 = silk_SUB32( LTP_pred_Q13, n_LTP_Q13 ); /* Q13 */
+ tmp1 = silk_ADD_LSHIFT32( tmp2, tmp1, 1 ); /* Q13 */
+ tmp1 = silk_RSHIFT_ROUND( tmp1, 3 ); /* Q10 */
+ } else {
+ tmp1 = silk_RSHIFT_ROUND( tmp1, 2 ); /* Q10 */
+ }
+
+ r_Q10 = silk_SUB32( x_sc_Q10[ i ], tmp1 ); /* residual error Q10 */
+
+ /* Flip sign depending on dither */
+ if ( NSQ->rand_seed < 0 ) {
+ r_Q10 = -r_Q10;
+ }
+ r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 );
+
+ /* Find two quantization level candidates and measure their rate-distortion */
+ q1_Q10 = silk_SUB32( r_Q10, offset_Q10 );
+ q1_Q0 = silk_RSHIFT( q1_Q10, 10 );
+ if( q1_Q0 > 0 ) {
+ q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
+ q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 );
+ q2_Q10 = silk_ADD32( q1_Q10, 1024 );
+ rd1_Q20 = silk_SMULBB( q1_Q10, Lambda_Q10 );
+ rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+ } else if( q1_Q0 == 0 ) {
+ q1_Q10 = offset_Q10;
+ q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
+ rd1_Q20 = silk_SMULBB( q1_Q10, Lambda_Q10 );
+ rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+ } else if( q1_Q0 == -1 ) {
+ q2_Q10 = offset_Q10;
+ q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
+ rd1_Q20 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
+ rd2_Q20 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+ } else { /* Q1_Q0 < -1 */
+ q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
+ q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 );
+ q2_Q10 = silk_ADD32( q1_Q10, 1024 );
+ rd1_Q20 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
+ rd2_Q20 = silk_SMULBB( -q2_Q10, Lambda_Q10 );
+ }
+ rr_Q10 = silk_SUB32( r_Q10, q1_Q10 );
+ rd1_Q20 = silk_SMLABB( rd1_Q20, rr_Q10, rr_Q10 );
+ rr_Q10 = silk_SUB32( r_Q10, q2_Q10 );
+ rd2_Q20 = silk_SMLABB( rd2_Q20, rr_Q10, rr_Q10 );
+
+ if( rd2_Q20 < rd1_Q20 ) {
+ q1_Q10 = q2_Q10;
+ }
+
+ pulses[ i ] = (opus_int8)silk_RSHIFT_ROUND( q1_Q10, 10 );
+
+ /* Excitation */
+ exc_Q14 = silk_LSHIFT( q1_Q10, 4 );
+ if ( NSQ->rand_seed < 0 ) {
+ exc_Q14 = -exc_Q14;
+ }
+
+ /* Add predictions */
+ LPC_exc_Q14 = silk_ADD_LSHIFT32( exc_Q14, LTP_pred_Q13, 1 );
+ xq_Q14 = silk_ADD_LSHIFT32( LPC_exc_Q14, LPC_pred_Q10, 4 );
+
+ /* Scale XQ back to normal level before saving */
+ xq[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( xq_Q14, Gain_Q10 ), 8 ) );
+
+ /* Update states */
+ psLPC_Q14++;
+ *psLPC_Q14 = xq_Q14;
+ sLF_AR_shp_Q14 = silk_SUB_LSHIFT32( xq_Q14, n_AR_Q12, 2 );
+ NSQ->sLF_AR_shp_Q14 = sLF_AR_shp_Q14;
+
+ NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx ] = silk_SUB_LSHIFT32( sLF_AR_shp_Q14, n_LF_Q12, 2 );
+ sLTP_Q15[ NSQ->sLTP_buf_idx ] = silk_LSHIFT( LPC_exc_Q14, 1 );
+ NSQ->sLTP_shp_buf_idx++;
+ NSQ->sLTP_buf_idx++;
+
+ /* Make dither dependent on quantized signal */
+ NSQ->rand_seed = silk_ADD32_ovflw( NSQ->rand_seed, pulses[ i ] );
+ }
+
+ /* Update LPC synth buffer */
+ silk_memcpy( NSQ->sLPC_Q14, &NSQ->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
+}
+
+static OPUS_INLINE void silk_nsq_scale_states(
+ const silk_encoder_state *psEncC, /* I Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ const opus_int32 x_Q3[], /* I input in Q3 */
+ opus_int32 x_sc_Q10[], /* O input scaled with 1/Gain */
+ const opus_int16 sLTP[], /* I re-whitened LTP state in Q0 */
+ opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */
+ opus_int subfr, /* I subframe number */
+ const opus_int LTP_scale_Q14, /* I */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */
+ const opus_int signal_type /* I Signal type */
+)
+{
+ opus_int i, lag;
+ opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q23;
+
+ lag = pitchL[ subfr ];
+ inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 );
+ silk_assert( inv_gain_Q31 != 0 );
+
+ /* Calculate gain adjustment factor */
+ if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) {
+ gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 );
+ } else {
+ gain_adj_Q16 = (opus_int32)1 << 16;
+ }
+
+ /* Scale input */
+ inv_gain_Q23 = silk_RSHIFT_ROUND( inv_gain_Q31, 8 );
+ for( i = 0; i < psEncC->subfr_length; i++ ) {
+ x_sc_Q10[ i ] = silk_SMULWW( x_Q3[ i ], inv_gain_Q23 );
+ }
+
+ /* Save inverse gain */
+ NSQ->prev_gain_Q16 = Gains_Q16[ subfr ];
+
+ /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */
+ if( NSQ->rewhite_flag ) {
+ if( subfr == 0 ) {
+ /* Do LTP downscaling */
+ inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 );
+ }
+ for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) {
+ silk_assert( i < MAX_FRAME_LENGTH );
+ sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] );
+ }
+ }
+
+ /* Adjust for changing gain */
+ if( gain_adj_Q16 != (opus_int32)1 << 16 ) {
+ /* Scale long-term shaping state */
+ for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx; i++ ) {
+ NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] );
+ }
+
+ /* Scale long-term prediction state */
+ if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) {
+ for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) {
+ sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] );
+ }
+ }
+
+ NSQ->sLF_AR_shp_Q14 = silk_SMULWW( gain_adj_Q16, NSQ->sLF_AR_shp_Q14 );
+
+ /* Scale short-term prediction and shaping states */
+ for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) {
+ NSQ->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLPC_Q14[ i ] );
+ }
+ for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) {
+ NSQ->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sAR2_Q14[ i ] );
+ }
+ }
+}
diff --git a/drivers/opus/silk/NSQ_del_dec.c b/drivers/opus/silk/NSQ_del_dec.c
new file mode 100644
index 0000000000..4aa730ed6a
--- /dev/null
+++ b/drivers/opus/silk/NSQ_del_dec.c
@@ -0,0 +1,719 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+#include "opus/celt/stack_alloc.h"
+
+typedef struct {
+ opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ];
+ opus_int32 RandState[ DECISION_DELAY ];
+ opus_int32 Q_Q10[ DECISION_DELAY ];
+ opus_int32 Xq_Q14[ DECISION_DELAY ];
+ opus_int32 Pred_Q15[ DECISION_DELAY ];
+ opus_int32 Shape_Q14[ DECISION_DELAY ];
+ opus_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ];
+ opus_int32 LF_AR_Q14;
+ opus_int32 Seed;
+ opus_int32 SeedInit;
+ opus_int32 RD_Q10;
+} NSQ_del_dec_struct;
+
+typedef struct {
+ opus_int32 Q_Q10;
+ opus_int32 RD_Q10;
+ opus_int32 xq_Q14;
+ opus_int32 LF_AR_Q14;
+ opus_int32 sLTP_shp_Q14;
+ opus_int32 LPC_exc_Q14;
+} NSQ_sample_struct;
+
+typedef NSQ_sample_struct NSQ_sample_pair[ 2 ];
+
+static OPUS_INLINE void silk_nsq_del_dec_scale_states(
+ const silk_encoder_state *psEncC, /* I Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */
+ const opus_int32 x_Q3[], /* I Input in Q3 */
+ opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */
+ const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */
+ opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */
+ opus_int subfr, /* I Subframe number */
+ opus_int nStatesDelayedDecision, /* I Number of del dec states */
+ const opus_int LTP_scale_Q14, /* I LTP state scaling */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */
+ const opus_int signal_type, /* I Signal type */
+ const opus_int decisionDelay /* I Decision delay */
+);
+
+/******************************************/
+/* Noise shape quantizer for one subframe */
+/******************************************/
+static OPUS_INLINE void silk_noise_shape_quantizer_del_dec(
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */
+ opus_int signalType, /* I Signal type */
+ const opus_int32 x_Q10[], /* I */
+ opus_int8 pulses[], /* O */
+ opus_int16 xq[], /* O */
+ opus_int32 sLTP_Q15[], /* I/O LTP filter state */
+ opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */
+ const opus_int16 a_Q12[], /* I Short term prediction coefs */
+ const opus_int16 b_Q14[], /* I Long term prediction coefs */
+ const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */
+ opus_int lag, /* I Pitch lag */
+ opus_int32 HarmShapeFIRPacked_Q14, /* I */
+ opus_int Tilt_Q14, /* I Spectral tilt */
+ opus_int32 LF_shp_Q14, /* I */
+ opus_int32 Gain_Q16, /* I */
+ opus_int Lambda_Q10, /* I */
+ opus_int offset_Q10, /* I */
+ opus_int length, /* I Input length */
+ opus_int subfr, /* I Subframe number */
+ opus_int shapingLPCOrder, /* I Shaping LPC filter order */
+ opus_int predictLPCOrder, /* I Prediction filter order */
+ opus_int warping_Q16, /* I */
+ opus_int nStatesDelayedDecision, /* I Number of states in decision tree */
+ opus_int *smpl_buf_idx, /* I Index to newest samples in buffers */
+ opus_int decisionDelay /* I */
+);
+
+void silk_NSQ_del_dec(
+ const silk_encoder_state *psEncC, /* I/O Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ SideInfoIndices *psIndices, /* I/O Quantization Indices */
+ const opus_int32 x_Q3[], /* I Prefiltered input signal */
+ opus_int8 pulses[], /* O Quantized pulse signal */
+ const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */
+ const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */
+ const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */
+ const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */
+ const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */
+ const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */
+ const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */
+ const opus_int LTP_scale_Q14 /* I LTP state scaling */
+)
+{
+ opus_int i, k, lag, start_idx, LSF_interpolation_flag, Winner_ind, subfr;
+ opus_int last_smple_idx, smpl_buf_idx, decisionDelay;
+ const opus_int16 *A_Q12, *B_Q14, *AR_shp_Q13;
+ opus_int16 *pxq;
+ VARDECL( opus_int32, sLTP_Q15 );
+ VARDECL( opus_int16, sLTP );
+ opus_int32 HarmShapeFIRPacked_Q14;
+ opus_int offset_Q10;
+ opus_int32 RDmin_Q10, Gain_Q10;
+ VARDECL( opus_int32, x_sc_Q10 );
+ VARDECL( opus_int32, delayedGain_Q10 );
+ VARDECL( NSQ_del_dec_struct, psDelDec );
+ NSQ_del_dec_struct *psDD;
+ SAVE_STACK;
+
+ /* Set unvoiced lag to the previous one, overwrite later for voiced */
+ lag = NSQ->lagPrev;
+
+ silk_assert( NSQ->prev_gain_Q16 != 0 );
+
+ /* Initialize delayed decision states */
+ ALLOC( psDelDec, psEncC->nStatesDelayedDecision, NSQ_del_dec_struct );
+ silk_memset( psDelDec, 0, psEncC->nStatesDelayedDecision * sizeof( NSQ_del_dec_struct ) );
+ for( k = 0; k < psEncC->nStatesDelayedDecision; k++ ) {
+ psDD = &psDelDec[ k ];
+ psDD->Seed = ( k + psIndices->Seed ) & 3;
+ psDD->SeedInit = psDD->Seed;
+ psDD->RD_Q10 = 0;
+ psDD->LF_AR_Q14 = NSQ->sLF_AR_shp_Q14;
+ psDD->Shape_Q14[ 0 ] = NSQ->sLTP_shp_Q14[ psEncC->ltp_mem_length - 1 ];
+ silk_memcpy( psDD->sLPC_Q14, NSQ->sLPC_Q14, NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
+ silk_memcpy( psDD->sAR2_Q14, NSQ->sAR2_Q14, sizeof( NSQ->sAR2_Q14 ) );
+ }
+
+ offset_Q10 = silk_Quantization_Offsets_Q10[ psIndices->signalType >> 1 ][ psIndices->quantOffsetType ];
+ smpl_buf_idx = 0; /* index of oldest samples */
+
+ decisionDelay = silk_min_int( DECISION_DELAY, psEncC->subfr_length );
+
+ /* For voiced frames limit the decision delay to lower than the pitch lag */
+ if( psIndices->signalType == TYPE_VOICED ) {
+ for( k = 0; k < psEncC->nb_subfr; k++ ) {
+ decisionDelay = silk_min_int( decisionDelay, pitchL[ k ] - LTP_ORDER / 2 - 1 );
+ }
+ } else {
+ if( lag > 0 ) {
+ decisionDelay = silk_min_int( decisionDelay, lag - LTP_ORDER / 2 - 1 );
+ }
+ }
+
+ if( psIndices->NLSFInterpCoef_Q2 == 4 ) {
+ LSF_interpolation_flag = 0;
+ } else {
+ LSF_interpolation_flag = 1;
+ }
+
+ ALLOC( sLTP_Q15,
+ psEncC->ltp_mem_length + psEncC->frame_length, opus_int32 );
+ ALLOC( sLTP, psEncC->ltp_mem_length + psEncC->frame_length, opus_int16 );
+ ALLOC( x_sc_Q10, psEncC->subfr_length, opus_int32 );
+ ALLOC( delayedGain_Q10, DECISION_DELAY, opus_int32 );
+ /* Set up pointers to start of sub frame */
+ pxq = &NSQ->xq[ psEncC->ltp_mem_length ];
+ NSQ->sLTP_shp_buf_idx = psEncC->ltp_mem_length;
+ NSQ->sLTP_buf_idx = psEncC->ltp_mem_length;
+ subfr = 0;
+ for( k = 0; k < psEncC->nb_subfr; k++ ) {
+ A_Q12 = &PredCoef_Q12[ ( ( k >> 1 ) | ( 1 - LSF_interpolation_flag ) ) * MAX_LPC_ORDER ];
+ B_Q14 = &LTPCoef_Q14[ k * LTP_ORDER ];
+ AR_shp_Q13 = &AR2_Q13[ k * MAX_SHAPE_LPC_ORDER ];
+
+ /* Noise shape parameters */
+ silk_assert( HarmShapeGain_Q14[ k ] >= 0 );
+ HarmShapeFIRPacked_Q14 = silk_RSHIFT( HarmShapeGain_Q14[ k ], 2 );
+ HarmShapeFIRPacked_Q14 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q14[ k ], 1 ), 16 );
+
+ NSQ->rewhite_flag = 0;
+ if( psIndices->signalType == TYPE_VOICED ) {
+ /* Voiced */
+ lag = pitchL[ k ];
+
+ /* Re-whitening */
+ if( ( k & ( 3 - silk_LSHIFT( LSF_interpolation_flag, 1 ) ) ) == 0 ) {
+ if( k == 2 ) {
+ /* RESET DELAYED DECISIONS */
+ /* Find winner */
+ RDmin_Q10 = psDelDec[ 0 ].RD_Q10;
+ Winner_ind = 0;
+ for( i = 1; i < psEncC->nStatesDelayedDecision; i++ ) {
+ if( psDelDec[ i ].RD_Q10 < RDmin_Q10 ) {
+ RDmin_Q10 = psDelDec[ i ].RD_Q10;
+ Winner_ind = i;
+ }
+ }
+ for( i = 0; i < psEncC->nStatesDelayedDecision; i++ ) {
+ if( i != Winner_ind ) {
+ psDelDec[ i ].RD_Q10 += ( silk_int32_MAX >> 4 );
+ silk_assert( psDelDec[ i ].RD_Q10 >= 0 );
+ }
+ }
+
+ /* Copy final part of signals from winner state to output and long-term filter states */
+ psDD = &psDelDec[ Winner_ind ];
+ last_smple_idx = smpl_buf_idx + decisionDelay;
+ for( i = 0; i < decisionDelay; i++ ) {
+ last_smple_idx = ( last_smple_idx - 1 ) & DECISION_DELAY_MASK;
+ pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 );
+ pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND(
+ silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gains_Q16[ 1 ] ), 14 ) );
+ NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ];
+ }
+
+ subfr = 0;
+ }
+
+ /* Rewhiten with new A coefs */
+ start_idx = psEncC->ltp_mem_length - lag - psEncC->predictLPCOrder - LTP_ORDER / 2;
+ silk_assert( start_idx > 0 );
+
+ silk_LPC_analysis_filter( &sLTP[ start_idx ], &NSQ->xq[ start_idx + k * psEncC->subfr_length ],
+ A_Q12, psEncC->ltp_mem_length - start_idx, psEncC->predictLPCOrder );
+
+ NSQ->sLTP_buf_idx = psEncC->ltp_mem_length;
+ NSQ->rewhite_flag = 1;
+ }
+ }
+
+ silk_nsq_del_dec_scale_states( psEncC, NSQ, psDelDec, x_Q3, x_sc_Q10, sLTP, sLTP_Q15, k,
+ psEncC->nStatesDelayedDecision, LTP_scale_Q14, Gains_Q16, pitchL, psIndices->signalType, decisionDelay );
+
+ silk_noise_shape_quantizer_del_dec( NSQ, psDelDec, psIndices->signalType, x_sc_Q10, pulses, pxq, sLTP_Q15,
+ delayedGain_Q10, A_Q12, B_Q14, AR_shp_Q13, lag, HarmShapeFIRPacked_Q14, Tilt_Q14[ k ], LF_shp_Q14[ k ],
+ Gains_Q16[ k ], Lambda_Q10, offset_Q10, psEncC->subfr_length, subfr++, psEncC->shapingLPCOrder,
+ psEncC->predictLPCOrder, psEncC->warping_Q16, psEncC->nStatesDelayedDecision, &smpl_buf_idx, decisionDelay );
+
+ x_Q3 += psEncC->subfr_length;
+ pulses += psEncC->subfr_length;
+ pxq += psEncC->subfr_length;
+ }
+
+ /* Find winner */
+ RDmin_Q10 = psDelDec[ 0 ].RD_Q10;
+ Winner_ind = 0;
+ for( k = 1; k < psEncC->nStatesDelayedDecision; k++ ) {
+ if( psDelDec[ k ].RD_Q10 < RDmin_Q10 ) {
+ RDmin_Q10 = psDelDec[ k ].RD_Q10;
+ Winner_ind = k;
+ }
+ }
+
+ /* Copy final part of signals from winner state to output and long-term filter states */
+ psDD = &psDelDec[ Winner_ind ];
+ psIndices->Seed = psDD->SeedInit;
+ last_smple_idx = smpl_buf_idx + decisionDelay;
+ Gain_Q10 = silk_RSHIFT32( Gains_Q16[ psEncC->nb_subfr - 1 ], 6 );
+ for( i = 0; i < decisionDelay; i++ ) {
+ last_smple_idx = ( last_smple_idx - 1 ) & DECISION_DELAY_MASK;
+ pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 );
+ pxq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND(
+ silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], Gain_Q10 ), 8 ) );
+ NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay + i ] = psDD->Shape_Q14[ last_smple_idx ];
+ }
+ silk_memcpy( NSQ->sLPC_Q14, &psDD->sLPC_Q14[ psEncC->subfr_length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
+ silk_memcpy( NSQ->sAR2_Q14, psDD->sAR2_Q14, sizeof( psDD->sAR2_Q14 ) );
+
+ /* Update states */
+ NSQ->sLF_AR_shp_Q14 = psDD->LF_AR_Q14;
+ NSQ->lagPrev = pitchL[ psEncC->nb_subfr - 1 ];
+
+ /* Save quantized speech signal */
+ /* DEBUG_STORE_DATA( enc.pcm, &NSQ->xq[psEncC->ltp_mem_length], psEncC->frame_length * sizeof( opus_int16 ) ) */
+ silk_memmove( NSQ->xq, &NSQ->xq[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int16 ) );
+ silk_memmove( NSQ->sLTP_shp_Q14, &NSQ->sLTP_shp_Q14[ psEncC->frame_length ], psEncC->ltp_mem_length * sizeof( opus_int32 ) );
+ RESTORE_STACK;
+}
+
+/******************************************/
+/* Noise shape quantizer for one subframe */
+/******************************************/
+static OPUS_INLINE void silk_noise_shape_quantizer_del_dec(
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */
+ opus_int signalType, /* I Signal type */
+ const opus_int32 x_Q10[], /* I */
+ opus_int8 pulses[], /* O */
+ opus_int16 xq[], /* O */
+ opus_int32 sLTP_Q15[], /* I/O LTP filter state */
+ opus_int32 delayedGain_Q10[], /* I/O Gain delay buffer */
+ const opus_int16 a_Q12[], /* I Short term prediction coefs */
+ const opus_int16 b_Q14[], /* I Long term prediction coefs */
+ const opus_int16 AR_shp_Q13[], /* I Noise shaping coefs */
+ opus_int lag, /* I Pitch lag */
+ opus_int32 HarmShapeFIRPacked_Q14, /* I */
+ opus_int Tilt_Q14, /* I Spectral tilt */
+ opus_int32 LF_shp_Q14, /* I */
+ opus_int32 Gain_Q16, /* I */
+ opus_int Lambda_Q10, /* I */
+ opus_int offset_Q10, /* I */
+ opus_int length, /* I Input length */
+ opus_int subfr, /* I Subframe number */
+ opus_int shapingLPCOrder, /* I Shaping LPC filter order */
+ opus_int predictLPCOrder, /* I Prediction filter order */
+ opus_int warping_Q16, /* I */
+ opus_int nStatesDelayedDecision, /* I Number of states in decision tree */
+ opus_int *smpl_buf_idx, /* I Index to newest samples in buffers */
+ opus_int decisionDelay /* I */
+)
+{
+ opus_int i, j, k, Winner_ind, RDmin_ind, RDmax_ind, last_smple_idx;
+ opus_int32 Winner_rand_state;
+ opus_int32 LTP_pred_Q14, LPC_pred_Q14, n_AR_Q14, n_LTP_Q14;
+ opus_int32 n_LF_Q14, r_Q10, rr_Q10, rd1_Q10, rd2_Q10, RDmin_Q10, RDmax_Q10;
+ opus_int32 q1_Q0, q1_Q10, q2_Q10, exc_Q14, LPC_exc_Q14, xq_Q14, Gain_Q10;
+ opus_int32 tmp1, tmp2, sLF_AR_shp_Q14;
+ opus_int32 *pred_lag_ptr, *shp_lag_ptr, *psLPC_Q14;
+ VARDECL( NSQ_sample_pair, psSampleState );
+ NSQ_del_dec_struct *psDD;
+ NSQ_sample_struct *psSS;
+ SAVE_STACK;
+
+ silk_assert( nStatesDelayedDecision > 0 );
+ ALLOC( psSampleState, nStatesDelayedDecision, NSQ_sample_pair );
+
+ shp_lag_ptr = &NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - lag + HARM_SHAPE_FIR_TAPS / 2 ];
+ pred_lag_ptr = &sLTP_Q15[ NSQ->sLTP_buf_idx - lag + LTP_ORDER / 2 ];
+ Gain_Q10 = silk_RSHIFT( Gain_Q16, 6 );
+
+ for( i = 0; i < length; i++ ) {
+ /* Perform common calculations used in all states */
+
+ /* Long-term prediction */
+ if( signalType == TYPE_VOICED ) {
+ /* Unrolled loop */
+ /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+ LTP_pred_Q14 = 2;
+ LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ 0 ], b_Q14[ 0 ] );
+ LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -1 ], b_Q14[ 1 ] );
+ LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -2 ], b_Q14[ 2 ] );
+ LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -3 ], b_Q14[ 3 ] );
+ LTP_pred_Q14 = silk_SMLAWB( LTP_pred_Q14, pred_lag_ptr[ -4 ], b_Q14[ 4 ] );
+ LTP_pred_Q14 = silk_LSHIFT( LTP_pred_Q14, 1 ); /* Q13 -> Q14 */
+ pred_lag_ptr++;
+ } else {
+ LTP_pred_Q14 = 0;
+ }
+
+ /* Long-term shaping */
+ if( lag > 0 ) {
+ /* Symmetric, packed FIR coefficients */
+ n_LTP_Q14 = silk_SMULWB( silk_ADD32( shp_lag_ptr[ 0 ], shp_lag_ptr[ -2 ] ), HarmShapeFIRPacked_Q14 );
+ n_LTP_Q14 = silk_SMLAWT( n_LTP_Q14, shp_lag_ptr[ -1 ], HarmShapeFIRPacked_Q14 );
+ n_LTP_Q14 = silk_SUB_LSHIFT32( LTP_pred_Q14, n_LTP_Q14, 2 ); /* Q12 -> Q14 */
+ shp_lag_ptr++;
+ } else {
+ n_LTP_Q14 = 0;
+ }
+
+ for( k = 0; k < nStatesDelayedDecision; k++ ) {
+ /* Delayed decision state */
+ psDD = &psDelDec[ k ];
+
+ /* Sample state */
+ psSS = psSampleState[ k ];
+
+ /* Generate dither */
+ psDD->Seed = silk_RAND( psDD->Seed );
+
+ /* Pointer used in short term prediction and shaping */
+ psLPC_Q14 = &psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH - 1 + i ];
+ /* Short-term prediction */
+ silk_assert( predictLPCOrder == 10 || predictLPCOrder == 16 );
+ /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+ LPC_pred_Q14 = silk_RSHIFT( predictLPCOrder, 1 );
+ LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ 0 ], a_Q12[ 0 ] );
+ LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -1 ], a_Q12[ 1 ] );
+ LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -2 ], a_Q12[ 2 ] );
+ LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -3 ], a_Q12[ 3 ] );
+ LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -4 ], a_Q12[ 4 ] );
+ LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -5 ], a_Q12[ 5 ] );
+ LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -6 ], a_Q12[ 6 ] );
+ LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -7 ], a_Q12[ 7 ] );
+ LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -8 ], a_Q12[ 8 ] );
+ LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -9 ], a_Q12[ 9 ] );
+ if( predictLPCOrder == 16 ) {
+ LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -10 ], a_Q12[ 10 ] );
+ LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -11 ], a_Q12[ 11 ] );
+ LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -12 ], a_Q12[ 12 ] );
+ LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -13 ], a_Q12[ 13 ] );
+ LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -14 ], a_Q12[ 14 ] );
+ LPC_pred_Q14 = silk_SMLAWB( LPC_pred_Q14, psLPC_Q14[ -15 ], a_Q12[ 15 ] );
+ }
+ LPC_pred_Q14 = silk_LSHIFT( LPC_pred_Q14, 4 ); /* Q10 -> Q14 */
+
+ /* Noise shape feedback */
+ silk_assert( ( shapingLPCOrder & 1 ) == 0 ); /* check that order is even */
+ /* Output of lowpass section */
+ tmp2 = silk_SMLAWB( psLPC_Q14[ 0 ], psDD->sAR2_Q14[ 0 ], warping_Q16 );
+ /* Output of allpass section */
+ tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ 0 ], psDD->sAR2_Q14[ 1 ] - tmp2, warping_Q16 );
+ psDD->sAR2_Q14[ 0 ] = tmp2;
+ n_AR_Q14 = silk_RSHIFT( shapingLPCOrder, 1 );
+ n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ 0 ] );
+ /* Loop over allpass sections */
+ for( j = 2; j < shapingLPCOrder; j += 2 ) {
+ /* Output of allpass section */
+ tmp2 = silk_SMLAWB( psDD->sAR2_Q14[ j - 1 ], psDD->sAR2_Q14[ j + 0 ] - tmp1, warping_Q16 );
+ psDD->sAR2_Q14[ j - 1 ] = tmp1;
+ n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ j - 1 ] );
+ /* Output of allpass section */
+ tmp1 = silk_SMLAWB( psDD->sAR2_Q14[ j + 0 ], psDD->sAR2_Q14[ j + 1 ] - tmp2, warping_Q16 );
+ psDD->sAR2_Q14[ j + 0 ] = tmp2;
+ n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp2, AR_shp_Q13[ j ] );
+ }
+ psDD->sAR2_Q14[ shapingLPCOrder - 1 ] = tmp1;
+ n_AR_Q14 = silk_SMLAWB( n_AR_Q14, tmp1, AR_shp_Q13[ shapingLPCOrder - 1 ] );
+
+ n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 1 ); /* Q11 -> Q12 */
+ n_AR_Q14 = silk_SMLAWB( n_AR_Q14, psDD->LF_AR_Q14, Tilt_Q14 ); /* Q12 */
+ n_AR_Q14 = silk_LSHIFT( n_AR_Q14, 2 ); /* Q12 -> Q14 */
+
+ n_LF_Q14 = silk_SMULWB( psDD->Shape_Q14[ *smpl_buf_idx ], LF_shp_Q14 ); /* Q12 */
+ n_LF_Q14 = silk_SMLAWT( n_LF_Q14, psDD->LF_AR_Q14, LF_shp_Q14 ); /* Q12 */
+ n_LF_Q14 = silk_LSHIFT( n_LF_Q14, 2 ); /* Q12 -> Q14 */
+
+ /* Input minus prediction plus noise feedback */
+ /* r = x[ i ] - LTP_pred - LPC_pred + n_AR + n_Tilt + n_LF + n_LTP */
+ tmp1 = silk_ADD32( n_AR_Q14, n_LF_Q14 ); /* Q14 */
+ tmp2 = silk_ADD32( n_LTP_Q14, LPC_pred_Q14 ); /* Q13 */
+ tmp1 = silk_SUB32( tmp2, tmp1 ); /* Q13 */
+ tmp1 = silk_RSHIFT_ROUND( tmp1, 4 ); /* Q10 */
+
+ r_Q10 = silk_SUB32( x_Q10[ i ], tmp1 ); /* residual error Q10 */
+
+ /* Flip sign depending on dither */
+ if ( psDD->Seed < 0 ) {
+ r_Q10 = -r_Q10;
+ }
+ r_Q10 = silk_LIMIT_32( r_Q10, -(31 << 10), 30 << 10 );
+
+ /* Find two quantization level candidates and measure their rate-distortion */
+ q1_Q10 = silk_SUB32( r_Q10, offset_Q10 );
+ q1_Q0 = silk_RSHIFT( q1_Q10, 10 );
+ if( q1_Q0 > 0 ) {
+ q1_Q10 = silk_SUB32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
+ q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 );
+ q2_Q10 = silk_ADD32( q1_Q10, 1024 );
+ rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 );
+ rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+ } else if( q1_Q0 == 0 ) {
+ q1_Q10 = offset_Q10;
+ q2_Q10 = silk_ADD32( q1_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
+ rd1_Q10 = silk_SMULBB( q1_Q10, Lambda_Q10 );
+ rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+ } else if( q1_Q0 == -1 ) {
+ q2_Q10 = offset_Q10;
+ q1_Q10 = silk_SUB32( q2_Q10, 1024 - QUANT_LEVEL_ADJUST_Q10 );
+ rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
+ rd2_Q10 = silk_SMULBB( q2_Q10, Lambda_Q10 );
+ } else { /* q1_Q0 < -1 */
+ q1_Q10 = silk_ADD32( silk_LSHIFT( q1_Q0, 10 ), QUANT_LEVEL_ADJUST_Q10 );
+ q1_Q10 = silk_ADD32( q1_Q10, offset_Q10 );
+ q2_Q10 = silk_ADD32( q1_Q10, 1024 );
+ rd1_Q10 = silk_SMULBB( -q1_Q10, Lambda_Q10 );
+ rd2_Q10 = silk_SMULBB( -q2_Q10, Lambda_Q10 );
+ }
+ rr_Q10 = silk_SUB32( r_Q10, q1_Q10 );
+ rd1_Q10 = silk_RSHIFT( silk_SMLABB( rd1_Q10, rr_Q10, rr_Q10 ), 10 );
+ rr_Q10 = silk_SUB32( r_Q10, q2_Q10 );
+ rd2_Q10 = silk_RSHIFT( silk_SMLABB( rd2_Q10, rr_Q10, rr_Q10 ), 10 );
+
+ if( rd1_Q10 < rd2_Q10 ) {
+ psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 );
+ psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 );
+ psSS[ 0 ].Q_Q10 = q1_Q10;
+ psSS[ 1 ].Q_Q10 = q2_Q10;
+ } else {
+ psSS[ 0 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd2_Q10 );
+ psSS[ 1 ].RD_Q10 = silk_ADD32( psDD->RD_Q10, rd1_Q10 );
+ psSS[ 0 ].Q_Q10 = q2_Q10;
+ psSS[ 1 ].Q_Q10 = q1_Q10;
+ }
+
+ /* Update states for best quantization */
+
+ /* Quantized excitation */
+ exc_Q14 = silk_LSHIFT32( psSS[ 0 ].Q_Q10, 4 );
+ if ( psDD->Seed < 0 ) {
+ exc_Q14 = -exc_Q14;
+ }
+
+ /* Add predictions */
+ LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 );
+ xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 );
+
+ /* Update states */
+ sLF_AR_shp_Q14 = silk_SUB32( xq_Q14, n_AR_Q14 );
+ psSS[ 0 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 );
+ psSS[ 0 ].LF_AR_Q14 = sLF_AR_shp_Q14;
+ psSS[ 0 ].LPC_exc_Q14 = LPC_exc_Q14;
+ psSS[ 0 ].xq_Q14 = xq_Q14;
+
+ /* Update states for second best quantization */
+
+ /* Quantized excitation */
+ exc_Q14 = silk_LSHIFT32( psSS[ 1 ].Q_Q10, 4 );
+ if ( psDD->Seed < 0 ) {
+ exc_Q14 = -exc_Q14;
+ }
+
+
+ /* Add predictions */
+ LPC_exc_Q14 = silk_ADD32( exc_Q14, LTP_pred_Q14 );
+ xq_Q14 = silk_ADD32( LPC_exc_Q14, LPC_pred_Q14 );
+
+ /* Update states */
+ sLF_AR_shp_Q14 = silk_SUB32( xq_Q14, n_AR_Q14 );
+ psSS[ 1 ].sLTP_shp_Q14 = silk_SUB32( sLF_AR_shp_Q14, n_LF_Q14 );
+ psSS[ 1 ].LF_AR_Q14 = sLF_AR_shp_Q14;
+ psSS[ 1 ].LPC_exc_Q14 = LPC_exc_Q14;
+ psSS[ 1 ].xq_Q14 = xq_Q14;
+ }
+
+ *smpl_buf_idx = ( *smpl_buf_idx - 1 ) & DECISION_DELAY_MASK; /* Index to newest samples */
+ last_smple_idx = ( *smpl_buf_idx + decisionDelay ) & DECISION_DELAY_MASK; /* Index to decisionDelay old samples */
+
+ /* Find winner */
+ RDmin_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10;
+ Winner_ind = 0;
+ for( k = 1; k < nStatesDelayedDecision; k++ ) {
+ if( psSampleState[ k ][ 0 ].RD_Q10 < RDmin_Q10 ) {
+ RDmin_Q10 = psSampleState[ k ][ 0 ].RD_Q10;
+ Winner_ind = k;
+ }
+ }
+
+ /* Increase RD values of expired states */
+ Winner_rand_state = psDelDec[ Winner_ind ].RandState[ last_smple_idx ];
+ for( k = 0; k < nStatesDelayedDecision; k++ ) {
+ if( psDelDec[ k ].RandState[ last_smple_idx ] != Winner_rand_state ) {
+ psSampleState[ k ][ 0 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 0 ].RD_Q10, silk_int32_MAX >> 4 );
+ psSampleState[ k ][ 1 ].RD_Q10 = silk_ADD32( psSampleState[ k ][ 1 ].RD_Q10, silk_int32_MAX >> 4 );
+ silk_assert( psSampleState[ k ][ 0 ].RD_Q10 >= 0 );
+ }
+ }
+
+ /* Find worst in first set and best in second set */
+ RDmax_Q10 = psSampleState[ 0 ][ 0 ].RD_Q10;
+ RDmin_Q10 = psSampleState[ 0 ][ 1 ].RD_Q10;
+ RDmax_ind = 0;
+ RDmin_ind = 0;
+ for( k = 1; k < nStatesDelayedDecision; k++ ) {
+ /* find worst in first set */
+ if( psSampleState[ k ][ 0 ].RD_Q10 > RDmax_Q10 ) {
+ RDmax_Q10 = psSampleState[ k ][ 0 ].RD_Q10;
+ RDmax_ind = k;
+ }
+ /* find best in second set */
+ if( psSampleState[ k ][ 1 ].RD_Q10 < RDmin_Q10 ) {
+ RDmin_Q10 = psSampleState[ k ][ 1 ].RD_Q10;
+ RDmin_ind = k;
+ }
+ }
+
+ /* Replace a state if best from second set outperforms worst in first set */
+ if( RDmin_Q10 < RDmax_Q10 ) {
+ silk_memcpy( ( (opus_int32 *)&psDelDec[ RDmax_ind ] ) + i,
+ ( (opus_int32 *)&psDelDec[ RDmin_ind ] ) + i, sizeof( NSQ_del_dec_struct ) - i * sizeof( opus_int32) );
+ silk_memcpy( &psSampleState[ RDmax_ind ][ 0 ], &psSampleState[ RDmin_ind ][ 1 ], sizeof( NSQ_sample_struct ) );
+ }
+
+ /* Write samples from winner to output and long-term filter states */
+ psDD = &psDelDec[ Winner_ind ];
+ if( subfr > 0 || i >= decisionDelay ) {
+ pulses[ i - decisionDelay ] = (opus_int8)silk_RSHIFT_ROUND( psDD->Q_Q10[ last_smple_idx ], 10 );
+ xq[ i - decisionDelay ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND(
+ silk_SMULWW( psDD->Xq_Q14[ last_smple_idx ], delayedGain_Q10[ last_smple_idx ] ), 8 ) );
+ NSQ->sLTP_shp_Q14[ NSQ->sLTP_shp_buf_idx - decisionDelay ] = psDD->Shape_Q14[ last_smple_idx ];
+ sLTP_Q15[ NSQ->sLTP_buf_idx - decisionDelay ] = psDD->Pred_Q15[ last_smple_idx ];
+ }
+ NSQ->sLTP_shp_buf_idx++;
+ NSQ->sLTP_buf_idx++;
+
+ /* Update states */
+ for( k = 0; k < nStatesDelayedDecision; k++ ) {
+ psDD = &psDelDec[ k ];
+ psSS = &psSampleState[ k ][ 0 ];
+ psDD->LF_AR_Q14 = psSS->LF_AR_Q14;
+ psDD->sLPC_Q14[ NSQ_LPC_BUF_LENGTH + i ] = psSS->xq_Q14;
+ psDD->Xq_Q14[ *smpl_buf_idx ] = psSS->xq_Q14;
+ psDD->Q_Q10[ *smpl_buf_idx ] = psSS->Q_Q10;
+ psDD->Pred_Q15[ *smpl_buf_idx ] = silk_LSHIFT32( psSS->LPC_exc_Q14, 1 );
+ psDD->Shape_Q14[ *smpl_buf_idx ] = psSS->sLTP_shp_Q14;
+ psDD->Seed = silk_ADD32_ovflw( psDD->Seed, silk_RSHIFT_ROUND( psSS->Q_Q10, 10 ) );
+ psDD->RandState[ *smpl_buf_idx ] = psDD->Seed;
+ psDD->RD_Q10 = psSS->RD_Q10;
+ }
+ delayedGain_Q10[ *smpl_buf_idx ] = Gain_Q10;
+ }
+ /* Update LPC states */
+ for( k = 0; k < nStatesDelayedDecision; k++ ) {
+ psDD = &psDelDec[ k ];
+ silk_memcpy( psDD->sLPC_Q14, &psDD->sLPC_Q14[ length ], NSQ_LPC_BUF_LENGTH * sizeof( opus_int32 ) );
+ }
+ RESTORE_STACK;
+}
+
+static OPUS_INLINE void silk_nsq_del_dec_scale_states(
+ const silk_encoder_state *psEncC, /* I Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ NSQ_del_dec_struct psDelDec[], /* I/O Delayed decision states */
+ const opus_int32 x_Q3[], /* I Input in Q3 */
+ opus_int32 x_sc_Q10[], /* O Input scaled with 1/Gain in Q10 */
+ const opus_int16 sLTP[], /* I Re-whitened LTP state in Q0 */
+ opus_int32 sLTP_Q15[], /* O LTP state matching scaled input */
+ opus_int subfr, /* I Subframe number */
+ opus_int nStatesDelayedDecision, /* I Number of del dec states */
+ const opus_int LTP_scale_Q14, /* I LTP state scaling */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag */
+ const opus_int signal_type, /* I Signal type */
+ const opus_int decisionDelay /* I Decision delay */
+)
+{
+ opus_int i, k, lag;
+ opus_int32 gain_adj_Q16, inv_gain_Q31, inv_gain_Q23;
+ NSQ_del_dec_struct *psDD;
+
+ lag = pitchL[ subfr ];
+ inv_gain_Q31 = silk_INVERSE32_varQ( silk_max( Gains_Q16[ subfr ], 1 ), 47 );
+ silk_assert( inv_gain_Q31 != 0 );
+
+ /* Calculate gain adjustment factor */
+ if( Gains_Q16[ subfr ] != NSQ->prev_gain_Q16 ) {
+ gain_adj_Q16 = silk_DIV32_varQ( NSQ->prev_gain_Q16, Gains_Q16[ subfr ], 16 );
+ } else {
+ gain_adj_Q16 = (opus_int32)1 << 16;
+ }
+
+ /* Scale input */
+ inv_gain_Q23 = silk_RSHIFT_ROUND( inv_gain_Q31, 8 );
+ for( i = 0; i < psEncC->subfr_length; i++ ) {
+ x_sc_Q10[ i ] = silk_SMULWW( x_Q3[ i ], inv_gain_Q23 );
+ }
+
+ /* Save inverse gain */
+ NSQ->prev_gain_Q16 = Gains_Q16[ subfr ];
+
+ /* After rewhitening the LTP state is un-scaled, so scale with inv_gain_Q16 */
+ if( NSQ->rewhite_flag ) {
+ if( subfr == 0 ) {
+ /* Do LTP downscaling */
+ inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, LTP_scale_Q14 ), 2 );
+ }
+ for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx; i++ ) {
+ silk_assert( i < MAX_FRAME_LENGTH );
+ sLTP_Q15[ i ] = silk_SMULWB( inv_gain_Q31, sLTP[ i ] );
+ }
+ }
+
+ /* Adjust for changing gain */
+ if( gain_adj_Q16 != (opus_int32)1 << 16 ) {
+ /* Scale long-term shaping state */
+ for( i = NSQ->sLTP_shp_buf_idx - psEncC->ltp_mem_length; i < NSQ->sLTP_shp_buf_idx; i++ ) {
+ NSQ->sLTP_shp_Q14[ i ] = silk_SMULWW( gain_adj_Q16, NSQ->sLTP_shp_Q14[ i ] );
+ }
+
+ /* Scale long-term prediction state */
+ if( signal_type == TYPE_VOICED && NSQ->rewhite_flag == 0 ) {
+ for( i = NSQ->sLTP_buf_idx - lag - LTP_ORDER / 2; i < NSQ->sLTP_buf_idx - decisionDelay; i++ ) {
+ sLTP_Q15[ i ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ i ] );
+ }
+ }
+
+ for( k = 0; k < nStatesDelayedDecision; k++ ) {
+ psDD = &psDelDec[ k ];
+
+ /* Scale scalar states */
+ psDD->LF_AR_Q14 = silk_SMULWW( gain_adj_Q16, psDD->LF_AR_Q14 );
+
+ /* Scale short-term prediction and shaping states */
+ for( i = 0; i < NSQ_LPC_BUF_LENGTH; i++ ) {
+ psDD->sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sLPC_Q14[ i ] );
+ }
+ for( i = 0; i < MAX_SHAPE_LPC_ORDER; i++ ) {
+ psDD->sAR2_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->sAR2_Q14[ i ] );
+ }
+ for( i = 0; i < DECISION_DELAY; i++ ) {
+ psDD->Pred_Q15[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Pred_Q15[ i ] );
+ psDD->Shape_Q14[ i ] = silk_SMULWW( gain_adj_Q16, psDD->Shape_Q14[ i ] );
+ }
+ }
+ }
+}
diff --git a/drivers/opus/silk/PLC.c b/drivers/opus/silk/PLC.c
new file mode 100644
index 0000000000..1f5ce09927
--- /dev/null
+++ b/drivers/opus/silk/PLC.c
@@ -0,0 +1,423 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+#include "opus/celt/stack_alloc.h"
+#include "opus/silk/PLC.h"
+
+#define NB_ATT 2
+static const opus_int16 HARM_ATT_Q15[NB_ATT] = { 32440, 31130 }; /* 0.99, 0.95 */
+static const opus_int16 PLC_RAND_ATTENUATE_V_Q15[NB_ATT] = { 31130, 26214 }; /* 0.95, 0.8 */
+static const opus_int16 PLC_RAND_ATTENUATE_UV_Q15[NB_ATT] = { 32440, 29491 }; /* 0.99, 0.9 */
+
+static OPUS_INLINE void silk_PLC_update(
+ silk_decoder_state *psDec, /* I/O Decoder state */
+ silk_decoder_control *psDecCtrl /* I/O Decoder control */
+);
+
+static OPUS_INLINE void silk_PLC_conceal(
+ silk_decoder_state *psDec, /* I/O Decoder state */
+ silk_decoder_control *psDecCtrl, /* I/O Decoder control */
+ opus_int16 frame[] /* O LPC residual signal */
+);
+
+
+void silk_PLC_Reset(
+ silk_decoder_state *psDec /* I/O Decoder state */
+)
+{
+ psDec->sPLC.pitchL_Q8 = silk_LSHIFT( psDec->frame_length, 8 - 1 );
+ psDec->sPLC.prevGain_Q16[ 0 ] = SILK_FIX_CONST( 1, 16 );
+ psDec->sPLC.prevGain_Q16[ 1 ] = SILK_FIX_CONST( 1, 16 );
+ psDec->sPLC.subfr_length = 20;
+ psDec->sPLC.nb_subfr = 2;
+}
+
+void silk_PLC(
+ silk_decoder_state *psDec, /* I/O Decoder state */
+ silk_decoder_control *psDecCtrl, /* I/O Decoder control */
+ opus_int16 frame[], /* I/O signal */
+ opus_int lost /* I Loss flag */
+)
+{
+ /* PLC control function */
+ if( psDec->fs_kHz != psDec->sPLC.fs_kHz ) {
+ silk_PLC_Reset( psDec );
+ psDec->sPLC.fs_kHz = psDec->fs_kHz;
+ }
+
+ if( lost ) {
+ /****************************/
+ /* Generate Signal */
+ /****************************/
+ silk_PLC_conceal( psDec, psDecCtrl, frame );
+
+ psDec->lossCnt++;
+ } else {
+ /****************************/
+ /* Update state */
+ /****************************/
+ silk_PLC_update( psDec, psDecCtrl );
+ }
+}
+
+/**************************************************/
+/* Update state of PLC */
+/**************************************************/
+static OPUS_INLINE void silk_PLC_update(
+ silk_decoder_state *psDec, /* I/O Decoder state */
+ silk_decoder_control *psDecCtrl /* I/O Decoder control */
+)
+{
+ opus_int32 LTP_Gain_Q14, temp_LTP_Gain_Q14;
+ opus_int i, j;
+ silk_PLC_struct *psPLC;
+
+ psPLC = &psDec->sPLC;
+
+ /* Update parameters used in case of packet loss */
+ psDec->prevSignalType = psDec->indices.signalType;
+ LTP_Gain_Q14 = 0;
+ if( psDec->indices.signalType == TYPE_VOICED ) {
+ /* Find the parameters for the last subframe which contains a pitch pulse */
+ for( j = 0; j * psDec->subfr_length < psDecCtrl->pitchL[ psDec->nb_subfr - 1 ]; j++ ) {
+ if( j == psDec->nb_subfr ) {
+ break;
+ }
+ temp_LTP_Gain_Q14 = 0;
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ temp_LTP_Gain_Q14 += psDecCtrl->LTPCoef_Q14[ ( psDec->nb_subfr - 1 - j ) * LTP_ORDER + i ];
+ }
+ if( temp_LTP_Gain_Q14 > LTP_Gain_Q14 ) {
+ LTP_Gain_Q14 = temp_LTP_Gain_Q14;
+ silk_memcpy( psPLC->LTPCoef_Q14,
+ &psDecCtrl->LTPCoef_Q14[ silk_SMULBB( psDec->nb_subfr - 1 - j, LTP_ORDER ) ],
+ LTP_ORDER * sizeof( opus_int16 ) );
+
+ psPLC->pitchL_Q8 = silk_LSHIFT( psDecCtrl->pitchL[ psDec->nb_subfr - 1 - j ], 8 );
+ }
+ }
+
+ silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) );
+ psPLC->LTPCoef_Q14[ LTP_ORDER / 2 ] = LTP_Gain_Q14;
+
+ /* Limit LT coefs */
+ if( LTP_Gain_Q14 < V_PITCH_GAIN_START_MIN_Q14 ) {
+ opus_int scale_Q10;
+ opus_int32 tmp;
+
+ tmp = silk_LSHIFT( V_PITCH_GAIN_START_MIN_Q14, 10 );
+ scale_Q10 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) );
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q10 ), 10 );
+ }
+ } else if( LTP_Gain_Q14 > V_PITCH_GAIN_START_MAX_Q14 ) {
+ opus_int scale_Q14;
+ opus_int32 tmp;
+
+ tmp = silk_LSHIFT( V_PITCH_GAIN_START_MAX_Q14, 14 );
+ scale_Q14 = silk_DIV32( tmp, silk_max( LTP_Gain_Q14, 1 ) );
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ psPLC->LTPCoef_Q14[ i ] = silk_RSHIFT( silk_SMULBB( psPLC->LTPCoef_Q14[ i ], scale_Q14 ), 14 );
+ }
+ }
+ } else {
+ psPLC->pitchL_Q8 = silk_LSHIFT( silk_SMULBB( psDec->fs_kHz, 18 ), 8 );
+ silk_memset( psPLC->LTPCoef_Q14, 0, LTP_ORDER * sizeof( opus_int16 ));
+ }
+
+ /* Save LPC coeficients */
+ silk_memcpy( psPLC->prevLPC_Q12, psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) );
+ psPLC->prevLTP_scale_Q14 = psDecCtrl->LTP_scale_Q14;
+
+ /* Save last two gains */
+ silk_memcpy( psPLC->prevGain_Q16, &psDecCtrl->Gains_Q16[ psDec->nb_subfr - 2 ], 2 * sizeof( opus_int32 ) );
+
+ psPLC->subfr_length = psDec->subfr_length;
+ psPLC->nb_subfr = psDec->nb_subfr;
+}
+
+static OPUS_INLINE void silk_PLC_conceal(
+ silk_decoder_state *psDec, /* I/O Decoder state */
+ silk_decoder_control *psDecCtrl, /* I/O Decoder control */
+ opus_int16 frame[] /* O LPC residual signal */
+)
+{
+ opus_int i, j, k;
+ opus_int lag, idx, sLTP_buf_idx, shift1, shift2;
+ opus_int32 rand_seed, harm_Gain_Q15, rand_Gain_Q15, inv_gain_Q30;
+ opus_int32 energy1, energy2, *rand_ptr, *pred_lag_ptr;
+ opus_int32 LPC_pred_Q10, LTP_pred_Q12;
+ opus_int16 rand_scale_Q14;
+ opus_int16 *B_Q14, *exc_buf_ptr;
+ opus_int32 *sLPC_Q14_ptr;
+ VARDECL( opus_int16, exc_buf );
+ opus_int16 A_Q12[ MAX_LPC_ORDER ];
+ VARDECL( opus_int16, sLTP );
+ VARDECL( opus_int32, sLTP_Q14 );
+ silk_PLC_struct *psPLC = &psDec->sPLC;
+ opus_int32 prevGain_Q10[2];
+ SAVE_STACK;
+
+ ALLOC( exc_buf, 2*psPLC->subfr_length, opus_int16 );
+ ALLOC( sLTP, psDec->ltp_mem_length, opus_int16 );
+ ALLOC( sLTP_Q14, psDec->ltp_mem_length + psDec->frame_length, opus_int32 );
+
+ prevGain_Q10[0] = silk_RSHIFT( psPLC->prevGain_Q16[ 0 ], 6);
+ prevGain_Q10[1] = silk_RSHIFT( psPLC->prevGain_Q16[ 1 ], 6);
+
+ if( psDec->first_frame_after_reset ) {
+ silk_memset( psPLC->prevLPC_Q12, 0, sizeof( psPLC->prevLPC_Q12 ) );
+ }
+
+ /* Find random noise component */
+ /* Scale previous excitation signal */
+ exc_buf_ptr = exc_buf;
+ for( k = 0; k < 2; k++ ) {
+ for( i = 0; i < psPLC->subfr_length; i++ ) {
+ exc_buf_ptr[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT(
+ silk_SMULWW( psDec->exc_Q14[ i + ( k + psPLC->nb_subfr - 2 ) * psPLC->subfr_length ], prevGain_Q10[ k ] ), 8 ) );
+ }
+ exc_buf_ptr += psPLC->subfr_length;
+ }
+ /* Find the subframe with lowest energy of the last two and use that as random noise generator */
+ silk_sum_sqr_shift( &energy1, &shift1, exc_buf, psPLC->subfr_length );
+ silk_sum_sqr_shift( &energy2, &shift2, &exc_buf[ psPLC->subfr_length ], psPLC->subfr_length );
+
+ if( silk_RSHIFT( energy1, shift2 ) < silk_RSHIFT( energy2, shift1 ) ) {
+ /* First sub-frame has lowest energy */
+ rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, ( psPLC->nb_subfr - 1 ) * psPLC->subfr_length - RAND_BUF_SIZE ) ];
+ } else {
+ /* Second sub-frame has lowest energy */
+ rand_ptr = &psDec->exc_Q14[ silk_max_int( 0, psPLC->nb_subfr * psPLC->subfr_length - RAND_BUF_SIZE ) ];
+ }
+
+ /* Set up Gain to random noise component */
+ B_Q14 = psPLC->LTPCoef_Q14;
+ rand_scale_Q14 = psPLC->randScale_Q14;
+
+ /* Set up attenuation gains */
+ harm_Gain_Q15 = HARM_ATT_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
+ if( psDec->prevSignalType == TYPE_VOICED ) {
+ rand_Gain_Q15 = PLC_RAND_ATTENUATE_V_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
+ } else {
+ rand_Gain_Q15 = PLC_RAND_ATTENUATE_UV_Q15[ silk_min_int( NB_ATT - 1, psDec->lossCnt ) ];
+ }
+
+ /* LPC concealment. Apply BWE to previous LPC */
+ silk_bwexpander( psPLC->prevLPC_Q12, psDec->LPC_order, SILK_FIX_CONST( BWE_COEF, 16 ) );
+
+ /* Preload LPC coeficients to array on stack. Gives small performance gain */
+ silk_memcpy( A_Q12, psPLC->prevLPC_Q12, psDec->LPC_order * sizeof( opus_int16 ) );
+
+ /* First Lost frame */
+ if( psDec->lossCnt == 0 ) {
+ rand_scale_Q14 = 1 << 14;
+
+ /* Reduce random noise Gain for voiced frames */
+ if( psDec->prevSignalType == TYPE_VOICED ) {
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ rand_scale_Q14 -= B_Q14[ i ];
+ }
+ rand_scale_Q14 = silk_max_16( 3277, rand_scale_Q14 ); /* 0.2 */
+ rand_scale_Q14 = (opus_int16)silk_RSHIFT( silk_SMULBB( rand_scale_Q14, psPLC->prevLTP_scale_Q14 ), 14 );
+ } else {
+ /* Reduce random noise for unvoiced frames with high LPC gain */
+ opus_int32 invGain_Q30, down_scale_Q30;
+
+ invGain_Q30 = silk_LPC_inverse_pred_gain( psPLC->prevLPC_Q12, psDec->LPC_order );
+
+ down_scale_Q30 = silk_min_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_HIGH_THRES ), invGain_Q30 );
+ down_scale_Q30 = silk_max_32( silk_RSHIFT( (opus_int32)1 << 30, LOG2_INV_LPC_GAIN_LOW_THRES ), down_scale_Q30 );
+ down_scale_Q30 = silk_LSHIFT( down_scale_Q30, LOG2_INV_LPC_GAIN_HIGH_THRES );
+
+ rand_Gain_Q15 = silk_RSHIFT( silk_SMULWB( down_scale_Q30, rand_Gain_Q15 ), 14 );
+ }
+ }
+
+ rand_seed = psPLC->rand_seed;
+ lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 );
+ sLTP_buf_idx = psDec->ltp_mem_length;
+
+ /* Rewhiten LTP state */
+ idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2;
+ silk_assert( idx > 0 );
+ silk_LPC_analysis_filter( &sLTP[ idx ], &psDec->outBuf[ idx ], A_Q12, psDec->ltp_mem_length - idx, psDec->LPC_order );
+ /* Scale LTP state */
+ inv_gain_Q30 = silk_INVERSE32_varQ( psPLC->prevGain_Q16[ 1 ], 46 );
+ inv_gain_Q30 = silk_min( inv_gain_Q30, silk_int32_MAX >> 1 );
+ for( i = idx + psDec->LPC_order; i < psDec->ltp_mem_length; i++ ) {
+ sLTP_Q14[ i ] = silk_SMULWB( inv_gain_Q30, sLTP[ i ] );
+ }
+
+ /***************************/
+ /* LTP synthesis filtering */
+ /***************************/
+ for( k = 0; k < psDec->nb_subfr; k++ ) {
+ /* Set up pointer */
+ pred_lag_ptr = &sLTP_Q14[ sLTP_buf_idx - lag + LTP_ORDER / 2 ];
+ for( i = 0; i < psDec->subfr_length; i++ ) {
+ /* Unrolled loop */
+ /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+ LTP_pred_Q12 = 2;
+ LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ 0 ], B_Q14[ 0 ] );
+ LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -1 ], B_Q14[ 1 ] );
+ LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -2 ], B_Q14[ 2 ] );
+ LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -3 ], B_Q14[ 3 ] );
+ LTP_pred_Q12 = silk_SMLAWB( LTP_pred_Q12, pred_lag_ptr[ -4 ], B_Q14[ 4 ] );
+ pred_lag_ptr++;
+
+ /* Generate LPC excitation */
+ rand_seed = silk_RAND( rand_seed );
+ idx = silk_RSHIFT( rand_seed, 25 ) & RAND_BUF_MASK;
+ sLTP_Q14[ sLTP_buf_idx ] = silk_LSHIFT32( silk_SMLAWB( LTP_pred_Q12, rand_ptr[ idx ], rand_scale_Q14 ), 2 );
+ sLTP_buf_idx++;
+ }
+
+ /* Gradually reduce LTP gain */
+ for( j = 0; j < LTP_ORDER; j++ ) {
+ B_Q14[ j ] = silk_RSHIFT( silk_SMULBB( harm_Gain_Q15, B_Q14[ j ] ), 15 );
+ }
+ /* Gradually reduce excitation gain */
+ rand_scale_Q14 = silk_RSHIFT( silk_SMULBB( rand_scale_Q14, rand_Gain_Q15 ), 15 );
+
+ /* Slowly increase pitch lag */
+ psPLC->pitchL_Q8 = silk_SMLAWB( psPLC->pitchL_Q8, psPLC->pitchL_Q8, PITCH_DRIFT_FAC_Q16 );
+ psPLC->pitchL_Q8 = silk_min_32( psPLC->pitchL_Q8, silk_LSHIFT( silk_SMULBB( MAX_PITCH_LAG_MS, psDec->fs_kHz ), 8 ) );
+ lag = silk_RSHIFT_ROUND( psPLC->pitchL_Q8, 8 );
+ }
+
+ /***************************/
+ /* LPC synthesis filtering */
+ /***************************/
+ sLPC_Q14_ptr = &sLTP_Q14[ psDec->ltp_mem_length - MAX_LPC_ORDER ];
+
+ /* Copy LPC state */
+ silk_memcpy( sLPC_Q14_ptr, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) );
+
+ silk_assert( psDec->LPC_order >= 10 ); /* check that unrolling works */
+ for( i = 0; i < psDec->frame_length; i++ ) {
+ /* partly unrolled */
+ /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+ LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 2 ], A_Q12[ 1 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 3 ], A_Q12[ 2 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 4 ], A_Q12[ 3 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 5 ], A_Q12[ 4 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 6 ], A_Q12[ 5 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 7 ], A_Q12[ 6 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 8 ], A_Q12[ 7 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 9 ], A_Q12[ 8 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - 10 ], A_Q12[ 9 ] );
+ for( j = 10; j < psDec->LPC_order; j++ ) {
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14_ptr[ MAX_LPC_ORDER + i - j - 1 ], A_Q12[ j ] );
+ }
+
+ /* Add prediction to LPC excitation */
+ sLPC_Q14_ptr[ MAX_LPC_ORDER + i ] = silk_ADD_LSHIFT32( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], LPC_pred_Q10, 4 );
+
+ /* Scale with Gain */
+ frame[ i ] = (opus_int16)silk_SAT16( silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14_ptr[ MAX_LPC_ORDER + i ], prevGain_Q10[ 1 ] ), 8 ) ) );
+ }
+
+ /* Save LPC state */
+ silk_memcpy( psDec->sLPC_Q14_buf, &sLPC_Q14_ptr[ psDec->frame_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) );
+
+ /**************************************/
+ /* Update states */
+ /**************************************/
+ psPLC->rand_seed = rand_seed;
+ psPLC->randScale_Q14 = rand_scale_Q14;
+ for( i = 0; i < MAX_NB_SUBFR; i++ ) {
+ psDecCtrl->pitchL[ i ] = lag;
+ }
+ RESTORE_STACK;
+}
+
+/* Glues concealed frames with new good received frames */
+void silk_PLC_glue_frames(
+ silk_decoder_state *psDec, /* I/O decoder state */
+ opus_int16 frame[], /* I/O signal */
+ opus_int length /* I length of signal */
+)
+{
+ opus_int i, energy_shift;
+ opus_int32 energy;
+ silk_PLC_struct *psPLC;
+ psPLC = &psDec->sPLC;
+
+ if( psDec->lossCnt ) {
+ /* Calculate energy in concealed residual */
+ silk_sum_sqr_shift( &psPLC->conc_energy, &psPLC->conc_energy_shift, frame, length );
+
+ psPLC->last_frame_lost = 1;
+ } else {
+ if( psDec->sPLC.last_frame_lost ) {
+ /* Calculate residual in decoded signal if last frame was lost */
+ silk_sum_sqr_shift( &energy, &energy_shift, frame, length );
+
+ /* Normalize energies */
+ if( energy_shift > psPLC->conc_energy_shift ) {
+ psPLC->conc_energy = silk_RSHIFT( psPLC->conc_energy, energy_shift - psPLC->conc_energy_shift );
+ } else if( energy_shift < psPLC->conc_energy_shift ) {
+ energy = silk_RSHIFT( energy, psPLC->conc_energy_shift - energy_shift );
+ }
+
+ /* Fade in the energy difference */
+ if( energy > psPLC->conc_energy ) {
+ opus_int32 frac_Q24, LZ;
+ opus_int32 gain_Q16, slope_Q16;
+
+ LZ = silk_CLZ32( psPLC->conc_energy );
+ LZ = LZ - 1;
+ psPLC->conc_energy = silk_LSHIFT( psPLC->conc_energy, LZ );
+ energy = silk_RSHIFT( energy, silk_max_32( 24 - LZ, 0 ) );
+
+ frac_Q24 = silk_DIV32( psPLC->conc_energy, silk_max( energy, 1 ) );
+
+ gain_Q16 = silk_LSHIFT( silk_SQRT_APPROX( frac_Q24 ), 4 );
+ slope_Q16 = silk_DIV32_16( ( (opus_int32)1 << 16 ) - gain_Q16, length );
+ /* Make slope 4x steeper to avoid missing onsets after DTX */
+ slope_Q16 = silk_LSHIFT( slope_Q16, 2 );
+
+ for( i = 0; i < length; i++ ) {
+ frame[ i ] = silk_SMULWB( gain_Q16, frame[ i ] );
+ gain_Q16 += slope_Q16;
+ if( gain_Q16 > (opus_int32)1 << 16 ) {
+ break;
+ }
+ }
+ }
+ }
+ psPLC->last_frame_lost = 0;
+ }
+}
diff --git a/drivers/opus/silk/PLC.h b/drivers/opus/silk/PLC.h
new file mode 100644
index 0000000000..ae573fc00c
--- /dev/null
+++ b/drivers/opus/silk/PLC.h
@@ -0,0 +1,61 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_PLC_H
+#define SILK_PLC_H
+
+#include "opus/silk/silk_main.h"
+
+#define BWE_COEF 0.99
+#define V_PITCH_GAIN_START_MIN_Q14 11469 /* 0.7 in Q14 */
+#define V_PITCH_GAIN_START_MAX_Q14 15565 /* 0.95 in Q14 */
+#define MAX_PITCH_LAG_MS 18
+#define RAND_BUF_SIZE 128
+#define RAND_BUF_MASK ( RAND_BUF_SIZE - 1 )
+#define LOG2_INV_LPC_GAIN_HIGH_THRES 3 /* 2^3 = 8 dB LPC gain */
+#define LOG2_INV_LPC_GAIN_LOW_THRES 8 /* 2^8 = 24 dB LPC gain */
+#define PITCH_DRIFT_FAC_Q16 655 /* 0.01 in Q16 */
+
+void silk_PLC_Reset(
+ silk_decoder_state *psDec /* I/O Decoder state */
+);
+
+void silk_PLC(
+ silk_decoder_state *psDec, /* I/O Decoder state */
+ silk_decoder_control *psDecCtrl, /* I/O Decoder control */
+ opus_int16 frame[], /* I/O signal */
+ opus_int lost /* I Loss flag */
+);
+
+void silk_PLC_glue_frames(
+ silk_decoder_state *psDec, /* I/O decoder state */
+ opus_int16 frame[], /* I/O signal */
+ opus_int length /* I length of signal */
+);
+
+#endif
+
diff --git a/drivers/opus/silk/SigProc_FIX.h b/drivers/opus/silk/SigProc_FIX.h
new file mode 100644
index 0000000000..f4db0fa9a4
--- /dev/null
+++ b/drivers/opus/silk/SigProc_FIX.h
@@ -0,0 +1,594 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_SIGPROC_FIX_H
+#define SILK_SIGPROC_FIX_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*#define silk_MACRO_COUNT */ /* Used to enable WMOPS counting */
+
+#define SILK_MAX_ORDER_LPC 16 /* max order of the LPC analysis in schur() and k2a() */
+
+#include <string.h> /* for memset(), memcpy(), memmove() */
+#include "opus/silk/typedef.h"
+#include "opus/silk/resampler_structs.h"
+#include "opus/silk/macros.h"
+
+
+/********************************************************************/
+/* SIGNAL PROCESSING FUNCTIONS */
+/********************************************************************/
+
+/*!
+ * Initialize/reset the resampler state for a given pair of input/output sampling rates
+*/
+opus_int silk_resampler_init(
+ silk_resampler_state_struct *S, /* I/O Resampler state */
+ opus_int32 Fs_Hz_in, /* I Input sampling rate (Hz) */
+ opus_int32 Fs_Hz_out, /* I Output sampling rate (Hz) */
+ opus_int forEnc /* I If 1: encoder; if 0: decoder */
+);
+
+/*!
+ * Resampler: convert from one sampling rate to another
+ */
+opus_int silk_resampler(
+ silk_resampler_state_struct *S, /* I/O Resampler state */
+ opus_int16 out[], /* O Output signal */
+ const opus_int16 in[], /* I Input signal */
+ opus_int32 inLen /* I Number of input samples */
+);
+
+/*!
+* Downsample 2x, mediocre quality
+*/
+void silk_resampler_down2(
+ opus_int32 *S, /* I/O State vector [ 2 ] */
+ opus_int16 *out, /* O Output signal [ len ] */
+ const opus_int16 *in, /* I Input signal [ floor(len/2) ] */
+ opus_int32 inLen /* I Number of input samples */
+);
+
+/*!
+ * Downsample by a factor 2/3, low quality
+*/
+void silk_resampler_down2_3(
+ opus_int32 *S, /* I/O State vector [ 6 ] */
+ opus_int16 *out, /* O Output signal [ floor(2*inLen/3) ] */
+ const opus_int16 *in, /* I Input signal [ inLen ] */
+ opus_int32 inLen /* I Number of input samples */
+);
+
+/*!
+ * second order ARMA filter;
+ * slower than biquad() but uses more precise coefficients
+ * can handle (slowly) varying coefficients
+ */
+void silk_biquad_alt(
+ const opus_int16 *in, /* I input signal */
+ const opus_int32 *B_Q28, /* I MA coefficients [3] */
+ const opus_int32 *A_Q28, /* I AR coefficients [2] */
+ opus_int32 *S, /* I/O State vector [2] */
+ opus_int16 *out, /* O output signal */
+ const opus_int32 len, /* I signal length (must be even) */
+ opus_int stride /* I Operate on interleaved signal if > 1 */
+);
+
+/* Variable order MA prediction error filter. */
+void silk_LPC_analysis_filter(
+ opus_int16 *out, /* O Output signal */
+ const opus_int16 *in, /* I Input signal */
+ const opus_int16 *B, /* I MA prediction coefficients, Q12 [order] */
+ const opus_int32 len, /* I Signal length */
+ const opus_int32 d /* I Filter order */
+);
+
+/* Chirp (bandwidth expand) LP AR filter */
+void silk_bwexpander(
+ opus_int16 *ar, /* I/O AR filter to be expanded (without leading 1) */
+ const opus_int d, /* I Length of ar */
+ opus_int32 chirp_Q16 /* I Chirp factor (typically in the range 0 to 1) */
+);
+
+/* Chirp (bandwidth expand) LP AR filter */
+void silk_bwexpander_32(
+ opus_int32 *ar, /* I/O AR filter to be expanded (without leading 1) */
+ const opus_int d, /* I Length of ar */
+ opus_int32 chirp_Q16 /* I Chirp factor in Q16 */
+);
+
+/* Compute inverse of LPC prediction gain, and */
+/* test if LPC coefficients are stable (all poles within unit circle) */
+opus_int32 silk_LPC_inverse_pred_gain( /* O Returns inverse prediction gain in energy domain, Q30 */
+ const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */
+ const opus_int order /* I Prediction order */
+);
+
+/* For input in Q24 domain */
+opus_int32 silk_LPC_inverse_pred_gain_Q24( /* O Returns inverse prediction gain in energy domain, Q30 */
+ const opus_int32 *A_Q24, /* I Prediction coefficients [order] */
+ const opus_int order /* I Prediction order */
+);
+
+/* Split signal in two decimated bands using first-order allpass filters */
+void silk_ana_filt_bank_1(
+ const opus_int16 *in, /* I Input signal [N] */
+ opus_int32 *S, /* I/O State vector [2] */
+ opus_int16 *outL, /* O Low band [N/2] */
+ opus_int16 *outH, /* O High band [N/2] */
+ const opus_int32 N /* I Number of input samples */
+);
+
+/********************************************************************/
+/* SCALAR FUNCTIONS */
+/********************************************************************/
+
+/* Approximation of 128 * log2() (exact inverse of approx 2^() below) */
+/* Convert input to a log scale */
+opus_int32 silk_lin2log(
+ const opus_int32 inLin /* I input in linear scale */
+);
+
+/* Approximation of a sigmoid function */
+opus_int silk_sigm_Q15(
+ opus_int in_Q5 /* I */
+);
+
+/* Approximation of 2^() (exact inverse of approx log2() above) */
+/* Convert input to a linear scale */
+opus_int32 silk_log2lin(
+ const opus_int32 inLog_Q7 /* I input on log scale */
+);
+
+/* Compute number of bits to right shift the sum of squares of a vector */
+/* of int16s to make it fit in an int32 */
+void silk_sum_sqr_shift(
+ opus_int32 *energy, /* O Energy of x, after shifting to the right */
+ opus_int *shift, /* O Number of bits right shift applied to energy */
+ const opus_int16 *x, /* I Input vector */
+ opus_int len /* I Length of input vector */
+);
+
+/* Calculates the reflection coefficients from the correlation sequence */
+/* Faster than schur64(), but much less accurate. */
+/* uses SMLAWB(), requiring armv5E and higher. */
+opus_int32 silk_schur( /* O Returns residual energy */
+ opus_int16 *rc_Q15, /* O reflection coefficients [order] Q15 */
+ const opus_int32 *c, /* I correlations [order+1] */
+ const opus_int32 order /* I prediction order */
+);
+
+/* Calculates the reflection coefficients from the correlation sequence */
+/* Slower than schur(), but more accurate. */
+/* Uses SMULL(), available on armv4 */
+opus_int32 silk_schur64( /* O returns residual energy */
+ opus_int32 rc_Q16[], /* O Reflection coefficients [order] Q16 */
+ const opus_int32 c[], /* I Correlations [order+1] */
+ opus_int32 order /* I Prediction order */
+);
+
+/* Step up function, converts reflection coefficients to prediction coefficients */
+void silk_k2a(
+ opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */
+ const opus_int16 *rc_Q15, /* I Reflection coefficients [order] Q15 */
+ const opus_int32 order /* I Prediction order */
+);
+
+/* Step up function, converts reflection coefficients to prediction coefficients */
+void silk_k2a_Q16(
+ opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */
+ const opus_int32 *rc_Q16, /* I Reflection coefficients [order] Q16 */
+ const opus_int32 order /* I Prediction order */
+);
+
+/* Apply sine window to signal vector. */
+/* Window types: */
+/* 1 -> sine window from 0 to pi/2 */
+/* 2 -> sine window from pi/2 to pi */
+/* every other sample of window is linearly interpolated, for speed */
+void silk_apply_sine_window(
+ opus_int16 px_win[], /* O Pointer to windowed signal */
+ const opus_int16 px[], /* I Pointer to input signal */
+ const opus_int win_type, /* I Selects a window type */
+ const opus_int length /* I Window length, multiple of 4 */
+);
+
+/* Compute autocorrelation */
+void silk_autocorr(
+ opus_int32 *results, /* O Result (length correlationCount) */
+ opus_int *scale, /* O Scaling of the correlation vector */
+ const opus_int16 *inputData, /* I Input data to correlate */
+ const opus_int inputDataSize, /* I Length of input */
+ const opus_int correlationCount, /* I Number of correlation taps to compute */
+ int arch /* I Run-time architecture */
+);
+
+void silk_decode_pitch(
+ opus_int16 lagIndex, /* I */
+ opus_int8 contourIndex, /* O */
+ opus_int pitch_lags[], /* O 4 pitch values */
+ const opus_int Fs_kHz, /* I sampling frequency (kHz) */
+ const opus_int nb_subfr /* I number of sub frames */
+);
+
+opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 voiced, 1 unvoiced */
+ const opus_int16 *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */
+ opus_int *pitch_out, /* O 4 pitch lag values */
+ opus_int16 *lagIndex, /* O Lag Index */
+ opus_int8 *contourIndex, /* O Pitch contour Index */
+ opus_int *LTPCorr_Q15, /* I/O Normalized correlation; input: value from previous frame */
+ opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */
+ const opus_int32 search_thres1_Q16, /* I First stage threshold for lag candidates 0 - 1 */
+ const opus_int search_thres2_Q13, /* I Final threshold for lag candidates 0 - 1 */
+ const opus_int Fs_kHz, /* I Sample frequency (kHz) */
+ const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */
+ const opus_int nb_subfr, /* I number of 5 ms subframes */
+ int arch /* I Run-time architecture */
+);
+
+/* Compute Normalized Line Spectral Frequencies (NLSFs) from whitening filter coefficients */
+/* If not all roots are found, the a_Q16 coefficients are bandwidth expanded until convergence. */
+void silk_A2NLSF(
+ opus_int16 *NLSF, /* O Normalized Line Spectral Frequencies in Q15 (0..2^15-1) [d] */
+ opus_int32 *a_Q16, /* I/O Monic whitening filter coefficients in Q16 [d] */
+ const opus_int d /* I Filter order (must be even) */
+);
+
+/* compute whitening filter coefficients from normalized line spectral frequencies */
+void silk_NLSF2A(
+ opus_int16 *a_Q12, /* O monic whitening filter coefficients in Q12, [ d ] */
+ const opus_int16 *NLSF, /* I normalized line spectral frequencies in Q15, [ d ] */
+ const opus_int d /* I filter order (should be even) */
+);
+
+void silk_insertion_sort_increasing(
+ opus_int32 *a, /* I/O Unsorted / Sorted vector */
+ opus_int *idx, /* O Index vector for the sorted elements */
+ const opus_int L, /* I Vector length */
+ const opus_int K /* I Number of correctly sorted positions */
+);
+
+void silk_insertion_sort_decreasing_int16(
+ opus_int16 *a, /* I/O Unsorted / Sorted vector */
+ opus_int *idx, /* O Index vector for the sorted elements */
+ const opus_int L, /* I Vector length */
+ const opus_int K /* I Number of correctly sorted positions */
+);
+
+void silk_insertion_sort_increasing_all_values_int16(
+ opus_int16 *a, /* I/O Unsorted / Sorted vector */
+ const opus_int L /* I Vector length */
+);
+
+/* NLSF stabilizer, for a single input data vector */
+void silk_NLSF_stabilize(
+ opus_int16 *NLSF_Q15, /* I/O Unstable/stabilized normalized LSF vector in Q15 [L] */
+ const opus_int16 *NDeltaMin_Q15, /* I Min distance vector, NDeltaMin_Q15[L] must be >= 1 [L+1] */
+ const opus_int L /* I Number of NLSF parameters in the input vector */
+);
+
+/* Laroia low complexity NLSF weights */
+void silk_NLSF_VQ_weights_laroia(
+ opus_int16 *pNLSFW_Q_OUT, /* O Pointer to input vector weights [D] */
+ const opus_int16 *pNLSF_Q15, /* I Pointer to input vector [D] */
+ const opus_int D /* I Input vector dimension (even) */
+);
+
+/* Compute reflection coefficients from input signal */
+void silk_burg_modified(
+ opus_int32 *res_nrg, /* O Residual energy */
+ opus_int *res_nrg_Q, /* O Residual energy Q value */
+ opus_int32 A_Q16[], /* O Prediction coefficients (length order) */
+ const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */
+ const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */
+ const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */
+ const opus_int nb_subfr, /* I Number of subframes stacked in x */
+ const opus_int D, /* I Order */
+ int arch /* I Run-time architecture */
+);
+
+/* Copy and multiply a vector by a constant */
+void silk_scale_copy_vector16(
+ opus_int16 *data_out,
+ const opus_int16 *data_in,
+ opus_int32 gain_Q16, /* I Gain in Q16 */
+ const opus_int dataSize /* I Length */
+);
+
+/* Some for the LTP related function requires Q26 to work.*/
+void silk_scale_vector32_Q26_lshift_18(
+ opus_int32 *data1, /* I/O Q0/Q18 */
+ opus_int32 gain_Q26, /* I Q26 */
+ opus_int dataSize /* I length */
+);
+
+/********************************************************************/
+/* INLINE ARM MATH */
+/********************************************************************/
+
+/* return sum( inVec1[i] * inVec2[i] ) */
+opus_int32 silk_inner_prod_aligned(
+ const opus_int16 *const inVec1, /* I input vector 1 */
+ const opus_int16 *const inVec2, /* I input vector 2 */
+ const opus_int len /* I vector lengths */
+);
+
+opus_int32 silk_inner_prod_aligned_scale(
+ const opus_int16 *const inVec1, /* I input vector 1 */
+ const opus_int16 *const inVec2, /* I input vector 2 */
+ const opus_int scale, /* I number of bits to shift */
+ const opus_int len /* I vector lengths */
+);
+
+opus_int64 silk_inner_prod16_aligned_64(
+ const opus_int16 *inVec1, /* I input vector 1 */
+ const opus_int16 *inVec2, /* I input vector 2 */
+ const opus_int len /* I vector lengths */
+);
+
+/********************************************************************/
+/* MACROS */
+/********************************************************************/
+
+/* Rotate a32 right by 'rot' bits. Negative rot values result in rotating
+ left. Output is 32bit int.
+ Note: contemporary compilers recognize the C expression below and
+ compile it into a 'ror' instruction if available. No need for OPUS_INLINE ASM! */
+static OPUS_INLINE opus_int32 silk_ROR32( opus_int32 a32, opus_int rot )
+{
+ opus_uint32 x = (opus_uint32) a32;
+ opus_uint32 r = (opus_uint32) rot;
+ opus_uint32 m = (opus_uint32) -rot;
+ if( rot == 0 ) {
+ return a32;
+ } else if( rot < 0 ) {
+ return (opus_int32) ((x << m) | (x >> (32 - m)));
+ } else {
+ return (opus_int32) ((x << (32 - r)) | (x >> r));
+ }
+}
+
+/* Allocate opus_int16 aligned to 4-byte memory address */
+#if EMBEDDED_ARM
+#define silk_DWORD_ALIGN __attribute__((aligned(4)))
+#else
+#define silk_DWORD_ALIGN
+#endif
+
+/* Useful Macros that can be adjusted to other platforms */
+#define silk_memcpy(dest, src, size) memcpy((dest), (src), (size))
+#define silk_memset(dest, src, size) memset((dest), (src), (size))
+#define silk_memmove(dest, src, size) memmove((dest), (src), (size))
+
+/* Fixed point macros */
+
+/* (a32 * b32) output have to be 32bit int */
+#define silk_MUL(a32, b32) ((a32) * (b32))
+
+/* (a32 * b32) output have to be 32bit uint */
+#define silk_MUL_uint(a32, b32) silk_MUL(a32, b32)
+
+/* a32 + (b32 * c32) output have to be 32bit int */
+#define silk_MLA(a32, b32, c32) silk_ADD32((a32),((b32) * (c32)))
+
+/* a32 + (b32 * c32) output have to be 32bit uint */
+#define silk_MLA_uint(a32, b32, c32) silk_MLA(a32, b32, c32)
+
+/* ((a32 >> 16) * (b32 >> 16)) output have to be 32bit int */
+#define silk_SMULTT(a32, b32) (((a32) >> 16) * ((b32) >> 16))
+
+/* a32 + ((a32 >> 16) * (b32 >> 16)) output have to be 32bit int */
+#define silk_SMLATT(a32, b32, c32) silk_ADD32((a32),((b32) >> 16) * ((c32) >> 16))
+
+#define silk_SMLALBB(a64, b16, c16) silk_ADD64((a64),(opus_int64)((opus_int32)(b16) * (opus_int32)(c16)))
+
+/* (a32 * b32) */
+#define silk_SMULL(a32, b32) ((opus_int64)(a32) * /*(opus_int64)*/(b32))
+
+/* Adds two signed 32-bit values in a way that can overflow, while not relying on undefined behaviour
+ (just standard two's complement implementation-specific behaviour) */
+#define silk_ADD32_ovflw(a, b) ((opus_int32)((opus_uint32)(a) + (opus_uint32)(b)))
+/* Subtractss two signed 32-bit values in a way that can overflow, while not relying on undefined behaviour
+ (just standard two's complement implementation-specific behaviour) */
+#define silk_SUB32_ovflw(a, b) ((opus_int32)((opus_uint32)(a) - (opus_uint32)(b)))
+
+/* Multiply-accumulate macros that allow overflow in the addition (ie, no asserts in debug mode) */
+#define silk_MLA_ovflw(a32, b32, c32) silk_ADD32_ovflw((a32), (opus_uint32)(b32) * (opus_uint32)(c32))
+#define silk_SMLABB_ovflw(a32, b32, c32) (silk_ADD32_ovflw((a32) , ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32))))
+
+#define silk_DIV32_16(a32, b16) ((opus_int32)((a32) / (b16)))
+#define silk_DIV32(a32, b32) ((opus_int32)((a32) / (b32)))
+
+/* These macros enables checking for overflow in silk_API_Debug.h*/
+#define silk_ADD16(a, b) ((a) + (b))
+#define silk_ADD32(a, b) ((a) + (b))
+#define silk_ADD64(a, b) ((a) + (b))
+
+#define silk_SUB16(a, b) ((a) - (b))
+#define silk_SUB32(a, b) ((a) - (b))
+#define silk_SUB64(a, b) ((a) - (b))
+
+#define silk_SAT8(a) ((a) > silk_int8_MAX ? silk_int8_MAX : \
+ ((a) < silk_int8_MIN ? silk_int8_MIN : (a)))
+#define silk_SAT16(a) ((a) > silk_int16_MAX ? silk_int16_MAX : \
+ ((a) < silk_int16_MIN ? silk_int16_MIN : (a)))
+#define silk_SAT32(a) ((a) > silk_int32_MAX ? silk_int32_MAX : \
+ ((a) < silk_int32_MIN ? silk_int32_MIN : (a)))
+
+#define silk_CHECK_FIT8(a) (a)
+#define silk_CHECK_FIT16(a) (a)
+#define silk_CHECK_FIT32(a) (a)
+
+#define silk_ADD_SAT16(a, b) (opus_int16)silk_SAT16( silk_ADD32( (opus_int32)(a), (b) ) )
+#define silk_ADD_SAT64(a, b) ((((a) + (b)) & 0x8000000000000000LL) == 0 ? \
+ ((((a) & (b)) & 0x8000000000000000LL) != 0 ? silk_int64_MIN : (a)+(b)) : \
+ ((((a) | (b)) & 0x8000000000000000LL) == 0 ? silk_int64_MAX : (a)+(b)) )
+
+#define silk_SUB_SAT16(a, b) (opus_int16)silk_SAT16( silk_SUB32( (opus_int32)(a), (b) ) )
+#define silk_SUB_SAT64(a, b) ((((a)-(b)) & 0x8000000000000000LL) == 0 ? \
+ (( (a) & ((b)^0x8000000000000000LL) & 0x8000000000000000LL) ? silk_int64_MIN : (a)-(b)) : \
+ ((((a)^0x8000000000000000LL) & (b) & 0x8000000000000000LL) ? silk_int64_MAX : (a)-(b)) )
+
+/* Saturation for positive input values */
+#define silk_POS_SAT32(a) ((a) > silk_int32_MAX ? silk_int32_MAX : (a))
+
+/* Add with saturation for positive input values */
+#define silk_ADD_POS_SAT8(a, b) ((((a)+(b)) & 0x80) ? silk_int8_MAX : ((a)+(b)))
+#define silk_ADD_POS_SAT16(a, b) ((((a)+(b)) & 0x8000) ? silk_int16_MAX : ((a)+(b)))
+#define silk_ADD_POS_SAT32(a, b) ((((a)+(b)) & 0x80000000) ? silk_int32_MAX : ((a)+(b)))
+#define silk_ADD_POS_SAT64(a, b) ((((a)+(b)) & 0x8000000000000000LL) ? silk_int64_MAX : ((a)+(b)))
+
+#define silk_LSHIFT8(a, shift) ((opus_int8)((opus_uint8)(a)<<(shift))) /* shift >= 0, shift < 8 */
+#define silk_LSHIFT16(a, shift) ((opus_int16)((opus_uint16)(a)<<(shift))) /* shift >= 0, shift < 16 */
+#define silk_LSHIFT32(a, shift) ((opus_int32)((opus_uint32)(a)<<(shift))) /* shift >= 0, shift < 32 */
+#define silk_LSHIFT64(a, shift) ((opus_int64)((opus_uint64)(a)<<(shift))) /* shift >= 0, shift < 64 */
+#define silk_LSHIFT(a, shift) silk_LSHIFT32(a, shift) /* shift >= 0, shift < 32 */
+
+#define silk_RSHIFT8(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 8 */
+#define silk_RSHIFT16(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 16 */
+#define silk_RSHIFT32(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 32 */
+#define silk_RSHIFT64(a, shift) ((a)>>(shift)) /* shift >= 0, shift < 64 */
+#define silk_RSHIFT(a, shift) silk_RSHIFT32(a, shift) /* shift >= 0, shift < 32 */
+
+/* saturates before shifting */
+#define silk_LSHIFT_SAT32(a, shift) (silk_LSHIFT32( silk_LIMIT( (a), silk_RSHIFT32( silk_int32_MIN, (shift) ), \
+ silk_RSHIFT32( silk_int32_MAX, (shift) ) ), (shift) ))
+
+#define silk_LSHIFT_ovflw(a, shift) ((opus_int32)((opus_uint32)(a) << (shift))) /* shift >= 0, allowed to overflow */
+#define silk_LSHIFT_uint(a, shift) ((a) << (shift)) /* shift >= 0 */
+#define silk_RSHIFT_uint(a, shift) ((a) >> (shift)) /* shift >= 0 */
+
+#define silk_ADD_LSHIFT(a, b, shift) ((a) + silk_LSHIFT((b), (shift))) /* shift >= 0 */
+#define silk_ADD_LSHIFT32(a, b, shift) silk_ADD32((a), silk_LSHIFT32((b), (shift))) /* shift >= 0 */
+#define silk_ADD_LSHIFT_uint(a, b, shift) ((a) + silk_LSHIFT_uint((b), (shift))) /* shift >= 0 */
+#define silk_ADD_RSHIFT(a, b, shift) ((a) + silk_RSHIFT((b), (shift))) /* shift >= 0 */
+#define silk_ADD_RSHIFT32(a, b, shift) silk_ADD32((a), silk_RSHIFT32((b), (shift))) /* shift >= 0 */
+#define silk_ADD_RSHIFT_uint(a, b, shift) ((a) + silk_RSHIFT_uint((b), (shift))) /* shift >= 0 */
+#define silk_SUB_LSHIFT32(a, b, shift) silk_SUB32((a), silk_LSHIFT32((b), (shift))) /* shift >= 0 */
+#define silk_SUB_RSHIFT32(a, b, shift) silk_SUB32((a), silk_RSHIFT32((b), (shift))) /* shift >= 0 */
+
+/* Requires that shift > 0 */
+#define silk_RSHIFT_ROUND(a, shift) ((shift) == 1 ? ((a) >> 1) + ((a) & 1) : (((a) >> ((shift) - 1)) + 1) >> 1)
+#define silk_RSHIFT_ROUND64(a, shift) ((shift) == 1 ? ((a) >> 1) + ((a) & 1) : (((a) >> ((shift) - 1)) + 1) >> 1)
+
+/* Number of rightshift required to fit the multiplication */
+#define silk_NSHIFT_MUL_32_32(a, b) ( -(31- (32-silk_CLZ32(silk_abs(a)) + (32-silk_CLZ32(silk_abs(b))))) )
+#define silk_NSHIFT_MUL_16_16(a, b) ( -(15- (16-silk_CLZ16(silk_abs(a)) + (16-silk_CLZ16(silk_abs(b))))) )
+
+
+#define silk_min(a, b) (((a) < (b)) ? (a) : (b))
+#define silk_max(a, b) (((a) > (b)) ? (a) : (b))
+
+/* Macro to convert floating-point constants to fixed-point */
+#define SILK_FIX_CONST( C, Q ) ((opus_int32)((C) * ((opus_int64)1 << (Q)) + 0.5))
+
+/* silk_min() versions with typecast in the function call */
+static OPUS_INLINE opus_int silk_min_int(opus_int a, opus_int b)
+{
+ return (((a) < (b)) ? (a) : (b));
+}
+static OPUS_INLINE opus_int16 silk_min_16(opus_int16 a, opus_int16 b)
+{
+ return (((a) < (b)) ? (a) : (b));
+}
+static OPUS_INLINE opus_int32 silk_min_32(opus_int32 a, opus_int32 b)
+{
+ return (((a) < (b)) ? (a) : (b));
+}
+static OPUS_INLINE opus_int64 silk_min_64(opus_int64 a, opus_int64 b)
+{
+ return (((a) < (b)) ? (a) : (b));
+}
+
+/* silk_min() versions with typecast in the function call */
+static OPUS_INLINE opus_int silk_max_int(opus_int a, opus_int b)
+{
+ return (((a) > (b)) ? (a) : (b));
+}
+static OPUS_INLINE opus_int16 silk_max_16(opus_int16 a, opus_int16 b)
+{
+ return (((a) > (b)) ? (a) : (b));
+}
+static OPUS_INLINE opus_int32 silk_max_32(opus_int32 a, opus_int32 b)
+{
+ return (((a) > (b)) ? (a) : (b));
+}
+static OPUS_INLINE opus_int64 silk_max_64(opus_int64 a, opus_int64 b)
+{
+ return (((a) > (b)) ? (a) : (b));
+}
+
+#define silk_LIMIT( a, limit1, limit2) ((limit1) > (limit2) ? ((a) > (limit1) ? (limit1) : ((a) < (limit2) ? (limit2) : (a))) \
+ : ((a) > (limit2) ? (limit2) : ((a) < (limit1) ? (limit1) : (a))))
+
+#define silk_LIMIT_int silk_LIMIT
+#define silk_LIMIT_16 silk_LIMIT
+#define silk_LIMIT_32 silk_LIMIT
+
+#define silk_abs(a) (((a) > 0) ? (a) : -(a)) /* Be careful, silk_abs returns wrong when input equals to silk_intXX_MIN */
+#define silk_abs_int(a) (((a) ^ ((a) >> (8 * sizeof(a) - 1))) - ((a) >> (8 * sizeof(a) - 1)))
+#define silk_abs_int32(a) (((a) ^ ((a) >> 31)) - ((a) >> 31))
+#define silk_abs_int64(a) (((a) > 0) ? (a) : -(a))
+
+#define silk_sign(a) ((a) > 0 ? 1 : ( (a) < 0 ? -1 : 0 ))
+
+/* PSEUDO-RANDOM GENERATOR */
+/* Make sure to store the result as the seed for the next call (also in between */
+/* frames), otherwise result won't be random at all. When only using some of the */
+/* bits, take the most significant bits by right-shifting. */
+#define silk_RAND(seed) (silk_MLA_ovflw(907633515, (seed), 196314165))
+
+/* Add some multiplication functions that can be easily mapped to ARM. */
+
+/* silk_SMMUL: Signed top word multiply.
+ ARMv6 2 instruction cycles.
+ ARMv3M+ 3 instruction cycles. use SMULL and ignore LSB registers.(except xM)*/
+/*#define silk_SMMUL(a32, b32) (opus_int32)silk_RSHIFT(silk_SMLAL(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16)), 16)*/
+/* the following seems faster on x86 */
+#define silk_SMMUL(a32, b32) (opus_int32)silk_RSHIFT64(silk_SMULL((a32), (b32)), 32)
+
+#include "opus/silk/Inlines.h"
+#include "opus/silk/MacroCount.h"
+#include "opus/silk/MacroDebug.h"
+
+#ifdef OPUS_ARM_INLINE_ASM
+#include "arm/SigProc_FIX_armv4.h"
+#endif
+
+#ifdef OPUS_ARM_INLINE_EDSP
+#include "arm/SigProc_FIX_armv5e.h"
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SILK_SIGPROC_FIX_H */
diff --git a/drivers/opus/silk/VAD.c b/drivers/opus/silk/VAD.c
new file mode 100644
index 0000000000..a789a13d32
--- /dev/null
+++ b/drivers/opus/silk/VAD.c
@@ -0,0 +1,357 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+#include "opus/celt/stack_alloc.h"
+
+/* Silk VAD noise level estimation */
+static OPUS_INLINE void silk_VAD_GetNoiseLevels(
+ const opus_int32 pX[ VAD_N_BANDS ], /* I subband energies */
+ silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */
+);
+
+/**********************************/
+/* Initialization of the Silk VAD */
+/**********************************/
+opus_int silk_VAD_Init( /* O Return value, 0 if success */
+ silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */
+)
+{
+ opus_int b, ret = 0;
+
+ /* reset state memory */
+ silk_memset( psSilk_VAD, 0, sizeof( silk_VAD_state ) );
+
+ /* init noise levels */
+ /* Initialize array with approx pink noise levels (psd proportional to inverse of frequency) */
+ for( b = 0; b < VAD_N_BANDS; b++ ) {
+ psSilk_VAD->NoiseLevelBias[ b ] = silk_max_32( silk_DIV32_16( VAD_NOISE_LEVELS_BIAS, b + 1 ), 1 );
+ }
+
+ /* Initialize state */
+ for( b = 0; b < VAD_N_BANDS; b++ ) {
+ psSilk_VAD->NL[ b ] = silk_MUL( 100, psSilk_VAD->NoiseLevelBias[ b ] );
+ psSilk_VAD->inv_NL[ b ] = silk_DIV32( silk_int32_MAX, psSilk_VAD->NL[ b ] );
+ }
+ psSilk_VAD->counter = 15;
+
+ /* init smoothed energy-to-noise ratio*/
+ for( b = 0; b < VAD_N_BANDS; b++ ) {
+ psSilk_VAD->NrgRatioSmth_Q8[ b ] = 100 * 256; /* 100 * 256 --> 20 dB SNR */
+ }
+
+ return( ret );
+}
+
+/* Weighting factors for tilt measure */
+static const opus_int32 tiltWeights[ VAD_N_BANDS ] = { 30000, 6000, -12000, -12000 };
+
+/***************************************/
+/* Get the speech activity level in Q8 */
+/***************************************/
+opus_int silk_VAD_GetSA_Q8( /* O Return value, 0 if success */
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ const opus_int16 pIn[] /* I PCM input */
+)
+{
+ opus_int SA_Q15, pSNR_dB_Q7, input_tilt;
+ opus_int decimated_framelength1, decimated_framelength2;
+ opus_int decimated_framelength;
+ opus_int dec_subframe_length, dec_subframe_offset, SNR_Q7, i, b, s;
+ opus_int32 sumSquared, smooth_coef_Q16;
+ opus_int16 HPstateTmp;
+ VARDECL( opus_int16, X );
+ opus_int32 Xnrg[ VAD_N_BANDS ];
+ opus_int32 NrgToNoiseRatio_Q8[ VAD_N_BANDS ];
+ opus_int32 speech_nrg, x_tmp;
+ opus_int X_offset[ VAD_N_BANDS ];
+ opus_int ret = 0;
+ silk_VAD_state *psSilk_VAD = &psEncC->sVAD;
+ SAVE_STACK;
+
+ /* Safety checks */
+ silk_assert( VAD_N_BANDS == 4 );
+ silk_assert( MAX_FRAME_LENGTH >= psEncC->frame_length );
+ silk_assert( psEncC->frame_length <= 512 );
+ silk_assert( psEncC->frame_length == 8 * silk_RSHIFT( psEncC->frame_length, 3 ) );
+
+ /***********************/
+ /* Filter and Decimate */
+ /***********************/
+ decimated_framelength1 = silk_RSHIFT( psEncC->frame_length, 1 );
+ decimated_framelength2 = silk_RSHIFT( psEncC->frame_length, 2 );
+ decimated_framelength = silk_RSHIFT( psEncC->frame_length, 3 );
+ /* Decimate into 4 bands:
+ 0 L 3L L 3L 5L
+ - -- - -- --
+ 8 8 2 4 4
+
+ [0-1 kHz| temp. |1-2 kHz| 2-4 kHz | 4-8 kHz |
+
+ They're arranged to allow the minimal ( frame_length / 4 ) extra
+ scratch space during the downsampling process */
+ X_offset[ 0 ] = 0;
+ X_offset[ 1 ] = decimated_framelength + decimated_framelength2;
+ X_offset[ 2 ] = X_offset[ 1 ] + decimated_framelength;
+ X_offset[ 3 ] = X_offset[ 2 ] + decimated_framelength2;
+ ALLOC( X, X_offset[ 3 ] + decimated_framelength1, opus_int16 );
+
+ /* 0-8 kHz to 0-4 kHz and 4-8 kHz */
+ silk_ana_filt_bank_1( pIn, &psSilk_VAD->AnaState[ 0 ],
+ X, &X[ X_offset[ 3 ] ], psEncC->frame_length );
+
+ /* 0-4 kHz to 0-2 kHz and 2-4 kHz */
+ silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState1[ 0 ],
+ X, &X[ X_offset[ 2 ] ], decimated_framelength1 );
+
+ /* 0-2 kHz to 0-1 kHz and 1-2 kHz */
+ silk_ana_filt_bank_1( X, &psSilk_VAD->AnaState2[ 0 ],
+ X, &X[ X_offset[ 1 ] ], decimated_framelength2 );
+
+ /*********************************************/
+ /* HP filter on lowest band (differentiator) */
+ /*********************************************/
+ X[ decimated_framelength - 1 ] = silk_RSHIFT( X[ decimated_framelength - 1 ], 1 );
+ HPstateTmp = X[ decimated_framelength - 1 ];
+ for( i = decimated_framelength - 1; i > 0; i-- ) {
+ X[ i - 1 ] = silk_RSHIFT( X[ i - 1 ], 1 );
+ X[ i ] -= X[ i - 1 ];
+ }
+ X[ 0 ] -= psSilk_VAD->HPstate;
+ psSilk_VAD->HPstate = HPstateTmp;
+
+ /*************************************/
+ /* Calculate the energy in each band */
+ /*************************************/
+ for( b = 0; b < VAD_N_BANDS; b++ ) {
+ /* Find the decimated framelength in the non-uniformly divided bands */
+ decimated_framelength = silk_RSHIFT( psEncC->frame_length, silk_min_int( VAD_N_BANDS - b, VAD_N_BANDS - 1 ) );
+
+ /* Split length into subframe lengths */
+ dec_subframe_length = silk_RSHIFT( decimated_framelength, VAD_INTERNAL_SUBFRAMES_LOG2 );
+ dec_subframe_offset = 0;
+
+ /* Compute energy per sub-frame */
+ /* initialize with summed energy of last subframe */
+ Xnrg[ b ] = psSilk_VAD->XnrgSubfr[ b ];
+ for( s = 0; s < VAD_INTERNAL_SUBFRAMES; s++ ) {
+ sumSquared = 0;
+ for( i = 0; i < dec_subframe_length; i++ ) {
+ /* The energy will be less than dec_subframe_length * ( silk_int16_MIN / 8 ) ^ 2. */
+ /* Therefore we can accumulate with no risk of overflow (unless dec_subframe_length > 128) */
+ x_tmp = silk_RSHIFT(
+ X[ X_offset[ b ] + i + dec_subframe_offset ], 3 );
+ sumSquared = silk_SMLABB( sumSquared, x_tmp, x_tmp );
+
+ /* Safety check */
+ silk_assert( sumSquared >= 0 );
+ }
+
+ /* Add/saturate summed energy of current subframe */
+ if( s < VAD_INTERNAL_SUBFRAMES - 1 ) {
+ Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], sumSquared );
+ } else {
+ /* Look-ahead subframe */
+ Xnrg[ b ] = silk_ADD_POS_SAT32( Xnrg[ b ], silk_RSHIFT( sumSquared, 1 ) );
+ }
+
+ dec_subframe_offset += dec_subframe_length;
+ }
+ psSilk_VAD->XnrgSubfr[ b ] = sumSquared;
+ }
+
+ /********************/
+ /* Noise estimation */
+ /********************/
+ silk_VAD_GetNoiseLevels( &Xnrg[ 0 ], psSilk_VAD );
+
+ /***********************************************/
+ /* Signal-plus-noise to noise ratio estimation */
+ /***********************************************/
+ sumSquared = 0;
+ input_tilt = 0;
+ for( b = 0; b < VAD_N_BANDS; b++ ) {
+ speech_nrg = Xnrg[ b ] - psSilk_VAD->NL[ b ];
+ if( speech_nrg > 0 ) {
+ /* Divide, with sufficient resolution */
+ if( ( Xnrg[ b ] & 0xFF800000 ) == 0 ) {
+ NrgToNoiseRatio_Q8[ b ] = silk_DIV32( silk_LSHIFT( Xnrg[ b ], 8 ), psSilk_VAD->NL[ b ] + 1 );
+ } else {
+ NrgToNoiseRatio_Q8[ b ] = silk_DIV32( Xnrg[ b ], silk_RSHIFT( psSilk_VAD->NL[ b ], 8 ) + 1 );
+ }
+
+ /* Convert to log domain */
+ SNR_Q7 = silk_lin2log( NrgToNoiseRatio_Q8[ b ] ) - 8 * 128;
+
+ /* Sum-of-squares */
+ sumSquared = silk_SMLABB( sumSquared, SNR_Q7, SNR_Q7 ); /* Q14 */
+
+ /* Tilt measure */
+ if( speech_nrg < ( (opus_int32)1 << 20 ) ) {
+ /* Scale down SNR value for small subband speech energies */
+ SNR_Q7 = silk_SMULWB( silk_LSHIFT( silk_SQRT_APPROX( speech_nrg ), 6 ), SNR_Q7 );
+ }
+ input_tilt = silk_SMLAWB( input_tilt, tiltWeights[ b ], SNR_Q7 );
+ } else {
+ NrgToNoiseRatio_Q8[ b ] = 256;
+ }
+ }
+
+ /* Mean-of-squares */
+ sumSquared = silk_DIV32_16( sumSquared, VAD_N_BANDS ); /* Q14 */
+
+ /* Root-mean-square approximation, scale to dBs, and write to output pointer */
+ pSNR_dB_Q7 = (opus_int16)( 3 * silk_SQRT_APPROX( sumSquared ) ); /* Q7 */
+
+ /*********************************/
+ /* Speech Probability Estimation */
+ /*********************************/
+ SA_Q15 = silk_sigm_Q15( silk_SMULWB( VAD_SNR_FACTOR_Q16, pSNR_dB_Q7 ) - VAD_NEGATIVE_OFFSET_Q5 );
+
+ /**************************/
+ /* Frequency Tilt Measure */
+ /**************************/
+ psEncC->input_tilt_Q15 = silk_LSHIFT( silk_sigm_Q15( input_tilt ) - 16384, 1 );
+
+ /**************************************************/
+ /* Scale the sigmoid output based on power levels */
+ /**************************************************/
+ speech_nrg = 0;
+ for( b = 0; b < VAD_N_BANDS; b++ ) {
+ /* Accumulate signal-without-noise energies, higher frequency bands have more weight */
+ speech_nrg += ( b + 1 ) * silk_RSHIFT( Xnrg[ b ] - psSilk_VAD->NL[ b ], 4 );
+ }
+
+ /* Power scaling */
+ if( speech_nrg <= 0 ) {
+ SA_Q15 = silk_RSHIFT( SA_Q15, 1 );
+ } else if( speech_nrg < 32768 ) {
+ if( psEncC->frame_length == 10 * psEncC->fs_kHz ) {
+ speech_nrg = silk_LSHIFT_SAT32( speech_nrg, 16 );
+ } else {
+ speech_nrg = silk_LSHIFT_SAT32( speech_nrg, 15 );
+ }
+
+ /* square-root */
+ speech_nrg = silk_SQRT_APPROX( speech_nrg );
+ SA_Q15 = silk_SMULWB( 32768 + speech_nrg, SA_Q15 );
+ }
+
+ /* Copy the resulting speech activity in Q8 */
+ psEncC->speech_activity_Q8 = silk_min_int( silk_RSHIFT( SA_Q15, 7 ), silk_uint8_MAX );
+
+ /***********************************/
+ /* Energy Level and SNR estimation */
+ /***********************************/
+ /* Smoothing coefficient */
+ smooth_coef_Q16 = silk_SMULWB( VAD_SNR_SMOOTH_COEF_Q18, silk_SMULWB( (opus_int32)SA_Q15, SA_Q15 ) );
+
+ if( psEncC->frame_length == 10 * psEncC->fs_kHz ) {
+ smooth_coef_Q16 >>= 1;
+ }
+
+ for( b = 0; b < VAD_N_BANDS; b++ ) {
+ /* compute smoothed energy-to-noise ratio per band */
+ psSilk_VAD->NrgRatioSmth_Q8[ b ] = silk_SMLAWB( psSilk_VAD->NrgRatioSmth_Q8[ b ],
+ NrgToNoiseRatio_Q8[ b ] - psSilk_VAD->NrgRatioSmth_Q8[ b ], smooth_coef_Q16 );
+
+ /* signal to noise ratio in dB per band */
+ SNR_Q7 = 3 * ( silk_lin2log( psSilk_VAD->NrgRatioSmth_Q8[b] ) - 8 * 128 );
+ /* quality = sigmoid( 0.25 * ( SNR_dB - 16 ) ); */
+ psEncC->input_quality_bands_Q15[ b ] = silk_sigm_Q15( silk_RSHIFT( SNR_Q7 - 16 * 128, 4 ) );
+ }
+
+ RESTORE_STACK;
+ return( ret );
+}
+
+/**************************/
+/* Noise level estimation */
+/**************************/
+static OPUS_INLINE void silk_VAD_GetNoiseLevels(
+ const opus_int32 pX[ VAD_N_BANDS ], /* I subband energies */
+ silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */
+)
+{
+ opus_int k;
+ opus_int32 nl, nrg, inv_nrg;
+ opus_int coef, min_coef;
+
+ /* Initially faster smoothing */
+ if( psSilk_VAD->counter < 1000 ) { /* 1000 = 20 sec */
+ min_coef = silk_DIV32_16( silk_int16_MAX, silk_RSHIFT( psSilk_VAD->counter, 4 ) + 1 );
+ } else {
+ min_coef = 0;
+ }
+
+ for( k = 0; k < VAD_N_BANDS; k++ ) {
+ /* Get old noise level estimate for current band */
+ nl = psSilk_VAD->NL[ k ];
+ silk_assert( nl >= 0 );
+
+ /* Add bias */
+ nrg = silk_ADD_POS_SAT32( pX[ k ], psSilk_VAD->NoiseLevelBias[ k ] );
+ silk_assert( nrg > 0 );
+
+ /* Invert energies */
+ inv_nrg = silk_DIV32( silk_int32_MAX, nrg );
+ silk_assert( inv_nrg >= 0 );
+
+ /* Less update when subband energy is high */
+ if( nrg > silk_LSHIFT( nl, 3 ) ) {
+ coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 >> 3;
+ } else if( nrg < nl ) {
+ coef = VAD_NOISE_LEVEL_SMOOTH_COEF_Q16;
+ } else {
+ coef = silk_SMULWB( silk_SMULWW( inv_nrg, nl ), VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 << 1 );
+ }
+
+ /* Initially faster smoothing */
+ coef = silk_max_int( coef, min_coef );
+
+ /* Smooth inverse energies */
+ psSilk_VAD->inv_NL[ k ] = silk_SMLAWB( psSilk_VAD->inv_NL[ k ], inv_nrg - psSilk_VAD->inv_NL[ k ], coef );
+ silk_assert( psSilk_VAD->inv_NL[ k ] >= 0 );
+
+ /* Compute noise level by inverting again */
+ nl = silk_DIV32( silk_int32_MAX, psSilk_VAD->inv_NL[ k ] );
+ silk_assert( nl >= 0 );
+
+ /* Limit noise levels (guarantee 7 bits of head room) */
+ nl = silk_min( nl, 0x00FFFFFF );
+
+ /* Store as part of state */
+ psSilk_VAD->NL[ k ] = nl;
+ }
+
+ /* Increment frame counter */
+ psSilk_VAD->counter++;
+}
diff --git a/drivers/opus/silk/VQ_WMat_EC.c b/drivers/opus/silk/VQ_WMat_EC.c
new file mode 100644
index 0000000000..a35b84ef14
--- /dev/null
+++ b/drivers/opus/silk/VQ_WMat_EC.c
@@ -0,0 +1,120 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+
+/* Entropy constrained matrix-weighted VQ, hard-coded to 5-element vectors, for a single input data vector */
+void silk_VQ_WMat_EC(
+ opus_int8 *ind, /* O index of best codebook vector */
+ opus_int32 *rate_dist_Q14, /* O best weighted quant error + mu * rate */
+ opus_int *gain_Q7, /* O sum of absolute LTP coefficients */
+ const opus_int16 *in_Q14, /* I input vector to be quantized */
+ const opus_int32 *W_Q18, /* I weighting matrix */
+ const opus_int8 *cb_Q7, /* I codebook */
+ const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */
+ const opus_uint8 *cl_Q5, /* I code length for each codebook vector */
+ const opus_int mu_Q9, /* I tradeoff betw. weighted error and rate */
+ const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */
+ opus_int L /* I number of vectors in codebook */
+)
+{
+ opus_int k, gain_tmp_Q7;
+ const opus_int8 *cb_row_Q7;
+ opus_int16 diff_Q14[ 5 ];
+ opus_int32 sum1_Q14, sum2_Q16;
+
+ /* Loop over codebook */
+ *rate_dist_Q14 = silk_int32_MAX;
+ cb_row_Q7 = cb_Q7;
+ for( k = 0; k < L; k++ ) {
+ gain_tmp_Q7 = cb_gain_Q7[k];
+
+ diff_Q14[ 0 ] = in_Q14[ 0 ] - silk_LSHIFT( cb_row_Q7[ 0 ], 7 );
+ diff_Q14[ 1 ] = in_Q14[ 1 ] - silk_LSHIFT( cb_row_Q7[ 1 ], 7 );
+ diff_Q14[ 2 ] = in_Q14[ 2 ] - silk_LSHIFT( cb_row_Q7[ 2 ], 7 );
+ diff_Q14[ 3 ] = in_Q14[ 3 ] - silk_LSHIFT( cb_row_Q7[ 3 ], 7 );
+ diff_Q14[ 4 ] = in_Q14[ 4 ] - silk_LSHIFT( cb_row_Q7[ 4 ], 7 );
+
+ /* Weighted rate */
+ sum1_Q14 = silk_SMULBB( mu_Q9, cl_Q5[ k ] );
+
+ /* Penalty for too large gain */
+ sum1_Q14 = silk_ADD_LSHIFT32( sum1_Q14, silk_max( silk_SUB32( gain_tmp_Q7, max_gain_Q7 ), 0 ), 10 );
+
+ silk_assert( sum1_Q14 >= 0 );
+
+ /* first row of W_Q18 */
+ sum2_Q16 = silk_SMULWB( W_Q18[ 1 ], diff_Q14[ 1 ] );
+ sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 2 ], diff_Q14[ 2 ] );
+ sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 3 ], diff_Q14[ 3 ] );
+ sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 4 ], diff_Q14[ 4 ] );
+ sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 );
+ sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 0 ], diff_Q14[ 0 ] );
+ sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 0 ] );
+
+ /* second row of W_Q18 */
+ sum2_Q16 = silk_SMULWB( W_Q18[ 7 ], diff_Q14[ 2 ] );
+ sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 8 ], diff_Q14[ 3 ] );
+ sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 9 ], diff_Q14[ 4 ] );
+ sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 );
+ sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 6 ], diff_Q14[ 1 ] );
+ sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 1 ] );
+
+ /* third row of W_Q18 */
+ sum2_Q16 = silk_SMULWB( W_Q18[ 13 ], diff_Q14[ 3 ] );
+ sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 14 ], diff_Q14[ 4 ] );
+ sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 );
+ sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 12 ], diff_Q14[ 2 ] );
+ sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 2 ] );
+
+ /* fourth row of W_Q18 */
+ sum2_Q16 = silk_SMULWB( W_Q18[ 19 ], diff_Q14[ 4 ] );
+ sum2_Q16 = silk_LSHIFT( sum2_Q16, 1 );
+ sum2_Q16 = silk_SMLAWB( sum2_Q16, W_Q18[ 18 ], diff_Q14[ 3 ] );
+ sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 3 ] );
+
+ /* last row of W_Q18 */
+ sum2_Q16 = silk_SMULWB( W_Q18[ 24 ], diff_Q14[ 4 ] );
+ sum1_Q14 = silk_SMLAWB( sum1_Q14, sum2_Q16, diff_Q14[ 4 ] );
+
+ silk_assert( sum1_Q14 >= 0 );
+
+ /* find best */
+ if( sum1_Q14 < *rate_dist_Q14 ) {
+ *rate_dist_Q14 = sum1_Q14;
+ *ind = (opus_int8)k;
+ *gain_Q7 = gain_tmp_Q7;
+ }
+
+ /* Go to next cbk vector */
+ cb_row_Q7 += LTP_ORDER;
+ }
+}
diff --git a/drivers/opus/silk/ana_filt_bank_1.c b/drivers/opus/silk/ana_filt_bank_1.c
new file mode 100644
index 0000000000..a2fa720bd0
--- /dev/null
+++ b/drivers/opus/silk/ana_filt_bank_1.c
@@ -0,0 +1,74 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/SigProc_FIX.h"
+
+/* Coefficients for 2-band filter bank based on first-order allpass filters */
+static opus_int16 A_fb1_20 = 5394 << 1;
+static opus_int16 A_fb1_21 = -24290; /* (opus_int16)(20623 << 1) */
+
+/* Split signal into two decimated bands using first-order allpass filters */
+void silk_ana_filt_bank_1(
+ const opus_int16 *in, /* I Input signal [N] */
+ opus_int32 *S, /* I/O State vector [2] */
+ opus_int16 *outL, /* O Low band [N/2] */
+ opus_int16 *outH, /* O High band [N/2] */
+ const opus_int32 N /* I Number of input samples */
+)
+{
+ opus_int k, N2 = silk_RSHIFT( N, 1 );
+ opus_int32 in32, X, Y, out_1, out_2;
+
+ /* Internal variables and state are in Q10 format */
+ for( k = 0; k < N2; k++ ) {
+ /* Convert to Q10 */
+ in32 = silk_LSHIFT( (opus_int32)in[ 2 * k ], 10 );
+
+ /* All-pass section for even input sample */
+ Y = silk_SUB32( in32, S[ 0 ] );
+ X = silk_SMLAWB( Y, Y, A_fb1_21 );
+ out_1 = silk_ADD32( S[ 0 ], X );
+ S[ 0 ] = silk_ADD32( in32, X );
+
+ /* Convert to Q10 */
+ in32 = silk_LSHIFT( (opus_int32)in[ 2 * k + 1 ], 10 );
+
+ /* All-pass section for odd input sample, and add to output of previous section */
+ Y = silk_SUB32( in32, S[ 1 ] );
+ X = silk_SMULWB( Y, A_fb1_20 );
+ out_2 = silk_ADD32( S[ 1 ], X );
+ S[ 1 ] = silk_ADD32( in32, X );
+
+ /* Add/subtract, convert back to int16 and store to output */
+ outL[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_ADD32( out_2, out_1 ), 11 ) );
+ outH[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SUB32( out_2, out_1 ), 11 ) );
+ }
+}
diff --git a/drivers/opus/silk/arm/SigProc_FIX_armv4.h b/drivers/opus/silk/arm/SigProc_FIX_armv4.h
new file mode 100644
index 0000000000..ff62b1e5d6
--- /dev/null
+++ b/drivers/opus/silk/arm/SigProc_FIX_armv4.h
@@ -0,0 +1,47 @@
+/***********************************************************************
+Copyright (C) 2013 Xiph.Org Foundation and contributors
+Copyright (c) 2013 Parrot
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_SIGPROC_FIX_ARMv4_H
+#define SILK_SIGPROC_FIX_ARMv4_H
+
+#undef silk_MLA
+static OPUS_INLINE opus_int32 silk_MLA_armv4(opus_int32 a, opus_int32 b,
+ opus_int32 c)
+{
+ opus_int32 res;
+ __asm__(
+ "#silk_MLA\n\t"
+ "mla %0, %1, %2, %3\n\t"
+ : "=&r"(res)
+ : "r"(b), "r"(c), "r"(a)
+ );
+ return res;
+}
+#define silk_MLA(a, b, c) (silk_MLA_armv4(a, b, c))
+
+#endif
diff --git a/drivers/opus/silk/arm/SigProc_FIX_armv5e.h b/drivers/opus/silk/arm/SigProc_FIX_armv5e.h
new file mode 100644
index 0000000000..617a09cab1
--- /dev/null
+++ b/drivers/opus/silk/arm/SigProc_FIX_armv5e.h
@@ -0,0 +1,61 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Copyright (c) 2013 Parrot
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_SIGPROC_FIX_ARMv5E_H
+#define SILK_SIGPROC_FIX_ARMv5E_H
+
+#undef silk_SMULTT
+static OPUS_INLINE opus_int32 silk_SMULTT_armv5e(opus_int32 a, opus_int32 b)
+{
+ opus_int32 res;
+ __asm__(
+ "#silk_SMULTT\n\t"
+ "smultt %0, %1, %2\n\t"
+ : "=r"(res)
+ : "%r"(a), "r"(b)
+ );
+ return res;
+}
+#define silk_SMULTT(a, b) (silk_SMULTT_armv5e(a, b))
+
+#undef silk_SMLATT
+static OPUS_INLINE opus_int32 silk_SMLATT_armv5e(opus_int32 a, opus_int32 b,
+ opus_int32 c)
+{
+ opus_int32 res;
+ __asm__(
+ "#silk_SMLATT\n\t"
+ "smlatt %0, %1, %2, %3\n\t"
+ : "=r"(res)
+ : "%r"(b), "r"(c), "r"(a)
+ );
+ return res;
+}
+#define silk_SMLATT(a, b, c) (silk_SMLATT_armv5e(a, b, c))
+
+#endif
diff --git a/drivers/opus/silk/arm/macros_armv4.h b/drivers/opus/silk/arm/macros_armv4.h
new file mode 100644
index 0000000000..3f30e97288
--- /dev/null
+++ b/drivers/opus/silk/arm/macros_armv4.h
@@ -0,0 +1,103 @@
+/***********************************************************************
+Copyright (C) 2013 Xiph.Org Foundation and contributors.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_MACROS_ARMv4_H
+#define SILK_MACROS_ARMv4_H
+
+/* (a32 * (opus_int32)((opus_int16)(b32))) >> 16 output have to be 32bit int */
+#undef silk_SMULWB
+static OPUS_INLINE opus_int32 silk_SMULWB_armv4(opus_int32 a, opus_int16 b)
+{
+ unsigned rd_lo;
+ int rd_hi;
+ __asm__(
+ "#silk_SMULWB\n\t"
+ "smull %0, %1, %2, %3\n\t"
+ : "=&r"(rd_lo), "=&r"(rd_hi)
+ : "%r"(a), "r"(b<<16)
+ );
+ return rd_hi;
+}
+#define silk_SMULWB(a, b) (silk_SMULWB_armv4(a, b))
+
+/* a32 + (b32 * (opus_int32)((opus_int16)(c32))) >> 16 output have to be 32bit int */
+#undef silk_SMLAWB
+#define silk_SMLAWB(a, b, c) ((a) + silk_SMULWB(b, c))
+
+/* (a32 * (b32 >> 16)) >> 16 */
+#undef silk_SMULWT
+static OPUS_INLINE opus_int32 silk_SMULWT_armv4(opus_int32 a, opus_int32 b)
+{
+ unsigned rd_lo;
+ int rd_hi;
+ __asm__(
+ "#silk_SMULWT\n\t"
+ "smull %0, %1, %2, %3\n\t"
+ : "=&r"(rd_lo), "=&r"(rd_hi)
+ : "%r"(a), "r"(b&~0xFFFF)
+ );
+ return rd_hi;
+}
+#define silk_SMULWT(a, b) (silk_SMULWT_armv4(a, b))
+
+/* a32 + (b32 * (c32 >> 16)) >> 16 */
+#undef silk_SMLAWT
+#define silk_SMLAWT(a, b, c) ((a) + silk_SMULWT(b, c))
+
+/* (a32 * b32) >> 16 */
+#undef silk_SMULWW
+static OPUS_INLINE opus_int32 silk_SMULWW_armv4(opus_int32 a, opus_int32 b)
+{
+ unsigned rd_lo;
+ int rd_hi;
+ __asm__(
+ "#silk_SMULWW\n\t"
+ "smull %0, %1, %2, %3\n\t"
+ : "=&r"(rd_lo), "=&r"(rd_hi)
+ : "%r"(a), "r"(b)
+ );
+ return (rd_hi<<16)+(rd_lo>>16);
+}
+#define silk_SMULWW(a, b) (silk_SMULWW_armv4(a, b))
+
+#undef silk_SMLAWW
+static OPUS_INLINE opus_int32 silk_SMLAWW_armv4(opus_int32 a, opus_int32 b,
+ opus_int32 c)
+{
+ unsigned rd_lo;
+ int rd_hi;
+ __asm__(
+ "#silk_SMLAWW\n\t"
+ "smull %0, %1, %2, %3\n\t"
+ : "=&r"(rd_lo), "=&r"(rd_hi)
+ : "%r"(b), "r"(c)
+ );
+ return a+(rd_hi<<16)+(rd_lo>>16);
+}
+#define silk_SMLAWW(a, b, c) (silk_SMLAWW_armv4(a, b, c))
+
+#endif /* SILK_MACROS_ARMv4_H */
diff --git a/drivers/opus/silk/arm/macros_armv5e.h b/drivers/opus/silk/arm/macros_armv5e.h
new file mode 100644
index 0000000000..aad4117e46
--- /dev/null
+++ b/drivers/opus/silk/arm/macros_armv5e.h
@@ -0,0 +1,213 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Copyright (c) 2013 Parrot
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_MACROS_ARMv5E_H
+#define SILK_MACROS_ARMv5E_H
+
+/* (a32 * (opus_int32)((opus_int16)(b32))) >> 16 output have to be 32bit int */
+#undef silk_SMULWB
+static OPUS_INLINE opus_int32 silk_SMULWB_armv5e(opus_int32 a, opus_int16 b)
+{
+ int res;
+ __asm__(
+ "#silk_SMULWB\n\t"
+ "smulwb %0, %1, %2\n\t"
+ : "=r"(res)
+ : "r"(a), "r"(b)
+ );
+ return res;
+}
+#define silk_SMULWB(a, b) (silk_SMULWB_armv5e(a, b))
+
+/* a32 + (b32 * (opus_int32)((opus_int16)(c32))) >> 16 output have to be 32bit int */
+#undef silk_SMLAWB
+static OPUS_INLINE opus_int32 silk_SMLAWB_armv5e(opus_int32 a, opus_int32 b,
+ opus_int16 c)
+{
+ int res;
+ __asm__(
+ "#silk_SMLAWB\n\t"
+ "smlawb %0, %1, %2, %3\n\t"
+ : "=r"(res)
+ : "r"(b), "r"(c), "r"(a)
+ );
+ return res;
+}
+#define silk_SMLAWB(a, b, c) (silk_SMLAWB_armv5e(a, b, c))
+
+/* (a32 * (b32 >> 16)) >> 16 */
+#undef silk_SMULWT
+static OPUS_INLINE opus_int32 silk_SMULWT_armv5e(opus_int32 a, opus_int32 b)
+{
+ int res;
+ __asm__(
+ "#silk_SMULWT\n\t"
+ "smulwt %0, %1, %2\n\t"
+ : "=r"(res)
+ : "r"(a), "r"(b)
+ );
+ return res;
+}
+#define silk_SMULWT(a, b) (silk_SMULWT_armv5e(a, b))
+
+/* a32 + (b32 * (c32 >> 16)) >> 16 */
+#undef silk_SMLAWT
+static OPUS_INLINE opus_int32 silk_SMLAWT_armv5e(opus_int32 a, opus_int32 b,
+ opus_int32 c)
+{
+ int res;
+ __asm__(
+ "#silk_SMLAWT\n\t"
+ "smlawt %0, %1, %2, %3\n\t"
+ : "=r"(res)
+ : "r"(b), "r"(c), "r"(a)
+ );
+ return res;
+}
+#define silk_SMLAWT(a, b, c) (silk_SMLAWT_armv5e(a, b, c))
+
+/* (opus_int32)((opus_int16)(a3))) * (opus_int32)((opus_int16)(b32)) output have to be 32bit int */
+#undef silk_SMULBB
+static OPUS_INLINE opus_int32 silk_SMULBB_armv5e(opus_int32 a, opus_int32 b)
+{
+ int res;
+ __asm__(
+ "#silk_SMULBB\n\t"
+ "smulbb %0, %1, %2\n\t"
+ : "=r"(res)
+ : "%r"(a), "r"(b)
+ );
+ return res;
+}
+#define silk_SMULBB(a, b) (silk_SMULBB_armv5e(a, b))
+
+/* a32 + (opus_int32)((opus_int16)(b32)) * (opus_int32)((opus_int16)(c32)) output have to be 32bit int */
+#undef silk_SMLABB
+static OPUS_INLINE opus_int32 silk_SMLABB_armv5e(opus_int32 a, opus_int32 b,
+ opus_int32 c)
+{
+ int res;
+ __asm__(
+ "#silk_SMLABB\n\t"
+ "smlabb %0, %1, %2, %3\n\t"
+ : "=r"(res)
+ : "%r"(b), "r"(c), "r"(a)
+ );
+ return res;
+}
+#define silk_SMLABB(a, b, c) (silk_SMLABB_armv5e(a, b, c))
+
+/* (opus_int32)((opus_int16)(a32)) * (b32 >> 16) */
+#undef silk_SMULBT
+static OPUS_INLINE opus_int32 silk_SMULBT_armv5e(opus_int32 a, opus_int32 b)
+{
+ int res;
+ __asm__(
+ "#silk_SMULBT\n\t"
+ "smulbt %0, %1, %2\n\t"
+ : "=r"(res)
+ : "r"(a), "r"(b)
+ );
+ return res;
+}
+#define silk_SMULBT(a, b) (silk_SMULBT_armv5e(a, b))
+
+/* a32 + (opus_int32)((opus_int16)(b32)) * (c32 >> 16) */
+#undef silk_SMLABT
+static OPUS_INLINE opus_int32 silk_SMLABT_armv5e(opus_int32 a, opus_int32 b,
+ opus_int32 c)
+{
+ int res;
+ __asm__(
+ "#silk_SMLABT\n\t"
+ "smlabt %0, %1, %2, %3\n\t"
+ : "=r"(res)
+ : "r"(b), "r"(c), "r"(a)
+ );
+ return res;
+}
+#define silk_SMLABT(a, b, c) (silk_SMLABT_armv5e(a, b, c))
+
+/* add/subtract with output saturated */
+#undef silk_ADD_SAT32
+static OPUS_INLINE opus_int32 silk_ADD_SAT32_armv5e(opus_int32 a, opus_int32 b)
+{
+ int res;
+ __asm__(
+ "#silk_ADD_SAT32\n\t"
+ "qadd %0, %1, %2\n\t"
+ : "=r"(res)
+ : "%r"(a), "r"(b)
+ );
+ return res;
+}
+#define silk_ADD_SAT32(a, b) (silk_ADD_SAT32_armv5e(a, b))
+
+#undef silk_SUB_SAT32
+static OPUS_INLINE opus_int32 silk_SUB_SAT32_armv5e(opus_int32 a, opus_int32 b)
+{
+ int res;
+ __asm__(
+ "#silk_SUB_SAT32\n\t"
+ "qsub %0, %1, %2\n\t"
+ : "=r"(res)
+ : "r"(a), "r"(b)
+ );
+ return res;
+}
+#define silk_SUB_SAT32(a, b) (silk_SUB_SAT32_armv5e(a, b))
+
+#undef silk_CLZ16
+static OPUS_INLINE opus_int32 silk_CLZ16_armv5(opus_int16 in16)
+{
+ int res;
+ __asm__(
+ "#silk_CLZ16\n\t"
+ "clz %0, %1;\n"
+ : "=r"(res)
+ : "r"(in16<<16|0x8000)
+ );
+ return res;
+}
+#define silk_CLZ16(in16) (silk_CLZ16_armv5(in16))
+
+#undef silk_CLZ32
+static OPUS_INLINE opus_int32 silk_CLZ32_armv5(opus_int32 in32)
+{
+ int res;
+ __asm__(
+ "#silk_CLZ32\n\t"
+ "clz %0, %1\n\t"
+ : "=r"(res)
+ : "r"(in32)
+ );
+ return res;
+}
+#define silk_CLZ32(in32) (silk_CLZ32_armv5(in32))
+
+#endif /* SILK_MACROS_ARMv5E_H */
diff --git a/drivers/opus/silk/biquad_alt.c b/drivers/opus/silk/biquad_alt.c
new file mode 100644
index 0000000000..85708167de
--- /dev/null
+++ b/drivers/opus/silk/biquad_alt.c
@@ -0,0 +1,78 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+/* *
+ * silk_biquad_alt.c *
+ * *
+ * Second order ARMA filter *
+ * Can handle slowly varying filter coefficients *
+ * */
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/SigProc_FIX.h"
+
+/* Second order ARMA filter, alternative implementation */
+void silk_biquad_alt(
+ const opus_int16 *in, /* I input signal */
+ const opus_int32 *B_Q28, /* I MA coefficients [3] */
+ const opus_int32 *A_Q28, /* I AR coefficients [2] */
+ opus_int32 *S, /* I/O State vector [2] */
+ opus_int16 *out, /* O output signal */
+ const opus_int32 len, /* I signal length (must be even) */
+ opus_int stride /* I Operate on interleaved signal if > 1 */
+)
+{
+ /* DIRECT FORM II TRANSPOSED (uses 2 element state vector) */
+ opus_int k;
+ opus_int32 inval, A0_U_Q28, A0_L_Q28, A1_U_Q28, A1_L_Q28, out32_Q14;
+
+ /* Negate A_Q28 values and split in two parts */
+ A0_L_Q28 = ( -A_Q28[ 0 ] ) & 0x00003FFF; /* lower part */
+ A0_U_Q28 = silk_RSHIFT( -A_Q28[ 0 ], 14 ); /* upper part */
+ A1_L_Q28 = ( -A_Q28[ 1 ] ) & 0x00003FFF; /* lower part */
+ A1_U_Q28 = silk_RSHIFT( -A_Q28[ 1 ], 14 ); /* upper part */
+
+ for( k = 0; k < len; k++ ) {
+ /* S[ 0 ], S[ 1 ]: Q12 */
+ inval = in[ k * stride ];
+ out32_Q14 = silk_LSHIFT( silk_SMLAWB( S[ 0 ], B_Q28[ 0 ], inval ), 2 );
+
+ S[ 0 ] = S[1] + silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14, A0_L_Q28 ), 14 );
+ S[ 0 ] = silk_SMLAWB( S[ 0 ], out32_Q14, A0_U_Q28 );
+ S[ 0 ] = silk_SMLAWB( S[ 0 ], B_Q28[ 1 ], inval);
+
+ S[ 1 ] = silk_RSHIFT_ROUND( silk_SMULWB( out32_Q14, A1_L_Q28 ), 14 );
+ S[ 1 ] = silk_SMLAWB( S[ 1 ], out32_Q14, A1_U_Q28 );
+ S[ 1 ] = silk_SMLAWB( S[ 1 ], B_Q28[ 2 ], inval );
+
+ /* Scale back to Q0 and saturate */
+ out[ k * stride ] = (opus_int16)silk_SAT16( silk_RSHIFT( out32_Q14 + (1<<14) - 1, 14 ) );
+ }
+}
diff --git a/drivers/opus/silk/bwexpander.c b/drivers/opus/silk/bwexpander.c
new file mode 100644
index 0000000000..7f81a2af99
--- /dev/null
+++ b/drivers/opus/silk/bwexpander.c
@@ -0,0 +1,51 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/SigProc_FIX.h"
+
+/* Chirp (bandwidth expand) LP AR filter */
+void silk_bwexpander(
+ opus_int16 *ar, /* I/O AR filter to be expanded (without leading 1) */
+ const opus_int d, /* I Length of ar */
+ opus_int32 chirp_Q16 /* I Chirp factor (typically in the range 0 to 1) */
+)
+{
+ opus_int i;
+ opus_int32 chirp_minus_one_Q16 = chirp_Q16 - 65536;
+
+ /* NB: Dont use silk_SMULWB, instead of silk_RSHIFT_ROUND( silk_MUL(), 16 ), below. */
+ /* Bias in silk_SMULWB can lead to unstable filters */
+ for( i = 0; i < d - 1; i++ ) {
+ ar[ i ] = (opus_int16)silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, ar[ i ] ), 16 );
+ chirp_Q16 += silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, chirp_minus_one_Q16 ), 16 );
+ }
+ ar[ d - 1 ] = (opus_int16)silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, ar[ d - 1 ] ), 16 );
+}
diff --git a/drivers/opus/silk/bwexpander_32.c b/drivers/opus/silk/bwexpander_32.c
new file mode 100644
index 0000000000..58dfe1f8d6
--- /dev/null
+++ b/drivers/opus/silk/bwexpander_32.c
@@ -0,0 +1,50 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/SigProc_FIX.h"
+
+/* Chirp (bandwidth expand) LP AR filter */
+void silk_bwexpander_32(
+ opus_int32 *ar, /* I/O AR filter to be expanded (without leading 1) */
+ const opus_int d, /* I Length of ar */
+ opus_int32 chirp_Q16 /* I Chirp factor in Q16 */
+)
+{
+ opus_int i;
+ opus_int32 chirp_minus_one_Q16 = chirp_Q16 - 65536;
+
+ for( i = 0; i < d - 1; i++ ) {
+ ar[ i ] = silk_SMULWW( chirp_Q16, ar[ i ] );
+ chirp_Q16 += silk_RSHIFT_ROUND( silk_MUL( chirp_Q16, chirp_minus_one_Q16 ), 16 );
+ }
+ ar[ d - 1 ] = silk_SMULWW( chirp_Q16, ar[ d - 1 ] );
+}
+
diff --git a/drivers/opus/silk/check_control_input.c b/drivers/opus/silk/check_control_input.c
new file mode 100644
index 0000000000..9c882334c3
--- /dev/null
+++ b/drivers/opus/silk/check_control_input.c
@@ -0,0 +1,106 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+#include "opus/silk/control.h"
+#include "opus/silk/errors.h"
+
+/* Check encoder control struct */
+opus_int check_control_input(
+ silk_EncControlStruct *encControl /* I Control structure */
+)
+{
+ silk_assert( encControl != NULL );
+
+ if( ( ( encControl->API_sampleRate != 8000 ) &&
+ ( encControl->API_sampleRate != 12000 ) &&
+ ( encControl->API_sampleRate != 16000 ) &&
+ ( encControl->API_sampleRate != 24000 ) &&
+ ( encControl->API_sampleRate != 32000 ) &&
+ ( encControl->API_sampleRate != 44100 ) &&
+ ( encControl->API_sampleRate != 48000 ) ) ||
+ ( ( encControl->desiredInternalSampleRate != 8000 ) &&
+ ( encControl->desiredInternalSampleRate != 12000 ) &&
+ ( encControl->desiredInternalSampleRate != 16000 ) ) ||
+ ( ( encControl->maxInternalSampleRate != 8000 ) &&
+ ( encControl->maxInternalSampleRate != 12000 ) &&
+ ( encControl->maxInternalSampleRate != 16000 ) ) ||
+ ( ( encControl->minInternalSampleRate != 8000 ) &&
+ ( encControl->minInternalSampleRate != 12000 ) &&
+ ( encControl->minInternalSampleRate != 16000 ) ) ||
+ ( encControl->minInternalSampleRate > encControl->desiredInternalSampleRate ) ||
+ ( encControl->maxInternalSampleRate < encControl->desiredInternalSampleRate ) ||
+ ( encControl->minInternalSampleRate > encControl->maxInternalSampleRate ) ) {
+ silk_assert( 0 );
+ return SILK_ENC_FS_NOT_SUPPORTED;
+ }
+ if( encControl->payloadSize_ms != 10 &&
+ encControl->payloadSize_ms != 20 &&
+ encControl->payloadSize_ms != 40 &&
+ encControl->payloadSize_ms != 60 ) {
+ silk_assert( 0 );
+ return SILK_ENC_PACKET_SIZE_NOT_SUPPORTED;
+ }
+ if( encControl->packetLossPercentage < 0 || encControl->packetLossPercentage > 100 ) {
+ silk_assert( 0 );
+ return SILK_ENC_INVALID_LOSS_RATE;
+ }
+ if( encControl->useDTX < 0 || encControl->useDTX > 1 ) {
+ silk_assert( 0 );
+ return SILK_ENC_INVALID_DTX_SETTING;
+ }
+ if( encControl->useCBR < 0 || encControl->useCBR > 1 ) {
+ silk_assert( 0 );
+ return SILK_ENC_INVALID_CBR_SETTING;
+ }
+ if( encControl->useInBandFEC < 0 || encControl->useInBandFEC > 1 ) {
+ silk_assert( 0 );
+ return SILK_ENC_INVALID_INBAND_FEC_SETTING;
+ }
+ if( encControl->nChannelsAPI < 1 || encControl->nChannelsAPI > ENCODER_NUM_CHANNELS ) {
+ silk_assert( 0 );
+ return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR;
+ }
+ if( encControl->nChannelsInternal < 1 || encControl->nChannelsInternal > ENCODER_NUM_CHANNELS ) {
+ silk_assert( 0 );
+ return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR;
+ }
+ if( encControl->nChannelsInternal > encControl->nChannelsAPI ) {
+ silk_assert( 0 );
+ return SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR;
+ }
+ if( encControl->complexity < 0 || encControl->complexity > 10 ) {
+ silk_assert( 0 );
+ return SILK_ENC_INVALID_COMPLEXITY_SETTING;
+ }
+
+ return SILK_NO_ERROR;
+}
diff --git a/drivers/opus/silk/code_signs.c b/drivers/opus/silk/code_signs.c
new file mode 100644
index 0000000000..e2f671d7ca
--- /dev/null
+++ b/drivers/opus/silk/code_signs.c
@@ -0,0 +1,115 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+
+/*#define silk_enc_map(a) ((a) > 0 ? 1 : 0)*/
+/*#define silk_dec_map(a) ((a) > 0 ? 1 : -1)*/
+/* shifting avoids if-statement */
+#define silk_enc_map(a) ( silk_RSHIFT( (a), 15 ) + 1 )
+#define silk_dec_map(a) ( silk_LSHIFT( (a), 1 ) - 1 )
+
+/* Encodes signs of excitation */
+void silk_encode_signs(
+ ec_enc *psRangeEnc, /* I/O Compressor data structure */
+ const opus_int8 pulses[], /* I pulse signal */
+ opus_int length, /* I length of input */
+ const opus_int signalType, /* I Signal type */
+ const opus_int quantOffsetType, /* I Quantization offset type */
+ const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */
+)
+{
+ opus_int i, j, p;
+ opus_uint8 icdf[ 2 ];
+ const opus_int8 *q_ptr;
+ const opus_uint8 *icdf_ptr;
+
+ icdf[ 1 ] = 0;
+ q_ptr = pulses;
+ i = silk_SMULBB( 7, silk_ADD_LSHIFT( quantOffsetType, signalType, 1 ) );
+ icdf_ptr = &silk_sign_iCDF[ i ];
+ length = silk_RSHIFT( length + SHELL_CODEC_FRAME_LENGTH/2, LOG2_SHELL_CODEC_FRAME_LENGTH );
+ for( i = 0; i < length; i++ ) {
+ p = sum_pulses[ i ];
+ if( p > 0 ) {
+ icdf[ 0 ] = icdf_ptr[ silk_min( p & 0x1F, 6 ) ];
+ for( j = 0; j < SHELL_CODEC_FRAME_LENGTH; j++ ) {
+ if( q_ptr[ j ] != 0 ) {
+ ec_enc_icdf( psRangeEnc, silk_enc_map( q_ptr[ j ]), icdf, 8 );
+ }
+ }
+ }
+ q_ptr += SHELL_CODEC_FRAME_LENGTH;
+ }
+}
+
+/* Decodes signs of excitation */
+void silk_decode_signs(
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int pulses[], /* I/O pulse signal */
+ opus_int length, /* I length of input */
+ const opus_int signalType, /* I Signal type */
+ const opus_int quantOffsetType, /* I Quantization offset type */
+ const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */
+)
+{
+ opus_int i, j, p;
+ opus_uint8 icdf[ 2 ];
+ opus_int *q_ptr;
+ const opus_uint8 *icdf_ptr;
+
+ icdf[ 1 ] = 0;
+ q_ptr = pulses;
+ i = silk_SMULBB( 7, silk_ADD_LSHIFT( quantOffsetType, signalType, 1 ) );
+ icdf_ptr = &silk_sign_iCDF[ i ];
+ length = silk_RSHIFT( length + SHELL_CODEC_FRAME_LENGTH/2, LOG2_SHELL_CODEC_FRAME_LENGTH );
+ for( i = 0; i < length; i++ ) {
+ p = sum_pulses[ i ];
+ if( p > 0 ) {
+ icdf[ 0 ] = icdf_ptr[ silk_min( p & 0x1F, 6 ) ];
+ for( j = 0; j < SHELL_CODEC_FRAME_LENGTH; j++ ) {
+ if( q_ptr[ j ] > 0 ) {
+ /* attach sign */
+#if 0
+ /* conditional implementation */
+ if( ec_dec_icdf( psRangeDec, icdf, 8 ) == 0 ) {
+ q_ptr[ j ] = -q_ptr[ j ];
+ }
+#else
+ /* implementation with shift, subtraction, multiplication */
+ q_ptr[ j ] *= silk_dec_map( ec_dec_icdf( psRangeDec, icdf, 8 ) );
+#endif
+ }
+ }
+ }
+ q_ptr += SHELL_CODEC_FRAME_LENGTH;
+ }
+}
diff --git a/drivers/opus/silk/control.h b/drivers/opus/silk/control.h
new file mode 100644
index 0000000000..4b20c4a8b8
--- /dev/null
+++ b/drivers/opus/silk/control.h
@@ -0,0 +1,142 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_CONTROL_H
+#define SILK_CONTROL_H
+
+#include "opus/silk/typedef.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Decoder API flags */
+#define FLAG_DECODE_NORMAL 0
+#define FLAG_PACKET_LOST 1
+#define FLAG_DECODE_LBRR 2
+
+/***********************************************/
+/* Structure for controlling encoder operation */
+/***********************************************/
+typedef struct {
+ /* I: Number of channels; 1/2 */
+ opus_int32 nChannelsAPI;
+
+ /* I: Number of channels; 1/2 */
+ opus_int32 nChannelsInternal;
+
+ /* I: Input signal sampling rate in Hertz; 8000/12000/16000/24000/32000/44100/48000 */
+ opus_int32 API_sampleRate;
+
+ /* I: Maximum internal sampling rate in Hertz; 8000/12000/16000 */
+ opus_int32 maxInternalSampleRate;
+
+ /* I: Minimum internal sampling rate in Hertz; 8000/12000/16000 */
+ opus_int32 minInternalSampleRate;
+
+ /* I: Soft request for internal sampling rate in Hertz; 8000/12000/16000 */
+ opus_int32 desiredInternalSampleRate;
+
+ /* I: Number of samples per packet in milliseconds; 10/20/40/60 */
+ opus_int payloadSize_ms;
+
+ /* I: Bitrate during active speech in bits/second; internally limited */
+ opus_int32 bitRate;
+
+ /* I: Uplink packet loss in percent (0-100) */
+ opus_int packetLossPercentage;
+
+ /* I: Complexity mode; 0 is lowest, 10 is highest complexity */
+ opus_int complexity;
+
+ /* I: Flag to enable in-band Forward Error Correction (FEC); 0/1 */
+ opus_int useInBandFEC;
+
+ /* I: Flag to enable discontinuous transmission (DTX); 0/1 */
+ opus_int useDTX;
+
+ /* I: Flag to use constant bitrate */
+ opus_int useCBR;
+
+ /* I: Maximum number of bits allowed for the frame */
+ opus_int maxBits;
+
+ /* I: Causes a smooth downmix to mono */
+ opus_int toMono;
+
+ /* I: Opus encoder is allowing us to switch bandwidth */
+ opus_int opusCanSwitch;
+
+ /* I: Make frames as independent as possible (but still use LPC) */
+ opus_int reducedDependency;
+
+ /* O: Internal sampling rate used, in Hertz; 8000/12000/16000 */
+ opus_int32 internalSampleRate;
+
+ /* O: Flag that bandwidth switching is allowed (because low voice activity) */
+ opus_int allowBandwidthSwitch;
+
+ /* O: Flag that SILK runs in WB mode without variable LP filter (use for switching between WB/SWB/FB) */
+ opus_int inWBmodeWithoutVariableLP;
+
+ /* O: Stereo width */
+ opus_int stereoWidth_Q14;
+
+ /* O: Tells the Opus encoder we're ready to switch */
+ opus_int switchReady;
+
+} silk_EncControlStruct;
+
+/**************************************************************************/
+/* Structure for controlling decoder operation and reading decoder status */
+/**************************************************************************/
+typedef struct {
+ /* I: Number of channels; 1/2 */
+ opus_int32 nChannelsAPI;
+
+ /* I: Number of channels; 1/2 */
+ opus_int32 nChannelsInternal;
+
+ /* I: Output signal sampling rate in Hertz; 8000/12000/16000/24000/32000/44100/48000 */
+ opus_int32 API_sampleRate;
+
+ /* I: Internal sampling rate used, in Hertz; 8000/12000/16000 */
+ opus_int32 internalSampleRate;
+
+ /* I: Number of samples per packet in milliseconds; 10/20/40/60 */
+ opus_int payloadSize_ms;
+
+ /* O: Pitch lag of previous frame (0 if unvoiced), measured in samples at 48 kHz */
+ opus_int prevPitchLag;
+} silk_DecControlStruct;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/opus/silk/control_SNR.c b/drivers/opus/silk/control_SNR.c
new file mode 100644
index 0000000000..e3983d5039
--- /dev/null
+++ b/drivers/opus/silk/control_SNR.c
@@ -0,0 +1,81 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+#include "opus/silk/tuning_parameters.h"
+
+/* Control SNR of redidual quantizer */
+opus_int silk_control_SNR(
+ silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */
+ opus_int32 TargetRate_bps /* I Target max bitrate (bps) */
+)
+{
+ opus_int k, ret = SILK_NO_ERROR;
+ opus_int32 frac_Q6;
+ const opus_int32 *rateTable;
+
+ /* Set bitrate/coding quality */
+ TargetRate_bps = silk_LIMIT( TargetRate_bps, MIN_TARGET_RATE_BPS, MAX_TARGET_RATE_BPS );
+ if( TargetRate_bps != psEncC->TargetRate_bps ) {
+ psEncC->TargetRate_bps = TargetRate_bps;
+
+ /* If new TargetRate_bps, translate to SNR_dB value */
+ if( psEncC->fs_kHz == 8 ) {
+ rateTable = silk_TargetRate_table_NB;
+ } else if( psEncC->fs_kHz == 12 ) {
+ rateTable = silk_TargetRate_table_MB;
+ } else {
+ rateTable = silk_TargetRate_table_WB;
+ }
+
+ /* Reduce bitrate for 10 ms modes in these calculations */
+ if( psEncC->nb_subfr == 2 ) {
+ TargetRate_bps -= REDUCE_BITRATE_10_MS_BPS;
+ }
+
+ /* Find bitrate interval in table and interpolate */
+ for( k = 1; k < TARGET_RATE_TAB_SZ; k++ ) {
+ if( TargetRate_bps <= rateTable[ k ] ) {
+ frac_Q6 = silk_DIV32( silk_LSHIFT( TargetRate_bps - rateTable[ k - 1 ], 6 ),
+ rateTable[ k ] - rateTable[ k - 1 ] );
+ psEncC->SNR_dB_Q7 = silk_LSHIFT( silk_SNR_table_Q1[ k - 1 ], 6 ) + silk_MUL( frac_Q6, silk_SNR_table_Q1[ k ] - silk_SNR_table_Q1[ k - 1 ] );
+ break;
+ }
+ }
+
+ /* Reduce coding quality whenever LBRR is enabled, to free up some bits */
+ if( psEncC->LBRR_enabled ) {
+ psEncC->SNR_dB_Q7 = silk_SMLABB( psEncC->SNR_dB_Q7, 12 - psEncC->LBRR_GainIncreases, SILK_FIX_CONST( -0.25, 7 ) );
+ }
+ }
+
+ return ret;
+}
diff --git a/drivers/opus/silk/control_audio_bandwidth.c b/drivers/opus/silk/control_audio_bandwidth.c
new file mode 100644
index 0000000000..846a7baa59
--- /dev/null
+++ b/drivers/opus/silk/control_audio_bandwidth.c
@@ -0,0 +1,126 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+#include "opus/silk/tuning_parameters.h"
+
+/* Control internal sampling rate */
+opus_int silk_control_audio_bandwidth(
+ silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */
+ silk_EncControlStruct *encControl /* I Control structure */
+)
+{
+ opus_int fs_kHz;
+ opus_int32 fs_Hz;
+
+ fs_kHz = psEncC->fs_kHz;
+ fs_Hz = silk_SMULBB( fs_kHz, 1000 );
+ if( fs_Hz == 0 ) {
+ /* Encoder has just been initialized */
+ fs_Hz = silk_min( psEncC->desiredInternal_fs_Hz, psEncC->API_fs_Hz );
+ fs_kHz = silk_DIV32_16( fs_Hz, 1000 );
+ } else if( fs_Hz > psEncC->API_fs_Hz || fs_Hz > psEncC->maxInternal_fs_Hz || fs_Hz < psEncC->minInternal_fs_Hz ) {
+ /* Make sure internal rate is not higher than external rate or maximum allowed, or lower than minimum allowed */
+ fs_Hz = psEncC->API_fs_Hz;
+ fs_Hz = silk_min( fs_Hz, psEncC->maxInternal_fs_Hz );
+ fs_Hz = silk_max( fs_Hz, psEncC->minInternal_fs_Hz );
+ fs_kHz = silk_DIV32_16( fs_Hz, 1000 );
+ } else {
+ /* State machine for the internal sampling rate switching */
+ if( psEncC->sLP.transition_frame_no >= TRANSITION_FRAMES ) {
+ /* Stop transition phase */
+ psEncC->sLP.mode = 0;
+ }
+ if( psEncC->allow_bandwidth_switch || encControl->opusCanSwitch ) {
+ /* Check if we should switch down */
+ if( silk_SMULBB( psEncC->fs_kHz, 1000 ) > psEncC->desiredInternal_fs_Hz )
+ {
+ /* Switch down */
+ if( psEncC->sLP.mode == 0 ) {
+ /* New transition */
+ psEncC->sLP.transition_frame_no = TRANSITION_FRAMES;
+
+ /* Reset transition filter state */
+ silk_memset( psEncC->sLP.In_LP_State, 0, sizeof( psEncC->sLP.In_LP_State ) );
+ }
+ if( encControl->opusCanSwitch ) {
+ /* Stop transition phase */
+ psEncC->sLP.mode = 0;
+
+ /* Switch to a lower sample frequency */
+ fs_kHz = psEncC->fs_kHz == 16 ? 12 : 8;
+ } else {
+ if( psEncC->sLP.transition_frame_no <= 0 ) {
+ encControl->switchReady = 1;
+ /* Make room for redundancy */
+ encControl->maxBits -= encControl->maxBits * 5 / ( encControl->payloadSize_ms + 5 );
+ } else {
+ /* Direction: down (at double speed) */
+ psEncC->sLP.mode = -2;
+ }
+ }
+ }
+ else
+ /* Check if we should switch up */
+ if( silk_SMULBB( psEncC->fs_kHz, 1000 ) < psEncC->desiredInternal_fs_Hz )
+ {
+ /* Switch up */
+ if( encControl->opusCanSwitch ) {
+ /* Switch to a higher sample frequency */
+ fs_kHz = psEncC->fs_kHz == 8 ? 12 : 16;
+
+ /* New transition */
+ psEncC->sLP.transition_frame_no = 0;
+
+ /* Reset transition filter state */
+ silk_memset( psEncC->sLP.In_LP_State, 0, sizeof( psEncC->sLP.In_LP_State ) );
+
+ /* Direction: up */
+ psEncC->sLP.mode = 1;
+ } else {
+ if( psEncC->sLP.mode == 0 ) {
+ encControl->switchReady = 1;
+ /* Make room for redundancy */
+ encControl->maxBits -= encControl->maxBits * 5 / ( encControl->payloadSize_ms + 5 );
+ } else {
+ /* Direction: up */
+ psEncC->sLP.mode = 1;
+ }
+ }
+ } else {
+ if (psEncC->sLP.mode<0)
+ psEncC->sLP.mode = 1;
+ }
+ }
+ }
+
+ return fs_kHz;
+}
diff --git a/drivers/opus/silk/control_codec.c b/drivers/opus/silk/control_codec.c
new file mode 100644
index 0000000000..beb6dfe6cd
--- /dev/null
+++ b/drivers/opus/silk/control_codec.c
@@ -0,0 +1,422 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+#ifdef OPUS_FIXED_POINT
+#include "opus/silk/fixed/main_FIX.h"
+#define silk_encoder_state_Fxx silk_encoder_state_FIX
+#else
+#include "opus/silk/float/main_FLP.h"
+#define silk_encoder_state_Fxx silk_encoder_state_FLP
+#endif
+#include "opus/celt/stack_alloc.h"
+#include "opus/silk/tuning_parameters.h"
+#include "opus/silk/pitch_est_defines.h"
+
+static opus_int silk_setup_resamplers(
+ silk_encoder_state_Fxx *psEnc, /* I/O */
+ opus_int fs_kHz /* I */
+);
+
+static opus_int silk_setup_fs(
+ silk_encoder_state_Fxx *psEnc, /* I/O */
+ opus_int fs_kHz, /* I */
+ opus_int PacketSize_ms /* I */
+);
+
+static opus_int silk_setup_complexity(
+ silk_encoder_state *psEncC, /* I/O */
+ opus_int Complexity /* I */
+);
+
+static OPUS_INLINE opus_int silk_setup_LBRR(
+ silk_encoder_state *psEncC, /* I/O */
+ const opus_int32 TargetRate_bps /* I */
+);
+
+
+/* Control encoder */
+opus_int silk_control_encoder(
+ silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk encoder state */
+ silk_EncControlStruct *encControl, /* I Control structure */
+ const opus_int32 TargetRate_bps, /* I Target max bitrate (bps) */
+ const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */
+ const opus_int channelNb, /* I Channel number */
+ const opus_int force_fs_kHz
+)
+{
+ opus_int fs_kHz, ret = 0;
+
+ psEnc->sCmn.useDTX = encControl->useDTX;
+ psEnc->sCmn.useCBR = encControl->useCBR;
+ psEnc->sCmn.API_fs_Hz = encControl->API_sampleRate;
+ psEnc->sCmn.maxInternal_fs_Hz = encControl->maxInternalSampleRate;
+ psEnc->sCmn.minInternal_fs_Hz = encControl->minInternalSampleRate;
+ psEnc->sCmn.desiredInternal_fs_Hz = encControl->desiredInternalSampleRate;
+ psEnc->sCmn.useInBandFEC = encControl->useInBandFEC;
+ psEnc->sCmn.nChannelsAPI = encControl->nChannelsAPI;
+ psEnc->sCmn.nChannelsInternal = encControl->nChannelsInternal;
+ psEnc->sCmn.allow_bandwidth_switch = allow_bw_switch;
+ psEnc->sCmn.channelNb = channelNb;
+
+ if( psEnc->sCmn.controlled_since_last_payload != 0 && psEnc->sCmn.prefillFlag == 0 ) {
+ if( psEnc->sCmn.API_fs_Hz != psEnc->sCmn.prev_API_fs_Hz && psEnc->sCmn.fs_kHz > 0 ) {
+ /* Change in API sampling rate in the middle of encoding a packet */
+ ret += silk_setup_resamplers( psEnc, psEnc->sCmn.fs_kHz );
+ }
+ return ret;
+ }
+
+ /* Beyond this point we know that there are no previously coded frames in the payload buffer */
+
+ /********************************************/
+ /* Determine internal sampling rate */
+ /********************************************/
+ fs_kHz = silk_control_audio_bandwidth( &psEnc->sCmn, encControl );
+ if( force_fs_kHz ) {
+ fs_kHz = force_fs_kHz;
+ }
+ /********************************************/
+ /* Prepare resampler and buffered data */
+ /********************************************/
+ ret += silk_setup_resamplers( psEnc, fs_kHz );
+
+ /********************************************/
+ /* Set internal sampling frequency */
+ /********************************************/
+ ret += silk_setup_fs( psEnc, fs_kHz, encControl->payloadSize_ms );
+
+ /********************************************/
+ /* Set encoding complexity */
+ /********************************************/
+ ret += silk_setup_complexity( &psEnc->sCmn, encControl->complexity );
+
+ /********************************************/
+ /* Set packet loss rate measured by farend */
+ /********************************************/
+ psEnc->sCmn.PacketLoss_perc = encControl->packetLossPercentage;
+
+ /********************************************/
+ /* Set LBRR usage */
+ /********************************************/
+ ret += silk_setup_LBRR( &psEnc->sCmn, TargetRate_bps );
+
+ psEnc->sCmn.controlled_since_last_payload = 1;
+
+ return ret;
+}
+
+static opus_int silk_setup_resamplers(
+ silk_encoder_state_Fxx *psEnc, /* I/O */
+ opus_int fs_kHz /* I */
+)
+{
+ opus_int ret = SILK_NO_ERROR;
+ SAVE_STACK;
+
+ if( psEnc->sCmn.fs_kHz != fs_kHz || psEnc->sCmn.prev_API_fs_Hz != psEnc->sCmn.API_fs_Hz )
+ {
+ if( psEnc->sCmn.fs_kHz == 0 ) {
+ /* Initialize the resampler for enc_API.c preparing resampling from API_fs_Hz to fs_kHz */
+ ret += silk_resampler_init( &psEnc->sCmn.resampler_state, psEnc->sCmn.API_fs_Hz, fs_kHz * 1000, 1 );
+ } else {
+ VARDECL( opus_int16, x_buf_API_fs_Hz );
+ VARDECL( silk_resampler_state_struct, temp_resampler_state );
+#ifdef OPUS_FIXED_POINT
+ opus_int16 *x_bufFIX = psEnc->x_buf;
+#else
+ VARDECL( opus_int16, x_bufFIX );
+ opus_int32 new_buf_samples;
+#endif
+ opus_int32 api_buf_samples;
+ opus_int32 old_buf_samples;
+ opus_int32 buf_length_ms;
+
+ buf_length_ms = silk_LSHIFT( psEnc->sCmn.nb_subfr * 5, 1 ) + LA_SHAPE_MS;
+ old_buf_samples = buf_length_ms * psEnc->sCmn.fs_kHz;
+
+#ifndef OPUS_FIXED_POINT
+ new_buf_samples = buf_length_ms * fs_kHz;
+ ALLOC( x_bufFIX, silk_max( old_buf_samples, new_buf_samples ),
+ opus_int16 );
+ silk_float2short_array( x_bufFIX, psEnc->x_buf, old_buf_samples );
+#endif
+
+ /* Initialize resampler for temporary resampling of x_buf data to API_fs_Hz */
+ ALLOC( temp_resampler_state, 1, silk_resampler_state_struct );
+ ret += silk_resampler_init( temp_resampler_state, silk_SMULBB( psEnc->sCmn.fs_kHz, 1000 ), psEnc->sCmn.API_fs_Hz, 0 );
+
+ /* Calculate number of samples to temporarily upsample */
+ api_buf_samples = buf_length_ms * silk_DIV32_16( psEnc->sCmn.API_fs_Hz, 1000 );
+
+ /* Temporary resampling of x_buf data to API_fs_Hz */
+ ALLOC( x_buf_API_fs_Hz, api_buf_samples, opus_int16 );
+ ret += silk_resampler( temp_resampler_state, x_buf_API_fs_Hz, x_bufFIX, old_buf_samples );
+
+ /* Initialize the resampler for enc_API.c preparing resampling from API_fs_Hz to fs_kHz */
+ ret += silk_resampler_init( &psEnc->sCmn.resampler_state, psEnc->sCmn.API_fs_Hz, silk_SMULBB( fs_kHz, 1000 ), 1 );
+
+ /* Correct resampler state by resampling buffered data from API_fs_Hz to fs_kHz */
+ ret += silk_resampler( &psEnc->sCmn.resampler_state, x_bufFIX, x_buf_API_fs_Hz, api_buf_samples );
+
+#ifndef OPUS_FIXED_POINT
+ silk_short2float_array( psEnc->x_buf, x_bufFIX, new_buf_samples);
+#endif
+ }
+ }
+
+ psEnc->sCmn.prev_API_fs_Hz = psEnc->sCmn.API_fs_Hz;
+
+ RESTORE_STACK;
+ return ret;
+}
+
+static opus_int silk_setup_fs(
+ silk_encoder_state_Fxx *psEnc, /* I/O */
+ opus_int fs_kHz, /* I */
+ opus_int PacketSize_ms /* I */
+)
+{
+ opus_int ret = SILK_NO_ERROR;
+
+ /* Set packet size */
+ if( PacketSize_ms != psEnc->sCmn.PacketSize_ms ) {
+ if( ( PacketSize_ms != 10 ) &&
+ ( PacketSize_ms != 20 ) &&
+ ( PacketSize_ms != 40 ) &&
+ ( PacketSize_ms != 60 ) ) {
+ ret = SILK_ENC_PACKET_SIZE_NOT_SUPPORTED;
+ }
+ if( PacketSize_ms <= 10 ) {
+ psEnc->sCmn.nFramesPerPacket = 1;
+ psEnc->sCmn.nb_subfr = PacketSize_ms == 10 ? 2 : 1;
+ psEnc->sCmn.frame_length = silk_SMULBB( PacketSize_ms, fs_kHz );
+ psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS_2_SF, fs_kHz );
+ if( psEnc->sCmn.fs_kHz == 8 ) {
+ psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF;
+ } else {
+ psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF;
+ }
+ } else {
+ psEnc->sCmn.nFramesPerPacket = silk_DIV32_16( PacketSize_ms, MAX_FRAME_LENGTH_MS );
+ psEnc->sCmn.nb_subfr = MAX_NB_SUBFR;
+ psEnc->sCmn.frame_length = silk_SMULBB( 20, fs_kHz );
+ psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS, fs_kHz );
+ if( psEnc->sCmn.fs_kHz == 8 ) {
+ psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_NB_iCDF;
+ } else {
+ psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_iCDF;
+ }
+ }
+ psEnc->sCmn.PacketSize_ms = PacketSize_ms;
+ psEnc->sCmn.TargetRate_bps = 0; /* trigger new SNR computation */
+ }
+
+ /* Set internal sampling frequency */
+ silk_assert( fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16 );
+ silk_assert( psEnc->sCmn.nb_subfr == 2 || psEnc->sCmn.nb_subfr == 4 );
+ if( psEnc->sCmn.fs_kHz != fs_kHz ) {
+ /* reset part of the state */
+ silk_memset( &psEnc->sShape, 0, sizeof( psEnc->sShape ) );
+ silk_memset( &psEnc->sPrefilt, 0, sizeof( psEnc->sPrefilt ) );
+ silk_memset( &psEnc->sCmn.sNSQ, 0, sizeof( psEnc->sCmn.sNSQ ) );
+ silk_memset( psEnc->sCmn.prev_NLSFq_Q15, 0, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) );
+ silk_memset( &psEnc->sCmn.sLP.In_LP_State, 0, sizeof( psEnc->sCmn.sLP.In_LP_State ) );
+ psEnc->sCmn.inputBufIx = 0;
+ psEnc->sCmn.nFramesEncoded = 0;
+ psEnc->sCmn.TargetRate_bps = 0; /* trigger new SNR computation */
+
+ /* Initialize non-zero parameters */
+ psEnc->sCmn.prevLag = 100;
+ psEnc->sCmn.first_frame_after_reset = 1;
+ psEnc->sPrefilt.lagPrev = 100;
+ psEnc->sShape.LastGainIndex = 10;
+ psEnc->sCmn.sNSQ.lagPrev = 100;
+ psEnc->sCmn.sNSQ.prev_gain_Q16 = 65536;
+ psEnc->sCmn.prevSignalType = TYPE_NO_VOICE_ACTIVITY;
+
+ psEnc->sCmn.fs_kHz = fs_kHz;
+ if( psEnc->sCmn.fs_kHz == 8 ) {
+ if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) {
+ psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_NB_iCDF;
+ } else {
+ psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF;
+ }
+ } else {
+ if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) {
+ psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_iCDF;
+ } else {
+ psEnc->sCmn.pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF;
+ }
+ }
+ if( psEnc->sCmn.fs_kHz == 8 || psEnc->sCmn.fs_kHz == 12 ) {
+ psEnc->sCmn.predictLPCOrder = MIN_LPC_ORDER;
+ psEnc->sCmn.psNLSF_CB = &silk_NLSF_CB_NB_MB;
+ } else {
+ psEnc->sCmn.predictLPCOrder = MAX_LPC_ORDER;
+ psEnc->sCmn.psNLSF_CB = &silk_NLSF_CB_WB;
+ }
+ psEnc->sCmn.subfr_length = SUB_FRAME_LENGTH_MS * fs_kHz;
+ psEnc->sCmn.frame_length = silk_SMULBB( psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr );
+ psEnc->sCmn.ltp_mem_length = silk_SMULBB( LTP_MEM_LENGTH_MS, fs_kHz );
+ psEnc->sCmn.la_pitch = silk_SMULBB( LA_PITCH_MS, fs_kHz );
+ psEnc->sCmn.max_pitch_lag = silk_SMULBB( 18, fs_kHz );
+ if( psEnc->sCmn.nb_subfr == MAX_NB_SUBFR ) {
+ psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS, fs_kHz );
+ } else {
+ psEnc->sCmn.pitch_LPC_win_length = silk_SMULBB( FIND_PITCH_LPC_WIN_MS_2_SF, fs_kHz );
+ }
+ if( psEnc->sCmn.fs_kHz == 16 ) {
+ psEnc->sCmn.mu_LTP_Q9 = SILK_FIX_CONST( MU_LTP_QUANT_WB, 9 );
+ psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform8_iCDF;
+ } else if( psEnc->sCmn.fs_kHz == 12 ) {
+ psEnc->sCmn.mu_LTP_Q9 = SILK_FIX_CONST( MU_LTP_QUANT_MB, 9 );
+ psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform6_iCDF;
+ } else {
+ psEnc->sCmn.mu_LTP_Q9 = SILK_FIX_CONST( MU_LTP_QUANT_NB, 9 );
+ psEnc->sCmn.pitch_lag_low_bits_iCDF = silk_uniform4_iCDF;
+ }
+ }
+
+ /* Check that settings are valid */
+ silk_assert( ( psEnc->sCmn.subfr_length * psEnc->sCmn.nb_subfr ) == psEnc->sCmn.frame_length );
+
+ return ret;
+}
+
+static opus_int silk_setup_complexity(
+ silk_encoder_state *psEncC, /* I/O */
+ opus_int Complexity /* I */
+)
+{
+ opus_int ret = 0;
+
+ /* Set encoding complexity */
+ silk_assert( Complexity >= 0 && Complexity <= 10 );
+ if( Complexity < 2 ) {
+ psEncC->pitchEstimationComplexity = SILK_PE_MIN_COMPLEX;
+ psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.8, 16 );
+ psEncC->pitchEstimationLPCOrder = 6;
+ psEncC->shapingLPCOrder = 8;
+ psEncC->la_shape = 3 * psEncC->fs_kHz;
+ psEncC->nStatesDelayedDecision = 1;
+ psEncC->useInterpolatedNLSFs = 0;
+ psEncC->LTPQuantLowComplexity = 1;
+ psEncC->NLSF_MSVQ_Survivors = 2;
+ psEncC->warping_Q16 = 0;
+ } else if( Complexity < 4 ) {
+ psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX;
+ psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.76, 16 );
+ psEncC->pitchEstimationLPCOrder = 8;
+ psEncC->shapingLPCOrder = 10;
+ psEncC->la_shape = 5 * psEncC->fs_kHz;
+ psEncC->nStatesDelayedDecision = 1;
+ psEncC->useInterpolatedNLSFs = 0;
+ psEncC->LTPQuantLowComplexity = 0;
+ psEncC->NLSF_MSVQ_Survivors = 4;
+ psEncC->warping_Q16 = 0;
+ } else if( Complexity < 6 ) {
+ psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX;
+ psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.74, 16 );
+ psEncC->pitchEstimationLPCOrder = 10;
+ psEncC->shapingLPCOrder = 12;
+ psEncC->la_shape = 5 * psEncC->fs_kHz;
+ psEncC->nStatesDelayedDecision = 2;
+ psEncC->useInterpolatedNLSFs = 1;
+ psEncC->LTPQuantLowComplexity = 0;
+ psEncC->NLSF_MSVQ_Survivors = 8;
+ psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 );
+ } else if( Complexity < 8 ) {
+ psEncC->pitchEstimationComplexity = SILK_PE_MID_COMPLEX;
+ psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.72, 16 );
+ psEncC->pitchEstimationLPCOrder = 12;
+ psEncC->shapingLPCOrder = 14;
+ psEncC->la_shape = 5 * psEncC->fs_kHz;
+ psEncC->nStatesDelayedDecision = 3;
+ psEncC->useInterpolatedNLSFs = 1;
+ psEncC->LTPQuantLowComplexity = 0;
+ psEncC->NLSF_MSVQ_Survivors = 16;
+ psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 );
+ } else {
+ psEncC->pitchEstimationComplexity = SILK_PE_MAX_COMPLEX;
+ psEncC->pitchEstimationThreshold_Q16 = SILK_FIX_CONST( 0.7, 16 );
+ psEncC->pitchEstimationLPCOrder = 16;
+ psEncC->shapingLPCOrder = 16;
+ psEncC->la_shape = 5 * psEncC->fs_kHz;
+ psEncC->nStatesDelayedDecision = MAX_DEL_DEC_STATES;
+ psEncC->useInterpolatedNLSFs = 1;
+ psEncC->LTPQuantLowComplexity = 0;
+ psEncC->NLSF_MSVQ_Survivors = 32;
+ psEncC->warping_Q16 = psEncC->fs_kHz * SILK_FIX_CONST( WARPING_MULTIPLIER, 16 );
+ }
+
+ /* Do not allow higher pitch estimation LPC order than predict LPC order */
+ psEncC->pitchEstimationLPCOrder = silk_min_int( psEncC->pitchEstimationLPCOrder, psEncC->predictLPCOrder );
+ psEncC->shapeWinLength = SUB_FRAME_LENGTH_MS * psEncC->fs_kHz + 2 * psEncC->la_shape;
+ psEncC->Complexity = Complexity;
+
+ silk_assert( psEncC->pitchEstimationLPCOrder <= MAX_FIND_PITCH_LPC_ORDER );
+ silk_assert( psEncC->shapingLPCOrder <= MAX_SHAPE_LPC_ORDER );
+ silk_assert( psEncC->nStatesDelayedDecision <= MAX_DEL_DEC_STATES );
+ silk_assert( psEncC->warping_Q16 <= 32767 );
+ silk_assert( psEncC->la_shape <= LA_SHAPE_MAX );
+ silk_assert( psEncC->shapeWinLength <= SHAPE_LPC_WIN_MAX );
+ silk_assert( psEncC->NLSF_MSVQ_Survivors <= NLSF_VQ_MAX_SURVIVORS );
+
+ return ret;
+}
+
+static OPUS_INLINE opus_int silk_setup_LBRR(
+ silk_encoder_state *psEncC, /* I/O */
+ const opus_int32 TargetRate_bps /* I */
+)
+{
+ opus_int ret = SILK_NO_ERROR;
+ opus_int32 LBRR_rate_thres_bps;
+
+ psEncC->LBRR_enabled = 0;
+ if( psEncC->useInBandFEC && psEncC->PacketLoss_perc > 0 ) {
+ if( psEncC->fs_kHz == 8 ) {
+ LBRR_rate_thres_bps = LBRR_NB_MIN_RATE_BPS;
+ } else if( psEncC->fs_kHz == 12 ) {
+ LBRR_rate_thres_bps = LBRR_MB_MIN_RATE_BPS;
+ } else {
+ LBRR_rate_thres_bps = LBRR_WB_MIN_RATE_BPS;
+ }
+ LBRR_rate_thres_bps = silk_SMULWB( silk_MUL( LBRR_rate_thres_bps, 125 - silk_min( psEncC->PacketLoss_perc, 25 ) ), SILK_FIX_CONST( 0.01, 16 ) );
+
+ if( TargetRate_bps > LBRR_rate_thres_bps ) {
+ /* Set gain increase for coding LBRR excitation */
+ psEncC->LBRR_enabled = 1;
+ psEncC->LBRR_GainIncreases = silk_max_int( 7 - silk_SMULWB( (opus_int32)psEncC->PacketLoss_perc, SILK_FIX_CONST( 0.4, 16 ) ), 2 );
+ }
+ }
+
+ return ret;
+}
diff --git a/drivers/opus/silk/debug.c b/drivers/opus/silk/debug.c
new file mode 100644
index 0000000000..9f31b68f76
--- /dev/null
+++ b/drivers/opus/silk/debug.c
@@ -0,0 +1,170 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/debug.h"
+#include "opus/silk/SigProc_FIX.h"
+
+#if SILK_TIC_TOC
+
+#ifdef _WIN32
+
+#if (defined(_WIN32) || defined(_WINCE))
+#include <windows.h> /* timer */
+#else /* Linux or Mac*/
+#include <sys/time.h>
+#endif
+
+unsigned long silk_GetHighResolutionTime(void) /* O time in usec*/
+{
+ /* Returns a time counter in microsec */
+ /* the resolution is platform dependent */
+ /* but is typically 1.62 us resolution */
+ LARGE_INTEGER lpPerformanceCount;
+ LARGE_INTEGER lpFrequency;
+ QueryPerformanceCounter(&lpPerformanceCount);
+ QueryPerformanceFrequency(&lpFrequency);
+ return (unsigned long)((1000000*(lpPerformanceCount.QuadPart)) / lpFrequency.QuadPart);
+}
+#else /* Linux or Mac*/
+unsigned long GetHighResolutionTime(void) /* O time in usec*/
+{
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ return((tv.tv_sec*1000000)+(tv.tv_usec));
+}
+#endif
+
+int silk_Timer_nTimers = 0;
+int silk_Timer_depth_ctr = 0;
+char silk_Timer_tags[silk_NUM_TIMERS_MAX][silk_NUM_TIMERS_MAX_TAG_LEN];
+#ifdef WIN32
+LARGE_INTEGER silk_Timer_start[silk_NUM_TIMERS_MAX];
+#else
+unsigned long silk_Timer_start[silk_NUM_TIMERS_MAX];
+#endif
+unsigned int silk_Timer_cnt[silk_NUM_TIMERS_MAX];
+opus_int64 silk_Timer_min[silk_NUM_TIMERS_MAX];
+opus_int64 silk_Timer_sum[silk_NUM_TIMERS_MAX];
+opus_int64 silk_Timer_max[silk_NUM_TIMERS_MAX];
+opus_int64 silk_Timer_depth[silk_NUM_TIMERS_MAX];
+
+#ifdef WIN32
+void silk_TimerSave(char *file_name)
+{
+ if( silk_Timer_nTimers > 0 )
+ {
+ int k;
+ FILE *fp;
+ LARGE_INTEGER lpFrequency;
+ LARGE_INTEGER lpPerformanceCount1, lpPerformanceCount2;
+ int del = 0x7FFFFFFF;
+ double avg, sum_avg;
+ /* estimate overhead of calling performance counters */
+ for( k = 0; k < 1000; k++ ) {
+ QueryPerformanceCounter(&lpPerformanceCount1);
+ QueryPerformanceCounter(&lpPerformanceCount2);
+ lpPerformanceCount2.QuadPart -= lpPerformanceCount1.QuadPart;
+ if( (int)lpPerformanceCount2.LowPart < del )
+ del = lpPerformanceCount2.LowPart;
+ }
+ QueryPerformanceFrequency(&lpFrequency);
+ /* print results to file */
+ sum_avg = 0.0f;
+ for( k = 0; k < silk_Timer_nTimers; k++ ) {
+ if (silk_Timer_depth[k] == 0) {
+ sum_avg += (1e6 * silk_Timer_sum[k] / silk_Timer_cnt[k] - del) / lpFrequency.QuadPart * silk_Timer_cnt[k];
+ }
+ }
+ fp = fopen(file_name, "w");
+ fprintf(fp, " min avg %% max count\n");
+ for( k = 0; k < silk_Timer_nTimers; k++ ) {
+ if (silk_Timer_depth[k] == 0) {
+ fprintf(fp, "%-28s", silk_Timer_tags[k]);
+ } else if (silk_Timer_depth[k] == 1) {
+ fprintf(fp, " %-27s", silk_Timer_tags[k]);
+ } else if (silk_Timer_depth[k] == 2) {
+ fprintf(fp, " %-26s", silk_Timer_tags[k]);
+ } else if (silk_Timer_depth[k] == 3) {
+ fprintf(fp, " %-25s", silk_Timer_tags[k]);
+ } else {
+ fprintf(fp, " %-24s", silk_Timer_tags[k]);
+ }
+ avg = (1e6 * silk_Timer_sum[k] / silk_Timer_cnt[k] - del) / lpFrequency.QuadPart;
+ fprintf(fp, "%8.2f", (1e6 * (silk_max_64(silk_Timer_min[k] - del, 0))) / lpFrequency.QuadPart);
+ fprintf(fp, "%12.2f %6.2f", avg, 100.0 * avg / sum_avg * silk_Timer_cnt[k]);
+ fprintf(fp, "%12.2f", (1e6 * (silk_max_64(silk_Timer_max[k] - del, 0))) / lpFrequency.QuadPart);
+ fprintf(fp, "%10d\n", silk_Timer_cnt[k]);
+ }
+ fprintf(fp, " microseconds\n");
+ fclose(fp);
+ }
+}
+#else
+void silk_TimerSave(char *file_name)
+{
+ if( silk_Timer_nTimers > 0 )
+ {
+ int k;
+ FILE *fp;
+ /* print results to file */
+ fp = fopen(file_name, "w");
+ fprintf(fp, " min avg max count\n");
+ for( k = 0; k < silk_Timer_nTimers; k++ )
+ {
+ if (silk_Timer_depth[k] == 0) {
+ fprintf(fp, "%-28s", silk_Timer_tags[k]);
+ } else if (silk_Timer_depth[k] == 1) {
+ fprintf(fp, " %-27s", silk_Timer_tags[k]);
+ } else if (silk_Timer_depth[k] == 2) {
+ fprintf(fp, " %-26s", silk_Timer_tags[k]);
+ } else if (silk_Timer_depth[k] == 3) {
+ fprintf(fp, " %-25s", silk_Timer_tags[k]);
+ } else {
+ fprintf(fp, " %-24s", silk_Timer_tags[k]);
+ }
+ fprintf(fp, "%d ", silk_Timer_min[k]);
+ fprintf(fp, "%f ", (double)silk_Timer_sum[k] / (double)silk_Timer_cnt[k]);
+ fprintf(fp, "%d ", silk_Timer_max[k]);
+ fprintf(fp, "%10d\n", silk_Timer_cnt[k]);
+ }
+ fprintf(fp, " microseconds\n");
+ fclose(fp);
+ }
+}
+#endif
+
+#endif /* SILK_TIC_TOC */
+
+#if SILK_DEBUG
+FILE *silk_debug_store_fp[ silk_NUM_STORES_MAX ];
+int silk_debug_store_count = 0;
+#endif /* SILK_DEBUG */
+
diff --git a/drivers/opus/silk/debug.h b/drivers/opus/silk/debug.h
new file mode 100644
index 0000000000..d2eccfa1e4
--- /dev/null
+++ b/drivers/opus/silk/debug.h
@@ -0,0 +1,279 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_DEBUG_H
+#define SILK_DEBUG_H
+
+#include "opus/silk/typedef.h"
+#include <stdio.h> /* file writing */
+#include <string.h> /* strcpy, strcmp */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+unsigned long GetHighResolutionTime(void); /* O time in usec*/
+
+/* make SILK_DEBUG dependent on compiler's _DEBUG */
+#if defined _WIN32
+ #ifdef _DEBUG
+ #define SILK_DEBUG 1
+ #else
+ #define SILK_DEBUG 0
+ #endif
+
+ /* overrule the above */
+ #if 0
+ /* #define NO_ASSERTS*/
+ #undef SILK_DEBUG
+ #define SILK_DEBUG 1
+ #endif
+#else
+ #define SILK_DEBUG 0
+#endif
+
+/* Flag for using timers */
+#define SILK_TIC_TOC 0
+
+
+#if SILK_TIC_TOC
+
+#if (defined(_WIN32) || defined(_WINCE))
+#include <windows.h> /* timer */
+#else /* Linux or Mac*/
+#include <sys/time.h>
+#endif
+
+/*********************************/
+/* timer functions for profiling */
+/*********************************/
+/* example: */
+/* */
+/* TIC(LPC) */
+/* do_LPC(in_vec, order, acoef); // do LPC analysis */
+/* TOC(LPC) */
+/* */
+/* and call the following just before exiting (from main) */
+/* */
+/* silk_TimerSave("silk_TimingData.txt"); */
+/* */
+/* results are now in silk_TimingData.txt */
+
+void silk_TimerSave(char *file_name);
+
+/* max number of timers (in different locations) */
+#define silk_NUM_TIMERS_MAX 50
+/* max length of name tags in TIC(..), TOC(..) */
+#define silk_NUM_TIMERS_MAX_TAG_LEN 30
+
+extern int silk_Timer_nTimers;
+extern int silk_Timer_depth_ctr;
+extern char silk_Timer_tags[silk_NUM_TIMERS_MAX][silk_NUM_TIMERS_MAX_TAG_LEN];
+#ifdef _WIN32
+extern LARGE_INTEGER silk_Timer_start[silk_NUM_TIMERS_MAX];
+#else
+extern unsigned long silk_Timer_start[silk_NUM_TIMERS_MAX];
+#endif
+extern unsigned int silk_Timer_cnt[silk_NUM_TIMERS_MAX];
+extern opus_int64 silk_Timer_sum[silk_NUM_TIMERS_MAX];
+extern opus_int64 silk_Timer_max[silk_NUM_TIMERS_MAX];
+extern opus_int64 silk_Timer_min[silk_NUM_TIMERS_MAX];
+extern opus_int64 silk_Timer_depth[silk_NUM_TIMERS_MAX];
+
+/* WARNING: TIC()/TOC can measure only up to 0.1 seconds at a time */
+#ifdef _WIN32
+#define TIC(TAG_NAME) { \
+ static int init = 0; \
+ static int ID = -1; \
+ if( init == 0 ) \
+ { \
+ int k; \
+ init = 1; \
+ for( k = 0; k < silk_Timer_nTimers; k++ ) { \
+ if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \
+ ID = k; \
+ break; \
+ } \
+ } \
+ if (ID == -1) { \
+ ID = silk_Timer_nTimers; \
+ silk_Timer_nTimers++; \
+ silk_Timer_depth[ID] = silk_Timer_depth_ctr; \
+ strcpy(silk_Timer_tags[ID], #TAG_NAME); \
+ silk_Timer_cnt[ID] = 0; \
+ silk_Timer_sum[ID] = 0; \
+ silk_Timer_min[ID] = 0xFFFFFFFF; \
+ silk_Timer_max[ID] = 0; \
+ } \
+ } \
+ silk_Timer_depth_ctr++; \
+ QueryPerformanceCounter(&silk_Timer_start[ID]); \
+}
+#else
+#define TIC(TAG_NAME) { \
+ static int init = 0; \
+ static int ID = -1; \
+ if( init == 0 ) \
+ { \
+ int k; \
+ init = 1; \
+ for( k = 0; k < silk_Timer_nTimers; k++ ) { \
+ if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \
+ ID = k; \
+ break; \
+ } \
+ } \
+ if (ID == -1) { \
+ ID = silk_Timer_nTimers; \
+ silk_Timer_nTimers++; \
+ silk_Timer_depth[ID] = silk_Timer_depth_ctr; \
+ strcpy(silk_Timer_tags[ID], #TAG_NAME); \
+ silk_Timer_cnt[ID] = 0; \
+ silk_Timer_sum[ID] = 0; \
+ silk_Timer_min[ID] = 0xFFFFFFFF; \
+ silk_Timer_max[ID] = 0; \
+ } \
+ } \
+ silk_Timer_depth_ctr++; \
+ silk_Timer_start[ID] = GetHighResolutionTime(); \
+}
+#endif
+
+#ifdef _WIN32
+#define TOC(TAG_NAME) { \
+ LARGE_INTEGER lpPerformanceCount; \
+ static int init = 0; \
+ static int ID = 0; \
+ if( init == 0 ) \
+ { \
+ int k; \
+ init = 1; \
+ for( k = 0; k < silk_Timer_nTimers; k++ ) { \
+ if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \
+ ID = k; \
+ break; \
+ } \
+ } \
+ } \
+ QueryPerformanceCounter(&lpPerformanceCount); \
+ lpPerformanceCount.QuadPart -= silk_Timer_start[ID].QuadPart; \
+ if((lpPerformanceCount.QuadPart < 100000000) && \
+ (lpPerformanceCount.QuadPart >= 0)) { \
+ silk_Timer_cnt[ID]++; \
+ silk_Timer_sum[ID] += lpPerformanceCount.QuadPart; \
+ if( lpPerformanceCount.QuadPart > silk_Timer_max[ID] ) \
+ silk_Timer_max[ID] = lpPerformanceCount.QuadPart; \
+ if( lpPerformanceCount.QuadPart < silk_Timer_min[ID] ) \
+ silk_Timer_min[ID] = lpPerformanceCount.QuadPart; \
+ } \
+ silk_Timer_depth_ctr--; \
+}
+#else
+#define TOC(TAG_NAME) { \
+ unsigned long endTime; \
+ static int init = 0; \
+ static int ID = 0; \
+ if( init == 0 ) \
+ { \
+ int k; \
+ init = 1; \
+ for( k = 0; k < silk_Timer_nTimers; k++ ) { \
+ if( strcmp(silk_Timer_tags[k], #TAG_NAME) == 0 ) { \
+ ID = k; \
+ break; \
+ } \
+ } \
+ } \
+ endTime = GetHighResolutionTime(); \
+ endTime -= silk_Timer_start[ID]; \
+ if((endTime < 100000000) && \
+ (endTime >= 0)) { \
+ silk_Timer_cnt[ID]++; \
+ silk_Timer_sum[ID] += endTime; \
+ if( endTime > silk_Timer_max[ID] ) \
+ silk_Timer_max[ID] = endTime; \
+ if( endTime < silk_Timer_min[ID] ) \
+ silk_Timer_min[ID] = endTime; \
+ } \
+ silk_Timer_depth_ctr--; \
+}
+#endif
+
+#else /* SILK_TIC_TOC */
+
+/* define macros as empty strings */
+#define TIC(TAG_NAME)
+#define TOC(TAG_NAME)
+#define silk_TimerSave(FILE_NAME)
+
+#endif /* SILK_TIC_TOC */
+
+
+#if SILK_DEBUG
+/************************************/
+/* write data to file for debugging */
+/************************************/
+/* Example: DEBUG_STORE_DATA(testfile.pcm, &RIN[0], 160*sizeof(opus_int16)); */
+
+#define silk_NUM_STORES_MAX 100
+extern FILE *silk_debug_store_fp[ silk_NUM_STORES_MAX ];
+extern int silk_debug_store_count;
+
+/* Faster way of storing the data */
+#define DEBUG_STORE_DATA( FILE_NAME, DATA_PTR, N_BYTES ) { \
+ static opus_int init = 0, cnt = 0; \
+ static FILE **fp; \
+ if (init == 0) { \
+ init = 1; \
+ cnt = silk_debug_store_count++; \
+ silk_debug_store_fp[ cnt ] = fopen(#FILE_NAME, "wb"); \
+ } \
+ fwrite((DATA_PTR), (N_BYTES), 1, silk_debug_store_fp[ cnt ]); \
+}
+
+/* Call this at the end of main() */
+#define SILK_DEBUG_STORE_CLOSE_FILES { \
+ opus_int i; \
+ for( i = 0; i < silk_debug_store_count; i++ ) { \
+ fclose( silk_debug_store_fp[ i ] ); \
+ } \
+}
+
+#else /* SILK_DEBUG */
+
+/* define macros as empty strings */
+#define DEBUG_STORE_DATA(FILE_NAME, DATA_PTR, N_BYTES)
+#define SILK_DEBUG_STORE_CLOSE_FILES
+
+#endif /* SILK_DEBUG */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SILK_DEBUG_H */
diff --git a/drivers/opus/silk/dec_API.c b/drivers/opus/silk/dec_API.c
new file mode 100644
index 0000000000..43aeb4faff
--- /dev/null
+++ b/drivers/opus/silk/dec_API.c
@@ -0,0 +1,397 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+#include "opus/silk/API.h"
+#include "opus/silk/silk_main.h"
+#include "opus/celt/stack_alloc.h"
+
+/************************/
+/* Decoder Super Struct */
+/************************/
+typedef struct {
+ silk_decoder_state channel_state[ DECODER_NUM_CHANNELS ];
+ stereo_dec_state sStereo;
+ opus_int nChannelsAPI;
+ opus_int nChannelsInternal;
+ opus_int prev_decode_only_middle;
+} silk_decoder;
+
+/*********************/
+/* Decoder functions */
+/*********************/
+
+opus_int silk_Get_Decoder_Size( /* O Returns error code */
+ opus_int *decSizeBytes /* O Number of bytes in SILK decoder state */
+)
+{
+ opus_int ret = SILK_NO_ERROR;
+
+ *decSizeBytes = sizeof( silk_decoder );
+
+ return ret;
+}
+
+/* Reset decoder state */
+opus_int silk_InitDecoder( /* O Returns error code */
+ void *decState /* I/O State */
+)
+{
+ opus_int n, ret = SILK_NO_ERROR;
+ silk_decoder_state *channel_state = ((silk_decoder *)decState)->channel_state;
+
+ for( n = 0; n < DECODER_NUM_CHANNELS; n++ ) {
+ ret = silk_init_decoder( &channel_state[ n ] );
+ }
+ silk_memset(&((silk_decoder *)decState)->sStereo, 0, sizeof(((silk_decoder *)decState)->sStereo));
+ /* Not strictly needed, but it's cleaner that way */
+ ((silk_decoder *)decState)->prev_decode_only_middle = 0;
+
+ return ret;
+}
+
+/* Decode a frame */
+opus_int silk_Decode( /* O Returns error code */
+ void* decState, /* I/O State */
+ silk_DecControlStruct* decControl, /* I/O Control Structure */
+ opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */
+ opus_int newPacketFlag, /* I Indicates first decoder call for this packet */
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int16 *samplesOut, /* O Decoded output speech vector */
+ opus_int32 *nSamplesOut /* O Number of samples decoded */
+)
+{
+ opus_int i, n, decode_only_middle = 0, ret = SILK_NO_ERROR;
+ opus_int32 nSamplesOutDec, LBRR_symbol;
+ opus_int16 *samplesOut1_tmp[ 2 ];
+ VARDECL( opus_int16, samplesOut1_tmp_storage );
+ VARDECL( opus_int16, samplesOut2_tmp );
+ opus_int32 MS_pred_Q13[ 2 ] = { 0 };
+ opus_int16 *resample_out_ptr;
+ silk_decoder *psDec = ( silk_decoder * )decState;
+ silk_decoder_state *channel_state = psDec->channel_state;
+ opus_int has_side;
+ opus_int stereo_to_mono;
+ SAVE_STACK;
+
+ silk_assert( decControl->nChannelsInternal == 1 || decControl->nChannelsInternal == 2 );
+
+ /**********************************/
+ /* Test if first frame in payload */
+ /**********************************/
+ if( newPacketFlag ) {
+ for( n = 0; n < decControl->nChannelsInternal; n++ ) {
+ channel_state[ n ].nFramesDecoded = 0; /* Used to count frames in packet */
+ }
+ }
+
+ /* If Mono -> Stereo transition in bitstream: init state of second channel */
+ if( decControl->nChannelsInternal > psDec->nChannelsInternal ) {
+ ret += silk_init_decoder( &channel_state[ 1 ] );
+ }
+
+ stereo_to_mono = decControl->nChannelsInternal == 1 && psDec->nChannelsInternal == 2 &&
+ ( decControl->internalSampleRate == 1000*channel_state[ 0 ].fs_kHz );
+
+ if( channel_state[ 0 ].nFramesDecoded == 0 ) {
+ for( n = 0; n < decControl->nChannelsInternal; n++ ) {
+ opus_int fs_kHz_dec;
+ if( decControl->payloadSize_ms == 0 ) {
+ /* Assuming packet loss, use 10 ms */
+ channel_state[ n ].nFramesPerPacket = 1;
+ channel_state[ n ].nb_subfr = 2;
+ } else if( decControl->payloadSize_ms == 10 ) {
+ channel_state[ n ].nFramesPerPacket = 1;
+ channel_state[ n ].nb_subfr = 2;
+ } else if( decControl->payloadSize_ms == 20 ) {
+ channel_state[ n ].nFramesPerPacket = 1;
+ channel_state[ n ].nb_subfr = 4;
+ } else if( decControl->payloadSize_ms == 40 ) {
+ channel_state[ n ].nFramesPerPacket = 2;
+ channel_state[ n ].nb_subfr = 4;
+ } else if( decControl->payloadSize_ms == 60 ) {
+ channel_state[ n ].nFramesPerPacket = 3;
+ channel_state[ n ].nb_subfr = 4;
+ } else {
+ silk_assert( 0 );
+ RESTORE_STACK;
+ return SILK_DEC_INVALID_FRAME_SIZE;
+ }
+ fs_kHz_dec = ( decControl->internalSampleRate >> 10 ) + 1;
+ if( fs_kHz_dec != 8 && fs_kHz_dec != 12 && fs_kHz_dec != 16 ) {
+ silk_assert( 0 );
+ RESTORE_STACK;
+ return SILK_DEC_INVALID_SAMPLING_FREQUENCY;
+ }
+ ret += silk_decoder_set_fs( &channel_state[ n ], fs_kHz_dec, decControl->API_sampleRate );
+ }
+ }
+
+ if( decControl->nChannelsAPI == 2 && decControl->nChannelsInternal == 2 && ( psDec->nChannelsAPI == 1 || psDec->nChannelsInternal == 1 ) ) {
+ silk_memset( psDec->sStereo.pred_prev_Q13, 0, sizeof( psDec->sStereo.pred_prev_Q13 ) );
+ silk_memset( psDec->sStereo.sSide, 0, sizeof( psDec->sStereo.sSide ) );
+ silk_memcpy( &channel_state[ 1 ].resampler_state, &channel_state[ 0 ].resampler_state, sizeof( silk_resampler_state_struct ) );
+ }
+ psDec->nChannelsAPI = decControl->nChannelsAPI;
+ psDec->nChannelsInternal = decControl->nChannelsInternal;
+
+ if( decControl->API_sampleRate > (opus_int32)MAX_API_FS_KHZ * 1000 || decControl->API_sampleRate < 8000 ) {
+ ret = SILK_DEC_INVALID_SAMPLING_FREQUENCY;
+ RESTORE_STACK;
+ return( ret );
+ }
+
+ if( lostFlag != FLAG_PACKET_LOST && channel_state[ 0 ].nFramesDecoded == 0 ) {
+ /* First decoder call for this payload */
+ /* Decode VAD flags and LBRR flag */
+ for( n = 0; n < decControl->nChannelsInternal; n++ ) {
+ for( i = 0; i < channel_state[ n ].nFramesPerPacket; i++ ) {
+ channel_state[ n ].VAD_flags[ i ] = ec_dec_bit_logp(psRangeDec, 1);
+ }
+ channel_state[ n ].LBRR_flag = ec_dec_bit_logp(psRangeDec, 1);
+ }
+ /* Decode LBRR flags */
+ for( n = 0; n < decControl->nChannelsInternal; n++ ) {
+ silk_memset( channel_state[ n ].LBRR_flags, 0, sizeof( channel_state[ n ].LBRR_flags ) );
+ if( channel_state[ n ].LBRR_flag ) {
+ if( channel_state[ n ].nFramesPerPacket == 1 ) {
+ channel_state[ n ].LBRR_flags[ 0 ] = 1;
+ } else {
+ LBRR_symbol = ec_dec_icdf( psRangeDec, silk_LBRR_flags_iCDF_ptr[ channel_state[ n ].nFramesPerPacket - 2 ], 8 ) + 1;
+ for( i = 0; i < channel_state[ n ].nFramesPerPacket; i++ ) {
+ channel_state[ n ].LBRR_flags[ i ] = silk_RSHIFT( LBRR_symbol, i ) & 1;
+ }
+ }
+ }
+ }
+
+ if( lostFlag == FLAG_DECODE_NORMAL ) {
+ /* Regular decoding: skip all LBRR data */
+ for( i = 0; i < channel_state[ 0 ].nFramesPerPacket; i++ ) {
+ for( n = 0; n < decControl->nChannelsInternal; n++ ) {
+ if( channel_state[ n ].LBRR_flags[ i ] ) {
+ opus_int pulses[ MAX_FRAME_LENGTH ];
+ opus_int condCoding;
+
+ if( decControl->nChannelsInternal == 2 && n == 0 ) {
+ silk_stereo_decode_pred( psRangeDec, MS_pred_Q13 );
+ if( channel_state[ 1 ].LBRR_flags[ i ] == 0 ) {
+ silk_stereo_decode_mid_only( psRangeDec, &decode_only_middle );
+ }
+ }
+ /* Use conditional coding if previous frame available */
+ if( i > 0 && channel_state[ n ].LBRR_flags[ i - 1 ] ) {
+ condCoding = CODE_CONDITIONALLY;
+ } else {
+ condCoding = CODE_INDEPENDENTLY;
+ }
+ silk_decode_indices( &channel_state[ n ], psRangeDec, i, 1, condCoding );
+ silk_decode_pulses( psRangeDec, pulses, channel_state[ n ].indices.signalType,
+ channel_state[ n ].indices.quantOffsetType, channel_state[ n ].frame_length );
+ }
+ }
+ }
+ }
+ }
+
+ /* Get MS predictor index */
+ if( decControl->nChannelsInternal == 2 ) {
+ if( lostFlag == FLAG_DECODE_NORMAL ||
+ ( lostFlag == FLAG_DECODE_LBRR && channel_state[ 0 ].LBRR_flags[ channel_state[ 0 ].nFramesDecoded ] == 1 ) )
+ {
+ silk_stereo_decode_pred( psRangeDec, MS_pred_Q13 );
+ /* For LBRR data, decode mid-only flag only if side-channel's LBRR flag is false */
+ if( ( lostFlag == FLAG_DECODE_NORMAL && channel_state[ 1 ].VAD_flags[ channel_state[ 0 ].nFramesDecoded ] == 0 ) ||
+ ( lostFlag == FLAG_DECODE_LBRR && channel_state[ 1 ].LBRR_flags[ channel_state[ 0 ].nFramesDecoded ] == 0 ) )
+ {
+ silk_stereo_decode_mid_only( psRangeDec, &decode_only_middle );
+ } else {
+ decode_only_middle = 0;
+ }
+ } else {
+ for( n = 0; n < 2; n++ ) {
+ MS_pred_Q13[ n ] = psDec->sStereo.pred_prev_Q13[ n ];
+ }
+ }
+ }
+
+ /* Reset side channel decoder prediction memory for first frame with side coding */
+ if( decControl->nChannelsInternal == 2 && decode_only_middle == 0 && psDec->prev_decode_only_middle == 1 ) {
+ silk_memset( psDec->channel_state[ 1 ].outBuf, 0, sizeof(psDec->channel_state[ 1 ].outBuf) );
+ silk_memset( psDec->channel_state[ 1 ].sLPC_Q14_buf, 0, sizeof(psDec->channel_state[ 1 ].sLPC_Q14_buf) );
+ psDec->channel_state[ 1 ].lagPrev = 100;
+ psDec->channel_state[ 1 ].LastGainIndex = 10;
+ psDec->channel_state[ 1 ].prevSignalType = TYPE_NO_VOICE_ACTIVITY;
+ psDec->channel_state[ 1 ].first_frame_after_reset = 1;
+ }
+
+ ALLOC( samplesOut1_tmp_storage,
+ decControl->nChannelsInternal*(
+ channel_state[ 0 ].frame_length + 2 ),
+ opus_int16 );
+ samplesOut1_tmp[ 0 ] = samplesOut1_tmp_storage;
+ samplesOut1_tmp[ 1 ] = samplesOut1_tmp_storage
+ + channel_state[ 0 ].frame_length + 2;
+
+ if( lostFlag == FLAG_DECODE_NORMAL ) {
+ has_side = !decode_only_middle;
+ } else {
+ has_side = !psDec->prev_decode_only_middle
+ || (decControl->nChannelsInternal == 2 && lostFlag == FLAG_DECODE_LBRR && channel_state[1].LBRR_flags[ channel_state[1].nFramesDecoded ] == 1 );
+ }
+ /* Call decoder for one frame */
+ for( n = 0; n < decControl->nChannelsInternal; n++ ) {
+ if( n == 0 || has_side ) {
+ opus_int FrameIndex;
+ opus_int condCoding;
+
+ FrameIndex = channel_state[ 0 ].nFramesDecoded - n;
+ /* Use independent coding if no previous frame available */
+ if( FrameIndex <= 0 ) {
+ condCoding = CODE_INDEPENDENTLY;
+ } else if( lostFlag == FLAG_DECODE_LBRR ) {
+ condCoding = channel_state[ n ].LBRR_flags[ FrameIndex - 1 ] ? CODE_CONDITIONALLY : CODE_INDEPENDENTLY;
+ } else if( n > 0 && psDec->prev_decode_only_middle ) {
+ /* If we skipped a side frame in this packet, we don't
+ need LTP scaling; the LTP state is well-defined. */
+ condCoding = CODE_INDEPENDENTLY_NO_LTP_SCALING;
+ } else {
+ condCoding = CODE_CONDITIONALLY;
+ }
+ ret += silk_decode_frame( &channel_state[ n ], psRangeDec, &samplesOut1_tmp[ n ][ 2 ], &nSamplesOutDec, lostFlag, condCoding);
+ } else {
+ silk_memset( &samplesOut1_tmp[ n ][ 2 ], 0, nSamplesOutDec * sizeof( opus_int16 ) );
+ }
+ channel_state[ n ].nFramesDecoded++;
+ }
+
+ if( decControl->nChannelsAPI == 2 && decControl->nChannelsInternal == 2 ) {
+ /* Convert Mid/Side to Left/Right */
+ silk_stereo_MS_to_LR( &psDec->sStereo, samplesOut1_tmp[ 0 ], samplesOut1_tmp[ 1 ], MS_pred_Q13, channel_state[ 0 ].fs_kHz, nSamplesOutDec );
+ } else {
+ /* Buffering */
+ silk_memcpy( samplesOut1_tmp[ 0 ], psDec->sStereo.sMid, 2 * sizeof( opus_int16 ) );
+ silk_memcpy( psDec->sStereo.sMid, &samplesOut1_tmp[ 0 ][ nSamplesOutDec ], 2 * sizeof( opus_int16 ) );
+ }
+
+ /* Number of output samples */
+ *nSamplesOut = silk_DIV32( nSamplesOutDec * decControl->API_sampleRate, silk_SMULBB( channel_state[ 0 ].fs_kHz, 1000 ) );
+
+ /* Set up pointers to temp buffers */
+ ALLOC( samplesOut2_tmp,
+ decControl->nChannelsAPI == 2 ? *nSamplesOut : ALLOC_NONE, opus_int16 );
+ if( decControl->nChannelsAPI == 2 ) {
+ resample_out_ptr = samplesOut2_tmp;
+ } else {
+ resample_out_ptr = samplesOut;
+ }
+
+ for( n = 0; n < silk_min( decControl->nChannelsAPI, decControl->nChannelsInternal ); n++ ) {
+
+ /* Resample decoded signal to API_sampleRate */
+ ret += silk_resampler( &channel_state[ n ].resampler_state, resample_out_ptr, &samplesOut1_tmp[ n ][ 1 ], nSamplesOutDec );
+
+ /* Interleave if stereo output and stereo stream */
+ if( decControl->nChannelsAPI == 2 ) {
+ for( i = 0; i < *nSamplesOut; i++ ) {
+ samplesOut[ n + 2 * i ] = resample_out_ptr[ i ];
+ }
+ }
+ }
+
+ /* Create two channel output from mono stream */
+ if( decControl->nChannelsAPI == 2 && decControl->nChannelsInternal == 1 ) {
+ if ( stereo_to_mono ){
+ /* Resample right channel for newly collapsed stereo just in case
+ we weren't doing collapsing when switching to mono */
+ ret += silk_resampler( &channel_state[ 1 ].resampler_state, resample_out_ptr, &samplesOut1_tmp[ 0 ][ 1 ], nSamplesOutDec );
+
+ for( i = 0; i < *nSamplesOut; i++ ) {
+ samplesOut[ 1 + 2 * i ] = resample_out_ptr[ i ];
+ }
+ } else {
+ for( i = 0; i < *nSamplesOut; i++ ) {
+ samplesOut[ 1 + 2 * i ] = samplesOut[ 0 + 2 * i ];
+ }
+ }
+ }
+
+ /* Export pitch lag, measured at 48 kHz sampling rate */
+ if( channel_state[ 0 ].prevSignalType == TYPE_VOICED ) {
+ int mult_tab[ 3 ] = { 6, 4, 3 };
+ decControl->prevPitchLag = channel_state[ 0 ].lagPrev * mult_tab[ ( channel_state[ 0 ].fs_kHz - 8 ) >> 2 ];
+ } else {
+ decControl->prevPitchLag = 0;
+ }
+
+ if( lostFlag == FLAG_PACKET_LOST ) {
+ /* On packet loss, remove the gain clamping to prevent having the energy "bounce back"
+ if we lose packets when the energy is going down */
+ for ( i = 0; i < psDec->nChannelsInternal; i++ )
+ psDec->channel_state[ i ].LastGainIndex = 10;
+ } else {
+ psDec->prev_decode_only_middle = decode_only_middle;
+ }
+ RESTORE_STACK;
+ return ret;
+}
+
+#if 0
+/* Getting table of contents for a packet */
+opus_int silk_get_TOC(
+ const opus_uint8 *payload, /* I Payload data */
+ const opus_int nBytesIn, /* I Number of input bytes */
+ const opus_int nFramesPerPayload, /* I Number of SILK frames per payload */
+ silk_TOC_struct *Silk_TOC /* O Type of content */
+)
+{
+ opus_int i, flags, ret = SILK_NO_ERROR;
+
+ if( nBytesIn < 1 ) {
+ return -1;
+ }
+ if( nFramesPerPayload < 0 || nFramesPerPayload > 3 ) {
+ return -1;
+ }
+
+ silk_memset( Silk_TOC, 0, sizeof( *Silk_TOC ) );
+
+ /* For stereo, extract the flags for the mid channel */
+ flags = silk_RSHIFT( payload[ 0 ], 7 - nFramesPerPayload ) & ( silk_LSHIFT( 1, nFramesPerPayload + 1 ) - 1 );
+
+ Silk_TOC->inbandFECFlag = flags & 1;
+ for( i = nFramesPerPayload - 1; i >= 0 ; i-- ) {
+ flags = silk_RSHIFT( flags, 1 );
+ Silk_TOC->VADFlags[ i ] = flags & 1;
+ Silk_TOC->VADFlag |= flags & 1;
+ }
+
+ return ret;
+}
+#endif
diff --git a/drivers/opus/silk/decode_core.c b/drivers/opus/silk/decode_core.c
new file mode 100644
index 0000000000..f7cd8db7c9
--- /dev/null
+++ b/drivers/opus/silk/decode_core.c
@@ -0,0 +1,238 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+#include "opus/celt/stack_alloc.h"
+
+/**********************************************************/
+/* Core decoder. Performs inverse NSQ operation LTP + LPC */
+/**********************************************************/
+void silk_decode_core(
+ silk_decoder_state *psDec, /* I/O Decoder state */
+ silk_decoder_control *psDecCtrl, /* I Decoder control */
+ opus_int16 xq[], /* O Decoded speech */
+ const opus_int pulses[ MAX_FRAME_LENGTH ] /* I Pulse signal */
+)
+{
+ opus_int i, k, lag = 0, start_idx, sLTP_buf_idx, NLSF_interpolation_flag, signalType;
+ opus_int16 *A_Q12, *B_Q14, *pxq, A_Q12_tmp[ MAX_LPC_ORDER ];
+ VARDECL( opus_int16, sLTP );
+ VARDECL( opus_int32, sLTP_Q15 );
+ opus_int32 LTP_pred_Q13, LPC_pred_Q10, Gain_Q10, inv_gain_Q31, gain_adj_Q16, rand_seed, offset_Q10;
+ opus_int32 *pred_lag_ptr, *pexc_Q14, *pres_Q14;
+ VARDECL( opus_int32, res_Q14 );
+ VARDECL( opus_int32, sLPC_Q14 );
+ SAVE_STACK;
+
+ silk_assert( psDec->prev_gain_Q16 != 0 );
+
+ ALLOC( sLTP, psDec->ltp_mem_length, opus_int16 );
+ ALLOC( sLTP_Q15, psDec->ltp_mem_length + psDec->frame_length, opus_int32 );
+ ALLOC( res_Q14, psDec->subfr_length, opus_int32 );
+ ALLOC( sLPC_Q14, psDec->subfr_length + MAX_LPC_ORDER, opus_int32 );
+
+ offset_Q10 = silk_Quantization_Offsets_Q10[ psDec->indices.signalType >> 1 ][ psDec->indices.quantOffsetType ];
+
+ if( psDec->indices.NLSFInterpCoef_Q2 < 1 << 2 ) {
+ NLSF_interpolation_flag = 1;
+ } else {
+ NLSF_interpolation_flag = 0;
+ }
+
+ /* Decode excitation */
+ rand_seed = psDec->indices.Seed;
+ for( i = 0; i < psDec->frame_length; i++ ) {
+ rand_seed = silk_RAND( rand_seed );
+ psDec->exc_Q14[ i ] = silk_LSHIFT( (opus_int32)pulses[ i ], 14 );
+ if( psDec->exc_Q14[ i ] > 0 ) {
+ psDec->exc_Q14[ i ] -= QUANT_LEVEL_ADJUST_Q10 << 4;
+ } else
+ if( psDec->exc_Q14[ i ] < 0 ) {
+ psDec->exc_Q14[ i ] += QUANT_LEVEL_ADJUST_Q10 << 4;
+ }
+ psDec->exc_Q14[ i ] += offset_Q10 << 4;
+ if( rand_seed < 0 ) {
+ psDec->exc_Q14[ i ] = -psDec->exc_Q14[ i ];
+ }
+
+ rand_seed = silk_ADD32_ovflw( rand_seed, pulses[ i ] );
+ }
+
+ /* Copy LPC state */
+ silk_memcpy( sLPC_Q14, psDec->sLPC_Q14_buf, MAX_LPC_ORDER * sizeof( opus_int32 ) );
+
+ pexc_Q14 = psDec->exc_Q14;
+ pxq = xq;
+ sLTP_buf_idx = psDec->ltp_mem_length;
+ /* Loop over subframes */
+ for( k = 0; k < psDec->nb_subfr; k++ ) {
+ pres_Q14 = res_Q14;
+ A_Q12 = psDecCtrl->PredCoef_Q12[ k >> 1 ];
+
+ /* Preload LPC coeficients to array on stack. Gives small performance gain */
+ silk_memcpy( A_Q12_tmp, A_Q12, psDec->LPC_order * sizeof( opus_int16 ) );
+ B_Q14 = &psDecCtrl->LTPCoef_Q14[ k * LTP_ORDER ];
+ signalType = psDec->indices.signalType;
+
+ Gain_Q10 = silk_RSHIFT( psDecCtrl->Gains_Q16[ k ], 6 );
+ inv_gain_Q31 = silk_INVERSE32_varQ( psDecCtrl->Gains_Q16[ k ], 47 );
+
+ /* Calculate gain adjustment factor */
+ if( psDecCtrl->Gains_Q16[ k ] != psDec->prev_gain_Q16 ) {
+ gain_adj_Q16 = silk_DIV32_varQ( psDec->prev_gain_Q16, psDecCtrl->Gains_Q16[ k ], 16 );
+
+ /* Scale short term state */
+ for( i = 0; i < MAX_LPC_ORDER; i++ ) {
+ sLPC_Q14[ i ] = silk_SMULWW( gain_adj_Q16, sLPC_Q14[ i ] );
+ }
+ } else {
+ gain_adj_Q16 = (opus_int32)1 << 16;
+ }
+
+ /* Save inv_gain */
+ silk_assert( inv_gain_Q31 != 0 );
+ psDec->prev_gain_Q16 = psDecCtrl->Gains_Q16[ k ];
+
+ /* Avoid abrupt transition from voiced PLC to unvoiced normal decoding */
+ if( psDec->lossCnt && psDec->prevSignalType == TYPE_VOICED &&
+ psDec->indices.signalType != TYPE_VOICED && k < MAX_NB_SUBFR/2 ) {
+
+ silk_memset( B_Q14, 0, LTP_ORDER * sizeof( opus_int16 ) );
+ B_Q14[ LTP_ORDER/2 ] = SILK_FIX_CONST( 0.25, 14 );
+
+ signalType = TYPE_VOICED;
+ psDecCtrl->pitchL[ k ] = psDec->lagPrev;
+ }
+
+ if( signalType == TYPE_VOICED ) {
+ /* Voiced */
+ lag = psDecCtrl->pitchL[ k ];
+
+ /* Re-whitening */
+ if( k == 0 || ( k == 2 && NLSF_interpolation_flag ) ) {
+ /* Rewhiten with new A coefs */
+ start_idx = psDec->ltp_mem_length - lag - psDec->LPC_order - LTP_ORDER / 2;
+ silk_assert( start_idx > 0 );
+
+ if( k == 2 ) {
+ silk_memcpy( &psDec->outBuf[ psDec->ltp_mem_length ], xq, 2 * psDec->subfr_length * sizeof( opus_int16 ) );
+ }
+
+ silk_LPC_analysis_filter( &sLTP[ start_idx ], &psDec->outBuf[ start_idx + k * psDec->subfr_length ],
+ A_Q12, psDec->ltp_mem_length - start_idx, psDec->LPC_order );
+
+ /* After rewhitening the LTP state is unscaled */
+ if( k == 0 ) {
+ /* Do LTP downscaling to reduce inter-packet dependency */
+ inv_gain_Q31 = silk_LSHIFT( silk_SMULWB( inv_gain_Q31, psDecCtrl->LTP_scale_Q14 ), 2 );
+ }
+ for( i = 0; i < lag + LTP_ORDER/2; i++ ) {
+ sLTP_Q15[ sLTP_buf_idx - i - 1 ] = silk_SMULWB( inv_gain_Q31, sLTP[ psDec->ltp_mem_length - i - 1 ] );
+ }
+ } else {
+ /* Update LTP state when Gain changes */
+ if( gain_adj_Q16 != (opus_int32)1 << 16 ) {
+ for( i = 0; i < lag + LTP_ORDER/2; i++ ) {
+ sLTP_Q15[ sLTP_buf_idx - i - 1 ] = silk_SMULWW( gain_adj_Q16, sLTP_Q15[ sLTP_buf_idx - i - 1 ] );
+ }
+ }
+ }
+ }
+
+ /* Long-term prediction */
+ if( signalType == TYPE_VOICED ) {
+ /* Set up pointer */
+ pred_lag_ptr = &sLTP_Q15[ sLTP_buf_idx - lag + LTP_ORDER / 2 ];
+ for( i = 0; i < psDec->subfr_length; i++ ) {
+ /* Unrolled loop */
+ /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+ LTP_pred_Q13 = 2;
+ LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ 0 ], B_Q14[ 0 ] );
+ LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -1 ], B_Q14[ 1 ] );
+ LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -2 ], B_Q14[ 2 ] );
+ LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -3 ], B_Q14[ 3 ] );
+ LTP_pred_Q13 = silk_SMLAWB( LTP_pred_Q13, pred_lag_ptr[ -4 ], B_Q14[ 4 ] );
+ pred_lag_ptr++;
+
+ /* Generate LPC excitation */
+ pres_Q14[ i ] = silk_ADD_LSHIFT32( pexc_Q14[ i ], LTP_pred_Q13, 1 );
+
+ /* Update states */
+ sLTP_Q15[ sLTP_buf_idx ] = silk_LSHIFT( pres_Q14[ i ], 1 );
+ sLTP_buf_idx++;
+ }
+ } else {
+ pres_Q14 = pexc_Q14;
+ }
+
+ for( i = 0; i < psDec->subfr_length; i++ ) {
+ /* Short-term prediction */
+ silk_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 );
+ /* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
+ LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 1 ], A_Q12_tmp[ 0 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 2 ], A_Q12_tmp[ 1 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 3 ], A_Q12_tmp[ 2 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 4 ], A_Q12_tmp[ 3 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 5 ], A_Q12_tmp[ 4 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 6 ], A_Q12_tmp[ 5 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 7 ], A_Q12_tmp[ 6 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 8 ], A_Q12_tmp[ 7 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 9 ], A_Q12_tmp[ 8 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 10 ], A_Q12_tmp[ 9 ] );
+ if( psDec->LPC_order == 16 ) {
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 11 ], A_Q12_tmp[ 10 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 12 ], A_Q12_tmp[ 11 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 13 ], A_Q12_tmp[ 12 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 14 ], A_Q12_tmp[ 13 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 15 ], A_Q12_tmp[ 14 ] );
+ LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, sLPC_Q14[ MAX_LPC_ORDER + i - 16 ], A_Q12_tmp[ 15 ] );
+ }
+
+ /* Add prediction to LPC excitation */
+ sLPC_Q14[ MAX_LPC_ORDER + i ] = silk_ADD_LSHIFT32( pres_Q14[ i ], LPC_pred_Q10, 4 );
+
+ /* Scale with gain */
+ pxq[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( sLPC_Q14[ MAX_LPC_ORDER + i ], Gain_Q10 ), 8 ) );
+ }
+
+ /* DEBUG_STORE_DATA( dec.pcm, pxq, psDec->subfr_length * sizeof( opus_int16 ) ) */
+
+ /* Update LPC filter state */
+ silk_memcpy( sLPC_Q14, &sLPC_Q14[ psDec->subfr_length ], MAX_LPC_ORDER * sizeof( opus_int32 ) );
+ pexc_Q14 += psDec->subfr_length;
+ pxq += psDec->subfr_length;
+ }
+
+ /* Save LPC state */
+ silk_memcpy( psDec->sLPC_Q14_buf, sLPC_Q14, MAX_LPC_ORDER * sizeof( opus_int32 ) );
+ RESTORE_STACK;
+}
diff --git a/drivers/opus/silk/decode_frame.c b/drivers/opus/silk/decode_frame.c
new file mode 100644
index 0000000000..f166019455
--- /dev/null
+++ b/drivers/opus/silk/decode_frame.c
@@ -0,0 +1,128 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+#include "opus/celt/stack_alloc.h"
+#include "opus/silk/PLC.h"
+
+/****************/
+/* Decode frame */
+/****************/
+opus_int silk_decode_frame(
+ silk_decoder_state *psDec, /* I/O Pointer to Silk decoder state */
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int16 pOut[], /* O Pointer to output speech frame */
+ opus_int32 *pN, /* O Pointer to size of output frame */
+ opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */
+ opus_int condCoding /* I The type of conditional coding to use */
+)
+{
+ VARDECL( silk_decoder_control, psDecCtrl );
+ opus_int L, mv_len, ret = 0;
+ VARDECL( opus_int, pulses );
+ SAVE_STACK;
+
+ L = psDec->frame_length;
+ ALLOC( psDecCtrl, 1, silk_decoder_control );
+ ALLOC( pulses, (L + SHELL_CODEC_FRAME_LENGTH - 1) &
+ ~(SHELL_CODEC_FRAME_LENGTH - 1), opus_int );
+ psDecCtrl->LTP_scale_Q14 = 0;
+
+ /* Safety checks */
+ silk_assert( L > 0 && L <= MAX_FRAME_LENGTH );
+
+ if( lostFlag == FLAG_DECODE_NORMAL ||
+ ( lostFlag == FLAG_DECODE_LBRR && psDec->LBRR_flags[ psDec->nFramesDecoded ] == 1 ) )
+ {
+ /*********************************************/
+ /* Decode quantization indices of side info */
+ /*********************************************/
+ silk_decode_indices( psDec, psRangeDec, psDec->nFramesDecoded, lostFlag, condCoding );
+
+ /*********************************************/
+ /* Decode quantization indices of excitation */
+ /*********************************************/
+ silk_decode_pulses( psRangeDec, pulses, psDec->indices.signalType,
+ psDec->indices.quantOffsetType, psDec->frame_length );
+
+ /********************************************/
+ /* Decode parameters and pulse signal */
+ /********************************************/
+ silk_decode_parameters( psDec, psDecCtrl, condCoding );
+
+ /********************************************************/
+ /* Run inverse NSQ */
+ /********************************************************/
+ silk_decode_core( psDec, psDecCtrl, pOut, pulses );
+
+ /********************************************************/
+ /* Update PLC state */
+ /********************************************************/
+ silk_PLC( psDec, psDecCtrl, pOut, 0 );
+
+ psDec->lossCnt = 0;
+ psDec->prevSignalType = psDec->indices.signalType;
+ silk_assert( psDec->prevSignalType >= 0 && psDec->prevSignalType <= 2 );
+
+ /* A frame has been decoded without errors */
+ psDec->first_frame_after_reset = 0;
+ } else {
+ /* Handle packet loss by extrapolation */
+ silk_PLC( psDec, psDecCtrl, pOut, 1 );
+ }
+
+ /*************************/
+ /* Update output buffer. */
+ /*************************/
+ silk_assert( psDec->ltp_mem_length >= psDec->frame_length );
+ mv_len = psDec->ltp_mem_length - psDec->frame_length;
+ silk_memmove( psDec->outBuf, &psDec->outBuf[ psDec->frame_length ], mv_len * sizeof(opus_int16) );
+ silk_memcpy( &psDec->outBuf[ mv_len ], pOut, psDec->frame_length * sizeof( opus_int16 ) );
+
+ /****************************************************************/
+ /* Ensure smooth connection of extrapolated and good frames */
+ /****************************************************************/
+ silk_PLC_glue_frames( psDec, pOut, L );
+
+ /************************************************/
+ /* Comfort noise generation / estimation */
+ /************************************************/
+ silk_CNG( psDec, psDecCtrl, pOut, L );
+
+ /* Update some decoder state variables */
+ psDec->lagPrev = psDecCtrl->pitchL[ psDec->nb_subfr - 1 ];
+
+ /* Set output frame length */
+ *pN = L;
+
+ RESTORE_STACK;
+ return ret;
+}
diff --git a/drivers/opus/silk/decode_indices.c b/drivers/opus/silk/decode_indices.c
new file mode 100644
index 0000000000..3e09fb416b
--- /dev/null
+++ b/drivers/opus/silk/decode_indices.c
@@ -0,0 +1,151 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+
+/* Decode side-information parameters from payload */
+void silk_decode_indices(
+ silk_decoder_state *psDec, /* I/O State */
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int FrameIndex, /* I Frame number */
+ opus_int decode_LBRR, /* I Flag indicating LBRR data is being decoded */
+ opus_int condCoding /* I The type of conditional coding to use */
+)
+{
+ opus_int i, k, Ix;
+ opus_int decode_absolute_lagIndex, delta_lagIndex;
+ opus_int16 ec_ix[ MAX_LPC_ORDER ];
+ opus_uint8 pred_Q8[ MAX_LPC_ORDER ];
+
+ /*******************************************/
+ /* Decode signal type and quantizer offset */
+ /*******************************************/
+ if( decode_LBRR || psDec->VAD_flags[ FrameIndex ] ) {
+ Ix = ec_dec_icdf( psRangeDec, silk_type_offset_VAD_iCDF, 8 ) + 2;
+ } else {
+ Ix = ec_dec_icdf( psRangeDec, silk_type_offset_no_VAD_iCDF, 8 );
+ }
+ psDec->indices.signalType = (opus_int8)silk_RSHIFT( Ix, 1 );
+ psDec->indices.quantOffsetType = (opus_int8)( Ix & 1 );
+
+ /****************/
+ /* Decode gains */
+ /****************/
+ /* First subframe */
+ if( condCoding == CODE_CONDITIONALLY ) {
+ /* Conditional coding */
+ psDec->indices.GainsIndices[ 0 ] = (opus_int8)ec_dec_icdf( psRangeDec, silk_delta_gain_iCDF, 8 );
+ } else {
+ /* Independent coding, in two stages: MSB bits followed by 3 LSBs */
+ psDec->indices.GainsIndices[ 0 ] = (opus_int8)silk_LSHIFT( ec_dec_icdf( psRangeDec, silk_gain_iCDF[ psDec->indices.signalType ], 8 ), 3 );
+ psDec->indices.GainsIndices[ 0 ] += (opus_int8)ec_dec_icdf( psRangeDec, silk_uniform8_iCDF, 8 );
+ }
+
+ /* Remaining subframes */
+ for( i = 1; i < psDec->nb_subfr; i++ ) {
+ psDec->indices.GainsIndices[ i ] = (opus_int8)ec_dec_icdf( psRangeDec, silk_delta_gain_iCDF, 8 );
+ }
+
+ /**********************/
+ /* Decode LSF Indices */
+ /**********************/
+ psDec->indices.NLSFIndices[ 0 ] = (opus_int8)ec_dec_icdf( psRangeDec, &psDec->psNLSF_CB->CB1_iCDF[ ( psDec->indices.signalType >> 1 ) * psDec->psNLSF_CB->nVectors ], 8 );
+ silk_NLSF_unpack( ec_ix, pred_Q8, psDec->psNLSF_CB, psDec->indices.NLSFIndices[ 0 ] );
+ silk_assert( psDec->psNLSF_CB->order == psDec->LPC_order );
+ for( i = 0; i < psDec->psNLSF_CB->order; i++ ) {
+ Ix = ec_dec_icdf( psRangeDec, &psDec->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 );
+ if( Ix == 0 ) {
+ Ix -= ec_dec_icdf( psRangeDec, silk_NLSF_EXT_iCDF, 8 );
+ } else if( Ix == 2 * NLSF_QUANT_MAX_AMPLITUDE ) {
+ Ix += ec_dec_icdf( psRangeDec, silk_NLSF_EXT_iCDF, 8 );
+ }
+ psDec->indices.NLSFIndices[ i+1 ] = (opus_int8)( Ix - NLSF_QUANT_MAX_AMPLITUDE );
+ }
+
+ /* Decode LSF interpolation factor */
+ if( psDec->nb_subfr == MAX_NB_SUBFR ) {
+ psDec->indices.NLSFInterpCoef_Q2 = (opus_int8)ec_dec_icdf( psRangeDec, silk_NLSF_interpolation_factor_iCDF, 8 );
+ } else {
+ psDec->indices.NLSFInterpCoef_Q2 = 4;
+ }
+
+ if( psDec->indices.signalType == TYPE_VOICED )
+ {
+ /*********************/
+ /* Decode pitch lags */
+ /*********************/
+ /* Get lag index */
+ decode_absolute_lagIndex = 1;
+ if( condCoding == CODE_CONDITIONALLY && psDec->ec_prevSignalType == TYPE_VOICED ) {
+ /* Decode Delta index */
+ delta_lagIndex = (opus_int16)ec_dec_icdf( psRangeDec, silk_pitch_delta_iCDF, 8 );
+ if( delta_lagIndex > 0 ) {
+ delta_lagIndex = delta_lagIndex - 9;
+ psDec->indices.lagIndex = (opus_int16)( psDec->ec_prevLagIndex + delta_lagIndex );
+ decode_absolute_lagIndex = 0;
+ }
+ }
+ if( decode_absolute_lagIndex ) {
+ /* Absolute decoding */
+ psDec->indices.lagIndex = (opus_int16)ec_dec_icdf( psRangeDec, silk_pitch_lag_iCDF, 8 ) * silk_RSHIFT( psDec->fs_kHz, 1 );
+ psDec->indices.lagIndex += (opus_int16)ec_dec_icdf( psRangeDec, psDec->pitch_lag_low_bits_iCDF, 8 );
+ }
+ psDec->ec_prevLagIndex = psDec->indices.lagIndex;
+
+ /* Get countour index */
+ psDec->indices.contourIndex = (opus_int8)ec_dec_icdf( psRangeDec, psDec->pitch_contour_iCDF, 8 );
+
+ /********************/
+ /* Decode LTP gains */
+ /********************/
+ /* Decode PERIndex value */
+ psDec->indices.PERIndex = (opus_int8)ec_dec_icdf( psRangeDec, silk_LTP_per_index_iCDF, 8 );
+
+ for( k = 0; k < psDec->nb_subfr; k++ ) {
+ psDec->indices.LTPIndex[ k ] = (opus_int8)ec_dec_icdf( psRangeDec, silk_LTP_gain_iCDF_ptrs[ psDec->indices.PERIndex ], 8 );
+ }
+
+ /**********************/
+ /* Decode LTP scaling */
+ /**********************/
+ if( condCoding == CODE_INDEPENDENTLY ) {
+ psDec->indices.LTP_scaleIndex = (opus_int8)ec_dec_icdf( psRangeDec, silk_LTPscale_iCDF, 8 );
+ } else {
+ psDec->indices.LTP_scaleIndex = 0;
+ }
+ }
+ psDec->ec_prevSignalType = psDec->indices.signalType;
+
+ /***************/
+ /* Decode seed */
+ /***************/
+ psDec->indices.Seed = (opus_int8)ec_dec_icdf( psRangeDec, silk_uniform4_iCDF, 8 );
+}
diff --git a/drivers/opus/silk/decode_parameters.c b/drivers/opus/silk/decode_parameters.c
new file mode 100644
index 0000000000..7f4cbeec29
--- /dev/null
+++ b/drivers/opus/silk/decode_parameters.c
@@ -0,0 +1,115 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+
+/* Decode parameters from payload */
+void silk_decode_parameters(
+ silk_decoder_state *psDec, /* I/O State */
+ silk_decoder_control *psDecCtrl, /* I/O Decoder control */
+ opus_int condCoding /* I The type of conditional coding to use */
+)
+{
+ opus_int i, k, Ix;
+ opus_int16 pNLSF_Q15[ MAX_LPC_ORDER ], pNLSF0_Q15[ MAX_LPC_ORDER ];
+ const opus_int8 *cbk_ptr_Q7;
+
+ /* Dequant Gains */
+ silk_gains_dequant( psDecCtrl->Gains_Q16, psDec->indices.GainsIndices,
+ &psDec->LastGainIndex, condCoding == CODE_CONDITIONALLY, psDec->nb_subfr );
+
+ /****************/
+ /* Decode NLSFs */
+ /****************/
+ silk_NLSF_decode( pNLSF_Q15, psDec->indices.NLSFIndices, psDec->psNLSF_CB );
+
+ /* Convert NLSF parameters to AR prediction filter coefficients */
+ silk_NLSF2A( psDecCtrl->PredCoef_Q12[ 1 ], pNLSF_Q15, psDec->LPC_order );
+
+ /* If just reset, e.g., because internal Fs changed, do not allow interpolation */
+ /* improves the case of packet loss in the first frame after a switch */
+ if( psDec->first_frame_after_reset == 1 ) {
+ psDec->indices.NLSFInterpCoef_Q2 = 4;
+ }
+
+ if( psDec->indices.NLSFInterpCoef_Q2 < 4 ) {
+ /* Calculation of the interpolated NLSF0 vector from the interpolation factor, */
+ /* the previous NLSF1, and the current NLSF1 */
+ for( i = 0; i < psDec->LPC_order; i++ ) {
+ pNLSF0_Q15[ i ] = psDec->prevNLSF_Q15[ i ] + silk_RSHIFT( silk_MUL( psDec->indices.NLSFInterpCoef_Q2,
+ pNLSF_Q15[ i ] - psDec->prevNLSF_Q15[ i ] ), 2 );
+ }
+
+ /* Convert NLSF parameters to AR prediction filter coefficients */
+ silk_NLSF2A( psDecCtrl->PredCoef_Q12[ 0 ], pNLSF0_Q15, psDec->LPC_order );
+ } else {
+ /* Copy LPC coefficients for first half from second half */
+ silk_memcpy( psDecCtrl->PredCoef_Q12[ 0 ], psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order * sizeof( opus_int16 ) );
+ }
+
+ silk_memcpy( psDec->prevNLSF_Q15, pNLSF_Q15, psDec->LPC_order * sizeof( opus_int16 ) );
+
+ /* After a packet loss do BWE of LPC coefs */
+ if( psDec->lossCnt ) {
+ silk_bwexpander( psDecCtrl->PredCoef_Q12[ 0 ], psDec->LPC_order, BWE_AFTER_LOSS_Q16 );
+ silk_bwexpander( psDecCtrl->PredCoef_Q12[ 1 ], psDec->LPC_order, BWE_AFTER_LOSS_Q16 );
+ }
+
+ if( psDec->indices.signalType == TYPE_VOICED ) {
+ /*********************/
+ /* Decode pitch lags */
+ /*********************/
+
+ /* Decode pitch values */
+ silk_decode_pitch( psDec->indices.lagIndex, psDec->indices.contourIndex, psDecCtrl->pitchL, psDec->fs_kHz, psDec->nb_subfr );
+
+ /* Decode Codebook Index */
+ cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ psDec->indices.PERIndex ]; /* set pointer to start of codebook */
+
+ for( k = 0; k < psDec->nb_subfr; k++ ) {
+ Ix = psDec->indices.LTPIndex[ k ];
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ psDecCtrl->LTPCoef_Q14[ k * LTP_ORDER + i ] = silk_LSHIFT( cbk_ptr_Q7[ Ix * LTP_ORDER + i ], 7 );
+ }
+ }
+
+ /**********************/
+ /* Decode LTP scaling */
+ /**********************/
+ Ix = psDec->indices.LTP_scaleIndex;
+ psDecCtrl->LTP_scale_Q14 = silk_LTPScales_table_Q14[ Ix ];
+ } else {
+ silk_memset( psDecCtrl->pitchL, 0, psDec->nb_subfr * sizeof( opus_int ) );
+ silk_memset( psDecCtrl->LTPCoef_Q14, 0, LTP_ORDER * psDec->nb_subfr * sizeof( opus_int16 ) );
+ psDec->indices.PERIndex = 0;
+ psDecCtrl->LTP_scale_Q14 = 0;
+ }
+}
diff --git a/drivers/opus/silk/decode_pitch.c b/drivers/opus/silk/decode_pitch.c
new file mode 100644
index 0000000000..73e94b4ee2
--- /dev/null
+++ b/drivers/opus/silk/decode_pitch.c
@@ -0,0 +1,77 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+/***********************************************************
+* Pitch analyser function
+********************************************************** */
+#include "opus/silk/SigProc_FIX.h"
+#include "opus/silk/pitch_est_defines.h"
+
+void silk_decode_pitch(
+ opus_int16 lagIndex, /* I */
+ opus_int8 contourIndex, /* O */
+ opus_int pitch_lags[], /* O 4 pitch values */
+ const opus_int Fs_kHz, /* I sampling frequency (kHz) */
+ const opus_int nb_subfr /* I number of sub frames */
+)
+{
+ opus_int lag, k, min_lag, max_lag, cbk_size;
+ const opus_int8 *Lag_CB_ptr;
+
+ if( Fs_kHz == 8 ) {
+ if( nb_subfr == PE_MAX_NB_SUBFR ) {
+ Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ];
+ cbk_size = PE_NB_CBKS_STAGE2_EXT;
+ } else {
+ silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1 );
+ Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ];
+ cbk_size = PE_NB_CBKS_STAGE2_10MS;
+ }
+ } else {
+ if( nb_subfr == PE_MAX_NB_SUBFR ) {
+ Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ];
+ cbk_size = PE_NB_CBKS_STAGE3_MAX;
+ } else {
+ silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1 );
+ Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
+ cbk_size = PE_NB_CBKS_STAGE3_10MS;
+ }
+ }
+
+ min_lag = silk_SMULBB( PE_MIN_LAG_MS, Fs_kHz );
+ max_lag = silk_SMULBB( PE_MAX_LAG_MS, Fs_kHz );
+ lag = min_lag + lagIndex;
+
+ for( k = 0; k < nb_subfr; k++ ) {
+ pitch_lags[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, contourIndex, cbk_size );
+ pitch_lags[ k ] = silk_LIMIT( pitch_lags[ k ], min_lag, max_lag );
+ }
+}
diff --git a/drivers/opus/silk/decode_pulses.c b/drivers/opus/silk/decode_pulses.c
new file mode 100644
index 0000000000..24f841881d
--- /dev/null
+++ b/drivers/opus/silk/decode_pulses.c
@@ -0,0 +1,115 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+
+/*********************************************/
+/* Decode quantization indices of excitation */
+/*********************************************/
+void silk_decode_pulses(
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int pulses[], /* O Excitation signal */
+ const opus_int signalType, /* I Sigtype */
+ const opus_int quantOffsetType, /* I quantOffsetType */
+ const opus_int frame_length /* I Frame length */
+)
+{
+ opus_int i, j, k, iter, abs_q, nLS, RateLevelIndex;
+ opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ], nLshifts[ MAX_NB_SHELL_BLOCKS ];
+ opus_int *pulses_ptr;
+ const opus_uint8 *cdf_ptr;
+
+ /*********************/
+ /* Decode rate level */
+ /*********************/
+ RateLevelIndex = ec_dec_icdf( psRangeDec, silk_rate_levels_iCDF[ signalType >> 1 ], 8 );
+
+ /* Calculate number of shell blocks */
+ silk_assert( 1 << LOG2_SHELL_CODEC_FRAME_LENGTH == SHELL_CODEC_FRAME_LENGTH );
+ iter = silk_RSHIFT( frame_length, LOG2_SHELL_CODEC_FRAME_LENGTH );
+ if( iter * SHELL_CODEC_FRAME_LENGTH < frame_length ) {
+ silk_assert( frame_length == 12 * 10 ); /* Make sure only happens for 10 ms @ 12 kHz */
+ iter++;
+ }
+
+ /***************************************************/
+ /* Sum-Weighted-Pulses Decoding */
+ /***************************************************/
+ cdf_ptr = silk_pulses_per_block_iCDF[ RateLevelIndex ];
+ for( i = 0; i < iter; i++ ) {
+ nLshifts[ i ] = 0;
+ sum_pulses[ i ] = ec_dec_icdf( psRangeDec, cdf_ptr, 8 );
+
+ /* LSB indication */
+ while( sum_pulses[ i ] == MAX_PULSES + 1 ) {
+ nLshifts[ i ]++;
+ /* When we've already got 10 LSBs, we shift the table to not allow (MAX_PULSES + 1) */
+ sum_pulses[ i ] = ec_dec_icdf( psRangeDec,
+ silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1] + ( nLshifts[ i ] == 10 ), 8 );
+ }
+ }
+
+ /***************************************************/
+ /* Shell decoding */
+ /***************************************************/
+ for( i = 0; i < iter; i++ ) {
+ if( sum_pulses[ i ] > 0 ) {
+ silk_shell_decoder( &pulses[ silk_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ], psRangeDec, sum_pulses[ i ] );
+ } else {
+ silk_memset( &pulses[ silk_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ], 0, SHELL_CODEC_FRAME_LENGTH * sizeof( opus_int ) );
+ }
+ }
+
+ /***************************************************/
+ /* LSB Decoding */
+ /***************************************************/
+ for( i = 0; i < iter; i++ ) {
+ if( nLshifts[ i ] > 0 ) {
+ nLS = nLshifts[ i ];
+ pulses_ptr = &pulses[ silk_SMULBB( i, SHELL_CODEC_FRAME_LENGTH ) ];
+ for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) {
+ abs_q = pulses_ptr[ k ];
+ for( j = 0; j < nLS; j++ ) {
+ abs_q = silk_LSHIFT( abs_q, 1 );
+ abs_q += ec_dec_icdf( psRangeDec, silk_lsb_iCDF, 8 );
+ }
+ pulses_ptr[ k ] = abs_q;
+ }
+ /* Mark the number of pulses non-zero for sign decoding. */
+ sum_pulses[ i ] |= nLS << 5;
+ }
+ }
+
+ /****************************************/
+ /* Decode and add signs to pulse signal */
+ /****************************************/
+ silk_decode_signs( psRangeDec, pulses, frame_length, signalType, quantOffsetType, sum_pulses );
+}
diff --git a/drivers/opus/silk/decoder_set_fs.c b/drivers/opus/silk/decoder_set_fs.c
new file mode 100644
index 0000000000..97ecd8afd1
--- /dev/null
+++ b/drivers/opus/silk/decoder_set_fs.c
@@ -0,0 +1,108 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+
+/* Set decoder sampling rate */
+opus_int silk_decoder_set_fs(
+ silk_decoder_state *psDec, /* I/O Decoder state pointer */
+ opus_int fs_kHz, /* I Sampling frequency (kHz) */
+ opus_int32 fs_API_Hz /* I API Sampling frequency (Hz) */
+)
+{
+ opus_int frame_length, ret = 0;
+
+ silk_assert( fs_kHz == 8 || fs_kHz == 12 || fs_kHz == 16 );
+ silk_assert( psDec->nb_subfr == MAX_NB_SUBFR || psDec->nb_subfr == MAX_NB_SUBFR/2 );
+
+ /* New (sub)frame length */
+ psDec->subfr_length = silk_SMULBB( SUB_FRAME_LENGTH_MS, fs_kHz );
+ frame_length = silk_SMULBB( psDec->nb_subfr, psDec->subfr_length );
+
+ /* Initialize resampler when switching internal or external sampling frequency */
+ if( psDec->fs_kHz != fs_kHz || psDec->fs_API_hz != fs_API_Hz ) {
+ /* Initialize the resampler for dec_API.c preparing resampling from fs_kHz to API_fs_Hz */
+ ret += silk_resampler_init( &psDec->resampler_state, silk_SMULBB( fs_kHz, 1000 ), fs_API_Hz, 0 );
+
+ psDec->fs_API_hz = fs_API_Hz;
+ }
+
+ if( psDec->fs_kHz != fs_kHz || frame_length != psDec->frame_length ) {
+ if( fs_kHz == 8 ) {
+ if( psDec->nb_subfr == MAX_NB_SUBFR ) {
+ psDec->pitch_contour_iCDF = silk_pitch_contour_NB_iCDF;
+ } else {
+ psDec->pitch_contour_iCDF = silk_pitch_contour_10_ms_NB_iCDF;
+ }
+ } else {
+ if( psDec->nb_subfr == MAX_NB_SUBFR ) {
+ psDec->pitch_contour_iCDF = silk_pitch_contour_iCDF;
+ } else {
+ psDec->pitch_contour_iCDF = silk_pitch_contour_10_ms_iCDF;
+ }
+ }
+ if( psDec->fs_kHz != fs_kHz ) {
+ psDec->ltp_mem_length = silk_SMULBB( LTP_MEM_LENGTH_MS, fs_kHz );
+ if( fs_kHz == 8 || fs_kHz == 12 ) {
+ psDec->LPC_order = MIN_LPC_ORDER;
+ psDec->psNLSF_CB = &silk_NLSF_CB_NB_MB;
+ } else {
+ psDec->LPC_order = MAX_LPC_ORDER;
+ psDec->psNLSF_CB = &silk_NLSF_CB_WB;
+ }
+ if( fs_kHz == 16 ) {
+ psDec->pitch_lag_low_bits_iCDF = silk_uniform8_iCDF;
+ } else if( fs_kHz == 12 ) {
+ psDec->pitch_lag_low_bits_iCDF = silk_uniform6_iCDF;
+ } else if( fs_kHz == 8 ) {
+ psDec->pitch_lag_low_bits_iCDF = silk_uniform4_iCDF;
+ } else {
+ /* unsupported sampling rate */
+ silk_assert( 0 );
+ }
+ psDec->first_frame_after_reset = 1;
+ psDec->lagPrev = 100;
+ psDec->LastGainIndex = 10;
+ psDec->prevSignalType = TYPE_NO_VOICE_ACTIVITY;
+ silk_memset( psDec->outBuf, 0, sizeof(psDec->outBuf));
+ silk_memset( psDec->sLPC_Q14_buf, 0, sizeof(psDec->sLPC_Q14_buf) );
+ }
+
+ psDec->fs_kHz = fs_kHz;
+ psDec->frame_length = frame_length;
+ }
+
+ /* Check that settings are valid */
+ silk_assert( psDec->frame_length > 0 && psDec->frame_length <= MAX_FRAME_LENGTH );
+
+ return ret;
+}
+
diff --git a/drivers/opus/silk/define.h b/drivers/opus/silk/define.h
new file mode 100644
index 0000000000..a38564c835
--- /dev/null
+++ b/drivers/opus/silk/define.h
@@ -0,0 +1,235 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_DEFINE_H
+#define SILK_DEFINE_H
+
+#include "opus/silk/errors.h"
+#include "opus/silk/typedef.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Max number of encoder channels (1/2) */
+#define ENCODER_NUM_CHANNELS 2
+/* Number of decoder channels (1/2) */
+#define DECODER_NUM_CHANNELS 2
+
+#define MAX_FRAMES_PER_PACKET 3
+
+/* Limits on bitrate */
+#define MIN_TARGET_RATE_BPS 5000
+#define MAX_TARGET_RATE_BPS 80000
+#define TARGET_RATE_TAB_SZ 8
+
+/* LBRR thresholds */
+#define LBRR_NB_MIN_RATE_BPS 12000
+#define LBRR_MB_MIN_RATE_BPS 14000
+#define LBRR_WB_MIN_RATE_BPS 16000
+
+/* DTX settings */
+#define NB_SPEECH_FRAMES_BEFORE_DTX 10 /* eq 200 ms */
+#define MAX_CONSECUTIVE_DTX 20 /* eq 400 ms */
+
+/* Maximum sampling frequency */
+#define MAX_FS_KHZ 16
+#define MAX_API_FS_KHZ 48
+
+/* Signal types */
+#define TYPE_NO_VOICE_ACTIVITY 0
+#define TYPE_UNVOICED 1
+#define TYPE_VOICED 2
+
+/* Conditional coding types */
+#define CODE_INDEPENDENTLY 0
+#define CODE_INDEPENDENTLY_NO_LTP_SCALING 1
+#define CODE_CONDITIONALLY 2
+
+/* Settings for stereo processing */
+#define STEREO_QUANT_TAB_SIZE 16
+#define STEREO_QUANT_SUB_STEPS 5
+#define STEREO_INTERP_LEN_MS 8 /* must be even */
+#define STEREO_RATIO_SMOOTH_COEF 0.01 /* smoothing coef for signal norms and stereo width */
+
+/* Range of pitch lag estimates */
+#define PITCH_EST_MIN_LAG_MS 2 /* 2 ms -> 500 Hz */
+#define PITCH_EST_MAX_LAG_MS 18 /* 18 ms -> 56 Hz */
+
+/* Maximum number of subframes */
+#define MAX_NB_SUBFR 4
+
+/* Number of samples per frame */
+#define LTP_MEM_LENGTH_MS 20
+#define SUB_FRAME_LENGTH_MS 5
+#define MAX_SUB_FRAME_LENGTH ( SUB_FRAME_LENGTH_MS * MAX_FS_KHZ )
+#define MAX_FRAME_LENGTH_MS ( SUB_FRAME_LENGTH_MS * MAX_NB_SUBFR )
+#define MAX_FRAME_LENGTH ( MAX_FRAME_LENGTH_MS * MAX_FS_KHZ )
+
+/* Milliseconds of lookahead for pitch analysis */
+#define LA_PITCH_MS 2
+#define LA_PITCH_MAX ( LA_PITCH_MS * MAX_FS_KHZ )
+
+/* Order of LPC used in find pitch */
+#define MAX_FIND_PITCH_LPC_ORDER 16
+
+/* Length of LPC window used in find pitch */
+#define FIND_PITCH_LPC_WIN_MS ( 20 + (LA_PITCH_MS << 1) )
+#define FIND_PITCH_LPC_WIN_MS_2_SF ( 10 + (LA_PITCH_MS << 1) )
+#define FIND_PITCH_LPC_WIN_MAX ( FIND_PITCH_LPC_WIN_MS * MAX_FS_KHZ )
+
+/* Milliseconds of lookahead for noise shape analysis */
+#define LA_SHAPE_MS 5
+#define LA_SHAPE_MAX ( LA_SHAPE_MS * MAX_FS_KHZ )
+
+/* Maximum length of LPC window used in noise shape analysis */
+#define SHAPE_LPC_WIN_MAX ( 15 * MAX_FS_KHZ )
+
+/* dB level of lowest gain quantization level */
+#define MIN_QGAIN_DB 2
+/* dB level of highest gain quantization level */
+#define MAX_QGAIN_DB 88
+/* Number of gain quantization levels */
+#define N_LEVELS_QGAIN 64
+/* Max increase in gain quantization index */
+#define MAX_DELTA_GAIN_QUANT 36
+/* Max decrease in gain quantization index */
+#define MIN_DELTA_GAIN_QUANT -4
+
+/* Quantization offsets (multiples of 4) */
+#define OFFSET_VL_Q10 32
+#define OFFSET_VH_Q10 100
+#define OFFSET_UVL_Q10 100
+#define OFFSET_UVH_Q10 240
+
+#define QUANT_LEVEL_ADJUST_Q10 80
+
+/* Maximum numbers of iterations used to stabilize an LPC vector */
+#define MAX_LPC_STABILIZE_ITERATIONS 16
+#define MAX_PREDICTION_POWER_GAIN 1e4f
+#define MAX_PREDICTION_POWER_GAIN_AFTER_RESET 1e2f
+
+#define MAX_LPC_ORDER 16
+#define MIN_LPC_ORDER 10
+
+/* Find Pred Coef defines */
+#define LTP_ORDER 5
+
+/* LTP quantization settings */
+#define NB_LTP_CBKS 3
+
+/* Flag to use harmonic noise shaping */
+#define USE_HARM_SHAPING 1
+
+/* Max LPC order of noise shaping filters */
+#define MAX_SHAPE_LPC_ORDER 16
+
+#define HARM_SHAPE_FIR_TAPS 3
+
+/* Maximum number of delayed decision states */
+#define MAX_DEL_DEC_STATES 4
+
+#define LTP_BUF_LENGTH 512
+#define LTP_MASK ( LTP_BUF_LENGTH - 1 )
+
+#define DECISION_DELAY 32
+#define DECISION_DELAY_MASK ( DECISION_DELAY - 1 )
+
+/* Number of subframes for excitation entropy coding */
+#define SHELL_CODEC_FRAME_LENGTH 16
+#define LOG2_SHELL_CODEC_FRAME_LENGTH 4
+#define MAX_NB_SHELL_BLOCKS ( MAX_FRAME_LENGTH / SHELL_CODEC_FRAME_LENGTH )
+
+/* Number of rate levels, for entropy coding of excitation */
+#define N_RATE_LEVELS 10
+
+/* Maximum sum of pulses per shell coding frame */
+#define MAX_PULSES 16
+
+#define MAX_MATRIX_SIZE MAX_LPC_ORDER /* Max of LPC Order and LTP order */
+
+#if( MAX_LPC_ORDER > DECISION_DELAY )
+# define NSQ_LPC_BUF_LENGTH MAX_LPC_ORDER
+#else
+# define NSQ_LPC_BUF_LENGTH DECISION_DELAY
+#endif
+
+/***************************/
+/* Voice activity detector */
+/***************************/
+#define VAD_N_BANDS 4
+
+#define VAD_INTERNAL_SUBFRAMES_LOG2 2
+#define VAD_INTERNAL_SUBFRAMES ( 1 << VAD_INTERNAL_SUBFRAMES_LOG2 )
+
+#define VAD_NOISE_LEVEL_SMOOTH_COEF_Q16 1024 /* Must be < 4096 */
+#define VAD_NOISE_LEVELS_BIAS 50
+
+/* Sigmoid settings */
+#define VAD_NEGATIVE_OFFSET_Q5 128 /* sigmoid is 0 at -128 */
+#define VAD_SNR_FACTOR_Q16 45000
+
+/* smoothing for SNR measurement */
+#define VAD_SNR_SMOOTH_COEF_Q18 4096
+
+/* Size of the piecewise linear cosine approximation table for the LSFs */
+#define LSF_COS_TAB_SZ_FIX 128
+
+/******************/
+/* NLSF quantizer */
+/******************/
+#define NLSF_W_Q 2
+#define NLSF_VQ_MAX_VECTORS 32
+#define NLSF_VQ_MAX_SURVIVORS 32
+#define NLSF_QUANT_MAX_AMPLITUDE 4
+#define NLSF_QUANT_MAX_AMPLITUDE_EXT 10
+#define NLSF_QUANT_LEVEL_ADJ 0.1
+#define NLSF_QUANT_DEL_DEC_STATES_LOG2 2
+#define NLSF_QUANT_DEL_DEC_STATES ( 1 << NLSF_QUANT_DEL_DEC_STATES_LOG2 )
+
+/* Transition filtering for mode switching */
+#define TRANSITION_TIME_MS 5120 /* 5120 = 64 * FRAME_LENGTH_MS * ( TRANSITION_INT_NUM - 1 ) = 64*(20*4)*/
+#define TRANSITION_NB 3 /* Hardcoded in tables */
+#define TRANSITION_NA 2 /* Hardcoded in tables */
+#define TRANSITION_INT_NUM 5 /* Hardcoded in tables */
+#define TRANSITION_FRAMES ( TRANSITION_TIME_MS / MAX_FRAME_LENGTH_MS )
+#define TRANSITION_INT_STEPS ( TRANSITION_FRAMES / ( TRANSITION_INT_NUM - 1 ) )
+
+/* BWE factors to apply after packet loss */
+#define BWE_AFTER_LOSS_Q16 63570
+
+/* Defines for CN generation */
+#define CNG_BUF_MASK_MAX 255 /* 2^floor(log2(MAX_FRAME_LENGTH))-1 */
+#define CNG_GAIN_SMTH_Q16 4634 /* 0.25^(1/4) */
+#define CNG_NLSF_SMTH_Q16 16348 /* 0.25 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/opus/silk/enc_API.c b/drivers/opus/silk/enc_API.c
new file mode 100644
index 0000000000..ac1a7854f0
--- /dev/null
+++ b/drivers/opus/silk/enc_API.c
@@ -0,0 +1,556 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+#include "opus/silk/define.h"
+#include "opus/silk/API.h"
+#include "opus/silk/control.h"
+#include "opus/silk/typedef.h"
+#include "opus/celt/stack_alloc.h"
+#include "opus/silk/structs.h"
+#include "opus/silk/tuning_parameters.h"
+#ifdef OPUS_FIXED_POINT
+#include "opus/silk/fixed/main_FIX.h"
+#else
+#include "opus/silk/float/main_FLP.h"
+#endif
+
+/***************************************/
+/* Read control structure from encoder */
+/***************************************/
+static opus_int silk_QueryEncoder( /* O Returns error code */
+ const void *encState, /* I State */
+ silk_EncControlStruct *encStatus /* O Encoder Status */
+);
+
+/****************************************/
+/* Encoder functions */
+/****************************************/
+
+opus_int silk_Get_Encoder_Size( /* O Returns error code */
+ opus_int *encSizeBytes /* O Number of bytes in SILK encoder state */
+)
+{
+ opus_int ret = SILK_NO_ERROR;
+
+ *encSizeBytes = sizeof( silk_encoder );
+
+ return ret;
+}
+
+/*************************/
+/* Init or Reset encoder */
+/*************************/
+opus_int silk_InitEncoder( /* O Returns error code */
+ void *encState, /* I/O State */
+ int arch, /* I Run-time architecture */
+ silk_EncControlStruct *encStatus /* O Encoder Status */
+)
+{
+ silk_encoder *psEnc;
+ opus_int n, ret = SILK_NO_ERROR;
+
+ psEnc = (silk_encoder *)encState;
+
+ /* Reset encoder */
+ silk_memset( psEnc, 0, sizeof( silk_encoder ) );
+ for( n = 0; n < ENCODER_NUM_CHANNELS; n++ ) {
+ if( ret += silk_init_encoder( &psEnc->state_Fxx[ n ], arch ) ) {
+ silk_assert( 0 );
+ }
+ }
+
+ psEnc->nChannelsAPI = 1;
+ psEnc->nChannelsInternal = 1;
+
+ /* Read control structure */
+ if( ret += silk_QueryEncoder( encState, encStatus ) ) {
+ silk_assert( 0 );
+ }
+
+ return ret;
+}
+
+/***************************************/
+/* Read control structure from encoder */
+/***************************************/
+static opus_int silk_QueryEncoder( /* O Returns error code */
+ const void *encState, /* I State */
+ silk_EncControlStruct *encStatus /* O Encoder Status */
+)
+{
+ opus_int ret = SILK_NO_ERROR;
+ silk_encoder_state_Fxx *state_Fxx;
+ silk_encoder *psEnc = (silk_encoder *)encState;
+
+ state_Fxx = psEnc->state_Fxx;
+
+ encStatus->nChannelsAPI = psEnc->nChannelsAPI;
+ encStatus->nChannelsInternal = psEnc->nChannelsInternal;
+ encStatus->API_sampleRate = state_Fxx[ 0 ].sCmn.API_fs_Hz;
+ encStatus->maxInternalSampleRate = state_Fxx[ 0 ].sCmn.maxInternal_fs_Hz;
+ encStatus->minInternalSampleRate = state_Fxx[ 0 ].sCmn.minInternal_fs_Hz;
+ encStatus->desiredInternalSampleRate = state_Fxx[ 0 ].sCmn.desiredInternal_fs_Hz;
+ encStatus->payloadSize_ms = state_Fxx[ 0 ].sCmn.PacketSize_ms;
+ encStatus->bitRate = state_Fxx[ 0 ].sCmn.TargetRate_bps;
+ encStatus->packetLossPercentage = state_Fxx[ 0 ].sCmn.PacketLoss_perc;
+ encStatus->complexity = state_Fxx[ 0 ].sCmn.Complexity;
+ encStatus->useInBandFEC = state_Fxx[ 0 ].sCmn.useInBandFEC;
+ encStatus->useDTX = state_Fxx[ 0 ].sCmn.useDTX;
+ encStatus->useCBR = state_Fxx[ 0 ].sCmn.useCBR;
+ encStatus->internalSampleRate = silk_SMULBB( state_Fxx[ 0 ].sCmn.fs_kHz, 1000 );
+ encStatus->allowBandwidthSwitch = state_Fxx[ 0 ].sCmn.allow_bandwidth_switch;
+ encStatus->inWBmodeWithoutVariableLP = state_Fxx[ 0 ].sCmn.fs_kHz == 16 && state_Fxx[ 0 ].sCmn.sLP.mode == 0;
+
+ return ret;
+}
+
+
+/**************************/
+/* Encode frame with Silk */
+/**************************/
+/* Note: if prefillFlag is set, the input must contain 10 ms of audio, irrespective of what */
+/* encControl->payloadSize_ms is set to */
+opus_int silk_Encode( /* O Returns error code */
+ void *encState, /* I/O State */
+ silk_EncControlStruct *encControl, /* I Control status */
+ const opus_int16 *samplesIn, /* I Speech sample input vector */
+ opus_int nSamplesIn, /* I Number of samples in input vector */
+ ec_enc *psRangeEnc, /* I/O Compressor data structure */
+ opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */
+ const opus_int prefillFlag /* I Flag to indicate prefilling buffers no coding */
+)
+{
+ opus_int n, i, nBits, flags, tmp_payloadSize_ms = 0, tmp_complexity = 0, ret = 0;
+ opus_int nSamplesToBuffer, nSamplesToBufferMax, nBlocksOf10ms;
+ opus_int nSamplesFromInput = 0, nSamplesFromInputMax;
+ opus_int speech_act_thr_for_switch_Q8;
+ opus_int32 TargetRate_bps, MStargetRates_bps[ 2 ], channelRate_bps, LBRR_symbol, sum;
+ silk_encoder *psEnc = ( silk_encoder * )encState;
+ VARDECL( opus_int16, buf );
+ opus_int transition, curr_block, tot_blocks;
+ SAVE_STACK;
+
+ if (encControl->reducedDependency)
+ {
+ psEnc->state_Fxx[0].sCmn.first_frame_after_reset = 1;
+ psEnc->state_Fxx[1].sCmn.first_frame_after_reset = 1;
+ }
+ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded = psEnc->state_Fxx[ 1 ].sCmn.nFramesEncoded = 0;
+
+ /* Check values in encoder control structure */
+ if( ( ret = check_control_input( encControl ) != 0 ) ) {
+ silk_assert( 0 );
+ RESTORE_STACK;
+ return ret;
+ }
+
+ encControl->switchReady = 0;
+
+ if( encControl->nChannelsInternal > psEnc->nChannelsInternal ) {
+ /* Mono -> Stereo transition: init state of second channel and stereo state */
+ ret += silk_init_encoder( &psEnc->state_Fxx[ 1 ], psEnc->state_Fxx[ 0 ].sCmn.arch );
+ silk_memset( psEnc->sStereo.pred_prev_Q13, 0, sizeof( psEnc->sStereo.pred_prev_Q13 ) );
+ silk_memset( psEnc->sStereo.sSide, 0, sizeof( psEnc->sStereo.sSide ) );
+ psEnc->sStereo.mid_side_amp_Q0[ 0 ] = 0;
+ psEnc->sStereo.mid_side_amp_Q0[ 1 ] = 1;
+ psEnc->sStereo.mid_side_amp_Q0[ 2 ] = 0;
+ psEnc->sStereo.mid_side_amp_Q0[ 3 ] = 1;
+ psEnc->sStereo.width_prev_Q14 = 0;
+ psEnc->sStereo.smth_width_Q14 = SILK_FIX_CONST( 1, 14 );
+ if( psEnc->nChannelsAPI == 2 ) {
+ silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, sizeof( silk_resampler_state_struct ) );
+ silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.In_HP_State, &psEnc->state_Fxx[ 0 ].sCmn.In_HP_State, sizeof( psEnc->state_Fxx[ 1 ].sCmn.In_HP_State ) );
+ }
+ }
+
+ transition = (encControl->payloadSize_ms != psEnc->state_Fxx[ 0 ].sCmn.PacketSize_ms) || (psEnc->nChannelsInternal != encControl->nChannelsInternal);
+
+ psEnc->nChannelsAPI = encControl->nChannelsAPI;
+ psEnc->nChannelsInternal = encControl->nChannelsInternal;
+
+ nBlocksOf10ms = silk_DIV32( 100 * nSamplesIn, encControl->API_sampleRate );
+ tot_blocks = ( nBlocksOf10ms > 1 ) ? nBlocksOf10ms >> 1 : 1;
+ curr_block = 0;
+ if( prefillFlag ) {
+ /* Only accept input length of 10 ms */
+ if( nBlocksOf10ms != 1 ) {
+ silk_assert( 0 );
+ RESTORE_STACK;
+ return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES;
+ }
+ /* Reset Encoder */
+ for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+ ret = silk_init_encoder( &psEnc->state_Fxx[ n ], psEnc->state_Fxx[ n ].sCmn.arch );
+ silk_assert( !ret );
+ }
+ tmp_payloadSize_ms = encControl->payloadSize_ms;
+ encControl->payloadSize_ms = 10;
+ tmp_complexity = encControl->complexity;
+ encControl->complexity = 0;
+ for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+ psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0;
+ psEnc->state_Fxx[ n ].sCmn.prefillFlag = 1;
+ }
+ } else {
+ /* Only accept input lengths that are a multiple of 10 ms */
+ if( nBlocksOf10ms * encControl->API_sampleRate != 100 * nSamplesIn || nSamplesIn < 0 ) {
+ silk_assert( 0 );
+ RESTORE_STACK;
+ return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES;
+ }
+ /* Make sure no more than one packet can be produced */
+ if( 1000 * (opus_int32)nSamplesIn > encControl->payloadSize_ms * encControl->API_sampleRate ) {
+ silk_assert( 0 );
+ RESTORE_STACK;
+ return SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES;
+ }
+ }
+
+ TargetRate_bps = silk_RSHIFT32( encControl->bitRate, encControl->nChannelsInternal - 1 );
+ for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+ /* Force the side channel to the same rate as the mid */
+ opus_int force_fs_kHz = (n==1) ? psEnc->state_Fxx[0].sCmn.fs_kHz : 0;
+ if( ( ret = silk_control_encoder( &psEnc->state_Fxx[ n ], encControl, TargetRate_bps, psEnc->allowBandwidthSwitch, n, force_fs_kHz ) ) != 0 ) {
+ silk_assert( 0 );
+ RESTORE_STACK;
+ return ret;
+ }
+ if( psEnc->state_Fxx[n].sCmn.first_frame_after_reset || transition ) {
+ for( i = 0; i < psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket; i++ ) {
+ psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ] = 0;
+ }
+ }
+ psEnc->state_Fxx[ n ].sCmn.inDTX = psEnc->state_Fxx[ n ].sCmn.useDTX;
+ }
+ silk_assert( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 0 ].sCmn.fs_kHz == psEnc->state_Fxx[ 1 ].sCmn.fs_kHz );
+
+ /* Input buffering/resampling and encoding */
+ nSamplesToBufferMax =
+ 10 * nBlocksOf10ms * psEnc->state_Fxx[ 0 ].sCmn.fs_kHz;
+ nSamplesFromInputMax =
+ silk_DIV32_16( nSamplesToBufferMax *
+ psEnc->state_Fxx[ 0 ].sCmn.API_fs_Hz,
+ psEnc->state_Fxx[ 0 ].sCmn.fs_kHz * 1000 );
+ ALLOC( buf, nSamplesFromInputMax, opus_int16 );
+ while( 1 ) {
+ nSamplesToBuffer = psEnc->state_Fxx[ 0 ].sCmn.frame_length - psEnc->state_Fxx[ 0 ].sCmn.inputBufIx;
+ nSamplesToBuffer = silk_min( nSamplesToBuffer, nSamplesToBufferMax );
+ nSamplesFromInput = silk_DIV32_16( nSamplesToBuffer * psEnc->state_Fxx[ 0 ].sCmn.API_fs_Hz, psEnc->state_Fxx[ 0 ].sCmn.fs_kHz * 1000 );
+ /* Resample and write to buffer */
+ if( encControl->nChannelsAPI == 2 && encControl->nChannelsInternal == 2 ) {
+ opus_int id = psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded;
+ for( n = 0; n < nSamplesFromInput; n++ ) {
+ buf[ n ] = samplesIn[ 2 * n ];
+ }
+ /* Making sure to start both resamplers from the same state when switching from mono to stereo */
+ if( psEnc->nPrevChannelsInternal == 1 && id==0 ) {
+ silk_memcpy( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state, &psEnc->state_Fxx[ 0 ].sCmn.resampler_state, sizeof(psEnc->state_Fxx[ 1 ].sCmn.resampler_state));
+ }
+
+ ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state,
+ &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput );
+ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer;
+
+ nSamplesToBuffer = psEnc->state_Fxx[ 1 ].sCmn.frame_length - psEnc->state_Fxx[ 1 ].sCmn.inputBufIx;
+ nSamplesToBuffer = silk_min( nSamplesToBuffer, 10 * nBlocksOf10ms * psEnc->state_Fxx[ 1 ].sCmn.fs_kHz );
+ for( n = 0; n < nSamplesFromInput; n++ ) {
+ buf[ n ] = samplesIn[ 2 * n + 1 ];
+ }
+ ret += silk_resampler( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state,
+ &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput );
+
+ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx += nSamplesToBuffer;
+ } else if( encControl->nChannelsAPI == 2 && encControl->nChannelsInternal == 1 ) {
+ /* Combine left and right channels before resampling */
+ for( n = 0; n < nSamplesFromInput; n++ ) {
+ sum = samplesIn[ 2 * n ] + samplesIn[ 2 * n + 1 ];
+ buf[ n ] = (opus_int16)silk_RSHIFT_ROUND( sum, 1 );
+ }
+ ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state,
+ &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput );
+ /* On the first mono frame, average the results for the two resampler states */
+ if( psEnc->nPrevChannelsInternal == 2 && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == 0 ) {
+ ret += silk_resampler( &psEnc->state_Fxx[ 1 ].sCmn.resampler_state,
+ &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput );
+ for( n = 0; n < psEnc->state_Fxx[ 0 ].sCmn.frame_length; n++ ) {
+ psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx+n+2 ] =
+ silk_RSHIFT(psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx+n+2 ]
+ + psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ psEnc->state_Fxx[ 1 ].sCmn.inputBufIx+n+2 ], 1);
+ }
+ }
+ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer;
+ } else {
+ silk_assert( encControl->nChannelsAPI == 1 && encControl->nChannelsInternal == 1 );
+ silk_memcpy(buf, samplesIn, nSamplesFromInput*sizeof(opus_int16));
+ ret += silk_resampler( &psEnc->state_Fxx[ 0 ].sCmn.resampler_state,
+ &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx + 2 ], buf, nSamplesFromInput );
+ psEnc->state_Fxx[ 0 ].sCmn.inputBufIx += nSamplesToBuffer;
+ }
+
+ samplesIn += nSamplesFromInput * encControl->nChannelsAPI;
+ nSamplesIn -= nSamplesFromInput;
+
+ /* Default */
+ psEnc->allowBandwidthSwitch = 0;
+
+ /* Silk encoder */
+ if( psEnc->state_Fxx[ 0 ].sCmn.inputBufIx >= psEnc->state_Fxx[ 0 ].sCmn.frame_length ) {
+ /* Enough data in input buffer, so encode */
+ silk_assert( psEnc->state_Fxx[ 0 ].sCmn.inputBufIx == psEnc->state_Fxx[ 0 ].sCmn.frame_length );
+ silk_assert( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 1 ].sCmn.inputBufIx == psEnc->state_Fxx[ 1 ].sCmn.frame_length );
+
+ /* Deal with LBRR data */
+ if( psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == 0 && !prefillFlag ) {
+ /* Create space at start of payload for VAD and FEC flags */
+ opus_uint8 iCDF[ 2 ] = { 0, 0 };
+ iCDF[ 0 ] = 256 - silk_RSHIFT( 256, ( psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket + 1 ) * encControl->nChannelsInternal );
+ ec_enc_icdf( psRangeEnc, 0, iCDF, 8 );
+
+ /* Encode any LBRR data from previous packet */
+ /* Encode LBRR flags */
+ for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+ LBRR_symbol = 0;
+ for( i = 0; i < psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket; i++ ) {
+ LBRR_symbol |= silk_LSHIFT( psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ], i );
+ }
+ psEnc->state_Fxx[ n ].sCmn.LBRR_flag = LBRR_symbol > 0 ? 1 : 0;
+ if( LBRR_symbol && psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket > 1 ) {
+ ec_enc_icdf( psRangeEnc, LBRR_symbol - 1, silk_LBRR_flags_iCDF_ptr[ psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket - 2 ], 8 );
+ }
+ }
+
+ /* Code LBRR indices and excitation signals */
+ for( i = 0; i < psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket; i++ ) {
+ for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+ if( psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i ] ) {
+ opus_int condCoding;
+
+ if( encControl->nChannelsInternal == 2 && n == 0 ) {
+ silk_stereo_encode_pred( psRangeEnc, psEnc->sStereo.predIx[ i ] );
+ /* For LBRR data there's no need to code the mid-only flag if the side-channel LBRR flag is set */
+ if( psEnc->state_Fxx[ 1 ].sCmn.LBRR_flags[ i ] == 0 ) {
+ silk_stereo_encode_mid_only( psRangeEnc, psEnc->sStereo.mid_only_flags[ i ] );
+ }
+ }
+ /* Use conditional coding if previous frame available */
+ if( i > 0 && psEnc->state_Fxx[ n ].sCmn.LBRR_flags[ i - 1 ] ) {
+ condCoding = CODE_CONDITIONALLY;
+ } else {
+ condCoding = CODE_INDEPENDENTLY;
+ }
+ silk_encode_indices( &psEnc->state_Fxx[ n ].sCmn, psRangeEnc, i, 1, condCoding );
+ silk_encode_pulses( psRangeEnc, psEnc->state_Fxx[ n ].sCmn.indices_LBRR[i].signalType, psEnc->state_Fxx[ n ].sCmn.indices_LBRR[i].quantOffsetType,
+ psEnc->state_Fxx[ n ].sCmn.pulses_LBRR[ i ], psEnc->state_Fxx[ n ].sCmn.frame_length );
+ }
+ }
+ }
+
+ /* Reset LBRR flags */
+ for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+ silk_memset( psEnc->state_Fxx[ n ].sCmn.LBRR_flags, 0, sizeof( psEnc->state_Fxx[ n ].sCmn.LBRR_flags ) );
+ }
+ }
+
+ silk_HP_variable_cutoff( psEnc->state_Fxx );
+
+ /* Total target bits for packet */
+ nBits = silk_DIV32_16( silk_MUL( encControl->bitRate, encControl->payloadSize_ms ), 1000 );
+ /* Subtract half of the bits already used */
+ if( !prefillFlag ) {
+ nBits -= ec_tell( psRangeEnc ) >> 1;
+ }
+ /* Divide by number of uncoded frames left in packet */
+ nBits = silk_DIV32_16( nBits, psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket - psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded );
+ /* Convert to bits/second */
+ if( encControl->payloadSize_ms == 10 ) {
+ TargetRate_bps = silk_SMULBB( nBits, 100 );
+ } else {
+ TargetRate_bps = silk_SMULBB( nBits, 50 );
+ }
+ /* Subtract fraction of bits in excess of target in previous packets */
+ TargetRate_bps -= silk_DIV32_16( silk_MUL( psEnc->nBitsExceeded, 1000 ), BITRESERVOIR_DECAY_TIME_MS );
+ /* Never exceed input bitrate */
+ TargetRate_bps = silk_LIMIT( TargetRate_bps, encControl->bitRate, 5000 );
+
+ /* Convert Left/Right to Mid/Side */
+ if( encControl->nChannelsInternal == 2 ) {
+ silk_stereo_LR_to_MS( &psEnc->sStereo, &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ 2 ], &psEnc->state_Fxx[ 1 ].sCmn.inputBuf[ 2 ],
+ psEnc->sStereo.predIx[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ], &psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ],
+ MStargetRates_bps, TargetRate_bps, psEnc->state_Fxx[ 0 ].sCmn.speech_activity_Q8, encControl->toMono,
+ psEnc->state_Fxx[ 0 ].sCmn.fs_kHz, psEnc->state_Fxx[ 0 ].sCmn.frame_length );
+ if( psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] == 0 ) {
+ /* Reset side channel encoder memory for first frame with side coding */
+ if( psEnc->prev_decode_only_middle == 1 ) {
+ silk_memset( &psEnc->state_Fxx[ 1 ].sShape, 0, sizeof( psEnc->state_Fxx[ 1 ].sShape ) );
+ silk_memset( &psEnc->state_Fxx[ 1 ].sPrefilt, 0, sizeof( psEnc->state_Fxx[ 1 ].sPrefilt ) );
+ silk_memset( &psEnc->state_Fxx[ 1 ].sCmn.sNSQ, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.sNSQ ) );
+ silk_memset( psEnc->state_Fxx[ 1 ].sCmn.prev_NLSFq_Q15, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.prev_NLSFq_Q15 ) );
+ silk_memset( &psEnc->state_Fxx[ 1 ].sCmn.sLP.In_LP_State, 0, sizeof( psEnc->state_Fxx[ 1 ].sCmn.sLP.In_LP_State ) );
+ psEnc->state_Fxx[ 1 ].sCmn.prevLag = 100;
+ psEnc->state_Fxx[ 1 ].sCmn.sNSQ.lagPrev = 100;
+ psEnc->state_Fxx[ 1 ].sShape.LastGainIndex = 10;
+ psEnc->state_Fxx[ 1 ].sCmn.prevSignalType = TYPE_NO_VOICE_ACTIVITY;
+ psEnc->state_Fxx[ 1 ].sCmn.sNSQ.prev_gain_Q16 = 65536;
+ psEnc->state_Fxx[ 1 ].sCmn.first_frame_after_reset = 1;
+ }
+ silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 1 ] );
+ } else {
+ psEnc->state_Fxx[ 1 ].sCmn.VAD_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] = 0;
+ }
+ if( !prefillFlag ) {
+ silk_stereo_encode_pred( psRangeEnc, psEnc->sStereo.predIx[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] );
+ if( psEnc->state_Fxx[ 1 ].sCmn.VAD_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] == 0 ) {
+ silk_stereo_encode_mid_only( psRangeEnc, psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded ] );
+ }
+ }
+ } else {
+ /* Buffering */
+ silk_memcpy( psEnc->state_Fxx[ 0 ].sCmn.inputBuf, psEnc->sStereo.sMid, 2 * sizeof( opus_int16 ) );
+ silk_memcpy( psEnc->sStereo.sMid, &psEnc->state_Fxx[ 0 ].sCmn.inputBuf[ psEnc->state_Fxx[ 0 ].sCmn.frame_length ], 2 * sizeof( opus_int16 ) );
+ }
+ silk_encode_do_VAD_Fxx( &psEnc->state_Fxx[ 0 ] );
+
+ /* Encode */
+ for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+ opus_int maxBits, useCBR;
+
+ /* Handling rate constraints */
+ maxBits = encControl->maxBits;
+ if( tot_blocks == 2 && curr_block == 0 ) {
+ maxBits = maxBits * 3 / 5;
+ } else if( tot_blocks == 3 ) {
+ if( curr_block == 0 ) {
+ maxBits = maxBits * 2 / 5;
+ } else if( curr_block == 1 ) {
+ maxBits = maxBits * 3 / 4;
+ }
+ }
+ useCBR = encControl->useCBR && curr_block == tot_blocks - 1;
+
+ if( encControl->nChannelsInternal == 1 ) {
+ channelRate_bps = TargetRate_bps;
+ } else {
+ channelRate_bps = MStargetRates_bps[ n ];
+ if( n == 0 && MStargetRates_bps[ 1 ] > 0 ) {
+ useCBR = 0;
+ /* Give mid up to 1/2 of the max bits for that frame */
+ maxBits -= encControl->maxBits / ( tot_blocks * 2 );
+ }
+ }
+
+ if( channelRate_bps > 0 ) {
+ opus_int condCoding;
+
+ silk_control_SNR( &psEnc->state_Fxx[ n ].sCmn, channelRate_bps );
+
+ /* Use independent coding if no previous frame available */
+ if( psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded - n <= 0 ) {
+ condCoding = CODE_INDEPENDENTLY;
+ } else if( n > 0 && psEnc->prev_decode_only_middle ) {
+ /* If we skipped a side frame in this packet, we don't
+ need LTP scaling; the LTP state is well-defined. */
+ condCoding = CODE_INDEPENDENTLY_NO_LTP_SCALING;
+ } else {
+ condCoding = CODE_CONDITIONALLY;
+ }
+ if( ( ret = silk_encode_frame_Fxx( &psEnc->state_Fxx[ n ], nBytesOut, psRangeEnc, condCoding, maxBits, useCBR ) ) != 0 ) {
+ silk_assert( 0 );
+ }
+ }
+ psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0;
+ psEnc->state_Fxx[ n ].sCmn.inputBufIx = 0;
+ psEnc->state_Fxx[ n ].sCmn.nFramesEncoded++;
+ }
+ psEnc->prev_decode_only_middle = psEnc->sStereo.mid_only_flags[ psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded - 1 ];
+
+ /* Insert VAD and FEC flags at beginning of bitstream */
+ if( *nBytesOut > 0 && psEnc->state_Fxx[ 0 ].sCmn.nFramesEncoded == psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket) {
+ flags = 0;
+ for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+ for( i = 0; i < psEnc->state_Fxx[ n ].sCmn.nFramesPerPacket; i++ ) {
+ flags = silk_LSHIFT( flags, 1 );
+ flags |= psEnc->state_Fxx[ n ].sCmn.VAD_flags[ i ];
+ }
+ flags = silk_LSHIFT( flags, 1 );
+ flags |= psEnc->state_Fxx[ n ].sCmn.LBRR_flag;
+ }
+ if( !prefillFlag ) {
+ ec_enc_patch_initial_bits( psRangeEnc, flags, ( psEnc->state_Fxx[ 0 ].sCmn.nFramesPerPacket + 1 ) * encControl->nChannelsInternal );
+ }
+
+ /* Return zero bytes if all channels DTXed */
+ if( psEnc->state_Fxx[ 0 ].sCmn.inDTX && ( encControl->nChannelsInternal == 1 || psEnc->state_Fxx[ 1 ].sCmn.inDTX ) ) {
+ *nBytesOut = 0;
+ }
+
+ psEnc->nBitsExceeded += *nBytesOut * 8;
+ psEnc->nBitsExceeded -= silk_DIV32_16( silk_MUL( encControl->bitRate, encControl->payloadSize_ms ), 1000 );
+ psEnc->nBitsExceeded = silk_LIMIT( psEnc->nBitsExceeded, 0, 10000 );
+
+ /* Update flag indicating if bandwidth switching is allowed */
+ speech_act_thr_for_switch_Q8 = silk_SMLAWB( SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ),
+ SILK_FIX_CONST( ( 1 - SPEECH_ACTIVITY_DTX_THRES ) / MAX_BANDWIDTH_SWITCH_DELAY_MS, 16 + 8 ), psEnc->timeSinceSwitchAllowed_ms );
+ if( psEnc->state_Fxx[ 0 ].sCmn.speech_activity_Q8 < speech_act_thr_for_switch_Q8 ) {
+ psEnc->allowBandwidthSwitch = 1;
+ psEnc->timeSinceSwitchAllowed_ms = 0;
+ } else {
+ psEnc->allowBandwidthSwitch = 0;
+ psEnc->timeSinceSwitchAllowed_ms += encControl->payloadSize_ms;
+ }
+ }
+
+ if( nSamplesIn == 0 ) {
+ break;
+ }
+ } else {
+ break;
+ }
+ curr_block++;
+ }
+
+ psEnc->nPrevChannelsInternal = encControl->nChannelsInternal;
+
+ encControl->allowBandwidthSwitch = psEnc->allowBandwidthSwitch;
+ encControl->inWBmodeWithoutVariableLP = psEnc->state_Fxx[ 0 ].sCmn.fs_kHz == 16 && psEnc->state_Fxx[ 0 ].sCmn.sLP.mode == 0;
+ encControl->internalSampleRate = silk_SMULBB( psEnc->state_Fxx[ 0 ].sCmn.fs_kHz, 1000 );
+ encControl->stereoWidth_Q14 = encControl->toMono ? 0 : psEnc->sStereo.smth_width_Q14;
+ if( prefillFlag ) {
+ encControl->payloadSize_ms = tmp_payloadSize_ms;
+ encControl->complexity = tmp_complexity;
+ for( n = 0; n < encControl->nChannelsInternal; n++ ) {
+ psEnc->state_Fxx[ n ].sCmn.controlled_since_last_payload = 0;
+ psEnc->state_Fxx[ n ].sCmn.prefillFlag = 0;
+ }
+ }
+
+ RESTORE_STACK;
+ return ret;
+}
+
diff --git a/drivers/opus/silk/encode_indices.c b/drivers/opus/silk/encode_indices.c
new file mode 100644
index 0000000000..7150325d49
--- /dev/null
+++ b/drivers/opus/silk/encode_indices.c
@@ -0,0 +1,181 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+
+/* Encode side-information parameters to payload */
+void silk_encode_indices(
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ ec_enc *psRangeEnc, /* I/O Compressor data structure */
+ opus_int FrameIndex, /* I Frame number */
+ opus_int encode_LBRR, /* I Flag indicating LBRR data is being encoded */
+ opus_int condCoding /* I The type of conditional coding to use */
+)
+{
+ opus_int i, k, typeOffset;
+ opus_int encode_absolute_lagIndex, delta_lagIndex;
+ opus_int16 ec_ix[ MAX_LPC_ORDER ];
+ opus_uint8 pred_Q8[ MAX_LPC_ORDER ];
+ const SideInfoIndices *psIndices;
+
+ if( encode_LBRR ) {
+ psIndices = &psEncC->indices_LBRR[ FrameIndex ];
+ } else {
+ psIndices = &psEncC->indices;
+ }
+
+ /*******************************************/
+ /* Encode signal type and quantizer offset */
+ /*******************************************/
+ typeOffset = 2 * psIndices->signalType + psIndices->quantOffsetType;
+ silk_assert( typeOffset >= 0 && typeOffset < 6 );
+ silk_assert( encode_LBRR == 0 || typeOffset >= 2 );
+ if( encode_LBRR || typeOffset >= 2 ) {
+ ec_enc_icdf( psRangeEnc, typeOffset - 2, silk_type_offset_VAD_iCDF, 8 );
+ } else {
+ ec_enc_icdf( psRangeEnc, typeOffset, silk_type_offset_no_VAD_iCDF, 8 );
+ }
+
+ /****************/
+ /* Encode gains */
+ /****************/
+ /* first subframe */
+ if( condCoding == CODE_CONDITIONALLY ) {
+ /* conditional coding */
+ silk_assert( psIndices->GainsIndices[ 0 ] >= 0 && psIndices->GainsIndices[ 0 ] < MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 );
+ ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ 0 ], silk_delta_gain_iCDF, 8 );
+ } else {
+ /* independent coding, in two stages: MSB bits followed by 3 LSBs */
+ silk_assert( psIndices->GainsIndices[ 0 ] >= 0 && psIndices->GainsIndices[ 0 ] < N_LEVELS_QGAIN );
+ ec_enc_icdf( psRangeEnc, silk_RSHIFT( psIndices->GainsIndices[ 0 ], 3 ), silk_gain_iCDF[ psIndices->signalType ], 8 );
+ ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ 0 ] & 7, silk_uniform8_iCDF, 8 );
+ }
+
+ /* remaining subframes */
+ for( i = 1; i < psEncC->nb_subfr; i++ ) {
+ silk_assert( psIndices->GainsIndices[ i ] >= 0 && psIndices->GainsIndices[ i ] < MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 );
+ ec_enc_icdf( psRangeEnc, psIndices->GainsIndices[ i ], silk_delta_gain_iCDF, 8 );
+ }
+
+ /****************/
+ /* Encode NLSFs */
+ /****************/
+ ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ 0 ], &psEncC->psNLSF_CB->CB1_iCDF[ ( psIndices->signalType >> 1 ) * psEncC->psNLSF_CB->nVectors ], 8 );
+ silk_NLSF_unpack( ec_ix, pred_Q8, psEncC->psNLSF_CB, psIndices->NLSFIndices[ 0 ] );
+ silk_assert( psEncC->psNLSF_CB->order == psEncC->predictLPCOrder );
+ for( i = 0; i < psEncC->psNLSF_CB->order; i++ ) {
+ if( psIndices->NLSFIndices[ i+1 ] >= NLSF_QUANT_MAX_AMPLITUDE ) {
+ ec_enc_icdf( psRangeEnc, 2 * NLSF_QUANT_MAX_AMPLITUDE, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 );
+ ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ i+1 ] - NLSF_QUANT_MAX_AMPLITUDE, silk_NLSF_EXT_iCDF, 8 );
+ } else if( psIndices->NLSFIndices[ i+1 ] <= -NLSF_QUANT_MAX_AMPLITUDE ) {
+ ec_enc_icdf( psRangeEnc, 0, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 );
+ ec_enc_icdf( psRangeEnc, -psIndices->NLSFIndices[ i+1 ] - NLSF_QUANT_MAX_AMPLITUDE, silk_NLSF_EXT_iCDF, 8 );
+ } else {
+ ec_enc_icdf( psRangeEnc, psIndices->NLSFIndices[ i+1 ] + NLSF_QUANT_MAX_AMPLITUDE, &psEncC->psNLSF_CB->ec_iCDF[ ec_ix[ i ] ], 8 );
+ }
+ }
+
+ /* Encode NLSF interpolation factor */
+ if( psEncC->nb_subfr == MAX_NB_SUBFR ) {
+ silk_assert( psIndices->NLSFInterpCoef_Q2 >= 0 && psIndices->NLSFInterpCoef_Q2 < 5 );
+ ec_enc_icdf( psRangeEnc, psIndices->NLSFInterpCoef_Q2, silk_NLSF_interpolation_factor_iCDF, 8 );
+ }
+
+ if( psIndices->signalType == TYPE_VOICED )
+ {
+ /*********************/
+ /* Encode pitch lags */
+ /*********************/
+ /* lag index */
+ encode_absolute_lagIndex = 1;
+ if( condCoding == CODE_CONDITIONALLY && psEncC->ec_prevSignalType == TYPE_VOICED ) {
+ /* Delta Encoding */
+ delta_lagIndex = psIndices->lagIndex - psEncC->ec_prevLagIndex;
+ if( delta_lagIndex < -8 || delta_lagIndex > 11 ) {
+ delta_lagIndex = 0;
+ } else {
+ delta_lagIndex = delta_lagIndex + 9;
+ encode_absolute_lagIndex = 0; /* Only use delta */
+ }
+ silk_assert( delta_lagIndex >= 0 && delta_lagIndex < 21 );
+ ec_enc_icdf( psRangeEnc, delta_lagIndex, silk_pitch_delta_iCDF, 8 );
+ }
+ if( encode_absolute_lagIndex ) {
+ /* Absolute encoding */
+ opus_int32 pitch_high_bits, pitch_low_bits;
+ pitch_high_bits = silk_DIV32_16( psIndices->lagIndex, silk_RSHIFT( psEncC->fs_kHz, 1 ) );
+ pitch_low_bits = psIndices->lagIndex - silk_SMULBB( pitch_high_bits, silk_RSHIFT( psEncC->fs_kHz, 1 ) );
+ silk_assert( pitch_low_bits < psEncC->fs_kHz / 2 );
+ silk_assert( pitch_high_bits < 32 );
+ ec_enc_icdf( psRangeEnc, pitch_high_bits, silk_pitch_lag_iCDF, 8 );
+ ec_enc_icdf( psRangeEnc, pitch_low_bits, psEncC->pitch_lag_low_bits_iCDF, 8 );
+ }
+ psEncC->ec_prevLagIndex = psIndices->lagIndex;
+
+ /* Countour index */
+ silk_assert( psIndices->contourIndex >= 0 );
+ silk_assert( ( psIndices->contourIndex < 34 && psEncC->fs_kHz > 8 && psEncC->nb_subfr == 4 ) ||
+ ( psIndices->contourIndex < 11 && psEncC->fs_kHz == 8 && psEncC->nb_subfr == 4 ) ||
+ ( psIndices->contourIndex < 12 && psEncC->fs_kHz > 8 && psEncC->nb_subfr == 2 ) ||
+ ( psIndices->contourIndex < 3 && psEncC->fs_kHz == 8 && psEncC->nb_subfr == 2 ) );
+ ec_enc_icdf( psRangeEnc, psIndices->contourIndex, psEncC->pitch_contour_iCDF, 8 );
+
+ /********************/
+ /* Encode LTP gains */
+ /********************/
+ /* PERIndex value */
+ silk_assert( psIndices->PERIndex >= 0 && psIndices->PERIndex < 3 );
+ ec_enc_icdf( psRangeEnc, psIndices->PERIndex, silk_LTP_per_index_iCDF, 8 );
+
+ /* Codebook Indices */
+ for( k = 0; k < psEncC->nb_subfr; k++ ) {
+ silk_assert( psIndices->LTPIndex[ k ] >= 0 && psIndices->LTPIndex[ k ] < ( 8 << psIndices->PERIndex ) );
+ ec_enc_icdf( psRangeEnc, psIndices->LTPIndex[ k ], silk_LTP_gain_iCDF_ptrs[ psIndices->PERIndex ], 8 );
+ }
+
+ /**********************/
+ /* Encode LTP scaling */
+ /**********************/
+ if( condCoding == CODE_INDEPENDENTLY ) {
+ silk_assert( psIndices->LTP_scaleIndex >= 0 && psIndices->LTP_scaleIndex < 3 );
+ ec_enc_icdf( psRangeEnc, psIndices->LTP_scaleIndex, silk_LTPscale_iCDF, 8 );
+ }
+ silk_assert( !condCoding || psIndices->LTP_scaleIndex == 0 );
+ }
+
+ psEncC->ec_prevSignalType = psIndices->signalType;
+
+ /***************/
+ /* Encode seed */
+ /***************/
+ silk_assert( psIndices->Seed >= 0 && psIndices->Seed < 4 );
+ ec_enc_icdf( psRangeEnc, psIndices->Seed, silk_uniform4_iCDF, 8 );
+}
diff --git a/drivers/opus/silk/encode_pulses.c b/drivers/opus/silk/encode_pulses.c
new file mode 100644
index 0000000000..f9fe39eeb8
--- /dev/null
+++ b/drivers/opus/silk/encode_pulses.c
@@ -0,0 +1,206 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+#include "opus/celt/stack_alloc.h"
+
+/*********************************************/
+/* Encode quantization indices of excitation */
+/*********************************************/
+
+static OPUS_INLINE opus_int combine_and_check( /* return ok */
+ opus_int *pulses_comb, /* O */
+ const opus_int *pulses_in, /* I */
+ opus_int max_pulses, /* I max value for sum of pulses */
+ opus_int len /* I number of output values */
+)
+{
+ opus_int k, sum;
+
+ for( k = 0; k < len; k++ ) {
+ sum = pulses_in[ 2 * k ] + pulses_in[ 2 * k + 1 ];
+ if( sum > max_pulses ) {
+ return 1;
+ }
+ pulses_comb[ k ] = sum;
+ }
+
+ return 0;
+}
+
+/* Encode quantization indices of excitation */
+void silk_encode_pulses(
+ ec_enc *psRangeEnc, /* I/O compressor data structure */
+ const opus_int signalType, /* I Signal type */
+ const opus_int quantOffsetType, /* I quantOffsetType */
+ opus_int8 pulses[], /* I quantization indices */
+ const opus_int frame_length /* I Frame length */
+)
+{
+ opus_int i, k, j, iter, bit, nLS, scale_down, RateLevelIndex = 0;
+ opus_int32 abs_q, minSumBits_Q5, sumBits_Q5;
+ VARDECL( opus_int, abs_pulses );
+ VARDECL( opus_int, sum_pulses );
+ VARDECL( opus_int, nRshifts );
+ opus_int pulses_comb[ 8 ];
+ opus_int *abs_pulses_ptr;
+ const opus_int8 *pulses_ptr;
+ const opus_uint8 *cdf_ptr;
+ const opus_uint8 *nBits_ptr;
+ SAVE_STACK;
+
+ silk_memset( pulses_comb, 0, 8 * sizeof( opus_int ) ); /* Fixing Valgrind reported problem*/
+
+ /****************************/
+ /* Prepare for shell coding */
+ /****************************/
+ /* Calculate number of shell blocks */
+ silk_assert( 1 << LOG2_SHELL_CODEC_FRAME_LENGTH == SHELL_CODEC_FRAME_LENGTH );
+ iter = silk_RSHIFT( frame_length, LOG2_SHELL_CODEC_FRAME_LENGTH );
+ if( iter * SHELL_CODEC_FRAME_LENGTH < frame_length ) {
+ silk_assert( frame_length == 12 * 10 ); /* Make sure only happens for 10 ms @ 12 kHz */
+ iter++;
+ silk_memset( &pulses[ frame_length ], 0, SHELL_CODEC_FRAME_LENGTH * sizeof(opus_int8));
+ }
+
+ /* Take the absolute value of the pulses */
+ ALLOC( abs_pulses, iter * SHELL_CODEC_FRAME_LENGTH, opus_int );
+ silk_assert( !( SHELL_CODEC_FRAME_LENGTH & 3 ) );
+ for( i = 0; i < iter * SHELL_CODEC_FRAME_LENGTH; i+=4 ) {
+ abs_pulses[i+0] = ( opus_int )silk_abs( pulses[ i + 0 ] );
+ abs_pulses[i+1] = ( opus_int )silk_abs( pulses[ i + 1 ] );
+ abs_pulses[i+2] = ( opus_int )silk_abs( pulses[ i + 2 ] );
+ abs_pulses[i+3] = ( opus_int )silk_abs( pulses[ i + 3 ] );
+ }
+
+ /* Calc sum pulses per shell code frame */
+ ALLOC( sum_pulses, iter, opus_int );
+ ALLOC( nRshifts, iter, opus_int );
+ abs_pulses_ptr = abs_pulses;
+ for( i = 0; i < iter; i++ ) {
+ nRshifts[ i ] = 0;
+
+ while( 1 ) {
+ /* 1+1 -> 2 */
+ scale_down = combine_and_check( pulses_comb, abs_pulses_ptr, silk_max_pulses_table[ 0 ], 8 );
+ /* 2+2 -> 4 */
+ scale_down += combine_and_check( pulses_comb, pulses_comb, silk_max_pulses_table[ 1 ], 4 );
+ /* 4+4 -> 8 */
+ scale_down += combine_and_check( pulses_comb, pulses_comb, silk_max_pulses_table[ 2 ], 2 );
+ /* 8+8 -> 16 */
+ scale_down += combine_and_check( &sum_pulses[ i ], pulses_comb, silk_max_pulses_table[ 3 ], 1 );
+
+ if( scale_down ) {
+ /* We need to downscale the quantization signal */
+ nRshifts[ i ]++;
+ for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) {
+ abs_pulses_ptr[ k ] = silk_RSHIFT( abs_pulses_ptr[ k ], 1 );
+ }
+ } else {
+ /* Jump out of while(1) loop and go to next shell coding frame */
+ break;
+ }
+ }
+ abs_pulses_ptr += SHELL_CODEC_FRAME_LENGTH;
+ }
+
+ /**************/
+ /* Rate level */
+ /**************/
+ /* find rate level that leads to fewest bits for coding of pulses per block info */
+ minSumBits_Q5 = silk_int32_MAX;
+ for( k = 0; k < N_RATE_LEVELS - 1; k++ ) {
+ nBits_ptr = silk_pulses_per_block_BITS_Q5[ k ];
+ sumBits_Q5 = silk_rate_levels_BITS_Q5[ signalType >> 1 ][ k ];
+ for( i = 0; i < iter; i++ ) {
+ if( nRshifts[ i ] > 0 ) {
+ sumBits_Q5 += nBits_ptr[ MAX_PULSES + 1 ];
+ } else {
+ sumBits_Q5 += nBits_ptr[ sum_pulses[ i ] ];
+ }
+ }
+ if( sumBits_Q5 < minSumBits_Q5 ) {
+ minSumBits_Q5 = sumBits_Q5;
+ RateLevelIndex = k;
+ }
+ }
+ ec_enc_icdf( psRangeEnc, RateLevelIndex, silk_rate_levels_iCDF[ signalType >> 1 ], 8 );
+
+ /***************************************************/
+ /* Sum-Weighted-Pulses Encoding */
+ /***************************************************/
+ cdf_ptr = silk_pulses_per_block_iCDF[ RateLevelIndex ];
+ for( i = 0; i < iter; i++ ) {
+ if( nRshifts[ i ] == 0 ) {
+ ec_enc_icdf( psRangeEnc, sum_pulses[ i ], cdf_ptr, 8 );
+ } else {
+ ec_enc_icdf( psRangeEnc, MAX_PULSES + 1, cdf_ptr, 8 );
+ for( k = 0; k < nRshifts[ i ] - 1; k++ ) {
+ ec_enc_icdf( psRangeEnc, MAX_PULSES + 1, silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1 ], 8 );
+ }
+ ec_enc_icdf( psRangeEnc, sum_pulses[ i ], silk_pulses_per_block_iCDF[ N_RATE_LEVELS - 1 ], 8 );
+ }
+ }
+
+ /******************/
+ /* Shell Encoding */
+ /******************/
+ for( i = 0; i < iter; i++ ) {
+ if( sum_pulses[ i ] > 0 ) {
+ silk_shell_encoder( psRangeEnc, &abs_pulses[ i * SHELL_CODEC_FRAME_LENGTH ] );
+ }
+ }
+
+ /****************/
+ /* LSB Encoding */
+ /****************/
+ for( i = 0; i < iter; i++ ) {
+ if( nRshifts[ i ] > 0 ) {
+ pulses_ptr = &pulses[ i * SHELL_CODEC_FRAME_LENGTH ];
+ nLS = nRshifts[ i ] - 1;
+ for( k = 0; k < SHELL_CODEC_FRAME_LENGTH; k++ ) {
+ abs_q = (opus_int8)silk_abs( pulses_ptr[ k ] );
+ for( j = nLS; j > 0; j-- ) {
+ bit = silk_RSHIFT( abs_q, j ) & 1;
+ ec_enc_icdf( psRangeEnc, bit, silk_lsb_iCDF, 8 );
+ }
+ bit = abs_q & 1;
+ ec_enc_icdf( psRangeEnc, bit, silk_lsb_iCDF, 8 );
+ }
+ }
+ }
+
+ /****************/
+ /* Encode signs */
+ /****************/
+ silk_encode_signs( psRangeEnc, pulses, frame_length, signalType, quantOffsetType, sum_pulses );
+ RESTORE_STACK;
+}
diff --git a/drivers/opus/silk/errors.h b/drivers/opus/silk/errors.h
new file mode 100644
index 0000000000..45070800f2
--- /dev/null
+++ b/drivers/opus/silk/errors.h
@@ -0,0 +1,98 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_ERRORS_H
+#define SILK_ERRORS_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/******************/
+/* Error messages */
+/******************/
+#define SILK_NO_ERROR 0
+
+/**************************/
+/* Encoder error messages */
+/**************************/
+
+/* Input length is not a multiple of 10 ms, or length is longer than the packet length */
+#define SILK_ENC_INPUT_INVALID_NO_OF_SAMPLES -101
+
+/* Sampling frequency not 8000, 12000 or 16000 Hertz */
+#define SILK_ENC_FS_NOT_SUPPORTED -102
+
+/* Packet size not 10, 20, 40, or 60 ms */
+#define SILK_ENC_PACKET_SIZE_NOT_SUPPORTED -103
+
+/* Allocated payload buffer too short */
+#define SILK_ENC_PAYLOAD_BUF_TOO_SHORT -104
+
+/* Loss rate not between 0 and 100 percent */
+#define SILK_ENC_INVALID_LOSS_RATE -105
+
+/* Complexity setting not valid, use 0...10 */
+#define SILK_ENC_INVALID_COMPLEXITY_SETTING -106
+
+/* Inband FEC setting not valid, use 0 or 1 */
+#define SILK_ENC_INVALID_INBAND_FEC_SETTING -107
+
+/* DTX setting not valid, use 0 or 1 */
+#define SILK_ENC_INVALID_DTX_SETTING -108
+
+/* CBR setting not valid, use 0 or 1 */
+#define SILK_ENC_INVALID_CBR_SETTING -109
+
+/* Internal encoder error */
+#define SILK_ENC_INTERNAL_ERROR -110
+
+/* Internal encoder error */
+#define SILK_ENC_INVALID_NUMBER_OF_CHANNELS_ERROR -111
+
+/**************************/
+/* Decoder error messages */
+/**************************/
+
+/* Output sampling frequency lower than internal decoded sampling frequency */
+#define SILK_DEC_INVALID_SAMPLING_FREQUENCY -200
+
+/* Payload size exceeded the maximum allowed 1024 bytes */
+#define SILK_DEC_PAYLOAD_TOO_LARGE -201
+
+/* Payload has bit errors */
+#define SILK_DEC_PAYLOAD_ERROR -202
+
+/* Payload has bit errors */
+#define SILK_DEC_INVALID_FRAME_SIZE -203
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/opus/silk/fixed/LTP_analysis_filter_FIX.c b/drivers/opus/silk/fixed/LTP_analysis_filter_FIX.c
new file mode 100644
index 0000000000..19d5defc7a
--- /dev/null
+++ b/drivers/opus/silk/fixed/LTP_analysis_filter_FIX.c
@@ -0,0 +1,85 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/fixed/main_FIX.h"
+
+void silk_LTP_analysis_filter_FIX(
+ opus_int16 *LTP_res, /* O LTP residual signal of length MAX_NB_SUBFR * ( pre_length + subfr_length ) */
+ const opus_int16 *x, /* I Pointer to input signal with at least max( pitchL ) preceding samples */
+ const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],/* I LTP_ORDER LTP coefficients for each MAX_NB_SUBFR subframe */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag, one for each subframe */
+ const opus_int32 invGains_Q16[ MAX_NB_SUBFR ], /* I Inverse quantization gains, one for each subframe */
+ const opus_int subfr_length, /* I Length of each subframe */
+ const opus_int nb_subfr, /* I Number of subframes */
+ const opus_int pre_length /* I Length of the preceding samples starting at &x[0] for each subframe */
+)
+{
+ const opus_int16 *x_ptr, *x_lag_ptr;
+ opus_int16 Btmp_Q14[ LTP_ORDER ];
+ opus_int16 *LTP_res_ptr;
+ opus_int k, i, j;
+ opus_int32 LTP_est;
+
+ x_ptr = x;
+ LTP_res_ptr = LTP_res;
+ for( k = 0; k < nb_subfr; k++ ) {
+
+ x_lag_ptr = x_ptr - pitchL[ k ];
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ Btmp_Q14[ i ] = LTPCoef_Q14[ k * LTP_ORDER + i ];
+ }
+
+ /* LTP analysis FIR filter */
+ for( i = 0; i < subfr_length + pre_length; i++ ) {
+ LTP_res_ptr[ i ] = x_ptr[ i ];
+
+ /* Long-term prediction */
+ LTP_est = silk_SMULBB( x_lag_ptr[ LTP_ORDER / 2 ], Btmp_Q14[ 0 ] );
+ for( j = 1; j < LTP_ORDER; j++ ) {
+ LTP_est = silk_SMLABB_ovflw( LTP_est, x_lag_ptr[ LTP_ORDER / 2 - j ], Btmp_Q14[ j ] );
+ }
+ LTP_est = silk_RSHIFT_ROUND( LTP_est, 14 ); /* round and -> Q0*/
+
+ /* Subtract long-term prediction */
+ LTP_res_ptr[ i ] = (opus_int16)silk_SAT16( (opus_int32)x_ptr[ i ] - LTP_est );
+
+ /* Scale residual */
+ LTP_res_ptr[ i ] = silk_SMULWB( invGains_Q16[ k ], LTP_res_ptr[ i ] );
+
+ x_lag_ptr++;
+ }
+
+ /* Update pointers */
+ LTP_res_ptr += subfr_length + pre_length;
+ x_ptr += subfr_length;
+ }
+}
+
diff --git a/drivers/opus/silk/fixed/LTP_scale_ctrl_FIX.c b/drivers/opus/silk/fixed/LTP_scale_ctrl_FIX.c
new file mode 100644
index 0000000000..0887fd03f7
--- /dev/null
+++ b/drivers/opus/silk/fixed/LTP_scale_ctrl_FIX.c
@@ -0,0 +1,53 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/fixed/main_FIX.h"
+
+/* Calculation of LTP state scaling */
+void silk_LTP_scale_ctrl_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */
+ opus_int condCoding /* I The type of conditional coding to use */
+)
+{
+ opus_int round_loss;
+
+ if( condCoding == CODE_INDEPENDENTLY ) {
+ /* Only scale if first frame in packet */
+ round_loss = psEnc->sCmn.PacketLoss_perc + psEnc->sCmn.nFramesPerPacket;
+ psEnc->sCmn.indices.LTP_scaleIndex = (opus_int8)silk_LIMIT(
+ silk_SMULWB( silk_SMULBB( round_loss, psEncCtrl->LTPredCodGain_Q7 ), SILK_FIX_CONST( 0.1, 9 ) ), 0, 2 );
+ } else {
+ /* Default is minimum scaling */
+ psEnc->sCmn.indices.LTP_scaleIndex = 0;
+ }
+ psEncCtrl->LTP_scale_Q14 = silk_LTPScales_table_Q14[ psEnc->sCmn.indices.LTP_scaleIndex ];
+}
diff --git a/drivers/opus/silk/fixed/apply_sine_window_FIX.c b/drivers/opus/silk/fixed/apply_sine_window_FIX.c
new file mode 100644
index 0000000000..5b4d8ebfdc
--- /dev/null
+++ b/drivers/opus/silk/fixed/apply_sine_window_FIX.c
@@ -0,0 +1,101 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/SigProc_FIX.h"
+
+/* Apply sine window to signal vector. */
+/* Window types: */
+/* 1 -> sine window from 0 to pi/2 */
+/* 2 -> sine window from pi/2 to pi */
+/* Every other sample is linearly interpolated, for speed. */
+/* Window length must be between 16 and 120 (incl) and a multiple of 4. */
+
+/* Matlab code for table:
+ for k=16:9*4:16+2*9*4, fprintf(' %7.d,', -round(65536*pi ./ (k:4:k+8*4))); fprintf('\n'); end
+*/
+static const opus_int16 freq_table_Q16[ 27 ] = {
+ 12111, 9804, 8235, 7100, 6239, 5565, 5022, 4575, 4202,
+ 3885, 3612, 3375, 3167, 2984, 2820, 2674, 2542, 2422,
+ 2313, 2214, 2123, 2038, 1961, 1889, 1822, 1760, 1702,
+};
+
+void silk_apply_sine_window(
+ opus_int16 px_win[], /* O Pointer to windowed signal */
+ const opus_int16 px[], /* I Pointer to input signal */
+ const opus_int win_type, /* I Selects a window type */
+ const opus_int length /* I Window length, multiple of 4 */
+)
+{
+ opus_int k, f_Q16, c_Q16;
+ opus_int32 S0_Q16, S1_Q16;
+
+ silk_assert( win_type == 1 || win_type == 2 );
+
+ /* Length must be in a range from 16 to 120 and a multiple of 4 */
+ silk_assert( length >= 16 && length <= 120 );
+ silk_assert( ( length & 3 ) == 0 );
+
+ /* Frequency */
+ k = ( length >> 2 ) - 4;
+ silk_assert( k >= 0 && k <= 26 );
+ f_Q16 = (opus_int)freq_table_Q16[ k ];
+
+ /* Factor used for cosine approximation */
+ c_Q16 = silk_SMULWB( (opus_int32)f_Q16, -f_Q16 );
+ silk_assert( c_Q16 >= -32768 );
+
+ /* initialize state */
+ if( win_type == 1 ) {
+ /* start from 0 */
+ S0_Q16 = 0;
+ /* approximation of sin(f) */
+ S1_Q16 = f_Q16 + silk_RSHIFT( length, 3 );
+ } else {
+ /* start from 1 */
+ S0_Q16 = ( (opus_int32)1 << 16 );
+ /* approximation of cos(f) */
+ S1_Q16 = ( (opus_int32)1 << 16 ) + silk_RSHIFT( c_Q16, 1 ) + silk_RSHIFT( length, 4 );
+ }
+
+ /* Uses the recursive equation: sin(n*f) = 2 * cos(f) * sin((n-1)*f) - sin((n-2)*f) */
+ /* 4 samples at a time */
+ for( k = 0; k < length; k += 4 ) {
+ px_win[ k ] = (opus_int16)silk_SMULWB( silk_RSHIFT( S0_Q16 + S1_Q16, 1 ), px[ k ] );
+ px_win[ k + 1 ] = (opus_int16)silk_SMULWB( S1_Q16, px[ k + 1] );
+ S0_Q16 = silk_SMULWB( S1_Q16, c_Q16 ) + silk_LSHIFT( S1_Q16, 1 ) - S0_Q16 + 1;
+ S0_Q16 = silk_min( S0_Q16, ( (opus_int32)1 << 16 ) );
+
+ px_win[ k + 2 ] = (opus_int16)silk_SMULWB( silk_RSHIFT( S0_Q16 + S1_Q16, 1 ), px[ k + 2] );
+ px_win[ k + 3 ] = (opus_int16)silk_SMULWB( S0_Q16, px[ k + 3 ] );
+ S1_Q16 = silk_SMULWB( S0_Q16, c_Q16 ) + silk_LSHIFT( S0_Q16, 1 ) - S1_Q16;
+ S1_Q16 = silk_min( S1_Q16, ( (opus_int32)1 << 16 ) );
+ }
+}
diff --git a/drivers/opus/silk/fixed/autocorr_FIX.c b/drivers/opus/silk/fixed/autocorr_FIX.c
new file mode 100644
index 0000000000..88a849e12c
--- /dev/null
+++ b/drivers/opus/silk/fixed/autocorr_FIX.c
@@ -0,0 +1,48 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/SigProc_FIX.h"
+#include "opus/celt/celt_lpc.h"
+
+/* Compute autocorrelation */
+void silk_autocorr(
+ opus_int32 *results, /* O Result (length correlationCount) */
+ opus_int *scale, /* O Scaling of the correlation vector */
+ const opus_int16 *inputData, /* I Input data to correlate */
+ const opus_int inputDataSize, /* I Length of input */
+ const opus_int correlationCount, /* I Number of correlation taps to compute */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int corrCount;
+ corrCount = silk_min_int( inputDataSize, correlationCount );
+ *scale = _celt_autocorr(inputData, results, NULL, 0, corrCount-1, inputDataSize, arch);
+}
diff --git a/drivers/opus/silk/fixed/burg_modified_FIX.c b/drivers/opus/silk/fixed/burg_modified_FIX.c
new file mode 100644
index 0000000000..5ef3ad2c38
--- /dev/null
+++ b/drivers/opus/silk/fixed/burg_modified_FIX.c
@@ -0,0 +1,279 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/SigProc_FIX.h"
+#include "opus/silk/define.h"
+#include "opus/silk/tuning_parameters.h"
+#include "opus/celt/pitch.h"
+
+#define MAX_FRAME_SIZE 384 /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384 */
+
+#define QA 25
+#define N_BITS_HEAD_ROOM 2
+#define MIN_RSHIFTS -16
+#define MAX_RSHIFTS (32 - QA)
+
+/* Compute reflection coefficients from input signal */
+void silk_burg_modified(
+ opus_int32 *res_nrg, /* O Residual energy */
+ opus_int *res_nrg_Q, /* O Residual energy Q value */
+ opus_int32 A_Q16[], /* O Prediction coefficients (length order) */
+ const opus_int16 x[], /* I Input signal, length: nb_subfr * ( D + subfr_length ) */
+ const opus_int32 minInvGain_Q30, /* I Inverse of max prediction gain */
+ const opus_int subfr_length, /* I Input signal subframe length (incl. D preceding samples) */
+ const opus_int nb_subfr, /* I Number of subframes stacked in x */
+ const opus_int D, /* I Order */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int k, n, s, lz, rshifts, rshifts_extra, reached_max_gain;
+ opus_int32 C0, num, nrg, rc_Q31, invGain_Q30, Atmp_QA, Atmp1, tmp1, tmp2, x1, x2;
+ const opus_int16 *x_ptr;
+ opus_int32 C_first_row[ SILK_MAX_ORDER_LPC ];
+ opus_int32 C_last_row[ SILK_MAX_ORDER_LPC ];
+ opus_int32 Af_QA[ SILK_MAX_ORDER_LPC ];
+ opus_int32 CAf[ SILK_MAX_ORDER_LPC + 1 ];
+ opus_int32 CAb[ SILK_MAX_ORDER_LPC + 1 ];
+ opus_int32 xcorr[ SILK_MAX_ORDER_LPC ];
+
+ silk_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE );
+
+ /* Compute autocorrelations, added over subframes */
+ silk_sum_sqr_shift( &C0, &rshifts, x, nb_subfr * subfr_length );
+ if( rshifts > MAX_RSHIFTS ) {
+ C0 = silk_LSHIFT32( C0, rshifts - MAX_RSHIFTS );
+ silk_assert( C0 > 0 );
+ rshifts = MAX_RSHIFTS;
+ } else {
+ lz = silk_CLZ32( C0 ) - 1;
+ rshifts_extra = N_BITS_HEAD_ROOM - lz;
+ if( rshifts_extra > 0 ) {
+ rshifts_extra = silk_min( rshifts_extra, MAX_RSHIFTS - rshifts );
+ C0 = silk_RSHIFT32( C0, rshifts_extra );
+ } else {
+ rshifts_extra = silk_max( rshifts_extra, MIN_RSHIFTS - rshifts );
+ C0 = silk_LSHIFT32( C0, -rshifts_extra );
+ }
+ rshifts += rshifts_extra;
+ }
+ CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */
+ silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) );
+ if( rshifts > 0 ) {
+ for( s = 0; s < nb_subfr; s++ ) {
+ x_ptr = x + s * subfr_length;
+ for( n = 1; n < D + 1; n++ ) {
+ C_first_row[ n - 1 ] += (opus_int32)silk_RSHIFT64(
+ silk_inner_prod16_aligned_64( x_ptr, x_ptr + n, subfr_length - n ), rshifts );
+ }
+ }
+ } else {
+ for( s = 0; s < nb_subfr; s++ ) {
+ int i;
+ opus_int32 d;
+ x_ptr = x + s * subfr_length;
+ celt_pitch_xcorr(x_ptr, x_ptr + 1, xcorr, subfr_length - D, D, arch );
+ for( n = 1; n < D + 1; n++ ) {
+ for ( i = n + subfr_length - D, d = 0; i < subfr_length; i++ )
+ d = MAC16_16( d, x_ptr[ i ], x_ptr[ i - n ] );
+ xcorr[ n - 1 ] += d;
+ }
+ for( n = 1; n < D + 1; n++ ) {
+ C_first_row[ n - 1 ] += silk_LSHIFT32( xcorr[ n - 1 ], -rshifts );
+ }
+ }
+ }
+ silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( opus_int32 ) );
+
+ /* Initialize */
+ CAb[ 0 ] = CAf[ 0 ] = C0 + silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ) + 1; /* Q(-rshifts) */
+
+ invGain_Q30 = (opus_int32)1 << 30;
+ reached_max_gain = 0;
+ for( n = 0; n < D; n++ ) {
+ /* Update first row of correlation matrix (without first element) */
+ /* Update last row of correlation matrix (without last element, stored in reversed order) */
+ /* Update C * Af */
+ /* Update C * flipud(Af) (stored in reversed order) */
+ if( rshifts > -2 ) {
+ for( s = 0; s < nb_subfr; s++ ) {
+ x_ptr = x + s * subfr_length;
+ x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], 16 - rshifts ); /* Q(16-rshifts) */
+ x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 16 - rshifts ); /* Q(16-rshifts) */
+ tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], QA - 16 ); /* Q(QA-16) */
+ tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], QA - 16 ); /* Q(QA-16) */
+ for( k = 0; k < n; k++ ) {
+ C_first_row[ k ] = silk_SMLAWB( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */
+ C_last_row[ k ] = silk_SMLAWB( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */
+ Atmp_QA = Af_QA[ k ];
+ tmp1 = silk_SMLAWB( tmp1, Atmp_QA, x_ptr[ n - k - 1 ] ); /* Q(QA-16) */
+ tmp2 = silk_SMLAWB( tmp2, Atmp_QA, x_ptr[ subfr_length - n + k ] ); /* Q(QA-16) */
+ }
+ tmp1 = silk_LSHIFT32( -tmp1, 32 - QA - rshifts ); /* Q(16-rshifts) */
+ tmp2 = silk_LSHIFT32( -tmp2, 32 - QA - rshifts ); /* Q(16-rshifts) */
+ for( k = 0; k <= n; k++ ) {
+ CAf[ k ] = silk_SMLAWB( CAf[ k ], tmp1, x_ptr[ n - k ] ); /* Q( -rshift ) */
+ CAb[ k ] = silk_SMLAWB( CAb[ k ], tmp2, x_ptr[ subfr_length - n + k - 1 ] ); /* Q( -rshift ) */
+ }
+ }
+ } else {
+ for( s = 0; s < nb_subfr; s++ ) {
+ x_ptr = x + s * subfr_length;
+ x1 = -silk_LSHIFT32( (opus_int32)x_ptr[ n ], -rshifts ); /* Q( -rshifts ) */
+ x2 = -silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], -rshifts ); /* Q( -rshifts ) */
+ tmp1 = silk_LSHIFT32( (opus_int32)x_ptr[ n ], 17 ); /* Q17 */
+ tmp2 = silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n - 1 ], 17 ); /* Q17 */
+ for( k = 0; k < n; k++ ) {
+ C_first_row[ k ] = silk_MLA( C_first_row[ k ], x1, x_ptr[ n - k - 1 ] ); /* Q( -rshifts ) */
+ C_last_row[ k ] = silk_MLA( C_last_row[ k ], x2, x_ptr[ subfr_length - n + k ] ); /* Q( -rshifts ) */
+ Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 17 ); /* Q17 */
+ tmp1 = silk_MLA( tmp1, x_ptr[ n - k - 1 ], Atmp1 ); /* Q17 */
+ tmp2 = silk_MLA( tmp2, x_ptr[ subfr_length - n + k ], Atmp1 ); /* Q17 */
+ }
+ tmp1 = -tmp1; /* Q17 */
+ tmp2 = -tmp2; /* Q17 */
+ for( k = 0; k <= n; k++ ) {
+ CAf[ k ] = silk_SMLAWW( CAf[ k ], tmp1,
+ silk_LSHIFT32( (opus_int32)x_ptr[ n - k ], -rshifts - 1 ) ); /* Q( -rshift ) */
+ CAb[ k ] = silk_SMLAWW( CAb[ k ], tmp2,
+ silk_LSHIFT32( (opus_int32)x_ptr[ subfr_length - n + k - 1 ], -rshifts - 1 ) ); /* Q( -rshift ) */
+ }
+ }
+ }
+
+ /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */
+ tmp1 = C_first_row[ n ]; /* Q( -rshifts ) */
+ tmp2 = C_last_row[ n ]; /* Q( -rshifts ) */
+ num = 0; /* Q( -rshifts ) */
+ nrg = silk_ADD32( CAb[ 0 ], CAf[ 0 ] ); /* Q( 1-rshifts ) */
+ for( k = 0; k < n; k++ ) {
+ Atmp_QA = Af_QA[ k ];
+ lz = silk_CLZ32( silk_abs( Atmp_QA ) ) - 1;
+ lz = silk_min( 32 - QA, lz );
+ Atmp1 = silk_LSHIFT32( Atmp_QA, lz ); /* Q( QA + lz ) */
+
+ tmp1 = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( C_last_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */
+ tmp2 = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( C_first_row[ n - k - 1 ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */
+ num = silk_ADD_LSHIFT32( num, silk_SMMUL( CAb[ n - k ], Atmp1 ), 32 - QA - lz ); /* Q( -rshifts ) */
+ nrg = silk_ADD_LSHIFT32( nrg, silk_SMMUL( silk_ADD32( CAb[ k + 1 ], CAf[ k + 1 ] ),
+ Atmp1 ), 32 - QA - lz ); /* Q( 1-rshifts ) */
+ }
+ CAf[ n + 1 ] = tmp1; /* Q( -rshifts ) */
+ CAb[ n + 1 ] = tmp2; /* Q( -rshifts ) */
+ num = silk_ADD32( num, tmp2 ); /* Q( -rshifts ) */
+ num = silk_LSHIFT32( -num, 1 ); /* Q( 1-rshifts ) */
+
+ /* Calculate the next order reflection (parcor) coefficient */
+ if( silk_abs( num ) < nrg ) {
+ rc_Q31 = silk_DIV32_varQ( num, nrg, 31 );
+ } else {
+ rc_Q31 = ( num > 0 ) ? silk_int32_MAX : silk_int32_MIN;
+ }
+
+ /* Update inverse prediction gain */
+ tmp1 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 );
+ tmp1 = silk_LSHIFT( silk_SMMUL( invGain_Q30, tmp1 ), 2 );
+ if( tmp1 <= minInvGain_Q30 ) {
+ /* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */
+ tmp2 = ( (opus_int32)1 << 30 ) - silk_DIV32_varQ( minInvGain_Q30, invGain_Q30, 30 ); /* Q30 */
+ rc_Q31 = silk_SQRT_APPROX( tmp2 ); /* Q15 */
+ /* Newton-Raphson iteration */
+ rc_Q31 = silk_RSHIFT32( rc_Q31 + silk_DIV32( tmp2, rc_Q31 ), 1 ); /* Q15 */
+ rc_Q31 = silk_LSHIFT32( rc_Q31, 16 ); /* Q31 */
+ if( num < 0 ) {
+ /* Ensure adjusted reflection coefficients has the original sign */
+ rc_Q31 = -rc_Q31;
+ }
+ invGain_Q30 = minInvGain_Q30;
+ reached_max_gain = 1;
+ } else {
+ invGain_Q30 = tmp1;
+ }
+
+ /* Update the AR coefficients */
+ for( k = 0; k < (n + 1) >> 1; k++ ) {
+ tmp1 = Af_QA[ k ]; /* QA */
+ tmp2 = Af_QA[ n - k - 1 ]; /* QA */
+ Af_QA[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* QA */
+ Af_QA[ n - k - 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* QA */
+ }
+ Af_QA[ n ] = silk_RSHIFT32( rc_Q31, 31 - QA ); /* QA */
+
+ if( reached_max_gain ) {
+ /* Reached max prediction gain; set remaining coefficients to zero and exit loop */
+ for( k = n + 1; k < D; k++ ) {
+ Af_QA[ k ] = 0;
+ }
+ break;
+ }
+
+ /* Update C * Af and C * Ab */
+ for( k = 0; k <= n + 1; k++ ) {
+ tmp1 = CAf[ k ]; /* Q( -rshifts ) */
+ tmp2 = CAb[ n - k + 1 ]; /* Q( -rshifts ) */
+ CAf[ k ] = silk_ADD_LSHIFT32( tmp1, silk_SMMUL( tmp2, rc_Q31 ), 1 ); /* Q( -rshifts ) */
+ CAb[ n - k + 1 ] = silk_ADD_LSHIFT32( tmp2, silk_SMMUL( tmp1, rc_Q31 ), 1 ); /* Q( -rshifts ) */
+ }
+ }
+
+ if( reached_max_gain ) {
+ for( k = 0; k < D; k++ ) {
+ /* Scale coefficients */
+ A_Q16[ k ] = -silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 );
+ }
+ /* Subtract energy of preceding samples from C0 */
+ if( rshifts > 0 ) {
+ for( s = 0; s < nb_subfr; s++ ) {
+ x_ptr = x + s * subfr_length;
+ C0 -= (opus_int32)silk_RSHIFT64( silk_inner_prod16_aligned_64( x_ptr, x_ptr, D ), rshifts );
+ }
+ } else {
+ for( s = 0; s < nb_subfr; s++ ) {
+ x_ptr = x + s * subfr_length;
+ C0 -= silk_LSHIFT32( silk_inner_prod_aligned( x_ptr, x_ptr, D ), -rshifts );
+ }
+ }
+ /* Approximate residual energy */
+ *res_nrg = silk_LSHIFT( silk_SMMUL( invGain_Q30, C0 ), 2 );
+ *res_nrg_Q = -rshifts;
+ } else {
+ /* Return residual energy */
+ nrg = CAf[ 0 ]; /* Q( -rshifts ) */
+ tmp1 = (opus_int32)1 << 16; /* Q16 */
+ for( k = 0; k < D; k++ ) {
+ Atmp1 = silk_RSHIFT_ROUND( Af_QA[ k ], QA - 16 ); /* Q16 */
+ nrg = silk_SMLAWW( nrg, CAf[ k + 1 ], Atmp1 ); /* Q( -rshifts ) */
+ tmp1 = silk_SMLAWW( tmp1, Atmp1, Atmp1 ); /* Q16 */
+ A_Q16[ k ] = -Atmp1;
+ }
+ *res_nrg = silk_SMLAWW( nrg, silk_SMMUL( SILK_FIX_CONST( FIND_LPC_COND_FAC, 32 ), C0 ), -tmp1 );/* Q( -rshifts ) */
+ *res_nrg_Q = -rshifts;
+ }
+}
diff --git a/drivers/opus/silk/fixed/corrMatrix_FIX.c b/drivers/opus/silk/fixed/corrMatrix_FIX.c
new file mode 100644
index 0000000000..9f50153dcc
--- /dev/null
+++ b/drivers/opus/silk/fixed/corrMatrix_FIX.c
@@ -0,0 +1,156 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+/**********************************************************************
+ * Correlation Matrix Computations for LS estimate.
+ **********************************************************************/
+
+#include "opus/silk/fixed/main_FIX.h"
+
+/* Calculates correlation vector X'*t */
+void silk_corrVector_FIX(
+ const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */
+ const opus_int16 *t, /* I Target vector [L] */
+ const opus_int L, /* I Length of vectors */
+ const opus_int order, /* I Max lag for correlation */
+ opus_int32 *Xt, /* O Pointer to X'*t correlation vector [order] */
+ const opus_int rshifts /* I Right shifts of correlations */
+)
+{
+ opus_int lag, i;
+ const opus_int16 *ptr1, *ptr2;
+ opus_int32 inner_prod;
+
+ ptr1 = &x[ order - 1 ]; /* Points to first sample of column 0 of X: X[:,0] */
+ ptr2 = t;
+ /* Calculate X'*t */
+ if( rshifts > 0 ) {
+ /* Right shifting used */
+ for( lag = 0; lag < order; lag++ ) {
+ inner_prod = 0;
+ for( i = 0; i < L; i++ ) {
+ inner_prod += silk_RSHIFT32( silk_SMULBB( ptr1[ i ], ptr2[i] ), rshifts );
+ }
+ Xt[ lag ] = inner_prod; /* X[:,lag]'*t */
+ ptr1--; /* Go to next column of X */
+ }
+ } else {
+ silk_assert( rshifts == 0 );
+ for( lag = 0; lag < order; lag++ ) {
+ Xt[ lag ] = silk_inner_prod_aligned( ptr1, ptr2, L ); /* X[:,lag]'*t */
+ ptr1--; /* Go to next column of X */
+ }
+ }
+}
+
+/* Calculates correlation matrix X'*X */
+void silk_corrMatrix_FIX(
+ const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */
+ const opus_int L, /* I Length of vectors */
+ const opus_int order, /* I Max lag for correlation */
+ const opus_int head_room, /* I Desired headroom */
+ opus_int32 *XX, /* O Pointer to X'*X correlation matrix [ order x order ] */
+ opus_int *rshifts /* I/O Right shifts of correlations */
+)
+{
+ opus_int i, j, lag, rshifts_local, head_room_rshifts;
+ opus_int32 energy;
+ const opus_int16 *ptr1, *ptr2;
+
+ /* Calculate energy to find shift used to fit in 32 bits */
+ silk_sum_sqr_shift( &energy, &rshifts_local, x, L + order - 1 );
+ /* Add shifts to get the desired head room */
+ head_room_rshifts = silk_max( head_room - silk_CLZ32( energy ), 0 );
+
+ energy = silk_RSHIFT32( energy, head_room_rshifts );
+ rshifts_local += head_room_rshifts;
+
+ /* Calculate energy of first column (0) of X: X[:,0]'*X[:,0] */
+ /* Remove contribution of first order - 1 samples */
+ for( i = 0; i < order - 1; i++ ) {
+ energy -= silk_RSHIFT32( silk_SMULBB( x[ i ], x[ i ] ), rshifts_local );
+ }
+ if( rshifts_local < *rshifts ) {
+ /* Adjust energy */
+ energy = silk_RSHIFT32( energy, *rshifts - rshifts_local );
+ rshifts_local = *rshifts;
+ }
+
+ /* Calculate energy of remaining columns of X: X[:,j]'*X[:,j] */
+ /* Fill out the diagonal of the correlation matrix */
+ matrix_ptr( XX, 0, 0, order ) = energy;
+ ptr1 = &x[ order - 1 ]; /* First sample of column 0 of X */
+ for( j = 1; j < order; j++ ) {
+ energy = silk_SUB32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ L - j ], ptr1[ L - j ] ), rshifts_local ) );
+ energy = silk_ADD32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ -j ], ptr1[ -j ] ), rshifts_local ) );
+ matrix_ptr( XX, j, j, order ) = energy;
+ }
+
+ ptr2 = &x[ order - 2 ]; /* First sample of column 1 of X */
+ /* Calculate the remaining elements of the correlation matrix */
+ if( rshifts_local > 0 ) {
+ /* Right shifting used */
+ for( lag = 1; lag < order; lag++ ) {
+ /* Inner product of column 0 and column lag: X[:,0]'*X[:,lag] */
+ energy = 0;
+ for( i = 0; i < L; i++ ) {
+ energy += silk_RSHIFT32( silk_SMULBB( ptr1[ i ], ptr2[i] ), rshifts_local );
+ }
+ /* Calculate remaining off diagonal: X[:,j]'*X[:,j + lag] */
+ matrix_ptr( XX, lag, 0, order ) = energy;
+ matrix_ptr( XX, 0, lag, order ) = energy;
+ for( j = 1; j < ( order - lag ); j++ ) {
+ energy = silk_SUB32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ L - j ], ptr2[ L - j ] ), rshifts_local ) );
+ energy = silk_ADD32( energy, silk_RSHIFT32( silk_SMULBB( ptr1[ -j ], ptr2[ -j ] ), rshifts_local ) );
+ matrix_ptr( XX, lag + j, j, order ) = energy;
+ matrix_ptr( XX, j, lag + j, order ) = energy;
+ }
+ ptr2--; /* Update pointer to first sample of next column (lag) in X */
+ }
+ } else {
+ for( lag = 1; lag < order; lag++ ) {
+ /* Inner product of column 0 and column lag: X[:,0]'*X[:,lag] */
+ energy = silk_inner_prod_aligned( ptr1, ptr2, L );
+ matrix_ptr( XX, lag, 0, order ) = energy;
+ matrix_ptr( XX, 0, lag, order ) = energy;
+ /* Calculate remaining off diagonal: X[:,j]'*X[:,j + lag] */
+ for( j = 1; j < ( order - lag ); j++ ) {
+ energy = silk_SUB32( energy, silk_SMULBB( ptr1[ L - j ], ptr2[ L - j ] ) );
+ energy = silk_SMLABB( energy, ptr1[ -j ], ptr2[ -j ] );
+ matrix_ptr( XX, lag + j, j, order ) = energy;
+ matrix_ptr( XX, j, lag + j, order ) = energy;
+ }
+ ptr2--;/* Update pointer to first sample of next column (lag) in X */
+ }
+ }
+ *rshifts = rshifts_local;
+}
+
diff --git a/drivers/opus/silk/fixed/encode_frame_FIX.c b/drivers/opus/silk/fixed/encode_frame_FIX.c
new file mode 100644
index 0000000000..27944729f8
--- /dev/null
+++ b/drivers/opus/silk/fixed/encode_frame_FIX.c
@@ -0,0 +1,385 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/fixed/main_FIX.h"
+#include "opus/celt/stack_alloc.h"
+#include "opus/silk/tuning_parameters.h"
+
+/* Low Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode with lower bitrate */
+static OPUS_INLINE void silk_LBRR_encode_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O Pointer to Silk FIX encoder control struct */
+ const opus_int32 xfw_Q3[], /* I Input signal */
+ opus_int condCoding /* I The type of conditional coding used so far for this frame */
+);
+
+void silk_encode_do_VAD_FIX(
+ silk_encoder_state_FIX *psEnc /* I/O Pointer to Silk FIX encoder state */
+)
+{
+ /****************************/
+ /* Voice Activity Detection */
+ /****************************/
+ silk_VAD_GetSA_Q8( &psEnc->sCmn, psEnc->sCmn.inputBuf + 1 );
+
+ /**************************************************/
+ /* Convert speech activity into VAD and DTX flags */
+ /**************************************************/
+ if( psEnc->sCmn.speech_activity_Q8 < SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ) ) {
+ psEnc->sCmn.indices.signalType = TYPE_NO_VOICE_ACTIVITY;
+ psEnc->sCmn.noSpeechCounter++;
+ if( psEnc->sCmn.noSpeechCounter < NB_SPEECH_FRAMES_BEFORE_DTX ) {
+ psEnc->sCmn.inDTX = 0;
+ } else if( psEnc->sCmn.noSpeechCounter > MAX_CONSECUTIVE_DTX + NB_SPEECH_FRAMES_BEFORE_DTX ) {
+ psEnc->sCmn.noSpeechCounter = NB_SPEECH_FRAMES_BEFORE_DTX;
+ psEnc->sCmn.inDTX = 0;
+ }
+ psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 0;
+ } else {
+ psEnc->sCmn.noSpeechCounter = 0;
+ psEnc->sCmn.inDTX = 0;
+ psEnc->sCmn.indices.signalType = TYPE_UNVOICED;
+ psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 1;
+ }
+}
+
+/****************/
+/* Encode frame */
+/****************/
+opus_int silk_encode_frame_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */
+ opus_int32 *pnBytesOut, /* O Pointer to number of payload bytes; */
+ ec_enc *psRangeEnc, /* I/O compressor data structure */
+ opus_int condCoding, /* I The type of conditional coding to use */
+ opus_int maxBits, /* I If > 0: maximum number of output bits */
+ opus_int useCBR /* I Flag to force constant-bitrate operation */
+)
+{
+ silk_encoder_control_FIX sEncCtrl;
+ opus_int i, iter, maxIter, found_upper, found_lower, ret = 0;
+ opus_int16 *x_frame;
+ ec_enc sRangeEnc_copy, sRangeEnc_copy2;
+ silk_nsq_state sNSQ_copy, sNSQ_copy2;
+ opus_int32 seed_copy, nBits, nBits_lower, nBits_upper, gainMult_lower, gainMult_upper;
+ opus_int32 gainsID, gainsID_lower, gainsID_upper;
+ opus_int16 gainMult_Q8;
+ opus_int16 ec_prevLagIndex_copy;
+ opus_int ec_prevSignalType_copy;
+ opus_int8 LastGainIndex_copy2;
+ SAVE_STACK;
+
+ /* This is totally unnecessary but many compilers (including gcc) are too dumb to realise it */
+ LastGainIndex_copy2 = nBits_lower = nBits_upper = gainMult_lower = gainMult_upper = 0;
+
+ psEnc->sCmn.indices.Seed = psEnc->sCmn.frameCounter++ & 3;
+
+ /**************************************************************/
+ /* Set up Input Pointers, and insert frame in input buffer */
+ /*************************************************************/
+ /* start of frame to encode */
+ x_frame = psEnc->x_buf + psEnc->sCmn.ltp_mem_length;
+
+ /***************************************/
+ /* Ensure smooth bandwidth transitions */
+ /***************************************/
+ silk_LP_variable_cutoff( &psEnc->sCmn.sLP, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length );
+
+ /*******************************************/
+ /* Copy new frame to front of input buffer */
+ /*******************************************/
+ silk_memcpy( x_frame + LA_SHAPE_MS * psEnc->sCmn.fs_kHz, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length * sizeof( opus_int16 ) );
+
+ if( !psEnc->sCmn.prefillFlag ) {
+ VARDECL( opus_int32, xfw_Q3 );
+ VARDECL( opus_int16, res_pitch );
+ VARDECL( opus_uint8, ec_buf_copy );
+ opus_int16 *res_pitch_frame;
+
+ ALLOC( res_pitch,
+ psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length
+ + psEnc->sCmn.ltp_mem_length, opus_int16 );
+ /* start of pitch LPC residual frame */
+ res_pitch_frame = res_pitch + psEnc->sCmn.ltp_mem_length;
+
+ /*****************************************/
+ /* Find pitch lags, initial LPC analysis */
+ /*****************************************/
+ silk_find_pitch_lags_FIX( psEnc, &sEncCtrl, res_pitch, x_frame, psEnc->sCmn.arch );
+
+ /************************/
+ /* Noise shape analysis */
+ /************************/
+ silk_noise_shape_analysis_FIX( psEnc, &sEncCtrl, res_pitch_frame, x_frame, psEnc->sCmn.arch );
+
+ /***************************************************/
+ /* Find linear prediction coefficients (LPC + LTP) */
+ /***************************************************/
+ silk_find_pred_coefs_FIX( psEnc, &sEncCtrl, res_pitch, x_frame, condCoding );
+
+ /****************************************/
+ /* Process gains */
+ /****************************************/
+ silk_process_gains_FIX( psEnc, &sEncCtrl, condCoding );
+
+ /*****************************************/
+ /* Prefiltering for noise shaper */
+ /*****************************************/
+ ALLOC( xfw_Q3, psEnc->sCmn.frame_length, opus_int32 );
+ silk_prefilter_FIX( psEnc, &sEncCtrl, xfw_Q3, x_frame );
+
+ /****************************************/
+ /* Low Bitrate Redundant Encoding */
+ /****************************************/
+ silk_LBRR_encode_FIX( psEnc, &sEncCtrl, xfw_Q3, condCoding );
+
+ /* Loop over quantizer and entropy coding to control bitrate */
+ maxIter = 6;
+ gainMult_Q8 = SILK_FIX_CONST( 1, 8 );
+ found_lower = 0;
+ found_upper = 0;
+ gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr );
+ gainsID_lower = -1;
+ gainsID_upper = -1;
+ /* Copy part of the input state */
+ silk_memcpy( &sRangeEnc_copy, psRangeEnc, sizeof( ec_enc ) );
+ silk_memcpy( &sNSQ_copy, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
+ seed_copy = psEnc->sCmn.indices.Seed;
+ ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex;
+ ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType;
+ ALLOC( ec_buf_copy, 1275, opus_uint8 );
+ for( iter = 0; ; iter++ ) {
+ if( gainsID == gainsID_lower ) {
+ nBits = nBits_lower;
+ } else if( gainsID == gainsID_upper ) {
+ nBits = nBits_upper;
+ } else {
+ /* Restore part of the input state */
+ if( iter > 0 ) {
+ silk_memcpy( psRangeEnc, &sRangeEnc_copy, sizeof( ec_enc ) );
+ silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy, sizeof( silk_nsq_state ) );
+ psEnc->sCmn.indices.Seed = seed_copy;
+ psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy;
+ psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy;
+ }
+
+ /*****************************************/
+ /* Noise shaping quantization */
+ /*****************************************/
+ if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) {
+ silk_NSQ_del_dec( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, xfw_Q3, psEnc->sCmn.pulses,
+ sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR2_Q13, sEncCtrl.HarmShapeGain_Q14,
+ sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14 );
+ } else {
+ silk_NSQ( &psEnc->sCmn, &psEnc->sCmn.sNSQ, &psEnc->sCmn.indices, xfw_Q3, psEnc->sCmn.pulses,
+ sEncCtrl.PredCoef_Q12[ 0 ], sEncCtrl.LTPCoef_Q14, sEncCtrl.AR2_Q13, sEncCtrl.HarmShapeGain_Q14,
+ sEncCtrl.Tilt_Q14, sEncCtrl.LF_shp_Q14, sEncCtrl.Gains_Q16, sEncCtrl.pitchL, sEncCtrl.Lambda_Q10, sEncCtrl.LTP_scale_Q14 );
+ }
+
+ /****************************************/
+ /* Encode Parameters */
+ /****************************************/
+ silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding );
+
+ /****************************************/
+ /* Encode Excitation Signal */
+ /****************************************/
+ silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType,
+ psEnc->sCmn.pulses, psEnc->sCmn.frame_length );
+
+ nBits = ec_tell( psRangeEnc );
+
+ if( useCBR == 0 && iter == 0 && nBits <= maxBits ) {
+ break;
+ }
+ }
+
+ if( iter == maxIter ) {
+ if( found_lower && ( gainsID == gainsID_lower || nBits > maxBits ) ) {
+ /* Restore output state from earlier iteration that did meet the bitrate budget */
+ silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) );
+ silk_assert( sRangeEnc_copy2.offs <= 1275 );
+ silk_memcpy( psRangeEnc->buf, ec_buf_copy, sRangeEnc_copy2.offs );
+ silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy2, sizeof( silk_nsq_state ) );
+ psEnc->sShape.LastGainIndex = LastGainIndex_copy2;
+ }
+ break;
+ }
+
+ if( nBits > maxBits ) {
+ if( found_lower == 0 && iter >= 2 ) {
+ /* Adjust the quantizer's rate/distortion tradeoff and discard previous "upper" results */
+ sEncCtrl.Lambda_Q10 = silk_ADD_RSHIFT32( sEncCtrl.Lambda_Q10, sEncCtrl.Lambda_Q10, 1 );
+ found_upper = 0;
+ gainsID_upper = -1;
+ } else {
+ found_upper = 1;
+ nBits_upper = nBits;
+ gainMult_upper = gainMult_Q8;
+ gainsID_upper = gainsID;
+ }
+ } else if( nBits < maxBits - 5 ) {
+ found_lower = 1;
+ nBits_lower = nBits;
+ gainMult_lower = gainMult_Q8;
+ if( gainsID != gainsID_lower ) {
+ gainsID_lower = gainsID;
+ /* Copy part of the output state */
+ silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) );
+ silk_assert( psRangeEnc->offs <= 1275 );
+ silk_memcpy( ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs );
+ silk_memcpy( &sNSQ_copy2, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
+ LastGainIndex_copy2 = psEnc->sShape.LastGainIndex;
+ }
+ } else {
+ /* Within 5 bits of budget: close enough */
+ break;
+ }
+
+ if( ( found_lower & found_upper ) == 0 ) {
+ /* Adjust gain according to high-rate rate/distortion curve */
+ opus_int32 gain_factor_Q16;
+ gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) );
+ gain_factor_Q16 = silk_min_32( gain_factor_Q16, SILK_FIX_CONST( 2, 16 ) );
+ if( nBits > maxBits ) {
+ gain_factor_Q16 = silk_max_32( gain_factor_Q16, SILK_FIX_CONST( 1.3, 16 ) );
+ }
+ gainMult_Q8 = silk_SMULWB( gain_factor_Q16, gainMult_Q8 );
+ } else {
+ /* Adjust gain by interpolating */
+ gainMult_Q8 = gainMult_lower + silk_DIV32_16( silk_MUL( gainMult_upper - gainMult_lower, maxBits - nBits_lower ), nBits_upper - nBits_lower );
+ /* New gain multplier must be between 25% and 75% of old range (note that gainMult_upper < gainMult_lower) */
+ if( gainMult_Q8 > silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ) ) {
+ gainMult_Q8 = silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 );
+ } else
+ if( gainMult_Q8 < silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ) ) {
+ gainMult_Q8 = silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 );
+ }
+ }
+
+ for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ sEncCtrl.Gains_Q16[ i ] = silk_LSHIFT_SAT32( silk_SMULWB( sEncCtrl.GainsUnq_Q16[ i ], gainMult_Q8 ), 8 );
+ }
+
+ /* Quantize gains */
+ psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev;
+ silk_gains_quant( psEnc->sCmn.indices.GainsIndices, sEncCtrl.Gains_Q16,
+ &psEnc->sShape.LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
+
+ /* Unique identifier of gains vector */
+ gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr );
+ }
+ }
+
+ /* Update input buffer */
+ silk_memmove( psEnc->x_buf, &psEnc->x_buf[ psEnc->sCmn.frame_length ],
+ ( psEnc->sCmn.ltp_mem_length + LA_SHAPE_MS * psEnc->sCmn.fs_kHz ) * sizeof( opus_int16 ) );
+
+ /* Exit without entropy coding */
+ if( psEnc->sCmn.prefillFlag ) {
+ /* No payload */
+ *pnBytesOut = 0;
+ RESTORE_STACK;
+ return ret;
+ }
+
+ /* Parameters needed for next frame */
+ psEnc->sCmn.prevLag = sEncCtrl.pitchL[ psEnc->sCmn.nb_subfr - 1 ];
+ psEnc->sCmn.prevSignalType = psEnc->sCmn.indices.signalType;
+
+ /****************************************/
+ /* Finalize payload */
+ /****************************************/
+ psEnc->sCmn.first_frame_after_reset = 0;
+ /* Payload size */
+ *pnBytesOut = silk_RSHIFT( ec_tell( psRangeEnc ) + 7, 3 );
+
+ RESTORE_STACK;
+ return ret;
+}
+
+/* Low-Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode excitation at lower bitrate */
+static OPUS_INLINE void silk_LBRR_encode_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O Pointer to Silk FIX encoder control struct */
+ const opus_int32 xfw_Q3[], /* I Input signal */
+ opus_int condCoding /* I The type of conditional coding used so far for this frame */
+)
+{
+ opus_int32 TempGains_Q16[ MAX_NB_SUBFR ];
+ SideInfoIndices *psIndices_LBRR = &psEnc->sCmn.indices_LBRR[ psEnc->sCmn.nFramesEncoded ];
+ silk_nsq_state sNSQ_LBRR;
+
+ /*******************************************/
+ /* Control use of inband LBRR */
+ /*******************************************/
+ if( psEnc->sCmn.LBRR_enabled && psEnc->sCmn.speech_activity_Q8 > SILK_FIX_CONST( LBRR_SPEECH_ACTIVITY_THRES, 8 ) ) {
+ psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded ] = 1;
+
+ /* Copy noise shaping quantizer state and quantization indices from regular encoding */
+ silk_memcpy( &sNSQ_LBRR, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
+ silk_memcpy( psIndices_LBRR, &psEnc->sCmn.indices, sizeof( SideInfoIndices ) );
+
+ /* Save original gains */
+ silk_memcpy( TempGains_Q16, psEncCtrl->Gains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) );
+
+ if( psEnc->sCmn.nFramesEncoded == 0 || psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded - 1 ] == 0 ) {
+ /* First frame in packet or previous frame not LBRR coded */
+ psEnc->sCmn.LBRRprevLastGainIndex = psEnc->sShape.LastGainIndex;
+
+ /* Increase Gains to get target LBRR rate */
+ psIndices_LBRR->GainsIndices[ 0 ] = psIndices_LBRR->GainsIndices[ 0 ] + psEnc->sCmn.LBRR_GainIncreases;
+ psIndices_LBRR->GainsIndices[ 0 ] = silk_min_int( psIndices_LBRR->GainsIndices[ 0 ], N_LEVELS_QGAIN - 1 );
+ }
+
+ /* Decode to get gains in sync with decoder */
+ /* Overwrite unquantized gains with quantized gains */
+ silk_gains_dequant( psEncCtrl->Gains_Q16, psIndices_LBRR->GainsIndices,
+ &psEnc->sCmn.LBRRprevLastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
+
+ /*****************************************/
+ /* Noise shaping quantization */
+ /*****************************************/
+ if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) {
+ silk_NSQ_del_dec( &psEnc->sCmn, &sNSQ_LBRR, psIndices_LBRR, xfw_Q3,
+ psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->LTPCoef_Q14,
+ psEncCtrl->AR2_Q13, psEncCtrl->HarmShapeGain_Q14, psEncCtrl->Tilt_Q14, psEncCtrl->LF_shp_Q14,
+ psEncCtrl->Gains_Q16, psEncCtrl->pitchL, psEncCtrl->Lambda_Q10, psEncCtrl->LTP_scale_Q14 );
+ } else {
+ silk_NSQ( &psEnc->sCmn, &sNSQ_LBRR, psIndices_LBRR, xfw_Q3,
+ psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], psEncCtrl->PredCoef_Q12[ 0 ], psEncCtrl->LTPCoef_Q14,
+ psEncCtrl->AR2_Q13, psEncCtrl->HarmShapeGain_Q14, psEncCtrl->Tilt_Q14, psEncCtrl->LF_shp_Q14,
+ psEncCtrl->Gains_Q16, psEncCtrl->pitchL, psEncCtrl->Lambda_Q10, psEncCtrl->LTP_scale_Q14 );
+ }
+
+ /* Restore original gains */
+ silk_memcpy( psEncCtrl->Gains_Q16, TempGains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) );
+ }
+}
diff --git a/drivers/opus/silk/fixed/find_LPC_FIX.c b/drivers/opus/silk/fixed/find_LPC_FIX.c
new file mode 100644
index 0000000000..df76e17ca2
--- /dev/null
+++ b/drivers/opus/silk/fixed/find_LPC_FIX.c
@@ -0,0 +1,151 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/fixed/main_FIX.h"
+#include "opus/celt/stack_alloc.h"
+#include "opus/silk/tuning_parameters.h"
+
+/* Finds LPC vector from correlations, and converts to NLSF */
+void silk_find_LPC_FIX(
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ opus_int16 NLSF_Q15[], /* O NLSFs */
+ const opus_int16 x[], /* I Input signal */
+ const opus_int32 minInvGain_Q30 /* I Inverse of max prediction gain */
+)
+{
+ opus_int k, subfr_length;
+ opus_int32 a_Q16[ MAX_LPC_ORDER ];
+ opus_int isInterpLower, shift;
+ opus_int32 res_nrg0, res_nrg1;
+ opus_int rshift0, rshift1;
+
+ /* Used only for LSF interpolation */
+ opus_int32 a_tmp_Q16[ MAX_LPC_ORDER ], res_nrg_interp, res_nrg, res_tmp_nrg;
+ opus_int res_nrg_interp_Q, res_nrg_Q, res_tmp_nrg_Q;
+ opus_int16 a_tmp_Q12[ MAX_LPC_ORDER ];
+ opus_int16 NLSF0_Q15[ MAX_LPC_ORDER ];
+ SAVE_STACK;
+
+ subfr_length = psEncC->subfr_length + psEncC->predictLPCOrder;
+
+ /* Default: no interpolation */
+ psEncC->indices.NLSFInterpCoef_Q2 = 4;
+
+ /* Burg AR analysis for the full frame */
+ silk_burg_modified( &res_nrg, &res_nrg_Q, a_Q16, x, minInvGain_Q30, subfr_length, psEncC->nb_subfr, psEncC->predictLPCOrder, psEncC->arch );
+
+ if( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) {
+ VARDECL( opus_int16, LPC_res );
+
+ /* Optimal solution for last 10 ms */
+ silk_burg_modified( &res_tmp_nrg, &res_tmp_nrg_Q, a_tmp_Q16, x + 2 * subfr_length, minInvGain_Q30, subfr_length, 2, psEncC->predictLPCOrder, psEncC->arch );
+
+ /* subtract residual energy here, as that's easier than adding it to the */
+ /* residual energy of the first 10 ms in each iteration of the search below */
+ shift = res_tmp_nrg_Q - res_nrg_Q;
+ if( shift >= 0 ) {
+ if( shift < 32 ) {
+ res_nrg = res_nrg - silk_RSHIFT( res_tmp_nrg, shift );
+ }
+ } else {
+ silk_assert( shift > -32 );
+ res_nrg = silk_RSHIFT( res_nrg, -shift ) - res_tmp_nrg;
+ res_nrg_Q = res_tmp_nrg_Q;
+ }
+
+ /* Convert to NLSFs */
+ silk_A2NLSF( NLSF_Q15, a_tmp_Q16, psEncC->predictLPCOrder );
+
+ ALLOC( LPC_res, 2 * subfr_length, opus_int16 );
+
+ /* Search over interpolation indices to find the one with lowest residual energy */
+ for( k = 3; k >= 0; k-- ) {
+ /* Interpolate NLSFs for first half */
+ silk_interpolate( NLSF0_Q15, psEncC->prev_NLSFq_Q15, NLSF_Q15, k, psEncC->predictLPCOrder );
+
+ /* Convert to LPC for residual energy evaluation */
+ silk_NLSF2A( a_tmp_Q12, NLSF0_Q15, psEncC->predictLPCOrder );
+
+ /* Calculate residual energy with NLSF interpolation */
+ silk_LPC_analysis_filter( LPC_res, x, a_tmp_Q12, 2 * subfr_length, psEncC->predictLPCOrder );
+
+ silk_sum_sqr_shift( &res_nrg0, &rshift0, LPC_res + psEncC->predictLPCOrder, subfr_length - psEncC->predictLPCOrder );
+ silk_sum_sqr_shift( &res_nrg1, &rshift1, LPC_res + psEncC->predictLPCOrder + subfr_length, subfr_length - psEncC->predictLPCOrder );
+
+ /* Add subframe energies from first half frame */
+ shift = rshift0 - rshift1;
+ if( shift >= 0 ) {
+ res_nrg1 = silk_RSHIFT( res_nrg1, shift );
+ res_nrg_interp_Q = -rshift0;
+ } else {
+ res_nrg0 = silk_RSHIFT( res_nrg0, -shift );
+ res_nrg_interp_Q = -rshift1;
+ }
+ res_nrg_interp = silk_ADD32( res_nrg0, res_nrg1 );
+
+ /* Compare with first half energy without NLSF interpolation, or best interpolated value so far */
+ shift = res_nrg_interp_Q - res_nrg_Q;
+ if( shift >= 0 ) {
+ if( silk_RSHIFT( res_nrg_interp, shift ) < res_nrg ) {
+ isInterpLower = silk_TRUE;
+ } else {
+ isInterpLower = silk_FALSE;
+ }
+ } else {
+ if( -shift < 32 ) {
+ if( res_nrg_interp < silk_RSHIFT( res_nrg, -shift ) ) {
+ isInterpLower = silk_TRUE;
+ } else {
+ isInterpLower = silk_FALSE;
+ }
+ } else {
+ isInterpLower = silk_FALSE;
+ }
+ }
+
+ /* Determine whether current interpolated NLSFs are best so far */
+ if( isInterpLower == silk_TRUE ) {
+ /* Interpolation has lower residual energy */
+ res_nrg = res_nrg_interp;
+ res_nrg_Q = res_nrg_interp_Q;
+ psEncC->indices.NLSFInterpCoef_Q2 = (opus_int8)k;
+ }
+ }
+ }
+
+ if( psEncC->indices.NLSFInterpCoef_Q2 == 4 ) {
+ /* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */
+ silk_A2NLSF( NLSF_Q15, a_Q16, psEncC->predictLPCOrder );
+ }
+
+ silk_assert( psEncC->indices.NLSFInterpCoef_Q2 == 4 || ( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) );
+ RESTORE_STACK;
+}
diff --git a/drivers/opus/silk/fixed/find_LTP_FIX.c b/drivers/opus/silk/fixed/find_LTP_FIX.c
new file mode 100644
index 0000000000..d556371ffa
--- /dev/null
+++ b/drivers/opus/silk/fixed/find_LTP_FIX.c
@@ -0,0 +1,244 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/fixed/main_FIX.h"
+#include "opus/silk/tuning_parameters.h"
+
+/* Head room for correlations */
+#define LTP_CORRS_HEAD_ROOM 2
+
+void silk_fit_LTP(
+ opus_int32 LTP_coefs_Q16[ LTP_ORDER ],
+ opus_int16 LTP_coefs_Q14[ LTP_ORDER ]
+);
+
+void silk_find_LTP_FIX(
+ opus_int16 b_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* O LTP coefs */
+ opus_int32 WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */
+ opus_int *LTPredCodGain_Q7, /* O LTP coding gain */
+ const opus_int16 r_lpc[], /* I residual signal after LPC signal + state for first 10 ms */
+ const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */
+ const opus_int32 Wght_Q15[ MAX_NB_SUBFR ], /* I weights */
+ const opus_int subfr_length, /* I subframe length */
+ const opus_int nb_subfr, /* I number of subframes */
+ const opus_int mem_offset, /* I number of samples in LTP memory */
+ opus_int corr_rshifts[ MAX_NB_SUBFR ] /* O right shifts applied to correlations */
+)
+{
+ opus_int i, k, lshift;
+ const opus_int16 *r_ptr, *lag_ptr;
+ opus_int16 *b_Q14_ptr;
+
+ opus_int32 regu;
+ opus_int32 *WLTP_ptr;
+ opus_int32 b_Q16[ LTP_ORDER ], delta_b_Q14[ LTP_ORDER ], d_Q14[ MAX_NB_SUBFR ], nrg[ MAX_NB_SUBFR ], g_Q26;
+ opus_int32 w[ MAX_NB_SUBFR ], WLTP_max, max_abs_d_Q14, max_w_bits;
+
+ opus_int32 temp32, denom32;
+ opus_int extra_shifts;
+ opus_int rr_shifts, maxRshifts, maxRshifts_wxtra, LZs;
+ opus_int32 LPC_res_nrg, LPC_LTP_res_nrg, div_Q16;
+ opus_int32 Rr[ LTP_ORDER ], rr[ MAX_NB_SUBFR ];
+ opus_int32 wd, m_Q12;
+
+ b_Q14_ptr = b_Q14;
+ WLTP_ptr = WLTP;
+ r_ptr = &r_lpc[ mem_offset ];
+ for( k = 0; k < nb_subfr; k++ ) {
+ lag_ptr = r_ptr - ( lag[ k ] + LTP_ORDER / 2 );
+
+ silk_sum_sqr_shift( &rr[ k ], &rr_shifts, r_ptr, subfr_length ); /* rr[ k ] in Q( -rr_shifts ) */
+
+ /* Assure headroom */
+ LZs = silk_CLZ32( rr[k] );
+ if( LZs < LTP_CORRS_HEAD_ROOM ) {
+ rr[ k ] = silk_RSHIFT_ROUND( rr[ k ], LTP_CORRS_HEAD_ROOM - LZs );
+ rr_shifts += ( LTP_CORRS_HEAD_ROOM - LZs );
+ }
+ corr_rshifts[ k ] = rr_shifts;
+ silk_corrMatrix_FIX( lag_ptr, subfr_length, LTP_ORDER, LTP_CORRS_HEAD_ROOM, WLTP_ptr, &corr_rshifts[ k ] ); /* WLTP_fix_ptr in Q( -corr_rshifts[ k ] ) */
+
+ /* The correlation vector always has lower max abs value than rr and/or RR so head room is assured */
+ silk_corrVector_FIX( lag_ptr, r_ptr, subfr_length, LTP_ORDER, Rr, corr_rshifts[ k ] ); /* Rr_fix_ptr in Q( -corr_rshifts[ k ] ) */
+ if( corr_rshifts[ k ] > rr_shifts ) {
+ rr[ k ] = silk_RSHIFT( rr[ k ], corr_rshifts[ k ] - rr_shifts ); /* rr[ k ] in Q( -corr_rshifts[ k ] ) */
+ }
+ silk_assert( rr[ k ] >= 0 );
+
+ regu = 1;
+ regu = silk_SMLAWB( regu, rr[ k ], SILK_FIX_CONST( LTP_DAMPING/3, 16 ) );
+ regu = silk_SMLAWB( regu, matrix_ptr( WLTP_ptr, 0, 0, LTP_ORDER ), SILK_FIX_CONST( LTP_DAMPING/3, 16 ) );
+ regu = silk_SMLAWB( regu, matrix_ptr( WLTP_ptr, LTP_ORDER-1, LTP_ORDER-1, LTP_ORDER ), SILK_FIX_CONST( LTP_DAMPING/3, 16 ) );
+ silk_regularize_correlations_FIX( WLTP_ptr, &rr[k], regu, LTP_ORDER );
+
+ silk_solve_LDL_FIX( WLTP_ptr, LTP_ORDER, Rr, b_Q16 ); /* WLTP_fix_ptr and Rr_fix_ptr both in Q(-corr_rshifts[k]) */
+
+ /* Limit and store in Q14 */
+ silk_fit_LTP( b_Q16, b_Q14_ptr );
+
+ /* Calculate residual energy */
+ nrg[ k ] = silk_residual_energy16_covar_FIX( b_Q14_ptr, WLTP_ptr, Rr, rr[ k ], LTP_ORDER, 14 ); /* nrg_fix in Q( -corr_rshifts[ k ] ) */
+
+ /* temp = Wght[ k ] / ( nrg[ k ] * Wght[ k ] + 0.01f * subfr_length ); */
+ extra_shifts = silk_min_int( corr_rshifts[ k ], LTP_CORRS_HEAD_ROOM );
+ denom32 = silk_LSHIFT_SAT32( silk_SMULWB( nrg[ k ], Wght_Q15[ k ] ), 1 + extra_shifts ) + /* Q( -corr_rshifts[ k ] + extra_shifts ) */
+ silk_RSHIFT( silk_SMULWB( (opus_int32)subfr_length, 655 ), corr_rshifts[ k ] - extra_shifts ); /* Q( -corr_rshifts[ k ] + extra_shifts ) */
+ denom32 = silk_max( denom32, 1 );
+ silk_assert( ((opus_int64)Wght_Q15[ k ] << 16 ) < silk_int32_MAX ); /* Wght always < 0.5 in Q0 */
+ temp32 = silk_DIV32( silk_LSHIFT( (opus_int32)Wght_Q15[ k ], 16 ), denom32 ); /* Q( 15 + 16 + corr_rshifts[k] - extra_shifts ) */
+ temp32 = silk_RSHIFT( temp32, 31 + corr_rshifts[ k ] - extra_shifts - 26 ); /* Q26 */
+
+ /* Limit temp such that the below scaling never wraps around */
+ WLTP_max = 0;
+ for( i = 0; i < LTP_ORDER * LTP_ORDER; i++ ) {
+ WLTP_max = silk_max( WLTP_ptr[ i ], WLTP_max );
+ }
+ lshift = silk_CLZ32( WLTP_max ) - 1 - 3; /* keep 3 bits free for vq_nearest_neighbor_fix */
+ silk_assert( 26 - 18 + lshift >= 0 );
+ if( 26 - 18 + lshift < 31 ) {
+ temp32 = silk_min_32( temp32, silk_LSHIFT( (opus_int32)1, 26 - 18 + lshift ) );
+ }
+
+ silk_scale_vector32_Q26_lshift_18( WLTP_ptr, temp32, LTP_ORDER * LTP_ORDER ); /* WLTP_ptr in Q( 18 - corr_rshifts[ k ] ) */
+
+ w[ k ] = matrix_ptr( WLTP_ptr, LTP_ORDER/2, LTP_ORDER/2, LTP_ORDER ); /* w in Q( 18 - corr_rshifts[ k ] ) */
+ silk_assert( w[k] >= 0 );
+
+ r_ptr += subfr_length;
+ b_Q14_ptr += LTP_ORDER;
+ WLTP_ptr += LTP_ORDER * LTP_ORDER;
+ }
+
+ maxRshifts = 0;
+ for( k = 0; k < nb_subfr; k++ ) {
+ maxRshifts = silk_max_int( corr_rshifts[ k ], maxRshifts );
+ }
+
+ /* Compute LTP coding gain */
+ if( LTPredCodGain_Q7 != NULL ) {
+ LPC_LTP_res_nrg = 0;
+ LPC_res_nrg = 0;
+ silk_assert( LTP_CORRS_HEAD_ROOM >= 2 ); /* Check that no overflow will happen when adding */
+ for( k = 0; k < nb_subfr; k++ ) {
+ LPC_res_nrg = silk_ADD32( LPC_res_nrg, silk_RSHIFT( silk_ADD32( silk_SMULWB( rr[ k ], Wght_Q15[ k ] ), 1 ), 1 + ( maxRshifts - corr_rshifts[ k ] ) ) ); /* Q( -maxRshifts ) */
+ LPC_LTP_res_nrg = silk_ADD32( LPC_LTP_res_nrg, silk_RSHIFT( silk_ADD32( silk_SMULWB( nrg[ k ], Wght_Q15[ k ] ), 1 ), 1 + ( maxRshifts - corr_rshifts[ k ] ) ) ); /* Q( -maxRshifts ) */
+ }
+ LPC_LTP_res_nrg = silk_max( LPC_LTP_res_nrg, 1 ); /* avoid division by zero */
+
+ div_Q16 = silk_DIV32_varQ( LPC_res_nrg, LPC_LTP_res_nrg, 16 );
+ *LTPredCodGain_Q7 = ( opus_int )silk_SMULBB( 3, silk_lin2log( div_Q16 ) - ( 16 << 7 ) );
+
+ silk_assert( *LTPredCodGain_Q7 == ( opus_int )silk_SAT16( silk_MUL( 3, silk_lin2log( div_Q16 ) - ( 16 << 7 ) ) ) );
+ }
+
+ /* smoothing */
+ /* d = sum( B, 1 ); */
+ b_Q14_ptr = b_Q14;
+ for( k = 0; k < nb_subfr; k++ ) {
+ d_Q14[ k ] = 0;
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ d_Q14[ k ] += b_Q14_ptr[ i ];
+ }
+ b_Q14_ptr += LTP_ORDER;
+ }
+
+ /* m = ( w * d' ) / ( sum( w ) + 1e-3 ); */
+
+ /* Find maximum absolute value of d_Q14 and the bits used by w in Q0 */
+ max_abs_d_Q14 = 0;
+ max_w_bits = 0;
+ for( k = 0; k < nb_subfr; k++ ) {
+ max_abs_d_Q14 = silk_max_32( max_abs_d_Q14, silk_abs( d_Q14[ k ] ) );
+ /* w[ k ] is in Q( 18 - corr_rshifts[ k ] ) */
+ /* Find bits needed in Q( 18 - maxRshifts ) */
+ max_w_bits = silk_max_32( max_w_bits, 32 - silk_CLZ32( w[ k ] ) + corr_rshifts[ k ] - maxRshifts );
+ }
+
+ /* max_abs_d_Q14 = (5 << 15); worst case, i.e. LTP_ORDER * -silk_int16_MIN */
+ silk_assert( max_abs_d_Q14 <= ( 5 << 15 ) );
+
+ /* How many bits is needed for w*d' in Q( 18 - maxRshifts ) in the worst case, of all d_Q14's being equal to max_abs_d_Q14 */
+ extra_shifts = max_w_bits + 32 - silk_CLZ32( max_abs_d_Q14 ) - 14;
+
+ /* Subtract what we got available; bits in output var plus maxRshifts */
+ extra_shifts -= ( 32 - 1 - 2 + maxRshifts ); /* Keep sign bit free as well as 2 bits for accumulation */
+ extra_shifts = silk_max_int( extra_shifts, 0 );
+
+ maxRshifts_wxtra = maxRshifts + extra_shifts;
+
+ temp32 = silk_RSHIFT( 262, maxRshifts + extra_shifts ) + 1; /* 1e-3f in Q( 18 - (maxRshifts + extra_shifts) ) */
+ wd = 0;
+ for( k = 0; k < nb_subfr; k++ ) {
+ /* w has at least 2 bits of headroom so no overflow should happen */
+ temp32 = silk_ADD32( temp32, silk_RSHIFT( w[ k ], maxRshifts_wxtra - corr_rshifts[ k ] ) ); /* Q( 18 - maxRshifts_wxtra ) */
+ wd = silk_ADD32( wd, silk_LSHIFT( silk_SMULWW( silk_RSHIFT( w[ k ], maxRshifts_wxtra - corr_rshifts[ k ] ), d_Q14[ k ] ), 2 ) ); /* Q( 18 - maxRshifts_wxtra ) */
+ }
+ m_Q12 = silk_DIV32_varQ( wd, temp32, 12 );
+
+ b_Q14_ptr = b_Q14;
+ for( k = 0; k < nb_subfr; k++ ) {
+ /* w_fix[ k ] from Q( 18 - corr_rshifts[ k ] ) to Q( 16 ) */
+ if( 2 - corr_rshifts[k] > 0 ) {
+ temp32 = silk_RSHIFT( w[ k ], 2 - corr_rshifts[ k ] );
+ } else {
+ temp32 = silk_LSHIFT_SAT32( w[ k ], corr_rshifts[ k ] - 2 );
+ }
+
+ g_Q26 = silk_MUL(
+ silk_DIV32(
+ SILK_FIX_CONST( LTP_SMOOTHING, 26 ),
+ silk_RSHIFT( SILK_FIX_CONST( LTP_SMOOTHING, 26 ), 10 ) + temp32 ), /* Q10 */
+ silk_LSHIFT_SAT32( silk_SUB_SAT32( (opus_int32)m_Q12, silk_RSHIFT( d_Q14[ k ], 2 ) ), 4 ) ); /* Q16 */
+
+ temp32 = 0;
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ delta_b_Q14[ i ] = silk_max_16( b_Q14_ptr[ i ], 1638 ); /* 1638_Q14 = 0.1_Q0 */
+ temp32 += delta_b_Q14[ i ]; /* Q14 */
+ }
+ temp32 = silk_DIV32( g_Q26, temp32 ); /* Q14 -> Q12 */
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ b_Q14_ptr[ i ] = silk_LIMIT_32( (opus_int32)b_Q14_ptr[ i ] + silk_SMULWB( silk_LSHIFT_SAT32( temp32, 4 ), delta_b_Q14[ i ] ), -16000, 28000 );
+ }
+ b_Q14_ptr += LTP_ORDER;
+ }
+}
+
+void silk_fit_LTP(
+ opus_int32 LTP_coefs_Q16[ LTP_ORDER ],
+ opus_int16 LTP_coefs_Q14[ LTP_ORDER ]
+)
+{
+ opus_int i;
+
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ LTP_coefs_Q14[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( LTP_coefs_Q16[ i ], 2 ) );
+ }
+}
diff --git a/drivers/opus/silk/fixed/find_pitch_lags_FIX.c b/drivers/opus/silk/fixed/find_pitch_lags_FIX.c
new file mode 100644
index 0000000000..0d00b3edf6
--- /dev/null
+++ b/drivers/opus/silk/fixed/find_pitch_lags_FIX.c
@@ -0,0 +1,145 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/fixed/main_FIX.h"
+#include "opus/celt/stack_alloc.h"
+#include "opus/silk/tuning_parameters.h"
+
+/* Find pitch lags */
+void silk_find_pitch_lags_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */
+ opus_int16 res[], /* O residual */
+ const opus_int16 x[], /* I Speech signal */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int buf_len, i, scale;
+ opus_int32 thrhld_Q13, res_nrg;
+ const opus_int16 *x_buf, *x_buf_ptr;
+ VARDECL( opus_int16, Wsig );
+ opus_int16 *Wsig_ptr;
+ opus_int32 auto_corr[ MAX_FIND_PITCH_LPC_ORDER + 1 ];
+ opus_int16 rc_Q15[ MAX_FIND_PITCH_LPC_ORDER ];
+ opus_int32 A_Q24[ MAX_FIND_PITCH_LPC_ORDER ];
+ opus_int16 A_Q12[ MAX_FIND_PITCH_LPC_ORDER ];
+ SAVE_STACK;
+
+ /******************************************/
+ /* Set up buffer lengths etc based on Fs */
+ /******************************************/
+ buf_len = psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length + psEnc->sCmn.ltp_mem_length;
+
+ /* Safety check */
+ silk_assert( buf_len >= psEnc->sCmn.pitch_LPC_win_length );
+
+ x_buf = x - psEnc->sCmn.ltp_mem_length;
+
+ /*************************************/
+ /* Estimate LPC AR coefficients */
+ /*************************************/
+
+ /* Calculate windowed signal */
+
+ ALLOC( Wsig, psEnc->sCmn.pitch_LPC_win_length, opus_int16 );
+
+ /* First LA_LTP samples */
+ x_buf_ptr = x_buf + buf_len - psEnc->sCmn.pitch_LPC_win_length;
+ Wsig_ptr = Wsig;
+ silk_apply_sine_window( Wsig_ptr, x_buf_ptr, 1, psEnc->sCmn.la_pitch );
+
+ /* Middle un - windowed samples */
+ Wsig_ptr += psEnc->sCmn.la_pitch;
+ x_buf_ptr += psEnc->sCmn.la_pitch;
+ silk_memcpy( Wsig_ptr, x_buf_ptr, ( psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 ) ) * sizeof( opus_int16 ) );
+
+ /* Last LA_LTP samples */
+ Wsig_ptr += psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 );
+ x_buf_ptr += psEnc->sCmn.pitch_LPC_win_length - silk_LSHIFT( psEnc->sCmn.la_pitch, 1 );
+ silk_apply_sine_window( Wsig_ptr, x_buf_ptr, 2, psEnc->sCmn.la_pitch );
+
+ /* Calculate autocorrelation sequence */
+ silk_autocorr( auto_corr, &scale, Wsig, psEnc->sCmn.pitch_LPC_win_length, psEnc->sCmn.pitchEstimationLPCOrder + 1, arch );
+
+ /* Add white noise, as fraction of energy */
+ auto_corr[ 0 ] = silk_SMLAWB( auto_corr[ 0 ], auto_corr[ 0 ], SILK_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) ) + 1;
+
+ /* Calculate the reflection coefficients using schur */
+ res_nrg = silk_schur( rc_Q15, auto_corr, psEnc->sCmn.pitchEstimationLPCOrder );
+
+ /* Prediction gain */
+ psEncCtrl->predGain_Q16 = silk_DIV32_varQ( auto_corr[ 0 ], silk_max_int( res_nrg, 1 ), 16 );
+
+ /* Convert reflection coefficients to prediction coefficients */
+ silk_k2a( A_Q24, rc_Q15, psEnc->sCmn.pitchEstimationLPCOrder );
+
+ /* Convert From 32 bit Q24 to 16 bit Q12 coefs */
+ for( i = 0; i < psEnc->sCmn.pitchEstimationLPCOrder; i++ ) {
+ A_Q12[ i ] = (opus_int16)silk_SAT16( silk_RSHIFT( A_Q24[ i ], 12 ) );
+ }
+
+ /* Do BWE */
+ silk_bwexpander( A_Q12, psEnc->sCmn.pitchEstimationLPCOrder, SILK_FIX_CONST( FIND_PITCH_BANDWIDTH_EXPANSION, 16 ) );
+
+ /*****************************************/
+ /* LPC analysis filtering */
+ /*****************************************/
+ silk_LPC_analysis_filter( res, x_buf, A_Q12, buf_len, psEnc->sCmn.pitchEstimationLPCOrder );
+
+ if( psEnc->sCmn.indices.signalType != TYPE_NO_VOICE_ACTIVITY && psEnc->sCmn.first_frame_after_reset == 0 ) {
+ /* Threshold for pitch estimator */
+ thrhld_Q13 = SILK_FIX_CONST( 0.6, 13 );
+ thrhld_Q13 = silk_SMLABB( thrhld_Q13, SILK_FIX_CONST( -0.004, 13 ), psEnc->sCmn.pitchEstimationLPCOrder );
+ thrhld_Q13 = silk_SMLAWB( thrhld_Q13, SILK_FIX_CONST( -0.1, 21 ), psEnc->sCmn.speech_activity_Q8 );
+ thrhld_Q13 = silk_SMLABB( thrhld_Q13, SILK_FIX_CONST( -0.15, 13 ), silk_RSHIFT( psEnc->sCmn.prevSignalType, 1 ) );
+ thrhld_Q13 = silk_SMLAWB( thrhld_Q13, SILK_FIX_CONST( -0.1, 14 ), psEnc->sCmn.input_tilt_Q15 );
+ thrhld_Q13 = silk_SAT16( thrhld_Q13 );
+
+ /*****************************************/
+ /* Call pitch estimator */
+ /*****************************************/
+ if( silk_pitch_analysis_core( res, psEncCtrl->pitchL, &psEnc->sCmn.indices.lagIndex, &psEnc->sCmn.indices.contourIndex,
+ &psEnc->LTPCorr_Q15, psEnc->sCmn.prevLag, psEnc->sCmn.pitchEstimationThreshold_Q16,
+ (opus_int)thrhld_Q13, psEnc->sCmn.fs_kHz, psEnc->sCmn.pitchEstimationComplexity, psEnc->sCmn.nb_subfr,
+ psEnc->sCmn.arch) == 0 )
+ {
+ psEnc->sCmn.indices.signalType = TYPE_VOICED;
+ } else {
+ psEnc->sCmn.indices.signalType = TYPE_UNVOICED;
+ }
+ } else {
+ silk_memset( psEncCtrl->pitchL, 0, sizeof( psEncCtrl->pitchL ) );
+ psEnc->sCmn.indices.lagIndex = 0;
+ psEnc->sCmn.indices.contourIndex = 0;
+ psEnc->LTPCorr_Q15 = 0;
+ }
+ RESTORE_STACK;
+}
diff --git a/drivers/opus/silk/fixed/find_pred_coefs_FIX.c b/drivers/opus/silk/fixed/find_pred_coefs_FIX.c
new file mode 100644
index 0000000000..93b506b523
--- /dev/null
+++ b/drivers/opus/silk/fixed/find_pred_coefs_FIX.c
@@ -0,0 +1,147 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/fixed/main_FIX.h"
+#include "opus/celt/stack_alloc.h"
+
+void silk_find_pred_coefs_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */
+ const opus_int16 res_pitch[], /* I Residual from pitch analysis */
+ const opus_int16 x[], /* I Speech signal */
+ opus_int condCoding /* I The type of conditional coding to use */
+)
+{
+ opus_int i;
+ opus_int32 invGains_Q16[ MAX_NB_SUBFR ], local_gains[ MAX_NB_SUBFR ], Wght_Q15[ MAX_NB_SUBFR ];
+ opus_int16 NLSF_Q15[ MAX_LPC_ORDER ];
+ const opus_int16 *x_ptr;
+ opus_int16 *x_pre_ptr;
+ VARDECL( opus_int16, LPC_in_pre );
+ opus_int32 tmp, min_gain_Q16, minInvGain_Q30;
+ opus_int LTP_corrs_rshift[ MAX_NB_SUBFR ];
+ SAVE_STACK;
+
+ /* weighting for weighted least squares */
+ min_gain_Q16 = silk_int32_MAX >> 6;
+ for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ min_gain_Q16 = silk_min( min_gain_Q16, psEncCtrl->Gains_Q16[ i ] );
+ }
+ for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ /* Divide to Q16 */
+ silk_assert( psEncCtrl->Gains_Q16[ i ] > 0 );
+ /* Invert and normalize gains, and ensure that maximum invGains_Q16 is within range of a 16 bit int */
+ invGains_Q16[ i ] = silk_DIV32_varQ( min_gain_Q16, psEncCtrl->Gains_Q16[ i ], 16 - 2 );
+
+ /* Ensure Wght_Q15 a minimum value 1 */
+ invGains_Q16[ i ] = silk_max( invGains_Q16[ i ], 363 );
+
+ /* Square the inverted gains */
+ silk_assert( invGains_Q16[ i ] == silk_SAT16( invGains_Q16[ i ] ) );
+ tmp = silk_SMULWB( invGains_Q16[ i ], invGains_Q16[ i ] );
+ Wght_Q15[ i ] = silk_RSHIFT( tmp, 1 );
+
+ /* Invert the inverted and normalized gains */
+ local_gains[ i ] = silk_DIV32( ( (opus_int32)1 << 16 ), invGains_Q16[ i ] );
+ }
+
+ ALLOC( LPC_in_pre,
+ psEnc->sCmn.nb_subfr * psEnc->sCmn.predictLPCOrder
+ + psEnc->sCmn.frame_length, opus_int16 );
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ VARDECL( opus_int32, WLTP );
+
+ /**********/
+ /* VOICED */
+ /**********/
+ silk_assert( psEnc->sCmn.ltp_mem_length - psEnc->sCmn.predictLPCOrder >= psEncCtrl->pitchL[ 0 ] + LTP_ORDER / 2 );
+
+ ALLOC( WLTP, psEnc->sCmn.nb_subfr * LTP_ORDER * LTP_ORDER, opus_int32 );
+
+ /* LTP analysis */
+ silk_find_LTP_FIX( psEncCtrl->LTPCoef_Q14, WLTP, &psEncCtrl->LTPredCodGain_Q7,
+ res_pitch, psEncCtrl->pitchL, Wght_Q15, psEnc->sCmn.subfr_length,
+ psEnc->sCmn.nb_subfr, psEnc->sCmn.ltp_mem_length, LTP_corrs_rshift );
+
+ /* Quantize LTP gain parameters */
+ silk_quant_LTP_gains( psEncCtrl->LTPCoef_Q14, psEnc->sCmn.indices.LTPIndex, &psEnc->sCmn.indices.PERIndex,
+ &psEnc->sCmn.sum_log_gain_Q7, WLTP, psEnc->sCmn.mu_LTP_Q9, psEnc->sCmn.LTPQuantLowComplexity, psEnc->sCmn.nb_subfr);
+
+ /* Control LTP scaling */
+ silk_LTP_scale_ctrl_FIX( psEnc, psEncCtrl, condCoding );
+
+ /* Create LTP residual */
+ silk_LTP_analysis_filter_FIX( LPC_in_pre, x - psEnc->sCmn.predictLPCOrder, psEncCtrl->LTPCoef_Q14,
+ psEncCtrl->pitchL, invGains_Q16, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder );
+
+ } else {
+ /************/
+ /* UNVOICED */
+ /************/
+ /* Create signal with prepended subframes, scaled by inverse gains */
+ x_ptr = x - psEnc->sCmn.predictLPCOrder;
+ x_pre_ptr = LPC_in_pre;
+ for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ silk_scale_copy_vector16( x_pre_ptr, x_ptr, invGains_Q16[ i ],
+ psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder );
+ x_pre_ptr += psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder;
+ x_ptr += psEnc->sCmn.subfr_length;
+ }
+
+ silk_memset( psEncCtrl->LTPCoef_Q14, 0, psEnc->sCmn.nb_subfr * LTP_ORDER * sizeof( opus_int16 ) );
+ psEncCtrl->LTPredCodGain_Q7 = 0;
+ psEnc->sCmn.sum_log_gain_Q7 = 0;
+ }
+
+ /* Limit on total predictive coding gain */
+ if( psEnc->sCmn.first_frame_after_reset ) {
+ minInvGain_Q30 = SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN_AFTER_RESET, 30 );
+ } else {
+ minInvGain_Q30 = silk_log2lin( silk_SMLAWB( 16 << 7, (opus_int32)psEncCtrl->LTPredCodGain_Q7, SILK_FIX_CONST( 1.0 / 3, 16 ) ) ); /* Q16 */
+ minInvGain_Q30 = silk_DIV32_varQ( minInvGain_Q30,
+ silk_SMULWW( SILK_FIX_CONST( MAX_PREDICTION_POWER_GAIN, 0 ),
+ silk_SMLAWB( SILK_FIX_CONST( 0.25, 18 ), SILK_FIX_CONST( 0.75, 18 ), psEncCtrl->coding_quality_Q14 ) ), 14 );
+ }
+
+ /* LPC_in_pre contains the LTP-filtered input for voiced, and the unfiltered input for unvoiced */
+ silk_find_LPC_FIX( &psEnc->sCmn, NLSF_Q15, LPC_in_pre, minInvGain_Q30 );
+
+ /* Quantize LSFs */
+ silk_process_NLSFs( &psEnc->sCmn, psEncCtrl->PredCoef_Q12, NLSF_Q15, psEnc->sCmn.prev_NLSFq_Q15 );
+
+ /* Calculate residual energy using quantized LPC coefficients */
+ silk_residual_energy_FIX( psEncCtrl->ResNrg, psEncCtrl->ResNrgQ, LPC_in_pre, psEncCtrl->PredCoef_Q12, local_gains,
+ psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder );
+
+ /* Copy to prediction struct for use in next frame for interpolation */
+ silk_memcpy( psEnc->sCmn.prev_NLSFq_Q15, NLSF_Q15, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) );
+ RESTORE_STACK;
+}
diff --git a/drivers/opus/silk/fixed/k2a_FIX.c b/drivers/opus/silk/fixed/k2a_FIX.c
new file mode 100644
index 0000000000..7d5808f190
--- /dev/null
+++ b/drivers/opus/silk/fixed/k2a_FIX.c
@@ -0,0 +1,53 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/SigProc_FIX.h"
+
+/* Step up function, converts reflection coefficients to prediction coefficients */
+void silk_k2a(
+ opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */
+ const opus_int16 *rc_Q15, /* I Reflection coefficients [order] Q15 */
+ const opus_int32 order /* I Prediction order */
+)
+{
+ opus_int k, n;
+ opus_int32 Atmp[ SILK_MAX_ORDER_LPC ];
+
+ for( k = 0; k < order; k++ ) {
+ for( n = 0; n < k; n++ ) {
+ Atmp[ n ] = A_Q24[ n ];
+ }
+ for( n = 0; n < k; n++ ) {
+ A_Q24[ n ] = silk_SMLAWB( A_Q24[ n ], silk_LSHIFT( Atmp[ k - n - 1 ], 1 ), rc_Q15[ k ] );
+ }
+ A_Q24[ k ] = -silk_LSHIFT( (opus_int32)rc_Q15[ k ], 9 );
+ }
+}
diff --git a/drivers/opus/silk/fixed/k2a_Q16_FIX.c b/drivers/opus/silk/fixed/k2a_Q16_FIX.c
new file mode 100644
index 0000000000..8df61dc3f6
--- /dev/null
+++ b/drivers/opus/silk/fixed/k2a_Q16_FIX.c
@@ -0,0 +1,53 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/SigProc_FIX.h"
+
+/* Step up function, converts reflection coefficients to prediction coefficients */
+void silk_k2a_Q16(
+ opus_int32 *A_Q24, /* O Prediction coefficients [order] Q24 */
+ const opus_int32 *rc_Q16, /* I Reflection coefficients [order] Q16 */
+ const opus_int32 order /* I Prediction order */
+)
+{
+ opus_int k, n;
+ opus_int32 Atmp[ SILK_MAX_ORDER_LPC ];
+
+ for( k = 0; k < order; k++ ) {
+ for( n = 0; n < k; n++ ) {
+ Atmp[ n ] = A_Q24[ n ];
+ }
+ for( n = 0; n < k; n++ ) {
+ A_Q24[ n ] = silk_SMLAWW( A_Q24[ n ], Atmp[ k - n - 1 ], rc_Q16[ k ] );
+ }
+ A_Q24[ k ] = -silk_LSHIFT( rc_Q16[ k ], 8 );
+ }
+}
diff --git a/drivers/opus/silk/fixed/main_FIX.h b/drivers/opus/silk/fixed/main_FIX.h
new file mode 100644
index 0000000000..71a560ef0e
--- /dev/null
+++ b/drivers/opus/silk/fixed/main_FIX.h
@@ -0,0 +1,257 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_MAIN_FIX_H
+#define SILK_MAIN_FIX_H
+
+#include "opus/silk/SigProc_FIX.h"
+#include "opus/silk/fixed/structs_FIX.h"
+#include "opus/silk/control.h"
+#include "opus/silk/silk_main.h"
+#include "opus/silk/PLC.h"
+#include "opus/silk/debug.h"
+#include "opus/celt/entenc.h"
+
+#ifndef FORCE_CPP_BUILD
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+#endif
+
+#define silk_encoder_state_Fxx silk_encoder_state_FIX
+#define silk_encode_do_VAD_Fxx silk_encode_do_VAD_FIX
+#define silk_encode_frame_Fxx silk_encode_frame_FIX
+
+/*********************/
+/* Encoder Functions */
+/*********************/
+
+/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */
+void silk_HP_variable_cutoff(
+ silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */
+);
+
+/* Encoder main function */
+void silk_encode_do_VAD_FIX(
+ silk_encoder_state_FIX *psEnc /* I/O Pointer to Silk FIX encoder state */
+);
+
+/* Encoder main function */
+opus_int silk_encode_frame_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Pointer to Silk FIX encoder state */
+ opus_int32 *pnBytesOut, /* O Pointer to number of payload bytes; */
+ ec_enc *psRangeEnc, /* I/O compressor data structure */
+ opus_int condCoding, /* I The type of conditional coding to use */
+ opus_int maxBits, /* I If > 0: maximum number of output bits */
+ opus_int useCBR /* I Flag to force constant-bitrate operation */
+);
+
+/* Initializes the Silk encoder state */
+opus_int silk_init_encoder(
+ silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk FIX encoder state */
+ int arch /* I Run-time architecture */
+);
+
+/* Control the Silk encoder */
+opus_int silk_control_encoder(
+ silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk encoder state */
+ silk_EncControlStruct *encControl, /* I Control structure */
+ const opus_int32 TargetRate_bps, /* I Target max bitrate (bps) */
+ const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */
+ const opus_int channelNb, /* I Channel number */
+ const opus_int force_fs_kHz
+);
+
+/****************/
+/* Prefiltering */
+/****************/
+void silk_prefilter_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Encoder state */
+ const silk_encoder_control_FIX *psEncCtrl, /* I Encoder control */
+ opus_int32 xw_Q10[], /* O Weighted signal */
+ const opus_int16 x[] /* I Speech signal */
+);
+
+/**************************/
+/* Noise shaping analysis */
+/**************************/
+/* Compute noise shaping coefficients and initial gain values */
+void silk_noise_shape_analysis_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */
+ const opus_int16 *pitch_res, /* I LPC residual from pitch analysis */
+ const opus_int16 *x, /* I Input signal [ frame_length + la_shape ] */
+ int arch /* I Run-time architecture */
+);
+
+/* Autocorrelations for a warped frequency axis */
+void silk_warped_autocorrelation_FIX(
+ opus_int32 *corr, /* O Result [order + 1] */
+ opus_int *scale, /* O Scaling of the correlation vector */
+ const opus_int16 *input, /* I Input data to correlate */
+ const opus_int warping_Q16, /* I Warping coefficient */
+ const opus_int length, /* I Length of input */
+ const opus_int order /* I Correlation order (even) */
+);
+
+/* Calculation of LTP state scaling */
+void silk_LTP_scale_ctrl_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */
+ opus_int condCoding /* I The type of conditional coding to use */
+);
+
+/**********************************************/
+/* Prediction Analysis */
+/**********************************************/
+/* Find pitch lags */
+void silk_find_pitch_lags_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */
+ opus_int16 res[], /* O residual */
+ const opus_int16 x[], /* I Speech signal */
+ int arch /* I Run-time architecture */
+);
+
+/* Find LPC and LTP coefficients */
+void silk_find_pred_coefs_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O encoder control */
+ const opus_int16 res_pitch[], /* I Residual from pitch analysis */
+ const opus_int16 x[], /* I Speech signal */
+ opus_int condCoding /* I The type of conditional coding to use */
+);
+
+/* LPC analysis */
+void silk_find_LPC_FIX(
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ opus_int16 NLSF_Q15[], /* O NLSFs */
+ const opus_int16 x[], /* I Input signal */
+ const opus_int32 minInvGain_Q30 /* I Inverse of max prediction gain */
+);
+
+/* LTP analysis */
+void silk_find_LTP_FIX(
+ opus_int16 b_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* O LTP coefs */
+ opus_int32 WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */
+ opus_int *LTPredCodGain_Q7, /* O LTP coding gain */
+ const opus_int16 r_lpc[], /* I residual signal after LPC signal + state for first 10 ms */
+ const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */
+ const opus_int32 Wght_Q15[ MAX_NB_SUBFR ], /* I weights */
+ const opus_int subfr_length, /* I subframe length */
+ const opus_int nb_subfr, /* I number of subframes */
+ const opus_int mem_offset, /* I number of samples in LTP memory */
+ opus_int corr_rshifts[ MAX_NB_SUBFR ] /* O right shifts applied to correlations */
+);
+
+void silk_LTP_analysis_filter_FIX(
+ opus_int16 *LTP_res, /* O LTP residual signal of length MAX_NB_SUBFR * ( pre_length + subfr_length ) */
+ const opus_int16 *x, /* I Pointer to input signal with at least max( pitchL ) preceding samples */
+ const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ],/* I LTP_ORDER LTP coefficients for each MAX_NB_SUBFR subframe */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lag, one for each subframe */
+ const opus_int32 invGains_Q16[ MAX_NB_SUBFR ], /* I Inverse quantization gains, one for each subframe */
+ const opus_int subfr_length, /* I Length of each subframe */
+ const opus_int nb_subfr, /* I Number of subframes */
+ const opus_int pre_length /* I Length of the preceding samples starting at &x[0] for each subframe */
+);
+
+/* Calculates residual energies of input subframes where all subframes have LPC_order */
+/* of preceding samples */
+void silk_residual_energy_FIX(
+ opus_int32 nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */
+ opus_int nrgsQ[ MAX_NB_SUBFR ], /* O Q value per subframe */
+ const opus_int16 x[], /* I Input signal */
+ opus_int16 a_Q12[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */
+ const opus_int32 gains[ MAX_NB_SUBFR ], /* I Quantization gains */
+ const opus_int subfr_length, /* I Subframe length */
+ const opus_int nb_subfr, /* I Number of subframes */
+ const opus_int LPC_order /* I LPC order */
+);
+
+/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */
+opus_int32 silk_residual_energy16_covar_FIX(
+ const opus_int16 *c, /* I Prediction vector */
+ const opus_int32 *wXX, /* I Correlation matrix */
+ const opus_int32 *wXx, /* I Correlation vector */
+ opus_int32 wxx, /* I Signal energy */
+ opus_int D, /* I Dimension */
+ opus_int cQ /* I Q value for c vector 0 - 15 */
+);
+
+/* Processing of gains */
+void silk_process_gains_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control */
+ opus_int condCoding /* I The type of conditional coding to use */
+);
+
+/******************/
+/* Linear Algebra */
+/******************/
+/* Calculates correlation matrix X'*X */
+void silk_corrMatrix_FIX(
+ const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */
+ const opus_int L, /* I Length of vectors */
+ const opus_int order, /* I Max lag for correlation */
+ const opus_int head_room, /* I Desired headroom */
+ opus_int32 *XX, /* O Pointer to X'*X correlation matrix [ order x order ] */
+ opus_int *rshifts /* I/O Right shifts of correlations */
+);
+
+/* Calculates correlation vector X'*t */
+void silk_corrVector_FIX(
+ const opus_int16 *x, /* I x vector [L + order - 1] used to form data matrix X */
+ const opus_int16 *t, /* I Target vector [L] */
+ const opus_int L, /* I Length of vectors */
+ const opus_int order, /* I Max lag for correlation */
+ opus_int32 *Xt, /* O Pointer to X'*t correlation vector [order] */
+ const opus_int rshifts /* I Right shifts of correlations */
+);
+
+/* Add noise to matrix diagonal */
+void silk_regularize_correlations_FIX(
+ opus_int32 *XX, /* I/O Correlation matrices */
+ opus_int32 *xx, /* I/O Correlation values */
+ opus_int32 noise, /* I Noise to add */
+ opus_int D /* I Dimension of XX */
+);
+
+/* Solves Ax = b, assuming A is symmetric */
+void silk_solve_LDL_FIX(
+ opus_int32 *A, /* I Pointer to symetric square matrix A */
+ opus_int M, /* I Size of matrix */
+ const opus_int32 *b, /* I Pointer to b vector */
+ opus_int32 *x_Q16 /* O Pointer to x solution vector */
+);
+
+#ifndef FORCE_CPP_BUILD
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* FORCE_CPP_BUILD */
+#endif /* SILK_MAIN_FIX_H */
diff --git a/drivers/opus/silk/fixed/noise_shape_analysis_FIX.c b/drivers/opus/silk/fixed/noise_shape_analysis_FIX.c
new file mode 100644
index 0000000000..862640d2c8
--- /dev/null
+++ b/drivers/opus/silk/fixed/noise_shape_analysis_FIX.c
@@ -0,0 +1,445 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/fixed/main_FIX.h"
+#include "opus/celt/stack_alloc.h"
+#include "opus/silk/tuning_parameters.h"
+
+/* Compute gain to make warped filter coefficients have a zero mean log frequency response on a */
+/* non-warped frequency scale. (So that it can be implemented with a minimum-phase monic filter.) */
+/* Note: A monic filter is one with the first coefficient equal to 1.0. In Silk we omit the first */
+/* coefficient in an array of coefficients, for monic filters. */
+static OPUS_INLINE opus_int32 warped_gain( /* gain in Q16*/
+ const opus_int32 *coefs_Q24,
+ opus_int lambda_Q16,
+ opus_int order
+) {
+ opus_int i;
+ opus_int32 gain_Q24;
+
+ lambda_Q16 = -lambda_Q16;
+ gain_Q24 = coefs_Q24[ order - 1 ];
+ for( i = order - 2; i >= 0; i-- ) {
+ gain_Q24 = silk_SMLAWB( coefs_Q24[ i ], gain_Q24, lambda_Q16 );
+ }
+ gain_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), gain_Q24, -lambda_Q16 );
+ return silk_INVERSE32_varQ( gain_Q24, 40 );
+}
+
+/* Convert warped filter coefficients to monic pseudo-warped coefficients and limit maximum */
+/* amplitude of monic warped coefficients by using bandwidth expansion on the true coefficients */
+static OPUS_INLINE void limit_warped_coefs(
+ opus_int32 *coefs_syn_Q24,
+ opus_int32 *coefs_ana_Q24,
+ opus_int lambda_Q16,
+ opus_int32 limit_Q24,
+ opus_int order
+) {
+ opus_int i, iter, ind = 0;
+ opus_int32 tmp, maxabs_Q24, chirp_Q16, gain_syn_Q16, gain_ana_Q16;
+ opus_int32 nom_Q16, den_Q24;
+
+ /* Convert to monic coefficients */
+ lambda_Q16 = -lambda_Q16;
+ for( i = order - 1; i > 0; i-- ) {
+ coefs_syn_Q24[ i - 1 ] = silk_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 );
+ coefs_ana_Q24[ i - 1 ] = silk_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 );
+ }
+ lambda_Q16 = -lambda_Q16;
+ nom_Q16 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 16 ), -(opus_int32)lambda_Q16, lambda_Q16 );
+ den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_syn_Q24[ 0 ], lambda_Q16 );
+ gain_syn_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 );
+ den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_ana_Q24[ 0 ], lambda_Q16 );
+ gain_ana_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 );
+ for( i = 0; i < order; i++ ) {
+ coefs_syn_Q24[ i ] = silk_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] );
+ coefs_ana_Q24[ i ] = silk_SMULWW( gain_ana_Q16, coefs_ana_Q24[ i ] );
+ }
+
+ for( iter = 0; iter < 10; iter++ ) {
+ /* Find maximum absolute value */
+ maxabs_Q24 = -1;
+ for( i = 0; i < order; i++ ) {
+ tmp = silk_max( silk_abs_int32( coefs_syn_Q24[ i ] ), silk_abs_int32( coefs_ana_Q24[ i ] ) );
+ if( tmp > maxabs_Q24 ) {
+ maxabs_Q24 = tmp;
+ ind = i;
+ }
+ }
+ if( maxabs_Q24 <= limit_Q24 ) {
+ /* Coefficients are within range - done */
+ return;
+ }
+
+ /* Convert back to true warped coefficients */
+ for( i = 1; i < order; i++ ) {
+ coefs_syn_Q24[ i - 1 ] = silk_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 );
+ coefs_ana_Q24[ i - 1 ] = silk_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 );
+ }
+ gain_syn_Q16 = silk_INVERSE32_varQ( gain_syn_Q16, 32 );
+ gain_ana_Q16 = silk_INVERSE32_varQ( gain_ana_Q16, 32 );
+ for( i = 0; i < order; i++ ) {
+ coefs_syn_Q24[ i ] = silk_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] );
+ coefs_ana_Q24[ i ] = silk_SMULWW( gain_ana_Q16, coefs_ana_Q24[ i ] );
+ }
+
+ /* Apply bandwidth expansion */
+ chirp_Q16 = SILK_FIX_CONST( 0.99, 16 ) - silk_DIV32_varQ(
+ silk_SMULWB( maxabs_Q24 - limit_Q24, silk_SMLABB( SILK_FIX_CONST( 0.8, 10 ), SILK_FIX_CONST( 0.1, 10 ), iter ) ),
+ silk_MUL( maxabs_Q24, ind + 1 ), 22 );
+ silk_bwexpander_32( coefs_syn_Q24, order, chirp_Q16 );
+ silk_bwexpander_32( coefs_ana_Q24, order, chirp_Q16 );
+
+ /* Convert to monic warped coefficients */
+ lambda_Q16 = -lambda_Q16;
+ for( i = order - 1; i > 0; i-- ) {
+ coefs_syn_Q24[ i - 1 ] = silk_SMLAWB( coefs_syn_Q24[ i - 1 ], coefs_syn_Q24[ i ], lambda_Q16 );
+ coefs_ana_Q24[ i - 1 ] = silk_SMLAWB( coefs_ana_Q24[ i - 1 ], coefs_ana_Q24[ i ], lambda_Q16 );
+ }
+ lambda_Q16 = -lambda_Q16;
+ nom_Q16 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 16 ), -(opus_int32)lambda_Q16, lambda_Q16 );
+ den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_syn_Q24[ 0 ], lambda_Q16 );
+ gain_syn_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 );
+ den_Q24 = silk_SMLAWB( SILK_FIX_CONST( 1.0, 24 ), coefs_ana_Q24[ 0 ], lambda_Q16 );
+ gain_ana_Q16 = silk_DIV32_varQ( nom_Q16, den_Q24, 24 );
+ for( i = 0; i < order; i++ ) {
+ coefs_syn_Q24[ i ] = silk_SMULWW( gain_syn_Q16, coefs_syn_Q24[ i ] );
+ coefs_ana_Q24[ i ] = silk_SMULWW( gain_ana_Q16, coefs_ana_Q24[ i ] );
+ }
+ }
+ silk_assert( 0 );
+}
+
+/**************************************************************/
+/* Compute noise shaping coefficients and initial gain values */
+/**************************************************************/
+void silk_noise_shape_analysis_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Encoder state FIX */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control FIX */
+ const opus_int16 *pitch_res, /* I LPC residual from pitch analysis */
+ const opus_int16 *x, /* I Input signal [ frame_length + la_shape ] */
+ int arch /* I Run-time architecture */
+)
+{
+ silk_shape_state_FIX *psShapeSt = &psEnc->sShape;
+ opus_int k, i, nSamples, Qnrg, b_Q14, warping_Q16, scale = 0;
+ opus_int32 SNR_adj_dB_Q7, HarmBoost_Q16, HarmShapeGain_Q16, Tilt_Q16, tmp32;
+ opus_int32 nrg, pre_nrg_Q30, log_energy_Q7, log_energy_prev_Q7, energy_variation_Q7;
+ opus_int32 delta_Q16, BWExp1_Q16, BWExp2_Q16, gain_mult_Q16, gain_add_Q16, strength_Q16, b_Q8;
+ opus_int32 auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ];
+ opus_int32 refl_coef_Q16[ MAX_SHAPE_LPC_ORDER ];
+ opus_int32 AR1_Q24[ MAX_SHAPE_LPC_ORDER ];
+ opus_int32 AR2_Q24[ MAX_SHAPE_LPC_ORDER ];
+ VARDECL( opus_int16, x_windowed );
+ const opus_int16 *x_ptr, *pitch_res_ptr;
+ SAVE_STACK;
+
+ /* Point to start of first LPC analysis block */
+ x_ptr = x - psEnc->sCmn.la_shape;
+
+ /****************/
+ /* GAIN CONTROL */
+ /****************/
+ SNR_adj_dB_Q7 = psEnc->sCmn.SNR_dB_Q7;
+
+ /* Input quality is the average of the quality in the lowest two VAD bands */
+ psEncCtrl->input_quality_Q14 = ( opus_int )silk_RSHIFT( (opus_int32)psEnc->sCmn.input_quality_bands_Q15[ 0 ]
+ + psEnc->sCmn.input_quality_bands_Q15[ 1 ], 2 );
+
+ /* Coding quality level, between 0.0_Q0 and 1.0_Q0, but in Q14 */
+ psEncCtrl->coding_quality_Q14 = silk_RSHIFT( silk_sigm_Q15( silk_RSHIFT_ROUND( SNR_adj_dB_Q7 -
+ SILK_FIX_CONST( 20.0, 7 ), 4 ) ), 1 );
+
+ /* Reduce coding SNR during low speech activity */
+ if( psEnc->sCmn.useCBR == 0 ) {
+ b_Q8 = SILK_FIX_CONST( 1.0, 8 ) - psEnc->sCmn.speech_activity_Q8;
+ b_Q8 = silk_SMULWB( silk_LSHIFT( b_Q8, 8 ), b_Q8 );
+ SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7,
+ silk_SMULBB( SILK_FIX_CONST( -BG_SNR_DECR_dB, 7 ) >> ( 4 + 1 ), b_Q8 ), /* Q11*/
+ silk_SMULWB( SILK_FIX_CONST( 1.0, 14 ) + psEncCtrl->input_quality_Q14, psEncCtrl->coding_quality_Q14 ) ); /* Q12*/
+ }
+
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ /* Reduce gains for periodic signals */
+ SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, SILK_FIX_CONST( HARM_SNR_INCR_dB, 8 ), psEnc->LTPCorr_Q15 );
+ } else {
+ /* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */
+ SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7,
+ silk_SMLAWB( SILK_FIX_CONST( 6.0, 9 ), -SILK_FIX_CONST( 0.4, 18 ), psEnc->sCmn.SNR_dB_Q7 ),
+ SILK_FIX_CONST( 1.0, 14 ) - psEncCtrl->input_quality_Q14 );
+ }
+
+ /*************************/
+ /* SPARSENESS PROCESSING */
+ /*************************/
+ /* Set quantizer offset */
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ /* Initially set to 0; may be overruled in process_gains(..) */
+ psEnc->sCmn.indices.quantOffsetType = 0;
+ psEncCtrl->sparseness_Q8 = 0;
+ } else {
+ /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */
+ nSamples = silk_LSHIFT( psEnc->sCmn.fs_kHz, 1 );
+ energy_variation_Q7 = 0;
+ log_energy_prev_Q7 = 0;
+ pitch_res_ptr = pitch_res;
+ for( k = 0; k < silk_SMULBB( SUB_FRAME_LENGTH_MS, psEnc->sCmn.nb_subfr ) / 2; k++ ) {
+ silk_sum_sqr_shift( &nrg, &scale, pitch_res_ptr, nSamples );
+ nrg += silk_RSHIFT( nSamples, scale ); /* Q(-scale)*/
+
+ log_energy_Q7 = silk_lin2log( nrg );
+ if( k > 0 ) {
+ energy_variation_Q7 += silk_abs( log_energy_Q7 - log_energy_prev_Q7 );
+ }
+ log_energy_prev_Q7 = log_energy_Q7;
+ pitch_res_ptr += nSamples;
+ }
+
+ psEncCtrl->sparseness_Q8 = silk_RSHIFT( silk_sigm_Q15( silk_SMULWB( energy_variation_Q7 -
+ SILK_FIX_CONST( 5.0, 7 ), SILK_FIX_CONST( 0.1, 16 ) ) ), 7 );
+
+ /* Set quantization offset depending on sparseness measure */
+ if( psEncCtrl->sparseness_Q8 > SILK_FIX_CONST( SPARSENESS_THRESHOLD_QNT_OFFSET, 8 ) ) {
+ psEnc->sCmn.indices.quantOffsetType = 0;
+ } else {
+ psEnc->sCmn.indices.quantOffsetType = 1;
+ }
+
+ /* Increase coding SNR for sparse signals */
+ SNR_adj_dB_Q7 = silk_SMLAWB( SNR_adj_dB_Q7, SILK_FIX_CONST( SPARSE_SNR_INCR_dB, 15 ), psEncCtrl->sparseness_Q8 - SILK_FIX_CONST( 0.5, 8 ) );
+ }
+
+ /*******************************/
+ /* Control bandwidth expansion */
+ /*******************************/
+ /* More BWE for signals with high prediction gain */
+ strength_Q16 = silk_SMULWB( psEncCtrl->predGain_Q16, SILK_FIX_CONST( FIND_PITCH_WHITE_NOISE_FRACTION, 16 ) );
+ BWExp1_Q16 = BWExp2_Q16 = silk_DIV32_varQ( SILK_FIX_CONST( BANDWIDTH_EXPANSION, 16 ),
+ silk_SMLAWW( SILK_FIX_CONST( 1.0, 16 ), strength_Q16, strength_Q16 ), 16 );
+ delta_Q16 = silk_SMULWB( SILK_FIX_CONST( 1.0, 16 ) - silk_SMULBB( 3, psEncCtrl->coding_quality_Q14 ),
+ SILK_FIX_CONST( LOW_RATE_BANDWIDTH_EXPANSION_DELTA, 16 ) );
+ BWExp1_Q16 = silk_SUB32( BWExp1_Q16, delta_Q16 );
+ BWExp2_Q16 = silk_ADD32( BWExp2_Q16, delta_Q16 );
+ /* BWExp1 will be applied after BWExp2, so make it relative */
+ BWExp1_Q16 = silk_DIV32_16( silk_LSHIFT( BWExp1_Q16, 14 ), silk_RSHIFT( BWExp2_Q16, 2 ) );
+
+ if( psEnc->sCmn.warping_Q16 > 0 ) {
+ /* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */
+ warping_Q16 = silk_SMLAWB( psEnc->sCmn.warping_Q16, (opus_int32)psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( 0.01, 18 ) );
+ } else {
+ warping_Q16 = 0;
+ }
+
+ /********************************************/
+ /* Compute noise shaping AR coefs and gains */
+ /********************************************/
+ ALLOC( x_windowed, psEnc->sCmn.shapeWinLength, opus_int16 );
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ /* Apply window: sine slope followed by flat part followed by cosine slope */
+ opus_int shift, slope_part, flat_part;
+ flat_part = psEnc->sCmn.fs_kHz * 3;
+ slope_part = silk_RSHIFT( psEnc->sCmn.shapeWinLength - flat_part, 1 );
+
+ silk_apply_sine_window( x_windowed, x_ptr, 1, slope_part );
+ shift = slope_part;
+ silk_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(opus_int16) );
+ shift += flat_part;
+ silk_apply_sine_window( x_windowed + shift, x_ptr + shift, 2, slope_part );
+
+ /* Update pointer: next LPC analysis block */
+ x_ptr += psEnc->sCmn.subfr_length;
+
+ if( psEnc->sCmn.warping_Q16 > 0 ) {
+ /* Calculate warped auto correlation */
+ silk_warped_autocorrelation_FIX( auto_corr, &scale, x_windowed, warping_Q16, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder );
+ } else {
+ /* Calculate regular auto correlation */
+ silk_autocorr( auto_corr, &scale, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1, arch );
+ }
+
+ /* Add white noise, as a fraction of energy */
+ auto_corr[0] = silk_ADD32( auto_corr[0], silk_max_32( silk_SMULWB( silk_RSHIFT( auto_corr[ 0 ], 4 ),
+ SILK_FIX_CONST( SHAPE_WHITE_NOISE_FRACTION, 20 ) ), 1 ) );
+
+ /* Calculate the reflection coefficients using schur */
+ nrg = silk_schur64( refl_coef_Q16, auto_corr, psEnc->sCmn.shapingLPCOrder );
+ silk_assert( nrg >= 0 );
+
+ /* Convert reflection coefficients to prediction coefficients */
+ silk_k2a_Q16( AR2_Q24, refl_coef_Q16, psEnc->sCmn.shapingLPCOrder );
+
+ Qnrg = -scale; /* range: -12...30*/
+ silk_assert( Qnrg >= -12 );
+ silk_assert( Qnrg <= 30 );
+
+ /* Make sure that Qnrg is an even number */
+ if( Qnrg & 1 ) {
+ Qnrg -= 1;
+ nrg >>= 1;
+ }
+
+ tmp32 = silk_SQRT_APPROX( nrg );
+ Qnrg >>= 1; /* range: -6...15*/
+
+ psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( tmp32, 16 - Qnrg );
+
+ if( psEnc->sCmn.warping_Q16 > 0 ) {
+ /* Adjust gain for warping */
+ gain_mult_Q16 = warped_gain( AR2_Q24, warping_Q16, psEnc->sCmn.shapingLPCOrder );
+ silk_assert( psEncCtrl->Gains_Q16[ k ] >= 0 );
+ if ( silk_SMULWW( silk_RSHIFT_ROUND( psEncCtrl->Gains_Q16[ k ], 1 ), gain_mult_Q16 ) >= ( silk_int32_MAX >> 1 ) ) {
+ psEncCtrl->Gains_Q16[ k ] = silk_int32_MAX;
+ } else {
+ psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 );
+ }
+ }
+
+ /* Bandwidth expansion for synthesis filter shaping */
+ silk_bwexpander_32( AR2_Q24, psEnc->sCmn.shapingLPCOrder, BWExp2_Q16 );
+
+ /* Compute noise shaping filter coefficients */
+ silk_memcpy( AR1_Q24, AR2_Q24, psEnc->sCmn.shapingLPCOrder * sizeof( opus_int32 ) );
+
+ /* Bandwidth expansion for analysis filter shaping */
+ silk_assert( BWExp1_Q16 <= SILK_FIX_CONST( 1.0, 16 ) );
+ silk_bwexpander_32( AR1_Q24, psEnc->sCmn.shapingLPCOrder, BWExp1_Q16 );
+
+ /* Ratio of prediction gains, in energy domain */
+ pre_nrg_Q30 = silk_LPC_inverse_pred_gain_Q24( AR2_Q24, psEnc->sCmn.shapingLPCOrder );
+ nrg = silk_LPC_inverse_pred_gain_Q24( AR1_Q24, psEnc->sCmn.shapingLPCOrder );
+
+ /*psEncCtrl->GainsPre[ k ] = 1.0f - 0.7f * ( 1.0f - pre_nrg / nrg ) = 0.3f + 0.7f * pre_nrg / nrg;*/
+ pre_nrg_Q30 = silk_LSHIFT32( silk_SMULWB( pre_nrg_Q30, SILK_FIX_CONST( 0.7, 15 ) ), 1 );
+ psEncCtrl->GainsPre_Q14[ k ] = ( opus_int ) SILK_FIX_CONST( 0.3, 14 ) + silk_DIV32_varQ( pre_nrg_Q30, nrg, 14 );
+
+ /* Convert to monic warped prediction coefficients and limit absolute values */
+ limit_warped_coefs( AR2_Q24, AR1_Q24, warping_Q16, SILK_FIX_CONST( 3.999, 24 ), psEnc->sCmn.shapingLPCOrder );
+
+ /* Convert from Q24 to Q13 and store in int16 */
+ for( i = 0; i < psEnc->sCmn.shapingLPCOrder; i++ ) {
+ psEncCtrl->AR1_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( AR1_Q24[ i ], 11 ) );
+ psEncCtrl->AR2_Q13[ k * MAX_SHAPE_LPC_ORDER + i ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( AR2_Q24[ i ], 11 ) );
+ }
+ }
+
+ /*****************/
+ /* Gain tweaking */
+ /*****************/
+ /* Increase gains during low speech activity and put lower limit on gains */
+ gain_mult_Q16 = silk_log2lin( -silk_SMLAWB( -SILK_FIX_CONST( 16.0, 7 ), SNR_adj_dB_Q7, SILK_FIX_CONST( 0.16, 16 ) ) );
+ gain_add_Q16 = silk_log2lin( silk_SMLAWB( SILK_FIX_CONST( 16.0, 7 ), SILK_FIX_CONST( MIN_QGAIN_DB, 7 ), SILK_FIX_CONST( 0.16, 16 ) ) );
+ silk_assert( gain_mult_Q16 > 0 );
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ psEncCtrl->Gains_Q16[ k ] = silk_SMULWW( psEncCtrl->Gains_Q16[ k ], gain_mult_Q16 );
+ silk_assert( psEncCtrl->Gains_Q16[ k ] >= 0 );
+ psEncCtrl->Gains_Q16[ k ] = silk_ADD_POS_SAT32( psEncCtrl->Gains_Q16[ k ], gain_add_Q16 );
+ }
+
+ gain_mult_Q16 = SILK_FIX_CONST( 1.0, 16 ) + silk_RSHIFT_ROUND( silk_MLA( SILK_FIX_CONST( INPUT_TILT, 26 ),
+ psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( HIGH_RATE_INPUT_TILT, 12 ) ), 10 );
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ psEncCtrl->GainsPre_Q14[ k ] = silk_SMULWB( gain_mult_Q16, psEncCtrl->GainsPre_Q14[ k ] );
+ }
+
+ /************************************************/
+ /* Control low-frequency shaping and noise tilt */
+ /************************************************/
+ /* Less low frequency shaping for noisy inputs */
+ strength_Q16 = silk_MUL( SILK_FIX_CONST( LOW_FREQ_SHAPING, 4 ), silk_SMLAWB( SILK_FIX_CONST( 1.0, 12 ),
+ SILK_FIX_CONST( LOW_QUALITY_LOW_FREQ_SHAPING_DECR, 13 ), psEnc->sCmn.input_quality_bands_Q15[ 0 ] - SILK_FIX_CONST( 1.0, 15 ) ) );
+ strength_Q16 = silk_RSHIFT( silk_MUL( strength_Q16, psEnc->sCmn.speech_activity_Q8 ), 8 );
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ /* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */
+ /*f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10, 1])*/
+ opus_int fs_kHz_inv = silk_DIV32_16( SILK_FIX_CONST( 0.2, 14 ), psEnc->sCmn.fs_kHz );
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ b_Q14 = fs_kHz_inv + silk_DIV32_16( SILK_FIX_CONST( 3.0, 14 ), psEncCtrl->pitchL[ k ] );
+ /* Pack two coefficients in one int32 */
+ psEncCtrl->LF_shp_Q14[ k ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 - silk_SMULWB( strength_Q16, b_Q14 ), 16 );
+ psEncCtrl->LF_shp_Q14[ k ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) );
+ }
+ silk_assert( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ) < SILK_FIX_CONST( 0.5, 24 ) ); /* Guarantees that second argument to SMULWB() is within range of an opus_int16*/
+ Tilt_Q16 = - SILK_FIX_CONST( HP_NOISE_COEF, 16 ) -
+ silk_SMULWB( SILK_FIX_CONST( 1.0, 16 ) - SILK_FIX_CONST( HP_NOISE_COEF, 16 ),
+ silk_SMULWB( SILK_FIX_CONST( HARM_HP_NOISE_COEF, 24 ), psEnc->sCmn.speech_activity_Q8 ) );
+ } else {
+ b_Q14 = silk_DIV32_16( 21299, psEnc->sCmn.fs_kHz ); /* 1.3_Q0 = 21299_Q14*/
+ /* Pack two coefficients in one int32 */
+ psEncCtrl->LF_shp_Q14[ 0 ] = silk_LSHIFT( SILK_FIX_CONST( 1.0, 14 ) - b_Q14 -
+ silk_SMULWB( strength_Q16, silk_SMULWB( SILK_FIX_CONST( 0.6, 16 ), b_Q14 ) ), 16 );
+ psEncCtrl->LF_shp_Q14[ 0 ] |= (opus_uint16)( b_Q14 - SILK_FIX_CONST( 1.0, 14 ) );
+ for( k = 1; k < psEnc->sCmn.nb_subfr; k++ ) {
+ psEncCtrl->LF_shp_Q14[ k ] = psEncCtrl->LF_shp_Q14[ 0 ];
+ }
+ Tilt_Q16 = -SILK_FIX_CONST( HP_NOISE_COEF, 16 );
+ }
+
+ /****************************/
+ /* HARMONIC SHAPING CONTROL */
+ /****************************/
+ /* Control boosting of harmonic frequencies */
+ HarmBoost_Q16 = silk_SMULWB( silk_SMULWB( SILK_FIX_CONST( 1.0, 17 ) - silk_LSHIFT( psEncCtrl->coding_quality_Q14, 3 ),
+ psEnc->LTPCorr_Q15 ), SILK_FIX_CONST( LOW_RATE_HARMONIC_BOOST, 16 ) );
+
+ /* More harmonic boost for noisy input signals */
+ HarmBoost_Q16 = silk_SMLAWB( HarmBoost_Q16,
+ SILK_FIX_CONST( 1.0, 16 ) - silk_LSHIFT( psEncCtrl->input_quality_Q14, 2 ), SILK_FIX_CONST( LOW_INPUT_QUALITY_HARMONIC_BOOST, 16 ) );
+
+ if( USE_HARM_SHAPING && psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ /* More harmonic noise shaping for high bitrates or noisy input */
+ HarmShapeGain_Q16 = silk_SMLAWB( SILK_FIX_CONST( HARMONIC_SHAPING, 16 ),
+ SILK_FIX_CONST( 1.0, 16 ) - silk_SMULWB( SILK_FIX_CONST( 1.0, 18 ) - silk_LSHIFT( psEncCtrl->coding_quality_Q14, 4 ),
+ psEncCtrl->input_quality_Q14 ), SILK_FIX_CONST( HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING, 16 ) );
+
+ /* Less harmonic noise shaping for less periodic signals */
+ HarmShapeGain_Q16 = silk_SMULWB( silk_LSHIFT( HarmShapeGain_Q16, 1 ),
+ silk_SQRT_APPROX( silk_LSHIFT( psEnc->LTPCorr_Q15, 15 ) ) );
+ } else {
+ HarmShapeGain_Q16 = 0;
+ }
+
+ /*************************/
+ /* Smooth over subframes */
+ /*************************/
+ for( k = 0; k < MAX_NB_SUBFR; k++ ) {
+ psShapeSt->HarmBoost_smth_Q16 =
+ silk_SMLAWB( psShapeSt->HarmBoost_smth_Q16, HarmBoost_Q16 - psShapeSt->HarmBoost_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) );
+ psShapeSt->HarmShapeGain_smth_Q16 =
+ silk_SMLAWB( psShapeSt->HarmShapeGain_smth_Q16, HarmShapeGain_Q16 - psShapeSt->HarmShapeGain_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) );
+ psShapeSt->Tilt_smth_Q16 =
+ silk_SMLAWB( psShapeSt->Tilt_smth_Q16, Tilt_Q16 - psShapeSt->Tilt_smth_Q16, SILK_FIX_CONST( SUBFR_SMTH_COEF, 16 ) );
+
+ psEncCtrl->HarmBoost_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->HarmBoost_smth_Q16, 2 );
+ psEncCtrl->HarmShapeGain_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->HarmShapeGain_smth_Q16, 2 );
+ psEncCtrl->Tilt_Q14[ k ] = ( opus_int )silk_RSHIFT_ROUND( psShapeSt->Tilt_smth_Q16, 2 );
+ }
+ RESTORE_STACK;
+}
diff --git a/drivers/opus/silk/fixed/pitch_analysis_core_FIX.c b/drivers/opus/silk/fixed/pitch_analysis_core_FIX.c
new file mode 100644
index 0000000000..2acd51db6a
--- /dev/null
+++ b/drivers/opus/silk/fixed/pitch_analysis_core_FIX.c
@@ -0,0 +1,744 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+/***********************************************************
+* Pitch analyser function
+********************************************************** */
+#include "opus/silk/SigProc_FIX.h"
+#include "opus/silk/pitch_est_defines.h"
+#include "opus/celt/stack_alloc.h"
+#include "opus/silk/debug.h"
+#include "opus/celt/pitch.h"
+
+#define SCRATCH_SIZE 22
+#define SF_LENGTH_4KHZ ( PE_SUBFR_LENGTH_MS * 4 )
+#define SF_LENGTH_8KHZ ( PE_SUBFR_LENGTH_MS * 8 )
+#define MIN_LAG_4KHZ ( PE_MIN_LAG_MS * 4 )
+#define MIN_LAG_8KHZ ( PE_MIN_LAG_MS * 8 )
+#define MAX_LAG_4KHZ ( PE_MAX_LAG_MS * 4 )
+#define MAX_LAG_8KHZ ( PE_MAX_LAG_MS * 8 - 1 )
+#define CSTRIDE_4KHZ ( MAX_LAG_4KHZ + 1 - MIN_LAG_4KHZ )
+#define CSTRIDE_8KHZ ( MAX_LAG_8KHZ + 3 - ( MIN_LAG_8KHZ - 2 ) )
+#define D_COMP_MIN ( MIN_LAG_8KHZ - 3 )
+#define D_COMP_MAX ( MAX_LAG_8KHZ + 4 )
+#define D_COMP_STRIDE ( D_COMP_MAX - D_COMP_MIN )
+
+typedef opus_int32 silk_pe_stage3_vals[ PE_NB_STAGE3_LAGS ];
+
+/************************************************************/
+/* Internally used functions */
+/************************************************************/
+static void silk_P_Ana_calc_corr_st3(
+ silk_pe_stage3_vals cross_corr_st3[], /* O 3 DIM correlation array */
+ const opus_int16 frame[], /* I vector to correlate */
+ opus_int start_lag, /* I lag offset to search around */
+ opus_int sf_length, /* I length of a 5 ms subframe */
+ opus_int nb_subfr, /* I number of subframes */
+ opus_int complexity, /* I Complexity setting */
+ int arch /* I Run-time architecture */
+);
+
+static void silk_P_Ana_calc_energy_st3(
+ silk_pe_stage3_vals energies_st3[], /* O 3 DIM energy array */
+ const opus_int16 frame[], /* I vector to calc energy in */
+ opus_int start_lag, /* I lag offset to search around */
+ opus_int sf_length, /* I length of one 5 ms subframe */
+ opus_int nb_subfr, /* I number of subframes */
+ opus_int complexity /* I Complexity setting */
+);
+
+/*************************************************************/
+/* FIXED POINT CORE PITCH ANALYSIS FUNCTION */
+/*************************************************************/
+opus_int silk_pitch_analysis_core( /* O Voicing estimate: 0 voiced, 1 unvoiced */
+ const opus_int16 *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */
+ opus_int *pitch_out, /* O 4 pitch lag values */
+ opus_int16 *lagIndex, /* O Lag Index */
+ opus_int8 *contourIndex, /* O Pitch contour Index */
+ opus_int *LTPCorr_Q15, /* I/O Normalized correlation; input: value from previous frame */
+ opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */
+ const opus_int32 search_thres1_Q16, /* I First stage threshold for lag candidates 0 - 1 */
+ const opus_int search_thres2_Q13, /* I Final threshold for lag candidates 0 - 1 */
+ const opus_int Fs_kHz, /* I Sample frequency (kHz) */
+ const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */
+ const opus_int nb_subfr, /* I number of 5 ms subframes */
+ int arch /* I Run-time architecture */
+)
+{
+ VARDECL( opus_int16, frame_8kHz );
+ VARDECL( opus_int16, frame_4kHz );
+ opus_int32 filt_state[ 6 ];
+ const opus_int16 *input_frame_ptr;
+ opus_int i, k, d, j;
+ VARDECL( opus_int16, C );
+ VARDECL( opus_int32, xcorr32 );
+ const opus_int16 *target_ptr, *basis_ptr;
+ opus_int32 cross_corr, normalizer, energy, shift, energy_basis, energy_target;
+ opus_int d_srch[ PE_D_SRCH_LENGTH ], Cmax, length_d_srch, length_d_comp;
+ VARDECL( opus_int16, d_comp );
+ opus_int32 sum, threshold, lag_counter;
+ opus_int CBimax, CBimax_new, CBimax_old, lag, start_lag, end_lag, lag_new;
+ opus_int32 CC[ PE_NB_CBKS_STAGE2_EXT ], CCmax, CCmax_b, CCmax_new_b, CCmax_new;
+ VARDECL( silk_pe_stage3_vals, energies_st3 );
+ VARDECL( silk_pe_stage3_vals, cross_corr_st3 );
+ opus_int frame_length, frame_length_8kHz, frame_length_4kHz;
+ opus_int sf_length;
+ opus_int min_lag;
+ opus_int max_lag;
+ opus_int32 contour_bias_Q15, diff;
+ opus_int nb_cbk_search, cbk_size;
+ opus_int32 delta_lag_log2_sqr_Q7, lag_log2_Q7, prevLag_log2_Q7, prev_lag_bias_Q13;
+ const opus_int8 *Lag_CB_ptr;
+ SAVE_STACK;
+ /* Check for valid sampling frequency */
+ silk_assert( Fs_kHz == 8 || Fs_kHz == 12 || Fs_kHz == 16 );
+
+ /* Check for valid complexity setting */
+ silk_assert( complexity >= SILK_PE_MIN_COMPLEX );
+ silk_assert( complexity <= SILK_PE_MAX_COMPLEX );
+
+ silk_assert( search_thres1_Q16 >= 0 && search_thres1_Q16 <= (1<<16) );
+ silk_assert( search_thres2_Q13 >= 0 && search_thres2_Q13 <= (1<<13) );
+
+ /* Set up frame lengths max / min lag for the sampling frequency */
+ frame_length = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * Fs_kHz;
+ frame_length_4kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 4;
+ frame_length_8kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 8;
+ sf_length = PE_SUBFR_LENGTH_MS * Fs_kHz;
+ min_lag = PE_MIN_LAG_MS * Fs_kHz;
+ max_lag = PE_MAX_LAG_MS * Fs_kHz - 1;
+
+ /* Resample from input sampled at Fs_kHz to 8 kHz */
+ ALLOC( frame_8kHz, frame_length_8kHz, opus_int16 );
+ if( Fs_kHz == 16 ) {
+ silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) );
+ silk_resampler_down2( filt_state, frame_8kHz, frame, frame_length );
+ } else if( Fs_kHz == 12 ) {
+ silk_memset( filt_state, 0, 6 * sizeof( opus_int32 ) );
+ silk_resampler_down2_3( filt_state, frame_8kHz, frame, frame_length );
+ } else {
+ silk_assert( Fs_kHz == 8 );
+ silk_memcpy( frame_8kHz, frame, frame_length_8kHz * sizeof(opus_int16) );
+ }
+
+ /* Decimate again to 4 kHz */
+ silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) );/* Set state to zero */
+ ALLOC( frame_4kHz, frame_length_4kHz, opus_int16 );
+ silk_resampler_down2( filt_state, frame_4kHz, frame_8kHz, frame_length_8kHz );
+
+ /* Low-pass filter */
+ for( i = frame_length_4kHz - 1; i > 0; i-- ) {
+ frame_4kHz[ i ] = silk_ADD_SAT16( frame_4kHz[ i ], frame_4kHz[ i - 1 ] );
+ }
+
+ /*******************************************************************************
+ ** Scale 4 kHz signal down to prevent correlations measures from overflowing
+ ** find scaling as max scaling for each 8kHz(?) subframe
+ *******************************************************************************/
+
+ /* Inner product is calculated with different lengths, so scale for the worst case */
+ silk_sum_sqr_shift( &energy, &shift, frame_4kHz, frame_length_4kHz );
+ if( shift > 0 ) {
+ shift = silk_RSHIFT( shift, 1 );
+ for( i = 0; i < frame_length_4kHz; i++ ) {
+ frame_4kHz[ i ] = silk_RSHIFT( frame_4kHz[ i ], shift );
+ }
+ }
+
+ /******************************************************************************
+ * FIRST STAGE, operating in 4 khz
+ ******************************************************************************/
+ ALLOC( C, nb_subfr * CSTRIDE_8KHZ, opus_int16 );
+ ALLOC( xcorr32, MAX_LAG_4KHZ-MIN_LAG_4KHZ+1, opus_int32 );
+ silk_memset( C, 0, (nb_subfr >> 1) * CSTRIDE_4KHZ * sizeof( opus_int16 ) );
+ target_ptr = &frame_4kHz[ silk_LSHIFT( SF_LENGTH_4KHZ, 2 ) ];
+ for( k = 0; k < nb_subfr >> 1; k++ ) {
+ /* Check that we are within range of the array */
+ silk_assert( target_ptr >= frame_4kHz );
+ silk_assert( target_ptr + SF_LENGTH_8KHZ <= frame_4kHz + frame_length_4kHz );
+
+ basis_ptr = target_ptr - MIN_LAG_4KHZ;
+
+ /* Check that we are within range of the array */
+ silk_assert( basis_ptr >= frame_4kHz );
+ silk_assert( basis_ptr + SF_LENGTH_8KHZ <= frame_4kHz + frame_length_4kHz );
+
+ celt_pitch_xcorr( target_ptr, target_ptr - MAX_LAG_4KHZ, xcorr32, SF_LENGTH_8KHZ, MAX_LAG_4KHZ - MIN_LAG_4KHZ + 1, arch );
+
+ /* Calculate first vector products before loop */
+ cross_corr = xcorr32[ MAX_LAG_4KHZ - MIN_LAG_4KHZ ];
+ normalizer = silk_inner_prod_aligned( target_ptr, target_ptr, SF_LENGTH_8KHZ );
+ normalizer = silk_ADD32( normalizer, silk_inner_prod_aligned( basis_ptr, basis_ptr, SF_LENGTH_8KHZ ) );
+ normalizer = silk_ADD32( normalizer, silk_SMULBB( SF_LENGTH_8KHZ, 4000 ) );
+
+ matrix_ptr( C, k, 0, CSTRIDE_4KHZ ) =
+ (opus_int16)silk_DIV32_varQ( cross_corr, normalizer, 13 + 1 ); /* Q13 */
+
+ /* From now on normalizer is computed recursively */
+ for( d = MIN_LAG_4KHZ + 1; d <= MAX_LAG_4KHZ; d++ ) {
+ basis_ptr--;
+
+ /* Check that we are within range of the array */
+ silk_assert( basis_ptr >= frame_4kHz );
+ silk_assert( basis_ptr + SF_LENGTH_8KHZ <= frame_4kHz + frame_length_4kHz );
+
+ cross_corr = xcorr32[ MAX_LAG_4KHZ - d ];
+
+ /* Add contribution of new sample and remove contribution from oldest sample */
+ normalizer = silk_ADD32( normalizer,
+ silk_SMULBB( basis_ptr[ 0 ], basis_ptr[ 0 ] ) -
+ silk_SMULBB( basis_ptr[ SF_LENGTH_8KHZ ], basis_ptr[ SF_LENGTH_8KHZ ] ) );
+
+ matrix_ptr( C, k, d - MIN_LAG_4KHZ, CSTRIDE_4KHZ) =
+ (opus_int16)silk_DIV32_varQ( cross_corr, normalizer, 13 + 1 ); /* Q13 */
+ }
+ /* Update target pointer */
+ target_ptr += SF_LENGTH_8KHZ;
+ }
+
+ /* Combine two subframes into single correlation measure and apply short-lag bias */
+ if( nb_subfr == PE_MAX_NB_SUBFR ) {
+ for( i = MAX_LAG_4KHZ; i >= MIN_LAG_4KHZ; i-- ) {
+ sum = (opus_int32)matrix_ptr( C, 0, i - MIN_LAG_4KHZ, CSTRIDE_4KHZ )
+ + (opus_int32)matrix_ptr( C, 1, i - MIN_LAG_4KHZ, CSTRIDE_4KHZ ); /* Q14 */
+ sum = silk_SMLAWB( sum, sum, silk_LSHIFT( -i, 4 ) ); /* Q14 */
+ C[ i - MIN_LAG_4KHZ ] = (opus_int16)sum; /* Q14 */
+ }
+ } else {
+ /* Only short-lag bias */
+ for( i = MAX_LAG_4KHZ; i >= MIN_LAG_4KHZ; i-- ) {
+ sum = silk_LSHIFT( (opus_int32)C[ i - MIN_LAG_4KHZ ], 1 ); /* Q14 */
+ sum = silk_SMLAWB( sum, sum, silk_LSHIFT( -i, 4 ) ); /* Q14 */
+ C[ i - MIN_LAG_4KHZ ] = (opus_int16)sum; /* Q14 */
+ }
+ }
+
+ /* Sort */
+ length_d_srch = silk_ADD_LSHIFT32( 4, complexity, 1 );
+ silk_assert( 3 * length_d_srch <= PE_D_SRCH_LENGTH );
+ silk_insertion_sort_decreasing_int16( C, d_srch, CSTRIDE_4KHZ,
+ length_d_srch );
+
+ /* Escape if correlation is very low already here */
+ Cmax = (opus_int)C[ 0 ]; /* Q14 */
+ if( Cmax < SILK_FIX_CONST( 0.2, 14 ) ) {
+ silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) );
+ *LTPCorr_Q15 = 0;
+ *lagIndex = 0;
+ *contourIndex = 0;
+ RESTORE_STACK;
+ return 1;
+ }
+
+ threshold = silk_SMULWB( search_thres1_Q16, Cmax );
+ for( i = 0; i < length_d_srch; i++ ) {
+ /* Convert to 8 kHz indices for the sorted correlation that exceeds the threshold */
+ if( C[ i ] > threshold ) {
+ d_srch[ i ] = silk_LSHIFT( d_srch[ i ] + MIN_LAG_4KHZ, 1 );
+ } else {
+ length_d_srch = i;
+ break;
+ }
+ }
+ silk_assert( length_d_srch > 0 );
+
+ ALLOC( d_comp, D_COMP_STRIDE, opus_int16 );
+ for( i = D_COMP_MIN; i < D_COMP_MAX; i++ ) {
+ d_comp[ i - D_COMP_MIN ] = 0;
+ }
+ for( i = 0; i < length_d_srch; i++ ) {
+ d_comp[ d_srch[ i ] - D_COMP_MIN ] = 1;
+ }
+
+ /* Convolution */
+ for( i = D_COMP_MAX - 1; i >= MIN_LAG_8KHZ; i-- ) {
+ d_comp[ i - D_COMP_MIN ] +=
+ d_comp[ i - 1 - D_COMP_MIN ] + d_comp[ i - 2 - D_COMP_MIN ];
+ }
+
+ length_d_srch = 0;
+ for( i = MIN_LAG_8KHZ; i < MAX_LAG_8KHZ + 1; i++ ) {
+ if( d_comp[ i + 1 - D_COMP_MIN ] > 0 ) {
+ d_srch[ length_d_srch ] = i;
+ length_d_srch++;
+ }
+ }
+
+ /* Convolution */
+ for( i = D_COMP_MAX - 1; i >= MIN_LAG_8KHZ; i-- ) {
+ d_comp[ i - D_COMP_MIN ] += d_comp[ i - 1 - D_COMP_MIN ]
+ + d_comp[ i - 2 - D_COMP_MIN ] + d_comp[ i - 3 - D_COMP_MIN ];
+ }
+
+ length_d_comp = 0;
+ for( i = MIN_LAG_8KHZ; i < D_COMP_MAX; i++ ) {
+ if( d_comp[ i - D_COMP_MIN ] > 0 ) {
+ d_comp[ length_d_comp ] = i - 2;
+ length_d_comp++;
+ }
+ }
+
+ /**********************************************************************************
+ ** SECOND STAGE, operating at 8 kHz, on lag sections with high correlation
+ *************************************************************************************/
+
+ /******************************************************************************
+ ** Scale signal down to avoid correlations measures from overflowing
+ *******************************************************************************/
+ /* find scaling as max scaling for each subframe */
+ silk_sum_sqr_shift( &energy, &shift, frame_8kHz, frame_length_8kHz );
+ if( shift > 0 ) {
+ shift = silk_RSHIFT( shift, 1 );
+ for( i = 0; i < frame_length_8kHz; i++ ) {
+ frame_8kHz[ i ] = silk_RSHIFT( frame_8kHz[ i ], shift );
+ }
+ }
+
+ /*********************************************************************************
+ * Find energy of each subframe projected onto its history, for a range of delays
+ *********************************************************************************/
+ silk_memset( C, 0, nb_subfr * CSTRIDE_8KHZ * sizeof( opus_int16 ) );
+
+ target_ptr = &frame_8kHz[ PE_LTP_MEM_LENGTH_MS * 8 ];
+ for( k = 0; k < nb_subfr; k++ ) {
+
+ /* Check that we are within range of the array */
+ silk_assert( target_ptr >= frame_8kHz );
+ silk_assert( target_ptr + SF_LENGTH_8KHZ <= frame_8kHz + frame_length_8kHz );
+
+ energy_target = silk_ADD32( silk_inner_prod_aligned( target_ptr, target_ptr, SF_LENGTH_8KHZ ), 1 );
+ for( j = 0; j < length_d_comp; j++ ) {
+ d = d_comp[ j ];
+ basis_ptr = target_ptr - d;
+
+ /* Check that we are within range of the array */
+ silk_assert( basis_ptr >= frame_8kHz );
+ silk_assert( basis_ptr + SF_LENGTH_8KHZ <= frame_8kHz + frame_length_8kHz );
+
+ cross_corr = silk_inner_prod_aligned( target_ptr, basis_ptr, SF_LENGTH_8KHZ );
+ if( cross_corr > 0 ) {
+ energy_basis = silk_inner_prod_aligned( basis_ptr, basis_ptr, SF_LENGTH_8KHZ );
+ matrix_ptr( C, k, d - ( MIN_LAG_8KHZ - 2 ), CSTRIDE_8KHZ ) =
+ (opus_int16)silk_DIV32_varQ( cross_corr,
+ silk_ADD32( energy_target,
+ energy_basis ),
+ 13 + 1 ); /* Q13 */
+ } else {
+ matrix_ptr( C, k, d - ( MIN_LAG_8KHZ - 2 ), CSTRIDE_8KHZ ) = 0;
+ }
+ }
+ target_ptr += SF_LENGTH_8KHZ;
+ }
+
+ /* search over lag range and lags codebook */
+ /* scale factor for lag codebook, as a function of center lag */
+
+ CCmax = silk_int32_MIN;
+ CCmax_b = silk_int32_MIN;
+
+ CBimax = 0; /* To avoid returning undefined lag values */
+ lag = -1; /* To check if lag with strong enough correlation has been found */
+
+ if( prevLag > 0 ) {
+ if( Fs_kHz == 12 ) {
+ prevLag = silk_DIV32_16( silk_LSHIFT( prevLag, 1 ), 3 );
+ } else if( Fs_kHz == 16 ) {
+ prevLag = silk_RSHIFT( prevLag, 1 );
+ }
+ prevLag_log2_Q7 = silk_lin2log( (opus_int32)prevLag );
+ } else {
+ prevLag_log2_Q7 = 0;
+ }
+ silk_assert( search_thres2_Q13 == silk_SAT16( search_thres2_Q13 ) );
+ /* Set up stage 2 codebook based on number of subframes */
+ if( nb_subfr == PE_MAX_NB_SUBFR ) {
+ cbk_size = PE_NB_CBKS_STAGE2_EXT;
+ Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ];
+ if( Fs_kHz == 8 && complexity > SILK_PE_MIN_COMPLEX ) {
+ /* If input is 8 khz use a larger codebook here because it is last stage */
+ nb_cbk_search = PE_NB_CBKS_STAGE2_EXT;
+ } else {
+ nb_cbk_search = PE_NB_CBKS_STAGE2;
+ }
+ } else {
+ cbk_size = PE_NB_CBKS_STAGE2_10MS;
+ Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ];
+ nb_cbk_search = PE_NB_CBKS_STAGE2_10MS;
+ }
+
+ for( k = 0; k < length_d_srch; k++ ) {
+ d = d_srch[ k ];
+ for( j = 0; j < nb_cbk_search; j++ ) {
+ CC[ j ] = 0;
+ for( i = 0; i < nb_subfr; i++ ) {
+ opus_int d_subfr;
+ /* Try all codebooks */
+ d_subfr = d + matrix_ptr( Lag_CB_ptr, i, j, cbk_size );
+ CC[ j ] = CC[ j ]
+ + (opus_int32)matrix_ptr( C, i,
+ d_subfr - ( MIN_LAG_8KHZ - 2 ),
+ CSTRIDE_8KHZ );
+ }
+ }
+ /* Find best codebook */
+ CCmax_new = silk_int32_MIN;
+ CBimax_new = 0;
+ for( i = 0; i < nb_cbk_search; i++ ) {
+ if( CC[ i ] > CCmax_new ) {
+ CCmax_new = CC[ i ];
+ CBimax_new = i;
+ }
+ }
+
+ /* Bias towards shorter lags */
+ lag_log2_Q7 = silk_lin2log( d ); /* Q7 */
+ silk_assert( lag_log2_Q7 == silk_SAT16( lag_log2_Q7 ) );
+ silk_assert( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 13 ) == silk_SAT16( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 13 ) ) );
+ CCmax_new_b = CCmax_new - silk_RSHIFT( silk_SMULBB( nb_subfr * SILK_FIX_CONST( PE_SHORTLAG_BIAS, 13 ), lag_log2_Q7 ), 7 ); /* Q13 */
+
+ /* Bias towards previous lag */
+ silk_assert( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 13 ) == silk_SAT16( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 13 ) ) );
+ if( prevLag > 0 ) {
+ delta_lag_log2_sqr_Q7 = lag_log2_Q7 - prevLag_log2_Q7;
+ silk_assert( delta_lag_log2_sqr_Q7 == silk_SAT16( delta_lag_log2_sqr_Q7 ) );
+ delta_lag_log2_sqr_Q7 = silk_RSHIFT( silk_SMULBB( delta_lag_log2_sqr_Q7, delta_lag_log2_sqr_Q7 ), 7 );
+ prev_lag_bias_Q13 = silk_RSHIFT( silk_SMULBB( nb_subfr * SILK_FIX_CONST( PE_PREVLAG_BIAS, 13 ), *LTPCorr_Q15 ), 15 ); /* Q13 */
+ prev_lag_bias_Q13 = silk_DIV32( silk_MUL( prev_lag_bias_Q13, delta_lag_log2_sqr_Q7 ), delta_lag_log2_sqr_Q7 + SILK_FIX_CONST( 0.5, 7 ) );
+ CCmax_new_b -= prev_lag_bias_Q13; /* Q13 */
+ }
+
+ if( CCmax_new_b > CCmax_b && /* Find maximum biased correlation */
+ CCmax_new > silk_SMULBB( nb_subfr, search_thres2_Q13 ) && /* Correlation needs to be high enough to be voiced */
+ silk_CB_lags_stage2[ 0 ][ CBimax_new ] <= MIN_LAG_8KHZ /* Lag must be in range */
+ ) {
+ CCmax_b = CCmax_new_b;
+ CCmax = CCmax_new;
+ lag = d;
+ CBimax = CBimax_new;
+ }
+ }
+
+ if( lag == -1 ) {
+ /* No suitable candidate found */
+ silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) );
+ *LTPCorr_Q15 = 0;
+ *lagIndex = 0;
+ *contourIndex = 0;
+ RESTORE_STACK;
+ return 1;
+ }
+
+ /* Output normalized correlation */
+ *LTPCorr_Q15 = (opus_int)silk_LSHIFT( silk_DIV32_16( CCmax, nb_subfr ), 2 );
+ silk_assert( *LTPCorr_Q15 >= 0 );
+
+ if( Fs_kHz > 8 ) {
+ VARDECL( opus_int16, scratch_mem );
+ /***************************************************************************/
+ /* Scale input signal down to avoid correlations measures from overflowing */
+ /***************************************************************************/
+ /* find scaling as max scaling for each subframe */
+ silk_sum_sqr_shift( &energy, &shift, frame, frame_length );
+ ALLOC( scratch_mem, shift > 0 ? frame_length : ALLOC_NONE, opus_int16 );
+ if( shift > 0 ) {
+ /* Move signal to scratch mem because the input signal should be unchanged */
+ shift = silk_RSHIFT( shift, 1 );
+ for( i = 0; i < frame_length; i++ ) {
+ scratch_mem[ i ] = silk_RSHIFT( frame[ i ], shift );
+ }
+ input_frame_ptr = scratch_mem;
+ } else {
+ input_frame_ptr = frame;
+ }
+
+ /* Search in original signal */
+
+ CBimax_old = CBimax;
+ /* Compensate for decimation */
+ silk_assert( lag == silk_SAT16( lag ) );
+ if( Fs_kHz == 12 ) {
+ lag = silk_RSHIFT( silk_SMULBB( lag, 3 ), 1 );
+ } else if( Fs_kHz == 16 ) {
+ lag = silk_LSHIFT( lag, 1 );
+ } else {
+ lag = silk_SMULBB( lag, 3 );
+ }
+
+ lag = silk_LIMIT_int( lag, min_lag, max_lag );
+ start_lag = silk_max_int( lag - 2, min_lag );
+ end_lag = silk_min_int( lag + 2, max_lag );
+ lag_new = lag; /* to avoid undefined lag */
+ CBimax = 0; /* to avoid undefined lag */
+
+ CCmax = silk_int32_MIN;
+ /* pitch lags according to second stage */
+ for( k = 0; k < nb_subfr; k++ ) {
+ pitch_out[ k ] = lag + 2 * silk_CB_lags_stage2[ k ][ CBimax_old ];
+ }
+
+ /* Set up codebook parameters according to complexity setting and frame length */
+ if( nb_subfr == PE_MAX_NB_SUBFR ) {
+ nb_cbk_search = (opus_int)silk_nb_cbk_searchs_stage3[ complexity ];
+ cbk_size = PE_NB_CBKS_STAGE3_MAX;
+ Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ];
+ } else {
+ nb_cbk_search = PE_NB_CBKS_STAGE3_10MS;
+ cbk_size = PE_NB_CBKS_STAGE3_10MS;
+ Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
+ }
+
+ /* Calculate the correlations and energies needed in stage 3 */
+ ALLOC( energies_st3, nb_subfr * nb_cbk_search, silk_pe_stage3_vals );
+ ALLOC( cross_corr_st3, nb_subfr * nb_cbk_search, silk_pe_stage3_vals );
+ silk_P_Ana_calc_corr_st3( cross_corr_st3, input_frame_ptr, start_lag, sf_length, nb_subfr, complexity, arch );
+ silk_P_Ana_calc_energy_st3( energies_st3, input_frame_ptr, start_lag, sf_length, nb_subfr, complexity );
+
+ lag_counter = 0;
+ silk_assert( lag == silk_SAT16( lag ) );
+ contour_bias_Q15 = silk_DIV32_16( SILK_FIX_CONST( PE_FLATCONTOUR_BIAS, 15 ), lag );
+
+ target_ptr = &input_frame_ptr[ PE_LTP_MEM_LENGTH_MS * Fs_kHz ];
+ energy_target = silk_ADD32( silk_inner_prod_aligned( target_ptr, target_ptr, nb_subfr * sf_length ), 1 );
+ for( d = start_lag; d <= end_lag; d++ ) {
+ for( j = 0; j < nb_cbk_search; j++ ) {
+ cross_corr = 0;
+ energy = energy_target;
+ for( k = 0; k < nb_subfr; k++ ) {
+ cross_corr = silk_ADD32( cross_corr,
+ matrix_ptr( cross_corr_st3, k, j,
+ nb_cbk_search )[ lag_counter ] );
+ energy = silk_ADD32( energy,
+ matrix_ptr( energies_st3, k, j,
+ nb_cbk_search )[ lag_counter ] );
+ silk_assert( energy >= 0 );
+ }
+ if( cross_corr > 0 ) {
+ CCmax_new = silk_DIV32_varQ( cross_corr, energy, 13 + 1 ); /* Q13 */
+ /* Reduce depending on flatness of contour */
+ diff = silk_int16_MAX - silk_MUL( contour_bias_Q15, j ); /* Q15 */
+ silk_assert( diff == silk_SAT16( diff ) );
+ CCmax_new = silk_SMULWB( CCmax_new, diff ); /* Q14 */
+ } else {
+ CCmax_new = 0;
+ }
+
+ if( CCmax_new > CCmax && ( d + silk_CB_lags_stage3[ 0 ][ j ] ) <= max_lag ) {
+ CCmax = CCmax_new;
+ lag_new = d;
+ CBimax = j;
+ }
+ }
+ lag_counter++;
+ }
+
+ for( k = 0; k < nb_subfr; k++ ) {
+ pitch_out[ k ] = lag_new + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size );
+ pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag, PE_MAX_LAG_MS * Fs_kHz );
+ }
+ *lagIndex = (opus_int16)( lag_new - min_lag);
+ *contourIndex = (opus_int8)CBimax;
+ } else { /* Fs_kHz == 8 */
+ /* Save Lags */
+ for( k = 0; k < nb_subfr; k++ ) {
+ pitch_out[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size );
+ pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], MIN_LAG_8KHZ, PE_MAX_LAG_MS * 8 );
+ }
+ *lagIndex = (opus_int16)( lag - MIN_LAG_8KHZ );
+ *contourIndex = (opus_int8)CBimax;
+ }
+ silk_assert( *lagIndex >= 0 );
+ /* return as voiced */
+ RESTORE_STACK;
+ return 0;
+}
+
+/***********************************************************************
+ * Calculates the correlations used in stage 3 search. In order to cover
+ * the whole lag codebook for all the searched offset lags (lag +- 2),
+ * the following correlations are needed in each sub frame:
+ *
+ * sf1: lag range [-8,...,7] total 16 correlations
+ * sf2: lag range [-4,...,4] total 9 correlations
+ * sf3: lag range [-3,....4] total 8 correltions
+ * sf4: lag range [-6,....8] total 15 correlations
+ *
+ * In total 48 correlations. The direct implementation computed in worst
+ * case 4*12*5 = 240 correlations, but more likely around 120.
+ ***********************************************************************/
+static void silk_P_Ana_calc_corr_st3(
+ silk_pe_stage3_vals cross_corr_st3[], /* O 3 DIM correlation array */
+ const opus_int16 frame[], /* I vector to correlate */
+ opus_int start_lag, /* I lag offset to search around */
+ opus_int sf_length, /* I length of a 5 ms subframe */
+ opus_int nb_subfr, /* I number of subframes */
+ opus_int complexity, /* I Complexity setting */
+ int arch /* I Run-time architecture */
+)
+{
+ const opus_int16 *target_ptr;
+ opus_int i, j, k, lag_counter, lag_low, lag_high;
+ opus_int nb_cbk_search, delta, idx, cbk_size;
+ VARDECL( opus_int32, scratch_mem );
+ VARDECL( opus_int32, xcorr32 );
+ const opus_int8 *Lag_range_ptr, *Lag_CB_ptr;
+ SAVE_STACK;
+
+ silk_assert( complexity >= SILK_PE_MIN_COMPLEX );
+ silk_assert( complexity <= SILK_PE_MAX_COMPLEX );
+
+ if( nb_subfr == PE_MAX_NB_SUBFR ) {
+ Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ];
+ Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ];
+ nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ];
+ cbk_size = PE_NB_CBKS_STAGE3_MAX;
+ } else {
+ silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1);
+ Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ];
+ Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
+ nb_cbk_search = PE_NB_CBKS_STAGE3_10MS;
+ cbk_size = PE_NB_CBKS_STAGE3_10MS;
+ }
+ ALLOC( scratch_mem, SCRATCH_SIZE, opus_int32 );
+ ALLOC( xcorr32, SCRATCH_SIZE, opus_int32 );
+
+ target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; /* Pointer to middle of frame */
+ for( k = 0; k < nb_subfr; k++ ) {
+ lag_counter = 0;
+
+ /* Calculate the correlations for each subframe */
+ lag_low = matrix_ptr( Lag_range_ptr, k, 0, 2 );
+ lag_high = matrix_ptr( Lag_range_ptr, k, 1, 2 );
+ silk_assert(lag_high-lag_low+1 <= SCRATCH_SIZE);
+ celt_pitch_xcorr( target_ptr, target_ptr - start_lag - lag_high, xcorr32, sf_length, lag_high - lag_low + 1, arch );
+ for( j = lag_low; j <= lag_high; j++ ) {
+ silk_assert( lag_counter < SCRATCH_SIZE );
+ scratch_mem[ lag_counter ] = xcorr32[ lag_high - j ];
+ lag_counter++;
+ }
+
+ delta = matrix_ptr( Lag_range_ptr, k, 0, 2 );
+ for( i = 0; i < nb_cbk_search; i++ ) {
+ /* Fill out the 3 dim array that stores the correlations for */
+ /* each code_book vector for each start lag */
+ idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta;
+ for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) {
+ silk_assert( idx + j < SCRATCH_SIZE );
+ silk_assert( idx + j < lag_counter );
+ matrix_ptr( cross_corr_st3, k, i, nb_cbk_search )[ j ] =
+ scratch_mem[ idx + j ];
+ }
+ }
+ target_ptr += sf_length;
+ }
+ RESTORE_STACK;
+}
+
+/********************************************************************/
+/* Calculate the energies for first two subframes. The energies are */
+/* calculated recursively. */
+/********************************************************************/
+static void silk_P_Ana_calc_energy_st3(
+ silk_pe_stage3_vals energies_st3[], /* O 3 DIM energy array */
+ const opus_int16 frame[], /* I vector to calc energy in */
+ opus_int start_lag, /* I lag offset to search around */
+ opus_int sf_length, /* I length of one 5 ms subframe */
+ opus_int nb_subfr, /* I number of subframes */
+ opus_int complexity /* I Complexity setting */
+)
+{
+ const opus_int16 *target_ptr, *basis_ptr;
+ opus_int32 energy;
+ opus_int k, i, j, lag_counter;
+ opus_int nb_cbk_search, delta, idx, cbk_size, lag_diff;
+ VARDECL( opus_int32, scratch_mem );
+ const opus_int8 *Lag_range_ptr, *Lag_CB_ptr;
+ SAVE_STACK;
+
+ silk_assert( complexity >= SILK_PE_MIN_COMPLEX );
+ silk_assert( complexity <= SILK_PE_MAX_COMPLEX );
+
+ if( nb_subfr == PE_MAX_NB_SUBFR ) {
+ Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ];
+ Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ];
+ nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ];
+ cbk_size = PE_NB_CBKS_STAGE3_MAX;
+ } else {
+ silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1);
+ Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ];
+ Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
+ nb_cbk_search = PE_NB_CBKS_STAGE3_10MS;
+ cbk_size = PE_NB_CBKS_STAGE3_10MS;
+ }
+ ALLOC( scratch_mem, SCRATCH_SIZE, opus_int32 );
+
+ target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ];
+ for( k = 0; k < nb_subfr; k++ ) {
+ lag_counter = 0;
+
+ /* Calculate the energy for first lag */
+ basis_ptr = target_ptr - ( start_lag + matrix_ptr( Lag_range_ptr, k, 0, 2 ) );
+ energy = silk_inner_prod_aligned( basis_ptr, basis_ptr, sf_length );
+ silk_assert( energy >= 0 );
+ scratch_mem[ lag_counter ] = energy;
+ lag_counter++;
+
+ lag_diff = ( matrix_ptr( Lag_range_ptr, k, 1, 2 ) - matrix_ptr( Lag_range_ptr, k, 0, 2 ) + 1 );
+ for( i = 1; i < lag_diff; i++ ) {
+ /* remove part outside new window */
+ energy -= silk_SMULBB( basis_ptr[ sf_length - i ], basis_ptr[ sf_length - i ] );
+ silk_assert( energy >= 0 );
+
+ /* add part that comes into window */
+ energy = silk_ADD_SAT32( energy, silk_SMULBB( basis_ptr[ -i ], basis_ptr[ -i ] ) );
+ silk_assert( energy >= 0 );
+ silk_assert( lag_counter < SCRATCH_SIZE );
+ scratch_mem[ lag_counter ] = energy;
+ lag_counter++;
+ }
+
+ delta = matrix_ptr( Lag_range_ptr, k, 0, 2 );
+ for( i = 0; i < nb_cbk_search; i++ ) {
+ /* Fill out the 3 dim array that stores the correlations for */
+ /* each code_book vector for each start lag */
+ idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta;
+ for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) {
+ silk_assert( idx + j < SCRATCH_SIZE );
+ silk_assert( idx + j < lag_counter );
+ matrix_ptr( energies_st3, k, i, nb_cbk_search )[ j ] =
+ scratch_mem[ idx + j ];
+ silk_assert(
+ matrix_ptr( energies_st3, k, i, nb_cbk_search )[ j ] >= 0 );
+ }
+ }
+ target_ptr += sf_length;
+ }
+ RESTORE_STACK;
+}
diff --git a/drivers/opus/silk/fixed/prefilter_FIX.c b/drivers/opus/silk/fixed/prefilter_FIX.c
new file mode 100644
index 0000000000..195df3da75
--- /dev/null
+++ b/drivers/opus/silk/fixed/prefilter_FIX.c
@@ -0,0 +1,209 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/fixed/main_FIX.h"
+#include "opus/celt/stack_alloc.h"
+#include "opus/silk/tuning_parameters.h"
+
+/* Prefilter for finding Quantizer input signal */
+static OPUS_INLINE void silk_prefilt_FIX(
+ silk_prefilter_state_FIX *P, /* I/O state */
+ opus_int32 st_res_Q12[], /* I short term residual signal */
+ opus_int32 xw_Q3[], /* O prefiltered signal */
+ opus_int32 HarmShapeFIRPacked_Q12, /* I Harmonic shaping coeficients */
+ opus_int Tilt_Q14, /* I Tilt shaping coeficient */
+ opus_int32 LF_shp_Q14, /* I Low-frequancy shaping coeficients */
+ opus_int lag, /* I Lag for harmonic shaping */
+ opus_int length /* I Length of signals */
+);
+
+void silk_warped_LPC_analysis_filter_FIX(
+ opus_int32 state[], /* I/O State [order + 1] */
+ opus_int32 res_Q2[], /* O Residual signal [length] */
+ const opus_int16 coef_Q13[], /* I Coefficients [order] */
+ const opus_int16 input[], /* I Input signal [length] */
+ const opus_int16 lambda_Q16, /* I Warping factor */
+ const opus_int length, /* I Length of input signal */
+ const opus_int order /* I Filter order (even) */
+)
+{
+ opus_int n, i;
+ opus_int32 acc_Q11, tmp1, tmp2;
+
+ /* Order must be even */
+ silk_assert( ( order & 1 ) == 0 );
+
+ for( n = 0; n < length; n++ ) {
+ /* Output of lowpass section */
+ tmp2 = silk_SMLAWB( state[ 0 ], state[ 1 ], lambda_Q16 );
+ state[ 0 ] = silk_LSHIFT( input[ n ], 14 );
+ /* Output of allpass section */
+ tmp1 = silk_SMLAWB( state[ 1 ], state[ 2 ] - tmp2, lambda_Q16 );
+ state[ 1 ] = tmp2;
+ acc_Q11 = silk_RSHIFT( order, 1 );
+ acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ 0 ] );
+ /* Loop over allpass sections */
+ for( i = 2; i < order; i += 2 ) {
+ /* Output of allpass section */
+ tmp2 = silk_SMLAWB( state[ i ], state[ i + 1 ] - tmp1, lambda_Q16 );
+ state[ i ] = tmp1;
+ acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ i - 1 ] );
+ /* Output of allpass section */
+ tmp1 = silk_SMLAWB( state[ i + 1 ], state[ i + 2 ] - tmp2, lambda_Q16 );
+ state[ i + 1 ] = tmp2;
+ acc_Q11 = silk_SMLAWB( acc_Q11, tmp2, coef_Q13[ i ] );
+ }
+ state[ order ] = tmp1;
+ acc_Q11 = silk_SMLAWB( acc_Q11, tmp1, coef_Q13[ order - 1 ] );
+ res_Q2[ n ] = silk_LSHIFT( (opus_int32)input[ n ], 2 ) - silk_RSHIFT_ROUND( acc_Q11, 9 );
+ }
+}
+
+void silk_prefilter_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Encoder state */
+ const silk_encoder_control_FIX *psEncCtrl, /* I Encoder control */
+ opus_int32 xw_Q3[], /* O Weighted signal */
+ const opus_int16 x[] /* I Speech signal */
+)
+{
+ silk_prefilter_state_FIX *P = &psEnc->sPrefilt;
+ opus_int j, k, lag;
+ opus_int32 tmp_32;
+ const opus_int16 *AR1_shp_Q13;
+ const opus_int16 *px;
+ opus_int32 *pxw_Q3;
+ opus_int HarmShapeGain_Q12, Tilt_Q14;
+ opus_int32 HarmShapeFIRPacked_Q12, LF_shp_Q14;
+ VARDECL( opus_int32, x_filt_Q12 );
+ VARDECL( opus_int32, st_res_Q2 );
+ opus_int16 B_Q10[ 2 ];
+ SAVE_STACK;
+
+ /* Set up pointers */
+ px = x;
+ pxw_Q3 = xw_Q3;
+ lag = P->lagPrev;
+ ALLOC( x_filt_Q12, psEnc->sCmn.subfr_length, opus_int32 );
+ ALLOC( st_res_Q2, psEnc->sCmn.subfr_length, opus_int32 );
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ /* Update Variables that change per sub frame */
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ lag = psEncCtrl->pitchL[ k ];
+ }
+
+ /* Noise shape parameters */
+ HarmShapeGain_Q12 = silk_SMULWB( (opus_int32)psEncCtrl->HarmShapeGain_Q14[ k ], 16384 - psEncCtrl->HarmBoost_Q14[ k ] );
+ silk_assert( HarmShapeGain_Q12 >= 0 );
+ HarmShapeFIRPacked_Q12 = silk_RSHIFT( HarmShapeGain_Q12, 2 );
+ HarmShapeFIRPacked_Q12 |= silk_LSHIFT( (opus_int32)silk_RSHIFT( HarmShapeGain_Q12, 1 ), 16 );
+ Tilt_Q14 = psEncCtrl->Tilt_Q14[ k ];
+ LF_shp_Q14 = psEncCtrl->LF_shp_Q14[ k ];
+ AR1_shp_Q13 = &psEncCtrl->AR1_Q13[ k * MAX_SHAPE_LPC_ORDER ];
+
+ /* Short term FIR filtering*/
+ silk_warped_LPC_analysis_filter_FIX( P->sAR_shp, st_res_Q2, AR1_shp_Q13, px,
+ psEnc->sCmn.warping_Q16, psEnc->sCmn.subfr_length, psEnc->sCmn.shapingLPCOrder );
+
+ /* Reduce (mainly) low frequencies during harmonic emphasis */
+ B_Q10[ 0 ] = silk_RSHIFT_ROUND( psEncCtrl->GainsPre_Q14[ k ], 4 );
+ tmp_32 = silk_SMLABB( SILK_FIX_CONST( INPUT_TILT, 26 ), psEncCtrl->HarmBoost_Q14[ k ], HarmShapeGain_Q12 ); /* Q26 */
+ tmp_32 = silk_SMLABB( tmp_32, psEncCtrl->coding_quality_Q14, SILK_FIX_CONST( HIGH_RATE_INPUT_TILT, 12 ) ); /* Q26 */
+ tmp_32 = silk_SMULWB( tmp_32, -psEncCtrl->GainsPre_Q14[ k ] ); /* Q24 */
+ tmp_32 = silk_RSHIFT_ROUND( tmp_32, 14 ); /* Q10 */
+ B_Q10[ 1 ]= silk_SAT16( tmp_32 );
+ x_filt_Q12[ 0 ] = silk_MLA( silk_MUL( st_res_Q2[ 0 ], B_Q10[ 0 ] ), P->sHarmHP_Q2, B_Q10[ 1 ] );
+ for( j = 1; j < psEnc->sCmn.subfr_length; j++ ) {
+ x_filt_Q12[ j ] = silk_MLA( silk_MUL( st_res_Q2[ j ], B_Q10[ 0 ] ), st_res_Q2[ j - 1 ], B_Q10[ 1 ] );
+ }
+ P->sHarmHP_Q2 = st_res_Q2[ psEnc->sCmn.subfr_length - 1 ];
+
+ silk_prefilt_FIX( P, x_filt_Q12, pxw_Q3, HarmShapeFIRPacked_Q12, Tilt_Q14, LF_shp_Q14, lag, psEnc->sCmn.subfr_length );
+
+ px += psEnc->sCmn.subfr_length;
+ pxw_Q3 += psEnc->sCmn.subfr_length;
+ }
+
+ P->lagPrev = psEncCtrl->pitchL[ psEnc->sCmn.nb_subfr - 1 ];
+ RESTORE_STACK;
+}
+
+/* Prefilter for finding Quantizer input signal */
+static OPUS_INLINE void silk_prefilt_FIX(
+ silk_prefilter_state_FIX *P, /* I/O state */
+ opus_int32 st_res_Q12[], /* I short term residual signal */
+ opus_int32 xw_Q3[], /* O prefiltered signal */
+ opus_int32 HarmShapeFIRPacked_Q12, /* I Harmonic shaping coeficients */
+ opus_int Tilt_Q14, /* I Tilt shaping coeficient */
+ opus_int32 LF_shp_Q14, /* I Low-frequancy shaping coeficients */
+ opus_int lag, /* I Lag for harmonic shaping */
+ opus_int length /* I Length of signals */
+)
+{
+ opus_int i, idx, LTP_shp_buf_idx;
+ opus_int32 n_LTP_Q12, n_Tilt_Q10, n_LF_Q10;
+ opus_int32 sLF_MA_shp_Q12, sLF_AR_shp_Q12;
+ opus_int16 *LTP_shp_buf;
+
+ /* To speed up use temp variables instead of using the struct */
+ LTP_shp_buf = P->sLTP_shp;
+ LTP_shp_buf_idx = P->sLTP_shp_buf_idx;
+ sLF_AR_shp_Q12 = P->sLF_AR_shp_Q12;
+ sLF_MA_shp_Q12 = P->sLF_MA_shp_Q12;
+
+ for( i = 0; i < length; i++ ) {
+ if( lag > 0 ) {
+ /* unrolled loop */
+ silk_assert( HARM_SHAPE_FIR_TAPS == 3 );
+ idx = lag + LTP_shp_buf_idx;
+ n_LTP_Q12 = silk_SMULBB( LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 - 1) & LTP_MASK ], HarmShapeFIRPacked_Q12 );
+ n_LTP_Q12 = silk_SMLABT( n_LTP_Q12, LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 ) & LTP_MASK ], HarmShapeFIRPacked_Q12 );
+ n_LTP_Q12 = silk_SMLABB( n_LTP_Q12, LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 + 1) & LTP_MASK ], HarmShapeFIRPacked_Q12 );
+ } else {
+ n_LTP_Q12 = 0;
+ }
+
+ n_Tilt_Q10 = silk_SMULWB( sLF_AR_shp_Q12, Tilt_Q14 );
+ n_LF_Q10 = silk_SMLAWB( silk_SMULWT( sLF_AR_shp_Q12, LF_shp_Q14 ), sLF_MA_shp_Q12, LF_shp_Q14 );
+
+ sLF_AR_shp_Q12 = silk_SUB32( st_res_Q12[ i ], silk_LSHIFT( n_Tilt_Q10, 2 ) );
+ sLF_MA_shp_Q12 = silk_SUB32( sLF_AR_shp_Q12, silk_LSHIFT( n_LF_Q10, 2 ) );
+
+ LTP_shp_buf_idx = ( LTP_shp_buf_idx - 1 ) & LTP_MASK;
+ LTP_shp_buf[ LTP_shp_buf_idx ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sLF_MA_shp_Q12, 12 ) );
+
+ xw_Q3[i] = silk_RSHIFT_ROUND( silk_SUB32( sLF_MA_shp_Q12, n_LTP_Q12 ), 9 );
+ }
+
+ /* Copy temp variable back to state */
+ P->sLF_AR_shp_Q12 = sLF_AR_shp_Q12;
+ P->sLF_MA_shp_Q12 = sLF_MA_shp_Q12;
+ P->sLTP_shp_buf_idx = LTP_shp_buf_idx;
+}
diff --git a/drivers/opus/silk/fixed/process_gains_FIX.c b/drivers/opus/silk/fixed/process_gains_FIX.c
new file mode 100644
index 0000000000..2c501a2010
--- /dev/null
+++ b/drivers/opus/silk/fixed/process_gains_FIX.c
@@ -0,0 +1,117 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/fixed/main_FIX.h"
+#include "opus/silk/tuning_parameters.h"
+
+/* Processing of gains */
+void silk_process_gains_FIX(
+ silk_encoder_state_FIX *psEnc, /* I/O Encoder state */
+ silk_encoder_control_FIX *psEncCtrl, /* I/O Encoder control */
+ opus_int condCoding /* I The type of conditional coding to use */
+)
+{
+ silk_shape_state_FIX *psShapeSt = &psEnc->sShape;
+ opus_int k;
+ opus_int32 s_Q16, InvMaxSqrVal_Q16, gain, gain_squared, ResNrg, ResNrgPart, quant_offset_Q10;
+
+ /* Gain reduction when LTP coding gain is high */
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ /*s = -0.5f * silk_sigmoid( 0.25f * ( psEncCtrl->LTPredCodGain - 12.0f ) ); */
+ s_Q16 = -silk_sigm_Q15( silk_RSHIFT_ROUND( psEncCtrl->LTPredCodGain_Q7 - SILK_FIX_CONST( 12.0, 7 ), 4 ) );
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ psEncCtrl->Gains_Q16[ k ] = silk_SMLAWB( psEncCtrl->Gains_Q16[ k ], psEncCtrl->Gains_Q16[ k ], s_Q16 );
+ }
+ }
+
+ /* Limit the quantized signal */
+ /* InvMaxSqrVal = pow( 2.0f, 0.33f * ( 21.0f - SNR_dB ) ) / subfr_length; */
+ InvMaxSqrVal_Q16 = silk_DIV32_16( silk_log2lin(
+ silk_SMULWB( SILK_FIX_CONST( 21 + 16 / 0.33, 7 ) - psEnc->sCmn.SNR_dB_Q7, SILK_FIX_CONST( 0.33, 16 ) ) ), psEnc->sCmn.subfr_length );
+
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ /* Soft limit on ratio residual energy and squared gains */
+ ResNrg = psEncCtrl->ResNrg[ k ];
+ ResNrgPart = silk_SMULWW( ResNrg, InvMaxSqrVal_Q16 );
+ if( psEncCtrl->ResNrgQ[ k ] > 0 ) {
+ ResNrgPart = silk_RSHIFT_ROUND( ResNrgPart, psEncCtrl->ResNrgQ[ k ] );
+ } else {
+ if( ResNrgPart >= silk_RSHIFT( silk_int32_MAX, -psEncCtrl->ResNrgQ[ k ] ) ) {
+ ResNrgPart = silk_int32_MAX;
+ } else {
+ ResNrgPart = silk_LSHIFT( ResNrgPart, -psEncCtrl->ResNrgQ[ k ] );
+ }
+ }
+ gain = psEncCtrl->Gains_Q16[ k ];
+ gain_squared = silk_ADD_SAT32( ResNrgPart, silk_SMMUL( gain, gain ) );
+ if( gain_squared < silk_int16_MAX ) {
+ /* recalculate with higher precision */
+ gain_squared = silk_SMLAWW( silk_LSHIFT( ResNrgPart, 16 ), gain, gain );
+ silk_assert( gain_squared > 0 );
+ gain = silk_SQRT_APPROX( gain_squared ); /* Q8 */
+ gain = silk_min( gain, silk_int32_MAX >> 8 );
+ psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( gain, 8 ); /* Q16 */
+ } else {
+ gain = silk_SQRT_APPROX( gain_squared ); /* Q0 */
+ gain = silk_min( gain, silk_int32_MAX >> 16 );
+ psEncCtrl->Gains_Q16[ k ] = silk_LSHIFT_SAT32( gain, 16 ); /* Q16 */
+ }
+ }
+
+ /* Save unquantized gains and gain Index */
+ silk_memcpy( psEncCtrl->GainsUnq_Q16, psEncCtrl->Gains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) );
+ psEncCtrl->lastGainIndexPrev = psShapeSt->LastGainIndex;
+
+ /* Quantize gains */
+ silk_gains_quant( psEnc->sCmn.indices.GainsIndices, psEncCtrl->Gains_Q16,
+ &psShapeSt->LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
+
+ /* Set quantizer offset for voiced signals. Larger offset when LTP coding gain is low or tilt is high (ie low-pass) */
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ if( psEncCtrl->LTPredCodGain_Q7 + silk_RSHIFT( psEnc->sCmn.input_tilt_Q15, 8 ) > SILK_FIX_CONST( 1.0, 7 ) ) {
+ psEnc->sCmn.indices.quantOffsetType = 0;
+ } else {
+ psEnc->sCmn.indices.quantOffsetType = 1;
+ }
+ }
+
+ /* Quantizer boundary adjustment */
+ quant_offset_Q10 = silk_Quantization_Offsets_Q10[ psEnc->sCmn.indices.signalType >> 1 ][ psEnc->sCmn.indices.quantOffsetType ];
+ psEncCtrl->Lambda_Q10 = SILK_FIX_CONST( LAMBDA_OFFSET, 10 )
+ + silk_SMULBB( SILK_FIX_CONST( LAMBDA_DELAYED_DECISIONS, 10 ), psEnc->sCmn.nStatesDelayedDecision )
+ + silk_SMULWB( SILK_FIX_CONST( LAMBDA_SPEECH_ACT, 18 ), psEnc->sCmn.speech_activity_Q8 )
+ + silk_SMULWB( SILK_FIX_CONST( LAMBDA_INPUT_QUALITY, 12 ), psEncCtrl->input_quality_Q14 )
+ + silk_SMULWB( SILK_FIX_CONST( LAMBDA_CODING_QUALITY, 12 ), psEncCtrl->coding_quality_Q14 )
+ + silk_SMULWB( SILK_FIX_CONST( LAMBDA_QUANT_OFFSET, 16 ), quant_offset_Q10 );
+
+ silk_assert( psEncCtrl->Lambda_Q10 > 0 );
+ silk_assert( psEncCtrl->Lambda_Q10 < SILK_FIX_CONST( 2, 10 ) );
+}
diff --git a/drivers/opus/silk/fixed/regularize_correlations_FIX.c b/drivers/opus/silk/fixed/regularize_correlations_FIX.c
new file mode 100644
index 0000000000..af34da68fa
--- /dev/null
+++ b/drivers/opus/silk/fixed/regularize_correlations_FIX.c
@@ -0,0 +1,47 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/fixed/main_FIX.h"
+
+/* Add noise to matrix diagonal */
+void silk_regularize_correlations_FIX(
+ opus_int32 *XX, /* I/O Correlation matrices */
+ opus_int32 *xx, /* I/O Correlation values */
+ opus_int32 noise, /* I Noise to add */
+ opus_int D /* I Dimension of XX */
+)
+{
+ opus_int i;
+ for( i = 0; i < D; i++ ) {
+ matrix_ptr( &XX[ 0 ], i, i, D ) = silk_ADD32( matrix_ptr( &XX[ 0 ], i, i, D ), noise );
+ }
+ xx[ 0 ] += noise;
+}
diff --git a/drivers/opus/silk/fixed/residual_energy16_FIX.c b/drivers/opus/silk/fixed/residual_energy16_FIX.c
new file mode 100644
index 0000000000..9b6e103a52
--- /dev/null
+++ b/drivers/opus/silk/fixed/residual_energy16_FIX.c
@@ -0,0 +1,103 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/fixed/main_FIX.h"
+
+/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */
+opus_int32 silk_residual_energy16_covar_FIX(
+ const opus_int16 *c, /* I Prediction vector */
+ const opus_int32 *wXX, /* I Correlation matrix */
+ const opus_int32 *wXx, /* I Correlation vector */
+ opus_int32 wxx, /* I Signal energy */
+ opus_int D, /* I Dimension */
+ opus_int cQ /* I Q value for c vector 0 - 15 */
+)
+{
+ opus_int i, j, lshifts, Qxtra;
+ opus_int32 c_max, w_max, tmp, tmp2, nrg;
+ opus_int cn[ MAX_MATRIX_SIZE ];
+ const opus_int32 *pRow;
+
+ /* Safety checks */
+ silk_assert( D >= 0 );
+ silk_assert( D <= 16 );
+ silk_assert( cQ > 0 );
+ silk_assert( cQ < 16 );
+
+ lshifts = 16 - cQ;
+ Qxtra = lshifts;
+
+ c_max = 0;
+ for( i = 0; i < D; i++ ) {
+ c_max = silk_max_32( c_max, silk_abs( (opus_int32)c[ i ] ) );
+ }
+ Qxtra = silk_min_int( Qxtra, silk_CLZ32( c_max ) - 17 );
+
+ w_max = silk_max_32( wXX[ 0 ], wXX[ D * D - 1 ] );
+ Qxtra = silk_min_int( Qxtra, silk_CLZ32( silk_MUL( D, silk_RSHIFT( silk_SMULWB( w_max, c_max ), 4 ) ) ) - 5 );
+ Qxtra = silk_max_int( Qxtra, 0 );
+ for( i = 0; i < D; i++ ) {
+ cn[ i ] = silk_LSHIFT( ( opus_int )c[ i ], Qxtra );
+ silk_assert( silk_abs(cn[i]) <= ( silk_int16_MAX + 1 ) ); /* Check that silk_SMLAWB can be used */
+ }
+ lshifts -= Qxtra;
+
+ /* Compute wxx - 2 * wXx * c */
+ tmp = 0;
+ for( i = 0; i < D; i++ ) {
+ tmp = silk_SMLAWB( tmp, wXx[ i ], cn[ i ] );
+ }
+ nrg = silk_RSHIFT( wxx, 1 + lshifts ) - tmp; /* Q: -lshifts - 1 */
+
+ /* Add c' * wXX * c, assuming wXX is symmetric */
+ tmp2 = 0;
+ for( i = 0; i < D; i++ ) {
+ tmp = 0;
+ pRow = &wXX[ i * D ];
+ for( j = i + 1; j < D; j++ ) {
+ tmp = silk_SMLAWB( tmp, pRow[ j ], cn[ j ] );
+ }
+ tmp = silk_SMLAWB( tmp, silk_RSHIFT( pRow[ i ], 1 ), cn[ i ] );
+ tmp2 = silk_SMLAWB( tmp2, tmp, cn[ i ] );
+ }
+ nrg = silk_ADD_LSHIFT32( nrg, tmp2, lshifts ); /* Q: -lshifts - 1 */
+
+ /* Keep one bit free always, because we add them for LSF interpolation */
+ if( nrg < 1 ) {
+ nrg = 1;
+ } else if( nrg > silk_RSHIFT( silk_int32_MAX, lshifts + 2 ) ) {
+ nrg = silk_int32_MAX >> 1;
+ } else {
+ nrg = silk_LSHIFT( nrg, lshifts + 1 ); /* Q0 */
+ }
+ return nrg;
+
+}
diff --git a/drivers/opus/silk/fixed/residual_energy_FIX.c b/drivers/opus/silk/fixed/residual_energy_FIX.c
new file mode 100644
index 0000000000..468bfbab48
--- /dev/null
+++ b/drivers/opus/silk/fixed/residual_energy_FIX.c
@@ -0,0 +1,97 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/fixed/main_FIX.h"
+#include "opus/celt/stack_alloc.h"
+
+/* Calculates residual energies of input subframes where all subframes have LPC_order */
+/* of preceding samples */
+void silk_residual_energy_FIX(
+ opus_int32 nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */
+ opus_int nrgsQ[ MAX_NB_SUBFR ], /* O Q value per subframe */
+ const opus_int16 x[], /* I Input signal */
+ opus_int16 a_Q12[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */
+ const opus_int32 gains[ MAX_NB_SUBFR ], /* I Quantization gains */
+ const opus_int subfr_length, /* I Subframe length */
+ const opus_int nb_subfr, /* I Number of subframes */
+ const opus_int LPC_order /* I LPC order */
+)
+{
+ opus_int offset, i, j, rshift, lz1, lz2;
+ opus_int16 *LPC_res_ptr;
+ VARDECL( opus_int16, LPC_res );
+ const opus_int16 *x_ptr;
+ opus_int32 tmp32;
+ SAVE_STACK;
+
+ x_ptr = x;
+ offset = LPC_order + subfr_length;
+
+ /* Filter input to create the LPC residual for each frame half, and measure subframe energies */
+ ALLOC( LPC_res, ( MAX_NB_SUBFR >> 1 ) * offset, opus_int16 );
+ silk_assert( ( nb_subfr >> 1 ) * ( MAX_NB_SUBFR >> 1 ) == nb_subfr );
+ for( i = 0; i < nb_subfr >> 1; i++ ) {
+ /* Calculate half frame LPC residual signal including preceding samples */
+ silk_LPC_analysis_filter( LPC_res, x_ptr, a_Q12[ i ], ( MAX_NB_SUBFR >> 1 ) * offset, LPC_order );
+
+ /* Point to first subframe of the just calculated LPC residual signal */
+ LPC_res_ptr = LPC_res + LPC_order;
+ for( j = 0; j < ( MAX_NB_SUBFR >> 1 ); j++ ) {
+ /* Measure subframe energy */
+ silk_sum_sqr_shift( &nrgs[ i * ( MAX_NB_SUBFR >> 1 ) + j ], &rshift, LPC_res_ptr, subfr_length );
+
+ /* Set Q values for the measured energy */
+ nrgsQ[ i * ( MAX_NB_SUBFR >> 1 ) + j ] = -rshift;
+
+ /* Move to next subframe */
+ LPC_res_ptr += offset;
+ }
+ /* Move to next frame half */
+ x_ptr += ( MAX_NB_SUBFR >> 1 ) * offset;
+ }
+
+ /* Apply the squared subframe gains */
+ for( i = 0; i < nb_subfr; i++ ) {
+ /* Fully upscale gains and energies */
+ lz1 = silk_CLZ32( nrgs[ i ] ) - 1;
+ lz2 = silk_CLZ32( gains[ i ] ) - 1;
+
+ tmp32 = silk_LSHIFT32( gains[ i ], lz2 );
+
+ /* Find squared gains */
+ tmp32 = silk_SMMUL( tmp32, tmp32 ); /* Q( 2 * lz2 - 32 )*/
+
+ /* Scale energies */
+ nrgs[ i ] = silk_SMMUL( tmp32, silk_LSHIFT32( nrgs[ i ], lz1 ) ); /* Q( nrgsQ[ i ] + lz1 + 2 * lz2 - 32 - 32 )*/
+ nrgsQ[ i ] += lz1 + 2 * lz2 - 32 - 32;
+ }
+ RESTORE_STACK;
+}
diff --git a/drivers/opus/silk/fixed/schur64_FIX.c b/drivers/opus/silk/fixed/schur64_FIX.c
new file mode 100644
index 0000000000..fe1278e062
--- /dev/null
+++ b/drivers/opus/silk/fixed/schur64_FIX.c
@@ -0,0 +1,92 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/SigProc_FIX.h"
+
+/* Slower than schur(), but more accurate. */
+/* Uses SMULL(), available on armv4 */
+opus_int32 silk_schur64( /* O returns residual energy */
+ opus_int32 rc_Q16[], /* O Reflection coefficients [order] Q16 */
+ const opus_int32 c[], /* I Correlations [order+1] */
+ opus_int32 order /* I Prediction order */
+)
+{
+ opus_int k, n;
+ opus_int32 C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ];
+ opus_int32 Ctmp1_Q30, Ctmp2_Q30, rc_tmp_Q31;
+
+ silk_assert( order==6||order==8||order==10||order==12||order==14||order==16 );
+
+ /* Check for invalid input */
+ if( c[ 0 ] <= 0 ) {
+ silk_memset( rc_Q16, 0, order * sizeof( opus_int32 ) );
+ return 0;
+ }
+
+ for( k = 0; k < order + 1; k++ ) {
+ C[ k ][ 0 ] = C[ k ][ 1 ] = c[ k ];
+ }
+
+ for( k = 0; k < order; k++ ) {
+ /* Check that we won't be getting an unstable rc, otherwise stop here. */
+ if (silk_abs_int32(C[ k + 1 ][ 0 ]) >= C[ 0 ][ 1 ]) {
+ if ( C[ k + 1 ][ 0 ] > 0 ) {
+ rc_Q16[ k ] = -SILK_FIX_CONST( .99f, 16 );
+ } else {
+ rc_Q16[ k ] = SILK_FIX_CONST( .99f, 16 );
+ }
+ k++;
+ break;
+ }
+
+ /* Get reflection coefficient: divide two Q30 values and get result in Q31 */
+ rc_tmp_Q31 = silk_DIV32_varQ( -C[ k + 1 ][ 0 ], C[ 0 ][ 1 ], 31 );
+
+ /* Save the output */
+ rc_Q16[ k ] = silk_RSHIFT_ROUND( rc_tmp_Q31, 15 );
+
+ /* Update correlations */
+ for( n = 0; n < order - k; n++ ) {
+ Ctmp1_Q30 = C[ n + k + 1 ][ 0 ];
+ Ctmp2_Q30 = C[ n ][ 1 ];
+
+ /* Multiply and add the highest int32 */
+ C[ n + k + 1 ][ 0 ] = Ctmp1_Q30 + silk_SMMUL( silk_LSHIFT( Ctmp2_Q30, 1 ), rc_tmp_Q31 );
+ C[ n ][ 1 ] = Ctmp2_Q30 + silk_SMMUL( silk_LSHIFT( Ctmp1_Q30, 1 ), rc_tmp_Q31 );
+ }
+ }
+
+ for(; k < order; k++ ) {
+ rc_Q16[ k ] = 0;
+ }
+
+ return silk_max_32( 1, C[ 0 ][ 1 ] );
+}
diff --git a/drivers/opus/silk/fixed/schur_FIX.c b/drivers/opus/silk/fixed/schur_FIX.c
new file mode 100644
index 0000000000..b0a36e5ad2
--- /dev/null
+++ b/drivers/opus/silk/fixed/schur_FIX.c
@@ -0,0 +1,106 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/SigProc_FIX.h"
+
+/* Faster than schur64(), but much less accurate. */
+/* uses SMLAWB(), requiring armv5E and higher. */
+opus_int32 silk_schur( /* O Returns residual energy */
+ opus_int16 *rc_Q15, /* O reflection coefficients [order] Q15 */
+ const opus_int32 *c, /* I correlations [order+1] */
+ const opus_int32 order /* I prediction order */
+)
+{
+ opus_int k, n, lz;
+ opus_int32 C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ];
+ opus_int32 Ctmp1, Ctmp2, rc_tmp_Q15;
+
+ silk_assert( order==6||order==8||order==10||order==12||order==14||order==16 );
+
+ /* Get number of leading zeros */
+ lz = silk_CLZ32( c[ 0 ] );
+
+ /* Copy correlations and adjust level to Q30 */
+ if( lz < 2 ) {
+ /* lz must be 1, so shift one to the right */
+ for( k = 0; k < order + 1; k++ ) {
+ C[ k ][ 0 ] = C[ k ][ 1 ] = silk_RSHIFT( c[ k ], 1 );
+ }
+ } else if( lz > 2 ) {
+ /* Shift to the left */
+ lz -= 2;
+ for( k = 0; k < order + 1; k++ ) {
+ C[ k ][ 0 ] = C[ k ][ 1 ] = silk_LSHIFT( c[ k ], lz );
+ }
+ } else {
+ /* No need to shift */
+ for( k = 0; k < order + 1; k++ ) {
+ C[ k ][ 0 ] = C[ k ][ 1 ] = c[ k ];
+ }
+ }
+
+ for( k = 0; k < order; k++ ) {
+ /* Check that we won't be getting an unstable rc, otherwise stop here. */
+ if (silk_abs_int32(C[ k + 1 ][ 0 ]) >= C[ 0 ][ 1 ]) {
+ if ( C[ k + 1 ][ 0 ] > 0 ) {
+ rc_Q15[ k ] = -SILK_FIX_CONST( .99f, 15 );
+ } else {
+ rc_Q15[ k ] = SILK_FIX_CONST( .99f, 15 );
+ }
+ k++;
+ break;
+ }
+
+ /* Get reflection coefficient */
+ rc_tmp_Q15 = -silk_DIV32_16( C[ k + 1 ][ 0 ], silk_max_32( silk_RSHIFT( C[ 0 ][ 1 ], 15 ), 1 ) );
+
+ /* Clip (shouldn't happen for properly conditioned inputs) */
+ rc_tmp_Q15 = silk_SAT16( rc_tmp_Q15 );
+
+ /* Store */
+ rc_Q15[ k ] = (opus_int16)rc_tmp_Q15;
+
+ /* Update correlations */
+ for( n = 0; n < order - k; n++ ) {
+ Ctmp1 = C[ n + k + 1 ][ 0 ];
+ Ctmp2 = C[ n ][ 1 ];
+ C[ n + k + 1 ][ 0 ] = silk_SMLAWB( Ctmp1, silk_LSHIFT( Ctmp2, 1 ), rc_tmp_Q15 );
+ C[ n ][ 1 ] = silk_SMLAWB( Ctmp2, silk_LSHIFT( Ctmp1, 1 ), rc_tmp_Q15 );
+ }
+ }
+
+ for(; k < order; k++ ) {
+ rc_Q15[ k ] = 0;
+ }
+
+ /* return residual energy */
+ return silk_max_32( 1, C[ 0 ][ 1 ] );
+}
diff --git a/drivers/opus/silk/fixed/solve_LS_FIX.c b/drivers/opus/silk/fixed/solve_LS_FIX.c
new file mode 100644
index 0000000000..6e8afaaa88
--- /dev/null
+++ b/drivers/opus/silk/fixed/solve_LS_FIX.c
@@ -0,0 +1,249 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/fixed/main_FIX.h"
+#include "opus/celt/stack_alloc.h"
+#include "opus/silk/tuning_parameters.h"
+
+/*****************************/
+/* Internal function headers */
+/*****************************/
+
+typedef struct {
+ opus_int32 Q36_part;
+ opus_int32 Q48_part;
+} inv_D_t;
+
+/* Factorize square matrix A into LDL form */
+static OPUS_INLINE void silk_LDL_factorize_FIX(
+ opus_int32 *A, /* I/O Pointer to Symetric Square Matrix */
+ opus_int M, /* I Size of Matrix */
+ opus_int32 *L_Q16, /* I/O Pointer to Square Upper triangular Matrix */
+ inv_D_t *inv_D /* I/O Pointer to vector holding inverted diagonal elements of D */
+);
+
+/* Solve Lx = b, when L is lower triangular and has ones on the diagonal */
+static OPUS_INLINE void silk_LS_SolveFirst_FIX(
+ const opus_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */
+ opus_int M, /* I Dim of Matrix equation */
+ const opus_int32 *b, /* I b Vector */
+ opus_int32 *x_Q16 /* O x Vector */
+);
+
+/* Solve L^t*x = b, where L is lower triangular with ones on the diagonal */
+static OPUS_INLINE void silk_LS_SolveLast_FIX(
+ const opus_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */
+ const opus_int M, /* I Dim of Matrix equation */
+ const opus_int32 *b, /* I b Vector */
+ opus_int32 *x_Q16 /* O x Vector */
+);
+
+static OPUS_INLINE void silk_LS_divide_Q16_FIX(
+ opus_int32 T[], /* I/O Numenator vector */
+ inv_D_t *inv_D, /* I 1 / D vector */
+ opus_int M /* I dimension */
+);
+
+/* Solves Ax = b, assuming A is symmetric */
+void silk_solve_LDL_FIX(
+ opus_int32 *A, /* I Pointer to symetric square matrix A */
+ opus_int M, /* I Size of matrix */
+ const opus_int32 *b, /* I Pointer to b vector */
+ opus_int32 *x_Q16 /* O Pointer to x solution vector */
+)
+{
+ VARDECL( opus_int32, L_Q16 );
+ opus_int32 Y[ MAX_MATRIX_SIZE ];
+ inv_D_t inv_D[ MAX_MATRIX_SIZE ];
+ SAVE_STACK;
+
+ silk_assert( M <= MAX_MATRIX_SIZE );
+ ALLOC( L_Q16, M * M, opus_int32 );
+
+ /***************************************************
+ Factorize A by LDL such that A = L*D*L',
+ where L is lower triangular with ones on diagonal
+ ****************************************************/
+ silk_LDL_factorize_FIX( A, M, L_Q16, inv_D );
+
+ /****************************************************
+ * substitute D*L'*x = Y. ie:
+ L*D*L'*x = b => L*Y = b <=> Y = inv(L)*b
+ ******************************************************/
+ silk_LS_SolveFirst_FIX( L_Q16, M, b, Y );
+
+ /****************************************************
+ D*L'*x = Y <=> L'*x = inv(D)*Y, because D is
+ diagonal just multiply with 1/d_i
+ ****************************************************/
+ silk_LS_divide_Q16_FIX( Y, inv_D, M );
+
+ /****************************************************
+ x = inv(L') * inv(D) * Y
+ *****************************************************/
+ silk_LS_SolveLast_FIX( L_Q16, M, Y, x_Q16 );
+ RESTORE_STACK;
+}
+
+static OPUS_INLINE void silk_LDL_factorize_FIX(
+ opus_int32 *A, /* I/O Pointer to Symetric Square Matrix */
+ opus_int M, /* I Size of Matrix */
+ opus_int32 *L_Q16, /* I/O Pointer to Square Upper triangular Matrix */
+ inv_D_t *inv_D /* I/O Pointer to vector holding inverted diagonal elements of D */
+)
+{
+ opus_int i, j, k, status, loop_count;
+ const opus_int32 *ptr1, *ptr2;
+ opus_int32 diag_min_value, tmp_32, err;
+ opus_int32 v_Q0[ MAX_MATRIX_SIZE ], D_Q0[ MAX_MATRIX_SIZE ];
+ opus_int32 one_div_diag_Q36, one_div_diag_Q40, one_div_diag_Q48;
+
+ silk_assert( M <= MAX_MATRIX_SIZE );
+
+ status = 1;
+ diag_min_value = silk_max_32( silk_SMMUL( silk_ADD_SAT32( A[ 0 ], A[ silk_SMULBB( M, M ) - 1 ] ), SILK_FIX_CONST( FIND_LTP_COND_FAC, 31 ) ), 1 << 9 );
+ for( loop_count = 0; loop_count < M && status == 1; loop_count++ ) {
+ status = 0;
+ for( j = 0; j < M; j++ ) {
+ ptr1 = matrix_adr( L_Q16, j, 0, M );
+ tmp_32 = 0;
+ for( i = 0; i < j; i++ ) {
+ v_Q0[ i ] = silk_SMULWW( D_Q0[ i ], ptr1[ i ] ); /* Q0 */
+ tmp_32 = silk_SMLAWW( tmp_32, v_Q0[ i ], ptr1[ i ] ); /* Q0 */
+ }
+ tmp_32 = silk_SUB32( matrix_ptr( A, j, j, M ), tmp_32 );
+
+ if( tmp_32 < diag_min_value ) {
+ tmp_32 = silk_SUB32( silk_SMULBB( loop_count + 1, diag_min_value ), tmp_32 );
+ /* Matrix not positive semi-definite, or ill conditioned */
+ for( i = 0; i < M; i++ ) {
+ matrix_ptr( A, i, i, M ) = silk_ADD32( matrix_ptr( A, i, i, M ), tmp_32 );
+ }
+ status = 1;
+ break;
+ }
+ D_Q0[ j ] = tmp_32; /* always < max(Correlation) */
+
+ /* two-step division */
+ one_div_diag_Q36 = silk_INVERSE32_varQ( tmp_32, 36 ); /* Q36 */
+ one_div_diag_Q40 = silk_LSHIFT( one_div_diag_Q36, 4 ); /* Q40 */
+ err = silk_SUB32( (opus_int32)1 << 24, silk_SMULWW( tmp_32, one_div_diag_Q40 ) ); /* Q24 */
+ one_div_diag_Q48 = silk_SMULWW( err, one_div_diag_Q40 ); /* Q48 */
+
+ /* Save 1/Ds */
+ inv_D[ j ].Q36_part = one_div_diag_Q36;
+ inv_D[ j ].Q48_part = one_div_diag_Q48;
+
+ matrix_ptr( L_Q16, j, j, M ) = 65536; /* 1.0 in Q16 */
+ ptr1 = matrix_adr( A, j, 0, M );
+ ptr2 = matrix_adr( L_Q16, j + 1, 0, M );
+ for( i = j + 1; i < M; i++ ) {
+ tmp_32 = 0;
+ for( k = 0; k < j; k++ ) {
+ tmp_32 = silk_SMLAWW( tmp_32, v_Q0[ k ], ptr2[ k ] ); /* Q0 */
+ }
+ tmp_32 = silk_SUB32( ptr1[ i ], tmp_32 ); /* always < max(Correlation) */
+
+ /* tmp_32 / D_Q0[j] : Divide to Q16 */
+ matrix_ptr( L_Q16, i, j, M ) = silk_ADD32( silk_SMMUL( tmp_32, one_div_diag_Q48 ),
+ silk_RSHIFT( silk_SMULWW( tmp_32, one_div_diag_Q36 ), 4 ) );
+
+ /* go to next column */
+ ptr2 += M;
+ }
+ }
+ }
+
+ silk_assert( status == 0 );
+}
+
+static OPUS_INLINE void silk_LS_divide_Q16_FIX(
+ opus_int32 T[], /* I/O Numenator vector */
+ inv_D_t *inv_D, /* I 1 / D vector */
+ opus_int M /* I dimension */
+)
+{
+ opus_int i;
+ opus_int32 tmp_32;
+ opus_int32 one_div_diag_Q36, one_div_diag_Q48;
+
+ for( i = 0; i < M; i++ ) {
+ one_div_diag_Q36 = inv_D[ i ].Q36_part;
+ one_div_diag_Q48 = inv_D[ i ].Q48_part;
+
+ tmp_32 = T[ i ];
+ T[ i ] = silk_ADD32( silk_SMMUL( tmp_32, one_div_diag_Q48 ), silk_RSHIFT( silk_SMULWW( tmp_32, one_div_diag_Q36 ), 4 ) );
+ }
+}
+
+/* Solve Lx = b, when L is lower triangular and has ones on the diagonal */
+static OPUS_INLINE void silk_LS_SolveFirst_FIX(
+ const opus_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */
+ opus_int M, /* I Dim of Matrix equation */
+ const opus_int32 *b, /* I b Vector */
+ opus_int32 *x_Q16 /* O x Vector */
+)
+{
+ opus_int i, j;
+ const opus_int32 *ptr32;
+ opus_int32 tmp_32;
+
+ for( i = 0; i < M; i++ ) {
+ ptr32 = matrix_adr( L_Q16, i, 0, M );
+ tmp_32 = 0;
+ for( j = 0; j < i; j++ ) {
+ tmp_32 = silk_SMLAWW( tmp_32, ptr32[ j ], x_Q16[ j ] );
+ }
+ x_Q16[ i ] = silk_SUB32( b[ i ], tmp_32 );
+ }
+}
+
+/* Solve L^t*x = b, where L is lower triangular with ones on the diagonal */
+static OPUS_INLINE void silk_LS_SolveLast_FIX(
+ const opus_int32 *L_Q16, /* I Pointer to Lower Triangular Matrix */
+ const opus_int M, /* I Dim of Matrix equation */
+ const opus_int32 *b, /* I b Vector */
+ opus_int32 *x_Q16 /* O x Vector */
+)
+{
+ opus_int i, j;
+ const opus_int32 *ptr32;
+ opus_int32 tmp_32;
+
+ for( i = M - 1; i >= 0; i-- ) {
+ ptr32 = matrix_adr( L_Q16, 0, i, M );
+ tmp_32 = 0;
+ for( j = M - 1; j > i; j-- ) {
+ tmp_32 = silk_SMLAWW( tmp_32, ptr32[ silk_SMULBB( j, M ) ], x_Q16[ j ] );
+ }
+ x_Q16[ i ] = silk_SUB32( b[ i ], tmp_32 );
+ }
+}
diff --git a/drivers/opus/silk/fixed/structs_FIX.h b/drivers/opus/silk/fixed/structs_FIX.h
new file mode 100644
index 0000000000..21eab05f0f
--- /dev/null
+++ b/drivers/opus/silk/fixed/structs_FIX.h
@@ -0,0 +1,133 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_STRUCTS_FIX_H
+#define SILK_STRUCTS_FIX_H
+
+#include "opus/silk/typedef.h"
+#include "opus/silk/silk_main.h"
+#include "opus/silk/structs.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/********************************/
+/* Noise shaping analysis state */
+/********************************/
+typedef struct {
+ opus_int8 LastGainIndex;
+ opus_int32 HarmBoost_smth_Q16;
+ opus_int32 HarmShapeGain_smth_Q16;
+ opus_int32 Tilt_smth_Q16;
+} silk_shape_state_FIX;
+
+/********************************/
+/* Prefilter state */
+/********************************/
+typedef struct {
+ opus_int16 sLTP_shp[ LTP_BUF_LENGTH ];
+ opus_int32 sAR_shp[ MAX_SHAPE_LPC_ORDER + 1 ];
+ opus_int sLTP_shp_buf_idx;
+ opus_int32 sLF_AR_shp_Q12;
+ opus_int32 sLF_MA_shp_Q12;
+ opus_int32 sHarmHP_Q2;
+ opus_int32 rand_seed;
+ opus_int lagPrev;
+} silk_prefilter_state_FIX;
+
+/********************************/
+/* Encoder state FIX */
+/********************************/
+typedef struct {
+ silk_encoder_state sCmn; /* Common struct, shared with floating-point code */
+ silk_shape_state_FIX sShape; /* Shape state */
+ silk_prefilter_state_FIX sPrefilt; /* Prefilter State */
+
+ /* Buffer for find pitch and noise shape analysis */
+ silk_DWORD_ALIGN opus_int16 x_buf[ 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ];/* Buffer for find pitch and noise shape analysis */
+ opus_int LTPCorr_Q15; /* Normalized correlation from pitch lag estimator */
+} silk_encoder_state_FIX;
+
+/************************/
+/* Encoder control FIX */
+/************************/
+typedef struct {
+ /* Prediction and coding parameters */
+ opus_int32 Gains_Q16[ MAX_NB_SUBFR ];
+ silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ];
+ opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ];
+ opus_int LTP_scale_Q14;
+ opus_int pitchL[ MAX_NB_SUBFR ];
+
+ /* Noise shaping parameters */
+ /* Testing */
+ silk_DWORD_ALIGN opus_int16 AR1_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ];
+ silk_DWORD_ALIGN opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ];
+ opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ]; /* Packs two int16 coefficients per int32 value */
+ opus_int GainsPre_Q14[ MAX_NB_SUBFR ];
+ opus_int HarmBoost_Q14[ MAX_NB_SUBFR ];
+ opus_int Tilt_Q14[ MAX_NB_SUBFR ];
+ opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ];
+ opus_int Lambda_Q10;
+ opus_int input_quality_Q14;
+ opus_int coding_quality_Q14;
+
+ /* measures */
+ opus_int sparseness_Q8;
+ opus_int32 predGain_Q16;
+ opus_int LTPredCodGain_Q7;
+ opus_int32 ResNrg[ MAX_NB_SUBFR ]; /* Residual energy per subframe */
+ opus_int ResNrgQ[ MAX_NB_SUBFR ]; /* Q domain for the residual energy > 0 */
+
+ /* Parameters for CBR mode */
+ opus_int32 GainsUnq_Q16[ MAX_NB_SUBFR ];
+ opus_int8 lastGainIndexPrev;
+} silk_encoder_control_FIX;
+
+/************************/
+/* Encoder Super Struct */
+/************************/
+typedef struct {
+ silk_encoder_state_FIX state_Fxx[ ENCODER_NUM_CHANNELS ];
+ stereo_enc_state sStereo;
+ opus_int32 nBitsExceeded;
+ opus_int nChannelsAPI;
+ opus_int nChannelsInternal;
+ opus_int nPrevChannelsInternal;
+ opus_int timeSinceSwitchAllowed_ms;
+ opus_int allowBandwidthSwitch;
+ opus_int prev_decode_only_middle;
+} silk_encoder;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/opus/silk/fixed/vector_ops_FIX.c b/drivers/opus/silk/fixed/vector_ops_FIX.c
new file mode 100644
index 0000000000..c2725194ec
--- /dev/null
+++ b/drivers/opus/silk/fixed/vector_ops_FIX.c
@@ -0,0 +1,96 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/SigProc_FIX.h"
+
+/* Copy and multiply a vector by a constant */
+void silk_scale_copy_vector16(
+ opus_int16 *data_out,
+ const opus_int16 *data_in,
+ opus_int32 gain_Q16, /* I Gain in Q16 */
+ const opus_int dataSize /* I Length */
+)
+{
+ opus_int i;
+ opus_int32 tmp32;
+
+ for( i = 0; i < dataSize; i++ ) {
+ tmp32 = silk_SMULWB( gain_Q16, data_in[ i ] );
+ data_out[ i ] = (opus_int16)silk_CHECK_FIT16( tmp32 );
+ }
+}
+
+/* Multiply a vector by a constant */
+void silk_scale_vector32_Q26_lshift_18(
+ opus_int32 *data1, /* I/O Q0/Q18 */
+ opus_int32 gain_Q26, /* I Q26 */
+ opus_int dataSize /* I length */
+)
+{
+ opus_int i;
+
+ for( i = 0; i < dataSize; i++ ) {
+ data1[ i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( silk_SMULL( data1[ i ], gain_Q26 ), 8 ) ); /* OUTPUT: Q18 */
+ }
+}
+
+/* sum = for(i=0;i<len;i++)inVec1[i]*inVec2[i]; --- inner product */
+/* Note for ARM asm: */
+/* * inVec1 and inVec2 should be at least 2 byte aligned. */
+/* * len should be positive 16bit integer. */
+/* * only when len>6, memory access can be reduced by half. */
+opus_int32 silk_inner_prod_aligned(
+ const opus_int16 *const inVec1, /* I input vector 1 */
+ const opus_int16 *const inVec2, /* I input vector 2 */
+ const opus_int len /* I vector lengths */
+)
+{
+ opus_int i;
+ opus_int32 sum = 0;
+ for( i = 0; i < len; i++ ) {
+ sum = silk_SMLABB( sum, inVec1[ i ], inVec2[ i ] );
+ }
+ return sum;
+}
+
+opus_int64 silk_inner_prod16_aligned_64(
+ const opus_int16 *inVec1, /* I input vector 1 */
+ const opus_int16 *inVec2, /* I input vector 2 */
+ const opus_int len /* I vector lengths */
+)
+{
+ opus_int i;
+ opus_int64 sum = 0;
+ for( i = 0; i < len; i++ ) {
+ sum = silk_SMLALBB( sum, inVec1[ i ], inVec2[ i ] );
+ }
+ return sum;
+}
diff --git a/drivers/opus/silk/fixed/warped_autocorrelation_FIX.c b/drivers/opus/silk/fixed/warped_autocorrelation_FIX.c
new file mode 100644
index 0000000000..4e5a7fee58
--- /dev/null
+++ b/drivers/opus/silk/fixed/warped_autocorrelation_FIX.c
@@ -0,0 +1,88 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/fixed/main_FIX.h"
+
+#define QC 10
+#define QS 14
+
+/* Autocorrelations for a warped frequency axis */
+void silk_warped_autocorrelation_FIX(
+ opus_int32 *corr, /* O Result [order + 1] */
+ opus_int *scale, /* O Scaling of the correlation vector */
+ const opus_int16 *input, /* I Input data to correlate */
+ const opus_int warping_Q16, /* I Warping coefficient */
+ const opus_int length, /* I Length of input */
+ const opus_int order /* I Correlation order (even) */
+)
+{
+ opus_int n, i, lsh;
+ opus_int32 tmp1_QS, tmp2_QS;
+ opus_int32 state_QS[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 };
+ opus_int64 corr_QC[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0 };
+
+ /* Order must be even */
+ silk_assert( ( order & 1 ) == 0 );
+ silk_assert( 2 * QS - QC >= 0 );
+
+ /* Loop over samples */
+ for( n = 0; n < length; n++ ) {
+ tmp1_QS = silk_LSHIFT32( (opus_int32)input[ n ], QS );
+ /* Loop over allpass sections */
+ for( i = 0; i < order; i += 2 ) {
+ /* Output of allpass section */
+ tmp2_QS = silk_SMLAWB( state_QS[ i ], state_QS[ i + 1 ] - tmp1_QS, warping_Q16 );
+ state_QS[ i ] = tmp1_QS;
+ corr_QC[ i ] += silk_RSHIFT64( silk_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC );
+ /* Output of allpass section */
+ tmp1_QS = silk_SMLAWB( state_QS[ i + 1 ], state_QS[ i + 2 ] - tmp2_QS, warping_Q16 );
+ state_QS[ i + 1 ] = tmp2_QS;
+ corr_QC[ i + 1 ] += silk_RSHIFT64( silk_SMULL( tmp2_QS, state_QS[ 0 ] ), 2 * QS - QC );
+ }
+ state_QS[ order ] = tmp1_QS;
+ corr_QC[ order ] += silk_RSHIFT64( silk_SMULL( tmp1_QS, state_QS[ 0 ] ), 2 * QS - QC );
+ }
+
+ lsh = silk_CLZ64( corr_QC[ 0 ] ) - 35;
+ lsh = silk_LIMIT( lsh, -12 - QC, 30 - QC );
+ *scale = -( QC + lsh );
+ silk_assert( *scale >= -30 && *scale <= 12 );
+ if( lsh >= 0 ) {
+ for( i = 0; i < order + 1; i++ ) {
+ corr[ i ] = (opus_int32)silk_CHECK_FIT32( silk_LSHIFT64( corr_QC[ i ], lsh ) );
+ }
+ } else {
+ for( i = 0; i < order + 1; i++ ) {
+ corr[ i ] = (opus_int32)silk_CHECK_FIT32( silk_RSHIFT64( corr_QC[ i ], -lsh ) );
+ }
+ }
+ silk_assert( corr_QC[ 0 ] >= 0 ); /* If breaking, decrease QC*/
+}
diff --git a/drivers/opus/silk/float/LPC_analysis_filter_FLP.c b/drivers/opus/silk/float/LPC_analysis_filter_FLP.c
new file mode 100644
index 0000000000..438b704fe9
--- /dev/null
+++ b/drivers/opus/silk/float/LPC_analysis_filter_FLP.c
@@ -0,0 +1,249 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include <stdlib.h>
+#include "opus/silk/float/main_FLP.h"
+
+/************************************************/
+/* LPC analysis filter */
+/* NB! State is kept internally and the */
+/* filter always starts with zero state */
+/* first Order output samples are set to zero */
+/************************************************/
+
+/* 16th order LPC analysis filter, does not write first 16 samples */
+static OPUS_INLINE void silk_LPC_analysis_filter16_FLP(
+ silk_float r_LPC[], /* O LPC residual signal */
+ const silk_float PredCoef[], /* I LPC coefficients */
+ const silk_float s[], /* I Input signal */
+ const opus_int length /* I Length of input signal */
+)
+{
+ opus_int ix;
+ silk_float LPC_pred;
+ const silk_float *s_ptr;
+
+ for( ix = 16; ix < length; ix++ ) {
+ s_ptr = &s[ix - 1];
+
+ /* short-term prediction */
+ LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] +
+ s_ptr[ -1 ] * PredCoef[ 1 ] +
+ s_ptr[ -2 ] * PredCoef[ 2 ] +
+ s_ptr[ -3 ] * PredCoef[ 3 ] +
+ s_ptr[ -4 ] * PredCoef[ 4 ] +
+ s_ptr[ -5 ] * PredCoef[ 5 ] +
+ s_ptr[ -6 ] * PredCoef[ 6 ] +
+ s_ptr[ -7 ] * PredCoef[ 7 ] +
+ s_ptr[ -8 ] * PredCoef[ 8 ] +
+ s_ptr[ -9 ] * PredCoef[ 9 ] +
+ s_ptr[ -10 ] * PredCoef[ 10 ] +
+ s_ptr[ -11 ] * PredCoef[ 11 ] +
+ s_ptr[ -12 ] * PredCoef[ 12 ] +
+ s_ptr[ -13 ] * PredCoef[ 13 ] +
+ s_ptr[ -14 ] * PredCoef[ 14 ] +
+ s_ptr[ -15 ] * PredCoef[ 15 ];
+
+ /* prediction error */
+ r_LPC[ix] = s_ptr[ 1 ] - LPC_pred;
+ }
+}
+
+/* 12th order LPC analysis filter, does not write first 12 samples */
+static OPUS_INLINE void silk_LPC_analysis_filter12_FLP(
+ silk_float r_LPC[], /* O LPC residual signal */
+ const silk_float PredCoef[], /* I LPC coefficients */
+ const silk_float s[], /* I Input signal */
+ const opus_int length /* I Length of input signal */
+)
+{
+ opus_int ix;
+ silk_float LPC_pred;
+ const silk_float *s_ptr;
+
+ for( ix = 12; ix < length; ix++ ) {
+ s_ptr = &s[ix - 1];
+
+ /* short-term prediction */
+ LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] +
+ s_ptr[ -1 ] * PredCoef[ 1 ] +
+ s_ptr[ -2 ] * PredCoef[ 2 ] +
+ s_ptr[ -3 ] * PredCoef[ 3 ] +
+ s_ptr[ -4 ] * PredCoef[ 4 ] +
+ s_ptr[ -5 ] * PredCoef[ 5 ] +
+ s_ptr[ -6 ] * PredCoef[ 6 ] +
+ s_ptr[ -7 ] * PredCoef[ 7 ] +
+ s_ptr[ -8 ] * PredCoef[ 8 ] +
+ s_ptr[ -9 ] * PredCoef[ 9 ] +
+ s_ptr[ -10 ] * PredCoef[ 10 ] +
+ s_ptr[ -11 ] * PredCoef[ 11 ];
+
+ /* prediction error */
+ r_LPC[ix] = s_ptr[ 1 ] - LPC_pred;
+ }
+}
+
+/* 10th order LPC analysis filter, does not write first 10 samples */
+static OPUS_INLINE void silk_LPC_analysis_filter10_FLP(
+ silk_float r_LPC[], /* O LPC residual signal */
+ const silk_float PredCoef[], /* I LPC coefficients */
+ const silk_float s[], /* I Input signal */
+ const opus_int length /* I Length of input signal */
+)
+{
+ opus_int ix;
+ silk_float LPC_pred;
+ const silk_float *s_ptr;
+
+ for( ix = 10; ix < length; ix++ ) {
+ s_ptr = &s[ix - 1];
+
+ /* short-term prediction */
+ LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] +
+ s_ptr[ -1 ] * PredCoef[ 1 ] +
+ s_ptr[ -2 ] * PredCoef[ 2 ] +
+ s_ptr[ -3 ] * PredCoef[ 3 ] +
+ s_ptr[ -4 ] * PredCoef[ 4 ] +
+ s_ptr[ -5 ] * PredCoef[ 5 ] +
+ s_ptr[ -6 ] * PredCoef[ 6 ] +
+ s_ptr[ -7 ] * PredCoef[ 7 ] +
+ s_ptr[ -8 ] * PredCoef[ 8 ] +
+ s_ptr[ -9 ] * PredCoef[ 9 ];
+
+ /* prediction error */
+ r_LPC[ix] = s_ptr[ 1 ] - LPC_pred;
+ }
+}
+
+/* 8th order LPC analysis filter, does not write first 8 samples */
+static OPUS_INLINE void silk_LPC_analysis_filter8_FLP(
+ silk_float r_LPC[], /* O LPC residual signal */
+ const silk_float PredCoef[], /* I LPC coefficients */
+ const silk_float s[], /* I Input signal */
+ const opus_int length /* I Length of input signal */
+)
+{
+ opus_int ix;
+ silk_float LPC_pred;
+ const silk_float *s_ptr;
+
+ for( ix = 8; ix < length; ix++ ) {
+ s_ptr = &s[ix - 1];
+
+ /* short-term prediction */
+ LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] +
+ s_ptr[ -1 ] * PredCoef[ 1 ] +
+ s_ptr[ -2 ] * PredCoef[ 2 ] +
+ s_ptr[ -3 ] * PredCoef[ 3 ] +
+ s_ptr[ -4 ] * PredCoef[ 4 ] +
+ s_ptr[ -5 ] * PredCoef[ 5 ] +
+ s_ptr[ -6 ] * PredCoef[ 6 ] +
+ s_ptr[ -7 ] * PredCoef[ 7 ];
+
+ /* prediction error */
+ r_LPC[ix] = s_ptr[ 1 ] - LPC_pred;
+ }
+}
+
+/* 6th order LPC analysis filter, does not write first 6 samples */
+static OPUS_INLINE void silk_LPC_analysis_filter6_FLP(
+ silk_float r_LPC[], /* O LPC residual signal */
+ const silk_float PredCoef[], /* I LPC coefficients */
+ const silk_float s[], /* I Input signal */
+ const opus_int length /* I Length of input signal */
+)
+{
+ opus_int ix;
+ silk_float LPC_pred;
+ const silk_float *s_ptr;
+
+ for( ix = 6; ix < length; ix++ ) {
+ s_ptr = &s[ix - 1];
+
+ /* short-term prediction */
+ LPC_pred = s_ptr[ 0 ] * PredCoef[ 0 ] +
+ s_ptr[ -1 ] * PredCoef[ 1 ] +
+ s_ptr[ -2 ] * PredCoef[ 2 ] +
+ s_ptr[ -3 ] * PredCoef[ 3 ] +
+ s_ptr[ -4 ] * PredCoef[ 4 ] +
+ s_ptr[ -5 ] * PredCoef[ 5 ];
+
+ /* prediction error */
+ r_LPC[ix] = s_ptr[ 1 ] - LPC_pred;
+ }
+}
+
+/************************************************/
+/* LPC analysis filter */
+/* NB! State is kept internally and the */
+/* filter always starts with zero state */
+/* first Order output samples are set to zero */
+/************************************************/
+void silk_LPC_analysis_filter_FLP(
+ silk_float r_LPC[], /* O LPC residual signal */
+ const silk_float PredCoef[], /* I LPC coefficients */
+ const silk_float s[], /* I Input signal */
+ const opus_int length, /* I Length of input signal */
+ const opus_int Order /* I LPC order */
+)
+{
+ silk_assert( Order <= length );
+
+ switch( Order ) {
+ case 6:
+ silk_LPC_analysis_filter6_FLP( r_LPC, PredCoef, s, length );
+ break;
+
+ case 8:
+ silk_LPC_analysis_filter8_FLP( r_LPC, PredCoef, s, length );
+ break;
+
+ case 10:
+ silk_LPC_analysis_filter10_FLP( r_LPC, PredCoef, s, length );
+ break;
+
+ case 12:
+ silk_LPC_analysis_filter12_FLP( r_LPC, PredCoef, s, length );
+ break;
+
+ case 16:
+ silk_LPC_analysis_filter16_FLP( r_LPC, PredCoef, s, length );
+ break;
+
+ default:
+ silk_assert( 0 );
+ break;
+ }
+
+ /* Set first Order output samples to zero */
+ silk_memset( r_LPC, 0, Order * sizeof( silk_float ) );
+}
+
diff --git a/drivers/opus/silk/float/LPC_inv_pred_gain_FLP.c b/drivers/opus/silk/float/LPC_inv_pred_gain_FLP.c
new file mode 100644
index 0000000000..2e86e269eb
--- /dev/null
+++ b/drivers/opus/silk/float/LPC_inv_pred_gain_FLP.c
@@ -0,0 +1,76 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/SigProc_FIX.h"
+#include "opus/silk/float/SigProc_FLP.h"
+
+#define RC_THRESHOLD 0.9999f
+
+/* compute inverse of LPC prediction gain, and */
+/* test if LPC coefficients are stable (all poles within unit circle) */
+/* this code is based on silk_a2k_FLP() */
+silk_float silk_LPC_inverse_pred_gain_FLP( /* O return inverse prediction gain, energy domain */
+ const silk_float *A, /* I prediction coefficients [order] */
+ opus_int32 order /* I prediction order */
+)
+{
+ opus_int k, n;
+ double invGain, rc, rc_mult1, rc_mult2;
+ silk_float Atmp[ 2 ][ SILK_MAX_ORDER_LPC ];
+ silk_float *Aold, *Anew;
+
+ Anew = Atmp[ order & 1 ];
+ silk_memcpy( Anew, A, order * sizeof(silk_float) );
+
+ invGain = 1.0;
+ for( k = order - 1; k > 0; k-- ) {
+ rc = -Anew[ k ];
+ if( rc > RC_THRESHOLD || rc < -RC_THRESHOLD ) {
+ return 0.0f;
+ }
+ rc_mult1 = 1.0f - rc * rc;
+ rc_mult2 = 1.0f / rc_mult1;
+ invGain *= rc_mult1;
+ /* swap pointers */
+ Aold = Anew;
+ Anew = Atmp[ k & 1 ];
+ for( n = 0; n < k; n++ ) {
+ Anew[ n ] = (silk_float)( ( Aold[ n ] - Aold[ k - n - 1 ] * rc ) * rc_mult2 );
+ }
+ }
+ rc = -Anew[ 0 ];
+ if( rc > RC_THRESHOLD || rc < -RC_THRESHOLD ) {
+ return 0.0f;
+ }
+ rc_mult1 = 1.0f - rc * rc;
+ invGain *= rc_mult1;
+ return (silk_float)invGain;
+}
diff --git a/drivers/opus/silk/float/LTP_analysis_filter_FLP.c b/drivers/opus/silk/float/LTP_analysis_filter_FLP.c
new file mode 100644
index 0000000000..5919ceb928
--- /dev/null
+++ b/drivers/opus/silk/float/LTP_analysis_filter_FLP.c
@@ -0,0 +1,75 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/float/main_FLP.h"
+
+void silk_LTP_analysis_filter_FLP(
+ silk_float *LTP_res, /* O LTP res MAX_NB_SUBFR*(pre_lgth+subfr_lngth) */
+ const silk_float *x, /* I Input signal, with preceding samples */
+ const silk_float B[ LTP_ORDER * MAX_NB_SUBFR ], /* I LTP coefficients for each subframe */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */
+ const silk_float invGains[ MAX_NB_SUBFR ], /* I Inverse quantization gains */
+ const opus_int subfr_length, /* I Length of each subframe */
+ const opus_int nb_subfr, /* I number of subframes */
+ const opus_int pre_length /* I Preceding samples for each subframe */
+)
+{
+ const silk_float *x_ptr, *x_lag_ptr;
+ silk_float Btmp[ LTP_ORDER ];
+ silk_float *LTP_res_ptr;
+ silk_float inv_gain;
+ opus_int k, i, j;
+
+ x_ptr = x;
+ LTP_res_ptr = LTP_res;
+ for( k = 0; k < nb_subfr; k++ ) {
+ x_lag_ptr = x_ptr - pitchL[ k ];
+ inv_gain = invGains[ k ];
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ Btmp[ i ] = B[ k * LTP_ORDER + i ];
+ }
+
+ /* LTP analysis FIR filter */
+ for( i = 0; i < subfr_length + pre_length; i++ ) {
+ LTP_res_ptr[ i ] = x_ptr[ i ];
+ /* Subtract long-term prediction */
+ for( j = 0; j < LTP_ORDER; j++ ) {
+ LTP_res_ptr[ i ] -= Btmp[ j ] * x_lag_ptr[ LTP_ORDER / 2 - j ];
+ }
+ LTP_res_ptr[ i ] *= inv_gain;
+ x_lag_ptr++;
+ }
+
+ /* Update pointers */
+ LTP_res_ptr += subfr_length + pre_length;
+ x_ptr += subfr_length;
+ }
+}
diff --git a/drivers/opus/silk/float/LTP_scale_ctrl_FLP.c b/drivers/opus/silk/float/LTP_scale_ctrl_FLP.c
new file mode 100644
index 0000000000..c952d810af
--- /dev/null
+++ b/drivers/opus/silk/float/LTP_scale_ctrl_FLP.c
@@ -0,0 +1,52 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/float/main_FLP.h"
+
+void silk_LTP_scale_ctrl_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ opus_int condCoding /* I The type of conditional coding to use */
+)
+{
+ opus_int round_loss;
+
+ if( condCoding == CODE_INDEPENDENTLY ) {
+ /* Only scale if first frame in packet */
+ round_loss = psEnc->sCmn.PacketLoss_perc + psEnc->sCmn.nFramesPerPacket;
+ psEnc->sCmn.indices.LTP_scaleIndex = (opus_int8)silk_LIMIT( round_loss * psEncCtrl->LTPredCodGain * 0.1f, 0.0f, 2.0f );
+ } else {
+ /* Default is minimum scaling */
+ psEnc->sCmn.indices.LTP_scaleIndex = 0;
+ }
+
+ psEncCtrl->LTP_scale = (silk_float)silk_LTPScales_table_Q14[ psEnc->sCmn.indices.LTP_scaleIndex ] / 16384.0f;
+}
diff --git a/drivers/opus/silk/float/SigProc_FLP.h b/drivers/opus/silk/float/SigProc_FLP.h
new file mode 100644
index 0000000000..9b14f24f21
--- /dev/null
+++ b/drivers/opus/silk/float/SigProc_FLP.h
@@ -0,0 +1,204 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_SIGPROC_FLP_H
+#define SILK_SIGPROC_FLP_H
+
+#include "opus/silk/SigProc_FIX.h"
+#include "opus/celt/float_cast.h"
+#include <math.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/********************************************************************/
+/* SIGNAL PROCESSING FUNCTIONS */
+/********************************************************************/
+
+/* Chirp (bw expand) LP AR filter */
+void silk_bwexpander_FLP(
+ silk_float *ar, /* I/O AR filter to be expanded (without leading 1) */
+ const opus_int d, /* I length of ar */
+ const silk_float chirp /* I chirp factor (typically in range (0..1) ) */
+);
+
+/* compute inverse of LPC prediction gain, and */
+/* test if LPC coefficients are stable (all poles within unit circle) */
+/* this code is based on silk_FLP_a2k() */
+silk_float silk_LPC_inverse_pred_gain_FLP( /* O return inverse prediction gain, energy domain */
+ const silk_float *A, /* I prediction coefficients [order] */
+ opus_int32 order /* I prediction order */
+);
+
+silk_float silk_schur_FLP( /* O returns residual energy */
+ silk_float refl_coef[], /* O reflection coefficients (length order) */
+ const silk_float auto_corr[], /* I autocorrelation sequence (length order+1) */
+ opus_int order /* I order */
+);
+
+void silk_k2a_FLP(
+ silk_float *A, /* O prediction coefficients [order] */
+ const silk_float *rc, /* I reflection coefficients [order] */
+ opus_int32 order /* I prediction order */
+);
+
+/* Solve the normal equations using the Levinson-Durbin recursion */
+silk_float silk_levinsondurbin_FLP( /* O prediction error energy */
+ silk_float A[], /* O prediction coefficients [order] */
+ const silk_float corr[], /* I input auto-correlations [order + 1] */
+ const opus_int order /* I prediction order */
+);
+
+/* compute autocorrelation */
+void silk_autocorrelation_FLP(
+ silk_float *results, /* O result (length correlationCount) */
+ const silk_float *inputData, /* I input data to correlate */
+ opus_int inputDataSize, /* I length of input */
+ opus_int correlationCount /* I number of correlation taps to compute */
+);
+
+opus_int silk_pitch_analysis_core_FLP( /* O Voicing estimate: 0 voiced, 1 unvoiced */
+ const silk_float *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */
+ opus_int *pitch_out, /* O Pitch lag values [nb_subfr] */
+ opus_int16 *lagIndex, /* O Lag Index */
+ opus_int8 *contourIndex, /* O Pitch contour Index */
+ silk_float *LTPCorr, /* I/O Normalized correlation; input: value from previous frame */
+ opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */
+ const silk_float search_thres1, /* I First stage threshold for lag candidates 0 - 1 */
+ const silk_float search_thres2, /* I Final threshold for lag candidates 0 - 1 */
+ const opus_int Fs_kHz, /* I sample frequency (kHz) */
+ const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */
+ const opus_int nb_subfr, /* I Number of 5 ms subframes */
+ int arch /* I Run-time architecture */
+);
+
+void silk_insertion_sort_decreasing_FLP(
+ silk_float *a, /* I/O Unsorted / Sorted vector */
+ opus_int *idx, /* O Index vector for the sorted elements */
+ const opus_int L, /* I Vector length */
+ const opus_int K /* I Number of correctly sorted positions */
+);
+
+/* Compute reflection coefficients from input signal */
+silk_float silk_burg_modified_FLP( /* O returns residual energy */
+ silk_float A[], /* O prediction coefficients (length order) */
+ const silk_float x[], /* I input signal, length: nb_subfr*(D+L_sub) */
+ const silk_float minInvGain, /* I minimum inverse prediction gain */
+ const opus_int subfr_length, /* I input signal subframe length (incl. D preceding samples) */
+ const opus_int nb_subfr, /* I number of subframes stacked in x */
+ const opus_int D /* I order */
+);
+
+/* multiply a vector by a constant */
+void silk_scale_vector_FLP(
+ silk_float *data1,
+ silk_float gain,
+ opus_int dataSize
+);
+
+/* copy and multiply a vector by a constant */
+void silk_scale_copy_vector_FLP(
+ silk_float *data_out,
+ const silk_float *data_in,
+ silk_float gain,
+ opus_int dataSize
+);
+
+/* inner product of two silk_float arrays, with result as double */
+double silk_inner_product_FLP(
+ const silk_float *data1,
+ const silk_float *data2,
+ opus_int dataSize
+);
+
+/* sum of squares of a silk_float array, with result as double */
+double silk_energy_FLP(
+ const silk_float *data,
+ opus_int dataSize
+);
+
+/********************************************************************/
+/* MACROS */
+/********************************************************************/
+
+#define PI (3.1415926536f)
+
+#define silk_min_float( a, b ) (((a) < (b)) ? (a) : (b))
+#define silk_max_float( a, b ) (((a) > (b)) ? (a) : (b))
+#define silk_abs_float( a ) ((silk_float)fabs(a))
+
+/* sigmoid function */
+static OPUS_INLINE silk_float silk_sigmoid( silk_float x )
+{
+ return (silk_float)(1.0 / (1.0 + exp(-x)));
+}
+
+/* floating-point to integer conversion (rounding) */
+static OPUS_INLINE opus_int32 silk_float2int( silk_float x )
+{
+ return (opus_int32)float2int( x );
+}
+
+/* floating-point to integer conversion (rounding) */
+static OPUS_INLINE void silk_float2short_array(
+ opus_int16 *out,
+ const silk_float *in,
+ opus_int32 length
+)
+{
+ opus_int32 k;
+ for( k = length - 1; k >= 0; k-- ) {
+ out[k] = silk_SAT16( (opus_int32)float2int( in[k] ) );
+ }
+}
+
+/* integer to floating-point conversion */
+static OPUS_INLINE void silk_short2float_array(
+ silk_float *out,
+ const opus_int16 *in,
+ opus_int32 length
+)
+{
+ opus_int32 k;
+ for( k = length - 1; k >= 0; k-- ) {
+ out[k] = (silk_float)in[k];
+ }
+}
+
+/* using log2() helps the fixed-point conversion */
+static OPUS_INLINE silk_float silk_log2( double x )
+{
+ return ( silk_float )( 3.32192809488736 * log10( x ) );
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SILK_SIGPROC_FLP_H */
diff --git a/drivers/opus/silk/float/apply_sine_window_FLP.c b/drivers/opus/silk/float/apply_sine_window_FLP.c
new file mode 100644
index 0000000000..e8aa197bb0
--- /dev/null
+++ b/drivers/opus/silk/float/apply_sine_window_FLP.c
@@ -0,0 +1,81 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/float/main_FLP.h"
+
+/* Apply sine window to signal vector */
+/* Window types: */
+/* 1 -> sine window from 0 to pi/2 */
+/* 2 -> sine window from pi/2 to pi */
+void silk_apply_sine_window_FLP(
+ silk_float px_win[], /* O Pointer to windowed signal */
+ const silk_float px[], /* I Pointer to input signal */
+ const opus_int win_type, /* I Selects a window type */
+ const opus_int length /* I Window length, multiple of 4 */
+)
+{
+ opus_int k;
+ silk_float freq, c, S0, S1;
+
+ silk_assert( win_type == 1 || win_type == 2 );
+
+ /* Length must be multiple of 4 */
+ silk_assert( ( length & 3 ) == 0 );
+
+ freq = PI / ( length + 1 );
+
+ /* Approximation of 2 * cos(f) */
+ c = 2.0f - freq * freq;
+
+ /* Initialize state */
+ if( win_type < 2 ) {
+ /* Start from 0 */
+ S0 = 0.0f;
+ /* Approximation of sin(f) */
+ S1 = freq;
+ } else {
+ /* Start from 1 */
+ S0 = 1.0f;
+ /* Approximation of cos(f) */
+ S1 = 0.5f * c;
+ }
+
+ /* Uses the recursive equation: sin(n*f) = 2 * cos(f) * sin((n-1)*f) - sin((n-2)*f) */
+ /* 4 samples at a time */
+ for( k = 0; k < length; k += 4 ) {
+ px_win[ k + 0 ] = px[ k + 0 ] * 0.5f * ( S0 + S1 );
+ px_win[ k + 1 ] = px[ k + 1 ] * S1;
+ S0 = c * S1 - S0;
+ px_win[ k + 2 ] = px[ k + 2 ] * 0.5f * ( S1 + S0 );
+ px_win[ k + 3 ] = px[ k + 3 ] * S0;
+ S1 = c * S0 - S1;
+ }
+}
diff --git a/drivers/opus/silk/float/autocorrelation_FLP.c b/drivers/opus/silk/float/autocorrelation_FLP.c
new file mode 100644
index 0000000000..f4b90ff32d
--- /dev/null
+++ b/drivers/opus/silk/float/autocorrelation_FLP.c
@@ -0,0 +1,52 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/typedef.h"
+#include "opus/silk/float/SigProc_FLP.h"
+
+/* compute autocorrelation */
+void silk_autocorrelation_FLP(
+ silk_float *results, /* O result (length correlationCount) */
+ const silk_float *inputData, /* I input data to correlate */
+ opus_int inputDataSize, /* I length of input */
+ opus_int correlationCount /* I number of correlation taps to compute */
+)
+{
+ opus_int i;
+
+ if( correlationCount > inputDataSize ) {
+ correlationCount = inputDataSize;
+ }
+
+ for( i = 0; i < correlationCount; i++ ) {
+ results[ i ] = (silk_float)silk_inner_product_FLP( inputData, inputData + i, inputDataSize - i );
+ }
+}
diff --git a/drivers/opus/silk/float/burg_modified_FLP.c b/drivers/opus/silk/float/burg_modified_FLP.c
new file mode 100644
index 0000000000..5a16334240
--- /dev/null
+++ b/drivers/opus/silk/float/burg_modified_FLP.c
@@ -0,0 +1,186 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/float/SigProc_FLP.h"
+#include "opus/silk/tuning_parameters.h"
+#include "opus/silk/define.h"
+
+#define MAX_FRAME_SIZE 384 /* subfr_length * nb_subfr = ( 0.005 * 16000 + 16 ) * 4 = 384*/
+
+/* Compute reflection coefficients from input signal */
+silk_float silk_burg_modified_FLP( /* O returns residual energy */
+ silk_float A[], /* O prediction coefficients (length order) */
+ const silk_float x[], /* I input signal, length: nb_subfr*(D+L_sub) */
+ const silk_float minInvGain, /* I minimum inverse prediction gain */
+ const opus_int subfr_length, /* I input signal subframe length (incl. D preceding samples) */
+ const opus_int nb_subfr, /* I number of subframes stacked in x */
+ const opus_int D /* I order */
+)
+{
+ opus_int k, n, s, reached_max_gain;
+ double C0, invGain, num, nrg_f, nrg_b, rc, Atmp, tmp1, tmp2;
+ const silk_float *x_ptr;
+ double C_first_row[ SILK_MAX_ORDER_LPC ], C_last_row[ SILK_MAX_ORDER_LPC ];
+ double CAf[ SILK_MAX_ORDER_LPC + 1 ], CAb[ SILK_MAX_ORDER_LPC + 1 ];
+ double Af[ SILK_MAX_ORDER_LPC ];
+
+ silk_assert( subfr_length * nb_subfr <= MAX_FRAME_SIZE );
+
+ /* Compute autocorrelations, added over subframes */
+ C0 = silk_energy_FLP( x, nb_subfr * subfr_length );
+ silk_memset( C_first_row, 0, SILK_MAX_ORDER_LPC * sizeof( double ) );
+ for( s = 0; s < nb_subfr; s++ ) {
+ x_ptr = x + s * subfr_length;
+ for( n = 1; n < D + 1; n++ ) {
+ C_first_row[ n - 1 ] += silk_inner_product_FLP( x_ptr, x_ptr + n, subfr_length - n );
+ }
+ }
+ silk_memcpy( C_last_row, C_first_row, SILK_MAX_ORDER_LPC * sizeof( double ) );
+
+ /* Initialize */
+ CAb[ 0 ] = CAf[ 0 ] = C0 + FIND_LPC_COND_FAC * C0 + 1e-9f;
+ invGain = 1.0f;
+ reached_max_gain = 0;
+ for( n = 0; n < D; n++ ) {
+ /* Update first row of correlation matrix (without first element) */
+ /* Update last row of correlation matrix (without last element, stored in reversed order) */
+ /* Update C * Af */
+ /* Update C * flipud(Af) (stored in reversed order) */
+ for( s = 0; s < nb_subfr; s++ ) {
+ x_ptr = x + s * subfr_length;
+ tmp1 = x_ptr[ n ];
+ tmp2 = x_ptr[ subfr_length - n - 1 ];
+ for( k = 0; k < n; k++ ) {
+ C_first_row[ k ] -= x_ptr[ n ] * x_ptr[ n - k - 1 ];
+ C_last_row[ k ] -= x_ptr[ subfr_length - n - 1 ] * x_ptr[ subfr_length - n + k ];
+ Atmp = Af[ k ];
+ tmp1 += x_ptr[ n - k - 1 ] * Atmp;
+ tmp2 += x_ptr[ subfr_length - n + k ] * Atmp;
+ }
+ for( k = 0; k <= n; k++ ) {
+ CAf[ k ] -= tmp1 * x_ptr[ n - k ];
+ CAb[ k ] -= tmp2 * x_ptr[ subfr_length - n + k - 1 ];
+ }
+ }
+ tmp1 = C_first_row[ n ];
+ tmp2 = C_last_row[ n ];
+ for( k = 0; k < n; k++ ) {
+ Atmp = Af[ k ];
+ tmp1 += C_last_row[ n - k - 1 ] * Atmp;
+ tmp2 += C_first_row[ n - k - 1 ] * Atmp;
+ }
+ CAf[ n + 1 ] = tmp1;
+ CAb[ n + 1 ] = tmp2;
+
+ /* Calculate nominator and denominator for the next order reflection (parcor) coefficient */
+ num = CAb[ n + 1 ];
+ nrg_b = CAb[ 0 ];
+ nrg_f = CAf[ 0 ];
+ for( k = 0; k < n; k++ ) {
+ Atmp = Af[ k ];
+ num += CAb[ n - k ] * Atmp;
+ nrg_b += CAb[ k + 1 ] * Atmp;
+ nrg_f += CAf[ k + 1 ] * Atmp;
+ }
+ silk_assert( nrg_f > 0.0 );
+ silk_assert( nrg_b > 0.0 );
+
+ /* Calculate the next order reflection (parcor) coefficient */
+ rc = -2.0 * num / ( nrg_f + nrg_b );
+ silk_assert( rc > -1.0 && rc < 1.0 );
+
+ /* Update inverse prediction gain */
+ tmp1 = invGain * ( 1.0 - rc * rc );
+ if( tmp1 <= minInvGain ) {
+ /* Max prediction gain exceeded; set reflection coefficient such that max prediction gain is exactly hit */
+ rc = sqrt( 1.0 - minInvGain / invGain );
+ if( num > 0 ) {
+ /* Ensure adjusted reflection coefficients has the original sign */
+ rc = -rc;
+ }
+ invGain = minInvGain;
+ reached_max_gain = 1;
+ } else {
+ invGain = tmp1;
+ }
+
+ /* Update the AR coefficients */
+ for( k = 0; k < (n + 1) >> 1; k++ ) {
+ tmp1 = Af[ k ];
+ tmp2 = Af[ n - k - 1 ];
+ Af[ k ] = tmp1 + rc * tmp2;
+ Af[ n - k - 1 ] = tmp2 + rc * tmp1;
+ }
+ Af[ n ] = rc;
+
+ if( reached_max_gain ) {
+ /* Reached max prediction gain; set remaining coefficients to zero and exit loop */
+ for( k = n + 1; k < D; k++ ) {
+ Af[ k ] = 0.0;
+ }
+ break;
+ }
+
+ /* Update C * Af and C * Ab */
+ for( k = 0; k <= n + 1; k++ ) {
+ tmp1 = CAf[ k ];
+ CAf[ k ] += rc * CAb[ n - k + 1 ];
+ CAb[ n - k + 1 ] += rc * tmp1;
+ }
+ }
+
+ if( reached_max_gain ) {
+ /* Convert to silk_float */
+ for( k = 0; k < D; k++ ) {
+ A[ k ] = (silk_float)( -Af[ k ] );
+ }
+ /* Subtract energy of preceding samples from C0 */
+ for( s = 0; s < nb_subfr; s++ ) {
+ C0 -= silk_energy_FLP( x + s * subfr_length, D );
+ }
+ /* Approximate residual energy */
+ nrg_f = C0 * invGain;
+ } else {
+ /* Compute residual energy and store coefficients as silk_float */
+ nrg_f = CAf[ 0 ];
+ tmp1 = 1.0;
+ for( k = 0; k < D; k++ ) {
+ Atmp = Af[ k ];
+ nrg_f += CAf[ k + 1 ] * Atmp;
+ tmp1 += Atmp * Atmp;
+ A[ k ] = (silk_float)(-Atmp);
+ }
+ nrg_f -= FIND_LPC_COND_FAC * C0 * tmp1;
+ }
+
+ /* Return residual energy */
+ return (silk_float)nrg_f;
+}
diff --git a/drivers/opus/silk/float/bwexpander_FLP.c b/drivers/opus/silk/float/bwexpander_FLP.c
new file mode 100644
index 0000000000..b3de4f6453
--- /dev/null
+++ b/drivers/opus/silk/float/bwexpander_FLP.c
@@ -0,0 +1,49 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/float/SigProc_FLP.h"
+
+/* Chirp (bw expand) LP AR filter */
+void silk_bwexpander_FLP(
+ silk_float *ar, /* I/O AR filter to be expanded (without leading 1) */
+ const opus_int d, /* I length of ar */
+ const silk_float chirp /* I chirp factor (typically in range (0..1) ) */
+)
+{
+ opus_int i;
+ silk_float cfac = chirp;
+
+ for( i = 0; i < d - 1; i++ ) {
+ ar[ i ] *= cfac;
+ cfac *= chirp;
+ }
+ ar[ d - 1 ] *= cfac;
+}
diff --git a/drivers/opus/silk/float/corrMatrix_FLP.c b/drivers/opus/silk/float/corrMatrix_FLP.c
new file mode 100644
index 0000000000..551f8578d7
--- /dev/null
+++ b/drivers/opus/silk/float/corrMatrix_FLP.c
@@ -0,0 +1,93 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+/**********************************************************************
+ * Correlation matrix computations for LS estimate.
+ **********************************************************************/
+
+#include "opus/silk/float/main_FLP.h"
+
+/* Calculates correlation vector X'*t */
+void silk_corrVector_FLP(
+ const silk_float *x, /* I x vector [L+order-1] used to create X */
+ const silk_float *t, /* I Target vector [L] */
+ const opus_int L, /* I Length of vecors */
+ const opus_int Order, /* I Max lag for correlation */
+ silk_float *Xt /* O X'*t correlation vector [order] */
+)
+{
+ opus_int lag;
+ const silk_float *ptr1;
+
+ ptr1 = &x[ Order - 1 ]; /* Points to first sample of column 0 of X: X[:,0] */
+ for( lag = 0; lag < Order; lag++ ) {
+ /* Calculate X[:,lag]'*t */
+ Xt[ lag ] = (silk_float)silk_inner_product_FLP( ptr1, t, L );
+ ptr1--; /* Next column of X */
+ }
+}
+
+/* Calculates correlation matrix X'*X */
+void silk_corrMatrix_FLP(
+ const silk_float *x, /* I x vector [ L+order-1 ] used to create X */
+ const opus_int L, /* I Length of vectors */
+ const opus_int Order, /* I Max lag for correlation */
+ silk_float *XX /* O X'*X correlation matrix [order x order] */
+)
+{
+ opus_int j, lag;
+ double energy;
+ const silk_float *ptr1, *ptr2;
+
+ ptr1 = &x[ Order - 1 ]; /* First sample of column 0 of X */
+ energy = silk_energy_FLP( ptr1, L ); /* X[:,0]'*X[:,0] */
+ matrix_ptr( XX, 0, 0, Order ) = ( silk_float )energy;
+ for( j = 1; j < Order; j++ ) {
+ /* Calculate X[:,j]'*X[:,j] */
+ energy += ptr1[ -j ] * ptr1[ -j ] - ptr1[ L - j ] * ptr1[ L - j ];
+ matrix_ptr( XX, j, j, Order ) = ( silk_float )energy;
+ }
+
+ ptr2 = &x[ Order - 2 ]; /* First sample of column 1 of X */
+ for( lag = 1; lag < Order; lag++ ) {
+ /* Calculate X[:,0]'*X[:,lag] */
+ energy = silk_inner_product_FLP( ptr1, ptr2, L );
+ matrix_ptr( XX, lag, 0, Order ) = ( silk_float )energy;
+ matrix_ptr( XX, 0, lag, Order ) = ( silk_float )energy;
+ /* Calculate X[:,j]'*X[:,j + lag] */
+ for( j = 1; j < ( Order - lag ); j++ ) {
+ energy += ptr1[ -j ] * ptr2[ -j ] - ptr1[ L - j ] * ptr2[ L - j ];
+ matrix_ptr( XX, lag + j, j, Order ) = ( silk_float )energy;
+ matrix_ptr( XX, j, lag + j, Order ) = ( silk_float )energy;
+ }
+ ptr2--; /* Next column of X */
+ }
+}
diff --git a/drivers/opus/silk/float/encode_frame_FLP.c b/drivers/opus/silk/float/encode_frame_FLP.c
new file mode 100644
index 0000000000..c5973b8922
--- /dev/null
+++ b/drivers/opus/silk/float/encode_frame_FLP.c
@@ -0,0 +1,372 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/float/main_FLP.h"
+#include "opus/silk/tuning_parameters.h"
+
+/* Low Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode with lower bitrate */
+static OPUS_INLINE void silk_LBRR_encode_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ const silk_float xfw[], /* I Input signal */
+ opus_int condCoding /* I The type of conditional coding used so far for this frame */
+);
+
+void silk_encode_do_VAD_FLP(
+ silk_encoder_state_FLP *psEnc /* I/O Encoder state FLP */
+)
+{
+ /****************************/
+ /* Voice Activity Detection */
+ /****************************/
+ silk_VAD_GetSA_Q8( &psEnc->sCmn, psEnc->sCmn.inputBuf + 1 );
+
+ /**************************************************/
+ /* Convert speech activity into VAD and DTX flags */
+ /**************************************************/
+ if( psEnc->sCmn.speech_activity_Q8 < SILK_FIX_CONST( SPEECH_ACTIVITY_DTX_THRES, 8 ) ) {
+ psEnc->sCmn.indices.signalType = TYPE_NO_VOICE_ACTIVITY;
+ psEnc->sCmn.noSpeechCounter++;
+ if( psEnc->sCmn.noSpeechCounter < NB_SPEECH_FRAMES_BEFORE_DTX ) {
+ psEnc->sCmn.inDTX = 0;
+ } else if( psEnc->sCmn.noSpeechCounter > MAX_CONSECUTIVE_DTX + NB_SPEECH_FRAMES_BEFORE_DTX ) {
+ psEnc->sCmn.noSpeechCounter = NB_SPEECH_FRAMES_BEFORE_DTX;
+ psEnc->sCmn.inDTX = 0;
+ }
+ psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 0;
+ } else {
+ psEnc->sCmn.noSpeechCounter = 0;
+ psEnc->sCmn.inDTX = 0;
+ psEnc->sCmn.indices.signalType = TYPE_UNVOICED;
+ psEnc->sCmn.VAD_flags[ psEnc->sCmn.nFramesEncoded ] = 1;
+ }
+}
+
+/****************/
+/* Encode frame */
+/****************/
+opus_int silk_encode_frame_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ opus_int32 *pnBytesOut, /* O Number of payload bytes; */
+ ec_enc *psRangeEnc, /* I/O compressor data structure */
+ opus_int condCoding, /* I The type of conditional coding to use */
+ opus_int maxBits, /* I If > 0: maximum number of output bits */
+ opus_int useCBR /* I Flag to force constant-bitrate operation */
+)
+{
+ silk_encoder_control_FLP sEncCtrl;
+ opus_int i, iter, maxIter, found_upper, found_lower, ret = 0;
+ silk_float *x_frame, *res_pitch_frame;
+ silk_float xfw[ MAX_FRAME_LENGTH ];
+ silk_float res_pitch[ 2 * MAX_FRAME_LENGTH + LA_PITCH_MAX ];
+ ec_enc sRangeEnc_copy, sRangeEnc_copy2;
+ silk_nsq_state sNSQ_copy, sNSQ_copy2;
+ opus_int32 seed_copy, nBits, nBits_lower, nBits_upper, gainMult_lower, gainMult_upper;
+ opus_int32 gainsID, gainsID_lower, gainsID_upper;
+ opus_int16 gainMult_Q8;
+ opus_int16 ec_prevLagIndex_copy;
+ opus_int ec_prevSignalType_copy;
+ opus_int8 LastGainIndex_copy2;
+ opus_int32 pGains_Q16[ MAX_NB_SUBFR ];
+ opus_uint8 ec_buf_copy[ 1275 ];
+
+ /* This is totally unnecessary but many compilers (including gcc) are too dumb to realise it */
+ LastGainIndex_copy2 = nBits_lower = nBits_upper = gainMult_lower = gainMult_upper = 0;
+
+ psEnc->sCmn.indices.Seed = psEnc->sCmn.frameCounter++ & 3;
+
+ /**************************************************************/
+ /* Set up Input Pointers, and insert frame in input buffer */
+ /**************************************************************/
+ /* pointers aligned with start of frame to encode */
+ x_frame = psEnc->x_buf + psEnc->sCmn.ltp_mem_length; /* start of frame to encode */
+ res_pitch_frame = res_pitch + psEnc->sCmn.ltp_mem_length; /* start of pitch LPC residual frame */
+
+ /***************************************/
+ /* Ensure smooth bandwidth transitions */
+ /***************************************/
+ silk_LP_variable_cutoff( &psEnc->sCmn.sLP, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length );
+
+ /*******************************************/
+ /* Copy new frame to front of input buffer */
+ /*******************************************/
+ silk_short2float_array( x_frame + LA_SHAPE_MS * psEnc->sCmn.fs_kHz, psEnc->sCmn.inputBuf + 1, psEnc->sCmn.frame_length );
+
+ /* Add tiny signal to avoid high CPU load from denormalized floating point numbers */
+ for( i = 0; i < 8; i++ ) {
+ x_frame[ LA_SHAPE_MS * psEnc->sCmn.fs_kHz + i * ( psEnc->sCmn.frame_length >> 3 ) ] += ( 1 - ( i & 2 ) ) * 1e-6f;
+ }
+
+ if( !psEnc->sCmn.prefillFlag ) {
+ /*****************************************/
+ /* Find pitch lags, initial LPC analysis */
+ /*****************************************/
+ silk_find_pitch_lags_FLP( psEnc, &sEncCtrl, res_pitch, x_frame, psEnc->sCmn.arch );
+
+ /************************/
+ /* Noise shape analysis */
+ /************************/
+ silk_noise_shape_analysis_FLP( psEnc, &sEncCtrl, res_pitch_frame, x_frame );
+
+ /***************************************************/
+ /* Find linear prediction coefficients (LPC + LTP) */
+ /***************************************************/
+ silk_find_pred_coefs_FLP( psEnc, &sEncCtrl, res_pitch, x_frame, condCoding );
+
+ /****************************************/
+ /* Process gains */
+ /****************************************/
+ silk_process_gains_FLP( psEnc, &sEncCtrl, condCoding );
+
+ /*****************************************/
+ /* Prefiltering for noise shaper */
+ /*****************************************/
+ silk_prefilter_FLP( psEnc, &sEncCtrl, xfw, x_frame );
+
+ /****************************************/
+ /* Low Bitrate Redundant Encoding */
+ /****************************************/
+ silk_LBRR_encode_FLP( psEnc, &sEncCtrl, xfw, condCoding );
+
+ /* Loop over quantizer and entroy coding to control bitrate */
+ maxIter = 6;
+ gainMult_Q8 = SILK_FIX_CONST( 1, 8 );
+ found_lower = 0;
+ found_upper = 0;
+ gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr );
+ gainsID_lower = -1;
+ gainsID_upper = -1;
+ /* Copy part of the input state */
+ silk_memcpy( &sRangeEnc_copy, psRangeEnc, sizeof( ec_enc ) );
+ silk_memcpy( &sNSQ_copy, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
+ seed_copy = psEnc->sCmn.indices.Seed;
+ ec_prevLagIndex_copy = psEnc->sCmn.ec_prevLagIndex;
+ ec_prevSignalType_copy = psEnc->sCmn.ec_prevSignalType;
+ for( iter = 0; ; iter++ ) {
+ if( gainsID == gainsID_lower ) {
+ nBits = nBits_lower;
+ } else if( gainsID == gainsID_upper ) {
+ nBits = nBits_upper;
+ } else {
+ /* Restore part of the input state */
+ if( iter > 0 ) {
+ silk_memcpy( psRangeEnc, &sRangeEnc_copy, sizeof( ec_enc ) );
+ silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy, sizeof( silk_nsq_state ) );
+ psEnc->sCmn.indices.Seed = seed_copy;
+ psEnc->sCmn.ec_prevLagIndex = ec_prevLagIndex_copy;
+ psEnc->sCmn.ec_prevSignalType = ec_prevSignalType_copy;
+ }
+
+ /*****************************************/
+ /* Noise shaping quantization */
+ /*****************************************/
+ silk_NSQ_wrapper_FLP( psEnc, &sEncCtrl, &psEnc->sCmn.indices, &psEnc->sCmn.sNSQ, psEnc->sCmn.pulses, xfw );
+
+ /****************************************/
+ /* Encode Parameters */
+ /****************************************/
+ silk_encode_indices( &psEnc->sCmn, psRangeEnc, psEnc->sCmn.nFramesEncoded, 0, condCoding );
+
+ /****************************************/
+ /* Encode Excitation Signal */
+ /****************************************/
+ silk_encode_pulses( psRangeEnc, psEnc->sCmn.indices.signalType, psEnc->sCmn.indices.quantOffsetType,
+ psEnc->sCmn.pulses, psEnc->sCmn.frame_length );
+
+ nBits = ec_tell( psRangeEnc );
+
+ if( useCBR == 0 && iter == 0 && nBits <= maxBits ) {
+ break;
+ }
+ }
+
+ if( iter == maxIter ) {
+ if( found_lower && ( gainsID == gainsID_lower || nBits > maxBits ) ) {
+ /* Restore output state from earlier iteration that did meet the bitrate budget */
+ silk_memcpy( psRangeEnc, &sRangeEnc_copy2, sizeof( ec_enc ) );
+ silk_assert( sRangeEnc_copy2.offs <= 1275 );
+ silk_memcpy( psRangeEnc->buf, ec_buf_copy, sRangeEnc_copy2.offs );
+ silk_memcpy( &psEnc->sCmn.sNSQ, &sNSQ_copy2, sizeof( silk_nsq_state ) );
+ psEnc->sShape.LastGainIndex = LastGainIndex_copy2;
+ }
+ break;
+ }
+
+ if( nBits > maxBits ) {
+ if( found_lower == 0 && iter >= 2 ) {
+ /* Adjust the quantizer's rate/distortion tradeoff and discard previous "upper" results */
+ sEncCtrl.Lambda *= 1.5f;
+ found_upper = 0;
+ gainsID_upper = -1;
+ } else {
+ found_upper = 1;
+ nBits_upper = nBits;
+ gainMult_upper = gainMult_Q8;
+ gainsID_upper = gainsID;
+ }
+ } else if( nBits < maxBits - 5 ) {
+ found_lower = 1;
+ nBits_lower = nBits;
+ gainMult_lower = gainMult_Q8;
+ if( gainsID != gainsID_lower ) {
+ gainsID_lower = gainsID;
+ /* Copy part of the output state */
+ silk_memcpy( &sRangeEnc_copy2, psRangeEnc, sizeof( ec_enc ) );
+ silk_assert( psRangeEnc->offs <= 1275 );
+ silk_memcpy( ec_buf_copy, psRangeEnc->buf, psRangeEnc->offs );
+ silk_memcpy( &sNSQ_copy2, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
+ LastGainIndex_copy2 = psEnc->sShape.LastGainIndex;
+ }
+ } else {
+ /* Within 5 bits of budget: close enough */
+ break;
+ }
+
+ if( ( found_lower & found_upper ) == 0 ) {
+ /* Adjust gain according to high-rate rate/distortion curve */
+ opus_int32 gain_factor_Q16;
+ gain_factor_Q16 = silk_log2lin( silk_LSHIFT( nBits - maxBits, 7 ) / psEnc->sCmn.frame_length + SILK_FIX_CONST( 16, 7 ) );
+ gain_factor_Q16 = silk_min_32( gain_factor_Q16, SILK_FIX_CONST( 2, 16 ) );
+ if( nBits > maxBits ) {
+ gain_factor_Q16 = silk_max_32( gain_factor_Q16, SILK_FIX_CONST( 1.3, 16 ) );
+ }
+ gainMult_Q8 = silk_SMULWB( gain_factor_Q16, gainMult_Q8 );
+ } else {
+ /* Adjust gain by interpolating */
+ gainMult_Q8 = gainMult_lower + ( ( gainMult_upper - gainMult_lower ) * ( maxBits - nBits_lower ) ) / ( nBits_upper - nBits_lower );
+ /* New gain multplier must be between 25% and 75% of old range (note that gainMult_upper < gainMult_lower) */
+ if( gainMult_Q8 > silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 ) ) {
+ gainMult_Q8 = silk_ADD_RSHIFT32( gainMult_lower, gainMult_upper - gainMult_lower, 2 );
+ } else
+ if( gainMult_Q8 < silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 ) ) {
+ gainMult_Q8 = silk_SUB_RSHIFT32( gainMult_upper, gainMult_upper - gainMult_lower, 2 );
+ }
+ }
+
+ for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ pGains_Q16[ i ] = silk_LSHIFT_SAT32( silk_SMULWB( sEncCtrl.GainsUnq_Q16[ i ], gainMult_Q8 ), 8 );
+ }
+
+ /* Quantize gains */
+ psEnc->sShape.LastGainIndex = sEncCtrl.lastGainIndexPrev;
+ silk_gains_quant( psEnc->sCmn.indices.GainsIndices, pGains_Q16,
+ &psEnc->sShape.LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
+
+ /* Unique identifier of gains vector */
+ gainsID = silk_gains_ID( psEnc->sCmn.indices.GainsIndices, psEnc->sCmn.nb_subfr );
+
+ /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */
+ for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ sEncCtrl.Gains[ i ] = pGains_Q16[ i ] / 65536.0f;
+ }
+ }
+ }
+
+ /* Update input buffer */
+ silk_memmove( psEnc->x_buf, &psEnc->x_buf[ psEnc->sCmn.frame_length ],
+ ( psEnc->sCmn.ltp_mem_length + LA_SHAPE_MS * psEnc->sCmn.fs_kHz ) * sizeof( silk_float ) );
+
+ /* Exit without entropy coding */
+ if( psEnc->sCmn.prefillFlag ) {
+ /* No payload */
+ *pnBytesOut = 0;
+ return ret;
+ }
+
+ /* Parameters needed for next frame */
+ psEnc->sCmn.prevLag = sEncCtrl.pitchL[ psEnc->sCmn.nb_subfr - 1 ];
+ psEnc->sCmn.prevSignalType = psEnc->sCmn.indices.signalType;
+
+ /****************************************/
+ /* Finalize payload */
+ /****************************************/
+ psEnc->sCmn.first_frame_after_reset = 0;
+ /* Payload size */
+ *pnBytesOut = silk_RSHIFT( ec_tell( psRangeEnc ) + 7, 3 );
+
+ return ret;
+}
+
+/* Low-Bitrate Redundancy (LBRR) encoding. Reuse all parameters but encode excitation at lower bitrate */
+static OPUS_INLINE void silk_LBRR_encode_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ const silk_float xfw[], /* I Input signal */
+ opus_int condCoding /* I The type of conditional coding used so far for this frame */
+)
+{
+ opus_int k;
+ opus_int32 Gains_Q16[ MAX_NB_SUBFR ];
+ silk_float TempGains[ MAX_NB_SUBFR ];
+ SideInfoIndices *psIndices_LBRR = &psEnc->sCmn.indices_LBRR[ psEnc->sCmn.nFramesEncoded ];
+ silk_nsq_state sNSQ_LBRR;
+
+ /*******************************************/
+ /* Control use of inband LBRR */
+ /*******************************************/
+ if( psEnc->sCmn.LBRR_enabled && psEnc->sCmn.speech_activity_Q8 > SILK_FIX_CONST( LBRR_SPEECH_ACTIVITY_THRES, 8 ) ) {
+ psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded ] = 1;
+
+ /* Copy noise shaping quantizer state and quantization indices from regular encoding */
+ silk_memcpy( &sNSQ_LBRR, &psEnc->sCmn.sNSQ, sizeof( silk_nsq_state ) );
+ silk_memcpy( psIndices_LBRR, &psEnc->sCmn.indices, sizeof( SideInfoIndices ) );
+
+ /* Save original gains */
+ silk_memcpy( TempGains, psEncCtrl->Gains, psEnc->sCmn.nb_subfr * sizeof( silk_float ) );
+
+ if( psEnc->sCmn.nFramesEncoded == 0 || psEnc->sCmn.LBRR_flags[ psEnc->sCmn.nFramesEncoded - 1 ] == 0 ) {
+ /* First frame in packet or previous frame not LBRR coded */
+ psEnc->sCmn.LBRRprevLastGainIndex = psEnc->sShape.LastGainIndex;
+
+ /* Increase Gains to get target LBRR rate */
+ psIndices_LBRR->GainsIndices[ 0 ] += psEnc->sCmn.LBRR_GainIncreases;
+ psIndices_LBRR->GainsIndices[ 0 ] = silk_min_int( psIndices_LBRR->GainsIndices[ 0 ], N_LEVELS_QGAIN - 1 );
+ }
+
+ /* Decode to get gains in sync with decoder */
+ silk_gains_dequant( Gains_Q16, psIndices_LBRR->GainsIndices,
+ &psEnc->sCmn.LBRRprevLastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
+
+ /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ psEncCtrl->Gains[ k ] = Gains_Q16[ k ] * ( 1.0f / 65536.0f );
+ }
+
+ /*****************************************/
+ /* Noise shaping quantization */
+ /*****************************************/
+ silk_NSQ_wrapper_FLP( psEnc, psEncCtrl, psIndices_LBRR, &sNSQ_LBRR,
+ psEnc->sCmn.pulses_LBRR[ psEnc->sCmn.nFramesEncoded ], xfw );
+
+ /* Restore original gains */
+ silk_memcpy( psEncCtrl->Gains, TempGains, psEnc->sCmn.nb_subfr * sizeof( silk_float ) );
+ }
+}
diff --git a/drivers/opus/silk/float/energy_FLP.c b/drivers/opus/silk/float/energy_FLP.c
new file mode 100644
index 0000000000..9c6fad48d7
--- /dev/null
+++ b/drivers/opus/silk/float/energy_FLP.c
@@ -0,0 +1,60 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/float/SigProc_FLP.h"
+
+/* sum of squares of a silk_float array, with result as double */
+double silk_energy_FLP(
+ const silk_float *data,
+ opus_int dataSize
+)
+{
+ opus_int i, dataSize4;
+ double result;
+
+ /* 4x unrolled loop */
+ result = 0.0;
+ dataSize4 = dataSize & 0xFFFC;
+ for( i = 0; i < dataSize4; i += 4 ) {
+ result += data[ i + 0 ] * (double)data[ i + 0 ] +
+ data[ i + 1 ] * (double)data[ i + 1 ] +
+ data[ i + 2 ] * (double)data[ i + 2 ] +
+ data[ i + 3 ] * (double)data[ i + 3 ];
+ }
+
+ /* add any remaining products */
+ for( ; i < dataSize; i++ ) {
+ result += data[ i ] * (double)data[ i ];
+ }
+
+ silk_assert( result >= 0.0 );
+ return result;
+}
diff --git a/drivers/opus/silk/float/find_LPC_FLP.c b/drivers/opus/silk/float/find_LPC_FLP.c
new file mode 100644
index 0000000000..2b8c54388f
--- /dev/null
+++ b/drivers/opus/silk/float/find_LPC_FLP.c
@@ -0,0 +1,104 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/define.h"
+#include "opus/silk/float/main_FLP.h"
+#include "opus/silk/tuning_parameters.h"
+
+/* LPC analysis */
+void silk_find_LPC_FLP(
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ opus_int16 NLSF_Q15[], /* O NLSFs */
+ const silk_float x[], /* I Input signal */
+ const silk_float minInvGain /* I Inverse of max prediction gain */
+)
+{
+ opus_int k, subfr_length;
+ silk_float a[ MAX_LPC_ORDER ];
+
+ /* Used only for NLSF interpolation */
+ silk_float res_nrg, res_nrg_2nd, res_nrg_interp;
+ opus_int16 NLSF0_Q15[ MAX_LPC_ORDER ];
+ silk_float a_tmp[ MAX_LPC_ORDER ];
+ silk_float LPC_res[ MAX_FRAME_LENGTH + MAX_NB_SUBFR * MAX_LPC_ORDER ];
+
+ subfr_length = psEncC->subfr_length + psEncC->predictLPCOrder;
+
+ /* Default: No interpolation */
+ psEncC->indices.NLSFInterpCoef_Q2 = 4;
+
+ /* Burg AR analysis for the full frame */
+ res_nrg = silk_burg_modified_FLP( a, x, minInvGain, subfr_length, psEncC->nb_subfr, psEncC->predictLPCOrder );
+
+ if( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) {
+ /* Optimal solution for last 10 ms; subtract residual energy here, as that's easier than */
+ /* adding it to the residual energy of the first 10 ms in each iteration of the search below */
+ res_nrg -= silk_burg_modified_FLP( a_tmp, x + ( MAX_NB_SUBFR / 2 ) * subfr_length, minInvGain, subfr_length, MAX_NB_SUBFR / 2, psEncC->predictLPCOrder );
+
+ /* Convert to NLSFs */
+ silk_A2NLSF_FLP( NLSF_Q15, a_tmp, psEncC->predictLPCOrder );
+
+ /* Search over interpolation indices to find the one with lowest residual energy */
+ res_nrg_2nd = silk_float_MAX;
+ for( k = 3; k >= 0; k-- ) {
+ /* Interpolate NLSFs for first half */
+ silk_interpolate( NLSF0_Q15, psEncC->prev_NLSFq_Q15, NLSF_Q15, k, psEncC->predictLPCOrder );
+
+ /* Convert to LPC for residual energy evaluation */
+ silk_NLSF2A_FLP( a_tmp, NLSF0_Q15, psEncC->predictLPCOrder );
+
+ /* Calculate residual energy with LSF interpolation */
+ silk_LPC_analysis_filter_FLP( LPC_res, a_tmp, x, 2 * subfr_length, psEncC->predictLPCOrder );
+ res_nrg_interp = (silk_float)(
+ silk_energy_FLP( LPC_res + psEncC->predictLPCOrder, subfr_length - psEncC->predictLPCOrder ) +
+ silk_energy_FLP( LPC_res + psEncC->predictLPCOrder + subfr_length, subfr_length - psEncC->predictLPCOrder ) );
+
+ /* Determine whether current interpolated NLSFs are best so far */
+ if( res_nrg_interp < res_nrg ) {
+ /* Interpolation has lower residual energy */
+ res_nrg = res_nrg_interp;
+ psEncC->indices.NLSFInterpCoef_Q2 = (opus_int8)k;
+ } else if( res_nrg_interp > res_nrg_2nd ) {
+ /* No reason to continue iterating - residual energies will continue to climb */
+ break;
+ }
+ res_nrg_2nd = res_nrg_interp;
+ }
+ }
+
+ if( psEncC->indices.NLSFInterpCoef_Q2 == 4 ) {
+ /* NLSF interpolation is currently inactive, calculate NLSFs from full frame AR coefficients */
+ silk_A2NLSF_FLP( NLSF_Q15, a, psEncC->predictLPCOrder );
+ }
+
+ silk_assert( psEncC->indices.NLSFInterpCoef_Q2 == 4 ||
+ ( psEncC->useInterpolatedNLSFs && !psEncC->first_frame_after_reset && psEncC->nb_subfr == MAX_NB_SUBFR ) );
+}
diff --git a/drivers/opus/silk/float/find_LTP_FLP.c b/drivers/opus/silk/float/find_LTP_FLP.c
new file mode 100644
index 0000000000..2f66de4684
--- /dev/null
+++ b/drivers/opus/silk/float/find_LTP_FLP.c
@@ -0,0 +1,132 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/float/main_FLP.h"
+#include "opus/silk/tuning_parameters.h"
+
+void silk_find_LTP_FLP(
+ silk_float b[ MAX_NB_SUBFR * LTP_ORDER ], /* O LTP coefs */
+ silk_float WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */
+ silk_float *LTPredCodGain, /* O LTP coding gain */
+ const silk_float r_lpc[], /* I LPC residual */
+ const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */
+ const silk_float Wght[ MAX_NB_SUBFR ], /* I Weights */
+ const opus_int subfr_length, /* I Subframe length */
+ const opus_int nb_subfr, /* I number of subframes */
+ const opus_int mem_offset /* I Number of samples in LTP memory */
+)
+{
+ opus_int i, k;
+ silk_float *b_ptr, temp, *WLTP_ptr;
+ silk_float LPC_res_nrg, LPC_LTP_res_nrg;
+ silk_float d[ MAX_NB_SUBFR ], m, g, delta_b[ LTP_ORDER ];
+ silk_float w[ MAX_NB_SUBFR ], nrg[ MAX_NB_SUBFR ], regu;
+ silk_float Rr[ LTP_ORDER ], rr[ MAX_NB_SUBFR ];
+ const silk_float *r_ptr, *lag_ptr;
+
+ b_ptr = b;
+ WLTP_ptr = WLTP;
+ r_ptr = &r_lpc[ mem_offset ];
+ for( k = 0; k < nb_subfr; k++ ) {
+ lag_ptr = r_ptr - ( lag[ k ] + LTP_ORDER / 2 );
+
+ silk_corrMatrix_FLP( lag_ptr, subfr_length, LTP_ORDER, WLTP_ptr );
+ silk_corrVector_FLP( lag_ptr, r_ptr, subfr_length, LTP_ORDER, Rr );
+
+ rr[ k ] = ( silk_float )silk_energy_FLP( r_ptr, subfr_length );
+ regu = 1.0f + rr[ k ] +
+ matrix_ptr( WLTP_ptr, 0, 0, LTP_ORDER ) +
+ matrix_ptr( WLTP_ptr, LTP_ORDER-1, LTP_ORDER-1, LTP_ORDER );
+ regu *= LTP_DAMPING / 3;
+ silk_regularize_correlations_FLP( WLTP_ptr, &rr[ k ], regu, LTP_ORDER );
+ silk_solve_LDL_FLP( WLTP_ptr, LTP_ORDER, Rr, b_ptr );
+
+ /* Calculate residual energy */
+ nrg[ k ] = silk_residual_energy_covar_FLP( b_ptr, WLTP_ptr, Rr, rr[ k ], LTP_ORDER );
+
+ temp = Wght[ k ] / ( nrg[ k ] * Wght[ k ] + 0.01f * subfr_length );
+ silk_scale_vector_FLP( WLTP_ptr, temp, LTP_ORDER * LTP_ORDER );
+ w[ k ] = matrix_ptr( WLTP_ptr, LTP_ORDER / 2, LTP_ORDER / 2, LTP_ORDER );
+
+ r_ptr += subfr_length;
+ b_ptr += LTP_ORDER;
+ WLTP_ptr += LTP_ORDER * LTP_ORDER;
+ }
+
+ /* Compute LTP coding gain */
+ if( LTPredCodGain != NULL ) {
+ LPC_LTP_res_nrg = 1e-6f;
+ LPC_res_nrg = 0.0f;
+ for( k = 0; k < nb_subfr; k++ ) {
+ LPC_res_nrg += rr[ k ] * Wght[ k ];
+ LPC_LTP_res_nrg += nrg[ k ] * Wght[ k ];
+ }
+
+ silk_assert( LPC_LTP_res_nrg > 0 );
+ *LTPredCodGain = 3.0f * silk_log2( LPC_res_nrg / LPC_LTP_res_nrg );
+ }
+
+ /* Smoothing */
+ /* d = sum( B, 1 ); */
+ b_ptr = b;
+ for( k = 0; k < nb_subfr; k++ ) {
+ d[ k ] = 0;
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ d[ k ] += b_ptr[ i ];
+ }
+ b_ptr += LTP_ORDER;
+ }
+ /* m = ( w * d' ) / ( sum( w ) + 1e-3 ); */
+ temp = 1e-3f;
+ for( k = 0; k < nb_subfr; k++ ) {
+ temp += w[ k ];
+ }
+ m = 0;
+ for( k = 0; k < nb_subfr; k++ ) {
+ m += d[ k ] * w[ k ];
+ }
+ m = m / temp;
+
+ b_ptr = b;
+ for( k = 0; k < nb_subfr; k++ ) {
+ g = LTP_SMOOTHING / ( LTP_SMOOTHING + w[ k ] ) * ( m - d[ k ] );
+ temp = 0;
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ delta_b[ i ] = silk_max_float( b_ptr[ i ], 0.1f );
+ temp += delta_b[ i ];
+ }
+ temp = g / temp;
+ for( i = 0; i < LTP_ORDER; i++ ) {
+ b_ptr[ i ] = b_ptr[ i ] + delta_b[ i ] * temp;
+ }
+ b_ptr += LTP_ORDER;
+ }
+}
diff --git a/drivers/opus/silk/float/find_pitch_lags_FLP.c b/drivers/opus/silk/float/find_pitch_lags_FLP.c
new file mode 100644
index 0000000000..a2d582c734
--- /dev/null
+++ b/drivers/opus/silk/float/find_pitch_lags_FLP.c
@@ -0,0 +1,132 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include <stdlib.h>
+#include "opus/silk/float/main_FLP.h"
+#include "opus/silk/tuning_parameters.h"
+
+void silk_find_pitch_lags_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ silk_float res[], /* O Residual */
+ const silk_float x[], /* I Speech signal */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int buf_len;
+ silk_float thrhld, res_nrg;
+ const silk_float *x_buf_ptr, *x_buf;
+ silk_float auto_corr[ MAX_FIND_PITCH_LPC_ORDER + 1 ];
+ silk_float A[ MAX_FIND_PITCH_LPC_ORDER ];
+ silk_float refl_coef[ MAX_FIND_PITCH_LPC_ORDER ];
+ silk_float Wsig[ FIND_PITCH_LPC_WIN_MAX ];
+ silk_float *Wsig_ptr;
+
+ /******************************************/
+ /* Set up buffer lengths etc based on Fs */
+ /******************************************/
+ buf_len = psEnc->sCmn.la_pitch + psEnc->sCmn.frame_length + psEnc->sCmn.ltp_mem_length;
+
+ /* Safety check */
+ silk_assert( buf_len >= psEnc->sCmn.pitch_LPC_win_length );
+
+ x_buf = x - psEnc->sCmn.ltp_mem_length;
+
+ /******************************************/
+ /* Estimate LPC AR coeficients */
+ /******************************************/
+
+ /* Calculate windowed signal */
+
+ /* First LA_LTP samples */
+ x_buf_ptr = x_buf + buf_len - psEnc->sCmn.pitch_LPC_win_length;
+ Wsig_ptr = Wsig;
+ silk_apply_sine_window_FLP( Wsig_ptr, x_buf_ptr, 1, psEnc->sCmn.la_pitch );
+
+ /* Middle non-windowed samples */
+ Wsig_ptr += psEnc->sCmn.la_pitch;
+ x_buf_ptr += psEnc->sCmn.la_pitch;
+ silk_memcpy( Wsig_ptr, x_buf_ptr, ( psEnc->sCmn.pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 ) ) * sizeof( silk_float ) );
+
+ /* Last LA_LTP samples */
+ Wsig_ptr += psEnc->sCmn.pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 );
+ x_buf_ptr += psEnc->sCmn.pitch_LPC_win_length - ( psEnc->sCmn.la_pitch << 1 );
+ silk_apply_sine_window_FLP( Wsig_ptr, x_buf_ptr, 2, psEnc->sCmn.la_pitch );
+
+ /* Calculate autocorrelation sequence */
+ silk_autocorrelation_FLP( auto_corr, Wsig, psEnc->sCmn.pitch_LPC_win_length, psEnc->sCmn.pitchEstimationLPCOrder + 1 );
+
+ /* Add white noise, as a fraction of the energy */
+ auto_corr[ 0 ] += auto_corr[ 0 ] * FIND_PITCH_WHITE_NOISE_FRACTION + 1;
+
+ /* Calculate the reflection coefficients using Schur */
+ res_nrg = silk_schur_FLP( refl_coef, auto_corr, psEnc->sCmn.pitchEstimationLPCOrder );
+
+ /* Prediction gain */
+ psEncCtrl->predGain = auto_corr[ 0 ] / silk_max_float( res_nrg, 1.0f );
+
+ /* Convert reflection coefficients to prediction coefficients */
+ silk_k2a_FLP( A, refl_coef, psEnc->sCmn.pitchEstimationLPCOrder );
+
+ /* Bandwidth expansion */
+ silk_bwexpander_FLP( A, psEnc->sCmn.pitchEstimationLPCOrder, FIND_PITCH_BANDWIDTH_EXPANSION );
+
+ /*****************************************/
+ /* LPC analysis filtering */
+ /*****************************************/
+ silk_LPC_analysis_filter_FLP( res, A, x_buf, buf_len, psEnc->sCmn.pitchEstimationLPCOrder );
+
+ if( psEnc->sCmn.indices.signalType != TYPE_NO_VOICE_ACTIVITY && psEnc->sCmn.first_frame_after_reset == 0 ) {
+ /* Threshold for pitch estimator */
+ thrhld = 0.6f;
+ thrhld -= 0.004f * psEnc->sCmn.pitchEstimationLPCOrder;
+ thrhld -= 0.1f * psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f );
+ thrhld -= 0.15f * (psEnc->sCmn.prevSignalType >> 1);
+ thrhld -= 0.1f * psEnc->sCmn.input_tilt_Q15 * ( 1.0f / 32768.0f );
+
+ /*****************************************/
+ /* Call Pitch estimator */
+ /*****************************************/
+ if( silk_pitch_analysis_core_FLP( res, psEncCtrl->pitchL, &psEnc->sCmn.indices.lagIndex,
+ &psEnc->sCmn.indices.contourIndex, &psEnc->LTPCorr, psEnc->sCmn.prevLag, psEnc->sCmn.pitchEstimationThreshold_Q16 / 65536.0f,
+ thrhld, psEnc->sCmn.fs_kHz, psEnc->sCmn.pitchEstimationComplexity, psEnc->sCmn.nb_subfr, arch ) == 0 )
+ {
+ psEnc->sCmn.indices.signalType = TYPE_VOICED;
+ } else {
+ psEnc->sCmn.indices.signalType = TYPE_UNVOICED;
+ }
+ } else {
+ silk_memset( psEncCtrl->pitchL, 0, sizeof( psEncCtrl->pitchL ) );
+ psEnc->sCmn.indices.lagIndex = 0;
+ psEnc->sCmn.indices.contourIndex = 0;
+ psEnc->LTPCorr = 0;
+ }
+}
diff --git a/drivers/opus/silk/float/find_pred_coefs_FLP.c b/drivers/opus/silk/float/find_pred_coefs_FLP.c
new file mode 100644
index 0000000000..61eead7573
--- /dev/null
+++ b/drivers/opus/silk/float/find_pred_coefs_FLP.c
@@ -0,0 +1,117 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/float/main_FLP.h"
+
+/* Find LPC and LTP coefficients */
+void silk_find_pred_coefs_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ const silk_float res_pitch[], /* I Residual from pitch analysis */
+ const silk_float x[], /* I Speech signal */
+ opus_int condCoding /* I The type of conditional coding to use */
+)
+{
+ opus_int i;
+ silk_float WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ];
+ silk_float invGains[ MAX_NB_SUBFR ], Wght[ MAX_NB_SUBFR ];
+ opus_int16 NLSF_Q15[ MAX_LPC_ORDER ];
+ const silk_float *x_ptr;
+ silk_float *x_pre_ptr, LPC_in_pre[ MAX_NB_SUBFR * MAX_LPC_ORDER + MAX_FRAME_LENGTH ];
+ silk_float minInvGain;
+
+ /* Weighting for weighted least squares */
+ for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ silk_assert( psEncCtrl->Gains[ i ] > 0.0f );
+ invGains[ i ] = 1.0f / psEncCtrl->Gains[ i ];
+ Wght[ i ] = invGains[ i ] * invGains[ i ];
+ }
+
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ /**********/
+ /* VOICED */
+ /**********/
+ silk_assert( psEnc->sCmn.ltp_mem_length - psEnc->sCmn.predictLPCOrder >= psEncCtrl->pitchL[ 0 ] + LTP_ORDER / 2 );
+
+ /* LTP analysis */
+ silk_find_LTP_FLP( psEncCtrl->LTPCoef, WLTP, &psEncCtrl->LTPredCodGain, res_pitch,
+ psEncCtrl->pitchL, Wght, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.ltp_mem_length );
+
+ /* Quantize LTP gain parameters */
+ silk_quant_LTP_gains_FLP( psEncCtrl->LTPCoef, psEnc->sCmn.indices.LTPIndex, &psEnc->sCmn.indices.PERIndex,
+ &psEnc->sCmn.sum_log_gain_Q7, WLTP, psEnc->sCmn.mu_LTP_Q9, psEnc->sCmn.LTPQuantLowComplexity, psEnc->sCmn.nb_subfr );
+
+ /* Control LTP scaling */
+ silk_LTP_scale_ctrl_FLP( psEnc, psEncCtrl, condCoding );
+
+ /* Create LTP residual */
+ silk_LTP_analysis_filter_FLP( LPC_in_pre, x - psEnc->sCmn.predictLPCOrder, psEncCtrl->LTPCoef,
+ psEncCtrl->pitchL, invGains, psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder );
+ } else {
+ /************/
+ /* UNVOICED */
+ /************/
+ /* Create signal with prepended subframes, scaled by inverse gains */
+ x_ptr = x - psEnc->sCmn.predictLPCOrder;
+ x_pre_ptr = LPC_in_pre;
+ for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ silk_scale_copy_vector_FLP( x_pre_ptr, x_ptr, invGains[ i ],
+ psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder );
+ x_pre_ptr += psEnc->sCmn.subfr_length + psEnc->sCmn.predictLPCOrder;
+ x_ptr += psEnc->sCmn.subfr_length;
+ }
+ silk_memset( psEncCtrl->LTPCoef, 0, psEnc->sCmn.nb_subfr * LTP_ORDER * sizeof( silk_float ) );
+ psEncCtrl->LTPredCodGain = 0.0f;
+ psEnc->sCmn.sum_log_gain_Q7 = 0;
+ }
+
+ /* Limit on total predictive coding gain */
+ if( psEnc->sCmn.first_frame_after_reset ) {
+ minInvGain = 1.0f / MAX_PREDICTION_POWER_GAIN_AFTER_RESET;
+ } else {
+ minInvGain = (silk_float)pow( 2, psEncCtrl->LTPredCodGain / 3 ) / MAX_PREDICTION_POWER_GAIN;
+ minInvGain /= 0.25f + 0.75f * psEncCtrl->coding_quality;
+ }
+
+ /* LPC_in_pre contains the LTP-filtered input for voiced, and the unfiltered input for unvoiced */
+ silk_find_LPC_FLP( &psEnc->sCmn, NLSF_Q15, LPC_in_pre, minInvGain );
+
+ /* Quantize LSFs */
+ silk_process_NLSFs_FLP( &psEnc->sCmn, psEncCtrl->PredCoef, NLSF_Q15, psEnc->sCmn.prev_NLSFq_Q15 );
+
+ /* Calculate residual energy using quantized LPC coefficients */
+ silk_residual_energy_FLP( psEncCtrl->ResNrg, LPC_in_pre, psEncCtrl->PredCoef, psEncCtrl->Gains,
+ psEnc->sCmn.subfr_length, psEnc->sCmn.nb_subfr, psEnc->sCmn.predictLPCOrder );
+
+ /* Copy to prediction struct for use in next frame for interpolation */
+ silk_memcpy( psEnc->sCmn.prev_NLSFq_Q15, NLSF_Q15, sizeof( psEnc->sCmn.prev_NLSFq_Q15 ) );
+}
+
diff --git a/drivers/opus/silk/float/inner_product_FLP.c b/drivers/opus/silk/float/inner_product_FLP.c
new file mode 100644
index 0000000000..e5f0308448
--- /dev/null
+++ b/drivers/opus/silk/float/inner_product_FLP.c
@@ -0,0 +1,60 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/float/SigProc_FLP.h"
+
+/* inner product of two silk_float arrays, with result as double */
+double silk_inner_product_FLP(
+ const silk_float *data1,
+ const silk_float *data2,
+ opus_int dataSize
+)
+{
+ opus_int i, dataSize4;
+ double result;
+
+ /* 4x unrolled loop */
+ result = 0.0;
+ dataSize4 = dataSize & 0xFFFC;
+ for( i = 0; i < dataSize4; i += 4 ) {
+ result += data1[ i + 0 ] * (double)data2[ i + 0 ] +
+ data1[ i + 1 ] * (double)data2[ i + 1 ] +
+ data1[ i + 2 ] * (double)data2[ i + 2 ] +
+ data1[ i + 3 ] * (double)data2[ i + 3 ];
+ }
+
+ /* add any remaining products */
+ for( ; i < dataSize; i++ ) {
+ result += data1[ i ] * (double)data2[ i ];
+ }
+
+ return result;
+}
diff --git a/drivers/opus/silk/float/k2a_FLP.c b/drivers/opus/silk/float/k2a_FLP.c
new file mode 100644
index 0000000000..71dc4c3c44
--- /dev/null
+++ b/drivers/opus/silk/float/k2a_FLP.c
@@ -0,0 +1,53 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/float/SigProc_FLP.h"
+
+/* step up function, converts reflection coefficients to prediction coefficients */
+void silk_k2a_FLP(
+ silk_float *A, /* O prediction coefficients [order] */
+ const silk_float *rc, /* I reflection coefficients [order] */
+ opus_int32 order /* I prediction order */
+)
+{
+ opus_int k, n;
+ silk_float Atmp[ SILK_MAX_ORDER_LPC ];
+
+ for( k = 0; k < order; k++ ) {
+ for( n = 0; n < k; n++ ) {
+ Atmp[ n ] = A[ n ];
+ }
+ for( n = 0; n < k; n++ ) {
+ A[ n ] += Atmp[ k - n - 1 ] * rc[ k ];
+ }
+ A[ k ] = -rc[ k ];
+ }
+}
diff --git a/drivers/opus/silk/float/levinsondurbin_FLP.c b/drivers/opus/silk/float/levinsondurbin_FLP.c
new file mode 100644
index 0000000000..8fbca230a5
--- /dev/null
+++ b/drivers/opus/silk/float/levinsondurbin_FLP.c
@@ -0,0 +1,81 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/float/SigProc_FLP.h"
+
+/* Solve the normal equations using the Levinson-Durbin recursion */
+silk_float silk_levinsondurbin_FLP( /* O prediction error energy */
+ silk_float A[], /* O prediction coefficients [order] */
+ const silk_float corr[], /* I input auto-correlations [order + 1] */
+ const opus_int order /* I prediction order */
+)
+{
+ opus_int i, mHalf, m;
+ silk_float min_nrg, nrg, t, km, Atmp1, Atmp2;
+
+ min_nrg = 1e-12f * corr[ 0 ] + 1e-9f;
+ nrg = corr[ 0 ];
+ nrg = silk_max_float(min_nrg, nrg);
+ A[ 0 ] = corr[ 1 ] / nrg;
+ nrg -= A[ 0 ] * corr[ 1 ];
+ nrg = silk_max_float(min_nrg, nrg);
+
+ for( m = 1; m < order; m++ )
+ {
+ t = corr[ m + 1 ];
+ for( i = 0; i < m; i++ ) {
+ t -= A[ i ] * corr[ m - i ];
+ }
+
+ /* reflection coefficient */
+ km = t / nrg;
+
+ /* residual energy */
+ nrg -= km * t;
+ nrg = silk_max_float(min_nrg, nrg);
+
+ mHalf = m >> 1;
+ for( i = 0; i < mHalf; i++ ) {
+ Atmp1 = A[ i ];
+ Atmp2 = A[ m - i - 1 ];
+ A[ m - i - 1 ] -= km * Atmp1;
+ A[ i ] -= km * Atmp2;
+ }
+ if( m & 1 ) {
+ A[ mHalf ] -= km * A[ mHalf ];
+ }
+ A[ m ] = km;
+ }
+
+ /* return the residual energy */
+ return nrg;
+}
+
diff --git a/drivers/opus/silk/float/main_FLP.h b/drivers/opus/silk/float/main_FLP.h
new file mode 100644
index 0000000000..4ec8ddeefc
--- /dev/null
+++ b/drivers/opus/silk/float/main_FLP.h
@@ -0,0 +1,312 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_MAIN_FLP_H
+#define SILK_MAIN_FLP_H
+
+#include "opus/silk/float/SigProc_FLP.h"
+#include "opus/silk/SigProc_FIX.h"
+#include "opus/silk/float/structs_FLP.h"
+#include "opus/silk/silk_main.h"
+#include "opus/silk/define.h"
+#include "opus/silk/debug.h"
+#include "opus/celt/entenc.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#define silk_encoder_state_Fxx silk_encoder_state_FLP
+#define silk_encode_do_VAD_Fxx silk_encode_do_VAD_FLP
+#define silk_encode_frame_Fxx silk_encode_frame_FLP
+
+/*********************/
+/* Encoder Functions */
+/*********************/
+
+/* High-pass filter with cutoff frequency adaptation based on pitch lag statistics */
+void silk_HP_variable_cutoff(
+ silk_encoder_state_Fxx state_Fxx[] /* I/O Encoder states */
+);
+
+/* Encoder main function */
+void silk_encode_do_VAD_FLP(
+ silk_encoder_state_FLP *psEnc /* I/O Encoder state FLP */
+);
+
+/* Encoder main function */
+opus_int silk_encode_frame_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ opus_int32 *pnBytesOut, /* O Number of payload bytes; */
+ ec_enc *psRangeEnc, /* I/O compressor data structure */
+ opus_int condCoding, /* I The type of conditional coding to use */
+ opus_int maxBits, /* I If > 0: maximum number of output bits */
+ opus_int useCBR /* I Flag to force constant-bitrate operation */
+);
+
+/* Initializes the Silk encoder state */
+opus_int silk_init_encoder(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ int arch /* I Run-tim architecture */
+);
+
+/* Control the Silk encoder */
+opus_int silk_control_encoder(
+ silk_encoder_state_FLP *psEnc, /* I/O Pointer to Silk encoder state FLP */
+ silk_EncControlStruct *encControl, /* I Control structure */
+ const opus_int32 TargetRate_bps, /* I Target max bitrate (bps) */
+ const opus_int allow_bw_switch, /* I Flag to allow switching audio bandwidth */
+ const opus_int channelNb, /* I Channel number */
+ const opus_int force_fs_kHz
+);
+
+/****************/
+/* Prefiltering */
+/****************/
+void silk_prefilter_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ const silk_encoder_control_FLP *psEncCtrl, /* I Encoder control FLP */
+ silk_float xw[], /* O Weighted signal */
+ const silk_float x[] /* I Speech signal */
+);
+
+/**************************/
+/* Noise shaping analysis */
+/**************************/
+/* Compute noise shaping coefficients and initial gain values */
+void silk_noise_shape_analysis_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ const silk_float *pitch_res, /* I LPC residual from pitch analysis */
+ const silk_float *x /* I Input signal [frame_length + la_shape] */
+);
+
+/* Autocorrelations for a warped frequency axis */
+void silk_warped_autocorrelation_FLP(
+ silk_float *corr, /* O Result [order + 1] */
+ const silk_float *input, /* I Input data to correlate */
+ const silk_float warping, /* I Warping coefficient */
+ const opus_int length, /* I Length of input */
+ const opus_int order /* I Correlation order (even) */
+);
+
+/* Calculation of LTP state scaling */
+void silk_LTP_scale_ctrl_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ opus_int condCoding /* I The type of conditional coding to use */
+);
+
+/**********************************************/
+/* Prediction Analysis */
+/**********************************************/
+/* Find pitch lags */
+void silk_find_pitch_lags_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ silk_float res[], /* O Residual */
+ const silk_float x[], /* I Speech signal */
+ int arch /* I Run-time architecture */
+);
+
+/* Find LPC and LTP coefficients */
+void silk_find_pred_coefs_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ const silk_float res_pitch[], /* I Residual from pitch analysis */
+ const silk_float x[], /* I Speech signal */
+ opus_int condCoding /* I The type of conditional coding to use */
+);
+
+/* LPC analysis */
+void silk_find_LPC_FLP(
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ opus_int16 NLSF_Q15[], /* O NLSFs */
+ const silk_float x[], /* I Input signal */
+ const silk_float minInvGain /* I Prediction gain from LTP (dB) */
+);
+
+/* LTP analysis */
+void silk_find_LTP_FLP(
+ silk_float b[ MAX_NB_SUBFR * LTP_ORDER ], /* O LTP coefs */
+ silk_float WLTP[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* O Weight for LTP quantization */
+ silk_float *LTPredCodGain, /* O LTP coding gain */
+ const silk_float r_lpc[], /* I LPC residual */
+ const opus_int lag[ MAX_NB_SUBFR ], /* I LTP lags */
+ const silk_float Wght[ MAX_NB_SUBFR ], /* I Weights */
+ const opus_int subfr_length, /* I Subframe length */
+ const opus_int nb_subfr, /* I number of subframes */
+ const opus_int mem_offset /* I Number of samples in LTP memory */
+);
+
+void silk_LTP_analysis_filter_FLP(
+ silk_float *LTP_res, /* O LTP res MAX_NB_SUBFR*(pre_lgth+subfr_lngth) */
+ const silk_float *x, /* I Input signal, with preceding samples */
+ const silk_float B[ LTP_ORDER * MAX_NB_SUBFR ], /* I LTP coefficients for each subframe */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */
+ const silk_float invGains[ MAX_NB_SUBFR ], /* I Inverse quantization gains */
+ const opus_int subfr_length, /* I Length of each subframe */
+ const opus_int nb_subfr, /* I number of subframes */
+ const opus_int pre_length /* I Preceding samples for each subframe */
+);
+
+/* Calculates residual energies of input subframes where all subframes have LPC_order */
+/* of preceding samples */
+void silk_residual_energy_FLP(
+ silk_float nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */
+ const silk_float x[], /* I Input signal */
+ silk_float a[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */
+ const silk_float gains[], /* I Quantization gains */
+ const opus_int subfr_length, /* I Subframe length */
+ const opus_int nb_subfr, /* I number of subframes */
+ const opus_int LPC_order /* I LPC order */
+);
+
+/* 16th order LPC analysis filter */
+void silk_LPC_analysis_filter_FLP(
+ silk_float r_LPC[], /* O LPC residual signal */
+ const silk_float PredCoef[], /* I LPC coefficients */
+ const silk_float s[], /* I Input signal */
+ const opus_int length, /* I Length of input signal */
+ const opus_int Order /* I LPC order */
+);
+
+/* LTP tap quantizer */
+void silk_quant_LTP_gains_FLP(
+ silk_float B[ MAX_NB_SUBFR * LTP_ORDER ], /* I/O (Un-)quantized LTP gains */
+ opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook index */
+ opus_int8 *periodicity_index, /* O Periodicity index */
+ opus_int32 *sum_log_gain_Q7, /* I/O Cumulative max prediction gain */
+ const silk_float W[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* I Error weights */
+ const opus_int mu_Q10, /* I Mu value (R/D tradeoff) */
+ const opus_int lowComplexity, /* I Flag for low complexity */
+ const opus_int nb_subfr /* I number of subframes */
+);
+
+/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */
+silk_float silk_residual_energy_covar_FLP( /* O Weighted residual energy */
+ const silk_float *c, /* I Filter coefficients */
+ silk_float *wXX, /* I/O Weighted correlation matrix, reg. out */
+ const silk_float *wXx, /* I Weighted correlation vector */
+ const silk_float wxx, /* I Weighted correlation value */
+ const opus_int D /* I Dimension */
+);
+
+/* Processing of gains */
+void silk_process_gains_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ opus_int condCoding /* I The type of conditional coding to use */
+);
+
+/******************/
+/* Linear Algebra */
+/******************/
+/* Calculates correlation matrix X'*X */
+void silk_corrMatrix_FLP(
+ const silk_float *x, /* I x vector [ L+order-1 ] used to create X */
+ const opus_int L, /* I Length of vectors */
+ const opus_int Order, /* I Max lag for correlation */
+ silk_float *XX /* O X'*X correlation matrix [order x order] */
+);
+
+/* Calculates correlation vector X'*t */
+void silk_corrVector_FLP(
+ const silk_float *x, /* I x vector [L+order-1] used to create X */
+ const silk_float *t, /* I Target vector [L] */
+ const opus_int L, /* I Length of vecors */
+ const opus_int Order, /* I Max lag for correlation */
+ silk_float *Xt /* O X'*t correlation vector [order] */
+);
+
+/* Add noise to matrix diagonal */
+void silk_regularize_correlations_FLP(
+ silk_float *XX, /* I/O Correlation matrices */
+ silk_float *xx, /* I/O Correlation values */
+ const silk_float noise, /* I Noise energy to add */
+ const opus_int D /* I Dimension of XX */
+);
+
+/* Function to solve linear equation Ax = b, where A is an MxM symmetric matrix */
+void silk_solve_LDL_FLP(
+ silk_float *A, /* I/O Symmetric square matrix, out: reg. */
+ const opus_int M, /* I Size of matrix */
+ const silk_float *b, /* I Pointer to b vector */
+ silk_float *x /* O Pointer to x solution vector */
+);
+
+/* Apply sine window to signal vector. */
+/* Window types: */
+/* 1 -> sine window from 0 to pi/2 */
+/* 2 -> sine window from pi/2 to pi */
+void silk_apply_sine_window_FLP(
+ silk_float px_win[], /* O Pointer to windowed signal */
+ const silk_float px[], /* I Pointer to input signal */
+ const opus_int win_type, /* I Selects a window type */
+ const opus_int length /* I Window length, multiple of 4 */
+);
+
+/* Wrapper functions. Call flp / fix code */
+
+/* Convert AR filter coefficients to NLSF parameters */
+void silk_A2NLSF_FLP(
+ opus_int16 *NLSF_Q15, /* O NLSF vector [ LPC_order ] */
+ const silk_float *pAR, /* I LPC coefficients [ LPC_order ] */
+ const opus_int LPC_order /* I LPC order */
+);
+
+/* Convert NLSF parameters to AR prediction filter coefficients */
+void silk_NLSF2A_FLP(
+ silk_float *pAR, /* O LPC coefficients [ LPC_order ] */
+ const opus_int16 *NLSF_Q15, /* I NLSF vector [ LPC_order ] */
+ const opus_int LPC_order /* I LPC order */
+);
+
+/* Limit, stabilize, and quantize NLSFs */
+void silk_process_NLSFs_FLP(
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ silk_float PredCoef[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */
+ opus_int16 NLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */
+ const opus_int16 prev_NLSF_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */
+);
+
+/* Floating-point Silk NSQ wrapper */
+void silk_NSQ_wrapper_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ SideInfoIndices *psIndices, /* I/O Quantization indices */
+ silk_nsq_state *psNSQ, /* I/O Noise Shaping Quantzation state */
+ opus_int8 pulses[], /* O Quantized pulse signal */
+ const silk_float x[] /* I Prefiltered input signal */
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/opus/silk/float/noise_shape_analysis_FLP.c b/drivers/opus/silk/float/noise_shape_analysis_FLP.c
new file mode 100644
index 0000000000..5d8bc6332a
--- /dev/null
+++ b/drivers/opus/silk/float/noise_shape_analysis_FLP.c
@@ -0,0 +1,365 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/float/main_FLP.h"
+#include "opus/silk/tuning_parameters.h"
+
+/* Compute gain to make warped filter coefficients have a zero mean log frequency response on a */
+/* non-warped frequency scale. (So that it can be implemented with a minimum-phase monic filter.) */
+/* Note: A monic filter is one with the first coefficient equal to 1.0. In Silk we omit the first */
+/* coefficient in an array of coefficients, for monic filters. */
+static OPUS_INLINE silk_float warped_gain(
+ const silk_float *coefs,
+ silk_float lambda,
+ opus_int order
+) {
+ opus_int i;
+ silk_float gain;
+
+ lambda = -lambda;
+ gain = coefs[ order - 1 ];
+ for( i = order - 2; i >= 0; i-- ) {
+ gain = lambda * gain + coefs[ i ];
+ }
+ return (silk_float)( 1.0f / ( 1.0f - lambda * gain ) );
+}
+
+/* Convert warped filter coefficients to monic pseudo-warped coefficients and limit maximum */
+/* amplitude of monic warped coefficients by using bandwidth expansion on the true coefficients */
+static OPUS_INLINE void warped_true2monic_coefs(
+ silk_float *coefs_syn,
+ silk_float *coefs_ana,
+ silk_float lambda,
+ silk_float limit,
+ opus_int order
+) {
+ opus_int i, iter, ind = 0;
+ silk_float tmp, maxabs, chirp, gain_syn, gain_ana;
+
+ /* Convert to monic coefficients */
+ for( i = order - 1; i > 0; i-- ) {
+ coefs_syn[ i - 1 ] -= lambda * coefs_syn[ i ];
+ coefs_ana[ i - 1 ] -= lambda * coefs_ana[ i ];
+ }
+ gain_syn = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_syn[ 0 ] );
+ gain_ana = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_ana[ 0 ] );
+ for( i = 0; i < order; i++ ) {
+ coefs_syn[ i ] *= gain_syn;
+ coefs_ana[ i ] *= gain_ana;
+ }
+
+ /* Limit */
+ for( iter = 0; iter < 10; iter++ ) {
+ /* Find maximum absolute value */
+ maxabs = -1.0f;
+ for( i = 0; i < order; i++ ) {
+ tmp = silk_max( silk_abs_float( coefs_syn[ i ] ), silk_abs_float( coefs_ana[ i ] ) );
+ if( tmp > maxabs ) {
+ maxabs = tmp;
+ ind = i;
+ }
+ }
+ if( maxabs <= limit ) {
+ /* Coefficients are within range - done */
+ return;
+ }
+
+ /* Convert back to true warped coefficients */
+ for( i = 1; i < order; i++ ) {
+ coefs_syn[ i - 1 ] += lambda * coefs_syn[ i ];
+ coefs_ana[ i - 1 ] += lambda * coefs_ana[ i ];
+ }
+ gain_syn = 1.0f / gain_syn;
+ gain_ana = 1.0f / gain_ana;
+ for( i = 0; i < order; i++ ) {
+ coefs_syn[ i ] *= gain_syn;
+ coefs_ana[ i ] *= gain_ana;
+ }
+
+ /* Apply bandwidth expansion */
+ chirp = 0.99f - ( 0.8f + 0.1f * iter ) * ( maxabs - limit ) / ( maxabs * ( ind + 1 ) );
+ silk_bwexpander_FLP( coefs_syn, order, chirp );
+ silk_bwexpander_FLP( coefs_ana, order, chirp );
+
+ /* Convert to monic warped coefficients */
+ for( i = order - 1; i > 0; i-- ) {
+ coefs_syn[ i - 1 ] -= lambda * coefs_syn[ i ];
+ coefs_ana[ i - 1 ] -= lambda * coefs_ana[ i ];
+ }
+ gain_syn = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_syn[ 0 ] );
+ gain_ana = ( 1.0f - lambda * lambda ) / ( 1.0f + lambda * coefs_ana[ 0 ] );
+ for( i = 0; i < order; i++ ) {
+ coefs_syn[ i ] *= gain_syn;
+ coefs_ana[ i ] *= gain_ana;
+ }
+ }
+ silk_assert( 0 );
+}
+
+/* Compute noise shaping coefficients and initial gain values */
+void silk_noise_shape_analysis_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ const silk_float *pitch_res, /* I LPC residual from pitch analysis */
+ const silk_float *x /* I Input signal [frame_length + la_shape] */
+)
+{
+ silk_shape_state_FLP *psShapeSt = &psEnc->sShape;
+ opus_int k, nSamples;
+ silk_float SNR_adj_dB, HarmBoost, HarmShapeGain, Tilt;
+ silk_float nrg, pre_nrg, log_energy, log_energy_prev, energy_variation;
+ silk_float delta, BWExp1, BWExp2, gain_mult, gain_add, strength, b, warping;
+ silk_float x_windowed[ SHAPE_LPC_WIN_MAX ];
+ silk_float auto_corr[ MAX_SHAPE_LPC_ORDER + 1 ];
+ const silk_float *x_ptr, *pitch_res_ptr;
+
+ /* Point to start of first LPC analysis block */
+ x_ptr = x - psEnc->sCmn.la_shape;
+
+ /****************/
+ /* GAIN CONTROL */
+ /****************/
+ SNR_adj_dB = psEnc->sCmn.SNR_dB_Q7 * ( 1 / 128.0f );
+
+ /* Input quality is the average of the quality in the lowest two VAD bands */
+ psEncCtrl->input_quality = 0.5f * ( psEnc->sCmn.input_quality_bands_Q15[ 0 ] + psEnc->sCmn.input_quality_bands_Q15[ 1 ] ) * ( 1.0f / 32768.0f );
+
+ /* Coding quality level, between 0.0 and 1.0 */
+ psEncCtrl->coding_quality = silk_sigmoid( 0.25f * ( SNR_adj_dB - 20.0f ) );
+
+ if( psEnc->sCmn.useCBR == 0 ) {
+ /* Reduce coding SNR during low speech activity */
+ b = 1.0f - psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f );
+ SNR_adj_dB -= BG_SNR_DECR_dB * psEncCtrl->coding_quality * ( 0.5f + 0.5f * psEncCtrl->input_quality ) * b * b;
+ }
+
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ /* Reduce gains for periodic signals */
+ SNR_adj_dB += HARM_SNR_INCR_dB * psEnc->LTPCorr;
+ } else {
+ /* For unvoiced signals and low-quality input, adjust the quality slower than SNR_dB setting */
+ SNR_adj_dB += ( -0.4f * psEnc->sCmn.SNR_dB_Q7 * ( 1 / 128.0f ) + 6.0f ) * ( 1.0f - psEncCtrl->input_quality );
+ }
+
+ /*************************/
+ /* SPARSENESS PROCESSING */
+ /*************************/
+ /* Set quantizer offset */
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ /* Initially set to 0; may be overruled in process_gains(..) */
+ psEnc->sCmn.indices.quantOffsetType = 0;
+ psEncCtrl->sparseness = 0.0f;
+ } else {
+ /* Sparseness measure, based on relative fluctuations of energy per 2 milliseconds */
+ nSamples = 2 * psEnc->sCmn.fs_kHz;
+ energy_variation = 0.0f;
+ log_energy_prev = 0.0f;
+ pitch_res_ptr = pitch_res;
+ for( k = 0; k < silk_SMULBB( SUB_FRAME_LENGTH_MS, psEnc->sCmn.nb_subfr ) / 2; k++ ) {
+ nrg = ( silk_float )nSamples + ( silk_float )silk_energy_FLP( pitch_res_ptr, nSamples );
+ log_energy = silk_log2( nrg );
+ if( k > 0 ) {
+ energy_variation += silk_abs_float( log_energy - log_energy_prev );
+ }
+ log_energy_prev = log_energy;
+ pitch_res_ptr += nSamples;
+ }
+ psEncCtrl->sparseness = silk_sigmoid( 0.4f * ( energy_variation - 5.0f ) );
+
+ /* Set quantization offset depending on sparseness measure */
+ if( psEncCtrl->sparseness > SPARSENESS_THRESHOLD_QNT_OFFSET ) {
+ psEnc->sCmn.indices.quantOffsetType = 0;
+ } else {
+ psEnc->sCmn.indices.quantOffsetType = 1;
+ }
+
+ /* Increase coding SNR for sparse signals */
+ SNR_adj_dB += SPARSE_SNR_INCR_dB * ( psEncCtrl->sparseness - 0.5f );
+ }
+
+ /*******************************/
+ /* Control bandwidth expansion */
+ /*******************************/
+ /* More BWE for signals with high prediction gain */
+ strength = FIND_PITCH_WHITE_NOISE_FRACTION * psEncCtrl->predGain; /* between 0.0 and 1.0 */
+ BWExp1 = BWExp2 = BANDWIDTH_EXPANSION / ( 1.0f + strength * strength );
+ delta = LOW_RATE_BANDWIDTH_EXPANSION_DELTA * ( 1.0f - 0.75f * psEncCtrl->coding_quality );
+ BWExp1 -= delta;
+ BWExp2 += delta;
+ /* BWExp1 will be applied after BWExp2, so make it relative */
+ BWExp1 /= BWExp2;
+
+ if( psEnc->sCmn.warping_Q16 > 0 ) {
+ /* Slightly more warping in analysis will move quantization noise up in frequency, where it's better masked */
+ warping = (silk_float)psEnc->sCmn.warping_Q16 / 65536.0f + 0.01f * psEncCtrl->coding_quality;
+ } else {
+ warping = 0.0f;
+ }
+
+ /********************************************/
+ /* Compute noise shaping AR coefs and gains */
+ /********************************************/
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ /* Apply window: sine slope followed by flat part followed by cosine slope */
+ opus_int shift, slope_part, flat_part;
+ flat_part = psEnc->sCmn.fs_kHz * 3;
+ slope_part = ( psEnc->sCmn.shapeWinLength - flat_part ) / 2;
+
+ silk_apply_sine_window_FLP( x_windowed, x_ptr, 1, slope_part );
+ shift = slope_part;
+ silk_memcpy( x_windowed + shift, x_ptr + shift, flat_part * sizeof(silk_float) );
+ shift += flat_part;
+ silk_apply_sine_window_FLP( x_windowed + shift, x_ptr + shift, 2, slope_part );
+
+ /* Update pointer: next LPC analysis block */
+ x_ptr += psEnc->sCmn.subfr_length;
+
+ if( psEnc->sCmn.warping_Q16 > 0 ) {
+ /* Calculate warped auto correlation */
+ silk_warped_autocorrelation_FLP( auto_corr, x_windowed, warping,
+ psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder );
+ } else {
+ /* Calculate regular auto correlation */
+ silk_autocorrelation_FLP( auto_corr, x_windowed, psEnc->sCmn.shapeWinLength, psEnc->sCmn.shapingLPCOrder + 1 );
+ }
+
+ /* Add white noise, as a fraction of energy */
+ auto_corr[ 0 ] += auto_corr[ 0 ] * SHAPE_WHITE_NOISE_FRACTION;
+
+ /* Convert correlations to prediction coefficients, and compute residual energy */
+ nrg = silk_levinsondurbin_FLP( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], auto_corr, psEnc->sCmn.shapingLPCOrder );
+ psEncCtrl->Gains[ k ] = ( silk_float )sqrt( nrg );
+
+ if( psEnc->sCmn.warping_Q16 > 0 ) {
+ /* Adjust gain for warping */
+ psEncCtrl->Gains[ k ] *= warped_gain( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], warping, psEnc->sCmn.shapingLPCOrder );
+ }
+
+ /* Bandwidth expansion for synthesis filter shaping */
+ silk_bwexpander_FLP( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder, BWExp2 );
+
+ /* Compute noise shaping filter coefficients */
+ silk_memcpy(
+ &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ],
+ &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ],
+ psEnc->sCmn.shapingLPCOrder * sizeof( silk_float ) );
+
+ /* Bandwidth expansion for analysis filter shaping */
+ silk_bwexpander_FLP( &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder, BWExp1 );
+
+ /* Ratio of prediction gains, in energy domain */
+ pre_nrg = silk_LPC_inverse_pred_gain_FLP( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder );
+ nrg = silk_LPC_inverse_pred_gain_FLP( &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ], psEnc->sCmn.shapingLPCOrder );
+ psEncCtrl->GainsPre[ k ] = 1.0f - 0.7f * ( 1.0f - pre_nrg / nrg );
+
+ /* Convert to monic warped prediction coefficients and limit absolute values */
+ warped_true2monic_coefs( &psEncCtrl->AR2[ k * MAX_SHAPE_LPC_ORDER ], &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ],
+ warping, 3.999f, psEnc->sCmn.shapingLPCOrder );
+ }
+
+ /*****************/
+ /* Gain tweaking */
+ /*****************/
+ /* Increase gains during low speech activity */
+ gain_mult = (silk_float)pow( 2.0f, -0.16f * SNR_adj_dB );
+ gain_add = (silk_float)pow( 2.0f, 0.16f * MIN_QGAIN_DB );
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ psEncCtrl->Gains[ k ] *= gain_mult;
+ psEncCtrl->Gains[ k ] += gain_add;
+ }
+
+ gain_mult = 1.0f + INPUT_TILT + psEncCtrl->coding_quality * HIGH_RATE_INPUT_TILT;
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ psEncCtrl->GainsPre[ k ] *= gain_mult;
+ }
+
+ /************************************************/
+ /* Control low-frequency shaping and noise tilt */
+ /************************************************/
+ /* Less low frequency shaping for noisy inputs */
+ strength = LOW_FREQ_SHAPING * ( 1.0f + LOW_QUALITY_LOW_FREQ_SHAPING_DECR * ( psEnc->sCmn.input_quality_bands_Q15[ 0 ] * ( 1.0f / 32768.0f ) - 1.0f ) );
+ strength *= psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f );
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ /* Reduce low frequencies quantization noise for periodic signals, depending on pitch lag */
+ /*f = 400; freqz([1, -0.98 + 2e-4 * f], [1, -0.97 + 7e-4 * f], 2^12, Fs); axis([0, 1000, -10, 1])*/
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ b = 0.2f / psEnc->sCmn.fs_kHz + 3.0f / psEncCtrl->pitchL[ k ];
+ psEncCtrl->LF_MA_shp[ k ] = -1.0f + b;
+ psEncCtrl->LF_AR_shp[ k ] = 1.0f - b - b * strength;
+ }
+ Tilt = - HP_NOISE_COEF -
+ (1 - HP_NOISE_COEF) * HARM_HP_NOISE_COEF * psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f );
+ } else {
+ b = 1.3f / psEnc->sCmn.fs_kHz;
+ psEncCtrl->LF_MA_shp[ 0 ] = -1.0f + b;
+ psEncCtrl->LF_AR_shp[ 0 ] = 1.0f - b - b * strength * 0.6f;
+ for( k = 1; k < psEnc->sCmn.nb_subfr; k++ ) {
+ psEncCtrl->LF_MA_shp[ k ] = psEncCtrl->LF_MA_shp[ 0 ];
+ psEncCtrl->LF_AR_shp[ k ] = psEncCtrl->LF_AR_shp[ 0 ];
+ }
+ Tilt = -HP_NOISE_COEF;
+ }
+
+ /****************************/
+ /* HARMONIC SHAPING CONTROL */
+ /****************************/
+ /* Control boosting of harmonic frequencies */
+ HarmBoost = LOW_RATE_HARMONIC_BOOST * ( 1.0f - psEncCtrl->coding_quality ) * psEnc->LTPCorr;
+
+ /* More harmonic boost for noisy input signals */
+ HarmBoost += LOW_INPUT_QUALITY_HARMONIC_BOOST * ( 1.0f - psEncCtrl->input_quality );
+
+ if( USE_HARM_SHAPING && psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ /* Harmonic noise shaping */
+ HarmShapeGain = HARMONIC_SHAPING;
+
+ /* More harmonic noise shaping for high bitrates or noisy input */
+ HarmShapeGain += HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING *
+ ( 1.0f - ( 1.0f - psEncCtrl->coding_quality ) * psEncCtrl->input_quality );
+
+ /* Less harmonic noise shaping for less periodic signals */
+ HarmShapeGain *= ( silk_float )sqrt( psEnc->LTPCorr );
+ } else {
+ HarmShapeGain = 0.0f;
+ }
+
+ /*************************/
+ /* Smooth over subframes */
+ /*************************/
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ psShapeSt->HarmBoost_smth += SUBFR_SMTH_COEF * ( HarmBoost - psShapeSt->HarmBoost_smth );
+ psEncCtrl->HarmBoost[ k ] = psShapeSt->HarmBoost_smth;
+ psShapeSt->HarmShapeGain_smth += SUBFR_SMTH_COEF * ( HarmShapeGain - psShapeSt->HarmShapeGain_smth );
+ psEncCtrl->HarmShapeGain[ k ] = psShapeSt->HarmShapeGain_smth;
+ psShapeSt->Tilt_smth += SUBFR_SMTH_COEF * ( Tilt - psShapeSt->Tilt_smth );
+ psEncCtrl->Tilt[ k ] = psShapeSt->Tilt_smth;
+ }
+}
diff --git a/drivers/opus/silk/float/pitch_analysis_core_FLP.c b/drivers/opus/silk/float/pitch_analysis_core_FLP.c
new file mode 100644
index 0000000000..2689c5008b
--- /dev/null
+++ b/drivers/opus/silk/float/pitch_analysis_core_FLP.c
@@ -0,0 +1,630 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+/*****************************************************************************
+* Pitch analyser function
+******************************************************************************/
+#include "opus/silk/float/SigProc_FLP.h"
+#include "opus/silk/SigProc_FIX.h"
+#include "opus/silk/pitch_est_defines.h"
+#include "opus/celt/pitch.h"
+
+#define SCRATCH_SIZE 22
+
+/************************************************************/
+/* Internally used functions */
+/************************************************************/
+static void silk_P_Ana_calc_corr_st3(
+ silk_float cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */
+ const silk_float frame[], /* I vector to correlate */
+ opus_int start_lag, /* I start lag */
+ opus_int sf_length, /* I sub frame length */
+ opus_int nb_subfr, /* I number of subframes */
+ opus_int complexity, /* I Complexity setting */
+ int arch /* I Run-time architecture */
+);
+
+static void silk_P_Ana_calc_energy_st3(
+ silk_float energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */
+ const silk_float frame[], /* I vector to correlate */
+ opus_int start_lag, /* I start lag */
+ opus_int sf_length, /* I sub frame length */
+ opus_int nb_subfr, /* I number of subframes */
+ opus_int complexity /* I Complexity setting */
+);
+
+/************************************************************/
+/* CORE PITCH ANALYSIS FUNCTION */
+/************************************************************/
+opus_int silk_pitch_analysis_core_FLP( /* O Voicing estimate: 0 voiced, 1 unvoiced */
+ const silk_float *frame, /* I Signal of length PE_FRAME_LENGTH_MS*Fs_kHz */
+ opus_int *pitch_out, /* O Pitch lag values [nb_subfr] */
+ opus_int16 *lagIndex, /* O Lag Index */
+ opus_int8 *contourIndex, /* O Pitch contour Index */
+ silk_float *LTPCorr, /* I/O Normalized correlation; input: value from previous frame */
+ opus_int prevLag, /* I Last lag of previous frame; set to zero is unvoiced */
+ const silk_float search_thres1, /* I First stage threshold for lag candidates 0 - 1 */
+ const silk_float search_thres2, /* I Final threshold for lag candidates 0 - 1 */
+ const opus_int Fs_kHz, /* I sample frequency (kHz) */
+ const opus_int complexity, /* I Complexity setting, 0-2, where 2 is highest */
+ const opus_int nb_subfr, /* I Number of 5 ms subframes */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int i, k, d, j;
+ silk_float frame_8kHz[ PE_MAX_FRAME_LENGTH_MS * 8 ];
+ silk_float frame_4kHz[ PE_MAX_FRAME_LENGTH_MS * 4 ];
+ opus_int16 frame_8_FIX[ PE_MAX_FRAME_LENGTH_MS * 8 ];
+ opus_int16 frame_4_FIX[ PE_MAX_FRAME_LENGTH_MS * 4 ];
+ opus_int32 filt_state[ 6 ];
+ silk_float threshold, contour_bias;
+ silk_float C[ PE_MAX_NB_SUBFR][ (PE_MAX_LAG >> 1) + 5 ];
+ opus_val32 xcorr[ PE_MAX_LAG_MS * 4 - PE_MIN_LAG_MS * 4 + 1 ];
+ silk_float CC[ PE_NB_CBKS_STAGE2_EXT ];
+ const silk_float *target_ptr, *basis_ptr;
+ double cross_corr, normalizer, energy, energy_tmp;
+ opus_int d_srch[ PE_D_SRCH_LENGTH ];
+ opus_int16 d_comp[ (PE_MAX_LAG >> 1) + 5 ];
+ opus_int length_d_srch, length_d_comp;
+ silk_float Cmax, CCmax, CCmax_b, CCmax_new_b, CCmax_new;
+ opus_int CBimax, CBimax_new, lag, start_lag, end_lag, lag_new;
+ opus_int cbk_size;
+ silk_float lag_log2, prevLag_log2, delta_lag_log2_sqr;
+ silk_float energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ];
+ silk_float cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ];
+ opus_int lag_counter;
+ opus_int frame_length, frame_length_8kHz, frame_length_4kHz;
+ opus_int sf_length, sf_length_8kHz, sf_length_4kHz;
+ opus_int min_lag, min_lag_8kHz, min_lag_4kHz;
+ opus_int max_lag, max_lag_8kHz, max_lag_4kHz;
+ opus_int nb_cbk_search;
+ const opus_int8 *Lag_CB_ptr;
+
+ /* Check for valid sampling frequency */
+ silk_assert( Fs_kHz == 8 || Fs_kHz == 12 || Fs_kHz == 16 );
+
+ /* Check for valid complexity setting */
+ silk_assert( complexity >= SILK_PE_MIN_COMPLEX );
+ silk_assert( complexity <= SILK_PE_MAX_COMPLEX );
+
+ silk_assert( search_thres1 >= 0.0f && search_thres1 <= 1.0f );
+ silk_assert( search_thres2 >= 0.0f && search_thres2 <= 1.0f );
+
+ /* Set up frame lengths max / min lag for the sampling frequency */
+ frame_length = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * Fs_kHz;
+ frame_length_4kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 4;
+ frame_length_8kHz = ( PE_LTP_MEM_LENGTH_MS + nb_subfr * PE_SUBFR_LENGTH_MS ) * 8;
+ sf_length = PE_SUBFR_LENGTH_MS * Fs_kHz;
+ sf_length_4kHz = PE_SUBFR_LENGTH_MS * 4;
+ sf_length_8kHz = PE_SUBFR_LENGTH_MS * 8;
+ min_lag = PE_MIN_LAG_MS * Fs_kHz;
+ min_lag_4kHz = PE_MIN_LAG_MS * 4;
+ min_lag_8kHz = PE_MIN_LAG_MS * 8;
+ max_lag = PE_MAX_LAG_MS * Fs_kHz - 1;
+ max_lag_4kHz = PE_MAX_LAG_MS * 4;
+ max_lag_8kHz = PE_MAX_LAG_MS * 8 - 1;
+
+ /* Resample from input sampled at Fs_kHz to 8 kHz */
+ if( Fs_kHz == 16 ) {
+ /* Resample to 16 -> 8 khz */
+ opus_int16 frame_16_FIX[ 16 * PE_MAX_FRAME_LENGTH_MS ];
+ silk_float2short_array( frame_16_FIX, frame, frame_length );
+ silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) );
+ silk_resampler_down2( filt_state, frame_8_FIX, frame_16_FIX, frame_length );
+ silk_short2float_array( frame_8kHz, frame_8_FIX, frame_length_8kHz );
+ } else if( Fs_kHz == 12 ) {
+ /* Resample to 12 -> 8 khz */
+ opus_int16 frame_12_FIX[ 12 * PE_MAX_FRAME_LENGTH_MS ];
+ silk_float2short_array( frame_12_FIX, frame, frame_length );
+ silk_memset( filt_state, 0, 6 * sizeof( opus_int32 ) );
+ silk_resampler_down2_3( filt_state, frame_8_FIX, frame_12_FIX, frame_length );
+ silk_short2float_array( frame_8kHz, frame_8_FIX, frame_length_8kHz );
+ } else {
+ silk_assert( Fs_kHz == 8 );
+ silk_float2short_array( frame_8_FIX, frame, frame_length_8kHz );
+ }
+
+ /* Decimate again to 4 kHz */
+ silk_memset( filt_state, 0, 2 * sizeof( opus_int32 ) );
+ silk_resampler_down2( filt_state, frame_4_FIX, frame_8_FIX, frame_length_8kHz );
+ silk_short2float_array( frame_4kHz, frame_4_FIX, frame_length_4kHz );
+
+ /* Low-pass filter */
+ for( i = frame_length_4kHz - 1; i > 0; i-- ) {
+ frame_4kHz[ i ] += frame_4kHz[ i - 1 ];
+ }
+
+ /******************************************************************************
+ * FIRST STAGE, operating in 4 khz
+ ******************************************************************************/
+ silk_memset(C, 0, sizeof(silk_float) * nb_subfr * ((PE_MAX_LAG >> 1) + 5));
+ target_ptr = &frame_4kHz[ silk_LSHIFT( sf_length_4kHz, 2 ) ];
+ for( k = 0; k < nb_subfr >> 1; k++ ) {
+ /* Check that we are within range of the array */
+ silk_assert( target_ptr >= frame_4kHz );
+ silk_assert( target_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz );
+
+ basis_ptr = target_ptr - min_lag_4kHz;
+
+ /* Check that we are within range of the array */
+ silk_assert( basis_ptr >= frame_4kHz );
+ silk_assert( basis_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz );
+
+ celt_pitch_xcorr( target_ptr, target_ptr-max_lag_4kHz, xcorr, sf_length_8kHz, max_lag_4kHz - min_lag_4kHz + 1, arch );
+
+ /* Calculate first vector products before loop */
+ cross_corr = xcorr[ max_lag_4kHz - min_lag_4kHz ];
+ normalizer = silk_energy_FLP( target_ptr, sf_length_8kHz ) +
+ silk_energy_FLP( basis_ptr, sf_length_8kHz ) +
+ sf_length_8kHz * 4000.0f;
+
+ C[ 0 ][ min_lag_4kHz ] += (silk_float)( 2 * cross_corr / normalizer );
+
+ /* From now on normalizer is computed recursively */
+ for( d = min_lag_4kHz + 1; d <= max_lag_4kHz; d++ ) {
+ basis_ptr--;
+
+ /* Check that we are within range of the array */
+ silk_assert( basis_ptr >= frame_4kHz );
+ silk_assert( basis_ptr + sf_length_8kHz <= frame_4kHz + frame_length_4kHz );
+
+ cross_corr = xcorr[ max_lag_4kHz - d ];
+
+ /* Add contribution of new sample and remove contribution from oldest sample */
+ normalizer +=
+ basis_ptr[ 0 ] * (double)basis_ptr[ 0 ] -
+ basis_ptr[ sf_length_8kHz ] * (double)basis_ptr[ sf_length_8kHz ];
+ C[ 0 ][ d ] += (silk_float)( 2 * cross_corr / normalizer );
+ }
+ /* Update target pointer */
+ target_ptr += sf_length_8kHz;
+ }
+
+ /* Apply short-lag bias */
+ for( i = max_lag_4kHz; i >= min_lag_4kHz; i-- ) {
+ C[ 0 ][ i ] -= C[ 0 ][ i ] * i / 4096.0f;
+ }
+
+ /* Sort */
+ length_d_srch = 4 + 2 * complexity;
+ silk_assert( 3 * length_d_srch <= PE_D_SRCH_LENGTH );
+ silk_insertion_sort_decreasing_FLP( &C[ 0 ][ min_lag_4kHz ], d_srch, max_lag_4kHz - min_lag_4kHz + 1, length_d_srch );
+
+ /* Escape if correlation is very low already here */
+ Cmax = C[ 0 ][ min_lag_4kHz ];
+ if( Cmax < 0.2f ) {
+ silk_memset( pitch_out, 0, nb_subfr * sizeof( opus_int ) );
+ *LTPCorr = 0.0f;
+ *lagIndex = 0;
+ *contourIndex = 0;
+ return 1;
+ }
+
+ threshold = search_thres1 * Cmax;
+ for( i = 0; i < length_d_srch; i++ ) {
+ /* Convert to 8 kHz indices for the sorted correlation that exceeds the threshold */
+ if( C[ 0 ][ min_lag_4kHz + i ] > threshold ) {
+ d_srch[ i ] = silk_LSHIFT( d_srch[ i ] + min_lag_4kHz, 1 );
+ } else {
+ length_d_srch = i;
+ break;
+ }
+ }
+ silk_assert( length_d_srch > 0 );
+
+ for( i = min_lag_8kHz - 5; i < max_lag_8kHz + 5; i++ ) {
+ d_comp[ i ] = 0;
+ }
+ for( i = 0; i < length_d_srch; i++ ) {
+ d_comp[ d_srch[ i ] ] = 1;
+ }
+
+ /* Convolution */
+ for( i = max_lag_8kHz + 3; i >= min_lag_8kHz; i-- ) {
+ d_comp[ i ] += d_comp[ i - 1 ] + d_comp[ i - 2 ];
+ }
+
+ length_d_srch = 0;
+ for( i = min_lag_8kHz; i < max_lag_8kHz + 1; i++ ) {
+ if( d_comp[ i + 1 ] > 0 ) {
+ d_srch[ length_d_srch ] = i;
+ length_d_srch++;
+ }
+ }
+
+ /* Convolution */
+ for( i = max_lag_8kHz + 3; i >= min_lag_8kHz; i-- ) {
+ d_comp[ i ] += d_comp[ i - 1 ] + d_comp[ i - 2 ] + d_comp[ i - 3 ];
+ }
+
+ length_d_comp = 0;
+ for( i = min_lag_8kHz; i < max_lag_8kHz + 4; i++ ) {
+ if( d_comp[ i ] > 0 ) {
+ d_comp[ length_d_comp ] = (opus_int16)( i - 2 );
+ length_d_comp++;
+ }
+ }
+
+ /**********************************************************************************
+ ** SECOND STAGE, operating at 8 kHz, on lag sections with high correlation
+ *************************************************************************************/
+ /*********************************************************************************
+ * Find energy of each subframe projected onto its history, for a range of delays
+ *********************************************************************************/
+ silk_memset( C, 0, PE_MAX_NB_SUBFR*((PE_MAX_LAG >> 1) + 5) * sizeof(silk_float));
+
+ if( Fs_kHz == 8 ) {
+ target_ptr = &frame[ PE_LTP_MEM_LENGTH_MS * 8 ];
+ } else {
+ target_ptr = &frame_8kHz[ PE_LTP_MEM_LENGTH_MS * 8 ];
+ }
+ for( k = 0; k < nb_subfr; k++ ) {
+ energy_tmp = silk_energy_FLP( target_ptr, sf_length_8kHz ) + 1.0;
+ for( j = 0; j < length_d_comp; j++ ) {
+ d = d_comp[ j ];
+ basis_ptr = target_ptr - d;
+ cross_corr = silk_inner_product_FLP( basis_ptr, target_ptr, sf_length_8kHz );
+ if( cross_corr > 0.0f ) {
+ energy = silk_energy_FLP( basis_ptr, sf_length_8kHz );
+ C[ k ][ d ] = (silk_float)( 2 * cross_corr / ( energy + energy_tmp ) );
+ } else {
+ C[ k ][ d ] = 0.0f;
+ }
+ }
+ target_ptr += sf_length_8kHz;
+ }
+
+ /* search over lag range and lags codebook */
+ /* scale factor for lag codebook, as a function of center lag */
+
+ CCmax = 0.0f; /* This value doesn't matter */
+ CCmax_b = -1000.0f;
+
+ CBimax = 0; /* To avoid returning undefined lag values */
+ lag = -1; /* To check if lag with strong enough correlation has been found */
+
+ if( prevLag > 0 ) {
+ if( Fs_kHz == 12 ) {
+ prevLag = silk_LSHIFT( prevLag, 1 ) / 3;
+ } else if( Fs_kHz == 16 ) {
+ prevLag = silk_RSHIFT( prevLag, 1 );
+ }
+ prevLag_log2 = silk_log2( (silk_float)prevLag );
+ } else {
+ prevLag_log2 = 0;
+ }
+
+ /* Set up stage 2 codebook based on number of subframes */
+ if( nb_subfr == PE_MAX_NB_SUBFR ) {
+ cbk_size = PE_NB_CBKS_STAGE2_EXT;
+ Lag_CB_ptr = &silk_CB_lags_stage2[ 0 ][ 0 ];
+ if( Fs_kHz == 8 && complexity > SILK_PE_MIN_COMPLEX ) {
+ /* If input is 8 khz use a larger codebook here because it is last stage */
+ nb_cbk_search = PE_NB_CBKS_STAGE2_EXT;
+ } else {
+ nb_cbk_search = PE_NB_CBKS_STAGE2;
+ }
+ } else {
+ cbk_size = PE_NB_CBKS_STAGE2_10MS;
+ Lag_CB_ptr = &silk_CB_lags_stage2_10_ms[ 0 ][ 0 ];
+ nb_cbk_search = PE_NB_CBKS_STAGE2_10MS;
+ }
+
+ for( k = 0; k < length_d_srch; k++ ) {
+ d = d_srch[ k ];
+ for( j = 0; j < nb_cbk_search; j++ ) {
+ CC[j] = 0.0f;
+ for( i = 0; i < nb_subfr; i++ ) {
+ /* Try all codebooks */
+ CC[ j ] += C[ i ][ d + matrix_ptr( Lag_CB_ptr, i, j, cbk_size )];
+ }
+ }
+ /* Find best codebook */
+ CCmax_new = -1000.0f;
+ CBimax_new = 0;
+ for( i = 0; i < nb_cbk_search; i++ ) {
+ if( CC[ i ] > CCmax_new ) {
+ CCmax_new = CC[ i ];
+ CBimax_new = i;
+ }
+ }
+
+ /* Bias towards shorter lags */
+ lag_log2 = silk_log2( (silk_float)d );
+ CCmax_new_b = CCmax_new - PE_SHORTLAG_BIAS * nb_subfr * lag_log2;
+
+ /* Bias towards previous lag */
+ if( prevLag > 0 ) {
+ delta_lag_log2_sqr = lag_log2 - prevLag_log2;
+ delta_lag_log2_sqr *= delta_lag_log2_sqr;
+ CCmax_new_b -= PE_PREVLAG_BIAS * nb_subfr * (*LTPCorr) * delta_lag_log2_sqr / ( delta_lag_log2_sqr + 0.5f );
+ }
+
+ if( CCmax_new_b > CCmax_b && /* Find maximum biased correlation */
+ CCmax_new > nb_subfr * search_thres2 /* Correlation needs to be high enough to be voiced */
+ ) {
+ CCmax_b = CCmax_new_b;
+ CCmax = CCmax_new;
+ lag = d;
+ CBimax = CBimax_new;
+ }
+ }
+
+ if( lag == -1 ) {
+ /* No suitable candidate found */
+ silk_memset( pitch_out, 0, PE_MAX_NB_SUBFR * sizeof(opus_int) );
+ *LTPCorr = 0.0f;
+ *lagIndex = 0;
+ *contourIndex = 0;
+ return 1;
+ }
+
+ /* Output normalized correlation */
+ *LTPCorr = (silk_float)( CCmax / nb_subfr );
+ silk_assert( *LTPCorr >= 0.0f );
+
+ if( Fs_kHz > 8 ) {
+ /* Search in original signal */
+
+ /* Compensate for decimation */
+ silk_assert( lag == silk_SAT16( lag ) );
+ if( Fs_kHz == 12 ) {
+ lag = silk_RSHIFT_ROUND( silk_SMULBB( lag, 3 ), 1 );
+ } else { /* Fs_kHz == 16 */
+ lag = silk_LSHIFT( lag, 1 );
+ }
+
+ lag = silk_LIMIT_int( lag, min_lag, max_lag );
+ start_lag = silk_max_int( lag - 2, min_lag );
+ end_lag = silk_min_int( lag + 2, max_lag );
+ lag_new = lag; /* to avoid undefined lag */
+ CBimax = 0; /* to avoid undefined lag */
+
+ CCmax = -1000.0f;
+
+ /* Calculate the correlations and energies needed in stage 3 */
+ silk_P_Ana_calc_corr_st3( cross_corr_st3, frame, start_lag, sf_length, nb_subfr, complexity, arch );
+ silk_P_Ana_calc_energy_st3( energies_st3, frame, start_lag, sf_length, nb_subfr, complexity );
+
+ lag_counter = 0;
+ silk_assert( lag == silk_SAT16( lag ) );
+ contour_bias = PE_FLATCONTOUR_BIAS / lag;
+
+ /* Set up cbk parameters according to complexity setting and frame length */
+ if( nb_subfr == PE_MAX_NB_SUBFR ) {
+ nb_cbk_search = (opus_int)silk_nb_cbk_searchs_stage3[ complexity ];
+ cbk_size = PE_NB_CBKS_STAGE3_MAX;
+ Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ];
+ } else {
+ nb_cbk_search = PE_NB_CBKS_STAGE3_10MS;
+ cbk_size = PE_NB_CBKS_STAGE3_10MS;
+ Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
+ }
+
+ target_ptr = &frame[ PE_LTP_MEM_LENGTH_MS * Fs_kHz ];
+ energy_tmp = silk_energy_FLP( target_ptr, nb_subfr * sf_length ) + 1.0;
+ for( d = start_lag; d <= end_lag; d++ ) {
+ for( j = 0; j < nb_cbk_search; j++ ) {
+ cross_corr = 0.0;
+ energy = energy_tmp;
+ for( k = 0; k < nb_subfr; k++ ) {
+ cross_corr += cross_corr_st3[ k ][ j ][ lag_counter ];
+ energy += energies_st3[ k ][ j ][ lag_counter ];
+ }
+ if( cross_corr > 0.0 ) {
+ CCmax_new = (silk_float)( 2 * cross_corr / energy );
+ /* Reduce depending on flatness of contour */
+ CCmax_new *= 1.0f - contour_bias * j;
+ } else {
+ CCmax_new = 0.0f;
+ }
+
+ if( CCmax_new > CCmax && ( d + (opus_int)silk_CB_lags_stage3[ 0 ][ j ] ) <= max_lag ) {
+ CCmax = CCmax_new;
+ lag_new = d;
+ CBimax = j;
+ }
+ }
+ lag_counter++;
+ }
+
+ for( k = 0; k < nb_subfr; k++ ) {
+ pitch_out[ k ] = lag_new + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size );
+ pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag, PE_MAX_LAG_MS * Fs_kHz );
+ }
+ *lagIndex = (opus_int16)( lag_new - min_lag );
+ *contourIndex = (opus_int8)CBimax;
+ } else { /* Fs_kHz == 8 */
+ /* Save Lags */
+ for( k = 0; k < nb_subfr; k++ ) {
+ pitch_out[ k ] = lag + matrix_ptr( Lag_CB_ptr, k, CBimax, cbk_size );
+ pitch_out[ k ] = silk_LIMIT( pitch_out[ k ], min_lag_8kHz, PE_MAX_LAG_MS * 8 );
+ }
+ *lagIndex = (opus_int16)( lag - min_lag_8kHz );
+ *contourIndex = (opus_int8)CBimax;
+ }
+ silk_assert( *lagIndex >= 0 );
+ /* return as voiced */
+ return 0;
+}
+
+/***********************************************************************
+ * Calculates the correlations used in stage 3 search. In order to cover
+ * the whole lag codebook for all the searched offset lags (lag +- 2),
+ * the following correlations are needed in each sub frame:
+ *
+ * sf1: lag range [-8,...,7] total 16 correlations
+ * sf2: lag range [-4,...,4] total 9 correlations
+ * sf3: lag range [-3,....4] total 8 correltions
+ * sf4: lag range [-6,....8] total 15 correlations
+ *
+ * In total 48 correlations. The direct implementation computed in worst
+ * case 4*12*5 = 240 correlations, but more likely around 120.
+ ***********************************************************************/
+static void silk_P_Ana_calc_corr_st3(
+ silk_float cross_corr_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */
+ const silk_float frame[], /* I vector to correlate */
+ opus_int start_lag, /* I start lag */
+ opus_int sf_length, /* I sub frame length */
+ opus_int nb_subfr, /* I number of subframes */
+ opus_int complexity, /* I Complexity setting */
+ int arch /* I Run-time architecture */
+)
+{
+ const silk_float *target_ptr;
+ opus_int i, j, k, lag_counter, lag_low, lag_high;
+ opus_int nb_cbk_search, delta, idx, cbk_size;
+ silk_float scratch_mem[ SCRATCH_SIZE ];
+ opus_val32 xcorr[ SCRATCH_SIZE ];
+ const opus_int8 *Lag_range_ptr, *Lag_CB_ptr;
+
+ silk_assert( complexity >= SILK_PE_MIN_COMPLEX );
+ silk_assert( complexity <= SILK_PE_MAX_COMPLEX );
+
+ if( nb_subfr == PE_MAX_NB_SUBFR ) {
+ Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ];
+ Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ];
+ nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ];
+ cbk_size = PE_NB_CBKS_STAGE3_MAX;
+ } else {
+ silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1);
+ Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ];
+ Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
+ nb_cbk_search = PE_NB_CBKS_STAGE3_10MS;
+ cbk_size = PE_NB_CBKS_STAGE3_10MS;
+ }
+
+ target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ]; /* Pointer to middle of frame */
+ for( k = 0; k < nb_subfr; k++ ) {
+ lag_counter = 0;
+
+ /* Calculate the correlations for each subframe */
+ lag_low = matrix_ptr( Lag_range_ptr, k, 0, 2 );
+ lag_high = matrix_ptr( Lag_range_ptr, k, 1, 2 );
+ silk_assert(lag_high-lag_low+1 <= SCRATCH_SIZE);
+ celt_pitch_xcorr( target_ptr, target_ptr - start_lag - lag_high, xcorr, sf_length, lag_high - lag_low + 1, arch );
+ for( j = lag_low; j <= lag_high; j++ ) {
+ silk_assert( lag_counter < SCRATCH_SIZE );
+ scratch_mem[ lag_counter ] = xcorr[ lag_high - j ];
+ lag_counter++;
+ }
+
+ delta = matrix_ptr( Lag_range_ptr, k, 0, 2 );
+ for( i = 0; i < nb_cbk_search; i++ ) {
+ /* Fill out the 3 dim array that stores the correlations for */
+ /* each code_book vector for each start lag */
+ idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta;
+ for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) {
+ silk_assert( idx + j < SCRATCH_SIZE );
+ silk_assert( idx + j < lag_counter );
+ cross_corr_st3[ k ][ i ][ j ] = scratch_mem[ idx + j ];
+ }
+ }
+ target_ptr += sf_length;
+ }
+}
+
+/********************************************************************/
+/* Calculate the energies for first two subframes. The energies are */
+/* calculated recursively. */
+/********************************************************************/
+static void silk_P_Ana_calc_energy_st3(
+ silk_float energies_st3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ][ PE_NB_STAGE3_LAGS ], /* O 3 DIM correlation array */
+ const silk_float frame[], /* I vector to correlate */
+ opus_int start_lag, /* I start lag */
+ opus_int sf_length, /* I sub frame length */
+ opus_int nb_subfr, /* I number of subframes */
+ opus_int complexity /* I Complexity setting */
+)
+{
+ const silk_float *target_ptr, *basis_ptr;
+ double energy;
+ opus_int k, i, j, lag_counter;
+ opus_int nb_cbk_search, delta, idx, cbk_size, lag_diff;
+ silk_float scratch_mem[ SCRATCH_SIZE ];
+ const opus_int8 *Lag_range_ptr, *Lag_CB_ptr;
+
+ silk_assert( complexity >= SILK_PE_MIN_COMPLEX );
+ silk_assert( complexity <= SILK_PE_MAX_COMPLEX );
+
+ if( nb_subfr == PE_MAX_NB_SUBFR ) {
+ Lag_range_ptr = &silk_Lag_range_stage3[ complexity ][ 0 ][ 0 ];
+ Lag_CB_ptr = &silk_CB_lags_stage3[ 0 ][ 0 ];
+ nb_cbk_search = silk_nb_cbk_searchs_stage3[ complexity ];
+ cbk_size = PE_NB_CBKS_STAGE3_MAX;
+ } else {
+ silk_assert( nb_subfr == PE_MAX_NB_SUBFR >> 1);
+ Lag_range_ptr = &silk_Lag_range_stage3_10_ms[ 0 ][ 0 ];
+ Lag_CB_ptr = &silk_CB_lags_stage3_10_ms[ 0 ][ 0 ];
+ nb_cbk_search = PE_NB_CBKS_STAGE3_10MS;
+ cbk_size = PE_NB_CBKS_STAGE3_10MS;
+ }
+
+ target_ptr = &frame[ silk_LSHIFT( sf_length, 2 ) ];
+ for( k = 0; k < nb_subfr; k++ ) {
+ lag_counter = 0;
+
+ /* Calculate the energy for first lag */
+ basis_ptr = target_ptr - ( start_lag + matrix_ptr( Lag_range_ptr, k, 0, 2 ) );
+ energy = silk_energy_FLP( basis_ptr, sf_length ) + 1e-3;
+ silk_assert( energy >= 0.0 );
+ scratch_mem[lag_counter] = (silk_float)energy;
+ lag_counter++;
+
+ lag_diff = ( matrix_ptr( Lag_range_ptr, k, 1, 2 ) - matrix_ptr( Lag_range_ptr, k, 0, 2 ) + 1 );
+ for( i = 1; i < lag_diff; i++ ) {
+ /* remove part outside new window */
+ energy -= basis_ptr[sf_length - i] * (double)basis_ptr[sf_length - i];
+ silk_assert( energy >= 0.0 );
+
+ /* add part that comes into window */
+ energy += basis_ptr[ -i ] * (double)basis_ptr[ -i ];
+ silk_assert( energy >= 0.0 );
+ silk_assert( lag_counter < SCRATCH_SIZE );
+ scratch_mem[lag_counter] = (silk_float)energy;
+ lag_counter++;
+ }
+
+ delta = matrix_ptr( Lag_range_ptr, k, 0, 2 );
+ for( i = 0; i < nb_cbk_search; i++ ) {
+ /* Fill out the 3 dim array that stores the correlations for */
+ /* each code_book vector for each start lag */
+ idx = matrix_ptr( Lag_CB_ptr, k, i, cbk_size ) - delta;
+ for( j = 0; j < PE_NB_STAGE3_LAGS; j++ ) {
+ silk_assert( idx + j < SCRATCH_SIZE );
+ silk_assert( idx + j < lag_counter );
+ energies_st3[ k ][ i ][ j ] = scratch_mem[ idx + j ];
+ silk_assert( energies_st3[ k ][ i ][ j ] >= 0.0f );
+ }
+ }
+ target_ptr += sf_length;
+ }
+}
diff --git a/drivers/opus/silk/float/prefilter_FLP.c b/drivers/opus/silk/float/prefilter_FLP.c
new file mode 100644
index 0000000000..0298ef2f8e
--- /dev/null
+++ b/drivers/opus/silk/float/prefilter_FLP.c
@@ -0,0 +1,206 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/float/main_FLP.h"
+#include "opus/silk/tuning_parameters.h"
+
+/*
+* Prefilter for finding Quantizer input signal
+*/
+static OPUS_INLINE void silk_prefilt_FLP(
+ silk_prefilter_state_FLP *P, /* I/O state */
+ silk_float st_res[], /* I */
+ silk_float xw[], /* O */
+ silk_float *HarmShapeFIR, /* I */
+ silk_float Tilt, /* I */
+ silk_float LF_MA_shp, /* I */
+ silk_float LF_AR_shp, /* I */
+ opus_int lag, /* I */
+ opus_int length /* I */
+);
+
+static void silk_warped_LPC_analysis_filter_FLP(
+ silk_float state[], /* I/O State [order + 1] */
+ silk_float res[], /* O Residual signal [length] */
+ const silk_float coef[], /* I Coefficients [order] */
+ const silk_float input[], /* I Input signal [length] */
+ const silk_float lambda, /* I Warping factor */
+ const opus_int length, /* I Length of input signal */
+ const opus_int order /* I Filter order (even) */
+)
+{
+ opus_int n, i;
+ silk_float acc, tmp1, tmp2;
+
+ /* Order must be even */
+ silk_assert( ( order & 1 ) == 0 );
+
+ for( n = 0; n < length; n++ ) {
+ /* Output of lowpass section */
+ tmp2 = state[ 0 ] + lambda * state[ 1 ];
+ state[ 0 ] = input[ n ];
+ /* Output of allpass section */
+ tmp1 = state[ 1 ] + lambda * ( state[ 2 ] - tmp2 );
+ state[ 1 ] = tmp2;
+ acc = coef[ 0 ] * tmp2;
+ /* Loop over allpass sections */
+ for( i = 2; i < order; i += 2 ) {
+ /* Output of allpass section */
+ tmp2 = state[ i ] + lambda * ( state[ i + 1 ] - tmp1 );
+ state[ i ] = tmp1;
+ acc += coef[ i - 1 ] * tmp1;
+ /* Output of allpass section */
+ tmp1 = state[ i + 1 ] + lambda * ( state[ i + 2 ] - tmp2 );
+ state[ i + 1 ] = tmp2;
+ acc += coef[ i ] * tmp2;
+ }
+ state[ order ] = tmp1;
+ acc += coef[ order - 1 ] * tmp1;
+ res[ n ] = input[ n ] - acc;
+ }
+}
+
+/*
+* silk_prefilter. Main prefilter function
+*/
+void silk_prefilter_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ const silk_encoder_control_FLP *psEncCtrl, /* I Encoder control FLP */
+ silk_float xw[], /* O Weighted signal */
+ const silk_float x[] /* I Speech signal */
+)
+{
+ silk_prefilter_state_FLP *P = &psEnc->sPrefilt;
+ opus_int j, k, lag;
+ silk_float HarmShapeGain, Tilt, LF_MA_shp, LF_AR_shp;
+ silk_float B[ 2 ];
+ const silk_float *AR1_shp;
+ const silk_float *px;
+ silk_float *pxw;
+ silk_float HarmShapeFIR[ 3 ];
+ silk_float st_res[ MAX_SUB_FRAME_LENGTH + MAX_LPC_ORDER ];
+
+ /* Set up pointers */
+ px = x;
+ pxw = xw;
+ lag = P->lagPrev;
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ /* Update Variables that change per sub frame */
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ lag = psEncCtrl->pitchL[ k ];
+ }
+
+ /* Noise shape parameters */
+ HarmShapeGain = psEncCtrl->HarmShapeGain[ k ] * ( 1.0f - psEncCtrl->HarmBoost[ k ] );
+ HarmShapeFIR[ 0 ] = 0.25f * HarmShapeGain;
+ HarmShapeFIR[ 1 ] = 32767.0f / 65536.0f * HarmShapeGain;
+ HarmShapeFIR[ 2 ] = 0.25f * HarmShapeGain;
+ Tilt = psEncCtrl->Tilt[ k ];
+ LF_MA_shp = psEncCtrl->LF_MA_shp[ k ];
+ LF_AR_shp = psEncCtrl->LF_AR_shp[ k ];
+ AR1_shp = &psEncCtrl->AR1[ k * MAX_SHAPE_LPC_ORDER ];
+
+ /* Short term FIR filtering */
+ silk_warped_LPC_analysis_filter_FLP( P->sAR_shp, st_res, AR1_shp, px,
+ (silk_float)psEnc->sCmn.warping_Q16 / 65536.0f, psEnc->sCmn.subfr_length, psEnc->sCmn.shapingLPCOrder );
+
+ /* Reduce (mainly) low frequencies during harmonic emphasis */
+ B[ 0 ] = psEncCtrl->GainsPre[ k ];
+ B[ 1 ] = -psEncCtrl->GainsPre[ k ] *
+ ( psEncCtrl->HarmBoost[ k ] * HarmShapeGain + INPUT_TILT + psEncCtrl->coding_quality * HIGH_RATE_INPUT_TILT );
+ pxw[ 0 ] = B[ 0 ] * st_res[ 0 ] + B[ 1 ] * P->sHarmHP;
+ for( j = 1; j < psEnc->sCmn.subfr_length; j++ ) {
+ pxw[ j ] = B[ 0 ] * st_res[ j ] + B[ 1 ] * st_res[ j - 1 ];
+ }
+ P->sHarmHP = st_res[ psEnc->sCmn.subfr_length - 1 ];
+
+ silk_prefilt_FLP( P, pxw, pxw, HarmShapeFIR, Tilt, LF_MA_shp, LF_AR_shp, lag, psEnc->sCmn.subfr_length );
+
+ px += psEnc->sCmn.subfr_length;
+ pxw += psEnc->sCmn.subfr_length;
+ }
+ P->lagPrev = psEncCtrl->pitchL[ psEnc->sCmn.nb_subfr - 1 ];
+}
+
+/*
+* Prefilter for finding Quantizer input signal
+*/
+static OPUS_INLINE void silk_prefilt_FLP(
+ silk_prefilter_state_FLP *P, /* I/O state */
+ silk_float st_res[], /* I */
+ silk_float xw[], /* O */
+ silk_float *HarmShapeFIR, /* I */
+ silk_float Tilt, /* I */
+ silk_float LF_MA_shp, /* I */
+ silk_float LF_AR_shp, /* I */
+ opus_int lag, /* I */
+ opus_int length /* I */
+)
+{
+ opus_int i;
+ opus_int idx, LTP_shp_buf_idx;
+ silk_float n_Tilt, n_LF, n_LTP;
+ silk_float sLF_AR_shp, sLF_MA_shp;
+ silk_float *LTP_shp_buf;
+
+ /* To speed up use temp variables instead of using the struct */
+ LTP_shp_buf = P->sLTP_shp;
+ LTP_shp_buf_idx = P->sLTP_shp_buf_idx;
+ sLF_AR_shp = P->sLF_AR_shp;
+ sLF_MA_shp = P->sLF_MA_shp;
+
+ for( i = 0; i < length; i++ ) {
+ if( lag > 0 ) {
+ silk_assert( HARM_SHAPE_FIR_TAPS == 3 );
+ idx = lag + LTP_shp_buf_idx;
+ n_LTP = LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 - 1) & LTP_MASK ] * HarmShapeFIR[ 0 ];
+ n_LTP += LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 ) & LTP_MASK ] * HarmShapeFIR[ 1 ];
+ n_LTP += LTP_shp_buf[ ( idx - HARM_SHAPE_FIR_TAPS / 2 + 1) & LTP_MASK ] * HarmShapeFIR[ 2 ];
+ } else {
+ n_LTP = 0;
+ }
+
+ n_Tilt = sLF_AR_shp * Tilt;
+ n_LF = sLF_AR_shp * LF_AR_shp + sLF_MA_shp * LF_MA_shp;
+
+ sLF_AR_shp = st_res[ i ] - n_Tilt;
+ sLF_MA_shp = sLF_AR_shp - n_LF;
+
+ LTP_shp_buf_idx = ( LTP_shp_buf_idx - 1 ) & LTP_MASK;
+ LTP_shp_buf[ LTP_shp_buf_idx ] = sLF_MA_shp;
+
+ xw[ i ] = sLF_MA_shp - n_LTP;
+ }
+ /* Copy temp variable back to state */
+ P->sLF_AR_shp = sLF_AR_shp;
+ P->sLF_MA_shp = sLF_MA_shp;
+ P->sLTP_shp_buf_idx = LTP_shp_buf_idx;
+}
diff --git a/drivers/opus/silk/float/process_gains_FLP.c b/drivers/opus/silk/float/process_gains_FLP.c
new file mode 100644
index 0000000000..bd5e7ee7a2
--- /dev/null
+++ b/drivers/opus/silk/float/process_gains_FLP.c
@@ -0,0 +1,103 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/float/main_FLP.h"
+#include "opus/silk/tuning_parameters.h"
+
+/* Processing of gains */
+void silk_process_gains_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ opus_int condCoding /* I The type of conditional coding to use */
+)
+{
+ silk_shape_state_FLP *psShapeSt = &psEnc->sShape;
+ opus_int k;
+ opus_int32 pGains_Q16[ MAX_NB_SUBFR ];
+ silk_float s, InvMaxSqrVal, gain, quant_offset;
+
+ /* Gain reduction when LTP coding gain is high */
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ s = 1.0f - 0.5f * silk_sigmoid( 0.25f * ( psEncCtrl->LTPredCodGain - 12.0f ) );
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ psEncCtrl->Gains[ k ] *= s;
+ }
+ }
+
+ /* Limit the quantized signal */
+ InvMaxSqrVal = ( silk_float )( pow( 2.0f, 0.33f * ( 21.0f - psEnc->sCmn.SNR_dB_Q7 * ( 1 / 128.0f ) ) ) / psEnc->sCmn.subfr_length );
+
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ /* Soft limit on ratio residual energy and squared gains */
+ gain = psEncCtrl->Gains[ k ];
+ gain = ( silk_float )sqrt( gain * gain + psEncCtrl->ResNrg[ k ] * InvMaxSqrVal );
+ psEncCtrl->Gains[ k ] = silk_min_float( gain, 32767.0f );
+ }
+
+ /* Prepare gains for noise shaping quantization */
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ pGains_Q16[ k ] = (opus_int32)( psEncCtrl->Gains[ k ] * 65536.0f );
+ }
+
+ /* Save unquantized gains and gain Index */
+ silk_memcpy( psEncCtrl->GainsUnq_Q16, pGains_Q16, psEnc->sCmn.nb_subfr * sizeof( opus_int32 ) );
+ psEncCtrl->lastGainIndexPrev = psShapeSt->LastGainIndex;
+
+ /* Quantize gains */
+ silk_gains_quant( psEnc->sCmn.indices.GainsIndices, pGains_Q16,
+ &psShapeSt->LastGainIndex, condCoding == CODE_CONDITIONALLY, psEnc->sCmn.nb_subfr );
+
+ /* Overwrite unquantized gains with quantized gains and convert back to Q0 from Q16 */
+ for( k = 0; k < psEnc->sCmn.nb_subfr; k++ ) {
+ psEncCtrl->Gains[ k ] = pGains_Q16[ k ] / 65536.0f;
+ }
+
+ /* Set quantizer offset for voiced signals. Larger offset when LTP coding gain is low or tilt is high (ie low-pass) */
+ if( psEnc->sCmn.indices.signalType == TYPE_VOICED ) {
+ if( psEncCtrl->LTPredCodGain + psEnc->sCmn.input_tilt_Q15 * ( 1.0f / 32768.0f ) > 1.0f ) {
+ psEnc->sCmn.indices.quantOffsetType = 0;
+ } else {
+ psEnc->sCmn.indices.quantOffsetType = 1;
+ }
+ }
+
+ /* Quantizer boundary adjustment */
+ quant_offset = silk_Quantization_Offsets_Q10[ psEnc->sCmn.indices.signalType >> 1 ][ psEnc->sCmn.indices.quantOffsetType ] / 1024.0f;
+ psEncCtrl->Lambda = LAMBDA_OFFSET
+ + LAMBDA_DELAYED_DECISIONS * psEnc->sCmn.nStatesDelayedDecision
+ + LAMBDA_SPEECH_ACT * psEnc->sCmn.speech_activity_Q8 * ( 1.0f / 256.0f )
+ + LAMBDA_INPUT_QUALITY * psEncCtrl->input_quality
+ + LAMBDA_CODING_QUALITY * psEncCtrl->coding_quality
+ + LAMBDA_QUANT_OFFSET * quant_offset;
+
+ silk_assert( psEncCtrl->Lambda > 0.0f );
+ silk_assert( psEncCtrl->Lambda < 2.0f );
+}
diff --git a/drivers/opus/silk/float/regularize_correlations_FLP.c b/drivers/opus/silk/float/regularize_correlations_FLP.c
new file mode 100644
index 0000000000..397e45b10b
--- /dev/null
+++ b/drivers/opus/silk/float/regularize_correlations_FLP.c
@@ -0,0 +1,48 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/float/main_FLP.h"
+
+/* Add noise to matrix diagonal */
+void silk_regularize_correlations_FLP(
+ silk_float *XX, /* I/O Correlation matrices */
+ silk_float *xx, /* I/O Correlation values */
+ const silk_float noise, /* I Noise energy to add */
+ const opus_int D /* I Dimension of XX */
+)
+{
+ opus_int i;
+
+ for( i = 0; i < D; i++ ) {
+ matrix_ptr( &XX[ 0 ], i, i, D ) += noise;
+ }
+ xx[ 0 ] += noise;
+}
diff --git a/drivers/opus/silk/float/residual_energy_FLP.c b/drivers/opus/silk/float/residual_energy_FLP.c
new file mode 100644
index 0000000000..50bc728b71
--- /dev/null
+++ b/drivers/opus/silk/float/residual_energy_FLP.c
@@ -0,0 +1,117 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/float/main_FLP.h"
+
+#define MAX_ITERATIONS_RESIDUAL_NRG 10
+#define REGULARIZATION_FACTOR 1e-8f
+
+/* Residual energy: nrg = wxx - 2 * wXx * c + c' * wXX * c */
+silk_float silk_residual_energy_covar_FLP( /* O Weighted residual energy */
+ const silk_float *c, /* I Filter coefficients */
+ silk_float *wXX, /* I/O Weighted correlation matrix, reg. out */
+ const silk_float *wXx, /* I Weighted correlation vector */
+ const silk_float wxx, /* I Weighted correlation value */
+ const opus_int D /* I Dimension */
+)
+{
+ opus_int i, j, k;
+ silk_float tmp, nrg = 0.0f, regularization;
+
+ /* Safety checks */
+ silk_assert( D >= 0 );
+
+ regularization = REGULARIZATION_FACTOR * ( wXX[ 0 ] + wXX[ D * D - 1 ] );
+ for( k = 0; k < MAX_ITERATIONS_RESIDUAL_NRG; k++ ) {
+ nrg = wxx;
+
+ tmp = 0.0f;
+ for( i = 0; i < D; i++ ) {
+ tmp += wXx[ i ] * c[ i ];
+ }
+ nrg -= 2.0f * tmp;
+
+ /* compute c' * wXX * c, assuming wXX is symmetric */
+ for( i = 0; i < D; i++ ) {
+ tmp = 0.0f;
+ for( j = i + 1; j < D; j++ ) {
+ tmp += matrix_c_ptr( wXX, i, j, D ) * c[ j ];
+ }
+ nrg += c[ i ] * ( 2.0f * tmp + matrix_c_ptr( wXX, i, i, D ) * c[ i ] );
+ }
+ if( nrg > 0 ) {
+ break;
+ } else {
+ /* Add white noise */
+ for( i = 0; i < D; i++ ) {
+ matrix_c_ptr( wXX, i, i, D ) += regularization;
+ }
+ /* Increase noise for next run */
+ regularization *= 2.0f;
+ }
+ }
+ if( k == MAX_ITERATIONS_RESIDUAL_NRG ) {
+ silk_assert( nrg == 0 );
+ nrg = 1.0f;
+ }
+
+ return nrg;
+}
+
+/* Calculates residual energies of input subframes where all subframes have LPC_order */
+/* of preceding samples */
+void silk_residual_energy_FLP(
+ silk_float nrgs[ MAX_NB_SUBFR ], /* O Residual energy per subframe */
+ const silk_float x[], /* I Input signal */
+ silk_float a[ 2 ][ MAX_LPC_ORDER ], /* I AR coefs for each frame half */
+ const silk_float gains[], /* I Quantization gains */
+ const opus_int subfr_length, /* I Subframe length */
+ const opus_int nb_subfr, /* I number of subframes */
+ const opus_int LPC_order /* I LPC order */
+)
+{
+ opus_int shift;
+ silk_float *LPC_res_ptr, LPC_res[ ( MAX_FRAME_LENGTH + MAX_NB_SUBFR * MAX_LPC_ORDER ) / 2 ];
+
+ LPC_res_ptr = LPC_res + LPC_order;
+ shift = LPC_order + subfr_length;
+
+ /* Filter input to create the LPC residual for each frame half, and measure subframe energies */
+ silk_LPC_analysis_filter_FLP( LPC_res, a[ 0 ], x + 0 * shift, 2 * shift, LPC_order );
+ nrgs[ 0 ] = ( silk_float )( gains[ 0 ] * gains[ 0 ] * silk_energy_FLP( LPC_res_ptr + 0 * shift, subfr_length ) );
+ nrgs[ 1 ] = ( silk_float )( gains[ 1 ] * gains[ 1 ] * silk_energy_FLP( LPC_res_ptr + 1 * shift, subfr_length ) );
+
+ if( nb_subfr == MAX_NB_SUBFR ) {
+ silk_LPC_analysis_filter_FLP( LPC_res, a[ 1 ], x + 2 * shift, 2 * shift, LPC_order );
+ nrgs[ 2 ] = ( silk_float )( gains[ 2 ] * gains[ 2 ] * silk_energy_FLP( LPC_res_ptr + 0 * shift, subfr_length ) );
+ nrgs[ 3 ] = ( silk_float )( gains[ 3 ] * gains[ 3 ] * silk_energy_FLP( LPC_res_ptr + 1 * shift, subfr_length ) );
+ }
+}
diff --git a/drivers/opus/silk/float/scale_copy_vector_FLP.c b/drivers/opus/silk/float/scale_copy_vector_FLP.c
new file mode 100644
index 0000000000..8c5bfadb3a
--- /dev/null
+++ b/drivers/opus/silk/float/scale_copy_vector_FLP.c
@@ -0,0 +1,57 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/float/SigProc_FLP.h"
+
+/* copy and multiply a vector by a constant */
+void silk_scale_copy_vector_FLP(
+ silk_float *data_out,
+ const silk_float *data_in,
+ silk_float gain,
+ opus_int dataSize
+)
+{
+ opus_int i, dataSize4;
+
+ /* 4x unrolled loop */
+ dataSize4 = dataSize & 0xFFFC;
+ for( i = 0; i < dataSize4; i += 4 ) {
+ data_out[ i + 0 ] = gain * data_in[ i + 0 ];
+ data_out[ i + 1 ] = gain * data_in[ i + 1 ];
+ data_out[ i + 2 ] = gain * data_in[ i + 2 ];
+ data_out[ i + 3 ] = gain * data_in[ i + 3 ];
+ }
+
+ /* any remaining elements */
+ for( ; i < dataSize; i++ ) {
+ data_out[ i ] = gain * data_in[ i ];
+ }
+}
diff --git a/drivers/opus/silk/float/scale_vector_FLP.c b/drivers/opus/silk/float/scale_vector_FLP.c
new file mode 100644
index 0000000000..191b3d6041
--- /dev/null
+++ b/drivers/opus/silk/float/scale_vector_FLP.c
@@ -0,0 +1,56 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/float/SigProc_FLP.h"
+
+/* multiply a vector by a constant */
+void silk_scale_vector_FLP(
+ silk_float *data1,
+ silk_float gain,
+ opus_int dataSize
+)
+{
+ opus_int i, dataSize4;
+
+ /* 4x unrolled loop */
+ dataSize4 = dataSize & 0xFFFC;
+ for( i = 0; i < dataSize4; i += 4 ) {
+ data1[ i + 0 ] *= gain;
+ data1[ i + 1 ] *= gain;
+ data1[ i + 2 ] *= gain;
+ data1[ i + 3 ] *= gain;
+ }
+
+ /* any remaining elements */
+ for( ; i < dataSize; i++ ) {
+ data1[ i ] *= gain;
+ }
+}
diff --git a/drivers/opus/silk/float/schur_FLP.c b/drivers/opus/silk/float/schur_FLP.c
new file mode 100644
index 0000000000..631dbe093a
--- /dev/null
+++ b/drivers/opus/silk/float/schur_FLP.c
@@ -0,0 +1,70 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/float/SigProc_FLP.h"
+
+silk_float silk_schur_FLP( /* O returns residual energy */
+ silk_float refl_coef[], /* O reflection coefficients (length order) */
+ const silk_float auto_corr[], /* I autocorrelation sequence (length order+1) */
+ opus_int order /* I order */
+)
+{
+ opus_int k, n;
+ silk_float C[ SILK_MAX_ORDER_LPC + 1 ][ 2 ];
+ silk_float Ctmp1, Ctmp2, rc_tmp;
+
+ silk_assert( order==6||order==8||order==10||order==12||order==14||order==16 );
+
+ /* Copy correlations */
+ for( k = 0; k < order+1; k++ ) {
+ C[ k ][ 0 ] = C[ k ][ 1 ] = auto_corr[ k ];
+ }
+
+ for( k = 0; k < order; k++ ) {
+ /* Get reflection coefficient */
+ rc_tmp = -C[ k + 1 ][ 0 ] / silk_max_float( C[ 0 ][ 1 ], 1e-9f );
+
+ /* Save the output */
+ refl_coef[ k ] = rc_tmp;
+
+ /* Update correlations */
+ for( n = 0; n < order - k; n++ ) {
+ Ctmp1 = C[ n + k + 1 ][ 0 ];
+ Ctmp2 = C[ n ][ 1 ];
+ C[ n + k + 1 ][ 0 ] = Ctmp1 + Ctmp2 * rc_tmp;
+ C[ n ][ 1 ] = Ctmp2 + Ctmp1 * rc_tmp;
+ }
+ }
+
+ /* Return residual energy */
+ return C[ 0 ][ 1 ];
+}
+
diff --git a/drivers/opus/silk/float/solve_LS_FLP.c b/drivers/opus/silk/float/solve_LS_FLP.c
new file mode 100644
index 0000000000..b3757ce03f
--- /dev/null
+++ b/drivers/opus/silk/float/solve_LS_FLP.c
@@ -0,0 +1,207 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/float/main_FLP.h"
+#include "opus/silk/tuning_parameters.h"
+
+/**********************************************************************
+ * LDL Factorisation. Finds the upper triangular matrix L and the diagonal
+ * Matrix D (only the diagonal elements returned in a vector)such that
+ * the symmetric matric A is given by A = L*D*L'.
+ **********************************************************************/
+static OPUS_INLINE void silk_LDL_FLP(
+ silk_float *A, /* I/O Pointer to Symetric Square Matrix */
+ opus_int M, /* I Size of Matrix */
+ silk_float *L, /* I/O Pointer to Square Upper triangular Matrix */
+ silk_float *Dinv /* I/O Pointer to vector holding the inverse diagonal elements of D */
+);
+
+/**********************************************************************
+ * Function to solve linear equation Ax = b, when A is a MxM lower
+ * triangular matrix, with ones on the diagonal.
+ **********************************************************************/
+static OPUS_INLINE void silk_SolveWithLowerTriangularWdiagOnes_FLP(
+ const silk_float *L, /* I Pointer to Lower Triangular Matrix */
+ opus_int M, /* I Dim of Matrix equation */
+ const silk_float *b, /* I b Vector */
+ silk_float *x /* O x Vector */
+);
+
+/**********************************************************************
+ * Function to solve linear equation (A^T)x = b, when A is a MxM lower
+ * triangular, with ones on the diagonal. (ie then A^T is upper triangular)
+ **********************************************************************/
+static OPUS_INLINE void silk_SolveWithUpperTriangularFromLowerWdiagOnes_FLP(
+ const silk_float *L, /* I Pointer to Lower Triangular Matrix */
+ opus_int M, /* I Dim of Matrix equation */
+ const silk_float *b, /* I b Vector */
+ silk_float *x /* O x Vector */
+);
+
+/**********************************************************************
+ * Function to solve linear equation Ax = b, when A is a MxM
+ * symmetric square matrix - using LDL factorisation
+ **********************************************************************/
+void silk_solve_LDL_FLP(
+ silk_float *A, /* I/O Symmetric square matrix, out: reg. */
+ const opus_int M, /* I Size of matrix */
+ const silk_float *b, /* I Pointer to b vector */
+ silk_float *x /* O Pointer to x solution vector */
+)
+{
+ opus_int i;
+ silk_float L[ MAX_MATRIX_SIZE ][ MAX_MATRIX_SIZE ];
+ silk_float T[ MAX_MATRIX_SIZE ];
+ silk_float Dinv[ MAX_MATRIX_SIZE ]; /* inverse diagonal elements of D*/
+
+ silk_assert( M <= MAX_MATRIX_SIZE );
+
+ /***************************************************
+ Factorize A by LDL such that A = L*D*(L^T),
+ where L is lower triangular with ones on diagonal
+ ****************************************************/
+ silk_LDL_FLP( A, M, &L[ 0 ][ 0 ], Dinv );
+
+ /****************************************************
+ * substitute D*(L^T) = T. ie:
+ L*D*(L^T)*x = b => L*T = b <=> T = inv(L)*b
+ ******************************************************/
+ silk_SolveWithLowerTriangularWdiagOnes_FLP( &L[ 0 ][ 0 ], M, b, T );
+
+ /****************************************************
+ D*(L^T)*x = T <=> (L^T)*x = inv(D)*T, because D is
+ diagonal just multiply with 1/d_i
+ ****************************************************/
+ for( i = 0; i < M; i++ ) {
+ T[ i ] = T[ i ] * Dinv[ i ];
+ }
+ /****************************************************
+ x = inv(L') * inv(D) * T
+ *****************************************************/
+ silk_SolveWithUpperTriangularFromLowerWdiagOnes_FLP( &L[ 0 ][ 0 ], M, T, x );
+}
+
+static OPUS_INLINE void silk_SolveWithUpperTriangularFromLowerWdiagOnes_FLP(
+ const silk_float *L, /* I Pointer to Lower Triangular Matrix */
+ opus_int M, /* I Dim of Matrix equation */
+ const silk_float *b, /* I b Vector */
+ silk_float *x /* O x Vector */
+)
+{
+ opus_int i, j;
+ silk_float temp;
+ const silk_float *ptr1;
+
+ for( i = M - 1; i >= 0; i-- ) {
+ ptr1 = matrix_adr( L, 0, i, M );
+ temp = 0;
+ for( j = M - 1; j > i ; j-- ) {
+ temp += ptr1[ j * M ] * x[ j ];
+ }
+ temp = b[ i ] - temp;
+ x[ i ] = temp;
+ }
+}
+
+static OPUS_INLINE void silk_SolveWithLowerTriangularWdiagOnes_FLP(
+ const silk_float *L, /* I Pointer to Lower Triangular Matrix */
+ opus_int M, /* I Dim of Matrix equation */
+ const silk_float *b, /* I b Vector */
+ silk_float *x /* O x Vector */
+)
+{
+ opus_int i, j;
+ silk_float temp;
+ const silk_float *ptr1;
+
+ for( i = 0; i < M; i++ ) {
+ ptr1 = matrix_adr( L, i, 0, M );
+ temp = 0;
+ for( j = 0; j < i; j++ ) {
+ temp += ptr1[ j ] * x[ j ];
+ }
+ temp = b[ i ] - temp;
+ x[ i ] = temp;
+ }
+}
+
+static OPUS_INLINE void silk_LDL_FLP(
+ silk_float *A, /* I/O Pointer to Symetric Square Matrix */
+ opus_int M, /* I Size of Matrix */
+ silk_float *L, /* I/O Pointer to Square Upper triangular Matrix */
+ silk_float *Dinv /* I/O Pointer to vector holding the inverse diagonal elements of D */
+)
+{
+ opus_int i, j, k, loop_count, err = 1;
+ silk_float *ptr1, *ptr2;
+ double temp, diag_min_value;
+ silk_float v[ MAX_MATRIX_SIZE ], D[ MAX_MATRIX_SIZE ]; /* temp arrays*/
+
+ silk_assert( M <= MAX_MATRIX_SIZE );
+
+ diag_min_value = FIND_LTP_COND_FAC * 0.5f * ( A[ 0 ] + A[ M * M - 1 ] );
+ for( loop_count = 0; loop_count < M && err == 1; loop_count++ ) {
+ err = 0;
+ for( j = 0; j < M; j++ ) {
+ ptr1 = matrix_adr( L, j, 0, M );
+ temp = matrix_ptr( A, j, j, M ); /* element in row j column j*/
+ for( i = 0; i < j; i++ ) {
+ v[ i ] = ptr1[ i ] * D[ i ];
+ temp -= ptr1[ i ] * v[ i ];
+ }
+ if( temp < diag_min_value ) {
+ /* Badly conditioned matrix: add white noise and run again */
+ temp = ( loop_count + 1 ) * diag_min_value - temp;
+ for( i = 0; i < M; i++ ) {
+ matrix_ptr( A, i, i, M ) += ( silk_float )temp;
+ }
+ err = 1;
+ break;
+ }
+ D[ j ] = ( silk_float )temp;
+ Dinv[ j ] = ( silk_float )( 1.0f / temp );
+ matrix_ptr( L, j, j, M ) = 1.0f;
+
+ ptr1 = matrix_adr( A, j, 0, M );
+ ptr2 = matrix_adr( L, j + 1, 0, M);
+ for( i = j + 1; i < M; i++ ) {
+ temp = 0.0;
+ for( k = 0; k < j; k++ ) {
+ temp += ptr2[ k ] * v[ k ];
+ }
+ matrix_ptr( L, i, j, M ) = ( silk_float )( ( ptr1[ i ] - temp ) * Dinv[ j ] );
+ ptr2 += M; /* go to next column*/
+ }
+ }
+ }
+ silk_assert( err == 0 );
+}
+
diff --git a/drivers/opus/silk/float/sort_FLP.c b/drivers/opus/silk/float/sort_FLP.c
new file mode 100644
index 0000000000..f2570503a5
--- /dev/null
+++ b/drivers/opus/silk/float/sort_FLP.c
@@ -0,0 +1,83 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+/* Insertion sort (fast for already almost sorted arrays): */
+/* Best case: O(n) for an already sorted array */
+/* Worst case: O(n^2) for an inversely sorted array */
+
+#include "opus/silk/typedef.h"
+#include "opus/silk/float/SigProc_FLP.h"
+
+void silk_insertion_sort_decreasing_FLP(
+ silk_float *a, /* I/O Unsorted / Sorted vector */
+ opus_int *idx, /* O Index vector for the sorted elements */
+ const opus_int L, /* I Vector length */
+ const opus_int K /* I Number of correctly sorted positions */
+)
+{
+ silk_float value;
+ opus_int i, j;
+
+ /* Safety checks */
+ silk_assert( K > 0 );
+ silk_assert( L > 0 );
+ silk_assert( L >= K );
+
+ /* Write start indices in index vector */
+ for( i = 0; i < K; i++ ) {
+ idx[ i ] = i;
+ }
+
+ /* Sort vector elements by value, decreasing order */
+ for( i = 1; i < K; i++ ) {
+ value = a[ i ];
+ for( j = i - 1; ( j >= 0 ) && ( value > a[ j ] ); j-- ) {
+ a[ j + 1 ] = a[ j ]; /* Shift value */
+ idx[ j + 1 ] = idx[ j ]; /* Shift index */
+ }
+ a[ j + 1 ] = value; /* Write value */
+ idx[ j + 1 ] = i; /* Write index */
+ }
+
+ /* If less than L values are asked check the remaining values, */
+ /* but only spend CPU to ensure that the K first values are correct */
+ for( i = K; i < L; i++ ) {
+ value = a[ i ];
+ if( value > a[ K - 1 ] ) {
+ for( j = K - 2; ( j >= 0 ) && ( value > a[ j ] ); j-- ) {
+ a[ j + 1 ] = a[ j ]; /* Shift value */
+ idx[ j + 1 ] = idx[ j ]; /* Shift index */
+ }
+ a[ j + 1 ] = value; /* Write value */
+ idx[ j + 1 ] = i; /* Write index */
+ }
+ }
+}
diff --git a/drivers/opus/silk/float/structs_FLP.h b/drivers/opus/silk/float/structs_FLP.h
new file mode 100644
index 0000000000..798aec2f43
--- /dev/null
+++ b/drivers/opus/silk/float/structs_FLP.h
@@ -0,0 +1,131 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_STRUCTS_FLP_H
+#define SILK_STRUCTS_FLP_H
+
+#include "opus/silk/typedef.h"
+#include "opus/silk/silk_main.h"
+#include "opus/silk/structs.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/********************************/
+/* Noise shaping analysis state */
+/********************************/
+typedef struct {
+ opus_int8 LastGainIndex;
+ silk_float HarmBoost_smth;
+ silk_float HarmShapeGain_smth;
+ silk_float Tilt_smth;
+} silk_shape_state_FLP;
+
+/********************************/
+/* Prefilter state */
+/********************************/
+typedef struct {
+ silk_float sLTP_shp[ LTP_BUF_LENGTH ];
+ silk_float sAR_shp[ MAX_SHAPE_LPC_ORDER + 1 ];
+ opus_int sLTP_shp_buf_idx;
+ silk_float sLF_AR_shp;
+ silk_float sLF_MA_shp;
+ silk_float sHarmHP;
+ opus_int32 rand_seed;
+ opus_int lagPrev;
+} silk_prefilter_state_FLP;
+
+/********************************/
+/* Encoder state FLP */
+/********************************/
+typedef struct {
+ silk_encoder_state sCmn; /* Common struct, shared with fixed-point code */
+ silk_shape_state_FLP sShape; /* Noise shaping state */
+ silk_prefilter_state_FLP sPrefilt; /* Prefilter State */
+
+ /* Buffer for find pitch and noise shape analysis */
+ silk_float x_buf[ 2 * MAX_FRAME_LENGTH + LA_SHAPE_MAX ];/* Buffer for find pitch and noise shape analysis */
+ silk_float LTPCorr; /* Normalized correlation from pitch lag estimator */
+} silk_encoder_state_FLP;
+
+/************************/
+/* Encoder control FLP */
+/************************/
+typedef struct {
+ /* Prediction and coding parameters */
+ silk_float Gains[ MAX_NB_SUBFR ];
+ silk_float PredCoef[ 2 ][ MAX_LPC_ORDER ]; /* holds interpolated and final coefficients */
+ silk_float LTPCoef[LTP_ORDER * MAX_NB_SUBFR];
+ silk_float LTP_scale;
+ opus_int pitchL[ MAX_NB_SUBFR ];
+
+ /* Noise shaping parameters */
+ silk_float AR1[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ];
+ silk_float AR2[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ];
+ silk_float LF_MA_shp[ MAX_NB_SUBFR ];
+ silk_float LF_AR_shp[ MAX_NB_SUBFR ];
+ silk_float GainsPre[ MAX_NB_SUBFR ];
+ silk_float HarmBoost[ MAX_NB_SUBFR ];
+ silk_float Tilt[ MAX_NB_SUBFR ];
+ silk_float HarmShapeGain[ MAX_NB_SUBFR ];
+ silk_float Lambda;
+ silk_float input_quality;
+ silk_float coding_quality;
+
+ /* Measures */
+ silk_float sparseness;
+ silk_float predGain;
+ silk_float LTPredCodGain;
+ silk_float ResNrg[ MAX_NB_SUBFR ]; /* Residual energy per subframe */
+
+ /* Parameters for CBR mode */
+ opus_int32 GainsUnq_Q16[ MAX_NB_SUBFR ];
+ opus_int8 lastGainIndexPrev;
+} silk_encoder_control_FLP;
+
+/************************/
+/* Encoder Super Struct */
+/************************/
+typedef struct {
+ silk_encoder_state_FLP state_Fxx[ ENCODER_NUM_CHANNELS ];
+ stereo_enc_state sStereo;
+ opus_int32 nBitsExceeded;
+ opus_int nChannelsAPI;
+ opus_int nChannelsInternal;
+ opus_int nPrevChannelsInternal;
+ opus_int timeSinceSwitchAllowed_ms;
+ opus_int allowBandwidthSwitch;
+ opus_int prev_decode_only_middle;
+} silk_encoder;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/opus/silk/float/warped_autocorrelation_FLP.c b/drivers/opus/silk/float/warped_autocorrelation_FLP.c
new file mode 100644
index 0000000000..092b998d93
--- /dev/null
+++ b/drivers/opus/silk/float/warped_autocorrelation_FLP.c
@@ -0,0 +1,73 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/float/main_FLP.h"
+
+/* Autocorrelations for a warped frequency axis */
+void silk_warped_autocorrelation_FLP(
+ silk_float *corr, /* O Result [order + 1] */
+ const silk_float *input, /* I Input data to correlate */
+ const silk_float warping, /* I Warping coefficient */
+ const opus_int length, /* I Length of input */
+ const opus_int order /* I Correlation order (even) */
+)
+{
+ opus_int n, i;
+ double tmp1, tmp2;
+ double state[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
+ double C[ MAX_SHAPE_LPC_ORDER + 1 ] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
+
+ /* Order must be even */
+ silk_assert( ( order & 1 ) == 0 );
+
+ /* Loop over samples */
+ for( n = 0; n < length; n++ ) {
+ tmp1 = input[ n ];
+ /* Loop over allpass sections */
+ for( i = 0; i < order; i += 2 ) {
+ /* Output of allpass section */
+ tmp2 = state[ i ] + warping * ( state[ i + 1 ] - tmp1 );
+ state[ i ] = tmp1;
+ C[ i ] += state[ 0 ] * tmp1;
+ /* Output of allpass section */
+ tmp1 = state[ i + 1 ] + warping * ( state[ i + 2 ] - tmp2 );
+ state[ i + 1 ] = tmp2;
+ C[ i + 1 ] += state[ 0 ] * tmp2;
+ }
+ state[ order ] = tmp1;
+ C[ order ] += state[ 0 ] * tmp1;
+ }
+
+ /* Copy correlations in silk_float output format */
+ for( i = 0; i < order + 1; i++ ) {
+ corr[ i ] = ( silk_float )C[ i ];
+ }
+}
diff --git a/drivers/opus/silk/float/wrappers_FLP.c b/drivers/opus/silk/float/wrappers_FLP.c
new file mode 100644
index 0000000000..31586cf2a9
--- /dev/null
+++ b/drivers/opus/silk/float/wrappers_FLP.c
@@ -0,0 +1,201 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/float/main_FLP.h"
+
+/* Wrappers. Calls flp / fix code */
+
+/* Convert AR filter coefficients to NLSF parameters */
+void silk_A2NLSF_FLP(
+ opus_int16 *NLSF_Q15, /* O NLSF vector [ LPC_order ] */
+ const silk_float *pAR, /* I LPC coefficients [ LPC_order ] */
+ const opus_int LPC_order /* I LPC order */
+)
+{
+ opus_int i;
+ opus_int32 a_fix_Q16[ MAX_LPC_ORDER ];
+
+ for( i = 0; i < LPC_order; i++ ) {
+ a_fix_Q16[ i ] = silk_float2int( pAR[ i ] * 65536.0f );
+ }
+
+ silk_A2NLSF( NLSF_Q15, a_fix_Q16, LPC_order );
+}
+
+/* Convert LSF parameters to AR prediction filter coefficients */
+void silk_NLSF2A_FLP(
+ silk_float *pAR, /* O LPC coefficients [ LPC_order ] */
+ const opus_int16 *NLSF_Q15, /* I NLSF vector [ LPC_order ] */
+ const opus_int LPC_order /* I LPC order */
+)
+{
+ opus_int i;
+ opus_int16 a_fix_Q12[ MAX_LPC_ORDER ];
+
+ silk_NLSF2A( a_fix_Q12, NLSF_Q15, LPC_order );
+
+ for( i = 0; i < LPC_order; i++ ) {
+ pAR[ i ] = ( silk_float )a_fix_Q12[ i ] * ( 1.0f / 4096.0f );
+ }
+}
+
+/******************************************/
+/* Floating-point NLSF processing wrapper */
+/******************************************/
+void silk_process_NLSFs_FLP(
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ silk_float PredCoef[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */
+ opus_int16 NLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */
+ const opus_int16 prev_NLSF_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */
+)
+{
+ opus_int i, j;
+ opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ];
+
+ silk_process_NLSFs( psEncC, PredCoef_Q12, NLSF_Q15, prev_NLSF_Q15);
+
+ for( j = 0; j < 2; j++ ) {
+ for( i = 0; i < psEncC->predictLPCOrder; i++ ) {
+ PredCoef[ j ][ i ] = ( silk_float )PredCoef_Q12[ j ][ i ] * ( 1.0f / 4096.0f );
+ }
+ }
+}
+
+/****************************************/
+/* Floating-point Silk NSQ wrapper */
+/****************************************/
+void silk_NSQ_wrapper_FLP(
+ silk_encoder_state_FLP *psEnc, /* I/O Encoder state FLP */
+ silk_encoder_control_FLP *psEncCtrl, /* I/O Encoder control FLP */
+ SideInfoIndices *psIndices, /* I/O Quantization indices */
+ silk_nsq_state *psNSQ, /* I/O Noise Shaping Quantzation state */
+ opus_int8 pulses[], /* O Quantized pulse signal */
+ const silk_float x[] /* I Prefiltered input signal */
+)
+{
+ opus_int i, j;
+ opus_int32 x_Q3[ MAX_FRAME_LENGTH ];
+ opus_int32 Gains_Q16[ MAX_NB_SUBFR ];
+ silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ];
+ opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ];
+ opus_int LTP_scale_Q14;
+
+ /* Noise shaping parameters */
+ opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ];
+ opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ]; /* Packs two int16 coefficients per int32 value */
+ opus_int Lambda_Q10;
+ opus_int Tilt_Q14[ MAX_NB_SUBFR ];
+ opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ];
+
+ /* Convert control struct to fix control struct */
+ /* Noise shape parameters */
+ for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ for( j = 0; j < psEnc->sCmn.shapingLPCOrder; j++ ) {
+ AR2_Q13[ i * MAX_SHAPE_LPC_ORDER + j ] = silk_float2int( psEncCtrl->AR2[ i * MAX_SHAPE_LPC_ORDER + j ] * 8192.0f );
+ }
+ }
+
+ for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ LF_shp_Q14[ i ] = silk_LSHIFT32( silk_float2int( psEncCtrl->LF_AR_shp[ i ] * 16384.0f ), 16 ) |
+ (opus_uint16)silk_float2int( psEncCtrl->LF_MA_shp[ i ] * 16384.0f );
+ Tilt_Q14[ i ] = (opus_int)silk_float2int( psEncCtrl->Tilt[ i ] * 16384.0f );
+ HarmShapeGain_Q14[ i ] = (opus_int)silk_float2int( psEncCtrl->HarmShapeGain[ i ] * 16384.0f );
+ }
+ Lambda_Q10 = ( opus_int )silk_float2int( psEncCtrl->Lambda * 1024.0f );
+
+ /* prediction and coding parameters */
+ for( i = 0; i < psEnc->sCmn.nb_subfr * LTP_ORDER; i++ ) {
+ LTPCoef_Q14[ i ] = (opus_int16)silk_float2int( psEncCtrl->LTPCoef[ i ] * 16384.0f );
+ }
+
+ for( j = 0; j < 2; j++ ) {
+ for( i = 0; i < psEnc->sCmn.predictLPCOrder; i++ ) {
+ PredCoef_Q12[ j ][ i ] = (opus_int16)silk_float2int( psEncCtrl->PredCoef[ j ][ i ] * 4096.0f );
+ }
+ }
+
+ for( i = 0; i < psEnc->sCmn.nb_subfr; i++ ) {
+ Gains_Q16[ i ] = silk_float2int( psEncCtrl->Gains[ i ] * 65536.0f );
+ silk_assert( Gains_Q16[ i ] > 0 );
+ }
+
+ if( psIndices->signalType == TYPE_VOICED ) {
+ LTP_scale_Q14 = silk_LTPScales_table_Q14[ psIndices->LTP_scaleIndex ];
+ } else {
+ LTP_scale_Q14 = 0;
+ }
+
+ /* Convert input to fix */
+ for( i = 0; i < psEnc->sCmn.frame_length; i++ ) {
+ x_Q3[ i ] = silk_float2int( 8.0f * x[ i ] );
+ }
+
+ /* Call NSQ */
+ if( psEnc->sCmn.nStatesDelayedDecision > 1 || psEnc->sCmn.warping_Q16 > 0 ) {
+ silk_NSQ_del_dec( &psEnc->sCmn, psNSQ, psIndices, x_Q3, pulses, PredCoef_Q12[ 0 ], LTPCoef_Q14,
+ AR2_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, psEncCtrl->pitchL, Lambda_Q10, LTP_scale_Q14 );
+ } else {
+ silk_NSQ( &psEnc->sCmn, psNSQ, psIndices, x_Q3, pulses, PredCoef_Q12[ 0 ], LTPCoef_Q14,
+ AR2_Q13, HarmShapeGain_Q14, Tilt_Q14, LF_shp_Q14, Gains_Q16, psEncCtrl->pitchL, Lambda_Q10, LTP_scale_Q14 );
+ }
+}
+
+/***********************************************/
+/* Floating-point Silk LTP quantiation wrapper */
+/***********************************************/
+void silk_quant_LTP_gains_FLP(
+ silk_float B[ MAX_NB_SUBFR * LTP_ORDER ], /* I/O (Un-)quantized LTP gains */
+ opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook index */
+ opus_int8 *periodicity_index, /* O Periodicity index */
+ opus_int32 *sum_log_gain_Q7, /* I/O Cumulative max prediction gain */
+ const silk_float W[ MAX_NB_SUBFR * LTP_ORDER * LTP_ORDER ], /* I Error weights */
+ const opus_int mu_Q10, /* I Mu value (R/D tradeoff) */
+ const opus_int lowComplexity, /* I Flag for low complexity */
+ const opus_int nb_subfr /* I number of subframes */
+)
+{
+ opus_int i;
+ opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ];
+ opus_int32 W_Q18[ MAX_NB_SUBFR*LTP_ORDER*LTP_ORDER ];
+
+ for( i = 0; i < nb_subfr * LTP_ORDER; i++ ) {
+ B_Q14[ i ] = (opus_int16)silk_float2int( B[ i ] * 16384.0f );
+ }
+ for( i = 0; i < nb_subfr * LTP_ORDER * LTP_ORDER; i++ ) {
+ W_Q18[ i ] = (opus_int32)silk_float2int( W[ i ] * 262144.0f );
+ }
+
+ silk_quant_LTP_gains( B_Q14, cbk_index, periodicity_index, sum_log_gain_Q7, W_Q18, mu_Q10, lowComplexity, nb_subfr );
+
+ for( i = 0; i < nb_subfr * LTP_ORDER; i++ ) {
+ B[ i ] = (silk_float)B_Q14[ i ] * ( 1.0f / 16384.0f );
+ }
+}
diff --git a/drivers/opus/silk/gain_quant.c b/drivers/opus/silk/gain_quant.c
new file mode 100644
index 0000000000..e1d9b91126
--- /dev/null
+++ b/drivers/opus/silk/gain_quant.c
@@ -0,0 +1,141 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+
+#define OFFSET ( ( MIN_QGAIN_DB * 128 ) / 6 + 16 * 128 )
+#define SCALE_Q16 ( ( 65536 * ( N_LEVELS_QGAIN - 1 ) ) / ( ( ( MAX_QGAIN_DB - MIN_QGAIN_DB ) * 128 ) / 6 ) )
+#define INV_SCALE_Q16 ( ( 65536 * ( ( ( MAX_QGAIN_DB - MIN_QGAIN_DB ) * 128 ) / 6 ) ) / ( N_LEVELS_QGAIN - 1 ) )
+
+/* Gain scalar quantization with hysteresis, uniform on log scale */
+void silk_gains_quant(
+ opus_int8 ind[ MAX_NB_SUBFR ], /* O gain indices */
+ opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* I/O gains (quantized out) */
+ opus_int8 *prev_ind, /* I/O last index in previous frame */
+ const opus_int conditional, /* I first gain is delta coded if 1 */
+ const opus_int nb_subfr /* I number of subframes */
+)
+{
+ opus_int k, double_step_size_threshold;
+
+ for( k = 0; k < nb_subfr; k++ ) {
+ /* Convert to log scale, scale, floor() */
+ ind[ k ] = silk_SMULWB( SCALE_Q16, silk_lin2log( gain_Q16[ k ] ) - OFFSET );
+
+ /* Round towards previous quantized gain (hysteresis) */
+ if( ind[ k ] < *prev_ind ) {
+ ind[ k ]++;
+ }
+ ind[ k ] = silk_LIMIT_int( ind[ k ], 0, N_LEVELS_QGAIN - 1 );
+
+ /* Compute delta indices and limit */
+ if( k == 0 && conditional == 0 ) {
+ /* Full index */
+ ind[ k ] = silk_LIMIT_int( ind[ k ], *prev_ind + MIN_DELTA_GAIN_QUANT, N_LEVELS_QGAIN - 1 );
+ *prev_ind = ind[ k ];
+ } else {
+ /* Delta index */
+ ind[ k ] = ind[ k ] - *prev_ind;
+
+ /* Double the quantization step size for large gain increases, so that the max gain level can be reached */
+ double_step_size_threshold = 2 * MAX_DELTA_GAIN_QUANT - N_LEVELS_QGAIN + *prev_ind;
+ if( ind[ k ] > double_step_size_threshold ) {
+ ind[ k ] = double_step_size_threshold + silk_RSHIFT( ind[ k ] - double_step_size_threshold + 1, 1 );
+ }
+
+ ind[ k ] = silk_LIMIT_int( ind[ k ], MIN_DELTA_GAIN_QUANT, MAX_DELTA_GAIN_QUANT );
+
+ /* Accumulate deltas */
+ if( ind[ k ] > double_step_size_threshold ) {
+ *prev_ind += silk_LSHIFT( ind[ k ], 1 ) - double_step_size_threshold;
+ } else {
+ *prev_ind += ind[ k ];
+ }
+
+ /* Shift to make non-negative */
+ ind[ k ] -= MIN_DELTA_GAIN_QUANT;
+ }
+
+ /* Scale and convert to linear scale */
+ gain_Q16[ k ] = silk_log2lin( silk_min_32( silk_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3967 = 31 in Q7 */
+ }
+}
+
+/* Gains scalar dequantization, uniform on log scale */
+void silk_gains_dequant(
+ opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* O quantized gains */
+ const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */
+ opus_int8 *prev_ind, /* I/O last index in previous frame */
+ const opus_int conditional, /* I first gain is delta coded if 1 */
+ const opus_int nb_subfr /* I number of subframes */
+)
+{
+ opus_int k, ind_tmp, double_step_size_threshold;
+
+ for( k = 0; k < nb_subfr; k++ ) {
+ if( k == 0 && conditional == 0 ) {
+ /* Gain index is not allowed to go down more than 16 steps (~21.8 dB) */
+ *prev_ind = silk_max_int( ind[ k ], *prev_ind - 16 );
+ } else {
+ /* Delta index */
+ ind_tmp = ind[ k ] + MIN_DELTA_GAIN_QUANT;
+
+ /* Accumulate deltas */
+ double_step_size_threshold = 2 * MAX_DELTA_GAIN_QUANT - N_LEVELS_QGAIN + *prev_ind;
+ if( ind_tmp > double_step_size_threshold ) {
+ *prev_ind += silk_LSHIFT( ind_tmp, 1 ) - double_step_size_threshold;
+ } else {
+ *prev_ind += ind_tmp;
+ }
+ }
+ *prev_ind = silk_LIMIT_int( *prev_ind, 0, N_LEVELS_QGAIN - 1 );
+
+ /* Scale and convert to linear scale */
+ gain_Q16[ k ] = silk_log2lin( silk_min_32( silk_SMULWB( INV_SCALE_Q16, *prev_ind ) + OFFSET, 3967 ) ); /* 3967 = 31 in Q7 */
+ }
+}
+
+/* Compute unique identifier of gain indices vector */
+opus_int32 silk_gains_ID( /* O returns unique identifier of gains */
+ const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */
+ const opus_int nb_subfr /* I number of subframes */
+)
+{
+ opus_int k;
+ opus_int32 gainsID;
+
+ gainsID = 0;
+ for( k = 0; k < nb_subfr; k++ ) {
+ gainsID = silk_ADD_LSHIFT32( ind[ k ], gainsID, 8 );
+ }
+
+ return gainsID;
+}
diff --git a/drivers/opus/silk/init_decoder.c b/drivers/opus/silk/init_decoder.c
new file mode 100644
index 0000000000..43fa1f1c38
--- /dev/null
+++ b/drivers/opus/silk/init_decoder.c
@@ -0,0 +1,56 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+
+/************************/
+/* Init Decoder State */
+/************************/
+opus_int silk_init_decoder(
+ silk_decoder_state *psDec /* I/O Decoder state pointer */
+)
+{
+ /* Clear the entire encoder state, except anything copied */
+ silk_memset( psDec, 0, sizeof( silk_decoder_state ) );
+
+ /* Used to deactivate LSF interpolation */
+ psDec->first_frame_after_reset = 1;
+ psDec->prev_gain_Q16 = 65536;
+
+ /* Reset CNG state */
+ silk_CNG_Reset( psDec );
+
+ /* Reset PLC state */
+ silk_PLC_Reset( psDec );
+
+ return(0);
+}
+
diff --git a/drivers/opus/silk/init_encoder.c b/drivers/opus/silk/init_encoder.c
new file mode 100644
index 0000000000..9ba4524b73
--- /dev/null
+++ b/drivers/opus/silk/init_encoder.c
@@ -0,0 +1,64 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+#ifdef OPUS_FIXED_POINT
+#include "opus/silk/fixed/main_FIX.h"
+#else
+#include "opus/silk/float/main_FLP.h"
+#endif
+#include "opus/silk/tuning_parameters.h"
+#include "opus/celt/cpu_support.h"
+
+/*********************************/
+/* Initialize Silk Encoder state */
+/*********************************/
+opus_int silk_init_encoder(
+ silk_encoder_state_Fxx *psEnc, /* I/O Pointer to Silk FIX encoder state */
+ int arch /* I Run-time architecture */
+)
+{
+ opus_int ret = 0;
+
+ /* Clear the entire encoder state */
+ silk_memset( psEnc, 0, sizeof( silk_encoder_state_Fxx ) );
+
+ psEnc->sCmn.arch = arch;
+
+ psEnc->sCmn.variable_HP_smth1_Q15 = silk_LSHIFT( silk_lin2log( SILK_FIX_CONST( VARIABLE_HP_MIN_CUTOFF_HZ, 16 ) ) - ( 16 << 7 ), 8 );
+ psEnc->sCmn.variable_HP_smth2_Q15 = psEnc->sCmn.variable_HP_smth1_Q15;
+
+ /* Used to deactivate LSF interpolation, pitch prediction */
+ psEnc->sCmn.first_frame_after_reset = 1;
+
+ /* Initialize Silk VAD */
+ ret += silk_VAD_Init( &psEnc->sCmn.sVAD );
+
+ return ret;
+}
diff --git a/drivers/opus/silk/inner_prod_aligned.c b/drivers/opus/silk/inner_prod_aligned.c
new file mode 100644
index 0000000000..86ecf463ad
--- /dev/null
+++ b/drivers/opus/silk/inner_prod_aligned.c
@@ -0,0 +1,47 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/SigProc_FIX.h"
+
+opus_int32 silk_inner_prod_aligned_scale(
+ const opus_int16 *const inVec1, /* I input vector 1 */
+ const opus_int16 *const inVec2, /* I input vector 2 */
+ const opus_int scale, /* I number of bits to shift */
+ const opus_int len /* I vector lengths */
+)
+{
+ opus_int i;
+ opus_int32 sum = 0;
+ for( i = 0; i < len; i++ ) {
+ sum = silk_ADD_RSHIFT32( sum, silk_SMULBB( inVec1[ i ], inVec2[ i ] ), scale );
+ }
+ return sum;
+}
diff --git a/drivers/opus/silk/interpolate.c b/drivers/opus/silk/interpolate.c
new file mode 100644
index 0000000000..26c44de493
--- /dev/null
+++ b/drivers/opus/silk/interpolate.c
@@ -0,0 +1,51 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+
+/* Interpolate two vectors */
+void silk_interpolate(
+ opus_int16 xi[ MAX_LPC_ORDER ], /* O interpolated vector */
+ const opus_int16 x0[ MAX_LPC_ORDER ], /* I first vector */
+ const opus_int16 x1[ MAX_LPC_ORDER ], /* I second vector */
+ const opus_int ifact_Q2, /* I interp. factor, weight on 2nd vector */
+ const opus_int d /* I number of parameters */
+)
+{
+ opus_int i;
+
+ silk_assert( ifact_Q2 >= 0 );
+ silk_assert( ifact_Q2 <= 4 );
+
+ for( i = 0; i < d; i++ ) {
+ xi[ i ] = (opus_int16)silk_ADD_RSHIFT( x0[ i ], silk_SMULBB( x1[ i ] - x0[ i ], ifact_Q2 ), 2 );
+ }
+}
diff --git a/drivers/opus/silk/lin2log.c b/drivers/opus/silk/lin2log.c
new file mode 100644
index 0000000000..ea11f33dd0
--- /dev/null
+++ b/drivers/opus/silk/lin2log.c
@@ -0,0 +1,46 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/SigProc_FIX.h"
+/* Approximation of 128 * log2() (very close inverse of silk_log2lin()) */
+/* Convert input to a log scale */
+opus_int32 silk_lin2log(
+ const opus_int32 inLin /* I input in linear scale */
+)
+{
+ opus_int32 lz, frac_Q7;
+
+ silk_CLZ_FRAC( inLin, &lz, &frac_Q7 );
+
+ /* Piece-wise parabolic approximation */
+ return silk_LSHIFT( 31 - lz, 7 ) + silk_SMLAWB( frac_Q7, silk_MUL( frac_Q7, 128 - frac_Q7 ), 179 );
+}
+
diff --git a/drivers/opus/silk/log2lin.c b/drivers/opus/silk/log2lin.c
new file mode 100644
index 0000000000..0a33ca48fb
--- /dev/null
+++ b/drivers/opus/silk/log2lin.c
@@ -0,0 +1,58 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/SigProc_FIX.h"
+
+/* Approximation of 2^() (very close inverse of silk_lin2log()) */
+/* Convert input to a linear scale */
+opus_int32 silk_log2lin(
+ const opus_int32 inLog_Q7 /* I input on log scale */
+)
+{
+ opus_int32 out, frac_Q7;
+
+ if( inLog_Q7 < 0 ) {
+ return 0;
+ } else if ( inLog_Q7 >= 3967 ) {
+ return silk_int32_MAX;
+ }
+
+ out = silk_LSHIFT( 1, silk_RSHIFT( inLog_Q7, 7 ) );
+ frac_Q7 = inLog_Q7 & 0x7F;
+ if( inLog_Q7 < 2048 ) {
+ /* Piece-wise parabolic approximation */
+ out = silk_ADD_RSHIFT32( out, silk_MUL( out, silk_SMLAWB( frac_Q7, silk_SMULBB( frac_Q7, 128 - frac_Q7 ), -174 ) ), 7 );
+ } else {
+ /* Piece-wise parabolic approximation */
+ out = silk_MLA( out, silk_RSHIFT( out, 7 ), silk_SMLAWB( frac_Q7, silk_SMULBB( frac_Q7, 128 - frac_Q7 ), -174 ) );
+ }
+ return out;
+}
diff --git a/drivers/opus/silk/macros.h b/drivers/opus/silk/macros.h
new file mode 100644
index 0000000000..8986dc8f82
--- /dev/null
+++ b/drivers/opus/silk/macros.h
@@ -0,0 +1,113 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_MACROS_H
+#define SILK_MACROS_H
+
+#include "opus/opus_config.h"
+
+#include "opus/opus_types.h"
+#include "opus/opus_defines.h"
+
+/* This is an OPUS_INLINE header file for general platform. */
+
+/* (a32 * (opus_int32)((opus_int16)(b32))) >> 16 output have to be 32bit int */
+#define silk_SMULWB(a32, b32) ((((a32) >> 16) * (opus_int32)((opus_int16)(b32))) + ((((a32) & 0x0000FFFF) * (opus_int32)((opus_int16)(b32))) >> 16))
+
+/* a32 + (b32 * (opus_int32)((opus_int16)(c32))) >> 16 output have to be 32bit int */
+#define silk_SMLAWB(a32, b32, c32) ((a32) + ((((b32) >> 16) * (opus_int32)((opus_int16)(c32))) + ((((b32) & 0x0000FFFF) * (opus_int32)((opus_int16)(c32))) >> 16)))
+
+/* (a32 * (b32 >> 16)) >> 16 */
+#define silk_SMULWT(a32, b32) (((a32) >> 16) * ((b32) >> 16) + ((((a32) & 0x0000FFFF) * ((b32) >> 16)) >> 16))
+
+/* a32 + (b32 * (c32 >> 16)) >> 16 */
+#define silk_SMLAWT(a32, b32, c32) ((a32) + (((b32) >> 16) * ((c32) >> 16)) + ((((b32) & 0x0000FFFF) * ((c32) >> 16)) >> 16))
+
+/* (opus_int32)((opus_int16)(a3))) * (opus_int32)((opus_int16)(b32)) output have to be 32bit int */
+#define silk_SMULBB(a32, b32) ((opus_int32)((opus_int16)(a32)) * (opus_int32)((opus_int16)(b32)))
+
+/* a32 + (opus_int32)((opus_int16)(b32)) * (opus_int32)((opus_int16)(c32)) output have to be 32bit int */
+#define silk_SMLABB(a32, b32, c32) ((a32) + ((opus_int32)((opus_int16)(b32))) * (opus_int32)((opus_int16)(c32)))
+
+/* (opus_int32)((opus_int16)(a32)) * (b32 >> 16) */
+#define silk_SMULBT(a32, b32) ((opus_int32)((opus_int16)(a32)) * ((b32) >> 16))
+
+/* a32 + (opus_int32)((opus_int16)(b32)) * (c32 >> 16) */
+#define silk_SMLABT(a32, b32, c32) ((a32) + ((opus_int32)((opus_int16)(b32))) * ((c32) >> 16))
+
+/* a64 + (b32 * c32) */
+#define silk_SMLAL(a64, b32, c32) (silk_ADD64((a64), ((opus_int64)(b32) * (opus_int64)(c32))))
+
+/* (a32 * b32) >> 16 */
+#define silk_SMULWW(a32, b32) silk_MLA(silk_SMULWB((a32), (b32)), (a32), silk_RSHIFT_ROUND((b32), 16))
+
+/* a32 + ((b32 * c32) >> 16) */
+#define silk_SMLAWW(a32, b32, c32) silk_MLA(silk_SMLAWB((a32), (b32), (c32)), (b32), silk_RSHIFT_ROUND((c32), 16))
+
+/* add/subtract with output saturated */
+#define silk_ADD_SAT32(a, b) ((((opus_uint32)(a) + (opus_uint32)(b)) & 0x80000000) == 0 ? \
+ ((((a) & (b)) & 0x80000000) != 0 ? silk_int32_MIN : (a)+(b)) : \
+ ((((a) | (b)) & 0x80000000) == 0 ? silk_int32_MAX : (a)+(b)) )
+
+#define silk_SUB_SAT32(a, b) ((((opus_uint32)(a)-(opus_uint32)(b)) & 0x80000000) == 0 ? \
+ (( (a) & ((b)^0x80000000) & 0x80000000) ? silk_int32_MIN : (a)-(b)) : \
+ ((((a)^0x80000000) & (b) & 0x80000000) ? silk_int32_MAX : (a)-(b)) )
+
+#include "opus/celt/ecintrin.h"
+
+static OPUS_INLINE opus_int32 silk_CLZ16(opus_int16 in16)
+{
+ return 32 - EC_ILOG(in16<<16|0x8000);
+}
+
+static OPUS_INLINE opus_int32 silk_CLZ32(opus_int32 in32)
+{
+ return in32 ? 32 - EC_ILOG(in32) : 32;
+}
+
+/* Row based */
+#define matrix_ptr(Matrix_base_adr, row, column, N) \
+ (*((Matrix_base_adr) + ((row)*(N)+(column))))
+#define matrix_adr(Matrix_base_adr, row, column, N) \
+ ((Matrix_base_adr) + ((row)*(N)+(column)))
+
+/* Column based */
+#ifndef matrix_c_ptr
+# define matrix_c_ptr(Matrix_base_adr, row, column, M) \
+ (*((Matrix_base_adr) + ((row)+(M)*(column))))
+#endif
+
+#ifdef OPUS_ARM_INLINE_ASM
+#include "arm/macros_armv4.h"
+#endif
+
+#ifdef OPUS_ARM_INLINE_EDSP
+#include "arm/macros_armv5e.h"
+#endif
+
+#endif /* SILK_MACROS_H */
+
diff --git a/drivers/opus/silk/pitch_est_defines.h b/drivers/opus/silk/pitch_est_defines.h
new file mode 100644
index 0000000000..e2d9e517c4
--- /dev/null
+++ b/drivers/opus/silk/pitch_est_defines.h
@@ -0,0 +1,88 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_PE_DEFINES_H
+#define SILK_PE_DEFINES_H
+
+#include "opus/silk/SigProc_FIX.h"
+
+/********************************************************/
+/* Definitions for pitch estimator */
+/********************************************************/
+
+#define PE_MAX_FS_KHZ 16 /* Maximum sampling frequency used */
+
+#define PE_MAX_NB_SUBFR 4
+#define PE_SUBFR_LENGTH_MS 5 /* 5 ms */
+
+#define PE_LTP_MEM_LENGTH_MS ( 4 * PE_SUBFR_LENGTH_MS )
+
+#define PE_MAX_FRAME_LENGTH_MS ( PE_LTP_MEM_LENGTH_MS + PE_MAX_NB_SUBFR * PE_SUBFR_LENGTH_MS )
+#define PE_MAX_FRAME_LENGTH ( PE_MAX_FRAME_LENGTH_MS * PE_MAX_FS_KHZ )
+#define PE_MAX_FRAME_LENGTH_ST_1 ( PE_MAX_FRAME_LENGTH >> 2 )
+#define PE_MAX_FRAME_LENGTH_ST_2 ( PE_MAX_FRAME_LENGTH >> 1 )
+
+#define PE_MAX_LAG_MS 18 /* 18 ms -> 56 Hz */
+#define PE_MIN_LAG_MS 2 /* 2 ms -> 500 Hz */
+#define PE_MAX_LAG ( PE_MAX_LAG_MS * PE_MAX_FS_KHZ )
+#define PE_MIN_LAG ( PE_MIN_LAG_MS * PE_MAX_FS_KHZ )
+
+#define PE_D_SRCH_LENGTH 24
+
+#define PE_NB_STAGE3_LAGS 5
+
+#define PE_NB_CBKS_STAGE2 3
+#define PE_NB_CBKS_STAGE2_EXT 11
+
+#define PE_NB_CBKS_STAGE3_MAX 34
+#define PE_NB_CBKS_STAGE3_MID 24
+#define PE_NB_CBKS_STAGE3_MIN 16
+
+#define PE_NB_CBKS_STAGE3_10MS 12
+#define PE_NB_CBKS_STAGE2_10MS 3
+
+#define PE_SHORTLAG_BIAS 0.2f /* for logarithmic weighting */
+#define PE_PREVLAG_BIAS 0.2f /* for logarithmic weighting */
+#define PE_FLATCONTOUR_BIAS 0.05f
+
+#define SILK_PE_MIN_COMPLEX 0
+#define SILK_PE_MID_COMPLEX 1
+#define SILK_PE_MAX_COMPLEX 2
+
+/* Tables for 20 ms frames */
+extern const opus_int8 silk_CB_lags_stage2[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE2_EXT ];
+extern const opus_int8 silk_CB_lags_stage3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ];
+extern const opus_int8 silk_Lag_range_stage3[ SILK_PE_MAX_COMPLEX + 1 ] [ PE_MAX_NB_SUBFR ][ 2 ];
+extern const opus_int8 silk_nb_cbk_searchs_stage3[ SILK_PE_MAX_COMPLEX + 1 ];
+
+/* Tables for 10 ms frames */
+extern const opus_int8 silk_CB_lags_stage2_10_ms[ PE_MAX_NB_SUBFR >> 1][ 3 ];
+extern const opus_int8 silk_CB_lags_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ 12 ];
+extern const opus_int8 silk_Lag_range_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ 2 ];
+
+#endif
+
diff --git a/drivers/opus/silk/pitch_est_tables.c b/drivers/opus/silk/pitch_est_tables.c
new file mode 100644
index 0000000000..7555f5b04b
--- /dev/null
+++ b/drivers/opus/silk/pitch_est_tables.c
@@ -0,0 +1,99 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/typedef.h"
+#include "opus/silk/pitch_est_defines.h"
+
+const opus_int8 silk_CB_lags_stage2_10_ms[ PE_MAX_NB_SUBFR >> 1][ PE_NB_CBKS_STAGE2_10MS ] =
+{
+ {0, 1, 0},
+ {0, 0, 1}
+};
+
+const opus_int8 silk_CB_lags_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ PE_NB_CBKS_STAGE3_10MS ] =
+{
+ { 0, 0, 1,-1, 1,-1, 2,-2, 2,-2, 3,-3},
+ { 0, 1, 0, 1,-1, 2,-1, 2,-2, 3,-2, 3}
+};
+
+const opus_int8 silk_Lag_range_stage3_10_ms[ PE_MAX_NB_SUBFR >> 1 ][ 2 ] =
+{
+ {-3, 7},
+ {-2, 7}
+};
+
+const opus_int8 silk_CB_lags_stage2[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE2_EXT ] =
+{
+ {0, 2,-1,-1,-1, 0, 0, 1, 1, 0, 1},
+ {0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0},
+ {0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0},
+ {0,-1, 2, 1, 0, 1, 1, 0, 0,-1,-1}
+};
+
+const opus_int8 silk_CB_lags_stage3[ PE_MAX_NB_SUBFR ][ PE_NB_CBKS_STAGE3_MAX ] =
+{
+ {0, 0, 1,-1, 0, 1,-1, 0,-1, 1,-2, 2,-2,-2, 2,-3, 2, 3,-3,-4, 3,-4, 4, 4,-5, 5,-6,-5, 6,-7, 6, 5, 8,-9},
+ {0, 0, 1, 0, 0, 0, 0, 0, 0, 0,-1, 1, 0, 0, 1,-1, 0, 1,-1,-1, 1,-1, 2, 1,-1, 2,-2,-2, 2,-2, 2, 2, 3,-3},
+ {0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1,-1, 1, 0, 0, 2, 1,-1, 2,-1,-1, 2,-1, 2, 2,-1, 3,-2,-2,-2, 3},
+ {0, 1, 0, 0, 1, 0, 1,-1, 2,-1, 2,-1, 2, 3,-2, 3,-2,-2, 4, 4,-3, 5,-3,-4, 6,-4, 6, 5,-5, 8,-6,-5,-7, 9}
+};
+
+const opus_int8 silk_Lag_range_stage3[ SILK_PE_MAX_COMPLEX + 1 ] [ PE_MAX_NB_SUBFR ][ 2 ] =
+{
+ /* Lags to search for low number of stage3 cbks */
+ {
+ {-5,8},
+ {-1,6},
+ {-1,6},
+ {-4,10}
+ },
+ /* Lags to search for middle number of stage3 cbks */
+ {
+ {-6,10},
+ {-2,6},
+ {-1,6},
+ {-5,10}
+ },
+ /* Lags to search for max number of stage3 cbks */
+ {
+ {-9,12},
+ {-3,7},
+ {-2,7},
+ {-7,13}
+ }
+};
+
+const opus_int8 silk_nb_cbk_searchs_stage3[ SILK_PE_MAX_COMPLEX + 1 ] =
+{
+ PE_NB_CBKS_STAGE3_MIN,
+ PE_NB_CBKS_STAGE3_MID,
+ PE_NB_CBKS_STAGE3_MAX
+};
diff --git a/drivers/opus/silk/process_NLSFs.c b/drivers/opus/silk/process_NLSFs.c
new file mode 100644
index 0000000000..9e6ebf827c
--- /dev/null
+++ b/drivers/opus/silk/process_NLSFs.c
@@ -0,0 +1,105 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+
+/* Limit, stabilize, convert and quantize NLSFs */
+void silk_process_NLSFs(
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */
+ opus_int16 pNLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */
+ const opus_int16 prev_NLSFq_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */
+)
+{
+ opus_int i, doInterpolate;
+ opus_int NLSF_mu_Q20;
+ opus_int32 i_sqr_Q15;
+ opus_int16 pNLSF0_temp_Q15[ MAX_LPC_ORDER ];
+ opus_int16 pNLSFW_QW[ MAX_LPC_ORDER ];
+ opus_int16 pNLSFW0_temp_QW[ MAX_LPC_ORDER ];
+
+ silk_assert( psEncC->speech_activity_Q8 >= 0 );
+ silk_assert( psEncC->speech_activity_Q8 <= SILK_FIX_CONST( 1.0, 8 ) );
+ silk_assert( psEncC->useInterpolatedNLSFs == 1 || psEncC->indices.NLSFInterpCoef_Q2 == ( 1 << 2 ) );
+
+ /***********************/
+ /* Calculate mu values */
+ /***********************/
+ /* NLSF_mu = 0.003 - 0.0015 * psEnc->speech_activity; */
+ NLSF_mu_Q20 = silk_SMLAWB( SILK_FIX_CONST( 0.003, 20 ), SILK_FIX_CONST( -0.001, 28 ), psEncC->speech_activity_Q8 );
+ if( psEncC->nb_subfr == 2 ) {
+ /* Multiply by 1.5 for 10 ms packets */
+ NLSF_mu_Q20 = silk_ADD_RSHIFT( NLSF_mu_Q20, NLSF_mu_Q20, 1 );
+ }
+
+ silk_assert( NLSF_mu_Q20 > 0 );
+ silk_assert( NLSF_mu_Q20 <= SILK_FIX_CONST( 0.005, 20 ) );
+
+ /* Calculate NLSF weights */
+ silk_NLSF_VQ_weights_laroia( pNLSFW_QW, pNLSF_Q15, psEncC->predictLPCOrder );
+
+ /* Update NLSF weights for interpolated NLSFs */
+ doInterpolate = ( psEncC->useInterpolatedNLSFs == 1 ) && ( psEncC->indices.NLSFInterpCoef_Q2 < 4 );
+ if( doInterpolate ) {
+ /* Calculate the interpolated NLSF vector for the first half */
+ silk_interpolate( pNLSF0_temp_Q15, prev_NLSFq_Q15, pNLSF_Q15,
+ psEncC->indices.NLSFInterpCoef_Q2, psEncC->predictLPCOrder );
+
+ /* Calculate first half NLSF weights for the interpolated NLSFs */
+ silk_NLSF_VQ_weights_laroia( pNLSFW0_temp_QW, pNLSF0_temp_Q15, psEncC->predictLPCOrder );
+
+ /* Update NLSF weights with contribution from first half */
+ i_sqr_Q15 = silk_LSHIFT( silk_SMULBB( psEncC->indices.NLSFInterpCoef_Q2, psEncC->indices.NLSFInterpCoef_Q2 ), 11 );
+ for( i = 0; i < psEncC->predictLPCOrder; i++ ) {
+ pNLSFW_QW[ i ] = silk_SMLAWB( silk_RSHIFT( pNLSFW_QW[ i ], 1 ), (opus_int32)pNLSFW0_temp_QW[ i ], i_sqr_Q15 );
+ silk_assert( pNLSFW_QW[ i ] >= 1 );
+ }
+ }
+
+ silk_NLSF_encode( psEncC->indices.NLSFIndices, pNLSF_Q15, psEncC->psNLSF_CB, pNLSFW_QW,
+ NLSF_mu_Q20, psEncC->NLSF_MSVQ_Survivors, psEncC->indices.signalType );
+
+ /* Convert quantized NLSFs back to LPC coefficients */
+ silk_NLSF2A( PredCoef_Q12[ 1 ], pNLSF_Q15, psEncC->predictLPCOrder );
+
+ if( doInterpolate ) {
+ /* Calculate the interpolated, quantized LSF vector for the first half */
+ silk_interpolate( pNLSF0_temp_Q15, prev_NLSFq_Q15, pNLSF_Q15,
+ psEncC->indices.NLSFInterpCoef_Q2, psEncC->predictLPCOrder );
+
+ /* Convert back to LPC coefficients */
+ silk_NLSF2A( PredCoef_Q12[ 0 ], pNLSF0_temp_Q15, psEncC->predictLPCOrder );
+
+ } else {
+ /* Copy LPC coefficients for first half from second half */
+ silk_memcpy( PredCoef_Q12[ 0 ], PredCoef_Q12[ 1 ], psEncC->predictLPCOrder * sizeof( opus_int16 ) );
+ }
+}
diff --git a/drivers/opus/silk/quant_LTP_gains.c b/drivers/opus/silk/quant_LTP_gains.c
new file mode 100644
index 0000000000..f6fff470f4
--- /dev/null
+++ b/drivers/opus/silk/quant_LTP_gains.c
@@ -0,0 +1,128 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+#include "opus/silk/tuning_parameters.h"
+
+void silk_quant_LTP_gains(
+ opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* I/O (un)quantized LTP gains */
+ opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook Index */
+ opus_int8 *periodicity_index, /* O Periodicity Index */
+ opus_int32 *sum_log_gain_Q7, /* I/O Cumulative max prediction gain */
+ const opus_int32 W_Q18[ MAX_NB_SUBFR*LTP_ORDER*LTP_ORDER ], /* I Error Weights in Q18 */
+ opus_int mu_Q9, /* I Mu value (R/D tradeoff) */
+ opus_int lowComplexity, /* I Flag for low complexity */
+ const opus_int nb_subfr /* I number of subframes */
+)
+{
+ opus_int j, k, cbk_size;
+ opus_int8 temp_idx[ MAX_NB_SUBFR ];
+ const opus_uint8 *cl_ptr_Q5;
+ const opus_int8 *cbk_ptr_Q7;
+ const opus_uint8 *cbk_gain_ptr_Q7;
+ const opus_int16 *b_Q14_ptr;
+ const opus_int32 *W_Q18_ptr;
+ opus_int32 rate_dist_Q14_subfr, rate_dist_Q14, min_rate_dist_Q14;
+ opus_int32 sum_log_gain_tmp_Q7, best_sum_log_gain_Q7, max_gain_Q7, gain_Q7;
+
+ /***************************************************/
+ /* iterate over different codebooks with different */
+ /* rates/distortions, and choose best */
+ /***************************************************/
+ min_rate_dist_Q14 = silk_int32_MAX;
+ best_sum_log_gain_Q7 = 0;
+ for( k = 0; k < 3; k++ ) {
+ /* Safety margin for pitch gain control, to take into account factors
+ such as state rescaling/rewhitening. */
+ opus_int32 gain_safety = SILK_FIX_CONST( 0.4, 7 );
+
+ cl_ptr_Q5 = silk_LTP_gain_BITS_Q5_ptrs[ k ];
+ cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ k ];
+ cbk_gain_ptr_Q7 = silk_LTP_vq_gain_ptrs_Q7[ k ];
+ cbk_size = silk_LTP_vq_sizes[ k ];
+
+ /* Set up pointer to first subframe */
+ W_Q18_ptr = W_Q18;
+ b_Q14_ptr = B_Q14;
+
+ rate_dist_Q14 = 0;
+ sum_log_gain_tmp_Q7 = *sum_log_gain_Q7;
+ for( j = 0; j < nb_subfr; j++ ) {
+ max_gain_Q7 = silk_log2lin( ( SILK_FIX_CONST( MAX_SUM_LOG_GAIN_DB / 6.0, 7 ) - sum_log_gain_tmp_Q7 )
+ + SILK_FIX_CONST( 7, 7 ) ) - gain_safety;
+
+ silk_VQ_WMat_EC(
+ &temp_idx[ j ], /* O index of best codebook vector */
+ &rate_dist_Q14_subfr, /* O best weighted quantization error + mu * rate */
+ &gain_Q7, /* O sum of absolute LTP coefficients */
+ b_Q14_ptr, /* I input vector to be quantized */
+ W_Q18_ptr, /* I weighting matrix */
+ cbk_ptr_Q7, /* I codebook */
+ cbk_gain_ptr_Q7, /* I codebook effective gains */
+ cl_ptr_Q5, /* I code length for each codebook vector */
+ mu_Q9, /* I tradeoff between weighted error and rate */
+ max_gain_Q7, /* I maximum sum of absolute LTP coefficients */
+ cbk_size /* I number of vectors in codebook */
+ );
+
+ rate_dist_Q14 = silk_ADD_POS_SAT32( rate_dist_Q14, rate_dist_Q14_subfr );
+ sum_log_gain_tmp_Q7 = silk_max(0, sum_log_gain_tmp_Q7
+ + silk_lin2log( gain_safety + gain_Q7 ) - SILK_FIX_CONST( 7, 7 ));
+
+ b_Q14_ptr += LTP_ORDER;
+ W_Q18_ptr += LTP_ORDER * LTP_ORDER;
+ }
+
+ /* Avoid never finding a codebook */
+ rate_dist_Q14 = silk_min( silk_int32_MAX - 1, rate_dist_Q14 );
+
+ if( rate_dist_Q14 < min_rate_dist_Q14 ) {
+ min_rate_dist_Q14 = rate_dist_Q14;
+ *periodicity_index = (opus_int8)k;
+ silk_memcpy( cbk_index, temp_idx, nb_subfr * sizeof( opus_int8 ) );
+ best_sum_log_gain_Q7 = sum_log_gain_tmp_Q7;
+ }
+
+ /* Break early in low-complexity mode if rate distortion is below threshold */
+ if( lowComplexity && ( rate_dist_Q14 < silk_LTP_gain_middle_avg_RD_Q14 ) ) {
+ break;
+ }
+ }
+
+ cbk_ptr_Q7 = silk_LTP_vq_ptrs_Q7[ *periodicity_index ];
+ for( j = 0; j < nb_subfr; j++ ) {
+ for( k = 0; k < LTP_ORDER; k++ ) {
+ B_Q14[ j * LTP_ORDER + k ] = silk_LSHIFT( cbk_ptr_Q7[ cbk_index[ j ] * LTP_ORDER + k ], 7 );
+ }
+ }
+ *sum_log_gain_Q7 = best_sum_log_gain_Q7;
+}
+
diff --git a/drivers/opus/silk/resampler.c b/drivers/opus/silk/resampler.c
new file mode 100644
index 0000000000..dde8fcddb1
--- /dev/null
+++ b/drivers/opus/silk/resampler.c
@@ -0,0 +1,215 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+/*
+ * Matrix of resampling methods used:
+ * Fs_out (kHz)
+ * 8 12 16 24 48
+ *
+ * 8 C UF U UF UF
+ * 12 AF C UF U UF
+ * Fs_in (kHz) 16 D AF C UF UF
+ * 24 AF D AF C U
+ * 48 AF AF AF D C
+ *
+ * C -> Copy (no resampling)
+ * D -> Allpass-based 2x downsampling
+ * U -> Allpass-based 2x upsampling
+ * UF -> Allpass-based 2x upsampling followed by FIR interpolation
+ * AF -> AR2 filter followed by FIR interpolation
+ */
+
+#include "opus/silk/resampler_private.h"
+
+/* Tables with delay compensation values to equalize total delay for different modes */
+static const opus_int8 delay_matrix_enc[ 5 ][ 3 ] = {
+/* in \ out 8 12 16 */
+/* 8 */ { 6, 0, 3 },
+/* 12 */ { 0, 7, 3 },
+/* 16 */ { 0, 1, 10 },
+/* 24 */ { 0, 2, 6 },
+/* 48 */ { 18, 10, 12 }
+};
+
+static const opus_int8 delay_matrix_dec[ 3 ][ 5 ] = {
+/* in \ out 8 12 16 24 48 */
+/* 8 */ { 4, 0, 2, 0, 0 },
+/* 12 */ { 0, 9, 4, 7, 4 },
+/* 16 */ { 0, 3, 12, 7, 7 }
+};
+
+/* Simple way to make [8000, 12000, 16000, 24000, 48000] to [0, 1, 2, 3, 4] */
+#define rateID(R) ( ( ( ((R)>>12) - ((R)>16000) ) >> ((R)>24000) ) - 1 )
+
+#define USE_silk_resampler_copy (0)
+#define USE_silk_resampler_private_up2_HQ_wrapper (1)
+#define USE_silk_resampler_private_IIR_FIR (2)
+#define USE_silk_resampler_private_down_FIR (3)
+
+/* Initialize/reset the resampler state for a given pair of input/output sampling rates */
+opus_int silk_resampler_init(
+ silk_resampler_state_struct *S, /* I/O Resampler state */
+ opus_int32 Fs_Hz_in, /* I Input sampling rate (Hz) */
+ opus_int32 Fs_Hz_out, /* I Output sampling rate (Hz) */
+ opus_int forEnc /* I If 1: encoder; if 0: decoder */
+)
+{
+ opus_int up2x;
+
+ /* Clear state */
+ silk_memset( S, 0, sizeof( silk_resampler_state_struct ) );
+
+ /* Input checking */
+ if( forEnc ) {
+ if( ( Fs_Hz_in != 8000 && Fs_Hz_in != 12000 && Fs_Hz_in != 16000 && Fs_Hz_in != 24000 && Fs_Hz_in != 48000 ) ||
+ ( Fs_Hz_out != 8000 && Fs_Hz_out != 12000 && Fs_Hz_out != 16000 ) ) {
+ silk_assert( 0 );
+ return -1;
+ }
+ S->inputDelay = delay_matrix_enc[ rateID( Fs_Hz_in ) ][ rateID( Fs_Hz_out ) ];
+ } else {
+ if( ( Fs_Hz_in != 8000 && Fs_Hz_in != 12000 && Fs_Hz_in != 16000 ) ||
+ ( Fs_Hz_out != 8000 && Fs_Hz_out != 12000 && Fs_Hz_out != 16000 && Fs_Hz_out != 24000 && Fs_Hz_out != 48000 ) ) {
+ silk_assert( 0 );
+ return -1;
+ }
+ S->inputDelay = delay_matrix_dec[ rateID( Fs_Hz_in ) ][ rateID( Fs_Hz_out ) ];
+ }
+
+ S->Fs_in_kHz = silk_DIV32_16( Fs_Hz_in, 1000 );
+ S->Fs_out_kHz = silk_DIV32_16( Fs_Hz_out, 1000 );
+
+ /* Number of samples processed per batch */
+ S->batchSize = S->Fs_in_kHz * RESAMPLER_MAX_BATCH_SIZE_MS;
+
+ /* Find resampler with the right sampling ratio */
+ up2x = 0;
+ if( Fs_Hz_out > Fs_Hz_in ) {
+ /* Upsample */
+ if( Fs_Hz_out == silk_MUL( Fs_Hz_in, 2 ) ) { /* Fs_out : Fs_in = 2 : 1 */
+ /* Special case: directly use 2x upsampler */
+ S->resampler_function = USE_silk_resampler_private_up2_HQ_wrapper;
+ } else {
+ /* Default resampler */
+ S->resampler_function = USE_silk_resampler_private_IIR_FIR;
+ up2x = 1;
+ }
+ } else if ( Fs_Hz_out < Fs_Hz_in ) {
+ /* Downsample */
+ S->resampler_function = USE_silk_resampler_private_down_FIR;
+ if( silk_MUL( Fs_Hz_out, 4 ) == silk_MUL( Fs_Hz_in, 3 ) ) { /* Fs_out : Fs_in = 3 : 4 */
+ S->FIR_Fracs = 3;
+ S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR0;
+ S->Coefs = silk_Resampler_3_4_COEFS;
+ } else if( silk_MUL( Fs_Hz_out, 3 ) == silk_MUL( Fs_Hz_in, 2 ) ) { /* Fs_out : Fs_in = 2 : 3 */
+ S->FIR_Fracs = 2;
+ S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR0;
+ S->Coefs = silk_Resampler_2_3_COEFS;
+ } else if( silk_MUL( Fs_Hz_out, 2 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 2 */
+ S->FIR_Fracs = 1;
+ S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR1;
+ S->Coefs = silk_Resampler_1_2_COEFS;
+ } else if( silk_MUL( Fs_Hz_out, 3 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 3 */
+ S->FIR_Fracs = 1;
+ S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR2;
+ S->Coefs = silk_Resampler_1_3_COEFS;
+ } else if( silk_MUL( Fs_Hz_out, 4 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 4 */
+ S->FIR_Fracs = 1;
+ S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR2;
+ S->Coefs = silk_Resampler_1_4_COEFS;
+ } else if( silk_MUL( Fs_Hz_out, 6 ) == Fs_Hz_in ) { /* Fs_out : Fs_in = 1 : 6 */
+ S->FIR_Fracs = 1;
+ S->FIR_Order = RESAMPLER_DOWN_ORDER_FIR2;
+ S->Coefs = silk_Resampler_1_6_COEFS;
+ } else {
+ /* None available */
+ silk_assert( 0 );
+ return -1;
+ }
+ } else {
+ /* Input and output sampling rates are equal: copy */
+ S->resampler_function = USE_silk_resampler_copy;
+ }
+
+ /* Ratio of input/output samples */
+ S->invRatio_Q16 = silk_LSHIFT32( silk_DIV32( silk_LSHIFT32( Fs_Hz_in, 14 + up2x ), Fs_Hz_out ), 2 );
+ /* Make sure the ratio is rounded up */
+ while( silk_SMULWW( S->invRatio_Q16, Fs_Hz_out ) < silk_LSHIFT32( Fs_Hz_in, up2x ) ) {
+ S->invRatio_Q16++;
+ }
+
+ return 0;
+}
+
+/* Resampler: convert from one sampling rate to another */
+/* Input and output sampling rate are at most 48000 Hz */
+opus_int silk_resampler(
+ silk_resampler_state_struct *S, /* I/O Resampler state */
+ opus_int16 out[], /* O Output signal */
+ const opus_int16 in[], /* I Input signal */
+ opus_int32 inLen /* I Number of input samples */
+)
+{
+ opus_int nSamples;
+
+ /* Need at least 1 ms of input data */
+ silk_assert( inLen >= S->Fs_in_kHz );
+ /* Delay can't exceed the 1 ms of buffering */
+ silk_assert( S->inputDelay <= S->Fs_in_kHz );
+
+ nSamples = S->Fs_in_kHz - S->inputDelay;
+
+ /* Copy to delay buffer */
+ silk_memcpy( &S->delayBuf[ S->inputDelay ], in, nSamples * sizeof( opus_int16 ) );
+
+ switch( S->resampler_function ) {
+ case USE_silk_resampler_private_up2_HQ_wrapper:
+ silk_resampler_private_up2_HQ_wrapper( S, out, S->delayBuf, S->Fs_in_kHz );
+ silk_resampler_private_up2_HQ_wrapper( S, &out[ S->Fs_out_kHz ], &in[ nSamples ], inLen - S->Fs_in_kHz );
+ break;
+ case USE_silk_resampler_private_IIR_FIR:
+ silk_resampler_private_IIR_FIR( S, out, S->delayBuf, S->Fs_in_kHz );
+ silk_resampler_private_IIR_FIR( S, &out[ S->Fs_out_kHz ], &in[ nSamples ], inLen - S->Fs_in_kHz );
+ break;
+ case USE_silk_resampler_private_down_FIR:
+ silk_resampler_private_down_FIR( S, out, S->delayBuf, S->Fs_in_kHz );
+ silk_resampler_private_down_FIR( S, &out[ S->Fs_out_kHz ], &in[ nSamples ], inLen - S->Fs_in_kHz );
+ break;
+ default:
+ silk_memcpy( out, S->delayBuf, S->Fs_in_kHz * sizeof( opus_int16 ) );
+ silk_memcpy( &out[ S->Fs_out_kHz ], &in[ nSamples ], ( inLen - S->Fs_in_kHz ) * sizeof( opus_int16 ) );
+ }
+
+ /* Copy to delay buffer */
+ silk_memcpy( S->delayBuf, &in[ inLen - S->inputDelay ], S->inputDelay * sizeof( opus_int16 ) );
+
+ return 0;
+}
diff --git a/drivers/opus/silk/resampler_down2.c b/drivers/opus/silk/resampler_down2.c
new file mode 100644
index 0000000000..dbc962c5ef
--- /dev/null
+++ b/drivers/opus/silk/resampler_down2.c
@@ -0,0 +1,74 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/SigProc_FIX.h"
+#include "opus/silk/resampler_rom.h"
+
+/* Downsample by a factor 2 */
+void silk_resampler_down2(
+ opus_int32 *S, /* I/O State vector [ 2 ] */
+ opus_int16 *out, /* O Output signal [ floor(len/2) ] */
+ const opus_int16 *in, /* I Input signal [ len ] */
+ opus_int32 inLen /* I Number of input samples */
+)
+{
+ opus_int32 k, len2 = silk_RSHIFT32( inLen, 1 );
+ opus_int32 in32, out32, Y, X;
+
+ silk_assert( silk_resampler_down2_0 > 0 );
+ silk_assert( silk_resampler_down2_1 < 0 );
+
+ /* Internal variables and state are in Q10 format */
+ for( k = 0; k < len2; k++ ) {
+ /* Convert to Q10 */
+ in32 = silk_LSHIFT( (opus_int32)in[ 2 * k ], 10 );
+
+ /* All-pass section for even input sample */
+ Y = silk_SUB32( in32, S[ 0 ] );
+ X = silk_SMLAWB( Y, Y, silk_resampler_down2_1 );
+ out32 = silk_ADD32( S[ 0 ], X );
+ S[ 0 ] = silk_ADD32( in32, X );
+
+ /* Convert to Q10 */
+ in32 = silk_LSHIFT( (opus_int32)in[ 2 * k + 1 ], 10 );
+
+ /* All-pass section for odd input sample, and add to output of previous section */
+ Y = silk_SUB32( in32, S[ 1 ] );
+ X = silk_SMULWB( Y, silk_resampler_down2_0 );
+ out32 = silk_ADD32( out32, S[ 1 ] );
+ out32 = silk_ADD32( out32, X );
+ S[ 1 ] = silk_ADD32( in32, X );
+
+ /* Add, convert back to int16 and store to output */
+ out[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32, 11 ) );
+ }
+}
+
diff --git a/drivers/opus/silk/resampler_down2_3.c b/drivers/opus/silk/resampler_down2_3.c
new file mode 100644
index 0000000000..6ff32ff336
--- /dev/null
+++ b/drivers/opus/silk/resampler_down2_3.c
@@ -0,0 +1,103 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/SigProc_FIX.h"
+#include "opus/silk/resampler_private.h"
+#include "opus/celt/stack_alloc.h"
+
+#define ORDER_FIR 4
+
+/* Downsample by a factor 2/3, low quality */
+void silk_resampler_down2_3(
+ opus_int32 *S, /* I/O State vector [ 6 ] */
+ opus_int16 *out, /* O Output signal [ floor(2*inLen/3) ] */
+ const opus_int16 *in, /* I Input signal [ inLen ] */
+ opus_int32 inLen /* I Number of input samples */
+)
+{
+ opus_int32 nSamplesIn, counter, res_Q6;
+ VARDECL( opus_int32, buf );
+ opus_int32 *buf_ptr;
+ SAVE_STACK;
+
+ ALLOC( buf, RESAMPLER_MAX_BATCH_SIZE_IN + ORDER_FIR, opus_int32 );
+
+ /* Copy buffered samples to start of buffer */
+ silk_memcpy( buf, S, ORDER_FIR * sizeof( opus_int32 ) );
+
+ /* Iterate over blocks of frameSizeIn input samples */
+ while( 1 ) {
+ nSamplesIn = silk_min( inLen, RESAMPLER_MAX_BATCH_SIZE_IN );
+
+ /* Second-order AR filter (output in Q8) */
+ silk_resampler_private_AR2( &S[ ORDER_FIR ], &buf[ ORDER_FIR ], in,
+ silk_Resampler_2_3_COEFS_LQ, nSamplesIn );
+
+ /* Interpolate filtered signal */
+ buf_ptr = buf;
+ counter = nSamplesIn;
+ while( counter > 2 ) {
+ /* Inner product */
+ res_Q6 = silk_SMULWB( buf_ptr[ 0 ], silk_Resampler_2_3_COEFS_LQ[ 2 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 1 ], silk_Resampler_2_3_COEFS_LQ[ 3 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], silk_Resampler_2_3_COEFS_LQ[ 5 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], silk_Resampler_2_3_COEFS_LQ[ 4 ] );
+
+ /* Scale down, saturate and store in output array */
+ *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) );
+
+ res_Q6 = silk_SMULWB( buf_ptr[ 1 ], silk_Resampler_2_3_COEFS_LQ[ 4 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], silk_Resampler_2_3_COEFS_LQ[ 5 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], silk_Resampler_2_3_COEFS_LQ[ 3 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 4 ], silk_Resampler_2_3_COEFS_LQ[ 2 ] );
+
+ /* Scale down, saturate and store in output array */
+ *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) );
+
+ buf_ptr += 3;
+ counter -= 3;
+ }
+
+ in += nSamplesIn;
+ inLen -= nSamplesIn;
+
+ if( inLen > 0 ) {
+ /* More iterations to do; copy last part of filtered signal to beginning of buffer */
+ silk_memcpy( buf, &buf[ nSamplesIn ], ORDER_FIR * sizeof( opus_int32 ) );
+ } else {
+ break;
+ }
+ }
+
+ /* Copy last part of filtered signal to the state for the next call */
+ silk_memcpy( S, &buf[ nSamplesIn ], ORDER_FIR * sizeof( opus_int32 ) );
+ RESTORE_STACK;
+}
diff --git a/drivers/opus/silk/resampler_private.h b/drivers/opus/silk/resampler_private.h
new file mode 100644
index 0000000000..5c0ee110fc
--- /dev/null
+++ b/drivers/opus/silk/resampler_private.h
@@ -0,0 +1,88 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_RESAMPLER_PRIVATE_H
+#define SILK_RESAMPLER_PRIVATE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "opus/silk/SigProc_FIX.h"
+#include "opus/silk/resampler_structs.h"
+#include "opus/silk/resampler_rom.h"
+
+/* Number of input samples to process in the inner loop */
+#define RESAMPLER_MAX_BATCH_SIZE_MS 10
+#define RESAMPLER_MAX_FS_KHZ 48
+#define RESAMPLER_MAX_BATCH_SIZE_IN ( RESAMPLER_MAX_BATCH_SIZE_MS * RESAMPLER_MAX_FS_KHZ )
+
+/* Description: Hybrid IIR/FIR polyphase implementation of resampling */
+void silk_resampler_private_IIR_FIR(
+ void *SS, /* I/O Resampler state */
+ opus_int16 out[], /* O Output signal */
+ const opus_int16 in[], /* I Input signal */
+ opus_int32 inLen /* I Number of input samples */
+);
+
+/* Description: Hybrid IIR/FIR polyphase implementation of resampling */
+void silk_resampler_private_down_FIR(
+ void *SS, /* I/O Resampler state */
+ opus_int16 out[], /* O Output signal */
+ const opus_int16 in[], /* I Input signal */
+ opus_int32 inLen /* I Number of input samples */
+);
+
+/* Upsample by a factor 2, high quality */
+void silk_resampler_private_up2_HQ_wrapper(
+ void *SS, /* I/O Resampler state (unused) */
+ opus_int16 *out, /* O Output signal [ 2 * len ] */
+ const opus_int16 *in, /* I Input signal [ len ] */
+ opus_int32 len /* I Number of input samples */
+);
+
+/* Upsample by a factor 2, high quality */
+void silk_resampler_private_up2_HQ(
+ opus_int32 *S, /* I/O Resampler state [ 6 ] */
+ opus_int16 *out, /* O Output signal [ 2 * len ] */
+ const opus_int16 *in, /* I Input signal [ len ] */
+ opus_int32 len /* I Number of input samples */
+);
+
+/* Second order AR filter */
+void silk_resampler_private_AR2(
+ opus_int32 S[], /* I/O State vector [ 2 ] */
+ opus_int32 out_Q8[], /* O Output signal */
+ const opus_int16 in[], /* I Input signal */
+ const opus_int16 A_Q14[], /* I AR coefficients, Q14 */
+ opus_int32 len /* I Signal length */
+);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* SILK_RESAMPLER_PRIVATE_H */
diff --git a/drivers/opus/silk/resampler_private_AR2.c b/drivers/opus/silk/resampler_private_AR2.c
new file mode 100644
index 0000000000..e04319da4d
--- /dev/null
+++ b/drivers/opus/silk/resampler_private_AR2.c
@@ -0,0 +1,55 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/SigProc_FIX.h"
+#include "opus/silk/resampler_private.h"
+
+/* Second order AR filter with single delay elements */
+void silk_resampler_private_AR2(
+ opus_int32 S[], /* I/O State vector [ 2 ] */
+ opus_int32 out_Q8[], /* O Output signal */
+ const opus_int16 in[], /* I Input signal */
+ const opus_int16 A_Q14[], /* I AR coefficients, Q14 */
+ opus_int32 len /* I Signal length */
+)
+{
+ opus_int32 k;
+ opus_int32 out32;
+
+ for( k = 0; k < len; k++ ) {
+ out32 = silk_ADD_LSHIFT32( S[ 0 ], (opus_int32)in[ k ], 8 );
+ out_Q8[ k ] = out32;
+ out32 = silk_LSHIFT( out32, 2 );
+ S[ 0 ] = silk_SMLAWB( S[ 1 ], out32, A_Q14[ 0 ] );
+ S[ 1 ] = silk_SMULWB( out32, A_Q14[ 1 ] );
+ }
+}
+
diff --git a/drivers/opus/silk/resampler_private_IIR_FIR.c b/drivers/opus/silk/resampler_private_IIR_FIR.c
new file mode 100644
index 0000000000..1d71ebd891
--- /dev/null
+++ b/drivers/opus/silk/resampler_private_IIR_FIR.c
@@ -0,0 +1,107 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/SigProc_FIX.h"
+#include "opus/silk/resampler_private.h"
+#include "opus/celt/stack_alloc.h"
+
+static OPUS_INLINE opus_int16 *silk_resampler_private_IIR_FIR_INTERPOL(
+ opus_int16 *out,
+ opus_int16 *buf,
+ opus_int32 max_index_Q16,
+ opus_int32 index_increment_Q16
+)
+{
+ opus_int32 index_Q16, res_Q15;
+ opus_int16 *buf_ptr;
+ opus_int32 table_index;
+
+ /* Interpolate upsampled signal and store in output array */
+ for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) {
+ table_index = silk_SMULWB( index_Q16 & 0xFFFF, 12 );
+ buf_ptr = &buf[ index_Q16 >> 16 ];
+
+ res_Q15 = silk_SMULBB( buf_ptr[ 0 ], silk_resampler_frac_FIR_12[ table_index ][ 0 ] );
+ res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 1 ], silk_resampler_frac_FIR_12[ table_index ][ 1 ] );
+ res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 2 ], silk_resampler_frac_FIR_12[ table_index ][ 2 ] );
+ res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 3 ], silk_resampler_frac_FIR_12[ table_index ][ 3 ] );
+ res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 4 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 3 ] );
+ res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 5 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 2 ] );
+ res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 6 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 1 ] );
+ res_Q15 = silk_SMLABB( res_Q15, buf_ptr[ 7 ], silk_resampler_frac_FIR_12[ 11 - table_index ][ 0 ] );
+ *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q15, 15 ) );
+ }
+ return out;
+}
+/* Upsample using a combination of allpass-based 2x upsampling and FIR interpolation */
+void silk_resampler_private_IIR_FIR(
+ void *SS, /* I/O Resampler state */
+ opus_int16 out[], /* O Output signal */
+ const opus_int16 in[], /* I Input signal */
+ opus_int32 inLen /* I Number of input samples */
+)
+{
+ silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS;
+ opus_int32 nSamplesIn;
+ opus_int32 max_index_Q16, index_increment_Q16;
+ VARDECL( opus_int16, buf );
+ SAVE_STACK;
+
+ ALLOC( buf, 2 * S->batchSize + RESAMPLER_ORDER_FIR_12, opus_int16 );
+
+ /* Copy buffered samples to start of buffer */
+ silk_memcpy( buf, S->sFIR.i16, RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) );
+
+ /* Iterate over blocks of frameSizeIn input samples */
+ index_increment_Q16 = S->invRatio_Q16;
+ while( 1 ) {
+ nSamplesIn = silk_min( inLen, S->batchSize );
+
+ /* Upsample 2x */
+ silk_resampler_private_up2_HQ( S->sIIR, &buf[ RESAMPLER_ORDER_FIR_12 ], in, nSamplesIn );
+
+ max_index_Q16 = silk_LSHIFT32( nSamplesIn, 16 + 1 ); /* + 1 because 2x upsampling */
+ out = silk_resampler_private_IIR_FIR_INTERPOL( out, buf, max_index_Q16, index_increment_Q16 );
+ in += nSamplesIn;
+ inLen -= nSamplesIn;
+
+ if( inLen > 0 ) {
+ /* More iterations to do; copy last part of filtered signal to beginning of buffer */
+ silk_memcpy( buf, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) );
+ } else {
+ break;
+ }
+ }
+
+ /* Copy last part of filtered signal to the state for the next call */
+ silk_memcpy( S->sFIR.i16, &buf[ nSamplesIn << 1 ], RESAMPLER_ORDER_FIR_12 * sizeof( opus_int16 ) );
+ RESTORE_STACK;
+}
diff --git a/drivers/opus/silk/resampler_private_down_FIR.c b/drivers/opus/silk/resampler_private_down_FIR.c
new file mode 100644
index 0000000000..739c91db29
--- /dev/null
+++ b/drivers/opus/silk/resampler_private_down_FIR.c
@@ -0,0 +1,194 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/SigProc_FIX.h"
+#include "opus/silk/resampler_private.h"
+#include "opus/celt/stack_alloc.h"
+
+static OPUS_INLINE opus_int16 *silk_resampler_private_down_FIR_INTERPOL(
+ opus_int16 *out,
+ opus_int32 *buf,
+ const opus_int16 *FIR_Coefs,
+ opus_int FIR_Order,
+ opus_int FIR_Fracs,
+ opus_int32 max_index_Q16,
+ opus_int32 index_increment_Q16
+)
+{
+ opus_int32 index_Q16, res_Q6;
+ opus_int32 *buf_ptr;
+ opus_int32 interpol_ind;
+ const opus_int16 *interpol_ptr;
+
+ switch( FIR_Order ) {
+ case RESAMPLER_DOWN_ORDER_FIR0:
+ for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) {
+ /* Integer part gives pointer to buffered input */
+ buf_ptr = buf + silk_RSHIFT( index_Q16, 16 );
+
+ /* Fractional part gives interpolation coefficients */
+ interpol_ind = silk_SMULWB( index_Q16 & 0xFFFF, FIR_Fracs );
+
+ /* Inner product */
+ interpol_ptr = &FIR_Coefs[ RESAMPLER_DOWN_ORDER_FIR0 / 2 * interpol_ind ];
+ res_Q6 = silk_SMULWB( buf_ptr[ 0 ], interpol_ptr[ 0 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 1 ], interpol_ptr[ 1 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 2 ], interpol_ptr[ 2 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 3 ], interpol_ptr[ 3 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 4 ], interpol_ptr[ 4 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 5 ], interpol_ptr[ 5 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 6 ], interpol_ptr[ 6 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 7 ], interpol_ptr[ 7 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 8 ], interpol_ptr[ 8 ] );
+ interpol_ptr = &FIR_Coefs[ RESAMPLER_DOWN_ORDER_FIR0 / 2 * ( FIR_Fracs - 1 - interpol_ind ) ];
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 17 ], interpol_ptr[ 0 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 16 ], interpol_ptr[ 1 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 15 ], interpol_ptr[ 2 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 14 ], interpol_ptr[ 3 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 13 ], interpol_ptr[ 4 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 12 ], interpol_ptr[ 5 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 11 ], interpol_ptr[ 6 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 10 ], interpol_ptr[ 7 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, buf_ptr[ 9 ], interpol_ptr[ 8 ] );
+
+ /* Scale down, saturate and store in output array */
+ *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) );
+ }
+ break;
+ case RESAMPLER_DOWN_ORDER_FIR1:
+ for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) {
+ /* Integer part gives pointer to buffered input */
+ buf_ptr = buf + silk_RSHIFT( index_Q16, 16 );
+
+ /* Inner product */
+ res_Q6 = silk_SMULWB( silk_ADD32( buf_ptr[ 0 ], buf_ptr[ 23 ] ), FIR_Coefs[ 0 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 1 ], buf_ptr[ 22 ] ), FIR_Coefs[ 1 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 2 ], buf_ptr[ 21 ] ), FIR_Coefs[ 2 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 3 ], buf_ptr[ 20 ] ), FIR_Coefs[ 3 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 4 ], buf_ptr[ 19 ] ), FIR_Coefs[ 4 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 5 ], buf_ptr[ 18 ] ), FIR_Coefs[ 5 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 6 ], buf_ptr[ 17 ] ), FIR_Coefs[ 6 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 7 ], buf_ptr[ 16 ] ), FIR_Coefs[ 7 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 8 ], buf_ptr[ 15 ] ), FIR_Coefs[ 8 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 9 ], buf_ptr[ 14 ] ), FIR_Coefs[ 9 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 10 ], buf_ptr[ 13 ] ), FIR_Coefs[ 10 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 11 ], buf_ptr[ 12 ] ), FIR_Coefs[ 11 ] );
+
+ /* Scale down, saturate and store in output array */
+ *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) );
+ }
+ break;
+ case RESAMPLER_DOWN_ORDER_FIR2:
+ for( index_Q16 = 0; index_Q16 < max_index_Q16; index_Q16 += index_increment_Q16 ) {
+ /* Integer part gives pointer to buffered input */
+ buf_ptr = buf + silk_RSHIFT( index_Q16, 16 );
+
+ /* Inner product */
+ res_Q6 = silk_SMULWB( silk_ADD32( buf_ptr[ 0 ], buf_ptr[ 35 ] ), FIR_Coefs[ 0 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 1 ], buf_ptr[ 34 ] ), FIR_Coefs[ 1 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 2 ], buf_ptr[ 33 ] ), FIR_Coefs[ 2 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 3 ], buf_ptr[ 32 ] ), FIR_Coefs[ 3 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 4 ], buf_ptr[ 31 ] ), FIR_Coefs[ 4 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 5 ], buf_ptr[ 30 ] ), FIR_Coefs[ 5 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 6 ], buf_ptr[ 29 ] ), FIR_Coefs[ 6 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 7 ], buf_ptr[ 28 ] ), FIR_Coefs[ 7 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 8 ], buf_ptr[ 27 ] ), FIR_Coefs[ 8 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 9 ], buf_ptr[ 26 ] ), FIR_Coefs[ 9 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 10 ], buf_ptr[ 25 ] ), FIR_Coefs[ 10 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 11 ], buf_ptr[ 24 ] ), FIR_Coefs[ 11 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 12 ], buf_ptr[ 23 ] ), FIR_Coefs[ 12 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 13 ], buf_ptr[ 22 ] ), FIR_Coefs[ 13 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 14 ], buf_ptr[ 21 ] ), FIR_Coefs[ 14 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 15 ], buf_ptr[ 20 ] ), FIR_Coefs[ 15 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 16 ], buf_ptr[ 19 ] ), FIR_Coefs[ 16 ] );
+ res_Q6 = silk_SMLAWB( res_Q6, silk_ADD32( buf_ptr[ 17 ], buf_ptr[ 18 ] ), FIR_Coefs[ 17 ] );
+
+ /* Scale down, saturate and store in output array */
+ *out++ = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( res_Q6, 6 ) );
+ }
+ break;
+ default:
+ silk_assert( 0 );
+ }
+ return out;
+}
+
+/* Resample with a 2nd order AR filter followed by FIR interpolation */
+void silk_resampler_private_down_FIR(
+ void *SS, /* I/O Resampler state */
+ opus_int16 out[], /* O Output signal */
+ const opus_int16 in[], /* I Input signal */
+ opus_int32 inLen /* I Number of input samples */
+)
+{
+ silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS;
+ opus_int32 nSamplesIn;
+ opus_int32 max_index_Q16, index_increment_Q16;
+ VARDECL( opus_int32, buf );
+ const opus_int16 *FIR_Coefs;
+ SAVE_STACK;
+
+ ALLOC( buf, S->batchSize + S->FIR_Order, opus_int32 );
+
+ /* Copy buffered samples to start of buffer */
+ silk_memcpy( buf, S->sFIR.i32, S->FIR_Order * sizeof( opus_int32 ) );
+
+ FIR_Coefs = &S->Coefs[ 2 ];
+
+ /* Iterate over blocks of frameSizeIn input samples */
+ index_increment_Q16 = S->invRatio_Q16;
+ while( 1 ) {
+ nSamplesIn = silk_min( inLen, S->batchSize );
+
+ /* Second-order AR filter (output in Q8) */
+ silk_resampler_private_AR2( S->sIIR, &buf[ S->FIR_Order ], in, S->Coefs, nSamplesIn );
+
+ max_index_Q16 = silk_LSHIFT32( nSamplesIn, 16 );
+
+ /* Interpolate filtered signal */
+ out = silk_resampler_private_down_FIR_INTERPOL( out, buf, FIR_Coefs, S->FIR_Order,
+ S->FIR_Fracs, max_index_Q16, index_increment_Q16 );
+
+ in += nSamplesIn;
+ inLen -= nSamplesIn;
+
+ if( inLen > 1 ) {
+ /* More iterations to do; copy last part of filtered signal to beginning of buffer */
+ silk_memcpy( buf, &buf[ nSamplesIn ], S->FIR_Order * sizeof( opus_int32 ) );
+ } else {
+ break;
+ }
+ }
+
+ /* Copy last part of filtered signal to the state for the next call */
+ silk_memcpy( S->sFIR.i32, &buf[ nSamplesIn ], S->FIR_Order * sizeof( opus_int32 ) );
+ RESTORE_STACK;
+}
diff --git a/drivers/opus/silk/resampler_private_up2_HQ.c b/drivers/opus/silk/resampler_private_up2_HQ.c
new file mode 100644
index 0000000000..a2b6ad432e
--- /dev/null
+++ b/drivers/opus/silk/resampler_private_up2_HQ.c
@@ -0,0 +1,113 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/SigProc_FIX.h"
+#include "opus/silk/resampler_private.h"
+
+/* Upsample by a factor 2, high quality */
+/* Uses 2nd order allpass filters for the 2x upsampling, followed by a */
+/* notch filter just above Nyquist. */
+void silk_resampler_private_up2_HQ(
+ opus_int32 *S, /* I/O Resampler state [ 6 ] */
+ opus_int16 *out, /* O Output signal [ 2 * len ] */
+ const opus_int16 *in, /* I Input signal [ len ] */
+ opus_int32 len /* I Number of input samples */
+)
+{
+ opus_int32 k;
+ opus_int32 in32, out32_1, out32_2, Y, X;
+
+ silk_assert( silk_resampler_up2_hq_0[ 0 ] > 0 );
+ silk_assert( silk_resampler_up2_hq_0[ 1 ] > 0 );
+ silk_assert( silk_resampler_up2_hq_0[ 2 ] < 0 );
+ silk_assert( silk_resampler_up2_hq_1[ 0 ] > 0 );
+ silk_assert( silk_resampler_up2_hq_1[ 1 ] > 0 );
+ silk_assert( silk_resampler_up2_hq_1[ 2 ] < 0 );
+
+ /* Internal variables and state are in Q10 format */
+ for( k = 0; k < len; k++ ) {
+ /* Convert to Q10 */
+ in32 = silk_LSHIFT( (opus_int32)in[ k ], 10 );
+
+ /* First all-pass section for even output sample */
+ Y = silk_SUB32( in32, S[ 0 ] );
+ X = silk_SMULWB( Y, silk_resampler_up2_hq_0[ 0 ] );
+ out32_1 = silk_ADD32( S[ 0 ], X );
+ S[ 0 ] = silk_ADD32( in32, X );
+
+ /* Second all-pass section for even output sample */
+ Y = silk_SUB32( out32_1, S[ 1 ] );
+ X = silk_SMULWB( Y, silk_resampler_up2_hq_0[ 1 ] );
+ out32_2 = silk_ADD32( S[ 1 ], X );
+ S[ 1 ] = silk_ADD32( out32_1, X );
+
+ /* Third all-pass section for even output sample */
+ Y = silk_SUB32( out32_2, S[ 2 ] );
+ X = silk_SMLAWB( Y, Y, silk_resampler_up2_hq_0[ 2 ] );
+ out32_1 = silk_ADD32( S[ 2 ], X );
+ S[ 2 ] = silk_ADD32( out32_2, X );
+
+ /* Apply gain in Q15, convert back to int16 and store to output */
+ out[ 2 * k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32_1, 10 ) );
+
+ /* First all-pass section for odd output sample */
+ Y = silk_SUB32( in32, S[ 3 ] );
+ X = silk_SMULWB( Y, silk_resampler_up2_hq_1[ 0 ] );
+ out32_1 = silk_ADD32( S[ 3 ], X );
+ S[ 3 ] = silk_ADD32( in32, X );
+
+ /* Second all-pass section for odd output sample */
+ Y = silk_SUB32( out32_1, S[ 4 ] );
+ X = silk_SMULWB( Y, silk_resampler_up2_hq_1[ 1 ] );
+ out32_2 = silk_ADD32( S[ 4 ], X );
+ S[ 4 ] = silk_ADD32( out32_1, X );
+
+ /* Third all-pass section for odd output sample */
+ Y = silk_SUB32( out32_2, S[ 5 ] );
+ X = silk_SMLAWB( Y, Y, silk_resampler_up2_hq_1[ 2 ] );
+ out32_1 = silk_ADD32( S[ 5 ], X );
+ S[ 5 ] = silk_ADD32( out32_2, X );
+
+ /* Apply gain in Q15, convert back to int16 and store to output */
+ out[ 2 * k + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( out32_1, 10 ) );
+ }
+}
+
+void silk_resampler_private_up2_HQ_wrapper(
+ void *SS, /* I/O Resampler state (unused) */
+ opus_int16 *out, /* O Output signal [ 2 * len ] */
+ const opus_int16 *in, /* I Input signal [ len ] */
+ opus_int32 len /* I Number of input samples */
+)
+{
+ silk_resampler_state_struct *S = (silk_resampler_state_struct *)SS;
+ silk_resampler_private_up2_HQ( S->sIIR, out, in, len );
+}
diff --git a/drivers/opus/silk/resampler_rom.c b/drivers/opus/silk/resampler_rom.c
new file mode 100644
index 0000000000..d564087051
--- /dev/null
+++ b/drivers/opus/silk/resampler_rom.c
@@ -0,0 +1,96 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+/* Filter coefficients for IIR/FIR polyphase resampling *
+ * Total size: 179 Words (358 Bytes) */
+
+#include "opus/silk/resampler_private.h"
+
+/* Matlab code for the notch filter coefficients: */
+/* B = [1, 0.147, 1]; A = [1, 0.107, 0.89]; G = 0.93; freqz(G * B, A, 2^14, 16e3); axis([0, 8000, -10, 1]) */
+/* fprintf('\t%6d, %6d, %6d, %6d\n', round(B(2)*2^16), round(-A(2)*2^16), round((1-A(3))*2^16), round(G*2^15)) */
+/* const opus_int16 silk_resampler_up2_hq_notch[ 4 ] = { 9634, -7012, 7209, 30474 }; */
+
+/* Tables with IIR and FIR coefficients for fractional downsamplers (123 Words) */
+silk_DWORD_ALIGN const opus_int16 silk_Resampler_3_4_COEFS[ 2 + 3 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ] = {
+ -20694, -13867,
+ -49, 64, 17, -157, 353, -496, 163, 11047, 22205,
+ -39, 6, 91, -170, 186, 23, -896, 6336, 19928,
+ -19, -36, 102, -89, -24, 328, -951, 2568, 15909,
+};
+
+silk_DWORD_ALIGN const opus_int16 silk_Resampler_2_3_COEFS[ 2 + 2 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ] = {
+ -14457, -14019,
+ 64, 128, -122, 36, 310, -768, 584, 9267, 17733,
+ 12, 128, 18, -142, 288, -117, -865, 4123, 14459,
+};
+
+silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_2_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR1 / 2 ] = {
+ 616, -14323,
+ -10, 39, 58, -46, -84, 120, 184, -315, -541, 1284, 5380, 9024,
+};
+
+silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_3_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ] = {
+ 16102, -15162,
+ -13, 0, 20, 26, 5, -31, -43, -4, 65, 90, 7, -157, -248, -44, 593, 1583, 2612, 3271,
+};
+
+silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_4_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ] = {
+ 22500, -15099,
+ 3, -14, -20, -15, 2, 25, 37, 25, -16, -71, -107, -79, 50, 292, 623, 982, 1288, 1464,
+};
+
+silk_DWORD_ALIGN const opus_int16 silk_Resampler_1_6_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ] = {
+ 27540, -15257,
+ 17, 12, 8, 1, -10, -22, -30, -32, -22, 3, 44, 100, 168, 243, 317, 381, 429, 455,
+};
+
+silk_DWORD_ALIGN const opus_int16 silk_Resampler_2_3_COEFS_LQ[ 2 + 2 * 2 ] = {
+ -2797, -6507,
+ 4697, 10739,
+ 1567, 8276,
+};
+
+/* Table with interplation fractions of 1/24, 3/24, 5/24, ... , 23/24 : 23/24 (46 Words) */
+silk_DWORD_ALIGN const opus_int16 silk_resampler_frac_FIR_12[ 12 ][ RESAMPLER_ORDER_FIR_12 / 2 ] = {
+ { 189, -600, 617, 30567 },
+ { 117, -159, -1070, 29704 },
+ { 52, 221, -2392, 28276 },
+ { -4, 529, -3350, 26341 },
+ { -48, 758, -3956, 23973 },
+ { -80, 905, -4235, 21254 },
+ { -99, 972, -4222, 18278 },
+ { -107, 967, -3957, 15143 },
+ { -103, 896, -3487, 11950 },
+ { -91, 773, -2865, 8798 },
+ { -71, 611, -2143, 5784 },
+ { -46, 425, -1375, 2996 },
+};
diff --git a/drivers/opus/silk/resampler_rom.h b/drivers/opus/silk/resampler_rom.h
new file mode 100644
index 0000000000..2fa586ebf2
--- /dev/null
+++ b/drivers/opus/silk/resampler_rom.h
@@ -0,0 +1,68 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_FIX_RESAMPLER_ROM_H
+#define SILK_FIX_RESAMPLER_ROM_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "opus/silk/typedef.h"
+#include "opus/silk/resampler_structs.h"
+
+#define RESAMPLER_DOWN_ORDER_FIR0 18
+#define RESAMPLER_DOWN_ORDER_FIR1 24
+#define RESAMPLER_DOWN_ORDER_FIR2 36
+#define RESAMPLER_ORDER_FIR_12 8
+
+/* Tables for 2x downsampler */
+static const opus_int16 silk_resampler_down2_0 = 9872;
+static const opus_int16 silk_resampler_down2_1 = 39809 - 65536;
+
+/* Tables for 2x upsampler, high quality */
+static const opus_int16 silk_resampler_up2_hq_0[ 3 ] = { 1746, 14986, 39083 - 65536 };
+static const opus_int16 silk_resampler_up2_hq_1[ 3 ] = { 6854, 25769, 55542 - 65536 };
+
+/* Tables with IIR and FIR coefficients for fractional downsamplers */
+extern const opus_int16 silk_Resampler_3_4_COEFS[ 2 + 3 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ];
+extern const opus_int16 silk_Resampler_2_3_COEFS[ 2 + 2 * RESAMPLER_DOWN_ORDER_FIR0 / 2 ];
+extern const opus_int16 silk_Resampler_1_2_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR1 / 2 ];
+extern const opus_int16 silk_Resampler_1_3_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ];
+extern const opus_int16 silk_Resampler_1_4_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ];
+extern const opus_int16 silk_Resampler_1_6_COEFS[ 2 + RESAMPLER_DOWN_ORDER_FIR2 / 2 ];
+extern const opus_int16 silk_Resampler_2_3_COEFS_LQ[ 2 + 2 * 2 ];
+
+/* Table with interplation fractions of 1/24, 3/24, ..., 23/24 */
+extern const opus_int16 silk_resampler_frac_FIR_12[ 12 ][ RESAMPLER_ORDER_FIR_12 / 2 ];
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SILK_FIX_RESAMPLER_ROM_H */
diff --git a/drivers/opus/silk/resampler_structs.h b/drivers/opus/silk/resampler_structs.h
new file mode 100644
index 0000000000..9e9457d11c
--- /dev/null
+++ b/drivers/opus/silk/resampler_structs.h
@@ -0,0 +1,60 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_RESAMPLER_STRUCTS_H
+#define SILK_RESAMPLER_STRUCTS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define SILK_RESAMPLER_MAX_FIR_ORDER 36
+#define SILK_RESAMPLER_MAX_IIR_ORDER 6
+
+typedef struct _silk_resampler_state_struct{
+ opus_int32 sIIR[ SILK_RESAMPLER_MAX_IIR_ORDER ]; /* this must be the first element of this struct */
+ union{
+ opus_int32 i32[ SILK_RESAMPLER_MAX_FIR_ORDER ];
+ opus_int16 i16[ SILK_RESAMPLER_MAX_FIR_ORDER ];
+ } sFIR;
+ opus_int16 delayBuf[ 48 ];
+ opus_int resampler_function;
+ opus_int batchSize;
+ opus_int32 invRatio_Q16;
+ opus_int FIR_Order;
+ opus_int FIR_Fracs;
+ opus_int Fs_in_kHz;
+ opus_int Fs_out_kHz;
+ opus_int inputDelay;
+ const opus_int16 *Coefs;
+} silk_resampler_state_struct;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* SILK_RESAMPLER_STRUCTS_H */
+
diff --git a/drivers/opus/silk/shell_coder.c b/drivers/opus/silk/shell_coder.c
new file mode 100644
index 0000000000..cd18ed638b
--- /dev/null
+++ b/drivers/opus/silk/shell_coder.c
@@ -0,0 +1,151 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+
+/* shell coder; pulse-subframe length is hardcoded */
+
+static OPUS_INLINE void combine_pulses(
+ opus_int *out, /* O combined pulses vector [len] */
+ const opus_int *in, /* I input vector [2 * len] */
+ const opus_int len /* I number of OUTPUT samples */
+)
+{
+ opus_int k;
+ for( k = 0; k < len; k++ ) {
+ out[ k ] = in[ 2 * k ] + in[ 2 * k + 1 ];
+ }
+}
+
+static OPUS_INLINE void encode_split(
+ ec_enc *psRangeEnc, /* I/O compressor data structure */
+ const opus_int p_child1, /* I pulse amplitude of first child subframe */
+ const opus_int p, /* I pulse amplitude of current subframe */
+ const opus_uint8 *shell_table /* I table of shell cdfs */
+)
+{
+ if( p > 0 ) {
+ ec_enc_icdf( psRangeEnc, p_child1, &shell_table[ silk_shell_code_table_offsets[ p ] ], 8 );
+ }
+}
+
+static OPUS_INLINE void decode_split(
+ opus_int *p_child1, /* O pulse amplitude of first child subframe */
+ opus_int *p_child2, /* O pulse amplitude of second child subframe */
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ const opus_int p, /* I pulse amplitude of current subframe */
+ const opus_uint8 *shell_table /* I table of shell cdfs */
+)
+{
+ if( p > 0 ) {
+ p_child1[ 0 ] = ec_dec_icdf( psRangeDec, &shell_table[ silk_shell_code_table_offsets[ p ] ], 8 );
+ p_child2[ 0 ] = p - p_child1[ 0 ];
+ } else {
+ p_child1[ 0 ] = 0;
+ p_child2[ 0 ] = 0;
+ }
+}
+
+/* Shell encoder, operates on one shell code frame of 16 pulses */
+void silk_shell_encoder(
+ ec_enc *psRangeEnc, /* I/O compressor data structure */
+ const opus_int *pulses0 /* I data: nonnegative pulse amplitudes */
+)
+{
+ opus_int pulses1[ 8 ], pulses2[ 4 ], pulses3[ 2 ], pulses4[ 1 ];
+
+ /* this function operates on one shell code frame of 16 pulses */
+ silk_assert( SHELL_CODEC_FRAME_LENGTH == 16 );
+
+ /* tree representation per pulse-subframe */
+ combine_pulses( pulses1, pulses0, 8 );
+ combine_pulses( pulses2, pulses1, 4 );
+ combine_pulses( pulses3, pulses2, 2 );
+ combine_pulses( pulses4, pulses3, 1 );
+
+ encode_split( psRangeEnc, pulses3[ 0 ], pulses4[ 0 ], silk_shell_code_table3 );
+
+ encode_split( psRangeEnc, pulses2[ 0 ], pulses3[ 0 ], silk_shell_code_table2 );
+
+ encode_split( psRangeEnc, pulses1[ 0 ], pulses2[ 0 ], silk_shell_code_table1 );
+ encode_split( psRangeEnc, pulses0[ 0 ], pulses1[ 0 ], silk_shell_code_table0 );
+ encode_split( psRangeEnc, pulses0[ 2 ], pulses1[ 1 ], silk_shell_code_table0 );
+
+ encode_split( psRangeEnc, pulses1[ 2 ], pulses2[ 1 ], silk_shell_code_table1 );
+ encode_split( psRangeEnc, pulses0[ 4 ], pulses1[ 2 ], silk_shell_code_table0 );
+ encode_split( psRangeEnc, pulses0[ 6 ], pulses1[ 3 ], silk_shell_code_table0 );
+
+ encode_split( psRangeEnc, pulses2[ 2 ], pulses3[ 1 ], silk_shell_code_table2 );
+
+ encode_split( psRangeEnc, pulses1[ 4 ], pulses2[ 2 ], silk_shell_code_table1 );
+ encode_split( psRangeEnc, pulses0[ 8 ], pulses1[ 4 ], silk_shell_code_table0 );
+ encode_split( psRangeEnc, pulses0[ 10 ], pulses1[ 5 ], silk_shell_code_table0 );
+
+ encode_split( psRangeEnc, pulses1[ 6 ], pulses2[ 3 ], silk_shell_code_table1 );
+ encode_split( psRangeEnc, pulses0[ 12 ], pulses1[ 6 ], silk_shell_code_table0 );
+ encode_split( psRangeEnc, pulses0[ 14 ], pulses1[ 7 ], silk_shell_code_table0 );
+}
+
+
+/* Shell decoder, operates on one shell code frame of 16 pulses */
+void silk_shell_decoder(
+ opus_int *pulses0, /* O data: nonnegative pulse amplitudes */
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ const opus_int pulses4 /* I number of pulses per pulse-subframe */
+)
+{
+ opus_int pulses3[ 2 ], pulses2[ 4 ], pulses1[ 8 ];
+
+ /* this function operates on one shell code frame of 16 pulses */
+ silk_assert( SHELL_CODEC_FRAME_LENGTH == 16 );
+
+ decode_split( &pulses3[ 0 ], &pulses3[ 1 ], psRangeDec, pulses4, silk_shell_code_table3 );
+
+ decode_split( &pulses2[ 0 ], &pulses2[ 1 ], psRangeDec, pulses3[ 0 ], silk_shell_code_table2 );
+
+ decode_split( &pulses1[ 0 ], &pulses1[ 1 ], psRangeDec, pulses2[ 0 ], silk_shell_code_table1 );
+ decode_split( &pulses0[ 0 ], &pulses0[ 1 ], psRangeDec, pulses1[ 0 ], silk_shell_code_table0 );
+ decode_split( &pulses0[ 2 ], &pulses0[ 3 ], psRangeDec, pulses1[ 1 ], silk_shell_code_table0 );
+
+ decode_split( &pulses1[ 2 ], &pulses1[ 3 ], psRangeDec, pulses2[ 1 ], silk_shell_code_table1 );
+ decode_split( &pulses0[ 4 ], &pulses0[ 5 ], psRangeDec, pulses1[ 2 ], silk_shell_code_table0 );
+ decode_split( &pulses0[ 6 ], &pulses0[ 7 ], psRangeDec, pulses1[ 3 ], silk_shell_code_table0 );
+
+ decode_split( &pulses2[ 2 ], &pulses2[ 3 ], psRangeDec, pulses3[ 1 ], silk_shell_code_table2 );
+
+ decode_split( &pulses1[ 4 ], &pulses1[ 5 ], psRangeDec, pulses2[ 2 ], silk_shell_code_table1 );
+ decode_split( &pulses0[ 8 ], &pulses0[ 9 ], psRangeDec, pulses1[ 4 ], silk_shell_code_table0 );
+ decode_split( &pulses0[ 10 ], &pulses0[ 11 ], psRangeDec, pulses1[ 5 ], silk_shell_code_table0 );
+
+ decode_split( &pulses1[ 6 ], &pulses1[ 7 ], psRangeDec, pulses2[ 3 ], silk_shell_code_table1 );
+ decode_split( &pulses0[ 12 ], &pulses0[ 13 ], psRangeDec, pulses1[ 6 ], silk_shell_code_table0 );
+ decode_split( &pulses0[ 14 ], &pulses0[ 15 ], psRangeDec, pulses1[ 7 ], silk_shell_code_table0 );
+}
diff --git a/drivers/opus/silk/sigm_Q15.c b/drivers/opus/silk/sigm_Q15.c
new file mode 100644
index 0000000000..4c78250472
--- /dev/null
+++ b/drivers/opus/silk/sigm_Q15.c
@@ -0,0 +1,76 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+/* Approximate sigmoid function */
+
+#include "opus/silk/SigProc_FIX.h"
+
+/* fprintf(1, '%d, ', round(1024 * ([1 ./ (1 + exp(-(1:5))), 1] - 1 ./ (1 + exp(-(0:5)))))); */
+static const opus_int32 sigm_LUT_slope_Q10[ 6 ] = {
+ 237, 153, 73, 30, 12, 7
+};
+/* fprintf(1, '%d, ', round(32767 * 1 ./ (1 + exp(-(0:5))))); */
+static const opus_int32 sigm_LUT_pos_Q15[ 6 ] = {
+ 16384, 23955, 28861, 31213, 32178, 32548
+};
+/* fprintf(1, '%d, ', round(32767 * 1 ./ (1 + exp((0:5))))); */
+static const opus_int32 sigm_LUT_neg_Q15[ 6 ] = {
+ 16384, 8812, 3906, 1554, 589, 219
+};
+
+opus_int silk_sigm_Q15(
+ opus_int in_Q5 /* I */
+)
+{
+ opus_int ind;
+
+ if( in_Q5 < 0 ) {
+ /* Negative input */
+ in_Q5 = -in_Q5;
+ if( in_Q5 >= 6 * 32 ) {
+ return 0; /* Clip */
+ } else {
+ /* Linear interpolation of look up table */
+ ind = silk_RSHIFT( in_Q5, 5 );
+ return( sigm_LUT_neg_Q15[ ind ] - silk_SMULBB( sigm_LUT_slope_Q10[ ind ], in_Q5 & 0x1F ) );
+ }
+ } else {
+ /* Positive input */
+ if( in_Q5 >= 6 * 32 ) {
+ return 32767; /* clip */
+ } else {
+ /* Linear interpolation of look up table */
+ ind = silk_RSHIFT( in_Q5, 5 );
+ return( sigm_LUT_pos_Q15[ ind ] + silk_SMULBB( sigm_LUT_slope_Q10[ ind ], in_Q5 & 0x1F ) );
+ }
+ }
+}
+
diff --git a/drivers/opus/silk/silk_main.h b/drivers/opus/silk/silk_main.h
new file mode 100644
index 0000000000..14671dcf72
--- /dev/null
+++ b/drivers/opus/silk/silk_main.h
@@ -0,0 +1,438 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_MAIN_H
+#define SILK_MAIN_H
+
+#include "opus/silk/SigProc_FIX.h"
+#include "opus/silk/define.h"
+#include "opus/silk/structs.h"
+#include "opus/silk/tables.h"
+#include "opus/silk/PLC.h"
+#include "opus/silk/control.h"
+#include "opus/silk/debug.h"
+#include "opus/celt/entenc.h"
+#include "opus/celt/entdec.h"
+
+/* Convert Left/Right stereo signal to adaptive Mid/Side representation */
+void silk_stereo_LR_to_MS(
+ stereo_enc_state *state, /* I/O State */
+ opus_int16 x1[], /* I/O Left input signal, becomes mid signal */
+ opus_int16 x2[], /* I/O Right input signal, becomes side signal */
+ opus_int8 ix[ 2 ][ 3 ], /* O Quantization indices */
+ opus_int8 *mid_only_flag, /* O Flag: only mid signal coded */
+ opus_int32 mid_side_rates_bps[], /* O Bitrates for mid and side signals */
+ opus_int32 total_rate_bps, /* I Total bitrate */
+ opus_int prev_speech_act_Q8, /* I Speech activity level in previous frame */
+ opus_int toMono, /* I Last frame before a stereo->mono transition */
+ opus_int fs_kHz, /* I Sample rate (kHz) */
+ opus_int frame_length /* I Number of samples */
+);
+
+/* Convert adaptive Mid/Side representation to Left/Right stereo signal */
+void silk_stereo_MS_to_LR(
+ stereo_dec_state *state, /* I/O State */
+ opus_int16 x1[], /* I/O Left input signal, becomes mid signal */
+ opus_int16 x2[], /* I/O Right input signal, becomes side signal */
+ const opus_int32 pred_Q13[], /* I Predictors */
+ opus_int fs_kHz, /* I Samples rate (kHz) */
+ opus_int frame_length /* I Number of samples */
+);
+
+/* Find least-squares prediction gain for one signal based on another and quantize it */
+opus_int32 silk_stereo_find_predictor( /* O Returns predictor in Q13 */
+ opus_int32 *ratio_Q14, /* O Ratio of residual and mid energies */
+ const opus_int16 x[], /* I Basis signal */
+ const opus_int16 y[], /* I Target signal */
+ opus_int32 mid_res_amp_Q0[], /* I/O Smoothed mid, residual norms */
+ opus_int length, /* I Number of samples */
+ opus_int smooth_coef_Q16 /* I Smoothing coefficient */
+);
+
+/* Quantize mid/side predictors */
+void silk_stereo_quant_pred(
+ opus_int32 pred_Q13[], /* I/O Predictors (out: quantized) */
+ opus_int8 ix[ 2 ][ 3 ] /* O Quantization indices */
+);
+
+/* Entropy code the mid/side quantization indices */
+void silk_stereo_encode_pred(
+ ec_enc *psRangeEnc, /* I/O Compressor data structure */
+ opus_int8 ix[ 2 ][ 3 ] /* I Quantization indices */
+);
+
+/* Entropy code the mid-only flag */
+void silk_stereo_encode_mid_only(
+ ec_enc *psRangeEnc, /* I/O Compressor data structure */
+ opus_int8 mid_only_flag
+);
+
+/* Decode mid/side predictors */
+void silk_stereo_decode_pred(
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int32 pred_Q13[] /* O Predictors */
+);
+
+/* Decode mid-only flag */
+void silk_stereo_decode_mid_only(
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int *decode_only_mid /* O Flag that only mid channel has been coded */
+);
+
+/* Encodes signs of excitation */
+void silk_encode_signs(
+ ec_enc *psRangeEnc, /* I/O Compressor data structure */
+ const opus_int8 pulses[], /* I pulse signal */
+ opus_int length, /* I length of input */
+ const opus_int signalType, /* I Signal type */
+ const opus_int quantOffsetType, /* I Quantization offset type */
+ const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */
+);
+
+/* Decodes signs of excitation */
+void silk_decode_signs(
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int pulses[], /* I/O pulse signal */
+ opus_int length, /* I length of input */
+ const opus_int signalType, /* I Signal type */
+ const opus_int quantOffsetType, /* I Quantization offset type */
+ const opus_int sum_pulses[ MAX_NB_SHELL_BLOCKS ] /* I Sum of absolute pulses per block */
+);
+
+/* Check encoder control struct */
+opus_int check_control_input(
+ silk_EncControlStruct *encControl /* I Control structure */
+);
+
+/* Control internal sampling rate */
+opus_int silk_control_audio_bandwidth(
+ silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */
+ silk_EncControlStruct *encControl /* I Control structure */
+);
+
+/* Control SNR of redidual quantizer */
+opus_int silk_control_SNR(
+ silk_encoder_state *psEncC, /* I/O Pointer to Silk encoder state */
+ opus_int32 TargetRate_bps /* I Target max bitrate (bps) */
+);
+
+/***************/
+/* Shell coder */
+/***************/
+
+/* Encode quantization indices of excitation */
+void silk_encode_pulses(
+ ec_enc *psRangeEnc, /* I/O compressor data structure */
+ const opus_int signalType, /* I Signal type */
+ const opus_int quantOffsetType, /* I quantOffsetType */
+ opus_int8 pulses[], /* I quantization indices */
+ const opus_int frame_length /* I Frame length */
+);
+
+/* Shell encoder, operates on one shell code frame of 16 pulses */
+void silk_shell_encoder(
+ ec_enc *psRangeEnc, /* I/O compressor data structure */
+ const opus_int *pulses0 /* I data: nonnegative pulse amplitudes */
+);
+
+/* Shell decoder, operates on one shell code frame of 16 pulses */
+void silk_shell_decoder(
+ opus_int *pulses0, /* O data: nonnegative pulse amplitudes */
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ const opus_int pulses4 /* I number of pulses per pulse-subframe */
+);
+
+/* Gain scalar quantization with hysteresis, uniform on log scale */
+void silk_gains_quant(
+ opus_int8 ind[ MAX_NB_SUBFR ], /* O gain indices */
+ opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* I/O gains (quantized out) */
+ opus_int8 *prev_ind, /* I/O last index in previous frame */
+ const opus_int conditional, /* I first gain is delta coded if 1 */
+ const opus_int nb_subfr /* I number of subframes */
+);
+
+/* Gains scalar dequantization, uniform on log scale */
+void silk_gains_dequant(
+ opus_int32 gain_Q16[ MAX_NB_SUBFR ], /* O quantized gains */
+ const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */
+ opus_int8 *prev_ind, /* I/O last index in previous frame */
+ const opus_int conditional, /* I first gain is delta coded if 1 */
+ const opus_int nb_subfr /* I number of subframes */
+);
+
+/* Compute unique identifier of gain indices vector */
+opus_int32 silk_gains_ID( /* O returns unique identifier of gains */
+ const opus_int8 ind[ MAX_NB_SUBFR ], /* I gain indices */
+ const opus_int nb_subfr /* I number of subframes */
+);
+
+/* Interpolate two vectors */
+void silk_interpolate(
+ opus_int16 xi[ MAX_LPC_ORDER ], /* O interpolated vector */
+ const opus_int16 x0[ MAX_LPC_ORDER ], /* I first vector */
+ const opus_int16 x1[ MAX_LPC_ORDER ], /* I second vector */
+ const opus_int ifact_Q2, /* I interp. factor, weight on 2nd vector */
+ const opus_int d /* I number of parameters */
+);
+
+/* LTP tap quantizer */
+void silk_quant_LTP_gains(
+ opus_int16 B_Q14[ MAX_NB_SUBFR * LTP_ORDER ], /* I/O (un)quantized LTP gains */
+ opus_int8 cbk_index[ MAX_NB_SUBFR ], /* O Codebook Index */
+ opus_int8 *periodicity_index, /* O Periodicity Index */
+ opus_int32 *sum_gain_dB_Q7, /* I/O Cumulative max prediction gain */
+ const opus_int32 W_Q18[ MAX_NB_SUBFR*LTP_ORDER*LTP_ORDER ], /* I Error Weights in Q18 */
+ opus_int mu_Q9, /* I Mu value (R/D tradeoff) */
+ opus_int lowComplexity, /* I Flag for low complexity */
+ const opus_int nb_subfr /* I number of subframes */
+);
+
+/* Entropy constrained matrix-weighted VQ, for a single input data vector */
+void silk_VQ_WMat_EC(
+ opus_int8 *ind, /* O index of best codebook vector */
+ opus_int32 *rate_dist_Q14, /* O best weighted quant error + mu * rate */
+ opus_int *gain_Q7, /* O sum of absolute LTP coefficients */
+ const opus_int16 *in_Q14, /* I input vector to be quantized */
+ const opus_int32 *W_Q18, /* I weighting matrix */
+ const opus_int8 *cb_Q7, /* I codebook */
+ const opus_uint8 *cb_gain_Q7, /* I codebook effective gain */
+ const opus_uint8 *cl_Q5, /* I code length for each codebook vector */
+ const opus_int mu_Q9, /* I tradeoff betw. weighted error and rate */
+ const opus_int32 max_gain_Q7, /* I maximum sum of absolute LTP coefficients */
+ opus_int L /* I number of vectors in codebook */
+);
+
+/************************************/
+/* Noise shaping quantization (NSQ) */
+/************************************/
+void silk_NSQ(
+ const silk_encoder_state *psEncC, /* I/O Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ SideInfoIndices *psIndices, /* I/O Quantization Indices */
+ const opus_int32 x_Q3[], /* I Prefiltered input signal */
+ opus_int8 pulses[], /* O Quantized pulse signal */
+ const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */
+ const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */
+ const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */
+ const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */
+ const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */
+ const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */
+ const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */
+ const opus_int LTP_scale_Q14 /* I LTP state scaling */
+);
+
+/* Noise shaping using delayed decision */
+void silk_NSQ_del_dec(
+ const silk_encoder_state *psEncC, /* I/O Encoder State */
+ silk_nsq_state *NSQ, /* I/O NSQ state */
+ SideInfoIndices *psIndices, /* I/O Quantization Indices */
+ const opus_int32 x_Q3[], /* I Prefiltered input signal */
+ opus_int8 pulses[], /* O Quantized pulse signal */
+ const opus_int16 PredCoef_Q12[ 2 * MAX_LPC_ORDER ], /* I Short term prediction coefs */
+ const opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ], /* I Long term prediction coefs */
+ const opus_int16 AR2_Q13[ MAX_NB_SUBFR * MAX_SHAPE_LPC_ORDER ], /* I Noise shaping coefs */
+ const opus_int HarmShapeGain_Q14[ MAX_NB_SUBFR ], /* I Long term shaping coefs */
+ const opus_int Tilt_Q14[ MAX_NB_SUBFR ], /* I Spectral tilt */
+ const opus_int32 LF_shp_Q14[ MAX_NB_SUBFR ], /* I Low frequency shaping coefs */
+ const opus_int32 Gains_Q16[ MAX_NB_SUBFR ], /* I Quantization step sizes */
+ const opus_int pitchL[ MAX_NB_SUBFR ], /* I Pitch lags */
+ const opus_int Lambda_Q10, /* I Rate/distortion tradeoff */
+ const opus_int LTP_scale_Q14 /* I LTP state scaling */
+);
+
+/************/
+/* Silk VAD */
+/************/
+/* Initialize the Silk VAD */
+opus_int silk_VAD_Init( /* O Return value, 0 if success */
+ silk_VAD_state *psSilk_VAD /* I/O Pointer to Silk VAD state */
+);
+
+/* Get speech activity level in Q8 */
+opus_int silk_VAD_GetSA_Q8( /* O Return value, 0 if success */
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ const opus_int16 pIn[] /* I PCM input */
+);
+
+/* Low-pass filter with variable cutoff frequency based on */
+/* piece-wise linear interpolation between elliptic filters */
+/* Start by setting transition_frame_no = 1; */
+void silk_LP_variable_cutoff(
+ silk_LP_state *psLP, /* I/O LP filter state */
+ opus_int16 *frame, /* I/O Low-pass filtered output signal */
+ const opus_int frame_length /* I Frame length */
+);
+
+/******************/
+/* NLSF Quantizer */
+/******************/
+/* Limit, stabilize, convert and quantize NLSFs */
+void silk_process_NLSFs(
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ], /* O Prediction coefficients */
+ opus_int16 pNLSF_Q15[ MAX_LPC_ORDER ], /* I/O Normalized LSFs (quant out) (0 - (2^15-1)) */
+ const opus_int16 prev_NLSFq_Q15[ MAX_LPC_ORDER ] /* I Previous Normalized LSFs (0 - (2^15-1)) */
+);
+
+opus_int32 silk_NLSF_encode( /* O Returns RD value in Q25 */
+ opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */
+ opus_int16 *pNLSF_Q15, /* I/O Quantized NLSF vector [ LPC_ORDER ] */
+ const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */
+ const opus_int16 *pW_QW, /* I NLSF weight vector [ LPC_ORDER ] */
+ const opus_int NLSF_mu_Q20, /* I Rate weight for the RD optimization */
+ const opus_int nSurvivors, /* I Max survivors after first stage */
+ const opus_int signalType /* I Signal type: 0/1/2 */
+);
+
+/* Compute quantization errors for an LPC_order element input vector for a VQ codebook */
+void silk_NLSF_VQ(
+ opus_int32 err_Q26[], /* O Quantization errors [K] */
+ const opus_int16 in_Q15[], /* I Input vectors to be quantized [LPC_order] */
+ const opus_uint8 pCB_Q8[], /* I Codebook vectors [K*LPC_order] */
+ const opus_int K, /* I Number of codebook vectors */
+ const opus_int LPC_order /* I Number of LPCs */
+);
+
+/* Delayed-decision quantizer for NLSF residuals */
+opus_int32 silk_NLSF_del_dec_quant( /* O Returns RD value in Q25 */
+ opus_int8 indices[], /* O Quantization indices [ order ] */
+ const opus_int16 x_Q10[], /* I Input [ order ] */
+ const opus_int16 w_Q5[], /* I Weights [ order ] */
+ const opus_uint8 pred_coef_Q8[], /* I Backward predictor coefs [ order ] */
+ const opus_int16 ec_ix[], /* I Indices to entropy coding tables [ order ] */
+ const opus_uint8 ec_rates_Q5[], /* I Rates [] */
+ const opus_int quant_step_size_Q16, /* I Quantization step size */
+ const opus_int16 inv_quant_step_size_Q6, /* I Inverse quantization step size */
+ const opus_int32 mu_Q20, /* I R/D tradeoff */
+ const opus_int16 order /* I Number of input values */
+);
+
+/* Unpack predictor values and indices for entropy coding tables */
+void silk_NLSF_unpack(
+ opus_int16 ec_ix[], /* O Indices to entropy tables [ LPC_ORDER ] */
+ opus_uint8 pred_Q8[], /* O LSF predictor [ LPC_ORDER ] */
+ const silk_NLSF_CB_struct *psNLSF_CB, /* I Codebook object */
+ const opus_int CB1_index /* I Index of vector in first LSF codebook */
+);
+
+/***********************/
+/* NLSF vector decoder */
+/***********************/
+void silk_NLSF_decode(
+ opus_int16 *pNLSF_Q15, /* O Quantized NLSF vector [ LPC_ORDER ] */
+ opus_int8 *NLSFIndices, /* I Codebook path vector [ LPC_ORDER + 1 ] */
+ const silk_NLSF_CB_struct *psNLSF_CB /* I Codebook object */
+);
+
+/****************************************************/
+/* Decoder Functions */
+/****************************************************/
+opus_int silk_init_decoder(
+ silk_decoder_state *psDec /* I/O Decoder state pointer */
+);
+
+/* Set decoder sampling rate */
+opus_int silk_decoder_set_fs(
+ silk_decoder_state *psDec, /* I/O Decoder state pointer */
+ opus_int fs_kHz, /* I Sampling frequency (kHz) */
+ opus_int32 fs_API_Hz /* I API Sampling frequency (Hz) */
+);
+
+/****************/
+/* Decode frame */
+/****************/
+opus_int silk_decode_frame(
+ silk_decoder_state *psDec, /* I/O Pointer to Silk decoder state */
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int16 pOut[], /* O Pointer to output speech frame */
+ opus_int32 *pN, /* O Pointer to size of output frame */
+ opus_int lostFlag, /* I 0: no loss, 1 loss, 2 decode fec */
+ opus_int condCoding /* I The type of conditional coding to use */
+);
+
+/* Decode indices from bitstream */
+void silk_decode_indices(
+ silk_decoder_state *psDec, /* I/O State */
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int FrameIndex, /* I Frame number */
+ opus_int decode_LBRR, /* I Flag indicating LBRR data is being decoded */
+ opus_int condCoding /* I The type of conditional coding to use */
+);
+
+/* Decode parameters from payload */
+void silk_decode_parameters(
+ silk_decoder_state *psDec, /* I/O State */
+ silk_decoder_control *psDecCtrl, /* I/O Decoder control */
+ opus_int condCoding /* I The type of conditional coding to use */
+);
+
+/* Core decoder. Performs inverse NSQ operation LTP + LPC */
+void silk_decode_core(
+ silk_decoder_state *psDec, /* I/O Decoder state */
+ silk_decoder_control *psDecCtrl, /* I Decoder control */
+ opus_int16 xq[], /* O Decoded speech */
+ const opus_int pulses[ MAX_FRAME_LENGTH ] /* I Pulse signal */
+);
+
+/* Decode quantization indices of excitation (Shell coding) */
+void silk_decode_pulses(
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int pulses[], /* O Excitation signal */
+ const opus_int signalType, /* I Sigtype */
+ const opus_int quantOffsetType, /* I quantOffsetType */
+ const opus_int frame_length /* I Frame length */
+);
+
+/******************/
+/* CNG */
+/******************/
+
+/* Reset CNG */
+void silk_CNG_Reset(
+ silk_decoder_state *psDec /* I/O Decoder state */
+);
+
+/* Updates CNG estimate, and applies the CNG when packet was lost */
+void silk_CNG(
+ silk_decoder_state *psDec, /* I/O Decoder state */
+ silk_decoder_control *psDecCtrl, /* I/O Decoder control */
+ opus_int16 frame[], /* I/O Signal */
+ opus_int length /* I Length of residual */
+);
+
+/* Encoding of various parameters */
+void silk_encode_indices(
+ silk_encoder_state *psEncC, /* I/O Encoder state */
+ ec_enc *psRangeEnc, /* I/O Compressor data structure */
+ opus_int FrameIndex, /* I Frame number */
+ opus_int encode_LBRR, /* I Flag indicating LBRR data is being encoded */
+ opus_int condCoding /* I The type of conditional coding to use */
+);
+
+#endif
diff --git a/drivers/opus/silk/sort.c b/drivers/opus/silk/sort.c
new file mode 100644
index 0000000000..495292ad51
--- /dev/null
+++ b/drivers/opus/silk/sort.c
@@ -0,0 +1,154 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+/* Insertion sort (fast for already almost sorted arrays): */
+/* Best case: O(n) for an already sorted array */
+/* Worst case: O(n^2) for an inversely sorted array */
+/* */
+/* Shell short: http://en.wikipedia.org/wiki/Shell_sort */
+
+#include "opus/silk/SigProc_FIX.h"
+
+void silk_insertion_sort_increasing(
+ opus_int32 *a, /* I/O Unsorted / Sorted vector */
+ opus_int *idx, /* O Index vector for the sorted elements */
+ const opus_int L, /* I Vector length */
+ const opus_int K /* I Number of correctly sorted positions */
+)
+{
+ opus_int32 value;
+ opus_int i, j;
+
+ /* Safety checks */
+ silk_assert( K > 0 );
+ silk_assert( L > 0 );
+ silk_assert( L >= K );
+
+ /* Write start indices in index vector */
+ for( i = 0; i < K; i++ ) {
+ idx[ i ] = i;
+ }
+
+ /* Sort vector elements by value, increasing order */
+ for( i = 1; i < K; i++ ) {
+ value = a[ i ];
+ for( j = i - 1; ( j >= 0 ) && ( value < a[ j ] ); j-- ) {
+ a[ j + 1 ] = a[ j ]; /* Shift value */
+ idx[ j + 1 ] = idx[ j ]; /* Shift index */
+ }
+ a[ j + 1 ] = value; /* Write value */
+ idx[ j + 1 ] = i; /* Write index */
+ }
+
+ /* If less than L values are asked for, check the remaining values, */
+ /* but only spend CPU to ensure that the K first values are correct */
+ for( i = K; i < L; i++ ) {
+ value = a[ i ];
+ if( value < a[ K - 1 ] ) {
+ for( j = K - 2; ( j >= 0 ) && ( value < a[ j ] ); j-- ) {
+ a[ j + 1 ] = a[ j ]; /* Shift value */
+ idx[ j + 1 ] = idx[ j ]; /* Shift index */
+ }
+ a[ j + 1 ] = value; /* Write value */
+ idx[ j + 1 ] = i; /* Write index */
+ }
+ }
+}
+
+#ifdef OPUS_FIXED_POINT
+/* This function is only used by the fixed-point build */
+void silk_insertion_sort_decreasing_int16(
+ opus_int16 *a, /* I/O Unsorted / Sorted vector */
+ opus_int *idx, /* O Index vector for the sorted elements */
+ const opus_int L, /* I Vector length */
+ const opus_int K /* I Number of correctly sorted positions */
+)
+{
+ opus_int i, j;
+ opus_int value;
+
+ /* Safety checks */
+ silk_assert( K > 0 );
+ silk_assert( L > 0 );
+ silk_assert( L >= K );
+
+ /* Write start indices in index vector */
+ for( i = 0; i < K; i++ ) {
+ idx[ i ] = i;
+ }
+
+ /* Sort vector elements by value, decreasing order */
+ for( i = 1; i < K; i++ ) {
+ value = a[ i ];
+ for( j = i - 1; ( j >= 0 ) && ( value > a[ j ] ); j-- ) {
+ a[ j + 1 ] = a[ j ]; /* Shift value */
+ idx[ j + 1 ] = idx[ j ]; /* Shift index */
+ }
+ a[ j + 1 ] = value; /* Write value */
+ idx[ j + 1 ] = i; /* Write index */
+ }
+
+ /* If less than L values are asked for, check the remaining values, */
+ /* but only spend CPU to ensure that the K first values are correct */
+ for( i = K; i < L; i++ ) {
+ value = a[ i ];
+ if( value > a[ K - 1 ] ) {
+ for( j = K - 2; ( j >= 0 ) && ( value > a[ j ] ); j-- ) {
+ a[ j + 1 ] = a[ j ]; /* Shift value */
+ idx[ j + 1 ] = idx[ j ]; /* Shift index */
+ }
+ a[ j + 1 ] = value; /* Write value */
+ idx[ j + 1 ] = i; /* Write index */
+ }
+ }
+}
+#endif
+
+void silk_insertion_sort_increasing_all_values_int16(
+ opus_int16 *a, /* I/O Unsorted / Sorted vector */
+ const opus_int L /* I Vector length */
+)
+{
+ opus_int value;
+ opus_int i, j;
+
+ /* Safety checks */
+ silk_assert( L > 0 );
+
+ /* Sort vector elements by value, increasing order */
+ for( i = 1; i < L; i++ ) {
+ value = a[ i ];
+ for( j = i - 1; ( j >= 0 ) && ( value < a[ j ] ); j-- ) {
+ a[ j + 1 ] = a[ j ]; /* Shift value */
+ }
+ a[ j + 1 ] = value; /* Write value */
+ }
+}
diff --git a/drivers/opus/silk/stereo_LR_to_MS.c b/drivers/opus/silk/stereo_LR_to_MS.c
new file mode 100644
index 0000000000..e17a36046e
--- /dev/null
+++ b/drivers/opus/silk/stereo_LR_to_MS.c
@@ -0,0 +1,229 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+#include "opus/celt/stack_alloc.h"
+
+/* Convert Left/Right stereo signal to adaptive Mid/Side representation */
+void silk_stereo_LR_to_MS(
+ stereo_enc_state *state, /* I/O State */
+ opus_int16 x1[], /* I/O Left input signal, becomes mid signal */
+ opus_int16 x2[], /* I/O Right input signal, becomes side signal */
+ opus_int8 ix[ 2 ][ 3 ], /* O Quantization indices */
+ opus_int8 *mid_only_flag, /* O Flag: only mid signal coded */
+ opus_int32 mid_side_rates_bps[], /* O Bitrates for mid and side signals */
+ opus_int32 total_rate_bps, /* I Total bitrate */
+ opus_int prev_speech_act_Q8, /* I Speech activity level in previous frame */
+ opus_int toMono, /* I Last frame before a stereo->mono transition */
+ opus_int fs_kHz, /* I Sample rate (kHz) */
+ opus_int frame_length /* I Number of samples */
+)
+{
+ opus_int n, is10msFrame, denom_Q16, delta0_Q13, delta1_Q13;
+ opus_int32 sum, diff, smooth_coef_Q16, pred_Q13[ 2 ], pred0_Q13, pred1_Q13;
+ opus_int32 LP_ratio_Q14, HP_ratio_Q14, frac_Q16, frac_3_Q16, min_mid_rate_bps, width_Q14, w_Q24, deltaw_Q24;
+ VARDECL( opus_int16, side );
+ VARDECL( opus_int16, LP_mid );
+ VARDECL( opus_int16, HP_mid );
+ VARDECL( opus_int16, LP_side );
+ VARDECL( opus_int16, HP_side );
+ opus_int16 *mid = &x1[ -2 ];
+ SAVE_STACK;
+
+ ALLOC( side, frame_length + 2, opus_int16 );
+ /* Convert to basic mid/side signals */
+ for( n = 0; n < frame_length + 2; n++ ) {
+ sum = x1[ n - 2 ] + (opus_int32)x2[ n - 2 ];
+ diff = x1[ n - 2 ] - (opus_int32)x2[ n - 2 ];
+ mid[ n ] = (opus_int16)silk_RSHIFT_ROUND( sum, 1 );
+ side[ n ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( diff, 1 ) );
+ }
+
+ /* Buffering */
+ silk_memcpy( mid, state->sMid, 2 * sizeof( opus_int16 ) );
+ silk_memcpy( side, state->sSide, 2 * sizeof( opus_int16 ) );
+ silk_memcpy( state->sMid, &mid[ frame_length ], 2 * sizeof( opus_int16 ) );
+ silk_memcpy( state->sSide, &side[ frame_length ], 2 * sizeof( opus_int16 ) );
+
+ /* LP and HP filter mid signal */
+ ALLOC( LP_mid, frame_length, opus_int16 );
+ ALLOC( HP_mid, frame_length, opus_int16 );
+ for( n = 0; n < frame_length; n++ ) {
+ sum = silk_RSHIFT_ROUND( silk_ADD_LSHIFT( mid[ n ] + mid[ n + 2 ], mid[ n + 1 ], 1 ), 2 );
+ LP_mid[ n ] = sum;
+ HP_mid[ n ] = mid[ n + 1 ] - sum;
+ }
+
+ /* LP and HP filter side signal */
+ ALLOC( LP_side, frame_length, opus_int16 );
+ ALLOC( HP_side, frame_length, opus_int16 );
+ for( n = 0; n < frame_length; n++ ) {
+ sum = silk_RSHIFT_ROUND( silk_ADD_LSHIFT( side[ n ] + side[ n + 2 ], side[ n + 1 ], 1 ), 2 );
+ LP_side[ n ] = sum;
+ HP_side[ n ] = side[ n + 1 ] - sum;
+ }
+
+ /* Find energies and predictors */
+ is10msFrame = frame_length == 10 * fs_kHz;
+ smooth_coef_Q16 = is10msFrame ?
+ SILK_FIX_CONST( STEREO_RATIO_SMOOTH_COEF / 2, 16 ) :
+ SILK_FIX_CONST( STEREO_RATIO_SMOOTH_COEF, 16 );
+ smooth_coef_Q16 = silk_SMULWB( silk_SMULBB( prev_speech_act_Q8, prev_speech_act_Q8 ), smooth_coef_Q16 );
+
+ pred_Q13[ 0 ] = silk_stereo_find_predictor( &LP_ratio_Q14, LP_mid, LP_side, &state->mid_side_amp_Q0[ 0 ], frame_length, smooth_coef_Q16 );
+ pred_Q13[ 1 ] = silk_stereo_find_predictor( &HP_ratio_Q14, HP_mid, HP_side, &state->mid_side_amp_Q0[ 2 ], frame_length, smooth_coef_Q16 );
+ /* Ratio of the norms of residual and mid signals */
+ frac_Q16 = silk_SMLABB( HP_ratio_Q14, LP_ratio_Q14, 3 );
+ frac_Q16 = silk_min( frac_Q16, SILK_FIX_CONST( 1, 16 ) );
+
+ /* Determine bitrate distribution between mid and side, and possibly reduce stereo width */
+ total_rate_bps -= is10msFrame ? 1200 : 600; /* Subtract approximate bitrate for coding stereo parameters */
+ if( total_rate_bps < 1 ) {
+ total_rate_bps = 1;
+ }
+ min_mid_rate_bps = silk_SMLABB( 2000, fs_kHz, 900 );
+ silk_assert( min_mid_rate_bps < 32767 );
+ /* Default bitrate distribution: 8 parts for Mid and (5+3*frac) parts for Side. so: mid_rate = ( 8 / ( 13 + 3 * frac ) ) * total_ rate */
+ frac_3_Q16 = silk_MUL( 3, frac_Q16 );
+ mid_side_rates_bps[ 0 ] = silk_DIV32_varQ( total_rate_bps, SILK_FIX_CONST( 8 + 5, 16 ) + frac_3_Q16, 16+3 );
+ /* If Mid bitrate below minimum, reduce stereo width */
+ if( mid_side_rates_bps[ 0 ] < min_mid_rate_bps ) {
+ mid_side_rates_bps[ 0 ] = min_mid_rate_bps;
+ mid_side_rates_bps[ 1 ] = total_rate_bps - mid_side_rates_bps[ 0 ];
+ /* width = 4 * ( 2 * side_rate - min_rate ) / ( ( 1 + 3 * frac ) * min_rate ) */
+ width_Q14 = silk_DIV32_varQ( silk_LSHIFT( mid_side_rates_bps[ 1 ], 1 ) - min_mid_rate_bps,
+ silk_SMULWB( SILK_FIX_CONST( 1, 16 ) + frac_3_Q16, min_mid_rate_bps ), 14+2 );
+ width_Q14 = silk_LIMIT( width_Q14, 0, SILK_FIX_CONST( 1, 14 ) );
+ } else {
+ mid_side_rates_bps[ 1 ] = total_rate_bps - mid_side_rates_bps[ 0 ];
+ width_Q14 = SILK_FIX_CONST( 1, 14 );
+ }
+
+ /* Smoother */
+ state->smth_width_Q14 = (opus_int16)silk_SMLAWB( state->smth_width_Q14, width_Q14 - state->smth_width_Q14, smooth_coef_Q16 );
+
+ /* At very low bitrates or for inputs that are nearly amplitude panned, switch to panned-mono coding */
+ *mid_only_flag = 0;
+ if( toMono ) {
+ /* Last frame before stereo->mono transition; collapse stereo width */
+ width_Q14 = 0;
+ pred_Q13[ 0 ] = 0;
+ pred_Q13[ 1 ] = 0;
+ silk_stereo_quant_pred( pred_Q13, ix );
+ } else if( state->width_prev_Q14 == 0 &&
+ ( 8 * total_rate_bps < 13 * min_mid_rate_bps || silk_SMULWB( frac_Q16, state->smth_width_Q14 ) < SILK_FIX_CONST( 0.05, 14 ) ) )
+ {
+ /* Code as panned-mono; previous frame already had zero width */
+ /* Scale down and quantize predictors */
+ pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 );
+ pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 );
+ silk_stereo_quant_pred( pred_Q13, ix );
+ /* Collapse stereo width */
+ width_Q14 = 0;
+ pred_Q13[ 0 ] = 0;
+ pred_Q13[ 1 ] = 0;
+ mid_side_rates_bps[ 0 ] = total_rate_bps;
+ mid_side_rates_bps[ 1 ] = 0;
+ *mid_only_flag = 1;
+ } else if( state->width_prev_Q14 != 0 &&
+ ( 8 * total_rate_bps < 11 * min_mid_rate_bps || silk_SMULWB( frac_Q16, state->smth_width_Q14 ) < SILK_FIX_CONST( 0.02, 14 ) ) )
+ {
+ /* Transition to zero-width stereo */
+ /* Scale down and quantize predictors */
+ pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 );
+ pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 );
+ silk_stereo_quant_pred( pred_Q13, ix );
+ /* Collapse stereo width */
+ width_Q14 = 0;
+ pred_Q13[ 0 ] = 0;
+ pred_Q13[ 1 ] = 0;
+ } else if( state->smth_width_Q14 > SILK_FIX_CONST( 0.95, 14 ) ) {
+ /* Full-width stereo coding */
+ silk_stereo_quant_pred( pred_Q13, ix );
+ width_Q14 = SILK_FIX_CONST( 1, 14 );
+ } else {
+ /* Reduced-width stereo coding; scale down and quantize predictors */
+ pred_Q13[ 0 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 0 ] ), 14 );
+ pred_Q13[ 1 ] = silk_RSHIFT( silk_SMULBB( state->smth_width_Q14, pred_Q13[ 1 ] ), 14 );
+ silk_stereo_quant_pred( pred_Q13, ix );
+ width_Q14 = state->smth_width_Q14;
+ }
+
+ /* Make sure to keep on encoding until the tapered output has been transmitted */
+ if( *mid_only_flag == 1 ) {
+ state->silent_side_len += frame_length - STEREO_INTERP_LEN_MS * fs_kHz;
+ if( state->silent_side_len < LA_SHAPE_MS * fs_kHz ) {
+ *mid_only_flag = 0;
+ } else {
+ /* Limit to avoid wrapping around */
+ state->silent_side_len = 10000;
+ }
+ } else {
+ state->silent_side_len = 0;
+ }
+
+ if( *mid_only_flag == 0 && mid_side_rates_bps[ 1 ] < 1 ) {
+ mid_side_rates_bps[ 1 ] = 1;
+ mid_side_rates_bps[ 0 ] = silk_max_int( 1, total_rate_bps - mid_side_rates_bps[ 1 ]);
+ }
+
+ /* Interpolate predictors and subtract prediction from side channel */
+ pred0_Q13 = -state->pred_prev_Q13[ 0 ];
+ pred1_Q13 = -state->pred_prev_Q13[ 1 ];
+ w_Q24 = silk_LSHIFT( state->width_prev_Q14, 10 );
+ denom_Q16 = silk_DIV32_16( (opus_int32)1 << 16, STEREO_INTERP_LEN_MS * fs_kHz );
+ delta0_Q13 = -silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 0 ] - state->pred_prev_Q13[ 0 ], denom_Q16 ), 16 );
+ delta1_Q13 = -silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 1 ] - state->pred_prev_Q13[ 1 ], denom_Q16 ), 16 );
+ deltaw_Q24 = silk_LSHIFT( silk_SMULWB( width_Q14 - state->width_prev_Q14, denom_Q16 ), 10 );
+ for( n = 0; n < STEREO_INTERP_LEN_MS * fs_kHz; n++ ) {
+ pred0_Q13 += delta0_Q13;
+ pred1_Q13 += delta1_Q13;
+ w_Q24 += deltaw_Q24;
+ sum = silk_LSHIFT( silk_ADD_LSHIFT( mid[ n ] + mid[ n + 2 ], mid[ n + 1 ], 1 ), 9 ); /* Q11 */
+ sum = silk_SMLAWB( silk_SMULWB( w_Q24, side[ n + 1 ] ), sum, pred0_Q13 ); /* Q8 */
+ sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)mid[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */
+ x2[ n - 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) );
+ }
+
+ pred0_Q13 = -pred_Q13[ 0 ];
+ pred1_Q13 = -pred_Q13[ 1 ];
+ w_Q24 = silk_LSHIFT( width_Q14, 10 );
+ for( n = STEREO_INTERP_LEN_MS * fs_kHz; n < frame_length; n++ ) {
+ sum = silk_LSHIFT( silk_ADD_LSHIFT( mid[ n ] + mid[ n + 2 ], mid[ n + 1 ], 1 ), 9 ); /* Q11 */
+ sum = silk_SMLAWB( silk_SMULWB( w_Q24, side[ n + 1 ] ), sum, pred0_Q13 ); /* Q8 */
+ sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)mid[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */
+ x2[ n - 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) );
+ }
+ state->pred_prev_Q13[ 0 ] = (opus_int16)pred_Q13[ 0 ];
+ state->pred_prev_Q13[ 1 ] = (opus_int16)pred_Q13[ 1 ];
+ state->width_prev_Q14 = (opus_int16)width_Q14;
+ RESTORE_STACK;
+}
diff --git a/drivers/opus/silk/stereo_MS_to_LR.c b/drivers/opus/silk/stereo_MS_to_LR.c
new file mode 100644
index 0000000000..dddb62c788
--- /dev/null
+++ b/drivers/opus/silk/stereo_MS_to_LR.c
@@ -0,0 +1,85 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+
+/* Convert adaptive Mid/Side representation to Left/Right stereo signal */
+void silk_stereo_MS_to_LR(
+ stereo_dec_state *state, /* I/O State */
+ opus_int16 x1[], /* I/O Left input signal, becomes mid signal */
+ opus_int16 x2[], /* I/O Right input signal, becomes side signal */
+ const opus_int32 pred_Q13[], /* I Predictors */
+ opus_int fs_kHz, /* I Samples rate (kHz) */
+ opus_int frame_length /* I Number of samples */
+)
+{
+ opus_int n, denom_Q16, delta0_Q13, delta1_Q13;
+ opus_int32 sum, diff, pred0_Q13, pred1_Q13;
+
+ /* Buffering */
+ silk_memcpy( x1, state->sMid, 2 * sizeof( opus_int16 ) );
+ silk_memcpy( x2, state->sSide, 2 * sizeof( opus_int16 ) );
+ silk_memcpy( state->sMid, &x1[ frame_length ], 2 * sizeof( opus_int16 ) );
+ silk_memcpy( state->sSide, &x2[ frame_length ], 2 * sizeof( opus_int16 ) );
+
+ /* Interpolate predictors and add prediction to side channel */
+ pred0_Q13 = state->pred_prev_Q13[ 0 ];
+ pred1_Q13 = state->pred_prev_Q13[ 1 ];
+ denom_Q16 = silk_DIV32_16( (opus_int32)1 << 16, STEREO_INTERP_LEN_MS * fs_kHz );
+ delta0_Q13 = silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 0 ] - state->pred_prev_Q13[ 0 ], denom_Q16 ), 16 );
+ delta1_Q13 = silk_RSHIFT_ROUND( silk_SMULBB( pred_Q13[ 1 ] - state->pred_prev_Q13[ 1 ], denom_Q16 ), 16 );
+ for( n = 0; n < STEREO_INTERP_LEN_MS * fs_kHz; n++ ) {
+ pred0_Q13 += delta0_Q13;
+ pred1_Q13 += delta1_Q13;
+ sum = silk_LSHIFT( silk_ADD_LSHIFT( x1[ n ] + x1[ n + 2 ], x1[ n + 1 ], 1 ), 9 ); /* Q11 */
+ sum = silk_SMLAWB( silk_LSHIFT( (opus_int32)x2[ n + 1 ], 8 ), sum, pred0_Q13 ); /* Q8 */
+ sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)x1[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */
+ x2[ n + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) );
+ }
+ pred0_Q13 = pred_Q13[ 0 ];
+ pred1_Q13 = pred_Q13[ 1 ];
+ for( n = STEREO_INTERP_LEN_MS * fs_kHz; n < frame_length; n++ ) {
+ sum = silk_LSHIFT( silk_ADD_LSHIFT( x1[ n ] + x1[ n + 2 ], x1[ n + 1 ], 1 ), 9 ); /* Q11 */
+ sum = silk_SMLAWB( silk_LSHIFT( (opus_int32)x2[ n + 1 ], 8 ), sum, pred0_Q13 ); /* Q8 */
+ sum = silk_SMLAWB( sum, silk_LSHIFT( (opus_int32)x1[ n + 1 ], 11 ), pred1_Q13 ); /* Q8 */
+ x2[ n + 1 ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( sum, 8 ) );
+ }
+ state->pred_prev_Q13[ 0 ] = pred_Q13[ 0 ];
+ state->pred_prev_Q13[ 1 ] = pred_Q13[ 1 ];
+
+ /* Convert to left/right signals */
+ for( n = 0; n < frame_length; n++ ) {
+ sum = x1[ n + 1 ] + (opus_int32)x2[ n + 1 ];
+ diff = x1[ n + 1 ] - (opus_int32)x2[ n + 1 ];
+ x1[ n + 1 ] = (opus_int16)silk_SAT16( sum );
+ x2[ n + 1 ] = (opus_int16)silk_SAT16( diff );
+ }
+}
diff --git a/drivers/opus/silk/stereo_decode_pred.c b/drivers/opus/silk/stereo_decode_pred.c
new file mode 100644
index 0000000000..d54faf137e
--- /dev/null
+++ b/drivers/opus/silk/stereo_decode_pred.c
@@ -0,0 +1,73 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+
+/* Decode mid/side predictors */
+void silk_stereo_decode_pred(
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int32 pred_Q13[] /* O Predictors */
+)
+{
+ opus_int n, ix[ 2 ][ 3 ];
+ opus_int32 low_Q13, step_Q13;
+
+ /* Entropy decoding */
+ n = ec_dec_icdf( psRangeDec, silk_stereo_pred_joint_iCDF, 8 );
+ ix[ 0 ][ 2 ] = silk_DIV32_16( n, 5 );
+ ix[ 1 ][ 2 ] = n - 5 * ix[ 0 ][ 2 ];
+ for( n = 0; n < 2; n++ ) {
+ ix[ n ][ 0 ] = ec_dec_icdf( psRangeDec, silk_uniform3_iCDF, 8 );
+ ix[ n ][ 1 ] = ec_dec_icdf( psRangeDec, silk_uniform5_iCDF, 8 );
+ }
+
+ /* Dequantize */
+ for( n = 0; n < 2; n++ ) {
+ ix[ n ][ 0 ] += 3 * ix[ n ][ 2 ];
+ low_Q13 = silk_stereo_pred_quant_Q13[ ix[ n ][ 0 ] ];
+ step_Q13 = silk_SMULWB( silk_stereo_pred_quant_Q13[ ix[ n ][ 0 ] + 1 ] - low_Q13,
+ SILK_FIX_CONST( 0.5 / STEREO_QUANT_SUB_STEPS, 16 ) );
+ pred_Q13[ n ] = silk_SMLABB( low_Q13, step_Q13, 2 * ix[ n ][ 1 ] + 1 );
+ }
+
+ /* Subtract second from first predictor (helps when actually applying these) */
+ pred_Q13[ 0 ] -= pred_Q13[ 1 ];
+}
+
+/* Decode mid-only flag */
+void silk_stereo_decode_mid_only(
+ ec_dec *psRangeDec, /* I/O Compressor data structure */
+ opus_int *decode_only_mid /* O Flag that only mid channel has been coded */
+)
+{
+ /* Decode flag that only mid channel is coded */
+ *decode_only_mid = ec_dec_icdf( psRangeDec, silk_stereo_only_code_mid_iCDF, 8 );
+}
diff --git a/drivers/opus/silk/stereo_encode_pred.c b/drivers/opus/silk/stereo_encode_pred.c
new file mode 100644
index 0000000000..d68922cf01
--- /dev/null
+++ b/drivers/opus/silk/stereo_encode_pred.c
@@ -0,0 +1,62 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+
+/* Entropy code the mid/side quantization indices */
+void silk_stereo_encode_pred(
+ ec_enc *psRangeEnc, /* I/O Compressor data structure */
+ opus_int8 ix[ 2 ][ 3 ] /* I Quantization indices */
+)
+{
+ opus_int n;
+
+ /* Entropy coding */
+ n = 5 * ix[ 0 ][ 2 ] + ix[ 1 ][ 2 ];
+ silk_assert( n < 25 );
+ ec_enc_icdf( psRangeEnc, n, silk_stereo_pred_joint_iCDF, 8 );
+ for( n = 0; n < 2; n++ ) {
+ silk_assert( ix[ n ][ 0 ] < 3 );
+ silk_assert( ix[ n ][ 1 ] < STEREO_QUANT_SUB_STEPS );
+ ec_enc_icdf( psRangeEnc, ix[ n ][ 0 ], silk_uniform3_iCDF, 8 );
+ ec_enc_icdf( psRangeEnc, ix[ n ][ 1 ], silk_uniform5_iCDF, 8 );
+ }
+}
+
+/* Entropy code the mid-only flag */
+void silk_stereo_encode_mid_only(
+ ec_enc *psRangeEnc, /* I/O Compressor data structure */
+ opus_int8 mid_only_flag
+)
+{
+ /* Encode flag that only mid channel is coded */
+ ec_enc_icdf( psRangeEnc, mid_only_flag, silk_stereo_only_code_mid_iCDF, 8 );
+}
diff --git a/drivers/opus/silk/stereo_find_predictor.c b/drivers/opus/silk/stereo_find_predictor.c
new file mode 100644
index 0000000000..1f529b28d0
--- /dev/null
+++ b/drivers/opus/silk/stereo_find_predictor.c
@@ -0,0 +1,79 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+
+/* Find least-squares prediction gain for one signal based on another and quantize it */
+opus_int32 silk_stereo_find_predictor( /* O Returns predictor in Q13 */
+ opus_int32 *ratio_Q14, /* O Ratio of residual and mid energies */
+ const opus_int16 x[], /* I Basis signal */
+ const opus_int16 y[], /* I Target signal */
+ opus_int32 mid_res_amp_Q0[], /* I/O Smoothed mid, residual norms */
+ opus_int length, /* I Number of samples */
+ opus_int smooth_coef_Q16 /* I Smoothing coefficient */
+)
+{
+ opus_int scale, scale1, scale2;
+ opus_int32 nrgx, nrgy, corr, pred_Q13, pred2_Q10;
+
+ /* Find predictor */
+ silk_sum_sqr_shift( &nrgx, &scale1, x, length );
+ silk_sum_sqr_shift( &nrgy, &scale2, y, length );
+ scale = silk_max_int( scale1, scale2 );
+ scale = scale + ( scale & 1 ); /* make even */
+ nrgy = silk_RSHIFT32( nrgy, scale - scale2 );
+ nrgx = silk_RSHIFT32( nrgx, scale - scale1 );
+ nrgx = silk_max_int( nrgx, 1 );
+ corr = silk_inner_prod_aligned_scale( x, y, scale, length );
+ pred_Q13 = silk_DIV32_varQ( corr, nrgx, 13 );
+ pred_Q13 = silk_LIMIT( pred_Q13, -(1 << 14), 1 << 14 );
+ pred2_Q10 = silk_SMULWB( pred_Q13, pred_Q13 );
+
+ /* Faster update for signals with large prediction parameters */
+ smooth_coef_Q16 = (opus_int)silk_max_int( smooth_coef_Q16, silk_abs( pred2_Q10 ) );
+
+ /* Smoothed mid and residual norms */
+ silk_assert( smooth_coef_Q16 < 32768 );
+ scale = silk_RSHIFT( scale, 1 );
+ mid_res_amp_Q0[ 0 ] = silk_SMLAWB( mid_res_amp_Q0[ 0 ], silk_LSHIFT( silk_SQRT_APPROX( nrgx ), scale ) - mid_res_amp_Q0[ 0 ],
+ smooth_coef_Q16 );
+ /* Residual energy = nrgy - 2 * pred * corr + pred^2 * nrgx */
+ nrgy = silk_SUB_LSHIFT32( nrgy, silk_SMULWB( corr, pred_Q13 ), 3 + 1 );
+ nrgy = silk_ADD_LSHIFT32( nrgy, silk_SMULWB( nrgx, pred2_Q10 ), 6 );
+ mid_res_amp_Q0[ 1 ] = silk_SMLAWB( mid_res_amp_Q0[ 1 ], silk_LSHIFT( silk_SQRT_APPROX( nrgy ), scale ) - mid_res_amp_Q0[ 1 ],
+ smooth_coef_Q16 );
+
+ /* Ratio of smoothed residual and mid norms */
+ *ratio_Q14 = silk_DIV32_varQ( mid_res_amp_Q0[ 1 ], silk_max( mid_res_amp_Q0[ 0 ], 1 ), 14 );
+ *ratio_Q14 = silk_LIMIT( *ratio_Q14, 0, 32767 );
+
+ return pred_Q13;
+}
diff --git a/drivers/opus/silk/stereo_quant_pred.c b/drivers/opus/silk/stereo_quant_pred.c
new file mode 100644
index 0000000000..3a4d9b31da
--- /dev/null
+++ b/drivers/opus/silk/stereo_quant_pred.c
@@ -0,0 +1,73 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/silk_main.h"
+
+/* Quantize mid/side predictors */
+void silk_stereo_quant_pred(
+ opus_int32 pred_Q13[], /* I/O Predictors (out: quantized) */
+ opus_int8 ix[ 2 ][ 3 ] /* O Quantization indices */
+)
+{
+ opus_int i, j, n;
+ opus_int32 low_Q13, step_Q13, lvl_Q13, err_min_Q13, err_Q13, quant_pred_Q13 = 0;
+
+ /* Quantize */
+ for( n = 0; n < 2; n++ ) {
+ /* Brute-force search over quantization levels */
+ err_min_Q13 = silk_int32_MAX;
+ for( i = 0; i < STEREO_QUANT_TAB_SIZE - 1; i++ ) {
+ low_Q13 = silk_stereo_pred_quant_Q13[ i ];
+ step_Q13 = silk_SMULWB( silk_stereo_pred_quant_Q13[ i + 1 ] - low_Q13,
+ SILK_FIX_CONST( 0.5 / STEREO_QUANT_SUB_STEPS, 16 ) );
+ for( j = 0; j < STEREO_QUANT_SUB_STEPS; j++ ) {
+ lvl_Q13 = silk_SMLABB( low_Q13, step_Q13, 2 * j + 1 );
+ err_Q13 = silk_abs( pred_Q13[ n ] - lvl_Q13 );
+ if( err_Q13 < err_min_Q13 ) {
+ err_min_Q13 = err_Q13;
+ quant_pred_Q13 = lvl_Q13;
+ ix[ n ][ 0 ] = i;
+ ix[ n ][ 1 ] = j;
+ } else {
+ /* Error increasing, so we're past the optimum */
+ goto done;
+ }
+ }
+ }
+ done:
+ ix[ n ][ 2 ] = silk_DIV32_16( ix[ n ][ 0 ], 3 );
+ ix[ n ][ 0 ] -= ix[ n ][ 2 ] * 3;
+ pred_Q13[ n ] = quant_pred_Q13;
+ }
+
+ /* Subtract second from first predictor (helps when actually applying these) */
+ pred_Q13[ 0 ] -= pred_Q13[ 1 ];
+}
diff --git a/drivers/opus/silk/structs.h b/drivers/opus/silk/structs.h
new file mode 100644
index 0000000000..c8c5dae844
--- /dev/null
+++ b/drivers/opus/silk/structs.h
@@ -0,0 +1,327 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_STRUCTS_H
+#define SILK_STRUCTS_H
+
+#include "opus/silk/typedef.h"
+#include "opus/silk/SigProc_FIX.h"
+#include "opus/silk/define.h"
+#include "opus/celt/entenc.h"
+#include "opus/celt/entdec.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/************************************/
+/* Noise shaping quantization state */
+/************************************/
+typedef struct {
+ opus_int16 xq[ 2 * MAX_FRAME_LENGTH ]; /* Buffer for quantized output signal */
+ opus_int32 sLTP_shp_Q14[ 2 * MAX_FRAME_LENGTH ];
+ opus_int32 sLPC_Q14[ MAX_SUB_FRAME_LENGTH + NSQ_LPC_BUF_LENGTH ];
+ opus_int32 sAR2_Q14[ MAX_SHAPE_LPC_ORDER ];
+ opus_int32 sLF_AR_shp_Q14;
+ opus_int lagPrev;
+ opus_int sLTP_buf_idx;
+ opus_int sLTP_shp_buf_idx;
+ opus_int32 rand_seed;
+ opus_int32 prev_gain_Q16;
+ opus_int rewhite_flag;
+} silk_nsq_state;
+
+/********************************/
+/* VAD state */
+/********************************/
+typedef struct {
+ opus_int32 AnaState[ 2 ]; /* Analysis filterbank state: 0-8 kHz */
+ opus_int32 AnaState1[ 2 ]; /* Analysis filterbank state: 0-4 kHz */
+ opus_int32 AnaState2[ 2 ]; /* Analysis filterbank state: 0-2 kHz */
+ opus_int32 XnrgSubfr[ VAD_N_BANDS ]; /* Subframe energies */
+ opus_int32 NrgRatioSmth_Q8[ VAD_N_BANDS ]; /* Smoothed energy level in each band */
+ opus_int16 HPstate; /* State of differentiator in the lowest band */
+ opus_int32 NL[ VAD_N_BANDS ]; /* Noise energy level in each band */
+ opus_int32 inv_NL[ VAD_N_BANDS ]; /* Inverse noise energy level in each band */
+ opus_int32 NoiseLevelBias[ VAD_N_BANDS ]; /* Noise level estimator bias/offset */
+ opus_int32 counter; /* Frame counter used in the initial phase */
+} silk_VAD_state;
+
+/* Variable cut-off low-pass filter state */
+typedef struct {
+ opus_int32 In_LP_State[ 2 ]; /* Low pass filter state */
+ opus_int32 transition_frame_no; /* Counter which is mapped to a cut-off frequency */
+ opus_int mode; /* Operating mode, <0: switch down, >0: switch up; 0: do nothing */
+} silk_LP_state;
+
+/* Structure containing NLSF codebook */
+typedef struct {
+ const opus_int16 nVectors;
+ const opus_int16 order;
+ const opus_int16 quantStepSize_Q16;
+ const opus_int16 invQuantStepSize_Q6;
+ const opus_uint8 *CB1_NLSF_Q8;
+ const opus_uint8 *CB1_iCDF;
+ const opus_uint8 *pred_Q8;
+ const opus_uint8 *ec_sel;
+ const opus_uint8 *ec_iCDF;
+ const opus_uint8 *ec_Rates_Q5;
+ const opus_int16 *deltaMin_Q15;
+} silk_NLSF_CB_struct;
+
+typedef struct {
+ opus_int16 pred_prev_Q13[ 2 ];
+ opus_int16 sMid[ 2 ];
+ opus_int16 sSide[ 2 ];
+ opus_int32 mid_side_amp_Q0[ 4 ];
+ opus_int16 smth_width_Q14;
+ opus_int16 width_prev_Q14;
+ opus_int16 silent_side_len;
+ opus_int8 predIx[ MAX_FRAMES_PER_PACKET ][ 2 ][ 3 ];
+ opus_int8 mid_only_flags[ MAX_FRAMES_PER_PACKET ];
+} stereo_enc_state;
+
+typedef struct {
+ opus_int16 pred_prev_Q13[ 2 ];
+ opus_int16 sMid[ 2 ];
+ opus_int16 sSide[ 2 ];
+} stereo_dec_state;
+
+typedef struct {
+ opus_int8 GainsIndices[ MAX_NB_SUBFR ];
+ opus_int8 LTPIndex[ MAX_NB_SUBFR ];
+ opus_int8 NLSFIndices[ MAX_LPC_ORDER + 1 ];
+ opus_int16 lagIndex;
+ opus_int8 contourIndex;
+ opus_int8 signalType;
+ opus_int8 quantOffsetType;
+ opus_int8 NLSFInterpCoef_Q2;
+ opus_int8 PERIndex;
+ opus_int8 LTP_scaleIndex;
+ opus_int8 Seed;
+} SideInfoIndices;
+
+/********************************/
+/* Encoder state */
+/********************************/
+typedef struct {
+ opus_int32 In_HP_State[ 2 ]; /* High pass filter state */
+ opus_int32 variable_HP_smth1_Q15; /* State of first smoother */
+ opus_int32 variable_HP_smth2_Q15; /* State of second smoother */
+ silk_LP_state sLP; /* Low pass filter state */
+ silk_VAD_state sVAD; /* Voice activity detector state */
+ silk_nsq_state sNSQ; /* Noise Shape Quantizer State */
+ opus_int16 prev_NLSFq_Q15[ MAX_LPC_ORDER ]; /* Previously quantized NLSF vector */
+ opus_int speech_activity_Q8; /* Speech activity */
+ opus_int allow_bandwidth_switch; /* Flag indicating that switching of internal bandwidth is allowed */
+ opus_int8 LBRRprevLastGainIndex;
+ opus_int8 prevSignalType;
+ opus_int prevLag;
+ opus_int pitch_LPC_win_length;
+ opus_int max_pitch_lag; /* Highest possible pitch lag (samples) */
+ opus_int32 API_fs_Hz; /* API sampling frequency (Hz) */
+ opus_int32 prev_API_fs_Hz; /* Previous API sampling frequency (Hz) */
+ opus_int maxInternal_fs_Hz; /* Maximum internal sampling frequency (Hz) */
+ opus_int minInternal_fs_Hz; /* Minimum internal sampling frequency (Hz) */
+ opus_int desiredInternal_fs_Hz; /* Soft request for internal sampling frequency (Hz) */
+ opus_int fs_kHz; /* Internal sampling frequency (kHz) */
+ opus_int nb_subfr; /* Number of 5 ms subframes in a frame */
+ opus_int frame_length; /* Frame length (samples) */
+ opus_int subfr_length; /* Subframe length (samples) */
+ opus_int ltp_mem_length; /* Length of LTP memory */
+ opus_int la_pitch; /* Look-ahead for pitch analysis (samples) */
+ opus_int la_shape; /* Look-ahead for noise shape analysis (samples) */
+ opus_int shapeWinLength; /* Window length for noise shape analysis (samples) */
+ opus_int32 TargetRate_bps; /* Target bitrate (bps) */
+ opus_int PacketSize_ms; /* Number of milliseconds to put in each packet */
+ opus_int PacketLoss_perc; /* Packet loss rate measured by farend */
+ opus_int32 frameCounter;
+ opus_int Complexity; /* Complexity setting */
+ opus_int nStatesDelayedDecision; /* Number of states in delayed decision quantization */
+ opus_int useInterpolatedNLSFs; /* Flag for using NLSF interpolation */
+ opus_int shapingLPCOrder; /* Filter order for noise shaping filters */
+ opus_int predictLPCOrder; /* Filter order for prediction filters */
+ opus_int pitchEstimationComplexity; /* Complexity level for pitch estimator */
+ opus_int pitchEstimationLPCOrder; /* Whitening filter order for pitch estimator */
+ opus_int32 pitchEstimationThreshold_Q16; /* Threshold for pitch estimator */
+ opus_int LTPQuantLowComplexity; /* Flag for low complexity LTP quantization */
+ opus_int mu_LTP_Q9; /* Rate-distortion tradeoff in LTP quantization */
+ opus_int32 sum_log_gain_Q7; /* Cumulative max prediction gain */
+ opus_int NLSF_MSVQ_Survivors; /* Number of survivors in NLSF MSVQ */
+ opus_int first_frame_after_reset; /* Flag for deactivating NLSF interpolation, pitch prediction */
+ opus_int controlled_since_last_payload; /* Flag for ensuring codec_control only runs once per packet */
+ opus_int warping_Q16; /* Warping parameter for warped noise shaping */
+ opus_int useCBR; /* Flag to enable constant bitrate */
+ opus_int prefillFlag; /* Flag to indicate that only buffers are prefilled, no coding */
+ const opus_uint8 *pitch_lag_low_bits_iCDF; /* Pointer to iCDF table for low bits of pitch lag index */
+ const opus_uint8 *pitch_contour_iCDF; /* Pointer to iCDF table for pitch contour index */
+ const silk_NLSF_CB_struct *psNLSF_CB; /* Pointer to NLSF codebook */
+ opus_int input_quality_bands_Q15[ VAD_N_BANDS ];
+ opus_int input_tilt_Q15;
+ opus_int SNR_dB_Q7; /* Quality setting */
+
+ opus_int8 VAD_flags[ MAX_FRAMES_PER_PACKET ];
+ opus_int8 LBRR_flag;
+ opus_int LBRR_flags[ MAX_FRAMES_PER_PACKET ];
+
+ SideInfoIndices indices;
+ opus_int8 pulses[ MAX_FRAME_LENGTH ];
+
+ int arch;
+
+ /* Input/output buffering */
+ opus_int16 inputBuf[ MAX_FRAME_LENGTH + 2 ]; /* Buffer containing input signal */
+ opus_int inputBufIx;
+ opus_int nFramesPerPacket;
+ opus_int nFramesEncoded; /* Number of frames analyzed in current packet */
+
+ opus_int nChannelsAPI;
+ opus_int nChannelsInternal;
+ opus_int channelNb;
+
+ /* Parameters For LTP scaling Control */
+ opus_int frames_since_onset;
+
+ /* Specifically for entropy coding */
+ opus_int ec_prevSignalType;
+ opus_int16 ec_prevLagIndex;
+
+ silk_resampler_state_struct resampler_state;
+
+ /* DTX */
+ opus_int useDTX; /* Flag to enable DTX */
+ opus_int inDTX; /* Flag to signal DTX period */
+ opus_int noSpeechCounter; /* Counts concecutive nonactive frames, used by DTX */
+
+ /* Inband Low Bitrate Redundancy (LBRR) data */
+ opus_int useInBandFEC; /* Saves the API setting for query */
+ opus_int LBRR_enabled; /* Depends on useInBandFRC, bitrate and packet loss rate */
+ opus_int LBRR_GainIncreases; /* Gains increment for coding LBRR frames */
+ SideInfoIndices indices_LBRR[ MAX_FRAMES_PER_PACKET ];
+ opus_int8 pulses_LBRR[ MAX_FRAMES_PER_PACKET ][ MAX_FRAME_LENGTH ];
+} silk_encoder_state;
+
+
+/* Struct for Packet Loss Concealment */
+typedef struct {
+ opus_int32 pitchL_Q8; /* Pitch lag to use for voiced concealment */
+ opus_int16 LTPCoef_Q14[ LTP_ORDER ]; /* LTP coeficients to use for voiced concealment */
+ opus_int16 prevLPC_Q12[ MAX_LPC_ORDER ];
+ opus_int last_frame_lost; /* Was previous frame lost */
+ opus_int32 rand_seed; /* Seed for unvoiced signal generation */
+ opus_int16 randScale_Q14; /* Scaling of unvoiced random signal */
+ opus_int32 conc_energy;
+ opus_int conc_energy_shift;
+ opus_int16 prevLTP_scale_Q14;
+ opus_int32 prevGain_Q16[ 2 ];
+ opus_int fs_kHz;
+ opus_int nb_subfr;
+ opus_int subfr_length;
+} silk_PLC_struct;
+
+/* Struct for CNG */
+typedef struct {
+ opus_int32 CNG_exc_buf_Q14[ MAX_FRAME_LENGTH ];
+ opus_int16 CNG_smth_NLSF_Q15[ MAX_LPC_ORDER ];
+ opus_int32 CNG_synth_state[ MAX_LPC_ORDER ];
+ opus_int32 CNG_smth_Gain_Q16;
+ opus_int32 rand_seed;
+ opus_int fs_kHz;
+} silk_CNG_struct;
+
+/********************************/
+/* Decoder state */
+/********************************/
+typedef struct {
+ opus_int32 prev_gain_Q16;
+ opus_int32 exc_Q14[ MAX_FRAME_LENGTH ];
+ opus_int32 sLPC_Q14_buf[ MAX_LPC_ORDER ];
+ opus_int16 outBuf[ MAX_FRAME_LENGTH + 2 * MAX_SUB_FRAME_LENGTH ]; /* Buffer for output signal */
+ opus_int lagPrev; /* Previous Lag */
+ opus_int8 LastGainIndex; /* Previous gain index */
+ opus_int fs_kHz; /* Sampling frequency in kHz */
+ opus_int32 fs_API_hz; /* API sample frequency (Hz) */
+ opus_int nb_subfr; /* Number of 5 ms subframes in a frame */
+ opus_int frame_length; /* Frame length (samples) */
+ opus_int subfr_length; /* Subframe length (samples) */
+ opus_int ltp_mem_length; /* Length of LTP memory */
+ opus_int LPC_order; /* LPC order */
+ opus_int16 prevNLSF_Q15[ MAX_LPC_ORDER ]; /* Used to interpolate LSFs */
+ opus_int first_frame_after_reset; /* Flag for deactivating NLSF interpolation */
+ const opus_uint8 *pitch_lag_low_bits_iCDF; /* Pointer to iCDF table for low bits of pitch lag index */
+ const opus_uint8 *pitch_contour_iCDF; /* Pointer to iCDF table for pitch contour index */
+
+ /* For buffering payload in case of more frames per packet */
+ opus_int nFramesDecoded;
+ opus_int nFramesPerPacket;
+
+ /* Specifically for entropy coding */
+ opus_int ec_prevSignalType;
+ opus_int16 ec_prevLagIndex;
+
+ opus_int VAD_flags[ MAX_FRAMES_PER_PACKET ];
+ opus_int LBRR_flag;
+ opus_int LBRR_flags[ MAX_FRAMES_PER_PACKET ];
+
+ silk_resampler_state_struct resampler_state;
+
+ const silk_NLSF_CB_struct *psNLSF_CB; /* Pointer to NLSF codebook */
+
+ /* Quantization indices */
+ SideInfoIndices indices;
+
+ /* CNG state */
+ silk_CNG_struct sCNG;
+
+ /* Stuff used for PLC */
+ opus_int lossCnt;
+ opus_int prevSignalType;
+
+ silk_PLC_struct sPLC;
+
+} silk_decoder_state;
+
+/************************/
+/* Decoder control */
+/************************/
+typedef struct {
+ /* Prediction and coding parameters */
+ opus_int pitchL[ MAX_NB_SUBFR ];
+ opus_int32 Gains_Q16[ MAX_NB_SUBFR ];
+ /* Holds interpolated and final coefficients, 4-byte aligned */
+ silk_DWORD_ALIGN opus_int16 PredCoef_Q12[ 2 ][ MAX_LPC_ORDER ];
+ opus_int16 LTPCoef_Q14[ LTP_ORDER * MAX_NB_SUBFR ];
+ opus_int LTP_scale_Q14;
+} silk_decoder_control;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/opus/silk/sum_sqr_shift.c b/drivers/opus/silk/sum_sqr_shift.c
new file mode 100644
index 0000000000..7e2a97b530
--- /dev/null
+++ b/drivers/opus/silk/sum_sqr_shift.c
@@ -0,0 +1,85 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/SigProc_FIX.h"
+
+/* Compute number of bits to right shift the sum of squares of a vector */
+/* of int16s to make it fit in an int32 */
+void silk_sum_sqr_shift(
+ opus_int32 *energy, /* O Energy of x, after shifting to the right */
+ opus_int *shift, /* O Number of bits right shift applied to energy */
+ const opus_int16 *x, /* I Input vector */
+ opus_int len /* I Length of input vector */
+)
+{
+ opus_int i, shft;
+ opus_int32 nrg_tmp, nrg;
+
+ nrg = 0;
+ shft = 0;
+ len--;
+ for( i = 0; i < len; i += 2 ) {
+ nrg = silk_SMLABB_ovflw( nrg, x[ i ], x[ i ] );
+ nrg = silk_SMLABB_ovflw( nrg, x[ i + 1 ], x[ i + 1 ] );
+ if( nrg < 0 ) {
+ /* Scale down */
+ nrg = (opus_int32)silk_RSHIFT_uint( (opus_uint32)nrg, 2 );
+ shft = 2;
+ break;
+ }
+ }
+ for( ; i < len; i += 2 ) {
+ nrg_tmp = silk_SMULBB( x[ i ], x[ i ] );
+ nrg_tmp = silk_SMLABB_ovflw( nrg_tmp, x[ i + 1 ], x[ i + 1 ] );
+ nrg = (opus_int32)silk_ADD_RSHIFT_uint( nrg, (opus_uint32)nrg_tmp, shft );
+ if( nrg < 0 ) {
+ /* Scale down */
+ nrg = (opus_int32)silk_RSHIFT_uint( (opus_uint32)nrg, 2 );
+ shft += 2;
+ }
+ }
+ if( i == len ) {
+ /* One sample left to process */
+ nrg_tmp = silk_SMULBB( x[ i ], x[ i ] );
+ nrg = (opus_int32)silk_ADD_RSHIFT_uint( nrg, nrg_tmp, shft );
+ }
+
+ /* Make sure to have at least one extra leading zero (two leading zeros in total) */
+ if( nrg & 0xC0000000 ) {
+ nrg = silk_RSHIFT_uint( (opus_uint32)nrg, 2 );
+ shft += 2;
+ }
+
+ /* Output arguments */
+ *shift = shft;
+ *energy = nrg;
+}
+
diff --git a/drivers/opus/silk/table_LSF_cos.c b/drivers/opus/silk/table_LSF_cos.c
new file mode 100644
index 0000000000..818a532c28
--- /dev/null
+++ b/drivers/opus/silk/table_LSF_cos.c
@@ -0,0 +1,70 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/tables.h"
+
+/* Cosine approximation table for LSF conversion */
+/* Q12 values (even) */
+const opus_int16 silk_LSFCosTab_FIX_Q12[ LSF_COS_TAB_SZ_FIX + 1 ] = {
+ 8192, 8190, 8182, 8170,
+ 8152, 8130, 8104, 8072,
+ 8034, 7994, 7946, 7896,
+ 7840, 7778, 7714, 7644,
+ 7568, 7490, 7406, 7318,
+ 7226, 7128, 7026, 6922,
+ 6812, 6698, 6580, 6458,
+ 6332, 6204, 6070, 5934,
+ 5792, 5648, 5502, 5352,
+ 5198, 5040, 4880, 4718,
+ 4552, 4382, 4212, 4038,
+ 3862, 3684, 3502, 3320,
+ 3136, 2948, 2760, 2570,
+ 2378, 2186, 1990, 1794,
+ 1598, 1400, 1202, 1002,
+ 802, 602, 402, 202,
+ 0, -202, -402, -602,
+ -802, -1002, -1202, -1400,
+ -1598, -1794, -1990, -2186,
+ -2378, -2570, -2760, -2948,
+ -3136, -3320, -3502, -3684,
+ -3862, -4038, -4212, -4382,
+ -4552, -4718, -4880, -5040,
+ -5198, -5352, -5502, -5648,
+ -5792, -5934, -6070, -6204,
+ -6332, -6458, -6580, -6698,
+ -6812, -6922, -7026, -7128,
+ -7226, -7318, -7406, -7490,
+ -7568, -7644, -7714, -7778,
+ -7840, -7896, -7946, -7994,
+ -8034, -8072, -8104, -8130,
+ -8152, -8170, -8182, -8190,
+ -8192
+};
diff --git a/drivers/opus/silk/tables.h b/drivers/opus/silk/tables.h
new file mode 100644
index 0000000000..0dc7c37545
--- /dev/null
+++ b/drivers/opus/silk/tables.h
@@ -0,0 +1,122 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_TABLES_H
+#define SILK_TABLES_H
+
+#include "opus/silk/define.h"
+#include "opus/silk/structs.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Entropy coding tables (with size in bytes indicated) */
+extern const opus_uint8 silk_gain_iCDF[ 3 ][ N_LEVELS_QGAIN / 8 ]; /* 24 */
+extern const opus_uint8 silk_delta_gain_iCDF[ MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ]; /* 41 */
+
+extern const opus_uint8 silk_pitch_lag_iCDF[ 2 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) ];/* 32 */
+extern const opus_uint8 silk_pitch_delta_iCDF[ 21 ]; /* 21 */
+extern const opus_uint8 silk_pitch_contour_iCDF[ 34 ]; /* 34 */
+extern const opus_uint8 silk_pitch_contour_NB_iCDF[ 11 ]; /* 11 */
+extern const opus_uint8 silk_pitch_contour_10_ms_iCDF[ 12 ]; /* 12 */
+extern const opus_uint8 silk_pitch_contour_10_ms_NB_iCDF[ 3 ]; /* 3 */
+
+extern const opus_uint8 silk_pulses_per_block_iCDF[ N_RATE_LEVELS ][ MAX_PULSES + 2 ]; /* 180 */
+extern const opus_uint8 silk_pulses_per_block_BITS_Q5[ N_RATE_LEVELS - 1 ][ MAX_PULSES + 2 ]; /* 162 */
+
+extern const opus_uint8 silk_rate_levels_iCDF[ 2 ][ N_RATE_LEVELS - 1 ]; /* 18 */
+extern const opus_uint8 silk_rate_levels_BITS_Q5[ 2 ][ N_RATE_LEVELS - 1 ]; /* 18 */
+
+extern const opus_uint8 silk_max_pulses_table[ 4 ]; /* 4 */
+
+extern const opus_uint8 silk_shell_code_table0[ 152 ]; /* 152 */
+extern const opus_uint8 silk_shell_code_table1[ 152 ]; /* 152 */
+extern const opus_uint8 silk_shell_code_table2[ 152 ]; /* 152 */
+extern const opus_uint8 silk_shell_code_table3[ 152 ]; /* 152 */
+extern const opus_uint8 silk_shell_code_table_offsets[ MAX_PULSES + 1 ]; /* 17 */
+
+extern const opus_uint8 silk_lsb_iCDF[ 2 ]; /* 2 */
+
+extern const opus_uint8 silk_sign_iCDF[ 42 ]; /* 42 */
+
+extern const opus_uint8 silk_uniform3_iCDF[ 3 ]; /* 3 */
+extern const opus_uint8 silk_uniform4_iCDF[ 4 ]; /* 4 */
+extern const opus_uint8 silk_uniform5_iCDF[ 5 ]; /* 5 */
+extern const opus_uint8 silk_uniform6_iCDF[ 6 ]; /* 6 */
+extern const opus_uint8 silk_uniform8_iCDF[ 8 ]; /* 8 */
+
+extern const opus_uint8 silk_NLSF_EXT_iCDF[ 7 ]; /* 7 */
+
+extern const opus_uint8 silk_LTP_per_index_iCDF[ 3 ]; /* 3 */
+extern const opus_uint8 * const silk_LTP_gain_iCDF_ptrs[ NB_LTP_CBKS ]; /* 3 */
+extern const opus_uint8 * const silk_LTP_gain_BITS_Q5_ptrs[ NB_LTP_CBKS ]; /* 3 */
+extern const opus_int16 silk_LTP_gain_middle_avg_RD_Q14;
+extern const opus_int8 * const silk_LTP_vq_ptrs_Q7[ NB_LTP_CBKS ]; /* 168 */
+extern const opus_uint8 * const silk_LTP_vq_gain_ptrs_Q7[NB_LTP_CBKS];
+
+extern const opus_int8 silk_LTP_vq_sizes[ NB_LTP_CBKS ]; /* 3 */
+
+extern const opus_uint8 silk_LTPscale_iCDF[ 3 ]; /* 4 */
+extern const opus_int16 silk_LTPScales_table_Q14[ 3 ]; /* 6 */
+
+extern const opus_uint8 silk_type_offset_VAD_iCDF[ 4 ]; /* 4 */
+extern const opus_uint8 silk_type_offset_no_VAD_iCDF[ 2 ]; /* 2 */
+
+extern const opus_int16 silk_stereo_pred_quant_Q13[ STEREO_QUANT_TAB_SIZE ]; /* 32 */
+extern const opus_uint8 silk_stereo_pred_joint_iCDF[ 25 ]; /* 25 */
+extern const opus_uint8 silk_stereo_only_code_mid_iCDF[ 2 ]; /* 2 */
+
+extern const opus_uint8 * const silk_LBRR_flags_iCDF_ptr[ 2 ]; /* 10 */
+
+extern const opus_uint8 silk_NLSF_interpolation_factor_iCDF[ 5 ]; /* 5 */
+
+extern const silk_NLSF_CB_struct silk_NLSF_CB_WB; /* 1040 */
+extern const silk_NLSF_CB_struct silk_NLSF_CB_NB_MB; /* 728 */
+
+/* Piece-wise linear mapping from bitrate in kbps to coding quality in dB SNR */
+extern const opus_int32 silk_TargetRate_table_NB[ TARGET_RATE_TAB_SZ ]; /* 32 */
+extern const opus_int32 silk_TargetRate_table_MB[ TARGET_RATE_TAB_SZ ]; /* 32 */
+extern const opus_int32 silk_TargetRate_table_WB[ TARGET_RATE_TAB_SZ ]; /* 32 */
+extern const opus_int16 silk_SNR_table_Q1[ TARGET_RATE_TAB_SZ ]; /* 32 */
+
+/* Quantization offsets */
+extern const opus_int16 silk_Quantization_Offsets_Q10[ 2 ][ 2 ]; /* 8 */
+
+/* Interpolation points for filter coefficients used in the bandwidth transition smoother */
+extern const opus_int32 silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NB ]; /* 60 */
+extern const opus_int32 silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NA ]; /* 60 */
+
+/* Rom table with cosine values */
+extern const opus_int16 silk_LSFCosTab_FIX_Q12[ LSF_COS_TAB_SZ_FIX + 1 ]; /* 258 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/opus/silk/tables_LTP.c b/drivers/opus/silk/tables_LTP.c
new file mode 100644
index 0000000000..6a05698252
--- /dev/null
+++ b/drivers/opus/silk/tables_LTP.c
@@ -0,0 +1,296 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/tables.h"
+
+const opus_uint8 silk_LTP_per_index_iCDF[3] = {
+ 179, 99, 0
+};
+
+static const opus_uint8 silk_LTP_gain_iCDF_0[8] = {
+ 71, 56, 43, 30, 21, 12, 6, 0
+};
+
+static const opus_uint8 silk_LTP_gain_iCDF_1[16] = {
+ 199, 165, 144, 124, 109, 96, 84, 71,
+ 61, 51, 42, 32, 23, 15, 8, 0
+};
+
+static const opus_uint8 silk_LTP_gain_iCDF_2[32] = {
+ 241, 225, 211, 199, 187, 175, 164, 153,
+ 142, 132, 123, 114, 105, 96, 88, 80,
+ 72, 64, 57, 50, 44, 38, 33, 29,
+ 24, 20, 16, 12, 9, 5, 2, 0
+};
+
+const opus_int16 silk_LTP_gain_middle_avg_RD_Q14 = 12304;
+
+static const opus_uint8 silk_LTP_gain_BITS_Q5_0[8] = {
+ 15, 131, 138, 138, 155, 155, 173, 173
+};
+
+static const opus_uint8 silk_LTP_gain_BITS_Q5_1[16] = {
+ 69, 93, 115, 118, 131, 138, 141, 138,
+ 150, 150, 155, 150, 155, 160, 166, 160
+};
+
+static const opus_uint8 silk_LTP_gain_BITS_Q5_2[32] = {
+ 131, 128, 134, 141, 141, 141, 145, 145,
+ 145, 150, 155, 155, 155, 155, 160, 160,
+ 160, 160, 166, 166, 173, 173, 182, 192,
+ 182, 192, 192, 192, 205, 192, 205, 224
+};
+
+const opus_uint8 * const silk_LTP_gain_iCDF_ptrs[NB_LTP_CBKS] = {
+ silk_LTP_gain_iCDF_0,
+ silk_LTP_gain_iCDF_1,
+ silk_LTP_gain_iCDF_2
+};
+
+const opus_uint8 * const silk_LTP_gain_BITS_Q5_ptrs[NB_LTP_CBKS] = {
+ silk_LTP_gain_BITS_Q5_0,
+ silk_LTP_gain_BITS_Q5_1,
+ silk_LTP_gain_BITS_Q5_2
+};
+
+static const opus_int8 silk_LTP_gain_vq_0[8][5] =
+{
+{
+ 4, 6, 24, 7, 5
+},
+{
+ 0, 0, 2, 0, 0
+},
+{
+ 12, 28, 41, 13, -4
+},
+{
+ -9, 15, 42, 25, 14
+},
+{
+ 1, -2, 62, 41, -9
+},
+{
+ -10, 37, 65, -4, 3
+},
+{
+ -6, 4, 66, 7, -8
+},
+{
+ 16, 14, 38, -3, 33
+}
+};
+
+static const opus_int8 silk_LTP_gain_vq_1[16][5] =
+{
+{
+ 13, 22, 39, 23, 12
+},
+{
+ -1, 36, 64, 27, -6
+},
+{
+ -7, 10, 55, 43, 17
+},
+{
+ 1, 1, 8, 1, 1
+},
+{
+ 6, -11, 74, 53, -9
+},
+{
+ -12, 55, 76, -12, 8
+},
+{
+ -3, 3, 93, 27, -4
+},
+{
+ 26, 39, 59, 3, -8
+},
+{
+ 2, 0, 77, 11, 9
+},
+{
+ -8, 22, 44, -6, 7
+},
+{
+ 40, 9, 26, 3, 9
+},
+{
+ -7, 20, 101, -7, 4
+},
+{
+ 3, -8, 42, 26, 0
+},
+{
+ -15, 33, 68, 2, 23
+},
+{
+ -2, 55, 46, -2, 15
+},
+{
+ 3, -1, 21, 16, 41
+}
+};
+
+static const opus_int8 silk_LTP_gain_vq_2[32][5] =
+{
+{
+ -6, 27, 61, 39, 5
+},
+{
+ -11, 42, 88, 4, 1
+},
+{
+ -2, 60, 65, 6, -4
+},
+{
+ -1, -5, 73, 56, 1
+},
+{
+ -9, 19, 94, 29, -9
+},
+{
+ 0, 12, 99, 6, 4
+},
+{
+ 8, -19, 102, 46, -13
+},
+{
+ 3, 2, 13, 3, 2
+},
+{
+ 9, -21, 84, 72, -18
+},
+{
+ -11, 46, 104, -22, 8
+},
+{
+ 18, 38, 48, 23, 0
+},
+{
+ -16, 70, 83, -21, 11
+},
+{
+ 5, -11, 117, 22, -8
+},
+{
+ -6, 23, 117, -12, 3
+},
+{
+ 3, -8, 95, 28, 4
+},
+{
+ -10, 15, 77, 60, -15
+},
+{
+ -1, 4, 124, 2, -4
+},
+{
+ 3, 38, 84, 24, -25
+},
+{
+ 2, 13, 42, 13, 31
+},
+{
+ 21, -4, 56, 46, -1
+},
+{
+ -1, 35, 79, -13, 19
+},
+{
+ -7, 65, 88, -9, -14
+},
+{
+ 20, 4, 81, 49, -29
+},
+{
+ 20, 0, 75, 3, -17
+},
+{
+ 5, -9, 44, 92, -8
+},
+{
+ 1, -3, 22, 69, 31
+},
+{
+ -6, 95, 41, -12, 5
+},
+{
+ 39, 67, 16, -4, 1
+},
+{
+ 0, -6, 120, 55, -36
+},
+{
+ -13, 44, 122, 4, -24
+},
+{
+ 81, 5, 11, 3, 7
+},
+{
+ 2, 0, 9, 10, 88
+}
+};
+
+const opus_int8 * const silk_LTP_vq_ptrs_Q7[NB_LTP_CBKS] = {
+ (opus_int8 *)&silk_LTP_gain_vq_0[0][0],
+ (opus_int8 *)&silk_LTP_gain_vq_1[0][0],
+ (opus_int8 *)&silk_LTP_gain_vq_2[0][0]
+};
+
+/* Maximum frequency-dependent response of the pitch taps above,
+ computed as max(abs(freqz(taps))) */
+static const opus_uint8 silk_LTP_gain_vq_0_gain[8] = {
+ 46, 2, 90, 87, 93, 91, 82, 98
+};
+
+static const opus_uint8 silk_LTP_gain_vq_1_gain[16] = {
+ 109, 120, 118, 12, 113, 115, 117, 119,
+ 99, 59, 87, 111, 63, 111, 112, 80
+};
+
+static const opus_uint8 silk_LTP_gain_vq_2_gain[32] = {
+ 126, 124, 125, 124, 129, 121, 126, 23,
+ 132, 127, 127, 127, 126, 127, 122, 133,
+ 130, 134, 101, 118, 119, 145, 126, 86,
+ 124, 120, 123, 119, 170, 173, 107, 109
+};
+
+const opus_uint8 * const silk_LTP_vq_gain_ptrs_Q7[NB_LTP_CBKS] = {
+ &silk_LTP_gain_vq_0_gain[0],
+ &silk_LTP_gain_vq_1_gain[0],
+ &silk_LTP_gain_vq_2_gain[0]
+};
+
+const opus_int8 silk_LTP_vq_sizes[NB_LTP_CBKS] = {
+ 8, 16, 32
+};
diff --git a/drivers/opus/silk/tables_NLSF_CB_NB_MB.c b/drivers/opus/silk/tables_NLSF_CB_NB_MB.c
new file mode 100644
index 0000000000..66c2fd4036
--- /dev/null
+++ b/drivers/opus/silk/tables_NLSF_CB_NB_MB.c
@@ -0,0 +1,159 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/tables.h"
+
+static const opus_uint8 silk_NLSF_CB1_NB_MB_Q8[ 320 ] = {
+ 12, 35, 60, 83, 108, 132, 157, 180,
+ 206, 228, 15, 32, 55, 77, 101, 125,
+ 151, 175, 201, 225, 19, 42, 66, 89,
+ 114, 137, 162, 184, 209, 230, 12, 25,
+ 50, 72, 97, 120, 147, 172, 200, 223,
+ 26, 44, 69, 90, 114, 135, 159, 180,
+ 205, 225, 13, 22, 53, 80, 106, 130,
+ 156, 180, 205, 228, 15, 25, 44, 64,
+ 90, 115, 142, 168, 196, 222, 19, 24,
+ 62, 82, 100, 120, 145, 168, 190, 214,
+ 22, 31, 50, 79, 103, 120, 151, 170,
+ 203, 227, 21, 29, 45, 65, 106, 124,
+ 150, 171, 196, 224, 30, 49, 75, 97,
+ 121, 142, 165, 186, 209, 229, 19, 25,
+ 52, 70, 93, 116, 143, 166, 192, 219,
+ 26, 34, 62, 75, 97, 118, 145, 167,
+ 194, 217, 25, 33, 56, 70, 91, 113,
+ 143, 165, 196, 223, 21, 34, 51, 72,
+ 97, 117, 145, 171, 196, 222, 20, 29,
+ 50, 67, 90, 117, 144, 168, 197, 221,
+ 22, 31, 48, 66, 95, 117, 146, 168,
+ 196, 222, 24, 33, 51, 77, 116, 134,
+ 158, 180, 200, 224, 21, 28, 70, 87,
+ 106, 124, 149, 170, 194, 217, 26, 33,
+ 53, 64, 83, 117, 152, 173, 204, 225,
+ 27, 34, 65, 95, 108, 129, 155, 174,
+ 210, 225, 20, 26, 72, 99, 113, 131,
+ 154, 176, 200, 219, 34, 43, 61, 78,
+ 93, 114, 155, 177, 205, 229, 23, 29,
+ 54, 97, 124, 138, 163, 179, 209, 229,
+ 30, 38, 56, 89, 118, 129, 158, 178,
+ 200, 231, 21, 29, 49, 63, 85, 111,
+ 142, 163, 193, 222, 27, 48, 77, 103,
+ 133, 158, 179, 196, 215, 232, 29, 47,
+ 74, 99, 124, 151, 176, 198, 220, 237,
+ 33, 42, 61, 76, 93, 121, 155, 174,
+ 207, 225, 29, 53, 87, 112, 136, 154,
+ 170, 188, 208, 227, 24, 30, 52, 84,
+ 131, 150, 166, 186, 203, 229, 37, 48,
+ 64, 84, 104, 118, 156, 177, 201, 230
+};
+
+static const opus_uint8 silk_NLSF_CB1_iCDF_NB_MB[ 64 ] = {
+ 212, 178, 148, 129, 108, 96, 85, 82,
+ 79, 77, 61, 59, 57, 56, 51, 49,
+ 48, 45, 42, 41, 40, 38, 36, 34,
+ 31, 30, 21, 12, 10, 3, 1, 0,
+ 255, 245, 244, 236, 233, 225, 217, 203,
+ 190, 176, 175, 161, 149, 136, 125, 114,
+ 102, 91, 81, 71, 60, 52, 43, 35,
+ 28, 20, 19, 18, 12, 11, 5, 0
+};
+
+static const opus_uint8 silk_NLSF_CB2_SELECT_NB_MB[ 160 ] = {
+ 16, 0, 0, 0, 0, 99, 66, 36,
+ 36, 34, 36, 34, 34, 34, 34, 83,
+ 69, 36, 52, 34, 116, 102, 70, 68,
+ 68, 176, 102, 68, 68, 34, 65, 85,
+ 68, 84, 36, 116, 141, 152, 139, 170,
+ 132, 187, 184, 216, 137, 132, 249, 168,
+ 185, 139, 104, 102, 100, 68, 68, 178,
+ 218, 185, 185, 170, 244, 216, 187, 187,
+ 170, 244, 187, 187, 219, 138, 103, 155,
+ 184, 185, 137, 116, 183, 155, 152, 136,
+ 132, 217, 184, 184, 170, 164, 217, 171,
+ 155, 139, 244, 169, 184, 185, 170, 164,
+ 216, 223, 218, 138, 214, 143, 188, 218,
+ 168, 244, 141, 136, 155, 170, 168, 138,
+ 220, 219, 139, 164, 219, 202, 216, 137,
+ 168, 186, 246, 185, 139, 116, 185, 219,
+ 185, 138, 100, 100, 134, 100, 102, 34,
+ 68, 68, 100, 68, 168, 203, 221, 218,
+ 168, 167, 154, 136, 104, 70, 164, 246,
+ 171, 137, 139, 137, 155, 218, 219, 139
+};
+
+static const opus_uint8 silk_NLSF_CB2_iCDF_NB_MB[ 72 ] = {
+ 255, 254, 253, 238, 14, 3, 2, 1,
+ 0, 255, 254, 252, 218, 35, 3, 2,
+ 1, 0, 255, 254, 250, 208, 59, 4,
+ 2, 1, 0, 255, 254, 246, 194, 71,
+ 10, 2, 1, 0, 255, 252, 236, 183,
+ 82, 8, 2, 1, 0, 255, 252, 235,
+ 180, 90, 17, 2, 1, 0, 255, 248,
+ 224, 171, 97, 30, 4, 1, 0, 255,
+ 254, 236, 173, 95, 37, 7, 1, 0
+};
+
+static const opus_uint8 silk_NLSF_CB2_BITS_NB_MB_Q5[ 72 ] = {
+ 255, 255, 255, 131, 6, 145, 255, 255,
+ 255, 255, 255, 236, 93, 15, 96, 255,
+ 255, 255, 255, 255, 194, 83, 25, 71,
+ 221, 255, 255, 255, 255, 162, 73, 34,
+ 66, 162, 255, 255, 255, 210, 126, 73,
+ 43, 57, 173, 255, 255, 255, 201, 125,
+ 71, 48, 58, 130, 255, 255, 255, 166,
+ 110, 73, 57, 62, 104, 210, 255, 255,
+ 251, 123, 65, 55, 68, 100, 171, 255
+};
+
+static const opus_uint8 silk_NLSF_PRED_NB_MB_Q8[ 18 ] = {
+ 179, 138, 140, 148, 151, 149, 153, 151,
+ 163, 116, 67, 82, 59, 92, 72, 100,
+ 89, 92
+};
+
+static const opus_int16 silk_NLSF_DELTA_MIN_NB_MB_Q15[ 11 ] = {
+ 250, 3, 6, 3, 3, 3, 4, 3,
+ 3, 3, 461
+};
+
+const silk_NLSF_CB_struct silk_NLSF_CB_NB_MB =
+{
+ 32,
+ 10,
+ SILK_FIX_CONST( 0.18, 16 ),
+ SILK_FIX_CONST( 1.0 / 0.18, 6 ),
+ silk_NLSF_CB1_NB_MB_Q8,
+ silk_NLSF_CB1_iCDF_NB_MB,
+ silk_NLSF_PRED_NB_MB_Q8,
+ silk_NLSF_CB2_SELECT_NB_MB,
+ silk_NLSF_CB2_iCDF_NB_MB,
+ silk_NLSF_CB2_BITS_NB_MB_Q5,
+ silk_NLSF_DELTA_MIN_NB_MB_Q15,
+};
diff --git a/drivers/opus/silk/tables_NLSF_CB_WB.c b/drivers/opus/silk/tables_NLSF_CB_WB.c
new file mode 100644
index 0000000000..366f1bc887
--- /dev/null
+++ b/drivers/opus/silk/tables_NLSF_CB_WB.c
@@ -0,0 +1,198 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/tables.h"
+
+static const opus_uint8 silk_NLSF_CB1_WB_Q8[ 512 ] = {
+ 7, 23, 38, 54, 69, 85, 100, 116,
+ 131, 147, 162, 178, 193, 208, 223, 239,
+ 13, 25, 41, 55, 69, 83, 98, 112,
+ 127, 142, 157, 171, 187, 203, 220, 236,
+ 15, 21, 34, 51, 61, 78, 92, 106,
+ 126, 136, 152, 167, 185, 205, 225, 240,
+ 10, 21, 36, 50, 63, 79, 95, 110,
+ 126, 141, 157, 173, 189, 205, 221, 237,
+ 17, 20, 37, 51, 59, 78, 89, 107,
+ 123, 134, 150, 164, 184, 205, 224, 240,
+ 10, 15, 32, 51, 67, 81, 96, 112,
+ 129, 142, 158, 173, 189, 204, 220, 236,
+ 8, 21, 37, 51, 65, 79, 98, 113,
+ 126, 138, 155, 168, 179, 192, 209, 218,
+ 12, 15, 34, 55, 63, 78, 87, 108,
+ 118, 131, 148, 167, 185, 203, 219, 236,
+ 16, 19, 32, 36, 56, 79, 91, 108,
+ 118, 136, 154, 171, 186, 204, 220, 237,
+ 11, 28, 43, 58, 74, 89, 105, 120,
+ 135, 150, 165, 180, 196, 211, 226, 241,
+ 6, 16, 33, 46, 60, 75, 92, 107,
+ 123, 137, 156, 169, 185, 199, 214, 225,
+ 11, 19, 30, 44, 57, 74, 89, 105,
+ 121, 135, 152, 169, 186, 202, 218, 234,
+ 12, 19, 29, 46, 57, 71, 88, 100,
+ 120, 132, 148, 165, 182, 199, 216, 233,
+ 17, 23, 35, 46, 56, 77, 92, 106,
+ 123, 134, 152, 167, 185, 204, 222, 237,
+ 14, 17, 45, 53, 63, 75, 89, 107,
+ 115, 132, 151, 171, 188, 206, 221, 240,
+ 9, 16, 29, 40, 56, 71, 88, 103,
+ 119, 137, 154, 171, 189, 205, 222, 237,
+ 16, 19, 36, 48, 57, 76, 87, 105,
+ 118, 132, 150, 167, 185, 202, 218, 236,
+ 12, 17, 29, 54, 71, 81, 94, 104,
+ 126, 136, 149, 164, 182, 201, 221, 237,
+ 15, 28, 47, 62, 79, 97, 115, 129,
+ 142, 155, 168, 180, 194, 208, 223, 238,
+ 8, 14, 30, 45, 62, 78, 94, 111,
+ 127, 143, 159, 175, 192, 207, 223, 239,
+ 17, 30, 49, 62, 79, 92, 107, 119,
+ 132, 145, 160, 174, 190, 204, 220, 235,
+ 14, 19, 36, 45, 61, 76, 91, 108,
+ 121, 138, 154, 172, 189, 205, 222, 238,
+ 12, 18, 31, 45, 60, 76, 91, 107,
+ 123, 138, 154, 171, 187, 204, 221, 236,
+ 13, 17, 31, 43, 53, 70, 83, 103,
+ 114, 131, 149, 167, 185, 203, 220, 237,
+ 17, 22, 35, 42, 58, 78, 93, 110,
+ 125, 139, 155, 170, 188, 206, 224, 240,
+ 8, 15, 34, 50, 67, 83, 99, 115,
+ 131, 146, 162, 178, 193, 209, 224, 239,
+ 13, 16, 41, 66, 73, 86, 95, 111,
+ 128, 137, 150, 163, 183, 206, 225, 241,
+ 17, 25, 37, 52, 63, 75, 92, 102,
+ 119, 132, 144, 160, 175, 191, 212, 231,
+ 19, 31, 49, 65, 83, 100, 117, 133,
+ 147, 161, 174, 187, 200, 213, 227, 242,
+ 18, 31, 52, 68, 88, 103, 117, 126,
+ 138, 149, 163, 177, 192, 207, 223, 239,
+ 16, 29, 47, 61, 76, 90, 106, 119,
+ 133, 147, 161, 176, 193, 209, 224, 240,
+ 15, 21, 35, 50, 61, 73, 86, 97,
+ 110, 119, 129, 141, 175, 198, 218, 237
+};
+
+static const opus_uint8 silk_NLSF_CB1_iCDF_WB[ 64 ] = {
+ 225, 204, 201, 184, 183, 175, 158, 154,
+ 153, 135, 119, 115, 113, 110, 109, 99,
+ 98, 95, 79, 68, 52, 50, 48, 45,
+ 43, 32, 31, 27, 18, 10, 3, 0,
+ 255, 251, 235, 230, 212, 201, 196, 182,
+ 167, 166, 163, 151, 138, 124, 110, 104,
+ 90, 78, 76, 70, 69, 57, 45, 34,
+ 24, 21, 11, 6, 5, 4, 3, 0
+};
+
+static const opus_uint8 silk_NLSF_CB2_SELECT_WB[ 256 ] = {
+ 0, 0, 0, 0, 0, 0, 0, 1,
+ 100, 102, 102, 68, 68, 36, 34, 96,
+ 164, 107, 158, 185, 180, 185, 139, 102,
+ 64, 66, 36, 34, 34, 0, 1, 32,
+ 208, 139, 141, 191, 152, 185, 155, 104,
+ 96, 171, 104, 166, 102, 102, 102, 132,
+ 1, 0, 0, 0, 0, 16, 16, 0,
+ 80, 109, 78, 107, 185, 139, 103, 101,
+ 208, 212, 141, 139, 173, 153, 123, 103,
+ 36, 0, 0, 0, 0, 0, 0, 1,
+ 48, 0, 0, 0, 0, 0, 0, 32,
+ 68, 135, 123, 119, 119, 103, 69, 98,
+ 68, 103, 120, 118, 118, 102, 71, 98,
+ 134, 136, 157, 184, 182, 153, 139, 134,
+ 208, 168, 248, 75, 189, 143, 121, 107,
+ 32, 49, 34, 34, 34, 0, 17, 2,
+ 210, 235, 139, 123, 185, 137, 105, 134,
+ 98, 135, 104, 182, 100, 183, 171, 134,
+ 100, 70, 68, 70, 66, 66, 34, 131,
+ 64, 166, 102, 68, 36, 2, 1, 0,
+ 134, 166, 102, 68, 34, 34, 66, 132,
+ 212, 246, 158, 139, 107, 107, 87, 102,
+ 100, 219, 125, 122, 137, 118, 103, 132,
+ 114, 135, 137, 105, 171, 106, 50, 34,
+ 164, 214, 141, 143, 185, 151, 121, 103,
+ 192, 34, 0, 0, 0, 0, 0, 1,
+ 208, 109, 74, 187, 134, 249, 159, 137,
+ 102, 110, 154, 118, 87, 101, 119, 101,
+ 0, 2, 0, 36, 36, 66, 68, 35,
+ 96, 164, 102, 100, 36, 0, 2, 33,
+ 167, 138, 174, 102, 100, 84, 2, 2,
+ 100, 107, 120, 119, 36, 197, 24, 0
+};
+
+static const opus_uint8 silk_NLSF_CB2_iCDF_WB[ 72 ] = {
+ 255, 254, 253, 244, 12, 3, 2, 1,
+ 0, 255, 254, 252, 224, 38, 3, 2,
+ 1, 0, 255, 254, 251, 209, 57, 4,
+ 2, 1, 0, 255, 254, 244, 195, 69,
+ 4, 2, 1, 0, 255, 251, 232, 184,
+ 84, 7, 2, 1, 0, 255, 254, 240,
+ 186, 86, 14, 2, 1, 0, 255, 254,
+ 239, 178, 91, 30, 5, 1, 0, 255,
+ 248, 227, 177, 100, 19, 2, 1, 0
+};
+
+static const opus_uint8 silk_NLSF_CB2_BITS_WB_Q5[ 72 ] = {
+ 255, 255, 255, 156, 4, 154, 255, 255,
+ 255, 255, 255, 227, 102, 15, 92, 255,
+ 255, 255, 255, 255, 213, 83, 24, 72,
+ 236, 255, 255, 255, 255, 150, 76, 33,
+ 63, 214, 255, 255, 255, 190, 121, 77,
+ 43, 55, 185, 255, 255, 255, 245, 137,
+ 71, 43, 59, 139, 255, 255, 255, 255,
+ 131, 66, 50, 66, 107, 194, 255, 255,
+ 166, 116, 76, 55, 53, 125, 255, 255
+};
+
+static const opus_uint8 silk_NLSF_PRED_WB_Q8[ 30 ] = {
+ 175, 148, 160, 176, 178, 173, 174, 164,
+ 177, 174, 196, 182, 198, 192, 182, 68,
+ 62, 66, 60, 72, 117, 85, 90, 118,
+ 136, 151, 142, 160, 142, 155
+};
+
+static const opus_int16 silk_NLSF_DELTA_MIN_WB_Q15[ 17 ] = {
+ 100, 3, 40, 3, 3, 3, 5, 14,
+ 14, 10, 11, 3, 8, 9, 7, 3,
+ 347
+};
+
+const silk_NLSF_CB_struct silk_NLSF_CB_WB =
+{
+ 32,
+ 16,
+ SILK_FIX_CONST( 0.15, 16 ),
+ SILK_FIX_CONST( 1.0 / 0.15, 6 ),
+ silk_NLSF_CB1_WB_Q8,
+ silk_NLSF_CB1_iCDF_WB,
+ silk_NLSF_PRED_WB_Q8,
+ silk_NLSF_CB2_SELECT_WB,
+ silk_NLSF_CB2_iCDF_WB,
+ silk_NLSF_CB2_BITS_WB_Q5,
+ silk_NLSF_DELTA_MIN_WB_Q15,
+};
+
diff --git a/drivers/opus/silk/tables_gain.c b/drivers/opus/silk/tables_gain.c
new file mode 100644
index 0000000000..efb5b899b8
--- /dev/null
+++ b/drivers/opus/silk/tables_gain.c
@@ -0,0 +1,63 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/tables.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+const opus_uint8 silk_gain_iCDF[ 3 ][ N_LEVELS_QGAIN / 8 ] =
+{
+{
+ 224, 112, 44, 15, 3, 2, 1, 0
+},
+{
+ 254, 237, 192, 132, 70, 23, 4, 0
+},
+{
+ 255, 252, 226, 155, 61, 11, 2, 0
+}
+};
+
+const opus_uint8 silk_delta_gain_iCDF[ MAX_DELTA_GAIN_QUANT - MIN_DELTA_GAIN_QUANT + 1 ] = {
+ 250, 245, 234, 203, 71, 50, 42, 38,
+ 35, 33, 31, 29, 28, 27, 26, 25,
+ 24, 23, 22, 21, 20, 19, 18, 17,
+ 16, 15, 14, 13, 12, 11, 10, 9,
+ 8, 7, 6, 5, 4, 3, 2, 1,
+ 0
+};
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/drivers/opus/silk/tables_other.c b/drivers/opus/silk/tables_other.c
new file mode 100644
index 0000000000..5e588fbf0c
--- /dev/null
+++ b/drivers/opus/silk/tables_other.c
@@ -0,0 +1,138 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/structs.h"
+#include "opus/silk/define.h"
+#include "opus/silk/tables.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Piece-wise linear mapping from bitrate in kbps to coding quality in dB SNR */
+const opus_int32 silk_TargetRate_table_NB[ TARGET_RATE_TAB_SZ ] = {
+ 0, 8000, 9400, 11500, 13500, 17500, 25000, MAX_TARGET_RATE_BPS
+};
+const opus_int32 silk_TargetRate_table_MB[ TARGET_RATE_TAB_SZ ] = {
+ 0, 9000, 12000, 14500, 18500, 24500, 35500, MAX_TARGET_RATE_BPS
+};
+const opus_int32 silk_TargetRate_table_WB[ TARGET_RATE_TAB_SZ ] = {
+ 0, 10500, 14000, 17000, 21500, 28500, 42000, MAX_TARGET_RATE_BPS
+};
+const opus_int16 silk_SNR_table_Q1[ TARGET_RATE_TAB_SZ ] = {
+ 18, 29, 38, 40, 46, 52, 62, 84
+};
+
+/* Tables for stereo predictor coding */
+const opus_int16 silk_stereo_pred_quant_Q13[ STEREO_QUANT_TAB_SIZE ] = {
+ -13732, -10050, -8266, -7526, -6500, -5000, -2950, -820,
+ 820, 2950, 5000, 6500, 7526, 8266, 10050, 13732
+};
+const opus_uint8 silk_stereo_pred_joint_iCDF[ 25 ] = {
+ 249, 247, 246, 245, 244,
+ 234, 210, 202, 201, 200,
+ 197, 174, 82, 59, 56,
+ 55, 54, 46, 22, 12,
+ 11, 10, 9, 7, 0
+};
+const opus_uint8 silk_stereo_only_code_mid_iCDF[ 2 ] = { 64, 0 };
+
+/* Tables for LBRR flags */
+static const opus_uint8 silk_LBRR_flags_2_iCDF[ 3 ] = { 203, 150, 0 };
+static const opus_uint8 silk_LBRR_flags_3_iCDF[ 7 ] = { 215, 195, 166, 125, 110, 82, 0 };
+const opus_uint8 * const silk_LBRR_flags_iCDF_ptr[ 2 ] = {
+ silk_LBRR_flags_2_iCDF,
+ silk_LBRR_flags_3_iCDF
+};
+
+/* Table for LSB coding */
+const opus_uint8 silk_lsb_iCDF[ 2 ] = { 120, 0 };
+
+/* Tables for LTPScale */
+const opus_uint8 silk_LTPscale_iCDF[ 3 ] = { 128, 64, 0 };
+
+/* Tables for signal type and offset coding */
+const opus_uint8 silk_type_offset_VAD_iCDF[ 4 ] = {
+ 232, 158, 10, 0
+};
+const opus_uint8 silk_type_offset_no_VAD_iCDF[ 2 ] = {
+ 230, 0
+};
+
+/* Tables for NLSF interpolation factor */
+const opus_uint8 silk_NLSF_interpolation_factor_iCDF[ 5 ] = { 243, 221, 192, 181, 0 };
+
+/* Quantization offsets */
+const opus_int16 silk_Quantization_Offsets_Q10[ 2 ][ 2 ] = {
+ { OFFSET_UVL_Q10, OFFSET_UVH_Q10 }, { OFFSET_VL_Q10, OFFSET_VH_Q10 }
+};
+
+/* Table for LTPScale */
+const opus_int16 silk_LTPScales_table_Q14[ 3 ] = { 15565, 12288, 8192 };
+
+/* Uniform entropy tables */
+const opus_uint8 silk_uniform3_iCDF[ 3 ] = { 171, 85, 0 };
+const opus_uint8 silk_uniform4_iCDF[ 4 ] = { 192, 128, 64, 0 };
+const opus_uint8 silk_uniform5_iCDF[ 5 ] = { 205, 154, 102, 51, 0 };
+const opus_uint8 silk_uniform6_iCDF[ 6 ] = { 213, 171, 128, 85, 43, 0 };
+const opus_uint8 silk_uniform8_iCDF[ 8 ] = { 224, 192, 160, 128, 96, 64, 32, 0 };
+
+const opus_uint8 silk_NLSF_EXT_iCDF[ 7 ] = { 100, 40, 16, 7, 3, 1, 0 };
+
+/* Elliptic/Cauer filters designed with 0.1 dB passband ripple,
+ 80 dB minimum stopband attenuation, and
+ [0.95 : 0.15 : 0.35] normalized cut off frequencies. */
+
+/* Interpolation points for filter coefficients used in the bandwidth transition smoother */
+const opus_int32 silk_Transition_LP_B_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NB ] =
+{
+{ 250767114, 501534038, 250767114 },
+{ 209867381, 419732057, 209867381 },
+{ 170987846, 341967853, 170987846 },
+{ 131531482, 263046905, 131531482 },
+{ 89306658, 178584282, 89306658 }
+};
+
+/* Interpolation points for filter coefficients used in the bandwidth transition smoother */
+const opus_int32 silk_Transition_LP_A_Q28[ TRANSITION_INT_NUM ][ TRANSITION_NA ] =
+{
+{ 506393414, 239854379 },
+{ 411067935, 169683996 },
+{ 306733530, 116694253 },
+{ 185807084, 77959395 },
+{ 35497197, 57401098 }
+};
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/drivers/opus/silk/tables_pitch_lag.c b/drivers/opus/silk/tables_pitch_lag.c
new file mode 100644
index 0000000000..e1c4617d0a
--- /dev/null
+++ b/drivers/opus/silk/tables_pitch_lag.c
@@ -0,0 +1,69 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/tables.h"
+
+const opus_uint8 silk_pitch_lag_iCDF[ 2 * ( PITCH_EST_MAX_LAG_MS - PITCH_EST_MIN_LAG_MS ) ] = {
+ 253, 250, 244, 233, 212, 182, 150, 131,
+ 120, 110, 98, 85, 72, 60, 49, 40,
+ 32, 25, 19, 15, 13, 11, 9, 8,
+ 7, 6, 5, 4, 3, 2, 1, 0
+};
+
+const opus_uint8 silk_pitch_delta_iCDF[21] = {
+ 210, 208, 206, 203, 199, 193, 183, 168,
+ 142, 104, 74, 52, 37, 27, 20, 14,
+ 10, 6, 4, 2, 0
+};
+
+const opus_uint8 silk_pitch_contour_iCDF[34] = {
+ 223, 201, 183, 167, 152, 138, 124, 111,
+ 98, 88, 79, 70, 62, 56, 50, 44,
+ 39, 35, 31, 27, 24, 21, 18, 16,
+ 14, 12, 10, 8, 6, 4, 3, 2,
+ 1, 0
+};
+
+const opus_uint8 silk_pitch_contour_NB_iCDF[11] = {
+ 188, 176, 155, 138, 119, 97, 67, 43,
+ 26, 10, 0
+};
+
+const opus_uint8 silk_pitch_contour_10_ms_iCDF[12] = {
+ 165, 119, 80, 61, 47, 35, 27, 20,
+ 14, 9, 4, 0
+};
+
+const opus_uint8 silk_pitch_contour_10_ms_NB_iCDF[3] = {
+ 113, 63, 0
+};
+
+
diff --git a/drivers/opus/silk/tables_pulses_per_block.c b/drivers/opus/silk/tables_pulses_per_block.c
new file mode 100644
index 0000000000..a1e2fb03d8
--- /dev/null
+++ b/drivers/opus/silk/tables_pulses_per_block.c
@@ -0,0 +1,264 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/silk/tables.h"
+
+const opus_uint8 silk_max_pulses_table[ 4 ] = {
+ 8, 10, 12, 16
+};
+
+const opus_uint8 silk_pulses_per_block_iCDF[ 10 ][ 18 ] = {
+{
+ 125, 51, 26, 18, 15, 12, 11, 10,
+ 9, 8, 7, 6, 5, 4, 3, 2,
+ 1, 0
+},
+{
+ 198, 105, 45, 22, 15, 12, 11, 10,
+ 9, 8, 7, 6, 5, 4, 3, 2,
+ 1, 0
+},
+{
+ 213, 162, 116, 83, 59, 43, 32, 24,
+ 18, 15, 12, 9, 7, 6, 5, 3,
+ 2, 0
+},
+{
+ 239, 187, 116, 59, 28, 16, 11, 10,
+ 9, 8, 7, 6, 5, 4, 3, 2,
+ 1, 0
+},
+{
+ 250, 229, 188, 135, 86, 51, 30, 19,
+ 13, 10, 8, 6, 5, 4, 3, 2,
+ 1, 0
+},
+{
+ 249, 235, 213, 185, 156, 128, 103, 83,
+ 66, 53, 42, 33, 26, 21, 17, 13,
+ 10, 0
+},
+{
+ 254, 249, 235, 206, 164, 118, 77, 46,
+ 27, 16, 10, 7, 5, 4, 3, 2,
+ 1, 0
+},
+{
+ 255, 253, 249, 239, 220, 191, 156, 119,
+ 85, 57, 37, 23, 15, 10, 6, 4,
+ 2, 0
+},
+{
+ 255, 253, 251, 246, 237, 223, 203, 179,
+ 152, 124, 98, 75, 55, 40, 29, 21,
+ 15, 0
+},
+{
+ 255, 254, 253, 247, 220, 162, 106, 67,
+ 42, 28, 18, 12, 9, 6, 4, 3,
+ 2, 0
+}
+};
+
+const opus_uint8 silk_pulses_per_block_BITS_Q5[ 9 ][ 18 ] = {
+{
+ 31, 57, 107, 160, 205, 205, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255
+},
+{
+ 69, 47, 67, 111, 166, 205, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255
+},
+{
+ 82, 74, 79, 95, 109, 128, 145, 160,
+ 173, 205, 205, 205, 224, 255, 255, 224,
+ 255, 224
+},
+{
+ 125, 74, 59, 69, 97, 141, 182, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255
+},
+{
+ 173, 115, 85, 73, 76, 92, 115, 145,
+ 173, 205, 224, 224, 255, 255, 255, 255,
+ 255, 255
+},
+{
+ 166, 134, 113, 102, 101, 102, 107, 118,
+ 125, 138, 145, 155, 166, 182, 192, 192,
+ 205, 150
+},
+{
+ 224, 182, 134, 101, 83, 79, 85, 97,
+ 120, 145, 173, 205, 224, 255, 255, 255,
+ 255, 255
+},
+{
+ 255, 224, 192, 150, 120, 101, 92, 89,
+ 93, 102, 118, 134, 160, 182, 192, 224,
+ 224, 224
+},
+{
+ 255, 224, 224, 182, 155, 134, 118, 109,
+ 104, 102, 106, 111, 118, 131, 145, 160,
+ 173, 131
+}
+};
+
+const opus_uint8 silk_rate_levels_iCDF[ 2 ][ 9 ] =
+{
+{
+ 241, 190, 178, 132, 87, 74, 41, 14,
+ 0
+},
+{
+ 223, 193, 157, 140, 106, 57, 39, 18,
+ 0
+}
+};
+
+const opus_uint8 silk_rate_levels_BITS_Q5[ 2 ][ 9 ] =
+{
+{
+ 131, 74, 141, 79, 80, 138, 95, 104,
+ 134
+},
+{
+ 95, 99, 91, 125, 93, 76, 123, 115,
+ 123
+}
+};
+
+const opus_uint8 silk_shell_code_table0[ 152 ] = {
+ 128, 0, 214, 42, 0, 235, 128, 21,
+ 0, 244, 184, 72, 11, 0, 248, 214,
+ 128, 42, 7, 0, 248, 225, 170, 80,
+ 25, 5, 0, 251, 236, 198, 126, 54,
+ 18, 3, 0, 250, 238, 211, 159, 82,
+ 35, 15, 5, 0, 250, 231, 203, 168,
+ 128, 88, 53, 25, 6, 0, 252, 238,
+ 216, 185, 148, 108, 71, 40, 18, 4,
+ 0, 253, 243, 225, 199, 166, 128, 90,
+ 57, 31, 13, 3, 0, 254, 246, 233,
+ 212, 183, 147, 109, 73, 44, 23, 10,
+ 2, 0, 255, 250, 240, 223, 198, 166,
+ 128, 90, 58, 33, 16, 6, 1, 0,
+ 255, 251, 244, 231, 210, 181, 146, 110,
+ 75, 46, 25, 12, 5, 1, 0, 255,
+ 253, 248, 238, 221, 196, 164, 128, 92,
+ 60, 35, 18, 8, 3, 1, 0, 255,
+ 253, 249, 242, 229, 208, 180, 146, 110,
+ 76, 48, 27, 14, 7, 3, 1, 0
+};
+
+const opus_uint8 silk_shell_code_table1[ 152 ] = {
+ 129, 0, 207, 50, 0, 236, 129, 20,
+ 0, 245, 185, 72, 10, 0, 249, 213,
+ 129, 42, 6, 0, 250, 226, 169, 87,
+ 27, 4, 0, 251, 233, 194, 130, 62,
+ 20, 4, 0, 250, 236, 207, 160, 99,
+ 47, 17, 3, 0, 255, 240, 217, 182,
+ 131, 81, 41, 11, 1, 0, 255, 254,
+ 233, 201, 159, 107, 61, 20, 2, 1,
+ 0, 255, 249, 233, 206, 170, 128, 86,
+ 50, 23, 7, 1, 0, 255, 250, 238,
+ 217, 186, 148, 108, 70, 39, 18, 6,
+ 1, 0, 255, 252, 243, 226, 200, 166,
+ 128, 90, 56, 30, 13, 4, 1, 0,
+ 255, 252, 245, 231, 209, 180, 146, 110,
+ 76, 47, 25, 11, 4, 1, 0, 255,
+ 253, 248, 237, 219, 194, 163, 128, 93,
+ 62, 37, 19, 8, 3, 1, 0, 255,
+ 254, 250, 241, 226, 205, 177, 145, 111,
+ 79, 51, 30, 15, 6, 2, 1, 0
+};
+
+const opus_uint8 silk_shell_code_table2[ 152 ] = {
+ 129, 0, 203, 54, 0, 234, 129, 23,
+ 0, 245, 184, 73, 10, 0, 250, 215,
+ 129, 41, 5, 0, 252, 232, 173, 86,
+ 24, 3, 0, 253, 240, 200, 129, 56,
+ 15, 2, 0, 253, 244, 217, 164, 94,
+ 38, 10, 1, 0, 253, 245, 226, 189,
+ 132, 71, 27, 7, 1, 0, 253, 246,
+ 231, 203, 159, 105, 56, 23, 6, 1,
+ 0, 255, 248, 235, 213, 179, 133, 85,
+ 47, 19, 5, 1, 0, 255, 254, 243,
+ 221, 194, 159, 117, 70, 37, 12, 2,
+ 1, 0, 255, 254, 248, 234, 208, 171,
+ 128, 85, 48, 22, 8, 2, 1, 0,
+ 255, 254, 250, 240, 220, 189, 149, 107,
+ 67, 36, 16, 6, 2, 1, 0, 255,
+ 254, 251, 243, 227, 201, 166, 128, 90,
+ 55, 29, 13, 5, 2, 1, 0, 255,
+ 254, 252, 246, 234, 213, 183, 147, 109,
+ 73, 43, 22, 10, 4, 2, 1, 0
+};
+
+const opus_uint8 silk_shell_code_table3[ 152 ] = {
+ 130, 0, 200, 58, 0, 231, 130, 26,
+ 0, 244, 184, 76, 12, 0, 249, 214,
+ 130, 43, 6, 0, 252, 232, 173, 87,
+ 24, 3, 0, 253, 241, 203, 131, 56,
+ 14, 2, 0, 254, 246, 221, 167, 94,
+ 35, 8, 1, 0, 254, 249, 232, 193,
+ 130, 65, 23, 5, 1, 0, 255, 251,
+ 239, 211, 162, 99, 45, 15, 4, 1,
+ 0, 255, 251, 243, 223, 186, 131, 74,
+ 33, 11, 3, 1, 0, 255, 252, 245,
+ 230, 202, 158, 105, 57, 24, 8, 2,
+ 1, 0, 255, 253, 247, 235, 214, 179,
+ 132, 84, 44, 19, 7, 2, 1, 0,
+ 255, 254, 250, 240, 223, 196, 159, 112,
+ 69, 36, 15, 6, 2, 1, 0, 255,
+ 254, 253, 245, 231, 209, 176, 136, 93,
+ 55, 27, 11, 3, 2, 1, 0, 255,
+ 254, 253, 252, 239, 221, 194, 158, 117,
+ 76, 42, 18, 4, 3, 2, 1, 0
+};
+
+const opus_uint8 silk_shell_code_table_offsets[ 17 ] = {
+ 0, 0, 2, 5, 9, 14, 20, 27,
+ 35, 44, 54, 65, 77, 90, 104, 119,
+ 135
+};
+
+const opus_uint8 silk_sign_iCDF[ 42 ] = {
+ 254, 49, 67, 77, 82, 93, 99,
+ 198, 11, 18, 24, 31, 36, 45,
+ 255, 46, 66, 78, 87, 94, 104,
+ 208, 14, 21, 32, 42, 51, 66,
+ 255, 94, 104, 109, 112, 115, 118,
+ 248, 53, 69, 80, 88, 95, 102
+};
diff --git a/drivers/opus/silk/tuning_parameters.h b/drivers/opus/silk/tuning_parameters.h
new file mode 100644
index 0000000000..e1057bbaae
--- /dev/null
+++ b/drivers/opus/silk/tuning_parameters.h
@@ -0,0 +1,171 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_TUNING_PARAMETERS_H
+#define SILK_TUNING_PARAMETERS_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Decay time for bitreservoir */
+#define BITRESERVOIR_DECAY_TIME_MS 500
+
+/*******************/
+/* Pitch estimator */
+/*******************/
+
+/* Level of noise floor for whitening filter LPC analysis in pitch analysis */
+#define FIND_PITCH_WHITE_NOISE_FRACTION 1e-3f
+
+/* Bandwidth expansion for whitening filter in pitch analysis */
+#define FIND_PITCH_BANDWIDTH_EXPANSION 0.99f
+
+/*********************/
+/* Linear prediction */
+/*********************/
+
+/* LPC analysis regularization */
+#define FIND_LPC_COND_FAC 1e-5f
+
+/* LTP analysis defines */
+#define FIND_LTP_COND_FAC 1e-5f
+#define LTP_DAMPING 0.05f
+#define LTP_SMOOTHING 0.1f
+
+/* LTP quantization settings */
+#define MU_LTP_QUANT_NB 0.03f
+#define MU_LTP_QUANT_MB 0.025f
+#define MU_LTP_QUANT_WB 0.02f
+
+/* Max cumulative LTP gain */
+#define MAX_SUM_LOG_GAIN_DB 250.0f
+
+/***********************/
+/* High pass filtering */
+/***********************/
+
+/* Smoothing parameters for low end of pitch frequency range estimation */
+#define VARIABLE_HP_SMTH_COEF1 0.1f
+#define VARIABLE_HP_SMTH_COEF2 0.015f
+#define VARIABLE_HP_MAX_DELTA_FREQ 0.4f
+
+/* Min and max cut-off frequency values (-3 dB points) */
+#define VARIABLE_HP_MIN_CUTOFF_HZ 60
+#define VARIABLE_HP_MAX_CUTOFF_HZ 100
+
+/***********/
+/* Various */
+/***********/
+
+/* VAD threshold */
+#define SPEECH_ACTIVITY_DTX_THRES 0.05f
+
+/* Speech Activity LBRR enable threshold */
+#define LBRR_SPEECH_ACTIVITY_THRES 0.3f
+
+/*************************/
+/* Perceptual parameters */
+/*************************/
+
+/* reduction in coding SNR during low speech activity */
+#define BG_SNR_DECR_dB 2.0f
+
+/* factor for reducing quantization noise during voiced speech */
+#define HARM_SNR_INCR_dB 2.0f
+
+/* factor for reducing quantization noise for unvoiced sparse signals */
+#define SPARSE_SNR_INCR_dB 2.0f
+
+/* threshold for sparseness measure above which to use lower quantization offset during unvoiced */
+#define SPARSENESS_THRESHOLD_QNT_OFFSET 0.75f
+
+/* warping control */
+#define WARPING_MULTIPLIER 0.015f
+
+/* fraction added to first autocorrelation value */
+#define SHAPE_WHITE_NOISE_FRACTION 5e-5f
+
+/* noise shaping filter chirp factor */
+#define BANDWIDTH_EXPANSION 0.95f
+
+/* difference between chirp factors for analysis and synthesis noise shaping filters at low bitrates */
+#define LOW_RATE_BANDWIDTH_EXPANSION_DELTA 0.01f
+
+/* extra harmonic boosting (signal shaping) at low bitrates */
+#define LOW_RATE_HARMONIC_BOOST 0.1f
+
+/* extra harmonic boosting (signal shaping) for noisy input signals */
+#define LOW_INPUT_QUALITY_HARMONIC_BOOST 0.1f
+
+/* harmonic noise shaping */
+#define HARMONIC_SHAPING 0.3f
+
+/* extra harmonic noise shaping for high bitrates or noisy input */
+#define HIGH_RATE_OR_LOW_QUALITY_HARMONIC_SHAPING 0.2f
+
+/* parameter for shaping noise towards higher frequencies */
+#define HP_NOISE_COEF 0.25f
+
+/* parameter for shaping noise even more towards higher frequencies during voiced speech */
+#define HARM_HP_NOISE_COEF 0.35f
+
+/* parameter for applying a high-pass tilt to the input signal */
+#define INPUT_TILT 0.05f
+
+/* parameter for extra high-pass tilt to the input signal at high rates */
+#define HIGH_RATE_INPUT_TILT 0.1f
+
+/* parameter for reducing noise at the very low frequencies */
+#define LOW_FREQ_SHAPING 4.0f
+
+/* less reduction of noise at the very low frequencies for signals with low SNR at low frequencies */
+#define LOW_QUALITY_LOW_FREQ_SHAPING_DECR 0.5f
+
+/* subframe smoothing coefficient for HarmBoost, HarmShapeGain, Tilt (lower -> more smoothing) */
+#define SUBFR_SMTH_COEF 0.4f
+
+/* parameters defining the R/D tradeoff in the residual quantizer */
+#define LAMBDA_OFFSET 1.2f
+#define LAMBDA_SPEECH_ACT -0.2f
+#define LAMBDA_DELAYED_DECISIONS -0.05f
+#define LAMBDA_INPUT_QUALITY -0.1f
+#define LAMBDA_CODING_QUALITY -0.2f
+#define LAMBDA_QUANT_OFFSET 0.8f
+
+/* Compensation in bitrate calculations for 10 ms modes */
+#define REDUCE_BITRATE_10_MS_BPS 2200
+
+/* Maximum time before allowing a bandwidth transition */
+#define MAX_BANDWIDTH_SWITCH_DELAY_MS 5000
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SILK_TUNING_PARAMETERS_H */
diff --git a/drivers/opus/silk/typedef.h b/drivers/opus/silk/typedef.h
new file mode 100644
index 0000000000..3e193b4a45
--- /dev/null
+++ b/drivers/opus/silk/typedef.h
@@ -0,0 +1,78 @@
+/***********************************************************************
+Copyright (c) 2006-2011, Skype Limited. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+- Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+- Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+- Neither the name of Internet Society, IETF or IETF Trust, nor the
+names of specific contributors, may be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+***********************************************************************/
+
+#ifndef SILK_TYPEDEF_H
+#define SILK_TYPEDEF_H
+
+#include "opus/opus_types.h"
+#include "opus/opus_defines.h"
+
+#ifndef OPUS_FIXED_POINT
+# include <float.h>
+# define silk_float float
+# define silk_float_MAX FLT_MAX
+#endif
+
+#define silk_int64_MAX ((opus_int64)0x7FFFFFFFFFFFFFFFLL) /* 2^63 - 1 */
+#define silk_int64_MIN ((opus_int64)0x8000000000000000LL) /* -2^63 */
+#define silk_int32_MAX 0x7FFFFFFF /* 2^31 - 1 = 2147483647 */
+#define silk_int32_MIN ((opus_int32)0x80000000) /* -2^31 = -2147483648 */
+#define silk_int16_MAX 0x7FFF /* 2^15 - 1 = 32767 */
+#define silk_int16_MIN ((opus_int16)0x8000) /* -2^15 = -32768 */
+#define silk_int8_MAX 0x7F /* 2^7 - 1 = 127 */
+#define silk_int8_MIN ((opus_int8)0x80) /* -2^7 = -128 */
+#define silk_uint8_MAX 0xFF /* 2^8 - 1 = 255 */
+
+#define silk_TRUE 1
+#define silk_FALSE 0
+
+/* assertions */
+#if (defined _WIN32 && !defined _WINCE && !defined(__GNUC__) && !defined(NO_ASSERTS))
+# ifndef silk_assert
+# include <crtdbg.h> /* ASSERTE() */
+# define silk_assert(COND) _ASSERTE(COND)
+# endif
+#else
+# ifdef ENABLE_ASSERTIONS
+# include <stdio.h>
+# include <stdlib.h>
+#define silk_fatal(str) _silk_fatal(str, __FILE__, __LINE__);
+#ifdef __GNUC__
+__attribute__((noreturn))
+#endif
+static OPUS_INLINE void _silk_fatal(const char *str, const char *file, int line)
+{
+ fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str);
+ abort();
+}
+# define silk_assert(COND) {if (!(COND)) {silk_fatal("assertion failed: " #COND);}}
+# else
+# define silk_assert(COND)
+# endif
+#endif
+
+#endif /* SILK_TYPEDEF_H */
diff --git a/drivers/opus/stream.c b/drivers/opus/stream.c
new file mode 100644
index 0000000000..8dd23e88e7
--- /dev/null
+++ b/drivers/opus/stream.c
@@ -0,0 +1,366 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 1994-2012 *
+ * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: stdio-based convenience library for opening/seeking/decoding
+ last mod: $Id: vorbisfile.c 17573 2010-10-27 14:53:59Z xiphmont $
+
+ ********************************************************************/
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/internal.h"
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#if defined(_WIN32)
+# include <io.h>
+#endif
+
+typedef struct OpusMemStream OpusMemStream;
+
+#define OP_MEM_SIZE_MAX (~(size_t)0>>1)
+#define OP_MEM_DIFF_MAX ((ptrdiff_t)OP_MEM_SIZE_MAX)
+
+/*The context information needed to read from a block of memory as if it were a
+ file.*/
+struct OpusMemStream{
+ /*The block of memory to read from.*/
+ const unsigned char *data;
+ /*The total size of the block.
+ This must be at most OP_MEM_SIZE_MAX to prevent signed overflow while
+ seeking.*/
+ ptrdiff_t size;
+ /*The current file position.
+ This is allowed to be set arbitrarily greater than size (i.e., past the end
+ of the block, though we will not read data past the end of the block), but
+ is not allowed to be negative (i.e., before the beginning of the block).*/
+ ptrdiff_t pos;
+};
+
+static int op_fread(void *_stream,unsigned char *_ptr,int _buf_size){
+ FILE *stream;
+ size_t ret;
+ /*Check for empty read.*/
+ if(_buf_size<=0)return 0;
+ stream=(FILE *)_stream;
+ ret=fread(_ptr,1,_buf_size,stream);
+ OP_ASSERT(ret<=(size_t)_buf_size);
+ /*If ret==0 and !feof(stream), there was a read error.*/
+ return ret>0||feof(stream)?(int)ret:OP_EREAD;
+}
+
+static int op_fseek(void *_stream,opus_int64 _offset,int _whence){
+#if defined(_WIN32)
+ /*_fseeki64() is not exposed until MSCVCRT80.
+ This is the default starting with MSVC 2005 (_MSC_VER>=1400), but we want
+ to allow linking against older MSVCRT versions for compatibility back to
+ XP without installing extra runtime libraries.
+ i686-pc-mingw32 does not have fseeko() and requires
+ __MSVCRT_VERSION__>=0x800 for _fseeki64(), which screws up linking with
+ other libraries (that don't use MSVCRT80 from MSVC 2005 by default).
+ i686-w64-mingw32 does have fseeko() and respects _FILE_OFFSET_BITS, but I
+ don't know how to detect that at compile time.
+ We could just use fseeko64() (which is available in both), but its
+ implemented using fgetpos()/fsetpos() just like this code, except without
+ the overflow checking, so we prefer our version.*/
+ opus_int64 pos;
+ /*We don't use fpos_t directly because it might be a struct if __STDC__ is
+ non-zero or _INTEGRAL_MAX_BITS < 64.
+ I'm not certain when the latter is true, but someone could in theory set
+ the former.
+ Either way, it should be binary compatible with a normal 64-bit int (this
+ assumption is not portable, but I believe it is true for MSVCRT).*/
+ OP_ASSERT(sizeof(pos)==sizeof(fpos_t));
+ /*Translate the seek to an absolute one.*/
+ if(_whence==SEEK_CUR){
+ int ret;
+ ret=fgetpos((FILE *)_stream,(fpos_t *)&pos);
+ if(ret)return ret;
+ }
+ else if(_whence==SEEK_END)pos=_filelengthi64(_fileno((FILE *)_stream));
+ else if(_whence==SEEK_SET)pos=0;
+ else return -1;
+ /*Check for errors or overflow.*/
+ if(pos<0||_offset<-pos||_offset>OP_INT64_MAX-pos)return -1;
+ pos+=_offset;
+ return fsetpos((FILE *)_stream,(fpos_t *)&pos);
+#else
+ /*This function actually conforms to the SUSv2 and POSIX.1-2001, so we prefer
+ it except on Windows.*/
+ return fseeko((FILE *)_stream,(off_t)_offset,_whence);
+#endif
+}
+
+static opus_int64 op_ftell(void *_stream){
+#if defined(_WIN32)
+ /*_ftelli64() is not exposed until MSCVCRT80, and ftello()/ftello64() have
+ the same problems as fseeko()/fseeko64() in MingW.
+ See above for a more detailed explanation.*/
+ opus_int64 pos;
+ OP_ASSERT(sizeof(pos)==sizeof(fpos_t));
+ return fgetpos((FILE *)_stream,(fpos_t *)&pos)?-1:pos;
+#else
+ /*This function actually conforms to the SUSv2 and POSIX.1-2001, so we prefer
+ it except on Windows.*/
+ return ftello((FILE *)_stream);
+#endif
+}
+
+static const OpusFileCallbacks OP_FILE_CALLBACKS={
+ op_fread,
+ op_fseek,
+ op_ftell,
+ (op_close_func)fclose
+};
+
+#if defined(_WIN32)
+# include <stddef.h>
+# include <errno.h>
+
+/*Windows doesn't accept UTF-8 by default, and we don't have a wchar_t API,
+ so if we just pass the path to fopen(), then there'd be no way for a user
+ of our API to open a Unicode filename.
+ Instead, we translate from UTF-8 to UTF-16 and use Windows' wchar_t API.
+ This makes this API more consistent with platforms where the character set
+ used by fopen is the same as used on disk, which is generally UTF-8, and
+ with our metadata API, which always uses UTF-8.*/
+static wchar_t *op_utf8_to_utf16(const char *_src){
+ wchar_t *dst;
+ size_t len;
+ len=strlen(_src);
+ /*Worst-case output is 1 wide character per 1 input character.*/
+ dst=(wchar_t *)_ogg_malloc(sizeof(*dst)*(len+1));
+ if(dst!=NULL){
+ size_t si;
+ size_t di;
+ for(di=si=0;si<len;si++){
+ int c0;
+ c0=(unsigned char)_src[si];
+ if(!(c0&0x80)){
+ /*Start byte says this is a 1-byte sequence.*/
+ dst[di++]=(wchar_t)c0;
+ continue;
+ }
+ else{
+ int c1;
+ /*This is safe, because c0 was not 0 and _src is NUL-terminated.*/
+ c1=(unsigned char)_src[si+1];
+ if((c1&0xC0)==0x80){
+ /*Found at least one continuation byte.*/
+ if((c0&0xE0)==0xC0){
+ wchar_t w;
+ /*Start byte says this is a 2-byte sequence.*/
+ w=(c0&0x1F)<<6|c1&0x3F;
+ if(w>=0x80U){
+ /*This is a 2-byte sequence that is not overlong.*/
+ dst[di++]=w;
+ si++;
+ continue;
+ }
+ }
+ else{
+ int c2;
+ /*This is safe, because c1 was not 0 and _src is NUL-terminated.*/
+ c2=(unsigned char)_src[si+2];
+ if((c2&0xC0)==0x80){
+ /*Found at least two continuation bytes.*/
+ if((c0&0xF0)==0xE0){
+ wchar_t w;
+ /*Start byte says this is a 3-byte sequence.*/
+ w=(c0&0xF)<<12|(c1&0x3F)<<6|c2&0x3F;
+ if(w>=0x800U&&(w<0xD800||w>=0xE000)&&w<0xFFFE){
+ /*This is a 3-byte sequence that is not overlong, not a
+ UTF-16 surrogate pair value, and not a 'not a character'
+ value.*/
+ dst[di++]=w;
+ si+=2;
+ continue;
+ }
+ }
+ else{
+ int c3;
+ /*This is safe, because c2 was not 0 and _src is
+ NUL-terminated.*/
+ c3=(unsigned char)_src[si+3];
+ if((c3&0xC0)==0x80){
+ /*Found at least three continuation bytes.*/
+ if((c0&0xF8)==0xF0){
+ opus_uint32 w;
+ /*Start byte says this is a 4-byte sequence.*/
+ w=(c0&7)<<18|(c1&0x3F)<<12|(c2&0x3F)<<6&(c3&0x3F);
+ if(w>=0x10000U&&w<0x110000U){
+ /*This is a 4-byte sequence that is not overlong and not
+ greater than the largest valid Unicode code point.
+ Convert it to a surrogate pair.*/
+ w-=0x10000;
+ dst[di++]=(wchar_t)(0xD800+(w>>10));
+ dst[di++]=(wchar_t)(0xDC00+(w&0x3FF));
+ si+=3;
+ continue;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ /*If we got here, we encountered an illegal UTF-8 sequence.*/
+ _ogg_free(dst);
+ return NULL;
+ }
+ OP_ASSERT(di<=len);
+ dst[di]='\0';
+ }
+ return dst;
+}
+
+#endif
+
+void *op_fopen(OpusFileCallbacks *_cb,const char *_path,const char *_mode){
+ FILE *fp;
+#if !defined(_WIN32)
+ fp=fopen(_path,_mode);
+#else
+ fp=NULL;
+ if(_path==NULL||_mode==NULL)errno=EINVAL;
+ else{
+ wchar_t *wpath;
+ wchar_t *wmode;
+ wpath=op_utf8_to_utf16(_path);
+ wmode=op_utf8_to_utf16(_mode);
+ if(wmode==NULL)errno=EINVAL;
+ else if(wpath==NULL)errno=ENOENT;
+ else fp=_wfopen(wpath,wmode);
+ _ogg_free(wmode);
+ _ogg_free(wpath);
+ }
+#endif
+ if(fp!=NULL)*_cb=*&OP_FILE_CALLBACKS;
+ return fp;
+}
+
+void *op_fdopen(OpusFileCallbacks *_cb,int _fd,const char *_mode){
+ FILE *fp;
+ fp=fdopen(_fd,_mode);
+ if(fp!=NULL)*_cb=*&OP_FILE_CALLBACKS;
+ return fp;
+}
+
+void *op_freopen(OpusFileCallbacks *_cb,const char *_path,const char *_mode,
+ void *_stream){
+ FILE *fp;
+#if !defined(_WIN32)
+ fp=freopen(_path,_mode,(FILE *)_stream);
+#else
+ fp=NULL;
+ if(_path==NULL||_mode==NULL)errno=EINVAL;
+ else{
+ wchar_t *wpath;
+ wchar_t *wmode;
+ wpath=op_utf8_to_utf16(_path);
+ wmode=op_utf8_to_utf16(_mode);
+ if(wmode==NULL)errno=EINVAL;
+ else if(wpath==NULL)errno=ENOENT;
+ else fp=_wfreopen(wpath,wmode,(FILE *)_stream);
+ _ogg_free(wmode);
+ _ogg_free(wpath);
+ }
+#endif
+ if(fp!=NULL)*_cb=*&OP_FILE_CALLBACKS;
+ return fp;
+}
+
+static int op_mem_read(void *_stream,unsigned char *_ptr,int _buf_size){
+ OpusMemStream *stream;
+ ptrdiff_t size;
+ ptrdiff_t pos;
+ stream=(OpusMemStream *)_stream;
+ /*Check for empty read.*/
+ if(_buf_size<=0)return 0;
+ size=stream->size;
+ pos=stream->pos;
+ /*Check for EOF.*/
+ if(pos>=size)return 0;
+ /*Check for a short read.*/
+ _buf_size=(int)OP_MIN(size-pos,_buf_size);
+ memcpy(_ptr,stream->data+pos,_buf_size);
+ pos+=_buf_size;
+ stream->pos=pos;
+ return _buf_size;
+}
+
+static int op_mem_seek(void *_stream,opus_int64 _offset,int _whence){
+ OpusMemStream *stream;
+ ptrdiff_t pos;
+ stream=(OpusMemStream *)_stream;
+ pos=stream->pos;
+ OP_ASSERT(pos>=0);
+ switch(_whence){
+ case SEEK_SET:{
+ /*Check for overflow:*/
+ if(_offset<0||_offset>OP_MEM_DIFF_MAX)return -1;
+ pos=(ptrdiff_t)_offset;
+ }break;
+ case SEEK_CUR:{
+ /*Check for overflow:*/
+ if(_offset<-pos||_offset>OP_MEM_DIFF_MAX-pos)return -1;
+ pos=(ptrdiff_t)(pos+_offset);
+ }break;
+ case SEEK_END:{
+ ptrdiff_t size;
+ size=stream->size;
+ OP_ASSERT(size>=0);
+ /*Check for overflow:*/
+ if(_offset>size||_offset<size-OP_MEM_DIFF_MAX)return -1;
+ pos=(ptrdiff_t)(size-_offset);
+ }break;
+ default:return -1;
+ }
+ stream->pos=pos;
+ return 0;
+}
+
+static opus_int64 op_mem_tell(void *_stream){
+ OpusMemStream *stream;
+ stream=(OpusMemStream *)_stream;
+ return (ogg_int64_t)stream->pos;
+}
+
+static int op_mem_close(void *_stream){
+ _ogg_free(_stream);
+ return 0;
+}
+
+static const OpusFileCallbacks OP_MEM_CALLBACKS={
+ op_mem_read,
+ op_mem_seek,
+ op_mem_tell,
+ op_mem_close
+};
+
+void *op_mem_stream_create(OpusFileCallbacks *_cb,
+ const unsigned char *_data,size_t _size){
+ OpusMemStream *stream;
+ if(_size>OP_MEM_SIZE_MAX)return NULL;
+ stream=(OpusMemStream *)_ogg_malloc(sizeof(*stream));
+ if(stream!=NULL){
+ *_cb=*&OP_MEM_CALLBACKS;
+ stream->data=_data;
+ stream->size=_size;
+ stream->pos=0;
+ }
+ return stream;
+}
diff --git a/drivers/opus/tansig_table.h b/drivers/opus/tansig_table.h
new file mode 100644
index 0000000000..c76f844a72
--- /dev/null
+++ b/drivers/opus/tansig_table.h
@@ -0,0 +1,45 @@
+/* This file is auto-generated by gen_tables */
+
+static const float tansig_table[201] = {
+0.000000f, 0.039979f, 0.079830f, 0.119427f, 0.158649f,
+0.197375f, 0.235496f, 0.272905f, 0.309507f, 0.345214f,
+0.379949f, 0.413644f, 0.446244f, 0.477700f, 0.507977f,
+0.537050f, 0.564900f, 0.591519f, 0.616909f, 0.641077f,
+0.664037f, 0.685809f, 0.706419f, 0.725897f, 0.744277f,
+0.761594f, 0.777888f, 0.793199f, 0.807569f, 0.821040f,
+0.833655f, 0.845456f, 0.856485f, 0.866784f, 0.876393f,
+0.885352f, 0.893698f, 0.901468f, 0.908698f, 0.915420f,
+0.921669f, 0.927473f, 0.932862f, 0.937863f, 0.942503f,
+0.946806f, 0.950795f, 0.954492f, 0.957917f, 0.961090f,
+0.964028f, 0.966747f, 0.969265f, 0.971594f, 0.973749f,
+0.975743f, 0.977587f, 0.979293f, 0.980869f, 0.982327f,
+0.983675f, 0.984921f, 0.986072f, 0.987136f, 0.988119f,
+0.989027f, 0.989867f, 0.990642f, 0.991359f, 0.992020f,
+0.992631f, 0.993196f, 0.993718f, 0.994199f, 0.994644f,
+0.995055f, 0.995434f, 0.995784f, 0.996108f, 0.996407f,
+0.996682f, 0.996937f, 0.997172f, 0.997389f, 0.997590f,
+0.997775f, 0.997946f, 0.998104f, 0.998249f, 0.998384f,
+0.998508f, 0.998623f, 0.998728f, 0.998826f, 0.998916f,
+0.999000f, 0.999076f, 0.999147f, 0.999213f, 0.999273f,
+0.999329f, 0.999381f, 0.999428f, 0.999472f, 0.999513f,
+0.999550f, 0.999585f, 0.999617f, 0.999646f, 0.999673f,
+0.999699f, 0.999722f, 0.999743f, 0.999763f, 0.999781f,
+0.999798f, 0.999813f, 0.999828f, 0.999841f, 0.999853f,
+0.999865f, 0.999875f, 0.999885f, 0.999893f, 0.999902f,
+0.999909f, 0.999916f, 0.999923f, 0.999929f, 0.999934f,
+0.999939f, 0.999944f, 0.999948f, 0.999952f, 0.999956f,
+0.999959f, 0.999962f, 0.999965f, 0.999968f, 0.999970f,
+0.999973f, 0.999975f, 0.999977f, 0.999978f, 0.999980f,
+0.999982f, 0.999983f, 0.999984f, 0.999986f, 0.999987f,
+0.999988f, 0.999989f, 0.999990f, 0.999990f, 0.999991f,
+0.999992f, 0.999992f, 0.999993f, 0.999994f, 0.999994f,
+0.999994f, 0.999995f, 0.999995f, 0.999996f, 0.999996f,
+0.999996f, 0.999997f, 0.999997f, 0.999997f, 0.999997f,
+0.999997f, 0.999998f, 0.999998f, 0.999998f, 0.999998f,
+0.999998f, 0.999998f, 0.999999f, 0.999999f, 0.999999f,
+0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f,
+0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f,
+1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
+1.000000f,
+};
diff --git a/drivers/opus/wincerts.c b/drivers/opus/wincerts.c
new file mode 100644
index 0000000000..2a04eab6d1
--- /dev/null
+++ b/drivers/opus/wincerts.c
@@ -0,0 +1,171 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2013 *
+ * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
+ * *
+ ********************************************************************/
+
+/*This should really be part of OpenSSL, but there's been a patch [1] sitting
+ in their bugtracker for over two years that implements this, without any
+ action, so I'm giving up and re-implementing it locally.
+
+ [1] <http://rt.openssl.org/Ticket/Display.html?id=2158>*/
+
+#ifdef OPUS_ENABLED
+#include "opus/opus_config.h"
+#endif
+
+#include "opus/internal.h"
+#if defined(OP_ENABLE_HTTP)&&defined(_WIN32)
+/*You must include windows.h before wincrypt.h and x509.h.*/
+# define WIN32_LEAN_AND_MEAN
+# define WIN32_EXTRA_LEAN
+# include <windows.h>
+/*You must include wincrypt.h before x509.h, too, or X509_NAME doesn't get
+ defined properly.*/
+# include <wincrypt.h>
+# include <openssl/ssl.h>
+# include <openssl/err.h>
+# include <openssl/x509.h>
+
+static int op_capi_new(X509_LOOKUP *_lu){
+ HCERTSTORE h_store;
+ h_store=CertOpenStore(CERT_STORE_PROV_SYSTEM_A,0,0,
+ CERT_STORE_OPEN_EXISTING_FLAG|CERT_STORE_READONLY_FLAG|
+ CERT_SYSTEM_STORE_CURRENT_USER|CERT_STORE_SHARE_CONTEXT_FLAG,"ROOT");
+ if(h_store!=NULL){
+ _lu->method_data=(char *)h_store;
+ return 1;
+ }
+ return 0;
+}
+
+static void op_capi_free(X509_LOOKUP *_lu){
+ HCERTSTORE h_store;
+ h_store=(HCERTSTORE)_lu->method_data;
+# if defined(OP_ENABLE_ASSERTIONS)
+ OP_ALWAYS_TRUE(CertCloseStore(h_store,CERT_CLOSE_STORE_CHECK_FLAG));
+# else
+ CertCloseStore(h_store,0);
+# endif
+}
+
+static int op_capi_retrieve_by_subject(X509_LOOKUP *_lu,int _type,
+ X509_NAME *_name,X509_OBJECT *_ret){
+ X509_OBJECT *obj;
+ CRYPTO_w_lock(CRYPTO_LOCK_X509_STORE);
+ obj=X509_OBJECT_retrieve_by_subject(_lu->store_ctx->objs,_type,_name);
+ CRYPTO_w_unlock(CRYPTO_LOCK_X509_STORE);
+ if(obj!=NULL){
+ _ret->type=obj->type;
+ memcpy(&_ret->data,&obj->data,sizeof(_ret->data));
+ return 1;
+ }
+ return 0;
+}
+
+static int op_capi_get_by_subject(X509_LOOKUP *_lu,int _type,X509_NAME *_name,
+ X509_OBJECT *_ret){
+ HCERTSTORE h_store;
+ if(_name==NULL)return 0;
+ if(_name->bytes==NULL||_name->bytes->length<=0||_name->modified){
+ if(i2d_X509_NAME(_name,NULL)<0)return 0;
+ OP_ASSERT(_name->bytes->length>0);
+ }
+ h_store=(HCERTSTORE)_lu->method_data;
+ switch(_type){
+ case X509_LU_X509:{
+ CERT_NAME_BLOB find_para;
+ PCCERT_CONTEXT cert;
+ X509 *x;
+ int ret;
+ /*Although X509_NAME contains a canon_enc field, that "canonical" [1]
+ encoding was just made up by OpenSSL.
+ It doesn't correspond to any actual standard, and since it drops the
+ initial sequence header, won't be recognized by the Crypto API.
+ The assumption here is that CertFindCertificateInStore() will allow any
+ appropriate variations in the encoding when it does its comparison.
+ This is, however, emphatically not true under Wine, which just compares
+ the encodings with memcmp().
+ Most of the time things work anyway, though, and there isn't really
+ anything we can do to make the situation better.
+
+ [1] A "canonical form" is defined as the one where, if you locked 10
+ mathematicians in a room and asked them to come up with a
+ representation for something, it's the answer that 9 of them would
+ give you back.
+ I don't think OpenSSL's encoding qualifies.*/
+ find_para.cbData=_name->bytes->length;
+ find_para.pbData=(unsigned char *)_name->bytes->data;
+ cert=CertFindCertificateInStore(h_store,X509_ASN_ENCODING,0,
+ CERT_FIND_SUBJECT_NAME,&find_para,NULL);
+ if(cert==NULL)return 0;
+ x=d2i_X509(NULL,(const unsigned char **)&cert->pbCertEncoded,
+ cert->cbCertEncoded);
+ CertFreeCertificateContext(cert);
+ if(x==NULL)return 0;
+ ret=X509_STORE_add_cert(_lu->store_ctx,x);
+ X509_free(x);
+ if(ret)return op_capi_retrieve_by_subject(_lu,_type,_name,_ret);
+ }break;
+ case X509_LU_CRL:{
+ CERT_INFO cert_info;
+ CERT_CONTEXT find_para;
+ PCCRL_CONTEXT crl;
+ X509_CRL *x;
+ int ret;
+ ret=op_capi_retrieve_by_subject(_lu,_type,_name,_ret);
+ if(ret>0)return ret;
+ memset(&cert_info,0,sizeof(cert_info));
+ cert_info.Issuer.cbData=_name->bytes->length;
+ cert_info.Issuer.pbData=(unsigned char *)_name->bytes->data;
+ memset(&find_para,0,sizeof(find_para));
+ find_para.pCertInfo=&cert_info;
+ crl=CertFindCRLInStore(h_store,0,0,CRL_FIND_ISSUED_BY,&find_para,NULL);
+ if(crl==NULL)return 0;
+ x=d2i_X509_CRL(NULL,(const unsigned char **)&crl->pbCrlEncoded,
+ crl->cbCrlEncoded);
+ CertFreeCRLContext(crl);
+ if(x==NULL)return 0;
+ ret=X509_STORE_add_crl(_lu->store_ctx,x);
+ X509_CRL_free(x);
+ if(ret)return op_capi_retrieve_by_subject(_lu,_type,_name,_ret);
+ }break;
+ }
+ return 0;
+}
+
+/*This is not const because OpenSSL doesn't allow it, even though it won't
+ write to it.*/
+static X509_LOOKUP_METHOD X509_LOOKUP_CAPI={
+ "Load Crypto API store into cache",
+ op_capi_new,
+ op_capi_free,
+ NULL,
+ NULL,
+ NULL,
+ op_capi_get_by_subject,
+ NULL,
+ NULL,
+ NULL
+};
+
+int SSL_CTX_set_default_verify_paths_win32(SSL_CTX *_ssl_ctx){
+ X509_STORE *store;
+ X509_LOOKUP *lu;
+ /*We intentionally do not add the normal default paths, as they are usually
+ wrong, and are just asking to be used as an exploit vector.*/
+ store=SSL_CTX_get_cert_store(_ssl_ctx);
+ OP_ASSERT(store!=NULL);
+ lu=X509_STORE_add_lookup(store,&X509_LOOKUP_CAPI);
+ if(lu==NULL)return 0;
+ ERR_clear_error();
+ return 1;
+}
+
+#endif
diff --git a/drivers/opus/winerrno.h b/drivers/opus/winerrno.h
new file mode 100644
index 0000000000..32a90b4ee1
--- /dev/null
+++ b/drivers/opus/winerrno.h
@@ -0,0 +1,90 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE libopusfile SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
+ * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
+ * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
+ * *
+ * THE libopusfile SOURCE CODE IS (C) COPYRIGHT 2012 *
+ * by the Xiph.Org Foundation and contributors http://www.xiph.org/ *
+ * *
+ ********************************************************************/
+#if !defined(_opusfile_winerrno_h)
+# define _opusfile_winerrno_h (1)
+
+# include <errno.h>
+# include <winerror.h>
+
+/*These conflict with the MSVC errno.h definitions, but we don't need to use
+ the original ones in any file that deals with sockets.
+ We could map the WSA errors to the errno.h ones (most of which are only
+ available on sufficiently new versions of MSVC), but they aren't ordered the
+ same, and given how rarely we actually look at the values, I don't think
+ it's worth a lookup table.*/
+# undef EWOULDBLOCK
+# undef EINPROGRESS
+# undef EALREADY
+# undef ENOTSOCK
+# undef EDESTADDRREQ
+# undef EMSGSIZE
+# undef EPROTOTYPE
+# undef ENOPROTOOPT
+# undef EPROTONOSUPPORT
+# undef EOPNOTSUPP
+# undef EAFNOSUPPORT
+# undef EADDRINUSE
+# undef EADDRNOTAVAIL
+# undef ENETDOWN
+# undef ENETUNREACH
+# undef ENETRESET
+# undef ECONNABORTED
+# undef ECONNRESET
+# undef ENOBUFS
+# undef EISCONN
+# undef ENOTCONN
+# undef ETIMEDOUT
+# undef ECONNREFUSED
+# undef ELOOP
+# undef ENAMETOOLONG
+# undef EHOSTUNREACH
+# undef ENOTEMPTY
+
+# define EWOULDBLOCK (WSAEWOULDBLOCK-WSABASEERR)
+# define EINPROGRESS (WSAEINPROGRESS-WSABASEERR)
+# define EALREADY (WSAEALREADY-WSABASEERR)
+# define ENOTSOCK (WSAENOTSOCK-WSABASEERR)
+# define EDESTADDRREQ (WSAEDESTADDRREQ-WSABASEERR)
+# define EMSGSIZE (WSAEMSGSIZE-WSABASEERR)
+# define EPROTOTYPE (WSAEPROTOTYPE-WSABASEERR)
+# define ENOPROTOOPT (WSAENOPROTOOPT-WSABASEERR)
+# define EPROTONOSUPPORT (WSAEPROTONOSUPPORT-WSABASEERR)
+# define ESOCKTNOSUPPORT (WSAESOCKTNOSUPPORT-WSABASEERR)
+# define EOPNOTSUPP (WSAEOPNOTSUPP-WSABASEERR)
+# define EPFNOSUPPORT (WSAEPFNOSUPPORT-WSABASEERR)
+# define EAFNOSUPPORT (WSAEAFNOSUPPORT-WSABASEERR)
+# define EADDRINUSE (WSAEADDRINUSE-WSABASEERR)
+# define EADDRNOTAVAIL (WSAEADDRNOTAVAIL-WSABASEERR)
+# define ENETDOWN (WSAENETDOWN-WSABASEERR)
+# define ENETUNREACH (WSAENETUNREACH-WSABASEERR)
+# define ENETRESET (WSAENETRESET-WSABASEERR)
+# define ECONNABORTED (WSAECONNABORTED-WSABASEERR)
+# define ECONNRESET (WSAECONNRESET-WSABASEERR)
+# define ENOBUFS (WSAENOBUFS-WSABASEERR)
+# define EISCONN (WSAEISCONN-WSABASEERR)
+# define ENOTCONN (WSAENOTCONN-WSABASEERR)
+# define ESHUTDOWN (WSAESHUTDOWN-WSABASEERR)
+# define ETOOMANYREFS (WSAETOOMANYREFS-WSABASEERR)
+# define ETIMEDOUT (WSAETIMEDOUT-WSABASEERR)
+# define ECONNREFUSED (WSAECONNREFUSED-WSABASEERR)
+# define ELOOP (WSAELOOP-WSABASEERR)
+# define ENAMETOOLONG (WSAENAMETOOLONG-WSABASEERR)
+# define EHOSTDOWN (WSAEHOSTDOWN-WSABASEERR)
+# define EHOSTUNREACH (WSAEHOSTUNREACH-WSABASEERR)
+# define ENOTEMPTY (WSAENOTEMPTY-WSABASEERR)
+# define EPROCLIM (WSAEPROCLIM-WSABASEERR)
+# define EUSERS (WSAEUSERS-WSABASEERR)
+# define EDQUOT (WSAEDQUOT-WSABASEERR)
+# define ESTALE (WSAESTALE-WSABASEERR)
+# define EREMOTE (WSAEREMOTE-WSABASEERR)
+
+#endif
diff --git a/drivers/png/SCsub b/drivers/png/SCsub
index c3919567bc..5532e28ade 100644
--- a/drivers/png/SCsub
+++ b/drivers/png/SCsub
@@ -23,16 +23,21 @@ png_sources = [
]
if ("neon_enabled" in env and env["neon_enabled"]):
+ env.Append(CPPFLAGS=["-DPNG_ARM_NEON_OPT=2"])
env_neon = env.Clone();
if "S_compiler" in env:
env_neon['CC'] = env['S_compiler']
- env_neon.Append(CPPFLAGS=["-DPNG_ARM_NEON"])
- png_sources.append(env_neon.Object("#drivers/png/filter_neon.S"))
-
+ #env_neon.Append(CPPFLAGS=["-DPNG_ARM_NEON"])
+ import os
+ # Currently .ASM filter_neon.S does not compile on NT.
+ if (os.name!="nt"):
+ png_sources.append(env_neon.Object("#drivers/png/arm/arm_init.c"))
+ png_sources.append(env_neon.Object("#drivers/png/arm/filter_neon.S"))
+else:
+ env.Append(CPPFLAGS=["-DPNG_ARM_NEON_OPT=0"])
env.drivers_sources+=png_sources
#env.add_source_files(env.drivers_sources, png_sources)
Export('env')
-
diff --git a/drivers/png/arm/arm_init.c b/drivers/png/arm/arm_init.c
new file mode 100644
index 0000000000..6a6a019acb
--- /dev/null
+++ b/drivers/png/arm/arm_init.c
@@ -0,0 +1,232 @@
+
+/* arm_init.c - NEON optimised filter functions
+ *
+ * Copyright (c) 2013 Glenn Randers-Pehrson
+ * Written by Mans Rullgard, 2011.
+ * Last changed in libpng 1.6.8 [December 19, 2013]
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * and license in png.h
+ */
+/* Below, after checking __linux__, various non-C90 POSIX 1003.1 functions are
+ * called.
+ */
+#define _POSIX_SOURCE 1
+
+#include "../pngpriv.h"
+
+#ifdef PNG_READ_SUPPORTED
+#if PNG_ARM_NEON_OPT > 0
+#ifdef PNG_ARM_NEON_CHECK_SUPPORTED /* Do run-time checks */
+#include <signal.h> /* for sig_atomic_t */
+
+#ifdef __ANDROID__
+/* Linux provides access to information about CPU capabilites via
+ * /proc/self/auxv, however Android blocks this while still claiming to be
+ * Linux. The Andoid NDK, however, provides appropriate support.
+ *
+ * Documentation: http://www.kandroid.org/ndk/docs/CPU-ARM-NEON.html
+ */
+#include <cpu-features.h>
+
+static int
+png_have_neon(png_structp png_ptr)
+{
+ /* This is a whole lot easier than the mess below, however it is probably
+ * implemented as below, therefore it is better to cache the result (these
+ * function calls may be slow!)
+ */
+ PNG_UNUSED(png_ptr)
+ return android_getCpuFamily() == ANDROID_CPU_FAMILY_ARM &&
+ (android_getCpuFeatures() & ANDROID_CPU_ARM_FEATURE_NEON) != 0;
+}
+#elif defined(__linux__)
+/* The generic __linux__ implementation requires reading /proc/self/auxv and
+ * looking at each element for one that records NEON capabilities.
+ */
+#include <unistd.h> /* for POSIX 1003.1 */
+#include <errno.h> /* for EINTR */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <elf.h>
+#include <asm/hwcap.h>
+
+/* A read call may be interrupted, in which case it returns -1 and sets errno to
+ * EINTR if nothing was done, otherwise (if something was done) a partial read
+ * may result.
+ */
+static size_t
+safe_read(png_structp png_ptr, int fd, void *buffer_in, size_t nbytes)
+{
+ size_t ntotal = 0;
+ char *buffer = png_voidcast(char*, buffer_in);
+
+ while (nbytes > 0)
+ {
+ unsigned int nread;
+ int iread;
+
+ /* Passing nread > INT_MAX to read is implementation defined in POSIX
+ * 1003.1, therefore despite the unsigned argument portable code must
+ * limit the value to INT_MAX!
+ */
+ if (nbytes > INT_MAX)
+ nread = INT_MAX;
+
+ else
+ nread = (unsigned int)/*SAFE*/nbytes;
+
+ iread = read(fd, buffer, nread);
+
+ if (iread == -1)
+ {
+ /* This is the devil in the details, a read can terminate early with 0
+ * bytes read because of EINTR, yet it still returns -1 otherwise end
+ * of file cannot be distinguished.
+ */
+ if (errno != EINTR)
+ {
+ png_warning(png_ptr, "/proc read failed");
+ return 0; /* I.e., a permanent failure */
+ }
+ }
+
+ else if (iread < 0)
+ {
+ /* Not a valid 'read' result: */
+ png_warning(png_ptr, "OS /proc read bug");
+ return 0;
+ }
+
+ else if (iread > 0)
+ {
+ /* Continue reading until a permanent failure, or EOF */
+ buffer += iread;
+ nbytes -= (unsigned int)/*SAFE*/iread;
+ ntotal += (unsigned int)/*SAFE*/iread;
+ }
+
+ else
+ return ntotal;
+ }
+
+ return ntotal; /* nbytes == 0 */
+}
+
+static int
+png_have_neon(png_structp png_ptr)
+{
+ int fd = open("/proc/self/auxv", O_RDONLY);
+ Elf32_auxv_t aux;
+
+ /* Failsafe: failure to open means no NEON */
+ if (fd == -1)
+ {
+ png_warning(png_ptr, "/proc/self/auxv open failed");
+ return 0;
+ }
+
+ while (safe_read(png_ptr, fd, &aux, sizeof aux) == sizeof aux)
+ {
+ if (aux.a_type == AT_HWCAP && (aux.a_un.a_val & HWCAP_NEON) != 0)
+ {
+ close(fd);
+ return 1;
+ }
+ }
+
+ close(fd);
+ return 0;
+}
+#else
+ /* We don't know how to do a run-time check on this system */
+# error "no support for run-time ARM NEON checks"
+#endif /* OS checks */
+#endif /* PNG_ARM_NEON_CHECK_SUPPORTED */
+
+#ifndef PNG_ALIGNED_MEMORY_SUPPORTED
+# error "ALIGNED_MEMORY is required; set: -DPNG_ALIGNED_MEMORY_SUPPORTED"
+#endif
+
+void
+png_init_filter_functions_neon(png_structp pp, unsigned int bpp)
+{
+ /* The switch statement is compiled in for ARM_NEON_API, the call to
+ * png_have_neon is compiled in for ARM_NEON_CHECK. If both are defined
+ * the check is only performed if the API has not set the NEON option on
+ * or off explicitly. In this case the check controls what happens.
+ *
+ * If the CHECK is not compiled in and the option is UNSET the behavior prior
+ * to 1.6.7 was to use the NEON code - this was a bug caused by having the
+ * wrong order of the 'ON' and 'default' cases. UNSET now defaults to OFF,
+ * as documented in png.h
+ */
+#ifdef PNG_ARM_NEON_API_SUPPORTED
+ switch ((pp->options >> PNG_ARM_NEON) & 3)
+ {
+ case PNG_OPTION_UNSET:
+ /* Allow the run-time check to execute if it has been enabled -
+ * thus both API and CHECK can be turned on. If it isn't supported
+ * this case will fall through to the 'default' below, which just
+ * returns.
+ */
+#endif /* PNG_ARM_NEON_API_SUPPORTED */
+#ifdef PNG_ARM_NEON_CHECK_SUPPORTED
+ {
+ static volatile sig_atomic_t no_neon = -1; /* not checked */
+
+ if (no_neon < 0)
+ no_neon = !png_have_neon(pp);
+
+ if (no_neon)
+ return;
+ }
+#ifdef PNG_ARM_NEON_API_SUPPORTED
+ break;
+#endif
+#endif /* PNG_ARM_NEON_CHECK_SUPPORTED */
+
+#ifdef PNG_ARM_NEON_API_SUPPORTED
+ default: /* OFF or INVALID */
+ return;
+
+ case PNG_OPTION_ON:
+ /* Option turned on */
+ break;
+ }
+#endif
+
+ /* IMPORTANT: any new external functions used here must be declared using
+ * PNG_INTERNAL_FUNCTION in ../pngpriv.h. This is required so that the
+ * 'prefix' option to configure works:
+ *
+ * ./configure --with-libpng-prefix=foobar_
+ *
+ * Verify you have got this right by running the above command, doing a build
+ * and examining pngprefix.h; it must contain a #define for every external
+ * function you add. (Notice that this happens automatically for the
+ * initialization function.)
+ */
+ pp->read_filter[PNG_FILTER_VALUE_UP-1] = png_read_filter_row_up_neon;
+
+ if (bpp == 3)
+ {
+ pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub3_neon;
+ pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg3_neon;
+ pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =
+ png_read_filter_row_paeth3_neon;
+ }
+
+ else if (bpp == 4)
+ {
+ pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub4_neon;
+ pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg4_neon;
+ pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =
+ png_read_filter_row_paeth4_neon;
+ }
+}
+#endif /* PNG_ARM_NEON_OPT > 0 */
+#endif /* PNG_READ_SUPPORTED */
diff --git a/drivers/png/arm/filter_neon.S b/drivers/png/arm/filter_neon.S
new file mode 100644
index 0000000000..477df7c99b
--- /dev/null
+++ b/drivers/png/arm/filter_neon.S
@@ -0,0 +1,235 @@
+
+/* filter_neon.S - NEON optimised filter functions
+ *
+ * Copyright (c) 2013 Glenn Randers-Pehrson
+ * Written by Mans Rullgard, 2011.
+ * Last changed in libpng 1.5.17 [June 27, 2013]
+ *
+ * This code is released under the libpng license.
+ * For conditions of distribution and use, see the disclaimer
+ * and license in png.h
+ */
+
+/* This is required to get the symbol renames, which are #defines, and also
+ * includes the definition (or not) of PNG_ARM_NEON_OPT.
+ */
+#define PNG_VERSION_INFO_ONLY
+#include "../pngpriv.h"
+
+#if defined(__linux__) && defined(__ELF__)
+.section .note.GNU-stack,"",%progbits /* mark stack as non-executable */
+#endif
+
+#if PNG_ARM_NEON_OPT > 0
+
+#ifdef __ELF__
+# define ELF
+#else
+# define ELF @
+#endif
+
+ .arch armv7-a
+ .fpu neon
+
+.macro func name, export=0
+ .macro endfunc
+ELF .size \name, . - \name
+ .endfunc
+ .purgem endfunc
+ .endm
+ .text
+ .if \export
+ .global \name
+ .endif
+ELF .type \name, STT_FUNC
+ .func \name
+\name:
+.endm
+
+func png_read_filter_row_sub4_neon, export=1
+ ldr r3, [r0, #4] @ rowbytes
+ vmov.i8 d3, #0
+1:
+ vld4.32 {d4[],d5[],d6[],d7[]}, [r1,:128]
+ vadd.u8 d0, d3, d4
+ vadd.u8 d1, d0, d5
+ vadd.u8 d2, d1, d6
+ vadd.u8 d3, d2, d7
+ vst4.32 {d0[0],d1[0],d2[0],d3[0]},[r1,:128]!
+ subs r3, r3, #16
+ bgt 1b
+
+ bx lr
+endfunc
+
+func png_read_filter_row_sub3_neon, export=1
+ ldr r3, [r0, #4] @ rowbytes
+ vmov.i8 d3, #0
+ mov r0, r1
+ mov r2, #3
+ mov r12, #12
+ vld1.8 {q11}, [r0], r12
+1:
+ vext.8 d5, d22, d23, #3
+ vadd.u8 d0, d3, d22
+ vext.8 d6, d22, d23, #6
+ vadd.u8 d1, d0, d5
+ vext.8 d7, d23, d23, #1
+ vld1.8 {q11}, [r0], r12
+ vst1.32 {d0[0]}, [r1,:32], r2
+ vadd.u8 d2, d1, d6
+ vst1.32 {d1[0]}, [r1], r2
+ vadd.u8 d3, d2, d7
+ vst1.32 {d2[0]}, [r1], r2
+ vst1.32 {d3[0]}, [r1], r2
+ subs r3, r3, #12
+ bgt 1b
+
+ bx lr
+endfunc
+
+func png_read_filter_row_up_neon, export=1
+ ldr r3, [r0, #4] @ rowbytes
+1:
+ vld1.8 {q0}, [r1,:128]
+ vld1.8 {q1}, [r2,:128]!
+ vadd.u8 q0, q0, q1
+ vst1.8 {q0}, [r1,:128]!
+ subs r3, r3, #16
+ bgt 1b
+
+ bx lr
+endfunc
+
+func png_read_filter_row_avg4_neon, export=1
+ ldr r12, [r0, #4] @ rowbytes
+ vmov.i8 d3, #0
+1:
+ vld4.32 {d4[],d5[],d6[],d7[]}, [r1,:128]
+ vld4.32 {d16[],d17[],d18[],d19[]},[r2,:128]!
+ vhadd.u8 d0, d3, d16
+ vadd.u8 d0, d0, d4
+ vhadd.u8 d1, d0, d17
+ vadd.u8 d1, d1, d5
+ vhadd.u8 d2, d1, d18
+ vadd.u8 d2, d2, d6
+ vhadd.u8 d3, d2, d19
+ vadd.u8 d3, d3, d7
+ vst4.32 {d0[0],d1[0],d2[0],d3[0]},[r1,:128]!
+ subs r12, r12, #16
+ bgt 1b
+
+ bx lr
+endfunc
+
+func png_read_filter_row_avg3_neon, export=1
+ push {r4,lr}
+ ldr r12, [r0, #4] @ rowbytes
+ vmov.i8 d3, #0
+ mov r0, r1
+ mov r4, #3
+ mov lr, #12
+ vld1.8 {q11}, [r0], lr
+1:
+ vld1.8 {q10}, [r2], lr
+ vext.8 d5, d22, d23, #3
+ vhadd.u8 d0, d3, d20
+ vext.8 d17, d20, d21, #3
+ vadd.u8 d0, d0, d22
+ vext.8 d6, d22, d23, #6
+ vhadd.u8 d1, d0, d17
+ vext.8 d18, d20, d21, #6
+ vadd.u8 d1, d1, d5
+ vext.8 d7, d23, d23, #1
+ vld1.8 {q11}, [r0], lr
+ vst1.32 {d0[0]}, [r1,:32], r4
+ vhadd.u8 d2, d1, d18
+ vst1.32 {d1[0]}, [r1], r4
+ vext.8 d19, d21, d21, #1
+ vadd.u8 d2, d2, d6
+ vhadd.u8 d3, d2, d19
+ vst1.32 {d2[0]}, [r1], r4
+ vadd.u8 d3, d3, d7
+ vst1.32 {d3[0]}, [r1], r4
+ subs r12, r12, #12
+ bgt 1b
+
+ pop {r4,pc}
+endfunc
+
+.macro paeth rx, ra, rb, rc
+ vaddl.u8 q12, \ra, \rb @ a + b
+ vaddl.u8 q15, \rc, \rc @ 2*c
+ vabdl.u8 q13, \rb, \rc @ pa
+ vabdl.u8 q14, \ra, \rc @ pb
+ vabd.u16 q15, q12, q15 @ pc
+ vcle.u16 q12, q13, q14 @ pa <= pb
+ vcle.u16 q13, q13, q15 @ pa <= pc
+ vcle.u16 q14, q14, q15 @ pb <= pc
+ vand q12, q12, q13 @ pa <= pb && pa <= pc
+ vmovn.u16 d28, q14
+ vmovn.u16 \rx, q12
+ vbsl d28, \rb, \rc
+ vbsl \rx, \ra, d28
+.endm
+
+func png_read_filter_row_paeth4_neon, export=1
+ ldr r12, [r0, #4] @ rowbytes
+ vmov.i8 d3, #0
+ vmov.i8 d20, #0
+1:
+ vld4.32 {d4[],d5[],d6[],d7[]}, [r1,:128]
+ vld4.32 {d16[],d17[],d18[],d19[]},[r2,:128]!
+ paeth d0, d3, d16, d20
+ vadd.u8 d0, d0, d4
+ paeth d1, d0, d17, d16
+ vadd.u8 d1, d1, d5
+ paeth d2, d1, d18, d17
+ vadd.u8 d2, d2, d6
+ paeth d3, d2, d19, d18
+ vmov d20, d19
+ vadd.u8 d3, d3, d7
+ vst4.32 {d0[0],d1[0],d2[0],d3[0]},[r1,:128]!
+ subs r12, r12, #16
+ bgt 1b
+
+ bx lr
+endfunc
+
+func png_read_filter_row_paeth3_neon, export=1
+ push {r4,lr}
+ ldr r12, [r0, #4] @ rowbytes
+ vmov.i8 d3, #0
+ vmov.i8 d4, #0
+ mov r0, r1
+ mov r4, #3
+ mov lr, #12
+ vld1.8 {q11}, [r0], lr
+1:
+ vld1.8 {q10}, [r2], lr
+ paeth d0, d3, d20, d4
+ vext.8 d5, d22, d23, #3
+ vadd.u8 d0, d0, d22
+ vext.8 d17, d20, d21, #3
+ paeth d1, d0, d17, d20
+ vst1.32 {d0[0]}, [r1,:32], r4
+ vext.8 d6, d22, d23, #6
+ vadd.u8 d1, d1, d5
+ vext.8 d18, d20, d21, #6
+ paeth d2, d1, d18, d17
+ vext.8 d7, d23, d23, #1
+ vld1.8 {q11}, [r0], lr
+ vst1.32 {d1[0]}, [r1], r4
+ vadd.u8 d2, d2, d6
+ vext.8 d19, d21, d21, #1
+ paeth d3, d2, d19, d18
+ vst1.32 {d2[0]}, [r1], r4
+ vmov d4, d19
+ vadd.u8 d3, d3, d7
+ vst1.32 {d3[0]}, [r1], r4
+ subs r12, r12, #12
+ bgt 1b
+
+ pop {r4,pc}
+endfunc
+#endif /* PNG_ARM_NEON_OPT > 0 */
diff --git a/drivers/png/example.c b/drivers/png/example.c
index ec53a8cdee..7171d9847e 100644
--- a/drivers/png/example.c
+++ b/drivers/png/example.c
@@ -2,8 +2,8 @@
#if 0 /* in case someone actually tries to compile this */
/* example.c - an example of using libpng
- * Last changed in libpng 1.5.7 [December 15, 2011]
- * Maintained 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.19 [August 21, 2014]
+ * Maintained 1998-2014 Glenn Randers-Pehrson
* Maintained 1996, 1997 Andreas Dilger
* Written 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
*/
@@ -89,7 +89,7 @@ void read_png(char *file_name) /* We need to open the file */
{
png_structp png_ptr;
png_infop info_ptr;
- unsigned int sig_read = 0;
+ int sig_read = 0;
png_uint_32 width, height;
int bit_depth, color_type, interlace_type;
FILE *fp;
@@ -98,7 +98,7 @@ void read_png(char *file_name) /* We need to open the file */
return (ERROR);
#else no_open_file /* prototype 2 */
-void read_png(FILE *fp, unsigned int sig_read) /* File is already open */
+void read_png(FILE *fp, int sig_read) /* File is already open */
{
png_structp png_ptr;
png_infop info_ptr;
@@ -188,7 +188,7 @@ void read_png(FILE *fp, unsigned int sig_read) /* File is already open */
* are mutually exclusive.
*/
- /* Tell libpng to strip 16 bit/color files down to 8 bits/color.
+ /* Tell libpng to strip 16 bits/color files down to 8 bits/color.
* Use accurate scaling if it's available, otherwise just chop off the
* low byte.
*/
@@ -259,9 +259,9 @@ void read_png(FILE *fp, unsigned int sig_read) /* File is already open */
/* If we don't have another value */
else
{
- screen_gamma = 2.2; /* A good guess for a PC monitor in a dimly
- lit room */
- screen_gamma = 1.7 or 1.0; /* A good guess for Mac systems */
+ screen_gamma = PNG_DEFAULT_sRGB; /* A good guess for a PC monitor
+ in a dimly lit room */
+ screen_gamma = PNG_GAMMA_MAC_18 or 1.0; /* Good guesses for Mac systems */
}
/* Tell libpng to handle the gamma conversion for you. The final call
@@ -273,7 +273,7 @@ void read_png(FILE *fp, unsigned int sig_read) /* File is already open */
int intent;
if (png_get_sRGB(png_ptr, info_ptr, &intent))
- png_set_gamma(png_ptr, screen_gamma, 0.45455);
+ png_set_gamma(png_ptr, screen_gamma, PNG_DEFAULT_sRGB);
else
{
double image_gamma;
@@ -284,7 +284,7 @@ void read_png(FILE *fp, unsigned int sig_read) /* File is already open */
}
#ifdef PNG_READ_QUANTIZE_SUPPORTED
- /* Quantize RGB files down to 8 bit palette or reduce palettes
+ /* Quantize RGB files down to 8-bit palette or reduce palettes
* to the number of colors available on your screen.
*/
if (color_type & PNG_COLOR_MASK_COLOR)
@@ -336,7 +336,7 @@ void read_png(FILE *fp, unsigned int sig_read) /* File is already open */
/* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */
png_set_swap_alpha(png_ptr);
- /* Swap bytes of 16 bit files to least significant byte first */
+ /* Swap bytes of 16-bit files to least significant byte first */
png_set_swap(png_ptr);
/* Add filler (or alpha) byte (before/after each RGB triplet) */
@@ -695,25 +695,38 @@ void write_png(char *file_name /* , ... other image information ... */)
png_set_gAMA(png_ptr, info_ptr, gamma);
/* Optionally write comments into the image */
- text_ptr[0].key = "Title";
- text_ptr[0].text = "Mona Lisa";
- text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
- text_ptr[0].itxt_length = 0;
- text_ptr[0].lang = NULL;
- text_ptr[0].lang_key = NULL;
- text_ptr[1].key = "Author";
- text_ptr[1].text = "Leonardo DaVinci";
- text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
- text_ptr[1].itxt_length = 0;
- text_ptr[1].lang = NULL;
- text_ptr[1].lang_key = NULL;
- text_ptr[2].key = "Description";
- text_ptr[2].text = "<long text>";
- text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt;
- text_ptr[2].itxt_length = 0;
- text_ptr[2].lang = NULL;
- text_ptr[2].lang_key = NULL;
- png_set_text(png_ptr, info_ptr, text_ptr, 3);
+ {
+ png_text text_ptr[3];
+
+ char key0[]="Title";
+ char text0[]="Mona Lisa";
+ text_ptr[0].key = key0;
+ text_ptr[0].text = text0;
+ text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
+ text_ptr[0].itxt_length = 0;
+ text_ptr[0].lang = NULL;
+ text_ptr[0].lang_key = NULL;
+
+ char key1[]="Author";
+ char text1[]="Leonardo DaVinci";
+ text_ptr[1].key = key1;
+ text_ptr[1].text = text1;
+ text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
+ text_ptr[1].itxt_length = 0;
+ text_ptr[1].lang = NULL;
+ text_ptr[1].lang_key = NULL;
+
+ char key2[]="Description";
+ char text2[]="<long text>";
+ text_ptr[2].key = key2;
+ text_ptr[2].text = text2;
+ text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt;
+ text_ptr[2].itxt_length = 0;
+ text_ptr[2].lang = NULL;
+ text_ptr[2].lang_key = NULL;
+
+ png_set_text(write_ptr, write_info_ptr, text_ptr, 3);
+ }
/* Other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs */
@@ -737,7 +750,7 @@ void write_png(char *file_name /* , ... other image information ... */)
*/
/* Once we write out the header, the compression type on the text
- * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or
+ * chunk gets changed to PNG_TEXT_COMPRESSION_NONE_WR or
* PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again
* at the end.
*/
@@ -771,11 +784,11 @@ void write_png(char *file_name /* , ... other image information ... */)
/* Swap bytes of 16-bit files to most significant byte first */
png_set_swap(png_ptr);
- /* Swap bits of 1, 2, 4 bit packed pixel formats */
+ /* Swap bits of 1-bit, 2-bit, 4-bit packed pixel formats */
png_set_packswap(png_ptr);
/* Turn on interlace handling if you are not using png_write_image() */
- if (interlacing)
+ if (interlacing != 0)
number_passes = png_set_interlace_handling(png_ptr);
else
@@ -786,12 +799,16 @@ void write_png(char *file_name /* , ... other image information ... */)
* use the first method if you aren't handling interlacing yourself.
*/
png_uint_32 k, height, width;
- png_byte image[height][width*bytes_per_pixel];
+
+ /* In this example, "image" is a one-dimensional array of bytes */
+ png_byte image[height*width*bytes_per_pixel];
+
png_bytep row_pointers[height];
if (height > PNG_UINT_32_MAX/png_sizeof(png_bytep))
png_error (png_ptr, "Image is too tall to process in memory");
+ /* Set up pointers into your "image" byte array */
for (k = 0; k < height; k++)
row_pointers[k] = image + k*width*bytes_per_pixel;
diff --git a/drivers/png/filter_neon.S b/drivers/png/filter_neon.S
deleted file mode 100644
index 63a5d8c17f..0000000000
--- a/drivers/png/filter_neon.S
+++ /dev/null
@@ -1,225 +0,0 @@
-
-/* filter_neon.S - NEON optimised filter functions
- *
- * Copyright (c) 2011 Glenn Randers-Pehrson
- * Written by Mans Rullgard, 2011.
- *
- * This code is released under the libpng license.
- * For conditions of distribution and use, see the disclaimer
- * and license in png.h
- */
-
-#if defined(__linux__) && defined(__ELF__)
-.section .note.GNU-stack,"",%progbits /* mark stack as non-executable */
-#endif
-
-#ifdef __ELF__
-# define ELF
-#else
-# define ELF @
-#endif
-
- .arch armv7-a
- .fpu neon
-
-.macro func name, export=0
- .macro endfunc
-ELF .size \name, . - \name
- .endfunc
- .purgem endfunc
- .endm
- .text
- .if \export
- .global \name
- .endif
-ELF .type \name, STT_FUNC
- .func \name
-\name:
-.endm
-
-func png_read_filter_row_sub4_neon, export=1
- ldr r3, [r0, #4] @ rowbytes
- vmov.i8 d3, #0
-1:
- vld4.32 {d4[],d5[],d6[],d7[]}, [r1,:128]
- vadd.u8 d0, d3, d4
- vadd.u8 d1, d0, d5
- vadd.u8 d2, d1, d6
- vadd.u8 d3, d2, d7
- vst4.32 {d0[0],d1[0],d2[0],d3[0]},[r1,:128]!
- subs r3, r3, #16
- bgt 1b
-
- bx lr
-endfunc
-
-func png_read_filter_row_sub3_neon, export=1
- ldr r3, [r0, #4] @ rowbytes
- vmov.i8 d3, #0
- mov r0, r1
- mov r2, #3
- mov r12, #12
- vld1.8 {q11}, [r0], r12
-1:
- vext.8 d5, d22, d23, #3
- vadd.u8 d0, d3, d22
- vext.8 d6, d22, d23, #6
- vadd.u8 d1, d0, d5
- vext.8 d7, d23, d23, #1
- vld1.8 {q11}, [r0], r12
- vst1.32 {d0[0]}, [r1,:32], r2
- vadd.u8 d2, d1, d6
- vst1.32 {d1[0]}, [r1], r2
- vadd.u8 d3, d2, d7
- vst1.32 {d2[0]}, [r1], r2
- vst1.32 {d3[0]}, [r1], r2
- subs r3, r3, #12
- bgt 1b
-
- bx lr
-endfunc
-
-func png_read_filter_row_up_neon, export=1
- ldr r3, [r0, #4] @ rowbytes
-1:
- vld1.8 {q0}, [r1,:128]
- vld1.8 {q1}, [r2,:128]!
- vadd.u8 q0, q0, q1
- vst1.8 {q0}, [r1,:128]!
- subs r3, r3, #16
- bgt 1b
-
- bx lr
-endfunc
-
-func png_read_filter_row_avg4_neon, export=1
- ldr r12, [r0, #4] @ rowbytes
- vmov.i8 d3, #0
-1:
- vld4.32 {d4[],d5[],d6[],d7[]}, [r1,:128]
- vld4.32 {d16[],d17[],d18[],d19[]},[r2,:128]!
- vhadd.u8 d0, d3, d16
- vadd.u8 d0, d0, d4
- vhadd.u8 d1, d0, d17
- vadd.u8 d1, d1, d5
- vhadd.u8 d2, d1, d18
- vadd.u8 d2, d2, d6
- vhadd.u8 d3, d2, d19
- vadd.u8 d3, d3, d7
- vst4.32 {d0[0],d1[0],d2[0],d3[0]},[r1,:128]!
- subs r12, r12, #16
- bgt 1b
-
- bx lr
-endfunc
-
-func png_read_filter_row_avg3_neon, export=1
- push {r4,lr}
- ldr r12, [r0, #4] @ rowbytes
- vmov.i8 d3, #0
- mov r0, r1
- mov r4, #3
- mov lr, #12
- vld1.8 {q11}, [r0], lr
-1:
- vld1.8 {q10}, [r2], lr
- vext.8 d5, d22, d23, #3
- vhadd.u8 d0, d3, d20
- vext.8 d17, d20, d21, #3
- vadd.u8 d0, d0, d22
- vext.8 d6, d22, d23, #6
- vhadd.u8 d1, d0, d17
- vext.8 d18, d20, d21, #6
- vadd.u8 d1, d1, d5
- vext.8 d7, d23, d23, #1
- vld1.8 {q11}, [r0], lr
- vst1.32 {d0[0]}, [r1,:32], r4
- vhadd.u8 d2, d1, d18
- vst1.32 {d1[0]}, [r1], r4
- vext.8 d19, d21, d21, #1
- vadd.u8 d2, d2, d6
- vhadd.u8 d3, d2, d19
- vst1.32 {d2[0]}, [r1], r4
- vadd.u8 d3, d3, d7
- vst1.32 {d3[0]}, [r1], r4
- subs r12, r12, #12
- bgt 1b
-
- pop {r4,pc}
-endfunc
-
-.macro paeth rx, ra, rb, rc
- vaddl.u8 q12, \ra, \rb @ a + b
- vaddl.u8 q15, \rc, \rc @ 2*c
- vabdl.u8 q13, \rb, \rc @ pa
- vabdl.u8 q14, \ra, \rc @ pb
- vabd.u16 q15, q12, q15 @ pc
- vcle.u16 q12, q13, q14 @ pa <= pb
- vcle.u16 q13, q13, q15 @ pa <= pc
- vcle.u16 q14, q14, q15 @ pb <= pc
- vand q12, q12, q13 @ pa <= pb && pa <= pc
- vmovn.u16 d28, q14
- vmovn.u16 \rx, q12
- vbsl d28, \rb, \rc
- vbsl \rx, \ra, d28
-.endm
-
-func png_read_filter_row_paeth4_neon, export=1
- ldr r12, [r0, #4] @ rowbytes
- vmov.i8 d3, #0
- vmov.i8 d20, #0
-1:
- vld4.32 {d4[],d5[],d6[],d7[]}, [r1,:128]
- vld4.32 {d16[],d17[],d18[],d19[]},[r2,:128]!
- paeth d0, d3, d16, d20
- vadd.u8 d0, d0, d4
- paeth d1, d0, d17, d16
- vadd.u8 d1, d1, d5
- paeth d2, d1, d18, d17
- vadd.u8 d2, d2, d6
- paeth d3, d2, d19, d18
- vmov d20, d19
- vadd.u8 d3, d3, d7
- vst4.32 {d0[0],d1[0],d2[0],d3[0]},[r1,:128]!
- subs r12, r12, #16
- bgt 1b
-
- bx lr
-endfunc
-
-func png_read_filter_row_paeth3_neon, export=1
- push {r4,lr}
- ldr r12, [r0, #4] @ rowbytes
- vmov.i8 d3, #0
- vmov.i8 d4, #0
- mov r0, r1
- mov r4, #3
- mov lr, #12
- vld1.8 {q11}, [r0], lr
-1:
- vld1.8 {q10}, [r2], lr
- paeth d0, d3, d20, d4
- vext.8 d5, d22, d23, #3
- vadd.u8 d0, d0, d22
- vext.8 d17, d20, d21, #3
- paeth d1, d0, d17, d20
- vst1.32 {d0[0]}, [r1,:32], r4
- vext.8 d6, d22, d23, #6
- vadd.u8 d1, d1, d5
- vext.8 d18, d20, d21, #6
- paeth d2, d1, d18, d17
- vext.8 d7, d23, d23, #1
- vld1.8 {q11}, [r0], lr
- vst1.32 {d1[0]}, [r1], r4
- vadd.u8 d2, d2, d6
- vext.8 d19, d21, d21, #1
- paeth d3, d2, d19, d18
- vst1.32 {d2[0]}, [r1], r4
- vmov d4, d19
- vadd.u8 d3, d3, d7
- vst1.32 {d3[0]}, [r1], r4
- subs r12, r12, #12
- bgt 1b
-
- pop {r4,pc}
-endfunc
diff --git a/drivers/png/image_loader_png.cpp b/drivers/png/image_loader_png.cpp
index 2a4720b07b..a86e747d80 100644
--- a/drivers/png/image_loader_png.cpp
+++ b/drivers/png/image_loader_png.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/png/image_loader_png.h b/drivers/png/image_loader_png.h
index 8413a7eae1..d87d67d898 100644
--- a/drivers/png/image_loader_png.h
+++ b/drivers/png/image_loader_png.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/png/png.c b/drivers/png/png.c
index 08074485b8..cd7da59222 100644
--- a/drivers/png/png.c
+++ b/drivers/png/png.c
@@ -1,8 +1,8 @@
/* png.c - location for general purpose libpng functions
*
- * Last changed in libpng 1.5.7 [December 15, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.23 [July 23, 2015]
+ * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
@@ -14,7 +14,7 @@
#include "pngpriv.h"
/* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_5_7 Your_png_h_is_not_version_1_5_7;
+typedef png_libpng_version_1_5_26 Your_png_h_is_not_version_1_5_26;
/* Tells libpng that we have already handled the first "num_bytes" bytes
* of the PNG file signature. If the PNG data is embedded into another
@@ -26,15 +26,20 @@ typedef png_libpng_version_1_5_7 Your_png_h_is_not_version_1_5_7;
void PNGAPI
png_set_sig_bytes(png_structp png_ptr, int num_bytes)
{
+ unsigned int nb = (unsigned int)num_bytes;
+
png_debug(1, "in png_set_sig_bytes");
if (png_ptr == NULL)
return;
- if (num_bytes > 8)
+ if (num_bytes < 0)
+ nb = 0;
+
+ if (nb > 8)
png_error(png_ptr, "Too many bytes for PNG signature");
- png_ptr->sig_bytes = (png_byte)(num_bytes < 0 ? 0 : num_bytes);
+ png_ptr->sig_bytes = (png_byte)nb;
}
/* Checks whether the supplied bytes match the PNG signature. We allow
@@ -73,13 +78,16 @@ PNG_FUNCTION(voidpf /* PRIVATE */,
png_zalloc,(voidpf png_ptr, uInt items, uInt size),PNG_ALLOCATED)
{
png_voidp ptr;
- png_structp p=(png_structp)png_ptr;
- png_uint_32 save_flags=p->flags;
+ png_structp p;
+ png_uint_32 save_flags;
png_alloc_size_t num_bytes;
if (png_ptr == NULL)
return (NULL);
+ p=(png_structp)png_ptr;
+ save_flags=p->flags;
+
if (items > PNG_UINT_32_MAX/size)
{
png_warning (p, "Potential overflow in png_zalloc()");
@@ -146,9 +154,10 @@ png_calculate_crc(png_structp png_ptr, png_const_bytep ptr, png_size_t length)
do
{
uInt safeLength = (uInt)length;
+#ifndef __COVERITY__
if (safeLength == 0)
safeLength = (uInt)-1; /* evil, but safe */
-
+#endif
crc = crc32(crc, ptr, safeLength);
/* The following should never issue compiler warnings, if they do the
@@ -171,49 +180,51 @@ png_calculate_crc(png_structp png_ptr, png_const_bytep ptr, png_size_t length)
int
png_user_version_check(png_structp png_ptr, png_const_charp user_png_ver)
{
- if (user_png_ver)
+ /* Libpng versions 1.0.0 and later are binary compatible if the version
+ * string matches through the second '.'; we must recompile any
+ * applications that use any older library version.
+ */
+
+ if (user_png_ver != NULL)
{
- int i = 0;
+ int i = -1;
+ int found_dots = 0;
do
{
- if (user_png_ver[i] != png_libpng_ver[i])
+ i++;
+ if (user_png_ver[i] != PNG_LIBPNG_VER_STRING[i])
png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
- } while (png_libpng_ver[i++]);
+ if (user_png_ver[i] == '.')
+ found_dots++;
+ } while (found_dots < 2 && user_png_ver[i] != 0 &&
+ PNG_LIBPNG_VER_STRING[i] != 0);
}
else
png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH;
- if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH)
+ if ((png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) != 0)
{
- /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so
- * we must recompile any applications that use any older library version.
- * For versions after libpng 1.0, we will be compatible, so we need
- * only check the first digit.
- */
- if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] ||
- (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) ||
- (user_png_ver[0] == '0' && user_png_ver[2] < '9'))
- {
#ifdef PNG_WARNINGS_SUPPORTED
- size_t pos = 0;
- char m[128];
+ size_t pos = 0;
+ char m[128];
- pos = png_safecat(m, sizeof m, pos, "Application built with libpng-");
- pos = png_safecat(m, sizeof m, pos, user_png_ver);
- pos = png_safecat(m, sizeof m, pos, " but running with ");
- pos = png_safecat(m, sizeof m, pos, png_libpng_ver);
+ pos = png_safecat(m, (sizeof m), pos,
+ "Application built with libpng-");
+ pos = png_safecat(m, (sizeof m), pos, user_png_ver);
+ pos = png_safecat(m, (sizeof m), pos, " but running with ");
+ pos = png_safecat(m, (sizeof m), pos, PNG_LIBPNG_VER_STRING);
+ PNG_UNUSED(pos)
- png_warning(png_ptr, m);
+ png_warning(png_ptr, m);
#endif
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
- png_ptr->flags = 0;
+ png_ptr->flags = 0;
#endif
- return 0;
- }
+ return 0;
}
/* Success return. */
@@ -300,6 +311,8 @@ png_info_init_3(png_infopp ptr_ptr, png_size_t png_info_struct_size)
png_destroy_struct(info_ptr);
info_ptr = (png_infop)png_create_struct(PNG_STRUCT_INFO);
*ptr_ptr = info_ptr;
+ if (info_ptr == NULL)
+ return;
}
/* Set everything to 0 */
@@ -337,42 +350,43 @@ png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask,
#ifdef PNG_TEXT_SUPPORTED
/* Free text item num or (if num == -1) all text items */
- if ((mask & PNG_FREE_TEXT) & info_ptr->free_me)
+ if (info_ptr->text != 0 &&
+ ((mask & PNG_FREE_TEXT) & info_ptr->free_me) != 0)
{
if (num != -1)
{
- if (info_ptr->text && info_ptr->text[num].key)
- {
- png_free(png_ptr, info_ptr->text[num].key);
- info_ptr->text[num].key = NULL;
- }
+ png_free(png_ptr, info_ptr->text[num].key);
+ info_ptr->text[num].key = NULL;
}
else
{
int i;
+
for (i = 0; i < info_ptr->num_text; i++)
- png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, i);
+ png_free(png_ptr, info_ptr->text[i].key);
+
png_free(png_ptr, info_ptr->text);
info_ptr->text = NULL;
- info_ptr->num_text=0;
+ info_ptr->num_text = 0;
}
}
#endif
#ifdef PNG_tRNS_SUPPORTED
/* Free any tRNS entry */
- if ((mask & PNG_FREE_TRNS) & info_ptr->free_me)
+ if (((mask & PNG_FREE_TRNS) & info_ptr->free_me) != 0)
{
+ info_ptr->valid &= ~PNG_INFO_tRNS;
png_free(png_ptr, info_ptr->trans_alpha);
info_ptr->trans_alpha = NULL;
- info_ptr->valid &= ~PNG_INFO_tRNS;
+ info_ptr->num_trans = 0;
}
#endif
#ifdef PNG_sCAL_SUPPORTED
/* Free any sCAL entry */
- if ((mask & PNG_FREE_SCAL) & info_ptr->free_me)
+ if (((mask & PNG_FREE_SCAL) & info_ptr->free_me) != 0)
{
png_free(png_ptr, info_ptr->scal_s_width);
png_free(png_ptr, info_ptr->scal_s_height);
@@ -384,20 +398,20 @@ png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask,
#ifdef PNG_pCAL_SUPPORTED
/* Free any pCAL entry */
- if ((mask & PNG_FREE_PCAL) & info_ptr->free_me)
+ if (((mask & PNG_FREE_PCAL) & info_ptr->free_me) != 0)
{
png_free(png_ptr, info_ptr->pcal_purpose);
png_free(png_ptr, info_ptr->pcal_units);
info_ptr->pcal_purpose = NULL;
info_ptr->pcal_units = NULL;
+
if (info_ptr->pcal_params != NULL)
{
int i;
- for (i = 0; i < (int)info_ptr->pcal_nparams; i++)
- {
+
+ for (i = 0; i < info_ptr->pcal_nparams; i++)
png_free(png_ptr, info_ptr->pcal_params[i]);
- info_ptr->pcal_params[i] = NULL;
- }
+
png_free(png_ptr, info_ptr->pcal_params);
info_ptr->pcal_params = NULL;
}
@@ -406,8 +420,8 @@ png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask,
#endif
#ifdef PNG_iCCP_SUPPORTED
- /* Free any iCCP entry */
- if ((mask & PNG_FREE_ICCP) & info_ptr->free_me)
+ /* Free any profile entry */
+ if (((mask & PNG_FREE_ICCP) & info_ptr->free_me) != 0)
{
png_free(png_ptr, info_ptr->iccp_name);
png_free(png_ptr, info_ptr->iccp_profile);
@@ -419,74 +433,62 @@ png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask,
#ifdef PNG_sPLT_SUPPORTED
/* Free a given sPLT entry, or (if num == -1) all sPLT entries */
- if ((mask & PNG_FREE_SPLT) & info_ptr->free_me)
+ if (info_ptr->splt_palettes != 0 &&
+ ((mask & PNG_FREE_SPLT) & info_ptr->free_me) != 0)
{
if (num != -1)
{
- if (info_ptr->splt_palettes)
- {
- png_free(png_ptr, info_ptr->splt_palettes[num].name);
- png_free(png_ptr, info_ptr->splt_palettes[num].entries);
- info_ptr->splt_palettes[num].name = NULL;
- info_ptr->splt_palettes[num].entries = NULL;
- }
+ png_free(png_ptr, info_ptr->splt_palettes[num].name);
+ png_free(png_ptr, info_ptr->splt_palettes[num].entries);
+ info_ptr->splt_palettes[num].name = NULL;
+ info_ptr->splt_palettes[num].entries = NULL;
}
else
{
- if (info_ptr->splt_palettes_num)
- {
- int i;
- for (i = 0; i < (int)info_ptr->splt_palettes_num; i++)
- png_free_data(png_ptr, info_ptr, PNG_FREE_SPLT, i);
+ int i;
- png_free(png_ptr, info_ptr->splt_palettes);
- info_ptr->splt_palettes = NULL;
- info_ptr->splt_palettes_num = 0;
+ for (i = 0; i < info_ptr->splt_palettes_num; i++)
+ {
+ png_free(png_ptr, info_ptr->splt_palettes[i].name);
+ png_free(png_ptr, info_ptr->splt_palettes[i].entries);
}
+
+ png_free(png_ptr, info_ptr->splt_palettes);
+ info_ptr->splt_palettes = NULL;
+ info_ptr->splt_palettes_num = 0;
info_ptr->valid &= ~PNG_INFO_sPLT;
}
}
#endif
#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
- if (png_ptr->unknown_chunk.data)
- {
- png_free(png_ptr, png_ptr->unknown_chunk.data);
- png_ptr->unknown_chunk.data = NULL;
- }
-
- if ((mask & PNG_FREE_UNKN) & info_ptr->free_me)
+ if (info_ptr->unknown_chunks != 0 &&
+ ((mask & PNG_FREE_UNKN) & info_ptr->free_me) != 0)
{
if (num != -1)
{
- if (info_ptr->unknown_chunks)
- {
- png_free(png_ptr, info_ptr->unknown_chunks[num].data);
- info_ptr->unknown_chunks[num].data = NULL;
- }
+ png_free(png_ptr, info_ptr->unknown_chunks[num].data);
+ info_ptr->unknown_chunks[num].data = NULL;
}
else
{
int i;
- if (info_ptr->unknown_chunks_num)
- {
- for (i = 0; i < info_ptr->unknown_chunks_num; i++)
- png_free_data(png_ptr, info_ptr, PNG_FREE_UNKN, i);
+ for (i = 0; i < info_ptr->unknown_chunks_num; i++)
+ png_free(png_ptr, info_ptr->unknown_chunks[i].data);
- png_free(png_ptr, info_ptr->unknown_chunks);
- info_ptr->unknown_chunks = NULL;
- info_ptr->unknown_chunks_num = 0;
- }
+ png_free(png_ptr, info_ptr->unknown_chunks);
+ info_ptr->unknown_chunks = NULL;
+ info_ptr->unknown_chunks_num = 0;
}
}
#endif
#ifdef PNG_hIST_SUPPORTED
/* Free any hIST entry */
- if ((mask & PNG_FREE_HIST) & info_ptr->free_me)
+ if (((mask & PNG_FREE_HIST) & info_ptr->free_me) != 0)
{
png_free(png_ptr, info_ptr->hist);
info_ptr->hist = NULL;
@@ -495,9 +497,9 @@ png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask,
#endif
/* Free any PLTE entry that was internally allocated */
- if ((mask & PNG_FREE_PLTE) & info_ptr->free_me)
+ if (((mask & PNG_FREE_PLTE) & info_ptr->free_me) != 0)
{
- png_zfree(png_ptr, info_ptr->palette);
+ png_free(png_ptr, info_ptr->palette);
info_ptr->palette = NULL;
info_ptr->valid &= ~PNG_INFO_PLTE;
info_ptr->num_palette = 0;
@@ -505,16 +507,14 @@ png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask,
#ifdef PNG_INFO_IMAGE_SUPPORTED
/* Free any image bits attached to the info structure */
- if ((mask & PNG_FREE_ROWS) & info_ptr->free_me)
+ if (((mask & PNG_FREE_ROWS) & info_ptr->free_me) != 0)
{
- if (info_ptr->row_pointers)
+ if (info_ptr->row_pointers != 0)
{
- int row;
- for (row = 0; row < (int)info_ptr->height; row++)
- {
+ png_uint_32 row;
+ for (row = 0; row < info_ptr->height; row++)
png_free(png_ptr, info_ptr->row_pointers[row]);
- info_ptr->row_pointers[row] = NULL;
- }
+
png_free(png_ptr, info_ptr->row_pointers);
info_ptr->row_pointers = NULL;
}
@@ -655,14 +655,15 @@ png_get_copyright(png_const_structp png_ptr)
#else
# ifdef __STDC__
return PNG_STRING_NEWLINE \
- "libpng version 1.5.7 - December 15, 2011" PNG_STRING_NEWLINE \
- "Copyright (c) 1998-2011 Glenn Randers-Pehrson" PNG_STRING_NEWLINE \
+ "libpng version 1.5.26 - December 17, 2015" PNG_STRING_NEWLINE \
+ "Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson" \
+ PNG_STRING_NEWLINE \
"Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
"Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \
PNG_STRING_NEWLINE;
# else
- return "libpng version 1.5.7 - December 15, 2011\
- Copyright (c) 1998-2011 Glenn Randers-Pehrson\
+ return "libpng version 1.5.26 - December 17, 2015\
+ Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson\
Copyright (c) 1996-1997 Andreas Dilger\
Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.";
# endif
@@ -892,7 +893,8 @@ int png_XYZ_from_xy(png_XYZ *XYZ, png_xy xy)
/* Check xy and, implicitly, z. Note that wide gamut color spaces typically
* have end points with 0 tristimulus values (these are impossible end
- * points, but they are used to cover the possible colors.)
+ * points, but they are used to cover the possible colors). We check
+ * xy.whitey against 5, not 0, to avoid a possible integer overflow.
*/
if (xy.redx < 0 || xy.redx > PNG_FP_1) return 1;
if (xy.redy < 0 || xy.redy > PNG_FP_1-xy.redx) return 1;
@@ -901,7 +903,7 @@ int png_XYZ_from_xy(png_XYZ *XYZ, png_xy xy)
if (xy.bluex < 0 || xy.bluex > PNG_FP_1) return 1;
if (xy.bluey < 0 || xy.bluey > PNG_FP_1-xy.bluex) return 1;
if (xy.whitex < 0 || xy.whitex > PNG_FP_1) return 1;
- if (xy.whitey < 0 || xy.whitey > PNG_FP_1-xy.whitex) return 1;
+ if (xy.whitey < 5 || xy.whitey > PNG_FP_1-xy.whitex) return 1;
/* The reverse calculation is more difficult because the original tristimulus
* value had 9 independent values (red,green,blue)x(X,Y,Z) however only 8
@@ -969,8 +971,8 @@ int png_XYZ_from_xy(png_XYZ *XYZ, png_xy xy)
* and it is certain that it becomes unstable where the end points are close
* together.
*
- * So this code uses the perhaps slighly less optimal but more understandable
- * and totally obvious approach of calculating color-scale.
+ * So this code uses the perhaps slightly less optimal but more
+ * understandable and totally obvious approach of calculating color-scale.
*
* This algorithm depends on the precision in white-scale and that is
* (1/white-y), so we can immediately see that as white-y approaches 0 the
@@ -1165,6 +1167,17 @@ int png_XYZ_from_xy_checked(png_structp png_ptr, png_XYZ *XYZ, png_xy xy)
}
#endif
+#ifdef __GNUC__
+/* This exists solely to work round a warning from GNU C. */
+static int /* PRIVATE */
+png_gt(size_t a, size_t b)
+{
+ return a > b;
+}
+#else
+# define png_gt(a,b) ((a) > (b))
+#endif
+
void /* PRIVATE */
png_check_IHDR(png_structp png_ptr,
png_uint_32 width, png_uint_32 height, int bit_depth,
@@ -1179,53 +1192,68 @@ png_check_IHDR(png_structp png_ptr,
png_warning(png_ptr, "Image width is zero in IHDR");
error = 1;
}
-
- if (height == 0)
+ else if (width > PNG_UINT_31_MAX)
{
- png_warning(png_ptr, "Image height is zero in IHDR");
+ png_warning(png_ptr, "Invalid image width in IHDR");
error = 1;
}
-# ifdef PNG_SET_USER_LIMITS_SUPPORTED
- if (width > png_ptr->user_width_max)
-
-# else
- if (width > PNG_USER_WIDTH_MAX)
-# endif
+ else if (png_gt(width,
+ (PNG_SIZE_MAX >> 3) /* 8-byte RGBA pixels */
+ - 48 /* big_row_buf hack */
+ - 1 /* filter byte */
+ - 7*8 /* rounding width to multiple of 8 pix */
+ - 8)) /* extra max_pixel_depth pad */
{
- png_warning(png_ptr, "Image width exceeds user limit in IHDR");
+ /* The size of the row must be within the limits of this architecture.
+ * Because the read code can perform arbitrary transformations the
+ * maximum size is checked here. Because the code in png_read_start_row
+ * adds extra space "for safety's sake" in several places a conservative
+ * limit is used here.
+ *
+ * NOTE: it would be far better to check the size that is actually used,
+ * but the effect in the real world is minor and the changes are more
+ * extensive, therefore much more dangerous and much more difficult to
+ * write in a way that avoids compiler warnings.
+ */
+ png_warning(png_ptr, "Image width is too large for this architecture");
error = 1;
}
-
-# ifdef PNG_SET_USER_LIMITS_SUPPORTED
- if (height > png_ptr->user_height_max)
-# else
- if (height > PNG_USER_HEIGHT_MAX)
-# endif
+ else
{
- png_warning(png_ptr, "Image height exceeds user limit in IHDR");
- error = 1;
+# ifdef PNG_SET_USER_LIMITS_SUPPORTED
+ if (width > png_ptr->user_width_max)
+# else
+ if (width > PNG_USER_WIDTH_MAX)
+# endif
+ {
+ png_warning(png_ptr, "Image width exceeds user limit in IHDR");
+ error = 1;
+ }
}
- if (width > PNG_UINT_31_MAX)
+ if (height == 0)
{
- png_warning(png_ptr, "Invalid image width in IHDR");
+ png_warning(png_ptr, "Image height is zero in IHDR");
error = 1;
}
-
- if (height > PNG_UINT_31_MAX)
+ else if (height > PNG_UINT_31_MAX)
{
png_warning(png_ptr, "Invalid image height in IHDR");
error = 1;
}
-
- if (width > (PNG_UINT_32_MAX
- >> 3) /* 8-byte RGBA pixels */
- - 48 /* bigrowbuf hack */
- - 1 /* filter byte */
- - 7*8 /* rounding of width to multiple of 8 pixels */
- - 8) /* extra max_pixel_depth pad */
- png_warning(png_ptr, "Width is too large for libpng to process pixels");
+ else
+ {
+# ifdef PNG_SET_USER_LIMITS_SUPPORTED
+ if (height > png_ptr->user_height_max)
+# else
+ if (height > PNG_USER_HEIGHT_MAX)
+# endif
+ {
+ png_warning(png_ptr, "Image height exceeds user limit in IHDR");
+ error = 1;
+ }
+ }
/* Check other values */
if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 &&
@@ -1458,7 +1486,7 @@ png_check_fp_string(png_const_charp string, png_size_t size)
}
#endif /* pCAL or sCAL */
-#ifdef PNG_READ_sCAL_SUPPORTED
+#ifdef PNG_sCAL_SUPPORTED
# ifdef PNG_FLOATING_POINT_SUPPORTED
/* Utility used below - a simple accurate power of ten from an integral
* exponent.
@@ -1467,7 +1495,7 @@ static double
png_pow10(int power)
{
int recip = 0;
- double d = 1;
+ double d = 1.0;
/* Handle negative exponent with a reciprocal at the end because
* 10 is exact whereas .1 is inexact in base 2
@@ -1481,7 +1509,7 @@ png_pow10(int power)
if (power > 0)
{
/* Decompose power bitwise. */
- double mult = 10;
+ double mult = 10.0;
do
{
if (power & 1) d *= mult;
@@ -1490,7 +1518,7 @@ png_pow10(int power)
}
while (power > 0);
- if (recip) d = 1/d;
+ if (recip != 0) d = 1/d;
}
/* else power is 0 and d is 1 */
@@ -1600,7 +1628,8 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size,
{
double d;
- fp *= 10;
+ fp *= 10.0;
+
/* Use modf here, not floor and subtract, so that
* the separation is done in one step. At the end
* of the loop don't break the number into parts so
@@ -1613,7 +1642,7 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size,
{
d = floor(fp + .5);
- if (d > 9)
+ if (d > 9.0)
{
/* Rounding up to 10, handle that here. */
if (czero > 0)
@@ -1621,9 +1650,10 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size,
--czero, d = 1;
if (cdigits == 0) --clead;
}
+
else
{
- while (cdigits > 0 && d > 9)
+ while (cdigits > 0 && d > 9.0)
{
int ch = *--ascii;
@@ -1648,7 +1678,7 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size,
* exponent but take into account the leading
* decimal point.
*/
- if (d > 9) /* cdigits == 0 */
+ if (d > 9.0) /* cdigits == 0 */
{
if (exp_b10 == (-1))
{
@@ -1669,18 +1699,19 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size,
++exp_b10;
/* In all cases we output a '1' */
- d = 1;
+ d = 1.0;
}
}
}
fp = 0; /* Guarantees termination below. */
}
- if (d == 0)
+ if (d == 0.0)
{
++czero;
if (cdigits == 0) ++clead;
}
+
else
{
/* Included embedded zeros in the digit count. */
@@ -1708,6 +1739,7 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size,
above */
--exp_b10;
}
+
*ascii++ = (char)(48 + (int)d), ++cdigits;
}
}
@@ -1718,7 +1750,7 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size,
/* Check for an exponent, if we don't need one we are
* done and just need to terminate the string. At
* this point exp_b10==(-1) is effectively if flag - it got
- * to '-1' because of the decrement after outputing
+ * to '-1' because of the decrement after outputting
* the decimal point above (the exponent required is
* *not* -1!)
*/
@@ -1726,7 +1758,7 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size,
{
/* The following only happens if we didn't output the
* leading zeros above for negative exponent, so this
- * doest add to the digit requirement. Note that the
+ * doesn't add to the digit requirement. Note that the
* two zeros here can only be output if the two leading
* zeros were *not* output, so this doesn't increase
* the output count.
@@ -1900,7 +1932,7 @@ png_fixed(png_structp png_ptr, double fp, png_const_charp text)
#endif
#if defined(PNG_READ_GAMMA_SUPPORTED) || \
- defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG__READ_pHYs_SUPPORTED)
+ defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED)
/* muldiv functions */
/* This API takes signed arguments and rounds the result to the nearest
* integer (or, for a fixed point number - the standard argument - to
@@ -2004,7 +2036,7 @@ png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times,
if (s00 >= (D >> 1))
++result;
- if (negative)
+ if (negative != 0)
result = -result;
/* Check for overflow. */
@@ -2040,26 +2072,31 @@ png_muldiv_warn(png_structp png_ptr, png_fixed_point a, png_int_32 times,
}
#endif
-#ifdef PNG_READ_GAMMA_SUPPORTED /* more fixed point functions for gammma */
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED)
+/* more fixed point functions for gamma and cHRM (xy/XYZ) suport. */
/* Calculate a reciprocal, return 0 on div-by-zero or overflow. */
png_fixed_point
png_reciprocal(png_fixed_point a)
{
+ if (a != 0)
+ {
#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
- double r = floor(1E10/a+.5);
+ double r = floor(1E10/a+.5);
- if (r <= 2147483647. && r >= -2147483648.)
- return (png_fixed_point)r;
+ if (r <= 2147483647. && r >= -2147483648.)
+ return (png_fixed_point)r;
#else
- png_fixed_point res;
+ png_fixed_point res;
- if (png_muldiv(&res, 100000, 100000, a))
- return res;
+ if (png_muldiv(&res, 100000, 100000, a))
+ return res;
#endif
+ }
return 0; /* error/overflow */
}
+#ifdef PNG_READ_GAMMA_SUPPORTED
/* A local convenience routine. */
static png_fixed_point
png_product2(png_fixed_point a, png_fixed_point b)
@@ -2081,6 +2118,7 @@ png_product2(png_fixed_point a, png_fixed_point b)
return 0; /* overflow */
}
+#endif /* READ_GAMMA */
/* The inverse of the above. */
png_fixed_point
@@ -2088,17 +2126,20 @@ png_reciprocal2(png_fixed_point a, png_fixed_point b)
{
/* The required result is 1/a * 1/b; the following preserves accuracy. */
#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
- double r = 1E15/a;
- r /= b;
- r = floor(r+.5);
+ if (a != 0 && b != 0)
+ {
+ double r = 1E15/a;
+ r /= b;
+ r = floor(r+.5);
- if (r <= 2147483647. && r >= -2147483648.)
- return (png_fixed_point)r;
+ if (r <= 2147483647. && r >= -2147483648.)
+ return (png_fixed_point)r;
+ }
#else
- /* This may overflow because the range of png_fixed_point isn't symmetric,
- * but this API is only used for the product of file and screen gamma so it
- * doesn't matter that the smallest number it can produce is 1/21474, not
- * 1/100000
+ /* This may overflow because the range of png_fixed_point isn't
+ * symmetric, but this API is only used for the product of file and
+ * screen gamma so it doesn't matter that the smallest number it can
+ * produce is 1/21474, not 1/100000
*/
png_fixed_point res = png_product2(a, b);
@@ -2108,7 +2149,7 @@ png_reciprocal2(png_fixed_point a, png_fixed_point b)
return 0; /* overflow */
}
-#endif /* READ_GAMMA */
+#endif /* READ_GAMMA || cHRM */
#ifdef PNG_CHECK_cHRM_SUPPORTED
/* Added at libpng version 1.2.34 (Dec 8, 2008) and 1.4.0 (Jan 2,
@@ -2519,6 +2560,7 @@ png_gamma_significant(png_fixed_point gamma_val)
gamma_val > PNG_FP_1 + PNG_GAMMA_THRESHOLD_FIXED;
}
+#ifdef PNG_16BIT_SUPPORTED
/* Internal function to build a single 16-bit table - the table consists of
* 'num' 256-entry subtables, where 'num' is determined by 'shift' - the amount
* to shift the input values right (or 16-number_of_signifiant_bits).
@@ -2567,7 +2609,7 @@ png_build_16bit_table(png_structp png_ptr, png_uint_16pp *ptable,
double d = floor(65535*pow(ig/(double)max, gamma_val*.00001)+.5);
sub_table[j] = (png_uint_16)d;
# else
- if (shift)
+ if (shift != 0)
ig = (ig * 65535U + max_by_2)/max;
sub_table[j] = png_gamma_16bit_correct(ig, gamma_val);
@@ -2583,7 +2625,7 @@ png_build_16bit_table(png_structp png_ptr, png_uint_16pp *ptable,
{
png_uint_32 ig = (j << (8-shift)) + i;
- if (shift)
+ if (shift != 0)
ig = (ig * 65535U + max_by_2)/max;
sub_table[j] = (png_uint_16)ig;
@@ -2591,6 +2633,7 @@ png_build_16bit_table(png_structp png_ptr, png_uint_16pp *ptable,
}
}
}
+#endif
/* NOTE: this function expects the *inverse* of the overall gamma transformation
* required.
@@ -2868,3 +2911,24 @@ png_build_gamma_table(png_structp png_ptr, int bit_depth)
}
#endif /* READ_GAMMA */
#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */
+
+/* HARDWARE OPTION SUPPORT */
+#ifdef PNG_SET_OPTION_SUPPORTED
+int PNGAPI
+png_set_option(png_structp png_ptr, int option, int onoff)
+{
+ if (png_ptr != NULL && option >= 0 && option < PNG_OPTION_NEXT &&
+ (option & 1) == 0)
+ {
+ int mask = 3 << option;
+ int setting = (2 + (onoff != 0)) << option;
+ int current = png_ptr->options;
+
+ png_ptr->options = (png_byte)((current & ~mask) | setting);
+
+ return (current & mask) >> option;
+ }
+
+ return PNG_OPTION_INVALID;
+}
+#endif
diff --git a/drivers/png/png.h b/drivers/png/png.h
index e22ec5c5df..c4f2bab15e 100644
--- a/drivers/png/png.h
+++ b/drivers/png/png.h
@@ -1,8 +1,9 @@
/* png.h - header file for PNG reference library
*
- * libpng version 1.5.7 - December 15, 2011
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * libpng version 1.5.26, December 17, 2015
+ *
+ * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
@@ -11,182 +12,9 @@
* Authors and maintainers:
* libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat
* libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger
- * libpng versions 0.97, January 1998, through 1.5.7 - December 15, 2011: Glenn
+ * libpng versions 0.97, January 1998, through 1.5.26, December 17, 2015:
+ * Glenn Randers-Pehrson.
* See also "Contributing Authors", below.
- *
- * Note about libpng version numbers:
- *
- * Due to various miscommunications, unforeseen code incompatibilities
- * and occasional factors outside the authors' control, version numbering
- * on the library has not always been consistent and straightforward.
- * The following table summarizes matters since version 0.89c, which was
- * the first widely used release:
- *
- * source png.h png.h shared-lib
- * version string int version
- * ------- ------ ----- ----------
- * 0.89c "1.0 beta 3" 0.89 89 1.0.89
- * 0.90 "1.0 beta 4" 0.90 90 0.90 [should have been 2.0.90]
- * 0.95 "1.0 beta 5" 0.95 95 0.95 [should have been 2.0.95]
- * 0.96 "1.0 beta 6" 0.96 96 0.96 [should have been 2.0.96]
- * 0.97b "1.00.97 beta 7" 1.00.97 97 1.0.1 [should have been 2.0.97]
- * 0.97c 0.97 97 2.0.97
- * 0.98 0.98 98 2.0.98
- * 0.99 0.99 98 2.0.99
- * 0.99a-m 0.99 99 2.0.99
- * 1.00 1.00 100 2.1.0 [100 should be 10000]
- * 1.0.0 (from here on, the 100 2.1.0 [100 should be 10000]
- * 1.0.1 png.h string is 10001 2.1.0
- * 1.0.1a-e identical to the 10002 from here on, the shared library
- * 1.0.2 source version) 10002 is 2.V where V is the source code
- * 1.0.2a-b 10003 version, except as noted.
- * 1.0.3 10003
- * 1.0.3a-d 10004
- * 1.0.4 10004
- * 1.0.4a-f 10005
- * 1.0.5 (+ 2 patches) 10005
- * 1.0.5a-d 10006
- * 1.0.5e-r 10100 (not source compatible)
- * 1.0.5s-v 10006 (not binary compatible)
- * 1.0.6 (+ 3 patches) 10006 (still binary incompatible)
- * 1.0.6d-f 10007 (still binary incompatible)
- * 1.0.6g 10007
- * 1.0.6h 10007 10.6h (testing xy.z so-numbering)
- * 1.0.6i 10007 10.6i
- * 1.0.6j 10007 2.1.0.6j (incompatible with 1.0.0)
- * 1.0.7beta11-14 DLLNUM 10007 2.1.0.7beta11-14 (binary compatible)
- * 1.0.7beta15-18 1 10007 2.1.0.7beta15-18 (binary compatible)
- * 1.0.7rc1-2 1 10007 2.1.0.7rc1-2 (binary compatible)
- * 1.0.7 1 10007 (still compatible)
- * 1.0.8beta1-4 1 10008 2.1.0.8beta1-4
- * 1.0.8rc1 1 10008 2.1.0.8rc1
- * 1.0.8 1 10008 2.1.0.8
- * 1.0.9beta1-6 1 10009 2.1.0.9beta1-6
- * 1.0.9rc1 1 10009 2.1.0.9rc1
- * 1.0.9beta7-10 1 10009 2.1.0.9beta7-10
- * 1.0.9rc2 1 10009 2.1.0.9rc2
- * 1.0.9 1 10009 2.1.0.9
- * 1.0.10beta1 1 10010 2.1.0.10beta1
- * 1.0.10rc1 1 10010 2.1.0.10rc1
- * 1.0.10 1 10010 2.1.0.10
- * 1.0.11beta1-3 1 10011 2.1.0.11beta1-3
- * 1.0.11rc1 1 10011 2.1.0.11rc1
- * 1.0.11 1 10011 2.1.0.11
- * 1.0.12beta1-2 2 10012 2.1.0.12beta1-2
- * 1.0.12rc1 2 10012 2.1.0.12rc1
- * 1.0.12 2 10012 2.1.0.12
- * 1.1.0a-f - 10100 2.1.1.0a-f (branch abandoned)
- * 1.2.0beta1-2 2 10200 2.1.2.0beta1-2
- * 1.2.0beta3-5 3 10200 3.1.2.0beta3-5
- * 1.2.0rc1 3 10200 3.1.2.0rc1
- * 1.2.0 3 10200 3.1.2.0
- * 1.2.1beta1-4 3 10201 3.1.2.1beta1-4
- * 1.2.1rc1-2 3 10201 3.1.2.1rc1-2
- * 1.2.1 3 10201 3.1.2.1
- * 1.2.2beta1-6 12 10202 12.so.0.1.2.2beta1-6
- * 1.0.13beta1 10 10013 10.so.0.1.0.13beta1
- * 1.0.13rc1 10 10013 10.so.0.1.0.13rc1
- * 1.2.2rc1 12 10202 12.so.0.1.2.2rc1
- * 1.0.13 10 10013 10.so.0.1.0.13
- * 1.2.2 12 10202 12.so.0.1.2.2
- * 1.2.3rc1-6 12 10203 12.so.0.1.2.3rc1-6
- * 1.2.3 12 10203 12.so.0.1.2.3
- * 1.2.4beta1-3 13 10204 12.so.0.1.2.4beta1-3
- * 1.0.14rc1 13 10014 10.so.0.1.0.14rc1
- * 1.2.4rc1 13 10204 12.so.0.1.2.4rc1
- * 1.0.14 10 10014 10.so.0.1.0.14
- * 1.2.4 13 10204 12.so.0.1.2.4
- * 1.2.5beta1-2 13 10205 12.so.0.1.2.5beta1-2
- * 1.0.15rc1-3 10 10015 10.so.0.1.0.15rc1-3
- * 1.2.5rc1-3 13 10205 12.so.0.1.2.5rc1-3
- * 1.0.15 10 10015 10.so.0.1.0.15
- * 1.2.5 13 10205 12.so.0.1.2.5
- * 1.2.6beta1-4 13 10206 12.so.0.1.2.6beta1-4
- * 1.0.16 10 10016 10.so.0.1.0.16
- * 1.2.6 13 10206 12.so.0.1.2.6
- * 1.2.7beta1-2 13 10207 12.so.0.1.2.7beta1-2
- * 1.0.17rc1 10 10017 12.so.0.1.0.17rc1
- * 1.2.7rc1 13 10207 12.so.0.1.2.7rc1
- * 1.0.17 10 10017 12.so.0.1.0.17
- * 1.2.7 13 10207 12.so.0.1.2.7
- * 1.2.8beta1-5 13 10208 12.so.0.1.2.8beta1-5
- * 1.0.18rc1-5 10 10018 12.so.0.1.0.18rc1-5
- * 1.2.8rc1-5 13 10208 12.so.0.1.2.8rc1-5
- * 1.0.18 10 10018 12.so.0.1.0.18
- * 1.2.8 13 10208 12.so.0.1.2.8
- * 1.2.9beta1-3 13 10209 12.so.0.1.2.9beta1-3
- * 1.2.9beta4-11 13 10209 12.so.0.9[.0]
- * 1.2.9rc1 13 10209 12.so.0.9[.0]
- * 1.2.9 13 10209 12.so.0.9[.0]
- * 1.2.10beta1-7 13 10210 12.so.0.10[.0]
- * 1.2.10rc1-2 13 10210 12.so.0.10[.0]
- * 1.2.10 13 10210 12.so.0.10[.0]
- * 1.4.0beta1-5 14 10400 14.so.0.0[.0]
- * 1.2.11beta1-4 13 10211 12.so.0.11[.0]
- * 1.4.0beta7-8 14 10400 14.so.0.0[.0]
- * 1.2.11 13 10211 12.so.0.11[.0]
- * 1.2.12 13 10212 12.so.0.12[.0]
- * 1.4.0beta9-14 14 10400 14.so.0.0[.0]
- * 1.2.13 13 10213 12.so.0.13[.0]
- * 1.4.0beta15-36 14 10400 14.so.0.0[.0]
- * 1.4.0beta37-87 14 10400 14.so.14.0[.0]
- * 1.4.0rc01 14 10400 14.so.14.0[.0]
- * 1.4.0beta88-109 14 10400 14.so.14.0[.0]
- * 1.4.0rc02-08 14 10400 14.so.14.0[.0]
- * 1.4.0 14 10400 14.so.14.0[.0]
- * 1.4.1beta01-03 14 10401 14.so.14.1[.0]
- * 1.4.1rc01 14 10401 14.so.14.1[.0]
- * 1.4.1beta04-12 14 10401 14.so.14.1[.0]
- * 1.4.1 14 10401 14.so.14.1[.0]
- * 1.4.2 14 10402 14.so.14.2[.0]
- * 1.4.3 14 10403 14.so.14.3[.0]
- * 1.4.4 14 10404 14.so.14.4[.0]
- * 1.5.0beta01-58 15 10500 15.so.15.0[.0]
- * 1.5.0rc01-07 15 10500 15.so.15.0[.0]
- * 1.5.0 15 10500 15.so.15.0[.0]
- * 1.5.1beta01-11 15 10501 15.so.15.1[.0]
- * 1.5.1rc01-02 15 10501 15.so.15.1[.0]
- * 1.5.1 15 10501 15.so.15.1[.0]
- * 1.5.2beta01-03 15 10502 15.so.15.2[.0]
- * 1.5.2rc01-03 15 10502 15.so.15.2[.0]
- * 1.5.2 15 10502 15.so.15.2[.0]
- * 1.5.3beta01-10 15 10503 15.so.15.3[.0]
- * 1.5.3rc01-02 15 10503 15.so.15.3[.0]
- * 1.5.3beta11 15 10503 15.so.15.3[.0]
- * 1.5.3 [omitted]
- * 1.5.4beta01-08 15 10504 15.so.15.4[.0]
- * 1.5.4rc01 15 10504 15.so.15.4[.0]
- * 1.5.4 15 10504 15.so.15.4[.0]
- * 1.5.5beta01-08 15 10505 15.so.15.5[.0]
- * 1.5.5rc01 15 10505 15.so.15.5[.0]
- * 1.5.5 15 10505 15.so.15.5[.0]
- * 1.5.6beta01-07 15 10506 15.so.15.6[.0]
- * 1.5.6rc01-03 15 10506 15.so.15.6[.0]
- * 1.5.6 15 10506 15.so.15.6[.0]
- * 1.5.7beta01-05 15 10507 15.so.15.7[.0]
- * 1.5.7rc01-03 15 10507 15.so.15.7[.0]
- * 1.5.7 15 10507 15.so.15.7[.0]
- *
- * Henceforth the source version will match the shared-library major
- * and minor numbers; the shared-library major version number will be
- * used for changes in backward compatibility, as it is intended. The
- * PNG_LIBPNG_VER macro, which is not used within libpng but is available
- * for applications, is an unsigned integer of the form xyyzz corresponding
- * to the source version x.y.z (leading zeros in y and z). Beta versions
- * were given the previous public release number plus a letter, until
- * version 1.0.6j; from then on they were given the upcoming public
- * release number plus "betaNN" or "rcN".
- *
- * Binary incompatibility exists only when applications make direct access
- * to the info_ptr or png_ptr members through png.h, and the compiled
- * application is loaded with a different version of the library.
- *
- * DLLNUM will change each time there are forward or backward changes
- * in binary compatibility (e.g., when a new feature is added).
- *
- * See libpng-manual.txt or libpng.3 for more information. The PNG
- * specification is available as a W3C Recommendation and as an ISO
- * Specification, <http://www.w3.org/TR/2003/REC-PNG-20031110/
*/
/*
@@ -197,20 +25,16 @@
*
* This code is released under the libpng license.
*
- * libpng versions 1.2.6, August 15, 2004, through 1.5.7, December 15, 2011, are
- * Copyright (c) 2004, 2006-2011 Glenn Randers-Pehrson, and are
- * distributed according to the same disclaimer and license as libpng-1.2.5
- * with the following individual added to the list of Contributing Authors:
- *
- * Cosmin Truta
- *
- * libpng versions 1.0.7, July 1, 2000, through 1.2.5, October 3, 2002, are
- * Copyright (c) 2000-2002 Glenn Randers-Pehrson, and are
- * distributed according to the same disclaimer and license as libpng-1.0.6
- * with the following individuals added to the list of Contributing Authors:
+ * libpng versions 1.0.7, July 1, 2000, through 1.5.26, December 17, 2015, are
+ * Copyright (c) 2000-2002, 2004, 2006-2015 Glenn Randers-Pehrson, are
+ * derived from libpng-1.0.6, and are distributed according to the same
+ * disclaimer and license as libpng-1.0.6 with the following individuals
+ * added to the list of Contributing Authors:
*
* Simon-Pierre Cadieux
* Eric S. Raymond
+ * Mans Rullgard
+ * Cosmin Truta
* Gilles Vollant
*
* and with the following additions to the disclaimer:
@@ -223,18 +47,20 @@
* the user.
*
* libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are
- * Copyright (c) 1998, 1999, 2000 Glenn Randers-Pehrson, and are
- * distributed according to the same disclaimer and license as libpng-0.96,
- * with the following individuals added to the list of Contributing Authors:
+ * Copyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from
+ * libpng-0.96, and are distributed according to the same disclaimer and
+ * license as libpng-0.96, with the following individuals added to the list
+ * of Contributing Authors:
*
* Tom Lane
* Glenn Randers-Pehrson
* Willem van Schaik
*
* libpng versions 0.89, June 1996, through 0.96, May 1997, are
- * Copyright (c) 1996, 1997 Andreas Dilger
- * Distributed according to the same disclaimer and license as libpng-0.88,
- * with the following individuals added to the list of Contributing Authors:
+ * Copyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88,
+ * and are distributed according to the same disclaimer and license as
+ * libpng-0.88, with the following individuals added to the list of
+ * Contributing Authors:
*
* John Bowler
* Kevin Bracey
@@ -244,7 +70,7 @@
* Tom Tanner
*
* libpng versions 0.5, May 1995, through 0.88, January 1996, are
- * Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.
+ * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
*
* For the purposes of this copyright and license, "Contributing Authors"
* is defined as the following set of individuals:
@@ -272,29 +98,32 @@
* 2. Altered versions must be plainly marked as such and must not
* be misrepresented as being the original source.
*
- * 3. This Copyright notice may not be removed or altered from
- * any source or altered source distribution.
+ * 3. This Copyright notice may not be removed or altered from any
+ * source or altered source distribution.
*
* The Contributing Authors and Group 42, Inc. specifically permit, without
* fee, and encourage the use of this source code as a component to
* supporting the PNG file format in commercial products. If you use this
* source code in a product, acknowledgment is not required but would be
* appreciated.
+ *
+ * END OF COPYRIGHT NOTICE, DISCLAIMER, and LICENSE.
*/
/*
* A "png_get_copyright" function is available, for convenient use in "about"
* boxes and the like:
*
- * printf("%s", png_get_copyright(NULL));
+ * printf("%s", png_get_copyright(NULL));
*
* Also, the PNG logo (in PNG format, of course) is supplied in the
* files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31).
*/
/*
- * Libpng is OSI Certified Open Source Software. OSI Certified is a
- * certification mark of the Open Source Initiative.
+ * Libpng is OSI Certified Open Source Software. OSI Certified Open Source is
+ * a certification mark of the Open Source Initiative. OSI has not addressed
+ * the additional disclaimers inserted at version 1.0.7.
*/
/*
@@ -305,17 +134,90 @@
* Thanks to Frank J. T. Wojcik for helping with the documentation.
*/
+/* Note about libpng version numbers:
+ *
+ * Due to various miscommunications, unforeseen code incompatibilities
+ * and occasional factors outside the authors' control, version numbering
+ * on the library has not always been consistent and straightforward.
+ * The following table summarizes matters since version 0.89c, which was
+ * the first widely used release:
+ *
+ * source png.h png.h shared-lib
+ * version string int version
+ * ------- ------ ----- ----------
+ * 0.89c "1.0 beta 3" 0.89 89 1.0.89
+ * 0.90 "1.0 beta 4" 0.90 90 0.90 [should have been 2.0.90]
+ * 0.95 "1.0 beta 5" 0.95 95 0.95 [should have been 2.0.95]
+ * 0.96 "1.0 beta 6" 0.96 96 0.96 [should have been 2.0.96]
+ * 0.97b "1.00.97 beta 7" 1.00.97 97 1.0.1 [should have been 2.0.97]
+ * 0.97c 0.97 97 2.0.97
+ * 0.98 0.98 98 2.0.98
+ * 0.99 0.99 98 2.0.99
+ * 0.99a-m 0.99 99 2.0.99
+ * 1.00 1.00 100 2.1.0 [100 should be 10000]
+ * 1.0.0 (from here on, the 100 2.1.0 [100 should be 10000]
+ * 1.0.1 png.h string is 10001 2.1.0
+ * 1.0.1a-e identical to the 10002 from here on, the shared library
+ * 1.0.2 source version) 10002 is 2.V where V is the source code
+ * 1.0.2a-b 10003 version, except as noted.
+ * 1.0.3 10003
+ * 1.0.3a-d 10004
+ * 1.0.4 10004
+ * 1.0.4a-f 10005
+ * 1.0.5 (+ 2 patches) 10005
+ * 1.0.5a-d 10006
+ * 1.0.5e-r 10100 (not source compatible)
+ * 1.0.5s-v 10006 (not binary compatible)
+ * 1.0.6 (+ 3 patches) 10006 (still binary incompatible)
+ * 1.0.6d-f 10007 (still binary incompatible)
+ * 1.0.6g 10007
+ * 1.0.6h 10007 10.6h (testing xy.z so-numbering)
+ * 1.0.6i 10007 10.6i
+ * 1.0.6j 10007 2.1.0.6j (incompatible with 1.0.0)
+ * 1.0.7beta11-14 DLLNUM 10007 2.1.0.7beta11-14 (binary compatible)
+ * 1.0.7beta15-18 1 10007 2.1.0.7beta15-18 (binary compatible)
+ * 1.0.7rc1-2 1 10007 2.1.0.7rc1-2 (binary compatible)
+ * 1.0.7 1 10007 (still compatible)
+ * ...
+ * 1.0.19 10 10019 10.so.0.19[.0]
+ * ...
+ * 1.2.53 13 10253 12.so.0.53[.0]
+ * ...
+ * 1.5.25 15 10525 15.so.15.25[.0]
+ *
+ * Henceforth the source version will match the shared-library major
+ * and minor numbers; the shared-library major version number will be
+ * used for changes in backward compatibility, as it is intended. The
+ * PNG_LIBPNG_VER macro, which is not used within libpng but is available
+ * for applications, is an unsigned integer of the form xyyzz corresponding
+ * to the source version x.y.z (leading zeros in y and z). Beta versions
+ * were given the previous public release number plus a letter, until
+ * version 1.0.6j; from then on they were given the upcoming public
+ * release number plus "betaNN" or "rcNN".
+ *
+ * Binary incompatibility exists only when applications make direct access
+ * to the info_ptr or png_ptr members through png.h, and the compiled
+ * application is loaded with a different version of the library.
+ *
+ * DLLNUM will change each time there are forward or backward changes
+ * in binary compatibility (e.g., when a new feature is added).
+ *
+ * See libpng.txt or libpng.3 for more information. The PNG specification
+ * is available as a W3C Recommendation and as an ISO Specification,
+ * <http://www.w3.org/TR/2003/REC-PNG-20031110/
+ */
+
/*
* Y2K compliance in libpng:
* =========================
*
- * December 15, 2011
+ * December 17, 2015
*
* Since the PNG Development group is an ad-hoc body, we can't make
* an official declaration.
*
* This is your unofficial assurance that libpng from version 0.71 and
- * upward through 1.5.7 are Y2K compliant. It is my belief that
+ * upward through 1.5.26 are Y2K compliant. It is my belief that
* earlier versions were also Y2K compliant.
*
* Libpng only has two year fields. One is a 2-byte unsigned integer
@@ -326,7 +228,8 @@
* "png_uint_16 year" in png_time_struct.
*
* The string is
- * "png_char time_buffer" in png_struct
+ * "char time_buffer[29]" in png_struct. This will be no
+ * longer used in libpng-1.6.0 and will be removed from libpng-1.7.0.
*
* There are seven time-related functions:
* png.c: png_convert_to_rfc_1123() in png.c
@@ -366,16 +269,18 @@
/* This is not the place to learn how to use libpng. The file libpng-manual.txt
* describes how to use libpng, and the file example.c summarizes it
* with some code on which to build. This file is useful for looking
- * at the actual function definitions and structure components.
+ * at the actual function definitions and structure components. If that
+ * file has been stripped from your copy of libpng, you can find it at
+ * <http://www.libpng.org/pub/png/libpng-manual.txt>
*
* If you just need to read a PNG file and don't want to read the documentation
* skip to the end of this file and read the section entitled 'simplified API'.
*/
/* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.5.7"
+#define PNG_LIBPNG_VER_STRING "1.5.26"
#define PNG_HEADER_VERSION_STRING \
- " libpng version 1.5.7 - December 15, 2011\n"
+ " libpng version 1.5.26 - December 17, 2015\n"
#define PNG_LIBPNG_VER_SONUM 15
#define PNG_LIBPNG_VER_DLLNUM 15
@@ -383,7 +288,7 @@
/* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
#define PNG_LIBPNG_VER_MAJOR 1
#define PNG_LIBPNG_VER_MINOR 5
-#define PNG_LIBPNG_VER_RELEASE 7
+#define PNG_LIBPNG_VER_RELEASE 26
/* This should match the numeric part of the final component of
* PNG_LIBPNG_VER_STRING, omitting any leading zero:
@@ -406,7 +311,7 @@
#define PNG_LIBPNG_BUILD_SPECIAL 32 /* Cannot be OR'ed with
PNG_LIBPNG_BUILD_PRIVATE */
-#define PNG_LIBPNG_BUILD_BASE_TYPE PNG_LIBPNG_BUILD_BETA
+#define PNG_LIBPNG_BUILD_BASE_TYPE PNG_LIBPNG_BUILD_STABLE
/* Careful here. At one time, Guy wanted to use 082, but that would be octal.
* We must not include leading zeros.
@@ -414,7 +319,7 @@
* version 1.0.0 was mis-numbered 100 instead of 10000). From
* version 1.0.1 it's xxyyzz, where x=major, y=minor, z=release
*/
-#define PNG_LIBPNG_VER 10507 /* 1.5.7 */
+#define PNG_LIBPNG_VER 10526 /* 1.5.26 */
/* Library configuration: these options cannot be changed after
* the library has been built.
@@ -447,7 +352,7 @@
/* Machine specific configuration. */
# include "pngconf.h"
-#endif
+#endif /* PNG_VERSION_INFO_ONLY */
/*
* Added at libpng-1.2.8
@@ -536,7 +441,7 @@ extern "C" {
/* This triggers a compiler error in png.c, if png.c and png.h
* do not agree upon the version number.
*/
-typedef char* png_libpng_version_1_5_7;
+typedef char* png_libpng_version_1_5_26;
/* Three color definitions. The order of the red, green, and blue, (and the
* exact size) is not important, although the size of the fields need to
@@ -1007,11 +912,13 @@ PNG_EXPORTA(5, png_structp, png_create_write_struct,
png_error_ptr warn_fn),
PNG_ALLOCATED);
+#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
PNG_EXPORT(6, png_size_t, png_get_compression_buffer_size,
(png_const_structp png_ptr));
PNG_EXPORT(7, void, png_set_compression_buffer_size, (png_structp png_ptr,
png_size_t size));
+#endif /* WRITE_CUSTOMIZE_COMPRESSION */
/* Moved from pngconf.h in 1.4.0 and modified to ensure setjmp/longjmp
* match up.
@@ -1145,9 +1052,9 @@ PNG_EXPORT(31, void, png_set_gray_to_rgb, (png_structp png_ptr));
#define PNG_RGB_TO_GRAY_DEFAULT (-1)/*for red/green coefficients*/
PNG_FP_EXPORT(32, void, png_set_rgb_to_gray, (png_structp png_ptr,
- int error_action, double red, double green));
+ int error_action, double red, double green))
PNG_FIXED_EXPORT(33, void, png_set_rgb_to_gray_fixed, (png_structp png_ptr,
- int error_action, png_fixed_point red, png_fixed_point green));
+ int error_action, png_fixed_point red, png_fixed_point green))
PNG_EXPORT(34, png_byte, png_get_rgb_to_gray_status, (png_const_structp
png_ptr));
@@ -1215,9 +1122,9 @@ PNG_EXPORT(35, void, png_build_grayscale_palette, (int bit_depth,
#define PNG_ALPHA_BROKEN 3 /* the alpha channel is gamma encoded */
PNG_FP_EXPORT(227, void, png_set_alpha_mode, (png_structp png_ptr, int mode,
- double output_gamma));
+ double output_gamma))
PNG_FIXED_EXPORT(228, void, png_set_alpha_mode_fixed, (png_structp png_ptr,
- int mode, png_fixed_point output_gamma));
+ int mode, png_fixed_point output_gamma))
#endif
#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_ALPHA_MODE_SUPPORTED)
@@ -1440,10 +1347,10 @@ PNG_EXPORT(46, void, png_set_invert_mono, (png_structp png_ptr));
*/
PNG_FP_EXPORT(47, void, png_set_background, (png_structp png_ptr,
png_const_color_16p background_color, int background_gamma_code,
- int need_expand, double background_gamma));
+ int need_expand, double background_gamma))
PNG_FIXED_EXPORT(215, void, png_set_background_fixed, (png_structp png_ptr,
png_const_color_16p background_color, int background_gamma_code,
- int need_expand, png_fixed_point background_gamma));
+ int need_expand, png_fixed_point background_gamma))
#endif
#ifdef PNG_READ_BACKGROUND_SUPPORTED
# define PNG_BACKGROUND_GAMMA_UNKNOWN 0
@@ -1492,9 +1399,9 @@ PNG_EXPORT(49, void, png_set_quantize,
*/
PNG_FP_EXPORT(50, void, png_set_gamma,
(png_structp png_ptr, double screen_gamma,
- double override_file_gamma));
+ double override_file_gamma))
PNG_FIXED_EXPORT(208, void, png_set_gamma_fixed, (png_structp png_ptr,
- png_fixed_point screen_gamma, png_fixed_point override_file_gamma));
+ png_fixed_point screen_gamma, png_fixed_point override_file_gamma))
#endif
#ifdef PNG_WRITE_FLUSH_SUPPORTED
@@ -1623,47 +1530,17 @@ PNG_EXPORT(67, void, png_set_filter,
#define PNG_FILTER_VALUE_PAETH 4
#define PNG_FILTER_VALUE_LAST 5
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* EXPERIMENTAL */
-/* The "heuristic_method" is given by one of the PNG_FILTER_HEURISTIC_
- * defines, either the default (minimum-sum-of-absolute-differences), or
- * the experimental method (weighted-minimum-sum-of-absolute-differences).
- *
- * Weights are factors >= 1.0, indicating how important it is to keep the
- * filter type consistent between rows. Larger numbers mean the current
- * filter is that many times as likely to be the same as the "num_weights"
- * previous filters. This is cumulative for each previous row with a weight.
- * There needs to be "num_weights" values in "filter_weights", or it can be
- * NULL if the weights aren't being specified. Weights have no influence on
- * the selection of the first row filter. Well chosen weights can (in theory)
- * improve the compression for a given image.
- *
- * Costs are factors >= 1.0 indicating the relative decoding costs of a
- * filter type. Higher costs indicate more decoding expense, and are
- * therefore less likely to be selected over a filter with lower computational
- * costs. There needs to be a value in "filter_costs" for each valid filter
- * type (given by PNG_FILTER_VALUE_LAST), or it can be NULL if you aren't
- * setting the costs. Costs try to improve the speed of decompression without
- * unduly increasing the compressed image size.
- *
- * A negative weight or cost indicates the default value is to be used, and
- * values in the range [0.0, 1.0) indicate the value is to remain unchanged.
- * The default values for both weights and costs are currently 1.0, but may
- * change if good general weighting/cost heuristics can be found. If both
- * the weights and costs are set to 1.0, this degenerates the WEIGHTED method
- * to the UNWEIGHTED method, but with added encoding time/computation.
- */
+#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* DEPRECATED */
PNG_FP_EXPORT(68, void, png_set_filter_heuristics, (png_structp png_ptr,
int heuristic_method, int num_weights, png_const_doublep filter_weights,
- png_const_doublep filter_costs));
+ png_const_doublep filter_costs))
PNG_FIXED_EXPORT(209, void, png_set_filter_heuristics_fixed,
(png_structp png_ptr,
int heuristic_method, int num_weights, png_const_fixed_point_p
- filter_weights, png_const_fixed_point_p filter_costs));
+ filter_weights, png_const_fixed_point_p filter_costs))
#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
-/* Heuristic used for row filter selection. These defines should NOT be
- * changed.
- */
+/* The following are no longer used and will be removed from libpng-1.7: */
#define PNG_FILTER_HEURISTIC_DEFAULT 0 /* Currently "UNWEIGHTED" */
#define PNG_FILTER_HEURISTIC_UNWEIGHTED 1 /* Used by libpng < 0.95 */
#define PNG_FILTER_HEURISTIC_WEIGHTED 2 /* Experimental feature */
@@ -1677,6 +1554,7 @@ PNG_FIXED_EXPORT(209, void, png_set_filter_heuristics_fixed,
* for PNG images, and do considerably fewer caclulations. In the future,
* these values may not correspond directly to the zlib compression levels.
*/
+#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
PNG_EXPORT(69, void, png_set_compression_level,
(png_structp png_ptr, int level));
@@ -1694,7 +1572,7 @@ PNG_EXPORT(72, void, png_set_compression_window_bits, (png_structp png_ptr,
PNG_EXPORT(73, void, png_set_compression_method, (png_structp png_ptr,
int method));
-#endif
+#endif /* WRITE_CUSTOMIZE_COMPRESSION */
#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
/* Also set zlib parameters for compressing non-IDAT chunks */
@@ -1716,6 +1594,7 @@ PNG_EXPORT(225, void, png_set_text_compression_window_bits, (png_structp
PNG_EXPORT(226, void, png_set_text_compression_method, (png_structp png_ptr,
int method));
#endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */
+#endif /* WRITE */
/* These next functions are called for input/output, memory, and error
* handling. They are in the file pngrio.c, pngwio.c, and pngerror.c,
@@ -1927,6 +1806,8 @@ PNG_EXPORTA(103, void, png_chunk_error, (png_structp png_ptr,
#else
/* Fatal error in PNG image of libpng - can't continue */
PNG_EXPORTA(104, void, png_err, (png_structp png_ptr), PNG_NORETURN);
+# define png_error(s1,s2) png_err(s1)
+# define png_chunk_error(s1,s2) png_err(s1)
#endif
#ifdef PNG_WARNINGS_SUPPORTED
@@ -1937,6 +1818,9 @@ PNG_EXPORT(105, void, png_warning, (png_structp png_ptr,
/* Non-fatal error in libpng, chunk name is prepended to message. */
PNG_EXPORT(106, void, png_chunk_warning, (png_structp png_ptr,
png_const_charp warning_message));
+#else
+# define png_warning(s1,s2) ((void)(s1))
+# define png_chunk_warning(s1,s2) ((void)(s1))
#endif
#ifdef PNG_BENIGN_ERRORS_SUPPORTED
@@ -2040,9 +1924,9 @@ PNG_EXPORT(124, png_uint_32, png_get_y_pixels_per_meter,
/* Returns pixel aspect ratio, computed from pHYs chunk data. */
PNG_FP_EXPORT(125, float, png_get_pixel_aspect_ratio,
- (png_const_structp png_ptr, png_const_infop info_ptr));
+ (png_const_structp png_ptr, png_const_infop info_ptr))
PNG_FIXED_EXPORT(210, png_fixed_point, png_get_pixel_aspect_ratio_fixed,
- (png_const_structp png_ptr, png_const_infop info_ptr));
+ (png_const_structp png_ptr, png_const_infop info_ptr))
/* Returns image x, y offset in pixels or microns, from oFFs chunk data. */
PNG_EXPORT(126, png_int_32, png_get_x_offset_pixels,
@@ -2075,11 +1959,11 @@ PNG_EXPORT(132, void, png_set_bKGD, (png_structp png_ptr, png_infop info_ptr,
PNG_FP_EXPORT(133, png_uint_32, png_get_cHRM, (png_const_structp png_ptr,
png_const_infop info_ptr, double *white_x, double *white_y, double *red_x,
double *red_y, double *green_x, double *green_y, double *blue_x,
- double *blue_y));
+ double *blue_y))
PNG_FP_EXPORT(230, png_uint_32, png_get_cHRM_XYZ, (png_structp png_ptr,
png_const_infop info_ptr, double *red_X, double *red_Y, double *red_Z,
double *green_X, double *green_Y, double *green_Z, double *blue_X,
- double *blue_Y, double *blue_Z));
+ double *blue_Y, double *blue_Z))
#ifdef PNG_FIXED_POINT_SUPPORTED /* Otherwise not implemented */
PNG_FIXED_EXPORT(134, png_uint_32, png_get_cHRM_fixed,
(png_const_structp png_ptr,
@@ -2087,7 +1971,7 @@ PNG_FIXED_EXPORT(134, png_uint_32, png_get_cHRM_fixed,
png_fixed_point *int_white_y, png_fixed_point *int_red_x,
png_fixed_point *int_red_y, png_fixed_point *int_green_x,
png_fixed_point *int_green_y, png_fixed_point *int_blue_x,
- png_fixed_point *int_blue_y));
+ png_fixed_point *int_blue_y))
#endif
PNG_FIXED_EXPORT(231, png_uint_32, png_get_cHRM_XYZ_fixed,
(png_structp png_ptr, png_const_infop info_ptr,
@@ -2095,46 +1979,46 @@ PNG_FIXED_EXPORT(231, png_uint_32, png_get_cHRM_XYZ_fixed,
png_fixed_point *int_red_Z, png_fixed_point *int_green_X,
png_fixed_point *int_green_Y, png_fixed_point *int_green_Z,
png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y,
- png_fixed_point *int_blue_Z));
+ png_fixed_point *int_blue_Z))
#endif
#ifdef PNG_cHRM_SUPPORTED
PNG_FP_EXPORT(135, void, png_set_cHRM,
(png_structp png_ptr, png_infop info_ptr,
double white_x, double white_y, double red_x, double red_y, double green_x,
- double green_y, double blue_x, double blue_y));
+ double green_y, double blue_x, double blue_y))
PNG_FP_EXPORT(232, void, png_set_cHRM_XYZ, (png_structp png_ptr,
png_infop info_ptr, double red_X, double red_Y, double red_Z,
double green_X, double green_Y, double green_Z, double blue_X,
- double blue_Y, double blue_Z));
+ double blue_Y, double blue_Z))
PNG_FIXED_EXPORT(136, void, png_set_cHRM_fixed, (png_structp png_ptr,
png_infop info_ptr, png_fixed_point int_white_x,
png_fixed_point int_white_y, png_fixed_point int_red_x,
png_fixed_point int_red_y, png_fixed_point int_green_x,
png_fixed_point int_green_y, png_fixed_point int_blue_x,
- png_fixed_point int_blue_y));
+ png_fixed_point int_blue_y))
PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, (png_structp png_ptr,
png_infop info_ptr, png_fixed_point int_red_X, png_fixed_point int_red_Y,
png_fixed_point int_red_Z, png_fixed_point int_green_X,
png_fixed_point int_green_Y, png_fixed_point int_green_Z,
png_fixed_point int_blue_X, png_fixed_point int_blue_Y,
- png_fixed_point int_blue_Z));
+ png_fixed_point int_blue_Z))
#endif
#ifdef PNG_gAMA_SUPPORTED
PNG_FP_EXPORT(137, png_uint_32, png_get_gAMA,
(png_const_structp png_ptr, png_const_infop info_ptr,
- double *file_gamma));
+ double *file_gamma))
PNG_FIXED_EXPORT(138, png_uint_32, png_get_gAMA_fixed,
(png_const_structp png_ptr, png_const_infop info_ptr,
- png_fixed_point *int_file_gamma));
+ png_fixed_point *int_file_gamma))
#endif
#ifdef PNG_gAMA_SUPPORTED
PNG_FP_EXPORT(139, void, png_set_gAMA, (png_structp png_ptr,
- png_infop info_ptr, double file_gamma));
+ png_infop info_ptr, double file_gamma))
PNG_FIXED_EXPORT(140, void, png_set_gAMA_fixed, (png_structp png_ptr,
- png_infop info_ptr, png_fixed_point int_file_gamma));
+ png_infop info_ptr, png_fixed_point int_file_gamma))
#endif
#ifdef PNG_hIST_SUPPORTED
@@ -2300,7 +2184,7 @@ PNG_EXPORT(167, void, png_set_tRNS,
#ifdef PNG_sCAL_SUPPORTED
PNG_FP_EXPORT(168, png_uint_32, png_get_sCAL,
(png_const_structp png_ptr, png_const_infop info_ptr,
- int *unit, double *width, double *height));
+ int *unit, double *width, double *height))
#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED
/* NOTE: this API is currently implemented using floating point arithmetic,
* consequently it can only be used on systems with floating point support.
@@ -2310,7 +2194,7 @@ PNG_FP_EXPORT(168, png_uint_32, png_get_sCAL,
PNG_FIXED_EXPORT(214, png_uint_32, png_get_sCAL_fixed,
(png_structp png_ptr, png_const_infop info_ptr, int *unit,
png_fixed_point *width,
- png_fixed_point *height));
+ png_fixed_point *height))
#endif
PNG_EXPORT(169, png_uint_32, png_get_sCAL_s,
(png_const_structp png_ptr, png_const_infop info_ptr,
@@ -2318,10 +2202,10 @@ PNG_EXPORT(169, png_uint_32, png_get_sCAL_s,
PNG_FP_EXPORT(170, void, png_set_sCAL,
(png_structp png_ptr, png_infop info_ptr,
- int unit, double width, double height));
+ int unit, double width, double height))
PNG_FIXED_EXPORT(213, void, png_set_sCAL_fixed, (png_structp png_ptr,
png_infop info_ptr, int unit, png_fixed_point width,
- png_fixed_point height));
+ png_fixed_point height))
PNG_EXPORT(171, void, png_set_sCAL_s,
(png_structp png_ptr, png_infop info_ptr,
int unit, png_const_charp swidth, png_const_charp sheight));
@@ -2434,17 +2318,17 @@ PNG_EXPORT(195, png_uint_32, png_get_y_pixels_per_inch,
(png_const_structp png_ptr, png_const_infop info_ptr));
PNG_FP_EXPORT(196, float, png_get_x_offset_inches,
- (png_const_structp png_ptr, png_const_infop info_ptr));
+ (png_const_structp png_ptr, png_const_infop info_ptr))
#ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */
PNG_FIXED_EXPORT(211, png_fixed_point, png_get_x_offset_inches_fixed,
- (png_structp png_ptr, png_const_infop info_ptr));
+ (png_structp png_ptr, png_const_infop info_ptr))
#endif
PNG_FP_EXPORT(197, float, png_get_y_offset_inches, (png_const_structp png_ptr,
- png_const_infop info_ptr));
+ png_const_infop info_ptr))
#ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */
PNG_FIXED_EXPORT(212, png_fixed_point, png_get_y_offset_inches_fixed,
- (png_structp png_ptr, png_const_infop info_ptr));
+ (png_structp png_ptr, png_const_infop info_ptr))
#endif
# ifdef PNG_pHYs_SUPPORTED
@@ -2627,10 +2511,60 @@ PNG_EXPORT(207, void, png_save_uint_16, (png_bytep buf, unsigned int i));
# define png_get_int_32(buf) \
((png_int_32)((*(buf) & 0x80) \
- ? -((png_int_32)((png_get_uint_32(buf) ^ 0xffffffffL) + 1)) \
+ ? -((png_int_32)(((png_get_uint_32(buf)^0xffffffffU)+1U)&0x7fffffffU)) \
: (png_int_32)png_get_uint_32(buf)))
#endif
+#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
+PNG_EXPORT(234, void, png_set_check_for_invalid_index, (png_structp png_ptr,
+ int allowed));
+# ifdef PNG_GET_PALETTE_MAX_SUPPORTED
+PNG_EXPORT(235, int, png_get_palette_max, (png_const_structp png_ptr,
+ png_const_infop info_ptr));
+# endif
+#endif /* CHECK_FOR_INVALID_INDEX */
+
+/*******************************************************************************
+ * IMPLEMENTATION OPTIONS
+ *******************************************************************************
+ *
+ * Support for arbitrary implementation-specific optimizations. The API allows
+ * particular options to be turned on or off. 'Option' is the number of the
+ * option and 'onoff' is 0 (off) or non-0 (on). The value returned is given
+ * by the PNG_OPTION_ defines below.
+ *
+ * HARDWARE: normally hardware capabilites, such as the Intel SSE instructions,
+ * are detected at run time, however sometimes it may be impossible
+ * to do this in user mode, in which case it is necessary to discover
+ * the capabilities in an OS specific way. Such capabilities are
+ * listed here when libpng has support for them and must be turned
+ * ON by the application if present.
+ *
+ * SOFTWARE: sometimes software optimizations actually result in performance
+ * decrease on some architectures or systems, or with some sets of
+ * PNG images. 'Software' options allow such optimizations to be
+ * selected at run time.
+ */
+#ifdef PNG_SET_OPTION_SUPPORTED
+#ifdef PNG_ARM_NEON_API_SUPPORTED
+# define PNG_ARM_NEON 0 /* HARDWARE: ARM Neon SIMD instructions supported */
+#endif
+#define PNG_OPTION_NEXT 2 /* Next option - numbers must be even */
+
+/* Return values: NOTE: there are four values and 'off' is *not* zero */
+#define PNG_OPTION_UNSET 0 /* Unset - defaults to off */
+#define PNG_OPTION_INVALID 1 /* Option number out of range */
+#define PNG_OPTION_OFF 2
+#define PNG_OPTION_ON 3
+
+PNG_EXPORT(236, int, png_set_option, (png_structp png_ptr, int option,
+ int onoff));
+#endif
+
+/*******************************************************************************
+ * END OF HARDWARE OPTIONS
+ ******************************************************************************/
+
/* Maintainer: Put new public prototypes here ^, in libpng.3, and project
* defs
*/
@@ -2640,7 +2574,7 @@ PNG_EXPORT(207, void, png_save_uint_16, (png_bytep buf, unsigned int i));
* scripts/symbols.def as well.
*/
#ifdef PNG_EXPORT_LAST_ORDINAL
- PNG_EXPORT_LAST_ORDINAL(233);
+ PNG_EXPORT_LAST_ORDINAL(236);
#endif
#ifdef __cplusplus
diff --git a/drivers/png/pngconf.h b/drivers/png/pngconf.h
index d07054de28..62588337d0 100644
--- a/drivers/png/pngconf.h
+++ b/drivers/png/pngconf.h
@@ -1,9 +1,9 @@
/* pngconf.h - machine configurable file for libpng
*
- * libpng version 1.5.7 - December 15, 2011
+ * libpng version 1.5.26, December 17, 2015
*
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Copyright (c) 1998-2002,2004,2006-2013 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
@@ -11,9 +11,7 @@
* For conditions of distribution and use, see the disclaimer
* and license in png.h
*
- */
-
-/* Any machine specific code is near the front of this file, so if you
+ * Any machine specific code is near the front of this file, so if you
* are configuring libpng for a machine, you may want to read the section
* starting here down to where it starts to typedef png_color, png_text,
* and png_info.
@@ -25,7 +23,7 @@
#ifndef PNG_BUILDING_SYMBOL_TABLE
/* PNG_NO_LIMITS_H may be used to turn off the use of the standard C
* definition file for machine specific limits, this may impact the
- * correctness of the definitons below (see uses of INT_MAX).
+ * correctness of the definitions below (see uses of INT_MAX).
*/
# ifndef PNG_NO_LIMITS_H
# include <limits.h>
@@ -51,8 +49,8 @@
/* This controls optimization of the reading of 16 and 32 bit values
* from PNG files. It can be set on a per-app-file basis - it
- * just changes whether a macro is used to the function is called.
- * The library builder sets the default, if read functions are not
+ * just changes whether a macro is used when the function is called.
+ * The library builder sets the default; if read functions are not
* built into the library the macro implementation is forced on.
*/
#ifndef PNG_READ_INT_FUNCTIONS_SUPPORTED
@@ -177,18 +175,16 @@
* ==========================
* This code is used at build time to find PNG_IMPEXP, the API settings
* and PNG_EXPORT_TYPE(), it may also set a macro to indicate the DLL
- * import processing is possible. On Windows/x86 systems it also sets
+ * import processing is possible. On Windows systems it also sets
* compiler-specific macros to the values required to change the calling
* conventions of the various functions.
*/
-#if ( defined(_Windows) || defined(_WINDOWS) || defined(WIN32) ||\
- defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) ) &&\
- ( defined(_X86_) || defined(_X64_) || defined(_M_IX86) ||\
- defined(_M_X64) || defined(_M_IA64) )
- /* Windows system (DOS doesn't support DLLs) running on x86/x64. Includes
- * builds under Cygwin or MinGW. Also includes Watcom builds but these need
- * special treatment because they are not compatible with GCC or Visual C
- * because of different calling conventions.
+#if defined(_Windows) || defined(_WINDOWS) || defined(WIN32) ||\
+ defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__)
+ /* Windows system (DOS doesn't support DLLs). Includes builds under Cygwin or
+ * MinGW on any architecture currently supported by Windows. Also includes
+ * Watcom builds but these need special treatment because they are not
+ * compatible with GCC or Visual C because of different calling conventions.
*/
# if PNG_API_RULE == 2
/* If this line results in an error, either because __watcall is not
@@ -199,9 +195,12 @@
# define PNGCAPI __watcall
# endif
-# if defined(__GNUC__) || (defined (_MSC_VER) && (_MSC_VER >= 800))
+# if defined(__GNUC__) || (defined(_MSC_VER) && (_MSC_VER >= 800))
# define PNGCAPI __cdecl
# if PNG_API_RULE == 1
+ /* If this line results in an error __stdcall is not understood and
+ * PNG_API_RULE should not have been set to '1'.
+ */
# define PNGAPI __stdcall
# endif
# else
@@ -239,7 +238,7 @@
# endif
# endif /* compiler */
-#else /* !Windows/x86 */
+#else /* !Windows */
# if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__)
# define PNGAPI _System
# else /* !Windows/x86 && !OS/2 */
@@ -337,6 +336,7 @@
* functions in png.h will generate compiler warnings. Added at libpng
* version 1.2.41.
*/
+
# if defined(__GNUC__)
# ifndef PNG_USE_RESULT
# define PNG_USE_RESULT __attribute__((__warn_unused_result__))
@@ -344,21 +344,23 @@
# ifndef PNG_NORETURN
# define PNG_NORETURN __attribute__((__noreturn__))
# endif
-# ifndef PNG_ALLOCATED
-# define PNG_ALLOCATED __attribute__((__malloc__))
-# endif
-# ifndef PNG_DEPRECATED
-# define PNG_DEPRECATED __attribute__((__deprecated__))
-# endif
-# ifndef PNG_PRIVATE
-# if 0 /* Doesn't work so we use deprecated instead*/
-# define PNG_PRIVATE \
- __attribute__((warning("This function is not exported by libpng.")))
-# else
-# define PNG_PRIVATE \
- __attribute__((__deprecated__))
+# if __GNUC__ >= 3
+# ifndef PNG_ALLOCATED
+# define PNG_ALLOCATED __attribute__((__malloc__))
# endif
-# endif
+# ifndef PNG_DEPRECATED
+# define PNG_DEPRECATED __attribute__((__deprecated__))
+# endif
+# ifndef PNG_PRIVATE
+# if 0 /* Doesn't work so we use deprecated instead*/
+# define PNG_PRIVATE \
+ __attribute__((warning("This function is not exported by libpng.")))
+# else
+# define PNG_PRIVATE \
+ __attribute__((__deprecated__))
+# endif
+# endif
+# endif /* __GNUC__ >= 3 */
# endif /* __GNUC__ */
# if defined(_MSC_VER) && (_MSC_VER >= 1300)
@@ -400,7 +402,7 @@
#ifndef PNG_FP_EXPORT /* A floating point API. */
# ifdef PNG_FLOATING_POINT_SUPPORTED
# define PNG_FP_EXPORT(ordinal, type, name, args)\
- PNG_EXPORT(ordinal, type, name, args)
+ PNG_EXPORT(ordinal, type, name, args);
# else /* No floating point APIs */
# define PNG_FP_EXPORT(ordinal, type, name, args)
# endif
@@ -408,7 +410,7 @@
#ifndef PNG_FIXED_EXPORT /* A fixed point API. */
# ifdef PNG_FIXED_POINT_SUPPORTED
# define PNG_FIXED_EXPORT(ordinal, type, name, args)\
- PNG_EXPORT(ordinal, type, name, args)
+ PNG_EXPORT(ordinal, type, name, args);
# else /* No fixed point APIs */
# define PNG_FIXED_EXPORT(ordinal, type, name, args)
# endif
diff --git a/drivers/png/pngdebug.h b/drivers/png/pngdebug.h
index 16f81fdd14..020369f061 100644
--- a/drivers/png/pngdebug.h
+++ b/drivers/png/pngdebug.h
@@ -1,12 +1,11 @@
/* pngdebug.h - Debugging macros for libpng, also used in pngtest.c
*
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.18 [February 6, 2014]
+ * Copyright (c) 1998-2002,2004,2006-2014 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
- * Last changed in libpng 1.5.0 [January 6, 2011]
- *
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
* and license in png.h
@@ -25,7 +24,7 @@
* (actually ((void)0)).
*
* level: level of detail of message, starting at 0. A level 'n'
- * message is preceded by 'n' tab characters (not implemented
+ * message is preceded by 'n' 3-space indentations (not implemented
* on Microsoft compilers unless PNG_DEBUG_FILE is also
* defined, to allow debug DLL compilation with no standard IO).
* message: a printf(3) style text string. A trailing '\n' is added
@@ -77,32 +76,29 @@
# endif /* PNG_DEBUG_FILE */
# if (PNG_DEBUG > 1)
-/* Note: ["%s"m PNG_STRING_NEWLINE] probably does not work on
- * non-ISO compilers
- */
# ifdef __STDC__
# ifndef png_debug
# define png_debug(l,m) \
do { \
int num_tabs=l; \
- fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \
- (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":"")))); \
+ fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? " " : \
+ (num_tabs==2 ? " " : (num_tabs>2 ? " " : "")))); \
} while (0)
# endif
# ifndef png_debug1
# define png_debug1(l,m,p1) \
do { \
int num_tabs=l; \
- fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \
- (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1); \
+ fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? " " : \
+ (num_tabs==2 ? " " : (num_tabs>2 ? " " : ""))),p1); \
} while (0)
# endif
# ifndef png_debug2
# define png_debug2(l,m,p1,p2) \
do { \
int num_tabs=l; \
- fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \
- (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1,p2); \
+ fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? " " : \
+ (num_tabs==2 ? " " : (num_tabs>2 ? " " : ""))),p1,p2);\
} while (0)
# endif
# else /* __STDC __ */
diff --git a/drivers/png/pngerror.c b/drivers/png/pngerror.c
index 7604bddf18..372d1b6fbd 100644
--- a/drivers/png/pngerror.c
+++ b/drivers/png/pngerror.c
@@ -1,8 +1,8 @@
/* pngerror.c - stub functions for i/o and memory allocation
*
- * Last changed in libpng 1.5.7 [December 15, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.19 [August 21, 2014]
+ * Copyright (c) 1998-2002,2004,2006-2014 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
@@ -161,7 +161,7 @@ png_format_number(png_const_charp start, png_charp end, int format,
case PNG_NUMBER_FORMAT_02u:
/* Expects at least 2 digits. */
mincount = 2;
- /* fall through */
+ /* FALL THROUGH */
case PNG_NUMBER_FORMAT_u:
*--end = digits[number % 10];
@@ -171,7 +171,7 @@ png_format_number(png_const_charp start, png_charp end, int format,
case PNG_NUMBER_FORMAT_02x:
/* This format expects at least two digits */
mincount = 2;
- /* fall through */
+ /* FALL THROUGH */
case PNG_NUMBER_FORMAT_x:
*--end = digits[number & 0xf];
@@ -193,7 +193,7 @@ png_format_number(png_const_charp start, png_charp end, int format,
* drop the decimal point. If the number is a true zero handle that
* here.
*/
- if (output)
+ if (output != 0)
*--end = '.';
else if (number == 0) /* and !output */
*--end = '0';
@@ -281,35 +281,40 @@ void
png_formatted_warning(png_structp png_ptr, png_warning_parameters p,
png_const_charp message)
{
- /* The internal buffer is just 128 bytes - enough for all our messages,
- * overflow doesn't happen because this code checks!
+ /* The internal buffer is just 192 bytes - enough for all our messages,
+ * overflow doesn't happen because this code checks! If someone figures
+ * out how to send us a message longer than 192 bytes, all that will
+ * happen is that the message will be truncated appropriately.
*/
- size_t i;
- char msg[128];
-
- for (i=0; i<(sizeof msg)-1 && *message != '\0'; ++i)
+ size_t i = 0; /* Index in the msg[] buffer: */
+ char msg[192];
+
+ /* Each iteration through the following loop writes at most one character
+ * to msg[i++] then returns here to validate that there is still space for
+ * the trailing '\0'. It may (in the case of a parameter) read more than
+ * one character from message[]; it must check for '\0' and continue to the
+ * test if it finds the end of string.
+ */
+ while (i<(sizeof msg)-1 && *message != '\0')
{
- if (*message == '@')
+ /* '@' at end of string is now just printed (previously it was skipped);
+ * it is an error in the calling code to terminate the string with @.
+ */
+ if (p != NULL && *message == '@' && message[1] != '\0')
{
- int parameter = -1;
- switch (*++message)
- {
- case '1':
- parameter = 0;
- break;
-
- case '2':
- parameter = 1;
- break;
+ int parameter_char = *++message; /* Consume the '@' */
+ static const char valid_parameters[] = "123456789";
+ int parameter = 0;
- case '\0':
- continue; /* To break out of the for loop above. */
-
- default:
- break;
- }
+ /* Search for the parameter digit, the index in the string is the
+ * parameter to use.
+ */
+ while (valid_parameters[parameter] != parameter_char &&
+ valid_parameters[parameter] != '\0')
+ ++parameter;
- if (parameter >= 0 && parameter < PNG_WARNING_PARAMETER_COUNT)
+ /* If the parameter digit is out of range it will just get printed. */
+ if (parameter < PNG_WARNING_PARAMETER_COUNT)
{
/* Append this parameter */
png_const_charp parm = p[parameter];
@@ -319,28 +324,32 @@ png_formatted_warning(png_structp png_ptr, png_warning_parameters p,
* that parm[] has been initialized, so there is no guarantee of a
* trailing '\0':
*/
- for (; i<(sizeof msg)-1 && parm != '\0' && parm < pend; ++i)
- msg[i] = *parm++;
+ while (i<(sizeof msg)-1 && *parm != '\0' && parm < pend)
+ msg[i++] = *parm++;
+ /* Consume the parameter digit too: */
++message;
continue;
}
/* else not a parameter and there is a character after the @ sign; just
- * copy that.
+ * copy that. This is known not to be '\0' because of the test above.
*/
}
/* At this point *message can't be '\0', even in the bad parameter case
* above where there is a lone '@' at the end of the message string.
*/
- msg[i] = *message++;
+ msg[i++] = *message++;
}
/* i is always less than (sizeof msg), so: */
msg[i] = '\0';
- /* And this is the formatted message: */
+ /* And this is the formatted message, it may be larger than
+ * PNG_MAX_ERROR_TEXT, but that is only used for 'chunk' errors and these are
+ * not (currently) formatted.
+ */
png_warning(png_ptr, msg);
}
#endif /* PNG_WARNINGS_SUPPORTED */
@@ -569,6 +578,9 @@ png_longjmp,(png_structp png_ptr, int val),PNG_NORETURN)
png_ptr->longjmp_fn(png_ptr->longjmp_buffer, val);
# endif
}
+#else
+ PNG_UNUSED(png_ptr);
+ PNG_UNUSED(val);
#endif
/* Here if not setjmp support or if png_ptr is null. */
PNG_ABORT();
diff --git a/drivers/png/pngget.c b/drivers/png/pngget.c
index 43400cda7e..5b1d757c66 100644
--- a/drivers/png/pngget.c
+++ b/drivers/png/pngget.c
@@ -1,8 +1,8 @@
/* pngget.c - retrieval of values from info struct
*
- * Last changed in libpng 1.5.7 [December 15, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.19 [August 21, 2014]
+ * Copyright (c) 1998-2002,2004,2006-2014 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
@@ -123,6 +123,9 @@ png_get_x_pixels_per_meter(png_const_structp png_ptr, png_const_infop info_ptr)
if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER)
return (info_ptr->x_pixels_per_unit);
}
+#else
+ PNG_UNUSED(png_ptr)
+ PNG_UNUSED(info_ptr)
#endif
return (0);
@@ -140,6 +143,9 @@ png_get_y_pixels_per_meter(png_const_structp png_ptr, png_const_infop info_ptr)
if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER)
return (info_ptr->y_pixels_per_unit);
}
+#else
+ PNG_UNUSED(png_ptr)
+ PNG_UNUSED(info_ptr)
#endif
return (0);
@@ -157,6 +163,9 @@ png_get_pixels_per_meter(png_const_structp png_ptr, png_const_infop info_ptr)
info_ptr->x_pixels_per_unit == info_ptr->y_pixels_per_unit)
return (info_ptr->x_pixels_per_unit);
}
+#else
+ PNG_UNUSED(png_ptr)
+ PNG_UNUSED(info_ptr)
#endif
return (0);
@@ -175,6 +184,9 @@ png_get_pixel_aspect_ratio(png_const_structp png_ptr, png_const_infop info_ptr)
return ((float)((float)info_ptr->y_pixels_per_unit
/(float)info_ptr->x_pixels_per_unit));
}
+#else
+ PNG_UNUSED(png_ptr)
+ PNG_UNUSED(info_ptr)
#endif
return ((float)0.0);
@@ -203,6 +215,9 @@ png_get_pixel_aspect_ratio_fixed(png_const_structp png_ptr,
(png_int_32)info_ptr->x_pixels_per_unit))
return res;
}
+#else
+ PNG_UNUSED(png_ptr)
+ PNG_UNUSED(info_ptr)
#endif
return 0;
@@ -220,6 +235,9 @@ png_get_x_offset_microns(png_const_structp png_ptr, png_const_infop info_ptr)
if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER)
return (info_ptr->x_offset);
}
+#else
+ PNG_UNUSED(png_ptr)
+ PNG_UNUSED(info_ptr)
#endif
return (0);
@@ -236,6 +254,9 @@ png_get_y_offset_microns(png_const_structp png_ptr, png_const_infop info_ptr)
if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER)
return (info_ptr->y_offset);
}
+#else
+ PNG_UNUSED(png_ptr)
+ PNG_UNUSED(info_ptr)
#endif
return (0);
@@ -252,6 +273,9 @@ png_get_x_offset_pixels(png_const_structp png_ptr, png_const_infop info_ptr)
if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL)
return (info_ptr->x_offset);
}
+#else
+ PNG_UNUSED(png_ptr)
+ PNG_UNUSED(info_ptr)
#endif
return (0);
@@ -268,6 +292,9 @@ png_get_y_offset_pixels(png_const_structp png_ptr, png_const_infop info_ptr)
if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL)
return (info_ptr->y_offset);
}
+#else
+ PNG_UNUSED(png_ptr)
+ PNG_UNUSED(info_ptr)
#endif
return (0);
@@ -646,7 +673,7 @@ png_get_gAMA(png_const_structp png_ptr, png_const_infop info_ptr,
png_fixed_point igamma;
png_uint_32 ok = png_get_gAMA_fixed(png_ptr, info_ptr, &igamma);
- if (ok)
+ if (ok != 0)
*file_gamma = png_float(png_ptr, igamma, "png_get_gAMA");
return ok;
@@ -741,14 +768,20 @@ png_get_IHDR(png_structp png_ptr, png_infop info_ptr,
{
png_debug1(1, "in %s retrieval function", "IHDR");
- if (png_ptr == NULL || info_ptr == NULL || width == NULL ||
- height == NULL || bit_depth == NULL || color_type == NULL)
+ if (png_ptr == NULL || info_ptr == NULL)
return (0);
- *width = info_ptr->width;
- *height = info_ptr->height;
- *bit_depth = info_ptr->bit_depth;
- *color_type = info_ptr->color_type;
+ if (width != NULL)
+ *width = info_ptr->width;
+
+ if (height != NULL)
+ *height = info_ptr->height;
+
+ if (bit_depth != NULL)
+ *bit_depth = info_ptr->bit_depth;
+
+ if (color_type != NULL)
+ *color_type = info_ptr->color_type;
if (compression_type != NULL)
*compression_type = info_ptr->compression_type;
@@ -1121,4 +1154,17 @@ png_get_io_chunk_name (png_structp png_ptr)
}
#endif /* ?PNG_IO_STATE_SUPPORTED */
+#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
+# ifdef PNG_GET_PALETTE_MAX_SUPPORTED
+int PNGAPI
+png_get_palette_max(png_const_structp png_ptr, png_const_infop info_ptr)
+{
+ if (png_ptr != NULL && info_ptr != NULL)
+ return png_ptr->num_palette_max;
+
+ return (-1);
+}
+# endif
+#endif
+
#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */
diff --git a/drivers/png/pnginfo.h b/drivers/png/pnginfo.h
index a33bfab06d..c5b68c1e84 100644
--- a/drivers/png/pnginfo.h
+++ b/drivers/png/pnginfo.h
@@ -1,12 +1,11 @@
/* pnginfo.h - header file for PNG reference library
*
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.0 [January 6, 2011]
+ * Copyright (c) 1998-2002,2004,2006-2011 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
- * Last changed in libpng 1.5.0 [January 6, 2011]
- *
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
* and license in png.h
@@ -242,7 +241,7 @@ defined(PNG_READ_BACKGROUND_SUPPORTED)
#ifdef PNG_sPLT_SUPPORTED
/* Data on sPLT chunks (there may be more than one). */
png_sPLT_tp splt_palettes;
- png_uint_32 splt_palettes_num;
+ int splt_palettes_num;
#endif
#ifdef PNG_sCAL_SUPPORTED
diff --git a/drivers/png/pnglibconf.h b/drivers/png/pnglibconf.h
index 0a799915f8..37f63f2721 100644
--- a/drivers/png/pnglibconf.h
+++ b/drivers/png/pnglibconf.h
@@ -1,51 +1,28 @@
-
-/* libpng STANDARD API DEFINITION */
-
+/* 1.5.26 STANDARD API DEFINITION */
/* pnglibconf.h - library build configuration */
-/* Libpng 1.5.7 - December 15, 2011 */
+/* libpng version 1.5.26 - December 17, 2015 */
-/* Copyright (c) 1998-2011 Glenn Randers-Pehrson */
+/* Copyright (c) 1998-2015 Glenn Randers-Pehrson */
/* This code is released under the libpng license. */
/* For conditions of distribution and use, see the disclaimer */
/* and license in png.h */
/* pnglibconf.h */
+/* Machine generated file: DO NOT EDIT */
/* Derived from: scripts/pnglibconf.dfa */
-/* If you edit this file by hand you must obey the rules expressed in */
-/* pnglibconf.dfa with respect to the dependencies between the following */
-/* symbols. It is much better to generate a new file using */
-/* scripts/libpngconf.mak */
-
#ifndef PNGLCONF_H
#define PNGLCONF_H
-/* settings */
-#define PNG_API_RULE 0
-#define PNG_CALLOC_SUPPORTED
-#define PNG_COST_SHIFT 3
-#define PNG_DEFAULT_READ_MACROS 1
-#define PNG_GAMMA_THRESHOLD_FIXED 5000
-#define PNG_MAX_GAMMA_8 11
-#define PNG_QUANTIZE_BLUE_BITS 5
-#define PNG_QUANTIZE_GREEN_BITS 5
-#define PNG_QUANTIZE_RED_BITS 5
-#define PNG_sCAL_PRECISION 5
-#define PNG_USER_CHUNK_CACHE_MAX 0
-#define PNG_USER_CHUNK_MALLOC_MAX 0
-#define PNG_USER_HEIGHT_MAX 1000000
-#define PNG_USER_WIDTH_MAX 1000000
-#define PNG_WEIGHT_SHIFT 8
-#define PNG_ZBUF_SIZE 8192
-/* end of settings */
/* options */
#define PNG_16BIT_SUPPORTED
-#define PNG_ALIGN_MEMORY_SUPPORTED
+#define PNG_ALIGNED_MEMORY_SUPPORTED
+/*#undef PNG_ARM_NEON_API_SUPPORTED*/
+/*#undef PNG_ARM_NEON_CHECK_SUPPORTED*/
#define PNG_BENIGN_ERRORS_SUPPORTED
-#define PNG_bKGD_SUPPORTED
#define PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED
+#define PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
#define PNG_CHECK_cHRM_SUPPORTED
-#define PNG_cHRM_SUPPORTED
#define PNG_CONSOLE_IO_SUPPORTED
#define PNG_CONVERT_tIME_SUPPORTED
#define PNG_EASY_ACCESS_SUPPORTED
@@ -54,20 +31,12 @@
#define PNG_FIXED_POINT_SUPPORTED
#define PNG_FLOATING_ARITHMETIC_SUPPORTED
#define PNG_FLOATING_POINT_SUPPORTED
-#define PNG_FORMAT_AFIRST_SUPPORTED
-#define PNG_FORMAT_BGR_SUPPORTED
-#define PNG_gAMA_SUPPORTED
+#define PNG_GET_PALETTE_MAX_SUPPORTED
#define PNG_HANDLE_AS_UNKNOWN_SUPPORTED
-#define PNG_hIST_SUPPORTED
-#define PNG_iCCP_SUPPORTED
#define PNG_INCH_CONVERSIONS_SUPPORTED
#define PNG_INFO_IMAGE_SUPPORTED
#define PNG_IO_STATE_SUPPORTED
-#define PNG_iTXt_SUPPORTED
#define PNG_MNG_FEATURES_SUPPORTED
-#define PNG_oFFs_SUPPORTED
-#define PNG_pCAL_SUPPORTED
-#define PNG_pHYs_SUPPORTED
#define PNG_POINTER_INDEXING_SUPPORTED
#define PNG_PROGRESSIVE_READ_SUPPORTED
#define PNG_READ_16BIT_SUPPORTED
@@ -75,67 +44,62 @@
#define PNG_READ_ANCILLARY_CHUNKS_SUPPORTED
#define PNG_READ_BACKGROUND_SUPPORTED
#define PNG_READ_BGR_SUPPORTED
-#define PNG_READ_bKGD_SUPPORTED
-#define PNG_READ_cHRM_SUPPORTED
+#define PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
#define PNG_READ_COMPOSITE_NODIV_SUPPORTED
#define PNG_READ_COMPRESSED_TEXT_SUPPORTED
#define PNG_READ_EXPAND_16_SUPPORTED
#define PNG_READ_EXPAND_SUPPORTED
#define PNG_READ_FILLER_SUPPORTED
-#define PNG_READ_gAMA_SUPPORTED
#define PNG_READ_GAMMA_SUPPORTED
+#define PNG_READ_GET_PALETTE_MAX_SUPPORTED
#define PNG_READ_GRAY_TO_RGB_SUPPORTED
-#define PNG_READ_hIST_SUPPORTED
-#define PNG_READ_iCCP_SUPPORTED
#define PNG_READ_INTERLACING_SUPPORTED
#define PNG_READ_INT_FUNCTIONS_SUPPORTED
#define PNG_READ_INVERT_ALPHA_SUPPORTED
#define PNG_READ_INVERT_SUPPORTED
-#define PNG_READ_iTXt_SUPPORTED
-#define PNG_READ_oFFs_SUPPORTED
#define PNG_READ_OPT_PLTE_SUPPORTED
-#define PNG_READ_PACK_SUPPORTED
#define PNG_READ_PACKSWAP_SUPPORTED
-#define PNG_READ_pCAL_SUPPORTED
-#define PNG_READ_pHYs_SUPPORTED
+#define PNG_READ_PACK_SUPPORTED
#define PNG_READ_QUANTIZE_SUPPORTED
#define PNG_READ_RGB_TO_GRAY_SUPPORTED
-#define PNG_READ_sBIT_SUPPORTED
#define PNG_READ_SCALE_16_TO_8_SUPPORTED
-#define PNG_READ_sCAL_SUPPORTED
#define PNG_READ_SHIFT_SUPPORTED
-#define PNG_READ_sPLT_SUPPORTED
-#define PNG_READ_sRGB_SUPPORTED
#define PNG_READ_STRIP_16_TO_8_SUPPORTED
#define PNG_READ_STRIP_ALPHA_SUPPORTED
#define PNG_READ_SUPPORTED
#define PNG_READ_SWAP_ALPHA_SUPPORTED
#define PNG_READ_SWAP_SUPPORTED
-#define PNG_READ_tEXt_SUPPORTED
#define PNG_READ_TEXT_SUPPORTED
-#define PNG_READ_tIME_SUPPORTED
#define PNG_READ_TRANSFORMS_SUPPORTED
-#define PNG_READ_tRNS_SUPPORTED
#define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
#define PNG_READ_USER_CHUNKS_SUPPORTED
#define PNG_READ_USER_TRANSFORM_SUPPORTED
+#define PNG_READ_bKGD_SUPPORTED
+#define PNG_READ_cHRM_SUPPORTED
+#define PNG_READ_gAMA_SUPPORTED
+#define PNG_READ_hIST_SUPPORTED
+#define PNG_READ_iCCP_SUPPORTED
+#define PNG_READ_iTXt_SUPPORTED
+#define PNG_READ_oFFs_SUPPORTED
+#define PNG_READ_pCAL_SUPPORTED
+#define PNG_READ_pHYs_SUPPORTED
+#define PNG_READ_sBIT_SUPPORTED
+#define PNG_READ_sCAL_SUPPORTED
+#define PNG_READ_sPLT_SUPPORTED
+#define PNG_READ_sRGB_SUPPORTED
+#define PNG_READ_tEXt_SUPPORTED
+#define PNG_READ_tIME_SUPPORTED
+#define PNG_READ_tRNS_SUPPORTED
#define PNG_READ_zTXt_SUPPORTED
+/*#undef PNG_SAFE_LIMITS_SUPPORTED*/
#define PNG_SAVE_INT_32_SUPPORTED
-#define PNG_sBIT_SUPPORTED
-#define PNG_sCAL_SUPPORTED
#define PNG_SEQUENTIAL_READ_SUPPORTED
-#define PNG_SET_CHUNK_CACHE_LIMIT_SUPPORTED
-#define PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED
#define PNG_SETJMP_SUPPORTED
+/*#undef PNG_SET_OPTION_SUPPORTED*/
#define PNG_SET_USER_LIMITS_SUPPORTED
-#define PNG_sPLT_SUPPORTED
-#define PNG_sRGB_SUPPORTED
#define PNG_STDIO_SUPPORTED
-#define PNG_tEXt_SUPPORTED
#define PNG_TEXT_SUPPORTED
#define PNG_TIME_RFC1123_SUPPORTED
-#define PNG_tIME_SUPPORTED
-#define PNG_tRNS_SUPPORTED
#define PNG_UNKNOWN_CHUNKS_SUPPORTED
#define PNG_USER_CHUNKS_SUPPORTED
#define PNG_USER_LIMITS_SUPPORTED
@@ -146,44 +110,78 @@
#define PNG_WRITE_16BIT_SUPPORTED
#define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED
#define PNG_WRITE_BGR_SUPPORTED
-#define PNG_WRITE_bKGD_SUPPORTED
-#define PNG_WRITE_cHRM_SUPPORTED
+#define PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
#define PNG_WRITE_COMPRESSED_TEXT_SUPPORTED
+#define PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
#define PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
#define PNG_WRITE_FILLER_SUPPORTED
#define PNG_WRITE_FILTER_SUPPORTED
#define PNG_WRITE_FLUSH_SUPPORTED
-#define PNG_WRITE_gAMA_SUPPORTED
-#define PNG_WRITE_hIST_SUPPORTED
-#define PNG_WRITE_iCCP_SUPPORTED
+#define PNG_WRITE_GET_PALETTE_MAX_SUPPORTED
#define PNG_WRITE_INTERLACING_SUPPORTED
#define PNG_WRITE_INT_FUNCTIONS_SUPPORTED
#define PNG_WRITE_INVERT_ALPHA_SUPPORTED
#define PNG_WRITE_INVERT_SUPPORTED
-#define PNG_WRITE_iTXt_SUPPORTED
-#define PNG_WRITE_oFFs_SUPPORTED
#define PNG_WRITE_OPTIMIZE_CMF_SUPPORTED
-#define PNG_WRITE_PACK_SUPPORTED
#define PNG_WRITE_PACKSWAP_SUPPORTED
-#define PNG_WRITE_pCAL_SUPPORTED
-#define PNG_WRITE_pHYs_SUPPORTED
-#define PNG_WRITE_sBIT_SUPPORTED
-#define PNG_WRITE_sCAL_SUPPORTED
+#define PNG_WRITE_PACK_SUPPORTED
#define PNG_WRITE_SHIFT_SUPPORTED
-#define PNG_WRITE_sPLT_SUPPORTED
-#define PNG_WRITE_sRGB_SUPPORTED
#define PNG_WRITE_SUPPORTED
#define PNG_WRITE_SWAP_ALPHA_SUPPORTED
#define PNG_WRITE_SWAP_SUPPORTED
-#define PNG_WRITE_tEXt_SUPPORTED
#define PNG_WRITE_TEXT_SUPPORTED
-#define PNG_WRITE_tIME_SUPPORTED
#define PNG_WRITE_TRANSFORMS_SUPPORTED
-#define PNG_WRITE_tRNS_SUPPORTED
#define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
#define PNG_WRITE_USER_TRANSFORM_SUPPORTED
#define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
+#define PNG_WRITE_bKGD_SUPPORTED
+#define PNG_WRITE_cHRM_SUPPORTED
+#define PNG_WRITE_gAMA_SUPPORTED
+#define PNG_WRITE_hIST_SUPPORTED
+#define PNG_WRITE_iCCP_SUPPORTED
+#define PNG_WRITE_iTXt_SUPPORTED
+#define PNG_WRITE_oFFs_SUPPORTED
+#define PNG_WRITE_pCAL_SUPPORTED
+#define PNG_WRITE_pHYs_SUPPORTED
+#define PNG_WRITE_sBIT_SUPPORTED
+#define PNG_WRITE_sCAL_SUPPORTED
+#define PNG_WRITE_sPLT_SUPPORTED
+#define PNG_WRITE_sRGB_SUPPORTED
+#define PNG_WRITE_tEXt_SUPPORTED
+#define PNG_WRITE_tIME_SUPPORTED
+#define PNG_WRITE_tRNS_SUPPORTED
#define PNG_WRITE_zTXt_SUPPORTED
+#define PNG_bKGD_SUPPORTED
+#define PNG_cHRM_SUPPORTED
+#define PNG_gAMA_SUPPORTED
+#define PNG_hIST_SUPPORTED
+#define PNG_iCCP_SUPPORTED
+#define PNG_iTXt_SUPPORTED
+#define PNG_oFFs_SUPPORTED
+#define PNG_pCAL_SUPPORTED
+#define PNG_pHYs_SUPPORTED
+#define PNG_sBIT_SUPPORTED
+#define PNG_sCAL_SUPPORTED
+#define PNG_sPLT_SUPPORTED
+#define PNG_sRGB_SUPPORTED
+#define PNG_tEXt_SUPPORTED
+#define PNG_tIME_SUPPORTED
+#define PNG_tRNS_SUPPORTED
#define PNG_zTXt_SUPPORTED
/* end of options */
+/* settings */
+#define PNG_API_RULE 0
+#define PNG_DEFAULT_READ_MACROS 1
+#define PNG_GAMMA_THRESHOLD_FIXED 5000
+#define PNG_MAX_GAMMA_8 11
+#define PNG_QUANTIZE_BLUE_BITS 5
+#define PNG_QUANTIZE_GREEN_BITS 5
+#define PNG_QUANTIZE_RED_BITS 5
+#define PNG_USER_CHUNK_CACHE_MAX 1000
+#define PNG_USER_CHUNK_MALLOC_MAX 8000000
+#define PNG_USER_HEIGHT_MAX 1000000
+#define PNG_USER_WIDTH_MAX 1000000
+#define PNG_ZBUF_SIZE 8192
+#define PNG_sCAL_PRECISION 5
+/* end of settings */
#endif /* PNGLCONF_H */
diff --git a/drivers/png/pngmem.c b/drivers/png/pngmem.c
index bf5ff037da..ae74dcace0 100644
--- a/drivers/png/pngmem.c
+++ b/drivers/png/pngmem.c
@@ -1,8 +1,8 @@
/* pngmem.c - stub functions for memory allocation
*
- * Last changed in libpng 1.5.7 [December 15, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.13 [September 27, 2012]
+ * Copyright (c) 1998-2002,2004,2006-2012 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
@@ -56,7 +56,7 @@ png_create_struct_2,(int type, png_malloc_ptr malloc_fn, png_voidp mem_ptr),
if (malloc_fn != NULL)
{
png_struct dummy_struct;
- memset(&dummy_struct, 0, sizeof dummy_struct);
+ png_memset(&dummy_struct, 0, sizeof dummy_struct);
dummy_struct.mem_ptr=mem_ptr;
struct_ptr = (*(malloc_fn))(&dummy_struct, (png_alloc_size_t)size);
}
@@ -90,7 +90,7 @@ png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn,
if (free_fn != NULL)
{
png_struct dummy_struct;
- memset(&dummy_struct, 0, sizeof dummy_struct);
+ png_memset(&dummy_struct, 0, sizeof dummy_struct);
dummy_struct.mem_ptr=mem_ptr;
(*(free_fn))(&dummy_struct, struct_ptr);
return;
@@ -102,7 +102,7 @@ png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn,
}
/* Allocate memory. For reasonable files, size should never exceed
- * 64K. However, zlib may allocate more then 64K if you don't tell
+ * 64K. However, zlib may allocate more than 64K if you don't tell
* it not to. See zconf.h and png.h for more information. zlib does
* need to allocate exactly 64K, so whatever you call here must
* have the ability to do that.
@@ -475,7 +475,7 @@ png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn,
}
/* Allocate memory. For reasonable files, size should never exceed
- * 64K. However, zlib may allocate more then 64K if you don't tell
+ * 64K. However, zlib may allocate more than 64K if you don't tell
* it not to. See zconf.h and png.h for more information. zlib does
* need to allocate exactly 64K, so whatever you call here must
* have the ability to do that.
diff --git a/drivers/png/pngpread.c b/drivers/png/pngpread.c
index 20d3f236e1..9cf987d7e3 100644
--- a/drivers/png/pngpread.c
+++ b/drivers/png/pngpread.c
@@ -1,8 +1,8 @@
/* pngpread.c - read a png file in push mode
*
- * Last changed in libpng 1.5.7 [December 15, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.23 [July 23, 2015]
+ * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
@@ -19,7 +19,6 @@
#define PNG_READ_SIG_MODE 0
#define PNG_READ_CHUNK_MODE 1
#define PNG_READ_IDAT_MODE 2
-#define PNG_SKIP_MODE 3
#define PNG_READ_tEXt_MODE 4
#define PNG_READ_zTXt_MODE 5
#define PNG_READ_DONE_MODE 6
@@ -49,7 +48,7 @@ png_process_data_pause(png_structp png_ptr, int save)
/* It's easiest for the caller if we do the save, then the caller doesn't
* have to supply the same data again:
*/
- if (save)
+ if (save != 0)
png_push_save_buffer(png_ptr);
else
{
@@ -71,32 +70,15 @@ png_process_data_pause(png_structp png_ptr, int save)
png_uint_32 PNGAPI
png_process_data_skip(png_structp png_ptr)
{
- png_uint_32 remaining = 0;
-
- if (png_ptr != NULL && png_ptr->process_mode == PNG_SKIP_MODE &&
- png_ptr->skip_length > 0)
- {
- /* At the end of png_process_data the buffer size must be 0 (see the loop
- * above) so we can detect a broken call here:
- */
- if (png_ptr->buffer_size != 0)
- png_error(png_ptr,
- "png_process_data_skip called inside png_process_data");
-
- /* If is impossible for there to be a saved buffer at this point -
- * otherwise we could not be in SKIP mode. This will also happen if
- * png_process_skip is called inside png_process_data (but only very
- * rarely.)
- */
- if (png_ptr->save_buffer_size != 0)
- png_error(png_ptr, "png_process_data_skip called with saved data");
-
- remaining = png_ptr->skip_length;
- png_ptr->skip_length = 0;
- png_ptr->process_mode = PNG_READ_CHUNK_MODE;
- }
-
- return remaining;
+ /* TODO: Deprecate and remove this API.
+ * Somewhere the implementation of this seems to have been lost,
+ * or abandoned. It was only to support some internal back-door access
+ * to png_struct) in libpng-1.4.x.
+ */
+ png_warning(png_ptr,
+ "png_process_data_skip is not implemented in any current version"
+ " of libpng");
+ return 0;
}
/* What we do with the incoming data depends on what we were previously
@@ -128,36 +110,6 @@ png_process_some_data(png_structp png_ptr, png_infop info_ptr)
break;
}
-#ifdef PNG_READ_tEXt_SUPPORTED
- case PNG_READ_tEXt_MODE:
- {
- png_push_read_tEXt(png_ptr, info_ptr);
- break;
- }
-
-#endif
-#ifdef PNG_READ_zTXt_SUPPORTED
- case PNG_READ_zTXt_MODE:
- {
- png_push_read_zTXt(png_ptr, info_ptr);
- break;
- }
-
-#endif
-#ifdef PNG_READ_iTXt_SUPPORTED
- case PNG_READ_iTXt_MODE:
- {
- png_push_read_iTXt(png_ptr, info_ptr);
- break;
- }
-
-#endif
- case PNG_SKIP_MODE:
- {
- png_push_crc_finish(png_ptr);
- break;
- }
-
default:
{
png_ptr->buffer_size = 0;
@@ -175,8 +127,8 @@ png_process_some_data(png_structp png_ptr, png_infop info_ptr)
void /* PRIVATE */
png_push_read_sig(png_structp png_ptr, png_infop info_ptr)
{
- png_size_t num_checked = png_ptr->sig_bytes,
- num_to_check = 8 - num_checked;
+ png_size_t num_checked = png_ptr->sig_bytes, /* SAFE, does not exceed 8 */
+ num_to_check = 8 - num_checked;
if (png_ptr->buffer_size < num_to_check)
{
@@ -196,6 +148,7 @@ png_push_read_sig(png_structp png_ptr, png_infop info_ptr)
else
png_error(png_ptr, "PNG file corrupted by ASCII conversion");
}
+
else
{
if (png_ptr->sig_bytes >= 8)
@@ -305,8 +258,8 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr)
png_error(png_ptr, "Missing PLTE before IDAT");
}
}
-
#endif
+
else if (chunk_name == png_PLTE)
{
if (png_ptr->push_length + 4 > png_ptr->buffer_size)
@@ -543,7 +496,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr)
return;
}
- png_push_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length);
+ png_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length);
}
#endif
@@ -556,7 +509,7 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr)
return;
}
- png_push_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length);
+ png_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length);
}
#endif
@@ -569,10 +522,11 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr)
return;
}
- png_push_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length);
+ png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length);
}
#endif
+
else
{
if (png_ptr->push_length + 4 > png_ptr->buffer_size)
@@ -580,80 +534,12 @@ png_push_read_chunk(png_structp png_ptr, png_infop info_ptr)
png_push_save_buffer(png_ptr);
return;
}
- png_push_handle_unknown(png_ptr, info_ptr, png_ptr->push_length);
+ png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length);
}
png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER;
}
-void /* PRIVATE */
-png_push_crc_skip(png_structp png_ptr, png_uint_32 skip)
-{
- png_ptr->process_mode = PNG_SKIP_MODE;
- png_ptr->skip_length = skip;
-}
-
-void /* PRIVATE */
-png_push_crc_finish(png_structp png_ptr)
-{
- if (png_ptr->skip_length && png_ptr->save_buffer_size)
- {
- png_size_t save_size = png_ptr->save_buffer_size;
- png_uint_32 skip_length = png_ptr->skip_length;
-
- /* We want the smaller of 'skip_length' and 'save_buffer_size', but
- * they are of different types and we don't know which variable has the
- * fewest bits. Carefully select the smaller and cast it to the type of
- * the larger - this cannot overflow. Do not cast in the following test
- * - it will break on either 16 or 64 bit platforms.
- */
- if (skip_length < save_size)
- save_size = (png_size_t)skip_length;
-
- else
- skip_length = (png_uint_32)save_size;
-
- png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size);
-
- png_ptr->skip_length -= skip_length;
- png_ptr->buffer_size -= save_size;
- png_ptr->save_buffer_size -= save_size;
- png_ptr->save_buffer_ptr += save_size;
- }
- if (png_ptr->skip_length && png_ptr->current_buffer_size)
- {
- png_size_t save_size = png_ptr->current_buffer_size;
- png_uint_32 skip_length = png_ptr->skip_length;
-
- /* We want the smaller of 'skip_length' and 'current_buffer_size', here,
- * the same problem exists as above and the same solution.
- */
- if (skip_length < save_size)
- save_size = (png_size_t)skip_length;
-
- else
- skip_length = (png_uint_32)save_size;
-
- png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size);
-
- png_ptr->skip_length -= skip_length;
- png_ptr->buffer_size -= save_size;
- png_ptr->current_buffer_size -= save_size;
- png_ptr->current_buffer_ptr += save_size;
- }
- if (!png_ptr->skip_length)
- {
- if (png_ptr->buffer_size < 4)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
-
- png_crc_finish(png_ptr, 0);
- png_ptr->process_mode = PNG_READ_CHUNK_MODE;
- }
-}
-
void PNGCBAPI
png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length)
{
@@ -663,6 +549,7 @@ png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length)
return;
ptr = buffer;
+
if (png_ptr->save_buffer_size)
{
png_size_t save_size;
@@ -680,6 +567,7 @@ png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length)
png_ptr->save_buffer_size -= save_size;
png_ptr->save_buffer_ptr += save_size;
}
+
if (length && png_ptr->current_buffer_size)
{
png_size_t save_size;
@@ -709,6 +597,7 @@ png_push_save_buffer(png_structp png_ptr)
png_bytep dp;
istop = png_ptr->save_buffer_size;
+
for (i = 0, sp = png_ptr->save_buffer_ptr, dp = png_ptr->save_buffer;
i < istop; i++, sp++, dp++)
{
@@ -716,6 +605,7 @@ png_push_save_buffer(png_structp png_ptr)
}
}
}
+
if (png_ptr->save_buffer_size + png_ptr->current_buffer_size >
png_ptr->save_buffer_max)
{
@@ -730,8 +620,7 @@ png_push_save_buffer(png_structp png_ptr)
new_max = png_ptr->save_buffer_size + png_ptr->current_buffer_size + 256;
old_buffer = png_ptr->save_buffer;
- png_ptr->save_buffer = (png_bytep)png_malloc_warn(png_ptr,
- (png_size_t)new_max);
+ png_ptr->save_buffer = (png_bytep)png_malloc_warn(png_ptr, new_max);
if (png_ptr->save_buffer == NULL)
{
@@ -743,6 +632,7 @@ png_push_save_buffer(png_structp png_ptr)
png_free(png_ptr, old_buffer);
png_ptr->save_buffer_max = new_max;
}
+
if (png_ptr->current_buffer_size)
{
png_memcpy(png_ptr->save_buffer + png_ptr->save_buffer_size,
@@ -750,6 +640,7 @@ png_push_save_buffer(png_structp png_ptr)
png_ptr->save_buffer_size += png_ptr->current_buffer_size;
png_ptr->current_buffer_size = 0;
}
+
png_ptr->save_buffer_ptr = png_ptr->save_buffer;
png_ptr->buffer_size = 0;
}
@@ -851,6 +742,7 @@ png_push_read_IDAT(png_structp png_ptr)
png_ptr->current_buffer_size -= save_size;
png_ptr->current_buffer_ptr += save_size;
}
+
if (!png_ptr->idat_size)
{
if (png_ptr->buffer_size < 4)
@@ -911,6 +803,12 @@ png_process_IDAT_data(png_structp png_ptr, png_bytep buffer,
*/
ret = inflate(&png_ptr->zstream, Z_SYNC_FLUSH);
+ /* Hack, added in 1.5.18: the progressive reader does not reset
+ * png_ptr->zstream, so any attempt to use it after the last IDAT fails
+ * (silently). This allows the read code to do the reset when required.
+ */
+ png_ptr->flags |= PNG_FLAG_ZSTREAM_PROGRESSIVE;
+
/* Check for any failure before proceeding. */
if (ret != Z_OK && ret != Z_STREAM_END)
{
@@ -1201,6 +1099,7 @@ png_push_process_row(png_structp png_ptr)
void /* PRIVATE */
png_read_push_finish_row(png_structp png_ptr)
{
+#ifdef PNG_READ_INTERLACING_SUPPORTED
/* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */
/* Start of interlace block */
@@ -1219,6 +1118,7 @@ png_read_push_finish_row(png_structp png_ptr)
* it, uncomment it here and in png.h
static PNG_CONST png_byte FARDATA png_pass_height[] = {8, 8, 4, 4, 2, 2, 1};
*/
+#endif
png_ptr->row_number++;
if (png_ptr->row_number < png_ptr->num_rows)
@@ -1262,525 +1162,6 @@ png_read_push_finish_row(png_structp png_ptr)
#endif /* PNG_READ_INTERLACING_SUPPORTED */
}
-#ifdef PNG_READ_tEXt_SUPPORTED
-void /* PRIVATE */
-png_push_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32
- length)
-{
- if (!(png_ptr->mode & PNG_HAVE_IHDR) || (png_ptr->mode & PNG_HAVE_IEND))
- {
- PNG_UNUSED(info_ptr) /* To quiet some compiler warnings */
- png_error(png_ptr, "Out of place tEXt");
- /* NOT REACHED */
- }
-
-#ifdef PNG_MAX_MALLOC_64K
- png_ptr->skip_length = 0; /* This may not be necessary */
-
- if (length > (png_uint_32)65535L) /* Can't hold entire string in memory */
- {
- png_warning(png_ptr, "tEXt chunk too large to fit in memory");
- png_ptr->skip_length = length - (png_uint_32)65535L;
- length = (png_uint_32)65535L;
- }
-#endif
-
- png_ptr->current_text = (png_charp)png_malloc(png_ptr,
- (png_size_t)(length + 1));
- png_ptr->current_text[length] = '\0';
- png_ptr->current_text_ptr = png_ptr->current_text;
- png_ptr->current_text_size = (png_size_t)length;
- png_ptr->current_text_left = (png_size_t)length;
- png_ptr->process_mode = PNG_READ_tEXt_MODE;
-}
-
-void /* PRIVATE */
-png_push_read_tEXt(png_structp png_ptr, png_infop info_ptr)
-{
- if (png_ptr->buffer_size && png_ptr->current_text_left)
- {
- png_size_t text_size;
-
- if (png_ptr->buffer_size < png_ptr->current_text_left)
- text_size = png_ptr->buffer_size;
-
- else
- text_size = png_ptr->current_text_left;
-
- png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size);
- png_ptr->current_text_left -= text_size;
- png_ptr->current_text_ptr += text_size;
- }
- if (!(png_ptr->current_text_left))
- {
- png_textp text_ptr;
- png_charp text;
- png_charp key;
- int ret;
-
- if (png_ptr->buffer_size < 4)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
-
- png_push_crc_finish(png_ptr);
-
-#ifdef PNG_MAX_MALLOC_64K
- if (png_ptr->skip_length)
- return;
-#endif
-
- key = png_ptr->current_text;
-
- for (text = key; *text; text++)
- /* Empty loop */ ;
-
- if (text < key + png_ptr->current_text_size)
- text++;
-
- text_ptr = (png_textp)png_malloc(png_ptr, png_sizeof(png_text));
- text_ptr->compression = PNG_TEXT_COMPRESSION_NONE;
- text_ptr->key = key;
- text_ptr->itxt_length = 0;
- text_ptr->lang = NULL;
- text_ptr->lang_key = NULL;
- text_ptr->text = text;
-
- ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
-
- png_free(png_ptr, key);
- png_free(png_ptr, text_ptr);
- png_ptr->current_text = NULL;
-
- if (ret)
- png_warning(png_ptr, "Insufficient memory to store text chunk");
- }
-}
-#endif
-
-#ifdef PNG_READ_zTXt_SUPPORTED
-void /* PRIVATE */
-png_push_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32
- length)
-{
- if (!(png_ptr->mode & PNG_HAVE_IHDR) || (png_ptr->mode & PNG_HAVE_IEND))
- {
- PNG_UNUSED(info_ptr) /* To quiet some compiler warnings */
- png_error(png_ptr, "Out of place zTXt");
- /* NOT REACHED */
- }
-
-#ifdef PNG_MAX_MALLOC_64K
- /* We can't handle zTXt chunks > 64K, since we don't have enough space
- * to be able to store the uncompressed data. Actually, the threshold
- * is probably around 32K, but it isn't as definite as 64K is.
- */
- if (length > (png_uint_32)65535L)
- {
- png_warning(png_ptr, "zTXt chunk too large to fit in memory");
- png_push_crc_skip(png_ptr, length);
- return;
- }
-#endif
-
- png_ptr->current_text = (png_charp)png_malloc(png_ptr,
- (png_size_t)(length + 1));
- png_ptr->current_text[length] = '\0';
- png_ptr->current_text_ptr = png_ptr->current_text;
- png_ptr->current_text_size = (png_size_t)length;
- png_ptr->current_text_left = (png_size_t)length;
- png_ptr->process_mode = PNG_READ_zTXt_MODE;
-}
-
-void /* PRIVATE */
-png_push_read_zTXt(png_structp png_ptr, png_infop info_ptr)
-{
- if (png_ptr->buffer_size && png_ptr->current_text_left)
- {
- png_size_t text_size;
-
- if (png_ptr->buffer_size < (png_uint_32)png_ptr->current_text_left)
- text_size = png_ptr->buffer_size;
-
- else
- text_size = png_ptr->current_text_left;
-
- png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size);
- png_ptr->current_text_left -= text_size;
- png_ptr->current_text_ptr += text_size;
- }
- if (!(png_ptr->current_text_left))
- {
- png_textp text_ptr;
- png_charp text;
- png_charp key;
- int ret;
- png_size_t text_size, key_size;
-
- if (png_ptr->buffer_size < 4)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
-
- png_push_crc_finish(png_ptr);
-
- key = png_ptr->current_text;
-
- for (text = key; *text; text++)
- /* Empty loop */ ;
-
- /* zTXt can't have zero text */
- if (text >= key + png_ptr->current_text_size)
- {
- png_ptr->current_text = NULL;
- png_free(png_ptr, key);
- return;
- }
-
- text++;
-
- if (*text != PNG_TEXT_COMPRESSION_zTXt) /* Check compression byte */
- {
- png_ptr->current_text = NULL;
- png_free(png_ptr, key);
- return;
- }
-
- text++;
-
- png_ptr->zstream.next_in = (png_bytep)text;
- png_ptr->zstream.avail_in = (uInt)(png_ptr->current_text_size -
- (text - key));
- png_ptr->zstream.next_out = png_ptr->zbuf;
- png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
-
- key_size = text - key;
- text_size = 0;
- text = NULL;
- ret = Z_STREAM_END;
-
- while (png_ptr->zstream.avail_in)
- {
- ret = inflate(&png_ptr->zstream, Z_PARTIAL_FLUSH);
- if (ret != Z_OK && ret != Z_STREAM_END)
- {
- inflateReset(&png_ptr->zstream);
- png_ptr->zstream.avail_in = 0;
- png_ptr->current_text = NULL;
- png_free(png_ptr, key);
- png_free(png_ptr, text);
- return;
- }
-
- if (!(png_ptr->zstream.avail_out) || ret == Z_STREAM_END)
- {
- if (text == NULL)
- {
- text = (png_charp)png_malloc(png_ptr,
- (png_ptr->zbuf_size
- - png_ptr->zstream.avail_out + key_size + 1));
-
- png_memcpy(text + key_size, png_ptr->zbuf,
- png_ptr->zbuf_size - png_ptr->zstream.avail_out);
-
- png_memcpy(text, key, key_size);
-
- text_size = key_size + png_ptr->zbuf_size -
- png_ptr->zstream.avail_out;
-
- *(text + text_size) = '\0';
- }
-
- else
- {
- png_charp tmp;
-
- tmp = text;
- text = (png_charp)png_malloc(png_ptr, text_size +
- (png_ptr->zbuf_size
- - png_ptr->zstream.avail_out + 1));
-
- png_memcpy(text, tmp, text_size);
- png_free(png_ptr, tmp);
-
- png_memcpy(text + text_size, png_ptr->zbuf,
- png_ptr->zbuf_size - png_ptr->zstream.avail_out);
-
- text_size += png_ptr->zbuf_size - png_ptr->zstream.avail_out;
- *(text + text_size) = '\0';
- }
-
- if (ret != Z_STREAM_END)
- {
- png_ptr->zstream.next_out = png_ptr->zbuf;
- png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size;
- }
- }
- else
- {
- break;
- }
-
- if (ret == Z_STREAM_END)
- break;
- }
-
- inflateReset(&png_ptr->zstream);
- png_ptr->zstream.avail_in = 0;
-
- if (ret != Z_STREAM_END)
- {
- png_ptr->current_text = NULL;
- png_free(png_ptr, key);
- png_free(png_ptr, text);
- return;
- }
-
- png_ptr->current_text = NULL;
- png_free(png_ptr, key);
- key = text;
- text += key_size;
-
- text_ptr = (png_textp)png_malloc(png_ptr,
- png_sizeof(png_text));
- text_ptr->compression = PNG_TEXT_COMPRESSION_zTXt;
- text_ptr->key = key;
- text_ptr->itxt_length = 0;
- text_ptr->lang = NULL;
- text_ptr->lang_key = NULL;
- text_ptr->text = text;
-
- ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
-
- png_free(png_ptr, key);
- png_free(png_ptr, text_ptr);
-
- if (ret)
- png_warning(png_ptr, "Insufficient memory to store text chunk");
- }
-}
-#endif
-
-#ifdef PNG_READ_iTXt_SUPPORTED
-void /* PRIVATE */
-png_push_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32
- length)
-{
- if (!(png_ptr->mode & PNG_HAVE_IHDR) || (png_ptr->mode & PNG_HAVE_IEND))
- {
- PNG_UNUSED(info_ptr) /* To quiet some compiler warnings */
- png_error(png_ptr, "Out of place iTXt");
- /* NOT REACHED */
- }
-
-#ifdef PNG_MAX_MALLOC_64K
- png_ptr->skip_length = 0; /* This may not be necessary */
-
- if (length > (png_uint_32)65535L) /* Can't hold entire string in memory */
- {
- png_warning(png_ptr, "iTXt chunk too large to fit in memory");
- png_ptr->skip_length = length - (png_uint_32)65535L;
- length = (png_uint_32)65535L;
- }
-#endif
-
- png_ptr->current_text = (png_charp)png_malloc(png_ptr,
- (png_size_t)(length + 1));
- png_ptr->current_text[length] = '\0';
- png_ptr->current_text_ptr = png_ptr->current_text;
- png_ptr->current_text_size = (png_size_t)length;
- png_ptr->current_text_left = (png_size_t)length;
- png_ptr->process_mode = PNG_READ_iTXt_MODE;
-}
-
-void /* PRIVATE */
-png_push_read_iTXt(png_structp png_ptr, png_infop info_ptr)
-{
-
- if (png_ptr->buffer_size && png_ptr->current_text_left)
- {
- png_size_t text_size;
-
- if (png_ptr->buffer_size < png_ptr->current_text_left)
- text_size = png_ptr->buffer_size;
-
- else
- text_size = png_ptr->current_text_left;
-
- png_crc_read(png_ptr, (png_bytep)png_ptr->current_text_ptr, text_size);
- png_ptr->current_text_left -= text_size;
- png_ptr->current_text_ptr += text_size;
- }
-
- if (!(png_ptr->current_text_left))
- {
- png_textp text_ptr;
- png_charp key;
- int comp_flag;
- png_charp lang;
- png_charp lang_key;
- png_charp text;
- int ret;
-
- if (png_ptr->buffer_size < 4)
- {
- png_push_save_buffer(png_ptr);
- return;
- }
-
- png_push_crc_finish(png_ptr);
-
-#ifdef PNG_MAX_MALLOC_64K
- if (png_ptr->skip_length)
- return;
-#endif
-
- key = png_ptr->current_text;
-
- for (lang = key; *lang; lang++)
- /* Empty loop */ ;
-
- if (lang < key + png_ptr->current_text_size - 3)
- lang++;
-
- comp_flag = *lang++;
- lang++; /* Skip comp_type, always zero */
-
- for (lang_key = lang; *lang_key; lang_key++)
- /* Empty loop */ ;
-
- lang_key++; /* Skip NUL separator */
-
- text=lang_key;
-
- if (lang_key < key + png_ptr->current_text_size - 1)
- {
- for (; *text; text++)
- /* Empty loop */ ;
- }
-
- if (text < key + png_ptr->current_text_size)
- text++;
-
- text_ptr = (png_textp)png_malloc(png_ptr,
- png_sizeof(png_text));
-
- text_ptr->compression = comp_flag + 2;
- text_ptr->key = key;
- text_ptr->lang = lang;
- text_ptr->lang_key = lang_key;
- text_ptr->text = text;
- text_ptr->text_length = 0;
- text_ptr->itxt_length = png_strlen(text);
-
- ret = png_set_text_2(png_ptr, info_ptr, text_ptr, 1);
-
- png_ptr->current_text = NULL;
-
- png_free(png_ptr, text_ptr);
- if (ret)
- png_warning(png_ptr, "Insufficient memory to store iTXt chunk");
- }
-}
-#endif
-
-/* This function is called when we haven't found a handler for this
- * chunk. If there isn't a problem with the chunk itself (ie a bad chunk
- * name or a critical chunk), the chunk is (currently) silently ignored.
- */
-void /* PRIVATE */
-png_push_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32
- length)
-{
- png_uint_32 skip = 0;
- png_uint_32 chunk_name = png_ptr->chunk_name;
-
- if (PNG_CHUNK_CRITICAL(chunk_name))
- {
-#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
- if (png_chunk_unknown_handling(png_ptr, chunk_name) !=
- PNG_HANDLE_CHUNK_ALWAYS
-#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
- && png_ptr->read_user_chunk_fn == NULL
-#endif
- )
-#endif
- png_chunk_error(png_ptr, "unknown critical chunk");
-
- PNG_UNUSED(info_ptr) /* To quiet some compiler warnings */
- }
-
-#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED
- /* TODO: the code below is apparently just using the
- * png_struct::unknown_chunk member as a temporarily variable, it should be
- * possible to eliminate both it and the temporary buffer.
- */
- if (png_ptr->flags & PNG_FLAG_KEEP_UNKNOWN_CHUNKS)
- {
-#ifdef PNG_MAX_MALLOC_64K
- if (length > 65535)
- {
- png_warning(png_ptr, "unknown chunk too large to fit in memory");
- skip = length - 65535;
- length = 65535;
- }
-#endif
- /* This is just a record for the user; libpng doesn't use the character
- * form of the name.
- */
- PNG_CSTRING_FROM_CHUNK(png_ptr->unknown_chunk.name, png_ptr->chunk_name);
-
- /* The following cast should be safe because of the check above. */
- png_ptr->unknown_chunk.size = (png_size_t)length;
-
- if (length == 0)
- png_ptr->unknown_chunk.data = NULL;
-
- else
- {
- png_ptr->unknown_chunk.data = (png_bytep)png_malloc(png_ptr,
- png_ptr->unknown_chunk.size);
- png_crc_read(png_ptr, (png_bytep)png_ptr->unknown_chunk.data,
- png_ptr->unknown_chunk.size);
- }
-
-#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
- if (png_ptr->read_user_chunk_fn != NULL)
- {
- /* Callback to user unknown chunk handler */
- int ret;
- ret = (*(png_ptr->read_user_chunk_fn))
- (png_ptr, &png_ptr->unknown_chunk);
-
- if (ret < 0)
- png_chunk_error(png_ptr, "error in user chunk");
-
- if (ret == 0)
- {
- if (PNG_CHUNK_CRITICAL(png_ptr->chunk_name))
- if (png_chunk_unknown_handling(png_ptr, chunk_name) !=
- PNG_HANDLE_CHUNK_ALWAYS)
- png_chunk_error(png_ptr, "unknown critical chunk");
- png_set_unknown_chunks(png_ptr, info_ptr,
- &png_ptr->unknown_chunk, 1);
- }
- }
-
- else
-#endif
- png_set_unknown_chunks(png_ptr, info_ptr, &png_ptr->unknown_chunk, 1);
- png_free(png_ptr, png_ptr->unknown_chunk.data);
- png_ptr->unknown_chunk.data = NULL;
- }
-
- else
-#endif
- skip=length;
- png_push_crc_skip(png_ptr, skip);
-}
-
void /* PRIVATE */
png_push_have_info(png_structp png_ptr, png_infop info_ptr)
{
@@ -1816,7 +1197,7 @@ png_progressive_combine_row (png_structp png_ptr, png_bytep old_row,
* it must be png_ptr->row_buf+1
*/
if (new_row != NULL)
- png_combine_row(png_ptr, old_row, 1/*display*/);
+ png_combine_row(png_ptr, old_row, 1/*blocky display*/);
}
#endif /* PNG_READ_INTERLACING_SUPPORTED */
diff --git a/drivers/png/pngpriv.h b/drivers/png/pngpriv.h
index 56532f4eeb..8bdccccafb 100644
--- a/drivers/png/pngpriv.h
+++ b/drivers/png/pngpriv.h
@@ -1,13 +1,11 @@
/* pngpriv.h - private declarations for use inside libpng
*
- * For conditions of distribution and use, see copyright notice in png.h
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.26 [December 17, 2015]
+ * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
- * Last changed in libpng 1.5.7 [December 15, 2011]
- *
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
* and license in png.h
@@ -39,6 +37,7 @@
*/
#define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */
+#ifndef PNG_VERSION_INFO_ONLY
/* This is required for the definition of abort(), used as a last ditch
* error handler when all else fails.
*/
@@ -46,6 +45,7 @@
/* This is used to find 'offsetof', used below for alignment tests. */
#include <stddef.h>
+#endif /* !PNG_VERSION_INFO_ONLY */
#define PNGLIB_BUILD /*libpng is being built, not used*/
@@ -125,21 +125,68 @@
#endif
#include "png.h"
-#include "pnginfo.h"
-#include "pngstruct.h"
/* pngconf.h does not set PNG_DLL_EXPORT unless it is required, so: */
#ifndef PNG_DLL_EXPORT
# define PNG_DLL_EXPORT
#endif
-/* This is used for 16 bit gamma tables - only the top level pointers are const,
- * this could be changed:
+/* Compile time options.
+ * =====================
+ * In a multi-arch build the compiler may compile the code several times for the
+ * same object module, producing different binaries for different architectures.
+ * When this happens configure-time setting of the target host options cannot be
+ * done and this interferes with the handling of the ARM NEON optimizations, and
+ * possibly other similar optimizations. Put additional tests here; in general
+ * this is needed when the same option can be changed at both compile time and
+ * run time depending on the target OS (i.e. iOS vs Android.)
+ *
+ * NOTE: symbol prefixing does not pass $(CFLAGS) to the preprocessor, because
+ * this is not possible with certain compilers (Oracle SUN OS CC), as a result
+ * it is necessary to ensure that all extern functions that *might* be used
+ * regardless of $(CFLAGS) get declared in this file. The test on __ARM_NEON__
+ * below is one example of this behavior because it is controlled by the
+ * presence or not of -mfpu=neon on the GCC command line, it is possible to do
+ * this in $(CC), e.g. "CC=gcc -mfpu=neon", but people who build libpng rarely
+ * do this.
*/
-typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
+#ifndef PNG_ARM_NEON_OPT
+ /* ARM NEON optimizations are being controlled by the compiler settings,
+ * typically the target FPU. If the FPU has been set to NEON (-mfpu=neon
+ * with GCC) then the compiler will define __ARM_NEON__ and we can rely
+ * unconditionally on NEON instructions not crashing, otherwise we must
+ * disable use of NEON instructions.
+ *
+ * NOTE: at present these optimizations depend on 'ALIGNED_MEMORY', so they
+ * can only be turned on automatically if that is supported too. If
+ * PNG_ARM_NEON_OPT is set in CPPFLAGS (to >0) then arm/arm_init.c will fail
+ * to compile with an appropriate #error if ALIGNED_MEMORY has been turned
+ * off.
+ */
+# if defined(__ARM_NEON__) && defined(PNG_ALIGNED_MEMORY_SUPPORTED)
+# define PNG_ARM_NEON_OPT 2
+# else
+# define PNG_ARM_NEON_OPT 0
+# endif
+#endif
-/* Added at libpng-1.2.9 */
-/* Moved to pngpriv.h at libpng-1.5.0 */
+
+#if PNG_ARM_NEON_OPT > 0
+ /* NEON optimizations are to be at least considered by libpng, so enable the
+ * callbacks to do this.
+ */
+# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_neon
+#endif
+
+/* SECURITY and SAFETY:
+ *
+ * By default libpng is built without any internal limits on image size,
+ * individual heap (png_malloc) allocations or the total amount of memory used.
+ * If PNG_SAFE_LIMITS_SUPPORTED is defined, however, the limits below are used
+ * (unless individually overridden). These limits are believed to be fairly
+ * safe, but builders of secure systems should verify the values against the
+ * real system capabilities.
+ */
/* config.h is created by and PNG_CONFIGURE_LIBPNG is set by the "configure"
* script. We may need it here to get the correct configuration on things
@@ -151,9 +198,11 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
# endif
#endif
-/* Moved to pngpriv.h at libpng-1.5.0 */
-/* NOTE: some of these may have been used in external applications as
- * these definitions were exposed in pngconf.h prior to 1.5.
+/* SECURITY and SAFETY:
+ *
+ * libpng is built with support for internal limits on image dimensions and
+ * memory usage. These are documented in scripts/pnglibconf.dfa of the
+ * source and recorded in the machine generated header file pnglibconf.h.
*/
/* If you are running on a machine where you cannot allocate more
@@ -171,6 +220,11 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
# define PNG_MAX_MALLOC_64K
#endif
+/* Moved to pngpriv.h at libpng-1.5.0 */
+/* NOTE: some of these may have been used in external applications as
+ * these definitions were exposed in pngconf.h prior to 1.5.
+ */
+
#ifndef PNG_UNUSED
/* Unused formal parameter warnings are silenced using the following macro
* which is expected to have no bad effects on performance (optimizing
@@ -206,7 +260,7 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
/* Modern compilers support restrict, but assume not for anything not
* recognized here:
*/
-# if defined __GNUC__ || defined _MSC_VER || defined __WATCOMC__
+# if defined(__GNUC__) || defined(_MSC_VER) || defined(__WATCOMC__)
# define PNG_RESTRICT restrict
# else
# define PNG_RESTRICT
@@ -220,8 +274,6 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
#ifdef PNG_WARNINGS_SUPPORTED
# define PNG_WARNING_PARAMETERS(p) png_warning_parameters p;
#else
-# define png_warning(s1,s2) ((void)(s1))
-# define png_chunk_warning(s1,s2) ((void)(s1))
# define png_warning_parameter(p,number,string) ((void)0)
# define png_warning_parameter_unsigned(p,number,format,value) ((void)0)
# define png_warning_parameter_signed(p,number,format,value) ((void)0)
@@ -229,8 +281,6 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
# define PNG_WARNING_PARAMETERS(p)
#endif
#ifndef PNG_ERROR_TEXT_SUPPORTED
-# define png_error(s1,s2) png_err(s1)
-# define png_chunk_error(s1,s2) png_err(s1)
# define png_fixed_error(s1,s2) png_err(s1)
#endif
@@ -268,6 +318,7 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
# define PNGFAPI /* PRIVATE */
#endif
+#ifndef PNG_VERSION_INFO_ONLY
/* Other defines specific to compilers can go here. Try to keep
* them inside an appropriate ifdef/endif pair for portability.
*/
@@ -312,6 +363,7 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
defined(_WIN32) || defined(__WIN32__)
# include <windows.h> /* defines _WINDOWS_ macro */
#endif
+#endif /* !PNG_VERSION_INFO_ONLY */
/* Moved here around 1.5.0beta36 from pngconf.h */
/* Users may want to use these so they are not private. Any library
@@ -341,13 +393,9 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
# ifdef _WINDOWS_ /* Favor Windows over C runtime fns */
# define CVT_PTR(ptr) (ptr)
# define CVT_PTR_NOCHECK(ptr) (ptr)
-# ifdef WINRT_ENABLED
-# define png_strlen strlen
-# else
-# define png_strlen lstrlenA
-# endif
+# define png_strlen lstrlenA
# define png_memcmp memcmp
-# define png_memcpy CopyMemory
+# define png_memcpy memcpy
# define png_memset memset
# else
# define CVT_PTR(ptr) (ptr)
@@ -380,7 +428,7 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
#if PNG_ALIGN_TYPE == PNG_ALIGN_SIZE
/* This is used because in some compiler implementations non-aligned
* structure members are supported, so the offsetof approach below fails.
- * Set PNG_ALIGN_TO_SIZE=0 for compiler combinations where unaligned access
+ * Set PNG_ALIGN_SIZE=0 for compiler combinations where unaligned access
* is good for performance. Do not do this unless you have tested the result
* and understand it.
*/
@@ -430,6 +478,7 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
#define PNG_BACKGROUND_IS_GRAY 0x800
#define PNG_HAVE_PNG_SIGNATURE 0x1000
#define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */
+#define PNG_HAVE_iCCP 0x4000
/* Flags for the transformations the PNG library does on the image data */
#define PNG_BGR 0x0001
@@ -468,10 +517,6 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
#define PNG_STRUCT_PNG 0x0001
#define PNG_STRUCT_INFO 0x0002
-/* Scaling factor for filter heuristic weighting calculations */
-#define PNG_WEIGHT_FACTOR (1<<(PNG_WEIGHT_SHIFT))
-#define PNG_COST_FACTOR (1<<(PNG_COST_SHIFT))
-
/* Flags for the png_ptr->flags rather than declaring a byte for each one */
#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0001
#define PNG_FLAG_ZLIB_CUSTOM_LEVEL 0x0002
@@ -494,7 +539,7 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000
#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000
#define PNG_FLAG_MALLOC_NULL_MEM_OK 0x100000
- /* 0x200000 unused */
+#define PNG_FLAG_ZSTREAM_PROGRESSIVE 0x200000
/* 0x400000 unused */
#define PNG_FLAG_BENIGN_ERRORS_WARN 0x800000 /* Added to libpng-1.4.0 */
#define PNG_FLAG_ZTXT_CUSTOM_STRATEGY 0x1000000 /* 5 lines added */
@@ -580,8 +625,10 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp;
#define png_fixed(png_ptr, fp, s) ((fp) <= 21474 && (fp) >= -21474 ?\
((png_fixed_point)(100000 * (fp))) : (png_fixed_error(png_ptr, s),0))
#else
+#ifndef PNG_VERSION_INFO_ONLY
PNG_EXTERN png_fixed_point png_fixed PNGARG((png_structp png_ptr, double fp,
png_const_charp text));
+#endif /* !PNG_VERSION_INFO_ONLY */
#endif
#endif
@@ -655,6 +702,18 @@ PNG_EXTERN png_fixed_point png_fixed PNGARG((png_structp png_ptr, double fp,
#define PNG_GAMMA_MAC_INVERSE 65909
#define PNG_GAMMA_sRGB_INVERSE 45455
+/* Almost everything below is C specific; the #defines above can be used in
+ * non-C code (so long as it is C-preprocessed) the rest of this stuff cannot.
+ */
+#ifndef PNG_VERSION_INFO_ONLY
+
+#include "pngstruct.h"
+#include "pnginfo.h"
+
+/* This is used for 16 bit gamma tables -- only the top level pointers are
+ * const; this could be changed:
+ */
+typedef const png_uint_16p * png_const_uint_16pp;
/* Inhibit C++ name-mangling for libpng functions but not for system calls. */
#ifdef __cplusplus
@@ -786,10 +845,8 @@ PNG_EXTERN void png_write_IEND PNGARG((png_structp png_ptr));
# ifdef PNG_FLOATING_POINT_SUPPORTED
PNG_EXTERN void png_write_gAMA PNGARG((png_structp png_ptr, double file_gamma));
# endif
-# ifdef PNG_FIXED_POINT_SUPPORTED
PNG_EXTERN void png_write_gAMA_fixed PNGARG((png_structp png_ptr,
png_fixed_point file_gamma));
-# endif
#endif
#ifdef PNG_WRITE_sBIT_SUPPORTED
@@ -844,13 +901,6 @@ PNG_EXTERN void png_write_hIST PNGARG((png_structp png_ptr,
png_const_uint_16p hist, int num_hist));
#endif
-/* Chunks that have keywords */
-#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \
- defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
-PNG_EXTERN png_size_t png_check_keyword PNGARG((png_structp png_ptr,
- png_const_charp key, png_charpp new_key));
-#endif
-
#ifdef PNG_WRITE_tEXt_SUPPORTED
PNG_EXTERN void png_write_tEXt PNGARG((png_structp png_ptr, png_const_charp key,
png_const_charp text, png_size_t text_len));
@@ -956,8 +1006,8 @@ PNG_EXTERN void png_do_write_interlace PNGARG((png_row_infop row_info,
/* Unfilter a row: check the filter value before calling this, there is no point
* calling it for PNG_FILTER_VALUE_NONE.
*/
-PNG_EXTERN void png_read_filter_row PNGARG((png_structp pp, png_row_infop row_info,
- png_bytep row, png_const_bytep prev_row, int filter));
+PNG_EXTERN void png_read_filter_row PNGARG((png_structp pp, png_row_infop
+ row_info, png_bytep row, png_const_bytep prev_row, int filter));
PNG_EXTERN void png_read_filter_row_up_neon PNGARG((png_row_infop row_info,
png_bytep row, png_const_bytep prev_row));
@@ -1222,10 +1272,8 @@ PNG_EXTERN void png_handle_zTXt PNGARG((png_structp png_ptr, png_infop info_ptr,
png_uint_32 length));
#endif
-#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
PNG_EXTERN void png_handle_unknown PNGARG((png_structp png_ptr,
png_infop info_ptr, png_uint_32 length));
-#endif
PNG_EXTERN void png_check_chunk_name PNGARG((png_structp png_ptr,
png_uint_32 chunk_name));
@@ -1258,9 +1306,6 @@ PNG_EXTERN void png_push_read_chunk PNGARG((png_structp png_ptr,
PNG_EXTERN void png_push_read_sig PNGARG((png_structp png_ptr,
png_infop info_ptr));
PNG_EXTERN void png_push_check_crc PNGARG((png_structp png_ptr));
-PNG_EXTERN void png_push_crc_skip PNGARG((png_structp png_ptr,
- png_uint_32 length));
-PNG_EXTERN void png_push_crc_finish PNGARG((png_structp png_ptr));
PNG_EXTERN void png_push_save_buffer PNGARG((png_structp png_ptr));
PNG_EXTERN void png_push_restore_buffer PNGARG((png_structp png_ptr,
png_bytep buffer, png_size_t buffer_length));
@@ -1359,6 +1404,13 @@ PNG_EXTERN void png_check_IHDR PNGARG((png_structp png_ptr,
int color_type, int interlace_type, int compression_type,
int filter_type));
+/* Added at libpng version 1.5.10 */
+#if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \
+ defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED)
+PNG_EXTERN void png_do_check_palette_indexes PNGARG((png_structp png_ptr,
+ png_row_infop row_info));
+#endif
+
/* Free all memory used by the read (old method - NOT DLL EXPORTED) */
PNG_EXTERN void png_read_destroy PNGARG((png_structp png_ptr,
png_infop info_ptr, png_infop end_info_ptr));
@@ -1449,14 +1501,16 @@ PNG_EXTERN void png_formatted_warning(png_structp png_ptr,
/* ASCII to FP interfaces, currently only implemented if sCAL
* support is required.
*/
-#if defined(PNG_READ_sCAL_SUPPORTED)
+#ifdef PNG_sCAL_SUPPORTED
/* MAX_DIGITS is actually the maximum number of characters in an sCAL
* width or height, derived from the precision (number of significant
* digits - a build time settable option) and assumpitions about the
* maximum ridiculous exponent.
*/
#define PNG_sCAL_MAX_DIGITS (PNG_sCAL_PRECISION+1/*.*/+1/*E*/+10/*exponent*/)
+#endif
+#ifdef PNG_sCAL_SUPPORTED
#ifdef PNG_FLOATING_POINT_SUPPORTED
PNG_EXTERN void png_ascii_from_fp PNGARG((png_structp png_ptr, png_charp ascii,
png_size_t size, double fp, unsigned int precision));
@@ -1540,15 +1594,15 @@ PNG_EXTERN void png_ascii_from_fixed PNGARG((png_structp png_ptr,
#define PNG_FP_IS_ZERO(state) (((state) & PNG_FP_Z_MASK) == PNG_FP_SAW_DIGIT)
#define PNG_FP_IS_POSITIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_Z_MASK)
#define PNG_FP_IS_NEGATIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_NZ_MASK)
-
-/* The actual parser. This can be called repeatedly, it updates
+
+/* The actual parser. This can be called repeatedly. It updates
* the index into the string and the state variable (which must
- * be initialzed to 0). It returns a result code, as above. There
+ * be initialized to 0). It returns a result code, as above. There
* is no point calling the parser any more if it fails to advance to
* the end of the string - it is stuck on an invalid character (or
* terminated by '\0').
*
- * Note that the pointer will consume an E or even an E+ then leave
+ * Note that the pointer will consume an E or even an E+ and then leave
* a 'maybe' state even though a preceding integer.fraction is valid.
* The PNG_FP_WAS_VALID flag indicates that a preceding substring was
* a valid number. It's possible to recover from this by calling
@@ -1587,7 +1641,7 @@ PNG_EXTERN png_fixed_point png_muldiv_warn PNGARG((png_structp png_ptr,
png_fixed_point a, png_int_32 multiplied_by, png_int_32 divided_by));
#endif
-#ifdef PNG_READ_GAMMA_SUPPORTED
+#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED)
/* Calculate a reciprocal - used for gamma values. This returns
* 0 if the argument is 0 in order to maintain an undefined value,
* there are no warnings.
@@ -1622,7 +1676,80 @@ PNG_EXTERN void png_build_gamma_table PNGARG((png_structp png_ptr,
int bit_depth));
#endif
-/* Maintainer: Put new private prototypes here ^ and in libpngpf.3 */
+/* Missing declarations if FIXED_POINT is *not* supported - fixed properly
+ * in libpng 1.6
+ */
+#ifndef PNG_FIXED_POINT_SUPPORTED
+#ifdef PNG_cHRM_SUPPORTED
+PNG_EXTERN png_uint_32 png_get_cHRM_XYZ_fixed PNGARG(
+ (png_structp png_ptr, png_const_infop info_ptr,
+ png_fixed_point *int_red_X, png_fixed_point *int_red_Y,
+ png_fixed_point *int_red_Z, png_fixed_point *int_green_X,
+ png_fixed_point *int_green_Y, png_fixed_point *int_green_Z,
+ png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y,
+ png_fixed_point *int_blue_Z));
+PNG_EXTERN void png_set_cHRM_XYZ_fixed PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_fixed_point int_red_X, png_fixed_point int_red_Y,
+ png_fixed_point int_red_Z, png_fixed_point int_green_X,
+ png_fixed_point int_green_Y, png_fixed_point int_green_Z,
+ png_fixed_point int_blue_X, png_fixed_point int_blue_Y,
+ png_fixed_point int_blue_Z));
+PNG_EXTERN void png_set_cHRM_fixed PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_fixed_point int_white_x,
+ png_fixed_point int_white_y, png_fixed_point int_red_x,
+ png_fixed_point int_red_y, png_fixed_point int_green_x,
+ png_fixed_point int_green_y, png_fixed_point int_blue_x,
+ png_fixed_point int_blue_y));
+#endif
+
+#ifdef PNG_gAMA_SUPPORTED
+PNG_EXTERN png_uint_32 png_get_gAMA_fixed PNGARG(
+ (png_const_structp png_ptr, png_const_infop info_ptr,
+ png_fixed_point *int_file_gamma));
+PNG_EXTERN void png_set_gAMA_fixed PNGARG((png_structp png_ptr,
+ png_infop info_ptr, png_fixed_point int_file_gamma));
+#endif
+
+#ifdef PNG_READ_BACKGROUND_SUPPORTED
+PNG_EXTERN void png_set_background_fixed PNGARG((png_structp png_ptr,
+ png_const_color_16p background_color, int background_gamma_code,
+ int need_expand, png_fixed_point background_gamma));
+#endif
+
+#ifdef PNG_READ_ALPHA_MODE_SUPPORTED
+PNG_EXTERN void png_set_alpha_mode_fixed PNGARG((png_structp png_ptr,
+ int mode, png_fixed_point output_gamma));
+#endif
+
+#ifdef PNG_READ_GAMMA_SUPPORTED
+PNG_EXTERN void png_set_gamma_fixed PNGARG((png_structp png_ptr,
+ png_fixed_point screen_gamma, png_fixed_point override_file_gamma));
+#endif
+
+#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED
+PNG_EXTERN void png_set_rgb_to_gray_fixed PNGARG((png_structp png_ptr,
+ int error_action, png_fixed_point red, png_fixed_point green));
+#endif
+#endif /* FIX MISSING !FIXED_POINT DECLARATIONS */
+
+/* These are initialization functions for hardware specific PNG filter
+ * optimizations; list these here then select the appropriate one at compile
+ * time using the macro PNG_FILTER_OPTIMIZATIONS. If the macro is not defined
+ * the generic code is used.
+ */
+#ifdef PNG_FILTER_OPTIMIZATIONS
+PNG_EXTERN void PNG_FILTER_OPTIMIZATIONS(png_structp png_ptr, unsigned int bpp);
+ /* Just declare the optimization that will be used */
+#else
+ /* List *all* the possible optimizations here - this branch is required if
+ * the builder of libpng passes the definition of PNG_FILTER_OPTIMIZATIONS in
+ * CFLAGS in place of CPPFLAGS *and* uses symbol prefixing.
+ */
+PNG_EXTERN void png_init_filter_functions_neon(png_structp png_ptr,
+ unsigned int bpp);
+#endif
+
+/* Maintainer: Put new private prototypes here ^ */
#include "pngdebug.h"
@@ -1630,4 +1757,5 @@ PNG_EXTERN void png_build_gamma_table PNGARG((png_structp png_ptr,
}
#endif
+#endif /* PNG_VERSION_INFO_ONLY */
#endif /* PNGPRIV_H */
diff --git a/drivers/png/pngread.c b/drivers/png/pngread.c
index 0643754dad..b90e017e62 100644
--- a/drivers/png/pngread.c
+++ b/drivers/png/pngread.c
@@ -1,8 +1,8 @@
/* pngread.c - read a PNG file
*
- * Last changed in libpng 1.5.7 [December 15, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.23 [July 23, 2015]
+ * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
@@ -67,15 +67,11 @@ png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
png_ptr->user_width_max = PNG_USER_WIDTH_MAX;
png_ptr->user_height_max = PNG_USER_HEIGHT_MAX;
-# ifdef PNG_USER_CHUNK_CACHE_MAX
/* Added at libpng-1.2.43 and 1.4.0 */
png_ptr->user_chunk_cache_max = PNG_USER_CHUNK_CACHE_MAX;
-# endif
-# ifdef PNG_SET_USER_CHUNK_MALLOC_MAX
/* Added at libpng-1.2.43 and 1.4.1 */
png_ptr->user_chunk_malloc_max = PNG_USER_CHUNK_MALLOC_MAX;
-# endif
#endif
#ifdef PNG_SETJMP_SUPPORTED
@@ -104,7 +100,7 @@ png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
if (!png_user_version_check(png_ptr, user_png_ver))
png_cleanup_needed = 1;
- if (!png_cleanup_needed)
+ if (png_cleanup_needed == 0)
{
/* Initialize zbuf - compression buffer */
png_ptr->zbuf_size = PNG_ZBUF_SIZE;
@@ -118,7 +114,7 @@ png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
png_ptr->zstream.zfree = png_zfree;
png_ptr->zstream.opaque = (voidpf)png_ptr;
- if (!png_cleanup_needed)
+ if (png_cleanup_needed == 0)
{
switch (inflateInit(&png_ptr->zstream))
{
@@ -145,7 +141,7 @@ png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
}
}
- if (png_cleanup_needed)
+ if (png_cleanup_needed != 0)
{
/* Clean up PNG structure and deallocate any memory. */
png_free(png_ptr, png_ptr->zbuf);
@@ -563,7 +559,7 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row)
if (ret == Z_STREAM_END)
{
if (png_ptr->zstream.avail_out || png_ptr->zstream.avail_in ||
- png_ptr->idat_size)
+ png_ptr->idat_size)
png_benign_error(png_ptr, "Extra compressed data");
png_ptr->mode |= PNG_AFTER_IDAT;
png_ptr->flags |= PNG_FLAG_ZLIB_FINISHED;
@@ -621,7 +617,7 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row)
#ifdef PNG_READ_INTERLACING_SUPPORTED
/* Blow up interlaced rows to full size */
if (png_ptr->interlaced &&
- (png_ptr->transformations & PNG_INTERLACE))
+ (png_ptr->transformations & PNG_INTERLACE))
{
if (png_ptr->pass < 6)
png_do_read_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass,
@@ -805,6 +801,13 @@ png_read_end(png_structp png_ptr, png_infop info_ptr)
png_crc_finish(png_ptr, 0); /* Finish off CRC from last IDAT chunk */
+#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
+ /* Report invalid palette index; added at libng-1.5.10 */
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE &&
+ png_ptr->num_palette_max > png_ptr->num_palette)
+ png_benign_error(png_ptr, "Read palette index exceeding num_palette");
+#endif
+
do
{
png_uint_32 length = png_read_chunk_header(png_ptr);
@@ -1070,12 +1073,6 @@ png_read_destroy(png_structp png_ptr, png_infop info_ptr,
png_free(png_ptr, png_ptr->save_buffer);
#endif
-#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
-#ifdef PNG_TEXT_SUPPORTED
- png_free(png_ptr, png_ptr->current_text);
-#endif /* PNG_TEXT_SUPPORTED */
-#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
-
/* Save the important info out of the png_struct, in case it is
* being used again.
*/
@@ -1122,9 +1119,8 @@ png_set_read_status_fn(png_structp png_ptr, png_read_status_ptr read_row_fn)
#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
#ifdef PNG_INFO_IMAGE_SUPPORTED
void PNGAPI
-png_read_png(png_structp png_ptr, png_infop info_ptr,
- int transforms,
- voidp params)
+png_read_png(png_structp png_ptr, png_infop info_ptr, int transforms,
+ voidp params)
{
int row;
@@ -1194,7 +1190,7 @@ png_read_png(png_structp png_ptr, png_infop info_ptr,
if (transforms & PNG_TRANSFORM_EXPAND)
if ((png_ptr->bit_depth < 8) ||
(png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ||
- (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
+ (info_ptr->valid & PNG_INFO_tRNS))
png_set_expand(png_ptr);
#endif
@@ -1213,14 +1209,8 @@ png_read_png(png_structp png_ptr, png_infop info_ptr,
* [0,65535] to the original [0,7] or [0,31], or whatever range the
* colors were originally in:
*/
- if ((transforms & PNG_TRANSFORM_SHIFT)
- && png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT))
- {
- png_color_8p sig_bit;
-
- png_get_sBIT(png_ptr, info_ptr, &sig_bit);
- png_set_shift(png_ptr, sig_bit);
- }
+ if ((transforms & PNG_TRANSFORM_SHIFT) && (info_ptr->valid & PNG_INFO_sBIT))
+ png_set_shift(png_ptr, &info_ptr->sig_bit);
#endif
#ifdef PNG_READ_BGR_SUPPORTED
@@ -1290,7 +1280,7 @@ png_read_png(png_structp png_ptr, png_infop info_ptr,
for (row = 0; row < (int)info_ptr->height; row++)
info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr,
- png_get_rowbytes(png_ptr, info_ptr));
+ png_get_rowbytes(png_ptr, info_ptr));
}
png_read_image(png_ptr, info_ptr->row_pointers);
diff --git a/drivers/png/pngrio.c b/drivers/png/pngrio.c
index e9c381c5ba..b4042e9ed3 100644
--- a/drivers/png/pngrio.c
+++ b/drivers/png/pngrio.c
@@ -2,7 +2,7 @@
/* pngrio.c - functions for data input
*
* Last changed in libpng 1.5.0 [January 6, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Copyright (c) 1998-2002,2004,2006-2011 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
@@ -26,7 +26,7 @@
* reads from a file pointer. Note that this routine sometimes gets called
* with very small lengths, so you should implement some kind of simple
* buffering if you are using unbuffered reads. This should never be asked
- * to read more then 64K on a 16 bit machine.
+ * to read more than 64K on a 16 bit machine.
*/
void /* PRIVATE */
png_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
diff --git a/drivers/png/pngrtran.c b/drivers/png/pngrtran.c
index 1079595f0a..f273362616 100644
--- a/drivers/png/pngrtran.c
+++ b/drivers/png/pngrtran.c
@@ -1,8 +1,8 @@
/* pngrtran.c - transforms the data in a row for PNG readers
*
- * Last changed in libpng 1.5.7 [December 15, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.24 [November 12, 2015]
+ * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
@@ -114,7 +114,7 @@ png_set_background_fixed(png_structp png_ptr,
png_sizeof(png_color_16));
png_ptr->background_gamma = background_gamma;
png_ptr->background_gamma_type = (png_byte)(background_gamma_code);
- if (need_expand)
+ if (need_expand != 0)
png_ptr->transformations |= PNG_BACKGROUND_EXPAND;
else
png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND;
@@ -194,8 +194,10 @@ translate_gamma_flags(png_structp png_ptr, png_fixed_point output_gamma,
*/
# ifdef PNG_READ_sRGB_SUPPORTED
png_ptr->flags |= PNG_FLAG_ASSUME_sRGB;
+# else
+ PNG_UNUSED(png_ptr)
# endif
- if (is_screen)
+ if (is_screen != 0)
output_gamma = PNG_GAMMA_sRGB;
else
output_gamma = PNG_GAMMA_sRGB_INVERSE;
@@ -204,7 +206,7 @@ translate_gamma_flags(png_structp png_ptr, png_fixed_point output_gamma,
else if (output_gamma == PNG_GAMMA_MAC_18 ||
output_gamma == PNG_FP_1 / PNG_GAMMA_MAC_18)
{
- if (is_screen)
+ if (is_screen != 0)
output_gamma = PNG_GAMMA_MAC_OLD;
else
output_gamma = PNG_GAMMA_MAC_INVERSE;
@@ -329,7 +331,7 @@ png_set_alpha_mode_fixed(png_structp png_ptr, int mode,
/* Finally, if pre-multiplying, set the background fields to achieve the
* desired result.
*/
- if (compose)
+ if (compose != 0)
{
/* And obtain alpha pre-multiplication by composing on black: */
png_memset(&png_ptr->background, 0, sizeof png_ptr->background);
@@ -389,7 +391,7 @@ png_set_quantize(png_structp png_ptr, png_colorp palette,
png_ptr->transformations |= PNG_QUANTIZE;
- if (!full_quantize)
+ if (full_quantize == 0)
{
int i;
@@ -444,12 +446,12 @@ png_set_quantize(png_structp png_ptr, png_colorp palette,
}
}
- if (done)
+ if (done != 0)
break;
}
/* Swap the palette around, and set up a table, if necessary */
- if (full_quantize)
+ if (full_quantize != 0)
{
int j = num_palette;
@@ -632,7 +634,7 @@ png_set_quantize(png_structp png_ptr, png_colorp palette,
num_new_palette--;
palette[png_ptr->index_to_palette[j]]
= palette[num_new_palette];
- if (!full_quantize)
+ if (full_quantize == 0)
{
int k;
@@ -700,7 +702,7 @@ png_set_quantize(png_structp png_ptr, png_colorp palette,
}
png_ptr->num_palette = (png_uint_16)num_palette;
- if (full_quantize)
+ if (full_quantize != 0)
{
int i;
png_bytep distance;
@@ -969,7 +971,7 @@ png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action,
png_uint_16 red_int, green_int;
/* NOTE: this calculation does not round, but this behavior is retained
- * for consistency, the inaccuracy is very small. The code here always
+ * for consistency; the inaccuracy is very small. The code here always
* overwrites the coefficients, regardless of whether they have been
* defaulted or set already.
*/
@@ -1068,7 +1070,7 @@ png_gamma_threshold(png_fixed_point screen_gamma, png_fixed_point file_gamma)
* the palette.
*/
-/*For the moment 'png_init_palette_transformations' and
+/* For the moment 'png_init_palette_transformations' and
* 'png_init_rgb_transformations' only do some flag canceling optimizations.
* The intent is that these two routines should have palette or rgb operations
* extracted from 'png_init_read_transformations'.
@@ -1093,25 +1095,31 @@ png_init_palette_transformations(png_structp png_ptr)
/* Ignore if all the entries are opaque (unlikely!) */
for (i=0; i<png_ptr->num_trans; ++i)
+ {
if (png_ptr->trans_alpha[i] == 255)
continue;
else if (png_ptr->trans_alpha[i] == 0)
input_has_transparency = 1;
else
+ {
+ input_has_transparency = 1;
input_has_alpha = 1;
+ break;
+ }
+ }
}
/* If no alpha we can optimize. */
- if (!input_has_alpha)
+ if (input_has_alpha == 0)
{
/* Any alpha means background and associative alpha processing is
- * required, however if the alpha is 0 or 1 throughout OPTIIMIZE_ALPHA
+ * required, however if the alpha is 0 or 1 throughout OPTIMIZE_ALPHA
* and ENCODE_ALPHA are irrelevant.
*/
png_ptr->transformations &= ~PNG_ENCODE_ALPHA;
png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
- if (!input_has_transparency)
+ if (input_has_transparency == 0)
png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND);
}
@@ -1167,10 +1175,10 @@ png_init_rgb_transformations(png_structp png_ptr)
int input_has_transparency = png_ptr->num_trans > 0;
/* If no alpha we can optimize. */
- if (!input_has_alpha)
+ if (input_has_alpha == 0)
{
/* Any alpha means background and associative alpha processing is
- * required, however if the alpha is 0 or 1 throughout OPTIIMIZE_ALPHA
+ * required, however if the alpha is 0 or 1 throughout OPTIMIZE_ALPHA
* and ENCODE_ALPHA are irrelevant.
*/
# ifdef PNG_READ_ALPHA_MODE_SUPPORTED
@@ -1178,7 +1186,7 @@ png_init_rgb_transformations(png_structp png_ptr)
png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA;
# endif
- if (!input_has_transparency)
+ if (input_has_transparency == 0)
png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND);
}
@@ -1221,7 +1229,7 @@ png_init_rgb_transformations(png_structp png_ptr)
default:
case 8:
- /* Already 8 bits, fall through */
+ /* FALL THROUGH (already 8 bits) */
case 16:
/* Already a full 16 bits */
@@ -1304,7 +1312,7 @@ png_init_read_transformations(png_structp png_ptr)
* the code immediately below if the transform can be handled outside the
* row loop.
*/
- if (gamma_correction)
+ if (gamma_correction != 0)
png_ptr->transformations |= PNG_GAMMA;
else
@@ -1313,7 +1321,7 @@ png_init_read_transformations(png_structp png_ptr)
#endif
/* Certain transformations have the effect of preventing other
- * transformations that happen afterward in png_do_read_transformations,
+ * transformations that happen afterward in png_do_read_transformations;
* resolve the interdependencies here. From the code of
* png_do_read_transformations the order is:
*
@@ -1702,11 +1710,11 @@ png_init_read_transformations(png_structp png_ptr)
g_sig = png_gamma_significant(g);
gs_sig = png_gamma_significant(gs);
- if (g_sig)
+ if (g_sig != 0)
png_ptr->background_1.gray = png_gamma_correct(png_ptr,
png_ptr->background.gray, g);
- if (gs_sig)
+ if (gs_sig != 0)
png_ptr->background.gray = png_gamma_correct(png_ptr,
png_ptr->background.gray, gs);
@@ -1715,7 +1723,7 @@ png_init_read_transformations(png_structp png_ptr)
(png_ptr->background.red != png_ptr->background.gray))
{
/* RGB or RGBA with color background */
- if (g_sig)
+ if (g_sig != 0)
{
png_ptr->background_1.red = png_gamma_correct(png_ptr,
png_ptr->background.red, g);
@@ -1727,7 +1735,7 @@ png_init_read_transformations(png_structp png_ptr)
png_ptr->background.blue, g);
}
- if (gs_sig)
+ if (gs_sig != 0)
{
png_ptr->background.red = png_gamma_correct(png_ptr,
png_ptr->background.red, gs);
@@ -1770,8 +1778,8 @@ png_init_read_transformations(png_structp png_ptr)
int num_palette = png_ptr->num_palette;
int i;
- /*NOTE: there are other transformations that should probably be in here
- * too.
+ /* NOTE: there are other transformations that should probably be in
+ * here too.
*/
for (i = 0; i < num_palette; i++)
{
@@ -1830,12 +1838,15 @@ png_init_read_transformations(png_structp png_ptr)
#ifdef PNG_READ_SHIFT_SUPPORTED
if ((png_ptr->transformations & PNG_SHIFT) &&
+ !(png_ptr->transformations & PNG_EXPAND) &&
(png_ptr->color_type == PNG_COLOR_TYPE_PALETTE))
{
int i;
int istop = png_ptr->num_palette;
int shift = 8 - png_ptr->sig_bit.red;
+ png_ptr->transformations &= ~PNG_SHIFT;
+
/* significant bits can be in the range 1 to 7 for a meaninful result, if
* the number of significant bits is 0 then no shift is done (this is an
* error condition which is silently ignored.)
@@ -1895,6 +1906,9 @@ png_read_transform_info(png_structp png_ptr, png_infop info_ptr)
info_ptr->bit_depth = 8;
info_ptr->num_trans = 0;
+
+ if (png_ptr->palette == NULL)
+ png_error (png_ptr, "Palette is NULL in indexed image");
}
else
{
@@ -2042,10 +2056,10 @@ png_read_transform_info(png_structp png_ptr, png_infop info_ptr)
defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
if (png_ptr->transformations & PNG_USER_TRANSFORM)
{
- if (info_ptr->bit_depth < png_ptr->user_transform_depth)
+ if (png_ptr->user_transform_depth)
info_ptr->bit_depth = png_ptr->user_transform_depth;
- if (info_ptr->channels < png_ptr->user_transform_channels)
+ if (png_ptr->user_transform_channels)
info_ptr->channels = png_ptr->user_transform_channels;
}
#endif
@@ -2064,7 +2078,7 @@ defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
png_ptr->info_rowbytes = info_ptr->rowbytes;
#ifndef PNG_READ_EXPAND_SUPPORTED
- if (png_ptr)
+ if (png_ptr != NULL)
return;
#endif
}
@@ -2141,7 +2155,7 @@ png_do_read_transformations(png_structp png_ptr, png_row_infop row_info)
png_do_rgb_to_gray(png_ptr, row_info,
png_ptr->row_buf + 1);
- if (rgb_error)
+ if (rgb_error != 0)
{
png_ptr->rgb_to_gray_status=1;
if ((png_ptr->transformations & PNG_RGB_TO_GRAY) ==
@@ -2195,8 +2209,8 @@ png_do_read_transformations(png_structp png_ptr, png_row_infop row_info)
png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1);
#endif
-#if (defined PNG_READ_BACKGROUND_SUPPORTED) ||\
- (defined PNG_READ_ALPHA_MODE_SUPPORTED)
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
+ defined(PNG_READ_ALPHA_MODE_SUPPORTED)
if (png_ptr->transformations & PNG_COMPOSE)
png_do_compose(row_info, png_ptr->row_buf + 1, png_ptr);
#endif
@@ -2207,8 +2221,8 @@ png_do_read_transformations(png_structp png_ptr, png_row_infop row_info)
/* Because RGB_TO_GRAY does the gamma transform. */
!(png_ptr->transformations & PNG_RGB_TO_GRAY) &&
#endif
-#if (defined PNG_READ_BACKGROUND_SUPPORTED) ||\
- (defined PNG_READ_ALPHA_MODE_SUPPORTED)
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
+ defined(PNG_READ_ALPHA_MODE_SUPPORTED)
/* Because PNG_COMPOSE does the gamma transform if there is something to
* do (if there is an alpha channel or transparency.)
*/
@@ -2274,7 +2288,7 @@ png_do_read_transformations(png_structp png_ptr, png_row_infop row_info)
#endif
#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED
- /*NOTE: moved here in 1.5.4 (from much later in this list.) */
+ /* NOTE: moved here in 1.5.4 (from much later in this list.) */
if ((png_ptr->transformations & PNG_GRAY_TO_RGB) &&
(png_ptr->mode & PNG_BACKGROUND_IS_GRAY))
png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1);
@@ -2296,6 +2310,13 @@ png_do_read_transformations(png_structp png_ptr, png_row_infop row_info)
png_do_unpack(row_info, png_ptr->row_buf + 1);
#endif
+#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
+ /* Added at libpng-1.5.10 */
+ if (row_info->color_type == PNG_COLOR_TYPE_PALETTE &&
+ png_ptr->num_palette_max >= 0)
+ png_do_check_palette_indexes(png_ptr, row_info);
+#endif
+
#ifdef PNG_READ_BGR_SUPPORTED
if (png_ptr->transformations & PNG_BGR)
png_do_bgr(row_info, png_ptr->row_buf + 1);
@@ -2512,7 +2533,7 @@ png_do_unshift(png_row_infop row_info, png_bytep row,
have_shift = 1;
}
- if (!have_shift)
+ if (have_shift == 0)
return;
}
@@ -2948,13 +2969,13 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
png_bytep dp = sp + (png_size_t)row_width * 2;
for (i = 1; i < row_width; i++)
{
- *(--dp) = hi_filler;
*(--dp) = lo_filler;
+ *(--dp) = hi_filler;
*(--dp) = *(--sp);
*(--dp) = *(--sp);
}
- *(--dp) = hi_filler;
*(--dp) = lo_filler;
+ *(--dp) = hi_filler;
row_info->channels = 2;
row_info->pixel_depth = 32;
row_info->rowbytes = row_width * 4;
@@ -2969,8 +2990,8 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
{
*(--dp) = *(--sp);
*(--dp) = *(--sp);
- *(--dp) = hi_filler;
*(--dp) = lo_filler;
+ *(--dp) = hi_filler;
}
row_info->channels = 2;
row_info->pixel_depth = 32;
@@ -3029,8 +3050,8 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
png_bytep dp = sp + (png_size_t)row_width * 2;
for (i = 1; i < row_width; i++)
{
- *(--dp) = hi_filler;
*(--dp) = lo_filler;
+ *(--dp) = hi_filler;
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = *(--sp);
@@ -3038,8 +3059,8 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
*(--dp) = *(--sp);
*(--dp) = *(--sp);
}
- *(--dp) = hi_filler;
*(--dp) = lo_filler;
+ *(--dp) = hi_filler;
row_info->channels = 4;
row_info->pixel_depth = 64;
row_info->rowbytes = row_width * 8;
@@ -3058,8 +3079,8 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
*(--dp) = *(--sp);
*(--dp) = *(--sp);
*(--dp) = *(--sp);
- *(--dp) = hi_filler;
*(--dp) = lo_filler;
+ *(--dp) = hi_filler;
}
row_info->channels = 4;
@@ -3273,7 +3294,7 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
*(dp++) = red;
}
- if (have_alpha)
+ if (have_alpha != 0)
*(dp++) = *(sp++);
}
}
@@ -3293,7 +3314,7 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
if (red != green || red != blue)
{
rgb_error |= 1;
- /*NOTE: this is the historical approach which simply
+ /* NOTE: this is the historical approach which simply
* truncates the results.
*/
*(dp++) = (png_byte)((rc*red + gc*green + bc*blue)>>15);
@@ -3302,7 +3323,7 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
else
*(dp++) = red;
- if (have_alpha)
+ if (have_alpha != 0)
*(dp++) = *(sp++);
}
}
@@ -3320,11 +3341,17 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
for (i = 0; i < row_width; i++)
{
png_uint_16 red, green, blue, w;
-
+#if 0 /* Coverity doesn't like this */
red = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;
green = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;
blue = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2;
+#else
+ png_byte hi,lo;
+ hi=*(sp)++; lo=*(sp)++; red = (png_uint_16)((hi << 8) | (lo));
+ hi=*(sp)++; lo=*(sp)++; green = (png_uint_16)((hi << 8) | (lo));
+ hi=*(sp)++; lo=*(sp)++; blue = (png_uint_16)((hi << 8) | (lo));
+#endif
if (red == green && red == blue)
{
if (png_ptr->gamma_16_table != NULL)
@@ -3354,7 +3381,7 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
*(dp++) = (png_byte)((w>>8) & 0xff);
*(dp++) = (png_byte)(w & 0xff);
- if (have_alpha)
+ if (have_alpha != 0)
{
*(dp++) = *(sp++);
*(dp++) = *(sp++);
@@ -3388,7 +3415,7 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row)
*(dp++) = (png_byte)((gray16>>8) & 0xff);
*(dp++) = (png_byte)(gray16 & 0xff);
- if (have_alpha)
+ if (have_alpha != 0)
{
*(dp++) = *(sp++);
*(dp++) = *(sp++);
@@ -3467,8 +3494,8 @@ png_build_grayscale_palette(int bit_depth, png_colorp palette)
#ifdef PNG_READ_TRANSFORMS_SUPPORTED
-#if (defined PNG_READ_BACKGROUND_SUPPORTED) ||\
- (defined PNG_READ_ALPHA_MODE_SUPPORTED)
+#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\
+ defined(PNG_READ_ALPHA_MODE_SUPPORTED)
/* Replace any alpha or transparency with the supplied background color.
* "background" is already in the screen gamma, while "background_1" is
* at a gamma of 1.0. Paletted files have already been taken care of.
@@ -3514,7 +3541,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
*sp |= (png_byte)(png_ptr->background.gray << shift);
}
- if (!shift)
+ if (shift == 0)
{
shift = 7;
sp++;
@@ -3551,7 +3578,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
*sp |= (png_byte)(g << shift);
}
- if (!shift)
+ if (shift == 0)
{
shift = 6;
sp++;
@@ -3576,7 +3603,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
*sp |= (png_byte)(png_ptr->background.gray << shift);
}
- if (!shift)
+ if (shift == 0)
{
shift = 6;
sp++;
@@ -3614,7 +3641,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
*sp |= (png_byte)(g << shift);
}
- if (!shift)
+ if (shift == 0)
{
shift = 4;
sp++;
@@ -3639,7 +3666,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
*sp |= (png_byte)(png_ptr->background.gray << shift);
}
- if (!shift)
+ if (shift == 0)
{
shift = 4;
sp++;
@@ -3695,8 +3722,10 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
if (v == png_ptr->trans_color.gray)
{
/* Background is already in screen gamma */
- *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff);
- *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff);
+ *sp = (png_byte)((png_ptr->background.gray >> 8)
+ & 0xff);
+ *(sp + 1) = (png_byte)(png_ptr->background.gray
+ & 0xff);
}
else
@@ -3719,8 +3748,10 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
if (v == png_ptr->trans_color.gray)
{
- *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff);
- *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff);
+ *sp = (png_byte)((png_ptr->background.gray >> 8)
+ & 0xff);
+ *(sp + 1) = (png_byte)(png_ptr->background.gray
+ & 0xff);
}
}
}
@@ -3800,9 +3831,12 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
/* Background is already in screen gamma */
*sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
*(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
- *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff);
- *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff);
- *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff);
+ *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)
+ & 0xff);
+ *(sp + 3) = (png_byte)(png_ptr->background.green
+ & 0xff);
+ *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)
+ & 0xff);
*(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
}
@@ -3843,9 +3877,12 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
{
*sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
*(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
- *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff);
- *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff);
- *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff);
+ *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)
+ & 0xff);
+ *(sp + 3) = (png_byte)(png_ptr->background.green
+ & 0xff);
+ *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)
+ & 0xff);
*(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
}
}
@@ -3882,7 +3919,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
v = gamma_to_1[*sp];
png_composite(w, v, a, png_ptr->background_1.gray);
- if (!optimize)
+ if (optimize == 0)
w = gamma_from_1[w];
*sp = w;
}
@@ -3900,7 +3937,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
*sp = (png_byte)png_ptr->background.gray;
else if (a < 0xff)
- png_composite(*sp, *sp, a, png_ptr->background_1.gray);
+ png_composite(*sp, *sp, a, png_ptr->background.gray);
}
}
}
@@ -3928,7 +3965,8 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
else if (a == 0)
{
/* Background is already in screen gamma */
- *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff);
+ *sp = (png_byte)((png_ptr->background.gray >> 8)
+ & 0xff);
*(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff);
}
@@ -3938,7 +3976,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
png_composite_16(v, g, a, png_ptr->background_1.gray);
- if (optimize)
+ if (optimize != 0)
w = v;
else
w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8];
@@ -3958,7 +3996,8 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
if (a == 0)
{
- *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff);
+ *sp = (png_byte)((png_ptr->background.gray >> 8)
+ & 0xff);
*(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff);
}
@@ -3967,7 +4006,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
png_uint_16 g, v;
g = (png_uint_16)(((*sp) << 8) + *(sp + 1));
- png_composite_16(v, g, a, png_ptr->background_1.gray);
+ png_composite_16(v, g, a, png_ptr->background.gray);
*sp = (png_byte)((v >> 8) & 0xff);
*(sp + 1) = (png_byte)(v & 0xff);
}
@@ -4011,17 +4050,17 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
v = gamma_to_1[*sp];
png_composite(w, v, a, png_ptr->background_1.red);
- if (!optimize) w = gamma_from_1[w];
+ if (optimize == 0) w = gamma_from_1[w];
*sp = w;
v = gamma_to_1[*(sp + 1)];
png_composite(w, v, a, png_ptr->background_1.green);
- if (!optimize) w = gamma_from_1[w];
+ if (optimize == 0) w = gamma_from_1[w];
*(sp + 1) = w;
v = gamma_to_1[*(sp + 2)];
png_composite(w, v, a, png_ptr->background_1.blue);
- if (!optimize) w = gamma_from_1[w];
+ if (optimize == 0) w = gamma_from_1[w];
*(sp + 2) = w;
}
}
@@ -4088,9 +4127,12 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
/* Background is already in screen gamma */
*sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
*(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
- *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff);
- *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff);
- *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff);
+ *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)
+ & 0xff);
+ *(sp + 3) = (png_byte)(png_ptr->background.green
+ & 0xff);
+ *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)
+ & 0xff);
*(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
}
@@ -4100,23 +4142,26 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp];
png_composite_16(w, v, a, png_ptr->background_1.red);
- if (!optimize)
- w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
+ if (optimize == 0)
+ w = gamma_16_from_1[((w&0xff) >> gamma_shift)]
+ [w >> 8];
*sp = (png_byte)((w >> 8) & 0xff);
*(sp + 1) = (png_byte)(w & 0xff);
v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)];
png_composite_16(w, v, a, png_ptr->background_1.green);
- if (!optimize)
- w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
+ if (optimize == 0)
+ w = gamma_16_from_1[((w&0xff) >> gamma_shift)]
+ [w >> 8];
*(sp + 2) = (png_byte)((w >> 8) & 0xff);
*(sp + 3) = (png_byte)(w & 0xff);
v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)];
png_composite_16(w, v, a, png_ptr->background_1.blue);
- if (!optimize)
- w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8];
+ if (optimize == 0)
+ w = gamma_16_from_1[((w&0xff) >> gamma_shift)]
+ [w >> 8];
*(sp + 4) = (png_byte)((w >> 8) & 0xff);
*(sp + 5) = (png_byte)(w & 0xff);
@@ -4137,9 +4182,12 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr)
{
*sp = (png_byte)((png_ptr->background.red >> 8) & 0xff);
*(sp + 1) = (png_byte)(png_ptr->background.red & 0xff);
- *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff);
- *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff);
- *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff);
+ *(sp + 2) = (png_byte)((png_ptr->background.green >> 8)
+ & 0xff);
+ *(sp + 3) = (png_byte)(png_ptr->background.green
+ & 0xff);
+ *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8)
+ & 0xff);
*(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff);
}
@@ -4715,7 +4763,9 @@ png_do_expand(png_row_infop row_info, png_bytep row,
{
if (row_info->bit_depth == 8)
{
- gray = gray & 0xff;
+ /* NOTE: prior to libpng 1.5.14 this cleared out the top bits of
+ * 'gray', however if those are set it is an error.
+ */
sp = row + (png_size_t)row_width - 1;
dp = row + (png_size_t)(row_width << 1) - 1;
diff --git a/drivers/png/pngrutil.c b/drivers/png/pngrutil.c
index c53117ab29..632c5c8e02 100644
--- a/drivers/png/pngrutil.c
+++ b/drivers/png/pngrutil.c
@@ -1,8 +1,8 @@
/* pngrutil.c - utilities to read a PNG file
*
- * Last changed in libpng 1.5.7 [December 15, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.25 [December 17, 2015]
+ * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
@@ -18,8 +18,6 @@
#ifdef PNG_READ_SUPPORTED
-#define png_strtod(p,a,b) strtod(a,b)
-
png_uint_32 PNGAPI
png_get_uint_31(png_structp png_ptr, png_const_bytep buf)
{
@@ -91,7 +89,13 @@ png_get_int_32)(png_const_bytep buf)
return uval;
uval = (uval ^ 0xffffffff) + 1; /* 2's complement: -x = ~x+1 */
- return -(png_int_32)uval;
+ if ((uval & 0x80000000) == 0) /* no overflow */
+ return -(png_int_32)uval;
+ /* The following has to be safe; this function only gets called on PNG data
+ * and if we get here that data is invalid. 0 is the most safe value and
+ * if not then an attacker would surely just generate a PNG with 0 instead.
+ */
+ return 0;
}
/* Grab an unsigned 16-bit integer from a buffer in big-endian format. */
@@ -211,7 +215,7 @@ png_crc_finish(png_structp png_ptr, png_uint_32 skip)
png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
}
- if (i)
+ if (i != 0)
{
png_crc_read(png_ptr, png_ptr->zbuf, i);
}
@@ -267,7 +271,7 @@ png_crc_error(png_structp png_ptr)
/* The chunk CRC must be serialized in a single I/O call. */
png_read_data(png_ptr, crc_bytes, 4);
- if (need_crc)
+ if (need_crc != 0)
{
crc = png_get_uint_32(crc_bytes);
return ((int)(crc != png_ptr->crc));
@@ -284,6 +288,17 @@ png_inflate(png_structp png_ptr, png_bytep data, png_size_t size,
{
png_size_t count = 0;
+ /* HACK: added in libpng 1.5.18: the progressive reader always leaves
+ * png_ptr->zstream in a non-reset state. This causes a reset if it needs to
+ * be used again. This only copes with that one specific error; see libpng
+ * 1.6 for a better solution.
+ */
+ if ((png_ptr->flags & PNG_FLAG_ZSTREAM_PROGRESSIVE) != 0)
+ {
+ (void)inflateReset(&png_ptr->zstream);
+ png_ptr->flags &= ~PNG_FLAG_ZSTREAM_PROGRESSIVE;
+ }
+
/* zlib can't necessarily handle more than 65535 bytes at once (i.e. it can't
* even necessarily handle 65536 bytes) because the type uInt is "16 bits or
* more". Consequently it is necessary to chunk the input to zlib. This
@@ -432,15 +447,16 @@ png_decompress_chunk(png_structp png_ptr, int comp_type,
/* Now check the limits on this chunk - if the limit fails the
* compressed data will be removed, the prefix will remain.
*/
-#ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED
- if (png_ptr->user_chunk_malloc_max &&
+ if (prefix_size >= (~(png_size_t)0) - 1 ||
+ expanded_size >= (~(png_size_t)0) - 1 - prefix_size
+#ifdef PNG_USER_LIMITS_SUPPORTED
+ || (png_ptr->user_chunk_malloc_max &&
(prefix_size + expanded_size >= png_ptr->user_chunk_malloc_max - 1))
#else
-# ifdef PNG_USER_CHUNK_MALLOC_MAX
- if ((PNG_USER_CHUNK_MALLOC_MAX > 0) &&
+ || ((PNG_USER_CHUNK_MALLOC_MAX > 0) &&
prefix_size + expanded_size >= PNG_USER_CHUNK_MALLOC_MAX - 1)
-# endif
#endif
+ )
png_warning(png_ptr, "Exceeded size limit while expanding chunk");
/* If the size is zero either there was an error and a message
@@ -448,12 +464,7 @@ png_decompress_chunk(png_structp png_ptr, int comp_type,
* and we have nothing to do - the code will exit through the
* error case below.
*/
-#if defined(PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED) || \
- defined(PNG_USER_CHUNK_MALLOC_MAX)
else if (expanded_size > 0)
-#else
- if (expanded_size > 0)
-#endif
{
/* Success (maybe) - really uncompress the chunk. */
png_size_t new_size = 0;
@@ -600,7 +611,7 @@ void /* PRIVATE */
png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
{
png_color palette[PNG_MAX_PALETTE_LENGTH];
- int num, i;
+ int max_palette_length, num, i;
#ifdef PNG_POINTER_INDEXING_SUPPORTED
png_colorp pal_ptr;
#endif
@@ -653,8 +664,22 @@ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
}
}
+ /* The cast is safe because 'length' is less than 3*PNG_MAX_PALETTE_LENGTH */
num = (int)length / 3;
+ /* If the palette has 256 or fewer entries but is too large for the bit
+ * depth, we don't issue an error, to preserve the behavior of previous
+ * libpng versions. We silently truncate the unused extra palette entries
+ * here.
+ */
+ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+ max_palette_length = (1 << png_ptr->bit_depth);
+ else
+ max_palette_length = PNG_MAX_PALETTE_LENGTH;
+
+ if (num > max_palette_length)
+ num = max_palette_length;
+
#ifdef PNG_POINTER_INDEXING_SUPPORTED
for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++)
{
@@ -687,7 +712,7 @@ png_handle_PLTE(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
#endif
{
- png_crc_finish(png_ptr, 0);
+ png_crc_finish(png_ptr, (int) length - num * 3);
}
#ifndef PNG_READ_OPT_PLTE_SUPPORTED
@@ -1261,13 +1286,16 @@ png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
/* Should be an error, but we can cope with it */
png_warning(png_ptr, "Out of place iCCP chunk");
- if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP))
+ if ((png_ptr->mode & PNG_HAVE_iCCP) || (info_ptr != NULL &&
+ (info_ptr->valid & (PNG_INFO_iCCP|PNG_INFO_sRGB))))
{
png_warning(png_ptr, "Duplicate iCCP chunk");
png_crc_finish(png_ptr, length);
return;
}
+ png_ptr->mode |= PNG_HAVE_iCCP;
+
#ifdef PNG_MAX_MALLOC_64K
if (length > (png_uint_32)65535L)
{
@@ -1279,7 +1307,7 @@ png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
png_free(png_ptr, png_ptr->chunkdata);
png_ptr->chunkdata = (png_charp)png_malloc(png_ptr, length + 1);
- slength = (png_size_t)length;
+ slength = length;
png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
if (png_crc_finish(png_ptr, skip))
@@ -1299,7 +1327,7 @@ png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
/* There should be at least one zero (the compression type byte)
* following the separator, and we should be on it
*/
- if (profile >= png_ptr->chunkdata + slength - 1)
+ if (slength < 1U || profile >= png_ptr->chunkdata + slength - 1U)
{
png_free(png_ptr, png_ptr->chunkdata);
png_ptr->chunkdata = NULL;
@@ -1310,7 +1338,7 @@ png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
/* Compression_type should always be zero */
compression_type = *profile++;
- if (compression_type)
+ if (compression_type != 0)
{
png_warning(png_ptr, "Ignoring nonzero compression type in iCCP chunk");
compression_type = 0x00; /* Reset it to zero (libpng-1.0.6 through 1.0.8
@@ -1429,7 +1457,7 @@ png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
* that the PNG_MAX_MALLOC_64K test is enabled in this case, but this is a
* potential breakage point if the types in pngconf.h aren't exactly right.
*/
- slength = (png_size_t)length;
+ slength = length;
png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
if (png_crc_finish(png_ptr, skip))
@@ -1448,7 +1476,8 @@ png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
++entry_start;
/* A sample depth should follow the separator, and we should be on it */
- if (entry_start > (png_bytep)png_ptr->chunkdata + slength - 2)
+ if (slength < 2U ||
+ entry_start > (png_bytep)png_ptr->chunkdata + slength - 2U)
{
png_free(png_ptr, png_ptr->chunkdata);
png_ptr->chunkdata = NULL;
@@ -1797,16 +1826,16 @@ png_handle_hIST(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
return;
}
- num = length / 2 ;
-
- if (num != (unsigned int)png_ptr->num_palette || num >
- (unsigned int)PNG_MAX_PALETTE_LENGTH)
+ if (length > 2*PNG_MAX_PALETTE_LENGTH ||
+ length != (unsigned int) (2*png_ptr->num_palette))
{
png_warning(png_ptr, "Incorrect hIST chunk length");
png_crc_finish(png_ptr, length);
return;
}
+ num = length / 2 ;
+
for (i = 0; i < num; i++)
{
png_byte buf[2];
@@ -1956,7 +1985,7 @@ png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
return;
}
- slength = (png_size_t)length;
+ slength = length;
png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
if (png_crc_finish(png_ptr, 0))
@@ -1977,7 +2006,7 @@ png_handle_pCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
/* We need to have at least 12 bytes after the purpose string
* in order to get the parameter information.
*/
- if (endptr <= buf + 12)
+ if (endptr - buf <= 12)
{
png_warning(png_ptr, "Invalid pCAL data");
png_free(png_ptr, png_ptr->chunkdata);
@@ -2105,7 +2134,7 @@ png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
return;
}
- slength = (png_size_t)length;
+ slength = length;
png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
png_ptr->chunkdata[slength] = 0x00; /* Null terminate the last string */
@@ -2265,7 +2294,7 @@ png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
return;
}
- slength = (png_size_t)length;
+ slength = length;
png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
if (png_crc_finish(png_ptr, skip))
@@ -2310,7 +2339,7 @@ png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
png_ptr->chunkdata = NULL;
png_free(png_ptr, text_ptr);
- if (ret)
+ if (ret != 0)
png_warning(png_ptr, "Insufficient memory to process text chunk");
}
#endif
@@ -2373,7 +2402,7 @@ png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
return;
}
- slength = (png_size_t)length;
+ slength = length;
png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
if (png_crc_finish(png_ptr, 0))
@@ -2389,7 +2418,7 @@ png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
/* Empty loop */ ;
/* zTXt must have some text after the chunkdataword */
- if (text >= png_ptr->chunkdata + slength - 2)
+ if (slength < 2U || text >= png_ptr->chunkdata + slength - 2U)
{
png_warning(png_ptr, "Truncated zTXt chunk");
png_free(png_ptr, png_ptr->chunkdata);
@@ -2440,7 +2469,7 @@ png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
png_free(png_ptr, png_ptr->chunkdata);
png_ptr->chunkdata = NULL;
- if (ret)
+ if (ret != 0)
png_error(png_ptr, "Insufficient memory to store zTXt chunk");
}
#endif
@@ -2453,7 +2482,7 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
png_textp text_ptr;
png_charp key, lang, text, lang_key;
int comp_flag;
- int comp_type = 0;
+ int comp_type;
int ret;
png_size_t slength, prefix_len, data_len;
@@ -2504,7 +2533,7 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
return;
}
- slength = (png_size_t)length;
+ slength = length;
png_crc_read(png_ptr, (png_bytep)png_ptr->chunkdata, slength);
if (png_crc_finish(png_ptr, 0))
@@ -2526,7 +2555,7 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
* keyword
*/
- if (lang >= png_ptr->chunkdata + slength - 3)
+ if (slength < 3U || lang >= png_ptr->chunkdata + slength - 3U)
{
png_warning(png_ptr, "Truncated iTXt chunk");
png_free(png_ptr, png_ptr->chunkdata);
@@ -2534,18 +2563,30 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
return;
}
- else
- {
- comp_flag = *lang++;
- comp_type = *lang++;
- }
+ comp_flag = *lang++;
+ comp_type = *lang++;
- if (comp_type || (comp_flag && comp_flag != PNG_TEXT_COMPRESSION_zTXt))
+ /* 1.5.14: The spec says "for uncompressed text decoders shall ignore [the
+ * compression type]". The compression flag shall be 0 (no compression) or
+ * 1 (compressed with method 0 - deflate.)
+ */
+ if (comp_flag/*compressed*/ != 0)
{
- png_warning(png_ptr, "Unknown iTXt compression type or method");
- png_free(png_ptr, png_ptr->chunkdata);
- png_ptr->chunkdata = NULL;
- return;
+ if (comp_flag != 1)
+ {
+ png_warning(png_ptr, "invalid iTXt compression flag");
+ png_free(png_ptr, png_ptr->chunkdata);
+ png_ptr->chunkdata = NULL;
+ return;
+ }
+
+ if (comp_type != 0)
+ {
+ png_warning(png_ptr, "unknown iTXt compression type");
+ png_free(png_ptr, png_ptr->chunkdata);
+ png_ptr->chunkdata = NULL;
+ return;
+ }
}
for (lang_key = lang; *lang_key; lang_key++)
@@ -2578,7 +2619,7 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
key=png_ptr->chunkdata;
- if (comp_flag)
+ if (comp_flag/*compressed*/)
png_decompress_chunk(png_ptr, comp_type,
(size_t)length, prefix_len, &data_len);
@@ -2596,7 +2637,8 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
return;
}
- text_ptr->compression = (int)comp_flag + 1;
+ text_ptr->compression =
+ (comp_flag ? PNG_ITXT_COMPRESSION_zTXt : PNG_ITXT_COMPRESSION_NONE);
text_ptr->lang_key = png_ptr->chunkdata + (lang_key - key);
text_ptr->lang = png_ptr->chunkdata + (lang - key);
text_ptr->itxt_length = data_len;
@@ -2610,7 +2652,7 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length)
png_free(png_ptr, png_ptr->chunkdata);
png_ptr->chunkdata = NULL;
- if (ret)
+ if (ret != 0)
png_error(png_ptr, "Insufficient memory to store iTXt chunk");
}
#endif
@@ -2787,7 +2829,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
{
unsigned int pixel_depth = png_ptr->transformed_pixel_depth;
png_const_bytep sp = png_ptr->row_buf + 1;
- png_uint_32 row_width = png_ptr->width;
+ png_alloc_size_t row_width = png_ptr->width;
unsigned int pass = png_ptr->pass;
png_bytep end_ptr = 0;
png_byte end_byte = 0;
@@ -2939,7 +2981,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
# define S_MASKS(d,s) { S_MASK(0,d,s), S_MASK(1,d,s), S_MASK(2,d,s),\
S_MASK(3,d,s), S_MASK(4,d,s), S_MASK(5,d,s) }
-# define B_MASKS(d,s) { B_MASK(1,d,s), S_MASK(3,d,s), S_MASK(5,d,s) }
+# define B_MASKS(d,s) { B_MASK(1,d,s), B_MASK(3,d,s), B_MASK(5,d,s) }
# define DEPTH_INDEX(d) ((d)==1?0:((d)==2?1:2))
@@ -3050,7 +3092,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
}
/* Work out the bytes to copy. */
- if (display)
+ if (display != 0)
{
/* When doing the 'block' algorithm the pixel in the pass gets
* replicated to adjacent pixels. This is why the even (0,2,4,6)
@@ -3060,7 +3102,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
/* But don't allow this number to exceed the actual row width. */
if (bytes_to_copy > row_width)
- bytes_to_copy = row_width;
+ bytes_to_copy = (unsigned int)/*SAFE*/row_width;
}
else /* normal row; Adam7 only ever gives us one pixel to copy. */
@@ -3152,7 +3194,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
{
png_uint_32p dp32 = (png_uint_32p)dp;
png_const_uint_32p sp32 = (png_const_uint_32p)sp;
- unsigned int skip = (bytes_to_jump-bytes_to_copy) /
+ size_t skip = (bytes_to_jump-bytes_to_copy) /
sizeof (png_uint_32);
do
@@ -3193,7 +3235,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
{
png_uint_16p dp16 = (png_uint_16p)dp;
png_const_uint_16p sp16 = (png_const_uint_16p)sp;
- unsigned int skip = (bytes_to_jump-bytes_to_copy) /
+ size_t skip = (bytes_to_jump-bytes_to_copy) /
sizeof (png_uint_16);
do
@@ -3238,7 +3280,7 @@ png_combine_row(png_structp png_ptr, png_bytep dp, int display)
dp += bytes_to_jump;
row_width -= bytes_to_jump;
if (bytes_to_copy > row_width)
- bytes_to_copy = row_width;
+ bytes_to_copy = (unsigned int)/*SAFE*/row_width;
}
}
@@ -3477,7 +3519,7 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass,
for (i = 0; i < row_info->width; i++)
{
- png_byte v[8];
+ png_byte v[8]; /* SAFE; pixel_depth does not exceed 64 */
int j;
png_memcpy(v, sp, pixel_bytes);
@@ -3661,68 +3703,6 @@ png_read_filter_row_paeth_multibyte_pixel(png_row_infop row_info, png_bytep row,
}
}
-#ifdef PNG_ARM_NEON
-
-#if 0
-#ifdef __linux__
-#include <stdio.h>
-#include <elf.h>
-#include <asm/hwcap.h>
-
-static int png_have_hwcap(unsigned cap)
-{
- FILE *f = fopen("/proc/self/auxv", "r");
- Elf32_auxv_t aux;
- int have_cap = 0;
-
- if (!f)
- return 0;
-
- while (fread(&aux, sizeof(aux), 1, f) > 0)
- {
- if (aux.a_type == AT_HWCAP &&
- aux.a_un.a_val & cap)
- {
- have_cap = 1;
- break;
- }
- }
-
- fclose(f);
-
- return have_cap;
-}
-#endif /* __linux__ */
-#endif
-static void
-png_init_filter_functions_neon(png_structp pp, unsigned int bpp)
-{
-#if 0
-#ifdef __linux__
- if (!png_have_hwcap(HWCAP_NEON))
- return;
-#endif
-#endif
- pp->read_filter[PNG_FILTER_VALUE_UP-1] = png_read_filter_row_up_neon;
-
- if (bpp == 3)
- {
- pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub3_neon;
- pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg3_neon;
- pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =
- png_read_filter_row_paeth3_neon;
- }
-
- else if (bpp == 4)
- {
- pp->read_filter[PNG_FILTER_VALUE_SUB-1] = png_read_filter_row_sub4_neon;
- pp->read_filter[PNG_FILTER_VALUE_AVG-1] = png_read_filter_row_avg4_neon;
- pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =
- png_read_filter_row_paeth4_neon;
- }
-}
-#endif /* PNG_ARM_NEON */
-
static void
png_init_filter_functions(png_structp pp)
{
@@ -3738,8 +3718,16 @@ png_init_filter_functions(png_structp pp)
pp->read_filter[PNG_FILTER_VALUE_PAETH-1] =
png_read_filter_row_paeth_multibyte_pixel;
-#ifdef PNG_ARM_NEON
- png_init_filter_functions_neon(pp, bpp);
+#ifdef PNG_FILTER_OPTIMIZATIONS
+ /* To use this define PNG_FILTER_OPTIMIZATIONS as the name of a function to
+ * call to install hardware optimizations for the above functions; simply
+ * replace whatever elements of the pp->read_filter[] array with a hardware
+ * specific (or, for that matter, generic) optimization.
+ *
+ * To see an example of this examine what configure.ac does when
+ * --enable-arm-neon is specified on the command line.
+ */
+ PNG_FILTER_OPTIMIZATIONS(pp, bpp);
#endif
}
@@ -3747,10 +3735,13 @@ void /* PRIVATE */
png_read_filter_row(png_structp pp, png_row_infop row_info, png_bytep row,
png_const_bytep prev_row, int filter)
{
- if (pp->read_filter[0] == NULL)
- png_init_filter_functions(pp);
if (filter > PNG_FILTER_VALUE_NONE && filter < PNG_FILTER_VALUE_LAST)
+ {
+ if (pp->read_filter[0] == NULL)
+ png_init_filter_functions(pp);
+
pp->read_filter[filter-1](row_info, row, prev_row);
+ }
}
#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
diff --git a/drivers/png/pngset.c b/drivers/png/pngset.c
index 92db3890a8..61be6bc62e 100644
--- a/drivers/png/pngset.c
+++ b/drivers/png/pngset.c
@@ -1,8 +1,8 @@
/* pngset.c - storage of image information into info struct
*
- * Last changed in libpng 1.5.7 [December 15, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.26 [December 17, 2015]
+ * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
@@ -20,6 +20,60 @@
#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
+#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) ||\
+ defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED)
+/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification,
+ * and if invalid, correct the keyword rather than discarding the entire
+ * chunk. The PNG 1.0 specification requires keywords 1-79 characters in
+ * length, forbids leading or trailing whitespace, multiple internal spaces,
+ * and the non-break space (0x80) from ISO 8859-1. Returns keyword length.
+ *
+ * The 'new_key' buffer must be 80 characters in size (for the keyword plus a
+ * trailing '\0'). If this routine returns 0 then there was no keyword, or a
+ * valid one could not be generated, and the caller must handle the error by not
+ * setting the keyword.
+ */
+static png_uint_32
+png_check_keyword(png_const_charp key, png_bytep new_key)
+{
+ png_uint_32 key_len = 0;
+ int space = 1;
+
+ if (key == NULL)
+ {
+ *new_key = 0;
+ return 0;
+ }
+
+ while (*key && key_len < 79)
+ {
+ png_byte ch = (png_byte)*key++;
+
+ if ((ch > 32 && ch <= 126) || (ch >= 161 /*&& ch <= 255*/))
+ *new_key++ = ch, ++key_len, space = 0;
+
+ else if (space == 0)
+ {
+ /* A space or an invalid character when one wasn't seen immediately
+ * before; output just a space.
+ */
+ *new_key++ = 32, ++key_len, space = 1;
+ }
+ }
+
+ if (key_len > 0 && space != 0) /* trailing space */
+ --key_len, --new_key;
+
+ /* Terminate the keyword */
+ *new_key = 0;
+
+ if (key_len == 0)
+ return 0;
+
+ return key_len;
+}
+#endif /* TEXT || pCAL || iCCP || sPLT */
+
#ifdef PNG_bKGD_SUPPORTED
void PNGAPI
png_set_bKGD(png_structp png_ptr, png_infop info_ptr,
@@ -123,12 +177,12 @@ png_set_cHRM_XYZ(png_structp png_ptr, png_infop info_ptr, double red_X,
png_fixed(png_ptr, red_X, "cHRM Red X"),
png_fixed(png_ptr, red_Y, "cHRM Red Y"),
png_fixed(png_ptr, red_Z, "cHRM Red Z"),
- png_fixed(png_ptr, green_X, "cHRM Red X"),
- png_fixed(png_ptr, green_Y, "cHRM Red Y"),
- png_fixed(png_ptr, green_Z, "cHRM Red Z"),
- png_fixed(png_ptr, blue_X, "cHRM Red X"),
- png_fixed(png_ptr, blue_Y, "cHRM Red Y"),
- png_fixed(png_ptr, blue_Z, "cHRM Red Z"));
+ png_fixed(png_ptr, green_X, "cHRM Green X"),
+ png_fixed(png_ptr, green_Y, "cHRM Green Y"),
+ png_fixed(png_ptr, green_Z, "cHRM Green Z"),
+ png_fixed(png_ptr, blue_X, "cHRM Blue X"),
+ png_fixed(png_ptr, blue_Y, "cHRM Blue Y"),
+ png_fixed(png_ptr, blue_Z, "cHRM Blue Z"));
}
# endif /* PNG_FLOATING_POINT_SUPPORTED */
@@ -149,7 +203,7 @@ png_set_gAMA_fixed(png_structp png_ptr, png_infop info_ptr, png_fixed_point
* possible for 1/gamma to overflow the limit of 21474 and this means the
* gamma value must be at least 5/100000 and hence at most 20000.0. For
* safety the limits here are a little narrower. The values are 0.00016 to
- * 6250.0, which are truly ridiculous gammma values (and will produce
+ * 6250.0, which are truly ridiculous gamma values (and will produce
* displays that are all black or all white.)
*/
if (file_gamma < 16 || file_gamma > 625000000)
@@ -252,16 +306,7 @@ png_set_IHDR(png_structp png_ptr, png_infop info_ptr,
info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
- /* Check for potential overflow */
- if (width >
- (PNG_UINT_32_MAX >> 3) /* 8-byte RRGGBBAA pixels */
- - 48 /* bigrowbuf hack */
- - 1 /* filter byte */
- - 7*8 /* rounding of width to multiple of 8 pixels */
- - 8) /* extra max_pixel_depth pad */
- info_ptr->rowbytes = 0;
- else
- info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
+ info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
}
#ifdef PNG_oFFs_SUPPORTED
@@ -287,6 +332,7 @@ png_set_pCAL(png_structp png_ptr, png_infop info_ptr,
png_const_charp purpose, png_int_32 X0, png_int_32 X1, int type,
int nparams, png_const_charp units, png_charpp params)
{
+ png_byte new_purpose[80];
png_size_t length;
int i;
@@ -295,7 +341,15 @@ png_set_pCAL(png_structp png_ptr, png_infop info_ptr,
if (png_ptr == NULL || info_ptr == NULL)
return;
- length = png_strlen(purpose) + 1;
+ length = png_check_keyword(purpose, new_purpose);
+
+ if (length == 0)
+ {
+ png_warning(png_ptr, "pCAL: invalid purpose keyword");
+ return;
+ }
+
+ ++length;
png_debug1(3, "allocating purpose for info (%lu bytes)",
(unsigned long)length);
@@ -318,7 +372,7 @@ png_set_pCAL(png_structp png_ptr, png_infop info_ptr,
return;
}
- png_memcpy(info_ptr->pcal_purpose, purpose, length);
+ png_memcpy(info_ptr->pcal_purpose, new_purpose, length);
png_debug(3, "storing X0, X1, type, and nparams in info");
info_ptr->pcal_X0 = X0;
@@ -517,12 +571,17 @@ png_set_PLTE(png_structp png_ptr, png_infop info_ptr,
png_const_colorp palette, int num_palette)
{
+ png_uint_32 max_palette_length;
+
png_debug1(1, "in %s storage function", "PLTE");
if (png_ptr == NULL || info_ptr == NULL)
return;
- if (num_palette < 0 || num_palette > PNG_MAX_PALETTE_LENGTH)
+ max_palette_length = (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ?
+ (1 << info_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH;
+
+ if (num_palette < 0 || num_palette > (int) max_palette_length)
{
if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
png_error(png_ptr, "Invalid palette length");
@@ -541,8 +600,8 @@ png_set_PLTE(png_structp png_ptr, png_infop info_ptr,
png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0);
/* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead
- * of num_palette entries, in case of an invalid PNG file that has
- * too-large sample values.
+ * of num_palette entries, in case of an invalid PNG file or incorrect
+ * call to png_set_PLTE() with too-large sample values.
*/
png_ptr->palette = (png_colorp)png_calloc(png_ptr,
PNG_MAX_PALETTE_LENGTH * png_sizeof(png_color));
@@ -618,6 +677,7 @@ png_set_iCCP(png_structp png_ptr, png_infop info_ptr,
png_const_charp name, int compression_type,
png_const_bytep profile, png_uint_32 proflen)
{
+ png_byte new_name[80];
png_charp new_iccp_name;
png_bytep new_iccp_profile;
png_size_t length;
@@ -627,7 +687,15 @@ png_set_iCCP(png_structp png_ptr, png_infop info_ptr,
if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL)
return;
- length = png_strlen(name)+1;
+ length = png_check_keyword(name, new_name);
+
+ if (length == 0)
+ {
+ png_warning(png_ptr, "iCCP: invalid keyword");
+ return;
+ }
+
+ ++length;
new_iccp_name = (png_charp)png_malloc_warn(png_ptr, length);
if (new_iccp_name == NULL)
@@ -636,7 +704,7 @@ png_set_iCCP(png_structp png_ptr, png_infop info_ptr,
return;
}
- png_memcpy(new_iccp_name, name, length);
+ png_memcpy(new_iccp_name, new_name, length);
new_iccp_profile = (png_bytep)png_malloc_warn(png_ptr, proflen);
if (new_iccp_profile == NULL)
@@ -671,7 +739,7 @@ png_set_text(png_structp png_ptr, png_infop info_ptr, png_const_textp text_ptr,
int ret;
ret = png_set_text_2(png_ptr, info_ptr, text_ptr, num_text);
- if (ret)
+ if (ret != 0)
png_error(png_ptr, "Insufficient memory to store text");
}
@@ -680,8 +748,9 @@ png_set_text_2(png_structp png_ptr, png_infop info_ptr,
png_const_textp text_ptr, int num_text)
{
int i;
+ size_t element_size;
- png_debug1(1, "in %lx storage function", png_ptr == NULL ? "unexpected" :
+ png_debug1(1, "in %lx storage function", png_ptr == NULL ? 0xabadca11 :
(unsigned long)png_ptr->chunk_name);
if (png_ptr == NULL || info_ptr == NULL || num_text == 0)
@@ -690,26 +759,42 @@ png_set_text_2(png_structp png_ptr, png_infop info_ptr,
/* Make sure we have enough space in the "text" array in info_struct
* to hold all of the incoming text_ptr objects.
*/
+
+ element_size=png_sizeof(png_text);
+ if (num_text < 0 ||
+ num_text > INT_MAX - info_ptr->num_text - 8 ||
+ (unsigned int)/*SAFE*/(num_text +/*SAFE*/
+ info_ptr->num_text + 8) >=
+ PNG_SIZE_MAX/element_size)
+ {
+ png_warning(png_ptr, "too many text chunks");
+ return(0);
+ }
+
if (info_ptr->num_text + num_text > info_ptr->max_text)
{
+ int old_max_text = info_ptr->max_text;
+ int old_num_text = info_ptr->num_text;
+
if (info_ptr->text != NULL)
{
png_textp old_text;
- int old_max;
- old_max = info_ptr->max_text;
info_ptr->max_text = info_ptr->num_text + num_text + 8;
old_text = info_ptr->text;
+
info_ptr->text = (png_textp)png_malloc_warn(png_ptr,
(png_size_t)(info_ptr->max_text * png_sizeof(png_text)));
if (info_ptr->text == NULL)
{
- png_free(png_ptr, old_text);
+ /* Restore to previous condition */
+ info_ptr->max_text = old_max_text;
+ info_ptr->text = old_text;
return(1);
}
- png_memcpy(info_ptr->text, old_text, (png_size_t)(old_max *
+ png_memcpy(info_ptr->text, old_text, (png_size_t)(old_max_text *
png_sizeof(png_text)));
png_free(png_ptr, old_text);
}
@@ -721,7 +806,12 @@ png_set_text_2(png_structp png_ptr, png_infop info_ptr,
info_ptr->text = (png_textp)png_malloc_warn(png_ptr,
(png_size_t)(info_ptr->max_text * png_sizeof(png_text)));
if (info_ptr->text == NULL)
+ {
+ /* Restore to previous condition */
+ info_ptr->num_text = old_num_text;
+ info_ptr->max_text = old_max_text;
return(1);
+ }
info_ptr->free_me |= PNG_FREE_TEXT;
}
@@ -730,6 +820,7 @@ png_set_text_2(png_structp png_ptr, png_infop info_ptr,
}
for (i = 0; i < num_text; i++)
{
+ png_byte new_key[80], new_lang[80];
png_size_t text_length, key_len;
png_size_t lang_len, lang_key_len;
png_textp textp = &(info_ptr->text[info_ptr->num_text]);
@@ -744,7 +835,13 @@ png_set_text_2(png_structp png_ptr, png_infop info_ptr,
continue;
}
- key_len = png_strlen(text_ptr[i].key);
+ key_len = png_check_keyword(text_ptr[i].key, new_key);
+
+ if (key_len == 0)
+ {
+ png_warning(png_ptr, "invalid text keyword");
+ continue;
+ }
if (text_ptr[i].compression <= 0)
{
@@ -757,8 +854,9 @@ png_set_text_2(png_structp png_ptr, png_infop info_ptr,
{
/* Set iTXt data */
+ /* Zero length language is OK */
if (text_ptr[i].lang != NULL)
- lang_len = png_strlen(text_ptr[i].lang);
+ lang_len = png_check_keyword(text_ptr[i].lang, new_lang);
else
lang_len = 0;
@@ -806,7 +904,7 @@ png_set_text_2(png_structp png_ptr, png_infop info_ptr,
(key_len + lang_len + lang_key_len + text_length + 4),
textp->key);
- png_memcpy(textp->key, text_ptr[i].key,(png_size_t)(key_len));
+ png_memcpy(textp->key, new_key, (png_size_t)(key_len));
*(textp->key + key_len) = '\0';
if (text_ptr[i].compression > 0)
@@ -827,7 +925,7 @@ png_set_text_2(png_structp png_ptr, png_infop info_ptr,
textp->text = textp->key + key_len + 1;
}
- if (text_length)
+ if (text_length != 0)
png_memcpy(textp->text, text_ptr[i].text,
(png_size_t)(text_length));
@@ -888,6 +986,12 @@ png_set_tRNS(png_structp png_ptr, png_infop info_ptr,
if (png_ptr == NULL || info_ptr == NULL)
return;
+ if (num_trans < 0 || num_trans > PNG_MAX_PALETTE_LENGTH)
+ {
+ png_warning(png_ptr, "Ignoring invalid num_trans value");
+ return;
+ }
+
if (trans_alpha != NULL)
{
/* It may not actually be necessary to set png_ptr->trans_alpha here;
@@ -907,16 +1011,19 @@ png_set_tRNS(png_structp png_ptr, png_infop info_ptr,
if (trans_color != NULL)
{
- int sample_max = (1 << info_ptr->bit_depth);
-
- if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY &&
- (int)trans_color->gray > sample_max) ||
- (info_ptr->color_type == PNG_COLOR_TYPE_RGB &&
- ((int)trans_color->red > sample_max ||
- (int)trans_color->green > sample_max ||
- (int)trans_color->blue > sample_max)))
- png_warning(png_ptr,
- "tRNS chunk has out-of-range samples for bit_depth");
+ if (info_ptr->bit_depth < 16)
+ {
+ unsigned int sample_max = (1U << info_ptr->bit_depth) - 1U;
+
+ if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY &&
+ trans_color->gray > sample_max) ||
+ (info_ptr->color_type == PNG_COLOR_TYPE_RGB &&
+ (trans_color->red > sample_max ||
+ trans_color->green > sample_max ||
+ trans_color->blue > sample_max)))
+ png_warning(png_ptr,
+ "tRNS chunk has out-of-range samples for bit_depth");
+ }
png_memcpy(&(info_ptr->trans_color), trans_color,
png_sizeof(png_color_16));
@@ -949,14 +1056,25 @@ png_set_sPLT(png_structp png_ptr,
*/
{
png_sPLT_tp np;
- int i;
+ int i, j;
+ size_t element_size;
if (png_ptr == NULL || info_ptr == NULL)
return;
- np = (png_sPLT_tp)png_malloc_warn(png_ptr,
- (info_ptr->splt_palettes_num + nentries) *
- (png_size_t)png_sizeof(png_sPLT_t));
+ element_size = png_sizeof(png_sPLT_t);
+ if (nentries < 0 ||
+ nentries > INT_MAX-info_ptr->splt_palettes_num ||
+ (unsigned int)/*SAFE*/(nentries +/*SAFE*/
+ info_ptr->splt_palettes_num) >=
+ PNG_SIZE_MAX/element_size)
+ np=NULL;
+
+ else
+
+ np = (png_sPLT_tp)png_malloc_warn(png_ptr,
+ (info_ptr->splt_palettes_num + nentries) *
+ (png_size_t)png_sizeof(png_sPLT_t));
if (np == NULL)
{
@@ -970,13 +1088,22 @@ png_set_sPLT(png_structp png_ptr,
png_free(png_ptr, info_ptr->splt_palettes);
info_ptr->splt_palettes=NULL;
- for (i = 0; i < nentries; i++)
+ for (i = j = 0; i < nentries; i++)
{
- png_sPLT_tp to = np + info_ptr->splt_palettes_num + i;
+ png_sPLT_tp to = np + info_ptr->splt_palettes_num + j;
png_const_sPLT_tp from = entries + i;
+ png_byte new_name[80];
png_size_t length;
- length = png_strlen(from->name) + 1;
+ length = png_check_keyword(from->name, new_name);
+
+ if (length == 0)
+ {
+ png_warning(png_ptr, "sPLT: invalid keyword");
+ continue;
+ }
+
+ ++length; /* for trailing '\0' */
to->name = (png_charp)png_malloc_warn(png_ptr, length);
if (to->name == NULL)
@@ -986,7 +1113,7 @@ png_set_sPLT(png_structp png_ptr,
continue;
}
- png_memcpy(to->name, from->name, length);
+ png_memcpy(to->name, new_name, length);
to->entries = (png_sPLT_entryp)png_malloc_warn(png_ptr,
from->nentries * png_sizeof(png_sPLT_entry));
@@ -1004,10 +1131,11 @@ png_set_sPLT(png_structp png_ptr,
to->nentries = from->nentries;
to->depth = from->depth;
+ ++j;
}
info_ptr->splt_palettes = np;
- info_ptr->splt_palettes_num += nentries;
+ info_ptr->splt_palettes_num = j;
info_ptr->valid |= PNG_INFO_sPLT;
info_ptr->free_me |= PNG_FREE_SPLT;
}
@@ -1020,13 +1148,23 @@ png_set_unknown_chunks(png_structp png_ptr,
{
png_unknown_chunkp np;
int i;
+ size_t element_size;
if (png_ptr == NULL || info_ptr == NULL || num_unknowns == 0)
return;
- np = (png_unknown_chunkp)png_malloc_warn(png_ptr,
- (png_size_t)(info_ptr->unknown_chunks_num + num_unknowns) *
- png_sizeof(png_unknown_chunk));
+ element_size = png_sizeof(png_unknown_chunk);
+ if (num_unknowns < 0 ||
+ num_unknowns > INT_MAX-info_ptr->unknown_chunks_num ||
+ (unsigned int)/*SAFE*/(num_unknowns +/*SAFE*/
+ info_ptr->unknown_chunks_num) >=
+ PNG_SIZE_MAX/element_size)
+ np=NULL;
+
+ else
+ np = (png_unknown_chunkp)png_malloc_warn(png_ptr,
+ (png_size_t)(info_ptr->unknown_chunks_num + num_unknowns) *
+ png_sizeof(png_unknown_chunk));
if (np == NULL)
{
@@ -1189,11 +1327,12 @@ png_set_rows(png_structp png_ptr, png_infop info_ptr, png_bytepp row_pointers)
info_ptr->row_pointers = row_pointers;
- if (row_pointers)
+ if (row_pointers != NULL)
info_ptr->valid |= PNG_INFO_IDAT;
}
#endif
+#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
void PNGAPI
png_set_compression_buffer_size(png_structp png_ptr, png_size_t size)
{
@@ -1221,6 +1360,7 @@ png_set_compression_buffer_size(png_structp png_ptr, png_size_t size)
png_ptr->zstream.avail_out = 0;
png_ptr->zstream.avail_in = 0;
}
+#endif /* WRITE_CUSTOMIZE_COMPRESSION */
void PNGAPI
png_set_invalid(png_structp png_ptr, png_infop info_ptr, int mask)
@@ -1239,7 +1379,7 @@ png_set_user_limits (png_structp png_ptr, png_uint_32 user_width_max,
{
/* Images with dimensions larger than these limits will be
* rejected by png_set_IHDR(). To accept any PNG datastream
- * regardless of dimensions, set both limits to 0x7ffffffL.
+ * regardless of dimensions, set both limits to 0x7fffffffL.
*/
if (png_ptr == NULL)
return;
@@ -1253,7 +1393,7 @@ void PNGAPI
png_set_chunk_cache_max (png_structp png_ptr,
png_uint_32 user_chunk_cache_max)
{
- if (png_ptr)
+ if (png_ptr != NULL)
png_ptr->user_chunk_cache_max = user_chunk_cache_max;
}
@@ -1262,7 +1402,7 @@ void PNGAPI
png_set_chunk_malloc_max (png_structp png_ptr,
png_alloc_size_t user_chunk_malloc_max)
{
- if (png_ptr)
+ if (png_ptr != NULL)
png_ptr->user_chunk_malloc_max = user_chunk_malloc_max;
}
#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */
@@ -1274,11 +1414,28 @@ png_set_benign_errors(png_structp png_ptr, int allowed)
{
png_debug(1, "in png_set_benign_errors");
- if (allowed)
+ if (allowed != 0)
png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN;
else
png_ptr->flags &= ~PNG_FLAG_BENIGN_ERRORS_WARN;
}
#endif /* PNG_BENIGN_ERRORS_SUPPORTED */
+
+#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
+/* Whether to report invalid palette index; added at libng-1.5.10
+ * allowed - one of 0: disable; 1: enable
+ */
+void PNGAPI
+png_set_check_for_invalid_index(png_structp png_ptr, int allowed)
+{
+ png_debug(1, "in png_set_check_for_invalid_index");
+
+ if (allowed != 0)
+ png_ptr->num_palette_max = 0;
+
+ else
+ png_ptr->num_palette_max = -1;
+}
+#endif
#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */
diff --git a/drivers/png/pngstruct.h b/drivers/png/pngstruct.h
index 07f3a04255..52eef80e69 100644
--- a/drivers/png/pngstruct.h
+++ b/drivers/png/pngstruct.h
@@ -1,12 +1,11 @@
/* pngstruct.h - header file for PNG reference library
*
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.23 [July 23, 2015]
+ * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
- * Last changed in libpng 1.5.5 [September 22, 2011]
- *
* This code is released under the libpng license.
* For conditions of distribution and use, see the disclaimer
* and license in png.h
@@ -121,6 +120,12 @@ struct png_struct_def
png_uint_32 crc; /* current chunk CRC value */
png_colorp palette; /* palette from the input file */
png_uint_16 num_palette; /* number of color entries in palette */
+
+/* Added at libpng-1.5.10 */
+#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
+ int num_palette_max; /* maximum palette index found in IDAT */
+#endif
+
png_uint_16 num_trans; /* number of transparency values */
png_byte compression; /* file compression type (always 0) */
png_byte filter; /* file filter type (always 0) */
@@ -211,13 +216,6 @@ struct png_struct_def
int process_mode; /* what push library is currently doing */
int cur_palette; /* current push library palette index */
-# ifdef PNG_TEXT_SUPPORTED
- png_size_t current_text_size; /* current size of text input data */
- png_size_t current_text_left; /* how much text left to read in input */
- png_charp current_text; /* current text chunk buffer */
- png_charp current_text_ptr; /* current location in current_text */
-# endif /* PNG_PROGRESSIVE_READ_SUPPORTED && PNG_TEXT_SUPPORTED */
-
#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */
#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__)
@@ -238,17 +236,8 @@ struct png_struct_def
png_uint_16p hist; /* histogram */
#endif
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
- png_byte heuristic_method; /* heuristic for row filter selection */
- png_byte num_prev_filters; /* number of weights for previous rows */
- png_bytep prev_filters; /* filter type(s) of previous row(s) */
- png_uint_16p filter_weights; /* weight(s) for previous line(s) */
- png_uint_16p inv_filter_weights; /* 1/weight(s) for previous line(s) */
- png_uint_16p filter_costs; /* relative filter calculation cost */
- png_uint_16p inv_filter_costs; /* 1/relative filter calculation cost */
-#endif
-
#ifdef PNG_TIME_RFC1123_SUPPORTED
+ /* This is going to be unused in libpng16 and removed from libpng17 */
char time_buffer[29]; /* String to hold RFC 1123 time text */
#endif
@@ -283,9 +272,7 @@ struct png_struct_def
#endif
/* New member added in libpng-1.0.4 (renamed in 1.0.9) */
-#if defined(PNG_MNG_FEATURES_SUPPORTED) || \
- defined(PNG_READ_EMPTY_PLTE_SUPPORTED) || \
- defined(PNG_WRITE_EMPTY_PLTE_SUPPORTED)
+#if defined(PNG_MNG_FEATURES_SUPPORTED)
/* Changed from png_byte to png_uint_32 at version 1.2.0 */
png_uint_32 mng_features_permitted;
#endif
@@ -354,7 +341,13 @@ struct png_struct_def
/* New member added in libpng-1.5.6 */
png_bytep big_prev_row;
+/* New member added in libpng-1.5.7 */
void (*read_filter[PNG_FILTER_VALUE_LAST-1])(png_row_infop row_info,
png_bytep row, png_const_bytep prev_row);
+
+ /* Options */
+#ifdef PNG_SET_OPTION_SUPPORTED
+ png_byte options; /* On/off state (up to 4 options) */
+#endif
};
#endif /* PNGSTRUCT_H */
diff --git a/drivers/png/pngtrans.c b/drivers/png/pngtrans.c
index 6a6908dcd2..a5df5afe00 100644
--- a/drivers/png/pngtrans.c
+++ b/drivers/png/pngtrans.c
@@ -1,8 +1,8 @@
/* pngtrans.c - transforms the data in a row (used by both readers and writers)
*
- * Last changed in libpng 1.5.4 [July 7, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.19 [August 21, 2014]
+ * Copyright (c) 1998-2002,2004,2006-2014 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
@@ -452,7 +452,7 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start)
{
if (row_info->bit_depth == 8)
{
- if (at_start) /* Skip initial filler */
+ if (at_start != 0) /* Skip initial filler */
++sp;
else /* Skip initial channel and, for sp, the filler */
sp += 2, ++dp;
@@ -466,7 +466,7 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start)
else if (row_info->bit_depth == 16)
{
- if (at_start) /* Skip initial filler */
+ if (at_start != 0) /* Skip initial filler */
sp += 2;
else /* Skip initial channel and, for sp, the filler */
sp += 4, dp += 2;
@@ -492,7 +492,7 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start)
{
if (row_info->bit_depth == 8)
{
- if (at_start) /* Skip initial filler */
+ if (at_start != 0) /* Skip initial filler */
++sp;
else /* Skip initial channels and, for sp, the filler */
sp += 4, dp += 3;
@@ -506,7 +506,7 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start)
else if (row_info->bit_depth == 16)
{
- if (at_start) /* Skip initial filler */
+ if (at_start != 0) /* Skip initial filler */
sp += 2;
else /* Skip initial channels and, for sp, the filler */
sp += 8, dp += 6;
@@ -619,6 +619,109 @@ png_do_bgr(png_row_infop row_info, png_bytep row)
}
#endif /* PNG_READ_BGR_SUPPORTED or PNG_WRITE_BGR_SUPPORTED */
+#if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \
+ defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED)
+/* Added at libpng-1.5.10 */
+void /* PRIVATE */
+png_do_check_palette_indexes(png_structp png_ptr, png_row_infop row_info)
+{
+ if (png_ptr->num_palette < (1 << row_info->bit_depth) &&
+ png_ptr->num_palette > 0) /* num_palette can be 0 in MNG files */
+ {
+ /* Calculations moved outside switch in an attempt to stop different
+ * compiler warnings. 'padding' is in *bits* within the last byte, it is
+ * an 'int' because pixel_depth becomes an 'int' in the expression below,
+ * and this calculation is used because it avoids warnings that other
+ * forms produced on either GCC or MSVC.
+ */
+ int padding = (-row_info->pixel_depth * row_info->width) & 7;
+ png_bytep rp = png_ptr->row_buf + row_info->rowbytes;
+
+ switch (row_info->bit_depth)
+ {
+ case 1:
+ {
+ /* in this case, all bytes must be 0 so we don't need
+ * to unpack the pixels except for the rightmost one.
+ */
+ for (; rp > png_ptr->row_buf; rp--)
+ {
+ if (*rp >> padding != 0)
+ png_ptr->num_palette_max = 1;
+ padding = 0;
+ }
+
+ break;
+ }
+
+ case 2:
+ {
+ for (; rp > png_ptr->row_buf; rp--)
+ {
+ int i = ((*rp >> padding) & 0x03);
+
+ if (i > png_ptr->num_palette_max)
+ png_ptr->num_palette_max = i;
+
+ i = (((*rp >> padding) >> 2) & 0x03);
+
+ if (i > png_ptr->num_palette_max)
+ png_ptr->num_palette_max = i;
+
+ i = (((*rp >> padding) >> 4) & 0x03);
+
+ if (i > png_ptr->num_palette_max)
+ png_ptr->num_palette_max = i;
+
+ i = (((*rp >> padding) >> 6) & 0x03);
+
+ if (i > png_ptr->num_palette_max)
+ png_ptr->num_palette_max = i;
+
+ padding = 0;
+ }
+
+ break;
+ }
+
+ case 4:
+ {
+ for (; rp > png_ptr->row_buf; rp--)
+ {
+ int i = ((*rp >> padding) & 0x0f);
+
+ if (i > png_ptr->num_palette_max)
+ png_ptr->num_palette_max = i;
+
+ i = (((*rp >> padding) >> 4) & 0x0f);
+
+ if (i > png_ptr->num_palette_max)
+ png_ptr->num_palette_max = i;
+
+ padding = 0;
+ }
+
+ break;
+ }
+
+ case 8:
+ {
+ for (; rp > png_ptr->row_buf; rp--)
+ {
+ if (*rp > png_ptr->num_palette_max)
+ png_ptr->num_palette_max = (int) *rp;
+ }
+
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+}
+#endif /* PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED */
+
#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \
defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED)
#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED
diff --git a/drivers/png/pngwio.c b/drivers/png/pngwio.c
index 95ffb3429f..cc55521452 100644
--- a/drivers/png/pngwio.c
+++ b/drivers/png/pngwio.c
@@ -1,8 +1,8 @@
/* pngwio.c - functions for data output
*
- * Last changed in libpng 1.5.0 [January 6, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.18 [February 6, 2014]
+ * Copyright (c) 1998-2002,2004,2006-2014 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
@@ -207,6 +207,8 @@ png_set_write_fn(png_structp png_ptr, png_voidp io_ptr,
# else
png_ptr->output_flush_fn = output_flush_fn;
# endif
+#else
+ PNG_UNUSED(output_flush_fn)
#endif /* PNG_WRITE_FLUSH_SUPPORTED */
/* It is an error to read while writing a png file */
diff --git a/drivers/png/pngwrite.c b/drivers/png/pngwrite.c
index 6d3fd4c386..776c23603a 100644
--- a/drivers/png/pngwrite.c
+++ b/drivers/png/pngwrite.c
@@ -1,8 +1,8 @@
/* pngwrite.c - general routines to write a PNG file
*
- * Last changed in libpng 1.5.7 [December 15, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.23 [July 23, 2015]
+ * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
@@ -34,85 +34,87 @@ png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr)
if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE))
{
- /* Write PNG signature */
- png_write_sig(png_ptr);
+ /* Write PNG signature */
+ png_write_sig(png_ptr);
#ifdef PNG_MNG_FEATURES_SUPPORTED
- if ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) && \
- (png_ptr->mng_features_permitted))
- {
- png_warning(png_ptr, "MNG features are not allowed in a PNG datastream");
- png_ptr->mng_features_permitted = 0;
- }
+ if ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) && \
+ (png_ptr->mng_features_permitted))
+ {
+ png_warning(png_ptr,
+ "MNG features are not allowed in a PNG datastream");
+ png_ptr->mng_features_permitted = 0;
+ }
#endif
- /* Write IHDR information. */
- png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,
- info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type,
- info_ptr->filter_type,
+ /* Write IHDR information. */
+ png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height,
+ info_ptr->bit_depth, info_ptr->color_type,
+ info_ptr->compression_type, info_ptr->filter_type,
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
- info_ptr->interlace_type);
+ info_ptr->interlace_type
#else
- 0);
+ 0
#endif
- /* The rest of these check to see if the valid field has the appropriate
- * flag set, and if it does, writes the chunk.
- */
+ );
+ /* The rest of these check to see if the valid field has the appropriate
+ * flag set, and if it does, writes the chunk.
+ */
#ifdef PNG_WRITE_gAMA_SUPPORTED
- if (info_ptr->valid & PNG_INFO_gAMA)
- png_write_gAMA_fixed(png_ptr, info_ptr->gamma);
+ if (info_ptr->valid & PNG_INFO_gAMA)
+ png_write_gAMA_fixed(png_ptr, info_ptr->gamma);
#endif
#ifdef PNG_WRITE_sRGB_SUPPORTED
- if (info_ptr->valid & PNG_INFO_sRGB)
- png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent);
+ if (info_ptr->valid & PNG_INFO_sRGB)
+ png_write_sRGB(png_ptr, (int)info_ptr->srgb_intent);
#endif
#ifdef PNG_WRITE_iCCP_SUPPORTED
- if (info_ptr->valid & PNG_INFO_iCCP)
- png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_COMPRESSION_TYPE_BASE,
- (png_charp)info_ptr->iccp_profile, (int)info_ptr->iccp_proflen);
+ if (info_ptr->valid & PNG_INFO_iCCP)
+ png_write_iCCP(png_ptr, info_ptr->iccp_name, PNG_COMPRESSION_TYPE_BASE,
+ (png_charp)info_ptr->iccp_profile, (int)info_ptr->iccp_proflen);
#endif
#ifdef PNG_WRITE_sBIT_SUPPORTED
- if (info_ptr->valid & PNG_INFO_sBIT)
- png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
+ if (info_ptr->valid & PNG_INFO_sBIT)
+ png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type);
#endif
#ifdef PNG_WRITE_cHRM_SUPPORTED
- if (info_ptr->valid & PNG_INFO_cHRM)
- png_write_cHRM_fixed(png_ptr,
- info_ptr->x_white, info_ptr->y_white,
- info_ptr->x_red, info_ptr->y_red,
- info_ptr->x_green, info_ptr->y_green,
- info_ptr->x_blue, info_ptr->y_blue);
+ if (info_ptr->valid & PNG_INFO_cHRM)
+ png_write_cHRM_fixed(png_ptr,
+ info_ptr->x_white, info_ptr->y_white,
+ info_ptr->x_red, info_ptr->y_red,
+ info_ptr->x_green, info_ptr->y_green,
+ info_ptr->x_blue, info_ptr->y_blue);
#endif
#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
- if (info_ptr->unknown_chunks_num)
- {
- png_unknown_chunk *up;
-
- png_debug(5, "writing extra chunks");
-
- for (up = info_ptr->unknown_chunks;
- up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
- up++)
+ if (info_ptr->unknown_chunks_num)
{
- int keep = png_handle_as_unknown(png_ptr, up->name);
+ png_unknown_chunk *up;
- if (keep != PNG_HANDLE_CHUNK_NEVER &&
- up->location &&
- !(up->location & PNG_HAVE_PLTE) &&
- !(up->location & PNG_HAVE_IDAT) &&
- !(up->location & PNG_AFTER_IDAT) &&
- ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
- (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
+ png_debug(5, "writing extra chunks");
+
+ for (up = info_ptr->unknown_chunks;
+ up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num;
+ up++)
{
- if (up->size == 0)
- png_warning(png_ptr, "Writing zero-length unknown chunk");
+ int keep = png_handle_as_unknown(png_ptr, up->name);
+
+ if (keep != PNG_HANDLE_CHUNK_NEVER &&
+ up->location &&
+ !(up->location & PNG_HAVE_PLTE) &&
+ !(up->location & PNG_HAVE_IDAT) &&
+ !(up->location & PNG_AFTER_IDAT) &&
+ ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS ||
+ (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS)))
+ {
+ if (up->size == 0)
+ png_warning(png_ptr, "Writing zero-length unknown chunk");
- png_write_chunk(png_ptr, up->name, up->data, up->size);
+ png_write_chunk(png_ptr, up->name, up->data, up->size);
+ }
}
}
- }
#endif
png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE;
}
@@ -223,11 +225,14 @@ png_write_info(png_structp png_ptr, png_infop info_ptr)
info_ptr->text[i].lang,
info_ptr->text[i].lang_key,
info_ptr->text[i].text);
+ /* Mark this chunk as written */
+ if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
+ else
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
#else
- png_warning(png_ptr, "Unable to write international text");
+ png_warning(png_ptr, "Unable to write international text");
#endif
- /* Mark this chunk as written */
- info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
}
/* If we want a compressed text chunk */
@@ -238,11 +243,11 @@ png_write_info(png_structp png_ptr, png_infop info_ptr)
png_write_zTXt(png_ptr, info_ptr->text[i].key,
info_ptr->text[i].text, 0,
info_ptr->text[i].compression);
+ /* Mark this chunk as written */
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
#else
png_warning(png_ptr, "Unable to write compressed text");
#endif
- /* Mark this chunk as written */
- info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
}
else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
@@ -305,6 +310,11 @@ png_write_end(png_structp png_ptr, png_infop info_ptr)
if (!(png_ptr->mode & PNG_HAVE_IDAT))
png_error(png_ptr, "No IDATs written into file");
+#ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
+ if (png_ptr->num_palette_max > png_ptr->num_palette)
+ png_benign_error(png_ptr, "Wrote palette index exceeding num_palette");
+#endif
+
/* See if user wants us to write information chunks */
if (info_ptr != NULL)
{
@@ -335,11 +345,11 @@ png_write_end(png_structp png_ptr, png_infop info_ptr)
info_ptr->text[i].lang,
info_ptr->text[i].lang_key,
info_ptr->text[i].text);
+ /* Mark this chunk as written */
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
#else
png_warning(png_ptr, "Unable to write international text");
#endif
- /* Mark this chunk as written */
- info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
}
else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt)
@@ -349,11 +359,11 @@ png_write_end(png_structp png_ptr, png_infop info_ptr)
png_write_zTXt(png_ptr, info_ptr->text[i].key,
info_ptr->text[i].text, 0,
info_ptr->text[i].compression);
+ /* Mark this chunk as written */
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
#else
png_warning(png_ptr, "Unable to write compressed text");
#endif
- /* Mark this chunk as written */
- info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR;
}
else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE)
@@ -362,12 +372,11 @@ png_write_end(png_structp png_ptr, png_infop info_ptr)
/* Write uncompressed chunk */
png_write_tEXt(png_ptr, info_ptr->text[i].key,
info_ptr->text[i].text, 0);
+ /* Mark this chunk as written */
+ info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
#else
png_warning(png_ptr, "Unable to write uncompressed text");
#endif
-
- /* Mark this chunk as written */
- info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR;
}
}
#endif
@@ -415,7 +424,6 @@ png_write_end(png_structp png_ptr, png_infop info_ptr)
}
#ifdef PNG_CONVERT_tIME_SUPPORTED
-/* "tm" structure is not supported on WindowsCE */
void PNGAPI
png_convert_from_struct_tm(png_timep ptime, PNG_CONST struct tm FAR * ttime)
{
@@ -451,9 +459,6 @@ png_create_write_struct,(png_const_charp user_png_ver, png_voidp error_ptr,
warn_fn, NULL, NULL, NULL));
}
-/* Alternate initialize png_ptr structure, and allocate any memory needed */
-static void png_reset_filter_heuristics(png_structp png_ptr); /* forward decl */
-
PNG_FUNCTION(png_structp,PNGAPI
png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr,
@@ -495,14 +500,13 @@ png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
*/
#ifdef USE_FAR_KEYWORD
if (setjmp(tmp_jmpbuf))
+ png_memcpy(png_jmpbuf(png_ptr), tmp_jmpbuf, png_sizeof(jmp_buf));
+ PNG_ABORT();
#else
if (setjmp(png_jmpbuf(png_ptr))) /* sets longjmp to match setjmp */
-#endif
-#ifdef USE_FAR_KEYWORD
- png_memcpy(png_jmpbuf(png_ptr), tmp_jmpbuf, png_sizeof(jmp_buf));
-#endif
PNG_ABORT();
#endif
+#endif
#ifdef PNG_USER_MEM_SUPPORTED
png_set_mem_fn(png_ptr, mem_ptr, malloc_fn, free_fn);
@@ -515,7 +519,7 @@ png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
/* Initialize zbuf - compression buffer */
png_ptr->zbuf_size = PNG_ZBUF_SIZE;
- if (!png_cleanup_needed)
+ if (png_cleanup_needed == 0)
{
png_ptr->zbuf = (png_bytep)png_malloc_warn(png_ptr,
png_ptr->zbuf_size);
@@ -523,7 +527,7 @@ png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
png_cleanup_needed = 1;
}
- if (png_cleanup_needed)
+ if (png_cleanup_needed != 0)
{
/* Clean up PNG structure and deallocate any memory. */
png_free(png_ptr, png_ptr->zbuf);
@@ -539,10 +543,6 @@ png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
png_set_write_fn(png_ptr, NULL, NULL, NULL);
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
- png_reset_filter_heuristics(png_ptr);
-#endif
-
return (png_ptr);
}
@@ -759,7 +759,7 @@ png_write_row(png_structp png_ptr, png_const_bytep row)
{
png_do_write_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass);
/* This should always get caught above, but still ... */
- if (!(row_info.width))
+ if (row_info.width == 0)
{
png_write_finish_row(png_ptr);
return;
@@ -798,6 +798,14 @@ png_write_row(png_structp png_ptr, png_const_bytep row)
}
#endif
+/* Added at libpng-1.5.10 */
+#ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED
+ /* Check for out-of-range palette index */
+ if (row_info.color_type == PNG_COLOR_TYPE_PALETTE &&
+ png_ptr->num_palette_max >= 0)
+ png_do_check_palette_indexes(png_ptr, &row_info);
+#endif
+
/* Find a filter if necessary, filter the row and write it out. */
png_write_find_filter(png_ptr, &row_info);
@@ -851,7 +859,7 @@ png_write_flush(png_structp png_ptr)
png_error(png_ptr, "zlib error");
}
- if (!(png_ptr->zstream.avail_out))
+ if ((png_ptr->zstream.avail_out) == 0)
{
/* Write the IDAT and reset the zlib output buffer */
png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
@@ -969,13 +977,6 @@ png_write_destroy(png_structp png_ptr)
png_free(png_ptr, png_ptr->paeth_row);
#endif
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
- /* Use this to save a little code space, it doesn't free the filter_costs */
- png_reset_filter_heuristics(png_ptr);
- png_free(png_ptr, png_ptr->filter_costs);
- png_free(png_ptr, png_ptr->inv_filter_costs);
-#endif
-
#ifdef PNG_SETJMP_SUPPORTED
/* Reset structure */
png_memcpy(tmp_jmp, png_ptr->longjmp_buffer, png_sizeof(jmp_buf));
@@ -1029,6 +1030,7 @@ png_set_filter(png_structp png_ptr, int method, int filters)
case 5:
case 6:
case 7: png_warning(png_ptr, "Unknown row filter for method 0");
+ /* FALL THROUGH */
#endif /* PNG_WRITE_FILTER_SUPPORTED */
case PNG_FILTER_VALUE_NONE:
png_ptr->do_filter = PNG_FILTER_NONE; break;
@@ -1065,6 +1067,7 @@ png_set_filter(png_structp png_ptr, int method, int filters)
*/
if (png_ptr->row_buf != NULL)
{
+ png_ptr->do_filter = PNG_FILTER_NONE;
#ifdef PNG_WRITE_FILTER_SUPPORTED
if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL)
{
@@ -1125,8 +1128,8 @@ png_set_filter(png_structp png_ptr, int method, int filters)
}
if (png_ptr->do_filter == PNG_NO_FILTERS)
-#endif /* PNG_WRITE_FILTER_SUPPORTED */
png_ptr->do_filter = PNG_FILTER_NONE;
+#endif /* PNG_WRITE_FILTER_SUPPORTED */
}
}
else
@@ -1140,122 +1143,7 @@ png_set_filter(png_structp png_ptr, int method, int filters)
* filtered data going to zlib more consistent, hopefully resulting in
* better compression.
*/
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* GRR 970116 */
-/* Convenience reset API. */
-static void
-png_reset_filter_heuristics(png_structp png_ptr)
-{
- /* Clear out any old values in the 'weights' - this must be done because if
- * the app calls set_filter_heuristics multiple times with different
- * 'num_weights' values we would otherwise potentially have wrong sized
- * arrays.
- */
- png_ptr->num_prev_filters = 0;
- png_ptr->heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED;
- if (png_ptr->prev_filters != NULL)
- {
- png_bytep old = png_ptr->prev_filters;
- png_ptr->prev_filters = NULL;
- png_free(png_ptr, old);
- }
- if (png_ptr->filter_weights != NULL)
- {
- png_uint_16p old = png_ptr->filter_weights;
- png_ptr->filter_weights = NULL;
- png_free(png_ptr, old);
- }
-
- if (png_ptr->inv_filter_weights != NULL)
- {
- png_uint_16p old = png_ptr->inv_filter_weights;
- png_ptr->inv_filter_weights = NULL;
- png_free(png_ptr, old);
- }
-
- /* Leave the filter_costs - this array is fixed size. */
-}
-
-static int
-png_init_filter_heuristics(png_structp png_ptr, int heuristic_method,
- int num_weights)
-{
- if (png_ptr == NULL)
- return 0;
-
- /* Clear out the arrays */
- png_reset_filter_heuristics(png_ptr);
-
- /* Check arguments; the 'reset' function makes the correct settings for the
- * unweighted case, but we must handle the weight case by initializing the
- * arrays for the caller.
- */
- if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- int i;
-
- if (num_weights > 0)
- {
- png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr,
- (png_uint_32)(png_sizeof(png_byte) * num_weights));
-
- /* To make sure that the weighting starts out fairly */
- for (i = 0; i < num_weights; i++)
- {
- png_ptr->prev_filters[i] = 255;
- }
-
- png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr,
- (png_uint_32)(png_sizeof(png_uint_16) * num_weights));
-
- png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr,
- (png_uint_32)(png_sizeof(png_uint_16) * num_weights));
-
- for (i = 0; i < num_weights; i++)
- {
- png_ptr->inv_filter_weights[i] =
- png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
- }
-
- /* Safe to set this now */
- png_ptr->num_prev_filters = (png_byte)num_weights;
- }
-
- /* If, in the future, there are other filter methods, this would
- * need to be based on png_ptr->filter.
- */
- if (png_ptr->filter_costs == NULL)
- {
- png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr,
- (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
-
- png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr,
- (png_uint_32)(png_sizeof(png_uint_16) * PNG_FILTER_VALUE_LAST));
- }
-
- for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
- {
- png_ptr->inv_filter_costs[i] =
- png_ptr->filter_costs[i] = PNG_COST_FACTOR;
- }
-
- /* All the arrays are inited, safe to set this: */
- png_ptr->heuristic_method = PNG_FILTER_HEURISTIC_WEIGHTED;
-
- /* Return the 'ok' code. */
- return 1;
- }
- else if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT ||
- heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED)
- {
- return 1;
- }
- else
- {
- png_warning(png_ptr, "Unknown filter heuristic method");
- return 0;
- }
-}
-
+#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* DEPRECATED */
/* Provide floating and fixed point APIs */
#ifdef PNG_FLOATING_POINT_SUPPORTED
void PNGAPI
@@ -1263,52 +1151,11 @@ png_set_filter_heuristics(png_structp png_ptr, int heuristic_method,
int num_weights, png_const_doublep filter_weights,
png_const_doublep filter_costs)
{
- png_debug(1, "in png_set_filter_heuristics");
-
- /* The internal API allocates all the arrays and ensures that the elements of
- * those arrays are set to the default value.
- */
- if (!png_init_filter_heuristics(png_ptr, heuristic_method, num_weights))
- return;
-
- /* If using the weighted method copy in the weights. */
- if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- int i;
- for (i = 0; i < num_weights; i++)
- {
- if (filter_weights[i] <= 0.0)
- {
- png_ptr->inv_filter_weights[i] =
- png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
- }
-
- else
- {
- png_ptr->inv_filter_weights[i] =
- (png_uint_16)(PNG_WEIGHT_FACTOR*filter_weights[i]+.5);
-
- png_ptr->filter_weights[i] =
- (png_uint_16)(PNG_WEIGHT_FACTOR/filter_weights[i]+.5);
- }
- }
-
- /* Here is where we set the relative costs of the different filters. We
- * should take the desired compression level into account when setting
- * the costs, so that Paeth, for instance, has a high relative cost at low
- * compression levels, while it has a lower relative cost at higher
- * compression settings. The filter types are in order of increasing
- * relative cost, so it would be possible to do this with an algorithm.
- */
- for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) if (filter_costs[i] >= 1.0)
- {
- png_ptr->inv_filter_costs[i] =
- (png_uint_16)(PNG_COST_FACTOR / filter_costs[i] + .5);
-
- png_ptr->filter_costs[i] =
- (png_uint_16)(PNG_COST_FACTOR * filter_costs[i] + .5);
- }
- }
+ PNG_UNUSED(png_ptr)
+ PNG_UNUSED(heuristic_method)
+ PNG_UNUSED(num_weights)
+ PNG_UNUSED(filter_weights)
+ PNG_UNUSED(filter_costs)
}
#endif /* FLOATING_POINT */
@@ -1318,67 +1165,16 @@ png_set_filter_heuristics_fixed(png_structp png_ptr, int heuristic_method,
int num_weights, png_const_fixed_point_p filter_weights,
png_const_fixed_point_p filter_costs)
{
- png_debug(1, "in png_set_filter_heuristics_fixed");
-
- /* The internal API allocates all the arrays and ensures that the elements of
- * those arrays are set to the default value.
- */
- if (!png_init_filter_heuristics(png_ptr, heuristic_method, num_weights))
- return;
-
- /* If using the weighted method copy in the weights. */
- if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- int i;
- for (i = 0; i < num_weights; i++)
- {
- if (filter_weights[i] <= 0)
- {
- png_ptr->inv_filter_weights[i] =
- png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR;
- }
-
- else
- {
- png_ptr->inv_filter_weights[i] = (png_uint_16)
- ((PNG_WEIGHT_FACTOR*filter_weights[i]+PNG_FP_HALF)/PNG_FP_1);
-
- png_ptr->filter_weights[i] = (png_uint_16)((PNG_WEIGHT_FACTOR*
- PNG_FP_1+(filter_weights[i]/2))/filter_weights[i]);
- }
- }
-
- /* Here is where we set the relative costs of the different filters. We
- * should take the desired compression level into account when setting
- * the costs, so that Paeth, for instance, has a high relative cost at low
- * compression levels, while it has a lower relative cost at higher
- * compression settings. The filter types are in order of increasing
- * relative cost, so it would be possible to do this with an algorithm.
- */
- for (i = 0; i < PNG_FILTER_VALUE_LAST; i++)
- if (filter_costs[i] >= PNG_FP_1)
- {
- png_uint_32 tmp;
-
- /* Use a 32 bit unsigned temporary here because otherwise the
- * intermediate value will be a 32 bit *signed* integer (ANSI rules)
- * and this will get the wrong answer on division.
- */
- tmp = PNG_COST_FACTOR*PNG_FP_1 + (filter_costs[i]/2);
- tmp /= filter_costs[i];
-
- png_ptr->inv_filter_costs[i] = (png_uint_16)tmp;
-
- tmp = PNG_COST_FACTOR * filter_costs[i] + PNG_FP_HALF;
- tmp /= PNG_FP_1;
-
- png_ptr->filter_costs[i] = (png_uint_16)tmp;
- }
- }
+ PNG_UNUSED(png_ptr)
+ PNG_UNUSED(heuristic_method)
+ PNG_UNUSED(num_weights)
+ PNG_UNUSED(filter_weights)
+ PNG_UNUSED(filter_costs)
}
#endif /* FIXED_POINT */
-#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */
+#endif /* WRITE_WEIGHTED_FILTER */
+#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED
void PNGAPI
png_set_compression_level(png_structp png_ptr, int level)
{
@@ -1457,6 +1253,7 @@ png_set_compression_method(png_structp png_ptr, int method)
png_ptr->flags |= PNG_FLAG_ZLIB_CUSTOM_METHOD;
png_ptr->zlib_method = method;
}
+#endif /* WRITE_CUSTOMIZE_COMPRESSION */
/* The following were added to libpng-1.5.4 */
#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED
@@ -1514,10 +1311,10 @@ png_set_text_compression_window_bits(png_structp png_ptr, int window_bits)
#ifndef WBITS_8_OK
/* Avoid libpng bug with 256-byte windows */
if (window_bits == 8)
- {
- png_warning(png_ptr, "Text compression window is being reset to 512");
- window_bits = 9;
- }
+ {
+ png_warning(png_ptr, "Text compression window is being reset to 512");
+ window_bits = 9;
+ }
#endif
png_ptr->flags |= PNG_FLAG_ZTXT_CUSTOM_WINDOW_BITS;
diff --git a/drivers/png/pngwtran.c b/drivers/png/pngwtran.c
index 96608efcb4..24c436ffe4 100644
--- a/drivers/png/pngwtran.c
+++ b/drivers/png/pngwtran.c
@@ -1,8 +1,8 @@
/* pngwtran.c - transforms the data in a row for PNG writers
*
- * Last changed in libpng 1.5.6 [November 3, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Copyright (c) 1998-2002,2004,2006-2012 Glenn Randers-Pehrson
+ * Copyright (c) 1998-2012 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
@@ -45,8 +45,20 @@ png_do_write_transformations(png_structp png_ptr, png_row_infop row_info)
#ifdef PNG_WRITE_FILLER_SUPPORTED
if (png_ptr->transformations & PNG_FILLER)
- png_do_strip_channel(row_info, png_ptr->row_buf + 1,
- !(png_ptr->flags & PNG_FLAG_FILLER_AFTER));
+ {
+ if (png_ptr->color_type & (PNG_COLOR_MASK_ALPHA|PNG_COLOR_MASK_PALETTE))
+ {
+ /* GA, RGBA or palette; in any of these cases libpng will not do the
+ * the correct thing (whatever that might be).
+ */
+ png_warning(png_ptr, "incorrect png_set_filler call ignored");
+ png_ptr->transformations &= ~PNG_FILLER;
+ }
+
+ else
+ png_do_strip_channel(row_info, png_ptr->row_buf + 1,
+ !(png_ptr->flags & PNG_FLAG_FILLER_AFTER));
+ }
#endif
#ifdef PNG_WRITE_PACKSWAP_SUPPORTED
diff --git a/drivers/png/pngwutil.c b/drivers/png/pngwutil.c
index da18e9502e..d5f097fb97 100644
--- a/drivers/png/pngwutil.c
+++ b/drivers/png/pngwutil.c
@@ -1,8 +1,8 @@
/* pngwutil.c - utilities to write a PNG file
*
- * Last changed in libpng 1.5.6 [November 3, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.5.26 [December 17, 2015]
+ * Copyright (c) 1998-2002,2004,2006-2015 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
@@ -30,19 +30,20 @@ png_save_uint_32(png_bytep buf, png_uint_32 i)
}
#ifdef PNG_SAVE_INT_32_SUPPORTED
-/* The png_save_int_32 function assumes integers are stored in two's
- * complement format. If this isn't the case, then this routine needs to
- * be modified to write data in two's complement format. Note that,
- * the following works correctly even if png_int_32 has more than 32 bits
- * (compare the more complex code required on read for sign extention.)
+/* PNG signed integers are saved in 32-bit 2's complement format. ANSI C-90
+ * defines a cast of a signed integer to an unsigned integer either to preserve
+ * the value, if it is positive, or to calculate:
+ *
+ * (UNSIGNED_MAX+1) + integer
+ *
+ * Where UNSIGNED_MAX is the appropriate maximum unsigned value, so when the
+ * negative integral value is added the result will be an unsigned value
+ * correspnding to the 2's complement representation.
*/
void PNGAPI
png_save_int_32(png_bytep buf, png_int_32 i)
{
- buf[0] = (png_byte)((i >> 24) & 0xff);
- buf[1] = (png_byte)((i >> 16) & 0xff);
- buf[2] = (png_byte)((i >> 8) & 0xff);
- buf[3] = (png_byte)(i & 0xff);
+ png_save_uint_32(buf, i);
}
#endif
@@ -315,6 +316,7 @@ png_zlib_release(png_structp png_ptr)
if (ret != Z_OK)
{
+#ifdef PNG_WARNINGS_SUPPORTED
png_const_charp err;
PNG_WARNING_PARAMETERS(p)
@@ -349,6 +351,7 @@ png_zlib_release(png_structp png_ptr)
png_formatted_warning(png_ptr, p,
"zlib failed to reset compressor: @1(@2): @3");
+#endif
}
}
@@ -460,24 +463,21 @@ png_text_compress(png_structp png_ptr,
old_ptr = comp->output_ptr;
comp->output_ptr = (png_bytepp)png_malloc(png_ptr,
- (png_alloc_size_t)
- (comp->max_output_ptr * png_sizeof(png_charpp)));
+ (comp->max_output_ptr * png_sizeof(png_bytep)));
png_memcpy(comp->output_ptr, old_ptr, old_max
- * png_sizeof(png_charp));
+ * png_sizeof(png_bytep));
png_free(png_ptr, old_ptr);
}
else
comp->output_ptr = (png_bytepp)png_malloc(png_ptr,
- (png_alloc_size_t)
- (comp->max_output_ptr * png_sizeof(png_charp)));
+ (comp->max_output_ptr * png_sizeof(png_bytep)));
}
/* Save the data */
comp->output_ptr[comp->num_output_ptr] =
- (png_bytep)png_malloc(png_ptr,
- (png_alloc_size_t)png_ptr->zbuf_size);
+ (png_bytep)png_malloc(png_ptr, png_ptr->zbuf_size);
png_memcpy(comp->output_ptr[comp->num_output_ptr], png_ptr->zbuf,
png_ptr->zbuf_size);
@@ -569,14 +569,15 @@ png_text_compress(png_structp png_ptr,
/* Ship the compressed text out via chunk writes */
static void /* PRIVATE */
-png_write_compressed_data_out(png_structp png_ptr, compression_state *comp)
+png_write_compressed_data_out(png_structp png_ptr, compression_state *comp,
+ png_size_t data_len)
{
int i;
/* Handle the no-compression case */
if (comp->input)
{
- png_write_chunk_data(png_ptr, comp->input, comp->input_len);
+ png_write_chunk_data(png_ptr, comp->input, data_len);
return;
}
@@ -585,7 +586,7 @@ png_write_compressed_data_out(png_structp png_ptr, compression_state *comp)
/* The zbuf_size test is because the code below doesn't work if zbuf_size is
* '1'; simply skip it to avoid memory overwrite.
*/
- if (comp->input_len >= 2 && comp->input_len < 16384 && png_ptr->zbuf_size > 1)
+ if (data_len >= 2 && comp->input_len < 16384 && png_ptr->zbuf_size > 1)
{
unsigned int z_cmf; /* zlib compression method and flags */
@@ -825,7 +826,7 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height,
png_ptr->zstream.zfree = png_zfree;
png_ptr->zstream.opaque = (voidpf)png_ptr;
- if (!(png_ptr->do_filter))
+ if ((png_ptr->do_filter) == PNG_NO_FILTERS)
{
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE ||
png_ptr->bit_depth < 8)
@@ -895,17 +896,20 @@ void /* PRIVATE */
png_write_PLTE(png_structp png_ptr, png_const_colorp palette,
png_uint_32 num_pal)
{
- png_uint_32 i;
+ png_uint_32 max_palette_length, i;
png_const_colorp pal_ptr;
png_byte buf[3];
png_debug(1, "in png_write_PLTE");
+ max_palette_length = (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ?
+ (1 << png_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH;
+
if ((
#ifdef PNG_MNG_FEATURES_SUPPORTED
!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) &&
#endif
- num_pal == 0) || num_pal > 256)
+ num_pal == 0) || num_pal > max_palette_length)
{
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{
@@ -1095,7 +1099,6 @@ png_write_iCCP(png_structp png_ptr, png_const_charp name, int compression_type,
png_const_charp profile, int profile_len)
{
png_size_t name_len;
- png_charp new_name;
compression_state comp;
int embedded_profile_len = 0;
@@ -1107,8 +1110,7 @@ png_write_iCCP(png_structp png_ptr, png_const_charp name, int compression_type,
comp.input = NULL;
comp.input_len = 0;
- if ((name_len = png_check_keyword(png_ptr, name, &new_name)) == 0)
- return;
+ name_len = png_strlen(name);
if (compression_type != PNG_COMPRESSION_TYPE_BASE)
png_warning(png_ptr, "Unknown compression type in iCCP chunk");
@@ -1127,8 +1129,6 @@ png_write_iCCP(png_structp png_ptr, png_const_charp name, int compression_type,
{
png_warning(png_ptr,
"Embedded profile length in iCCP chunk is negative");
-
- png_free(png_ptr, new_name);
return;
}
@@ -1136,8 +1136,6 @@ png_write_iCCP(png_structp png_ptr, png_const_charp name, int compression_type,
{
png_warning(png_ptr,
"Embedded profile length too large in iCCP chunk");
-
- png_free(png_ptr, new_name);
return;
}
@@ -1149,7 +1147,7 @@ png_write_iCCP(png_structp png_ptr, png_const_charp name, int compression_type,
profile_len = embedded_profile_len;
}
- if (profile_len)
+ if (profile_len != 0)
profile_len = png_text_compress(png_ptr, profile,
(png_size_t)profile_len, PNG_COMPRESSION_TYPE_BASE, &comp);
@@ -1157,19 +1155,21 @@ png_write_iCCP(png_structp png_ptr, png_const_charp name, int compression_type,
png_write_chunk_header(png_ptr, png_iCCP,
(png_uint_32)(name_len + profile_len + 2));
- new_name[name_len + 1] = 0x00;
+ png_write_chunk_data(png_ptr, (png_bytep)name, name_len);
- png_write_chunk_data(png_ptr, (png_bytep)new_name,
- (png_size_t)(name_len + 2));
+ {
+ png_byte buffer[2];
+ buffer[0] = 0; /* terminate name */
+ buffer[1] = 0xFFU & compression_type;
+ png_write_chunk_data(png_ptr, buffer, 2);
+ }
- if (profile_len)
+ if (profile_len != 0)
{
- comp.input_len = profile_len;
- png_write_compressed_data_out(png_ptr, &comp);
+ png_write_compressed_data_out(png_ptr, &comp, profile_len);
}
png_write_chunk_end(png_ptr);
- png_free(png_ptr, new_name);
}
#endif
@@ -1179,7 +1179,6 @@ void /* PRIVATE */
png_write_sPLT(png_structp png_ptr, png_const_sPLT_tp spalette)
{
png_size_t name_len;
- png_charp new_name;
png_byte entrybuf[10];
png_size_t entry_size = (spalette->depth == 8 ? 6 : 10);
png_size_t palette_size = entry_size * spalette->nentries;
@@ -1190,14 +1189,13 @@ png_write_sPLT(png_structp png_ptr, png_const_sPLT_tp spalette)
png_debug(1, "in png_write_sPLT");
- if ((name_len = png_check_keyword(png_ptr,spalette->name, &new_name))==0)
- return;
+ name_len = png_strlen(spalette->name);
/* Make sure we include the NULL after the name */
png_write_chunk_header(png_ptr, png_sPLT,
(png_uint_32)(name_len + 2 + palette_size));
- png_write_chunk_data(png_ptr, (png_bytep)new_name,
+ png_write_chunk_data(png_ptr, (png_bytep)spalette->name,
(png_size_t)(name_len + 1));
png_write_chunk_data(png_ptr, &spalette->depth, (png_size_t)1);
@@ -1253,7 +1251,6 @@ png_write_sPLT(png_structp png_ptr, png_const_sPLT_tp spalette)
#endif
png_write_chunk_end(png_ptr);
- png_free(png_ptr, new_name);
}
#endif
@@ -1370,7 +1367,8 @@ png_write_tRNS(png_structp png_ptr, png_const_bytep trans_alpha,
}
/* Write the chunk out as it is */
- png_write_complete_chunk(png_ptr, png_tRNS, trans_alpha, (png_size_t)num_trans);
+ png_write_complete_chunk(png_ptr, png_tRNS, trans_alpha,
+ (png_size_t)num_trans);
}
else if (color_type == PNG_COLOR_TYPE_GRAY)
@@ -1508,138 +1506,6 @@ png_write_hIST(png_structp png_ptr, png_const_uint_16p hist, int num_hist)
}
#endif
-#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \
- defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
-/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification,
- * and if invalid, correct the keyword rather than discarding the entire
- * chunk. The PNG 1.0 specification requires keywords 1-79 characters in
- * length, forbids leading or trailing whitespace, multiple internal spaces,
- * and the non-break space (0x80) from ISO 8859-1. Returns keyword length.
- *
- * The new_key is allocated to hold the corrected keyword and must be freed
- * by the calling routine. This avoids problems with trying to write to
- * static keywords without having to have duplicate copies of the strings.
- */
-png_size_t /* PRIVATE */
-png_check_keyword(png_structp png_ptr, png_const_charp key, png_charpp new_key)
-{
- png_size_t key_len;
- png_const_charp ikp;
- png_charp kp, dp;
- int kflag;
- int kwarn=0;
-
- png_debug(1, "in png_check_keyword");
-
- *new_key = NULL;
-
- if (key == NULL || (key_len = png_strlen(key)) == 0)
- {
- png_warning(png_ptr, "zero length keyword");
- return ((png_size_t)0);
- }
-
- png_debug1(2, "Keyword to be checked is '%s'", key);
-
- *new_key = (png_charp)png_malloc_warn(png_ptr, (png_uint_32)(key_len + 2));
-
- if (*new_key == NULL)
- {
- png_warning(png_ptr, "Out of memory while procesing keyword");
- return ((png_size_t)0);
- }
-
- /* Replace non-printing characters with a blank and print a warning */
- for (ikp = key, dp = *new_key; *ikp != '\0'; ikp++, dp++)
- {
- if ((png_byte)*ikp < 0x20 ||
- ((png_byte)*ikp > 0x7E && (png_byte)*ikp < 0xA1))
- {
- PNG_WARNING_PARAMETERS(p)
-
- png_warning_parameter_unsigned(p, 1, PNG_NUMBER_FORMAT_02x,
- (png_byte)*ikp);
- png_formatted_warning(png_ptr, p, "invalid keyword character 0x@1");
- *dp = ' ';
- }
-
- else
- {
- *dp = *ikp;
- }
- }
- *dp = '\0';
-
- /* Remove any trailing white space. */
- kp = *new_key + key_len - 1;
- if (*kp == ' ')
- {
- png_warning(png_ptr, "trailing spaces removed from keyword");
-
- while (*kp == ' ')
- {
- *(kp--) = '\0';
- key_len--;
- }
- }
-
- /* Remove any leading white space. */
- kp = *new_key;
- if (*kp == ' ')
- {
- png_warning(png_ptr, "leading spaces removed from keyword");
-
- while (*kp == ' ')
- {
- kp++;
- key_len--;
- }
- }
-
- png_debug1(2, "Checking for multiple internal spaces in '%s'", kp);
-
- /* Remove multiple internal spaces. */
- for (kflag = 0, dp = *new_key; *kp != '\0'; kp++)
- {
- if (*kp == ' ' && kflag == 0)
- {
- *(dp++) = *kp;
- kflag = 1;
- }
-
- else if (*kp == ' ')
- {
- key_len--;
- kwarn = 1;
- }
-
- else
- {
- *(dp++) = *kp;
- kflag = 0;
- }
- }
- *dp = '\0';
- if (kwarn)
- png_warning(png_ptr, "extra interior spaces removed from keyword");
-
- if (key_len == 0)
- {
- png_free(png_ptr, *new_key);
- png_warning(png_ptr, "Zero length keyword");
- }
-
- if (key_len > 79)
- {
- png_warning(png_ptr, "keyword length must be 1 - 79 characters");
- (*new_key)[79] = '\0';
- key_len = 79;
- }
-
- return (key_len);
-}
-#endif
-
#ifdef PNG_WRITE_tEXt_SUPPORTED
/* Write a tEXt chunk */
void /* PRIVATE */
@@ -1647,12 +1513,10 @@ png_write_tEXt(png_structp png_ptr, png_const_charp key, png_const_charp text,
png_size_t text_len)
{
png_size_t key_len;
- png_charp new_key;
png_debug(1, "in png_write_tEXt");
- if ((key_len = png_check_keyword(png_ptr, key, &new_key))==0)
- return;
+ key_len = strlen(key);
if (text == NULL || *text == '\0')
text_len = 0;
@@ -1669,15 +1533,14 @@ png_write_tEXt(png_structp png_ptr, png_const_charp key, png_const_charp text,
* any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them.
* The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
*/
- png_write_chunk_data(png_ptr, (png_bytep)new_key,
+ png_write_chunk_data(png_ptr, (png_bytep)key,
(png_size_t)(key_len + 1));
- if (text_len)
+ if (text_len != 0)
png_write_chunk_data(png_ptr, (png_const_bytep)text,
(png_size_t)text_len);
png_write_chunk_end(png_ptr);
- png_free(png_ptr, new_key);
}
#endif
@@ -1689,7 +1552,6 @@ png_write_zTXt(png_structp png_ptr, png_const_charp key, png_const_charp text,
{
png_size_t key_len;
png_byte buf;
- png_charp new_key;
compression_state comp;
png_debug(1, "in png_write_zTXt");
@@ -1700,16 +1562,11 @@ png_write_zTXt(png_structp png_ptr, png_const_charp key, png_const_charp text,
comp.input = NULL;
comp.input_len = 0;
- if ((key_len = png_check_keyword(png_ptr, key, &new_key)) == 0)
- {
- png_free(png_ptr, new_key);
- return;
- }
+ key_len = strlen(key);
if (text == NULL || *text == '\0' || compression==PNG_TEXT_COMPRESSION_NONE)
{
- png_write_tEXt(png_ptr, new_key, text, (png_size_t)0);
- png_free(png_ptr, new_key);
+ png_write_tEXt(png_ptr, key, text, (png_size_t)0);
return;
}
@@ -1724,19 +1581,16 @@ png_write_zTXt(png_structp png_ptr, png_const_charp key, png_const_charp text,
(png_uint_32)(key_len+text_len + 2));
/* Write key */
- png_write_chunk_data(png_ptr, (png_bytep)new_key,
+ png_write_chunk_data(png_ptr, (png_bytep)key,
(png_size_t)(key_len + 1));
- png_free(png_ptr, new_key);
-
buf = (png_byte)compression;
/* Write compression */
png_write_chunk_data(png_ptr, &buf, (png_size_t)1);
/* Write the compressed data */
- comp.input_len = text_len;
- png_write_compressed_data_out(png_ptr, &comp);
+ png_write_compressed_data_out(png_ptr, &comp, text_len);
/* Close the chunk */
png_write_chunk_end(png_ptr);
@@ -1750,8 +1604,6 @@ png_write_iTXt(png_structp png_ptr, int compression, png_const_charp key,
png_const_charp lang, png_const_charp lang_key, png_const_charp text)
{
png_size_t lang_len, key_len, lang_key_len, text_len;
- png_charp new_lang;
- png_charp new_key = NULL;
png_byte cbuf[2];
compression_state comp;
@@ -1762,15 +1614,13 @@ png_write_iTXt(png_structp png_ptr, int compression, png_const_charp key,
comp.output_ptr = NULL;
comp.input = NULL;
- if ((key_len = png_check_keyword(png_ptr, key, &new_key)) == 0)
- return;
+ key_len = png_strlen(key);
- if ((lang_len = png_check_keyword(png_ptr, lang, &new_lang)) == 0)
- {
- png_warning(png_ptr, "Empty language field in iTXt chunk");
- new_lang = NULL;
+ if (lang == NULL)
lang_len = 0;
- }
+
+ else
+ lang_len = png_strlen(lang);
if (lang_key == NULL)
lang_key_len = 0;
@@ -1805,7 +1655,7 @@ png_write_iTXt(png_structp png_ptr, int compression, png_const_charp key,
* any non-Latin-1 characters except for NEWLINE. ISO PNG will forbid them.
* The NUL character is forbidden by PNG-1.0 through PNG-1.2 and ISO PNG.
*/
- png_write_chunk_data(png_ptr, (png_bytep)new_key, (png_size_t)(key_len + 1));
+ png_write_chunk_data(png_ptr, (png_bytep)key, (png_size_t)(key_len + 1));
/* Set the compression flag */
if (compression == PNG_ITXT_COMPRESSION_NONE ||
@@ -1821,18 +1671,15 @@ png_write_iTXt(png_structp png_ptr, int compression, png_const_charp key,
png_write_chunk_data(png_ptr, cbuf, (png_size_t)2);
cbuf[0] = 0;
- png_write_chunk_data(png_ptr, (new_lang ? (png_const_bytep)new_lang : cbuf),
+ png_write_chunk_data(png_ptr, (lang ? (png_const_bytep)lang : cbuf),
(png_size_t)(lang_len + 1));
png_write_chunk_data(png_ptr, (lang_key ? (png_const_bytep)lang_key : cbuf),
(png_size_t)(lang_key_len + 1));
- png_write_compressed_data_out(png_ptr, &comp);
+ png_write_compressed_data_out(png_ptr, &comp, text_len);
png_write_chunk_end(png_ptr);
-
- png_free(png_ptr, new_key);
- png_free(png_ptr, new_lang);
}
#endif
@@ -1866,7 +1713,6 @@ png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0,
png_size_t purpose_len, units_len, total_len;
png_size_tp params_len;
png_byte buf[10];
- png_charp new_purpose;
int i;
png_debug1(1, "in png_write_pCAL (%d parameters)", nparams);
@@ -1874,7 +1720,7 @@ png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0,
if (type >= PNG_EQUATION_LAST)
png_warning(png_ptr, "Unrecognized equation type for pCAL chunk");
- purpose_len = png_check_keyword(png_ptr, purpose, &new_purpose) + 1;
+ purpose_len = strlen(purpose) + 1;
png_debug1(3, "pCAL purpose length = %d", (int)purpose_len);
units_len = png_strlen(units) + (nparams == 0 ? 0 : 1);
png_debug1(3, "pCAL units length = %d", (int)units_len);
@@ -1896,7 +1742,7 @@ png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0,
png_debug1(3, "pCAL total length = %d", (int)total_len);
png_write_chunk_header(png_ptr, png_pCAL, (png_uint_32)total_len);
- png_write_chunk_data(png_ptr, (png_const_bytep)new_purpose, purpose_len);
+ png_write_chunk_data(png_ptr, (png_const_bytep)purpose, purpose_len);
png_save_int_32(buf, X0);
png_save_int_32(buf + 4, X1);
buf[8] = (png_byte)type;
@@ -1904,8 +1750,6 @@ png_write_pCAL(png_structp png_ptr, png_charp purpose, png_int_32 X0,
png_write_chunk_data(png_ptr, buf, (png_size_t)10);
png_write_chunk_data(png_ptr, (png_const_bytep)units, (png_size_t)units_len);
- png_free(png_ptr, new_purpose);
-
for (i = 0; i < nparams; i++)
{
png_write_chunk_data(png_ptr, (png_const_bytep)params[i], params_len[i]);
@@ -2430,20 +2274,9 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
png_uint_32 mins, bpp;
png_byte filter_to_do = png_ptr->do_filter;
png_size_t row_bytes = row_info->rowbytes;
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
- int num_p_filters = png_ptr->num_prev_filters;
-#endif
png_debug(1, "in png_write_find_filter");
-#ifndef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
- if (png_ptr->row_number == 0 && filter_to_do == PNG_ALL_FILTERS)
- {
- /* These will never be selected so we need not test them. */
- filter_to_do &= ~(PNG_FILTER_UP | PNG_FILTER_PAETH);
- }
-#endif
-
/* Find out how many bytes offset each pixel is */
bpp = (row_info->pixel_depth + 7) >> 3;
@@ -2495,44 +2328,6 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
sum += (v < 128) ? v : 256 - v;
}
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
- if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- png_uint_32 sumhi, sumlo;
- int j;
- sumlo = sum & PNG_LOMASK;
- sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */
-
- /* Reduce the sum if we match any of the previous rows */
- for (j = 0; j < num_p_filters; j++)
- {
- if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
- {
- sumlo = (sumlo * png_ptr->filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
-
- sumhi = (sumhi * png_ptr->filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- }
- }
-
- /* Factor in the cost of this filter (this is here for completeness,
- * but it makes no sense to have a "cost" for the NONE filter, as
- * it has the minimum possible computational cost - none).
- */
- sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
- PNG_COST_SHIFT;
-
- sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
- PNG_COST_SHIFT;
-
- if (sumhi > PNG_HIMASK)
- sum = PNG_MAXSUM;
-
- else
- sum = (sumhi << PNG_HISHIFT) + sumlo;
- }
-#endif
mins = sum;
}
@@ -2565,44 +2360,6 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
png_size_t i;
int v;
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
- /* We temporarily increase the "minimum sum" by the factor we
- * would reduce the sum of this filter, so that we can do the
- * early exit comparison without scaling the sum each time.
- */
- if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- int j;
- png_uint_32 lmhi, lmlo;
- lmlo = lmins & PNG_LOMASK;
- lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
-
- for (j = 0; j < num_p_filters; j++)
- {
- if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
- {
- lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
-
- lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- }
- }
-
- lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
- PNG_COST_SHIFT;
-
- lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
- PNG_COST_SHIFT;
-
- if (lmhi > PNG_HIMASK)
- lmins = PNG_MAXSUM;
-
- else
- lmins = (lmhi << PNG_HISHIFT) + lmlo;
- }
-#endif
-
for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
i++, rp++, dp++)
{
@@ -2622,40 +2379,6 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
break;
}
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
- if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- int j;
- png_uint_32 sumhi, sumlo;
- sumlo = sum & PNG_LOMASK;
- sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
-
- for (j = 0; j < num_p_filters; j++)
- {
- if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
- {
- sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
-
- sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- }
- }
-
- sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
- PNG_COST_SHIFT;
-
- sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
- PNG_COST_SHIFT;
-
- if (sumhi > PNG_HIMASK)
- sum = PNG_MAXSUM;
-
- else
- sum = (sumhi << PNG_HISHIFT) + sumlo;
- }
-#endif
-
if (sum < mins)
{
mins = sum;
@@ -2686,41 +2409,6 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
png_size_t i;
int v;
-
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
- if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- int j;
- png_uint_32 lmhi, lmlo;
- lmlo = lmins & PNG_LOMASK;
- lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
-
- for (j = 0; j < num_p_filters; j++)
- {
- if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
- {
- lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
-
- lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- }
- }
-
- lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
- PNG_COST_SHIFT;
-
- lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
- PNG_COST_SHIFT;
-
- if (lmhi > PNG_HIMASK)
- lmins = PNG_MAXSUM;
-
- else
- lmins = (lmhi << PNG_HISHIFT) + lmlo;
- }
-#endif
-
for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
pp = prev_row + 1; i < row_bytes; i++)
{
@@ -2732,40 +2420,6 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
break;
}
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
- if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- int j;
- png_uint_32 sumhi, sumlo;
- sumlo = sum & PNG_LOMASK;
- sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
-
- for (j = 0; j < num_p_filters; j++)
- {
- if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
- {
- sumlo = (sumlo * png_ptr->filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
-
- sumhi = (sumhi * png_ptr->filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- }
- }
-
- sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
- PNG_COST_SHIFT;
-
- sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
- PNG_COST_SHIFT;
-
- if (sumhi > PNG_HIMASK)
- sum = PNG_MAXSUM;
-
- else
- sum = (sumhi << PNG_HISHIFT) + sumlo;
- }
-#endif
-
if (sum < mins)
{
mins = sum;
@@ -2800,40 +2454,6 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
png_size_t i;
int v;
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
- if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- int j;
- png_uint_32 lmhi, lmlo;
- lmlo = lmins & PNG_LOMASK;
- lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
-
- for (j = 0; j < num_p_filters; j++)
- {
- if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG)
- {
- lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
-
- lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- }
- }
-
- lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
- PNG_COST_SHIFT;
-
- lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
- PNG_COST_SHIFT;
-
- if (lmhi > PNG_HIMASK)
- lmins = PNG_MAXSUM;
-
- else
- lmins = (lmhi << PNG_HISHIFT) + lmlo;
- }
-#endif
-
for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
pp = prev_row + 1; i < bpp; i++)
{
@@ -2853,40 +2473,6 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
break;
}
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
- if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- int j;
- png_uint_32 sumhi, sumlo;
- sumlo = sum & PNG_LOMASK;
- sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
-
- for (j = 0; j < num_p_filters; j++)
- {
- if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
- {
- sumlo = (sumlo * png_ptr->filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
-
- sumhi = (sumhi * png_ptr->filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- }
- }
-
- sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
- PNG_COST_SHIFT;
-
- sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
- PNG_COST_SHIFT;
-
- if (sumhi > PNG_HIMASK)
- sum = PNG_MAXSUM;
-
- else
- sum = (sumhi << PNG_HISHIFT) + sumlo;
- }
-#endif
-
if (sum < mins)
{
mins = sum;
@@ -2941,40 +2527,6 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
png_size_t i;
int v;
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
- if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- int j;
- png_uint_32 lmhi, lmlo;
- lmlo = lmins & PNG_LOMASK;
- lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
-
- for (j = 0; j < num_p_filters; j++)
- {
- if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
- {
- lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
-
- lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- }
- }
-
- lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
- PNG_COST_SHIFT;
-
- lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
- PNG_COST_SHIFT;
-
- if (lmhi > PNG_HIMASK)
- lmins = PNG_MAXSUM;
-
- else
- lmins = (lmhi << PNG_HISHIFT) + lmlo;
- }
-#endif
-
for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
pp = prev_row + 1; i < bpp; i++)
{
@@ -3028,40 +2580,6 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
break;
}
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
- if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- int j;
- png_uint_32 sumhi, sumlo;
- sumlo = sum & PNG_LOMASK;
- sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
-
- for (j = 0; j < num_p_filters; j++)
- {
- if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
- {
- sumlo = (sumlo * png_ptr->filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
-
- sumhi = (sumhi * png_ptr->filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- }
- }
-
- sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
- PNG_COST_SHIFT;
-
- sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
- PNG_COST_SHIFT;
-
- if (sumhi > PNG_HIMASK)
- sum = PNG_MAXSUM;
-
- else
- sum = (sumhi << PNG_HISHIFT) + sumlo;
- }
-#endif
-
if (sum < mins)
{
best_row = png_ptr->paeth_row;
@@ -3071,26 +2589,8 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
/* Do the actual writing of the filtered row data from the chosen filter. */
png_write_filtered_row(png_ptr, best_row, row_info->rowbytes+1);
-
-#ifdef PNG_WRITE_FILTER_SUPPORTED
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
- /* Save the type of filter we picked this time for future calculations */
- if (png_ptr->num_prev_filters > 0)
- {
- int j;
-
- for (j = 1; j < num_p_filters; j++)
- {
- png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1];
- }
-
- png_ptr->prev_filters[j] = best_row[0];
- }
-#endif
-#endif /* PNG_WRITE_FILTER_SUPPORTED */
}
-
/* Do the actual writing of a previously filtered row. */
static void
png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row,
diff --git a/drivers/png/resource_saver_png.cpp b/drivers/png/resource_saver_png.cpp
index 8524aa2121..b91329c8da 100644
--- a/drivers/png/resource_saver_png.cpp
+++ b/drivers/png/resource_saver_png.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -75,6 +75,9 @@ Error ResourceSaverPNG::save(const String &p_path,const RES& p_resource,uint32_t
if (bool(texture->get_flags()&Texture::FLAG_CONVERT_TO_LINEAR)) {
text+="tolinear=true\n";
}
+ if (bool(texture->get_flags()&Texture::FLAG_MIRRORED_REPEAT)) {
+ text+="mirroredrepeat=true\n";
+ }
if (text!="" || FileAccess::exists(p_path+".flags")) {
@@ -211,6 +214,7 @@ Error ResourceSaverPNG::save_image(const String &p_path, Image &p_img) {
memdelete(f);
/* cleanup heap allocation */
+ png_destroy_write_struct(&png_ptr, &info_ptr);
return OK;
}
diff --git a/drivers/pnm/SCsub b/drivers/pnm/SCsub
new file mode 100644
index 0000000000..28b35773a4
--- /dev/null
+++ b/drivers/pnm/SCsub
@@ -0,0 +1,10 @@
+Import('env')
+
+
+pnm_sources = [
+ "pnm/bitmap_loader_pnm.cpp"
+ ]
+
+env.drivers_sources+=pnm_sources
+
+#env.add_source_files(env.drivers_sources, pnm_sources)
diff --git a/drivers/pnm/bitmap_loader_pnm.cpp b/drivers/pnm/bitmap_loader_pnm.cpp
new file mode 100644
index 0000000000..c9298be26a
--- /dev/null
+++ b/drivers/pnm/bitmap_loader_pnm.cpp
@@ -0,0 +1,235 @@
+/*************************************************/
+/* image_loader_jpg.cpp */
+/*************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/*************************************************/
+/* Source code within this file is: */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
+/* All Rights Reserved. */
+/*************************************************/
+
+#include "bitmap_loader_pnm.h"
+#include "os/file_access.h"
+#include "scene/resources/bit_mask.h"
+
+
+static bool _get_token(FileAccessRef& f,uint8_t &saved,DVector<uint8_t>& r_token,bool p_binary=false,bool p_single_chunk=false) {
+
+
+ int token_max = r_token.size();
+ DVector<uint8_t>::Write w;
+ if (token_max)
+ w=r_token.write();
+ int ofs=0;
+ bool lf=false;
+
+
+ while(true) {
+
+ uint8_t b;
+ if (saved) {
+ b=saved;
+ saved=0;
+ } else {
+ b = f->get_8();
+ }
+ if (f->eof_reached()) {
+ if (ofs) {
+ w=DVector<uint8_t>::Write();
+ r_token.resize(ofs);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ if (!ofs && !p_binary && b=='#') {
+ //skip comment
+ while(b!='\n') {
+ if (f->eof_reached()) {
+ return false;
+ }
+
+ b = f->get_8();
+ }
+
+ lf=true;
+
+ } else if (b<=32 && !(p_binary && (ofs || lf))) {
+
+ if (b=='\n') {
+ lf=true;
+ }
+
+
+ if (ofs && !p_single_chunk) {
+ w=DVector<uint8_t>::Write();
+ r_token.resize(ofs);
+ saved=b;
+
+ return true;
+ }
+ } else {
+
+ bool resized=false;
+ while (ofs>=token_max) {
+ if (token_max)
+ token_max<<=1;
+ else
+ token_max=1;
+ resized=true;
+ }
+ if (resized) {
+ w=DVector<uint8_t>::Write();
+ r_token.resize(token_max);
+ w=r_token.write();
+ }
+ w[ofs++]=b;
+ }
+ }
+
+ return false;
+}
+
+static int _get_number_from_token(DVector<uint8_t>& r_token) {
+
+ int len = r_token.size();
+ DVector<uint8_t>::Read r = r_token.read();
+ return String::to_int((const char*)r.ptr(),len);
+
+}
+
+
+RES ResourceFormatPBM::load(const String &p_path,const String& p_original_path,Error *r_error) {
+
+#define _RETURN(m_err)\
+{\
+ if (r_error)\
+ *r_error=m_err;\
+ ERR_FAIL_V(RES());\
+}
+
+
+ FileAccessRef f=FileAccess::open(p_path,FileAccess::READ);
+ uint8_t saved=0;
+ if (!f)
+ _RETURN(ERR_CANT_OPEN);
+
+ DVector<uint8_t> token;
+
+ if (!_get_token(f,saved,token)) {
+ _RETURN(ERR_PARSE_ERROR);
+ }
+
+ if (token.size()!=2) {
+ _RETURN(ERR_FILE_CORRUPT);
+ }
+ if (token[0]!='P') {
+ _RETURN(ERR_FILE_CORRUPT);
+ }
+ if (token[1]!='1' && token[1]!='4') {
+ _RETURN(ERR_FILE_CORRUPT);
+ }
+
+ bool bits = token[1]=='4';
+
+ if (!_get_token(f,saved,token)) {
+ _RETURN(ERR_PARSE_ERROR);
+ }
+
+ int width = _get_number_from_token(token);
+ if (width<=0) {
+ _RETURN(ERR_FILE_CORRUPT);
+ }
+
+
+ if (!_get_token(f,saved,token)) {
+ _RETURN(ERR_PARSE_ERROR);
+ }
+
+ int height = _get_number_from_token(token);
+ if (height<=0) {
+ _RETURN(ERR_FILE_CORRUPT);
+ }
+
+
+ Ref<BitMap> bm;
+ bm.instance();
+ bm->create(Size2i(width,height));
+
+ if (!bits) {
+
+ int required_bytes = width*height;
+ if (!_get_token(f,saved,token,false,true)) {
+ _RETURN(ERR_PARSE_ERROR);
+ }
+
+ if (token.size()<required_bytes) {
+ _RETURN(ERR_FILE_CORRUPT);
+ }
+
+ DVector<uint8_t>::Read r=token.read();
+
+ for(int i=0;i<height;i++) {
+ for(int j=0;j<width;j++) {
+
+
+ char num = r[i*width+j];
+ bm->set_bit(Point2i(j,i),num=='0');
+ }
+
+ }
+
+
+
+ } else {
+ //a single, entire token of bits!
+ if (!_get_token(f,saved,token,true)) {
+ _RETURN(ERR_PARSE_ERROR);
+ }
+ int required_bytes = Math::ceil((width*height)/8.0);
+ if (token.size()<required_bytes) {
+ _RETURN(ERR_FILE_CORRUPT);
+ }
+
+ DVector<uint8_t>::Read r=token.read();
+ int bitwidth = width;
+ if (bitwidth % 8)
+ bitwidth+=8-(bitwidth%8);
+
+ for(int i=0;i<height;i++) {
+ for(int j=0;j<width;j++) {
+
+ int ofs = bitwidth*i+j;
+
+ uint8_t byte = r[ofs/8];
+ bool bit = (byte>>(7-(ofs%8)))&1;
+
+ bm->set_bit(Point2i(j,i),!bit);
+
+ }
+
+ }
+
+ }
+
+ return bm;
+
+
+}
+
+void ResourceFormatPBM::get_recognized_extensions(List<String> *p_extensions) const {
+ p_extensions->push_back("pbm");
+}
+bool ResourceFormatPBM::handles_type(const String& p_type) const {
+ return p_type=="BitMap";
+}
+String ResourceFormatPBM::get_resource_type(const String &p_path) const {
+
+ if (p_path.extension().to_lower()=="pbm")
+ return "BitMap";
+ return "";
+}
+
+
diff --git a/drivers/pnm/bitmap_loader_pnm.h b/drivers/pnm/bitmap_loader_pnm.h
new file mode 100644
index 0000000000..6e6c8a59c8
--- /dev/null
+++ b/drivers/pnm/bitmap_loader_pnm.h
@@ -0,0 +1,33 @@
+/*************************************************/
+/* image_loader_jpg.h */
+/*************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/*************************************************/
+/* Source code within this file is: */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
+/* All Rights Reserved. */
+/*************************************************/
+
+#ifndef BITMAP_LOADER_PNM_H
+#define BITMAP_LOADER_PNM_H
+
+#include "io/resource_loader.h"
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+class ResourceFormatPBM : public ResourceFormatLoader {
+
+
+public:
+
+ virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL);
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual bool handles_type(const String& p_type) const;
+ virtual String get_resource_type(const String &p_path) const;
+};
+
+
+
+#endif
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
index dfe9ddc55f..813a95816b 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -82,6 +82,17 @@ Error AudioDriverPulseAudio::init() {
return OK;
}
+float AudioDriverPulseAudio::get_latency() {
+
+ if (latency==0) { //only do this once since it's approximate anyway
+ int error_code;
+ pa_usec_t palat = pa_simple_get_latency( pulse,&error_code);
+ latency=double(palat)/1000000.0;
+ }
+
+ return latency;
+}
+
void AudioDriverPulseAudio::thread_func(void* p_udata) {
AudioDriverPulseAudio* ad = (AudioDriverPulseAudio*)p_udata;
@@ -121,6 +132,7 @@ void AudioDriverPulseAudio::thread_func(void* p_udata) {
ad->exit_thread = true;
break;
}
+
}
ad->thread_exited = true;
@@ -185,6 +197,7 @@ AudioDriverPulseAudio::AudioDriverPulseAudio() {
mutex = NULL;
thread = NULL;
pulse = NULL;
+ latency=0;
}
AudioDriverPulseAudio::~AudioDriverPulseAudio() {
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.h b/drivers/pulseaudio/audio_driver_pulseaudio.h
index e82e0c24be..8a2fbfd38b 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.h
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -58,6 +58,8 @@ class AudioDriverPulseAudio : public AudioDriverSW {
mutable bool exit_thread;
bool pcm_open;
+ float latency;
+
public:
const char* get_name() const {
@@ -72,6 +74,9 @@ public:
virtual void unlock();
virtual void finish();
+ virtual float get_latency();
+
+
AudioDriverPulseAudio();
~AudioDriverPulseAudio();
};
diff --git a/drivers/pvr/texture_loader_pvr.cpp b/drivers/pvr/texture_loader_pvr.cpp
index 5268b953f4..eb67dad8cf 100644
--- a/drivers/pvr/texture_loader_pvr.cpp
+++ b/drivers/pvr/texture_loader_pvr.cpp
@@ -22,8 +22,10 @@ enum PVRFLags {
-RES ResourceFormatPVR::load(const String &p_path,const String& p_original_path) {
+RES ResourceFormatPVR::load(const String &p_path,const String& p_original_path,Error *r_error) {
+ if (r_error)
+ *r_error=ERR_CANT_OPEN;
Error err;
FileAccess *f = FileAccess::open(p_path,FileAccess::READ,&err);
@@ -34,6 +36,8 @@ RES ResourceFormatPVR::load(const String &p_path,const String& p_original_path)
ERR_FAIL_COND_V(err,RES());
+ if (r_error)
+ *r_error=ERR_FILE_CORRUPT;
uint32_t hsize = f->get_32();
@@ -135,6 +139,9 @@ RES ResourceFormatPVR::load(const String &p_path,const String& p_original_path)
Ref<ImageTexture> texture = memnew( ImageTexture );
texture->create_from_image(image,tex_flags);
+ if (r_error)
+ *r_error=OK;
+
return texture;
}
diff --git a/drivers/pvr/texture_loader_pvr.h b/drivers/pvr/texture_loader_pvr.h
index ad86660aa1..735cb2b48b 100644
--- a/drivers/pvr/texture_loader_pvr.h
+++ b/drivers/pvr/texture_loader_pvr.h
@@ -9,7 +9,7 @@
class ResourceFormatPVR : public ResourceFormatLoader{
public:
- virtual RES load(const String &p_path,const String& p_original_path);
+ virtual RES load(const String &p_path,const String& p_original_path,Error *r_error=NULL);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String& p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/drivers/register_driver_types.cpp b/drivers/register_driver_types.cpp
index e730171fbb..e7bbf28f01 100644
--- a/drivers/register_driver_types.cpp
+++ b/drivers/register_driver_types.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/*************************************************/
/* Source code within this file is: */
-/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
/* All Rights Reserved. */
/*************************************************/
@@ -14,11 +14,12 @@
#include "png/image_loader_png.h"
#include "webp/image_loader_webp.h"
#include "png/resource_saver_png.h"
-#include "jpg/image_loader_jpg.h"
+#include "jpegd/image_loader_jpegd.h"
#include "dds/texture_loader_dds.h"
#include "pvr/texture_loader_pvr.h"
#include "etc1/image_etc.h"
#include "chibi/event_stream_chibi.h"
+#include "pnm/bitmap_loader_pnm.h"
#ifdef TOOLS_ENABLED
@@ -29,6 +30,11 @@
#include "convex_decomp/b2d_decompose.h"
#endif
+#ifdef TOOLS_ENABLED
+#include "pe_bliss/pe_bliss_godot.h"
+#include "platform/windows/export/export.h"
+#endif
+
#ifdef TREMOR_ENABLED
#include "teora/audio_stream_ogg.h"
#endif
@@ -37,18 +43,20 @@
#include "vorbis/audio_stream_ogg_vorbis.h"
#endif
+#ifdef OPUS_ENABLED
+#include "opus/audio_stream_opus.h"
+#endif
#ifdef SPEEX_ENABLED
#include "speex/audio_stream_speex.h"
#endif
#ifdef THEORA_ENABLED
-//#include "theora/video_stream_theora.h"
-#include "theoraplayer/video_stream_theoraplayer.h"
+#include "theora/video_stream_theora.h"
#endif
-#include "drivers/trex/regex.h"
+#include "drivers/nrex/regex.h"
#ifdef MUSEPACK_ENABLED
#include "mpc/audio_stream_mpc.h"
@@ -85,13 +93,16 @@ static ResourceFormatLoaderAudioStreamOGG *vorbis_stream_loader=NULL;
static ResourceFormatLoaderAudioStreamOGGVorbis *vorbis_stream_loader=NULL;
#endif
+#ifdef OPUS_ENABLED
+static ResourceFormatLoaderAudioStreamOpus *opus_stream_loader=NULL;
+#endif
+
#ifdef SPEEX_ENABLED
static ResourceFormatLoaderAudioStreamSpeex *speex_stream_loader=NULL;
#endif
#ifdef THEORA_ENABLED
-//static ResourceFormatLoaderVideoStreamTheora* theora_stream_loader = NULL;
-static ResourceFormatLoaderVideoStreamTheoraplayer* theoraplayer_stream_loader = NULL;
+static ResourceFormatLoaderVideoStreamTheora* theora_stream_loader = NULL;
#endif
#ifdef MUSEPACK_ENABLED
@@ -102,6 +113,9 @@ static ResourceFormatLoaderAudioStreamMPC * mpc_stream_loader=NULL;
#include "openssl/register_openssl.h"
#endif
+
+static ResourceFormatPBM * pbm_loader=NULL;
+
void register_core_driver_types() {
#ifdef PNG_ENABLED
@@ -128,6 +142,9 @@ void register_core_driver_types() {
ImageLoader::add_image_format_loader( image_loader_jpg );
#endif
+ pbm_loader = memnew( ResourceFormatPBM );
+ ResourceLoader::add_resource_format_loader(pbm_loader);
+
ObjectTypeDB::register_type<RegEx>();
}
@@ -152,6 +169,7 @@ void unregister_core_driver_types() {
memdelete( image_loader_jpg );
#endif
+ memdelete( pbm_loader );
}
@@ -169,6 +187,11 @@ void register_driver_types() {
ObjectTypeDB::register_type<AudioStreamOGGVorbis>();
#endif
+#ifdef OPUS_ENABLED
+ opus_stream_loader=memnew( ResourceFormatLoaderAudioStreamOpus );
+ ResourceLoader::add_resource_format_loader( opus_stream_loader );
+ ObjectTypeDB::register_type<AudioStreamOpus>();
+#endif
#ifdef DDS_ENABLED
resource_loader_dds = memnew( ResourceFormatDDS );
@@ -205,12 +228,9 @@ void register_driver_types() {
#endif
#ifdef THEORA_ENABLED
- //theora_stream_loader = memnew( ResourceFormatLoaderVideoStreamTheora );
- //ResourceLoader::add_resource_format_loader(theora_stream_loader);
- //ObjectTypeDB::register_type<VideoStreamTheora>();
- theoraplayer_stream_loader = memnew( ResourceFormatLoaderVideoStreamTheoraplayer );
- ResourceLoader::add_resource_format_loader(theoraplayer_stream_loader);
- ObjectTypeDB::register_type<VideoStreamTheoraplayer>();
+ theora_stream_loader = memnew( ResourceFormatLoaderVideoStreamTheora );
+ ResourceLoader::add_resource_format_loader(theora_stream_loader);
+ ObjectTypeDB::register_type<VideoStreamTheora>();
#endif
@@ -225,7 +245,7 @@ void register_driver_types() {
#ifdef ETC1_ENABLED
_register_etc1_compress_func();
#endif
-
+
initialize_chibi();
}
@@ -239,15 +259,19 @@ void unregister_driver_types() {
memdelete( vorbis_stream_loader );
#endif
+#ifdef OPUS_ENABLED
+ memdelete( opus_stream_loader );
+#endif
+
#ifdef SPEEX_ENABLED
memdelete( speex_stream_loader );
#endif
#ifdef THEORA_ENABLED
- //memdelete (theora_stream_loader);
- memdelete (theoraplayer_stream_loader);
+ memdelete (theora_stream_loader);
#endif
+
#ifdef MUSEPACK_ENABLED
memdelete (mpc_stream_loader);
diff --git a/drivers/register_driver_types.h b/drivers/register_driver_types.h
index 9ae4b0be08..8a13ad4471 100644
--- a/drivers/register_driver_types.h
+++ b/drivers/register_driver_types.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/*************************************************/
/* Source code within this file is: */
-/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
/* All Rights Reserved. */
/*************************************************/
diff --git a/drivers/rtaudio/RtAudio.cpp b/drivers/rtaudio/RtAudio.cpp
index 8876f72e21..86981e56d2 100644
--- a/drivers/rtaudio/RtAudio.cpp
+++ b/drivers/rtaudio/RtAudio.cpp
@@ -1,10234 +1,10232 @@
-#ifdef RTAUDIO_ENABLED
-/************************************************************************/
-/*! \class RtAudio
- \brief Realtime audio i/o C++ classes.
-
- RtAudio provides a common API (Application Programming Interface)
- for realtime audio input/output across Linux (native ALSA, Jack,
- and OSS), Macintosh OS X (CoreAudio and Jack), and Windows
- (DirectSound, ASIO and WASAPI) operating systems.
-
- RtAudio WWW site: http://www.music.mcgill.ca/~gary/rtaudio/
-
- RtAudio: realtime audio i/o C++ classes
- Copyright (c) 2001-2014 Gary P. Scavone
-
- 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.
-
- Any person wishing to distribute modifications to the Software is
- asked to send the modifications to the original developer so that
- they can be incorporated into the canonical version. This is,
- however, not a binding provision of this license.
-
- 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.
-*/
-/************************************************************************/
-
-// RtAudio: Version 4.1.1
-
-#include "RtAudio.h"
-#include <iostream>
-#include <cstdlib>
-#include <cstring>
-#include <climits>
-#include <algorithm>
-
-// Static variable definitions.
-const unsigned int RtApi::MAX_SAMPLE_RATES = 14;
-const unsigned int RtApi::SAMPLE_RATES[] = {
- 4000, 5512, 8000, 9600, 11025, 16000, 22050,
- 32000, 44100, 48000, 88200, 96000, 176400, 192000
-};
-
-#if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__) || defined(__WINDOWS_WASAPI__)
-#ifdef WINRT_ENABLED
- #define MUTEX_INITIALIZE(A) InitializeCriticalSectionEx(A, 0, 0)
-#else
- #define MUTEX_INITIALIZE(A) InitializeCriticalSection(A)
-#endif
- #define MUTEX_DESTROY(A) DeleteCriticalSection(A)
- #define MUTEX_LOCK(A) EnterCriticalSection(A)
- #define MUTEX_UNLOCK(A) LeaveCriticalSection(A)
-
- #include "tchar.h"
-
- static std::string convertCharPointerToStdString(const char *text)
- {
- return std::string(text);
- }
-
- static std::string convertCharPointerToStdString(const wchar_t *text)
- {
- int length = WideCharToMultiByte(CP_UTF8, 0, text, -1, NULL, 0, NULL, NULL);
- std::string s( length-1, '\0' );
- WideCharToMultiByte(CP_UTF8, 0, text, -1, &s[0], length, NULL, NULL);
- return s;
- }
-
-#elif defined(__LINUX_ALSA__) || defined(__LINUX_PULSE__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__)
- // pthread API
- #define MUTEX_INITIALIZE(A) pthread_mutex_init(A, NULL)
- #define MUTEX_DESTROY(A) pthread_mutex_destroy(A)
- #define MUTEX_LOCK(A) pthread_mutex_lock(A)
- #define MUTEX_UNLOCK(A) pthread_mutex_unlock(A)
-#else
- #define MUTEX_INITIALIZE(A) abs(*A) // dummy definitions
- #define MUTEX_DESTROY(A) abs(*A) // dummy definitions
-#endif
-
-// *************************************************** //
-//
-// RtAudio definitions.
-//
-// *************************************************** //
-
-std::string RtAudio :: getVersion( void ) throw()
-{
- return RTAUDIO_VERSION;
-}
-
-void RtAudio :: getCompiledApi( std::vector<RtAudio::Api> &apis ) throw()
-{
- apis.clear();
-
- // The order here will control the order of RtAudio's API search in
- // the constructor.
-#if defined(__UNIX_JACK__)
- apis.push_back( UNIX_JACK );
-#endif
-#if defined(__LINUX_ALSA__)
- apis.push_back( LINUX_ALSA );
-#endif
-#if defined(__LINUX_PULSE__)
- apis.push_back( LINUX_PULSE );
-#endif
-#if defined(__LINUX_OSS__)
- apis.push_back( LINUX_OSS );
-#endif
-#if defined(__WINDOWS_ASIO__)
- apis.push_back( WINDOWS_ASIO );
-#endif
-#if defined(__WINDOWS_WASAPI__)
- apis.push_back( WINDOWS_WASAPI );
-#endif
-#if defined(__WINDOWS_DS__)
- apis.push_back( WINDOWS_DS );
-#endif
-#if defined(__MACOSX_CORE__)
- apis.push_back( MACOSX_CORE );
-#endif
-#if defined(__RTAUDIO_DUMMY__)
- apis.push_back( RTAUDIO_DUMMY );
-#endif
-}
-
-void RtAudio :: openRtApi( RtAudio::Api api )
-{
- if ( rtapi_ )
- delete rtapi_;
- rtapi_ = 0;
-
-#if defined(__UNIX_JACK__)
- if ( api == UNIX_JACK )
- rtapi_ = new RtApiJack();
-#endif
-#if defined(__LINUX_ALSA__)
- if ( api == LINUX_ALSA )
- rtapi_ = new RtApiAlsa();
-#endif
-#if defined(__LINUX_PULSE__)
- if ( api == LINUX_PULSE )
- rtapi_ = new RtApiPulse();
-#endif
-#if defined(__LINUX_OSS__)
- if ( api == LINUX_OSS )
- rtapi_ = new RtApiOss();
-#endif
-#if defined(__WINDOWS_ASIO__)
- if ( api == WINDOWS_ASIO )
- rtapi_ = new RtApiAsio();
-#endif
-#if defined(__WINDOWS_WASAPI__)
- if ( api == WINDOWS_WASAPI )
- rtapi_ = new RtApiWasapi();
-#endif
-#if defined(__WINDOWS_DS__)
- if ( api == WINDOWS_DS )
- rtapi_ = new RtApiDs();
-#endif
-#if defined(__MACOSX_CORE__)
- if ( api == MACOSX_CORE )
- rtapi_ = new RtApiCore();
-#endif
-#if defined(__RTAUDIO_DUMMY__)
- if ( api == RTAUDIO_DUMMY )
- rtapi_ = new RtApiDummy();
-#endif
-}
-
-RtAudio :: RtAudio( RtAudio::Api api )
-{
- rtapi_ = 0;
-
- if ( api != UNSPECIFIED ) {
- // Attempt to open the specified API.
- openRtApi( api );
- if ( rtapi_ ) return;
-
- // No compiled support for specified API value. Issue a debug
- // warning and continue as if no API was specified.
- std::cerr << "\nRtAudio: no compiled support for specified API argument!\n" << std::endl;
- }
-
- // Iterate through the compiled APIs and return as soon as we find
- // one with at least one device or we reach the end of the list.
- std::vector< RtAudio::Api > apis;
- getCompiledApi( apis );
- for ( unsigned int i=0; i<apis.size(); i++ ) {
- openRtApi( apis[i] );
- if ( rtapi_ && rtapi_->getDeviceCount() ) break;
- }
-
- if ( rtapi_ ) return;
-
- // It should not be possible to get here because the preprocessor
- // definition __RTAUDIO_DUMMY__ is automatically defined if no
- // API-specific definitions are passed to the compiler. But just in
- // case something weird happens, we'll thow an error.
- std::string errorText = "\nRtAudio: no compiled API support found ... critical error!!\n\n";
- throw( RtAudioError( errorText, RtAudioError::UNSPECIFIED ) );
-}
-
-RtAudio :: ~RtAudio() throw()
-{
- if ( rtapi_ )
- delete rtapi_;
-}
-
-void RtAudio :: openStream( RtAudio::StreamParameters *outputParameters,
- RtAudio::StreamParameters *inputParameters,
- RtAudioFormat format, unsigned int sampleRate,
- unsigned int *bufferFrames,
- RtAudioCallback callback, void *userData,
- RtAudio::StreamOptions *options,
- RtAudioErrorCallback errorCallback )
-{
- return rtapi_->openStream( outputParameters, inputParameters, format,
- sampleRate, bufferFrames, callback,
- userData, options, errorCallback );
-}
-
-// *************************************************** //
-//
-// Public RtApi definitions (see end of file for
-// private or protected utility functions).
-//
-// *************************************************** //
-
-RtApi :: RtApi()
-{
- stream_.state = STREAM_CLOSED;
- stream_.mode = UNINITIALIZED;
- stream_.apiHandle = 0;
- stream_.userBuffer[0] = 0;
- stream_.userBuffer[1] = 0;
- MUTEX_INITIALIZE( &stream_.mutex );
- showWarnings_ = true;
- firstErrorOccurred_ = false;
-}
-
-RtApi :: ~RtApi()
-{
- MUTEX_DESTROY( &stream_.mutex );
-}
-
-void RtApi :: openStream( RtAudio::StreamParameters *oParams,
- RtAudio::StreamParameters *iParams,
- RtAudioFormat format, unsigned int sampleRate,
- unsigned int *bufferFrames,
- RtAudioCallback callback, void *userData,
- RtAudio::StreamOptions *options,
- RtAudioErrorCallback errorCallback )
-{
- if ( stream_.state != STREAM_CLOSED ) {
- errorText_ = "RtApi::openStream: a stream is already open!";
- error( RtAudioError::INVALID_USE );
- return;
- }
-
- // Clear stream information potentially left from a previously open stream.
- clearStreamInfo();
-
- if ( oParams && oParams->nChannels < 1 ) {
- errorText_ = "RtApi::openStream: a non-NULL output StreamParameters structure cannot have an nChannels value less than one.";
- error( RtAudioError::INVALID_USE );
- return;
- }
-
- if ( iParams && iParams->nChannels < 1 ) {
- errorText_ = "RtApi::openStream: a non-NULL input StreamParameters structure cannot have an nChannels value less than one.";
- error( RtAudioError::INVALID_USE );
- return;
- }
-
- if ( oParams == NULL && iParams == NULL ) {
- errorText_ = "RtApi::openStream: input and output StreamParameters structures are both NULL!";
- error( RtAudioError::INVALID_USE );
- return;
- }
-
- if ( formatBytes(format) == 0 ) {
- errorText_ = "RtApi::openStream: 'format' parameter value is undefined.";
- error( RtAudioError::INVALID_USE );
- return;
- }
-
- unsigned int nDevices = getDeviceCount();
- unsigned int oChannels = 0;
- if ( oParams ) {
- oChannels = oParams->nChannels;
- if ( oParams->deviceId >= nDevices ) {
- errorText_ = "RtApi::openStream: output device parameter value is invalid.";
- error( RtAudioError::INVALID_USE );
- return;
- }
- }
-
- unsigned int iChannels = 0;
- if ( iParams ) {
- iChannels = iParams->nChannels;
- if ( iParams->deviceId >= nDevices ) {
- errorText_ = "RtApi::openStream: input device parameter value is invalid.";
- error( RtAudioError::INVALID_USE );
- return;
- }
- }
-
- bool result;
-
- if ( oChannels > 0 ) {
-
- result = probeDeviceOpen( oParams->deviceId, OUTPUT, oChannels, oParams->firstChannel,
- sampleRate, format, bufferFrames, options );
- if ( result == false ) {
- error( RtAudioError::SYSTEM_ERROR );
- return;
- }
- }
-
- if ( iChannels > 0 ) {
-
- result = probeDeviceOpen( iParams->deviceId, INPUT, iChannels, iParams->firstChannel,
- sampleRate, format, bufferFrames, options );
- if ( result == false ) {
- if ( oChannels > 0 ) closeStream();
- error( RtAudioError::SYSTEM_ERROR );
- return;
- }
- }
-
- stream_.callbackInfo.callback = (void *) callback;
- stream_.callbackInfo.userData = userData;
- stream_.callbackInfo.errorCallback = (void *) errorCallback;
-
- if ( options ) options->numberOfBuffers = stream_.nBuffers;
- stream_.state = STREAM_STOPPED;
-}
-
-unsigned int RtApi :: getDefaultInputDevice( void )
-{
- // Should be implemented in subclasses if possible.
- return 0;
-}
-
-unsigned int RtApi :: getDefaultOutputDevice( void )
-{
- // Should be implemented in subclasses if possible.
- return 0;
-}
-
-void RtApi :: closeStream( void )
-{
- // MUST be implemented in subclasses!
- return;
-}
-
-bool RtApi :: probeDeviceOpen( unsigned int /*device*/, StreamMode /*mode*/, unsigned int /*channels*/,
- unsigned int /*firstChannel*/, unsigned int /*sampleRate*/,
- RtAudioFormat /*format*/, unsigned int * /*bufferSize*/,
- RtAudio::StreamOptions * /*options*/ )
-{
- // MUST be implemented in subclasses!
- return FAILURE;
-}
-
-void RtApi :: tickStreamTime( void )
-{
- // Subclasses that do not provide their own implementation of
- // getStreamTime should call this function once per buffer I/O to
- // provide basic stream time support.
-
- stream_.streamTime += ( stream_.bufferSize * 1.0 / stream_.sampleRate );
-
-#if defined( HAVE_GETTIMEOFDAY )
- gettimeofday( &stream_.lastTickTimestamp, NULL );
-#endif
-}
-
-long RtApi :: getStreamLatency( void )
-{
- verifyStream();
-
- long totalLatency = 0;
- if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX )
- totalLatency = stream_.latency[0];
- if ( stream_.mode == INPUT || stream_.mode == DUPLEX )
- totalLatency += stream_.latency[1];
-
- return totalLatency;
-}
-
-double RtApi :: getStreamTime( void )
-{
- verifyStream();
-
-#if defined( HAVE_GETTIMEOFDAY )
- // Return a very accurate estimate of the stream time by
- // adding in the elapsed time since the last tick.
- struct timeval then;
- struct timeval now;
-
- if ( stream_.state != STREAM_RUNNING || stream_.streamTime == 0.0 )
- return stream_.streamTime;
-
- gettimeofday( &now, NULL );
- then = stream_.lastTickTimestamp;
- return stream_.streamTime +
- ((now.tv_sec + 0.000001 * now.tv_usec) -
- (then.tv_sec + 0.000001 * then.tv_usec));
-#else
- return stream_.streamTime;
-#endif
-}
-
-void RtApi :: setStreamTime( double time )
-{
- verifyStream();
-
- if ( time >= 0.0 )
- stream_.streamTime = time;
-}
-
-unsigned int RtApi :: getStreamSampleRate( void )
-{
- verifyStream();
-
- return stream_.sampleRate;
-}
-
-
-// *************************************************** //
-//
-// OS/API-specific methods.
-//
-// *************************************************** //
-
-#if defined(__MACOSX_CORE__)
-
-// The OS X CoreAudio API is designed to use a separate callback
-// procedure for each of its audio devices. A single RtAudio duplex
-// stream using two different devices is supported here, though it
-// cannot be guaranteed to always behave correctly because we cannot
-// synchronize these two callbacks.
-//
-// A property listener is installed for over/underrun information.
-// However, no functionality is currently provided to allow property
-// listeners to trigger user handlers because it is unclear what could
-// be done if a critical stream parameter (buffer size, sample rate,
-// device disconnect) notification arrived. The listeners entail
-// quite a bit of extra code and most likely, a user program wouldn't
-// be prepared for the result anyway. However, we do provide a flag
-// to the client callback function to inform of an over/underrun.
-
-// A structure to hold various information related to the CoreAudio API
-// implementation.
-struct CoreHandle {
- AudioDeviceID id[2]; // device ids
-#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
- AudioDeviceIOProcID procId[2];
-#endif
- UInt32 iStream[2]; // device stream index (or first if using multiple)
- UInt32 nStreams[2]; // number of streams to use
- bool xrun[2];
- char *deviceBuffer;
- pthread_cond_t condition;
- int drainCounter; // Tracks callback counts when draining
- bool internalDrain; // Indicates if stop is initiated from callback or not.
-
- CoreHandle()
- :deviceBuffer(0), drainCounter(0), internalDrain(false) { nStreams[0] = 1; nStreams[1] = 1; id[0] = 0; id[1] = 0; xrun[0] = false; xrun[1] = false; }
-};
-
-RtApiCore:: RtApiCore()
-{
-#if defined( AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER )
- // This is a largely undocumented but absolutely necessary
- // requirement starting with OS-X 10.6. If not called, queries and
- // updates to various audio device properties are not handled
- // correctly.
- CFRunLoopRef theRunLoop = NULL;
- AudioObjectPropertyAddress property = { kAudioHardwarePropertyRunLoop,
- kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
- OSStatus result = AudioObjectSetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);
- if ( result != noErr ) {
- errorText_ = "RtApiCore::RtApiCore: error setting run loop property!";
- error( RtAudioError::WARNING );
- }
-#endif
-}
-
-RtApiCore :: ~RtApiCore()
-{
- // The subclass destructor gets called before the base class
- // destructor, so close an existing stream before deallocating
- // apiDeviceId memory.
- if ( stream_.state != STREAM_CLOSED ) closeStream();
-}
-
-unsigned int RtApiCore :: getDeviceCount( void )
-{
- // Find out how many audio devices there are, if any.
- UInt32 dataSize;
- AudioObjectPropertyAddress propertyAddress = { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
- OSStatus result = AudioObjectGetPropertyDataSize( kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize );
- if ( result != noErr ) {
- errorText_ = "RtApiCore::getDeviceCount: OS-X error getting device info!";
- error( RtAudioError::WARNING );
- return 0;
- }
-
- return dataSize / sizeof( AudioDeviceID );
-}
-
-unsigned int RtApiCore :: getDefaultInputDevice( void )
-{
- unsigned int nDevices = getDeviceCount();
- if ( nDevices <= 1 ) return 0;
-
- AudioDeviceID id;
- UInt32 dataSize = sizeof( AudioDeviceID );
- AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
- OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, &id );
- if ( result != noErr ) {
- errorText_ = "RtApiCore::getDefaultInputDevice: OS-X system error getting device.";
- error( RtAudioError::WARNING );
- return 0;
- }
-
- dataSize *= nDevices;
- AudioDeviceID deviceList[ nDevices ];
- property.mSelector = kAudioHardwarePropertyDevices;
- result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, (void *) &deviceList );
- if ( result != noErr ) {
- errorText_ = "RtApiCore::getDefaultInputDevice: OS-X system error getting device IDs.";
- error( RtAudioError::WARNING );
- return 0;
- }
-
- for ( unsigned int i=0; i<nDevices; i++ )
- if ( id == deviceList[i] ) return i;
-
- errorText_ = "RtApiCore::getDefaultInputDevice: No default device found!";
- error( RtAudioError::WARNING );
- return 0;
-}
-
-unsigned int RtApiCore :: getDefaultOutputDevice( void )
-{
- unsigned int nDevices = getDeviceCount();
- if ( nDevices <= 1 ) return 0;
-
- AudioDeviceID id;
- UInt32 dataSize = sizeof( AudioDeviceID );
- AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
- OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, &id );
- if ( result != noErr ) {
- errorText_ = "RtApiCore::getDefaultOutputDevice: OS-X system error getting device.";
- error( RtAudioError::WARNING );
- return 0;
- }
-
- dataSize = sizeof( AudioDeviceID ) * nDevices;
- AudioDeviceID deviceList[ nDevices ];
- property.mSelector = kAudioHardwarePropertyDevices;
- result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, (void *) &deviceList );
- if ( result != noErr ) {
- errorText_ = "RtApiCore::getDefaultOutputDevice: OS-X system error getting device IDs.";
- error( RtAudioError::WARNING );
- return 0;
- }
-
- for ( unsigned int i=0; i<nDevices; i++ )
- if ( id == deviceList[i] ) return i;
-
- errorText_ = "RtApiCore::getDefaultOutputDevice: No default device found!";
- error( RtAudioError::WARNING );
- return 0;
-}
-
-RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
-{
- RtAudio::DeviceInfo info;
- info.probed = false;
-
- // Get device ID
- unsigned int nDevices = getDeviceCount();
- if ( nDevices == 0 ) {
- errorText_ = "RtApiCore::getDeviceInfo: no devices found!";
- error( RtAudioError::INVALID_USE );
- return info;
- }
-
- if ( device >= nDevices ) {
- errorText_ = "RtApiCore::getDeviceInfo: device ID is invalid!";
- error( RtAudioError::INVALID_USE );
- return info;
- }
-
- AudioDeviceID deviceList[ nDevices ];
- UInt32 dataSize = sizeof( AudioDeviceID ) * nDevices;
- AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices,
- kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
- OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property,
- 0, NULL, &dataSize, (void *) &deviceList );
- if ( result != noErr ) {
- errorText_ = "RtApiCore::getDeviceInfo: OS-X system error getting device IDs.";
- error( RtAudioError::WARNING );
- return info;
- }
-
- AudioDeviceID id = deviceList[ device ];
-
- // Get the device name.
- info.name.erase();
- CFStringRef cfname;
- dataSize = sizeof( CFStringRef );
- property.mSelector = kAudioObjectPropertyManufacturer;
- result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &cfname );
- if ( result != noErr ) {
- errorStream_ << "RtApiCore::probeDeviceInfo: system error (" << getErrorCode( result ) << ") getting device manufacturer.";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- return info;
- }
-
- //const char *mname = CFStringGetCStringPtr( cfname, CFStringGetSystemEncoding() );
- int length = CFStringGetLength(cfname);
- char *mname = (char *)malloc(length * 3 + 1);
-#if defined( UNICODE ) || defined( _UNICODE )
- CFStringGetCString(cfname, mname, length * 3 + 1, kCFStringEncodingUTF8);
-#else
- CFStringGetCString(cfname, mname, length * 3 + 1, CFStringGetSystemEncoding());
-#endif
- info.name.append( (const char *)mname, strlen(mname) );
- info.name.append( ": " );
- CFRelease( cfname );
- free(mname);
-
- property.mSelector = kAudioObjectPropertyName;
- result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &cfname );
- if ( result != noErr ) {
- errorStream_ << "RtApiCore::probeDeviceInfo: system error (" << getErrorCode( result ) << ") getting device name.";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- return info;
- }
-
- //const char *name = CFStringGetCStringPtr( cfname, CFStringGetSystemEncoding() );
- length = CFStringGetLength(cfname);
- char *name = (char *)malloc(length * 3 + 1);
-#if defined( UNICODE ) || defined( _UNICODE )
- CFStringGetCString(cfname, name, length * 3 + 1, kCFStringEncodingUTF8);
-#else
- CFStringGetCString(cfname, name, length * 3 + 1, CFStringGetSystemEncoding());
-#endif
- info.name.append( (const char *)name, strlen(name) );
- CFRelease( cfname );
- free(name);
-
- // Get the output stream "configuration".
- AudioBufferList *bufferList = nil;
- property.mSelector = kAudioDevicePropertyStreamConfiguration;
- property.mScope = kAudioDevicePropertyScopeOutput;
- // property.mElement = kAudioObjectPropertyElementWildcard;
- dataSize = 0;
- result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize );
- if ( result != noErr || dataSize == 0 ) {
- errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting output stream configuration info for device (" << device << ").";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- return info;
- }
-
- // Allocate the AudioBufferList.
- bufferList = (AudioBufferList *) malloc( dataSize );
- if ( bufferList == NULL ) {
- errorText_ = "RtApiCore::getDeviceInfo: memory error allocating output AudioBufferList.";
- error( RtAudioError::WARNING );
- return info;
- }
-
- result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, bufferList );
- if ( result != noErr || dataSize == 0 ) {
- free( bufferList );
- errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting output stream configuration for device (" << device << ").";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- return info;
- }
-
- // Get output channel information.
- unsigned int i, nStreams = bufferList->mNumberBuffers;
- for ( i=0; i<nStreams; i++ )
- info.outputChannels += bufferList->mBuffers[i].mNumberChannels;
- free( bufferList );
-
- // Get the input stream "configuration".
- property.mScope = kAudioDevicePropertyScopeInput;
- result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize );
- if ( result != noErr || dataSize == 0 ) {
- errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting input stream configuration info for device (" << device << ").";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- return info;
- }
-
- // Allocate the AudioBufferList.
- bufferList = (AudioBufferList *) malloc( dataSize );
- if ( bufferList == NULL ) {
- errorText_ = "RtApiCore::getDeviceInfo: memory error allocating input AudioBufferList.";
- error( RtAudioError::WARNING );
- return info;
- }
-
- result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, bufferList );
- if (result != noErr || dataSize == 0) {
- free( bufferList );
- errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting input stream configuration for device (" << device << ").";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- return info;
- }
-
- // Get input channel information.
- nStreams = bufferList->mNumberBuffers;
- for ( i=0; i<nStreams; i++ )
- info.inputChannels += bufferList->mBuffers[i].mNumberChannels;
- free( bufferList );
-
- // If device opens for both playback and capture, we determine the channels.
- if ( info.outputChannels > 0 && info.inputChannels > 0 )
- info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;
-
- // Probe the device sample rates.
- bool isInput = false;
- if ( info.outputChannels == 0 ) isInput = true;
-
- // Determine the supported sample rates.
- property.mSelector = kAudioDevicePropertyAvailableNominalSampleRates;
- if ( isInput == false ) property.mScope = kAudioDevicePropertyScopeOutput;
- result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize );
- if ( result != kAudioHardwareNoError || dataSize == 0 ) {
- errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting sample rate info.";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- return info;
- }
-
- UInt32 nRanges = dataSize / sizeof( AudioValueRange );
- AudioValueRange rangeList[ nRanges ];
- result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &rangeList );
- if ( result != kAudioHardwareNoError ) {
- errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting sample rates.";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- return info;
- }
-
- // The sample rate reporting mechanism is a bit of a mystery. It
- // seems that it can either return individual rates or a range of
- // rates. I assume that if the min / max range values are the same,
- // then that represents a single supported rate and if the min / max
- // range values are different, the device supports an arbitrary
- // range of values (though there might be multiple ranges, so we'll
- // use the most conservative range).
- Float64 minimumRate = 1.0, maximumRate = 10000000000.0;
- bool haveValueRange = false;
- info.sampleRates.clear();
- for ( UInt32 i=0; i<nRanges; i++ ) {
- if ( rangeList[i].mMinimum == rangeList[i].mMaximum ) {
- unsigned int tmpSr = (unsigned int) rangeList[i].mMinimum;
- info.sampleRates.push_back( tmpSr );
-
- if ( !info.preferredSampleRate || ( tmpSr <= 48000 && tmpSr > info.preferredSampleRate ) )
- info.preferredSampleRate = tmpSr;
-
- } else {
- haveValueRange = true;
- if ( rangeList[i].mMinimum > minimumRate ) minimumRate = rangeList[i].mMinimum;
- if ( rangeList[i].mMaximum < maximumRate ) maximumRate = rangeList[i].mMaximum;
- }
- }
-
- if ( haveValueRange ) {
- for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {
- if ( SAMPLE_RATES[k] >= (unsigned int) minimumRate && SAMPLE_RATES[k] <= (unsigned int) maximumRate ) {
- info.sampleRates.push_back( SAMPLE_RATES[k] );
-
- if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) )
- info.preferredSampleRate = SAMPLE_RATES[k];
- }
- }
- }
-
- // Sort and remove any redundant values
- std::sort( info.sampleRates.begin(), info.sampleRates.end() );
- info.sampleRates.erase( unique( info.sampleRates.begin(), info.sampleRates.end() ), info.sampleRates.end() );
-
- if ( info.sampleRates.size() == 0 ) {
- errorStream_ << "RtApiCore::probeDeviceInfo: No supported sample rates found for device (" << device << ").";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- return info;
- }
-
- // CoreAudio always uses 32-bit floating point data for PCM streams.
- // Thus, any other "physical" formats supported by the device are of
- // no interest to the client.
- info.nativeFormats = RTAUDIO_FLOAT32;
-
- if ( info.outputChannels > 0 )
- if ( getDefaultOutputDevice() == device ) info.isDefaultOutput = true;
- if ( info.inputChannels > 0 )
- if ( getDefaultInputDevice() == device ) info.isDefaultInput = true;
-
- info.probed = true;
- return info;
-}
-
-static OSStatus callbackHandler( AudioDeviceID inDevice,
- const AudioTimeStamp* /*inNow*/,
- const AudioBufferList* inInputData,
- const AudioTimeStamp* /*inInputTime*/,
- AudioBufferList* outOutputData,
- const AudioTimeStamp* /*inOutputTime*/,
- void* infoPointer )
-{
- CallbackInfo *info = (CallbackInfo *) infoPointer;
-
- RtApiCore *object = (RtApiCore *) info->object;
- if ( object->callbackEvent( inDevice, inInputData, outOutputData ) == false )
- return kAudioHardwareUnspecifiedError;
- else
- return kAudioHardwareNoError;
-}
-
-static OSStatus xrunListener( AudioObjectID /*inDevice*/,
- UInt32 nAddresses,
- const AudioObjectPropertyAddress properties[],
- void* handlePointer )
-{
- CoreHandle *handle = (CoreHandle *) handlePointer;
- for ( UInt32 i=0; i<nAddresses; i++ ) {
- if ( properties[i].mSelector == kAudioDeviceProcessorOverload ) {
- if ( properties[i].mScope == kAudioDevicePropertyScopeInput )
- handle->xrun[1] = true;
- else
- handle->xrun[0] = true;
- }
- }
-
- return kAudioHardwareNoError;
-}
-
-static OSStatus rateListener( AudioObjectID inDevice,
- UInt32 /*nAddresses*/,
- const AudioObjectPropertyAddress /*properties*/[],
- void* ratePointer )
-{
- Float64 *rate = (Float64 *) ratePointer;
- UInt32 dataSize = sizeof( Float64 );
- AudioObjectPropertyAddress property = { kAudioDevicePropertyNominalSampleRate,
- kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
- AudioObjectGetPropertyData( inDevice, &property, 0, NULL, &dataSize, rate );
- return kAudioHardwareNoError;
-}
-
-bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
- unsigned int firstChannel, unsigned int sampleRate,
- RtAudioFormat format, unsigned int *bufferSize,
- RtAudio::StreamOptions *options )
-{
- // Get device ID
- unsigned int nDevices = getDeviceCount();
- if ( nDevices == 0 ) {
- // This should not happen because a check is made before this function is called.
- errorText_ = "RtApiCore::probeDeviceOpen: no devices found!";
- return FAILURE;
- }
-
- if ( device >= nDevices ) {
- // This should not happen because a check is made before this function is called.
- errorText_ = "RtApiCore::probeDeviceOpen: device ID is invalid!";
- return FAILURE;
- }
-
- AudioDeviceID deviceList[ nDevices ];
- UInt32 dataSize = sizeof( AudioDeviceID ) * nDevices;
- AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices,
- kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
- OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property,
- 0, NULL, &dataSize, (void *) &deviceList );
- if ( result != noErr ) {
- errorText_ = "RtApiCore::probeDeviceOpen: OS-X system error getting device IDs.";
- return FAILURE;
- }
-
- AudioDeviceID id = deviceList[ device ];
-
- // Setup for stream mode.
- bool isInput = false;
- if ( mode == INPUT ) {
- isInput = true;
- property.mScope = kAudioDevicePropertyScopeInput;
- }
- else
- property.mScope = kAudioDevicePropertyScopeOutput;
-
- // Get the stream "configuration".
- AudioBufferList *bufferList = nil;
- dataSize = 0;
- property.mSelector = kAudioDevicePropertyStreamConfiguration;
- result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize );
- if ( result != noErr || dataSize == 0 ) {
- errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream configuration info for device (" << device << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Allocate the AudioBufferList.
- bufferList = (AudioBufferList *) malloc( dataSize );
- if ( bufferList == NULL ) {
- errorText_ = "RtApiCore::probeDeviceOpen: memory error allocating AudioBufferList.";
- return FAILURE;
- }
-
- result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, bufferList );
- if (result != noErr || dataSize == 0) {
- free( bufferList );
- errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream configuration for device (" << device << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Search for one or more streams that contain the desired number of
- // channels. CoreAudio devices can have an arbitrary number of
- // streams and each stream can have an arbitrary number of channels.
- // For each stream, a single buffer of interleaved samples is
- // provided. RtAudio prefers the use of one stream of interleaved
- // data or multiple consecutive single-channel streams. However, we
- // now support multiple consecutive multi-channel streams of
- // interleaved data as well.
- UInt32 iStream, offsetCounter = firstChannel;
- UInt32 nStreams = bufferList->mNumberBuffers;
- bool monoMode = false;
- bool foundStream = false;
-
- // First check that the device supports the requested number of
- // channels.
- UInt32 deviceChannels = 0;
- for ( iStream=0; iStream<nStreams; iStream++ )
- deviceChannels += bufferList->mBuffers[iStream].mNumberChannels;
-
- if ( deviceChannels < ( channels + firstChannel ) ) {
- free( bufferList );
- errorStream_ << "RtApiCore::probeDeviceOpen: the device (" << device << ") does not support the requested channel count.";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Look for a single stream meeting our needs.
- UInt32 firstStream, streamCount = 1, streamChannels = 0, channelOffset = 0;
- for ( iStream=0; iStream<nStreams; iStream++ ) {
- streamChannels = bufferList->mBuffers[iStream].mNumberChannels;
- if ( streamChannels >= channels + offsetCounter ) {
- firstStream = iStream;
- channelOffset = offsetCounter;
- foundStream = true;
- break;
- }
- if ( streamChannels > offsetCounter ) break;
- offsetCounter -= streamChannels;
- }
-
- // If we didn't find a single stream above, then we should be able
- // to meet the channel specification with multiple streams.
- if ( foundStream == false ) {
- monoMode = true;
- offsetCounter = firstChannel;
- for ( iStream=0; iStream<nStreams; iStream++ ) {
- streamChannels = bufferList->mBuffers[iStream].mNumberChannels;
- if ( streamChannels > offsetCounter ) break;
- offsetCounter -= streamChannels;
- }
-
- firstStream = iStream;
- channelOffset = offsetCounter;
- Int32 channelCounter = channels + offsetCounter - streamChannels;
-
- if ( streamChannels > 1 ) monoMode = false;
- while ( channelCounter > 0 ) {
- streamChannels = bufferList->mBuffers[++iStream].mNumberChannels;
- if ( streamChannels > 1 ) monoMode = false;
- channelCounter -= streamChannels;
- streamCount++;
- }
- }
-
- free( bufferList );
-
- // Determine the buffer size.
- AudioValueRange bufferRange;
- dataSize = sizeof( AudioValueRange );
- property.mSelector = kAudioDevicePropertyBufferFrameSizeRange;
- result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &bufferRange );
-
- if ( result != noErr ) {
- errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting buffer size range for device (" << device << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- if ( bufferRange.mMinimum > *bufferSize ) *bufferSize = (unsigned long) bufferRange.mMinimum;
- else if ( bufferRange.mMaximum < *bufferSize ) *bufferSize = (unsigned long) bufferRange.mMaximum;
- if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) *bufferSize = (unsigned long) bufferRange.mMinimum;
-
- // Set the buffer size. For multiple streams, I'm assuming we only
- // need to make this setting for the master channel.
- UInt32 theSize = (UInt32) *bufferSize;
- dataSize = sizeof( UInt32 );
- property.mSelector = kAudioDevicePropertyBufferFrameSize;
- result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &theSize );
-
- if ( result != noErr ) {
- errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting the buffer size for device (" << device << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // If attempting to setup a duplex stream, the bufferSize parameter
- // MUST be the same in both directions!
- *bufferSize = theSize;
- if ( stream_.mode == OUTPUT && mode == INPUT && *bufferSize != stream_.bufferSize ) {
- errorStream_ << "RtApiCore::probeDeviceOpen: system error setting buffer size for duplex stream on device (" << device << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- stream_.bufferSize = *bufferSize;
- stream_.nBuffers = 1;
-
- // Try to set "hog" mode ... it's not clear to me this is working.
- if ( options && options->flags & RTAUDIO_HOG_DEVICE ) {
- pid_t hog_pid;
- dataSize = sizeof( hog_pid );
- property.mSelector = kAudioDevicePropertyHogMode;
- result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &hog_pid );
- if ( result != noErr ) {
- errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting 'hog' state!";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- if ( hog_pid != getpid() ) {
- hog_pid = getpid();
- result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &hog_pid );
- if ( result != noErr ) {
- errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting 'hog' state!";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
- }
- }
-
- // Check and if necessary, change the sample rate for the device.
- Float64 nominalRate;
- dataSize = sizeof( Float64 );
- property.mSelector = kAudioDevicePropertyNominalSampleRate;
- result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &nominalRate );
- if ( result != noErr ) {
- errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting current sample rate.";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Only change the sample rate if off by more than 1 Hz.
- if ( fabs( nominalRate - (double)sampleRate ) > 1.0 ) {
-
- // Set a property listener for the sample rate change
- Float64 reportedRate = 0.0;
- AudioObjectPropertyAddress tmp = { kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
- result = AudioObjectAddPropertyListener( id, &tmp, rateListener, (void *) &reportedRate );
- if ( result != noErr ) {
- errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate property listener for device (" << device << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- nominalRate = (Float64) sampleRate;
- result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &nominalRate );
- if ( result != noErr ) {
- AudioObjectRemovePropertyListener( id, &tmp, rateListener, (void *) &reportedRate );
- errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate for device (" << device << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Now wait until the reported nominal rate is what we just set.
- UInt32 microCounter = 0;
- while ( reportedRate != nominalRate ) {
- microCounter += 5000;
- if ( microCounter > 5000000 ) break;
- usleep( 5000 );
- }
-
- // Remove the property listener.
- AudioObjectRemovePropertyListener( id, &tmp, rateListener, (void *) &reportedRate );
-
- if ( microCounter > 5000000 ) {
- errorStream_ << "RtApiCore::probeDeviceOpen: timeout waiting for sample rate update for device (" << device << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
- }
-
- // Now set the stream format for all streams. Also, check the
- // physical format of the device and change that if necessary.
- AudioStreamBasicDescription description;
- dataSize = sizeof( AudioStreamBasicDescription );
- property.mSelector = kAudioStreamPropertyVirtualFormat;
- result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &description );
- if ( result != noErr ) {
- errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream format for device (" << device << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Set the sample rate and data format id. However, only make the
- // change if the sample rate is not within 1.0 of the desired
- // rate and the format is not linear pcm.
- bool updateFormat = false;
- if ( fabs( description.mSampleRate - (Float64)sampleRate ) > 1.0 ) {
- description.mSampleRate = (Float64) sampleRate;
- updateFormat = true;
- }
-
- if ( description.mFormatID != kAudioFormatLinearPCM ) {
- description.mFormatID = kAudioFormatLinearPCM;
- updateFormat = true;
- }
-
- if ( updateFormat ) {
- result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &description );
- if ( result != noErr ) {
- errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate or data format for device (" << device << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
- }
-
- // Now check the physical format.
- property.mSelector = kAudioStreamPropertyPhysicalFormat;
- result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &description );
- if ( result != noErr ) {
- errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream physical format for device (" << device << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- //std::cout << "Current physical stream format:" << std::endl;
- //std::cout << " mBitsPerChan = " << description.mBitsPerChannel << std::endl;
- //std::cout << " aligned high = " << (description.mFormatFlags & kAudioFormatFlagIsAlignedHigh) << ", isPacked = " << (description.mFormatFlags & kAudioFormatFlagIsPacked) << std::endl;
- //std::cout << " bytesPerFrame = " << description.mBytesPerFrame << std::endl;
- //std::cout << " sample rate = " << description.mSampleRate << std::endl;
-
- if ( description.mFormatID != kAudioFormatLinearPCM || description.mBitsPerChannel < 16 ) {
- description.mFormatID = kAudioFormatLinearPCM;
- //description.mSampleRate = (Float64) sampleRate;
- AudioStreamBasicDescription testDescription = description;
- UInt32 formatFlags;
-
- // We'll try higher bit rates first and then work our way down.
- std::vector< std::pair<UInt32, UInt32> > physicalFormats;
- formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsFloat) & ~kLinearPCMFormatFlagIsSignedInteger;
- physicalFormats.push_back( std::pair<Float32, UInt32>( 32, formatFlags ) );
- formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked) & ~kLinearPCMFormatFlagIsFloat;
- physicalFormats.push_back( std::pair<Float32, UInt32>( 32, formatFlags ) );
- physicalFormats.push_back( std::pair<Float32, UInt32>( 24, formatFlags ) ); // 24-bit packed
- formatFlags &= ~( kAudioFormatFlagIsPacked | kAudioFormatFlagIsAlignedHigh );
- physicalFormats.push_back( std::pair<Float32, UInt32>( 24.2, formatFlags ) ); // 24-bit in 4 bytes, aligned low
- formatFlags |= kAudioFormatFlagIsAlignedHigh;
- physicalFormats.push_back( std::pair<Float32, UInt32>( 24.4, formatFlags ) ); // 24-bit in 4 bytes, aligned high
- formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked) & ~kLinearPCMFormatFlagIsFloat;
- physicalFormats.push_back( std::pair<Float32, UInt32>( 16, formatFlags ) );
- physicalFormats.push_back( std::pair<Float32, UInt32>( 8, formatFlags ) );
-
- bool setPhysicalFormat = false;
- for( unsigned int i=0; i<physicalFormats.size(); i++ ) {
- testDescription = description;
- testDescription.mBitsPerChannel = (UInt32) physicalFormats[i].first;
- testDescription.mFormatFlags = physicalFormats[i].second;
- if ( (24 == (UInt32)physicalFormats[i].first) && ~( physicalFormats[i].second & kAudioFormatFlagIsPacked ) )
- testDescription.mBytesPerFrame = 4 * testDescription.mChannelsPerFrame;
- else
- testDescription.mBytesPerFrame = testDescription.mBitsPerChannel/8 * testDescription.mChannelsPerFrame;
- testDescription.mBytesPerPacket = testDescription.mBytesPerFrame * testDescription.mFramesPerPacket;
- result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &testDescription );
- if ( result == noErr ) {
- setPhysicalFormat = true;
- //std::cout << "Updated physical stream format:" << std::endl;
- //std::cout << " mBitsPerChan = " << testDescription.mBitsPerChannel << std::endl;
- //std::cout << " aligned high = " << (testDescription.mFormatFlags & kAudioFormatFlagIsAlignedHigh) << ", isPacked = " << (testDescription.mFormatFlags & kAudioFormatFlagIsPacked) << std::endl;
- //std::cout << " bytesPerFrame = " << testDescription.mBytesPerFrame << std::endl;
- //std::cout << " sample rate = " << testDescription.mSampleRate << std::endl;
- break;
- }
- }
-
- if ( !setPhysicalFormat ) {
- errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting physical data format for device (" << device << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
- } // done setting virtual/physical formats.
-
- // Get the stream / device latency.
- UInt32 latency;
- dataSize = sizeof( UInt32 );
- property.mSelector = kAudioDevicePropertyLatency;
- if ( AudioObjectHasProperty( id, &property ) == true ) {
- result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &latency );
- if ( result == kAudioHardwareNoError ) stream_.latency[ mode ] = latency;
- else {
- errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting device latency for device (" << device << ").";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- }
- }
-
- // Byte-swapping: According to AudioHardware.h, the stream data will
- // always be presented in native-endian format, so we should never
- // need to byte swap.
- stream_.doByteSwap[mode] = false;
-
- // From the CoreAudio documentation, PCM data must be supplied as
- // 32-bit floats.
- stream_.userFormat = format;
- stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
-
- if ( streamCount == 1 )
- stream_.nDeviceChannels[mode] = description.mChannelsPerFrame;
- else // multiple streams
- stream_.nDeviceChannels[mode] = channels;
- stream_.nUserChannels[mode] = channels;
- stream_.channelOffset[mode] = channelOffset; // offset within a CoreAudio stream
- if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;
- else stream_.userInterleaved = true;
- stream_.deviceInterleaved[mode] = true;
- if ( monoMode == true ) stream_.deviceInterleaved[mode] = false;
-
- // Set flags for buffer conversion.
- stream_.doConvertBuffer[mode] = false;
- if ( stream_.userFormat != stream_.deviceFormat[mode] )
- stream_.doConvertBuffer[mode] = true;
- if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] )
- stream_.doConvertBuffer[mode] = true;
- if ( streamCount == 1 ) {
- if ( stream_.nUserChannels[mode] > 1 &&
- stream_.userInterleaved != stream_.deviceInterleaved[mode] )
- stream_.doConvertBuffer[mode] = true;
- }
- else if ( monoMode && stream_.userInterleaved )
- stream_.doConvertBuffer[mode] = true;
-
- // Allocate our CoreHandle structure for the stream.
- CoreHandle *handle = 0;
- if ( stream_.apiHandle == 0 ) {
- try {
- handle = new CoreHandle;
- }
- catch ( std::bad_alloc& ) {
- errorText_ = "RtApiCore::probeDeviceOpen: error allocating CoreHandle memory.";
- goto error;
- }
-
- if ( pthread_cond_init( &handle->condition, NULL ) ) {
- errorText_ = "RtApiCore::probeDeviceOpen: error initializing pthread condition variable.";
- goto error;
- }
- stream_.apiHandle = (void *) handle;
- }
- else
- handle = (CoreHandle *) stream_.apiHandle;
- handle->iStream[mode] = firstStream;
- handle->nStreams[mode] = streamCount;
- handle->id[mode] = id;
-
- // Allocate necessary internal buffers.
- unsigned long bufferBytes;
- bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
- // stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );
- stream_.userBuffer[mode] = (char *) malloc( bufferBytes * sizeof(char) );
- memset( stream_.userBuffer[mode], 0, bufferBytes * sizeof(char) );
- if ( stream_.userBuffer[mode] == NULL ) {
- errorText_ = "RtApiCore::probeDeviceOpen: error allocating user buffer memory.";
- goto error;
- }
-
- // If possible, we will make use of the CoreAudio stream buffers as
- // "device buffers". However, we can't do this if using multiple
- // streams.
- if ( stream_.doConvertBuffer[mode] && handle->nStreams[mode] > 1 ) {
-
- bool makeBuffer = true;
- bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );
- if ( mode == INPUT ) {
- if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
- unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );
- if ( bufferBytes <= bytesOut ) makeBuffer = false;
- }
- }
-
- if ( makeBuffer ) {
- bufferBytes *= *bufferSize;
- if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );
- stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );
- if ( stream_.deviceBuffer == NULL ) {
- errorText_ = "RtApiCore::probeDeviceOpen: error allocating device buffer memory.";
- goto error;
- }
- }
- }
-
- stream_.sampleRate = sampleRate;
- stream_.device[mode] = device;
- stream_.state = STREAM_STOPPED;
- stream_.callbackInfo.object = (void *) this;
-
- // Setup the buffer conversion information structure.
- if ( stream_.doConvertBuffer[mode] ) {
- if ( streamCount > 1 ) setConvertInfo( mode, 0 );
- else setConvertInfo( mode, channelOffset );
- }
-
- if ( mode == INPUT && stream_.mode == OUTPUT && stream_.device[0] == device )
- // Only one callback procedure per device.
- stream_.mode = DUPLEX;
- else {
-#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
- result = AudioDeviceCreateIOProcID( id, callbackHandler, (void *) &stream_.callbackInfo, &handle->procId[mode] );
-#else
- // deprecated in favor of AudioDeviceCreateIOProcID()
- result = AudioDeviceAddIOProc( id, callbackHandler, (void *) &stream_.callbackInfo );
-#endif
- if ( result != noErr ) {
- errorStream_ << "RtApiCore::probeDeviceOpen: system error setting callback for device (" << device << ").";
- errorText_ = errorStream_.str();
- goto error;
- }
- if ( stream_.mode == OUTPUT && mode == INPUT )
- stream_.mode = DUPLEX;
- else
- stream_.mode = mode;
- }
-
- // Setup the device property listener for over/underload.
- property.mSelector = kAudioDeviceProcessorOverload;
- property.mScope = kAudioObjectPropertyScopeGlobal;
- result = AudioObjectAddPropertyListener( id, &property, xrunListener, (void *) handle );
-
- return SUCCESS;
-
- error:
- if ( handle ) {
- pthread_cond_destroy( &handle->condition );
- delete handle;
- stream_.apiHandle = 0;
- }
-
- for ( int i=0; i<2; i++ ) {
- if ( stream_.userBuffer[i] ) {
- free( stream_.userBuffer[i] );
- stream_.userBuffer[i] = 0;
- }
- }
-
- if ( stream_.deviceBuffer ) {
- free( stream_.deviceBuffer );
- stream_.deviceBuffer = 0;
- }
-
- stream_.state = STREAM_CLOSED;
- return FAILURE;
-}
-
-void RtApiCore :: closeStream( void )
-{
- if ( stream_.state == STREAM_CLOSED ) {
- errorText_ = "RtApiCore::closeStream(): no open stream to close!";
- error( RtAudioError::WARNING );
- return;
- }
-
- CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
- if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
- if (handle) {
- AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices,
- kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
-
- property.mSelector = kAudioDeviceProcessorOverload;
- property.mScope = kAudioObjectPropertyScopeGlobal;
- if (AudioObjectRemovePropertyListener( handle->id[0], &property, xrunListener, (void *) handle ) != noErr) {
- errorText_ = "RtApiCore::closeStream(): error removing property listener!";
- error( RtAudioError::WARNING );
- }
- }
- if ( stream_.state == STREAM_RUNNING )
- AudioDeviceStop( handle->id[0], callbackHandler );
-#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
- AudioDeviceDestroyIOProcID( handle->id[0], handle->procId[0] );
-#else
- // deprecated in favor of AudioDeviceDestroyIOProcID()
- AudioDeviceRemoveIOProc( handle->id[0], callbackHandler );
-#endif
- }
-
- if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) {
- if (handle) {
- AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices,
- kAudioObjectPropertyScopeGlobal,
- kAudioObjectPropertyElementMaster };
-
- property.mSelector = kAudioDeviceProcessorOverload;
- property.mScope = kAudioObjectPropertyScopeGlobal;
- if (AudioObjectRemovePropertyListener( handle->id[1], &property, xrunListener, (void *) handle ) != noErr) {
- errorText_ = "RtApiCore::closeStream(): error removing property listener!";
- error( RtAudioError::WARNING );
- }
- }
- if ( stream_.state == STREAM_RUNNING )
- AudioDeviceStop( handle->id[1], callbackHandler );
-#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
- AudioDeviceDestroyIOProcID( handle->id[1], handle->procId[1] );
-#else
- // deprecated in favor of AudioDeviceDestroyIOProcID()
- AudioDeviceRemoveIOProc( handle->id[1], callbackHandler );
-#endif
- }
-
- for ( int i=0; i<2; i++ ) {
- if ( stream_.userBuffer[i] ) {
- free( stream_.userBuffer[i] );
- stream_.userBuffer[i] = 0;
- }
- }
-
- if ( stream_.deviceBuffer ) {
- free( stream_.deviceBuffer );
- stream_.deviceBuffer = 0;
- }
-
- // Destroy pthread condition variable.
- pthread_cond_destroy( &handle->condition );
- delete handle;
- stream_.apiHandle = 0;
-
- stream_.mode = UNINITIALIZED;
- stream_.state = STREAM_CLOSED;
-}
-
-void RtApiCore :: startStream( void )
-{
- verifyStream();
- if ( stream_.state == STREAM_RUNNING ) {
- errorText_ = "RtApiCore::startStream(): the stream is already running!";
- error( RtAudioError::WARNING );
- return;
- }
-
- OSStatus result = noErr;
- CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
- if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
-
- result = AudioDeviceStart( handle->id[0], callbackHandler );
- if ( result != noErr ) {
- errorStream_ << "RtApiCore::startStream: system error (" << getErrorCode( result ) << ") starting callback procedure on device (" << stream_.device[0] << ").";
- errorText_ = errorStream_.str();
- goto unlock;
- }
- }
-
- if ( stream_.mode == INPUT ||
- ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) {
-
- result = AudioDeviceStart( handle->id[1], callbackHandler );
- if ( result != noErr ) {
- errorStream_ << "RtApiCore::startStream: system error starting input callback procedure on device (" << stream_.device[1] << ").";
- errorText_ = errorStream_.str();
- goto unlock;
- }
- }
-
- handle->drainCounter = 0;
- handle->internalDrain = false;
- stream_.state = STREAM_RUNNING;
-
- unlock:
- if ( result == noErr ) return;
- error( RtAudioError::SYSTEM_ERROR );
-}
-
-void RtApiCore :: stopStream( void )
-{
- verifyStream();
- if ( stream_.state == STREAM_STOPPED ) {
- errorText_ = "RtApiCore::stopStream(): the stream is already stopped!";
- error( RtAudioError::WARNING );
- return;
- }
-
- OSStatus result = noErr;
- CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
- if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
-
- if ( handle->drainCounter == 0 ) {
- handle->drainCounter = 2;
- pthread_cond_wait( &handle->condition, &stream_.mutex ); // block until signaled
- }
-
- result = AudioDeviceStop( handle->id[0], callbackHandler );
- if ( result != noErr ) {
- errorStream_ << "RtApiCore::stopStream: system error (" << getErrorCode( result ) << ") stopping callback procedure on device (" << stream_.device[0] << ").";
- errorText_ = errorStream_.str();
- goto unlock;
- }
- }
-
- if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) {
-
- result = AudioDeviceStop( handle->id[1], callbackHandler );
- if ( result != noErr ) {
- errorStream_ << "RtApiCore::stopStream: system error (" << getErrorCode( result ) << ") stopping input callback procedure on device (" << stream_.device[1] << ").";
- errorText_ = errorStream_.str();
- goto unlock;
- }
- }
-
- stream_.state = STREAM_STOPPED;
-
- unlock:
- if ( result == noErr ) return;
- error( RtAudioError::SYSTEM_ERROR );
-}
-
-void RtApiCore :: abortStream( void )
-{
- verifyStream();
- if ( stream_.state == STREAM_STOPPED ) {
- errorText_ = "RtApiCore::abortStream(): the stream is already stopped!";
- error( RtAudioError::WARNING );
- return;
- }
-
- CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
- handle->drainCounter = 2;
-
- stopStream();
-}
-
-// This function will be called by a spawned thread when the user
-// callback function signals that the stream should be stopped or
-// aborted. It is better to handle it this way because the
-// callbackEvent() function probably should return before the AudioDeviceStop()
-// function is called.
-static void *coreStopStream( void *ptr )
-{
- CallbackInfo *info = (CallbackInfo *) ptr;
- RtApiCore *object = (RtApiCore *) info->object;
-
- object->stopStream();
- pthread_exit( NULL );
-}
-
-bool RtApiCore :: callbackEvent( AudioDeviceID deviceId,
- const AudioBufferList *inBufferList,
- const AudioBufferList *outBufferList )
-{
- if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) return SUCCESS;
- if ( stream_.state == STREAM_CLOSED ) {
- errorText_ = "RtApiCore::callbackEvent(): the stream is closed ... this shouldn't happen!";
- error( RtAudioError::WARNING );
- return FAILURE;
- }
-
- CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
- CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
-
- // Check if we were draining the stream and signal is finished.
- if ( handle->drainCounter > 3 ) {
- ThreadHandle threadId;
-
- stream_.state = STREAM_STOPPING;
- if ( handle->internalDrain == true )
- pthread_create( &threadId, NULL, coreStopStream, info );
- else // external call to stopStream()
- pthread_cond_signal( &handle->condition );
- return SUCCESS;
- }
-
- AudioDeviceID outputDevice = handle->id[0];
-
- // Invoke user callback to get fresh output data UNLESS we are
- // draining stream or duplex mode AND the input/output devices are
- // different AND this function is called for the input device.
- if ( handle->drainCounter == 0 && ( stream_.mode != DUPLEX || deviceId == outputDevice ) ) {
- RtAudioCallback callback = (RtAudioCallback) info->callback;
- double streamTime = getStreamTime();
- RtAudioStreamStatus status = 0;
- if ( stream_.mode != INPUT && handle->xrun[0] == true ) {
- status |= RTAUDIO_OUTPUT_UNDERFLOW;
- handle->xrun[0] = false;
- }
- if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) {
- status |= RTAUDIO_INPUT_OVERFLOW;
- handle->xrun[1] = false;
- }
-
- int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1],
- stream_.bufferSize, streamTime, status, info->userData );
- if ( cbReturnValue == 2 ) {
- stream_.state = STREAM_STOPPING;
- handle->drainCounter = 2;
- abortStream();
- return SUCCESS;
- }
- else if ( cbReturnValue == 1 ) {
- handle->drainCounter = 1;
- handle->internalDrain = true;
- }
- }
-
- if ( stream_.mode == OUTPUT || ( stream_.mode == DUPLEX && deviceId == outputDevice ) ) {
-
- if ( handle->drainCounter > 1 ) { // write zeros to the output stream
-
- if ( handle->nStreams[0] == 1 ) {
- memset( outBufferList->mBuffers[handle->iStream[0]].mData,
- 0,
- outBufferList->mBuffers[handle->iStream[0]].mDataByteSize );
- }
- else { // fill multiple streams with zeros
- for ( unsigned int i=0; i<handle->nStreams[0]; i++ ) {
- memset( outBufferList->mBuffers[handle->iStream[0]+i].mData,
- 0,
- outBufferList->mBuffers[handle->iStream[0]+i].mDataByteSize );
- }
- }
- }
- else if ( handle->nStreams[0] == 1 ) {
- if ( stream_.doConvertBuffer[0] ) { // convert directly to CoreAudio stream buffer
- convertBuffer( (char *) outBufferList->mBuffers[handle->iStream[0]].mData,
- stream_.userBuffer[0], stream_.convertInfo[0] );
- }
- else { // copy from user buffer
- memcpy( outBufferList->mBuffers[handle->iStream[0]].mData,
- stream_.userBuffer[0],
- outBufferList->mBuffers[handle->iStream[0]].mDataByteSize );
- }
- }
- else { // fill multiple streams
- Float32 *inBuffer = (Float32 *) stream_.userBuffer[0];
- if ( stream_.doConvertBuffer[0] ) {
- convertBuffer( stream_.deviceBuffer, stream_.userBuffer[0], stream_.convertInfo[0] );
- inBuffer = (Float32 *) stream_.deviceBuffer;
- }
-
- if ( stream_.deviceInterleaved[0] == false ) { // mono mode
- UInt32 bufferBytes = outBufferList->mBuffers[handle->iStream[0]].mDataByteSize;
- for ( unsigned int i=0; i<stream_.nUserChannels[0]; i++ ) {
- memcpy( outBufferList->mBuffers[handle->iStream[0]+i].mData,
- (void *)&inBuffer[i*stream_.bufferSize], bufferBytes );
- }
- }
- else { // fill multiple multi-channel streams with interleaved data
- UInt32 streamChannels, channelsLeft, inJump, outJump, inOffset;
- Float32 *out, *in;
-
- bool inInterleaved = ( stream_.userInterleaved ) ? true : false;
- UInt32 inChannels = stream_.nUserChannels[0];
- if ( stream_.doConvertBuffer[0] ) {
- inInterleaved = true; // device buffer will always be interleaved for nStreams > 1 and not mono mode
- inChannels = stream_.nDeviceChannels[0];
- }
-
- if ( inInterleaved ) inOffset = 1;
- else inOffset = stream_.bufferSize;
-
- channelsLeft = inChannels;
- for ( unsigned int i=0; i<handle->nStreams[0]; i++ ) {
- in = inBuffer;
- out = (Float32 *) outBufferList->mBuffers[handle->iStream[0]+i].mData;
- streamChannels = outBufferList->mBuffers[handle->iStream[0]+i].mNumberChannels;
-
- outJump = 0;
- // Account for possible channel offset in first stream
- if ( i == 0 && stream_.channelOffset[0] > 0 ) {
- streamChannels -= stream_.channelOffset[0];
- outJump = stream_.channelOffset[0];
- out += outJump;
- }
-
- // Account for possible unfilled channels at end of the last stream
- if ( streamChannels > channelsLeft ) {
- outJump = streamChannels - channelsLeft;
- streamChannels = channelsLeft;
- }
-
- // Determine input buffer offsets and skips
- if ( inInterleaved ) {
- inJump = inChannels;
- in += inChannels - channelsLeft;
- }
- else {
- inJump = 1;
- in += (inChannels - channelsLeft) * inOffset;
- }
-
- for ( unsigned int i=0; i<stream_.bufferSize; i++ ) {
- for ( unsigned int j=0; j<streamChannels; j++ ) {
- *out++ = in[j*inOffset];
- }
- out += outJump;
- in += inJump;
- }
- channelsLeft -= streamChannels;
- }
- }
- }
- }
-
- // Don't bother draining input
- if ( handle->drainCounter ) {
- handle->drainCounter++;
- goto unlock;
- }
-
- AudioDeviceID inputDevice;
- inputDevice = handle->id[1];
- if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && deviceId == inputDevice ) ) {
-
- if ( handle->nStreams[1] == 1 ) {
- if ( stream_.doConvertBuffer[1] ) { // convert directly from CoreAudio stream buffer
- convertBuffer( stream_.userBuffer[1],
- (char *) inBufferList->mBuffers[handle->iStream[1]].mData,
- stream_.convertInfo[1] );
- }
- else { // copy to user buffer
- memcpy( stream_.userBuffer[1],
- inBufferList->mBuffers[handle->iStream[1]].mData,
- inBufferList->mBuffers[handle->iStream[1]].mDataByteSize );
- }
- }
- else { // read from multiple streams
- Float32 *outBuffer = (Float32 *) stream_.userBuffer[1];
- if ( stream_.doConvertBuffer[1] ) outBuffer = (Float32 *) stream_.deviceBuffer;
-
- if ( stream_.deviceInterleaved[1] == false ) { // mono mode
- UInt32 bufferBytes = inBufferList->mBuffers[handle->iStream[1]].mDataByteSize;
- for ( unsigned int i=0; i<stream_.nUserChannels[1]; i++ ) {
- memcpy( (void *)&outBuffer[i*stream_.bufferSize],
- inBufferList->mBuffers[handle->iStream[1]+i].mData, bufferBytes );
- }
- }
- else { // read from multiple multi-channel streams
- UInt32 streamChannels, channelsLeft, inJump, outJump, outOffset;
- Float32 *out, *in;
-
- bool outInterleaved = ( stream_.userInterleaved ) ? true : false;
- UInt32 outChannels = stream_.nUserChannels[1];
- if ( stream_.doConvertBuffer[1] ) {
- outInterleaved = true; // device buffer will always be interleaved for nStreams > 1 and not mono mode
- outChannels = stream_.nDeviceChannels[1];
- }
-
- if ( outInterleaved ) outOffset = 1;
- else outOffset = stream_.bufferSize;
-
- channelsLeft = outChannels;
- for ( unsigned int i=0; i<handle->nStreams[1]; i++ ) {
- out = outBuffer;
- in = (Float32 *) inBufferList->mBuffers[handle->iStream[1]+i].mData;
- streamChannels = inBufferList->mBuffers[handle->iStream[1]+i].mNumberChannels;
-
- inJump = 0;
- // Account for possible channel offset in first stream
- if ( i == 0 && stream_.channelOffset[1] > 0 ) {
- streamChannels -= stream_.channelOffset[1];
- inJump = stream_.channelOffset[1];
- in += inJump;
- }
-
- // Account for possible unread channels at end of the last stream
- if ( streamChannels > channelsLeft ) {
- inJump = streamChannels - channelsLeft;
- streamChannels = channelsLeft;
- }
-
- // Determine output buffer offsets and skips
- if ( outInterleaved ) {
- outJump = outChannels;
- out += outChannels - channelsLeft;
- }
- else {
- outJump = 1;
- out += (outChannels - channelsLeft) * outOffset;
- }
-
- for ( unsigned int i=0; i<stream_.bufferSize; i++ ) {
- for ( unsigned int j=0; j<streamChannels; j++ ) {
- out[j*outOffset] = *in++;
- }
- out += outJump;
- in += inJump;
- }
- channelsLeft -= streamChannels;
- }
- }
-
- if ( stream_.doConvertBuffer[1] ) { // convert from our internal "device" buffer
- convertBuffer( stream_.userBuffer[1],
- stream_.deviceBuffer,
- stream_.convertInfo[1] );
- }
- }
- }
-
- unlock:
- //MUTEX_UNLOCK( &stream_.mutex );
-
- RtApi::tickStreamTime();
- return SUCCESS;
-}
-
-const char* RtApiCore :: getErrorCode( OSStatus code )
-{
- switch( code ) {
-
- case kAudioHardwareNotRunningError:
- return "kAudioHardwareNotRunningError";
-
- case kAudioHardwareUnspecifiedError:
- return "kAudioHardwareUnspecifiedError";
-
- case kAudioHardwareUnknownPropertyError:
- return "kAudioHardwareUnknownPropertyError";
-
- case kAudioHardwareBadPropertySizeError:
- return "kAudioHardwareBadPropertySizeError";
-
- case kAudioHardwareIllegalOperationError:
- return "kAudioHardwareIllegalOperationError";
-
- case kAudioHardwareBadObjectError:
- return "kAudioHardwareBadObjectError";
-
- case kAudioHardwareBadDeviceError:
- return "kAudioHardwareBadDeviceError";
-
- case kAudioHardwareBadStreamError:
- return "kAudioHardwareBadStreamError";
-
- case kAudioHardwareUnsupportedOperationError:
- return "kAudioHardwareUnsupportedOperationError";
-
- case kAudioDeviceUnsupportedFormatError:
- return "kAudioDeviceUnsupportedFormatError";
-
- case kAudioDevicePermissionsError:
- return "kAudioDevicePermissionsError";
-
- default:
- return "CoreAudio unknown error";
- }
-}
-
- //******************** End of __MACOSX_CORE__ *********************//
-#endif
-
-#if defined(__UNIX_JACK__)
-
-// JACK is a low-latency audio server, originally written for the
-// GNU/Linux operating system and now also ported to OS-X. It can
-// connect a number of different applications to an audio device, as
-// well as allowing them to share audio between themselves.
-//
-// When using JACK with RtAudio, "devices" refer to JACK clients that
-// have ports connected to the server. The JACK server is typically
-// started in a terminal as follows:
-//
-// .jackd -d alsa -d hw:0
-//
-// or through an interface program such as qjackctl. Many of the
-// parameters normally set for a stream are fixed by the JACK server
-// and can be specified when the JACK server is started. In
-// particular,
-//
-// .jackd -d alsa -d hw:0 -r 44100 -p 512 -n 4
-//
-// specifies a sample rate of 44100 Hz, a buffer size of 512 sample
-// frames, and number of buffers = 4. Once the server is running, it
-// is not possible to override these values. If the values are not
-// specified in the command-line, the JACK server uses default values.
-//
-// The JACK server does not have to be running when an instance of
-// RtApiJack is created, though the function getDeviceCount() will
-// report 0 devices found until JACK has been started. When no
-// devices are available (i.e., the JACK server is not running), a
-// stream cannot be opened.
-
-#include <jack/jack.h>
-#include <unistd.h>
-#include <cstdio>
-
-// A structure to hold various information related to the Jack API
-// implementation.
-struct JackHandle {
- jack_client_t *client;
- jack_port_t **ports[2];
- std::string deviceName[2];
- bool xrun[2];
- pthread_cond_t condition;
- int drainCounter; // Tracks callback counts when draining
- bool internalDrain; // Indicates if stop is initiated from callback or not.
-
- JackHandle()
- :client(0), drainCounter(0), internalDrain(false) { ports[0] = 0; ports[1] = 0; xrun[0] = false; xrun[1] = false; }
-};
-
-static void jackSilentError( const char * ) {};
-
-RtApiJack :: RtApiJack()
-{
- // Nothing to do here.
-#if !defined(__RTAUDIO_DEBUG__)
- // Turn off Jack's internal error reporting.
- jack_set_error_function( &jackSilentError );
-#endif
-}
-
-RtApiJack :: ~RtApiJack()
-{
- if ( stream_.state != STREAM_CLOSED ) closeStream();
-}
-
-unsigned int RtApiJack :: getDeviceCount( void )
-{
- // See if we can become a jack client.
- jack_options_t options = (jack_options_t) ( JackNoStartServer ); //JackNullOption;
- jack_status_t *status = NULL;
- jack_client_t *client = jack_client_open( "RtApiJackCount", options, status );
- if ( client == 0 ) return 0;
-
- const char **ports;
- std::string port, previousPort;
- unsigned int nChannels = 0, nDevices = 0;
- ports = jack_get_ports( client, NULL, NULL, 0 );
- if ( ports ) {
- // Parse the port names up to the first colon (:).
- size_t iColon = 0;
- do {
- port = (char *) ports[ nChannels ];
- iColon = port.find(":");
- if ( iColon != std::string::npos ) {
- port = port.substr( 0, iColon + 1 );
- if ( port != previousPort ) {
- nDevices++;
- previousPort = port;
- }
- }
- } while ( ports[++nChannels] );
- free( ports );
- }
-
- jack_client_close( client );
- return nDevices;
-}
-
-RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device )
-{
- RtAudio::DeviceInfo info;
- info.probed = false;
-
- jack_options_t options = (jack_options_t) ( JackNoStartServer ); //JackNullOption
- jack_status_t *status = NULL;
- jack_client_t *client = jack_client_open( "RtApiJackInfo", options, status );
- if ( client == 0 ) {
- errorText_ = "RtApiJack::getDeviceInfo: Jack server not found or connection error!";
- error( RtAudioError::WARNING );
- return info;
- }
-
- const char **ports;
- std::string port, previousPort;
- unsigned int nPorts = 0, nDevices = 0;
- ports = jack_get_ports( client, NULL, NULL, 0 );
- if ( ports ) {
- // Parse the port names up to the first colon (:).
- size_t iColon = 0;
- do {
- port = (char *) ports[ nPorts ];
- iColon = port.find(":");
- if ( iColon != std::string::npos ) {
- port = port.substr( 0, iColon );
- if ( port != previousPort ) {
- if ( nDevices == device ) info.name = port;
- nDevices++;
- previousPort = port;
- }
- }
- } while ( ports[++nPorts] );
- free( ports );
- }
-
- if ( device >= nDevices ) {
- jack_client_close( client );
- errorText_ = "RtApiJack::getDeviceInfo: device ID is invalid!";
- error( RtAudioError::INVALID_USE );
- return info;
- }
-
- // Get the current jack server sample rate.
- info.sampleRates.clear();
-
- info.preferredSampleRate = jack_get_sample_rate( client );
- info.sampleRates.push_back( info.preferredSampleRate );
-
- // Count the available ports containing the client name as device
- // channels. Jack "input ports" equal RtAudio output channels.
- unsigned int nChannels = 0;
- ports = jack_get_ports( client, info.name.c_str(), NULL, JackPortIsInput );
- if ( ports ) {
- while ( ports[ nChannels ] ) nChannels++;
- free( ports );
- info.outputChannels = nChannels;
- }
-
- // Jack "output ports" equal RtAudio input channels.
- nChannels = 0;
- ports = jack_get_ports( client, info.name.c_str(), NULL, JackPortIsOutput );
- if ( ports ) {
- while ( ports[ nChannels ] ) nChannels++;
- free( ports );
- info.inputChannels = nChannels;
- }
-
- if ( info.outputChannels == 0 && info.inputChannels == 0 ) {
- jack_client_close(client);
- errorText_ = "RtApiJack::getDeviceInfo: error determining Jack input/output channels!";
- error( RtAudioError::WARNING );
- return info;
- }
-
- // If device opens for both playback and capture, we determine the channels.
- if ( info.outputChannels > 0 && info.inputChannels > 0 )
- info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;
-
- // Jack always uses 32-bit floats.
- info.nativeFormats = RTAUDIO_FLOAT32;
-
- // Jack doesn't provide default devices so we'll use the first available one.
- if ( device == 0 && info.outputChannels > 0 )
- info.isDefaultOutput = true;
- if ( device == 0 && info.inputChannels > 0 )
- info.isDefaultInput = true;
-
- jack_client_close(client);
- info.probed = true;
- return info;
-}
-
-static int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer )
-{
- CallbackInfo *info = (CallbackInfo *) infoPointer;
-
- RtApiJack *object = (RtApiJack *) info->object;
- if ( object->callbackEvent( (unsigned long) nframes ) == false ) return 1;
-
- return 0;
-}
-
-// This function will be called by a spawned thread when the Jack
-// server signals that it is shutting down. It is necessary to handle
-// it this way because the jackShutdown() function must return before
-// the jack_deactivate() function (in closeStream()) will return.
-static void *jackCloseStream( void *ptr )
-{
- CallbackInfo *info = (CallbackInfo *) ptr;
- RtApiJack *object = (RtApiJack *) info->object;
-
- object->closeStream();
-
- pthread_exit( NULL );
-}
-static void jackShutdown( void *infoPointer )
-{
- CallbackInfo *info = (CallbackInfo *) infoPointer;
- RtApiJack *object = (RtApiJack *) info->object;
-
- // Check current stream state. If stopped, then we'll assume this
- // was called as a result of a call to RtApiJack::stopStream (the
- // deactivation of a client handle causes this function to be called).
- // If not, we'll assume the Jack server is shutting down or some
- // other problem occurred and we should close the stream.
- if ( object->isStreamRunning() == false ) return;
-
- ThreadHandle threadId;
- pthread_create( &threadId, NULL, jackCloseStream, info );
- std::cerr << "\nRtApiJack: the Jack server is shutting down this client ... stream stopped and closed!!\n" << std::endl;
-}
-
-static int jackXrun( void *infoPointer )
-{
- JackHandle *handle = (JackHandle *) infoPointer;
-
- if ( handle->ports[0] ) handle->xrun[0] = true;
- if ( handle->ports[1] ) handle->xrun[1] = true;
-
- return 0;
-}
-
-bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
- unsigned int firstChannel, unsigned int sampleRate,
- RtAudioFormat format, unsigned int *bufferSize,
- RtAudio::StreamOptions *options )
-{
- JackHandle *handle = (JackHandle *) stream_.apiHandle;
-
- // Look for jack server and try to become a client (only do once per stream).
- jack_client_t *client = 0;
- if ( mode == OUTPUT || ( mode == INPUT && stream_.mode != OUTPUT ) ) {
- jack_options_t jackoptions = (jack_options_t) ( JackNoStartServer ); //JackNullOption;
- jack_status_t *status = NULL;
- if ( options && !options->streamName.empty() )
- client = jack_client_open( options->streamName.c_str(), jackoptions, status );
- else
- client = jack_client_open( "RtApiJack", jackoptions, status );
- if ( client == 0 ) {
- errorText_ = "RtApiJack::probeDeviceOpen: Jack server not found or connection error!";
- error( RtAudioError::WARNING );
- return FAILURE;
- }
- }
- else {
- // The handle must have been created on an earlier pass.
- client = handle->client;
- }
-
- const char **ports;
- std::string port, previousPort, deviceName;
- unsigned int nPorts = 0, nDevices = 0;
- ports = jack_get_ports( client, NULL, NULL, 0 );
- if ( ports ) {
- // Parse the port names up to the first colon (:).
- size_t iColon = 0;
- do {
- port = (char *) ports[ nPorts ];
- iColon = port.find(":");
- if ( iColon != std::string::npos ) {
- port = port.substr( 0, iColon );
- if ( port != previousPort ) {
- if ( nDevices == device ) deviceName = port;
- nDevices++;
- previousPort = port;
- }
- }
- } while ( ports[++nPorts] );
- free( ports );
- }
-
- if ( device >= nDevices ) {
- errorText_ = "RtApiJack::probeDeviceOpen: device ID is invalid!";
- return FAILURE;
- }
-
- // Count the available ports containing the client name as device
- // channels. Jack "input ports" equal RtAudio output channels.
- unsigned int nChannels = 0;
- unsigned long flag = JackPortIsInput;
- if ( mode == INPUT ) flag = JackPortIsOutput;
- ports = jack_get_ports( client, deviceName.c_str(), NULL, flag );
- if ( ports ) {
- while ( ports[ nChannels ] ) nChannels++;
- free( ports );
- }
-
- // Compare the jack ports for specified client to the requested number of channels.
- if ( nChannels < (channels + firstChannel) ) {
- errorStream_ << "RtApiJack::probeDeviceOpen: requested number of channels (" << channels << ") + offset (" << firstChannel << ") not found for specified device (" << device << ":" << deviceName << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Check the jack server sample rate.
- unsigned int jackRate = jack_get_sample_rate( client );
- if ( sampleRate != jackRate ) {
- jack_client_close( client );
- errorStream_ << "RtApiJack::probeDeviceOpen: the requested sample rate (" << sampleRate << ") is different than the JACK server rate (" << jackRate << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
- stream_.sampleRate = jackRate;
-
- // Get the latency of the JACK port.
- ports = jack_get_ports( client, deviceName.c_str(), NULL, flag );
- if ( ports[ firstChannel ] ) {
- // Added by Ge Wang
- jack_latency_callback_mode_t cbmode = (mode == INPUT ? JackCaptureLatency : JackPlaybackLatency);
- // the range (usually the min and max are equal)
- jack_latency_range_t latrange; latrange.min = latrange.max = 0;
- // get the latency range
- jack_port_get_latency_range( jack_port_by_name( client, ports[firstChannel] ), cbmode, &latrange );
- // be optimistic, use the min!
- stream_.latency[mode] = latrange.min;
- //stream_.latency[mode] = jack_port_get_latency( jack_port_by_name( client, ports[ firstChannel ] ) );
- }
- free( ports );
-
- // The jack server always uses 32-bit floating-point data.
- stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
- stream_.userFormat = format;
-
- if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;
- else stream_.userInterleaved = true;
-
- // Jack always uses non-interleaved buffers.
- stream_.deviceInterleaved[mode] = false;
-
- // Jack always provides host byte-ordered data.
- stream_.doByteSwap[mode] = false;
-
- // Get the buffer size. The buffer size and number of buffers
- // (periods) is set when the jack server is started.
- stream_.bufferSize = (int) jack_get_buffer_size( client );
- *bufferSize = stream_.bufferSize;
-
- stream_.nDeviceChannels[mode] = channels;
- stream_.nUserChannels[mode] = channels;
-
- // Set flags for buffer conversion.
- stream_.doConvertBuffer[mode] = false;
- if ( stream_.userFormat != stream_.deviceFormat[mode] )
- stream_.doConvertBuffer[mode] = true;
- if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&
- stream_.nUserChannels[mode] > 1 )
- stream_.doConvertBuffer[mode] = true;
-
- // Allocate our JackHandle structure for the stream.
- if ( handle == 0 ) {
- try {
- handle = new JackHandle;
- }
- catch ( std::bad_alloc& ) {
- errorText_ = "RtApiJack::probeDeviceOpen: error allocating JackHandle memory.";
- goto error;
- }
-
- if ( pthread_cond_init(&handle->condition, NULL) ) {
- errorText_ = "RtApiJack::probeDeviceOpen: error initializing pthread condition variable.";
- goto error;
- }
- stream_.apiHandle = (void *) handle;
- handle->client = client;
- }
- handle->deviceName[mode] = deviceName;
-
- // Allocate necessary internal buffers.
- unsigned long bufferBytes;
- bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
- stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );
- if ( stream_.userBuffer[mode] == NULL ) {
- errorText_ = "RtApiJack::probeDeviceOpen: error allocating user buffer memory.";
- goto error;
- }
-
- if ( stream_.doConvertBuffer[mode] ) {
-
- bool makeBuffer = true;
- if ( mode == OUTPUT )
- bufferBytes = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );
- else { // mode == INPUT
- bufferBytes = stream_.nDeviceChannels[1] * formatBytes( stream_.deviceFormat[1] );
- if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
- unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
- if ( bufferBytes < bytesOut ) makeBuffer = false;
- }
- }
-
- if ( makeBuffer ) {
- bufferBytes *= *bufferSize;
- if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );
- stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );
- if ( stream_.deviceBuffer == NULL ) {
- errorText_ = "RtApiJack::probeDeviceOpen: error allocating device buffer memory.";
- goto error;
- }
- }
- }
-
- // Allocate memory for the Jack ports (channels) identifiers.
- handle->ports[mode] = (jack_port_t **) malloc ( sizeof (jack_port_t *) * channels );
- if ( handle->ports[mode] == NULL ) {
- errorText_ = "RtApiJack::probeDeviceOpen: error allocating port memory.";
- goto error;
- }
-
- stream_.device[mode] = device;
- stream_.channelOffset[mode] = firstChannel;
- stream_.state = STREAM_STOPPED;
- stream_.callbackInfo.object = (void *) this;
-
- if ( stream_.mode == OUTPUT && mode == INPUT )
- // We had already set up the stream for output.
- stream_.mode = DUPLEX;
- else {
- stream_.mode = mode;
- jack_set_process_callback( handle->client, jackCallbackHandler, (void *) &stream_.callbackInfo );
- jack_set_xrun_callback( handle->client, jackXrun, (void *) &handle );
- jack_on_shutdown( handle->client, jackShutdown, (void *) &stream_.callbackInfo );
- }
-
- // Register our ports.
- char label[64];
- if ( mode == OUTPUT ) {
- for ( unsigned int i=0; i<stream_.nUserChannels[0]; i++ ) {
- snprintf( label, 64, "outport %d", i );
- handle->ports[0][i] = jack_port_register( handle->client, (const char *)label,
- JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 );
- }
- }
- else {
- for ( unsigned int i=0; i<stream_.nUserChannels[1]; i++ ) {
- snprintf( label, 64, "inport %d", i );
- handle->ports[1][i] = jack_port_register( handle->client, (const char *)label,
- JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 );
- }
- }
-
- // Setup the buffer conversion information structure. We don't use
- // buffers to do channel offsets, so we override that parameter
- // here.
- if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, 0 );
-
- return SUCCESS;
-
- error:
- if ( handle ) {
- pthread_cond_destroy( &handle->condition );
- jack_client_close( handle->client );
-
- if ( handle->ports[0] ) free( handle->ports[0] );
- if ( handle->ports[1] ) free( handle->ports[1] );
-
- delete handle;
- stream_.apiHandle = 0;
- }
-
- for ( int i=0; i<2; i++ ) {
- if ( stream_.userBuffer[i] ) {
- free( stream_.userBuffer[i] );
- stream_.userBuffer[i] = 0;
- }
- }
-
- if ( stream_.deviceBuffer ) {
- free( stream_.deviceBuffer );
- stream_.deviceBuffer = 0;
- }
-
- return FAILURE;
-}
-
-void RtApiJack :: closeStream( void )
-{
- if ( stream_.state == STREAM_CLOSED ) {
- errorText_ = "RtApiJack::closeStream(): no open stream to close!";
- error( RtAudioError::WARNING );
- return;
- }
-
- JackHandle *handle = (JackHandle *) stream_.apiHandle;
- if ( handle ) {
-
- if ( stream_.state == STREAM_RUNNING )
- jack_deactivate( handle->client );
-
- jack_client_close( handle->client );
- }
-
- if ( handle ) {
- if ( handle->ports[0] ) free( handle->ports[0] );
- if ( handle->ports[1] ) free( handle->ports[1] );
- pthread_cond_destroy( &handle->condition );
- delete handle;
- stream_.apiHandle = 0;
- }
-
- for ( int i=0; i<2; i++ ) {
- if ( stream_.userBuffer[i] ) {
- free( stream_.userBuffer[i] );
- stream_.userBuffer[i] = 0;
- }
- }
-
- if ( stream_.deviceBuffer ) {
- free( stream_.deviceBuffer );
- stream_.deviceBuffer = 0;
- }
-
- stream_.mode = UNINITIALIZED;
- stream_.state = STREAM_CLOSED;
-}
-
-void RtApiJack :: startStream( void )
-{
- verifyStream();
- if ( stream_.state == STREAM_RUNNING ) {
- errorText_ = "RtApiJack::startStream(): the stream is already running!";
- error( RtAudioError::WARNING );
- return;
- }
-
- JackHandle *handle = (JackHandle *) stream_.apiHandle;
- int result = jack_activate( handle->client );
- if ( result ) {
- errorText_ = "RtApiJack::startStream(): unable to activate JACK client!";
- goto unlock;
- }
-
- const char **ports;
-
- // Get the list of available ports.
- if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
- result = 1;
- ports = jack_get_ports( handle->client, handle->deviceName[0].c_str(), NULL, JackPortIsInput);
- if ( ports == NULL) {
- errorText_ = "RtApiJack::startStream(): error determining available JACK input ports!";
- goto unlock;
- }
-
- // Now make the port connections. Since RtAudio wasn't designed to
- // allow the user to select particular channels of a device, we'll
- // just open the first "nChannels" ports with offset.
- for ( unsigned int i=0; i<stream_.nUserChannels[0]; i++ ) {
- result = 1;
- if ( ports[ stream_.channelOffset[0] + i ] )
- result = jack_connect( handle->client, jack_port_name( handle->ports[0][i] ), ports[ stream_.channelOffset[0] + i ] );
- if ( result ) {
- free( ports );
- errorText_ = "RtApiJack::startStream(): error connecting output ports!";
- goto unlock;
- }
- }
- free(ports);
- }
-
- if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
- result = 1;
- ports = jack_get_ports( handle->client, handle->deviceName[1].c_str(), NULL, JackPortIsOutput );
- if ( ports == NULL) {
- errorText_ = "RtApiJack::startStream(): error determining available JACK output ports!";
- goto unlock;
- }
-
- // Now make the port connections. See note above.
- for ( unsigned int i=0; i<stream_.nUserChannels[1]; i++ ) {
- result = 1;
- if ( ports[ stream_.channelOffset[1] + i ] )
- result = jack_connect( handle->client, ports[ stream_.channelOffset[1] + i ], jack_port_name( handle->ports[1][i] ) );
- if ( result ) {
- free( ports );
- errorText_ = "RtApiJack::startStream(): error connecting input ports!";
- goto unlock;
- }
- }
- free(ports);
- }
-
- handle->drainCounter = 0;
- handle->internalDrain = false;
- stream_.state = STREAM_RUNNING;
-
- unlock:
- if ( result == 0 ) return;
- error( RtAudioError::SYSTEM_ERROR );
-}
-
-void RtApiJack :: stopStream( void )
-{
- verifyStream();
- if ( stream_.state == STREAM_STOPPED ) {
- errorText_ = "RtApiJack::stopStream(): the stream is already stopped!";
- error( RtAudioError::WARNING );
- return;
- }
-
- JackHandle *handle = (JackHandle *) stream_.apiHandle;
- if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
-
- if ( handle->drainCounter == 0 ) {
- handle->drainCounter = 2;
- pthread_cond_wait( &handle->condition, &stream_.mutex ); // block until signaled
- }
- }
-
- jack_deactivate( handle->client );
- stream_.state = STREAM_STOPPED;
-}
-
-void RtApiJack :: abortStream( void )
-{
- verifyStream();
- if ( stream_.state == STREAM_STOPPED ) {
- errorText_ = "RtApiJack::abortStream(): the stream is already stopped!";
- error( RtAudioError::WARNING );
- return;
- }
-
- JackHandle *handle = (JackHandle *) stream_.apiHandle;
- handle->drainCounter = 2;
-
- stopStream();
-}
-
-// This function will be called by a spawned thread when the user
-// callback function signals that the stream should be stopped or
-// aborted. It is necessary to handle it this way because the
-// callbackEvent() function must return before the jack_deactivate()
-// function will return.
-static void *jackStopStream( void *ptr )
-{
- CallbackInfo *info = (CallbackInfo *) ptr;
- RtApiJack *object = (RtApiJack *) info->object;
-
- object->stopStream();
- pthread_exit( NULL );
-}
-
-bool RtApiJack :: callbackEvent( unsigned long nframes )
-{
- if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) return SUCCESS;
- if ( stream_.state == STREAM_CLOSED ) {
- errorText_ = "RtApiCore::callbackEvent(): the stream is closed ... this shouldn't happen!";
- error( RtAudioError::WARNING );
- return FAILURE;
- }
- if ( stream_.bufferSize != nframes ) {
- errorText_ = "RtApiCore::callbackEvent(): the JACK buffer size has changed ... cannot process!";
- error( RtAudioError::WARNING );
- return FAILURE;
- }
-
- CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
- JackHandle *handle = (JackHandle *) stream_.apiHandle;
-
- // Check if we were draining the stream and signal is finished.
- if ( handle->drainCounter > 3 ) {
- ThreadHandle threadId;
-
- stream_.state = STREAM_STOPPING;
- if ( handle->internalDrain == true )
- pthread_create( &threadId, NULL, jackStopStream, info );
- else
- pthread_cond_signal( &handle->condition );
- return SUCCESS;
- }
-
- // Invoke user callback first, to get fresh output data.
- if ( handle->drainCounter == 0 ) {
- RtAudioCallback callback = (RtAudioCallback) info->callback;
- double streamTime = getStreamTime();
- RtAudioStreamStatus status = 0;
- if ( stream_.mode != INPUT && handle->xrun[0] == true ) {
- status |= RTAUDIO_OUTPUT_UNDERFLOW;
- handle->xrun[0] = false;
- }
- if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) {
- status |= RTAUDIO_INPUT_OVERFLOW;
- handle->xrun[1] = false;
- }
- int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1],
- stream_.bufferSize, streamTime, status, info->userData );
- if ( cbReturnValue == 2 ) {
- stream_.state = STREAM_STOPPING;
- handle->drainCounter = 2;
- ThreadHandle id;
- pthread_create( &id, NULL, jackStopStream, info );
- return SUCCESS;
- }
- else if ( cbReturnValue == 1 ) {
- handle->drainCounter = 1;
- handle->internalDrain = true;
- }
- }
-
- jack_default_audio_sample_t *jackbuffer;
- unsigned long bufferBytes = nframes * sizeof( jack_default_audio_sample_t );
- if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
-
- if ( handle->drainCounter > 1 ) { // write zeros to the output stream
-
- for ( unsigned int i=0; i<stream_.nDeviceChannels[0]; i++ ) {
- jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[0][i], (jack_nframes_t) nframes );
- memset( jackbuffer, 0, bufferBytes );
- }
-
- }
- else if ( stream_.doConvertBuffer[0] ) {
-
- convertBuffer( stream_.deviceBuffer, stream_.userBuffer[0], stream_.convertInfo[0] );
-
- for ( unsigned int i=0; i<stream_.nDeviceChannels[0]; i++ ) {
- jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[0][i], (jack_nframes_t) nframes );
- memcpy( jackbuffer, &stream_.deviceBuffer[i*bufferBytes], bufferBytes );
- }
- }
- else { // no buffer conversion
- for ( unsigned int i=0; i<stream_.nUserChannels[0]; i++ ) {
- jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[0][i], (jack_nframes_t) nframes );
- memcpy( jackbuffer, &stream_.userBuffer[0][i*bufferBytes], bufferBytes );
- }
- }
- }
-
- // Don't bother draining input
- if ( handle->drainCounter ) {
- handle->drainCounter++;
- goto unlock;
- }
-
- if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
-
- if ( stream_.doConvertBuffer[1] ) {
- for ( unsigned int i=0; i<stream_.nDeviceChannels[1]; i++ ) {
- jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[1][i], (jack_nframes_t) nframes );
- memcpy( &stream_.deviceBuffer[i*bufferBytes], jackbuffer, bufferBytes );
- }
- convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );
- }
- else { // no buffer conversion
- for ( unsigned int i=0; i<stream_.nUserChannels[1]; i++ ) {
- jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[1][i], (jack_nframes_t) nframes );
- memcpy( &stream_.userBuffer[1][i*bufferBytes], jackbuffer, bufferBytes );
- }
- }
- }
-
- unlock:
- RtApi::tickStreamTime();
- return SUCCESS;
-}
- //******************** End of __UNIX_JACK__ *********************//
-#endif
-
-#if defined(__WINDOWS_ASIO__) // ASIO API on Windows
-
-// The ASIO API is designed around a callback scheme, so this
-// implementation is similar to that used for OS-X CoreAudio and Linux
-// Jack. The primary constraint with ASIO is that it only allows
-// access to a single driver at a time. Thus, it is not possible to
-// have more than one simultaneous RtAudio stream.
-//
-// This implementation also requires a number of external ASIO files
-// and a few global variables. The ASIO callback scheme does not
-// allow for the passing of user data, so we must create a global
-// pointer to our callbackInfo structure.
-//
-// On unix systems, we make use of a pthread condition variable.
-// Since there is no equivalent in Windows, I hacked something based
-// on information found in
-// http://www.cs.wustl.edu/~schmidt/win32-cv-1.html.
-
-#include "asiosys.h"
-#include "asio.h"
-#include "iasiothiscallresolver.h"
-#include "asiodrivers.h"
-#include <cmath>
-
-static AsioDrivers drivers;
-static ASIOCallbacks asioCallbacks;
-static ASIODriverInfo driverInfo;
-static CallbackInfo *asioCallbackInfo;
-static bool asioXRun;
-
-struct AsioHandle {
- int drainCounter; // Tracks callback counts when draining
- bool internalDrain; // Indicates if stop is initiated from callback or not.
- ASIOBufferInfo *bufferInfos;
- HANDLE condition;
-
- AsioHandle()
- :drainCounter(0), internalDrain(false), bufferInfos(0) {}
-};
-
-// Function declarations (definitions at end of section)
-static const char* getAsioErrorString( ASIOError result );
-static void sampleRateChanged( ASIOSampleRate sRate );
-static long asioMessages( long selector, long value, void* message, double* opt );
-
-RtApiAsio :: RtApiAsio()
-{
- // ASIO cannot run on a multi-threaded appartment. You can call
- // CoInitialize beforehand, but it must be for appartment threading
- // (in which case, CoInitilialize will return S_FALSE here).
- coInitialized_ = false;
- HRESULT hr = CoInitialize( NULL );
- if ( FAILED(hr) ) {
- errorText_ = "RtApiAsio::ASIO requires a single-threaded appartment. Call CoInitializeEx(0,COINIT_APARTMENTTHREADED)";
- error( RtAudioError::WARNING );
- }
- coInitialized_ = true;
-
- drivers.removeCurrentDriver();
- driverInfo.asioVersion = 2;
-
- // See note in DirectSound implementation about GetDesktopWindow().
- driverInfo.sysRef = GetForegroundWindow();
-}
-
-RtApiAsio :: ~RtApiAsio()
-{
- if ( stream_.state != STREAM_CLOSED ) closeStream();
- if ( coInitialized_ ) CoUninitialize();
-}
-
-unsigned int RtApiAsio :: getDeviceCount( void )
-{
- return (unsigned int) drivers.asioGetNumDev();
-}
-
-RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
-{
- RtAudio::DeviceInfo info;
- info.probed = false;
-
- // Get device ID
- unsigned int nDevices = getDeviceCount();
- if ( nDevices == 0 ) {
- errorText_ = "RtApiAsio::getDeviceInfo: no devices found!";
- error( RtAudioError::INVALID_USE );
- return info;
- }
-
- if ( device >= nDevices ) {
- errorText_ = "RtApiAsio::getDeviceInfo: device ID is invalid!";
- error( RtAudioError::INVALID_USE );
- return info;
- }
-
- // If a stream is already open, we cannot probe other devices. Thus, use the saved results.
- if ( stream_.state != STREAM_CLOSED ) {
- if ( device >= devices_.size() ) {
- errorText_ = "RtApiAsio::getDeviceInfo: device ID was not present before stream was opened.";
- error( RtAudioError::WARNING );
- return info;
- }
- return devices_[ device ];
- }
-
- char driverName[32];
- ASIOError result = drivers.asioGetDriverName( (int) device, driverName, 32 );
- if ( result != ASE_OK ) {
- errorStream_ << "RtApiAsio::getDeviceInfo: unable to get driver name (" << getAsioErrorString( result ) << ").";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- return info;
- }
-
- info.name = driverName;
-
- if ( !drivers.loadDriver( driverName ) ) {
- errorStream_ << "RtApiAsio::getDeviceInfo: unable to load driver (" << driverName << ").";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- return info;
- }
-
- result = ASIOInit( &driverInfo );
- if ( result != ASE_OK ) {
- errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") initializing driver (" << driverName << ").";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- return info;
- }
-
- // Determine the device channel information.
- long inputChannels, outputChannels;
- result = ASIOGetChannels( &inputChannels, &outputChannels );
- if ( result != ASE_OK ) {
- drivers.removeCurrentDriver();
- errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") getting channel count (" << driverName << ").";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- return info;
- }
-
- info.outputChannels = outputChannels;
- info.inputChannels = inputChannels;
- if ( info.outputChannels > 0 && info.inputChannels > 0 )
- info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;
-
- // Determine the supported sample rates.
- info.sampleRates.clear();
- for ( unsigned int i=0; i<MAX_SAMPLE_RATES; i++ ) {
- result = ASIOCanSampleRate( (ASIOSampleRate) SAMPLE_RATES[i] );
- if ( result == ASE_OK ) {
- info.sampleRates.push_back( SAMPLE_RATES[i] );
-
- if ( !info.preferredSampleRate || ( SAMPLE_RATES[i] <= 48000 && SAMPLE_RATES[i] > info.preferredSampleRate ) )
- info.preferredSampleRate = SAMPLE_RATES[i];
- }
- }
-
- // Determine supported data types ... just check first channel and assume rest are the same.
- ASIOChannelInfo channelInfo;
- channelInfo.channel = 0;
- channelInfo.isInput = true;
- if ( info.inputChannels <= 0 ) channelInfo.isInput = false;
- result = ASIOGetChannelInfo( &channelInfo );
- if ( result != ASE_OK ) {
- drivers.removeCurrentDriver();
- errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") getting driver channel info (" << driverName << ").";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- return info;
- }
-
- info.nativeFormats = 0;
- if ( channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB )
- info.nativeFormats |= RTAUDIO_SINT16;
- else if ( channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB )
- info.nativeFormats |= RTAUDIO_SINT32;
- else if ( channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB )
- info.nativeFormats |= RTAUDIO_FLOAT32;
- else if ( channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB )
- info.nativeFormats |= RTAUDIO_FLOAT64;
- else if ( channelInfo.type == ASIOSTInt24MSB || channelInfo.type == ASIOSTInt24LSB )
- info.nativeFormats |= RTAUDIO_SINT24;
-
- if ( info.outputChannels > 0 )
- if ( getDefaultOutputDevice() == device ) info.isDefaultOutput = true;
- if ( info.inputChannels > 0 )
- if ( getDefaultInputDevice() == device ) info.isDefaultInput = true;
-
- info.probed = true;
- drivers.removeCurrentDriver();
- return info;
-}
-
-static void bufferSwitch( long index, ASIOBool /*processNow*/ )
-{
- RtApiAsio *object = (RtApiAsio *) asioCallbackInfo->object;
- object->callbackEvent( index );
-}
-
-void RtApiAsio :: saveDeviceInfo( void )
-{
- devices_.clear();
-
- unsigned int nDevices = getDeviceCount();
- devices_.resize( nDevices );
- for ( unsigned int i=0; i<nDevices; i++ )
- devices_[i] = getDeviceInfo( i );
-}
-
-bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
- unsigned int firstChannel, unsigned int sampleRate,
- RtAudioFormat format, unsigned int *bufferSize,
- RtAudio::StreamOptions *options )
-{////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
- bool isDuplexInput = mode == INPUT && stream_.mode == OUTPUT;
-
- // For ASIO, a duplex stream MUST use the same driver.
- if ( isDuplexInput && stream_.device[0] != device ) {
- errorText_ = "RtApiAsio::probeDeviceOpen: an ASIO duplex stream must use the same device for input and output!";
- return FAILURE;
- }
-
- char driverName[32];
- ASIOError result = drivers.asioGetDriverName( (int) device, driverName, 32 );
- if ( result != ASE_OK ) {
- errorStream_ << "RtApiAsio::probeDeviceOpen: unable to get driver name (" << getAsioErrorString( result ) << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Only load the driver once for duplex stream.
- if ( !isDuplexInput ) {
- // The getDeviceInfo() function will not work when a stream is open
- // because ASIO does not allow multiple devices to run at the same
- // time. Thus, we'll probe the system before opening a stream and
- // save the results for use by getDeviceInfo().
- this->saveDeviceInfo();
-
- if ( !drivers.loadDriver( driverName ) ) {
- errorStream_ << "RtApiAsio::probeDeviceOpen: unable to load driver (" << driverName << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- result = ASIOInit( &driverInfo );
- if ( result != ASE_OK ) {
- errorStream_ << "RtApiAsio::probeDeviceOpen: error (" << getAsioErrorString( result ) << ") initializing driver (" << driverName << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
- }
-
- // keep them before any "goto error", they are used for error cleanup + goto device boundary checks
- bool buffersAllocated = false;
- AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
- unsigned int nChannels;
-
-
- // Check the device channel count.
- long inputChannels, outputChannels;
- result = ASIOGetChannels( &inputChannels, &outputChannels );
- if ( result != ASE_OK ) {
- errorStream_ << "RtApiAsio::probeDeviceOpen: error (" << getAsioErrorString( result ) << ") getting channel count (" << driverName << ").";
- errorText_ = errorStream_.str();
- goto error;
- }
-
- if ( ( mode == OUTPUT && (channels+firstChannel) > (unsigned int) outputChannels) ||
- ( mode == INPUT && (channels+firstChannel) > (unsigned int) inputChannels) ) {
- errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested channel count (" << channels << ") + offset (" << firstChannel << ").";
- errorText_ = errorStream_.str();
- goto error;
- }
- stream_.nDeviceChannels[mode] = channels;
- stream_.nUserChannels[mode] = channels;
- stream_.channelOffset[mode] = firstChannel;
-
- // Verify the sample rate is supported.
- result = ASIOCanSampleRate( (ASIOSampleRate) sampleRate );
- if ( result != ASE_OK ) {
- errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested sample rate (" << sampleRate << ").";
- errorText_ = errorStream_.str();
- goto error;
- }
-
- // Get the current sample rate
- ASIOSampleRate currentRate;
- result = ASIOGetSampleRate( &currentRate );
- if ( result != ASE_OK ) {
- errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error getting sample rate.";
- errorText_ = errorStream_.str();
- goto error;
- }
-
- // Set the sample rate only if necessary
- if ( currentRate != sampleRate ) {
- result = ASIOSetSampleRate( (ASIOSampleRate) sampleRate );
- if ( result != ASE_OK ) {
- errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error setting sample rate (" << sampleRate << ").";
- errorText_ = errorStream_.str();
- goto error;
- }
- }
-
- // Determine the driver data type.
- ASIOChannelInfo channelInfo;
- channelInfo.channel = 0;
- if ( mode == OUTPUT ) channelInfo.isInput = false;
- else channelInfo.isInput = true;
- result = ASIOGetChannelInfo( &channelInfo );
- if ( result != ASE_OK ) {
- errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting data format.";
- errorText_ = errorStream_.str();
- goto error;
- }
-
- // Assuming WINDOWS host is always little-endian.
- stream_.doByteSwap[mode] = false;
- stream_.userFormat = format;
- stream_.deviceFormat[mode] = 0;
- if ( channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB ) {
- stream_.deviceFormat[mode] = RTAUDIO_SINT16;
- if ( channelInfo.type == ASIOSTInt16MSB ) stream_.doByteSwap[mode] = true;
- }
- else if ( channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB ) {
- stream_.deviceFormat[mode] = RTAUDIO_SINT32;
- if ( channelInfo.type == ASIOSTInt32MSB ) stream_.doByteSwap[mode] = true;
- }
- else if ( channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB ) {
- stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
- if ( channelInfo.type == ASIOSTFloat32MSB ) stream_.doByteSwap[mode] = true;
- }
- else if ( channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB ) {
- stream_.deviceFormat[mode] = RTAUDIO_FLOAT64;
- if ( channelInfo.type == ASIOSTFloat64MSB ) stream_.doByteSwap[mode] = true;
- }
- else if ( channelInfo.type == ASIOSTInt24MSB || channelInfo.type == ASIOSTInt24LSB ) {
- stream_.deviceFormat[mode] = RTAUDIO_SINT24;
- if ( channelInfo.type == ASIOSTInt24MSB ) stream_.doByteSwap[mode] = true;
- }
-
- if ( stream_.deviceFormat[mode] == 0 ) {
- errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") data format not supported by RtAudio.";
- errorText_ = errorStream_.str();
- goto error;
- }
-
- // Set the buffer size. For a duplex stream, this will end up
- // setting the buffer size based on the input constraints, which
- // should be ok.
- long minSize, maxSize, preferSize, granularity;
- result = ASIOGetBufferSize( &minSize, &maxSize, &preferSize, &granularity );
- if ( result != ASE_OK ) {
- errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting buffer size.";
- errorText_ = errorStream_.str();
- goto error;
- }
-
- if ( isDuplexInput ) {
- // When this is the duplex input (output was opened before), then we have to use the same
- // buffersize as the output, because it might use the preferred buffer size, which most
- // likely wasn't passed as input to this. The buffer sizes have to be identically anyway,
- // So instead of throwing an error, make them equal. The caller uses the reference
- // to the "bufferSize" param as usual to set up processing buffers.
-
- *bufferSize = stream_.bufferSize;
-
- } else {
- if ( *bufferSize == 0 ) *bufferSize = preferSize;
- else if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize;
- else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize;
- else if ( granularity == -1 ) {
- // Make sure bufferSize is a power of two.
- int log2_of_min_size = 0;
- int log2_of_max_size = 0;
-
- for ( unsigned int i = 0; i < sizeof(long) * 8; i++ ) {
- if ( minSize & ((long)1 << i) ) log2_of_min_size = i;
- if ( maxSize & ((long)1 << i) ) log2_of_max_size = i;
- }
-
- long min_delta = std::abs( (long)*bufferSize - ((long)1 << log2_of_min_size) );
- int min_delta_num = log2_of_min_size;
-
- for (int i = log2_of_min_size + 1; i <= log2_of_max_size; i++) {
- long current_delta = std::abs( (long)*bufferSize - ((long)1 << i) );
- if (current_delta < min_delta) {
- min_delta = current_delta;
- min_delta_num = i;
- }
- }
-
- *bufferSize = ( (unsigned int)1 << min_delta_num );
- if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize;
- else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize;
- }
- else if ( granularity != 0 ) {
- // Set to an even multiple of granularity, rounding up.
- *bufferSize = (*bufferSize + granularity-1) / granularity * granularity;
- }
- }
-
- /*
- // we don't use it anymore, see above!
- // Just left it here for the case...
- if ( isDuplexInput && stream_.bufferSize != *bufferSize ) {
- errorText_ = "RtApiAsio::probeDeviceOpen: input/output buffersize discrepancy!";
- goto error;
- }
- */
-
- stream_.bufferSize = *bufferSize;
- stream_.nBuffers = 2;
-
- if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;
- else stream_.userInterleaved = true;
-
- // ASIO always uses non-interleaved buffers.
- stream_.deviceInterleaved[mode] = false;
-
- // Allocate, if necessary, our AsioHandle structure for the stream.
- if ( handle == 0 ) {
- try {
- handle = new AsioHandle;
- }
- catch ( std::bad_alloc& ) {
- errorText_ = "RtApiAsio::probeDeviceOpen: error allocating AsioHandle memory.";
- goto error;
- }
- handle->bufferInfos = 0;
-
- // Create a manual-reset event.
- handle->condition = CreateEvent( NULL, // no security
- TRUE, // manual-reset
- FALSE, // non-signaled initially
- NULL ); // unnamed
- stream_.apiHandle = (void *) handle;
- }
-
- // Create the ASIO internal buffers. Since RtAudio sets up input
- // and output separately, we'll have to dispose of previously
- // created output buffers for a duplex stream.
- if ( mode == INPUT && stream_.mode == OUTPUT ) {
- ASIODisposeBuffers();
- if ( handle->bufferInfos ) free( handle->bufferInfos );
- }
-
- // Allocate, initialize, and save the bufferInfos in our stream callbackInfo structure.
- unsigned int i;
- nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1];
- handle->bufferInfos = (ASIOBufferInfo *) malloc( nChannels * sizeof(ASIOBufferInfo) );
- if ( handle->bufferInfos == NULL ) {
- errorStream_ << "RtApiAsio::probeDeviceOpen: error allocating bufferInfo memory for driver (" << driverName << ").";
- errorText_ = errorStream_.str();
- goto error;
- }
-
- ASIOBufferInfo *infos;
- infos = handle->bufferInfos;
- for ( i=0; i<stream_.nDeviceChannels[0]; i++, infos++ ) {
- infos->isInput = ASIOFalse;
- infos->channelNum = i + stream_.channelOffset[0];
- infos->buffers[0] = infos->buffers[1] = 0;
- }
- for ( i=0; i<stream_.nDeviceChannels[1]; i++, infos++ ) {
- infos->isInput = ASIOTrue;
- infos->channelNum = i + stream_.channelOffset[1];
- infos->buffers[0] = infos->buffers[1] = 0;
- }
-
- // prepare for callbacks
- stream_.sampleRate = sampleRate;
- stream_.device[mode] = device;
- stream_.mode = isDuplexInput ? DUPLEX : mode;
-
- // store this class instance before registering callbacks, that are going to use it
- asioCallbackInfo = &stream_.callbackInfo;
- stream_.callbackInfo.object = (void *) this;
-
- // Set up the ASIO callback structure and create the ASIO data buffers.
- asioCallbacks.bufferSwitch = &bufferSwitch;
- asioCallbacks.sampleRateDidChange = &sampleRateChanged;
- asioCallbacks.asioMessage = &asioMessages;
- asioCallbacks.bufferSwitchTimeInfo = NULL;
- result = ASIOCreateBuffers( handle->bufferInfos, nChannels, stream_.bufferSize, &asioCallbacks );
- if ( result != ASE_OK ) {
- // Standard method failed. This can happen with strict/misbehaving drivers that return valid buffer size ranges
- // but only accept the preferred buffer size as parameter for ASIOCreateBuffers. eg. Creatives ASIO driver
- // in that case, let's be naïve and try that instead
- *bufferSize = preferSize;
- stream_.bufferSize = *bufferSize;
- result = ASIOCreateBuffers( handle->bufferInfos, nChannels, stream_.bufferSize, &asioCallbacks );
- }
-
- if ( result != ASE_OK ) {
- errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") creating buffers.";
- errorText_ = errorStream_.str();
- goto error;
- }
- buffersAllocated = true;
- stream_.state = STREAM_STOPPED;
-
- // Set flags for buffer conversion.
- stream_.doConvertBuffer[mode] = false;
- if ( stream_.userFormat != stream_.deviceFormat[mode] )
- stream_.doConvertBuffer[mode] = true;
- if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&
- stream_.nUserChannels[mode] > 1 )
- stream_.doConvertBuffer[mode] = true;
-
- // Allocate necessary internal buffers
- unsigned long bufferBytes;
- bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
- stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );
- if ( stream_.userBuffer[mode] == NULL ) {
- errorText_ = "RtApiAsio::probeDeviceOpen: error allocating user buffer memory.";
- goto error;
- }
-
- if ( stream_.doConvertBuffer[mode] ) {
-
- bool makeBuffer = true;
- bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );
- if ( isDuplexInput && stream_.deviceBuffer ) {
- unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );
- if ( bufferBytes <= bytesOut ) makeBuffer = false;
- }
-
- if ( makeBuffer ) {
- bufferBytes *= *bufferSize;
- if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );
- stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );
- if ( stream_.deviceBuffer == NULL ) {
- errorText_ = "RtApiAsio::probeDeviceOpen: error allocating device buffer memory.";
- goto error;
- }
- }
- }
-
- // Determine device latencies
- long inputLatency, outputLatency;
- result = ASIOGetLatencies( &inputLatency, &outputLatency );
- if ( result != ASE_OK ) {
- errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting latency.";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING); // warn but don't fail
- }
- else {
- stream_.latency[0] = outputLatency;
- stream_.latency[1] = inputLatency;
- }
-
- // Setup the buffer conversion information structure. We don't use
- // buffers to do channel offsets, so we override that parameter
- // here.
- if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, 0 );
-
- return SUCCESS;
-
- error:
- if ( !isDuplexInput ) {
- // the cleanup for error in the duplex input, is done by RtApi::openStream
- // So we clean up for single channel only
-
- if ( buffersAllocated )
- ASIODisposeBuffers();
-
- drivers.removeCurrentDriver();
-
- if ( handle ) {
- CloseHandle( handle->condition );
- if ( handle->bufferInfos )
- free( handle->bufferInfos );
-
- delete handle;
- stream_.apiHandle = 0;
- }
-
-
- if ( stream_.userBuffer[mode] ) {
- free( stream_.userBuffer[mode] );
- stream_.userBuffer[mode] = 0;
- }
-
- if ( stream_.deviceBuffer ) {
- free( stream_.deviceBuffer );
- stream_.deviceBuffer = 0;
- }
- }
-
- return FAILURE;
-}////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-void RtApiAsio :: closeStream()
-{
- if ( stream_.state == STREAM_CLOSED ) {
- errorText_ = "RtApiAsio::closeStream(): no open stream to close!";
- error( RtAudioError::WARNING );
- return;
- }
-
- if ( stream_.state == STREAM_RUNNING ) {
- stream_.state = STREAM_STOPPED;
- ASIOStop();
- }
- ASIODisposeBuffers();
- drivers.removeCurrentDriver();
-
- AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
- if ( handle ) {
- CloseHandle( handle->condition );
- if ( handle->bufferInfos )
- free( handle->bufferInfos );
- delete handle;
- stream_.apiHandle = 0;
- }
-
- for ( int i=0; i<2; i++ ) {
- if ( stream_.userBuffer[i] ) {
- free( stream_.userBuffer[i] );
- stream_.userBuffer[i] = 0;
- }
- }
-
- if ( stream_.deviceBuffer ) {
- free( stream_.deviceBuffer );
- stream_.deviceBuffer = 0;
- }
-
- stream_.mode = UNINITIALIZED;
- stream_.state = STREAM_CLOSED;
-}
-
-bool stopThreadCalled = false;
-
-void RtApiAsio :: startStream()
-{
- verifyStream();
- if ( stream_.state == STREAM_RUNNING ) {
- errorText_ = "RtApiAsio::startStream(): the stream is already running!";
- error( RtAudioError::WARNING );
- return;
- }
-
- AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
- ASIOError result = ASIOStart();
- if ( result != ASE_OK ) {
- errorStream_ << "RtApiAsio::startStream: error (" << getAsioErrorString( result ) << ") starting device.";
- errorText_ = errorStream_.str();
- goto unlock;
- }
-
- handle->drainCounter = 0;
- handle->internalDrain = false;
- ResetEvent( handle->condition );
- stream_.state = STREAM_RUNNING;
- asioXRun = false;
-
- unlock:
- stopThreadCalled = false;
-
- if ( result == ASE_OK ) return;
- error( RtAudioError::SYSTEM_ERROR );
-}
-
-void RtApiAsio :: stopStream()
-{
- verifyStream();
- if ( stream_.state == STREAM_STOPPED ) {
- errorText_ = "RtApiAsio::stopStream(): the stream is already stopped!";
- error( RtAudioError::WARNING );
- return;
- }
-
- AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
- if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
- if ( handle->drainCounter == 0 ) {
- handle->drainCounter = 2;
- WaitForSingleObject( handle->condition, INFINITE ); // block until signaled
- }
- }
-
- stream_.state = STREAM_STOPPED;
-
- ASIOError result = ASIOStop();
- if ( result != ASE_OK ) {
- errorStream_ << "RtApiAsio::stopStream: error (" << getAsioErrorString( result ) << ") stopping device.";
- errorText_ = errorStream_.str();
- }
-
- if ( result == ASE_OK ) return;
- error( RtAudioError::SYSTEM_ERROR );
-}
-
-void RtApiAsio :: abortStream()
-{
- verifyStream();
- if ( stream_.state == STREAM_STOPPED ) {
- errorText_ = "RtApiAsio::abortStream(): the stream is already stopped!";
- error( RtAudioError::WARNING );
- return;
- }
-
- // The following lines were commented-out because some behavior was
- // noted where the device buffers need to be zeroed to avoid
- // continuing sound, even when the device buffers are completely
- // disposed. So now, calling abort is the same as calling stop.
- // AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
- // handle->drainCounter = 2;
- stopStream();
-}
-
-// This function will be called by a spawned thread when the user
-// callback function signals that the stream should be stopped or
-// aborted. It is necessary to handle it this way because the
-// callbackEvent() function must return before the ASIOStop()
-// function will return.
-static unsigned __stdcall asioStopStream( void *ptr )
-{
- CallbackInfo *info = (CallbackInfo *) ptr;
- RtApiAsio *object = (RtApiAsio *) info->object;
-
- object->stopStream();
- _endthreadex( 0 );
- return 0;
-}
-
-bool RtApiAsio :: callbackEvent( long bufferIndex )
-{
- if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) return SUCCESS;
- if ( stream_.state == STREAM_CLOSED ) {
- errorText_ = "RtApiAsio::callbackEvent(): the stream is closed ... this shouldn't happen!";
- error( RtAudioError::WARNING );
- return FAILURE;
- }
-
- CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
- AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
-
- // Check if we were draining the stream and signal if finished.
- if ( handle->drainCounter > 3 ) {
-
- stream_.state = STREAM_STOPPING;
- if ( handle->internalDrain == false )
- SetEvent( handle->condition );
- else { // spawn a thread to stop the stream
- unsigned threadId;
- stream_.callbackInfo.thread = _beginthreadex( NULL, 0, &asioStopStream,
- &stream_.callbackInfo, 0, &threadId );
- }
- return SUCCESS;
- }
-
- // Invoke user callback to get fresh output data UNLESS we are
- // draining stream.
- if ( handle->drainCounter == 0 ) {
- RtAudioCallback callback = (RtAudioCallback) info->callback;
- double streamTime = getStreamTime();
- RtAudioStreamStatus status = 0;
- if ( stream_.mode != INPUT && asioXRun == true ) {
- status |= RTAUDIO_OUTPUT_UNDERFLOW;
- asioXRun = false;
- }
- if ( stream_.mode != OUTPUT && asioXRun == true ) {
- status |= RTAUDIO_INPUT_OVERFLOW;
- asioXRun = false;
- }
- int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1],
- stream_.bufferSize, streamTime, status, info->userData );
- if ( cbReturnValue == 2 ) {
- stream_.state = STREAM_STOPPING;
- handle->drainCounter = 2;
- unsigned threadId;
- stream_.callbackInfo.thread = _beginthreadex( NULL, 0, &asioStopStream,
- &stream_.callbackInfo, 0, &threadId );
- return SUCCESS;
- }
- else if ( cbReturnValue == 1 ) {
- handle->drainCounter = 1;
- handle->internalDrain = true;
- }
- }
-
- unsigned int nChannels, bufferBytes, i, j;
- nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1];
- if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
-
- bufferBytes = stream_.bufferSize * formatBytes( stream_.deviceFormat[0] );
-
- if ( handle->drainCounter > 1 ) { // write zeros to the output stream
-
- for ( i=0, j=0; i<nChannels; i++ ) {
- if ( handle->bufferInfos[i].isInput != ASIOTrue )
- memset( handle->bufferInfos[i].buffers[bufferIndex], 0, bufferBytes );
- }
-
- }
- else if ( stream_.doConvertBuffer[0] ) {
-
- convertBuffer( stream_.deviceBuffer, stream_.userBuffer[0], stream_.convertInfo[0] );
- if ( stream_.doByteSwap[0] )
- byteSwapBuffer( stream_.deviceBuffer,
- stream_.bufferSize * stream_.nDeviceChannels[0],
- stream_.deviceFormat[0] );
-
- for ( i=0, j=0; i<nChannels; i++ ) {
- if ( handle->bufferInfos[i].isInput != ASIOTrue )
- memcpy( handle->bufferInfos[i].buffers[bufferIndex],
- &stream_.deviceBuffer[j++*bufferBytes], bufferBytes );
- }
-
- }
- else {
-
- if ( stream_.doByteSwap[0] )
- byteSwapBuffer( stream_.userBuffer[0],
- stream_.bufferSize * stream_.nUserChannels[0],
- stream_.userFormat );
-
- for ( i=0, j=0; i<nChannels; i++ ) {
- if ( handle->bufferInfos[i].isInput != ASIOTrue )
- memcpy( handle->bufferInfos[i].buffers[bufferIndex],
- &stream_.userBuffer[0][bufferBytes*j++], bufferBytes );
- }
-
- }
- }
-
- // Don't bother draining input
- if ( handle->drainCounter ) {
- handle->drainCounter++;
- goto unlock;
- }
-
- if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
-
- bufferBytes = stream_.bufferSize * formatBytes(stream_.deviceFormat[1]);
-
- if (stream_.doConvertBuffer[1]) {
-
- // Always interleave ASIO input data.
- for ( i=0, j=0; i<nChannels; i++ ) {
- if ( handle->bufferInfos[i].isInput == ASIOTrue )
- memcpy( &stream_.deviceBuffer[j++*bufferBytes],
- handle->bufferInfos[i].buffers[bufferIndex],
- bufferBytes );
- }
-
- if ( stream_.doByteSwap[1] )
- byteSwapBuffer( stream_.deviceBuffer,
- stream_.bufferSize * stream_.nDeviceChannels[1],
- stream_.deviceFormat[1] );
- convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );
-
- }
- else {
- for ( i=0, j=0; i<nChannels; i++ ) {
- if ( handle->bufferInfos[i].isInput == ASIOTrue ) {
- memcpy( &stream_.userBuffer[1][bufferBytes*j++],
- handle->bufferInfos[i].buffers[bufferIndex],
- bufferBytes );
- }
- }
-
- if ( stream_.doByteSwap[1] )
- byteSwapBuffer( stream_.userBuffer[1],
- stream_.bufferSize * stream_.nUserChannels[1],
- stream_.userFormat );
- }
- }
-
- unlock:
- // The following call was suggested by Malte Clasen. While the API
- // documentation indicates it should not be required, some device
- // drivers apparently do not function correctly without it.
- ASIOOutputReady();
-
- RtApi::tickStreamTime();
- return SUCCESS;
-}
-
-static void sampleRateChanged( ASIOSampleRate sRate )
-{
- // The ASIO documentation says that this usually only happens during
- // external sync. Audio processing is not stopped by the driver,
- // actual sample rate might not have even changed, maybe only the
- // sample rate status of an AES/EBU or S/PDIF digital input at the
- // audio device.
-
- RtApi *object = (RtApi *) asioCallbackInfo->object;
- try {
- object->stopStream();
- }
- catch ( RtAudioError &exception ) {
- std::cerr << "\nRtApiAsio: sampleRateChanged() error (" << exception.getMessage() << ")!\n" << std::endl;
- return;
- }
-
- std::cerr << "\nRtApiAsio: driver reports sample rate changed to " << sRate << " ... stream stopped!!!\n" << std::endl;
-}
-
-static long asioMessages( long selector, long value, void* /*message*/, double* /*opt*/ )
-{
- long ret = 0;
-
- switch( selector ) {
- case kAsioSelectorSupported:
- if ( value == kAsioResetRequest
- || value == kAsioEngineVersion
- || value == kAsioResyncRequest
- || value == kAsioLatenciesChanged
- // The following three were added for ASIO 2.0, you don't
- // necessarily have to support them.
- || value == kAsioSupportsTimeInfo
- || value == kAsioSupportsTimeCode
- || value == kAsioSupportsInputMonitor)
- ret = 1L;
- break;
- case kAsioResetRequest:
- // Defer the task and perform the reset of the driver during the
- // next "safe" situation. You cannot reset the driver right now,
- // as this code is called from the driver. Reset the driver is
- // done by completely destruct is. I.e. ASIOStop(),
- // ASIODisposeBuffers(), Destruction Afterwards you initialize the
- // driver again.
- std::cerr << "\nRtApiAsio: driver reset requested!!!" << std::endl;
- ret = 1L;
- break;
- case kAsioResyncRequest:
- // This informs the application that the driver encountered some
- // non-fatal data loss. It is used for synchronization purposes
- // of different media. Added mainly to work around the Win16Mutex
- // problems in Windows 95/98 with the Windows Multimedia system,
- // which could lose data because the Mutex was held too long by
- // another thread. However a driver can issue it in other
- // situations, too.
- // std::cerr << "\nRtApiAsio: driver resync requested!!!" << std::endl;
- asioXRun = true;
- ret = 1L;
- break;
- case kAsioLatenciesChanged:
- // This will inform the host application that the drivers were
- // latencies changed. Beware, it this does not mean that the
- // buffer sizes have changed! You might need to update internal
- // delay data.
- std::cerr << "\nRtApiAsio: driver latency may have changed!!!" << std::endl;
- ret = 1L;
- break;
- case kAsioEngineVersion:
- // Return the supported ASIO version of the host application. If
- // a host application does not implement this selector, ASIO 1.0
- // is assumed by the driver.
- ret = 2L;
- break;
- case kAsioSupportsTimeInfo:
- // Informs the driver whether the
- // asioCallbacks.bufferSwitchTimeInfo() callback is supported.
- // For compatibility with ASIO 1.0 drivers the host application
- // should always support the "old" bufferSwitch method, too.
- ret = 0;
- break;
- case kAsioSupportsTimeCode:
- // Informs the driver whether application is interested in time
- // code info. If an application does not need to know about time
- // code, the driver has less work to do.
- ret = 0;
- break;
- }
- return ret;
-}
-
-static const char* getAsioErrorString( ASIOError result )
-{
- struct Messages
- {
- ASIOError value;
- const char*message;
- };
-
- static const Messages m[] =
- {
- { ASE_NotPresent, "Hardware input or output is not present or available." },
- { ASE_HWMalfunction, "Hardware is malfunctioning." },
- { ASE_InvalidParameter, "Invalid input parameter." },
- { ASE_InvalidMode, "Invalid mode." },
- { ASE_SPNotAdvancing, "Sample position not advancing." },
- { ASE_NoClock, "Sample clock or rate cannot be determined or is not present." },
- { ASE_NoMemory, "Not enough memory to complete the request." }
- };
-
- for ( unsigned int i = 0; i < sizeof(m)/sizeof(m[0]); ++i )
- if ( m[i].value == result ) return m[i].message;
-
- return "Unknown error.";
-}
-
-//******************** End of __WINDOWS_ASIO__ *********************//
-#endif
-
-
-#if defined(__WINDOWS_WASAPI__) // Windows WASAPI API
-
-// Authored by Marcus Tomlinson <themarcustomlinson@gmail.com>, April 2014
-// - Introduces support for the Windows WASAPI API
-// - Aims to deliver bit streams to and from hardware at the lowest possible latency, via the absolute minimum buffer sizes required
-// - Provides flexible stream configuration to an otherwise strict and inflexible WASAPI interface
-// - Includes automatic internal conversion of sample rate and buffer size between hardware and the user
-
-#ifndef INITGUID
- #define INITGUID
-#endif
-#include <audioclient.h>
-#include <avrt.h>
-#include <mmdeviceapi.h>
-#include <functiondiscoverykeys_devpkey.h>
-
-//=============================================================================
-
-#define SAFE_RELEASE( objectPtr )\
-if ( objectPtr )\
-{\
- objectPtr->Release();\
- objectPtr = NULL;\
-}
-
-typedef HANDLE ( __stdcall *TAvSetMmThreadCharacteristicsPtr )( LPCWSTR TaskName, LPDWORD TaskIndex );
-
-//-----------------------------------------------------------------------------
-
-// WASAPI dictates stream sample rate, format, channel count, and in some cases, buffer size.
-// Therefore we must perform all necessary conversions to user buffers in order to satisfy these
-// requirements. WasapiBuffer ring buffers are used between HwIn->UserIn and UserOut->HwOut to
-// provide intermediate storage for read / write synchronization.
-class WasapiBuffer
-{
-public:
- WasapiBuffer()
- : buffer_( NULL ),
- bufferSize_( 0 ),
- inIndex_( 0 ),
- outIndex_( 0 ) {}
-
- ~WasapiBuffer() {
- free( buffer_ );
- }
-
- // sets the length of the internal ring buffer
- void setBufferSize( unsigned int bufferSize, unsigned int formatBytes ) {
- free( buffer_ );
-
- buffer_ = ( char* ) calloc( bufferSize, formatBytes );
-
- bufferSize_ = bufferSize;
- inIndex_ = 0;
- outIndex_ = 0;
- }
-
- // attempt to push a buffer into the ring buffer at the current "in" index
- bool pushBuffer( char* buffer, unsigned int bufferSize, RtAudioFormat format )
- {
- if ( !buffer || // incoming buffer is NULL
- bufferSize == 0 || // incoming buffer has no data
- bufferSize > bufferSize_ ) // incoming buffer too large
- {
- return false;
- }
-
- unsigned int relOutIndex = outIndex_;
- unsigned int inIndexEnd = inIndex_ + bufferSize;
- if ( relOutIndex < inIndex_ && inIndexEnd >= bufferSize_ ) {
- relOutIndex += bufferSize_;
- }
-
- // "in" index can end on the "out" index but cannot begin at it
- if ( inIndex_ <= relOutIndex && inIndexEnd > relOutIndex ) {
- return false; // not enough space between "in" index and "out" index
- }
-
- // copy buffer from external to internal
- int fromZeroSize = inIndex_ + bufferSize - bufferSize_;
- fromZeroSize = fromZeroSize < 0 ? 0 : fromZeroSize;
- int fromInSize = bufferSize - fromZeroSize;
-
- switch( format )
- {
- case RTAUDIO_SINT8:
- memcpy( &( ( char* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( char ) );
- memcpy( buffer_, &( ( char* ) buffer )[fromInSize], fromZeroSize * sizeof( char ) );
- break;
- case RTAUDIO_SINT16:
- memcpy( &( ( short* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( short ) );
- memcpy( buffer_, &( ( short* ) buffer )[fromInSize], fromZeroSize * sizeof( short ) );
- break;
- case RTAUDIO_SINT24:
- memcpy( &( ( S24* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( S24 ) );
- memcpy( buffer_, &( ( S24* ) buffer )[fromInSize], fromZeroSize * sizeof( S24 ) );
- break;
- case RTAUDIO_SINT32:
- memcpy( &( ( int* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( int ) );
- memcpy( buffer_, &( ( int* ) buffer )[fromInSize], fromZeroSize * sizeof( int ) );
- break;
- case RTAUDIO_FLOAT32:
- memcpy( &( ( float* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( float ) );
- memcpy( buffer_, &( ( float* ) buffer )[fromInSize], fromZeroSize * sizeof( float ) );
- break;
- case RTAUDIO_FLOAT64:
- memcpy( &( ( double* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( double ) );
- memcpy( buffer_, &( ( double* ) buffer )[fromInSize], fromZeroSize * sizeof( double ) );
- break;
- }
-
- // update "in" index
- inIndex_ += bufferSize;
- inIndex_ %= bufferSize_;
-
- return true;
- }
-
- // attempt to pull a buffer from the ring buffer from the current "out" index
- bool pullBuffer( char* buffer, unsigned int bufferSize, RtAudioFormat format )
- {
- if ( !buffer || // incoming buffer is NULL
- bufferSize == 0 || // incoming buffer has no data
- bufferSize > bufferSize_ ) // incoming buffer too large
- {
- return false;
- }
-
- unsigned int relInIndex = inIndex_;
- unsigned int outIndexEnd = outIndex_ + bufferSize;
- if ( relInIndex < outIndex_ && outIndexEnd >= bufferSize_ ) {
- relInIndex += bufferSize_;
- }
-
- // "out" index can begin at and end on the "in" index
- if ( outIndex_ < relInIndex && outIndexEnd > relInIndex ) {
- return false; // not enough space between "out" index and "in" index
- }
-
- // copy buffer from internal to external
- int fromZeroSize = outIndex_ + bufferSize - bufferSize_;
- fromZeroSize = fromZeroSize < 0 ? 0 : fromZeroSize;
- int fromOutSize = bufferSize - fromZeroSize;
-
- switch( format )
- {
- case RTAUDIO_SINT8:
- memcpy( buffer, &( ( char* ) buffer_ )[outIndex_], fromOutSize * sizeof( char ) );
- memcpy( &( ( char* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( char ) );
- break;
- case RTAUDIO_SINT16:
- memcpy( buffer, &( ( short* ) buffer_ )[outIndex_], fromOutSize * sizeof( short ) );
- memcpy( &( ( short* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( short ) );
- break;
- case RTAUDIO_SINT24:
- memcpy( buffer, &( ( S24* ) buffer_ )[outIndex_], fromOutSize * sizeof( S24 ) );
- memcpy( &( ( S24* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( S24 ) );
- break;
- case RTAUDIO_SINT32:
- memcpy( buffer, &( ( int* ) buffer_ )[outIndex_], fromOutSize * sizeof( int ) );
- memcpy( &( ( int* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( int ) );
- break;
- case RTAUDIO_FLOAT32:
- memcpy( buffer, &( ( float* ) buffer_ )[outIndex_], fromOutSize * sizeof( float ) );
- memcpy( &( ( float* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( float ) );
- break;
- case RTAUDIO_FLOAT64:
- memcpy( buffer, &( ( double* ) buffer_ )[outIndex_], fromOutSize * sizeof( double ) );
- memcpy( &( ( double* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( double ) );
- break;
- }
-
- // update "out" index
- outIndex_ += bufferSize;
- outIndex_ %= bufferSize_;
-
- return true;
- }
-
-private:
- char* buffer_;
- unsigned int bufferSize_;
- unsigned int inIndex_;
- unsigned int outIndex_;
-};
-
-//-----------------------------------------------------------------------------
-
-// In order to satisfy WASAPI's buffer requirements, we need a means of converting sample rate
-// between HW and the user. The convertBufferWasapi function is used to perform this conversion
-// between HwIn->UserIn and UserOut->HwOut during the stream callback loop.
-// This sample rate converter favors speed over quality, and works best with conversions between
-// one rate and its multiple.
-void convertBufferWasapi( char* outBuffer,
- const char* inBuffer,
- const unsigned int& channelCount,
- const unsigned int& inSampleRate,
- const unsigned int& outSampleRate,
- const unsigned int& inSampleCount,
- unsigned int& outSampleCount,
- const RtAudioFormat& format )
-{
- // calculate the new outSampleCount and relative sampleStep
- float sampleRatio = ( float ) outSampleRate / inSampleRate;
- float sampleStep = 1.0f / sampleRatio;
- float inSampleFraction = 0.0f;
-
- outSampleCount = ( unsigned int ) roundf( inSampleCount * sampleRatio );
-
- // frame-by-frame, copy each relative input sample into it's corresponding output sample
- for ( unsigned int outSample = 0; outSample < outSampleCount; outSample++ )
- {
- unsigned int inSample = ( unsigned int ) inSampleFraction;
-
- switch ( format )
- {
- case RTAUDIO_SINT8:
- memcpy( &( ( char* ) outBuffer )[ outSample * channelCount ], &( ( char* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( char ) );
- break;
- case RTAUDIO_SINT16:
- memcpy( &( ( short* ) outBuffer )[ outSample * channelCount ], &( ( short* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( short ) );
- break;
- case RTAUDIO_SINT24:
- memcpy( &( ( S24* ) outBuffer )[ outSample * channelCount ], &( ( S24* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( S24 ) );
- break;
- case RTAUDIO_SINT32:
- memcpy( &( ( int* ) outBuffer )[ outSample * channelCount ], &( ( int* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( int ) );
- break;
- case RTAUDIO_FLOAT32:
- memcpy( &( ( float* ) outBuffer )[ outSample * channelCount ], &( ( float* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( float ) );
- break;
- case RTAUDIO_FLOAT64:
- memcpy( &( ( double* ) outBuffer )[ outSample * channelCount ], &( ( double* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( double ) );
- break;
- }
-
- // jump to next in sample
- inSampleFraction += sampleStep;
- }
-}
-
-//-----------------------------------------------------------------------------
-
-// A structure to hold various information related to the WASAPI implementation.
-struct WasapiHandle
-{
- IAudioClient* captureAudioClient;
- IAudioClient* renderAudioClient;
- IAudioCaptureClient* captureClient;
- IAudioRenderClient* renderClient;
- HANDLE captureEvent;
- HANDLE renderEvent;
-
- WasapiHandle()
- : captureAudioClient( NULL ),
- renderAudioClient( NULL ),
- captureClient( NULL ),
- renderClient( NULL ),
- captureEvent( NULL ),
- renderEvent( NULL ) {}
-};
-
-//=============================================================================
-
-RtApiWasapi::RtApiWasapi()
- : coInitialized_( false ), deviceEnumerator_( NULL )
-{
- // WASAPI can run either apartment or multi-threaded
- HRESULT hr = CoInitialize( NULL );
- if ( !FAILED( hr ) )
- coInitialized_ = true;
-
- // Instantiate device enumerator
- hr = CoCreateInstance( __uuidof( MMDeviceEnumerator ), NULL,
- CLSCTX_ALL, __uuidof( IMMDeviceEnumerator ),
- ( void** ) &deviceEnumerator_ );
-
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::RtApiWasapi: Unable to instantiate device enumerator";
- error( RtAudioError::DRIVER_ERROR );
- }
-}
-
-//-----------------------------------------------------------------------------
-
-RtApiWasapi::~RtApiWasapi()
-{
- if ( stream_.state != STREAM_CLOSED )
- closeStream();
-
- SAFE_RELEASE( deviceEnumerator_ );
-
- // If this object previously called CoInitialize()
- if ( coInitialized_ )
- CoUninitialize();
-}
-
-//=============================================================================
-
-unsigned int RtApiWasapi::getDeviceCount( void )
-{
- unsigned int captureDeviceCount = 0;
- unsigned int renderDeviceCount = 0;
-
- IMMDeviceCollection* captureDevices = NULL;
- IMMDeviceCollection* renderDevices = NULL;
-
- // Count capture devices
- errorText_.clear();
- HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve capture device collection.";
- goto Exit;
- }
-
- hr = captureDevices->GetCount( &captureDeviceCount );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve capture device count.";
- goto Exit;
- }
-
- // Count render devices
- hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve render device collection.";
- goto Exit;
- }
-
- hr = renderDevices->GetCount( &renderDeviceCount );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve render device count.";
- goto Exit;
- }
-
-Exit:
- // release all references
- SAFE_RELEASE( captureDevices );
- SAFE_RELEASE( renderDevices );
-
- if ( errorText_.empty() )
- return captureDeviceCount + renderDeviceCount;
-
- error( RtAudioError::DRIVER_ERROR );
- return 0;
-}
-
-//-----------------------------------------------------------------------------
-
-RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device )
-{
- RtAudio::DeviceInfo info;
- unsigned int captureDeviceCount = 0;
- unsigned int renderDeviceCount = 0;
- std::string defaultDeviceName;
- bool isCaptureDevice = false;
-
- PROPVARIANT deviceNameProp;
- PROPVARIANT defaultDeviceNameProp;
-
- IMMDeviceCollection* captureDevices = NULL;
- IMMDeviceCollection* renderDevices = NULL;
- IMMDevice* devicePtr = NULL;
- IMMDevice* defaultDevicePtr = NULL;
- IAudioClient* audioClient = NULL;
- IPropertyStore* devicePropStore = NULL;
- IPropertyStore* defaultDevicePropStore = NULL;
-
- WAVEFORMATEX* deviceFormat = NULL;
- WAVEFORMATEX* closestMatchFormat = NULL;
-
- // probed
- info.probed = false;
-
- // Count capture devices
- errorText_.clear();
- RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR;
- HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device collection.";
- goto Exit;
- }
-
- hr = captureDevices->GetCount( &captureDeviceCount );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device count.";
- goto Exit;
- }
-
- // Count render devices
- hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device collection.";
- goto Exit;
- }
-
- hr = renderDevices->GetCount( &renderDeviceCount );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device count.";
- goto Exit;
- }
-
- // validate device index
- if ( device >= captureDeviceCount + renderDeviceCount ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Invalid device index.";
- errorType = RtAudioError::INVALID_USE;
- goto Exit;
- }
-
- // determine whether index falls within capture or render devices
- if ( device >= renderDeviceCount ) {
- hr = captureDevices->Item( device - renderDeviceCount, &devicePtr );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device handle.";
- goto Exit;
- }
- isCaptureDevice = true;
- }
- else {
- hr = renderDevices->Item( device, &devicePtr );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device handle.";
- goto Exit;
- }
- isCaptureDevice = false;
- }
-
- // get default device name
- if ( isCaptureDevice ) {
- hr = deviceEnumerator_->GetDefaultAudioEndpoint( eCapture, eConsole, &defaultDevicePtr );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default capture device handle.";
- goto Exit;
- }
- }
- else {
- hr = deviceEnumerator_->GetDefaultAudioEndpoint( eRender, eConsole, &defaultDevicePtr );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default render device handle.";
- goto Exit;
- }
- }
-
- hr = defaultDevicePtr->OpenPropertyStore( STGM_READ, &defaultDevicePropStore );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to open default device property store.";
- goto Exit;
- }
- PropVariantInit( &defaultDeviceNameProp );
-
- hr = defaultDevicePropStore->GetValue( PKEY_Device_FriendlyName, &defaultDeviceNameProp );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default device property: PKEY_Device_FriendlyName.";
- goto Exit;
- }
-
- defaultDeviceName = convertCharPointerToStdString(defaultDeviceNameProp.pwszVal);
-
- // name
- hr = devicePtr->OpenPropertyStore( STGM_READ, &devicePropStore );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to open device property store.";
- goto Exit;
- }
-
- PropVariantInit( &deviceNameProp );
-
- hr = devicePropStore->GetValue( PKEY_Device_FriendlyName, &deviceNameProp );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device property: PKEY_Device_FriendlyName.";
- goto Exit;
- }
-
- info.name =convertCharPointerToStdString(deviceNameProp.pwszVal);
-
- // is default
- if ( isCaptureDevice ) {
- info.isDefaultInput = info.name == defaultDeviceName;
- info.isDefaultOutput = false;
- }
- else {
- info.isDefaultInput = false;
- info.isDefaultOutput = info.name == defaultDeviceName;
- }
-
- // channel count
- hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL, NULL, ( void** ) &audioClient );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device audio client.";
- goto Exit;
- }
-
- hr = audioClient->GetMixFormat( &deviceFormat );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device mix format.";
- goto Exit;
- }
-
- if ( isCaptureDevice ) {
- info.inputChannels = deviceFormat->nChannels;
- info.outputChannels = 0;
- info.duplexChannels = 0;
- }
- else {
- info.inputChannels = 0;
- info.outputChannels = deviceFormat->nChannels;
- info.duplexChannels = 0;
- }
-
- // sample rates
- info.sampleRates.clear();
-
- // allow support for all sample rates as we have a built-in sample rate converter
- for ( unsigned int i = 0; i < MAX_SAMPLE_RATES; i++ ) {
- info.sampleRates.push_back( SAMPLE_RATES[i] );
- }
- info.preferredSampleRate = deviceFormat->nSamplesPerSec;
-
- // native format
- info.nativeFormats = 0;
-
- if ( deviceFormat->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
- ( deviceFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
- ( ( WAVEFORMATEXTENSIBLE* ) deviceFormat )->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT ) )
- {
- if ( deviceFormat->wBitsPerSample == 32 ) {
- info.nativeFormats |= RTAUDIO_FLOAT32;
- }
- else if ( deviceFormat->wBitsPerSample == 64 ) {
- info.nativeFormats |= RTAUDIO_FLOAT64;
- }
- }
- else if ( deviceFormat->wFormatTag == WAVE_FORMAT_PCM ||
- ( deviceFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
- ( ( WAVEFORMATEXTENSIBLE* ) deviceFormat )->SubFormat == KSDATAFORMAT_SUBTYPE_PCM ) )
- {
- if ( deviceFormat->wBitsPerSample == 8 ) {
- info.nativeFormats |= RTAUDIO_SINT8;
- }
- else if ( deviceFormat->wBitsPerSample == 16 ) {
- info.nativeFormats |= RTAUDIO_SINT16;
- }
- else if ( deviceFormat->wBitsPerSample == 24 ) {
- info.nativeFormats |= RTAUDIO_SINT24;
- }
- else if ( deviceFormat->wBitsPerSample == 32 ) {
- info.nativeFormats |= RTAUDIO_SINT32;
- }
- }
-
- // probed
- info.probed = true;
-
-Exit:
- // release all references
- PropVariantClear( &deviceNameProp );
- PropVariantClear( &defaultDeviceNameProp );
-
- SAFE_RELEASE( captureDevices );
- SAFE_RELEASE( renderDevices );
- SAFE_RELEASE( devicePtr );
- SAFE_RELEASE( defaultDevicePtr );
- SAFE_RELEASE( audioClient );
- SAFE_RELEASE( devicePropStore );
- SAFE_RELEASE( defaultDevicePropStore );
-
- CoTaskMemFree( deviceFormat );
- CoTaskMemFree( closestMatchFormat );
-
- if ( !errorText_.empty() )
- error( errorType );
- return info;
-}
-
-//-----------------------------------------------------------------------------
-
-unsigned int RtApiWasapi::getDefaultOutputDevice( void )
-{
- for ( unsigned int i = 0; i < getDeviceCount(); i++ ) {
- if ( getDeviceInfo( i ).isDefaultOutput ) {
- return i;
- }
- }
-
- return 0;
-}
-
-//-----------------------------------------------------------------------------
-
-unsigned int RtApiWasapi::getDefaultInputDevice( void )
-{
- for ( unsigned int i = 0; i < getDeviceCount(); i++ ) {
- if ( getDeviceInfo( i ).isDefaultInput ) {
- return i;
- }
- }
-
- return 0;
-}
-
-//-----------------------------------------------------------------------------
-
-void RtApiWasapi::closeStream( void )
-{
- if ( stream_.state == STREAM_CLOSED ) {
- errorText_ = "RtApiWasapi::closeStream: No open stream to close.";
- error( RtAudioError::WARNING );
- return;
- }
-
- if ( stream_.state != STREAM_STOPPED )
- stopStream();
-
- // clean up stream memory
- SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient )
- SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient )
-
- SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->captureClient )
- SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->renderClient )
-
- if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent )
- CloseHandle( ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent );
-
- if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent )
- CloseHandle( ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent );
-
- delete ( WasapiHandle* ) stream_.apiHandle;
- stream_.apiHandle = NULL;
-
- for ( int i = 0; i < 2; i++ ) {
- if ( stream_.userBuffer[i] ) {
- free( stream_.userBuffer[i] );
- stream_.userBuffer[i] = 0;
- }
- }
-
- if ( stream_.deviceBuffer ) {
- free( stream_.deviceBuffer );
- stream_.deviceBuffer = 0;
- }
-
- // update stream state
- stream_.state = STREAM_CLOSED;
-}
-
-//-----------------------------------------------------------------------------
-
-void RtApiWasapi::startStream( void )
-{
- verifyStream();
-
- if ( stream_.state == STREAM_RUNNING ) {
- errorText_ = "RtApiWasapi::startStream: The stream is already running.";
- error( RtAudioError::WARNING );
- return;
- }
-
- // update stream state
- stream_.state = STREAM_RUNNING;
-
- // create WASAPI stream thread
- stream_.callbackInfo.thread = ( ThreadHandle ) CreateThread( NULL, 0, runWasapiThread, this, CREATE_SUSPENDED, NULL );
-
- if ( !stream_.callbackInfo.thread ) {
- errorText_ = "RtApiWasapi::startStream: Unable to instantiate callback thread.";
- error( RtAudioError::THREAD_ERROR );
- }
- else {
- SetThreadPriority( ( void* ) stream_.callbackInfo.thread, stream_.callbackInfo.priority );
- ResumeThread( ( void* ) stream_.callbackInfo.thread );
- }
-}
-
-//-----------------------------------------------------------------------------
-
-void RtApiWasapi::stopStream( void )
-{
- verifyStream();
-
- if ( stream_.state == STREAM_STOPPED ) {
- errorText_ = "RtApiWasapi::stopStream: The stream is already stopped.";
- error( RtAudioError::WARNING );
- return;
- }
-
- // inform stream thread by setting stream state to STREAM_STOPPING
- stream_.state = STREAM_STOPPING;
-
- // wait until stream thread is stopped
- while( stream_.state != STREAM_STOPPED ) {
- Sleep( 1 );
- }
-
- // Wait for the last buffer to play before stopping.
- Sleep( 1000 * stream_.bufferSize / stream_.sampleRate );
-
- // stop capture client if applicable
- if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient ) {
- HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient->Stop();
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::stopStream: Unable to stop capture stream.";
- error( RtAudioError::DRIVER_ERROR );
- return;
- }
- }
-
- // stop render client if applicable
- if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient ) {
- HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient->Stop();
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::stopStream: Unable to stop render stream.";
- error( RtAudioError::DRIVER_ERROR );
- return;
- }
- }
-
- // close thread handle
- if ( stream_.callbackInfo.thread && !CloseHandle( ( void* ) stream_.callbackInfo.thread ) ) {
- errorText_ = "RtApiWasapi::stopStream: Unable to close callback thread.";
- error( RtAudioError::THREAD_ERROR );
- return;
- }
-
- stream_.callbackInfo.thread = (ThreadHandle) NULL;
-}
-
-//-----------------------------------------------------------------------------
-
-void RtApiWasapi::abortStream( void )
-{
- verifyStream();
-
- if ( stream_.state == STREAM_STOPPED ) {
- errorText_ = "RtApiWasapi::abortStream: The stream is already stopped.";
- error( RtAudioError::WARNING );
- return;
- }
-
- // inform stream thread by setting stream state to STREAM_STOPPING
- stream_.state = STREAM_STOPPING;
-
- // wait until stream thread is stopped
- while ( stream_.state != STREAM_STOPPED ) {
- Sleep( 1 );
- }
-
- // stop capture client if applicable
- if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient ) {
- HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient->Stop();
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::abortStream: Unable to stop capture stream.";
- error( RtAudioError::DRIVER_ERROR );
- return;
- }
- }
-
- // stop render client if applicable
- if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient ) {
- HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient->Stop();
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::abortStream: Unable to stop render stream.";
- error( RtAudioError::DRIVER_ERROR );
- return;
- }
- }
-
- // close thread handle
- if ( stream_.callbackInfo.thread && !CloseHandle( ( void* ) stream_.callbackInfo.thread ) ) {
- errorText_ = "RtApiWasapi::abortStream: Unable to close callback thread.";
- error( RtAudioError::THREAD_ERROR );
- return;
- }
-
- stream_.callbackInfo.thread = (ThreadHandle) NULL;
-}
-
-//-----------------------------------------------------------------------------
-
-bool RtApiWasapi::probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
- unsigned int firstChannel, unsigned int sampleRate,
- RtAudioFormat format, unsigned int* bufferSize,
- RtAudio::StreamOptions* options )
-{
- bool methodResult = FAILURE;
- unsigned int captureDeviceCount = 0;
- unsigned int renderDeviceCount = 0;
-
- IMMDeviceCollection* captureDevices = NULL;
- IMMDeviceCollection* renderDevices = NULL;
- IMMDevice* devicePtr = NULL;
- WAVEFORMATEX* deviceFormat = NULL;
- unsigned int bufferBytes;
- stream_.state = STREAM_STOPPED;
-
- // create API Handle if not already created
- if ( !stream_.apiHandle )
- stream_.apiHandle = ( void* ) new WasapiHandle();
-
- // Count capture devices
- errorText_.clear();
- RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR;
- HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device collection.";
- goto Exit;
- }
-
- hr = captureDevices->GetCount( &captureDeviceCount );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device count.";
- goto Exit;
- }
-
- // Count render devices
- hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device collection.";
- goto Exit;
- }
-
- hr = renderDevices->GetCount( &renderDeviceCount );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device count.";
- goto Exit;
- }
-
- // validate device index
- if ( device >= captureDeviceCount + renderDeviceCount ) {
- errorType = RtAudioError::INVALID_USE;
- errorText_ = "RtApiWasapi::probeDeviceOpen: Invalid device index.";
- goto Exit;
- }
-
- // determine whether index falls within capture or render devices
- if ( device >= renderDeviceCount ) {
- if ( mode != INPUT ) {
- errorType = RtAudioError::INVALID_USE;
- errorText_ = "RtApiWasapi::probeDeviceOpen: Capture device selected as output device.";
- goto Exit;
- }
-
- // retrieve captureAudioClient from devicePtr
- IAudioClient*& captureAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient;
-
- hr = captureDevices->Item( device - renderDeviceCount, &devicePtr );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device handle.";
- goto Exit;
- }
-
- hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL,
- NULL, ( void** ) &captureAudioClient );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device audio client.";
- goto Exit;
- }
-
- hr = captureAudioClient->GetMixFormat( &deviceFormat );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device mix format.";
- goto Exit;
- }
-
- stream_.nDeviceChannels[mode] = deviceFormat->nChannels;
- captureAudioClient->GetStreamLatency( ( long long* ) &stream_.latency[mode] );
- }
- else {
- if ( mode != OUTPUT ) {
- errorType = RtAudioError::INVALID_USE;
- errorText_ = "RtApiWasapi::probeDeviceOpen: Render device selected as input device.";
- goto Exit;
- }
-
- // retrieve renderAudioClient from devicePtr
- IAudioClient*& renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient;
-
- hr = renderDevices->Item( device, &devicePtr );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device handle.";
- goto Exit;
- }
-
- hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL,
- NULL, ( void** ) &renderAudioClient );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device audio client.";
- goto Exit;
- }
-
- hr = renderAudioClient->GetMixFormat( &deviceFormat );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device mix format.";
- goto Exit;
- }
-
- stream_.nDeviceChannels[mode] = deviceFormat->nChannels;
- renderAudioClient->GetStreamLatency( ( long long* ) &stream_.latency[mode] );
- }
-
- // fill stream data
- if ( ( stream_.mode == OUTPUT && mode == INPUT ) ||
- ( stream_.mode == INPUT && mode == OUTPUT ) ) {
- stream_.mode = DUPLEX;
- }
- else {
- stream_.mode = mode;
- }
-
- stream_.device[mode] = device;
- stream_.doByteSwap[mode] = false;
- stream_.sampleRate = sampleRate;
- stream_.bufferSize = *bufferSize;
- stream_.nBuffers = 1;
- stream_.nUserChannels[mode] = channels;
- stream_.channelOffset[mode] = firstChannel;
- stream_.userFormat = format;
- stream_.deviceFormat[mode] = getDeviceInfo( device ).nativeFormats;
-
- if ( options && options->flags & RTAUDIO_NONINTERLEAVED )
- stream_.userInterleaved = false;
- else
- stream_.userInterleaved = true;
- stream_.deviceInterleaved[mode] = true;
-
- // Set flags for buffer conversion.
- stream_.doConvertBuffer[mode] = false;
- if ( stream_.userFormat != stream_.deviceFormat[mode] ||
- stream_.nUserChannels != stream_.nDeviceChannels )
- stream_.doConvertBuffer[mode] = true;
- else if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&
- stream_.nUserChannels[mode] > 1 )
- stream_.doConvertBuffer[mode] = true;
-
- if ( stream_.doConvertBuffer[mode] )
- setConvertInfo( mode, 0 );
-
- // Allocate necessary internal buffers
- bufferBytes = stream_.nUserChannels[mode] * stream_.bufferSize * formatBytes( stream_.userFormat );
-
- stream_.userBuffer[mode] = ( char* ) calloc( bufferBytes, 1 );
- if ( !stream_.userBuffer[mode] ) {
- errorType = RtAudioError::MEMORY_ERROR;
- errorText_ = "RtApiWasapi::probeDeviceOpen: Error allocating user buffer memory.";
- goto Exit;
- }
-
- if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME )
- stream_.callbackInfo.priority = 15;
- else
- stream_.callbackInfo.priority = 0;
-
- ///! TODO: RTAUDIO_MINIMIZE_LATENCY // Provide stream buffers directly to callback
- ///! TODO: RTAUDIO_HOG_DEVICE // Exclusive mode
-
- methodResult = SUCCESS;
-
-Exit:
- //clean up
- SAFE_RELEASE( captureDevices );
- SAFE_RELEASE( renderDevices );
- SAFE_RELEASE( devicePtr );
- CoTaskMemFree( deviceFormat );
-
- // if method failed, close the stream
- if ( methodResult == FAILURE )
- closeStream();
-
- if ( !errorText_.empty() )
- error( errorType );
- return methodResult;
-}
-
-//=============================================================================
-
-DWORD WINAPI RtApiWasapi::runWasapiThread( void* wasapiPtr )
-{
- if ( wasapiPtr )
- ( ( RtApiWasapi* ) wasapiPtr )->wasapiThread();
-
- return 0;
-}
-
-DWORD WINAPI RtApiWasapi::stopWasapiThread( void* wasapiPtr )
-{
- if ( wasapiPtr )
- ( ( RtApiWasapi* ) wasapiPtr )->stopStream();
-
- return 0;
-}
-
-DWORD WINAPI RtApiWasapi::abortWasapiThread( void* wasapiPtr )
-{
- if ( wasapiPtr )
- ( ( RtApiWasapi* ) wasapiPtr )->abortStream();
-
- return 0;
-}
-
-//-----------------------------------------------------------------------------
-
-void RtApiWasapi::wasapiThread()
-{
- // as this is a new thread, we must CoInitialize it
- CoInitialize( NULL );
-
- HRESULT hr;
-
- IAudioClient* captureAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient;
- IAudioClient* renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient;
- IAudioCaptureClient* captureClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureClient;
- IAudioRenderClient* renderClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderClient;
- HANDLE captureEvent = ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent;
- HANDLE renderEvent = ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent;
-
- WAVEFORMATEX* captureFormat = NULL;
- WAVEFORMATEX* renderFormat = NULL;
- float captureSrRatio = 0.0f;
- float renderSrRatio = 0.0f;
- WasapiBuffer captureBuffer;
- WasapiBuffer renderBuffer;
-
- // declare local stream variables
- RtAudioCallback callback = ( RtAudioCallback ) stream_.callbackInfo.callback;
- BYTE* streamBuffer = NULL;
- unsigned long captureFlags = 0;
- unsigned int bufferFrameCount = 0;
- unsigned int numFramesPadding = 0;
- unsigned int convBufferSize = 0;
- bool callbackPushed = false;
- bool callbackPulled = false;
- bool callbackStopped = false;
- int callbackResult = 0;
-
- // convBuffer is used to store converted buffers between WASAPI and the user
- char* convBuffer = NULL;
- unsigned int convBuffSize = 0;
- unsigned int deviceBuffSize = 0;
-
- errorText_.clear();
- RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR;
-
- // Attempt to assign "Pro Audio" characteristic to thread
- HMODULE AvrtDll = LoadLibrary( (LPCTSTR) "AVRT.dll" );
- if ( AvrtDll ) {
- DWORD taskIndex = 0;
- TAvSetMmThreadCharacteristicsPtr AvSetMmThreadCharacteristicsPtr = ( TAvSetMmThreadCharacteristicsPtr ) GetProcAddress( AvrtDll, "AvSetMmThreadCharacteristicsW" );
- AvSetMmThreadCharacteristicsPtr( L"Pro Audio", &taskIndex );
- FreeLibrary( AvrtDll );
- }
-
- // start capture stream if applicable
- if ( captureAudioClient ) {
- hr = captureAudioClient->GetMixFormat( &captureFormat );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve device mix format.";
- goto Exit;
- }
-
- captureSrRatio = ( ( float ) captureFormat->nSamplesPerSec / stream_.sampleRate );
-
- // initialize capture stream according to desire buffer size
- float desiredBufferSize = stream_.bufferSize * captureSrRatio;
- REFERENCE_TIME desiredBufferPeriod = ( REFERENCE_TIME ) ( ( float ) desiredBufferSize * 10000000 / captureFormat->nSamplesPerSec );
-
- if ( !captureClient ) {
- hr = captureAudioClient->Initialize( AUDCLNT_SHAREMODE_SHARED,
- AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
- desiredBufferPeriod,
- desiredBufferPeriod,
- captureFormat,
- NULL );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to initialize capture audio client.";
- goto Exit;
- }
-
- hr = captureAudioClient->GetService( __uuidof( IAudioCaptureClient ),
- ( void** ) &captureClient );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve capture client handle.";
- goto Exit;
- }
-
- // configure captureEvent to trigger on every available capture buffer
- captureEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
- if ( !captureEvent ) {
- errorType = RtAudioError::SYSTEM_ERROR;
- errorText_ = "RtApiWasapi::wasapiThread: Unable to create capture event.";
- goto Exit;
- }
-
- hr = captureAudioClient->SetEventHandle( captureEvent );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to set capture event handle.";
- goto Exit;
- }
-
- ( ( WasapiHandle* ) stream_.apiHandle )->captureClient = captureClient;
- ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent = captureEvent;
- }
-
- unsigned int inBufferSize = 0;
- hr = captureAudioClient->GetBufferSize( &inBufferSize );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to get capture buffer size.";
- goto Exit;
- }
-
- // scale outBufferSize according to stream->user sample rate ratio
- unsigned int outBufferSize = ( unsigned int ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT];
- inBufferSize *= stream_.nDeviceChannels[INPUT];
-
- // set captureBuffer size
- captureBuffer.setBufferSize( inBufferSize + outBufferSize, formatBytes( stream_.deviceFormat[INPUT] ) );
-
- // reset the capture stream
- hr = captureAudioClient->Reset();
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to reset capture stream.";
- goto Exit;
- }
-
- // start the capture stream
- hr = captureAudioClient->Start();
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to start capture stream.";
- goto Exit;
- }
- }
-
- // start render stream if applicable
- if ( renderAudioClient ) {
- hr = renderAudioClient->GetMixFormat( &renderFormat );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve device mix format.";
- goto Exit;
- }
-
- renderSrRatio = ( ( float ) renderFormat->nSamplesPerSec / stream_.sampleRate );
-
- // initialize render stream according to desire buffer size
- float desiredBufferSize = stream_.bufferSize * renderSrRatio;
- REFERENCE_TIME desiredBufferPeriod = ( REFERENCE_TIME ) ( ( float ) desiredBufferSize * 10000000 / renderFormat->nSamplesPerSec );
-
- if ( !renderClient ) {
- hr = renderAudioClient->Initialize( AUDCLNT_SHAREMODE_SHARED,
- AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
- desiredBufferPeriod,
- desiredBufferPeriod,
- renderFormat,
- NULL );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to initialize render audio client.";
- goto Exit;
- }
-
- hr = renderAudioClient->GetService( __uuidof( IAudioRenderClient ),
- ( void** ) &renderClient );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render client handle.";
- goto Exit;
- }
-
- // configure renderEvent to trigger on every available render buffer
- renderEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
- if ( !renderEvent ) {
- errorType = RtAudioError::SYSTEM_ERROR;
- errorText_ = "RtApiWasapi::wasapiThread: Unable to create render event.";
- goto Exit;
- }
-
- hr = renderAudioClient->SetEventHandle( renderEvent );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to set render event handle.";
- goto Exit;
- }
-
- ( ( WasapiHandle* ) stream_.apiHandle )->renderClient = renderClient;
- ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent = renderEvent;
- }
-
- unsigned int outBufferSize = 0;
- hr = renderAudioClient->GetBufferSize( &outBufferSize );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to get render buffer size.";
- goto Exit;
- }
-
- // scale inBufferSize according to user->stream sample rate ratio
- unsigned int inBufferSize = ( unsigned int ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT];
- outBufferSize *= stream_.nDeviceChannels[OUTPUT];
-
- // set renderBuffer size
- renderBuffer.setBufferSize( inBufferSize + outBufferSize, formatBytes( stream_.deviceFormat[OUTPUT] ) );
-
- // reset the render stream
- hr = renderAudioClient->Reset();
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to reset render stream.";
- goto Exit;
- }
-
- // start the render stream
- hr = renderAudioClient->Start();
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to start render stream.";
- goto Exit;
- }
- }
-
- if ( stream_.mode == INPUT ) {
- convBuffSize = ( size_t ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] );
- deviceBuffSize = stream_.bufferSize * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] );
- }
- else if ( stream_.mode == OUTPUT ) {
- convBuffSize = ( size_t ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] );
- deviceBuffSize = stream_.bufferSize * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] );
- }
- else if ( stream_.mode == DUPLEX ) {
- convBuffSize = std::max( ( size_t ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] ),
- ( size_t ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] ) );
- deviceBuffSize = std::max( stream_.bufferSize * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] ),
- stream_.bufferSize * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] ) );
- }
-
- convBuffer = ( char* ) malloc( convBuffSize );
- stream_.deviceBuffer = ( char* ) malloc( deviceBuffSize );
- if ( !convBuffer || !stream_.deviceBuffer ) {
- errorType = RtAudioError::MEMORY_ERROR;
- errorText_ = "RtApiWasapi::wasapiThread: Error allocating device buffer memory.";
- goto Exit;
- }
-
- // stream process loop
- while ( stream_.state != STREAM_STOPPING ) {
- if ( !callbackPulled ) {
- // Callback Input
- // ==============
- // 1. Pull callback buffer from inputBuffer
- // 2. If 1. was successful: Convert callback buffer to user sample rate and channel count
- // Convert callback buffer to user format
-
- if ( captureAudioClient ) {
- // Pull callback buffer from inputBuffer
- callbackPulled = captureBuffer.pullBuffer( convBuffer,
- ( unsigned int ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT],
- stream_.deviceFormat[INPUT] );
-
- if ( callbackPulled ) {
- // Convert callback buffer to user sample rate
- convertBufferWasapi( stream_.deviceBuffer,
- convBuffer,
- stream_.nDeviceChannels[INPUT],
- captureFormat->nSamplesPerSec,
- stream_.sampleRate,
- ( unsigned int ) ( stream_.bufferSize * captureSrRatio ),
- convBufferSize,
- stream_.deviceFormat[INPUT] );
-
- if ( stream_.doConvertBuffer[INPUT] ) {
- // Convert callback buffer to user format
- convertBuffer( stream_.userBuffer[INPUT],
- stream_.deviceBuffer,
- stream_.convertInfo[INPUT] );
- }
- else {
- // no further conversion, simple copy deviceBuffer to userBuffer
- memcpy( stream_.userBuffer[INPUT],
- stream_.deviceBuffer,
- stream_.bufferSize * stream_.nUserChannels[INPUT] * formatBytes( stream_.userFormat ) );
- }
- }
- }
- else {
- // if there is no capture stream, set callbackPulled flag
- callbackPulled = true;
- }
-
- // Execute Callback
- // ================
- // 1. Execute user callback method
- // 2. Handle return value from callback
-
- // if callback has not requested the stream to stop
- if ( callbackPulled && !callbackStopped ) {
- // Execute user callback method
- callbackResult = callback( stream_.userBuffer[OUTPUT],
- stream_.userBuffer[INPUT],
- stream_.bufferSize,
- getStreamTime(),
- captureFlags & AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY ? RTAUDIO_INPUT_OVERFLOW : 0,
- stream_.callbackInfo.userData );
-
- // Handle return value from callback
- if ( callbackResult == 1 ) {
- // instantiate a thread to stop this thread
- HANDLE threadHandle = CreateThread( NULL, 0, stopWasapiThread, this, 0, NULL );
- if ( !threadHandle ) {
- errorType = RtAudioError::THREAD_ERROR;
- errorText_ = "RtApiWasapi::wasapiThread: Unable to instantiate stream stop thread.";
- goto Exit;
- }
- else if ( !CloseHandle( threadHandle ) ) {
- errorType = RtAudioError::THREAD_ERROR;
- errorText_ = "RtApiWasapi::wasapiThread: Unable to close stream stop thread handle.";
- goto Exit;
- }
-
- callbackStopped = true;
- }
- else if ( callbackResult == 2 ) {
- // instantiate a thread to stop this thread
- HANDLE threadHandle = CreateThread( NULL, 0, abortWasapiThread, this, 0, NULL );
- if ( !threadHandle ) {
- errorType = RtAudioError::THREAD_ERROR;
- errorText_ = "RtApiWasapi::wasapiThread: Unable to instantiate stream abort thread.";
- goto Exit;
- }
- else if ( !CloseHandle( threadHandle ) ) {
- errorType = RtAudioError::THREAD_ERROR;
- errorText_ = "RtApiWasapi::wasapiThread: Unable to close stream abort thread handle.";
- goto Exit;
- }
-
- callbackStopped = true;
- }
- }
- }
-
- // Callback Output
- // ===============
- // 1. Convert callback buffer to stream format
- // 2. Convert callback buffer to stream sample rate and channel count
- // 3. Push callback buffer into outputBuffer
-
- if ( renderAudioClient && callbackPulled ) {
- if ( stream_.doConvertBuffer[OUTPUT] ) {
- // Convert callback buffer to stream format
- convertBuffer( stream_.deviceBuffer,
- stream_.userBuffer[OUTPUT],
- stream_.convertInfo[OUTPUT] );
-
- }
-
- // Convert callback buffer to stream sample rate
- convertBufferWasapi( convBuffer,
- stream_.deviceBuffer,
- stream_.nDeviceChannels[OUTPUT],
- stream_.sampleRate,
- renderFormat->nSamplesPerSec,
- stream_.bufferSize,
- convBufferSize,
- stream_.deviceFormat[OUTPUT] );
-
- // Push callback buffer into outputBuffer
- callbackPushed = renderBuffer.pushBuffer( convBuffer,
- convBufferSize * stream_.nDeviceChannels[OUTPUT],
- stream_.deviceFormat[OUTPUT] );
- }
- else {
- // if there is no render stream, set callbackPushed flag
- callbackPushed = true;
- }
-
- // Stream Capture
- // ==============
- // 1. Get capture buffer from stream
- // 2. Push capture buffer into inputBuffer
- // 3. If 2. was successful: Release capture buffer
-
- if ( captureAudioClient ) {
- // if the callback input buffer was not pulled from captureBuffer, wait for next capture event
- if ( !callbackPulled ) {
- WaitForSingleObject( captureEvent, INFINITE );
- }
-
- // Get capture buffer from stream
- hr = captureClient->GetBuffer( &streamBuffer,
- &bufferFrameCount,
- &captureFlags, NULL, NULL );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve capture buffer.";
- goto Exit;
- }
-
- if ( bufferFrameCount != 0 ) {
- // Push capture buffer into inputBuffer
- if ( captureBuffer.pushBuffer( ( char* ) streamBuffer,
- bufferFrameCount * stream_.nDeviceChannels[INPUT],
- stream_.deviceFormat[INPUT] ) )
- {
- // Release capture buffer
- hr = captureClient->ReleaseBuffer( bufferFrameCount );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";
- goto Exit;
- }
- }
- else
- {
- // Inform WASAPI that capture was unsuccessful
- hr = captureClient->ReleaseBuffer( 0 );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";
- goto Exit;
- }
- }
- }
- else
- {
- // Inform WASAPI that capture was unsuccessful
- hr = captureClient->ReleaseBuffer( 0 );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";
- goto Exit;
- }
- }
- }
-
- // Stream Render
- // =============
- // 1. Get render buffer from stream
- // 2. Pull next buffer from outputBuffer
- // 3. If 2. was successful: Fill render buffer with next buffer
- // Release render buffer
-
- if ( renderAudioClient ) {
- // if the callback output buffer was not pushed to renderBuffer, wait for next render event
- if ( callbackPulled && !callbackPushed ) {
- WaitForSingleObject( renderEvent, INFINITE );
- }
-
- // Get render buffer from stream
- hr = renderAudioClient->GetBufferSize( &bufferFrameCount );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer size.";
- goto Exit;
- }
-
- hr = renderAudioClient->GetCurrentPadding( &numFramesPadding );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer padding.";
- goto Exit;
- }
-
- bufferFrameCount -= numFramesPadding;
-
- if ( bufferFrameCount != 0 ) {
- hr = renderClient->GetBuffer( bufferFrameCount, &streamBuffer );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer.";
- goto Exit;
- }
-
- // Pull next buffer from outputBuffer
- // Fill render buffer with next buffer
- if ( renderBuffer.pullBuffer( ( char* ) streamBuffer,
- bufferFrameCount * stream_.nDeviceChannels[OUTPUT],
- stream_.deviceFormat[OUTPUT] ) )
- {
- // Release render buffer
- hr = renderClient->ReleaseBuffer( bufferFrameCount, 0 );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";
- goto Exit;
- }
- }
- else
- {
- // Inform WASAPI that render was unsuccessful
- hr = renderClient->ReleaseBuffer( 0, 0 );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";
- goto Exit;
- }
- }
- }
- else
- {
- // Inform WASAPI that render was unsuccessful
- hr = renderClient->ReleaseBuffer( 0, 0 );
- if ( FAILED( hr ) ) {
- errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";
- goto Exit;
- }
- }
- }
-
- // if the callback buffer was pushed renderBuffer reset callbackPulled flag
- if ( callbackPushed ) {
- callbackPulled = false;
- }
-
- // tick stream time
- RtApi::tickStreamTime();
- }
-
-Exit:
- // clean up
- CoTaskMemFree( captureFormat );
- CoTaskMemFree( renderFormat );
-
- free ( convBuffer );
-
- CoUninitialize();
-
- // update stream state
- stream_.state = STREAM_STOPPED;
-
- if ( errorText_.empty() )
- return;
- else
- error( errorType );
-}
-
-//******************** End of __WINDOWS_WASAPI__ *********************//
-#endif
-
-
-#if defined(__WINDOWS_DS__) // Windows DirectSound API
-
-// Modified by Robin Davies, October 2005
-// - Improvements to DirectX pointer chasing.
-// - Bug fix for non-power-of-two Asio granularity used by Edirol PCR-A30.
-// - Auto-call CoInitialize for DSOUND and ASIO platforms.
-// Various revisions for RtAudio 4.0 by Gary Scavone, April 2007
-// Changed device query structure for RtAudio 4.0.7, January 2010
-
-#include <dsound.h>
-#include <assert.h>
-#include <algorithm>
-
-#if defined(__MINGW32__)
- // missing from latest mingw winapi
-#define WAVE_FORMAT_96M08 0x00010000 /* 96 kHz, Mono, 8-bit */
-#define WAVE_FORMAT_96S08 0x00020000 /* 96 kHz, Stereo, 8-bit */
-#define WAVE_FORMAT_96M16 0x00040000 /* 96 kHz, Mono, 16-bit */
-#define WAVE_FORMAT_96S16 0x00080000 /* 96 kHz, Stereo, 16-bit */
-#endif
-
-#define MINIMUM_DEVICE_BUFFER_SIZE 32768
-
-#ifdef _MSC_VER // if Microsoft Visual C++
-#pragma comment( lib, "winmm.lib" ) // then, auto-link winmm.lib. Otherwise, it has to be added manually.
-#endif
-
-static inline DWORD dsPointerBetween( DWORD pointer, DWORD laterPointer, DWORD earlierPointer, DWORD bufferSize )
-{
- if ( pointer > bufferSize ) pointer -= bufferSize;
- if ( laterPointer < earlierPointer ) laterPointer += bufferSize;
- if ( pointer < earlierPointer ) pointer += bufferSize;
- return pointer >= earlierPointer && pointer < laterPointer;
-}
-
-// A structure to hold various information related to the DirectSound
-// API implementation.
-struct DsHandle {
- unsigned int drainCounter; // Tracks callback counts when draining
- bool internalDrain; // Indicates if stop is initiated from callback or not.
- void *id[2];
- void *buffer[2];
- bool xrun[2];
- UINT bufferPointer[2];
- DWORD dsBufferSize[2];
- DWORD dsPointerLeadTime[2]; // the number of bytes ahead of the safe pointer to lead by.
- HANDLE condition;
-
- DsHandle()
- :drainCounter(0), internalDrain(false) { id[0] = 0; id[1] = 0; buffer[0] = 0; buffer[1] = 0; xrun[0] = false; xrun[1] = false; bufferPointer[0] = 0; bufferPointer[1] = 0; }
-};
-
-// Declarations for utility functions, callbacks, and structures
-// specific to the DirectSound implementation.
-static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
- LPCTSTR description,
- LPCTSTR module,
- LPVOID lpContext );
-
-static const char* getErrorString( int code );
-
-static unsigned __stdcall callbackHandler( void *ptr );
-
-struct DsDevice {
- LPGUID id[2];
- bool validId[2];
- bool found;
- std::string name;
-
- DsDevice()
- : found(false) { validId[0] = false; validId[1] = false; }
-};
-
-struct DsProbeData {
- bool isInput;
- std::vector<struct DsDevice>* dsDevices;
-};
-
-RtApiDs :: RtApiDs()
-{
- // Dsound will run both-threaded. If CoInitialize fails, then just
- // accept whatever the mainline chose for a threading model.
- coInitialized_ = false;
- HRESULT hr = CoInitialize( NULL );
- if ( !FAILED( hr ) ) coInitialized_ = true;
-}
-
-RtApiDs :: ~RtApiDs()
-{
- if ( coInitialized_ ) CoUninitialize(); // balanced call.
- if ( stream_.state != STREAM_CLOSED ) closeStream();
-}
-
-// The DirectSound default output is always the first device.
-unsigned int RtApiDs :: getDefaultOutputDevice( void )
-{
- return 0;
-}
-
-// The DirectSound default input is always the first input device,
-// which is the first capture device enumerated.
-unsigned int RtApiDs :: getDefaultInputDevice( void )
-{
- return 0;
-}
-
-unsigned int RtApiDs :: getDeviceCount( void )
-{
- // Set query flag for previously found devices to false, so that we
- // can check for any devices that have disappeared.
- for ( unsigned int i=0; i<dsDevices.size(); i++ )
- dsDevices[i].found = false;
-
- // Query DirectSound devices.
- struct DsProbeData probeInfo;
- probeInfo.isInput = false;
- probeInfo.dsDevices = &dsDevices;
- HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &probeInfo );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::getDeviceCount: error (" << getErrorString( result ) << ") enumerating output devices!";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- }
-
- // Query DirectSoundCapture devices.
- probeInfo.isInput = true;
- result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &probeInfo );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::getDeviceCount: error (" << getErrorString( result ) << ") enumerating input devices!";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- }
-
- // Clean out any devices that may have disappeared (code update submitted by Eli Zehngut).
- for ( unsigned int i=0; i<dsDevices.size(); ) {
- if ( dsDevices[i].found == false ) dsDevices.erase( dsDevices.begin() + i );
- else i++;
- }
-
- return static_cast<unsigned int>(dsDevices.size());
-}
-
-RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )
-{
- RtAudio::DeviceInfo info;
- info.probed = false;
-
- if ( dsDevices.size() == 0 ) {
- // Force a query of all devices
- getDeviceCount();
- if ( dsDevices.size() == 0 ) {
- errorText_ = "RtApiDs::getDeviceInfo: no devices found!";
- error( RtAudioError::INVALID_USE );
- return info;
- }
- }
-
- if ( device >= dsDevices.size() ) {
- errorText_ = "RtApiDs::getDeviceInfo: device ID is invalid!";
- error( RtAudioError::INVALID_USE );
- return info;
- }
-
- HRESULT result;
- if ( dsDevices[ device ].validId[0] == false ) goto probeInput;
-
- LPDIRECTSOUND output;
- DSCAPS outCaps;
- result = DirectSoundCreate( dsDevices[ device ].id[0], &output, NULL );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") opening output device (" << dsDevices[ device ].name << ")!";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- goto probeInput;
- }
-
- outCaps.dwSize = sizeof( outCaps );
- result = output->GetCaps( &outCaps );
- if ( FAILED( result ) ) {
- output->Release();
- errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") getting capabilities!";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- goto probeInput;
- }
-
- // Get output channel information.
- info.outputChannels = ( outCaps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1;
-
- // Get sample rate information.
- info.sampleRates.clear();
- for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {
- if ( SAMPLE_RATES[k] >= (unsigned int) outCaps.dwMinSecondarySampleRate &&
- SAMPLE_RATES[k] <= (unsigned int) outCaps.dwMaxSecondarySampleRate ) {
- info.sampleRates.push_back( SAMPLE_RATES[k] );
-
- if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) )
- info.preferredSampleRate = SAMPLE_RATES[k];
- }
- }
-
- // Get format information.
- if ( outCaps.dwFlags & DSCAPS_PRIMARY16BIT ) info.nativeFormats |= RTAUDIO_SINT16;
- if ( outCaps.dwFlags & DSCAPS_PRIMARY8BIT ) info.nativeFormats |= RTAUDIO_SINT8;
-
- output->Release();
-
- if ( getDefaultOutputDevice() == device )
- info.isDefaultOutput = true;
-
- if ( dsDevices[ device ].validId[1] == false ) {
- info.name = dsDevices[ device ].name;
- info.probed = true;
- return info;
- }
-
- probeInput:
-
- LPDIRECTSOUNDCAPTURE input;
- result = DirectSoundCaptureCreate( dsDevices[ device ].id[1], &input, NULL );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") opening input device (" << dsDevices[ device ].name << ")!";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- return info;
- }
-
- DSCCAPS inCaps;
- inCaps.dwSize = sizeof( inCaps );
- result = input->GetCaps( &inCaps );
- if ( FAILED( result ) ) {
- input->Release();
- errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") getting object capabilities (" << dsDevices[ device ].name << ")!";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- return info;
- }
-
- // Get input channel information.
- info.inputChannels = inCaps.dwChannels;
-
- // Get sample rate and format information.
- std::vector<unsigned int> rates;
- if ( inCaps.dwChannels >= 2 ) {
- if ( inCaps.dwFormats & WAVE_FORMAT_1S16 ) info.nativeFormats |= RTAUDIO_SINT16;
- if ( inCaps.dwFormats & WAVE_FORMAT_2S16 ) info.nativeFormats |= RTAUDIO_SINT16;
- if ( inCaps.dwFormats & WAVE_FORMAT_4S16 ) info.nativeFormats |= RTAUDIO_SINT16;
- if ( inCaps.dwFormats & WAVE_FORMAT_96S16 ) info.nativeFormats |= RTAUDIO_SINT16;
- if ( inCaps.dwFormats & WAVE_FORMAT_1S08 ) info.nativeFormats |= RTAUDIO_SINT8;
- if ( inCaps.dwFormats & WAVE_FORMAT_2S08 ) info.nativeFormats |= RTAUDIO_SINT8;
- if ( inCaps.dwFormats & WAVE_FORMAT_4S08 ) info.nativeFormats |= RTAUDIO_SINT8;
- if ( inCaps.dwFormats & WAVE_FORMAT_96S08 ) info.nativeFormats |= RTAUDIO_SINT8;
-
- if ( info.nativeFormats & RTAUDIO_SINT16 ) {
- if ( inCaps.dwFormats & WAVE_FORMAT_1S16 ) rates.push_back( 11025 );
- if ( inCaps.dwFormats & WAVE_FORMAT_2S16 ) rates.push_back( 22050 );
- if ( inCaps.dwFormats & WAVE_FORMAT_4S16 ) rates.push_back( 44100 );
- if ( inCaps.dwFormats & WAVE_FORMAT_96S16 ) rates.push_back( 96000 );
- }
- else if ( info.nativeFormats & RTAUDIO_SINT8 ) {
- if ( inCaps.dwFormats & WAVE_FORMAT_1S08 ) rates.push_back( 11025 );
- if ( inCaps.dwFormats & WAVE_FORMAT_2S08 ) rates.push_back( 22050 );
- if ( inCaps.dwFormats & WAVE_FORMAT_4S08 ) rates.push_back( 44100 );
- if ( inCaps.dwFormats & WAVE_FORMAT_96S08 ) rates.push_back( 96000 );
- }
- }
- else if ( inCaps.dwChannels == 1 ) {
- if ( inCaps.dwFormats & WAVE_FORMAT_1M16 ) info.nativeFormats |= RTAUDIO_SINT16;
- if ( inCaps.dwFormats & WAVE_FORMAT_2M16 ) info.nativeFormats |= RTAUDIO_SINT16;
- if ( inCaps.dwFormats & WAVE_FORMAT_4M16 ) info.nativeFormats |= RTAUDIO_SINT16;
- if ( inCaps.dwFormats & WAVE_FORMAT_96M16 ) info.nativeFormats |= RTAUDIO_SINT16;
- if ( inCaps.dwFormats & WAVE_FORMAT_1M08 ) info.nativeFormats |= RTAUDIO_SINT8;
- if ( inCaps.dwFormats & WAVE_FORMAT_2M08 ) info.nativeFormats |= RTAUDIO_SINT8;
- if ( inCaps.dwFormats & WAVE_FORMAT_4M08 ) info.nativeFormats |= RTAUDIO_SINT8;
- if ( inCaps.dwFormats & WAVE_FORMAT_96M08 ) info.nativeFormats |= RTAUDIO_SINT8;
-
- if ( info.nativeFormats & RTAUDIO_SINT16 ) {
- if ( inCaps.dwFormats & WAVE_FORMAT_1M16 ) rates.push_back( 11025 );
- if ( inCaps.dwFormats & WAVE_FORMAT_2M16 ) rates.push_back( 22050 );
- if ( inCaps.dwFormats & WAVE_FORMAT_4M16 ) rates.push_back( 44100 );
- if ( inCaps.dwFormats & WAVE_FORMAT_96M16 ) rates.push_back( 96000 );
- }
- else if ( info.nativeFormats & RTAUDIO_SINT8 ) {
- if ( inCaps.dwFormats & WAVE_FORMAT_1M08 ) rates.push_back( 11025 );
- if ( inCaps.dwFormats & WAVE_FORMAT_2M08 ) rates.push_back( 22050 );
- if ( inCaps.dwFormats & WAVE_FORMAT_4M08 ) rates.push_back( 44100 );
- if ( inCaps.dwFormats & WAVE_FORMAT_96M08 ) rates.push_back( 96000 );
- }
- }
- else info.inputChannels = 0; // technically, this would be an error
-
- input->Release();
-
- if ( info.inputChannels == 0 ) return info;
-
- // Copy the supported rates to the info structure but avoid duplication.
- bool found;
- for ( unsigned int i=0; i<rates.size(); i++ ) {
- found = false;
- for ( unsigned int j=0; j<info.sampleRates.size(); j++ ) {
- if ( rates[i] == info.sampleRates[j] ) {
- found = true;
- break;
- }
- }
- if ( found == false ) info.sampleRates.push_back( rates[i] );
- }
- std::sort( info.sampleRates.begin(), info.sampleRates.end() );
-
- // If device opens for both playback and capture, we determine the channels.
- if ( info.outputChannels > 0 && info.inputChannels > 0 )
- info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;
-
- if ( device == 0 ) info.isDefaultInput = true;
-
- // Copy name and return.
- info.name = dsDevices[ device ].name;
- info.probed = true;
- return info;
-}
-
-bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
- unsigned int firstChannel, unsigned int sampleRate,
- RtAudioFormat format, unsigned int *bufferSize,
- RtAudio::StreamOptions *options )
-{
- if ( channels + firstChannel > 2 ) {
- errorText_ = "RtApiDs::probeDeviceOpen: DirectSound does not support more than 2 channels per device.";
- return FAILURE;
- }
-
- size_t nDevices = dsDevices.size();
- if ( nDevices == 0 ) {
- // This should not happen because a check is made before this function is called.
- errorText_ = "RtApiDs::probeDeviceOpen: no devices found!";
- return FAILURE;
- }
-
- if ( device >= nDevices ) {
- // This should not happen because a check is made before this function is called.
- errorText_ = "RtApiDs::probeDeviceOpen: device ID is invalid!";
- return FAILURE;
- }
-
- if ( mode == OUTPUT ) {
- if ( dsDevices[ device ].validId[0] == false ) {
- errorStream_ << "RtApiDs::probeDeviceOpen: device (" << device << ") does not support output!";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
- }
- else { // mode == INPUT
- if ( dsDevices[ device ].validId[1] == false ) {
- errorStream_ << "RtApiDs::probeDeviceOpen: device (" << device << ") does not support input!";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
- }
-
- // According to a note in PortAudio, using GetDesktopWindow()
- // instead of GetForegroundWindow() is supposed to avoid problems
- // that occur when the application's window is not the foreground
- // window. Also, if the application window closes before the
- // DirectSound buffer, DirectSound can crash. In the past, I had
- // problems when using GetDesktopWindow() but it seems fine now
- // (January 2010). I'll leave it commented here.
- // HWND hWnd = GetForegroundWindow();
- HWND hWnd = GetDesktopWindow();
-
- // Check the numberOfBuffers parameter and limit the lowest value to
- // two. This is a judgement call and a value of two is probably too
- // low for capture, but it should work for playback.
- int nBuffers = 0;
- if ( options ) nBuffers = options->numberOfBuffers;
- if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) nBuffers = 2;
- if ( nBuffers < 2 ) nBuffers = 3;
-
- // Check the lower range of the user-specified buffer size and set
- // (arbitrarily) to a lower bound of 32.
- if ( *bufferSize < 32 ) *bufferSize = 32;
-
- // Create the wave format structure. The data format setting will
- // be determined later.
- WAVEFORMATEX waveFormat;
- ZeroMemory( &waveFormat, sizeof(WAVEFORMATEX) );
- waveFormat.wFormatTag = WAVE_FORMAT_PCM;
- waveFormat.nChannels = channels + firstChannel;
- waveFormat.nSamplesPerSec = (unsigned long) sampleRate;
-
- // Determine the device buffer size. By default, we'll use the value
- // defined above (32K), but we will grow it to make allowances for
- // very large software buffer sizes.
- DWORD dsBufferSize = MINIMUM_DEVICE_BUFFER_SIZE;
- DWORD dsPointerLeadTime = 0;
-
- void *ohandle = 0, *bhandle = 0;
- HRESULT result;
- if ( mode == OUTPUT ) {
-
- LPDIRECTSOUND output;
- result = DirectSoundCreate( dsDevices[ device ].id[0], &output, NULL );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") opening output device (" << dsDevices[ device ].name << ")!";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- DSCAPS outCaps;
- outCaps.dwSize = sizeof( outCaps );
- result = output->GetCaps( &outCaps );
- if ( FAILED( result ) ) {
- output->Release();
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting capabilities (" << dsDevices[ device ].name << ")!";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Check channel information.
- if ( channels + firstChannel == 2 && !( outCaps.dwFlags & DSCAPS_PRIMARYSTEREO ) ) {
- errorStream_ << "RtApiDs::getDeviceInfo: the output device (" << dsDevices[ device ].name << ") does not support stereo playback.";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Check format information. Use 16-bit format unless not
- // supported or user requests 8-bit.
- if ( outCaps.dwFlags & DSCAPS_PRIMARY16BIT &&
- !( format == RTAUDIO_SINT8 && outCaps.dwFlags & DSCAPS_PRIMARY8BIT ) ) {
- waveFormat.wBitsPerSample = 16;
- stream_.deviceFormat[mode] = RTAUDIO_SINT16;
- }
- else {
- waveFormat.wBitsPerSample = 8;
- stream_.deviceFormat[mode] = RTAUDIO_SINT8;
- }
- stream_.userFormat = format;
-
- // Update wave format structure and buffer information.
- waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
- waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
- dsPointerLeadTime = nBuffers * (*bufferSize) * (waveFormat.wBitsPerSample / 8) * channels;
-
- // If the user wants an even bigger buffer, increase the device buffer size accordingly.
- while ( dsPointerLeadTime * 2U > dsBufferSize )
- dsBufferSize *= 2;
-
- // Set cooperative level to DSSCL_EXCLUSIVE ... sound stops when window focus changes.
- // result = output->SetCooperativeLevel( hWnd, DSSCL_EXCLUSIVE );
- // Set cooperative level to DSSCL_PRIORITY ... sound remains when window focus changes.
- result = output->SetCooperativeLevel( hWnd, DSSCL_PRIORITY );
- if ( FAILED( result ) ) {
- output->Release();
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") setting cooperative level (" << dsDevices[ device ].name << ")!";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Even though we will write to the secondary buffer, we need to
- // access the primary buffer to set the correct output format
- // (since the default is 8-bit, 22 kHz!). Setup the DS primary
- // buffer description.
- DSBUFFERDESC bufferDescription;
- ZeroMemory( &bufferDescription, sizeof( DSBUFFERDESC ) );
- bufferDescription.dwSize = sizeof( DSBUFFERDESC );
- bufferDescription.dwFlags = DSBCAPS_PRIMARYBUFFER;
-
- // Obtain the primary buffer
- LPDIRECTSOUNDBUFFER buffer;
- result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL );
- if ( FAILED( result ) ) {
- output->Release();
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") accessing primary buffer (" << dsDevices[ device ].name << ")!";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Set the primary DS buffer sound format.
- result = buffer->SetFormat( &waveFormat );
- if ( FAILED( result ) ) {
- output->Release();
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") setting primary buffer format (" << dsDevices[ device ].name << ")!";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Setup the secondary DS buffer description.
- ZeroMemory( &bufferDescription, sizeof( DSBUFFERDESC ) );
- bufferDescription.dwSize = sizeof( DSBUFFERDESC );
- bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
- DSBCAPS_GLOBALFOCUS |
- DSBCAPS_GETCURRENTPOSITION2 |
- DSBCAPS_LOCHARDWARE ); // Force hardware mixing
- bufferDescription.dwBufferBytes = dsBufferSize;
- bufferDescription.lpwfxFormat = &waveFormat;
-
- // Try to create the secondary DS buffer. If that doesn't work,
- // try to use software mixing. Otherwise, there's a problem.
- result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL );
- if ( FAILED( result ) ) {
- bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
- DSBCAPS_GLOBALFOCUS |
- DSBCAPS_GETCURRENTPOSITION2 |
- DSBCAPS_LOCSOFTWARE ); // Force software mixing
- result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL );
- if ( FAILED( result ) ) {
- output->Release();
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") creating secondary buffer (" << dsDevices[ device ].name << ")!";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
- }
-
- // Get the buffer size ... might be different from what we specified.
- DSBCAPS dsbcaps;
- dsbcaps.dwSize = sizeof( DSBCAPS );
- result = buffer->GetCaps( &dsbcaps );
- if ( FAILED( result ) ) {
- output->Release();
- buffer->Release();
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting buffer settings (" << dsDevices[ device ].name << ")!";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- dsBufferSize = dsbcaps.dwBufferBytes;
-
- // Lock the DS buffer
- LPVOID audioPtr;
- DWORD dataLen;
- result = buffer->Lock( 0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0 );
- if ( FAILED( result ) ) {
- output->Release();
- buffer->Release();
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") locking buffer (" << dsDevices[ device ].name << ")!";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Zero the DS buffer
- ZeroMemory( audioPtr, dataLen );
-
- // Unlock the DS buffer
- result = buffer->Unlock( audioPtr, dataLen, NULL, 0 );
- if ( FAILED( result ) ) {
- output->Release();
- buffer->Release();
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") unlocking buffer (" << dsDevices[ device ].name << ")!";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- ohandle = (void *) output;
- bhandle = (void *) buffer;
- }
-
- if ( mode == INPUT ) {
-
- LPDIRECTSOUNDCAPTURE input;
- result = DirectSoundCaptureCreate( dsDevices[ device ].id[1], &input, NULL );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") opening input device (" << dsDevices[ device ].name << ")!";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- DSCCAPS inCaps;
- inCaps.dwSize = sizeof( inCaps );
- result = input->GetCaps( &inCaps );
- if ( FAILED( result ) ) {
- input->Release();
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting input capabilities (" << dsDevices[ device ].name << ")!";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Check channel information.
- if ( inCaps.dwChannels < channels + firstChannel ) {
- errorText_ = "RtApiDs::getDeviceInfo: the input device does not support requested input channels.";
- return FAILURE;
- }
-
- // Check format information. Use 16-bit format unless user
- // requests 8-bit.
- DWORD deviceFormats;
- if ( channels + firstChannel == 2 ) {
- deviceFormats = WAVE_FORMAT_1S08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_96S08;
- if ( format == RTAUDIO_SINT8 && inCaps.dwFormats & deviceFormats ) {
- waveFormat.wBitsPerSample = 8;
- stream_.deviceFormat[mode] = RTAUDIO_SINT8;
- }
- else { // assume 16-bit is supported
- waveFormat.wBitsPerSample = 16;
- stream_.deviceFormat[mode] = RTAUDIO_SINT16;
- }
- }
- else { // channel == 1
- deviceFormats = WAVE_FORMAT_1M08 | WAVE_FORMAT_2M08 | WAVE_FORMAT_4M08 | WAVE_FORMAT_96M08;
- if ( format == RTAUDIO_SINT8 && inCaps.dwFormats & deviceFormats ) {
- waveFormat.wBitsPerSample = 8;
- stream_.deviceFormat[mode] = RTAUDIO_SINT8;
- }
- else { // assume 16-bit is supported
- waveFormat.wBitsPerSample = 16;
- stream_.deviceFormat[mode] = RTAUDIO_SINT16;
- }
- }
- stream_.userFormat = format;
-
- // Update wave format structure and buffer information.
- waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
- waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
- dsPointerLeadTime = nBuffers * (*bufferSize) * (waveFormat.wBitsPerSample / 8) * channels;
-
- // If the user wants an even bigger buffer, increase the device buffer size accordingly.
- while ( dsPointerLeadTime * 2U > dsBufferSize )
- dsBufferSize *= 2;
-
- // Setup the secondary DS buffer description.
- DSCBUFFERDESC bufferDescription;
- ZeroMemory( &bufferDescription, sizeof( DSCBUFFERDESC ) );
- bufferDescription.dwSize = sizeof( DSCBUFFERDESC );
- bufferDescription.dwFlags = 0;
- bufferDescription.dwReserved = 0;
- bufferDescription.dwBufferBytes = dsBufferSize;
- bufferDescription.lpwfxFormat = &waveFormat;
-
- // Create the capture buffer.
- LPDIRECTSOUNDCAPTUREBUFFER buffer;
- result = input->CreateCaptureBuffer( &bufferDescription, &buffer, NULL );
- if ( FAILED( result ) ) {
- input->Release();
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") creating input buffer (" << dsDevices[ device ].name << ")!";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Get the buffer size ... might be different from what we specified.
- DSCBCAPS dscbcaps;
- dscbcaps.dwSize = sizeof( DSCBCAPS );
- result = buffer->GetCaps( &dscbcaps );
- if ( FAILED( result ) ) {
- input->Release();
- buffer->Release();
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting buffer settings (" << dsDevices[ device ].name << ")!";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- dsBufferSize = dscbcaps.dwBufferBytes;
-
- // NOTE: We could have a problem here if this is a duplex stream
- // and the play and capture hardware buffer sizes are different
- // (I'm actually not sure if that is a problem or not).
- // Currently, we are not verifying that.
-
- // Lock the capture buffer
- LPVOID audioPtr;
- DWORD dataLen;
- result = buffer->Lock( 0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0 );
- if ( FAILED( result ) ) {
- input->Release();
- buffer->Release();
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") locking input buffer (" << dsDevices[ device ].name << ")!";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Zero the buffer
- ZeroMemory( audioPtr, dataLen );
-
- // Unlock the buffer
- result = buffer->Unlock( audioPtr, dataLen, NULL, 0 );
- if ( FAILED( result ) ) {
- input->Release();
- buffer->Release();
- errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") unlocking input buffer (" << dsDevices[ device ].name << ")!";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- ohandle = (void *) input;
- bhandle = (void *) buffer;
- }
-
- // Set various stream parameters
- DsHandle *handle = 0;
- stream_.nDeviceChannels[mode] = channels + firstChannel;
- stream_.nUserChannels[mode] = channels;
- stream_.bufferSize = *bufferSize;
- stream_.channelOffset[mode] = firstChannel;
- stream_.deviceInterleaved[mode] = true;
- if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;
- else stream_.userInterleaved = true;
-
- // Set flag for buffer conversion
- stream_.doConvertBuffer[mode] = false;
- if (stream_.nUserChannels[mode] != stream_.nDeviceChannels[mode])
- stream_.doConvertBuffer[mode] = true;
- if (stream_.userFormat != stream_.deviceFormat[mode])
- stream_.doConvertBuffer[mode] = true;
- if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&
- stream_.nUserChannels[mode] > 1 )
- stream_.doConvertBuffer[mode] = true;
-
- // Allocate necessary internal buffers
- long bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
- stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );
- if ( stream_.userBuffer[mode] == NULL ) {
- errorText_ = "RtApiDs::probeDeviceOpen: error allocating user buffer memory.";
- goto error;
- }
-
- if ( stream_.doConvertBuffer[mode] ) {
-
- bool makeBuffer = true;
- bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );
- if ( mode == INPUT ) {
- if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
- unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );
- if ( bufferBytes <= (long) bytesOut ) makeBuffer = false;
- }
- }
-
- if ( makeBuffer ) {
- bufferBytes *= *bufferSize;
- if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );
- stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );
- if ( stream_.deviceBuffer == NULL ) {
- errorText_ = "RtApiDs::probeDeviceOpen: error allocating device buffer memory.";
- goto error;
- }
- }
- }
-
- // Allocate our DsHandle structures for the stream.
- if ( stream_.apiHandle == 0 ) {
- try {
- handle = new DsHandle;
- }
- catch ( std::bad_alloc& ) {
- errorText_ = "RtApiDs::probeDeviceOpen: error allocating AsioHandle memory.";
- goto error;
- }
-
- // Create a manual-reset event.
- handle->condition = CreateEvent( NULL, // no security
- TRUE, // manual-reset
- FALSE, // non-signaled initially
- NULL ); // unnamed
- stream_.apiHandle = (void *) handle;
- }
- else
- handle = (DsHandle *) stream_.apiHandle;
- handle->id[mode] = ohandle;
- handle->buffer[mode] = bhandle;
- handle->dsBufferSize[mode] = dsBufferSize;
- handle->dsPointerLeadTime[mode] = dsPointerLeadTime;
-
- stream_.device[mode] = device;
- stream_.state = STREAM_STOPPED;
- if ( stream_.mode == OUTPUT && mode == INPUT )
- // We had already set up an output stream.
- stream_.mode = DUPLEX;
- else
- stream_.mode = mode;
- stream_.nBuffers = nBuffers;
- stream_.sampleRate = sampleRate;
-
- // Setup the buffer conversion information structure.
- if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel );
-
- // Setup the callback thread.
- if ( stream_.callbackInfo.isRunning == false ) {
- unsigned threadId;
- stream_.callbackInfo.isRunning = true;
- stream_.callbackInfo.object = (void *) this;
- stream_.callbackInfo.thread = _beginthreadex( NULL, 0, &callbackHandler,
- &stream_.callbackInfo, 0, &threadId );
- if ( stream_.callbackInfo.thread == 0 ) {
- errorText_ = "RtApiDs::probeDeviceOpen: error creating callback thread!";
- goto error;
- }
-
- // Boost DS thread priority
- SetThreadPriority( (HANDLE) stream_.callbackInfo.thread, THREAD_PRIORITY_HIGHEST );
- }
- return SUCCESS;
-
- error:
- if ( handle ) {
- if ( handle->buffer[0] ) { // the object pointer can be NULL and valid
- LPDIRECTSOUND object = (LPDIRECTSOUND) handle->id[0];
- LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
- if ( buffer ) buffer->Release();
- object->Release();
- }
- if ( handle->buffer[1] ) {
- LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) handle->id[1];
- LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
- if ( buffer ) buffer->Release();
- object->Release();
- }
- CloseHandle( handle->condition );
- delete handle;
- stream_.apiHandle = 0;
- }
-
- for ( int i=0; i<2; i++ ) {
- if ( stream_.userBuffer[i] ) {
- free( stream_.userBuffer[i] );
- stream_.userBuffer[i] = 0;
- }
- }
-
- if ( stream_.deviceBuffer ) {
- free( stream_.deviceBuffer );
- stream_.deviceBuffer = 0;
- }
-
- stream_.state = STREAM_CLOSED;
- return FAILURE;
-}
-
-void RtApiDs :: closeStream()
-{
- if ( stream_.state == STREAM_CLOSED ) {
- errorText_ = "RtApiDs::closeStream(): no open stream to close!";
- error( RtAudioError::WARNING );
- return;
- }
-
- // Stop the callback thread.
- stream_.callbackInfo.isRunning = false;
- WaitForSingleObject( (HANDLE) stream_.callbackInfo.thread, INFINITE );
- CloseHandle( (HANDLE) stream_.callbackInfo.thread );
-
- DsHandle *handle = (DsHandle *) stream_.apiHandle;
- if ( handle ) {
- if ( handle->buffer[0] ) { // the object pointer can be NULL and valid
- LPDIRECTSOUND object = (LPDIRECTSOUND) handle->id[0];
- LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
- if ( buffer ) {
- buffer->Stop();
- buffer->Release();
- }
- object->Release();
- }
- if ( handle->buffer[1] ) {
- LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) handle->id[1];
- LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
- if ( buffer ) {
- buffer->Stop();
- buffer->Release();
- }
- object->Release();
- }
- CloseHandle( handle->condition );
- delete handle;
- stream_.apiHandle = 0;
- }
-
- for ( int i=0; i<2; i++ ) {
- if ( stream_.userBuffer[i] ) {
- free( stream_.userBuffer[i] );
- stream_.userBuffer[i] = 0;
- }
- }
-
- if ( stream_.deviceBuffer ) {
- free( stream_.deviceBuffer );
- stream_.deviceBuffer = 0;
- }
-
- stream_.mode = UNINITIALIZED;
- stream_.state = STREAM_CLOSED;
-}
-
-void RtApiDs :: startStream()
-{
- verifyStream();
- if ( stream_.state == STREAM_RUNNING ) {
- errorText_ = "RtApiDs::startStream(): the stream is already running!";
- error( RtAudioError::WARNING );
- return;
- }
-
- DsHandle *handle = (DsHandle *) stream_.apiHandle;
-
- // Increase scheduler frequency on lesser windows (a side-effect of
- // increasing timer accuracy). On greater windows (Win2K or later),
- // this is already in effect.
- timeBeginPeriod( 1 );
-
- buffersRolling = false;
- duplexPrerollBytes = 0;
-
- if ( stream_.mode == DUPLEX ) {
- // 0.5 seconds of silence in DUPLEX mode while the devices spin up and synchronize.
- duplexPrerollBytes = (int) ( 0.5 * stream_.sampleRate * formatBytes( stream_.deviceFormat[1] ) * stream_.nDeviceChannels[1] );
- }
-
- HRESULT result = 0;
- if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
-
- LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
- result = buffer->Play( 0, 0, DSBPLAY_LOOPING );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::startStream: error (" << getErrorString( result ) << ") starting output buffer!";
- errorText_ = errorStream_.str();
- goto unlock;
- }
- }
-
- if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
-
- LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
- result = buffer->Start( DSCBSTART_LOOPING );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::startStream: error (" << getErrorString( result ) << ") starting input buffer!";
- errorText_ = errorStream_.str();
- goto unlock;
- }
- }
-
- handle->drainCounter = 0;
- handle->internalDrain = false;
- ResetEvent( handle->condition );
- stream_.state = STREAM_RUNNING;
-
- unlock:
- if ( FAILED( result ) ) error( RtAudioError::SYSTEM_ERROR );
-}
-
-void RtApiDs :: stopStream()
-{
- verifyStream();
- if ( stream_.state == STREAM_STOPPED ) {
- errorText_ = "RtApiDs::stopStream(): the stream is already stopped!";
- error( RtAudioError::WARNING );
- return;
- }
-
- HRESULT result = 0;
- LPVOID audioPtr;
- DWORD dataLen;
- DsHandle *handle = (DsHandle *) stream_.apiHandle;
- if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
- if ( handle->drainCounter == 0 ) {
- handle->drainCounter = 2;
- WaitForSingleObject( handle->condition, INFINITE ); // block until signaled
- }
-
- stream_.state = STREAM_STOPPED;
-
- MUTEX_LOCK( &stream_.mutex );
-
- // Stop the buffer and clear memory
- LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
- result = buffer->Stop();
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") stopping output buffer!";
- errorText_ = errorStream_.str();
- goto unlock;
- }
-
- // Lock the buffer and clear it so that if we start to play again,
- // we won't have old data playing.
- result = buffer->Lock( 0, handle->dsBufferSize[0], &audioPtr, &dataLen, NULL, NULL, 0 );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") locking output buffer!";
- errorText_ = errorStream_.str();
- goto unlock;
- }
-
- // Zero the DS buffer
- ZeroMemory( audioPtr, dataLen );
-
- // Unlock the DS buffer
- result = buffer->Unlock( audioPtr, dataLen, NULL, 0 );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") unlocking output buffer!";
- errorText_ = errorStream_.str();
- goto unlock;
- }
-
- // If we start playing again, we must begin at beginning of buffer.
- handle->bufferPointer[0] = 0;
- }
-
- if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
- LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
- audioPtr = NULL;
- dataLen = 0;
-
- stream_.state = STREAM_STOPPED;
-
- if ( stream_.mode != DUPLEX )
- MUTEX_LOCK( &stream_.mutex );
-
- result = buffer->Stop();
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") stopping input buffer!";
- errorText_ = errorStream_.str();
- goto unlock;
- }
-
- // Lock the buffer and clear it so that if we start to play again,
- // we won't have old data playing.
- result = buffer->Lock( 0, handle->dsBufferSize[1], &audioPtr, &dataLen, NULL, NULL, 0 );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") locking input buffer!";
- errorText_ = errorStream_.str();
- goto unlock;
- }
-
- // Zero the DS buffer
- ZeroMemory( audioPtr, dataLen );
-
- // Unlock the DS buffer
- result = buffer->Unlock( audioPtr, dataLen, NULL, 0 );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") unlocking input buffer!";
- errorText_ = errorStream_.str();
- goto unlock;
- }
-
- // If we start recording again, we must begin at beginning of buffer.
- handle->bufferPointer[1] = 0;
- }
-
- unlock:
- timeEndPeriod( 1 ); // revert to normal scheduler frequency on lesser windows.
- MUTEX_UNLOCK( &stream_.mutex );
-
- if ( FAILED( result ) ) error( RtAudioError::SYSTEM_ERROR );
-}
-
-void RtApiDs :: abortStream()
-{
- verifyStream();
- if ( stream_.state == STREAM_STOPPED ) {
- errorText_ = "RtApiDs::abortStream(): the stream is already stopped!";
- error( RtAudioError::WARNING );
- return;
- }
-
- DsHandle *handle = (DsHandle *) stream_.apiHandle;
- handle->drainCounter = 2;
-
- stopStream();
-}
-
-void RtApiDs :: callbackEvent()
-{
- if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) {
- Sleep( 50 ); // sleep 50 milliseconds
- return;
- }
-
- if ( stream_.state == STREAM_CLOSED ) {
- errorText_ = "RtApiDs::callbackEvent(): the stream is closed ... this shouldn't happen!";
- error( RtAudioError::WARNING );
- return;
- }
-
- CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
- DsHandle *handle = (DsHandle *) stream_.apiHandle;
-
- // Check if we were draining the stream and signal is finished.
- if ( handle->drainCounter > stream_.nBuffers + 2 ) {
-
- stream_.state = STREAM_STOPPING;
- if ( handle->internalDrain == false )
- SetEvent( handle->condition );
- else
- stopStream();
- return;
- }
-
- // Invoke user callback to get fresh output data UNLESS we are
- // draining stream.
- if ( handle->drainCounter == 0 ) {
- RtAudioCallback callback = (RtAudioCallback) info->callback;
- double streamTime = getStreamTime();
- RtAudioStreamStatus status = 0;
- if ( stream_.mode != INPUT && handle->xrun[0] == true ) {
- status |= RTAUDIO_OUTPUT_UNDERFLOW;
- handle->xrun[0] = false;
- }
- if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) {
- status |= RTAUDIO_INPUT_OVERFLOW;
- handle->xrun[1] = false;
- }
- int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1],
- stream_.bufferSize, streamTime, status, info->userData );
- if ( cbReturnValue == 2 ) {
- stream_.state = STREAM_STOPPING;
- handle->drainCounter = 2;
- abortStream();
- return;
- }
- else if ( cbReturnValue == 1 ) {
- handle->drainCounter = 1;
- handle->internalDrain = true;
- }
- }
-
- HRESULT result;
- DWORD currentWritePointer, safeWritePointer;
- DWORD currentReadPointer, safeReadPointer;
- UINT nextWritePointer;
-
- LPVOID buffer1 = NULL;
- LPVOID buffer2 = NULL;
- DWORD bufferSize1 = 0;
- DWORD bufferSize2 = 0;
-
- char *buffer;
- long bufferBytes;
-
- MUTEX_LOCK( &stream_.mutex );
- if ( stream_.state == STREAM_STOPPED ) {
- MUTEX_UNLOCK( &stream_.mutex );
- return;
- }
-
- if ( buffersRolling == false ) {
- if ( stream_.mode == DUPLEX ) {
- //assert( handle->dsBufferSize[0] == handle->dsBufferSize[1] );
-
- // It takes a while for the devices to get rolling. As a result,
- // there's no guarantee that the capture and write device pointers
- // will move in lockstep. Wait here for both devices to start
- // rolling, and then set our buffer pointers accordingly.
- // e.g. Crystal Drivers: the capture buffer starts up 5700 to 9600
- // bytes later than the write buffer.
-
- // Stub: a serious risk of having a pre-emptive scheduling round
- // take place between the two GetCurrentPosition calls... but I'm
- // really not sure how to solve the problem. Temporarily boost to
- // Realtime priority, maybe; but I'm not sure what priority the
- // DirectSound service threads run at. We *should* be roughly
- // within a ms or so of correct.
-
- LPDIRECTSOUNDBUFFER dsWriteBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
- LPDIRECTSOUNDCAPTUREBUFFER dsCaptureBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
-
- DWORD startSafeWritePointer, startSafeReadPointer;
-
- result = dsWriteBuffer->GetCurrentPosition( NULL, &startSafeWritePointer );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
- errorText_ = errorStream_.str();
- MUTEX_UNLOCK( &stream_.mutex );
- error( RtAudioError::SYSTEM_ERROR );
- return;
- }
- result = dsCaptureBuffer->GetCurrentPosition( NULL, &startSafeReadPointer );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
- errorText_ = errorStream_.str();
- MUTEX_UNLOCK( &stream_.mutex );
- error( RtAudioError::SYSTEM_ERROR );
- return;
- }
- while ( true ) {
- result = dsWriteBuffer->GetCurrentPosition( NULL, &safeWritePointer );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
- errorText_ = errorStream_.str();
- MUTEX_UNLOCK( &stream_.mutex );
- error( RtAudioError::SYSTEM_ERROR );
- return;
- }
- result = dsCaptureBuffer->GetCurrentPosition( NULL, &safeReadPointer );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
- errorText_ = errorStream_.str();
- MUTEX_UNLOCK( &stream_.mutex );
- error( RtAudioError::SYSTEM_ERROR );
- return;
- }
- if ( safeWritePointer != startSafeWritePointer && safeReadPointer != startSafeReadPointer ) break;
- Sleep( 1 );
- }
-
- //assert( handle->dsBufferSize[0] == handle->dsBufferSize[1] );
-
- handle->bufferPointer[0] = safeWritePointer + handle->dsPointerLeadTime[0];
- if ( handle->bufferPointer[0] >= handle->dsBufferSize[0] ) handle->bufferPointer[0] -= handle->dsBufferSize[0];
- handle->bufferPointer[1] = safeReadPointer;
- }
- else if ( stream_.mode == OUTPUT ) {
-
- // Set the proper nextWritePosition after initial startup.
- LPDIRECTSOUNDBUFFER dsWriteBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
- result = dsWriteBuffer->GetCurrentPosition( &currentWritePointer, &safeWritePointer );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
- errorText_ = errorStream_.str();
- MUTEX_UNLOCK( &stream_.mutex );
- error( RtAudioError::SYSTEM_ERROR );
- return;
- }
- handle->bufferPointer[0] = safeWritePointer + handle->dsPointerLeadTime[0];
- if ( handle->bufferPointer[0] >= handle->dsBufferSize[0] ) handle->bufferPointer[0] -= handle->dsBufferSize[0];
- }
-
- buffersRolling = true;
- }
-
- if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
-
- LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
-
- if ( handle->drainCounter > 1 ) { // write zeros to the output stream
- bufferBytes = stream_.bufferSize * stream_.nUserChannels[0];
- bufferBytes *= formatBytes( stream_.userFormat );
- memset( stream_.userBuffer[0], 0, bufferBytes );
- }
-
- // Setup parameters and do buffer conversion if necessary.
- if ( stream_.doConvertBuffer[0] ) {
- buffer = stream_.deviceBuffer;
- convertBuffer( buffer, stream_.userBuffer[0], stream_.convertInfo[0] );
- bufferBytes = stream_.bufferSize * stream_.nDeviceChannels[0];
- bufferBytes *= formatBytes( stream_.deviceFormat[0] );
- }
- else {
- buffer = stream_.userBuffer[0];
- bufferBytes = stream_.bufferSize * stream_.nUserChannels[0];
- bufferBytes *= formatBytes( stream_.userFormat );
- }
-
- // No byte swapping necessary in DirectSound implementation.
-
- // Ahhh ... windoze. 16-bit data is signed but 8-bit data is
- // unsigned. So, we need to convert our signed 8-bit data here to
- // unsigned.
- if ( stream_.deviceFormat[0] == RTAUDIO_SINT8 )
- for ( int i=0; i<bufferBytes; i++ ) buffer[i] = (unsigned char) ( buffer[i] + 128 );
-
- DWORD dsBufferSize = handle->dsBufferSize[0];
- nextWritePointer = handle->bufferPointer[0];
-
- DWORD endWrite, leadPointer;
- while ( true ) {
- // Find out where the read and "safe write" pointers are.
- result = dsBuffer->GetCurrentPosition( &currentWritePointer, &safeWritePointer );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
- errorText_ = errorStream_.str();
- error( RtAudioError::SYSTEM_ERROR );
- return;
- }
-
- // We will copy our output buffer into the region between
- // safeWritePointer and leadPointer. If leadPointer is not
- // beyond the next endWrite position, wait until it is.
- leadPointer = safeWritePointer + handle->dsPointerLeadTime[0];
- //std::cout << "safeWritePointer = " << safeWritePointer << ", leadPointer = " << leadPointer << ", nextWritePointer = " << nextWritePointer << std::endl;
- if ( leadPointer > dsBufferSize ) leadPointer -= dsBufferSize;
- if ( leadPointer < nextWritePointer ) leadPointer += dsBufferSize; // unwrap offset
- endWrite = nextWritePointer + bufferBytes;
-
- // Check whether the entire write region is behind the play pointer.
- if ( leadPointer >= endWrite ) break;
-
- // If we are here, then we must wait until the leadPointer advances
- // beyond the end of our next write region. We use the
- // Sleep() function to suspend operation until that happens.
- double millis = ( endWrite - leadPointer ) * 1000.0;
- millis /= ( formatBytes( stream_.deviceFormat[0]) * stream_.nDeviceChannels[0] * stream_.sampleRate);
- if ( millis < 1.0 ) millis = 1.0;
- Sleep( (DWORD) millis );
- }
-
- if ( dsPointerBetween( nextWritePointer, safeWritePointer, currentWritePointer, dsBufferSize )
- || dsPointerBetween( endWrite, safeWritePointer, currentWritePointer, dsBufferSize ) ) {
- // We've strayed into the forbidden zone ... resync the read pointer.
- handle->xrun[0] = true;
- nextWritePointer = safeWritePointer + handle->dsPointerLeadTime[0] - bufferBytes;
- if ( nextWritePointer >= dsBufferSize ) nextWritePointer -= dsBufferSize;
- handle->bufferPointer[0] = nextWritePointer;
- endWrite = nextWritePointer + bufferBytes;
- }
-
- // Lock free space in the buffer
- result = dsBuffer->Lock( nextWritePointer, bufferBytes, &buffer1,
- &bufferSize1, &buffer2, &bufferSize2, 0 );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking buffer during playback!";
- errorText_ = errorStream_.str();
- MUTEX_UNLOCK( &stream_.mutex );
- error( RtAudioError::SYSTEM_ERROR );
- return;
- }
-
- // Copy our buffer into the DS buffer
- CopyMemory( buffer1, buffer, bufferSize1 );
- if ( buffer2 != NULL ) CopyMemory( buffer2, buffer+bufferSize1, bufferSize2 );
-
- // Update our buffer offset and unlock sound buffer
- dsBuffer->Unlock( buffer1, bufferSize1, buffer2, bufferSize2 );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking buffer during playback!";
- errorText_ = errorStream_.str();
- MUTEX_UNLOCK( &stream_.mutex );
- error( RtAudioError::SYSTEM_ERROR );
- return;
- }
- nextWritePointer = ( nextWritePointer + bufferSize1 + bufferSize2 ) % dsBufferSize;
- handle->bufferPointer[0] = nextWritePointer;
- }
-
- // Don't bother draining input
- if ( handle->drainCounter ) {
- handle->drainCounter++;
- goto unlock;
- }
-
- if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
-
- // Setup parameters.
- if ( stream_.doConvertBuffer[1] ) {
- buffer = stream_.deviceBuffer;
- bufferBytes = stream_.bufferSize * stream_.nDeviceChannels[1];
- bufferBytes *= formatBytes( stream_.deviceFormat[1] );
- }
- else {
- buffer = stream_.userBuffer[1];
- bufferBytes = stream_.bufferSize * stream_.nUserChannels[1];
- bufferBytes *= formatBytes( stream_.userFormat );
- }
-
- LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
- long nextReadPointer = handle->bufferPointer[1];
- DWORD dsBufferSize = handle->dsBufferSize[1];
-
- // Find out where the write and "safe read" pointers are.
- result = dsBuffer->GetCurrentPosition( &currentReadPointer, &safeReadPointer );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
- errorText_ = errorStream_.str();
- MUTEX_UNLOCK( &stream_.mutex );
- error( RtAudioError::SYSTEM_ERROR );
- return;
- }
-
- if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset
- DWORD endRead = nextReadPointer + bufferBytes;
-
- // Handling depends on whether we are INPUT or DUPLEX.
- // If we're in INPUT mode then waiting is a good thing. If we're in DUPLEX mode,
- // then a wait here will drag the write pointers into the forbidden zone.
- //
- // In DUPLEX mode, rather than wait, we will back off the read pointer until
- // it's in a safe position. This causes dropouts, but it seems to be the only
- // practical way to sync up the read and write pointers reliably, given the
- // the very complex relationship between phase and increment of the read and write
- // pointers.
- //
- // In order to minimize audible dropouts in DUPLEX mode, we will
- // provide a pre-roll period of 0.5 seconds in which we return
- // zeros from the read buffer while the pointers sync up.
-
- if ( stream_.mode == DUPLEX ) {
- if ( safeReadPointer < endRead ) {
- if ( duplexPrerollBytes <= 0 ) {
- // Pre-roll time over. Be more agressive.
- int adjustment = endRead-safeReadPointer;
-
- handle->xrun[1] = true;
- // Two cases:
- // - large adjustments: we've probably run out of CPU cycles, so just resync exactly,
- // and perform fine adjustments later.
- // - small adjustments: back off by twice as much.
- if ( adjustment >= 2*bufferBytes )
- nextReadPointer = safeReadPointer-2*bufferBytes;
- else
- nextReadPointer = safeReadPointer-bufferBytes-adjustment;
-
- if ( nextReadPointer < 0 ) nextReadPointer += dsBufferSize;
-
- }
- else {
- // In pre=roll time. Just do it.
- nextReadPointer = safeReadPointer - bufferBytes;
- while ( nextReadPointer < 0 ) nextReadPointer += dsBufferSize;
- }
- endRead = nextReadPointer + bufferBytes;
- }
- }
- else { // mode == INPUT
- while ( safeReadPointer < endRead && stream_.callbackInfo.isRunning ) {
- // See comments for playback.
- double millis = (endRead - safeReadPointer) * 1000.0;
- millis /= ( formatBytes(stream_.deviceFormat[1]) * stream_.nDeviceChannels[1] * stream_.sampleRate);
- if ( millis < 1.0 ) millis = 1.0;
- Sleep( (DWORD) millis );
-
- // Wake up and find out where we are now.
- result = dsBuffer->GetCurrentPosition( &currentReadPointer, &safeReadPointer );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
- errorText_ = errorStream_.str();
- MUTEX_UNLOCK( &stream_.mutex );
- error( RtAudioError::SYSTEM_ERROR );
- return;
- }
-
- if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset
- }
- }
-
- // Lock free space in the buffer
- result = dsBuffer->Lock( nextReadPointer, bufferBytes, &buffer1,
- &bufferSize1, &buffer2, &bufferSize2, 0 );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking capture buffer!";
- errorText_ = errorStream_.str();
- MUTEX_UNLOCK( &stream_.mutex );
- error( RtAudioError::SYSTEM_ERROR );
- return;
- }
-
- if ( duplexPrerollBytes <= 0 ) {
- // Copy our buffer into the DS buffer
- CopyMemory( buffer, buffer1, bufferSize1 );
- if ( buffer2 != NULL ) CopyMemory( buffer+bufferSize1, buffer2, bufferSize2 );
- }
- else {
- memset( buffer, 0, bufferSize1 );
- if ( buffer2 != NULL ) memset( buffer + bufferSize1, 0, bufferSize2 );
- duplexPrerollBytes -= bufferSize1 + bufferSize2;
- }
-
- // Update our buffer offset and unlock sound buffer
- nextReadPointer = ( nextReadPointer + bufferSize1 + bufferSize2 ) % dsBufferSize;
- dsBuffer->Unlock( buffer1, bufferSize1, buffer2, bufferSize2 );
- if ( FAILED( result ) ) {
- errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking capture buffer!";
- errorText_ = errorStream_.str();
- MUTEX_UNLOCK( &stream_.mutex );
- error( RtAudioError::SYSTEM_ERROR );
- return;
- }
- handle->bufferPointer[1] = nextReadPointer;
-
- // No byte swapping necessary in DirectSound implementation.
-
- // If necessary, convert 8-bit data from unsigned to signed.
- if ( stream_.deviceFormat[1] == RTAUDIO_SINT8 )
- for ( int j=0; j<bufferBytes; j++ ) buffer[j] = (signed char) ( buffer[j] - 128 );
-
- // Do buffer conversion if necessary.
- if ( stream_.doConvertBuffer[1] )
- convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );
- }
-
- unlock:
- MUTEX_UNLOCK( &stream_.mutex );
- RtApi::tickStreamTime();
-}
-
-// Definitions for utility functions and callbacks
-// specific to the DirectSound implementation.
-
-static unsigned __stdcall callbackHandler( void *ptr )
-{
- CallbackInfo *info = (CallbackInfo *) ptr;
- RtApiDs *object = (RtApiDs *) info->object;
- bool* isRunning = &info->isRunning;
-
- while ( *isRunning == true ) {
- object->callbackEvent();
- }
-
- _endthreadex( 0 );
- return 0;
-}
-
-static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
- LPCTSTR description,
- LPCTSTR /*module*/,
- LPVOID lpContext )
-{
- struct DsProbeData& probeInfo = *(struct DsProbeData*) lpContext;
- std::vector<struct DsDevice>& dsDevices = *probeInfo.dsDevices;
-
- HRESULT hr;
- bool validDevice = false;
- if ( probeInfo.isInput == true ) {
- DSCCAPS caps;
- LPDIRECTSOUNDCAPTURE object;
-
- hr = DirectSoundCaptureCreate( lpguid, &object, NULL );
- if ( hr != DS_OK ) return TRUE;
-
- caps.dwSize = sizeof(caps);
- hr = object->GetCaps( &caps );
- if ( hr == DS_OK ) {
- if ( caps.dwChannels > 0 && caps.dwFormats > 0 )
- validDevice = true;
- }
- object->Release();
- }
- else {
- DSCAPS caps;
- LPDIRECTSOUND object;
- hr = DirectSoundCreate( lpguid, &object, NULL );
- if ( hr != DS_OK ) return TRUE;
-
- caps.dwSize = sizeof(caps);
- hr = object->GetCaps( &caps );
- if ( hr == DS_OK ) {
- if ( caps.dwFlags & DSCAPS_PRIMARYMONO || caps.dwFlags & DSCAPS_PRIMARYSTEREO )
- validDevice = true;
- }
- object->Release();
- }
-
- // If good device, then save its name and guid.
- std::string name = convertCharPointerToStdString( description );
- //if ( name == "Primary Sound Driver" || name == "Primary Sound Capture Driver" )
- if ( lpguid == NULL )
- name = "Default Device";
- if ( validDevice ) {
- for ( unsigned int i=0; i<dsDevices.size(); i++ ) {
- if ( dsDevices[i].name == name ) {
- dsDevices[i].found = true;
- if ( probeInfo.isInput ) {
- dsDevices[i].id[1] = lpguid;
- dsDevices[i].validId[1] = true;
- }
- else {
- dsDevices[i].id[0] = lpguid;
- dsDevices[i].validId[0] = true;
- }
- return TRUE;
- }
- }
-
- DsDevice device;
- device.name = name;
- device.found = true;
- if ( probeInfo.isInput ) {
- device.id[1] = lpguid;
- device.validId[1] = true;
- }
- else {
- device.id[0] = lpguid;
- device.validId[0] = true;
- }
- dsDevices.push_back( device );
- }
-
- return TRUE;
-}
-
-static const char* getErrorString( int code )
-{
- switch ( code ) {
-
- case DSERR_ALLOCATED:
- return "Already allocated";
-
- case DSERR_CONTROLUNAVAIL:
- return "Control unavailable";
-
- case DSERR_INVALIDPARAM:
- return "Invalid parameter";
-
- case DSERR_INVALIDCALL:
- return "Invalid call";
-
- case DSERR_GENERIC:
- return "Generic error";
-
- case DSERR_PRIOLEVELNEEDED:
- return "Priority level needed";
-
- case DSERR_OUTOFMEMORY:
- return "Out of memory";
-
- case DSERR_BADFORMAT:
- return "The sample rate or the channel format is not supported";
-
- case DSERR_UNSUPPORTED:
- return "Not supported";
-
- case DSERR_NODRIVER:
- return "No driver";
-
- case DSERR_ALREADYINITIALIZED:
- return "Already initialized";
-
- case DSERR_NOAGGREGATION:
- return "No aggregation";
-
- case DSERR_BUFFERLOST:
- return "Buffer lost";
-
- case DSERR_OTHERAPPHASPRIO:
- return "Another application already has priority";
-
- case DSERR_UNINITIALIZED:
- return "Uninitialized";
-
- default:
- return "DirectSound unknown error";
- }
-}
-//******************** End of __WINDOWS_DS__ *********************//
-#endif
-
-
-#if defined(__LINUX_ALSA__)
-
-#include <alsa/asoundlib.h>
-#include <unistd.h>
-
- // A structure to hold various information related to the ALSA API
- // implementation.
-struct AlsaHandle {
- snd_pcm_t *handles[2];
- bool synchronized;
- bool xrun[2];
- pthread_cond_t runnable_cv;
- bool runnable;
-
- AlsaHandle()
- :synchronized(false), runnable(false) { xrun[0] = false; xrun[1] = false; }
-};
-
-static void *alsaCallbackHandler( void * ptr );
-
-RtApiAlsa :: RtApiAlsa()
-{
- // Nothing to do here.
-}
-
-RtApiAlsa :: ~RtApiAlsa()
-{
- if ( stream_.state != STREAM_CLOSED ) closeStream();
-}
-
-unsigned int RtApiAlsa :: getDeviceCount( void )
-{
- unsigned nDevices = 0;
- int result, subdevice, card;
- char name[64];
- snd_ctl_t *handle;
-
- // Count cards and devices
- card = -1;
- snd_card_next( &card );
- while ( card >= 0 ) {
- sprintf( name, "hw:%d", card );
- result = snd_ctl_open( &handle, name, 0 );
- if ( result < 0 ) {
- errorStream_ << "RtApiAlsa::getDeviceCount: control open, card = " << card << ", " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- goto nextcard;
- }
- subdevice = -1;
- while( 1 ) {
- result = snd_ctl_pcm_next_device( handle, &subdevice );
- if ( result < 0 ) {
- errorStream_ << "RtApiAlsa::getDeviceCount: control next device, card = " << card << ", " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- break;
- }
- if ( subdevice < 0 )
- break;
- nDevices++;
- }
- nextcard:
- snd_ctl_close( handle );
- snd_card_next( &card );
- }
-
- result = snd_ctl_open( &handle, "default", 0 );
- if (result == 0) {
- nDevices++;
- snd_ctl_close( handle );
- }
-
- return nDevices;
-}
-
-RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
-{
- RtAudio::DeviceInfo info;
- info.probed = false;
-
- unsigned nDevices = 0;
- int result, subdevice, card;
- char name[64];
- snd_ctl_t *chandle;
-
- // Count cards and devices
- card = -1;
- subdevice = -1;
- snd_card_next( &card );
- while ( card >= 0 ) {
- sprintf( name, "hw:%d", card );
- result = snd_ctl_open( &chandle, name, SND_CTL_NONBLOCK );
- if ( result < 0 ) {
- errorStream_ << "RtApiAlsa::getDeviceInfo: control open, card = " << card << ", " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- goto nextcard;
- }
- subdevice = -1;
- while( 1 ) {
- result = snd_ctl_pcm_next_device( chandle, &subdevice );
- if ( result < 0 ) {
- errorStream_ << "RtApiAlsa::getDeviceInfo: control next device, card = " << card << ", " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- break;
- }
- if ( subdevice < 0 ) break;
- if ( nDevices == device ) {
- sprintf( name, "hw:%d,%d", card, subdevice );
- goto foundDevice;
- }
- nDevices++;
- }
- nextcard:
- snd_ctl_close( chandle );
- snd_card_next( &card );
- }
-
- result = snd_ctl_open( &chandle, "default", SND_CTL_NONBLOCK );
- if ( result == 0 ) {
- if ( nDevices == device ) {
- strcpy( name, "default" );
- goto foundDevice;
- }
- nDevices++;
- }
-
- if ( nDevices == 0 ) {
- errorText_ = "RtApiAlsa::getDeviceInfo: no devices found!";
- error( RtAudioError::INVALID_USE );
- return info;
- }
-
- if ( device >= nDevices ) {
- errorText_ = "RtApiAlsa::getDeviceInfo: device ID is invalid!";
- error( RtAudioError::INVALID_USE );
- return info;
- }
-
- foundDevice:
-
- // If a stream is already open, we cannot probe the stream devices.
- // Thus, use the saved results.
- if ( stream_.state != STREAM_CLOSED &&
- ( stream_.device[0] == device || stream_.device[1] == device ) ) {
- snd_ctl_close( chandle );
- if ( device >= devices_.size() ) {
- errorText_ = "RtApiAlsa::getDeviceInfo: device ID was not present before stream was opened.";
- error( RtAudioError::WARNING );
- return info;
- }
- return devices_[ device ];
- }
-
- int openMode = SND_PCM_ASYNC;
- snd_pcm_stream_t stream;
- snd_pcm_info_t *pcminfo;
- snd_pcm_info_alloca( &pcminfo );
- snd_pcm_t *phandle;
- snd_pcm_hw_params_t *params;
- snd_pcm_hw_params_alloca( &params );
-
- // First try for playback unless default device (which has subdev -1)
- stream = SND_PCM_STREAM_PLAYBACK;
- snd_pcm_info_set_stream( pcminfo, stream );
- if ( subdevice != -1 ) {
- snd_pcm_info_set_device( pcminfo, subdevice );
- snd_pcm_info_set_subdevice( pcminfo, 0 );
-
- result = snd_ctl_pcm_info( chandle, pcminfo );
- if ( result < 0 ) {
- // Device probably doesn't support playback.
- goto captureProbe;
- }
- }
-
- result = snd_pcm_open( &phandle, name, stream, openMode | SND_PCM_NONBLOCK );
- if ( result < 0 ) {
- errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- goto captureProbe;
- }
-
- // The device is open ... fill the parameter structure.
- result = snd_pcm_hw_params_any( phandle, params );
- if ( result < 0 ) {
- snd_pcm_close( phandle );
- errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- goto captureProbe;
- }
-
- // Get output channel information.
- unsigned int value;
- result = snd_pcm_hw_params_get_channels_max( params, &value );
- if ( result < 0 ) {
- snd_pcm_close( phandle );
- errorStream_ << "RtApiAlsa::getDeviceInfo: error getting device (" << name << ") output channels, " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- goto captureProbe;
- }
- info.outputChannels = value;
- snd_pcm_close( phandle );
-
- captureProbe:
- stream = SND_PCM_STREAM_CAPTURE;
- snd_pcm_info_set_stream( pcminfo, stream );
-
- // Now try for capture unless default device (with subdev = -1)
- if ( subdevice != -1 ) {
- result = snd_ctl_pcm_info( chandle, pcminfo );
- snd_ctl_close( chandle );
- if ( result < 0 ) {
- // Device probably doesn't support capture.
- if ( info.outputChannels == 0 ) return info;
- goto probeParameters;
- }
- }
- else
- snd_ctl_close( chandle );
-
- result = snd_pcm_open( &phandle, name, stream, openMode | SND_PCM_NONBLOCK);
- if ( result < 0 ) {
- errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- if ( info.outputChannels == 0 ) return info;
- goto probeParameters;
- }
-
- // The device is open ... fill the parameter structure.
- result = snd_pcm_hw_params_any( phandle, params );
- if ( result < 0 ) {
- snd_pcm_close( phandle );
- errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- if ( info.outputChannels == 0 ) return info;
- goto probeParameters;
- }
-
- result = snd_pcm_hw_params_get_channels_max( params, &value );
- if ( result < 0 ) {
- snd_pcm_close( phandle );
- errorStream_ << "RtApiAlsa::getDeviceInfo: error getting device (" << name << ") input channels, " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- if ( info.outputChannels == 0 ) return info;
- goto probeParameters;
- }
- info.inputChannels = value;
- snd_pcm_close( phandle );
-
- // If device opens for both playback and capture, we determine the channels.
- if ( info.outputChannels > 0 && info.inputChannels > 0 )
- info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;
-
- // ALSA doesn't provide default devices so we'll use the first available one.
- if ( device == 0 && info.outputChannels > 0 )
- info.isDefaultOutput = true;
- if ( device == 0 && info.inputChannels > 0 )
- info.isDefaultInput = true;
-
- probeParameters:
- // At this point, we just need to figure out the supported data
- // formats and sample rates. We'll proceed by opening the device in
- // the direction with the maximum number of channels, or playback if
- // they are equal. This might limit our sample rate options, but so
- // be it.
-
- if ( info.outputChannels >= info.inputChannels )
- stream = SND_PCM_STREAM_PLAYBACK;
- else
- stream = SND_PCM_STREAM_CAPTURE;
- snd_pcm_info_set_stream( pcminfo, stream );
-
- result = snd_pcm_open( &phandle, name, stream, openMode | SND_PCM_NONBLOCK);
- if ( result < 0 ) {
- errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- return info;
- }
-
- // The device is open ... fill the parameter structure.
- result = snd_pcm_hw_params_any( phandle, params );
- if ( result < 0 ) {
- snd_pcm_close( phandle );
- errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- return info;
- }
-
- // Test our discrete set of sample rate values.
- info.sampleRates.clear();
- for ( unsigned int i=0; i<MAX_SAMPLE_RATES; i++ ) {
- if ( snd_pcm_hw_params_test_rate( phandle, params, SAMPLE_RATES[i], 0 ) == 0 ) {
- info.sampleRates.push_back( SAMPLE_RATES[i] );
-
- if ( !info.preferredSampleRate || ( SAMPLE_RATES[i] <= 48000 && SAMPLE_RATES[i] > info.preferredSampleRate ) )
- info.preferredSampleRate = SAMPLE_RATES[i];
- }
- }
- if ( info.sampleRates.size() == 0 ) {
- snd_pcm_close( phandle );
- errorStream_ << "RtApiAlsa::getDeviceInfo: no supported sample rates found for device (" << name << ").";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- return info;
- }
-
- // Probe the supported data formats ... we don't care about endian-ness just yet
- snd_pcm_format_t format;
- info.nativeFormats = 0;
- format = SND_PCM_FORMAT_S8;
- if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )
- info.nativeFormats |= RTAUDIO_SINT8;
- format = SND_PCM_FORMAT_S16;
- if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )
- info.nativeFormats |= RTAUDIO_SINT16;
- format = SND_PCM_FORMAT_S24;
- if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )
- info.nativeFormats |= RTAUDIO_SINT24;
- format = SND_PCM_FORMAT_S32;
- if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )
- info.nativeFormats |= RTAUDIO_SINT32;
- format = SND_PCM_FORMAT_FLOAT;
- if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )
- info.nativeFormats |= RTAUDIO_FLOAT32;
- format = SND_PCM_FORMAT_FLOAT64;
- if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )
- info.nativeFormats |= RTAUDIO_FLOAT64;
-
- // Check that we have at least one supported format
- if ( info.nativeFormats == 0 ) {
- snd_pcm_close( phandle );
- errorStream_ << "RtApiAlsa::getDeviceInfo: pcm device (" << name << ") data format not supported by RtAudio.";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- return info;
- }
-
- // Get the device name
- char *cardname;
- result = snd_card_get_name( card, &cardname );
- if ( result >= 0 ) {
- sprintf( name, "hw:%s,%d", cardname, subdevice );
- free( cardname );
- }
- info.name = name;
-
- // That's all ... close the device and return
- snd_pcm_close( phandle );
- info.probed = true;
- return info;
-}
-
-void RtApiAlsa :: saveDeviceInfo( void )
-{
- devices_.clear();
-
- unsigned int nDevices = getDeviceCount();
- devices_.resize( nDevices );
- for ( unsigned int i=0; i<nDevices; i++ )
- devices_[i] = getDeviceInfo( i );
-}
-
-bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
- unsigned int firstChannel, unsigned int sampleRate,
- RtAudioFormat format, unsigned int *bufferSize,
- RtAudio::StreamOptions *options )
-
-{
-#if defined(__RTAUDIO_DEBUG__)
- snd_output_t *out;
- snd_output_stdio_attach(&out, stderr, 0);
-#endif
-
- // I'm not using the "plug" interface ... too much inconsistent behavior.
-
- unsigned nDevices = 0;
- int result, subdevice, card;
- char name[64];
- snd_ctl_t *chandle;
-
- if ( options && options->flags & RTAUDIO_ALSA_USE_DEFAULT )
- snprintf(name, sizeof(name), "%s", "default");
- else {
- // Count cards and devices
- card = -1;
- snd_card_next( &card );
- while ( card >= 0 ) {
- sprintf( name, "hw:%d", card );
- result = snd_ctl_open( &chandle, name, SND_CTL_NONBLOCK );
- if ( result < 0 ) {
- errorStream_ << "RtApiAlsa::probeDeviceOpen: control open, card = " << card << ", " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
- subdevice = -1;
- while( 1 ) {
- result = snd_ctl_pcm_next_device( chandle, &subdevice );
- if ( result < 0 ) break;
- if ( subdevice < 0 ) break;
- if ( nDevices == device ) {
- sprintf( name, "hw:%d,%d", card, subdevice );
- snd_ctl_close( chandle );
- goto foundDevice;
- }
- nDevices++;
- }
- snd_ctl_close( chandle );
- snd_card_next( &card );
- }
-
- result = snd_ctl_open( &chandle, "default", SND_CTL_NONBLOCK );
- if ( result == 0 ) {
- if ( nDevices == device ) {
- strcpy( name, "default" );
- goto foundDevice;
- }
- nDevices++;
- }
-
- if ( nDevices == 0 ) {
- // This should not happen because a check is made before this function is called.
- errorText_ = "RtApiAlsa::probeDeviceOpen: no devices found!";
- return FAILURE;
- }
-
- if ( device >= nDevices ) {
- // This should not happen because a check is made before this function is called.
- errorText_ = "RtApiAlsa::probeDeviceOpen: device ID is invalid!";
- return FAILURE;
- }
- }
-
- foundDevice:
-
- // The getDeviceInfo() function will not work for a device that is
- // already open. Thus, we'll probe the system before opening a
- // stream and save the results for use by getDeviceInfo().
- if ( mode == OUTPUT || ( mode == INPUT && stream_.mode != OUTPUT ) ) // only do once
- this->saveDeviceInfo();
-
- snd_pcm_stream_t stream;
- if ( mode == OUTPUT )
- stream = SND_PCM_STREAM_PLAYBACK;
- else
- stream = SND_PCM_STREAM_CAPTURE;
-
- snd_pcm_t *phandle;
- int openMode = SND_PCM_ASYNC;
- result = snd_pcm_open( &phandle, name, stream, openMode );
- if ( result < 0 ) {
- if ( mode == OUTPUT )
- errorStream_ << "RtApiAlsa::probeDeviceOpen: pcm device (" << name << ") won't open for output.";
- else
- errorStream_ << "RtApiAlsa::probeDeviceOpen: pcm device (" << name << ") won't open for input.";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Fill the parameter structure.
- snd_pcm_hw_params_t *hw_params;
- snd_pcm_hw_params_alloca( &hw_params );
- result = snd_pcm_hw_params_any( phandle, hw_params );
- if ( result < 0 ) {
- snd_pcm_close( phandle );
- errorStream_ << "RtApiAlsa::probeDeviceOpen: error getting pcm device (" << name << ") parameters, " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
-#if defined(__RTAUDIO_DEBUG__)
- fprintf( stderr, "\nRtApiAlsa: dump hardware params just after device open:\n\n" );
- snd_pcm_hw_params_dump( hw_params, out );
-#endif
-
- // Set access ... check user preference.
- if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) {
- stream_.userInterleaved = false;
- result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED );
- if ( result < 0 ) {
- result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED );
- stream_.deviceInterleaved[mode] = true;
- }
- else
- stream_.deviceInterleaved[mode] = false;
- }
- else {
- stream_.userInterleaved = true;
- result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED );
- if ( result < 0 ) {
- result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED );
- stream_.deviceInterleaved[mode] = false;
- }
- else
- stream_.deviceInterleaved[mode] = true;
- }
-
- if ( result < 0 ) {
- snd_pcm_close( phandle );
- errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting pcm device (" << name << ") access, " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Determine how to set the device format.
- stream_.userFormat = format;
- snd_pcm_format_t deviceFormat = SND_PCM_FORMAT_UNKNOWN;
-
- if ( format == RTAUDIO_SINT8 )
- deviceFormat = SND_PCM_FORMAT_S8;
- else if ( format == RTAUDIO_SINT16 )
- deviceFormat = SND_PCM_FORMAT_S16;
- else if ( format == RTAUDIO_SINT24 )
- deviceFormat = SND_PCM_FORMAT_S24;
- else if ( format == RTAUDIO_SINT32 )
- deviceFormat = SND_PCM_FORMAT_S32;
- else if ( format == RTAUDIO_FLOAT32 )
- deviceFormat = SND_PCM_FORMAT_FLOAT;
- else if ( format == RTAUDIO_FLOAT64 )
- deviceFormat = SND_PCM_FORMAT_FLOAT64;
-
- if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat) == 0) {
- stream_.deviceFormat[mode] = format;
- goto setFormat;
- }
-
- // The user requested format is not natively supported by the device.
- deviceFormat = SND_PCM_FORMAT_FLOAT64;
- if ( snd_pcm_hw_params_test_format( phandle, hw_params, deviceFormat ) == 0 ) {
- stream_.deviceFormat[mode] = RTAUDIO_FLOAT64;
- goto setFormat;
- }
-
- deviceFormat = SND_PCM_FORMAT_FLOAT;
- if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) {
- stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
- goto setFormat;
- }
-
- deviceFormat = SND_PCM_FORMAT_S32;
- if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) {
- stream_.deviceFormat[mode] = RTAUDIO_SINT32;
- goto setFormat;
- }
-
- deviceFormat = SND_PCM_FORMAT_S24;
- if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) {
- stream_.deviceFormat[mode] = RTAUDIO_SINT24;
- goto setFormat;
- }
-
- deviceFormat = SND_PCM_FORMAT_S16;
- if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) {
- stream_.deviceFormat[mode] = RTAUDIO_SINT16;
- goto setFormat;
- }
-
- deviceFormat = SND_PCM_FORMAT_S8;
- if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) {
- stream_.deviceFormat[mode] = RTAUDIO_SINT8;
- goto setFormat;
- }
-
- // If we get here, no supported format was found.
- snd_pcm_close( phandle );
- errorStream_ << "RtApiAlsa::probeDeviceOpen: pcm device " << device << " data format not supported by RtAudio.";
- errorText_ = errorStream_.str();
- return FAILURE;
-
- setFormat:
- result = snd_pcm_hw_params_set_format( phandle, hw_params, deviceFormat );
- if ( result < 0 ) {
- snd_pcm_close( phandle );
- errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting pcm device (" << name << ") data format, " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Determine whether byte-swaping is necessary.
- stream_.doByteSwap[mode] = false;
- if ( deviceFormat != SND_PCM_FORMAT_S8 ) {
- result = snd_pcm_format_cpu_endian( deviceFormat );
- if ( result == 0 )
- stream_.doByteSwap[mode] = true;
- else if (result < 0) {
- snd_pcm_close( phandle );
- errorStream_ << "RtApiAlsa::probeDeviceOpen: error getting pcm device (" << name << ") endian-ness, " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
- }
-
- // Set the sample rate.
- result = snd_pcm_hw_params_set_rate_near( phandle, hw_params, (unsigned int*) &sampleRate, 0 );
- if ( result < 0 ) {
- snd_pcm_close( phandle );
- errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting sample rate on device (" << name << "), " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Determine the number of channels for this device. We support a possible
- // minimum device channel number > than the value requested by the user.
- stream_.nUserChannels[mode] = channels;
- unsigned int value;
- result = snd_pcm_hw_params_get_channels_max( hw_params, &value );
- unsigned int deviceChannels = value;
- if ( result < 0 || deviceChannels < channels + firstChannel ) {
- snd_pcm_close( phandle );
- errorStream_ << "RtApiAlsa::probeDeviceOpen: requested channel parameters not supported by device (" << name << "), " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- result = snd_pcm_hw_params_get_channels_min( hw_params, &value );
- if ( result < 0 ) {
- snd_pcm_close( phandle );
- errorStream_ << "RtApiAlsa::probeDeviceOpen: error getting minimum channels for device (" << name << "), " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
- deviceChannels = value;
- if ( deviceChannels < channels + firstChannel ) deviceChannels = channels + firstChannel;
- stream_.nDeviceChannels[mode] = deviceChannels;
-
- // Set the device channels.
- result = snd_pcm_hw_params_set_channels( phandle, hw_params, deviceChannels );
- if ( result < 0 ) {
- snd_pcm_close( phandle );
- errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting channels for device (" << name << "), " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Set the buffer (or period) size.
- int dir = 0;
- snd_pcm_uframes_t periodSize = *bufferSize;
- result = snd_pcm_hw_params_set_period_size_near( phandle, hw_params, &periodSize, &dir );
- if ( result < 0 ) {
- snd_pcm_close( phandle );
- errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting period size for device (" << name << "), " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
- *bufferSize = periodSize;
-
- // Set the buffer number, which in ALSA is referred to as the "period".
- unsigned int periods = 0;
- if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) periods = 2;
- if ( options && options->numberOfBuffers > 0 ) periods = options->numberOfBuffers;
- if ( periods < 2 ) periods = 4; // a fairly safe default value
- result = snd_pcm_hw_params_set_periods_near( phandle, hw_params, &periods, &dir );
- if ( result < 0 ) {
- snd_pcm_close( phandle );
- errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting periods for device (" << name << "), " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // If attempting to setup a duplex stream, the bufferSize parameter
- // MUST be the same in both directions!
- if ( stream_.mode == OUTPUT && mode == INPUT && *bufferSize != stream_.bufferSize ) {
- snd_pcm_close( phandle );
- errorStream_ << "RtApiAlsa::probeDeviceOpen: system error setting buffer size for duplex stream on device (" << name << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- stream_.bufferSize = *bufferSize;
-
- // Install the hardware configuration
- result = snd_pcm_hw_params( phandle, hw_params );
- if ( result < 0 ) {
- snd_pcm_close( phandle );
- errorStream_ << "RtApiAlsa::probeDeviceOpen: error installing hardware configuration on device (" << name << "), " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
-#if defined(__RTAUDIO_DEBUG__)
- fprintf(stderr, "\nRtApiAlsa: dump hardware params after installation:\n\n");
- snd_pcm_hw_params_dump( hw_params, out );
-#endif
-
- // Set the software configuration to fill buffers with zeros and prevent device stopping on xruns.
- snd_pcm_sw_params_t *sw_params = NULL;
- snd_pcm_sw_params_alloca( &sw_params );
- snd_pcm_sw_params_current( phandle, sw_params );
- snd_pcm_sw_params_set_start_threshold( phandle, sw_params, *bufferSize );
- snd_pcm_sw_params_set_stop_threshold( phandle, sw_params, ULONG_MAX );
- snd_pcm_sw_params_set_silence_threshold( phandle, sw_params, 0 );
-
- // The following two settings were suggested by Theo Veenker
- //snd_pcm_sw_params_set_avail_min( phandle, sw_params, *bufferSize );
- //snd_pcm_sw_params_set_xfer_align( phandle, sw_params, 1 );
-
- // here are two options for a fix
- //snd_pcm_sw_params_set_silence_size( phandle, sw_params, ULONG_MAX );
- snd_pcm_uframes_t val;
- snd_pcm_sw_params_get_boundary( sw_params, &val );
- snd_pcm_sw_params_set_silence_size( phandle, sw_params, val );
-
- result = snd_pcm_sw_params( phandle, sw_params );
- if ( result < 0 ) {
- snd_pcm_close( phandle );
- errorStream_ << "RtApiAlsa::probeDeviceOpen: error installing software configuration on device (" << name << "), " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
-#if defined(__RTAUDIO_DEBUG__)
- fprintf(stderr, "\nRtApiAlsa: dump software params after installation:\n\n");
- snd_pcm_sw_params_dump( sw_params, out );
-#endif
-
- // Set flags for buffer conversion
- stream_.doConvertBuffer[mode] = false;
- if ( stream_.userFormat != stream_.deviceFormat[mode] )
- stream_.doConvertBuffer[mode] = true;
- if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] )
- stream_.doConvertBuffer[mode] = true;
- if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&
- stream_.nUserChannels[mode] > 1 )
- stream_.doConvertBuffer[mode] = true;
-
- // Allocate the ApiHandle if necessary and then save.
- AlsaHandle *apiInfo = 0;
- if ( stream_.apiHandle == 0 ) {
- try {
- apiInfo = (AlsaHandle *) new AlsaHandle;
- }
- catch ( std::bad_alloc& ) {
- errorText_ = "RtApiAlsa::probeDeviceOpen: error allocating AlsaHandle memory.";
- goto error;
- }
-
- if ( pthread_cond_init( &apiInfo->runnable_cv, NULL ) ) {
- errorText_ = "RtApiAlsa::probeDeviceOpen: error initializing pthread condition variable.";
- goto error;
- }
-
- stream_.apiHandle = (void *) apiInfo;
- apiInfo->handles[0] = 0;
- apiInfo->handles[1] = 0;
- }
- else {
- apiInfo = (AlsaHandle *) stream_.apiHandle;
- }
- apiInfo->handles[mode] = phandle;
- phandle = 0;
-
- // Allocate necessary internal buffers.
- unsigned long bufferBytes;
- bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
- stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );
- if ( stream_.userBuffer[mode] == NULL ) {
- errorText_ = "RtApiAlsa::probeDeviceOpen: error allocating user buffer memory.";
- goto error;
- }
-
- if ( stream_.doConvertBuffer[mode] ) {
-
- bool makeBuffer = true;
- bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );
- if ( mode == INPUT ) {
- if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
- unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );
- if ( bufferBytes <= bytesOut ) makeBuffer = false;
- }
- }
-
- if ( makeBuffer ) {
- bufferBytes *= *bufferSize;
- if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );
- stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );
- if ( stream_.deviceBuffer == NULL ) {
- errorText_ = "RtApiAlsa::probeDeviceOpen: error allocating device buffer memory.";
- goto error;
- }
- }
- }
-
- stream_.sampleRate = sampleRate;
- stream_.nBuffers = periods;
- stream_.device[mode] = device;
- stream_.state = STREAM_STOPPED;
-
- // Setup the buffer conversion information structure.
- if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel );
-
- // Setup thread if necessary.
- if ( stream_.mode == OUTPUT && mode == INPUT ) {
- // We had already set up an output stream.
- stream_.mode = DUPLEX;
- // Link the streams if possible.
- apiInfo->synchronized = false;
- if ( snd_pcm_link( apiInfo->handles[0], apiInfo->handles[1] ) == 0 )
- apiInfo->synchronized = true;
- else {
- errorText_ = "RtApiAlsa::probeDeviceOpen: unable to synchronize input and output devices.";
- error( RtAudioError::WARNING );
- }
- }
- else {
- stream_.mode = mode;
-
- // Setup callback thread.
- stream_.callbackInfo.object = (void *) this;
-
- // Set the thread attributes for joinable and realtime scheduling
- // priority (optional). The higher priority will only take affect
- // if the program is run as root or suid. Note, under Linux
- // processes with CAP_SYS_NICE privilege, a user can change
- // scheduling policy and priority (thus need not be root). See
- // POSIX "capabilities".
- pthread_attr_t attr;
- pthread_attr_init( &attr );
- pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
-
-#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)
- if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) {
- // We previously attempted to increase the audio callback priority
- // to SCHED_RR here via the attributes. However, while no errors
- // were reported in doing so, it did not work. So, now this is
- // done in the alsaCallbackHandler function.
- stream_.callbackInfo.doRealtime = true;
- int priority = options->priority;
- int min = sched_get_priority_min( SCHED_RR );
- int max = sched_get_priority_max( SCHED_RR );
- if ( priority < min ) priority = min;
- else if ( priority > max ) priority = max;
- stream_.callbackInfo.priority = priority;
- }
-#endif
-
- stream_.callbackInfo.isRunning = true;
- result = pthread_create( &stream_.callbackInfo.thread, &attr, alsaCallbackHandler, &stream_.callbackInfo );
- pthread_attr_destroy( &attr );
- if ( result ) {
- stream_.callbackInfo.isRunning = false;
- errorText_ = "RtApiAlsa::error creating callback thread!";
- goto error;
- }
- }
-
- return SUCCESS;
-
- error:
- if ( apiInfo ) {
- pthread_cond_destroy( &apiInfo->runnable_cv );
- if ( apiInfo->handles[0] ) snd_pcm_close( apiInfo->handles[0] );
- if ( apiInfo->handles[1] ) snd_pcm_close( apiInfo->handles[1] );
- delete apiInfo;
- stream_.apiHandle = 0;
- }
-
- if ( phandle) snd_pcm_close( phandle );
-
- for ( int i=0; i<2; i++ ) {
- if ( stream_.userBuffer[i] ) {
- free( stream_.userBuffer[i] );
- stream_.userBuffer[i] = 0;
- }
- }
-
- if ( stream_.deviceBuffer ) {
- free( stream_.deviceBuffer );
- stream_.deviceBuffer = 0;
- }
-
- stream_.state = STREAM_CLOSED;
- return FAILURE;
-}
-
-void RtApiAlsa :: closeStream()
-{
- if ( stream_.state == STREAM_CLOSED ) {
- errorText_ = "RtApiAlsa::closeStream(): no open stream to close!";
- error( RtAudioError::WARNING );
- return;
- }
-
- AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
- stream_.callbackInfo.isRunning = false;
- MUTEX_LOCK( &stream_.mutex );
- if ( stream_.state == STREAM_STOPPED ) {
- apiInfo->runnable = true;
- pthread_cond_signal( &apiInfo->runnable_cv );
- }
- MUTEX_UNLOCK( &stream_.mutex );
- pthread_join( stream_.callbackInfo.thread, NULL );
-
- if ( stream_.state == STREAM_RUNNING ) {
- stream_.state = STREAM_STOPPED;
- if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX )
- snd_pcm_drop( apiInfo->handles[0] );
- if ( stream_.mode == INPUT || stream_.mode == DUPLEX )
- snd_pcm_drop( apiInfo->handles[1] );
- }
-
- if ( apiInfo ) {
- pthread_cond_destroy( &apiInfo->runnable_cv );
- if ( apiInfo->handles[0] ) snd_pcm_close( apiInfo->handles[0] );
- if ( apiInfo->handles[1] ) snd_pcm_close( apiInfo->handles[1] );
- delete apiInfo;
- stream_.apiHandle = 0;
- }
-
- for ( int i=0; i<2; i++ ) {
- if ( stream_.userBuffer[i] ) {
- free( stream_.userBuffer[i] );
- stream_.userBuffer[i] = 0;
- }
- }
-
- if ( stream_.deviceBuffer ) {
- free( stream_.deviceBuffer );
- stream_.deviceBuffer = 0;
- }
-
- stream_.mode = UNINITIALIZED;
- stream_.state = STREAM_CLOSED;
-}
-
-void RtApiAlsa :: startStream()
-{
- // This method calls snd_pcm_prepare if the device isn't already in that state.
-
- verifyStream();
- if ( stream_.state == STREAM_RUNNING ) {
- errorText_ = "RtApiAlsa::startStream(): the stream is already running!";
- error( RtAudioError::WARNING );
- return;
- }
-
- MUTEX_LOCK( &stream_.mutex );
-
- int result = 0;
- snd_pcm_state_t state;
- AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
- snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles;
- if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
- state = snd_pcm_state( handle[0] );
- if ( state != SND_PCM_STATE_PREPARED ) {
- result = snd_pcm_prepare( handle[0] );
- if ( result < 0 ) {
- errorStream_ << "RtApiAlsa::startStream: error preparing output pcm device, " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- goto unlock;
- }
- }
- }
-
- if ( ( stream_.mode == INPUT || stream_.mode == DUPLEX ) && !apiInfo->synchronized ) {
- result = snd_pcm_drop(handle[1]); // fix to remove stale data received since device has been open
- state = snd_pcm_state( handle[1] );
- if ( state != SND_PCM_STATE_PREPARED ) {
- result = snd_pcm_prepare( handle[1] );
- if ( result < 0 ) {
- errorStream_ << "RtApiAlsa::startStream: error preparing input pcm device, " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- goto unlock;
- }
- }
- }
-
- stream_.state = STREAM_RUNNING;
-
- unlock:
- apiInfo->runnable = true;
- pthread_cond_signal( &apiInfo->runnable_cv );
- MUTEX_UNLOCK( &stream_.mutex );
-
- if ( result >= 0 ) return;
- error( RtAudioError::SYSTEM_ERROR );
-}
-
-void RtApiAlsa :: stopStream()
-{
- verifyStream();
- if ( stream_.state == STREAM_STOPPED ) {
- errorText_ = "RtApiAlsa::stopStream(): the stream is already stopped!";
- error( RtAudioError::WARNING );
- return;
- }
-
- stream_.state = STREAM_STOPPED;
- MUTEX_LOCK( &stream_.mutex );
-
- int result = 0;
- AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
- snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles;
- if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
- if ( apiInfo->synchronized )
- result = snd_pcm_drop( handle[0] );
- else
- result = snd_pcm_drain( handle[0] );
- if ( result < 0 ) {
- errorStream_ << "RtApiAlsa::stopStream: error draining output pcm device, " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- goto unlock;
- }
- }
-
- if ( ( stream_.mode == INPUT || stream_.mode == DUPLEX ) && !apiInfo->synchronized ) {
- result = snd_pcm_drop( handle[1] );
- if ( result < 0 ) {
- errorStream_ << "RtApiAlsa::stopStream: error stopping input pcm device, " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- goto unlock;
- }
- }
-
- unlock:
- apiInfo->runnable = false; // fixes high CPU usage when stopped
- MUTEX_UNLOCK( &stream_.mutex );
-
- if ( result >= 0 ) return;
- error( RtAudioError::SYSTEM_ERROR );
-}
-
-void RtApiAlsa :: abortStream()
-{
- verifyStream();
- if ( stream_.state == STREAM_STOPPED ) {
- errorText_ = "RtApiAlsa::abortStream(): the stream is already stopped!";
- error( RtAudioError::WARNING );
- return;
- }
-
- stream_.state = STREAM_STOPPED;
- MUTEX_LOCK( &stream_.mutex );
-
- int result = 0;
- AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
- snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles;
- if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
- result = snd_pcm_drop( handle[0] );
- if ( result < 0 ) {
- errorStream_ << "RtApiAlsa::abortStream: error aborting output pcm device, " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- goto unlock;
- }
- }
-
- if ( ( stream_.mode == INPUT || stream_.mode == DUPLEX ) && !apiInfo->synchronized ) {
- result = snd_pcm_drop( handle[1] );
- if ( result < 0 ) {
- errorStream_ << "RtApiAlsa::abortStream: error aborting input pcm device, " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- goto unlock;
- }
- }
-
- unlock:
- apiInfo->runnable = false; // fixes high CPU usage when stopped
- MUTEX_UNLOCK( &stream_.mutex );
-
- if ( result >= 0 ) return;
- error( RtAudioError::SYSTEM_ERROR );
-}
-
-void RtApiAlsa :: callbackEvent()
-{
- AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
- if ( stream_.state == STREAM_STOPPED ) {
- MUTEX_LOCK( &stream_.mutex );
- while ( !apiInfo->runnable )
- pthread_cond_wait( &apiInfo->runnable_cv, &stream_.mutex );
-
- if ( stream_.state != STREAM_RUNNING ) {
- MUTEX_UNLOCK( &stream_.mutex );
- return;
- }
- MUTEX_UNLOCK( &stream_.mutex );
- }
-
- if ( stream_.state == STREAM_CLOSED ) {
- errorText_ = "RtApiAlsa::callbackEvent(): the stream is closed ... this shouldn't happen!";
- error( RtAudioError::WARNING );
- return;
- }
-
- int doStopStream = 0;
- RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;
- double streamTime = getStreamTime();
- RtAudioStreamStatus status = 0;
- if ( stream_.mode != INPUT && apiInfo->xrun[0] == true ) {
- status |= RTAUDIO_OUTPUT_UNDERFLOW;
- apiInfo->xrun[0] = false;
- }
- if ( stream_.mode != OUTPUT && apiInfo->xrun[1] == true ) {
- status |= RTAUDIO_INPUT_OVERFLOW;
- apiInfo->xrun[1] = false;
- }
- doStopStream = callback( stream_.userBuffer[0], stream_.userBuffer[1],
- stream_.bufferSize, streamTime, status, stream_.callbackInfo.userData );
-
- if ( doStopStream == 2 ) {
- abortStream();
- return;
- }
-
- MUTEX_LOCK( &stream_.mutex );
-
- // The state might change while waiting on a mutex.
- if ( stream_.state == STREAM_STOPPED ) goto unlock;
-
- int result;
- char *buffer;
- int channels;
- snd_pcm_t **handle;
- snd_pcm_sframes_t frames;
- RtAudioFormat format;
- handle = (snd_pcm_t **) apiInfo->handles;
-
- if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
-
- // Setup parameters.
- if ( stream_.doConvertBuffer[1] ) {
- buffer = stream_.deviceBuffer;
- channels = stream_.nDeviceChannels[1];
- format = stream_.deviceFormat[1];
- }
- else {
- buffer = stream_.userBuffer[1];
- channels = stream_.nUserChannels[1];
- format = stream_.userFormat;
- }
-
- // Read samples from device in interleaved/non-interleaved format.
- if ( stream_.deviceInterleaved[1] )
- result = snd_pcm_readi( handle[1], buffer, stream_.bufferSize );
- else {
- void *bufs[channels];
- size_t offset = stream_.bufferSize * formatBytes( format );
- for ( int i=0; i<channels; i++ )
- bufs[i] = (void *) (buffer + (i * offset));
- result = snd_pcm_readn( handle[1], bufs, stream_.bufferSize );
- }
-
- if ( result < (int) stream_.bufferSize ) {
- // Either an error or overrun occured.
- if ( result == -EPIPE ) {
- snd_pcm_state_t state = snd_pcm_state( handle[1] );
- if ( state == SND_PCM_STATE_XRUN ) {
- apiInfo->xrun[1] = true;
- result = snd_pcm_prepare( handle[1] );
- if ( result < 0 ) {
- errorStream_ << "RtApiAlsa::callbackEvent: error preparing device after overrun, " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- }
- }
- else {
- errorStream_ << "RtApiAlsa::callbackEvent: error, current state is " << snd_pcm_state_name( state ) << ", " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- }
- }
- else {
- errorStream_ << "RtApiAlsa::callbackEvent: audio read error, " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- }
- error( RtAudioError::WARNING );
- goto tryOutput;
- }
-
- // Do byte swapping if necessary.
- if ( stream_.doByteSwap[1] )
- byteSwapBuffer( buffer, stream_.bufferSize * channels, format );
-
- // Do buffer conversion if necessary.
- if ( stream_.doConvertBuffer[1] )
- convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );
-
- // Check stream latency
- result = snd_pcm_delay( handle[1], &frames );
- if ( result == 0 && frames > 0 ) stream_.latency[1] = frames;
- }
-
- tryOutput:
-
- if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
-
- // Setup parameters and do buffer conversion if necessary.
- if ( stream_.doConvertBuffer[0] ) {
- buffer = stream_.deviceBuffer;
- convertBuffer( buffer, stream_.userBuffer[0], stream_.convertInfo[0] );
- channels = stream_.nDeviceChannels[0];
- format = stream_.deviceFormat[0];
- }
- else {
- buffer = stream_.userBuffer[0];
- channels = stream_.nUserChannels[0];
- format = stream_.userFormat;
- }
-
- // Do byte swapping if necessary.
- if ( stream_.doByteSwap[0] )
- byteSwapBuffer(buffer, stream_.bufferSize * channels, format);
-
- // Write samples to device in interleaved/non-interleaved format.
- if ( stream_.deviceInterleaved[0] )
- result = snd_pcm_writei( handle[0], buffer, stream_.bufferSize );
- else {
- void *bufs[channels];
- size_t offset = stream_.bufferSize * formatBytes( format );
- for ( int i=0; i<channels; i++ )
- bufs[i] = (void *) (buffer + (i * offset));
- result = snd_pcm_writen( handle[0], bufs, stream_.bufferSize );
- }
-
- if ( result < (int) stream_.bufferSize ) {
- // Either an error or underrun occured.
- if ( result == -EPIPE ) {
- snd_pcm_state_t state = snd_pcm_state( handle[0] );
- if ( state == SND_PCM_STATE_XRUN ) {
- apiInfo->xrun[0] = true;
- result = snd_pcm_prepare( handle[0] );
- if ( result < 0 ) {
- errorStream_ << "RtApiAlsa::callbackEvent: error preparing device after underrun, " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- }
- else
- errorText_ = "RtApiAlsa::callbackEvent: audio write error, underrun.";
- }
- else {
- errorStream_ << "RtApiAlsa::callbackEvent: error, current state is " << snd_pcm_state_name( state ) << ", " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- }
- }
- else {
- errorStream_ << "RtApiAlsa::callbackEvent: audio write error, " << snd_strerror( result ) << ".";
- errorText_ = errorStream_.str();
- }
- error( RtAudioError::WARNING );
- goto unlock;
- }
-
- // Check stream latency
- result = snd_pcm_delay( handle[0], &frames );
- if ( result == 0 && frames > 0 ) stream_.latency[0] = frames;
- }
-
- unlock:
- MUTEX_UNLOCK( &stream_.mutex );
-
- RtApi::tickStreamTime();
- if ( doStopStream == 1 ) this->stopStream();
-}
-
-static void *alsaCallbackHandler( void *ptr )
-{
- CallbackInfo *info = (CallbackInfo *) ptr;
- RtApiAlsa *object = (RtApiAlsa *) info->object;
- bool *isRunning = &info->isRunning;
-
-#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)
- if ( &info->doRealtime ) {
- pthread_t tID = pthread_self(); // ID of this thread
- sched_param prio = { info->priority }; // scheduling priority of thread
- pthread_setschedparam( tID, SCHED_RR, &prio );
- }
-#endif
-
- while ( *isRunning == true ) {
- pthread_testcancel();
- object->callbackEvent();
- }
-
- pthread_exit( NULL );
-}
-
-//******************** End of __LINUX_ALSA__ *********************//
-#endif
-
-#if defined(__LINUX_PULSE__)
-
-// Code written by Peter Meerwald, pmeerw@pmeerw.net
-// and Tristan Matthews.
-
-#include <pulse/error.h>
-#include <pulse/simple.h>
-#include <cstdio>
-
-static const unsigned int SUPPORTED_SAMPLERATES[] = { 8000, 16000, 22050, 32000,
- 44100, 48000, 96000, 0};
-
-struct rtaudio_pa_format_mapping_t {
- RtAudioFormat rtaudio_format;
- pa_sample_format_t pa_format;
-};
-
-static const rtaudio_pa_format_mapping_t supported_sampleformats[] = {
- {RTAUDIO_SINT16, PA_SAMPLE_S16LE},
- {RTAUDIO_SINT32, PA_SAMPLE_S32LE},
- {RTAUDIO_FLOAT32, PA_SAMPLE_FLOAT32LE},
- {0, PA_SAMPLE_INVALID}};
-
-struct PulseAudioHandle {
- pa_simple *s_play;
- pa_simple *s_rec;
- pthread_t thread;
- pthread_cond_t runnable_cv;
- bool runnable;
- PulseAudioHandle() : s_play(0), s_rec(0), runnable(false) { }
-};
-
-RtApiPulse::~RtApiPulse()
-{
- if ( stream_.state != STREAM_CLOSED )
- closeStream();
-}
-
-unsigned int RtApiPulse::getDeviceCount( void )
-{
- return 1;
-}
-
-RtAudio::DeviceInfo RtApiPulse::getDeviceInfo( unsigned int /*device*/ )
-{
- RtAudio::DeviceInfo info;
- info.probed = true;
- info.name = "PulseAudio";
- info.outputChannels = 2;
- info.inputChannels = 2;
- info.duplexChannels = 2;
- info.isDefaultOutput = true;
- info.isDefaultInput = true;
-
- for ( const unsigned int *sr = SUPPORTED_SAMPLERATES; *sr; ++sr )
- info.sampleRates.push_back( *sr );
-
- info.preferredSampleRate = 48000;
- info.nativeFormats = RTAUDIO_SINT16 | RTAUDIO_SINT32 | RTAUDIO_FLOAT32;
-
- return info;
-}
-
-static void *pulseaudio_callback( void * user )
-{
- CallbackInfo *cbi = static_cast<CallbackInfo *>( user );
- RtApiPulse *context = static_cast<RtApiPulse *>( cbi->object );
- volatile bool *isRunning = &cbi->isRunning;
-
- while ( *isRunning ) {
- pthread_testcancel();
- context->callbackEvent();
- }
-
- pthread_exit( NULL );
-}
-
-void RtApiPulse::closeStream( void )
-{
- PulseAudioHandle *pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );
-
- stream_.callbackInfo.isRunning = false;
- if ( pah ) {
- MUTEX_LOCK( &stream_.mutex );
- if ( stream_.state == STREAM_STOPPED ) {
- pah->runnable = true;
- pthread_cond_signal( &pah->runnable_cv );
- }
- MUTEX_UNLOCK( &stream_.mutex );
-
- pthread_join( pah->thread, 0 );
- if ( pah->s_play ) {
- pa_simple_flush( pah->s_play, NULL );
- pa_simple_free( pah->s_play );
- }
- if ( pah->s_rec )
- pa_simple_free( pah->s_rec );
-
- pthread_cond_destroy( &pah->runnable_cv );
- delete pah;
- stream_.apiHandle = 0;
- }
-
- if ( stream_.userBuffer[0] ) {
- free( stream_.userBuffer[0] );
- stream_.userBuffer[0] = 0;
- }
- if ( stream_.userBuffer[1] ) {
- free( stream_.userBuffer[1] );
- stream_.userBuffer[1] = 0;
- }
-
- stream_.state = STREAM_CLOSED;
- stream_.mode = UNINITIALIZED;
-}
-
-void RtApiPulse::callbackEvent( void )
-{
- PulseAudioHandle *pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );
-
- if ( stream_.state == STREAM_STOPPED ) {
- MUTEX_LOCK( &stream_.mutex );
- while ( !pah->runnable )
- pthread_cond_wait( &pah->runnable_cv, &stream_.mutex );
-
- if ( stream_.state != STREAM_RUNNING ) {
- MUTEX_UNLOCK( &stream_.mutex );
- return;
- }
- MUTEX_UNLOCK( &stream_.mutex );
- }
-
- if ( stream_.state == STREAM_CLOSED ) {
- errorText_ = "RtApiPulse::callbackEvent(): the stream is closed ... "
- "this shouldn't happen!";
- error( RtAudioError::WARNING );
- return;
- }
-
- RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;
- double streamTime = getStreamTime();
- RtAudioStreamStatus status = 0;
- int doStopStream = callback( stream_.userBuffer[OUTPUT], stream_.userBuffer[INPUT],
- stream_.bufferSize, streamTime, status,
- stream_.callbackInfo.userData );
-
- if ( doStopStream == 2 ) {
- abortStream();
- return;
- }
-
- MUTEX_LOCK( &stream_.mutex );
- void *pulse_in = stream_.doConvertBuffer[INPUT] ? stream_.deviceBuffer : stream_.userBuffer[INPUT];
- void *pulse_out = stream_.doConvertBuffer[OUTPUT] ? stream_.deviceBuffer : stream_.userBuffer[OUTPUT];
-
- if ( stream_.state != STREAM_RUNNING )
- goto unlock;
-
- int pa_error;
- size_t bytes;
- if (stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
- if ( stream_.doConvertBuffer[OUTPUT] ) {
- convertBuffer( stream_.deviceBuffer,
- stream_.userBuffer[OUTPUT],
- stream_.convertInfo[OUTPUT] );
- bytes = stream_.nDeviceChannels[OUTPUT] * stream_.bufferSize *
- formatBytes( stream_.deviceFormat[OUTPUT] );
- } else
- bytes = stream_.nUserChannels[OUTPUT] * stream_.bufferSize *
- formatBytes( stream_.userFormat );
-
- if ( pa_simple_write( pah->s_play, pulse_out, bytes, &pa_error ) < 0 ) {
- errorStream_ << "RtApiPulse::callbackEvent: audio write error, " <<
- pa_strerror( pa_error ) << ".";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- }
- }
-
- if ( stream_.mode == INPUT || stream_.mode == DUPLEX) {
- if ( stream_.doConvertBuffer[INPUT] )
- bytes = stream_.nDeviceChannels[INPUT] * stream_.bufferSize *
- formatBytes( stream_.deviceFormat[INPUT] );
- else
- bytes = stream_.nUserChannels[INPUT] * stream_.bufferSize *
- formatBytes( stream_.userFormat );
-
- if ( pa_simple_read( pah->s_rec, pulse_in, bytes, &pa_error ) < 0 ) {
- errorStream_ << "RtApiPulse::callbackEvent: audio read error, " <<
- pa_strerror( pa_error ) << ".";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- }
- if ( stream_.doConvertBuffer[INPUT] ) {
- convertBuffer( stream_.userBuffer[INPUT],
- stream_.deviceBuffer,
- stream_.convertInfo[INPUT] );
- }
- }
-
- unlock:
- MUTEX_UNLOCK( &stream_.mutex );
- RtApi::tickStreamTime();
-
- if ( doStopStream == 1 )
- stopStream();
-}
-
-void RtApiPulse::startStream( void )
-{
- PulseAudioHandle *pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );
-
- if ( stream_.state == STREAM_CLOSED ) {
- errorText_ = "RtApiPulse::startStream(): the stream is not open!";
- error( RtAudioError::INVALID_USE );
- return;
- }
- if ( stream_.state == STREAM_RUNNING ) {
- errorText_ = "RtApiPulse::startStream(): the stream is already running!";
- error( RtAudioError::WARNING );
- return;
- }
-
- MUTEX_LOCK( &stream_.mutex );
-
- stream_.state = STREAM_RUNNING;
-
- pah->runnable = true;
- pthread_cond_signal( &pah->runnable_cv );
- MUTEX_UNLOCK( &stream_.mutex );
-}
-
-void RtApiPulse::stopStream( void )
-{
- PulseAudioHandle *pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );
-
- if ( stream_.state == STREAM_CLOSED ) {
- errorText_ = "RtApiPulse::stopStream(): the stream is not open!";
- error( RtAudioError::INVALID_USE );
- return;
- }
- if ( stream_.state == STREAM_STOPPED ) {
- errorText_ = "RtApiPulse::stopStream(): the stream is already stopped!";
- error( RtAudioError::WARNING );
- return;
- }
-
- stream_.state = STREAM_STOPPED;
- MUTEX_LOCK( &stream_.mutex );
-
- if ( pah && pah->s_play ) {
- int pa_error;
- if ( pa_simple_drain( pah->s_play, &pa_error ) < 0 ) {
- errorStream_ << "RtApiPulse::stopStream: error draining output device, " <<
- pa_strerror( pa_error ) << ".";
- errorText_ = errorStream_.str();
- MUTEX_UNLOCK( &stream_.mutex );
- error( RtAudioError::SYSTEM_ERROR );
- return;
- }
- }
-
- stream_.state = STREAM_STOPPED;
- MUTEX_UNLOCK( &stream_.mutex );
-}
-
-void RtApiPulse::abortStream( void )
-{
- PulseAudioHandle *pah = static_cast<PulseAudioHandle*>( stream_.apiHandle );
-
- if ( stream_.state == STREAM_CLOSED ) {
- errorText_ = "RtApiPulse::abortStream(): the stream is not open!";
- error( RtAudioError::INVALID_USE );
- return;
- }
- if ( stream_.state == STREAM_STOPPED ) {
- errorText_ = "RtApiPulse::abortStream(): the stream is already stopped!";
- error( RtAudioError::WARNING );
- return;
- }
-
- stream_.state = STREAM_STOPPED;
- MUTEX_LOCK( &stream_.mutex );
-
- if ( pah && pah->s_play ) {
- int pa_error;
- if ( pa_simple_flush( pah->s_play, &pa_error ) < 0 ) {
- errorStream_ << "RtApiPulse::abortStream: error flushing output device, " <<
- pa_strerror( pa_error ) << ".";
- errorText_ = errorStream_.str();
- MUTEX_UNLOCK( &stream_.mutex );
- error( RtAudioError::SYSTEM_ERROR );
- return;
- }
- }
-
- stream_.state = STREAM_STOPPED;
- MUTEX_UNLOCK( &stream_.mutex );
-}
-
-bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode,
- unsigned int channels, unsigned int firstChannel,
- unsigned int sampleRate, RtAudioFormat format,
- unsigned int *bufferSize, RtAudio::StreamOptions *options )
-{
- PulseAudioHandle *pah = 0;
- unsigned long bufferBytes = 0;
- pa_sample_spec ss;
-
- if ( device != 0 ) return false;
- if ( mode != INPUT && mode != OUTPUT ) return false;
- if ( channels != 1 && channels != 2 ) {
- errorText_ = "RtApiPulse::probeDeviceOpen: unsupported number of channels.";
- return false;
- }
- ss.channels = channels;
-
- if ( firstChannel != 0 ) return false;
-
- bool sr_found = false;
- for ( const unsigned int *sr = SUPPORTED_SAMPLERATES; *sr; ++sr ) {
- if ( sampleRate == *sr ) {
- sr_found = true;
- stream_.sampleRate = sampleRate;
- ss.rate = sampleRate;
- break;
- }
- }
- if ( !sr_found ) {
- errorText_ = "RtApiPulse::probeDeviceOpen: unsupported sample rate.";
- return false;
- }
-
- bool sf_found = 0;
- for ( const rtaudio_pa_format_mapping_t *sf = supported_sampleformats;
- sf->rtaudio_format && sf->pa_format != PA_SAMPLE_INVALID; ++sf ) {
- if ( format == sf->rtaudio_format ) {
- sf_found = true;
- stream_.userFormat = sf->rtaudio_format;
- stream_.deviceFormat[mode] = stream_.userFormat;
- ss.format = sf->pa_format;
- break;
- }
- }
- if ( !sf_found ) { // Use internal data format conversion.
- stream_.userFormat = format;
- stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
- ss.format = PA_SAMPLE_FLOAT32LE;
- }
-
- // Set other stream parameters.
- if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;
- else stream_.userInterleaved = true;
- stream_.deviceInterleaved[mode] = true;
- stream_.nBuffers = 1;
- stream_.doByteSwap[mode] = false;
- stream_.nUserChannels[mode] = channels;
- stream_.nDeviceChannels[mode] = channels + firstChannel;
- stream_.channelOffset[mode] = 0;
- std::string streamName = "RtAudio";
-
- // Set flags for buffer conversion.
- stream_.doConvertBuffer[mode] = false;
- if ( stream_.userFormat != stream_.deviceFormat[mode] )
- stream_.doConvertBuffer[mode] = true;
- if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] )
- stream_.doConvertBuffer[mode] = true;
-
- // Allocate necessary internal buffers.
- bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
- stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );
- if ( stream_.userBuffer[mode] == NULL ) {
- errorText_ = "RtApiPulse::probeDeviceOpen: error allocating user buffer memory.";
- goto error;
- }
- stream_.bufferSize = *bufferSize;
-
- if ( stream_.doConvertBuffer[mode] ) {
-
- bool makeBuffer = true;
- bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );
- if ( mode == INPUT ) {
- if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
- unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );
- if ( bufferBytes <= bytesOut ) makeBuffer = false;
- }
- }
-
- if ( makeBuffer ) {
- bufferBytes *= *bufferSize;
- if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );
- stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );
- if ( stream_.deviceBuffer == NULL ) {
- errorText_ = "RtApiPulse::probeDeviceOpen: error allocating device buffer memory.";
- goto error;
- }
- }
- }
-
- stream_.device[mode] = device;
-
- // Setup the buffer conversion information structure.
- if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel );
-
- if ( !stream_.apiHandle ) {
- PulseAudioHandle *pah = new PulseAudioHandle;
- if ( !pah ) {
- errorText_ = "RtApiPulse::probeDeviceOpen: error allocating memory for handle.";
- goto error;
- }
-
- stream_.apiHandle = pah;
- if ( pthread_cond_init( &pah->runnable_cv, NULL ) != 0 ) {
- errorText_ = "RtApiPulse::probeDeviceOpen: error creating condition variable.";
- goto error;
- }
- }
- pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );
-
- int error;
- if ( options && !options->streamName.empty() ) streamName = options->streamName;
- switch ( mode ) {
- case INPUT:
- pa_buffer_attr buffer_attr;
- buffer_attr.fragsize = bufferBytes;
- buffer_attr.maxlength = -1;
-
- pah->s_rec = pa_simple_new( NULL, streamName.c_str(), PA_STREAM_RECORD, NULL, "Record", &ss, NULL, &buffer_attr, &error );
- if ( !pah->s_rec ) {
- errorText_ = "RtApiPulse::probeDeviceOpen: error connecting input to PulseAudio server.";
- goto error;
- }
- break;
- case OUTPUT:
- pah->s_play = pa_simple_new( NULL, "RtAudio", PA_STREAM_PLAYBACK, NULL, "Playback", &ss, NULL, NULL, &error );
- if ( !pah->s_play ) {
- errorText_ = "RtApiPulse::probeDeviceOpen: error connecting output to PulseAudio server.";
- goto error;
- }
- break;
- default:
- goto error;
- }
-
- if ( stream_.mode == UNINITIALIZED )
- stream_.mode = mode;
- else if ( stream_.mode == mode )
- goto error;
- else
- stream_.mode = DUPLEX;
-
- if ( !stream_.callbackInfo.isRunning ) {
- stream_.callbackInfo.object = this;
- stream_.callbackInfo.isRunning = true;
- if ( pthread_create( &pah->thread, NULL, pulseaudio_callback, (void *)&stream_.callbackInfo) != 0 ) {
- errorText_ = "RtApiPulse::probeDeviceOpen: error creating thread.";
- goto error;
- }
- }
-
- stream_.state = STREAM_STOPPED;
- return true;
-
- error:
- if ( pah && stream_.callbackInfo.isRunning ) {
- pthread_cond_destroy( &pah->runnable_cv );
- delete pah;
- stream_.apiHandle = 0;
- }
-
- for ( int i=0; i<2; i++ ) {
- if ( stream_.userBuffer[i] ) {
- free( stream_.userBuffer[i] );
- stream_.userBuffer[i] = 0;
- }
- }
-
- if ( stream_.deviceBuffer ) {
- free( stream_.deviceBuffer );
- stream_.deviceBuffer = 0;
- }
-
- return FAILURE;
-}
-
-//******************** End of __LINUX_PULSE__ *********************//
-#endif
-
-#if defined(__LINUX_OSS__)
-
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/soundcard.h>
-#include <errno.h>
-#include <math.h>
-
-static void *ossCallbackHandler(void * ptr);
-
-// A structure to hold various information related to the OSS API
-// implementation.
-struct OssHandle {
- int id[2]; // device ids
- bool xrun[2];
- bool triggered;
- pthread_cond_t runnable;
-
- OssHandle()
- :triggered(false) { id[0] = 0; id[1] = 0; xrun[0] = false; xrun[1] = false; }
-};
-
-RtApiOss :: RtApiOss()
-{
- // Nothing to do here.
-}
-
-RtApiOss :: ~RtApiOss()
-{
- if ( stream_.state != STREAM_CLOSED ) closeStream();
-}
-
-unsigned int RtApiOss :: getDeviceCount( void )
-{
- int mixerfd = open( "/dev/mixer", O_RDWR, 0 );
- if ( mixerfd == -1 ) {
- errorText_ = "RtApiOss::getDeviceCount: error opening '/dev/mixer'.";
- error( RtAudioError::WARNING );
- return 0;
- }
-
- oss_sysinfo sysinfo;
- if ( ioctl( mixerfd, SNDCTL_SYSINFO, &sysinfo ) == -1 ) {
- close( mixerfd );
- errorText_ = "RtApiOss::getDeviceCount: error getting sysinfo, OSS version >= 4.0 is required.";
- error( RtAudioError::WARNING );
- return 0;
- }
-
- close( mixerfd );
- return sysinfo.numaudios;
-}
-
-RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
-{
- RtAudio::DeviceInfo info;
- info.probed = false;
-
- int mixerfd = open( "/dev/mixer", O_RDWR, 0 );
- if ( mixerfd == -1 ) {
- errorText_ = "RtApiOss::getDeviceInfo: error opening '/dev/mixer'.";
- error( RtAudioError::WARNING );
- return info;
- }
-
- oss_sysinfo sysinfo;
- int result = ioctl( mixerfd, SNDCTL_SYSINFO, &sysinfo );
- if ( result == -1 ) {
- close( mixerfd );
- errorText_ = "RtApiOss::getDeviceInfo: error getting sysinfo, OSS version >= 4.0 is required.";
- error( RtAudioError::WARNING );
- return info;
- }
-
- unsigned nDevices = sysinfo.numaudios;
- if ( nDevices == 0 ) {
- close( mixerfd );
- errorText_ = "RtApiOss::getDeviceInfo: no devices found!";
- error( RtAudioError::INVALID_USE );
- return info;
- }
-
- if ( device >= nDevices ) {
- close( mixerfd );
- errorText_ = "RtApiOss::getDeviceInfo: device ID is invalid!";
- error( RtAudioError::INVALID_USE );
- return info;
- }
-
- oss_audioinfo ainfo;
- ainfo.dev = device;
- result = ioctl( mixerfd, SNDCTL_AUDIOINFO, &ainfo );
- close( mixerfd );
- if ( result == -1 ) {
- errorStream_ << "RtApiOss::getDeviceInfo: error getting device (" << ainfo.name << ") info.";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- return info;
- }
-
- // Probe channels
- if ( ainfo.caps & PCM_CAP_OUTPUT ) info.outputChannels = ainfo.max_channels;
- if ( ainfo.caps & PCM_CAP_INPUT ) info.inputChannels = ainfo.max_channels;
- if ( ainfo.caps & PCM_CAP_DUPLEX ) {
- if ( info.outputChannels > 0 && info.inputChannels > 0 && ainfo.caps & PCM_CAP_DUPLEX )
- info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;
- }
-
- // Probe data formats ... do for input
- unsigned long mask = ainfo.iformats;
- if ( mask & AFMT_S16_LE || mask & AFMT_S16_BE )
- info.nativeFormats |= RTAUDIO_SINT16;
- if ( mask & AFMT_S8 )
- info.nativeFormats |= RTAUDIO_SINT8;
- if ( mask & AFMT_S32_LE || mask & AFMT_S32_BE )
- info.nativeFormats |= RTAUDIO_SINT32;
- if ( mask & AFMT_FLOAT )
- info.nativeFormats |= RTAUDIO_FLOAT32;
- if ( mask & AFMT_S24_LE || mask & AFMT_S24_BE )
- info.nativeFormats |= RTAUDIO_SINT24;
-
- // Check that we have at least one supported format
- if ( info.nativeFormats == 0 ) {
- errorStream_ << "RtApiOss::getDeviceInfo: device (" << ainfo.name << ") data format not supported by RtAudio.";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- return info;
- }
-
- // Probe the supported sample rates.
- info.sampleRates.clear();
- if ( ainfo.nrates ) {
- for ( unsigned int i=0; i<ainfo.nrates; i++ ) {
- for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {
- if ( ainfo.rates[i] == SAMPLE_RATES[k] ) {
- info.sampleRates.push_back( SAMPLE_RATES[k] );
-
- if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) )
- info.preferredSampleRate = SAMPLE_RATES[k];
-
- break;
- }
- }
- }
- }
- else {
- // Check min and max rate values;
- for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {
- if ( ainfo.min_rate <= (int) SAMPLE_RATES[k] && ainfo.max_rate >= (int) SAMPLE_RATES[k] ) {
- info.sampleRates.push_back( SAMPLE_RATES[k] );
-
- if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) )
- info.preferredSampleRate = SAMPLE_RATES[k];
- }
- }
- }
-
- if ( info.sampleRates.size() == 0 ) {
- errorStream_ << "RtApiOss::getDeviceInfo: no supported sample rates found for device (" << ainfo.name << ").";
- errorText_ = errorStream_.str();
- error( RtAudioError::WARNING );
- }
- else {
- info.probed = true;
- info.name = ainfo.name;
- }
-
- return info;
-}
-
-
-bool RtApiOss :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
- unsigned int firstChannel, unsigned int sampleRate,
- RtAudioFormat format, unsigned int *bufferSize,
- RtAudio::StreamOptions *options )
-{
- int mixerfd = open( "/dev/mixer", O_RDWR, 0 );
- if ( mixerfd == -1 ) {
- errorText_ = "RtApiOss::probeDeviceOpen: error opening '/dev/mixer'.";
- return FAILURE;
- }
-
- oss_sysinfo sysinfo;
- int result = ioctl( mixerfd, SNDCTL_SYSINFO, &sysinfo );
- if ( result == -1 ) {
- close( mixerfd );
- errorText_ = "RtApiOss::probeDeviceOpen: error getting sysinfo, OSS version >= 4.0 is required.";
- return FAILURE;
- }
-
- unsigned nDevices = sysinfo.numaudios;
- if ( nDevices == 0 ) {
- // This should not happen because a check is made before this function is called.
- close( mixerfd );
- errorText_ = "RtApiOss::probeDeviceOpen: no devices found!";
- return FAILURE;
- }
-
- if ( device >= nDevices ) {
- // This should not happen because a check is made before this function is called.
- close( mixerfd );
- errorText_ = "RtApiOss::probeDeviceOpen: device ID is invalid!";
- return FAILURE;
- }
-
- oss_audioinfo ainfo;
- ainfo.dev = device;
- result = ioctl( mixerfd, SNDCTL_AUDIOINFO, &ainfo );
- close( mixerfd );
- if ( result == -1 ) {
- errorStream_ << "RtApiOss::getDeviceInfo: error getting device (" << ainfo.name << ") info.";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Check if device supports input or output
- if ( ( mode == OUTPUT && !( ainfo.caps & PCM_CAP_OUTPUT ) ) ||
- ( mode == INPUT && !( ainfo.caps & PCM_CAP_INPUT ) ) ) {
- if ( mode == OUTPUT )
- errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support output.";
- else
- errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support input.";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- int flags = 0;
- OssHandle *handle = (OssHandle *) stream_.apiHandle;
- if ( mode == OUTPUT )
- flags |= O_WRONLY;
- else { // mode == INPUT
- if (stream_.mode == OUTPUT && stream_.device[0] == device) {
- // We just set the same device for playback ... close and reopen for duplex (OSS only).
- close( handle->id[0] );
- handle->id[0] = 0;
- if ( !( ainfo.caps & PCM_CAP_DUPLEX ) ) {
- errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support duplex mode.";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
- // Check that the number previously set channels is the same.
- if ( stream_.nUserChannels[0] != channels ) {
- errorStream_ << "RtApiOss::probeDeviceOpen: input/output channels must be equal for OSS duplex device (" << ainfo.name << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
- flags |= O_RDWR;
- }
- else
- flags |= O_RDONLY;
- }
-
- // Set exclusive access if specified.
- if ( options && options->flags & RTAUDIO_HOG_DEVICE ) flags |= O_EXCL;
-
- // Try to open the device.
- int fd;
- fd = open( ainfo.devnode, flags, 0 );
- if ( fd == -1 ) {
- if ( errno == EBUSY )
- errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") is busy.";
- else
- errorStream_ << "RtApiOss::probeDeviceOpen: error opening device (" << ainfo.name << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // For duplex operation, specifically set this mode (this doesn't seem to work).
- /*
- if ( flags | O_RDWR ) {
- result = ioctl( fd, SNDCTL_DSP_SETDUPLEX, NULL );
- if ( result == -1) {
- errorStream_ << "RtApiOss::probeDeviceOpen: error setting duplex mode for device (" << ainfo.name << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
- }
- */
-
- // Check the device channel support.
- stream_.nUserChannels[mode] = channels;
- if ( ainfo.max_channels < (int)(channels + firstChannel) ) {
- close( fd );
- errorStream_ << "RtApiOss::probeDeviceOpen: the device (" << ainfo.name << ") does not support requested channel parameters.";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Set the number of channels.
- int deviceChannels = channels + firstChannel;
- result = ioctl( fd, SNDCTL_DSP_CHANNELS, &deviceChannels );
- if ( result == -1 || deviceChannels < (int)(channels + firstChannel) ) {
- close( fd );
- errorStream_ << "RtApiOss::probeDeviceOpen: error setting channel parameters on device (" << ainfo.name << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
- stream_.nDeviceChannels[mode] = deviceChannels;
-
- // Get the data format mask
- int mask;
- result = ioctl( fd, SNDCTL_DSP_GETFMTS, &mask );
- if ( result == -1 ) {
- close( fd );
- errorStream_ << "RtApiOss::probeDeviceOpen: error getting device (" << ainfo.name << ") data formats.";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Determine how to set the device format.
- stream_.userFormat = format;
- int deviceFormat = -1;
- stream_.doByteSwap[mode] = false;
- if ( format == RTAUDIO_SINT8 ) {
- if ( mask & AFMT_S8 ) {
- deviceFormat = AFMT_S8;
- stream_.deviceFormat[mode] = RTAUDIO_SINT8;
- }
- }
- else if ( format == RTAUDIO_SINT16 ) {
- if ( mask & AFMT_S16_NE ) {
- deviceFormat = AFMT_S16_NE;
- stream_.deviceFormat[mode] = RTAUDIO_SINT16;
- }
- else if ( mask & AFMT_S16_OE ) {
- deviceFormat = AFMT_S16_OE;
- stream_.deviceFormat[mode] = RTAUDIO_SINT16;
- stream_.doByteSwap[mode] = true;
- }
- }
- else if ( format == RTAUDIO_SINT24 ) {
- if ( mask & AFMT_S24_NE ) {
- deviceFormat = AFMT_S24_NE;
- stream_.deviceFormat[mode] = RTAUDIO_SINT24;
- }
- else if ( mask & AFMT_S24_OE ) {
- deviceFormat = AFMT_S24_OE;
- stream_.deviceFormat[mode] = RTAUDIO_SINT24;
- stream_.doByteSwap[mode] = true;
- }
- }
- else if ( format == RTAUDIO_SINT32 ) {
- if ( mask & AFMT_S32_NE ) {
- deviceFormat = AFMT_S32_NE;
- stream_.deviceFormat[mode] = RTAUDIO_SINT32;
- }
- else if ( mask & AFMT_S32_OE ) {
- deviceFormat = AFMT_S32_OE;
- stream_.deviceFormat[mode] = RTAUDIO_SINT32;
- stream_.doByteSwap[mode] = true;
- }
- }
-
- if ( deviceFormat == -1 ) {
- // The user requested format is not natively supported by the device.
- if ( mask & AFMT_S16_NE ) {
- deviceFormat = AFMT_S16_NE;
- stream_.deviceFormat[mode] = RTAUDIO_SINT16;
- }
- else if ( mask & AFMT_S32_NE ) {
- deviceFormat = AFMT_S32_NE;
- stream_.deviceFormat[mode] = RTAUDIO_SINT32;
- }
- else if ( mask & AFMT_S24_NE ) {
- deviceFormat = AFMT_S24_NE;
- stream_.deviceFormat[mode] = RTAUDIO_SINT24;
- }
- else if ( mask & AFMT_S16_OE ) {
- deviceFormat = AFMT_S16_OE;
- stream_.deviceFormat[mode] = RTAUDIO_SINT16;
- stream_.doByteSwap[mode] = true;
- }
- else if ( mask & AFMT_S32_OE ) {
- deviceFormat = AFMT_S32_OE;
- stream_.deviceFormat[mode] = RTAUDIO_SINT32;
- stream_.doByteSwap[mode] = true;
- }
- else if ( mask & AFMT_S24_OE ) {
- deviceFormat = AFMT_S24_OE;
- stream_.deviceFormat[mode] = RTAUDIO_SINT24;
- stream_.doByteSwap[mode] = true;
- }
- else if ( mask & AFMT_S8) {
- deviceFormat = AFMT_S8;
- stream_.deviceFormat[mode] = RTAUDIO_SINT8;
- }
- }
-
- if ( stream_.deviceFormat[mode] == 0 ) {
- // This really shouldn't happen ...
- close( fd );
- errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") data format not supported by RtAudio.";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Set the data format.
- int temp = deviceFormat;
- result = ioctl( fd, SNDCTL_DSP_SETFMT, &deviceFormat );
- if ( result == -1 || deviceFormat != temp ) {
- close( fd );
- errorStream_ << "RtApiOss::probeDeviceOpen: error setting data format on device (" << ainfo.name << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Attempt to set the buffer size. According to OSS, the minimum
- // number of buffers is two. The supposed minimum buffer size is 16
- // bytes, so that will be our lower bound. The argument to this
- // call is in the form 0xMMMMSSSS (hex), where the buffer size (in
- // bytes) is given as 2^SSSS and the number of buffers as 2^MMMM.
- // We'll check the actual value used near the end of the setup
- // procedure.
- int ossBufferBytes = *bufferSize * formatBytes( stream_.deviceFormat[mode] ) * deviceChannels;
- if ( ossBufferBytes < 16 ) ossBufferBytes = 16;
- int buffers = 0;
- if ( options ) buffers = options->numberOfBuffers;
- if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) buffers = 2;
- if ( buffers < 2 ) buffers = 3;
- temp = ((int) buffers << 16) + (int)( log10( (double)ossBufferBytes ) / log10( 2.0 ) );
- result = ioctl( fd, SNDCTL_DSP_SETFRAGMENT, &temp );
- if ( result == -1 ) {
- close( fd );
- errorStream_ << "RtApiOss::probeDeviceOpen: error setting buffer size on device (" << ainfo.name << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
- stream_.nBuffers = buffers;
-
- // Save buffer size (in sample frames).
- *bufferSize = ossBufferBytes / ( formatBytes(stream_.deviceFormat[mode]) * deviceChannels );
- stream_.bufferSize = *bufferSize;
-
- // Set the sample rate.
- int srate = sampleRate;
- result = ioctl( fd, SNDCTL_DSP_SPEED, &srate );
- if ( result == -1 ) {
- close( fd );
- errorStream_ << "RtApiOss::probeDeviceOpen: error setting sample rate (" << sampleRate << ") on device (" << ainfo.name << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
-
- // Verify the sample rate setup worked.
- if ( abs( srate - sampleRate ) > 100 ) {
- close( fd );
- errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support sample rate (" << sampleRate << ").";
- errorText_ = errorStream_.str();
- return FAILURE;
- }
- stream_.sampleRate = sampleRate;
-
- if ( mode == INPUT && stream_.mode == OUTPUT && stream_.device[0] == device) {
- // We're doing duplex setup here.
- stream_.deviceFormat[0] = stream_.deviceFormat[1];
- stream_.nDeviceChannels[0] = deviceChannels;
- }
-
- // Set interleaving parameters.
- stream_.userInterleaved = true;
- stream_.deviceInterleaved[mode] = true;
- if ( options && options->flags & RTAUDIO_NONINTERLEAVED )
- stream_.userInterleaved = false;
-
- // Set flags for buffer conversion
- stream_.doConvertBuffer[mode] = false;
- if ( stream_.userFormat != stream_.deviceFormat[mode] )
- stream_.doConvertBuffer[mode] = true;
- if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] )
- stream_.doConvertBuffer[mode] = true;
- if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&
- stream_.nUserChannels[mode] > 1 )
- stream_.doConvertBuffer[mode] = true;
-
- // Allocate the stream handles if necessary and then save.
- if ( stream_.apiHandle == 0 ) {
- try {
- handle = new OssHandle;
- }
- catch ( std::bad_alloc& ) {
- errorText_ = "RtApiOss::probeDeviceOpen: error allocating OssHandle memory.";
- goto error;
- }
-
- if ( pthread_cond_init( &handle->runnable, NULL ) ) {
- errorText_ = "RtApiOss::probeDeviceOpen: error initializing pthread condition variable.";
- goto error;
- }
-
- stream_.apiHandle = (void *) handle;
- }
- else {
- handle = (OssHandle *) stream_.apiHandle;
- }
- handle->id[mode] = fd;
-
- // Allocate necessary internal buffers.
- unsigned long bufferBytes;
- bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
- stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );
- if ( stream_.userBuffer[mode] == NULL ) {
- errorText_ = "RtApiOss::probeDeviceOpen: error allocating user buffer memory.";
- goto error;
- }
-
- if ( stream_.doConvertBuffer[mode] ) {
-
- bool makeBuffer = true;
- bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );
- if ( mode == INPUT ) {
- if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
- unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );
- if ( bufferBytes <= bytesOut ) makeBuffer = false;
- }
- }
-
- if ( makeBuffer ) {
- bufferBytes *= *bufferSize;
- if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );
- stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );
- if ( stream_.deviceBuffer == NULL ) {
- errorText_ = "RtApiOss::probeDeviceOpen: error allocating device buffer memory.";
- goto error;
- }
- }
- }
-
- stream_.device[mode] = device;
- stream_.state = STREAM_STOPPED;
-
- // Setup the buffer conversion information structure.
- if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel );
-
- // Setup thread if necessary.
- if ( stream_.mode == OUTPUT && mode == INPUT ) {
- // We had already set up an output stream.
- stream_.mode = DUPLEX;
- if ( stream_.device[0] == device ) handle->id[0] = fd;
- }
- else {
- stream_.mode = mode;
-
- // Setup callback thread.
- stream_.callbackInfo.object = (void *) this;
-
- // Set the thread attributes for joinable and realtime scheduling
- // priority. The higher priority will only take affect if the
- // program is run as root or suid.
- pthread_attr_t attr;
- pthread_attr_init( &attr );
- pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
-#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)
- if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) {
- struct sched_param param;
- int priority = options->priority;
- int min = sched_get_priority_min( SCHED_RR );
- int max = sched_get_priority_max( SCHED_RR );
- if ( priority < min ) priority = min;
- else if ( priority > max ) priority = max;
- param.sched_priority = priority;
- pthread_attr_setschedparam( &attr, &param );
- pthread_attr_setschedpolicy( &attr, SCHED_RR );
- }
- else
- pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
-#else
- pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
-#endif
-
- stream_.callbackInfo.isRunning = true;
- result = pthread_create( &stream_.callbackInfo.thread, &attr, ossCallbackHandler, &stream_.callbackInfo );
- pthread_attr_destroy( &attr );
- if ( result ) {
- stream_.callbackInfo.isRunning = false;
- errorText_ = "RtApiOss::error creating callback thread!";
- goto error;
- }
- }
-
- return SUCCESS;
-
- error:
- if ( handle ) {
- pthread_cond_destroy( &handle->runnable );
- if ( handle->id[0] ) close( handle->id[0] );
- if ( handle->id[1] ) close( handle->id[1] );
- delete handle;
- stream_.apiHandle = 0;
- }
-
- for ( int i=0; i<2; i++ ) {
- if ( stream_.userBuffer[i] ) {
- free( stream_.userBuffer[i] );
- stream_.userBuffer[i] = 0;
- }
- }
-
- if ( stream_.deviceBuffer ) {
- free( stream_.deviceBuffer );
- stream_.deviceBuffer = 0;
- }
-
- return FAILURE;
-}
-
-void RtApiOss :: closeStream()
-{
- if ( stream_.state == STREAM_CLOSED ) {
- errorText_ = "RtApiOss::closeStream(): no open stream to close!";
- error( RtAudioError::WARNING );
- return;
- }
-
- OssHandle *handle = (OssHandle *) stream_.apiHandle;
- stream_.callbackInfo.isRunning = false;
- MUTEX_LOCK( &stream_.mutex );
- if ( stream_.state == STREAM_STOPPED )
- pthread_cond_signal( &handle->runnable );
- MUTEX_UNLOCK( &stream_.mutex );
- pthread_join( stream_.callbackInfo.thread, NULL );
-
- if ( stream_.state == STREAM_RUNNING ) {
- if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX )
- ioctl( handle->id[0], SNDCTL_DSP_HALT, 0 );
- else
- ioctl( handle->id[1], SNDCTL_DSP_HALT, 0 );
- stream_.state = STREAM_STOPPED;
- }
-
- if ( handle ) {
- pthread_cond_destroy( &handle->runnable );
- if ( handle->id[0] ) close( handle->id[0] );
- if ( handle->id[1] ) close( handle->id[1] );
- delete handle;
- stream_.apiHandle = 0;
- }
-
- for ( int i=0; i<2; i++ ) {
- if ( stream_.userBuffer[i] ) {
- free( stream_.userBuffer[i] );
- stream_.userBuffer[i] = 0;
- }
- }
-
- if ( stream_.deviceBuffer ) {
- free( stream_.deviceBuffer );
- stream_.deviceBuffer = 0;
- }
-
- stream_.mode = UNINITIALIZED;
- stream_.state = STREAM_CLOSED;
-}
-
-void RtApiOss :: startStream()
-{
- verifyStream();
- if ( stream_.state == STREAM_RUNNING ) {
- errorText_ = "RtApiOss::startStream(): the stream is already running!";
- error( RtAudioError::WARNING );
- return;
- }
-
- MUTEX_LOCK( &stream_.mutex );
-
- stream_.state = STREAM_RUNNING;
-
- // No need to do anything else here ... OSS automatically starts
- // when fed samples.
-
- MUTEX_UNLOCK( &stream_.mutex );
-
- OssHandle *handle = (OssHandle *) stream_.apiHandle;
- pthread_cond_signal( &handle->runnable );
-}
-
-void RtApiOss :: stopStream()
-{
- verifyStream();
- if ( stream_.state == STREAM_STOPPED ) {
- errorText_ = "RtApiOss::stopStream(): the stream is already stopped!";
- error( RtAudioError::WARNING );
- return;
- }
-
- MUTEX_LOCK( &stream_.mutex );
-
- // The state might change while waiting on a mutex.
- if ( stream_.state == STREAM_STOPPED ) {
- MUTEX_UNLOCK( &stream_.mutex );
- return;
- }
-
- int result = 0;
- OssHandle *handle = (OssHandle *) stream_.apiHandle;
- if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
-
- // Flush the output with zeros a few times.
- char *buffer;
- int samples;
- RtAudioFormat format;
-
- if ( stream_.doConvertBuffer[0] ) {
- buffer = stream_.deviceBuffer;
- samples = stream_.bufferSize * stream_.nDeviceChannels[0];
- format = stream_.deviceFormat[0];
- }
- else {
- buffer = stream_.userBuffer[0];
- samples = stream_.bufferSize * stream_.nUserChannels[0];
- format = stream_.userFormat;
- }
-
- memset( buffer, 0, samples * formatBytes(format) );
- for ( unsigned int i=0; i<stream_.nBuffers+1; i++ ) {
- result = write( handle->id[0], buffer, samples * formatBytes(format) );
- if ( result == -1 ) {
- errorText_ = "RtApiOss::stopStream: audio write error.";
- error( RtAudioError::WARNING );
- }
- }
-
- result = ioctl( handle->id[0], SNDCTL_DSP_HALT, 0 );
- if ( result == -1 ) {
- errorStream_ << "RtApiOss::stopStream: system error stopping callback procedure on device (" << stream_.device[0] << ").";
- errorText_ = errorStream_.str();
- goto unlock;
- }
- handle->triggered = false;
- }
-
- if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && handle->id[0] != handle->id[1] ) ) {
- result = ioctl( handle->id[1], SNDCTL_DSP_HALT, 0 );
- if ( result == -1 ) {
- errorStream_ << "RtApiOss::stopStream: system error stopping input callback procedure on device (" << stream_.device[0] << ").";
- errorText_ = errorStream_.str();
- goto unlock;
- }
- }
-
- unlock:
- stream_.state = STREAM_STOPPED;
- MUTEX_UNLOCK( &stream_.mutex );
-
- if ( result != -1 ) return;
- error( RtAudioError::SYSTEM_ERROR );
-}
-
-void RtApiOss :: abortStream()
-{
- verifyStream();
- if ( stream_.state == STREAM_STOPPED ) {
- errorText_ = "RtApiOss::abortStream(): the stream is already stopped!";
- error( RtAudioError::WARNING );
- return;
- }
-
- MUTEX_LOCK( &stream_.mutex );
-
- // The state might change while waiting on a mutex.
- if ( stream_.state == STREAM_STOPPED ) {
- MUTEX_UNLOCK( &stream_.mutex );
- return;
- }
-
- int result = 0;
- OssHandle *handle = (OssHandle *) stream_.apiHandle;
- if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
- result = ioctl( handle->id[0], SNDCTL_DSP_HALT, 0 );
- if ( result == -1 ) {
- errorStream_ << "RtApiOss::abortStream: system error stopping callback procedure on device (" << stream_.device[0] << ").";
- errorText_ = errorStream_.str();
- goto unlock;
- }
- handle->triggered = false;
- }
-
- if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && handle->id[0] != handle->id[1] ) ) {
- result = ioctl( handle->id[1], SNDCTL_DSP_HALT, 0 );
- if ( result == -1 ) {
- errorStream_ << "RtApiOss::abortStream: system error stopping input callback procedure on device (" << stream_.device[0] << ").";
- errorText_ = errorStream_.str();
- goto unlock;
- }
- }
-
- unlock:
- stream_.state = STREAM_STOPPED;
- MUTEX_UNLOCK( &stream_.mutex );
-
- if ( result != -1 ) return;
- error( RtAudioError::SYSTEM_ERROR );
-}
-
-void RtApiOss :: callbackEvent()
-{
- OssHandle *handle = (OssHandle *) stream_.apiHandle;
- if ( stream_.state == STREAM_STOPPED ) {
- MUTEX_LOCK( &stream_.mutex );
- pthread_cond_wait( &handle->runnable, &stream_.mutex );
- if ( stream_.state != STREAM_RUNNING ) {
- MUTEX_UNLOCK( &stream_.mutex );
- return;
- }
- MUTEX_UNLOCK( &stream_.mutex );
- }
-
- if ( stream_.state == STREAM_CLOSED ) {
- errorText_ = "RtApiOss::callbackEvent(): the stream is closed ... this shouldn't happen!";
- error( RtAudioError::WARNING );
- return;
- }
-
- // Invoke user callback to get fresh output data.
- int doStopStream = 0;
- RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;
- double streamTime = getStreamTime();
- RtAudioStreamStatus status = 0;
- if ( stream_.mode != INPUT && handle->xrun[0] == true ) {
- status |= RTAUDIO_OUTPUT_UNDERFLOW;
- handle->xrun[0] = false;
- }
- if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) {
- status |= RTAUDIO_INPUT_OVERFLOW;
- handle->xrun[1] = false;
- }
- doStopStream = callback( stream_.userBuffer[0], stream_.userBuffer[1],
- stream_.bufferSize, streamTime, status, stream_.callbackInfo.userData );
- if ( doStopStream == 2 ) {
- this->abortStream();
- return;
- }
-
- MUTEX_LOCK( &stream_.mutex );
-
- // The state might change while waiting on a mutex.
- if ( stream_.state == STREAM_STOPPED ) goto unlock;
-
- int result;
- char *buffer;
- int samples;
- RtAudioFormat format;
-
- if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
-
- // Setup parameters and do buffer conversion if necessary.
- if ( stream_.doConvertBuffer[0] ) {
- buffer = stream_.deviceBuffer;
- convertBuffer( buffer, stream_.userBuffer[0], stream_.convertInfo[0] );
- samples = stream_.bufferSize * stream_.nDeviceChannels[0];
- format = stream_.deviceFormat[0];
- }
- else {
- buffer = stream_.userBuffer[0];
- samples = stream_.bufferSize * stream_.nUserChannels[0];
- format = stream_.userFormat;
- }
-
- // Do byte swapping if necessary.
- if ( stream_.doByteSwap[0] )
- byteSwapBuffer( buffer, samples, format );
-
- if ( stream_.mode == DUPLEX && handle->triggered == false ) {
- int trig = 0;
- ioctl( handle->id[0], SNDCTL_DSP_SETTRIGGER, &trig );
- result = write( handle->id[0], buffer, samples * formatBytes(format) );
- trig = PCM_ENABLE_INPUT|PCM_ENABLE_OUTPUT;
- ioctl( handle->id[0], SNDCTL_DSP_SETTRIGGER, &trig );
- handle->triggered = true;
- }
- else
- // Write samples to device.
- result = write( handle->id[0], buffer, samples * formatBytes(format) );
-
- if ( result == -1 ) {
- // We'll assume this is an underrun, though there isn't a
- // specific means for determining that.
- handle->xrun[0] = true;
- errorText_ = "RtApiOss::callbackEvent: audio write error.";
- error( RtAudioError::WARNING );
- // Continue on to input section.
- }
- }
-
- if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
-
- // Setup parameters.
- if ( stream_.doConvertBuffer[1] ) {
- buffer = stream_.deviceBuffer;
- samples = stream_.bufferSize * stream_.nDeviceChannels[1];
- format = stream_.deviceFormat[1];
- }
- else {
- buffer = stream_.userBuffer[1];
- samples = stream_.bufferSize * stream_.nUserChannels[1];
- format = stream_.userFormat;
- }
-
- // Read samples from device.
- result = read( handle->id[1], buffer, samples * formatBytes(format) );
-
- if ( result == -1 ) {
- // We'll assume this is an overrun, though there isn't a
- // specific means for determining that.
- handle->xrun[1] = true;
- errorText_ = "RtApiOss::callbackEvent: audio read error.";
- error( RtAudioError::WARNING );
- goto unlock;
- }
-
- // Do byte swapping if necessary.
- if ( stream_.doByteSwap[1] )
- byteSwapBuffer( buffer, samples, format );
-
- // Do buffer conversion if necessary.
- if ( stream_.doConvertBuffer[1] )
- convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );
- }
-
- unlock:
- MUTEX_UNLOCK( &stream_.mutex );
-
- RtApi::tickStreamTime();
- if ( doStopStream == 1 ) this->stopStream();
-}
-
-static void *ossCallbackHandler( void *ptr )
-{
- CallbackInfo *info = (CallbackInfo *) ptr;
- RtApiOss *object = (RtApiOss *) info->object;
- bool *isRunning = &info->isRunning;
-
- while ( *isRunning == true ) {
- pthread_testcancel();
- object->callbackEvent();
- }
-
- pthread_exit( NULL );
-}
-
-//******************** End of __LINUX_OSS__ *********************//
-#endif
-
-
-// *************************************************** //
-//
-// Protected common (OS-independent) RtAudio methods.
-//
-// *************************************************** //
-
-// This method can be modified to control the behavior of error
-// message printing.
-void RtApi :: error( RtAudioError::Type type )
-{
- errorStream_.str(""); // clear the ostringstream
-
- RtAudioErrorCallback errorCallback = (RtAudioErrorCallback) stream_.callbackInfo.errorCallback;
- if ( errorCallback ) {
- // abortStream() can generate new error messages. Ignore them. Just keep original one.
-
- if ( firstErrorOccurred_ )
- return;
-
- firstErrorOccurred_ = true;
- const std::string errorMessage = errorText_;
-
- if ( type != RtAudioError::WARNING && stream_.state != STREAM_STOPPED) {
- stream_.callbackInfo.isRunning = false; // exit from the thread
- abortStream();
- }
-
- errorCallback( type, errorMessage );
- firstErrorOccurred_ = false;
- return;
- }
-
- if ( type == RtAudioError::WARNING && showWarnings_ == true )
- std::cerr << '\n' << errorText_ << "\n\n";
- else if ( type != RtAudioError::WARNING )
- throw( RtAudioError( errorText_, type ) );
-}
-
-void RtApi :: verifyStream()
-{
- if ( stream_.state == STREAM_CLOSED ) {
- errorText_ = "RtApi:: a stream is not open!";
- error( RtAudioError::INVALID_USE );
- }
-}
-
-void RtApi :: clearStreamInfo()
-{
- stream_.mode = UNINITIALIZED;
- stream_.state = STREAM_CLOSED;
- stream_.sampleRate = 0;
- stream_.bufferSize = 0;
- stream_.nBuffers = 0;
- stream_.userFormat = 0;
- stream_.userInterleaved = true;
- stream_.streamTime = 0.0;
- stream_.apiHandle = 0;
- stream_.deviceBuffer = 0;
- stream_.callbackInfo.callback = 0;
- stream_.callbackInfo.userData = 0;
- stream_.callbackInfo.isRunning = false;
- stream_.callbackInfo.errorCallback = 0;
- for ( int i=0; i<2; i++ ) {
- stream_.device[i] = 11111;
- stream_.doConvertBuffer[i] = false;
- stream_.deviceInterleaved[i] = true;
- stream_.doByteSwap[i] = false;
- stream_.nUserChannels[i] = 0;
- stream_.nDeviceChannels[i] = 0;
- stream_.channelOffset[i] = 0;
- stream_.deviceFormat[i] = 0;
- stream_.latency[i] = 0;
- stream_.userBuffer[i] = 0;
- stream_.convertInfo[i].channels = 0;
- stream_.convertInfo[i].inJump = 0;
- stream_.convertInfo[i].outJump = 0;
- stream_.convertInfo[i].inFormat = 0;
- stream_.convertInfo[i].outFormat = 0;
- stream_.convertInfo[i].inOffset.clear();
- stream_.convertInfo[i].outOffset.clear();
- }
-}
-
-unsigned int RtApi :: formatBytes( RtAudioFormat format )
-{
- if ( format == RTAUDIO_SINT16 )
- return 2;
- else if ( format == RTAUDIO_SINT32 || format == RTAUDIO_FLOAT32 )
- return 4;
- else if ( format == RTAUDIO_FLOAT64 )
- return 8;
- else if ( format == RTAUDIO_SINT24 )
- return 3;
- else if ( format == RTAUDIO_SINT8 )
- return 1;
-
- errorText_ = "RtApi::formatBytes: undefined format.";
- error( RtAudioError::WARNING );
-
- return 0;
-}
-
-void RtApi :: setConvertInfo( StreamMode mode, unsigned int firstChannel )
-{
- if ( mode == INPUT ) { // convert device to user buffer
- stream_.convertInfo[mode].inJump = stream_.nDeviceChannels[1];
- stream_.convertInfo[mode].outJump = stream_.nUserChannels[1];
- stream_.convertInfo[mode].inFormat = stream_.deviceFormat[1];
- stream_.convertInfo[mode].outFormat = stream_.userFormat;
- }
- else { // convert user to device buffer
- stream_.convertInfo[mode].inJump = stream_.nUserChannels[0];
- stream_.convertInfo[mode].outJump = stream_.nDeviceChannels[0];
- stream_.convertInfo[mode].inFormat = stream_.userFormat;
- stream_.convertInfo[mode].outFormat = stream_.deviceFormat[0];
- }
-
- if ( stream_.convertInfo[mode].inJump < stream_.convertInfo[mode].outJump )
- stream_.convertInfo[mode].channels = stream_.convertInfo[mode].inJump;
- else
- stream_.convertInfo[mode].channels = stream_.convertInfo[mode].outJump;
-
- // Set up the interleave/deinterleave offsets.
- if ( stream_.deviceInterleaved[mode] != stream_.userInterleaved ) {
- if ( ( mode == OUTPUT && stream_.deviceInterleaved[mode] ) ||
- ( mode == INPUT && stream_.userInterleaved ) ) {
- for ( int k=0; k<stream_.convertInfo[mode].channels; k++ ) {
- stream_.convertInfo[mode].inOffset.push_back( k * stream_.bufferSize );
- stream_.convertInfo[mode].outOffset.push_back( k );
- stream_.convertInfo[mode].inJump = 1;
- }
- }
- else {
- for ( int k=0; k<stream_.convertInfo[mode].channels; k++ ) {
- stream_.convertInfo[mode].inOffset.push_back( k );
- stream_.convertInfo[mode].outOffset.push_back( k * stream_.bufferSize );
- stream_.convertInfo[mode].outJump = 1;
- }
- }
- }
- else { // no (de)interleaving
- if ( stream_.userInterleaved ) {
- for ( int k=0; k<stream_.convertInfo[mode].channels; k++ ) {
- stream_.convertInfo[mode].inOffset.push_back( k );
- stream_.convertInfo[mode].outOffset.push_back( k );
- }
- }
- else {
- for ( int k=0; k<stream_.convertInfo[mode].channels; k++ ) {
- stream_.convertInfo[mode].inOffset.push_back( k * stream_.bufferSize );
- stream_.convertInfo[mode].outOffset.push_back( k * stream_.bufferSize );
- stream_.convertInfo[mode].inJump = 1;
- stream_.convertInfo[mode].outJump = 1;
- }
- }
- }
-
- // Add channel offset.
- if ( firstChannel > 0 ) {
- if ( stream_.deviceInterleaved[mode] ) {
- if ( mode == OUTPUT ) {
- for ( int k=0; k<stream_.convertInfo[mode].channels; k++ )
- stream_.convertInfo[mode].outOffset[k] += firstChannel;
- }
- else {
- for ( int k=0; k<stream_.convertInfo[mode].channels; k++ )
- stream_.convertInfo[mode].inOffset[k] += firstChannel;
- }
- }
- else {
- if ( mode == OUTPUT ) {
- for ( int k=0; k<stream_.convertInfo[mode].channels; k++ )
- stream_.convertInfo[mode].outOffset[k] += ( firstChannel * stream_.bufferSize );
- }
- else {
- for ( int k=0; k<stream_.convertInfo[mode].channels; k++ )
- stream_.convertInfo[mode].inOffset[k] += ( firstChannel * stream_.bufferSize );
- }
- }
- }
-}
-
-void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info )
-{
- // This function does format conversion, input/output channel compensation, and
- // data interleaving/deinterleaving. 24-bit integers are assumed to occupy
- // the lower three bytes of a 32-bit integer.
-
- // Clear our device buffer when in/out duplex device channels are different
- if ( outBuffer == stream_.deviceBuffer && stream_.mode == DUPLEX &&
- ( stream_.nDeviceChannels[0] < stream_.nDeviceChannels[1] ) )
- memset( outBuffer, 0, stream_.bufferSize * info.outJump * formatBytes( info.outFormat ) );
-
- int j;
- if (info.outFormat == RTAUDIO_FLOAT64) {
- Float64 scale;
- Float64 *out = (Float64 *)outBuffer;
-
- if (info.inFormat == RTAUDIO_SINT8) {
- signed char *in = (signed char *)inBuffer;
- scale = 1.0 / 127.5;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];
- out[info.outOffset[j]] += 0.5;
- out[info.outOffset[j]] *= scale;
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_SINT16) {
- Int16 *in = (Int16 *)inBuffer;
- scale = 1.0 / 32767.5;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];
- out[info.outOffset[j]] += 0.5;
- out[info.outOffset[j]] *= scale;
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_SINT24) {
- Int24 *in = (Int24 *)inBuffer;
- scale = 1.0 / 8388607.5;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Float64) (in[info.inOffset[j]].asInt());
- out[info.outOffset[j]] += 0.5;
- out[info.outOffset[j]] *= scale;
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_SINT32) {
- Int32 *in = (Int32 *)inBuffer;
- scale = 1.0 / 2147483647.5;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];
- out[info.outOffset[j]] += 0.5;
- out[info.outOffset[j]] *= scale;
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_FLOAT32) {
- Float32 *in = (Float32 *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_FLOAT64) {
- // Channel compensation and/or (de)interleaving only.
- Float64 *in = (Float64 *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = in[info.inOffset[j]];
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- }
- else if (info.outFormat == RTAUDIO_FLOAT32) {
- Float32 scale;
- Float32 *out = (Float32 *)outBuffer;
-
- if (info.inFormat == RTAUDIO_SINT8) {
- signed char *in = (signed char *)inBuffer;
- scale = (Float32) ( 1.0 / 127.5 );
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];
- out[info.outOffset[j]] += 0.5;
- out[info.outOffset[j]] *= scale;
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_SINT16) {
- Int16 *in = (Int16 *)inBuffer;
- scale = (Float32) ( 1.0 / 32767.5 );
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];
- out[info.outOffset[j]] += 0.5;
- out[info.outOffset[j]] *= scale;
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_SINT24) {
- Int24 *in = (Int24 *)inBuffer;
- scale = (Float32) ( 1.0 / 8388607.5 );
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Float32) (in[info.inOffset[j]].asInt());
- out[info.outOffset[j]] += 0.5;
- out[info.outOffset[j]] *= scale;
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_SINT32) {
- Int32 *in = (Int32 *)inBuffer;
- scale = (Float32) ( 1.0 / 2147483647.5 );
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];
- out[info.outOffset[j]] += 0.5;
- out[info.outOffset[j]] *= scale;
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_FLOAT32) {
- // Channel compensation and/or (de)interleaving only.
- Float32 *in = (Float32 *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = in[info.inOffset[j]];
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_FLOAT64) {
- Float64 *in = (Float64 *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- }
- else if (info.outFormat == RTAUDIO_SINT32) {
- Int32 *out = (Int32 *)outBuffer;
- if (info.inFormat == RTAUDIO_SINT8) {
- signed char *in = (signed char *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Int32) in[info.inOffset[j]];
- out[info.outOffset[j]] <<= 24;
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_SINT16) {
- Int16 *in = (Int16 *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Int32) in[info.inOffset[j]];
- out[info.outOffset[j]] <<= 16;
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_SINT24) {
- Int24 *in = (Int24 *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Int32) in[info.inOffset[j]].asInt();
- out[info.outOffset[j]] <<= 8;
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_SINT32) {
- // Channel compensation and/or (de)interleaving only.
- Int32 *in = (Int32 *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = in[info.inOffset[j]];
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_FLOAT32) {
- Float32 *in = (Float32 *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.5 - 0.5);
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_FLOAT64) {
- Float64 *in = (Float64 *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.5 - 0.5);
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- }
- else if (info.outFormat == RTAUDIO_SINT24) {
- Int24 *out = (Int24 *)outBuffer;
- if (info.inFormat == RTAUDIO_SINT8) {
- signed char *in = (signed char *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] << 16);
- //out[info.outOffset[j]] <<= 16;
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_SINT16) {
- Int16 *in = (Int16 *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] << 8);
- //out[info.outOffset[j]] <<= 8;
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_SINT24) {
- // Channel compensation and/or (de)interleaving only.
- Int24 *in = (Int24 *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = in[info.inOffset[j]];
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_SINT32) {
- Int32 *in = (Int32 *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] >> 8);
- //out[info.outOffset[j]] >>= 8;
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_FLOAT32) {
- Float32 *in = (Float32 *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 8388607.5 - 0.5);
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_FLOAT64) {
- Float64 *in = (Float64 *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 8388607.5 - 0.5);
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- }
- else if (info.outFormat == RTAUDIO_SINT16) {
- Int16 *out = (Int16 *)outBuffer;
- if (info.inFormat == RTAUDIO_SINT8) {
- signed char *in = (signed char *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Int16) in[info.inOffset[j]];
- out[info.outOffset[j]] <<= 8;
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_SINT16) {
- // Channel compensation and/or (de)interleaving only.
- Int16 *in = (Int16 *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = in[info.inOffset[j]];
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_SINT24) {
- Int24 *in = (Int24 *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]].asInt() >> 8);
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_SINT32) {
- Int32 *in = (Int32 *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Int16) ((in[info.inOffset[j]] >> 16) & 0x0000ffff);
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_FLOAT32) {
- Float32 *in = (Float32 *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]] * 32767.5 - 0.5);
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_FLOAT64) {
- Float64 *in = (Float64 *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]] * 32767.5 - 0.5);
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- }
- else if (info.outFormat == RTAUDIO_SINT8) {
- signed char *out = (signed char *)outBuffer;
- if (info.inFormat == RTAUDIO_SINT8) {
- // Channel compensation and/or (de)interleaving only.
- signed char *in = (signed char *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = in[info.inOffset[j]];
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- if (info.inFormat == RTAUDIO_SINT16) {
- Int16 *in = (Int16 *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (signed char) ((in[info.inOffset[j]] >> 8) & 0x00ff);
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_SINT24) {
- Int24 *in = (Int24 *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]].asInt() >> 16);
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_SINT32) {
- Int32 *in = (Int32 *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (signed char) ((in[info.inOffset[j]] >> 24) & 0x000000ff);
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_FLOAT32) {
- Float32 *in = (Float32 *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]] * 127.5 - 0.5);
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- else if (info.inFormat == RTAUDIO_FLOAT64) {
- Float64 *in = (Float64 *)inBuffer;
- for (unsigned int i=0; i<stream_.bufferSize; i++) {
- for (j=0; j<info.channels; j++) {
- out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]] * 127.5 - 0.5);
- }
- in += info.inJump;
- out += info.outJump;
- }
- }
- }
-}
-
-//static inline uint16_t bswap_16(uint16_t x) { return (x>>8) | (x<<8); }
-//static inline uint32_t bswap_32(uint32_t x) { return (bswap_16(x&0xffff)<<16) | (bswap_16(x>>16)); }
-//static inline uint64_t bswap_64(uint64_t x) { return (((unsigned long long)bswap_32(x&0xffffffffull))<<32) | (bswap_32(x>>32)); }
-
-void RtApi :: byteSwapBuffer( char *buffer, unsigned int samples, RtAudioFormat format )
-{
- register char val;
- register char *ptr;
-
- ptr = buffer;
- if ( format == RTAUDIO_SINT16 ) {
- for ( unsigned int i=0; i<samples; i++ ) {
- // Swap 1st and 2nd bytes.
- val = *(ptr);
- *(ptr) = *(ptr+1);
- *(ptr+1) = val;
-
- // Increment 2 bytes.
- ptr += 2;
- }
- }
- else if ( format == RTAUDIO_SINT32 ||
- format == RTAUDIO_FLOAT32 ) {
- for ( unsigned int i=0; i<samples; i++ ) {
- // Swap 1st and 4th bytes.
- val = *(ptr);
- *(ptr) = *(ptr+3);
- *(ptr+3) = val;
-
- // Swap 2nd and 3rd bytes.
- ptr += 1;
- val = *(ptr);
- *(ptr) = *(ptr+1);
- *(ptr+1) = val;
-
- // Increment 3 more bytes.
- ptr += 3;
- }
- }
- else if ( format == RTAUDIO_SINT24 ) {
- for ( unsigned int i=0; i<samples; i++ ) {
- // Swap 1st and 3rd bytes.
- val = *(ptr);
- *(ptr) = *(ptr+2);
- *(ptr+2) = val;
-
- // Increment 2 more bytes.
- ptr += 2;
- }
- }
- else if ( format == RTAUDIO_FLOAT64 ) {
- for ( unsigned int i=0; i<samples; i++ ) {
- // Swap 1st and 8th bytes
- val = *(ptr);
- *(ptr) = *(ptr+7);
- *(ptr+7) = val;
-
- // Swap 2nd and 7th bytes
- ptr += 1;
- val = *(ptr);
- *(ptr) = *(ptr+5);
- *(ptr+5) = val;
-
- // Swap 3rd and 6th bytes
- ptr += 1;
- val = *(ptr);
- *(ptr) = *(ptr+3);
- *(ptr+3) = val;
-
- // Swap 4th and 5th bytes
- ptr += 1;
- val = *(ptr);
- *(ptr) = *(ptr+1);
- *(ptr+1) = val;
-
- // Increment 5 more bytes.
- ptr += 5;
- }
- }
-}
-
- // Indentation settings for Vim and Emacs
- //
- // Local Variables:
- // c-basic-offset: 2
- // indent-tabs-mode: nil
- // End:
- //
- // vim: et sts=2 sw=2
-
-#endif
+#ifdef RTAUDIO_ENABLED
+/************************************************************************/
+/*! \class RtAudio
+ \brief Realtime audio i/o C++ classes.
+
+ RtAudio provides a common API (Application Programming Interface)
+ for realtime audio input/output across Linux (native ALSA, Jack,
+ and OSS), Macintosh OS X (CoreAudio and Jack), and Windows
+ (DirectSound, ASIO and WASAPI) operating systems.
+
+ RtAudio WWW site: http://www.music.mcgill.ca/~gary/rtaudio/
+
+ RtAudio: realtime audio i/o C++ classes
+ Copyright (c) 2001-2014 Gary P. Scavone
+
+ 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.
+
+ Any person wishing to distribute modifications to the Software is
+ asked to send the modifications to the original developer so that
+ they can be incorporated into the canonical version. This is,
+ however, not a binding provision of this license.
+
+ 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.
+*/
+/************************************************************************/
+
+// RtAudio: Version 4.1.1
+
+#include "RtAudio.h"
+#include <iostream>
+#include <cstdlib>
+#include <cstring>
+#include <climits>
+#include <algorithm>
+
+// Static variable definitions.
+const unsigned int RtApi::MAX_SAMPLE_RATES = 14;
+const unsigned int RtApi::SAMPLE_RATES[] = {
+ 4000, 5512, 8000, 9600, 11025, 16000, 22050,
+ 32000, 44100, 48000, 88200, 96000, 176400, 192000
+};
+
+#if defined(__WINDOWS_DS__) || defined(__WINDOWS_ASIO__) || defined(__WINDOWS_WASAPI__)
+#ifdef WINRT_ENABLED
+ #define MUTEX_INITIALIZE(A) InitializeCriticalSectionEx(A, 0, 0)
+#else
+ #define MUTEX_INITIALIZE(A) InitializeCriticalSection(A)
+#endif
+ #define MUTEX_DESTROY(A) DeleteCriticalSection(A)
+ #define MUTEX_LOCK(A) EnterCriticalSection(A)
+ #define MUTEX_UNLOCK(A) LeaveCriticalSection(A)
+
+ #include "tchar.h"
+
+ static std::string convertCharPointerToStdString(const char *text)
+ {
+ return std::string(text);
+ }
+
+ static std::string convertCharPointerToStdString(const wchar_t *text)
+ {
+ int length = WideCharToMultiByte(CP_UTF8, 0, text, -1, NULL, 0, NULL, NULL);
+ std::string s( length-1, '\0' );
+ WideCharToMultiByte(CP_UTF8, 0, text, -1, &s[0], length, NULL, NULL);
+ return s;
+ }
+
+#elif defined(__LINUX_ALSA__) || defined(__LINUX_PULSE__) || defined(__UNIX_JACK__) || defined(__LINUX_OSS__) || defined(__MACOSX_CORE__)
+ // pthread API
+ #define MUTEX_INITIALIZE(A) pthread_mutex_init(A, NULL)
+ #define MUTEX_DESTROY(A) pthread_mutex_destroy(A)
+ #define MUTEX_LOCK(A) pthread_mutex_lock(A)
+ #define MUTEX_UNLOCK(A) pthread_mutex_unlock(A)
+#else
+ #define MUTEX_INITIALIZE(A) abs(*A) // dummy definitions
+ #define MUTEX_DESTROY(A) abs(*A) // dummy definitions
+#endif
+
+// *************************************************** //
+//
+// RtAudio definitions.
+//
+// *************************************************** //
+
+std::string RtAudio :: getVersion( void ) throw()
+{
+ return RTAUDIO_VERSION;
+}
+
+void RtAudio :: getCompiledApi( std::vector<RtAudio::Api> &apis ) throw()
+{
+ apis.clear();
+
+ // The order here will control the order of RtAudio's API search in
+ // the constructor.
+#if defined(__UNIX_JACK__)
+ apis.push_back( UNIX_JACK );
+#endif
+#if defined(__LINUX_ALSA__)
+ apis.push_back( LINUX_ALSA );
+#endif
+#if defined(__LINUX_PULSE__)
+ apis.push_back( LINUX_PULSE );
+#endif
+#if defined(__LINUX_OSS__)
+ apis.push_back( LINUX_OSS );
+#endif
+#if defined(__WINDOWS_ASIO__)
+ apis.push_back( WINDOWS_ASIO );
+#endif
+#if defined(__WINDOWS_WASAPI__)
+ apis.push_back( WINDOWS_WASAPI );
+#endif
+#if defined(__WINDOWS_DS__)
+ apis.push_back( WINDOWS_DS );
+#endif
+#if defined(__MACOSX_CORE__)
+ apis.push_back( MACOSX_CORE );
+#endif
+#if defined(__RTAUDIO_DUMMY__)
+ apis.push_back( RTAUDIO_DUMMY );
+#endif
+}
+
+void RtAudio :: openRtApi( RtAudio::Api api )
+{
+ delete rtapi_;
+ rtapi_ = 0;
+
+#if defined(__UNIX_JACK__)
+ if ( api == UNIX_JACK )
+ rtapi_ = new RtApiJack();
+#endif
+#if defined(__LINUX_ALSA__)
+ if ( api == LINUX_ALSA )
+ rtapi_ = new RtApiAlsa();
+#endif
+#if defined(__LINUX_PULSE__)
+ if ( api == LINUX_PULSE )
+ rtapi_ = new RtApiPulse();
+#endif
+#if defined(__LINUX_OSS__)
+ if ( api == LINUX_OSS )
+ rtapi_ = new RtApiOss();
+#endif
+#if defined(__WINDOWS_ASIO__)
+ if ( api == WINDOWS_ASIO )
+ rtapi_ = new RtApiAsio();
+#endif
+#if defined(__WINDOWS_WASAPI__)
+ if ( api == WINDOWS_WASAPI )
+ rtapi_ = new RtApiWasapi();
+#endif
+#if defined(__WINDOWS_DS__)
+ if ( api == WINDOWS_DS )
+ rtapi_ = new RtApiDs();
+#endif
+#if defined(__MACOSX_CORE__)
+ if ( api == MACOSX_CORE )
+ rtapi_ = new RtApiCore();
+#endif
+#if defined(__RTAUDIO_DUMMY__)
+ if ( api == RTAUDIO_DUMMY )
+ rtapi_ = new RtApiDummy();
+#endif
+}
+
+RtAudio :: RtAudio( RtAudio::Api api )
+{
+ rtapi_ = 0;
+
+ if ( api != UNSPECIFIED ) {
+ // Attempt to open the specified API.
+ openRtApi( api );
+ if ( rtapi_ ) return;
+
+ // No compiled support for specified API value. Issue a debug
+ // warning and continue as if no API was specified.
+ std::cerr << "\nRtAudio: no compiled support for specified API argument!\n" << std::endl;
+ }
+
+ // Iterate through the compiled APIs and return as soon as we find
+ // one with at least one device or we reach the end of the list.
+ std::vector< RtAudio::Api > apis;
+ getCompiledApi( apis );
+ for ( unsigned int i=0; i<apis.size(); i++ ) {
+ openRtApi( apis[i] );
+ if ( rtapi_ && rtapi_->getDeviceCount() ) break;
+ }
+
+ if ( rtapi_ ) return;
+
+ // It should not be possible to get here because the preprocessor
+ // definition __RTAUDIO_DUMMY__ is automatically defined if no
+ // API-specific definitions are passed to the compiler. But just in
+ // case something weird happens, we'll thow an error.
+ std::string errorText = "\nRtAudio: no compiled API support found ... critical error!!\n\n";
+ throw( RtAudioError( errorText, RtAudioError::UNSPECIFIED ) );
+}
+
+RtAudio :: ~RtAudio() throw()
+{
+ delete rtapi_;
+}
+
+void RtAudio :: openStream( RtAudio::StreamParameters *outputParameters,
+ RtAudio::StreamParameters *inputParameters,
+ RtAudioFormat format, unsigned int sampleRate,
+ unsigned int *bufferFrames,
+ RtAudioCallback callback, void *userData,
+ RtAudio::StreamOptions *options,
+ RtAudioErrorCallback errorCallback )
+{
+ return rtapi_->openStream( outputParameters, inputParameters, format,
+ sampleRate, bufferFrames, callback,
+ userData, options, errorCallback );
+}
+
+// *************************************************** //
+//
+// Public RtApi definitions (see end of file for
+// private or protected utility functions).
+//
+// *************************************************** //
+
+RtApi :: RtApi()
+{
+ stream_.state = STREAM_CLOSED;
+ stream_.mode = UNINITIALIZED;
+ stream_.apiHandle = 0;
+ stream_.userBuffer[0] = 0;
+ stream_.userBuffer[1] = 0;
+ MUTEX_INITIALIZE( &stream_.mutex );
+ showWarnings_ = true;
+ firstErrorOccurred_ = false;
+}
+
+RtApi :: ~RtApi()
+{
+ MUTEX_DESTROY( &stream_.mutex );
+}
+
+void RtApi :: openStream( RtAudio::StreamParameters *oParams,
+ RtAudio::StreamParameters *iParams,
+ RtAudioFormat format, unsigned int sampleRate,
+ unsigned int *bufferFrames,
+ RtAudioCallback callback, void *userData,
+ RtAudio::StreamOptions *options,
+ RtAudioErrorCallback errorCallback )
+{
+ if ( stream_.state != STREAM_CLOSED ) {
+ errorText_ = "RtApi::openStream: a stream is already open!";
+ error( RtAudioError::INVALID_USE );
+ return;
+ }
+
+ // Clear stream information potentially left from a previously open stream.
+ clearStreamInfo();
+
+ if ( oParams && oParams->nChannels < 1 ) {
+ errorText_ = "RtApi::openStream: a non-NULL output StreamParameters structure cannot have an nChannels value less than one.";
+ error( RtAudioError::INVALID_USE );
+ return;
+ }
+
+ if ( iParams && iParams->nChannels < 1 ) {
+ errorText_ = "RtApi::openStream: a non-NULL input StreamParameters structure cannot have an nChannels value less than one.";
+ error( RtAudioError::INVALID_USE );
+ return;
+ }
+
+ if ( oParams == NULL && iParams == NULL ) {
+ errorText_ = "RtApi::openStream: input and output StreamParameters structures are both NULL!";
+ error( RtAudioError::INVALID_USE );
+ return;
+ }
+
+ if ( formatBytes(format) == 0 ) {
+ errorText_ = "RtApi::openStream: 'format' parameter value is undefined.";
+ error( RtAudioError::INVALID_USE );
+ return;
+ }
+
+ unsigned int nDevices = getDeviceCount();
+ unsigned int oChannels = 0;
+ if ( oParams ) {
+ oChannels = oParams->nChannels;
+ if ( oParams->deviceId >= nDevices ) {
+ errorText_ = "RtApi::openStream: output device parameter value is invalid.";
+ error( RtAudioError::INVALID_USE );
+ return;
+ }
+ }
+
+ unsigned int iChannels = 0;
+ if ( iParams ) {
+ iChannels = iParams->nChannels;
+ if ( iParams->deviceId >= nDevices ) {
+ errorText_ = "RtApi::openStream: input device parameter value is invalid.";
+ error( RtAudioError::INVALID_USE );
+ return;
+ }
+ }
+
+ bool result;
+
+ if ( oChannels > 0 ) {
+
+ result = probeDeviceOpen( oParams->deviceId, OUTPUT, oChannels, oParams->firstChannel,
+ sampleRate, format, bufferFrames, options );
+ if ( result == false ) {
+ error( RtAudioError::SYSTEM_ERROR );
+ return;
+ }
+ }
+
+ if ( iChannels > 0 ) {
+
+ result = probeDeviceOpen( iParams->deviceId, INPUT, iChannels, iParams->firstChannel,
+ sampleRate, format, bufferFrames, options );
+ if ( result == false ) {
+ if ( oChannels > 0 ) closeStream();
+ error( RtAudioError::SYSTEM_ERROR );
+ return;
+ }
+ }
+
+ stream_.callbackInfo.callback = (void *) callback;
+ stream_.callbackInfo.userData = userData;
+ stream_.callbackInfo.errorCallback = (void *) errorCallback;
+
+ if ( options ) options->numberOfBuffers = stream_.nBuffers;
+ stream_.state = STREAM_STOPPED;
+}
+
+unsigned int RtApi :: getDefaultInputDevice( void )
+{
+ // Should be implemented in subclasses if possible.
+ return 0;
+}
+
+unsigned int RtApi :: getDefaultOutputDevice( void )
+{
+ // Should be implemented in subclasses if possible.
+ return 0;
+}
+
+void RtApi :: closeStream( void )
+{
+ // MUST be implemented in subclasses!
+ return;
+}
+
+bool RtApi :: probeDeviceOpen( unsigned int /*device*/, StreamMode /*mode*/, unsigned int /*channels*/,
+ unsigned int /*firstChannel*/, unsigned int /*sampleRate*/,
+ RtAudioFormat /*format*/, unsigned int * /*bufferSize*/,
+ RtAudio::StreamOptions * /*options*/ )
+{
+ // MUST be implemented in subclasses!
+ return FAILURE;
+}
+
+void RtApi :: tickStreamTime( void )
+{
+ // Subclasses that do not provide their own implementation of
+ // getStreamTime should call this function once per buffer I/O to
+ // provide basic stream time support.
+
+ stream_.streamTime += ( stream_.bufferSize * 1.0 / stream_.sampleRate );
+
+#if defined( HAVE_GETTIMEOFDAY )
+ gettimeofday( &stream_.lastTickTimestamp, NULL );
+#endif
+}
+
+long RtApi :: getStreamLatency( void )
+{
+ verifyStream();
+
+ long totalLatency = 0;
+ if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX )
+ totalLatency = stream_.latency[0];
+ if ( stream_.mode == INPUT || stream_.mode == DUPLEX )
+ totalLatency += stream_.latency[1];
+
+ return totalLatency;
+}
+
+double RtApi :: getStreamTime( void )
+{
+ verifyStream();
+
+#if defined( HAVE_GETTIMEOFDAY )
+ // Return a very accurate estimate of the stream time by
+ // adding in the elapsed time since the last tick.
+ struct timeval then;
+ struct timeval now;
+
+ if ( stream_.state != STREAM_RUNNING || stream_.streamTime == 0.0 )
+ return stream_.streamTime;
+
+ gettimeofday( &now, NULL );
+ then = stream_.lastTickTimestamp;
+ return stream_.streamTime +
+ ((now.tv_sec + 0.000001 * now.tv_usec) -
+ (then.tv_sec + 0.000001 * then.tv_usec));
+#else
+ return stream_.streamTime;
+#endif
+}
+
+void RtApi :: setStreamTime( double time )
+{
+ verifyStream();
+
+ if ( time >= 0.0 )
+ stream_.streamTime = time;
+}
+
+unsigned int RtApi :: getStreamSampleRate( void )
+{
+ verifyStream();
+
+ return stream_.sampleRate;
+}
+
+
+// *************************************************** //
+//
+// OS/API-specific methods.
+//
+// *************************************************** //
+
+#if defined(__MACOSX_CORE__)
+
+// The OS X CoreAudio API is designed to use a separate callback
+// procedure for each of its audio devices. A single RtAudio duplex
+// stream using two different devices is supported here, though it
+// cannot be guaranteed to always behave correctly because we cannot
+// synchronize these two callbacks.
+//
+// A property listener is installed for over/underrun information.
+// However, no functionality is currently provided to allow property
+// listeners to trigger user handlers because it is unclear what could
+// be done if a critical stream parameter (buffer size, sample rate,
+// device disconnect) notification arrived. The listeners entail
+// quite a bit of extra code and most likely, a user program wouldn't
+// be prepared for the result anyway. However, we do provide a flag
+// to the client callback function to inform of an over/underrun.
+
+// A structure to hold various information related to the CoreAudio API
+// implementation.
+struct CoreHandle {
+ AudioDeviceID id[2]; // device ids
+#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
+ AudioDeviceIOProcID procId[2];
+#endif
+ UInt32 iStream[2]; // device stream index (or first if using multiple)
+ UInt32 nStreams[2]; // number of streams to use
+ bool xrun[2];
+ char *deviceBuffer;
+ pthread_cond_t condition;
+ int drainCounter; // Tracks callback counts when draining
+ bool internalDrain; // Indicates if stop is initiated from callback or not.
+
+ CoreHandle()
+ :deviceBuffer(0), drainCounter(0), internalDrain(false) { nStreams[0] = 1; nStreams[1] = 1; id[0] = 0; id[1] = 0; xrun[0] = false; xrun[1] = false; }
+};
+
+RtApiCore:: RtApiCore()
+{
+#if defined( AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER )
+ // This is a largely undocumented but absolutely necessary
+ // requirement starting with OS-X 10.6. If not called, queries and
+ // updates to various audio device properties are not handled
+ // correctly.
+ CFRunLoopRef theRunLoop = NULL;
+ AudioObjectPropertyAddress property = { kAudioHardwarePropertyRunLoop,
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster };
+ OSStatus result = AudioObjectSetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, sizeof(CFRunLoopRef), &theRunLoop);
+ if ( result != noErr ) {
+ errorText_ = "RtApiCore::RtApiCore: error setting run loop property!";
+ error( RtAudioError::WARNING );
+ }
+#endif
+}
+
+RtApiCore :: ~RtApiCore()
+{
+ // The subclass destructor gets called before the base class
+ // destructor, so close an existing stream before deallocating
+ // apiDeviceId memory.
+ if ( stream_.state != STREAM_CLOSED ) closeStream();
+}
+
+unsigned int RtApiCore :: getDeviceCount( void )
+{
+ // Find out how many audio devices there are, if any.
+ UInt32 dataSize;
+ AudioObjectPropertyAddress propertyAddress = { kAudioHardwarePropertyDevices, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
+ OSStatus result = AudioObjectGetPropertyDataSize( kAudioObjectSystemObject, &propertyAddress, 0, NULL, &dataSize );
+ if ( result != noErr ) {
+ errorText_ = "RtApiCore::getDeviceCount: OS-X error getting device info!";
+ error( RtAudioError::WARNING );
+ return 0;
+ }
+
+ return dataSize / sizeof( AudioDeviceID );
+}
+
+unsigned int RtApiCore :: getDefaultInputDevice( void )
+{
+ unsigned int nDevices = getDeviceCount();
+ if ( nDevices <= 1 ) return 0;
+
+ AudioDeviceID id;
+ UInt32 dataSize = sizeof( AudioDeviceID );
+ AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
+ OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, &id );
+ if ( result != noErr ) {
+ errorText_ = "RtApiCore::getDefaultInputDevice: OS-X system error getting device.";
+ error( RtAudioError::WARNING );
+ return 0;
+ }
+
+ dataSize *= nDevices;
+ AudioDeviceID deviceList[ nDevices ];
+ property.mSelector = kAudioHardwarePropertyDevices;
+ result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, (void *) &deviceList );
+ if ( result != noErr ) {
+ errorText_ = "RtApiCore::getDefaultInputDevice: OS-X system error getting device IDs.";
+ error( RtAudioError::WARNING );
+ return 0;
+ }
+
+ for ( unsigned int i=0; i<nDevices; i++ )
+ if ( id == deviceList[i] ) return i;
+
+ errorText_ = "RtApiCore::getDefaultInputDevice: No default device found!";
+ error( RtAudioError::WARNING );
+ return 0;
+}
+
+unsigned int RtApiCore :: getDefaultOutputDevice( void )
+{
+ unsigned int nDevices = getDeviceCount();
+ if ( nDevices <= 1 ) return 0;
+
+ AudioDeviceID id;
+ UInt32 dataSize = sizeof( AudioDeviceID );
+ AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
+ OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, &id );
+ if ( result != noErr ) {
+ errorText_ = "RtApiCore::getDefaultOutputDevice: OS-X system error getting device.";
+ error( RtAudioError::WARNING );
+ return 0;
+ }
+
+ dataSize = sizeof( AudioDeviceID ) * nDevices;
+ AudioDeviceID deviceList[ nDevices ];
+ property.mSelector = kAudioHardwarePropertyDevices;
+ result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property, 0, NULL, &dataSize, (void *) &deviceList );
+ if ( result != noErr ) {
+ errorText_ = "RtApiCore::getDefaultOutputDevice: OS-X system error getting device IDs.";
+ error( RtAudioError::WARNING );
+ return 0;
+ }
+
+ for ( unsigned int i=0; i<nDevices; i++ )
+ if ( id == deviceList[i] ) return i;
+
+ errorText_ = "RtApiCore::getDefaultOutputDevice: No default device found!";
+ error( RtAudioError::WARNING );
+ return 0;
+}
+
+RtAudio::DeviceInfo RtApiCore :: getDeviceInfo( unsigned int device )
+{
+ RtAudio::DeviceInfo info;
+ info.probed = false;
+
+ // Get device ID
+ unsigned int nDevices = getDeviceCount();
+ if ( nDevices == 0 ) {
+ errorText_ = "RtApiCore::getDeviceInfo: no devices found!";
+ error( RtAudioError::INVALID_USE );
+ return info;
+ }
+
+ if ( device >= nDevices ) {
+ errorText_ = "RtApiCore::getDeviceInfo: device ID is invalid!";
+ error( RtAudioError::INVALID_USE );
+ return info;
+ }
+
+ AudioDeviceID deviceList[ nDevices ];
+ UInt32 dataSize = sizeof( AudioDeviceID ) * nDevices;
+ AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices,
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster };
+ OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property,
+ 0, NULL, &dataSize, (void *) &deviceList );
+ if ( result != noErr ) {
+ errorText_ = "RtApiCore::getDeviceInfo: OS-X system error getting device IDs.";
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ AudioDeviceID id = deviceList[ device ];
+
+ // Get the device name.
+ info.name.erase();
+ CFStringRef cfname;
+ dataSize = sizeof( CFStringRef );
+ property.mSelector = kAudioObjectPropertyManufacturer;
+ result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &cfname );
+ if ( result != noErr ) {
+ errorStream_ << "RtApiCore::probeDeviceInfo: system error (" << getErrorCode( result ) << ") getting device manufacturer.";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ //const char *mname = CFStringGetCStringPtr( cfname, CFStringGetSystemEncoding() );
+ int length = CFStringGetLength(cfname);
+ char *mname = (char *)malloc(length * 3 + 1);
+#if defined( UNICODE ) || defined( _UNICODE )
+ CFStringGetCString(cfname, mname, length * 3 + 1, kCFStringEncodingUTF8);
+#else
+ CFStringGetCString(cfname, mname, length * 3 + 1, CFStringGetSystemEncoding());
+#endif
+ info.name.append( (const char *)mname, strlen(mname) );
+ info.name.append( ": " );
+ CFRelease( cfname );
+ free(mname);
+
+ property.mSelector = kAudioObjectPropertyName;
+ result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &cfname );
+ if ( result != noErr ) {
+ errorStream_ << "RtApiCore::probeDeviceInfo: system error (" << getErrorCode( result ) << ") getting device name.";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ //const char *name = CFStringGetCStringPtr( cfname, CFStringGetSystemEncoding() );
+ length = CFStringGetLength(cfname);
+ char *name = (char *)malloc(length * 3 + 1);
+#if defined( UNICODE ) || defined( _UNICODE )
+ CFStringGetCString(cfname, name, length * 3 + 1, kCFStringEncodingUTF8);
+#else
+ CFStringGetCString(cfname, name, length * 3 + 1, CFStringGetSystemEncoding());
+#endif
+ info.name.append( (const char *)name, strlen(name) );
+ CFRelease( cfname );
+ free(name);
+
+ // Get the output stream "configuration".
+ AudioBufferList *bufferList = nil;
+ property.mSelector = kAudioDevicePropertyStreamConfiguration;
+ property.mScope = kAudioDevicePropertyScopeOutput;
+ // property.mElement = kAudioObjectPropertyElementWildcard;
+ dataSize = 0;
+ result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize );
+ if ( result != noErr || dataSize == 0 ) {
+ errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting output stream configuration info for device (" << device << ").";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ // Allocate the AudioBufferList.
+ bufferList = (AudioBufferList *) malloc( dataSize );
+ if ( bufferList == NULL ) {
+ errorText_ = "RtApiCore::getDeviceInfo: memory error allocating output AudioBufferList.";
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, bufferList );
+ if ( result != noErr || dataSize == 0 ) {
+ free( bufferList );
+ errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting output stream configuration for device (" << device << ").";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ // Get output channel information.
+ unsigned int i, nStreams = bufferList->mNumberBuffers;
+ for ( i=0; i<nStreams; i++ )
+ info.outputChannels += bufferList->mBuffers[i].mNumberChannels;
+ free( bufferList );
+
+ // Get the input stream "configuration".
+ property.mScope = kAudioDevicePropertyScopeInput;
+ result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize );
+ if ( result != noErr || dataSize == 0 ) {
+ errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting input stream configuration info for device (" << device << ").";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ // Allocate the AudioBufferList.
+ bufferList = (AudioBufferList *) malloc( dataSize );
+ if ( bufferList == NULL ) {
+ errorText_ = "RtApiCore::getDeviceInfo: memory error allocating input AudioBufferList.";
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, bufferList );
+ if (result != noErr || dataSize == 0) {
+ free( bufferList );
+ errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting input stream configuration for device (" << device << ").";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ // Get input channel information.
+ nStreams = bufferList->mNumberBuffers;
+ for ( i=0; i<nStreams; i++ )
+ info.inputChannels += bufferList->mBuffers[i].mNumberChannels;
+ free( bufferList );
+
+ // If device opens for both playback and capture, we determine the channels.
+ if ( info.outputChannels > 0 && info.inputChannels > 0 )
+ info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;
+
+ // Probe the device sample rates.
+ bool isInput = false;
+ if ( info.outputChannels == 0 ) isInput = true;
+
+ // Determine the supported sample rates.
+ property.mSelector = kAudioDevicePropertyAvailableNominalSampleRates;
+ if ( isInput == false ) property.mScope = kAudioDevicePropertyScopeOutput;
+ result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize );
+ if ( result != kAudioHardwareNoError || dataSize == 0 ) {
+ errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting sample rate info.";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ UInt32 nRanges = dataSize / sizeof( AudioValueRange );
+ AudioValueRange rangeList[ nRanges ];
+ result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &rangeList );
+ if ( result != kAudioHardwareNoError ) {
+ errorStream_ << "RtApiCore::getDeviceInfo: system error (" << getErrorCode( result ) << ") getting sample rates.";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ // The sample rate reporting mechanism is a bit of a mystery. It
+ // seems that it can either return individual rates or a range of
+ // rates. I assume that if the min / max range values are the same,
+ // then that represents a single supported rate and if the min / max
+ // range values are different, the device supports an arbitrary
+ // range of values (though there might be multiple ranges, so we'll
+ // use the most conservative range).
+ Float64 minimumRate = 1.0, maximumRate = 10000000000.0;
+ bool haveValueRange = false;
+ info.sampleRates.clear();
+ for ( UInt32 i=0; i<nRanges; i++ ) {
+ if ( rangeList[i].mMinimum == rangeList[i].mMaximum ) {
+ unsigned int tmpSr = (unsigned int) rangeList[i].mMinimum;
+ info.sampleRates.push_back( tmpSr );
+
+ if ( !info.preferredSampleRate || ( tmpSr <= 48000 && tmpSr > info.preferredSampleRate ) )
+ info.preferredSampleRate = tmpSr;
+
+ } else {
+ haveValueRange = true;
+ if ( rangeList[i].mMinimum > minimumRate ) minimumRate = rangeList[i].mMinimum;
+ if ( rangeList[i].mMaximum < maximumRate ) maximumRate = rangeList[i].mMaximum;
+ }
+ }
+
+ if ( haveValueRange ) {
+ for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {
+ if ( SAMPLE_RATES[k] >= (unsigned int) minimumRate && SAMPLE_RATES[k] <= (unsigned int) maximumRate ) {
+ info.sampleRates.push_back( SAMPLE_RATES[k] );
+
+ if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) )
+ info.preferredSampleRate = SAMPLE_RATES[k];
+ }
+ }
+ }
+
+ // Sort and remove any redundant values
+ std::sort( info.sampleRates.begin(), info.sampleRates.end() );
+ info.sampleRates.erase( unique( info.sampleRates.begin(), info.sampleRates.end() ), info.sampleRates.end() );
+
+ if ( info.sampleRates.size() == 0 ) {
+ errorStream_ << "RtApiCore::probeDeviceInfo: No supported sample rates found for device (" << device << ").";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ // CoreAudio always uses 32-bit floating point data for PCM streams.
+ // Thus, any other "physical" formats supported by the device are of
+ // no interest to the client.
+ info.nativeFormats = RTAUDIO_FLOAT32;
+
+ if ( info.outputChannels > 0 )
+ if ( getDefaultOutputDevice() == device ) info.isDefaultOutput = true;
+ if ( info.inputChannels > 0 )
+ if ( getDefaultInputDevice() == device ) info.isDefaultInput = true;
+
+ info.probed = true;
+ return info;
+}
+
+static OSStatus callbackHandler( AudioDeviceID inDevice,
+ const AudioTimeStamp* /*inNow*/,
+ const AudioBufferList* inInputData,
+ const AudioTimeStamp* /*inInputTime*/,
+ AudioBufferList* outOutputData,
+ const AudioTimeStamp* /*inOutputTime*/,
+ void* infoPointer )
+{
+ CallbackInfo *info = (CallbackInfo *) infoPointer;
+
+ RtApiCore *object = (RtApiCore *) info->object;
+ if ( object->callbackEvent( inDevice, inInputData, outOutputData ) == false )
+ return kAudioHardwareUnspecifiedError;
+ else
+ return kAudioHardwareNoError;
+}
+
+static OSStatus xrunListener( AudioObjectID /*inDevice*/,
+ UInt32 nAddresses,
+ const AudioObjectPropertyAddress properties[],
+ void* handlePointer )
+{
+ CoreHandle *handle = (CoreHandle *) handlePointer;
+ for ( UInt32 i=0; i<nAddresses; i++ ) {
+ if ( properties[i].mSelector == kAudioDeviceProcessorOverload ) {
+ if ( properties[i].mScope == kAudioDevicePropertyScopeInput )
+ handle->xrun[1] = true;
+ else
+ handle->xrun[0] = true;
+ }
+ }
+
+ return kAudioHardwareNoError;
+}
+
+static OSStatus rateListener( AudioObjectID inDevice,
+ UInt32 /*nAddresses*/,
+ const AudioObjectPropertyAddress /*properties*/[],
+ void* ratePointer )
+{
+ Float64 *rate = (Float64 *) ratePointer;
+ UInt32 dataSize = sizeof( Float64 );
+ AudioObjectPropertyAddress property = { kAudioDevicePropertyNominalSampleRate,
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster };
+ AudioObjectGetPropertyData( inDevice, &property, 0, NULL, &dataSize, rate );
+ return kAudioHardwareNoError;
+}
+
+bool RtApiCore :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
+ unsigned int firstChannel, unsigned int sampleRate,
+ RtAudioFormat format, unsigned int *bufferSize,
+ RtAudio::StreamOptions *options )
+{
+ // Get device ID
+ unsigned int nDevices = getDeviceCount();
+ if ( nDevices == 0 ) {
+ // This should not happen because a check is made before this function is called.
+ errorText_ = "RtApiCore::probeDeviceOpen: no devices found!";
+ return FAILURE;
+ }
+
+ if ( device >= nDevices ) {
+ // This should not happen because a check is made before this function is called.
+ errorText_ = "RtApiCore::probeDeviceOpen: device ID is invalid!";
+ return FAILURE;
+ }
+
+ AudioDeviceID deviceList[ nDevices ];
+ UInt32 dataSize = sizeof( AudioDeviceID ) * nDevices;
+ AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices,
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster };
+ OSStatus result = AudioObjectGetPropertyData( kAudioObjectSystemObject, &property,
+ 0, NULL, &dataSize, (void *) &deviceList );
+ if ( result != noErr ) {
+ errorText_ = "RtApiCore::probeDeviceOpen: OS-X system error getting device IDs.";
+ return FAILURE;
+ }
+
+ AudioDeviceID id = deviceList[ device ];
+
+ // Setup for stream mode.
+ bool isInput = false;
+ if ( mode == INPUT ) {
+ isInput = true;
+ property.mScope = kAudioDevicePropertyScopeInput;
+ }
+ else
+ property.mScope = kAudioDevicePropertyScopeOutput;
+
+ // Get the stream "configuration".
+ AudioBufferList *bufferList = nil;
+ dataSize = 0;
+ property.mSelector = kAudioDevicePropertyStreamConfiguration;
+ result = AudioObjectGetPropertyDataSize( id, &property, 0, NULL, &dataSize );
+ if ( result != noErr || dataSize == 0 ) {
+ errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream configuration info for device (" << device << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Allocate the AudioBufferList.
+ bufferList = (AudioBufferList *) malloc( dataSize );
+ if ( bufferList == NULL ) {
+ errorText_ = "RtApiCore::probeDeviceOpen: memory error allocating AudioBufferList.";
+ return FAILURE;
+ }
+
+ result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, bufferList );
+ if (result != noErr || dataSize == 0) {
+ free( bufferList );
+ errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream configuration for device (" << device << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Search for one or more streams that contain the desired number of
+ // channels. CoreAudio devices can have an arbitrary number of
+ // streams and each stream can have an arbitrary number of channels.
+ // For each stream, a single buffer of interleaved samples is
+ // provided. RtAudio prefers the use of one stream of interleaved
+ // data or multiple consecutive single-channel streams. However, we
+ // now support multiple consecutive multi-channel streams of
+ // interleaved data as well.
+ UInt32 iStream, offsetCounter = firstChannel;
+ UInt32 nStreams = bufferList->mNumberBuffers;
+ bool monoMode = false;
+ bool foundStream = false;
+
+ // First check that the device supports the requested number of
+ // channels.
+ UInt32 deviceChannels = 0;
+ for ( iStream=0; iStream<nStreams; iStream++ )
+ deviceChannels += bufferList->mBuffers[iStream].mNumberChannels;
+
+ if ( deviceChannels < ( channels + firstChannel ) ) {
+ free( bufferList );
+ errorStream_ << "RtApiCore::probeDeviceOpen: the device (" << device << ") does not support the requested channel count.";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Look for a single stream meeting our needs.
+ UInt32 firstStream, streamCount = 1, streamChannels = 0, channelOffset = 0;
+ for ( iStream=0; iStream<nStreams; iStream++ ) {
+ streamChannels = bufferList->mBuffers[iStream].mNumberChannels;
+ if ( streamChannels >= channels + offsetCounter ) {
+ firstStream = iStream;
+ channelOffset = offsetCounter;
+ foundStream = true;
+ break;
+ }
+ if ( streamChannels > offsetCounter ) break;
+ offsetCounter -= streamChannels;
+ }
+
+ // If we didn't find a single stream above, then we should be able
+ // to meet the channel specification with multiple streams.
+ if ( foundStream == false ) {
+ monoMode = true;
+ offsetCounter = firstChannel;
+ for ( iStream=0; iStream<nStreams; iStream++ ) {
+ streamChannels = bufferList->mBuffers[iStream].mNumberChannels;
+ if ( streamChannels > offsetCounter ) break;
+ offsetCounter -= streamChannels;
+ }
+
+ firstStream = iStream;
+ channelOffset = offsetCounter;
+ Int32 channelCounter = channels + offsetCounter - streamChannels;
+
+ if ( streamChannels > 1 ) monoMode = false;
+ while ( channelCounter > 0 ) {
+ streamChannels = bufferList->mBuffers[++iStream].mNumberChannels;
+ if ( streamChannels > 1 ) monoMode = false;
+ channelCounter -= streamChannels;
+ streamCount++;
+ }
+ }
+
+ free( bufferList );
+
+ // Determine the buffer size.
+ AudioValueRange bufferRange;
+ dataSize = sizeof( AudioValueRange );
+ property.mSelector = kAudioDevicePropertyBufferFrameSizeRange;
+ result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &bufferRange );
+
+ if ( result != noErr ) {
+ errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting buffer size range for device (" << device << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ if ( bufferRange.mMinimum > *bufferSize ) *bufferSize = (unsigned long) bufferRange.mMinimum;
+ else if ( bufferRange.mMaximum < *bufferSize ) *bufferSize = (unsigned long) bufferRange.mMaximum;
+ if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) *bufferSize = (unsigned long) bufferRange.mMinimum;
+
+ // Set the buffer size. For multiple streams, I'm assuming we only
+ // need to make this setting for the master channel.
+ UInt32 theSize = (UInt32) *bufferSize;
+ dataSize = sizeof( UInt32 );
+ property.mSelector = kAudioDevicePropertyBufferFrameSize;
+ result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &theSize );
+
+ if ( result != noErr ) {
+ errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting the buffer size for device (" << device << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // If attempting to setup a duplex stream, the bufferSize parameter
+ // MUST be the same in both directions!
+ *bufferSize = theSize;
+ if ( stream_.mode == OUTPUT && mode == INPUT && *bufferSize != stream_.bufferSize ) {
+ errorStream_ << "RtApiCore::probeDeviceOpen: system error setting buffer size for duplex stream on device (" << device << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ stream_.bufferSize = *bufferSize;
+ stream_.nBuffers = 1;
+
+ // Try to set "hog" mode ... it's not clear to me this is working.
+ if ( options && options->flags & RTAUDIO_HOG_DEVICE ) {
+ pid_t hog_pid;
+ dataSize = sizeof( hog_pid );
+ property.mSelector = kAudioDevicePropertyHogMode;
+ result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &hog_pid );
+ if ( result != noErr ) {
+ errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting 'hog' state!";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ if ( hog_pid != getpid() ) {
+ hog_pid = getpid();
+ result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &hog_pid );
+ if ( result != noErr ) {
+ errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting 'hog' state!";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+ }
+ }
+
+ // Check and if necessary, change the sample rate for the device.
+ Float64 nominalRate;
+ dataSize = sizeof( Float64 );
+ property.mSelector = kAudioDevicePropertyNominalSampleRate;
+ result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &nominalRate );
+ if ( result != noErr ) {
+ errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting current sample rate.";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Only change the sample rate if off by more than 1 Hz.
+ if ( fabs( nominalRate - (double)sampleRate ) > 1.0 ) {
+
+ // Set a property listener for the sample rate change
+ Float64 reportedRate = 0.0;
+ AudioObjectPropertyAddress tmp = { kAudioDevicePropertyNominalSampleRate, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
+ result = AudioObjectAddPropertyListener( id, &tmp, rateListener, (void *) &reportedRate );
+ if ( result != noErr ) {
+ errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate property listener for device (" << device << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ nominalRate = (Float64) sampleRate;
+ result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &nominalRate );
+ if ( result != noErr ) {
+ AudioObjectRemovePropertyListener( id, &tmp, rateListener, (void *) &reportedRate );
+ errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate for device (" << device << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Now wait until the reported nominal rate is what we just set.
+ UInt32 microCounter = 0;
+ while ( reportedRate != nominalRate ) {
+ microCounter += 5000;
+ if ( microCounter > 5000000 ) break;
+ usleep( 5000 );
+ }
+
+ // Remove the property listener.
+ AudioObjectRemovePropertyListener( id, &tmp, rateListener, (void *) &reportedRate );
+
+ if ( microCounter > 5000000 ) {
+ errorStream_ << "RtApiCore::probeDeviceOpen: timeout waiting for sample rate update for device (" << device << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+ }
+
+ // Now set the stream format for all streams. Also, check the
+ // physical format of the device and change that if necessary.
+ AudioStreamBasicDescription description;
+ dataSize = sizeof( AudioStreamBasicDescription );
+ property.mSelector = kAudioStreamPropertyVirtualFormat;
+ result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &description );
+ if ( result != noErr ) {
+ errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream format for device (" << device << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Set the sample rate and data format id. However, only make the
+ // change if the sample rate is not within 1.0 of the desired
+ // rate and the format is not linear pcm.
+ bool updateFormat = false;
+ if ( fabs( description.mSampleRate - (Float64)sampleRate ) > 1.0 ) {
+ description.mSampleRate = (Float64) sampleRate;
+ updateFormat = true;
+ }
+
+ if ( description.mFormatID != kAudioFormatLinearPCM ) {
+ description.mFormatID = kAudioFormatLinearPCM;
+ updateFormat = true;
+ }
+
+ if ( updateFormat ) {
+ result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &description );
+ if ( result != noErr ) {
+ errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting sample rate or data format for device (" << device << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+ }
+
+ // Now check the physical format.
+ property.mSelector = kAudioStreamPropertyPhysicalFormat;
+ result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &description );
+ if ( result != noErr ) {
+ errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting stream physical format for device (" << device << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ //std::cout << "Current physical stream format:" << std::endl;
+ //std::cout << " mBitsPerChan = " << description.mBitsPerChannel << std::endl;
+ //std::cout << " aligned high = " << (description.mFormatFlags & kAudioFormatFlagIsAlignedHigh) << ", isPacked = " << (description.mFormatFlags & kAudioFormatFlagIsPacked) << std::endl;
+ //std::cout << " bytesPerFrame = " << description.mBytesPerFrame << std::endl;
+ //std::cout << " sample rate = " << description.mSampleRate << std::endl;
+
+ if ( description.mFormatID != kAudioFormatLinearPCM || description.mBitsPerChannel < 16 ) {
+ description.mFormatID = kAudioFormatLinearPCM;
+ //description.mSampleRate = (Float64) sampleRate;
+ AudioStreamBasicDescription testDescription = description;
+ UInt32 formatFlags;
+
+ // We'll try higher bit rates first and then work our way down.
+ std::vector< std::pair<UInt32, UInt32> > physicalFormats;
+ formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsFloat) & ~kLinearPCMFormatFlagIsSignedInteger;
+ physicalFormats.push_back( std::pair<Float32, UInt32>( 32, formatFlags ) );
+ formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked) & ~kLinearPCMFormatFlagIsFloat;
+ physicalFormats.push_back( std::pair<Float32, UInt32>( 32, formatFlags ) );
+ physicalFormats.push_back( std::pair<Float32, UInt32>( 24, formatFlags ) ); // 24-bit packed
+ formatFlags &= ~( kAudioFormatFlagIsPacked | kAudioFormatFlagIsAlignedHigh );
+ physicalFormats.push_back( std::pair<Float32, UInt32>( 24.2, formatFlags ) ); // 24-bit in 4 bytes, aligned low
+ formatFlags |= kAudioFormatFlagIsAlignedHigh;
+ physicalFormats.push_back( std::pair<Float32, UInt32>( 24.4, formatFlags ) ); // 24-bit in 4 bytes, aligned high
+ formatFlags = (description.mFormatFlags | kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked) & ~kLinearPCMFormatFlagIsFloat;
+ physicalFormats.push_back( std::pair<Float32, UInt32>( 16, formatFlags ) );
+ physicalFormats.push_back( std::pair<Float32, UInt32>( 8, formatFlags ) );
+
+ bool setPhysicalFormat = false;
+ for( unsigned int i=0; i<physicalFormats.size(); i++ ) {
+ testDescription = description;
+ testDescription.mBitsPerChannel = (UInt32) physicalFormats[i].first;
+ testDescription.mFormatFlags = physicalFormats[i].second;
+ if ( (24 == (UInt32)physicalFormats[i].first) && ~( physicalFormats[i].second & kAudioFormatFlagIsPacked ) )
+ testDescription.mBytesPerFrame = 4 * testDescription.mChannelsPerFrame;
+ else
+ testDescription.mBytesPerFrame = testDescription.mBitsPerChannel/8 * testDescription.mChannelsPerFrame;
+ testDescription.mBytesPerPacket = testDescription.mBytesPerFrame * testDescription.mFramesPerPacket;
+ result = AudioObjectSetPropertyData( id, &property, 0, NULL, dataSize, &testDescription );
+ if ( result == noErr ) {
+ setPhysicalFormat = true;
+ //std::cout << "Updated physical stream format:" << std::endl;
+ //std::cout << " mBitsPerChan = " << testDescription.mBitsPerChannel << std::endl;
+ //std::cout << " aligned high = " << (testDescription.mFormatFlags & kAudioFormatFlagIsAlignedHigh) << ", isPacked = " << (testDescription.mFormatFlags & kAudioFormatFlagIsPacked) << std::endl;
+ //std::cout << " bytesPerFrame = " << testDescription.mBytesPerFrame << std::endl;
+ //std::cout << " sample rate = " << testDescription.mSampleRate << std::endl;
+ break;
+ }
+ }
+
+ if ( !setPhysicalFormat ) {
+ errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") setting physical data format for device (" << device << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+ } // done setting virtual/physical formats.
+
+ // Get the stream / device latency.
+ UInt32 latency;
+ dataSize = sizeof( UInt32 );
+ property.mSelector = kAudioDevicePropertyLatency;
+ if ( AudioObjectHasProperty( id, &property ) == true ) {
+ result = AudioObjectGetPropertyData( id, &property, 0, NULL, &dataSize, &latency );
+ if ( result == kAudioHardwareNoError ) stream_.latency[ mode ] = latency;
+ else {
+ errorStream_ << "RtApiCore::probeDeviceOpen: system error (" << getErrorCode( result ) << ") getting device latency for device (" << device << ").";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ }
+ }
+
+ // Byte-swapping: According to AudioHardware.h, the stream data will
+ // always be presented in native-endian format, so we should never
+ // need to byte swap.
+ stream_.doByteSwap[mode] = false;
+
+ // From the CoreAudio documentation, PCM data must be supplied as
+ // 32-bit floats.
+ stream_.userFormat = format;
+ stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
+
+ if ( streamCount == 1 )
+ stream_.nDeviceChannels[mode] = description.mChannelsPerFrame;
+ else // multiple streams
+ stream_.nDeviceChannels[mode] = channels;
+ stream_.nUserChannels[mode] = channels;
+ stream_.channelOffset[mode] = channelOffset; // offset within a CoreAudio stream
+ if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;
+ else stream_.userInterleaved = true;
+ stream_.deviceInterleaved[mode] = true;
+ if ( monoMode == true ) stream_.deviceInterleaved[mode] = false;
+
+ // Set flags for buffer conversion.
+ stream_.doConvertBuffer[mode] = false;
+ if ( stream_.userFormat != stream_.deviceFormat[mode] )
+ stream_.doConvertBuffer[mode] = true;
+ if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] )
+ stream_.doConvertBuffer[mode] = true;
+ if ( streamCount == 1 ) {
+ if ( stream_.nUserChannels[mode] > 1 &&
+ stream_.userInterleaved != stream_.deviceInterleaved[mode] )
+ stream_.doConvertBuffer[mode] = true;
+ }
+ else if ( monoMode && stream_.userInterleaved )
+ stream_.doConvertBuffer[mode] = true;
+
+ // Allocate our CoreHandle structure for the stream.
+ CoreHandle *handle = 0;
+ if ( stream_.apiHandle == 0 ) {
+ try {
+ handle = new CoreHandle;
+ }
+ catch ( std::bad_alloc& ) {
+ errorText_ = "RtApiCore::probeDeviceOpen: error allocating CoreHandle memory.";
+ goto error;
+ }
+
+ if ( pthread_cond_init( &handle->condition, NULL ) ) {
+ errorText_ = "RtApiCore::probeDeviceOpen: error initializing pthread condition variable.";
+ goto error;
+ }
+ stream_.apiHandle = (void *) handle;
+ }
+ else
+ handle = (CoreHandle *) stream_.apiHandle;
+ handle->iStream[mode] = firstStream;
+ handle->nStreams[mode] = streamCount;
+ handle->id[mode] = id;
+
+ // Allocate necessary internal buffers.
+ unsigned long bufferBytes;
+ bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
+ // stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );
+ stream_.userBuffer[mode] = (char *) malloc( bufferBytes * sizeof(char) );
+ memset( stream_.userBuffer[mode], 0, bufferBytes * sizeof(char) );
+ if ( stream_.userBuffer[mode] == NULL ) {
+ errorText_ = "RtApiCore::probeDeviceOpen: error allocating user buffer memory.";
+ goto error;
+ }
+
+ // If possible, we will make use of the CoreAudio stream buffers as
+ // "device buffers". However, we can't do this if using multiple
+ // streams.
+ if ( stream_.doConvertBuffer[mode] && handle->nStreams[mode] > 1 ) {
+
+ bool makeBuffer = true;
+ bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );
+ if ( mode == INPUT ) {
+ if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
+ unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );
+ if ( bufferBytes <= bytesOut ) makeBuffer = false;
+ }
+ }
+
+ if ( makeBuffer ) {
+ bufferBytes *= *bufferSize;
+ if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );
+ stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );
+ if ( stream_.deviceBuffer == NULL ) {
+ errorText_ = "RtApiCore::probeDeviceOpen: error allocating device buffer memory.";
+ goto error;
+ }
+ }
+ }
+
+ stream_.sampleRate = sampleRate;
+ stream_.device[mode] = device;
+ stream_.state = STREAM_STOPPED;
+ stream_.callbackInfo.object = (void *) this;
+
+ // Setup the buffer conversion information structure.
+ if ( stream_.doConvertBuffer[mode] ) {
+ if ( streamCount > 1 ) setConvertInfo( mode, 0 );
+ else setConvertInfo( mode, channelOffset );
+ }
+
+ if ( mode == INPUT && stream_.mode == OUTPUT && stream_.device[0] == device )
+ // Only one callback procedure per device.
+ stream_.mode = DUPLEX;
+ else {
+#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
+ result = AudioDeviceCreateIOProcID( id, callbackHandler, (void *) &stream_.callbackInfo, &handle->procId[mode] );
+#else
+ // deprecated in favor of AudioDeviceCreateIOProcID()
+ result = AudioDeviceAddIOProc( id, callbackHandler, (void *) &stream_.callbackInfo );
+#endif
+ if ( result != noErr ) {
+ errorStream_ << "RtApiCore::probeDeviceOpen: system error setting callback for device (" << device << ").";
+ errorText_ = errorStream_.str();
+ goto error;
+ }
+ if ( stream_.mode == OUTPUT && mode == INPUT )
+ stream_.mode = DUPLEX;
+ else
+ stream_.mode = mode;
+ }
+
+ // Setup the device property listener for over/underload.
+ property.mSelector = kAudioDeviceProcessorOverload;
+ property.mScope = kAudioObjectPropertyScopeGlobal;
+ result = AudioObjectAddPropertyListener( id, &property, xrunListener, (void *) handle );
+
+ return SUCCESS;
+
+ error:
+ if ( handle ) {
+ pthread_cond_destroy( &handle->condition );
+ delete handle;
+ stream_.apiHandle = 0;
+ }
+
+ for ( int i=0; i<2; i++ ) {
+ if ( stream_.userBuffer[i] ) {
+ free( stream_.userBuffer[i] );
+ stream_.userBuffer[i] = 0;
+ }
+ }
+
+ if ( stream_.deviceBuffer ) {
+ free( stream_.deviceBuffer );
+ stream_.deviceBuffer = 0;
+ }
+
+ stream_.state = STREAM_CLOSED;
+ return FAILURE;
+}
+
+void RtApiCore :: closeStream( void )
+{
+ if ( stream_.state == STREAM_CLOSED ) {
+ errorText_ = "RtApiCore::closeStream(): no open stream to close!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
+ if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
+ if (handle) {
+ AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices,
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster };
+
+ property.mSelector = kAudioDeviceProcessorOverload;
+ property.mScope = kAudioObjectPropertyScopeGlobal;
+ if (AudioObjectRemovePropertyListener( handle->id[0], &property, xrunListener, (void *) handle ) != noErr) {
+ errorText_ = "RtApiCore::closeStream(): error removing property listener!";
+ error( RtAudioError::WARNING );
+ }
+ }
+ if ( stream_.state == STREAM_RUNNING )
+ AudioDeviceStop( handle->id[0], callbackHandler );
+#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
+ AudioDeviceDestroyIOProcID( handle->id[0], handle->procId[0] );
+#else
+ // deprecated in favor of AudioDeviceDestroyIOProcID()
+ AudioDeviceRemoveIOProc( handle->id[0], callbackHandler );
+#endif
+ }
+
+ if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) {
+ if (handle) {
+ AudioObjectPropertyAddress property = { kAudioHardwarePropertyDevices,
+ kAudioObjectPropertyScopeGlobal,
+ kAudioObjectPropertyElementMaster };
+
+ property.mSelector = kAudioDeviceProcessorOverload;
+ property.mScope = kAudioObjectPropertyScopeGlobal;
+ if (AudioObjectRemovePropertyListener( handle->id[1], &property, xrunListener, (void *) handle ) != noErr) {
+ errorText_ = "RtApiCore::closeStream(): error removing property listener!";
+ error( RtAudioError::WARNING );
+ }
+ }
+ if ( stream_.state == STREAM_RUNNING )
+ AudioDeviceStop( handle->id[1], callbackHandler );
+#if defined( MAC_OS_X_VERSION_10_5 ) && ( MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 )
+ AudioDeviceDestroyIOProcID( handle->id[1], handle->procId[1] );
+#else
+ // deprecated in favor of AudioDeviceDestroyIOProcID()
+ AudioDeviceRemoveIOProc( handle->id[1], callbackHandler );
+#endif
+ }
+
+ for ( int i=0; i<2; i++ ) {
+ if ( stream_.userBuffer[i] ) {
+ free( stream_.userBuffer[i] );
+ stream_.userBuffer[i] = 0;
+ }
+ }
+
+ if ( stream_.deviceBuffer ) {
+ free( stream_.deviceBuffer );
+ stream_.deviceBuffer = 0;
+ }
+
+ // Destroy pthread condition variable.
+ pthread_cond_destroy( &handle->condition );
+ delete handle;
+ stream_.apiHandle = 0;
+
+ stream_.mode = UNINITIALIZED;
+ stream_.state = STREAM_CLOSED;
+}
+
+void RtApiCore :: startStream( void )
+{
+ verifyStream();
+ if ( stream_.state == STREAM_RUNNING ) {
+ errorText_ = "RtApiCore::startStream(): the stream is already running!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ OSStatus result = noErr;
+ CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
+ if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
+
+ result = AudioDeviceStart( handle->id[0], callbackHandler );
+ if ( result != noErr ) {
+ errorStream_ << "RtApiCore::startStream: system error (" << getErrorCode( result ) << ") starting callback procedure on device (" << stream_.device[0] << ").";
+ errorText_ = errorStream_.str();
+ goto unlock;
+ }
+ }
+
+ if ( stream_.mode == INPUT ||
+ ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) {
+
+ result = AudioDeviceStart( handle->id[1], callbackHandler );
+ if ( result != noErr ) {
+ errorStream_ << "RtApiCore::startStream: system error starting input callback procedure on device (" << stream_.device[1] << ").";
+ errorText_ = errorStream_.str();
+ goto unlock;
+ }
+ }
+
+ handle->drainCounter = 0;
+ handle->internalDrain = false;
+ stream_.state = STREAM_RUNNING;
+
+ unlock:
+ if ( result == noErr ) return;
+ error( RtAudioError::SYSTEM_ERROR );
+}
+
+void RtApiCore :: stopStream( void )
+{
+ verifyStream();
+ if ( stream_.state == STREAM_STOPPED ) {
+ errorText_ = "RtApiCore::stopStream(): the stream is already stopped!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ OSStatus result = noErr;
+ CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
+ if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
+
+ if ( handle->drainCounter == 0 ) {
+ handle->drainCounter = 2;
+ pthread_cond_wait( &handle->condition, &stream_.mutex ); // block until signaled
+ }
+
+ result = AudioDeviceStop( handle->id[0], callbackHandler );
+ if ( result != noErr ) {
+ errorStream_ << "RtApiCore::stopStream: system error (" << getErrorCode( result ) << ") stopping callback procedure on device (" << stream_.device[0] << ").";
+ errorText_ = errorStream_.str();
+ goto unlock;
+ }
+ }
+
+ if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && stream_.device[0] != stream_.device[1] ) ) {
+
+ result = AudioDeviceStop( handle->id[1], callbackHandler );
+ if ( result != noErr ) {
+ errorStream_ << "RtApiCore::stopStream: system error (" << getErrorCode( result ) << ") stopping input callback procedure on device (" << stream_.device[1] << ").";
+ errorText_ = errorStream_.str();
+ goto unlock;
+ }
+ }
+
+ stream_.state = STREAM_STOPPED;
+
+ unlock:
+ if ( result == noErr ) return;
+ error( RtAudioError::SYSTEM_ERROR );
+}
+
+void RtApiCore :: abortStream( void )
+{
+ verifyStream();
+ if ( stream_.state == STREAM_STOPPED ) {
+ errorText_ = "RtApiCore::abortStream(): the stream is already stopped!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
+ handle->drainCounter = 2;
+
+ stopStream();
+}
+
+// This function will be called by a spawned thread when the user
+// callback function signals that the stream should be stopped or
+// aborted. It is better to handle it this way because the
+// callbackEvent() function probably should return before the AudioDeviceStop()
+// function is called.
+static void *coreStopStream( void *ptr )
+{
+ CallbackInfo *info = (CallbackInfo *) ptr;
+ RtApiCore *object = (RtApiCore *) info->object;
+
+ object->stopStream();
+ pthread_exit( NULL );
+}
+
+bool RtApiCore :: callbackEvent( AudioDeviceID deviceId,
+ const AudioBufferList *inBufferList,
+ const AudioBufferList *outBufferList )
+{
+ if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) return SUCCESS;
+ if ( stream_.state == STREAM_CLOSED ) {
+ errorText_ = "RtApiCore::callbackEvent(): the stream is closed ... this shouldn't happen!";
+ error( RtAudioError::WARNING );
+ return FAILURE;
+ }
+
+ CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
+ CoreHandle *handle = (CoreHandle *) stream_.apiHandle;
+
+ // Check if we were draining the stream and signal is finished.
+ if ( handle->drainCounter > 3 ) {
+ ThreadHandle threadId;
+
+ stream_.state = STREAM_STOPPING;
+ if ( handle->internalDrain == true )
+ pthread_create( &threadId, NULL, coreStopStream, info );
+ else // external call to stopStream()
+ pthread_cond_signal( &handle->condition );
+ return SUCCESS;
+ }
+
+ AudioDeviceID outputDevice = handle->id[0];
+
+ // Invoke user callback to get fresh output data UNLESS we are
+ // draining stream or duplex mode AND the input/output devices are
+ // different AND this function is called for the input device.
+ if ( handle->drainCounter == 0 && ( stream_.mode != DUPLEX || deviceId == outputDevice ) ) {
+ RtAudioCallback callback = (RtAudioCallback) info->callback;
+ double streamTime = getStreamTime();
+ RtAudioStreamStatus status = 0;
+ if ( stream_.mode != INPUT && handle->xrun[0] == true ) {
+ status |= RTAUDIO_OUTPUT_UNDERFLOW;
+ handle->xrun[0] = false;
+ }
+ if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) {
+ status |= RTAUDIO_INPUT_OVERFLOW;
+ handle->xrun[1] = false;
+ }
+
+ int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1],
+ stream_.bufferSize, streamTime, status, info->userData );
+ if ( cbReturnValue == 2 ) {
+ stream_.state = STREAM_STOPPING;
+ handle->drainCounter = 2;
+ abortStream();
+ return SUCCESS;
+ }
+ else if ( cbReturnValue == 1 ) {
+ handle->drainCounter = 1;
+ handle->internalDrain = true;
+ }
+ }
+
+ if ( stream_.mode == OUTPUT || ( stream_.mode == DUPLEX && deviceId == outputDevice ) ) {
+
+ if ( handle->drainCounter > 1 ) { // write zeros to the output stream
+
+ if ( handle->nStreams[0] == 1 ) {
+ memset( outBufferList->mBuffers[handle->iStream[0]].mData,
+ 0,
+ outBufferList->mBuffers[handle->iStream[0]].mDataByteSize );
+ }
+ else { // fill multiple streams with zeros
+ for ( unsigned int i=0; i<handle->nStreams[0]; i++ ) {
+ memset( outBufferList->mBuffers[handle->iStream[0]+i].mData,
+ 0,
+ outBufferList->mBuffers[handle->iStream[0]+i].mDataByteSize );
+ }
+ }
+ }
+ else if ( handle->nStreams[0] == 1 ) {
+ if ( stream_.doConvertBuffer[0] ) { // convert directly to CoreAudio stream buffer
+ convertBuffer( (char *) outBufferList->mBuffers[handle->iStream[0]].mData,
+ stream_.userBuffer[0], stream_.convertInfo[0] );
+ }
+ else { // copy from user buffer
+ memcpy( outBufferList->mBuffers[handle->iStream[0]].mData,
+ stream_.userBuffer[0],
+ outBufferList->mBuffers[handle->iStream[0]].mDataByteSize );
+ }
+ }
+ else { // fill multiple streams
+ Float32 *inBuffer = (Float32 *) stream_.userBuffer[0];
+ if ( stream_.doConvertBuffer[0] ) {
+ convertBuffer( stream_.deviceBuffer, stream_.userBuffer[0], stream_.convertInfo[0] );
+ inBuffer = (Float32 *) stream_.deviceBuffer;
+ }
+
+ if ( stream_.deviceInterleaved[0] == false ) { // mono mode
+ UInt32 bufferBytes = outBufferList->mBuffers[handle->iStream[0]].mDataByteSize;
+ for ( unsigned int i=0; i<stream_.nUserChannels[0]; i++ ) {
+ memcpy( outBufferList->mBuffers[handle->iStream[0]+i].mData,
+ (void *)&inBuffer[i*stream_.bufferSize], bufferBytes );
+ }
+ }
+ else { // fill multiple multi-channel streams with interleaved data
+ UInt32 streamChannels, channelsLeft, inJump, outJump, inOffset;
+ Float32 *out, *in;
+
+ bool inInterleaved = ( stream_.userInterleaved ) ? true : false;
+ UInt32 inChannels = stream_.nUserChannels[0];
+ if ( stream_.doConvertBuffer[0] ) {
+ inInterleaved = true; // device buffer will always be interleaved for nStreams > 1 and not mono mode
+ inChannels = stream_.nDeviceChannels[0];
+ }
+
+ if ( inInterleaved ) inOffset = 1;
+ else inOffset = stream_.bufferSize;
+
+ channelsLeft = inChannels;
+ for ( unsigned int i=0; i<handle->nStreams[0]; i++ ) {
+ in = inBuffer;
+ out = (Float32 *) outBufferList->mBuffers[handle->iStream[0]+i].mData;
+ streamChannels = outBufferList->mBuffers[handle->iStream[0]+i].mNumberChannels;
+
+ outJump = 0;
+ // Account for possible channel offset in first stream
+ if ( i == 0 && stream_.channelOffset[0] > 0 ) {
+ streamChannels -= stream_.channelOffset[0];
+ outJump = stream_.channelOffset[0];
+ out += outJump;
+ }
+
+ // Account for possible unfilled channels at end of the last stream
+ if ( streamChannels > channelsLeft ) {
+ outJump = streamChannels - channelsLeft;
+ streamChannels = channelsLeft;
+ }
+
+ // Determine input buffer offsets and skips
+ if ( inInterleaved ) {
+ inJump = inChannels;
+ in += inChannels - channelsLeft;
+ }
+ else {
+ inJump = 1;
+ in += (inChannels - channelsLeft) * inOffset;
+ }
+
+ for ( unsigned int i=0; i<stream_.bufferSize; i++ ) {
+ for ( unsigned int j=0; j<streamChannels; j++ ) {
+ *out++ = in[j*inOffset];
+ }
+ out += outJump;
+ in += inJump;
+ }
+ channelsLeft -= streamChannels;
+ }
+ }
+ }
+ }
+
+ // Don't bother draining input
+ if ( handle->drainCounter ) {
+ handle->drainCounter++;
+ goto unlock;
+ }
+
+ AudioDeviceID inputDevice;
+ inputDevice = handle->id[1];
+ if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && deviceId == inputDevice ) ) {
+
+ if ( handle->nStreams[1] == 1 ) {
+ if ( stream_.doConvertBuffer[1] ) { // convert directly from CoreAudio stream buffer
+ convertBuffer( stream_.userBuffer[1],
+ (char *) inBufferList->mBuffers[handle->iStream[1]].mData,
+ stream_.convertInfo[1] );
+ }
+ else { // copy to user buffer
+ memcpy( stream_.userBuffer[1],
+ inBufferList->mBuffers[handle->iStream[1]].mData,
+ inBufferList->mBuffers[handle->iStream[1]].mDataByteSize );
+ }
+ }
+ else { // read from multiple streams
+ Float32 *outBuffer = (Float32 *) stream_.userBuffer[1];
+ if ( stream_.doConvertBuffer[1] ) outBuffer = (Float32 *) stream_.deviceBuffer;
+
+ if ( stream_.deviceInterleaved[1] == false ) { // mono mode
+ UInt32 bufferBytes = inBufferList->mBuffers[handle->iStream[1]].mDataByteSize;
+ for ( unsigned int i=0; i<stream_.nUserChannels[1]; i++ ) {
+ memcpy( (void *)&outBuffer[i*stream_.bufferSize],
+ inBufferList->mBuffers[handle->iStream[1]+i].mData, bufferBytes );
+ }
+ }
+ else { // read from multiple multi-channel streams
+ UInt32 streamChannels, channelsLeft, inJump, outJump, outOffset;
+ Float32 *out, *in;
+
+ bool outInterleaved = ( stream_.userInterleaved ) ? true : false;
+ UInt32 outChannels = stream_.nUserChannels[1];
+ if ( stream_.doConvertBuffer[1] ) {
+ outInterleaved = true; // device buffer will always be interleaved for nStreams > 1 and not mono mode
+ outChannels = stream_.nDeviceChannels[1];
+ }
+
+ if ( outInterleaved ) outOffset = 1;
+ else outOffset = stream_.bufferSize;
+
+ channelsLeft = outChannels;
+ for ( unsigned int i=0; i<handle->nStreams[1]; i++ ) {
+ out = outBuffer;
+ in = (Float32 *) inBufferList->mBuffers[handle->iStream[1]+i].mData;
+ streamChannels = inBufferList->mBuffers[handle->iStream[1]+i].mNumberChannels;
+
+ inJump = 0;
+ // Account for possible channel offset in first stream
+ if ( i == 0 && stream_.channelOffset[1] > 0 ) {
+ streamChannels -= stream_.channelOffset[1];
+ inJump = stream_.channelOffset[1];
+ in += inJump;
+ }
+
+ // Account for possible unread channels at end of the last stream
+ if ( streamChannels > channelsLeft ) {
+ inJump = streamChannels - channelsLeft;
+ streamChannels = channelsLeft;
+ }
+
+ // Determine output buffer offsets and skips
+ if ( outInterleaved ) {
+ outJump = outChannels;
+ out += outChannels - channelsLeft;
+ }
+ else {
+ outJump = 1;
+ out += (outChannels - channelsLeft) * outOffset;
+ }
+
+ for ( unsigned int i=0; i<stream_.bufferSize; i++ ) {
+ for ( unsigned int j=0; j<streamChannels; j++ ) {
+ out[j*outOffset] = *in++;
+ }
+ out += outJump;
+ in += inJump;
+ }
+ channelsLeft -= streamChannels;
+ }
+ }
+
+ if ( stream_.doConvertBuffer[1] ) { // convert from our internal "device" buffer
+ convertBuffer( stream_.userBuffer[1],
+ stream_.deviceBuffer,
+ stream_.convertInfo[1] );
+ }
+ }
+ }
+
+ unlock:
+ //MUTEX_UNLOCK( &stream_.mutex );
+
+ RtApi::tickStreamTime();
+ return SUCCESS;
+}
+
+const char* RtApiCore :: getErrorCode( OSStatus code )
+{
+ switch( code ) {
+
+ case kAudioHardwareNotRunningError:
+ return "kAudioHardwareNotRunningError";
+
+ case kAudioHardwareUnspecifiedError:
+ return "kAudioHardwareUnspecifiedError";
+
+ case kAudioHardwareUnknownPropertyError:
+ return "kAudioHardwareUnknownPropertyError";
+
+ case kAudioHardwareBadPropertySizeError:
+ return "kAudioHardwareBadPropertySizeError";
+
+ case kAudioHardwareIllegalOperationError:
+ return "kAudioHardwareIllegalOperationError";
+
+ case kAudioHardwareBadObjectError:
+ return "kAudioHardwareBadObjectError";
+
+ case kAudioHardwareBadDeviceError:
+ return "kAudioHardwareBadDeviceError";
+
+ case kAudioHardwareBadStreamError:
+ return "kAudioHardwareBadStreamError";
+
+ case kAudioHardwareUnsupportedOperationError:
+ return "kAudioHardwareUnsupportedOperationError";
+
+ case kAudioDeviceUnsupportedFormatError:
+ return "kAudioDeviceUnsupportedFormatError";
+
+ case kAudioDevicePermissionsError:
+ return "kAudioDevicePermissionsError";
+
+ default:
+ return "CoreAudio unknown error";
+ }
+}
+
+ //******************** End of __MACOSX_CORE__ *********************//
+#endif
+
+#if defined(__UNIX_JACK__)
+
+// JACK is a low-latency audio server, originally written for the
+// GNU/Linux operating system and now also ported to OS-X. It can
+// connect a number of different applications to an audio device, as
+// well as allowing them to share audio between themselves.
+//
+// When using JACK with RtAudio, "devices" refer to JACK clients that
+// have ports connected to the server. The JACK server is typically
+// started in a terminal as follows:
+//
+// .jackd -d alsa -d hw:0
+//
+// or through an interface program such as qjackctl. Many of the
+// parameters normally set for a stream are fixed by the JACK server
+// and can be specified when the JACK server is started. In
+// particular,
+//
+// .jackd -d alsa -d hw:0 -r 44100 -p 512 -n 4
+//
+// specifies a sample rate of 44100 Hz, a buffer size of 512 sample
+// frames, and number of buffers = 4. Once the server is running, it
+// is not possible to override these values. If the values are not
+// specified in the command-line, the JACK server uses default values.
+//
+// The JACK server does not have to be running when an instance of
+// RtApiJack is created, though the function getDeviceCount() will
+// report 0 devices found until JACK has been started. When no
+// devices are available (i.e., the JACK server is not running), a
+// stream cannot be opened.
+
+#include <jack/jack.h>
+#include <unistd.h>
+#include <cstdio>
+
+// A structure to hold various information related to the Jack API
+// implementation.
+struct JackHandle {
+ jack_client_t *client;
+ jack_port_t **ports[2];
+ std::string deviceName[2];
+ bool xrun[2];
+ pthread_cond_t condition;
+ int drainCounter; // Tracks callback counts when draining
+ bool internalDrain; // Indicates if stop is initiated from callback or not.
+
+ JackHandle()
+ :client(0), drainCounter(0), internalDrain(false) { ports[0] = 0; ports[1] = 0; xrun[0] = false; xrun[1] = false; }
+};
+
+static void jackSilentError( const char * ) {};
+
+RtApiJack :: RtApiJack()
+{
+ // Nothing to do here.
+#if !defined(__RTAUDIO_DEBUG__)
+ // Turn off Jack's internal error reporting.
+ jack_set_error_function( &jackSilentError );
+#endif
+}
+
+RtApiJack :: ~RtApiJack()
+{
+ if ( stream_.state != STREAM_CLOSED ) closeStream();
+}
+
+unsigned int RtApiJack :: getDeviceCount( void )
+{
+ // See if we can become a jack client.
+ jack_options_t options = (jack_options_t) ( JackNoStartServer ); //JackNullOption;
+ jack_status_t *status = NULL;
+ jack_client_t *client = jack_client_open( "RtApiJackCount", options, status );
+ if ( client == 0 ) return 0;
+
+ const char **ports;
+ std::string port, previousPort;
+ unsigned int nChannels = 0, nDevices = 0;
+ ports = jack_get_ports( client, NULL, NULL, 0 );
+ if ( ports ) {
+ // Parse the port names up to the first colon (:).
+ size_t iColon = 0;
+ do {
+ port = (char *) ports[ nChannels ];
+ iColon = port.find(":");
+ if ( iColon != std::string::npos ) {
+ port = port.substr( 0, iColon + 1 );
+ if ( port != previousPort ) {
+ nDevices++;
+ previousPort = port;
+ }
+ }
+ } while ( ports[++nChannels] );
+ free( ports );
+ }
+
+ jack_client_close( client );
+ return nDevices;
+}
+
+RtAudio::DeviceInfo RtApiJack :: getDeviceInfo( unsigned int device )
+{
+ RtAudio::DeviceInfo info;
+ info.probed = false;
+
+ jack_options_t options = (jack_options_t) ( JackNoStartServer ); //JackNullOption
+ jack_status_t *status = NULL;
+ jack_client_t *client = jack_client_open( "RtApiJackInfo", options, status );
+ if ( client == 0 ) {
+ errorText_ = "RtApiJack::getDeviceInfo: Jack server not found or connection error!";
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ const char **ports;
+ std::string port, previousPort;
+ unsigned int nPorts = 0, nDevices = 0;
+ ports = jack_get_ports( client, NULL, NULL, 0 );
+ if ( ports ) {
+ // Parse the port names up to the first colon (:).
+ size_t iColon = 0;
+ do {
+ port = (char *) ports[ nPorts ];
+ iColon = port.find(":");
+ if ( iColon != std::string::npos ) {
+ port = port.substr( 0, iColon );
+ if ( port != previousPort ) {
+ if ( nDevices == device ) info.name = port;
+ nDevices++;
+ previousPort = port;
+ }
+ }
+ } while ( ports[++nPorts] );
+ free( ports );
+ }
+
+ if ( device >= nDevices ) {
+ jack_client_close( client );
+ errorText_ = "RtApiJack::getDeviceInfo: device ID is invalid!";
+ error( RtAudioError::INVALID_USE );
+ return info;
+ }
+
+ // Get the current jack server sample rate.
+ info.sampleRates.clear();
+
+ info.preferredSampleRate = jack_get_sample_rate( client );
+ info.sampleRates.push_back( info.preferredSampleRate );
+
+ // Count the available ports containing the client name as device
+ // channels. Jack "input ports" equal RtAudio output channels.
+ unsigned int nChannels = 0;
+ ports = jack_get_ports( client, info.name.c_str(), NULL, JackPortIsInput );
+ if ( ports ) {
+ while ( ports[ nChannels ] ) nChannels++;
+ free( ports );
+ info.outputChannels = nChannels;
+ }
+
+ // Jack "output ports" equal RtAudio input channels.
+ nChannels = 0;
+ ports = jack_get_ports( client, info.name.c_str(), NULL, JackPortIsOutput );
+ if ( ports ) {
+ while ( ports[ nChannels ] ) nChannels++;
+ free( ports );
+ info.inputChannels = nChannels;
+ }
+
+ if ( info.outputChannels == 0 && info.inputChannels == 0 ) {
+ jack_client_close(client);
+ errorText_ = "RtApiJack::getDeviceInfo: error determining Jack input/output channels!";
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ // If device opens for both playback and capture, we determine the channels.
+ if ( info.outputChannels > 0 && info.inputChannels > 0 )
+ info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;
+
+ // Jack always uses 32-bit floats.
+ info.nativeFormats = RTAUDIO_FLOAT32;
+
+ // Jack doesn't provide default devices so we'll use the first available one.
+ if ( device == 0 && info.outputChannels > 0 )
+ info.isDefaultOutput = true;
+ if ( device == 0 && info.inputChannels > 0 )
+ info.isDefaultInput = true;
+
+ jack_client_close(client);
+ info.probed = true;
+ return info;
+}
+
+static int jackCallbackHandler( jack_nframes_t nframes, void *infoPointer )
+{
+ CallbackInfo *info = (CallbackInfo *) infoPointer;
+
+ RtApiJack *object = (RtApiJack *) info->object;
+ if ( object->callbackEvent( (unsigned long) nframes ) == false ) return 1;
+
+ return 0;
+}
+
+// This function will be called by a spawned thread when the Jack
+// server signals that it is shutting down. It is necessary to handle
+// it this way because the jackShutdown() function must return before
+// the jack_deactivate() function (in closeStream()) will return.
+static void *jackCloseStream( void *ptr )
+{
+ CallbackInfo *info = (CallbackInfo *) ptr;
+ RtApiJack *object = (RtApiJack *) info->object;
+
+ object->closeStream();
+
+ pthread_exit( NULL );
+}
+static void jackShutdown( void *infoPointer )
+{
+ CallbackInfo *info = (CallbackInfo *) infoPointer;
+ RtApiJack *object = (RtApiJack *) info->object;
+
+ // Check current stream state. If stopped, then we'll assume this
+ // was called as a result of a call to RtApiJack::stopStream (the
+ // deactivation of a client handle causes this function to be called).
+ // If not, we'll assume the Jack server is shutting down or some
+ // other problem occurred and we should close the stream.
+ if ( object->isStreamRunning() == false ) return;
+
+ ThreadHandle threadId;
+ pthread_create( &threadId, NULL, jackCloseStream, info );
+ std::cerr << "\nRtApiJack: the Jack server is shutting down this client ... stream stopped and closed!!\n" << std::endl;
+}
+
+static int jackXrun( void *infoPointer )
+{
+ JackHandle *handle = (JackHandle *) infoPointer;
+
+ if ( handle->ports[0] ) handle->xrun[0] = true;
+ if ( handle->ports[1] ) handle->xrun[1] = true;
+
+ return 0;
+}
+
+bool RtApiJack :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
+ unsigned int firstChannel, unsigned int sampleRate,
+ RtAudioFormat format, unsigned int *bufferSize,
+ RtAudio::StreamOptions *options )
+{
+ JackHandle *handle = (JackHandle *) stream_.apiHandle;
+
+ // Look for jack server and try to become a client (only do once per stream).
+ jack_client_t *client = 0;
+ if ( mode == OUTPUT || ( mode == INPUT && stream_.mode != OUTPUT ) ) {
+ jack_options_t jackoptions = (jack_options_t) ( JackNoStartServer ); //JackNullOption;
+ jack_status_t *status = NULL;
+ if ( options && !options->streamName.empty() )
+ client = jack_client_open( options->streamName.c_str(), jackoptions, status );
+ else
+ client = jack_client_open( "RtApiJack", jackoptions, status );
+ if ( client == 0 ) {
+ errorText_ = "RtApiJack::probeDeviceOpen: Jack server not found or connection error!";
+ error( RtAudioError::WARNING );
+ return FAILURE;
+ }
+ }
+ else {
+ // The handle must have been created on an earlier pass.
+ client = handle->client;
+ }
+
+ const char **ports;
+ std::string port, previousPort, deviceName;
+ unsigned int nPorts = 0, nDevices = 0;
+ ports = jack_get_ports( client, NULL, NULL, 0 );
+ if ( ports ) {
+ // Parse the port names up to the first colon (:).
+ size_t iColon = 0;
+ do {
+ port = (char *) ports[ nPorts ];
+ iColon = port.find(":");
+ if ( iColon != std::string::npos ) {
+ port = port.substr( 0, iColon );
+ if ( port != previousPort ) {
+ if ( nDevices == device ) deviceName = port;
+ nDevices++;
+ previousPort = port;
+ }
+ }
+ } while ( ports[++nPorts] );
+ free( ports );
+ }
+
+ if ( device >= nDevices ) {
+ errorText_ = "RtApiJack::probeDeviceOpen: device ID is invalid!";
+ return FAILURE;
+ }
+
+ // Count the available ports containing the client name as device
+ // channels. Jack "input ports" equal RtAudio output channels.
+ unsigned int nChannels = 0;
+ unsigned long flag = JackPortIsInput;
+ if ( mode == INPUT ) flag = JackPortIsOutput;
+ ports = jack_get_ports( client, deviceName.c_str(), NULL, flag );
+ if ( ports ) {
+ while ( ports[ nChannels ] ) nChannels++;
+ free( ports );
+ }
+
+ // Compare the jack ports for specified client to the requested number of channels.
+ if ( nChannels < (channels + firstChannel) ) {
+ errorStream_ << "RtApiJack::probeDeviceOpen: requested number of channels (" << channels << ") + offset (" << firstChannel << ") not found for specified device (" << device << ":" << deviceName << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Check the jack server sample rate.
+ unsigned int jackRate = jack_get_sample_rate( client );
+ if ( sampleRate != jackRate ) {
+ jack_client_close( client );
+ errorStream_ << "RtApiJack::probeDeviceOpen: the requested sample rate (" << sampleRate << ") is different than the JACK server rate (" << jackRate << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+ stream_.sampleRate = jackRate;
+
+ // Get the latency of the JACK port.
+ ports = jack_get_ports( client, deviceName.c_str(), NULL, flag );
+ if ( ports[ firstChannel ] ) {
+ // Added by Ge Wang
+ jack_latency_callback_mode_t cbmode = (mode == INPUT ? JackCaptureLatency : JackPlaybackLatency);
+ // the range (usually the min and max are equal)
+ jack_latency_range_t latrange; latrange.min = latrange.max = 0;
+ // get the latency range
+ jack_port_get_latency_range( jack_port_by_name( client, ports[firstChannel] ), cbmode, &latrange );
+ // be optimistic, use the min!
+ stream_.latency[mode] = latrange.min;
+ //stream_.latency[mode] = jack_port_get_latency( jack_port_by_name( client, ports[ firstChannel ] ) );
+ }
+ free( ports );
+
+ // The jack server always uses 32-bit floating-point data.
+ stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
+ stream_.userFormat = format;
+
+ if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;
+ else stream_.userInterleaved = true;
+
+ // Jack always uses non-interleaved buffers.
+ stream_.deviceInterleaved[mode] = false;
+
+ // Jack always provides host byte-ordered data.
+ stream_.doByteSwap[mode] = false;
+
+ // Get the buffer size. The buffer size and number of buffers
+ // (periods) is set when the jack server is started.
+ stream_.bufferSize = (int) jack_get_buffer_size( client );
+ *bufferSize = stream_.bufferSize;
+
+ stream_.nDeviceChannels[mode] = channels;
+ stream_.nUserChannels[mode] = channels;
+
+ // Set flags for buffer conversion.
+ stream_.doConvertBuffer[mode] = false;
+ if ( stream_.userFormat != stream_.deviceFormat[mode] )
+ stream_.doConvertBuffer[mode] = true;
+ if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&
+ stream_.nUserChannels[mode] > 1 )
+ stream_.doConvertBuffer[mode] = true;
+
+ // Allocate our JackHandle structure for the stream.
+ if ( handle == 0 ) {
+ try {
+ handle = new JackHandle;
+ }
+ catch ( std::bad_alloc& ) {
+ errorText_ = "RtApiJack::probeDeviceOpen: error allocating JackHandle memory.";
+ goto error;
+ }
+
+ if ( pthread_cond_init(&handle->condition, NULL) ) {
+ errorText_ = "RtApiJack::probeDeviceOpen: error initializing pthread condition variable.";
+ goto error;
+ }
+ stream_.apiHandle = (void *) handle;
+ handle->client = client;
+ }
+ handle->deviceName[mode] = deviceName;
+
+ // Allocate necessary internal buffers.
+ unsigned long bufferBytes;
+ bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
+ stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );
+ if ( stream_.userBuffer[mode] == NULL ) {
+ errorText_ = "RtApiJack::probeDeviceOpen: error allocating user buffer memory.";
+ goto error;
+ }
+
+ if ( stream_.doConvertBuffer[mode] ) {
+
+ bool makeBuffer = true;
+ if ( mode == OUTPUT )
+ bufferBytes = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );
+ else { // mode == INPUT
+ bufferBytes = stream_.nDeviceChannels[1] * formatBytes( stream_.deviceFormat[1] );
+ if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
+ unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes(stream_.deviceFormat[0]);
+ if ( bufferBytes < bytesOut ) makeBuffer = false;
+ }
+ }
+
+ if ( makeBuffer ) {
+ bufferBytes *= *bufferSize;
+ if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );
+ stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );
+ if ( stream_.deviceBuffer == NULL ) {
+ errorText_ = "RtApiJack::probeDeviceOpen: error allocating device buffer memory.";
+ goto error;
+ }
+ }
+ }
+
+ // Allocate memory for the Jack ports (channels) identifiers.
+ handle->ports[mode] = (jack_port_t **) malloc ( sizeof (jack_port_t *) * channels );
+ if ( handle->ports[mode] == NULL ) {
+ errorText_ = "RtApiJack::probeDeviceOpen: error allocating port memory.";
+ goto error;
+ }
+
+ stream_.device[mode] = device;
+ stream_.channelOffset[mode] = firstChannel;
+ stream_.state = STREAM_STOPPED;
+ stream_.callbackInfo.object = (void *) this;
+
+ if ( stream_.mode == OUTPUT && mode == INPUT )
+ // We had already set up the stream for output.
+ stream_.mode = DUPLEX;
+ else {
+ stream_.mode = mode;
+ jack_set_process_callback( handle->client, jackCallbackHandler, (void *) &stream_.callbackInfo );
+ jack_set_xrun_callback( handle->client, jackXrun, (void *) &handle );
+ jack_on_shutdown( handle->client, jackShutdown, (void *) &stream_.callbackInfo );
+ }
+
+ // Register our ports.
+ char label[64];
+ if ( mode == OUTPUT ) {
+ for ( unsigned int i=0; i<stream_.nUserChannels[0]; i++ ) {
+ snprintf( label, 64, "outport %d", i );
+ handle->ports[0][i] = jack_port_register( handle->client, (const char *)label,
+ JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 );
+ }
+ }
+ else {
+ for ( unsigned int i=0; i<stream_.nUserChannels[1]; i++ ) {
+ snprintf( label, 64, "inport %d", i );
+ handle->ports[1][i] = jack_port_register( handle->client, (const char *)label,
+ JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 );
+ }
+ }
+
+ // Setup the buffer conversion information structure. We don't use
+ // buffers to do channel offsets, so we override that parameter
+ // here.
+ if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, 0 );
+
+ return SUCCESS;
+
+ error:
+ if ( handle ) {
+ pthread_cond_destroy( &handle->condition );
+ jack_client_close( handle->client );
+
+ if ( handle->ports[0] ) free( handle->ports[0] );
+ if ( handle->ports[1] ) free( handle->ports[1] );
+
+ delete handle;
+ stream_.apiHandle = 0;
+ }
+
+ for ( int i=0; i<2; i++ ) {
+ if ( stream_.userBuffer[i] ) {
+ free( stream_.userBuffer[i] );
+ stream_.userBuffer[i] = 0;
+ }
+ }
+
+ if ( stream_.deviceBuffer ) {
+ free( stream_.deviceBuffer );
+ stream_.deviceBuffer = 0;
+ }
+
+ return FAILURE;
+}
+
+void RtApiJack :: closeStream( void )
+{
+ if ( stream_.state == STREAM_CLOSED ) {
+ errorText_ = "RtApiJack::closeStream(): no open stream to close!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ JackHandle *handle = (JackHandle *) stream_.apiHandle;
+ if ( handle ) {
+
+ if ( stream_.state == STREAM_RUNNING )
+ jack_deactivate( handle->client );
+
+ jack_client_close( handle->client );
+ }
+
+ if ( handle ) {
+ if ( handle->ports[0] ) free( handle->ports[0] );
+ if ( handle->ports[1] ) free( handle->ports[1] );
+ pthread_cond_destroy( &handle->condition );
+ delete handle;
+ stream_.apiHandle = 0;
+ }
+
+ for ( int i=0; i<2; i++ ) {
+ if ( stream_.userBuffer[i] ) {
+ free( stream_.userBuffer[i] );
+ stream_.userBuffer[i] = 0;
+ }
+ }
+
+ if ( stream_.deviceBuffer ) {
+ free( stream_.deviceBuffer );
+ stream_.deviceBuffer = 0;
+ }
+
+ stream_.mode = UNINITIALIZED;
+ stream_.state = STREAM_CLOSED;
+}
+
+void RtApiJack :: startStream( void )
+{
+ verifyStream();
+ if ( stream_.state == STREAM_RUNNING ) {
+ errorText_ = "RtApiJack::startStream(): the stream is already running!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ JackHandle *handle = (JackHandle *) stream_.apiHandle;
+ int result = jack_activate( handle->client );
+ if ( result ) {
+ errorText_ = "RtApiJack::startStream(): unable to activate JACK client!";
+ goto unlock;
+ }
+
+ const char **ports;
+
+ // Get the list of available ports.
+ if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
+ result = 1;
+ ports = jack_get_ports( handle->client, handle->deviceName[0].c_str(), NULL, JackPortIsInput);
+ if ( ports == NULL) {
+ errorText_ = "RtApiJack::startStream(): error determining available JACK input ports!";
+ goto unlock;
+ }
+
+ // Now make the port connections. Since RtAudio wasn't designed to
+ // allow the user to select particular channels of a device, we'll
+ // just open the first "nChannels" ports with offset.
+ for ( unsigned int i=0; i<stream_.nUserChannels[0]; i++ ) {
+ result = 1;
+ if ( ports[ stream_.channelOffset[0] + i ] )
+ result = jack_connect( handle->client, jack_port_name( handle->ports[0][i] ), ports[ stream_.channelOffset[0] + i ] );
+ if ( result ) {
+ free( ports );
+ errorText_ = "RtApiJack::startStream(): error connecting output ports!";
+ goto unlock;
+ }
+ }
+ free(ports);
+ }
+
+ if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
+ result = 1;
+ ports = jack_get_ports( handle->client, handle->deviceName[1].c_str(), NULL, JackPortIsOutput );
+ if ( ports == NULL) {
+ errorText_ = "RtApiJack::startStream(): error determining available JACK output ports!";
+ goto unlock;
+ }
+
+ // Now make the port connections. See note above.
+ for ( unsigned int i=0; i<stream_.nUserChannels[1]; i++ ) {
+ result = 1;
+ if ( ports[ stream_.channelOffset[1] + i ] )
+ result = jack_connect( handle->client, ports[ stream_.channelOffset[1] + i ], jack_port_name( handle->ports[1][i] ) );
+ if ( result ) {
+ free( ports );
+ errorText_ = "RtApiJack::startStream(): error connecting input ports!";
+ goto unlock;
+ }
+ }
+ free(ports);
+ }
+
+ handle->drainCounter = 0;
+ handle->internalDrain = false;
+ stream_.state = STREAM_RUNNING;
+
+ unlock:
+ if ( result == 0 ) return;
+ error( RtAudioError::SYSTEM_ERROR );
+}
+
+void RtApiJack :: stopStream( void )
+{
+ verifyStream();
+ if ( stream_.state == STREAM_STOPPED ) {
+ errorText_ = "RtApiJack::stopStream(): the stream is already stopped!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ JackHandle *handle = (JackHandle *) stream_.apiHandle;
+ if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
+
+ if ( handle->drainCounter == 0 ) {
+ handle->drainCounter = 2;
+ pthread_cond_wait( &handle->condition, &stream_.mutex ); // block until signaled
+ }
+ }
+
+ jack_deactivate( handle->client );
+ stream_.state = STREAM_STOPPED;
+}
+
+void RtApiJack :: abortStream( void )
+{
+ verifyStream();
+ if ( stream_.state == STREAM_STOPPED ) {
+ errorText_ = "RtApiJack::abortStream(): the stream is already stopped!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ JackHandle *handle = (JackHandle *) stream_.apiHandle;
+ handle->drainCounter = 2;
+
+ stopStream();
+}
+
+// This function will be called by a spawned thread when the user
+// callback function signals that the stream should be stopped or
+// aborted. It is necessary to handle it this way because the
+// callbackEvent() function must return before the jack_deactivate()
+// function will return.
+static void *jackStopStream( void *ptr )
+{
+ CallbackInfo *info = (CallbackInfo *) ptr;
+ RtApiJack *object = (RtApiJack *) info->object;
+
+ object->stopStream();
+ pthread_exit( NULL );
+}
+
+bool RtApiJack :: callbackEvent( unsigned long nframes )
+{
+ if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) return SUCCESS;
+ if ( stream_.state == STREAM_CLOSED ) {
+ errorText_ = "RtApiCore::callbackEvent(): the stream is closed ... this shouldn't happen!";
+ error( RtAudioError::WARNING );
+ return FAILURE;
+ }
+ if ( stream_.bufferSize != nframes ) {
+ errorText_ = "RtApiCore::callbackEvent(): the JACK buffer size has changed ... cannot process!";
+ error( RtAudioError::WARNING );
+ return FAILURE;
+ }
+
+ CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
+ JackHandle *handle = (JackHandle *) stream_.apiHandle;
+
+ // Check if we were draining the stream and signal is finished.
+ if ( handle->drainCounter > 3 ) {
+ ThreadHandle threadId;
+
+ stream_.state = STREAM_STOPPING;
+ if ( handle->internalDrain == true )
+ pthread_create( &threadId, NULL, jackStopStream, info );
+ else
+ pthread_cond_signal( &handle->condition );
+ return SUCCESS;
+ }
+
+ // Invoke user callback first, to get fresh output data.
+ if ( handle->drainCounter == 0 ) {
+ RtAudioCallback callback = (RtAudioCallback) info->callback;
+ double streamTime = getStreamTime();
+ RtAudioStreamStatus status = 0;
+ if ( stream_.mode != INPUT && handle->xrun[0] == true ) {
+ status |= RTAUDIO_OUTPUT_UNDERFLOW;
+ handle->xrun[0] = false;
+ }
+ if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) {
+ status |= RTAUDIO_INPUT_OVERFLOW;
+ handle->xrun[1] = false;
+ }
+ int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1],
+ stream_.bufferSize, streamTime, status, info->userData );
+ if ( cbReturnValue == 2 ) {
+ stream_.state = STREAM_STOPPING;
+ handle->drainCounter = 2;
+ ThreadHandle id;
+ pthread_create( &id, NULL, jackStopStream, info );
+ return SUCCESS;
+ }
+ else if ( cbReturnValue == 1 ) {
+ handle->drainCounter = 1;
+ handle->internalDrain = true;
+ }
+ }
+
+ jack_default_audio_sample_t *jackbuffer;
+ unsigned long bufferBytes = nframes * sizeof( jack_default_audio_sample_t );
+ if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
+
+ if ( handle->drainCounter > 1 ) { // write zeros to the output stream
+
+ for ( unsigned int i=0; i<stream_.nDeviceChannels[0]; i++ ) {
+ jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[0][i], (jack_nframes_t) nframes );
+ memset( jackbuffer, 0, bufferBytes );
+ }
+
+ }
+ else if ( stream_.doConvertBuffer[0] ) {
+
+ convertBuffer( stream_.deviceBuffer, stream_.userBuffer[0], stream_.convertInfo[0] );
+
+ for ( unsigned int i=0; i<stream_.nDeviceChannels[0]; i++ ) {
+ jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[0][i], (jack_nframes_t) nframes );
+ memcpy( jackbuffer, &stream_.deviceBuffer[i*bufferBytes], bufferBytes );
+ }
+ }
+ else { // no buffer conversion
+ for ( unsigned int i=0; i<stream_.nUserChannels[0]; i++ ) {
+ jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[0][i], (jack_nframes_t) nframes );
+ memcpy( jackbuffer, &stream_.userBuffer[0][i*bufferBytes], bufferBytes );
+ }
+ }
+ }
+
+ // Don't bother draining input
+ if ( handle->drainCounter ) {
+ handle->drainCounter++;
+ goto unlock;
+ }
+
+ if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
+
+ if ( stream_.doConvertBuffer[1] ) {
+ for ( unsigned int i=0; i<stream_.nDeviceChannels[1]; i++ ) {
+ jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[1][i], (jack_nframes_t) nframes );
+ memcpy( &stream_.deviceBuffer[i*bufferBytes], jackbuffer, bufferBytes );
+ }
+ convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );
+ }
+ else { // no buffer conversion
+ for ( unsigned int i=0; i<stream_.nUserChannels[1]; i++ ) {
+ jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer( handle->ports[1][i], (jack_nframes_t) nframes );
+ memcpy( &stream_.userBuffer[1][i*bufferBytes], jackbuffer, bufferBytes );
+ }
+ }
+ }
+
+ unlock:
+ RtApi::tickStreamTime();
+ return SUCCESS;
+}
+ //******************** End of __UNIX_JACK__ *********************//
+#endif
+
+#if defined(__WINDOWS_ASIO__) // ASIO API on Windows
+
+// The ASIO API is designed around a callback scheme, so this
+// implementation is similar to that used for OS-X CoreAudio and Linux
+// Jack. The primary constraint with ASIO is that it only allows
+// access to a single driver at a time. Thus, it is not possible to
+// have more than one simultaneous RtAudio stream.
+//
+// This implementation also requires a number of external ASIO files
+// and a few global variables. The ASIO callback scheme does not
+// allow for the passing of user data, so we must create a global
+// pointer to our callbackInfo structure.
+//
+// On unix systems, we make use of a pthread condition variable.
+// Since there is no equivalent in Windows, I hacked something based
+// on information found in
+// http://www.cs.wustl.edu/~schmidt/win32-cv-1.html.
+
+#include "asiosys.h"
+#include "asio.h"
+#include "iasiothiscallresolver.h"
+#include "asiodrivers.h"
+#include <cmath>
+
+static AsioDrivers drivers;
+static ASIOCallbacks asioCallbacks;
+static ASIODriverInfo driverInfo;
+static CallbackInfo *asioCallbackInfo;
+static bool asioXRun;
+
+struct AsioHandle {
+ int drainCounter; // Tracks callback counts when draining
+ bool internalDrain; // Indicates if stop is initiated from callback or not.
+ ASIOBufferInfo *bufferInfos;
+ HANDLE condition;
+
+ AsioHandle()
+ :drainCounter(0), internalDrain(false), bufferInfos(0) {}
+};
+
+// Function declarations (definitions at end of section)
+static const char* getAsioErrorString( ASIOError result );
+static void sampleRateChanged( ASIOSampleRate sRate );
+static long asioMessages( long selector, long value, void* message, double* opt );
+
+RtApiAsio :: RtApiAsio()
+{
+ // ASIO cannot run on a multi-threaded appartment. You can call
+ // CoInitialize beforehand, but it must be for appartment threading
+ // (in which case, CoInitilialize will return S_FALSE here).
+ coInitialized_ = false;
+ HRESULT hr = CoInitialize( NULL );
+ if ( FAILED(hr) ) {
+ errorText_ = "RtApiAsio::ASIO requires a single-threaded appartment. Call CoInitializeEx(0,COINIT_APARTMENTTHREADED)";
+ error( RtAudioError::WARNING );
+ }
+ coInitialized_ = true;
+
+ drivers.removeCurrentDriver();
+ driverInfo.asioVersion = 2;
+
+ // See note in DirectSound implementation about GetDesktopWindow().
+ driverInfo.sysRef = GetForegroundWindow();
+}
+
+RtApiAsio :: ~RtApiAsio()
+{
+ if ( stream_.state != STREAM_CLOSED ) closeStream();
+ if ( coInitialized_ ) CoUninitialize();
+}
+
+unsigned int RtApiAsio :: getDeviceCount( void )
+{
+ return (unsigned int) drivers.asioGetNumDev();
+}
+
+RtAudio::DeviceInfo RtApiAsio :: getDeviceInfo( unsigned int device )
+{
+ RtAudio::DeviceInfo info;
+ info.probed = false;
+
+ // Get device ID
+ unsigned int nDevices = getDeviceCount();
+ if ( nDevices == 0 ) {
+ errorText_ = "RtApiAsio::getDeviceInfo: no devices found!";
+ error( RtAudioError::INVALID_USE );
+ return info;
+ }
+
+ if ( device >= nDevices ) {
+ errorText_ = "RtApiAsio::getDeviceInfo: device ID is invalid!";
+ error( RtAudioError::INVALID_USE );
+ return info;
+ }
+
+ // If a stream is already open, we cannot probe other devices. Thus, use the saved results.
+ if ( stream_.state != STREAM_CLOSED ) {
+ if ( device >= devices_.size() ) {
+ errorText_ = "RtApiAsio::getDeviceInfo: device ID was not present before stream was opened.";
+ error( RtAudioError::WARNING );
+ return info;
+ }
+ return devices_[ device ];
+ }
+
+ char driverName[32];
+ ASIOError result = drivers.asioGetDriverName( (int) device, driverName, 32 );
+ if ( result != ASE_OK ) {
+ errorStream_ << "RtApiAsio::getDeviceInfo: unable to get driver name (" << getAsioErrorString( result ) << ").";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ info.name = driverName;
+
+ if ( !drivers.loadDriver( driverName ) ) {
+ errorStream_ << "RtApiAsio::getDeviceInfo: unable to load driver (" << driverName << ").";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ result = ASIOInit( &driverInfo );
+ if ( result != ASE_OK ) {
+ errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") initializing driver (" << driverName << ").";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ // Determine the device channel information.
+ long inputChannels, outputChannels;
+ result = ASIOGetChannels( &inputChannels, &outputChannels );
+ if ( result != ASE_OK ) {
+ drivers.removeCurrentDriver();
+ errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") getting channel count (" << driverName << ").";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ info.outputChannels = outputChannels;
+ info.inputChannels = inputChannels;
+ if ( info.outputChannels > 0 && info.inputChannels > 0 )
+ info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;
+
+ // Determine the supported sample rates.
+ info.sampleRates.clear();
+ for ( unsigned int i=0; i<MAX_SAMPLE_RATES; i++ ) {
+ result = ASIOCanSampleRate( (ASIOSampleRate) SAMPLE_RATES[i] );
+ if ( result == ASE_OK ) {
+ info.sampleRates.push_back( SAMPLE_RATES[i] );
+
+ if ( !info.preferredSampleRate || ( SAMPLE_RATES[i] <= 48000 && SAMPLE_RATES[i] > info.preferredSampleRate ) )
+ info.preferredSampleRate = SAMPLE_RATES[i];
+ }
+ }
+
+ // Determine supported data types ... just check first channel and assume rest are the same.
+ ASIOChannelInfo channelInfo;
+ channelInfo.channel = 0;
+ channelInfo.isInput = true;
+ if ( info.inputChannels <= 0 ) channelInfo.isInput = false;
+ result = ASIOGetChannelInfo( &channelInfo );
+ if ( result != ASE_OK ) {
+ drivers.removeCurrentDriver();
+ errorStream_ << "RtApiAsio::getDeviceInfo: error (" << getAsioErrorString( result ) << ") getting driver channel info (" << driverName << ").";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ info.nativeFormats = 0;
+ if ( channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB )
+ info.nativeFormats |= RTAUDIO_SINT16;
+ else if ( channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB )
+ info.nativeFormats |= RTAUDIO_SINT32;
+ else if ( channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB )
+ info.nativeFormats |= RTAUDIO_FLOAT32;
+ else if ( channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB )
+ info.nativeFormats |= RTAUDIO_FLOAT64;
+ else if ( channelInfo.type == ASIOSTInt24MSB || channelInfo.type == ASIOSTInt24LSB )
+ info.nativeFormats |= RTAUDIO_SINT24;
+
+ if ( info.outputChannels > 0 )
+ if ( getDefaultOutputDevice() == device ) info.isDefaultOutput = true;
+ if ( info.inputChannels > 0 )
+ if ( getDefaultInputDevice() == device ) info.isDefaultInput = true;
+
+ info.probed = true;
+ drivers.removeCurrentDriver();
+ return info;
+}
+
+static void bufferSwitch( long index, ASIOBool /*processNow*/ )
+{
+ RtApiAsio *object = (RtApiAsio *) asioCallbackInfo->object;
+ object->callbackEvent( index );
+}
+
+void RtApiAsio :: saveDeviceInfo( void )
+{
+ devices_.clear();
+
+ unsigned int nDevices = getDeviceCount();
+ devices_.resize( nDevices );
+ for ( unsigned int i=0; i<nDevices; i++ )
+ devices_[i] = getDeviceInfo( i );
+}
+
+bool RtApiAsio :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
+ unsigned int firstChannel, unsigned int sampleRate,
+ RtAudioFormat format, unsigned int *bufferSize,
+ RtAudio::StreamOptions *options )
+{////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ bool isDuplexInput = mode == INPUT && stream_.mode == OUTPUT;
+
+ // For ASIO, a duplex stream MUST use the same driver.
+ if ( isDuplexInput && stream_.device[0] != device ) {
+ errorText_ = "RtApiAsio::probeDeviceOpen: an ASIO duplex stream must use the same device for input and output!";
+ return FAILURE;
+ }
+
+ char driverName[32];
+ ASIOError result = drivers.asioGetDriverName( (int) device, driverName, 32 );
+ if ( result != ASE_OK ) {
+ errorStream_ << "RtApiAsio::probeDeviceOpen: unable to get driver name (" << getAsioErrorString( result ) << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Only load the driver once for duplex stream.
+ if ( !isDuplexInput ) {
+ // The getDeviceInfo() function will not work when a stream is open
+ // because ASIO does not allow multiple devices to run at the same
+ // time. Thus, we'll probe the system before opening a stream and
+ // save the results for use by getDeviceInfo().
+ this->saveDeviceInfo();
+
+ if ( !drivers.loadDriver( driverName ) ) {
+ errorStream_ << "RtApiAsio::probeDeviceOpen: unable to load driver (" << driverName << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ result = ASIOInit( &driverInfo );
+ if ( result != ASE_OK ) {
+ errorStream_ << "RtApiAsio::probeDeviceOpen: error (" << getAsioErrorString( result ) << ") initializing driver (" << driverName << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+ }
+
+ // keep them before any "goto error", they are used for error cleanup + goto device boundary checks
+ bool buffersAllocated = false;
+ AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
+ unsigned int nChannels;
+
+
+ // Check the device channel count.
+ long inputChannels, outputChannels;
+ result = ASIOGetChannels( &inputChannels, &outputChannels );
+ if ( result != ASE_OK ) {
+ errorStream_ << "RtApiAsio::probeDeviceOpen: error (" << getAsioErrorString( result ) << ") getting channel count (" << driverName << ").";
+ errorText_ = errorStream_.str();
+ goto error;
+ }
+
+ if ( ( mode == OUTPUT && (channels+firstChannel) > (unsigned int) outputChannels) ||
+ ( mode == INPUT && (channels+firstChannel) > (unsigned int) inputChannels) ) {
+ errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested channel count (" << channels << ") + offset (" << firstChannel << ").";
+ errorText_ = errorStream_.str();
+ goto error;
+ }
+ stream_.nDeviceChannels[mode] = channels;
+ stream_.nUserChannels[mode] = channels;
+ stream_.channelOffset[mode] = firstChannel;
+
+ // Verify the sample rate is supported.
+ result = ASIOCanSampleRate( (ASIOSampleRate) sampleRate );
+ if ( result != ASE_OK ) {
+ errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") does not support requested sample rate (" << sampleRate << ").";
+ errorText_ = errorStream_.str();
+ goto error;
+ }
+
+ // Get the current sample rate
+ ASIOSampleRate currentRate;
+ result = ASIOGetSampleRate( &currentRate );
+ if ( result != ASE_OK ) {
+ errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error getting sample rate.";
+ errorText_ = errorStream_.str();
+ goto error;
+ }
+
+ // Set the sample rate only if necessary
+ if ( currentRate != sampleRate ) {
+ result = ASIOSetSampleRate( (ASIOSampleRate) sampleRate );
+ if ( result != ASE_OK ) {
+ errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error setting sample rate (" << sampleRate << ").";
+ errorText_ = errorStream_.str();
+ goto error;
+ }
+ }
+
+ // Determine the driver data type.
+ ASIOChannelInfo channelInfo;
+ channelInfo.channel = 0;
+ if ( mode == OUTPUT ) channelInfo.isInput = false;
+ else channelInfo.isInput = true;
+ result = ASIOGetChannelInfo( &channelInfo );
+ if ( result != ASE_OK ) {
+ errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting data format.";
+ errorText_ = errorStream_.str();
+ goto error;
+ }
+
+ // Assuming WINDOWS host is always little-endian.
+ stream_.doByteSwap[mode] = false;
+ stream_.userFormat = format;
+ stream_.deviceFormat[mode] = 0;
+ if ( channelInfo.type == ASIOSTInt16MSB || channelInfo.type == ASIOSTInt16LSB ) {
+ stream_.deviceFormat[mode] = RTAUDIO_SINT16;
+ if ( channelInfo.type == ASIOSTInt16MSB ) stream_.doByteSwap[mode] = true;
+ }
+ else if ( channelInfo.type == ASIOSTInt32MSB || channelInfo.type == ASIOSTInt32LSB ) {
+ stream_.deviceFormat[mode] = RTAUDIO_SINT32;
+ if ( channelInfo.type == ASIOSTInt32MSB ) stream_.doByteSwap[mode] = true;
+ }
+ else if ( channelInfo.type == ASIOSTFloat32MSB || channelInfo.type == ASIOSTFloat32LSB ) {
+ stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
+ if ( channelInfo.type == ASIOSTFloat32MSB ) stream_.doByteSwap[mode] = true;
+ }
+ else if ( channelInfo.type == ASIOSTFloat64MSB || channelInfo.type == ASIOSTFloat64LSB ) {
+ stream_.deviceFormat[mode] = RTAUDIO_FLOAT64;
+ if ( channelInfo.type == ASIOSTFloat64MSB ) stream_.doByteSwap[mode] = true;
+ }
+ else if ( channelInfo.type == ASIOSTInt24MSB || channelInfo.type == ASIOSTInt24LSB ) {
+ stream_.deviceFormat[mode] = RTAUDIO_SINT24;
+ if ( channelInfo.type == ASIOSTInt24MSB ) stream_.doByteSwap[mode] = true;
+ }
+
+ if ( stream_.deviceFormat[mode] == 0 ) {
+ errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") data format not supported by RtAudio.";
+ errorText_ = errorStream_.str();
+ goto error;
+ }
+
+ // Set the buffer size. For a duplex stream, this will end up
+ // setting the buffer size based on the input constraints, which
+ // should be ok.
+ long minSize, maxSize, preferSize, granularity;
+ result = ASIOGetBufferSize( &minSize, &maxSize, &preferSize, &granularity );
+ if ( result != ASE_OK ) {
+ errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting buffer size.";
+ errorText_ = errorStream_.str();
+ goto error;
+ }
+
+ if ( isDuplexInput ) {
+ // When this is the duplex input (output was opened before), then we have to use the same
+ // buffersize as the output, because it might use the preferred buffer size, which most
+ // likely wasn't passed as input to this. The buffer sizes have to be identically anyway,
+ // So instead of throwing an error, make them equal. The caller uses the reference
+ // to the "bufferSize" param as usual to set up processing buffers.
+
+ *bufferSize = stream_.bufferSize;
+
+ } else {
+ if ( *bufferSize == 0 ) *bufferSize = preferSize;
+ else if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize;
+ else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize;
+ else if ( granularity == -1 ) {
+ // Make sure bufferSize is a power of two.
+ int log2_of_min_size = 0;
+ int log2_of_max_size = 0;
+
+ for ( unsigned int i = 0; i < sizeof(long) * 8; i++ ) {
+ if ( minSize & ((long)1 << i) ) log2_of_min_size = i;
+ if ( maxSize & ((long)1 << i) ) log2_of_max_size = i;
+ }
+
+ long min_delta = std::abs( (long)*bufferSize - ((long)1 << log2_of_min_size) );
+ int min_delta_num = log2_of_min_size;
+
+ for (int i = log2_of_min_size + 1; i <= log2_of_max_size; i++) {
+ long current_delta = std::abs( (long)*bufferSize - ((long)1 << i) );
+ if (current_delta < min_delta) {
+ min_delta = current_delta;
+ min_delta_num = i;
+ }
+ }
+
+ *bufferSize = ( (unsigned int)1 << min_delta_num );
+ if ( *bufferSize < (unsigned int) minSize ) *bufferSize = (unsigned int) minSize;
+ else if ( *bufferSize > (unsigned int) maxSize ) *bufferSize = (unsigned int) maxSize;
+ }
+ else if ( granularity != 0 ) {
+ // Set to an even multiple of granularity, rounding up.
+ *bufferSize = (*bufferSize + granularity-1) / granularity * granularity;
+ }
+ }
+
+ /*
+ // we don't use it anymore, see above!
+ // Just left it here for the case...
+ if ( isDuplexInput && stream_.bufferSize != *bufferSize ) {
+ errorText_ = "RtApiAsio::probeDeviceOpen: input/output buffersize discrepancy!";
+ goto error;
+ }
+ */
+
+ stream_.bufferSize = *bufferSize;
+ stream_.nBuffers = 2;
+
+ if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;
+ else stream_.userInterleaved = true;
+
+ // ASIO always uses non-interleaved buffers.
+ stream_.deviceInterleaved[mode] = false;
+
+ // Allocate, if necessary, our AsioHandle structure for the stream.
+ if ( handle == 0 ) {
+ try {
+ handle = new AsioHandle;
+ }
+ catch ( std::bad_alloc& ) {
+ errorText_ = "RtApiAsio::probeDeviceOpen: error allocating AsioHandle memory.";
+ goto error;
+ }
+ handle->bufferInfos = 0;
+
+ // Create a manual-reset event.
+ handle->condition = CreateEvent( NULL, // no security
+ TRUE, // manual-reset
+ FALSE, // non-signaled initially
+ NULL ); // unnamed
+ stream_.apiHandle = (void *) handle;
+ }
+
+ // Create the ASIO internal buffers. Since RtAudio sets up input
+ // and output separately, we'll have to dispose of previously
+ // created output buffers for a duplex stream.
+ if ( mode == INPUT && stream_.mode == OUTPUT ) {
+ ASIODisposeBuffers();
+ if ( handle->bufferInfos ) free( handle->bufferInfos );
+ }
+
+ // Allocate, initialize, and save the bufferInfos in our stream callbackInfo structure.
+ unsigned int i;
+ nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1];
+ handle->bufferInfos = (ASIOBufferInfo *) malloc( nChannels * sizeof(ASIOBufferInfo) );
+ if ( handle->bufferInfos == NULL ) {
+ errorStream_ << "RtApiAsio::probeDeviceOpen: error allocating bufferInfo memory for driver (" << driverName << ").";
+ errorText_ = errorStream_.str();
+ goto error;
+ }
+
+ ASIOBufferInfo *infos;
+ infos = handle->bufferInfos;
+ for ( i=0; i<stream_.nDeviceChannels[0]; i++, infos++ ) {
+ infos->isInput = ASIOFalse;
+ infos->channelNum = i + stream_.channelOffset[0];
+ infos->buffers[0] = infos->buffers[1] = 0;
+ }
+ for ( i=0; i<stream_.nDeviceChannels[1]; i++, infos++ ) {
+ infos->isInput = ASIOTrue;
+ infos->channelNum = i + stream_.channelOffset[1];
+ infos->buffers[0] = infos->buffers[1] = 0;
+ }
+
+ // prepare for callbacks
+ stream_.sampleRate = sampleRate;
+ stream_.device[mode] = device;
+ stream_.mode = isDuplexInput ? DUPLEX : mode;
+
+ // store this class instance before registering callbacks, that are going to use it
+ asioCallbackInfo = &stream_.callbackInfo;
+ stream_.callbackInfo.object = (void *) this;
+
+ // Set up the ASIO callback structure and create the ASIO data buffers.
+ asioCallbacks.bufferSwitch = &bufferSwitch;
+ asioCallbacks.sampleRateDidChange = &sampleRateChanged;
+ asioCallbacks.asioMessage = &asioMessages;
+ asioCallbacks.bufferSwitchTimeInfo = NULL;
+ result = ASIOCreateBuffers( handle->bufferInfos, nChannels, stream_.bufferSize, &asioCallbacks );
+ if ( result != ASE_OK ) {
+ // Standard method failed. This can happen with strict/misbehaving drivers that return valid buffer size ranges
+ // but only accept the preferred buffer size as parameter for ASIOCreateBuffers. eg. Creatives ASIO driver
+ // in that case, let's be naïve and try that instead
+ *bufferSize = preferSize;
+ stream_.bufferSize = *bufferSize;
+ result = ASIOCreateBuffers( handle->bufferInfos, nChannels, stream_.bufferSize, &asioCallbacks );
+ }
+
+ if ( result != ASE_OK ) {
+ errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") creating buffers.";
+ errorText_ = errorStream_.str();
+ goto error;
+ }
+ buffersAllocated = true;
+ stream_.state = STREAM_STOPPED;
+
+ // Set flags for buffer conversion.
+ stream_.doConvertBuffer[mode] = false;
+ if ( stream_.userFormat != stream_.deviceFormat[mode] )
+ stream_.doConvertBuffer[mode] = true;
+ if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&
+ stream_.nUserChannels[mode] > 1 )
+ stream_.doConvertBuffer[mode] = true;
+
+ // Allocate necessary internal buffers
+ unsigned long bufferBytes;
+ bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
+ stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );
+ if ( stream_.userBuffer[mode] == NULL ) {
+ errorText_ = "RtApiAsio::probeDeviceOpen: error allocating user buffer memory.";
+ goto error;
+ }
+
+ if ( stream_.doConvertBuffer[mode] ) {
+
+ bool makeBuffer = true;
+ bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );
+ if ( isDuplexInput && stream_.deviceBuffer ) {
+ unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );
+ if ( bufferBytes <= bytesOut ) makeBuffer = false;
+ }
+
+ if ( makeBuffer ) {
+ bufferBytes *= *bufferSize;
+ if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );
+ stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );
+ if ( stream_.deviceBuffer == NULL ) {
+ errorText_ = "RtApiAsio::probeDeviceOpen: error allocating device buffer memory.";
+ goto error;
+ }
+ }
+ }
+
+ // Determine device latencies
+ long inputLatency, outputLatency;
+ result = ASIOGetLatencies( &inputLatency, &outputLatency );
+ if ( result != ASE_OK ) {
+ errorStream_ << "RtApiAsio::probeDeviceOpen: driver (" << driverName << ") error (" << getAsioErrorString( result ) << ") getting latency.";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING); // warn but don't fail
+ }
+ else {
+ stream_.latency[0] = outputLatency;
+ stream_.latency[1] = inputLatency;
+ }
+
+ // Setup the buffer conversion information structure. We don't use
+ // buffers to do channel offsets, so we override that parameter
+ // here.
+ if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, 0 );
+
+ return SUCCESS;
+
+ error:
+ if ( !isDuplexInput ) {
+ // the cleanup for error in the duplex input, is done by RtApi::openStream
+ // So we clean up for single channel only
+
+ if ( buffersAllocated )
+ ASIODisposeBuffers();
+
+ drivers.removeCurrentDriver();
+
+ if ( handle ) {
+ CloseHandle( handle->condition );
+ if ( handle->bufferInfos )
+ free( handle->bufferInfos );
+
+ delete handle;
+ stream_.apiHandle = 0;
+ }
+
+
+ if ( stream_.userBuffer[mode] ) {
+ free( stream_.userBuffer[mode] );
+ stream_.userBuffer[mode] = 0;
+ }
+
+ if ( stream_.deviceBuffer ) {
+ free( stream_.deviceBuffer );
+ stream_.deviceBuffer = 0;
+ }
+ }
+
+ return FAILURE;
+}////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void RtApiAsio :: closeStream()
+{
+ if ( stream_.state == STREAM_CLOSED ) {
+ errorText_ = "RtApiAsio::closeStream(): no open stream to close!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ if ( stream_.state == STREAM_RUNNING ) {
+ stream_.state = STREAM_STOPPED;
+ ASIOStop();
+ }
+ ASIODisposeBuffers();
+ drivers.removeCurrentDriver();
+
+ AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
+ if ( handle ) {
+ CloseHandle( handle->condition );
+ if ( handle->bufferInfos )
+ free( handle->bufferInfos );
+ delete handle;
+ stream_.apiHandle = 0;
+ }
+
+ for ( int i=0; i<2; i++ ) {
+ if ( stream_.userBuffer[i] ) {
+ free( stream_.userBuffer[i] );
+ stream_.userBuffer[i] = 0;
+ }
+ }
+
+ if ( stream_.deviceBuffer ) {
+ free( stream_.deviceBuffer );
+ stream_.deviceBuffer = 0;
+ }
+
+ stream_.mode = UNINITIALIZED;
+ stream_.state = STREAM_CLOSED;
+}
+
+bool stopThreadCalled = false;
+
+void RtApiAsio :: startStream()
+{
+ verifyStream();
+ if ( stream_.state == STREAM_RUNNING ) {
+ errorText_ = "RtApiAsio::startStream(): the stream is already running!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
+ ASIOError result = ASIOStart();
+ if ( result != ASE_OK ) {
+ errorStream_ << "RtApiAsio::startStream: error (" << getAsioErrorString( result ) << ") starting device.";
+ errorText_ = errorStream_.str();
+ goto unlock;
+ }
+
+ handle->drainCounter = 0;
+ handle->internalDrain = false;
+ ResetEvent( handle->condition );
+ stream_.state = STREAM_RUNNING;
+ asioXRun = false;
+
+ unlock:
+ stopThreadCalled = false;
+
+ if ( result == ASE_OK ) return;
+ error( RtAudioError::SYSTEM_ERROR );
+}
+
+void RtApiAsio :: stopStream()
+{
+ verifyStream();
+ if ( stream_.state == STREAM_STOPPED ) {
+ errorText_ = "RtApiAsio::stopStream(): the stream is already stopped!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
+ if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
+ if ( handle->drainCounter == 0 ) {
+ handle->drainCounter = 2;
+ WaitForSingleObject( handle->condition, INFINITE ); // block until signaled
+ }
+ }
+
+ stream_.state = STREAM_STOPPED;
+
+ ASIOError result = ASIOStop();
+ if ( result != ASE_OK ) {
+ errorStream_ << "RtApiAsio::stopStream: error (" << getAsioErrorString( result ) << ") stopping device.";
+ errorText_ = errorStream_.str();
+ }
+
+ if ( result == ASE_OK ) return;
+ error( RtAudioError::SYSTEM_ERROR );
+}
+
+void RtApiAsio :: abortStream()
+{
+ verifyStream();
+ if ( stream_.state == STREAM_STOPPED ) {
+ errorText_ = "RtApiAsio::abortStream(): the stream is already stopped!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ // The following lines were commented-out because some behavior was
+ // noted where the device buffers need to be zeroed to avoid
+ // continuing sound, even when the device buffers are completely
+ // disposed. So now, calling abort is the same as calling stop.
+ // AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
+ // handle->drainCounter = 2;
+ stopStream();
+}
+
+// This function will be called by a spawned thread when the user
+// callback function signals that the stream should be stopped or
+// aborted. It is necessary to handle it this way because the
+// callbackEvent() function must return before the ASIOStop()
+// function will return.
+static unsigned __stdcall asioStopStream( void *ptr )
+{
+ CallbackInfo *info = (CallbackInfo *) ptr;
+ RtApiAsio *object = (RtApiAsio *) info->object;
+
+ object->stopStream();
+ _endthreadex( 0 );
+ return 0;
+}
+
+bool RtApiAsio :: callbackEvent( long bufferIndex )
+{
+ if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) return SUCCESS;
+ if ( stream_.state == STREAM_CLOSED ) {
+ errorText_ = "RtApiAsio::callbackEvent(): the stream is closed ... this shouldn't happen!";
+ error( RtAudioError::WARNING );
+ return FAILURE;
+ }
+
+ CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
+ AsioHandle *handle = (AsioHandle *) stream_.apiHandle;
+
+ // Check if we were draining the stream and signal if finished.
+ if ( handle->drainCounter > 3 ) {
+
+ stream_.state = STREAM_STOPPING;
+ if ( handle->internalDrain == false )
+ SetEvent( handle->condition );
+ else { // spawn a thread to stop the stream
+ unsigned threadId;
+ stream_.callbackInfo.thread = _beginthreadex( NULL, 0, &asioStopStream,
+ &stream_.callbackInfo, 0, &threadId );
+ }
+ return SUCCESS;
+ }
+
+ // Invoke user callback to get fresh output data UNLESS we are
+ // draining stream.
+ if ( handle->drainCounter == 0 ) {
+ RtAudioCallback callback = (RtAudioCallback) info->callback;
+ double streamTime = getStreamTime();
+ RtAudioStreamStatus status = 0;
+ if ( stream_.mode != INPUT && asioXRun == true ) {
+ status |= RTAUDIO_OUTPUT_UNDERFLOW;
+ asioXRun = false;
+ }
+ if ( stream_.mode != OUTPUT && asioXRun == true ) {
+ status |= RTAUDIO_INPUT_OVERFLOW;
+ asioXRun = false;
+ }
+ int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1],
+ stream_.bufferSize, streamTime, status, info->userData );
+ if ( cbReturnValue == 2 ) {
+ stream_.state = STREAM_STOPPING;
+ handle->drainCounter = 2;
+ unsigned threadId;
+ stream_.callbackInfo.thread = _beginthreadex( NULL, 0, &asioStopStream,
+ &stream_.callbackInfo, 0, &threadId );
+ return SUCCESS;
+ }
+ else if ( cbReturnValue == 1 ) {
+ handle->drainCounter = 1;
+ handle->internalDrain = true;
+ }
+ }
+
+ unsigned int nChannels, bufferBytes, i, j;
+ nChannels = stream_.nDeviceChannels[0] + stream_.nDeviceChannels[1];
+ if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
+
+ bufferBytes = stream_.bufferSize * formatBytes( stream_.deviceFormat[0] );
+
+ if ( handle->drainCounter > 1 ) { // write zeros to the output stream
+
+ for ( i=0, j=0; i<nChannels; i++ ) {
+ if ( handle->bufferInfos[i].isInput != ASIOTrue )
+ memset( handle->bufferInfos[i].buffers[bufferIndex], 0, bufferBytes );
+ }
+
+ }
+ else if ( stream_.doConvertBuffer[0] ) {
+
+ convertBuffer( stream_.deviceBuffer, stream_.userBuffer[0], stream_.convertInfo[0] );
+ if ( stream_.doByteSwap[0] )
+ byteSwapBuffer( stream_.deviceBuffer,
+ stream_.bufferSize * stream_.nDeviceChannels[0],
+ stream_.deviceFormat[0] );
+
+ for ( i=0, j=0; i<nChannels; i++ ) {
+ if ( handle->bufferInfos[i].isInput != ASIOTrue )
+ memcpy( handle->bufferInfos[i].buffers[bufferIndex],
+ &stream_.deviceBuffer[j++*bufferBytes], bufferBytes );
+ }
+
+ }
+ else {
+
+ if ( stream_.doByteSwap[0] )
+ byteSwapBuffer( stream_.userBuffer[0],
+ stream_.bufferSize * stream_.nUserChannels[0],
+ stream_.userFormat );
+
+ for ( i=0, j=0; i<nChannels; i++ ) {
+ if ( handle->bufferInfos[i].isInput != ASIOTrue )
+ memcpy( handle->bufferInfos[i].buffers[bufferIndex],
+ &stream_.userBuffer[0][bufferBytes*j++], bufferBytes );
+ }
+
+ }
+ }
+
+ // Don't bother draining input
+ if ( handle->drainCounter ) {
+ handle->drainCounter++;
+ goto unlock;
+ }
+
+ if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
+
+ bufferBytes = stream_.bufferSize * formatBytes(stream_.deviceFormat[1]);
+
+ if (stream_.doConvertBuffer[1]) {
+
+ // Always interleave ASIO input data.
+ for ( i=0, j=0; i<nChannels; i++ ) {
+ if ( handle->bufferInfos[i].isInput == ASIOTrue )
+ memcpy( &stream_.deviceBuffer[j++*bufferBytes],
+ handle->bufferInfos[i].buffers[bufferIndex],
+ bufferBytes );
+ }
+
+ if ( stream_.doByteSwap[1] )
+ byteSwapBuffer( stream_.deviceBuffer,
+ stream_.bufferSize * stream_.nDeviceChannels[1],
+ stream_.deviceFormat[1] );
+ convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );
+
+ }
+ else {
+ for ( i=0, j=0; i<nChannels; i++ ) {
+ if ( handle->bufferInfos[i].isInput == ASIOTrue ) {
+ memcpy( &stream_.userBuffer[1][bufferBytes*j++],
+ handle->bufferInfos[i].buffers[bufferIndex],
+ bufferBytes );
+ }
+ }
+
+ if ( stream_.doByteSwap[1] )
+ byteSwapBuffer( stream_.userBuffer[1],
+ stream_.bufferSize * stream_.nUserChannels[1],
+ stream_.userFormat );
+ }
+ }
+
+ unlock:
+ // The following call was suggested by Malte Clasen. While the API
+ // documentation indicates it should not be required, some device
+ // drivers apparently do not function correctly without it.
+ ASIOOutputReady();
+
+ RtApi::tickStreamTime();
+ return SUCCESS;
+}
+
+static void sampleRateChanged( ASIOSampleRate sRate )
+{
+ // The ASIO documentation says that this usually only happens during
+ // external sync. Audio processing is not stopped by the driver,
+ // actual sample rate might not have even changed, maybe only the
+ // sample rate status of an AES/EBU or S/PDIF digital input at the
+ // audio device.
+
+ RtApi *object = (RtApi *) asioCallbackInfo->object;
+ try {
+ object->stopStream();
+ }
+ catch ( RtAudioError &exception ) {
+ std::cerr << "\nRtApiAsio: sampleRateChanged() error (" << exception.getMessage() << ")!\n" << std::endl;
+ return;
+ }
+
+ std::cerr << "\nRtApiAsio: driver reports sample rate changed to " << sRate << " ... stream stopped!!!\n" << std::endl;
+}
+
+static long asioMessages( long selector, long value, void* /*message*/, double* /*opt*/ )
+{
+ long ret = 0;
+
+ switch( selector ) {
+ case kAsioSelectorSupported:
+ if ( value == kAsioResetRequest
+ || value == kAsioEngineVersion
+ || value == kAsioResyncRequest
+ || value == kAsioLatenciesChanged
+ // The following three were added for ASIO 2.0, you don't
+ // necessarily have to support them.
+ || value == kAsioSupportsTimeInfo
+ || value == kAsioSupportsTimeCode
+ || value == kAsioSupportsInputMonitor)
+ ret = 1L;
+ break;
+ case kAsioResetRequest:
+ // Defer the task and perform the reset of the driver during the
+ // next "safe" situation. You cannot reset the driver right now,
+ // as this code is called from the driver. Reset the driver is
+ // done by completely destruct is. I.e. ASIOStop(),
+ // ASIODisposeBuffers(), Destruction Afterwards you initialize the
+ // driver again.
+ std::cerr << "\nRtApiAsio: driver reset requested!!!" << std::endl;
+ ret = 1L;
+ break;
+ case kAsioResyncRequest:
+ // This informs the application that the driver encountered some
+ // non-fatal data loss. It is used for synchronization purposes
+ // of different media. Added mainly to work around the Win16Mutex
+ // problems in Windows 95/98 with the Windows Multimedia system,
+ // which could lose data because the Mutex was held too long by
+ // another thread. However a driver can issue it in other
+ // situations, too.
+ // std::cerr << "\nRtApiAsio: driver resync requested!!!" << std::endl;
+ asioXRun = true;
+ ret = 1L;
+ break;
+ case kAsioLatenciesChanged:
+ // This will inform the host application that the drivers were
+ // latencies changed. Beware, it this does not mean that the
+ // buffer sizes have changed! You might need to update internal
+ // delay data.
+ std::cerr << "\nRtApiAsio: driver latency may have changed!!!" << std::endl;
+ ret = 1L;
+ break;
+ case kAsioEngineVersion:
+ // Return the supported ASIO version of the host application. If
+ // a host application does not implement this selector, ASIO 1.0
+ // is assumed by the driver.
+ ret = 2L;
+ break;
+ case kAsioSupportsTimeInfo:
+ // Informs the driver whether the
+ // asioCallbacks.bufferSwitchTimeInfo() callback is supported.
+ // For compatibility with ASIO 1.0 drivers the host application
+ // should always support the "old" bufferSwitch method, too.
+ ret = 0;
+ break;
+ case kAsioSupportsTimeCode:
+ // Informs the driver whether application is interested in time
+ // code info. If an application does not need to know about time
+ // code, the driver has less work to do.
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+static const char* getAsioErrorString( ASIOError result )
+{
+ struct Messages
+ {
+ ASIOError value;
+ const char*message;
+ };
+
+ static const Messages m[] =
+ {
+ { ASE_NotPresent, "Hardware input or output is not present or available." },
+ { ASE_HWMalfunction, "Hardware is malfunctioning." },
+ { ASE_InvalidParameter, "Invalid input parameter." },
+ { ASE_InvalidMode, "Invalid mode." },
+ { ASE_SPNotAdvancing, "Sample position not advancing." },
+ { ASE_NoClock, "Sample clock or rate cannot be determined or is not present." },
+ { ASE_NoMemory, "Not enough memory to complete the request." }
+ };
+
+ for ( unsigned int i = 0; i < sizeof(m)/sizeof(m[0]); ++i )
+ if ( m[i].value == result ) return m[i].message;
+
+ return "Unknown error.";
+}
+
+//******************** End of __WINDOWS_ASIO__ *********************//
+#endif
+
+
+#if defined(__WINDOWS_WASAPI__) // Windows WASAPI API
+
+// Authored by Marcus Tomlinson <themarcustomlinson@gmail.com>, April 2014
+// - Introduces support for the Windows WASAPI API
+// - Aims to deliver bit streams to and from hardware at the lowest possible latency, via the absolute minimum buffer sizes required
+// - Provides flexible stream configuration to an otherwise strict and inflexible WASAPI interface
+// - Includes automatic internal conversion of sample rate and buffer size between hardware and the user
+
+#ifndef INITGUID
+ #define INITGUID
+#endif
+#include <audioclient.h>
+#include <avrt.h>
+#include <mmdeviceapi.h>
+#include <functiondiscoverykeys_devpkey.h>
+
+//=============================================================================
+
+#define SAFE_RELEASE( objectPtr )\
+if ( objectPtr )\
+{\
+ objectPtr->Release();\
+ objectPtr = NULL;\
+}
+
+typedef HANDLE ( __stdcall *TAvSetMmThreadCharacteristicsPtr )( LPCWSTR TaskName, LPDWORD TaskIndex );
+
+//-----------------------------------------------------------------------------
+
+// WASAPI dictates stream sample rate, format, channel count, and in some cases, buffer size.
+// Therefore we must perform all necessary conversions to user buffers in order to satisfy these
+// requirements. WasapiBuffer ring buffers are used between HwIn->UserIn and UserOut->HwOut to
+// provide intermediate storage for read / write synchronization.
+class WasapiBuffer
+{
+public:
+ WasapiBuffer()
+ : buffer_( NULL ),
+ bufferSize_( 0 ),
+ inIndex_( 0 ),
+ outIndex_( 0 ) {}
+
+ ~WasapiBuffer() {
+ free( buffer_ );
+ }
+
+ // sets the length of the internal ring buffer
+ void setBufferSize( unsigned int bufferSize, unsigned int formatBytes ) {
+ free( buffer_ );
+
+ buffer_ = ( char* ) calloc( bufferSize, formatBytes );
+
+ bufferSize_ = bufferSize;
+ inIndex_ = 0;
+ outIndex_ = 0;
+ }
+
+ // attempt to push a buffer into the ring buffer at the current "in" index
+ bool pushBuffer( char* buffer, unsigned int bufferSize, RtAudioFormat format )
+ {
+ if ( !buffer || // incoming buffer is NULL
+ bufferSize == 0 || // incoming buffer has no data
+ bufferSize > bufferSize_ ) // incoming buffer too large
+ {
+ return false;
+ }
+
+ unsigned int relOutIndex = outIndex_;
+ unsigned int inIndexEnd = inIndex_ + bufferSize;
+ if ( relOutIndex < inIndex_ && inIndexEnd >= bufferSize_ ) {
+ relOutIndex += bufferSize_;
+ }
+
+ // "in" index can end on the "out" index but cannot begin at it
+ if ( inIndex_ <= relOutIndex && inIndexEnd > relOutIndex ) {
+ return false; // not enough space between "in" index and "out" index
+ }
+
+ // copy buffer from external to internal
+ int fromZeroSize = inIndex_ + bufferSize - bufferSize_;
+ fromZeroSize = fromZeroSize < 0 ? 0 : fromZeroSize;
+ int fromInSize = bufferSize - fromZeroSize;
+
+ switch( format )
+ {
+ case RTAUDIO_SINT8:
+ memcpy( &( ( char* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( char ) );
+ memcpy( buffer_, &( ( char* ) buffer )[fromInSize], fromZeroSize * sizeof( char ) );
+ break;
+ case RTAUDIO_SINT16:
+ memcpy( &( ( short* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( short ) );
+ memcpy( buffer_, &( ( short* ) buffer )[fromInSize], fromZeroSize * sizeof( short ) );
+ break;
+ case RTAUDIO_SINT24:
+ memcpy( &( ( S24* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( S24 ) );
+ memcpy( buffer_, &( ( S24* ) buffer )[fromInSize], fromZeroSize * sizeof( S24 ) );
+ break;
+ case RTAUDIO_SINT32:
+ memcpy( &( ( int* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( int ) );
+ memcpy( buffer_, &( ( int* ) buffer )[fromInSize], fromZeroSize * sizeof( int ) );
+ break;
+ case RTAUDIO_FLOAT32:
+ memcpy( &( ( float* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( float ) );
+ memcpy( buffer_, &( ( float* ) buffer )[fromInSize], fromZeroSize * sizeof( float ) );
+ break;
+ case RTAUDIO_FLOAT64:
+ memcpy( &( ( double* ) buffer_ )[inIndex_], buffer, fromInSize * sizeof( double ) );
+ memcpy( buffer_, &( ( double* ) buffer )[fromInSize], fromZeroSize * sizeof( double ) );
+ break;
+ }
+
+ // update "in" index
+ inIndex_ += bufferSize;
+ inIndex_ %= bufferSize_;
+
+ return true;
+ }
+
+ // attempt to pull a buffer from the ring buffer from the current "out" index
+ bool pullBuffer( char* buffer, unsigned int bufferSize, RtAudioFormat format )
+ {
+ if ( !buffer || // incoming buffer is NULL
+ bufferSize == 0 || // incoming buffer has no data
+ bufferSize > bufferSize_ ) // incoming buffer too large
+ {
+ return false;
+ }
+
+ unsigned int relInIndex = inIndex_;
+ unsigned int outIndexEnd = outIndex_ + bufferSize;
+ if ( relInIndex < outIndex_ && outIndexEnd >= bufferSize_ ) {
+ relInIndex += bufferSize_;
+ }
+
+ // "out" index can begin at and end on the "in" index
+ if ( outIndex_ < relInIndex && outIndexEnd > relInIndex ) {
+ return false; // not enough space between "out" index and "in" index
+ }
+
+ // copy buffer from internal to external
+ int fromZeroSize = outIndex_ + bufferSize - bufferSize_;
+ fromZeroSize = fromZeroSize < 0 ? 0 : fromZeroSize;
+ int fromOutSize = bufferSize - fromZeroSize;
+
+ switch( format )
+ {
+ case RTAUDIO_SINT8:
+ memcpy( buffer, &( ( char* ) buffer_ )[outIndex_], fromOutSize * sizeof( char ) );
+ memcpy( &( ( char* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( char ) );
+ break;
+ case RTAUDIO_SINT16:
+ memcpy( buffer, &( ( short* ) buffer_ )[outIndex_], fromOutSize * sizeof( short ) );
+ memcpy( &( ( short* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( short ) );
+ break;
+ case RTAUDIO_SINT24:
+ memcpy( buffer, &( ( S24* ) buffer_ )[outIndex_], fromOutSize * sizeof( S24 ) );
+ memcpy( &( ( S24* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( S24 ) );
+ break;
+ case RTAUDIO_SINT32:
+ memcpy( buffer, &( ( int* ) buffer_ )[outIndex_], fromOutSize * sizeof( int ) );
+ memcpy( &( ( int* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( int ) );
+ break;
+ case RTAUDIO_FLOAT32:
+ memcpy( buffer, &( ( float* ) buffer_ )[outIndex_], fromOutSize * sizeof( float ) );
+ memcpy( &( ( float* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( float ) );
+ break;
+ case RTAUDIO_FLOAT64:
+ memcpy( buffer, &( ( double* ) buffer_ )[outIndex_], fromOutSize * sizeof( double ) );
+ memcpy( &( ( double* ) buffer )[fromOutSize], buffer_, fromZeroSize * sizeof( double ) );
+ break;
+ }
+
+ // update "out" index
+ outIndex_ += bufferSize;
+ outIndex_ %= bufferSize_;
+
+ return true;
+ }
+
+private:
+ char* buffer_;
+ unsigned int bufferSize_;
+ unsigned int inIndex_;
+ unsigned int outIndex_;
+};
+
+//-----------------------------------------------------------------------------
+
+// In order to satisfy WASAPI's buffer requirements, we need a means of converting sample rate
+// between HW and the user. The convertBufferWasapi function is used to perform this conversion
+// between HwIn->UserIn and UserOut->HwOut during the stream callback loop.
+// This sample rate converter favors speed over quality, and works best with conversions between
+// one rate and its multiple.
+void convertBufferWasapi( char* outBuffer,
+ const char* inBuffer,
+ const unsigned int& channelCount,
+ const unsigned int& inSampleRate,
+ const unsigned int& outSampleRate,
+ const unsigned int& inSampleCount,
+ unsigned int& outSampleCount,
+ const RtAudioFormat& format )
+{
+ // calculate the new outSampleCount and relative sampleStep
+ float sampleRatio = ( float ) outSampleRate / inSampleRate;
+ float sampleStep = 1.0f / sampleRatio;
+ float inSampleFraction = 0.0f;
+
+ outSampleCount = ( unsigned int ) roundf( inSampleCount * sampleRatio );
+
+ // frame-by-frame, copy each relative input sample into it's corresponding output sample
+ for ( unsigned int outSample = 0; outSample < outSampleCount; outSample++ )
+ {
+ unsigned int inSample = ( unsigned int ) inSampleFraction;
+
+ switch ( format )
+ {
+ case RTAUDIO_SINT8:
+ memcpy( &( ( char* ) outBuffer )[ outSample * channelCount ], &( ( char* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( char ) );
+ break;
+ case RTAUDIO_SINT16:
+ memcpy( &( ( short* ) outBuffer )[ outSample * channelCount ], &( ( short* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( short ) );
+ break;
+ case RTAUDIO_SINT24:
+ memcpy( &( ( S24* ) outBuffer )[ outSample * channelCount ], &( ( S24* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( S24 ) );
+ break;
+ case RTAUDIO_SINT32:
+ memcpy( &( ( int* ) outBuffer )[ outSample * channelCount ], &( ( int* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( int ) );
+ break;
+ case RTAUDIO_FLOAT32:
+ memcpy( &( ( float* ) outBuffer )[ outSample * channelCount ], &( ( float* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( float ) );
+ break;
+ case RTAUDIO_FLOAT64:
+ memcpy( &( ( double* ) outBuffer )[ outSample * channelCount ], &( ( double* ) inBuffer )[ inSample * channelCount ], channelCount * sizeof( double ) );
+ break;
+ }
+
+ // jump to next in sample
+ inSampleFraction += sampleStep;
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+// A structure to hold various information related to the WASAPI implementation.
+struct WasapiHandle
+{
+ IAudioClient* captureAudioClient;
+ IAudioClient* renderAudioClient;
+ IAudioCaptureClient* captureClient;
+ IAudioRenderClient* renderClient;
+ HANDLE captureEvent;
+ HANDLE renderEvent;
+
+ WasapiHandle()
+ : captureAudioClient( NULL ),
+ renderAudioClient( NULL ),
+ captureClient( NULL ),
+ renderClient( NULL ),
+ captureEvent( NULL ),
+ renderEvent( NULL ) {}
+};
+
+//=============================================================================
+
+RtApiWasapi::RtApiWasapi()
+ : coInitialized_( false ), deviceEnumerator_( NULL )
+{
+ // WASAPI can run either apartment or multi-threaded
+ HRESULT hr = CoInitialize( NULL );
+ if ( !FAILED( hr ) )
+ coInitialized_ = true;
+
+ // Instantiate device enumerator
+ hr = CoCreateInstance( __uuidof( MMDeviceEnumerator ), NULL,
+ CLSCTX_ALL, __uuidof( IMMDeviceEnumerator ),
+ ( void** ) &deviceEnumerator_ );
+
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::RtApiWasapi: Unable to instantiate device enumerator";
+ error( RtAudioError::DRIVER_ERROR );
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+RtApiWasapi::~RtApiWasapi()
+{
+ if ( stream_.state != STREAM_CLOSED )
+ closeStream();
+
+ SAFE_RELEASE( deviceEnumerator_ );
+
+ // If this object previously called CoInitialize()
+ if ( coInitialized_ )
+ CoUninitialize();
+}
+
+//=============================================================================
+
+unsigned int RtApiWasapi::getDeviceCount( void )
+{
+ unsigned int captureDeviceCount = 0;
+ unsigned int renderDeviceCount = 0;
+
+ IMMDeviceCollection* captureDevices = NULL;
+ IMMDeviceCollection* renderDevices = NULL;
+
+ // Count capture devices
+ errorText_.clear();
+ HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve capture device collection.";
+ goto Exit;
+ }
+
+ hr = captureDevices->GetCount( &captureDeviceCount );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve capture device count.";
+ goto Exit;
+ }
+
+ // Count render devices
+ hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve render device collection.";
+ goto Exit;
+ }
+
+ hr = renderDevices->GetCount( &renderDeviceCount );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceCount: Unable to retrieve render device count.";
+ goto Exit;
+ }
+
+Exit:
+ // release all references
+ SAFE_RELEASE( captureDevices );
+ SAFE_RELEASE( renderDevices );
+
+ if ( errorText_.empty() )
+ return captureDeviceCount + renderDeviceCount;
+
+ error( RtAudioError::DRIVER_ERROR );
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+
+RtAudio::DeviceInfo RtApiWasapi::getDeviceInfo( unsigned int device )
+{
+ RtAudio::DeviceInfo info;
+ unsigned int captureDeviceCount = 0;
+ unsigned int renderDeviceCount = 0;
+ std::string defaultDeviceName;
+ bool isCaptureDevice = false;
+
+ PROPVARIANT deviceNameProp;
+ PROPVARIANT defaultDeviceNameProp;
+
+ IMMDeviceCollection* captureDevices = NULL;
+ IMMDeviceCollection* renderDevices = NULL;
+ IMMDevice* devicePtr = NULL;
+ IMMDevice* defaultDevicePtr = NULL;
+ IAudioClient* audioClient = NULL;
+ IPropertyStore* devicePropStore = NULL;
+ IPropertyStore* defaultDevicePropStore = NULL;
+
+ WAVEFORMATEX* deviceFormat = NULL;
+ WAVEFORMATEX* closestMatchFormat = NULL;
+
+ // probed
+ info.probed = false;
+
+ // Count capture devices
+ errorText_.clear();
+ RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR;
+ HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device collection.";
+ goto Exit;
+ }
+
+ hr = captureDevices->GetCount( &captureDeviceCount );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device count.";
+ goto Exit;
+ }
+
+ // Count render devices
+ hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device collection.";
+ goto Exit;
+ }
+
+ hr = renderDevices->GetCount( &renderDeviceCount );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device count.";
+ goto Exit;
+ }
+
+ // validate device index
+ if ( device >= captureDeviceCount + renderDeviceCount ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Invalid device index.";
+ errorType = RtAudioError::INVALID_USE;
+ goto Exit;
+ }
+
+ // determine whether index falls within capture or render devices
+ if ( device >= renderDeviceCount ) {
+ hr = captureDevices->Item( device - renderDeviceCount, &devicePtr );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve capture device handle.";
+ goto Exit;
+ }
+ isCaptureDevice = true;
+ }
+ else {
+ hr = renderDevices->Item( device, &devicePtr );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve render device handle.";
+ goto Exit;
+ }
+ isCaptureDevice = false;
+ }
+
+ // get default device name
+ if ( isCaptureDevice ) {
+ hr = deviceEnumerator_->GetDefaultAudioEndpoint( eCapture, eConsole, &defaultDevicePtr );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default capture device handle.";
+ goto Exit;
+ }
+ }
+ else {
+ hr = deviceEnumerator_->GetDefaultAudioEndpoint( eRender, eConsole, &defaultDevicePtr );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default render device handle.";
+ goto Exit;
+ }
+ }
+
+ hr = defaultDevicePtr->OpenPropertyStore( STGM_READ, &defaultDevicePropStore );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to open default device property store.";
+ goto Exit;
+ }
+ PropVariantInit( &defaultDeviceNameProp );
+
+ hr = defaultDevicePropStore->GetValue( PKEY_Device_FriendlyName, &defaultDeviceNameProp );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve default device property: PKEY_Device_FriendlyName.";
+ goto Exit;
+ }
+
+ defaultDeviceName = convertCharPointerToStdString(defaultDeviceNameProp.pwszVal);
+
+ // name
+ hr = devicePtr->OpenPropertyStore( STGM_READ, &devicePropStore );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to open device property store.";
+ goto Exit;
+ }
+
+ PropVariantInit( &deviceNameProp );
+
+ hr = devicePropStore->GetValue( PKEY_Device_FriendlyName, &deviceNameProp );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device property: PKEY_Device_FriendlyName.";
+ goto Exit;
+ }
+
+ info.name =convertCharPointerToStdString(deviceNameProp.pwszVal);
+
+ // is default
+ if ( isCaptureDevice ) {
+ info.isDefaultInput = info.name == defaultDeviceName;
+ info.isDefaultOutput = false;
+ }
+ else {
+ info.isDefaultInput = false;
+ info.isDefaultOutput = info.name == defaultDeviceName;
+ }
+
+ // channel count
+ hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL, NULL, ( void** ) &audioClient );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device audio client.";
+ goto Exit;
+ }
+
+ hr = audioClient->GetMixFormat( &deviceFormat );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::getDeviceInfo: Unable to retrieve device mix format.";
+ goto Exit;
+ }
+
+ if ( isCaptureDevice ) {
+ info.inputChannels = deviceFormat->nChannels;
+ info.outputChannels = 0;
+ info.duplexChannels = 0;
+ }
+ else {
+ info.inputChannels = 0;
+ info.outputChannels = deviceFormat->nChannels;
+ info.duplexChannels = 0;
+ }
+
+ // sample rates
+ info.sampleRates.clear();
+
+ // allow support for all sample rates as we have a built-in sample rate converter
+ for ( unsigned int i = 0; i < MAX_SAMPLE_RATES; i++ ) {
+ info.sampleRates.push_back( SAMPLE_RATES[i] );
+ }
+ info.preferredSampleRate = deviceFormat->nSamplesPerSec;
+
+ // native format
+ info.nativeFormats = 0;
+
+ if ( deviceFormat->wFormatTag == WAVE_FORMAT_IEEE_FLOAT ||
+ ( deviceFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
+ ( ( WAVEFORMATEXTENSIBLE* ) deviceFormat )->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT ) )
+ {
+ if ( deviceFormat->wBitsPerSample == 32 ) {
+ info.nativeFormats |= RTAUDIO_FLOAT32;
+ }
+ else if ( deviceFormat->wBitsPerSample == 64 ) {
+ info.nativeFormats |= RTAUDIO_FLOAT64;
+ }
+ }
+ else if ( deviceFormat->wFormatTag == WAVE_FORMAT_PCM ||
+ ( deviceFormat->wFormatTag == WAVE_FORMAT_EXTENSIBLE &&
+ ( ( WAVEFORMATEXTENSIBLE* ) deviceFormat )->SubFormat == KSDATAFORMAT_SUBTYPE_PCM ) )
+ {
+ if ( deviceFormat->wBitsPerSample == 8 ) {
+ info.nativeFormats |= RTAUDIO_SINT8;
+ }
+ else if ( deviceFormat->wBitsPerSample == 16 ) {
+ info.nativeFormats |= RTAUDIO_SINT16;
+ }
+ else if ( deviceFormat->wBitsPerSample == 24 ) {
+ info.nativeFormats |= RTAUDIO_SINT24;
+ }
+ else if ( deviceFormat->wBitsPerSample == 32 ) {
+ info.nativeFormats |= RTAUDIO_SINT32;
+ }
+ }
+
+ // probed
+ info.probed = true;
+
+Exit:
+ // release all references
+ PropVariantClear( &deviceNameProp );
+ PropVariantClear( &defaultDeviceNameProp );
+
+ SAFE_RELEASE( captureDevices );
+ SAFE_RELEASE( renderDevices );
+ SAFE_RELEASE( devicePtr );
+ SAFE_RELEASE( defaultDevicePtr );
+ SAFE_RELEASE( audioClient );
+ SAFE_RELEASE( devicePropStore );
+ SAFE_RELEASE( defaultDevicePropStore );
+
+ CoTaskMemFree( deviceFormat );
+ CoTaskMemFree( closestMatchFormat );
+
+ if ( !errorText_.empty() )
+ error( errorType );
+ return info;
+}
+
+//-----------------------------------------------------------------------------
+
+unsigned int RtApiWasapi::getDefaultOutputDevice( void )
+{
+ for ( unsigned int i = 0; i < getDeviceCount(); i++ ) {
+ if ( getDeviceInfo( i ).isDefaultOutput ) {
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+
+unsigned int RtApiWasapi::getDefaultInputDevice( void )
+{
+ for ( unsigned int i = 0; i < getDeviceCount(); i++ ) {
+ if ( getDeviceInfo( i ).isDefaultInput ) {
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+
+void RtApiWasapi::closeStream( void )
+{
+ if ( stream_.state == STREAM_CLOSED ) {
+ errorText_ = "RtApiWasapi::closeStream: No open stream to close.";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ if ( stream_.state != STREAM_STOPPED )
+ stopStream();
+
+ // clean up stream memory
+ SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient )
+ SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient )
+
+ SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->captureClient )
+ SAFE_RELEASE( ( ( WasapiHandle* ) stream_.apiHandle )->renderClient )
+
+ if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent )
+ CloseHandle( ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent );
+
+ if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent )
+ CloseHandle( ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent );
+
+ delete ( WasapiHandle* ) stream_.apiHandle;
+ stream_.apiHandle = NULL;
+
+ for ( int i = 0; i < 2; i++ ) {
+ if ( stream_.userBuffer[i] ) {
+ free( stream_.userBuffer[i] );
+ stream_.userBuffer[i] = 0;
+ }
+ }
+
+ if ( stream_.deviceBuffer ) {
+ free( stream_.deviceBuffer );
+ stream_.deviceBuffer = 0;
+ }
+
+ // update stream state
+ stream_.state = STREAM_CLOSED;
+}
+
+//-----------------------------------------------------------------------------
+
+void RtApiWasapi::startStream( void )
+{
+ verifyStream();
+
+ if ( stream_.state == STREAM_RUNNING ) {
+ errorText_ = "RtApiWasapi::startStream: The stream is already running.";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ // update stream state
+ stream_.state = STREAM_RUNNING;
+
+ // create WASAPI stream thread
+ stream_.callbackInfo.thread = ( ThreadHandle ) CreateThread( NULL, 0, runWasapiThread, this, CREATE_SUSPENDED, NULL );
+
+ if ( !stream_.callbackInfo.thread ) {
+ errorText_ = "RtApiWasapi::startStream: Unable to instantiate callback thread.";
+ error( RtAudioError::THREAD_ERROR );
+ }
+ else {
+ SetThreadPriority( ( void* ) stream_.callbackInfo.thread, stream_.callbackInfo.priority );
+ ResumeThread( ( void* ) stream_.callbackInfo.thread );
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+void RtApiWasapi::stopStream( void )
+{
+ verifyStream();
+
+ if ( stream_.state == STREAM_STOPPED ) {
+ errorText_ = "RtApiWasapi::stopStream: The stream is already stopped.";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ // inform stream thread by setting stream state to STREAM_STOPPING
+ stream_.state = STREAM_STOPPING;
+
+ // wait until stream thread is stopped
+ while( stream_.state != STREAM_STOPPED ) {
+ Sleep( 1 );
+ }
+
+ // Wait for the last buffer to play before stopping.
+ Sleep( 1000 * stream_.bufferSize / stream_.sampleRate );
+
+ // stop capture client if applicable
+ if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient ) {
+ HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient->Stop();
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::stopStream: Unable to stop capture stream.";
+ error( RtAudioError::DRIVER_ERROR );
+ return;
+ }
+ }
+
+ // stop render client if applicable
+ if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient ) {
+ HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient->Stop();
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::stopStream: Unable to stop render stream.";
+ error( RtAudioError::DRIVER_ERROR );
+ return;
+ }
+ }
+
+ // close thread handle
+ if ( stream_.callbackInfo.thread && !CloseHandle( ( void* ) stream_.callbackInfo.thread ) ) {
+ errorText_ = "RtApiWasapi::stopStream: Unable to close callback thread.";
+ error( RtAudioError::THREAD_ERROR );
+ return;
+ }
+
+ stream_.callbackInfo.thread = (ThreadHandle) NULL;
+}
+
+//-----------------------------------------------------------------------------
+
+void RtApiWasapi::abortStream( void )
+{
+ verifyStream();
+
+ if ( stream_.state == STREAM_STOPPED ) {
+ errorText_ = "RtApiWasapi::abortStream: The stream is already stopped.";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ // inform stream thread by setting stream state to STREAM_STOPPING
+ stream_.state = STREAM_STOPPING;
+
+ // wait until stream thread is stopped
+ while ( stream_.state != STREAM_STOPPED ) {
+ Sleep( 1 );
+ }
+
+ // stop capture client if applicable
+ if ( ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient ) {
+ HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient->Stop();
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::abortStream: Unable to stop capture stream.";
+ error( RtAudioError::DRIVER_ERROR );
+ return;
+ }
+ }
+
+ // stop render client if applicable
+ if ( ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient ) {
+ HRESULT hr = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient->Stop();
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::abortStream: Unable to stop render stream.";
+ error( RtAudioError::DRIVER_ERROR );
+ return;
+ }
+ }
+
+ // close thread handle
+ if ( stream_.callbackInfo.thread && !CloseHandle( ( void* ) stream_.callbackInfo.thread ) ) {
+ errorText_ = "RtApiWasapi::abortStream: Unable to close callback thread.";
+ error( RtAudioError::THREAD_ERROR );
+ return;
+ }
+
+ stream_.callbackInfo.thread = (ThreadHandle) NULL;
+}
+
+//-----------------------------------------------------------------------------
+
+bool RtApiWasapi::probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
+ unsigned int firstChannel, unsigned int sampleRate,
+ RtAudioFormat format, unsigned int* bufferSize,
+ RtAudio::StreamOptions* options )
+{
+ bool methodResult = FAILURE;
+ unsigned int captureDeviceCount = 0;
+ unsigned int renderDeviceCount = 0;
+
+ IMMDeviceCollection* captureDevices = NULL;
+ IMMDeviceCollection* renderDevices = NULL;
+ IMMDevice* devicePtr = NULL;
+ WAVEFORMATEX* deviceFormat = NULL;
+ unsigned int bufferBytes;
+ stream_.state = STREAM_STOPPED;
+
+ // create API Handle if not already created
+ if ( !stream_.apiHandle )
+ stream_.apiHandle = ( void* ) new WasapiHandle();
+
+ // Count capture devices
+ errorText_.clear();
+ RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR;
+ HRESULT hr = deviceEnumerator_->EnumAudioEndpoints( eCapture, DEVICE_STATE_ACTIVE, &captureDevices );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device collection.";
+ goto Exit;
+ }
+
+ hr = captureDevices->GetCount( &captureDeviceCount );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device count.";
+ goto Exit;
+ }
+
+ // Count render devices
+ hr = deviceEnumerator_->EnumAudioEndpoints( eRender, DEVICE_STATE_ACTIVE, &renderDevices );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device collection.";
+ goto Exit;
+ }
+
+ hr = renderDevices->GetCount( &renderDeviceCount );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device count.";
+ goto Exit;
+ }
+
+ // validate device index
+ if ( device >= captureDeviceCount + renderDeviceCount ) {
+ errorType = RtAudioError::INVALID_USE;
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Invalid device index.";
+ goto Exit;
+ }
+
+ // determine whether index falls within capture or render devices
+ if ( device >= renderDeviceCount ) {
+ if ( mode != INPUT ) {
+ errorType = RtAudioError::INVALID_USE;
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Capture device selected as output device.";
+ goto Exit;
+ }
+
+ // retrieve captureAudioClient from devicePtr
+ IAudioClient*& captureAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient;
+
+ hr = captureDevices->Item( device - renderDeviceCount, &devicePtr );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve capture device handle.";
+ goto Exit;
+ }
+
+ hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL,
+ NULL, ( void** ) &captureAudioClient );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device audio client.";
+ goto Exit;
+ }
+
+ hr = captureAudioClient->GetMixFormat( &deviceFormat );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device mix format.";
+ goto Exit;
+ }
+
+ stream_.nDeviceChannels[mode] = deviceFormat->nChannels;
+ captureAudioClient->GetStreamLatency( ( long long* ) &stream_.latency[mode] );
+ }
+ else {
+ if ( mode != OUTPUT ) {
+ errorType = RtAudioError::INVALID_USE;
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Render device selected as input device.";
+ goto Exit;
+ }
+
+ // retrieve renderAudioClient from devicePtr
+ IAudioClient*& renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient;
+
+ hr = renderDevices->Item( device, &devicePtr );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve render device handle.";
+ goto Exit;
+ }
+
+ hr = devicePtr->Activate( __uuidof( IAudioClient ), CLSCTX_ALL,
+ NULL, ( void** ) &renderAudioClient );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device audio client.";
+ goto Exit;
+ }
+
+ hr = renderAudioClient->GetMixFormat( &deviceFormat );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Unable to retrieve device mix format.";
+ goto Exit;
+ }
+
+ stream_.nDeviceChannels[mode] = deviceFormat->nChannels;
+ renderAudioClient->GetStreamLatency( ( long long* ) &stream_.latency[mode] );
+ }
+
+ // fill stream data
+ if ( ( stream_.mode == OUTPUT && mode == INPUT ) ||
+ ( stream_.mode == INPUT && mode == OUTPUT ) ) {
+ stream_.mode = DUPLEX;
+ }
+ else {
+ stream_.mode = mode;
+ }
+
+ stream_.device[mode] = device;
+ stream_.doByteSwap[mode] = false;
+ stream_.sampleRate = sampleRate;
+ stream_.bufferSize = *bufferSize;
+ stream_.nBuffers = 1;
+ stream_.nUserChannels[mode] = channels;
+ stream_.channelOffset[mode] = firstChannel;
+ stream_.userFormat = format;
+ stream_.deviceFormat[mode] = getDeviceInfo( device ).nativeFormats;
+
+ if ( options && options->flags & RTAUDIO_NONINTERLEAVED )
+ stream_.userInterleaved = false;
+ else
+ stream_.userInterleaved = true;
+ stream_.deviceInterleaved[mode] = true;
+
+ // Set flags for buffer conversion.
+ stream_.doConvertBuffer[mode] = false;
+ if ( stream_.userFormat != stream_.deviceFormat[mode] ||
+ stream_.nUserChannels != stream_.nDeviceChannels )
+ stream_.doConvertBuffer[mode] = true;
+ else if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&
+ stream_.nUserChannels[mode] > 1 )
+ stream_.doConvertBuffer[mode] = true;
+
+ if ( stream_.doConvertBuffer[mode] )
+ setConvertInfo( mode, 0 );
+
+ // Allocate necessary internal buffers
+ bufferBytes = stream_.nUserChannels[mode] * stream_.bufferSize * formatBytes( stream_.userFormat );
+
+ stream_.userBuffer[mode] = ( char* ) calloc( bufferBytes, 1 );
+ if ( !stream_.userBuffer[mode] ) {
+ errorType = RtAudioError::MEMORY_ERROR;
+ errorText_ = "RtApiWasapi::probeDeviceOpen: Error allocating user buffer memory.";
+ goto Exit;
+ }
+
+ if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME )
+ stream_.callbackInfo.priority = 15;
+ else
+ stream_.callbackInfo.priority = 0;
+
+ ///! TODO: RTAUDIO_MINIMIZE_LATENCY // Provide stream buffers directly to callback
+ ///! TODO: RTAUDIO_HOG_DEVICE // Exclusive mode
+
+ methodResult = SUCCESS;
+
+Exit:
+ //clean up
+ SAFE_RELEASE( captureDevices );
+ SAFE_RELEASE( renderDevices );
+ SAFE_RELEASE( devicePtr );
+ CoTaskMemFree( deviceFormat );
+
+ // if method failed, close the stream
+ if ( methodResult == FAILURE )
+ closeStream();
+
+ if ( !errorText_.empty() )
+ error( errorType );
+ return methodResult;
+}
+
+//=============================================================================
+
+DWORD WINAPI RtApiWasapi::runWasapiThread( void* wasapiPtr )
+{
+ if ( wasapiPtr )
+ ( ( RtApiWasapi* ) wasapiPtr )->wasapiThread();
+
+ return 0;
+}
+
+DWORD WINAPI RtApiWasapi::stopWasapiThread( void* wasapiPtr )
+{
+ if ( wasapiPtr )
+ ( ( RtApiWasapi* ) wasapiPtr )->stopStream();
+
+ return 0;
+}
+
+DWORD WINAPI RtApiWasapi::abortWasapiThread( void* wasapiPtr )
+{
+ if ( wasapiPtr )
+ ( ( RtApiWasapi* ) wasapiPtr )->abortStream();
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+
+void RtApiWasapi::wasapiThread()
+{
+ // as this is a new thread, we must CoInitialize it
+ CoInitialize( NULL );
+
+ HRESULT hr;
+
+ IAudioClient* captureAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureAudioClient;
+ IAudioClient* renderAudioClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderAudioClient;
+ IAudioCaptureClient* captureClient = ( ( WasapiHandle* ) stream_.apiHandle )->captureClient;
+ IAudioRenderClient* renderClient = ( ( WasapiHandle* ) stream_.apiHandle )->renderClient;
+ HANDLE captureEvent = ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent;
+ HANDLE renderEvent = ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent;
+
+ WAVEFORMATEX* captureFormat = NULL;
+ WAVEFORMATEX* renderFormat = NULL;
+ float captureSrRatio = 0.0f;
+ float renderSrRatio = 0.0f;
+ WasapiBuffer captureBuffer;
+ WasapiBuffer renderBuffer;
+
+ // declare local stream variables
+ RtAudioCallback callback = ( RtAudioCallback ) stream_.callbackInfo.callback;
+ BYTE* streamBuffer = NULL;
+ unsigned long captureFlags = 0;
+ unsigned int bufferFrameCount = 0;
+ unsigned int numFramesPadding = 0;
+ unsigned int convBufferSize = 0;
+ bool callbackPushed = false;
+ bool callbackPulled = false;
+ bool callbackStopped = false;
+ int callbackResult = 0;
+
+ // convBuffer is used to store converted buffers between WASAPI and the user
+ char* convBuffer = NULL;
+ unsigned int convBuffSize = 0;
+ unsigned int deviceBuffSize = 0;
+
+ errorText_.clear();
+ RtAudioError::Type errorType = RtAudioError::DRIVER_ERROR;
+
+ // Attempt to assign "Pro Audio" characteristic to thread
+ HMODULE AvrtDll = LoadLibrary( (LPCTSTR) "AVRT.dll" );
+ if ( AvrtDll ) {
+ DWORD taskIndex = 0;
+ TAvSetMmThreadCharacteristicsPtr AvSetMmThreadCharacteristicsPtr = ( TAvSetMmThreadCharacteristicsPtr ) GetProcAddress( AvrtDll, "AvSetMmThreadCharacteristicsW" );
+ AvSetMmThreadCharacteristicsPtr( L"Pro Audio", &taskIndex );
+ FreeLibrary( AvrtDll );
+ }
+
+ // start capture stream if applicable
+ if ( captureAudioClient ) {
+ hr = captureAudioClient->GetMixFormat( &captureFormat );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve device mix format.";
+ goto Exit;
+ }
+
+ captureSrRatio = ( ( float ) captureFormat->nSamplesPerSec / stream_.sampleRate );
+
+ // initialize capture stream according to desire buffer size
+ float desiredBufferSize = stream_.bufferSize * captureSrRatio;
+ REFERENCE_TIME desiredBufferPeriod = ( REFERENCE_TIME ) ( ( float ) desiredBufferSize * 10000000 / captureFormat->nSamplesPerSec );
+
+ if ( !captureClient ) {
+ hr = captureAudioClient->Initialize( AUDCLNT_SHAREMODE_SHARED,
+ AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
+ desiredBufferPeriod,
+ desiredBufferPeriod,
+ captureFormat,
+ NULL );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to initialize capture audio client.";
+ goto Exit;
+ }
+
+ hr = captureAudioClient->GetService( __uuidof( IAudioCaptureClient ),
+ ( void** ) &captureClient );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve capture client handle.";
+ goto Exit;
+ }
+
+ // configure captureEvent to trigger on every available capture buffer
+ captureEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+ if ( !captureEvent ) {
+ errorType = RtAudioError::SYSTEM_ERROR;
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to create capture event.";
+ goto Exit;
+ }
+
+ hr = captureAudioClient->SetEventHandle( captureEvent );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to set capture event handle.";
+ goto Exit;
+ }
+
+ ( ( WasapiHandle* ) stream_.apiHandle )->captureClient = captureClient;
+ ( ( WasapiHandle* ) stream_.apiHandle )->captureEvent = captureEvent;
+ }
+
+ unsigned int inBufferSize = 0;
+ hr = captureAudioClient->GetBufferSize( &inBufferSize );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to get capture buffer size.";
+ goto Exit;
+ }
+
+ // scale outBufferSize according to stream->user sample rate ratio
+ unsigned int outBufferSize = ( unsigned int ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT];
+ inBufferSize *= stream_.nDeviceChannels[INPUT];
+
+ // set captureBuffer size
+ captureBuffer.setBufferSize( inBufferSize + outBufferSize, formatBytes( stream_.deviceFormat[INPUT] ) );
+
+ // reset the capture stream
+ hr = captureAudioClient->Reset();
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to reset capture stream.";
+ goto Exit;
+ }
+
+ // start the capture stream
+ hr = captureAudioClient->Start();
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to start capture stream.";
+ goto Exit;
+ }
+ }
+
+ // start render stream if applicable
+ if ( renderAudioClient ) {
+ hr = renderAudioClient->GetMixFormat( &renderFormat );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve device mix format.";
+ goto Exit;
+ }
+
+ renderSrRatio = ( ( float ) renderFormat->nSamplesPerSec / stream_.sampleRate );
+
+ // initialize render stream according to desire buffer size
+ float desiredBufferSize = stream_.bufferSize * renderSrRatio;
+ REFERENCE_TIME desiredBufferPeriod = ( REFERENCE_TIME ) ( ( float ) desiredBufferSize * 10000000 / renderFormat->nSamplesPerSec );
+
+ if ( !renderClient ) {
+ hr = renderAudioClient->Initialize( AUDCLNT_SHAREMODE_SHARED,
+ AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
+ desiredBufferPeriod,
+ desiredBufferPeriod,
+ renderFormat,
+ NULL );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to initialize render audio client.";
+ goto Exit;
+ }
+
+ hr = renderAudioClient->GetService( __uuidof( IAudioRenderClient ),
+ ( void** ) &renderClient );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render client handle.";
+ goto Exit;
+ }
+
+ // configure renderEvent to trigger on every available render buffer
+ renderEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+ if ( !renderEvent ) {
+ errorType = RtAudioError::SYSTEM_ERROR;
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to create render event.";
+ goto Exit;
+ }
+
+ hr = renderAudioClient->SetEventHandle( renderEvent );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to set render event handle.";
+ goto Exit;
+ }
+
+ ( ( WasapiHandle* ) stream_.apiHandle )->renderClient = renderClient;
+ ( ( WasapiHandle* ) stream_.apiHandle )->renderEvent = renderEvent;
+ }
+
+ unsigned int outBufferSize = 0;
+ hr = renderAudioClient->GetBufferSize( &outBufferSize );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to get render buffer size.";
+ goto Exit;
+ }
+
+ // scale inBufferSize according to user->stream sample rate ratio
+ unsigned int inBufferSize = ( unsigned int ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT];
+ outBufferSize *= stream_.nDeviceChannels[OUTPUT];
+
+ // set renderBuffer size
+ renderBuffer.setBufferSize( inBufferSize + outBufferSize, formatBytes( stream_.deviceFormat[OUTPUT] ) );
+
+ // reset the render stream
+ hr = renderAudioClient->Reset();
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to reset render stream.";
+ goto Exit;
+ }
+
+ // start the render stream
+ hr = renderAudioClient->Start();
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to start render stream.";
+ goto Exit;
+ }
+ }
+
+ if ( stream_.mode == INPUT ) {
+ convBuffSize = ( size_t ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] );
+ deviceBuffSize = stream_.bufferSize * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] );
+ }
+ else if ( stream_.mode == OUTPUT ) {
+ convBuffSize = ( size_t ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] );
+ deviceBuffSize = stream_.bufferSize * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] );
+ }
+ else if ( stream_.mode == DUPLEX ) {
+ convBuffSize = std::max( ( size_t ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] ),
+ ( size_t ) ( stream_.bufferSize * renderSrRatio ) * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] ) );
+ deviceBuffSize = std::max( stream_.bufferSize * stream_.nDeviceChannels[INPUT] * formatBytes( stream_.deviceFormat[INPUT] ),
+ stream_.bufferSize * stream_.nDeviceChannels[OUTPUT] * formatBytes( stream_.deviceFormat[OUTPUT] ) );
+ }
+
+ convBuffer = ( char* ) malloc( convBuffSize );
+ stream_.deviceBuffer = ( char* ) malloc( deviceBuffSize );
+ if ( !convBuffer || !stream_.deviceBuffer ) {
+ errorType = RtAudioError::MEMORY_ERROR;
+ errorText_ = "RtApiWasapi::wasapiThread: Error allocating device buffer memory.";
+ goto Exit;
+ }
+
+ // stream process loop
+ while ( stream_.state != STREAM_STOPPING ) {
+ if ( !callbackPulled ) {
+ // Callback Input
+ // ==============
+ // 1. Pull callback buffer from inputBuffer
+ // 2. If 1. was successful: Convert callback buffer to user sample rate and channel count
+ // Convert callback buffer to user format
+
+ if ( captureAudioClient ) {
+ // Pull callback buffer from inputBuffer
+ callbackPulled = captureBuffer.pullBuffer( convBuffer,
+ ( unsigned int ) ( stream_.bufferSize * captureSrRatio ) * stream_.nDeviceChannels[INPUT],
+ stream_.deviceFormat[INPUT] );
+
+ if ( callbackPulled ) {
+ // Convert callback buffer to user sample rate
+ convertBufferWasapi( stream_.deviceBuffer,
+ convBuffer,
+ stream_.nDeviceChannels[INPUT],
+ captureFormat->nSamplesPerSec,
+ stream_.sampleRate,
+ ( unsigned int ) ( stream_.bufferSize * captureSrRatio ),
+ convBufferSize,
+ stream_.deviceFormat[INPUT] );
+
+ if ( stream_.doConvertBuffer[INPUT] ) {
+ // Convert callback buffer to user format
+ convertBuffer( stream_.userBuffer[INPUT],
+ stream_.deviceBuffer,
+ stream_.convertInfo[INPUT] );
+ }
+ else {
+ // no further conversion, simple copy deviceBuffer to userBuffer
+ memcpy( stream_.userBuffer[INPUT],
+ stream_.deviceBuffer,
+ stream_.bufferSize * stream_.nUserChannels[INPUT] * formatBytes( stream_.userFormat ) );
+ }
+ }
+ }
+ else {
+ // if there is no capture stream, set callbackPulled flag
+ callbackPulled = true;
+ }
+
+ // Execute Callback
+ // ================
+ // 1. Execute user callback method
+ // 2. Handle return value from callback
+
+ // if callback has not requested the stream to stop
+ if ( callbackPulled && !callbackStopped ) {
+ // Execute user callback method
+ callbackResult = callback( stream_.userBuffer[OUTPUT],
+ stream_.userBuffer[INPUT],
+ stream_.bufferSize,
+ getStreamTime(),
+ captureFlags & AUDCLNT_BUFFERFLAGS_DATA_DISCONTINUITY ? RTAUDIO_INPUT_OVERFLOW : 0,
+ stream_.callbackInfo.userData );
+
+ // Handle return value from callback
+ if ( callbackResult == 1 ) {
+ // instantiate a thread to stop this thread
+ HANDLE threadHandle = CreateThread( NULL, 0, stopWasapiThread, this, 0, NULL );
+ if ( !threadHandle ) {
+ errorType = RtAudioError::THREAD_ERROR;
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to instantiate stream stop thread.";
+ goto Exit;
+ }
+ else if ( !CloseHandle( threadHandle ) ) {
+ errorType = RtAudioError::THREAD_ERROR;
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to close stream stop thread handle.";
+ goto Exit;
+ }
+
+ callbackStopped = true;
+ }
+ else if ( callbackResult == 2 ) {
+ // instantiate a thread to stop this thread
+ HANDLE threadHandle = CreateThread( NULL, 0, abortWasapiThread, this, 0, NULL );
+ if ( !threadHandle ) {
+ errorType = RtAudioError::THREAD_ERROR;
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to instantiate stream abort thread.";
+ goto Exit;
+ }
+ else if ( !CloseHandle( threadHandle ) ) {
+ errorType = RtAudioError::THREAD_ERROR;
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to close stream abort thread handle.";
+ goto Exit;
+ }
+
+ callbackStopped = true;
+ }
+ }
+ }
+
+ // Callback Output
+ // ===============
+ // 1. Convert callback buffer to stream format
+ // 2. Convert callback buffer to stream sample rate and channel count
+ // 3. Push callback buffer into outputBuffer
+
+ if ( renderAudioClient && callbackPulled ) {
+ if ( stream_.doConvertBuffer[OUTPUT] ) {
+ // Convert callback buffer to stream format
+ convertBuffer( stream_.deviceBuffer,
+ stream_.userBuffer[OUTPUT],
+ stream_.convertInfo[OUTPUT] );
+
+ }
+
+ // Convert callback buffer to stream sample rate
+ convertBufferWasapi( convBuffer,
+ stream_.deviceBuffer,
+ stream_.nDeviceChannels[OUTPUT],
+ stream_.sampleRate,
+ renderFormat->nSamplesPerSec,
+ stream_.bufferSize,
+ convBufferSize,
+ stream_.deviceFormat[OUTPUT] );
+
+ // Push callback buffer into outputBuffer
+ callbackPushed = renderBuffer.pushBuffer( convBuffer,
+ convBufferSize * stream_.nDeviceChannels[OUTPUT],
+ stream_.deviceFormat[OUTPUT] );
+ }
+ else {
+ // if there is no render stream, set callbackPushed flag
+ callbackPushed = true;
+ }
+
+ // Stream Capture
+ // ==============
+ // 1. Get capture buffer from stream
+ // 2. Push capture buffer into inputBuffer
+ // 3. If 2. was successful: Release capture buffer
+
+ if ( captureAudioClient ) {
+ // if the callback input buffer was not pulled from captureBuffer, wait for next capture event
+ if ( !callbackPulled ) {
+ WaitForSingleObject( captureEvent, INFINITE );
+ }
+
+ // Get capture buffer from stream
+ hr = captureClient->GetBuffer( &streamBuffer,
+ &bufferFrameCount,
+ &captureFlags, NULL, NULL );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve capture buffer.";
+ goto Exit;
+ }
+
+ if ( bufferFrameCount != 0 ) {
+ // Push capture buffer into inputBuffer
+ if ( captureBuffer.pushBuffer( ( char* ) streamBuffer,
+ bufferFrameCount * stream_.nDeviceChannels[INPUT],
+ stream_.deviceFormat[INPUT] ) )
+ {
+ // Release capture buffer
+ hr = captureClient->ReleaseBuffer( bufferFrameCount );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";
+ goto Exit;
+ }
+ }
+ else
+ {
+ // Inform WASAPI that capture was unsuccessful
+ hr = captureClient->ReleaseBuffer( 0 );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";
+ goto Exit;
+ }
+ }
+ }
+ else
+ {
+ // Inform WASAPI that capture was unsuccessful
+ hr = captureClient->ReleaseBuffer( 0 );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to release capture buffer.";
+ goto Exit;
+ }
+ }
+ }
+
+ // Stream Render
+ // =============
+ // 1. Get render buffer from stream
+ // 2. Pull next buffer from outputBuffer
+ // 3. If 2. was successful: Fill render buffer with next buffer
+ // Release render buffer
+
+ if ( renderAudioClient ) {
+ // if the callback output buffer was not pushed to renderBuffer, wait for next render event
+ if ( callbackPulled && !callbackPushed ) {
+ WaitForSingleObject( renderEvent, INFINITE );
+ }
+
+ // Get render buffer from stream
+ hr = renderAudioClient->GetBufferSize( &bufferFrameCount );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer size.";
+ goto Exit;
+ }
+
+ hr = renderAudioClient->GetCurrentPadding( &numFramesPadding );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer padding.";
+ goto Exit;
+ }
+
+ bufferFrameCount -= numFramesPadding;
+
+ if ( bufferFrameCount != 0 ) {
+ hr = renderClient->GetBuffer( bufferFrameCount, &streamBuffer );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to retrieve render buffer.";
+ goto Exit;
+ }
+
+ // Pull next buffer from outputBuffer
+ // Fill render buffer with next buffer
+ if ( renderBuffer.pullBuffer( ( char* ) streamBuffer,
+ bufferFrameCount * stream_.nDeviceChannels[OUTPUT],
+ stream_.deviceFormat[OUTPUT] ) )
+ {
+ // Release render buffer
+ hr = renderClient->ReleaseBuffer( bufferFrameCount, 0 );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";
+ goto Exit;
+ }
+ }
+ else
+ {
+ // Inform WASAPI that render was unsuccessful
+ hr = renderClient->ReleaseBuffer( 0, 0 );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";
+ goto Exit;
+ }
+ }
+ }
+ else
+ {
+ // Inform WASAPI that render was unsuccessful
+ hr = renderClient->ReleaseBuffer( 0, 0 );
+ if ( FAILED( hr ) ) {
+ errorText_ = "RtApiWasapi::wasapiThread: Unable to release render buffer.";
+ goto Exit;
+ }
+ }
+ }
+
+ // if the callback buffer was pushed renderBuffer reset callbackPulled flag
+ if ( callbackPushed ) {
+ callbackPulled = false;
+ }
+
+ // tick stream time
+ RtApi::tickStreamTime();
+ }
+
+Exit:
+ // clean up
+ CoTaskMemFree( captureFormat );
+ CoTaskMemFree( renderFormat );
+
+ free ( convBuffer );
+
+ CoUninitialize();
+
+ // update stream state
+ stream_.state = STREAM_STOPPED;
+
+ if ( errorText_.empty() )
+ return;
+ else
+ error( errorType );
+}
+
+//******************** End of __WINDOWS_WASAPI__ *********************//
+#endif
+
+
+#if defined(__WINDOWS_DS__) // Windows DirectSound API
+
+// Modified by Robin Davies, October 2005
+// - Improvements to DirectX pointer chasing.
+// - Bug fix for non-power-of-two Asio granularity used by Edirol PCR-A30.
+// - Auto-call CoInitialize for DSOUND and ASIO platforms.
+// Various revisions for RtAudio 4.0 by Gary Scavone, April 2007
+// Changed device query structure for RtAudio 4.0.7, January 2010
+
+#include <dsound.h>
+#include <assert.h>
+#include <algorithm>
+
+#if defined(__MINGW32__)
+ // missing from latest mingw winapi
+#define WAVE_FORMAT_96M08 0x00010000 /* 96 kHz, Mono, 8-bit */
+#define WAVE_FORMAT_96S08 0x00020000 /* 96 kHz, Stereo, 8-bit */
+#define WAVE_FORMAT_96M16 0x00040000 /* 96 kHz, Mono, 16-bit */
+#define WAVE_FORMAT_96S16 0x00080000 /* 96 kHz, Stereo, 16-bit */
+#endif
+
+#define MINIMUM_DEVICE_BUFFER_SIZE 32768
+
+#ifdef _MSC_VER // if Microsoft Visual C++
+#pragma comment( lib, "winmm.lib" ) // then, auto-link winmm.lib. Otherwise, it has to be added manually.
+#endif
+
+static inline DWORD dsPointerBetween( DWORD pointer, DWORD laterPointer, DWORD earlierPointer, DWORD bufferSize )
+{
+ if ( pointer > bufferSize ) pointer -= bufferSize;
+ if ( laterPointer < earlierPointer ) laterPointer += bufferSize;
+ if ( pointer < earlierPointer ) pointer += bufferSize;
+ return pointer >= earlierPointer && pointer < laterPointer;
+}
+
+// A structure to hold various information related to the DirectSound
+// API implementation.
+struct DsHandle {
+ unsigned int drainCounter; // Tracks callback counts when draining
+ bool internalDrain; // Indicates if stop is initiated from callback or not.
+ void *id[2];
+ void *buffer[2];
+ bool xrun[2];
+ UINT bufferPointer[2];
+ DWORD dsBufferSize[2];
+ DWORD dsPointerLeadTime[2]; // the number of bytes ahead of the safe pointer to lead by.
+ HANDLE condition;
+
+ DsHandle()
+ :drainCounter(0), internalDrain(false) { id[0] = 0; id[1] = 0; buffer[0] = 0; buffer[1] = 0; xrun[0] = false; xrun[1] = false; bufferPointer[0] = 0; bufferPointer[1] = 0; }
+};
+
+// Declarations for utility functions, callbacks, and structures
+// specific to the DirectSound implementation.
+static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
+ LPCTSTR description,
+ LPCTSTR module,
+ LPVOID lpContext );
+
+static const char* getErrorString( int code );
+
+static unsigned __stdcall callbackHandler( void *ptr );
+
+struct DsDevice {
+ LPGUID id[2];
+ bool validId[2];
+ bool found;
+ std::string name;
+
+ DsDevice()
+ : found(false) { validId[0] = false; validId[1] = false; }
+};
+
+struct DsProbeData {
+ bool isInput;
+ std::vector<struct DsDevice>* dsDevices;
+};
+
+RtApiDs :: RtApiDs()
+{
+ // Dsound will run both-threaded. If CoInitialize fails, then just
+ // accept whatever the mainline chose for a threading model.
+ coInitialized_ = false;
+ HRESULT hr = CoInitialize( NULL );
+ if ( !FAILED( hr ) ) coInitialized_ = true;
+}
+
+RtApiDs :: ~RtApiDs()
+{
+ if ( coInitialized_ ) CoUninitialize(); // balanced call.
+ if ( stream_.state != STREAM_CLOSED ) closeStream();
+}
+
+// The DirectSound default output is always the first device.
+unsigned int RtApiDs :: getDefaultOutputDevice( void )
+{
+ return 0;
+}
+
+// The DirectSound default input is always the first input device,
+// which is the first capture device enumerated.
+unsigned int RtApiDs :: getDefaultInputDevice( void )
+{
+ return 0;
+}
+
+unsigned int RtApiDs :: getDeviceCount( void )
+{
+ // Set query flag for previously found devices to false, so that we
+ // can check for any devices that have disappeared.
+ for ( unsigned int i=0; i<dsDevices.size(); i++ )
+ dsDevices[i].found = false;
+
+ // Query DirectSound devices.
+ struct DsProbeData probeInfo;
+ probeInfo.isInput = false;
+ probeInfo.dsDevices = &dsDevices;
+ HRESULT result = DirectSoundEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &probeInfo );
+ if ( FAILED( result ) ) {
+ errorStream_ << "RtApiDs::getDeviceCount: error (" << getErrorString( result ) << ") enumerating output devices!";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ }
+
+ // Query DirectSoundCapture devices.
+ probeInfo.isInput = true;
+ result = DirectSoundCaptureEnumerate( (LPDSENUMCALLBACK) deviceQueryCallback, &probeInfo );
+ if ( FAILED( result ) ) {
+ errorStream_ << "RtApiDs::getDeviceCount: error (" << getErrorString( result ) << ") enumerating input devices!";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ }
+
+ // Clean out any devices that may have disappeared (code update submitted by Eli Zehngut).
+ for ( unsigned int i=0; i<dsDevices.size(); ) {
+ if ( dsDevices[i].found == false ) dsDevices.erase( dsDevices.begin() + i );
+ else i++;
+ }
+
+ return static_cast<unsigned int>(dsDevices.size());
+}
+
+RtAudio::DeviceInfo RtApiDs :: getDeviceInfo( unsigned int device )
+{
+ RtAudio::DeviceInfo info;
+ info.probed = false;
+
+ if ( dsDevices.size() == 0 ) {
+ // Force a query of all devices
+ getDeviceCount();
+ if ( dsDevices.size() == 0 ) {
+ errorText_ = "RtApiDs::getDeviceInfo: no devices found!";
+ error( RtAudioError::INVALID_USE );
+ return info;
+ }
+ }
+
+ if ( device >= dsDevices.size() ) {
+ errorText_ = "RtApiDs::getDeviceInfo: device ID is invalid!";
+ error( RtAudioError::INVALID_USE );
+ return info;
+ }
+
+ HRESULT result;
+ if ( dsDevices[ device ].validId[0] == false ) goto probeInput;
+
+ LPDIRECTSOUND output;
+ DSCAPS outCaps;
+ result = DirectSoundCreate( dsDevices[ device ].id[0], &output, NULL );
+ if ( FAILED( result ) ) {
+ errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") opening output device (" << dsDevices[ device ].name << ")!";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ goto probeInput;
+ }
+
+ outCaps.dwSize = sizeof( outCaps );
+ result = output->GetCaps( &outCaps );
+ if ( FAILED( result ) ) {
+ output->Release();
+ errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") getting capabilities!";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ goto probeInput;
+ }
+
+ // Get output channel information.
+ info.outputChannels = ( outCaps.dwFlags & DSCAPS_PRIMARYSTEREO ) ? 2 : 1;
+
+ // Get sample rate information.
+ info.sampleRates.clear();
+ for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {
+ if ( SAMPLE_RATES[k] >= (unsigned int) outCaps.dwMinSecondarySampleRate &&
+ SAMPLE_RATES[k] <= (unsigned int) outCaps.dwMaxSecondarySampleRate ) {
+ info.sampleRates.push_back( SAMPLE_RATES[k] );
+
+ if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) )
+ info.preferredSampleRate = SAMPLE_RATES[k];
+ }
+ }
+
+ // Get format information.
+ if ( outCaps.dwFlags & DSCAPS_PRIMARY16BIT ) info.nativeFormats |= RTAUDIO_SINT16;
+ if ( outCaps.dwFlags & DSCAPS_PRIMARY8BIT ) info.nativeFormats |= RTAUDIO_SINT8;
+
+ output->Release();
+
+ if ( getDefaultOutputDevice() == device )
+ info.isDefaultOutput = true;
+
+ if ( dsDevices[ device ].validId[1] == false ) {
+ info.name = dsDevices[ device ].name;
+ info.probed = true;
+ return info;
+ }
+
+ probeInput:
+
+ LPDIRECTSOUNDCAPTURE input;
+ result = DirectSoundCaptureCreate( dsDevices[ device ].id[1], &input, NULL );
+ if ( FAILED( result ) ) {
+ errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") opening input device (" << dsDevices[ device ].name << ")!";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ DSCCAPS inCaps;
+ inCaps.dwSize = sizeof( inCaps );
+ result = input->GetCaps( &inCaps );
+ if ( FAILED( result ) ) {
+ input->Release();
+ errorStream_ << "RtApiDs::getDeviceInfo: error (" << getErrorString( result ) << ") getting object capabilities (" << dsDevices[ device ].name << ")!";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ // Get input channel information.
+ info.inputChannels = inCaps.dwChannels;
+
+ // Get sample rate and format information.
+ std::vector<unsigned int> rates;
+ if ( inCaps.dwChannels >= 2 ) {
+ if ( inCaps.dwFormats & WAVE_FORMAT_1S16 ) info.nativeFormats |= RTAUDIO_SINT16;
+ if ( inCaps.dwFormats & WAVE_FORMAT_2S16 ) info.nativeFormats |= RTAUDIO_SINT16;
+ if ( inCaps.dwFormats & WAVE_FORMAT_4S16 ) info.nativeFormats |= RTAUDIO_SINT16;
+ if ( inCaps.dwFormats & WAVE_FORMAT_96S16 ) info.nativeFormats |= RTAUDIO_SINT16;
+ if ( inCaps.dwFormats & WAVE_FORMAT_1S08 ) info.nativeFormats |= RTAUDIO_SINT8;
+ if ( inCaps.dwFormats & WAVE_FORMAT_2S08 ) info.nativeFormats |= RTAUDIO_SINT8;
+ if ( inCaps.dwFormats & WAVE_FORMAT_4S08 ) info.nativeFormats |= RTAUDIO_SINT8;
+ if ( inCaps.dwFormats & WAVE_FORMAT_96S08 ) info.nativeFormats |= RTAUDIO_SINT8;
+
+ if ( info.nativeFormats & RTAUDIO_SINT16 ) {
+ if ( inCaps.dwFormats & WAVE_FORMAT_1S16 ) rates.push_back( 11025 );
+ if ( inCaps.dwFormats & WAVE_FORMAT_2S16 ) rates.push_back( 22050 );
+ if ( inCaps.dwFormats & WAVE_FORMAT_4S16 ) rates.push_back( 44100 );
+ if ( inCaps.dwFormats & WAVE_FORMAT_96S16 ) rates.push_back( 96000 );
+ }
+ else if ( info.nativeFormats & RTAUDIO_SINT8 ) {
+ if ( inCaps.dwFormats & WAVE_FORMAT_1S08 ) rates.push_back( 11025 );
+ if ( inCaps.dwFormats & WAVE_FORMAT_2S08 ) rates.push_back( 22050 );
+ if ( inCaps.dwFormats & WAVE_FORMAT_4S08 ) rates.push_back( 44100 );
+ if ( inCaps.dwFormats & WAVE_FORMAT_96S08 ) rates.push_back( 96000 );
+ }
+ }
+ else if ( inCaps.dwChannels == 1 ) {
+ if ( inCaps.dwFormats & WAVE_FORMAT_1M16 ) info.nativeFormats |= RTAUDIO_SINT16;
+ if ( inCaps.dwFormats & WAVE_FORMAT_2M16 ) info.nativeFormats |= RTAUDIO_SINT16;
+ if ( inCaps.dwFormats & WAVE_FORMAT_4M16 ) info.nativeFormats |= RTAUDIO_SINT16;
+ if ( inCaps.dwFormats & WAVE_FORMAT_96M16 ) info.nativeFormats |= RTAUDIO_SINT16;
+ if ( inCaps.dwFormats & WAVE_FORMAT_1M08 ) info.nativeFormats |= RTAUDIO_SINT8;
+ if ( inCaps.dwFormats & WAVE_FORMAT_2M08 ) info.nativeFormats |= RTAUDIO_SINT8;
+ if ( inCaps.dwFormats & WAVE_FORMAT_4M08 ) info.nativeFormats |= RTAUDIO_SINT8;
+ if ( inCaps.dwFormats & WAVE_FORMAT_96M08 ) info.nativeFormats |= RTAUDIO_SINT8;
+
+ if ( info.nativeFormats & RTAUDIO_SINT16 ) {
+ if ( inCaps.dwFormats & WAVE_FORMAT_1M16 ) rates.push_back( 11025 );
+ if ( inCaps.dwFormats & WAVE_FORMAT_2M16 ) rates.push_back( 22050 );
+ if ( inCaps.dwFormats & WAVE_FORMAT_4M16 ) rates.push_back( 44100 );
+ if ( inCaps.dwFormats & WAVE_FORMAT_96M16 ) rates.push_back( 96000 );
+ }
+ else if ( info.nativeFormats & RTAUDIO_SINT8 ) {
+ if ( inCaps.dwFormats & WAVE_FORMAT_1M08 ) rates.push_back( 11025 );
+ if ( inCaps.dwFormats & WAVE_FORMAT_2M08 ) rates.push_back( 22050 );
+ if ( inCaps.dwFormats & WAVE_FORMAT_4M08 ) rates.push_back( 44100 );
+ if ( inCaps.dwFormats & WAVE_FORMAT_96M08 ) rates.push_back( 96000 );
+ }
+ }
+ else info.inputChannels = 0; // technically, this would be an error
+
+ input->Release();
+
+ if ( info.inputChannels == 0 ) return info;
+
+ // Copy the supported rates to the info structure but avoid duplication.
+ bool found;
+ for ( unsigned int i=0; i<rates.size(); i++ ) {
+ found = false;
+ for ( unsigned int j=0; j<info.sampleRates.size(); j++ ) {
+ if ( rates[i] == info.sampleRates[j] ) {
+ found = true;
+ break;
+ }
+ }
+ if ( found == false ) info.sampleRates.push_back( rates[i] );
+ }
+ std::sort( info.sampleRates.begin(), info.sampleRates.end() );
+
+ // If device opens for both playback and capture, we determine the channels.
+ if ( info.outputChannels > 0 && info.inputChannels > 0 )
+ info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;
+
+ if ( device == 0 ) info.isDefaultInput = true;
+
+ // Copy name and return.
+ info.name = dsDevices[ device ].name;
+ info.probed = true;
+ return info;
+}
+
+bool RtApiDs :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
+ unsigned int firstChannel, unsigned int sampleRate,
+ RtAudioFormat format, unsigned int *bufferSize,
+ RtAudio::StreamOptions *options )
+{
+ if ( channels + firstChannel > 2 ) {
+ errorText_ = "RtApiDs::probeDeviceOpen: DirectSound does not support more than 2 channels per device.";
+ return FAILURE;
+ }
+
+ size_t nDevices = dsDevices.size();
+ if ( nDevices == 0 ) {
+ // This should not happen because a check is made before this function is called.
+ errorText_ = "RtApiDs::probeDeviceOpen: no devices found!";
+ return FAILURE;
+ }
+
+ if ( device >= nDevices ) {
+ // This should not happen because a check is made before this function is called.
+ errorText_ = "RtApiDs::probeDeviceOpen: device ID is invalid!";
+ return FAILURE;
+ }
+
+ if ( mode == OUTPUT ) {
+ if ( dsDevices[ device ].validId[0] == false ) {
+ errorStream_ << "RtApiDs::probeDeviceOpen: device (" << device << ") does not support output!";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+ }
+ else { // mode == INPUT
+ if ( dsDevices[ device ].validId[1] == false ) {
+ errorStream_ << "RtApiDs::probeDeviceOpen: device (" << device << ") does not support input!";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+ }
+
+ // According to a note in PortAudio, using GetDesktopWindow()
+ // instead of GetForegroundWindow() is supposed to avoid problems
+ // that occur when the application's window is not the foreground
+ // window. Also, if the application window closes before the
+ // DirectSound buffer, DirectSound can crash. In the past, I had
+ // problems when using GetDesktopWindow() but it seems fine now
+ // (January 2010). I'll leave it commented here.
+ // HWND hWnd = GetForegroundWindow();
+ HWND hWnd = GetDesktopWindow();
+
+ // Check the numberOfBuffers parameter and limit the lowest value to
+ // two. This is a judgement call and a value of two is probably too
+ // low for capture, but it should work for playback.
+ int nBuffers = 0;
+ if ( options ) nBuffers = options->numberOfBuffers;
+ if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) nBuffers = 2;
+ if ( nBuffers < 2 ) nBuffers = 3;
+
+ // Check the lower range of the user-specified buffer size and set
+ // (arbitrarily) to a lower bound of 32.
+ if ( *bufferSize < 32 ) *bufferSize = 32;
+
+ // Create the wave format structure. The data format setting will
+ // be determined later.
+ WAVEFORMATEX waveFormat;
+ ZeroMemory( &waveFormat, sizeof(WAVEFORMATEX) );
+ waveFormat.wFormatTag = WAVE_FORMAT_PCM;
+ waveFormat.nChannels = channels + firstChannel;
+ waveFormat.nSamplesPerSec = (unsigned long) sampleRate;
+
+ // Determine the device buffer size. By default, we'll use the value
+ // defined above (32K), but we will grow it to make allowances for
+ // very large software buffer sizes.
+ DWORD dsBufferSize = MINIMUM_DEVICE_BUFFER_SIZE;
+ DWORD dsPointerLeadTime = 0;
+
+ void *ohandle = 0, *bhandle = 0;
+ HRESULT result;
+ if ( mode == OUTPUT ) {
+
+ LPDIRECTSOUND output;
+ result = DirectSoundCreate( dsDevices[ device ].id[0], &output, NULL );
+ if ( FAILED( result ) ) {
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") opening output device (" << dsDevices[ device ].name << ")!";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ DSCAPS outCaps;
+ outCaps.dwSize = sizeof( outCaps );
+ result = output->GetCaps( &outCaps );
+ if ( FAILED( result ) ) {
+ output->Release();
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting capabilities (" << dsDevices[ device ].name << ")!";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Check channel information.
+ if ( channels + firstChannel == 2 && !( outCaps.dwFlags & DSCAPS_PRIMARYSTEREO ) ) {
+ errorStream_ << "RtApiDs::getDeviceInfo: the output device (" << dsDevices[ device ].name << ") does not support stereo playback.";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Check format information. Use 16-bit format unless not
+ // supported or user requests 8-bit.
+ if ( outCaps.dwFlags & DSCAPS_PRIMARY16BIT &&
+ !( format == RTAUDIO_SINT8 && outCaps.dwFlags & DSCAPS_PRIMARY8BIT ) ) {
+ waveFormat.wBitsPerSample = 16;
+ stream_.deviceFormat[mode] = RTAUDIO_SINT16;
+ }
+ else {
+ waveFormat.wBitsPerSample = 8;
+ stream_.deviceFormat[mode] = RTAUDIO_SINT8;
+ }
+ stream_.userFormat = format;
+
+ // Update wave format structure and buffer information.
+ waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
+ waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
+ dsPointerLeadTime = nBuffers * (*bufferSize) * (waveFormat.wBitsPerSample / 8) * channels;
+
+ // If the user wants an even bigger buffer, increase the device buffer size accordingly.
+ while ( dsPointerLeadTime * 2U > dsBufferSize )
+ dsBufferSize *= 2;
+
+ // Set cooperative level to DSSCL_EXCLUSIVE ... sound stops when window focus changes.
+ // result = output->SetCooperativeLevel( hWnd, DSSCL_EXCLUSIVE );
+ // Set cooperative level to DSSCL_PRIORITY ... sound remains when window focus changes.
+ result = output->SetCooperativeLevel( hWnd, DSSCL_PRIORITY );
+ if ( FAILED( result ) ) {
+ output->Release();
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") setting cooperative level (" << dsDevices[ device ].name << ")!";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Even though we will write to the secondary buffer, we need to
+ // access the primary buffer to set the correct output format
+ // (since the default is 8-bit, 22 kHz!). Setup the DS primary
+ // buffer description.
+ DSBUFFERDESC bufferDescription;
+ ZeroMemory( &bufferDescription, sizeof( DSBUFFERDESC ) );
+ bufferDescription.dwSize = sizeof( DSBUFFERDESC );
+ bufferDescription.dwFlags = DSBCAPS_PRIMARYBUFFER;
+
+ // Obtain the primary buffer
+ LPDIRECTSOUNDBUFFER buffer;
+ result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL );
+ if ( FAILED( result ) ) {
+ output->Release();
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") accessing primary buffer (" << dsDevices[ device ].name << ")!";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Set the primary DS buffer sound format.
+ result = buffer->SetFormat( &waveFormat );
+ if ( FAILED( result ) ) {
+ output->Release();
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") setting primary buffer format (" << dsDevices[ device ].name << ")!";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Setup the secondary DS buffer description.
+ ZeroMemory( &bufferDescription, sizeof( DSBUFFERDESC ) );
+ bufferDescription.dwSize = sizeof( DSBUFFERDESC );
+ bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
+ DSBCAPS_GLOBALFOCUS |
+ DSBCAPS_GETCURRENTPOSITION2 |
+ DSBCAPS_LOCHARDWARE ); // Force hardware mixing
+ bufferDescription.dwBufferBytes = dsBufferSize;
+ bufferDescription.lpwfxFormat = &waveFormat;
+
+ // Try to create the secondary DS buffer. If that doesn't work,
+ // try to use software mixing. Otherwise, there's a problem.
+ result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL );
+ if ( FAILED( result ) ) {
+ bufferDescription.dwFlags = ( DSBCAPS_STICKYFOCUS |
+ DSBCAPS_GLOBALFOCUS |
+ DSBCAPS_GETCURRENTPOSITION2 |
+ DSBCAPS_LOCSOFTWARE ); // Force software mixing
+ result = output->CreateSoundBuffer( &bufferDescription, &buffer, NULL );
+ if ( FAILED( result ) ) {
+ output->Release();
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") creating secondary buffer (" << dsDevices[ device ].name << ")!";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+ }
+
+ // Get the buffer size ... might be different from what we specified.
+ DSBCAPS dsbcaps;
+ dsbcaps.dwSize = sizeof( DSBCAPS );
+ result = buffer->GetCaps( &dsbcaps );
+ if ( FAILED( result ) ) {
+ output->Release();
+ buffer->Release();
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting buffer settings (" << dsDevices[ device ].name << ")!";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ dsBufferSize = dsbcaps.dwBufferBytes;
+
+ // Lock the DS buffer
+ LPVOID audioPtr;
+ DWORD dataLen;
+ result = buffer->Lock( 0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0 );
+ if ( FAILED( result ) ) {
+ output->Release();
+ buffer->Release();
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") locking buffer (" << dsDevices[ device ].name << ")!";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Zero the DS buffer
+ ZeroMemory( audioPtr, dataLen );
+
+ // Unlock the DS buffer
+ result = buffer->Unlock( audioPtr, dataLen, NULL, 0 );
+ if ( FAILED( result ) ) {
+ output->Release();
+ buffer->Release();
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") unlocking buffer (" << dsDevices[ device ].name << ")!";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ ohandle = (void *) output;
+ bhandle = (void *) buffer;
+ }
+
+ if ( mode == INPUT ) {
+
+ LPDIRECTSOUNDCAPTURE input;
+ result = DirectSoundCaptureCreate( dsDevices[ device ].id[1], &input, NULL );
+ if ( FAILED( result ) ) {
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") opening input device (" << dsDevices[ device ].name << ")!";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ DSCCAPS inCaps;
+ inCaps.dwSize = sizeof( inCaps );
+ result = input->GetCaps( &inCaps );
+ if ( FAILED( result ) ) {
+ input->Release();
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting input capabilities (" << dsDevices[ device ].name << ")!";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Check channel information.
+ if ( inCaps.dwChannels < channels + firstChannel ) {
+ errorText_ = "RtApiDs::getDeviceInfo: the input device does not support requested input channels.";
+ return FAILURE;
+ }
+
+ // Check format information. Use 16-bit format unless user
+ // requests 8-bit.
+ DWORD deviceFormats;
+ if ( channels + firstChannel == 2 ) {
+ deviceFormats = WAVE_FORMAT_1S08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_4S08 | WAVE_FORMAT_96S08;
+ if ( format == RTAUDIO_SINT8 && inCaps.dwFormats & deviceFormats ) {
+ waveFormat.wBitsPerSample = 8;
+ stream_.deviceFormat[mode] = RTAUDIO_SINT8;
+ }
+ else { // assume 16-bit is supported
+ waveFormat.wBitsPerSample = 16;
+ stream_.deviceFormat[mode] = RTAUDIO_SINT16;
+ }
+ }
+ else { // channel == 1
+ deviceFormats = WAVE_FORMAT_1M08 | WAVE_FORMAT_2M08 | WAVE_FORMAT_4M08 | WAVE_FORMAT_96M08;
+ if ( format == RTAUDIO_SINT8 && inCaps.dwFormats & deviceFormats ) {
+ waveFormat.wBitsPerSample = 8;
+ stream_.deviceFormat[mode] = RTAUDIO_SINT8;
+ }
+ else { // assume 16-bit is supported
+ waveFormat.wBitsPerSample = 16;
+ stream_.deviceFormat[mode] = RTAUDIO_SINT16;
+ }
+ }
+ stream_.userFormat = format;
+
+ // Update wave format structure and buffer information.
+ waveFormat.nBlockAlign = waveFormat.nChannels * waveFormat.wBitsPerSample / 8;
+ waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
+ dsPointerLeadTime = nBuffers * (*bufferSize) * (waveFormat.wBitsPerSample / 8) * channels;
+
+ // If the user wants an even bigger buffer, increase the device buffer size accordingly.
+ while ( dsPointerLeadTime * 2U > dsBufferSize )
+ dsBufferSize *= 2;
+
+ // Setup the secondary DS buffer description.
+ DSCBUFFERDESC bufferDescription;
+ ZeroMemory( &bufferDescription, sizeof( DSCBUFFERDESC ) );
+ bufferDescription.dwSize = sizeof( DSCBUFFERDESC );
+ bufferDescription.dwFlags = 0;
+ bufferDescription.dwReserved = 0;
+ bufferDescription.dwBufferBytes = dsBufferSize;
+ bufferDescription.lpwfxFormat = &waveFormat;
+
+ // Create the capture buffer.
+ LPDIRECTSOUNDCAPTUREBUFFER buffer;
+ result = input->CreateCaptureBuffer( &bufferDescription, &buffer, NULL );
+ if ( FAILED( result ) ) {
+ input->Release();
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") creating input buffer (" << dsDevices[ device ].name << ")!";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Get the buffer size ... might be different from what we specified.
+ DSCBCAPS dscbcaps;
+ dscbcaps.dwSize = sizeof( DSCBCAPS );
+ result = buffer->GetCaps( &dscbcaps );
+ if ( FAILED( result ) ) {
+ input->Release();
+ buffer->Release();
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") getting buffer settings (" << dsDevices[ device ].name << ")!";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ dsBufferSize = dscbcaps.dwBufferBytes;
+
+ // NOTE: We could have a problem here if this is a duplex stream
+ // and the play and capture hardware buffer sizes are different
+ // (I'm actually not sure if that is a problem or not).
+ // Currently, we are not verifying that.
+
+ // Lock the capture buffer
+ LPVOID audioPtr;
+ DWORD dataLen;
+ result = buffer->Lock( 0, dsBufferSize, &audioPtr, &dataLen, NULL, NULL, 0 );
+ if ( FAILED( result ) ) {
+ input->Release();
+ buffer->Release();
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") locking input buffer (" << dsDevices[ device ].name << ")!";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Zero the buffer
+ ZeroMemory( audioPtr, dataLen );
+
+ // Unlock the buffer
+ result = buffer->Unlock( audioPtr, dataLen, NULL, 0 );
+ if ( FAILED( result ) ) {
+ input->Release();
+ buffer->Release();
+ errorStream_ << "RtApiDs::probeDeviceOpen: error (" << getErrorString( result ) << ") unlocking input buffer (" << dsDevices[ device ].name << ")!";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ ohandle = (void *) input;
+ bhandle = (void *) buffer;
+ }
+
+ // Set various stream parameters
+ DsHandle *handle = 0;
+ stream_.nDeviceChannels[mode] = channels + firstChannel;
+ stream_.nUserChannels[mode] = channels;
+ stream_.bufferSize = *bufferSize;
+ stream_.channelOffset[mode] = firstChannel;
+ stream_.deviceInterleaved[mode] = true;
+ if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;
+ else stream_.userInterleaved = true;
+
+ // Set flag for buffer conversion
+ stream_.doConvertBuffer[mode] = false;
+ if (stream_.nUserChannels[mode] != stream_.nDeviceChannels[mode])
+ stream_.doConvertBuffer[mode] = true;
+ if (stream_.userFormat != stream_.deviceFormat[mode])
+ stream_.doConvertBuffer[mode] = true;
+ if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&
+ stream_.nUserChannels[mode] > 1 )
+ stream_.doConvertBuffer[mode] = true;
+
+ // Allocate necessary internal buffers
+ long bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
+ stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );
+ if ( stream_.userBuffer[mode] == NULL ) {
+ errorText_ = "RtApiDs::probeDeviceOpen: error allocating user buffer memory.";
+ goto error;
+ }
+
+ if ( stream_.doConvertBuffer[mode] ) {
+
+ bool makeBuffer = true;
+ bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );
+ if ( mode == INPUT ) {
+ if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
+ unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );
+ if ( bufferBytes <= (long) bytesOut ) makeBuffer = false;
+ }
+ }
+
+ if ( makeBuffer ) {
+ bufferBytes *= *bufferSize;
+ if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );
+ stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );
+ if ( stream_.deviceBuffer == NULL ) {
+ errorText_ = "RtApiDs::probeDeviceOpen: error allocating device buffer memory.";
+ goto error;
+ }
+ }
+ }
+
+ // Allocate our DsHandle structures for the stream.
+ if ( stream_.apiHandle == 0 ) {
+ try {
+ handle = new DsHandle;
+ }
+ catch ( std::bad_alloc& ) {
+ errorText_ = "RtApiDs::probeDeviceOpen: error allocating AsioHandle memory.";
+ goto error;
+ }
+
+ // Create a manual-reset event.
+ handle->condition = CreateEvent( NULL, // no security
+ TRUE, // manual-reset
+ FALSE, // non-signaled initially
+ NULL ); // unnamed
+ stream_.apiHandle = (void *) handle;
+ }
+ else
+ handle = (DsHandle *) stream_.apiHandle;
+ handle->id[mode] = ohandle;
+ handle->buffer[mode] = bhandle;
+ handle->dsBufferSize[mode] = dsBufferSize;
+ handle->dsPointerLeadTime[mode] = dsPointerLeadTime;
+
+ stream_.device[mode] = device;
+ stream_.state = STREAM_STOPPED;
+ if ( stream_.mode == OUTPUT && mode == INPUT )
+ // We had already set up an output stream.
+ stream_.mode = DUPLEX;
+ else
+ stream_.mode = mode;
+ stream_.nBuffers = nBuffers;
+ stream_.sampleRate = sampleRate;
+
+ // Setup the buffer conversion information structure.
+ if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel );
+
+ // Setup the callback thread.
+ if ( stream_.callbackInfo.isRunning == false ) {
+ unsigned threadId;
+ stream_.callbackInfo.isRunning = true;
+ stream_.callbackInfo.object = (void *) this;
+ stream_.callbackInfo.thread = _beginthreadex( NULL, 0, &callbackHandler,
+ &stream_.callbackInfo, 0, &threadId );
+ if ( stream_.callbackInfo.thread == 0 ) {
+ errorText_ = "RtApiDs::probeDeviceOpen: error creating callback thread!";
+ goto error;
+ }
+
+ // Boost DS thread priority
+ SetThreadPriority( (HANDLE) stream_.callbackInfo.thread, THREAD_PRIORITY_HIGHEST );
+ }
+ return SUCCESS;
+
+ error:
+ if ( handle ) {
+ if ( handle->buffer[0] ) { // the object pointer can be NULL and valid
+ LPDIRECTSOUND object = (LPDIRECTSOUND) handle->id[0];
+ LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
+ if ( buffer ) buffer->Release();
+ object->Release();
+ }
+ if ( handle->buffer[1] ) {
+ LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) handle->id[1];
+ LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
+ if ( buffer ) buffer->Release();
+ object->Release();
+ }
+ CloseHandle( handle->condition );
+ delete handle;
+ stream_.apiHandle = 0;
+ }
+
+ for ( int i=0; i<2; i++ ) {
+ if ( stream_.userBuffer[i] ) {
+ free( stream_.userBuffer[i] );
+ stream_.userBuffer[i] = 0;
+ }
+ }
+
+ if ( stream_.deviceBuffer ) {
+ free( stream_.deviceBuffer );
+ stream_.deviceBuffer = 0;
+ }
+
+ stream_.state = STREAM_CLOSED;
+ return FAILURE;
+}
+
+void RtApiDs :: closeStream()
+{
+ if ( stream_.state == STREAM_CLOSED ) {
+ errorText_ = "RtApiDs::closeStream(): no open stream to close!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ // Stop the callback thread.
+ stream_.callbackInfo.isRunning = false;
+ WaitForSingleObject( (HANDLE) stream_.callbackInfo.thread, INFINITE );
+ CloseHandle( (HANDLE) stream_.callbackInfo.thread );
+
+ DsHandle *handle = (DsHandle *) stream_.apiHandle;
+ if ( handle ) {
+ if ( handle->buffer[0] ) { // the object pointer can be NULL and valid
+ LPDIRECTSOUND object = (LPDIRECTSOUND) handle->id[0];
+ LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
+ if ( buffer ) {
+ buffer->Stop();
+ buffer->Release();
+ }
+ object->Release();
+ }
+ if ( handle->buffer[1] ) {
+ LPDIRECTSOUNDCAPTURE object = (LPDIRECTSOUNDCAPTURE) handle->id[1];
+ LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
+ if ( buffer ) {
+ buffer->Stop();
+ buffer->Release();
+ }
+ object->Release();
+ }
+ CloseHandle( handle->condition );
+ delete handle;
+ stream_.apiHandle = 0;
+ }
+
+ for ( int i=0; i<2; i++ ) {
+ if ( stream_.userBuffer[i] ) {
+ free( stream_.userBuffer[i] );
+ stream_.userBuffer[i] = 0;
+ }
+ }
+
+ if ( stream_.deviceBuffer ) {
+ free( stream_.deviceBuffer );
+ stream_.deviceBuffer = 0;
+ }
+
+ stream_.mode = UNINITIALIZED;
+ stream_.state = STREAM_CLOSED;
+}
+
+void RtApiDs :: startStream()
+{
+ verifyStream();
+ if ( stream_.state == STREAM_RUNNING ) {
+ errorText_ = "RtApiDs::startStream(): the stream is already running!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ DsHandle *handle = (DsHandle *) stream_.apiHandle;
+
+ // Increase scheduler frequency on lesser windows (a side-effect of
+ // increasing timer accuracy). On greater windows (Win2K or later),
+ // this is already in effect.
+ timeBeginPeriod( 1 );
+
+ buffersRolling = false;
+ duplexPrerollBytes = 0;
+
+ if ( stream_.mode == DUPLEX ) {
+ // 0.5 seconds of silence in DUPLEX mode while the devices spin up and synchronize.
+ duplexPrerollBytes = (int) ( 0.5 * stream_.sampleRate * formatBytes( stream_.deviceFormat[1] ) * stream_.nDeviceChannels[1] );
+ }
+
+ HRESULT result = 0;
+ if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
+
+ LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
+ result = buffer->Play( 0, 0, DSBPLAY_LOOPING );
+ if ( FAILED( result ) ) {
+ errorStream_ << "RtApiDs::startStream: error (" << getErrorString( result ) << ") starting output buffer!";
+ errorText_ = errorStream_.str();
+ goto unlock;
+ }
+ }
+
+ if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
+
+ LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
+ result = buffer->Start( DSCBSTART_LOOPING );
+ if ( FAILED( result ) ) {
+ errorStream_ << "RtApiDs::startStream: error (" << getErrorString( result ) << ") starting input buffer!";
+ errorText_ = errorStream_.str();
+ goto unlock;
+ }
+ }
+
+ handle->drainCounter = 0;
+ handle->internalDrain = false;
+ ResetEvent( handle->condition );
+ stream_.state = STREAM_RUNNING;
+
+ unlock:
+ if ( FAILED( result ) ) error( RtAudioError::SYSTEM_ERROR );
+}
+
+void RtApiDs :: stopStream()
+{
+ verifyStream();
+ if ( stream_.state == STREAM_STOPPED ) {
+ errorText_ = "RtApiDs::stopStream(): the stream is already stopped!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ HRESULT result = 0;
+ LPVOID audioPtr;
+ DWORD dataLen;
+ DsHandle *handle = (DsHandle *) stream_.apiHandle;
+ if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
+ if ( handle->drainCounter == 0 ) {
+ handle->drainCounter = 2;
+ WaitForSingleObject( handle->condition, INFINITE ); // block until signaled
+ }
+
+ stream_.state = STREAM_STOPPED;
+
+ MUTEX_LOCK( &stream_.mutex );
+
+ // Stop the buffer and clear memory
+ LPDIRECTSOUNDBUFFER buffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
+ result = buffer->Stop();
+ if ( FAILED( result ) ) {
+ errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") stopping output buffer!";
+ errorText_ = errorStream_.str();
+ goto unlock;
+ }
+
+ // Lock the buffer and clear it so that if we start to play again,
+ // we won't have old data playing.
+ result = buffer->Lock( 0, handle->dsBufferSize[0], &audioPtr, &dataLen, NULL, NULL, 0 );
+ if ( FAILED( result ) ) {
+ errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") locking output buffer!";
+ errorText_ = errorStream_.str();
+ goto unlock;
+ }
+
+ // Zero the DS buffer
+ ZeroMemory( audioPtr, dataLen );
+
+ // Unlock the DS buffer
+ result = buffer->Unlock( audioPtr, dataLen, NULL, 0 );
+ if ( FAILED( result ) ) {
+ errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") unlocking output buffer!";
+ errorText_ = errorStream_.str();
+ goto unlock;
+ }
+
+ // If we start playing again, we must begin at beginning of buffer.
+ handle->bufferPointer[0] = 0;
+ }
+
+ if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
+ LPDIRECTSOUNDCAPTUREBUFFER buffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
+ audioPtr = NULL;
+ dataLen = 0;
+
+ stream_.state = STREAM_STOPPED;
+
+ if ( stream_.mode != DUPLEX )
+ MUTEX_LOCK( &stream_.mutex );
+
+ result = buffer->Stop();
+ if ( FAILED( result ) ) {
+ errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") stopping input buffer!";
+ errorText_ = errorStream_.str();
+ goto unlock;
+ }
+
+ // Lock the buffer and clear it so that if we start to play again,
+ // we won't have old data playing.
+ result = buffer->Lock( 0, handle->dsBufferSize[1], &audioPtr, &dataLen, NULL, NULL, 0 );
+ if ( FAILED( result ) ) {
+ errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") locking input buffer!";
+ errorText_ = errorStream_.str();
+ goto unlock;
+ }
+
+ // Zero the DS buffer
+ ZeroMemory( audioPtr, dataLen );
+
+ // Unlock the DS buffer
+ result = buffer->Unlock( audioPtr, dataLen, NULL, 0 );
+ if ( FAILED( result ) ) {
+ errorStream_ << "RtApiDs::stopStream: error (" << getErrorString( result ) << ") unlocking input buffer!";
+ errorText_ = errorStream_.str();
+ goto unlock;
+ }
+
+ // If we start recording again, we must begin at beginning of buffer.
+ handle->bufferPointer[1] = 0;
+ }
+
+ unlock:
+ timeEndPeriod( 1 ); // revert to normal scheduler frequency on lesser windows.
+ MUTEX_UNLOCK( &stream_.mutex );
+
+ if ( FAILED( result ) ) error( RtAudioError::SYSTEM_ERROR );
+}
+
+void RtApiDs :: abortStream()
+{
+ verifyStream();
+ if ( stream_.state == STREAM_STOPPED ) {
+ errorText_ = "RtApiDs::abortStream(): the stream is already stopped!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ DsHandle *handle = (DsHandle *) stream_.apiHandle;
+ handle->drainCounter = 2;
+
+ stopStream();
+}
+
+void RtApiDs :: callbackEvent()
+{
+ if ( stream_.state == STREAM_STOPPED || stream_.state == STREAM_STOPPING ) {
+ Sleep( 50 ); // sleep 50 milliseconds
+ return;
+ }
+
+ if ( stream_.state == STREAM_CLOSED ) {
+ errorText_ = "RtApiDs::callbackEvent(): the stream is closed ... this shouldn't happen!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ CallbackInfo *info = (CallbackInfo *) &stream_.callbackInfo;
+ DsHandle *handle = (DsHandle *) stream_.apiHandle;
+
+ // Check if we were draining the stream and signal is finished.
+ if ( handle->drainCounter > stream_.nBuffers + 2 ) {
+
+ stream_.state = STREAM_STOPPING;
+ if ( handle->internalDrain == false )
+ SetEvent( handle->condition );
+ else
+ stopStream();
+ return;
+ }
+
+ // Invoke user callback to get fresh output data UNLESS we are
+ // draining stream.
+ if ( handle->drainCounter == 0 ) {
+ RtAudioCallback callback = (RtAudioCallback) info->callback;
+ double streamTime = getStreamTime();
+ RtAudioStreamStatus status = 0;
+ if ( stream_.mode != INPUT && handle->xrun[0] == true ) {
+ status |= RTAUDIO_OUTPUT_UNDERFLOW;
+ handle->xrun[0] = false;
+ }
+ if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) {
+ status |= RTAUDIO_INPUT_OVERFLOW;
+ handle->xrun[1] = false;
+ }
+ int cbReturnValue = callback( stream_.userBuffer[0], stream_.userBuffer[1],
+ stream_.bufferSize, streamTime, status, info->userData );
+ if ( cbReturnValue == 2 ) {
+ stream_.state = STREAM_STOPPING;
+ handle->drainCounter = 2;
+ abortStream();
+ return;
+ }
+ else if ( cbReturnValue == 1 ) {
+ handle->drainCounter = 1;
+ handle->internalDrain = true;
+ }
+ }
+
+ HRESULT result;
+ DWORD currentWritePointer, safeWritePointer;
+ DWORD currentReadPointer, safeReadPointer;
+ UINT nextWritePointer;
+
+ LPVOID buffer1 = NULL;
+ LPVOID buffer2 = NULL;
+ DWORD bufferSize1 = 0;
+ DWORD bufferSize2 = 0;
+
+ char *buffer;
+ long bufferBytes;
+
+ MUTEX_LOCK( &stream_.mutex );
+ if ( stream_.state == STREAM_STOPPED ) {
+ MUTEX_UNLOCK( &stream_.mutex );
+ return;
+ }
+
+ if ( buffersRolling == false ) {
+ if ( stream_.mode == DUPLEX ) {
+ //assert( handle->dsBufferSize[0] == handle->dsBufferSize[1] );
+
+ // It takes a while for the devices to get rolling. As a result,
+ // there's no guarantee that the capture and write device pointers
+ // will move in lockstep. Wait here for both devices to start
+ // rolling, and then set our buffer pointers accordingly.
+ // e.g. Crystal Drivers: the capture buffer starts up 5700 to 9600
+ // bytes later than the write buffer.
+
+ // Stub: a serious risk of having a pre-emptive scheduling round
+ // take place between the two GetCurrentPosition calls... but I'm
+ // really not sure how to solve the problem. Temporarily boost to
+ // Realtime priority, maybe; but I'm not sure what priority the
+ // DirectSound service threads run at. We *should* be roughly
+ // within a ms or so of correct.
+
+ LPDIRECTSOUNDBUFFER dsWriteBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
+ LPDIRECTSOUNDCAPTUREBUFFER dsCaptureBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
+
+ DWORD startSafeWritePointer, startSafeReadPointer;
+
+ result = dsWriteBuffer->GetCurrentPosition( NULL, &startSafeWritePointer );
+ if ( FAILED( result ) ) {
+ errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
+ errorText_ = errorStream_.str();
+ MUTEX_UNLOCK( &stream_.mutex );
+ error( RtAudioError::SYSTEM_ERROR );
+ return;
+ }
+ result = dsCaptureBuffer->GetCurrentPosition( NULL, &startSafeReadPointer );
+ if ( FAILED( result ) ) {
+ errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
+ errorText_ = errorStream_.str();
+ MUTEX_UNLOCK( &stream_.mutex );
+ error( RtAudioError::SYSTEM_ERROR );
+ return;
+ }
+ while ( true ) {
+ result = dsWriteBuffer->GetCurrentPosition( NULL, &safeWritePointer );
+ if ( FAILED( result ) ) {
+ errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
+ errorText_ = errorStream_.str();
+ MUTEX_UNLOCK( &stream_.mutex );
+ error( RtAudioError::SYSTEM_ERROR );
+ return;
+ }
+ result = dsCaptureBuffer->GetCurrentPosition( NULL, &safeReadPointer );
+ if ( FAILED( result ) ) {
+ errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
+ errorText_ = errorStream_.str();
+ MUTEX_UNLOCK( &stream_.mutex );
+ error( RtAudioError::SYSTEM_ERROR );
+ return;
+ }
+ if ( safeWritePointer != startSafeWritePointer && safeReadPointer != startSafeReadPointer ) break;
+ Sleep( 1 );
+ }
+
+ //assert( handle->dsBufferSize[0] == handle->dsBufferSize[1] );
+
+ handle->bufferPointer[0] = safeWritePointer + handle->dsPointerLeadTime[0];
+ if ( handle->bufferPointer[0] >= handle->dsBufferSize[0] ) handle->bufferPointer[0] -= handle->dsBufferSize[0];
+ handle->bufferPointer[1] = safeReadPointer;
+ }
+ else if ( stream_.mode == OUTPUT ) {
+
+ // Set the proper nextWritePosition after initial startup.
+ LPDIRECTSOUNDBUFFER dsWriteBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
+ result = dsWriteBuffer->GetCurrentPosition( &currentWritePointer, &safeWritePointer );
+ if ( FAILED( result ) ) {
+ errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
+ errorText_ = errorStream_.str();
+ MUTEX_UNLOCK( &stream_.mutex );
+ error( RtAudioError::SYSTEM_ERROR );
+ return;
+ }
+ handle->bufferPointer[0] = safeWritePointer + handle->dsPointerLeadTime[0];
+ if ( handle->bufferPointer[0] >= handle->dsBufferSize[0] ) handle->bufferPointer[0] -= handle->dsBufferSize[0];
+ }
+
+ buffersRolling = true;
+ }
+
+ if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
+
+ LPDIRECTSOUNDBUFFER dsBuffer = (LPDIRECTSOUNDBUFFER) handle->buffer[0];
+
+ if ( handle->drainCounter > 1 ) { // write zeros to the output stream
+ bufferBytes = stream_.bufferSize * stream_.nUserChannels[0];
+ bufferBytes *= formatBytes( stream_.userFormat );
+ memset( stream_.userBuffer[0], 0, bufferBytes );
+ }
+
+ // Setup parameters and do buffer conversion if necessary.
+ if ( stream_.doConvertBuffer[0] ) {
+ buffer = stream_.deviceBuffer;
+ convertBuffer( buffer, stream_.userBuffer[0], stream_.convertInfo[0] );
+ bufferBytes = stream_.bufferSize * stream_.nDeviceChannels[0];
+ bufferBytes *= formatBytes( stream_.deviceFormat[0] );
+ }
+ else {
+ buffer = stream_.userBuffer[0];
+ bufferBytes = stream_.bufferSize * stream_.nUserChannels[0];
+ bufferBytes *= formatBytes( stream_.userFormat );
+ }
+
+ // No byte swapping necessary in DirectSound implementation.
+
+ // Ahhh ... windoze. 16-bit data is signed but 8-bit data is
+ // unsigned. So, we need to convert our signed 8-bit data here to
+ // unsigned.
+ if ( stream_.deviceFormat[0] == RTAUDIO_SINT8 )
+ for ( int i=0; i<bufferBytes; i++ ) buffer[i] = (unsigned char) ( buffer[i] + 128 );
+
+ DWORD dsBufferSize = handle->dsBufferSize[0];
+ nextWritePointer = handle->bufferPointer[0];
+
+ DWORD endWrite, leadPointer;
+ while ( true ) {
+ // Find out where the read and "safe write" pointers are.
+ result = dsBuffer->GetCurrentPosition( &currentWritePointer, &safeWritePointer );
+ if ( FAILED( result ) ) {
+ errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current write position!";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::SYSTEM_ERROR );
+ return;
+ }
+
+ // We will copy our output buffer into the region between
+ // safeWritePointer and leadPointer. If leadPointer is not
+ // beyond the next endWrite position, wait until it is.
+ leadPointer = safeWritePointer + handle->dsPointerLeadTime[0];
+ //std::cout << "safeWritePointer = " << safeWritePointer << ", leadPointer = " << leadPointer << ", nextWritePointer = " << nextWritePointer << std::endl;
+ if ( leadPointer > dsBufferSize ) leadPointer -= dsBufferSize;
+ if ( leadPointer < nextWritePointer ) leadPointer += dsBufferSize; // unwrap offset
+ endWrite = nextWritePointer + bufferBytes;
+
+ // Check whether the entire write region is behind the play pointer.
+ if ( leadPointer >= endWrite ) break;
+
+ // If we are here, then we must wait until the leadPointer advances
+ // beyond the end of our next write region. We use the
+ // Sleep() function to suspend operation until that happens.
+ double millis = ( endWrite - leadPointer ) * 1000.0;
+ millis /= ( formatBytes( stream_.deviceFormat[0]) * stream_.nDeviceChannels[0] * stream_.sampleRate);
+ if ( millis < 1.0 ) millis = 1.0;
+ Sleep( (DWORD) millis );
+ }
+
+ if ( dsPointerBetween( nextWritePointer, safeWritePointer, currentWritePointer, dsBufferSize )
+ || dsPointerBetween( endWrite, safeWritePointer, currentWritePointer, dsBufferSize ) ) {
+ // We've strayed into the forbidden zone ... resync the read pointer.
+ handle->xrun[0] = true;
+ nextWritePointer = safeWritePointer + handle->dsPointerLeadTime[0] - bufferBytes;
+ if ( nextWritePointer >= dsBufferSize ) nextWritePointer -= dsBufferSize;
+ handle->bufferPointer[0] = nextWritePointer;
+ endWrite = nextWritePointer + bufferBytes;
+ }
+
+ // Lock free space in the buffer
+ result = dsBuffer->Lock( nextWritePointer, bufferBytes, &buffer1,
+ &bufferSize1, &buffer2, &bufferSize2, 0 );
+ if ( FAILED( result ) ) {
+ errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking buffer during playback!";
+ errorText_ = errorStream_.str();
+ MUTEX_UNLOCK( &stream_.mutex );
+ error( RtAudioError::SYSTEM_ERROR );
+ return;
+ }
+
+ // Copy our buffer into the DS buffer
+ CopyMemory( buffer1, buffer, bufferSize1 );
+ if ( buffer2 != NULL ) CopyMemory( buffer2, buffer+bufferSize1, bufferSize2 );
+
+ // Update our buffer offset and unlock sound buffer
+ dsBuffer->Unlock( buffer1, bufferSize1, buffer2, bufferSize2 );
+ if ( FAILED( result ) ) {
+ errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking buffer during playback!";
+ errorText_ = errorStream_.str();
+ MUTEX_UNLOCK( &stream_.mutex );
+ error( RtAudioError::SYSTEM_ERROR );
+ return;
+ }
+ nextWritePointer = ( nextWritePointer + bufferSize1 + bufferSize2 ) % dsBufferSize;
+ handle->bufferPointer[0] = nextWritePointer;
+ }
+
+ // Don't bother draining input
+ if ( handle->drainCounter ) {
+ handle->drainCounter++;
+ goto unlock;
+ }
+
+ if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
+
+ // Setup parameters.
+ if ( stream_.doConvertBuffer[1] ) {
+ buffer = stream_.deviceBuffer;
+ bufferBytes = stream_.bufferSize * stream_.nDeviceChannels[1];
+ bufferBytes *= formatBytes( stream_.deviceFormat[1] );
+ }
+ else {
+ buffer = stream_.userBuffer[1];
+ bufferBytes = stream_.bufferSize * stream_.nUserChannels[1];
+ bufferBytes *= formatBytes( stream_.userFormat );
+ }
+
+ LPDIRECTSOUNDCAPTUREBUFFER dsBuffer = (LPDIRECTSOUNDCAPTUREBUFFER) handle->buffer[1];
+ long nextReadPointer = handle->bufferPointer[1];
+ DWORD dsBufferSize = handle->dsBufferSize[1];
+
+ // Find out where the write and "safe read" pointers are.
+ result = dsBuffer->GetCurrentPosition( &currentReadPointer, &safeReadPointer );
+ if ( FAILED( result ) ) {
+ errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
+ errorText_ = errorStream_.str();
+ MUTEX_UNLOCK( &stream_.mutex );
+ error( RtAudioError::SYSTEM_ERROR );
+ return;
+ }
+
+ if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset
+ DWORD endRead = nextReadPointer + bufferBytes;
+
+ // Handling depends on whether we are INPUT or DUPLEX.
+ // If we're in INPUT mode then waiting is a good thing. If we're in DUPLEX mode,
+ // then a wait here will drag the write pointers into the forbidden zone.
+ //
+ // In DUPLEX mode, rather than wait, we will back off the read pointer until
+ // it's in a safe position. This causes dropouts, but it seems to be the only
+ // practical way to sync up the read and write pointers reliably, given the
+ // the very complex relationship between phase and increment of the read and write
+ // pointers.
+ //
+ // In order to minimize audible dropouts in DUPLEX mode, we will
+ // provide a pre-roll period of 0.5 seconds in which we return
+ // zeros from the read buffer while the pointers sync up.
+
+ if ( stream_.mode == DUPLEX ) {
+ if ( safeReadPointer < endRead ) {
+ if ( duplexPrerollBytes <= 0 ) {
+ // Pre-roll time over. Be more agressive.
+ int adjustment = endRead-safeReadPointer;
+
+ handle->xrun[1] = true;
+ // Two cases:
+ // - large adjustments: we've probably run out of CPU cycles, so just resync exactly,
+ // and perform fine adjustments later.
+ // - small adjustments: back off by twice as much.
+ if ( adjustment >= 2*bufferBytes )
+ nextReadPointer = safeReadPointer-2*bufferBytes;
+ else
+ nextReadPointer = safeReadPointer-bufferBytes-adjustment;
+
+ if ( nextReadPointer < 0 ) nextReadPointer += dsBufferSize;
+
+ }
+ else {
+ // In pre=roll time. Just do it.
+ nextReadPointer = safeReadPointer - bufferBytes;
+ while ( nextReadPointer < 0 ) nextReadPointer += dsBufferSize;
+ }
+ endRead = nextReadPointer + bufferBytes;
+ }
+ }
+ else { // mode == INPUT
+ while ( safeReadPointer < endRead && stream_.callbackInfo.isRunning ) {
+ // See comments for playback.
+ double millis = (endRead - safeReadPointer) * 1000.0;
+ millis /= ( formatBytes(stream_.deviceFormat[1]) * stream_.nDeviceChannels[1] * stream_.sampleRate);
+ if ( millis < 1.0 ) millis = 1.0;
+ Sleep( (DWORD) millis );
+
+ // Wake up and find out where we are now.
+ result = dsBuffer->GetCurrentPosition( &currentReadPointer, &safeReadPointer );
+ if ( FAILED( result ) ) {
+ errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") getting current read position!";
+ errorText_ = errorStream_.str();
+ MUTEX_UNLOCK( &stream_.mutex );
+ error( RtAudioError::SYSTEM_ERROR );
+ return;
+ }
+
+ if ( safeReadPointer < (DWORD)nextReadPointer ) safeReadPointer += dsBufferSize; // unwrap offset
+ }
+ }
+
+ // Lock free space in the buffer
+ result = dsBuffer->Lock( nextReadPointer, bufferBytes, &buffer1,
+ &bufferSize1, &buffer2, &bufferSize2, 0 );
+ if ( FAILED( result ) ) {
+ errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") locking capture buffer!";
+ errorText_ = errorStream_.str();
+ MUTEX_UNLOCK( &stream_.mutex );
+ error( RtAudioError::SYSTEM_ERROR );
+ return;
+ }
+
+ if ( duplexPrerollBytes <= 0 ) {
+ // Copy our buffer into the DS buffer
+ CopyMemory( buffer, buffer1, bufferSize1 );
+ if ( buffer2 != NULL ) CopyMemory( buffer+bufferSize1, buffer2, bufferSize2 );
+ }
+ else {
+ memset( buffer, 0, bufferSize1 );
+ if ( buffer2 != NULL ) memset( buffer + bufferSize1, 0, bufferSize2 );
+ duplexPrerollBytes -= bufferSize1 + bufferSize2;
+ }
+
+ // Update our buffer offset and unlock sound buffer
+ nextReadPointer = ( nextReadPointer + bufferSize1 + bufferSize2 ) % dsBufferSize;
+ dsBuffer->Unlock( buffer1, bufferSize1, buffer2, bufferSize2 );
+ if ( FAILED( result ) ) {
+ errorStream_ << "RtApiDs::callbackEvent: error (" << getErrorString( result ) << ") unlocking capture buffer!";
+ errorText_ = errorStream_.str();
+ MUTEX_UNLOCK( &stream_.mutex );
+ error( RtAudioError::SYSTEM_ERROR );
+ return;
+ }
+ handle->bufferPointer[1] = nextReadPointer;
+
+ // No byte swapping necessary in DirectSound implementation.
+
+ // If necessary, convert 8-bit data from unsigned to signed.
+ if ( stream_.deviceFormat[1] == RTAUDIO_SINT8 )
+ for ( int j=0; j<bufferBytes; j++ ) buffer[j] = (signed char) ( buffer[j] - 128 );
+
+ // Do buffer conversion if necessary.
+ if ( stream_.doConvertBuffer[1] )
+ convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );
+ }
+
+ unlock:
+ MUTEX_UNLOCK( &stream_.mutex );
+ RtApi::tickStreamTime();
+}
+
+// Definitions for utility functions and callbacks
+// specific to the DirectSound implementation.
+
+static unsigned __stdcall callbackHandler( void *ptr )
+{
+ CallbackInfo *info = (CallbackInfo *) ptr;
+ RtApiDs *object = (RtApiDs *) info->object;
+ bool* isRunning = &info->isRunning;
+
+ while ( *isRunning == true ) {
+ object->callbackEvent();
+ }
+
+ _endthreadex( 0 );
+ return 0;
+}
+
+static BOOL CALLBACK deviceQueryCallback( LPGUID lpguid,
+ LPCTSTR description,
+ LPCTSTR /*module*/,
+ LPVOID lpContext )
+{
+ struct DsProbeData& probeInfo = *(struct DsProbeData*) lpContext;
+ std::vector<struct DsDevice>& dsDevices = *probeInfo.dsDevices;
+
+ HRESULT hr;
+ bool validDevice = false;
+ if ( probeInfo.isInput == true ) {
+ DSCCAPS caps;
+ LPDIRECTSOUNDCAPTURE object;
+
+ hr = DirectSoundCaptureCreate( lpguid, &object, NULL );
+ if ( hr != DS_OK ) return TRUE;
+
+ caps.dwSize = sizeof(caps);
+ hr = object->GetCaps( &caps );
+ if ( hr == DS_OK ) {
+ if ( caps.dwChannels > 0 && caps.dwFormats > 0 )
+ validDevice = true;
+ }
+ object->Release();
+ }
+ else {
+ DSCAPS caps;
+ LPDIRECTSOUND object;
+ hr = DirectSoundCreate( lpguid, &object, NULL );
+ if ( hr != DS_OK ) return TRUE;
+
+ caps.dwSize = sizeof(caps);
+ hr = object->GetCaps( &caps );
+ if ( hr == DS_OK ) {
+ if ( caps.dwFlags & DSCAPS_PRIMARYMONO || caps.dwFlags & DSCAPS_PRIMARYSTEREO )
+ validDevice = true;
+ }
+ object->Release();
+ }
+
+ // If good device, then save its name and guid.
+ std::string name = convertCharPointerToStdString( description );
+ //if ( name == "Primary Sound Driver" || name == "Primary Sound Capture Driver" )
+ if ( lpguid == NULL )
+ name = "Default Device";
+ if ( validDevice ) {
+ for ( unsigned int i=0; i<dsDevices.size(); i++ ) {
+ if ( dsDevices[i].name == name ) {
+ dsDevices[i].found = true;
+ if ( probeInfo.isInput ) {
+ dsDevices[i].id[1] = lpguid;
+ dsDevices[i].validId[1] = true;
+ }
+ else {
+ dsDevices[i].id[0] = lpguid;
+ dsDevices[i].validId[0] = true;
+ }
+ return TRUE;
+ }
+ }
+
+ DsDevice device;
+ device.name = name;
+ device.found = true;
+ if ( probeInfo.isInput ) {
+ device.id[1] = lpguid;
+ device.validId[1] = true;
+ }
+ else {
+ device.id[0] = lpguid;
+ device.validId[0] = true;
+ }
+ dsDevices.push_back( device );
+ }
+
+ return TRUE;
+}
+
+static const char* getErrorString( int code )
+{
+ switch ( code ) {
+
+ case DSERR_ALLOCATED:
+ return "Already allocated";
+
+ case DSERR_CONTROLUNAVAIL:
+ return "Control unavailable";
+
+ case DSERR_INVALIDPARAM:
+ return "Invalid parameter";
+
+ case DSERR_INVALIDCALL:
+ return "Invalid call";
+
+ case DSERR_GENERIC:
+ return "Generic error";
+
+ case DSERR_PRIOLEVELNEEDED:
+ return "Priority level needed";
+
+ case DSERR_OUTOFMEMORY:
+ return "Out of memory";
+
+ case DSERR_BADFORMAT:
+ return "The sample rate or the channel format is not supported";
+
+ case DSERR_UNSUPPORTED:
+ return "Not supported";
+
+ case DSERR_NODRIVER:
+ return "No driver";
+
+ case DSERR_ALREADYINITIALIZED:
+ return "Already initialized";
+
+ case DSERR_NOAGGREGATION:
+ return "No aggregation";
+
+ case DSERR_BUFFERLOST:
+ return "Buffer lost";
+
+ case DSERR_OTHERAPPHASPRIO:
+ return "Another application already has priority";
+
+ case DSERR_UNINITIALIZED:
+ return "Uninitialized";
+
+ default:
+ return "DirectSound unknown error";
+ }
+}
+//******************** End of __WINDOWS_DS__ *********************//
+#endif
+
+
+#if defined(__LINUX_ALSA__)
+
+#include <alsa/asoundlib.h>
+#include <unistd.h>
+
+ // A structure to hold various information related to the ALSA API
+ // implementation.
+struct AlsaHandle {
+ snd_pcm_t *handles[2];
+ bool synchronized;
+ bool xrun[2];
+ pthread_cond_t runnable_cv;
+ bool runnable;
+
+ AlsaHandle()
+ :synchronized(false), runnable(false) { xrun[0] = false; xrun[1] = false; }
+};
+
+static void *alsaCallbackHandler( void * ptr );
+
+RtApiAlsa :: RtApiAlsa()
+{
+ // Nothing to do here.
+}
+
+RtApiAlsa :: ~RtApiAlsa()
+{
+ if ( stream_.state != STREAM_CLOSED ) closeStream();
+}
+
+unsigned int RtApiAlsa :: getDeviceCount( void )
+{
+ unsigned nDevices = 0;
+ int result, subdevice, card;
+ char name[64];
+ snd_ctl_t *handle;
+
+ // Count cards and devices
+ card = -1;
+ snd_card_next( &card );
+ while ( card >= 0 ) {
+ sprintf( name, "hw:%d", card );
+ result = snd_ctl_open( &handle, name, 0 );
+ if ( result < 0 ) {
+ errorStream_ << "RtApiAlsa::getDeviceCount: control open, card = " << card << ", " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ goto nextcard;
+ }
+ subdevice = -1;
+ while( 1 ) {
+ result = snd_ctl_pcm_next_device( handle, &subdevice );
+ if ( result < 0 ) {
+ errorStream_ << "RtApiAlsa::getDeviceCount: control next device, card = " << card << ", " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ break;
+ }
+ if ( subdevice < 0 )
+ break;
+ nDevices++;
+ }
+ nextcard:
+ snd_ctl_close( handle );
+ snd_card_next( &card );
+ }
+
+ result = snd_ctl_open( &handle, "default", 0 );
+ if (result == 0) {
+ nDevices++;
+ snd_ctl_close( handle );
+ }
+
+ return nDevices;
+}
+
+RtAudio::DeviceInfo RtApiAlsa :: getDeviceInfo( unsigned int device )
+{
+ RtAudio::DeviceInfo info;
+ info.probed = false;
+
+ unsigned nDevices = 0;
+ int result, subdevice, card;
+ char name[64];
+ snd_ctl_t *chandle;
+
+ // Count cards and devices
+ card = -1;
+ subdevice = -1;
+ snd_card_next( &card );
+ while ( card >= 0 ) {
+ sprintf( name, "hw:%d", card );
+ result = snd_ctl_open( &chandle, name, SND_CTL_NONBLOCK );
+ if ( result < 0 ) {
+ errorStream_ << "RtApiAlsa::getDeviceInfo: control open, card = " << card << ", " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ goto nextcard;
+ }
+ subdevice = -1;
+ while( 1 ) {
+ result = snd_ctl_pcm_next_device( chandle, &subdevice );
+ if ( result < 0 ) {
+ errorStream_ << "RtApiAlsa::getDeviceInfo: control next device, card = " << card << ", " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ break;
+ }
+ if ( subdevice < 0 ) break;
+ if ( nDevices == device ) {
+ sprintf( name, "hw:%d,%d", card, subdevice );
+ goto foundDevice;
+ }
+ nDevices++;
+ }
+ nextcard:
+ snd_ctl_close( chandle );
+ snd_card_next( &card );
+ }
+
+ result = snd_ctl_open( &chandle, "default", SND_CTL_NONBLOCK );
+ if ( result == 0 ) {
+ if ( nDevices == device ) {
+ strcpy( name, "default" );
+ goto foundDevice;
+ }
+ nDevices++;
+ }
+
+ if ( nDevices == 0 ) {
+ errorText_ = "RtApiAlsa::getDeviceInfo: no devices found!";
+ error( RtAudioError::INVALID_USE );
+ return info;
+ }
+
+ if ( device >= nDevices ) {
+ errorText_ = "RtApiAlsa::getDeviceInfo: device ID is invalid!";
+ error( RtAudioError::INVALID_USE );
+ return info;
+ }
+
+ foundDevice:
+
+ // If a stream is already open, we cannot probe the stream devices.
+ // Thus, use the saved results.
+ if ( stream_.state != STREAM_CLOSED &&
+ ( stream_.device[0] == device || stream_.device[1] == device ) ) {
+ snd_ctl_close( chandle );
+ if ( device >= devices_.size() ) {
+ errorText_ = "RtApiAlsa::getDeviceInfo: device ID was not present before stream was opened.";
+ error( RtAudioError::WARNING );
+ return info;
+ }
+ return devices_[ device ];
+ }
+
+ int openMode = SND_PCM_ASYNC;
+ snd_pcm_stream_t stream;
+ snd_pcm_info_t *pcminfo;
+ snd_pcm_info_alloca( &pcminfo );
+ snd_pcm_t *phandle;
+ snd_pcm_hw_params_t *params;
+ snd_pcm_hw_params_alloca( &params );
+
+ // First try for playback unless default device (which has subdev -1)
+ stream = SND_PCM_STREAM_PLAYBACK;
+ snd_pcm_info_set_stream( pcminfo, stream );
+ if ( subdevice != -1 ) {
+ snd_pcm_info_set_device( pcminfo, subdevice );
+ snd_pcm_info_set_subdevice( pcminfo, 0 );
+
+ result = snd_ctl_pcm_info( chandle, pcminfo );
+ if ( result < 0 ) {
+ // Device probably doesn't support playback.
+ goto captureProbe;
+ }
+ }
+
+ result = snd_pcm_open( &phandle, name, stream, openMode | SND_PCM_NONBLOCK );
+ if ( result < 0 ) {
+ errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ goto captureProbe;
+ }
+
+ // The device is open ... fill the parameter structure.
+ result = snd_pcm_hw_params_any( phandle, params );
+ if ( result < 0 ) {
+ snd_pcm_close( phandle );
+ errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ goto captureProbe;
+ }
+
+ // Get output channel information.
+ unsigned int value;
+ result = snd_pcm_hw_params_get_channels_max( params, &value );
+ if ( result < 0 ) {
+ snd_pcm_close( phandle );
+ errorStream_ << "RtApiAlsa::getDeviceInfo: error getting device (" << name << ") output channels, " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ goto captureProbe;
+ }
+ info.outputChannels = value;
+ snd_pcm_close( phandle );
+
+ captureProbe:
+ stream = SND_PCM_STREAM_CAPTURE;
+ snd_pcm_info_set_stream( pcminfo, stream );
+
+ // Now try for capture unless default device (with subdev = -1)
+ if ( subdevice != -1 ) {
+ result = snd_ctl_pcm_info( chandle, pcminfo );
+ snd_ctl_close( chandle );
+ if ( result < 0 ) {
+ // Device probably doesn't support capture.
+ if ( info.outputChannels == 0 ) return info;
+ goto probeParameters;
+ }
+ }
+ else
+ snd_ctl_close( chandle );
+
+ result = snd_pcm_open( &phandle, name, stream, openMode | SND_PCM_NONBLOCK);
+ if ( result < 0 ) {
+ errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ if ( info.outputChannels == 0 ) return info;
+ goto probeParameters;
+ }
+
+ // The device is open ... fill the parameter structure.
+ result = snd_pcm_hw_params_any( phandle, params );
+ if ( result < 0 ) {
+ snd_pcm_close( phandle );
+ errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ if ( info.outputChannels == 0 ) return info;
+ goto probeParameters;
+ }
+
+ result = snd_pcm_hw_params_get_channels_max( params, &value );
+ if ( result < 0 ) {
+ snd_pcm_close( phandle );
+ errorStream_ << "RtApiAlsa::getDeviceInfo: error getting device (" << name << ") input channels, " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ if ( info.outputChannels == 0 ) return info;
+ goto probeParameters;
+ }
+ info.inputChannels = value;
+ snd_pcm_close( phandle );
+
+ // If device opens for both playback and capture, we determine the channels.
+ if ( info.outputChannels > 0 && info.inputChannels > 0 )
+ info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;
+
+ // ALSA doesn't provide default devices so we'll use the first available one.
+ if ( device == 0 && info.outputChannels > 0 )
+ info.isDefaultOutput = true;
+ if ( device == 0 && info.inputChannels > 0 )
+ info.isDefaultInput = true;
+
+ probeParameters:
+ // At this point, we just need to figure out the supported data
+ // formats and sample rates. We'll proceed by opening the device in
+ // the direction with the maximum number of channels, or playback if
+ // they are equal. This might limit our sample rate options, but so
+ // be it.
+
+ if ( info.outputChannels >= info.inputChannels )
+ stream = SND_PCM_STREAM_PLAYBACK;
+ else
+ stream = SND_PCM_STREAM_CAPTURE;
+ snd_pcm_info_set_stream( pcminfo, stream );
+
+ result = snd_pcm_open( &phandle, name, stream, openMode | SND_PCM_NONBLOCK);
+ if ( result < 0 ) {
+ errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_open error for device (" << name << "), " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ // The device is open ... fill the parameter structure.
+ result = snd_pcm_hw_params_any( phandle, params );
+ if ( result < 0 ) {
+ snd_pcm_close( phandle );
+ errorStream_ << "RtApiAlsa::getDeviceInfo: snd_pcm_hw_params error for device (" << name << "), " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ // Test our discrete set of sample rate values.
+ info.sampleRates.clear();
+ for ( unsigned int i=0; i<MAX_SAMPLE_RATES; i++ ) {
+ if ( snd_pcm_hw_params_test_rate( phandle, params, SAMPLE_RATES[i], 0 ) == 0 ) {
+ info.sampleRates.push_back( SAMPLE_RATES[i] );
+
+ if ( !info.preferredSampleRate || ( SAMPLE_RATES[i] <= 48000 && SAMPLE_RATES[i] > info.preferredSampleRate ) )
+ info.preferredSampleRate = SAMPLE_RATES[i];
+ }
+ }
+ if ( info.sampleRates.size() == 0 ) {
+ snd_pcm_close( phandle );
+ errorStream_ << "RtApiAlsa::getDeviceInfo: no supported sample rates found for device (" << name << ").";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ // Probe the supported data formats ... we don't care about endian-ness just yet
+ snd_pcm_format_t format;
+ info.nativeFormats = 0;
+ format = SND_PCM_FORMAT_S8;
+ if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )
+ info.nativeFormats |= RTAUDIO_SINT8;
+ format = SND_PCM_FORMAT_S16;
+ if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )
+ info.nativeFormats |= RTAUDIO_SINT16;
+ format = SND_PCM_FORMAT_S24;
+ if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )
+ info.nativeFormats |= RTAUDIO_SINT24;
+ format = SND_PCM_FORMAT_S32;
+ if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )
+ info.nativeFormats |= RTAUDIO_SINT32;
+ format = SND_PCM_FORMAT_FLOAT;
+ if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )
+ info.nativeFormats |= RTAUDIO_FLOAT32;
+ format = SND_PCM_FORMAT_FLOAT64;
+ if ( snd_pcm_hw_params_test_format( phandle, params, format ) == 0 )
+ info.nativeFormats |= RTAUDIO_FLOAT64;
+
+ // Check that we have at least one supported format
+ if ( info.nativeFormats == 0 ) {
+ snd_pcm_close( phandle );
+ errorStream_ << "RtApiAlsa::getDeviceInfo: pcm device (" << name << ") data format not supported by RtAudio.";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ // Get the device name
+ char *cardname;
+ result = snd_card_get_name( card, &cardname );
+ if ( result >= 0 ) {
+ sprintf( name, "hw:%s,%d", cardname, subdevice );
+ free( cardname );
+ }
+ info.name = name;
+
+ // That's all ... close the device and return
+ snd_pcm_close( phandle );
+ info.probed = true;
+ return info;
+}
+
+void RtApiAlsa :: saveDeviceInfo( void )
+{
+ devices_.clear();
+
+ unsigned int nDevices = getDeviceCount();
+ devices_.resize( nDevices );
+ for ( unsigned int i=0; i<nDevices; i++ )
+ devices_[i] = getDeviceInfo( i );
+}
+
+bool RtApiAlsa :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
+ unsigned int firstChannel, unsigned int sampleRate,
+ RtAudioFormat format, unsigned int *bufferSize,
+ RtAudio::StreamOptions *options )
+
+{
+#if defined(__RTAUDIO_DEBUG__)
+ snd_output_t *out;
+ snd_output_stdio_attach(&out, stderr, 0);
+#endif
+
+ // I'm not using the "plug" interface ... too much inconsistent behavior.
+
+ unsigned nDevices = 0;
+ int result, subdevice, card;
+ char name[64];
+ snd_ctl_t *chandle;
+
+ if ( options && options->flags & RTAUDIO_ALSA_USE_DEFAULT )
+ snprintf(name, sizeof(name), "%s", "default");
+ else {
+ // Count cards and devices
+ card = -1;
+ snd_card_next( &card );
+ while ( card >= 0 ) {
+ sprintf( name, "hw:%d", card );
+ result = snd_ctl_open( &chandle, name, SND_CTL_NONBLOCK );
+ if ( result < 0 ) {
+ errorStream_ << "RtApiAlsa::probeDeviceOpen: control open, card = " << card << ", " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+ subdevice = -1;
+ while( 1 ) {
+ result = snd_ctl_pcm_next_device( chandle, &subdevice );
+ if ( result < 0 ) break;
+ if ( subdevice < 0 ) break;
+ if ( nDevices == device ) {
+ sprintf( name, "hw:%d,%d", card, subdevice );
+ snd_ctl_close( chandle );
+ goto foundDevice;
+ }
+ nDevices++;
+ }
+ snd_ctl_close( chandle );
+ snd_card_next( &card );
+ }
+
+ result = snd_ctl_open( &chandle, "default", SND_CTL_NONBLOCK );
+ if ( result == 0 ) {
+ if ( nDevices == device ) {
+ strcpy( name, "default" );
+ goto foundDevice;
+ }
+ nDevices++;
+ }
+
+ if ( nDevices == 0 ) {
+ // This should not happen because a check is made before this function is called.
+ errorText_ = "RtApiAlsa::probeDeviceOpen: no devices found!";
+ return FAILURE;
+ }
+
+ if ( device >= nDevices ) {
+ // This should not happen because a check is made before this function is called.
+ errorText_ = "RtApiAlsa::probeDeviceOpen: device ID is invalid!";
+ return FAILURE;
+ }
+ }
+
+ foundDevice:
+
+ // The getDeviceInfo() function will not work for a device that is
+ // already open. Thus, we'll probe the system before opening a
+ // stream and save the results for use by getDeviceInfo().
+ if ( mode == OUTPUT || ( mode == INPUT && stream_.mode != OUTPUT ) ) // only do once
+ this->saveDeviceInfo();
+
+ snd_pcm_stream_t stream;
+ if ( mode == OUTPUT )
+ stream = SND_PCM_STREAM_PLAYBACK;
+ else
+ stream = SND_PCM_STREAM_CAPTURE;
+
+ snd_pcm_t *phandle;
+ int openMode = SND_PCM_ASYNC;
+ result = snd_pcm_open( &phandle, name, stream, openMode );
+ if ( result < 0 ) {
+ if ( mode == OUTPUT )
+ errorStream_ << "RtApiAlsa::probeDeviceOpen: pcm device (" << name << ") won't open for output.";
+ else
+ errorStream_ << "RtApiAlsa::probeDeviceOpen: pcm device (" << name << ") won't open for input.";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Fill the parameter structure.
+ snd_pcm_hw_params_t *hw_params;
+ snd_pcm_hw_params_alloca( &hw_params );
+ result = snd_pcm_hw_params_any( phandle, hw_params );
+ if ( result < 0 ) {
+ snd_pcm_close( phandle );
+ errorStream_ << "RtApiAlsa::probeDeviceOpen: error getting pcm device (" << name << ") parameters, " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+#if defined(__RTAUDIO_DEBUG__)
+ fprintf( stderr, "\nRtApiAlsa: dump hardware params just after device open:\n\n" );
+ snd_pcm_hw_params_dump( hw_params, out );
+#endif
+
+ // Set access ... check user preference.
+ if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) {
+ stream_.userInterleaved = false;
+ result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED );
+ if ( result < 0 ) {
+ result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED );
+ stream_.deviceInterleaved[mode] = true;
+ }
+ else
+ stream_.deviceInterleaved[mode] = false;
+ }
+ else {
+ stream_.userInterleaved = true;
+ result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED );
+ if ( result < 0 ) {
+ result = snd_pcm_hw_params_set_access( phandle, hw_params, SND_PCM_ACCESS_RW_NONINTERLEAVED );
+ stream_.deviceInterleaved[mode] = false;
+ }
+ else
+ stream_.deviceInterleaved[mode] = true;
+ }
+
+ if ( result < 0 ) {
+ snd_pcm_close( phandle );
+ errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting pcm device (" << name << ") access, " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Determine how to set the device format.
+ stream_.userFormat = format;
+ snd_pcm_format_t deviceFormat = SND_PCM_FORMAT_UNKNOWN;
+
+ if ( format == RTAUDIO_SINT8 )
+ deviceFormat = SND_PCM_FORMAT_S8;
+ else if ( format == RTAUDIO_SINT16 )
+ deviceFormat = SND_PCM_FORMAT_S16;
+ else if ( format == RTAUDIO_SINT24 )
+ deviceFormat = SND_PCM_FORMAT_S24;
+ else if ( format == RTAUDIO_SINT32 )
+ deviceFormat = SND_PCM_FORMAT_S32;
+ else if ( format == RTAUDIO_FLOAT32 )
+ deviceFormat = SND_PCM_FORMAT_FLOAT;
+ else if ( format == RTAUDIO_FLOAT64 )
+ deviceFormat = SND_PCM_FORMAT_FLOAT64;
+
+ if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat) == 0) {
+ stream_.deviceFormat[mode] = format;
+ goto setFormat;
+ }
+
+ // The user requested format is not natively supported by the device.
+ deviceFormat = SND_PCM_FORMAT_FLOAT64;
+ if ( snd_pcm_hw_params_test_format( phandle, hw_params, deviceFormat ) == 0 ) {
+ stream_.deviceFormat[mode] = RTAUDIO_FLOAT64;
+ goto setFormat;
+ }
+
+ deviceFormat = SND_PCM_FORMAT_FLOAT;
+ if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) {
+ stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
+ goto setFormat;
+ }
+
+ deviceFormat = SND_PCM_FORMAT_S32;
+ if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) {
+ stream_.deviceFormat[mode] = RTAUDIO_SINT32;
+ goto setFormat;
+ }
+
+ deviceFormat = SND_PCM_FORMAT_S24;
+ if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) {
+ stream_.deviceFormat[mode] = RTAUDIO_SINT24;
+ goto setFormat;
+ }
+
+ deviceFormat = SND_PCM_FORMAT_S16;
+ if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) {
+ stream_.deviceFormat[mode] = RTAUDIO_SINT16;
+ goto setFormat;
+ }
+
+ deviceFormat = SND_PCM_FORMAT_S8;
+ if ( snd_pcm_hw_params_test_format(phandle, hw_params, deviceFormat ) == 0 ) {
+ stream_.deviceFormat[mode] = RTAUDIO_SINT8;
+ goto setFormat;
+ }
+
+ // If we get here, no supported format was found.
+ snd_pcm_close( phandle );
+ errorStream_ << "RtApiAlsa::probeDeviceOpen: pcm device " << device << " data format not supported by RtAudio.";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+
+ setFormat:
+ result = snd_pcm_hw_params_set_format( phandle, hw_params, deviceFormat );
+ if ( result < 0 ) {
+ snd_pcm_close( phandle );
+ errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting pcm device (" << name << ") data format, " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Determine whether byte-swaping is necessary.
+ stream_.doByteSwap[mode] = false;
+ if ( deviceFormat != SND_PCM_FORMAT_S8 ) {
+ result = snd_pcm_format_cpu_endian( deviceFormat );
+ if ( result == 0 )
+ stream_.doByteSwap[mode] = true;
+ else if (result < 0) {
+ snd_pcm_close( phandle );
+ errorStream_ << "RtApiAlsa::probeDeviceOpen: error getting pcm device (" << name << ") endian-ness, " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+ }
+
+ // Set the sample rate.
+ result = snd_pcm_hw_params_set_rate_near( phandle, hw_params, (unsigned int*) &sampleRate, 0 );
+ if ( result < 0 ) {
+ snd_pcm_close( phandle );
+ errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting sample rate on device (" << name << "), " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Determine the number of channels for this device. We support a possible
+ // minimum device channel number > than the value requested by the user.
+ stream_.nUserChannels[mode] = channels;
+ unsigned int value;
+ result = snd_pcm_hw_params_get_channels_max( hw_params, &value );
+ unsigned int deviceChannels = value;
+ if ( result < 0 || deviceChannels < channels + firstChannel ) {
+ snd_pcm_close( phandle );
+ errorStream_ << "RtApiAlsa::probeDeviceOpen: requested channel parameters not supported by device (" << name << "), " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ result = snd_pcm_hw_params_get_channels_min( hw_params, &value );
+ if ( result < 0 ) {
+ snd_pcm_close( phandle );
+ errorStream_ << "RtApiAlsa::probeDeviceOpen: error getting minimum channels for device (" << name << "), " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+ deviceChannels = value;
+ if ( deviceChannels < channels + firstChannel ) deviceChannels = channels + firstChannel;
+ stream_.nDeviceChannels[mode] = deviceChannels;
+
+ // Set the device channels.
+ result = snd_pcm_hw_params_set_channels( phandle, hw_params, deviceChannels );
+ if ( result < 0 ) {
+ snd_pcm_close( phandle );
+ errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting channels for device (" << name << "), " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Set the buffer (or period) size.
+ int dir = 0;
+ snd_pcm_uframes_t periodSize = *bufferSize;
+ result = snd_pcm_hw_params_set_period_size_near( phandle, hw_params, &periodSize, &dir );
+ if ( result < 0 ) {
+ snd_pcm_close( phandle );
+ errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting period size for device (" << name << "), " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+ *bufferSize = periodSize;
+
+ // Set the buffer number, which in ALSA is referred to as the "period".
+ unsigned int periods = 0;
+ if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) periods = 2;
+ if ( options && options->numberOfBuffers > 0 ) periods = options->numberOfBuffers;
+ if ( periods < 2 ) periods = 4; // a fairly safe default value
+ result = snd_pcm_hw_params_set_periods_near( phandle, hw_params, &periods, &dir );
+ if ( result < 0 ) {
+ snd_pcm_close( phandle );
+ errorStream_ << "RtApiAlsa::probeDeviceOpen: error setting periods for device (" << name << "), " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // If attempting to setup a duplex stream, the bufferSize parameter
+ // MUST be the same in both directions!
+ if ( stream_.mode == OUTPUT && mode == INPUT && *bufferSize != stream_.bufferSize ) {
+ snd_pcm_close( phandle );
+ errorStream_ << "RtApiAlsa::probeDeviceOpen: system error setting buffer size for duplex stream on device (" << name << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ stream_.bufferSize = *bufferSize;
+
+ // Install the hardware configuration
+ result = snd_pcm_hw_params( phandle, hw_params );
+ if ( result < 0 ) {
+ snd_pcm_close( phandle );
+ errorStream_ << "RtApiAlsa::probeDeviceOpen: error installing hardware configuration on device (" << name << "), " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+#if defined(__RTAUDIO_DEBUG__)
+ fprintf(stderr, "\nRtApiAlsa: dump hardware params after installation:\n\n");
+ snd_pcm_hw_params_dump( hw_params, out );
+#endif
+
+ // Set the software configuration to fill buffers with zeros and prevent device stopping on xruns.
+ snd_pcm_sw_params_t *sw_params = NULL;
+ snd_pcm_sw_params_alloca( &sw_params );
+ snd_pcm_sw_params_current( phandle, sw_params );
+ snd_pcm_sw_params_set_start_threshold( phandle, sw_params, *bufferSize );
+ snd_pcm_sw_params_set_stop_threshold( phandle, sw_params, ULONG_MAX );
+ snd_pcm_sw_params_set_silence_threshold( phandle, sw_params, 0 );
+
+ // The following two settings were suggested by Theo Veenker
+ //snd_pcm_sw_params_set_avail_min( phandle, sw_params, *bufferSize );
+ //snd_pcm_sw_params_set_xfer_align( phandle, sw_params, 1 );
+
+ // here are two options for a fix
+ //snd_pcm_sw_params_set_silence_size( phandle, sw_params, ULONG_MAX );
+ snd_pcm_uframes_t val;
+ snd_pcm_sw_params_get_boundary( sw_params, &val );
+ snd_pcm_sw_params_set_silence_size( phandle, sw_params, val );
+
+ result = snd_pcm_sw_params( phandle, sw_params );
+ if ( result < 0 ) {
+ snd_pcm_close( phandle );
+ errorStream_ << "RtApiAlsa::probeDeviceOpen: error installing software configuration on device (" << name << "), " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+#if defined(__RTAUDIO_DEBUG__)
+ fprintf(stderr, "\nRtApiAlsa: dump software params after installation:\n\n");
+ snd_pcm_sw_params_dump( sw_params, out );
+#endif
+
+ // Set flags for buffer conversion
+ stream_.doConvertBuffer[mode] = false;
+ if ( stream_.userFormat != stream_.deviceFormat[mode] )
+ stream_.doConvertBuffer[mode] = true;
+ if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] )
+ stream_.doConvertBuffer[mode] = true;
+ if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&
+ stream_.nUserChannels[mode] > 1 )
+ stream_.doConvertBuffer[mode] = true;
+
+ // Allocate the ApiHandle if necessary and then save.
+ AlsaHandle *apiInfo = 0;
+ if ( stream_.apiHandle == 0 ) {
+ try {
+ apiInfo = (AlsaHandle *) new AlsaHandle;
+ }
+ catch ( std::bad_alloc& ) {
+ errorText_ = "RtApiAlsa::probeDeviceOpen: error allocating AlsaHandle memory.";
+ goto error;
+ }
+
+ if ( pthread_cond_init( &apiInfo->runnable_cv, NULL ) ) {
+ errorText_ = "RtApiAlsa::probeDeviceOpen: error initializing pthread condition variable.";
+ goto error;
+ }
+
+ stream_.apiHandle = (void *) apiInfo;
+ apiInfo->handles[0] = 0;
+ apiInfo->handles[1] = 0;
+ }
+ else {
+ apiInfo = (AlsaHandle *) stream_.apiHandle;
+ }
+ apiInfo->handles[mode] = phandle;
+ phandle = 0;
+
+ // Allocate necessary internal buffers.
+ unsigned long bufferBytes;
+ bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
+ stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );
+ if ( stream_.userBuffer[mode] == NULL ) {
+ errorText_ = "RtApiAlsa::probeDeviceOpen: error allocating user buffer memory.";
+ goto error;
+ }
+
+ if ( stream_.doConvertBuffer[mode] ) {
+
+ bool makeBuffer = true;
+ bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );
+ if ( mode == INPUT ) {
+ if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
+ unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );
+ if ( bufferBytes <= bytesOut ) makeBuffer = false;
+ }
+ }
+
+ if ( makeBuffer ) {
+ bufferBytes *= *bufferSize;
+ if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );
+ stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );
+ if ( stream_.deviceBuffer == NULL ) {
+ errorText_ = "RtApiAlsa::probeDeviceOpen: error allocating device buffer memory.";
+ goto error;
+ }
+ }
+ }
+
+ stream_.sampleRate = sampleRate;
+ stream_.nBuffers = periods;
+ stream_.device[mode] = device;
+ stream_.state = STREAM_STOPPED;
+
+ // Setup the buffer conversion information structure.
+ if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel );
+
+ // Setup thread if necessary.
+ if ( stream_.mode == OUTPUT && mode == INPUT ) {
+ // We had already set up an output stream.
+ stream_.mode = DUPLEX;
+ // Link the streams if possible.
+ apiInfo->synchronized = false;
+ if ( snd_pcm_link( apiInfo->handles[0], apiInfo->handles[1] ) == 0 )
+ apiInfo->synchronized = true;
+ else {
+ errorText_ = "RtApiAlsa::probeDeviceOpen: unable to synchronize input and output devices.";
+ error( RtAudioError::WARNING );
+ }
+ }
+ else {
+ stream_.mode = mode;
+
+ // Setup callback thread.
+ stream_.callbackInfo.object = (void *) this;
+
+ // Set the thread attributes for joinable and realtime scheduling
+ // priority (optional). The higher priority will only take affect
+ // if the program is run as root or suid. Note, under Linux
+ // processes with CAP_SYS_NICE privilege, a user can change
+ // scheduling policy and priority (thus need not be root). See
+ // POSIX "capabilities".
+ pthread_attr_t attr;
+ pthread_attr_init( &attr );
+ pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
+
+#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)
+ if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) {
+ // We previously attempted to increase the audio callback priority
+ // to SCHED_RR here via the attributes. However, while no errors
+ // were reported in doing so, it did not work. So, now this is
+ // done in the alsaCallbackHandler function.
+ stream_.callbackInfo.doRealtime = true;
+ int priority = options->priority;
+ int min = sched_get_priority_min( SCHED_RR );
+ int max = sched_get_priority_max( SCHED_RR );
+ if ( priority < min ) priority = min;
+ else if ( priority > max ) priority = max;
+ stream_.callbackInfo.priority = priority;
+ }
+#endif
+
+ stream_.callbackInfo.isRunning = true;
+ result = pthread_create( &stream_.callbackInfo.thread, &attr, alsaCallbackHandler, &stream_.callbackInfo );
+ pthread_attr_destroy( &attr );
+ if ( result ) {
+ stream_.callbackInfo.isRunning = false;
+ errorText_ = "RtApiAlsa::error creating callback thread!";
+ goto error;
+ }
+ }
+
+ return SUCCESS;
+
+ error:
+ if ( apiInfo ) {
+ pthread_cond_destroy( &apiInfo->runnable_cv );
+ if ( apiInfo->handles[0] ) snd_pcm_close( apiInfo->handles[0] );
+ if ( apiInfo->handles[1] ) snd_pcm_close( apiInfo->handles[1] );
+ delete apiInfo;
+ stream_.apiHandle = 0;
+ }
+
+ if ( phandle) snd_pcm_close( phandle );
+
+ for ( int i=0; i<2; i++ ) {
+ if ( stream_.userBuffer[i] ) {
+ free( stream_.userBuffer[i] );
+ stream_.userBuffer[i] = 0;
+ }
+ }
+
+ if ( stream_.deviceBuffer ) {
+ free( stream_.deviceBuffer );
+ stream_.deviceBuffer = 0;
+ }
+
+ stream_.state = STREAM_CLOSED;
+ return FAILURE;
+}
+
+void RtApiAlsa :: closeStream()
+{
+ if ( stream_.state == STREAM_CLOSED ) {
+ errorText_ = "RtApiAlsa::closeStream(): no open stream to close!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
+ stream_.callbackInfo.isRunning = false;
+ MUTEX_LOCK( &stream_.mutex );
+ if ( stream_.state == STREAM_STOPPED ) {
+ apiInfo->runnable = true;
+ pthread_cond_signal( &apiInfo->runnable_cv );
+ }
+ MUTEX_UNLOCK( &stream_.mutex );
+ pthread_join( stream_.callbackInfo.thread, NULL );
+
+ if ( stream_.state == STREAM_RUNNING ) {
+ stream_.state = STREAM_STOPPED;
+ if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX )
+ snd_pcm_drop( apiInfo->handles[0] );
+ if ( stream_.mode == INPUT || stream_.mode == DUPLEX )
+ snd_pcm_drop( apiInfo->handles[1] );
+ }
+
+ if ( apiInfo ) {
+ pthread_cond_destroy( &apiInfo->runnable_cv );
+ if ( apiInfo->handles[0] ) snd_pcm_close( apiInfo->handles[0] );
+ if ( apiInfo->handles[1] ) snd_pcm_close( apiInfo->handles[1] );
+ delete apiInfo;
+ stream_.apiHandle = 0;
+ }
+
+ for ( int i=0; i<2; i++ ) {
+ if ( stream_.userBuffer[i] ) {
+ free( stream_.userBuffer[i] );
+ stream_.userBuffer[i] = 0;
+ }
+ }
+
+ if ( stream_.deviceBuffer ) {
+ free( stream_.deviceBuffer );
+ stream_.deviceBuffer = 0;
+ }
+
+ stream_.mode = UNINITIALIZED;
+ stream_.state = STREAM_CLOSED;
+}
+
+void RtApiAlsa :: startStream()
+{
+ // This method calls snd_pcm_prepare if the device isn't already in that state.
+
+ verifyStream();
+ if ( stream_.state == STREAM_RUNNING ) {
+ errorText_ = "RtApiAlsa::startStream(): the stream is already running!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ MUTEX_LOCK( &stream_.mutex );
+
+ int result = 0;
+ snd_pcm_state_t state;
+ AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
+ snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles;
+ if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
+ state = snd_pcm_state( handle[0] );
+ if ( state != SND_PCM_STATE_PREPARED ) {
+ result = snd_pcm_prepare( handle[0] );
+ if ( result < 0 ) {
+ errorStream_ << "RtApiAlsa::startStream: error preparing output pcm device, " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ goto unlock;
+ }
+ }
+ }
+
+ if ( ( stream_.mode == INPUT || stream_.mode == DUPLEX ) && !apiInfo->synchronized ) {
+ result = snd_pcm_drop(handle[1]); // fix to remove stale data received since device has been open
+ state = snd_pcm_state( handle[1] );
+ if ( state != SND_PCM_STATE_PREPARED ) {
+ result = snd_pcm_prepare( handle[1] );
+ if ( result < 0 ) {
+ errorStream_ << "RtApiAlsa::startStream: error preparing input pcm device, " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ goto unlock;
+ }
+ }
+ }
+
+ stream_.state = STREAM_RUNNING;
+
+ unlock:
+ apiInfo->runnable = true;
+ pthread_cond_signal( &apiInfo->runnable_cv );
+ MUTEX_UNLOCK( &stream_.mutex );
+
+ if ( result >= 0 ) return;
+ error( RtAudioError::SYSTEM_ERROR );
+}
+
+void RtApiAlsa :: stopStream()
+{
+ verifyStream();
+ if ( stream_.state == STREAM_STOPPED ) {
+ errorText_ = "RtApiAlsa::stopStream(): the stream is already stopped!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ stream_.state = STREAM_STOPPED;
+ MUTEX_LOCK( &stream_.mutex );
+
+ int result = 0;
+ AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
+ snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles;
+ if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
+ if ( apiInfo->synchronized )
+ result = snd_pcm_drop( handle[0] );
+ else
+ result = snd_pcm_drain( handle[0] );
+ if ( result < 0 ) {
+ errorStream_ << "RtApiAlsa::stopStream: error draining output pcm device, " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ goto unlock;
+ }
+ }
+
+ if ( ( stream_.mode == INPUT || stream_.mode == DUPLEX ) && !apiInfo->synchronized ) {
+ result = snd_pcm_drop( handle[1] );
+ if ( result < 0 ) {
+ errorStream_ << "RtApiAlsa::stopStream: error stopping input pcm device, " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ goto unlock;
+ }
+ }
+
+ unlock:
+ apiInfo->runnable = false; // fixes high CPU usage when stopped
+ MUTEX_UNLOCK( &stream_.mutex );
+
+ if ( result >= 0 ) return;
+ error( RtAudioError::SYSTEM_ERROR );
+}
+
+void RtApiAlsa :: abortStream()
+{
+ verifyStream();
+ if ( stream_.state == STREAM_STOPPED ) {
+ errorText_ = "RtApiAlsa::abortStream(): the stream is already stopped!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ stream_.state = STREAM_STOPPED;
+ MUTEX_LOCK( &stream_.mutex );
+
+ int result = 0;
+ AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
+ snd_pcm_t **handle = (snd_pcm_t **) apiInfo->handles;
+ if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
+ result = snd_pcm_drop( handle[0] );
+ if ( result < 0 ) {
+ errorStream_ << "RtApiAlsa::abortStream: error aborting output pcm device, " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ goto unlock;
+ }
+ }
+
+ if ( ( stream_.mode == INPUT || stream_.mode == DUPLEX ) && !apiInfo->synchronized ) {
+ result = snd_pcm_drop( handle[1] );
+ if ( result < 0 ) {
+ errorStream_ << "RtApiAlsa::abortStream: error aborting input pcm device, " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ goto unlock;
+ }
+ }
+
+ unlock:
+ apiInfo->runnable = false; // fixes high CPU usage when stopped
+ MUTEX_UNLOCK( &stream_.mutex );
+
+ if ( result >= 0 ) return;
+ error( RtAudioError::SYSTEM_ERROR );
+}
+
+void RtApiAlsa :: callbackEvent()
+{
+ AlsaHandle *apiInfo = (AlsaHandle *) stream_.apiHandle;
+ if ( stream_.state == STREAM_STOPPED ) {
+ MUTEX_LOCK( &stream_.mutex );
+ while ( !apiInfo->runnable )
+ pthread_cond_wait( &apiInfo->runnable_cv, &stream_.mutex );
+
+ if ( stream_.state != STREAM_RUNNING ) {
+ MUTEX_UNLOCK( &stream_.mutex );
+ return;
+ }
+ MUTEX_UNLOCK( &stream_.mutex );
+ }
+
+ if ( stream_.state == STREAM_CLOSED ) {
+ errorText_ = "RtApiAlsa::callbackEvent(): the stream is closed ... this shouldn't happen!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ int doStopStream = 0;
+ RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;
+ double streamTime = getStreamTime();
+ RtAudioStreamStatus status = 0;
+ if ( stream_.mode != INPUT && apiInfo->xrun[0] == true ) {
+ status |= RTAUDIO_OUTPUT_UNDERFLOW;
+ apiInfo->xrun[0] = false;
+ }
+ if ( stream_.mode != OUTPUT && apiInfo->xrun[1] == true ) {
+ status |= RTAUDIO_INPUT_OVERFLOW;
+ apiInfo->xrun[1] = false;
+ }
+ doStopStream = callback( stream_.userBuffer[0], stream_.userBuffer[1],
+ stream_.bufferSize, streamTime, status, stream_.callbackInfo.userData );
+
+ if ( doStopStream == 2 ) {
+ abortStream();
+ return;
+ }
+
+ MUTEX_LOCK( &stream_.mutex );
+
+ // The state might change while waiting on a mutex.
+ if ( stream_.state == STREAM_STOPPED ) goto unlock;
+
+ int result;
+ char *buffer;
+ int channels;
+ snd_pcm_t **handle;
+ snd_pcm_sframes_t frames;
+ RtAudioFormat format;
+ handle = (snd_pcm_t **) apiInfo->handles;
+
+ if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
+
+ // Setup parameters.
+ if ( stream_.doConvertBuffer[1] ) {
+ buffer = stream_.deviceBuffer;
+ channels = stream_.nDeviceChannels[1];
+ format = stream_.deviceFormat[1];
+ }
+ else {
+ buffer = stream_.userBuffer[1];
+ channels = stream_.nUserChannels[1];
+ format = stream_.userFormat;
+ }
+
+ // Read samples from device in interleaved/non-interleaved format.
+ if ( stream_.deviceInterleaved[1] )
+ result = snd_pcm_readi( handle[1], buffer, stream_.bufferSize );
+ else {
+ void *bufs[channels];
+ size_t offset = stream_.bufferSize * formatBytes( format );
+ for ( int i=0; i<channels; i++ )
+ bufs[i] = (void *) (buffer + (i * offset));
+ result = snd_pcm_readn( handle[1], bufs, stream_.bufferSize );
+ }
+
+ if ( result < (int) stream_.bufferSize ) {
+ // Either an error or overrun occured.
+ if ( result == -EPIPE ) {
+ snd_pcm_state_t state = snd_pcm_state( handle[1] );
+ if ( state == SND_PCM_STATE_XRUN ) {
+ apiInfo->xrun[1] = true;
+ result = snd_pcm_prepare( handle[1] );
+ if ( result < 0 ) {
+ errorStream_ << "RtApiAlsa::callbackEvent: error preparing device after overrun, " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ }
+ }
+ else {
+ errorStream_ << "RtApiAlsa::callbackEvent: error, current state is " << snd_pcm_state_name( state ) << ", " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ }
+ }
+ else {
+ errorStream_ << "RtApiAlsa::callbackEvent: audio read error, " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ }
+ error( RtAudioError::WARNING );
+ goto tryOutput;
+ }
+
+ // Do byte swapping if necessary.
+ if ( stream_.doByteSwap[1] )
+ byteSwapBuffer( buffer, stream_.bufferSize * channels, format );
+
+ // Do buffer conversion if necessary.
+ if ( stream_.doConvertBuffer[1] )
+ convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );
+
+ // Check stream latency
+ result = snd_pcm_delay( handle[1], &frames );
+ if ( result == 0 && frames > 0 ) stream_.latency[1] = frames;
+ }
+
+ tryOutput:
+
+ if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
+
+ // Setup parameters and do buffer conversion if necessary.
+ if ( stream_.doConvertBuffer[0] ) {
+ buffer = stream_.deviceBuffer;
+ convertBuffer( buffer, stream_.userBuffer[0], stream_.convertInfo[0] );
+ channels = stream_.nDeviceChannels[0];
+ format = stream_.deviceFormat[0];
+ }
+ else {
+ buffer = stream_.userBuffer[0];
+ channels = stream_.nUserChannels[0];
+ format = stream_.userFormat;
+ }
+
+ // Do byte swapping if necessary.
+ if ( stream_.doByteSwap[0] )
+ byteSwapBuffer(buffer, stream_.bufferSize * channels, format);
+
+ // Write samples to device in interleaved/non-interleaved format.
+ if ( stream_.deviceInterleaved[0] )
+ result = snd_pcm_writei( handle[0], buffer, stream_.bufferSize );
+ else {
+ void *bufs[channels];
+ size_t offset = stream_.bufferSize * formatBytes( format );
+ for ( int i=0; i<channels; i++ )
+ bufs[i] = (void *) (buffer + (i * offset));
+ result = snd_pcm_writen( handle[0], bufs, stream_.bufferSize );
+ }
+
+ if ( result < (int) stream_.bufferSize ) {
+ // Either an error or underrun occured.
+ if ( result == -EPIPE ) {
+ snd_pcm_state_t state = snd_pcm_state( handle[0] );
+ if ( state == SND_PCM_STATE_XRUN ) {
+ apiInfo->xrun[0] = true;
+ result = snd_pcm_prepare( handle[0] );
+ if ( result < 0 ) {
+ errorStream_ << "RtApiAlsa::callbackEvent: error preparing device after underrun, " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ }
+ else
+ errorText_ = "RtApiAlsa::callbackEvent: audio write error, underrun.";
+ }
+ else {
+ errorStream_ << "RtApiAlsa::callbackEvent: error, current state is " << snd_pcm_state_name( state ) << ", " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ }
+ }
+ else {
+ errorStream_ << "RtApiAlsa::callbackEvent: audio write error, " << snd_strerror( result ) << ".";
+ errorText_ = errorStream_.str();
+ }
+ error( RtAudioError::WARNING );
+ goto unlock;
+ }
+
+ // Check stream latency
+ result = snd_pcm_delay( handle[0], &frames );
+ if ( result == 0 && frames > 0 ) stream_.latency[0] = frames;
+ }
+
+ unlock:
+ MUTEX_UNLOCK( &stream_.mutex );
+
+ RtApi::tickStreamTime();
+ if ( doStopStream == 1 ) this->stopStream();
+}
+
+static void *alsaCallbackHandler( void *ptr )
+{
+ CallbackInfo *info = (CallbackInfo *) ptr;
+ RtApiAlsa *object = (RtApiAlsa *) info->object;
+ bool *isRunning = &info->isRunning;
+
+#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)
+ if ( &info->doRealtime ) {
+ pthread_t tID = pthread_self(); // ID of this thread
+ sched_param prio = { info->priority }; // scheduling priority of thread
+ pthread_setschedparam( tID, SCHED_RR, &prio );
+ }
+#endif
+
+ while ( *isRunning == true ) {
+ pthread_testcancel();
+ object->callbackEvent();
+ }
+
+ pthread_exit( NULL );
+}
+
+//******************** End of __LINUX_ALSA__ *********************//
+#endif
+
+#if defined(__LINUX_PULSE__)
+
+// Code written by Peter Meerwald, pmeerw@pmeerw.net
+// and Tristan Matthews.
+
+#include <pulse/error.h>
+#include <pulse/simple.h>
+#include <cstdio>
+
+static const unsigned int SUPPORTED_SAMPLERATES[] = { 8000, 16000, 22050, 32000,
+ 44100, 48000, 96000, 0};
+
+struct rtaudio_pa_format_mapping_t {
+ RtAudioFormat rtaudio_format;
+ pa_sample_format_t pa_format;
+};
+
+static const rtaudio_pa_format_mapping_t supported_sampleformats[] = {
+ {RTAUDIO_SINT16, PA_SAMPLE_S16LE},
+ {RTAUDIO_SINT32, PA_SAMPLE_S32LE},
+ {RTAUDIO_FLOAT32, PA_SAMPLE_FLOAT32LE},
+ {0, PA_SAMPLE_INVALID}};
+
+struct PulseAudioHandle {
+ pa_simple *s_play;
+ pa_simple *s_rec;
+ pthread_t thread;
+ pthread_cond_t runnable_cv;
+ bool runnable;
+ PulseAudioHandle() : s_play(0), s_rec(0), runnable(false) { }
+};
+
+RtApiPulse::~RtApiPulse()
+{
+ if ( stream_.state != STREAM_CLOSED )
+ closeStream();
+}
+
+unsigned int RtApiPulse::getDeviceCount( void )
+{
+ return 1;
+}
+
+RtAudio::DeviceInfo RtApiPulse::getDeviceInfo( unsigned int /*device*/ )
+{
+ RtAudio::DeviceInfo info;
+ info.probed = true;
+ info.name = "PulseAudio";
+ info.outputChannels = 2;
+ info.inputChannels = 2;
+ info.duplexChannels = 2;
+ info.isDefaultOutput = true;
+ info.isDefaultInput = true;
+
+ for ( const unsigned int *sr = SUPPORTED_SAMPLERATES; *sr; ++sr )
+ info.sampleRates.push_back( *sr );
+
+ info.preferredSampleRate = 48000;
+ info.nativeFormats = RTAUDIO_SINT16 | RTAUDIO_SINT32 | RTAUDIO_FLOAT32;
+
+ return info;
+}
+
+static void *pulseaudio_callback( void * user )
+{
+ CallbackInfo *cbi = static_cast<CallbackInfo *>( user );
+ RtApiPulse *context = static_cast<RtApiPulse *>( cbi->object );
+ volatile bool *isRunning = &cbi->isRunning;
+
+ while ( *isRunning ) {
+ pthread_testcancel();
+ context->callbackEvent();
+ }
+
+ pthread_exit( NULL );
+}
+
+void RtApiPulse::closeStream( void )
+{
+ PulseAudioHandle *pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );
+
+ stream_.callbackInfo.isRunning = false;
+ if ( pah ) {
+ MUTEX_LOCK( &stream_.mutex );
+ if ( stream_.state == STREAM_STOPPED ) {
+ pah->runnable = true;
+ pthread_cond_signal( &pah->runnable_cv );
+ }
+ MUTEX_UNLOCK( &stream_.mutex );
+
+ pthread_join( pah->thread, 0 );
+ if ( pah->s_play ) {
+ pa_simple_flush( pah->s_play, NULL );
+ pa_simple_free( pah->s_play );
+ }
+ if ( pah->s_rec )
+ pa_simple_free( pah->s_rec );
+
+ pthread_cond_destroy( &pah->runnable_cv );
+ delete pah;
+ stream_.apiHandle = 0;
+ }
+
+ if ( stream_.userBuffer[0] ) {
+ free( stream_.userBuffer[0] );
+ stream_.userBuffer[0] = 0;
+ }
+ if ( stream_.userBuffer[1] ) {
+ free( stream_.userBuffer[1] );
+ stream_.userBuffer[1] = 0;
+ }
+
+ stream_.state = STREAM_CLOSED;
+ stream_.mode = UNINITIALIZED;
+}
+
+void RtApiPulse::callbackEvent( void )
+{
+ PulseAudioHandle *pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );
+
+ if ( stream_.state == STREAM_STOPPED ) {
+ MUTEX_LOCK( &stream_.mutex );
+ while ( !pah->runnable )
+ pthread_cond_wait( &pah->runnable_cv, &stream_.mutex );
+
+ if ( stream_.state != STREAM_RUNNING ) {
+ MUTEX_UNLOCK( &stream_.mutex );
+ return;
+ }
+ MUTEX_UNLOCK( &stream_.mutex );
+ }
+
+ if ( stream_.state == STREAM_CLOSED ) {
+ errorText_ = "RtApiPulse::callbackEvent(): the stream is closed ... "
+ "this shouldn't happen!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;
+ double streamTime = getStreamTime();
+ RtAudioStreamStatus status = 0;
+ int doStopStream = callback( stream_.userBuffer[OUTPUT], stream_.userBuffer[INPUT],
+ stream_.bufferSize, streamTime, status,
+ stream_.callbackInfo.userData );
+
+ if ( doStopStream == 2 ) {
+ abortStream();
+ return;
+ }
+
+ MUTEX_LOCK( &stream_.mutex );
+ void *pulse_in = stream_.doConvertBuffer[INPUT] ? stream_.deviceBuffer : stream_.userBuffer[INPUT];
+ void *pulse_out = stream_.doConvertBuffer[OUTPUT] ? stream_.deviceBuffer : stream_.userBuffer[OUTPUT];
+
+ if ( stream_.state != STREAM_RUNNING )
+ goto unlock;
+
+ int pa_error;
+ size_t bytes;
+ if (stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
+ if ( stream_.doConvertBuffer[OUTPUT] ) {
+ convertBuffer( stream_.deviceBuffer,
+ stream_.userBuffer[OUTPUT],
+ stream_.convertInfo[OUTPUT] );
+ bytes = stream_.nDeviceChannels[OUTPUT] * stream_.bufferSize *
+ formatBytes( stream_.deviceFormat[OUTPUT] );
+ } else
+ bytes = stream_.nUserChannels[OUTPUT] * stream_.bufferSize *
+ formatBytes( stream_.userFormat );
+
+ if ( pa_simple_write( pah->s_play, pulse_out, bytes, &pa_error ) < 0 ) {
+ errorStream_ << "RtApiPulse::callbackEvent: audio write error, " <<
+ pa_strerror( pa_error ) << ".";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ }
+ }
+
+ if ( stream_.mode == INPUT || stream_.mode == DUPLEX) {
+ if ( stream_.doConvertBuffer[INPUT] )
+ bytes = stream_.nDeviceChannels[INPUT] * stream_.bufferSize *
+ formatBytes( stream_.deviceFormat[INPUT] );
+ else
+ bytes = stream_.nUserChannels[INPUT] * stream_.bufferSize *
+ formatBytes( stream_.userFormat );
+
+ if ( pa_simple_read( pah->s_rec, pulse_in, bytes, &pa_error ) < 0 ) {
+ errorStream_ << "RtApiPulse::callbackEvent: audio read error, " <<
+ pa_strerror( pa_error ) << ".";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ }
+ if ( stream_.doConvertBuffer[INPUT] ) {
+ convertBuffer( stream_.userBuffer[INPUT],
+ stream_.deviceBuffer,
+ stream_.convertInfo[INPUT] );
+ }
+ }
+
+ unlock:
+ MUTEX_UNLOCK( &stream_.mutex );
+ RtApi::tickStreamTime();
+
+ if ( doStopStream == 1 )
+ stopStream();
+}
+
+void RtApiPulse::startStream( void )
+{
+ PulseAudioHandle *pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );
+
+ if ( stream_.state == STREAM_CLOSED ) {
+ errorText_ = "RtApiPulse::startStream(): the stream is not open!";
+ error( RtAudioError::INVALID_USE );
+ return;
+ }
+ if ( stream_.state == STREAM_RUNNING ) {
+ errorText_ = "RtApiPulse::startStream(): the stream is already running!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ MUTEX_LOCK( &stream_.mutex );
+
+ stream_.state = STREAM_RUNNING;
+
+ pah->runnable = true;
+ pthread_cond_signal( &pah->runnable_cv );
+ MUTEX_UNLOCK( &stream_.mutex );
+}
+
+void RtApiPulse::stopStream( void )
+{
+ PulseAudioHandle *pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );
+
+ if ( stream_.state == STREAM_CLOSED ) {
+ errorText_ = "RtApiPulse::stopStream(): the stream is not open!";
+ error( RtAudioError::INVALID_USE );
+ return;
+ }
+ if ( stream_.state == STREAM_STOPPED ) {
+ errorText_ = "RtApiPulse::stopStream(): the stream is already stopped!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ stream_.state = STREAM_STOPPED;
+ MUTEX_LOCK( &stream_.mutex );
+
+ if ( pah && pah->s_play ) {
+ int pa_error;
+ if ( pa_simple_drain( pah->s_play, &pa_error ) < 0 ) {
+ errorStream_ << "RtApiPulse::stopStream: error draining output device, " <<
+ pa_strerror( pa_error ) << ".";
+ errorText_ = errorStream_.str();
+ MUTEX_UNLOCK( &stream_.mutex );
+ error( RtAudioError::SYSTEM_ERROR );
+ return;
+ }
+ }
+
+ stream_.state = STREAM_STOPPED;
+ MUTEX_UNLOCK( &stream_.mutex );
+}
+
+void RtApiPulse::abortStream( void )
+{
+ PulseAudioHandle *pah = static_cast<PulseAudioHandle*>( stream_.apiHandle );
+
+ if ( stream_.state == STREAM_CLOSED ) {
+ errorText_ = "RtApiPulse::abortStream(): the stream is not open!";
+ error( RtAudioError::INVALID_USE );
+ return;
+ }
+ if ( stream_.state == STREAM_STOPPED ) {
+ errorText_ = "RtApiPulse::abortStream(): the stream is already stopped!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ stream_.state = STREAM_STOPPED;
+ MUTEX_LOCK( &stream_.mutex );
+
+ if ( pah && pah->s_play ) {
+ int pa_error;
+ if ( pa_simple_flush( pah->s_play, &pa_error ) < 0 ) {
+ errorStream_ << "RtApiPulse::abortStream: error flushing output device, " <<
+ pa_strerror( pa_error ) << ".";
+ errorText_ = errorStream_.str();
+ MUTEX_UNLOCK( &stream_.mutex );
+ error( RtAudioError::SYSTEM_ERROR );
+ return;
+ }
+ }
+
+ stream_.state = STREAM_STOPPED;
+ MUTEX_UNLOCK( &stream_.mutex );
+}
+
+bool RtApiPulse::probeDeviceOpen( unsigned int device, StreamMode mode,
+ unsigned int channels, unsigned int firstChannel,
+ unsigned int sampleRate, RtAudioFormat format,
+ unsigned int *bufferSize, RtAudio::StreamOptions *options )
+{
+ PulseAudioHandle *pah = 0;
+ unsigned long bufferBytes = 0;
+ pa_sample_spec ss;
+
+ if ( device != 0 ) return false;
+ if ( mode != INPUT && mode != OUTPUT ) return false;
+ if ( channels != 1 && channels != 2 ) {
+ errorText_ = "RtApiPulse::probeDeviceOpen: unsupported number of channels.";
+ return false;
+ }
+ ss.channels = channels;
+
+ if ( firstChannel != 0 ) return false;
+
+ bool sr_found = false;
+ for ( const unsigned int *sr = SUPPORTED_SAMPLERATES; *sr; ++sr ) {
+ if ( sampleRate == *sr ) {
+ sr_found = true;
+ stream_.sampleRate = sampleRate;
+ ss.rate = sampleRate;
+ break;
+ }
+ }
+ if ( !sr_found ) {
+ errorText_ = "RtApiPulse::probeDeviceOpen: unsupported sample rate.";
+ return false;
+ }
+
+ bool sf_found = 0;
+ for ( const rtaudio_pa_format_mapping_t *sf = supported_sampleformats;
+ sf->rtaudio_format && sf->pa_format != PA_SAMPLE_INVALID; ++sf ) {
+ if ( format == sf->rtaudio_format ) {
+ sf_found = true;
+ stream_.userFormat = sf->rtaudio_format;
+ stream_.deviceFormat[mode] = stream_.userFormat;
+ ss.format = sf->pa_format;
+ break;
+ }
+ }
+ if ( !sf_found ) { // Use internal data format conversion.
+ stream_.userFormat = format;
+ stream_.deviceFormat[mode] = RTAUDIO_FLOAT32;
+ ss.format = PA_SAMPLE_FLOAT32LE;
+ }
+
+ // Set other stream parameters.
+ if ( options && options->flags & RTAUDIO_NONINTERLEAVED ) stream_.userInterleaved = false;
+ else stream_.userInterleaved = true;
+ stream_.deviceInterleaved[mode] = true;
+ stream_.nBuffers = 1;
+ stream_.doByteSwap[mode] = false;
+ stream_.nUserChannels[mode] = channels;
+ stream_.nDeviceChannels[mode] = channels + firstChannel;
+ stream_.channelOffset[mode] = 0;
+ std::string streamName = "RtAudio";
+
+ // Set flags for buffer conversion.
+ stream_.doConvertBuffer[mode] = false;
+ if ( stream_.userFormat != stream_.deviceFormat[mode] )
+ stream_.doConvertBuffer[mode] = true;
+ if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] )
+ stream_.doConvertBuffer[mode] = true;
+
+ // Allocate necessary internal buffers.
+ bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
+ stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );
+ if ( stream_.userBuffer[mode] == NULL ) {
+ errorText_ = "RtApiPulse::probeDeviceOpen: error allocating user buffer memory.";
+ goto error;
+ }
+ stream_.bufferSize = *bufferSize;
+
+ if ( stream_.doConvertBuffer[mode] ) {
+
+ bool makeBuffer = true;
+ bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );
+ if ( mode == INPUT ) {
+ if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
+ unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );
+ if ( bufferBytes <= bytesOut ) makeBuffer = false;
+ }
+ }
+
+ if ( makeBuffer ) {
+ bufferBytes *= *bufferSize;
+ if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );
+ stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );
+ if ( stream_.deviceBuffer == NULL ) {
+ errorText_ = "RtApiPulse::probeDeviceOpen: error allocating device buffer memory.";
+ goto error;
+ }
+ }
+ }
+
+ stream_.device[mode] = device;
+
+ // Setup the buffer conversion information structure.
+ if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel );
+
+ if ( !stream_.apiHandle ) {
+ PulseAudioHandle *pah = new PulseAudioHandle;
+ if ( !pah ) {
+ errorText_ = "RtApiPulse::probeDeviceOpen: error allocating memory for handle.";
+ goto error;
+ }
+
+ stream_.apiHandle = pah;
+ if ( pthread_cond_init( &pah->runnable_cv, NULL ) != 0 ) {
+ errorText_ = "RtApiPulse::probeDeviceOpen: error creating condition variable.";
+ goto error;
+ }
+ }
+ pah = static_cast<PulseAudioHandle *>( stream_.apiHandle );
+
+ int error;
+ if ( options && !options->streamName.empty() ) streamName = options->streamName;
+ switch ( mode ) {
+ case INPUT:
+ pa_buffer_attr buffer_attr;
+ buffer_attr.fragsize = bufferBytes;
+ buffer_attr.maxlength = -1;
+
+ pah->s_rec = pa_simple_new( NULL, streamName.c_str(), PA_STREAM_RECORD, NULL, "Record", &ss, NULL, &buffer_attr, &error );
+ if ( !pah->s_rec ) {
+ errorText_ = "RtApiPulse::probeDeviceOpen: error connecting input to PulseAudio server.";
+ goto error;
+ }
+ break;
+ case OUTPUT:
+ pah->s_play = pa_simple_new( NULL, "RtAudio", PA_STREAM_PLAYBACK, NULL, "Playback", &ss, NULL, NULL, &error );
+ if ( !pah->s_play ) {
+ errorText_ = "RtApiPulse::probeDeviceOpen: error connecting output to PulseAudio server.";
+ goto error;
+ }
+ break;
+ default:
+ goto error;
+ }
+
+ if ( stream_.mode == UNINITIALIZED )
+ stream_.mode = mode;
+ else if ( stream_.mode == mode )
+ goto error;
+ else
+ stream_.mode = DUPLEX;
+
+ if ( !stream_.callbackInfo.isRunning ) {
+ stream_.callbackInfo.object = this;
+ stream_.callbackInfo.isRunning = true;
+ if ( pthread_create( &pah->thread, NULL, pulseaudio_callback, (void *)&stream_.callbackInfo) != 0 ) {
+ errorText_ = "RtApiPulse::probeDeviceOpen: error creating thread.";
+ goto error;
+ }
+ }
+
+ stream_.state = STREAM_STOPPED;
+ return true;
+
+ error:
+ if ( pah && stream_.callbackInfo.isRunning ) {
+ pthread_cond_destroy( &pah->runnable_cv );
+ delete pah;
+ stream_.apiHandle = 0;
+ }
+
+ for ( int i=0; i<2; i++ ) {
+ if ( stream_.userBuffer[i] ) {
+ free( stream_.userBuffer[i] );
+ stream_.userBuffer[i] = 0;
+ }
+ }
+
+ if ( stream_.deviceBuffer ) {
+ free( stream_.deviceBuffer );
+ stream_.deviceBuffer = 0;
+ }
+
+ return FAILURE;
+}
+
+//******************** End of __LINUX_PULSE__ *********************//
+#endif
+
+#if defined(__LINUX_OSS__)
+
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/soundcard.h>
+#include <errno.h>
+#include <math.h>
+
+static void *ossCallbackHandler(void * ptr);
+
+// A structure to hold various information related to the OSS API
+// implementation.
+struct OssHandle {
+ int id[2]; // device ids
+ bool xrun[2];
+ bool triggered;
+ pthread_cond_t runnable;
+
+ OssHandle()
+ :triggered(false) { id[0] = 0; id[1] = 0; xrun[0] = false; xrun[1] = false; }
+};
+
+RtApiOss :: RtApiOss()
+{
+ // Nothing to do here.
+}
+
+RtApiOss :: ~RtApiOss()
+{
+ if ( stream_.state != STREAM_CLOSED ) closeStream();
+}
+
+unsigned int RtApiOss :: getDeviceCount( void )
+{
+ int mixerfd = open( "/dev/mixer", O_RDWR, 0 );
+ if ( mixerfd == -1 ) {
+ errorText_ = "RtApiOss::getDeviceCount: error opening '/dev/mixer'.";
+ error( RtAudioError::WARNING );
+ return 0;
+ }
+
+ oss_sysinfo sysinfo;
+ if ( ioctl( mixerfd, SNDCTL_SYSINFO, &sysinfo ) == -1 ) {
+ close( mixerfd );
+ errorText_ = "RtApiOss::getDeviceCount: error getting sysinfo, OSS version >= 4.0 is required.";
+ error( RtAudioError::WARNING );
+ return 0;
+ }
+
+ close( mixerfd );
+ return sysinfo.numaudios;
+}
+
+RtAudio::DeviceInfo RtApiOss :: getDeviceInfo( unsigned int device )
+{
+ RtAudio::DeviceInfo info;
+ info.probed = false;
+
+ int mixerfd = open( "/dev/mixer", O_RDWR, 0 );
+ if ( mixerfd == -1 ) {
+ errorText_ = "RtApiOss::getDeviceInfo: error opening '/dev/mixer'.";
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ oss_sysinfo sysinfo;
+ int result = ioctl( mixerfd, SNDCTL_SYSINFO, &sysinfo );
+ if ( result == -1 ) {
+ close( mixerfd );
+ errorText_ = "RtApiOss::getDeviceInfo: error getting sysinfo, OSS version >= 4.0 is required.";
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ unsigned nDevices = sysinfo.numaudios;
+ if ( nDevices == 0 ) {
+ close( mixerfd );
+ errorText_ = "RtApiOss::getDeviceInfo: no devices found!";
+ error( RtAudioError::INVALID_USE );
+ return info;
+ }
+
+ if ( device >= nDevices ) {
+ close( mixerfd );
+ errorText_ = "RtApiOss::getDeviceInfo: device ID is invalid!";
+ error( RtAudioError::INVALID_USE );
+ return info;
+ }
+
+ oss_audioinfo ainfo;
+ ainfo.dev = device;
+ result = ioctl( mixerfd, SNDCTL_AUDIOINFO, &ainfo );
+ close( mixerfd );
+ if ( result == -1 ) {
+ errorStream_ << "RtApiOss::getDeviceInfo: error getting device (" << ainfo.name << ") info.";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ // Probe channels
+ if ( ainfo.caps & PCM_CAP_OUTPUT ) info.outputChannels = ainfo.max_channels;
+ if ( ainfo.caps & PCM_CAP_INPUT ) info.inputChannels = ainfo.max_channels;
+ if ( ainfo.caps & PCM_CAP_DUPLEX ) {
+ if ( info.outputChannels > 0 && info.inputChannels > 0 && ainfo.caps & PCM_CAP_DUPLEX )
+ info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;
+ }
+
+ // Probe data formats ... do for input
+ unsigned long mask = ainfo.iformats;
+ if ( mask & AFMT_S16_LE || mask & AFMT_S16_BE )
+ info.nativeFormats |= RTAUDIO_SINT16;
+ if ( mask & AFMT_S8 )
+ info.nativeFormats |= RTAUDIO_SINT8;
+ if ( mask & AFMT_S32_LE || mask & AFMT_S32_BE )
+ info.nativeFormats |= RTAUDIO_SINT32;
+ if ( mask & AFMT_FLOAT )
+ info.nativeFormats |= RTAUDIO_FLOAT32;
+ if ( mask & AFMT_S24_LE || mask & AFMT_S24_BE )
+ info.nativeFormats |= RTAUDIO_SINT24;
+
+ // Check that we have at least one supported format
+ if ( info.nativeFormats == 0 ) {
+ errorStream_ << "RtApiOss::getDeviceInfo: device (" << ainfo.name << ") data format not supported by RtAudio.";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ return info;
+ }
+
+ // Probe the supported sample rates.
+ info.sampleRates.clear();
+ if ( ainfo.nrates ) {
+ for ( unsigned int i=0; i<ainfo.nrates; i++ ) {
+ for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {
+ if ( ainfo.rates[i] == SAMPLE_RATES[k] ) {
+ info.sampleRates.push_back( SAMPLE_RATES[k] );
+
+ if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) )
+ info.preferredSampleRate = SAMPLE_RATES[k];
+
+ break;
+ }
+ }
+ }
+ }
+ else {
+ // Check min and max rate values;
+ for ( unsigned int k=0; k<MAX_SAMPLE_RATES; k++ ) {
+ if ( ainfo.min_rate <= (int) SAMPLE_RATES[k] && ainfo.max_rate >= (int) SAMPLE_RATES[k] ) {
+ info.sampleRates.push_back( SAMPLE_RATES[k] );
+
+ if ( !info.preferredSampleRate || ( SAMPLE_RATES[k] <= 48000 && SAMPLE_RATES[k] > info.preferredSampleRate ) )
+ info.preferredSampleRate = SAMPLE_RATES[k];
+ }
+ }
+ }
+
+ if ( info.sampleRates.size() == 0 ) {
+ errorStream_ << "RtApiOss::getDeviceInfo: no supported sample rates found for device (" << ainfo.name << ").";
+ errorText_ = errorStream_.str();
+ error( RtAudioError::WARNING );
+ }
+ else {
+ info.probed = true;
+ info.name = ainfo.name;
+ }
+
+ return info;
+}
+
+
+bool RtApiOss :: probeDeviceOpen( unsigned int device, StreamMode mode, unsigned int channels,
+ unsigned int firstChannel, unsigned int sampleRate,
+ RtAudioFormat format, unsigned int *bufferSize,
+ RtAudio::StreamOptions *options )
+{
+ int mixerfd = open( "/dev/mixer", O_RDWR, 0 );
+ if ( mixerfd == -1 ) {
+ errorText_ = "RtApiOss::probeDeviceOpen: error opening '/dev/mixer'.";
+ return FAILURE;
+ }
+
+ oss_sysinfo sysinfo;
+ int result = ioctl( mixerfd, SNDCTL_SYSINFO, &sysinfo );
+ if ( result == -1 ) {
+ close( mixerfd );
+ errorText_ = "RtApiOss::probeDeviceOpen: error getting sysinfo, OSS version >= 4.0 is required.";
+ return FAILURE;
+ }
+
+ unsigned nDevices = sysinfo.numaudios;
+ if ( nDevices == 0 ) {
+ // This should not happen because a check is made before this function is called.
+ close( mixerfd );
+ errorText_ = "RtApiOss::probeDeviceOpen: no devices found!";
+ return FAILURE;
+ }
+
+ if ( device >= nDevices ) {
+ // This should not happen because a check is made before this function is called.
+ close( mixerfd );
+ errorText_ = "RtApiOss::probeDeviceOpen: device ID is invalid!";
+ return FAILURE;
+ }
+
+ oss_audioinfo ainfo;
+ ainfo.dev = device;
+ result = ioctl( mixerfd, SNDCTL_AUDIOINFO, &ainfo );
+ close( mixerfd );
+ if ( result == -1 ) {
+ errorStream_ << "RtApiOss::getDeviceInfo: error getting device (" << ainfo.name << ") info.";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Check if device supports input or output
+ if ( ( mode == OUTPUT && !( ainfo.caps & PCM_CAP_OUTPUT ) ) ||
+ ( mode == INPUT && !( ainfo.caps & PCM_CAP_INPUT ) ) ) {
+ if ( mode == OUTPUT )
+ errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support output.";
+ else
+ errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support input.";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ int flags = 0;
+ OssHandle *handle = (OssHandle *) stream_.apiHandle;
+ if ( mode == OUTPUT )
+ flags |= O_WRONLY;
+ else { // mode == INPUT
+ if (stream_.mode == OUTPUT && stream_.device[0] == device) {
+ // We just set the same device for playback ... close and reopen for duplex (OSS only).
+ close( handle->id[0] );
+ handle->id[0] = 0;
+ if ( !( ainfo.caps & PCM_CAP_DUPLEX ) ) {
+ errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support duplex mode.";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+ // Check that the number previously set channels is the same.
+ if ( stream_.nUserChannels[0] != channels ) {
+ errorStream_ << "RtApiOss::probeDeviceOpen: input/output channels must be equal for OSS duplex device (" << ainfo.name << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+ flags |= O_RDWR;
+ }
+ else
+ flags |= O_RDONLY;
+ }
+
+ // Set exclusive access if specified.
+ if ( options && options->flags & RTAUDIO_HOG_DEVICE ) flags |= O_EXCL;
+
+ // Try to open the device.
+ int fd;
+ fd = open( ainfo.devnode, flags, 0 );
+ if ( fd == -1 ) {
+ if ( errno == EBUSY )
+ errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") is busy.";
+ else
+ errorStream_ << "RtApiOss::probeDeviceOpen: error opening device (" << ainfo.name << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // For duplex operation, specifically set this mode (this doesn't seem to work).
+ /*
+ if ( flags | O_RDWR ) {
+ result = ioctl( fd, SNDCTL_DSP_SETDUPLEX, NULL );
+ if ( result == -1) {
+ errorStream_ << "RtApiOss::probeDeviceOpen: error setting duplex mode for device (" << ainfo.name << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+ }
+ */
+
+ // Check the device channel support.
+ stream_.nUserChannels[mode] = channels;
+ if ( ainfo.max_channels < (int)(channels + firstChannel) ) {
+ close( fd );
+ errorStream_ << "RtApiOss::probeDeviceOpen: the device (" << ainfo.name << ") does not support requested channel parameters.";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Set the number of channels.
+ int deviceChannels = channels + firstChannel;
+ result = ioctl( fd, SNDCTL_DSP_CHANNELS, &deviceChannels );
+ if ( result == -1 || deviceChannels < (int)(channels + firstChannel) ) {
+ close( fd );
+ errorStream_ << "RtApiOss::probeDeviceOpen: error setting channel parameters on device (" << ainfo.name << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+ stream_.nDeviceChannels[mode] = deviceChannels;
+
+ // Get the data format mask
+ int mask;
+ result = ioctl( fd, SNDCTL_DSP_GETFMTS, &mask );
+ if ( result == -1 ) {
+ close( fd );
+ errorStream_ << "RtApiOss::probeDeviceOpen: error getting device (" << ainfo.name << ") data formats.";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Determine how to set the device format.
+ stream_.userFormat = format;
+ int deviceFormat = -1;
+ stream_.doByteSwap[mode] = false;
+ if ( format == RTAUDIO_SINT8 ) {
+ if ( mask & AFMT_S8 ) {
+ deviceFormat = AFMT_S8;
+ stream_.deviceFormat[mode] = RTAUDIO_SINT8;
+ }
+ }
+ else if ( format == RTAUDIO_SINT16 ) {
+ if ( mask & AFMT_S16_NE ) {
+ deviceFormat = AFMT_S16_NE;
+ stream_.deviceFormat[mode] = RTAUDIO_SINT16;
+ }
+ else if ( mask & AFMT_S16_OE ) {
+ deviceFormat = AFMT_S16_OE;
+ stream_.deviceFormat[mode] = RTAUDIO_SINT16;
+ stream_.doByteSwap[mode] = true;
+ }
+ }
+ else if ( format == RTAUDIO_SINT24 ) {
+ if ( mask & AFMT_S24_NE ) {
+ deviceFormat = AFMT_S24_NE;
+ stream_.deviceFormat[mode] = RTAUDIO_SINT24;
+ }
+ else if ( mask & AFMT_S24_OE ) {
+ deviceFormat = AFMT_S24_OE;
+ stream_.deviceFormat[mode] = RTAUDIO_SINT24;
+ stream_.doByteSwap[mode] = true;
+ }
+ }
+ else if ( format == RTAUDIO_SINT32 ) {
+ if ( mask & AFMT_S32_NE ) {
+ deviceFormat = AFMT_S32_NE;
+ stream_.deviceFormat[mode] = RTAUDIO_SINT32;
+ }
+ else if ( mask & AFMT_S32_OE ) {
+ deviceFormat = AFMT_S32_OE;
+ stream_.deviceFormat[mode] = RTAUDIO_SINT32;
+ stream_.doByteSwap[mode] = true;
+ }
+ }
+
+ if ( deviceFormat == -1 ) {
+ // The user requested format is not natively supported by the device.
+ if ( mask & AFMT_S16_NE ) {
+ deviceFormat = AFMT_S16_NE;
+ stream_.deviceFormat[mode] = RTAUDIO_SINT16;
+ }
+ else if ( mask & AFMT_S32_NE ) {
+ deviceFormat = AFMT_S32_NE;
+ stream_.deviceFormat[mode] = RTAUDIO_SINT32;
+ }
+ else if ( mask & AFMT_S24_NE ) {
+ deviceFormat = AFMT_S24_NE;
+ stream_.deviceFormat[mode] = RTAUDIO_SINT24;
+ }
+ else if ( mask & AFMT_S16_OE ) {
+ deviceFormat = AFMT_S16_OE;
+ stream_.deviceFormat[mode] = RTAUDIO_SINT16;
+ stream_.doByteSwap[mode] = true;
+ }
+ else if ( mask & AFMT_S32_OE ) {
+ deviceFormat = AFMT_S32_OE;
+ stream_.deviceFormat[mode] = RTAUDIO_SINT32;
+ stream_.doByteSwap[mode] = true;
+ }
+ else if ( mask & AFMT_S24_OE ) {
+ deviceFormat = AFMT_S24_OE;
+ stream_.deviceFormat[mode] = RTAUDIO_SINT24;
+ stream_.doByteSwap[mode] = true;
+ }
+ else if ( mask & AFMT_S8) {
+ deviceFormat = AFMT_S8;
+ stream_.deviceFormat[mode] = RTAUDIO_SINT8;
+ }
+ }
+
+ if ( stream_.deviceFormat[mode] == 0 ) {
+ // This really shouldn't happen ...
+ close( fd );
+ errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") data format not supported by RtAudio.";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Set the data format.
+ int temp = deviceFormat;
+ result = ioctl( fd, SNDCTL_DSP_SETFMT, &deviceFormat );
+ if ( result == -1 || deviceFormat != temp ) {
+ close( fd );
+ errorStream_ << "RtApiOss::probeDeviceOpen: error setting data format on device (" << ainfo.name << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Attempt to set the buffer size. According to OSS, the minimum
+ // number of buffers is two. The supposed minimum buffer size is 16
+ // bytes, so that will be our lower bound. The argument to this
+ // call is in the form 0xMMMMSSSS (hex), where the buffer size (in
+ // bytes) is given as 2^SSSS and the number of buffers as 2^MMMM.
+ // We'll check the actual value used near the end of the setup
+ // procedure.
+ int ossBufferBytes = *bufferSize * formatBytes( stream_.deviceFormat[mode] ) * deviceChannels;
+ if ( ossBufferBytes < 16 ) ossBufferBytes = 16;
+ int buffers = 0;
+ if ( options ) buffers = options->numberOfBuffers;
+ if ( options && options->flags & RTAUDIO_MINIMIZE_LATENCY ) buffers = 2;
+ if ( buffers < 2 ) buffers = 3;
+ temp = ((int) buffers << 16) + (int)( log10( (double)ossBufferBytes ) / log10( 2.0 ) );
+ result = ioctl( fd, SNDCTL_DSP_SETFRAGMENT, &temp );
+ if ( result == -1 ) {
+ close( fd );
+ errorStream_ << "RtApiOss::probeDeviceOpen: error setting buffer size on device (" << ainfo.name << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+ stream_.nBuffers = buffers;
+
+ // Save buffer size (in sample frames).
+ *bufferSize = ossBufferBytes / ( formatBytes(stream_.deviceFormat[mode]) * deviceChannels );
+ stream_.bufferSize = *bufferSize;
+
+ // Set the sample rate.
+ int srate = sampleRate;
+ result = ioctl( fd, SNDCTL_DSP_SPEED, &srate );
+ if ( result == -1 ) {
+ close( fd );
+ errorStream_ << "RtApiOss::probeDeviceOpen: error setting sample rate (" << sampleRate << ") on device (" << ainfo.name << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+
+ // Verify the sample rate setup worked.
+ if ( abs( srate - sampleRate ) > 100 ) {
+ close( fd );
+ errorStream_ << "RtApiOss::probeDeviceOpen: device (" << ainfo.name << ") does not support sample rate (" << sampleRate << ").";
+ errorText_ = errorStream_.str();
+ return FAILURE;
+ }
+ stream_.sampleRate = sampleRate;
+
+ if ( mode == INPUT && stream_.mode == OUTPUT && stream_.device[0] == device) {
+ // We're doing duplex setup here.
+ stream_.deviceFormat[0] = stream_.deviceFormat[1];
+ stream_.nDeviceChannels[0] = deviceChannels;
+ }
+
+ // Set interleaving parameters.
+ stream_.userInterleaved = true;
+ stream_.deviceInterleaved[mode] = true;
+ if ( options && options->flags & RTAUDIO_NONINTERLEAVED )
+ stream_.userInterleaved = false;
+
+ // Set flags for buffer conversion
+ stream_.doConvertBuffer[mode] = false;
+ if ( stream_.userFormat != stream_.deviceFormat[mode] )
+ stream_.doConvertBuffer[mode] = true;
+ if ( stream_.nUserChannels[mode] < stream_.nDeviceChannels[mode] )
+ stream_.doConvertBuffer[mode] = true;
+ if ( stream_.userInterleaved != stream_.deviceInterleaved[mode] &&
+ stream_.nUserChannels[mode] > 1 )
+ stream_.doConvertBuffer[mode] = true;
+
+ // Allocate the stream handles if necessary and then save.
+ if ( stream_.apiHandle == 0 ) {
+ try {
+ handle = new OssHandle;
+ }
+ catch ( std::bad_alloc& ) {
+ errorText_ = "RtApiOss::probeDeviceOpen: error allocating OssHandle memory.";
+ goto error;
+ }
+
+ if ( pthread_cond_init( &handle->runnable, NULL ) ) {
+ errorText_ = "RtApiOss::probeDeviceOpen: error initializing pthread condition variable.";
+ goto error;
+ }
+
+ stream_.apiHandle = (void *) handle;
+ }
+ else {
+ handle = (OssHandle *) stream_.apiHandle;
+ }
+ handle->id[mode] = fd;
+
+ // Allocate necessary internal buffers.
+ unsigned long bufferBytes;
+ bufferBytes = stream_.nUserChannels[mode] * *bufferSize * formatBytes( stream_.userFormat );
+ stream_.userBuffer[mode] = (char *) calloc( bufferBytes, 1 );
+ if ( stream_.userBuffer[mode] == NULL ) {
+ errorText_ = "RtApiOss::probeDeviceOpen: error allocating user buffer memory.";
+ goto error;
+ }
+
+ if ( stream_.doConvertBuffer[mode] ) {
+
+ bool makeBuffer = true;
+ bufferBytes = stream_.nDeviceChannels[mode] * formatBytes( stream_.deviceFormat[mode] );
+ if ( mode == INPUT ) {
+ if ( stream_.mode == OUTPUT && stream_.deviceBuffer ) {
+ unsigned long bytesOut = stream_.nDeviceChannels[0] * formatBytes( stream_.deviceFormat[0] );
+ if ( bufferBytes <= bytesOut ) makeBuffer = false;
+ }
+ }
+
+ if ( makeBuffer ) {
+ bufferBytes *= *bufferSize;
+ if ( stream_.deviceBuffer ) free( stream_.deviceBuffer );
+ stream_.deviceBuffer = (char *) calloc( bufferBytes, 1 );
+ if ( stream_.deviceBuffer == NULL ) {
+ errorText_ = "RtApiOss::probeDeviceOpen: error allocating device buffer memory.";
+ goto error;
+ }
+ }
+ }
+
+ stream_.device[mode] = device;
+ stream_.state = STREAM_STOPPED;
+
+ // Setup the buffer conversion information structure.
+ if ( stream_.doConvertBuffer[mode] ) setConvertInfo( mode, firstChannel );
+
+ // Setup thread if necessary.
+ if ( stream_.mode == OUTPUT && mode == INPUT ) {
+ // We had already set up an output stream.
+ stream_.mode = DUPLEX;
+ if ( stream_.device[0] == device ) handle->id[0] = fd;
+ }
+ else {
+ stream_.mode = mode;
+
+ // Setup callback thread.
+ stream_.callbackInfo.object = (void *) this;
+
+ // Set the thread attributes for joinable and realtime scheduling
+ // priority. The higher priority will only take affect if the
+ // program is run as root or suid.
+ pthread_attr_t attr;
+ pthread_attr_init( &attr );
+ pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE );
+#ifdef SCHED_RR // Undefined with some OSes (eg: NetBSD 1.6.x with GNU Pthread)
+ if ( options && options->flags & RTAUDIO_SCHEDULE_REALTIME ) {
+ struct sched_param param;
+ int priority = options->priority;
+ int min = sched_get_priority_min( SCHED_RR );
+ int max = sched_get_priority_max( SCHED_RR );
+ if ( priority < min ) priority = min;
+ else if ( priority > max ) priority = max;
+ param.sched_priority = priority;
+ pthread_attr_setschedparam( &attr, &param );
+ pthread_attr_setschedpolicy( &attr, SCHED_RR );
+ }
+ else
+ pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
+#else
+ pthread_attr_setschedpolicy( &attr, SCHED_OTHER );
+#endif
+
+ stream_.callbackInfo.isRunning = true;
+ result = pthread_create( &stream_.callbackInfo.thread, &attr, ossCallbackHandler, &stream_.callbackInfo );
+ pthread_attr_destroy( &attr );
+ if ( result ) {
+ stream_.callbackInfo.isRunning = false;
+ errorText_ = "RtApiOss::error creating callback thread!";
+ goto error;
+ }
+ }
+
+ return SUCCESS;
+
+ error:
+ if ( handle ) {
+ pthread_cond_destroy( &handle->runnable );
+ if ( handle->id[0] ) close( handle->id[0] );
+ if ( handle->id[1] ) close( handle->id[1] );
+ delete handle;
+ stream_.apiHandle = 0;
+ }
+
+ for ( int i=0; i<2; i++ ) {
+ if ( stream_.userBuffer[i] ) {
+ free( stream_.userBuffer[i] );
+ stream_.userBuffer[i] = 0;
+ }
+ }
+
+ if ( stream_.deviceBuffer ) {
+ free( stream_.deviceBuffer );
+ stream_.deviceBuffer = 0;
+ }
+
+ return FAILURE;
+}
+
+void RtApiOss :: closeStream()
+{
+ if ( stream_.state == STREAM_CLOSED ) {
+ errorText_ = "RtApiOss::closeStream(): no open stream to close!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ OssHandle *handle = (OssHandle *) stream_.apiHandle;
+ stream_.callbackInfo.isRunning = false;
+ MUTEX_LOCK( &stream_.mutex );
+ if ( stream_.state == STREAM_STOPPED )
+ pthread_cond_signal( &handle->runnable );
+ MUTEX_UNLOCK( &stream_.mutex );
+ pthread_join( stream_.callbackInfo.thread, NULL );
+
+ if ( stream_.state == STREAM_RUNNING ) {
+ if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX )
+ ioctl( handle->id[0], SNDCTL_DSP_HALT, 0 );
+ else
+ ioctl( handle->id[1], SNDCTL_DSP_HALT, 0 );
+ stream_.state = STREAM_STOPPED;
+ }
+
+ if ( handle ) {
+ pthread_cond_destroy( &handle->runnable );
+ if ( handle->id[0] ) close( handle->id[0] );
+ if ( handle->id[1] ) close( handle->id[1] );
+ delete handle;
+ stream_.apiHandle = 0;
+ }
+
+ for ( int i=0; i<2; i++ ) {
+ if ( stream_.userBuffer[i] ) {
+ free( stream_.userBuffer[i] );
+ stream_.userBuffer[i] = 0;
+ }
+ }
+
+ if ( stream_.deviceBuffer ) {
+ free( stream_.deviceBuffer );
+ stream_.deviceBuffer = 0;
+ }
+
+ stream_.mode = UNINITIALIZED;
+ stream_.state = STREAM_CLOSED;
+}
+
+void RtApiOss :: startStream()
+{
+ verifyStream();
+ if ( stream_.state == STREAM_RUNNING ) {
+ errorText_ = "RtApiOss::startStream(): the stream is already running!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ MUTEX_LOCK( &stream_.mutex );
+
+ stream_.state = STREAM_RUNNING;
+
+ // No need to do anything else here ... OSS automatically starts
+ // when fed samples.
+
+ MUTEX_UNLOCK( &stream_.mutex );
+
+ OssHandle *handle = (OssHandle *) stream_.apiHandle;
+ pthread_cond_signal( &handle->runnable );
+}
+
+void RtApiOss :: stopStream()
+{
+ verifyStream();
+ if ( stream_.state == STREAM_STOPPED ) {
+ errorText_ = "RtApiOss::stopStream(): the stream is already stopped!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ MUTEX_LOCK( &stream_.mutex );
+
+ // The state might change while waiting on a mutex.
+ if ( stream_.state == STREAM_STOPPED ) {
+ MUTEX_UNLOCK( &stream_.mutex );
+ return;
+ }
+
+ int result = 0;
+ OssHandle *handle = (OssHandle *) stream_.apiHandle;
+ if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
+
+ // Flush the output with zeros a few times.
+ char *buffer;
+ int samples;
+ RtAudioFormat format;
+
+ if ( stream_.doConvertBuffer[0] ) {
+ buffer = stream_.deviceBuffer;
+ samples = stream_.bufferSize * stream_.nDeviceChannels[0];
+ format = stream_.deviceFormat[0];
+ }
+ else {
+ buffer = stream_.userBuffer[0];
+ samples = stream_.bufferSize * stream_.nUserChannels[0];
+ format = stream_.userFormat;
+ }
+
+ memset( buffer, 0, samples * formatBytes(format) );
+ for ( unsigned int i=0; i<stream_.nBuffers+1; i++ ) {
+ result = write( handle->id[0], buffer, samples * formatBytes(format) );
+ if ( result == -1 ) {
+ errorText_ = "RtApiOss::stopStream: audio write error.";
+ error( RtAudioError::WARNING );
+ }
+ }
+
+ result = ioctl( handle->id[0], SNDCTL_DSP_HALT, 0 );
+ if ( result == -1 ) {
+ errorStream_ << "RtApiOss::stopStream: system error stopping callback procedure on device (" << stream_.device[0] << ").";
+ errorText_ = errorStream_.str();
+ goto unlock;
+ }
+ handle->triggered = false;
+ }
+
+ if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && handle->id[0] != handle->id[1] ) ) {
+ result = ioctl( handle->id[1], SNDCTL_DSP_HALT, 0 );
+ if ( result == -1 ) {
+ errorStream_ << "RtApiOss::stopStream: system error stopping input callback procedure on device (" << stream_.device[0] << ").";
+ errorText_ = errorStream_.str();
+ goto unlock;
+ }
+ }
+
+ unlock:
+ stream_.state = STREAM_STOPPED;
+ MUTEX_UNLOCK( &stream_.mutex );
+
+ if ( result != -1 ) return;
+ error( RtAudioError::SYSTEM_ERROR );
+}
+
+void RtApiOss :: abortStream()
+{
+ verifyStream();
+ if ( stream_.state == STREAM_STOPPED ) {
+ errorText_ = "RtApiOss::abortStream(): the stream is already stopped!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ MUTEX_LOCK( &stream_.mutex );
+
+ // The state might change while waiting on a mutex.
+ if ( stream_.state == STREAM_STOPPED ) {
+ MUTEX_UNLOCK( &stream_.mutex );
+ return;
+ }
+
+ int result = 0;
+ OssHandle *handle = (OssHandle *) stream_.apiHandle;
+ if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
+ result = ioctl( handle->id[0], SNDCTL_DSP_HALT, 0 );
+ if ( result == -1 ) {
+ errorStream_ << "RtApiOss::abortStream: system error stopping callback procedure on device (" << stream_.device[0] << ").";
+ errorText_ = errorStream_.str();
+ goto unlock;
+ }
+ handle->triggered = false;
+ }
+
+ if ( stream_.mode == INPUT || ( stream_.mode == DUPLEX && handle->id[0] != handle->id[1] ) ) {
+ result = ioctl( handle->id[1], SNDCTL_DSP_HALT, 0 );
+ if ( result == -1 ) {
+ errorStream_ << "RtApiOss::abortStream: system error stopping input callback procedure on device (" << stream_.device[0] << ").";
+ errorText_ = errorStream_.str();
+ goto unlock;
+ }
+ }
+
+ unlock:
+ stream_.state = STREAM_STOPPED;
+ MUTEX_UNLOCK( &stream_.mutex );
+
+ if ( result != -1 ) return;
+ error( RtAudioError::SYSTEM_ERROR );
+}
+
+void RtApiOss :: callbackEvent()
+{
+ OssHandle *handle = (OssHandle *) stream_.apiHandle;
+ if ( stream_.state == STREAM_STOPPED ) {
+ MUTEX_LOCK( &stream_.mutex );
+ pthread_cond_wait( &handle->runnable, &stream_.mutex );
+ if ( stream_.state != STREAM_RUNNING ) {
+ MUTEX_UNLOCK( &stream_.mutex );
+ return;
+ }
+ MUTEX_UNLOCK( &stream_.mutex );
+ }
+
+ if ( stream_.state == STREAM_CLOSED ) {
+ errorText_ = "RtApiOss::callbackEvent(): the stream is closed ... this shouldn't happen!";
+ error( RtAudioError::WARNING );
+ return;
+ }
+
+ // Invoke user callback to get fresh output data.
+ int doStopStream = 0;
+ RtAudioCallback callback = (RtAudioCallback) stream_.callbackInfo.callback;
+ double streamTime = getStreamTime();
+ RtAudioStreamStatus status = 0;
+ if ( stream_.mode != INPUT && handle->xrun[0] == true ) {
+ status |= RTAUDIO_OUTPUT_UNDERFLOW;
+ handle->xrun[0] = false;
+ }
+ if ( stream_.mode != OUTPUT && handle->xrun[1] == true ) {
+ status |= RTAUDIO_INPUT_OVERFLOW;
+ handle->xrun[1] = false;
+ }
+ doStopStream = callback( stream_.userBuffer[0], stream_.userBuffer[1],
+ stream_.bufferSize, streamTime, status, stream_.callbackInfo.userData );
+ if ( doStopStream == 2 ) {
+ this->abortStream();
+ return;
+ }
+
+ MUTEX_LOCK( &stream_.mutex );
+
+ // The state might change while waiting on a mutex.
+ if ( stream_.state == STREAM_STOPPED ) goto unlock;
+
+ int result;
+ char *buffer;
+ int samples;
+ RtAudioFormat format;
+
+ if ( stream_.mode == OUTPUT || stream_.mode == DUPLEX ) {
+
+ // Setup parameters and do buffer conversion if necessary.
+ if ( stream_.doConvertBuffer[0] ) {
+ buffer = stream_.deviceBuffer;
+ convertBuffer( buffer, stream_.userBuffer[0], stream_.convertInfo[0] );
+ samples = stream_.bufferSize * stream_.nDeviceChannels[0];
+ format = stream_.deviceFormat[0];
+ }
+ else {
+ buffer = stream_.userBuffer[0];
+ samples = stream_.bufferSize * stream_.nUserChannels[0];
+ format = stream_.userFormat;
+ }
+
+ // Do byte swapping if necessary.
+ if ( stream_.doByteSwap[0] )
+ byteSwapBuffer( buffer, samples, format );
+
+ if ( stream_.mode == DUPLEX && handle->triggered == false ) {
+ int trig = 0;
+ ioctl( handle->id[0], SNDCTL_DSP_SETTRIGGER, &trig );
+ result = write( handle->id[0], buffer, samples * formatBytes(format) );
+ trig = PCM_ENABLE_INPUT|PCM_ENABLE_OUTPUT;
+ ioctl( handle->id[0], SNDCTL_DSP_SETTRIGGER, &trig );
+ handle->triggered = true;
+ }
+ else
+ // Write samples to device.
+ result = write( handle->id[0], buffer, samples * formatBytes(format) );
+
+ if ( result == -1 ) {
+ // We'll assume this is an underrun, though there isn't a
+ // specific means for determining that.
+ handle->xrun[0] = true;
+ errorText_ = "RtApiOss::callbackEvent: audio write error.";
+ error( RtAudioError::WARNING );
+ // Continue on to input section.
+ }
+ }
+
+ if ( stream_.mode == INPUT || stream_.mode == DUPLEX ) {
+
+ // Setup parameters.
+ if ( stream_.doConvertBuffer[1] ) {
+ buffer = stream_.deviceBuffer;
+ samples = stream_.bufferSize * stream_.nDeviceChannels[1];
+ format = stream_.deviceFormat[1];
+ }
+ else {
+ buffer = stream_.userBuffer[1];
+ samples = stream_.bufferSize * stream_.nUserChannels[1];
+ format = stream_.userFormat;
+ }
+
+ // Read samples from device.
+ result = read( handle->id[1], buffer, samples * formatBytes(format) );
+
+ if ( result == -1 ) {
+ // We'll assume this is an overrun, though there isn't a
+ // specific means for determining that.
+ handle->xrun[1] = true;
+ errorText_ = "RtApiOss::callbackEvent: audio read error.";
+ error( RtAudioError::WARNING );
+ goto unlock;
+ }
+
+ // Do byte swapping if necessary.
+ if ( stream_.doByteSwap[1] )
+ byteSwapBuffer( buffer, samples, format );
+
+ // Do buffer conversion if necessary.
+ if ( stream_.doConvertBuffer[1] )
+ convertBuffer( stream_.userBuffer[1], stream_.deviceBuffer, stream_.convertInfo[1] );
+ }
+
+ unlock:
+ MUTEX_UNLOCK( &stream_.mutex );
+
+ RtApi::tickStreamTime();
+ if ( doStopStream == 1 ) this->stopStream();
+}
+
+static void *ossCallbackHandler( void *ptr )
+{
+ CallbackInfo *info = (CallbackInfo *) ptr;
+ RtApiOss *object = (RtApiOss *) info->object;
+ bool *isRunning = &info->isRunning;
+
+ while ( *isRunning == true ) {
+ pthread_testcancel();
+ object->callbackEvent();
+ }
+
+ pthread_exit( NULL );
+}
+
+//******************** End of __LINUX_OSS__ *********************//
+#endif
+
+
+// *************************************************** //
+//
+// Protected common (OS-independent) RtAudio methods.
+//
+// *************************************************** //
+
+// This method can be modified to control the behavior of error
+// message printing.
+void RtApi :: error( RtAudioError::Type type )
+{
+ errorStream_.str(""); // clear the ostringstream
+
+ RtAudioErrorCallback errorCallback = (RtAudioErrorCallback) stream_.callbackInfo.errorCallback;
+ if ( errorCallback ) {
+ // abortStream() can generate new error messages. Ignore them. Just keep original one.
+
+ if ( firstErrorOccurred_ )
+ return;
+
+ firstErrorOccurred_ = true;
+ const std::string errorMessage = errorText_;
+
+ if ( type != RtAudioError::WARNING && stream_.state != STREAM_STOPPED) {
+ stream_.callbackInfo.isRunning = false; // exit from the thread
+ abortStream();
+ }
+
+ errorCallback( type, errorMessage );
+ firstErrorOccurred_ = false;
+ return;
+ }
+
+ if ( type == RtAudioError::WARNING && showWarnings_ == true )
+ std::cerr << '\n' << errorText_ << "\n\n";
+ else if ( type != RtAudioError::WARNING )
+ throw( RtAudioError( errorText_, type ) );
+}
+
+void RtApi :: verifyStream()
+{
+ if ( stream_.state == STREAM_CLOSED ) {
+ errorText_ = "RtApi:: a stream is not open!";
+ error( RtAudioError::INVALID_USE );
+ }
+}
+
+void RtApi :: clearStreamInfo()
+{
+ stream_.mode = UNINITIALIZED;
+ stream_.state = STREAM_CLOSED;
+ stream_.sampleRate = 0;
+ stream_.bufferSize = 0;
+ stream_.nBuffers = 0;
+ stream_.userFormat = 0;
+ stream_.userInterleaved = true;
+ stream_.streamTime = 0.0;
+ stream_.apiHandle = 0;
+ stream_.deviceBuffer = 0;
+ stream_.callbackInfo.callback = 0;
+ stream_.callbackInfo.userData = 0;
+ stream_.callbackInfo.isRunning = false;
+ stream_.callbackInfo.errorCallback = 0;
+ for ( int i=0; i<2; i++ ) {
+ stream_.device[i] = 11111;
+ stream_.doConvertBuffer[i] = false;
+ stream_.deviceInterleaved[i] = true;
+ stream_.doByteSwap[i] = false;
+ stream_.nUserChannels[i] = 0;
+ stream_.nDeviceChannels[i] = 0;
+ stream_.channelOffset[i] = 0;
+ stream_.deviceFormat[i] = 0;
+ stream_.latency[i] = 0;
+ stream_.userBuffer[i] = 0;
+ stream_.convertInfo[i].channels = 0;
+ stream_.convertInfo[i].inJump = 0;
+ stream_.convertInfo[i].outJump = 0;
+ stream_.convertInfo[i].inFormat = 0;
+ stream_.convertInfo[i].outFormat = 0;
+ stream_.convertInfo[i].inOffset.clear();
+ stream_.convertInfo[i].outOffset.clear();
+ }
+}
+
+unsigned int RtApi :: formatBytes( RtAudioFormat format )
+{
+ if ( format == RTAUDIO_SINT16 )
+ return 2;
+ else if ( format == RTAUDIO_SINT32 || format == RTAUDIO_FLOAT32 )
+ return 4;
+ else if ( format == RTAUDIO_FLOAT64 )
+ return 8;
+ else if ( format == RTAUDIO_SINT24 )
+ return 3;
+ else if ( format == RTAUDIO_SINT8 )
+ return 1;
+
+ errorText_ = "RtApi::formatBytes: undefined format.";
+ error( RtAudioError::WARNING );
+
+ return 0;
+}
+
+void RtApi :: setConvertInfo( StreamMode mode, unsigned int firstChannel )
+{
+ if ( mode == INPUT ) { // convert device to user buffer
+ stream_.convertInfo[mode].inJump = stream_.nDeviceChannels[1];
+ stream_.convertInfo[mode].outJump = stream_.nUserChannels[1];
+ stream_.convertInfo[mode].inFormat = stream_.deviceFormat[1];
+ stream_.convertInfo[mode].outFormat = stream_.userFormat;
+ }
+ else { // convert user to device buffer
+ stream_.convertInfo[mode].inJump = stream_.nUserChannels[0];
+ stream_.convertInfo[mode].outJump = stream_.nDeviceChannels[0];
+ stream_.convertInfo[mode].inFormat = stream_.userFormat;
+ stream_.convertInfo[mode].outFormat = stream_.deviceFormat[0];
+ }
+
+ if ( stream_.convertInfo[mode].inJump < stream_.convertInfo[mode].outJump )
+ stream_.convertInfo[mode].channels = stream_.convertInfo[mode].inJump;
+ else
+ stream_.convertInfo[mode].channels = stream_.convertInfo[mode].outJump;
+
+ // Set up the interleave/deinterleave offsets.
+ if ( stream_.deviceInterleaved[mode] != stream_.userInterleaved ) {
+ if ( ( mode == OUTPUT && stream_.deviceInterleaved[mode] ) ||
+ ( mode == INPUT && stream_.userInterleaved ) ) {
+ for ( int k=0; k<stream_.convertInfo[mode].channels; k++ ) {
+ stream_.convertInfo[mode].inOffset.push_back( k * stream_.bufferSize );
+ stream_.convertInfo[mode].outOffset.push_back( k );
+ stream_.convertInfo[mode].inJump = 1;
+ }
+ }
+ else {
+ for ( int k=0; k<stream_.convertInfo[mode].channels; k++ ) {
+ stream_.convertInfo[mode].inOffset.push_back( k );
+ stream_.convertInfo[mode].outOffset.push_back( k * stream_.bufferSize );
+ stream_.convertInfo[mode].outJump = 1;
+ }
+ }
+ }
+ else { // no (de)interleaving
+ if ( stream_.userInterleaved ) {
+ for ( int k=0; k<stream_.convertInfo[mode].channels; k++ ) {
+ stream_.convertInfo[mode].inOffset.push_back( k );
+ stream_.convertInfo[mode].outOffset.push_back( k );
+ }
+ }
+ else {
+ for ( int k=0; k<stream_.convertInfo[mode].channels; k++ ) {
+ stream_.convertInfo[mode].inOffset.push_back( k * stream_.bufferSize );
+ stream_.convertInfo[mode].outOffset.push_back( k * stream_.bufferSize );
+ stream_.convertInfo[mode].inJump = 1;
+ stream_.convertInfo[mode].outJump = 1;
+ }
+ }
+ }
+
+ // Add channel offset.
+ if ( firstChannel > 0 ) {
+ if ( stream_.deviceInterleaved[mode] ) {
+ if ( mode == OUTPUT ) {
+ for ( int k=0; k<stream_.convertInfo[mode].channels; k++ )
+ stream_.convertInfo[mode].outOffset[k] += firstChannel;
+ }
+ else {
+ for ( int k=0; k<stream_.convertInfo[mode].channels; k++ )
+ stream_.convertInfo[mode].inOffset[k] += firstChannel;
+ }
+ }
+ else {
+ if ( mode == OUTPUT ) {
+ for ( int k=0; k<stream_.convertInfo[mode].channels; k++ )
+ stream_.convertInfo[mode].outOffset[k] += ( firstChannel * stream_.bufferSize );
+ }
+ else {
+ for ( int k=0; k<stream_.convertInfo[mode].channels; k++ )
+ stream_.convertInfo[mode].inOffset[k] += ( firstChannel * stream_.bufferSize );
+ }
+ }
+ }
+}
+
+void RtApi :: convertBuffer( char *outBuffer, char *inBuffer, ConvertInfo &info )
+{
+ // This function does format conversion, input/output channel compensation, and
+ // data interleaving/deinterleaving. 24-bit integers are assumed to occupy
+ // the lower three bytes of a 32-bit integer.
+
+ // Clear our device buffer when in/out duplex device channels are different
+ if ( outBuffer == stream_.deviceBuffer && stream_.mode == DUPLEX &&
+ ( stream_.nDeviceChannels[0] < stream_.nDeviceChannels[1] ) )
+ memset( outBuffer, 0, stream_.bufferSize * info.outJump * formatBytes( info.outFormat ) );
+
+ int j;
+ if (info.outFormat == RTAUDIO_FLOAT64) {
+ Float64 scale;
+ Float64 *out = (Float64 *)outBuffer;
+
+ if (info.inFormat == RTAUDIO_SINT8) {
+ signed char *in = (signed char *)inBuffer;
+ scale = 1.0 / 127.5;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];
+ out[info.outOffset[j]] += 0.5;
+ out[info.outOffset[j]] *= scale;
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_SINT16) {
+ Int16 *in = (Int16 *)inBuffer;
+ scale = 1.0 / 32767.5;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];
+ out[info.outOffset[j]] += 0.5;
+ out[info.outOffset[j]] *= scale;
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_SINT24) {
+ Int24 *in = (Int24 *)inBuffer;
+ scale = 1.0 / 8388607.5;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (Float64) (in[info.inOffset[j]].asInt());
+ out[info.outOffset[j]] += 0.5;
+ out[info.outOffset[j]] *= scale;
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_SINT32) {
+ Int32 *in = (Int32 *)inBuffer;
+ scale = 1.0 / 2147483647.5;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];
+ out[info.outOffset[j]] += 0.5;
+ out[info.outOffset[j]] *= scale;
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_FLOAT32) {
+ Float32 *in = (Float32 *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (Float64) in[info.inOffset[j]];
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_FLOAT64) {
+ // Channel compensation and/or (de)interleaving only.
+ Float64 *in = (Float64 *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = in[info.inOffset[j]];
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ }
+ else if (info.outFormat == RTAUDIO_FLOAT32) {
+ Float32 scale;
+ Float32 *out = (Float32 *)outBuffer;
+
+ if (info.inFormat == RTAUDIO_SINT8) {
+ signed char *in = (signed char *)inBuffer;
+ scale = (Float32) ( 1.0 / 127.5 );
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];
+ out[info.outOffset[j]] += 0.5;
+ out[info.outOffset[j]] *= scale;
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_SINT16) {
+ Int16 *in = (Int16 *)inBuffer;
+ scale = (Float32) ( 1.0 / 32767.5 );
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];
+ out[info.outOffset[j]] += 0.5;
+ out[info.outOffset[j]] *= scale;
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_SINT24) {
+ Int24 *in = (Int24 *)inBuffer;
+ scale = (Float32) ( 1.0 / 8388607.5 );
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (Float32) (in[info.inOffset[j]].asInt());
+ out[info.outOffset[j]] += 0.5;
+ out[info.outOffset[j]] *= scale;
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_SINT32) {
+ Int32 *in = (Int32 *)inBuffer;
+ scale = (Float32) ( 1.0 / 2147483647.5 );
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];
+ out[info.outOffset[j]] += 0.5;
+ out[info.outOffset[j]] *= scale;
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_FLOAT32) {
+ // Channel compensation and/or (de)interleaving only.
+ Float32 *in = (Float32 *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = in[info.inOffset[j]];
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_FLOAT64) {
+ Float64 *in = (Float64 *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (Float32) in[info.inOffset[j]];
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ }
+ else if (info.outFormat == RTAUDIO_SINT32) {
+ Int32 *out = (Int32 *)outBuffer;
+ if (info.inFormat == RTAUDIO_SINT8) {
+ signed char *in = (signed char *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (Int32) in[info.inOffset[j]];
+ out[info.outOffset[j]] <<= 24;
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_SINT16) {
+ Int16 *in = (Int16 *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (Int32) in[info.inOffset[j]];
+ out[info.outOffset[j]] <<= 16;
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_SINT24) {
+ Int24 *in = (Int24 *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (Int32) in[info.inOffset[j]].asInt();
+ out[info.outOffset[j]] <<= 8;
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_SINT32) {
+ // Channel compensation and/or (de)interleaving only.
+ Int32 *in = (Int32 *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = in[info.inOffset[j]];
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_FLOAT32) {
+ Float32 *in = (Float32 *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.5 - 0.5);
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_FLOAT64) {
+ Float64 *in = (Float64 *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 2147483647.5 - 0.5);
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ }
+ else if (info.outFormat == RTAUDIO_SINT24) {
+ Int24 *out = (Int24 *)outBuffer;
+ if (info.inFormat == RTAUDIO_SINT8) {
+ signed char *in = (signed char *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] << 16);
+ //out[info.outOffset[j]] <<= 16;
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_SINT16) {
+ Int16 *in = (Int16 *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] << 8);
+ //out[info.outOffset[j]] <<= 8;
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_SINT24) {
+ // Channel compensation and/or (de)interleaving only.
+ Int24 *in = (Int24 *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = in[info.inOffset[j]];
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_SINT32) {
+ Int32 *in = (Int32 *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] >> 8);
+ //out[info.outOffset[j]] >>= 8;
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_FLOAT32) {
+ Float32 *in = (Float32 *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 8388607.5 - 0.5);
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_FLOAT64) {
+ Float64 *in = (Float64 *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (Int32) (in[info.inOffset[j]] * 8388607.5 - 0.5);
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ }
+ else if (info.outFormat == RTAUDIO_SINT16) {
+ Int16 *out = (Int16 *)outBuffer;
+ if (info.inFormat == RTAUDIO_SINT8) {
+ signed char *in = (signed char *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (Int16) in[info.inOffset[j]];
+ out[info.outOffset[j]] <<= 8;
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_SINT16) {
+ // Channel compensation and/or (de)interleaving only.
+ Int16 *in = (Int16 *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = in[info.inOffset[j]];
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_SINT24) {
+ Int24 *in = (Int24 *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]].asInt() >> 8);
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_SINT32) {
+ Int32 *in = (Int32 *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (Int16) ((in[info.inOffset[j]] >> 16) & 0x0000ffff);
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_FLOAT32) {
+ Float32 *in = (Float32 *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]] * 32767.5 - 0.5);
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_FLOAT64) {
+ Float64 *in = (Float64 *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (Int16) (in[info.inOffset[j]] * 32767.5 - 0.5);
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ }
+ else if (info.outFormat == RTAUDIO_SINT8) {
+ signed char *out = (signed char *)outBuffer;
+ if (info.inFormat == RTAUDIO_SINT8) {
+ // Channel compensation and/or (de)interleaving only.
+ signed char *in = (signed char *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = in[info.inOffset[j]];
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ if (info.inFormat == RTAUDIO_SINT16) {
+ Int16 *in = (Int16 *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (signed char) ((in[info.inOffset[j]] >> 8) & 0x00ff);
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_SINT24) {
+ Int24 *in = (Int24 *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]].asInt() >> 16);
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_SINT32) {
+ Int32 *in = (Int32 *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (signed char) ((in[info.inOffset[j]] >> 24) & 0x000000ff);
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_FLOAT32) {
+ Float32 *in = (Float32 *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]] * 127.5 - 0.5);
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ else if (info.inFormat == RTAUDIO_FLOAT64) {
+ Float64 *in = (Float64 *)inBuffer;
+ for (unsigned int i=0; i<stream_.bufferSize; i++) {
+ for (j=0; j<info.channels; j++) {
+ out[info.outOffset[j]] = (signed char) (in[info.inOffset[j]] * 127.5 - 0.5);
+ }
+ in += info.inJump;
+ out += info.outJump;
+ }
+ }
+ }
+}
+
+//static inline uint16_t bswap_16(uint16_t x) { return (x>>8) | (x<<8); }
+//static inline uint32_t bswap_32(uint32_t x) { return (bswap_16(x&0xffff)<<16) | (bswap_16(x>>16)); }
+//static inline uint64_t bswap_64(uint64_t x) { return (((unsigned long long)bswap_32(x&0xffffffffull))<<32) | (bswap_32(x>>32)); }
+
+void RtApi :: byteSwapBuffer( char *buffer, unsigned int samples, RtAudioFormat format )
+{
+ register char val;
+ register char *ptr;
+
+ ptr = buffer;
+ if ( format == RTAUDIO_SINT16 ) {
+ for ( unsigned int i=0; i<samples; i++ ) {
+ // Swap 1st and 2nd bytes.
+ val = *(ptr);
+ *(ptr) = *(ptr+1);
+ *(ptr+1) = val;
+
+ // Increment 2 bytes.
+ ptr += 2;
+ }
+ }
+ else if ( format == RTAUDIO_SINT32 ||
+ format == RTAUDIO_FLOAT32 ) {
+ for ( unsigned int i=0; i<samples; i++ ) {
+ // Swap 1st and 4th bytes.
+ val = *(ptr);
+ *(ptr) = *(ptr+3);
+ *(ptr+3) = val;
+
+ // Swap 2nd and 3rd bytes.
+ ptr += 1;
+ val = *(ptr);
+ *(ptr) = *(ptr+1);
+ *(ptr+1) = val;
+
+ // Increment 3 more bytes.
+ ptr += 3;
+ }
+ }
+ else if ( format == RTAUDIO_SINT24 ) {
+ for ( unsigned int i=0; i<samples; i++ ) {
+ // Swap 1st and 3rd bytes.
+ val = *(ptr);
+ *(ptr) = *(ptr+2);
+ *(ptr+2) = val;
+
+ // Increment 2 more bytes.
+ ptr += 2;
+ }
+ }
+ else if ( format == RTAUDIO_FLOAT64 ) {
+ for ( unsigned int i=0; i<samples; i++ ) {
+ // Swap 1st and 8th bytes
+ val = *(ptr);
+ *(ptr) = *(ptr+7);
+ *(ptr+7) = val;
+
+ // Swap 2nd and 7th bytes
+ ptr += 1;
+ val = *(ptr);
+ *(ptr) = *(ptr+5);
+ *(ptr+5) = val;
+
+ // Swap 3rd and 6th bytes
+ ptr += 1;
+ val = *(ptr);
+ *(ptr) = *(ptr+3);
+ *(ptr+3) = val;
+
+ // Swap 4th and 5th bytes
+ ptr += 1;
+ val = *(ptr);
+ *(ptr) = *(ptr+1);
+ *(ptr+1) = val;
+
+ // Increment 5 more bytes.
+ ptr += 5;
+ }
+ }
+}
+
+ // Indentation settings for Vim and Emacs
+ //
+ // Local Variables:
+ // c-basic-offset: 2
+ // indent-tabs-mode: nil
+ // End:
+ //
+ // vim: et sts=2 sw=2
+
+#endif
diff --git a/drivers/rtaudio/audio_driver_rtaudio.cpp b/drivers/rtaudio/audio_driver_rtaudio.cpp
index 7bee495869..335f4b632f 100644
--- a/drivers/rtaudio/audio_driver_rtaudio.cpp
+++ b/drivers/rtaudio/audio_driver_rtaudio.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/*************************************************/
/* Source code within this file is: */
-/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
/* All Rights Reserved. */
/*************************************************/
diff --git a/drivers/rtaudio/audio_driver_rtaudio.h b/drivers/rtaudio/audio_driver_rtaudio.h
index a16470d701..115953ce1f 100644
--- a/drivers/rtaudio/audio_driver_rtaudio.h
+++ b/drivers/rtaudio/audio_driver_rtaudio.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/*************************************************/
/* Source code within this file is: */
-/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
/* All Rights Reserved. */
/*************************************************/
diff --git a/drivers/speex/audio_stream_speex.cpp b/drivers/speex/audio_stream_speex.cpp
index a6bac78b4d..1bb4952cc8 100644
--- a/drivers/speex/audio_stream_speex.cpp
+++ b/drivers/speex/audio_stream_speex.cpp
@@ -15,14 +15,15 @@ static _FORCE_INLINE_ uint16_t le_short(uint16_t s)
}
-void AudioStreamSpeex::update() {
+int AudioStreamPlaybackSpeex::mix(int16_t* p_buffer,int p_frames) {
+
+
- _THREAD_SAFE_METHOD_;
//printf("update, loops %i, read ofs %i\n", (int)loops, read_ofs);
//printf("playing %i, paused %i\n", (int)playing, (int)paused);
- if (!playing || paused || !data.size())
- return;
+ if (!active || !playing || !data.size())
+ return 0;
/*
if (read_ofs >= data.size()) {
@@ -35,12 +36,13 @@ void AudioStreamSpeex::update() {
};
*/
- int todo = get_todo();
+ int todo = p_frames;
if (todo < page_size) {
- return;
+ return 0;
};
- int eos = 0;
+ int eos = 0;
+ bool reloaded=false;
while (todo > page_size) {
@@ -92,7 +94,7 @@ void AudioStreamSpeex::update() {
for (int j=0;j!=nframes;j++)
{
- int16_t* out = get_write_buffer();
+ int16_t* out = p_buffer;
int ret;
/*Decode frame*/
@@ -120,7 +122,7 @@ void AudioStreamSpeex::update() {
/*Convert to short and save to output file*/
- for (int i=0;i<frame_size*get_channel_count();i++) {
+ for (int i=0;i<frame_size*stream_channels;i++) {
out[i]=le_short(out[i]);
}
@@ -149,7 +151,7 @@ void AudioStreamSpeex::update() {
}
- write(new_frame_size);
+ p_buffer+=new_frame_size*stream_channels;
todo-=new_frame_size;
}
}
@@ -175,6 +177,7 @@ void AudioStreamSpeex::update() {
if (loops) {
reload();
++loop_count;
+ //break;
} else {
playing=false;
unload();
@@ -183,18 +186,22 @@ void AudioStreamSpeex::update() {
}
};
};
+
+ return p_frames-todo;
};
-void AudioStreamSpeex::unload() {
+void AudioStreamPlaybackSpeex::unload() {
+
- _THREAD_SAFE_METHOD_
if (!active) return;
speex_bits_destroy(&bits);
if (st)
speex_decoder_destroy(st);
+
+ ogg_sync_clear(&oy);
active = false;
//data.resize(0);
st = NULL;
@@ -204,7 +211,7 @@ void AudioStreamSpeex::unload() {
loop_count = 0;
}
-void *AudioStreamSpeex::process_header(ogg_packet *op, int *frame_size, int *rate, int *nframes, int *channels, int *extra_headers) {
+void *AudioStreamPlaybackSpeex::process_header(ogg_packet *op, int *frame_size, int *rate, int *nframes, int *channels, int *extra_headers) {
void *st;
SpeexHeader *header;
@@ -276,9 +283,9 @@ void *AudioStreamSpeex::process_header(ogg_packet *op, int *frame_size, int *rat
-void AudioStreamSpeex::reload() {
+void AudioStreamPlaybackSpeex::reload() {
+
- _THREAD_SAFE_METHOD_
if (active)
unload();
@@ -359,8 +366,10 @@ void AudioStreamSpeex::reload() {
};
page_size = nframes * frame_size;
+ stream_srate=rate;
+ stream_channels=channels;
+ stream_minbuff_size=page_size;
- _setup(channels, rate,page_size);
} else if (packet_count==1)
{
@@ -374,23 +383,23 @@ void AudioStreamSpeex::reload() {
} while (packet_count <= extra_headers);
- active = true;
+ active=true;
}
-void AudioStreamSpeex::_bind_methods() {
+void AudioStreamPlaybackSpeex::_bind_methods() {
- ObjectTypeDB::bind_method(_MD("set_file","file"),&AudioStreamSpeex::set_file);
- ObjectTypeDB::bind_method(_MD("get_file"),&AudioStreamSpeex::get_file);
+ //ObjectTypeDB::bind_method(_MD("set_file","file"),&AudioStreamPlaybackSpeex::set_file);
+// ObjectTypeDB::bind_method(_MD("get_file"),&AudioStreamPlaybackSpeex::get_file);
- ObjectTypeDB::bind_method(_MD("_set_bundled"),&AudioStreamSpeex::_set_bundled);
- ObjectTypeDB::bind_method(_MD("_get_bundled"),&AudioStreamSpeex::_get_bundled);
+ ObjectTypeDB::bind_method(_MD("_set_bundled"),&AudioStreamPlaybackSpeex::_set_bundled);
+ ObjectTypeDB::bind_method(_MD("_get_bundled"),&AudioStreamPlaybackSpeex::_get_bundled);
ADD_PROPERTY( PropertyInfo(Variant::DICTIONARY,"_bundled",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_BUNDLE),_SCS("_set_bundled"),_SCS("_get_bundled"));
- ADD_PROPERTY( PropertyInfo(Variant::STRING,"file",PROPERTY_HINT_FILE,"*.spx"),_SCS("set_file"),_SCS("get_file"));
+ //ADD_PROPERTY( PropertyInfo(Variant::STRING,"file",PROPERTY_HINT_FILE,"*.spx"),_SCS("set_file"),_SCS("get_file"));
};
-void AudioStreamSpeex::_set_bundled(const Dictionary& dict) {
+void AudioStreamPlaybackSpeex::_set_bundled(const Dictionary& dict) {
ERR_FAIL_COND( !dict.has("filename"));
ERR_FAIL_COND( !dict.has("data"));
@@ -399,7 +408,7 @@ void AudioStreamSpeex::_set_bundled(const Dictionary& dict) {
data = dict["data"];
};
-Dictionary AudioStreamSpeex::_get_bundled() const {
+Dictionary AudioStreamPlaybackSpeex::_get_bundled() const {
Dictionary d;
d["filename"] = filename;
@@ -408,43 +417,17 @@ Dictionary AudioStreamSpeex::_get_bundled() const {
};
-String AudioStreamSpeex::get_file() const {
- return filename;
-};
-
-void AudioStreamSpeex::set_file(const String& p_file){
-
- if (filename == p_file)
- return;
-
- if (active) {
- unload();
- }
-
- if (p_file == "") {
- data.resize(0);
- return;
- };
-
- Error err;
- FileAccess* file = FileAccess::open(p_file, FileAccess::READ,&err);
- if (err != OK) {
- data.resize(0);
- };
- ERR_FAIL_COND(err != OK);
-
- filename = p_file;
- data.resize(file->get_len());
- int read = file->get_buffer(&data[0], data.size());
- memdelete(file);
+void AudioStreamPlaybackSpeex::set_data(const Vector<uint8_t>& p_data) {
+ data=p_data;
reload();
}
-void AudioStreamSpeex::play() {
- _THREAD_SAFE_METHOD_
+void AudioStreamPlaybackSpeex::play(float p_from_pos) {
+
+
reload();
if (!active)
@@ -452,85 +435,109 @@ void AudioStreamSpeex::play() {
playing = true;
}
-void AudioStreamSpeex::stop(){
+void AudioStreamPlaybackSpeex::stop(){
+
- _THREAD_SAFE_METHOD_
unload();
playing = false;
- _clear();
-}
-bool AudioStreamSpeex::is_playing() const{
- return _is_ready() && (playing || (get_total() - get_todo() -1 > 0));
}
+bool AudioStreamPlaybackSpeex::is_playing() const{
-void AudioStreamSpeex::set_paused(bool p_paused){
-
- playing = !p_paused;
- paused = p_paused;
+ return playing;
}
-bool AudioStreamSpeex::is_paused(bool p_paused) const{
- return paused;
-}
-void AudioStreamSpeex::set_loop(bool p_enable){
+void AudioStreamPlaybackSpeex::set_loop(bool p_enable){
loops = p_enable;
}
-bool AudioStreamSpeex::has_loop() const{
+bool AudioStreamPlaybackSpeex::has_loop() const{
return loops;
}
-float AudioStreamSpeex::get_length() const{
+float AudioStreamPlaybackSpeex::get_length() const{
return 0;
}
-String AudioStreamSpeex::get_stream_name() const{
+String AudioStreamPlaybackSpeex::get_stream_name() const{
return "";
}
-int AudioStreamSpeex::get_loop_count() const{
+int AudioStreamPlaybackSpeex::get_loop_count() const{
return 0;
}
-float AudioStreamSpeex::get_pos() const{
+float AudioStreamPlaybackSpeex::get_pos() const{
return 0;
}
-void AudioStreamSpeex::seek_pos(float p_time){
+void AudioStreamPlaybackSpeex::seek_pos(float p_time){
};
-bool AudioStreamSpeex::_can_mix() const {
- //return playing;
- return data.size() != 0;
-};
+AudioStreamPlaybackSpeex::AudioStreamPlaybackSpeex() {
+
+ active=false;
+ st = NULL;
+ stream_channels=1;
+ stream_srate=1;
+ stream_minbuff_size=1;
+ playing=false;
-AudioStream::UpdateMode AudioStreamSpeex::get_update_mode() const {
- return UPDATE_THREAD;
}
-AudioStreamSpeex::AudioStreamSpeex() {
+AudioStreamPlaybackSpeex::~AudioStreamPlaybackSpeex() {
- active=false;
- st = NULL;
+ unload();
}
-AudioStreamSpeex::~AudioStreamSpeex() {
- unload();
+
+
+
+////////////////////////////////////////
+
+
+
+void AudioStreamSpeex::set_file(const String& p_file) {
+
+ if (this->file == p_file)
+ return;
+
+ this->file=p_file;
+
+ if (p_file == "") {
+ data.resize(0);
+ return;
+ };
+
+ Error err;
+ FileAccess* file = FileAccess::open(p_file, FileAccess::READ,&err);
+ if (err != OK) {
+ data.resize(0);
+ };
+ ERR_FAIL_COND(err != OK);
+
+ this->file = p_file;
+ data.resize(file->get_len());
+ int read = file->get_buffer(&data[0], data.size());
+ memdelete(file);
+
}
-RES ResourceFormatLoaderAudioStreamSpeex::load(const String &p_path,const String& p_original_path) {
+RES ResourceFormatLoaderAudioStreamSpeex::load(const String &p_path, const String& p_original_path, Error *r_error) {
+
+ if (r_error)
+ *r_error=OK;
AudioStreamSpeex *stream = memnew(AudioStreamSpeex);
stream->set_file(p_path);
diff --git a/drivers/speex/audio_stream_speex.h b/drivers/speex/audio_stream_speex.h
index 9557ebe0b8..f0617b302f 100644
--- a/drivers/speex/audio_stream_speex.h
+++ b/drivers/speex/audio_stream_speex.h
@@ -1,7 +1,7 @@
#ifndef AUDIO_STREAM_SPEEX_H
#define AUDIO_STREAM_SPEEX_H
-#include "scene/resources/audio_stream_resampled.h"
+#include "scene/resources/audio_stream.h"
#include "speex/speex.h"
#include "os/file_access.h"
#include "io/resource_loader.h"
@@ -14,10 +14,10 @@
#include <ogg/ogg.h>
-class AudioStreamSpeex : public AudioStreamResampled {
+class AudioStreamPlaybackSpeex : public AudioStreamPlayback {
+
+ OBJ_TYPE(AudioStreamPlaybackSpeex, AudioStreamPlayback);
- OBJ_TYPE(AudioStreamSpeex, AudioStreamResampled);
- _THREAD_SAFE_CLASS_
void *st;
SpeexBits bits;
@@ -29,7 +29,6 @@ class AudioStreamSpeex : public AudioStreamResampled {
bool loops;
int page_size;
bool playing;
- bool paused;
bool packets_available;
void unload();
@@ -45,6 +44,9 @@ class AudioStreamSpeex : public AudioStreamResampled {
ogg_int64_t page_granule, last_granule;
int skip_samples, page_nb_packets;
+ int stream_channels;
+ int stream_srate;
+ int stream_minbuff_size;
void* process_header(ogg_packet *op, int *frame_size, int *rate, int *nframes, int *channels, int *extra_headers);
@@ -52,7 +54,7 @@ class AudioStreamSpeex : public AudioStreamResampled {
protected:
- virtual bool _can_mix() const;
+ //virtual bool _can_mix() const;
Dictionary _get_bundled() const;
void _set_bundled(const Dictionary& dict);
@@ -60,16 +62,12 @@ protected:
public:
- void set_file(const String& p_file);
- String get_file() const;
+ void set_data(const Vector<uint8_t>& p_data);
- virtual void play();
+ virtual void play(float p_from_pos=0);
virtual void stop();
virtual bool is_playing() const;
- virtual void set_paused(bool p_paused);
- virtual bool is_paused(bool p_paused) const;
-
virtual void set_loop(bool p_enable);
virtual bool has_loop() const;
@@ -82,16 +80,42 @@ public:
virtual float get_pos() const;
virtual void seek_pos(float p_time);
- virtual UpdateMode get_update_mode() const;
- virtual void update();
+ virtual int get_channels() const { return stream_channels; }
+ virtual int get_mix_rate() const { return stream_srate; }
+
+ virtual int get_minimum_buffer_size() const { return stream_minbuff_size; }
+ virtual int mix(int16_t* p_bufer,int p_frames);
+
+ virtual void set_loop_restart_time(float p_time) { } //no loop restart, ignore
+
+ AudioStreamPlaybackSpeex();
+ ~AudioStreamPlaybackSpeex();
+};
+
+
+
+class AudioStreamSpeex : public AudioStream {
+
+ OBJ_TYPE(AudioStreamSpeex,AudioStream);
+
+ Vector<uint8_t> data;
+ String file;
+public:
+
+ Ref<AudioStreamPlayback> instance_playback() {
+ Ref<AudioStreamPlaybackSpeex> pb = memnew( AudioStreamPlaybackSpeex );
+ pb->set_data(data);
+ return pb;
+ }
+
+ void set_file(const String& p_file);
- AudioStreamSpeex();
- ~AudioStreamSpeex();
};
+
class ResourceFormatLoaderAudioStreamSpeex : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path,const String& p_original_path="");
+ virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String& p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/drivers/speex/config.h b/drivers/speex/config.h
index d31382702c..8c48e3b99d 100644
--- a/drivers/speex/config.h
+++ b/drivers/speex/config.h
@@ -1,52 +1,52 @@
-/*
- Copyright (C) 2003 Commonwealth Scientific and Industrial Research
- Organisation (CSIRO) Australia
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- - Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- - Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- - Neither the name of CSIRO Australia nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ORGANISATION OR
- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-#ifndef CONFIG_H
-#define CONFIG_H
-
-/* An inline macro is required for use of the inline keyword as not all C compilers support */
-/* inline. It is officially C99 and C++ only */
-
-
-/* Use only fixed point arithmetic */
-
-//#ifdef _MSC_VER
-//#define inline _inline
-//#endif
-
-#define FIXED_POINT 1
-
-#ifdef _MSC_VER
-#define inline __inline
-#endif
-
-#endif /* ! CONFIG_H */
+/*
+ Copyright (C) 2003 Commonwealth Scientific and Industrial Research
+ Organisation (CSIRO) Australia
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ - Neither the name of CSIRO Australia nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ORGANISATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+/* An inline macro is required for use of the inline keyword as not all C compilers support */
+/* inline. It is officially C99 and C++ only */
+
+
+/* Use only fixed point arithmetic */
+
+//#ifdef _MSC_VER
+//#define inline _inline
+//#endif
+
+#define FIXED_POINT 1
+
+#ifdef _MSC_VER
+#define inline __inline
+#endif
+
+#endif /* ! CONFIG_H */
diff --git a/drivers/speex/lsp.h b/drivers/speex/lsp.h
index 648652fb9e..b55bd42f2c 100644
--- a/drivers/speex/lsp.h
+++ b/drivers/speex/lsp.h
@@ -1,64 +1,64 @@
-/*---------------------------------------------------------------------------*\
-Original Copyright
- FILE........: AK2LSPD.H
- TYPE........: Turbo C header file
- COMPANY.....: Voicetronix
- AUTHOR......: James Whitehall
- DATE CREATED: 21/11/95
-
-Modified by Jean-Marc Valin
-
- This file contains functions for converting Linear Prediction
- Coefficients (LPC) to Line Spectral Pair (LSP) and back. Note that the
- LSP coefficients are not in radians format but in the x domain of the
- unit circle.
-
-\*---------------------------------------------------------------------------*/
-/**
- @file lsp.h
- @brief Line Spectral Pair (LSP) functions.
-*/
-/* Speex License:
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- - Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- - Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
- - Neither the name of the Xiph.org Foundation nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-#ifndef __AK2LSPD__
-#define __AK2LSPD__
-
-#include "arch.h"
-
-int lpc_to_lsp (spx_coef_t *a, int lpcrdr, spx_lsp_t *freq, int nb, spx_word16_t delta, char *stack);
-void lsp_to_lpc(spx_lsp_t *freq, spx_coef_t *ak, int lpcrdr, char *stack);
-
-/*Added by JMV*/
-void lsp_enforce_margin(spx_lsp_t *lsp, int len, spx_word16_t margin);
-
-void lsp_interpolate(spx_lsp_t *old_lsp, spx_lsp_t *new_lsp, spx_lsp_t *interp_lsp, int len, int subframe, int nb_subframes);
-
-#endif /* __AK2LSPD__ */
+/*---------------------------------------------------------------------------*\
+Original Copyright
+ FILE........: AK2LSPD.H
+ TYPE........: Turbo C header file
+ COMPANY.....: Voicetronix
+ AUTHOR......: James Whitehall
+ DATE CREATED: 21/11/95
+
+Modified by Jean-Marc Valin
+
+ This file contains functions for converting Linear Prediction
+ Coefficients (LPC) to Line Spectral Pair (LSP) and back. Note that the
+ LSP coefficients are not in radians format but in the x domain of the
+ unit circle.
+
+\*---------------------------------------------------------------------------*/
+/**
+ @file lsp.h
+ @brief Line Spectral Pair (LSP) functions.
+*/
+/* Speex License:
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ - Neither the name of the Xiph.org Foundation nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
+ CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __AK2LSPD__
+#define __AK2LSPD__
+
+#include "arch.h"
+
+int lpc_to_lsp (spx_coef_t *a, int lpcrdr, spx_lsp_t *freq, int nb, spx_word16_t delta, char *stack);
+void lsp_to_lpc(spx_lsp_t *freq, spx_coef_t *ak, int lpcrdr, char *stack);
+
+/*Added by JMV*/
+void lsp_enforce_margin(spx_lsp_t *lsp, int len, spx_word16_t margin);
+
+void lsp_interpolate(spx_lsp_t *old_lsp, spx_lsp_t *new_lsp, spx_lsp_t *interp_lsp, int len, int subframe, int nb_subframes);
+
+#endif /* __AK2LSPD__ */
diff --git a/drivers/speex/speex_bind.cpp b/drivers/speex/speex_bind.cpp
index 6e9eb638a2..d15bb3da8c 100644
--- a/drivers/speex/speex_bind.cpp
+++ b/drivers/speex/speex_bind.cpp
@@ -1,64 +1,64 @@
-
-#include "memory.h"
-#include "speex_bind.h"
-#include
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void *speex_alloc (int size) {
-
- uint8_t * mem = (uint8_t*)memalloc(size);
- for(int i=0;i<size;i++)
- mem[i]=0;
- return mem;
-}
-
-void *speex_alloc_scratch (int size) {
-
- return memalloc(size);
-}
-
-void *speex_realloc (void *ptr, int size) {
-
- return memrealloc(ptr,size);
-}
-
-void speex_free (void *ptr) {
-
- memfree(ptr);
-}
-
-void speex_free_scratch (void *ptr) {
-
- memfree(ptr);
-}
-
-void _speex_fatal(const char *str, const char *file, int line) {
-
- _err_print_error("SPEEX ERROR",p_file,p_line,str);
-}
-
-void speex_warning(const char *str) {
-
- _err_print_error("SPEEX WARNING","",0,str);
-}
-
-void speex_warning_int(const char *str, int val) {
-
- _err_print_error("SPEEX WARNING INT","Value",val,str);
-}
-
-void speex_notify(const char *str) {
-
- print_line(str);
-}
-
-void _speex_putc(int ch, void *file) {
-
- // will not putc, no.
-}
-
-#ifdef __cplusplus
-}
-#endif
+
+#include "memory.h"
+#include "speex_bind.h"
+#include
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void *speex_alloc (int size) {
+
+ uint8_t * mem = (uint8_t*)memalloc(size);
+ for(int i=0;i<size;i++)
+ mem[i]=0;
+ return mem;
+}
+
+void *speex_alloc_scratch (int size) {
+
+ return memalloc(size);
+}
+
+void *speex_realloc (void *ptr, int size) {
+
+ return memrealloc(ptr,size);
+}
+
+void speex_free (void *ptr) {
+
+ memfree(ptr);
+}
+
+void speex_free_scratch (void *ptr) {
+
+ memfree(ptr);
+}
+
+void _speex_fatal(const char *str, const char *file, int line) {
+
+ _err_print_error("SPEEX ERROR",p_file,p_line,str);
+}
+
+void speex_warning(const char *str) {
+
+ _err_print_error("SPEEX WARNING","",0,str);
+}
+
+void speex_warning_int(const char *str, int val) {
+
+ _err_print_error("SPEEX WARNING INT","Value",val,str);
+}
+
+void speex_notify(const char *str) {
+
+ print_line(str);
+}
+
+void _speex_putc(int ch, void *file) {
+
+ // will not putc, no.
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/drivers/speex/speex_bind.h b/drivers/speex/speex_bind.h
index e842960d3c..c928430a33 100644
--- a/drivers/speex/speex_bind.h
+++ b/drivers/speex/speex_bind.h
@@ -1,48 +1,48 @@
-#ifndef SPEEX_BIND_H
-#define SPEEX_BIND_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
-#define OVERRIDE_SPEEX_ALLOC
-#define OVERRIDE_SPEEX_ALLOC_SCRATCH
-#define OVERRIDE_SPEEX_REALLOC
-#define OVERRIDE_SPEEX_FREE
-#define OVERRIDE_SPEEX_FREE_SCRATCH
-#define OVERRIDE_SPEEX_FATAL
-#define OVERRIDE_SPEEX_WARNING
-#define OVERRIDE_SPEEX_WARNING_INT
-#define OVERRIDE_SPEEX_NOTIFY
-#define OVERRIDE_SPEEX_PUTC
-
-void *speex_alloc (int size);
-void *speex_alloc_scratch (int size);
-void *speex_realloc (void *ptr, int size);
-void speex_free (void *ptr);
-void speex_free_scratch (void *ptr);
-void _speex_fatal(const char *str, const char *file, int line);
-void speex_warning(const char *str);
-void speex_warning_int(const char *str, int val);
-void speex_notify(const char *str);
-void _speex_putc(int ch, void *file);
-
-
-*/
-#define RELEASE
-#define SPEEX_PI 3.14159265358979323846
-
-#ifdef _MSC_VER
-#define SPEEX_INLINE __inline
-#else
-#define SPEEX_INLINE inline
-#endif
-
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // SPEEX_BIND_H
+#ifndef SPEEX_BIND_H
+#define SPEEX_BIND_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+#define OVERRIDE_SPEEX_ALLOC
+#define OVERRIDE_SPEEX_ALLOC_SCRATCH
+#define OVERRIDE_SPEEX_REALLOC
+#define OVERRIDE_SPEEX_FREE
+#define OVERRIDE_SPEEX_FREE_SCRATCH
+#define OVERRIDE_SPEEX_FATAL
+#define OVERRIDE_SPEEX_WARNING
+#define OVERRIDE_SPEEX_WARNING_INT
+#define OVERRIDE_SPEEX_NOTIFY
+#define OVERRIDE_SPEEX_PUTC
+
+void *speex_alloc (int size);
+void *speex_alloc_scratch (int size);
+void *speex_realloc (void *ptr, int size);
+void speex_free (void *ptr);
+void speex_free_scratch (void *ptr);
+void _speex_fatal(const char *str, const char *file, int line);
+void speex_warning(const char *str);
+void speex_warning_int(const char *str, int val);
+void speex_notify(const char *str);
+void _speex_putc(int ch, void *file);
+
+
+*/
+#define RELEASE
+#define SPEEX_PI 3.14159265358979323846
+
+#ifdef _MSC_VER
+#define SPEEX_INLINE __inline
+#else
+#define SPEEX_INLINE inline
+#endif
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // SPEEX_BIND_H
diff --git a/drivers/squish/SCsub b/drivers/squish/SCsub
index d55a32ad5e..da39dc1ebc 100644
--- a/drivers/squish/SCsub
+++ b/drivers/squish/SCsub
@@ -21,4 +21,3 @@ if (env["tools"]=="yes"):
#env.add_source_files(env.drivers_sources, squish_sources)
Export('env')
-
diff --git a/drivers/theora/SCsub b/drivers/theora/SCsub
index ecabce6c9d..fa85b49804 100644
--- a/drivers/theora/SCsub
+++ b/drivers/theora/SCsub
@@ -1,4 +1,3 @@
-
Import('env')
sources = [
@@ -32,7 +31,37 @@ sources = [
"theora/video_stream_theora.cpp",
]
-if env['use_theoraplayer_binary'] != "yes":
- env.drivers_sources += sources
+sources_x86 = [
+ "theora/x86/mmxencfrag.c",
+ "theora/x86/mmxfdct.c",
+ "theora/x86/mmxfrag.c",
+ "theora/x86/mmxidct.c",
+ "theora/x86/mmxstate.c",
+ "theora/x86/sse2fdct.c",
+ "theora/x86/x86enc.c",
+ "theora/x86/x86state.c",
+]
+
+sources_x86_vc = [
+ "theora/x86_vc/mmxencfrag.c",
+ "theora/x86_vc/mmxfdct.c",
+ "theora/x86_vc/mmxfrag.c",
+ "theora/x86_vc/mmxidct.c",
+ "theora/x86_vc/mmxstate.c",
+ "theora/x86_vc/x86enc.c",
+ "theora/x86_vc/x86state.c",
+]
+
+env.drivers_sources += sources
+
+if (env["x86_opt_gcc"]):
+ env.Append(CCFLAGS=["-DOC_X86_ASM"])
+ env.drivers_sources += sources_x86
+
+if (env["x86_opt_vc"]):
+ env.Append(CCFLAGS=["-DOC_X86_ASM"])
+ env.drivers_sources += sources_x86_vc
+
+
diff --git a/drivers/theora/decode.c b/drivers/theora/decode.c
index 7be66463d8..882606ae77 100644
--- a/drivers/theora/decode.c
+++ b/drivers/theora/decode.c
@@ -1611,28 +1611,35 @@ static void oc_filter_hedge(unsigned char *_dst,int _dst_ystride,
int sum1;
int bx;
int by;
+ int _rlimit1;
+ int _rlimit2;
rdst=_dst;
rsrc=_src;
- for(bx=0;bx<8;bx++){
+ for(bx=0;bx<8;++bx){
cdst=rdst;
csrc=rsrc;
- for(by=0;by<10;by++){
+ _rlimit1 = _rlimit2 = _flimit;
+ for(by=0;by<10;++by){
r[by]=*csrc;
csrc+=_src_ystride;
}
sum0=sum1=0;
- for(by=0;by<4;by++){
- sum0+=abs(r[by+1]-r[by]);
- sum1+=abs(r[by+5]-r[by+6]);
+ for(by=0;by<4;++by){
+ int sumed = abs(r[by+1]-r[by]);
+ sum0+=sumed;
+ _rlimit1-=sumed;
+ sumed = abs(r[by+5]-r[by+6]);
+ sum1+=sumed;
+ _rlimit2-=sumed;
}
*_variance0+=OC_MINI(255,sum0);
*_variance1+=OC_MINI(255,sum1);
- if(sum0<_flimit&&sum1<_flimit&&r[5]-r[4]<_qstep&&r[4]-r[5]<_qstep){
+ if(_rlimit1&&_rlimit2&&!(r[5]-r[4]-_qstep)&&!(r[4]-r[5]-_qstep)){
*cdst=(unsigned char)(r[0]*3+r[1]*2+r[2]+r[3]+r[4]+4>>3);
cdst+=_dst_ystride;
*cdst=(unsigned char)(r[0]*2+r[1]+r[2]*2+r[3]+r[4]+r[5]+4>>3);
cdst+=_dst_ystride;
- for(by=0;by<4;by++){
+ for(by=0;by<4;++by){
*cdst=(unsigned char)(r[by]+r[by+1]+r[by+2]+r[by+3]*2+
r[by+4]+r[by+5]+r[by+6]+4>>3);
cdst+=_dst_ystride;
@@ -1642,13 +1649,13 @@ static void oc_filter_hedge(unsigned char *_dst,int _dst_ystride,
*cdst=(unsigned char)(r[5]+r[6]+r[7]+r[8]*2+r[9]*3+4>>3);
}
else{
- for(by=1;by<=8;by++){
+ for(by=1;by<=8;++by){
*cdst=(unsigned char)r[by];
cdst+=_dst_ystride;
}
}
- rdst++;
- rsrc++;
+ ++rdst;
+ ++rsrc;
}
}
@@ -1663,19 +1670,26 @@ static void oc_filter_vedge(unsigned char *_dst,int _dst_ystride,
int sum1;
int bx;
int by;
+ int _rlimit1;
+ int _rlimit2;
cdst=_dst;
- for(by=0;by<8;by++){
+ for(by=0;by<8;++by){
rsrc=cdst-1;
rdst=cdst;
- for(bx=0;bx<10;bx++)r[bx]=*rsrc++;
+ for(bx=0;bx<10;++bx)r[bx]=*rsrc++;
sum0=sum1=0;
- for(bx=0;bx<4;bx++){
- sum0+=abs(r[bx+1]-r[bx]);
- sum1+=abs(r[bx+5]-r[bx+6]);
+ _rlimit1 = _rlimit2 = _flimit;
+ for(bx=0;bx<4;++bx){
+ int sumed = abs(r[bx+1]-r[bx]);
+ sum0+=sumed;
+ _rlimit1-=sumed;
+ sumed = abs(r[bx+5]-r[bx+6]);
+ sum1+=sumed;
+ _rlimit2-=sumed;
}
_variances[0]+=OC_MINI(255,sum0);
_variances[1]+=OC_MINI(255,sum1);
- if(sum0<_flimit&&sum1<_flimit&&r[5]-r[4]<_qstep&&r[4]-r[5]<_qstep){
+ if(_rlimit1&&_rlimit2&&!(r[5]-r[4]-_qstep)&&!(r[4]-r[5]-_qstep)){
*rdst++=(unsigned char)(r[0]*3+r[1]*2+r[2]+r[3]+r[4]+4>>3);
*rdst++=(unsigned char)(r[0]*2+r[1]+r[2]*2+r[3]+r[4]+r[5]+4>>3);
for(bx=0;bx<4;bx++){
diff --git a/drivers/theora/encint.h b/drivers/theora/encint.h
index 97897d5a04..82338256dc 100644
--- a/drivers/theora/encint.h
+++ b/drivers/theora/encint.h
@@ -14,6 +14,7 @@
last mod: $Id: encint.h 16503 2009-08-22 18:14:02Z giles $
********************************************************************/
+
#if !defined(_encint_H)
# define _encint_H (1)
# if defined(HAVE_CONFIG_H)
diff --git a/drivers/theora/video_stream_theora.cpp b/drivers/theora/video_stream_theora.cpp
index 214185cf88..0659f007e5 100644
--- a/drivers/theora/video_stream_theora.cpp
+++ b/drivers/theora/video_stream_theora.cpp
@@ -1,50 +1,49 @@
#ifdef THEORA_ENABLED
-#if 0
+
#include "video_stream_theora.h"
#include "os/os.h"
#include "yuv2rgb.h"
+#include "globals.h"
-AudioStream::UpdateMode VideoStreamTheora::get_update_mode() const {
+int VideoStreamPlaybackTheora:: buffer_data() {
- return UPDATE_IDLE;
-};
+ char *buffer=ogg_sync_buffer(&oy,4096);
-int VideoStreamTheora:: buffer_data() {
- char *buffer=ogg_sync_buffer(&oy,4096);
- int bytes=file->get_buffer((uint8_t*)buffer, 4096);
+#ifdef THEORA_USE_THREAD_STREAMING
- ogg_sync_wrote(&oy,bytes);
- return(bytes);
-}
+ int read;
-int VideoStreamTheora::queue_page(ogg_page *page){
- if(theora_p)ogg_stream_pagein(&to,page);
- if(vorbis_p)ogg_stream_pagein(&vo,page);
- return 0;
-}
-
-Image VideoStreamTheora::peek_frame() const {
+ do {
+ thread_sem->post();
+ read = MIN(ring_buffer.data_left(),4096);
+ if (read) {
+ ring_buffer.read((uint8_t*)buffer,read);
+ ogg_sync_wrote(&oy,read);
+ } else {
+ OS::get_singleton()->delay_usec(100);
+ }
- if (frames_pending == 0)
- return Image();
- return Image(size.x, size.y, 0, format, frame_data);
-};
+ } while(read==0);
-Image VideoStreamTheora::pop_frame() {
+ return read;
- Image ret = peek_frame();
- frames_pending = 0;
+#else
- return ret;
-};
+ int bytes=file->get_buffer((uint8_t*)buffer, 4096);
+ ogg_sync_wrote(&oy,bytes);
+ return(bytes);
-int VideoStreamTheora::get_pending_frame_count() const {
+#endif
+}
- return frames_pending;
-};
+int VideoStreamPlaybackTheora::queue_page(ogg_page *page){
+ if(theora_p)ogg_stream_pagein(&to,page);
+ if(vorbis_p)ogg_stream_pagein(&vo,page);
+ return 0;
+}
-void VideoStreamTheora::video_write(void){
+void VideoStreamPlaybackTheora::video_write(void){
th_ycbcr_buffer yuv;
int y_offset, uv_offset;
th_decode_ycbcr_out(td,yuv);
@@ -78,25 +77,31 @@ void VideoStreamTheora::video_write(void){
int pitch = 4;
frame_data.resize(size.x * size.y * pitch);
- DVector<uint8_t>::Write w = frame_data.write();
- char* dst = (char*)w.ptr();
+ {
+ DVector<uint8_t>::Write w = frame_data.write();
+ char* dst = (char*)w.ptr();
- uv_offset=(ti.pic_x/2)+(yuv[1].stride)*(ti.pic_y/2);
+ uv_offset=(ti.pic_x/2)+(yuv[1].stride)*(ti.pic_y/2);
- if (px_fmt == TH_PF_444) {
+ if (px_fmt == TH_PF_444) {
- yuv444_2_rgb8888((uint8_t*)dst, (uint8_t*)yuv[0].data, (uint8_t*)yuv[1].data, (uint8_t*)yuv[2].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x<<2, 0);
+ yuv444_2_rgb8888((uint8_t*)dst, (uint8_t*)yuv[0].data, (uint8_t*)yuv[1].data, (uint8_t*)yuv[2].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x<<2, 0);
- } else if (px_fmt == TH_PF_422) {
+ } else if (px_fmt == TH_PF_422) {
- yuv422_2_rgb8888((uint8_t*)dst, (uint8_t*)yuv[0].data, (uint8_t*)yuv[1].data, (uint8_t*)yuv[2].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x<<2, 0);
+ yuv422_2_rgb8888((uint8_t*)dst, (uint8_t*)yuv[0].data, (uint8_t*)yuv[1].data, (uint8_t*)yuv[2].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x<<2, 0);
- } else if (px_fmt == TH_PF_420) {
+ } else if (px_fmt == TH_PF_420) {
- yuv420_2_rgb8888((uint8_t*)dst, (uint8_t*)yuv[0].data, (uint8_t*)yuv[2].data, (uint8_t*)yuv[1].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x<<2, 0);
- };
+ yuv420_2_rgb8888((uint8_t*)dst, (uint8_t*)yuv[0].data, (uint8_t*)yuv[2].data, (uint8_t*)yuv[1].data, size.x, size.y, yuv[0].stride, yuv[1].stride, size.x<<2, 0);
+ };
- format = Image::FORMAT_RGBA;
+ format = Image::FORMAT_RGBA;
+ }
+
+ Image img(size.x,size.y,0,Image::FORMAT_RGBA,frame_data); //zero copy image creation
+
+ texture->set_data(img); //zero copy send to visual server
/*
@@ -194,9 +199,9 @@ void VideoStreamTheora::video_write(void){
frames_pending = 1;
}
-void VideoStreamTheora::clear() {
+void VideoStreamPlaybackTheora::clear() {
- if (file_name == "")
+ if (!file)
return;
if(vorbis_p){
@@ -218,7 +223,15 @@ void VideoStreamTheora::clear() {
}
ogg_sync_clear(&oy);
- file_name = "";
+#ifdef THEORA_USE_THREAD_STREAMING
+ thread_exit=true;
+ thread_sem->post(); //just in case
+ Thread::wait_to_finish(thread);
+ memdelete(thread);
+ thread=NULL;
+ ring_buffer.clear();
+#endif
+ //file_name = "";
theora_p = 0;
vorbis_p = 0;
@@ -226,11 +239,16 @@ void VideoStreamTheora::clear() {
frames_pending = 0;
videobuf_time = 0;
+ if (file) {
+ memdelete(file);
+ }
+ file=NULL;
playing = false;
};
-void VideoStreamTheora::set_file(const String& p_file) {
+void VideoStreamPlaybackTheora::set_file(const String& p_file) {
+ ERR_FAIL_COND(playing);
ogg_packet op;
th_setup_info *ts = NULL;
@@ -241,7 +259,17 @@ void VideoStreamTheora::set_file(const String& p_file) {
file = FileAccess::open(p_file, FileAccess::READ);
ERR_FAIL_COND(!file);
- audio_frames_wrote = 0;
+#ifdef THEORA_USE_THREAD_STREAMING
+ thread_exit=false;
+ thread_eof=false;
+ //pre-fill buffer
+ int to_read = ring_buffer.space_left();
+ int read = file->get_buffer(read_buffer.ptr(),to_read);
+ ring_buffer.write(read_buffer.ptr(),read);
+
+ thread=Thread::create(_streaming_thread,this);
+
+#endif
ogg_sync_init(&oy);
@@ -256,6 +284,10 @@ void VideoStreamTheora::set_file(const String& p_file) {
/* Ogg file open; parse the headers */
/* Only interested in Vorbis/Theora streams */
int stateflag = 0;
+
+ int audio_track_skip=audio_track;
+
+
while(!stateflag){
int ret=buffer_data();
if(ret==0)break;
@@ -281,9 +313,21 @@ void VideoStreamTheora::set_file(const String& p_file) {
copymem(&to,&test,sizeof(test));
theora_p=1;
}else if(!vorbis_p && vorbis_synthesis_headerin(&vi,&vc,&op)>=0){
+
+
/* it is vorbis */
- copymem(&vo,&test,sizeof(test));
- vorbis_p=1;
+ if (audio_track_skip) {
+ vorbis_info_clear(&vi);
+ vorbis_comment_clear(&vc);
+ ogg_stream_clear(&test);
+ vorbis_info_init(&vi);
+ vorbis_comment_init(&vc);
+
+ audio_track_skip--;
+ } else {
+ copymem(&vo,&test,sizeof(test));
+ vorbis_p=1;
+ }
}else{
/* whatever it is, we don't care about it */
ogg_stream_clear(&test);
@@ -367,6 +411,7 @@ void VideoStreamTheora::set_file(const String& p_file) {
th_decode_ctl(td,TH_DECCTL_GET_PPLEVEL_MAX,&pp_level_max,
sizeof(pp_level_max));
pp_level=pp_level_max;
+ pp_level=0;
th_decode_ctl(td,TH_DECCTL_SET_PPLEVEL,&pp_level,sizeof(pp_level));
pp_inc=0;
@@ -386,6 +431,8 @@ void VideoStreamTheora::set_file(const String& p_file) {
size.x = w;
size.y = h;
+ texture->create(w,h,Image::FORMAT_RGBA,Texture::FLAG_FILTER|Texture::FLAG_VIDEO_SURFACE);
+
}else{
/* tear down the partial theora setup */
th_info_clear(&ti);
@@ -399,7 +446,8 @@ void VideoStreamTheora::set_file(const String& p_file) {
vorbis_block_init(&vd,&vb);
fprintf(stderr,"Ogg logical stream %lx is Vorbis %d channel %ld Hz audio.\n",
vo.serialno,vi.channels,vi.rate);
- _setup(vi.channels, vi.rate);
+ //_setup(vi.channels, vi.rate);
+
}else{
/* tear down the partial vorbis setup */
vorbis_info_clear(&vi);
@@ -409,229 +457,374 @@ void VideoStreamTheora::set_file(const String& p_file) {
playing = false;
buffering=true;
time=0;
+ audio_frames_wrote=0;
+
+
};
-float VideoStreamTheora::get_time() const {
+float VideoStreamPlaybackTheora::get_time() const {
//print_line("total: "+itos(get_total())+" todo: "+itos(get_todo()));
//return MAX(0,time-((get_total())/(float)vi.rate));
- return time-((get_total())/(float)vi.rate);
+ return time-AudioServer::get_singleton()->get_output_delay()-delay_compensation;//-((get_total())/(float)vi.rate);
};
-void VideoStreamTheora::update() {
+Ref<Texture> VideoStreamPlaybackTheora::get_texture() {
+
+ return texture;
+}
- if (!playing) {
+void VideoStreamPlaybackTheora::update(float p_delta) {
+
+ if (!playing || paused) {
//printf("not playing\n");
return;
};
- double ctime =AudioServer::get_singleton()->get_mix_time();
- if (last_update_time) {
- double delta = (ctime-last_update_time);
- time+=delta;
- //print_line("delta: "+rtos(delta));
+
+#ifdef THEORA_USE_THREAD_STREAMING
+ thread_sem->post();
+#endif
+
+ //double ctime =AudioServer::get_singleton()->get_mix_time();
+
+ //print_line("play "+rtos(p_delta));
+ time+=p_delta;
+
+ if (videobuf_time>get_time()) {
+ return; //no new frames need to be produced
}
- last_update_time=ctime;
+ bool frame_done=false;
+ bool audio_done=false;
- int audio_todo = get_todo();
- ogg_packet op;
- int audio_pending = 0;
+ while (!frame_done || !audio_done) {
+ //a frame needs to be produced
+ ogg_packet op;
+ bool audio_pending = false;
- while (vorbis_p && audio_todo) {
- int ret;
- float **pcm;
-
- /* if there's pending, decoded audio, grab it */
- if ((ret=vorbis_synthesis_pcmout(&vd,&pcm))>0) {
-
- audio_pending = ret;
- int16_t* out = get_write_buffer();
- int count = 0;
- int to_read = MIN(ret, audio_todo);
- for (int i=0; i<to_read; i++) {
-
- for(int j=0;j<vi.channels;j++){
- int val=Math::fast_ftoi(pcm[j][i]*32767.f);
- if(val>32767)val=32767;
- if(val<-32768)val=-32768;
- out[count++] = val;
- };
- };
- int tr = vorbis_synthesis_read(&vd, to_read);
- audio_todo -= to_read;
- audio_frames_wrote += to_read;
- write(to_read);
- audio_pending -= to_read;
- if (audio_todo==0)
- buffering=false;
+
+ bool no_vorbis=false;
+ bool no_theora=false;
+
+
+ while (vorbis_p) {
+ int ret;
+ float **pcm;
+
+ bool buffer_full=false;
+
+ /* if there's pending, decoded audio, grab it */
+ if ((ret=vorbis_synthesis_pcmout(&vd,&pcm))>0) {
- } else {
- /* no pending audio; is there a pending packet to decode? */
- if (ogg_stream_packetout(&vo,&op)>0){
- if(vorbis_synthesis(&vb,&op)==0) { /* test for success! */
- vorbis_synthesis_blockin(&vd,&vb);
+ const int AUXBUF_LEN=4096;
+ int to_read = ret;
+ int16_t aux_buffer[AUXBUF_LEN];
+
+ while(to_read) {
+
+ int m = MIN(AUXBUF_LEN/vi.channels,to_read);
+
+ int count = 0;
+
+ for(int j=0;j<m;j++){
+ for(int i=0;i<vi.channels;i++){
+
+ int val=Math::fast_ftoi(pcm[i][j]*32767.f);
+ if(val>32767)val=32767;
+ if(val<-32768)val=-32768;
+ aux_buffer[count++] = val;
+ }
+ }
+
+ if (mix_callback) {
+ int mixed = mix_callback(mix_udata,aux_buffer,m);
+ to_read-=mixed;
+ if (mixed!=m) { //could mix no more
+ buffer_full=true;
+ break;
+ }
+ } else {
+ to_read-=m; //just pretend we sent the audio
+ }
+
+
}
- } else { /* we need more data; break out to suck in another page */
- //printf("need moar data\n");
+
+
+ int tr = vorbis_synthesis_read(&vd, ret-to_read);
+
+ audio_pending=true;
+
+
+ if (vd.granulepos>=0) {
+ // print_line("wrote: "+itos(audio_frames_wrote)+" gpos: "+itos(vd.granulepos));
+ }
+
+ //print_line("mix audio!");
+
+ audio_frames_wrote+=ret-to_read;
+
+ //print_line("AGP: "+itos(vd.granulepos)+" added "+itos(ret-to_read));
+
+
+ } else {
+
+ /* no pending audio; is there a pending packet to decode? */
+ if (ogg_stream_packetout(&vo,&op)>0){
+ if(vorbis_synthesis(&vb,&op)==0) { /* test for success! */
+ vorbis_synthesis_blockin(&vd,&vb);
+ }
+ } else { /* we need more data; break out to suck in another page */
+ //printf("need moar data\n");
+ no_vorbis=true;
+ break;
+ };
+ }
+
+
+ audio_done = videobuf_time < (audio_frames_wrote/float(vi.rate));
+
+ if (buffer_full)
break;
- };
}
- }
- while(theora_p && !videobuf_ready){
- /* theora is one in, one out... */
- if(ogg_stream_packetout(&to,&op)>0){
+ while(theora_p && !frame_done){
+ /* theora is one in, one out... */
+ if(ogg_stream_packetout(&to,&op)>0){
- if(pp_inc){
- pp_level+=pp_inc;
- th_decode_ctl(td,TH_DECCTL_SET_PPLEVEL,&pp_level,
- sizeof(pp_level));
- pp_inc=0;
- }
- /*HACK: This should be set after a seek or a gap, but we might not have
- a granulepos for the first packet (we only have them for the last
- packet on a page), so we just set it as often as we get it.
- To do this right, we should back-track from the last packet on the
- page and compute the correct granulepos for the first packet after
- a seek or a gap.*/
- if(op.granulepos>=0){
- th_decode_ctl(td,TH_DECCTL_SET_GRANPOS,&op.granulepos,
- sizeof(op.granulepos));
- }
- ogg_int64_t videobuf_granulepos;
- if(th_decode_packetin(td,&op,&videobuf_granulepos)==0){
- videobuf_time=th_granule_time(td,videobuf_granulepos);
- //printf("frame time %f, play time %f, ready %i\n", (float)videobuf_time, get_time(), videobuf_ready);
-
- /* is it already too old to be useful? This is only actually
- useful cosmetically after a SIGSTOP. Note that we have to
- decode the frame even if we don't show it (for now) due to
- keyframing. Soon enough libtheora will be able to deal
- with non-keyframe seeks. */
-
- if(videobuf_time>=get_time())
- videobuf_ready=1;
- else{
- /*If we are too slow, reduce the pp level.*/
- pp_inc=pp_level>0?-1:0;
+ if(false && pp_inc){
+ pp_level+=pp_inc;
+ th_decode_ctl(td,TH_DECCTL_SET_PPLEVEL,&pp_level,
+ sizeof(pp_level));
+ pp_inc=0;
+ }
+ /*HACK: This should be set after a seek or a gap, but we might not have
+ a granulepos for the first packet (we only have them for the last
+ packet on a page), so we just set it as often as we get it.
+ To do this right, we should back-track from the last packet on the
+ page and compute the correct granulepos for the first packet after
+ a seek or a gap.*/
+ if(op.granulepos>=0){
+ th_decode_ctl(td,TH_DECCTL_SET_GRANPOS,&op.granulepos,
+ sizeof(op.granulepos));
+ }
+ ogg_int64_t videobuf_granulepos;
+ if(th_decode_packetin(td,&op,&videobuf_granulepos)==0){
+ videobuf_time=th_granule_time(td,videobuf_granulepos);
+
+ //printf("frame time %f, play time %f, ready %i\n", (float)videobuf_time, get_time(), videobuf_ready);
+
+ /* is it already too old to be useful? This is only actually
+ useful cosmetically after a SIGSTOP. Note that we have to
+ decode the frame even if we don't show it (for now) due to
+ keyframing. Soon enough libtheora will be able to deal
+ with non-keyframe seeks. */
+
+ if(videobuf_time>=get_time()) {
+ frame_done=true;
+ } else{
+ /*If we are too slow, reduce the pp level.*/
+ pp_inc=pp_level>0?-1:0;
+ }
+ } else {
+
}
+
+ } else {
+ no_theora=true;
+ break;
}
+ }
+#ifdef THEORA_USE_THREAD_STREAMING
+ if (file && thread_eof && (no_vorbis || no_theora) && ring_buffer.data_left()==0) {
+#else
+ if (file && /*!videobuf_ready && */ (no_vorbis || no_theora) && file->eof_reached()) {
+#endif
+ printf("video done, stopping\n");
+ stop();
+ return;
+ };
+ #if 0
+ if (!videobuf_ready || audio_todo > 0){
+ /* no data yet for somebody. Grab another page */
- } else
- break;
- }
+ buffer_data();
+ while(ogg_sync_pageout(&oy,&og)>0){
+ queue_page(&og);
+ }
+ }
+ #else
- if (/*!videobuf_ready && */ audio_pending == 0 && file->eof_reached()) {
- printf("video done, stopping\n");
- stop();
- return;
- };
- if (!videobuf_ready || audio_todo > 0){
- /* no data yet for somebody. Grab another page */
+ if (!frame_done || !audio_done){
+ //what's the point of waiting for audio to grab a page?
- buffer_data();
- while(ogg_sync_pageout(&oy,&og)>0){
- queue_page(&og);
+ buffer_data();
+ while(ogg_sync_pageout(&oy,&og)>0){
+ queue_page(&og);
+ }
}
- }
+ #endif
+ /* If playback has begun, top audio buffer off immediately. */
+ //if(stateflag) audio_write_nonblocking();
- /* If playback has begun, top audio buffer off immediately. */
- //if(stateflag) audio_write_nonblocking();
+ /* are we at or past time for this video frame? */
+ if(videobuf_ready && videobuf_time<=get_time()){
- /* are we at or past time for this video frame? */
- if(videobuf_ready && videobuf_time<=get_time()){
+ //video_write();
+ //videobuf_ready=0;
+ } else {
+ //printf("frame at %f not ready (time %f), ready %i\n", (float)videobuf_time, get_time(), videobuf_ready);
+ }
- video_write();
- videobuf_ready=0;
- } else {
- //printf("frame at %f not ready (time %f), ready %i\n", (float)videobuf_time, get_time(), videobuf_ready);
- }
+ float tdiff=videobuf_time-get_time();
+ /*If we have lots of extra time, increase the post-processing level.*/
+ if(tdiff>ti.fps_denominator*0.25/ti.fps_numerator){
+ pp_inc=pp_level<pp_level_max?1:0;
+ }
+ else if(tdiff<ti.fps_denominator*0.05/ti.fps_numerator){
+ pp_inc=pp_level>0?-1:0;
+ }
- float tdiff=videobuf_time-get_time();
- /*If we have lots of extra time, increase the post-processing level.*/
- if(tdiff>ti.fps_denominator*0.25/ti.fps_numerator){
- pp_inc=pp_level<pp_level_max?1:0;
- }
- else if(tdiff<ti.fps_denominator*0.05/ti.fps_numerator){
- pp_inc=pp_level>0?-1:0;
}
-};
-bool VideoStreamTheora::_can_mix() const {
+ video_write();
- return !buffering;
};
-void VideoStreamTheora::play() {
+
+void VideoStreamPlaybackTheora::play() {
if (!playing)
- last_update_time=0;
+ time=0;
+ else {
+ stop();
+ }
+
playing = true;
+ delay_compensation=Globals::get_singleton()->get("audio/video_delay_compensation_ms");
+ delay_compensation/=1000.0;
+
+
};
-void VideoStreamTheora::stop() {
+void VideoStreamPlaybackTheora::stop() {
+
+ if (playing) {
+ clear();
+ set_file(file_name); //reset
+ }
playing = false;
- last_update_time=0;
+ time=0;
};
-bool VideoStreamTheora::is_playing() const {
+bool VideoStreamPlaybackTheora::is_playing() const {
return playing;
};
-void VideoStreamTheora::set_paused(bool p_paused) {
+void VideoStreamPlaybackTheora::set_paused(bool p_paused) {
- playing = !p_paused;
+ paused=p_paused;
+ //pau = !p_paused;
};
-bool VideoStreamTheora::is_paused(bool p_paused) const {
+bool VideoStreamPlaybackTheora::is_paused(bool p_paused) const {
- return playing;
+ return paused;
};
-void VideoStreamTheora::set_loop(bool p_enable) {
+void VideoStreamPlaybackTheora::set_loop(bool p_enable) {
};
-bool VideoStreamTheora::has_loop() const {
+bool VideoStreamPlaybackTheora::has_loop() const {
return false;
};
-float VideoStreamTheora::get_length() const {
+float VideoStreamPlaybackTheora::get_length() const {
return 0;
};
-String VideoStreamTheora::get_stream_name() const {
+String VideoStreamPlaybackTheora::get_stream_name() const {
return "";
};
-int VideoStreamTheora::get_loop_count() const {
+int VideoStreamPlaybackTheora::get_loop_count() const {
return 0;
};
-float VideoStreamTheora::get_pos() const {
+float VideoStreamPlaybackTheora::get_pos() const {
return get_time();
};
-void VideoStreamTheora::seek_pos(float p_time) {
+void VideoStreamPlaybackTheora::seek_pos(float p_time) {
// no
};
-VideoStreamTheora::VideoStreamTheora() {
+void VideoStreamPlaybackTheora::set_mix_callback(AudioMixCallback p_callback,void *p_userdata) {
+
+ mix_callback=p_callback;
+ mix_udata=p_userdata;
+}
+
+int VideoStreamPlaybackTheora::get_channels() const{
+
+ return vi.channels;
+}
+
+void VideoStreamPlaybackTheora::set_audio_track(int p_idx) {
+
+ audio_track=p_idx;
+}
+
+int VideoStreamPlaybackTheora::get_mix_rate() const{
+
+ return vi.rate;
+}
+
+#ifdef THEORA_USE_THREAD_STREAMING
+
+
+void VideoStreamPlaybackTheora::_streaming_thread(void *ud) {
+
+ VideoStreamPlaybackTheora *vs=(VideoStreamPlaybackTheora*)ud;
+
+ while(!vs->thread_exit) {
+
+ //just fill back the buffer
+ if (!vs->thread_eof) {
+
+ int to_read = vs->ring_buffer.space_left();
+ if (to_read) {
+ int read = vs->file->get_buffer(vs->read_buffer.ptr(),to_read);
+ vs->ring_buffer.write(vs->read_buffer.ptr(),read);
+ vs->thread_eof=vs->file->eof_reached();
+ }
+
+
+ }
+
+ vs->thread_sem->wait();
+ }
+}
+
+#endif
+
+VideoStreamPlaybackTheora::VideoStreamPlaybackTheora() {
file = NULL;
theora_p = 0;
@@ -640,23 +833,53 @@ VideoStreamTheora::VideoStreamTheora() {
playing = false;
frames_pending = 0;
videobuf_time = 0;
- last_update_time =0;
+ paused=false;
+
buffering=false;
+ texture = Ref<ImageTexture>( memnew(ImageTexture ));
+ mix_callback=NULL;
+ mix_udata=NULL;
+ audio_track=0;
+ delay_compensation=0;
+ audio_frames_wrote=0;
+
+#ifdef THEORA_USE_THREAD_STREAMING
+ int rb_power = nearest_shift(RB_SIZE_KB*1024);
+ ring_buffer.resize(rb_power);
+ read_buffer.resize(RB_SIZE_KB*1024);
+ thread_sem=Semaphore::create();
+ thread=NULL;
+ thread_exit=false;
+ thread_eof=false;
+
+#endif
};
-VideoStreamTheora::~VideoStreamTheora() {
+VideoStreamPlaybackTheora::~VideoStreamPlaybackTheora() {
+
+#ifdef THEORA_USE_THREAD_STREAMING
+ memdelete(thread_sem);
+#endif
clear();
if (file)
memdelete(file);
+
+
};
-RES ResourceFormatLoaderVideoStreamTheora::load(const String &p_path,const String& p_original_path) {
+RES ResourceFormatLoaderVideoStreamTheora::load(const String &p_path,const String& p_original_path, Error *r_error) {
+ if (r_error)
+ *r_error=ERR_FILE_CANT_OPEN;
VideoStreamTheora *stream = memnew(VideoStreamTheora);
stream->set_file(p_path);
+
+ if (r_error)
+ *r_error=OK;
+
return Ref<VideoStreamTheora>(stream);
}
@@ -666,16 +889,16 @@ void ResourceFormatLoaderVideoStreamTheora::get_recognized_extensions(List<Strin
p_extensions->push_back("ogv");
}
bool ResourceFormatLoaderVideoStreamTheora::handles_type(const String& p_type) const {
- return (p_type=="AudioStream" || p_type=="VideoStreamTheora");
+ return (p_type=="VideoStream" || p_type=="VideoStreamTheora");
}
String ResourceFormatLoaderVideoStreamTheora::get_resource_type(const String &p_path) const {
String exl=p_path.extension().to_lower();
if (exl=="ogm" || exl=="ogv")
- return "AudioStreamTheora";
+ return "VideoStreamTheora";
return "";
}
#endif
-#endif
+
diff --git a/drivers/theora/video_stream_theora.h b/drivers/theora/video_stream_theora.h
index b408f9db13..3e144c0125 100644
--- a/drivers/theora/video_stream_theora.h
+++ b/drivers/theora/video_stream_theora.h
@@ -6,13 +6,17 @@
#include "theora/theoradec.h"
#include "vorbis/codec.h"
#include "os/file_access.h"
-
+#include "ring_buffer.h"
#include "io/resource_loader.h"
#include "scene/resources/video_stream.h"
+#include "os/thread.h"
+#include "os/semaphore.h"
-class VideoStreamTheora : public VideoStream {
+//#define THEORA_USE_THREAD_STREAMING
+
+class VideoStreamPlaybackTheora : public VideoStreamPlayback {
- OBJ_TYPE(VideoStreamTheora, VideoStream);
+ OBJ_TYPE(VideoStreamPlaybackTheora, VideoStreamPlayback);
enum {
MAX_FRAMES = 4,
@@ -32,6 +36,7 @@ class VideoStreamTheora : public VideoStream {
void video_write(void);
float get_time() const;
+
ogg_sync_state oy;
ogg_page og;
ogg_stream_state vo;
@@ -58,16 +63,38 @@ class VideoStreamTheora : public VideoStream {
double last_update_time;
double time;
+ double delay_compensation;
-protected:
+ Ref<ImageTexture> texture;
- virtual UpdateMode get_update_mode() const;
- virtual void update();
+ AudioMixCallback mix_callback;
+ void* mix_udata;
+ bool paused;
- void clear();
+#ifdef THEORA_USE_THREAD_STREAMING
+
+ enum {
+ RB_SIZE_KB=1024
+ };
- virtual bool _can_mix() const;
+ RingBuffer<uint8_t> ring_buffer;
+ Vector<uint8_t> read_buffer;
+ bool thread_eof;
+ Semaphore *thread_sem;
+ Thread *thread;
+ volatile bool thread_exit;
+ static void _streaming_thread(void *ud);
+
+#endif
+
+
+ int audio_track;
+
+protected:
+
+ void clear();
+
public:
virtual void play();
@@ -92,17 +119,48 @@ public:
void set_file(const String& p_file);
- int get_pending_frame_count() const;
- Image pop_frame();
- Image peek_frame() const;
+ virtual Ref<Texture> get_texture();
+ virtual void update(float p_delta);
+
+ virtual void set_mix_callback(AudioMixCallback p_callback,void *p_userdata);
+ virtual int get_channels() const;
+ virtual int get_mix_rate() const;
+
+ virtual void set_audio_track(int p_idx);
+
+ VideoStreamPlaybackTheora();
+ ~VideoStreamPlaybackTheora();
+};
+
+
+
+class VideoStreamTheora : public VideoStream {
+
+ OBJ_TYPE(VideoStreamTheora,VideoStream);
+
+ String file;
+ int audio_track;
+
+
+public:
+
+ Ref<VideoStreamPlayback> instance_playback() {
+ Ref<VideoStreamPlaybackTheora> pb = memnew( VideoStreamPlaybackTheora );
+ pb->set_audio_track(audio_track);
+ pb->set_file(file);
+ return pb;
+ }
+
+ void set_file(const String& p_file) { file=p_file; }
+ void set_audio_track(int p_track) { audio_track=p_track; }
+
+ VideoStreamTheora() { audio_track=0; }
- VideoStreamTheora();
- ~VideoStreamTheora();
};
class ResourceFormatLoaderVideoStreamTheora : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path,const String& p_original_path="");
+ virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String& p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/drivers/theoraplayer/SCsub b/drivers/theoraplayer/SCsub
deleted file mode 100644
index 09fb13d8e9..0000000000
--- a/drivers/theoraplayer/SCsub
+++ /dev/null
@@ -1,106 +0,0 @@
-Import("env")
-
-import string
-
-sources = string.split("""
-src/TheoraVideoClip.cpp
-src/FFmpeg/TheoraVideoClip_FFmpeg.cpp
-src/TheoraAsync.cpp
-src/TheoraAudioInterface.cpp
-src/TheoraException.cpp
-src/TheoraWorkerThread.cpp
-src/TheoraVideoManager.cpp
-src/TheoraTimer.cpp
-src/TheoraUtil.cpp
-src/TheoraDataSource.cpp
-src/TheoraAudioPacketQueue.cpp
-src/TheoraFrameQueue.cpp
-src/Theora/TheoraVideoClip_Theora.cpp
-src/YUV/yuv_util.c
-src/YUV/libyuv/src/row_any.cc
-src/YUV/libyuv/src/compare_common.cc
-src/YUV/libyuv/src/scale_neon.cc
-src/YUV/libyuv/src/planar_functions.cc
-src/YUV/libyuv/src/compare.cc
-src/YUV/libyuv/src/scale_mips.cc
-src/YUV/libyuv/src/scale_posix.cc
-src/YUV/libyuv/src/row_posix.cc
-src/YUV/libyuv/src/row_win.cc
-src/YUV/libyuv/src/compare_neon.cc
-src/YUV/libyuv/src/convert_from_argb.cc
-src/YUV/libyuv/src/mjpeg_validate.cc
-src/YUV/libyuv/src/convert_from.cc
-src/YUV/libyuv/src/rotate_neon.cc
-src/YUV/libyuv/src/row_neon.cc
-src/YUV/libyuv/src/rotate_mips.cc
-src/YUV/libyuv/src/compare_posix.cc
-src/YUV/libyuv/src/row_mips.cc
-src/YUV/libyuv/src/scale.cc
-src/YUV/libyuv/src/scale_argb.cc
-src/YUV/libyuv/src/mjpeg_decoder.cc
-src/YUV/libyuv/src/scale_win.cc
-src/YUV/libyuv/src/scale_common.cc
-src/YUV/libyuv/src/scale_argb_neon.cc
-src/YUV/libyuv/src/row_common.cc
-src/YUV/libyuv/src/convert.cc
-src/YUV/libyuv/src/format_conversion.cc
-src/YUV/libyuv/src/rotate_argb.cc
-src/YUV/libyuv/src/rotate.cc
-src/YUV/libyuv/src/convert_argb.cc
-src/YUV/libyuv/src/cpu_id.cc
-src/YUV/libyuv/src/video_common.cc
-src/YUV/libyuv/src/convert_to_argb.cc
-src/YUV/libyuv/src/compare_win.cc
-src/YUV/libyuv/src/convert_to_i420.cc
-src/YUV/libyuv/src/convert_jpeg.cc
-src/YUV/libyuv/yuv_libyuv.c
-src/YUV/android/cpu-features.c
-src/YUV/C/yuv420_grey_c.c
-src/YUV/C/yuv420_yuv_c.c
-src/YUV/C/yuv420_rgb_c.c
-src/TheoraVideoFrame.cpp
-""")
-
-env_theora = env.Clone()
-
-if env["platform"] == "iphone":
- sources.append("src/AVFoundation/TheoraVideoClip_AVFoundation.mm")
- env.Append(LINKFLAGS=['-framework', 'CoreVideo', '-framework', 'CoreMedia', '-framework', 'AVFoundation'])
- if env["target"] == "release":
- env_theora.Append(CPPFLAGS=["-D_IOS", "-D__ARM_NEON__", "-fstrict-aliasing", "-fmessage-length=210", "-fdiagnostics-show-note-include-stack", "-fmacro-backtrace-limit=0", "-fcolor-diagnostics", "-Wno-trigraphs", "-fpascal-strings", "-fvisibility=hidden", "-fvisibility-inlines-hidden"])
-
-env_theora.Append(CPPFLAGS=["-D_LIB", "-D__THEORA"]) # removed -D_YUV_C
-env_theora.Append(CPPFLAGS=["-D_YUV_LIBYUV"])
-#env_theora.Append(CPPFLAGS=["-D_YUV_C"])
-
-if env["platform"] == "iphone":
- env_theora.Append(CPPFLAGS=["-D__AVFOUNDATION"])
-else:
- pass
- #env_theora.Append(CPPFLAGS=["-D__FFMPEG"])
-
-if env["platform"] == "android":
- env_theora.Append(CPPFLAGS=["-D_ANDROID"])
-
-if env["platform"] == "winrt":
- env_theora.Append(CPPFLAGS=["-D_WINRT"])
-
-env_theora.Append(CPPPATH=["#drivers/theoraplayer/include/theoraplayer", "#drivers/theoraplayer/src/YUV", "#drivers/theoraplayer/src/YUV/libyuv/include", "#drivers/theoraplayer/src/Theora", "#drivers/theoraplayer/src/AVFoundation"])
-
-objs = []
-
-env_theora.add_source_files(objs, ["video_stream_theoraplayer.cpp"])
-
-if env['use_theoraplayer_binary'] == "yes":
- if env["platform"] == "iphone":
- env.Append(LIBPATH=['#drivers/theoraplayer/lib/ios'])
- env.Append(LIBS=['theoraplayer', 'ogg', 'theora', 'tremor'])
- if env["platform"] == "windows":
- env.Append(LIBPATH=['#drivers/theoraplayer/lib/windows'])
- env.Append(LINKFLAGS=['libtheoraplayer_static.lib', 'libogg.lib', 'libtheora.lib', 'libvorbis.lib'])
-else:
- env_theora.add_source_files(objs, sources)
-
-env.drivers_sources += objs
-
-
diff --git a/drivers/theoraplayer/include/theoraplayer/TheoraAsync.h b/drivers/theoraplayer/include/theoraplayer/TheoraAsync.h
deleted file mode 100644
index 7f1b49b9af..0000000000
--- a/drivers/theoraplayer/include/theoraplayer/TheoraAsync.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#ifndef _TheoraAsync_h
-#define _TheoraAsync_h
-
-#ifndef _WIN32
-#include <pthread.h>
-#endif
-
-/// @note Based on hltypes::Thread
-class TheoraMutex
-{
-public:
- TheoraMutex();
- ~TheoraMutex();
- void lock();
- void unlock();
-
-protected:
- void* mHandle;
-
-};
-
-/// @note Based on hltypes::Thread
-class TheoraThread
-{
- TheoraMutex mRunningMutex;
-public:
- TheoraThread();
- virtual ~TheoraThread();
- void start();
- void stop();
- void resume();
- void pause();
- bool isRunning();
- virtual void execute() = 0;
- void join();
-
-protected:
- void* mId;
- volatile bool mRunning;
-
-};
-
-#endif
diff --git a/drivers/theoraplayer/include/theoraplayer/TheoraAudioInterface.h b/drivers/theoraplayer/include/theoraplayer/TheoraAudioInterface.h
deleted file mode 100644
index aa03293806..0000000000
--- a/drivers/theoraplayer/include/theoraplayer/TheoraAudioInterface.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#ifndef _TheoraAudioInterface_h
-#define _TheoraAudioInterface_h
-
-#include "TheoraExport.h"
-
-class TheoraVideoClip;
-
-
-/**
- This is the class that serves as an interface between the library's audio
- output and the audio playback library of your choice.
- The class gets mono or stereo PCM data in in floating point data
- */
-class TheoraPlayerExport TheoraAudioInterface
-{
-public:
- //! PCM frequency, usualy 44100 Hz
- int mFreq;
- //! Mono or stereo
- int mNumChannels;
- //! Pointer to the parent TheoraVideoClip object
- TheoraVideoClip* mClip;
-
- TheoraAudioInterface(TheoraVideoClip* owner, int nChannels, int freq);
- virtual ~TheoraAudioInterface();
- //! A function that the TheoraVideoClip object calls once more audio packets are decoded
- /*!
- \param data contains one or two channels of float PCM data in the range [-1,1]
- \param nSamples contains the number of samples that the data parameter contains in each channel
- */
- virtual void insertData(float* data, int nSamples)=0;
-};
-
-class TheoraPlayerExport TheoraAudioInterfaceFactory
-{
-public:
- //! VideoManager calls this when creating a new TheoraVideoClip object
- virtual TheoraAudioInterface* createInstance(TheoraVideoClip* owner, int nChannels, int freq) = 0;
-};
-
-
-#endif
-
diff --git a/drivers/theoraplayer/include/theoraplayer/TheoraAudioPacketQueue.h b/drivers/theoraplayer/include/theoraplayer/TheoraAudioPacketQueue.h
deleted file mode 100644
index e0d17516e6..0000000000
--- a/drivers/theoraplayer/include/theoraplayer/TheoraAudioPacketQueue.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#ifndef _TheoraAudioPacketQueue_h
-#define _TheoraAudioPacketQueue_h
-
-#include "TheoraExport.h"
-
-class TheoraAudioInterface;
-/**
- This is an internal structure which TheoraVideoClip_Theora uses to store audio packets
- */
-struct TheoraAudioPacket
-{
- float* pcm;
- int numSamples; //! size in number of float samples (stereo has twice the number of samples)
- TheoraAudioPacket* next; // pointer to the next audio packet, to implement a linked list
-};
-
-/**
- This is a Mutex object, used in thread syncronization.
- */
-class TheoraPlayerExport TheoraAudioPacketQueue
-{
-protected:
- unsigned int mAudioFrequency, mNumAudioChannels;
- TheoraAudioPacket* mTheoraAudioPacketQueue;
- void _addAudioPacket(float* data, int numSamples);
-public:
- TheoraAudioPacketQueue();
- ~TheoraAudioPacketQueue();
-
- float getAudioPacketQueueLength();
- void addAudioPacket(float** buffer, int numSamples, float gain);
- void addAudioPacket(float* buffer, int numSamples, float gain);
- TheoraAudioPacket* popAudioPacket();
- void destroyAudioPacket(TheoraAudioPacket* p);
- void destroyAllAudioPackets();
-
- void flushAudioPackets(TheoraAudioInterface* audioInterface);
-};
-
-#endif
diff --git a/drivers/theoraplayer/include/theoraplayer/TheoraDataSource.h b/drivers/theoraplayer/include/theoraplayer/TheoraDataSource.h
deleted file mode 100644
index b7427e97d3..0000000000
--- a/drivers/theoraplayer/include/theoraplayer/TheoraDataSource.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#ifndef _TheoraDataSource_h
-#define _TheoraDataSource_h
-
-#include <stdio.h>
-#include <string>
-#include "TheoraExport.h"
-
-/**
- This is a simple class that provides abstracted data feeding. You can use the
- TheoraFileDataSource for regular file playback or you can implement your own
- internet streaming solution, or a class that uses encrypted datafiles etc.
- The sky is the limit
-*/
-class TheoraPlayerExport TheoraDataSource
-{
-public:
-
- virtual ~TheoraDataSource();
- /**
- Reads nBytes bytes from data source and returns number of read bytes.
- if function returns less bytes then nBytes, the system assumes EOF is reached.
- */
- virtual int read(void* output,int nBytes)=0;
- //! returns a string representation of the DataSource, eg 'File: source.ogg'
- virtual std::string repr()=0;
- //! position the source pointer to byte_index from the start of the source
- virtual void seek(unsigned long byte_index)=0;
- //! return the size of the stream in bytes
- virtual unsigned long size()=0;
- //! return the current position of the source pointer
- virtual unsigned long tell()=0;
-};
-
-
-/**
- provides standard file IO
-*/
-class TheoraPlayerExport TheoraFileDataSource : public TheoraDataSource
-{
- FILE* mFilePtr;
- std::string mFilename;
- unsigned long mSize;
-
- void openFile();
-public:
- TheoraFileDataSource(std::string filename);
- ~TheoraFileDataSource();
-
- int read(void* output,int nBytes);
- void seek(unsigned long byte_index);
- std::string repr() { return mFilename; }
- unsigned long size();
- unsigned long tell();
-
- std::string getFilename() { return mFilename; }
-};
-
-/**
- Pre-loads the entire file and streams from memory.
- Very useful if you're continuously displaying a video and want to avoid disk reads.
- Not very practical for large files.
-*/
-class TheoraPlayerExport TheoraMemoryFileDataSource : public TheoraDataSource
-{
- std::string mFilename;
- unsigned long mSize, mReadPointer;
- unsigned char* mData;
-public:
- TheoraMemoryFileDataSource(unsigned char* data, long size, const std::string& filename = "memory");
- TheoraMemoryFileDataSource(std::string filename);
- ~TheoraMemoryFileDataSource();
-
- int read(void* output,int nBytes);
- void seek(unsigned long byte_index);
- std::string repr() { return "MEM:"+mFilename; }
- unsigned long size();
- unsigned long tell();
- std::string getFilename() { return mFilename; }
-};
-
-#endif
diff --git a/drivers/theoraplayer/include/theoraplayer/TheoraException.h b/drivers/theoraplayer/include/theoraplayer/TheoraException.h
deleted file mode 100644
index f79368fa1e..0000000000
--- a/drivers/theoraplayer/include/theoraplayer/TheoraException.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#ifndef EXCEPTION_H
-#define EXCEPTION_H
-
-#include <string>
-#include "TheoraExport.h"
-
-class TheoraPlayerExport _TheoraGenericException
-{
-public:
- std::string mErrText,mFile,mType;
- int mLineNumber;
-
- _TheoraGenericException(const std::string& errorText, std::string type = "",std::string file = "", int line = 0);
- virtual ~_TheoraGenericException() {}
-
- virtual std::string repr();
-
- void writeOutput();
-
- virtual const std::string& getErrorText() { return mErrText; }
-
- const std::string getType(){ return mType; }
-};
-
-#define TheoraGenericException(msg) _TheoraGenericException(msg, "TheoraGenericException", __FILE__, __LINE__)
-
-
-#define exception_cls(name) class name : public _TheoraGenericException \
-{ \
-public: \
- name(const std::string& errorText,std::string type = "",std::string file = "",int line = 0) : \
- _TheoraGenericException(errorText, type, file, line){} \
-}
-
-exception_cls(_KeyException);
-
-
-#endif
diff --git a/drivers/theoraplayer/include/theoraplayer/TheoraExport.h b/drivers/theoraplayer/include/theoraplayer/TheoraExport.h
deleted file mode 100644
index cf16d1004c..0000000000
--- a/drivers/theoraplayer/include/theoraplayer/TheoraExport.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#ifndef _theoraVideoExport_h
-#define _theoraVideoExport_h
-
- #ifdef _LIB
- #define TheoraPlayerExport
- #define TheoraPlayerFnExport
- #else
- #ifdef _WIN32
- #ifdef THEORAVIDEO_EXPORTS
- #define TheoraPlayerExport __declspec(dllexport)
- #define TheoraPlayerFnExport __declspec(dllexport)
- #else
- #define TheoraPlayerExport __declspec(dllimport)
- #define TheoraPlayerFnExport __declspec(dllimport)
- #endif
- #else
- #define TheoraPlayerExport __attribute__ ((visibility("default")))
- #define TheoraPlayerFnExport __attribute__ ((visibility("default")))
- #endif
- #endif
- #ifndef DEPRECATED_ATTRIBUTE
- #ifdef _MSC_VER
- #define DEPRECATED_ATTRIBUTE __declspec(deprecated("function is deprecated"))
- #else
- #define DEPRECATED_ATTRIBUTE __attribute__((deprecated))
- #endif
- #endif
-
-#endif
-
diff --git a/drivers/theoraplayer/include/theoraplayer/TheoraFrameQueue.h b/drivers/theoraplayer/include/theoraplayer/TheoraFrameQueue.h
deleted file mode 100644
index fd985bb65a..0000000000
--- a/drivers/theoraplayer/include/theoraplayer/TheoraFrameQueue.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-
-#ifndef _TheoraFrameQueue_h
-#define _TheoraFrameQueue_h
-
-#include "TheoraAsync.h"
-#include <list>
-#include "TheoraExport.h"
-
-class TheoraVideoFrame;
-class TheoraVideoClip;
-
-/**
- This class handles the frame queue. contains frames and handles their alloctation/deallocation
- it is designed to be thread-safe
-*/
-class TheoraPlayerExport TheoraFrameQueue
-{
-protected:
- std::list<TheoraVideoFrame*> mQueue;
- TheoraVideoClip* mParent;
- TheoraMutex mMutex;
-
- //! implementation function that returns a TheoraVideoFrame instance
- TheoraVideoFrame* createFrameInstance(TheoraVideoClip* clip);
-public:
- TheoraFrameQueue(TheoraVideoClip* parent);
- ~TheoraFrameQueue();
-
- /**
- \brief Returns the first available frame in the queue or NULL if no frames are available.
-
- This function DOES NOT remove the frame from the queue, you have to do it manually
- when you want to mark the frame as used by calling the pop() function.
- */
- TheoraVideoFrame* getFirstAvailableFrame();
- //! non-mutex version
- TheoraVideoFrame* _getFirstAvailableFrame();
-
- //! return the number of used (not ready) frames
- int getUsedCount();
-
- //! return the number of ready frames
- int getReadyCount();
- //! non-mutex version
- int _getReadyCount();
-
- /**
- \brief remove the first N available frame from the queue.
-
- Use this every time you display a frame so you can get the next one when the time comes.
- This function marks the frame on the front of the queue as unused and it's memory then
- get's used again in the decoding process.
- If you don't call this, the frame queue will fill up with precached frames up to the
- specified amount in the TheoraVideoManager class and you won't be able to advance the video.
- */
- void pop(int n = 1);
-
- //! This is an internal _pop function. use externally only in combination with lock() / unlock() calls
- void _pop(int n);
-
- //! frees all decoded frames for reuse (does not destroy memory, just marks them as free)
- void clear();
- //! Called by WorkerThreads when they need to unload frame data, do not call directly!
- TheoraVideoFrame* requestEmptyFrame();
-
- /**
- \brief set's the size of the frame queue.
-
- Beware, currently stored ready frames will be lost upon this call
- */
- void setSize(int n);
- //! return the size of the queue
- int getSize();
-
- //! return whether all frames in the queue are ready for display
- bool isFull();
-
- //! lock the queue's mutex manually
- void lock();
- //! unlock the queue's mutex manually
- void unlock();
-
- //! returns the internal frame queue. Warning: Always lock / unlock queue's mutex before accessing frames directly!
- std::list<TheoraVideoFrame*>& _getFrameQueue();
-};
-
-#endif
diff --git a/drivers/theoraplayer/include/theoraplayer/TheoraPixelTransform.h b/drivers/theoraplayer/include/theoraplayer/TheoraPixelTransform.h
deleted file mode 100644
index 73d853cd03..0000000000
--- a/drivers/theoraplayer/include/theoraplayer/TheoraPixelTransform.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#ifndef _TheoraPixelTransform_h
-#define _TheoraPixelTransform_h
-
-struct TheoraPixelTransform
-{
- unsigned char *raw, *y, *u, *v, *out;
- unsigned int w, h, rawStride, yStride, uStride, vStride;
-};
-
-#endif
diff --git a/drivers/theoraplayer/include/theoraplayer/TheoraPlayer.h b/drivers/theoraplayer/include/theoraplayer/TheoraPlayer.h
deleted file mode 100644
index 8c5f2c735c..0000000000
--- a/drivers/theoraplayer/include/theoraplayer/TheoraPlayer.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#ifndef _TheoraPlayer_h
-#define _TheoraPlayer_h
-
-#include "TheoraVideoManager.h"
-#include "TheoraVideoClip.h"
-#include "TheoraVideoFrame.h"
-
-#endif
-
diff --git a/drivers/theoraplayer/include/theoraplayer/TheoraTimer.h b/drivers/theoraplayer/include/theoraplayer/TheoraTimer.h
deleted file mode 100644
index 14fdbf47fc..0000000000
--- a/drivers/theoraplayer/include/theoraplayer/TheoraTimer.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-
-#ifndef _TheoraTimer_h
-#define _TheoraTimer_h
-
-#include "TheoraExport.h"
-
-/**
- This is a Timer object, it is used to control the playback of a TheoraVideoClip.
-
- You can inherit this class and make a timer that eg. plays twice as fast,
- or playbacks an audio track and uses it's time offset for syncronizing Video etc.
- */
-class TheoraPlayerExport TheoraTimer
-{
-protected:
- //! Current time in seconds
- float mTime,mSpeed;
- //! Is the timer paused or not
- bool mPaused;
-public:
- TheoraTimer();
- virtual ~TheoraTimer();
-
- virtual float getTime();
- /**
- \brief advance the time.
-
- If you're using another synronization system, eg. an audio track,
- then you can ignore this call or use it to perform other updates.
-
- NOTE: this is called by TheoraVideoManager from the main thread
- */
- virtual void update(float timeDelta);
-
- virtual void pause();
- virtual void play();
- virtual bool isPaused();
- virtual void stop();
- /**
- \brief set's playback speed
-
- 1.0 is the default. The speed factor multiplies time advance, thus
- setting the value higher will increase playback speed etc.
-
- NOTE: depending on Timer implementation, it may not support setting the speed
-
- */
- virtual void setSpeed(float speed);
- //! return the update speed 1.0 is the default
- virtual float getSpeed();
-
- /**
- \brief change the current time.
-
- if you're using another syncronization mechanism, make sure to adjust
- the time offset there
- */
- virtual void seek(float time);
-};
-#endif
-
diff --git a/drivers/theoraplayer/include/theoraplayer/TheoraUtil.h b/drivers/theoraplayer/include/theoraplayer/TheoraUtil.h
deleted file mode 100644
index f168971ac7..0000000000
--- a/drivers/theoraplayer/include/theoraplayer/TheoraUtil.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#ifndef _TheoraUtil_h
-#define _TheoraUtil_h
-
-#include <string>
-#include <vector>
-
-#ifndef THEORAUTIL_NOMACROS
-
-#define foreach(type,lst) for (std::vector<type>::iterator it=lst.begin();it != lst.end(); ++it)
-#define foreach_l(type,lst) for (std::list<type>::iterator it=lst.begin();it != lst.end(); ++it)
-#define foreach_r(type,lst) for (std::vector<type>::reverse_iterator it=lst.rbegin();it != lst.rend(); ++it)
-#define foreach_in_map(type,lst) for (std::map<std::string,type>::iterator it=lst.begin();it != lst.end(); ++it)
-
-#endif
-
-#define th_writelog(x) TheoraVideoManager::getSingleton().logMessage(x)
-
-
-std::string str(int i);
-std::string strf(float i);
-void _psleep(int milliseconds);
-int _nextPow2(int x);
-
-#endif \ No newline at end of file
diff --git a/drivers/theoraplayer/include/theoraplayer/TheoraVideoClip.h b/drivers/theoraplayer/include/theoraplayer/TheoraVideoClip.h
deleted file mode 100644
index fe71cf8566..0000000000
--- a/drivers/theoraplayer/include/theoraplayer/TheoraVideoClip.h
+++ /dev/null
@@ -1,282 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-
-#ifndef _TheoraVideoClip_h
-#define _TheoraVideoClip_h
-
-#include <string>
-#include "TheoraExport.h"
-
-// forward class declarations
-class TheoraMutex;
-class TheoraFrameQueue;
-class TheoraTimer;
-class TheoraAudioInterface;
-class TheoraWorkerThread;
-class TheoraDataSource;
-class TheoraVideoFrame;
-
-/**
- format of the TheoraVideoFrame pixels. Affects decoding time
- */
-enum TheoraOutputMode
-{
- // A = full alpha (255), order of letters represents the byte order for a pixel
- // A means the image is treated as if it contains an alpha channel, while X formats
- // just mean that RGB frame is transformed to a 4 byte format
- TH_UNDEFINED = 0,
- TH_RGB = 1,
- TH_RGBA = 2,
- TH_RGBX = 3,
- TH_ARGB = 4,
- TH_XRGB = 5,
- TH_BGR = 6,
- TH_BGRA = 7,
- TH_BGRX = 8,
- TH_ABGR = 9,
- TH_XBGR = 10,
- TH_GREY = 11,
- TH_GREY3 = 12,
- TH_GREY3A = 13,
- TH_GREY3X = 14,
- TH_AGREY3 = 15,
- TH_XGREY3 = 16,
- TH_YUV = 17,
- TH_YUVA = 18,
- TH_YUVX = 19,
- TH_AYUV = 20,
- TH_XYUV = 21
-};
-
-/**
- This object contains all data related to video playback, eg. the open source file,
- the frame queue etc.
-*/
-class TheoraPlayerExport TheoraVideoClip
-{
- friend class TheoraWorkerThread;
- friend class TheoraVideoFrame;
- friend class TheoraVideoManager;
-protected:
- TheoraFrameQueue* mFrameQueue;
- TheoraAudioInterface* mAudioInterface;
- TheoraDataSource* mStream;
-
- TheoraTimer *mTimer, *mDefaultTimer;
-
- TheoraWorkerThread* mAssignedWorkerThread;
-
- bool mUseAlpha;
-
- bool mWaitingForCache;
-
- // benchmark vars
- int mNumDroppedFrames, mNumDisplayedFrames, mNumPrecachedFrames;
-
- int mThreadAccessCount; //! counter used by TheoraVideoManager to schedule workload
-
- int mSeekFrame; //! stores desired seek position as a frame number. next worker thread will do the seeking and reset this var to -1
- float mDuration, mFrameDuration, mFPS;
- float mPriority; //! User assigned priority. Default value is 1
- std::string mName;
- int mWidth, mHeight, mStride;
- int mNumFrames;
- int audio_track;
-
- int mSubFrameWidth, mSubFrameHeight, mSubFrameOffsetX, mSubFrameOffsetY;
- float mAudioGain; //! multiplier for audio samples. between 0 and 1
-
- TheoraOutputMode mOutputMode, mRequestedOutputMode;
- bool mFirstFrameDisplayed;
- bool mAutoRestart;
- bool mEndOfFile, mRestarted;
- int mIteration, mPlaybackIteration; //! used to ensure smooth playback of looping videos
-
- TheoraMutex* mAudioMutex; //! syncs audio decoding and extraction
- TheoraMutex* mThreadAccessMutex;
-
- /**
- * Get the priority of a video clip. based on a forumula that includes user
- * priority factor, whether the video is paused or not, how many precached
- * frames it has etc.
- * This function is used in TheoraVideoManager to efficiently distribute job
- * assignments among worker threads
- * @return priority number of this video clip
- */
- int calculatePriority();
- void readTheoraVorbisHeaders();
- virtual void doSeek() = 0; //! called by WorkerThread to seek to mSeekFrame
- virtual bool _readData() = 0;
- bool isBusy();
-
- /**
- * decodes audio from the vorbis stream and stores it in audio packets
- * This is an internal function of TheoraVideoClip, called regularly if playing an
- * audio enabled video clip.
- * @return last decoded timestamp (if found in decoded packet's granule position)
- */
- virtual float decodeAudio() = 0;
-
- int _getNumReadyFrames();
- void resetFrameQueue();
- int discardOutdatedFrames(float absTime);
- float getAbsPlaybackTime();
- virtual void load(TheoraDataSource* source) = 0;
-
- virtual void _restart() = 0; // resets the decoder and stream but leaves the frame queue intact
-public:
- TheoraVideoClip(TheoraDataSource* data_source,
- TheoraOutputMode output_mode,
- int nPrecachedFrames,
- bool usePower2Stride);
- virtual ~TheoraVideoClip();
-
- std::string getName();
- //! Returns the string name of the decoder backend (eg. Theora, AVFoundation)
- virtual std::string getDecoderName() = 0;
-
- //! benchmark function
- int getNumDisplayedFrames() { return mNumDisplayedFrames; }
- //! benchmark function
- int getNumDroppedFrames() { return mNumDroppedFrames; }
-
- //! return width in pixels of the video clip
- int getWidth();
- //! return height in pixels of the video clip
- int getHeight();
-
- //! Width of the actual picture inside a video frame (depending on implementation, this may be equal to mWidth or differ within a codec block size (usually 16))
- int getSubFrameWidth();
- //! Height of the actual picture inside a video frame (depending on implementation, this may be equal to mHeight or differ within a codec block size (usually 16))
- int getSubFrameHeight();
- //! X Offset of the actual picture inside a video frame (depending on implementation, this may be 0 or within a codec block size (usually 16))
- int getSubFrameOffsetX();
- //! Y Offset of the actual picture inside a video frame (depending on implementation, this may be 0 or differ within a codec block size (usually 16))
- int getSubFrameOffsetY();
- /**
- \brief return stride in pixels
-
- If you've specified usePower2Stride when creating the TheoraVideoClip object
- then this value will be the next power of two size compared to width,
- eg: w=376, stride=512.
-
- Otherwise, stride will be equal to width
- */
- int getStride() { return mStride; }
-
- //! retur the timer objet associated with this object
- TheoraTimer* getTimer();
- //! replace the timer object with a new one
- void setTimer(TheoraTimer* timer);
-
- //! used by TheoraWorkerThread, do not call directly
- virtual bool decodeNextFrame() = 0;
-
- //! advance time. TheoraVideoManager calls this
- void update(float timeDelta);
- /**
- \brief update timer to the display time of the next frame
-
- useful if you want to grab frames instead of regular display
- \return time advanced. 0 if no frames are ready
- */
- float updateToNextFrame();
-
-
- TheoraFrameQueue* getFrameQueue();
-
- /**
- \brief pop the frame from the front of the FrameQueue
-
- see TheoraFrameQueue::pop() for more details
- */
- void popFrame();
-
- /**
- \brief Returns the first available frame in the queue or NULL if no frames are available.
-
- see TheoraFrameQueue::getFirstAvailableFrame() for more details
- */
- TheoraVideoFrame* getNextFrame();
- /**
- check if there is enough audio data decoded to submit to the audio interface
-
- TheoraWorkerThread calls this
- */
- virtual void decodedAudioCheck() = 0;
-
- void setAudioInterface(TheoraAudioInterface* iface);
- TheoraAudioInterface* getAudioInterface();
-
- /**
- \brief resize the frame queues
-
- Warning: this call discards ready frames in the frame queue
- */
- void setNumPrecachedFrames(int n);
- //! returns the size of the frame queue
- int getNumPrecachedFrames();
- //! returns the number of ready frames in the frame queue
- int getNumReadyFrames();
-
- //! if you want to adjust the audio gain. range [0,1]
- void setAudioGain(float gain);
- float getAudioGain();
-
- //! if you want the video to automatically and smoothly restart when the last frame is reached
- void setAutoRestart(bool value);
- bool getAutoRestart() { return mAutoRestart; }
-
-
- void set_audio_track(int p_track) { audio_track=p_track; }
-
- /**
- TODO: user priority. Useful only when more than one video is being decoded
- */
- void setPriority(float priority);
- float getPriority();
-
- //! Used by TheoraVideoManager to schedule work
- float getPriorityIndex();
-
- //! get the current time index from the timer object
- float getTimePosition();
- //! get the duration of the movie in seconds
- float getDuration();
- //! return the clips' frame rate, warning, fps can be a non integer number!
- float getFPS();
- //! get the number of frames in this movie
- int getNumFrames() { return mNumFrames; }
-
- //! return the current output mode for this video object
- TheoraOutputMode getOutputMode();
- /**
- set a new output mode
-
- Warning: this discards the frame queue. ready frames will be lost.
- */
- void setOutputMode(TheoraOutputMode mode);
-
- bool isDone();
- void play();
- void pause();
- void restart();
- bool isPaused();
- void stop();
- void setPlaybackSpeed(float speed);
- float getPlaybackSpeed();
- //! seek to a given time position
- void seek(float time);
- //! seek to a given frame number
- void seekToFrame(int frame);
- //! wait max_time for the clip to cache a given percentage of frames, factor in range [0,1]
- void waitForCache(float desired_cache_factor = 0.5f, float max_wait_time = 1.0f);
-};
-
-#endif
diff --git a/drivers/theoraplayer/include/theoraplayer/TheoraVideoFrame.h b/drivers/theoraplayer/include/theoraplayer/TheoraVideoFrame.h
deleted file mode 100644
index 5d27f54d1c..0000000000
--- a/drivers/theoraplayer/include/theoraplayer/TheoraVideoFrame.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#ifndef _TheoraVideoFrame_h
-#define _TheoraVideoFrame_h
-
-#include "TheoraExport.h"
-#include "TheoraVideoClip.h"
-
-struct TheoraPixelTransform;
-/**
-
-*/
-class TheoraPlayerExport TheoraVideoFrame
-{
-protected:
- TheoraVideoClip* mParent;
- unsigned char* mBuffer;
- unsigned long mFrameNumber;
-public:
- //! global time in seconds this frame should be displayed on
- float mTimeToDisplay;
- //! whether the frame is ready for display or not
- bool mReady;
- //! indicates the frame is being used by TheoraWorkerThread instance
- bool mInUse;
- //! used to keep track of linear time in looping videos
- int mIteration;
-
- int mBpp;
-
- TheoraVideoFrame(TheoraVideoClip* parent);
- virtual ~TheoraVideoFrame();
-
- //! internal function, do not use directly
- void _setFrameNumber(unsigned long number) { mFrameNumber = number; }
- //! returns the frame number of this frame in the theora stream
- unsigned long getFrameNumber() { return mFrameNumber; }
-
- void clear();
-
- int getWidth();
- int getStride();
- int getHeight();
-
- unsigned char* getBuffer();
-
- //! Called by TheoraVideoClip to decode a source buffer onto itself
- virtual void decode(struct TheoraPixelTransform* t);
-};
-#endif
diff --git a/drivers/theoraplayer/include/theoraplayer/TheoraVideoManager.h b/drivers/theoraplayer/include/theoraplayer/TheoraVideoManager.h
deleted file mode 100644
index d94c51b4d4..0000000000
--- a/drivers/theoraplayer/include/theoraplayer/TheoraVideoManager.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-
-#ifndef _TheoraVideoManager_h
-#define _TheoraVideoManager_h
-
-#include <vector>
-#include <list>
-#include <string>
-#include "TheoraExport.h"
-#include "TheoraVideoClip.h"
-#ifdef _WIN32
-#pragma warning( disable: 4251 ) // MSVC++
-#endif
-// forward class declarations
-class TheoraWorkerThread;
-class TheoraMutex;
-class TheoraDataSource;
-class TheoraAudioInterfaceFactory;
-/**
- This is the main singleton class that handles all playback/sync operations
-*/
-class TheoraPlayerExport TheoraVideoManager
-{
-protected:
- friend class TheoraWorkerThread;
- typedef std::vector<TheoraVideoClip*> ClipList;
- typedef std::vector<TheoraWorkerThread*> ThreadList;
-
- //! stores pointers to worker threads which are decoding video and audio
- ThreadList mWorkerThreads;
- //! stores pointers to created video clips
- ClipList mClips;
-
- //! stores pointer to clips that were docoded in the past in order to achieve fair scheduling
- std::list<TheoraVideoClip*> mWorkLog;
-
- int mDefaultNumPrecachedFrames;
-
- TheoraMutex* mWorkMutex;
- TheoraAudioInterfaceFactory* mAudioFactory;
-
- void createWorkerThreads(int n);
- void destroyWorkerThreads();
-
- float calcClipWorkTime(TheoraVideoClip* clip);
-
- /**
- * Called by TheoraWorkerThread to request a TheoraVideoClip instance to work on decoding
- */
- TheoraVideoClip* requestWork(TheoraWorkerThread* caller);
-public:
- TheoraVideoManager(int num_worker_threads=1);
- virtual ~TheoraVideoManager();
-
- //! get the global reference to the manager instance
- static TheoraVideoManager& getSingleton();
- //! get the global pointer to the manager instance
- static TheoraVideoManager* getSingletonPtr();
-
- //! search registered clips by name
- TheoraVideoClip* getVideoClipByName(std::string name);
-
- TheoraVideoClip* createVideoClip(std::string filename,TheoraOutputMode output_mode=TH_RGB,int numPrecachedOverride=0,bool usePower2Stride=0, int p_track=0);
- TheoraVideoClip* createVideoClip(TheoraDataSource* data_source,TheoraOutputMode output_mode=TH_RGB,int numPrecachedOverride=0,bool usePower2Stride=0, int p_audio_track=0);
-
- void update(float timeDelta);
-
- void destroyVideoClip(TheoraVideoClip* clip);
-
- void setAudioInterfaceFactory(TheoraAudioInterfaceFactory* factory);
- TheoraAudioInterfaceFactory* getAudioInterfaceFactory();
-
- int getNumWorkerThreads();
- void setNumWorkerThreads(int n);
-
- void setDefaultNumPrecachedFrames(int n) { mDefaultNumPrecachedFrames=n; }
- int getDefaultNumPrecachedFrames() { return mDefaultNumPrecachedFrames; }
-
- //! used by libtheoraplayer functions
- void logMessage(std::string msg);
-
- /**
- \brief you can set your own log function to recieve theora's log calls
-
- This way you can integrate libtheoraplayer's log messages in your own
- logging system, prefix them, mute them or whatever you want
- */
- static void setLogFunction(void (*fn)(std::string));
-
- //! get nicely formated version string
- std::string getVersionString();
- /**
- \brief get version numbers
-
- if c is negative, it means it's a release candidate -c
- */
- void getVersion(int* a,int* b,int* c);
-
- //! returns the supported decoders (eg. Theora, AVFoundation...)
- std::vector<std::string> getSupportedDecoders();
-};
-#endif
-
diff --git a/drivers/theoraplayer/include/theoraplayer/TheoraWorkerThread.h b/drivers/theoraplayer/include/theoraplayer/TheoraWorkerThread.h
deleted file mode 100644
index 2299acedbd..0000000000
--- a/drivers/theoraplayer/include/theoraplayer/TheoraWorkerThread.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#ifndef _TheoraWorkerThread_h
-#define _TheoraWorkerThread_h
-
-#include "TheoraAsync.h"
-
-class TheoraVideoClip;
-
-/**
- This is the worker thread, requests work from TheoraVideoManager
- and decodes assigned TheoraVideoClip objects
-*/
-class TheoraWorkerThread : public TheoraThread
-{
- TheoraVideoClip* mClip;
-public:
- TheoraWorkerThread();
- ~TheoraWorkerThread();
-
- TheoraVideoClip* getAssignedClip() { return mClip; }
-
- //! Main Thread Body - do not call directly!
- void execute();
-};
-#endif
diff --git a/drivers/theoraplayer/src/AVFoundation/TheoraVideoClip_AVFoundation.h b/drivers/theoraplayer/src/AVFoundation/TheoraVideoClip_AVFoundation.h
deleted file mode 100644
index abd898aa01..0000000000
--- a/drivers/theoraplayer/src/AVFoundation/TheoraVideoClip_AVFoundation.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#if defined(__AVFOUNDATION) && !defined(_TheoraVideoClip_AVFoundation_h)
-#define _TheoraVideoClip_AVFoundation_h
-
-#include "TheoraAudioPacketQueue.h"
-#include "TheoraVideoClip.h"
-
-#ifndef AVFOUNDATION_CLASSES_DEFINED
-class AVAssetReader;
-class AVAssetReaderTrackOutput;
-#endif
-
-class TheoraVideoClip_AVFoundation : public TheoraVideoClip, public TheoraAudioPacketQueue
-{
-protected:
- bool mLoaded;
- int mFrameNumber;
- AVAssetReader* mReader;
- AVAssetReaderTrackOutput *mOutput, *mAudioOutput;
- unsigned int mReadAudioSamples;
-
- void unload();
- void doSeek();
-public:
- TheoraVideoClip_AVFoundation(TheoraDataSource* data_source,
- TheoraOutputMode output_mode,
- int nPrecachedFrames,
- bool usePower2Stride);
- ~TheoraVideoClip_AVFoundation();
-
- bool _readData();
- bool decodeNextFrame();
- void _restart();
- void load(TheoraDataSource* source);
- float decodeAudio();
- void decodedAudioCheck();
- std::string getDecoderName() { return "AVFoundation"; }
-};
-
-#endif
diff --git a/drivers/theoraplayer/src/AVFoundation/TheoraVideoClip_AVFoundation.mm b/drivers/theoraplayer/src/AVFoundation/TheoraVideoClip_AVFoundation.mm
deleted file mode 100644
index 1b5cf0ab13..0000000000
--- a/drivers/theoraplayer/src/AVFoundation/TheoraVideoClip_AVFoundation.mm
+++ /dev/null
@@ -1,457 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#ifdef __AVFOUNDATION
-#define AVFOUNDATION_CLASSES_DEFINED
-#import <AVFoundation/AVFoundation.h>
-#include "TheoraAudioInterface.h"
-#include "TheoraDataSource.h"
-#include "TheoraException.h"
-#include "TheoraTimer.h"
-#include "TheoraUtil.h"
-#include "TheoraFrameQueue.h"
-#include "TheoraVideoFrame.h"
-#include "TheoraVideoManager.h"
-#include "TheoraVideoClip_AVFoundation.h"
-#include "TheoraPixelTransform.h"
-
-#ifdef _AVFOUNDATION_BGRX
-// a fast function developed to use kernel byte swapping calls to optimize alpha decoding.
-// In AVFoundation, BGRX mode conversion is prefered to YUV conversion because apple's YUV
-// conversion on iOS seems to run faster than libtheoraplayer's implementation
-// This may change in the future with more optimizations to libtheoraplayers's YUV conversion
-// code, making this function obsolete.
-static void bgrx2rgba(unsigned char* dest, int w, int h, struct TheoraPixelTransform* t)
-{
- unsigned register int a;
- unsigned int *dst = (unsigned int*) dest, *dstEnd;
- unsigned char* src = t->raw;
- int y, x, ax;
-
- for (y = 0; y < h; ++y, src += t->rawStride)
- {
- for (x = 0, ax = w * 4, dstEnd = dst + w; dst != dstEnd; x += 4, ax += 4, ++dst)
- {
- // use the full alpha range here because the Y channel has already been converted
- // to RGB and that's in [0, 255] range.
- a = src[ax];
- *dst = (OSReadSwapInt32(src, x) >> 8) | (a << 24);
- }
- }
-}
-#endif
-
-static CVPlanarPixelBufferInfo_YCbCrPlanar getYUVStruct(void* src)
-{
- CVPlanarPixelBufferInfo_YCbCrPlanar* bigEndianYuv = (CVPlanarPixelBufferInfo_YCbCrPlanar*) src;
- CVPlanarPixelBufferInfo_YCbCrPlanar yuv;
- yuv.componentInfoY.offset = OSSwapInt32(bigEndianYuv->componentInfoY.offset);
- yuv.componentInfoY.rowBytes = OSSwapInt32(bigEndianYuv->componentInfoY.rowBytes);
- yuv.componentInfoCb.offset = OSSwapInt32(bigEndianYuv->componentInfoCb.offset);
- yuv.componentInfoCb.rowBytes = OSSwapInt32(bigEndianYuv->componentInfoCb.rowBytes);
- yuv.componentInfoCr.offset = OSSwapInt32(bigEndianYuv->componentInfoCr.offset);
- yuv.componentInfoCr.rowBytes = OSSwapInt32(bigEndianYuv->componentInfoCr.rowBytes);
- return yuv;
-}
-
-TheoraVideoClip_AVFoundation::TheoraVideoClip_AVFoundation(TheoraDataSource* data_source,
- TheoraOutputMode output_mode,
- int nPrecachedFrames,
- bool usePower2Stride):
- TheoraVideoClip(data_source, output_mode, nPrecachedFrames, usePower2Stride),
- TheoraAudioPacketQueue()
-{
- mLoaded = 0;
- mReader = NULL;
- mOutput = mAudioOutput = NULL;
- mReadAudioSamples = mAudioFrequency = mNumAudioChannels = 0;
-}
-
-TheoraVideoClip_AVFoundation::~TheoraVideoClip_AVFoundation()
-{
- unload();
-}
-
-void TheoraVideoClip_AVFoundation::unload()
-{
- if (mOutput != NULL || mAudioOutput != NULL || mReader != NULL)
- {
- NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
-
- if (mOutput != NULL)
- {
- [mOutput release];
- mOutput = NULL;
- }
-
- if (mAudioOutput)
- {
- [mAudioOutput release];
- mAudioOutput = NULL;
- }
-
- if (mReader != NULL)
- {
- [mReader release];
- mReader = NULL;
- }
-
- [pool release];
- }
-}
-
-bool TheoraVideoClip_AVFoundation::_readData()
-{
- return 1;
-}
-
-bool TheoraVideoClip_AVFoundation::decodeNextFrame()
-{
- if (mReader == NULL || mEndOfFile) return 0;
- AVAssetReaderStatus status = [mReader status];
- if (status == AVAssetReaderStatusFailed)
- {
- // This can happen on iOS when you suspend the app... Only happens on the device, iOS simulator seems to work fine.
- th_writelog("AVAssetReader reading failed, restarting...");
-
- mSeekFrame = mTimer->getTime() * mFPS;
- // just in case
- if (mSeekFrame < 0) mSeekFrame = 0;
- if (mSeekFrame > mDuration * mFPS - 1) mSeekFrame = mDuration * mFPS - 1;
- _restart();
- status = [mReader status];
- if (status == AVAssetReaderStatusFailed)
- {
- th_writelog("AVAssetReader restart failed!");
- return 0;
- }
- th_writelog("AVAssetReader restart succeeded!");
- }
-
- TheoraVideoFrame* frame = mFrameQueue->requestEmptyFrame();
- if (!frame) return 0;
-
- CMSampleBufferRef sampleBuffer = NULL;
- NSAutoreleasePool* pool = NULL;
- CMTime presentationTime;
-
- if (mAudioInterface) decodeAudio();
-
- if (status == AVAssetReaderStatusReading)
- {
- pool = [[NSAutoreleasePool alloc] init];
-
- while ((sampleBuffer = [mOutput copyNextSampleBuffer]))
- {
- presentationTime = CMSampleBufferGetOutputPresentationTimeStamp(sampleBuffer);
- frame->mTimeToDisplay = (float) CMTimeGetSeconds(presentationTime);
- frame->mIteration = mIteration;
- frame->_setFrameNumber(mFrameNumber);
- ++mFrameNumber;
- if (frame->mTimeToDisplay < mTimer->getTime() && !mRestarted && mFrameNumber % 16 != 0)
- {
- // %16 operation is here to prevent a playback halt during video playback if the decoder can't keep up with demand.
-#ifdef _DEBUG
- th_writelog(mName + ": pre-dropped frame " + str(mFrameNumber - 1));
-#endif
- ++mNumDisplayedFrames;
- ++mNumDroppedFrames;
- CMSampleBufferInvalidate(sampleBuffer);
- CFRelease(sampleBuffer);
- sampleBuffer = NULL;
- continue; // drop frame
- }
-
- CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
- CVPixelBufferLockBaseAddress(imageBuffer, 0);
- void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);
-
- mStride = CVPixelBufferGetBytesPerRow(imageBuffer);
- size_t width = CVPixelBufferGetWidth(imageBuffer);
- size_t height = CVPixelBufferGetHeight(imageBuffer);
-
- TheoraPixelTransform t;
- memset(&t, 0, sizeof(TheoraPixelTransform));
-#ifdef _AVFOUNDATION_BGRX
- if (mOutputMode == TH_BGRX || mOutputMode == TH_RGBA)
- {
- t.raw = (unsigned char*) baseAddress;
- t.rawStride = mStride;
- }
- else
-#endif
- {
- CVPlanarPixelBufferInfo_YCbCrPlanar yuv = getYUVStruct(baseAddress);
-
- t.y = (unsigned char*) baseAddress + yuv.componentInfoY.offset; t.yStride = yuv.componentInfoY.rowBytes;
- t.u = (unsigned char*) baseAddress + yuv.componentInfoCb.offset; t.uStride = yuv.componentInfoCb.rowBytes;
- t.v = (unsigned char*) baseAddress + yuv.componentInfoCr.offset; t.vStride = yuv.componentInfoCr.rowBytes;
- }
-#ifdef _AVFOUNDATION_BGRX
- if (mOutputMode == TH_RGBA)
- {
- for (int i = 0; i < 1000; ++i)
- bgrx2rgba(frame->getBuffer(), mWidth / 2, mHeight, &t);
- frame->mReady = true;
- }
- else
-#endif
- frame->decode(&t);
-
- CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
- CMSampleBufferInvalidate(sampleBuffer);
- CFRelease(sampleBuffer);
-
- break; // TODO - should this really be a while loop instead of an if block?
- }
- }
- if (pool) [pool release];
-
- if (!frame->mReady) // in case the frame wasn't used
- {
- frame->mInUse = 0;
- }
-
- if (sampleBuffer == NULL && mReader.status == AVAssetReaderStatusCompleted) // other cases could be app suspended
- {
- if (mAutoRestart)
- {
- ++mIteration;
- _restart();
- }
- else
- {
- unload();
- mEndOfFile = true;
- }
- return 0;
- }
-
-
- return 1;
-}
-
-void TheoraVideoClip_AVFoundation::_restart()
-{
- mEndOfFile = false;
- unload();
- load(mStream);
- mRestarted = true;
-}
-
-void TheoraVideoClip_AVFoundation::load(TheoraDataSource* source)
-{
- mStream = source;
- mFrameNumber = 0;
- mEndOfFile = false;
- TheoraFileDataSource* fileDataSource = dynamic_cast<TheoraFileDataSource*>(source);
- std::string filename;
- if (fileDataSource != NULL) filename = fileDataSource->getFilename();
- else
- {
- TheoraMemoryFileDataSource* memoryDataSource = dynamic_cast<TheoraMemoryFileDataSource*>(source);
- if (memoryDataSource != NULL) filename = memoryDataSource->getFilename();
- else throw TheoraGenericException("Unable to load MP4 file");
- }
-
- NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
- NSString* path = [NSString stringWithUTF8String:filename.c_str()];
- NSError* err;
- NSURL *url = [NSURL fileURLWithPath:path];
- AVAsset* asset = [[AVURLAsset alloc] initWithURL:url options:nil];
- mReader = [[AVAssetReader alloc] initWithAsset:asset error:&err];
- NSArray* tracks = [asset tracksWithMediaType:AVMediaTypeVideo];
- if ([tracks count] == 0)
- throw TheoraGenericException("Unable to open video file: " + filename);
- AVAssetTrack *videoTrack = [tracks objectAtIndex:0];
-
- NSArray* audioTracks = [asset tracksWithMediaType:AVMediaTypeAudio];
- if (audio_track >= audioTracks.count)
- audio_track = 0;
- AVAssetTrack *audioTrack = audioTracks.count > 0 ? [audioTracks objectAtIndex:audio_track] : NULL;
- printf("*********** using audio track %i\n", audio_track);
-
-#ifdef _AVFOUNDATION_BGRX
- bool yuv_output = (mOutputMode != TH_BGRX && mOutputMode != TH_RGBA);
-#else
- bool yuv_output = true;
-#endif
-
- NSDictionary *videoOptions = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:(yuv_output) ? kCVPixelFormatType_420YpCbCr8Planar : kCVPixelFormatType_32BGRA], kCVPixelBufferPixelFormatTypeKey, nil];
-
- mOutput = [[AVAssetReaderTrackOutput alloc] initWithTrack:videoTrack outputSettings:videoOptions];
- [mReader addOutput:mOutput];
- if ([mOutput respondsToSelector:@selector(setAlwaysCopiesSampleData:)]) // Not supported on iOS versions older than 5.0
- mOutput.alwaysCopiesSampleData = NO;
-
- mFPS = videoTrack.nominalFrameRate;
- mWidth = mSubFrameWidth = mStride = videoTrack.naturalSize.width;
- mHeight = mSubFrameHeight = videoTrack.naturalSize.height;
- mFrameDuration = 1.0f / mFPS;
- mDuration = (float) CMTimeGetSeconds(asset.duration);
- if (mFrameQueue == NULL)
- {
- mFrameQueue = new TheoraFrameQueue(this);
- mFrameQueue->setSize(mNumPrecachedFrames);
- }
-
- if (mSeekFrame != -1)
- {
- mFrameNumber = mSeekFrame;
- [mReader setTimeRange: CMTimeRangeMake(CMTimeMakeWithSeconds(mSeekFrame / mFPS, 1), kCMTimePositiveInfinity)];
- }
- if (audioTrack)
- {
- TheoraAudioInterfaceFactory* audio_factory = TheoraVideoManager::getSingleton().getAudioInterfaceFactory();
- if (audio_factory)
- {
- NSDictionary *audioOptions = [NSDictionary dictionaryWithObjectsAndKeys:
- [NSNumber numberWithInt:kAudioFormatLinearPCM], AVFormatIDKey,
- [NSNumber numberWithBool:NO], AVLinearPCMIsNonInterleaved,
- [NSNumber numberWithBool:NO], AVLinearPCMIsBigEndianKey,
- [NSNumber numberWithBool:YES], AVLinearPCMIsFloatKey,
- [NSNumber numberWithInt:32], AVLinearPCMBitDepthKey,
- nil];
-
- mAudioOutput = [[AVAssetReaderTrackOutput alloc] initWithTrack:audioTrack outputSettings:audioOptions];
- [mReader addOutput:mAudioOutput];
- if ([mAudioOutput respondsToSelector:@selector(setAlwaysCopiesSampleData:)]) // Not supported on iOS versions older than 5.0
- mAudioOutput.alwaysCopiesSampleData = NO;
-
- NSArray* desclst = audioTrack.formatDescriptions;
- CMAudioFormatDescriptionRef desc = (CMAudioFormatDescriptionRef) [desclst objectAtIndex:0];
- const AudioStreamBasicDescription* audioDesc = CMAudioFormatDescriptionGetStreamBasicDescription(desc);
- mAudioFrequency = (unsigned int) audioDesc->mSampleRate;
- mNumAudioChannels = audioDesc->mChannelsPerFrame;
-
- if (mSeekFrame != -1)
- {
- mReadAudioSamples = mFrameNumber * (mAudioFrequency * mNumAudioChannels) / mFPS;
- }
- else mReadAudioSamples = 0;
-
- if (mAudioInterface == NULL)
- setAudioInterface(audio_factory->createInstance(this, mNumAudioChannels, mAudioFrequency));
- }
- }
-
-#ifdef _DEBUG
- else if (!mLoaded)
- {
- th_writelog("-----\nwidth: " + str(mWidth) + ", height: " + str(mHeight) + ", fps: " + str((int) getFPS()));
- th_writelog("duration: " + strf(mDuration) + " seconds\n-----");
- }
-#endif
- [mReader startReading];
- [pool release];
- mLoaded = true;
-}
-
-void TheoraVideoClip_AVFoundation::decodedAudioCheck()
-{
- if (!mAudioInterface || mTimer->isPaused()) return;
-
- mAudioMutex->lock();
- flushAudioPackets(mAudioInterface);
- mAudioMutex->unlock();
-}
-
-float TheoraVideoClip_AVFoundation::decodeAudio()
-{
- if (mRestarted) return -1;
-
- if (mReader == NULL || mEndOfFile) return 0;
- AVAssetReaderStatus status = [mReader status];
-
- if (mAudioOutput)
- {
- CMSampleBufferRef sampleBuffer = NULL;
- NSAutoreleasePool* pool = NULL;
- bool mutexLocked = 0;
-
- float factor = 1.0f / (mAudioFrequency * mNumAudioChannels);
- float videoTime = (float) mFrameNumber / mFPS;
- float min = mFrameQueue->getSize() / mFPS + 1.0f;
-
- if (status == AVAssetReaderStatusReading)
- {
- pool = [[NSAutoreleasePool alloc] init];
-
- // always buffer up of audio ahead of the frames
- while (mReadAudioSamples * factor - videoTime < min)
- {
- if ((sampleBuffer = [mAudioOutput copyNextSampleBuffer]))
- {
- AudioBufferList audioBufferList;
-
- CMBlockBufferRef blockBuffer = NULL;
- CMSampleBufferGetAudioBufferListWithRetainedBlockBuffer(sampleBuffer, NULL, &audioBufferList, sizeof(audioBufferList), NULL, NULL, 0, &blockBuffer);
-
- for (int y = 0; y < audioBufferList.mNumberBuffers; ++y)
- {
- AudioBuffer audioBuffer = audioBufferList.mBuffers[y];
- float *frame = (float*) audioBuffer.mData;
-
- if (!mutexLocked)
- {
- mAudioMutex->lock();
- mutexLocked = 1;
- }
- addAudioPacket(frame, audioBuffer.mDataByteSize / (mNumAudioChannels * sizeof(float)), mAudioGain);
-
- mReadAudioSamples += audioBuffer.mDataByteSize / (sizeof(float));
- }
-
- CFRelease(blockBuffer);
- CMSampleBufferInvalidate(sampleBuffer);
- CFRelease(sampleBuffer);
- }
- else
- {
- [mAudioOutput release];
- mAudioOutput = nil;
- break;
- }
- }
- [pool release];
- }
- if (mutexLocked) mAudioMutex->unlock();
- }
-
- return -1;
-}
-
-void TheoraVideoClip_AVFoundation::doSeek()
-{
-#if _DEBUG
- th_writelog(mName + " [seek]: seeking to frame " + str(mSeekFrame));
-#endif
- int frame;
- float time = mSeekFrame / getFPS();
- mTimer->seek(time);
- bool paused = mTimer->isPaused();
- if (!paused) mTimer->pause(); // pause until seeking is done
-
- mEndOfFile = false;
- mRestarted = false;
-
- resetFrameQueue();
- unload();
- load(mStream);
-
- if (mAudioInterface)
- {
- mAudioMutex->lock();
- destroyAllAudioPackets();
- mAudioMutex->unlock();
- }
-
- if (!paused) mTimer->play();
- mSeekFrame = -1;
-}
-#endif
diff --git a/drivers/theoraplayer/src/FFmpeg/TheoraVideoClip_FFmpeg.cpp b/drivers/theoraplayer/src/FFmpeg/TheoraVideoClip_FFmpeg.cpp
deleted file mode 100644
index fa3fd43a47..0000000000
--- a/drivers/theoraplayer/src/FFmpeg/TheoraVideoClip_FFmpeg.cpp
+++ /dev/null
@@ -1,439 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#ifdef __FFMPEG
-#include "TheoraAudioInterface.h"
-#include "TheoraDataSource.h"
-#include "TheoraException.h"
-#include "TheoraTimer.h"
-#include "TheoraUtil.h"
-#include "TheoraFrameQueue.h"
-#include "TheoraVideoFrame.h"
-#include "TheoraVideoManager.h"
-#include "TheoraVideoClip_FFmpeg.h"
-#include "TheoraPixelTransform.h"
-
-#define READ_BUFFER_SIZE 4096
-
-#ifdef __cplusplus
-#define __STDC_CONSTANT_MACROS
-#ifdef _STDINT_H
-#undef _STDINT_H
-#endif
-# include <stdint.h>
-#endif
-
-#define _FFMPEG_DEBUG
-
-extern "C"
-{
-#include <libavcodec/avcodec.h>
-#include <libavformat/avformat.h>
-#include "libavutil/avassert.h"
-}
-
-static bool ffmpegInitialised = 0;
-
-static int readFunction(void* data, uint8_t* buf, int buf_size)
-{
-#ifdef _FFMPEG_DEBUG
- th_writelog("reading " + str(buf_size) + " bytes");
-#endif
-
- TheoraDataSource* src = (TheoraDataSource*) data;
- return src->read(buf, buf_size);
-}
-
-static int64_t seekFunction(void* data, int64_t offset, int whence)
-{
-#ifdef _FFMPEG_DEBUG
- th_writelog("seeking: offset = " + str((long) offset) + ", whence = " + str(whence));
-#endif
-
- TheoraDataSource* src = (TheoraDataSource*) data;
- if (whence == AVSEEK_SIZE)
- return src->size();
- else if (whence == SEEK_SET)
- src->seek((long) offset);
- else if (whence == SEEK_END)
- src->seek(src->size() - (long) offset);
- return src->tell();
-}
-
-static void avlog_theoraplayer(void* p, int level, const char* fmt, va_list vargs)
-{
- th_writelog(fmt);
- static char logstr[2048];
- vsprintf(logstr, fmt, vargs);
- th_writelog("ffmpeg: " + std::string(logstr));
-}
-
-
-std::string text;
-
-static void _log(const char* s)
-{
- text += s;
-// th_writelog(text);
-// text = "";
-}
-
-static void _log(const char c)
-{
- char s[2] = {c, 0};
- _log(s);
-}
-
-static const AVCodec *next_codec_for_id(enum AVCodecID id, const AVCodec *prev,
- int encoder)
-{
- while ((prev = av_codec_next(prev))) {
- if (prev->id == id &&
- (encoder ? av_codec_is_encoder(prev) : av_codec_is_decoder(prev)))
- return prev;
- }
- return NULL;
-}
-
-static int compare_codec_desc(const void *a, const void *b)
-{
- const AVCodecDescriptor **da = (const AVCodecDescriptor **) a;
- const AVCodecDescriptor **db = (const AVCodecDescriptor **) b;
-
- return (*da)->type != (*db)->type ? (*da)->type - (*db)->type :
- strcmp((*da)->name, (*db)->name);
-}
-
-static unsigned get_codecs_sorted(const AVCodecDescriptor ***rcodecs)
-{
- const AVCodecDescriptor *desc = NULL;
- const AVCodecDescriptor **codecs;
- unsigned nb_codecs = 0, i = 0;
-
- while ((desc = avcodec_descriptor_next(desc)))
- ++nb_codecs;
- if (!(codecs = (const AVCodecDescriptor**) av_calloc(nb_codecs, sizeof(*codecs)))) {
- av_log(NULL, AV_LOG_ERROR, "Out of memory\n");
- exit(1);
- }
- desc = NULL;
- while ((desc = avcodec_descriptor_next(desc)))
- codecs[i++] = desc;
- av_assert0(i == nb_codecs);
- qsort(codecs, nb_codecs, sizeof(*codecs), compare_codec_desc);
- *rcodecs = codecs;
- return nb_codecs;
-}
-
-static char get_media_type_char(enum AVMediaType type)
-{
- switch (type) {
- case AVMEDIA_TYPE_VIDEO: return 'V';
- case AVMEDIA_TYPE_AUDIO: return 'A';
- case AVMEDIA_TYPE_DATA: return 'D';
- case AVMEDIA_TYPE_SUBTITLE: return 'S';
- case AVMEDIA_TYPE_ATTACHMENT:return 'T';
- default: return '?';
- }
-}
-
-static void print_codecs_for_id(enum AVCodecID id, int encoder)
-{
- const AVCodec *codec = NULL;
-
- _log(encoder ? "encoders" : "decoders");
-
- while ((codec = next_codec_for_id(id, codec, encoder)))
- _log(codec->name);
-
- _log(")");
-}
-
-int show_codecs(void *optctx, const char *opt, const char *arg)
-{
- const AVCodecDescriptor **codecs;
- unsigned i, nb_codecs = get_codecs_sorted(&codecs);
-
- char tmp[1024];
- th_writelog("Codecs:\n"
- " D..... = Decoding supported\n"
- " .E.... = Encoding supported\n"
- " ..V... = Video codec\n"
- " ..A... = Audio codec\n"
- " ..S... = Subtitle codec\n"
- " ...I.. = Intra frame-only codec\n"
- " ....L. = Lossy compression\n"
- " .....S = Lossless compression\n"
- " -------\n");
- for (i = 0; i < nb_codecs; ++i) {
- const AVCodecDescriptor *desc = codecs[i];
- const AVCodec *codec = NULL;
-
- _log(" ");
- _log(avcodec_find_decoder(desc->id) ? "D" : ".");
- _log(avcodec_find_encoder(desc->id) ? "E" : ".");
-
- _log(get_media_type_char(desc->type));
- _log((desc->props & AV_CODEC_PROP_INTRA_ONLY) ? "I" : ".");
- _log((desc->props & AV_CODEC_PROP_LOSSY) ? "L" : ".");
- _log((desc->props & AV_CODEC_PROP_LOSSLESS) ? "S" : ".");
-
-
- sprintf(tmp, " %-20s %s", desc->name, desc->long_name ? desc->long_name : "");
-
- _log(tmp);
- /* print decoders/encoders when there's more than one or their
- * names are different from codec name */
- while ((codec = next_codec_for_id(desc->id, codec, 0))) {
- if (strcmp(codec->name, desc->name)) {
- print_codecs_for_id(desc->id, 0);
- break;
- }
- }
- codec = NULL;
- while ((codec = next_codec_for_id(desc->id, codec, 1))) {
- if (strcmp(codec->name, desc->name)) {
- print_codecs_for_id(desc->id, 1);
- break;
- }
- }
- _log("\n");
- }
- av_free(codecs);
-
- av_log(0, 0, "%s", text.c_str());
- return 0;
-}
-
-TheoraVideoClip_FFmpeg::TheoraVideoClip_FFmpeg(TheoraDataSource* data_source,
- TheoraOutputMode output_mode,
- int nPrecachedFrames,
- bool usePower2Stride):
- TheoraVideoClip(data_source, output_mode, nPrecachedFrames, usePower2Stride),
- TheoraAudioPacketQueue()
-{
- mFormatContext = NULL;
- mCodecContext = NULL;
- mCodec = NULL;
- mFrame = NULL;
- mVideoStreamIndex = -1;
-}
-
-TheoraVideoClip_FFmpeg::~TheoraVideoClip_FFmpeg()
-{
- unload();
-}
-
-void TheoraVideoClip_FFmpeg::load(TheoraDataSource* source)
-{
- mVideoStreamIndex = -1;
- mFrameNumber = 0;
- AVDictionary* optionsDict = NULL;
-
- if (!ffmpegInitialised)
- {
-#ifdef _FFMPEG_DEBUG
- th_writelog("Initializing ffmpeg");
-#endif
- th_writelog("avcodec version: " + str(avcodec_version()));
- av_register_all();
- av_log_set_level(AV_LOG_DEBUG);
- av_log_set_callback(avlog_theoraplayer);
- ffmpegInitialised = 1;
- //show_codecs(0, 0, 0);
- }
-
- mInputBuffer = (unsigned char*) av_malloc(READ_BUFFER_SIZE);
- mAvioContext = avio_alloc_context(mInputBuffer, READ_BUFFER_SIZE, 0, source, &readFunction, NULL, &seekFunction);
-
-#ifdef _FFMPEG_DEBUG
- th_writelog(mName + ": avio context created");
-#endif
-
- mFormatContext = avformat_alloc_context();
-#ifdef _FFMPEG_DEBUG
- th_writelog(mName + ": avformat context created");
-#endif
- mFormatContext->pb = mAvioContext;
-
- int err;
- if ((err = avformat_open_input(&mFormatContext, "", NULL, NULL)) != 0)
- {
- th_writelog(mName + ": avformat input opening failed!");
- th_writelog(mName + ": error_code: " + str(err));
- return;
- }
-
-#ifdef _FFMPEG_DEBUG
- th_writelog(mName + ": avformat input opened");
-#endif
-
- // Retrieve stream information
- if (avformat_find_stream_info(mFormatContext, NULL) < 0)
- return; // Couldn't find stream information
-
-#ifdef _FFMPEG_DEBUG
- th_writelog(mName + ": got stream info");
-#endif
-
- // Dump information about file onto standard error
- // av_dump_format(mFormatContext, 0, "", 0);
-
- // Find the first video stream
- for (int i = 0; i < mFormatContext->nb_streams; ++i)
- {
- if(mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
- {
- mVideoStreamIndex = i;
- break;
- }
- }
- if (mVideoStreamIndex == -1)
- return; // Didn't find a video stream
-
-#ifdef _FFMPEG_DEBUG
- th_writelog(mName + ": Found video stream at index " + str(mVideoStreamIndex));
-#endif
-
- // Get a pointer to the codec context for the video stream
- mCodecContext = mFormatContext->streams[mVideoStreamIndex]->codec;
-
- // Find the decoder for the video stream
- mCodec = avcodec_find_decoder(mCodecContext->codec_id);
- if (mCodec == NULL)
- {
- th_writelog("Unsupported codec!");
- return; // Codec not found
- }
- // Open codec
- if(avcodec_open2(mCodecContext, mCodec, &optionsDict) < 0)
- return; // Could not open codec
-
-#ifdef _FFMPEG_DEBUG
- th_writelog(mName + ": Codec opened");
-#endif
-
-
- mFrame = avcodec_alloc_frame();
-
-#ifdef _FFMPEG_DEBUG
- th_writelog(mName + ": Frame allocated");
-#endif
-
- //AVRational rational = mCodecContext->time_base;
-
- mFPS = 25; //TODOOOOOO!!!
-
- mWidth = mStride = mCodecContext->width;
- mHeight = mCodecContext->height;
- mFrameDuration = 1.0f / mFPS;
- mDuration = mFormatContext->duration / AV_TIME_BASE;
-
- if (mFrameQueue == NULL) // todo - why is this set in the backend class? it should be set in the base class, check other backends as well
- {
- mFrameQueue = new TheoraFrameQueue(this);
- mFrameQueue->setSize(mNumPrecachedFrames);
- }
-}
-
-void TheoraVideoClip_FFmpeg::unload()
-{
- if (mInputBuffer)
- {
-// av_free(mInputBuffer);
- mInputBuffer = NULL;
- }
- if (mAvioContext)
- {
- av_free(mAvioContext);
- mAvioContext = NULL;
- }
- if (mFrame)
- {
- av_free(mFrame);
- mFrame = NULL;
- }
- if (mCodecContext)
- {
- avcodec_close(mCodecContext);
- mCodecContext = NULL;
- }
- if (mFormatContext)
- {
- avformat_close_input(&mFormatContext);
- mFormatContext = NULL;
- }
-}
-
-bool TheoraVideoClip_FFmpeg::_readData()
-{
- return 1;
-}
-
-bool TheoraVideoClip_FFmpeg::decodeNextFrame()
-{
- TheoraVideoFrame* frame = mFrameQueue->requestEmptyFrame();
- if (!frame) return 0;
-
- AVPacket packet;
- int frameFinished;
-
- while (av_read_frame(mFormatContext, &packet) >= 0)
- {
- if (packet.stream_index == mVideoStreamIndex)
- {
- avcodec_decode_video2(mCodecContext, mFrame, &frameFinished, &packet);
-
- if (frameFinished)
- {
- TheoraPixelTransform t;
- memset(&t, 0, sizeof(TheoraPixelTransform));
-
- t.y = mFrame->data[0]; t.yStride = mFrame->linesize[0];
- t.u = mFrame->data[1]; t.uStride = mFrame->linesize[1];
- t.v = mFrame->data[2]; t.vStride = mFrame->linesize[2];
-
- frame->decode(&t);
- frame->mTimeToDisplay = mFrameNumber / mFPS;
- frame->mIteration = mIteration;
- frame->_setFrameNumber(mFrameNumber++);
-
- av_free_packet(&packet);
- break;
- }
- }
- av_free_packet(&packet);
- }
- return 1;
-}
-
-void TheoraVideoClip_FFmpeg::decodedAudioCheck()
-{
- if (!mAudioInterface || mTimer->isPaused()) return;
-
- mAudioMutex->lock();
- flushAudioPackets(mAudioInterface);
- mAudioMutex->unlock();
-}
-
-float TheoraVideoClip_FFmpeg::decodeAudio()
-{
- return -1;
-}
-
-void TheoraVideoClip_FFmpeg::doSeek()
-{
-
-}
-
-void TheoraVideoClip_FFmpeg::_restart()
-{
-
-}
-
-#endif
diff --git a/drivers/theoraplayer/src/FFmpeg/TheoraVideoClip_FFmpeg.h b/drivers/theoraplayer/src/FFmpeg/TheoraVideoClip_FFmpeg.h
deleted file mode 100644
index 03f9a3d964..0000000000
--- a/drivers/theoraplayer/src/FFmpeg/TheoraVideoClip_FFmpeg.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#if defined(__FFMPEG) && !defined(_TheoraVideoClip_FFmpeg_h)
-#define _TheoraVideoClip_FFmpeg_h
-
-#include "TheoraAudioPacketQueue.h"
-#include "TheoraVideoClip.h"
-
-struct AVFormatContext;
-struct AVCodecContext;
-struct AVCodec;
-struct AVFrame;
-struct AVIOContext;
-
-class TheoraVideoClip_FFmpeg : public TheoraVideoClip, public TheoraAudioPacketQueue
-{
-protected:
- bool mLoaded;
-
- AVFormatContext* mFormatContext;
- AVCodecContext* mCodecContext;
- AVIOContext* mAvioContext;
- AVCodec* mCodec;
- AVFrame* mFrame;
- unsigned char* mInputBuffer;
- int mVideoStreamIndex;
- int mFrameNumber;
-
- void unload();
- void doSeek();
-public:
- TheoraVideoClip_FFmpeg(TheoraDataSource* data_source,
- TheoraOutputMode output_mode,
- int nPrecachedFrames,
- bool usePower2Stride);
- ~TheoraVideoClip_FFmpeg();
-
- bool _readData();
- bool decodeNextFrame();
- void _restart();
- void load(TheoraDataSource* source);
- float decodeAudio();
- void decodedAudioCheck();
- std::string getDecoderName() { return "FFmpeg"; }
-};
-
-#endif
diff --git a/drivers/theoraplayer/src/Theora/TheoraVideoClip_Theora.cpp b/drivers/theoraplayer/src/Theora/TheoraVideoClip_Theora.cpp
deleted file mode 100644
index c4f070ec50..0000000000
--- a/drivers/theoraplayer/src/Theora/TheoraVideoClip_Theora.cpp
+++ /dev/null
@@ -1,703 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#ifdef __THEORA
-#include <memory.h>
-#include <algorithm>
-#include "TheoraVideoManager.h"
-#include "TheoraFrameQueue.h"
-#include "TheoraVideoFrame.h"
-#include "TheoraAudioInterface.h"
-#include "TheoraTimer.h"
-#include "TheoraDataSource.h"
-#include "TheoraUtil.h"
-#include "TheoraException.h"
-#include "TheoraVideoClip_Theora.h"
-#include "TheoraPixelTransform.h"
-
-TheoraVideoClip_Theora::TheoraVideoClip_Theora(TheoraDataSource* data_source,
- TheoraOutputMode output_mode,
- int nPrecachedFrames,
- bool usePower2Stride):
- TheoraVideoClip(data_source, output_mode, nPrecachedFrames, usePower2Stride),
- TheoraAudioPacketQueue()
-{
- mInfo.TheoraDecoder = NULL;
- mInfo.TheoraSetup = NULL;
- mVorbisStreams = mTheoraStreams = 0;
- mReadAudioSamples = 0;
- mLastDecodedFrameNumber = 0;
-}
-
-TheoraVideoClip_Theora::~TheoraVideoClip_Theora()
-{
- if (mInfo.TheoraDecoder)
- {
- th_decode_free(mInfo.TheoraDecoder);
- th_setup_free(mInfo.TheoraSetup);
-
- if (mAudioInterface)
- {
- vorbis_dsp_clear(&mInfo.VorbisDSPState);
- vorbis_block_clear(&mInfo.VorbisBlock);
- }
-
- ogg_stream_clear(&mInfo.TheoraStreamState);
- th_comment_clear(&mInfo.TheoraComment);
- th_info_clear(&mInfo.TheoraInfo);
-
- ogg_stream_clear(&mInfo.VorbisStreamState);
- vorbis_comment_clear(&mInfo.VorbisComment);
- vorbis_info_clear(&mInfo.VorbisInfo);
-
- ogg_sync_clear(&mInfo.OggSyncState);
- }
-}
-
-bool TheoraVideoClip_Theora::_readData()
-{
- int audio_eos = 0, serno;
- float audio_time = 0;
- float time = mTimer->getTime();
- if (mRestarted) time = 0;
-
- for (;;)
- {
- char *buffer = ogg_sync_buffer(&mInfo.OggSyncState, 4096);
- int bytes_read = mStream->read(buffer, 4096);
- ogg_sync_wrote(&mInfo.OggSyncState, bytes_read);
-
- if (bytes_read < 4096)
- {
- if (bytes_read == 0)
- {
- if (!mAutoRestart) mEndOfFile = true;
- return 0;
- }
- }
- // when we fill the stream with enough pages, it'll start spitting out packets
- // which contain keyframes, delta frames or audio data
- while (ogg_sync_pageout(&mInfo.OggSyncState, &mInfo.OggPage) > 0)
- {
- serno = ogg_page_serialno(&mInfo.OggPage);
- if (serno == mInfo.TheoraStreamState.serialno) ogg_stream_pagein(&mInfo.TheoraStreamState, &mInfo.OggPage);
- if (mAudioInterface && serno == mInfo.VorbisStreamState.serialno)
- {
- ogg_int64_t g = ogg_page_granulepos(&mInfo.OggPage);
- audio_time = (float) vorbis_granule_time(&mInfo.VorbisDSPState, g);
- audio_eos = ogg_page_eos(&mInfo.OggPage);
- ogg_stream_pagein(&mInfo.VorbisStreamState, &mInfo.OggPage);
- }
- }
- if (!(mAudioInterface && !audio_eos && audio_time < time + 1.0f))
- break;
- }
- return 1;
-}
-
-bool TheoraVideoClip_Theora::decodeNextFrame()
-{
- if (mEndOfFile) return 0;
-
- TheoraVideoFrame* frame = mFrameQueue->requestEmptyFrame();
- if (!frame) return 0; // max number of precached frames reached
- bool should_restart = 0;
- ogg_packet opTheora;
- ogg_int64_t granulePos;
- th_ycbcr_buffer buff;
- int ret, nAttempts;
- for (;;)
- {
- // ogg_stream_packetout can return -1 and the official docs suggest to do subsequent calls until it succeeds
- // because the data is out of sync. still will limit the number of attempts just in case
- for (ret = -1, nAttempts = 0; ret < 0 && nAttempts < 100; nAttempts++)
- {
- ret = ogg_stream_packetout(&mInfo.TheoraStreamState, &opTheora);
- }
-
- if (ret > 0)
- {
- int status = th_decode_packetin(mInfo.TheoraDecoder, &opTheora, &granulePos);
- if (status != 0 && status != TH_DUPFRAME) continue; // 0 means success
-
- float time = (float) th_granule_time(mInfo.TheoraDecoder, granulePos);
- unsigned long frame_number = (unsigned long) th_granule_frame(mInfo.TheoraDecoder, granulePos);
-
- if (time < mTimer->getTime() && !mRestarted && frame_number % 16 != 0)
- {
- // %16 operation is here to prevent a playback halt during video playback if the decoder can't keep up with demand.
-#ifdef _DEBUG
- th_writelog(mName + ": pre-dropped frame " + str((int) frame_number));
-#endif
- ++mNumDroppedFrames;
- continue; // drop frame
- }
- frame->mTimeToDisplay = time - mFrameDuration;
- frame->mIteration = mIteration;
- frame->_setFrameNumber(frame_number);
- mLastDecodedFrameNumber = frame_number;
- th_decode_ycbcr_out(mInfo.TheoraDecoder, buff);
- TheoraPixelTransform t;
- memset(&t, 0, sizeof(TheoraPixelTransform));
-
- t.y = buff[0].data; t.yStride = buff[0].stride;
- t.u = buff[1].data; t.uStride = buff[1].stride;
- t.v = buff[2].data; t.vStride = buff[2].stride;
- frame->decode(&t);
- break;
- }
- else
- {
- if (!_readData())
- {
- frame->mInUse = 0;
- should_restart = mAutoRestart;
- break;
- }
- }
- }
-
- if (mAudioInterface != NULL)
- {
- mAudioMutex->lock();
- decodeAudio();
- mAudioMutex->unlock();
- }
- if (should_restart)
- {
- ++mIteration;
- _restart();
- }
- return 1;
-}
-
-void TheoraVideoClip_Theora::_restart()
-{
- bool paused = mTimer->isPaused();
- if (!paused) mTimer->pause();
- long granule=0;
- th_decode_ctl(mInfo.TheoraDecoder,TH_DECCTL_SET_GRANPOS,&granule,sizeof(granule));
- th_decode_free(mInfo.TheoraDecoder);
- mInfo.TheoraDecoder=th_decode_alloc(&mInfo.TheoraInfo,mInfo.TheoraSetup);
- ogg_stream_reset(&mInfo.TheoraStreamState);
- if (mAudioInterface)
- {
- // empty the DSP buffer
- //float **pcm;
- //int len = vorbis_synthesis_pcmout(&mInfo.VorbisDSPState,&pcm);
- //if (len) vorbis_synthesis_read(&mInfo.VorbisDSPState,len);
- ogg_packet opVorbis;
- mReadAudioSamples = 0;
- while (ogg_stream_packetout(&mInfo.VorbisStreamState,&opVorbis) > 0)
- {
- if (vorbis_synthesis(&mInfo.VorbisBlock,&opVorbis) == 0)
- vorbis_synthesis_blockin(&mInfo.VorbisDSPState,&mInfo.VorbisBlock);
- }
- ogg_stream_reset(&mInfo.VorbisStreamState);
- }
-
- ogg_sync_reset(&mInfo.OggSyncState);
- mStream->seek(0);
- ogg_int64_t granulePos = 0;
- th_decode_ctl(mInfo.TheoraDecoder, TH_DECCTL_SET_GRANPOS, &granulePos, sizeof(granule));
-
- mEndOfFile = false;
-
- mRestarted = 1;
-
- if (!paused) mTimer->play();
-}
-
-void TheoraVideoClip_Theora::load(TheoraDataSource* source)
-{
-#ifdef _DEBUG
- th_writelog("-----");
-#endif
- mStream = source;
- readTheoraVorbisHeaders();
-
- mInfo.TheoraDecoder = th_decode_alloc(&mInfo.TheoraInfo,mInfo.TheoraSetup);
-
- mWidth = mInfo.TheoraInfo.frame_width;
- mHeight = mInfo.TheoraInfo.frame_height;
- mSubFrameWidth = mInfo.TheoraInfo.pic_width;
- mSubFrameHeight = mInfo.TheoraInfo.pic_height;
- mSubFrameOffsetX = mInfo.TheoraInfo.pic_x;
- mSubFrameOffsetY = mInfo.TheoraInfo.pic_y;
- mStride = (mStride == 1) ? mStride = _nextPow2(getWidth()) : getWidth();
- mFPS = mInfo.TheoraInfo.fps_numerator / (float) mInfo.TheoraInfo.fps_denominator;
-
-#ifdef _DEBUG
- th_writelog("width: " + str(mWidth) + ", height: " + str(mHeight) + ", fps: " + str((int) getFPS()));
-#endif
- mFrameQueue = new TheoraFrameQueue(this);
- mFrameQueue->setSize(mNumPrecachedFrames);
- // find out the duration of the file by seeking to the end
- // having ogg decode pages, extract the granule pos from
- // the last theora page and seek back to beginning of the file
- long streamSize = mStream->size(), seekPos;
- for (int i = 1; i <= 50; ++i)
- {
- ogg_sync_reset(&mInfo.OggSyncState);
- seekPos = streamSize - 4096 * i;
- if (seekPos < 0) seekPos = 0;
- mStream->seek(seekPos);
-
- char *buffer = ogg_sync_buffer(&mInfo.OggSyncState, 4096 * i);
- int bytes_read = mStream->read(buffer, 4096 * i);
- ogg_sync_wrote(&mInfo.OggSyncState, bytes_read);
- ogg_sync_pageseek(&mInfo.OggSyncState, &mInfo.OggPage);
-
- for (;;)
- {
- int ret = ogg_sync_pageout(&mInfo.OggSyncState, &mInfo.OggPage);
- if (ret == 0) break;
- // if page is not a theora page, skip it
- if (ogg_page_serialno(&mInfo.OggPage) != mInfo.TheoraStreamState.serialno) continue;
-
- ogg_int64_t granule = ogg_page_granulepos(&mInfo.OggPage);
- if (granule >= 0)
- {
- mNumFrames = (int) th_granule_frame(mInfo.TheoraDecoder, granule) + 1;
- }
- else if (mNumFrames > 0)
- ++mNumFrames; // append delta frames at the end to get the exact numbe
- }
- if (mNumFrames > 0 || streamSize - 4096 * i < 0) break;
-
- }
- if (mNumFrames < 0)
- th_writelog("unable to determine file duration!");
- else
- {
- mDuration = mNumFrames / mFPS;
-#ifdef _DEBUG
- th_writelog("duration: " + strf(mDuration) + " seconds");
-#endif
- }
- // restore to beginning of stream.
- ogg_sync_reset(&mInfo.OggSyncState);
- mStream->seek(0);
-
- if (mVorbisStreams) // if there is no audio interface factory defined, even though the video
- // clip might have audio, it will be ignored
- {
- vorbis_synthesis_init(&mInfo.VorbisDSPState, &mInfo.VorbisInfo);
- vorbis_block_init(&mInfo.VorbisDSPState, &mInfo.VorbisBlock);
- mNumAudioChannels = mInfo.VorbisInfo.channels;
- mAudioFrequency = (int) mInfo.VorbisInfo.rate;
-
- // create an audio interface instance if available
- TheoraAudioInterfaceFactory* audio_factory = TheoraVideoManager::getSingleton().getAudioInterfaceFactory();
- printf("**** audio factory is %p\n", audio_factory);
- if (audio_factory) setAudioInterface(audio_factory->createInstance(this, mNumAudioChannels, mAudioFrequency));
- }
-
- mFrameDuration = 1.0f / getFPS();
-#ifdef _DEBUG
- th_writelog("-----");
-#endif
-}
-
-void TheoraVideoClip_Theora::readTheoraVorbisHeaders()
-{
- ogg_packet tempOggPacket;
- bool done = false;
- bool decode_audio=TheoraVideoManager::getSingleton().getAudioInterfaceFactory() != NULL;
- //init Vorbis/Theora Layer
- //Ensure all structures get cleared out.
- memset(&mInfo.OggSyncState, 0, sizeof(ogg_sync_state));
- memset(&mInfo.OggPage, 0, sizeof(ogg_page));
- memset(&mInfo.VorbisStreamState, 0, sizeof(ogg_stream_state));
- memset(&mInfo.TheoraStreamState, 0, sizeof(ogg_stream_state));
- memset(&mInfo.TheoraInfo, 0, sizeof(th_info));
- memset(&mInfo.TheoraComment, 0, sizeof(th_comment));
- memset(&mInfo.VorbisInfo, 0, sizeof(vorbis_info));
- memset(&mInfo.VorbisDSPState, 0, sizeof(vorbis_dsp_state));
- memset(&mInfo.VorbisBlock, 0, sizeof(vorbis_block));
- memset(&mInfo.VorbisComment, 0, sizeof(vorbis_comment));
-
- ogg_sync_init(&mInfo.OggSyncState);
- th_comment_init(&mInfo.TheoraComment);
- th_info_init(&mInfo.TheoraInfo);
- vorbis_info_init(&mInfo.VorbisInfo);
- vorbis_comment_init(&mInfo.VorbisComment);
-
- while (!done)
- {
- char *buffer = ogg_sync_buffer(&mInfo.OggSyncState, 4096);
- int bytes_read = mStream->read(buffer, 4096);
- ogg_sync_wrote(&mInfo.OggSyncState, bytes_read);
-
- if (bytes_read == 0)
- break;
-
- while (ogg_sync_pageout(&mInfo.OggSyncState, &mInfo.OggPage) > 0)
- {
- ogg_stream_state OggStateTest;
-
- //is this an initial header? If not, stop
- if (!ogg_page_bos(&mInfo.OggPage))
- {
- //This is done blindly, because stream only accept themselves
- if (mTheoraStreams) ogg_stream_pagein(&mInfo.TheoraStreamState, &mInfo.OggPage);
- if (mVorbisStreams) ogg_stream_pagein(&mInfo.VorbisStreamState, &mInfo.OggPage);
-
- done=true;
- break;
- }
-
- ogg_stream_init(&OggStateTest, ogg_page_serialno(&mInfo.OggPage));
- ogg_stream_pagein(&OggStateTest, &mInfo.OggPage);
- ogg_stream_packetout(&OggStateTest, &tempOggPacket);
-
- //identify the codec
- int ret;
- if (!mTheoraStreams)
- {
- ret = th_decode_headerin(&mInfo.TheoraInfo, &mInfo.TheoraComment, &mInfo.TheoraSetup, &tempOggPacket);
-
- if (ret > 0)
- {
- //This is the Theora Header
- memcpy(&mInfo.TheoraStreamState, &OggStateTest, sizeof(OggStateTest));
- mTheoraStreams = 1;
- continue;
- }
- }
- if (decode_audio && !mVorbisStreams &&
- vorbis_synthesis_headerin(&mInfo.VorbisInfo, &mInfo.VorbisComment, &tempOggPacket) >=0)
- {
- //This is vorbis header
- memcpy(&mInfo.VorbisStreamState, &OggStateTest, sizeof(OggStateTest));
- mVorbisStreams = 1;
- continue;
- }
- //Hmm. I guess it's not a header we support, so erase it
- ogg_stream_clear(&OggStateTest);
- }
- }
-
- while ((mTheoraStreams && (mTheoraStreams < 3)) ||
- (mVorbisStreams && (mVorbisStreams < 3)))
- {
- //Check 2nd'dary headers... Theora First
- int iSuccess;
- while (mTheoraStreams && mTheoraStreams < 3 &&
- (iSuccess = ogg_stream_packetout(&mInfo.TheoraStreamState, &tempOggPacket)))
- {
- if (iSuccess < 0)
- throw TheoraGenericException("Error parsing Theora stream headers.");
- if (!th_decode_headerin(&mInfo.TheoraInfo, &mInfo.TheoraComment, &mInfo.TheoraSetup, &tempOggPacket))
- throw TheoraGenericException("invalid theora stream");
-
- ++mTheoraStreams;
- } //end while looking for more theora headers
-
- //look 2nd vorbis header packets
- while (mVorbisStreams < 3 && (iSuccess = ogg_stream_packetout(&mInfo.VorbisStreamState, &tempOggPacket)))
- {
- if (iSuccess < 0)
- throw TheoraGenericException("Error parsing vorbis stream headers");
-
- if (vorbis_synthesis_headerin(&mInfo.VorbisInfo, &mInfo.VorbisComment,&tempOggPacket))
- throw TheoraGenericException("invalid stream");
-
- ++mVorbisStreams;
- } //end while looking for more vorbis headers
-
- //Not finished with Headers, get some more file data
- if (ogg_sync_pageout(&mInfo.OggSyncState, &mInfo.OggPage) > 0)
- {
- if (mTheoraStreams) ogg_stream_pagein(&mInfo.TheoraStreamState, &mInfo.OggPage);
- if (mVorbisStreams) ogg_stream_pagein(&mInfo.VorbisStreamState, &mInfo.OggPage);
- }
- else
- {
- char *buffer = ogg_sync_buffer(&mInfo.OggSyncState, 4096);
- int bytes_read = mStream->read(buffer, 4096);
- ogg_sync_wrote(&mInfo.OggSyncState, bytes_read);
-
- if (bytes_read == 0)
- throw TheoraGenericException("End of file found prematurely");
- }
- } //end while looking for all headers
- // writelog("Vorbis Headers: " + str(mVorbisHeaders) + " Theora Headers : " + str(mTheoraHeaders));
-}
-
-void TheoraVideoClip_Theora::decodedAudioCheck()
-{
- if (!mAudioInterface || mTimer->isPaused()) return;
-
- mAudioMutex->lock();
- flushAudioPackets(mAudioInterface);
- mAudioMutex->unlock();
-}
-
-float TheoraVideoClip_Theora::decodeAudio()
-{
- if (mRestarted) return -1;
-
- ogg_packet opVorbis;
- float **pcm;
- int len = 0;
- float timestamp = -1;
- bool read_past_timestamp = 0;
-
- float factor = 1.0f / mAudioFrequency;
- float videoTime = (float) mLastDecodedFrameNumber / mFPS;
- float min = mFrameQueue->getSize() / mFPS + 1.0f;
-
- for (;;)
- {
- len = vorbis_synthesis_pcmout(&mInfo.VorbisDSPState, &pcm);
- if (len == 0)
- {
- if (ogg_stream_packetout(&mInfo.VorbisStreamState, &opVorbis) > 0)
- {
- if (vorbis_synthesis(&mInfo.VorbisBlock, &opVorbis) == 0)
- {
- if (timestamp < 0 && opVorbis.granulepos >= 0)
- {
- timestamp = (float) vorbis_granule_time(&mInfo.VorbisDSPState, opVorbis.granulepos);
- }
- else if (timestamp >= 0) read_past_timestamp = 1;
- vorbis_synthesis_blockin(&mInfo.VorbisDSPState, &mInfo.VorbisBlock);
- }
- continue;
- }
- else
- {
- float audioTime = mReadAudioSamples * factor;
- // always buffer up of audio ahead of the frames
- if (audioTime - videoTime < min)
- {
- if (!_readData()) break;
- }
- else
- break;
- }
- }
- addAudioPacket(pcm, len, mAudioGain);
- mReadAudioSamples += len;
- if (read_past_timestamp) timestamp += (float) len / mInfo.VorbisInfo.rate;
- vorbis_synthesis_read(&mInfo.VorbisDSPState, len); // tell vorbis we read a number of samples
- }
- return timestamp;
-}
-
-long TheoraVideoClip_Theora::seekPage(long targetFrame, bool return_keyframe)
-{
- int i,seek_min = 0, seek_max = (int) mStream->size();
- long frame;
- ogg_int64_t granule = 0;
-
- if (targetFrame == 0) mStream->seek(0);
- for (i = (targetFrame == 0) ? 100 : 0; i < 100; ++i)
- {
- ogg_sync_reset(&mInfo.OggSyncState);
- mStream->seek((seek_min + seek_max) / 2); // do a binary search
- memset(&mInfo.OggPage, 0, sizeof(ogg_page));
- ogg_sync_pageseek(&mInfo.OggSyncState, &mInfo.OggPage);
-
- for (;i < 1000;)
- {
- int ret = ogg_sync_pageout(&mInfo.OggSyncState, &mInfo.OggPage);
- if (ret == 1)
- {
- int serno = ogg_page_serialno(&mInfo.OggPage);
- if (serno == mInfo.TheoraStreamState.serialno)
- {
- granule = ogg_page_granulepos(&mInfo.OggPage);
- if (granule >= 0)
- {
- frame = (long) th_granule_frame(mInfo.TheoraDecoder, granule);
- if (frame < targetFrame && targetFrame - frame < 10)
- {
- // we're close enough, let's break this.
- i = 1000;
- break;
- }
- // we're not close enough, let's shorten the borders of the binary search
- if (targetFrame - 1 > frame) seek_min = (seek_min + seek_max) / 2;
- else seek_max = (seek_min + seek_max) / 2;
- break;
- }
- }
- }
- else
- {
- char *buffer = ogg_sync_buffer(&mInfo.OggSyncState, 4096);
- int bytes_read = mStream->read(buffer, 4096);
- if (bytes_read == 0) break;
- ogg_sync_wrote(&mInfo.OggSyncState, bytes_read);
- }
- }
- }
- if (return_keyframe) return (long) (granule >> mInfo.TheoraInfo.keyframe_granule_shift);
-
- ogg_sync_reset(&mInfo.OggSyncState);
- memset(&mInfo.OggPage, 0, sizeof(ogg_page));
- ogg_sync_pageseek(&mInfo.OggSyncState, &mInfo.OggPage);
- if (targetFrame == 0) return -1;
- mStream->seek((seek_min + seek_max) / 2); // do a binary search
- return -1;
-}
-
-void TheoraVideoClip_Theora::doSeek()
-{
-#if _DEBUG
- th_writelog(mName + " [seek]: seeking to frame " + str(mSeekFrame));
-#endif
- int frame;
- float time = mSeekFrame / getFPS();
- mTimer->seek(time);
- bool paused = mTimer->isPaused();
- if (!paused) mTimer->pause(); // pause until seeking is done
-
- mEndOfFile = false;
- mRestarted = false;
-
- resetFrameQueue();
- // reset the video decoder.
- ogg_stream_reset(&mInfo.TheoraStreamState);
- th_decode_free(mInfo.TheoraDecoder);
- mInfo.TheoraDecoder = th_decode_alloc(&mInfo.TheoraInfo, mInfo.TheoraSetup);
-
- if (mAudioInterface)
- {
- mAudioMutex->lock();
- ogg_stream_reset(&mInfo.VorbisStreamState);
- vorbis_synthesis_restart(&mInfo.VorbisDSPState);
- destroyAllAudioPackets();
- }
- // first seek to desired frame, then figure out the location of the
- // previous keyframe and seek to it.
- // then by setting the correct time, the decoder will skip N frames untill
- // we get the frame we want.
- frame = (int) seekPage(mSeekFrame, 1); // find the keyframe nearest to the target frame
-#ifdef _DEBUG
- // th_writelog(mName + " [seek]: nearest keyframe for frame " + str(mSeekFrame) + " is frame: " + str(frame));
-#endif
- seekPage(std::max(0, frame - 1), 0);
-
- ogg_packet opTheora;
- ogg_int64_t granulePos;
- bool granule_set = 0;
- if (frame <= 1)
- {
- if (mInfo.TheoraInfo.version_major == 3 && mInfo.TheoraInfo.version_minor == 2 && mInfo.TheoraInfo.version_subminor == 0)
- granulePos = 0;
- else
- granulePos = 1; // because of difference in granule interpretation in theora streams 3.2.0 and newer ones
- th_decode_ctl(mInfo.TheoraDecoder, TH_DECCTL_SET_GRANPOS, &granulePos, sizeof(granulePos));
- granule_set = 1;
- }
-
- // now that we've found the keyframe that preceeds our desired frame, lets keep on decoding frames until we
- // reach our target frame.
-
- int status, ret;
- for (;mSeekFrame != 0;)
- {
- ret = ogg_stream_packetout(&mInfo.TheoraStreamState, &opTheora);
- if (ret > 0)
- {
- if (!granule_set)
- {
- // theora decoder requires to set the granule pos after seek to be able to determine the current frame
- if (opTheora.granulepos >= 0)
- {
- th_decode_ctl(mInfo.TheoraDecoder, TH_DECCTL_SET_GRANPOS, &opTheora.granulepos, sizeof(opTheora.granulepos));
- granule_set = 1;
- }
- else continue; // ignore prev delta frames until we hit a keyframe
- }
- status = th_decode_packetin(mInfo.TheoraDecoder, &opTheora, &granulePos);
- if (status != 0 && status != TH_DUPFRAME) continue;
- frame = (int) th_granule_frame(mInfo.TheoraDecoder, granulePos);
- if (frame >= mSeekFrame - 1) break;
- }
- else
- {
- if (!_readData())
- {
- th_writelog(mName + " [seek]: fineseeking failed, _readData failed!");
- if (mAudioInterface) mAudioMutex->unlock();
- return;
- }
- }
- }
-#ifdef _DEBUG
- // th_writelog(mName + " [seek]: fineseeked to frame " + str(frame + 1) + ", requested: " + str(mSeekFrame));
-#endif
- if (mAudioInterface)
- {
- // read audio data until we reach a timestamp. this usually takes only one iteration, but just in case let's
- // wrap it in a loop
- float timestamp;
- for (;;)
- {
- timestamp = decodeAudio();
- if (timestamp >= 0) break;
- else _readData();
- }
- float rate = (float) mAudioFrequency * mNumAudioChannels;
- float queued_time = getAudioPacketQueueLength();
- // at this point there are only 2 possibilities: either we have too much packets and we have to delete
- // the first N ones, or we don't have enough, so let's fill the gap with silence.
- if (time > timestamp - queued_time)
- {
- while (mTheoraAudioPacketQueue != NULL)
- {
- if (time > timestamp - queued_time + mTheoraAudioPacketQueue->numSamples / rate)
- {
- queued_time -= mTheoraAudioPacketQueue->numSamples / rate;
- destroyAudioPacket(popAudioPacket());
- }
- else
- {
- int n_trim = (int) ((timestamp - queued_time + mTheoraAudioPacketQueue->numSamples / rate - time) * rate);
- if (mTheoraAudioPacketQueue->numSamples - n_trim <= 0)
- destroyAudioPacket(popAudioPacket()); // if there's no data to be left, just destroy it
- else
- {
- for (int i = n_trim, j = 0; i < mTheoraAudioPacketQueue->numSamples; ++i, ++j)
- mTheoraAudioPacketQueue->pcm[j] = mTheoraAudioPacketQueue->pcm[i];
- mTheoraAudioPacketQueue->numSamples -= n_trim;
- }
- break;
- }
- }
- }
- else
- {
- // expand the first packet with silence.
- if (mTheoraAudioPacketQueue) // just in case!
- {
- int i, j, nmissing = (int) ((timestamp - queued_time - time) * rate);
- if (nmissing > 0)
- {
- float* samples = new float[nmissing + mTheoraAudioPacketQueue->numSamples];
- for (i = 0; i < nmissing; ++i) samples[i] = 0;
- for (j = 0; i < nmissing + mTheoraAudioPacketQueue->numSamples; ++i, ++j)
- samples[i] = mTheoraAudioPacketQueue->pcm[j];
- delete [] mTheoraAudioPacketQueue->pcm;
- mTheoraAudioPacketQueue->pcm = samples;
- }
- }
- }
- mLastDecodedFrameNumber = mSeekFrame;
- mReadAudioSamples = (unsigned int) (timestamp * mAudioFrequency);
-
- mAudioMutex->unlock();
- }
- if (!paused) mTimer->play();
- mSeekFrame = -1;
-}
-#endif
diff --git a/drivers/theoraplayer/src/Theora/TheoraVideoClip_Theora.h b/drivers/theoraplayer/src/Theora/TheoraVideoClip_Theora.h
deleted file mode 100644
index c64c183029..0000000000
--- a/drivers/theoraplayer/src/Theora/TheoraVideoClip_Theora.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#if defined(__THEORA) && !defined(_TheoraVideoClip_Theora_h)
-#define _TheoraVideoClip_Theora_h
-
-#include <ogg/ogg.h>
-#include <vorbis/vorbisfile.h>
-#include <theora/theoradec.h>
-#include "TheoraAudioPacketQueue.h"
-#include "TheoraVideoClip.h"
-
-struct TheoraInfoStruct
-{
- // ogg/vorbis/theora variables
- ogg_sync_state OggSyncState;
- ogg_page OggPage;
- ogg_stream_state VorbisStreamState;
- ogg_stream_state TheoraStreamState;
- //Theora State
- th_info TheoraInfo;
- th_comment TheoraComment;
- th_setup_info* TheoraSetup;
- th_dec_ctx* TheoraDecoder;
- //Vorbis State
- vorbis_info VorbisInfo;
- vorbis_dsp_state VorbisDSPState;
- vorbis_block VorbisBlock;
- vorbis_comment VorbisComment;
-};
-
-class TheoraVideoClip_Theora : public TheoraVideoClip, public TheoraAudioPacketQueue
-{
-protected:
- TheoraInfoStruct mInfo; // a pointer is used to avoid having to include theora & vorbis headers
- int mTheoraStreams, mVorbisStreams; // Keeps track of Theora and Vorbis Streams
-
- long seekPage(long targetFrame, bool return_keyframe);
- void doSeek();
- void readTheoraVorbisHeaders();
- unsigned int mReadAudioSamples;
- unsigned long mLastDecodedFrameNumber;
-public:
- TheoraVideoClip_Theora(TheoraDataSource* data_source,
- TheoraOutputMode output_mode,
- int nPrecachedFrames,
- bool usePower2Stride);
- ~TheoraVideoClip_Theora();
-
- bool _readData();
- bool decodeNextFrame();
- void _restart();
- void load(TheoraDataSource* source);
- float decodeAudio();
- void decodedAudioCheck();
- std::string getDecoderName() { return "Theora"; }
-};
-
-#endif
diff --git a/drivers/theoraplayer/src/TheoraAsync.cpp b/drivers/theoraplayer/src/TheoraAsync.cpp
deleted file mode 100644
index cc3b7a4bf5..0000000000
--- a/drivers/theoraplayer/src/TheoraAsync.cpp
+++ /dev/null
@@ -1,253 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#ifdef _WIN32
-#include <windows.h>
-#else
-#include <unistd.h>
-#include <pthread.h>
-#endif
-
-#include "TheoraAsync.h"
-#include "TheoraUtil.h"
-
-#ifdef _WINRT
-#include <wrl.h>
-#endif
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Mutex
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-TheoraMutex::TheoraMutex()
-{
-#ifdef _WIN32
-#ifndef _WINRT // WinXP does not have CreateTheoraMutexEx()
- mHandle = CreateMutex(0, 0, 0);
-#else
- mHandle = CreateMutexEx(NULL, NULL, 0, SYNCHRONIZE);
-#endif
-#else
- mHandle = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t));
- pthread_mutex_init((pthread_mutex_t*)mHandle, 0);
-#endif
-}
-
-TheoraMutex::~TheoraMutex()
-{
-#ifdef _WIN32
- CloseHandle(mHandle);
-#else
- pthread_mutex_destroy((pthread_mutex_t*)mHandle);
- free((pthread_mutex_t*)mHandle);
- mHandle = NULL;
-#endif
-}
-
-void TheoraMutex::lock()
-{
-#ifdef _WIN32
- WaitForSingleObjectEx(mHandle, INFINITE, FALSE);
-#else
- pthread_mutex_lock((pthread_mutex_t*)mHandle);
-#endif
-}
-
-void TheoraMutex::unlock()
-{
-#ifdef _WIN32
- ReleaseMutex(mHandle);
-#else
- pthread_mutex_unlock((pthread_mutex_t*)mHandle);
-#endif
-}
-
-///////////////////////////////////////////////////////////////////////////////////////////////////
-// Thread
-///////////////////////////////////////////////////////////////////////////////////////////////////
-
-#ifdef _WINRT
-using namespace Windows::Foundation;
-using namespace Windows::System::Threading;
-#endif
-
-#ifdef _WIN32
-unsigned long WINAPI theoraAsyncCall(void* param)
-#else
-void* theoraAsyncCall(void* param)
-#endif
-{
- TheoraThread* t = (TheoraThread*)param;
- t->execute();
-#ifdef _WIN32
- return 0;
-#else
- pthread_exit(NULL);
- return NULL;
-#endif
-}
-
-#ifdef _WINRT
-struct TheoraAsyncActionWrapper
-{
-public:
- IAsyncAction^ mAsyncAction;
- TheoraAsyncActionWrapper(IAsyncAction^ asyncAction)
- {
- mAsyncAction = asyncAction;
- }
-};
-#endif
-
-TheoraThread::TheoraThread() : mRunning(false), mId(0)
-{
-#ifndef _WIN32
- mId = (pthread_t*)malloc(sizeof(pthread_t));
-#endif
-}
-
-TheoraThread::~TheoraThread()
-{
- if (mRunning)
- {
- stop();
- }
- if (mId != NULL)
- {
-#ifdef _WIN32
-#ifndef _WINRT
- CloseHandle(mId);
-#else
- delete mId;
-#endif
-#else
- free((pthread_t*)mId);
-#endif
- mId = NULL;
- }
-}
-
-void TheoraThread::start()
-{
- mRunning = true;
-#ifdef _WIN32
-#ifndef _WINRT
- mId = CreateThread(0, 0, &theoraAsyncCall, this, 0, 0);
-#else
- mId = new TheoraAsyncActionWrapper(ThreadPool::RunAsync(
- ref new WorkItemHandler([&](IAsyncAction^ work_item)
- {
- execute();
- }),
- WorkItemPriority::Normal, WorkItemOptions::TimeSliced));
-#endif
-#else
- pthread_create((pthread_t*)mId, NULL, &theoraAsyncCall, this);
-#endif
-}
-
-bool TheoraThread::isRunning()
-{
- bool ret;
- mRunningMutex.lock();
- ret = mRunning;
- mRunningMutex.unlock();
-
- return ret;
-}
-
-void TheoraThread::join()
-{
- mRunningMutex.lock();
- mRunning = false;
- mRunningMutex.unlock();
-#ifdef _WIN32
-#ifndef _WINRT
- WaitForSingleObject(mId, INFINITE);
- if (mId != NULL)
- {
- CloseHandle(mId);
- mId = NULL;
- }
-#else
- IAsyncAction^ action = ((TheoraAsyncActionWrapper*)mId)->mAsyncAction;
- int i = 0;
- while (action->Status != AsyncStatus::Completed &&
- action->Status != AsyncStatus::Canceled &&
- action->Status != AsyncStatus::Error &&
- i < 100)
- {
- _psleep(50);
- ++i;
- }
- if (i >= 100)
- {
- i = 0;
- action->Cancel();
- while (action->Status != AsyncStatus::Completed &&
- action->Status != AsyncStatus::Canceled &&
- action->Status != AsyncStatus::Error &&
- i < 100)
- {
- _psleep(50);
- ++i;
- }
- }
-#endif
-#else
- pthread_join(*((pthread_t*)mId), 0);
-#endif
-}
-
-void TheoraThread::resume()
-{
-#ifdef _WIN32
-#ifndef _WINRT
- ResumeThread(mId);
-#else
- // not available in WinRT
-#endif
-#endif
-}
-
-void TheoraThread::pause()
-{
-#ifdef _WIN32
-#ifndef _WINRT
- SuspendThread(mId);
-#else
- // not available in WinRT
-#endif
-#endif
-}
-
-void TheoraThread::stop()
-{
- if (mRunning)
- {
- mRunningMutex.lock();
- mRunning = false;
- mRunningMutex.unlock();
-#ifdef _WIN32
-#ifndef _WINRT
- TerminateThread(mId, 0);
-#else
- ((TheoraAsyncActionWrapper*)mId)->mAsyncAction->Cancel();
-#endif
-#elif defined(_ANDROID)
- pthread_kill(*((pthread_t*)mId), 0);
-#else
- pthread_cancel(*((pthread_t*)mId));
-#endif
- }
-}
-
diff --git a/drivers/theoraplayer/src/TheoraAudioInterface.cpp b/drivers/theoraplayer/src/TheoraAudioInterface.cpp
deleted file mode 100644
index a265cb57b5..0000000000
--- a/drivers/theoraplayer/src/TheoraAudioInterface.cpp
+++ /dev/null
@@ -1,21 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#include "TheoraAudioInterface.h"
-
-TheoraAudioInterface::TheoraAudioInterface(TheoraVideoClip* owner, int nChannels, int freq)
-{
- mFreq = freq;
- mNumChannels = nChannels;
- mClip = owner;
-}
-
-TheoraAudioInterface::~TheoraAudioInterface()
-{
-
-}
diff --git a/drivers/theoraplayer/src/TheoraAudioPacketQueue.cpp b/drivers/theoraplayer/src/TheoraAudioPacketQueue.cpp
deleted file mode 100644
index be5e1018f9..0000000000
--- a/drivers/theoraplayer/src/TheoraAudioPacketQueue.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#include <stdlib.h>
-#include "TheoraAudioPacketQueue.h"
-#include "TheoraAudioInterface.h"
-
-TheoraAudioPacketQueue::TheoraAudioPacketQueue()
-{
- mTheoraAudioPacketQueue = NULL;
-}
-
-TheoraAudioPacketQueue::~TheoraAudioPacketQueue()
-{
- destroyAllAudioPackets();
-}
-
-float TheoraAudioPacketQueue::getAudioPacketQueueLength()
-{
- float len = 0;
- for (TheoraAudioPacket* p = mTheoraAudioPacketQueue; p != NULL; p = p->next)
- len += p->numSamples;
-
- return len / (mAudioFrequency * mNumAudioChannels);
-}
-
-void TheoraAudioPacketQueue::_addAudioPacket(float* data, int numSamples)
-{
- TheoraAudioPacket* packet = new TheoraAudioPacket;
- packet->pcm = data;
- packet->numSamples = numSamples;
- packet->next = NULL;
-
-
- if (mTheoraAudioPacketQueue == NULL) mTheoraAudioPacketQueue = packet;
- else
- {
- TheoraAudioPacket* last = mTheoraAudioPacketQueue;
- for (TheoraAudioPacket* p = last; p != NULL; p = p->next)
- last = p;
- last->next = packet;
- }
-}
-
-void TheoraAudioPacketQueue::addAudioPacket(float** buffer, int numSamples, float gain)
-{
- float* data = new float[numSamples * mNumAudioChannels];
- float* dataptr = data;
- int i;
- unsigned int j;
-
- if (gain < 1.0f)
- {
- // apply gain, let's attenuate the samples
- for (i = 0; i < numSamples; ++i)
- for (j = 0; j < mNumAudioChannels; j++, ++dataptr)
- *dataptr = buffer[i][j] * gain;
- }
- else
- {
- // do a simple copy, faster then the above method, when gain is 1.0f
- for (i = 0; i < numSamples; ++i)
- for (j = 0; j < mNumAudioChannels; j++, ++dataptr)
- *dataptr = buffer[j][i];
- }
-
- _addAudioPacket(data, numSamples * mNumAudioChannels);
-}
-
-void TheoraAudioPacketQueue::addAudioPacket(float* buffer, int numSamples, float gain)
-{
- float* data = new float[numSamples * mNumAudioChannels];
- float* dataptr = data;
- int i, numFloats = numSamples * mNumAudioChannels;
-
- if (gain < 1.0f)
- {
- // apply gain, let's attenuate the samples
- for (i = 0; i < numFloats; ++i, dataptr++)
- *dataptr = buffer[i] * gain;
- }
- else
- {
- // do a simple copy, faster then the above method, when gain is 1.0f
- for (i = 0; i < numFloats; ++i, dataptr++)
- *dataptr = buffer[i];
- }
-
- _addAudioPacket(data, numFloats);
-}
-
-TheoraAudioPacket* TheoraAudioPacketQueue::popAudioPacket()
-{
- if (mTheoraAudioPacketQueue == NULL) return NULL;
- TheoraAudioPacket* p = mTheoraAudioPacketQueue;
- mTheoraAudioPacketQueue = mTheoraAudioPacketQueue->next;
- return p;
-}
-
-void TheoraAudioPacketQueue::destroyAudioPacket(TheoraAudioPacket* p)
-{
- if (p == NULL) return;
- delete [] p->pcm;
- delete p;
-}
-
-void TheoraAudioPacketQueue::destroyAllAudioPackets()
-{
- for (TheoraAudioPacket* p = popAudioPacket(); p != NULL; p = popAudioPacket())
- destroyAudioPacket(p);
-}
-
-void TheoraAudioPacketQueue::flushAudioPackets(TheoraAudioInterface* audioInterface)
-{
-
- for (TheoraAudioPacket* p = popAudioPacket(); p != NULL; p = popAudioPacket())
- {
- audioInterface->insertData(p->pcm, p->numSamples);
- destroyAudioPacket(p);
- }
-} \ No newline at end of file
diff --git a/drivers/theoraplayer/src/TheoraDataSource.cpp b/drivers/theoraplayer/src/TheoraDataSource.cpp
deleted file mode 100644
index 6011dc6783..0000000000
--- a/drivers/theoraplayer/src/TheoraDataSource.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#include <stdio.h>
-#include <memory.h>
-#include "TheoraDataSource.h"
-#include "TheoraException.h"
-#include "TheoraVideoManager.h"
-#include "TheoraUtil.h"
-
-TheoraDataSource::~TheoraDataSource()
-{
-
-}
-
-TheoraFileDataSource::TheoraFileDataSource(std::string filename)
-{
- mFilename = filename;
- mFilePtr = NULL;
-}
-
-TheoraFileDataSource::~TheoraFileDataSource()
-{
- if (mFilePtr)
- {
- fclose(mFilePtr);
- mFilePtr = NULL;
- }
-}
-
-void TheoraFileDataSource::openFile()
-{
- if (mFilePtr == NULL)
- {
- mFilePtr=fopen(mFilename.c_str(), "rb");
- if (!mFilePtr)
- {
- std::string msg = "Can't open video file: " + mFilename;
- th_writelog(msg);
- throw TheoraGenericException(msg);
- }
- fseek(mFilePtr, 0, SEEK_END);
- mSize = ftell(mFilePtr);
- fseek(mFilePtr, 0, SEEK_SET);
- }
-}
-
-int TheoraFileDataSource::read(void* output, int nBytes)
-{
- if (mFilePtr == NULL) openFile();
- size_t n = fread(output, 1, nBytes, mFilePtr);
- return (int) n;
-}
-
-void TheoraFileDataSource::seek(unsigned long byte_index)
-{
- if (mFilePtr == NULL) openFile();
- fseek(mFilePtr, byte_index, SEEK_SET);
-}
-
-unsigned long TheoraFileDataSource::size()
-{
- if (mFilePtr == NULL) openFile();
- return mSize;
-}
-
-unsigned long TheoraFileDataSource::tell()
-{
- if (mFilePtr == NULL) return 0;
- return ftell(mFilePtr);
-}
-
-TheoraMemoryFileDataSource::TheoraMemoryFileDataSource(std::string filename) :
- mReadPointer(0),
- mData(0)
-{
- mFilename=filename;
- FILE* f=fopen(filename.c_str(),"rb");
- if (!f) throw TheoraGenericException("Can't open video file: "+filename);
- fseek(f,0,SEEK_END);
- mSize=ftell(f);
- fseek(f,0,SEEK_SET);
- mData=new unsigned char[mSize];
- fread(mData,1,mSize,f);
- fclose(f);
-}
-
-TheoraMemoryFileDataSource::TheoraMemoryFileDataSource(unsigned char* data, long size, const std::string& filename)
-{
- mFilename = filename;
- mData = data;
- mSize = size;
- mReadPointer = 0;
-}
-
-TheoraMemoryFileDataSource::~TheoraMemoryFileDataSource()
-{
- if (mData) delete [] mData;
-}
-
-int TheoraMemoryFileDataSource::read(void* output, int nBytes)
-{
- int n = (int) ((mReadPointer+nBytes <= mSize) ? nBytes : mSize - mReadPointer);
- if (!n) return 0;
- memcpy(output, mData + mReadPointer, n);
- mReadPointer += n;
- return n;
-}
-
-void TheoraMemoryFileDataSource::seek(unsigned long byte_index)
-{
- mReadPointer=byte_index;
-}
-
-unsigned long TheoraMemoryFileDataSource::size()
-{
- return mSize;
-}
-
-unsigned long TheoraMemoryFileDataSource::tell()
-{
- return mReadPointer;
-}
diff --git a/drivers/theoraplayer/src/TheoraException.cpp b/drivers/theoraplayer/src/TheoraException.cpp
deleted file mode 100644
index 4588a81397..0000000000
--- a/drivers/theoraplayer/src/TheoraException.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#include "TheoraException.h"
-#include "TheoraUtil.h"
-#include "TheoraVideoManager.h"
-#include <stdio.h>
-
-_TheoraGenericException::_TheoraGenericException(const std::string& errorText, std::string type, std::string file, int line)
-{
- mErrText = errorText;
- int src = (int) file.find("src");
- if (src >= 0) file = file.substr(src + 4, 1000);
- mLineNumber = line;
- mFile = file;
-}
-
-
-std::string _TheoraGenericException::repr()
-{
- std::string text = getType();
- if (text != "") text += ": ";
-
- if (mFile != "") text += "[" + mFile + ":" + str(mLineNumber) + "] - ";
-
- return text + getErrorText();
-}
-
-void _TheoraGenericException::writeOutput()
-{
- th_writelog("----------------\nException Error!\n\n" + repr() + "\n----------------");
-}
diff --git a/drivers/theoraplayer/src/TheoraFrameQueue.cpp b/drivers/theoraplayer/src/TheoraFrameQueue.cpp
deleted file mode 100644
index f402144795..0000000000
--- a/drivers/theoraplayer/src/TheoraFrameQueue.cpp
+++ /dev/null
@@ -1,174 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#include "TheoraFrameQueue.h"
-#include "TheoraVideoFrame.h"
-#include "TheoraVideoManager.h"
-#include "TheoraUtil.h"
-
-
-TheoraFrameQueue::TheoraFrameQueue(TheoraVideoClip* parent)
-{
- mParent = parent;
-}
-
-TheoraFrameQueue::~TheoraFrameQueue()
-{
- foreach_l(TheoraVideoFrame*, mQueue)
- {
- delete (*it);
- }
- mQueue.clear();
-}
-
-TheoraVideoFrame* TheoraFrameQueue::createFrameInstance(TheoraVideoClip* clip)
-{
- TheoraVideoFrame* frame = new TheoraVideoFrame(clip);
- if (frame->getBuffer() == NULL) // This can happen if you run out of memory
- {
- delete frame;
- return NULL;
- }
- return frame;
-}
-
-void TheoraFrameQueue::setSize(int n)
-{
- mMutex.lock();
- if (mQueue.size() > 0)
- {
- foreach_l (TheoraVideoFrame*, mQueue)
- {
- delete (*it);
- }
- mQueue.clear();
- }
- TheoraVideoFrame* frame;
- for (int i = 0;i < n; ++i)
- {
- frame = createFrameInstance(mParent);
- if (frame != NULL) mQueue.push_back(frame);
- else
- {
- TheoraVideoManager::getSingleton().logMessage("TheoraFrameQueue: unable to create " + str(n) + " frames, out of memory. Created " + str((int) mQueue.size()) + " frames.");
- break;
- }
- }
- mMutex.unlock();
-}
-
-int TheoraFrameQueue::getSize()
-{
- return (int) mQueue.size();
-}
-
-TheoraVideoFrame* TheoraFrameQueue::_getFirstAvailableFrame()
-{
- TheoraVideoFrame* frame = mQueue.front();
- if (frame->mReady) return frame;
- else return NULL;
-}
-
-TheoraVideoFrame* TheoraFrameQueue::getFirstAvailableFrame()
-{
- mMutex.lock();
- TheoraVideoFrame* frame = _getFirstAvailableFrame();
- mMutex.unlock();
- return frame;
-}
-
-void TheoraFrameQueue::clear()
-{
- mMutex.lock();
- foreach_l (TheoraVideoFrame*, mQueue)
- (*it)->clear();
- mMutex.unlock();
-}
-
-void TheoraFrameQueue::_pop(int n)
-{
- for (int i = 0; i < n; ++i)
- {
- TheoraVideoFrame* first = mQueue.front();
- first->clear();
- mQueue.pop_front();
- mQueue.push_back(first);
- }
-}
-
-void TheoraFrameQueue::pop(int n)
-{
- mMutex.lock();
- _pop(n);
- mMutex.unlock();
-}
-
-TheoraVideoFrame* TheoraFrameQueue::requestEmptyFrame()
-{
- TheoraVideoFrame* frame = NULL;
- mMutex.lock();
- foreach_l (TheoraVideoFrame*, mQueue)
- {
- if (!(*it)->mInUse)
- {
- (*it)->mInUse = 1;
- (*it)->mReady = 0;
- frame = (*it);
- break;
- }
- }
- mMutex.unlock();
- return frame;
-}
-
-int TheoraFrameQueue::getUsedCount()
-{
- mMutex.lock();
- int n=0;
- foreach_l(TheoraVideoFrame*,mQueue)
- if ((*it)->mInUse) ++n;
- mMutex.unlock();
- return n;
-}
-
-int TheoraFrameQueue::_getReadyCount()
-{
- int n = 0;
- foreach_l (TheoraVideoFrame*, mQueue)
- if ((*it)->mReady) ++n;
- return n;
-}
-
-
-int TheoraFrameQueue::getReadyCount()
-{
- mMutex.lock();
- int n = _getReadyCount();
- mMutex.unlock();
- return n;
-}
-
-bool TheoraFrameQueue::isFull()
-{
- return getReadyCount() == mQueue.size();
-}
-
-void TheoraFrameQueue::lock()
-{
- mMutex.lock();
-}
-
-void TheoraFrameQueue::unlock()
-{
- mMutex.unlock();
-}
-
-std::list<TheoraVideoFrame*>& TheoraFrameQueue::_getFrameQueue()
-{
- return mQueue;
-}
diff --git a/drivers/theoraplayer/src/TheoraTimer.cpp b/drivers/theoraplayer/src/TheoraTimer.cpp
deleted file mode 100644
index 644d1c2ab7..0000000000
--- a/drivers/theoraplayer/src/TheoraTimer.cpp
+++ /dev/null
@@ -1,70 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#include "TheoraTimer.h"
-
-TheoraTimer::TheoraTimer()
-{
- mTime = 0;
- mPaused = 0;
- mSpeed = 1.0f;
-}
-
-TheoraTimer::~TheoraTimer()
-{
-
-}
-
-void TheoraTimer::update(float timeDelta)
-{
- if (!isPaused())
- {
- mTime += timeDelta * mSpeed;
- }
-}
-
-float TheoraTimer::getTime()
-{
- return mTime;
-}
-
-void TheoraTimer::pause()
-{
- mPaused = true;
-}
-
-void TheoraTimer::play()
-{
- mPaused = false;
-}
-
-
-bool TheoraTimer::isPaused()
-{
- return mPaused;
-}
-
-void TheoraTimer::stop()
-{
-
-}
-
-void TheoraTimer::seek(float time)
-{
- mTime = time;
-}
-
-void TheoraTimer::setSpeed(float speed)
-{
- mSpeed = speed;
-}
-
-float TheoraTimer::getSpeed()
-{
- return mSpeed;
-}
diff --git a/drivers/theoraplayer/src/TheoraUtil.cpp b/drivers/theoraplayer/src/TheoraUtil.cpp
deleted file mode 100644
index 8f1ad0c9c1..0000000000
--- a/drivers/theoraplayer/src/TheoraUtil.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#include <stdio.h>
-#include <algorithm>
-#include <math.h>
-#include <map>
-#ifndef _WIN32
-#include <unistd.h>
-#include <pthread.h>
-#endif
-
-#include "TheoraUtil.h"
-#include "TheoraException.h"
-
-#ifdef _WIN32
-#include <windows.h>
-#pragma warning( disable: 4996 ) // MSVC++
-#endif
-
-std::string str(int i)
-{
- char s[32];
- sprintf(s, "%d", i);
- return std::string(s);
-}
-
-std::string strf(float i)
-{
- char s[32];
- sprintf(s, "%.3f", i);
- return std::string(s);
-}
-
-void _psleep(int miliseconds)
-{
-#ifdef _WIN32
-#ifndef _WINRT
- Sleep(miliseconds);
-#else
- WaitForSingleObjectEx(GetCurrentThread(), miliseconds, 0);
-#endif
-#else
- usleep(miliseconds * 1000);
-#endif
-}
-
-
-int _nextPow2(int x)
-{
- int y;
- for (y = 1; y < x; y *= 2);
- return y;
-}
diff --git a/drivers/theoraplayer/src/TheoraVideoClip.cpp b/drivers/theoraplayer/src/TheoraVideoClip.cpp
deleted file mode 100644
index 16897ee80e..0000000000
--- a/drivers/theoraplayer/src/TheoraVideoClip.cpp
+++ /dev/null
@@ -1,496 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#include "TheoraVideoClip.h"
-#include "TheoraVideoManager.h"
-#include "TheoraVideoFrame.h"
-#include "TheoraFrameQueue.h"
-#include "TheoraAudioInterface.h"
-#include "TheoraTimer.h"
-#include "TheoraDataSource.h"
-#include "TheoraUtil.h"
-#include "TheoraException.h"
-
-#include "core/os/memory.h"
-
-TheoraVideoClip::TheoraVideoClip(TheoraDataSource* data_source,
- TheoraOutputMode output_mode,
- int nPrecachedFrames,
- bool usePower2Stride):
- mAudioInterface(NULL),
- mNumDroppedFrames(0),
- mNumDisplayedFrames(0),
- mSeekFrame(-1),
- mDuration(-1),
- mNumFrames(-1),
- mFPS(1),
- mUseAlpha(0),
- mFrameDuration(0),
- mName(data_source->repr()),
- mStride(usePower2Stride),
- mSubFrameWidth(0),
- mSubFrameHeight(0),
- mSubFrameOffsetX(0),
- mSubFrameOffsetY(0),
- mAudioGain(1),
- mRequestedOutputMode(output_mode),
- mAutoRestart(0),
- mEndOfFile(0),
- mRestarted(0),
- mIteration(0),
- mPlaybackIteration(0),
- mStream(0),
- mThreadAccessCount(0),
- mPriority(1),
- mFirstFrameDisplayed(0),
- mWaitingForCache(false),
- mOutputMode(TH_UNDEFINED)
-{
-
- audio_track=0;
- mAudioMutex = NULL;
- mThreadAccessMutex = new TheoraMutex();
- mTimer = mDefaultTimer = new TheoraTimer();
-
- mFrameQueue = NULL;
- mAssignedWorkerThread = NULL;
- mNumPrecachedFrames = nPrecachedFrames;
- setOutputMode(output_mode);
-}
-
-TheoraVideoClip::~TheoraVideoClip()
-{
- // wait untill a worker thread is done decoding the frame
- mThreadAccessMutex->lock();
-
- delete mDefaultTimer;
-
- if (mStream) memdelete(mStream);
-
- if (mFrameQueue) delete mFrameQueue;
-
- if (mAudioInterface)
- {
- mAudioMutex->lock(); // ensure a thread isn't using this mutex
- delete mAudioInterface; // notify audio interface it's time to call it a day
- mAudioMutex ->unlock();
- delete mAudioMutex;
- }
-
- mThreadAccessMutex->unlock();
-
- delete mThreadAccessMutex;
-}
-
-TheoraTimer* TheoraVideoClip::getTimer()
-{
- return mTimer;
-}
-
-void TheoraVideoClip::setTimer(TheoraTimer* timer)
-{
- if (!timer) mTimer = mDefaultTimer;
- else mTimer = timer;
-}
-
-void TheoraVideoClip::resetFrameQueue()
-{
- mFrameQueue->clear();
- mPlaybackIteration = mIteration = 0;
-}
-
-void TheoraVideoClip::restart()
-{
- mEndOfFile = true; //temp, to prevent threads to decode while restarting
- mThreadAccessMutex->lock();
- _restart();
- mTimer->seek(0);
- mFirstFrameDisplayed = false;
- resetFrameQueue();
- mEndOfFile = false;
- mRestarted = false;
- mSeekFrame = -1;
- mThreadAccessMutex->unlock();
-}
-
-void TheoraVideoClip::update(float timeDelta)
-{
- if (mTimer->isPaused())
- {
- mTimer->update(0); // update timer in case there is some code that needs to execute each frame
- return;
- }
- float time = mTimer->getTime(), speed = mTimer->getSpeed();
- if (time + timeDelta * speed >= mDuration)
- {
- if (mAutoRestart && mRestarted)
- {
- float seekTime = time + timeDelta * speed;
- for (;seekTime >= mDuration;)
- {
- seekTime -= mDuration;
- ++mPlaybackIteration;
- }
-
- mTimer->seek(seekTime);
- }
- else
- {
- if (time != mDuration)
- {
- mTimer->update((mDuration - time) / speed);
- }
- }
- }
- else
- {
- mTimer->update(timeDelta);
- }
-}
-
-float TheoraVideoClip::updateToNextFrame()
-{
- TheoraVideoFrame* f = mFrameQueue->getFirstAvailableFrame();
- if (!f) return 0;
-
- float time = f->mTimeToDisplay - mTimer->getTime();
- update(time);
- return time;
-}
-
-TheoraFrameQueue* TheoraVideoClip::getFrameQueue()
-{
- return mFrameQueue;
-}
-
-void TheoraVideoClip::popFrame()
-{
- ++mNumDisplayedFrames;
-
- // after transfering frame data to the texture, free the frame
- // so it can be used again
- if (!mFirstFrameDisplayed)
- {
- mFrameQueue->lock();
- mFrameQueue->_pop(1);
- mFirstFrameDisplayed = true;
- mFrameQueue->unlock();
- }
- else
- {
- mFrameQueue->pop();
- }
-}
-
-int TheoraVideoClip::getWidth()
-{
- return mUseAlpha ? mWidth / 2 : mWidth;
-}
-
-int TheoraVideoClip::getHeight()
-{
- return mHeight;
-}
-
-int TheoraVideoClip::getSubFrameWidth()
-{
- return mUseAlpha ? mWidth / 2 : mSubFrameWidth;
-}
-
-int TheoraVideoClip::getSubFrameHeight()
-{
- return mUseAlpha ? mHeight : mSubFrameHeight;
-}
-
-int TheoraVideoClip::getSubFrameOffsetX()
-{
- return mUseAlpha ? 0 : mSubFrameOffsetX;
-}
-
-int TheoraVideoClip::getSubFrameOffsetY()
-{
- return mUseAlpha ? 0 : mSubFrameOffsetY;
-}
-
-float TheoraVideoClip::getAbsPlaybackTime()
-{
- return mTimer->getTime() + mPlaybackIteration * mDuration;
-}
-
-int TheoraVideoClip::discardOutdatedFrames(float absTime)
-{
- int nReady = mFrameQueue->_getReadyCount();
- // only drop frames if you have more frames to show. otherwise even the late frame will do..
- if (nReady == 1) return 0;
- float time = absTime;
-
- int nPop = 0;
- TheoraVideoFrame* frame;
- float timeToDisplay;
-
- std::list<TheoraVideoFrame*>& queue = mFrameQueue->_getFrameQueue();
- foreach_l (TheoraVideoFrame*, queue)
- {
- frame = *it;
- if (!frame->mReady) break;
- timeToDisplay = frame->mTimeToDisplay + frame->mIteration * mDuration;
- if (time > timeToDisplay + mFrameDuration)
- {
- ++nPop;
- if (nReady - nPop == 1) break; // always leave at least one in the queue
- }
- else break;
- }
-
- if (nPop > 0)
- {
-#define _DEBUG
-#ifdef _DEBUG
- std::string log = getName() + ": dropped frame ";
-
- int i = nPop;
- foreach_l (TheoraVideoFrame*, queue)
- {
- log += str((int) (*it)->getFrameNumber());
- if (i-- > 1)
- {
- log += ", ";
- }
- else break;
- }
- th_writelog(log);
-#endif
- mNumDroppedFrames += nPop;
- mFrameQueue->_pop(nPop);
- }
-
- return nPop;
-}
-
-TheoraVideoFrame* TheoraVideoClip::getNextFrame()
-{
- TheoraVideoFrame* frame;
- // if we are about to seek, then the current frame queue is invalidated
- // (will be cleared when a worker thread does the actual seek)
- if (mSeekFrame != -1) return NULL;
-
- mFrameQueue->lock();
- float time = getAbsPlaybackTime();
- discardOutdatedFrames(time);
-
- frame = mFrameQueue->_getFirstAvailableFrame();
- if (frame != NULL)
- {
- if (frame->mTimeToDisplay + frame->mIteration * mDuration > time && mFirstFrameDisplayed)
- {
- frame = NULL; // frame is ready but it's not yet time to display it, except when we haven't displayed any frames yet
- }
- }
-
- mFrameQueue->unlock();
- return frame;
-}
-
-std::string TheoraVideoClip::getName()
-{
- return mName;
-}
-
-bool TheoraVideoClip::isBusy()
-{
- return mAssignedWorkerThread || mOutputMode != mRequestedOutputMode;
-}
-
-TheoraOutputMode TheoraVideoClip::getOutputMode()
-{
- return mOutputMode;
-}
-
-void TheoraVideoClip::setOutputMode(TheoraOutputMode mode)
-{
- if (mode == TH_UNDEFINED) throw TheoraGenericException("Invalid output mode: TH_UNDEFINED for video: " + mName);
- if (mOutputMode == mode) return;
- mRequestedOutputMode = mode;
- mUseAlpha = (mode == TH_RGBA ||
- mode == TH_ARGB ||
- mode == TH_BGRA ||
- mode == TH_ABGR ||
- mode == TH_GREY3A ||
- mode == TH_AGREY3 ||
- mode == TH_YUVA ||
- mode == TH_AYUV);
- if (mAssignedWorkerThread)
- {
- mThreadAccessMutex->lock();
- // discard current frames and recreate them
- mFrameQueue->setSize(mFrameQueue->getSize());
- mThreadAccessMutex->unlock();
-
- }
- mOutputMode = mRequestedOutputMode;
-}
-
-float TheoraVideoClip::getTimePosition()
-{
- return mTimer->getTime();
-}
-
-int TheoraVideoClip::getNumPrecachedFrames()
-{
- return mFrameQueue->getSize();
-}
-
-void TheoraVideoClip::setNumPrecachedFrames(int n)
-{
- if (mFrameQueue->getSize() != n)
- mFrameQueue->setSize(n);
-}
-
-int TheoraVideoClip::_getNumReadyFrames()
-{
- if (mSeekFrame != -1) return 0;
- return mFrameQueue->_getReadyCount();
-}
-
-int TheoraVideoClip::getNumReadyFrames()
-{
- if (mSeekFrame != -1) return 0; // we are about to seek, consider frame queue empty even though it will be emptied upon seek
- return mFrameQueue->getReadyCount();
-}
-
-float TheoraVideoClip::getDuration()
-{
- return mDuration;
-}
-
-float TheoraVideoClip::getFPS()
-{
- return mFPS;
-}
-
-void TheoraVideoClip::play()
-{
- mTimer->play();
-}
-
-void TheoraVideoClip::pause()
-{
- mTimer->pause();
-}
-
-bool TheoraVideoClip::isPaused()
-{
- return mTimer->isPaused();
-}
-
-bool TheoraVideoClip::isDone()
-{
- return mEndOfFile && !mFrameQueue->getFirstAvailableFrame();
-}
-
-void TheoraVideoClip::stop()
-{
- pause();
- resetFrameQueue();
- mFirstFrameDisplayed = false;
- seek(0);
-}
-
-void TheoraVideoClip::setPlaybackSpeed(float speed)
-{
- mTimer->setSpeed(speed);
-}
-
-float TheoraVideoClip::getPlaybackSpeed()
-{
- return mTimer->getSpeed();
-}
-
-void TheoraVideoClip::seek(float time)
-{
- seekToFrame((int) (time * getFPS()));
-}
-
-void TheoraVideoClip::seekToFrame(int frame)
-{
- if (frame < 0) mSeekFrame = 0;
- else if (frame > mNumFrames) mSeekFrame = mNumFrames;
- else mSeekFrame = frame;
-
- mFirstFrameDisplayed = false;
- mEndOfFile = false;
-}
-
-void TheoraVideoClip::waitForCache(float desired_cache_factor, float max_wait_time)
-{
- mWaitingForCache = true;
- bool paused = mTimer->isPaused();
- if (!paused) mTimer->pause();
- int elapsed = 0;
- int desired_num_precached_frames = (int) (desired_cache_factor * getNumPrecachedFrames());
- while (getNumReadyFrames() < desired_num_precached_frames)
- {
- _psleep(10);
- elapsed += 10;
- if (elapsed >= max_wait_time * 1000) break;
- }
- if (!paused) mTimer->play();
- mWaitingForCache = false;
-}
-
-float TheoraVideoClip::getPriority()
-{
- return mPriority;
-}
-
-void TheoraVideoClip::setPriority(float priority)
-{
- mPriority = priority;
-}
-
-float TheoraVideoClip::getPriorityIndex()
-{
- float priority = (float) getNumReadyFrames();
- if (mTimer->isPaused()) priority += getNumPrecachedFrames() / 2;
-
- return priority;
-}
-
-void TheoraVideoClip::setAudioInterface(TheoraAudioInterface* iface)
-{
- mAudioInterface = iface;
- if (iface && !mAudioMutex) mAudioMutex = new TheoraMutex;
- if (!iface && mAudioMutex)
- {
- delete mAudioMutex;
- mAudioMutex = NULL;
- }
-}
-
-TheoraAudioInterface* TheoraVideoClip::getAudioInterface()
-{
- return mAudioInterface;
-}
-
-void TheoraVideoClip::setAudioGain(float gain)
-{
- if (gain > 1) mAudioGain=1;
- if (gain < 0) mAudioGain=0;
- else mAudioGain=gain;
-}
-
-float TheoraVideoClip::getAudioGain()
-{
- return mAudioGain;
-}
-
-void TheoraVideoClip::setAutoRestart(bool value)
-{
- mAutoRestart = value;
- if (value) mEndOfFile = false;
-}
diff --git a/drivers/theoraplayer/src/TheoraVideoFrame.cpp b/drivers/theoraplayer/src/TheoraVideoFrame.cpp
deleted file mode 100644
index b70253dabf..0000000000
--- a/drivers/theoraplayer/src/TheoraVideoFrame.cpp
+++ /dev/null
@@ -1,159 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#include <memory.h>
-#include "TheoraPixelTransform.h"
-#include "TheoraVideoClip.h"
-#include "TheoraVideoFrame.h"
-#include "TheoraVideoManager.h"
-
-//#define YUV_TEST // uncomment this if you want to benchmark YUV decoding functions
-
-extern "C"
-{
-void decodeRGB (struct TheoraPixelTransform* t);
-void decodeRGBA (struct TheoraPixelTransform* t);
-void decodeRGBX (struct TheoraPixelTransform* t);
-void decodeARGB (struct TheoraPixelTransform* t);
-void decodeXRGB (struct TheoraPixelTransform* t);
-void decodeBGR (struct TheoraPixelTransform* t);
-void decodeBGRA (struct TheoraPixelTransform* t);
-void decodeBGRX (struct TheoraPixelTransform* t);
-void decodeABGR (struct TheoraPixelTransform* t);
-void decodeXBGR (struct TheoraPixelTransform* t);
-void decodeGrey (struct TheoraPixelTransform* t);
-void decodeGrey3(struct TheoraPixelTransform* t);
-void decodeGreyA(struct TheoraPixelTransform* t);
-void decodeGreyX(struct TheoraPixelTransform* t);
-void decodeAGrey(struct TheoraPixelTransform* t);
-void decodeXGrey(struct TheoraPixelTransform* t);
-void decodeYUV (struct TheoraPixelTransform* t);
-void decodeYUVA (struct TheoraPixelTransform* t);
-void decodeYUVX (struct TheoraPixelTransform* t);
-void decodeAYUV (struct TheoraPixelTransform* t);
-void decodeXYUV (struct TheoraPixelTransform* t);
-}
-
-static void (*conversion_functions[])(struct TheoraPixelTransform*) = {0,
- decodeRGB,
- decodeRGBA,
- decodeRGBX,
- decodeARGB,
- decodeXRGB,
- decodeBGR,
- decodeBGRA,
- decodeBGRX,
- decodeABGR,
- decodeXBGR,
- decodeGrey,
- decodeGrey3,
- decodeGreyA,
- decodeGreyX,
- decodeAGrey,
- decodeXGrey,
- decodeYUV,
- decodeYUVA,
- decodeYUVX,
- decodeAYUV,
- decodeXYUV
-};
-
-TheoraVideoFrame::TheoraVideoFrame(TheoraVideoClip* parent)
-{
- mReady = mInUse = false;
- mParent = parent;
- mIteration = 0;
- // number of bytes based on output mode
- int bytemap[]={0, 3, 4, 4, 4, 4, 3, 4, 4, 4, 4, 1, 3, 4, 4, 4, 4, 3, 4, 4, 4, 4};
- mBpp = bytemap[mParent->getOutputMode()];
- unsigned int size = mParent->getStride() * mParent->mHeight * mBpp;
- try
- {
- mBuffer = new unsigned char[size];
- }
- catch (std::bad_alloc)
- {
- mBuffer = NULL;
- return;
- }
- memset(mBuffer, 255, size);
-}
-
-TheoraVideoFrame::~TheoraVideoFrame()
-{
- if (mBuffer) delete [] mBuffer;
-}
-
-int TheoraVideoFrame::getWidth()
-{
- return mParent->getWidth();
-}
-
-int TheoraVideoFrame::getStride()
-{
- return mParent->mStride;
-}
-
-int TheoraVideoFrame::getHeight()
-{
- return mParent->getHeight();
-}
-
-unsigned char* TheoraVideoFrame::getBuffer()
-{
- return mBuffer;
-}
-
-void TheoraVideoFrame::decode(struct TheoraPixelTransform* t)
-{
- if (t->raw != NULL)
- {
- int bufferStride = mParent->getWidth() * mBpp;
- if (bufferStride == t->rawStride)
- {
- memcpy(mBuffer, t->raw, t->rawStride * mParent->getHeight());
- }
- else
- {
- unsigned char *buff = mBuffer, *src = t->raw;
- int i, h = mParent->getHeight();
- for (i = 0; i < h; ++i, buff += bufferStride, src += t->rawStride)
- {
- memcpy(buff, src, bufferStride);
- }
- }
- }
- else
- {
- t->out = mBuffer;
- t->w = mParent->getWidth();
- t->h = mParent->getHeight();
-
-#ifdef YUV_TEST // when benchmarking yuv conversion functions during development, do a timed average
- #define N 1000
- clock_t time = clock();
- for (int i = 0; i < N; ++i)
- {
- conversion_functions[mParent->getOutputMode()](t);
- }
- float diff = (clock() - time) * 1000.0f / CLOCKS_PER_SEC;
-
- char s[128];
- sprintf(s, "%.2f", diff / N);
- TheoraVideoManager::getSingleton().logMessage("YUV Decoding time: " + std::string(s) + " ms\n");
-#else
- conversion_functions[mParent->getOutputMode()](t);
-#endif
- }
- mReady = true;
-}
-
-void TheoraVideoFrame::clear()
-{
- mInUse = mReady = false;
-}
diff --git a/drivers/theoraplayer/src/TheoraVideoManager.cpp b/drivers/theoraplayer/src/TheoraVideoManager.cpp
deleted file mode 100644
index 53b211374a..0000000000
--- a/drivers/theoraplayer/src/TheoraVideoManager.cpp
+++ /dev/null
@@ -1,485 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#include "TheoraVideoManager.h"
-#include "TheoraWorkerThread.h"
-#include "TheoraVideoClip.h"
-#include "TheoraFrameQueue.h"
-#include "TheoraAudioInterface.h"
-#include "TheoraUtil.h"
-#include "TheoraDataSource.h"
-#include "TheoraException.h"
-#ifdef __THEORA
- #include <theora/codec.h>
- #include <vorbis/codec.h>
- #include "TheoraVideoClip_Theora.h"
-#endif
-#ifdef __AVFOUNDATION
- #include "TheoraVideoClip_AVFoundation.h"
-#endif
-#ifdef __FFMPEG
- #include "TheoraVideoClip_FFmpeg.h"
-#endif
-#ifdef _ANDROID //libtheoraplayer addition for cpu feature detection
- #include "cpu-features.h"
-#endif
-// declaring function prototype here so I don't have to put it in a header file
-// it only needs to be used by this plugin and called once
-extern "C"
-{
- void initYUVConversionModule();
-}
-
-#include "core/os/memory.h"
-
-//#define _DECODING_BENCHMARK //uncomment to test average decoding time on a given device
-
-
-// --------------------------
-//#define _SCHEDULING_DEBUG
-#ifdef _SCHEDULING_DEBUG
-float gThreadDiagnosticTimer = 0;
-#endif
-// --------------------------
-
-#ifdef _DECODING_BENCHMARK
-void benchmark(TheoraVideoClip* clip)
-{
- int nPrecached = 256;
- int n = nPrecached;
- char msg[1024];
- clock_t t = clock();
- while (n > 0)
- {
- clip->waitForCache(1.0f, 1000000);
- n -= 32;
- clip->getFrameQueue()->clear();
- }
- float diff = ((float) (clock() - t) * 1000.0f) / CLOCKS_PER_SEC;
- sprintf(msg, "BENCHMARK: %s: Decoding %d frames took %.1fms (%.2fms average per frame)\n",clip->getName().c_str(), nPrecached, diff, diff / nPrecached);
- TheoraVideoManager::getSingleton().logMessage(msg);
- clip->seek(0);
-}
-#endif
-
-struct TheoraWorkCandidate
-{
- TheoraVideoClip* clip;
- float priority, queuedTime, workTime, entitledTime;
-};
-
-TheoraVideoManager* g_ManagerSingleton = NULL;
-
-void theora_writelog(std::string output)
-{
- printf("%s\n", output.c_str());
-}
-
-void (*g_LogFuction)(std::string) = theora_writelog;
-
-void TheoraVideoManager::setLogFunction(void (*fn)(std::string))
-{
- g_LogFuction = fn;
-}
-
-TheoraVideoManager* TheoraVideoManager::getSingletonPtr()
-{
- return g_ManagerSingleton;
-}
-
-TheoraVideoManager& TheoraVideoManager::getSingleton()
-{
- return *g_ManagerSingleton;
-}
-
-TheoraVideoManager::TheoraVideoManager(int num_worker_threads) :
- mDefaultNumPrecachedFrames(8)
-{
- if (num_worker_threads < 1) throw TheoraGenericException("Unable to create TheoraVideoManager, at least one worker thread is reqired");
-
- g_ManagerSingleton = this;
-
- std::string msg = "Initializing Theora Playback Library (" + getVersionString() + ")\n";
-#ifdef __THEORA
- msg += " - libtheora version: " + std::string(th_version_string()) + "\n" +
- " - libvorbis version: " + std::string(vorbis_version_string()) + "\n";
-#endif
-#ifdef _ANDROID
- uint64_t features = android_getCpuFeaturesExt();
- char s[128];
- sprintf(s, " - Android: CPU Features: %u\n", (unsigned int) features);
- msg += s;
- if ((features & ANDROID_CPU_ARM_FEATURE_NEON) == 0)
- msg += " - Android: NEON features NOT SUPPORTED by CPU\n";
- else
- msg += " - Android: Detected NEON CPU features\n";
-#endif
-
-#ifdef __AVFOUNDATION
- msg += " - using Apple AVFoundation classes.\n";
-#endif
-#ifdef __FFMPEG
- msg += " - using FFmpeg library.\n";
-#endif
-
- logMessage(msg + "------------------------------------");
- mAudioFactory = NULL;
- mWorkMutex = new TheoraMutex();
-
- // for CPU based yuv2rgb decoding
- initYUVConversionModule();
-
- createWorkerThreads(num_worker_threads);
-}
-
-TheoraVideoManager::~TheoraVideoManager()
-{
- destroyWorkerThreads();
-
- mWorkMutex->lock();
- ClipList::iterator ci;
- for (ci = mClips.begin(); ci != mClips.end(); ++ci)
- delete (*ci);
- mClips.clear();
- mWorkMutex->unlock();
- delete mWorkMutex;
-}
-
-void TheoraVideoManager::logMessage(std::string msg)
-{
- g_LogFuction(msg);
-}
-
-TheoraVideoClip* TheoraVideoManager::getVideoClipByName(std::string name)
-{
- TheoraVideoClip* clip = NULL;
- mWorkMutex->lock();
-
- foreach(TheoraVideoClip*, mClips)
- {
- if ((*it)->getName() == name)
- {
- clip = *it;
- break;
- }
- }
- mWorkMutex->unlock();
-
- return clip;
-}
-
-void TheoraVideoManager::setAudioInterfaceFactory(TheoraAudioInterfaceFactory* factory)
-{
- mAudioFactory = factory;
-}
-
-TheoraAudioInterfaceFactory* TheoraVideoManager::getAudioInterfaceFactory()
-{
- return mAudioFactory;
-}
-
-TheoraVideoClip* TheoraVideoManager::createVideoClip(std::string filename,
- TheoraOutputMode output_mode,
- int numPrecachedOverride,
- bool usePower2Stride,
- int p_track)
-{
- TheoraDataSource* src=memnew(TheoraFileDataSource(filename));
- return createVideoClip(src,output_mode,numPrecachedOverride,usePower2Stride, p_track);
-}
-
-TheoraVideoClip* TheoraVideoManager::createVideoClip(TheoraDataSource* data_source,
- TheoraOutputMode output_mode,
- int numPrecachedOverride,
- bool usePower2Stride,
- int p_audio_track)
-{
- mWorkMutex->lock();
-
- TheoraVideoClip* clip = NULL;
- int nPrecached = numPrecachedOverride ? numPrecachedOverride : mDefaultNumPrecachedFrames;
- logMessage("Creating video from data source: " + data_source->repr() + " [" + str(nPrecached) + " precached frames].");
-
-#ifdef __AVFOUNDATION
- TheoraFileDataSource* fileDataSource = dynamic_cast<TheoraFileDataSource*>(data_source);
- std::string filename;
- if (fileDataSource == NULL)
- {
- TheoraMemoryFileDataSource* memoryDataSource = dynamic_cast<TheoraMemoryFileDataSource*>(data_source);
- if (memoryDataSource != NULL) filename = memoryDataSource->getFilename();
- // if the user has his own data source, it's going to be a problem for AVAssetReader since it only supports reading from files...
- }
- else filename = fileDataSource->getFilename();
-
- if (filename.size() > 4 && filename.substr(filename.size() - 4, filename.size()) == ".mp4")
- {
- clip = new TheoraVideoClip_AVFoundation(data_source, output_mode, nPrecached, usePower2Stride);
- }
-#endif
-#if defined(__AVFOUNDATION) && defined(__THEORA)
- else
-#endif
-#ifdef __THEORA
- clip = new TheoraVideoClip_Theora(data_source, output_mode, nPrecached, usePower2Stride);
-#endif
-#ifdef __FFMPEG
- clip = new TheoraVideoClip_FFmpeg(data_source, output_mode, nPrecached, usePower2Stride);
-#endif
-
- clip->set_audio_track(p_audio_track);
- clip->load(data_source);
- clip->decodeNextFrame(); // ensure the first frame is always preloaded and have the main thread do it to prevent potential thread starvatio
-
- mClips.push_back(clip);
- mWorkMutex->unlock();
-
-#ifdef _DECODING_BENCHMARK
- benchmark(clip);
-#endif
- return clip;
-}
-
-void TheoraVideoManager::destroyVideoClip(TheoraVideoClip* clip)
-{
- if (clip)
- {
- th_writelog("Destroying video clip: " + clip->getName());
- mWorkMutex->lock();
- bool reported = 0;
- while (clip->mAssignedWorkerThread)
- {
- if (!reported)
- {
- th_writelog(" - Waiting for WorkerThread to finish decoding in order to destroy");
- reported = 1;
- }
- _psleep(1);
- }
- if (reported) th_writelog(" - WorkerThread done, destroying...");
-
- // erase the clip from the clip list
- foreach (TheoraVideoClip*, mClips)
- {
- if ((*it) == clip)
- {
- mClips.erase(it);
- break;
- }
- }
- // remove all it's references from the work log
- mWorkLog.remove(clip);
-
- // delete the actual clip
- delete clip;
-#ifdef _DEBUG
- th_writelog("Destroyed video.");
-#endif
- mWorkMutex->unlock();
- }
-}
-
-TheoraVideoClip* TheoraVideoManager::requestWork(TheoraWorkerThread* caller)
-{
- if (!mWorkMutex) return NULL;
- mWorkMutex->lock();
-
- TheoraVideoClip* selectedClip = NULL;
- float maxQueuedTime = 0, totalAccessCount = 0, prioritySum = 0, diff, maxDiff = -1;
- int nReadyFrames;
- std::vector<TheoraWorkCandidate> candidates;
- TheoraVideoClip* clip;
- TheoraWorkCandidate candidate;
-
- // first pass is for playing videos, but if no such videos are available for decoding
- // paused videos are selected in the second pass.
- // Note that paused videos that are waiting for cache are considered equal to playing
- // videos in the scheduling context
-
- for (int i = 0; i < 2 && candidates.size() == 0; ++i)
- {
- foreach (TheoraVideoClip*, mClips)
- {
- clip = *it;
- if (clip->isBusy() || (i == 0 && clip->isPaused() && !clip->mWaitingForCache)) continue;
- nReadyFrames = clip->getNumReadyFrames();
- if (nReadyFrames == clip->getFrameQueue()->getSize()) continue;
-
- candidate.clip = clip;
- candidate.priority = clip->getPriority();
- candidate.queuedTime = (float) nReadyFrames / (clip->getFPS() * clip->getPlaybackSpeed());
- candidate.workTime = (float) clip->mThreadAccessCount;
-
- totalAccessCount += candidate.workTime;
- if (maxQueuedTime < candidate.queuedTime) maxQueuedTime = candidate.queuedTime;
-
- candidates.push_back(candidate);
- }
- }
-
- // prevent division by zero
- if (totalAccessCount == 0) totalAccessCount = 1;
- if (maxQueuedTime == 0) maxQueuedTime = 1;
-
- // normalize candidate values
- foreach (TheoraWorkCandidate, candidates)
- {
- it->workTime /= totalAccessCount;
- // adjust user priorities to favor clips that have fewer frames queued
- it->priority *= 1.0f - (it->queuedTime / maxQueuedTime) * 0.5f;
- prioritySum += it->priority;
- }
- foreach (TheoraWorkCandidate, candidates)
- {
- it->entitledTime = it->priority / prioritySum;
- }
-
- // now, based on how much access time has been given to each clip in the work log
- // and how much time should be given to each clip based on calculated priorities,
- // we choose a best suited clip for this worker thread to decode next
- foreach (TheoraWorkCandidate, candidates)
- {
- diff = it->entitledTime - it->workTime;
-
- if (maxDiff < diff)
- {
- maxDiff = diff;
- selectedClip = it->clip;
- }
- }
-
- if (selectedClip)
- {
- selectedClip->mAssignedWorkerThread = caller;
-
- int nClips = (int) mClips.size();
- unsigned int maxWorkLogSize = (nClips - 1) * 50;
-
- if (nClips > 1)
- {
- mWorkLog.push_front(selectedClip);
- ++selectedClip->mThreadAccessCount;
- }
-
- TheoraVideoClip* c;
- while (mWorkLog.size() > maxWorkLogSize)
- {
- c = mWorkLog.back();
- mWorkLog.pop_back();
- c->mThreadAccessCount--;
- }
-#ifdef _SCHEDULING_DEBUG
- if (mClips.size() > 1)
- {
- int accessCount = mWorkLog.size();
- if (gThreadDiagnosticTimer > 2.0f)
- {
- gThreadDiagnosticTimer = 0;
- std::string logstr = "-----\nTheora Playback Library debug CPU time analysis (" + str(accessCount) + "):\n";
- int percent;
- foreach (TheoraVideoClip*, mClips)
- {
- percent = ((float) (*it)->mThreadAccessCount / mWorkLog.size()) * 100.0f;
- logstr += (*it)->getName() + " (" + str((*it)->getPriority()) + "): " + str((*it)->mThreadAccessCount) + ", " + str(percent) + "%\n";
- }
- logstr += "-----";
- th_writelog(logstr);
- }
- }
-#endif
- }
-
- mWorkMutex->unlock();
- return selectedClip;
-}
-
-void TheoraVideoManager::update(float timeDelta)
-{
- mWorkMutex->lock();
- foreach (TheoraVideoClip*, mClips)
- {
- (*it)->update(timeDelta);
- (*it)->decodedAudioCheck();
- }
- mWorkMutex->unlock();
-#ifdef _SCHEDULING_DEBUG
- gThreadDiagnosticTimer += timeDelta;
-#endif
-}
-
-int TheoraVideoManager::getNumWorkerThreads()
-{
- return (int) mWorkerThreads.size();
-}
-
-void TheoraVideoManager::createWorkerThreads(int n)
-{
- TheoraWorkerThread* t;
- for (int i=0;i<n;++i)
- {
- t=new TheoraWorkerThread();
- t->start();
- mWorkerThreads.push_back(t);
- }
-}
-
-void TheoraVideoManager::destroyWorkerThreads()
-{
- foreach(TheoraWorkerThread*,mWorkerThreads)
- {
- (*it)->join();
- delete (*it);
- }
- mWorkerThreads.clear();
-}
-
-void TheoraVideoManager::setNumWorkerThreads(int n)
-{
- if (n == getNumWorkerThreads()) return;
- if (n < 1) throw TheoraGenericException("Unable to change the number of worker threads in TheoraVideoManager, at least one worker thread is reqired");
-
- th_writelog("changing number of worker threats to: "+str(n));
-
- destroyWorkerThreads();
- createWorkerThreads(n);
-}
-
-std::string TheoraVideoManager::getVersionString()
-{
- int a, b, c;
- getVersion(&a, &b, &c);
- std::string out = str(a) + "." + str(b);
- if (c != 0)
- {
- if (c < 0) out += " RC" + str(-c);
- else out += "." + str(c);
- }
- return out;
-}
-
-void TheoraVideoManager::getVersion(int* a, int* b, int* c) // TODO, return a struct instead of the current solution.
-{
- *a = 1;
- *b = 1;
- *c = 0;
-}
-
-std::vector<std::string> TheoraVideoManager::getSupportedDecoders()
-{
- std::vector<std::string> lst;
-#ifdef __THEORA
- lst.push_back("Theora");
-#endif
-#ifdef __AVFOUNDATION
- lst.push_back("AVFoundation");
-#endif
-#ifdef __FFMPEG
- lst.push_back("FFmpeg");
-#endif
-
- return lst;
-}
diff --git a/drivers/theoraplayer/src/TheoraWorkerThread.cpp b/drivers/theoraplayer/src/TheoraWorkerThread.cpp
deleted file mode 100644
index cef8545b8d..0000000000
--- a/drivers/theoraplayer/src/TheoraWorkerThread.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#ifdef _WIN32
-#pragma warning( disable: 4251 ) // MSVC++
-#endif
-#include "TheoraWorkerThread.h"
-#include "TheoraVideoManager.h"
-#include "TheoraVideoClip.h"
-#include "TheoraUtil.h"
-
-TheoraWorkerThread::TheoraWorkerThread() : TheoraThread()
-{
- mClip = NULL;
-}
-
-TheoraWorkerThread::~TheoraWorkerThread()
-{
-
-}
-
-void TheoraWorkerThread::execute()
-{
- while (isRunning())
- {
- mClip = TheoraVideoManager::getSingleton().requestWork(this);
- if (!mClip)
- {
- _psleep(100);
- continue;
- }
-
- mClip->mThreadAccessMutex->lock();
- // if user requested seeking, do that then.
- if (mClip->mSeekFrame >= 0) mClip->doSeek();
-
- if (!mClip->decodeNextFrame())
- _psleep(1); // this happens when the video frame queue is full.
-
- mClip->mAssignedWorkerThread = NULL;
- mClip->mThreadAccessMutex->unlock();
- mClip = NULL;
- }
-}
diff --git a/drivers/theoraplayer/src/YUV/C/yuv420_grey_c.c b/drivers/theoraplayer/src/YUV/C/yuv420_grey_c.c
deleted file mode 100644
index 8af5dd1f58..0000000000
--- a/drivers/theoraplayer/src/YUV/C/yuv420_grey_c.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#include "yuv_util.h"
-
-static void _decodeGrey3(struct TheoraPixelTransform* t, int stride, int nBytes)
-{
- unsigned char *ySrc = t->y, *yLineEnd, *out = t->out;
- unsigned int y;
- for (y = 0; y < t->h; ++y, ySrc += t->yStride - t->w, out += stride-t->w * nBytes)
- for (yLineEnd = ySrc + t->w; ySrc != yLineEnd; ++ySrc, out += nBytes)
- out[0] = out[1] = out[2] = *ySrc;
-}
-
-void decodeGrey(struct TheoraPixelTransform* t)
-{
- unsigned char *ySrc = t->y, *yLineEnd, *out = t->out;
- unsigned int y;
- for (y = 0; y < t->h; ++y, ySrc += t->yStride - t->w)
- for (yLineEnd = ySrc + t->w; ySrc != yLineEnd; ++ySrc, ++out)
- *out = *ySrc;
-
-}
-
-void decodeGrey3(struct TheoraPixelTransform* t)
-{
- _decodeGrey3(t, t->w * 3, 3);
-}
-
-void decodeGreyA(struct TheoraPixelTransform* t)
-{
- _decodeGrey3(t, t->w * 4, 4);
- _decodeAlpha(incOut(t, 3), t->w * 4);
-}
-
-void decodeGreyX(struct TheoraPixelTransform* t)
-{
- _decodeGrey3(t, t->w * 4, 4);
-}
-
-void decodeAGrey(struct TheoraPixelTransform* t)
-{
- _decodeGrey3(incOut(t, 1), t->w * 4, 4);
- _decodeAlpha(t, t->w * 4);
-}
-
-void decodeXGrey(struct TheoraPixelTransform* t)
-{
- _decodeGrey3(incOut(t, 1), t->w * 4, 4);
-}
-
diff --git a/drivers/theoraplayer/src/YUV/C/yuv420_rgb_c.c b/drivers/theoraplayer/src/YUV/C/yuv420_rgb_c.c
deleted file mode 100644
index e981e75ead..0000000000
--- a/drivers/theoraplayer/src/YUV/C/yuv420_rgb_c.c
+++ /dev/null
@@ -1,358 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#ifdef _YUV_C
-#include "yuv_util.h"
-
-int YTable [256];
-int BUTable[256];
-int GUTable[256];
-int GVTable[256];
-int RVTable[256];
-
-#define CLIP_RGB_COLOR(dst, x) \
- tmp = (x) >> 13;\
- if ((tmp & ~0xFF) == 0) dst = tmp;\
- else dst = (-tmp) >> 31;
-
-#define _decodeRGB(t, stride, nBytes, maxWidth, i1, i2, i3, j1, j2, j3)\
- register int tmp;\
- int nBytes2 = nBytes * 2, cv, cu, rgbY1, rgbY2, rgbY3, rgbY4, rV, gUV, bU, width = maxWidth == 0 ? t->w : maxWidth;\
- unsigned int y;\
- unsigned char *ySrcEven, *ySrcOdd, *yLineEnd, *uSrc, *vSrc, *out1, *out2;\
- \
- for (y = 0; y < t->h; y += 2)\
- {\
- ySrcEven = t->y + y * t->yStride;\
- ySrcOdd = t->y + (y + 1) * t->yStride;\
- uSrc = t->u + y * t->uStride / 2;\
- vSrc = t->v + y * t->vStride / 2;\
- out1 = t->out + y * stride;\
- out2 = t->out + (y + 1) * stride;\
- \
- for (yLineEnd = ySrcEven + width; ySrcEven != yLineEnd;)\
- {\
- cu = *uSrc; ++uSrc;\
- cv = *vSrc; ++vSrc;\
- rV = RVTable[cv];\
- gUV = GUTable[cu] + GVTable[cv];\
- bU = BUTable[cu];\
- \
- rgbY1 = YTable[*ySrcEven]; ++ySrcEven;\
- rgbY2 = YTable[*ySrcOdd]; ++ySrcOdd;\
- rgbY3 = YTable[*ySrcEven]; ++ySrcEven;\
- rgbY4 = YTable[*ySrcOdd]; ++ySrcOdd;\
- \
- CLIP_RGB_COLOR(out1[i1], rgbY1 + rV );\
- CLIP_RGB_COLOR(out1[i2], rgbY1 - gUV);\
- CLIP_RGB_COLOR(out1[i3], rgbY1 + bU );\
- \
- CLIP_RGB_COLOR(out2[i1], rgbY2 + rV );\
- CLIP_RGB_COLOR(out2[i2], rgbY2 - gUV);\
- CLIP_RGB_COLOR(out2[i3], rgbY2 + bU );\
- \
- CLIP_RGB_COLOR(out1[j1], rgbY3 + rV );\
- CLIP_RGB_COLOR(out1[j2], rgbY3 - gUV);\
- CLIP_RGB_COLOR(out1[j3], rgbY3 + bU );\
- \
- CLIP_RGB_COLOR(out2[j1], rgbY4 + rV );\
- CLIP_RGB_COLOR(out2[j2], rgbY4 - gUV);\
- CLIP_RGB_COLOR(out2[j3], rgbY4 + bU );\
- \
- out1 += nBytes2; out2 += nBytes2;\
- }\
- }
-
-// The 'trick' with this function is that it skips decoding YUV pixels if the alpha value is 0, thus improving the decoding speed of a frame
-#define _decodeRGBA(t, stride, nBytes, maxWidth, i1, i2, i3, j1, j2, j3, aindex1, aindex2)\
-\
- register int tmp;\
- int nBytes2 = nBytes * 2, cv, cu, rgbY1, rgbY2, rgbY3, rgbY4, a1, a2, a3, a4, rV, gUV, bU, width = maxWidth == 0 ? t->w : maxWidth;\
- int alphaStride = t->w;\
- unsigned int y;\
- unsigned char *ySrcEven, *ySrcOdd, *yLineEnd, *uSrc, *vSrc, *out1, *out2;\
- \
- for (y = 0; y < t->h; y += 2)\
- {\
- ySrcEven = t->y + y * t->yStride;\
- ySrcOdd = t->y + (y + 1) * t->yStride;\
- uSrc = t->u + y * t->uStride / 2;\
- vSrc = t->v + y * t->vStride / 2;\
- out1 = t->out + y * stride;\
- out2 = t->out + (y + 1) * stride;\
- \
- for (yLineEnd = ySrcEven + width; ySrcEven != yLineEnd;)\
- {\
- cu = *uSrc; ++uSrc;\
- cv = *vSrc; ++vSrc;\
- rV = RVTable[cv];\
- gUV = GUTable[cu] + GVTable[cv];\
- bU = BUTable[cu];\
- \
- rgbY1 = YTable[*ySrcEven]; a1 = ySrcEven[alphaStride]; ++ySrcEven;\
- rgbY2 = YTable[*ySrcOdd]; a2 = ySrcOdd [alphaStride]; ++ySrcOdd;\
- rgbY3 = YTable[*ySrcEven]; a3 = ySrcEven[alphaStride]; ++ySrcEven;\
- rgbY4 = YTable[*ySrcOdd]; a4 = ySrcOdd [alphaStride]; ++ySrcOdd;\
- \
- if (a1 > 16)\
- {\
- CLIP_RGB_COLOR(out1[i1], rgbY1 + rV );\
- CLIP_RGB_COLOR(out1[i2], rgbY1 - gUV);\
- CLIP_RGB_COLOR(out1[i3], rgbY1 + bU );\
- out1[aindex1] = a1 >= 235 ? 255 : (unsigned char) (((a1 - 16) * 255) / 219);\
- }\
- else *((unsigned int*) out1) = 0;\
- \
- if (a2 > 16)\
- {\
- CLIP_RGB_COLOR(out2[i1], rgbY2 + rV );\
- CLIP_RGB_COLOR(out2[i2], rgbY2 - gUV);\
- CLIP_RGB_COLOR(out2[i3], rgbY2 + bU );\
- out2[aindex1] = a2 >= 235 ? 255 : (unsigned char) (((a2 - 16) * 255) / 219);\
- }\
- else *((unsigned int*) out2) = 0;\
- \
- if (a3 > 16)\
- {\
- CLIP_RGB_COLOR(out1[j1], rgbY3 + rV );\
- CLIP_RGB_COLOR(out1[j2], rgbY3 - gUV);\
- CLIP_RGB_COLOR(out1[j3], rgbY3 + bU );\
- out1[aindex2] = a3 >= 235 ? 255 : (unsigned char) (((a3 - 16) * 255) / 219);\
- }\
- else *((unsigned int*) &out1[4]) = 0;\
- \
- if (a4 > 16)\
- {\
- CLIP_RGB_COLOR(out2[j1], rgbY4 + rV );\
- CLIP_RGB_COLOR(out2[j2], rgbY4 - gUV);\
- CLIP_RGB_COLOR(out2[j3], rgbY4 + bU );\
- out2[aindex2] = a4 >= 235 ? 255 : (unsigned char) (((a4 - 16) * 255) / 219);\
- }\
- else *((unsigned int*) &out2[4]) = 0;\
- \
- out1 += nBytes2; out2 += nBytes2;\
- }\
- }\
-
-void decodeRGB(struct TheoraPixelTransform* t)
-{
- _decodeRGB(t, t->w * 3, 3, 0, 0, 1, 2, 3, 4, 5);
-}
-
-void decodeRGBA(struct TheoraPixelTransform* t)
-{
- _decodeRGBA(t, t->w * 4, 4, 0, 0, 1, 2, 4, 5, 6, 3, 7);
-// This is the old 2-phase version, leaving it here in case more debugging is needed
-// _decodeRGB(t, t->w * 4, 4, 0, 0, 1, 2, 4, 5, 6);
-// _decodeAlpha(incOut(t, 3), t->w * 4);
-}
-
-void decodeRGBX(struct TheoraPixelTransform* t)
-{
- _decodeRGB(t, t->w * 4, 4, 0, 0, 1, 2, 4, 5, 6);
-}
-
-void decodeARGB(struct TheoraPixelTransform* t)
-{
- _decodeRGBA(t, t->w * 4, 4, 0, 1, 2, 3, 5, 6, 7, 0, 4);
-// This is the old 2-phase version, leaving it here in case more debugging is needed
-// _decodeRGB(t, t->w * 4, 4, 0, 1, 2, 3, 5, 6, 7);
-// _decodeAlpha(t, t->w * 4);
-}
-
-void decodeXRGB(struct TheoraPixelTransform* t)
-{
- _decodeRGB(t, t->w * 4, 4, 0, 1, 2, 3, 5, 6, 7);
-}
-
-void decodeBGR(struct TheoraPixelTransform* t)
-{
- _decodeRGB(t, t->w * 3, 3, 0, 2, 1, 0, 5, 4, 3);
-}
-
-void decodeBGRA(struct TheoraPixelTransform* t)
-{
- _decodeRGBA(t, t->w * 4, 4, 0, 2, 1, 0, 6, 5, 4, 3, 7);
-// This is the old 2-phase version, leaving it here in case more debugging is needed
-// _decodeRGB(t, t->w * 4, 4, 0, 2, 1, 0, 6, 5, 4);
-// _decodeAlpha(incOut(t, 3), t->w * 4);
-}
-
-void decodeBGRX(struct TheoraPixelTransform* t)
-{
- _decodeRGB(t, t->w * 4, 4, 0, 2, 1, 0, 6, 5, 4);
-}
-
-void decodeABGR(struct TheoraPixelTransform* t)
-{
- _decodeRGBA(t, t->w * 4, 4, 0, 3, 2, 1, 7, 6, 5, 0, 4);
-// This is the old 2-phase version, leaving it here in case more debugging is needed
-// _decodeRGB(t, t->w * 4, 4, 0, 3, 2, 1, 7, 6, 5);
-// _decodeAlpha(t, t->w * 4);
-}
-
-void decodeXBGR(struct TheoraPixelTransform* t)
-{
- _decodeRGB(t, t->w * 4, 4, 0, 3, 2, 1, 7, 6, 5);
-}
-
-void initYUVConversionModule()
-{
- //used to bring the table into the high side (scale up) so we
- //can maintain high precision and not use floats (FIXED POINT)
-
- // this is the pseudocode for yuv->rgb conversion
- // r = 1.164*(*ySrc - 16) + 1.596*(cv - 128);
- // b = 1.164*(*ySrc - 16) + 2.018*(cu - 128);
- // g = 1.164*(*ySrc - 16) - 0.813*(cv - 128) - 0.391*(cu - 128);
-
- double scale = 1L << 13, temp;
-
- int i;
- for (i = 0; i < 256; ++i)
- {
- temp = i - 128;
-
- YTable[i] = (int)((1.164 * scale + 0.5) * (i - 16)); //Calc Y component
- RVTable[i] = (int)((1.596 * scale + 0.5) * temp); //Calc R component
- GUTable[i] = (int)((0.391 * scale + 0.5) * temp); //Calc G u & v components
- GVTable[i] = (int)((0.813 * scale + 0.5) * temp);
- BUTable[i] = (int)((2.018 * scale + 0.5) * temp); //Calc B component
- }
-}
-
-/*
- * Below are the function versions of the above macros, use those for debugging, but leave the macros for maximum CPU execution speed
- *
- *
- *
- *
-
-void _decodeRGB(struct TheoraPixelTransform* t, int stride, int nBytes, int maxWidth, int i1, int i2, int i3, int j1, int j2, int j3)
-{
- register int tmp;
- int nBytes2 = nBytes * 2, cv, cu, rgbY1, rgbY2, rgbY3, rgbY4, rV, gUV, bU, width = maxWidth == 0 ? t->w : maxWidth;
- unsigned int y;
- unsigned char *ySrcEven, *ySrcOdd, *yLineEnd, *uSrc, *vSrc, *out1, *out2;
-
- for (y = 0; y < t->h; y += 2)
- {
- ySrcEven = t->y + y * t->yStride;
- ySrcOdd = t->y + (y + 1) * t->yStride;
- uSrc = t->u + y * t->uStride / 2;
- vSrc = t->v + y * t->vStride / 2;
- out1 = t->out + y * stride;
- out2 = t->out + (y + 1) * stride;
-
- for (yLineEnd = ySrcEven + width; ySrcEven != yLineEnd;)
- {
- cu = *uSrc; ++uSrc;
- cv = *vSrc; ++vSrc;
- rV = RVTable[cv];
- gUV = GUTable[cu] + GVTable[cv];
- bU = BUTable[cu];
-
- rgbY1 = YTable[*ySrcEven]; ++ySrcEven;
- rgbY2 = YTable[*ySrcOdd]; ++ySrcOdd;
- rgbY3 = YTable[*ySrcEven]; ++ySrcEven;
- rgbY4 = YTable[*ySrcOdd]; ++ySrcOdd;
-
- CLIP_RGB_COLOR(out1[i1], rgbY1 + rV );
- CLIP_RGB_COLOR(out1[i2], rgbY1 - gUV);
- CLIP_RGB_COLOR(out1[i3], rgbY1 + bU );
-
- CLIP_RGB_COLOR(out2[i1], rgbY2 + rV );
- CLIP_RGB_COLOR(out2[i2], rgbY2 - gUV);
- CLIP_RGB_COLOR(out2[i3], rgbY2 + bU );
-
- CLIP_RGB_COLOR(out1[j1], rgbY3 + rV );
- CLIP_RGB_COLOR(out1[j2], rgbY3 - gUV);
- CLIP_RGB_COLOR(out1[j3], rgbY3 + bU );
-
- CLIP_RGB_COLOR(out2[j1], rgbY4 + rV );
- CLIP_RGB_COLOR(out2[j2], rgbY4 - gUV);
- CLIP_RGB_COLOR(out2[j3], rgbY4 + bU );
-
- out1 += nBytes2; out2 += nBytes2;
- }
- }
-}
-
-void _decodeRGBA(struct TheoraPixelTransform* t, int stride, int nBytes, int maxWidth, int i1, int i2, int i3, int j1, int j2, int j3, int aindex1, int aindex2)
-{
- register int tmp;
- int nBytes2 = nBytes * 2, cv, cu, rgbY1, rgbY2, rgbY3, rgbY4, a1, a2, a3, a4, rV, gUV, bU, width = maxWidth == 0 ? t->w : maxWidth;
- int alphaStride = t->w;
- unsigned int y;
- unsigned char *ySrcEven, *ySrcOdd, *yLineEnd, *uSrc, *vSrc, *out1, *out2;
-
- for (y = 0; y < t->h; y += 2)
- {
- ySrcEven = t->y + y * t->yStride;
- ySrcOdd = t->y + (y + 1) * t->yStride;
- uSrc = t->u + y * t->uStride / 2;
- vSrc = t->v + y * t->vStride / 2;
- out1 = t->out + y * stride;
- out2 = t->out + (y + 1) * stride;
-
- for (yLineEnd = ySrcEven + width; ySrcEven != yLineEnd;)
- {
- cu = *uSrc; ++uSrc;
- cv = *vSrc; ++vSrc;
- rV = RVTable[cv];
- gUV = GUTable[cu] + GVTable[cv];
- bU = BUTable[cu];
-
- rgbY1 = YTable[*ySrcEven]; a1 = ySrcEven[alphaStride]; ++ySrcEven;
- rgbY2 = YTable[*ySrcOdd]; a2 = ySrcOdd [alphaStride]; ++ySrcOdd;
- rgbY3 = YTable[*ySrcEven]; a3 = ySrcEven[alphaStride]; ++ySrcEven;
- rgbY4 = YTable[*ySrcOdd]; a4 = ySrcOdd [alphaStride]; ++ySrcOdd;
-
- if (a1 >= 32)
- {
- CLIP_RGB_COLOR(out1[i1], rgbY1 + rV );
- CLIP_RGB_COLOR(out1[i2], rgbY1 - gUV);
- CLIP_RGB_COLOR(out1[i3], rgbY1 + bU );
- out1[aindex1] = a1 > 224 ? 255 : a1;
- }
- else *((unsigned int*) out1) = 0;
-
- if (a2 >= 32)
- {
- CLIP_RGB_COLOR(out2[i1], rgbY2 + rV );
- CLIP_RGB_COLOR(out2[i2], rgbY2 - gUV);
- CLIP_RGB_COLOR(out2[i3], rgbY2 + bU );
- out2[aindex1] = a2 > 224 ? 255 : a2;
- }
- else *((unsigned int*) out2) = 0;
-
-
- if (a3 >= 32)
- {
- CLIP_RGB_COLOR(out1[j1], rgbY3 + rV );
- CLIP_RGB_COLOR(out1[j2], rgbY3 - gUV);
- CLIP_RGB_COLOR(out1[j3], rgbY3 + bU );
- out1[aindex2] = a3 > 224 ? 255 : a3;
- }
- else *((unsigned int*) &out1[4]) = 0;
-
- if (a4 >= 32)
- {
- CLIP_RGB_COLOR(out2[j1], rgbY4 + rV );
- CLIP_RGB_COLOR(out2[j2], rgbY4 - gUV);
- CLIP_RGB_COLOR(out2[j3], rgbY4 + bU );
- out2[aindex2] = a4 > 224 ? 255 : a4;
- }
- else *((unsigned int*) &out2[4]) = 0;
-
- out1 += nBytes2; out2 += nBytes2;
- }
- }
-}
-*/
-#endif
diff --git a/drivers/theoraplayer/src/YUV/C/yuv420_yuv_c.c b/drivers/theoraplayer/src/YUV/C/yuv420_yuv_c.c
deleted file mode 100644
index fea74eca71..0000000000
--- a/drivers/theoraplayer/src/YUV/C/yuv420_yuv_c.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#include "yuv_util.h"
-
-static void _decodeYUV(struct TheoraPixelTransform* t, int stride, int nBytes, int maxWidth)
-{
- int cv, cu, y1, y2, y3, y4, width = maxWidth == 0 ? t->w : maxWidth;
- unsigned char *ySrcEven, *ySrcOdd, *yLineEnd, *uSrc, *vSrc, *out1, *out2;
- unsigned int y;
-
- for (y=0; y < t->h; y += 2)
- {
- ySrcEven = t->y + y * t->yStride;
- ySrcOdd = t->y + (y + 1) * t->yStride;
- uSrc = t->u + y * t->uStride / 2;
- vSrc = t->v + y * t->vStride / 2;
- out1 = t->out + y * stride;
- out2 = t->out + (y + 1) * stride;
-
- for (yLineEnd = ySrcEven + width; ySrcEven != yLineEnd;)
- {
- // EVEN columns
- cu = *uSrc; ++uSrc;
- cv = *vSrc; ++vSrc;
-
- y1 = *ySrcEven; ++ySrcEven;
- y2 = *ySrcOdd; ++ySrcOdd;
- y3 = *ySrcEven; ++ySrcEven;
- y4 = *ySrcOdd; ++ySrcOdd;
-
- // EVEN columns
- out1[0] = y1;
- out1[1] = cu;
- out1[2] = cv;
-
- out2[0] = y2;
- out2[1] = cu;
- out2[2] = cv;
-
- out1 += nBytes; out2 += nBytes;
- // ODD columns
- out1[0] = y3;
- out1[1] = cu;
- out1[2] = cv;
-
- out2[0] = y4;
- out2[1] = cu;
- out2[2] = cv;
- out1 += nBytes; out2 += nBytes;
- }
- }
-}
-
-void decodeYUV(struct TheoraPixelTransform* t)
-{
- _decodeYUV(t, t->w * 3, 3, 0);
-}
-
-void decodeYUVA(struct TheoraPixelTransform* t)
-{
- _decodeYUV(t, t->w * 4, 4, 0);
- _decodeAlpha(incOut(t, 3), t->w * 4);
-}
-
-void decodeYUVX(struct TheoraPixelTransform* t)
-{
- _decodeYUV(t, t->w * 4, 4, 0);
-}
-
-void decodeAYUV(struct TheoraPixelTransform* t)
-{
- _decodeYUV(incOut(t, 1), t->w * 4, 4, 0);
- _decodeAlpha(t, t->w * 4);
-}
-
-void decodeXYUV(struct TheoraPixelTransform* t)
-{
- _decodeYUV(incOut(t, 1), t->w * 4, 4, 0);
-}
-
diff --git a/drivers/theoraplayer/src/YUV/android/cpu-features.c b/drivers/theoraplayer/src/YUV/android/cpu-features.c
deleted file mode 100644
index 623dc94e0e..0000000000
--- a/drivers/theoraplayer/src/YUV/android/cpu-features.c
+++ /dev/null
@@ -1,1095 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/* ChangeLog for this library:
- *
- * NDK r8d: Add android_setCpu().
- *
- * NDK r8c: Add new ARM CPU features: VFPv2, VFP_D32, VFP_FP16,
- * VFP_FMA, NEON_FMA, IDIV_ARM, IDIV_THUMB2 and iWMMXt.
- *
- * Rewrite the code to parse /proc/self/auxv instead of
- * the "Features" field in /proc/cpuinfo.
- *
- * Dynamically allocate the buffer that hold the content
- * of /proc/cpuinfo to deal with newer hardware.
- *
- * NDK r7c: Fix CPU count computation. The old method only reported the
- * number of _active_ CPUs when the library was initialized,
- * which could be less than the real total.
- *
- * NDK r5: Handle buggy kernels which report a CPU Architecture number of 7
- * for an ARMv6 CPU (see below).
- *
- * Handle kernels that only report 'neon', and not 'vfpv3'
- * (VFPv3 is mandated by the ARM architecture is Neon is implemented)
- *
- * Handle kernels that only report 'vfpv3d16', and not 'vfpv3'
- *
- * Fix x86 compilation. Report ANDROID_CPU_FAMILY_X86 in
- * android_getCpuFamily().
- *
- * NDK r4: Initial release
- */
-
-#if 0
-
-#ifdef _ANDROID
-#if defined(__le32__)
-
-// When users enter this, we should only provide interface and
-// libportable will give the implementations.
-
-#else // !__le32__
-
-#include <sys/system_properties.h>
-#include <pthread.h>
-#include "cpu-features.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <errno.h>
-
-static pthread_once_t g_once;
-static int g_inited;
-static AndroidCpuFamily g_cpuFamily;
-static uint64_t g_cpuFeatures;
-static int g_cpuCount;
-
-#ifdef __arm__
-static uint32_t g_cpuIdArm;
-#endif
-
-static const int android_cpufeatures_debug = 0;
-
-#ifdef __arm__
-# define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_ARM
-#elif defined __i386__
-# define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_X86
-#else
-# define DEFAULT_CPU_FAMILY ANDROID_CPU_FAMILY_UNKNOWN
-#endif
-
-#define D(...) \
- do { \
- if (android_cpufeatures_debug) { \
- printf(__VA_ARGS__); fflush(stdout); \
- } \
- } while (0)
-
-#ifdef __i386__
-static __inline__ void x86_cpuid(int func, int values[4])
-{
- int a, b, c, d;
- /* We need to preserve ebx since we're compiling PIC code */
- /* this means we can't use "=b" for the second output register */
- __asm__ __volatile__ ( \
- "push %%ebx\n"
- "cpuid\n" \
- "mov %%ebx, %1\n"
- "pop %%ebx\n"
- : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \
- : "a" (func) \
- );
- values[0] = a;
- values[1] = b;
- values[2] = c;
- values[3] = d;
-}
-#endif
-
-/* Get the size of a file by reading it until the end. This is needed
- * because files under /proc do not always return a valid size when
- * using fseek(0, SEEK_END) + ftell(). Nor can they be mmap()-ed.
- */
-static int
-get_file_size(const char* pathname)
-{
- int fd, ret, result = 0;
- char buffer[256];
-
- fd = open(pathname, O_RDONLY);
- if (fd < 0) {
- D("Can't open %s: %s\n", pathname, strerror(errno));
- return -1;
- }
-
- for (;;) {
- int ret = read(fd, buffer, sizeof buffer);
- if (ret < 0) {
- if (errno == EINTR)
- continue;
- D("Error while reading %s: %s\n", pathname, strerror(errno));
- break;
- }
- if (ret == 0)
- break;
-
- result += ret;
- }
- close(fd);
- return result;
-}
-
-/* Read the content of /proc/cpuinfo into a user-provided buffer.
- * Return the length of the data, or -1 on error. Does *not*
- * zero-terminate the content. Will not read more
- * than 'buffsize' bytes.
- */
-static int
-read_file(const char* pathname, char* buffer, size_t buffsize)
-{
- int fd, count;
-
- fd = open(pathname, O_RDONLY);
- if (fd < 0) {
- D("Could not open %s: %s\n", pathname, strerror(errno));
- return -1;
- }
- count = 0;
- while (count < (int)buffsize) {
- int ret = read(fd, buffer + count, buffsize - count);
- if (ret < 0) {
- if (errno == EINTR)
- continue;
- D("Error while reading from %s: %s\n", pathname, strerror(errno));
- if (count == 0)
- count = -1;
- break;
- }
- if (ret == 0)
- break;
- count += ret;
- }
- close(fd);
- return count;
-}
-
-/* Extract the content of a the first occurence of a given field in
- * the content of /proc/cpuinfo and return it as a heap-allocated
- * string that must be freed by the caller.
- *
- * Return NULL if not found
- */
-static char*
-extract_cpuinfo_field(const char* buffer, int buflen, const char* field)
-{
- int fieldlen = strlen(field);
- const char* bufend = buffer + buflen;
- char* result = NULL;
- int len, ignore;
- const char *p, *q;
-
- /* Look for first field occurence, and ensures it starts the line. */
- p = buffer;
- for (;;) {
- p = memmem(p, bufend-p, field, fieldlen);
- if (p == NULL)
- goto EXIT;
-
- if (p == buffer || p[-1] == '\n')
- break;
-
- p += fieldlen;
- }
-
- /* Skip to the first column followed by a space */
- p += fieldlen;
- p = memchr(p, ':', bufend-p);
- if (p == NULL || p[1] != ' ')
- goto EXIT;
-
- /* Find the end of the line */
- p += 2;
- q = memchr(p, '\n', bufend-p);
- if (q == NULL)
- q = bufend;
-
- /* Copy the line into a heap-allocated buffer */
- len = q-p;
- result = malloc(len+1);
- if (result == NULL)
- goto EXIT;
-
- memcpy(result, p, len);
- result[len] = '\0';
-
-EXIT:
- return result;
-}
-
-/* Checks that a space-separated list of items contains one given 'item'.
- * Returns 1 if found, 0 otherwise.
- */
-static int
-has_list_item(const char* list, const char* item)
-{
- const char* p = list;
- int itemlen = strlen(item);
-
- if (list == NULL)
- return 0;
-
- while (*p) {
- const char* q;
-
- /* skip spaces */
- while (*p == ' ' || *p == '\t')
- p++;
-
- /* find end of current list item */
- q = p;
- while (*q && *q != ' ' && *q != '\t')
- q++;
-
- if (itemlen == q-p && !memcmp(p, item, itemlen))
- return 1;
-
- /* skip to next item */
- p = q;
- }
- return 0;
-}
-
-/* Parse a number starting from 'input', but not going further
- * than 'limit'. Return the value into '*result'.
- *
- * NOTE: Does not skip over leading spaces, or deal with sign characters.
- * NOTE: Ignores overflows.
- *
- * The function returns NULL in case of error (bad format), or the new
- * position after the decimal number in case of success (which will always
- * be <= 'limit').
- */
-static const char*
-parse_number(const char* input, const char* limit, int base, int* result)
-{
- const char* p = input;
- int val = 0;
- while (p < limit) {
- int d = (*p - '0');
- if ((unsigned)d >= 10U) {
- d = (*p - 'a');
- if ((unsigned)d >= 6U)
- d = (*p - 'A');
- if ((unsigned)d >= 6U)
- break;
- d += 10;
- }
- if (d >= base)
- break;
- val = val*base + d;
- p++;
- }
- if (p == input)
- return NULL;
-
- *result = val;
- return p;
-}
-
-static const char*
-parse_decimal(const char* input, const char* limit, int* result)
-{
- return parse_number(input, limit, 10, result);
-}
-
-static const char*
-parse_hexadecimal(const char* input, const char* limit, int* result)
-{
- return parse_number(input, limit, 16, result);
-}
-
-/* This small data type is used to represent a CPU list / mask, as read
- * from sysfs on Linux. See http://www.kernel.org/doc/Documentation/cputopology.txt
- *
- * For now, we don't expect more than 32 cores on mobile devices, so keep
- * everything simple.
- */
-typedef struct {
- uint32_t mask;
-} CpuList;
-
-static __inline__ void
-cpulist_init(CpuList* list) {
- list->mask = 0;
-}
-
-static __inline__ void
-cpulist_and(CpuList* list1, CpuList* list2) {
- list1->mask &= list2->mask;
-}
-
-static __inline__ void
-cpulist_set(CpuList* list, int index) {
- if ((unsigned)index < 32) {
- list->mask |= (uint32_t)(1U << index);
- }
-}
-
-static __inline__ int
-cpulist_count(CpuList* list) {
- return __builtin_popcount(list->mask);
-}
-
-/* Parse a textual list of cpus and store the result inside a CpuList object.
- * Input format is the following:
- * - comma-separated list of items (no spaces)
- * - each item is either a single decimal number (cpu index), or a range made
- * of two numbers separated by a single dash (-). Ranges are inclusive.
- *
- * Examples: 0
- * 2,4-127,128-143
- * 0-1
- */
-static void
-cpulist_parse(CpuList* list, const char* line, int line_len)
-{
- const char* p = line;
- const char* end = p + line_len;
- const char* q;
-
- /* NOTE: the input line coming from sysfs typically contains a
- * trailing newline, so take care of it in the code below
- */
- while (p < end && *p != '\n')
- {
- int val, start_value, end_value;
-
- /* Find the end of current item, and put it into 'q' */
- q = memchr(p, ',', end-p);
- if (q == NULL) {
- q = end;
- }
-
- /* Get first value */
- p = parse_decimal(p, q, &start_value);
- if (p == NULL)
- goto BAD_FORMAT;
-
- end_value = start_value;
-
- /* If we're not at the end of the item, expect a dash and
- * and integer; extract end value.
- */
- if (p < q && *p == '-') {
- p = parse_decimal(p+1, q, &end_value);
- if (p == NULL)
- goto BAD_FORMAT;
- }
-
- /* Set bits CPU list bits */
- for (val = start_value; val <= end_value; val++) {
- cpulist_set(list, val);
- }
-
- /* Jump to next item */
- p = q;
- if (p < end)
- p++;
- }
-
-BAD_FORMAT:
- ;
-}
-
-/* Read a CPU list from one sysfs file */
-static void
-cpulist_read_from(CpuList* list, const char* filename)
-{
- char file[64];
- int filelen;
-
- cpulist_init(list);
-
- filelen = read_file(filename, file, sizeof file);
- if (filelen < 0) {
- D("Could not read %s: %s\n", filename, strerror(errno));
- return;
- }
-
- cpulist_parse(list, file, filelen);
-}
-
-// See <asm/hwcap.h> kernel header.
-#define HWCAP_VFP (1 << 6)
-#define HWCAP_IWMMXT (1 << 9)
-#define HWCAP_NEON (1 << 12)
-#define HWCAP_VFPv3 (1 << 13)
-#define HWCAP_VFPv3D16 (1 << 14)
-#define HWCAP_VFPv4 (1 << 16)
-#define HWCAP_IDIVA (1 << 17)
-#define HWCAP_IDIVT (1 << 18)
-
-#define AT_HWCAP 16
-
-#if defined(__arm__)
-/* Compute the ELF HWCAP flags.
- */
-static uint32_t
-get_elf_hwcap(const char* cpuinfo, int cpuinfo_len)
-{
- /* IMPORTANT:
- * Accessing /proc/self/auxv doesn't work anymore on all
- * platform versions. More specifically, when running inside
- * a regular application process, most of /proc/self/ will be
- * non-readable, including /proc/self/auxv. This doesn't
- * happen however if the application is debuggable, or when
- * running under the "shell" UID, which is why this was not
- * detected appropriately.
- */
-#if 0
- uint32_t result = 0;
- const char filepath[] = "/proc/self/auxv";
- int fd = open(filepath, O_RDONLY);
- if (fd < 0) {
- D("Could not open %s: %s\n", filepath, strerror(errno));
- return 0;
- }
-
- struct { uint32_t tag; uint32_t value; } entry;
-
- for (;;) {
- int ret = read(fd, (char*)&entry, sizeof entry);
- if (ret < 0) {
- if (errno == EINTR)
- continue;
- D("Error while reading %s: %s\n", filepath, strerror(errno));
- break;
- }
- // Detect end of list.
- if (ret == 0 || (entry.tag == 0 && entry.value == 0))
- break;
- if (entry.tag == AT_HWCAP) {
- result = entry.value;
- break;
- }
- }
- close(fd);
- return result;
-#else
- // Recreate ELF hwcaps by parsing /proc/cpuinfo Features tag.
- uint32_t hwcaps = 0;
-
- char* cpuFeatures = extract_cpuinfo_field(cpuinfo, cpuinfo_len, "Features");
-
- if (cpuFeatures != NULL) {
- D("Found cpuFeatures = '%s'\n", cpuFeatures);
-
- if (has_list_item(cpuFeatures, "vfp"))
- hwcaps |= HWCAP_VFP;
- if (has_list_item(cpuFeatures, "vfpv3"))
- hwcaps |= HWCAP_VFPv3;
- if (has_list_item(cpuFeatures, "vfpv3d16"))
- hwcaps |= HWCAP_VFPv3D16;
- if (has_list_item(cpuFeatures, "vfpv4"))
- hwcaps |= HWCAP_VFPv4;
- if (has_list_item(cpuFeatures, "neon"))
- hwcaps |= HWCAP_NEON;
- if (has_list_item(cpuFeatures, "idiva"))
- hwcaps |= HWCAP_IDIVA;
- if (has_list_item(cpuFeatures, "idivt"))
- hwcaps |= HWCAP_IDIVT;
- if (has_list_item(cpuFeatures, "idiv"))
- hwcaps |= HWCAP_IDIVA | HWCAP_IDIVT;
- if (has_list_item(cpuFeatures, "iwmmxt"))
- hwcaps |= HWCAP_IWMMXT;
-
- free(cpuFeatures);
- }
- return hwcaps;
-#endif
-}
-#endif /* __arm__ */
-
-/* Return the number of cpus present on a given device.
- *
- * To handle all weird kernel configurations, we need to compute the
- * intersection of the 'present' and 'possible' CPU lists and count
- * the result.
- */
-static int
-get_cpu_count(void)
-{
- CpuList cpus_present[1];
- CpuList cpus_possible[1];
-
- cpulist_read_from(cpus_present, "/sys/devices/system/cpu/present");
- cpulist_read_from(cpus_possible, "/sys/devices/system/cpu/possible");
-
- /* Compute the intersection of both sets to get the actual number of
- * CPU cores that can be used on this device by the kernel.
- */
- cpulist_and(cpus_present, cpus_possible);
-
- return cpulist_count(cpus_present);
-}
-
-static void
-android_cpuInitFamily(void)
-{
-#if defined(__arm__)
- g_cpuFamily = ANDROID_CPU_FAMILY_ARM;
-#elif defined(__i386__)
- g_cpuFamily = ANDROID_CPU_FAMILY_X86;
-#elif defined(__mips64)
-/* Needs to be before __mips__ since the compiler defines both */
- g_cpuFamily = ANDROID_CPU_FAMILY_MIPS64;
-#elif defined(__mips__)
- g_cpuFamily = ANDROID_CPU_FAMILY_MIPS;
-#elif defined(__aarch64__)
- g_cpuFamily = ANDROID_CPU_FAMILY_ARM64;
-#elif defined(__x86_64__)
- g_cpuFamily = ANDROID_CPU_FAMILY_X86_64;
-#else
- g_cpuFamily = ANDROID_CPU_FAMILY_UNKNOWN;
-#endif
-}
-
-static void
-android_cpuInit(void)
-{
- char* cpuinfo = NULL;
- int cpuinfo_len;
-
- android_cpuInitFamily();
-
- g_cpuFeatures = 0;
- g_cpuCount = 1;
- g_inited = 1;
-
- cpuinfo_len = get_file_size("/proc/cpuinfo");
- if (cpuinfo_len < 0) {
- D("cpuinfo_len cannot be computed!");
- return;
- }
- cpuinfo = malloc(cpuinfo_len);
- if (cpuinfo == NULL) {
- D("cpuinfo buffer could not be allocated");
- return;
- }
- cpuinfo_len = read_file("/proc/cpuinfo", cpuinfo, cpuinfo_len);
- D("cpuinfo_len is (%d):\n%.*s\n", cpuinfo_len,
- cpuinfo_len >= 0 ? cpuinfo_len : 0, cpuinfo);
-
- if (cpuinfo_len < 0) /* should not happen */ {
- free(cpuinfo);
- return;
- }
-
- /* Count the CPU cores, the value may be 0 for single-core CPUs */
- g_cpuCount = get_cpu_count();
- if (g_cpuCount == 0) {
- g_cpuCount = 1;
- }
-
- D("found cpuCount = %d\n", g_cpuCount);
-
-#ifdef __arm__
- {
- char* features = NULL;
- char* architecture = NULL;
-
- /* Extract architecture from the "CPU Architecture" field.
- * The list is well-known, unlike the the output of
- * the 'Processor' field which can vary greatly.
- *
- * See the definition of the 'proc_arch' array in
- * $KERNEL/arch/arm/kernel/setup.c and the 'c_show' function in
- * same file.
- */
- char* cpuArch = extract_cpuinfo_field(cpuinfo, cpuinfo_len, "CPU architecture");
-
- if (cpuArch != NULL) {
- char* end;
- long archNumber;
- int hasARMv7 = 0;
-
- D("found cpuArch = '%s'\n", cpuArch);
-
- /* read the initial decimal number, ignore the rest */
- archNumber = strtol(cpuArch, &end, 10);
-
- /* Here we assume that ARMv8 will be upwards compatible with v7
- * in the future. Unfortunately, there is no 'Features' field to
- * indicate that Thumb-2 is supported.
- */
- if (end > cpuArch && archNumber >= 7) {
- hasARMv7 = 1;
- }
-
- /* Unfortunately, it seems that certain ARMv6-based CPUs
- * report an incorrect architecture number of 7!
- *
- * See http://code.google.com/p/android/issues/detail?id=10812
- *
- * We try to correct this by looking at the 'elf_format'
- * field reported by the 'Processor' field, which is of the
- * form of "(v7l)" for an ARMv7-based CPU, and "(v6l)" for
- * an ARMv6-one.
- */
- if (hasARMv7) {
- char* cpuProc = extract_cpuinfo_field(cpuinfo, cpuinfo_len,
- "Processor");
- if (cpuProc != NULL) {
- D("found cpuProc = '%s'\n", cpuProc);
- if (has_list_item(cpuProc, "(v6l)")) {
- D("CPU processor and architecture mismatch!!\n");
- hasARMv7 = 0;
- }
- free(cpuProc);
- }
- }
-
- if (hasARMv7) {
- g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_ARMv7;
- }
-
- /* The LDREX / STREX instructions are available from ARMv6 */
- if (archNumber >= 6) {
- g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_LDREX_STREX;
- }
-
- free(cpuArch);
- }
-
- /* Extract the list of CPU features from ELF hwcaps */
- uint32_t hwcaps = get_elf_hwcap(cpuinfo, cpuinfo_len);
-
- if (hwcaps != 0) {
- int has_vfp = (hwcaps & HWCAP_VFP);
- int has_vfpv3 = (hwcaps & HWCAP_VFPv3);
- int has_vfpv3d16 = (hwcaps & HWCAP_VFPv3D16);
- int has_vfpv4 = (hwcaps & HWCAP_VFPv4);
- int has_neon = (hwcaps & HWCAP_NEON);
- int has_idiva = (hwcaps & HWCAP_IDIVA);
- int has_idivt = (hwcaps & HWCAP_IDIVT);
- int has_iwmmxt = (hwcaps & HWCAP_IWMMXT);
-
- // The kernel does a poor job at ensuring consistency when
- // describing CPU features. So lots of guessing is needed.
-
- // 'vfpv4' implies VFPv3|VFP_FMA|FP16
- if (has_vfpv4)
- g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3 |
- ANDROID_CPU_ARM_FEATURE_VFP_FP16 |
- ANDROID_CPU_ARM_FEATURE_VFP_FMA;
-
- // 'vfpv3' or 'vfpv3d16' imply VFPv3. Note that unlike GCC,
- // a value of 'vfpv3' doesn't necessarily mean that the D32
- // feature is present, so be conservative. All CPUs in the
- // field that support D32 also support NEON, so this should
- // not be a problem in practice.
- if (has_vfpv3 || has_vfpv3d16)
- g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3;
-
- // 'vfp' is super ambiguous. Depending on the kernel, it can
- // either mean VFPv2 or VFPv3. Make it depend on ARMv7.
- if (has_vfp) {
- if (g_cpuFeatures & ANDROID_CPU_ARM_FEATURE_ARMv7)
- g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3;
- else
- g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv2;
- }
-
- // Neon implies VFPv3|D32, and if vfpv4 is detected, NEON_FMA
- if (has_neon) {
- g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3 |
- ANDROID_CPU_ARM_FEATURE_NEON |
- ANDROID_CPU_ARM_FEATURE_VFP_D32;
- if (has_vfpv4)
- g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_NEON_FMA;
- }
-
- // VFPv3 implies VFPv2 and ARMv7
- if (g_cpuFeatures & ANDROID_CPU_ARM_FEATURE_VFPv3)
- g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv2 |
- ANDROID_CPU_ARM_FEATURE_ARMv7;
-
- if (has_idiva)
- g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_IDIV_ARM;
- if (has_idivt)
- g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2;
-
- if (has_iwmmxt)
- g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_iWMMXt;
- }
-
- /* Extract the cpuid value from various fields */
- // The CPUID value is broken up in several entries in /proc/cpuinfo.
- // This table is used to rebuild it from the entries.
- static const struct CpuIdEntry {
- const char* field;
- char format;
- char bit_lshift;
- char bit_length;
- } cpu_id_entries[] = {
- { "CPU implementer", 'x', 24, 8 },
- { "CPU variant", 'x', 20, 4 },
- { "CPU part", 'x', 4, 12 },
- { "CPU revision", 'd', 0, 4 },
- };
- size_t i;
- D("Parsing /proc/cpuinfo to recover CPUID\n");
- for (i = 0;
- i < sizeof(cpu_id_entries)/sizeof(cpu_id_entries[0]);
- ++i) {
- const struct CpuIdEntry* entry = &cpu_id_entries[i];
- char* value = extract_cpuinfo_field(cpuinfo,
- cpuinfo_len,
- entry->field);
- if (value == NULL)
- continue;
-
- D("field=%s value='%s'\n", entry->field, value);
- char* value_end = value + strlen(value);
- int val = 0;
- const char* start = value;
- const char* p;
- if (value[0] == '0' && (value[1] == 'x' || value[1] == 'X')) {
- start += 2;
- p = parse_hexadecimal(start, value_end, &val);
- } else if (entry->format == 'x')
- p = parse_hexadecimal(value, value_end, &val);
- else
- p = parse_decimal(value, value_end, &val);
-
- if (p > (const char*)start) {
- val &= ((1 << entry->bit_length)-1);
- val <<= entry->bit_lshift;
- g_cpuIdArm |= (uint32_t) val;
- }
-
- free(value);
- }
-
- // Handle kernel configuration bugs that prevent the correct
- // reporting of CPU features.
- static const struct CpuFix {
- uint32_t cpuid;
- uint64_t or_flags;
- } cpu_fixes[] = {
- /* The Nexus 4 (Qualcomm Krait) kernel configuration
- * forgets to report IDIV support. */
- { 0x510006f2, ANDROID_CPU_ARM_FEATURE_IDIV_ARM |
- ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2 },
- { 0x510006f3, ANDROID_CPU_ARM_FEATURE_IDIV_ARM |
- ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2 },
- };
- size_t n;
- for (n = 0; n < sizeof(cpu_fixes)/sizeof(cpu_fixes[0]); ++n) {
- const struct CpuFix* entry = &cpu_fixes[n];
-
- if (g_cpuIdArm == entry->cpuid)
- g_cpuFeatures |= entry->or_flags;
- }
-
- }
-#endif /* __arm__ */
-
-#ifdef __i386__
- int regs[4];
-
-/* According to http://en.wikipedia.org/wiki/CPUID */
-#define VENDOR_INTEL_b 0x756e6547
-#define VENDOR_INTEL_c 0x6c65746e
-#define VENDOR_INTEL_d 0x49656e69
-
- x86_cpuid(0, regs);
- int vendorIsIntel = (regs[1] == VENDOR_INTEL_b &&
- regs[2] == VENDOR_INTEL_c &&
- regs[3] == VENDOR_INTEL_d);
-
- x86_cpuid(1, regs);
- if ((regs[2] & (1 << 9)) != 0) {
- g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSSE3;
- }
- if ((regs[2] & (1 << 23)) != 0) {
- g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_POPCNT;
- }
- if (vendorIsIntel && (regs[2] & (1 << 22)) != 0) {
- g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_MOVBE;
- }
-#endif
-
- free(cpuinfo);
-}
-
-
-AndroidCpuFamily
-android_getCpuFamily(void)
-{
- pthread_once(&g_once, android_cpuInit);
- return g_cpuFamily;
-}
-
-
-uint64_t
-android_getCpuFeaturesExt(void)
-{
- pthread_once(&g_once, android_cpuInit);
- return g_cpuFeatures;
-}
-
-
-int
-android_getCpuCount(void)
-{
- pthread_once(&g_once, android_cpuInit);
- return g_cpuCount;
-}
-
-static void
-android_cpuInitDummy(void)
-{
- g_inited = 1;
-}
-
-int
-android_setCpu(int cpu_count, uint64_t cpu_features)
-{
- /* Fail if the library was already initialized. */
- if (g_inited)
- return 0;
-
- android_cpuInitFamily();
- g_cpuCount = (cpu_count <= 0 ? 1 : cpu_count);
- g_cpuFeatures = cpu_features;
- pthread_once(&g_once, android_cpuInitDummy);
-
- return 1;
-}
-
-#ifdef __arm__
-uint32_t
-android_getCpuIdArm(void)
-{
- pthread_once(&g_once, android_cpuInit);
- return g_cpuIdArm;
-}
-
-int
-android_setCpuArm(int cpu_count, uint64_t cpu_features, uint32_t cpu_id)
-{
- if (!android_setCpu(cpu_count, cpu_features))
- return 0;
-
- g_cpuIdArm = cpu_id;
- return 1;
-}
-#endif /* __arm__ */
-
-/*
- * Technical note: Making sense of ARM's FPU architecture versions.
- *
- * FPA was ARM's first attempt at an FPU architecture. There is no Android
- * device that actually uses it since this technology was already obsolete
- * when the project started. If you see references to FPA instructions
- * somewhere, you can be sure that this doesn't apply to Android at all.
- *
- * FPA was followed by "VFP", soon renamed "VFPv1" due to the emergence of
- * new versions / additions to it. ARM considers this obsolete right now,
- * and no known Android device implements it either.
- *
- * VFPv2 added a few instructions to VFPv1, and is an *optional* extension
- * supported by some ARMv5TE, ARMv6 and ARMv6T2 CPUs. Note that a device
- * supporting the 'armeabi' ABI doesn't necessarily support these.
- *
- * VFPv3-D16 adds a few instructions on top of VFPv2 and is typically used
- * on ARMv7-A CPUs which implement a FPU. Note that it is also mandated
- * by the Android 'armeabi-v7a' ABI. The -D16 suffix in its name means
- * that it provides 16 double-precision FPU registers (d0-d15) and 32
- * single-precision ones (s0-s31) which happen to be mapped to the same
- * register banks.
- *
- * VFPv3-D32 is the name of an extension to VFPv3-D16 that provides 16
- * additional double precision registers (d16-d31). Note that there are
- * still only 32 single precision registers.
- *
- * VFPv3xD is a *subset* of VFPv3-D16 that only provides single-precision
- * registers. It is only used on ARMv7-M (i.e. on micro-controllers) which
- * are not supported by Android. Note that it is not compatible with VFPv2.
- *
- * NOTE: The term 'VFPv3' usually designate either VFPv3-D16 or VFPv3-D32
- * depending on context. For example GCC uses it for VFPv3-D32, but
- * the Linux kernel code uses it for VFPv3-D16 (especially in
- * /proc/cpuinfo). Always try to use the full designation when
- * possible.
- *
- * NEON, a.k.a. "ARM Advanced SIMD" is an extension that provides
- * instructions to perform parallel computations on vectors of 8, 16,
- * 32, 64 and 128 bit quantities. NEON requires VFPv32-D32 since all
- * NEON registers are also mapped to the same register banks.
- *
- * VFPv4-D16, adds a few instructions on top of VFPv3-D16 in order to
- * perform fused multiply-accumulate on VFP registers, as well as
- * half-precision (16-bit) conversion operations.
- *
- * VFPv4-D32 is VFPv4-D16 with 32, instead of 16, FPU double precision
- * registers.
- *
- * VPFv4-NEON is VFPv4-D32 with NEON instructions. It also adds fused
- * multiply-accumulate instructions that work on the NEON registers.
- *
- * NOTE: Similarly, "VFPv4" might either reference VFPv4-D16 or VFPv4-D32
- * depending on context.
- *
- * The following information was determined by scanning the binutils-2.22
- * sources:
- *
- * Basic VFP instruction subsets:
- *
- * #define FPU_VFP_EXT_V1xD 0x08000000 // Base VFP instruction set.
- * #define FPU_VFP_EXT_V1 0x04000000 // Double-precision insns.
- * #define FPU_VFP_EXT_V2 0x02000000 // ARM10E VFPr1.
- * #define FPU_VFP_EXT_V3xD 0x01000000 // VFPv3 single-precision.
- * #define FPU_VFP_EXT_V3 0x00800000 // VFPv3 double-precision.
- * #define FPU_NEON_EXT_V1 0x00400000 // Neon (SIMD) insns.
- * #define FPU_VFP_EXT_D32 0x00200000 // Registers D16-D31.
- * #define FPU_VFP_EXT_FP16 0x00100000 // Half-precision extensions.
- * #define FPU_NEON_EXT_FMA 0x00080000 // Neon fused multiply-add
- * #define FPU_VFP_EXT_FMA 0x00040000 // VFP fused multiply-add
- *
- * FPU types (excluding NEON)
- *
- * FPU_VFP_V1xD (EXT_V1xD)
- * |
- * +--------------------------+
- * | |
- * FPU_VFP_V1 (+EXT_V1) FPU_VFP_V3xD (+EXT_V2+EXT_V3xD)
- * | |
- * | |
- * FPU_VFP_V2 (+EXT_V2) FPU_VFP_V4_SP_D16 (+EXT_FP16+EXT_FMA)
- * |
- * FPU_VFP_V3D16 (+EXT_Vx3D+EXT_V3)
- * |
- * +--------------------------+
- * | |
- * FPU_VFP_V3 (+EXT_D32) FPU_VFP_V4D16 (+EXT_FP16+EXT_FMA)
- * | |
- * | FPU_VFP_V4 (+EXT_D32)
- * |
- * FPU_VFP_HARD (+EXT_FMA+NEON_EXT_FMA)
- *
- * VFP architectures:
- *
- * ARCH_VFP_V1xD (EXT_V1xD)
- * |
- * +------------------+
- * | |
- * | ARCH_VFP_V3xD (+EXT_V2+EXT_V3xD)
- * | |
- * | ARCH_VFP_V3xD_FP16 (+EXT_FP16)
- * | |
- * | ARCH_VFP_V4_SP_D16 (+EXT_FMA)
- * |
- * ARCH_VFP_V1 (+EXT_V1)
- * |
- * ARCH_VFP_V2 (+EXT_V2)
- * |
- * ARCH_VFP_V3D16 (+EXT_V3xD+EXT_V3)
- * |
- * +-------------------+
- * | |
- * | ARCH_VFP_V3D16_FP16 (+EXT_FP16)
- * |
- * +-------------------+
- * | |
- * | ARCH_VFP_V4_D16 (+EXT_FP16+EXT_FMA)
- * | |
- * | ARCH_VFP_V4 (+EXT_D32)
- * | |
- * | ARCH_NEON_VFP_V4 (+EXT_NEON+EXT_NEON_FMA)
- * |
- * ARCH_VFP_V3 (+EXT_D32)
- * |
- * +-------------------+
- * | |
- * | ARCH_VFP_V3_FP16 (+EXT_FP16)
- * |
- * ARCH_VFP_V3_PLUS_NEON_V1 (+EXT_NEON)
- * |
- * ARCH_NEON_FP16 (+EXT_FP16)
- *
- * -fpu=<name> values and their correspondance with FPU architectures above:
- *
- * {"vfp", FPU_ARCH_VFP_V2},
- * {"vfp9", FPU_ARCH_VFP_V2},
- * {"vfp3", FPU_ARCH_VFP_V3}, // For backwards compatbility.
- * {"vfp10", FPU_ARCH_VFP_V2},
- * {"vfp10-r0", FPU_ARCH_VFP_V1},
- * {"vfpxd", FPU_ARCH_VFP_V1xD},
- * {"vfpv2", FPU_ARCH_VFP_V2},
- * {"vfpv3", FPU_ARCH_VFP_V3},
- * {"vfpv3-fp16", FPU_ARCH_VFP_V3_FP16},
- * {"vfpv3-d16", FPU_ARCH_VFP_V3D16},
- * {"vfpv3-d16-fp16", FPU_ARCH_VFP_V3D16_FP16},
- * {"vfpv3xd", FPU_ARCH_VFP_V3xD},
- * {"vfpv3xd-fp16", FPU_ARCH_VFP_V3xD_FP16},
- * {"neon", FPU_ARCH_VFP_V3_PLUS_NEON_V1},
- * {"neon-fp16", FPU_ARCH_NEON_FP16},
- * {"vfpv4", FPU_ARCH_VFP_V4},
- * {"vfpv4-d16", FPU_ARCH_VFP_V4D16},
- * {"fpv4-sp-d16", FPU_ARCH_VFP_V4_SP_D16},
- * {"neon-vfpv4", FPU_ARCH_NEON_VFP_V4},
- *
- *
- * Simplified diagram that only includes FPUs supported by Android:
- * Only ARCH_VFP_V3D16 is actually mandated by the armeabi-v7a ABI,
- * all others are optional and must be probed at runtime.
- *
- * ARCH_VFP_V3D16 (EXT_V1xD+EXT_V1+EXT_V2+EXT_V3xD+EXT_V3)
- * |
- * +-------------------+
- * | |
- * | ARCH_VFP_V3D16_FP16 (+EXT_FP16)
- * |
- * +-------------------+
- * | |
- * | ARCH_VFP_V4_D16 (+EXT_FP16+EXT_FMA)
- * | |
- * | ARCH_VFP_V4 (+EXT_D32)
- * | |
- * | ARCH_NEON_VFP_V4 (+EXT_NEON+EXT_NEON_FMA)
- * |
- * ARCH_VFP_V3 (+EXT_D32)
- * |
- * +-------------------+
- * | |
- * | ARCH_VFP_V3_FP16 (+EXT_FP16)
- * |
- * ARCH_VFP_V3_PLUS_NEON_V1 (+EXT_NEON)
- * |
- * ARCH_NEON_FP16 (+EXT_FP16)
- *
- */
-
-#endif // defined(__le32__)
-#endif
-
-#endif
diff --git a/drivers/theoraplayer/src/YUV/android/cpu-features.h b/drivers/theoraplayer/src/YUV/android/cpu-features.h
deleted file mode 100644
index 12d3ad5645..0000000000
--- a/drivers/theoraplayer/src/YUV/android/cpu-features.h
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-#ifndef CPU_FEATURES_H
-#define CPU_FEATURES_H
-
-#include <sys/cdefs.h>
-#include <stdint.h>
-
-__BEGIN_DECLS
-
-typedef enum {
- ANDROID_CPU_FAMILY_UNKNOWN = 0,
- ANDROID_CPU_FAMILY_ARM,
- ANDROID_CPU_FAMILY_X86,
- ANDROID_CPU_FAMILY_MIPS,
-
- ANDROID_CPU_FAMILY_MAX /* do not remove */
-
-} AndroidCpuFamily;
-
-/* Return family of the device's CPU */
-extern AndroidCpuFamily android_getCpuFamily(void);
-
-/* The list of feature flags for ARM CPUs that can be recognized by the
- * library. Value details are:
- *
- * VFPv2:
- * CPU supports the VFPv2 instruction set. Many, but not all, ARMv6 CPUs
- * support these instructions. VFPv2 is a subset of VFPv3 so this will
- * be set whenever VFPv3 is set too.
- *
- * ARMv7:
- * CPU supports the ARMv7-A basic instruction set.
- * This feature is mandated by the 'armeabi-v7a' ABI.
- *
- * VFPv3:
- * CPU supports the VFPv3-D16 instruction set, providing hardware FPU
- * support for single and double precision floating point registers.
- * Note that only 16 FPU registers are available by default, unless
- * the D32 bit is set too. This feature is also mandated by the
- * 'armeabi-v7a' ABI.
- *
- * VFP_D32:
- * CPU VFP optional extension that provides 32 FPU registers,
- * instead of 16. Note that ARM mandates this feature is the 'NEON'
- * feature is implemented by the CPU.
- *
- * NEON:
- * CPU FPU supports "ARM Advanced SIMD" instructions, also known as
- * NEON. Note that this mandates the VFP_D32 feature as well, per the
- * ARM Architecture specification.
- *
- * VFP_FP16:
- * Half-width floating precision VFP extension. If set, the CPU
- * supports instructions to perform floating-point operations on
- * 16-bit registers. This is part of the VFPv4 specification, but
- * not mandated by any Android ABI.
- *
- * VFP_FMA:
- * Fused multiply-accumulate VFP instructions extension. Also part of
- * the VFPv4 specification, but not mandated by any Android ABI.
- *
- * NEON_FMA:
- * Fused multiply-accumulate NEON instructions extension. Optional
- * extension from the VFPv4 specification, but not mandated by any
- * Android ABI.
- *
- * IDIV_ARM:
- * Integer division available in ARM mode. Only available
- * on recent CPUs (e.g. Cortex-A15).
- *
- * IDIV_THUMB2:
- * Integer division available in Thumb-2 mode. Only available
- * on recent CPUs (e.g. Cortex-A15).
- *
- * iWMMXt:
- * Optional extension that adds MMX registers and operations to an
- * ARM CPU. This is only available on a few XScale-based CPU designs
- * sold by Marvell. Pretty rare in practice.
- *
- * If you want to tell the compiler to generate code that targets one of
- * the feature set above, you should probably use one of the following
- * flags (for more details, see technical note at the end of this file):
- *
- * -mfpu=vfp
- * -mfpu=vfpv2
- * These are equivalent and tell GCC to use VFPv2 instructions for
- * floating-point operations. Use this if you want your code to
- * run on *some* ARMv6 devices, and any ARMv7-A device supported
- * by Android.
- *
- * Generated code requires VFPv2 feature.
- *
- * -mfpu=vfpv3-d16
- * Tell GCC to use VFPv3 instructions (using only 16 FPU registers).
- * This should be generic code that runs on any CPU that supports the
- * 'armeabi-v7a' Android ABI. Note that no ARMv6 CPU supports this.
- *
- * Generated code requires VFPv3 feature.
- *
- * -mfpu=vfpv3
- * Tell GCC to use VFPv3 instructions with 32 FPU registers.
- * Generated code requires VFPv3|VFP_D32 features.
- *
- * -mfpu=neon
- * Tell GCC to use VFPv3 instructions with 32 FPU registers, and
- * also support NEON intrinsics (see <arm_neon.h>).
- * Generated code requires VFPv3|VFP_D32|NEON features.
- *
- * -mfpu=vfpv4-d16
- * Generated code requires VFPv3|VFP_FP16|VFP_FMA features.
- *
- * -mfpu=vfpv4
- * Generated code requires VFPv3|VFP_FP16|VFP_FMA|VFP_D32 features.
- *
- * -mfpu=neon-vfpv4
- * Generated code requires VFPv3|VFP_FP16|VFP_FMA|VFP_D32|NEON|NEON_FMA
- * features.
- *
- * -mcpu=cortex-a7
- * -mcpu=cortex-a15
- * Generated code requires VFPv3|VFP_FP16|VFP_FMA|VFP_D32|
- * NEON|NEON_FMA|IDIV_ARM|IDIV_THUMB2
- * This flag implies -mfpu=neon-vfpv4.
- *
- * -mcpu=iwmmxt
- * Allows the use of iWMMXt instrinsics with GCC.
- */
-enum {
- ANDROID_CPU_ARM_FEATURE_ARMv7 = (1 << 0),
- ANDROID_CPU_ARM_FEATURE_VFPv3 = (1 << 1),
- ANDROID_CPU_ARM_FEATURE_NEON = (1 << 2),
- ANDROID_CPU_ARM_FEATURE_LDREX_STREX = (1 << 3),
- ANDROID_CPU_ARM_FEATURE_VFPv2 = (1 << 4),
- ANDROID_CPU_ARM_FEATURE_VFP_D32 = (1 << 5),
- ANDROID_CPU_ARM_FEATURE_VFP_FP16 = (1 << 6),
- ANDROID_CPU_ARM_FEATURE_VFP_FMA = (1 << 7),
- ANDROID_CPU_ARM_FEATURE_NEON_FMA = (1 << 8),
- ANDROID_CPU_ARM_FEATURE_IDIV_ARM = (1 << 9),
- ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2 = (1 << 10),
- ANDROID_CPU_ARM_FEATURE_iWMMXt = (1 << 11),
-};
-
-enum {
- ANDROID_CPU_X86_FEATURE_SSSE3 = (1 << 0),
- ANDROID_CPU_X86_FEATURE_POPCNT = (1 << 1),
- ANDROID_CPU_X86_FEATURE_MOVBE = (1 << 2),
-};
-
-// libtheoraplayer addition, renamed this to "Ext" as not to conflict with your own project if you've included cpu-features.c in it
-//extern uint64_t android_getCpuFeaturesExt(void);
-#define android_getCpuFeaturesExt android_getCpuFeatures
-
-/* Return the number of CPU cores detected on this device. */
-extern int android_getCpuCount(void);
-
-/* The following is used to force the CPU count and features
- * mask in sandboxed processes. Under 4.1 and higher, these processes
- * cannot access /proc, which is the only way to get information from
- * the kernel about the current hardware (at least on ARM).
- *
- * It _must_ be called only once, and before any android_getCpuXXX
- * function, any other case will fail.
- *
- * This function return 1 on success, and 0 on failure.
- */
-extern int android_setCpu(int cpu_count,
- uint64_t cpu_features);
-
-#ifdef __arm__
-/* Retrieve the ARM 32-bit CPUID value from the kernel.
- * Note that this cannot work on sandboxed processes under 4.1 and
- * higher, unless you called android_setCpuArm() before.
- */
-extern uint32_t android_getCpuIdArm(void);
-
-/* An ARM-specific variant of android_setCpu() that also allows you
- * to set the ARM CPUID field.
- */
-extern int android_setCpuArm(int cpu_count,
- uint64_t cpu_features,
- uint32_t cpu_id);
-#endif
-
-__END_DECLS
-
-#endif /* CPU_FEATURES_H */
diff --git a/drivers/theoraplayer/src/YUV/libyuv/LICENSE b/drivers/theoraplayer/src/YUV/libyuv/LICENSE
deleted file mode 100755
index c911747a6b..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/LICENSE
+++ /dev/null
@@ -1,29 +0,0 @@
-Copyright 2011 The LibYuv Project Authors. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
-
- * Neither the name of Google nor the names of its contributors may
- be used to endorse or promote products derived from this software
- without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/drivers/theoraplayer/src/YUV/libyuv/LICENSE_THIRD_PARTY b/drivers/theoraplayer/src/YUV/libyuv/LICENSE_THIRD_PARTY
deleted file mode 100755
index a71591e771..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/LICENSE_THIRD_PARTY
+++ /dev/null
@@ -1,8 +0,0 @@
-This source tree contains third party source code which is governed by third
-party licenses. This file contains references to files which are under other
-licenses than the one provided in the LICENSE file in the root of the source
-tree.
-
-Files governed by third party licenses:
-source/x86inc.asm
-
diff --git a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv.h b/drivers/theoraplayer/src/YUV/libyuv/include/libyuv.h
deleted file mode 100755
index 3bebe642cc..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef INCLUDE_LIBYUV_H_ // NOLINT
-#define INCLUDE_LIBYUV_H_
-
-#include "libyuv/basic_types.h"
-#include "libyuv/compare.h"
-#include "libyuv/convert.h"
-#include "libyuv/convert_argb.h"
-#include "libyuv/convert_from.h"
-#include "libyuv/convert_from_argb.h"
-#include "libyuv/cpu_id.h"
-#include "libyuv/format_conversion.h"
-#include "libyuv/mjpeg_decoder.h"
-#include "libyuv/planar_functions.h"
-#include "libyuv/rotate.h"
-#include "libyuv/rotate_argb.h"
-#include "libyuv/row.h"
-#include "libyuv/scale.h"
-#include "libyuv/scale_argb.h"
-#include "libyuv/scale_row.h"
-#include "libyuv/version.h"
-#include "libyuv/video_common.h"
-
-#endif // INCLUDE_LIBYUV_H_ NOLINT
diff --git a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/basic_types.h b/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/basic_types.h
deleted file mode 100755
index beb750ba65..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/basic_types.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef INCLUDE_LIBYUV_BASIC_TYPES_H_ // NOLINT
-#define INCLUDE_LIBYUV_BASIC_TYPES_H_
-
-#include <stddef.h> // for NULL, size_t
-
-#if defined(__ANDROID__) || (defined(_MSC_VER) && (_MSC_VER < 1600))
-#include <sys/types.h> // for uintptr_t on x86
-#else
-#include <stdint.h> // for uintptr_t
-#endif
-
-#ifndef GG_LONGLONG
-#ifndef INT_TYPES_DEFINED
-#define INT_TYPES_DEFINED
-#ifdef COMPILER_MSVC
-typedef unsigned __int64 uint64;
-typedef __int64 int64;
-#ifndef INT64_C
-#define INT64_C(x) x ## I64
-#endif
-#ifndef UINT64_C
-#define UINT64_C(x) x ## UI64
-#endif
-#define INT64_F "I64"
-#else // COMPILER_MSVC
-#if defined(__LP64__) && !defined(__OpenBSD__) && !defined(__APPLE__)
-typedef unsigned long uint64; // NOLINT
-typedef long int64; // NOLINT
-#ifndef INT64_C
-#define INT64_C(x) x ## L
-#endif
-#ifndef UINT64_C
-#define UINT64_C(x) x ## UL
-#endif
-#define INT64_F "l"
-#else // defined(__LP64__) && !defined(__OpenBSD__) && !defined(__APPLE__)
-typedef unsigned long long uint64; // NOLINT
-typedef long long int64; // NOLINT
-#ifndef INT64_C
-#define INT64_C(x) x ## LL
-#endif
-#ifndef UINT64_C
-#define UINT64_C(x) x ## ULL
-#endif
-#define INT64_F "ll"
-#endif // __LP64__
-#endif // COMPILER_MSVC
-typedef unsigned int uint32;
-typedef int int32;
-typedef unsigned short uint16; // NOLINT
-typedef short int16; // NOLINT
-typedef unsigned char uint8;
-typedef signed char int8;
-#endif // INT_TYPES_DEFINED
-#endif // GG_LONGLONG
-
-// Detect compiler is for x86 or x64.
-#if defined(__x86_64__) || defined(_M_X64) || \
- defined(__i386__) || defined(_M_IX86)
-#define CPU_X86 1
-#endif
-// Detect compiler is for ARM.
-#if defined(__arm__) || defined(_M_ARM)
-#define CPU_ARM 1
-#endif
-
-#ifndef ALIGNP
-#ifdef __cplusplus
-#define ALIGNP(p, t) \
- (reinterpret_cast<uint8*>(((reinterpret_cast<uintptr_t>(p) + \
- ((t) - 1)) & ~((t) - 1))))
-#else
-#define ALIGNP(p, t) \
- ((uint8*)((((uintptr_t)(p) + ((t) - 1)) & ~((t) - 1)))) /* NOLINT */
-#endif
-#endif
-
-#if !defined(LIBYUV_API)
-#if defined(_WIN32) || defined(__CYGWIN__)
-#if defined(LIBYUV_BUILDING_SHARED_LIBRARY)
-#define LIBYUV_API __declspec(dllexport)
-#elif defined(LIBYUV_USING_SHARED_LIBRARY)
-#define LIBYUV_API __declspec(dllimport)
-#else
-#define LIBYUV_API
-#endif // LIBYUV_BUILDING_SHARED_LIBRARY
-#elif defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__APPLE__) && \
- (defined(LIBYUV_BUILDING_SHARED_LIBRARY) || \
- defined(LIBYUV_USING_SHARED_LIBRARY))
-#define LIBYUV_API __attribute__ ((visibility ("default")))
-#else
-#define LIBYUV_API
-#endif // __GNUC__
-#endif // LIBYUV_API
-
-#define LIBYUV_BOOL int
-#define LIBYUV_FALSE 0
-#define LIBYUV_TRUE 1
-
-// Visual C x86 or GCC little endian.
-#if defined(__x86_64__) || defined(_M_X64) || \
- defined(__i386__) || defined(_M_IX86) || \
- defined(__arm__) || defined(_M_ARM) || \
- (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
-#define LIBYUV_LITTLE_ENDIAN
-#endif
-
-#endif // INCLUDE_LIBYUV_BASIC_TYPES_H_ NOLINT
diff --git a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/compare.h b/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/compare.h
deleted file mode 100755
index 5dfac7c86a..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/compare.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef INCLUDE_LIBYUV_COMPARE_H_ // NOLINT
-#define INCLUDE_LIBYUV_COMPARE_H_
-
-#include "libyuv/basic_types.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// Compute a hash for specified memory. Seed of 5381 recommended.
-LIBYUV_API
-uint32 HashDjb2(const uint8* src, uint64 count, uint32 seed);
-
-// Sum Square Error - used to compute Mean Square Error or PSNR.
-LIBYUV_API
-uint64 ComputeSumSquareError(const uint8* src_a,
- const uint8* src_b, int count);
-
-LIBYUV_API
-uint64 ComputeSumSquareErrorPlane(const uint8* src_a, int stride_a,
- const uint8* src_b, int stride_b,
- int width, int height);
-
-static const int kMaxPsnr = 128;
-
-LIBYUV_API
-double SumSquareErrorToPsnr(uint64 sse, uint64 count);
-
-LIBYUV_API
-double CalcFramePsnr(const uint8* src_a, int stride_a,
- const uint8* src_b, int stride_b,
- int width, int height);
-
-LIBYUV_API
-double I420Psnr(const uint8* src_y_a, int stride_y_a,
- const uint8* src_u_a, int stride_u_a,
- const uint8* src_v_a, int stride_v_a,
- const uint8* src_y_b, int stride_y_b,
- const uint8* src_u_b, int stride_u_b,
- const uint8* src_v_b, int stride_v_b,
- int width, int height);
-
-LIBYUV_API
-double CalcFrameSsim(const uint8* src_a, int stride_a,
- const uint8* src_b, int stride_b,
- int width, int height);
-
-LIBYUV_API
-double I420Ssim(const uint8* src_y_a, int stride_y_a,
- const uint8* src_u_a, int stride_u_a,
- const uint8* src_v_a, int stride_v_a,
- const uint8* src_y_b, int stride_y_b,
- const uint8* src_u_b, int stride_u_b,
- const uint8* src_v_b, int stride_v_b,
- int width, int height);
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
-
-#endif // INCLUDE_LIBYUV_COMPARE_H_ NOLINT
diff --git a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/convert.h b/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/convert.h
deleted file mode 100755
index 1bd45c837f..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/convert.h
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef INCLUDE_LIBYUV_CONVERT_H_ // NOLINT
-#define INCLUDE_LIBYUV_CONVERT_H_
-
-#include "libyuv/basic_types.h"
-// TODO(fbarchard): Remove the following headers includes.
-#include "libyuv/convert_from.h"
-#include "libyuv/planar_functions.h"
-#include "libyuv/rotate.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// Convert I444 to I420.
-LIBYUV_API
-int I444ToI420(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// Convert I422 to I420.
-LIBYUV_API
-int I422ToI420(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// Convert I411 to I420.
-LIBYUV_API
-int I411ToI420(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// Copy I420 to I420.
-#define I420ToI420 I420Copy
-LIBYUV_API
-int I420Copy(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// Convert I400 (grey) to I420.
-LIBYUV_API
-int I400ToI420(const uint8* src_y, int src_stride_y,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// Convert NV12 to I420.
-LIBYUV_API
-int NV12ToI420(const uint8* src_y, int src_stride_y,
- const uint8* src_uv, int src_stride_uv,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// Convert NV21 to I420.
-LIBYUV_API
-int NV21ToI420(const uint8* src_y, int src_stride_y,
- const uint8* src_vu, int src_stride_vu,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// Convert YUY2 to I420.
-LIBYUV_API
-int YUY2ToI420(const uint8* src_yuy2, int src_stride_yuy2,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// Convert UYVY to I420.
-LIBYUV_API
-int UYVYToI420(const uint8* src_uyvy, int src_stride_uyvy,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// Convert M420 to I420.
-LIBYUV_API
-int M420ToI420(const uint8* src_m420, int src_stride_m420,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// Convert Q420 to I420.
-LIBYUV_API
-int Q420ToI420(const uint8* src_y, int src_stride_y,
- const uint8* src_yuy2, int src_stride_yuy2,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// ARGB little endian (bgra in memory) to I420.
-LIBYUV_API
-int ARGBToI420(const uint8* src_frame, int src_stride_frame,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// BGRA little endian (argb in memory) to I420.
-LIBYUV_API
-int BGRAToI420(const uint8* src_frame, int src_stride_frame,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// ABGR little endian (rgba in memory) to I420.
-LIBYUV_API
-int ABGRToI420(const uint8* src_frame, int src_stride_frame,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// RGBA little endian (abgr in memory) to I420.
-LIBYUV_API
-int RGBAToI420(const uint8* src_frame, int src_stride_frame,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// RGB little endian (bgr in memory) to I420.
-LIBYUV_API
-int RGB24ToI420(const uint8* src_frame, int src_stride_frame,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// RGB big endian (rgb in memory) to I420.
-LIBYUV_API
-int RAWToI420(const uint8* src_frame, int src_stride_frame,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// RGB16 (RGBP fourcc) little endian to I420.
-LIBYUV_API
-int RGB565ToI420(const uint8* src_frame, int src_stride_frame,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// RGB15 (RGBO fourcc) little endian to I420.
-LIBYUV_API
-int ARGB1555ToI420(const uint8* src_frame, int src_stride_frame,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// RGB12 (R444 fourcc) little endian to I420.
-LIBYUV_API
-int ARGB4444ToI420(const uint8* src_frame, int src_stride_frame,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-#ifdef HAVE_JPEG
-// src_width/height provided by capture.
-// dst_width/height for clipping determine final size.
-LIBYUV_API
-int MJPGToI420(const uint8* sample, size_t sample_size,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int src_width, int src_height,
- int dst_width, int dst_height);
-
-// Query size of MJPG in pixels.
-LIBYUV_API
-int MJPGSize(const uint8* sample, size_t sample_size,
- int* width, int* height);
-#endif
-
-// Note Bayer formats (BGGR) To I420 are in format_conversion.h
-
-// Convert camera sample to I420 with cropping, rotation and vertical flip.
-// "src_size" is needed to parse MJPG.
-// "dst_stride_y" number of bytes in a row of the dst_y plane.
-// Normally this would be the same as dst_width, with recommended alignment
-// to 16 bytes for better efficiency.
-// If rotation of 90 or 270 is used, stride is affected. The caller should
-// allocate the I420 buffer according to rotation.
-// "dst_stride_u" number of bytes in a row of the dst_u plane.
-// Normally this would be the same as (dst_width + 1) / 2, with
-// recommended alignment to 16 bytes for better efficiency.
-// If rotation of 90 or 270 is used, stride is affected.
-// "crop_x" and "crop_y" are starting position for cropping.
-// To center, crop_x = (src_width - dst_width) / 2
-// crop_y = (src_height - dst_height) / 2
-// "src_width" / "src_height" is size of src_frame in pixels.
-// "src_height" can be negative indicating a vertically flipped image source.
-// "crop_width" / "crop_height" is the size to crop the src to.
-// Must be less than or equal to src_width/src_height
-// Cropping parameters are pre-rotation.
-// "rotation" can be 0, 90, 180 or 270.
-// "format" is a fourcc. ie 'I420', 'YUY2'
-// Returns 0 for successful; -1 for invalid parameter. Non-zero for failure.
-LIBYUV_API
-int ConvertToI420(const uint8* src_frame, size_t src_size,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int crop_x, int crop_y,
- int src_width, int src_height,
- int crop_width, int crop_height,
- enum RotationMode rotation,
- uint32 format);
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
-
-#endif // INCLUDE_LIBYUV_CONVERT_H_ NOLINT
diff --git a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/convert_argb.h b/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/convert_argb.h
deleted file mode 100755
index a18014ca2c..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/convert_argb.h
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright 2012 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef INCLUDE_LIBYUV_CONVERT_ARGB_H_ // NOLINT
-#define INCLUDE_LIBYUV_CONVERT_ARGB_H_
-
-#include "libyuv/basic_types.h"
-// TODO(fbarchard): Remove the following headers includes
-#include "libyuv/convert_from.h"
-#include "libyuv/planar_functions.h"
-#include "libyuv/rotate.h"
-
-// TODO(fbarchard): This set of functions should exactly match convert.h
-// Add missing Q420.
-// TODO(fbarchard): Add tests. Create random content of right size and convert
-// with C vs Opt and or to I420 and compare.
-// TODO(fbarchard): Some of these functions lack parameter setting.
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// Alias.
-#define ARGBToARGB ARGBCopy
-
-// Copy ARGB to ARGB.
-LIBYUV_API
-int ARGBCopy(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// Convert I420 to ARGB.
-LIBYUV_API
-int I420ToARGB(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// Convert I422 to ARGB.
-LIBYUV_API
-int I422ToARGB(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// Convert I444 to ARGB.
-LIBYUV_API
-int I444ToARGB(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// Convert I411 to ARGB.
-LIBYUV_API
-int I411ToARGB(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// Convert I400 (grey) to ARGB.
-LIBYUV_API
-int I400ToARGB(const uint8* src_y, int src_stride_y,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// Alias.
-#define YToARGB I400ToARGB_Reference
-
-// Convert I400 to ARGB. Reverse of ARGBToI400.
-LIBYUV_API
-int I400ToARGB_Reference(const uint8* src_y, int src_stride_y,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// Convert NV12 to ARGB.
-LIBYUV_API
-int NV12ToARGB(const uint8* src_y, int src_stride_y,
- const uint8* src_uv, int src_stride_uv,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// Convert NV21 to ARGB.
-LIBYUV_API
-int NV21ToARGB(const uint8* src_y, int src_stride_y,
- const uint8* src_vu, int src_stride_vu,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// Convert M420 to ARGB.
-LIBYUV_API
-int M420ToARGB(const uint8* src_m420, int src_stride_m420,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// TODO(fbarchard): Convert Q420 to ARGB.
-// LIBYUV_API
-// int Q420ToARGB(const uint8* src_y, int src_stride_y,
-// const uint8* src_yuy2, int src_stride_yuy2,
-// uint8* dst_argb, int dst_stride_argb,
-// int width, int height);
-
-// Convert YUY2 to ARGB.
-LIBYUV_API
-int YUY2ToARGB(const uint8* src_yuy2, int src_stride_yuy2,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// Convert UYVY to ARGB.
-LIBYUV_API
-int UYVYToARGB(const uint8* src_uyvy, int src_stride_uyvy,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// BGRA little endian (argb in memory) to ARGB.
-LIBYUV_API
-int BGRAToARGB(const uint8* src_frame, int src_stride_frame,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// ABGR little endian (rgba in memory) to ARGB.
-LIBYUV_API
-int ABGRToARGB(const uint8* src_frame, int src_stride_frame,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// RGBA little endian (abgr in memory) to ARGB.
-LIBYUV_API
-int RGBAToARGB(const uint8* src_frame, int src_stride_frame,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// Deprecated function name.
-#define BG24ToARGB RGB24ToARGB
-
-// RGB little endian (bgr in memory) to ARGB.
-LIBYUV_API
-int RGB24ToARGB(const uint8* src_frame, int src_stride_frame,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// RGB big endian (rgb in memory) to ARGB.
-LIBYUV_API
-int RAWToARGB(const uint8* src_frame, int src_stride_frame,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// RGB16 (RGBP fourcc) little endian to ARGB.
-LIBYUV_API
-int RGB565ToARGB(const uint8* src_frame, int src_stride_frame,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// RGB15 (RGBO fourcc) little endian to ARGB.
-LIBYUV_API
-int ARGB1555ToARGB(const uint8* src_frame, int src_stride_frame,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// RGB12 (R444 fourcc) little endian to ARGB.
-LIBYUV_API
-int ARGB4444ToARGB(const uint8* src_frame, int src_stride_frame,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-#ifdef HAVE_JPEG
-// src_width/height provided by capture
-// dst_width/height for clipping determine final size.
-LIBYUV_API
-int MJPGToARGB(const uint8* sample, size_t sample_size,
- uint8* dst_argb, int dst_stride_argb,
- int src_width, int src_height,
- int dst_width, int dst_height);
-#endif
-
-// Note Bayer formats (BGGR) to ARGB are in format_conversion.h.
-
-// Convert camera sample to ARGB with cropping, rotation and vertical flip.
-// "src_size" is needed to parse MJPG.
-// "dst_stride_argb" number of bytes in a row of the dst_argb plane.
-// Normally this would be the same as dst_width, with recommended alignment
-// to 16 bytes for better efficiency.
-// If rotation of 90 or 270 is used, stride is affected. The caller should
-// allocate the I420 buffer according to rotation.
-// "dst_stride_u" number of bytes in a row of the dst_u plane.
-// Normally this would be the same as (dst_width + 1) / 2, with
-// recommended alignment to 16 bytes for better efficiency.
-// If rotation of 90 or 270 is used, stride is affected.
-// "crop_x" and "crop_y" are starting position for cropping.
-// To center, crop_x = (src_width - dst_width) / 2
-// crop_y = (src_height - dst_height) / 2
-// "src_width" / "src_height" is size of src_frame in pixels.
-// "src_height" can be negative indicating a vertically flipped image source.
-// "crop_width" / "crop_height" is the size to crop the src to.
-// Must be less than or equal to src_width/src_height
-// Cropping parameters are pre-rotation.
-// "rotation" can be 0, 90, 180 or 270.
-// "format" is a fourcc. ie 'I420', 'YUY2'
-// Returns 0 for successful; -1 for invalid parameter. Non-zero for failure.
-LIBYUV_API
-int ConvertToARGB(const uint8* src_frame, size_t src_size,
- uint8* dst_argb, int dst_stride_argb,
- int crop_x, int crop_y,
- int src_width, int src_height,
- int crop_width, int crop_height,
- enum RotationMode rotation,
- uint32 format);
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
-
-#endif // INCLUDE_LIBYUV_CONVERT_ARGB_H_ NOLINT
diff --git a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/convert_from.h b/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/convert_from.h
deleted file mode 100755
index b1cf57f7dc..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/convert_from.h
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef INCLUDE_LIBYUV_CONVERT_FROM_H_ // NOLINT
-#define INCLUDE_LIBYUV_CONVERT_FROM_H_
-
-#include "libyuv/basic_types.h"
-#include "libyuv/rotate.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// See Also convert.h for conversions from formats to I420.
-
-// I420Copy in convert to I420ToI420.
-
-LIBYUV_API
-int I420ToI422(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-LIBYUV_API
-int I420ToI444(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-LIBYUV_API
-int I420ToI411(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// Copy to I400. Source can be I420, I422, I444, I400, NV12 or NV21.
-LIBYUV_API
-int I400Copy(const uint8* src_y, int src_stride_y,
- uint8* dst_y, int dst_stride_y,
- int width, int height);
-
-// TODO(fbarchard): I420ToM420
-// TODO(fbarchard): I420ToQ420
-
-LIBYUV_API
-int I420ToNV12(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_uv, int dst_stride_uv,
- int width, int height);
-
-LIBYUV_API
-int I420ToNV21(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_vu, int dst_stride_vu,
- int width, int height);
-
-LIBYUV_API
-int I420ToYUY2(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_frame, int dst_stride_frame,
- int width, int height);
-
-LIBYUV_API
-int I420ToUYVY(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_frame, int dst_stride_frame,
- int width, int height);
-
-LIBYUV_API
-int I420ToARGB(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-LIBYUV_API
-int I420ToBGRA(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-LIBYUV_API
-int I420ToABGR(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-LIBYUV_API
-int I420ToRGBA(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_rgba, int dst_stride_rgba,
- int width, int height);
-
-LIBYUV_API
-int I420ToRGB24(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_frame, int dst_stride_frame,
- int width, int height);
-
-LIBYUV_API
-int I420ToRAW(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_frame, int dst_stride_frame,
- int width, int height);
-
-LIBYUV_API
-int I420ToRGB565(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_frame, int dst_stride_frame,
- int width, int height);
-
-LIBYUV_API
-int I420ToARGB1555(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_frame, int dst_stride_frame,
- int width, int height);
-
-LIBYUV_API
-int I420ToARGB4444(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_frame, int dst_stride_frame,
- int width, int height);
-
-// Note Bayer formats (BGGR) To I420 are in format_conversion.h.
-
-// Convert I420 to specified format.
-// "dst_sample_stride" is bytes in a row for the destination. Pass 0 if the
-// buffer has contiguous rows. Can be negative. A multiple of 16 is optimal.
-LIBYUV_API
-int ConvertFromI420(const uint8* y, int y_stride,
- const uint8* u, int u_stride,
- const uint8* v, int v_stride,
- uint8* dst_sample, int dst_sample_stride,
- int width, int height,
- uint32 format);
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
-
-#endif // INCLUDE_LIBYUV_CONVERT_FROM_H_ NOLINT
diff --git a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/convert_from_argb.h b/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/convert_from_argb.h
deleted file mode 100755
index f0343a77d3..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/convert_from_argb.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright 2012 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef INCLUDE_LIBYUV_CONVERT_FROM_ARGB_H_ // NOLINT
-#define INCLUDE_LIBYUV_CONVERT_FROM_ARGB_H_
-
-#include "libyuv/basic_types.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// Copy ARGB to ARGB.
-#define ARGBToARGB ARGBCopy
-LIBYUV_API
-int ARGBCopy(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// Convert ARGB To BGRA. (alias)
-#define ARGBToBGRA BGRAToARGB
-LIBYUV_API
-int BGRAToARGB(const uint8* src_frame, int src_stride_frame,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// Convert ARGB To ABGR. (alias)
-#define ARGBToABGR ABGRToARGB
-LIBYUV_API
-int ABGRToARGB(const uint8* src_frame, int src_stride_frame,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// Convert ARGB To RGBA.
-LIBYUV_API
-int ARGBToRGBA(const uint8* src_frame, int src_stride_frame,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// Convert ARGB To RGB24.
-LIBYUV_API
-int ARGBToRGB24(const uint8* src_argb, int src_stride_argb,
- uint8* dst_rgb24, int dst_stride_rgb24,
- int width, int height);
-
-// Convert ARGB To RAW.
-LIBYUV_API
-int ARGBToRAW(const uint8* src_argb, int src_stride_argb,
- uint8* dst_rgb, int dst_stride_rgb,
- int width, int height);
-
-// Convert ARGB To RGB565.
-LIBYUV_API
-int ARGBToRGB565(const uint8* src_argb, int src_stride_argb,
- uint8* dst_rgb565, int dst_stride_rgb565,
- int width, int height);
-
-// Convert ARGB To ARGB1555.
-LIBYUV_API
-int ARGBToARGB1555(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb1555, int dst_stride_argb1555,
- int width, int height);
-
-// Convert ARGB To ARGB4444.
-LIBYUV_API
-int ARGBToARGB4444(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb4444, int dst_stride_argb4444,
- int width, int height);
-
-// Convert ARGB To I444.
-LIBYUV_API
-int ARGBToI444(const uint8* src_argb, int src_stride_argb,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// Convert ARGB To I422.
-LIBYUV_API
-int ARGBToI422(const uint8* src_argb, int src_stride_argb,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// Convert ARGB To I420. (also in convert.h)
-LIBYUV_API
-int ARGBToI420(const uint8* src_argb, int src_stride_argb,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// Convert ARGB to J420. (JPeg full range I420).
-LIBYUV_API
-int ARGBToJ420(const uint8* src_argb, int src_stride_argb,
- uint8* dst_yj, int dst_stride_yj,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// Convert ARGB To I411.
-LIBYUV_API
-int ARGBToI411(const uint8* src_argb, int src_stride_argb,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// Convert ARGB to J400. (JPeg full range).
-LIBYUV_API
-int ARGBToJ400(const uint8* src_argb, int src_stride_argb,
- uint8* dst_yj, int dst_stride_yj,
- int width, int height);
-
-// Convert ARGB to I400.
-LIBYUV_API
-int ARGBToI400(const uint8* src_argb, int src_stride_argb,
- uint8* dst_y, int dst_stride_y,
- int width, int height);
-
-// Convert ARGB To NV12.
-LIBYUV_API
-int ARGBToNV12(const uint8* src_argb, int src_stride_argb,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_uv, int dst_stride_uv,
- int width, int height);
-
-// Convert ARGB To NV21.
-LIBYUV_API
-int ARGBToNV21(const uint8* src_argb, int src_stride_argb,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_vu, int dst_stride_vu,
- int width, int height);
-
-// Convert ARGB To NV21.
-LIBYUV_API
-int ARGBToNV21(const uint8* src_argb, int src_stride_argb,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_vu, int dst_stride_vu,
- int width, int height);
-
-// Convert ARGB To YUY2.
-LIBYUV_API
-int ARGBToYUY2(const uint8* src_argb, int src_stride_argb,
- uint8* dst_yuy2, int dst_stride_yuy2,
- int width, int height);
-
-// Convert ARGB To UYVY.
-LIBYUV_API
-int ARGBToUYVY(const uint8* src_argb, int src_stride_argb,
- uint8* dst_uyvy, int dst_stride_uyvy,
- int width, int height);
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
-
-#endif // INCLUDE_LIBYUV_CONVERT_FROM_ARGB_H_ NOLINT
diff --git a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/cpu_id.h b/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/cpu_id.h
deleted file mode 100755
index dc858a814a..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/cpu_id.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef INCLUDE_LIBYUV_CPU_ID_H_ // NOLINT
-#define INCLUDE_LIBYUV_CPU_ID_H_
-
-#include "libyuv/basic_types.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// TODO(fbarchard): Consider overlapping bits for different architectures.
-// Internal flag to indicate cpuid requires initialization.
-#define kCpuInit 0x1
-
-// These flags are only valid on ARM processors.
-static const int kCpuHasARM = 0x2;
-static const int kCpuHasNEON = 0x4;
-// 0x8 reserved for future ARM flag.
-
-// These flags are only valid on x86 processors.
-static const int kCpuHasX86 = 0x10;
-static const int kCpuHasSSE2 = 0x20;
-static const int kCpuHasSSSE3 = 0x40;
-static const int kCpuHasSSE41 = 0x80;
-static const int kCpuHasSSE42 = 0x100;
-static const int kCpuHasAVX = 0x200;
-static const int kCpuHasAVX2 = 0x400;
-static const int kCpuHasERMS = 0x800;
-static const int kCpuHasFMA3 = 0x1000;
-// 0x2000, 0x4000, 0x8000 reserved for future X86 flags.
-
-// These flags are only valid on MIPS processors.
-static const int kCpuHasMIPS = 0x10000;
-static const int kCpuHasMIPS_DSP = 0x20000;
-static const int kCpuHasMIPS_DSPR2 = 0x40000;
-
-// Internal function used to auto-init.
-LIBYUV_API
-int InitCpuFlags(void);
-
-// Internal function for parsing /proc/cpuinfo.
-LIBYUV_API
-int ArmCpuCaps(const char* cpuinfo_name);
-
-// Detect CPU has SSE2 etc.
-// Test_flag parameter should be one of kCpuHas constants above.
-// returns non-zero if instruction set is detected
-static __inline int TestCpuFlag(int test_flag) {
- LIBYUV_API extern int cpu_info_;
- return (cpu_info_ == kCpuInit ? InitCpuFlags() : cpu_info_) & test_flag;
-}
-
-// For testing, allow CPU flags to be disabled.
-// ie MaskCpuFlags(~kCpuHasSSSE3) to disable SSSE3.
-// MaskCpuFlags(-1) to enable all cpu specific optimizations.
-// MaskCpuFlags(0) to disable all cpu specific optimizations.
-LIBYUV_API
-void MaskCpuFlags(int enable_flags);
-
-// Low level cpuid for X86. Returns zeros on other CPUs.
-// eax is the info type that you want.
-// ecx is typically the cpu number, and should normally be zero.
-LIBYUV_API
-void CpuId(uint32 eax, uint32 ecx, uint32* cpu_info);
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
-
-#endif // INCLUDE_LIBYUV_CPU_ID_H_ NOLINT
diff --git a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/format_conversion.h b/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/format_conversion.h
deleted file mode 100755
index b18bf05343..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/format_conversion.h
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef INCLUDE_LIBYUV_FORMATCONVERSION_H_ // NOLINT
-#define INCLUDE_LIBYUV_FORMATCONVERSION_H_
-
-#include "libyuv/basic_types.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// Convert Bayer RGB formats to I420.
-LIBYUV_API
-int BayerBGGRToI420(const uint8* src_bayer, int src_stride_bayer,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-LIBYUV_API
-int BayerGBRGToI420(const uint8* src_bayer, int src_stride_bayer,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-LIBYUV_API
-int BayerGRBGToI420(const uint8* src_bayer, int src_stride_bayer,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-LIBYUV_API
-int BayerRGGBToI420(const uint8* src_bayer, int src_stride_bayer,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// Temporary API mapper.
-#define BayerRGBToI420(b, bs, f, y, ys, u, us, v, vs, w, h) \
- BayerToI420(b, bs, y, ys, u, us, v, vs, w, h, f)
-
-LIBYUV_API
-int BayerToI420(const uint8* src_bayer, int src_stride_bayer,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height,
- uint32 src_fourcc_bayer);
-
-// Convert I420 to Bayer RGB formats.
-LIBYUV_API
-int I420ToBayerBGGR(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_frame, int dst_stride_frame,
- int width, int height);
-
-LIBYUV_API
-int I420ToBayerGBRG(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_frame, int dst_stride_frame,
- int width, int height);
-
-LIBYUV_API
-int I420ToBayerGRBG(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_frame, int dst_stride_frame,
- int width, int height);
-
-LIBYUV_API
-int I420ToBayerRGGB(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_frame, int dst_stride_frame,
- int width, int height);
-
-// Temporary API mapper.
-#define I420ToBayerRGB(y, ys, u, us, v, vs, b, bs, f, w, h) \
- I420ToBayer(y, ys, u, us, v, vs, b, bs, w, h, f)
-
-LIBYUV_API
-int I420ToBayer(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_frame, int dst_stride_frame,
- int width, int height,
- uint32 dst_fourcc_bayer);
-
-// Convert Bayer RGB formats to ARGB.
-LIBYUV_API
-int BayerBGGRToARGB(const uint8* src_bayer, int src_stride_bayer,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-LIBYUV_API
-int BayerGBRGToARGB(const uint8* src_bayer, int src_stride_bayer,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-LIBYUV_API
-int BayerGRBGToARGB(const uint8* src_bayer, int src_stride_bayer,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-LIBYUV_API
-int BayerRGGBToARGB(const uint8* src_bayer, int src_stride_bayer,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// Temporary API mapper.
-#define BayerRGBToARGB(b, bs, f, a, as, w, h) BayerToARGB(b, bs, a, as, w, h, f)
-
-LIBYUV_API
-int BayerToARGB(const uint8* src_bayer, int src_stride_bayer,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height,
- uint32 src_fourcc_bayer);
-
-// Converts ARGB to Bayer RGB formats.
-LIBYUV_API
-int ARGBToBayerBGGR(const uint8* src_argb, int src_stride_argb,
- uint8* dst_bayer, int dst_stride_bayer,
- int width, int height);
-
-LIBYUV_API
-int ARGBToBayerGBRG(const uint8* src_argb, int src_stride_argb,
- uint8* dst_bayer, int dst_stride_bayer,
- int width, int height);
-
-LIBYUV_API
-int ARGBToBayerGRBG(const uint8* src_argb, int src_stride_argb,
- uint8* dst_bayer, int dst_stride_bayer,
- int width, int height);
-
-LIBYUV_API
-int ARGBToBayerRGGB(const uint8* src_argb, int src_stride_argb,
- uint8* dst_bayer, int dst_stride_bayer,
- int width, int height);
-
-// Temporary API mapper.
-#define ARGBToBayerRGB(a, as, b, bs, f, w, h) ARGBToBayer(b, bs, a, as, w, h, f)
-
-LIBYUV_API
-int ARGBToBayer(const uint8* src_argb, int src_stride_argb,
- uint8* dst_bayer, int dst_stride_bayer,
- int width, int height,
- uint32 dst_fourcc_bayer);
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
-
-#endif // INCLUDE_LIBYUV_FORMATCONVERSION_H_ NOLINT
diff --git a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/mjpeg_decoder.h b/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/mjpeg_decoder.h
deleted file mode 100755
index faffaea8fa..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/mjpeg_decoder.h
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright 2012 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef INCLUDE_LIBYUV_MJPEG_DECODER_H_ // NOLINT
-#define INCLUDE_LIBYUV_MJPEG_DECODER_H_
-
-#include "libyuv/basic_types.h"
-
-#ifdef __cplusplus
-// NOTE: For a simplified public API use convert.h MJPGToI420().
-
-struct jpeg_common_struct;
-struct jpeg_decompress_struct;
-struct jpeg_source_mgr;
-
-namespace libyuv {
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-LIBYUV_BOOL ValidateJpeg(const uint8* sample, size_t sample_size);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-static const uint32 kUnknownDataSize = 0xFFFFFFFF;
-
-enum JpegSubsamplingType {
- kJpegYuv420,
- kJpegYuv422,
- kJpegYuv411,
- kJpegYuv444,
- kJpegYuv400,
- kJpegUnknown
-};
-
-struct SetJmpErrorMgr;
-
-// MJPEG ("Motion JPEG") is a pseudo-standard video codec where the frames are
-// simply independent JPEG images with a fixed huffman table (which is omitted).
-// It is rarely used in video transmission, but is common as a camera capture
-// format, especially in Logitech devices. This class implements a decoder for
-// MJPEG frames.
-//
-// See http://tools.ietf.org/html/rfc2435
-class LIBYUV_API MJpegDecoder {
- public:
- typedef void (*CallbackFunction)(void* opaque,
- const uint8* const* data,
- const int* strides,
- int rows);
-
- static const int kColorSpaceUnknown;
- static const int kColorSpaceGrayscale;
- static const int kColorSpaceRgb;
- static const int kColorSpaceYCbCr;
- static const int kColorSpaceCMYK;
- static const int kColorSpaceYCCK;
-
- MJpegDecoder();
- ~MJpegDecoder();
-
- // Loads a new frame, reads its headers, and determines the uncompressed
- // image format.
- // Returns LIBYUV_TRUE if image looks valid and format is supported.
- // If return value is LIBYUV_TRUE, then the values for all the following
- // getters are populated.
- // src_len is the size of the compressed mjpeg frame in bytes.
- LIBYUV_BOOL LoadFrame(const uint8* src, size_t src_len);
-
- // Returns width of the last loaded frame in pixels.
- int GetWidth();
-
- // Returns height of the last loaded frame in pixels.
- int GetHeight();
-
- // Returns format of the last loaded frame. The return value is one of the
- // kColorSpace* constants.
- int GetColorSpace();
-
- // Number of color components in the color space.
- int GetNumComponents();
-
- // Sample factors of the n-th component.
- int GetHorizSampFactor(int component);
-
- int GetVertSampFactor(int component);
-
- int GetHorizSubSampFactor(int component);
-
- int GetVertSubSampFactor(int component);
-
- // Public for testability.
- int GetImageScanlinesPerImcuRow();
-
- // Public for testability.
- int GetComponentScanlinesPerImcuRow(int component);
-
- // Width of a component in bytes.
- int GetComponentWidth(int component);
-
- // Height of a component.
- int GetComponentHeight(int component);
-
- // Width of a component in bytes with padding for DCTSIZE. Public for testing.
- int GetComponentStride(int component);
-
- // Size of a component in bytes.
- int GetComponentSize(int component);
-
- // Call this after LoadFrame() if you decide you don't want to decode it
- // after all.
- LIBYUV_BOOL UnloadFrame();
-
- // Decodes the entire image into a one-buffer-per-color-component format.
- // dst_width must match exactly. dst_height must be <= to image height; if
- // less, the image is cropped. "planes" must have size equal to at least
- // GetNumComponents() and they must point to non-overlapping buffers of size
- // at least GetComponentSize(i). The pointers in planes are incremented
- // to point to after the end of the written data.
- // TODO(fbarchard): Add dst_x, dst_y to allow specific rect to be decoded.
- LIBYUV_BOOL DecodeToBuffers(uint8** planes, int dst_width, int dst_height);
-
- // Decodes the entire image and passes the data via repeated calls to a
- // callback function. Each call will get the data for a whole number of
- // image scanlines.
- // TODO(fbarchard): Add dst_x, dst_y to allow specific rect to be decoded.
- LIBYUV_BOOL DecodeToCallback(CallbackFunction fn, void* opaque,
- int dst_width, int dst_height);
-
- // The helper function which recognizes the jpeg sub-sampling type.
- static JpegSubsamplingType JpegSubsamplingTypeHelper(
- int* subsample_x, int* subsample_y, int number_of_components);
-
- private:
- struct Buffer {
- const uint8* data;
- int len;
- };
-
- struct BufferVector {
- Buffer* buffers;
- int len;
- int pos;
- };
-
- // Methods that are passed to jpeglib.
- static int fill_input_buffer(jpeg_decompress_struct* cinfo);
- static void init_source(jpeg_decompress_struct* cinfo);
- static void skip_input_data(jpeg_decompress_struct* cinfo,
- long num_bytes); // NOLINT
- static void term_source(jpeg_decompress_struct* cinfo);
-
- static void ErrorHandler(jpeg_common_struct* cinfo);
-
- void AllocOutputBuffers(int num_outbufs);
- void DestroyOutputBuffers();
-
- LIBYUV_BOOL StartDecode();
- LIBYUV_BOOL FinishDecode();
-
- void SetScanlinePointers(uint8** data);
- LIBYUV_BOOL DecodeImcuRow();
-
- int GetComponentScanlinePadding(int component);
-
- // A buffer holding the input data for a frame.
- Buffer buf_;
- BufferVector buf_vec_;
-
- jpeg_decompress_struct* decompress_struct_;
- jpeg_source_mgr* source_mgr_;
- SetJmpErrorMgr* error_mgr_;
-
- // LIBYUV_TRUE iff at least one component has scanline padding. (i.e.,
- // GetComponentScanlinePadding() != 0.)
- LIBYUV_BOOL has_scanline_padding_;
-
- // Temporaries used to point to scanline outputs.
- int num_outbufs_; // Outermost size of all arrays below.
- uint8*** scanlines_;
- int* scanlines_sizes_;
- // Temporary buffer used for decoding when we can't decode directly to the
- // output buffers. Large enough for just one iMCU row.
- uint8** databuf_;
- int* databuf_strides_;
-};
-
-} // namespace libyuv
-
-#endif // __cplusplus
-#endif // INCLUDE_LIBYUV_MJPEG_DECODER_H_ NOLINT
diff --git a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/planar_functions.h b/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/planar_functions.h
deleted file mode 100755
index ac516c5ba5..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/planar_functions.h
+++ /dev/null
@@ -1,434 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef INCLUDE_LIBYUV_PLANAR_FUNCTIONS_H_ // NOLINT
-#define INCLUDE_LIBYUV_PLANAR_FUNCTIONS_H_
-
-#include "libyuv/basic_types.h"
-
-// TODO(fbarchard): Remove the following headers includes.
-#include "libyuv/convert.h"
-#include "libyuv/convert_argb.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// Copy a plane of data.
-LIBYUV_API
-void CopyPlane(const uint8* src_y, int src_stride_y,
- uint8* dst_y, int dst_stride_y,
- int width, int height);
-
-// Set a plane of data to a 32 bit value.
-LIBYUV_API
-void SetPlane(uint8* dst_y, int dst_stride_y,
- int width, int height,
- uint32 value);
-
-// Copy I400. Supports inverting.
-LIBYUV_API
-int I400ToI400(const uint8* src_y, int src_stride_y,
- uint8* dst_y, int dst_stride_y,
- int width, int height);
-
-
-// Copy I422 to I422.
-#define I422ToI422 I422Copy
-LIBYUV_API
-int I422Copy(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// Copy I444 to I444.
-#define I444ToI444 I444Copy
-LIBYUV_API
-int I444Copy(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// Convert YUY2 to I422.
-LIBYUV_API
-int YUY2ToI422(const uint8* src_yuy2, int src_stride_yuy2,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// Convert UYVY to I422.
-LIBYUV_API
-int UYVYToI422(const uint8* src_uyvy, int src_stride_uyvy,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// Convert I420 to I400. (calls CopyPlane ignoring u/v).
-LIBYUV_API
-int I420ToI400(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- int width, int height);
-
-// Alias
-#define I420ToI420Mirror I420Mirror
-
-// I420 mirror.
-LIBYUV_API
-int I420Mirror(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height);
-
-// Alias
-#define I400ToI400Mirror I400Mirror
-
-// I400 mirror. A single plane is mirrored horizontally.
-// Pass negative height to achieve 180 degree rotation.
-LIBYUV_API
-int I400Mirror(const uint8* src_y, int src_stride_y,
- uint8* dst_y, int dst_stride_y,
- int width, int height);
-
-// Alias
-#define ARGBToARGBMirror ARGBMirror
-
-// ARGB mirror.
-LIBYUV_API
-int ARGBMirror(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// Convert NV12 to RGB565.
-LIBYUV_API
-int NV12ToRGB565(const uint8* src_y, int src_stride_y,
- const uint8* src_uv, int src_stride_uv,
- uint8* dst_rgb565, int dst_stride_rgb565,
- int width, int height);
-
-// Convert NV21 to RGB565.
-LIBYUV_API
-int NV21ToRGB565(const uint8* src_y, int src_stride_y,
- const uint8* src_uv, int src_stride_uv,
- uint8* dst_rgb565, int dst_stride_rgb565,
- int width, int height);
-
-// I422ToARGB is in convert_argb.h
-// Convert I422 to BGRA.
-LIBYUV_API
-int I422ToBGRA(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_bgra, int dst_stride_bgra,
- int width, int height);
-
-// Convert I422 to ABGR.
-LIBYUV_API
-int I422ToABGR(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_abgr, int dst_stride_abgr,
- int width, int height);
-
-// Convert I422 to RGBA.
-LIBYUV_API
-int I422ToRGBA(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_rgba, int dst_stride_rgba,
- int width, int height);
-
-// Draw a rectangle into I420.
-LIBYUV_API
-int I420Rect(uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int x, int y, int width, int height,
- int value_y, int value_u, int value_v);
-
-// Draw a rectangle into ARGB.
-LIBYUV_API
-int ARGBRect(uint8* dst_argb, int dst_stride_argb,
- int x, int y, int width, int height, uint32 value);
-
-// Convert ARGB to gray scale ARGB.
-LIBYUV_API
-int ARGBGrayTo(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// Make a rectangle of ARGB gray scale.
-LIBYUV_API
-int ARGBGray(uint8* dst_argb, int dst_stride_argb,
- int x, int y, int width, int height);
-
-// Make a rectangle of ARGB Sepia tone.
-LIBYUV_API
-int ARGBSepia(uint8* dst_argb, int dst_stride_argb,
- int x, int y, int width, int height);
-
-// Apply a matrix rotation to each ARGB pixel.
-// matrix_argb is 4 signed ARGB values. -128 to 127 representing -2 to 2.
-// The first 4 coefficients apply to B, G, R, A and produce B of the output.
-// The next 4 coefficients apply to B, G, R, A and produce G of the output.
-// The next 4 coefficients apply to B, G, R, A and produce R of the output.
-// The last 4 coefficients apply to B, G, R, A and produce A of the output.
-LIBYUV_API
-int ARGBColorMatrix(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- const int8* matrix_argb,
- int width, int height);
-
-// Deprecated. Use ARGBColorMatrix instead.
-// Apply a matrix rotation to each ARGB pixel.
-// matrix_argb is 3 signed ARGB values. -128 to 127 representing -1 to 1.
-// The first 4 coefficients apply to B, G, R, A and produce B of the output.
-// The next 4 coefficients apply to B, G, R, A and produce G of the output.
-// The last 4 coefficients apply to B, G, R, A and produce R of the output.
-LIBYUV_API
-int RGBColorMatrix(uint8* dst_argb, int dst_stride_argb,
- const int8* matrix_rgb,
- int x, int y, int width, int height);
-
-// Apply a color table each ARGB pixel.
-// Table contains 256 ARGB values.
-LIBYUV_API
-int ARGBColorTable(uint8* dst_argb, int dst_stride_argb,
- const uint8* table_argb,
- int x, int y, int width, int height);
-
-// Apply a color table each ARGB pixel but preserve destination alpha.
-// Table contains 256 ARGB values.
-LIBYUV_API
-int RGBColorTable(uint8* dst_argb, int dst_stride_argb,
- const uint8* table_argb,
- int x, int y, int width, int height);
-
-// Apply a luma/color table each ARGB pixel but preserve destination alpha.
-// Table contains 32768 values indexed by [Y][C] where 7 it 7 bit luma from
-// RGB (YJ style) and C is an 8 bit color component (R, G or B).
-LIBYUV_API
-int ARGBLumaColorTable(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- const uint8* luma_rgb_table,
- int width, int height);
-
-// Apply a 3 term polynomial to ARGB values.
-// poly points to a 4x4 matrix. The first row is constants. The 2nd row is
-// coefficients for b, g, r and a. The 3rd row is coefficients for b squared,
-// g squared, r squared and a squared. The 4rd row is coefficients for b to
-// the 3, g to the 3, r to the 3 and a to the 3. The values are summed and
-// result clamped to 0 to 255.
-// A polynomial approximation can be dirived using software such as 'R'.
-
-LIBYUV_API
-int ARGBPolynomial(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- const float* poly,
- int width, int height);
-
-// Quantize a rectangle of ARGB. Alpha unaffected.
-// scale is a 16 bit fractional fixed point scaler between 0 and 65535.
-// interval_size should be a value between 1 and 255.
-// interval_offset should be a value between 0 and 255.
-LIBYUV_API
-int ARGBQuantize(uint8* dst_argb, int dst_stride_argb,
- int scale, int interval_size, int interval_offset,
- int x, int y, int width, int height);
-
-// Copy ARGB to ARGB.
-LIBYUV_API
-int ARGBCopy(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// Copy ARGB to ARGB.
-LIBYUV_API
-int ARGBCopyAlpha(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// Copy ARGB to ARGB.
-LIBYUV_API
-int ARGBCopyYToAlpha(const uint8* src_y, int src_stride_y,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-typedef void (*ARGBBlendRow)(const uint8* src_argb0, const uint8* src_argb1,
- uint8* dst_argb, int width);
-
-// Get function to Alpha Blend ARGB pixels and store to destination.
-LIBYUV_API
-ARGBBlendRow GetARGBBlend();
-
-// Alpha Blend ARGB images and store to destination.
-// Alpha of destination is set to 255.
-LIBYUV_API
-int ARGBBlend(const uint8* src_argb0, int src_stride_argb0,
- const uint8* src_argb1, int src_stride_argb1,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// Multiply ARGB image by ARGB image. Shifted down by 8. Saturates to 255.
-LIBYUV_API
-int ARGBMultiply(const uint8* src_argb0, int src_stride_argb0,
- const uint8* src_argb1, int src_stride_argb1,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// Add ARGB image with ARGB image. Saturates to 255.
-LIBYUV_API
-int ARGBAdd(const uint8* src_argb0, int src_stride_argb0,
- const uint8* src_argb1, int src_stride_argb1,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// Subtract ARGB image (argb1) from ARGB image (argb0). Saturates to 0.
-LIBYUV_API
-int ARGBSubtract(const uint8* src_argb0, int src_stride_argb0,
- const uint8* src_argb1, int src_stride_argb1,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// Convert I422 to YUY2.
-LIBYUV_API
-int I422ToYUY2(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_frame, int dst_stride_frame,
- int width, int height);
-
-// Convert I422 to UYVY.
-LIBYUV_API
-int I422ToUYVY(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_frame, int dst_stride_frame,
- int width, int height);
-
-// Convert unattentuated ARGB to preattenuated ARGB.
-LIBYUV_API
-int ARGBAttenuate(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// Convert preattentuated ARGB to unattenuated ARGB.
-LIBYUV_API
-int ARGBUnattenuate(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// Convert MJPG to ARGB.
-LIBYUV_API
-int MJPGToARGB(const uint8* sample, size_t sample_size,
- uint8* argb, int argb_stride,
- int w, int h, int dw, int dh);
-
-// Internal function - do not call directly.
-// Computes table of cumulative sum for image where the value is the sum
-// of all values above and to the left of the entry. Used by ARGBBlur.
-LIBYUV_API
-int ARGBComputeCumulativeSum(const uint8* src_argb, int src_stride_argb,
- int32* dst_cumsum, int dst_stride32_cumsum,
- int width, int height);
-
-// Blur ARGB image.
-// dst_cumsum table of width * (height + 1) * 16 bytes aligned to
-// 16 byte boundary.
-// dst_stride32_cumsum is number of ints in a row (width * 4).
-// radius is number of pixels around the center. e.g. 1 = 3x3. 2=5x5.
-// Blur is optimized for radius of 5 (11x11) or less.
-LIBYUV_API
-int ARGBBlur(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- int32* dst_cumsum, int dst_stride32_cumsum,
- int width, int height, int radius);
-
-// Multiply ARGB image by ARGB value.
-LIBYUV_API
-int ARGBShade(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height, uint32 value);
-
-// Interpolate between two ARGB images using specified amount of interpolation
-// (0 to 255) and store to destination.
-// 'interpolation' is specified as 8 bit fraction where 0 means 100% src_argb0
-// and 255 means 1% src_argb0 and 99% src_argb1.
-// Internally uses ARGBScale bilinear filtering.
-// Caveat: This function will write up to 16 bytes beyond the end of dst_argb.
-LIBYUV_API
-int ARGBInterpolate(const uint8* src_argb0, int src_stride_argb0,
- const uint8* src_argb1, int src_stride_argb1,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height, int interpolation);
-
-#if defined(__pnacl__) || defined(__CLR_VER) || defined(COVERAGE_ENABLED) || \
- defined(TARGET_IPHONE_SIMULATOR)
-#define LIBYUV_DISABLE_X86
-#endif
-
-// Row functions for copying a pixels from a source with a slope to a row
-// of destination. Useful for scaling, rotation, mirror, texture mapping.
-LIBYUV_API
-void ARGBAffineRow_C(const uint8* src_argb, int src_argb_stride,
- uint8* dst_argb, const float* uv_dudv, int width);
-// The following are available on all x86 platforms:
-#if !defined(LIBYUV_DISABLE_X86) && \
- (defined(_M_IX86) || defined(__x86_64__) || defined(__i386__))
-LIBYUV_API
-void ARGBAffineRow_SSE2(const uint8* src_argb, int src_argb_stride,
- uint8* dst_argb, const float* uv_dudv, int width);
-#define HAS_ARGBAFFINEROW_SSE2
-#endif // LIBYUV_DISABLE_X86
-
-// Shuffle ARGB channel order. e.g. BGRA to ARGB.
-// shuffler is 16 bytes and must be aligned.
-LIBYUV_API
-int ARGBShuffle(const uint8* src_bgra, int src_stride_bgra,
- uint8* dst_argb, int dst_stride_argb,
- const uint8* shuffler, int width, int height);
-
-// Sobel ARGB effect with planar output.
-LIBYUV_API
-int ARGBSobelToPlane(const uint8* src_argb, int src_stride_argb,
- uint8* dst_y, int dst_stride_y,
- int width, int height);
-
-// Sobel ARGB effect.
-LIBYUV_API
-int ARGBSobel(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-// Sobel ARGB effect w/ Sobel X, Sobel, Sobel Y in ARGB.
-LIBYUV_API
-int ARGBSobelXY(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height);
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
-
-#endif // INCLUDE_LIBYUV_PLANAR_FUNCTIONS_H_ NOLINT
diff --git a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/rotate.h b/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/rotate.h
deleted file mode 100755
index 8af60b8955..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/rotate.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef INCLUDE_LIBYUV_ROTATE_H_ // NOLINT
-#define INCLUDE_LIBYUV_ROTATE_H_
-
-#include "libyuv/basic_types.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// Supported rotation.
-typedef enum RotationMode {
- kRotate0 = 0, // No rotation.
- kRotate90 = 90, // Rotate 90 degrees clockwise.
- kRotate180 = 180, // Rotate 180 degrees.
- kRotate270 = 270, // Rotate 270 degrees clockwise.
-
- // Deprecated.
- kRotateNone = 0,
- kRotateClockwise = 90,
- kRotateCounterClockwise = 270,
-} RotationModeEnum;
-
-// Rotate I420 frame.
-LIBYUV_API
-int I420Rotate(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int src_width, int src_height, enum RotationMode mode);
-
-// Rotate NV12 input and store in I420.
-LIBYUV_API
-int NV12ToI420Rotate(const uint8* src_y, int src_stride_y,
- const uint8* src_uv, int src_stride_uv,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int src_width, int src_height, enum RotationMode mode);
-
-// Rotate a plane by 0, 90, 180, or 270.
-LIBYUV_API
-int RotatePlane(const uint8* src, int src_stride,
- uint8* dst, int dst_stride,
- int src_width, int src_height, enum RotationMode mode);
-
-// Rotate planes by 90, 180, 270. Deprecated.
-LIBYUV_API
-void RotatePlane90(const uint8* src, int src_stride,
- uint8* dst, int dst_stride,
- int width, int height);
-
-LIBYUV_API
-void RotatePlane180(const uint8* src, int src_stride,
- uint8* dst, int dst_stride,
- int width, int height);
-
-LIBYUV_API
-void RotatePlane270(const uint8* src, int src_stride,
- uint8* dst, int dst_stride,
- int width, int height);
-
-LIBYUV_API
-void RotateUV90(const uint8* src, int src_stride,
- uint8* dst_a, int dst_stride_a,
- uint8* dst_b, int dst_stride_b,
- int width, int height);
-
-// Rotations for when U and V are interleaved.
-// These functions take one input pointer and
-// split the data into two buffers while
-// rotating them. Deprecated.
-LIBYUV_API
-void RotateUV180(const uint8* src, int src_stride,
- uint8* dst_a, int dst_stride_a,
- uint8* dst_b, int dst_stride_b,
- int width, int height);
-
-LIBYUV_API
-void RotateUV270(const uint8* src, int src_stride,
- uint8* dst_a, int dst_stride_a,
- uint8* dst_b, int dst_stride_b,
- int width, int height);
-
-// The 90 and 270 functions are based on transposes.
-// Doing a transpose with reversing the read/write
-// order will result in a rotation by +- 90 degrees.
-// Deprecated.
-LIBYUV_API
-void TransposePlane(const uint8* src, int src_stride,
- uint8* dst, int dst_stride,
- int width, int height);
-
-LIBYUV_API
-void TransposeUV(const uint8* src, int src_stride,
- uint8* dst_a, int dst_stride_a,
- uint8* dst_b, int dst_stride_b,
- int width, int height);
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
-
-#endif // INCLUDE_LIBYUV_ROTATE_H_ NOLINT
diff --git a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/rotate_argb.h b/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/rotate_argb.h
deleted file mode 100755
index 660ff5573e..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/rotate_argb.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2012 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef INCLUDE_LIBYUV_ROTATE_ARGB_H_ // NOLINT
-#define INCLUDE_LIBYUV_ROTATE_ARGB_H_
-
-#include "libyuv/basic_types.h"
-#include "libyuv/rotate.h" // For RotationMode.
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// Rotate ARGB frame
-LIBYUV_API
-int ARGBRotate(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- int src_width, int src_height, enum RotationMode mode);
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
-
-#endif // INCLUDE_LIBYUV_ROTATE_ARGB_H_ NOLINT
diff --git a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/row.h b/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/row.h
deleted file mode 100755
index 757020da86..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/row.h
+++ /dev/null
@@ -1,1694 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef INCLUDE_LIBYUV_ROW_H_ // NOLINT
-#define INCLUDE_LIBYUV_ROW_H_
-
-#include <stdlib.h> // For malloc.
-
-#include "libyuv/basic_types.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-#define IS_ALIGNED(p, a) (!((uintptr_t)(p) & ((a) - 1)))
-
-#ifdef __cplusplus
-#define align_buffer_64(var, size) \
- uint8* var##_mem = reinterpret_cast<uint8*>(malloc((size) + 63)); \
- uint8* var = reinterpret_cast<uint8*> \
- ((reinterpret_cast<intptr_t>(var##_mem) + 63) & ~63)
-#else
-#define align_buffer_64(var, size) \
- uint8* var##_mem = (uint8*)(malloc((size) + 63)); /* NOLINT */ \
- uint8* var = (uint8*)(((intptr_t)(var##_mem) + 63) & ~63) /* NOLINT */
-#endif
-
-#define free_aligned_buffer_64(var) \
- free(var##_mem); \
- var = 0
-
-#if defined(__pnacl__) || defined(__CLR_VER) || defined(COVERAGE_ENABLED) || \
- defined(TARGET_IPHONE_SIMULATOR)
-#define LIBYUV_DISABLE_X86
-#endif
-// True if compiling for SSSE3 as a requirement.
-#if defined(__SSSE3__) || (defined(_M_IX86_FP) && (_M_IX86_FP >= 3))
-#define LIBYUV_SSSE3_ONLY
-#endif
-
-// Enable for NaCL pepper 33 for bundle and AVX2 support.
-// #define NEW_BINUTILS
-
-// The following are available on all x86 platforms:
-#if !defined(LIBYUV_DISABLE_X86) && \
- (defined(_M_IX86) || defined(__x86_64__) || defined(__i386__))
-// Effects:
-#define HAS_ARGBADDROW_SSE2
-#define HAS_ARGBAFFINEROW_SSE2
-#define HAS_ARGBATTENUATEROW_SSSE3
-#define HAS_ARGBBLENDROW_SSSE3
-#define HAS_ARGBCOLORMATRIXROW_SSSE3
-#define HAS_ARGBCOLORTABLEROW_X86
-#define HAS_ARGBCOPYALPHAROW_SSE2
-#define HAS_ARGBCOPYYTOALPHAROW_SSE2
-#define HAS_ARGBGRAYROW_SSSE3
-#define HAS_ARGBLUMACOLORTABLEROW_SSSE3
-#define HAS_ARGBMIRRORROW_SSSE3
-#define HAS_ARGBMULTIPLYROW_SSE2
-#define HAS_ARGBPOLYNOMIALROW_SSE2
-#define HAS_ARGBQUANTIZEROW_SSE2
-#define HAS_ARGBSEPIAROW_SSSE3
-#define HAS_ARGBSHADEROW_SSE2
-#define HAS_ARGBSUBTRACTROW_SSE2
-#define HAS_ARGBTOUVROW_SSSE3
-#define HAS_ARGBUNATTENUATEROW_SSE2
-#define HAS_COMPUTECUMULATIVESUMROW_SSE2
-#define HAS_CUMULATIVESUMTOAVERAGEROW_SSE2
-#define HAS_INTERPOLATEROW_SSE2
-#define HAS_INTERPOLATEROW_SSSE3
-#define HAS_RGBCOLORTABLEROW_X86
-#define HAS_SOBELROW_SSE2
-#define HAS_SOBELTOPLANEROW_SSE2
-#define HAS_SOBELXROW_SSE2
-#define HAS_SOBELXYROW_SSE2
-#define HAS_SOBELYROW_SSE2
-
-// Conversions:
-#define HAS_ABGRTOUVROW_SSSE3
-#define HAS_ABGRTOYROW_SSSE3
-#define HAS_ARGB1555TOARGBROW_SSE2
-#define HAS_ARGB4444TOARGBROW_SSE2
-#define HAS_ARGBSHUFFLEROW_SSE2
-#define HAS_ARGBSHUFFLEROW_SSSE3
-#define HAS_ARGBTOARGB1555ROW_SSE2
-#define HAS_ARGBTOARGB4444ROW_SSE2
-#define HAS_ARGBTOBAYERGGROW_SSE2
-#define HAS_ARGBTOBAYERROW_SSSE3
-#define HAS_ARGBTORAWROW_SSSE3
-#define HAS_ARGBTORGB24ROW_SSSE3
-#define HAS_ARGBTORGB565ROW_SSE2
-#define HAS_ARGBTOUV422ROW_SSSE3
-#define HAS_ARGBTOUV444ROW_SSSE3
-#define HAS_ARGBTOUVJROW_SSSE3
-#define HAS_ARGBTOYJROW_SSSE3
-#define HAS_ARGBTOYROW_SSSE3
-#define HAS_BGRATOUVROW_SSSE3
-#define HAS_BGRATOYROW_SSSE3
-#define HAS_COPYROW_ERMS
-#define HAS_COPYROW_SSE2
-#define HAS_COPYROW_X86
-#define HAS_HALFROW_SSE2
-#define HAS_I400TOARGBROW_SSE2
-#define HAS_I411TOARGBROW_SSSE3
-#define HAS_I422TOARGB1555ROW_SSSE3
-#define HAS_I422TOABGRROW_SSSE3
-#define HAS_I422TOARGB1555ROW_SSSE3
-#define HAS_I422TOARGB4444ROW_SSSE3
-#define HAS_I422TOARGBROW_SSSE3
-#define HAS_I422TOBGRAROW_SSSE3
-#define HAS_I422TORAWROW_SSSE3
-#define HAS_I422TORGB24ROW_SSSE3
-#define HAS_I422TORGB565ROW_SSSE3
-#define HAS_I422TORGBAROW_SSSE3
-#define HAS_I422TOUYVYROW_SSE2
-#define HAS_I422TOYUY2ROW_SSE2
-#define HAS_I444TOARGBROW_SSSE3
-#define HAS_MERGEUVROW_SSE2
-#define HAS_MIRRORROW_SSE2
-#define HAS_MIRRORROW_SSSE3
-#define HAS_MIRRORROW_UV_SSSE3
-#define HAS_MIRRORUVROW_SSSE3
-#define HAS_NV12TOARGBROW_SSSE3
-#define HAS_NV12TORGB565ROW_SSSE3
-#define HAS_NV21TOARGBROW_SSSE3
-#define HAS_NV21TORGB565ROW_SSSE3
-#define HAS_RAWTOARGBROW_SSSE3
-#define HAS_RAWTOYROW_SSSE3
-#define HAS_RGB24TOARGBROW_SSSE3
-#define HAS_RGB24TOYROW_SSSE3
-#define HAS_RGB565TOARGBROW_SSE2
-#define HAS_RGBATOUVROW_SSSE3
-#define HAS_RGBATOYROW_SSSE3
-#define HAS_SETROW_X86
-#define HAS_SPLITUVROW_SSE2
-#define HAS_UYVYTOARGBROW_SSSE3
-#define HAS_UYVYTOUV422ROW_SSE2
-#define HAS_UYVYTOUVROW_SSE2
-#define HAS_UYVYTOYROW_SSE2
-#define HAS_YTOARGBROW_SSE2
-#define HAS_YUY2TOARGBROW_SSSE3
-#define HAS_YUY2TOUV422ROW_SSE2
-#define HAS_YUY2TOUVROW_SSE2
-#define HAS_YUY2TOYROW_SSE2
-#endif
-
-// GCC >= 4.7.0 required for AVX2.
-#if defined(__GNUC__) && (defined(__x86_64__) || defined(__i386__))
-#if (__GNUC__ > 4) || (__GNUC__ == 4 && (__GNUC_MINOR__ >= 7))
-#define GCC_HAS_AVX2 1
-#endif // GNUC >= 4.7
-#endif // __GNUC__
-
-// clang >= 3.4.0 required for AVX2.
-#if defined(__clang__) && (defined(__x86_64__) || defined(__i386__))
-#if (__clang_major__ > 3) || (__clang_major__ == 3 && (__clang_minor__ >= 4))
-#define CLANG_HAS_AVX2 1
-#endif // clang >= 3.4
-#endif // __clang__
-
-// Visual C 2012 required for AVX2.
-#if defined(_M_IX86) && defined(_MSC_VER) && _MSC_VER >= 1700
-#define VISUALC_HAS_AVX2 1
-#endif // VisualStudio >= 2012
-
-// The following are available on all x86 platforms, but
-// require VS2012, clang 3.4 or gcc 4.7.
-// The code supports NaCL but requires a new compiler and validator.
-#if !defined(LIBYUV_DISABLE_X86) && (defined(VISUALC_HAS_AVX2) || \
- defined(CLANG_HAS_AVX2) || defined(GCC_HAS_AVX2))
-// Effects:
-#define HAS_ARGBPOLYNOMIALROW_AVX2
-#define HAS_ARGBSHUFFLEROW_AVX2
-#define HAS_ARGBCOPYALPHAROW_AVX2
-#define HAS_ARGBCOPYYTOALPHAROW_AVX2
-#endif
-
-// The following are require VS2012.
-// TODO(fbarchard): Port to gcc.
-#if !defined(LIBYUV_DISABLE_X86) && defined(VISUALC_HAS_AVX2)
-#define HAS_ARGBTOUVROW_AVX2
-#define HAS_ARGBTOYJROW_AVX2
-#define HAS_ARGBTOYROW_AVX2
-#define HAS_HALFROW_AVX2
-#define HAS_I422TOARGBROW_AVX2
-#define HAS_INTERPOLATEROW_AVX2
-#define HAS_MERGEUVROW_AVX2
-#define HAS_MIRRORROW_AVX2
-#define HAS_SPLITUVROW_AVX2
-#define HAS_UYVYTOUV422ROW_AVX2
-#define HAS_UYVYTOUVROW_AVX2
-#define HAS_UYVYTOYROW_AVX2
-#define HAS_YUY2TOUV422ROW_AVX2
-#define HAS_YUY2TOUVROW_AVX2
-#define HAS_YUY2TOYROW_AVX2
-
-// Effects:
-#define HAS_ARGBADDROW_AVX2
-#define HAS_ARGBATTENUATEROW_AVX2
-#define HAS_ARGBMIRRORROW_AVX2
-#define HAS_ARGBMULTIPLYROW_AVX2
-#define HAS_ARGBSUBTRACTROW_AVX2
-#define HAS_ARGBUNATTENUATEROW_AVX2
-#endif // defined(VISUALC_HAS_AVX2)
-
-// The following are Yasm x86 only:
-// TODO(fbarchard): Port AVX2 to inline.
-#if !defined(LIBYUV_DISABLE_X86) && defined(HAVE_YASM)
- (defined(_M_IX86) || defined(_M_X64) || \
- defined(__x86_64__) || defined(__i386__))
-#define HAS_MERGEUVROW_AVX2
-#define HAS_MERGEUVROW_MMX
-#define HAS_SPLITUVROW_AVX2
-#define HAS_SPLITUVROW_MMX
-#define HAS_UYVYTOYROW_AVX2
-#define HAS_UYVYTOYROW_MMX
-#define HAS_YUY2TOYROW_AVX2
-#define HAS_YUY2TOYROW_MMX
-#endif
-
-// The following are disabled when SSSE3 is available:
-#if !defined(LIBYUV_DISABLE_X86) && \
- (defined(_M_IX86) || defined(__x86_64__) || defined(__i386__)) && \
- !defined(LIBYUV_SSSE3_ONLY)
-#define HAS_ARGBBLENDROW_SSE2
-#define HAS_ARGBATTENUATEROW_SSE2
-#define HAS_MIRRORROW_SSE2
-#endif
-
-// The following are available on Neon platforms:
-#if !defined(LIBYUV_DISABLE_NEON) && \
- (defined(__ARM_NEON__) || defined(LIBYUV_NEON))
-#define HAS_ABGRTOUVROW_NEON
-#define HAS_ABGRTOYROW_NEON
-#define HAS_ARGB1555TOARGBROW_NEON
-#define HAS_ARGB1555TOUVROW_NEON
-#define HAS_ARGB1555TOYROW_NEON
-#define HAS_ARGB4444TOARGBROW_NEON
-#define HAS_ARGB4444TOUVROW_NEON
-#define HAS_ARGB4444TOYROW_NEON
-#define HAS_ARGBTOARGB1555ROW_NEON
-#define HAS_ARGBTOARGB4444ROW_NEON
-#define HAS_ARGBTOBAYERROW_NEON
-#define HAS_ARGBTOBAYERGGROW_NEON
-#define HAS_ARGBTORAWROW_NEON
-#define HAS_ARGBTORGB24ROW_NEON
-#define HAS_ARGBTORGB565ROW_NEON
-#define HAS_ARGBTOUV411ROW_NEON
-#define HAS_ARGBTOUV422ROW_NEON
-#define HAS_ARGBTOUV444ROW_NEON
-#define HAS_ARGBTOUVROW_NEON
-#define HAS_ARGBTOUVJROW_NEON
-#define HAS_ARGBTOYROW_NEON
-#define HAS_ARGBTOYJROW_NEON
-#define HAS_BGRATOUVROW_NEON
-#define HAS_BGRATOYROW_NEON
-#define HAS_COPYROW_NEON
-#define HAS_HALFROW_NEON
-#define HAS_I400TOARGBROW_NEON
-#define HAS_I411TOARGBROW_NEON
-#define HAS_I422TOABGRROW_NEON
-#define HAS_I422TOARGB1555ROW_NEON
-#define HAS_I422TOARGB4444ROW_NEON
-#define HAS_I422TOARGBROW_NEON
-#define HAS_I422TOBGRAROW_NEON
-#define HAS_I422TORAWROW_NEON
-#define HAS_I422TORGB24ROW_NEON
-#define HAS_I422TORGB565ROW_NEON
-#define HAS_I422TORGBAROW_NEON
-#define HAS_I422TOUYVYROW_NEON
-#define HAS_I422TOYUY2ROW_NEON
-#define HAS_I444TOARGBROW_NEON
-#define HAS_MERGEUVROW_NEON
-#define HAS_MIRRORROW_NEON
-#define HAS_MIRRORUVROW_NEON
-#define HAS_NV12TOARGBROW_NEON
-#define HAS_NV12TORGB565ROW_NEON
-#define HAS_NV21TOARGBROW_NEON
-#define HAS_NV21TORGB565ROW_NEON
-#define HAS_RAWTOARGBROW_NEON
-#define HAS_RAWTOUVROW_NEON
-#define HAS_RAWTOYROW_NEON
-#define HAS_RGB24TOARGBROW_NEON
-#define HAS_RGB24TOUVROW_NEON
-#define HAS_RGB24TOYROW_NEON
-#define HAS_RGB565TOARGBROW_NEON
-#define HAS_RGB565TOUVROW_NEON
-#define HAS_RGB565TOYROW_NEON
-#define HAS_RGBATOUVROW_NEON
-#define HAS_RGBATOYROW_NEON
-#define HAS_SETROW_NEON
-#define HAS_SPLITUVROW_NEON
-#define HAS_UYVYTOARGBROW_NEON
-#define HAS_UYVYTOUV422ROW_NEON
-#define HAS_UYVYTOUVROW_NEON
-#define HAS_UYVYTOYROW_NEON
-#define HAS_YTOARGBROW_NEON
-#define HAS_YUY2TOARGBROW_NEON
-#define HAS_YUY2TOUV422ROW_NEON
-#define HAS_YUY2TOUVROW_NEON
-#define HAS_YUY2TOYROW_NEON
-
-// Effects:
-#define HAS_ARGBADDROW_NEON
-#define HAS_ARGBATTENUATEROW_NEON
-#define HAS_ARGBBLENDROW_NEON
-#define HAS_ARGBCOLORMATRIXROW_NEON
-#define HAS_ARGBGRAYROW_NEON
-#define HAS_ARGBMIRRORROW_NEON
-#define HAS_ARGBMULTIPLYROW_NEON
-#define HAS_ARGBQUANTIZEROW_NEON
-#define HAS_ARGBSEPIAROW_NEON
-#define HAS_ARGBSHADEROW_NEON
-#define HAS_ARGBSUBTRACTROW_NEON
-#define HAS_SOBELROW_NEON
-#define HAS_SOBELTOPLANEROW_NEON
-#define HAS_SOBELXYROW_NEON
-#define HAS_SOBELXROW_NEON
-#define HAS_SOBELYROW_NEON
-#define HAS_INTERPOLATEROW_NEON
-#endif
-
-// The following are available on Mips platforms:
-#if !defined(LIBYUV_DISABLE_MIPS) && defined(__mips__)
-#define HAS_COPYROW_MIPS
-#if defined(__mips_dsp) && (__mips_dsp_rev >= 2)
-#define HAS_I422TOABGRROW_MIPS_DSPR2
-#define HAS_I422TOARGBROW_MIPS_DSPR2
-#define HAS_I422TOBGRAROW_MIPS_DSPR2
-#define HAS_INTERPOLATEROWS_MIPS_DSPR2
-#define HAS_MIRRORROW_MIPS_DSPR2
-#define HAS_MIRRORUVROW_MIPS_DSPR2
-#define HAS_SPLITUVROW_MIPS_DSPR2
-#endif
-#endif
-
-#if defined(_MSC_VER) && !defined(__CLR_VER)
-#define SIMD_ALIGNED(var) __declspec(align(16)) var
-typedef __declspec(align(16)) int16 vec16[8];
-typedef __declspec(align(16)) int32 vec32[4];
-typedef __declspec(align(16)) int8 vec8[16];
-typedef __declspec(align(16)) uint16 uvec16[8];
-typedef __declspec(align(16)) uint32 uvec32[4];
-typedef __declspec(align(16)) uint8 uvec8[16];
-typedef __declspec(align(32)) int16 lvec16[16];
-typedef __declspec(align(32)) int32 lvec32[8];
-typedef __declspec(align(32)) int8 lvec8[32];
-typedef __declspec(align(32)) uint16 ulvec16[16];
-typedef __declspec(align(32)) uint32 ulvec32[8];
-typedef __declspec(align(32)) uint8 ulvec8[32];
-
-#elif defined(__GNUC__)
-// Caveat GCC 4.2 to 4.7 have a known issue using vectors with const.
-#define SIMD_ALIGNED(var) var __attribute__((aligned(16)))
-typedef int16 __attribute__((vector_size(16))) vec16;
-typedef int32 __attribute__((vector_size(16))) vec32;
-typedef int8 __attribute__((vector_size(16))) vec8;
-typedef uint16 __attribute__((vector_size(16))) uvec16;
-typedef uint32 __attribute__((vector_size(16))) uvec32;
-typedef uint8 __attribute__((vector_size(16))) uvec8;
-#else
-#define SIMD_ALIGNED(var) var
-typedef int16 vec16[8];
-typedef int32 vec32[4];
-typedef int8 vec8[16];
-typedef uint16 uvec16[8];
-typedef uint32 uvec32[4];
-typedef uint8 uvec8[16];
-#endif
-
-#if defined(__APPLE__) || defined(__x86_64__) || defined(__llvm__)
-#define OMITFP
-#else
-#define OMITFP __attribute__((optimize("omit-frame-pointer")))
-#endif
-
-// NaCL macros for GCC x86 and x64.
-
-// TODO(nfullagar): When pepper_33 toolchain is distributed, default to
-// NEW_BINUTILS and remove all BUNDLEALIGN occurances.
-#if defined(__native_client__)
-#define LABELALIGN ".p2align 5\n"
-#else
-#define LABELALIGN ".p2align 2\n"
-#endif
-#if defined(__native_client__) && defined(__x86_64__)
-#if defined(NEW_BINUTILS)
-#define BUNDLELOCK ".bundle_lock\n"
-#define BUNDLEUNLOCK ".bundle_unlock\n"
-#define BUNDLEALIGN "\n"
-#else
-#define BUNDLELOCK "\n"
-#define BUNDLEUNLOCK "\n"
-#define BUNDLEALIGN ".p2align 5\n"
-#endif
-#define MEMACCESS(base) "%%nacl:(%%r15,%q" #base ")"
-#define MEMACCESS2(offset, base) "%%nacl:" #offset "(%%r15,%q" #base ")"
-#define MEMLEA(offset, base) #offset "(%q" #base ")"
-#define MEMLEA3(offset, index, scale) \
- #offset "(,%q" #index "," #scale ")"
-#define MEMLEA4(offset, base, index, scale) \
- #offset "(%q" #base ",%q" #index "," #scale ")"
-#define MEMMOVESTRING(s, d) "%%nacl:(%q" #s "),%%nacl:(%q" #d "), %%r15"
-#define MEMSTORESTRING(reg, d) "%%" #reg ",%%nacl:(%q" #d "), %%r15"
-#define MEMOPREG(opcode, offset, base, index, scale, reg) \
- BUNDLELOCK \
- "lea " #offset "(%q" #base ",%q" #index "," #scale "),%%r14d\n" \
- #opcode " (%%r15,%%r14),%%" #reg "\n" \
- BUNDLEUNLOCK
-#define MEMOPMEM(opcode, reg, offset, base, index, scale) \
- BUNDLELOCK \
- "lea " #offset "(%q" #base ",%q" #index "," #scale "),%%r14d\n" \
- #opcode " %%" #reg ",(%%r15,%%r14)\n" \
- BUNDLEUNLOCK
-#define MEMOPARG(opcode, offset, base, index, scale, arg) \
- BUNDLELOCK \
- "lea " #offset "(%q" #base ",%q" #index "," #scale "),%%r14d\n" \
- #opcode " (%%r15,%%r14),%" #arg "\n" \
- BUNDLEUNLOCK
-#else
-#define BUNDLEALIGN "\n"
-#define MEMACCESS(base) "(%" #base ")"
-#define MEMACCESS2(offset, base) #offset "(%" #base ")"
-#define MEMLEA(offset, base) #offset "(%" #base ")"
-#define MEMLEA3(offset, index, scale) \
- #offset "(,%" #index "," #scale ")"
-#define MEMLEA4(offset, base, index, scale) \
- #offset "(%" #base ",%" #index "," #scale ")"
-#define MEMMOVESTRING(s, d)
-#define MEMSTORESTRING(reg, d)
-#define MEMOPREG(opcode, offset, base, index, scale, reg) \
- #opcode " " #offset "(%" #base ",%" #index "," #scale "),%%" #reg "\n"
-#define MEMOPMEM(opcode, reg, offset, base, index, scale) \
- #opcode " %%" #reg ","#offset "(%" #base ",%" #index "," #scale ")\n"
-#define MEMOPARG(opcode, offset, base, index, scale, arg) \
- #opcode " " #offset "(%" #base ",%" #index "," #scale "),%" #arg "\n"
-#endif
-
-void I444ToARGBRow_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I422ToARGBRow_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I411ToARGBRow_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I422ToBGRARow_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_bgra,
- int width);
-void I422ToABGRRow_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_abgr,
- int width);
-void I422ToRGBARow_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_rgba,
- int width);
-void I422ToRGB24Row_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_rgb24,
- int width);
-void I422ToRAWRow_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_raw,
- int width);
-void I422ToRGB565Row_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_rgb565,
- int width);
-void I422ToARGB1555Row_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb1555,
- int width);
-void I422ToARGB4444Row_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb4444,
- int width);
-void NV12ToARGBRow_NEON(const uint8* src_y,
- const uint8* src_uv,
- uint8* dst_argb,
- int width);
-void NV21ToARGBRow_NEON(const uint8* src_y,
- const uint8* src_vu,
- uint8* dst_argb,
- int width);
-void NV12ToRGB565Row_NEON(const uint8* src_y,
- const uint8* src_uv,
- uint8* dst_rgb565,
- int width);
-void NV21ToRGB565Row_NEON(const uint8* src_y,
- const uint8* src_vu,
- uint8* dst_rgb565,
- int width);
-void YUY2ToARGBRow_NEON(const uint8* src_yuy2,
- uint8* dst_argb,
- int width);
-void UYVYToARGBRow_NEON(const uint8* src_uyvy,
- uint8* dst_argb,
- int width);
-
-void ARGBToYRow_AVX2(const uint8* src_argb, uint8* dst_y, int pix);
-void ARGBToYRow_Any_AVX2(const uint8* src_argb, uint8* dst_y, int pix);
-void ARGBToYRow_SSSE3(const uint8* src_argb, uint8* dst_y, int pix);
-void ARGBToYJRow_AVX2(const uint8* src_argb, uint8* dst_y, int pix);
-void ARGBToYJRow_Any_AVX2(const uint8* src_argb, uint8* dst_y, int pix);
-void ARGBToYJRow_SSSE3(const uint8* src_argb, uint8* dst_y, int pix);
-void BGRAToYRow_SSSE3(const uint8* src_bgra, uint8* dst_y, int pix);
-void ABGRToYRow_SSSE3(const uint8* src_abgr, uint8* dst_y, int pix);
-void RGBAToYRow_SSSE3(const uint8* src_rgba, uint8* dst_y, int pix);
-void RGB24ToYRow_SSSE3(const uint8* src_rgb24, uint8* dst_y, int pix);
-void RAWToYRow_SSSE3(const uint8* src_raw, uint8* dst_y, int pix);
-void ARGBToYRow_Unaligned_SSSE3(const uint8* src_argb, uint8* dst_y, int pix);
-void ARGBToYJRow_Unaligned_SSSE3(const uint8* src_argb, uint8* dst_y, int pix);
-void BGRAToYRow_Unaligned_SSSE3(const uint8* src_bgra, uint8* dst_y, int pix);
-void ABGRToYRow_Unaligned_SSSE3(const uint8* src_abgr, uint8* dst_y, int pix);
-void RGBAToYRow_Unaligned_SSSE3(const uint8* src_rgba, uint8* dst_y, int pix);
-void RGB24ToYRow_Unaligned_SSSE3(const uint8* src_rgb24, uint8* dst_y, int pix);
-void RAWToYRow_Unaligned_SSSE3(const uint8* src_raw, uint8* dst_y, int pix);
-void ARGBToYRow_NEON(const uint8* src_argb, uint8* dst_y, int pix);
-void ARGBToYJRow_NEON(const uint8* src_argb, uint8* dst_y, int pix);
-void ARGBToUV444Row_NEON(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
- int pix);
-void ARGBToUV422Row_NEON(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
- int pix);
-void ARGBToUV411Row_NEON(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
- int pix);
-void ARGBToUVRow_NEON(const uint8* src_argb, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int pix);
-void ARGBToUVJRow_NEON(const uint8* src_argb, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int pix);
-void BGRAToUVRow_NEON(const uint8* src_bgra, int src_stride_bgra,
- uint8* dst_u, uint8* dst_v, int pix);
-void ABGRToUVRow_NEON(const uint8* src_abgr, int src_stride_abgr,
- uint8* dst_u, uint8* dst_v, int pix);
-void RGBAToUVRow_NEON(const uint8* src_rgba, int src_stride_rgba,
- uint8* dst_u, uint8* dst_v, int pix);
-void RGB24ToUVRow_NEON(const uint8* src_rgb24, int src_stride_rgb24,
- uint8* dst_u, uint8* dst_v, int pix);
-void RAWToUVRow_NEON(const uint8* src_raw, int src_stride_raw,
- uint8* dst_u, uint8* dst_v, int pix);
-void RGB565ToUVRow_NEON(const uint8* src_rgb565, int src_stride_rgb565,
- uint8* dst_u, uint8* dst_v, int pix);
-void ARGB1555ToUVRow_NEON(const uint8* src_argb1555, int src_stride_argb1555,
- uint8* dst_u, uint8* dst_v, int pix);
-void ARGB4444ToUVRow_NEON(const uint8* src_argb4444, int src_stride_argb4444,
- uint8* dst_u, uint8* dst_v, int pix);
-void BGRAToYRow_NEON(const uint8* src_bgra, uint8* dst_y, int pix);
-void ABGRToYRow_NEON(const uint8* src_abgr, uint8* dst_y, int pix);
-void RGBAToYRow_NEON(const uint8* src_rgba, uint8* dst_y, int pix);
-void RGB24ToYRow_NEON(const uint8* src_rgb24, uint8* dst_y, int pix);
-void RAWToYRow_NEON(const uint8* src_raw, uint8* dst_y, int pix);
-void RGB565ToYRow_NEON(const uint8* src_rgb565, uint8* dst_y, int pix);
-void ARGB1555ToYRow_NEON(const uint8* src_argb1555, uint8* dst_y, int pix);
-void ARGB4444ToYRow_NEON(const uint8* src_argb4444, uint8* dst_y, int pix);
-void ARGBToYRow_C(const uint8* src_argb, uint8* dst_y, int pix);
-void ARGBToYJRow_C(const uint8* src_argb, uint8* dst_y, int pix);
-void BGRAToYRow_C(const uint8* src_bgra, uint8* dst_y, int pix);
-void ABGRToYRow_C(const uint8* src_abgr, uint8* dst_y, int pix);
-void RGBAToYRow_C(const uint8* src_rgba, uint8* dst_y, int pix);
-void RGB24ToYRow_C(const uint8* src_rgb24, uint8* dst_y, int pix);
-void RAWToYRow_C(const uint8* src_raw, uint8* dst_y, int pix);
-void RGB565ToYRow_C(const uint8* src_rgb565, uint8* dst_y, int pix);
-void ARGB1555ToYRow_C(const uint8* src_argb1555, uint8* dst_y, int pix);
-void ARGB4444ToYRow_C(const uint8* src_argb4444, uint8* dst_y, int pix);
-void ARGBToYRow_Any_SSSE3(const uint8* src_argb, uint8* dst_y, int pix);
-void ARGBToYJRow_Any_SSSE3(const uint8* src_argb, uint8* dst_y, int pix);
-void BGRAToYRow_Any_SSSE3(const uint8* src_bgra, uint8* dst_y, int pix);
-void ABGRToYRow_Any_SSSE3(const uint8* src_abgr, uint8* dst_y, int pix);
-void RGBAToYRow_Any_SSSE3(const uint8* src_rgba, uint8* dst_y, int pix);
-void RGB24ToYRow_Any_SSSE3(const uint8* src_rgb24, uint8* dst_y, int pix);
-void RAWToYRow_Any_SSSE3(const uint8* src_raw, uint8* dst_y, int pix);
-void ARGBToYRow_Any_NEON(const uint8* src_argb, uint8* dst_y, int pix);
-void ARGBToYJRow_Any_NEON(const uint8* src_argb, uint8* dst_y, int pix);
-void BGRAToYRow_Any_NEON(const uint8* src_bgra, uint8* dst_y, int pix);
-void ABGRToYRow_Any_NEON(const uint8* src_abgr, uint8* dst_y, int pix);
-void RGBAToYRow_Any_NEON(const uint8* src_rgba, uint8* dst_y, int pix);
-void RGB24ToYRow_Any_NEON(const uint8* src_rgb24, uint8* dst_y, int pix);
-void RAWToYRow_Any_NEON(const uint8* src_raw, uint8* dst_y, int pix);
-void RGB565ToYRow_Any_NEON(const uint8* src_rgb565, uint8* dst_y, int pix);
-void ARGB1555ToYRow_Any_NEON(const uint8* src_argb1555, uint8* dst_y, int pix);
-void ARGB4444ToYRow_Any_NEON(const uint8* src_argb4444, uint8* dst_y, int pix);
-
-void ARGBToUVRow_AVX2(const uint8* src_argb, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width);
-void ARGBToUVRow_Any_AVX2(const uint8* src_argb, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width);
-void ARGBToUVRow_SSSE3(const uint8* src_argb, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width);
-void ARGBToUVJRow_SSSE3(const uint8* src_argb, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width);
-void BGRAToUVRow_SSSE3(const uint8* src_bgra, int src_stride_bgra,
- uint8* dst_u, uint8* dst_v, int width);
-void ABGRToUVRow_SSSE3(const uint8* src_abgr, int src_stride_abgr,
- uint8* dst_u, uint8* dst_v, int width);
-void RGBAToUVRow_SSSE3(const uint8* src_rgba, int src_stride_rgba,
- uint8* dst_u, uint8* dst_v, int width);
-void ARGBToUVRow_Unaligned_SSSE3(const uint8* src_argb, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width);
-void ARGBToUVJRow_Unaligned_SSSE3(const uint8* src_argb, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width);
-void BGRAToUVRow_Unaligned_SSSE3(const uint8* src_bgra, int src_stride_bgra,
- uint8* dst_u, uint8* dst_v, int width);
-void ABGRToUVRow_Unaligned_SSSE3(const uint8* src_abgr, int src_stride_abgr,
- uint8* dst_u, uint8* dst_v, int width);
-void RGBAToUVRow_Unaligned_SSSE3(const uint8* src_rgba, int src_stride_rgba,
- uint8* dst_u, uint8* dst_v, int width);
-void ARGBToUVRow_Any_SSSE3(const uint8* src_argb, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width);
-void ARGBToUVJRow_Any_SSSE3(const uint8* src_argb, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width);
-void BGRAToUVRow_Any_SSSE3(const uint8* src_bgra, int src_stride_bgra,
- uint8* dst_u, uint8* dst_v, int width);
-void ABGRToUVRow_Any_SSSE3(const uint8* src_abgr, int src_stride_abgr,
- uint8* dst_u, uint8* dst_v, int width);
-void RGBAToUVRow_Any_SSSE3(const uint8* src_rgba, int src_stride_rgba,
- uint8* dst_u, uint8* dst_v, int width);
-void ARGBToUV444Row_Any_NEON(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
- int pix);
-void ARGBToUV422Row_Any_NEON(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
- int pix);
-void ARGBToUV411Row_Any_NEON(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
- int pix);
-void ARGBToUVRow_Any_NEON(const uint8* src_argb, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int pix);
-void ARGBToUVJRow_Any_NEON(const uint8* src_argb, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int pix);
-void BGRAToUVRow_Any_NEON(const uint8* src_bgra, int src_stride_bgra,
- uint8* dst_u, uint8* dst_v, int pix);
-void ABGRToUVRow_Any_NEON(const uint8* src_abgr, int src_stride_abgr,
- uint8* dst_u, uint8* dst_v, int pix);
-void RGBAToUVRow_Any_NEON(const uint8* src_rgba, int src_stride_rgba,
- uint8* dst_u, uint8* dst_v, int pix);
-void RGB24ToUVRow_Any_NEON(const uint8* src_rgb24, int src_stride_rgb24,
- uint8* dst_u, uint8* dst_v, int pix);
-void RAWToUVRow_Any_NEON(const uint8* src_raw, int src_stride_raw,
- uint8* dst_u, uint8* dst_v, int pix);
-void RGB565ToUVRow_Any_NEON(const uint8* src_rgb565, int src_stride_rgb565,
- uint8* dst_u, uint8* dst_v, int pix);
-void ARGB1555ToUVRow_Any_NEON(const uint8* src_argb1555,
- int src_stride_argb1555,
- uint8* dst_u, uint8* dst_v, int pix);
-void ARGB4444ToUVRow_Any_NEON(const uint8* src_argb4444,
- int src_stride_argb4444,
- uint8* dst_u, uint8* dst_v, int pix);
-void ARGBToUVRow_C(const uint8* src_argb, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width);
-void ARGBToUVJRow_C(const uint8* src_argb, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width);
-void BGRAToUVRow_C(const uint8* src_bgra, int src_stride_bgra,
- uint8* dst_u, uint8* dst_v, int width);
-void ABGRToUVRow_C(const uint8* src_abgr, int src_stride_abgr,
- uint8* dst_u, uint8* dst_v, int width);
-void RGBAToUVRow_C(const uint8* src_rgba, int src_stride_rgba,
- uint8* dst_u, uint8* dst_v, int width);
-void RGB24ToUVRow_C(const uint8* src_rgb24, int src_stride_rgb24,
- uint8* dst_u, uint8* dst_v, int width);
-void RAWToUVRow_C(const uint8* src_raw, int src_stride_raw,
- uint8* dst_u, uint8* dst_v, int width);
-void RGB565ToUVRow_C(const uint8* src_rgb565, int src_stride_rgb565,
- uint8* dst_u, uint8* dst_v, int width);
-void ARGB1555ToUVRow_C(const uint8* src_argb1555, int src_stride_argb1555,
- uint8* dst_u, uint8* dst_v, int width);
-void ARGB4444ToUVRow_C(const uint8* src_argb4444, int src_stride_argb4444,
- uint8* dst_u, uint8* dst_v, int width);
-
-void ARGBToUV444Row_SSSE3(const uint8* src_argb,
- uint8* dst_u, uint8* dst_v, int width);
-void ARGBToUV444Row_Unaligned_SSSE3(const uint8* src_argb,
- uint8* dst_u, uint8* dst_v, int width);
-void ARGBToUV444Row_Any_SSSE3(const uint8* src_argb,
- uint8* dst_u, uint8* dst_v, int width);
-
-void ARGBToUV422Row_SSSE3(const uint8* src_argb,
- uint8* dst_u, uint8* dst_v, int width);
-void ARGBToUV422Row_Unaligned_SSSE3(const uint8* src_argb,
- uint8* dst_u, uint8* dst_v, int width);
-void ARGBToUV422Row_Any_SSSE3(const uint8* src_argb,
- uint8* dst_u, uint8* dst_v, int width);
-
-void ARGBToUV444Row_C(const uint8* src_argb,
- uint8* dst_u, uint8* dst_v, int width);
-void ARGBToUV422Row_C(const uint8* src_argb,
- uint8* dst_u, uint8* dst_v, int width);
-void ARGBToUV411Row_C(const uint8* src_argb,
- uint8* dst_u, uint8* dst_v, int width);
-
-void MirrorRow_AVX2(const uint8* src, uint8* dst, int width);
-void MirrorRow_SSSE3(const uint8* src, uint8* dst, int width);
-void MirrorRow_SSE2(const uint8* src, uint8* dst, int width);
-void MirrorRow_NEON(const uint8* src, uint8* dst, int width);
-void MirrorRow_MIPS_DSPR2(const uint8* src, uint8* dst, int width);
-void MirrorRow_C(const uint8* src, uint8* dst, int width);
-
-void MirrorUVRow_SSSE3(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
- int width);
-void MirrorUVRow_NEON(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
- int width);
-void MirrorUVRow_MIPS_DSPR2(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
- int width);
-void MirrorUVRow_C(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
- int width);
-
-void ARGBMirrorRow_AVX2(const uint8* src, uint8* dst, int width);
-void ARGBMirrorRow_SSSE3(const uint8* src, uint8* dst, int width);
-void ARGBMirrorRow_NEON(const uint8* src, uint8* dst, int width);
-void ARGBMirrorRow_C(const uint8* src, uint8* dst, int width);
-
-void SplitUVRow_C(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int pix);
-void SplitUVRow_SSE2(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int pix);
-void SplitUVRow_AVX2(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int pix);
-void SplitUVRow_NEON(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int pix);
-void SplitUVRow_MIPS_DSPR2(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
- int pix);
-void SplitUVRow_Unaligned_SSE2(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
- int pix);
-void SplitUVRow_Unaligned_MIPS_DSPR2(const uint8* src_uv, uint8* dst_u,
- uint8* dst_v, int pix);
-void SplitUVRow_Any_SSE2(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
- int pix);
-void SplitUVRow_Any_AVX2(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
- int pix);
-void SplitUVRow_Any_NEON(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
- int pix);
-void SplitUVRow_Any_MIPS_DSPR2(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
- int pix);
-
-void MergeUVRow_C(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
- int width);
-void MergeUVRow_SSE2(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
- int width);
-void MergeUVRow_AVX2(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
- int width);
-void MergeUVRow_NEON(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
- int width);
-void MergeUVRow_Unaligned_SSE2(const uint8* src_u, const uint8* src_v,
- uint8* dst_uv, int width);
-void MergeUVRow_Any_SSE2(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
- int width);
-void MergeUVRow_Any_AVX2(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
- int width);
-void MergeUVRow_Any_NEON(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
- int width);
-
-void CopyRow_SSE2(const uint8* src, uint8* dst, int count);
-void CopyRow_ERMS(const uint8* src, uint8* dst, int count);
-void CopyRow_X86(const uint8* src, uint8* dst, int count);
-void CopyRow_NEON(const uint8* src, uint8* dst, int count);
-void CopyRow_MIPS(const uint8* src, uint8* dst, int count);
-void CopyRow_C(const uint8* src, uint8* dst, int count);
-
-void ARGBCopyAlphaRow_C(const uint8* src_argb, uint8* dst_argb, int width);
-void ARGBCopyAlphaRow_SSE2(const uint8* src_argb, uint8* dst_argb, int width);
-void ARGBCopyAlphaRow_AVX2(const uint8* src_argb, uint8* dst_argb, int width);
-
-void ARGBCopyYToAlphaRow_C(const uint8* src_y, uint8* dst_argb, int width);
-void ARGBCopyYToAlphaRow_SSE2(const uint8* src_y, uint8* dst_argb, int width);
-void ARGBCopyYToAlphaRow_AVX2(const uint8* src_y, uint8* dst_argb, int width);
-
-void SetRow_X86(uint8* dst, uint32 v32, int count);
-void ARGBSetRows_X86(uint8* dst, uint32 v32, int width,
- int dst_stride, int height);
-void SetRow_NEON(uint8* dst, uint32 v32, int count);
-void ARGBSetRows_NEON(uint8* dst, uint32 v32, int width,
- int dst_stride, int height);
-void SetRow_C(uint8* dst, uint32 v32, int count);
-void ARGBSetRows_C(uint8* dst, uint32 v32, int width, int dst_stride,
- int height);
-
-// ARGBShufflers for BGRAToARGB etc.
-void ARGBShuffleRow_C(const uint8* src_argb, uint8* dst_argb,
- const uint8* shuffler, int pix);
-void ARGBShuffleRow_SSE2(const uint8* src_argb, uint8* dst_argb,
- const uint8* shuffler, int pix);
-void ARGBShuffleRow_SSSE3(const uint8* src_argb, uint8* dst_argb,
- const uint8* shuffler, int pix);
-void ARGBShuffleRow_AVX2(const uint8* src_argb, uint8* dst_argb,
- const uint8* shuffler, int pix);
-void ARGBShuffleRow_NEON(const uint8* src_argb, uint8* dst_argb,
- const uint8* shuffler, int pix);
-void ARGBShuffleRow_Unaligned_SSSE3(const uint8* src_argb, uint8* dst_argb,
- const uint8* shuffler, int pix);
-void ARGBShuffleRow_Any_SSE2(const uint8* src_argb, uint8* dst_argb,
- const uint8* shuffler, int pix);
-void ARGBShuffleRow_Any_SSSE3(const uint8* src_argb, uint8* dst_argb,
- const uint8* shuffler, int pix);
-void ARGBShuffleRow_Any_AVX2(const uint8* src_argb, uint8* dst_argb,
- const uint8* shuffler, int pix);
-void ARGBShuffleRow_Any_NEON(const uint8* src_argb, uint8* dst_argb,
- const uint8* shuffler, int pix);
-
-void RGB24ToARGBRow_SSSE3(const uint8* src_rgb24, uint8* dst_argb, int pix);
-void RAWToARGBRow_SSSE3(const uint8* src_raw, uint8* dst_argb, int pix);
-void RGB565ToARGBRow_SSE2(const uint8* src_rgb565, uint8* dst_argb, int pix);
-void ARGB1555ToARGBRow_SSE2(const uint8* src_argb1555, uint8* dst_argb,
- int pix);
-void ARGB4444ToARGBRow_SSE2(const uint8* src_argb4444, uint8* dst_argb,
- int pix);
-
-void RGB24ToARGBRow_NEON(const uint8* src_rgb24, uint8* dst_argb, int pix);
-void RAWToARGBRow_NEON(const uint8* src_raw, uint8* dst_argb, int pix);
-void RGB565ToARGBRow_NEON(const uint8* src_rgb565, uint8* dst_argb, int pix);
-void ARGB1555ToARGBRow_NEON(const uint8* src_argb1555, uint8* dst_argb,
- int pix);
-void ARGB4444ToARGBRow_NEON(const uint8* src_argb4444, uint8* dst_argb,
- int pix);
-void RGB24ToARGBRow_C(const uint8* src_rgb24, uint8* dst_argb, int pix);
-void RAWToARGBRow_C(const uint8* src_raw, uint8* dst_argb, int pix);
-void RGB565ToARGBRow_C(const uint8* src_rgb, uint8* dst_argb, int pix);
-void ARGB1555ToARGBRow_C(const uint8* src_argb, uint8* dst_argb, int pix);
-void ARGB4444ToARGBRow_C(const uint8* src_argb, uint8* dst_argb, int pix);
-void RGB24ToARGBRow_Any_SSSE3(const uint8* src_rgb24, uint8* dst_argb, int pix);
-void RAWToARGBRow_Any_SSSE3(const uint8* src_raw, uint8* dst_argb, int pix);
-void RGB565ToARGBRow_Any_SSE2(const uint8* src_rgb565, uint8* dst_argb,
- int pix);
-void ARGB1555ToARGBRow_Any_SSE2(const uint8* src_argb1555, uint8* dst_argb,
- int pix);
-void ARGB4444ToARGBRow_Any_SSE2(const uint8* src_argb4444, uint8* dst_argb,
- int pix);
-void RGB24ToARGBRow_Any_NEON(const uint8* src_rgb24, uint8* dst_argb, int pix);
-void RAWToARGBRow_Any_NEON(const uint8* src_raw, uint8* dst_argb, int pix);
-void RGB565ToARGBRow_Any_NEON(const uint8* src_rgb565, uint8* dst_argb,
- int pix);
-void ARGB1555ToARGBRow_Any_NEON(const uint8* src_argb1555, uint8* dst_argb,
- int pix);
-void ARGB4444ToARGBRow_Any_NEON(const uint8* src_argb4444, uint8* dst_argb,
- int pix);
-
-void ARGBToRGB24Row_SSSE3(const uint8* src_argb, uint8* dst_rgb, int pix);
-void ARGBToRAWRow_SSSE3(const uint8* src_argb, uint8* dst_rgb, int pix);
-void ARGBToRGB565Row_SSE2(const uint8* src_argb, uint8* dst_rgb, int pix);
-void ARGBToARGB1555Row_SSE2(const uint8* src_argb, uint8* dst_rgb, int pix);
-void ARGBToARGB4444Row_SSE2(const uint8* src_argb, uint8* dst_rgb, int pix);
-
-void ARGBToRGB24Row_NEON(const uint8* src_argb, uint8* dst_rgb, int pix);
-void ARGBToRAWRow_NEON(const uint8* src_argb, uint8* dst_rgb, int pix);
-void ARGBToRGB565Row_NEON(const uint8* src_argb, uint8* dst_rgb, int pix);
-void ARGBToARGB1555Row_NEON(const uint8* src_argb, uint8* dst_rgb, int pix);
-void ARGBToARGB4444Row_NEON(const uint8* src_argb, uint8* dst_rgb, int pix);
-
-void ARGBToRGBARow_C(const uint8* src_argb, uint8* dst_rgb, int pix);
-void ARGBToRGB24Row_C(const uint8* src_argb, uint8* dst_rgb, int pix);
-void ARGBToRAWRow_C(const uint8* src_argb, uint8* dst_rgb, int pix);
-void ARGBToRGB565Row_C(const uint8* src_argb, uint8* dst_rgb, int pix);
-void ARGBToARGB1555Row_C(const uint8* src_argb, uint8* dst_rgb, int pix);
-void ARGBToARGB4444Row_C(const uint8* src_argb, uint8* dst_rgb, int pix);
-
-void I400ToARGBRow_SSE2(const uint8* src_y, uint8* dst_argb, int pix);
-void I400ToARGBRow_Unaligned_SSE2(const uint8* src_y, uint8* dst_argb, int pix);
-void I400ToARGBRow_NEON(const uint8* src_y, uint8* dst_argb, int pix);
-void I400ToARGBRow_C(const uint8* src_y, uint8* dst_argb, int pix);
-void I400ToARGBRow_Any_SSE2(const uint8* src_y, uint8* dst_argb, int pix);
-void I400ToARGBRow_Any_NEON(const uint8* src_y, uint8* dst_argb, int pix);
-
-void I444ToARGBRow_C(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I422ToARGBRow_C(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I411ToARGBRow_C(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void NV12ToARGBRow_C(const uint8* src_y,
- const uint8* src_uv,
- uint8* dst_argb,
- int width);
-void NV21ToRGB565Row_C(const uint8* src_y,
- const uint8* src_vu,
- uint8* dst_argb,
- int width);
-void NV12ToRGB565Row_C(const uint8* src_y,
- const uint8* src_uv,
- uint8* dst_argb,
- int width);
-void NV21ToARGBRow_C(const uint8* src_y,
- const uint8* src_vu,
- uint8* dst_argb,
- int width);
-void YUY2ToARGBRow_C(const uint8* src_yuy2,
- uint8* dst_argb,
- int width);
-void UYVYToARGBRow_C(const uint8* src_uyvy,
- uint8* dst_argb,
- int width);
-void I422ToBGRARow_C(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_bgra,
- int width);
-void I422ToABGRRow_C(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_abgr,
- int width);
-void I422ToRGBARow_C(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_rgba,
- int width);
-void I422ToRGB24Row_C(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_rgb24,
- int width);
-void I422ToRAWRow_C(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_raw,
- int width);
-void I422ToARGB4444Row_C(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb4444,
- int width);
-void I422ToARGB1555Row_C(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb4444,
- int width);
-void I422ToRGB565Row_C(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_rgb565,
- int width);
-void YToARGBRow_C(const uint8* src_y,
- uint8* dst_argb,
- int width);
-void I422ToARGBRow_AVX2(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I444ToARGBRow_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I422ToARGBRow_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I411ToARGBRow_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void NV12ToARGBRow_SSSE3(const uint8* src_y,
- const uint8* src_uv,
- uint8* dst_argb,
- int width);
-void NV21ToARGBRow_SSSE3(const uint8* src_y,
- const uint8* src_vu,
- uint8* dst_argb,
- int width);
-void NV12ToRGB565Row_SSSE3(const uint8* src_y,
- const uint8* src_uv,
- uint8* dst_argb,
- int width);
-void NV21ToRGB565Row_SSSE3(const uint8* src_y,
- const uint8* src_vu,
- uint8* dst_argb,
- int width);
-void YUY2ToARGBRow_SSSE3(const uint8* src_yuy2,
- uint8* dst_argb,
- int width);
-void UYVYToARGBRow_SSSE3(const uint8* src_uyvy,
- uint8* dst_argb,
- int width);
-void I422ToBGRARow_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_bgra,
- int width);
-void I422ToABGRRow_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_abgr,
- int width);
-void I422ToRGBARow_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_rgba,
- int width);
-void I422ToARGB4444Row_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I422ToARGB1555Row_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I422ToRGB565Row_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-// RGB24/RAW are unaligned.
-void I422ToRGB24Row_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_rgb24,
- int width);
-void I422ToRAWRow_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_raw,
- int width);
-
-void I444ToARGBRow_Unaligned_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I422ToARGBRow_Unaligned_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I411ToARGBRow_Unaligned_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void NV12ToARGBRow_Unaligned_SSSE3(const uint8* src_y,
- const uint8* src_uv,
- uint8* dst_argb,
- int width);
-void NV21ToARGBRow_Unaligned_SSSE3(const uint8* src_y,
- const uint8* src_vu,
- uint8* dst_argb,
- int width);
-void YUY2ToARGBRow_Unaligned_SSSE3(const uint8* src_yuy2,
- uint8* dst_argb,
- int width);
-void UYVYToARGBRow_Unaligned_SSSE3(const uint8* src_uyvy,
- uint8* dst_argb,
- int width);
-void I422ToBGRARow_Unaligned_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_bgra,
- int width);
-void I422ToABGRRow_Unaligned_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_abgr,
- int width);
-void I422ToRGBARow_Unaligned_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_rgba,
- int width);
-void I422ToARGBRow_Any_AVX2(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I444ToARGBRow_Any_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I422ToARGBRow_Any_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I411ToARGBRow_Any_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void NV12ToARGBRow_Any_SSSE3(const uint8* src_y,
- const uint8* src_uv,
- uint8* dst_argb,
- int width);
-void NV21ToARGBRow_Any_SSSE3(const uint8* src_y,
- const uint8* src_vu,
- uint8* dst_argb,
- int width);
-void NV12ToRGB565Row_Any_SSSE3(const uint8* src_y,
- const uint8* src_uv,
- uint8* dst_argb,
- int width);
-void NV21ToRGB565Row_Any_SSSE3(const uint8* src_y,
- const uint8* src_vu,
- uint8* dst_argb,
- int width);
-void YUY2ToARGBRow_Any_SSSE3(const uint8* src_yuy2,
- uint8* dst_argb,
- int width);
-void UYVYToARGBRow_Any_SSSE3(const uint8* src_uyvy,
- uint8* dst_argb,
- int width);
-void I422ToBGRARow_Any_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_bgra,
- int width);
-void I422ToABGRRow_Any_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_abgr,
- int width);
-void I422ToRGBARow_Any_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_rgba,
- int width);
-void I422ToARGB4444Row_Any_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_rgba,
- int width);
-void I422ToARGB1555Row_Any_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_rgba,
- int width);
-void I422ToRGB565Row_Any_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_rgba,
- int width);
-// RGB24/RAW are unaligned.
-void I422ToRGB24Row_Any_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I422ToRAWRow_Any_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void YToARGBRow_SSE2(const uint8* src_y,
- uint8* dst_argb,
- int width);
-void YToARGBRow_NEON(const uint8* src_y,
- uint8* dst_argb,
- int width);
-void YToARGBRow_Any_SSE2(const uint8* src_y,
- uint8* dst_argb,
- int width);
-void YToARGBRow_Any_NEON(const uint8* src_y,
- uint8* dst_argb,
- int width);
-
-// ARGB preattenuated alpha blend.
-void ARGBBlendRow_SSSE3(const uint8* src_argb, const uint8* src_argb1,
- uint8* dst_argb, int width);
-void ARGBBlendRow_SSE2(const uint8* src_argb, const uint8* src_argb1,
- uint8* dst_argb, int width);
-void ARGBBlendRow_NEON(const uint8* src_argb, const uint8* src_argb1,
- uint8* dst_argb, int width);
-void ARGBBlendRow_C(const uint8* src_argb, const uint8* src_argb1,
- uint8* dst_argb, int width);
-
-// ARGB multiply images. Same API as Blend, but these require
-// pointer and width alignment for SSE2.
-void ARGBMultiplyRow_C(const uint8* src_argb, const uint8* src_argb1,
- uint8* dst_argb, int width);
-void ARGBMultiplyRow_SSE2(const uint8* src_argb, const uint8* src_argb1,
- uint8* dst_argb, int width);
-void ARGBMultiplyRow_Any_SSE2(const uint8* src_argb, const uint8* src_argb1,
- uint8* dst_argb, int width);
-void ARGBMultiplyRow_AVX2(const uint8* src_argb, const uint8* src_argb1,
- uint8* dst_argb, int width);
-void ARGBMultiplyRow_Any_AVX2(const uint8* src_argb, const uint8* src_argb1,
- uint8* dst_argb, int width);
-void ARGBMultiplyRow_NEON(const uint8* src_argb, const uint8* src_argb1,
- uint8* dst_argb, int width);
-void ARGBMultiplyRow_Any_NEON(const uint8* src_argb, const uint8* src_argb1,
- uint8* dst_argb, int width);
-
-// ARGB add images.
-void ARGBAddRow_C(const uint8* src_argb, const uint8* src_argb1,
- uint8* dst_argb, int width);
-void ARGBAddRow_SSE2(const uint8* src_argb, const uint8* src_argb1,
- uint8* dst_argb, int width);
-void ARGBAddRow_Any_SSE2(const uint8* src_argb, const uint8* src_argb1,
- uint8* dst_argb, int width);
-void ARGBAddRow_AVX2(const uint8* src_argb, const uint8* src_argb1,
- uint8* dst_argb, int width);
-void ARGBAddRow_Any_AVX2(const uint8* src_argb, const uint8* src_argb1,
- uint8* dst_argb, int width);
-void ARGBAddRow_NEON(const uint8* src_argb, const uint8* src_argb1,
- uint8* dst_argb, int width);
-void ARGBAddRow_Any_NEON(const uint8* src_argb, const uint8* src_argb1,
- uint8* dst_argb, int width);
-
-// ARGB subtract images. Same API as Blend, but these require
-// pointer and width alignment for SSE2.
-void ARGBSubtractRow_C(const uint8* src_argb, const uint8* src_argb1,
- uint8* dst_argb, int width);
-void ARGBSubtractRow_SSE2(const uint8* src_argb, const uint8* src_argb1,
- uint8* dst_argb, int width);
-void ARGBSubtractRow_Any_SSE2(const uint8* src_argb, const uint8* src_argb1,
- uint8* dst_argb, int width);
-void ARGBSubtractRow_AVX2(const uint8* src_argb, const uint8* src_argb1,
- uint8* dst_argb, int width);
-void ARGBSubtractRow_Any_AVX2(const uint8* src_argb, const uint8* src_argb1,
- uint8* dst_argb, int width);
-void ARGBSubtractRow_NEON(const uint8* src_argb, const uint8* src_argb1,
- uint8* dst_argb, int width);
-void ARGBSubtractRow_Any_NEON(const uint8* src_argb, const uint8* src_argb1,
- uint8* dst_argb, int width);
-
-void ARGBToRGB24Row_Any_SSSE3(const uint8* src_argb, uint8* dst_rgb, int pix);
-void ARGBToRAWRow_Any_SSSE3(const uint8* src_argb, uint8* dst_rgb, int pix);
-void ARGBToRGB565Row_Any_SSE2(const uint8* src_argb, uint8* dst_rgb, int pix);
-void ARGBToARGB1555Row_Any_SSE2(const uint8* src_argb, uint8* dst_rgb, int pix);
-void ARGBToARGB4444Row_Any_SSE2(const uint8* src_argb, uint8* dst_rgb, int pix);
-
-void ARGBToRGB24Row_Any_NEON(const uint8* src_argb, uint8* dst_rgb, int pix);
-void ARGBToRAWRow_Any_NEON(const uint8* src_argb, uint8* dst_rgb, int pix);
-void ARGBToRGB565Row_Any_NEON(const uint8* src_argb, uint8* dst_rgb, int pix);
-void ARGBToARGB1555Row_Any_NEON(const uint8* src_argb, uint8* dst_rgb, int pix);
-void ARGBToARGB4444Row_Any_NEON(const uint8* src_argb, uint8* dst_rgb, int pix);
-
-void I444ToARGBRow_Any_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I422ToARGBRow_Any_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I411ToARGBRow_Any_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I422ToBGRARow_Any_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I422ToABGRRow_Any_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I422ToRGBARow_Any_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I422ToRGB24Row_Any_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I422ToRAWRow_Any_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I422ToARGB4444Row_Any_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I422ToARGB1555Row_Any_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I422ToRGB565Row_Any_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void NV12ToARGBRow_Any_NEON(const uint8* src_y,
- const uint8* src_uv,
- uint8* dst_argb,
- int width);
-void NV21ToARGBRow_Any_NEON(const uint8* src_y,
- const uint8* src_uv,
- uint8* dst_argb,
- int width);
-void NV12ToRGB565Row_Any_NEON(const uint8* src_y,
- const uint8* src_uv,
- uint8* dst_argb,
- int width);
-void NV21ToRGB565Row_Any_NEON(const uint8* src_y,
- const uint8* src_uv,
- uint8* dst_argb,
- int width);
-void YUY2ToARGBRow_Any_NEON(const uint8* src_yuy2,
- uint8* dst_argb,
- int width);
-void UYVYToARGBRow_Any_NEON(const uint8* src_uyvy,
- uint8* dst_argb,
- int width);
-void I422ToARGBRow_MIPS_DSPR2(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I422ToBGRARow_MIPS_DSPR2(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I422ToABGRRow_MIPS_DSPR2(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I422ToARGBRow_MIPS_DSPR2(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I422ToBGRARow_MIPS_DSPR2(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-void I422ToABGRRow_MIPS_DSPR2(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width);
-
-void YUY2ToYRow_AVX2(const uint8* src_yuy2, uint8* dst_y, int pix);
-void YUY2ToUVRow_AVX2(const uint8* src_yuy2, int stride_yuy2,
- uint8* dst_u, uint8* dst_v, int pix);
-void YUY2ToUV422Row_AVX2(const uint8* src_yuy2,
- uint8* dst_u, uint8* dst_v, int pix);
-void YUY2ToYRow_SSE2(const uint8* src_yuy2, uint8* dst_y, int pix);
-void YUY2ToUVRow_SSE2(const uint8* src_yuy2, int stride_yuy2,
- uint8* dst_u, uint8* dst_v, int pix);
-void YUY2ToUV422Row_SSE2(const uint8* src_yuy2,
- uint8* dst_u, uint8* dst_v, int pix);
-void YUY2ToYRow_Unaligned_SSE2(const uint8* src_yuy2,
- uint8* dst_y, int pix);
-void YUY2ToUVRow_Unaligned_SSE2(const uint8* src_yuy2, int stride_yuy2,
- uint8* dst_u, uint8* dst_v, int pix);
-void YUY2ToUV422Row_Unaligned_SSE2(const uint8* src_yuy2,
- uint8* dst_u, uint8* dst_v, int pix);
-void YUY2ToYRow_NEON(const uint8* src_yuy2, uint8* dst_y, int pix);
-void YUY2ToUVRow_NEON(const uint8* src_yuy2, int stride_yuy2,
- uint8* dst_u, uint8* dst_v, int pix);
-void YUY2ToUV422Row_NEON(const uint8* src_yuy2,
- uint8* dst_u, uint8* dst_v, int pix);
-void YUY2ToYRow_C(const uint8* src_yuy2, uint8* dst_y, int pix);
-void YUY2ToUVRow_C(const uint8* src_yuy2, int stride_yuy2,
- uint8* dst_u, uint8* dst_v, int pix);
-void YUY2ToUV422Row_C(const uint8* src_yuy2,
- uint8* dst_u, uint8* dst_v, int pix);
-void YUY2ToYRow_Any_AVX2(const uint8* src_yuy2, uint8* dst_y, int pix);
-void YUY2ToUVRow_Any_AVX2(const uint8* src_yuy2, int stride_yuy2,
- uint8* dst_u, uint8* dst_v, int pix);
-void YUY2ToUV422Row_Any_AVX2(const uint8* src_yuy2,
- uint8* dst_u, uint8* dst_v, int pix);
-void YUY2ToYRow_Any_SSE2(const uint8* src_yuy2, uint8* dst_y, int pix);
-void YUY2ToUVRow_Any_SSE2(const uint8* src_yuy2, int stride_yuy2,
- uint8* dst_u, uint8* dst_v, int pix);
-void YUY2ToUV422Row_Any_SSE2(const uint8* src_yuy2,
- uint8* dst_u, uint8* dst_v, int pix);
-void YUY2ToYRow_Any_NEON(const uint8* src_yuy2, uint8* dst_y, int pix);
-void YUY2ToUVRow_Any_NEON(const uint8* src_yuy2, int stride_yuy2,
- uint8* dst_u, uint8* dst_v, int pix);
-void YUY2ToUV422Row_Any_NEON(const uint8* src_yuy2,
- uint8* dst_u, uint8* dst_v, int pix);
-void UYVYToYRow_AVX2(const uint8* src_uyvy, uint8* dst_y, int pix);
-void UYVYToUVRow_AVX2(const uint8* src_uyvy, int stride_uyvy,
- uint8* dst_u, uint8* dst_v, int pix);
-void UYVYToUV422Row_AVX2(const uint8* src_uyvy,
- uint8* dst_u, uint8* dst_v, int pix);
-void UYVYToYRow_SSE2(const uint8* src_uyvy, uint8* dst_y, int pix);
-void UYVYToUVRow_SSE2(const uint8* src_uyvy, int stride_uyvy,
- uint8* dst_u, uint8* dst_v, int pix);
-void UYVYToUV422Row_SSE2(const uint8* src_uyvy,
- uint8* dst_u, uint8* dst_v, int pix);
-void UYVYToYRow_Unaligned_SSE2(const uint8* src_uyvy,
- uint8* dst_y, int pix);
-void UYVYToUVRow_Unaligned_SSE2(const uint8* src_uyvy, int stride_uyvy,
- uint8* dst_u, uint8* dst_v, int pix);
-void UYVYToUV422Row_Unaligned_SSE2(const uint8* src_uyvy,
- uint8* dst_u, uint8* dst_v, int pix);
-void UYVYToYRow_AVX2(const uint8* src_uyvy, uint8* dst_y, int pix);
-void UYVYToUVRow_AVX2(const uint8* src_uyvy, int stride_uyvy,
- uint8* dst_u, uint8* dst_v, int pix);
-void UYVYToUV422Row_AVX2(const uint8* src_uyvy,
- uint8* dst_u, uint8* dst_v, int pix);
-void UYVYToYRow_NEON(const uint8* src_uyvy, uint8* dst_y, int pix);
-void UYVYToUVRow_NEON(const uint8* src_uyvy, int stride_uyvy,
- uint8* dst_u, uint8* dst_v, int pix);
-void UYVYToUV422Row_NEON(const uint8* src_uyvy,
- uint8* dst_u, uint8* dst_v, int pix);
-
-void UYVYToYRow_C(const uint8* src_uyvy, uint8* dst_y, int pix);
-void UYVYToUVRow_C(const uint8* src_uyvy, int stride_uyvy,
- uint8* dst_u, uint8* dst_v, int pix);
-void UYVYToUV422Row_C(const uint8* src_uyvy,
- uint8* dst_u, uint8* dst_v, int pix);
-void UYVYToYRow_Any_AVX2(const uint8* src_uyvy, uint8* dst_y, int pix);
-void UYVYToUVRow_Any_AVX2(const uint8* src_uyvy, int stride_uyvy,
- uint8* dst_u, uint8* dst_v, int pix);
-void UYVYToUV422Row_Any_AVX2(const uint8* src_uyvy,
- uint8* dst_u, uint8* dst_v, int pix);
-void UYVYToYRow_Any_SSE2(const uint8* src_uyvy, uint8* dst_y, int pix);
-void UYVYToUVRow_Any_SSE2(const uint8* src_uyvy, int stride_uyvy,
- uint8* dst_u, uint8* dst_v, int pix);
-void UYVYToUV422Row_Any_SSE2(const uint8* src_uyvy,
- uint8* dst_u, uint8* dst_v, int pix);
-void UYVYToYRow_Any_NEON(const uint8* src_uyvy, uint8* dst_y, int pix);
-void UYVYToUVRow_Any_NEON(const uint8* src_uyvy, int stride_uyvy,
- uint8* dst_u, uint8* dst_v, int pix);
-void UYVYToUV422Row_Any_NEON(const uint8* src_uyvy,
- uint8* dst_u, uint8* dst_v, int pix);
-
-void HalfRow_C(const uint8* src_uv, int src_uv_stride,
- uint8* dst_uv, int pix);
-void HalfRow_SSE2(const uint8* src_uv, int src_uv_stride,
- uint8* dst_uv, int pix);
-void HalfRow_AVX2(const uint8* src_uv, int src_uv_stride,
- uint8* dst_uv, int pix);
-void HalfRow_NEON(const uint8* src_uv, int src_uv_stride,
- uint8* dst_uv, int pix);
-
-void ARGBToBayerRow_C(const uint8* src_argb, uint8* dst_bayer,
- uint32 selector, int pix);
-void ARGBToBayerRow_SSSE3(const uint8* src_argb, uint8* dst_bayer,
- uint32 selector, int pix);
-void ARGBToBayerRow_NEON(const uint8* src_argb, uint8* dst_bayer,
- uint32 selector, int pix);
-void ARGBToBayerRow_Any_SSSE3(const uint8* src_argb, uint8* dst_bayer,
- uint32 selector, int pix);
-void ARGBToBayerRow_Any_NEON(const uint8* src_argb, uint8* dst_bayer,
- uint32 selector, int pix);
-void ARGBToBayerGGRow_C(const uint8* src_argb, uint8* dst_bayer,
- uint32 /* selector */, int pix);
-void ARGBToBayerGGRow_SSE2(const uint8* src_argb, uint8* dst_bayer,
- uint32 /* selector */, int pix);
-void ARGBToBayerGGRow_NEON(const uint8* src_argb, uint8* dst_bayer,
- uint32 /* selector */, int pix);
-void ARGBToBayerGGRow_Any_SSE2(const uint8* src_argb, uint8* dst_bayer,
- uint32 /* selector */, int pix);
-void ARGBToBayerGGRow_Any_NEON(const uint8* src_argb, uint8* dst_bayer,
- uint32 /* selector */, int pix);
-
-void I422ToYUY2Row_C(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_yuy2, int width);
-void I422ToUYVYRow_C(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_uyvy, int width);
-void I422ToYUY2Row_SSE2(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_yuy2, int width);
-void I422ToUYVYRow_SSE2(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_uyvy, int width);
-void I422ToYUY2Row_Any_SSE2(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_yuy2, int width);
-void I422ToUYVYRow_Any_SSE2(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_uyvy, int width);
-void I422ToYUY2Row_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_yuy2, int width);
-void I422ToUYVYRow_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_uyvy, int width);
-void I422ToYUY2Row_Any_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_yuy2, int width);
-void I422ToUYVYRow_Any_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_uyvy, int width);
-
-// Effects related row functions.
-void ARGBAttenuateRow_C(const uint8* src_argb, uint8* dst_argb, int width);
-void ARGBAttenuateRow_SSE2(const uint8* src_argb, uint8* dst_argb, int width);
-void ARGBAttenuateRow_SSSE3(const uint8* src_argb, uint8* dst_argb, int width);
-void ARGBAttenuateRow_AVX2(const uint8* src_argb, uint8* dst_argb, int width);
-void ARGBAttenuateRow_NEON(const uint8* src_argb, uint8* dst_argb, int width);
-void ARGBAttenuateRow_Any_SSE2(const uint8* src_argb, uint8* dst_argb,
- int width);
-void ARGBAttenuateRow_Any_SSSE3(const uint8* src_argb, uint8* dst_argb,
- int width);
-void ARGBAttenuateRow_Any_AVX2(const uint8* src_argb, uint8* dst_argb,
- int width);
-void ARGBAttenuateRow_Any_NEON(const uint8* src_argb, uint8* dst_argb,
- int width);
-
-// Inverse table for unattenuate, shared by C and SSE2.
-extern const uint32 fixed_invtbl8[256];
-void ARGBUnattenuateRow_C(const uint8* src_argb, uint8* dst_argb, int width);
-void ARGBUnattenuateRow_SSE2(const uint8* src_argb, uint8* dst_argb, int width);
-void ARGBUnattenuateRow_AVX2(const uint8* src_argb, uint8* dst_argb, int width);
-void ARGBUnattenuateRow_Any_SSE2(const uint8* src_argb, uint8* dst_argb,
- int width);
-void ARGBUnattenuateRow_Any_AVX2(const uint8* src_argb, uint8* dst_argb,
- int width);
-
-void ARGBGrayRow_C(const uint8* src_argb, uint8* dst_argb, int width);
-void ARGBGrayRow_SSSE3(const uint8* src_argb, uint8* dst_argb, int width);
-void ARGBGrayRow_NEON(const uint8* src_argb, uint8* dst_argb, int width);
-
-void ARGBSepiaRow_C(uint8* dst_argb, int width);
-void ARGBSepiaRow_SSSE3(uint8* dst_argb, int width);
-void ARGBSepiaRow_NEON(uint8* dst_argb, int width);
-
-void ARGBColorMatrixRow_C(const uint8* src_argb, uint8* dst_argb,
- const int8* matrix_argb, int width);
-void ARGBColorMatrixRow_SSSE3(const uint8* src_argb, uint8* dst_argb,
- const int8* matrix_argb, int width);
-void ARGBColorMatrixRow_NEON(const uint8* src_argb, uint8* dst_argb,
- const int8* matrix_argb, int width);
-
-void ARGBColorTableRow_C(uint8* dst_argb, const uint8* table_argb, int width);
-void ARGBColorTableRow_X86(uint8* dst_argb, const uint8* table_argb, int width);
-
-void RGBColorTableRow_C(uint8* dst_argb, const uint8* table_argb, int width);
-void RGBColorTableRow_X86(uint8* dst_argb, const uint8* table_argb, int width);
-
-void ARGBQuantizeRow_C(uint8* dst_argb, int scale, int interval_size,
- int interval_offset, int width);
-void ARGBQuantizeRow_SSE2(uint8* dst_argb, int scale, int interval_size,
- int interval_offset, int width);
-void ARGBQuantizeRow_NEON(uint8* dst_argb, int scale, int interval_size,
- int interval_offset, int width);
-
-void ARGBShadeRow_C(const uint8* src_argb, uint8* dst_argb, int width,
- uint32 value);
-void ARGBShadeRow_SSE2(const uint8* src_argb, uint8* dst_argb, int width,
- uint32 value);
-void ARGBShadeRow_NEON(const uint8* src_argb, uint8* dst_argb, int width,
- uint32 value);
-
-// Used for blur.
-void CumulativeSumToAverageRow_SSE2(const int32* topleft, const int32* botleft,
- int width, int area, uint8* dst, int count);
-void ComputeCumulativeSumRow_SSE2(const uint8* row, int32* cumsum,
- const int32* previous_cumsum, int width);
-
-void CumulativeSumToAverageRow_C(const int32* topleft, const int32* botleft,
- int width, int area, uint8* dst, int count);
-void ComputeCumulativeSumRow_C(const uint8* row, int32* cumsum,
- const int32* previous_cumsum, int width);
-
-LIBYUV_API
-void ARGBAffineRow_C(const uint8* src_argb, int src_argb_stride,
- uint8* dst_argb, const float* uv_dudv, int width);
-LIBYUV_API
-void ARGBAffineRow_SSE2(const uint8* src_argb, int src_argb_stride,
- uint8* dst_argb, const float* uv_dudv, int width);
-
-// Used for I420Scale, ARGBScale, and ARGBInterpolate.
-void InterpolateRow_C(uint8* dst_ptr, const uint8* src_ptr,
- ptrdiff_t src_stride_ptr,
- int width, int source_y_fraction);
-void InterpolateRow_SSE2(uint8* dst_ptr, const uint8* src_ptr,
- ptrdiff_t src_stride_ptr, int width,
- int source_y_fraction);
-void InterpolateRow_SSSE3(uint8* dst_ptr, const uint8* src_ptr,
- ptrdiff_t src_stride_ptr, int width,
- int source_y_fraction);
-void InterpolateRow_AVX2(uint8* dst_ptr, const uint8* src_ptr,
- ptrdiff_t src_stride_ptr, int width,
- int source_y_fraction);
-void InterpolateRow_NEON(uint8* dst_ptr, const uint8* src_ptr,
- ptrdiff_t src_stride_ptr, int width,
- int source_y_fraction);
-void InterpolateRows_MIPS_DSPR2(uint8* dst_ptr, const uint8* src_ptr,
- ptrdiff_t src_stride_ptr, int width,
- int source_y_fraction);
-void InterpolateRow_Unaligned_SSE2(uint8* dst_ptr, const uint8* src_ptr,
- ptrdiff_t src_stride_ptr, int width,
- int source_y_fraction);
-void InterpolateRow_Unaligned_SSSE3(uint8* dst_ptr, const uint8* src_ptr,
- ptrdiff_t src_stride_ptr, int width,
- int source_y_fraction);
-void InterpolateRow_Any_NEON(uint8* dst_ptr, const uint8* src_ptr,
- ptrdiff_t src_stride_ptr, int width,
- int source_y_fraction);
-void InterpolateRow_Any_SSE2(uint8* dst_ptr, const uint8* src_ptr,
- ptrdiff_t src_stride_ptr, int width,
- int source_y_fraction);
-void InterpolateRow_Any_SSSE3(uint8* dst_ptr, const uint8* src_ptr,
- ptrdiff_t src_stride_ptr, int width,
- int source_y_fraction);
-void InterpolateRow_Any_AVX2(uint8* dst_ptr, const uint8* src_ptr,
- ptrdiff_t src_stride_ptr, int width,
- int source_y_fraction);
-void InterpolateRows_Any_MIPS_DSPR2(uint8* dst_ptr, const uint8* src_ptr,
- ptrdiff_t src_stride_ptr, int width,
- int source_y_fraction);
-
-// Sobel images.
-void SobelXRow_C(const uint8* src_y0, const uint8* src_y1, const uint8* src_y2,
- uint8* dst_sobelx, int width);
-void SobelXRow_SSE2(const uint8* src_y0, const uint8* src_y1,
- const uint8* src_y2, uint8* dst_sobelx, int width);
-void SobelXRow_NEON(const uint8* src_y0, const uint8* src_y1,
- const uint8* src_y2, uint8* dst_sobelx, int width);
-void SobelYRow_C(const uint8* src_y0, const uint8* src_y1,
- uint8* dst_sobely, int width);
-void SobelYRow_SSE2(const uint8* src_y0, const uint8* src_y1,
- uint8* dst_sobely, int width);
-void SobelYRow_NEON(const uint8* src_y0, const uint8* src_y1,
- uint8* dst_sobely, int width);
-void SobelRow_C(const uint8* src_sobelx, const uint8* src_sobely,
- uint8* dst_argb, int width);
-void SobelRow_SSE2(const uint8* src_sobelx, const uint8* src_sobely,
- uint8* dst_argb, int width);
-void SobelRow_NEON(const uint8* src_sobelx, const uint8* src_sobely,
- uint8* dst_argb, int width);
-void SobelToPlaneRow_C(const uint8* src_sobelx, const uint8* src_sobely,
- uint8* dst_y, int width);
-void SobelToPlaneRow_SSE2(const uint8* src_sobelx, const uint8* src_sobely,
- uint8* dst_y, int width);
-void SobelToPlaneRow_NEON(const uint8* src_sobelx, const uint8* src_sobely,
- uint8* dst_y, int width);
-void SobelXYRow_C(const uint8* src_sobelx, const uint8* src_sobely,
- uint8* dst_argb, int width);
-void SobelXYRow_SSE2(const uint8* src_sobelx, const uint8* src_sobely,
- uint8* dst_argb, int width);
-void SobelXYRow_NEON(const uint8* src_sobelx, const uint8* src_sobely,
- uint8* dst_argb, int width);
-
-void ARGBPolynomialRow_C(const uint8* src_argb,
- uint8* dst_argb, const float* poly,
- int width);
-void ARGBPolynomialRow_SSE2(const uint8* src_argb,
- uint8* dst_argb, const float* poly,
- int width);
-void ARGBPolynomialRow_AVX2(const uint8* src_argb,
- uint8* dst_argb, const float* poly,
- int width);
-
-void ARGBLumaColorTableRow_C(const uint8* src_argb, uint8* dst_argb, int width,
- const uint8* luma, uint32 lumacoeff);
-void ARGBLumaColorTableRow_SSSE3(const uint8* src_argb, uint8* dst_argb,
- int width,
- const uint8* luma, uint32 lumacoeff);
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
-
-#endif // INCLUDE_LIBYUV_ROW_H_ NOLINT
diff --git a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/scale.h b/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/scale.h
deleted file mode 100755
index 592b8ed5fa..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/scale.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef INCLUDE_LIBYUV_SCALE_H_ // NOLINT
-#define INCLUDE_LIBYUV_SCALE_H_
-
-#include "libyuv/basic_types.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// Supported filtering.
-typedef enum FilterMode {
- kFilterNone = 0, // Point sample; Fastest.
- kFilterLinear = 1, // Filter horizontally only.
- kFilterBilinear = 2, // Faster than box, but lower quality scaling down.
- kFilterBox = 3 // Highest quality.
-} FilterModeEnum;
-
-// Scale a YUV plane.
-LIBYUV_API
-void ScalePlane(const uint8* src, int src_stride,
- int src_width, int src_height,
- uint8* dst, int dst_stride,
- int dst_width, int dst_height,
- enum FilterMode filtering);
-
-// Scales a YUV 4:2:0 image from the src width and height to the
-// dst width and height.
-// If filtering is kFilterNone, a simple nearest-neighbor algorithm is
-// used. This produces basic (blocky) quality at the fastest speed.
-// If filtering is kFilterBilinear, interpolation is used to produce a better
-// quality image, at the expense of speed.
-// If filtering is kFilterBox, averaging is used to produce ever better
-// quality image, at further expense of speed.
-// Returns 0 if successful.
-
-LIBYUV_API
-int I420Scale(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- int src_width, int src_height,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int dst_width, int dst_height,
- enum FilterMode filtering);
-
-#ifdef __cplusplus
-// Legacy API. Deprecated.
-LIBYUV_API
-int Scale(const uint8* src_y, const uint8* src_u, const uint8* src_v,
- int src_stride_y, int src_stride_u, int src_stride_v,
- int src_width, int src_height,
- uint8* dst_y, uint8* dst_u, uint8* dst_v,
- int dst_stride_y, int dst_stride_u, int dst_stride_v,
- int dst_width, int dst_height,
- LIBYUV_BOOL interpolate);
-
-// Legacy API. Deprecated.
-LIBYUV_API
-int ScaleOffset(const uint8* src_i420, int src_width, int src_height,
- uint8* dst_i420, int dst_width, int dst_height, int dst_yoffset,
- LIBYUV_BOOL interpolate);
-
-// For testing, allow disabling of specialized scalers.
-LIBYUV_API
-void SetUseReferenceImpl(LIBYUV_BOOL use);
-#endif // __cplusplus
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
-
-#endif // INCLUDE_LIBYUV_SCALE_H_ NOLINT
diff --git a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/scale_argb.h b/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/scale_argb.h
deleted file mode 100755
index 0c9b362575..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/scale_argb.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2012 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef INCLUDE_LIBYUV_SCALE_ARGB_H_ // NOLINT
-#define INCLUDE_LIBYUV_SCALE_ARGB_H_
-
-#include "libyuv/basic_types.h"
-#include "libyuv/scale.h" // For FilterMode
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-LIBYUV_API
-int ARGBScale(const uint8* src_argb, int src_stride_argb,
- int src_width, int src_height,
- uint8* dst_argb, int dst_stride_argb,
- int dst_width, int dst_height,
- enum FilterMode filtering);
-
-// Clipped scale takes destination rectangle coordinates for clip values.
-LIBYUV_API
-int ARGBScaleClip(const uint8* src_argb, int src_stride_argb,
- int src_width, int src_height,
- uint8* dst_argb, int dst_stride_argb,
- int dst_width, int dst_height,
- int clip_x, int clip_y, int clip_width, int clip_height,
- enum FilterMode filtering);
-
-// TODO(fbarchard): Implement this.
-// Scale with YUV conversion to ARGB and clipping.
-LIBYUV_API
-int YUVToARGBScaleClip(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint32 src_fourcc,
- int src_width, int src_height,
- uint8* dst_argb, int dst_stride_argb,
- uint32 dst_fourcc,
- int dst_width, int dst_height,
- int clip_x, int clip_y, int clip_width, int clip_height,
- enum FilterMode filtering);
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
-
-#endif // INCLUDE_LIBYUV_SCALE_ARGB_H_ NOLINT
diff --git a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/scale_row.h b/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/scale_row.h
deleted file mode 100644
index 13eccc4d77..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/scale_row.h
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * Copyright 2013 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef INCLUDE_LIBYUV_SCALE_ROW_H_ // NOLINT
-#define INCLUDE_LIBYUV_SCALE_ROW_H_
-
-#include "libyuv/basic_types.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-#if defined(__pnacl__) || defined(__CLR_VER) || defined(COVERAGE_ENABLED) || \
- defined(TARGET_IPHONE_SIMULATOR)
-#define LIBYUV_DISABLE_X86
-#endif
-
-// The following are available on all x86 platforms:
-#if !defined(LIBYUV_DISABLE_X86) && \
- (defined(_M_IX86) || defined(__x86_64__) || defined(__i386__))
-#define HAS_SCALEROWDOWN2_SSE2
-#define HAS_SCALEROWDOWN4_SSE2
-#define HAS_SCALEROWDOWN34_SSSE3
-#define HAS_SCALEROWDOWN38_SSSE3
-#define HAS_SCALEADDROWS_SSE2
-#define HAS_SCALEFILTERCOLS_SSSE3
-#define HAS_SCALECOLSUP2_SSE2
-#define HAS_SCALEARGBROWDOWN2_SSE2
-#define HAS_SCALEARGBROWDOWNEVEN_SSE2
-#define HAS_SCALEARGBCOLS_SSE2
-#define HAS_SCALEARGBFILTERCOLS_SSSE3
-#define HAS_SCALEARGBCOLSUP2_SSE2
-#define HAS_FIXEDDIV_X86
-#define HAS_FIXEDDIV1_X86
-#endif
-
-// The following are available on Neon platforms:
-#if !defined(LIBYUV_DISABLE_NEON) && !defined(__native_client__) && \
- (defined(__ARM_NEON__) || defined(LIBYUV_NEON))
-#define HAS_SCALEROWDOWN2_NEON
-#define HAS_SCALEROWDOWN4_NEON
-#define HAS_SCALEROWDOWN34_NEON
-#define HAS_SCALEROWDOWN38_NEON
-#define HAS_SCALEARGBROWDOWNEVEN_NEON
-#define HAS_SCALEARGBROWDOWN2_NEON
-#endif
-
-// The following are available on Mips platforms:
-#if !defined(LIBYUV_DISABLE_MIPS) && !defined(__native_client__) && \
- defined(__mips__) && defined(__mips_dsp) && (__mips_dsp_rev >= 2)
-#define HAS_SCALEROWDOWN2_MIPS_DSPR2
-#define HAS_SCALEROWDOWN4_MIPS_DSPR2
-#define HAS_SCALEROWDOWN34_MIPS_DSPR2
-#define HAS_SCALEROWDOWN38_MIPS_DSPR2
-#endif
-
-// Scale ARGB vertically with bilinear interpolation.
-void ScalePlaneVertical(int src_height,
- int dst_width, int dst_height,
- int src_stride, int dst_stride,
- const uint8* src_argb, uint8* dst_argb,
- int x, int y, int dy,
- int bpp, enum FilterMode filtering);
-
-// Simplify the filtering based on scale factors.
-enum FilterMode ScaleFilterReduce(int src_width, int src_height,
- int dst_width, int dst_height,
- enum FilterMode filtering);
-
-// Divide num by div and return as 16.16 fixed point result.
-int FixedDiv_C(int num, int div);
-int FixedDiv_X86(int num, int div);
-// Divide num - 1 by div - 1 and return as 16.16 fixed point result.
-int FixedDiv1_C(int num, int div);
-int FixedDiv1_X86(int num, int div);
-#ifdef HAS_FIXEDDIV_X86
-#define FixedDiv FixedDiv_X86
-#define FixedDiv1 FixedDiv1_X86
-#else
-#define FixedDiv FixedDiv_C
-#define FixedDiv1 FixedDiv1_C
-#endif
-
-// Compute slope values for stepping.
-void ScaleSlope(int src_width, int src_height,
- int dst_width, int dst_height,
- enum FilterMode filtering,
- int* x, int* y, int* dx, int* dy);
-
-void ScaleRowDown2_C(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width);
-void ScaleRowDown2Linear_C(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width);
-void ScaleRowDown2Box_C(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width);
-void ScaleRowDown4_C(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width);
-void ScaleRowDown4Box_C(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width);
-void ScaleRowDown34_C(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width);
-void ScaleRowDown34_0_Box_C(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* d, int dst_width);
-void ScaleRowDown34_1_Box_C(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* d, int dst_width);
-void ScaleCols_C(uint8* dst_ptr, const uint8* src_ptr,
- int dst_width, int x, int dx);
-void ScaleColsUp2_C(uint8* dst_ptr, const uint8* src_ptr,
- int dst_width, int, int);
-void ScaleFilterCols_C(uint8* dst_ptr, const uint8* src_ptr,
- int dst_width, int x, int dx);
-void ScaleFilterCols64_C(uint8* dst_ptr, const uint8* src_ptr,
- int dst_width, int x, int dx);
-void ScaleRowDown38_C(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width);
-void ScaleRowDown38_3_Box_C(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
-void ScaleRowDown38_2_Box_C(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
-void ScaleAddRows_C(const uint8* src_ptr, ptrdiff_t src_stride,
- uint16* dst_ptr, int src_width, int src_height);
-void ScaleARGBRowDown2_C(const uint8* src_argb,
- ptrdiff_t src_stride,
- uint8* dst_argb, int dst_width);
-void ScaleARGBRowDown2Linear_C(const uint8* src_argb,
- ptrdiff_t src_stride,
- uint8* dst_argb, int dst_width);
-void ScaleARGBRowDown2Box_C(const uint8* src_argb, ptrdiff_t src_stride,
- uint8* dst_argb, int dst_width);
-void ScaleARGBRowDownEven_C(const uint8* src_argb, ptrdiff_t src_stride,
- int src_stepx,
- uint8* dst_argb, int dst_width);
-void ScaleARGBRowDownEvenBox_C(const uint8* src_argb,
- ptrdiff_t src_stride,
- int src_stepx,
- uint8* dst_argb, int dst_width);
-void ScaleARGBCols_C(uint8* dst_argb, const uint8* src_argb,
- int dst_width, int x, int dx);
-void ScaleARGBCols64_C(uint8* dst_argb, const uint8* src_argb,
- int dst_width, int x, int dx);
-void ScaleARGBColsUp2_C(uint8* dst_argb, const uint8* src_argb,
- int dst_width, int, int);
-void ScaleARGBFilterCols_C(uint8* dst_argb, const uint8* src_argb,
- int dst_width, int x, int dx);
-void ScaleARGBFilterCols64_C(uint8* dst_argb, const uint8* src_argb,
- int dst_width, int x, int dx);
-
-void ScaleRowDown2_SSE2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
-void ScaleRowDown2Linear_SSE2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
-void ScaleRowDown2Box_SSE2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
-void ScaleRowDown2_Unaligned_SSE2(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
-void ScaleRowDown2Linear_Unaligned_SSE2(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
-void ScaleRowDown2Box_Unaligned_SSE2(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
-void ScaleRowDown4_SSE2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
-void ScaleRowDown4Box_SSE2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
-void ScaleRowDown34_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
-void ScaleRowDown34_1_Box_SSSE3(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
-void ScaleRowDown34_0_Box_SSSE3(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
-void ScaleRowDown38_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
-void ScaleRowDown38_3_Box_SSSE3(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
-void ScaleRowDown38_2_Box_SSSE3(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
-void ScaleAddRows_SSE2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint16* dst_ptr, int src_width,
- int src_height);
-void ScaleFilterCols_SSSE3(uint8* dst_ptr, const uint8* src_ptr,
- int dst_width, int x, int dx);
-void ScaleColsUp2_SSE2(uint8* dst_ptr, const uint8* src_ptr,
- int dst_width, int x, int dx);
-void ScaleARGBRowDown2_SSE2(const uint8* src_argb,
- ptrdiff_t src_stride,
- uint8* dst_argb, int dst_width);
-void ScaleARGBRowDown2Linear_SSE2(const uint8* src_argb,
- ptrdiff_t src_stride,
- uint8* dst_argb, int dst_width);
-void ScaleARGBRowDown2Box_SSE2(const uint8* src_argb,
- ptrdiff_t src_stride,
- uint8* dst_argb, int dst_width);
-void ScaleARGBRowDownEven_SSE2(const uint8* src_argb, ptrdiff_t src_stride,
- int src_stepx,
- uint8* dst_argb, int dst_width);
-void ScaleARGBRowDownEvenBox_SSE2(const uint8* src_argb,
- ptrdiff_t src_stride,
- int src_stepx,
- uint8* dst_argb, int dst_width);
-void ScaleARGBCols_SSE2(uint8* dst_argb, const uint8* src_argb,
- int dst_width, int x, int dx);
-void ScaleARGBFilterCols_SSSE3(uint8* dst_argb, const uint8* src_argb,
- int dst_width, int x, int dx);
-void ScaleARGBColsUp2_SSE2(uint8* dst_argb, const uint8* src_argb,
- int dst_width, int x, int dx);
-// Row functions.
-void ScaleARGBRowDownEven_NEON(const uint8* src_argb, int src_stride,
- int src_stepx,
- uint8* dst_argb, int dst_width);
-void ScaleARGBRowDownEvenBox_NEON(const uint8* src_argb, int src_stride,
- int src_stepx,
- uint8* dst_argb, int dst_width);
-void ScaleARGBRowDown2_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width);
-void ScaleARGBRowDown2Box_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width);
-
-// ScaleRowDown2Box also used by planar functions
-// NEON downscalers with interpolation.
-
-// Note - not static due to reuse in convert for 444 to 420.
-void ScaleRowDown2_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width);
-
-void ScaleRowDown2Box_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width);
-
-void ScaleRowDown4_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
-void ScaleRowDown4Box_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
-
-// Down scale from 4 to 3 pixels. Use the neon multilane read/write
-// to load up the every 4th pixel into a 4 different registers.
-// Point samples 32 pixels to 24 pixels.
-void ScaleRowDown34_NEON(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
-void ScaleRowDown34_0_Box_NEON(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
-void ScaleRowDown34_1_Box_NEON(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
-
-// 32 -> 12
-void ScaleRowDown38_NEON(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
-// 32x3 -> 12x1
-void ScaleRowDown38_3_Box_NEON(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
-// 32x2 -> 12x1
-void ScaleRowDown38_2_Box_NEON(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
-
-void ScaleRowDown2_MIPS_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width);
-void ScaleRowDown2Box_MIPS_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width);
-void ScaleRowDown4_MIPS_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width);
-void ScaleRowDown4Box_MIPS_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width);
-void ScaleRowDown34_MIPS_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width);
-void ScaleRowDown34_0_Box_MIPS_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* d, int dst_width);
-void ScaleRowDown34_1_Box_MIPS_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* d, int dst_width);
-void ScaleRowDown38_MIPS_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width);
-void ScaleRowDown38_2_Box_MIPS_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
-void ScaleRowDown38_3_Box_MIPS_DSPR2(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
-
-#endif // INCLUDE_LIBYUV_SCALE_ROW_H_ NOLINT
diff --git a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/version.h b/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/version.h
deleted file mode 100755
index 4881861866..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/version.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Copyright 2012 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#ifndef INCLUDE_LIBYUV_VERSION_H_ // NOLINT
-#define INCLUDE_LIBYUV_VERSION_H_
-
-#define LIBYUV_VERSION 998
-
-#endif // INCLUDE_LIBYUV_VERSION_H_ NOLINT
diff --git a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/video_common.h b/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/video_common.h
deleted file mode 100755
index 039efb96d1..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/include/libyuv/video_common.h
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-// Common definitions for video, including fourcc and VideoFormat.
-
-#ifndef INCLUDE_LIBYUV_VIDEO_COMMON_H_ // NOLINT
-#define INCLUDE_LIBYUV_VIDEO_COMMON_H_
-
-#include "libyuv/basic_types.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-//////////////////////////////////////////////////////////////////////////////
-// Definition of FourCC codes
-//////////////////////////////////////////////////////////////////////////////
-
-// Convert four characters to a FourCC code.
-// Needs to be a macro otherwise the OS X compiler complains when the kFormat*
-// constants are used in a switch.
-#ifdef __cplusplus
-#define FOURCC(a, b, c, d) ( \
- (static_cast<uint32>(a)) | (static_cast<uint32>(b) << 8) | \
- (static_cast<uint32>(c) << 16) | (static_cast<uint32>(d) << 24))
-#else
-#define FOURCC(a, b, c, d) ( \
- ((uint32)(a)) | ((uint32)(b) << 8) | /* NOLINT */ \
- ((uint32)(c) << 16) | ((uint32)(d) << 24)) /* NOLINT */
-#endif
-
-// Some pages discussing FourCC codes:
-// http://www.fourcc.org/yuv.php
-// http://v4l2spec.bytesex.org/spec/book1.htm
-// http://developer.apple.com/quicktime/icefloe/dispatch020.html
-// http://msdn.microsoft.com/library/windows/desktop/dd206750.aspx#nv12
-// http://people.xiph.org/~xiphmont/containers/nut/nut4cc.txt
-
-// FourCC codes grouped according to implementation efficiency.
-// Primary formats should convert in 1 efficient step.
-// Secondary formats are converted in 2 steps.
-// Auxilliary formats call primary converters.
-enum FourCC {
- // 9 Primary YUV formats: 5 planar, 2 biplanar, 2 packed.
- FOURCC_I420 = FOURCC('I', '4', '2', '0'),
- FOURCC_I422 = FOURCC('I', '4', '2', '2'),
- FOURCC_I444 = FOURCC('I', '4', '4', '4'),
- FOURCC_I411 = FOURCC('I', '4', '1', '1'),
- FOURCC_I400 = FOURCC('I', '4', '0', '0'),
- FOURCC_NV21 = FOURCC('N', 'V', '2', '1'),
- FOURCC_NV12 = FOURCC('N', 'V', '1', '2'),
- FOURCC_YUY2 = FOURCC('Y', 'U', 'Y', '2'),
- FOURCC_UYVY = FOURCC('U', 'Y', 'V', 'Y'),
-
- // 2 Secondary YUV formats: row biplanar.
- FOURCC_M420 = FOURCC('M', '4', '2', '0'),
- FOURCC_Q420 = FOURCC('Q', '4', '2', '0'),
-
- // 9 Primary RGB formats: 4 32 bpp, 2 24 bpp, 3 16 bpp.
- FOURCC_ARGB = FOURCC('A', 'R', 'G', 'B'),
- FOURCC_BGRA = FOURCC('B', 'G', 'R', 'A'),
- FOURCC_ABGR = FOURCC('A', 'B', 'G', 'R'),
- FOURCC_24BG = FOURCC('2', '4', 'B', 'G'),
- FOURCC_RAW = FOURCC('r', 'a', 'w', ' '),
- FOURCC_RGBA = FOURCC('R', 'G', 'B', 'A'),
- FOURCC_RGBP = FOURCC('R', 'G', 'B', 'P'), // rgb565 LE.
- FOURCC_RGBO = FOURCC('R', 'G', 'B', 'O'), // argb1555 LE.
- FOURCC_R444 = FOURCC('R', '4', '4', '4'), // argb4444 LE.
-
- // 4 Secondary RGB formats: 4 Bayer Patterns.
- FOURCC_RGGB = FOURCC('R', 'G', 'G', 'B'),
- FOURCC_BGGR = FOURCC('B', 'G', 'G', 'R'),
- FOURCC_GRBG = FOURCC('G', 'R', 'B', 'G'),
- FOURCC_GBRG = FOURCC('G', 'B', 'R', 'G'),
-
- // 1 Primary Compressed YUV format.
- FOURCC_MJPG = FOURCC('M', 'J', 'P', 'G'),
-
- // 5 Auxiliary YUV variations: 3 with U and V planes are swapped, 1 Alias.
- FOURCC_YV12 = FOURCC('Y', 'V', '1', '2'),
- FOURCC_YV16 = FOURCC('Y', 'V', '1', '6'),
- FOURCC_YV24 = FOURCC('Y', 'V', '2', '4'),
- FOURCC_YU12 = FOURCC('Y', 'U', '1', '2'), // Linux version of I420.
- FOURCC_J420 = FOURCC('J', '4', '2', '0'),
- FOURCC_J400 = FOURCC('J', '4', '0', '0'),
-
- // 14 Auxiliary aliases. CanonicalFourCC() maps these to canonical fourcc.
- FOURCC_IYUV = FOURCC('I', 'Y', 'U', 'V'), // Alias for I420.
- FOURCC_YU16 = FOURCC('Y', 'U', '1', '6'), // Alias for I422.
- FOURCC_YU24 = FOURCC('Y', 'U', '2', '4'), // Alias for I444.
- FOURCC_YUYV = FOURCC('Y', 'U', 'Y', 'V'), // Alias for YUY2.
- FOURCC_YUVS = FOURCC('y', 'u', 'v', 's'), // Alias for YUY2 on Mac.
- FOURCC_HDYC = FOURCC('H', 'D', 'Y', 'C'), // Alias for UYVY.
- FOURCC_2VUY = FOURCC('2', 'v', 'u', 'y'), // Alias for UYVY on Mac.
- FOURCC_JPEG = FOURCC('J', 'P', 'E', 'G'), // Alias for MJPG.
- FOURCC_DMB1 = FOURCC('d', 'm', 'b', '1'), // Alias for MJPG on Mac.
- FOURCC_BA81 = FOURCC('B', 'A', '8', '1'), // Alias for BGGR.
- FOURCC_RGB3 = FOURCC('R', 'G', 'B', '3'), // Alias for RAW.
- FOURCC_BGR3 = FOURCC('B', 'G', 'R', '3'), // Alias for 24BG.
- FOURCC_CM32 = FOURCC(0, 0, 0, 32), // Alias for BGRA kCMPixelFormat_32ARGB
- FOURCC_CM24 = FOURCC(0, 0, 0, 24), // Alias for RAW kCMPixelFormat_24RGB
- FOURCC_L555 = FOURCC('L', '5', '5', '5'), // Alias for RGBO.
- FOURCC_L565 = FOURCC('L', '5', '6', '5'), // Alias for RGBP.
- FOURCC_5551 = FOURCC('5', '5', '5', '1'), // Alias for RGBO.
-
- // 1 Auxiliary compressed YUV format set aside for capturer.
- FOURCC_H264 = FOURCC('H', '2', '6', '4'),
-
- // Match any fourcc.
- FOURCC_ANY = 0xFFFFFFFF,
-};
-
-enum FourCCBpp {
- // Canonical fourcc codes used in our code.
- FOURCC_BPP_I420 = 12,
- FOURCC_BPP_I422 = 16,
- FOURCC_BPP_I444 = 24,
- FOURCC_BPP_I411 = 12,
- FOURCC_BPP_I400 = 8,
- FOURCC_BPP_NV21 = 12,
- FOURCC_BPP_NV12 = 12,
- FOURCC_BPP_YUY2 = 16,
- FOURCC_BPP_UYVY = 16,
- FOURCC_BPP_M420 = 12,
- FOURCC_BPP_Q420 = 12,
- FOURCC_BPP_ARGB = 32,
- FOURCC_BPP_BGRA = 32,
- FOURCC_BPP_ABGR = 32,
- FOURCC_BPP_RGBA = 32,
- FOURCC_BPP_24BG = 24,
- FOURCC_BPP_RAW = 24,
- FOURCC_BPP_RGBP = 16,
- FOURCC_BPP_RGBO = 16,
- FOURCC_BPP_R444 = 16,
- FOURCC_BPP_RGGB = 8,
- FOURCC_BPP_BGGR = 8,
- FOURCC_BPP_GRBG = 8,
- FOURCC_BPP_GBRG = 8,
- FOURCC_BPP_YV12 = 12,
- FOURCC_BPP_YV16 = 16,
- FOURCC_BPP_YV24 = 24,
- FOURCC_BPP_YU12 = 12,
- FOURCC_BPP_J420 = 12,
- FOURCC_BPP_J400 = 8,
- FOURCC_BPP_MJPG = 0, // 0 means unknown.
- FOURCC_BPP_H264 = 0,
- FOURCC_BPP_IYUV = 12,
- FOURCC_BPP_YU16 = 16,
- FOURCC_BPP_YU24 = 24,
- FOURCC_BPP_YUYV = 16,
- FOURCC_BPP_YUVS = 16,
- FOURCC_BPP_HDYC = 16,
- FOURCC_BPP_2VUY = 16,
- FOURCC_BPP_JPEG = 1,
- FOURCC_BPP_DMB1 = 1,
- FOURCC_BPP_BA81 = 8,
- FOURCC_BPP_RGB3 = 24,
- FOURCC_BPP_BGR3 = 24,
- FOURCC_BPP_CM32 = 32,
- FOURCC_BPP_CM24 = 24,
-
- // Match any fourcc.
- FOURCC_BPP_ANY = 0, // 0 means unknown.
-};
-
-// Converts fourcc aliases into canonical ones.
-LIBYUV_API uint32 CanonicalFourCC(uint32 fourcc);
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
-
-#endif // INCLUDE_LIBYUV_VIDEO_COMMON_H_ NOLINT
diff --git a/drivers/theoraplayer/src/YUV/libyuv/libtheoraplayer-readme.txt b/drivers/theoraplayer/src/YUV/libyuv/libtheoraplayer-readme.txt
deleted file mode 100755
index 680e4a1c36..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/libtheoraplayer-readme.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-libyuv's source code is here provided in minimalist distribution format
-with all source files not needed for compiling libtheoraplayer removed.
-
-- The project files were modified to fit libtheoraplayer's binary output
- folder structure.
-- Some project files missing in the original source distibution were added to support
- compiling the libtheoraplayer on those platforms.
-- Also, some code may have been changed to address certain compiler/platform
- specific problems and is so indicated in the source code.
-
-libyuv is owned and maintained by the Google Inc. and this distribution
-is present here only for convenience and easier compilation of libtheoraplayer.
-
-If you want to use libyuv outside of libtheoraplayer, it is encouraged to use the
-original source distribution by Google Inc: https://code.google.com/p/libyuv/ \ No newline at end of file
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/compare.cc b/drivers/theoraplayer/src/YUV/libyuv/src/compare.cc
deleted file mode 100755
index 9ea81b4e21..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/compare.cc
+++ /dev/null
@@ -1,325 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/compare.h"
-
-#include <float.h>
-#include <math.h>
-#ifdef _OPENMP
-#include <omp.h>
-#endif
-
-#include "libyuv/basic_types.h"
-#include "libyuv/cpu_id.h"
-#include "libyuv/row.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// hash seed of 5381 recommended.
-// Internal C version of HashDjb2 with int sized count for efficiency.
-uint32 HashDjb2_C(const uint8* src, int count, uint32 seed);
-
-// This module is for Visual C x86
-#if !defined(LIBYUV_DISABLE_X86) && \
- (defined(_M_IX86) || \
- (defined(__x86_64__) || (defined(__i386__) && !defined(__pic__))))
-#define HAS_HASHDJB2_SSE41
-uint32 HashDjb2_SSE41(const uint8* src, int count, uint32 seed);
-
-#if _MSC_VER >= 1700
-#define HAS_HASHDJB2_AVX2
-uint32 HashDjb2_AVX2(const uint8* src, int count, uint32 seed);
-#endif
-
-#endif // HAS_HASHDJB2_SSE41
-
-// hash seed of 5381 recommended.
-LIBYUV_API
-uint32 HashDjb2(const uint8* src, uint64 count, uint32 seed) {
- const int kBlockSize = 1 << 15; // 32768;
- int remainder;
- uint32 (*HashDjb2_SSE)(const uint8* src, int count, uint32 seed) = HashDjb2_C;
-#if defined(HAS_HASHDJB2_SSE41)
- if (TestCpuFlag(kCpuHasSSE41)) {
- HashDjb2_SSE = HashDjb2_SSE41;
- }
-#endif
-#if defined(HAS_HASHDJB2_AVX2)
- if (TestCpuFlag(kCpuHasAVX2)) {
- HashDjb2_SSE = HashDjb2_AVX2;
- }
-#endif
-
- while (count >= (uint64)(kBlockSize)) {
- seed = HashDjb2_SSE(src, kBlockSize, seed);
- src += kBlockSize;
- count -= kBlockSize;
- }
- remainder = (int)(count) & ~15;
- if (remainder) {
- seed = HashDjb2_SSE(src, remainder, seed);
- src += remainder;
- count -= remainder;
- }
- remainder = (int)(count) & 15;
- if (remainder) {
- seed = HashDjb2_C(src, remainder, seed);
- }
- return seed;
-}
-
-uint32 SumSquareError_C(const uint8* src_a, const uint8* src_b, int count);
-#if !defined(LIBYUV_DISABLE_NEON) && \
- (defined(__ARM_NEON__) || defined(LIBYUV_NEON))
-#define HAS_SUMSQUAREERROR_NEON
-uint32 SumSquareError_NEON(const uint8* src_a, const uint8* src_b, int count);
-#endif
-#if !defined(LIBYUV_DISABLE_X86) && \
- (defined(_M_IX86) || defined(__x86_64__) || defined(__i386__))
-#define HAS_SUMSQUAREERROR_SSE2
-uint32 SumSquareError_SSE2(const uint8* src_a, const uint8* src_b, int count);
-#endif
-// Visual C 2012 required for AVX2.
-#if !defined(LIBYUV_DISABLE_X86) && defined(_M_IX86) && _MSC_VER >= 1700
-#define HAS_SUMSQUAREERROR_AVX2
-uint32 SumSquareError_AVX2(const uint8* src_a, const uint8* src_b, int count);
-#endif
-
-// TODO(fbarchard): Refactor into row function.
-LIBYUV_API
-uint64 ComputeSumSquareError(const uint8* src_a, const uint8* src_b,
- int count) {
- // SumSquareError returns values 0 to 65535 for each squared difference.
- // Up to 65536 of those can be summed and remain within a uint32.
- // After each block of 65536 pixels, accumulate into a uint64.
- const int kBlockSize = 65536;
- int remainder = count & (kBlockSize - 1) & ~31;
- uint64 sse = 0;
- int i;
- uint32 (*SumSquareError)(const uint8* src_a, const uint8* src_b, int count) =
- SumSquareError_C;
-#if defined(HAS_SUMSQUAREERROR_NEON)
- if (TestCpuFlag(kCpuHasNEON)) {
- SumSquareError = SumSquareError_NEON;
- }
-#endif
-#if defined(HAS_SUMSQUAREERROR_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) &&
- IS_ALIGNED(src_a, 16) && IS_ALIGNED(src_b, 16)) {
- // Note only used for multiples of 16 so count is not checked.
- SumSquareError = SumSquareError_SSE2;
- }
-#endif
-#if defined(HAS_SUMSQUAREERROR_AVX2)
- if (TestCpuFlag(kCpuHasAVX2)) {
- // Note only used for multiples of 32 so count is not checked.
- SumSquareError = SumSquareError_AVX2;
- }
-#endif
-#ifdef _OPENMP
-#pragma omp parallel for reduction(+: sse)
-#endif
- for (i = 0; i < (count - (kBlockSize - 1)); i += kBlockSize) {
- sse += SumSquareError(src_a + i, src_b + i, kBlockSize);
- }
- src_a += count & ~(kBlockSize - 1);
- src_b += count & ~(kBlockSize - 1);
- if (remainder) {
- sse += SumSquareError(src_a, src_b, remainder);
- src_a += remainder;
- src_b += remainder;
- }
- remainder = count & 31;
- if (remainder) {
- sse += SumSquareError_C(src_a, src_b, remainder);
- }
- return sse;
-}
-
-LIBYUV_API
-uint64 ComputeSumSquareErrorPlane(const uint8* src_a, int stride_a,
- const uint8* src_b, int stride_b,
- int width, int height) {
- uint64 sse = 0;
- int h;
- // Coalesce rows.
- if (stride_a == width &&
- stride_b == width) {
- width *= height;
- height = 1;
- stride_a = stride_b = 0;
- }
- for (h = 0; h < height; ++h) {
- sse += ComputeSumSquareError(src_a, src_b, width);
- src_a += stride_a;
- src_b += stride_b;
- }
- return sse;
-}
-
-LIBYUV_API
-double SumSquareErrorToPsnr(uint64 sse, uint64 count) {
- double psnr;
- if (sse > 0) {
- double mse = (double)(count) / (double)(sse);
- psnr = 10.0 * log10(255.0 * 255.0 * mse);
- } else {
- psnr = kMaxPsnr; // Limit to prevent divide by 0
- }
-
- if (psnr > kMaxPsnr)
- psnr = kMaxPsnr;
-
- return psnr;
-}
-
-LIBYUV_API
-double CalcFramePsnr(const uint8* src_a, int stride_a,
- const uint8* src_b, int stride_b,
- int width, int height) {
- const uint64 samples = width * height;
- const uint64 sse = ComputeSumSquareErrorPlane(src_a, stride_a,
- src_b, stride_b,
- width, height);
- return SumSquareErrorToPsnr(sse, samples);
-}
-
-LIBYUV_API
-double I420Psnr(const uint8* src_y_a, int stride_y_a,
- const uint8* src_u_a, int stride_u_a,
- const uint8* src_v_a, int stride_v_a,
- const uint8* src_y_b, int stride_y_b,
- const uint8* src_u_b, int stride_u_b,
- const uint8* src_v_b, int stride_v_b,
- int width, int height) {
- const uint64 sse_y = ComputeSumSquareErrorPlane(src_y_a, stride_y_a,
- src_y_b, stride_y_b,
- width, height);
- const int width_uv = (width + 1) >> 1;
- const int height_uv = (height + 1) >> 1;
- const uint64 sse_u = ComputeSumSquareErrorPlane(src_u_a, stride_u_a,
- src_u_b, stride_u_b,
- width_uv, height_uv);
- const uint64 sse_v = ComputeSumSquareErrorPlane(src_v_a, stride_v_a,
- src_v_b, stride_v_b,
- width_uv, height_uv);
- const uint64 samples = width * height + 2 * (width_uv * height_uv);
- const uint64 sse = sse_y + sse_u + sse_v;
- return SumSquareErrorToPsnr(sse, samples);
-}
-
-static const int64 cc1 = 26634; // (64^2*(.01*255)^2
-static const int64 cc2 = 239708; // (64^2*(.03*255)^2
-
-static double Ssim8x8_C(const uint8* src_a, int stride_a,
- const uint8* src_b, int stride_b) {
- int64 sum_a = 0;
- int64 sum_b = 0;
- int64 sum_sq_a = 0;
- int64 sum_sq_b = 0;
- int64 sum_axb = 0;
-
- int i;
- for (i = 0; i < 8; ++i) {
- int j;
- for (j = 0; j < 8; ++j) {
- sum_a += src_a[j];
- sum_b += src_b[j];
- sum_sq_a += src_a[j] * src_a[j];
- sum_sq_b += src_b[j] * src_b[j];
- sum_axb += src_a[j] * src_b[j];
- }
-
- src_a += stride_a;
- src_b += stride_b;
- }
-
- {
- const int64 count = 64;
- // scale the constants by number of pixels
- const int64 c1 = (cc1 * count * count) >> 12;
- const int64 c2 = (cc2 * count * count) >> 12;
-
- const int64 sum_a_x_sum_b = sum_a * sum_b;
-
- const int64 ssim_n = (2 * sum_a_x_sum_b + c1) *
- (2 * count * sum_axb - 2 * sum_a_x_sum_b + c2);
-
- const int64 sum_a_sq = sum_a*sum_a;
- const int64 sum_b_sq = sum_b*sum_b;
-
- const int64 ssim_d = (sum_a_sq + sum_b_sq + c1) *
- (count * sum_sq_a - sum_a_sq +
- count * sum_sq_b - sum_b_sq + c2);
-
- if (ssim_d == 0.0) {
- return DBL_MAX;
- }
- return ssim_n * 1.0 / ssim_d;
- }
-}
-
-// We are using a 8x8 moving window with starting location of each 8x8 window
-// on the 4x4 pixel grid. Such arrangement allows the windows to overlap
-// block boundaries to penalize blocking artifacts.
-LIBYUV_API
-double CalcFrameSsim(const uint8* src_a, int stride_a,
- const uint8* src_b, int stride_b,
- int width, int height) {
- int samples = 0;
- double ssim_total = 0;
- double (*Ssim8x8)(const uint8* src_a, int stride_a,
- const uint8* src_b, int stride_b) = Ssim8x8_C;
-
- // sample point start with each 4x4 location
- int i;
- for (i = 0; i < height - 8; i += 4) {
- int j;
- for (j = 0; j < width - 8; j += 4) {
- ssim_total += Ssim8x8(src_a + j, stride_a, src_b + j, stride_b);
- samples++;
- }
-
- src_a += stride_a * 4;
- src_b += stride_b * 4;
- }
-
- ssim_total /= samples;
- return ssim_total;
-}
-
-LIBYUV_API
-double I420Ssim(const uint8* src_y_a, int stride_y_a,
- const uint8* src_u_a, int stride_u_a,
- const uint8* src_v_a, int stride_v_a,
- const uint8* src_y_b, int stride_y_b,
- const uint8* src_u_b, int stride_u_b,
- const uint8* src_v_b, int stride_v_b,
- int width, int height) {
- const double ssim_y = CalcFrameSsim(src_y_a, stride_y_a,
- src_y_b, stride_y_b, width, height);
- const int width_uv = (width + 1) >> 1;
- const int height_uv = (height + 1) >> 1;
- const double ssim_u = CalcFrameSsim(src_u_a, stride_u_a,
- src_u_b, stride_u_b,
- width_uv, height_uv);
- const double ssim_v = CalcFrameSsim(src_v_a, stride_v_a,
- src_v_b, stride_v_b,
- width_uv, height_uv);
- return ssim_y * 0.8 + 0.1 * (ssim_u + ssim_v);
-}
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/compare_common.cc b/drivers/theoraplayer/src/YUV/libyuv/src/compare_common.cc
deleted file mode 100755
index c546b51829..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/compare_common.cc
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2012 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/basic_types.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-uint32 SumSquareError_C(const uint8* src_a, const uint8* src_b, int count) {
- uint32 sse = 0u;
- int i;
- for (i = 0; i < count; ++i) {
- int diff = src_a[i] - src_b[i];
- sse += (uint32)(diff * diff);
- }
- return sse;
-}
-
-// hash seed of 5381 recommended.
-// Internal C version of HashDjb2 with int sized count for efficiency.
-uint32 HashDjb2_C(const uint8* src, int count, uint32 seed) {
- uint32 hash = seed;
- int i;
- for (i = 0; i < count; ++i) {
- hash += (hash << 5) + src[i];
- }
- return hash;
-}
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/compare_neon.cc b/drivers/theoraplayer/src/YUV/libyuv/src/compare_neon.cc
deleted file mode 100755
index bb843a6ab8..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/compare_neon.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2012 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/basic_types.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-#if !defined(LIBYUV_DISABLE_NEON) && defined(__ARM_NEON__)
-
-uint32 SumSquareError_NEON(const uint8* src_a, const uint8* src_b, int count) {
- volatile uint32 sse;
- asm volatile (
-#ifdef _ANDROID
- ".fpu neon\n"
-#endif
- "vmov.u8 q8, #0 \n"
- "vmov.u8 q10, #0 \n"
- "vmov.u8 q9, #0 \n"
- "vmov.u8 q11, #0 \n"
-
- ".p2align 2 \n"
- "1: \n"
- "vld1.8 {q0}, [%0]! \n"
- "vld1.8 {q1}, [%1]! \n"
- "subs %2, %2, #16 \n"
- "vsubl.u8 q2, d0, d2 \n"
- "vsubl.u8 q3, d1, d3 \n"
- "vmlal.s16 q8, d4, d4 \n"
- "vmlal.s16 q9, d6, d6 \n"
- "vmlal.s16 q10, d5, d5 \n"
- "vmlal.s16 q11, d7, d7 \n"
- "bgt 1b \n"
-
- "vadd.u32 q8, q8, q9 \n"
- "vadd.u32 q10, q10, q11 \n"
- "vadd.u32 q11, q8, q10 \n"
- "vpaddl.u32 q1, q11 \n"
- "vadd.u64 d0, d2, d3 \n"
- "vmov.32 %3, d0[0] \n"
- : "+r"(src_a),
- "+r"(src_b),
- "+r"(count),
- "=r"(sse)
- :
- : "memory", "cc", "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11");
- return sse;
-}
-
-#endif // __ARM_NEON__
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/compare_posix.cc b/drivers/theoraplayer/src/YUV/libyuv/src/compare_posix.cc
deleted file mode 100755
index ac361190e8..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/compare_posix.cc
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright 2012 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/basic_types.h"
-#include "libyuv/row.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-#if !defined(LIBYUV_DISABLE_X86) && (defined(__x86_64__) || defined(__i386__))
-
-uint32 SumSquareError_SSE2(const uint8* src_a, const uint8* src_b, int count) {
- uint32 sse;
- asm volatile ( // NOLINT
- "pxor %%xmm0,%%xmm0 \n"
- "pxor %%xmm5,%%xmm5 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm1 \n"
- "lea " MEMLEA(0x10, 0) ",%0 \n"
- "movdqa " MEMACCESS(1) ",%%xmm2 \n"
- "lea " MEMLEA(0x10, 1) ",%1 \n"
- "sub $0x10,%2 \n"
- "movdqa %%xmm1,%%xmm3 \n"
- "psubusb %%xmm2,%%xmm1 \n"
- "psubusb %%xmm3,%%xmm2 \n"
- "por %%xmm2,%%xmm1 \n"
- "movdqa %%xmm1,%%xmm2 \n"
- "punpcklbw %%xmm5,%%xmm1 \n"
- "punpckhbw %%xmm5,%%xmm2 \n"
- "pmaddwd %%xmm1,%%xmm1 \n"
- "pmaddwd %%xmm2,%%xmm2 \n"
- "paddd %%xmm1,%%xmm0 \n"
- "paddd %%xmm2,%%xmm0 \n"
- "jg 1b \n"
-
- "pshufd $0xee,%%xmm0,%%xmm1 \n"
- "paddd %%xmm1,%%xmm0 \n"
- "pshufd $0x1,%%xmm0,%%xmm1 \n"
- "paddd %%xmm1,%%xmm0 \n"
- "movd %%xmm0,%3 \n"
-
- : "+r"(src_a), // %0
- "+r"(src_b), // %1
- "+r"(count), // %2
- "=g"(sse) // %3
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"
-#endif
- ); // NOLINT
- return sse;
-}
-
-#endif // defined(__x86_64__) || defined(__i386__)
-
-#if !defined(LIBYUV_DISABLE_X86) && \
- (defined(__x86_64__) || (defined(__i386__) && !defined(__pic__)))
-#define HAS_HASHDJB2_SSE41
-static uvec32 kHash16x33 = { 0x92d9e201, 0, 0, 0 }; // 33 ^ 16
-static uvec32 kHashMul0 = {
- 0x0c3525e1, // 33 ^ 15
- 0xa3476dc1, // 33 ^ 14
- 0x3b4039a1, // 33 ^ 13
- 0x4f5f0981, // 33 ^ 12
-};
-static uvec32 kHashMul1 = {
- 0x30f35d61, // 33 ^ 11
- 0x855cb541, // 33 ^ 10
- 0x040a9121, // 33 ^ 9
- 0x747c7101, // 33 ^ 8
-};
-static uvec32 kHashMul2 = {
- 0xec41d4e1, // 33 ^ 7
- 0x4cfa3cc1, // 33 ^ 6
- 0x025528a1, // 33 ^ 5
- 0x00121881, // 33 ^ 4
-};
-static uvec32 kHashMul3 = {
- 0x00008c61, // 33 ^ 3
- 0x00000441, // 33 ^ 2
- 0x00000021, // 33 ^ 1
- 0x00000001, // 33 ^ 0
-};
-
-uint32 HashDjb2_SSE41(const uint8* src, int count, uint32 seed) {
- uint32 hash;
- asm volatile ( // NOLINT
- "movd %2,%%xmm0 \n"
- "pxor %%xmm7,%%xmm7 \n"
- "movdqa %4,%%xmm6 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm1 \n"
- "lea " MEMLEA(0x10, 0) ",%0 \n"
- "pmulld %%xmm6,%%xmm0 \n"
- "movdqa %5,%%xmm5 \n"
- "movdqa %%xmm1,%%xmm2 \n"
- "punpcklbw %%xmm7,%%xmm2 \n"
- "movdqa %%xmm2,%%xmm3 \n"
- "punpcklwd %%xmm7,%%xmm3 \n"
- "pmulld %%xmm5,%%xmm3 \n"
- "movdqa %6,%%xmm5 \n"
- "movdqa %%xmm2,%%xmm4 \n"
- "punpckhwd %%xmm7,%%xmm4 \n"
- "pmulld %%xmm5,%%xmm4 \n"
- "movdqa %7,%%xmm5 \n"
- "punpckhbw %%xmm7,%%xmm1 \n"
- "movdqa %%xmm1,%%xmm2 \n"
- "punpcklwd %%xmm7,%%xmm2 \n"
- "pmulld %%xmm5,%%xmm2 \n"
- "movdqa %8,%%xmm5 \n"
- "punpckhwd %%xmm7,%%xmm1 \n"
- "pmulld %%xmm5,%%xmm1 \n"
- "paddd %%xmm4,%%xmm3 \n"
- "paddd %%xmm2,%%xmm1 \n"
- "sub $0x10,%1 \n"
- "paddd %%xmm3,%%xmm1 \n"
- "pshufd $0xe,%%xmm1,%%xmm2 \n"
- "paddd %%xmm2,%%xmm1 \n"
- "pshufd $0x1,%%xmm1,%%xmm2 \n"
- "paddd %%xmm2,%%xmm1 \n"
- "paddd %%xmm1,%%xmm0 \n"
- "jg 1b \n"
- "movd %%xmm0,%3 \n"
- : "+r"(src), // %0
- "+r"(count), // %1
- "+rm"(seed), // %2
- "=g"(hash) // %3
- : "m"(kHash16x33), // %4
- "m"(kHashMul0), // %5
- "m"(kHashMul1), // %6
- "m"(kHashMul2), // %7
- "m"(kHashMul3) // %8
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
-#endif
- ); // NOLINT
- return hash;
-}
-#endif // defined(__x86_64__) || (defined(__i386__) && !defined(__pic__)))
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
-
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/compare_win.cc b/drivers/theoraplayer/src/YUV/libyuv/src/compare_win.cc
deleted file mode 100755
index 99831651f5..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/compare_win.cc
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Copyright 2012 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/basic_types.h"
-#include "libyuv/row.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-#if !defined(LIBYUV_DISABLE_X86) && defined(_M_IX86) && defined(_MSC_VER)
-
-__declspec(naked) __declspec(align(16))
-uint32 SumSquareError_SSE2(const uint8* src_a, const uint8* src_b, int count) {
- __asm {
- mov eax, [esp + 4] // src_a
- mov edx, [esp + 8] // src_b
- mov ecx, [esp + 12] // count
- pxor xmm0, xmm0
- pxor xmm5, xmm5
-
- align 4
- wloop:
- movdqa xmm1, [eax]
- lea eax, [eax + 16]
- movdqa xmm2, [edx]
- lea edx, [edx + 16]
- sub ecx, 16
- movdqa xmm3, xmm1 // abs trick
- psubusb xmm1, xmm2
- psubusb xmm2, xmm3
- por xmm1, xmm2
- movdqa xmm2, xmm1
- punpcklbw xmm1, xmm5
- punpckhbw xmm2, xmm5
- pmaddwd xmm1, xmm1
- pmaddwd xmm2, xmm2
- paddd xmm0, xmm1
- paddd xmm0, xmm2
- jg wloop
-
- pshufd xmm1, xmm0, 0xee
- paddd xmm0, xmm1
- pshufd xmm1, xmm0, 0x01
- paddd xmm0, xmm1
- movd eax, xmm0
- ret
- }
-}
-
-// Visual C 2012 required for AVX2.
-#if _MSC_VER >= 1700
-// C4752: found Intel(R) Advanced Vector Extensions; consider using /arch:AVX.
-#pragma warning(disable: 4752)
-__declspec(naked) __declspec(align(16))
-uint32 SumSquareError_AVX2(const uint8* src_a, const uint8* src_b, int count) {
- __asm {
- mov eax, [esp + 4] // src_a
- mov edx, [esp + 8] // src_b
- mov ecx, [esp + 12] // count
- vpxor ymm0, ymm0, ymm0 // sum
- vpxor ymm5, ymm5, ymm5 // constant 0 for unpck
- sub edx, eax
-
- align 4
- wloop:
- vmovdqu ymm1, [eax]
- vmovdqu ymm2, [eax + edx]
- lea eax, [eax + 32]
- sub ecx, 32
- vpsubusb ymm3, ymm1, ymm2 // abs difference trick
- vpsubusb ymm2, ymm2, ymm1
- vpor ymm1, ymm2, ymm3
- vpunpcklbw ymm2, ymm1, ymm5 // u16. mutates order.
- vpunpckhbw ymm1, ymm1, ymm5
- vpmaddwd ymm2, ymm2, ymm2 // square + hadd to u32.
- vpmaddwd ymm1, ymm1, ymm1
- vpaddd ymm0, ymm0, ymm1
- vpaddd ymm0, ymm0, ymm2
- jg wloop
-
- vpshufd ymm1, ymm0, 0xee // 3, 2 + 1, 0 both lanes.
- vpaddd ymm0, ymm0, ymm1
- vpshufd ymm1, ymm0, 0x01 // 1 + 0 both lanes.
- vpaddd ymm0, ymm0, ymm1
- vpermq ymm1, ymm0, 0x02 // high + low lane.
- vpaddd ymm0, ymm0, ymm1
- vmovd eax, xmm0
- vzeroupper
- ret
- }
-}
-#endif // _MSC_VER >= 1700
-
-#define HAS_HASHDJB2_SSE41
-static uvec32 kHash16x33 = { 0x92d9e201, 0, 0, 0 }; // 33 ^ 16
-static uvec32 kHashMul0 = {
- 0x0c3525e1, // 33 ^ 15
- 0xa3476dc1, // 33 ^ 14
- 0x3b4039a1, // 33 ^ 13
- 0x4f5f0981, // 33 ^ 12
-};
-static uvec32 kHashMul1 = {
- 0x30f35d61, // 33 ^ 11
- 0x855cb541, // 33 ^ 10
- 0x040a9121, // 33 ^ 9
- 0x747c7101, // 33 ^ 8
-};
-static uvec32 kHashMul2 = {
- 0xec41d4e1, // 33 ^ 7
- 0x4cfa3cc1, // 33 ^ 6
- 0x025528a1, // 33 ^ 5
- 0x00121881, // 33 ^ 4
-};
-static uvec32 kHashMul3 = {
- 0x00008c61, // 33 ^ 3
- 0x00000441, // 33 ^ 2
- 0x00000021, // 33 ^ 1
- 0x00000001, // 33 ^ 0
-};
-
-// 27: 66 0F 38 40 C6 pmulld xmm0,xmm6
-// 44: 66 0F 38 40 DD pmulld xmm3,xmm5
-// 59: 66 0F 38 40 E5 pmulld xmm4,xmm5
-// 72: 66 0F 38 40 D5 pmulld xmm2,xmm5
-// 83: 66 0F 38 40 CD pmulld xmm1,xmm5
-#define pmulld(reg) _asm _emit 0x66 _asm _emit 0x0F _asm _emit 0x38 \
- _asm _emit 0x40 _asm _emit reg
-
-__declspec(naked) __declspec(align(16))
-uint32 HashDjb2_SSE41(const uint8* src, int count, uint32 seed) {
- __asm {
- mov eax, [esp + 4] // src
- mov ecx, [esp + 8] // count
- movd xmm0, [esp + 12] // seed
-
- pxor xmm7, xmm7 // constant 0 for unpck
- movdqa xmm6, kHash16x33
-
- align 4
- wloop:
- movdqu xmm1, [eax] // src[0-15]
- lea eax, [eax + 16]
- pmulld(0xc6) // pmulld xmm0,xmm6 hash *= 33 ^ 16
- movdqa xmm5, kHashMul0
- movdqa xmm2, xmm1
- punpcklbw xmm2, xmm7 // src[0-7]
- movdqa xmm3, xmm2
- punpcklwd xmm3, xmm7 // src[0-3]
- pmulld(0xdd) // pmulld xmm3, xmm5
- movdqa xmm5, kHashMul1
- movdqa xmm4, xmm2
- punpckhwd xmm4, xmm7 // src[4-7]
- pmulld(0xe5) // pmulld xmm4, xmm5
- movdqa xmm5, kHashMul2
- punpckhbw xmm1, xmm7 // src[8-15]
- movdqa xmm2, xmm1
- punpcklwd xmm2, xmm7 // src[8-11]
- pmulld(0xd5) // pmulld xmm2, xmm5
- movdqa xmm5, kHashMul3
- punpckhwd xmm1, xmm7 // src[12-15]
- pmulld(0xcd) // pmulld xmm1, xmm5
- paddd xmm3, xmm4 // add 16 results
- paddd xmm1, xmm2
- sub ecx, 16
- paddd xmm1, xmm3
-
- pshufd xmm2, xmm1, 0x0e // upper 2 dwords
- paddd xmm1, xmm2
- pshufd xmm2, xmm1, 0x01
- paddd xmm1, xmm2
- paddd xmm0, xmm1
- jg wloop
-
- movd eax, xmm0 // return hash
- ret
- }
-}
-
-// Visual C 2012 required for AVX2.
-#if _MSC_VER >= 1700
-__declspec(naked) __declspec(align(16))
-uint32 HashDjb2_AVX2(const uint8* src, int count, uint32 seed) {
- __asm {
- mov eax, [esp + 4] // src
- mov ecx, [esp + 8] // count
- movd xmm0, [esp + 12] // seed
- movdqa xmm6, kHash16x33
-
- align 4
- wloop:
- vpmovzxbd xmm3, dword ptr [eax] // src[0-3]
- pmulld xmm0, xmm6 // hash *= 33 ^ 16
- vpmovzxbd xmm4, dword ptr [eax + 4] // src[4-7]
- pmulld xmm3, kHashMul0
- vpmovzxbd xmm2, dword ptr [eax + 8] // src[8-11]
- pmulld xmm4, kHashMul1
- vpmovzxbd xmm1, dword ptr [eax + 12] // src[12-15]
- pmulld xmm2, kHashMul2
- lea eax, [eax + 16]
- pmulld xmm1, kHashMul3
- paddd xmm3, xmm4 // add 16 results
- paddd xmm1, xmm2
- sub ecx, 16
- paddd xmm1, xmm3
- pshufd xmm2, xmm1, 0x0e // upper 2 dwords
- paddd xmm1, xmm2
- pshufd xmm2, xmm1, 0x01
- paddd xmm1, xmm2
- paddd xmm0, xmm1
- jg wloop
-
- movd eax, xmm0 // return hash
- ret
- }
-}
-#endif // _MSC_VER >= 1700
-
-#endif // !defined(LIBYUV_DISABLE_X86) && defined(_M_IX86) && defined(_MSC_VER)
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/convert.cc b/drivers/theoraplayer/src/YUV/libyuv/src/convert.cc
deleted file mode 100755
index c8408dc798..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/convert.cc
+++ /dev/null
@@ -1,1491 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/convert.h"
-
-#include "libyuv/basic_types.h"
-#include "libyuv/cpu_id.h"
-#include "libyuv/planar_functions.h"
-#include "libyuv/rotate.h"
-#include "libyuv/scale.h" // For ScalePlane()
-#include "libyuv/row.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-#define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
-static __inline int Abs(int v) {
- return v >= 0 ? v : -v;
-}
-
-// Any I4xx To I420 format with mirroring.
-static int I4xxToI420(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int src_y_width, int src_y_height,
- int src_uv_width, int src_uv_height) {
- if (src_y_width == 0 || src_y_height == 0 ||
- src_uv_width == 0 || src_uv_height == 0) {
- return -1;
- }
- const int dst_y_width = Abs(src_y_width);
- const int dst_y_height = Abs(src_y_height);
- const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1);
- const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1);
- ScalePlane(src_y, src_stride_y, src_y_width, src_y_height,
- dst_y, dst_stride_y, dst_y_width, dst_y_height,
- kFilterBilinear);
- ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height,
- dst_u, dst_stride_u, dst_uv_width, dst_uv_height,
- kFilterBilinear);
- ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height,
- dst_v, dst_stride_v, dst_uv_width, dst_uv_height,
- kFilterBilinear);
- return 0;
-}
-
-// Copy I420 with optional flipping
-// TODO(fbarchard): Use Scale plane which supports mirroring, but ensure
-// is does row coalescing.
-LIBYUV_API
-int I420Copy(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- if (!src_y || !src_u || !src_v ||
- !dst_y || !dst_u || !dst_v ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- const int halfheight = (height + 1) >> 1;
- src_y = src_y + (height - 1) * src_stride_y;
- src_u = src_u + (halfheight - 1) * src_stride_u;
- src_v = src_v + (halfheight - 1) * src_stride_v;
- src_stride_y = -src_stride_y;
- src_stride_u = -src_stride_u;
- src_stride_v = -src_stride_v;
- }
-
- if (dst_y) {
- CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
- }
- // Copy UV planes.
- const int halfwidth = (width + 1) >> 1;
- const int halfheight = (height + 1) >> 1;
- CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
- CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
- return 0;
-}
-
-// 422 chroma is 1/2 width, 1x height
-// 420 chroma is 1/2 width, 1/2 height
-LIBYUV_API
-int I422ToI420(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- const int src_uv_width = SUBSAMPLE(width, 1, 1);
- return I4xxToI420(src_y, src_stride_y,
- src_u, src_stride_u,
- src_v, src_stride_v,
- dst_y, dst_stride_y,
- dst_u, dst_stride_u,
- dst_v, dst_stride_v,
- width, height,
- src_uv_width, height);
-}
-
-// 444 chroma is 1x width, 1x height
-// 420 chroma is 1/2 width, 1/2 height
-LIBYUV_API
-int I444ToI420(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- return I4xxToI420(src_y, src_stride_y,
- src_u, src_stride_u,
- src_v, src_stride_v,
- dst_y, dst_stride_y,
- dst_u, dst_stride_u,
- dst_v, dst_stride_v,
- width, height,
- width, height);
-}
-
-// 411 chroma is 1/4 width, 1x height
-// 420 chroma is 1/2 width, 1/2 height
-LIBYUV_API
-int I411ToI420(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- const int src_uv_width = SUBSAMPLE(width, 3, 2);
- return I4xxToI420(src_y, src_stride_y,
- src_u, src_stride_u,
- src_v, src_stride_v,
- dst_y, dst_stride_y,
- dst_u, dst_stride_u,
- dst_v, dst_stride_v,
- width, height,
- src_uv_width, height);
-}
-
-// I400 is greyscale typically used in MJPG
-LIBYUV_API
-int I400ToI420(const uint8* src_y, int src_stride_y,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- if (!src_y || !dst_y || !dst_u || !dst_v ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_y = src_y + (height - 1) * src_stride_y;
- src_stride_y = -src_stride_y;
- }
- int halfwidth = (width + 1) >> 1;
- int halfheight = (height + 1) >> 1;
- CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
- SetPlane(dst_u, dst_stride_u, halfwidth, halfheight, 128);
- SetPlane(dst_v, dst_stride_v, halfwidth, halfheight, 128);
- return 0;
-}
-
-static void CopyPlane2(const uint8* src, int src_stride_0, int src_stride_1,
- uint8* dst, int dst_stride,
- int width, int height) {
- void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
-#if defined(HAS_COPYROW_X86)
- if (TestCpuFlag(kCpuHasX86) && IS_ALIGNED(width, 4)) {
- CopyRow = CopyRow_X86;
- }
-#endif
-#if defined(HAS_COPYROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 32) &&
- IS_ALIGNED(src, 16) &&
- IS_ALIGNED(src_stride_0, 16) && IS_ALIGNED(src_stride_1, 16) &&
- IS_ALIGNED(dst, 16) && IS_ALIGNED(dst_stride, 16)) {
- CopyRow = CopyRow_SSE2;
- }
-#endif
-#if defined(HAS_COPYROW_ERMS)
- if (TestCpuFlag(kCpuHasERMS)) {
- CopyRow = CopyRow_ERMS;
- }
-#endif
-#if defined(HAS_COPYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 32)) {
- CopyRow = CopyRow_NEON;
- }
-#endif
-#if defined(HAS_COPYROW_MIPS)
- if (TestCpuFlag(kCpuHasMIPS)) {
- CopyRow = CopyRow_MIPS;
- }
-#endif
-
- // Copy plane
- for (int y = 0; y < height - 1; y += 2) {
- CopyRow(src, dst, width);
- CopyRow(src + src_stride_0, dst + dst_stride, width);
- src += src_stride_0 + src_stride_1;
- dst += dst_stride * 2;
- }
- if (height & 1) {
- CopyRow(src, dst, width);
- }
-}
-
-// Support converting from FOURCC_M420
-// Useful for bandwidth constrained transports like USB 1.0 and 2.0 and for
-// easy conversion to I420.
-// M420 format description:
-// M420 is row biplanar 420: 2 rows of Y and 1 row of UV.
-// Chroma is half width / half height. (420)
-// src_stride_m420 is row planar. Normally this will be the width in pixels.
-// The UV plane is half width, but 2 values, so src_stride_m420 applies to
-// this as well as the two Y planes.
-static int X420ToI420(const uint8* src_y,
- int src_stride_y0, int src_stride_y1,
- const uint8* src_uv, int src_stride_uv,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- if (!src_y || !src_uv ||
- !dst_y || !dst_u || !dst_v ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- int halfheight = (height + 1) >> 1;
- dst_y = dst_y + (height - 1) * dst_stride_y;
- dst_u = dst_u + (halfheight - 1) * dst_stride_u;
- dst_v = dst_v + (halfheight - 1) * dst_stride_v;
- dst_stride_y = -dst_stride_y;
- dst_stride_u = -dst_stride_u;
- dst_stride_v = -dst_stride_v;
- }
- // Coalesce rows.
- int halfwidth = (width + 1) >> 1;
- int halfheight = (height + 1) >> 1;
- if (src_stride_y0 == width &&
- src_stride_y1 == width &&
- dst_stride_y == width) {
- width *= height;
- height = 1;
- src_stride_y0 = src_stride_y1 = dst_stride_y = 0;
- }
- // Coalesce rows.
- if (src_stride_uv == halfwidth * 2 &&
- dst_stride_u == halfwidth &&
- dst_stride_v == halfwidth) {
- halfwidth *= halfheight;
- halfheight = 1;
- src_stride_uv = dst_stride_u = dst_stride_v = 0;
- }
- void (*SplitUVRow)(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int pix) =
- SplitUVRow_C;
-#if defined(HAS_SPLITUVROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && halfwidth >= 16) {
- SplitUVRow = SplitUVRow_Any_SSE2;
- if (IS_ALIGNED(halfwidth, 16)) {
- SplitUVRow = SplitUVRow_Unaligned_SSE2;
- if (IS_ALIGNED(src_uv, 16) && IS_ALIGNED(src_stride_uv, 16) &&
- IS_ALIGNED(dst_u, 16) && IS_ALIGNED(dst_stride_u, 16) &&
- IS_ALIGNED(dst_v, 16) && IS_ALIGNED(dst_stride_v, 16)) {
- SplitUVRow = SplitUVRow_SSE2;
- }
- }
- }
-#endif
-#if defined(HAS_SPLITUVROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && halfwidth >= 32) {
- SplitUVRow = SplitUVRow_Any_AVX2;
- if (IS_ALIGNED(halfwidth, 32)) {
- SplitUVRow = SplitUVRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_SPLITUVROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && halfwidth >= 16) {
- SplitUVRow = SplitUVRow_Any_NEON;
- if (IS_ALIGNED(halfwidth, 16)) {
- SplitUVRow = SplitUVRow_NEON;
- }
- }
-#endif
-#if defined(HAS_SPLITUVROW_MIPS_DSPR2)
- if (TestCpuFlag(kCpuHasMIPS_DSPR2) && halfwidth >= 16) {
- SplitUVRow = SplitUVRow_Any_MIPS_DSPR2;
- if (IS_ALIGNED(halfwidth, 16)) {
- SplitUVRow = SplitUVRow_Unaligned_MIPS_DSPR2;
- if (IS_ALIGNED(src_uv, 4) && IS_ALIGNED(src_stride_uv, 4) &&
- IS_ALIGNED(dst_u, 4) && IS_ALIGNED(dst_stride_u, 4) &&
- IS_ALIGNED(dst_v, 4) && IS_ALIGNED(dst_stride_v, 4)) {
- SplitUVRow = SplitUVRow_MIPS_DSPR2;
- }
- }
- }
-#endif
-
- if (dst_y) {
- if (src_stride_y0 == src_stride_y1) {
- CopyPlane(src_y, src_stride_y0, dst_y, dst_stride_y, width, height);
- } else {
- CopyPlane2(src_y, src_stride_y0, src_stride_y1, dst_y, dst_stride_y,
- width, height);
- }
- }
-
- for (int y = 0; y < halfheight; ++y) {
- // Copy a row of UV.
- SplitUVRow(src_uv, dst_u, dst_v, halfwidth);
- dst_u += dst_stride_u;
- dst_v += dst_stride_v;
- src_uv += src_stride_uv;
- }
- return 0;
-}
-
-// Convert NV12 to I420.
-LIBYUV_API
-int NV12ToI420(const uint8* src_y, int src_stride_y,
- const uint8* src_uv, int src_stride_uv,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- return X420ToI420(src_y, src_stride_y, src_stride_y,
- src_uv, src_stride_uv,
- dst_y, dst_stride_y,
- dst_u, dst_stride_u,
- dst_v, dst_stride_v,
- width, height);
-}
-
-// Convert NV21 to I420. Same as NV12 but u and v pointers swapped.
-LIBYUV_API
-int NV21ToI420(const uint8* src_y, int src_stride_y,
- const uint8* src_vu, int src_stride_vu,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- return X420ToI420(src_y, src_stride_y, src_stride_y,
- src_vu, src_stride_vu,
- dst_y, dst_stride_y,
- dst_v, dst_stride_v,
- dst_u, dst_stride_u,
- width, height);
-}
-
-// Convert M420 to I420.
-LIBYUV_API
-int M420ToI420(const uint8* src_m420, int src_stride_m420,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- return X420ToI420(src_m420, src_stride_m420, src_stride_m420 * 2,
- src_m420 + src_stride_m420 * 2, src_stride_m420 * 3,
- dst_y, dst_stride_y,
- dst_u, dst_stride_u,
- dst_v, dst_stride_v,
- width, height);
-}
-
-// Convert Q420 to I420.
-// Format is rows of YY/YUYV
-LIBYUV_API
-int Q420ToI420(const uint8* src_y, int src_stride_y,
- const uint8* src_yuy2, int src_stride_yuy2,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- if (!src_y || !src_yuy2 ||
- !dst_y || !dst_u || !dst_v ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- int halfheight = (height + 1) >> 1;
- dst_y = dst_y + (height - 1) * dst_stride_y;
- dst_u = dst_u + (halfheight - 1) * dst_stride_u;
- dst_v = dst_v + (halfheight - 1) * dst_stride_v;
- dst_stride_y = -dst_stride_y;
- dst_stride_u = -dst_stride_u;
- dst_stride_v = -dst_stride_v;
- }
- // CopyRow for rows of just Y in Q420 copied to Y plane of I420.
- void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
-#if defined(HAS_COPYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 32)) {
- CopyRow = CopyRow_NEON;
- }
-#endif
-#if defined(HAS_COPYROW_X86)
- if (IS_ALIGNED(width, 4)) {
- CopyRow = CopyRow_X86;
- }
-#endif
-#if defined(HAS_COPYROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 32) &&
- IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) &&
- IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
- CopyRow = CopyRow_SSE2;
- }
-#endif
-#if defined(HAS_COPYROW_ERMS)
- if (TestCpuFlag(kCpuHasERMS)) {
- CopyRow = CopyRow_ERMS;
- }
-#endif
-#if defined(HAS_COPYROW_MIPS)
- if (TestCpuFlag(kCpuHasMIPS)) {
- CopyRow = CopyRow_MIPS;
- }
-#endif
-
- void (*YUY2ToUV422Row)(const uint8* src_yuy2, uint8* dst_u, uint8* dst_v,
- int pix) = YUY2ToUV422Row_C;
- void (*YUY2ToYRow)(const uint8* src_yuy2, uint8* dst_y, int pix) =
- YUY2ToYRow_C;
-#if defined(HAS_YUY2TOYROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
- YUY2ToUV422Row = YUY2ToUV422Row_Any_SSE2;
- YUY2ToYRow = YUY2ToYRow_Any_SSE2;
- if (IS_ALIGNED(width, 16)) {
- YUY2ToUV422Row = YUY2ToUV422Row_Unaligned_SSE2;
- YUY2ToYRow = YUY2ToYRow_Unaligned_SSE2;
- if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16)) {
- YUY2ToUV422Row = YUY2ToUV422Row_SSE2;
- if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
- YUY2ToYRow = YUY2ToYRow_SSE2;
- }
- }
- }
- }
-#endif
-#if defined(HAS_YUY2TOYROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
- YUY2ToUV422Row = YUY2ToUV422Row_Any_AVX2;
- YUY2ToYRow = YUY2ToYRow_Any_AVX2;
- if (IS_ALIGNED(width, 32)) {
- YUY2ToUV422Row = YUY2ToUV422Row_AVX2;
- YUY2ToYRow = YUY2ToYRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_YUY2TOYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- YUY2ToYRow = YUY2ToYRow_Any_NEON;
- if (width >= 16) {
- YUY2ToUV422Row = YUY2ToUV422Row_Any_NEON;
- }
- if (IS_ALIGNED(width, 16)) {
- YUY2ToYRow = YUY2ToYRow_NEON;
- YUY2ToUV422Row = YUY2ToUV422Row_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height - 1; y += 2) {
- CopyRow(src_y, dst_y, width);
- src_y += src_stride_y;
- dst_y += dst_stride_y;
-
- YUY2ToUV422Row(src_yuy2, dst_u, dst_v, width);
- YUY2ToYRow(src_yuy2, dst_y, width);
- src_yuy2 += src_stride_yuy2;
- dst_y += dst_stride_y;
- dst_u += dst_stride_u;
- dst_v += dst_stride_v;
- }
- if (height & 1) {
- CopyRow(src_y, dst_y, width);
- YUY2ToUV422Row(src_yuy2, dst_u, dst_v, width);
- }
- return 0;
-}
-
-// Convert YUY2 to I420.
-LIBYUV_API
-int YUY2ToI420(const uint8* src_yuy2, int src_stride_yuy2,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
- src_stride_yuy2 = -src_stride_yuy2;
- }
- void (*YUY2ToUVRow)(const uint8* src_yuy2, int src_stride_yuy2,
- uint8* dst_u, uint8* dst_v, int pix);
- void (*YUY2ToYRow)(const uint8* src_yuy2,
- uint8* dst_y, int pix);
- YUY2ToYRow = YUY2ToYRow_C;
- YUY2ToUVRow = YUY2ToUVRow_C;
-#if defined(HAS_YUY2TOYROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
- YUY2ToUVRow = YUY2ToUVRow_Any_SSE2;
- YUY2ToYRow = YUY2ToYRow_Any_SSE2;
- if (IS_ALIGNED(width, 16)) {
- YUY2ToUVRow = YUY2ToUVRow_Unaligned_SSE2;
- YUY2ToYRow = YUY2ToYRow_Unaligned_SSE2;
- if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16)) {
- YUY2ToUVRow = YUY2ToUVRow_SSE2;
- if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
- YUY2ToYRow = YUY2ToYRow_SSE2;
- }
- }
- }
- }
-#endif
-#if defined(HAS_YUY2TOYROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
- YUY2ToUVRow = YUY2ToUVRow_Any_AVX2;
- YUY2ToYRow = YUY2ToYRow_Any_AVX2;
- if (IS_ALIGNED(width, 32)) {
- YUY2ToUVRow = YUY2ToUVRow_AVX2;
- YUY2ToYRow = YUY2ToYRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_YUY2TOYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- YUY2ToYRow = YUY2ToYRow_Any_NEON;
- if (width >= 16) {
- YUY2ToUVRow = YUY2ToUVRow_Any_NEON;
- }
- if (IS_ALIGNED(width, 16)) {
- YUY2ToYRow = YUY2ToYRow_NEON;
- YUY2ToUVRow = YUY2ToUVRow_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height - 1; y += 2) {
- YUY2ToUVRow(src_yuy2, src_stride_yuy2, dst_u, dst_v, width);
- YUY2ToYRow(src_yuy2, dst_y, width);
- YUY2ToYRow(src_yuy2 + src_stride_yuy2, dst_y + dst_stride_y, width);
- src_yuy2 += src_stride_yuy2 * 2;
- dst_y += dst_stride_y * 2;
- dst_u += dst_stride_u;
- dst_v += dst_stride_v;
- }
- if (height & 1) {
- YUY2ToUVRow(src_yuy2, 0, dst_u, dst_v, width);
- YUY2ToYRow(src_yuy2, dst_y, width);
- }
- return 0;
-}
-
-// Convert UYVY to I420.
-LIBYUV_API
-int UYVYToI420(const uint8* src_uyvy, int src_stride_uyvy,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
- src_stride_uyvy = -src_stride_uyvy;
- }
- void (*UYVYToUVRow)(const uint8* src_uyvy, int src_stride_uyvy,
- uint8* dst_u, uint8* dst_v, int pix);
- void (*UYVYToYRow)(const uint8* src_uyvy,
- uint8* dst_y, int pix);
- UYVYToYRow = UYVYToYRow_C;
- UYVYToUVRow = UYVYToUVRow_C;
-#if defined(HAS_UYVYTOYROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
- UYVYToUVRow = UYVYToUVRow_Any_SSE2;
- UYVYToYRow = UYVYToYRow_Any_SSE2;
- if (IS_ALIGNED(width, 16)) {
- UYVYToUVRow = UYVYToUVRow_Unaligned_SSE2;
- UYVYToYRow = UYVYToYRow_Unaligned_SSE2;
- if (IS_ALIGNED(src_uyvy, 16) && IS_ALIGNED(src_stride_uyvy, 16)) {
- UYVYToUVRow = UYVYToUVRow_SSE2;
- if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
- UYVYToYRow = UYVYToYRow_SSE2;
- }
- }
- }
- }
-#endif
-#if defined(HAS_UYVYTOYROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
- UYVYToUVRow = UYVYToUVRow_Any_AVX2;
- UYVYToYRow = UYVYToYRow_Any_AVX2;
- if (IS_ALIGNED(width, 32)) {
- UYVYToUVRow = UYVYToUVRow_AVX2;
- UYVYToYRow = UYVYToYRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_UYVYTOYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- UYVYToYRow = UYVYToYRow_Any_NEON;
- if (width >= 16) {
- UYVYToUVRow = UYVYToUVRow_Any_NEON;
- }
- if (IS_ALIGNED(width, 16)) {
- UYVYToYRow = UYVYToYRow_NEON;
- UYVYToUVRow = UYVYToUVRow_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height - 1; y += 2) {
- UYVYToUVRow(src_uyvy, src_stride_uyvy, dst_u, dst_v, width);
- UYVYToYRow(src_uyvy, dst_y, width);
- UYVYToYRow(src_uyvy + src_stride_uyvy, dst_y + dst_stride_y, width);
- src_uyvy += src_stride_uyvy * 2;
- dst_y += dst_stride_y * 2;
- dst_u += dst_stride_u;
- dst_v += dst_stride_v;
- }
- if (height & 1) {
- UYVYToUVRow(src_uyvy, 0, dst_u, dst_v, width);
- UYVYToYRow(src_uyvy, dst_y, width);
- }
- return 0;
-}
-
-// Convert ARGB to I420.
-LIBYUV_API
-int ARGBToI420(const uint8* src_argb, int src_stride_argb,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- if (!src_argb ||
- !dst_y || !dst_u || !dst_v ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
- void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
- ARGBToYRow_C;
-#if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
- ARGBToYRow = ARGBToYRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToUVRow = ARGBToUVRow_Unaligned_SSSE3;
- ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
- if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) {
- ARGBToUVRow = ARGBToUVRow_SSSE3;
- if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
- ARGBToYRow = ARGBToYRow_SSSE3;
- }
- }
- }
- }
-#endif
-#if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
- ARGBToUVRow = ARGBToUVRow_Any_AVX2;
- ARGBToYRow = ARGBToYRow_Any_AVX2;
- if (IS_ALIGNED(width, 32)) {
- ARGBToUVRow = ARGBToUVRow_AVX2;
- ARGBToYRow = ARGBToYRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_ARGBTOYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGBToYRow = ARGBToYRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGBToYRow = ARGBToYRow_NEON;
- }
- if (width >= 16) {
- ARGBToUVRow = ARGBToUVRow_Any_NEON;
- if (IS_ALIGNED(width, 16)) {
- ARGBToUVRow = ARGBToUVRow_NEON;
- }
- }
- }
-#endif
-
- for (int y = 0; y < height - 1; y += 2) {
- ARGBToUVRow(src_argb, src_stride_argb, dst_u, dst_v, width);
- ARGBToYRow(src_argb, dst_y, width);
- ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
- src_argb += src_stride_argb * 2;
- dst_y += dst_stride_y * 2;
- dst_u += dst_stride_u;
- dst_v += dst_stride_v;
- }
- if (height & 1) {
- ARGBToUVRow(src_argb, 0, dst_u, dst_v, width);
- ARGBToYRow(src_argb, dst_y, width);
- }
- return 0;
-}
-
-// Convert BGRA to I420.
-LIBYUV_API
-int BGRAToI420(const uint8* src_bgra, int src_stride_bgra,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- if (!src_bgra ||
- !dst_y || !dst_u || !dst_v ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_bgra = src_bgra + (height - 1) * src_stride_bgra;
- src_stride_bgra = -src_stride_bgra;
- }
- void (*BGRAToUVRow)(const uint8* src_bgra0, int src_stride_bgra,
- uint8* dst_u, uint8* dst_v, int width) = BGRAToUVRow_C;
- void (*BGRAToYRow)(const uint8* src_bgra, uint8* dst_y, int pix) =
- BGRAToYRow_C;
-#if defined(HAS_BGRATOYROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- BGRAToUVRow = BGRAToUVRow_Any_SSSE3;
- BGRAToYRow = BGRAToYRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- BGRAToUVRow = BGRAToUVRow_Unaligned_SSSE3;
- BGRAToYRow = BGRAToYRow_Unaligned_SSSE3;
- if (IS_ALIGNED(src_bgra, 16) && IS_ALIGNED(src_stride_bgra, 16)) {
- BGRAToUVRow = BGRAToUVRow_SSSE3;
- if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
- BGRAToYRow = BGRAToYRow_SSSE3;
- }
- }
- }
- }
-#elif defined(HAS_BGRATOYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- BGRAToYRow = BGRAToYRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- BGRAToYRow = BGRAToYRow_NEON;
- }
- if (width >= 16) {
- BGRAToUVRow = BGRAToUVRow_Any_NEON;
- if (IS_ALIGNED(width, 16)) {
- BGRAToUVRow = BGRAToUVRow_NEON;
- }
- }
- }
-#endif
-
- for (int y = 0; y < height - 1; y += 2) {
- BGRAToUVRow(src_bgra, src_stride_bgra, dst_u, dst_v, width);
- BGRAToYRow(src_bgra, dst_y, width);
- BGRAToYRow(src_bgra + src_stride_bgra, dst_y + dst_stride_y, width);
- src_bgra += src_stride_bgra * 2;
- dst_y += dst_stride_y * 2;
- dst_u += dst_stride_u;
- dst_v += dst_stride_v;
- }
- if (height & 1) {
- BGRAToUVRow(src_bgra, 0, dst_u, dst_v, width);
- BGRAToYRow(src_bgra, dst_y, width);
- }
- return 0;
-}
-
-// Convert ABGR to I420.
-LIBYUV_API
-int ABGRToI420(const uint8* src_abgr, int src_stride_abgr,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- if (!src_abgr ||
- !dst_y || !dst_u || !dst_v ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_abgr = src_abgr + (height - 1) * src_stride_abgr;
- src_stride_abgr = -src_stride_abgr;
- }
- void (*ABGRToUVRow)(const uint8* src_abgr0, int src_stride_abgr,
- uint8* dst_u, uint8* dst_v, int width) = ABGRToUVRow_C;
- void (*ABGRToYRow)(const uint8* src_abgr, uint8* dst_y, int pix) =
- ABGRToYRow_C;
-#if defined(HAS_ABGRTOYROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ABGRToUVRow = ABGRToUVRow_Any_SSSE3;
- ABGRToYRow = ABGRToYRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ABGRToUVRow = ABGRToUVRow_Unaligned_SSSE3;
- ABGRToYRow = ABGRToYRow_Unaligned_SSSE3;
- if (IS_ALIGNED(src_abgr, 16) && IS_ALIGNED(src_stride_abgr, 16)) {
- ABGRToUVRow = ABGRToUVRow_SSSE3;
- if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
- ABGRToYRow = ABGRToYRow_SSSE3;
- }
- }
- }
- }
-#elif defined(HAS_ABGRTOYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ABGRToYRow = ABGRToYRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ABGRToYRow = ABGRToYRow_NEON;
- }
- if (width >= 16) {
- ABGRToUVRow = ABGRToUVRow_Any_NEON;
- if (IS_ALIGNED(width, 16)) {
- ABGRToUVRow = ABGRToUVRow_NEON;
- }
- }
- }
-#endif
-
- for (int y = 0; y < height - 1; y += 2) {
- ABGRToUVRow(src_abgr, src_stride_abgr, dst_u, dst_v, width);
- ABGRToYRow(src_abgr, dst_y, width);
- ABGRToYRow(src_abgr + src_stride_abgr, dst_y + dst_stride_y, width);
- src_abgr += src_stride_abgr * 2;
- dst_y += dst_stride_y * 2;
- dst_u += dst_stride_u;
- dst_v += dst_stride_v;
- }
- if (height & 1) {
- ABGRToUVRow(src_abgr, 0, dst_u, dst_v, width);
- ABGRToYRow(src_abgr, dst_y, width);
- }
- return 0;
-}
-
-// Convert RGBA to I420.
-LIBYUV_API
-int RGBAToI420(const uint8* src_rgba, int src_stride_rgba,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- if (!src_rgba ||
- !dst_y || !dst_u || !dst_v ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_rgba = src_rgba + (height - 1) * src_stride_rgba;
- src_stride_rgba = -src_stride_rgba;
- }
- void (*RGBAToUVRow)(const uint8* src_rgba0, int src_stride_rgba,
- uint8* dst_u, uint8* dst_v, int width) = RGBAToUVRow_C;
- void (*RGBAToYRow)(const uint8* src_rgba, uint8* dst_y, int pix) =
- RGBAToYRow_C;
-#if defined(HAS_RGBATOYROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- RGBAToUVRow = RGBAToUVRow_Any_SSSE3;
- RGBAToYRow = RGBAToYRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- RGBAToUVRow = RGBAToUVRow_Unaligned_SSSE3;
- RGBAToYRow = RGBAToYRow_Unaligned_SSSE3;
- if (IS_ALIGNED(src_rgba, 16) && IS_ALIGNED(src_stride_rgba, 16)) {
- RGBAToUVRow = RGBAToUVRow_SSSE3;
- if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
- RGBAToYRow = RGBAToYRow_SSSE3;
- }
- }
- }
- }
-#elif defined(HAS_RGBATOYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- RGBAToYRow = RGBAToYRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- RGBAToYRow = RGBAToYRow_NEON;
- }
- if (width >= 16) {
- RGBAToUVRow = RGBAToUVRow_Any_NEON;
- if (IS_ALIGNED(width, 16)) {
- RGBAToUVRow = RGBAToUVRow_NEON;
- }
- }
- }
-#endif
-
- for (int y = 0; y < height - 1; y += 2) {
- RGBAToUVRow(src_rgba, src_stride_rgba, dst_u, dst_v, width);
- RGBAToYRow(src_rgba, dst_y, width);
- RGBAToYRow(src_rgba + src_stride_rgba, dst_y + dst_stride_y, width);
- src_rgba += src_stride_rgba * 2;
- dst_y += dst_stride_y * 2;
- dst_u += dst_stride_u;
- dst_v += dst_stride_v;
- }
- if (height & 1) {
- RGBAToUVRow(src_rgba, 0, dst_u, dst_v, width);
- RGBAToYRow(src_rgba, dst_y, width);
- }
- return 0;
-}
-
-// Convert RGB24 to I420.
-LIBYUV_API
-int RGB24ToI420(const uint8* src_rgb24, int src_stride_rgb24,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- if (!src_rgb24 || !dst_y || !dst_u || !dst_v ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
- src_stride_rgb24 = -src_stride_rgb24;
- }
-
-#if defined(HAS_RGB24TOYROW_NEON)
- void (*RGB24ToUVRow)(const uint8* src_rgb24, int src_stride_rgb24,
- uint8* dst_u, uint8* dst_v, int width) = RGB24ToUVRow_C;
- void (*RGB24ToYRow)(const uint8* src_rgb24, uint8* dst_y, int pix) =
- RGB24ToYRow_C;
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- RGB24ToYRow = RGB24ToYRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- RGB24ToYRow = RGB24ToYRow_NEON;
- }
- if (width >= 16) {
- RGB24ToUVRow = RGB24ToUVRow_Any_NEON;
- if (IS_ALIGNED(width, 16)) {
- RGB24ToUVRow = RGB24ToUVRow_NEON;
- }
- }
- }
-#else // HAS_RGB24TOYROW_NEON
-
- // Allocate 2 rows of ARGB.
- const int kRowSize = (width * 4 + 15) & ~15;
- align_buffer_64(row, kRowSize * 2);
-
- void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
- RGB24ToARGBRow_C;
-#if defined(HAS_RGB24TOARGBROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
- }
- }
-#endif
- void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
-#if defined(HAS_ARGBTOUVROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToUVRow = ARGBToUVRow_SSSE3;
- }
- }
-#endif
- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
- ARGBToYRow_C;
-#if defined(HAS_ARGBTOUVROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToYRow = ARGBToYRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
- if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
- ARGBToYRow = ARGBToYRow_SSSE3;
- }
- }
- }
-#endif // HAS_ARGBTOUVROW_SSSE3
-#endif // HAS_RGB24TOYROW_NEON
-
- for (int y = 0; y < height - 1; y += 2) {
-#if defined(HAS_RGB24TOYROW_NEON)
- RGB24ToUVRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width);
- RGB24ToYRow(src_rgb24, dst_y, width);
- RGB24ToYRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width);
-#else
- RGB24ToARGBRow(src_rgb24, row, width);
- RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width);
- ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
- ARGBToYRow(row, dst_y, width);
- ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
-#endif
- src_rgb24 += src_stride_rgb24 * 2;
- dst_y += dst_stride_y * 2;
- dst_u += dst_stride_u;
- dst_v += dst_stride_v;
- }
- if (height & 1) {
-#if defined(HAS_RGB24TOYROW_NEON)
- RGB24ToUVRow(src_rgb24, 0, dst_u, dst_v, width);
- RGB24ToYRow(src_rgb24, dst_y, width);
-#else
- RGB24ToARGBRow(src_rgb24, row, width);
- ARGBToUVRow(row, 0, dst_u, dst_v, width);
- ARGBToYRow(row, dst_y, width);
-#endif
- }
-#if !defined(HAS_RGB24TOYROW_NEON)
- free_aligned_buffer_64(row);
-#endif
- return 0;
-}
-
-// Convert RAW to I420.
-LIBYUV_API
-int RAWToI420(const uint8* src_raw, int src_stride_raw,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- if (!src_raw || !dst_y || !dst_u || !dst_v ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_raw = src_raw + (height - 1) * src_stride_raw;
- src_stride_raw = -src_stride_raw;
- }
-
-#if defined(HAS_RAWTOYROW_NEON)
- void (*RAWToUVRow)(const uint8* src_raw, int src_stride_raw,
- uint8* dst_u, uint8* dst_v, int width) = RAWToUVRow_C;
- void (*RAWToYRow)(const uint8* src_raw, uint8* dst_y, int pix) =
- RAWToYRow_C;
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- RAWToYRow = RAWToYRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- RAWToYRow = RAWToYRow_NEON;
- }
- if (width >= 16) {
- RAWToUVRow = RAWToUVRow_Any_NEON;
- if (IS_ALIGNED(width, 16)) {
- RAWToUVRow = RAWToUVRow_NEON;
- }
- }
- }
-#else // HAS_RAWTOYROW_NEON
-
- // Allocate 2 rows of ARGB.
- const int kRowSize = (width * 4 + 15) & ~15;
- align_buffer_64(row, kRowSize * 2);
-
- void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
- RAWToARGBRow_C;
-#if defined(HAS_RAWTOARGBROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- RAWToARGBRow = RAWToARGBRow_SSSE3;
- }
- }
-#endif
- void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
-#if defined(HAS_ARGBTOUVROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToUVRow = ARGBToUVRow_SSSE3;
- }
- }
-#endif
- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
- ARGBToYRow_C;
-#if defined(HAS_ARGBTOUVROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToYRow = ARGBToYRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
- if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
- ARGBToYRow = ARGBToYRow_SSSE3;
- }
- }
- }
-#endif // HAS_ARGBTOUVROW_SSSE3
-#endif // HAS_RAWTOYROW_NEON
-
- for (int y = 0; y < height - 1; y += 2) {
-#if defined(HAS_RAWTOYROW_NEON)
- RAWToUVRow(src_raw, src_stride_raw, dst_u, dst_v, width);
- RAWToYRow(src_raw, dst_y, width);
- RAWToYRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width);
-#else
- RAWToARGBRow(src_raw, row, width);
- RAWToARGBRow(src_raw + src_stride_raw, row + kRowSize, width);
- ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
- ARGBToYRow(row, dst_y, width);
- ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
-#endif
- src_raw += src_stride_raw * 2;
- dst_y += dst_stride_y * 2;
- dst_u += dst_stride_u;
- dst_v += dst_stride_v;
- }
- if (height & 1) {
-#if defined(HAS_RAWTOYROW_NEON)
- RAWToUVRow(src_raw, 0, dst_u, dst_v, width);
- RAWToYRow(src_raw, dst_y, width);
-#else
- RAWToARGBRow(src_raw, row, width);
- ARGBToUVRow(row, 0, dst_u, dst_v, width);
- ARGBToYRow(row, dst_y, width);
-#endif
- }
-#if !defined(HAS_RAWTOYROW_NEON)
- free_aligned_buffer_64(row);
-#endif
- return 0;
-}
-
-// Convert RGB565 to I420.
-LIBYUV_API
-int RGB565ToI420(const uint8* src_rgb565, int src_stride_rgb565,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- if (!src_rgb565 || !dst_y || !dst_u || !dst_v ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
- src_stride_rgb565 = -src_stride_rgb565;
- }
-
-#if defined(HAS_RGB565TOYROW_NEON)
- void (*RGB565ToUVRow)(const uint8* src_rgb565, int src_stride_rgb565,
- uint8* dst_u, uint8* dst_v, int width) = RGB565ToUVRow_C;
- void (*RGB565ToYRow)(const uint8* src_rgb565, uint8* dst_y, int pix) =
- RGB565ToYRow_C;
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- RGB565ToYRow = RGB565ToYRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- RGB565ToYRow = RGB565ToYRow_NEON;
- }
- if (width >= 16) {
- RGB565ToUVRow = RGB565ToUVRow_Any_NEON;
- if (IS_ALIGNED(width, 16)) {
- RGB565ToUVRow = RGB565ToUVRow_NEON;
- }
- }
- }
-#else // HAS_RGB565TOYROW_NEON
-
- // Allocate 2 rows of ARGB.
- const int kRowSize = (width * 4 + 15) & ~15;
- align_buffer_64(row, kRowSize * 2);
-
- void (*RGB565ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
- RGB565ToARGBRow_C;
-#if defined(HAS_RGB565TOARGBROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 8) {
- RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
- if (IS_ALIGNED(width, 8)) {
- RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
- }
- }
-#endif
- void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
-#if defined(HAS_ARGBTOUVROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToUVRow = ARGBToUVRow_SSSE3;
- }
- }
-#endif
- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
- ARGBToYRow_C;
-#if defined(HAS_ARGBTOUVROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToYRow = ARGBToYRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
- if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
- ARGBToYRow = ARGBToYRow_SSSE3;
- }
- }
- }
-#endif // HAS_ARGBTOUVROW_SSSE3
-#endif // HAS_RGB565TOYROW_NEON
-
- for (int y = 0; y < height - 1; y += 2) {
-#if defined(HAS_RGB565TOYROW_NEON)
- RGB565ToUVRow(src_rgb565, src_stride_rgb565, dst_u, dst_v, width);
- RGB565ToYRow(src_rgb565, dst_y, width);
- RGB565ToYRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y, width);
-#else
- RGB565ToARGBRow(src_rgb565, row, width);
- RGB565ToARGBRow(src_rgb565 + src_stride_rgb565, row + kRowSize, width);
- ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
- ARGBToYRow(row, dst_y, width);
- ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
-#endif
- src_rgb565 += src_stride_rgb565 * 2;
- dst_y += dst_stride_y * 2;
- dst_u += dst_stride_u;
- dst_v += dst_stride_v;
- }
- if (height & 1) {
-#if defined(HAS_RGB565TOYROW_NEON)
- RGB565ToUVRow(src_rgb565, 0, dst_u, dst_v, width);
- RGB565ToYRow(src_rgb565, dst_y, width);
-#else
- RGB565ToARGBRow(src_rgb565, row, width);
- ARGBToUVRow(row, 0, dst_u, dst_v, width);
- ARGBToYRow(row, dst_y, width);
-#endif
- }
-#if !defined(HAS_RGB565TOYROW_NEON)
- free_aligned_buffer_64(row);
-#endif
- return 0;
-}
-
-// Convert ARGB1555 to I420.
-LIBYUV_API
-int ARGB1555ToI420(const uint8* src_argb1555, int src_stride_argb1555,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- if (!src_argb1555 || !dst_y || !dst_u || !dst_v ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
- src_stride_argb1555 = -src_stride_argb1555;
- }
-
-#if defined(HAS_ARGB1555TOYROW_NEON)
- void (*ARGB1555ToUVRow)(const uint8* src_argb1555, int src_stride_argb1555,
- uint8* dst_u, uint8* dst_v, int width) = ARGB1555ToUVRow_C;
- void (*ARGB1555ToYRow)(const uint8* src_argb1555, uint8* dst_y, int pix) =
- ARGB1555ToYRow_C;
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGB1555ToYRow = ARGB1555ToYRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGB1555ToYRow = ARGB1555ToYRow_NEON;
- }
- if (width >= 16) {
- ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON;
- if (IS_ALIGNED(width, 16)) {
- ARGB1555ToUVRow = ARGB1555ToUVRow_NEON;
- }
- }
- }
-#else // HAS_ARGB1555TOYROW_NEON
-
- // Allocate 2 rows of ARGB.
- const int kRowSize = (width * 4 + 15) & ~15;
- align_buffer_64(row, kRowSize * 2);
-
- void (*ARGB1555ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
- ARGB1555ToARGBRow_C;
-#if defined(HAS_ARGB1555TOARGBROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 8) {
- ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
- if (IS_ALIGNED(width, 8)) {
- ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
- }
- }
-#endif
- void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
-#if defined(HAS_ARGBTOUVROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToUVRow = ARGBToUVRow_SSSE3;
- }
- }
-#endif
- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
- ARGBToYRow_C;
-#if defined(HAS_ARGBTOUVROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToYRow = ARGBToYRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
- if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
- ARGBToYRow = ARGBToYRow_SSSE3;
- }
- }
- }
-#endif // HAS_ARGBTOUVROW_SSSE3
-#endif // HAS_ARGB1555TOYROW_NEON
-
- for (int y = 0; y < height - 1; y += 2) {
-#if defined(HAS_ARGB1555TOYROW_NEON)
- ARGB1555ToUVRow(src_argb1555, src_stride_argb1555, dst_u, dst_v, width);
- ARGB1555ToYRow(src_argb1555, dst_y, width);
- ARGB1555ToYRow(src_argb1555 + src_stride_argb1555, dst_y + dst_stride_y,
- width);
-#else
- ARGB1555ToARGBRow(src_argb1555, row, width);
- ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555, row + kRowSize,
- width);
- ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
- ARGBToYRow(row, dst_y, width);
- ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
-#endif
- src_argb1555 += src_stride_argb1555 * 2;
- dst_y += dst_stride_y * 2;
- dst_u += dst_stride_u;
- dst_v += dst_stride_v;
- }
- if (height & 1) {
-#if defined(HAS_ARGB1555TOYROW_NEON)
- ARGB1555ToUVRow(src_argb1555, 0, dst_u, dst_v, width);
- ARGB1555ToYRow(src_argb1555, dst_y, width);
-#else
- ARGB1555ToARGBRow(src_argb1555, row, width);
- ARGBToUVRow(row, 0, dst_u, dst_v, width);
- ARGBToYRow(row, dst_y, width);
-#endif
- }
-#if !defined(HAS_ARGB1555TOYROW_NEON)
- free_aligned_buffer_64(row);
-#endif
- return 0;
-}
-
-// Convert ARGB4444 to I420.
-LIBYUV_API
-int ARGB4444ToI420(const uint8* src_argb4444, int src_stride_argb4444,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- if (!src_argb4444 || !dst_y || !dst_u || !dst_v ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
- src_stride_argb4444 = -src_stride_argb4444;
- }
-
-#if defined(HAS_ARGB4444TOYROW_NEON)
- void (*ARGB4444ToUVRow)(const uint8* src_argb4444, int src_stride_argb4444,
- uint8* dst_u, uint8* dst_v, int width) = ARGB4444ToUVRow_C;
- void (*ARGB4444ToYRow)(const uint8* src_argb4444, uint8* dst_y, int pix) =
- ARGB4444ToYRow_C;
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGB4444ToYRow = ARGB4444ToYRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGB4444ToYRow = ARGB4444ToYRow_NEON;
- }
- if (width >= 16) {
- ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON;
- if (IS_ALIGNED(width, 16)) {
- ARGB4444ToUVRow = ARGB4444ToUVRow_NEON;
- }
- }
- }
-#else // HAS_ARGB4444TOYROW_NEON
-
- // Allocate 2 rows of ARGB.
- const int kRowSize = (width * 4 + 15) & ~15;
- align_buffer_64(row, kRowSize * 2);
-
- void (*ARGB4444ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
- ARGB4444ToARGBRow_C;
-#if defined(HAS_ARGB4444TOARGBROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 8) {
- ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
- if (IS_ALIGNED(width, 8)) {
- ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
- }
- }
-#endif
- void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
-#if defined(HAS_ARGBTOUVROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToUVRow = ARGBToUVRow_SSSE3;
- }
- }
-#endif
- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
- ARGBToYRow_C;
-#if defined(HAS_ARGBTOUVROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToYRow = ARGBToYRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
- if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
- ARGBToYRow = ARGBToYRow_SSSE3;
- }
- }
- }
-#endif // HAS_ARGBTOUVROW_SSSE3
-#endif // HAS_ARGB4444TOYROW_NEON
-
- for (int y = 0; y < height - 1; y += 2) {
-#if defined(HAS_ARGB4444TOYROW_NEON)
- ARGB4444ToUVRow(src_argb4444, src_stride_argb4444, dst_u, dst_v, width);
- ARGB4444ToYRow(src_argb4444, dst_y, width);
- ARGB4444ToYRow(src_argb4444 + src_stride_argb4444, dst_y + dst_stride_y,
- width);
-#else
- ARGB4444ToARGBRow(src_argb4444, row, width);
- ARGB4444ToARGBRow(src_argb4444 + src_stride_argb4444, row + kRowSize,
- width);
- ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
- ARGBToYRow(row, dst_y, width);
- ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
-#endif
- src_argb4444 += src_stride_argb4444 * 2;
- dst_y += dst_stride_y * 2;
- dst_u += dst_stride_u;
- dst_v += dst_stride_v;
- }
- if (height & 1) {
-#if defined(HAS_ARGB4444TOYROW_NEON)
- ARGB4444ToUVRow(src_argb4444, 0, dst_u, dst_v, width);
- ARGB4444ToYRow(src_argb4444, dst_y, width);
-#else
- ARGB4444ToARGBRow(src_argb4444, row, width);
- ARGBToUVRow(row, 0, dst_u, dst_v, width);
- ARGBToYRow(row, dst_y, width);
-#endif
- }
-#if !defined(HAS_ARGB4444TOYROW_NEON)
- free_aligned_buffer_64(row);
-#endif
- return 0;
-}
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/convert_argb.cc b/drivers/theoraplayer/src/YUV/libyuv/src/convert_argb.cc
deleted file mode 100755
index a8aab91478..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/convert_argb.cc
+++ /dev/null
@@ -1,901 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/convert_argb.h"
-
-#include "libyuv/cpu_id.h"
-#include "libyuv/format_conversion.h"
-#ifdef HAVE_JPEG
-#include "libyuv/mjpeg_decoder.h"
-#endif
-#include "libyuv/rotate_argb.h"
-#include "libyuv/row.h"
-#include "libyuv/video_common.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// Copy ARGB with optional flipping
-LIBYUV_API
-int ARGBCopy(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- if (!src_argb || !dst_argb ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
-
- CopyPlane(src_argb, src_stride_argb, dst_argb, dst_stride_argb,
- width * 4, height);
- return 0;
-}
-
-// Convert I444 to ARGB.
-LIBYUV_API
-int I444ToARGB(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- if (!src_y || !src_u || !src_v ||
- !dst_argb ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_argb = dst_argb + (height - 1) * dst_stride_argb;
- dst_stride_argb = -dst_stride_argb;
- }
- // Coalesce rows.
- if (src_stride_y == width &&
- src_stride_u == width &&
- src_stride_v == width &&
- dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0;
- }
- void (*I444ToARGBRow)(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* rgb_buf,
- int width) = I444ToARGBRow_C;
-#if defined(HAS_I444TOARGBROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
- I444ToARGBRow = I444ToARGBRow_Any_SSSE3;
- if (IS_ALIGNED(width, 8)) {
- I444ToARGBRow = I444ToARGBRow_Unaligned_SSSE3;
- if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- I444ToARGBRow = I444ToARGBRow_SSSE3;
- }
- }
- }
-#elif defined(HAS_I444TOARGBROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- I444ToARGBRow = I444ToARGBRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- I444ToARGBRow = I444ToARGBRow_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- I444ToARGBRow(src_y, src_u, src_v, dst_argb, width);
- dst_argb += dst_stride_argb;
- src_y += src_stride_y;
- src_u += src_stride_u;
- src_v += src_stride_v;
- }
- return 0;
-}
-
-// Convert I422 to ARGB.
-LIBYUV_API
-int I422ToARGB(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- if (!src_y || !src_u || !src_v ||
- !dst_argb ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_argb = dst_argb + (height - 1) * dst_stride_argb;
- dst_stride_argb = -dst_stride_argb;
- }
- // Coalesce rows.
- if (src_stride_y == width &&
- src_stride_u * 2 == width &&
- src_stride_v * 2 == width &&
- dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0;
- }
- void (*I422ToARGBRow)(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* rgb_buf,
- int width) = I422ToARGBRow_C;
-#if defined(HAS_I422TOARGBROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
- I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
- if (IS_ALIGNED(width, 8)) {
- I422ToARGBRow = I422ToARGBRow_Unaligned_SSSE3;
- if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- I422ToARGBRow = I422ToARGBRow_SSSE3;
- }
- }
- }
-#endif
-#if defined(HAS_I422TOARGBROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && width >= 16) {
- I422ToARGBRow = I422ToARGBRow_Any_AVX2;
- if (IS_ALIGNED(width, 16)) {
- I422ToARGBRow = I422ToARGBRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_I422TOARGBROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- I422ToARGBRow = I422ToARGBRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- I422ToARGBRow = I422ToARGBRow_NEON;
- }
- }
-#endif
-#if defined(HAS_I422TOARGBROW_MIPS_DSPR2)
- if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(width, 4) &&
- IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
- IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
- IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) &&
- IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) {
- I422ToARGBRow = I422ToARGBRow_MIPS_DSPR2;
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- I422ToARGBRow(src_y, src_u, src_v, dst_argb, width);
- dst_argb += dst_stride_argb;
- src_y += src_stride_y;
- src_u += src_stride_u;
- src_v += src_stride_v;
- }
- return 0;
-}
-
-// Convert I411 to ARGB.
-LIBYUV_API
-int I411ToARGB(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- if (!src_y || !src_u || !src_v ||
- !dst_argb ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_argb = dst_argb + (height - 1) * dst_stride_argb;
- dst_stride_argb = -dst_stride_argb;
- }
- // Coalesce rows.
- if (src_stride_y == width &&
- src_stride_u * 4 == width &&
- src_stride_v * 4 == width &&
- dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0;
- }
- void (*I411ToARGBRow)(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* rgb_buf,
- int width) = I411ToARGBRow_C;
-#if defined(HAS_I411TOARGBROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
- I411ToARGBRow = I411ToARGBRow_Any_SSSE3;
- if (IS_ALIGNED(width, 8)) {
- I411ToARGBRow = I411ToARGBRow_Unaligned_SSSE3;
- if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- I411ToARGBRow = I411ToARGBRow_SSSE3;
- }
- }
- }
-#elif defined(HAS_I411TOARGBROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- I411ToARGBRow = I411ToARGBRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- I411ToARGBRow = I411ToARGBRow_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- I411ToARGBRow(src_y, src_u, src_v, dst_argb, width);
- dst_argb += dst_stride_argb;
- src_y += src_stride_y;
- src_u += src_stride_u;
- src_v += src_stride_v;
- }
- return 0;
-}
-
-// Convert I400 to ARGB.
-LIBYUV_API
-int I400ToARGB_Reference(const uint8* src_y, int src_stride_y,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- if (!src_y || !dst_argb ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_argb = dst_argb + (height - 1) * dst_stride_argb;
- dst_stride_argb = -dst_stride_argb;
- }
- // Coalesce rows.
- if (src_stride_y == width &&
- dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- src_stride_y = dst_stride_argb = 0;
- }
- void (*YToARGBRow)(const uint8* y_buf,
- uint8* rgb_buf,
- int width) = YToARGBRow_C;
-#if defined(HAS_YTOARGBROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 8 &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- YToARGBRow = YToARGBRow_Any_SSE2;
- if (IS_ALIGNED(width, 8)) {
- YToARGBRow = YToARGBRow_SSE2;
- }
- }
-#elif defined(HAS_YTOARGBROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- YToARGBRow = YToARGBRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- YToARGBRow = YToARGBRow_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- YToARGBRow(src_y, dst_argb, width);
- dst_argb += dst_stride_argb;
- src_y += src_stride_y;
- }
- return 0;
-}
-
-// Convert I400 to ARGB.
-LIBYUV_API
-int I400ToARGB(const uint8* src_y, int src_stride_y,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- if (!src_y || !dst_argb ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_y = src_y + (height - 1) * src_stride_y;
- src_stride_y = -src_stride_y;
- }
- // Coalesce rows.
- if (src_stride_y == width &&
- dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- src_stride_y = dst_stride_argb = 0;
- }
- void (*I400ToARGBRow)(const uint8* src_y, uint8* dst_argb, int pix) =
- I400ToARGBRow_C;
-#if defined(HAS_I400TOARGBROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 8) {
- I400ToARGBRow = I400ToARGBRow_Any_SSE2;
- if (IS_ALIGNED(width, 8)) {
- I400ToARGBRow = I400ToARGBRow_Unaligned_SSE2;
- if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- I400ToARGBRow = I400ToARGBRow_SSE2;
- }
- }
- }
-#elif defined(HAS_I400TOARGBROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- I400ToARGBRow = I400ToARGBRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- I400ToARGBRow = I400ToARGBRow_NEON;
- }
- }
-#endif
- for (int y = 0; y < height; ++y) {
- I400ToARGBRow(src_y, dst_argb, width);
- src_y += src_stride_y;
- dst_argb += dst_stride_argb;
- }
- return 0;
-}
-
-// Shuffle table for converting BGRA to ARGB.
-static uvec8 kShuffleMaskBGRAToARGB = {
- 3u, 2u, 1u, 0u, 7u, 6u, 5u, 4u, 11u, 10u, 9u, 8u, 15u, 14u, 13u, 12u
-};
-
-// Shuffle table for converting ABGR to ARGB.
-static uvec8 kShuffleMaskABGRToARGB = {
- 2u, 1u, 0u, 3u, 6u, 5u, 4u, 7u, 10u, 9u, 8u, 11u, 14u, 13u, 12u, 15u
-};
-
-// Shuffle table for converting RGBA to ARGB.
-static uvec8 kShuffleMaskRGBAToARGB = {
- 1u, 2u, 3u, 0u, 5u, 6u, 7u, 4u, 9u, 10u, 11u, 8u, 13u, 14u, 15u, 12u
-};
-
-// Convert BGRA to ARGB.
-LIBYUV_API
-int BGRAToARGB(const uint8* src_bgra, int src_stride_bgra,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- return ARGBShuffle(src_bgra, src_stride_bgra,
- dst_argb, dst_stride_argb,
- (const uint8*)(&kShuffleMaskBGRAToARGB),
- width, height);
-}
-
-// Convert ABGR to ARGB.
-LIBYUV_API
-int ABGRToARGB(const uint8* src_abgr, int src_stride_abgr,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- return ARGBShuffle(src_abgr, src_stride_abgr,
- dst_argb, dst_stride_argb,
- (const uint8*)(&kShuffleMaskABGRToARGB),
- width, height);
-}
-
-// Convert RGBA to ARGB.
-LIBYUV_API
-int RGBAToARGB(const uint8* src_rgba, int src_stride_rgba,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- return ARGBShuffle(src_rgba, src_stride_rgba,
- dst_argb, dst_stride_argb,
- (const uint8*)(&kShuffleMaskRGBAToARGB),
- width, height);
-}
-
-// Convert RGB24 to ARGB.
-LIBYUV_API
-int RGB24ToARGB(const uint8* src_rgb24, int src_stride_rgb24,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- if (!src_rgb24 || !dst_argb ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
- src_stride_rgb24 = -src_stride_rgb24;
- }
- // Coalesce rows.
- if (src_stride_rgb24 == width * 3 &&
- dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- src_stride_rgb24 = dst_stride_argb = 0;
- }
- void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
- RGB24ToARGBRow_C;
-#if defined(HAS_RGB24TOARGBROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16 &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
- }
- }
-#elif defined(HAS_RGB24TOARGBROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- RGB24ToARGBRow = RGB24ToARGBRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- RGB24ToARGBRow = RGB24ToARGBRow_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- RGB24ToARGBRow(src_rgb24, dst_argb, width);
- src_rgb24 += src_stride_rgb24;
- dst_argb += dst_stride_argb;
- }
- return 0;
-}
-
-// Convert RAW to ARGB.
-LIBYUV_API
-int RAWToARGB(const uint8* src_raw, int src_stride_raw,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- if (!src_raw || !dst_argb ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_raw = src_raw + (height - 1) * src_stride_raw;
- src_stride_raw = -src_stride_raw;
- }
- // Coalesce rows.
- if (src_stride_raw == width * 3 &&
- dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- src_stride_raw = dst_stride_argb = 0;
- }
- void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
- RAWToARGBRow_C;
-#if defined(HAS_RAWTOARGBROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16 &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- RAWToARGBRow = RAWToARGBRow_SSSE3;
- }
- }
-#elif defined(HAS_RAWTOARGBROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- RAWToARGBRow = RAWToARGBRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- RAWToARGBRow = RAWToARGBRow_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- RAWToARGBRow(src_raw, dst_argb, width);
- src_raw += src_stride_raw;
- dst_argb += dst_stride_argb;
- }
- return 0;
-}
-
-// Convert RGB565 to ARGB.
-LIBYUV_API
-int RGB565ToARGB(const uint8* src_rgb565, int src_stride_rgb565,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- if (!src_rgb565 || !dst_argb ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
- src_stride_rgb565 = -src_stride_rgb565;
- }
- // Coalesce rows.
- if (src_stride_rgb565 == width * 2 &&
- dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- src_stride_rgb565 = dst_stride_argb = 0;
- }
- void (*RGB565ToARGBRow)(const uint8* src_rgb565, uint8* dst_argb, int pix) =
- RGB565ToARGBRow_C;
-#if defined(HAS_RGB565TOARGBROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 8 &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
- if (IS_ALIGNED(width, 8)) {
- RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
- }
- }
-#elif defined(HAS_RGB565TOARGBROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- RGB565ToARGBRow = RGB565ToARGBRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- RGB565ToARGBRow = RGB565ToARGBRow_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- RGB565ToARGBRow(src_rgb565, dst_argb, width);
- src_rgb565 += src_stride_rgb565;
- dst_argb += dst_stride_argb;
- }
- return 0;
-}
-
-// Convert ARGB1555 to ARGB.
-LIBYUV_API
-int ARGB1555ToARGB(const uint8* src_argb1555, int src_stride_argb1555,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- if (!src_argb1555 || !dst_argb ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
- src_stride_argb1555 = -src_stride_argb1555;
- }
- // Coalesce rows.
- if (src_stride_argb1555 == width * 2 &&
- dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- src_stride_argb1555 = dst_stride_argb = 0;
- }
- void (*ARGB1555ToARGBRow)(const uint8* src_argb1555, uint8* dst_argb,
- int pix) = ARGB1555ToARGBRow_C;
-#if defined(HAS_ARGB1555TOARGBROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 8 &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
- if (IS_ALIGNED(width, 8)) {
- ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
- }
- }
-#elif defined(HAS_ARGB1555TOARGBROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGB1555ToARGBRow = ARGB1555ToARGBRow_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- ARGB1555ToARGBRow(src_argb1555, dst_argb, width);
- src_argb1555 += src_stride_argb1555;
- dst_argb += dst_stride_argb;
- }
- return 0;
-}
-
-// Convert ARGB4444 to ARGB.
-LIBYUV_API
-int ARGB4444ToARGB(const uint8* src_argb4444, int src_stride_argb4444,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- if (!src_argb4444 || !dst_argb ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
- src_stride_argb4444 = -src_stride_argb4444;
- }
- // Coalesce rows.
- if (src_stride_argb4444 == width * 2 &&
- dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- src_stride_argb4444 = dst_stride_argb = 0;
- }
- void (*ARGB4444ToARGBRow)(const uint8* src_argb4444, uint8* dst_argb,
- int pix) = ARGB4444ToARGBRow_C;
-#if defined(HAS_ARGB4444TOARGBROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 8 &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
- if (IS_ALIGNED(width, 8)) {
- ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
- }
- }
-#elif defined(HAS_ARGB4444TOARGBROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGB4444ToARGBRow = ARGB4444ToARGBRow_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- ARGB4444ToARGBRow(src_argb4444, dst_argb, width);
- src_argb4444 += src_stride_argb4444;
- dst_argb += dst_stride_argb;
- }
- return 0;
-}
-
-// Convert NV12 to ARGB.
-LIBYUV_API
-int NV12ToARGB(const uint8* src_y, int src_stride_y,
- const uint8* src_uv, int src_stride_uv,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- if (!src_y || !src_uv || !dst_argb ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_argb = dst_argb + (height - 1) * dst_stride_argb;
- dst_stride_argb = -dst_stride_argb;
- }
- void (*NV12ToARGBRow)(const uint8* y_buf,
- const uint8* uv_buf,
- uint8* rgb_buf,
- int width) = NV12ToARGBRow_C;
-#if defined(HAS_NV12TOARGBROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
- NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3;
- if (IS_ALIGNED(width, 8)) {
- NV12ToARGBRow = NV12ToARGBRow_Unaligned_SSSE3;
- if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- NV12ToARGBRow = NV12ToARGBRow_SSSE3;
- }
- }
- }
-#elif defined(HAS_NV12TOARGBROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- NV12ToARGBRow = NV12ToARGBRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- NV12ToARGBRow = NV12ToARGBRow_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- NV12ToARGBRow(src_y, src_uv, dst_argb, width);
- dst_argb += dst_stride_argb;
- src_y += src_stride_y;
- if (y & 1) {
- src_uv += src_stride_uv;
- }
- }
- return 0;
-}
-
-// Convert NV21 to ARGB.
-LIBYUV_API
-int NV21ToARGB(const uint8* src_y, int src_stride_y,
- const uint8* src_uv, int src_stride_uv,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- if (!src_y || !src_uv || !dst_argb ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_argb = dst_argb + (height - 1) * dst_stride_argb;
- dst_stride_argb = -dst_stride_argb;
- }
- void (*NV21ToARGBRow)(const uint8* y_buf,
- const uint8* uv_buf,
- uint8* rgb_buf,
- int width) = NV21ToARGBRow_C;
-#if defined(HAS_NV21TOARGBROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
- NV21ToARGBRow = NV21ToARGBRow_Any_SSSE3;
- if (IS_ALIGNED(width, 8)) {
- NV21ToARGBRow = NV21ToARGBRow_Unaligned_SSSE3;
- if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- NV21ToARGBRow = NV21ToARGBRow_SSSE3;
- }
- }
- }
-#endif
-#if defined(HAS_NV21TOARGBROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- NV21ToARGBRow = NV21ToARGBRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- NV21ToARGBRow = NV21ToARGBRow_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- NV21ToARGBRow(src_y, src_uv, dst_argb, width);
- dst_argb += dst_stride_argb;
- src_y += src_stride_y;
- if (y & 1) {
- src_uv += src_stride_uv;
- }
- }
- return 0;
-}
-
-// Convert M420 to ARGB.
-LIBYUV_API
-int M420ToARGB(const uint8* src_m420, int src_stride_m420,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- if (!src_m420 || !dst_argb ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_argb = dst_argb + (height - 1) * dst_stride_argb;
- dst_stride_argb = -dst_stride_argb;
- }
- void (*NV12ToARGBRow)(const uint8* y_buf,
- const uint8* uv_buf,
- uint8* rgb_buf,
- int width) = NV12ToARGBRow_C;
-#if defined(HAS_NV12TOARGBROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
- NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3;
- if (IS_ALIGNED(width, 8)) {
- NV12ToARGBRow = NV12ToARGBRow_Unaligned_SSSE3;
- if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- NV12ToARGBRow = NV12ToARGBRow_SSSE3;
- }
- }
- }
-#elif defined(HAS_NV12TOARGBROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- NV12ToARGBRow = NV12ToARGBRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- NV12ToARGBRow = NV12ToARGBRow_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height - 1; y += 2) {
- NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb, width);
- NV12ToARGBRow(src_m420 + src_stride_m420, src_m420 + src_stride_m420 * 2,
- dst_argb + dst_stride_argb, width);
- dst_argb += dst_stride_argb * 2;
- src_m420 += src_stride_m420 * 3;
- }
- if (height & 1) {
- NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb, width);
- }
- return 0;
-}
-
-// Convert YUY2 to ARGB.
-LIBYUV_API
-int YUY2ToARGB(const uint8* src_yuy2, int src_stride_yuy2,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- if (!src_yuy2 || !dst_argb ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
- src_stride_yuy2 = -src_stride_yuy2;
- }
- // Coalesce rows.
- if (src_stride_yuy2 == width * 2 &&
- dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- src_stride_yuy2 = dst_stride_argb = 0;
- }
- void (*YUY2ToARGBRow)(const uint8* src_yuy2, uint8* dst_argb, int pix) =
- YUY2ToARGBRow_C;
-#if defined(HAS_YUY2TOARGBROW_SSSE3)
- // Posix is 16, Windows is 8.
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- YUY2ToARGBRow = YUY2ToARGBRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- YUY2ToARGBRow = YUY2ToARGBRow_Unaligned_SSSE3;
- if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16) &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- YUY2ToARGBRow = YUY2ToARGBRow_SSSE3;
- }
- }
- }
-#elif defined(HAS_YUY2TOARGBROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- YUY2ToARGBRow = YUY2ToARGBRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- YUY2ToARGBRow = YUY2ToARGBRow_NEON;
- }
- }
-#endif
- for (int y = 0; y < height; ++y) {
- YUY2ToARGBRow(src_yuy2, dst_argb, width);
- src_yuy2 += src_stride_yuy2;
- dst_argb += dst_stride_argb;
- }
- return 0;
-}
-
-// Convert UYVY to ARGB.
-LIBYUV_API
-int UYVYToARGB(const uint8* src_uyvy, int src_stride_uyvy,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- if (!src_uyvy || !dst_argb ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
- src_stride_uyvy = -src_stride_uyvy;
- }
- // Coalesce rows.
- if (src_stride_uyvy == width * 2 &&
- dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- src_stride_uyvy = dst_stride_argb = 0;
- }
- void (*UYVYToARGBRow)(const uint8* src_uyvy, uint8* dst_argb, int pix) =
- UYVYToARGBRow_C;
-#if defined(HAS_UYVYTOARGBROW_SSSE3)
- // Posix is 16, Windows is 8.
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- UYVYToARGBRow = UYVYToARGBRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- UYVYToARGBRow = UYVYToARGBRow_Unaligned_SSSE3;
- if (IS_ALIGNED(src_uyvy, 16) && IS_ALIGNED(src_stride_uyvy, 16) &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- UYVYToARGBRow = UYVYToARGBRow_SSSE3;
- }
- }
- }
-#elif defined(HAS_UYVYTOARGBROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- UYVYToARGBRow = UYVYToARGBRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- UYVYToARGBRow = UYVYToARGBRow_NEON;
- }
- }
-#endif
- for (int y = 0; y < height; ++y) {
- UYVYToARGBRow(src_uyvy, dst_argb, width);
- src_uyvy += src_stride_uyvy;
- dst_argb += dst_stride_argb;
- }
- return 0;
-}
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/convert_from.cc b/drivers/theoraplayer/src/YUV/libyuv/src/convert_from.cc
deleted file mode 100755
index 1e10832856..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/convert_from.cc
+++ /dev/null
@@ -1,1196 +0,0 @@
-/*
- * Copyright 2012 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/convert_from.h"
-
-#include "libyuv/basic_types.h"
-#include "libyuv/convert.h" // For I420Copy
-#include "libyuv/cpu_id.h"
-#include "libyuv/format_conversion.h"
-#include "libyuv/planar_functions.h"
-#include "libyuv/rotate.h"
-#include "libyuv/scale.h" // For ScalePlane()
-#include "libyuv/video_common.h"
-#include "libyuv/row.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-#define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
-static __inline int Abs(int v) {
- return v >= 0 ? v : -v;
-}
-
-// I420 To any I4xx YUV format with mirroring.
-static int I420ToI4xx(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int src_y_width, int src_y_height,
- int dst_uv_width, int dst_uv_height) {
- if (src_y_width == 0 || src_y_height == 0 ||
- dst_uv_width <= 0 || dst_uv_height <= 0) {
- return -1;
- }
- const int dst_y_width = Abs(src_y_width);
- const int dst_y_height = Abs(src_y_height);
- const int src_uv_width = SUBSAMPLE(src_y_width, 1, 1);
- const int src_uv_height = SUBSAMPLE(src_y_height, 1, 1);
- ScalePlane(src_y, src_stride_y, src_y_width, src_y_height,
- dst_y, dst_stride_y, dst_y_width, dst_y_height,
- kFilterBilinear);
- ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height,
- dst_u, dst_stride_u, dst_uv_width, dst_uv_height,
- kFilterBilinear);
- ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height,
- dst_v, dst_stride_v, dst_uv_width, dst_uv_height,
- kFilterBilinear);
- return 0;
-}
-
-// 420 chroma is 1/2 width, 1/2 height
-// 422 chroma is 1/2 width, 1x height
-LIBYUV_API
-int I420ToI422(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- const int dst_uv_width = (Abs(width) + 1) >> 1;
- const int dst_uv_height = Abs(height);
- return I420ToI4xx(src_y, src_stride_y,
- src_u, src_stride_u,
- src_v, src_stride_v,
- dst_y, dst_stride_y,
- dst_u, dst_stride_u,
- dst_v, dst_stride_v,
- width, height,
- dst_uv_width, dst_uv_height);
-}
-
-// 420 chroma is 1/2 width, 1/2 height
-// 444 chroma is 1x width, 1x height
-LIBYUV_API
-int I420ToI444(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- const int dst_uv_width = Abs(width);
- const int dst_uv_height = Abs(height);
- return I420ToI4xx(src_y, src_stride_y,
- src_u, src_stride_u,
- src_v, src_stride_v,
- dst_y, dst_stride_y,
- dst_u, dst_stride_u,
- dst_v, dst_stride_v,
- width, height,
- dst_uv_width, dst_uv_height);
-}
-
-// 420 chroma is 1/2 width, 1/2 height
-// 411 chroma is 1/4 width, 1x height
-LIBYUV_API
-int I420ToI411(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- const int dst_uv_width = (Abs(width) + 3) >> 2;
- const int dst_uv_height = Abs(height);
- return I420ToI4xx(src_y, src_stride_y,
- src_u, src_stride_u,
- src_v, src_stride_v,
- dst_y, dst_stride_y,
- dst_u, dst_stride_u,
- dst_v, dst_stride_v,
- width, height,
- dst_uv_width, dst_uv_height);
-}
-
-// Copy to I400. Source can be I420,422,444,400,NV12,NV21
-LIBYUV_API
-int I400Copy(const uint8* src_y, int src_stride_y,
- uint8* dst_y, int dst_stride_y,
- int width, int height) {
- if (!src_y || !dst_y ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_y = src_y + (height - 1) * src_stride_y;
- src_stride_y = -src_stride_y;
- }
- CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
- return 0;
-}
-
-LIBYUV_API
-int I422ToYUY2(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_yuy2, int dst_stride_yuy2,
- int width, int height) {
- if (!src_y || !src_u || !src_v || !dst_yuy2 ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
- dst_stride_yuy2 = -dst_stride_yuy2;
- }
- // Coalesce rows.
- if (src_stride_y == width &&
- src_stride_u * 2 == width &&
- src_stride_v * 2 == width &&
- dst_stride_yuy2 == width * 2) {
- width *= height;
- height = 1;
- src_stride_y = src_stride_u = src_stride_v = dst_stride_yuy2 = 0;
- }
- void (*I422ToYUY2Row)(const uint8* src_y, const uint8* src_u,
- const uint8* src_v, uint8* dst_yuy2, int width) =
- I422ToYUY2Row_C;
-#if defined(HAS_I422TOYUY2ROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
- I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
- if (IS_ALIGNED(width, 16)) {
- I422ToYUY2Row = I422ToYUY2Row_SSE2;
- }
- }
-#elif defined(HAS_I422TOYUY2ROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 16) {
- I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
- if (IS_ALIGNED(width, 16)) {
- I422ToYUY2Row = I422ToYUY2Row_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
- src_y += src_stride_y;
- src_u += src_stride_u;
- src_v += src_stride_v;
- dst_yuy2 += dst_stride_yuy2;
- }
- return 0;
-}
-
-LIBYUV_API
-int I420ToYUY2(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_yuy2, int dst_stride_yuy2,
- int width, int height) {
- if (!src_y || !src_u || !src_v || !dst_yuy2 ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
- dst_stride_yuy2 = -dst_stride_yuy2;
- }
- void (*I422ToYUY2Row)(const uint8* src_y, const uint8* src_u,
- const uint8* src_v, uint8* dst_yuy2, int width) =
- I422ToYUY2Row_C;
-#if defined(HAS_I422TOYUY2ROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
- I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
- if (IS_ALIGNED(width, 16)) {
- I422ToYUY2Row = I422ToYUY2Row_SSE2;
- }
- }
-#elif defined(HAS_I422TOYUY2ROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 16) {
- I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
- if (IS_ALIGNED(width, 16)) {
- I422ToYUY2Row = I422ToYUY2Row_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height - 1; y += 2) {
- I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
- I422ToYUY2Row(src_y + src_stride_y, src_u, src_v,
- dst_yuy2 + dst_stride_yuy2, width);
- src_y += src_stride_y * 2;
- src_u += src_stride_u;
- src_v += src_stride_v;
- dst_yuy2 += dst_stride_yuy2 * 2;
- }
- if (height & 1) {
- I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
- }
- return 0;
-}
-
-LIBYUV_API
-int I422ToUYVY(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_uyvy, int dst_stride_uyvy,
- int width, int height) {
- if (!src_y || !src_u || !src_v || !dst_uyvy ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
- dst_stride_uyvy = -dst_stride_uyvy;
- }
- // Coalesce rows.
- if (src_stride_y == width &&
- src_stride_u * 2 == width &&
- src_stride_v * 2 == width &&
- dst_stride_uyvy == width * 2) {
- width *= height;
- height = 1;
- src_stride_y = src_stride_u = src_stride_v = dst_stride_uyvy = 0;
- }
- void (*I422ToUYVYRow)(const uint8* src_y, const uint8* src_u,
- const uint8* src_v, uint8* dst_uyvy, int width) =
- I422ToUYVYRow_C;
-#if defined(HAS_I422TOUYVYROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
- I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
- if (IS_ALIGNED(width, 16)) {
- I422ToUYVYRow = I422ToUYVYRow_SSE2;
- }
- }
-#elif defined(HAS_I422TOUYVYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 16) {
- I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
- if (IS_ALIGNED(width, 16)) {
- I422ToUYVYRow = I422ToUYVYRow_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
- src_y += src_stride_y;
- src_u += src_stride_u;
- src_v += src_stride_v;
- dst_uyvy += dst_stride_uyvy;
- }
- return 0;
-}
-
-LIBYUV_API
-int I420ToUYVY(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_uyvy, int dst_stride_uyvy,
- int width, int height) {
- if (!src_y || !src_u || !src_v || !dst_uyvy ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
- dst_stride_uyvy = -dst_stride_uyvy;
- }
- void (*I422ToUYVYRow)(const uint8* src_y, const uint8* src_u,
- const uint8* src_v, uint8* dst_uyvy, int width) =
- I422ToUYVYRow_C;
-#if defined(HAS_I422TOUYVYROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
- I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
- if (IS_ALIGNED(width, 16)) {
- I422ToUYVYRow = I422ToUYVYRow_SSE2;
- }
- }
-#elif defined(HAS_I422TOUYVYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 16) {
- I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
- if (IS_ALIGNED(width, 16)) {
- I422ToUYVYRow = I422ToUYVYRow_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height - 1; y += 2) {
- I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
- I422ToUYVYRow(src_y + src_stride_y, src_u, src_v,
- dst_uyvy + dst_stride_uyvy, width);
- src_y += src_stride_y * 2;
- src_u += src_stride_u;
- src_v += src_stride_v;
- dst_uyvy += dst_stride_uyvy * 2;
- }
- if (height & 1) {
- I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
- }
- return 0;
-}
-
-LIBYUV_API
-int I420ToNV12(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_uv, int dst_stride_uv,
- int width, int height) {
- if (!src_y || !src_u || !src_v || !dst_y || !dst_uv ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- int halfheight = (height + 1) >> 1;
- dst_y = dst_y + (height - 1) * dst_stride_y;
- dst_uv = dst_uv + (halfheight - 1) * dst_stride_uv;
- dst_stride_y = -dst_stride_y;
- dst_stride_uv = -dst_stride_uv;
- }
- // Coalesce rows.
- int halfwidth = (width + 1) >> 1;
- int halfheight = (height + 1) >> 1;
- if (src_stride_y == width &&
- dst_stride_y == width) {
- width *= height;
- height = 1;
- src_stride_y = dst_stride_y = 0;
- }
- // Coalesce rows.
- if (src_stride_u == halfwidth &&
- src_stride_v == halfwidth &&
- dst_stride_uv == halfwidth * 2) {
- halfwidth *= halfheight;
- halfheight = 1;
- src_stride_u = src_stride_v = dst_stride_uv = 0;
- }
- void (*MergeUVRow_)(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
- int width) = MergeUVRow_C;
-#if defined(HAS_MERGEUVROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && halfwidth >= 16) {
- MergeUVRow_ = MergeUVRow_Any_SSE2;
- if (IS_ALIGNED(halfwidth, 16)) {
- MergeUVRow_ = MergeUVRow_Unaligned_SSE2;
- if (IS_ALIGNED(src_u, 16) && IS_ALIGNED(src_stride_u, 16) &&
- IS_ALIGNED(src_v, 16) && IS_ALIGNED(src_stride_v, 16) &&
- IS_ALIGNED(dst_uv, 16) && IS_ALIGNED(dst_stride_uv, 16)) {
- MergeUVRow_ = MergeUVRow_SSE2;
- }
- }
- }
-#endif
-#if defined(HAS_MERGEUVROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && halfwidth >= 32) {
- MergeUVRow_ = MergeUVRow_Any_AVX2;
- if (IS_ALIGNED(halfwidth, 32)) {
- MergeUVRow_ = MergeUVRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_MERGEUVROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && halfwidth >= 16) {
- MergeUVRow_ = MergeUVRow_Any_NEON;
- if (IS_ALIGNED(halfwidth, 16)) {
- MergeUVRow_ = MergeUVRow_NEON;
- }
- }
-#endif
-
- CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
- for (int y = 0; y < halfheight; ++y) {
- // Merge a row of U and V into a row of UV.
- MergeUVRow_(src_u, src_v, dst_uv, halfwidth);
- src_u += src_stride_u;
- src_v += src_stride_v;
- dst_uv += dst_stride_uv;
- }
- return 0;
-}
-
-LIBYUV_API
-int I420ToNV21(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_vu, int dst_stride_vu,
- int width, int height) {
- return I420ToNV12(src_y, src_stride_y,
- src_v, src_stride_v,
- src_u, src_stride_u,
- dst_y, src_stride_y,
- dst_vu, dst_stride_vu,
- width, height);
-}
-
-// Convert I420 to ARGB.
-LIBYUV_API
-int I420ToARGB(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- if (!src_y || !src_u || !src_v || !dst_argb ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_argb = dst_argb + (height - 1) * dst_stride_argb;
- dst_stride_argb = -dst_stride_argb;
- }
- void (*I422ToARGBRow)(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* rgb_buf,
- int width) = I422ToARGBRow_C;
-#if defined(HAS_I422TOARGBROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
- I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
- if (IS_ALIGNED(width, 8)) {
- I422ToARGBRow = I422ToARGBRow_Unaligned_SSSE3;
- if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- I422ToARGBRow = I422ToARGBRow_SSSE3;
- }
- }
- }
-#endif
-#if defined(HAS_I422TOARGBROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && width >= 16) {
- I422ToARGBRow = I422ToARGBRow_Any_AVX2;
- if (IS_ALIGNED(width, 16)) {
- I422ToARGBRow = I422ToARGBRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_I422TOARGBROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- I422ToARGBRow = I422ToARGBRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- I422ToARGBRow = I422ToARGBRow_NEON;
- }
- }
-#endif
-#if defined(HAS_I422TOARGBROW_MIPS_DSPR2)
- if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(width, 4) &&
- IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
- IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
- IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) &&
- IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) {
- I422ToARGBRow = I422ToARGBRow_MIPS_DSPR2;
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- I422ToARGBRow(src_y, src_u, src_v, dst_argb, width);
- dst_argb += dst_stride_argb;
- src_y += src_stride_y;
- if (y & 1) {
- src_u += src_stride_u;
- src_v += src_stride_v;
- }
- }
- return 0;
-}
-
-// Convert I420 to BGRA.
-LIBYUV_API
-int I420ToBGRA(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_bgra, int dst_stride_bgra,
- int width, int height) {
- if (!src_y || !src_u || !src_v || !dst_bgra ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_bgra = dst_bgra + (height - 1) * dst_stride_bgra;
- dst_stride_bgra = -dst_stride_bgra;
- }
- void (*I422ToBGRARow)(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* rgb_buf,
- int width) = I422ToBGRARow_C;
-#if defined(HAS_I422TOBGRAROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
- I422ToBGRARow = I422ToBGRARow_Any_SSSE3;
- if (IS_ALIGNED(width, 8)) {
- I422ToBGRARow = I422ToBGRARow_Unaligned_SSSE3;
- if (IS_ALIGNED(dst_bgra, 16) && IS_ALIGNED(dst_stride_bgra, 16)) {
- I422ToBGRARow = I422ToBGRARow_SSSE3;
- }
- }
- }
-#elif defined(HAS_I422TOBGRAROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- I422ToBGRARow = I422ToBGRARow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- I422ToBGRARow = I422ToBGRARow_NEON;
- }
- }
-#elif defined(HAS_I422TOBGRAROW_MIPS_DSPR2)
- if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(width, 4) &&
- IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
- IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
- IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) &&
- IS_ALIGNED(dst_bgra, 4) && IS_ALIGNED(dst_stride_bgra, 4)) {
- I422ToBGRARow = I422ToBGRARow_MIPS_DSPR2;
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- I422ToBGRARow(src_y, src_u, src_v, dst_bgra, width);
- dst_bgra += dst_stride_bgra;
- src_y += src_stride_y;
- if (y & 1) {
- src_u += src_stride_u;
- src_v += src_stride_v;
- }
- }
- return 0;
-}
-
-// Convert I420 to ABGR.
-LIBYUV_API
-int I420ToABGR(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_abgr, int dst_stride_abgr,
- int width, int height) {
- if (!src_y || !src_u || !src_v || !dst_abgr ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_abgr = dst_abgr + (height - 1) * dst_stride_abgr;
- dst_stride_abgr = -dst_stride_abgr;
- }
- void (*I422ToABGRRow)(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* rgb_buf,
- int width) = I422ToABGRRow_C;
-#if defined(HAS_I422TOABGRROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
- I422ToABGRRow = I422ToABGRRow_Any_SSSE3;
- if (IS_ALIGNED(width, 8)) {
- I422ToABGRRow = I422ToABGRRow_Unaligned_SSSE3;
- if (IS_ALIGNED(dst_abgr, 16) && IS_ALIGNED(dst_stride_abgr, 16)) {
- I422ToABGRRow = I422ToABGRRow_SSSE3;
- }
- }
- }
-#elif defined(HAS_I422TOABGRROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- I422ToABGRRow = I422ToABGRRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- I422ToABGRRow = I422ToABGRRow_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- I422ToABGRRow(src_y, src_u, src_v, dst_abgr, width);
- dst_abgr += dst_stride_abgr;
- src_y += src_stride_y;
- if (y & 1) {
- src_u += src_stride_u;
- src_v += src_stride_v;
- }
- }
- return 0;
-}
-
-// Convert I420 to RGBA.
-LIBYUV_API
-int I420ToRGBA(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_rgba, int dst_stride_rgba,
- int width, int height) {
- if (!src_y || !src_u || !src_v || !dst_rgba ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_rgba = dst_rgba + (height - 1) * dst_stride_rgba;
- dst_stride_rgba = -dst_stride_rgba;
- }
- void (*I422ToRGBARow)(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* rgb_buf,
- int width) = I422ToRGBARow_C;
-#if defined(HAS_I422TORGBAROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
- I422ToRGBARow = I422ToRGBARow_Any_SSSE3;
- if (IS_ALIGNED(width, 8)) {
- I422ToRGBARow = I422ToRGBARow_Unaligned_SSSE3;
- if (IS_ALIGNED(dst_rgba, 16) && IS_ALIGNED(dst_stride_rgba, 16)) {
- I422ToRGBARow = I422ToRGBARow_SSSE3;
- }
- }
- }
-#elif defined(HAS_I422TORGBAROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- I422ToRGBARow = I422ToRGBARow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- I422ToRGBARow = I422ToRGBARow_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- I422ToRGBARow(src_y, src_u, src_v, dst_rgba, width);
- dst_rgba += dst_stride_rgba;
- src_y += src_stride_y;
- if (y & 1) {
- src_u += src_stride_u;
- src_v += src_stride_v;
- }
- }
- return 0;
-}
-
-// Convert I420 to RGB24.
-LIBYUV_API
-int I420ToRGB24(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_rgb24, int dst_stride_rgb24,
- int width, int height) {
- if (!src_y || !src_u || !src_v || !dst_rgb24 ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24;
- dst_stride_rgb24 = -dst_stride_rgb24;
- }
- void (*I422ToRGB24Row)(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* rgb_buf,
- int width) = I422ToRGB24Row_C;
-#if defined(HAS_I422TORGB24ROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
- I422ToRGB24Row = I422ToRGB24Row_Any_SSSE3;
- if (IS_ALIGNED(width, 8)) {
- I422ToRGB24Row = I422ToRGB24Row_SSSE3;
- }
- }
-#elif defined(HAS_I422TORGB24ROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- I422ToRGB24Row = I422ToRGB24Row_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- I422ToRGB24Row = I422ToRGB24Row_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- I422ToRGB24Row(src_y, src_u, src_v, dst_rgb24, width);
- dst_rgb24 += dst_stride_rgb24;
- src_y += src_stride_y;
- if (y & 1) {
- src_u += src_stride_u;
- src_v += src_stride_v;
- }
- }
- return 0;
-}
-
-// Convert I420 to RAW.
-LIBYUV_API
-int I420ToRAW(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_raw, int dst_stride_raw,
- int width, int height) {
- if (!src_y || !src_u || !src_v || !dst_raw ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_raw = dst_raw + (height - 1) * dst_stride_raw;
- dst_stride_raw = -dst_stride_raw;
- }
- void (*I422ToRAWRow)(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* rgb_buf,
- int width) = I422ToRAWRow_C;
-#if defined(HAS_I422TORAWROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
- I422ToRAWRow = I422ToRAWRow_Any_SSSE3;
- if (IS_ALIGNED(width, 8)) {
- I422ToRAWRow = I422ToRAWRow_SSSE3;
- }
- }
-#elif defined(HAS_I422TORAWROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- I422ToRAWRow = I422ToRAWRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- I422ToRAWRow = I422ToRAWRow_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- I422ToRAWRow(src_y, src_u, src_v, dst_raw, width);
- dst_raw += dst_stride_raw;
- src_y += src_stride_y;
- if (y & 1) {
- src_u += src_stride_u;
- src_v += src_stride_v;
- }
- }
- return 0;
-}
-
-// Convert I420 to ARGB1555.
-LIBYUV_API
-int I420ToARGB1555(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_argb1555, int dst_stride_argb1555,
- int width, int height) {
- if (!src_y || !src_u || !src_v || !dst_argb1555 ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_argb1555 = dst_argb1555 + (height - 1) * dst_stride_argb1555;
- dst_stride_argb1555 = -dst_stride_argb1555;
- }
- void (*I422ToARGB1555Row)(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* rgb_buf,
- int width) = I422ToARGB1555Row_C;
-#if defined(HAS_I422TOARGB1555ROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
- I422ToARGB1555Row = I422ToARGB1555Row_Any_SSSE3;
- if (IS_ALIGNED(width, 8)) {
- I422ToARGB1555Row = I422ToARGB1555Row_SSSE3;
- }
- }
-#elif defined(HAS_I422TOARGB1555ROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- I422ToARGB1555Row = I422ToARGB1555Row_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- I422ToARGB1555Row = I422ToARGB1555Row_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- I422ToARGB1555Row(src_y, src_u, src_v, dst_argb1555, width);
- dst_argb1555 += dst_stride_argb1555;
- src_y += src_stride_y;
- if (y & 1) {
- src_u += src_stride_u;
- src_v += src_stride_v;
- }
- }
- return 0;
-}
-
-
-// Convert I420 to ARGB4444.
-LIBYUV_API
-int I420ToARGB4444(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_argb4444, int dst_stride_argb4444,
- int width, int height) {
- if (!src_y || !src_u || !src_v || !dst_argb4444 ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_argb4444 = dst_argb4444 + (height - 1) * dst_stride_argb4444;
- dst_stride_argb4444 = -dst_stride_argb4444;
- }
- void (*I422ToARGB4444Row)(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* rgb_buf,
- int width) = I422ToARGB4444Row_C;
-#if defined(HAS_I422TOARGB4444ROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
- I422ToARGB4444Row = I422ToARGB4444Row_Any_SSSE3;
- if (IS_ALIGNED(width, 8)) {
- I422ToARGB4444Row = I422ToARGB4444Row_SSSE3;
- }
- }
-#elif defined(HAS_I422TOARGB4444ROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- I422ToARGB4444Row = I422ToARGB4444Row_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- I422ToARGB4444Row = I422ToARGB4444Row_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- I422ToARGB4444Row(src_y, src_u, src_v, dst_argb4444, width);
- dst_argb4444 += dst_stride_argb4444;
- src_y += src_stride_y;
- if (y & 1) {
- src_u += src_stride_u;
- src_v += src_stride_v;
- }
- }
- return 0;
-}
-
-// Convert I420 to RGB565.
-LIBYUV_API
-int I420ToRGB565(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_rgb565, int dst_stride_rgb565,
- int width, int height) {
- if (!src_y || !src_u || !src_v || !dst_rgb565 ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
- dst_stride_rgb565 = -dst_stride_rgb565;
- }
- void (*I422ToRGB565Row)(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* rgb_buf,
- int width) = I422ToRGB565Row_C;
-#if defined(HAS_I422TORGB565ROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
- I422ToRGB565Row = I422ToRGB565Row_Any_SSSE3;
- if (IS_ALIGNED(width, 8)) {
- I422ToRGB565Row = I422ToRGB565Row_SSSE3;
- }
- }
-#elif defined(HAS_I422TORGB565ROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- I422ToRGB565Row = I422ToRGB565Row_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- I422ToRGB565Row = I422ToRGB565Row_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- I422ToRGB565Row(src_y, src_u, src_v, dst_rgb565, width);
- dst_rgb565 += dst_stride_rgb565;
- src_y += src_stride_y;
- if (y & 1) {
- src_u += src_stride_u;
- src_v += src_stride_v;
- }
- }
- return 0;
-}
-
-// Convert I420 to specified format
-LIBYUV_API
-int ConvertFromI420(const uint8* y, int y_stride,
- const uint8* u, int u_stride,
- const uint8* v, int v_stride,
- uint8* dst_sample, int dst_sample_stride,
- int width, int height,
- uint32 fourcc) {
- uint32 format = CanonicalFourCC(fourcc);
- if (!y || !u|| !v || !dst_sample ||
- width <= 0 || height == 0) {
- return -1;
- }
- int r = 0;
- switch (format) {
- // Single plane formats
- case FOURCC_YUY2:
- r = I420ToYUY2(y, y_stride,
- u, u_stride,
- v, v_stride,
- dst_sample,
- dst_sample_stride ? dst_sample_stride : width * 2,
- width, height);
- break;
- case FOURCC_UYVY:
- r = I420ToUYVY(y, y_stride,
- u, u_stride,
- v, v_stride,
- dst_sample,
- dst_sample_stride ? dst_sample_stride : width * 2,
- width, height);
- break;
- case FOURCC_RGBP:
- r = I420ToRGB565(y, y_stride,
- u, u_stride,
- v, v_stride,
- dst_sample,
- dst_sample_stride ? dst_sample_stride : width * 2,
- width, height);
- break;
- case FOURCC_RGBO:
- r = I420ToARGB1555(y, y_stride,
- u, u_stride,
- v, v_stride,
- dst_sample,
- dst_sample_stride ? dst_sample_stride : width * 2,
- width, height);
- break;
- case FOURCC_R444:
- r = I420ToARGB4444(y, y_stride,
- u, u_stride,
- v, v_stride,
- dst_sample,
- dst_sample_stride ? dst_sample_stride : width * 2,
- width, height);
- break;
- case FOURCC_24BG:
- r = I420ToRGB24(y, y_stride,
- u, u_stride,
- v, v_stride,
- dst_sample,
- dst_sample_stride ? dst_sample_stride : width * 3,
- width, height);
- break;
- case FOURCC_RAW:
- r = I420ToRAW(y, y_stride,
- u, u_stride,
- v, v_stride,
- dst_sample,
- dst_sample_stride ? dst_sample_stride : width * 3,
- width, height);
- break;
- case FOURCC_ARGB:
- r = I420ToARGB(y, y_stride,
- u, u_stride,
- v, v_stride,
- dst_sample,
- dst_sample_stride ? dst_sample_stride : width * 4,
- width, height);
- break;
- case FOURCC_BGRA:
- r = I420ToBGRA(y, y_stride,
- u, u_stride,
- v, v_stride,
- dst_sample,
- dst_sample_stride ? dst_sample_stride : width * 4,
- width, height);
- break;
- case FOURCC_ABGR:
- r = I420ToABGR(y, y_stride,
- u, u_stride,
- v, v_stride,
- dst_sample,
- dst_sample_stride ? dst_sample_stride : width * 4,
- width, height);
- break;
- case FOURCC_RGBA:
- r = I420ToRGBA(y, y_stride,
- u, u_stride,
- v, v_stride,
- dst_sample,
- dst_sample_stride ? dst_sample_stride : width * 4,
- width, height);
- break;
- case FOURCC_BGGR:
- r = I420ToBayerBGGR(y, y_stride,
- u, u_stride,
- v, v_stride,
- dst_sample,
- dst_sample_stride ? dst_sample_stride : width,
- width, height);
- break;
- case FOURCC_GBRG:
- r = I420ToBayerGBRG(y, y_stride,
- u, u_stride,
- v, v_stride,
- dst_sample,
- dst_sample_stride ? dst_sample_stride : width,
- width, height);
- break;
- case FOURCC_GRBG:
- r = I420ToBayerGRBG(y, y_stride,
- u, u_stride,
- v, v_stride,
- dst_sample,
- dst_sample_stride ? dst_sample_stride : width,
- width, height);
- break;
- case FOURCC_RGGB:
- r = I420ToBayerRGGB(y, y_stride,
- u, u_stride,
- v, v_stride,
- dst_sample,
- dst_sample_stride ? dst_sample_stride : width,
- width, height);
- break;
- case FOURCC_I400:
- r = I400Copy(y, y_stride,
- dst_sample,
- dst_sample_stride ? dst_sample_stride : width,
- width, height);
- break;
- case FOURCC_NV12: {
- uint8* dst_uv = dst_sample + width * height;
- r = I420ToNV12(y, y_stride,
- u, u_stride,
- v, v_stride,
- dst_sample,
- dst_sample_stride ? dst_sample_stride : width,
- dst_uv,
- dst_sample_stride ? dst_sample_stride : width,
- width, height);
- break;
- }
- case FOURCC_NV21: {
- uint8* dst_vu = dst_sample + width * height;
- r = I420ToNV21(y, y_stride,
- u, u_stride,
- v, v_stride,
- dst_sample,
- dst_sample_stride ? dst_sample_stride : width,
- dst_vu,
- dst_sample_stride ? dst_sample_stride : width,
- width, height);
- break;
- }
- // TODO(fbarchard): Add M420 and Q420.
- // Triplanar formats
- // TODO(fbarchard): halfstride instead of halfwidth
- case FOURCC_I420:
- case FOURCC_YU12:
- case FOURCC_YV12: {
- int halfwidth = (width + 1) / 2;
- int halfheight = (height + 1) / 2;
- uint8* dst_u;
- uint8* dst_v;
- if (format == FOURCC_YV12) {
- dst_v = dst_sample + width * height;
- dst_u = dst_v + halfwidth * halfheight;
- } else {
- dst_u = dst_sample + width * height;
- dst_v = dst_u + halfwidth * halfheight;
- }
- r = I420Copy(y, y_stride,
- u, u_stride,
- v, v_stride,
- dst_sample, width,
- dst_u, halfwidth,
- dst_v, halfwidth,
- width, height);
- break;
- }
- case FOURCC_I422:
- case FOURCC_YV16: {
- int halfwidth = (width + 1) / 2;
- uint8* dst_u;
- uint8* dst_v;
- if (format == FOURCC_YV16) {
- dst_v = dst_sample + width * height;
- dst_u = dst_v + halfwidth * height;
- } else {
- dst_u = dst_sample + width * height;
- dst_v = dst_u + halfwidth * height;
- }
- r = I420ToI422(y, y_stride,
- u, u_stride,
- v, v_stride,
- dst_sample, width,
- dst_u, halfwidth,
- dst_v, halfwidth,
- width, height);
- break;
- }
- case FOURCC_I444:
- case FOURCC_YV24: {
- uint8* dst_u;
- uint8* dst_v;
- if (format == FOURCC_YV24) {
- dst_v = dst_sample + width * height;
- dst_u = dst_v + width * height;
- } else {
- dst_u = dst_sample + width * height;
- dst_v = dst_u + width * height;
- }
- r = I420ToI444(y, y_stride,
- u, u_stride,
- v, v_stride,
- dst_sample, width,
- dst_u, width,
- dst_v, width,
- width, height);
- break;
- }
- case FOURCC_I411: {
- int quarterwidth = (width + 3) / 4;
- uint8* dst_u = dst_sample + width * height;
- uint8* dst_v = dst_u + quarterwidth * height;
- r = I420ToI411(y, y_stride,
- u, u_stride,
- v, v_stride,
- dst_sample, width,
- dst_u, quarterwidth,
- dst_v, quarterwidth,
- width, height);
- break;
- }
-
- // Formats not supported - MJPG, biplanar, some rgb formats.
- default:
- return -1; // unknown fourcc - return failure code.
- }
- return r;
-}
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/convert_from_argb.cc b/drivers/theoraplayer/src/YUV/libyuv/src/convert_from_argb.cc
deleted file mode 100755
index 41421fb30b..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/convert_from_argb.cc
+++ /dev/null
@@ -1,1096 +0,0 @@
-/*
- * Copyright 2012 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/convert_from_argb.h"
-
-#include "libyuv/basic_types.h"
-#include "libyuv/cpu_id.h"
-#include "libyuv/format_conversion.h"
-#include "libyuv/planar_functions.h"
-#include "libyuv/row.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// ARGB little endian (bgra in memory) to I444
-LIBYUV_API
-int ARGBToI444(const uint8* src_argb, int src_stride_argb,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
- return -1;
- }
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
- // Coalesce rows.
- if (src_stride_argb == width * 4 &&
- dst_stride_y == width &&
- dst_stride_u == width &&
- dst_stride_v == width) {
- width *= height;
- height = 1;
- src_stride_argb = dst_stride_y = dst_stride_u = dst_stride_v = 0;
- }
- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
- ARGBToYRow_C;
- void (*ARGBToUV444Row)(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
- int pix) = ARGBToUV444Row_C;
-#if defined(HAS_ARGBTOUV444ROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToUV444Row = ARGBToUV444Row_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToUV444Row = ARGBToUV444Row_Unaligned_SSSE3;
- if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) {
- ARGBToUV444Row = ARGBToUV444Row_SSSE3;
- }
- }
- }
-#endif
-#if defined(HAS_ARGBTOYROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToYRow = ARGBToYRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
- if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16) &&
- IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
- ARGBToYRow = ARGBToYRow_SSSE3;
- }
- }
- }
-
-#elif defined(HAS_ARGBTOYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGBToYRow = ARGBToYRow_Any_NEON;
- ARGBToUV444Row = ARGBToUV444Row_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGBToYRow = ARGBToYRow_NEON;
- ARGBToUV444Row = ARGBToUV444Row_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- ARGBToUV444Row(src_argb, dst_u, dst_v, width);
- ARGBToYRow(src_argb, dst_y, width);
- src_argb += src_stride_argb;
- dst_y += dst_stride_y;
- dst_u += dst_stride_u;
- dst_v += dst_stride_v;
- }
- return 0;
-}
-
-// ARGB little endian (bgra in memory) to I422
-LIBYUV_API
-int ARGBToI422(const uint8* src_argb, int src_stride_argb,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
- return -1;
- }
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
- // Coalesce rows.
- if (src_stride_argb == width * 4 &&
- dst_stride_y == width &&
- dst_stride_u * 2 == width &&
- dst_stride_v * 2 == width) {
- width *= height;
- height = 1;
- src_stride_argb = dst_stride_y = dst_stride_u = dst_stride_v = 0;
- }
- void (*ARGBToUV422Row)(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
- int pix) = ARGBToUV422Row_C;
-#if defined(HAS_ARGBTOUV422ROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToUV422Row = ARGBToUV422Row_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToUV422Row = ARGBToUV422Row_Unaligned_SSSE3;
- if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) {
- ARGBToUV422Row = ARGBToUV422Row_SSSE3;
- }
- }
- }
-#endif
-
- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
- ARGBToYRow_C;
-#if defined(HAS_ARGBTOYROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToYRow = ARGBToYRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
- if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16) &&
- IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
- ARGBToYRow = ARGBToYRow_SSSE3;
- }
- }
- }
-#elif defined(HAS_ARGBTOYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGBToYRow = ARGBToYRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGBToYRow = ARGBToYRow_NEON;
- }
- if (width >= 16) {
- ARGBToUV422Row = ARGBToUV422Row_Any_NEON;
- if (IS_ALIGNED(width, 16)) {
- ARGBToUV422Row = ARGBToUV422Row_NEON;
- }
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- ARGBToUV422Row(src_argb, dst_u, dst_v, width);
- ARGBToYRow(src_argb, dst_y, width);
- src_argb += src_stride_argb;
- dst_y += dst_stride_y;
- dst_u += dst_stride_u;
- dst_v += dst_stride_v;
- }
- return 0;
-}
-
-// ARGB little endian (bgra in memory) to I411
-LIBYUV_API
-int ARGBToI411(const uint8* src_argb, int src_stride_argb,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
- return -1;
- }
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
- // Coalesce rows.
- if (src_stride_argb == width * 4 &&
- dst_stride_y == width &&
- dst_stride_u * 4 == width &&
- dst_stride_v * 4 == width) {
- width *= height;
- height = 1;
- src_stride_argb = dst_stride_y = dst_stride_u = dst_stride_v = 0;
- }
- void (*ARGBToUV411Row)(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
- int pix) = ARGBToUV411Row_C;
- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
- ARGBToYRow_C;
-#if defined(HAS_ARGBTOYROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToYRow = ARGBToYRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
- if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16) &&
- IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
- ARGBToYRow = ARGBToYRow_SSSE3;
- }
- }
- }
-#endif
-#if defined(HAS_ARGBTOYROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
- ARGBToYRow = ARGBToYRow_Any_AVX2;
- if (IS_ALIGNED(width, 32)) {
- ARGBToYRow = ARGBToYRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_ARGBTOYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGBToYRow = ARGBToYRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGBToYRow = ARGBToYRow_NEON;
- }
- if (width >= 32) {
- ARGBToUV411Row = ARGBToUV411Row_Any_NEON;
- if (IS_ALIGNED(width, 32)) {
- ARGBToUV411Row = ARGBToUV411Row_NEON;
- }
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- ARGBToUV411Row(src_argb, dst_u, dst_v, width);
- ARGBToYRow(src_argb, dst_y, width);
- src_argb += src_stride_argb;
- dst_y += dst_stride_y;
- dst_u += dst_stride_u;
- dst_v += dst_stride_v;
- }
- return 0;
-}
-
-LIBYUV_API
-int ARGBToNV12(const uint8* src_argb, int src_stride_argb,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_uv, int dst_stride_uv,
- int width, int height) {
- if (!src_argb ||
- !dst_y || !dst_uv ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
- void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
- ARGBToYRow_C;
-#if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
- ARGBToYRow = ARGBToYRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToUVRow = ARGBToUVRow_Unaligned_SSSE3;
- ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
- if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) {
- ARGBToUVRow = ARGBToUVRow_SSSE3;
- if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
- ARGBToYRow = ARGBToYRow_SSSE3;
- }
- }
- }
- }
-#elif defined(HAS_ARGBTOYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGBToYRow = ARGBToYRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGBToYRow = ARGBToYRow_NEON;
- }
- if (width >= 16) {
- ARGBToUVRow = ARGBToUVRow_Any_NEON;
- if (IS_ALIGNED(width, 16)) {
- ARGBToUVRow = ARGBToUVRow_NEON;
- }
- }
- }
-#endif
- int halfwidth = (width + 1) >> 1;
- void (*MergeUVRow_)(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
- int width) = MergeUVRow_C;
-#if defined(HAS_MERGEUVROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && halfwidth >= 16) {
- MergeUVRow_ = MergeUVRow_Any_SSE2;
- if (IS_ALIGNED(halfwidth, 16)) {
- MergeUVRow_ = MergeUVRow_Unaligned_SSE2;
- if (IS_ALIGNED(dst_uv, 16) && IS_ALIGNED(dst_stride_uv, 16)) {
- MergeUVRow_ = MergeUVRow_SSE2;
- }
- }
- }
-#endif
-#if defined(HAS_MERGEUVROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && halfwidth >= 32) {
- MergeUVRow_ = MergeUVRow_Any_AVX2;
- if (IS_ALIGNED(halfwidth, 32)) {
- MergeUVRow_ = MergeUVRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_MERGEUVROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && halfwidth >= 16) {
- MergeUVRow_ = MergeUVRow_Any_NEON;
- if (IS_ALIGNED(halfwidth, 16)) {
- MergeUVRow_ = MergeUVRow_NEON;
- }
- }
-#endif
-
- // Allocate a rows of uv.
- align_buffer_64(row_u, ((halfwidth + 15) & ~15) * 2);
- uint8* row_v = row_u + ((halfwidth + 15) & ~15);
-
- for (int y = 0; y < height - 1; y += 2) {
- ARGBToUVRow(src_argb, src_stride_argb, row_u, row_v, width);
- MergeUVRow_(row_u, row_v, dst_uv, halfwidth);
- ARGBToYRow(src_argb, dst_y, width);
- ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
- src_argb += src_stride_argb * 2;
- dst_y += dst_stride_y * 2;
- dst_uv += dst_stride_uv;
- }
- if (height & 1) {
- ARGBToUVRow(src_argb, 0, row_u, row_v, width);
- MergeUVRow_(row_u, row_v, dst_uv, halfwidth);
- ARGBToYRow(src_argb, dst_y, width);
- }
- free_aligned_buffer_64(row_u);
- return 0;
-}
-
-// Same as NV12 but U and V swapped.
-LIBYUV_API
-int ARGBToNV21(const uint8* src_argb, int src_stride_argb,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_uv, int dst_stride_uv,
- int width, int height) {
- if (!src_argb ||
- !dst_y || !dst_uv ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
- void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
- ARGBToYRow_C;
-#if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
- ARGBToYRow = ARGBToYRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToUVRow = ARGBToUVRow_Unaligned_SSSE3;
- ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
- if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) {
- ARGBToUVRow = ARGBToUVRow_SSSE3;
- if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
- ARGBToYRow = ARGBToYRow_SSSE3;
- }
- }
- }
- }
-#elif defined(HAS_ARGBTOYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGBToYRow = ARGBToYRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGBToYRow = ARGBToYRow_NEON;
- }
- if (width >= 16) {
- ARGBToUVRow = ARGBToUVRow_Any_NEON;
- if (IS_ALIGNED(width, 16)) {
- ARGBToUVRow = ARGBToUVRow_NEON;
- }
- }
- }
-#endif
- int halfwidth = (width + 1) >> 1;
- void (*MergeUVRow_)(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
- int width) = MergeUVRow_C;
-#if defined(HAS_MERGEUVROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && halfwidth >= 16) {
- MergeUVRow_ = MergeUVRow_Any_SSE2;
- if (IS_ALIGNED(halfwidth, 16)) {
- MergeUVRow_ = MergeUVRow_Unaligned_SSE2;
- if (IS_ALIGNED(dst_uv, 16) && IS_ALIGNED(dst_stride_uv, 16)) {
- MergeUVRow_ = MergeUVRow_SSE2;
- }
- }
- }
-#endif
-#if defined(HAS_MERGEUVROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && halfwidth >= 32) {
- MergeUVRow_ = MergeUVRow_Any_AVX2;
- if (IS_ALIGNED(halfwidth, 32)) {
- MergeUVRow_ = MergeUVRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_MERGEUVROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && halfwidth >= 16) {
- MergeUVRow_ = MergeUVRow_Any_NEON;
- if (IS_ALIGNED(halfwidth, 16)) {
- MergeUVRow_ = MergeUVRow_NEON;
- }
- }
-#endif
-
- // Allocate a rows of uv.
- align_buffer_64(row_u, ((halfwidth + 15) & ~15) * 2);
- uint8* row_v = row_u + ((halfwidth + 15) & ~15);
-
- for (int y = 0; y < height - 1; y += 2) {
- ARGBToUVRow(src_argb, src_stride_argb, row_u, row_v, width);
- MergeUVRow_(row_v, row_u, dst_uv, halfwidth);
- ARGBToYRow(src_argb, dst_y, width);
- ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
- src_argb += src_stride_argb * 2;
- dst_y += dst_stride_y * 2;
- dst_uv += dst_stride_uv;
- }
- if (height & 1) {
- ARGBToUVRow(src_argb, 0, row_u, row_v, width);
- MergeUVRow_(row_v, row_u, dst_uv, halfwidth);
- ARGBToYRow(src_argb, dst_y, width);
- }
- free_aligned_buffer_64(row_u);
- return 0;
-}
-
-// Convert ARGB to YUY2.
-LIBYUV_API
-int ARGBToYUY2(const uint8* src_argb, int src_stride_argb,
- uint8* dst_yuy2, int dst_stride_yuy2,
- int width, int height) {
- if (!src_argb || !dst_yuy2 ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
- dst_stride_yuy2 = -dst_stride_yuy2;
- }
- // Coalesce rows.
- if (src_stride_argb == width * 4 &&
- dst_stride_yuy2 == width * 2) {
- width *= height;
- height = 1;
- src_stride_argb = dst_stride_yuy2 = 0;
- }
- void (*ARGBToUV422Row)(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
- int pix) = ARGBToUV422Row_C;
-#if defined(HAS_ARGBTOUV422ROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToUV422Row = ARGBToUV422Row_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToUV422Row = ARGBToUV422Row_Unaligned_SSSE3;
- if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) {
- ARGBToUV422Row = ARGBToUV422Row_SSSE3;
- }
- }
- }
-#endif
- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
- ARGBToYRow_C;
-#if defined(HAS_ARGBTOYROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToYRow = ARGBToYRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
- if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) {
- ARGBToYRow = ARGBToYRow_SSSE3;
- }
- }
- }
-#elif defined(HAS_ARGBTOYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGBToYRow = ARGBToYRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGBToYRow = ARGBToYRow_NEON;
- }
- if (width >= 16) {
- ARGBToUV422Row = ARGBToUV422Row_Any_NEON;
- if (IS_ALIGNED(width, 16)) {
- ARGBToUV422Row = ARGBToUV422Row_NEON;
- }
- }
- }
-#endif
-
- void (*I422ToYUY2Row)(const uint8* src_y, const uint8* src_u,
- const uint8* src_v, uint8* dst_yuy2, int width) =
- I422ToYUY2Row_C;
-#if defined(HAS_I422TOYUY2ROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
- I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
- if (IS_ALIGNED(width, 16)) {
- I422ToYUY2Row = I422ToYUY2Row_SSE2;
- }
- }
-#elif defined(HAS_I422TOYUY2ROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 16) {
- I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
- if (IS_ALIGNED(width, 16)) {
- I422ToYUY2Row = I422ToYUY2Row_NEON;
- }
- }
-#endif
-
- // Allocate a rows of yuv.
- align_buffer_64(row_y, ((width + 63) & ~63) * 2);
- uint8* row_u = row_y + ((width + 63) & ~63);
- uint8* row_v = row_u + ((width + 63) & ~63) / 2;
-
- for (int y = 0; y < height; ++y) {
- ARGBToUV422Row(src_argb, row_u, row_v, width);
- ARGBToYRow(src_argb, row_y, width);
- I422ToYUY2Row(row_y, row_u, row_v, dst_yuy2, width);
- src_argb += src_stride_argb;
- dst_yuy2 += dst_stride_yuy2;
- }
-
- free_aligned_buffer_64(row_y);
- return 0;
-}
-
-// Convert ARGB to UYVY.
-LIBYUV_API
-int ARGBToUYVY(const uint8* src_argb, int src_stride_argb,
- uint8* dst_uyvy, int dst_stride_uyvy,
- int width, int height) {
- if (!src_argb || !dst_uyvy ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
- dst_stride_uyvy = -dst_stride_uyvy;
- }
- // Coalesce rows.
- if (src_stride_argb == width * 4 &&
- dst_stride_uyvy == width * 2) {
- width *= height;
- height = 1;
- src_stride_argb = dst_stride_uyvy = 0;
- }
- void (*ARGBToUV422Row)(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
- int pix) = ARGBToUV422Row_C;
-#if defined(HAS_ARGBTOUV422ROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToUV422Row = ARGBToUV422Row_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToUV422Row = ARGBToUV422Row_Unaligned_SSSE3;
- if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) {
- ARGBToUV422Row = ARGBToUV422Row_SSSE3;
- }
- }
- }
-#endif
- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
- ARGBToYRow_C;
-#if defined(HAS_ARGBTOYROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToYRow = ARGBToYRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
- if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) {
- ARGBToYRow = ARGBToYRow_SSSE3;
- }
- }
- }
-#elif defined(HAS_ARGBTOYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGBToYRow = ARGBToYRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGBToYRow = ARGBToYRow_NEON;
- }
- if (width >= 16) {
- ARGBToUV422Row = ARGBToUV422Row_Any_NEON;
- if (IS_ALIGNED(width, 16)) {
- ARGBToUV422Row = ARGBToUV422Row_NEON;
- }
- }
- }
-#endif
-
- void (*I422ToUYVYRow)(const uint8* src_y, const uint8* src_u,
- const uint8* src_v, uint8* dst_uyvy, int width) =
- I422ToUYVYRow_C;
-#if defined(HAS_I422TOUYVYROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
- I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
- if (IS_ALIGNED(width, 16)) {
- I422ToUYVYRow = I422ToUYVYRow_SSE2;
- }
- }
-#elif defined(HAS_I422TOUYVYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 16) {
- I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
- if (IS_ALIGNED(width, 16)) {
- I422ToUYVYRow = I422ToUYVYRow_NEON;
- }
- }
-#endif
-
- // Allocate a rows of yuv.
- align_buffer_64(row_y, ((width + 63) & ~63) * 2);
- uint8* row_u = row_y + ((width + 63) & ~63);
- uint8* row_v = row_u + ((width + 63) & ~63) / 2;
-
- for (int y = 0; y < height; ++y) {
- ARGBToUV422Row(src_argb, row_u, row_v, width);
- ARGBToYRow(src_argb, row_y, width);
- I422ToUYVYRow(row_y, row_u, row_v, dst_uyvy, width);
- src_argb += src_stride_argb;
- dst_uyvy += dst_stride_uyvy;
- }
-
- free_aligned_buffer_64(row_y);
- return 0;
-}
-
-// Convert ARGB to I400.
-LIBYUV_API
-int ARGBToI400(const uint8* src_argb, int src_stride_argb,
- uint8* dst_y, int dst_stride_y,
- int width, int height) {
- if (!src_argb || !dst_y || width <= 0 || height == 0) {
- return -1;
- }
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
- // Coalesce rows.
- if (src_stride_argb == width * 4 &&
- dst_stride_y == width) {
- width *= height;
- height = 1;
- src_stride_argb = dst_stride_y = 0;
- }
- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
- ARGBToYRow_C;
-#if defined(HAS_ARGBTOYROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToYRow = ARGBToYRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
- if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16) &&
- IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
- ARGBToYRow = ARGBToYRow_SSSE3;
- }
- }
- }
-#endif
-#if defined(HAS_ARGBTOYROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
- ARGBToYRow = ARGBToYRow_Any_AVX2;
- if (IS_ALIGNED(width, 32)) {
- ARGBToYRow = ARGBToYRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_ARGBTOYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGBToYRow = ARGBToYRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGBToYRow = ARGBToYRow_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- ARGBToYRow(src_argb, dst_y, width);
- src_argb += src_stride_argb;
- dst_y += dst_stride_y;
- }
- return 0;
-}
-
-// Shuffle table for converting ARGB to RGBA.
-static uvec8 kShuffleMaskARGBToRGBA = {
- 3u, 0u, 1u, 2u, 7u, 4u, 5u, 6u, 11u, 8u, 9u, 10u, 15u, 12u, 13u, 14u
-};
-
-// Convert ARGB to RGBA.
-LIBYUV_API
-int ARGBToRGBA(const uint8* src_argb, int src_stride_argb,
- uint8* dst_rgba, int dst_stride_rgba,
- int width, int height) {
- return ARGBShuffle(src_argb, src_stride_argb,
- dst_rgba, dst_stride_rgba,
- (const uint8*)(&kShuffleMaskARGBToRGBA),
- width, height);
-}
-
-// Convert ARGB To RGB24.
-LIBYUV_API
-int ARGBToRGB24(const uint8* src_argb, int src_stride_argb,
- uint8* dst_rgb24, int dst_stride_rgb24,
- int width, int height) {
- if (!src_argb || !dst_rgb24 || width <= 0 || height == 0) {
- return -1;
- }
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
- // Coalesce rows.
- if (src_stride_argb == width * 4 &&
- dst_stride_rgb24 == width * 3) {
- width *= height;
- height = 1;
- src_stride_argb = dst_stride_rgb24 = 0;
- }
- void (*ARGBToRGB24Row)(const uint8* src_argb, uint8* dst_rgb, int pix) =
- ARGBToRGB24Row_C;
-#if defined(HAS_ARGBTORGB24ROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToRGB24Row = ARGBToRGB24Row_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToRGB24Row = ARGBToRGB24Row_SSSE3;
- }
- }
-#elif defined(HAS_ARGBTORGB24ROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGBToRGB24Row = ARGBToRGB24Row_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGBToRGB24Row = ARGBToRGB24Row_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- ARGBToRGB24Row(src_argb, dst_rgb24, width);
- src_argb += src_stride_argb;
- dst_rgb24 += dst_stride_rgb24;
- }
- return 0;
-}
-
-// Convert ARGB To RAW.
-LIBYUV_API
-int ARGBToRAW(const uint8* src_argb, int src_stride_argb,
- uint8* dst_raw, int dst_stride_raw,
- int width, int height) {
- if (!src_argb || !dst_raw || width <= 0 || height == 0) {
- return -1;
- }
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
- // Coalesce rows.
- if (src_stride_argb == width * 4 &&
- dst_stride_raw == width * 3) {
- width *= height;
- height = 1;
- src_stride_argb = dst_stride_raw = 0;
- }
- void (*ARGBToRAWRow)(const uint8* src_argb, uint8* dst_rgb, int pix) =
- ARGBToRAWRow_C;
-#if defined(HAS_ARGBTORAWROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToRAWRow = ARGBToRAWRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToRAWRow = ARGBToRAWRow_SSSE3;
- }
- }
-#elif defined(HAS_ARGBTORAWROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGBToRAWRow = ARGBToRAWRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGBToRAWRow = ARGBToRAWRow_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- ARGBToRAWRow(src_argb, dst_raw, width);
- src_argb += src_stride_argb;
- dst_raw += dst_stride_raw;
- }
- return 0;
-}
-
-// Convert ARGB To RGB565.
-LIBYUV_API
-int ARGBToRGB565(const uint8* src_argb, int src_stride_argb,
- uint8* dst_rgb565, int dst_stride_rgb565,
- int width, int height) {
- if (!src_argb || !dst_rgb565 || width <= 0 || height == 0) {
- return -1;
- }
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
- // Coalesce rows.
- if (src_stride_argb == width * 4 &&
- dst_stride_rgb565 == width * 2) {
- width *= height;
- height = 1;
- src_stride_argb = dst_stride_rgb565 = 0;
- }
- void (*ARGBToRGB565Row)(const uint8* src_argb, uint8* dst_rgb, int pix) =
- ARGBToRGB565Row_C;
-#if defined(HAS_ARGBTORGB565ROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 4 &&
- IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) {
- ARGBToRGB565Row = ARGBToRGB565Row_Any_SSE2;
- if (IS_ALIGNED(width, 4)) {
- ARGBToRGB565Row = ARGBToRGB565Row_SSE2;
- }
- }
-#elif defined(HAS_ARGBTORGB565ROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGBToRGB565Row = ARGBToRGB565Row_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGBToRGB565Row = ARGBToRGB565Row_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- ARGBToRGB565Row(src_argb, dst_rgb565, width);
- src_argb += src_stride_argb;
- dst_rgb565 += dst_stride_rgb565;
- }
- return 0;
-}
-
-// Convert ARGB To ARGB1555.
-LIBYUV_API
-int ARGBToARGB1555(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb1555, int dst_stride_argb1555,
- int width, int height) {
- if (!src_argb || !dst_argb1555 || width <= 0 || height == 0) {
- return -1;
- }
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
- // Coalesce rows.
- if (src_stride_argb == width * 4 &&
- dst_stride_argb1555 == width * 2) {
- width *= height;
- height = 1;
- src_stride_argb = dst_stride_argb1555 = 0;
- }
- void (*ARGBToARGB1555Row)(const uint8* src_argb, uint8* dst_rgb, int pix) =
- ARGBToARGB1555Row_C;
-#if defined(HAS_ARGBTOARGB1555ROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 4 &&
- IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) {
- ARGBToARGB1555Row = ARGBToARGB1555Row_Any_SSE2;
- if (IS_ALIGNED(width, 4)) {
- ARGBToARGB1555Row = ARGBToARGB1555Row_SSE2;
- }
- }
-#elif defined(HAS_ARGBTOARGB1555ROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGBToARGB1555Row = ARGBToARGB1555Row_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGBToARGB1555Row = ARGBToARGB1555Row_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- ARGBToARGB1555Row(src_argb, dst_argb1555, width);
- src_argb += src_stride_argb;
- dst_argb1555 += dst_stride_argb1555;
- }
- return 0;
-}
-
-// Convert ARGB To ARGB4444.
-LIBYUV_API
-int ARGBToARGB4444(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb4444, int dst_stride_argb4444,
- int width, int height) {
- if (!src_argb || !dst_argb4444 || width <= 0 || height == 0) {
- return -1;
- }
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
- // Coalesce rows.
- if (src_stride_argb == width * 4 &&
- dst_stride_argb4444 == width * 2) {
- width *= height;
- height = 1;
- src_stride_argb = dst_stride_argb4444 = 0;
- }
- void (*ARGBToARGB4444Row)(const uint8* src_argb, uint8* dst_rgb, int pix) =
- ARGBToARGB4444Row_C;
-#if defined(HAS_ARGBTOARGB4444ROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 4 &&
- IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) {
- ARGBToARGB4444Row = ARGBToARGB4444Row_Any_SSE2;
- if (IS_ALIGNED(width, 4)) {
- ARGBToARGB4444Row = ARGBToARGB4444Row_SSE2;
- }
- }
-#elif defined(HAS_ARGBTOARGB4444ROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGBToARGB4444Row = ARGBToARGB4444Row_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGBToARGB4444Row = ARGBToARGB4444Row_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- ARGBToARGB4444Row(src_argb, dst_argb4444, width);
- src_argb += src_stride_argb;
- dst_argb4444 += dst_stride_argb4444;
- }
- return 0;
-}
-
-// Convert ARGB to J420. (JPeg full range I420).
-LIBYUV_API
-int ARGBToJ420(const uint8* src_argb, int src_stride_argb,
- uint8* dst_yj, int dst_stride_yj,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- if (!src_argb ||
- !dst_yj || !dst_u || !dst_v ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
- void (*ARGBToUVJRow)(const uint8* src_argb0, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width) = ARGBToUVJRow_C;
- void (*ARGBToYJRow)(const uint8* src_argb, uint8* dst_yj, int pix) =
- ARGBToYJRow_C;
-#if defined(HAS_ARGBTOYJROW_SSSE3) && defined(HAS_ARGBTOUVJROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToUVJRow = ARGBToUVJRow_Any_SSSE3;
- ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToUVJRow = ARGBToUVJRow_Unaligned_SSSE3;
- ARGBToYJRow = ARGBToYJRow_Unaligned_SSSE3;
- if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) {
- ARGBToUVJRow = ARGBToUVJRow_SSSE3;
- if (IS_ALIGNED(dst_yj, 16) && IS_ALIGNED(dst_stride_yj, 16)) {
- ARGBToYJRow = ARGBToYJRow_SSSE3;
- }
- }
- }
- }
-#endif
-#if defined(HAS_ARGBTOYJROW_AVX2) && defined(HAS_ARGBTOUVJROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
- ARGBToYJRow = ARGBToYJRow_Any_AVX2;
- if (IS_ALIGNED(width, 32)) {
- ARGBToYJRow = ARGBToYJRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_ARGBTOYJROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGBToYJRow = ARGBToYJRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGBToYJRow = ARGBToYJRow_NEON;
- }
- if (width >= 16) {
- ARGBToUVJRow = ARGBToUVJRow_Any_NEON;
- if (IS_ALIGNED(width, 16)) {
- ARGBToUVJRow = ARGBToUVJRow_NEON;
- }
- }
- }
-#endif
-
- for (int y = 0; y < height - 1; y += 2) {
- ARGBToUVJRow(src_argb, src_stride_argb, dst_u, dst_v, width);
- ARGBToYJRow(src_argb, dst_yj, width);
- ARGBToYJRow(src_argb + src_stride_argb, dst_yj + dst_stride_yj, width);
- src_argb += src_stride_argb * 2;
- dst_yj += dst_stride_yj * 2;
- dst_u += dst_stride_u;
- dst_v += dst_stride_v;
- }
- if (height & 1) {
- ARGBToUVJRow(src_argb, 0, dst_u, dst_v, width);
- ARGBToYJRow(src_argb, dst_yj, width);
- }
- return 0;
-}
-
-// Convert ARGB to J400.
-LIBYUV_API
-int ARGBToJ400(const uint8* src_argb, int src_stride_argb,
- uint8* dst_yj, int dst_stride_yj,
- int width, int height) {
- if (!src_argb || !dst_yj || width <= 0 || height == 0) {
- return -1;
- }
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
- // Coalesce rows.
- if (src_stride_argb == width * 4 &&
- dst_stride_yj == width) {
- width *= height;
- height = 1;
- src_stride_argb = dst_stride_yj = 0;
- }
- void (*ARGBToYJRow)(const uint8* src_argb, uint8* dst_yj, int pix) =
- ARGBToYJRow_C;
-#if defined(HAS_ARGBTOYJROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToYJRow = ARGBToYJRow_Unaligned_SSSE3;
- if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16) &&
- IS_ALIGNED(dst_yj, 16) && IS_ALIGNED(dst_stride_yj, 16)) {
- ARGBToYJRow = ARGBToYJRow_SSSE3;
- }
- }
- }
-#endif
-#if defined(HAS_ARGBTOYJROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
- ARGBToYJRow = ARGBToYJRow_Any_AVX2;
- if (IS_ALIGNED(width, 32)) {
- ARGBToYJRow = ARGBToYJRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_ARGBTOYJROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGBToYJRow = ARGBToYJRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGBToYJRow = ARGBToYJRow_NEON;
- }
- }
-#endif
-
- for (int y = 0; y < height; ++y) {
- ARGBToYJRow(src_argb, dst_yj, width);
- src_argb += src_stride_argb;
- dst_yj += dst_stride_yj;
- }
- return 0;
-}
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/convert_jpeg.cc b/drivers/theoraplayer/src/YUV/libyuv/src/convert_jpeg.cc
deleted file mode 100755
index bcb980f7f1..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/convert_jpeg.cc
+++ /dev/null
@@ -1,392 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/convert.h"
-
-#ifdef HAVE_JPEG
-#include "libyuv/mjpeg_decoder.h"
-#endif
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-#ifdef HAVE_JPEG
-struct I420Buffers {
- uint8* y;
- int y_stride;
- uint8* u;
- int u_stride;
- uint8* v;
- int v_stride;
- int w;
- int h;
-};
-
-static void JpegCopyI420(void* opaque,
- const uint8* const* data,
- const int* strides,
- int rows) {
- I420Buffers* dest = (I420Buffers*)(opaque);
- I420Copy(data[0], strides[0],
- data[1], strides[1],
- data[2], strides[2],
- dest->y, dest->y_stride,
- dest->u, dest->u_stride,
- dest->v, dest->v_stride,
- dest->w, rows);
- dest->y += rows * dest->y_stride;
- dest->u += ((rows + 1) >> 1) * dest->u_stride;
- dest->v += ((rows + 1) >> 1) * dest->v_stride;
- dest->h -= rows;
-}
-
-static void JpegI422ToI420(void* opaque,
- const uint8* const* data,
- const int* strides,
- int rows) {
- I420Buffers* dest = (I420Buffers*)(opaque);
- I422ToI420(data[0], strides[0],
- data[1], strides[1],
- data[2], strides[2],
- dest->y, dest->y_stride,
- dest->u, dest->u_stride,
- dest->v, dest->v_stride,
- dest->w, rows);
- dest->y += rows * dest->y_stride;
- dest->u += ((rows + 1) >> 1) * dest->u_stride;
- dest->v += ((rows + 1) >> 1) * dest->v_stride;
- dest->h -= rows;
-}
-
-static void JpegI444ToI420(void* opaque,
- const uint8* const* data,
- const int* strides,
- int rows) {
- I420Buffers* dest = (I420Buffers*)(opaque);
- I444ToI420(data[0], strides[0],
- data[1], strides[1],
- data[2], strides[2],
- dest->y, dest->y_stride,
- dest->u, dest->u_stride,
- dest->v, dest->v_stride,
- dest->w, rows);
- dest->y += rows * dest->y_stride;
- dest->u += ((rows + 1) >> 1) * dest->u_stride;
- dest->v += ((rows + 1) >> 1) * dest->v_stride;
- dest->h -= rows;
-}
-
-static void JpegI411ToI420(void* opaque,
- const uint8* const* data,
- const int* strides,
- int rows) {
- I420Buffers* dest = (I420Buffers*)(opaque);
- I411ToI420(data[0], strides[0],
- data[1], strides[1],
- data[2], strides[2],
- dest->y, dest->y_stride,
- dest->u, dest->u_stride,
- dest->v, dest->v_stride,
- dest->w, rows);
- dest->y += rows * dest->y_stride;
- dest->u += ((rows + 1) >> 1) * dest->u_stride;
- dest->v += ((rows + 1) >> 1) * dest->v_stride;
- dest->h -= rows;
-}
-
-static void JpegI400ToI420(void* opaque,
- const uint8* const* data,
- const int* strides,
- int rows) {
- I420Buffers* dest = (I420Buffers*)(opaque);
- I400ToI420(data[0], strides[0],
- dest->y, dest->y_stride,
- dest->u, dest->u_stride,
- dest->v, dest->v_stride,
- dest->w, rows);
- dest->y += rows * dest->y_stride;
- dest->u += ((rows + 1) >> 1) * dest->u_stride;
- dest->v += ((rows + 1) >> 1) * dest->v_stride;
- dest->h -= rows;
-}
-
-// Query size of MJPG in pixels.
-LIBYUV_API
-int MJPGSize(const uint8* sample, size_t sample_size,
- int* width, int* height) {
- MJpegDecoder mjpeg_decoder;
- LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size);
- if (ret) {
- *width = mjpeg_decoder.GetWidth();
- *height = mjpeg_decoder.GetHeight();
- }
- mjpeg_decoder.UnloadFrame();
- return ret ? 0 : -1; // -1 for runtime failure.
-}
-
-// MJPG (Motion JPeg) to I420
-// TODO(fbarchard): review w and h requirement. dw and dh may be enough.
-LIBYUV_API
-int MJPGToI420(const uint8* sample,
- size_t sample_size,
- uint8* y, int y_stride,
- uint8* u, int u_stride,
- uint8* v, int v_stride,
- int w, int h,
- int dw, int dh) {
- if (sample_size == kUnknownDataSize) {
- // ERROR: MJPEG frame size unknown
- return -1;
- }
-
- // TODO(fbarchard): Port MJpeg to C.
- MJpegDecoder mjpeg_decoder;
- LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size);
- if (ret && (mjpeg_decoder.GetWidth() != w ||
- mjpeg_decoder.GetHeight() != h)) {
- // ERROR: MJPEG frame has unexpected dimensions
- mjpeg_decoder.UnloadFrame();
- return 1; // runtime failure
- }
- if (ret) {
- I420Buffers bufs = { y, y_stride, u, u_stride, v, v_stride, dw, dh };
- // YUV420
- if (mjpeg_decoder.GetColorSpace() ==
- MJpegDecoder::kColorSpaceYCbCr &&
- mjpeg_decoder.GetNumComponents() == 3 &&
- mjpeg_decoder.GetVertSampFactor(0) == 2 &&
- mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
- mjpeg_decoder.GetVertSampFactor(1) == 1 &&
- mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
- mjpeg_decoder.GetVertSampFactor(2) == 1 &&
- mjpeg_decoder.GetHorizSampFactor(2) == 1) {
- ret = mjpeg_decoder.DecodeToCallback(&JpegCopyI420, &bufs, dw, dh);
- // YUV422
- } else if (mjpeg_decoder.GetColorSpace() ==
- MJpegDecoder::kColorSpaceYCbCr &&
- mjpeg_decoder.GetNumComponents() == 3 &&
- mjpeg_decoder.GetVertSampFactor(0) == 1 &&
- mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
- mjpeg_decoder.GetVertSampFactor(1) == 1 &&
- mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
- mjpeg_decoder.GetVertSampFactor(2) == 1 &&
- mjpeg_decoder.GetHorizSampFactor(2) == 1) {
- ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToI420, &bufs, dw, dh);
- // YUV444
- } else if (mjpeg_decoder.GetColorSpace() ==
- MJpegDecoder::kColorSpaceYCbCr &&
- mjpeg_decoder.GetNumComponents() == 3 &&
- mjpeg_decoder.GetVertSampFactor(0) == 1 &&
- mjpeg_decoder.GetHorizSampFactor(0) == 1 &&
- mjpeg_decoder.GetVertSampFactor(1) == 1 &&
- mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
- mjpeg_decoder.GetVertSampFactor(2) == 1 &&
- mjpeg_decoder.GetHorizSampFactor(2) == 1) {
- ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToI420, &bufs, dw, dh);
- // YUV411
- } else if (mjpeg_decoder.GetColorSpace() ==
- MJpegDecoder::kColorSpaceYCbCr &&
- mjpeg_decoder.GetNumComponents() == 3 &&
- mjpeg_decoder.GetVertSampFactor(0) == 1 &&
- mjpeg_decoder.GetHorizSampFactor(0) == 4 &&
- mjpeg_decoder.GetVertSampFactor(1) == 1 &&
- mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
- mjpeg_decoder.GetVertSampFactor(2) == 1 &&
- mjpeg_decoder.GetHorizSampFactor(2) == 1) {
- ret = mjpeg_decoder.DecodeToCallback(&JpegI411ToI420, &bufs, dw, dh);
- // YUV400
- } else if (mjpeg_decoder.GetColorSpace() ==
- MJpegDecoder::kColorSpaceGrayscale &&
- mjpeg_decoder.GetNumComponents() == 1 &&
- mjpeg_decoder.GetVertSampFactor(0) == 1 &&
- mjpeg_decoder.GetHorizSampFactor(0) == 1) {
- ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToI420, &bufs, dw, dh);
- } else {
- // TODO(fbarchard): Implement conversion for any other colorspace/sample
- // factors that occur in practice. 411 is supported by libjpeg
- // ERROR: Unable to convert MJPEG frame because format is not supported
- mjpeg_decoder.UnloadFrame();
- return 1;
- }
- }
- return ret ? 0 : 1;
-}
-
-#ifdef HAVE_JPEG
-struct ARGBBuffers {
- uint8* argb;
- int argb_stride;
- int w;
- int h;
-};
-
-static void JpegI420ToARGB(void* opaque,
- const uint8* const* data,
- const int* strides,
- int rows) {
- ARGBBuffers* dest = (ARGBBuffers*)(opaque);
- I420ToARGB(data[0], strides[0],
- data[1], strides[1],
- data[2], strides[2],
- dest->argb, dest->argb_stride,
- dest->w, rows);
- dest->argb += rows * dest->argb_stride;
- dest->h -= rows;
-}
-
-static void JpegI422ToARGB(void* opaque,
- const uint8* const* data,
- const int* strides,
- int rows) {
- ARGBBuffers* dest = (ARGBBuffers*)(opaque);
- I422ToARGB(data[0], strides[0],
- data[1], strides[1],
- data[2], strides[2],
- dest->argb, dest->argb_stride,
- dest->w, rows);
- dest->argb += rows * dest->argb_stride;
- dest->h -= rows;
-}
-
-static void JpegI444ToARGB(void* opaque,
- const uint8* const* data,
- const int* strides,
- int rows) {
- ARGBBuffers* dest = (ARGBBuffers*)(opaque);
- I444ToARGB(data[0], strides[0],
- data[1], strides[1],
- data[2], strides[2],
- dest->argb, dest->argb_stride,
- dest->w, rows);
- dest->argb += rows * dest->argb_stride;
- dest->h -= rows;
-}
-
-static void JpegI411ToARGB(void* opaque,
- const uint8* const* data,
- const int* strides,
- int rows) {
- ARGBBuffers* dest = (ARGBBuffers*)(opaque);
- I411ToARGB(data[0], strides[0],
- data[1], strides[1],
- data[2], strides[2],
- dest->argb, dest->argb_stride,
- dest->w, rows);
- dest->argb += rows * dest->argb_stride;
- dest->h -= rows;
-}
-
-static void JpegI400ToARGB(void* opaque,
- const uint8* const* data,
- const int* strides,
- int rows) {
- ARGBBuffers* dest = (ARGBBuffers*)(opaque);
- I400ToARGB(data[0], strides[0],
- dest->argb, dest->argb_stride,
- dest->w, rows);
- dest->argb += rows * dest->argb_stride;
- dest->h -= rows;
-}
-
-// MJPG (Motion JPeg) to ARGB
-// TODO(fbarchard): review w and h requirement. dw and dh may be enough.
-LIBYUV_API
-int MJPGToARGB(const uint8* sample,
- size_t sample_size,
- uint8* argb, int argb_stride,
- int w, int h,
- int dw, int dh) {
- if (sample_size == kUnknownDataSize) {
- // ERROR: MJPEG frame size unknown
- return -1;
- }
-
- // TODO(fbarchard): Port MJpeg to C.
- MJpegDecoder mjpeg_decoder;
- LIBYUV_BOOL ret = mjpeg_decoder.LoadFrame(sample, sample_size);
- if (ret && (mjpeg_decoder.GetWidth() != w ||
- mjpeg_decoder.GetHeight() != h)) {
- // ERROR: MJPEG frame has unexpected dimensions
- mjpeg_decoder.UnloadFrame();
- return 1; // runtime failure
- }
- if (ret) {
- ARGBBuffers bufs = { argb, argb_stride, dw, dh };
- // YUV420
- if (mjpeg_decoder.GetColorSpace() ==
- MJpegDecoder::kColorSpaceYCbCr &&
- mjpeg_decoder.GetNumComponents() == 3 &&
- mjpeg_decoder.GetVertSampFactor(0) == 2 &&
- mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
- mjpeg_decoder.GetVertSampFactor(1) == 1 &&
- mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
- mjpeg_decoder.GetVertSampFactor(2) == 1 &&
- mjpeg_decoder.GetHorizSampFactor(2) == 1) {
- ret = mjpeg_decoder.DecodeToCallback(&JpegI420ToARGB, &bufs, dw, dh);
- // YUV422
- } else if (mjpeg_decoder.GetColorSpace() ==
- MJpegDecoder::kColorSpaceYCbCr &&
- mjpeg_decoder.GetNumComponents() == 3 &&
- mjpeg_decoder.GetVertSampFactor(0) == 1 &&
- mjpeg_decoder.GetHorizSampFactor(0) == 2 &&
- mjpeg_decoder.GetVertSampFactor(1) == 1 &&
- mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
- mjpeg_decoder.GetVertSampFactor(2) == 1 &&
- mjpeg_decoder.GetHorizSampFactor(2) == 1) {
- ret = mjpeg_decoder.DecodeToCallback(&JpegI422ToARGB, &bufs, dw, dh);
- // YUV444
- } else if (mjpeg_decoder.GetColorSpace() ==
- MJpegDecoder::kColorSpaceYCbCr &&
- mjpeg_decoder.GetNumComponents() == 3 &&
- mjpeg_decoder.GetVertSampFactor(0) == 1 &&
- mjpeg_decoder.GetHorizSampFactor(0) == 1 &&
- mjpeg_decoder.GetVertSampFactor(1) == 1 &&
- mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
- mjpeg_decoder.GetVertSampFactor(2) == 1 &&
- mjpeg_decoder.GetHorizSampFactor(2) == 1) {
- ret = mjpeg_decoder.DecodeToCallback(&JpegI444ToARGB, &bufs, dw, dh);
- // YUV411
- } else if (mjpeg_decoder.GetColorSpace() ==
- MJpegDecoder::kColorSpaceYCbCr &&
- mjpeg_decoder.GetNumComponents() == 3 &&
- mjpeg_decoder.GetVertSampFactor(0) == 1 &&
- mjpeg_decoder.GetHorizSampFactor(0) == 4 &&
- mjpeg_decoder.GetVertSampFactor(1) == 1 &&
- mjpeg_decoder.GetHorizSampFactor(1) == 1 &&
- mjpeg_decoder.GetVertSampFactor(2) == 1 &&
- mjpeg_decoder.GetHorizSampFactor(2) == 1) {
- ret = mjpeg_decoder.DecodeToCallback(&JpegI411ToARGB, &bufs, dw, dh);
- // YUV400
- } else if (mjpeg_decoder.GetColorSpace() ==
- MJpegDecoder::kColorSpaceGrayscale &&
- mjpeg_decoder.GetNumComponents() == 1 &&
- mjpeg_decoder.GetVertSampFactor(0) == 1 &&
- mjpeg_decoder.GetHorizSampFactor(0) == 1) {
- ret = mjpeg_decoder.DecodeToCallback(&JpegI400ToARGB, &bufs, dw, dh);
- } else {
- // TODO(fbarchard): Implement conversion for any other colorspace/sample
- // factors that occur in practice. 411 is supported by libjpeg
- // ERROR: Unable to convert MJPEG frame because format is not supported
- mjpeg_decoder.UnloadFrame();
- return 1;
- }
- }
- return ret ? 0 : 1;
-}
-#endif
-
-#endif
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/convert_to_argb.cc b/drivers/theoraplayer/src/YUV/libyuv/src/convert_to_argb.cc
deleted file mode 100755
index 1b228a7b4d..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/convert_to_argb.cc
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/convert_argb.h"
-
-#include "libyuv/cpu_id.h"
-#include "libyuv/format_conversion.h"
-#ifdef HAVE_JPEG
-#include "libyuv/mjpeg_decoder.h"
-#endif
-#include "libyuv/rotate_argb.h"
-#include "libyuv/row.h"
-#include "libyuv/video_common.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// Convert camera sample to I420 with cropping, rotation and vertical flip.
-// src_width is used for source stride computation
-// src_height is used to compute location of planes, and indicate inversion
-// sample_size is measured in bytes and is the size of the frame.
-// With MJPEG it is the compressed size of the frame.
-LIBYUV_API
-int ConvertToARGB(const uint8* sample, size_t sample_size,
- uint8* crop_argb, int argb_stride,
- int crop_x, int crop_y,
- int src_width, int src_height,
- int crop_width, int crop_height,
- enum RotationMode rotation,
- uint32 fourcc) {
- uint32 format = CanonicalFourCC(fourcc);
- int aligned_src_width = (src_width + 1) & ~1;
- const uint8* src;
- const uint8* src_uv;
- int abs_src_height = (src_height < 0) ? -src_height : src_height;
- int inv_crop_height = (crop_height < 0) ? -crop_height : crop_height;
- int r = 0;
-
- // One pass rotation is available for some formats. For the rest, convert
- // to I420 (with optional vertical flipping) into a temporary I420 buffer,
- // and then rotate the I420 to the final destination buffer.
- // For in-place conversion, if destination crop_argb is same as source sample,
- // also enable temporary buffer.
- LIBYUV_BOOL need_buf = (rotation && format != FOURCC_ARGB) ||
- crop_argb == sample;
- uint8* tmp_argb = crop_argb;
- int tmp_argb_stride = argb_stride;
- uint8* rotate_buffer = NULL;
- int abs_crop_height = (crop_height < 0) ? -crop_height : crop_height;
-
- if (crop_argb == NULL || sample == NULL ||
- src_width <= 0 || crop_width <= 0 ||
- src_height == 0 || crop_height == 0) {
- return -1;
- }
- if (src_height < 0) {
- inv_crop_height = -inv_crop_height;
- }
-
- if (need_buf) {
- int argb_size = crop_width * abs_crop_height * 4;
- rotate_buffer = (uint8*)malloc(argb_size);
- if (!rotate_buffer) {
- return 1; // Out of memory runtime error.
- }
- crop_argb = rotate_buffer;
- argb_stride = crop_width;
- }
-
- switch (format) {
- // Single plane formats
- case FOURCC_YUY2:
- src = sample + (aligned_src_width * crop_y + crop_x) * 2;
- r = YUY2ToARGB(src, aligned_src_width * 2,
- crop_argb, argb_stride,
- crop_width, inv_crop_height);
- break;
- case FOURCC_UYVY:
- src = sample + (aligned_src_width * crop_y + crop_x) * 2;
- r = UYVYToARGB(src, aligned_src_width * 2,
- crop_argb, argb_stride,
- crop_width, inv_crop_height);
- break;
- case FOURCC_24BG:
- src = sample + (src_width * crop_y + crop_x) * 3;
- r = RGB24ToARGB(src, src_width * 3,
- crop_argb, argb_stride,
- crop_width, inv_crop_height);
- break;
- case FOURCC_RAW:
- src = sample + (src_width * crop_y + crop_x) * 3;
- r = RAWToARGB(src, src_width * 3,
- crop_argb, argb_stride,
- crop_width, inv_crop_height);
- break;
- case FOURCC_ARGB:
- src = sample + (src_width * crop_y + crop_x) * 4;
- r = ARGBToARGB(src, src_width * 4,
- crop_argb, argb_stride,
- crop_width, inv_crop_height);
- break;
- case FOURCC_BGRA:
- src = sample + (src_width * crop_y + crop_x) * 4;
- r = BGRAToARGB(src, src_width * 4,
- crop_argb, argb_stride,
- crop_width, inv_crop_height);
- break;
- case FOURCC_ABGR:
- src = sample + (src_width * crop_y + crop_x) * 4;
- r = ABGRToARGB(src, src_width * 4,
- crop_argb, argb_stride,
- crop_width, inv_crop_height);
- break;
- case FOURCC_RGBA:
- src = sample + (src_width * crop_y + crop_x) * 4;
- r = RGBAToARGB(src, src_width * 4,
- crop_argb, argb_stride,
- crop_width, inv_crop_height);
- break;
- case FOURCC_RGBP:
- src = sample + (src_width * crop_y + crop_x) * 2;
- r = RGB565ToARGB(src, src_width * 2,
- crop_argb, argb_stride,
- crop_width, inv_crop_height);
- break;
- case FOURCC_RGBO:
- src = sample + (src_width * crop_y + crop_x) * 2;
- r = ARGB1555ToARGB(src, src_width * 2,
- crop_argb, argb_stride,
- crop_width, inv_crop_height);
- break;
- case FOURCC_R444:
- src = sample + (src_width * crop_y + crop_x) * 2;
- r = ARGB4444ToARGB(src, src_width * 2,
- crop_argb, argb_stride,
- crop_width, inv_crop_height);
- break;
- // TODO(fbarchard): Support cropping Bayer by odd numbers
- // by adjusting fourcc.
- case FOURCC_BGGR:
- src = sample + (src_width * crop_y + crop_x);
- r = BayerBGGRToARGB(src, src_width,
- crop_argb, argb_stride,
- crop_width, inv_crop_height);
- break;
-
- case FOURCC_GBRG:
- src = sample + (src_width * crop_y + crop_x);
- r = BayerGBRGToARGB(src, src_width,
- crop_argb, argb_stride,
- crop_width, inv_crop_height);
- break;
-
- case FOURCC_GRBG:
- src = sample + (src_width * crop_y + crop_x);
- r = BayerGRBGToARGB(src, src_width,
- crop_argb, argb_stride,
- crop_width, inv_crop_height);
- break;
-
- case FOURCC_RGGB:
- src = sample + (src_width * crop_y + crop_x);
- r = BayerRGGBToARGB(src, src_width,
- crop_argb, argb_stride,
- crop_width, inv_crop_height);
- break;
-
- case FOURCC_I400:
- src = sample + src_width * crop_y + crop_x;
- r = I400ToARGB(src, src_width,
- crop_argb, argb_stride,
- crop_width, inv_crop_height);
- break;
-
- // Biplanar formats
- case FOURCC_NV12:
- src = sample + (src_width * crop_y + crop_x);
- src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x;
- r = NV12ToARGB(src, src_width,
- src_uv, aligned_src_width,
- crop_argb, argb_stride,
- crop_width, inv_crop_height);
- break;
- case FOURCC_NV21:
- src = sample + (src_width * crop_y + crop_x);
- src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x;
- // Call NV12 but with u and v parameters swapped.
- r = NV21ToARGB(src, src_width,
- src_uv, aligned_src_width,
- crop_argb, argb_stride,
- crop_width, inv_crop_height);
- break;
- case FOURCC_M420:
- src = sample + (src_width * crop_y) * 12 / 8 + crop_x;
- r = M420ToARGB(src, src_width,
- crop_argb, argb_stride,
- crop_width, inv_crop_height);
- break;
-// case FOURCC_Q420:
-// src = sample + (src_width + aligned_src_width * 2) * crop_y + crop_x;
-// src_uv = sample + (src_width + aligned_src_width * 2) * crop_y +
-// src_width + crop_x * 2;
-// r = Q420ToARGB(src, src_width * 3,
-// src_uv, src_width * 3,
-// crop_argb, argb_stride,
-// crop_width, inv_crop_height);
-// break;
- // Triplanar formats
- case FOURCC_I420:
- case FOURCC_YU12:
- case FOURCC_YV12: {
- const uint8* src_y = sample + (src_width * crop_y + crop_x);
- const uint8* src_u;
- const uint8* src_v;
- int halfwidth = (src_width + 1) / 2;
- int halfheight = (abs_src_height + 1) / 2;
- if (format == FOURCC_YV12) {
- src_v = sample + src_width * abs_src_height +
- (halfwidth * crop_y + crop_x) / 2;
- src_u = sample + src_width * abs_src_height +
- halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
- } else {
- src_u = sample + src_width * abs_src_height +
- (halfwidth * crop_y + crop_x) / 2;
- src_v = sample + src_width * abs_src_height +
- halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
- }
- r = I420ToARGB(src_y, src_width,
- src_u, halfwidth,
- src_v, halfwidth,
- crop_argb, argb_stride,
- crop_width, inv_crop_height);
- break;
- }
- case FOURCC_I422:
- case FOURCC_YV16: {
- const uint8* src_y = sample + src_width * crop_y + crop_x;
- const uint8* src_u;
- const uint8* src_v;
- int halfwidth = (src_width + 1) / 2;
- if (format == FOURCC_YV16) {
- src_v = sample + src_width * abs_src_height +
- halfwidth * crop_y + crop_x / 2;
- src_u = sample + src_width * abs_src_height +
- halfwidth * (abs_src_height + crop_y) + crop_x / 2;
- } else {
- src_u = sample + src_width * abs_src_height +
- halfwidth * crop_y + crop_x / 2;
- src_v = sample + src_width * abs_src_height +
- halfwidth * (abs_src_height + crop_y) + crop_x / 2;
- }
- r = I422ToARGB(src_y, src_width,
- src_u, halfwidth,
- src_v, halfwidth,
- crop_argb, argb_stride,
- crop_width, inv_crop_height);
- break;
- }
- case FOURCC_I444:
- case FOURCC_YV24: {
- const uint8* src_y = sample + src_width * crop_y + crop_x;
- const uint8* src_u;
- const uint8* src_v;
- if (format == FOURCC_YV24) {
- src_v = sample + src_width * (abs_src_height + crop_y) + crop_x;
- src_u = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
- } else {
- src_u = sample + src_width * (abs_src_height + crop_y) + crop_x;
- src_v = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
- }
- r = I444ToARGB(src_y, src_width,
- src_u, src_width,
- src_v, src_width,
- crop_argb, argb_stride,
- crop_width, inv_crop_height);
- break;
- }
- case FOURCC_I411: {
- int quarterwidth = (src_width + 3) / 4;
- const uint8* src_y = sample + src_width * crop_y + crop_x;
- const uint8* src_u = sample + src_width * abs_src_height +
- quarterwidth * crop_y + crop_x / 4;
- const uint8* src_v = sample + src_width * abs_src_height +
- quarterwidth * (abs_src_height + crop_y) + crop_x / 4;
- r = I411ToARGB(src_y, src_width,
- src_u, quarterwidth,
- src_v, quarterwidth,
- crop_argb, argb_stride,
- crop_width, inv_crop_height);
- break;
- }
-#ifdef HAVE_JPEG
- case FOURCC_MJPG:
- r = MJPGToARGB(sample, sample_size,
- crop_argb, argb_stride,
- src_width, abs_src_height, crop_width, inv_crop_height);
- break;
-#endif
- default:
- r = -1; // unknown fourcc - return failure code.
- }
-
- if (need_buf) {
- if (!r) {
- r = ARGBRotate(crop_argb, argb_stride,
- tmp_argb, tmp_argb_stride,
- crop_width, abs_crop_height, rotation);
- }
- free(rotate_buffer);
- }
-
- return r;
-}
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/convert_to_i420.cc b/drivers/theoraplayer/src/YUV/libyuv/src/convert_to_i420.cc
deleted file mode 100755
index 7b194fff72..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/convert_to_i420.cc
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include <stdlib.h>
-
-#include "libyuv/convert.h"
-
-#include "libyuv/format_conversion.h"
-#include "libyuv/video_common.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// Convert camera sample to I420 with cropping, rotation and vertical flip.
-// src_width is used for source stride computation
-// src_height is used to compute location of planes, and indicate inversion
-// sample_size is measured in bytes and is the size of the frame.
-// With MJPEG it is the compressed size of the frame.
-LIBYUV_API
-int ConvertToI420(const uint8* sample,
- size_t sample_size,
- uint8* y, int y_stride,
- uint8* u, int u_stride,
- uint8* v, int v_stride,
- int crop_x, int crop_y,
- int src_width, int src_height,
- int crop_width, int crop_height,
- enum RotationMode rotation,
- uint32 fourcc) {
- uint32 format = CanonicalFourCC(fourcc);
- int aligned_src_width = (src_width + 1) & ~1;
- const uint8* src;
- const uint8* src_uv;
- int abs_src_height = (src_height < 0) ? -src_height : src_height;
- int inv_crop_height = (crop_height < 0) ? -crop_height : crop_height;
- int r = 0;
- LIBYUV_BOOL need_buf = (rotation && format != FOURCC_I420 &&
- format != FOURCC_NV12 && format != FOURCC_NV21 &&
- format != FOURCC_YU12 && format != FOURCC_YV12) || y == sample;
- uint8* tmp_y = y;
- uint8* tmp_u = u;
- uint8* tmp_v = v;
- int tmp_y_stride = y_stride;
- int tmp_u_stride = u_stride;
- int tmp_v_stride = v_stride;
- uint8* rotate_buffer = NULL;
- int abs_crop_height = (crop_height < 0) ? -crop_height : crop_height;
-
- if (!y || !u || !v || !sample ||
- src_width <= 0 || crop_width <= 0 ||
- src_height == 0 || crop_height == 0) {
- return -1;
- }
- if (src_height < 0) {
- inv_crop_height = -inv_crop_height;
- }
-
- // One pass rotation is available for some formats. For the rest, convert
- // to I420 (with optional vertical flipping) into a temporary I420 buffer,
- // and then rotate the I420 to the final destination buffer.
- // For in-place conversion, if destination y is same as source sample,
- // also enable temporary buffer.
- if (need_buf) {
- int y_size = crop_width * abs_crop_height;
- int uv_size = ((crop_width + 1) / 2) * ((abs_crop_height + 1) / 2);
- rotate_buffer = (uint8*)malloc(y_size + uv_size * 2);
- if (!rotate_buffer) {
- return 1; // Out of memory runtime error.
- }
- y = rotate_buffer;
- u = y + y_size;
- v = u + uv_size;
- y_stride = crop_width;
- u_stride = v_stride = ((crop_width + 1) / 2);
- }
-
- switch (format) {
- // Single plane formats
- case FOURCC_YUY2:
- src = sample + (aligned_src_width * crop_y + crop_x) * 2;
- r = YUY2ToI420(src, aligned_src_width * 2,
- y, y_stride,
- u, u_stride,
- v, v_stride,
- crop_width, inv_crop_height);
- break;
- case FOURCC_UYVY:
- src = sample + (aligned_src_width * crop_y + crop_x) * 2;
- r = UYVYToI420(src, aligned_src_width * 2,
- y, y_stride,
- u, u_stride,
- v, v_stride,
- crop_width, inv_crop_height);
- break;
- case FOURCC_RGBP:
- src = sample + (src_width * crop_y + crop_x) * 2;
- r = RGB565ToI420(src, src_width * 2,
- y, y_stride,
- u, u_stride,
- v, v_stride,
- crop_width, inv_crop_height);
- break;
- case FOURCC_RGBO:
- src = sample + (src_width * crop_y + crop_x) * 2;
- r = ARGB1555ToI420(src, src_width * 2,
- y, y_stride,
- u, u_stride,
- v, v_stride,
- crop_width, inv_crop_height);
- break;
- case FOURCC_R444:
- src = sample + (src_width * crop_y + crop_x) * 2;
- r = ARGB4444ToI420(src, src_width * 2,
- y, y_stride,
- u, u_stride,
- v, v_stride,
- crop_width, inv_crop_height);
- break;
- case FOURCC_24BG:
- src = sample + (src_width * crop_y + crop_x) * 3;
- r = RGB24ToI420(src, src_width * 3,
- y, y_stride,
- u, u_stride,
- v, v_stride,
- crop_width, inv_crop_height);
- break;
- case FOURCC_RAW:
- src = sample + (src_width * crop_y + crop_x) * 3;
- r = RAWToI420(src, src_width * 3,
- y, y_stride,
- u, u_stride,
- v, v_stride,
- crop_width, inv_crop_height);
- break;
- case FOURCC_ARGB:
- src = sample + (src_width * crop_y + crop_x) * 4;
- r = ARGBToI420(src, src_width * 4,
- y, y_stride,
- u, u_stride,
- v, v_stride,
- crop_width, inv_crop_height);
- break;
- case FOURCC_BGRA:
- src = sample + (src_width * crop_y + crop_x) * 4;
- r = BGRAToI420(src, src_width * 4,
- y, y_stride,
- u, u_stride,
- v, v_stride,
- crop_width, inv_crop_height);
- break;
- case FOURCC_ABGR:
- src = sample + (src_width * crop_y + crop_x) * 4;
- r = ABGRToI420(src, src_width * 4,
- y, y_stride,
- u, u_stride,
- v, v_stride,
- crop_width, inv_crop_height);
- break;
- case FOURCC_RGBA:
- src = sample + (src_width * crop_y + crop_x) * 4;
- r = RGBAToI420(src, src_width * 4,
- y, y_stride,
- u, u_stride,
- v, v_stride,
- crop_width, inv_crop_height);
- break;
- // TODO(fbarchard): Support cropping Bayer by odd numbers
- // by adjusting fourcc.
- case FOURCC_BGGR:
- src = sample + (src_width * crop_y + crop_x);
- r = BayerBGGRToI420(src, src_width,
- y, y_stride,
- u, u_stride,
- v, v_stride,
- crop_width, inv_crop_height);
- break;
- case FOURCC_GBRG:
- src = sample + (src_width * crop_y + crop_x);
- r = BayerGBRGToI420(src, src_width,
- y, y_stride,
- u, u_stride,
- v, v_stride,
- crop_width, inv_crop_height);
- break;
- case FOURCC_GRBG:
- src = sample + (src_width * crop_y + crop_x);
- r = BayerGRBGToI420(src, src_width,
- y, y_stride,
- u, u_stride,
- v, v_stride,
- crop_width, inv_crop_height);
- break;
- case FOURCC_RGGB:
- src = sample + (src_width * crop_y + crop_x);
- r = BayerRGGBToI420(src, src_width,
- y, y_stride,
- u, u_stride,
- v, v_stride,
- crop_width, inv_crop_height);
- break;
- case FOURCC_I400:
- src = sample + src_width * crop_y + crop_x;
- r = I400ToI420(src, src_width,
- y, y_stride,
- u, u_stride,
- v, v_stride,
- crop_width, inv_crop_height);
- break;
- // Biplanar formats
- case FOURCC_NV12:
- src = sample + (src_width * crop_y + crop_x);
- src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x;
- r = NV12ToI420Rotate(src, src_width,
- src_uv, aligned_src_width,
- y, y_stride,
- u, u_stride,
- v, v_stride,
- crop_width, inv_crop_height, rotation);
- break;
- case FOURCC_NV21:
- src = sample + (src_width * crop_y + crop_x);
- src_uv = sample + aligned_src_width * (src_height + crop_y / 2) + crop_x;
- // Call NV12 but with u and v parameters swapped.
- r = NV12ToI420Rotate(src, src_width,
- src_uv, aligned_src_width,
- y, y_stride,
- v, v_stride,
- u, u_stride,
- crop_width, inv_crop_height, rotation);
- break;
- case FOURCC_M420:
- src = sample + (src_width * crop_y) * 12 / 8 + crop_x;
- r = M420ToI420(src, src_width,
- y, y_stride,
- u, u_stride,
- v, v_stride,
- crop_width, inv_crop_height);
- break;
- case FOURCC_Q420:
- src = sample + (src_width + aligned_src_width * 2) * crop_y + crop_x;
- src_uv = sample + (src_width + aligned_src_width * 2) * crop_y +
- src_width + crop_x * 2;
- r = Q420ToI420(src, src_width * 3,
- src_uv, src_width * 3,
- y, y_stride,
- u, u_stride,
- v, v_stride,
- crop_width, inv_crop_height);
- break;
- // Triplanar formats
- case FOURCC_I420:
- case FOURCC_YU12:
- case FOURCC_YV12: {
- const uint8* src_y = sample + (src_width * crop_y + crop_x);
- const uint8* src_u;
- const uint8* src_v;
- int halfwidth = (src_width + 1) / 2;
- int halfheight = (abs_src_height + 1) / 2;
- if (format == FOURCC_YV12) {
- src_v = sample + src_width * abs_src_height +
- (halfwidth * crop_y + crop_x) / 2;
- src_u = sample + src_width * abs_src_height +
- halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
- } else {
- src_u = sample + src_width * abs_src_height +
- (halfwidth * crop_y + crop_x) / 2;
- src_v = sample + src_width * abs_src_height +
- halfwidth * (halfheight + crop_y / 2) + crop_x / 2;
- }
- r = I420Rotate(src_y, src_width,
- src_u, halfwidth,
- src_v, halfwidth,
- y, y_stride,
- u, u_stride,
- v, v_stride,
- crop_width, inv_crop_height, rotation);
- break;
- }
- case FOURCC_I422:
- case FOURCC_YV16: {
- const uint8* src_y = sample + src_width * crop_y + crop_x;
- const uint8* src_u;
- const uint8* src_v;
- int halfwidth = (src_width + 1) / 2;
- if (format == FOURCC_YV16) {
- src_v = sample + src_width * abs_src_height +
- halfwidth * crop_y + crop_x / 2;
- src_u = sample + src_width * abs_src_height +
- halfwidth * (abs_src_height + crop_y) + crop_x / 2;
- } else {
- src_u = sample + src_width * abs_src_height +
- halfwidth * crop_y + crop_x / 2;
- src_v = sample + src_width * abs_src_height +
- halfwidth * (abs_src_height + crop_y) + crop_x / 2;
- }
- r = I422ToI420(src_y, src_width,
- src_u, halfwidth,
- src_v, halfwidth,
- y, y_stride,
- u, u_stride,
- v, v_stride,
- crop_width, inv_crop_height);
- break;
- }
- case FOURCC_I444:
- case FOURCC_YV24: {
- const uint8* src_y = sample + src_width * crop_y + crop_x;
- const uint8* src_u;
- const uint8* src_v;
- if (format == FOURCC_YV24) {
- src_v = sample + src_width * (abs_src_height + crop_y) + crop_x;
- src_u = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
- } else {
- src_u = sample + src_width * (abs_src_height + crop_y) + crop_x;
- src_v = sample + src_width * (abs_src_height * 2 + crop_y) + crop_x;
- }
- r = I444ToI420(src_y, src_width,
- src_u, src_width,
- src_v, src_width,
- y, y_stride,
- u, u_stride,
- v, v_stride,
- crop_width, inv_crop_height);
- break;
- }
- case FOURCC_I411: {
- int quarterwidth = (src_width + 3) / 4;
- const uint8* src_y = sample + src_width * crop_y + crop_x;
- const uint8* src_u = sample + src_width * abs_src_height +
- quarterwidth * crop_y + crop_x / 4;
- const uint8* src_v = sample + src_width * abs_src_height +
- quarterwidth * (abs_src_height + crop_y) + crop_x / 4;
- r = I411ToI420(src_y, src_width,
- src_u, quarterwidth,
- src_v, quarterwidth,
- y, y_stride,
- u, u_stride,
- v, v_stride,
- crop_width, inv_crop_height);
- break;
- }
-#ifdef HAVE_JPEG
- case FOURCC_MJPG:
- r = MJPGToI420(sample, sample_size,
- y, y_stride,
- u, u_stride,
- v, v_stride,
- src_width, abs_src_height, crop_width, inv_crop_height);
- break;
-#endif
- default:
- r = -1; // unknown fourcc - return failure code.
- }
-
- if (need_buf) {
- if (!r) {
- r = I420Rotate(y, y_stride,
- u, u_stride,
- v, v_stride,
- tmp_y, tmp_y_stride,
- tmp_u, tmp_u_stride,
- tmp_v, tmp_v_stride,
- crop_width, abs_crop_height, rotation);
- }
- free(rotate_buffer);
- }
-
- return r;
-}
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/cpu_id.cc b/drivers/theoraplayer/src/YUV/libyuv/src/cpu_id.cc
deleted file mode 100755
index f52bd95551..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/cpu_id.cc
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/cpu_id.h"
-
-#ifdef _ANDROID //libtheoraplayer addition for cpu feature detection
-#include "cpu-features.h"
-#endif
-
-#ifdef _MSC_VER
-#include <intrin.h> // For __cpuidex()
-#endif
-#if !defined(__pnacl__) && !defined(__CLR_VER) && \
- !defined(__native_client__) && defined(_M_X64) && \
- defined(_MSC_VER) && (_MSC_FULL_VER >= 160040219)
-#include <immintrin.h> // For _xgetbv()
-#endif
-
-#if !defined(__native_client__)
-#include <stdlib.h> // For getenv()
-#endif
-
-// For ArmCpuCaps() but unittested on all platforms
-#include <stdio.h>
-#include <string.h>
-
-#include "libyuv/basic_types.h" // For CPU_X86
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// For functions that use the stack and have runtime checks for overflow,
-// use SAFEBUFFERS to avoid additional check.
-#if defined(_MSC_VER) && (_MSC_FULL_VER >= 160040219)
-#define SAFEBUFFERS __declspec(safebuffers)
-#else
-#define SAFEBUFFERS
-#endif
-
-// Low level cpuid for X86. Returns zeros on other CPUs.
-#if !defined(__pnacl__) && !defined(__CLR_VER) && \
- (defined(_M_IX86) || defined(_M_X64) || \
- defined(__i386__) || defined(__x86_64__))
-LIBYUV_API
-void CpuId(uint32 info_eax, uint32 info_ecx, uint32* cpu_info) {
-#if defined(_MSC_VER)
-#if (_MSC_FULL_VER >= 160040219)
- __cpuidex((int*)(cpu_info), info_eax, info_ecx);
-#elif defined(_M_IX86)
- __asm {
- mov eax, info_eax
- mov ecx, info_ecx
- mov edi, cpu_info
- cpuid
- mov [edi], eax
- mov [edi + 4], ebx
- mov [edi + 8], ecx
- mov [edi + 12], edx
- }
-#else
- if (info_ecx == 0) {
- __cpuid((int*)(cpu_info), info_eax);
- } else {
- cpu_info[3] = cpu_info[2] = cpu_info[1] = cpu_info[0] = 0;
- }
-#endif
-#else // defined(_MSC_VER)
- uint32 info_ebx, info_edx;
- asm volatile ( // NOLINT
-#if defined( __i386__) && defined(__PIC__)
- // Preserve ebx for fpic 32 bit.
- "mov %%ebx, %%edi \n"
- "cpuid \n"
- "xchg %%edi, %%ebx \n"
- : "=D" (info_ebx),
-#else
- "cpuid \n"
- : "=b" (info_ebx),
-#endif // defined( __i386__) && defined(__PIC__)
- "+a" (info_eax), "+c" (info_ecx), "=d" (info_edx));
- cpu_info[0] = info_eax;
- cpu_info[1] = info_ebx;
- cpu_info[2] = info_ecx;
- cpu_info[3] = info_edx;
-#endif // defined(_MSC_VER)
-}
-
-#if !defined(__native_client__)
-#define HAS_XGETBV
-// X86 CPUs have xgetbv to detect OS saves high parts of ymm registers.
-int TestOsSaveYmm() {
- uint32 xcr0 = 0u;
-#if defined(_MSC_VER) && (_MSC_FULL_VER >= 160040219)
- xcr0 = (uint32)(_xgetbv(0)); // VS2010 SP1 required.
-#elif defined(_M_IX86)
- __asm {
- xor ecx, ecx // xcr 0
- _asm _emit 0x0f _asm _emit 0x01 _asm _emit 0xd0 // For VS2010 and earlier.
- mov xcr0, eax
- }
-#elif defined(__i386__) || defined(__x86_64__)
- asm(".byte 0x0f, 0x01, 0xd0" : "=a" (xcr0) : "c" (0) : "%edx");
-#endif // defined(_MSC_VER)
- return((xcr0 & 6) == 6); // Is ymm saved?
-}
-#endif // !defined(__native_client__)
-#else
-LIBYUV_API
-void CpuId(uint32 eax, uint32 ecx, uint32* cpu_info) {
- cpu_info[0] = cpu_info[1] = cpu_info[2] = cpu_info[3] = 0;
-}
-#endif
-
-// based on libvpx arm_cpudetect.c
-// For Arm, but public to allow testing on any CPU
-LIBYUV_API SAFEBUFFERS
-int ArmCpuCaps(const char* cpuinfo_name) {
- char cpuinfo_line[512];
- FILE* f = fopen(cpuinfo_name, "r");
- if (!f) {
- // Assume Neon if /proc/cpuinfo is unavailable.
- // This will occur for Chrome sandbox for Pepper or Render process.
- return kCpuHasNEON;
- }
- while (fgets(cpuinfo_line, sizeof(cpuinfo_line) - 1, f)) {
- if (memcmp(cpuinfo_line, "Features", 8) == 0) {
- char* p = strstr(cpuinfo_line, " neon");
- if (p && (p[5] == ' ' || p[5] == '\n')) {
- fclose(f);
- return kCpuHasNEON;
- }
- }
- }
- fclose(f);
- return 0;
-}
-
-#if defined(__mips__) && defined(__linux__)
-static int MipsCpuCaps(const char* search_string) {
- char cpuinfo_line[512];
- const char* file_name = "/proc/cpuinfo";
- FILE* f = fopen(file_name, "r");
- if (!f) {
- // Assume DSP if /proc/cpuinfo is unavailable.
- // This will occur for Chrome sandbox for Pepper or Render process.
- return kCpuHasMIPS_DSP;
- }
- while (fgets(cpuinfo_line, sizeof(cpuinfo_line) - 1, f) != NULL) {
- if (strstr(cpuinfo_line, search_string) != NULL) {
- fclose(f);
- return kCpuHasMIPS_DSP;
- }
- }
- fclose(f);
- return 0;
-}
-#endif
-
-// CPU detect function for SIMD instruction sets.
-LIBYUV_API
-int cpu_info_ = kCpuInit; // cpu_info is not initialized yet.
-
-// Test environment variable for disabling CPU features. Any non-zero value
-// to disable. Zero ignored to make it easy to set the variable on/off.
-#if !defined(__native_client__) && !defined(_M_ARM)
-
-static LIBYUV_BOOL TestEnv(const char* name) {
-#ifndef _WINRT
- const char* var = getenv(name);
- if (var) {
- if (var[0] != '0') {
- return LIBYUV_TRUE;
- }
- }
-#endif
- return LIBYUV_FALSE;
-}
-#else // nacl does not support getenv().
-static LIBYUV_BOOL TestEnv(const char*) {
- return LIBYUV_FALSE;
-}
-#endif
-
-LIBYUV_API SAFEBUFFERS
-int InitCpuFlags(void) {
-#if !defined(__pnacl__) && !defined(__CLR_VER) && defined(CPU_X86)
-
- uint32 cpu_info1[4] = { 0, 0, 0, 0 };
- uint32 cpu_info7[4] = { 0, 0, 0, 0 };
- CpuId(1, 0, cpu_info1);
- CpuId(7, 0, cpu_info7);
- cpu_info_ = ((cpu_info1[3] & 0x04000000) ? kCpuHasSSE2 : 0) |
- ((cpu_info1[2] & 0x00000200) ? kCpuHasSSSE3 : 0) |
- ((cpu_info1[2] & 0x00080000) ? kCpuHasSSE41 : 0) |
- ((cpu_info1[2] & 0x00100000) ? kCpuHasSSE42 : 0) |
- ((cpu_info7[1] & 0x00000200) ? kCpuHasERMS : 0) |
- ((cpu_info1[2] & 0x00001000) ? kCpuHasFMA3 : 0) |
- kCpuHasX86;
-#ifdef HAS_XGETBV
- if ((cpu_info1[2] & 0x18000000) == 0x18000000 && // AVX and OSSave
- TestOsSaveYmm()) { // Saves YMM.
- cpu_info_ |= ((cpu_info7[1] & 0x00000020) ? kCpuHasAVX2 : 0) |
- kCpuHasAVX;
- }
-#endif
- // Environment variable overrides for testing.
- if (TestEnv("LIBYUV_DISABLE_X86")) {
- cpu_info_ &= ~kCpuHasX86;
- }
- if (TestEnv("LIBYUV_DISABLE_SSE2")) {
- cpu_info_ &= ~kCpuHasSSE2;
- }
- if (TestEnv("LIBYUV_DISABLE_SSSE3")) {
- cpu_info_ &= ~kCpuHasSSSE3;
- }
- if (TestEnv("LIBYUV_DISABLE_SSE41")) {
- cpu_info_ &= ~kCpuHasSSE41;
- }
- if (TestEnv("LIBYUV_DISABLE_SSE42")) {
- cpu_info_ &= ~kCpuHasSSE42;
- }
- if (TestEnv("LIBYUV_DISABLE_AVX")) {
- cpu_info_ &= ~kCpuHasAVX;
- }
- if (TestEnv("LIBYUV_DISABLE_AVX2")) {
- cpu_info_ &= ~kCpuHasAVX2;
- }
- if (TestEnv("LIBYUV_DISABLE_ERMS")) {
- cpu_info_ &= ~kCpuHasERMS;
- }
- if (TestEnv("LIBYUV_DISABLE_FMA3")) {
- cpu_info_ &= ~kCpuHasFMA3;
- }
-#elif defined(__mips__) && defined(__linux__)
- // Linux mips parse text file for dsp detect.
- cpu_info_ = MipsCpuCaps("dsp"); // set kCpuHasMIPS_DSP.
-#if defined(__mips_dspr2)
- cpu_info_ |= kCpuHasMIPS_DSPR2;
-#endif
- cpu_info_ |= kCpuHasMIPS;
-
- if (getenv("LIBYUV_DISABLE_MIPS")) {
- cpu_info_ &= ~kCpuHasMIPS;
- }
- if (getenv("LIBYUV_DISABLE_MIPS_DSP")) {
- cpu_info_ &= ~kCpuHasMIPS_DSP;
- }
- if (getenv("LIBYUV_DISABLE_MIPS_DSPR2")) {
- cpu_info_ &= ~kCpuHasMIPS_DSPR2;
- }
-#elif defined(__arm__)
-// gcc -mfpu=neon defines __ARM_NEON__
-// __ARM_NEON__ generates code that requires Neon. NaCL also requires Neon.
-// For Linux, /proc/cpuinfo can be tested but without that assume Neon.
-#if defined(__ARM_NEON__) || defined(__native_client__) || !defined(__linux__)
-#ifdef _ANDROID
- cpu_info_ = ArmCpuCaps("/proc/cpuinfo"); // libtheoraplayer #ifdef addition, just in case, android gave us troubles
-#else
- cpu_info_ = kCpuHasNEON;
-#endif
-#else
- // Linux arm parse text file for neon detect.
- cpu_info_ = ArmCpuCaps("/proc/cpuinfo");
-#endif
- cpu_info_ |= kCpuHasARM;
- if (TestEnv("LIBYUV_DISABLE_NEON")) {
- cpu_info_ &= ~kCpuHasNEON;
- }
-#ifdef _ANDROID
- // libtheoraplayer addition to disable NEON support on android devices that don't support it, once again, just in case
- if ((android_getCpuFeaturesExt() & ANDROID_CPU_ARM_FEATURE_NEON) == 0)
- {
- cpu_info_ = kCpuHasARM;
- }
-#endif
-#endif // __arm__
- if (TestEnv("LIBYUV_DISABLE_ASM")) {
- cpu_info_ = 0;
- }
- return cpu_info_;
-}
-
-LIBYUV_API
-void MaskCpuFlags(int enable_flags) {
- cpu_info_ = InitCpuFlags() & enable_flags;
-}
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/format_conversion.cc b/drivers/theoraplayer/src/YUV/libyuv/src/format_conversion.cc
deleted file mode 100755
index a3daf96a98..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/format_conversion.cc
+++ /dev/null
@@ -1,552 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/format_conversion.h"
-
-#include "libyuv/basic_types.h"
-#include "libyuv/cpu_id.h"
-#include "libyuv/video_common.h"
-#include "libyuv/row.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// generate a selector mask useful for pshufb
-static uint32 GenerateSelector(int select0, int select1) {
- return (uint32)(select0) |
- (uint32)((select1 + 4) << 8) |
- (uint32)((select0 + 8) << 16) |
- (uint32)((select1 + 12) << 24);
-}
-
-static int MakeSelectors(const int blue_index,
- const int green_index,
- const int red_index,
- uint32 dst_fourcc_bayer,
- uint32* index_map) {
- // Now build a lookup table containing the indices for the four pixels in each
- // 2x2 Bayer grid.
- switch (dst_fourcc_bayer) {
- case FOURCC_BGGR:
- index_map[0] = GenerateSelector(blue_index, green_index);
- index_map[1] = GenerateSelector(green_index, red_index);
- break;
- case FOURCC_GBRG:
- index_map[0] = GenerateSelector(green_index, blue_index);
- index_map[1] = GenerateSelector(red_index, green_index);
- break;
- case FOURCC_RGGB:
- index_map[0] = GenerateSelector(red_index, green_index);
- index_map[1] = GenerateSelector(green_index, blue_index);
- break;
- case FOURCC_GRBG:
- index_map[0] = GenerateSelector(green_index, red_index);
- index_map[1] = GenerateSelector(blue_index, green_index);
- break;
- default:
- return -1; // Bad FourCC
- }
- return 0;
-}
-
-// Converts 32 bit ARGB to Bayer RGB formats.
-LIBYUV_API
-int ARGBToBayer(const uint8* src_argb, int src_stride_argb,
- uint8* dst_bayer, int dst_stride_bayer,
- int width, int height,
- uint32 dst_fourcc_bayer) {
- int y;
- const int blue_index = 0; // Offsets for ARGB format
- const int green_index = 1;
- const int red_index = 2;
- uint32 index_map[2];
- void (*ARGBToBayerRow)(const uint8* src_argb, uint8* dst_bayer,
- uint32 selector, int pix) = ARGBToBayerRow_C;
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
-#if defined(HAS_ARGBTOBAYERROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 8 &&
- IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) {
- ARGBToBayerRow = ARGBToBayerRow_Any_SSSE3;
- if (IS_ALIGNED(width, 8)) {
- ARGBToBayerRow = ARGBToBayerRow_SSSE3;
- }
- }
-#elif defined(HAS_ARGBTOBAYERROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGBToBayerRow = ARGBToBayerRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGBToBayerRow = ARGBToBayerRow_NEON;
- }
- }
-#endif
- if (MakeSelectors(blue_index, green_index, red_index,
- dst_fourcc_bayer, index_map)) {
- return -1; // Bad FourCC
- }
-
- for (y = 0; y < height; ++y) {
- ARGBToBayerRow(src_argb, dst_bayer, index_map[y & 1], width);
- src_argb += src_stride_argb;
- dst_bayer += dst_stride_bayer;
- }
- return 0;
-}
-
-#define AVG(a, b) (((a) + (b)) >> 1)
-
-static void BayerRowBG(const uint8* src_bayer0, int src_stride_bayer,
- uint8* dst_argb, int pix) {
- const uint8* src_bayer1 = src_bayer0 + src_stride_bayer;
- uint8 g = src_bayer0[1];
- uint8 r = src_bayer1[1];
- int x;
- for (x = 0; x < pix - 2; x += 2) {
- dst_argb[0] = src_bayer0[0];
- dst_argb[1] = AVG(g, src_bayer0[1]);
- dst_argb[2] = AVG(r, src_bayer1[1]);
- dst_argb[3] = 255U;
- dst_argb[4] = AVG(src_bayer0[0], src_bayer0[2]);
- dst_argb[5] = src_bayer0[1];
- dst_argb[6] = src_bayer1[1];
- dst_argb[7] = 255U;
- g = src_bayer0[1];
- r = src_bayer1[1];
- src_bayer0 += 2;
- src_bayer1 += 2;
- dst_argb += 8;
- }
- dst_argb[0] = src_bayer0[0];
- dst_argb[1] = AVG(g, src_bayer0[1]);
- dst_argb[2] = AVG(r, src_bayer1[1]);
- dst_argb[3] = 255U;
- if (!(pix & 1)) {
- dst_argb[4] = src_bayer0[0];
- dst_argb[5] = src_bayer0[1];
- dst_argb[6] = src_bayer1[1];
- dst_argb[7] = 255U;
- }
-}
-
-static void BayerRowRG(const uint8* src_bayer0, int src_stride_bayer,
- uint8* dst_argb, int pix) {
- const uint8* src_bayer1 = src_bayer0 + src_stride_bayer;
- uint8 g = src_bayer0[1];
- uint8 b = src_bayer1[1];
- int x;
- for (x = 0; x < pix - 2; x += 2) {
- dst_argb[0] = AVG(b, src_bayer1[1]);
- dst_argb[1] = AVG(g, src_bayer0[1]);
- dst_argb[2] = src_bayer0[0];
- dst_argb[3] = 255U;
- dst_argb[4] = src_bayer1[1];
- dst_argb[5] = src_bayer0[1];
- dst_argb[6] = AVG(src_bayer0[0], src_bayer0[2]);
- dst_argb[7] = 255U;
- g = src_bayer0[1];
- b = src_bayer1[1];
- src_bayer0 += 2;
- src_bayer1 += 2;
- dst_argb += 8;
- }
- dst_argb[0] = AVG(b, src_bayer1[1]);
- dst_argb[1] = AVG(g, src_bayer0[1]);
- dst_argb[2] = src_bayer0[0];
- dst_argb[3] = 255U;
- if (!(pix & 1)) {
- dst_argb[4] = src_bayer1[1];
- dst_argb[5] = src_bayer0[1];
- dst_argb[6] = src_bayer0[0];
- dst_argb[7] = 255U;
- }
-}
-
-static void BayerRowGB(const uint8* src_bayer0, int src_stride_bayer,
- uint8* dst_argb, int pix) {
- const uint8* src_bayer1 = src_bayer0 + src_stride_bayer;
- uint8 b = src_bayer0[1];
- int x;
- for (x = 0; x < pix - 2; x += 2) {
- dst_argb[0] = AVG(b, src_bayer0[1]);
- dst_argb[1] = src_bayer0[0];
- dst_argb[2] = src_bayer1[0];
- dst_argb[3] = 255U;
- dst_argb[4] = src_bayer0[1];
- dst_argb[5] = AVG(src_bayer0[0], src_bayer0[2]);
- dst_argb[6] = AVG(src_bayer1[0], src_bayer1[2]);
- dst_argb[7] = 255U;
- b = src_bayer0[1];
- src_bayer0 += 2;
- src_bayer1 += 2;
- dst_argb += 8;
- }
- dst_argb[0] = AVG(b, src_bayer0[1]);
- dst_argb[1] = src_bayer0[0];
- dst_argb[2] = src_bayer1[0];
- dst_argb[3] = 255U;
- if (!(pix & 1)) {
- dst_argb[4] = src_bayer0[1];
- dst_argb[5] = src_bayer0[0];
- dst_argb[6] = src_bayer1[0];
- dst_argb[7] = 255U;
- }
-}
-
-static void BayerRowGR(const uint8* src_bayer0, int src_stride_bayer,
- uint8* dst_argb, int pix) {
- const uint8* src_bayer1 = src_bayer0 + src_stride_bayer;
- uint8 r = src_bayer0[1];
- int x;
- for (x = 0; x < pix - 2; x += 2) {
- dst_argb[0] = src_bayer1[0];
- dst_argb[1] = src_bayer0[0];
- dst_argb[2] = AVG(r, src_bayer0[1]);
- dst_argb[3] = 255U;
- dst_argb[4] = AVG(src_bayer1[0], src_bayer1[2]);
- dst_argb[5] = AVG(src_bayer0[0], src_bayer0[2]);
- dst_argb[6] = src_bayer0[1];
- dst_argb[7] = 255U;
- r = src_bayer0[1];
- src_bayer0 += 2;
- src_bayer1 += 2;
- dst_argb += 8;
- }
- dst_argb[0] = src_bayer1[0];
- dst_argb[1] = src_bayer0[0];
- dst_argb[2] = AVG(r, src_bayer0[1]);
- dst_argb[3] = 255U;
- if (!(pix & 1)) {
- dst_argb[4] = src_bayer1[0];
- dst_argb[5] = src_bayer0[0];
- dst_argb[6] = src_bayer0[1];
- dst_argb[7] = 255U;
- }
-}
-
-// Converts any Bayer RGB format to ARGB.
-LIBYUV_API
-int BayerToARGB(const uint8* src_bayer, int src_stride_bayer,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height,
- uint32 src_fourcc_bayer) {
- int y;
- void (*BayerRow0)(const uint8* src_bayer, int src_stride_bayer,
- uint8* dst_argb, int pix);
- void (*BayerRow1)(const uint8* src_bayer, int src_stride_bayer,
- uint8* dst_argb, int pix);
- if (height < 0) {
- height = -height;
- dst_argb = dst_argb + (height - 1) * dst_stride_argb;
- dst_stride_argb = -dst_stride_argb;
- }
- switch (src_fourcc_bayer) {
- case FOURCC_BGGR:
- BayerRow0 = BayerRowBG;
- BayerRow1 = BayerRowGR;
- break;
- case FOURCC_GBRG:
- BayerRow0 = BayerRowGB;
- BayerRow1 = BayerRowRG;
- break;
- case FOURCC_GRBG:
- BayerRow0 = BayerRowGR;
- BayerRow1 = BayerRowBG;
- break;
- case FOURCC_RGGB:
- BayerRow0 = BayerRowRG;
- BayerRow1 = BayerRowGB;
- break;
- default:
- return -1; // Bad FourCC
- }
-
- for (y = 0; y < height - 1; y += 2) {
- BayerRow0(src_bayer, src_stride_bayer, dst_argb, width);
- BayerRow1(src_bayer + src_stride_bayer, -src_stride_bayer,
- dst_argb + dst_stride_argb, width);
- src_bayer += src_stride_bayer * 2;
- dst_argb += dst_stride_argb * 2;
- }
- if (height & 1) {
- BayerRow0(src_bayer, src_stride_bayer, dst_argb, width);
- }
- return 0;
-}
-
-// Converts any Bayer RGB format to ARGB.
-LIBYUV_API
-int BayerToI420(const uint8* src_bayer, int src_stride_bayer,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height,
- uint32 src_fourcc_bayer) {
- void (*BayerRow0)(const uint8* src_bayer, int src_stride_bayer,
- uint8* dst_argb, int pix);
- void (*BayerRow1)(const uint8* src_bayer, int src_stride_bayer,
- uint8* dst_argb, int pix);
-
- void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
- void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
- ARGBToYRow_C;
- // Negative height means invert the image.
- if (height < 0) {
- int halfheight;
- height = -height;
- halfheight = (height + 1) >> 1;
- dst_y = dst_y + (height - 1) * dst_stride_y;
- dst_u = dst_u + (halfheight - 1) * dst_stride_u;
- dst_v = dst_v + (halfheight - 1) * dst_stride_v;
- dst_stride_y = -dst_stride_y;
- dst_stride_u = -dst_stride_u;
- dst_stride_v = -dst_stride_v;
- }
-#if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
- ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
- ARGBToYRow = ARGBToYRow_Any_SSSE3;
- if (IS_ALIGNED(width, 16)) {
- ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
- ARGBToUVRow = ARGBToUVRow_SSSE3;
- if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
- ARGBToYRow = ARGBToYRow_SSSE3;
- }
- }
- }
-#elif defined(HAS_ARGBTOYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGBToYRow = ARGBToYRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGBToYRow = ARGBToYRow_NEON;
- }
- if (width >= 16) {
- ARGBToUVRow = ARGBToUVRow_Any_NEON;
- if (IS_ALIGNED(width, 16)) {
- ARGBToUVRow = ARGBToUVRow_NEON;
- }
- }
- }
-#endif
-
- switch (src_fourcc_bayer) {
- case FOURCC_BGGR:
- BayerRow0 = BayerRowBG;
- BayerRow1 = BayerRowGR;
- break;
- case FOURCC_GBRG:
- BayerRow0 = BayerRowGB;
- BayerRow1 = BayerRowRG;
- break;
- case FOURCC_GRBG:
- BayerRow0 = BayerRowGR;
- BayerRow1 = BayerRowBG;
- break;
- case FOURCC_RGGB:
- BayerRow0 = BayerRowRG;
- BayerRow1 = BayerRowGB;
- break;
- default:
- return -1; // Bad FourCC
- }
-
- {
- // Allocate 2 rows of ARGB.
- const int kRowSize = (width * 4 + 15) & ~15;
- align_buffer_64(row, kRowSize * 2);
- int y;
- for (y = 0; y < height - 1; y += 2) {
- BayerRow0(src_bayer, src_stride_bayer, row, width);
- BayerRow1(src_bayer + src_stride_bayer, -src_stride_bayer,
- row + kRowSize, width);
- ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
- ARGBToYRow(row, dst_y, width);
- ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
- src_bayer += src_stride_bayer * 2;
- dst_y += dst_stride_y * 2;
- dst_u += dst_stride_u;
- dst_v += dst_stride_v;
- }
- if (height & 1) {
- BayerRow0(src_bayer, src_stride_bayer, row, width);
- ARGBToUVRow(row, 0, dst_u, dst_v, width);
- ARGBToYRow(row, dst_y, width);
- }
- free_aligned_buffer_64(row);
- }
- return 0;
-}
-
-// Convert I420 to Bayer.
-LIBYUV_API
-int I420ToBayer(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_bayer, int dst_stride_bayer,
- int width, int height,
- uint32 dst_fourcc_bayer) {
- void (*I422ToARGBRow)(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* rgb_buf,
- int width) = I422ToARGBRow_C;
- void (*ARGBToBayerRow)(const uint8* src_argb, uint8* dst_bayer,
- uint32 selector, int pix) = ARGBToBayerRow_C;
- const int blue_index = 0; // Offsets for ARGB format
- const int green_index = 1;
- const int red_index = 2;
- uint32 index_map[2];
- // Negative height means invert the image.
- if (height < 0) {
- int halfheight;
- height = -height;
- halfheight = (height + 1) >> 1;
- src_y = src_y + (height - 1) * src_stride_y;
- src_u = src_u + (halfheight - 1) * src_stride_u;
- src_v = src_v + (halfheight - 1) * src_stride_v;
- src_stride_y = -src_stride_y;
- src_stride_u = -src_stride_u;
- src_stride_v = -src_stride_v;
- }
-#if defined(HAS_I422TOARGBROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
- I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
- if (IS_ALIGNED(width, 8)) {
- I422ToARGBRow = I422ToARGBRow_SSSE3;
- }
- }
-#endif
-#if defined(HAS_I422TOARGBROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && width >= 16) {
- I422ToARGBRow = I422ToARGBRow_Any_AVX2;
- if (IS_ALIGNED(width, 16)) {
- I422ToARGBRow = I422ToARGBRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_I422TOARGBROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- I422ToARGBRow = I422ToARGBRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- I422ToARGBRow = I422ToARGBRow_NEON;
- }
- }
-#endif
-#if defined(HAS_I422TOARGBROW_MIPS_DSPR2)
- if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(width, 4) &&
- IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
- IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
- IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2)) {
- I422ToARGBRow = I422ToARGBRow_MIPS_DSPR2;
- }
-#endif
-
-#if defined(HAS_ARGBTOBAYERROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
- ARGBToBayerRow = ARGBToBayerRow_Any_SSSE3;
- if (IS_ALIGNED(width, 8)) {
- ARGBToBayerRow = ARGBToBayerRow_SSSE3;
- }
- }
-#elif defined(HAS_ARGBTOBAYERROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGBToBayerRow = ARGBToBayerRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGBToBayerRow = ARGBToBayerRow_NEON;
- }
- }
-#endif
-
- if (MakeSelectors(blue_index, green_index, red_index,
- dst_fourcc_bayer, index_map)) {
- return -1; // Bad FourCC
- }
- {
- // Allocate a row of ARGB.
- align_buffer_64(row, width * 4);
- int y;
- for (y = 0; y < height; ++y) {
- I422ToARGBRow(src_y, src_u, src_v, row, width);
- ARGBToBayerRow(row, dst_bayer, index_map[y & 1], width);
- dst_bayer += dst_stride_bayer;
- src_y += src_stride_y;
- if (y & 1) {
- src_u += src_stride_u;
- src_v += src_stride_v;
- }
- }
- free_aligned_buffer_64(row);
- }
- return 0;
-}
-
-#define MAKEBAYERFOURCC(BAYER) \
-LIBYUV_API \
-int Bayer##BAYER##ToI420(const uint8* src_bayer, int src_stride_bayer, \
- uint8* dst_y, int dst_stride_y, \
- uint8* dst_u, int dst_stride_u, \
- uint8* dst_v, int dst_stride_v, \
- int width, int height) { \
- return BayerToI420(src_bayer, src_stride_bayer, \
- dst_y, dst_stride_y, \
- dst_u, dst_stride_u, \
- dst_v, dst_stride_v, \
- width, height, \
- FOURCC_##BAYER); \
-} \
- \
-LIBYUV_API \
-int I420ToBayer##BAYER(const uint8* src_y, int src_stride_y, \
- const uint8* src_u, int src_stride_u, \
- const uint8* src_v, int src_stride_v, \
- uint8* dst_bayer, int dst_stride_bayer, \
- int width, int height) { \
- return I420ToBayer(src_y, src_stride_y, \
- src_u, src_stride_u, \
- src_v, src_stride_v, \
- dst_bayer, dst_stride_bayer, \
- width, height, \
- FOURCC_##BAYER); \
-} \
- \
-LIBYUV_API \
-int ARGBToBayer##BAYER(const uint8* src_argb, int src_stride_argb, \
- uint8* dst_bayer, int dst_stride_bayer, \
- int width, int height) { \
- return ARGBToBayer(src_argb, src_stride_argb, \
- dst_bayer, dst_stride_bayer, \
- width, height, \
- FOURCC_##BAYER); \
-} \
- \
-LIBYUV_API \
-int Bayer##BAYER##ToARGB(const uint8* src_bayer, int src_stride_bayer, \
- uint8* dst_argb, int dst_stride_argb, \
- int width, int height) { \
- return BayerToARGB(src_bayer, src_stride_bayer, \
- dst_argb, dst_stride_argb, \
- width, height, \
- FOURCC_##BAYER); \
-}
-
-MAKEBAYERFOURCC(BGGR)
-MAKEBAYERFOURCC(GBRG)
-MAKEBAYERFOURCC(GRBG)
-MAKEBAYERFOURCC(RGGB)
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/mjpeg_decoder.cc b/drivers/theoraplayer/src/YUV/libyuv/src/mjpeg_decoder.cc
deleted file mode 100755
index 193b829ba9..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/mjpeg_decoder.cc
+++ /dev/null
@@ -1,558 +0,0 @@
-/*
- * Copyright 2012 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/mjpeg_decoder.h"
-
-#ifdef HAVE_JPEG
-#include <assert.h>
-
-#if !defined(__pnacl__) && !defined(__CLR_VER) && !defined(COVERAGE_ENABLED) &&\
- !defined(TARGET_IPHONE_SIMULATOR)
-// Must be included before jpeglib.
-#include <setjmp.h>
-#define HAVE_SETJMP
-#endif
-struct FILE; // For jpeglib.h.
-
-// C++ build requires extern C for jpeg internals.
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <jpeglib.h>
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
-#include "libyuv/planar_functions.h" // For CopyPlane().
-
-namespace libyuv {
-
-#ifdef HAVE_SETJMP
-struct SetJmpErrorMgr {
- jpeg_error_mgr base; // Must be at the top
- jmp_buf setjmp_buffer;
-};
-#endif
-
-const int MJpegDecoder::kColorSpaceUnknown = JCS_UNKNOWN;
-const int MJpegDecoder::kColorSpaceGrayscale = JCS_GRAYSCALE;
-const int MJpegDecoder::kColorSpaceRgb = JCS_RGB;
-const int MJpegDecoder::kColorSpaceYCbCr = JCS_YCbCr;
-const int MJpegDecoder::kColorSpaceCMYK = JCS_CMYK;
-const int MJpegDecoder::kColorSpaceYCCK = JCS_YCCK;
-
-MJpegDecoder::MJpegDecoder()
- : has_scanline_padding_(LIBYUV_FALSE),
- num_outbufs_(0),
- scanlines_(NULL),
- scanlines_sizes_(NULL),
- databuf_(NULL),
- databuf_strides_(NULL) {
- decompress_struct_ = new jpeg_decompress_struct;
- source_mgr_ = new jpeg_source_mgr;
-#ifdef HAVE_SETJMP
- error_mgr_ = new SetJmpErrorMgr;
- decompress_struct_->err = jpeg_std_error(&error_mgr_->base);
- // Override standard exit()-based error handler.
- error_mgr_->base.error_exit = &ErrorHandler;
-#endif
- decompress_struct_->client_data = NULL;
- source_mgr_->init_source = &init_source;
- source_mgr_->fill_input_buffer = &fill_input_buffer;
- source_mgr_->skip_input_data = &skip_input_data;
- source_mgr_->resync_to_restart = &jpeg_resync_to_restart;
- source_mgr_->term_source = &term_source;
- jpeg_create_decompress(decompress_struct_);
- decompress_struct_->src = source_mgr_;
- buf_vec_.buffers = &buf_;
- buf_vec_.len = 1;
-}
-
-MJpegDecoder::~MJpegDecoder() {
- jpeg_destroy_decompress(decompress_struct_);
- delete decompress_struct_;
- delete source_mgr_;
-#ifdef HAVE_SETJMP
- delete error_mgr_;
-#endif
- DestroyOutputBuffers();
-}
-
-LIBYUV_BOOL MJpegDecoder::LoadFrame(const uint8* src, size_t src_len) {
- if (!ValidateJpeg(src, src_len)) {
- return LIBYUV_FALSE;
- }
-
- buf_.data = src;
- buf_.len = (int)(src_len);
- buf_vec_.pos = 0;
- decompress_struct_->client_data = &buf_vec_;
-#ifdef HAVE_SETJMP
- if (setjmp(error_mgr_->setjmp_buffer)) {
- // We called jpeg_read_header, it experienced an error, and we called
- // longjmp() and rewound the stack to here. Return error.
- return LIBYUV_FALSE;
- }
-#endif
- if (jpeg_read_header(decompress_struct_, TRUE) != JPEG_HEADER_OK) {
- // ERROR: Bad MJPEG header
- return LIBYUV_FALSE;
- }
- AllocOutputBuffers(GetNumComponents());
- for (int i = 0; i < num_outbufs_; ++i) {
- int scanlines_size = GetComponentScanlinesPerImcuRow(i);
- if (scanlines_sizes_[i] != scanlines_size) {
- if (scanlines_[i]) {
- delete scanlines_[i];
- }
- scanlines_[i] = new uint8* [scanlines_size];
- scanlines_sizes_[i] = scanlines_size;
- }
-
- // We allocate padding for the final scanline to pad it up to DCTSIZE bytes
- // to avoid memory errors, since jpeglib only reads full MCUs blocks. For
- // the preceding scanlines, the padding is not needed/wanted because the
- // following addresses will already be valid (they are the initial bytes of
- // the next scanline) and will be overwritten when jpeglib writes out that
- // next scanline.
- int databuf_stride = GetComponentStride(i);
- int databuf_size = scanlines_size * databuf_stride;
- if (databuf_strides_[i] != databuf_stride) {
- if (databuf_[i]) {
- delete databuf_[i];
- }
- databuf_[i] = new uint8[databuf_size];
- databuf_strides_[i] = databuf_stride;
- }
-
- if (GetComponentStride(i) != GetComponentWidth(i)) {
- has_scanline_padding_ = LIBYUV_TRUE;
- }
- }
- return LIBYUV_TRUE;
-}
-
-static int DivideAndRoundUp(int numerator, int denominator) {
- return (numerator + denominator - 1) / denominator;
-}
-
-static int DivideAndRoundDown(int numerator, int denominator) {
- return numerator / denominator;
-}
-
-// Returns width of the last loaded frame.
-int MJpegDecoder::GetWidth() {
- return decompress_struct_->image_width;
-}
-
-// Returns height of the last loaded frame.
-int MJpegDecoder::GetHeight() {
- return decompress_struct_->image_height;
-}
-
-// Returns format of the last loaded frame. The return value is one of the
-// kColorSpace* constants.
-int MJpegDecoder::GetColorSpace() {
- return decompress_struct_->jpeg_color_space;
-}
-
-// Number of color components in the color space.
-int MJpegDecoder::GetNumComponents() {
- return decompress_struct_->num_components;
-}
-
-// Sample factors of the n-th component.
-int MJpegDecoder::GetHorizSampFactor(int component) {
- return decompress_struct_->comp_info[component].h_samp_factor;
-}
-
-int MJpegDecoder::GetVertSampFactor(int component) {
- return decompress_struct_->comp_info[component].v_samp_factor;
-}
-
-int MJpegDecoder::GetHorizSubSampFactor(int component) {
- return decompress_struct_->max_h_samp_factor /
- GetHorizSampFactor(component);
-}
-
-int MJpegDecoder::GetVertSubSampFactor(int component) {
- return decompress_struct_->max_v_samp_factor /
- GetVertSampFactor(component);
-}
-
-int MJpegDecoder::GetImageScanlinesPerImcuRow() {
- return decompress_struct_->max_v_samp_factor * DCTSIZE;
-}
-
-int MJpegDecoder::GetComponentScanlinesPerImcuRow(int component) {
- int vs = GetVertSubSampFactor(component);
- return DivideAndRoundUp(GetImageScanlinesPerImcuRow(), vs);
-}
-
-int MJpegDecoder::GetComponentWidth(int component) {
- int hs = GetHorizSubSampFactor(component);
- return DivideAndRoundUp(GetWidth(), hs);
-}
-
-int MJpegDecoder::GetComponentHeight(int component) {
- int vs = GetVertSubSampFactor(component);
- return DivideAndRoundUp(GetHeight(), vs);
-}
-
-// Get width in bytes padded out to a multiple of DCTSIZE
-int MJpegDecoder::GetComponentStride(int component) {
- return (GetComponentWidth(component) + DCTSIZE - 1) & ~(DCTSIZE - 1);
-}
-
-int MJpegDecoder::GetComponentSize(int component) {
- return GetComponentWidth(component) * GetComponentHeight(component);
-}
-
-LIBYUV_BOOL MJpegDecoder::UnloadFrame() {
-#ifdef HAVE_SETJMP
- if (setjmp(error_mgr_->setjmp_buffer)) {
- // We called jpeg_abort_decompress, it experienced an error, and we called
- // longjmp() and rewound the stack to here. Return error.
- return LIBYUV_FALSE;
- }
-#endif
- jpeg_abort_decompress(decompress_struct_);
- return LIBYUV_TRUE;
-}
-
-// TODO(fbarchard): Allow rectangle to be specified: x, y, width, height.
-LIBYUV_BOOL MJpegDecoder::DecodeToBuffers(
- uint8** planes, int dst_width, int dst_height) {
- if (dst_width != GetWidth() ||
- dst_height > GetHeight()) {
- // ERROR: Bad dimensions
- return LIBYUV_FALSE;
- }
-#ifdef HAVE_SETJMP
- if (setjmp(error_mgr_->setjmp_buffer)) {
- // We called into jpeglib, it experienced an error sometime during this
- // function call, and we called longjmp() and rewound the stack to here.
- // Return error.
- return LIBYUV_FALSE;
- }
-#endif
- if (!StartDecode()) {
- return LIBYUV_FALSE;
- }
- SetScanlinePointers(databuf_);
- int lines_left = dst_height;
- // Compute amount of lines to skip to implement vertical crop.
- // TODO(fbarchard): Ensure skip is a multiple of maximum component
- // subsample. ie 2
- int skip = (GetHeight() - dst_height) / 2;
- if (skip > 0) {
- // There is no API to skip lines in the output data, so we read them
- // into the temp buffer.
- while (skip >= GetImageScanlinesPerImcuRow()) {
- if (!DecodeImcuRow()) {
- FinishDecode();
- return LIBYUV_FALSE;
- }
- skip -= GetImageScanlinesPerImcuRow();
- }
- if (skip > 0) {
- // Have a partial iMCU row left over to skip. Must read it and then
- // copy the parts we want into the destination.
- if (!DecodeImcuRow()) {
- FinishDecode();
- return LIBYUV_FALSE;
- }
- for (int i = 0; i < num_outbufs_; ++i) {
- // TODO(fbarchard): Compute skip to avoid this
- assert(skip % GetVertSubSampFactor(i) == 0);
- int rows_to_skip =
- DivideAndRoundDown(skip, GetVertSubSampFactor(i));
- int scanlines_to_copy = GetComponentScanlinesPerImcuRow(i) -
- rows_to_skip;
- int data_to_skip = rows_to_skip * GetComponentStride(i);
- CopyPlane(databuf_[i] + data_to_skip, GetComponentStride(i),
- planes[i], GetComponentWidth(i),
- GetComponentWidth(i), scanlines_to_copy);
- planes[i] += scanlines_to_copy * GetComponentWidth(i);
- }
- lines_left -= (GetImageScanlinesPerImcuRow() - skip);
- }
- }
-
- // Read full MCUs but cropped horizontally
- for (; lines_left > GetImageScanlinesPerImcuRow();
- lines_left -= GetImageScanlinesPerImcuRow()) {
- if (!DecodeImcuRow()) {
- FinishDecode();
- return LIBYUV_FALSE;
- }
- for (int i = 0; i < num_outbufs_; ++i) {
- int scanlines_to_copy = GetComponentScanlinesPerImcuRow(i);
- CopyPlane(databuf_[i], GetComponentStride(i),
- planes[i], GetComponentWidth(i),
- GetComponentWidth(i), scanlines_to_copy);
- planes[i] += scanlines_to_copy * GetComponentWidth(i);
- }
- }
-
- if (lines_left > 0) {
- // Have a partial iMCU row left over to decode.
- if (!DecodeImcuRow()) {
- FinishDecode();
- return LIBYUV_FALSE;
- }
- for (int i = 0; i < num_outbufs_; ++i) {
- int scanlines_to_copy =
- DivideAndRoundUp(lines_left, GetVertSubSampFactor(i));
- CopyPlane(databuf_[i], GetComponentStride(i),
- planes[i], GetComponentWidth(i),
- GetComponentWidth(i), scanlines_to_copy);
- planes[i] += scanlines_to_copy * GetComponentWidth(i);
- }
- }
- return FinishDecode();
-}
-
-LIBYUV_BOOL MJpegDecoder::DecodeToCallback(CallbackFunction fn, void* opaque,
- int dst_width, int dst_height) {
- if (dst_width != GetWidth() ||
- dst_height > GetHeight()) {
- // ERROR: Bad dimensions
- return LIBYUV_FALSE;
- }
-#ifdef HAVE_SETJMP
- if (setjmp(error_mgr_->setjmp_buffer)) {
- // We called into jpeglib, it experienced an error sometime during this
- // function call, and we called longjmp() and rewound the stack to here.
- // Return error.
- return LIBYUV_FALSE;
- }
-#endif
- if (!StartDecode()) {
- return LIBYUV_FALSE;
- }
- SetScanlinePointers(databuf_);
- int lines_left = dst_height;
- // TODO(fbarchard): Compute amount of lines to skip to implement vertical crop
- int skip = (GetHeight() - dst_height) / 2;
- if (skip > 0) {
- while (skip >= GetImageScanlinesPerImcuRow()) {
- if (!DecodeImcuRow()) {
- FinishDecode();
- return LIBYUV_FALSE;
- }
- skip -= GetImageScanlinesPerImcuRow();
- }
- if (skip > 0) {
- // Have a partial iMCU row left over to skip.
- if (!DecodeImcuRow()) {
- FinishDecode();
- return LIBYUV_FALSE;
- }
- for (int i = 0; i < num_outbufs_; ++i) {
- // TODO(fbarchard): Compute skip to avoid this
- assert(skip % GetVertSubSampFactor(i) == 0);
- int rows_to_skip = DivideAndRoundDown(skip, GetVertSubSampFactor(i));
- int data_to_skip = rows_to_skip * GetComponentStride(i);
- // Change our own data buffer pointers so we can pass them to the
- // callback.
- databuf_[i] += data_to_skip;
- }
- int scanlines_to_copy = GetImageScanlinesPerImcuRow() - skip;
- (*fn)(opaque, databuf_, databuf_strides_, scanlines_to_copy);
- // Now change them back.
- for (int i = 0; i < num_outbufs_; ++i) {
- int rows_to_skip = DivideAndRoundDown(skip, GetVertSubSampFactor(i));
- int data_to_skip = rows_to_skip * GetComponentStride(i);
- databuf_[i] -= data_to_skip;
- }
- lines_left -= scanlines_to_copy;
- }
- }
- // Read full MCUs until we get to the crop point.
- for (; lines_left >= GetImageScanlinesPerImcuRow();
- lines_left -= GetImageScanlinesPerImcuRow()) {
- if (!DecodeImcuRow()) {
- FinishDecode();
- return LIBYUV_FALSE;
- }
- (*fn)(opaque, databuf_, databuf_strides_, GetImageScanlinesPerImcuRow());
- }
- if (lines_left > 0) {
- // Have a partial iMCU row left over to decode.
- if (!DecodeImcuRow()) {
- FinishDecode();
- return LIBYUV_FALSE;
- }
- (*fn)(opaque, databuf_, databuf_strides_, lines_left);
- }
- return FinishDecode();
-}
-
-void MJpegDecoder::init_source(j_decompress_ptr cinfo) {
- fill_input_buffer(cinfo);
-}
-
-boolean MJpegDecoder::fill_input_buffer(j_decompress_ptr cinfo) {
- BufferVector* buf_vec = (BufferVector*)(cinfo->client_data);
- if (buf_vec->pos >= buf_vec->len) {
- assert(0 && "No more data");
- // ERROR: No more data
- return FALSE;
- }
- cinfo->src->next_input_byte = buf_vec->buffers[buf_vec->pos].data;
- cinfo->src->bytes_in_buffer = buf_vec->buffers[buf_vec->pos].len;
- ++buf_vec->pos;
- return TRUE;
-}
-
-void MJpegDecoder::skip_input_data(j_decompress_ptr cinfo,
- long num_bytes) { // NOLINT
- cinfo->src->next_input_byte += num_bytes;
-}
-
-void MJpegDecoder::term_source(j_decompress_ptr cinfo) {
- // Nothing to do.
-}
-
-#ifdef HAVE_SETJMP
-void MJpegDecoder::ErrorHandler(j_common_ptr cinfo) {
- // This is called when a jpeglib command experiences an error. Unfortunately
- // jpeglib's error handling model is not very flexible, because it expects the
- // error handler to not return--i.e., it wants the program to terminate. To
- // recover from errors we use setjmp() as shown in their example. setjmp() is
- // C's implementation for the "call with current continuation" functionality
- // seen in some functional programming languages.
- // A formatted message can be output, but is unsafe for release.
-#ifdef DEBUG
- char buf[JMSG_LENGTH_MAX];
- (*cinfo->err->format_message)(cinfo, buf);
- // ERROR: Error in jpeglib: buf
-#endif
-
- SetJmpErrorMgr* mgr = (SetJmpErrorMgr*)(cinfo->err);
- // This rewinds the call stack to the point of the corresponding setjmp()
- // and causes it to return (for a second time) with value 1.
- longjmp(mgr->setjmp_buffer, 1);
-}
-#endif
-
-void MJpegDecoder::AllocOutputBuffers(int num_outbufs) {
- if (num_outbufs != num_outbufs_) {
- // We could perhaps optimize this case to resize the output buffers without
- // necessarily having to delete and recreate each one, but it's not worth
- // it.
- DestroyOutputBuffers();
-
- scanlines_ = new uint8** [num_outbufs];
- scanlines_sizes_ = new int[num_outbufs];
- databuf_ = new uint8* [num_outbufs];
- databuf_strides_ = new int[num_outbufs];
-
- for (int i = 0; i < num_outbufs; ++i) {
- scanlines_[i] = NULL;
- scanlines_sizes_[i] = 0;
- databuf_[i] = NULL;
- databuf_strides_[i] = 0;
- }
-
- num_outbufs_ = num_outbufs;
- }
-}
-
-void MJpegDecoder::DestroyOutputBuffers() {
- for (int i = 0; i < num_outbufs_; ++i) {
- delete [] scanlines_[i];
- delete [] databuf_[i];
- }
- delete [] scanlines_;
- delete [] databuf_;
- delete [] scanlines_sizes_;
- delete [] databuf_strides_;
- scanlines_ = NULL;
- databuf_ = NULL;
- scanlines_sizes_ = NULL;
- databuf_strides_ = NULL;
- num_outbufs_ = 0;
-}
-
-// JDCT_IFAST and do_block_smoothing improve performance substantially.
-LIBYUV_BOOL MJpegDecoder::StartDecode() {
- decompress_struct_->raw_data_out = TRUE;
- decompress_struct_->dct_method = JDCT_IFAST; // JDCT_ISLOW is default
- decompress_struct_->dither_mode = JDITHER_NONE;
- // Not applicable to 'raw':
- decompress_struct_->do_fancy_upsampling = LIBYUV_FALSE;
- // Only for buffered mode:
- decompress_struct_->enable_2pass_quant = LIBYUV_FALSE;
- // Blocky but fast:
- decompress_struct_->do_block_smoothing = LIBYUV_FALSE;
-
- if (!jpeg_start_decompress(decompress_struct_)) {
- // ERROR: Couldn't start JPEG decompressor";
- return LIBYUV_FALSE;
- }
- return LIBYUV_TRUE;
-}
-
-LIBYUV_BOOL MJpegDecoder::FinishDecode() {
- // jpeglib considers it an error if we finish without decoding the whole
- // image, so we call "abort" rather than "finish".
- jpeg_abort_decompress(decompress_struct_);
- return LIBYUV_TRUE;
-}
-
-void MJpegDecoder::SetScanlinePointers(uint8** data) {
- for (int i = 0; i < num_outbufs_; ++i) {
- uint8* data_i = data[i];
- for (int j = 0; j < scanlines_sizes_[i]; ++j) {
- scanlines_[i][j] = data_i;
- data_i += GetComponentStride(i);
- }
- }
-}
-
-inline LIBYUV_BOOL MJpegDecoder::DecodeImcuRow() {
- return (unsigned int)(GetImageScanlinesPerImcuRow()) ==
- jpeg_read_raw_data(decompress_struct_,
- scanlines_,
- GetImageScanlinesPerImcuRow());
-}
-
-// The helper function which recognizes the jpeg sub-sampling type.
-JpegSubsamplingType MJpegDecoder::JpegSubsamplingTypeHelper(
- int* subsample_x, int* subsample_y, int number_of_components) {
- if (number_of_components == 3) { // Color images.
- if (subsample_x[0] == 1 && subsample_y[0] == 1 &&
- subsample_x[1] == 2 && subsample_y[1] == 2 &&
- subsample_x[2] == 2 && subsample_y[2] == 2) {
- return kJpegYuv420;
- } else if (subsample_x[0] == 1 && subsample_y[0] == 1 &&
- subsample_x[1] == 2 && subsample_y[1] == 1 &&
- subsample_x[2] == 2 && subsample_y[2] == 1) {
- return kJpegYuv422;
- } else if (subsample_x[0] == 1 && subsample_y[0] == 1 &&
- subsample_x[1] == 1 && subsample_y[1] == 1 &&
- subsample_x[2] == 1 && subsample_y[2] == 1) {
- return kJpegYuv444;
- }
- } else if (number_of_components == 1) { // Grey-scale images.
- if (subsample_x[0] == 1 && subsample_y[0] == 1) {
- return kJpegYuv400;
- }
- }
- return kJpegUnknown;
-}
-
-} // namespace libyuv
-#endif // HAVE_JPEG
-
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/mjpeg_validate.cc b/drivers/theoraplayer/src/YUV/libyuv/src/mjpeg_validate.cc
deleted file mode 100755
index 23d22d099b..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/mjpeg_validate.cc
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2012 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/mjpeg_decoder.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// Helper function to validate the jpeg appears intact.
-// TODO(fbarchard): Optimize case where SOI is found but EOI is not.
-LIBYUV_BOOL ValidateJpeg(const uint8* sample, size_t sample_size) {
- size_t i;
- if (sample_size < 64) {
- // ERROR: Invalid jpeg size: sample_size
- return LIBYUV_FALSE;
- }
- if (sample[0] != 0xff || sample[1] != 0xd8) { // Start Of Image
- // ERROR: Invalid jpeg initial start code
- return LIBYUV_FALSE;
- }
- for (i = sample_size - 2; i > 1;) {
- if (sample[i] != 0xd9) {
- if (sample[i] == 0xff && sample[i + 1] == 0xd9) { // End Of Image
- return LIBYUV_TRUE; // Success: Valid jpeg.
- }
- --i;
- }
- --i;
- }
- // ERROR: Invalid jpeg end code not found. Size sample_size
- return LIBYUV_FALSE;
-}
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
-
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/planar_functions.cc b/drivers/theoraplayer/src/YUV/libyuv/src/planar_functions.cc
deleted file mode 100755
index f0a8989051..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/planar_functions.cc
+++ /dev/null
@@ -1,2238 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/planar_functions.h"
-
-#include <string.h> // for memset()
-
-#include "libyuv/cpu_id.h"
-#ifdef HAVE_JPEG
-#include "libyuv/mjpeg_decoder.h"
-#endif
-#include "libyuv/row.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// Copy a plane of data
-LIBYUV_API
-void CopyPlane(const uint8* src_y, int src_stride_y,
- uint8* dst_y, int dst_stride_y,
- int width, int height) {
- int y;
- void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
- // Coalesce rows.
- if (src_stride_y == width &&
- dst_stride_y == width) {
- width *= height;
- height = 1;
- src_stride_y = dst_stride_y = 0;
- }
-#if defined(HAS_COPYROW_X86)
- if (TestCpuFlag(kCpuHasX86) && IS_ALIGNED(width, 4)) {
- CopyRow = CopyRow_X86;
- }
-#endif
-#if defined(HAS_COPYROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 32) &&
- IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) &&
- IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
- CopyRow = CopyRow_SSE2;
- }
-#endif
-#if defined(HAS_COPYROW_ERMS)
- if (TestCpuFlag(kCpuHasERMS)) {
- CopyRow = CopyRow_ERMS;
- }
-#endif
-#if defined(HAS_COPYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 32)) {
- CopyRow = CopyRow_NEON;
- }
-#endif
-#if defined(HAS_COPYROW_MIPS)
- if (TestCpuFlag(kCpuHasMIPS)) {
- CopyRow = CopyRow_MIPS;
- }
-#endif
-
- // Copy plane
- for (y = 0; y < height; ++y) {
- CopyRow(src_y, dst_y, width);
- src_y += src_stride_y;
- dst_y += dst_stride_y;
- }
-}
-
-// Copy I422.
-LIBYUV_API
-int I422Copy(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- int halfwidth = (width + 1) >> 1;
- if (!src_y || !src_u || !src_v ||
- !dst_y || !dst_u || !dst_v ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_y = src_y + (height - 1) * src_stride_y;
- src_u = src_u + (height - 1) * src_stride_u;
- src_v = src_v + (height - 1) * src_stride_v;
- src_stride_y = -src_stride_y;
- src_stride_u = -src_stride_u;
- src_stride_v = -src_stride_v;
- }
- CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
- CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, height);
- CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, height);
- return 0;
-}
-
-// Copy I444.
-LIBYUV_API
-int I444Copy(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- if (!src_y || !src_u || !src_v ||
- !dst_y || !dst_u || !dst_v ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_y = src_y + (height - 1) * src_stride_y;
- src_u = src_u + (height - 1) * src_stride_u;
- src_v = src_v + (height - 1) * src_stride_v;
- src_stride_y = -src_stride_y;
- src_stride_u = -src_stride_u;
- src_stride_v = -src_stride_v;
- }
-
- CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
- CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, width, height);
- CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, width, height);
- return 0;
-}
-
-// Copy I400.
-LIBYUV_API
-int I400ToI400(const uint8* src_y, int src_stride_y,
- uint8* dst_y, int dst_stride_y,
- int width, int height) {
- if (!src_y || !dst_y || width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_y = src_y + (height - 1) * src_stride_y;
- src_stride_y = -src_stride_y;
- }
- CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
- return 0;
-}
-
-// Convert I420 to I400.
-LIBYUV_API
-int I420ToI400(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- int width, int height) {
- if (!src_y || !dst_y || width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_y = src_y + (height - 1) * src_stride_y;
- src_stride_y = -src_stride_y;
- }
- CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
- return 0;
-}
-
-// Mirror a plane of data.
-void MirrorPlane(const uint8* src_y, int src_stride_y,
- uint8* dst_y, int dst_stride_y,
- int width, int height) {
- int y;
- void (*MirrorRow)(const uint8* src, uint8* dst, int width) = MirrorRow_C;
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_y = src_y + (height - 1) * src_stride_y;
- src_stride_y = -src_stride_y;
- }
-#if defined(HAS_MIRRORROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 16)) {
- MirrorRow = MirrorRow_NEON;
- }
-#endif
-#if defined(HAS_MIRRORROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 16)) {
- MirrorRow = MirrorRow_SSE2;
- }
-#endif
-#if defined(HAS_MIRRORROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 16) &&
- IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) &&
- IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
- MirrorRow = MirrorRow_SSSE3;
- }
-#endif
-#if defined(HAS_MIRRORROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && IS_ALIGNED(width, 32)) {
- MirrorRow = MirrorRow_AVX2;
- }
-#endif
-
- // Mirror plane
- for (y = 0; y < height; ++y) {
- MirrorRow(src_y, dst_y, width);
- src_y += src_stride_y;
- dst_y += dst_stride_y;
- }
-}
-
-// Convert YUY2 to I422.
-LIBYUV_API
-int YUY2ToI422(const uint8* src_yuy2, int src_stride_yuy2,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- int y;
- void (*YUY2ToUV422Row)(const uint8* src_yuy2,
- uint8* dst_u, uint8* dst_v, int pix) =
- YUY2ToUV422Row_C;
- void (*YUY2ToYRow)(const uint8* src_yuy2, uint8* dst_y, int pix) =
- YUY2ToYRow_C;
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
- src_stride_yuy2 = -src_stride_yuy2;
- }
- // Coalesce rows.
- if (src_stride_yuy2 == width * 2 &&
- dst_stride_y == width &&
- dst_stride_u * 2 == width &&
- dst_stride_v * 2 == width) {
- width *= height;
- height = 1;
- src_stride_yuy2 = dst_stride_y = dst_stride_u = dst_stride_v = 0;
- }
-#if defined(HAS_YUY2TOYROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
- YUY2ToUV422Row = YUY2ToUV422Row_Any_SSE2;
- YUY2ToYRow = YUY2ToYRow_Any_SSE2;
- if (IS_ALIGNED(width, 16)) {
- YUY2ToUV422Row = YUY2ToUV422Row_Unaligned_SSE2;
- YUY2ToYRow = YUY2ToYRow_Unaligned_SSE2;
- if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16)) {
- YUY2ToUV422Row = YUY2ToUV422Row_SSE2;
- if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
- YUY2ToYRow = YUY2ToYRow_SSE2;
- }
- }
- }
- }
-#endif
-#if defined(HAS_YUY2TOYROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
- YUY2ToUV422Row = YUY2ToUV422Row_Any_AVX2;
- YUY2ToYRow = YUY2ToYRow_Any_AVX2;
- if (IS_ALIGNED(width, 32)) {
- YUY2ToUV422Row = YUY2ToUV422Row_AVX2;
- YUY2ToYRow = YUY2ToYRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_YUY2TOYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- YUY2ToYRow = YUY2ToYRow_Any_NEON;
- if (width >= 16) {
- YUY2ToUV422Row = YUY2ToUV422Row_Any_NEON;
- }
- if (IS_ALIGNED(width, 16)) {
- YUY2ToYRow = YUY2ToYRow_NEON;
- YUY2ToUV422Row = YUY2ToUV422Row_NEON;
- }
- }
-#endif
-
- for (y = 0; y < height; ++y) {
- YUY2ToUV422Row(src_yuy2, dst_u, dst_v, width);
- YUY2ToYRow(src_yuy2, dst_y, width);
- src_yuy2 += src_stride_yuy2;
- dst_y += dst_stride_y;
- dst_u += dst_stride_u;
- dst_v += dst_stride_v;
- }
- return 0;
-}
-
-// Convert UYVY to I422.
-LIBYUV_API
-int UYVYToI422(const uint8* src_uyvy, int src_stride_uyvy,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- int y;
- void (*UYVYToUV422Row)(const uint8* src_uyvy,
- uint8* dst_u, uint8* dst_v, int pix) =
- UYVYToUV422Row_C;
- void (*UYVYToYRow)(const uint8* src_uyvy,
- uint8* dst_y, int pix) = UYVYToYRow_C;
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
- src_stride_uyvy = -src_stride_uyvy;
- }
- // Coalesce rows.
- if (src_stride_uyvy == width * 2 &&
- dst_stride_y == width &&
- dst_stride_u * 2 == width &&
- dst_stride_v * 2 == width) {
- width *= height;
- height = 1;
- src_stride_uyvy = dst_stride_y = dst_stride_u = dst_stride_v = 0;
- }
-#if defined(HAS_UYVYTOYROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
- UYVYToUV422Row = UYVYToUV422Row_Any_SSE2;
- UYVYToYRow = UYVYToYRow_Any_SSE2;
- if (IS_ALIGNED(width, 16)) {
- UYVYToUV422Row = UYVYToUV422Row_Unaligned_SSE2;
- UYVYToYRow = UYVYToYRow_Unaligned_SSE2;
- if (IS_ALIGNED(src_uyvy, 16) && IS_ALIGNED(src_stride_uyvy, 16)) {
- UYVYToUV422Row = UYVYToUV422Row_SSE2;
- if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
- UYVYToYRow = UYVYToYRow_SSE2;
- }
- }
- }
- }
-#endif
-#if defined(HAS_UYVYTOYROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
- UYVYToUV422Row = UYVYToUV422Row_Any_AVX2;
- UYVYToYRow = UYVYToYRow_Any_AVX2;
- if (IS_ALIGNED(width, 32)) {
- UYVYToUV422Row = UYVYToUV422Row_AVX2;
- UYVYToYRow = UYVYToYRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_UYVYTOYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- UYVYToYRow = UYVYToYRow_Any_NEON;
- if (width >= 16) {
- UYVYToUV422Row = UYVYToUV422Row_Any_NEON;
- }
- if (IS_ALIGNED(width, 16)) {
- UYVYToYRow = UYVYToYRow_NEON;
- UYVYToUV422Row = UYVYToUV422Row_NEON;
- }
- }
-#endif
-
- for (y = 0; y < height; ++y) {
- UYVYToUV422Row(src_uyvy, dst_u, dst_v, width);
- UYVYToYRow(src_uyvy, dst_y, width);
- src_uyvy += src_stride_uyvy;
- dst_y += dst_stride_y;
- dst_u += dst_stride_u;
- dst_v += dst_stride_v;
- }
- return 0;
-}
-
-// Mirror I400 with optional flipping
-LIBYUV_API
-int I400Mirror(const uint8* src_y, int src_stride_y,
- uint8* dst_y, int dst_stride_y,
- int width, int height) {
- if (!src_y || !dst_y ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_y = src_y + (height - 1) * src_stride_y;
- src_stride_y = -src_stride_y;
- }
-
- MirrorPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
- return 0;
-}
-
-// Mirror I420 with optional flipping
-LIBYUV_API
-int I420Mirror(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height) {
- int halfwidth = (width + 1) >> 1;
- int halfheight = (height + 1) >> 1;
- if (!src_y || !src_u || !src_v || !dst_y || !dst_u || !dst_v ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- halfheight = (height + 1) >> 1;
- src_y = src_y + (height - 1) * src_stride_y;
- src_u = src_u + (halfheight - 1) * src_stride_u;
- src_v = src_v + (halfheight - 1) * src_stride_v;
- src_stride_y = -src_stride_y;
- src_stride_u = -src_stride_u;
- src_stride_v = -src_stride_v;
- }
-
- if (dst_y) {
- MirrorPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
- }
- MirrorPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
- MirrorPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
- return 0;
-}
-
-// ARGB mirror.
-LIBYUV_API
-int ARGBMirror(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- int y;
- void (*ARGBMirrorRow)(const uint8* src, uint8* dst, int width) =
- ARGBMirrorRow_C;
- if (!src_argb || !dst_argb || width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
-
-#if defined(HAS_ARGBMIRRORROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 4) &&
- IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16) &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- ARGBMirrorRow = ARGBMirrorRow_SSSE3;
- }
-#endif
-#if defined(HAS_ARGBMIRRORROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && IS_ALIGNED(width, 8)) {
- ARGBMirrorRow = ARGBMirrorRow_AVX2;
- }
-#endif
-#if defined(HAS_ARGBMIRRORROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 4)) {
- ARGBMirrorRow = ARGBMirrorRow_NEON;
- }
-#endif
-
- // Mirror plane
- for (y = 0; y < height; ++y) {
- ARGBMirrorRow(src_argb, dst_argb, width);
- src_argb += src_stride_argb;
- dst_argb += dst_stride_argb;
- }
- return 0;
-}
-
-// Get a blender that optimized for the CPU, alignment and pixel count.
-// As there are 6 blenders to choose from, the caller should try to use
-// the same blend function for all pixels if possible.
-LIBYUV_API
-ARGBBlendRow GetARGBBlend() {
- void (*ARGBBlendRow)(const uint8* src_argb, const uint8* src_argb1,
- uint8* dst_argb, int width) = ARGBBlendRow_C;
-#if defined(HAS_ARGBBLENDROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3)) {
- ARGBBlendRow = ARGBBlendRow_SSSE3;
- return ARGBBlendRow;
- }
-#endif
-#if defined(HAS_ARGBBLENDROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2)) {
- ARGBBlendRow = ARGBBlendRow_SSE2;
- }
-#endif
-#if defined(HAS_ARGBBLENDROW_NEON)
- if (TestCpuFlag(kCpuHasNEON)) {
- ARGBBlendRow = ARGBBlendRow_NEON;
- }
-#endif
- return ARGBBlendRow;
-}
-
-// Alpha Blend 2 ARGB images and store to destination.
-LIBYUV_API
-int ARGBBlend(const uint8* src_argb0, int src_stride_argb0,
- const uint8* src_argb1, int src_stride_argb1,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- int y;
- void (*ARGBBlendRow)(const uint8* src_argb, const uint8* src_argb1,
- uint8* dst_argb, int width) = GetARGBBlend();
- if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_argb = dst_argb + (height - 1) * dst_stride_argb;
- dst_stride_argb = -dst_stride_argb;
- }
- // Coalesce rows.
- if (src_stride_argb0 == width * 4 &&
- src_stride_argb1 == width * 4 &&
- dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- src_stride_argb0 = src_stride_argb1 = dst_stride_argb = 0;
- }
-
- for (y = 0; y < height; ++y) {
- ARGBBlendRow(src_argb0, src_argb1, dst_argb, width);
- src_argb0 += src_stride_argb0;
- src_argb1 += src_stride_argb1;
- dst_argb += dst_stride_argb;
- }
- return 0;
-}
-
-// Multiply 2 ARGB images and store to destination.
-LIBYUV_API
-int ARGBMultiply(const uint8* src_argb0, int src_stride_argb0,
- const uint8* src_argb1, int src_stride_argb1,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- int y;
- void (*ARGBMultiplyRow)(const uint8* src0, const uint8* src1, uint8* dst,
- int width) = ARGBMultiplyRow_C;
- if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_argb = dst_argb + (height - 1) * dst_stride_argb;
- dst_stride_argb = -dst_stride_argb;
- }
- // Coalesce rows.
- if (src_stride_argb0 == width * 4 &&
- src_stride_argb1 == width * 4 &&
- dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- src_stride_argb0 = src_stride_argb1 = dst_stride_argb = 0;
- }
-#if defined(HAS_ARGBMULTIPLYROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 4) {
- ARGBMultiplyRow = ARGBMultiplyRow_Any_SSE2;
- if (IS_ALIGNED(width, 4)) {
- ARGBMultiplyRow = ARGBMultiplyRow_SSE2;
- }
- }
-#endif
-#if defined(HAS_ARGBMULTIPLYROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && width >= 8) {
- ARGBMultiplyRow = ARGBMultiplyRow_Any_AVX2;
- if (IS_ALIGNED(width, 8)) {
- ARGBMultiplyRow = ARGBMultiplyRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_ARGBMULTIPLYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGBMultiplyRow = ARGBMultiplyRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGBMultiplyRow = ARGBMultiplyRow_NEON;
- }
- }
-#endif
-
- // Multiply plane
- for (y = 0; y < height; ++y) {
- ARGBMultiplyRow(src_argb0, src_argb1, dst_argb, width);
- src_argb0 += src_stride_argb0;
- src_argb1 += src_stride_argb1;
- dst_argb += dst_stride_argb;
- }
- return 0;
-}
-
-// Add 2 ARGB images and store to destination.
-LIBYUV_API
-int ARGBAdd(const uint8* src_argb0, int src_stride_argb0,
- const uint8* src_argb1, int src_stride_argb1,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- int y;
- void (*ARGBAddRow)(const uint8* src0, const uint8* src1, uint8* dst,
- int width) = ARGBAddRow_C;
- if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_argb = dst_argb + (height - 1) * dst_stride_argb;
- dst_stride_argb = -dst_stride_argb;
- }
- // Coalesce rows.
- if (src_stride_argb0 == width * 4 &&
- src_stride_argb1 == width * 4 &&
- dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- src_stride_argb0 = src_stride_argb1 = dst_stride_argb = 0;
- }
-#if defined(HAS_ARGBADDROW_SSE2) && defined(_MSC_VER)
- if (TestCpuFlag(kCpuHasSSE2)) {
- ARGBAddRow = ARGBAddRow_SSE2;
- }
-#endif
-#if defined(HAS_ARGBADDROW_SSE2) && !defined(_MSC_VER)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 4) {
- ARGBAddRow = ARGBAddRow_Any_SSE2;
- if (IS_ALIGNED(width, 4)) {
- ARGBAddRow = ARGBAddRow_SSE2;
- }
- }
-#endif
-#if defined(HAS_ARGBADDROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && width >= 8) {
- ARGBAddRow = ARGBAddRow_Any_AVX2;
- if (IS_ALIGNED(width, 8)) {
- ARGBAddRow = ARGBAddRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_ARGBADDROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGBAddRow = ARGBAddRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGBAddRow = ARGBAddRow_NEON;
- }
- }
-#endif
-
- // Add plane
- for (y = 0; y < height; ++y) {
- ARGBAddRow(src_argb0, src_argb1, dst_argb, width);
- src_argb0 += src_stride_argb0;
- src_argb1 += src_stride_argb1;
- dst_argb += dst_stride_argb;
- }
- return 0;
-}
-
-// Subtract 2 ARGB images and store to destination.
-LIBYUV_API
-int ARGBSubtract(const uint8* src_argb0, int src_stride_argb0,
- const uint8* src_argb1, int src_stride_argb1,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- int y;
- void (*ARGBSubtractRow)(const uint8* src0, const uint8* src1, uint8* dst,
- int width) = ARGBSubtractRow_C;
- if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_argb = dst_argb + (height - 1) * dst_stride_argb;
- dst_stride_argb = -dst_stride_argb;
- }
- // Coalesce rows.
- if (src_stride_argb0 == width * 4 &&
- src_stride_argb1 == width * 4 &&
- dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- src_stride_argb0 = src_stride_argb1 = dst_stride_argb = 0;
- }
-#if defined(HAS_ARGBSUBTRACTROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 4) {
- ARGBSubtractRow = ARGBSubtractRow_Any_SSE2;
- if (IS_ALIGNED(width, 4)) {
- ARGBSubtractRow = ARGBSubtractRow_SSE2;
- }
- }
-#endif
-#if defined(HAS_ARGBSUBTRACTROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && width >= 8) {
- ARGBSubtractRow = ARGBSubtractRow_Any_AVX2;
- if (IS_ALIGNED(width, 8)) {
- ARGBSubtractRow = ARGBSubtractRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_ARGBSUBTRACTROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGBSubtractRow = ARGBSubtractRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGBSubtractRow = ARGBSubtractRow_NEON;
- }
- }
-#endif
-
- // Subtract plane
- for (y = 0; y < height; ++y) {
- ARGBSubtractRow(src_argb0, src_argb1, dst_argb, width);
- src_argb0 += src_stride_argb0;
- src_argb1 += src_stride_argb1;
- dst_argb += dst_stride_argb;
- }
- return 0;
-}
-
-// Convert I422 to BGRA.
-LIBYUV_API
-int I422ToBGRA(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_bgra, int dst_stride_bgra,
- int width, int height) {
- int y;
- void (*I422ToBGRARow)(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* rgb_buf,
- int width) = I422ToBGRARow_C;
- if (!src_y || !src_u || !src_v ||
- !dst_bgra ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_bgra = dst_bgra + (height - 1) * dst_stride_bgra;
- dst_stride_bgra = -dst_stride_bgra;
- }
- // Coalesce rows.
- if (src_stride_y == width &&
- src_stride_u * 2 == width &&
- src_stride_v * 2 == width &&
- dst_stride_bgra == width * 4) {
- width *= height;
- height = 1;
- src_stride_y = src_stride_u = src_stride_v = dst_stride_bgra = 0;
- }
-#if defined(HAS_I422TOBGRAROW_NEON)
- if (TestCpuFlag(kCpuHasNEON)) {
- I422ToBGRARow = I422ToBGRARow_Any_NEON;
- if (IS_ALIGNED(width, 16)) {
- I422ToBGRARow = I422ToBGRARow_NEON;
- }
- }
-#elif defined(HAS_I422TOBGRAROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
- I422ToBGRARow = I422ToBGRARow_Any_SSSE3;
- if (IS_ALIGNED(width, 8)) {
- I422ToBGRARow = I422ToBGRARow_Unaligned_SSSE3;
- if (IS_ALIGNED(dst_bgra, 16) && IS_ALIGNED(dst_stride_bgra, 16)) {
- I422ToBGRARow = I422ToBGRARow_SSSE3;
- }
- }
- }
-#elif defined(HAS_I422TOBGRAROW_MIPS_DSPR2)
- if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(width, 4) &&
- IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
- IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
- IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) &&
- IS_ALIGNED(dst_bgra, 4) && IS_ALIGNED(dst_stride_bgra, 4)) {
- I422ToBGRARow = I422ToBGRARow_MIPS_DSPR2;
- }
-#endif
-
- for (y = 0; y < height; ++y) {
- I422ToBGRARow(src_y, src_u, src_v, dst_bgra, width);
- dst_bgra += dst_stride_bgra;
- src_y += src_stride_y;
- src_u += src_stride_u;
- src_v += src_stride_v;
- }
- return 0;
-}
-
-// Convert I422 to ABGR.
-LIBYUV_API
-int I422ToABGR(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_abgr, int dst_stride_abgr,
- int width, int height) {
- int y;
- void (*I422ToABGRRow)(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* rgb_buf,
- int width) = I422ToABGRRow_C;
- if (!src_y || !src_u || !src_v ||
- !dst_abgr ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_abgr = dst_abgr + (height - 1) * dst_stride_abgr;
- dst_stride_abgr = -dst_stride_abgr;
- }
- // Coalesce rows.
- if (src_stride_y == width &&
- src_stride_u * 2 == width &&
- src_stride_v * 2 == width &&
- dst_stride_abgr == width * 4) {
- width *= height;
- height = 1;
- src_stride_y = src_stride_u = src_stride_v = dst_stride_abgr = 0;
- }
-#if defined(HAS_I422TOABGRROW_NEON)
- if (TestCpuFlag(kCpuHasNEON)) {
- I422ToABGRRow = I422ToABGRRow_Any_NEON;
- if (IS_ALIGNED(width, 16)) {
- I422ToABGRRow = I422ToABGRRow_NEON;
- }
- }
-#elif defined(HAS_I422TOABGRROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
- I422ToABGRRow = I422ToABGRRow_Any_SSSE3;
- if (IS_ALIGNED(width, 8)) {
- I422ToABGRRow = I422ToABGRRow_Unaligned_SSSE3;
- if (IS_ALIGNED(dst_abgr, 16) && IS_ALIGNED(dst_stride_abgr, 16)) {
- I422ToABGRRow = I422ToABGRRow_SSSE3;
- }
- }
- }
-#endif
-
- for (y = 0; y < height; ++y) {
- I422ToABGRRow(src_y, src_u, src_v, dst_abgr, width);
- dst_abgr += dst_stride_abgr;
- src_y += src_stride_y;
- src_u += src_stride_u;
- src_v += src_stride_v;
- }
- return 0;
-}
-
-// Convert I422 to RGBA.
-LIBYUV_API
-int I422ToRGBA(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_rgba, int dst_stride_rgba,
- int width, int height) {
- int y;
- void (*I422ToRGBARow)(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* rgb_buf,
- int width) = I422ToRGBARow_C;
- if (!src_y || !src_u || !src_v ||
- !dst_rgba ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_rgba = dst_rgba + (height - 1) * dst_stride_rgba;
- dst_stride_rgba = -dst_stride_rgba;
- }
- // Coalesce rows.
- if (src_stride_y == width &&
- src_stride_u * 2 == width &&
- src_stride_v * 2 == width &&
- dst_stride_rgba == width * 4) {
- width *= height;
- height = 1;
- src_stride_y = src_stride_u = src_stride_v = dst_stride_rgba = 0;
- }
-#if defined(HAS_I422TORGBAROW_NEON)
- if (TestCpuFlag(kCpuHasNEON)) {
- I422ToRGBARow = I422ToRGBARow_Any_NEON;
- if (IS_ALIGNED(width, 16)) {
- I422ToRGBARow = I422ToRGBARow_NEON;
- }
- }
-#elif defined(HAS_I422TORGBAROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
- I422ToRGBARow = I422ToRGBARow_Any_SSSE3;
- if (IS_ALIGNED(width, 8)) {
- I422ToRGBARow = I422ToRGBARow_Unaligned_SSSE3;
- if (IS_ALIGNED(dst_rgba, 16) && IS_ALIGNED(dst_stride_rgba, 16)) {
- I422ToRGBARow = I422ToRGBARow_SSSE3;
- }
- }
- }
-#endif
-
- for (y = 0; y < height; ++y) {
- I422ToRGBARow(src_y, src_u, src_v, dst_rgba, width);
- dst_rgba += dst_stride_rgba;
- src_y += src_stride_y;
- src_u += src_stride_u;
- src_v += src_stride_v;
- }
- return 0;
-}
-
-// Convert NV12 to RGB565.
-LIBYUV_API
-int NV12ToRGB565(const uint8* src_y, int src_stride_y,
- const uint8* src_uv, int src_stride_uv,
- uint8* dst_rgb565, int dst_stride_rgb565,
- int width, int height) {
- int y;
- void (*NV12ToRGB565Row)(const uint8* y_buf,
- const uint8* uv_buf,
- uint8* rgb_buf,
- int width) = NV12ToRGB565Row_C;
- if (!src_y || !src_uv || !dst_rgb565 ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
- dst_stride_rgb565 = -dst_stride_rgb565;
- }
-#if defined(HAS_NV12TORGB565ROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
- NV12ToRGB565Row = NV12ToRGB565Row_Any_SSSE3;
- if (IS_ALIGNED(width, 8)) {
- NV12ToRGB565Row = NV12ToRGB565Row_SSSE3;
- }
- }
-#elif defined(HAS_NV12TORGB565ROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- NV12ToRGB565Row = NV12ToRGB565Row_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- NV12ToRGB565Row = NV12ToRGB565Row_NEON;
- }
- }
-#endif
-
- for (y = 0; y < height; ++y) {
- NV12ToRGB565Row(src_y, src_uv, dst_rgb565, width);
- dst_rgb565 += dst_stride_rgb565;
- src_y += src_stride_y;
- if (y & 1) {
- src_uv += src_stride_uv;
- }
- }
- return 0;
-}
-
-// Convert NV21 to RGB565.
-LIBYUV_API
-int NV21ToRGB565(const uint8* src_y, int src_stride_y,
- const uint8* src_vu, int src_stride_vu,
- uint8* dst_rgb565, int dst_stride_rgb565,
- int width, int height) {
- int y;
- void (*NV21ToRGB565Row)(const uint8* y_buf,
- const uint8* src_vu,
- uint8* rgb_buf,
- int width) = NV21ToRGB565Row_C;
- if (!src_y || !src_vu || !dst_rgb565 ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
- dst_stride_rgb565 = -dst_stride_rgb565;
- }
-#if defined(HAS_NV21TORGB565ROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
- NV21ToRGB565Row = NV21ToRGB565Row_Any_SSSE3;
- if (IS_ALIGNED(width, 8)) {
- NV21ToRGB565Row = NV21ToRGB565Row_SSSE3;
- }
- }
-#elif defined(HAS_NV21TORGB565ROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- NV21ToRGB565Row = NV21ToRGB565Row_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- NV21ToRGB565Row = NV21ToRGB565Row_NEON;
- }
- }
-#endif
-
- for (y = 0; y < height; ++y) {
- NV21ToRGB565Row(src_y, src_vu, dst_rgb565, width);
- dst_rgb565 += dst_stride_rgb565;
- src_y += src_stride_y;
- if (y & 1) {
- src_vu += src_stride_vu;
- }
- }
- return 0;
-}
-
-LIBYUV_API
-void SetPlane(uint8* dst_y, int dst_stride_y,
- int width, int height,
- uint32 value) {
- int y;
- uint32 v32 = value | (value << 8) | (value << 16) | (value << 24);
- void (*SetRow)(uint8* dst, uint32 value, int pix) = SetRow_C;
- // Coalesce rows.
- if (dst_stride_y == width) {
- width *= height;
- height = 1;
- dst_stride_y = 0;
- }
-#if defined(HAS_SETROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) &&
- IS_ALIGNED(width, 16) &&
- IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
- SetRow = SetRow_NEON;
- }
-#endif
-#if defined(HAS_SETROW_X86)
- if (TestCpuFlag(kCpuHasX86) && IS_ALIGNED(width, 4)) {
- SetRow = SetRow_X86;
- }
-#endif
-
- // Set plane
- for (y = 0; y < height; ++y) {
- SetRow(dst_y, v32, width);
- dst_y += dst_stride_y;
- }
-}
-
-// Draw a rectangle into I420
-LIBYUV_API
-int I420Rect(uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int x, int y,
- int width, int height,
- int value_y, int value_u, int value_v) {
- int halfwidth = (width + 1) >> 1;
- int halfheight = (height + 1) >> 1;
- uint8* start_y = dst_y + y * dst_stride_y + x;
- uint8* start_u = dst_u + (y / 2) * dst_stride_u + (x / 2);
- uint8* start_v = dst_v + (y / 2) * dst_stride_v + (x / 2);
- if (!dst_y || !dst_u || !dst_v ||
- width <= 0 || height <= 0 ||
- x < 0 || y < 0 ||
- value_y < 0 || value_y > 255 ||
- value_u < 0 || value_u > 255 ||
- value_v < 0 || value_v > 255) {
- return -1;
- }
-
- SetPlane(start_y, dst_stride_y, width, height, value_y);
- SetPlane(start_u, dst_stride_u, halfwidth, halfheight, value_u);
- SetPlane(start_v, dst_stride_v, halfwidth, halfheight, value_v);
- return 0;
-}
-
-// Draw a rectangle into ARGB
-LIBYUV_API
-int ARGBRect(uint8* dst_argb, int dst_stride_argb,
- int dst_x, int dst_y,
- int width, int height,
- uint32 value) {
- if (!dst_argb ||
- width <= 0 || height <= 0 ||
- dst_x < 0 || dst_y < 0) {
- return -1;
- }
- dst_argb += dst_y * dst_stride_argb + dst_x * 4;
- // Coalesce rows.
- if (dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- dst_stride_argb = 0;
- }
-#if defined(HAS_SETROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 16) &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- ARGBSetRows_NEON(dst_argb, value, width, dst_stride_argb, height);
- return 0;
- }
-#endif
-#if defined(HAS_SETROW_X86)
- if (TestCpuFlag(kCpuHasX86)) {
- ARGBSetRows_X86(dst_argb, value, width, dst_stride_argb, height);
- return 0;
- }
-#endif
- ARGBSetRows_C(dst_argb, value, width, dst_stride_argb, height);
- return 0;
-}
-
-// Convert unattentuated ARGB to preattenuated ARGB.
-// An unattenutated ARGB alpha blend uses the formula
-// p = a * f + (1 - a) * b
-// where
-// p is output pixel
-// f is foreground pixel
-// b is background pixel
-// a is alpha value from foreground pixel
-// An preattenutated ARGB alpha blend uses the formula
-// p = f + (1 - a) * b
-// where
-// f is foreground pixel premultiplied by alpha
-
-LIBYUV_API
-int ARGBAttenuate(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- int y;
- void (*ARGBAttenuateRow)(const uint8* src_argb, uint8* dst_argb,
- int width) = ARGBAttenuateRow_C;
- if (!src_argb || !dst_argb || width <= 0 || height == 0) {
- return -1;
- }
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
- // Coalesce rows.
- if (src_stride_argb == width * 4 &&
- dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- src_stride_argb = dst_stride_argb = 0;
- }
-#if defined(HAS_ARGBATTENUATEROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 4 &&
- IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16) &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- ARGBAttenuateRow = ARGBAttenuateRow_Any_SSE2;
- if (IS_ALIGNED(width, 4)) {
- ARGBAttenuateRow = ARGBAttenuateRow_SSE2;
- }
- }
-#endif
-#if defined(HAS_ARGBATTENUATEROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 4) {
- ARGBAttenuateRow = ARGBAttenuateRow_Any_SSSE3;
- if (IS_ALIGNED(width, 4)) {
- ARGBAttenuateRow = ARGBAttenuateRow_SSSE3;
- }
- }
-#endif
-#if defined(HAS_ARGBATTENUATEROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && width >= 8) {
- ARGBAttenuateRow = ARGBAttenuateRow_Any_AVX2;
- if (IS_ALIGNED(width, 8)) {
- ARGBAttenuateRow = ARGBAttenuateRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_ARGBATTENUATEROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGBAttenuateRow = ARGBAttenuateRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGBAttenuateRow = ARGBAttenuateRow_NEON;
- }
- }
-#endif
-
- for (y = 0; y < height; ++y) {
- ARGBAttenuateRow(src_argb, dst_argb, width);
- src_argb += src_stride_argb;
- dst_argb += dst_stride_argb;
- }
- return 0;
-}
-
-// Convert preattentuated ARGB to unattenuated ARGB.
-LIBYUV_API
-int ARGBUnattenuate(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- int y;
- void (*ARGBUnattenuateRow)(const uint8* src_argb, uint8* dst_argb,
- int width) = ARGBUnattenuateRow_C;
- if (!src_argb || !dst_argb || width <= 0 || height == 0) {
- return -1;
- }
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
- // Coalesce rows.
- if (src_stride_argb == width * 4 &&
- dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- src_stride_argb = dst_stride_argb = 0;
- }
-#if defined(HAS_ARGBUNATTENUATEROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 4) {
- ARGBUnattenuateRow = ARGBUnattenuateRow_Any_SSE2;
- if (IS_ALIGNED(width, 4)) {
- ARGBUnattenuateRow = ARGBUnattenuateRow_SSE2;
- }
- }
-#endif
-#if defined(HAS_ARGBUNATTENUATEROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && width >= 8) {
- ARGBUnattenuateRow = ARGBUnattenuateRow_Any_AVX2;
- if (IS_ALIGNED(width, 8)) {
- ARGBUnattenuateRow = ARGBUnattenuateRow_AVX2;
- }
- }
-#endif
-// TODO(fbarchard): Neon version.
-
- for (y = 0; y < height; ++y) {
- ARGBUnattenuateRow(src_argb, dst_argb, width);
- src_argb += src_stride_argb;
- dst_argb += dst_stride_argb;
- }
- return 0;
-}
-
-// Convert ARGB to Grayed ARGB.
-LIBYUV_API
-int ARGBGrayTo(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- int y;
- void (*ARGBGrayRow)(const uint8* src_argb, uint8* dst_argb,
- int width) = ARGBGrayRow_C;
- if (!src_argb || !dst_argb || width <= 0 || height == 0) {
- return -1;
- }
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
- // Coalesce rows.
- if (src_stride_argb == width * 4 &&
- dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- src_stride_argb = dst_stride_argb = 0;
- }
-#if defined(HAS_ARGBGRAYROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 8) &&
- IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16) &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- ARGBGrayRow = ARGBGrayRow_SSSE3;
- }
-#elif defined(HAS_ARGBGRAYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
- ARGBGrayRow = ARGBGrayRow_NEON;
- }
-#endif
-
- for (y = 0; y < height; ++y) {
- ARGBGrayRow(src_argb, dst_argb, width);
- src_argb += src_stride_argb;
- dst_argb += dst_stride_argb;
- }
- return 0;
-}
-
-// Make a rectangle of ARGB gray scale.
-LIBYUV_API
-int ARGBGray(uint8* dst_argb, int dst_stride_argb,
- int dst_x, int dst_y,
- int width, int height) {
- int y;
- void (*ARGBGrayRow)(const uint8* src_argb, uint8* dst_argb,
- int width) = ARGBGrayRow_C;
- uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
- if (!dst_argb || width <= 0 || height <= 0 || dst_x < 0 || dst_y < 0) {
- return -1;
- }
- // Coalesce rows.
- if (dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- dst_stride_argb = 0;
- }
-#if defined(HAS_ARGBGRAYROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 8) &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- ARGBGrayRow = ARGBGrayRow_SSSE3;
- }
-#elif defined(HAS_ARGBGRAYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
- ARGBGrayRow = ARGBGrayRow_NEON;
- }
-#endif
- for (y = 0; y < height; ++y) {
- ARGBGrayRow(dst, dst, width);
- dst += dst_stride_argb;
- }
- return 0;
-}
-
-// Make a rectangle of ARGB Sepia tone.
-LIBYUV_API
-int ARGBSepia(uint8* dst_argb, int dst_stride_argb,
- int dst_x, int dst_y, int width, int height) {
- int y;
- void (*ARGBSepiaRow)(uint8* dst_argb, int width) = ARGBSepiaRow_C;
- uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
- if (!dst_argb || width <= 0 || height <= 0 || dst_x < 0 || dst_y < 0) {
- return -1;
- }
- // Coalesce rows.
- if (dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- dst_stride_argb = 0;
- }
-#if defined(HAS_ARGBSEPIAROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 8) &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- ARGBSepiaRow = ARGBSepiaRow_SSSE3;
- }
-#elif defined(HAS_ARGBSEPIAROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
- ARGBSepiaRow = ARGBSepiaRow_NEON;
- }
-#endif
- for (y = 0; y < height; ++y) {
- ARGBSepiaRow(dst, width);
- dst += dst_stride_argb;
- }
- return 0;
-}
-
-// Apply a 4x4 matrix to each ARGB pixel.
-// Note: Normally for shading, but can be used to swizzle or invert.
-LIBYUV_API
-int ARGBColorMatrix(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- const int8* matrix_argb,
- int width, int height) {
- int y;
- void (*ARGBColorMatrixRow)(const uint8* src_argb, uint8* dst_argb,
- const int8* matrix_argb, int width) = ARGBColorMatrixRow_C;
- if (!src_argb || !dst_argb || !matrix_argb || width <= 0 || height == 0) {
- return -1;
- }
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
- // Coalesce rows.
- if (src_stride_argb == width * 4 &&
- dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- src_stride_argb = dst_stride_argb = 0;
- }
-#if defined(HAS_ARGBCOLORMATRIXROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 8) &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- ARGBColorMatrixRow = ARGBColorMatrixRow_SSSE3;
- }
-#elif defined(HAS_ARGBCOLORMATRIXROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
- ARGBColorMatrixRow = ARGBColorMatrixRow_NEON;
- }
-#endif
- for (y = 0; y < height; ++y) {
- ARGBColorMatrixRow(src_argb, dst_argb, matrix_argb, width);
- src_argb += src_stride_argb;
- dst_argb += dst_stride_argb;
- }
- return 0;
-}
-
-// Apply a 4x3 matrix to each ARGB pixel.
-// Deprecated.
-LIBYUV_API
-int RGBColorMatrix(uint8* dst_argb, int dst_stride_argb,
- const int8* matrix_rgb,
- int dst_x, int dst_y, int width, int height) {
- SIMD_ALIGNED(int8 matrix_argb[16]);
- uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
- if (!dst_argb || !matrix_rgb || width <= 0 || height <= 0 ||
- dst_x < 0 || dst_y < 0) {
- return -1;
- }
-
- // Convert 4x3 7 bit matrix to 4x4 6 bit matrix.
- matrix_argb[0] = matrix_rgb[0] / 2;
- matrix_argb[1] = matrix_rgb[1] / 2;
- matrix_argb[2] = matrix_rgb[2] / 2;
- matrix_argb[3] = matrix_rgb[3] / 2;
- matrix_argb[4] = matrix_rgb[4] / 2;
- matrix_argb[5] = matrix_rgb[5] / 2;
- matrix_argb[6] = matrix_rgb[6] / 2;
- matrix_argb[7] = matrix_rgb[7] / 2;
- matrix_argb[8] = matrix_rgb[8] / 2;
- matrix_argb[9] = matrix_rgb[9] / 2;
- matrix_argb[10] = matrix_rgb[10] / 2;
- matrix_argb[11] = matrix_rgb[11] / 2;
- matrix_argb[14] = matrix_argb[13] = matrix_argb[12] = 0;
- matrix_argb[15] = 64; // 1.0
-
- return ARGBColorMatrix((const uint8*)(dst), dst_stride_argb,
- dst, dst_stride_argb,
- &matrix_argb[0], width, height);
-}
-
-// Apply a color table each ARGB pixel.
-// Table contains 256 ARGB values.
-LIBYUV_API
-int ARGBColorTable(uint8* dst_argb, int dst_stride_argb,
- const uint8* table_argb,
- int dst_x, int dst_y, int width, int height) {
- int y;
- void (*ARGBColorTableRow)(uint8* dst_argb, const uint8* table_argb,
- int width) = ARGBColorTableRow_C;
- uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
- if (!dst_argb || !table_argb || width <= 0 || height <= 0 ||
- dst_x < 0 || dst_y < 0) {
- return -1;
- }
- // Coalesce rows.
- if (dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- dst_stride_argb = 0;
- }
-#if defined(HAS_ARGBCOLORTABLEROW_X86)
- if (TestCpuFlag(kCpuHasX86)) {
- ARGBColorTableRow = ARGBColorTableRow_X86;
- }
-#endif
- for (y = 0; y < height; ++y) {
- ARGBColorTableRow(dst, table_argb, width);
- dst += dst_stride_argb;
- }
- return 0;
-}
-
-// Apply a color table each ARGB pixel but preserve destination alpha.
-// Table contains 256 ARGB values.
-LIBYUV_API
-int RGBColorTable(uint8* dst_argb, int dst_stride_argb,
- const uint8* table_argb,
- int dst_x, int dst_y, int width, int height) {
- int y;
- void (*RGBColorTableRow)(uint8* dst_argb, const uint8* table_argb,
- int width) = RGBColorTableRow_C;
- uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
- if (!dst_argb || !table_argb || width <= 0 || height <= 0 ||
- dst_x < 0 || dst_y < 0) {
- return -1;
- }
- // Coalesce rows.
- if (dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- dst_stride_argb = 0;
- }
-#if defined(HAS_RGBCOLORTABLEROW_X86)
- if (TestCpuFlag(kCpuHasX86)) {
- RGBColorTableRow = RGBColorTableRow_X86;
- }
-#endif
- for (y = 0; y < height; ++y) {
- RGBColorTableRow(dst, table_argb, width);
- dst += dst_stride_argb;
- }
- return 0;
-}
-
-// ARGBQuantize is used to posterize art.
-// e.g. rgb / qvalue * qvalue + qvalue / 2
-// But the low levels implement efficiently with 3 parameters, and could be
-// used for other high level operations.
-// dst_argb[0] = (b * scale >> 16) * interval_size + interval_offset;
-// where scale is 1 / interval_size as a fixed point value.
-// The divide is replaces with a multiply by reciprocal fixed point multiply.
-// Caveat - although SSE2 saturates, the C function does not and should be used
-// with care if doing anything but quantization.
-LIBYUV_API
-int ARGBQuantize(uint8* dst_argb, int dst_stride_argb,
- int scale, int interval_size, int interval_offset,
- int dst_x, int dst_y, int width, int height) {
- int y;
- void (*ARGBQuantizeRow)(uint8* dst_argb, int scale, int interval_size,
- int interval_offset, int width) = ARGBQuantizeRow_C;
- uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
- if (!dst_argb || width <= 0 || height <= 0 || dst_x < 0 || dst_y < 0 ||
- interval_size < 1 || interval_size > 255) {
- return -1;
- }
- // Coalesce rows.
- if (dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- dst_stride_argb = 0;
- }
-#if defined(HAS_ARGBQUANTIZEROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 4) &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- ARGBQuantizeRow = ARGBQuantizeRow_SSE2;
- }
-#elif defined(HAS_ARGBQUANTIZEROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
- ARGBQuantizeRow = ARGBQuantizeRow_NEON;
- }
-#endif
- for (y = 0; y < height; ++y) {
- ARGBQuantizeRow(dst, scale, interval_size, interval_offset, width);
- dst += dst_stride_argb;
- }
- return 0;
-}
-
-// Computes table of cumulative sum for image where the value is the sum
-// of all values above and to the left of the entry. Used by ARGBBlur.
-LIBYUV_API
-int ARGBComputeCumulativeSum(const uint8* src_argb, int src_stride_argb,
- int32* dst_cumsum, int dst_stride32_cumsum,
- int width, int height) {
- int y;
- void (*ComputeCumulativeSumRow)(const uint8* row, int32* cumsum,
- const int32* previous_cumsum, int width) = ComputeCumulativeSumRow_C;
- int32* previous_cumsum = dst_cumsum;
- if (!dst_cumsum || !src_argb || width <= 0 || height <= 0) {
- return -1;
- }
-#if defined(HAS_CUMULATIVESUMTOAVERAGEROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2)) {
- ComputeCumulativeSumRow = ComputeCumulativeSumRow_SSE2;
- }
-#endif
- memset(dst_cumsum, 0, width * sizeof(dst_cumsum[0]) * 4); // 4 int per pixel.
- for (y = 0; y < height; ++y) {
- ComputeCumulativeSumRow(src_argb, dst_cumsum, previous_cumsum, width);
- previous_cumsum = dst_cumsum;
- dst_cumsum += dst_stride32_cumsum;
- src_argb += src_stride_argb;
- }
- return 0;
-}
-
-// Blur ARGB image.
-// Caller should allocate CumulativeSum table of width * height * 16 bytes
-// aligned to 16 byte boundary. height can be radius * 2 + 2 to save memory
-// as the buffer is treated as circular.
-LIBYUV_API
-int ARGBBlur(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- int32* dst_cumsum, int dst_stride32_cumsum,
- int width, int height, int radius) {
- int y;
- void (*ComputeCumulativeSumRow)(const uint8 *row, int32 *cumsum,
- const int32* previous_cumsum, int width) = ComputeCumulativeSumRow_C;
- void (*CumulativeSumToAverageRow)(const int32* topleft, const int32* botleft,
- int width, int area, uint8* dst, int count) = CumulativeSumToAverageRow_C;
- int32* cumsum_bot_row;
- int32* max_cumsum_bot_row;
- int32* cumsum_top_row;
-
- if (!src_argb || !dst_argb || width <= 0 || height == 0) {
- return -1;
- }
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
- if (radius > height) {
- radius = height;
- }
- if (radius > (width / 2 - 1)) {
- radius = width / 2 - 1;
- }
- if (radius <= 0) {
- return -1;
- }
-#if defined(HAS_CUMULATIVESUMTOAVERAGEROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2)) {
- ComputeCumulativeSumRow = ComputeCumulativeSumRow_SSE2;
- CumulativeSumToAverageRow = CumulativeSumToAverageRow_SSE2;
- }
-#endif
- // Compute enough CumulativeSum for first row to be blurred. After this
- // one row of CumulativeSum is updated at a time.
- ARGBComputeCumulativeSum(src_argb, src_stride_argb,
- dst_cumsum, dst_stride32_cumsum,
- width, radius);
-
- src_argb = src_argb + radius * src_stride_argb;
- cumsum_bot_row = &dst_cumsum[(radius - 1) * dst_stride32_cumsum];
-
- max_cumsum_bot_row = &dst_cumsum[(radius * 2 + 2) * dst_stride32_cumsum];
- cumsum_top_row = &dst_cumsum[0];
-
- for (y = 0; y < height; ++y) {
- int top_y = ((y - radius - 1) >= 0) ? (y - radius - 1) : 0;
- int bot_y = ((y + radius) < height) ? (y + radius) : (height - 1);
- int area = radius * (bot_y - top_y);
- int boxwidth = radius * 4;
- int x;
- int n;
-
- // Increment cumsum_top_row pointer with circular buffer wrap around.
- if (top_y) {
- cumsum_top_row += dst_stride32_cumsum;
- if (cumsum_top_row >= max_cumsum_bot_row) {
- cumsum_top_row = dst_cumsum;
- }
- }
- // Increment cumsum_bot_row pointer with circular buffer wrap around and
- // then fill in a row of CumulativeSum.
- if ((y + radius) < height) {
- const int32* prev_cumsum_bot_row = cumsum_bot_row;
- cumsum_bot_row += dst_stride32_cumsum;
- if (cumsum_bot_row >= max_cumsum_bot_row) {
- cumsum_bot_row = dst_cumsum;
- }
- ComputeCumulativeSumRow(src_argb, cumsum_bot_row, prev_cumsum_bot_row,
- width);
- src_argb += src_stride_argb;
- }
-
- // Left clipped.
- for (x = 0; x < radius + 1; ++x) {
- CumulativeSumToAverageRow(cumsum_top_row, cumsum_bot_row,
- boxwidth, area, &dst_argb[x * 4], 1);
- area += (bot_y - top_y);
- boxwidth += 4;
- }
-
- // Middle unclipped.
- n = (width - 1) - radius - x + 1;
- CumulativeSumToAverageRow(cumsum_top_row, cumsum_bot_row,
- boxwidth, area, &dst_argb[x * 4], n);
-
- // Right clipped.
- for (x += n; x <= width - 1; ++x) {
- area -= (bot_y - top_y);
- boxwidth -= 4;
- CumulativeSumToAverageRow(cumsum_top_row + (x - radius - 1) * 4,
- cumsum_bot_row + (x - radius - 1) * 4,
- boxwidth, area, &dst_argb[x * 4], 1);
- }
- dst_argb += dst_stride_argb;
- }
- return 0;
-}
-
-// Multiply ARGB image by a specified ARGB value.
-LIBYUV_API
-int ARGBShade(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height, uint32 value) {
- int y;
- void (*ARGBShadeRow)(const uint8* src_argb, uint8* dst_argb,
- int width, uint32 value) = ARGBShadeRow_C;
- if (!src_argb || !dst_argb || width <= 0 || height == 0 || value == 0u) {
- return -1;
- }
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
- // Coalesce rows.
- if (src_stride_argb == width * 4 &&
- dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- src_stride_argb = dst_stride_argb = 0;
- }
-#if defined(HAS_ARGBSHADEROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 4) &&
- IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16) &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- ARGBShadeRow = ARGBShadeRow_SSE2;
- }
-#elif defined(HAS_ARGBSHADEROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
- ARGBShadeRow = ARGBShadeRow_NEON;
- }
-#endif
-
- for (y = 0; y < height; ++y) {
- ARGBShadeRow(src_argb, dst_argb, width, value);
- src_argb += src_stride_argb;
- dst_argb += dst_stride_argb;
- }
- return 0;
-}
-
-// Interpolate 2 ARGB images by specified amount (0 to 255).
-LIBYUV_API
-int ARGBInterpolate(const uint8* src_argb0, int src_stride_argb0,
- const uint8* src_argb1, int src_stride_argb1,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height, int interpolation) {
- int y;
- void (*InterpolateRow)(uint8* dst_ptr, const uint8* src_ptr,
- ptrdiff_t src_stride, int dst_width,
- int source_y_fraction) = InterpolateRow_C;
- if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- dst_argb = dst_argb + (height - 1) * dst_stride_argb;
- dst_stride_argb = -dst_stride_argb;
- }
- // Coalesce rows.
- if (src_stride_argb0 == width * 4 &&
- src_stride_argb1 == width * 4 &&
- dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- src_stride_argb0 = src_stride_argb1 = dst_stride_argb = 0;
- }
-#if defined(HAS_INTERPOLATEROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 4) {
- InterpolateRow = InterpolateRow_Any_SSE2;
- if (IS_ALIGNED(width, 4)) {
- InterpolateRow = InterpolateRow_Unaligned_SSE2;
- if (IS_ALIGNED(src_argb0, 16) && IS_ALIGNED(src_stride_argb0, 16) &&
- IS_ALIGNED(src_argb1, 16) && IS_ALIGNED(src_stride_argb1, 16) &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- InterpolateRow = InterpolateRow_SSE2;
- }
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 4) {
- InterpolateRow = InterpolateRow_Any_SSSE3;
- if (IS_ALIGNED(width, 4)) {
- InterpolateRow = InterpolateRow_Unaligned_SSSE3;
- if (IS_ALIGNED(src_argb0, 16) && IS_ALIGNED(src_stride_argb0, 16) &&
- IS_ALIGNED(src_argb1, 16) && IS_ALIGNED(src_stride_argb1, 16) &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- InterpolateRow = InterpolateRow_SSSE3;
- }
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && width >= 8) {
- InterpolateRow = InterpolateRow_Any_AVX2;
- if (IS_ALIGNED(width, 8)) {
- InterpolateRow = InterpolateRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 4) {
- InterpolateRow = InterpolateRow_Any_NEON;
- if (IS_ALIGNED(width, 4)) {
- InterpolateRow = InterpolateRow_NEON;
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROWS_MIPS_DSPR2)
- if (TestCpuFlag(kCpuHasMIPS_DSPR2) && width >= 1 &&
- IS_ALIGNED(src_argb0, 4) && IS_ALIGNED(src_stride_argb0, 4) &&
- IS_ALIGNED(src_argb1, 4) && IS_ALIGNED(src_stride_argb1, 4) &&
- IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) {
- ScaleARGBFilterRows = InterpolateRow_MIPS_DSPR2;
- }
-#endif
-
- for (y = 0; y < height; ++y) {
- InterpolateRow(dst_argb, src_argb0, src_argb1 - src_argb0,
- width * 4, interpolation);
- src_argb0 += src_stride_argb0;
- src_argb1 += src_stride_argb1;
- dst_argb += dst_stride_argb;
- }
- return 0;
-}
-
-// Shuffle ARGB channel order. e.g. BGRA to ARGB.
-LIBYUV_API
-int ARGBShuffle(const uint8* src_bgra, int src_stride_bgra,
- uint8* dst_argb, int dst_stride_argb,
- const uint8* shuffler, int width, int height) {
- int y;
- void (*ARGBShuffleRow)(const uint8* src_bgra, uint8* dst_argb,
- const uint8* shuffler, int pix) = ARGBShuffleRow_C;
- if (!src_bgra || !dst_argb ||
- width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_bgra = src_bgra + (height - 1) * src_stride_bgra;
- src_stride_bgra = -src_stride_bgra;
- }
- // Coalesce rows.
- if (src_stride_bgra == width * 4 &&
- dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- src_stride_bgra = dst_stride_argb = 0;
- }
-#if defined(HAS_ARGBSHUFFLEROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 4) {
- ARGBShuffleRow = ARGBShuffleRow_Any_SSE2;
- if (IS_ALIGNED(width, 4)) {
- ARGBShuffleRow = ARGBShuffleRow_SSE2;
- }
- }
-#endif
-#if defined(HAS_ARGBSHUFFLEROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
- ARGBShuffleRow = ARGBShuffleRow_Any_SSSE3;
- if (IS_ALIGNED(width, 8)) {
- ARGBShuffleRow = ARGBShuffleRow_Unaligned_SSSE3;
- if (IS_ALIGNED(src_bgra, 16) && IS_ALIGNED(src_stride_bgra, 16) &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- ARGBShuffleRow = ARGBShuffleRow_SSSE3;
- }
- }
- }
-#endif
-#if defined(HAS_ARGBSHUFFLEROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && width >= 16) {
- ARGBShuffleRow = ARGBShuffleRow_Any_AVX2;
- if (IS_ALIGNED(width, 16)) {
- ARGBShuffleRow = ARGBShuffleRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_ARGBSHUFFLEROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 4) {
- ARGBShuffleRow = ARGBShuffleRow_Any_NEON;
- if (IS_ALIGNED(width, 4)) {
- ARGBShuffleRow = ARGBShuffleRow_NEON;
- }
- }
-#endif
-
- for (y = 0; y < height; ++y) {
- ARGBShuffleRow(src_bgra, dst_argb, shuffler, width);
- src_bgra += src_stride_bgra;
- dst_argb += dst_stride_argb;
- }
- return 0;
-}
-
-// Sobel ARGB effect.
-static int ARGBSobelize(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height,
- void (*SobelRow)(const uint8* src_sobelx,
- const uint8* src_sobely,
- uint8* dst, int width)) {
- int y;
- void (*ARGBToBayerRow)(const uint8* src_argb, uint8* dst_bayer,
- uint32 selector, int pix) = ARGBToBayerGGRow_C;
- void (*SobelYRow)(const uint8* src_y0, const uint8* src_y1,
- uint8* dst_sobely, int width) = SobelYRow_C;
- void (*SobelXRow)(const uint8* src_y0, const uint8* src_y1,
- const uint8* src_y2, uint8* dst_sobely, int width) =
- SobelXRow_C;
- const int kEdge = 16; // Extra pixels at start of row for extrude/align.
- if (!src_argb || !dst_argb || width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
- // ARGBToBayer used to select G channel from ARGB.
-#if defined(HAS_ARGBTOBAYERGGROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && width >= 8 &&
- IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) {
- ARGBToBayerRow = ARGBToBayerGGRow_Any_SSE2;
- if (IS_ALIGNED(width, 8)) {
- ARGBToBayerRow = ARGBToBayerGGRow_SSE2;
- }
- }
-#endif
-#if defined(HAS_ARGBTOBAYERROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && width >= 8 &&
- IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) {
- ARGBToBayerRow = ARGBToBayerRow_Any_SSSE3;
- if (IS_ALIGNED(width, 8)) {
- ARGBToBayerRow = ARGBToBayerRow_SSSE3;
- }
- }
-#endif
-#if defined(HAS_ARGBTOBAYERGGROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
- ARGBToBayerRow = ARGBToBayerGGRow_Any_NEON;
- if (IS_ALIGNED(width, 8)) {
- ARGBToBayerRow = ARGBToBayerGGRow_NEON;
- }
- }
-#endif
-#if defined(HAS_SOBELYROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2)) {
- SobelYRow = SobelYRow_SSE2;
- }
-#endif
-#if defined(HAS_SOBELYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON)) {
- SobelYRow = SobelYRow_NEON;
- }
-#endif
-#if defined(HAS_SOBELXROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2)) {
- SobelXRow = SobelXRow_SSE2;
- }
-#endif
-#if defined(HAS_SOBELXROW_NEON)
- if (TestCpuFlag(kCpuHasNEON)) {
- SobelXRow = SobelXRow_NEON;
- }
-#endif
- {
- // 3 rows with edges before/after.
- const int kRowSize = (width + kEdge + 15) & ~15;
- align_buffer_64(rows, kRowSize * 2 + (kEdge + kRowSize * 3 + kEdge));
- uint8* row_sobelx = rows;
- uint8* row_sobely = rows + kRowSize;
- uint8* row_y = rows + kRowSize * 2;
-
- // Convert first row.
- uint8* row_y0 = row_y + kEdge;
- uint8* row_y1 = row_y0 + kRowSize;
- uint8* row_y2 = row_y1 + kRowSize;
- ARGBToBayerRow(src_argb, row_y0, 0x0d090501, width);
- row_y0[-1] = row_y0[0];
- memset(row_y0 + width, row_y0[width - 1], 16); // Extrude 16 for valgrind.
- ARGBToBayerRow(src_argb, row_y1, 0x0d090501, width);
- row_y1[-1] = row_y1[0];
- memset(row_y1 + width, row_y1[width - 1], 16);
- memset(row_y2 + width, 0, 16);
-
- for (y = 0; y < height; ++y) {
- // Convert next row of ARGB to Y.
- if (y < (height - 1)) {
- src_argb += src_stride_argb;
- }
- ARGBToBayerRow(src_argb, row_y2, 0x0d090501, width);
- row_y2[-1] = row_y2[0];
- row_y2[width] = row_y2[width - 1];
-
- SobelXRow(row_y0 - 1, row_y1 - 1, row_y2 - 1, row_sobelx, width);
- SobelYRow(row_y0 - 1, row_y2 - 1, row_sobely, width);
- SobelRow(row_sobelx, row_sobely, dst_argb, width);
-
- // Cycle thru circular queue of 3 row_y buffers.
- {
- uint8* row_yt = row_y0;
- row_y0 = row_y1;
- row_y1 = row_y2;
- row_y2 = row_yt;
- }
-
- dst_argb += dst_stride_argb;
- }
- free_aligned_buffer_64(rows);
- }
- return 0;
-}
-
-// Sobel ARGB effect.
-LIBYUV_API
-int ARGBSobel(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- void (*SobelRow)(const uint8* src_sobelx, const uint8* src_sobely,
- uint8* dst_argb, int width) = SobelRow_C;
-#if defined(HAS_SOBELROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 16) &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- SobelRow = SobelRow_SSE2;
- }
-#endif
-#if defined(HAS_SOBELROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
- SobelRow = SobelRow_NEON;
- }
-#endif
- return ARGBSobelize(src_argb, src_stride_argb, dst_argb, dst_stride_argb,
- width, height, SobelRow);
-}
-
-// Sobel ARGB effect with planar output.
-LIBYUV_API
-int ARGBSobelToPlane(const uint8* src_argb, int src_stride_argb,
- uint8* dst_y, int dst_stride_y,
- int width, int height) {
- void (*SobelToPlaneRow)(const uint8* src_sobelx, const uint8* src_sobely,
- uint8* dst_, int width) = SobelToPlaneRow_C;
-#if defined(HAS_SOBELTOPLANEROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 16) &&
- IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
- SobelToPlaneRow = SobelToPlaneRow_SSE2;
- }
-#endif
-#if defined(HAS_SOBELTOPLANEROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 16)) {
- SobelToPlaneRow = SobelToPlaneRow_NEON;
- }
-#endif
- return ARGBSobelize(src_argb, src_stride_argb, dst_y, dst_stride_y,
- width, height, SobelToPlaneRow);
-}
-
-// SobelXY ARGB effect.
-// Similar to Sobel, but also stores Sobel X in R and Sobel Y in B. G = Sobel.
-LIBYUV_API
-int ARGBSobelXY(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- void (*SobelXYRow)(const uint8* src_sobelx, const uint8* src_sobely,
- uint8* dst_argb, int width) = SobelXYRow_C;
-#if defined(HAS_SOBELXYROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 16) &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- SobelXYRow = SobelXYRow_SSE2;
- }
-#endif
-#if defined(HAS_SOBELXYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
- SobelXYRow = SobelXYRow_NEON;
- }
-#endif
- return ARGBSobelize(src_argb, src_stride_argb, dst_argb, dst_stride_argb,
- width, height, SobelXYRow);
-}
-
-// Apply a 4x4 polynomial to each ARGB pixel.
-LIBYUV_API
-int ARGBPolynomial(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- const float* poly,
- int width, int height) {
- int y;
- void (*ARGBPolynomialRow)(const uint8* src_argb,
- uint8* dst_argb, const float* poly,
- int width) = ARGBPolynomialRow_C;
- if (!src_argb || !dst_argb || !poly || width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
- // Coalesce rows.
- if (src_stride_argb == width * 4 &&
- dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- src_stride_argb = dst_stride_argb = 0;
- }
-#if defined(HAS_ARGBPOLYNOMIALROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 2)) {
- ARGBPolynomialRow = ARGBPolynomialRow_SSE2;
- }
-#endif
-#if defined(HAS_ARGBPOLYNOMIALROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && TestCpuFlag(kCpuHasFMA3) &&
- IS_ALIGNED(width, 2)) {
- ARGBPolynomialRow = ARGBPolynomialRow_AVX2;
- }
-#endif
-
- for (y = 0; y < height; ++y) {
- ARGBPolynomialRow(src_argb, dst_argb, poly, width);
- src_argb += src_stride_argb;
- dst_argb += dst_stride_argb;
- }
- return 0;
-}
-
-// Apply a lumacolortable to each ARGB pixel.
-LIBYUV_API
-int ARGBLumaColorTable(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- const uint8* luma,
- int width, int height) {
- int y;
- void (*ARGBLumaColorTableRow)(const uint8* src_argb, uint8* dst_argb,
- int width, const uint8* luma, const uint32 lumacoeff) =
- ARGBLumaColorTableRow_C;
- if (!src_argb || !dst_argb || !luma || width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
- // Coalesce rows.
- if (src_stride_argb == width * 4 &&
- dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- src_stride_argb = dst_stride_argb = 0;
- }
-#if defined(HAS_ARGBLUMACOLORTABLEROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 4)) {
- ARGBLumaColorTableRow = ARGBLumaColorTableRow_SSSE3;
- }
-#endif
-
- for (y = 0; y < height; ++y) {
- ARGBLumaColorTableRow(src_argb, dst_argb, width, luma, 0x00264b0f);
- src_argb += src_stride_argb;
- dst_argb += dst_stride_argb;
- }
- return 0;
-}
-
-// Copy Alpha from one ARGB image to another.
-LIBYUV_API
-int ARGBCopyAlpha(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- int y;
- void (*ARGBCopyAlphaRow)(const uint8* src_argb, uint8* dst_argb, int width) =
- ARGBCopyAlphaRow_C;
- if (!src_argb || !dst_argb || width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
- // Coalesce rows.
- if (src_stride_argb == width * 4 &&
- dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- src_stride_argb = dst_stride_argb = 0;
- }
-#if defined(HAS_ARGBCOPYALPHAROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) &&
- IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16) &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16) &&
- IS_ALIGNED(width, 8)) {
- ARGBCopyAlphaRow = ARGBCopyAlphaRow_SSE2;
- }
-#endif
-#if defined(HAS_ARGBCOPYALPHAROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && IS_ALIGNED(width, 16)) {
- ARGBCopyAlphaRow = ARGBCopyAlphaRow_AVX2;
- }
-#endif
-
- for (y = 0; y < height; ++y) {
- ARGBCopyAlphaRow(src_argb, dst_argb, width);
- src_argb += src_stride_argb;
- dst_argb += dst_stride_argb;
- }
- return 0;
-}
-
-// Copy a planar Y channel to the alpha channel of a destination ARGB image.
-LIBYUV_API
-int ARGBCopyYToAlpha(const uint8* src_y, int src_stride_y,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height) {
- int y;
- void (*ARGBCopyYToAlphaRow)(const uint8* src_y, uint8* dst_argb, int width) =
- ARGBCopyYToAlphaRow_C;
- if (!src_y || !dst_argb || width <= 0 || height == 0) {
- return -1;
- }
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_y = src_y + (height - 1) * src_stride_y;
- src_stride_y = -src_stride_y;
- }
- // Coalesce rows.
- if (src_stride_y == width &&
- dst_stride_argb == width * 4) {
- width *= height;
- height = 1;
- src_stride_y = dst_stride_argb = 0;
- }
-#if defined(HAS_ARGBCOPYYTOALPHAROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) &&
- IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16) &&
- IS_ALIGNED(width, 8)) {
- ARGBCopyYToAlphaRow = ARGBCopyYToAlphaRow_SSE2;
- }
-#endif
-#if defined(HAS_ARGBCOPYYTOALPHAROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && IS_ALIGNED(width, 16)) {
- ARGBCopyYToAlphaRow = ARGBCopyYToAlphaRow_AVX2;
- }
-#endif
-
- for (y = 0; y < height; ++y) {
- ARGBCopyYToAlphaRow(src_y, dst_argb, width);
- src_y += src_stride_y;
- dst_argb += dst_stride_argb;
- }
- return 0;
-}
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/rotate.cc b/drivers/theoraplayer/src/YUV/libyuv/src/rotate.cc
deleted file mode 100755
index b052ac1dc4..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/rotate.cc
+++ /dev/null
@@ -1,1301 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/rotate.h"
-
-#include "libyuv/cpu_id.h"
-#include "libyuv/convert.h"
-#include "libyuv/planar_functions.h"
-#include "libyuv/row.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-#if !defined(LIBYUV_DISABLE_X86) && \
- (defined(_M_IX86) || defined(__x86_64__) || defined(__i386__))
-#if defined(__APPLE__) && defined(__i386__)
-#define DECLARE_FUNCTION(name) \
- ".text \n" \
- ".private_extern _" #name " \n" \
- ".align 4,0x90 \n" \
-"_" #name ": \n"
-#elif defined(__MINGW32__) || defined(__CYGWIN__) && defined(__i386__)
-#define DECLARE_FUNCTION(name) \
- ".text \n" \
- ".align 4,0x90 \n" \
-"_" #name ": \n"
-#else
-#define DECLARE_FUNCTION(name) \
- ".text \n" \
- ".align 4,0x90 \n" \
-#name ": \n"
-#endif
-#endif
-
-#if !defined(LIBYUV_DISABLE_NEON) && !defined(__native_client__) && \
- (defined(__ARM_NEON__) || defined(LIBYUV_NEON))
-#define HAS_MIRRORROW_NEON
-void MirrorRow_NEON(const uint8* src, uint8* dst, int width);
-#define HAS_MIRRORROW_UV_NEON
-void MirrorUVRow_NEON(const uint8* src, uint8* dst_a, uint8* dst_b, int width);
-#define HAS_TRANSPOSE_WX8_NEON
-void TransposeWx8_NEON(const uint8* src, int src_stride,
- uint8* dst, int dst_stride, int width);
-#define HAS_TRANSPOSE_UVWX8_NEON
-void TransposeUVWx8_NEON(const uint8* src, int src_stride,
- uint8* dst_a, int dst_stride_a,
- uint8* dst_b, int dst_stride_b,
- int width);
-#endif // defined(__ARM_NEON__)
-
-#if !defined(LIBYUV_DISABLE_MIPS) && !defined(__native_client__) && \
- defined(__mips__) && \
- defined(__mips_dsp) && (__mips_dsp_rev >= 2)
-#define HAS_TRANSPOSE_WX8_MIPS_DSPR2
-void TransposeWx8_MIPS_DSPR2(const uint8* src, int src_stride,
- uint8* dst, int dst_stride, int width);
-
-void TransposeWx8_FAST_MIPS_DSPR2(const uint8* src, int src_stride,
- uint8* dst, int dst_stride, int width);
-#define HAS_TRANSPOSE_UVWx8_MIPS_DSPR2
-void TransposeUVWx8_MIPS_DSPR2(const uint8* src, int src_stride,
- uint8* dst_a, int dst_stride_a,
- uint8* dst_b, int dst_stride_b,
- int width);
-#endif // defined(__mips__)
-
-#if !defined(LIBYUV_DISABLE_X86) && \
- defined(_M_IX86) && defined(_MSC_VER)
-#define HAS_TRANSPOSE_WX8_SSSE3
-__declspec(naked) __declspec(align(16))
-static void TransposeWx8_SSSE3(const uint8* src, int src_stride,
- uint8* dst, int dst_stride, int width) {
- __asm {
- push edi
- push esi
- push ebp
- mov eax, [esp + 12 + 4] // src
- mov edi, [esp + 12 + 8] // src_stride
- mov edx, [esp + 12 + 12] // dst
- mov esi, [esp + 12 + 16] // dst_stride
- mov ecx, [esp + 12 + 20] // width
-
- // Read in the data from the source pointer.
- // First round of bit swap.
- align 4
- convertloop:
- movq xmm0, qword ptr [eax]
- lea ebp, [eax + 8]
- movq xmm1, qword ptr [eax + edi]
- lea eax, [eax + 2 * edi]
- punpcklbw xmm0, xmm1
- movq xmm2, qword ptr [eax]
- movdqa xmm1, xmm0
- palignr xmm1, xmm1, 8
- movq xmm3, qword ptr [eax + edi]
- lea eax, [eax + 2 * edi]
- punpcklbw xmm2, xmm3
- movdqa xmm3, xmm2
- movq xmm4, qword ptr [eax]
- palignr xmm3, xmm3, 8
- movq xmm5, qword ptr [eax + edi]
- punpcklbw xmm4, xmm5
- lea eax, [eax + 2 * edi]
- movdqa xmm5, xmm4
- movq xmm6, qword ptr [eax]
- palignr xmm5, xmm5, 8
- movq xmm7, qword ptr [eax + edi]
- punpcklbw xmm6, xmm7
- mov eax, ebp
- movdqa xmm7, xmm6
- palignr xmm7, xmm7, 8
- // Second round of bit swap.
- punpcklwd xmm0, xmm2
- punpcklwd xmm1, xmm3
- movdqa xmm2, xmm0
- movdqa xmm3, xmm1
- palignr xmm2, xmm2, 8
- palignr xmm3, xmm3, 8
- punpcklwd xmm4, xmm6
- punpcklwd xmm5, xmm7
- movdqa xmm6, xmm4
- movdqa xmm7, xmm5
- palignr xmm6, xmm6, 8
- palignr xmm7, xmm7, 8
- // Third round of bit swap.
- // Write to the destination pointer.
- punpckldq xmm0, xmm4
- movq qword ptr [edx], xmm0
- movdqa xmm4, xmm0
- palignr xmm4, xmm4, 8
- movq qword ptr [edx + esi], xmm4
- lea edx, [edx + 2 * esi]
- punpckldq xmm2, xmm6
- movdqa xmm6, xmm2
- palignr xmm6, xmm6, 8
- movq qword ptr [edx], xmm2
- punpckldq xmm1, xmm5
- movq qword ptr [edx + esi], xmm6
- lea edx, [edx + 2 * esi]
- movdqa xmm5, xmm1
- movq qword ptr [edx], xmm1
- palignr xmm5, xmm5, 8
- punpckldq xmm3, xmm7
- movq qword ptr [edx + esi], xmm5
- lea edx, [edx + 2 * esi]
- movq qword ptr [edx], xmm3
- movdqa xmm7, xmm3
- palignr xmm7, xmm7, 8
- sub ecx, 8
- movq qword ptr [edx + esi], xmm7
- lea edx, [edx + 2 * esi]
- jg convertloop
-
- pop ebp
- pop esi
- pop edi
- ret
- }
-}
-
-#define HAS_TRANSPOSE_UVWX8_SSE2
-__declspec(naked) __declspec(align(16))
-static void TransposeUVWx8_SSE2(const uint8* src, int src_stride,
- uint8* dst_a, int dst_stride_a,
- uint8* dst_b, int dst_stride_b,
- int w) {
- __asm {
- push ebx
- push esi
- push edi
- push ebp
- mov eax, [esp + 16 + 4] // src
- mov edi, [esp + 16 + 8] // src_stride
- mov edx, [esp + 16 + 12] // dst_a
- mov esi, [esp + 16 + 16] // dst_stride_a
- mov ebx, [esp + 16 + 20] // dst_b
- mov ebp, [esp + 16 + 24] // dst_stride_b
- mov ecx, esp
- sub esp, 4 + 16
- and esp, ~15
- mov [esp + 16], ecx
- mov ecx, [ecx + 16 + 28] // w
-
- align 4
- convertloop:
- // Read in the data from the source pointer.
- // First round of bit swap.
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + edi]
- lea eax, [eax + 2 * edi]
- movdqa xmm7, xmm0 // use xmm7 as temp register.
- punpcklbw xmm0, xmm1
- punpckhbw xmm7, xmm1
- movdqa xmm1, xmm7
- movdqa xmm2, [eax]
- movdqa xmm3, [eax + edi]
- lea eax, [eax + 2 * edi]
- movdqa xmm7, xmm2
- punpcklbw xmm2, xmm3
- punpckhbw xmm7, xmm3
- movdqa xmm3, xmm7
- movdqa xmm4, [eax]
- movdqa xmm5, [eax + edi]
- lea eax, [eax + 2 * edi]
- movdqa xmm7, xmm4
- punpcklbw xmm4, xmm5
- punpckhbw xmm7, xmm5
- movdqa xmm5, xmm7
- movdqa xmm6, [eax]
- movdqa xmm7, [eax + edi]
- lea eax, [eax + 2 * edi]
- movdqa [esp], xmm5 // backup xmm5
- neg edi
- movdqa xmm5, xmm6 // use xmm5 as temp register.
- punpcklbw xmm6, xmm7
- punpckhbw xmm5, xmm7
- movdqa xmm7, xmm5
- lea eax, [eax + 8 * edi + 16]
- neg edi
- // Second round of bit swap.
- movdqa xmm5, xmm0
- punpcklwd xmm0, xmm2
- punpckhwd xmm5, xmm2
- movdqa xmm2, xmm5
- movdqa xmm5, xmm1
- punpcklwd xmm1, xmm3
- punpckhwd xmm5, xmm3
- movdqa xmm3, xmm5
- movdqa xmm5, xmm4
- punpcklwd xmm4, xmm6
- punpckhwd xmm5, xmm6
- movdqa xmm6, xmm5
- movdqa xmm5, [esp] // restore xmm5
- movdqa [esp], xmm6 // backup xmm6
- movdqa xmm6, xmm5 // use xmm6 as temp register.
- punpcklwd xmm5, xmm7
- punpckhwd xmm6, xmm7
- movdqa xmm7, xmm6
- // Third round of bit swap.
- // Write to the destination pointer.
- movdqa xmm6, xmm0
- punpckldq xmm0, xmm4
- punpckhdq xmm6, xmm4
- movdqa xmm4, xmm6
- movdqa xmm6, [esp] // restore xmm6
- movlpd qword ptr [edx], xmm0
- movhpd qword ptr [ebx], xmm0
- movlpd qword ptr [edx + esi], xmm4
- lea edx, [edx + 2 * esi]
- movhpd qword ptr [ebx + ebp], xmm4
- lea ebx, [ebx + 2 * ebp]
- movdqa xmm0, xmm2 // use xmm0 as the temp register.
- punpckldq xmm2, xmm6
- movlpd qword ptr [edx], xmm2
- movhpd qword ptr [ebx], xmm2
- punpckhdq xmm0, xmm6
- movlpd qword ptr [edx + esi], xmm0
- lea edx, [edx + 2 * esi]
- movhpd qword ptr [ebx + ebp], xmm0
- lea ebx, [ebx + 2 * ebp]
- movdqa xmm0, xmm1 // use xmm0 as the temp register.
- punpckldq xmm1, xmm5
- movlpd qword ptr [edx], xmm1
- movhpd qword ptr [ebx], xmm1
- punpckhdq xmm0, xmm5
- movlpd qword ptr [edx + esi], xmm0
- lea edx, [edx + 2 * esi]
- movhpd qword ptr [ebx + ebp], xmm0
- lea ebx, [ebx + 2 * ebp]
- movdqa xmm0, xmm3 // use xmm0 as the temp register.
- punpckldq xmm3, xmm7
- movlpd qword ptr [edx], xmm3
- movhpd qword ptr [ebx], xmm3
- punpckhdq xmm0, xmm7
- sub ecx, 8
- movlpd qword ptr [edx + esi], xmm0
- lea edx, [edx + 2 * esi]
- movhpd qword ptr [ebx + ebp], xmm0
- lea ebx, [ebx + 2 * ebp]
- jg convertloop
-
- mov esp, [esp + 16]
- pop ebp
- pop edi
- pop esi
- pop ebx
- ret
- }
-}
-#elif !defined(LIBYUV_DISABLE_X86) && \
- (defined(__i386__) || (defined(__x86_64__) && !defined(__native_client__)))
-#define HAS_TRANSPOSE_WX8_SSSE3
-static void TransposeWx8_SSSE3(const uint8* src, int src_stride,
- uint8* dst, int dst_stride, int width) {
- asm volatile (
- // Read in the data from the source pointer.
- // First round of bit swap.
- ".p2align 2 \n"
- "1: \n"
- "movq (%0),%%xmm0 \n"
- "movq (%0,%3),%%xmm1 \n"
- "lea (%0,%3,2),%0 \n"
- "punpcklbw %%xmm1,%%xmm0 \n"
- "movq (%0),%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "palignr $0x8,%%xmm1,%%xmm1 \n"
- "movq (%0,%3),%%xmm3 \n"
- "lea (%0,%3,2),%0 \n"
- "punpcklbw %%xmm3,%%xmm2 \n"
- "movdqa %%xmm2,%%xmm3 \n"
- "movq (%0),%%xmm4 \n"
- "palignr $0x8,%%xmm3,%%xmm3 \n"
- "movq (%0,%3),%%xmm5 \n"
- "lea (%0,%3,2),%0 \n"
- "punpcklbw %%xmm5,%%xmm4 \n"
- "movdqa %%xmm4,%%xmm5 \n"
- "movq (%0),%%xmm6 \n"
- "palignr $0x8,%%xmm5,%%xmm5 \n"
- "movq (%0,%3),%%xmm7 \n"
- "lea (%0,%3,2),%0 \n"
- "punpcklbw %%xmm7,%%xmm6 \n"
- "neg %3 \n"
- "movdqa %%xmm6,%%xmm7 \n"
- "lea 0x8(%0,%3,8),%0 \n"
- "palignr $0x8,%%xmm7,%%xmm7 \n"
- "neg %3 \n"
- // Second round of bit swap.
- "punpcklwd %%xmm2,%%xmm0 \n"
- "punpcklwd %%xmm3,%%xmm1 \n"
- "movdqa %%xmm0,%%xmm2 \n"
- "movdqa %%xmm1,%%xmm3 \n"
- "palignr $0x8,%%xmm2,%%xmm2 \n"
- "palignr $0x8,%%xmm3,%%xmm3 \n"
- "punpcklwd %%xmm6,%%xmm4 \n"
- "punpcklwd %%xmm7,%%xmm5 \n"
- "movdqa %%xmm4,%%xmm6 \n"
- "movdqa %%xmm5,%%xmm7 \n"
- "palignr $0x8,%%xmm6,%%xmm6 \n"
- "palignr $0x8,%%xmm7,%%xmm7 \n"
- // Third round of bit swap.
- // Write to the destination pointer.
- "punpckldq %%xmm4,%%xmm0 \n"
- "movq %%xmm0,(%1) \n"
- "movdqa %%xmm0,%%xmm4 \n"
- "palignr $0x8,%%xmm4,%%xmm4 \n"
- "movq %%xmm4,(%1,%4) \n"
- "lea (%1,%4,2),%1 \n"
- "punpckldq %%xmm6,%%xmm2 \n"
- "movdqa %%xmm2,%%xmm6 \n"
- "movq %%xmm2,(%1) \n"
- "palignr $0x8,%%xmm6,%%xmm6 \n"
- "punpckldq %%xmm5,%%xmm1 \n"
- "movq %%xmm6,(%1,%4) \n"
- "lea (%1,%4,2),%1 \n"
- "movdqa %%xmm1,%%xmm5 \n"
- "movq %%xmm1,(%1) \n"
- "palignr $0x8,%%xmm5,%%xmm5 \n"
- "movq %%xmm5,(%1,%4) \n"
- "lea (%1,%4,2),%1 \n"
- "punpckldq %%xmm7,%%xmm3 \n"
- "movq %%xmm3,(%1) \n"
- "movdqa %%xmm3,%%xmm7 \n"
- "palignr $0x8,%%xmm7,%%xmm7 \n"
- "sub $0x8,%2 \n"
- "movq %%xmm7,(%1,%4) \n"
- "lea (%1,%4,2),%1 \n"
- "jg 1b \n"
- : "+r"(src), // %0
- "+r"(dst), // %1
- "+r"(width) // %2
- : "r"((intptr_t)(src_stride)), // %3
- "r"((intptr_t)(dst_stride)) // %4
- : "memory", "cc"
- #if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
- #endif
- );
-}
-
-#if !defined(LIBYUV_DISABLE_X86) && defined(__i386__)
-#define HAS_TRANSPOSE_UVWX8_SSE2
-extern "C" void TransposeUVWx8_SSE2(const uint8* src, int src_stride,
- uint8* dst_a, int dst_stride_a,
- uint8* dst_b, int dst_stride_b,
- int w);
- asm (
- DECLARE_FUNCTION(TransposeUVWx8_SSE2)
- "push %ebx \n"
- "push %esi \n"
- "push %edi \n"
- "push %ebp \n"
- "mov 0x14(%esp),%eax \n"
- "mov 0x18(%esp),%edi \n"
- "mov 0x1c(%esp),%edx \n"
- "mov 0x20(%esp),%esi \n"
- "mov 0x24(%esp),%ebx \n"
- "mov 0x28(%esp),%ebp \n"
- "mov %esp,%ecx \n"
- "sub $0x14,%esp \n"
- "and $0xfffffff0,%esp \n"
- "mov %ecx,0x10(%esp) \n"
- "mov 0x2c(%ecx),%ecx \n"
-
-"1: \n"
- "movdqa (%eax),%xmm0 \n"
- "movdqa (%eax,%edi,1),%xmm1 \n"
- "lea (%eax,%edi,2),%eax \n"
- "movdqa %xmm0,%xmm7 \n"
- "punpcklbw %xmm1,%xmm0 \n"
- "punpckhbw %xmm1,%xmm7 \n"
- "movdqa %xmm7,%xmm1 \n"
- "movdqa (%eax),%xmm2 \n"
- "movdqa (%eax,%edi,1),%xmm3 \n"
- "lea (%eax,%edi,2),%eax \n"
- "movdqa %xmm2,%xmm7 \n"
- "punpcklbw %xmm3,%xmm2 \n"
- "punpckhbw %xmm3,%xmm7 \n"
- "movdqa %xmm7,%xmm3 \n"
- "movdqa (%eax),%xmm4 \n"
- "movdqa (%eax,%edi,1),%xmm5 \n"
- "lea (%eax,%edi,2),%eax \n"
- "movdqa %xmm4,%xmm7 \n"
- "punpcklbw %xmm5,%xmm4 \n"
- "punpckhbw %xmm5,%xmm7 \n"
- "movdqa %xmm7,%xmm5 \n"
- "movdqa (%eax),%xmm6 \n"
- "movdqa (%eax,%edi,1),%xmm7 \n"
- "lea (%eax,%edi,2),%eax \n"
- "movdqa %xmm5,(%esp) \n"
- "neg %edi \n"
- "movdqa %xmm6,%xmm5 \n"
- "punpcklbw %xmm7,%xmm6 \n"
- "punpckhbw %xmm7,%xmm5 \n"
- "movdqa %xmm5,%xmm7 \n"
- "lea 0x10(%eax,%edi,8),%eax \n"
- "neg %edi \n"
- "movdqa %xmm0,%xmm5 \n"
- "punpcklwd %xmm2,%xmm0 \n"
- "punpckhwd %xmm2,%xmm5 \n"
- "movdqa %xmm5,%xmm2 \n"
- "movdqa %xmm1,%xmm5 \n"
- "punpcklwd %xmm3,%xmm1 \n"
- "punpckhwd %xmm3,%xmm5 \n"
- "movdqa %xmm5,%xmm3 \n"
- "movdqa %xmm4,%xmm5 \n"
- "punpcklwd %xmm6,%xmm4 \n"
- "punpckhwd %xmm6,%xmm5 \n"
- "movdqa %xmm5,%xmm6 \n"
- "movdqa (%esp),%xmm5 \n"
- "movdqa %xmm6,(%esp) \n"
- "movdqa %xmm5,%xmm6 \n"
- "punpcklwd %xmm7,%xmm5 \n"
- "punpckhwd %xmm7,%xmm6 \n"
- "movdqa %xmm6,%xmm7 \n"
- "movdqa %xmm0,%xmm6 \n"
- "punpckldq %xmm4,%xmm0 \n"
- "punpckhdq %xmm4,%xmm6 \n"
- "movdqa %xmm6,%xmm4 \n"
- "movdqa (%esp),%xmm6 \n"
- "movlpd %xmm0,(%edx) \n"
- "movhpd %xmm0,(%ebx) \n"
- "movlpd %xmm4,(%edx,%esi,1) \n"
- "lea (%edx,%esi,2),%edx \n"
- "movhpd %xmm4,(%ebx,%ebp,1) \n"
- "lea (%ebx,%ebp,2),%ebx \n"
- "movdqa %xmm2,%xmm0 \n"
- "punpckldq %xmm6,%xmm2 \n"
- "movlpd %xmm2,(%edx) \n"
- "movhpd %xmm2,(%ebx) \n"
- "punpckhdq %xmm6,%xmm0 \n"
- "movlpd %xmm0,(%edx,%esi,1) \n"
- "lea (%edx,%esi,2),%edx \n"
- "movhpd %xmm0,(%ebx,%ebp,1) \n"
- "lea (%ebx,%ebp,2),%ebx \n"
- "movdqa %xmm1,%xmm0 \n"
- "punpckldq %xmm5,%xmm1 \n"
- "movlpd %xmm1,(%edx) \n"
- "movhpd %xmm1,(%ebx) \n"
- "punpckhdq %xmm5,%xmm0 \n"
- "movlpd %xmm0,(%edx,%esi,1) \n"
- "lea (%edx,%esi,2),%edx \n"
- "movhpd %xmm0,(%ebx,%ebp,1) \n"
- "lea (%ebx,%ebp,2),%ebx \n"
- "movdqa %xmm3,%xmm0 \n"
- "punpckldq %xmm7,%xmm3 \n"
- "movlpd %xmm3,(%edx) \n"
- "movhpd %xmm3,(%ebx) \n"
- "punpckhdq %xmm7,%xmm0 \n"
- "sub $0x8,%ecx \n"
- "movlpd %xmm0,(%edx,%esi,1) \n"
- "lea (%edx,%esi,2),%edx \n"
- "movhpd %xmm0,(%ebx,%ebp,1) \n"
- "lea (%ebx,%ebp,2),%ebx \n"
- "jg 1b \n"
- "mov 0x10(%esp),%esp \n"
- "pop %ebp \n"
- "pop %edi \n"
- "pop %esi \n"
- "pop %ebx \n"
-#if defined(__native_client__)
- "pop %ecx \n"
- "and $0xffffffe0,%ecx \n"
- "jmp *%ecx \n"
-#else
- "ret \n"
-#endif
-);
-#elif !defined(LIBYUV_DISABLE_X86) && !defined(__native_client__) && \
- defined(__x86_64__)
-// 64 bit version has enough registers to do 16x8 to 8x16 at a time.
-#define HAS_TRANSPOSE_WX8_FAST_SSSE3
-static void TransposeWx8_FAST_SSSE3(const uint8* src, int src_stride,
- uint8* dst, int dst_stride, int width) {
- asm volatile (
- // Read in the data from the source pointer.
- // First round of bit swap.
- ".p2align 2 \n"
-"1: \n"
- "movdqa (%0),%%xmm0 \n"
- "movdqa (%0,%3),%%xmm1 \n"
- "lea (%0,%3,2),%0 \n"
- "movdqa %%xmm0,%%xmm8 \n"
- "punpcklbw %%xmm1,%%xmm0 \n"
- "punpckhbw %%xmm1,%%xmm8 \n"
- "movdqa (%0),%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "movdqa %%xmm8,%%xmm9 \n"
- "palignr $0x8,%%xmm1,%%xmm1 \n"
- "palignr $0x8,%%xmm9,%%xmm9 \n"
- "movdqa (%0,%3),%%xmm3 \n"
- "lea (%0,%3,2),%0 \n"
- "movdqa %%xmm2,%%xmm10 \n"
- "punpcklbw %%xmm3,%%xmm2 \n"
- "punpckhbw %%xmm3,%%xmm10 \n"
- "movdqa %%xmm2,%%xmm3 \n"
- "movdqa %%xmm10,%%xmm11 \n"
- "movdqa (%0),%%xmm4 \n"
- "palignr $0x8,%%xmm3,%%xmm3 \n"
- "palignr $0x8,%%xmm11,%%xmm11 \n"
- "movdqa (%0,%3),%%xmm5 \n"
- "lea (%0,%3,2),%0 \n"
- "movdqa %%xmm4,%%xmm12 \n"
- "punpcklbw %%xmm5,%%xmm4 \n"
- "punpckhbw %%xmm5,%%xmm12 \n"
- "movdqa %%xmm4,%%xmm5 \n"
- "movdqa %%xmm12,%%xmm13 \n"
- "movdqa (%0),%%xmm6 \n"
- "palignr $0x8,%%xmm5,%%xmm5 \n"
- "palignr $0x8,%%xmm13,%%xmm13 \n"
- "movdqa (%0,%3),%%xmm7 \n"
- "lea (%0,%3,2),%0 \n"
- "movdqa %%xmm6,%%xmm14 \n"
- "punpcklbw %%xmm7,%%xmm6 \n"
- "punpckhbw %%xmm7,%%xmm14 \n"
- "neg %3 \n"
- "movdqa %%xmm6,%%xmm7 \n"
- "movdqa %%xmm14,%%xmm15 \n"
- "lea 0x10(%0,%3,8),%0 \n"
- "palignr $0x8,%%xmm7,%%xmm7 \n"
- "palignr $0x8,%%xmm15,%%xmm15 \n"
- "neg %3 \n"
- // Second round of bit swap.
- "punpcklwd %%xmm2,%%xmm0 \n"
- "punpcklwd %%xmm3,%%xmm1 \n"
- "movdqa %%xmm0,%%xmm2 \n"
- "movdqa %%xmm1,%%xmm3 \n"
- "palignr $0x8,%%xmm2,%%xmm2 \n"
- "palignr $0x8,%%xmm3,%%xmm3 \n"
- "punpcklwd %%xmm6,%%xmm4 \n"
- "punpcklwd %%xmm7,%%xmm5 \n"
- "movdqa %%xmm4,%%xmm6 \n"
- "movdqa %%xmm5,%%xmm7 \n"
- "palignr $0x8,%%xmm6,%%xmm6 \n"
- "palignr $0x8,%%xmm7,%%xmm7 \n"
- "punpcklwd %%xmm10,%%xmm8 \n"
- "punpcklwd %%xmm11,%%xmm9 \n"
- "movdqa %%xmm8,%%xmm10 \n"
- "movdqa %%xmm9,%%xmm11 \n"
- "palignr $0x8,%%xmm10,%%xmm10 \n"
- "palignr $0x8,%%xmm11,%%xmm11 \n"
- "punpcklwd %%xmm14,%%xmm12 \n"
- "punpcklwd %%xmm15,%%xmm13 \n"
- "movdqa %%xmm12,%%xmm14 \n"
- "movdqa %%xmm13,%%xmm15 \n"
- "palignr $0x8,%%xmm14,%%xmm14 \n"
- "palignr $0x8,%%xmm15,%%xmm15 \n"
- // Third round of bit swap.
- // Write to the destination pointer.
- "punpckldq %%xmm4,%%xmm0 \n"
- "movq %%xmm0,(%1) \n"
- "movdqa %%xmm0,%%xmm4 \n"
- "palignr $0x8,%%xmm4,%%xmm4 \n"
- "movq %%xmm4,(%1,%4) \n"
- "lea (%1,%4,2),%1 \n"
- "punpckldq %%xmm6,%%xmm2 \n"
- "movdqa %%xmm2,%%xmm6 \n"
- "movq %%xmm2,(%1) \n"
- "palignr $0x8,%%xmm6,%%xmm6 \n"
- "punpckldq %%xmm5,%%xmm1 \n"
- "movq %%xmm6,(%1,%4) \n"
- "lea (%1,%4,2),%1 \n"
- "movdqa %%xmm1,%%xmm5 \n"
- "movq %%xmm1,(%1) \n"
- "palignr $0x8,%%xmm5,%%xmm5 \n"
- "movq %%xmm5,(%1,%4) \n"
- "lea (%1,%4,2),%1 \n"
- "punpckldq %%xmm7,%%xmm3 \n"
- "movq %%xmm3,(%1) \n"
- "movdqa %%xmm3,%%xmm7 \n"
- "palignr $0x8,%%xmm7,%%xmm7 \n"
- "movq %%xmm7,(%1,%4) \n"
- "lea (%1,%4,2),%1 \n"
- "punpckldq %%xmm12,%%xmm8 \n"
- "movq %%xmm8,(%1) \n"
- "movdqa %%xmm8,%%xmm12 \n"
- "palignr $0x8,%%xmm12,%%xmm12 \n"
- "movq %%xmm12,(%1,%4) \n"
- "lea (%1,%4,2),%1 \n"
- "punpckldq %%xmm14,%%xmm10 \n"
- "movdqa %%xmm10,%%xmm14 \n"
- "movq %%xmm10,(%1) \n"
- "palignr $0x8,%%xmm14,%%xmm14 \n"
- "punpckldq %%xmm13,%%xmm9 \n"
- "movq %%xmm14,(%1,%4) \n"
- "lea (%1,%4,2),%1 \n"
- "movdqa %%xmm9,%%xmm13 \n"
- "movq %%xmm9,(%1) \n"
- "palignr $0x8,%%xmm13,%%xmm13 \n"
- "movq %%xmm13,(%1,%4) \n"
- "lea (%1,%4,2),%1 \n"
- "punpckldq %%xmm15,%%xmm11 \n"
- "movq %%xmm11,(%1) \n"
- "movdqa %%xmm11,%%xmm15 \n"
- "palignr $0x8,%%xmm15,%%xmm15 \n"
- "sub $0x10,%2 \n"
- "movq %%xmm15,(%1,%4) \n"
- "lea (%1,%4,2),%1 \n"
- "jg 1b \n"
- : "+r"(src), // %0
- "+r"(dst), // %1
- "+r"(width) // %2
- : "r"((intptr_t)(src_stride)), // %3
- "r"((intptr_t)(dst_stride)) // %4
- : "memory", "cc",
- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
- "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
-);
-}
-
-#define HAS_TRANSPOSE_UVWX8_SSE2
-static void TransposeUVWx8_SSE2(const uint8* src, int src_stride,
- uint8* dst_a, int dst_stride_a,
- uint8* dst_b, int dst_stride_b,
- int w) {
- asm volatile (
- // Read in the data from the source pointer.
- // First round of bit swap.
- ".p2align 2 \n"
-"1: \n"
- "movdqa (%0),%%xmm0 \n"
- "movdqa (%0,%4),%%xmm1 \n"
- "lea (%0,%4,2),%0 \n"
- "movdqa %%xmm0,%%xmm8 \n"
- "punpcklbw %%xmm1,%%xmm0 \n"
- "punpckhbw %%xmm1,%%xmm8 \n"
- "movdqa %%xmm8,%%xmm1 \n"
- "movdqa (%0),%%xmm2 \n"
- "movdqa (%0,%4),%%xmm3 \n"
- "lea (%0,%4,2),%0 \n"
- "movdqa %%xmm2,%%xmm8 \n"
- "punpcklbw %%xmm3,%%xmm2 \n"
- "punpckhbw %%xmm3,%%xmm8 \n"
- "movdqa %%xmm8,%%xmm3 \n"
- "movdqa (%0),%%xmm4 \n"
- "movdqa (%0,%4),%%xmm5 \n"
- "lea (%0,%4,2),%0 \n"
- "movdqa %%xmm4,%%xmm8 \n"
- "punpcklbw %%xmm5,%%xmm4 \n"
- "punpckhbw %%xmm5,%%xmm8 \n"
- "movdqa %%xmm8,%%xmm5 \n"
- "movdqa (%0),%%xmm6 \n"
- "movdqa (%0,%4),%%xmm7 \n"
- "lea (%0,%4,2),%0 \n"
- "movdqa %%xmm6,%%xmm8 \n"
- "punpcklbw %%xmm7,%%xmm6 \n"
- "neg %4 \n"
- "lea 0x10(%0,%4,8),%0 \n"
- "punpckhbw %%xmm7,%%xmm8 \n"
- "movdqa %%xmm8,%%xmm7 \n"
- "neg %4 \n"
- // Second round of bit swap.
- "movdqa %%xmm0,%%xmm8 \n"
- "movdqa %%xmm1,%%xmm9 \n"
- "punpckhwd %%xmm2,%%xmm8 \n"
- "punpckhwd %%xmm3,%%xmm9 \n"
- "punpcklwd %%xmm2,%%xmm0 \n"
- "punpcklwd %%xmm3,%%xmm1 \n"
- "movdqa %%xmm8,%%xmm2 \n"
- "movdqa %%xmm9,%%xmm3 \n"
- "movdqa %%xmm4,%%xmm8 \n"
- "movdqa %%xmm5,%%xmm9 \n"
- "punpckhwd %%xmm6,%%xmm8 \n"
- "punpckhwd %%xmm7,%%xmm9 \n"
- "punpcklwd %%xmm6,%%xmm4 \n"
- "punpcklwd %%xmm7,%%xmm5 \n"
- "movdqa %%xmm8,%%xmm6 \n"
- "movdqa %%xmm9,%%xmm7 \n"
- // Third round of bit swap.
- // Write to the destination pointer.
- "movdqa %%xmm0,%%xmm8 \n"
- "punpckldq %%xmm4,%%xmm0 \n"
- "movlpd %%xmm0,(%1) \n" // Write back U channel
- "movhpd %%xmm0,(%2) \n" // Write back V channel
- "punpckhdq %%xmm4,%%xmm8 \n"
- "movlpd %%xmm8,(%1,%5) \n"
- "lea (%1,%5,2),%1 \n"
- "movhpd %%xmm8,(%2,%6) \n"
- "lea (%2,%6,2),%2 \n"
- "movdqa %%xmm2,%%xmm8 \n"
- "punpckldq %%xmm6,%%xmm2 \n"
- "movlpd %%xmm2,(%1) \n"
- "movhpd %%xmm2,(%2) \n"
- "punpckhdq %%xmm6,%%xmm8 \n"
- "movlpd %%xmm8,(%1,%5) \n"
- "lea (%1,%5,2),%1 \n"
- "movhpd %%xmm8,(%2,%6) \n"
- "lea (%2,%6,2),%2 \n"
- "movdqa %%xmm1,%%xmm8 \n"
- "punpckldq %%xmm5,%%xmm1 \n"
- "movlpd %%xmm1,(%1) \n"
- "movhpd %%xmm1,(%2) \n"
- "punpckhdq %%xmm5,%%xmm8 \n"
- "movlpd %%xmm8,(%1,%5) \n"
- "lea (%1,%5,2),%1 \n"
- "movhpd %%xmm8,(%2,%6) \n"
- "lea (%2,%6,2),%2 \n"
- "movdqa %%xmm3,%%xmm8 \n"
- "punpckldq %%xmm7,%%xmm3 \n"
- "movlpd %%xmm3,(%1) \n"
- "movhpd %%xmm3,(%2) \n"
- "punpckhdq %%xmm7,%%xmm8 \n"
- "sub $0x8,%3 \n"
- "movlpd %%xmm8,(%1,%5) \n"
- "lea (%1,%5,2),%1 \n"
- "movhpd %%xmm8,(%2,%6) \n"
- "lea (%2,%6,2),%2 \n"
- "jg 1b \n"
- : "+r"(src), // %0
- "+r"(dst_a), // %1
- "+r"(dst_b), // %2
- "+r"(w) // %3
- : "r"((intptr_t)(src_stride)), // %4
- "r"((intptr_t)(dst_stride_a)), // %5
- "r"((intptr_t)(dst_stride_b)) // %6
- : "memory", "cc",
- "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
- "xmm8", "xmm9"
-);
-}
-#endif
-#endif
-
-static void TransposeWx8_C(const uint8* src, int src_stride,
- uint8* dst, int dst_stride,
- int width) {
- int i;
- for (i = 0; i < width; ++i) {
- dst[0] = src[0 * src_stride];
- dst[1] = src[1 * src_stride];
- dst[2] = src[2 * src_stride];
- dst[3] = src[3 * src_stride];
- dst[4] = src[4 * src_stride];
- dst[5] = src[5 * src_stride];
- dst[6] = src[6 * src_stride];
- dst[7] = src[7 * src_stride];
- ++src;
- dst += dst_stride;
- }
-}
-
-static void TransposeWxH_C(const uint8* src, int src_stride,
- uint8* dst, int dst_stride,
- int width, int height) {
- int i;
- for (i = 0; i < width; ++i) {
- int j;
- for (j = 0; j < height; ++j) {
- dst[i * dst_stride + j] = src[j * src_stride + i];
- }
- }
-}
-
-LIBYUV_API
-void TransposePlane(const uint8* src, int src_stride,
- uint8* dst, int dst_stride,
- int width, int height) {
- int i = height;
- void (*TransposeWx8)(const uint8* src, int src_stride,
- uint8* dst, int dst_stride,
- int width) = TransposeWx8_C;
-#if defined(HAS_TRANSPOSE_WX8_NEON)
- if (TestCpuFlag(kCpuHasNEON)) {
- TransposeWx8 = TransposeWx8_NEON;
- }
-#endif
-#if defined(HAS_TRANSPOSE_WX8_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 8)) {
- TransposeWx8 = TransposeWx8_SSSE3;
- }
-#endif
-#if defined(HAS_TRANSPOSE_WX8_FAST_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) &&
- IS_ALIGNED(width, 16) &&
- IS_ALIGNED(src, 16) && IS_ALIGNED(src_stride, 16)) {
- TransposeWx8 = TransposeWx8_FAST_SSSE3;
- }
-#endif
-#if defined(HAS_TRANSPOSE_WX8_MIPS_DSPR2)
- if (TestCpuFlag(kCpuHasMIPS_DSPR2)) {
- if (IS_ALIGNED(width, 4) &&
- IS_ALIGNED(src, 4) && IS_ALIGNED(src_stride, 4)) {
- TransposeWx8 = TransposeWx8_FAST_MIPS_DSPR2;
- } else {
- TransposeWx8 = TransposeWx8_MIPS_DSPR2;
- }
- }
-#endif
-
- // Work across the source in 8x8 tiles
- while (i >= 8) {
- TransposeWx8(src, src_stride, dst, dst_stride, width);
- src += 8 * src_stride; // Go down 8 rows.
- dst += 8; // Move over 8 columns.
- i -= 8;
- }
-
- TransposeWxH_C(src, src_stride, dst, dst_stride, width, i);
-}
-
-LIBYUV_API
-void RotatePlane90(const uint8* src, int src_stride,
- uint8* dst, int dst_stride,
- int width, int height) {
- // Rotate by 90 is a transpose with the source read
- // from bottom to top. So set the source pointer to the end
- // of the buffer and flip the sign of the source stride.
- src += src_stride * (height - 1);
- src_stride = -src_stride;
- TransposePlane(src, src_stride, dst, dst_stride, width, height);
-}
-
-LIBYUV_API
-void RotatePlane270(const uint8* src, int src_stride,
- uint8* dst, int dst_stride,
- int width, int height) {
- // Rotate by 270 is a transpose with the destination written
- // from bottom to top. So set the destination pointer to the end
- // of the buffer and flip the sign of the destination stride.
- dst += dst_stride * (width - 1);
- dst_stride = -dst_stride;
- TransposePlane(src, src_stride, dst, dst_stride, width, height);
-}
-
-LIBYUV_API
-void RotatePlane180(const uint8* src, int src_stride,
- uint8* dst, int dst_stride,
- int width, int height) {
- // Swap first and last row and mirror the content. Uses a temporary row.
- align_buffer_64(row, width);
- const uint8* src_bot = src + src_stride * (height - 1);
- uint8* dst_bot = dst + dst_stride * (height - 1);
- int half_height = (height + 1) >> 1;
- int y;
- void (*MirrorRow)(const uint8* src, uint8* dst, int width) = MirrorRow_C;
- void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
-#if defined(HAS_MIRRORROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 16)) {
- MirrorRow = MirrorRow_NEON;
- }
-#endif
-#if defined(HAS_MIRRORROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 16) &&
- IS_ALIGNED(src, 16) && IS_ALIGNED(src_stride, 16) &&
- IS_ALIGNED(dst, 16) && IS_ALIGNED(dst_stride, 16)) {
- MirrorRow = MirrorRow_SSE2;
- }
-#endif
-#if defined(HAS_MIRRORROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 16) &&
- IS_ALIGNED(src, 16) && IS_ALIGNED(src_stride, 16) &&
- IS_ALIGNED(dst, 16) && IS_ALIGNED(dst_stride, 16)) {
- MirrorRow = MirrorRow_SSSE3;
- }
-#endif
-#if defined(HAS_MIRRORROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && IS_ALIGNED(width, 32)) {
- MirrorRow = MirrorRow_AVX2;
- }
-#endif
-#if defined(HAS_MIRRORROW_MIPS_DSPR2)
- if (TestCpuFlag(kCpuHasMIPS_DSPR2) &&
- IS_ALIGNED(src, 4) && IS_ALIGNED(src_stride, 4) &&
- IS_ALIGNED(dst, 4) && IS_ALIGNED(dst_stride, 4)) {
- MirrorRow = MirrorRow_MIPS_DSPR2;
- }
-#endif
-#if defined(HAS_COPYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 32)) {
- CopyRow = CopyRow_NEON;
- }
-#endif
-#if defined(HAS_COPYROW_X86)
- if (TestCpuFlag(kCpuHasX86) && IS_ALIGNED(width, 4)) {
- CopyRow = CopyRow_X86;
- }
-#endif
-#if defined(HAS_COPYROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 32) &&
- IS_ALIGNED(src, 16) && IS_ALIGNED(src_stride, 16) &&
- IS_ALIGNED(dst, 16) && IS_ALIGNED(dst_stride, 16)) {
- CopyRow = CopyRow_SSE2;
- }
-#endif
-#if defined(HAS_COPYROW_ERMS)
- if (TestCpuFlag(kCpuHasERMS)) {
- CopyRow = CopyRow_ERMS;
- }
-#endif
-#if defined(HAS_COPYROW_MIPS)
- if (TestCpuFlag(kCpuHasMIPS)) {
- CopyRow = CopyRow_MIPS;
- }
-#endif
-
- // Odd height will harmlessly mirror the middle row twice.
- for (y = 0; y < half_height; ++y) {
- MirrorRow(src, row, width); // Mirror first row into a buffer
- src += src_stride;
- MirrorRow(src_bot, dst, width); // Mirror last row into first row
- dst += dst_stride;
- CopyRow(row, dst_bot, width); // Copy first mirrored row into last
- src_bot -= src_stride;
- dst_bot -= dst_stride;
- }
- free_aligned_buffer_64(row);
-}
-
-static void TransposeUVWx8_C(const uint8* src, int src_stride,
- uint8* dst_a, int dst_stride_a,
- uint8* dst_b, int dst_stride_b,
- int width) {
- int i;
- for (i = 0; i < width; ++i) {
- dst_a[0] = src[0 * src_stride + 0];
- dst_b[0] = src[0 * src_stride + 1];
- dst_a[1] = src[1 * src_stride + 0];
- dst_b[1] = src[1 * src_stride + 1];
- dst_a[2] = src[2 * src_stride + 0];
- dst_b[2] = src[2 * src_stride + 1];
- dst_a[3] = src[3 * src_stride + 0];
- dst_b[3] = src[3 * src_stride + 1];
- dst_a[4] = src[4 * src_stride + 0];
- dst_b[4] = src[4 * src_stride + 1];
- dst_a[5] = src[5 * src_stride + 0];
- dst_b[5] = src[5 * src_stride + 1];
- dst_a[6] = src[6 * src_stride + 0];
- dst_b[6] = src[6 * src_stride + 1];
- dst_a[7] = src[7 * src_stride + 0];
- dst_b[7] = src[7 * src_stride + 1];
- src += 2;
- dst_a += dst_stride_a;
- dst_b += dst_stride_b;
- }
-}
-
-static void TransposeUVWxH_C(const uint8* src, int src_stride,
- uint8* dst_a, int dst_stride_a,
- uint8* dst_b, int dst_stride_b,
- int width, int height) {
- int i;
- for (i = 0; i < width * 2; i += 2) {
- int j;
- for (j = 0; j < height; ++j) {
- dst_a[j + ((i >> 1) * dst_stride_a)] = src[i + (j * src_stride)];
- dst_b[j + ((i >> 1) * dst_stride_b)] = src[i + (j * src_stride) + 1];
- }
- }
-}
-
-LIBYUV_API
-void TransposeUV(const uint8* src, int src_stride,
- uint8* dst_a, int dst_stride_a,
- uint8* dst_b, int dst_stride_b,
- int width, int height) {
- int i = height;
- void (*TransposeUVWx8)(const uint8* src, int src_stride,
- uint8* dst_a, int dst_stride_a,
- uint8* dst_b, int dst_stride_b,
- int width) = TransposeUVWx8_C;
-#if defined(HAS_TRANSPOSE_UVWX8_NEON)
- if (TestCpuFlag(kCpuHasNEON)) {
- TransposeUVWx8 = TransposeUVWx8_NEON;
- }
-#elif defined(HAS_TRANSPOSE_UVWX8_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) &&
- IS_ALIGNED(width, 8) &&
- IS_ALIGNED(src, 16) && IS_ALIGNED(src_stride, 16)) {
- TransposeUVWx8 = TransposeUVWx8_SSE2;
- }
-#elif defined(HAS_TRANSPOSE_UVWx8_MIPS_DSPR2)
- if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(width, 2) &&
- IS_ALIGNED(src, 4) && IS_ALIGNED(src_stride, 4)) {
- TransposeUVWx8 = TransposeUVWx8_MIPS_DSPR2;
- }
-#endif
-
- // Work through the source in 8x8 tiles.
- while (i >= 8) {
- TransposeUVWx8(src, src_stride,
- dst_a, dst_stride_a,
- dst_b, dst_stride_b,
- width);
- src += 8 * src_stride; // Go down 8 rows.
- dst_a += 8; // Move over 8 columns.
- dst_b += 8; // Move over 8 columns.
- i -= 8;
- }
-
- TransposeUVWxH_C(src, src_stride,
- dst_a, dst_stride_a,
- dst_b, dst_stride_b,
- width, i);
-}
-
-LIBYUV_API
-void RotateUV90(const uint8* src, int src_stride,
- uint8* dst_a, int dst_stride_a,
- uint8* dst_b, int dst_stride_b,
- int width, int height) {
- src += src_stride * (height - 1);
- src_stride = -src_stride;
-
- TransposeUV(src, src_stride,
- dst_a, dst_stride_a,
- dst_b, dst_stride_b,
- width, height);
-}
-
-LIBYUV_API
-void RotateUV270(const uint8* src, int src_stride,
- uint8* dst_a, int dst_stride_a,
- uint8* dst_b, int dst_stride_b,
- int width, int height) {
- dst_a += dst_stride_a * (width - 1);
- dst_b += dst_stride_b * (width - 1);
- dst_stride_a = -dst_stride_a;
- dst_stride_b = -dst_stride_b;
-
- TransposeUV(src, src_stride,
- dst_a, dst_stride_a,
- dst_b, dst_stride_b,
- width, height);
-}
-
-// Rotate 180 is a horizontal and vertical flip.
-LIBYUV_API
-void RotateUV180(const uint8* src, int src_stride,
- uint8* dst_a, int dst_stride_a,
- uint8* dst_b, int dst_stride_b,
- int width, int height) {
- int i;
- void (*MirrorRowUV)(const uint8* src, uint8* dst_u, uint8* dst_v, int width) =
- MirrorUVRow_C;
-#if defined(HAS_MIRRORUVROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
- MirrorRowUV = MirrorUVRow_NEON;
- }
-#elif defined(HAS_MIRRORROW_UV_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 16) &&
- IS_ALIGNED(src, 16) && IS_ALIGNED(src_stride, 16)) {
- MirrorRowUV = MirrorUVRow_SSSE3;
- }
-#elif defined(HAS_MIRRORUVROW_MIPS_DSPR2)
- if (TestCpuFlag(kCpuHasMIPS_DSPR2) &&
- IS_ALIGNED(src, 4) && IS_ALIGNED(src_stride, 4)) {
- MirrorRowUV = MirrorUVRow_MIPS_DSPR2;
- }
-#endif
-
- dst_a += dst_stride_a * (height - 1);
- dst_b += dst_stride_b * (height - 1);
-
- for (i = 0; i < height; ++i) {
- MirrorRowUV(src, dst_a, dst_b, width);
- src += src_stride;
- dst_a -= dst_stride_a;
- dst_b -= dst_stride_b;
- }
-}
-
-LIBYUV_API
-int RotatePlane(const uint8* src, int src_stride,
- uint8* dst, int dst_stride,
- int width, int height,
- enum RotationMode mode) {
- if (!src || width <= 0 || height == 0 || !dst) {
- return -1;
- }
-
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src = src + (height - 1) * src_stride;
- src_stride = -src_stride;
- }
-
- switch (mode) {
- case kRotate0:
- // copy frame
- CopyPlane(src, src_stride,
- dst, dst_stride,
- width, height);
- return 0;
- case kRotate90:
- RotatePlane90(src, src_stride,
- dst, dst_stride,
- width, height);
- return 0;
- case kRotate270:
- RotatePlane270(src, src_stride,
- dst, dst_stride,
- width, height);
- return 0;
- case kRotate180:
- RotatePlane180(src, src_stride,
- dst, dst_stride,
- width, height);
- return 0;
- default:
- break;
- }
- return -1;
-}
-
-LIBYUV_API
-int I420Rotate(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height,
- enum RotationMode mode) {
- int halfwidth = (width + 1) >> 1;
- int halfheight = (height + 1) >> 1;
- if (!src_y || !src_u || !src_v || width <= 0 || height == 0 ||
- !dst_y || !dst_u || !dst_v) {
- return -1;
- }
-
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- halfheight = (height + 1) >> 1;
- src_y = src_y + (height - 1) * src_stride_y;
- src_u = src_u + (halfheight - 1) * src_stride_u;
- src_v = src_v + (halfheight - 1) * src_stride_v;
- src_stride_y = -src_stride_y;
- src_stride_u = -src_stride_u;
- src_stride_v = -src_stride_v;
- }
-
- switch (mode) {
- case kRotate0:
- // copy frame
- return I420Copy(src_y, src_stride_y,
- src_u, src_stride_u,
- src_v, src_stride_v,
- dst_y, dst_stride_y,
- dst_u, dst_stride_u,
- dst_v, dst_stride_v,
- width, height);
- case kRotate90:
- RotatePlane90(src_y, src_stride_y,
- dst_y, dst_stride_y,
- width, height);
- RotatePlane90(src_u, src_stride_u,
- dst_u, dst_stride_u,
- halfwidth, halfheight);
- RotatePlane90(src_v, src_stride_v,
- dst_v, dst_stride_v,
- halfwidth, halfheight);
- return 0;
- case kRotate270:
- RotatePlane270(src_y, src_stride_y,
- dst_y, dst_stride_y,
- width, height);
- RotatePlane270(src_u, src_stride_u,
- dst_u, dst_stride_u,
- halfwidth, halfheight);
- RotatePlane270(src_v, src_stride_v,
- dst_v, dst_stride_v,
- halfwidth, halfheight);
- return 0;
- case kRotate180:
- RotatePlane180(src_y, src_stride_y,
- dst_y, dst_stride_y,
- width, height);
- RotatePlane180(src_u, src_stride_u,
- dst_u, dst_stride_u,
- halfwidth, halfheight);
- RotatePlane180(src_v, src_stride_v,
- dst_v, dst_stride_v,
- halfwidth, halfheight);
- return 0;
- default:
- break;
- }
- return -1;
-}
-
-LIBYUV_API
-int NV12ToI420Rotate(const uint8* src_y, int src_stride_y,
- const uint8* src_uv, int src_stride_uv,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int width, int height,
- enum RotationMode mode) {
- int halfwidth = (width + 1) >> 1;
- int halfheight = (height + 1) >> 1;
- if (!src_y || !src_uv || width <= 0 || height == 0 ||
- !dst_y || !dst_u || !dst_v) {
- return -1;
- }
-
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- halfheight = (height + 1) >> 1;
- src_y = src_y + (height - 1) * src_stride_y;
- src_uv = src_uv + (halfheight - 1) * src_stride_uv;
- src_stride_y = -src_stride_y;
- src_stride_uv = -src_stride_uv;
- }
-
- switch (mode) {
- case kRotate0:
- // copy frame
- return NV12ToI420(src_y, src_stride_y,
- src_uv, src_stride_uv,
- dst_y, dst_stride_y,
- dst_u, dst_stride_u,
- dst_v, dst_stride_v,
- width, height);
- case kRotate90:
- RotatePlane90(src_y, src_stride_y,
- dst_y, dst_stride_y,
- width, height);
- RotateUV90(src_uv, src_stride_uv,
- dst_u, dst_stride_u,
- dst_v, dst_stride_v,
- halfwidth, halfheight);
- return 0;
- case kRotate270:
- RotatePlane270(src_y, src_stride_y,
- dst_y, dst_stride_y,
- width, height);
- RotateUV270(src_uv, src_stride_uv,
- dst_u, dst_stride_u,
- dst_v, dst_stride_v,
- halfwidth, halfheight);
- return 0;
- case kRotate180:
- RotatePlane180(src_y, src_stride_y,
- dst_y, dst_stride_y,
- width, height);
- RotateUV180(src_uv, src_stride_uv,
- dst_u, dst_stride_u,
- dst_v, dst_stride_v,
- halfwidth, halfheight);
- return 0;
- default:
- break;
- }
- return -1;
-}
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/rotate_argb.cc b/drivers/theoraplayer/src/YUV/libyuv/src/rotate_argb.cc
deleted file mode 100755
index ab0f9ce070..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/rotate_argb.cc
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright 2012 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/rotate.h"
-
-#include "libyuv/cpu_id.h"
-#include "libyuv/convert.h"
-#include "libyuv/planar_functions.h"
-#include "libyuv/row.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// ARGBScale has a function to copy pixels to a row, striding each source
-// pixel by a constant.
-#if !defined(LIBYUV_DISABLE_X86) && \
- (defined(_M_IX86) || \
- (defined(__x86_64__) && !defined(__native_client__)) || defined(__i386__))
-#define HAS_SCALEARGBROWDOWNEVEN_SSE2
-void ScaleARGBRowDownEven_SSE2(const uint8* src_ptr, int src_stride,
- int src_stepx,
- uint8* dst_ptr, int dst_width);
-#endif
-#if !defined(LIBYUV_DISABLE_NEON) && !defined(__native_client__) && \
- (defined(__ARM_NEON__) || defined(LIBYUV_NEON))
-#define HAS_SCALEARGBROWDOWNEVEN_NEON
-void ScaleARGBRowDownEven_NEON(const uint8* src_ptr, int src_stride,
- int src_stepx,
- uint8* dst_ptr, int dst_width);
-#endif
-
-void ScaleARGBRowDownEven_C(const uint8* src_ptr, int,
- int src_stepx,
- uint8* dst_ptr, int dst_width);
-
-static void ARGBTranspose(const uint8* src, int src_stride,
- uint8* dst, int dst_stride,
- int width, int height) {
- int i;
- int src_pixel_step = src_stride >> 2;
- void (*ScaleARGBRowDownEven)(const uint8* src_ptr, int src_stride,
- int src_step, uint8* dst_ptr, int dst_width) = ScaleARGBRowDownEven_C;
-#if defined(HAS_SCALEARGBROWDOWNEVEN_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(height, 4) && // Width of dest.
- IS_ALIGNED(dst, 16) && IS_ALIGNED(dst_stride, 16)) {
- ScaleARGBRowDownEven = ScaleARGBRowDownEven_SSE2;
- }
-#elif defined(HAS_SCALEARGBROWDOWNEVEN_NEON)
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(height, 4) && // Width of dest.
- IS_ALIGNED(src, 4)) {
- ScaleARGBRowDownEven = ScaleARGBRowDownEven_NEON;
- }
-#endif
-
- for (i = 0; i < width; ++i) { // column of source to row of dest.
- ScaleARGBRowDownEven(src, 0, src_pixel_step, dst, height);
- dst += dst_stride;
- src += 4;
- }
-}
-
-void ARGBRotate90(const uint8* src, int src_stride,
- uint8* dst, int dst_stride,
- int width, int height) {
- // Rotate by 90 is a ARGBTranspose with the source read
- // from bottom to top. So set the source pointer to the end
- // of the buffer and flip the sign of the source stride.
- src += src_stride * (height - 1);
- src_stride = -src_stride;
- ARGBTranspose(src, src_stride, dst, dst_stride, width, height);
-}
-
-void ARGBRotate270(const uint8* src, int src_stride,
- uint8* dst, int dst_stride,
- int width, int height) {
- // Rotate by 270 is a ARGBTranspose with the destination written
- // from bottom to top. So set the destination pointer to the end
- // of the buffer and flip the sign of the destination stride.
- dst += dst_stride * (width - 1);
- dst_stride = -dst_stride;
- ARGBTranspose(src, src_stride, dst, dst_stride, width, height);
-}
-
-void ARGBRotate180(const uint8* src, int src_stride,
- uint8* dst, int dst_stride,
- int width, int height) {
- // Swap first and last row and mirror the content. Uses a temporary row.
- align_buffer_64(row, width * 4);
- const uint8* src_bot = src + src_stride * (height - 1);
- uint8* dst_bot = dst + dst_stride * (height - 1);
- int half_height = (height + 1) >> 1;
- int y;
- void (*ARGBMirrorRow)(const uint8* src, uint8* dst, int width) =
- ARGBMirrorRow_C;
- void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
-#if defined(HAS_ARGBMIRRORROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 4) &&
- IS_ALIGNED(src, 16) && IS_ALIGNED(src_stride, 16) &&
- IS_ALIGNED(dst, 16) && IS_ALIGNED(dst_stride, 16)) {
- ARGBMirrorRow = ARGBMirrorRow_SSSE3;
- }
-#endif
-#if defined(HAS_ARGBMIRRORROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && IS_ALIGNED(width, 8)) {
- ARGBMirrorRow = ARGBMirrorRow_AVX2;
- }
-#endif
-#if defined(HAS_ARGBMIRRORROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 4)) {
- ARGBMirrorRow = ARGBMirrorRow_NEON;
- }
-#endif
-#if defined(HAS_COPYROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width * 4, 32)) {
- CopyRow = CopyRow_NEON;
- }
-#endif
-#if defined(HAS_COPYROW_X86)
- if (TestCpuFlag(kCpuHasX86)) {
- CopyRow = CopyRow_X86;
- }
-#endif
-#if defined(HAS_COPYROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width * 4, 32) &&
- IS_ALIGNED(src, 16) && IS_ALIGNED(src_stride, 16) &&
- IS_ALIGNED(dst, 16) && IS_ALIGNED(dst_stride, 16)) {
- CopyRow = CopyRow_SSE2;
- }
-#endif
-#if defined(HAS_COPYROW_ERMS)
- if (TestCpuFlag(kCpuHasERMS)) {
- CopyRow = CopyRow_ERMS;
- }
-#endif
-#if defined(HAS_COPYROW_MIPS)
- if (TestCpuFlag(kCpuHasMIPS)) {
- CopyRow = CopyRow_MIPS;
- }
-#endif
-
- // Odd height will harmlessly mirror the middle row twice.
- for (y = 0; y < half_height; ++y) {
- ARGBMirrorRow(src, row, width); // Mirror first row into a buffer
- ARGBMirrorRow(src_bot, dst, width); // Mirror last row into first row
- CopyRow(row, dst_bot, width * 4); // Copy first mirrored row into last
- src += src_stride;
- dst += dst_stride;
- src_bot -= src_stride;
- dst_bot -= dst_stride;
- }
- free_aligned_buffer_64(row);
-}
-
-LIBYUV_API
-int ARGBRotate(const uint8* src_argb, int src_stride_argb,
- uint8* dst_argb, int dst_stride_argb,
- int width, int height,
- enum RotationMode mode) {
- if (!src_argb || width <= 0 || height == 0 || !dst_argb) {
- return -1;
- }
-
- // Negative height means invert the image.
- if (height < 0) {
- height = -height;
- src_argb = src_argb + (height - 1) * src_stride_argb;
- src_stride_argb = -src_stride_argb;
- }
-
- switch (mode) {
- case kRotate0:
- // copy frame
- return ARGBCopy(src_argb, src_stride_argb,
- dst_argb, dst_stride_argb,
- width, height);
- case kRotate90:
- ARGBRotate90(src_argb, src_stride_argb,
- dst_argb, dst_stride_argb,
- width, height);
- return 0;
- case kRotate270:
- ARGBRotate270(src_argb, src_stride_argb,
- dst_argb, dst_stride_argb,
- width, height);
- return 0;
- case kRotate180:
- ARGBRotate180(src_argb, src_stride_argb,
- dst_argb, dst_stride_argb,
- width, height);
- return 0;
- default:
- break;
- }
- return -1;
-}
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/rotate_mips.cc b/drivers/theoraplayer/src/YUV/libyuv/src/rotate_mips.cc
deleted file mode 100755
index 04d5a663f7..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/rotate_mips.cc
+++ /dev/null
@@ -1,486 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/row.h"
-
-#include "libyuv/basic_types.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-#if !defined(LIBYUV_DISABLE_MIPS) && \
- defined(__mips_dsp) && (__mips_dsp_rev >= 2)
-
-void TransposeWx8_MIPS_DSPR2(const uint8* src, int src_stride,
- uint8* dst, int dst_stride,
- int width) {
- __asm__ __volatile__ (
- ".set push \n"
- ".set noreorder \n"
- "sll $t2, %[src_stride], 0x1 \n" // src_stride x 2
- "sll $t4, %[src_stride], 0x2 \n" // src_stride x 4
- "sll $t9, %[src_stride], 0x3 \n" // src_stride x 8
- "addu $t3, $t2, %[src_stride] \n"
- "addu $t5, $t4, %[src_stride] \n"
- "addu $t6, $t2, $t4 \n"
- "andi $t0, %[dst], 0x3 \n"
- "andi $t1, %[dst_stride], 0x3 \n"
- "or $t0, $t0, $t1 \n"
- "bnez $t0, 11f \n"
- " subu $t7, $t9, %[src_stride] \n"
-//dst + dst_stride word aligned
- "1: \n"
- "lbu $t0, 0(%[src]) \n"
- "lbux $t1, %[src_stride](%[src]) \n"
- "lbux $t8, $t2(%[src]) \n"
- "lbux $t9, $t3(%[src]) \n"
- "sll $t1, $t1, 16 \n"
- "sll $t9, $t9, 16 \n"
- "or $t0, $t0, $t1 \n"
- "or $t8, $t8, $t9 \n"
- "precr.qb.ph $s0, $t8, $t0 \n"
- "lbux $t0, $t4(%[src]) \n"
- "lbux $t1, $t5(%[src]) \n"
- "lbux $t8, $t6(%[src]) \n"
- "lbux $t9, $t7(%[src]) \n"
- "sll $t1, $t1, 16 \n"
- "sll $t9, $t9, 16 \n"
- "or $t0, $t0, $t1 \n"
- "or $t8, $t8, $t9 \n"
- "precr.qb.ph $s1, $t8, $t0 \n"
- "sw $s0, 0(%[dst]) \n"
- "addiu %[width], -1 \n"
- "addiu %[src], 1 \n"
- "sw $s1, 4(%[dst]) \n"
- "bnez %[width], 1b \n"
- " addu %[dst], %[dst], %[dst_stride] \n"
- "b 2f \n"
-//dst + dst_stride unaligned
- "11: \n"
- "lbu $t0, 0(%[src]) \n"
- "lbux $t1, %[src_stride](%[src]) \n"
- "lbux $t8, $t2(%[src]) \n"
- "lbux $t9, $t3(%[src]) \n"
- "sll $t1, $t1, 16 \n"
- "sll $t9, $t9, 16 \n"
- "or $t0, $t0, $t1 \n"
- "or $t8, $t8, $t9 \n"
- "precr.qb.ph $s0, $t8, $t0 \n"
- "lbux $t0, $t4(%[src]) \n"
- "lbux $t1, $t5(%[src]) \n"
- "lbux $t8, $t6(%[src]) \n"
- "lbux $t9, $t7(%[src]) \n"
- "sll $t1, $t1, 16 \n"
- "sll $t9, $t9, 16 \n"
- "or $t0, $t0, $t1 \n"
- "or $t8, $t8, $t9 \n"
- "precr.qb.ph $s1, $t8, $t0 \n"
- "swr $s0, 0(%[dst]) \n"
- "swl $s0, 3(%[dst]) \n"
- "addiu %[width], -1 \n"
- "addiu %[src], 1 \n"
- "swr $s1, 4(%[dst]) \n"
- "swl $s1, 7(%[dst]) \n"
- "bnez %[width], 11b \n"
- "addu %[dst], %[dst], %[dst_stride] \n"
- "2: \n"
- ".set pop \n"
- :[src] "+r" (src),
- [dst] "+r" (dst),
- [width] "+r" (width)
- :[src_stride] "r" (src_stride),
- [dst_stride] "r" (dst_stride)
- : "t0", "t1", "t2", "t3", "t4", "t5",
- "t6", "t7", "t8", "t9",
- "s0", "s1"
- );
-}
-
-void TransposeWx8_FAST_MIPS_DSPR2(const uint8* src, int src_stride,
- uint8* dst, int dst_stride,
- int width) {
- __asm__ __volatile__ (
- ".set noat \n"
- ".set push \n"
- ".set noreorder \n"
- "beqz %[width], 2f \n"
- " sll $t2, %[src_stride], 0x1 \n" // src_stride x 2
- "sll $t4, %[src_stride], 0x2 \n" // src_stride x 4
- "sll $t9, %[src_stride], 0x3 \n" // src_stride x 8
- "addu $t3, $t2, %[src_stride] \n"
- "addu $t5, $t4, %[src_stride] \n"
- "addu $t6, $t2, $t4 \n"
-
- "srl $AT, %[width], 0x2 \n"
- "andi $t0, %[dst], 0x3 \n"
- "andi $t1, %[dst_stride], 0x3 \n"
- "or $t0, $t0, $t1 \n"
- "bnez $t0, 11f \n"
- " subu $t7, $t9, %[src_stride] \n"
-//dst + dst_stride word aligned
- "1: \n"
- "lw $t0, 0(%[src]) \n"
- "lwx $t1, %[src_stride](%[src]) \n"
- "lwx $t8, $t2(%[src]) \n"
- "lwx $t9, $t3(%[src]) \n"
-
-// t0 = | 30 | 20 | 10 | 00 |
-// t1 = | 31 | 21 | 11 | 01 |
-// t8 = | 32 | 22 | 12 | 02 |
-// t9 = | 33 | 23 | 13 | 03 |
-
- "precr.qb.ph $s0, $t1, $t0 \n"
- "precr.qb.ph $s1, $t9, $t8 \n"
- "precrq.qb.ph $s2, $t1, $t0 \n"
- "precrq.qb.ph $s3, $t9, $t8 \n"
-
- // s0 = | 21 | 01 | 20 | 00 |
- // s1 = | 23 | 03 | 22 | 02 |
- // s2 = | 31 | 11 | 30 | 10 |
- // s3 = | 33 | 13 | 32 | 12 |
-
- "precr.qb.ph $s4, $s1, $s0 \n"
- "precrq.qb.ph $s5, $s1, $s0 \n"
- "precr.qb.ph $s6, $s3, $s2 \n"
- "precrq.qb.ph $s7, $s3, $s2 \n"
-
- // s4 = | 03 | 02 | 01 | 00 |
- // s5 = | 23 | 22 | 21 | 20 |
- // s6 = | 13 | 12 | 11 | 10 |
- // s7 = | 33 | 32 | 31 | 30 |
-
- "lwx $t0, $t4(%[src]) \n"
- "lwx $t1, $t5(%[src]) \n"
- "lwx $t8, $t6(%[src]) \n"
- "lwx $t9, $t7(%[src]) \n"
-
-// t0 = | 34 | 24 | 14 | 04 |
-// t1 = | 35 | 25 | 15 | 05 |
-// t8 = | 36 | 26 | 16 | 06 |
-// t9 = | 37 | 27 | 17 | 07 |
-
- "precr.qb.ph $s0, $t1, $t0 \n"
- "precr.qb.ph $s1, $t9, $t8 \n"
- "precrq.qb.ph $s2, $t1, $t0 \n"
- "precrq.qb.ph $s3, $t9, $t8 \n"
-
- // s0 = | 25 | 05 | 24 | 04 |
- // s1 = | 27 | 07 | 26 | 06 |
- // s2 = | 35 | 15 | 34 | 14 |
- // s3 = | 37 | 17 | 36 | 16 |
-
- "precr.qb.ph $t0, $s1, $s0 \n"
- "precrq.qb.ph $t1, $s1, $s0 \n"
- "precr.qb.ph $t8, $s3, $s2 \n"
- "precrq.qb.ph $t9, $s3, $s2 \n"
-
- // t0 = | 07 | 06 | 05 | 04 |
- // t1 = | 27 | 26 | 25 | 24 |
- // t8 = | 17 | 16 | 15 | 14 |
- // t9 = | 37 | 36 | 35 | 34 |
-
- "addu $s0, %[dst], %[dst_stride] \n"
- "addu $s1, $s0, %[dst_stride] \n"
- "addu $s2, $s1, %[dst_stride] \n"
-
- "sw $s4, 0(%[dst]) \n"
- "sw $t0, 4(%[dst]) \n"
- "sw $s6, 0($s0) \n"
- "sw $t8, 4($s0) \n"
- "sw $s5, 0($s1) \n"
- "sw $t1, 4($s1) \n"
- "sw $s7, 0($s2) \n"
- "sw $t9, 4($s2) \n"
-
- "addiu $AT, -1 \n"
- "addiu %[src], 4 \n"
-
- "bnez $AT, 1b \n"
- " addu %[dst], $s2, %[dst_stride] \n"
- "b 2f \n"
-//dst + dst_stride unaligned
- "11: \n"
- "lw $t0, 0(%[src]) \n"
- "lwx $t1, %[src_stride](%[src]) \n"
- "lwx $t8, $t2(%[src]) \n"
- "lwx $t9, $t3(%[src]) \n"
-
-// t0 = | 30 | 20 | 10 | 00 |
-// t1 = | 31 | 21 | 11 | 01 |
-// t8 = | 32 | 22 | 12 | 02 |
-// t9 = | 33 | 23 | 13 | 03 |
-
- "precr.qb.ph $s0, $t1, $t0 \n"
- "precr.qb.ph $s1, $t9, $t8 \n"
- "precrq.qb.ph $s2, $t1, $t0 \n"
- "precrq.qb.ph $s3, $t9, $t8 \n"
-
- // s0 = | 21 | 01 | 20 | 00 |
- // s1 = | 23 | 03 | 22 | 02 |
- // s2 = | 31 | 11 | 30 | 10 |
- // s3 = | 33 | 13 | 32 | 12 |
-
- "precr.qb.ph $s4, $s1, $s0 \n"
- "precrq.qb.ph $s5, $s1, $s0 \n"
- "precr.qb.ph $s6, $s3, $s2 \n"
- "precrq.qb.ph $s7, $s3, $s2 \n"
-
- // s4 = | 03 | 02 | 01 | 00 |
- // s5 = | 23 | 22 | 21 | 20 |
- // s6 = | 13 | 12 | 11 | 10 |
- // s7 = | 33 | 32 | 31 | 30 |
-
- "lwx $t0, $t4(%[src]) \n"
- "lwx $t1, $t5(%[src]) \n"
- "lwx $t8, $t6(%[src]) \n"
- "lwx $t9, $t7(%[src]) \n"
-
-// t0 = | 34 | 24 | 14 | 04 |
-// t1 = | 35 | 25 | 15 | 05 |
-// t8 = | 36 | 26 | 16 | 06 |
-// t9 = | 37 | 27 | 17 | 07 |
-
- "precr.qb.ph $s0, $t1, $t0 \n"
- "precr.qb.ph $s1, $t9, $t8 \n"
- "precrq.qb.ph $s2, $t1, $t0 \n"
- "precrq.qb.ph $s3, $t9, $t8 \n"
-
- // s0 = | 25 | 05 | 24 | 04 |
- // s1 = | 27 | 07 | 26 | 06 |
- // s2 = | 35 | 15 | 34 | 14 |
- // s3 = | 37 | 17 | 36 | 16 |
-
- "precr.qb.ph $t0, $s1, $s0 \n"
- "precrq.qb.ph $t1, $s1, $s0 \n"
- "precr.qb.ph $t8, $s3, $s2 \n"
- "precrq.qb.ph $t9, $s3, $s2 \n"
-
- // t0 = | 07 | 06 | 05 | 04 |
- // t1 = | 27 | 26 | 25 | 24 |
- // t8 = | 17 | 16 | 15 | 14 |
- // t9 = | 37 | 36 | 35 | 34 |
-
- "addu $s0, %[dst], %[dst_stride] \n"
- "addu $s1, $s0, %[dst_stride] \n"
- "addu $s2, $s1, %[dst_stride] \n"
-
- "swr $s4, 0(%[dst]) \n"
- "swl $s4, 3(%[dst]) \n"
- "swr $t0, 4(%[dst]) \n"
- "swl $t0, 7(%[dst]) \n"
- "swr $s6, 0($s0) \n"
- "swl $s6, 3($s0) \n"
- "swr $t8, 4($s0) \n"
- "swl $t8, 7($s0) \n"
- "swr $s5, 0($s1) \n"
- "swl $s5, 3($s1) \n"
- "swr $t1, 4($s1) \n"
- "swl $t1, 7($s1) \n"
- "swr $s7, 0($s2) \n"
- "swl $s7, 3($s2) \n"
- "swr $t9, 4($s2) \n"
- "swl $t9, 7($s2) \n"
-
- "addiu $AT, -1 \n"
- "addiu %[src], 4 \n"
-
- "bnez $AT, 11b \n"
- " addu %[dst], $s2, %[dst_stride] \n"
- "2: \n"
- ".set pop \n"
- ".set at \n"
- :[src] "+r" (src),
- [dst] "+r" (dst),
- [width] "+r" (width)
- :[src_stride] "r" (src_stride),
- [dst_stride] "r" (dst_stride)
- : "t0", "t1", "t2", "t3", "t4", "t5",
- "t6", "t7", "t8", "t9",
- "s0", "s1", "s2", "s3", "s4",
- "s5", "s6", "s7"
- );
-}
-
-void TransposeUVWx8_MIPS_DSPR2(const uint8* src, int src_stride,
- uint8* dst_a, int dst_stride_a,
- uint8* dst_b, int dst_stride_b,
- int width) {
- __asm__ __volatile__ (
- ".set push \n"
- ".set noreorder \n"
- "beqz %[width], 2f \n"
- " sll $t2, %[src_stride], 0x1 \n" // src_stride x 2
- "sll $t4, %[src_stride], 0x2 \n" // src_stride x 4
- "sll $t9, %[src_stride], 0x3 \n" // src_stride x 8
- "addu $t3, $t2, %[src_stride] \n"
- "addu $t5, $t4, %[src_stride] \n"
- "addu $t6, $t2, $t4 \n"
- "subu $t7, $t9, %[src_stride] \n"
- "srl $t1, %[width], 1 \n"
-
-// check word aligment for dst_a, dst_b, dst_stride_a and dst_stride_b
- "andi $t0, %[dst_a], 0x3 \n"
- "andi $t8, %[dst_b], 0x3 \n"
- "or $t0, $t0, $t8 \n"
- "andi $t8, %[dst_stride_a], 0x3 \n"
- "andi $s5, %[dst_stride_b], 0x3 \n"
- "or $t8, $t8, $s5 \n"
- "or $t0, $t0, $t8 \n"
- "bnez $t0, 11f \n"
- " nop \n"
-// dst + dst_stride word aligned (both, a & b dst addresses)
- "1: \n"
- "lw $t0, 0(%[src]) \n" // |B0|A0|b0|a0|
- "lwx $t8, %[src_stride](%[src]) \n" // |B1|A1|b1|a1|
- "addu $s5, %[dst_a], %[dst_stride_a] \n"
- "lwx $t9, $t2(%[src]) \n" // |B2|A2|b2|a2|
- "lwx $s0, $t3(%[src]) \n" // |B3|A3|b3|a3|
- "addu $s6, %[dst_b], %[dst_stride_b] \n"
-
- "precrq.ph.w $s1, $t8, $t0 \n" // |B1|A1|B0|A0|
- "precrq.ph.w $s2, $s0, $t9 \n" // |B3|A3|B2|A2|
- "precr.qb.ph $s3, $s2, $s1 \n" // |A3|A2|A1|A0|
- "precrq.qb.ph $s4, $s2, $s1 \n" // |B3|B2|B1|B0|
-
- "sll $t0, $t0, 16 \n"
- "packrl.ph $s1, $t8, $t0 \n" // |b1|a1|b0|a0|
- "sll $t9, $t9, 16 \n"
- "packrl.ph $s2, $s0, $t9 \n" // |b3|a3|b2|a2|
-
- "sw $s3, 0($s5) \n"
- "sw $s4, 0($s6) \n"
-
- "precr.qb.ph $s3, $s2, $s1 \n" // |a3|a2|a1|a0|
- "precrq.qb.ph $s4, $s2, $s1 \n" // |b3|b2|b1|b0|
-
- "lwx $t0, $t4(%[src]) \n" // |B4|A4|b4|a4|
- "lwx $t8, $t5(%[src]) \n" // |B5|A5|b5|a5|
- "lwx $t9, $t6(%[src]) \n" // |B6|A6|b6|a6|
- "lwx $s0, $t7(%[src]) \n" // |B7|A7|b7|a7|
- "sw $s3, 0(%[dst_a]) \n"
- "sw $s4, 0(%[dst_b]) \n"
-
- "precrq.ph.w $s1, $t8, $t0 \n" // |B5|A5|B4|A4|
- "precrq.ph.w $s2, $s0, $t9 \n" // |B6|A6|B7|A7|
- "precr.qb.ph $s3, $s2, $s1 \n" // |A7|A6|A5|A4|
- "precrq.qb.ph $s4, $s2, $s1 \n" // |B7|B6|B5|B4|
-
- "sll $t0, $t0, 16 \n"
- "packrl.ph $s1, $t8, $t0 \n" // |b5|a5|b4|a4|
- "sll $t9, $t9, 16 \n"
- "packrl.ph $s2, $s0, $t9 \n" // |b7|a7|b6|a6|
- "sw $s3, 4($s5) \n"
- "sw $s4, 4($s6) \n"
-
- "precr.qb.ph $s3, $s2, $s1 \n" // |a7|a6|a5|a4|
- "precrq.qb.ph $s4, $s2, $s1 \n" // |b7|b6|b5|b4|
-
- "addiu %[src], 4 \n"
- "addiu $t1, -1 \n"
- "sll $t0, %[dst_stride_a], 1 \n"
- "sll $t8, %[dst_stride_b], 1 \n"
- "sw $s3, 4(%[dst_a]) \n"
- "sw $s4, 4(%[dst_b]) \n"
- "addu %[dst_a], %[dst_a], $t0 \n"
- "bnez $t1, 1b \n"
- " addu %[dst_b], %[dst_b], $t8 \n"
- "b 2f \n"
- " nop \n"
-
-// dst_a or dst_b or dst_stride_a or dst_stride_b not word aligned
- "11: \n"
- "lw $t0, 0(%[src]) \n" // |B0|A0|b0|a0|
- "lwx $t8, %[src_stride](%[src]) \n" // |B1|A1|b1|a1|
- "addu $s5, %[dst_a], %[dst_stride_a] \n"
- "lwx $t9, $t2(%[src]) \n" // |B2|A2|b2|a2|
- "lwx $s0, $t3(%[src]) \n" // |B3|A3|b3|a3|
- "addu $s6, %[dst_b], %[dst_stride_b] \n"
-
- "precrq.ph.w $s1, $t8, $t0 \n" // |B1|A1|B0|A0|
- "precrq.ph.w $s2, $s0, $t9 \n" // |B3|A3|B2|A2|
- "precr.qb.ph $s3, $s2, $s1 \n" // |A3|A2|A1|A0|
- "precrq.qb.ph $s4, $s2, $s1 \n" // |B3|B2|B1|B0|
-
- "sll $t0, $t0, 16 \n"
- "packrl.ph $s1, $t8, $t0 \n" // |b1|a1|b0|a0|
- "sll $t9, $t9, 16 \n"
- "packrl.ph $s2, $s0, $t9 \n" // |b3|a3|b2|a2|
-
- "swr $s3, 0($s5) \n"
- "swl $s3, 3($s5) \n"
- "swr $s4, 0($s6) \n"
- "swl $s4, 3($s6) \n"
-
- "precr.qb.ph $s3, $s2, $s1 \n" // |a3|a2|a1|a0|
- "precrq.qb.ph $s4, $s2, $s1 \n" // |b3|b2|b1|b0|
-
- "lwx $t0, $t4(%[src]) \n" // |B4|A4|b4|a4|
- "lwx $t8, $t5(%[src]) \n" // |B5|A5|b5|a5|
- "lwx $t9, $t6(%[src]) \n" // |B6|A6|b6|a6|
- "lwx $s0, $t7(%[src]) \n" // |B7|A7|b7|a7|
- "swr $s3, 0(%[dst_a]) \n"
- "swl $s3, 3(%[dst_a]) \n"
- "swr $s4, 0(%[dst_b]) \n"
- "swl $s4, 3(%[dst_b]) \n"
-
- "precrq.ph.w $s1, $t8, $t0 \n" // |B5|A5|B4|A4|
- "precrq.ph.w $s2, $s0, $t9 \n" // |B6|A6|B7|A7|
- "precr.qb.ph $s3, $s2, $s1 \n" // |A7|A6|A5|A4|
- "precrq.qb.ph $s4, $s2, $s1 \n" // |B7|B6|B5|B4|
-
- "sll $t0, $t0, 16 \n"
- "packrl.ph $s1, $t8, $t0 \n" // |b5|a5|b4|a4|
- "sll $t9, $t9, 16 \n"
- "packrl.ph $s2, $s0, $t9 \n" // |b7|a7|b6|a6|
-
- "swr $s3, 4($s5) \n"
- "swl $s3, 7($s5) \n"
- "swr $s4, 4($s6) \n"
- "swl $s4, 7($s6) \n"
-
- "precr.qb.ph $s3, $s2, $s1 \n" // |a7|a6|a5|a4|
- "precrq.qb.ph $s4, $s2, $s1 \n" // |b7|b6|b5|b4|
-
- "addiu %[src], 4 \n"
- "addiu $t1, -1 \n"
- "sll $t0, %[dst_stride_a], 1 \n"
- "sll $t8, %[dst_stride_b], 1 \n"
- "swr $s3, 4(%[dst_a]) \n"
- "swl $s3, 7(%[dst_a]) \n"
- "swr $s4, 4(%[dst_b]) \n"
- "swl $s4, 7(%[dst_b]) \n"
- "addu %[dst_a], %[dst_a], $t0 \n"
- "bnez $t1, 11b \n"
- " addu %[dst_b], %[dst_b], $t8 \n"
-
- "2: \n"
- ".set pop \n"
- : [src] "+r" (src),
- [dst_a] "+r" (dst_a),
- [dst_b] "+r" (dst_b),
- [width] "+r" (width),
- [src_stride] "+r" (src_stride)
- : [dst_stride_a] "r" (dst_stride_a),
- [dst_stride_b] "r" (dst_stride_b)
- : "t0", "t1", "t2", "t3", "t4", "t5",
- "t6", "t7", "t8", "t9",
- "s0", "s1", "s2", "s3",
- "s4", "s5", "s6"
- );
-}
-
-#endif // defined(__mips_dsp) && (__mips_dsp_rev >= 2)
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/rotate_neon.cc b/drivers/theoraplayer/src/YUV/libyuv/src/rotate_neon.cc
deleted file mode 100755
index 274c4109cd..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/rotate_neon.cc
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/row.h"
-
-#include "libyuv/basic_types.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-#if !defined(LIBYUV_DISABLE_NEON) && defined(__ARM_NEON__)
-static uvec8 kVTbl4x4Transpose =
- { 0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15 };
-
-void TransposeWx8_NEON(const uint8* src, int src_stride,
- uint8* dst, int dst_stride,
- int width) {
- const uint8* src_temp = NULL;
- asm volatile (
- // loops are on blocks of 8. loop will stop when
- // counter gets to or below 0. starting the counter
- // at w-8 allow for this
-#ifdef _ANDROID
- ".fpu neon\n"
-#endif
- "sub %5, #8 \n"
-
- // handle 8x8 blocks. this should be the majority of the plane
- ".p2align 2 \n"
- "1: \n"
- "mov %0, %1 \n"
-
- "vld1.8 {d0}, [%0], %2 \n"
- "vld1.8 {d1}, [%0], %2 \n"
- "vld1.8 {d2}, [%0], %2 \n"
- "vld1.8 {d3}, [%0], %2 \n"
- "vld1.8 {d4}, [%0], %2 \n"
- "vld1.8 {d5}, [%0], %2 \n"
- "vld1.8 {d6}, [%0], %2 \n"
- "vld1.8 {d7}, [%0] \n"
-
- "vtrn.8 d1, d0 \n"
- "vtrn.8 d3, d2 \n"
- "vtrn.8 d5, d4 \n"
- "vtrn.8 d7, d6 \n"
-
- "vtrn.16 d1, d3 \n"
- "vtrn.16 d0, d2 \n"
- "vtrn.16 d5, d7 \n"
- "vtrn.16 d4, d6 \n"
-
- "vtrn.32 d1, d5 \n"
- "vtrn.32 d0, d4 \n"
- "vtrn.32 d3, d7 \n"
- "vtrn.32 d2, d6 \n"
-
- "vrev16.8 q0, q0 \n"
- "vrev16.8 q1, q1 \n"
- "vrev16.8 q2, q2 \n"
- "vrev16.8 q3, q3 \n"
-
- "mov %0, %3 \n"
-
- "vst1.8 {d1}, [%0], %4 \n"
- "vst1.8 {d0}, [%0], %4 \n"
- "vst1.8 {d3}, [%0], %4 \n"
- "vst1.8 {d2}, [%0], %4 \n"
- "vst1.8 {d5}, [%0], %4 \n"
- "vst1.8 {d4}, [%0], %4 \n"
- "vst1.8 {d7}, [%0], %4 \n"
- "vst1.8 {d6}, [%0] \n"
-
- "add %1, #8 \n" // src += 8
- "add %3, %3, %4, lsl #3 \n" // dst += 8 * dst_stride
- "subs %5, #8 \n" // w -= 8
- "bge 1b \n"
-
- // add 8 back to counter. if the result is 0 there are
- // no residuals.
- "adds %5, #8 \n"
- "beq 4f \n"
-
- // some residual, so between 1 and 7 lines left to transpose
- "cmp %5, #2 \n"
- "blt 3f \n"
-
- "cmp %5, #4 \n"
- "blt 2f \n"
-
- // 4x8 block
- "mov %0, %1 \n"
- "vld1.32 {d0[0]}, [%0], %2 \n"
- "vld1.32 {d0[1]}, [%0], %2 \n"
- "vld1.32 {d1[0]}, [%0], %2 \n"
- "vld1.32 {d1[1]}, [%0], %2 \n"
- "vld1.32 {d2[0]}, [%0], %2 \n"
- "vld1.32 {d2[1]}, [%0], %2 \n"
- "vld1.32 {d3[0]}, [%0], %2 \n"
- "vld1.32 {d3[1]}, [%0] \n"
-
- "mov %0, %3 \n"
-
- "vld1.8 {q3}, [%6] \n"
-
- "vtbl.8 d4, {d0, d1}, d6 \n"
- "vtbl.8 d5, {d0, d1}, d7 \n"
- "vtbl.8 d0, {d2, d3}, d6 \n"
- "vtbl.8 d1, {d2, d3}, d7 \n"
-
- // TODO(frkoenig): Rework shuffle above to
- // write out with 4 instead of 8 writes.
- "vst1.32 {d4[0]}, [%0], %4 \n"
- "vst1.32 {d4[1]}, [%0], %4 \n"
- "vst1.32 {d5[0]}, [%0], %4 \n"
- "vst1.32 {d5[1]}, [%0] \n"
-
- "add %0, %3, #4 \n"
- "vst1.32 {d0[0]}, [%0], %4 \n"
- "vst1.32 {d0[1]}, [%0], %4 \n"
- "vst1.32 {d1[0]}, [%0], %4 \n"
- "vst1.32 {d1[1]}, [%0] \n"
-
- "add %1, #4 \n" // src += 4
- "add %3, %3, %4, lsl #2 \n" // dst += 4 * dst_stride
- "subs %5, #4 \n" // w -= 4
- "beq 4f \n"
-
- // some residual, check to see if it includes a 2x8 block,
- // or less
- "cmp %5, #2 \n"
- "blt 3f \n"
-
- // 2x8 block
- "2: \n"
- "mov %0, %1 \n"
- "vld1.16 {d0[0]}, [%0], %2 \n"
- "vld1.16 {d1[0]}, [%0], %2 \n"
- "vld1.16 {d0[1]}, [%0], %2 \n"
- "vld1.16 {d1[1]}, [%0], %2 \n"
- "vld1.16 {d0[2]}, [%0], %2 \n"
- "vld1.16 {d1[2]}, [%0], %2 \n"
- "vld1.16 {d0[3]}, [%0], %2 \n"
- "vld1.16 {d1[3]}, [%0] \n"
-
- "vtrn.8 d0, d1 \n"
-
- "mov %0, %3 \n"
-
- "vst1.64 {d0}, [%0], %4 \n"
- "vst1.64 {d1}, [%0] \n"
-
- "add %1, #2 \n" // src += 2
- "add %3, %3, %4, lsl #1 \n" // dst += 2 * dst_stride
- "subs %5, #2 \n" // w -= 2
- "beq 4f \n"
-
- // 1x8 block
- "3: \n"
- "vld1.8 {d0[0]}, [%1], %2 \n"
- "vld1.8 {d0[1]}, [%1], %2 \n"
- "vld1.8 {d0[2]}, [%1], %2 \n"
- "vld1.8 {d0[3]}, [%1], %2 \n"
- "vld1.8 {d0[4]}, [%1], %2 \n"
- "vld1.8 {d0[5]}, [%1], %2 \n"
- "vld1.8 {d0[6]}, [%1], %2 \n"
- "vld1.8 {d0[7]}, [%1] \n"
-
- "vst1.64 {d0}, [%3] \n"
-
- "4: \n"
-
- : "+r"(src_temp), // %0
- "+r"(src), // %1
- "+r"(src_stride), // %2
- "+r"(dst), // %3
- "+r"(dst_stride), // %4
- "+r"(width) // %5
- : "r"(&kVTbl4x4Transpose) // %6
- : "memory", "cc", "q0", "q1", "q2", "q3"
- );
-}
-
-static uvec8 kVTbl4x4TransposeDi =
- { 0, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15 };
-
-void TransposeUVWx8_NEON(const uint8* src, int src_stride,
- uint8* dst_a, int dst_stride_a,
- uint8* dst_b, int dst_stride_b,
- int width) {
- const uint8* src_temp = NULL;
- asm volatile (
- // loops are on blocks of 8. loop will stop when
- // counter gets to or below 0. starting the counter
- // at w-8 allow for this
- "sub %7, #8 \n"
-
- // handle 8x8 blocks. this should be the majority of the plane
- ".p2align 2 \n"
- "1: \n"
- "mov %0, %1 \n"
-
- "vld2.8 {d0, d1}, [%0], %2 \n"
- "vld2.8 {d2, d3}, [%0], %2 \n"
- "vld2.8 {d4, d5}, [%0], %2 \n"
- "vld2.8 {d6, d7}, [%0], %2 \n"
- "vld2.8 {d16, d17}, [%0], %2 \n"
- "vld2.8 {d18, d19}, [%0], %2 \n"
- "vld2.8 {d20, d21}, [%0], %2 \n"
- "vld2.8 {d22, d23}, [%0] \n"
-
- "vtrn.8 q1, q0 \n"
- "vtrn.8 q3, q2 \n"
- "vtrn.8 q9, q8 \n"
- "vtrn.8 q11, q10 \n"
-
- "vtrn.16 q1, q3 \n"
- "vtrn.16 q0, q2 \n"
- "vtrn.16 q9, q11 \n"
- "vtrn.16 q8, q10 \n"
-
- "vtrn.32 q1, q9 \n"
- "vtrn.32 q0, q8 \n"
- "vtrn.32 q3, q11 \n"
- "vtrn.32 q2, q10 \n"
-
- "vrev16.8 q0, q0 \n"
- "vrev16.8 q1, q1 \n"
- "vrev16.8 q2, q2 \n"
- "vrev16.8 q3, q3 \n"
- "vrev16.8 q8, q8 \n"
- "vrev16.8 q9, q9 \n"
- "vrev16.8 q10, q10 \n"
- "vrev16.8 q11, q11 \n"
-
- "mov %0, %3 \n"
-
- "vst1.8 {d2}, [%0], %4 \n"
- "vst1.8 {d0}, [%0], %4 \n"
- "vst1.8 {d6}, [%0], %4 \n"
- "vst1.8 {d4}, [%0], %4 \n"
- "vst1.8 {d18}, [%0], %4 \n"
- "vst1.8 {d16}, [%0], %4 \n"
- "vst1.8 {d22}, [%0], %4 \n"
- "vst1.8 {d20}, [%0] \n"
-
- "mov %0, %5 \n"
-
- "vst1.8 {d3}, [%0], %6 \n"
- "vst1.8 {d1}, [%0], %6 \n"
- "vst1.8 {d7}, [%0], %6 \n"
- "vst1.8 {d5}, [%0], %6 \n"
- "vst1.8 {d19}, [%0], %6 \n"
- "vst1.8 {d17}, [%0], %6 \n"
- "vst1.8 {d23}, [%0], %6 \n"
- "vst1.8 {d21}, [%0] \n"
-
- "add %1, #8*2 \n" // src += 8*2
- "add %3, %3, %4, lsl #3 \n" // dst_a += 8 * dst_stride_a
- "add %5, %5, %6, lsl #3 \n" // dst_b += 8 * dst_stride_b
- "subs %7, #8 \n" // w -= 8
- "bge 1b \n"
-
- // add 8 back to counter. if the result is 0 there are
- // no residuals.
- "adds %7, #8 \n"
- "beq 4f \n"
-
- // some residual, so between 1 and 7 lines left to transpose
- "cmp %7, #2 \n"
- "blt 3f \n"
-
- "cmp %7, #4 \n"
- "blt 2f \n"
-
- //TODO(frkoenig): Clean this up
- // 4x8 block
- "mov %0, %1 \n"
- "vld1.64 {d0}, [%0], %2 \n"
- "vld1.64 {d1}, [%0], %2 \n"
- "vld1.64 {d2}, [%0], %2 \n"
- "vld1.64 {d3}, [%0], %2 \n"
- "vld1.64 {d4}, [%0], %2 \n"
- "vld1.64 {d5}, [%0], %2 \n"
- "vld1.64 {d6}, [%0], %2 \n"
- "vld1.64 {d7}, [%0] \n"
-
- "vld1.8 {q15}, [%8] \n"
-
- "vtrn.8 q0, q1 \n"
- "vtrn.8 q2, q3 \n"
-
- "vtbl.8 d16, {d0, d1}, d30 \n"
- "vtbl.8 d17, {d0, d1}, d31 \n"
- "vtbl.8 d18, {d2, d3}, d30 \n"
- "vtbl.8 d19, {d2, d3}, d31 \n"
- "vtbl.8 d20, {d4, d5}, d30 \n"
- "vtbl.8 d21, {d4, d5}, d31 \n"
- "vtbl.8 d22, {d6, d7}, d30 \n"
- "vtbl.8 d23, {d6, d7}, d31 \n"
-
- "mov %0, %3 \n"
-
- "vst1.32 {d16[0]}, [%0], %4 \n"
- "vst1.32 {d16[1]}, [%0], %4 \n"
- "vst1.32 {d17[0]}, [%0], %4 \n"
- "vst1.32 {d17[1]}, [%0], %4 \n"
-
- "add %0, %3, #4 \n"
- "vst1.32 {d20[0]}, [%0], %4 \n"
- "vst1.32 {d20[1]}, [%0], %4 \n"
- "vst1.32 {d21[0]}, [%0], %4 \n"
- "vst1.32 {d21[1]}, [%0] \n"
-
- "mov %0, %5 \n"
-
- "vst1.32 {d18[0]}, [%0], %6 \n"
- "vst1.32 {d18[1]}, [%0], %6 \n"
- "vst1.32 {d19[0]}, [%0], %6 \n"
- "vst1.32 {d19[1]}, [%0], %6 \n"
-
- "add %0, %5, #4 \n"
- "vst1.32 {d22[0]}, [%0], %6 \n"
- "vst1.32 {d22[1]}, [%0], %6 \n"
- "vst1.32 {d23[0]}, [%0], %6 \n"
- "vst1.32 {d23[1]}, [%0] \n"
-
- "add %1, #4*2 \n" // src += 4 * 2
- "add %3, %3, %4, lsl #2 \n" // dst_a += 4 * dst_stride_a
- "add %5, %5, %6, lsl #2 \n" // dst_b += 4 * dst_stride_b
- "subs %7, #4 \n" // w -= 4
- "beq 4f \n"
-
- // some residual, check to see if it includes a 2x8 block,
- // or less
- "cmp %7, #2 \n"
- "blt 3f \n"
-
- // 2x8 block
- "2: \n"
- "mov %0, %1 \n"
- "vld2.16 {d0[0], d2[0]}, [%0], %2 \n"
- "vld2.16 {d1[0], d3[0]}, [%0], %2 \n"
- "vld2.16 {d0[1], d2[1]}, [%0], %2 \n"
- "vld2.16 {d1[1], d3[1]}, [%0], %2 \n"
- "vld2.16 {d0[2], d2[2]}, [%0], %2 \n"
- "vld2.16 {d1[2], d3[2]}, [%0], %2 \n"
- "vld2.16 {d0[3], d2[3]}, [%0], %2 \n"
- "vld2.16 {d1[3], d3[3]}, [%0] \n"
-
- "vtrn.8 d0, d1 \n"
- "vtrn.8 d2, d3 \n"
-
- "mov %0, %3 \n"
-
- "vst1.64 {d0}, [%0], %4 \n"
- "vst1.64 {d2}, [%0] \n"
-
- "mov %0, %5 \n"
-
- "vst1.64 {d1}, [%0], %6 \n"
- "vst1.64 {d3}, [%0] \n"
-
- "add %1, #2*2 \n" // src += 2 * 2
- "add %3, %3, %4, lsl #1 \n" // dst_a += 2 * dst_stride_a
- "add %5, %5, %6, lsl #1 \n" // dst_b += 2 * dst_stride_b
- "subs %7, #2 \n" // w -= 2
- "beq 4f \n"
-
- // 1x8 block
- "3: \n"
- "vld2.8 {d0[0], d1[0]}, [%1], %2 \n"
- "vld2.8 {d0[1], d1[1]}, [%1], %2 \n"
- "vld2.8 {d0[2], d1[2]}, [%1], %2 \n"
- "vld2.8 {d0[3], d1[3]}, [%1], %2 \n"
- "vld2.8 {d0[4], d1[4]}, [%1], %2 \n"
- "vld2.8 {d0[5], d1[5]}, [%1], %2 \n"
- "vld2.8 {d0[6], d1[6]}, [%1], %2 \n"
- "vld2.8 {d0[7], d1[7]}, [%1] \n"
-
- "vst1.64 {d0}, [%3] \n"
- "vst1.64 {d1}, [%5] \n"
-
- "4: \n"
-
- : "+r"(src_temp), // %0
- "+r"(src), // %1
- "+r"(src_stride), // %2
- "+r"(dst_a), // %3
- "+r"(dst_stride_a), // %4
- "+r"(dst_b), // %5
- "+r"(dst_stride_b), // %6
- "+r"(width) // %7
- : "r"(&kVTbl4x4TransposeDi) // %8
- : "memory", "cc",
- "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11"
- );
-}
-#endif
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/row_any.cc b/drivers/theoraplayer/src/YUV/libyuv/src/row_any.cc
deleted file mode 100755
index 90c6a3ff5f..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/row_any.cc
+++ /dev/null
@@ -1,542 +0,0 @@
-/*
- * Copyright 2012 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/row.h"
-
-#include "libyuv/basic_types.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// TODO(fbarchard): Consider 'any' functions handling any quantity of pixels.
-// TODO(fbarchard): Consider 'any' functions handling odd alignment.
-// YUV to RGB does multiple of 8 with SIMD and remainder with C.
-#define YANY(NAMEANY, I420TORGB_SIMD, I420TORGB_C, UV_SHIFT, BPP, MASK) \
- void NAMEANY(const uint8* y_buf, \
- const uint8* u_buf, \
- const uint8* v_buf, \
- uint8* rgb_buf, \
- int width) { \
- int n = width & ~MASK; \
- I420TORGB_SIMD(y_buf, u_buf, v_buf, rgb_buf, n); \
- I420TORGB_C(y_buf + n, \
- u_buf + (n >> UV_SHIFT), \
- v_buf + (n >> UV_SHIFT), \
- rgb_buf + n * BPP, width & MASK); \
- }
-
-#ifdef HAS_I422TOARGBROW_SSSE3
-YANY(I444ToARGBRow_Any_SSSE3, I444ToARGBRow_Unaligned_SSSE3, I444ToARGBRow_C,
- 0, 4, 7)
-YANY(I422ToARGBRow_Any_SSSE3, I422ToARGBRow_Unaligned_SSSE3, I422ToARGBRow_C,
- 1, 4, 7)
-YANY(I411ToARGBRow_Any_SSSE3, I411ToARGBRow_Unaligned_SSSE3, I411ToARGBRow_C,
- 2, 4, 7)
-YANY(I422ToBGRARow_Any_SSSE3, I422ToBGRARow_Unaligned_SSSE3, I422ToBGRARow_C,
- 1, 4, 7)
-YANY(I422ToABGRRow_Any_SSSE3, I422ToABGRRow_Unaligned_SSSE3, I422ToABGRRow_C,
- 1, 4, 7)
-YANY(I422ToRGBARow_Any_SSSE3, I422ToRGBARow_Unaligned_SSSE3, I422ToRGBARow_C,
- 1, 4, 7)
-// I422ToRGB565Row_SSSE3 is unaligned.
-YANY(I422ToARGB4444Row_Any_SSSE3, I422ToARGB4444Row_SSSE3, I422ToARGB4444Row_C,
- 1, 2, 7)
-YANY(I422ToARGB1555Row_Any_SSSE3, I422ToARGB1555Row_SSSE3, I422ToARGB1555Row_C,
- 1, 2, 7)
-YANY(I422ToRGB565Row_Any_SSSE3, I422ToRGB565Row_SSSE3, I422ToRGB565Row_C,
- 1, 2, 7)
-// I422ToRGB24Row_SSSE3 is unaligned.
-YANY(I422ToRGB24Row_Any_SSSE3, I422ToRGB24Row_SSSE3, I422ToRGB24Row_C, 1, 3, 7)
-YANY(I422ToRAWRow_Any_SSSE3, I422ToRAWRow_SSSE3, I422ToRAWRow_C, 1, 3, 7)
-YANY(I422ToYUY2Row_Any_SSE2, I422ToYUY2Row_SSE2, I422ToYUY2Row_C, 1, 2, 15)
-YANY(I422ToUYVYRow_Any_SSE2, I422ToUYVYRow_SSE2, I422ToUYVYRow_C, 1, 2, 15)
-#endif // HAS_I422TOARGBROW_SSSE3
-#ifdef HAS_I422TOARGBROW_AVX2
-YANY(I422ToARGBRow_Any_AVX2, I422ToARGBRow_AVX2, I422ToARGBRow_C, 1, 4, 15)
-#endif // HAS_I422TOARGBROW_AVX2
-#ifdef HAS_I422TOARGBROW_NEON
-YANY(I444ToARGBRow_Any_NEON, I444ToARGBRow_NEON, I444ToARGBRow_C, 0, 4, 7)
-YANY(I422ToARGBRow_Any_NEON, I422ToARGBRow_NEON, I422ToARGBRow_C, 1, 4, 7)
-YANY(I411ToARGBRow_Any_NEON, I411ToARGBRow_NEON, I411ToARGBRow_C, 2, 4, 7)
-YANY(I422ToBGRARow_Any_NEON, I422ToBGRARow_NEON, I422ToBGRARow_C, 1, 4, 7)
-YANY(I422ToABGRRow_Any_NEON, I422ToABGRRow_NEON, I422ToABGRRow_C, 1, 4, 7)
-YANY(I422ToRGBARow_Any_NEON, I422ToRGBARow_NEON, I422ToRGBARow_C, 1, 4, 7)
-YANY(I422ToRGB24Row_Any_NEON, I422ToRGB24Row_NEON, I422ToRGB24Row_C, 1, 3, 7)
-YANY(I422ToRAWRow_Any_NEON, I422ToRAWRow_NEON, I422ToRAWRow_C, 1, 3, 7)
-YANY(I422ToARGB4444Row_Any_NEON, I422ToARGB4444Row_NEON, I422ToARGB4444Row_C,
- 1, 2, 7)
-YANY(I422ToARGB1555Row_Any_NEON, I422ToARGB1555Row_NEON, I422ToARGB1555Row_C,
- 1, 2, 7)
-YANY(I422ToRGB565Row_Any_NEON, I422ToRGB565Row_NEON, I422ToRGB565Row_C, 1, 2, 7)
-YANY(I422ToYUY2Row_Any_NEON, I422ToYUY2Row_NEON, I422ToYUY2Row_C, 1, 2, 15)
-YANY(I422ToUYVYRow_Any_NEON, I422ToUYVYRow_NEON, I422ToUYVYRow_C, 1, 2, 15)
-#endif // HAS_I422TOARGBROW_NEON
-#undef YANY
-
-// Wrappers to handle odd width
-#define NV2NY(NAMEANY, NV12TORGB_SIMD, NV12TORGB_C, UV_SHIFT, BPP) \
- void NAMEANY(const uint8* y_buf, \
- const uint8* uv_buf, \
- uint8* rgb_buf, \
- int width) { \
- int n = width & ~7; \
- NV12TORGB_SIMD(y_buf, uv_buf, rgb_buf, n); \
- NV12TORGB_C(y_buf + n, \
- uv_buf + (n >> UV_SHIFT), \
- rgb_buf + n * BPP, width & 7); \
- }
-
-#ifdef HAS_NV12TOARGBROW_SSSE3
-NV2NY(NV12ToARGBRow_Any_SSSE3, NV12ToARGBRow_Unaligned_SSSE3, NV12ToARGBRow_C,
- 0, 4)
-NV2NY(NV21ToARGBRow_Any_SSSE3, NV21ToARGBRow_Unaligned_SSSE3, NV21ToARGBRow_C,
- 0, 4)
-#endif // HAS_NV12TOARGBROW_SSSE3
-#ifdef HAS_NV12TOARGBROW_NEON
-NV2NY(NV12ToARGBRow_Any_NEON, NV12ToARGBRow_NEON, NV12ToARGBRow_C, 0, 4)
-NV2NY(NV21ToARGBRow_Any_NEON, NV21ToARGBRow_NEON, NV21ToARGBRow_C, 0, 4)
-#endif // HAS_NV12TOARGBROW_NEON
-#ifdef HAS_NV12TORGB565ROW_SSSE3
-NV2NY(NV12ToRGB565Row_Any_SSSE3, NV12ToRGB565Row_SSSE3, NV12ToRGB565Row_C,
- 0, 2)
-NV2NY(NV21ToRGB565Row_Any_SSSE3, NV21ToRGB565Row_SSSE3, NV21ToRGB565Row_C,
- 0, 2)
-#endif // HAS_NV12TORGB565ROW_SSSE3
-#ifdef HAS_NV12TORGB565ROW_NEON
-NV2NY(NV12ToRGB565Row_Any_NEON, NV12ToRGB565Row_NEON, NV12ToRGB565Row_C, 0, 2)
-NV2NY(NV21ToRGB565Row_Any_NEON, NV21ToRGB565Row_NEON, NV21ToRGB565Row_C, 0, 2)
-#endif // HAS_NV12TORGB565ROW_NEON
-#undef NVANY
-
-#define RGBANY(NAMEANY, ARGBTORGB_SIMD, ARGBTORGB_C, MASK, SBPP, BPP) \
- void NAMEANY(const uint8* src, \
- uint8* dst, \
- int width) { \
- int n = width & ~MASK; \
- ARGBTORGB_SIMD(src, dst, n); \
- ARGBTORGB_C(src + n * SBPP, dst + n * BPP, width & MASK); \
- }
-
-#if defined(HAS_ARGBTORGB24ROW_SSSE3)
-RGBANY(ARGBToRGB24Row_Any_SSSE3, ARGBToRGB24Row_SSSE3, ARGBToRGB24Row_C,
- 15, 4, 3)
-RGBANY(ARGBToRAWRow_Any_SSSE3, ARGBToRAWRow_SSSE3, ARGBToRAWRow_C,
- 15, 4, 3)
-RGBANY(ARGBToRGB565Row_Any_SSE2, ARGBToRGB565Row_SSE2, ARGBToRGB565Row_C,
- 3, 4, 2)
-RGBANY(ARGBToARGB1555Row_Any_SSE2, ARGBToARGB1555Row_SSE2, ARGBToARGB1555Row_C,
- 3, 4, 2)
-RGBANY(ARGBToARGB4444Row_Any_SSE2, ARGBToARGB4444Row_SSE2, ARGBToARGB4444Row_C,
- 3, 4, 2)
-#endif
-#if defined(HAS_I400TOARGBROW_SSE2)
-RGBANY(I400ToARGBRow_Any_SSE2, I400ToARGBRow_Unaligned_SSE2, I400ToARGBRow_C,
- 7, 1, 4)
-#endif
-#if defined(HAS_YTOARGBROW_SSE2)
-RGBANY(YToARGBRow_Any_SSE2, YToARGBRow_SSE2, YToARGBRow_C,
- 7, 1, 4)
-RGBANY(YUY2ToARGBRow_Any_SSSE3, YUY2ToARGBRow_Unaligned_SSSE3, YUY2ToARGBRow_C,
- 15, 2, 4)
-RGBANY(UYVYToARGBRow_Any_SSSE3, UYVYToARGBRow_Unaligned_SSSE3, UYVYToARGBRow_C,
- 15, 2, 4)
-// These require alignment on ARGB, so C is used for remainder.
-RGBANY(RGB24ToARGBRow_Any_SSSE3, RGB24ToARGBRow_SSSE3, RGB24ToARGBRow_C,
- 15, 3, 4)
-RGBANY(RAWToARGBRow_Any_SSSE3, RAWToARGBRow_SSSE3, RAWToARGBRow_C,
- 15, 3, 4)
-RGBANY(RGB565ToARGBRow_Any_SSE2, RGB565ToARGBRow_SSE2, RGB565ToARGBRow_C,
- 7, 2, 4)
-RGBANY(ARGB1555ToARGBRow_Any_SSE2, ARGB1555ToARGBRow_SSE2, ARGB1555ToARGBRow_C,
- 7, 2, 4)
-RGBANY(ARGB4444ToARGBRow_Any_SSE2, ARGB4444ToARGBRow_SSE2, ARGB4444ToARGBRow_C,
- 7, 2, 4)
-#endif
-#if defined(HAS_ARGBTORGB24ROW_NEON)
-RGBANY(ARGBToRGB24Row_Any_NEON, ARGBToRGB24Row_NEON, ARGBToRGB24Row_C, 7, 4, 3)
-RGBANY(ARGBToRAWRow_Any_NEON, ARGBToRAWRow_NEON, ARGBToRAWRow_C, 7, 4, 3)
-RGBANY(ARGBToRGB565Row_Any_NEON, ARGBToRGB565Row_NEON, ARGBToRGB565Row_C,
- 7, 4, 2)
-RGBANY(ARGBToARGB1555Row_Any_NEON, ARGBToARGB1555Row_NEON, ARGBToARGB1555Row_C,
- 7, 4, 2)
-RGBANY(ARGBToARGB4444Row_Any_NEON, ARGBToARGB4444Row_NEON, ARGBToARGB4444Row_C,
- 7, 4, 2)
-RGBANY(I400ToARGBRow_Any_NEON, I400ToARGBRow_NEON, I400ToARGBRow_C,
- 7, 1, 4)
-RGBANY(YToARGBRow_Any_NEON, YToARGBRow_NEON, YToARGBRow_C,
- 7, 1, 4)
-RGBANY(YUY2ToARGBRow_Any_NEON, YUY2ToARGBRow_NEON, YUY2ToARGBRow_C,
- 7, 2, 4)
-RGBANY(UYVYToARGBRow_Any_NEON, UYVYToARGBRow_NEON, UYVYToARGBRow_C,
- 7, 2, 4)
-#endif
-#undef RGBANY
-
-// ARGB to Bayer does multiple of 4 pixels, SSSE3 aligned src, unaligned dst.
-#define BAYERANY(NAMEANY, ARGBTORGB_SIMD, ARGBTORGB_C, MASK, SBPP, BPP) \
- void NAMEANY(const uint8* src, \
- uint8* dst, uint32 selector, \
- int width) { \
- int n = width & ~MASK; \
- ARGBTORGB_SIMD(src, dst, selector, n); \
- ARGBTORGB_C(src + n * SBPP, dst + n * BPP, selector, width & MASK); \
- }
-
-#if defined(HAS_ARGBTOBAYERROW_SSSE3)
-BAYERANY(ARGBToBayerRow_Any_SSSE3, ARGBToBayerRow_SSSE3, ARGBToBayerRow_C,
- 7, 4, 1)
-#endif
-#if defined(HAS_ARGBTOBAYERROW_NEON)
-BAYERANY(ARGBToBayerRow_Any_NEON, ARGBToBayerRow_NEON, ARGBToBayerRow_C,
- 7, 4, 1)
-#endif
-#if defined(HAS_ARGBTOBAYERGGROW_SSE2)
-BAYERANY(ARGBToBayerGGRow_Any_SSE2, ARGBToBayerGGRow_SSE2, ARGBToBayerGGRow_C,
- 7, 4, 1)
-#endif
-#if defined(HAS_ARGBTOBAYERGGROW_NEON)
-BAYERANY(ARGBToBayerGGRow_Any_NEON, ARGBToBayerGGRow_NEON, ARGBToBayerGGRow_C,
- 7, 4, 1)
-#endif
-
-#undef BAYERANY
-
-// RGB/YUV to Y does multiple of 16 with SIMD and last 16 with SIMD.
-#define YANY(NAMEANY, ARGBTOY_SIMD, SBPP, BPP, NUM) \
- void NAMEANY(const uint8* src_argb, uint8* dst_y, int width) { \
- ARGBTOY_SIMD(src_argb, dst_y, width - NUM); \
- ARGBTOY_SIMD(src_argb + (width - NUM) * SBPP, \
- dst_y + (width - NUM) * BPP, NUM); \
- }
-
-#ifdef HAS_ARGBTOYROW_AVX2
-YANY(ARGBToYRow_Any_AVX2, ARGBToYRow_AVX2, 4, 1, 32)
-YANY(ARGBToYJRow_Any_AVX2, ARGBToYJRow_AVX2, 4, 1, 32)
-YANY(YUY2ToYRow_Any_AVX2, YUY2ToYRow_AVX2, 2, 1, 32)
-YANY(UYVYToYRow_Any_AVX2, UYVYToYRow_AVX2, 2, 1, 32)
-#endif
-#ifdef HAS_ARGBTOYROW_SSSE3
-YANY(ARGBToYRow_Any_SSSE3, ARGBToYRow_Unaligned_SSSE3, 4, 1, 16)
-#endif
-#ifdef HAS_BGRATOYROW_SSSE3
-YANY(BGRAToYRow_Any_SSSE3, BGRAToYRow_Unaligned_SSSE3, 4, 1, 16)
-YANY(ABGRToYRow_Any_SSSE3, ABGRToYRow_Unaligned_SSSE3, 4, 1, 16)
-YANY(RGBAToYRow_Any_SSSE3, RGBAToYRow_Unaligned_SSSE3, 4, 1, 16)
-YANY(YUY2ToYRow_Any_SSE2, YUY2ToYRow_Unaligned_SSE2, 2, 1, 16)
-YANY(UYVYToYRow_Any_SSE2, UYVYToYRow_Unaligned_SSE2, 2, 1, 16)
-#endif
-#ifdef HAS_ARGBTOYJROW_SSSE3
-YANY(ARGBToYJRow_Any_SSSE3, ARGBToYJRow_Unaligned_SSSE3, 4, 1, 16)
-#endif
-#ifdef HAS_ARGBTOYROW_NEON
-YANY(ARGBToYRow_Any_NEON, ARGBToYRow_NEON, 4, 1, 8)
-YANY(ARGBToYJRow_Any_NEON, ARGBToYJRow_NEON, 4, 1, 8)
-YANY(BGRAToYRow_Any_NEON, BGRAToYRow_NEON, 4, 1, 8)
-YANY(ABGRToYRow_Any_NEON, ABGRToYRow_NEON, 4, 1, 8)
-YANY(RGBAToYRow_Any_NEON, RGBAToYRow_NEON, 4, 1, 8)
-YANY(RGB24ToYRow_Any_NEON, RGB24ToYRow_NEON, 3, 1, 8)
-YANY(RAWToYRow_Any_NEON, RAWToYRow_NEON, 3, 1, 8)
-YANY(RGB565ToYRow_Any_NEON, RGB565ToYRow_NEON, 2, 1, 8)
-YANY(ARGB1555ToYRow_Any_NEON, ARGB1555ToYRow_NEON, 2, 1, 8)
-YANY(ARGB4444ToYRow_Any_NEON, ARGB4444ToYRow_NEON, 2, 1, 8)
-YANY(YUY2ToYRow_Any_NEON, YUY2ToYRow_NEON, 2, 1, 16)
-YANY(UYVYToYRow_Any_NEON, UYVYToYRow_NEON, 2, 1, 16)
-YANY(RGB24ToARGBRow_Any_NEON, RGB24ToARGBRow_NEON, 3, 4, 8)
-YANY(RAWToARGBRow_Any_NEON, RAWToARGBRow_NEON, 3, 4, 8)
-YANY(RGB565ToARGBRow_Any_NEON, RGB565ToARGBRow_NEON, 2, 4, 8)
-YANY(ARGB1555ToARGBRow_Any_NEON, ARGB1555ToARGBRow_NEON, 2, 4, 8)
-YANY(ARGB4444ToARGBRow_Any_NEON, ARGB4444ToARGBRow_NEON, 2, 4, 8)
-#endif
-#undef YANY
-
-#define YANY(NAMEANY, ARGBTOY_SIMD, ARGBTOY_C, SBPP, BPP, MASK) \
- void NAMEANY(const uint8* src_argb, uint8* dst_y, int width) { \
- int n = width & ~MASK; \
- ARGBTOY_SIMD(src_argb, dst_y, n); \
- ARGBTOY_C(src_argb + n * SBPP, \
- dst_y + n * BPP, width & MASK); \
- }
-
-// Attenuate is destructive so last16 method can not be used due to overlap.
-#ifdef HAS_ARGBATTENUATEROW_SSSE3
-YANY(ARGBAttenuateRow_Any_SSSE3, ARGBAttenuateRow_SSSE3, ARGBAttenuateRow_C,
- 4, 4, 3)
-#endif
-#ifdef HAS_ARGBATTENUATEROW_SSE2
-YANY(ARGBAttenuateRow_Any_SSE2, ARGBAttenuateRow_SSE2, ARGBAttenuateRow_C,
- 4, 4, 3)
-#endif
-#ifdef HAS_ARGBUNATTENUATEROW_SSE2
-YANY(ARGBUnattenuateRow_Any_SSE2, ARGBUnattenuateRow_SSE2, ARGBUnattenuateRow_C,
- 4, 4, 3)
-#endif
-#ifdef HAS_ARGBATTENUATEROW_AVX2
-YANY(ARGBAttenuateRow_Any_AVX2, ARGBAttenuateRow_AVX2, ARGBAttenuateRow_C,
- 4, 4, 7)
-#endif
-#ifdef HAS_ARGBUNATTENUATEROW_AVX2
-YANY(ARGBUnattenuateRow_Any_AVX2, ARGBUnattenuateRow_AVX2, ARGBUnattenuateRow_C,
- 4, 4, 7)
-#endif
-#ifdef HAS_ARGBATTENUATEROW_NEON
-YANY(ARGBAttenuateRow_Any_NEON, ARGBAttenuateRow_NEON, ARGBAttenuateRow_C,
- 4, 4, 7)
-#endif
-#undef YANY
-
-// RGB/YUV to UV does multiple of 16 with SIMD and remainder with C.
-#define UVANY(NAMEANY, ANYTOUV_SIMD, ANYTOUV_C, BPP, MASK) \
- void NAMEANY(const uint8* src_argb, int src_stride_argb, \
- uint8* dst_u, uint8* dst_v, int width) { \
- int n = width & ~MASK; \
- ANYTOUV_SIMD(src_argb, src_stride_argb, dst_u, dst_v, n); \
- ANYTOUV_C(src_argb + n * BPP, src_stride_argb, \
- dst_u + (n >> 1), \
- dst_v + (n >> 1), \
- width & MASK); \
- }
-
-#ifdef HAS_ARGBTOUVROW_AVX2
-UVANY(ARGBToUVRow_Any_AVX2, ARGBToUVRow_AVX2, ARGBToUVRow_C, 4, 31)
-UVANY(YUY2ToUVRow_Any_AVX2, YUY2ToUVRow_AVX2, YUY2ToUVRow_C, 2, 31)
-UVANY(UYVYToUVRow_Any_AVX2, UYVYToUVRow_AVX2, UYVYToUVRow_C, 2, 31)
-#endif
-#ifdef HAS_ARGBTOUVROW_SSSE3
-UVANY(ARGBToUVRow_Any_SSSE3, ARGBToUVRow_Unaligned_SSSE3, ARGBToUVRow_C, 4, 15)
-UVANY(ARGBToUVJRow_Any_SSSE3, ARGBToUVJRow_Unaligned_SSSE3, ARGBToUVJRow_C,
- 4, 15)
-UVANY(BGRAToUVRow_Any_SSSE3, BGRAToUVRow_Unaligned_SSSE3, BGRAToUVRow_C, 4, 15)
-UVANY(ABGRToUVRow_Any_SSSE3, ABGRToUVRow_Unaligned_SSSE3, ABGRToUVRow_C, 4, 15)
-UVANY(RGBAToUVRow_Any_SSSE3, RGBAToUVRow_Unaligned_SSSE3, RGBAToUVRow_C, 4, 15)
-UVANY(YUY2ToUVRow_Any_SSE2, YUY2ToUVRow_Unaligned_SSE2, YUY2ToUVRow_C, 2, 15)
-UVANY(UYVYToUVRow_Any_SSE2, UYVYToUVRow_Unaligned_SSE2, UYVYToUVRow_C, 2, 15)
-#endif
-#ifdef HAS_ARGBTOUVROW_NEON
-UVANY(ARGBToUVRow_Any_NEON, ARGBToUVRow_NEON, ARGBToUVRow_C, 4, 15)
-UVANY(ARGBToUVJRow_Any_NEON, ARGBToUVJRow_NEON, ARGBToUVJRow_C, 4, 15)
-UVANY(BGRAToUVRow_Any_NEON, BGRAToUVRow_NEON, BGRAToUVRow_C, 4, 15)
-UVANY(ABGRToUVRow_Any_NEON, ABGRToUVRow_NEON, ABGRToUVRow_C, 4, 15)
-UVANY(RGBAToUVRow_Any_NEON, RGBAToUVRow_NEON, RGBAToUVRow_C, 4, 15)
-UVANY(RGB24ToUVRow_Any_NEON, RGB24ToUVRow_NEON, RGB24ToUVRow_C, 3, 15)
-UVANY(RAWToUVRow_Any_NEON, RAWToUVRow_NEON, RAWToUVRow_C, 3, 15)
-UVANY(RGB565ToUVRow_Any_NEON, RGB565ToUVRow_NEON, RGB565ToUVRow_C, 2, 15)
-UVANY(ARGB1555ToUVRow_Any_NEON, ARGB1555ToUVRow_NEON, ARGB1555ToUVRow_C, 2, 15)
-UVANY(ARGB4444ToUVRow_Any_NEON, ARGB4444ToUVRow_NEON, ARGB4444ToUVRow_C, 2, 15)
-UVANY(YUY2ToUVRow_Any_NEON, YUY2ToUVRow_NEON, YUY2ToUVRow_C, 2, 15)
-UVANY(UYVYToUVRow_Any_NEON, UYVYToUVRow_NEON, UYVYToUVRow_C, 2, 15)
-#endif
-#undef UVANY
-
-#define UV422ANY(NAMEANY, ANYTOUV_SIMD, ANYTOUV_C, BPP, MASK, SHIFT) \
- void NAMEANY(const uint8* src_uv, \
- uint8* dst_u, uint8* dst_v, int width) { \
- int n = width & ~MASK; \
- ANYTOUV_SIMD(src_uv, dst_u, dst_v, n); \
- ANYTOUV_C(src_uv + n * BPP, \
- dst_u + (n >> SHIFT), \
- dst_v + (n >> SHIFT), \
- width & MASK); \
- }
-
-#ifdef HAS_ARGBTOUV444ROW_SSSE3
-UV422ANY(ARGBToUV444Row_Any_SSSE3, ARGBToUV444Row_Unaligned_SSSE3,
- ARGBToUV444Row_C, 4, 15, 0)
-#endif
-#ifdef HAS_YUY2TOUV422ROW_AVX2
-UV422ANY(YUY2ToUV422Row_Any_AVX2, YUY2ToUV422Row_AVX2,
- YUY2ToUV422Row_C, 2, 31, 1)
-UV422ANY(UYVYToUV422Row_Any_AVX2, UYVYToUV422Row_AVX2,
- UYVYToUV422Row_C, 2, 31, 1)
-#endif
-#ifdef HAS_ARGBTOUVROW_SSSE3
-UV422ANY(ARGBToUV422Row_Any_SSSE3, ARGBToUV422Row_Unaligned_SSSE3,
- ARGBToUV422Row_C, 4, 15, 1)
-UV422ANY(YUY2ToUV422Row_Any_SSE2, YUY2ToUV422Row_Unaligned_SSE2,
- YUY2ToUV422Row_C, 2, 15, 1)
-UV422ANY(UYVYToUV422Row_Any_SSE2, UYVYToUV422Row_Unaligned_SSE2,
- UYVYToUV422Row_C, 2, 15, 1)
-#endif
-#ifdef HAS_YUY2TOUV422ROW_NEON
-UV422ANY(ARGBToUV444Row_Any_NEON, ARGBToUV444Row_NEON,
- ARGBToUV444Row_C, 4, 7, 0)
-UV422ANY(ARGBToUV422Row_Any_NEON, ARGBToUV422Row_NEON,
- ARGBToUV422Row_C, 4, 15, 1)
-UV422ANY(ARGBToUV411Row_Any_NEON, ARGBToUV411Row_NEON,
- ARGBToUV411Row_C, 4, 31, 2)
-UV422ANY(YUY2ToUV422Row_Any_NEON, YUY2ToUV422Row_NEON,
- YUY2ToUV422Row_C, 2, 15, 1)
-UV422ANY(UYVYToUV422Row_Any_NEON, UYVYToUV422Row_NEON,
- UYVYToUV422Row_C, 2, 15, 1)
-#endif
-#undef UV422ANY
-
-#define SPLITUVROWANY(NAMEANY, ANYTOUV_SIMD, ANYTOUV_C, MASK) \
- void NAMEANY(const uint8* src_uv, \
- uint8* dst_u, uint8* dst_v, int width) { \
- int n = width & ~MASK; \
- ANYTOUV_SIMD(src_uv, dst_u, dst_v, n); \
- ANYTOUV_C(src_uv + n * 2, \
- dst_u + n, \
- dst_v + n, \
- width & MASK); \
- }
-
-#ifdef HAS_SPLITUVROW_SSE2
-SPLITUVROWANY(SplitUVRow_Any_SSE2, SplitUVRow_Unaligned_SSE2, SplitUVRow_C, 15)
-#endif
-#ifdef HAS_SPLITUVROW_AVX2
-SPLITUVROWANY(SplitUVRow_Any_AVX2, SplitUVRow_AVX2, SplitUVRow_C, 31)
-#endif
-#ifdef HAS_SPLITUVROW_NEON
-SPLITUVROWANY(SplitUVRow_Any_NEON, SplitUVRow_NEON, SplitUVRow_C, 15)
-#endif
-#ifdef HAS_SPLITUVROW_MIPS_DSPR2
-SPLITUVROWANY(SplitUVRow_Any_MIPS_DSPR2, SplitUVRow_Unaligned_MIPS_DSPR2,
- SplitUVRow_C, 15)
-#endif
-#undef SPLITUVROWANY
-
-#define MERGEUVROW_ANY(NAMEANY, ANYTOUV_SIMD, ANYTOUV_C, MASK) \
- void NAMEANY(const uint8* src_u, const uint8* src_v, \
- uint8* dst_uv, int width) { \
- int n = width & ~MASK; \
- ANYTOUV_SIMD(src_u, src_v, dst_uv, n); \
- ANYTOUV_C(src_u + n, \
- src_v + n, \
- dst_uv + n * 2, \
- width & MASK); \
- }
-
-#ifdef HAS_MERGEUVROW_SSE2
-MERGEUVROW_ANY(MergeUVRow_Any_SSE2, MergeUVRow_Unaligned_SSE2, MergeUVRow_C, 15)
-#endif
-#ifdef HAS_MERGEUVROW_AVX2
-MERGEUVROW_ANY(MergeUVRow_Any_AVX2, MergeUVRow_AVX2, MergeUVRow_C, 31)
-#endif
-#ifdef HAS_MERGEUVROW_NEON
-MERGEUVROW_ANY(MergeUVRow_Any_NEON, MergeUVRow_NEON, MergeUVRow_C, 15)
-#endif
-#undef MERGEUVROW_ANY
-
-#define MATHROW_ANY(NAMEANY, ARGBMATH_SIMD, ARGBMATH_C, MASK) \
- void NAMEANY(const uint8* src_argb0, const uint8* src_argb1, \
- uint8* dst_argb, int width) { \
- int n = width & ~MASK; \
- ARGBMATH_SIMD(src_argb0, src_argb1, dst_argb, n); \
- ARGBMATH_C(src_argb0 + n * 4, \
- src_argb1 + n * 4, \
- dst_argb + n * 4, \
- width & MASK); \
- }
-
-#ifdef HAS_ARGBMULTIPLYROW_SSE2
-MATHROW_ANY(ARGBMultiplyRow_Any_SSE2, ARGBMultiplyRow_SSE2, ARGBMultiplyRow_C,
- 3)
-#endif
-#ifdef HAS_ARGBADDROW_SSE2
-MATHROW_ANY(ARGBAddRow_Any_SSE2, ARGBAddRow_SSE2, ARGBAddRow_C, 3)
-#endif
-#ifdef HAS_ARGBSUBTRACTROW_SSE2
-MATHROW_ANY(ARGBSubtractRow_Any_SSE2, ARGBSubtractRow_SSE2, ARGBSubtractRow_C,
- 3)
-#endif
-#ifdef HAS_ARGBMULTIPLYROW_AVX2
-MATHROW_ANY(ARGBMultiplyRow_Any_AVX2, ARGBMultiplyRow_AVX2, ARGBMultiplyRow_C,
- 7)
-#endif
-#ifdef HAS_ARGBADDROW_AVX2
-MATHROW_ANY(ARGBAddRow_Any_AVX2, ARGBAddRow_AVX2, ARGBAddRow_C, 7)
-#endif
-#ifdef HAS_ARGBSUBTRACTROW_AVX2
-MATHROW_ANY(ARGBSubtractRow_Any_AVX2, ARGBSubtractRow_AVX2, ARGBSubtractRow_C,
- 7)
-#endif
-#ifdef HAS_ARGBMULTIPLYROW_NEON
-MATHROW_ANY(ARGBMultiplyRow_Any_NEON, ARGBMultiplyRow_NEON, ARGBMultiplyRow_C,
- 7)
-#endif
-#ifdef HAS_ARGBADDROW_NEON
-MATHROW_ANY(ARGBAddRow_Any_NEON, ARGBAddRow_NEON, ARGBAddRow_C, 7)
-#endif
-#ifdef HAS_ARGBSUBTRACTROW_NEON
-MATHROW_ANY(ARGBSubtractRow_Any_NEON, ARGBSubtractRow_NEON, ARGBSubtractRow_C,
- 7)
-#endif
-#undef MATHROW_ANY
-
-// Shuffle may want to work in place, so last16 method can not be used.
-#define YANY(NAMEANY, ARGBTOY_SIMD, ARGBTOY_C, SBPP, BPP, MASK) \
- void NAMEANY(const uint8* src_argb, uint8* dst_argb, \
- const uint8* shuffler, int width) { \
- int n = width & ~MASK; \
- ARGBTOY_SIMD(src_argb, dst_argb, shuffler, n); \
- ARGBTOY_C(src_argb + n * SBPP, \
- dst_argb + n * BPP, shuffler, width & MASK); \
- }
-
-#ifdef HAS_ARGBSHUFFLEROW_SSE2
-YANY(ARGBShuffleRow_Any_SSE2, ARGBShuffleRow_SSE2,
- ARGBShuffleRow_C, 4, 4, 3)
-#endif
-#ifdef HAS_ARGBSHUFFLEROW_SSSE3
-YANY(ARGBShuffleRow_Any_SSSE3, ARGBShuffleRow_Unaligned_SSSE3,
- ARGBShuffleRow_C, 4, 4, 7)
-#endif
-#ifdef HAS_ARGBSHUFFLEROW_AVX2
-YANY(ARGBShuffleRow_Any_AVX2, ARGBShuffleRow_AVX2,
- ARGBShuffleRow_C, 4, 4, 15)
-#endif
-#ifdef HAS_ARGBSHUFFLEROW_NEON
-YANY(ARGBShuffleRow_Any_NEON, ARGBShuffleRow_NEON,
- ARGBShuffleRow_C, 4, 4, 3)
-#endif
-#undef YANY
-
-// Interpolate may want to work in place, so last16 method can not be used.
-#define NANY(NAMEANY, TERP_SIMD, TERP_C, SBPP, BPP, MASK) \
- void NAMEANY(uint8* dst_ptr, const uint8* src_ptr, \
- ptrdiff_t src_stride_ptr, int width, \
- int source_y_fraction) { \
- int n = width & ~MASK; \
- TERP_SIMD(dst_ptr, src_ptr, src_stride_ptr, \
- n, source_y_fraction); \
- TERP_C(dst_ptr + n * BPP, \
- src_ptr + n * SBPP, src_stride_ptr, \
- width & MASK, source_y_fraction); \
- }
-
-#ifdef HAS_INTERPOLATEROW_AVX2
-NANY(InterpolateRow_Any_AVX2, InterpolateRow_AVX2,
- InterpolateRow_C, 1, 1, 32)
-#endif
-#ifdef HAS_INTERPOLATEROW_SSSE3
-NANY(InterpolateRow_Any_SSSE3, InterpolateRow_Unaligned_SSSE3,
- InterpolateRow_C, 1, 1, 15)
-#endif
-#ifdef HAS_INTERPOLATEROW_SSE2
-NANY(InterpolateRow_Any_SSE2, InterpolateRow_Unaligned_SSE2,
- InterpolateRow_C, 1, 1, 15)
-#endif
-#ifdef HAS_INTERPOLATEROW_NEON
-NANY(InterpolateRow_Any_NEON, InterpolateRow_NEON,
- InterpolateRow_C, 1, 1, 15)
-#endif
-#ifdef HAS_INTERPOLATEROW_MIPS_DSPR2
-NANY(InterpolateRow_Any_MIPS_DSPR2, InterpolateRow_MIPS_DSPR2,
- InterpolateRow_C, 1, 1, 3)
-#endif
-#undef NANY
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/row_common.cc b/drivers/theoraplayer/src/YUV/libyuv/src/row_common.cc
deleted file mode 100755
index 135bdc9084..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/row_common.cc
+++ /dev/null
@@ -1,2247 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/row.h"
-
-#include <string.h> // For memcpy and memset.
-
-#include "libyuv/basic_types.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// llvm x86 is poor at ternary operator, so use branchless min/max.
-
-#define USE_BRANCHLESS 1
-#if USE_BRANCHLESS
-static __inline int32 clamp0(int32 v) {
- return ((-(v) >> 31) & (v));
-}
-
-static __inline int32 clamp255(int32 v) {
- return (((255 - (v)) >> 31) | (v)) & 255;
-}
-
-static __inline uint32 Clamp(int32 val) {
- int v = clamp0(val);
- return (uint32)(clamp255(v));
-}
-
-static __inline uint32 Abs(int32 v) {
- int m = v >> 31;
- return (v + m) ^ m;
-}
-#else // USE_BRANCHLESS
-static __inline int32 clamp0(int32 v) {
- return (v < 0) ? 0 : v;
-}
-
-static __inline int32 clamp255(int32 v) {
- return (v > 255) ? 255 : v;
-}
-
-static __inline uint32 Clamp(int32 val) {
- int v = clamp0(val);
- return (uint32)(clamp255(v));
-}
-
-static __inline uint32 Abs(int32 v) {
- return (v < 0) ? -v : v;
-}
-#endif // USE_BRANCHLESS
-
-#ifdef LIBYUV_LITTLE_ENDIAN
-#define WRITEWORD(p, v) *(uint32*)(p) = v
-#else
-static inline void WRITEWORD(uint8* p, uint32 v) {
- p[0] = (uint8)(v & 255);
- p[1] = (uint8)((v >> 8) & 255);
- p[2] = (uint8)((v >> 16) & 255);
- p[3] = (uint8)((v >> 24) & 255);
-}
-#endif
-
-void RGB24ToARGBRow_C(const uint8* src_rgb24, uint8* dst_argb, int width) {
- int x;
- for (x = 0; x < width; ++x) {
- uint8 b = src_rgb24[0];
- uint8 g = src_rgb24[1];
- uint8 r = src_rgb24[2];
- dst_argb[0] = b;
- dst_argb[1] = g;
- dst_argb[2] = r;
- dst_argb[3] = 255u;
- dst_argb += 4;
- src_rgb24 += 3;
- }
-}
-
-void RAWToARGBRow_C(const uint8* src_raw, uint8* dst_argb, int width) {
- int x;
- for (x = 0; x < width; ++x) {
- uint8 r = src_raw[0];
- uint8 g = src_raw[1];
- uint8 b = src_raw[2];
- dst_argb[0] = b;
- dst_argb[1] = g;
- dst_argb[2] = r;
- dst_argb[3] = 255u;
- dst_argb += 4;
- src_raw += 3;
- }
-}
-
-void RGB565ToARGBRow_C(const uint8* src_rgb565, uint8* dst_argb, int width) {
- int x;
- for (x = 0; x < width; ++x) {
- uint8 b = src_rgb565[0] & 0x1f;
- uint8 g = (src_rgb565[0] >> 5) | ((src_rgb565[1] & 0x07) << 3);
- uint8 r = src_rgb565[1] >> 3;
- dst_argb[0] = (b << 3) | (b >> 2);
- dst_argb[1] = (g << 2) | (g >> 4);
- dst_argb[2] = (r << 3) | (r >> 2);
- dst_argb[3] = 255u;
- dst_argb += 4;
- src_rgb565 += 2;
- }
-}
-
-void ARGB1555ToARGBRow_C(const uint8* src_argb1555, uint8* dst_argb,
- int width) {
- int x;
- for (x = 0; x < width; ++x) {
- uint8 b = src_argb1555[0] & 0x1f;
- uint8 g = (src_argb1555[0] >> 5) | ((src_argb1555[1] & 0x03) << 3);
- uint8 r = (src_argb1555[1] & 0x7c) >> 2;
- uint8 a = src_argb1555[1] >> 7;
- dst_argb[0] = (b << 3) | (b >> 2);
- dst_argb[1] = (g << 3) | (g >> 2);
- dst_argb[2] = (r << 3) | (r >> 2);
- dst_argb[3] = -a;
- dst_argb += 4;
- src_argb1555 += 2;
- }
-}
-
-void ARGB4444ToARGBRow_C(const uint8* src_argb4444, uint8* dst_argb,
- int width) {
- int x;
- for (x = 0; x < width; ++x) {
- uint8 b = src_argb4444[0] & 0x0f;
- uint8 g = src_argb4444[0] >> 4;
- uint8 r = src_argb4444[1] & 0x0f;
- uint8 a = src_argb4444[1] >> 4;
- dst_argb[0] = (b << 4) | b;
- dst_argb[1] = (g << 4) | g;
- dst_argb[2] = (r << 4) | r;
- dst_argb[3] = (a << 4) | a;
- dst_argb += 4;
- src_argb4444 += 2;
- }
-}
-
-void ARGBToRGB24Row_C(const uint8* src_argb, uint8* dst_rgb, int width) {
- int x;
- for (x = 0; x < width; ++x) {
- uint8 b = src_argb[0];
- uint8 g = src_argb[1];
- uint8 r = src_argb[2];
- dst_rgb[0] = b;
- dst_rgb[1] = g;
- dst_rgb[2] = r;
- dst_rgb += 3;
- src_argb += 4;
- }
-}
-
-void ARGBToRAWRow_C(const uint8* src_argb, uint8* dst_rgb, int width) {
- int x;
- for (x = 0; x < width; ++x) {
- uint8 b = src_argb[0];
- uint8 g = src_argb[1];
- uint8 r = src_argb[2];
- dst_rgb[0] = r;
- dst_rgb[1] = g;
- dst_rgb[2] = b;
- dst_rgb += 3;
- src_argb += 4;
- }
-}
-
-void ARGBToRGB565Row_C(const uint8* src_argb, uint8* dst_rgb, int width) {
- int x;
- for (x = 0; x < width - 1; x += 2) {
- uint8 b0 = src_argb[0] >> 3;
- uint8 g0 = src_argb[1] >> 2;
- uint8 r0 = src_argb[2] >> 3;
- uint8 b1 = src_argb[4] >> 3;
- uint8 g1 = src_argb[5] >> 2;
- uint8 r1 = src_argb[6] >> 3;
- WRITEWORD(dst_rgb, b0 | (g0 << 5) | (r0 << 11) |
- (b1 << 16) | (g1 << 21) | (r1 << 27));
- dst_rgb += 4;
- src_argb += 8;
- }
- if (width & 1) {
- uint8 b0 = src_argb[0] >> 3;
- uint8 g0 = src_argb[1] >> 2;
- uint8 r0 = src_argb[2] >> 3;
- *(uint16*)(dst_rgb) = b0 | (g0 << 5) | (r0 << 11);
- }
-}
-
-void ARGBToARGB1555Row_C(const uint8* src_argb, uint8* dst_rgb, int width) {
- int x;
- for (x = 0; x < width - 1; x += 2) {
- uint8 b0 = src_argb[0] >> 3;
- uint8 g0 = src_argb[1] >> 3;
- uint8 r0 = src_argb[2] >> 3;
- uint8 a0 = src_argb[3] >> 7;
- uint8 b1 = src_argb[4] >> 3;
- uint8 g1 = src_argb[5] >> 3;
- uint8 r1 = src_argb[6] >> 3;
- uint8 a1 = src_argb[7] >> 7;
- *(uint32*)(dst_rgb) =
- b0 | (g0 << 5) | (r0 << 10) | (a0 << 15) |
- (b1 << 16) | (g1 << 21) | (r1 << 26) | (a1 << 31);
- dst_rgb += 4;
- src_argb += 8;
- }
- if (width & 1) {
- uint8 b0 = src_argb[0] >> 3;
- uint8 g0 = src_argb[1] >> 3;
- uint8 r0 = src_argb[2] >> 3;
- uint8 a0 = src_argb[3] >> 7;
- *(uint16*)(dst_rgb) =
- b0 | (g0 << 5) | (r0 << 10) | (a0 << 15);
- }
-}
-
-void ARGBToARGB4444Row_C(const uint8* src_argb, uint8* dst_rgb, int width) {
- int x;
- for (x = 0; x < width - 1; x += 2) {
- uint8 b0 = src_argb[0] >> 4;
- uint8 g0 = src_argb[1] >> 4;
- uint8 r0 = src_argb[2] >> 4;
- uint8 a0 = src_argb[3] >> 4;
- uint8 b1 = src_argb[4] >> 4;
- uint8 g1 = src_argb[5] >> 4;
- uint8 r1 = src_argb[6] >> 4;
- uint8 a1 = src_argb[7] >> 4;
- *(uint32*)(dst_rgb) =
- b0 | (g0 << 4) | (r0 << 8) | (a0 << 12) |
- (b1 << 16) | (g1 << 20) | (r1 << 24) | (a1 << 28);
- dst_rgb += 4;
- src_argb += 8;
- }
- if (width & 1) {
- uint8 b0 = src_argb[0] >> 4;
- uint8 g0 = src_argb[1] >> 4;
- uint8 r0 = src_argb[2] >> 4;
- uint8 a0 = src_argb[3] >> 4;
- *(uint16*)(dst_rgb) =
- b0 | (g0 << 4) | (r0 << 8) | (a0 << 12);
- }
-}
-
-static __inline int RGBToY(uint8 r, uint8 g, uint8 b) {
- return (66 * r + 129 * g + 25 * b + 0x1080) >> 8;
-}
-
-static __inline int RGBToU(uint8 r, uint8 g, uint8 b) {
- return (112 * b - 74 * g - 38 * r + 0x8080) >> 8;
-}
-static __inline int RGBToV(uint8 r, uint8 g, uint8 b) {
- return (112 * r - 94 * g - 18 * b + 0x8080) >> 8;
-}
-
-#define MAKEROWY(NAME, R, G, B, BPP) \
-void NAME ## ToYRow_C(const uint8* src_argb0, uint8* dst_y, int width) { \
- int x; \
- for (x = 0; x < width; ++x) { \
- dst_y[0] = RGBToY(src_argb0[R], src_argb0[G], src_argb0[B]); \
- src_argb0 += BPP; \
- dst_y += 1; \
- } \
-} \
-void NAME ## ToUVRow_C(const uint8* src_rgb0, int src_stride_rgb, \
- uint8* dst_u, uint8* dst_v, int width) { \
- const uint8* src_rgb1 = src_rgb0 + src_stride_rgb; \
- int x; \
- for (x = 0; x < width - 1; x += 2) { \
- uint8 ab = (src_rgb0[B] + src_rgb0[B + BPP] + \
- src_rgb1[B] + src_rgb1[B + BPP]) >> 2; \
- uint8 ag = (src_rgb0[G] + src_rgb0[G + BPP] + \
- src_rgb1[G] + src_rgb1[G + BPP]) >> 2; \
- uint8 ar = (src_rgb0[R] + src_rgb0[R + BPP] + \
- src_rgb1[R] + src_rgb1[R + BPP]) >> 2; \
- dst_u[0] = RGBToU(ar, ag, ab); \
- dst_v[0] = RGBToV(ar, ag, ab); \
- src_rgb0 += BPP * 2; \
- src_rgb1 += BPP * 2; \
- dst_u += 1; \
- dst_v += 1; \
- } \
- if (width & 1) { \
- uint8 ab = (src_rgb0[B] + src_rgb1[B]) >> 1; \
- uint8 ag = (src_rgb0[G] + src_rgb1[G]) >> 1; \
- uint8 ar = (src_rgb0[R] + src_rgb1[R]) >> 1; \
- dst_u[0] = RGBToU(ar, ag, ab); \
- dst_v[0] = RGBToV(ar, ag, ab); \
- } \
-}
-
-MAKEROWY(ARGB, 2, 1, 0, 4)
-MAKEROWY(BGRA, 1, 2, 3, 4)
-MAKEROWY(ABGR, 0, 1, 2, 4)
-MAKEROWY(RGBA, 3, 2, 1, 4)
-MAKEROWY(RGB24, 2, 1, 0, 3)
-MAKEROWY(RAW, 0, 1, 2, 3)
-#undef MAKEROWY
-
-// JPeg uses a variation on BT.601-1 full range
-// y = 0.29900 * r + 0.58700 * g + 0.11400 * b
-// u = -0.16874 * r - 0.33126 * g + 0.50000 * b + center
-// v = 0.50000 * r - 0.41869 * g - 0.08131 * b + center
-// BT.601 Mpeg range uses:
-// b 0.1016 * 255 = 25.908 = 25
-// g 0.5078 * 255 = 129.489 = 129
-// r 0.2578 * 255 = 65.739 = 66
-// JPeg 8 bit Y (not used):
-// b 0.11400 * 256 = 29.184 = 29
-// g 0.58700 * 256 = 150.272 = 150
-// r 0.29900 * 256 = 76.544 = 77
-// JPeg 7 bit Y:
-// b 0.11400 * 128 = 14.592 = 15
-// g 0.58700 * 128 = 75.136 = 75
-// r 0.29900 * 128 = 38.272 = 38
-// JPeg 8 bit U:
-// b 0.50000 * 255 = 127.5 = 127
-// g -0.33126 * 255 = -84.4713 = -84
-// r -0.16874 * 255 = -43.0287 = -43
-// JPeg 8 bit V:
-// b -0.08131 * 255 = -20.73405 = -20
-// g -0.41869 * 255 = -106.76595 = -107
-// r 0.50000 * 255 = 127.5 = 127
-
-static __inline int RGBToYJ(uint8 r, uint8 g, uint8 b) {
- return (38 * r + 75 * g + 15 * b + 64) >> 7;
-}
-
-static __inline int RGBToUJ(uint8 r, uint8 g, uint8 b) {
- return (127 * b - 84 * g - 43 * r + 0x8080) >> 8;
-}
-static __inline int RGBToVJ(uint8 r, uint8 g, uint8 b) {
- return (127 * r - 107 * g - 20 * b + 0x8080) >> 8;
-}
-
-#define AVGB(a, b) (((a) + (b) + 1) >> 1)
-
-#define MAKEROWYJ(NAME, R, G, B, BPP) \
-void NAME ## ToYJRow_C(const uint8* src_argb0, uint8* dst_y, int width) { \
- int x; \
- for (x = 0; x < width; ++x) { \
- dst_y[0] = RGBToYJ(src_argb0[R], src_argb0[G], src_argb0[B]); \
- src_argb0 += BPP; \
- dst_y += 1; \
- } \
-} \
-void NAME ## ToUVJRow_C(const uint8* src_rgb0, int src_stride_rgb, \
- uint8* dst_u, uint8* dst_v, int width) { \
- const uint8* src_rgb1 = src_rgb0 + src_stride_rgb; \
- int x; \
- for (x = 0; x < width - 1; x += 2) { \
- uint8 ab = AVGB(AVGB(src_rgb0[B], src_rgb1[B]), \
- AVGB(src_rgb0[B + BPP], src_rgb1[B + BPP])); \
- uint8 ag = AVGB(AVGB(src_rgb0[G], src_rgb1[G]), \
- AVGB(src_rgb0[G + BPP], src_rgb1[G + BPP])); \
- uint8 ar = AVGB(AVGB(src_rgb0[R], src_rgb1[R]), \
- AVGB(src_rgb0[R + BPP], src_rgb1[R + BPP])); \
- dst_u[0] = RGBToUJ(ar, ag, ab); \
- dst_v[0] = RGBToVJ(ar, ag, ab); \
- src_rgb0 += BPP * 2; \
- src_rgb1 += BPP * 2; \
- dst_u += 1; \
- dst_v += 1; \
- } \
- if (width & 1) { \
- uint8 ab = AVGB(src_rgb0[B], src_rgb1[B]); \
- uint8 ag = AVGB(src_rgb0[G], src_rgb1[G]); \
- uint8 ar = AVGB(src_rgb0[R], src_rgb1[R]); \
- dst_u[0] = RGBToUJ(ar, ag, ab); \
- dst_v[0] = RGBToVJ(ar, ag, ab); \
- } \
-}
-
-MAKEROWYJ(ARGB, 2, 1, 0, 4)
-#undef MAKEROWYJ
-
-void RGB565ToYRow_C(const uint8* src_rgb565, uint8* dst_y, int width) {
- int x;
- for (x = 0; x < width; ++x) {
- uint8 b = src_rgb565[0] & 0x1f;
- uint8 g = (src_rgb565[0] >> 5) | ((src_rgb565[1] & 0x07) << 3);
- uint8 r = src_rgb565[1] >> 3;
- b = (b << 3) | (b >> 2);
- g = (g << 2) | (g >> 4);
- r = (r << 3) | (r >> 2);
- dst_y[0] = RGBToY(r, g, b);
- src_rgb565 += 2;
- dst_y += 1;
- }
-}
-
-void ARGB1555ToYRow_C(const uint8* src_argb1555, uint8* dst_y, int width) {
- int x;
- for (x = 0; x < width; ++x) {
- uint8 b = src_argb1555[0] & 0x1f;
- uint8 g = (src_argb1555[0] >> 5) | ((src_argb1555[1] & 0x03) << 3);
- uint8 r = (src_argb1555[1] & 0x7c) >> 2;
- b = (b << 3) | (b >> 2);
- g = (g << 3) | (g >> 2);
- r = (r << 3) | (r >> 2);
- dst_y[0] = RGBToY(r, g, b);
- src_argb1555 += 2;
- dst_y += 1;
- }
-}
-
-void ARGB4444ToYRow_C(const uint8* src_argb4444, uint8* dst_y, int width) {
- int x;
- for (x = 0; x < width; ++x) {
- uint8 b = src_argb4444[0] & 0x0f;
- uint8 g = src_argb4444[0] >> 4;
- uint8 r = src_argb4444[1] & 0x0f;
- b = (b << 4) | b;
- g = (g << 4) | g;
- r = (r << 4) | r;
- dst_y[0] = RGBToY(r, g, b);
- src_argb4444 += 2;
- dst_y += 1;
- }
-}
-
-void RGB565ToUVRow_C(const uint8* src_rgb565, int src_stride_rgb565,
- uint8* dst_u, uint8* dst_v, int width) {
- const uint8* next_rgb565 = src_rgb565 + src_stride_rgb565;
- int x;
- for (x = 0; x < width - 1; x += 2) {
- uint8 b0 = src_rgb565[0] & 0x1f;
- uint8 g0 = (src_rgb565[0] >> 5) | ((src_rgb565[1] & 0x07) << 3);
- uint8 r0 = src_rgb565[1] >> 3;
- uint8 b1 = src_rgb565[2] & 0x1f;
- uint8 g1 = (src_rgb565[2] >> 5) | ((src_rgb565[3] & 0x07) << 3);
- uint8 r1 = src_rgb565[3] >> 3;
- uint8 b2 = next_rgb565[0] & 0x1f;
- uint8 g2 = (next_rgb565[0] >> 5) | ((next_rgb565[1] & 0x07) << 3);
- uint8 r2 = next_rgb565[1] >> 3;
- uint8 b3 = next_rgb565[2] & 0x1f;
- uint8 g3 = (next_rgb565[2] >> 5) | ((next_rgb565[3] & 0x07) << 3);
- uint8 r3 = next_rgb565[3] >> 3;
- uint8 b = (b0 + b1 + b2 + b3); // 565 * 4 = 787.
- uint8 g = (g0 + g1 + g2 + g3);
- uint8 r = (r0 + r1 + r2 + r3);
- b = (b << 1) | (b >> 6); // 787 -> 888.
- r = (r << 1) | (r >> 6);
- dst_u[0] = RGBToU(r, g, b);
- dst_v[0] = RGBToV(r, g, b);
- src_rgb565 += 4;
- next_rgb565 += 4;
- dst_u += 1;
- dst_v += 1;
- }
- if (width & 1) {
- uint8 b0 = src_rgb565[0] & 0x1f;
- uint8 g0 = (src_rgb565[0] >> 5) | ((src_rgb565[1] & 0x07) << 3);
- uint8 r0 = src_rgb565[1] >> 3;
- uint8 b2 = next_rgb565[0] & 0x1f;
- uint8 g2 = (next_rgb565[0] >> 5) | ((next_rgb565[1] & 0x07) << 3);
- uint8 r2 = next_rgb565[1] >> 3;
- uint8 b = (b0 + b2); // 565 * 2 = 676.
- uint8 g = (g0 + g2);
- uint8 r = (r0 + r2);
- b = (b << 2) | (b >> 4); // 676 -> 888
- g = (g << 1) | (g >> 6);
- r = (r << 2) | (r >> 4);
- dst_u[0] = RGBToU(r, g, b);
- dst_v[0] = RGBToV(r, g, b);
- }
-}
-
-void ARGB1555ToUVRow_C(const uint8* src_argb1555, int src_stride_argb1555,
- uint8* dst_u, uint8* dst_v, int width) {
- const uint8* next_argb1555 = src_argb1555 + src_stride_argb1555;
- int x;
- for (x = 0; x < width - 1; x += 2) {
- uint8 b0 = src_argb1555[0] & 0x1f;
- uint8 g0 = (src_argb1555[0] >> 5) | ((src_argb1555[1] & 0x03) << 3);
- uint8 r0 = (src_argb1555[1] & 0x7c) >> 2;
- uint8 b1 = src_argb1555[2] & 0x1f;
- uint8 g1 = (src_argb1555[2] >> 5) | ((src_argb1555[3] & 0x03) << 3);
- uint8 r1 = (src_argb1555[3] & 0x7c) >> 2;
- uint8 b2 = next_argb1555[0] & 0x1f;
- uint8 g2 = (next_argb1555[0] >> 5) | ((next_argb1555[1] & 0x03) << 3);
- uint8 r2 = (next_argb1555[1] & 0x7c) >> 2;
- uint8 b3 = next_argb1555[2] & 0x1f;
- uint8 g3 = (next_argb1555[2] >> 5) | ((next_argb1555[3] & 0x03) << 3);
- uint8 r3 = (next_argb1555[3] & 0x7c) >> 2;
- uint8 b = (b0 + b1 + b2 + b3); // 555 * 4 = 777.
- uint8 g = (g0 + g1 + g2 + g3);
- uint8 r = (r0 + r1 + r2 + r3);
- b = (b << 1) | (b >> 6); // 777 -> 888.
- g = (g << 1) | (g >> 6);
- r = (r << 1) | (r >> 6);
- dst_u[0] = RGBToU(r, g, b);
- dst_v[0] = RGBToV(r, g, b);
- src_argb1555 += 4;
- next_argb1555 += 4;
- dst_u += 1;
- dst_v += 1;
- }
- if (width & 1) {
- uint8 b0 = src_argb1555[0] & 0x1f;
- uint8 g0 = (src_argb1555[0] >> 5) | ((src_argb1555[1] & 0x03) << 3);
- uint8 r0 = (src_argb1555[1] & 0x7c) >> 2;
- uint8 b2 = next_argb1555[0] & 0x1f;
- uint8 g2 = (next_argb1555[0] >> 5) | ((next_argb1555[1] & 0x03) << 3);
- uint8 r2 = next_argb1555[1] >> 3;
- uint8 b = (b0 + b2); // 555 * 2 = 666.
- uint8 g = (g0 + g2);
- uint8 r = (r0 + r2);
- b = (b << 2) | (b >> 4); // 666 -> 888.
- g = (g << 2) | (g >> 4);
- r = (r << 2) | (r >> 4);
- dst_u[0] = RGBToU(r, g, b);
- dst_v[0] = RGBToV(r, g, b);
- }
-}
-
-void ARGB4444ToUVRow_C(const uint8* src_argb4444, int src_stride_argb4444,
- uint8* dst_u, uint8* dst_v, int width) {
- const uint8* next_argb4444 = src_argb4444 + src_stride_argb4444;
- int x;
- for (x = 0; x < width - 1; x += 2) {
- uint8 b0 = src_argb4444[0] & 0x0f;
- uint8 g0 = src_argb4444[0] >> 4;
- uint8 r0 = src_argb4444[1] & 0x0f;
- uint8 b1 = src_argb4444[2] & 0x0f;
- uint8 g1 = src_argb4444[2] >> 4;
- uint8 r1 = src_argb4444[3] & 0x0f;
- uint8 b2 = next_argb4444[0] & 0x0f;
- uint8 g2 = next_argb4444[0] >> 4;
- uint8 r2 = next_argb4444[1] & 0x0f;
- uint8 b3 = next_argb4444[2] & 0x0f;
- uint8 g3 = next_argb4444[2] >> 4;
- uint8 r3 = next_argb4444[3] & 0x0f;
- uint8 b = (b0 + b1 + b2 + b3); // 444 * 4 = 666.
- uint8 g = (g0 + g1 + g2 + g3);
- uint8 r = (r0 + r1 + r2 + r3);
- b = (b << 2) | (b >> 4); // 666 -> 888.
- g = (g << 2) | (g >> 4);
- r = (r << 2) | (r >> 4);
- dst_u[0] = RGBToU(r, g, b);
- dst_v[0] = RGBToV(r, g, b);
- src_argb4444 += 4;
- next_argb4444 += 4;
- dst_u += 1;
- dst_v += 1;
- }
- if (width & 1) {
- uint8 b0 = src_argb4444[0] & 0x0f;
- uint8 g0 = src_argb4444[0] >> 4;
- uint8 r0 = src_argb4444[1] & 0x0f;
- uint8 b2 = next_argb4444[0] & 0x0f;
- uint8 g2 = next_argb4444[0] >> 4;
- uint8 r2 = next_argb4444[1] & 0x0f;
- uint8 b = (b0 + b2); // 444 * 2 = 555.
- uint8 g = (g0 + g2);
- uint8 r = (r0 + r2);
- b = (b << 3) | (b >> 2); // 555 -> 888.
- g = (g << 3) | (g >> 2);
- r = (r << 3) | (r >> 2);
- dst_u[0] = RGBToU(r, g, b);
- dst_v[0] = RGBToV(r, g, b);
- }
-}
-
-void ARGBToUV444Row_C(const uint8* src_argb,
- uint8* dst_u, uint8* dst_v, int width) {
- int x;
- for (x = 0; x < width; ++x) {
- uint8 ab = src_argb[0];
- uint8 ag = src_argb[1];
- uint8 ar = src_argb[2];
- dst_u[0] = RGBToU(ar, ag, ab);
- dst_v[0] = RGBToV(ar, ag, ab);
- src_argb += 4;
- dst_u += 1;
- dst_v += 1;
- }
-}
-
-void ARGBToUV422Row_C(const uint8* src_argb,
- uint8* dst_u, uint8* dst_v, int width) {
- int x;
- for (x = 0; x < width - 1; x += 2) {
- uint8 ab = (src_argb[0] + src_argb[4]) >> 1;
- uint8 ag = (src_argb[1] + src_argb[5]) >> 1;
- uint8 ar = (src_argb[2] + src_argb[6]) >> 1;
- dst_u[0] = RGBToU(ar, ag, ab);
- dst_v[0] = RGBToV(ar, ag, ab);
- src_argb += 8;
- dst_u += 1;
- dst_v += 1;
- }
- if (width & 1) {
- uint8 ab = src_argb[0];
- uint8 ag = src_argb[1];
- uint8 ar = src_argb[2];
- dst_u[0] = RGBToU(ar, ag, ab);
- dst_v[0] = RGBToV(ar, ag, ab);
- }
-}
-
-void ARGBToUV411Row_C(const uint8* src_argb,
- uint8* dst_u, uint8* dst_v, int width) {
- int x;
- for (x = 0; x < width - 3; x += 4) {
- uint8 ab = (src_argb[0] + src_argb[4] + src_argb[8] + src_argb[12]) >> 2;
- uint8 ag = (src_argb[1] + src_argb[5] + src_argb[9] + src_argb[13]) >> 2;
- uint8 ar = (src_argb[2] + src_argb[6] + src_argb[10] + src_argb[14]) >> 2;
- dst_u[0] = RGBToU(ar, ag, ab);
- dst_v[0] = RGBToV(ar, ag, ab);
- src_argb += 16;
- dst_u += 1;
- dst_v += 1;
- }
- if ((width & 3) == 3) {
- uint8 ab = (src_argb[0] + src_argb[4] + src_argb[8]) / 3;
- uint8 ag = (src_argb[1] + src_argb[5] + src_argb[9]) / 3;
- uint8 ar = (src_argb[2] + src_argb[6] + src_argb[10]) / 3;
- dst_u[0] = RGBToU(ar, ag, ab);
- dst_v[0] = RGBToV(ar, ag, ab);
- } else if ((width & 3) == 2) {
- uint8 ab = (src_argb[0] + src_argb[4]) >> 1;
- uint8 ag = (src_argb[1] + src_argb[5]) >> 1;
- uint8 ar = (src_argb[2] + src_argb[6]) >> 1;
- dst_u[0] = RGBToU(ar, ag, ab);
- dst_v[0] = RGBToV(ar, ag, ab);
- } else if ((width & 3) == 1) {
- uint8 ab = src_argb[0];
- uint8 ag = src_argb[1];
- uint8 ar = src_argb[2];
- dst_u[0] = RGBToU(ar, ag, ab);
- dst_v[0] = RGBToV(ar, ag, ab);
- }
-}
-
-void ARGBGrayRow_C(const uint8* src_argb, uint8* dst_argb, int width) {
- int x;
- for (x = 0; x < width; ++x) {
- uint8 y = RGBToYJ(src_argb[2], src_argb[1], src_argb[0]);
- dst_argb[2] = dst_argb[1] = dst_argb[0] = y;
- dst_argb[3] = src_argb[3];
- dst_argb += 4;
- src_argb += 4;
- }
-}
-
-// Convert a row of image to Sepia tone.
-void ARGBSepiaRow_C(uint8* dst_argb, int width) {
- int x;
- for (x = 0; x < width; ++x) {
- int b = dst_argb[0];
- int g = dst_argb[1];
- int r = dst_argb[2];
- int sb = (b * 17 + g * 68 + r * 35) >> 7;
- int sg = (b * 22 + g * 88 + r * 45) >> 7;
- int sr = (b * 24 + g * 98 + r * 50) >> 7;
- // b does not over flow. a is preserved from original.
- dst_argb[0] = sb;
- dst_argb[1] = clamp255(sg);
- dst_argb[2] = clamp255(sr);
- dst_argb += 4;
- }
-}
-
-// Apply color matrix to a row of image. Matrix is signed.
-// TODO(fbarchard): Consider adding rounding (+32).
-void ARGBColorMatrixRow_C(const uint8* src_argb, uint8* dst_argb,
- const int8* matrix_argb, int width) {
- int x;
- for (x = 0; x < width; ++x) {
- int b = src_argb[0];
- int g = src_argb[1];
- int r = src_argb[2];
- int a = src_argb[3];
- int sb = (b * matrix_argb[0] + g * matrix_argb[1] +
- r * matrix_argb[2] + a * matrix_argb[3]) >> 6;
- int sg = (b * matrix_argb[4] + g * matrix_argb[5] +
- r * matrix_argb[6] + a * matrix_argb[7]) >> 6;
- int sr = (b * matrix_argb[8] + g * matrix_argb[9] +
- r * matrix_argb[10] + a * matrix_argb[11]) >> 6;
- int sa = (b * matrix_argb[12] + g * matrix_argb[13] +
- r * matrix_argb[14] + a * matrix_argb[15]) >> 6;
- dst_argb[0] = Clamp(sb);
- dst_argb[1] = Clamp(sg);
- dst_argb[2] = Clamp(sr);
- dst_argb[3] = Clamp(sa);
- src_argb += 4;
- dst_argb += 4;
- }
-}
-
-// Apply color table to a row of image.
-void ARGBColorTableRow_C(uint8* dst_argb, const uint8* table_argb, int width) {
- int x;
- for (x = 0; x < width; ++x) {
- int b = dst_argb[0];
- int g = dst_argb[1];
- int r = dst_argb[2];
- int a = dst_argb[3];
- dst_argb[0] = table_argb[b * 4 + 0];
- dst_argb[1] = table_argb[g * 4 + 1];
- dst_argb[2] = table_argb[r * 4 + 2];
- dst_argb[3] = table_argb[a * 4 + 3];
- dst_argb += 4;
- }
-}
-
-// Apply color table to a row of image.
-void RGBColorTableRow_C(uint8* dst_argb, const uint8* table_argb, int width) {
- int x;
- for (x = 0; x < width; ++x) {
- int b = dst_argb[0];
- int g = dst_argb[1];
- int r = dst_argb[2];
- dst_argb[0] = table_argb[b * 4 + 0];
- dst_argb[1] = table_argb[g * 4 + 1];
- dst_argb[2] = table_argb[r * 4 + 2];
- dst_argb += 4;
- }
-}
-
-void ARGBQuantizeRow_C(uint8* dst_argb, int scale, int interval_size,
- int interval_offset, int width) {
- int x;
- for (x = 0; x < width; ++x) {
- int b = dst_argb[0];
- int g = dst_argb[1];
- int r = dst_argb[2];
- dst_argb[0] = (b * scale >> 16) * interval_size + interval_offset;
- dst_argb[1] = (g * scale >> 16) * interval_size + interval_offset;
- dst_argb[2] = (r * scale >> 16) * interval_size + interval_offset;
- dst_argb += 4;
- }
-}
-
-#define REPEAT8(v) (v) | ((v) << 8)
-#define SHADE(f, v) v * f >> 24
-
-void ARGBShadeRow_C(const uint8* src_argb, uint8* dst_argb, int width,
- uint32 value) {
- const uint32 b_scale = REPEAT8(value & 0xff);
- const uint32 g_scale = REPEAT8((value >> 8) & 0xff);
- const uint32 r_scale = REPEAT8((value >> 16) & 0xff);
- const uint32 a_scale = REPEAT8(value >> 24);
-
- int i;
- for (i = 0; i < width; ++i) {
- const uint32 b = REPEAT8(src_argb[0]);
- const uint32 g = REPEAT8(src_argb[1]);
- const uint32 r = REPEAT8(src_argb[2]);
- const uint32 a = REPEAT8(src_argb[3]);
- dst_argb[0] = SHADE(b, b_scale);
- dst_argb[1] = SHADE(g, g_scale);
- dst_argb[2] = SHADE(r, r_scale);
- dst_argb[3] = SHADE(a, a_scale);
- src_argb += 4;
- dst_argb += 4;
- }
-}
-#undef REPEAT8
-#undef SHADE
-
-#define REPEAT8(v) (v) | ((v) << 8)
-#define SHADE(f, v) v * f >> 16
-
-void ARGBMultiplyRow_C(const uint8* src_argb0, const uint8* src_argb1,
- uint8* dst_argb, int width) {
- int i;
- for (i = 0; i < width; ++i) {
- const uint32 b = REPEAT8(src_argb0[0]);
- const uint32 g = REPEAT8(src_argb0[1]);
- const uint32 r = REPEAT8(src_argb0[2]);
- const uint32 a = REPEAT8(src_argb0[3]);
- const uint32 b_scale = src_argb1[0];
- const uint32 g_scale = src_argb1[1];
- const uint32 r_scale = src_argb1[2];
- const uint32 a_scale = src_argb1[3];
- dst_argb[0] = SHADE(b, b_scale);
- dst_argb[1] = SHADE(g, g_scale);
- dst_argb[2] = SHADE(r, r_scale);
- dst_argb[3] = SHADE(a, a_scale);
- src_argb0 += 4;
- src_argb1 += 4;
- dst_argb += 4;
- }
-}
-#undef REPEAT8
-#undef SHADE
-
-#define SHADE(f, v) clamp255(v + f)
-
-void ARGBAddRow_C(const uint8* src_argb0, const uint8* src_argb1,
- uint8* dst_argb, int width) {
- int i;
- for (i = 0; i < width; ++i) {
- const int b = src_argb0[0];
- const int g = src_argb0[1];
- const int r = src_argb0[2];
- const int a = src_argb0[3];
- const int b_add = src_argb1[0];
- const int g_add = src_argb1[1];
- const int r_add = src_argb1[2];
- const int a_add = src_argb1[3];
- dst_argb[0] = SHADE(b, b_add);
- dst_argb[1] = SHADE(g, g_add);
- dst_argb[2] = SHADE(r, r_add);
- dst_argb[3] = SHADE(a, a_add);
- src_argb0 += 4;
- src_argb1 += 4;
- dst_argb += 4;
- }
-}
-#undef SHADE
-
-#define SHADE(f, v) clamp0(f - v)
-
-void ARGBSubtractRow_C(const uint8* src_argb0, const uint8* src_argb1,
- uint8* dst_argb, int width) {
- int i;
- for (i = 0; i < width; ++i) {
- const int b = src_argb0[0];
- const int g = src_argb0[1];
- const int r = src_argb0[2];
- const int a = src_argb0[3];
- const int b_sub = src_argb1[0];
- const int g_sub = src_argb1[1];
- const int r_sub = src_argb1[2];
- const int a_sub = src_argb1[3];
- dst_argb[0] = SHADE(b, b_sub);
- dst_argb[1] = SHADE(g, g_sub);
- dst_argb[2] = SHADE(r, r_sub);
- dst_argb[3] = SHADE(a, a_sub);
- src_argb0 += 4;
- src_argb1 += 4;
- dst_argb += 4;
- }
-}
-#undef SHADE
-
-// Sobel functions which mimics SSSE3.
-void SobelXRow_C(const uint8* src_y0, const uint8* src_y1, const uint8* src_y2,
- uint8* dst_sobelx, int width) {
- int i;
- for (i = 0; i < width; ++i) {
- int a = src_y0[i];
- int b = src_y1[i];
- int c = src_y2[i];
- int a_sub = src_y0[i + 2];
- int b_sub = src_y1[i + 2];
- int c_sub = src_y2[i + 2];
- int a_diff = a - a_sub;
- int b_diff = b - b_sub;
- int c_diff = c - c_sub;
- int sobel = Abs(a_diff + b_diff * 2 + c_diff);
- dst_sobelx[i] = (uint8)(clamp255(sobel));
- }
-}
-
-void SobelYRow_C(const uint8* src_y0, const uint8* src_y1,
- uint8* dst_sobely, int width) {
- int i;
- for (i = 0; i < width; ++i) {
- int a = src_y0[i + 0];
- int b = src_y0[i + 1];
- int c = src_y0[i + 2];
- int a_sub = src_y1[i + 0];
- int b_sub = src_y1[i + 1];
- int c_sub = src_y1[i + 2];
- int a_diff = a - a_sub;
- int b_diff = b - b_sub;
- int c_diff = c - c_sub;
- int sobel = Abs(a_diff + b_diff * 2 + c_diff);
- dst_sobely[i] = (uint8)(clamp255(sobel));
- }
-}
-
-void SobelRow_C(const uint8* src_sobelx, const uint8* src_sobely,
- uint8* dst_argb, int width) {
- int i;
- for (i = 0; i < width; ++i) {
- int r = src_sobelx[i];
- int b = src_sobely[i];
- int s = clamp255(r + b);
- dst_argb[0] = (uint8)(s);
- dst_argb[1] = (uint8)(s);
- dst_argb[2] = (uint8)(s);
- dst_argb[3] = (uint8)(255u);
- dst_argb += 4;
- }
-}
-
-void SobelToPlaneRow_C(const uint8* src_sobelx, const uint8* src_sobely,
- uint8* dst_y, int width) {
- int i;
- for (i = 0; i < width; ++i) {
- int r = src_sobelx[i];
- int b = src_sobely[i];
- int s = clamp255(r + b);
- dst_y[i] = (uint8)(s);
- }
-}
-
-void SobelXYRow_C(const uint8* src_sobelx, const uint8* src_sobely,
- uint8* dst_argb, int width) {
- int i;
- for (i = 0; i < width; ++i) {
- int r = src_sobelx[i];
- int b = src_sobely[i];
- int g = clamp255(r + b);
- dst_argb[0] = (uint8)(b);
- dst_argb[1] = (uint8)(g);
- dst_argb[2] = (uint8)(r);
- dst_argb[3] = (uint8)(255u);
- dst_argb += 4;
- }
-}
-
-void I400ToARGBRow_C(const uint8* src_y, uint8* dst_argb, int width) {
- // Copy a Y to RGB.
- int x;
- for (x = 0; x < width; ++x) {
- uint8 y = src_y[0];
- dst_argb[2] = dst_argb[1] = dst_argb[0] = y;
- dst_argb[3] = 255u;
- dst_argb += 4;
- ++src_y;
- }
-}
-
-// C reference code that mimics the YUV assembly.
-
-#define YG 74 /* (int8)(1.164 * 64 + 0.5) */
-
-#define UB 127 /* min(63,(int8)(2.018 * 64)) */
-#define UG -25 /* (int8)(-0.391 * 64 - 0.5) */
-#define UR 0
-
-#define VB 0
-#define VG -52 /* (int8)(-0.813 * 64 - 0.5) */
-#define VR 102 /* (int8)(1.596 * 64 + 0.5) */
-
-// Bias
-#define BB UB * 128 + VB * 128
-#define BG UG * 128 + VG * 128
-#define BR UR * 128 + VR * 128
-
-static __inline void YuvPixel(uint8 y, uint8 u, uint8 v,
- uint8* b, uint8* g, uint8* r) {
- int32 y1 = ((int32)(y) - 16) * YG;
- *b = Clamp((int32)((u * UB + v * VB) - (BB) + y1) >> 6);
- *g = Clamp((int32)((u * UG + v * VG) - (BG) + y1) >> 6);
- *r = Clamp((int32)((u * UR + v * VR) - (BR) + y1) >> 6);
-}
-
-#if !defined(LIBYUV_DISABLE_NEON) && \
- (defined(__ARM_NEON__) || defined(LIBYUV_NEON))
-// C mimic assembly.
-// TODO(fbarchard): Remove subsampling from Neon.
-void I444ToARGBRow_C(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* rgb_buf,
- int width) {
- int x;
- for (x = 0; x < width - 1; x += 2) {
- uint8 u = (src_u[0] + src_u[1] + 1) >> 1;
- uint8 v = (src_v[0] + src_v[1] + 1) >> 1;
- YuvPixel(src_y[0], u, v, rgb_buf + 0, rgb_buf + 1, rgb_buf + 2);
- rgb_buf[3] = 255;
- YuvPixel(src_y[1], u, v, rgb_buf + 4, rgb_buf + 5, rgb_buf + 6);
- rgb_buf[7] = 255;
- src_y += 2;
- src_u += 2;
- src_v += 2;
- rgb_buf += 8; // Advance 2 pixels.
- }
- if (width & 1) {
- YuvPixel(src_y[0], src_u[0], src_v[0],
- rgb_buf + 0, rgb_buf + 1, rgb_buf + 2);
- }
-}
-#else
-void I444ToARGBRow_C(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* rgb_buf,
- int width) {
- int x;
- for (x = 0; x < width; ++x) {
- YuvPixel(src_y[0], src_u[0], src_v[0],
- rgb_buf + 0, rgb_buf + 1, rgb_buf + 2);
- rgb_buf[3] = 255;
- src_y += 1;
- src_u += 1;
- src_v += 1;
- rgb_buf += 4; // Advance 1 pixel.
- }
-}
-#endif
-// Also used for 420
-void I422ToARGBRow_C(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* rgb_buf,
- int width) {
- int x;
- for (x = 0; x < width - 1; x += 2) {
- YuvPixel(src_y[0], src_u[0], src_v[0],
- rgb_buf + 0, rgb_buf + 1, rgb_buf + 2);
- rgb_buf[3] = 255;
- YuvPixel(src_y[1], src_u[0], src_v[0],
- rgb_buf + 4, rgb_buf + 5, rgb_buf + 6);
- rgb_buf[7] = 255;
- src_y += 2;
- src_u += 1;
- src_v += 1;
- rgb_buf += 8; // Advance 2 pixels.
- }
- if (width & 1) {
- YuvPixel(src_y[0], src_u[0], src_v[0],
- rgb_buf + 0, rgb_buf + 1, rgb_buf + 2);
- rgb_buf[3] = 255;
- }
-}
-
-void I422ToRGB24Row_C(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* rgb_buf,
- int width) {
- int x;
- for (x = 0; x < width - 1; x += 2) {
- YuvPixel(src_y[0], src_u[0], src_v[0],
- rgb_buf + 0, rgb_buf + 1, rgb_buf + 2);
- YuvPixel(src_y[1], src_u[0], src_v[0],
- rgb_buf + 3, rgb_buf + 4, rgb_buf + 5);
- src_y += 2;
- src_u += 1;
- src_v += 1;
- rgb_buf += 6; // Advance 2 pixels.
- }
- if (width & 1) {
- YuvPixel(src_y[0], src_u[0], src_v[0],
- rgb_buf + 0, rgb_buf + 1, rgb_buf + 2);
- }
-}
-
-void I422ToRAWRow_C(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* rgb_buf,
- int width) {
- int x;
- for (x = 0; x < width - 1; x += 2) {
- YuvPixel(src_y[0], src_u[0], src_v[0],
- rgb_buf + 2, rgb_buf + 1, rgb_buf + 0);
- YuvPixel(src_y[1], src_u[0], src_v[0],
- rgb_buf + 5, rgb_buf + 4, rgb_buf + 3);
- src_y += 2;
- src_u += 1;
- src_v += 1;
- rgb_buf += 6; // Advance 2 pixels.
- }
- if (width & 1) {
- YuvPixel(src_y[0], src_u[0], src_v[0],
- rgb_buf + 2, rgb_buf + 1, rgb_buf + 0);
- }
-}
-
-void I422ToARGB4444Row_C(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb4444,
- int width) {
- uint8 b0;
- uint8 g0;
- uint8 r0;
- uint8 b1;
- uint8 g1;
- uint8 r1;
- int x;
- for (x = 0; x < width - 1; x += 2) {
- YuvPixel(src_y[0], src_u[0], src_v[0], &b0, &g0, &r0);
- YuvPixel(src_y[1], src_u[0], src_v[0], &b1, &g1, &r1);
- b0 = b0 >> 4;
- g0 = g0 >> 4;
- r0 = r0 >> 4;
- b1 = b1 >> 4;
- g1 = g1 >> 4;
- r1 = r1 >> 4;
- *(uint32*)(dst_argb4444) = b0 | (g0 << 4) | (r0 << 8) |
- (b1 << 16) | (g1 << 20) | (r1 << 24) | 0xf000f000;
- src_y += 2;
- src_u += 1;
- src_v += 1;
- dst_argb4444 += 4; // Advance 2 pixels.
- }
- if (width & 1) {
- YuvPixel(src_y[0], src_u[0], src_v[0], &b0, &g0, &r0);
- b0 = b0 >> 4;
- g0 = g0 >> 4;
- r0 = r0 >> 4;
- *(uint16*)(dst_argb4444) = b0 | (g0 << 4) | (r0 << 8) |
- 0xf000;
- }
-}
-
-void I422ToARGB1555Row_C(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb1555,
- int width) {
- uint8 b0;
- uint8 g0;
- uint8 r0;
- uint8 b1;
- uint8 g1;
- uint8 r1;
- int x;
- for (x = 0; x < width - 1; x += 2) {
- YuvPixel(src_y[0], src_u[0], src_v[0], &b0, &g0, &r0);
- YuvPixel(src_y[1], src_u[0], src_v[0], &b1, &g1, &r1);
- b0 = b0 >> 3;
- g0 = g0 >> 3;
- r0 = r0 >> 3;
- b1 = b1 >> 3;
- g1 = g1 >> 3;
- r1 = r1 >> 3;
- *(uint32*)(dst_argb1555) = b0 | (g0 << 5) | (r0 << 10) |
- (b1 << 16) | (g1 << 21) | (r1 << 26) | 0x80008000;
- src_y += 2;
- src_u += 1;
- src_v += 1;
- dst_argb1555 += 4; // Advance 2 pixels.
- }
- if (width & 1) {
- YuvPixel(src_y[0], src_u[0], src_v[0], &b0, &g0, &r0);
- b0 = b0 >> 3;
- g0 = g0 >> 3;
- r0 = r0 >> 3;
- *(uint16*)(dst_argb1555) = b0 | (g0 << 5) | (r0 << 10) |
- 0x8000;
- }
-}
-
-void I422ToRGB565Row_C(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_rgb565,
- int width) {
- uint8 b0;
- uint8 g0;
- uint8 r0;
- uint8 b1;
- uint8 g1;
- uint8 r1;
- int x;
- for (x = 0; x < width - 1; x += 2) {
- YuvPixel(src_y[0], src_u[0], src_v[0], &b0, &g0, &r0);
- YuvPixel(src_y[1], src_u[0], src_v[0], &b1, &g1, &r1);
- b0 = b0 >> 3;
- g0 = g0 >> 2;
- r0 = r0 >> 3;
- b1 = b1 >> 3;
- g1 = g1 >> 2;
- r1 = r1 >> 3;
- *(uint32*)(dst_rgb565) = b0 | (g0 << 5) | (r0 << 11) |
- (b1 << 16) | (g1 << 21) | (r1 << 27);
- src_y += 2;
- src_u += 1;
- src_v += 1;
- dst_rgb565 += 4; // Advance 2 pixels.
- }
- if (width & 1) {
- YuvPixel(src_y[0], src_u[0], src_v[0], &b0, &g0, &r0);
- b0 = b0 >> 3;
- g0 = g0 >> 2;
- r0 = r0 >> 3;
- *(uint16*)(dst_rgb565) = b0 | (g0 << 5) | (r0 << 11);
- }
-}
-
-void I411ToARGBRow_C(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* rgb_buf,
- int width) {
- int x;
- for (x = 0; x < width - 3; x += 4) {
- YuvPixel(src_y[0], src_u[0], src_v[0],
- rgb_buf + 0, rgb_buf + 1, rgb_buf + 2);
- rgb_buf[3] = 255;
- YuvPixel(src_y[1], src_u[0], src_v[0],
- rgb_buf + 4, rgb_buf + 5, rgb_buf + 6);
- rgb_buf[7] = 255;
- YuvPixel(src_y[2], src_u[0], src_v[0],
- rgb_buf + 8, rgb_buf + 9, rgb_buf + 10);
- rgb_buf[11] = 255;
- YuvPixel(src_y[3], src_u[0], src_v[0],
- rgb_buf + 12, rgb_buf + 13, rgb_buf + 14);
- rgb_buf[15] = 255;
- src_y += 4;
- src_u += 1;
- src_v += 1;
- rgb_buf += 16; // Advance 4 pixels.
- }
- if (width & 2) {
- YuvPixel(src_y[0], src_u[0], src_v[0],
- rgb_buf + 0, rgb_buf + 1, rgb_buf + 2);
- rgb_buf[3] = 255;
- YuvPixel(src_y[1], src_u[0], src_v[0],
- rgb_buf + 4, rgb_buf + 5, rgb_buf + 6);
- rgb_buf[7] = 255;
- src_y += 2;
- rgb_buf += 8; // Advance 2 pixels.
- }
- if (width & 1) {
- YuvPixel(src_y[0], src_u[0], src_v[0],
- rgb_buf + 0, rgb_buf + 1, rgb_buf + 2);
- rgb_buf[3] = 255;
- }
-}
-
-void NV12ToARGBRow_C(const uint8* src_y,
- const uint8* usrc_v,
- uint8* rgb_buf,
- int width) {
- int x;
- for (x = 0; x < width - 1; x += 2) {
- YuvPixel(src_y[0], usrc_v[0], usrc_v[1],
- rgb_buf + 0, rgb_buf + 1, rgb_buf + 2);
- rgb_buf[3] = 255;
- YuvPixel(src_y[1], usrc_v[0], usrc_v[1],
- rgb_buf + 4, rgb_buf + 5, rgb_buf + 6);
- rgb_buf[7] = 255;
- src_y += 2;
- usrc_v += 2;
- rgb_buf += 8; // Advance 2 pixels.
- }
- if (width & 1) {
- YuvPixel(src_y[0], usrc_v[0], usrc_v[1],
- rgb_buf + 0, rgb_buf + 1, rgb_buf + 2);
- rgb_buf[3] = 255;
- }
-}
-
-void NV21ToARGBRow_C(const uint8* src_y,
- const uint8* src_vu,
- uint8* rgb_buf,
- int width) {
- int x;
- for (x = 0; x < width - 1; x += 2) {
- YuvPixel(src_y[0], src_vu[1], src_vu[0],
- rgb_buf + 0, rgb_buf + 1, rgb_buf + 2);
- rgb_buf[3] = 255;
-
- YuvPixel(src_y[1], src_vu[1], src_vu[0],
- rgb_buf + 4, rgb_buf + 5, rgb_buf + 6);
- rgb_buf[7] = 255;
-
- src_y += 2;
- src_vu += 2;
- rgb_buf += 8; // Advance 2 pixels.
- }
- if (width & 1) {
- YuvPixel(src_y[0], src_vu[1], src_vu[0],
- rgb_buf + 0, rgb_buf + 1, rgb_buf + 2);
- rgb_buf[3] = 255;
- }
-}
-
-void NV12ToRGB565Row_C(const uint8* src_y,
- const uint8* usrc_v,
- uint8* dst_rgb565,
- int width) {
- uint8 b0;
- uint8 g0;
- uint8 r0;
- uint8 b1;
- uint8 g1;
- uint8 r1;
- int x;
- for (x = 0; x < width - 1; x += 2) {
- YuvPixel(src_y[0], usrc_v[0], usrc_v[1], &b0, &g0, &r0);
- YuvPixel(src_y[1], usrc_v[0], usrc_v[1], &b1, &g1, &r1);
- b0 = b0 >> 3;
- g0 = g0 >> 2;
- r0 = r0 >> 3;
- b1 = b1 >> 3;
- g1 = g1 >> 2;
- r1 = r1 >> 3;
- *(uint32*)(dst_rgb565) = b0 | (g0 << 5) | (r0 << 11) |
- (b1 << 16) | (g1 << 21) | (r1 << 27);
- src_y += 2;
- usrc_v += 2;
- dst_rgb565 += 4; // Advance 2 pixels.
- }
- if (width & 1) {
- YuvPixel(src_y[0], usrc_v[0], usrc_v[1], &b0, &g0, &r0);
- b0 = b0 >> 3;
- g0 = g0 >> 2;
- r0 = r0 >> 3;
- *(uint16*)(dst_rgb565) = b0 | (g0 << 5) | (r0 << 11);
- }
-}
-
-void NV21ToRGB565Row_C(const uint8* src_y,
- const uint8* vsrc_u,
- uint8* dst_rgb565,
- int width) {
- uint8 b0;
- uint8 g0;
- uint8 r0;
- uint8 b1;
- uint8 g1;
- uint8 r1;
- int x;
- for (x = 0; x < width - 1; x += 2) {
- YuvPixel(src_y[0], vsrc_u[1], vsrc_u[0], &b0, &g0, &r0);
- YuvPixel(src_y[1], vsrc_u[1], vsrc_u[0], &b1, &g1, &r1);
- b0 = b0 >> 3;
- g0 = g0 >> 2;
- r0 = r0 >> 3;
- b1 = b1 >> 3;
- g1 = g1 >> 2;
- r1 = r1 >> 3;
- *(uint32*)(dst_rgb565) = b0 | (g0 << 5) | (r0 << 11) |
- (b1 << 16) | (g1 << 21) | (r1 << 27);
- src_y += 2;
- vsrc_u += 2;
- dst_rgb565 += 4; // Advance 2 pixels.
- }
- if (width & 1) {
- YuvPixel(src_y[0], vsrc_u[1], vsrc_u[0], &b0, &g0, &r0);
- b0 = b0 >> 3;
- g0 = g0 >> 2;
- r0 = r0 >> 3;
- *(uint16*)(dst_rgb565) = b0 | (g0 << 5) | (r0 << 11);
- }
-}
-
-void YUY2ToARGBRow_C(const uint8* src_yuy2,
- uint8* rgb_buf,
- int width) {
- int x;
- for (x = 0; x < width - 1; x += 2) {
- YuvPixel(src_yuy2[0], src_yuy2[1], src_yuy2[3],
- rgb_buf + 0, rgb_buf + 1, rgb_buf + 2);
- rgb_buf[3] = 255;
- YuvPixel(src_yuy2[2], src_yuy2[1], src_yuy2[3],
- rgb_buf + 4, rgb_buf + 5, rgb_buf + 6);
- rgb_buf[7] = 255;
- src_yuy2 += 4;
- rgb_buf += 8; // Advance 2 pixels.
- }
- if (width & 1) {
- YuvPixel(src_yuy2[0], src_yuy2[1], src_yuy2[3],
- rgb_buf + 0, rgb_buf + 1, rgb_buf + 2);
- rgb_buf[3] = 255;
- }
-}
-
-void UYVYToARGBRow_C(const uint8* src_uyvy,
- uint8* rgb_buf,
- int width) {
- int x;
- for (x = 0; x < width - 1; x += 2) {
- YuvPixel(src_uyvy[1], src_uyvy[0], src_uyvy[2],
- rgb_buf + 0, rgb_buf + 1, rgb_buf + 2);
- rgb_buf[3] = 255;
- YuvPixel(src_uyvy[3], src_uyvy[0], src_uyvy[2],
- rgb_buf + 4, rgb_buf + 5, rgb_buf + 6);
- rgb_buf[7] = 255;
- src_uyvy += 4;
- rgb_buf += 8; // Advance 2 pixels.
- }
- if (width & 1) {
- YuvPixel(src_uyvy[1], src_uyvy[0], src_uyvy[2],
- rgb_buf + 0, rgb_buf + 1, rgb_buf + 2);
- rgb_buf[3] = 255;
- }
-}
-
-void I422ToBGRARow_C(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* rgb_buf,
- int width) {
- int x;
- for (x = 0; x < width - 1; x += 2) {
- YuvPixel(src_y[0], src_u[0], src_v[0],
- rgb_buf + 3, rgb_buf + 2, rgb_buf + 1);
- rgb_buf[0] = 255;
- YuvPixel(src_y[1], src_u[0], src_v[0],
- rgb_buf + 7, rgb_buf + 6, rgb_buf + 5);
- rgb_buf[4] = 255;
- src_y += 2;
- src_u += 1;
- src_v += 1;
- rgb_buf += 8; // Advance 2 pixels.
- }
- if (width & 1) {
- YuvPixel(src_y[0], src_u[0], src_v[0],
- rgb_buf + 3, rgb_buf + 2, rgb_buf + 1);
- rgb_buf[0] = 255;
- }
-}
-
-void I422ToABGRRow_C(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* rgb_buf,
- int width) {
- int x;
- for (x = 0; x < width - 1; x += 2) {
- YuvPixel(src_y[0], src_u[0], src_v[0],
- rgb_buf + 2, rgb_buf + 1, rgb_buf + 0);
- rgb_buf[3] = 255;
- YuvPixel(src_y[1], src_u[0], src_v[0],
- rgb_buf + 6, rgb_buf + 5, rgb_buf + 4);
- rgb_buf[7] = 255;
- src_y += 2;
- src_u += 1;
- src_v += 1;
- rgb_buf += 8; // Advance 2 pixels.
- }
- if (width & 1) {
- YuvPixel(src_y[0], src_u[0], src_v[0],
- rgb_buf + 2, rgb_buf + 1, rgb_buf + 0);
- rgb_buf[3] = 255;
- }
-}
-
-void I422ToRGBARow_C(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* rgb_buf,
- int width) {
- int x;
- for (x = 0; x < width - 1; x += 2) {
- YuvPixel(src_y[0], src_u[0], src_v[0],
- rgb_buf + 1, rgb_buf + 2, rgb_buf + 3);
- rgb_buf[0] = 255;
- YuvPixel(src_y[1], src_u[0], src_v[0],
- rgb_buf + 5, rgb_buf + 6, rgb_buf + 7);
- rgb_buf[4] = 255;
- src_y += 2;
- src_u += 1;
- src_v += 1;
- rgb_buf += 8; // Advance 2 pixels.
- }
- if (width & 1) {
- YuvPixel(src_y[0], src_u[0], src_v[0],
- rgb_buf + 1, rgb_buf + 2, rgb_buf + 3);
- rgb_buf[0] = 255;
- }
-}
-
-void YToARGBRow_C(const uint8* src_y, uint8* rgb_buf, int width) {
- int x;
- for (x = 0; x < width - 1; x += 2) {
- YuvPixel(src_y[0], 128, 128,
- rgb_buf + 0, rgb_buf + 1, rgb_buf + 2);
- rgb_buf[3] = 255;
- YuvPixel(src_y[1], 128, 128,
- rgb_buf + 4, rgb_buf + 5, rgb_buf + 6);
- rgb_buf[7] = 255;
- src_y += 2;
- rgb_buf += 8; // Advance 2 pixels.
- }
- if (width & 1) {
- YuvPixel(src_y[0], 128, 128,
- rgb_buf + 0, rgb_buf + 1, rgb_buf + 2);
- rgb_buf[3] = 255;
- }
-}
-
-void MirrorRow_C(const uint8* src, uint8* dst, int width) {
- int x;
- src += width - 1;
- for (x = 0; x < width - 1; x += 2) {
- dst[x] = src[0];
- dst[x + 1] = src[-1];
- src -= 2;
- }
- if (width & 1) {
- dst[width - 1] = src[0];
- }
-}
-
-void MirrorUVRow_C(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int width) {
- int x;
- src_uv += (width - 1) << 1;
- for (x = 0; x < width - 1; x += 2) {
- dst_u[x] = src_uv[0];
- dst_u[x + 1] = src_uv[-2];
- dst_v[x] = src_uv[1];
- dst_v[x + 1] = src_uv[-2 + 1];
- src_uv -= 4;
- }
- if (width & 1) {
- dst_u[width - 1] = src_uv[0];
- dst_v[width - 1] = src_uv[1];
- }
-}
-
-void ARGBMirrorRow_C(const uint8* src, uint8* dst, int width) {
- int x;
- const uint32* src32 = (const uint32*)(src);
- uint32* dst32 = (uint32*)(dst);
- src32 += width - 1;
- for (x = 0; x < width - 1; x += 2) {
- dst32[x] = src32[0];
- dst32[x + 1] = src32[-1];
- src32 -= 2;
- }
- if (width & 1) {
- dst32[width - 1] = src32[0];
- }
-}
-
-void SplitUVRow_C(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int width) {
- int x;
- for (x = 0; x < width - 1; x += 2) {
- dst_u[x] = src_uv[0];
- dst_u[x + 1] = src_uv[2];
- dst_v[x] = src_uv[1];
- dst_v[x + 1] = src_uv[3];
- src_uv += 4;
- }
- if (width & 1) {
- dst_u[width - 1] = src_uv[0];
- dst_v[width - 1] = src_uv[1];
- }
-}
-
-void MergeUVRow_C(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
- int width) {
- int x;
- for (x = 0; x < width - 1; x += 2) {
- dst_uv[0] = src_u[x];
- dst_uv[1] = src_v[x];
- dst_uv[2] = src_u[x + 1];
- dst_uv[3] = src_v[x + 1];
- dst_uv += 4;
- }
- if (width & 1) {
- dst_uv[0] = src_u[width - 1];
- dst_uv[1] = src_v[width - 1];
- }
-}
-
-void CopyRow_C(const uint8* src, uint8* dst, int count) {
- memcpy(dst, src, count);
-}
-
-void SetRow_C(uint8* dst, uint32 v8, int count) {
-#ifdef _MSC_VER
- // VC will generate rep stosb.
- int x;
- for (x = 0; x < count; ++x) {
- dst[x] = v8;
- }
-#else
- memset(dst, v8, count);
-#endif
-}
-
-void ARGBSetRows_C(uint8* dst, uint32 v32, int width,
- int dst_stride, int height) {
- int y;
- for (y = 0; y < height; ++y) {
- uint32* d = (uint32*)(dst);
- int x;
- for (x = 0; x < width; ++x) {
- d[x] = v32;
- }
- dst += dst_stride;
- }
-}
-
-// Filter 2 rows of YUY2 UV's (422) into U and V (420).
-void YUY2ToUVRow_C(const uint8* src_yuy2, int src_stride_yuy2,
- uint8* dst_u, uint8* dst_v, int width) {
- // Output a row of UV values, filtering 2 rows of YUY2.
- int x;
- for (x = 0; x < width; x += 2) {
- dst_u[0] = (src_yuy2[1] + src_yuy2[src_stride_yuy2 + 1] + 1) >> 1;
- dst_v[0] = (src_yuy2[3] + src_yuy2[src_stride_yuy2 + 3] + 1) >> 1;
- src_yuy2 += 4;
- dst_u += 1;
- dst_v += 1;
- }
-}
-
-// Copy row of YUY2 UV's (422) into U and V (422).
-void YUY2ToUV422Row_C(const uint8* src_yuy2,
- uint8* dst_u, uint8* dst_v, int width) {
- // Output a row of UV values.
- int x;
- for (x = 0; x < width; x += 2) {
- dst_u[0] = src_yuy2[1];
- dst_v[0] = src_yuy2[3];
- src_yuy2 += 4;
- dst_u += 1;
- dst_v += 1;
- }
-}
-
-// Copy row of YUY2 Y's (422) into Y (420/422).
-void YUY2ToYRow_C(const uint8* src_yuy2, uint8* dst_y, int width) {
- // Output a row of Y values.
- int x;
- for (x = 0; x < width - 1; x += 2) {
- dst_y[x] = src_yuy2[0];
- dst_y[x + 1] = src_yuy2[2];
- src_yuy2 += 4;
- }
- if (width & 1) {
- dst_y[width - 1] = src_yuy2[0];
- }
-}
-
-// Filter 2 rows of UYVY UV's (422) into U and V (420).
-void UYVYToUVRow_C(const uint8* src_uyvy, int src_stride_uyvy,
- uint8* dst_u, uint8* dst_v, int width) {
- // Output a row of UV values.
- int x;
- for (x = 0; x < width; x += 2) {
- dst_u[0] = (src_uyvy[0] + src_uyvy[src_stride_uyvy + 0] + 1) >> 1;
- dst_v[0] = (src_uyvy[2] + src_uyvy[src_stride_uyvy + 2] + 1) >> 1;
- src_uyvy += 4;
- dst_u += 1;
- dst_v += 1;
- }
-}
-
-// Copy row of UYVY UV's (422) into U and V (422).
-void UYVYToUV422Row_C(const uint8* src_uyvy,
- uint8* dst_u, uint8* dst_v, int width) {
- // Output a row of UV values.
- int x;
- for (x = 0; x < width; x += 2) {
- dst_u[0] = src_uyvy[0];
- dst_v[0] = src_uyvy[2];
- src_uyvy += 4;
- dst_u += 1;
- dst_v += 1;
- }
-}
-
-// Copy row of UYVY Y's (422) into Y (420/422).
-void UYVYToYRow_C(const uint8* src_uyvy, uint8* dst_y, int width) {
- // Output a row of Y values.
- int x;
- for (x = 0; x < width - 1; x += 2) {
- dst_y[x] = src_uyvy[1];
- dst_y[x + 1] = src_uyvy[3];
- src_uyvy += 4;
- }
- if (width & 1) {
- dst_y[width - 1] = src_uyvy[1];
- }
-}
-
-#define BLEND(f, b, a) (((256 - a) * b) >> 8) + f
-
-// Blend src_argb0 over src_argb1 and store to dst_argb.
-// dst_argb may be src_argb0 or src_argb1.
-// This code mimics the SSSE3 version for better testability.
-void ARGBBlendRow_C(const uint8* src_argb0, const uint8* src_argb1,
- uint8* dst_argb, int width) {
- int x;
- for (x = 0; x < width - 1; x += 2) {
- uint32 fb = src_argb0[0];
- uint32 fg = src_argb0[1];
- uint32 fr = src_argb0[2];
- uint32 a = src_argb0[3];
- uint32 bb = src_argb1[0];
- uint32 bg = src_argb1[1];
- uint32 br = src_argb1[2];
- dst_argb[0] = BLEND(fb, bb, a);
- dst_argb[1] = BLEND(fg, bg, a);
- dst_argb[2] = BLEND(fr, br, a);
- dst_argb[3] = 255u;
-
- fb = src_argb0[4 + 0];
- fg = src_argb0[4 + 1];
- fr = src_argb0[4 + 2];
- a = src_argb0[4 + 3];
- bb = src_argb1[4 + 0];
- bg = src_argb1[4 + 1];
- br = src_argb1[4 + 2];
- dst_argb[4 + 0] = BLEND(fb, bb, a);
- dst_argb[4 + 1] = BLEND(fg, bg, a);
- dst_argb[4 + 2] = BLEND(fr, br, a);
- dst_argb[4 + 3] = 255u;
- src_argb0 += 8;
- src_argb1 += 8;
- dst_argb += 8;
- }
-
- if (width & 1) {
- uint32 fb = src_argb0[0];
- uint32 fg = src_argb0[1];
- uint32 fr = src_argb0[2];
- uint32 a = src_argb0[3];
- uint32 bb = src_argb1[0];
- uint32 bg = src_argb1[1];
- uint32 br = src_argb1[2];
- dst_argb[0] = BLEND(fb, bb, a);
- dst_argb[1] = BLEND(fg, bg, a);
- dst_argb[2] = BLEND(fr, br, a);
- dst_argb[3] = 255u;
- }
-}
-#undef BLEND
-#define ATTENUATE(f, a) (a | (a << 8)) * (f | (f << 8)) >> 24
-
-// Multiply source RGB by alpha and store to destination.
-// This code mimics the SSSE3 version for better testability.
-void ARGBAttenuateRow_C(const uint8* src_argb, uint8* dst_argb, int width) {
- int i;
- for (i = 0; i < width - 1; i += 2) {
- uint32 b = src_argb[0];
- uint32 g = src_argb[1];
- uint32 r = src_argb[2];
- uint32 a = src_argb[3];
- dst_argb[0] = ATTENUATE(b, a);
- dst_argb[1] = ATTENUATE(g, a);
- dst_argb[2] = ATTENUATE(r, a);
- dst_argb[3] = a;
- b = src_argb[4];
- g = src_argb[5];
- r = src_argb[6];
- a = src_argb[7];
- dst_argb[4] = ATTENUATE(b, a);
- dst_argb[5] = ATTENUATE(g, a);
- dst_argb[6] = ATTENUATE(r, a);
- dst_argb[7] = a;
- src_argb += 8;
- dst_argb += 8;
- }
-
- if (width & 1) {
- const uint32 b = src_argb[0];
- const uint32 g = src_argb[1];
- const uint32 r = src_argb[2];
- const uint32 a = src_argb[3];
- dst_argb[0] = ATTENUATE(b, a);
- dst_argb[1] = ATTENUATE(g, a);
- dst_argb[2] = ATTENUATE(r, a);
- dst_argb[3] = a;
- }
-}
-#undef ATTENUATE
-
-// Divide source RGB by alpha and store to destination.
-// b = (b * 255 + (a / 2)) / a;
-// g = (g * 255 + (a / 2)) / a;
-// r = (r * 255 + (a / 2)) / a;
-// Reciprocal method is off by 1 on some values. ie 125
-// 8.8 fixed point inverse table with 1.0 in upper short and 1 / a in lower.
-#define T(a) 0x01000000 + (0x10000 / a)
-const uint32 fixed_invtbl8[256] = {
- 0x01000000, 0x0100ffff, T(0x02), T(0x03), T(0x04), T(0x05), T(0x06), T(0x07),
- T(0x08), T(0x09), T(0x0a), T(0x0b), T(0x0c), T(0x0d), T(0x0e), T(0x0f),
- T(0x10), T(0x11), T(0x12), T(0x13), T(0x14), T(0x15), T(0x16), T(0x17),
- T(0x18), T(0x19), T(0x1a), T(0x1b), T(0x1c), T(0x1d), T(0x1e), T(0x1f),
- T(0x20), T(0x21), T(0x22), T(0x23), T(0x24), T(0x25), T(0x26), T(0x27),
- T(0x28), T(0x29), T(0x2a), T(0x2b), T(0x2c), T(0x2d), T(0x2e), T(0x2f),
- T(0x30), T(0x31), T(0x32), T(0x33), T(0x34), T(0x35), T(0x36), T(0x37),
- T(0x38), T(0x39), T(0x3a), T(0x3b), T(0x3c), T(0x3d), T(0x3e), T(0x3f),
- T(0x40), T(0x41), T(0x42), T(0x43), T(0x44), T(0x45), T(0x46), T(0x47),
- T(0x48), T(0x49), T(0x4a), T(0x4b), T(0x4c), T(0x4d), T(0x4e), T(0x4f),
- T(0x50), T(0x51), T(0x52), T(0x53), T(0x54), T(0x55), T(0x56), T(0x57),
- T(0x58), T(0x59), T(0x5a), T(0x5b), T(0x5c), T(0x5d), T(0x5e), T(0x5f),
- T(0x60), T(0x61), T(0x62), T(0x63), T(0x64), T(0x65), T(0x66), T(0x67),
- T(0x68), T(0x69), T(0x6a), T(0x6b), T(0x6c), T(0x6d), T(0x6e), T(0x6f),
- T(0x70), T(0x71), T(0x72), T(0x73), T(0x74), T(0x75), T(0x76), T(0x77),
- T(0x78), T(0x79), T(0x7a), T(0x7b), T(0x7c), T(0x7d), T(0x7e), T(0x7f),
- T(0x80), T(0x81), T(0x82), T(0x83), T(0x84), T(0x85), T(0x86), T(0x87),
- T(0x88), T(0x89), T(0x8a), T(0x8b), T(0x8c), T(0x8d), T(0x8e), T(0x8f),
- T(0x90), T(0x91), T(0x92), T(0x93), T(0x94), T(0x95), T(0x96), T(0x97),
- T(0x98), T(0x99), T(0x9a), T(0x9b), T(0x9c), T(0x9d), T(0x9e), T(0x9f),
- T(0xa0), T(0xa1), T(0xa2), T(0xa3), T(0xa4), T(0xa5), T(0xa6), T(0xa7),
- T(0xa8), T(0xa9), T(0xaa), T(0xab), T(0xac), T(0xad), T(0xae), T(0xaf),
- T(0xb0), T(0xb1), T(0xb2), T(0xb3), T(0xb4), T(0xb5), T(0xb6), T(0xb7),
- T(0xb8), T(0xb9), T(0xba), T(0xbb), T(0xbc), T(0xbd), T(0xbe), T(0xbf),
- T(0xc0), T(0xc1), T(0xc2), T(0xc3), T(0xc4), T(0xc5), T(0xc6), T(0xc7),
- T(0xc8), T(0xc9), T(0xca), T(0xcb), T(0xcc), T(0xcd), T(0xce), T(0xcf),
- T(0xd0), T(0xd1), T(0xd2), T(0xd3), T(0xd4), T(0xd5), T(0xd6), T(0xd7),
- T(0xd8), T(0xd9), T(0xda), T(0xdb), T(0xdc), T(0xdd), T(0xde), T(0xdf),
- T(0xe0), T(0xe1), T(0xe2), T(0xe3), T(0xe4), T(0xe5), T(0xe6), T(0xe7),
- T(0xe8), T(0xe9), T(0xea), T(0xeb), T(0xec), T(0xed), T(0xee), T(0xef),
- T(0xf0), T(0xf1), T(0xf2), T(0xf3), T(0xf4), T(0xf5), T(0xf6), T(0xf7),
- T(0xf8), T(0xf9), T(0xfa), T(0xfb), T(0xfc), T(0xfd), T(0xfe), 0x01000100 };
-#undef T
-
-void ARGBUnattenuateRow_C(const uint8* src_argb, uint8* dst_argb, int width) {
- int i;
- for (i = 0; i < width; ++i) {
- uint32 b = src_argb[0];
- uint32 g = src_argb[1];
- uint32 r = src_argb[2];
- const uint32 a = src_argb[3];
- const uint32 ia = fixed_invtbl8[a] & 0xffff; // 8.8 fixed point
- b = (b * ia) >> 8;
- g = (g * ia) >> 8;
- r = (r * ia) >> 8;
- // Clamping should not be necessary but is free in assembly.
- dst_argb[0] = clamp255(b);
- dst_argb[1] = clamp255(g);
- dst_argb[2] = clamp255(r);
- dst_argb[3] = a;
- src_argb += 4;
- dst_argb += 4;
- }
-}
-
-void ComputeCumulativeSumRow_C(const uint8* row, int32* cumsum,
- const int32* previous_cumsum, int width) {
- int32 row_sum[4] = {0, 0, 0, 0};
- int x;
- for (x = 0; x < width; ++x) {
- row_sum[0] += row[x * 4 + 0];
- row_sum[1] += row[x * 4 + 1];
- row_sum[2] += row[x * 4 + 2];
- row_sum[3] += row[x * 4 + 3];
- cumsum[x * 4 + 0] = row_sum[0] + previous_cumsum[x * 4 + 0];
- cumsum[x * 4 + 1] = row_sum[1] + previous_cumsum[x * 4 + 1];
- cumsum[x * 4 + 2] = row_sum[2] + previous_cumsum[x * 4 + 2];
- cumsum[x * 4 + 3] = row_sum[3] + previous_cumsum[x * 4 + 3];
- }
-}
-
-void CumulativeSumToAverageRow_C(const int32* tl, const int32* bl,
- int w, int area, uint8* dst, int count) {
- float ooa = 1.0f / area;
- int i;
- for (i = 0; i < count; ++i) {
- dst[0] = (uint8)((bl[w + 0] + tl[0] - bl[0] - tl[w + 0]) * ooa);
- dst[1] = (uint8)((bl[w + 1] + tl[1] - bl[1] - tl[w + 1]) * ooa);
- dst[2] = (uint8)((bl[w + 2] + tl[2] - bl[2] - tl[w + 2]) * ooa);
- dst[3] = (uint8)((bl[w + 3] + tl[3] - bl[3] - tl[w + 3]) * ooa);
- dst += 4;
- tl += 4;
- bl += 4;
- }
-}
-
-// Copy pixels from rotated source to destination row with a slope.
-LIBYUV_API
-void ARGBAffineRow_C(const uint8* src_argb, int src_argb_stride,
- uint8* dst_argb, const float* uv_dudv, int width) {
- int i;
- // Render a row of pixels from source into a buffer.
- float uv[2];
- uv[0] = uv_dudv[0];
- uv[1] = uv_dudv[1];
- for (i = 0; i < width; ++i) {
- int x = (int)(uv[0]);
- int y = (int)(uv[1]);
- *(uint32*)(dst_argb) =
- *(const uint32*)(src_argb + y * src_argb_stride +
- x * 4);
- dst_argb += 4;
- uv[0] += uv_dudv[2];
- uv[1] += uv_dudv[3];
- }
-}
-
-// Blend 2 rows into 1 for conversions such as I422ToI420.
-void HalfRow_C(const uint8* src_uv, int src_uv_stride,
- uint8* dst_uv, int pix) {
- int x;
- for (x = 0; x < pix; ++x) {
- dst_uv[x] = (src_uv[x] + src_uv[src_uv_stride + x] + 1) >> 1;
- }
-}
-
-// C version 2x2 -> 2x1.
-void InterpolateRow_C(uint8* dst_ptr, const uint8* src_ptr,
- ptrdiff_t src_stride,
- int width, int source_y_fraction) {
- int y1_fraction = source_y_fraction;
- int y0_fraction = 256 - y1_fraction;
- const uint8* src_ptr1 = src_ptr + src_stride;
- int x;
- if (source_y_fraction == 0) {
- memcpy(dst_ptr, src_ptr, width);
- return;
- }
- if (source_y_fraction == 128) {
- HalfRow_C(src_ptr, (int)(src_stride), dst_ptr, width);
- return;
- }
- for (x = 0; x < width - 1; x += 2) {
- dst_ptr[0] = (src_ptr[0] * y0_fraction + src_ptr1[0] * y1_fraction) >> 8;
- dst_ptr[1] = (src_ptr[1] * y0_fraction + src_ptr1[1] * y1_fraction) >> 8;
- src_ptr += 2;
- src_ptr1 += 2;
- dst_ptr += 2;
- }
- if (width & 1) {
- dst_ptr[0] = (src_ptr[0] * y0_fraction + src_ptr1[0] * y1_fraction) >> 8;
- }
-}
-
-// Select 2 channels from ARGB on alternating pixels. e.g. BGBGBGBG
-void ARGBToBayerRow_C(const uint8* src_argb,
- uint8* dst_bayer, uint32 selector, int pix) {
- int index0 = selector & 0xff;
- int index1 = (selector >> 8) & 0xff;
- // Copy a row of Bayer.
- int x;
- for (x = 0; x < pix - 1; x += 2) {
- dst_bayer[0] = src_argb[index0];
- dst_bayer[1] = src_argb[index1];
- src_argb += 8;
- dst_bayer += 2;
- }
- if (pix & 1) {
- dst_bayer[0] = src_argb[index0];
- }
-}
-
-// Select G channel from ARGB. e.g. GGGGGGGG
-void ARGBToBayerGGRow_C(const uint8* src_argb,
- uint8* dst_bayer, uint32 selector, int pix) {
- // Copy a row of G.
- int x;
- for (x = 0; x < pix - 1; x += 2) {
- dst_bayer[0] = src_argb[1];
- dst_bayer[1] = src_argb[5];
- src_argb += 8;
- dst_bayer += 2;
- }
- if (pix & 1) {
- dst_bayer[0] = src_argb[1];
- }
-}
-
-// Use first 4 shuffler values to reorder ARGB channels.
-void ARGBShuffleRow_C(const uint8* src_argb, uint8* dst_argb,
- const uint8* shuffler, int pix) {
- int index0 = shuffler[0];
- int index1 = shuffler[1];
- int index2 = shuffler[2];
- int index3 = shuffler[3];
- // Shuffle a row of ARGB.
- int x;
- for (x = 0; x < pix; ++x) {
- // To support in-place conversion.
- uint8 b = src_argb[index0];
- uint8 g = src_argb[index1];
- uint8 r = src_argb[index2];
- uint8 a = src_argb[index3];
- dst_argb[0] = b;
- dst_argb[1] = g;
- dst_argb[2] = r;
- dst_argb[3] = a;
- src_argb += 4;
- dst_argb += 4;
- }
-}
-
-void I422ToYUY2Row_C(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_frame, int width) {
- int x;
- for (x = 0; x < width - 1; x += 2) {
- dst_frame[0] = src_y[0];
- dst_frame[1] = src_u[0];
- dst_frame[2] = src_y[1];
- dst_frame[3] = src_v[0];
- dst_frame += 4;
- src_y += 2;
- src_u += 1;
- src_v += 1;
- }
- if (width & 1) {
- dst_frame[0] = src_y[0];
- dst_frame[1] = src_u[0];
- dst_frame[2] = src_y[0]; // duplicate last y
- dst_frame[3] = src_v[0];
- }
-}
-
-void I422ToUYVYRow_C(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_frame, int width) {
- int x;
- for (x = 0; x < width - 1; x += 2) {
- dst_frame[0] = src_u[0];
- dst_frame[1] = src_y[0];
- dst_frame[2] = src_v[0];
- dst_frame[3] = src_y[1];
- dst_frame += 4;
- src_y += 2;
- src_u += 1;
- src_v += 1;
- }
- if (width & 1) {
- dst_frame[0] = src_u[0];
- dst_frame[1] = src_y[0];
- dst_frame[2] = src_v[0];
- dst_frame[3] = src_y[0]; // duplicate last y
- }
-}
-
-#if !defined(LIBYUV_DISABLE_X86) && defined(HAS_I422TOARGBROW_SSSE3)
-// row_win.cc has asm version, but GCC uses 2 step wrapper.
-#if !defined(_MSC_VER) && (defined(__x86_64__) || defined(__i386__))
-void I422ToRGB565Row_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* rgb_buf,
- int width) {
- // Allocate a row of ARGB.
- align_buffer_64(row, width * 4);
- I422ToARGBRow_SSSE3(src_y, src_u, src_v, row, width);
- ARGBToRGB565Row_SSE2(row, rgb_buf, width);
- free_aligned_buffer_64(row);
-}
-#endif // !defined(_MSC_VER) && (defined(__x86_64__) || defined(__i386__))
-
-#if defined(_M_IX86) || defined(__x86_64__) || defined(__i386__)
-void I422ToARGB1555Row_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* rgb_buf,
- int width) {
- // Allocate a row of ARGB.
- align_buffer_64(row, width * 4);
- I422ToARGBRow_SSSE3(src_y, src_u, src_v, row, width);
- ARGBToARGB1555Row_SSE2(row, rgb_buf, width);
- free_aligned_buffer_64(row);
-}
-
-void I422ToARGB4444Row_SSSE3(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* rgb_buf,
- int width) {
- // Allocate a row of ARGB.
- align_buffer_64(row, width * 4);
- I422ToARGBRow_SSSE3(src_y, src_u, src_v, row, width);
- ARGBToARGB4444Row_SSE2(row, rgb_buf, width);
- free_aligned_buffer_64(row);
-}
-
-void NV12ToRGB565Row_SSSE3(const uint8* src_y,
- const uint8* src_uv,
- uint8* dst_rgb565,
- int width) {
- // Allocate a row of ARGB.
- align_buffer_64(row, width * 4);
- NV12ToARGBRow_SSSE3(src_y, src_uv, row, width);
- ARGBToRGB565Row_SSE2(row, dst_rgb565, width);
- free_aligned_buffer_64(row);
-}
-
-void NV21ToRGB565Row_SSSE3(const uint8* src_y,
- const uint8* src_vu,
- uint8* dst_rgb565,
- int width) {
- // Allocate a row of ARGB.
- align_buffer_64(row, width * 4);
- NV21ToARGBRow_SSSE3(src_y, src_vu, row, width);
- ARGBToRGB565Row_SSE2(row, dst_rgb565, width);
- free_aligned_buffer_64(row);
-}
-
-void YUY2ToARGBRow_SSSE3(const uint8* src_yuy2,
- uint8* dst_argb,
- int width) {
- // Allocate a rows of yuv.
- align_buffer_64(row_y, ((width + 63) & ~63) * 2);
- uint8* row_u = row_y + ((width + 63) & ~63);
- uint8* row_v = row_u + ((width + 63) & ~63) / 2;
- YUY2ToUV422Row_SSE2(src_yuy2, row_u, row_v, width);
- YUY2ToYRow_SSE2(src_yuy2, row_y, width);
- I422ToARGBRow_SSSE3(row_y, row_u, row_v, dst_argb, width);
- free_aligned_buffer_64(row_y);
-}
-
-void YUY2ToARGBRow_Unaligned_SSSE3(const uint8* src_yuy2,
- uint8* dst_argb,
- int width) {
- // Allocate a rows of yuv.
- align_buffer_64(row_y, ((width + 63) & ~63) * 2);
- uint8* row_u = row_y + ((width + 63) & ~63);
- uint8* row_v = row_u + ((width + 63) & ~63) / 2;
- YUY2ToUV422Row_Unaligned_SSE2(src_yuy2, row_u, row_v, width);
- YUY2ToYRow_Unaligned_SSE2(src_yuy2, row_y, width);
- I422ToARGBRow_Unaligned_SSSE3(row_y, row_u, row_v, dst_argb, width);
- free_aligned_buffer_64(row_y);
-}
-
-void UYVYToARGBRow_SSSE3(const uint8* src_uyvy,
- uint8* dst_argb,
- int width) {
- // Allocate a rows of yuv.
- align_buffer_64(row_y, ((width + 63) & ~63) * 2);
- uint8* row_u = row_y + ((width + 63) & ~63);
- uint8* row_v = row_u + ((width + 63) & ~63) / 2;
- UYVYToUV422Row_SSE2(src_uyvy, row_u, row_v, width);
- UYVYToYRow_SSE2(src_uyvy, row_y, width);
- I422ToARGBRow_SSSE3(row_y, row_u, row_v, dst_argb, width);
- free_aligned_buffer_64(row_y);
-}
-
-void UYVYToARGBRow_Unaligned_SSSE3(const uint8* src_uyvy,
- uint8* dst_argb,
- int width) {
- // Allocate a rows of yuv.
- align_buffer_64(row_y, ((width + 63) & ~63) * 2);
- uint8* row_u = row_y + ((width + 63) & ~63);
- uint8* row_v = row_u + ((width + 63) & ~63) / 2;
- UYVYToUV422Row_Unaligned_SSE2(src_uyvy, row_u, row_v, width);
- UYVYToYRow_Unaligned_SSE2(src_uyvy, row_y, width);
- I422ToARGBRow_Unaligned_SSSE3(row_y, row_u, row_v, dst_argb, width);
- free_aligned_buffer_64(row_y);
-}
-
-#endif // defined(_M_IX86) || defined(__x86_64__) || defined(__i386__)
-#endif // !defined(LIBYUV_DISABLE_X86)
-
-void ARGBPolynomialRow_C(const uint8* src_argb,
- uint8* dst_argb, const float* poly,
- int width) {
- int i;
- for (i = 0; i < width; ++i) {
- float b = (float)(src_argb[0]);
- float g = (float)(src_argb[1]);
- float r = (float)(src_argb[2]);
- float a = (float)(src_argb[3]);
- float b2 = b * b;
- float g2 = g * g;
- float r2 = r * r;
- float a2 = a * a;
- float db = poly[0] + poly[4] * b;
- float dg = poly[1] + poly[5] * g;
- float dr = poly[2] + poly[6] * r;
- float da = poly[3] + poly[7] * a;
- float b3 = b2 * b;
- float g3 = g2 * g;
- float r3 = r2 * r;
- float a3 = a2 * a;
- db += poly[8] * b2;
- dg += poly[9] * g2;
- dr += poly[10] * r2;
- da += poly[11] * a2;
- db += poly[12] * b3;
- dg += poly[13] * g3;
- dr += poly[14] * r3;
- da += poly[15] * a3;
-
- dst_argb[0] = Clamp((int32)(db));
- dst_argb[1] = Clamp((int32)(dg));
- dst_argb[2] = Clamp((int32)(dr));
- dst_argb[3] = Clamp((int32)(da));
- src_argb += 4;
- dst_argb += 4;
- }
-}
-
-void ARGBLumaColorTableRow_C(const uint8* src_argb, uint8* dst_argb, int width,
- const uint8* luma, uint32 lumacoeff) {
- uint32 bc = lumacoeff & 0xff;
- uint32 gc = (lumacoeff >> 8) & 0xff;
- uint32 rc = (lumacoeff >> 16) & 0xff;
-
- int i;
- for (i = 0; i < width - 1; i += 2) {
- // Luminance in rows, color values in columns.
- const uint8* luma0 = ((src_argb[0] * bc + src_argb[1] * gc +
- src_argb[2] * rc) & 0x7F00u) + luma;
- const uint8* luma1;
- dst_argb[0] = luma0[src_argb[0]];
- dst_argb[1] = luma0[src_argb[1]];
- dst_argb[2] = luma0[src_argb[2]];
- dst_argb[3] = src_argb[3];
- luma1 = ((src_argb[4] * bc + src_argb[5] * gc +
- src_argb[6] * rc) & 0x7F00u) + luma;
- dst_argb[4] = luma1[src_argb[4]];
- dst_argb[5] = luma1[src_argb[5]];
- dst_argb[6] = luma1[src_argb[6]];
- dst_argb[7] = src_argb[7];
- src_argb += 8;
- dst_argb += 8;
- }
- if (width & 1) {
- // Luminance in rows, color values in columns.
- const uint8* luma0 = ((src_argb[0] * bc + src_argb[1] * gc +
- src_argb[2] * rc) & 0x7F00u) + luma;
- dst_argb[0] = luma0[src_argb[0]];
- dst_argb[1] = luma0[src_argb[1]];
- dst_argb[2] = luma0[src_argb[2]];
- dst_argb[3] = src_argb[3];
- }
-}
-
-void ARGBCopyAlphaRow_C(const uint8* src, uint8* dst, int width) {
- int i;
- for (i = 0; i < width - 1; i += 2) {
- dst[3] = src[3];
- dst[7] = src[7];
- dst += 8;
- src += 8;
- }
- if (width & 1) {
- dst[3] = src[3];
- }
-}
-
-void ARGBCopyYToAlphaRow_C(const uint8* src, uint8* dst, int width) {
- int i;
- for (i = 0; i < width - 1; i += 2) {
- dst[3] = src[0];
- dst[7] = src[1];
- dst += 8;
- src += 2;
- }
- if (width & 1) {
- dst[3] = src[0];
- }
-}
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/row_mips.cc b/drivers/theoraplayer/src/YUV/libyuv/src/row_mips.cc
deleted file mode 100755
index 4435c55c5c..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/row_mips.cc
+++ /dev/null
@@ -1,991 +0,0 @@
-/*
- * Copyright (c) 2012 The LibYuv project authors. All Rights Reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/row.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// The following are available on Mips platforms:
-#if !defined(LIBYUV_DISABLE_MIPS) && defined(__mips__)
-
-#ifdef HAS_COPYROW_MIPS
-void CopyRow_MIPS(const uint8* src, uint8* dst, int count) {
- __asm__ __volatile__ (
- ".set noreorder \n"
- ".set noat \n"
- "slti $at, %[count], 8 \n"
- "bne $at ,$zero, $last8 \n"
- "xor $t8, %[src], %[dst] \n"
- "andi $t8, $t8, 0x3 \n"
-
- "bne $t8, $zero, unaligned \n"
- "negu $a3, %[dst] \n"
- // make dst/src aligned
- "andi $a3, $a3, 0x3 \n"
- "beq $a3, $zero, $chk16w \n"
- // word-aligned now count is the remining bytes count
- "subu %[count], %[count], $a3 \n"
-
- "lwr $t8, 0(%[src]) \n"
- "addu %[src], %[src], $a3 \n"
- "swr $t8, 0(%[dst]) \n"
- "addu %[dst], %[dst], $a3 \n"
-
- // Now the dst/src are mutually word-aligned with word-aligned addresses
- "$chk16w: \n"
- "andi $t8, %[count], 0x3f \n" // whole 64-B chunks?
- // t8 is the byte count after 64-byte chunks
- "beq %[count], $t8, chk8w \n"
- // There will be at most 1 32-byte chunk after it
- "subu $a3, %[count], $t8 \n" // the reminder
- // Here a3 counts bytes in 16w chunks
- "addu $a3, %[dst], $a3 \n"
- // Now a3 is the final dst after 64-byte chunks
- "addu $t0, %[dst], %[count] \n"
- // t0 is the "past the end" address
-
- // When in the loop we exercise "pref 30,x(a1)", the a1+x should not be past
- // the "t0-32" address
- // This means: for x=128 the last "safe" a1 address is "t0-160"
- // Alternatively, for x=64 the last "safe" a1 address is "t0-96"
- // we will use "pref 30,128(a1)", so "t0-160" is the limit
- "subu $t9, $t0, 160 \n"
- // t9 is the "last safe pref 30,128(a1)" address
- "pref 0, 0(%[src]) \n" // first line of src
- "pref 0, 32(%[src]) \n" // second line of src
- "pref 0, 64(%[src]) \n"
- "pref 30, 32(%[dst]) \n"
- // In case the a1 > t9 don't use "pref 30" at all
- "sgtu $v1, %[dst], $t9 \n"
- "bgtz $v1, $loop16w \n"
- "nop \n"
- // otherwise, start with using pref30
- "pref 30, 64(%[dst]) \n"
- "$loop16w: \n"
- "pref 0, 96(%[src]) \n"
- "lw $t0, 0(%[src]) \n"
- "bgtz $v1, $skip_pref30_96 \n" // skip
- "lw $t1, 4(%[src]) \n"
- "pref 30, 96(%[dst]) \n" // continue
- "$skip_pref30_96: \n"
- "lw $t2, 8(%[src]) \n"
- "lw $t3, 12(%[src]) \n"
- "lw $t4, 16(%[src]) \n"
- "lw $t5, 20(%[src]) \n"
- "lw $t6, 24(%[src]) \n"
- "lw $t7, 28(%[src]) \n"
- "pref 0, 128(%[src]) \n"
- // bring the next lines of src, addr 128
- "sw $t0, 0(%[dst]) \n"
- "sw $t1, 4(%[dst]) \n"
- "sw $t2, 8(%[dst]) \n"
- "sw $t3, 12(%[dst]) \n"
- "sw $t4, 16(%[dst]) \n"
- "sw $t5, 20(%[dst]) \n"
- "sw $t6, 24(%[dst]) \n"
- "sw $t7, 28(%[dst]) \n"
- "lw $t0, 32(%[src]) \n"
- "bgtz $v1, $skip_pref30_128 \n" // skip pref 30,128(a1)
- "lw $t1, 36(%[src]) \n"
- "pref 30, 128(%[dst]) \n" // set dest, addr 128
- "$skip_pref30_128: \n"
- "lw $t2, 40(%[src]) \n"
- "lw $t3, 44(%[src]) \n"
- "lw $t4, 48(%[src]) \n"
- "lw $t5, 52(%[src]) \n"
- "lw $t6, 56(%[src]) \n"
- "lw $t7, 60(%[src]) \n"
- "pref 0, 160(%[src]) \n"
- // bring the next lines of src, addr 160
- "sw $t0, 32(%[dst]) \n"
- "sw $t1, 36(%[dst]) \n"
- "sw $t2, 40(%[dst]) \n"
- "sw $t3, 44(%[dst]) \n"
- "sw $t4, 48(%[dst]) \n"
- "sw $t5, 52(%[dst]) \n"
- "sw $t6, 56(%[dst]) \n"
- "sw $t7, 60(%[dst]) \n"
-
- "addiu %[dst], %[dst], 64 \n" // adding 64 to dest
- "sgtu $v1, %[dst], $t9 \n"
- "bne %[dst], $a3, $loop16w \n"
- " addiu %[src], %[src], 64 \n" // adding 64 to src
- "move %[count], $t8 \n"
-
- // Here we have src and dest word-aligned but less than 64-bytes to go
-
- "chk8w: \n"
- "pref 0, 0x0(%[src]) \n"
- "andi $t8, %[count], 0x1f \n" // 32-byte chunk?
- // the t8 is the reminder count past 32-bytes
- "beq %[count], $t8, chk1w \n"
- // count=t8,no 32-byte chunk
- " nop \n"
-
- "lw $t0, 0(%[src]) \n"
- "lw $t1, 4(%[src]) \n"
- "lw $t2, 8(%[src]) \n"
- "lw $t3, 12(%[src]) \n"
- "lw $t4, 16(%[src]) \n"
- "lw $t5, 20(%[src]) \n"
- "lw $t6, 24(%[src]) \n"
- "lw $t7, 28(%[src]) \n"
- "addiu %[src], %[src], 32 \n"
-
- "sw $t0, 0(%[dst]) \n"
- "sw $t1, 4(%[dst]) \n"
- "sw $t2, 8(%[dst]) \n"
- "sw $t3, 12(%[dst]) \n"
- "sw $t4, 16(%[dst]) \n"
- "sw $t5, 20(%[dst]) \n"
- "sw $t6, 24(%[dst]) \n"
- "sw $t7, 28(%[dst]) \n"
- "addiu %[dst], %[dst], 32 \n"
-
- "chk1w: \n"
- "andi %[count], $t8, 0x3 \n"
- // now count is the reminder past 1w chunks
- "beq %[count], $t8, $last8 \n"
- " subu $a3, $t8, %[count] \n"
- // a3 is count of bytes in 1w chunks
- "addu $a3, %[dst], $a3 \n"
- // now a3 is the dst address past the 1w chunks
- // copying in words (4-byte chunks)
- "$wordCopy_loop: \n"
- "lw $t3, 0(%[src]) \n"
- // the first t3 may be equal t0 ... optimize?
- "addiu %[src], %[src],4 \n"
- "addiu %[dst], %[dst],4 \n"
- "bne %[dst], $a3,$wordCopy_loop \n"
- " sw $t3, -4(%[dst]) \n"
-
- // For the last (<8) bytes
- "$last8: \n"
- "blez %[count], leave \n"
- " addu $a3, %[dst], %[count] \n" // a3 -last dst address
- "$last8loop: \n"
- "lb $v1, 0(%[src]) \n"
- "addiu %[src], %[src], 1 \n"
- "addiu %[dst], %[dst], 1 \n"
- "bne %[dst], $a3, $last8loop \n"
- " sb $v1, -1(%[dst]) \n"
-
- "leave: \n"
- " j $ra \n"
- " nop \n"
-
- //
- // UNALIGNED case
- //
-
- "unaligned: \n"
- // got here with a3="negu a1"
- "andi $a3, $a3, 0x3 \n" // a1 is word aligned?
- "beqz $a3, $ua_chk16w \n"
- " subu %[count], %[count], $a3 \n"
- // bytes left after initial a3 bytes
- "lwr $v1, 0(%[src]) \n"
- "lwl $v1, 3(%[src]) \n"
- "addu %[src], %[src], $a3 \n" // a3 may be 1, 2 or 3
- "swr $v1, 0(%[dst]) \n"
- "addu %[dst], %[dst], $a3 \n"
- // below the dst will be word aligned (NOTE1)
- "$ua_chk16w: \n"
- "andi $t8, %[count], 0x3f \n" // whole 64-B chunks?
- // t8 is the byte count after 64-byte chunks
- "beq %[count], $t8, ua_chk8w \n"
- // if a2==t8, no 64-byte chunks
- // There will be at most 1 32-byte chunk after it
- "subu $a3, %[count], $t8 \n" // the reminder
- // Here a3 counts bytes in 16w chunks
- "addu $a3, %[dst], $a3 \n"
- // Now a3 is the final dst after 64-byte chunks
- "addu $t0, %[dst], %[count] \n" // t0 "past the end"
- "subu $t9, $t0, 160 \n"
- // t9 is the "last safe pref 30,128(a1)" address
- "pref 0, 0(%[src]) \n" // first line of src
- "pref 0, 32(%[src]) \n" // second line addr 32
- "pref 0, 64(%[src]) \n"
- "pref 30, 32(%[dst]) \n"
- // safe, as we have at least 64 bytes ahead
- // In case the a1 > t9 don't use "pref 30" at all
- "sgtu $v1, %[dst], $t9 \n"
- "bgtz $v1, $ua_loop16w \n"
- // skip "pref 30,64(a1)" for too short arrays
- " nop \n"
- // otherwise, start with using pref30
- "pref 30, 64(%[dst]) \n"
- "$ua_loop16w: \n"
- "pref 0, 96(%[src]) \n"
- "lwr $t0, 0(%[src]) \n"
- "lwl $t0, 3(%[src]) \n"
- "lwr $t1, 4(%[src]) \n"
- "bgtz $v1, $ua_skip_pref30_96 \n"
- " lwl $t1, 7(%[src]) \n"
- "pref 30, 96(%[dst]) \n"
- // continue setting up the dest, addr 96
- "$ua_skip_pref30_96: \n"
- "lwr $t2, 8(%[src]) \n"
- "lwl $t2, 11(%[src]) \n"
- "lwr $t3, 12(%[src]) \n"
- "lwl $t3, 15(%[src]) \n"
- "lwr $t4, 16(%[src]) \n"
- "lwl $t4, 19(%[src]) \n"
- "lwr $t5, 20(%[src]) \n"
- "lwl $t5, 23(%[src]) \n"
- "lwr $t6, 24(%[src]) \n"
- "lwl $t6, 27(%[src]) \n"
- "lwr $t7, 28(%[src]) \n"
- "lwl $t7, 31(%[src]) \n"
- "pref 0, 128(%[src]) \n"
- // bring the next lines of src, addr 128
- "sw $t0, 0(%[dst]) \n"
- "sw $t1, 4(%[dst]) \n"
- "sw $t2, 8(%[dst]) \n"
- "sw $t3, 12(%[dst]) \n"
- "sw $t4, 16(%[dst]) \n"
- "sw $t5, 20(%[dst]) \n"
- "sw $t6, 24(%[dst]) \n"
- "sw $t7, 28(%[dst]) \n"
- "lwr $t0, 32(%[src]) \n"
- "lwl $t0, 35(%[src]) \n"
- "lwr $t1, 36(%[src]) \n"
- "bgtz $v1, ua_skip_pref30_128 \n"
- " lwl $t1, 39(%[src]) \n"
- "pref 30, 128(%[dst]) \n"
- // continue setting up the dest, addr 128
- "ua_skip_pref30_128: \n"
-
- "lwr $t2, 40(%[src]) \n"
- "lwl $t2, 43(%[src]) \n"
- "lwr $t3, 44(%[src]) \n"
- "lwl $t3, 47(%[src]) \n"
- "lwr $t4, 48(%[src]) \n"
- "lwl $t4, 51(%[src]) \n"
- "lwr $t5, 52(%[src]) \n"
- "lwl $t5, 55(%[src]) \n"
- "lwr $t6, 56(%[src]) \n"
- "lwl $t6, 59(%[src]) \n"
- "lwr $t7, 60(%[src]) \n"
- "lwl $t7, 63(%[src]) \n"
- "pref 0, 160(%[src]) \n"
- // bring the next lines of src, addr 160
- "sw $t0, 32(%[dst]) \n"
- "sw $t1, 36(%[dst]) \n"
- "sw $t2, 40(%[dst]) \n"
- "sw $t3, 44(%[dst]) \n"
- "sw $t4, 48(%[dst]) \n"
- "sw $t5, 52(%[dst]) \n"
- "sw $t6, 56(%[dst]) \n"
- "sw $t7, 60(%[dst]) \n"
-
- "addiu %[dst],%[dst],64 \n" // adding 64 to dest
- "sgtu $v1,%[dst],$t9 \n"
- "bne %[dst],$a3,$ua_loop16w \n"
- " addiu %[src],%[src],64 \n" // adding 64 to src
- "move %[count],$t8 \n"
-
- // Here we have src and dest word-aligned but less than 64-bytes to go
-
- "ua_chk8w: \n"
- "pref 0, 0x0(%[src]) \n"
- "andi $t8, %[count], 0x1f \n" // 32-byte chunk?
- // the t8 is the reminder count
- "beq %[count], $t8, $ua_chk1w \n"
- // when count==t8, no 32-byte chunk
-
- "lwr $t0, 0(%[src]) \n"
- "lwl $t0, 3(%[src]) \n"
- "lwr $t1, 4(%[src]) \n"
- "lwl $t1, 7(%[src]) \n"
- "lwr $t2, 8(%[src]) \n"
- "lwl $t2, 11(%[src]) \n"
- "lwr $t3, 12(%[src]) \n"
- "lwl $t3, 15(%[src]) \n"
- "lwr $t4, 16(%[src]) \n"
- "lwl $t4, 19(%[src]) \n"
- "lwr $t5, 20(%[src]) \n"
- "lwl $t5, 23(%[src]) \n"
- "lwr $t6, 24(%[src]) \n"
- "lwl $t6, 27(%[src]) \n"
- "lwr $t7, 28(%[src]) \n"
- "lwl $t7, 31(%[src]) \n"
- "addiu %[src], %[src], 32 \n"
-
- "sw $t0, 0(%[dst]) \n"
- "sw $t1, 4(%[dst]) \n"
- "sw $t2, 8(%[dst]) \n"
- "sw $t3, 12(%[dst]) \n"
- "sw $t4, 16(%[dst]) \n"
- "sw $t5, 20(%[dst]) \n"
- "sw $t6, 24(%[dst]) \n"
- "sw $t7, 28(%[dst]) \n"
- "addiu %[dst], %[dst], 32 \n"
-
- "$ua_chk1w: \n"
- "andi %[count], $t8, 0x3 \n"
- // now count is the reminder past 1w chunks
- "beq %[count], $t8, ua_smallCopy \n"
- "subu $a3, $t8, %[count] \n"
- // a3 is count of bytes in 1w chunks
- "addu $a3, %[dst], $a3 \n"
- // now a3 is the dst address past the 1w chunks
-
- // copying in words (4-byte chunks)
- "$ua_wordCopy_loop: \n"
- "lwr $v1, 0(%[src]) \n"
- "lwl $v1, 3(%[src]) \n"
- "addiu %[src], %[src], 4 \n"
- "addiu %[dst], %[dst], 4 \n"
- // note: dst=a1 is word aligned here, see NOTE1
- "bne %[dst], $a3, $ua_wordCopy_loop \n"
- " sw $v1,-4(%[dst]) \n"
-
- // Now less than 4 bytes (value in count) left to copy
- "ua_smallCopy: \n"
- "beqz %[count], leave \n"
- " addu $a3, %[dst], %[count] \n" // a3 = last dst address
- "$ua_smallCopy_loop: \n"
- "lb $v1, 0(%[src]) \n"
- "addiu %[src], %[src], 1 \n"
- "addiu %[dst], %[dst], 1 \n"
- "bne %[dst],$a3,$ua_smallCopy_loop \n"
- " sb $v1, -1(%[dst]) \n"
-
- "j $ra \n"
- " nop \n"
- ".set at \n"
- ".set reorder \n"
- : [dst] "+r" (dst), [src] "+r" (src)
- : [count] "r" (count)
- : "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
- "t8", "t9", "a3", "v1", "at"
- );
-}
-#endif // HAS_COPYROW_MIPS
-
-// MIPS DSPR2 functions
-#if !defined(LIBYUV_DISABLE_MIPS) && defined(__mips_dsp) && \
- (__mips_dsp_rev >= 2)
-void SplitUVRow_MIPS_DSPR2(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
- int width) {
- __asm__ __volatile__ (
- ".set push \n"
- ".set noreorder \n"
- "srl $t4, %[width], 4 \n" // multiplies of 16
- "blez $t4, 2f \n"
- " andi %[width], %[width], 0xf \n" // residual
-
- ".p2align 2 \n"
- "1: \n"
- "addiu $t4, $t4, -1 \n"
- "lw $t0, 0(%[src_uv]) \n" // V1 | U1 | V0 | U0
- "lw $t1, 4(%[src_uv]) \n" // V3 | U3 | V2 | U2
- "lw $t2, 8(%[src_uv]) \n" // V5 | U5 | V4 | U4
- "lw $t3, 12(%[src_uv]) \n" // V7 | U7 | V6 | U6
- "lw $t5, 16(%[src_uv]) \n" // V9 | U9 | V8 | U8
- "lw $t6, 20(%[src_uv]) \n" // V11 | U11 | V10 | U10
- "lw $t7, 24(%[src_uv]) \n" // V13 | U13 | V12 | U12
- "lw $t8, 28(%[src_uv]) \n" // V15 | U15 | V14 | U14
- "addiu %[src_uv], %[src_uv], 32 \n"
- "precrq.qb.ph $t9, $t1, $t0 \n" // V3 | V2 | V1 | V0
- "precr.qb.ph $t0, $t1, $t0 \n" // U3 | U2 | U1 | U0
- "precrq.qb.ph $t1, $t3, $t2 \n" // V7 | V6 | V5 | V4
- "precr.qb.ph $t2, $t3, $t2 \n" // U7 | U6 | U5 | U4
- "precrq.qb.ph $t3, $t6, $t5 \n" // V11 | V10 | V9 | V8
- "precr.qb.ph $t5, $t6, $t5 \n" // U11 | U10 | U9 | U8
- "precrq.qb.ph $t6, $t8, $t7 \n" // V15 | V14 | V13 | V12
- "precr.qb.ph $t7, $t8, $t7 \n" // U15 | U14 | U13 | U12
- "sw $t9, 0(%[dst_v]) \n"
- "sw $t0, 0(%[dst_u]) \n"
- "sw $t1, 4(%[dst_v]) \n"
- "sw $t2, 4(%[dst_u]) \n"
- "sw $t3, 8(%[dst_v]) \n"
- "sw $t5, 8(%[dst_u]) \n"
- "sw $t6, 12(%[dst_v]) \n"
- "sw $t7, 12(%[dst_u]) \n"
- "addiu %[dst_v], %[dst_v], 16 \n"
- "bgtz $t4, 1b \n"
- " addiu %[dst_u], %[dst_u], 16 \n"
-
- "beqz %[width], 3f \n"
- " nop \n"
-
- "2: \n"
- "lbu $t0, 0(%[src_uv]) \n"
- "lbu $t1, 1(%[src_uv]) \n"
- "addiu %[src_uv], %[src_uv], 2 \n"
- "addiu %[width], %[width], -1 \n"
- "sb $t0, 0(%[dst_u]) \n"
- "sb $t1, 0(%[dst_v]) \n"
- "addiu %[dst_u], %[dst_u], 1 \n"
- "bgtz %[width], 2b \n"
- " addiu %[dst_v], %[dst_v], 1 \n"
-
- "3: \n"
- ".set pop \n"
- : [src_uv] "+r" (src_uv),
- [width] "+r" (width),
- [dst_u] "+r" (dst_u),
- [dst_v] "+r" (dst_v)
- :
- : "t0", "t1", "t2", "t3",
- "t4", "t5", "t6", "t7", "t8", "t9"
- );
-}
-
-void SplitUVRow_Unaligned_MIPS_DSPR2(const uint8* src_uv, uint8* dst_u,
- uint8* dst_v, int width) {
- __asm__ __volatile__ (
- ".set push \n"
- ".set noreorder \n"
- "srl $t4, %[width], 4 \n" // multiplies of 16
- "blez $t4, 2f \n"
- " andi %[width], %[width], 0xf \n" // residual
-
- ".p2align 2 \n"
- "1: \n"
- "addiu $t4, $t4, -1 \n"
- "lwr $t0, 0(%[src_uv]) \n"
- "lwl $t0, 3(%[src_uv]) \n" // V1 | U1 | V0 | U0
- "lwr $t1, 4(%[src_uv]) \n"
- "lwl $t1, 7(%[src_uv]) \n" // V3 | U3 | V2 | U2
- "lwr $t2, 8(%[src_uv]) \n"
- "lwl $t2, 11(%[src_uv]) \n" // V5 | U5 | V4 | U4
- "lwr $t3, 12(%[src_uv]) \n"
- "lwl $t3, 15(%[src_uv]) \n" // V7 | U7 | V6 | U6
- "lwr $t5, 16(%[src_uv]) \n"
- "lwl $t5, 19(%[src_uv]) \n" // V9 | U9 | V8 | U8
- "lwr $t6, 20(%[src_uv]) \n"
- "lwl $t6, 23(%[src_uv]) \n" // V11 | U11 | V10 | U10
- "lwr $t7, 24(%[src_uv]) \n"
- "lwl $t7, 27(%[src_uv]) \n" // V13 | U13 | V12 | U12
- "lwr $t8, 28(%[src_uv]) \n"
- "lwl $t8, 31(%[src_uv]) \n" // V15 | U15 | V14 | U14
- "precrq.qb.ph $t9, $t1, $t0 \n" // V3 | V2 | V1 | V0
- "precr.qb.ph $t0, $t1, $t0 \n" // U3 | U2 | U1 | U0
- "precrq.qb.ph $t1, $t3, $t2 \n" // V7 | V6 | V5 | V4
- "precr.qb.ph $t2, $t3, $t2 \n" // U7 | U6 | U5 | U4
- "precrq.qb.ph $t3, $t6, $t5 \n" // V11 | V10 | V9 | V8
- "precr.qb.ph $t5, $t6, $t5 \n" // U11 | U10 | U9 | U8
- "precrq.qb.ph $t6, $t8, $t7 \n" // V15 | V14 | V13 | V12
- "precr.qb.ph $t7, $t8, $t7 \n" // U15 | U14 | U13 | U12
- "addiu %[src_uv], %[src_uv], 32 \n"
- "swr $t9, 0(%[dst_v]) \n"
- "swl $t9, 3(%[dst_v]) \n"
- "swr $t0, 0(%[dst_u]) \n"
- "swl $t0, 3(%[dst_u]) \n"
- "swr $t1, 4(%[dst_v]) \n"
- "swl $t1, 7(%[dst_v]) \n"
- "swr $t2, 4(%[dst_u]) \n"
- "swl $t2, 7(%[dst_u]) \n"
- "swr $t3, 8(%[dst_v]) \n"
- "swl $t3, 11(%[dst_v]) \n"
- "swr $t5, 8(%[dst_u]) \n"
- "swl $t5, 11(%[dst_u]) \n"
- "swr $t6, 12(%[dst_v]) \n"
- "swl $t6, 15(%[dst_v]) \n"
- "swr $t7, 12(%[dst_u]) \n"
- "swl $t7, 15(%[dst_u]) \n"
- "addiu %[dst_u], %[dst_u], 16 \n"
- "bgtz $t4, 1b \n"
- " addiu %[dst_v], %[dst_v], 16 \n"
-
- "beqz %[width], 3f \n"
- " nop \n"
-
- "2: \n"
- "lbu $t0, 0(%[src_uv]) \n"
- "lbu $t1, 1(%[src_uv]) \n"
- "addiu %[src_uv], %[src_uv], 2 \n"
- "addiu %[width], %[width], -1 \n"
- "sb $t0, 0(%[dst_u]) \n"
- "sb $t1, 0(%[dst_v]) \n"
- "addiu %[dst_u], %[dst_u], 1 \n"
- "bgtz %[width], 2b \n"
- " addiu %[dst_v], %[dst_v], 1 \n"
-
- "3: \n"
- ".set pop \n"
- : [src_uv] "+r" (src_uv),
- [width] "+r" (width),
- [dst_u] "+r" (dst_u),
- [dst_v] "+r" (dst_v)
- :
- : "t0", "t1", "t2", "t3",
- "t4", "t5", "t6", "t7", "t8", "t9"
- );
-}
-
-void MirrorRow_MIPS_DSPR2(const uint8* src, uint8* dst, int width) {
- __asm__ __volatile__ (
- ".set push \n"
- ".set noreorder \n"
-
- "srl $t4, %[width], 4 \n" // multiplies of 16
- "andi $t5, %[width], 0xf \n"
- "blez $t4, 2f \n"
- " addu %[src], %[src], %[width] \n" // src += width
-
- ".p2align 2 \n"
- "1: \n"
- "lw $t0, -16(%[src]) \n" // |3|2|1|0|
- "lw $t1, -12(%[src]) \n" // |7|6|5|4|
- "lw $t2, -8(%[src]) \n" // |11|10|9|8|
- "lw $t3, -4(%[src]) \n" // |15|14|13|12|
- "wsbh $t0, $t0 \n" // |2|3|0|1|
- "wsbh $t1, $t1 \n" // |6|7|4|5|
- "wsbh $t2, $t2 \n" // |10|11|8|9|
- "wsbh $t3, $t3 \n" // |14|15|12|13|
- "rotr $t0, $t0, 16 \n" // |0|1|2|3|
- "rotr $t1, $t1, 16 \n" // |4|5|6|7|
- "rotr $t2, $t2, 16 \n" // |8|9|10|11|
- "rotr $t3, $t3, 16 \n" // |12|13|14|15|
- "addiu %[src], %[src], -16 \n"
- "addiu $t4, $t4, -1 \n"
- "sw $t3, 0(%[dst]) \n" // |15|14|13|12|
- "sw $t2, 4(%[dst]) \n" // |11|10|9|8|
- "sw $t1, 8(%[dst]) \n" // |7|6|5|4|
- "sw $t0, 12(%[dst]) \n" // |3|2|1|0|
- "bgtz $t4, 1b \n"
- " addiu %[dst], %[dst], 16 \n"
- "beqz $t5, 3f \n"
- " nop \n"
-
- "2: \n"
- "lbu $t0, -1(%[src]) \n"
- "addiu $t5, $t5, -1 \n"
- "addiu %[src], %[src], -1 \n"
- "sb $t0, 0(%[dst]) \n"
- "bgez $t5, 2b \n"
- " addiu %[dst], %[dst], 1 \n"
-
- "3: \n"
- ".set pop \n"
- : [src] "+r" (src), [dst] "+r" (dst)
- : [width] "r" (width)
- : "t0", "t1", "t2", "t3", "t4", "t5"
- );
-}
-
-void MirrorUVRow_MIPS_DSPR2(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
- int width) {
- int x = 0;
- int y = 0;
- __asm__ __volatile__ (
- ".set push \n"
- ".set noreorder \n"
-
- "addu $t4, %[width], %[width] \n"
- "srl %[x], %[width], 4 \n"
- "andi %[y], %[width], 0xf \n"
- "blez %[x], 2f \n"
- " addu %[src_uv], %[src_uv], $t4 \n"
-
- ".p2align 2 \n"
- "1: \n"
- "lw $t0, -32(%[src_uv]) \n" // |3|2|1|0|
- "lw $t1, -28(%[src_uv]) \n" // |7|6|5|4|
- "lw $t2, -24(%[src_uv]) \n" // |11|10|9|8|
- "lw $t3, -20(%[src_uv]) \n" // |15|14|13|12|
- "lw $t4, -16(%[src_uv]) \n" // |19|18|17|16|
- "lw $t6, -12(%[src_uv]) \n" // |23|22|21|20|
- "lw $t7, -8(%[src_uv]) \n" // |27|26|25|24|
- "lw $t8, -4(%[src_uv]) \n" // |31|30|29|28|
-
- "rotr $t0, $t0, 16 \n" // |1|0|3|2|
- "rotr $t1, $t1, 16 \n" // |5|4|7|6|
- "rotr $t2, $t2, 16 \n" // |9|8|11|10|
- "rotr $t3, $t3, 16 \n" // |13|12|15|14|
- "rotr $t4, $t4, 16 \n" // |17|16|19|18|
- "rotr $t6, $t6, 16 \n" // |21|20|23|22|
- "rotr $t7, $t7, 16 \n" // |25|24|27|26|
- "rotr $t8, $t8, 16 \n" // |29|28|31|30|
- "precr.qb.ph $t9, $t0, $t1 \n" // |0|2|4|6|
- "precrq.qb.ph $t5, $t0, $t1 \n" // |1|3|5|7|
- "precr.qb.ph $t0, $t2, $t3 \n" // |8|10|12|14|
- "precrq.qb.ph $t1, $t2, $t3 \n" // |9|11|13|15|
- "precr.qb.ph $t2, $t4, $t6 \n" // |16|18|20|22|
- "precrq.qb.ph $t3, $t4, $t6 \n" // |17|19|21|23|
- "precr.qb.ph $t4, $t7, $t8 \n" // |24|26|28|30|
- "precrq.qb.ph $t6, $t7, $t8 \n" // |25|27|29|31|
- "addiu %[src_uv], %[src_uv], -32 \n"
- "addiu %[x], %[x], -1 \n"
- "swr $t4, 0(%[dst_u]) \n"
- "swl $t4, 3(%[dst_u]) \n" // |30|28|26|24|
- "swr $t6, 0(%[dst_v]) \n"
- "swl $t6, 3(%[dst_v]) \n" // |31|29|27|25|
- "swr $t2, 4(%[dst_u]) \n"
- "swl $t2, 7(%[dst_u]) \n" // |22|20|18|16|
- "swr $t3, 4(%[dst_v]) \n"
- "swl $t3, 7(%[dst_v]) \n" // |23|21|19|17|
- "swr $t0, 8(%[dst_u]) \n"
- "swl $t0, 11(%[dst_u]) \n" // |14|12|10|8|
- "swr $t1, 8(%[dst_v]) \n"
- "swl $t1, 11(%[dst_v]) \n" // |15|13|11|9|
- "swr $t9, 12(%[dst_u]) \n"
- "swl $t9, 15(%[dst_u]) \n" // |6|4|2|0|
- "swr $t5, 12(%[dst_v]) \n"
- "swl $t5, 15(%[dst_v]) \n" // |7|5|3|1|
- "addiu %[dst_v], %[dst_v], 16 \n"
- "bgtz %[x], 1b \n"
- " addiu %[dst_u], %[dst_u], 16 \n"
- "beqz %[y], 3f \n"
- " nop \n"
- "b 2f \n"
- " nop \n"
-
- "2: \n"
- "lbu $t0, -2(%[src_uv]) \n"
- "lbu $t1, -1(%[src_uv]) \n"
- "addiu %[src_uv], %[src_uv], -2 \n"
- "addiu %[y], %[y], -1 \n"
- "sb $t0, 0(%[dst_u]) \n"
- "sb $t1, 0(%[dst_v]) \n"
- "addiu %[dst_u], %[dst_u], 1 \n"
- "bgtz %[y], 2b \n"
- " addiu %[dst_v], %[dst_v], 1 \n"
-
- "3: \n"
- ".set pop \n"
- : [src_uv] "+r" (src_uv),
- [dst_u] "+r" (dst_u),
- [dst_v] "+r" (dst_v),
- [x] "=&r" (x),
- [y] "+r" (y)
- : [width] "r" (width)
- : "t0", "t1", "t2", "t3", "t4",
- "t5", "t7", "t8", "t9"
- );
-}
-
-// Convert (4 Y and 2 VU) I422 and arrange RGB values into
-// t5 = | 0 | B0 | 0 | b0 |
-// t4 = | 0 | B1 | 0 | b1 |
-// t9 = | 0 | G0 | 0 | g0 |
-// t8 = | 0 | G1 | 0 | g1 |
-// t2 = | 0 | R0 | 0 | r0 |
-// t1 = | 0 | R1 | 0 | r1 |
-#define I422ToTransientMipsRGB \
- "lw $t0, 0(%[y_buf]) \n" \
- "lhu $t1, 0(%[u_buf]) \n" \
- "lhu $t2, 0(%[v_buf]) \n" \
- "preceu.ph.qbr $t1, $t1 \n" \
- "preceu.ph.qbr $t2, $t2 \n" \
- "preceu.ph.qbra $t3, $t0 \n" \
- "preceu.ph.qbla $t0, $t0 \n" \
- "subu.ph $t1, $t1, $s5 \n" \
- "subu.ph $t2, $t2, $s5 \n" \
- "subu.ph $t3, $t3, $s4 \n" \
- "subu.ph $t0, $t0, $s4 \n" \
- "mul.ph $t3, $t3, $s0 \n" \
- "mul.ph $t0, $t0, $s0 \n" \
- "shll.ph $t4, $t1, 0x7 \n" \
- "subu.ph $t4, $t4, $t1 \n" \
- "mul.ph $t6, $t1, $s1 \n" \
- "mul.ph $t1, $t2, $s2 \n" \
- "addq_s.ph $t5, $t4, $t3 \n" \
- "addq_s.ph $t4, $t4, $t0 \n" \
- "shra.ph $t5, $t5, 6 \n" \
- "shra.ph $t4, $t4, 6 \n" \
- "addiu %[u_buf], 2 \n" \
- "addiu %[v_buf], 2 \n" \
- "addu.ph $t6, $t6, $t1 \n" \
- "mul.ph $t1, $t2, $s3 \n" \
- "addu.ph $t9, $t6, $t3 \n" \
- "addu.ph $t8, $t6, $t0 \n" \
- "shra.ph $t9, $t9, 6 \n" \
- "shra.ph $t8, $t8, 6 \n" \
- "addu.ph $t2, $t1, $t3 \n" \
- "addu.ph $t1, $t1, $t0 \n" \
- "shra.ph $t2, $t2, 6 \n" \
- "shra.ph $t1, $t1, 6 \n" \
- "subu.ph $t5, $t5, $s5 \n" \
- "subu.ph $t4, $t4, $s5 \n" \
- "subu.ph $t9, $t9, $s5 \n" \
- "subu.ph $t8, $t8, $s5 \n" \
- "subu.ph $t2, $t2, $s5 \n" \
- "subu.ph $t1, $t1, $s5 \n" \
- "shll_s.ph $t5, $t5, 8 \n" \
- "shll_s.ph $t4, $t4, 8 \n" \
- "shll_s.ph $t9, $t9, 8 \n" \
- "shll_s.ph $t8, $t8, 8 \n" \
- "shll_s.ph $t2, $t2, 8 \n" \
- "shll_s.ph $t1, $t1, 8 \n" \
- "shra.ph $t5, $t5, 8 \n" \
- "shra.ph $t4, $t4, 8 \n" \
- "shra.ph $t9, $t9, 8 \n" \
- "shra.ph $t8, $t8, 8 \n" \
- "shra.ph $t2, $t2, 8 \n" \
- "shra.ph $t1, $t1, 8 \n" \
- "addu.ph $t5, $t5, $s5 \n" \
- "addu.ph $t4, $t4, $s5 \n" \
- "addu.ph $t9, $t9, $s5 \n" \
- "addu.ph $t8, $t8, $s5 \n" \
- "addu.ph $t2, $t2, $s5 \n" \
- "addu.ph $t1, $t1, $s5 \n"
-
-void I422ToARGBRow_MIPS_DSPR2(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* rgb_buf,
- int width) {
- __asm__ __volatile__ (
- ".set push \n"
- ".set noreorder \n"
- "beqz %[width], 2f \n"
- " repl.ph $s0, 74 \n" // |YG|YG| = |74|74|
- "repl.ph $s1, -25 \n" // |UG|UG| = |-25|-25|
- "repl.ph $s2, -52 \n" // |VG|VG| = |-52|-52|
- "repl.ph $s3, 102 \n" // |VR|VR| = |102|102|
- "repl.ph $s4, 16 \n" // |0|16|0|16|
- "repl.ph $s5, 128 \n" // |128|128| // clipping
- "lui $s6, 0xff00 \n"
- "ori $s6, 0xff00 \n" // |ff|00|ff|00|ff|
-
- ".p2align 2 \n"
- "1: \n"
- I422ToTransientMipsRGB
-// Arranging into argb format
- "precr.qb.ph $t4, $t8, $t4 \n" // |G1|g1|B1|b1|
- "precr.qb.ph $t5, $t9, $t5 \n" // |G0|g0|B0|b0|
- "addiu %[width], -4 \n"
- "precrq.qb.ph $t8, $t4, $t5 \n" // |G1|B1|G0|B0|
- "precr.qb.ph $t9, $t4, $t5 \n" // |g1|b1|g0|b0|
- "precr.qb.ph $t2, $t1, $t2 \n" // |R1|r1|R0|r0|
-
- "addiu %[y_buf], 4 \n"
- "preceu.ph.qbla $t1, $t2 \n" // |0 |R1|0 |R0|
- "preceu.ph.qbra $t2, $t2 \n" // |0 |r1|0 |r0|
- "or $t1, $t1, $s6 \n" // |ff|R1|ff|R0|
- "or $t2, $t2, $s6 \n" // |ff|r1|ff|r0|
- "precrq.ph.w $t0, $t2, $t9 \n" // |ff|r1|g1|b1|
- "precrq.ph.w $t3, $t1, $t8 \n" // |ff|R1|G1|B1|
- "sll $t9, $t9, 16 \n"
- "sll $t8, $t8, 16 \n"
- "packrl.ph $t2, $t2, $t9 \n" // |ff|r0|g0|b0|
- "packrl.ph $t1, $t1, $t8 \n" // |ff|R0|G0|B0|
-// Store results.
- "sw $t2, 0(%[rgb_buf]) \n"
- "sw $t0, 4(%[rgb_buf]) \n"
- "sw $t1, 8(%[rgb_buf]) \n"
- "sw $t3, 12(%[rgb_buf]) \n"
- "bnez %[width], 1b \n"
- " addiu %[rgb_buf], 16 \n"
- "2: \n"
- ".set pop \n"
- :[y_buf] "+r" (y_buf),
- [u_buf] "+r" (u_buf),
- [v_buf] "+r" (v_buf),
- [width] "+r" (width),
- [rgb_buf] "+r" (rgb_buf)
- :
- : "t0", "t1", "t2", "t3", "t4", "t5",
- "t6", "t7", "t8", "t9",
- "s0", "s1", "s2", "s3",
- "s4", "s5", "s6"
- );
-}
-
-void I422ToABGRRow_MIPS_DSPR2(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* rgb_buf,
- int width) {
- __asm__ __volatile__ (
- ".set push \n"
- ".set noreorder \n"
- "beqz %[width], 2f \n"
- " repl.ph $s0, 74 \n" // |YG|YG| = |74|74|
- "repl.ph $s1, -25 \n" // |UG|UG| = |-25|-25|
- "repl.ph $s2, -52 \n" // |VG|VG| = |-52|-52|
- "repl.ph $s3, 102 \n" // |VR|VR| = |102|102|
- "repl.ph $s4, 16 \n" // |0|16|0|16|
- "repl.ph $s5, 128 \n" // |128|128|
- "lui $s6, 0xff00 \n"
- "ori $s6, 0xff00 \n" // |ff|00|ff|00|
-
- ".p2align 2 \n"
- "1: \n"
- I422ToTransientMipsRGB
-// Arranging into abgr format
- "precr.qb.ph $t0, $t8, $t1 \n" // |G1|g1|R1|r1|
- "precr.qb.ph $t3, $t9, $t2 \n" // |G0|g0|R0|r0|
- "precrq.qb.ph $t8, $t0, $t3 \n" // |G1|R1|G0|R0|
- "precr.qb.ph $t9, $t0, $t3 \n" // |g1|r1|g0|r0|
-
- "precr.qb.ph $t2, $t4, $t5 \n" // |B1|b1|B0|b0|
- "addiu %[width], -4 \n"
- "addiu %[y_buf], 4 \n"
- "preceu.ph.qbla $t1, $t2 \n" // |0 |B1|0 |B0|
- "preceu.ph.qbra $t2, $t2 \n" // |0 |b1|0 |b0|
- "or $t1, $t1, $s6 \n" // |ff|B1|ff|B0|
- "or $t2, $t2, $s6 \n" // |ff|b1|ff|b0|
- "precrq.ph.w $t0, $t2, $t9 \n" // |ff|b1|g1|r1|
- "precrq.ph.w $t3, $t1, $t8 \n" // |ff|B1|G1|R1|
- "sll $t9, $t9, 16 \n"
- "sll $t8, $t8, 16 \n"
- "packrl.ph $t2, $t2, $t9 \n" // |ff|b0|g0|r0|
- "packrl.ph $t1, $t1, $t8 \n" // |ff|B0|G0|R0|
-// Store results.
- "sw $t2, 0(%[rgb_buf]) \n"
- "sw $t0, 4(%[rgb_buf]) \n"
- "sw $t1, 8(%[rgb_buf]) \n"
- "sw $t3, 12(%[rgb_buf]) \n"
- "bnez %[width], 1b \n"
- " addiu %[rgb_buf], 16 \n"
- "2: \n"
- ".set pop \n"
- :[y_buf] "+r" (y_buf),
- [u_buf] "+r" (u_buf),
- [v_buf] "+r" (v_buf),
- [width] "+r" (width),
- [rgb_buf] "+r" (rgb_buf)
- :
- : "t0", "t1", "t2", "t3", "t4", "t5",
- "t6", "t7", "t8", "t9",
- "s0", "s1", "s2", "s3",
- "s4", "s5", "s6"
- );
-}
-
-void I422ToBGRARow_MIPS_DSPR2(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* rgb_buf,
- int width) {
- __asm__ __volatile__ (
- ".set push \n"
- ".set noreorder \n"
- "beqz %[width], 2f \n"
- " repl.ph $s0, 74 \n" // |YG|YG| = |74 |74 |
- "repl.ph $s1, -25 \n" // |UG|UG| = |-25|-25|
- "repl.ph $s2, -52 \n" // |VG|VG| = |-52|-52|
- "repl.ph $s3, 102 \n" // |VR|VR| = |102|102|
- "repl.ph $s4, 16 \n" // |0|16|0|16|
- "repl.ph $s5, 128 \n" // |128|128|
- "lui $s6, 0xff \n"
- "ori $s6, 0xff \n" // |00|ff|00|ff|
-
- ".p2align 2 \n"
- "1: \n"
- I422ToTransientMipsRGB
- // Arranging into bgra format
- "precr.qb.ph $t4, $t4, $t8 \n" // |B1|b1|G1|g1|
- "precr.qb.ph $t5, $t5, $t9 \n" // |B0|b0|G0|g0|
- "precrq.qb.ph $t8, $t4, $t5 \n" // |B1|G1|B0|G0|
- "precr.qb.ph $t9, $t4, $t5 \n" // |b1|g1|b0|g0|
-
- "precr.qb.ph $t2, $t1, $t2 \n" // |R1|r1|R0|r0|
- "addiu %[width], -4 \n"
- "addiu %[y_buf], 4 \n"
- "preceu.ph.qbla $t1, $t2 \n" // |0 |R1|0 |R0|
- "preceu.ph.qbra $t2, $t2 \n" // |0 |r1|0 |r0|
- "sll $t1, $t1, 8 \n" // |R1|0 |R0|0 |
- "sll $t2, $t2, 8 \n" // |r1|0 |r0|0 |
- "or $t1, $t1, $s6 \n" // |R1|ff|R0|ff|
- "or $t2, $t2, $s6 \n" // |r1|ff|r0|ff|
- "precrq.ph.w $t0, $t9, $t2 \n" // |b1|g1|r1|ff|
- "precrq.ph.w $t3, $t8, $t1 \n" // |B1|G1|R1|ff|
- "sll $t1, $t1, 16 \n"
- "sll $t2, $t2, 16 \n"
- "packrl.ph $t2, $t9, $t2 \n" // |b0|g0|r0|ff|
- "packrl.ph $t1, $t8, $t1 \n" // |B0|G0|R0|ff|
-// Store results.
- "sw $t2, 0(%[rgb_buf]) \n"
- "sw $t0, 4(%[rgb_buf]) \n"
- "sw $t1, 8(%[rgb_buf]) \n"
- "sw $t3, 12(%[rgb_buf]) \n"
- "bnez %[width], 1b \n"
- " addiu %[rgb_buf], 16 \n"
- "2: \n"
- ".set pop \n"
- :[y_buf] "+r" (y_buf),
- [u_buf] "+r" (u_buf),
- [v_buf] "+r" (v_buf),
- [width] "+r" (width),
- [rgb_buf] "+r" (rgb_buf)
- :
- : "t0", "t1", "t2", "t3", "t4", "t5",
- "t6", "t7", "t8", "t9",
- "s0", "s1", "s2", "s3",
- "s4", "s5", "s6"
- );
-}
-
-// Bilinear filter 8x2 -> 8x1
-void InterpolateRows_MIPS_DSPR2(uint8* dst_ptr, const uint8* src_ptr,
- ptrdiff_t src_stride, int dst_width,
- int source_y_fraction) {
- int y0_fraction = 256 - source_y_fraction;
- const uint8* src_ptr1 = src_ptr + src_stride;
-
- __asm__ __volatile__ (
- ".set push \n"
- ".set noreorder \n"
-
- "replv.ph $t0, %[y0_fraction] \n"
- "replv.ph $t1, %[source_y_fraction] \n"
-
- ".p2align 2 \n"
- "1: \n"
- "lw $t2, 0(%[src_ptr]) \n"
- "lw $t3, 0(%[src_ptr1]) \n"
- "lw $t4, 4(%[src_ptr]) \n"
- "lw $t5, 4(%[src_ptr1]) \n"
- "muleu_s.ph.qbl $t6, $t2, $t0 \n"
- "muleu_s.ph.qbr $t7, $t2, $t0 \n"
- "muleu_s.ph.qbl $t8, $t3, $t1 \n"
- "muleu_s.ph.qbr $t9, $t3, $t1 \n"
- "muleu_s.ph.qbl $t2, $t4, $t0 \n"
- "muleu_s.ph.qbr $t3, $t4, $t0 \n"
- "muleu_s.ph.qbl $t4, $t5, $t1 \n"
- "muleu_s.ph.qbr $t5, $t5, $t1 \n"
- "addq.ph $t6, $t6, $t8 \n"
- "addq.ph $t7, $t7, $t9 \n"
- "addq.ph $t2, $t2, $t4 \n"
- "addq.ph $t3, $t3, $t5 \n"
- "shra.ph $t6, $t6, 8 \n"
- "shra.ph $t7, $t7, 8 \n"
- "shra.ph $t2, $t2, 8 \n"
- "shra.ph $t3, $t3, 8 \n"
- "precr.qb.ph $t6, $t6, $t7 \n"
- "precr.qb.ph $t2, $t2, $t3 \n"
- "addiu %[src_ptr], %[src_ptr], 8 \n"
- "addiu %[src_ptr1], %[src_ptr1], 8 \n"
- "addiu %[dst_width], %[dst_width], -8 \n"
- "sw $t6, 0(%[dst_ptr]) \n"
- "sw $t2, 4(%[dst_ptr]) \n"
- "bgtz %[dst_width], 1b \n"
- " addiu %[dst_ptr], %[dst_ptr], 8 \n"
-
- ".set pop \n"
- : [dst_ptr] "+r" (dst_ptr),
- [src_ptr1] "+r" (src_ptr1),
- [src_ptr] "+r" (src_ptr),
- [dst_width] "+r" (dst_width)
- : [source_y_fraction] "r" (source_y_fraction),
- [y0_fraction] "r" (y0_fraction),
- [src_stride] "r" (src_stride)
- : "t0", "t1", "t2", "t3", "t4", "t5",
- "t6", "t7", "t8", "t9"
- );
-}
-#endif // __mips_dsp_rev >= 2
-
-#endif // defined(__mips__)
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/row_neon.cc b/drivers/theoraplayer/src/YUV/libyuv/src/row_neon.cc
deleted file mode 100755
index 68e380051b..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/row_neon.cc
+++ /dev/null
@@ -1,2847 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/row.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// This module is for GCC Neon
-#if !defined(LIBYUV_DISABLE_NEON) && defined(__ARM_NEON__)
-
-// Read 8 Y, 4 U and 4 V from 422
-#define READYUV422 \
- "vld1.8 {d0}, [%0]! \n" \
- "vld1.32 {d2[0]}, [%1]! \n" \
- "vld1.32 {d2[1]}, [%2]! \n"
-
-// Read 8 Y, 2 U and 2 V from 422
-#define READYUV411 \
- "vld1.8 {d0}, [%0]! \n" \
- "vld1.16 {d2[0]}, [%1]! \n" \
- "vld1.16 {d2[1]}, [%2]! \n" \
- "vmov.u8 d3, d2 \n" \
- "vzip.u8 d2, d3 \n"
-
-// Read 8 Y, 8 U and 8 V from 444
-#define READYUV444 \
- "vld1.8 {d0}, [%0]! \n" \
- "vld1.8 {d2}, [%1]! \n" \
- "vld1.8 {d3}, [%2]! \n" \
- "vpaddl.u8 q1, q1 \n" \
- "vrshrn.u16 d2, q1, #1 \n"
-
-// Read 8 Y, and set 4 U and 4 V to 128
-#define READYUV400 \
- "vld1.8 {d0}, [%0]! \n" \
- "vmov.u8 d2, #128 \n"
-
-// Read 8 Y and 4 UV from NV12
-#define READNV12 \
- "vld1.8 {d0}, [%0]! \n" \
- "vld1.8 {d2}, [%1]! \n" \
- "vmov.u8 d3, d2 \n"/* split odd/even uv apart */\
- "vuzp.u8 d2, d3 \n" \
- "vtrn.u32 d2, d3 \n"
-
-// Read 8 Y and 4 VU from NV21
-#define READNV21 \
- "vld1.8 {d0}, [%0]! \n" \
- "vld1.8 {d2}, [%1]! \n" \
- "vmov.u8 d3, d2 \n"/* split odd/even uv apart */\
- "vuzp.u8 d3, d2 \n" \
- "vtrn.u32 d2, d3 \n"
-
-// Read 8 YUY2
-#define READYUY2 \
- "vld2.8 {d0, d2}, [%0]! \n" \
- "vmov.u8 d3, d2 \n" \
- "vuzp.u8 d2, d3 \n" \
- "vtrn.u32 d2, d3 \n"
-
-// Read 8 UYVY
-#define READUYVY \
- "vld2.8 {d2, d3}, [%0]! \n" \
- "vmov.u8 d0, d3 \n" \
- "vmov.u8 d3, d2 \n" \
- "vuzp.u8 d2, d3 \n" \
- "vtrn.u32 d2, d3 \n"
-
-#define YUV422TORGB \
- "veor.u8 d2, d26 \n"/*subtract 128 from u and v*/\
- "vmull.s8 q8, d2, d24 \n"/* u/v B/R component */\
- "vmull.s8 q9, d2, d25 \n"/* u/v G component */\
- "vmov.u8 d1, #0 \n"/* split odd/even y apart */\
- "vtrn.u8 d0, d1 \n" \
- "vsub.s16 q0, q0, q15 \n"/* offset y */\
- "vmul.s16 q0, q0, q14 \n" \
- "vadd.s16 d18, d19 \n" \
- "vqadd.s16 d20, d0, d16 \n" /* B */ \
- "vqadd.s16 d21, d1, d16 \n" \
- "vqadd.s16 d22, d0, d17 \n" /* R */ \
- "vqadd.s16 d23, d1, d17 \n" \
- "vqadd.s16 d16, d0, d18 \n" /* G */ \
- "vqadd.s16 d17, d1, d18 \n" \
- "vqshrun.s16 d0, q10, #6 \n" /* B */ \
- "vqshrun.s16 d1, q11, #6 \n" /* G */ \
- "vqshrun.s16 d2, q8, #6 \n" /* R */ \
- "vmovl.u8 q10, d0 \n"/* set up for reinterleave*/\
- "vmovl.u8 q11, d1 \n" \
- "vmovl.u8 q8, d2 \n" \
- "vtrn.u8 d20, d21 \n" \
- "vtrn.u8 d22, d23 \n" \
- "vtrn.u8 d16, d17 \n" \
- "vmov.u8 d21, d16 \n"
-
-static vec8 kUVToRB = { 127, 127, 127, 127, 102, 102, 102, 102,
- 0, 0, 0, 0, 0, 0, 0, 0 };
-static vec8 kUVToG = { -25, -25, -25, -25, -52, -52, -52, -52,
- 0, 0, 0, 0, 0, 0, 0, 0 };
-
-void I444ToARGBRow_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width) {
- asm volatile (
-#ifdef _ANDROID
- ".fpu neon\n"
-#endif
- "vld1.8 {d24}, [%5] \n"
- "vld1.8 {d25}, [%6] \n"
- "vmov.u8 d26, #128 \n"
- "vmov.u16 q14, #74 \n"
- "vmov.u16 q15, #16 \n"
- ".p2align 2 \n"
- "1: \n"
- READYUV444
- YUV422TORGB
- "subs %4, %4, #8 \n"
- "vmov.u8 d23, #255 \n"
- "vst4.8 {d20, d21, d22, d23}, [%3]! \n"
- "bgt 1b \n"
- : "+r"(src_y), // %0
- "+r"(src_u), // %1
- "+r"(src_v), // %2
- "+r"(dst_argb), // %3
- "+r"(width) // %4
- : "r"(&kUVToRB), // %5
- "r"(&kUVToG) // %6
- : "cc", "memory", "q0", "q1", "q2", "q3",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-void I422ToARGBRow_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width) {
- asm volatile (
- "vld1.8 {d24}, [%5] \n"
- "vld1.8 {d25}, [%6] \n"
- "vmov.u8 d26, #128 \n"
- "vmov.u16 q14, #74 \n"
- "vmov.u16 q15, #16 \n"
- ".p2align 2 \n"
- "1: \n"
- READYUV422
- YUV422TORGB
- "subs %4, %4, #8 \n"
- "vmov.u8 d23, #255 \n"
- "vst4.8 {d20, d21, d22, d23}, [%3]! \n"
- "bgt 1b \n"
- : "+r"(src_y), // %0
- "+r"(src_u), // %1
- "+r"(src_v), // %2
- "+r"(dst_argb), // %3
- "+r"(width) // %4
- : "r"(&kUVToRB), // %5
- "r"(&kUVToG) // %6
- : "cc", "memory", "q0", "q1", "q2", "q3",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-void I411ToARGBRow_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int width) {
- asm volatile (
- "vld1.8 {d24}, [%5] \n"
- "vld1.8 {d25}, [%6] \n"
- "vmov.u8 d26, #128 \n"
- "vmov.u16 q14, #74 \n"
- "vmov.u16 q15, #16 \n"
- ".p2align 2 \n"
- "1: \n"
- READYUV411
- YUV422TORGB
- "subs %4, %4, #8 \n"
- "vmov.u8 d23, #255 \n"
- "vst4.8 {d20, d21, d22, d23}, [%3]! \n"
- "bgt 1b \n"
- : "+r"(src_y), // %0
- "+r"(src_u), // %1
- "+r"(src_v), // %2
- "+r"(dst_argb), // %3
- "+r"(width) // %4
- : "r"(&kUVToRB), // %5
- "r"(&kUVToG) // %6
- : "cc", "memory", "q0", "q1", "q2", "q3",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-void I422ToBGRARow_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_bgra,
- int width) {
- asm volatile (
- "vld1.8 {d24}, [%5] \n"
- "vld1.8 {d25}, [%6] \n"
- "vmov.u8 d26, #128 \n"
- "vmov.u16 q14, #74 \n"
- "vmov.u16 q15, #16 \n"
- ".p2align 2 \n"
- "1: \n"
- READYUV422
- YUV422TORGB
- "subs %4, %4, #8 \n"
- "vswp.u8 d20, d22 \n"
- "vmov.u8 d19, #255 \n"
- "vst4.8 {d19, d20, d21, d22}, [%3]! \n"
- "bgt 1b \n"
- : "+r"(src_y), // %0
- "+r"(src_u), // %1
- "+r"(src_v), // %2
- "+r"(dst_bgra), // %3
- "+r"(width) // %4
- : "r"(&kUVToRB), // %5
- "r"(&kUVToG) // %6
- : "cc", "memory", "q0", "q1", "q2", "q3",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-void I422ToABGRRow_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_abgr,
- int width) {
- asm volatile (
- "vld1.8 {d24}, [%5] \n"
- "vld1.8 {d25}, [%6] \n"
- "vmov.u8 d26, #128 \n"
- "vmov.u16 q14, #74 \n"
- "vmov.u16 q15, #16 \n"
- ".p2align 2 \n"
- "1: \n"
- READYUV422
- YUV422TORGB
- "subs %4, %4, #8 \n"
- "vswp.u8 d20, d22 \n"
- "vmov.u8 d23, #255 \n"
- "vst4.8 {d20, d21, d22, d23}, [%3]! \n"
- "bgt 1b \n"
- : "+r"(src_y), // %0
- "+r"(src_u), // %1
- "+r"(src_v), // %2
- "+r"(dst_abgr), // %3
- "+r"(width) // %4
- : "r"(&kUVToRB), // %5
- "r"(&kUVToG) // %6
- : "cc", "memory", "q0", "q1", "q2", "q3",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-void I422ToRGBARow_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_rgba,
- int width) {
- asm volatile (
- "vld1.8 {d24}, [%5] \n"
- "vld1.8 {d25}, [%6] \n"
- "vmov.u8 d26, #128 \n"
- "vmov.u16 q14, #74 \n"
- "vmov.u16 q15, #16 \n"
- ".p2align 2 \n"
- "1: \n"
- READYUV422
- YUV422TORGB
- "subs %4, %4, #8 \n"
- "vmov.u8 d19, #255 \n"
- "vst4.8 {d19, d20, d21, d22}, [%3]! \n"
- "bgt 1b \n"
- : "+r"(src_y), // %0
- "+r"(src_u), // %1
- "+r"(src_v), // %2
- "+r"(dst_rgba), // %3
- "+r"(width) // %4
- : "r"(&kUVToRB), // %5
- "r"(&kUVToG) // %6
- : "cc", "memory", "q0", "q1", "q2", "q3",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-void I422ToRGB24Row_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_rgb24,
- int width) {
- asm volatile (
- "vld1.8 {d24}, [%5] \n"
- "vld1.8 {d25}, [%6] \n"
- "vmov.u8 d26, #128 \n"
- "vmov.u16 q14, #74 \n"
- "vmov.u16 q15, #16 \n"
- ".p2align 2 \n"
- "1: \n"
- READYUV422
- YUV422TORGB
- "subs %4, %4, #8 \n"
- "vst3.8 {d20, d21, d22}, [%3]! \n"
- "bgt 1b \n"
- : "+r"(src_y), // %0
- "+r"(src_u), // %1
- "+r"(src_v), // %2
- "+r"(dst_rgb24), // %3
- "+r"(width) // %4
- : "r"(&kUVToRB), // %5
- "r"(&kUVToG) // %6
- : "cc", "memory", "q0", "q1", "q2", "q3",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-void I422ToRAWRow_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_raw,
- int width) {
- asm volatile (
- "vld1.8 {d24}, [%5] \n"
- "vld1.8 {d25}, [%6] \n"
- "vmov.u8 d26, #128 \n"
- "vmov.u16 q14, #74 \n"
- "vmov.u16 q15, #16 \n"
- ".p2align 2 \n"
- "1: \n"
- READYUV422
- YUV422TORGB
- "subs %4, %4, #8 \n"
- "vswp.u8 d20, d22 \n"
- "vst3.8 {d20, d21, d22}, [%3]! \n"
- "bgt 1b \n"
- : "+r"(src_y), // %0
- "+r"(src_u), // %1
- "+r"(src_v), // %2
- "+r"(dst_raw), // %3
- "+r"(width) // %4
- : "r"(&kUVToRB), // %5
- "r"(&kUVToG) // %6
- : "cc", "memory", "q0", "q1", "q2", "q3",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-#define ARGBTORGB565 \
- "vshr.u8 d20, d20, #3 \n" /* B */ \
- "vshr.u8 d21, d21, #2 \n" /* G */ \
- "vshr.u8 d22, d22, #3 \n" /* R */ \
- "vmovl.u8 q8, d20 \n" /* B */ \
- "vmovl.u8 q9, d21 \n" /* G */ \
- "vmovl.u8 q10, d22 \n" /* R */ \
- "vshl.u16 q9, q9, #5 \n" /* G */ \
- "vshl.u16 q10, q10, #11 \n" /* R */ \
- "vorr q0, q8, q9 \n" /* BG */ \
- "vorr q0, q0, q10 \n" /* BGR */
-
-void I422ToRGB565Row_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_rgb565,
- int width) {
- asm volatile (
- "vld1.8 {d24}, [%5] \n"
- "vld1.8 {d25}, [%6] \n"
- "vmov.u8 d26, #128 \n"
- "vmov.u16 q14, #74 \n"
- "vmov.u16 q15, #16 \n"
- ".p2align 2 \n"
- "1: \n"
- READYUV422
- YUV422TORGB
- "subs %4, %4, #8 \n"
- ARGBTORGB565
- "vst1.8 {q0}, [%3]! \n" // store 8 pixels RGB565.
- "bgt 1b \n"
- : "+r"(src_y), // %0
- "+r"(src_u), // %1
- "+r"(src_v), // %2
- "+r"(dst_rgb565), // %3
- "+r"(width) // %4
- : "r"(&kUVToRB), // %5
- "r"(&kUVToG) // %6
- : "cc", "memory", "q0", "q1", "q2", "q3",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-#define ARGBTOARGB1555 \
- "vshr.u8 q10, q10, #3 \n" /* B */ \
- "vshr.u8 d22, d22, #3 \n" /* R */ \
- "vshr.u8 d23, d23, #7 \n" /* A */ \
- "vmovl.u8 q8, d20 \n" /* B */ \
- "vmovl.u8 q9, d21 \n" /* G */ \
- "vmovl.u8 q10, d22 \n" /* R */ \
- "vmovl.u8 q11, d23 \n" /* A */ \
- "vshl.u16 q9, q9, #5 \n" /* G */ \
- "vshl.u16 q10, q10, #10 \n" /* R */ \
- "vshl.u16 q11, q11, #15 \n" /* A */ \
- "vorr q0, q8, q9 \n" /* BG */ \
- "vorr q1, q10, q11 \n" /* RA */ \
- "vorr q0, q0, q1 \n" /* BGRA */
-
-void I422ToARGB1555Row_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb1555,
- int width) {
- asm volatile (
- "vld1.8 {d24}, [%5] \n"
- "vld1.8 {d25}, [%6] \n"
- "vmov.u8 d26, #128 \n"
- "vmov.u16 q14, #74 \n"
- "vmov.u16 q15, #16 \n"
- ".p2align 2 \n"
- "1: \n"
- READYUV422
- YUV422TORGB
- "subs %4, %4, #8 \n"
- "vmov.u8 d23, #255 \n"
- ARGBTOARGB1555
- "vst1.8 {q0}, [%3]! \n" // store 8 pixels ARGB1555.
- "bgt 1b \n"
- : "+r"(src_y), // %0
- "+r"(src_u), // %1
- "+r"(src_v), // %2
- "+r"(dst_argb1555), // %3
- "+r"(width) // %4
- : "r"(&kUVToRB), // %5
- "r"(&kUVToG) // %6
- : "cc", "memory", "q0", "q1", "q2", "q3",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-#define ARGBTOARGB4444 \
- "vshr.u8 d20, d20, #4 \n" /* B */ \
- "vbic.32 d21, d21, d4 \n" /* G */ \
- "vshr.u8 d22, d22, #4 \n" /* R */ \
- "vbic.32 d23, d23, d4 \n" /* A */ \
- "vorr d0, d20, d21 \n" /* BG */ \
- "vorr d1, d22, d23 \n" /* RA */ \
- "vzip.u8 d0, d1 \n" /* BGRA */
-
-void I422ToARGB4444Row_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb4444,
- int width) {
- asm volatile (
- "vld1.8 {d24}, [%5] \n"
- "vld1.8 {d25}, [%6] \n"
- "vmov.u8 d26, #128 \n"
- "vmov.u16 q14, #74 \n"
- "vmov.u16 q15, #16 \n"
- "vmov.u8 d4, #0x0f \n" // bits to clear with vbic.
- ".p2align 2 \n"
- "1: \n"
- READYUV422
- YUV422TORGB
- "subs %4, %4, #8 \n"
- "vmov.u8 d23, #255 \n"
- ARGBTOARGB4444
- "vst1.8 {q0}, [%3]! \n" // store 8 pixels ARGB4444.
- "bgt 1b \n"
- : "+r"(src_y), // %0
- "+r"(src_u), // %1
- "+r"(src_v), // %2
- "+r"(dst_argb4444), // %3
- "+r"(width) // %4
- : "r"(&kUVToRB), // %5
- "r"(&kUVToG) // %6
- : "cc", "memory", "q0", "q1", "q2", "q3",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-void YToARGBRow_NEON(const uint8* src_y,
- uint8* dst_argb,
- int width) {
- asm volatile (
- "vld1.8 {d24}, [%3] \n"
- "vld1.8 {d25}, [%4] \n"
- "vmov.u8 d26, #128 \n"
- "vmov.u16 q14, #74 \n"
- "vmov.u16 q15, #16 \n"
- ".p2align 2 \n"
- "1: \n"
- READYUV400
- YUV422TORGB
- "subs %2, %2, #8 \n"
- "vmov.u8 d23, #255 \n"
- "vst4.8 {d20, d21, d22, d23}, [%1]! \n"
- "bgt 1b \n"
- : "+r"(src_y), // %0
- "+r"(dst_argb), // %1
- "+r"(width) // %2
- : "r"(&kUVToRB), // %3
- "r"(&kUVToG) // %4
- : "cc", "memory", "q0", "q1", "q2", "q3",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-void I400ToARGBRow_NEON(const uint8* src_y,
- uint8* dst_argb,
- int width) {
- asm volatile (
- ".p2align 2 \n"
- "vmov.u8 d23, #255 \n"
- "1: \n"
- "vld1.8 {d20}, [%0]! \n"
- "vmov d21, d20 \n"
- "vmov d22, d20 \n"
- "subs %2, %2, #8 \n"
- "vst4.8 {d20, d21, d22, d23}, [%1]! \n"
- "bgt 1b \n"
- : "+r"(src_y), // %0
- "+r"(dst_argb), // %1
- "+r"(width) // %2
- :
- : "cc", "memory", "d20", "d21", "d22", "d23"
- );
-}
-
-void NV12ToARGBRow_NEON(const uint8* src_y,
- const uint8* src_uv,
- uint8* dst_argb,
- int width) {
- asm volatile (
- "vld1.8 {d24}, [%4] \n"
- "vld1.8 {d25}, [%5] \n"
- "vmov.u8 d26, #128 \n"
- "vmov.u16 q14, #74 \n"
- "vmov.u16 q15, #16 \n"
- ".p2align 2 \n"
- "1: \n"
- READNV12
- YUV422TORGB
- "subs %3, %3, #8 \n"
- "vmov.u8 d23, #255 \n"
- "vst4.8 {d20, d21, d22, d23}, [%2]! \n"
- "bgt 1b \n"
- : "+r"(src_y), // %0
- "+r"(src_uv), // %1
- "+r"(dst_argb), // %2
- "+r"(width) // %3
- : "r"(&kUVToRB), // %4
- "r"(&kUVToG) // %5
- : "cc", "memory", "q0", "q1", "q2", "q3",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-void NV21ToARGBRow_NEON(const uint8* src_y,
- const uint8* src_uv,
- uint8* dst_argb,
- int width) {
- asm volatile (
- "vld1.8 {d24}, [%4] \n"
- "vld1.8 {d25}, [%5] \n"
- "vmov.u8 d26, #128 \n"
- "vmov.u16 q14, #74 \n"
- "vmov.u16 q15, #16 \n"
- ".p2align 2 \n"
- "1: \n"
- READNV21
- YUV422TORGB
- "subs %3, %3, #8 \n"
- "vmov.u8 d23, #255 \n"
- "vst4.8 {d20, d21, d22, d23}, [%2]! \n"
- "bgt 1b \n"
- : "+r"(src_y), // %0
- "+r"(src_uv), // %1
- "+r"(dst_argb), // %2
- "+r"(width) // %3
- : "r"(&kUVToRB), // %4
- "r"(&kUVToG) // %5
- : "cc", "memory", "q0", "q1", "q2", "q3",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-void NV12ToRGB565Row_NEON(const uint8* src_y,
- const uint8* src_uv,
- uint8* dst_rgb565,
- int width) {
- asm volatile (
- "vld1.8 {d24}, [%4] \n"
- "vld1.8 {d25}, [%5] \n"
- "vmov.u8 d26, #128 \n"
- "vmov.u16 q14, #74 \n"
- "vmov.u16 q15, #16 \n"
- ".p2align 2 \n"
- "1: \n"
- READNV12
- YUV422TORGB
- "subs %3, %3, #8 \n"
- ARGBTORGB565
- "vst1.8 {q0}, [%2]! \n" // store 8 pixels RGB565.
- "bgt 1b \n"
- : "+r"(src_y), // %0
- "+r"(src_uv), // %1
- "+r"(dst_rgb565), // %2
- "+r"(width) // %3
- : "r"(&kUVToRB), // %4
- "r"(&kUVToG) // %5
- : "cc", "memory", "q0", "q1", "q2", "q3",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-void NV21ToRGB565Row_NEON(const uint8* src_y,
- const uint8* src_uv,
- uint8* dst_rgb565,
- int width) {
- asm volatile (
- "vld1.8 {d24}, [%4] \n"
- "vld1.8 {d25}, [%5] \n"
- "vmov.u8 d26, #128 \n"
- "vmov.u16 q14, #74 \n"
- "vmov.u16 q15, #16 \n"
- ".p2align 2 \n"
- "1: \n"
- READNV21
- YUV422TORGB
- "subs %3, %3, #8 \n"
- ARGBTORGB565
- "vst1.8 {q0}, [%2]! \n" // store 8 pixels RGB565.
- "bgt 1b \n"
- : "+r"(src_y), // %0
- "+r"(src_uv), // %1
- "+r"(dst_rgb565), // %2
- "+r"(width) // %3
- : "r"(&kUVToRB), // %4
- "r"(&kUVToG) // %5
- : "cc", "memory", "q0", "q1", "q2", "q3",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-void YUY2ToARGBRow_NEON(const uint8* src_yuy2,
- uint8* dst_argb,
- int width) {
- asm volatile (
- "vld1.8 {d24}, [%3] \n"
- "vld1.8 {d25}, [%4] \n"
- "vmov.u8 d26, #128 \n"
- "vmov.u16 q14, #74 \n"
- "vmov.u16 q15, #16 \n"
- ".p2align 2 \n"
- "1: \n"
- READYUY2
- YUV422TORGB
- "subs %2, %2, #8 \n"
- "vmov.u8 d23, #255 \n"
- "vst4.8 {d20, d21, d22, d23}, [%1]! \n"
- "bgt 1b \n"
- : "+r"(src_yuy2), // %0
- "+r"(dst_argb), // %1
- "+r"(width) // %2
- : "r"(&kUVToRB), // %3
- "r"(&kUVToG) // %4
- : "cc", "memory", "q0", "q1", "q2", "q3",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-void UYVYToARGBRow_NEON(const uint8* src_uyvy,
- uint8* dst_argb,
- int width) {
- asm volatile (
- "vld1.8 {d24}, [%3] \n"
- "vld1.8 {d25}, [%4] \n"
- "vmov.u8 d26, #128 \n"
- "vmov.u16 q14, #74 \n"
- "vmov.u16 q15, #16 \n"
- ".p2align 2 \n"
- "1: \n"
- READUYVY
- YUV422TORGB
- "subs %2, %2, #8 \n"
- "vmov.u8 d23, #255 \n"
- "vst4.8 {d20, d21, d22, d23}, [%1]! \n"
- "bgt 1b \n"
- : "+r"(src_uyvy), // %0
- "+r"(dst_argb), // %1
- "+r"(width) // %2
- : "r"(&kUVToRB), // %3
- "r"(&kUVToG) // %4
- : "cc", "memory", "q0", "q1", "q2", "q3",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-// Reads 16 pairs of UV and write even values to dst_u and odd to dst_v.
-void SplitUVRow_NEON(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
- int width) {
- asm volatile (
- ".p2align 2 \n"
- "1: \n"
- "vld2.8 {q0, q1}, [%0]! \n" // load 16 pairs of UV
- "subs %3, %3, #16 \n" // 16 processed per loop
- "vst1.8 {q0}, [%1]! \n" // store U
- "vst1.8 {q1}, [%2]! \n" // store V
- "bgt 1b \n"
- : "+r"(src_uv), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+r"(width) // %3 // Output registers
- : // Input registers
- : "cc", "memory", "q0", "q1" // Clobber List
- );
-}
-
-// Reads 16 U's and V's and writes out 16 pairs of UV.
-void MergeUVRow_NEON(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
- int width) {
- asm volatile (
- ".p2align 2 \n"
- "1: \n"
- "vld1.8 {q0}, [%0]! \n" // load U
- "vld1.8 {q1}, [%1]! \n" // load V
- "subs %3, %3, #16 \n" // 16 processed per loop
- "vst2.u8 {q0, q1}, [%2]! \n" // store 16 pairs of UV
- "bgt 1b \n"
- :
- "+r"(src_u), // %0
- "+r"(src_v), // %1
- "+r"(dst_uv), // %2
- "+r"(width) // %3 // Output registers
- : // Input registers
- : "cc", "memory", "q0", "q1" // Clobber List
- );
-}
-
-// Copy multiple of 32. vld4.8 allow unaligned and is fastest on a15.
-void CopyRow_NEON(const uint8* src, uint8* dst, int count) {
- asm volatile (
- ".p2align 2 \n"
- "1: \n"
- "vld1.8 {d0, d1, d2, d3}, [%0]! \n" // load 32
- "subs %2, %2, #32 \n" // 32 processed per loop
- "vst1.8 {d0, d1, d2, d3}, [%1]! \n" // store 32
- "bgt 1b \n"
- : "+r"(src), // %0
- "+r"(dst), // %1
- "+r"(count) // %2 // Output registers
- : // Input registers
- : "cc", "memory", "q0", "q1" // Clobber List
- );
-}
-
-// SetRow8 writes 'count' bytes using a 32 bit value repeated.
-void SetRow_NEON(uint8* dst, uint32 v32, int count) {
- asm volatile (
- "vdup.u32 q0, %2 \n" // duplicate 4 ints
- "1: \n"
- "subs %1, %1, #16 \n" // 16 bytes per loop
- "vst1.8 {q0}, [%0]! \n" // store
- "bgt 1b \n"
- : "+r"(dst), // %0
- "+r"(count) // %1
- : "r"(v32) // %2
- : "cc", "memory", "q0"
- );
-}
-
-// TODO(fbarchard): Make fully assembler
-// SetRow32 writes 'count' words using a 32 bit value repeated.
-void ARGBSetRows_NEON(uint8* dst, uint32 v32, int width,
- int dst_stride, int height) {
- for (int y = 0; y < height; ++y) {
- SetRow_NEON(dst, v32, width << 2);
- dst += dst_stride;
- }
-}
-
-void MirrorRow_NEON(const uint8* src, uint8* dst, int width) {
- asm volatile (
- // Start at end of source row.
- "mov r3, #-16 \n"
- "add %0, %0, %2 \n"
- "sub %0, #16 \n"
-
- ".p2align 2 \n"
- "1: \n"
- "vld1.8 {q0}, [%0], r3 \n" // src -= 16
- "subs %2, #16 \n" // 16 pixels per loop.
- "vrev64.8 q0, q0 \n"
- "vst1.8 {d1}, [%1]! \n" // dst += 16
- "vst1.8 {d0}, [%1]! \n"
- "bgt 1b \n"
- : "+r"(src), // %0
- "+r"(dst), // %1
- "+r"(width) // %2
- :
- : "cc", "memory", "r3", "q0"
- );
-}
-
-void MirrorUVRow_NEON(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
- int width) {
- asm volatile (
- // Start at end of source row.
- "mov r12, #-16 \n"
- "add %0, %0, %3, lsl #1 \n"
- "sub %0, #16 \n"
-
- ".p2align 2 \n"
- "1: \n"
- "vld2.8 {d0, d1}, [%0], r12 \n" // src -= 16
- "subs %3, #8 \n" // 8 pixels per loop.
- "vrev64.8 q0, q0 \n"
- "vst1.8 {d0}, [%1]! \n" // dst += 8
- "vst1.8 {d1}, [%2]! \n"
- "bgt 1b \n"
- : "+r"(src_uv), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+r"(width) // %3
- :
- : "cc", "memory", "r12", "q0"
- );
-}
-
-void ARGBMirrorRow_NEON(const uint8* src, uint8* dst, int width) {
- asm volatile (
- // Start at end of source row.
- "mov r3, #-16 \n"
- "add %0, %0, %2, lsl #2 \n"
- "sub %0, #16 \n"
-
- ".p2align 2 \n"
- "1: \n"
- "vld1.8 {q0}, [%0], r3 \n" // src -= 16
- "subs %2, #4 \n" // 4 pixels per loop.
- "vrev64.32 q0, q0 \n"
- "vst1.8 {d1}, [%1]! \n" // dst += 16
- "vst1.8 {d0}, [%1]! \n"
- "bgt 1b \n"
- : "+r"(src), // %0
- "+r"(dst), // %1
- "+r"(width) // %2
- :
- : "cc", "memory", "r3", "q0"
- );
-}
-
-void RGB24ToARGBRow_NEON(const uint8* src_rgb24, uint8* dst_argb, int pix) {
- asm volatile (
- "vmov.u8 d4, #255 \n" // Alpha
- ".p2align 2 \n"
- "1: \n"
- "vld3.8 {d1, d2, d3}, [%0]! \n" // load 8 pixels of RGB24.
- "subs %2, %2, #8 \n" // 8 processed per loop.
- "vst4.8 {d1, d2, d3, d4}, [%1]! \n" // store 8 pixels of ARGB.
- "bgt 1b \n"
- : "+r"(src_rgb24), // %0
- "+r"(dst_argb), // %1
- "+r"(pix) // %2
- :
- : "cc", "memory", "d1", "d2", "d3", "d4" // Clobber List
- );
-}
-
-void RAWToARGBRow_NEON(const uint8* src_raw, uint8* dst_argb, int pix) {
- asm volatile (
- "vmov.u8 d4, #255 \n" // Alpha
- ".p2align 2 \n"
- "1: \n"
- "vld3.8 {d1, d2, d3}, [%0]! \n" // load 8 pixels of RAW.
- "subs %2, %2, #8 \n" // 8 processed per loop.
- "vswp.u8 d1, d3 \n" // swap R, B
- "vst4.8 {d1, d2, d3, d4}, [%1]! \n" // store 8 pixels of ARGB.
- "bgt 1b \n"
- : "+r"(src_raw), // %0
- "+r"(dst_argb), // %1
- "+r"(pix) // %2
- :
- : "cc", "memory", "d1", "d2", "d3", "d4" // Clobber List
- );
-}
-
-#define RGB565TOARGB \
- "vshrn.u16 d6, q0, #5 \n" /* G xxGGGGGG */ \
- "vuzp.u8 d0, d1 \n" /* d0 xxxBBBBB RRRRRxxx */ \
- "vshl.u8 d6, d6, #2 \n" /* G GGGGGG00 upper 6 */ \
- "vshr.u8 d1, d1, #3 \n" /* R 000RRRRR lower 5 */ \
- "vshl.u8 q0, q0, #3 \n" /* B,R BBBBB000 upper 5 */ \
- "vshr.u8 q2, q0, #5 \n" /* B,R 00000BBB lower 3 */ \
- "vorr.u8 d0, d0, d4 \n" /* B */ \
- "vshr.u8 d4, d6, #6 \n" /* G 000000GG lower 2 */ \
- "vorr.u8 d2, d1, d5 \n" /* R */ \
- "vorr.u8 d1, d4, d6 \n" /* G */
-
-void RGB565ToARGBRow_NEON(const uint8* src_rgb565, uint8* dst_argb, int pix) {
- asm volatile (
- "vmov.u8 d3, #255 \n" // Alpha
- ".p2align 2 \n"
- "1: \n"
- "vld1.8 {q0}, [%0]! \n" // load 8 RGB565 pixels.
- "subs %2, %2, #8 \n" // 8 processed per loop.
- RGB565TOARGB
- "vst4.8 {d0, d1, d2, d3}, [%1]! \n" // store 8 pixels of ARGB.
- "bgt 1b \n"
- : "+r"(src_rgb565), // %0
- "+r"(dst_argb), // %1
- "+r"(pix) // %2
- :
- : "cc", "memory", "q0", "q1", "q2", "q3" // Clobber List
- );
-}
-
-#define ARGB1555TOARGB \
- "vshrn.u16 d7, q0, #8 \n" /* A Arrrrrxx */ \
- "vshr.u8 d6, d7, #2 \n" /* R xxxRRRRR */ \
- "vshrn.u16 d5, q0, #5 \n" /* G xxxGGGGG */ \
- "vmovn.u16 d4, q0 \n" /* B xxxBBBBB */ \
- "vshr.u8 d7, d7, #7 \n" /* A 0000000A */ \
- "vneg.s8 d7, d7 \n" /* A AAAAAAAA upper 8 */ \
- "vshl.u8 d6, d6, #3 \n" /* R RRRRR000 upper 5 */ \
- "vshr.u8 q1, q3, #5 \n" /* R,A 00000RRR lower 3 */ \
- "vshl.u8 q0, q2, #3 \n" /* B,G BBBBB000 upper 5 */ \
- "vshr.u8 q2, q0, #5 \n" /* B,G 00000BBB lower 3 */ \
- "vorr.u8 q1, q1, q3 \n" /* R,A */ \
- "vorr.u8 q0, q0, q2 \n" /* B,G */ \
-
-// RGB555TOARGB is same as ARGB1555TOARGB but ignores alpha.
-#define RGB555TOARGB \
- "vshrn.u16 d6, q0, #5 \n" /* G xxxGGGGG */ \
- "vuzp.u8 d0, d1 \n" /* d0 xxxBBBBB xRRRRRxx */ \
- "vshl.u8 d6, d6, #3 \n" /* G GGGGG000 upper 5 */ \
- "vshr.u8 d1, d1, #2 \n" /* R 00xRRRRR lower 5 */ \
- "vshl.u8 q0, q0, #3 \n" /* B,R BBBBB000 upper 5 */ \
- "vshr.u8 q2, q0, #5 \n" /* B,R 00000BBB lower 3 */ \
- "vorr.u8 d0, d0, d4 \n" /* B */ \
- "vshr.u8 d4, d6, #5 \n" /* G 00000GGG lower 3 */ \
- "vorr.u8 d2, d1, d5 \n" /* R */ \
- "vorr.u8 d1, d4, d6 \n" /* G */
-
-void ARGB1555ToARGBRow_NEON(const uint8* src_argb1555, uint8* dst_argb,
- int pix) {
- asm volatile (
- "vmov.u8 d3, #255 \n" // Alpha
- ".p2align 2 \n"
- "1: \n"
- "vld1.8 {q0}, [%0]! \n" // load 8 ARGB1555 pixels.
- "subs %2, %2, #8 \n" // 8 processed per loop.
- ARGB1555TOARGB
- "vst4.8 {d0, d1, d2, d3}, [%1]! \n" // store 8 pixels of ARGB.
- "bgt 1b \n"
- : "+r"(src_argb1555), // %0
- "+r"(dst_argb), // %1
- "+r"(pix) // %2
- :
- : "cc", "memory", "q0", "q1", "q2", "q3" // Clobber List
- );
-}
-
-#define ARGB4444TOARGB \
- "vuzp.u8 d0, d1 \n" /* d0 BG, d1 RA */ \
- "vshl.u8 q2, q0, #4 \n" /* B,R BBBB0000 */ \
- "vshr.u8 q1, q0, #4 \n" /* G,A 0000GGGG */ \
- "vshr.u8 q0, q2, #4 \n" /* B,R 0000BBBB */ \
- "vorr.u8 q0, q0, q2 \n" /* B,R BBBBBBBB */ \
- "vshl.u8 q2, q1, #4 \n" /* G,A GGGG0000 */ \
- "vorr.u8 q1, q1, q2 \n" /* G,A GGGGGGGG */ \
- "vswp.u8 d1, d2 \n" /* B,R,G,A -> B,G,R,A */
-
-void ARGB4444ToARGBRow_NEON(const uint8* src_argb4444, uint8* dst_argb,
- int pix) {
- asm volatile (
- "vmov.u8 d3, #255 \n" // Alpha
- ".p2align 2 \n"
- "1: \n"
- "vld1.8 {q0}, [%0]! \n" // load 8 ARGB4444 pixels.
- "subs %2, %2, #8 \n" // 8 processed per loop.
- ARGB4444TOARGB
- "vst4.8 {d0, d1, d2, d3}, [%1]! \n" // store 8 pixels of ARGB.
- "bgt 1b \n"
- : "+r"(src_argb4444), // %0
- "+r"(dst_argb), // %1
- "+r"(pix) // %2
- :
- : "cc", "memory", "q0", "q1", "q2" // Clobber List
- );
-}
-
-void ARGBToRGB24Row_NEON(const uint8* src_argb, uint8* dst_rgb24, int pix) {
- asm volatile (
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d1, d2, d3, d4}, [%0]! \n" // load 8 pixels of ARGB.
- "subs %2, %2, #8 \n" // 8 processed per loop.
- "vst3.8 {d1, d2, d3}, [%1]! \n" // store 8 pixels of RGB24.
- "bgt 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_rgb24), // %1
- "+r"(pix) // %2
- :
- : "cc", "memory", "d1", "d2", "d3", "d4" // Clobber List
- );
-}
-
-void ARGBToRAWRow_NEON(const uint8* src_argb, uint8* dst_raw, int pix) {
- asm volatile (
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d1, d2, d3, d4}, [%0]! \n" // load 8 pixels of ARGB.
- "subs %2, %2, #8 \n" // 8 processed per loop.
- "vswp.u8 d1, d3 \n" // swap R, B
- "vst3.8 {d1, d2, d3}, [%1]! \n" // store 8 pixels of RAW.
- "bgt 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_raw), // %1
- "+r"(pix) // %2
- :
- : "cc", "memory", "d1", "d2", "d3", "d4" // Clobber List
- );
-}
-
-void YUY2ToYRow_NEON(const uint8* src_yuy2, uint8* dst_y, int pix) {
- asm volatile (
- ".p2align 2 \n"
- "1: \n"
- "vld2.8 {q0, q1}, [%0]! \n" // load 16 pixels of YUY2.
- "subs %2, %2, #16 \n" // 16 processed per loop.
- "vst1.8 {q0}, [%1]! \n" // store 16 pixels of Y.
- "bgt 1b \n"
- : "+r"(src_yuy2), // %0
- "+r"(dst_y), // %1
- "+r"(pix) // %2
- :
- : "cc", "memory", "q0", "q1" // Clobber List
- );
-}
-
-void UYVYToYRow_NEON(const uint8* src_uyvy, uint8* dst_y, int pix) {
- asm volatile (
- ".p2align 2 \n"
- "1: \n"
- "vld2.8 {q0, q1}, [%0]! \n" // load 16 pixels of UYVY.
- "subs %2, %2, #16 \n" // 16 processed per loop.
- "vst1.8 {q1}, [%1]! \n" // store 16 pixels of Y.
- "bgt 1b \n"
- : "+r"(src_uyvy), // %0
- "+r"(dst_y), // %1
- "+r"(pix) // %2
- :
- : "cc", "memory", "q0", "q1" // Clobber List
- );
-}
-
-void YUY2ToUV422Row_NEON(const uint8* src_yuy2, uint8* dst_u, uint8* dst_v,
- int pix) {
- asm volatile (
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 16 pixels of YUY2.
- "subs %3, %3, #16 \n" // 16 pixels = 8 UVs.
- "vst1.8 {d1}, [%1]! \n" // store 8 U.
- "vst1.8 {d3}, [%2]! \n" // store 8 V.
- "bgt 1b \n"
- : "+r"(src_yuy2), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+r"(pix) // %3
- :
- : "cc", "memory", "d0", "d1", "d2", "d3" // Clobber List
- );
-}
-
-void UYVYToUV422Row_NEON(const uint8* src_uyvy, uint8* dst_u, uint8* dst_v,
- int pix) {
- asm volatile (
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 16 pixels of UYVY.
- "subs %3, %3, #16 \n" // 16 pixels = 8 UVs.
- "vst1.8 {d0}, [%1]! \n" // store 8 U.
- "vst1.8 {d2}, [%2]! \n" // store 8 V.
- "bgt 1b \n"
- : "+r"(src_uyvy), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+r"(pix) // %3
- :
- : "cc", "memory", "d0", "d1", "d2", "d3" // Clobber List
- );
-}
-
-void YUY2ToUVRow_NEON(const uint8* src_yuy2, int stride_yuy2,
- uint8* dst_u, uint8* dst_v, int pix) {
- asm volatile (
- "add %1, %0, %1 \n" // stride + src_yuy2
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 16 pixels of YUY2.
- "subs %4, %4, #16 \n" // 16 pixels = 8 UVs.
- "vld4.8 {d4, d5, d6, d7}, [%1]! \n" // load next row YUY2.
- "vrhadd.u8 d1, d1, d5 \n" // average rows of U
- "vrhadd.u8 d3, d3, d7 \n" // average rows of V
- "vst1.8 {d1}, [%2]! \n" // store 8 U.
- "vst1.8 {d3}, [%3]! \n" // store 8 V.
- "bgt 1b \n"
- : "+r"(src_yuy2), // %0
- "+r"(stride_yuy2), // %1
- "+r"(dst_u), // %2
- "+r"(dst_v), // %3
- "+r"(pix) // %4
- :
- : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7" // Clobber List
- );
-}
-
-void UYVYToUVRow_NEON(const uint8* src_uyvy, int stride_uyvy,
- uint8* dst_u, uint8* dst_v, int pix) {
- asm volatile (
- "add %1, %0, %1 \n" // stride + src_uyvy
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 16 pixels of UYVY.
- "subs %4, %4, #16 \n" // 16 pixels = 8 UVs.
- "vld4.8 {d4, d5, d6, d7}, [%1]! \n" // load next row UYVY.
- "vrhadd.u8 d0, d0, d4 \n" // average rows of U
- "vrhadd.u8 d2, d2, d6 \n" // average rows of V
- "vst1.8 {d0}, [%2]! \n" // store 8 U.
- "vst1.8 {d2}, [%3]! \n" // store 8 V.
- "bgt 1b \n"
- : "+r"(src_uyvy), // %0
- "+r"(stride_uyvy), // %1
- "+r"(dst_u), // %2
- "+r"(dst_v), // %3
- "+r"(pix) // %4
- :
- : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7" // Clobber List
- );
-}
-
-void HalfRow_NEON(const uint8* src_uv, int src_uv_stride,
- uint8* dst_uv, int pix) {
- asm volatile (
- // change the stride to row 2 pointer
- "add %1, %0 \n"
- "1: \n"
- "vld1.8 {q0}, [%0]! \n" // load row 1 16 pixels.
- "subs %3, %3, #16 \n" // 16 processed per loop
- "vld1.8 {q1}, [%1]! \n" // load row 2 16 pixels.
- "vrhadd.u8 q0, q1 \n" // average row 1 and 2
- "vst1.8 {q0}, [%2]! \n"
- "bgt 1b \n"
- : "+r"(src_uv), // %0
- "+r"(src_uv_stride), // %1
- "+r"(dst_uv), // %2
- "+r"(pix) // %3
- :
- : "cc", "memory", "q0", "q1" // Clobber List
- );
-}
-
-// Select 2 channels from ARGB on alternating pixels. e.g. BGBGBGBG
-void ARGBToBayerRow_NEON(const uint8* src_argb, uint8* dst_bayer,
- uint32 selector, int pix) {
- asm volatile (
- "vmov.u32 d6[0], %3 \n" // selector
- "1: \n"
- "vld1.8 {q0, q1}, [%0]! \n" // load row 8 pixels.
- "subs %2, %2, #8 \n" // 8 processed per loop
- "vtbl.8 d4, {d0, d1}, d6 \n" // look up 4 pixels
- "vtbl.8 d5, {d2, d3}, d6 \n" // look up 4 pixels
- "vtrn.u32 d4, d5 \n" // combine 8 pixels
- "vst1.8 {d4}, [%1]! \n" // store 8.
- "bgt 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_bayer), // %1
- "+r"(pix) // %2
- : "r"(selector) // %3
- : "cc", "memory", "q0", "q1", "q2", "q3" // Clobber List
- );
-}
-
-// Select G channels from ARGB. e.g. GGGGGGGG
-void ARGBToBayerGGRow_NEON(const uint8* src_argb, uint8* dst_bayer,
- uint32 /*selector*/, int pix) {
- asm volatile (
- "1: \n"
- "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load row 8 pixels.
- "subs %2, %2, #8 \n" // 8 processed per loop
- "vst1.8 {d1}, [%1]! \n" // store 8 G's.
- "bgt 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_bayer), // %1
- "+r"(pix) // %2
- :
- : "cc", "memory", "q0", "q1" // Clobber List
- );
-}
-
-// For BGRAToARGB, ABGRToARGB, RGBAToARGB, and ARGBToRGBA.
-void ARGBShuffleRow_NEON(const uint8* src_argb, uint8* dst_argb,
- const uint8* shuffler, int pix) {
- asm volatile (
- "vld1.8 {q2}, [%3] \n" // shuffler
- "1: \n"
- "vld1.8 {q0}, [%0]! \n" // load 4 pixels.
- "subs %2, %2, #4 \n" // 4 processed per loop
- "vtbl.8 d2, {d0, d1}, d4 \n" // look up 2 first pixels
- "vtbl.8 d3, {d0, d1}, d5 \n" // look up 2 next pixels
- "vst1.8 {q1}, [%1]! \n" // store 4.
- "bgt 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_argb), // %1
- "+r"(pix) // %2
- : "r"(shuffler) // %3
- : "cc", "memory", "q0", "q1", "q2" // Clobber List
- );
-}
-
-void I422ToYUY2Row_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_yuy2, int width) {
- asm volatile (
- ".p2align 2 \n"
- "1: \n"
- "vld2.8 {d0, d2}, [%0]! \n" // load 16 Ys
- "vld1.8 {d1}, [%1]! \n" // load 8 Us
- "vld1.8 {d3}, [%2]! \n" // load 8 Vs
- "subs %4, %4, #16 \n" // 16 pixels
- "vst4.8 {d0, d1, d2, d3}, [%3]! \n" // Store 8 YUY2/16 pixels.
- "bgt 1b \n"
- : "+r"(src_y), // %0
- "+r"(src_u), // %1
- "+r"(src_v), // %2
- "+r"(dst_yuy2), // %3
- "+r"(width) // %4
- :
- : "cc", "memory", "d0", "d1", "d2", "d3"
- );
-}
-
-void I422ToUYVYRow_NEON(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_uyvy, int width) {
- asm volatile (
- ".p2align 2 \n"
- "1: \n"
- "vld2.8 {d1, d3}, [%0]! \n" // load 16 Ys
- "vld1.8 {d0}, [%1]! \n" // load 8 Us
- "vld1.8 {d2}, [%2]! \n" // load 8 Vs
- "subs %4, %4, #16 \n" // 16 pixels
- "vst4.8 {d0, d1, d2, d3}, [%3]! \n" // Store 8 UYVY/16 pixels.
- "bgt 1b \n"
- : "+r"(src_y), // %0
- "+r"(src_u), // %1
- "+r"(src_v), // %2
- "+r"(dst_uyvy), // %3
- "+r"(width) // %4
- :
- : "cc", "memory", "d0", "d1", "d2", "d3"
- );
-}
-
-void ARGBToRGB565Row_NEON(const uint8* src_argb, uint8* dst_rgb565, int pix) {
- asm volatile (
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d20, d21, d22, d23}, [%0]! \n" // load 8 pixels of ARGB.
- "subs %2, %2, #8 \n" // 8 processed per loop.
- ARGBTORGB565
- "vst1.8 {q0}, [%1]! \n" // store 8 pixels RGB565.
- "bgt 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_rgb565), // %1
- "+r"(pix) // %2
- :
- : "cc", "memory", "q0", "q8", "q9", "q10", "q11"
- );
-}
-
-void ARGBToARGB1555Row_NEON(const uint8* src_argb, uint8* dst_argb1555,
- int pix) {
- asm volatile (
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d20, d21, d22, d23}, [%0]! \n" // load 8 pixels of ARGB.
- "subs %2, %2, #8 \n" // 8 processed per loop.
- ARGBTOARGB1555
- "vst1.8 {q0}, [%1]! \n" // store 8 pixels ARGB1555.
- "bgt 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_argb1555), // %1
- "+r"(pix) // %2
- :
- : "cc", "memory", "q0", "q8", "q9", "q10", "q11"
- );
-}
-
-void ARGBToARGB4444Row_NEON(const uint8* src_argb, uint8* dst_argb4444,
- int pix) {
- asm volatile (
- "vmov.u8 d4, #0x0f \n" // bits to clear with vbic.
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d20, d21, d22, d23}, [%0]! \n" // load 8 pixels of ARGB.
- "subs %2, %2, #8 \n" // 8 processed per loop.
- ARGBTOARGB4444
- "vst1.8 {q0}, [%1]! \n" // store 8 pixels ARGB4444.
- "bgt 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_argb4444), // %1
- "+r"(pix) // %2
- :
- : "cc", "memory", "q0", "q8", "q9", "q10", "q11"
- );
-}
-
-void ARGBToYRow_NEON(const uint8* src_argb, uint8* dst_y, int pix) {
- asm volatile (
- "vmov.u8 d24, #13 \n" // B * 0.1016 coefficient
- "vmov.u8 d25, #65 \n" // G * 0.5078 coefficient
- "vmov.u8 d26, #33 \n" // R * 0.2578 coefficient
- "vmov.u8 d27, #16 \n" // Add 16 constant
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 ARGB pixels.
- "subs %2, %2, #8 \n" // 8 processed per loop.
- "vmull.u8 q2, d0, d24 \n" // B
- "vmlal.u8 q2, d1, d25 \n" // G
- "vmlal.u8 q2, d2, d26 \n" // R
- "vqrshrun.s16 d0, q2, #7 \n" // 16 bit to 8 bit Y
- "vqadd.u8 d0, d27 \n"
- "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y.
- "bgt 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_y), // %1
- "+r"(pix) // %2
- :
- : "cc", "memory", "q0", "q1", "q2", "q12", "q13"
- );
-}
-
-void ARGBToYJRow_NEON(const uint8* src_argb, uint8* dst_y, int pix) {
- asm volatile (
- "vmov.u8 d24, #15 \n" // B * 0.11400 coefficient
- "vmov.u8 d25, #75 \n" // G * 0.58700 coefficient
- "vmov.u8 d26, #38 \n" // R * 0.29900 coefficient
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 ARGB pixels.
- "subs %2, %2, #8 \n" // 8 processed per loop.
- "vmull.u8 q2, d0, d24 \n" // B
- "vmlal.u8 q2, d1, d25 \n" // G
- "vmlal.u8 q2, d2, d26 \n" // R
- "vqrshrun.s16 d0, q2, #7 \n" // 15 bit to 8 bit Y
- "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y.
- "bgt 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_y), // %1
- "+r"(pix) // %2
- :
- : "cc", "memory", "q0", "q1", "q2", "q12", "q13"
- );
-}
-
-// 8x1 pixels.
-void ARGBToUV444Row_NEON(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
- int pix) {
- asm volatile (
- "vmov.u8 d24, #112 \n" // UB / VR 0.875 coefficient
- "vmov.u8 d25, #74 \n" // UG -0.5781 coefficient
- "vmov.u8 d26, #38 \n" // UR -0.2969 coefficient
- "vmov.u8 d27, #18 \n" // VB -0.1406 coefficient
- "vmov.u8 d28, #94 \n" // VG -0.7344 coefficient
- "vmov.u16 q15, #0x8080 \n" // 128.5
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 ARGB pixels.
- "subs %3, %3, #8 \n" // 8 processed per loop.
- "vmull.u8 q2, d0, d24 \n" // B
- "vmlsl.u8 q2, d1, d25 \n" // G
- "vmlsl.u8 q2, d2, d26 \n" // R
- "vadd.u16 q2, q2, q15 \n" // +128 -> unsigned
-
- "vmull.u8 q3, d2, d24 \n" // R
- "vmlsl.u8 q3, d1, d28 \n" // G
- "vmlsl.u8 q3, d0, d27 \n" // B
- "vadd.u16 q3, q3, q15 \n" // +128 -> unsigned
-
- "vqshrn.u16 d0, q2, #8 \n" // 16 bit to 8 bit U
- "vqshrn.u16 d1, q3, #8 \n" // 16 bit to 8 bit V
-
- "vst1.8 {d0}, [%1]! \n" // store 8 pixels U.
- "vst1.8 {d1}, [%2]! \n" // store 8 pixels V.
- "bgt 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+r"(pix) // %3
- :
- : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q12", "q13", "q14", "q15"
- );
-}
-
-// 16x1 pixels -> 8x1. pix is number of argb pixels. e.g. 16.
-void ARGBToUV422Row_NEON(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
- int pix) {
- asm volatile (
- "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient
- "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient
- "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient
- "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient
- "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient
- "vmov.u16 q15, #0x8080 \n" // 128.5
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 ARGB pixels.
- "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 ARGB pixels.
-
- "vpaddl.u8 q0, q0 \n" // B 16 bytes -> 8 shorts.
- "vpaddl.u8 q1, q1 \n" // G 16 bytes -> 8 shorts.
- "vpaddl.u8 q2, q2 \n" // R 16 bytes -> 8 shorts.
-
- "subs %3, %3, #16 \n" // 16 processed per loop.
- "vmul.s16 q8, q0, q10 \n" // B
- "vmls.s16 q8, q1, q11 \n" // G
- "vmls.s16 q8, q2, q12 \n" // R
- "vadd.u16 q8, q8, q15 \n" // +128 -> unsigned
-
- "vmul.s16 q9, q2, q10 \n" // R
- "vmls.s16 q9, q1, q14 \n" // G
- "vmls.s16 q9, q0, q13 \n" // B
- "vadd.u16 q9, q9, q15 \n" // +128 -> unsigned
-
- "vqshrn.u16 d0, q8, #8 \n" // 16 bit to 8 bit U
- "vqshrn.u16 d1, q9, #8 \n" // 16 bit to 8 bit V
-
- "vst1.8 {d0}, [%1]! \n" // store 8 pixels U.
- "vst1.8 {d1}, [%2]! \n" // store 8 pixels V.
- "bgt 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+r"(pix) // %3
- :
- : "cc", "memory", "q0", "q1", "q2", "q3",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-// 32x1 pixels -> 8x1. pix is number of argb pixels. e.g. 32.
-void ARGBToUV411Row_NEON(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
- int pix) {
- asm volatile (
- "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient
- "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient
- "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient
- "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient
- "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient
- "vmov.u16 q15, #0x8080 \n" // 128.5
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 ARGB pixels.
- "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 ARGB pixels.
- "vpaddl.u8 q0, q0 \n" // B 16 bytes -> 8 shorts.
- "vpaddl.u8 q1, q1 \n" // G 16 bytes -> 8 shorts.
- "vpaddl.u8 q2, q2 \n" // R 16 bytes -> 8 shorts.
- "vld4.8 {d8, d10, d12, d14}, [%0]! \n" // load 8 more ARGB pixels.
- "vld4.8 {d9, d11, d13, d15}, [%0]! \n" // load last 8 ARGB pixels.
- "vpaddl.u8 q4, q4 \n" // B 16 bytes -> 8 shorts.
- "vpaddl.u8 q5, q5 \n" // G 16 bytes -> 8 shorts.
- "vpaddl.u8 q6, q6 \n" // R 16 bytes -> 8 shorts.
-
- "vpadd.u16 d0, d0, d1 \n" // B 16 shorts -> 8 shorts.
- "vpadd.u16 d1, d8, d9 \n" // B
- "vpadd.u16 d2, d2, d3 \n" // G 16 shorts -> 8 shorts.
- "vpadd.u16 d3, d10, d11 \n" // G
- "vpadd.u16 d4, d4, d5 \n" // R 16 shorts -> 8 shorts.
- "vpadd.u16 d5, d12, d13 \n" // R
-
- "vrshr.u16 q0, q0, #1 \n" // 2x average
- "vrshr.u16 q1, q1, #1 \n"
- "vrshr.u16 q2, q2, #1 \n"
-
- "subs %3, %3, #32 \n" // 32 processed per loop.
- "vmul.s16 q8, q0, q10 \n" // B
- "vmls.s16 q8, q1, q11 \n" // G
- "vmls.s16 q8, q2, q12 \n" // R
- "vadd.u16 q8, q8, q15 \n" // +128 -> unsigned
- "vmul.s16 q9, q2, q10 \n" // R
- "vmls.s16 q9, q1, q14 \n" // G
- "vmls.s16 q9, q0, q13 \n" // B
- "vadd.u16 q9, q9, q15 \n" // +128 -> unsigned
- "vqshrn.u16 d0, q8, #8 \n" // 16 bit to 8 bit U
- "vqshrn.u16 d1, q9, #8 \n" // 16 bit to 8 bit V
- "vst1.8 {d0}, [%1]! \n" // store 8 pixels U.
- "vst1.8 {d1}, [%2]! \n" // store 8 pixels V.
- "bgt 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+r"(pix) // %3
- :
- : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-// 16x2 pixels -> 8x1. pix is number of argb pixels. e.g. 16.
-#define RGBTOUV(QB, QG, QR) \
- "vmul.s16 q8, " #QB ", q10 \n" /* B */ \
- "vmls.s16 q8, " #QG ", q11 \n" /* G */ \
- "vmls.s16 q8, " #QR ", q12 \n" /* R */ \
- "vadd.u16 q8, q8, q15 \n" /* +128 -> unsigned */ \
- "vmul.s16 q9, " #QR ", q10 \n" /* R */ \
- "vmls.s16 q9, " #QG ", q14 \n" /* G */ \
- "vmls.s16 q9, " #QB ", q13 \n" /* B */ \
- "vadd.u16 q9, q9, q15 \n" /* +128 -> unsigned */ \
- "vqshrn.u16 d0, q8, #8 \n" /* 16 bit to 8 bit U */ \
- "vqshrn.u16 d1, q9, #8 \n" /* 16 bit to 8 bit V */
-
-// TODO(fbarchard): Consider vhadd vertical, then vpaddl horizontal, avoid shr.
-void ARGBToUVRow_NEON(const uint8* src_argb, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int pix) {
- asm volatile (
- "add %1, %0, %1 \n" // src_stride + src_argb
- "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient
- "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient
- "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient
- "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient
- "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient
- "vmov.u16 q15, #0x8080 \n" // 128.5
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 ARGB pixels.
- "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 ARGB pixels.
- "vpaddl.u8 q0, q0 \n" // B 16 bytes -> 8 shorts.
- "vpaddl.u8 q1, q1 \n" // G 16 bytes -> 8 shorts.
- "vpaddl.u8 q2, q2 \n" // R 16 bytes -> 8 shorts.
- "vld4.8 {d8, d10, d12, d14}, [%1]! \n" // load 8 more ARGB pixels.
- "vld4.8 {d9, d11, d13, d15}, [%1]! \n" // load last 8 ARGB pixels.
- "vpadal.u8 q0, q4 \n" // B 16 bytes -> 8 shorts.
- "vpadal.u8 q1, q5 \n" // G 16 bytes -> 8 shorts.
- "vpadal.u8 q2, q6 \n" // R 16 bytes -> 8 shorts.
-
- "vrshr.u16 q0, q0, #1 \n" // 2x average
- "vrshr.u16 q1, q1, #1 \n"
- "vrshr.u16 q2, q2, #1 \n"
-
- "subs %4, %4, #16 \n" // 32 processed per loop.
- RGBTOUV(q0, q1, q2)
- "vst1.8 {d0}, [%2]! \n" // store 8 pixels U.
- "vst1.8 {d1}, [%3]! \n" // store 8 pixels V.
- "bgt 1b \n"
- : "+r"(src_argb), // %0
- "+r"(src_stride_argb), // %1
- "+r"(dst_u), // %2
- "+r"(dst_v), // %3
- "+r"(pix) // %4
- :
- : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-// TODO(fbarchard): Subsample match C code.
-void ARGBToUVJRow_NEON(const uint8* src_argb, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int pix) {
- asm volatile (
- "add %1, %0, %1 \n" // src_stride + src_argb
- "vmov.s16 q10, #127 / 2 \n" // UB / VR 0.500 coefficient
- "vmov.s16 q11, #84 / 2 \n" // UG -0.33126 coefficient
- "vmov.s16 q12, #43 / 2 \n" // UR -0.16874 coefficient
- "vmov.s16 q13, #20 / 2 \n" // VB -0.08131 coefficient
- "vmov.s16 q14, #107 / 2 \n" // VG -0.41869 coefficient
- "vmov.u16 q15, #0x8080 \n" // 128.5
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 ARGB pixels.
- "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 ARGB pixels.
- "vpaddl.u8 q0, q0 \n" // B 16 bytes -> 8 shorts.
- "vpaddl.u8 q1, q1 \n" // G 16 bytes -> 8 shorts.
- "vpaddl.u8 q2, q2 \n" // R 16 bytes -> 8 shorts.
- "vld4.8 {d8, d10, d12, d14}, [%1]! \n" // load 8 more ARGB pixels.
- "vld4.8 {d9, d11, d13, d15}, [%1]! \n" // load last 8 ARGB pixels.
- "vpadal.u8 q0, q4 \n" // B 16 bytes -> 8 shorts.
- "vpadal.u8 q1, q5 \n" // G 16 bytes -> 8 shorts.
- "vpadal.u8 q2, q6 \n" // R 16 bytes -> 8 shorts.
-
- "vrshr.u16 q0, q0, #1 \n" // 2x average
- "vrshr.u16 q1, q1, #1 \n"
- "vrshr.u16 q2, q2, #1 \n"
-
- "subs %4, %4, #16 \n" // 32 processed per loop.
- RGBTOUV(q0, q1, q2)
- "vst1.8 {d0}, [%2]! \n" // store 8 pixels U.
- "vst1.8 {d1}, [%3]! \n" // store 8 pixels V.
- "bgt 1b \n"
- : "+r"(src_argb), // %0
- "+r"(src_stride_argb), // %1
- "+r"(dst_u), // %2
- "+r"(dst_v), // %3
- "+r"(pix) // %4
- :
- : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-void BGRAToUVRow_NEON(const uint8* src_bgra, int src_stride_bgra,
- uint8* dst_u, uint8* dst_v, int pix) {
- asm volatile (
- "add %1, %0, %1 \n" // src_stride + src_bgra
- "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient
- "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient
- "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient
- "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient
- "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient
- "vmov.u16 q15, #0x8080 \n" // 128.5
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 BGRA pixels.
- "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 BGRA pixels.
- "vpaddl.u8 q3, q3 \n" // B 16 bytes -> 8 shorts.
- "vpaddl.u8 q2, q2 \n" // G 16 bytes -> 8 shorts.
- "vpaddl.u8 q1, q1 \n" // R 16 bytes -> 8 shorts.
- "vld4.8 {d8, d10, d12, d14}, [%1]! \n" // load 8 more BGRA pixels.
- "vld4.8 {d9, d11, d13, d15}, [%1]! \n" // load last 8 BGRA pixels.
- "vpadal.u8 q3, q7 \n" // B 16 bytes -> 8 shorts.
- "vpadal.u8 q2, q6 \n" // G 16 bytes -> 8 shorts.
- "vpadal.u8 q1, q5 \n" // R 16 bytes -> 8 shorts.
-
- "vrshr.u16 q1, q1, #1 \n" // 2x average
- "vrshr.u16 q2, q2, #1 \n"
- "vrshr.u16 q3, q3, #1 \n"
-
- "subs %4, %4, #16 \n" // 32 processed per loop.
- RGBTOUV(q3, q2, q1)
- "vst1.8 {d0}, [%2]! \n" // store 8 pixels U.
- "vst1.8 {d1}, [%3]! \n" // store 8 pixels V.
- "bgt 1b \n"
- : "+r"(src_bgra), // %0
- "+r"(src_stride_bgra), // %1
- "+r"(dst_u), // %2
- "+r"(dst_v), // %3
- "+r"(pix) // %4
- :
- : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-void ABGRToUVRow_NEON(const uint8* src_abgr, int src_stride_abgr,
- uint8* dst_u, uint8* dst_v, int pix) {
- asm volatile (
- "add %1, %0, %1 \n" // src_stride + src_abgr
- "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient
- "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient
- "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient
- "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient
- "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient
- "vmov.u16 q15, #0x8080 \n" // 128.5
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 ABGR pixels.
- "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 ABGR pixels.
- "vpaddl.u8 q2, q2 \n" // B 16 bytes -> 8 shorts.
- "vpaddl.u8 q1, q1 \n" // G 16 bytes -> 8 shorts.
- "vpaddl.u8 q0, q0 \n" // R 16 bytes -> 8 shorts.
- "vld4.8 {d8, d10, d12, d14}, [%1]! \n" // load 8 more ABGR pixels.
- "vld4.8 {d9, d11, d13, d15}, [%1]! \n" // load last 8 ABGR pixels.
- "vpadal.u8 q2, q6 \n" // B 16 bytes -> 8 shorts.
- "vpadal.u8 q1, q5 \n" // G 16 bytes -> 8 shorts.
- "vpadal.u8 q0, q4 \n" // R 16 bytes -> 8 shorts.
-
- "vrshr.u16 q0, q0, #1 \n" // 2x average
- "vrshr.u16 q1, q1, #1 \n"
- "vrshr.u16 q2, q2, #1 \n"
-
- "subs %4, %4, #16 \n" // 32 processed per loop.
- RGBTOUV(q2, q1, q0)
- "vst1.8 {d0}, [%2]! \n" // store 8 pixels U.
- "vst1.8 {d1}, [%3]! \n" // store 8 pixels V.
- "bgt 1b \n"
- : "+r"(src_abgr), // %0
- "+r"(src_stride_abgr), // %1
- "+r"(dst_u), // %2
- "+r"(dst_v), // %3
- "+r"(pix) // %4
- :
- : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-void RGBAToUVRow_NEON(const uint8* src_rgba, int src_stride_rgba,
- uint8* dst_u, uint8* dst_v, int pix) {
- asm volatile (
- "add %1, %0, %1 \n" // src_stride + src_rgba
- "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient
- "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient
- "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient
- "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient
- "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient
- "vmov.u16 q15, #0x8080 \n" // 128.5
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 RGBA pixels.
- "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 RGBA pixels.
- "vpaddl.u8 q0, q1 \n" // B 16 bytes -> 8 shorts.
- "vpaddl.u8 q1, q2 \n" // G 16 bytes -> 8 shorts.
- "vpaddl.u8 q2, q3 \n" // R 16 bytes -> 8 shorts.
- "vld4.8 {d8, d10, d12, d14}, [%1]! \n" // load 8 more RGBA pixels.
- "vld4.8 {d9, d11, d13, d15}, [%1]! \n" // load last 8 RGBA pixels.
- "vpadal.u8 q0, q5 \n" // B 16 bytes -> 8 shorts.
- "vpadal.u8 q1, q6 \n" // G 16 bytes -> 8 shorts.
- "vpadal.u8 q2, q7 \n" // R 16 bytes -> 8 shorts.
-
- "vrshr.u16 q0, q0, #1 \n" // 2x average
- "vrshr.u16 q1, q1, #1 \n"
- "vrshr.u16 q2, q2, #1 \n"
-
- "subs %4, %4, #16 \n" // 32 processed per loop.
- RGBTOUV(q0, q1, q2)
- "vst1.8 {d0}, [%2]! \n" // store 8 pixels U.
- "vst1.8 {d1}, [%3]! \n" // store 8 pixels V.
- "bgt 1b \n"
- : "+r"(src_rgba), // %0
- "+r"(src_stride_rgba), // %1
- "+r"(dst_u), // %2
- "+r"(dst_v), // %3
- "+r"(pix) // %4
- :
- : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-void RGB24ToUVRow_NEON(const uint8* src_rgb24, int src_stride_rgb24,
- uint8* dst_u, uint8* dst_v, int pix) {
- asm volatile (
- "add %1, %0, %1 \n" // src_stride + src_rgb24
- "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient
- "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient
- "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient
- "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient
- "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient
- "vmov.u16 q15, #0x8080 \n" // 128.5
- ".p2align 2 \n"
- "1: \n"
- "vld3.8 {d0, d2, d4}, [%0]! \n" // load 8 RGB24 pixels.
- "vld3.8 {d1, d3, d5}, [%0]! \n" // load next 8 RGB24 pixels.
- "vpaddl.u8 q0, q0 \n" // B 16 bytes -> 8 shorts.
- "vpaddl.u8 q1, q1 \n" // G 16 bytes -> 8 shorts.
- "vpaddl.u8 q2, q2 \n" // R 16 bytes -> 8 shorts.
- "vld3.8 {d8, d10, d12}, [%1]! \n" // load 8 more RGB24 pixels.
- "vld3.8 {d9, d11, d13}, [%1]! \n" // load last 8 RGB24 pixels.
- "vpadal.u8 q0, q4 \n" // B 16 bytes -> 8 shorts.
- "vpadal.u8 q1, q5 \n" // G 16 bytes -> 8 shorts.
- "vpadal.u8 q2, q6 \n" // R 16 bytes -> 8 shorts.
-
- "vrshr.u16 q0, q0, #1 \n" // 2x average
- "vrshr.u16 q1, q1, #1 \n"
- "vrshr.u16 q2, q2, #1 \n"
-
- "subs %4, %4, #16 \n" // 32 processed per loop.
- RGBTOUV(q0, q1, q2)
- "vst1.8 {d0}, [%2]! \n" // store 8 pixels U.
- "vst1.8 {d1}, [%3]! \n" // store 8 pixels V.
- "bgt 1b \n"
- : "+r"(src_rgb24), // %0
- "+r"(src_stride_rgb24), // %1
- "+r"(dst_u), // %2
- "+r"(dst_v), // %3
- "+r"(pix) // %4
- :
- : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-void RAWToUVRow_NEON(const uint8* src_raw, int src_stride_raw,
- uint8* dst_u, uint8* dst_v, int pix) {
- asm volatile (
- "add %1, %0, %1 \n" // src_stride + src_raw
- "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient
- "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient
- "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient
- "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient
- "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient
- "vmov.u16 q15, #0x8080 \n" // 128.5
- ".p2align 2 \n"
- "1: \n"
- "vld3.8 {d0, d2, d4}, [%0]! \n" // load 8 RAW pixels.
- "vld3.8 {d1, d3, d5}, [%0]! \n" // load next 8 RAW pixels.
- "vpaddl.u8 q2, q2 \n" // B 16 bytes -> 8 shorts.
- "vpaddl.u8 q1, q1 \n" // G 16 bytes -> 8 shorts.
- "vpaddl.u8 q0, q0 \n" // R 16 bytes -> 8 shorts.
- "vld3.8 {d8, d10, d12}, [%1]! \n" // load 8 more RAW pixels.
- "vld3.8 {d9, d11, d13}, [%1]! \n" // load last 8 RAW pixels.
- "vpadal.u8 q2, q6 \n" // B 16 bytes -> 8 shorts.
- "vpadal.u8 q1, q5 \n" // G 16 bytes -> 8 shorts.
- "vpadal.u8 q0, q4 \n" // R 16 bytes -> 8 shorts.
-
- "vrshr.u16 q0, q0, #1 \n" // 2x average
- "vrshr.u16 q1, q1, #1 \n"
- "vrshr.u16 q2, q2, #1 \n"
-
- "subs %4, %4, #16 \n" // 32 processed per loop.
- RGBTOUV(q2, q1, q0)
- "vst1.8 {d0}, [%2]! \n" // store 8 pixels U.
- "vst1.8 {d1}, [%3]! \n" // store 8 pixels V.
- "bgt 1b \n"
- : "+r"(src_raw), // %0
- "+r"(src_stride_raw), // %1
- "+r"(dst_u), // %2
- "+r"(dst_v), // %3
- "+r"(pix) // %4
- :
- : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-// 16x2 pixels -> 8x1. pix is number of argb pixels. e.g. 16.
-void RGB565ToUVRow_NEON(const uint8* src_rgb565, int src_stride_rgb565,
- uint8* dst_u, uint8* dst_v, int pix) {
- asm volatile (
- "add %1, %0, %1 \n" // src_stride + src_argb
- "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient
- "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient
- "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient
- "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient
- "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient
- "vmov.u16 q15, #0x8080 \n" // 128.5
- ".p2align 2 \n"
- "1: \n"
- "vld1.8 {q0}, [%0]! \n" // load 8 RGB565 pixels.
- RGB565TOARGB
- "vpaddl.u8 d8, d0 \n" // B 8 bytes -> 4 shorts.
- "vpaddl.u8 d10, d1 \n" // G 8 bytes -> 4 shorts.
- "vpaddl.u8 d12, d2 \n" // R 8 bytes -> 4 shorts.
- "vld1.8 {q0}, [%0]! \n" // next 8 RGB565 pixels.
- RGB565TOARGB
- "vpaddl.u8 d9, d0 \n" // B 8 bytes -> 4 shorts.
- "vpaddl.u8 d11, d1 \n" // G 8 bytes -> 4 shorts.
- "vpaddl.u8 d13, d2 \n" // R 8 bytes -> 4 shorts.
-
- "vld1.8 {q0}, [%1]! \n" // load 8 RGB565 pixels.
- RGB565TOARGB
- "vpadal.u8 d8, d0 \n" // B 8 bytes -> 4 shorts.
- "vpadal.u8 d10, d1 \n" // G 8 bytes -> 4 shorts.
- "vpadal.u8 d12, d2 \n" // R 8 bytes -> 4 shorts.
- "vld1.8 {q0}, [%1]! \n" // next 8 RGB565 pixels.
- RGB565TOARGB
- "vpadal.u8 d9, d0 \n" // B 8 bytes -> 4 shorts.
- "vpadal.u8 d11, d1 \n" // G 8 bytes -> 4 shorts.
- "vpadal.u8 d13, d2 \n" // R 8 bytes -> 4 shorts.
-
- "vrshr.u16 q4, q4, #1 \n" // 2x average
- "vrshr.u16 q5, q5, #1 \n"
- "vrshr.u16 q6, q6, #1 \n"
-
- "subs %4, %4, #16 \n" // 16 processed per loop.
- "vmul.s16 q8, q4, q10 \n" // B
- "vmls.s16 q8, q5, q11 \n" // G
- "vmls.s16 q8, q6, q12 \n" // R
- "vadd.u16 q8, q8, q15 \n" // +128 -> unsigned
- "vmul.s16 q9, q6, q10 \n" // R
- "vmls.s16 q9, q5, q14 \n" // G
- "vmls.s16 q9, q4, q13 \n" // B
- "vadd.u16 q9, q9, q15 \n" // +128 -> unsigned
- "vqshrn.u16 d0, q8, #8 \n" // 16 bit to 8 bit U
- "vqshrn.u16 d1, q9, #8 \n" // 16 bit to 8 bit V
- "vst1.8 {d0}, [%2]! \n" // store 8 pixels U.
- "vst1.8 {d1}, [%3]! \n" // store 8 pixels V.
- "bgt 1b \n"
- : "+r"(src_rgb565), // %0
- "+r"(src_stride_rgb565), // %1
- "+r"(dst_u), // %2
- "+r"(dst_v), // %3
- "+r"(pix) // %4
- :
- : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-// 16x2 pixels -> 8x1. pix is number of argb pixels. e.g. 16.
-void ARGB1555ToUVRow_NEON(const uint8* src_argb1555, int src_stride_argb1555,
- uint8* dst_u, uint8* dst_v, int pix) {
- asm volatile (
- "add %1, %0, %1 \n" // src_stride + src_argb
- "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient
- "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient
- "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient
- "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient
- "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient
- "vmov.u16 q15, #0x8080 \n" // 128.5
- ".p2align 2 \n"
- "1: \n"
- "vld1.8 {q0}, [%0]! \n" // load 8 ARGB1555 pixels.
- RGB555TOARGB
- "vpaddl.u8 d8, d0 \n" // B 8 bytes -> 4 shorts.
- "vpaddl.u8 d10, d1 \n" // G 8 bytes -> 4 shorts.
- "vpaddl.u8 d12, d2 \n" // R 8 bytes -> 4 shorts.
- "vld1.8 {q0}, [%0]! \n" // next 8 ARGB1555 pixels.
- RGB555TOARGB
- "vpaddl.u8 d9, d0 \n" // B 8 bytes -> 4 shorts.
- "vpaddl.u8 d11, d1 \n" // G 8 bytes -> 4 shorts.
- "vpaddl.u8 d13, d2 \n" // R 8 bytes -> 4 shorts.
-
- "vld1.8 {q0}, [%1]! \n" // load 8 ARGB1555 pixels.
- RGB555TOARGB
- "vpadal.u8 d8, d0 \n" // B 8 bytes -> 4 shorts.
- "vpadal.u8 d10, d1 \n" // G 8 bytes -> 4 shorts.
- "vpadal.u8 d12, d2 \n" // R 8 bytes -> 4 shorts.
- "vld1.8 {q0}, [%1]! \n" // next 8 ARGB1555 pixels.
- RGB555TOARGB
- "vpadal.u8 d9, d0 \n" // B 8 bytes -> 4 shorts.
- "vpadal.u8 d11, d1 \n" // G 8 bytes -> 4 shorts.
- "vpadal.u8 d13, d2 \n" // R 8 bytes -> 4 shorts.
-
- "vrshr.u16 q4, q4, #1 \n" // 2x average
- "vrshr.u16 q5, q5, #1 \n"
- "vrshr.u16 q6, q6, #1 \n"
-
- "subs %4, %4, #16 \n" // 16 processed per loop.
- "vmul.s16 q8, q4, q10 \n" // B
- "vmls.s16 q8, q5, q11 \n" // G
- "vmls.s16 q8, q6, q12 \n" // R
- "vadd.u16 q8, q8, q15 \n" // +128 -> unsigned
- "vmul.s16 q9, q6, q10 \n" // R
- "vmls.s16 q9, q5, q14 \n" // G
- "vmls.s16 q9, q4, q13 \n" // B
- "vadd.u16 q9, q9, q15 \n" // +128 -> unsigned
- "vqshrn.u16 d0, q8, #8 \n" // 16 bit to 8 bit U
- "vqshrn.u16 d1, q9, #8 \n" // 16 bit to 8 bit V
- "vst1.8 {d0}, [%2]! \n" // store 8 pixels U.
- "vst1.8 {d1}, [%3]! \n" // store 8 pixels V.
- "bgt 1b \n"
- : "+r"(src_argb1555), // %0
- "+r"(src_stride_argb1555), // %1
- "+r"(dst_u), // %2
- "+r"(dst_v), // %3
- "+r"(pix) // %4
- :
- : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-// 16x2 pixels -> 8x1. pix is number of argb pixels. e.g. 16.
-void ARGB4444ToUVRow_NEON(const uint8* src_argb4444, int src_stride_argb4444,
- uint8* dst_u, uint8* dst_v, int pix) {
- asm volatile (
- "add %1, %0, %1 \n" // src_stride + src_argb
- "vmov.s16 q10, #112 / 2 \n" // UB / VR 0.875 coefficient
- "vmov.s16 q11, #74 / 2 \n" // UG -0.5781 coefficient
- "vmov.s16 q12, #38 / 2 \n" // UR -0.2969 coefficient
- "vmov.s16 q13, #18 / 2 \n" // VB -0.1406 coefficient
- "vmov.s16 q14, #94 / 2 \n" // VG -0.7344 coefficient
- "vmov.u16 q15, #0x8080 \n" // 128.5
- ".p2align 2 \n"
- "1: \n"
- "vld1.8 {q0}, [%0]! \n" // load 8 ARGB4444 pixels.
- ARGB4444TOARGB
- "vpaddl.u8 d8, d0 \n" // B 8 bytes -> 4 shorts.
- "vpaddl.u8 d10, d1 \n" // G 8 bytes -> 4 shorts.
- "vpaddl.u8 d12, d2 \n" // R 8 bytes -> 4 shorts.
- "vld1.8 {q0}, [%0]! \n" // next 8 ARGB4444 pixels.
- ARGB4444TOARGB
- "vpaddl.u8 d9, d0 \n" // B 8 bytes -> 4 shorts.
- "vpaddl.u8 d11, d1 \n" // G 8 bytes -> 4 shorts.
- "vpaddl.u8 d13, d2 \n" // R 8 bytes -> 4 shorts.
-
- "vld1.8 {q0}, [%1]! \n" // load 8 ARGB4444 pixels.
- ARGB4444TOARGB
- "vpadal.u8 d8, d0 \n" // B 8 bytes -> 4 shorts.
- "vpadal.u8 d10, d1 \n" // G 8 bytes -> 4 shorts.
- "vpadal.u8 d12, d2 \n" // R 8 bytes -> 4 shorts.
- "vld1.8 {q0}, [%1]! \n" // next 8 ARGB4444 pixels.
- ARGB4444TOARGB
- "vpadal.u8 d9, d0 \n" // B 8 bytes -> 4 shorts.
- "vpadal.u8 d11, d1 \n" // G 8 bytes -> 4 shorts.
- "vpadal.u8 d13, d2 \n" // R 8 bytes -> 4 shorts.
-
- "vrshr.u16 q4, q4, #1 \n" // 2x average
- "vrshr.u16 q5, q5, #1 \n"
- "vrshr.u16 q6, q6, #1 \n"
-
- "subs %4, %4, #16 \n" // 16 processed per loop.
- "vmul.s16 q8, q4, q10 \n" // B
- "vmls.s16 q8, q5, q11 \n" // G
- "vmls.s16 q8, q6, q12 \n" // R
- "vadd.u16 q8, q8, q15 \n" // +128 -> unsigned
- "vmul.s16 q9, q6, q10 \n" // R
- "vmls.s16 q9, q5, q14 \n" // G
- "vmls.s16 q9, q4, q13 \n" // B
- "vadd.u16 q9, q9, q15 \n" // +128 -> unsigned
- "vqshrn.u16 d0, q8, #8 \n" // 16 bit to 8 bit U
- "vqshrn.u16 d1, q9, #8 \n" // 16 bit to 8 bit V
- "vst1.8 {d0}, [%2]! \n" // store 8 pixels U.
- "vst1.8 {d1}, [%3]! \n" // store 8 pixels V.
- "bgt 1b \n"
- : "+r"(src_argb4444), // %0
- "+r"(src_stride_argb4444), // %1
- "+r"(dst_u), // %2
- "+r"(dst_v), // %3
- "+r"(pix) // %4
- :
- : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
- "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-void RGB565ToYRow_NEON(const uint8* src_rgb565, uint8* dst_y, int pix) {
- asm volatile (
- "vmov.u8 d24, #13 \n" // B * 0.1016 coefficient
- "vmov.u8 d25, #65 \n" // G * 0.5078 coefficient
- "vmov.u8 d26, #33 \n" // R * 0.2578 coefficient
- "vmov.u8 d27, #16 \n" // Add 16 constant
- ".p2align 2 \n"
- "1: \n"
- "vld1.8 {q0}, [%0]! \n" // load 8 RGB565 pixels.
- "subs %2, %2, #8 \n" // 8 processed per loop.
- RGB565TOARGB
- "vmull.u8 q2, d0, d24 \n" // B
- "vmlal.u8 q2, d1, d25 \n" // G
- "vmlal.u8 q2, d2, d26 \n" // R
- "vqrshrun.s16 d0, q2, #7 \n" // 16 bit to 8 bit Y
- "vqadd.u8 d0, d27 \n"
- "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y.
- "bgt 1b \n"
- : "+r"(src_rgb565), // %0
- "+r"(dst_y), // %1
- "+r"(pix) // %2
- :
- : "cc", "memory", "q0", "q1", "q2", "q3", "q12", "q13"
- );
-}
-
-void ARGB1555ToYRow_NEON(const uint8* src_argb1555, uint8* dst_y, int pix) {
- asm volatile (
- "vmov.u8 d24, #13 \n" // B * 0.1016 coefficient
- "vmov.u8 d25, #65 \n" // G * 0.5078 coefficient
- "vmov.u8 d26, #33 \n" // R * 0.2578 coefficient
- "vmov.u8 d27, #16 \n" // Add 16 constant
- ".p2align 2 \n"
- "1: \n"
- "vld1.8 {q0}, [%0]! \n" // load 8 ARGB1555 pixels.
- "subs %2, %2, #8 \n" // 8 processed per loop.
- ARGB1555TOARGB
- "vmull.u8 q2, d0, d24 \n" // B
- "vmlal.u8 q2, d1, d25 \n" // G
- "vmlal.u8 q2, d2, d26 \n" // R
- "vqrshrun.s16 d0, q2, #7 \n" // 16 bit to 8 bit Y
- "vqadd.u8 d0, d27 \n"
- "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y.
- "bgt 1b \n"
- : "+r"(src_argb1555), // %0
- "+r"(dst_y), // %1
- "+r"(pix) // %2
- :
- : "cc", "memory", "q0", "q1", "q2", "q3", "q12", "q13"
- );
-}
-
-void ARGB4444ToYRow_NEON(const uint8* src_argb4444, uint8* dst_y, int pix) {
- asm volatile (
- "vmov.u8 d24, #13 \n" // B * 0.1016 coefficient
- "vmov.u8 d25, #65 \n" // G * 0.5078 coefficient
- "vmov.u8 d26, #33 \n" // R * 0.2578 coefficient
- "vmov.u8 d27, #16 \n" // Add 16 constant
- ".p2align 2 \n"
- "1: \n"
- "vld1.8 {q0}, [%0]! \n" // load 8 ARGB4444 pixels.
- "subs %2, %2, #8 \n" // 8 processed per loop.
- ARGB4444TOARGB
- "vmull.u8 q2, d0, d24 \n" // B
- "vmlal.u8 q2, d1, d25 \n" // G
- "vmlal.u8 q2, d2, d26 \n" // R
- "vqrshrun.s16 d0, q2, #7 \n" // 16 bit to 8 bit Y
- "vqadd.u8 d0, d27 \n"
- "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y.
- "bgt 1b \n"
- : "+r"(src_argb4444), // %0
- "+r"(dst_y), // %1
- "+r"(pix) // %2
- :
- : "cc", "memory", "q0", "q1", "q2", "q3", "q12", "q13"
- );
-}
-
-void BGRAToYRow_NEON(const uint8* src_bgra, uint8* dst_y, int pix) {
- asm volatile (
- "vmov.u8 d4, #33 \n" // R * 0.2578 coefficient
- "vmov.u8 d5, #65 \n" // G * 0.5078 coefficient
- "vmov.u8 d6, #13 \n" // B * 0.1016 coefficient
- "vmov.u8 d7, #16 \n" // Add 16 constant
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 pixels of BGRA.
- "subs %2, %2, #8 \n" // 8 processed per loop.
- "vmull.u8 q8, d1, d4 \n" // R
- "vmlal.u8 q8, d2, d5 \n" // G
- "vmlal.u8 q8, d3, d6 \n" // B
- "vqrshrun.s16 d0, q8, #7 \n" // 16 bit to 8 bit Y
- "vqadd.u8 d0, d7 \n"
- "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y.
- "bgt 1b \n"
- : "+r"(src_bgra), // %0
- "+r"(dst_y), // %1
- "+r"(pix) // %2
- :
- : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8"
- );
-}
-
-void ABGRToYRow_NEON(const uint8* src_abgr, uint8* dst_y, int pix) {
- asm volatile (
- "vmov.u8 d4, #33 \n" // R * 0.2578 coefficient
- "vmov.u8 d5, #65 \n" // G * 0.5078 coefficient
- "vmov.u8 d6, #13 \n" // B * 0.1016 coefficient
- "vmov.u8 d7, #16 \n" // Add 16 constant
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 pixels of ABGR.
- "subs %2, %2, #8 \n" // 8 processed per loop.
- "vmull.u8 q8, d0, d4 \n" // R
- "vmlal.u8 q8, d1, d5 \n" // G
- "vmlal.u8 q8, d2, d6 \n" // B
- "vqrshrun.s16 d0, q8, #7 \n" // 16 bit to 8 bit Y
- "vqadd.u8 d0, d7 \n"
- "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y.
- "bgt 1b \n"
- : "+r"(src_abgr), // %0
- "+r"(dst_y), // %1
- "+r"(pix) // %2
- :
- : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8"
- );
-}
-
-void RGBAToYRow_NEON(const uint8* src_rgba, uint8* dst_y, int pix) {
- asm volatile (
- "vmov.u8 d4, #13 \n" // B * 0.1016 coefficient
- "vmov.u8 d5, #65 \n" // G * 0.5078 coefficient
- "vmov.u8 d6, #33 \n" // R * 0.2578 coefficient
- "vmov.u8 d7, #16 \n" // Add 16 constant
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 pixels of RGBA.
- "subs %2, %2, #8 \n" // 8 processed per loop.
- "vmull.u8 q8, d1, d4 \n" // B
- "vmlal.u8 q8, d2, d5 \n" // G
- "vmlal.u8 q8, d3, d6 \n" // R
- "vqrshrun.s16 d0, q8, #7 \n" // 16 bit to 8 bit Y
- "vqadd.u8 d0, d7 \n"
- "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y.
- "bgt 1b \n"
- : "+r"(src_rgba), // %0
- "+r"(dst_y), // %1
- "+r"(pix) // %2
- :
- : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8"
- );
-}
-
-void RGB24ToYRow_NEON(const uint8* src_rgb24, uint8* dst_y, int pix) {
- asm volatile (
- "vmov.u8 d4, #13 \n" // B * 0.1016 coefficient
- "vmov.u8 d5, #65 \n" // G * 0.5078 coefficient
- "vmov.u8 d6, #33 \n" // R * 0.2578 coefficient
- "vmov.u8 d7, #16 \n" // Add 16 constant
- ".p2align 2 \n"
- "1: \n"
- "vld3.8 {d0, d1, d2}, [%0]! \n" // load 8 pixels of RGB24.
- "subs %2, %2, #8 \n" // 8 processed per loop.
- "vmull.u8 q8, d0, d4 \n" // B
- "vmlal.u8 q8, d1, d5 \n" // G
- "vmlal.u8 q8, d2, d6 \n" // R
- "vqrshrun.s16 d0, q8, #7 \n" // 16 bit to 8 bit Y
- "vqadd.u8 d0, d7 \n"
- "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y.
- "bgt 1b \n"
- : "+r"(src_rgb24), // %0
- "+r"(dst_y), // %1
- "+r"(pix) // %2
- :
- : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8"
- );
-}
-
-void RAWToYRow_NEON(const uint8* src_raw, uint8* dst_y, int pix) {
- asm volatile (
- "vmov.u8 d4, #33 \n" // R * 0.2578 coefficient
- "vmov.u8 d5, #65 \n" // G * 0.5078 coefficient
- "vmov.u8 d6, #13 \n" // B * 0.1016 coefficient
- "vmov.u8 d7, #16 \n" // Add 16 constant
- ".p2align 2 \n"
- "1: \n"
- "vld3.8 {d0, d1, d2}, [%0]! \n" // load 8 pixels of RAW.
- "subs %2, %2, #8 \n" // 8 processed per loop.
- "vmull.u8 q8, d0, d4 \n" // B
- "vmlal.u8 q8, d1, d5 \n" // G
- "vmlal.u8 q8, d2, d6 \n" // R
- "vqrshrun.s16 d0, q8, #7 \n" // 16 bit to 8 bit Y
- "vqadd.u8 d0, d7 \n"
- "vst1.8 {d0}, [%1]! \n" // store 8 pixels Y.
- "bgt 1b \n"
- : "+r"(src_raw), // %0
- "+r"(dst_y), // %1
- "+r"(pix) // %2
- :
- : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "q8"
- );
-}
-
-// Bilinear filter 16x2 -> 16x1
-void InterpolateRow_NEON(uint8* dst_ptr,
- const uint8* src_ptr, ptrdiff_t src_stride,
- int dst_width, int source_y_fraction) {
- asm volatile (
- "cmp %4, #0 \n"
- "beq 100f \n"
- "add %2, %1 \n"
- "cmp %4, #64 \n"
- "beq 75f \n"
- "cmp %4, #128 \n"
- "beq 50f \n"
- "cmp %4, #192 \n"
- "beq 25f \n"
-
- "vdup.8 d5, %4 \n"
- "rsb %4, #256 \n"
- "vdup.8 d4, %4 \n"
- // General purpose row blend.
- "1: \n"
- "vld1.8 {q0}, [%1]! \n"
- "vld1.8 {q1}, [%2]! \n"
- "subs %3, %3, #16 \n"
- "vmull.u8 q13, d0, d4 \n"
- "vmull.u8 q14, d1, d4 \n"
- "vmlal.u8 q13, d2, d5 \n"
- "vmlal.u8 q14, d3, d5 \n"
- "vrshrn.u16 d0, q13, #8 \n"
- "vrshrn.u16 d1, q14, #8 \n"
- "vst1.8 {q0}, [%0]! \n"
- "bgt 1b \n"
- "b 99f \n"
-
- // Blend 25 / 75.
- "25: \n"
- "vld1.8 {q0}, [%1]! \n"
- "vld1.8 {q1}, [%2]! \n"
- "subs %3, %3, #16 \n"
- "vrhadd.u8 q0, q1 \n"
- "vrhadd.u8 q0, q1 \n"
- "vst1.8 {q0}, [%0]! \n"
- "bgt 25b \n"
- "b 99f \n"
-
- // Blend 50 / 50.
- "50: \n"
- "vld1.8 {q0}, [%1]! \n"
- "vld1.8 {q1}, [%2]! \n"
- "subs %3, %3, #16 \n"
- "vrhadd.u8 q0, q1 \n"
- "vst1.8 {q0}, [%0]! \n"
- "bgt 50b \n"
- "b 99f \n"
-
- // Blend 75 / 25.
- "75: \n"
- "vld1.8 {q1}, [%1]! \n"
- "vld1.8 {q0}, [%2]! \n"
- "subs %3, %3, #16 \n"
- "vrhadd.u8 q0, q1 \n"
- "vrhadd.u8 q0, q1 \n"
- "vst1.8 {q0}, [%0]! \n"
- "bgt 75b \n"
- "b 99f \n"
-
- // Blend 100 / 0 - Copy row unchanged.
- "100: \n"
- "vld1.8 {q0}, [%1]! \n"
- "subs %3, %3, #16 \n"
- "vst1.8 {q0}, [%0]! \n"
- "bgt 100b \n"
-
- "99: \n"
- : "+r"(dst_ptr), // %0
- "+r"(src_ptr), // %1
- "+r"(src_stride), // %2
- "+r"(dst_width), // %3
- "+r"(source_y_fraction) // %4
- :
- : "cc", "memory", "q0", "q1", "d4", "d5", "q13", "q14"
- );
-}
-
-// dr * (256 - sa) / 256 + sr = dr - dr * sa / 256 + sr
-void ARGBBlendRow_NEON(const uint8* src_argb0, const uint8* src_argb1,
- uint8* dst_argb, int width) {
- asm volatile (
- "subs %3, #8 \n"
- "blt 89f \n"
- // Blend 8 pixels.
- "8: \n"
- "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 pixels of ARGB0.
- "vld4.8 {d4, d5, d6, d7}, [%1]! \n" // load 8 pixels of ARGB1.
- "subs %3, %3, #8 \n" // 8 processed per loop.
- "vmull.u8 q10, d4, d3 \n" // db * a
- "vmull.u8 q11, d5, d3 \n" // dg * a
- "vmull.u8 q12, d6, d3 \n" // dr * a
- "vqrshrn.u16 d20, q10, #8 \n" // db >>= 8
- "vqrshrn.u16 d21, q11, #8 \n" // dg >>= 8
- "vqrshrn.u16 d22, q12, #8 \n" // dr >>= 8
- "vqsub.u8 q2, q2, q10 \n" // dbg - dbg * a / 256
- "vqsub.u8 d6, d6, d22 \n" // dr - dr * a / 256
- "vqadd.u8 q0, q0, q2 \n" // + sbg
- "vqadd.u8 d2, d2, d6 \n" // + sr
- "vmov.u8 d3, #255 \n" // a = 255
- "vst4.8 {d0, d1, d2, d3}, [%2]! \n" // store 8 pixels of ARGB.
- "bge 8b \n"
-
- "89: \n"
- "adds %3, #8-1 \n"
- "blt 99f \n"
-
- // Blend 1 pixels.
- "1: \n"
- "vld4.8 {d0[0],d1[0],d2[0],d3[0]}, [%0]! \n" // load 1 pixel ARGB0.
- "vld4.8 {d4[0],d5[0],d6[0],d7[0]}, [%1]! \n" // load 1 pixel ARGB1.
- "subs %3, %3, #1 \n" // 1 processed per loop.
- "vmull.u8 q10, d4, d3 \n" // db * a
- "vmull.u8 q11, d5, d3 \n" // dg * a
- "vmull.u8 q12, d6, d3 \n" // dr * a
- "vqrshrn.u16 d20, q10, #8 \n" // db >>= 8
- "vqrshrn.u16 d21, q11, #8 \n" // dg >>= 8
- "vqrshrn.u16 d22, q12, #8 \n" // dr >>= 8
- "vqsub.u8 q2, q2, q10 \n" // dbg - dbg * a / 256
- "vqsub.u8 d6, d6, d22 \n" // dr - dr * a / 256
- "vqadd.u8 q0, q0, q2 \n" // + sbg
- "vqadd.u8 d2, d2, d6 \n" // + sr
- "vmov.u8 d3, #255 \n" // a = 255
- "vst4.8 {d0[0],d1[0],d2[0],d3[0]}, [%2]! \n" // store 1 pixel.
- "bge 1b \n"
-
- "99: \n"
-
- : "+r"(src_argb0), // %0
- "+r"(src_argb1), // %1
- "+r"(dst_argb), // %2
- "+r"(width) // %3
- :
- : "cc", "memory", "q0", "q1", "q2", "q3", "q10", "q11", "q12"
- );
-}
-
-// Attenuate 8 pixels at a time.
-void ARGBAttenuateRow_NEON(const uint8* src_argb, uint8* dst_argb, int width) {
- asm volatile (
- // Attenuate 8 pixels.
- "1: \n"
- "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 pixels of ARGB.
- "subs %2, %2, #8 \n" // 8 processed per loop.
- "vmull.u8 q10, d0, d3 \n" // b * a
- "vmull.u8 q11, d1, d3 \n" // g * a
- "vmull.u8 q12, d2, d3 \n" // r * a
- "vqrshrn.u16 d0, q10, #8 \n" // b >>= 8
- "vqrshrn.u16 d1, q11, #8 \n" // g >>= 8
- "vqrshrn.u16 d2, q12, #8 \n" // r >>= 8
- "vst4.8 {d0, d1, d2, d3}, [%1]! \n" // store 8 pixels of ARGB.
- "bgt 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_argb), // %1
- "+r"(width) // %2
- :
- : "cc", "memory", "q0", "q1", "q10", "q11", "q12"
- );
-}
-
-// Quantize 8 ARGB pixels (32 bytes).
-// dst = (dst * scale >> 16) * interval_size + interval_offset;
-void ARGBQuantizeRow_NEON(uint8* dst_argb, int scale, int interval_size,
- int interval_offset, int width) {
- asm volatile (
- "vdup.u16 q8, %2 \n"
- "vshr.u16 q8, q8, #1 \n" // scale >>= 1
- "vdup.u16 q9, %3 \n" // interval multiply.
- "vdup.u16 q10, %4 \n" // interval add
-
- // 8 pixel loop.
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d2, d4, d6}, [%0] \n" // load 8 pixels of ARGB.
- "subs %1, %1, #8 \n" // 8 processed per loop.
- "vmovl.u8 q0, d0 \n" // b (0 .. 255)
- "vmovl.u8 q1, d2 \n"
- "vmovl.u8 q2, d4 \n"
- "vqdmulh.s16 q0, q0, q8 \n" // b * scale
- "vqdmulh.s16 q1, q1, q8 \n" // g
- "vqdmulh.s16 q2, q2, q8 \n" // r
- "vmul.u16 q0, q0, q9 \n" // b * interval_size
- "vmul.u16 q1, q1, q9 \n" // g
- "vmul.u16 q2, q2, q9 \n" // r
- "vadd.u16 q0, q0, q10 \n" // b + interval_offset
- "vadd.u16 q1, q1, q10 \n" // g
- "vadd.u16 q2, q2, q10 \n" // r
- "vqmovn.u16 d0, q0 \n"
- "vqmovn.u16 d2, q1 \n"
- "vqmovn.u16 d4, q2 \n"
- "vst4.8 {d0, d2, d4, d6}, [%0]! \n" // store 8 pixels of ARGB.
- "bgt 1b \n"
- : "+r"(dst_argb), // %0
- "+r"(width) // %1
- : "r"(scale), // %2
- "r"(interval_size), // %3
- "r"(interval_offset) // %4
- : "cc", "memory", "q0", "q1", "q2", "q3", "q8", "q9", "q10"
- );
-}
-
-// Shade 8 pixels at a time by specified value.
-// NOTE vqrdmulh.s16 q10, q10, d0[0] must use a scaler register from 0 to 8.
-// Rounding in vqrdmulh does +1 to high if high bit of low s16 is set.
-void ARGBShadeRow_NEON(const uint8* src_argb, uint8* dst_argb, int width,
- uint32 value) {
- asm volatile (
- "vdup.u32 q0, %3 \n" // duplicate scale value.
- "vzip.u8 d0, d1 \n" // d0 aarrggbb.
- "vshr.u16 q0, q0, #1 \n" // scale / 2.
-
- // 8 pixel loop.
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d20, d22, d24, d26}, [%0]! \n" // load 8 pixels of ARGB.
- "subs %2, %2, #8 \n" // 8 processed per loop.
- "vmovl.u8 q10, d20 \n" // b (0 .. 255)
- "vmovl.u8 q11, d22 \n"
- "vmovl.u8 q12, d24 \n"
- "vmovl.u8 q13, d26 \n"
- "vqrdmulh.s16 q10, q10, d0[0] \n" // b * scale * 2
- "vqrdmulh.s16 q11, q11, d0[1] \n" // g
- "vqrdmulh.s16 q12, q12, d0[2] \n" // r
- "vqrdmulh.s16 q13, q13, d0[3] \n" // a
- "vqmovn.u16 d20, q10 \n"
- "vqmovn.u16 d22, q11 \n"
- "vqmovn.u16 d24, q12 \n"
- "vqmovn.u16 d26, q13 \n"
- "vst4.8 {d20, d22, d24, d26}, [%1]! \n" // store 8 pixels of ARGB.
- "bgt 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_argb), // %1
- "+r"(width) // %2
- : "r"(value) // %3
- : "cc", "memory", "q0", "q10", "q11", "q12", "q13"
- );
-}
-
-// Convert 8 ARGB pixels (64 bytes) to 8 Gray ARGB pixels
-// Similar to ARGBToYJ but stores ARGB.
-// C code is (15 * b + 75 * g + 38 * r + 64) >> 7;
-void ARGBGrayRow_NEON(const uint8* src_argb, uint8* dst_argb, int width) {
- asm volatile (
- "vmov.u8 d24, #15 \n" // B * 0.11400 coefficient
- "vmov.u8 d25, #75 \n" // G * 0.58700 coefficient
- "vmov.u8 d26, #38 \n" // R * 0.29900 coefficient
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 ARGB pixels.
- "subs %2, %2, #8 \n" // 8 processed per loop.
- "vmull.u8 q2, d0, d24 \n" // B
- "vmlal.u8 q2, d1, d25 \n" // G
- "vmlal.u8 q2, d2, d26 \n" // R
- "vqrshrun.s16 d0, q2, #7 \n" // 15 bit to 8 bit B
- "vmov d1, d0 \n" // G
- "vmov d2, d0 \n" // R
- "vst4.8 {d0, d1, d2, d3}, [%1]! \n" // store 8 ARGB pixels.
- "bgt 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_argb), // %1
- "+r"(width) // %2
- :
- : "cc", "memory", "q0", "q1", "q2", "q12", "q13"
- );
-}
-
-// Convert 8 ARGB pixels (32 bytes) to 8 Sepia ARGB pixels.
-// b = (r * 35 + g * 68 + b * 17) >> 7
-// g = (r * 45 + g * 88 + b * 22) >> 7
-// r = (r * 50 + g * 98 + b * 24) >> 7
-void ARGBSepiaRow_NEON(uint8* dst_argb, int width) {
- asm volatile (
- "vmov.u8 d20, #17 \n" // BB coefficient
- "vmov.u8 d21, #68 \n" // BG coefficient
- "vmov.u8 d22, #35 \n" // BR coefficient
- "vmov.u8 d24, #22 \n" // GB coefficient
- "vmov.u8 d25, #88 \n" // GG coefficient
- "vmov.u8 d26, #45 \n" // GR coefficient
- "vmov.u8 d28, #24 \n" // BB coefficient
- "vmov.u8 d29, #98 \n" // BG coefficient
- "vmov.u8 d30, #50 \n" // BR coefficient
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d1, d2, d3}, [%0] \n" // load 8 ARGB pixels.
- "subs %1, %1, #8 \n" // 8 processed per loop.
- "vmull.u8 q2, d0, d20 \n" // B to Sepia B
- "vmlal.u8 q2, d1, d21 \n" // G
- "vmlal.u8 q2, d2, d22 \n" // R
- "vmull.u8 q3, d0, d24 \n" // B to Sepia G
- "vmlal.u8 q3, d1, d25 \n" // G
- "vmlal.u8 q3, d2, d26 \n" // R
- "vmull.u8 q8, d0, d28 \n" // B to Sepia R
- "vmlal.u8 q8, d1, d29 \n" // G
- "vmlal.u8 q8, d2, d30 \n" // R
- "vqshrn.u16 d0, q2, #7 \n" // 16 bit to 8 bit B
- "vqshrn.u16 d1, q3, #7 \n" // 16 bit to 8 bit G
- "vqshrn.u16 d2, q8, #7 \n" // 16 bit to 8 bit R
- "vst4.8 {d0, d1, d2, d3}, [%0]! \n" // store 8 ARGB pixels.
- "bgt 1b \n"
- : "+r"(dst_argb), // %0
- "+r"(width) // %1
- :
- : "cc", "memory", "q0", "q1", "q2", "q3",
- "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-// Tranform 8 ARGB pixels (32 bytes) with color matrix.
-// TODO(fbarchard): Was same as Sepia except matrix is provided. This function
-// needs to saturate. Consider doing a non-saturating version.
-void ARGBColorMatrixRow_NEON(const uint8* src_argb, uint8* dst_argb,
- const int8* matrix_argb, int width) {
- asm volatile (
- "vld1.8 {q2}, [%3] \n" // load 3 ARGB vectors.
- "vmovl.s8 q0, d4 \n" // B,G coefficients s16.
- "vmovl.s8 q1, d5 \n" // R,A coefficients s16.
-
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d16, d18, d20, d22}, [%0]! \n" // load 8 ARGB pixels.
- "subs %2, %2, #8 \n" // 8 processed per loop.
- "vmovl.u8 q8, d16 \n" // b (0 .. 255) 16 bit
- "vmovl.u8 q9, d18 \n" // g
- "vmovl.u8 q10, d20 \n" // r
- "vmovl.u8 q15, d22 \n" // a
- "vmul.s16 q12, q8, d0[0] \n" // B = B * Matrix B
- "vmul.s16 q13, q8, d1[0] \n" // G = B * Matrix G
- "vmul.s16 q14, q8, d2[0] \n" // R = B * Matrix R
- "vmul.s16 q15, q8, d3[0] \n" // A = B * Matrix A
- "vmul.s16 q4, q9, d0[1] \n" // B += G * Matrix B
- "vmul.s16 q5, q9, d1[1] \n" // G += G * Matrix G
- "vmul.s16 q6, q9, d2[1] \n" // R += G * Matrix R
- "vmul.s16 q7, q9, d3[1] \n" // A += G * Matrix A
- "vqadd.s16 q12, q12, q4 \n" // Accumulate B
- "vqadd.s16 q13, q13, q5 \n" // Accumulate G
- "vqadd.s16 q14, q14, q6 \n" // Accumulate R
- "vqadd.s16 q15, q15, q7 \n" // Accumulate A
- "vmul.s16 q4, q10, d0[2] \n" // B += R * Matrix B
- "vmul.s16 q5, q10, d1[2] \n" // G += R * Matrix G
- "vmul.s16 q6, q10, d2[2] \n" // R += R * Matrix R
- "vmul.s16 q7, q10, d3[2] \n" // A += R * Matrix A
- "vqadd.s16 q12, q12, q4 \n" // Accumulate B
- "vqadd.s16 q13, q13, q5 \n" // Accumulate G
- "vqadd.s16 q14, q14, q6 \n" // Accumulate R
- "vqadd.s16 q15, q15, q7 \n" // Accumulate A
- "vmul.s16 q4, q15, d0[3] \n" // B += A * Matrix B
- "vmul.s16 q5, q15, d1[3] \n" // G += A * Matrix G
- "vmul.s16 q6, q15, d2[3] \n" // R += A * Matrix R
- "vmul.s16 q7, q15, d3[3] \n" // A += A * Matrix A
- "vqadd.s16 q12, q12, q4 \n" // Accumulate B
- "vqadd.s16 q13, q13, q5 \n" // Accumulate G
- "vqadd.s16 q14, q14, q6 \n" // Accumulate R
- "vqadd.s16 q15, q15, q7 \n" // Accumulate A
- "vqshrun.s16 d16, q12, #6 \n" // 16 bit to 8 bit B
- "vqshrun.s16 d18, q13, #6 \n" // 16 bit to 8 bit G
- "vqshrun.s16 d20, q14, #6 \n" // 16 bit to 8 bit R
- "vqshrun.s16 d22, q15, #6 \n" // 16 bit to 8 bit A
- "vst4.8 {d16, d18, d20, d22}, [%1]! \n" // store 8 ARGB pixels.
- "bgt 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_argb), // %1
- "+r"(width) // %2
- : "r"(matrix_argb) // %3
- : "cc", "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9",
- "q10", "q11", "q12", "q13", "q14", "q15"
- );
-}
-
-// TODO(fbarchard): fix vqshrun in ARGBMultiplyRow_NEON and reenable.
-#ifdef HAS_ARGBMULTIPLYROW_NEON
-// Multiply 2 rows of ARGB pixels together, 8 pixels at a time.
-void ARGBMultiplyRow_NEON(const uint8* src_argb0, const uint8* src_argb1,
- uint8* dst_argb, int width) {
- asm volatile (
- // 8 pixel loop.
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 ARGB pixels.
- "vld4.8 {d1, d3, d5, d7}, [%1]! \n" // load 8 more ARGB pixels.
- "subs %3, %3, #8 \n" // 8 processed per loop.
- "vmull.u8 q0, d0, d1 \n" // multiply B
- "vmull.u8 q1, d2, d3 \n" // multiply G
- "vmull.u8 q2, d4, d5 \n" // multiply R
- "vmull.u8 q3, d6, d7 \n" // multiply A
- "vrshrn.u16 d0, q0, #8 \n" // 16 bit to 8 bit B
- "vrshrn.u16 d1, q1, #8 \n" // 16 bit to 8 bit G
- "vrshrn.u16 d2, q2, #8 \n" // 16 bit to 8 bit R
- "vrshrn.u16 d3, q3, #8 \n" // 16 bit to 8 bit A
- "vst4.8 {d0, d1, d2, d3}, [%2]! \n" // store 8 ARGB pixels.
- "bgt 1b \n"
-
- : "+r"(src_argb0), // %0
- "+r"(src_argb1), // %1
- "+r"(dst_argb), // %2
- "+r"(width) // %3
- :
- : "cc", "memory", "q0", "q1", "q2", "q3"
- );
-}
-#endif // HAS_ARGBMULTIPLYROW_NEON
-
-// Add 2 rows of ARGB pixels together, 8 pixels at a time.
-void ARGBAddRow_NEON(const uint8* src_argb0, const uint8* src_argb1,
- uint8* dst_argb, int width) {
- asm volatile (
- // 8 pixel loop.
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 ARGB pixels.
- "vld4.8 {d4, d5, d6, d7}, [%1]! \n" // load 8 more ARGB pixels.
- "subs %3, %3, #8 \n" // 8 processed per loop.
- "vqadd.u8 q0, q0, q2 \n" // add B, G
- "vqadd.u8 q1, q1, q3 \n" // add R, A
- "vst4.8 {d0, d1, d2, d3}, [%2]! \n" // store 8 ARGB pixels.
- "bgt 1b \n"
-
- : "+r"(src_argb0), // %0
- "+r"(src_argb1), // %1
- "+r"(dst_argb), // %2
- "+r"(width) // %3
- :
- : "cc", "memory", "q0", "q1", "q2", "q3"
- );
-}
-
-// Subtract 2 rows of ARGB pixels, 8 pixels at a time.
-void ARGBSubtractRow_NEON(const uint8* src_argb0, const uint8* src_argb1,
- uint8* dst_argb, int width) {
- asm volatile (
- // 8 pixel loop.
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // load 8 ARGB pixels.
- "vld4.8 {d4, d5, d6, d7}, [%1]! \n" // load 8 more ARGB pixels.
- "subs %3, %3, #8 \n" // 8 processed per loop.
- "vqsub.u8 q0, q0, q2 \n" // subtract B, G
- "vqsub.u8 q1, q1, q3 \n" // subtract R, A
- "vst4.8 {d0, d1, d2, d3}, [%2]! \n" // store 8 ARGB pixels.
- "bgt 1b \n"
-
- : "+r"(src_argb0), // %0
- "+r"(src_argb1), // %1
- "+r"(dst_argb), // %2
- "+r"(width) // %3
- :
- : "cc", "memory", "q0", "q1", "q2", "q3"
- );
-}
-
-// Adds Sobel X and Sobel Y and stores Sobel into ARGB.
-// A = 255
-// R = Sobel
-// G = Sobel
-// B = Sobel
-void SobelRow_NEON(const uint8* src_sobelx, const uint8* src_sobely,
- uint8* dst_argb, int width) {
- asm volatile (
- "vmov.u8 d3, #255 \n" // alpha
- // 8 pixel loop.
- ".p2align 2 \n"
- "1: \n"
- "vld1.8 {d0}, [%0]! \n" // load 8 sobelx.
- "vld1.8 {d1}, [%1]! \n" // load 8 sobely.
- "subs %3, %3, #8 \n" // 8 processed per loop.
- "vqadd.u8 d0, d0, d1 \n" // add
- "vmov.u8 d1, d0 \n"
- "vmov.u8 d2, d0 \n"
- "vst4.8 {d0, d1, d2, d3}, [%2]! \n" // store 8 ARGB pixels.
- "bgt 1b \n"
- : "+r"(src_sobelx), // %0
- "+r"(src_sobely), // %1
- "+r"(dst_argb), // %2
- "+r"(width) // %3
- :
- : "cc", "memory", "q0", "q1"
- );
-}
-
-// Adds Sobel X and Sobel Y and stores Sobel into plane.
-void SobelToPlaneRow_NEON(const uint8* src_sobelx, const uint8* src_sobely,
- uint8* dst_y, int width) {
- asm volatile (
- // 16 pixel loop.
- ".p2align 2 \n"
- "1: \n"
- "vld1.8 {q0}, [%0]! \n" // load 16 sobelx.
- "vld1.8 {q1}, [%1]! \n" // load 16 sobely.
- "subs %3, %3, #16 \n" // 16 processed per loop.
- "vqadd.u8 q0, q0, q1 \n" // add
- "vst1.8 {q0}, [%2]! \n" // store 16 pixels.
- "bgt 1b \n"
- : "+r"(src_sobelx), // %0
- "+r"(src_sobely), // %1
- "+r"(dst_y), // %2
- "+r"(width) // %3
- :
- : "cc", "memory", "q0", "q1"
- );
-}
-
-// Mixes Sobel X, Sobel Y and Sobel into ARGB.
-// A = 255
-// R = Sobel X
-// G = Sobel
-// B = Sobel Y
-void SobelXYRow_NEON(const uint8* src_sobelx, const uint8* src_sobely,
- uint8* dst_argb, int width) {
- asm volatile (
- "vmov.u8 d3, #255 \n" // alpha
- // 8 pixel loop.
- ".p2align 2 \n"
- "1: \n"
- "vld1.8 {d2}, [%0]! \n" // load 8 sobelx.
- "vld1.8 {d0}, [%1]! \n" // load 8 sobely.
- "subs %3, %3, #8 \n" // 8 processed per loop.
- "vqadd.u8 d1, d0, d2 \n" // add
- "vst4.8 {d0, d1, d2, d3}, [%2]! \n" // store 8 ARGB pixels.
- "bgt 1b \n"
- : "+r"(src_sobelx), // %0
- "+r"(src_sobely), // %1
- "+r"(dst_argb), // %2
- "+r"(width) // %3
- :
- : "cc", "memory", "q0", "q1"
- );
-}
-
-// SobelX as a matrix is
-// -1 0 1
-// -2 0 2
-// -1 0 1
-void SobelXRow_NEON(const uint8* src_y0, const uint8* src_y1,
- const uint8* src_y2, uint8* dst_sobelx, int width) {
- asm volatile (
- ".p2align 2 \n"
- "1: \n"
- "vld1.8 {d0}, [%0],%5 \n" // top
- "vld1.8 {d1}, [%0],%6 \n"
- "vsubl.u8 q0, d0, d1 \n"
- "vld1.8 {d2}, [%1],%5 \n" // center * 2
- "vld1.8 {d3}, [%1],%6 \n"
- "vsubl.u8 q1, d2, d3 \n"
- "vadd.s16 q0, q0, q1 \n"
- "vadd.s16 q0, q0, q1 \n"
- "vld1.8 {d2}, [%2],%5 \n" // bottom
- "vld1.8 {d3}, [%2],%6 \n"
- "subs %4, %4, #8 \n" // 8 pixels
- "vsubl.u8 q1, d2, d3 \n"
- "vadd.s16 q0, q0, q1 \n"
- "vabs.s16 q0, q0 \n"
- "vqmovn.u16 d0, q0 \n"
- "vst1.8 {d0}, [%3]! \n" // store 8 sobelx
- "bgt 1b \n"
- : "+r"(src_y0), // %0
- "+r"(src_y1), // %1
- "+r"(src_y2), // %2
- "+r"(dst_sobelx), // %3
- "+r"(width) // %4
- : "r"(2), // %5
- "r"(6) // %6
- : "cc", "memory", "q0", "q1" // Clobber List
- );
-}
-
-// SobelY as a matrix is
-// -1 -2 -1
-// 0 0 0
-// 1 2 1
-void SobelYRow_NEON(const uint8* src_y0, const uint8* src_y1,
- uint8* dst_sobely, int width) {
- asm volatile (
- ".p2align 2 \n"
- "1: \n"
- "vld1.8 {d0}, [%0],%4 \n" // left
- "vld1.8 {d1}, [%1],%4 \n"
- "vsubl.u8 q0, d0, d1 \n"
- "vld1.8 {d2}, [%0],%4 \n" // center * 2
- "vld1.8 {d3}, [%1],%4 \n"
- "vsubl.u8 q1, d2, d3 \n"
- "vadd.s16 q0, q0, q1 \n"
- "vadd.s16 q0, q0, q1 \n"
- "vld1.8 {d2}, [%0],%5 \n" // right
- "vld1.8 {d3}, [%1],%5 \n"
- "subs %3, %3, #8 \n" // 8 pixels
- "vsubl.u8 q1, d2, d3 \n"
- "vadd.s16 q0, q0, q1 \n"
- "vabs.s16 q0, q0 \n"
- "vqmovn.u16 d0, q0 \n"
- "vst1.8 {d0}, [%2]! \n" // store 8 sobely
- "bgt 1b \n"
- : "+r"(src_y0), // %0
- "+r"(src_y1), // %1
- "+r"(dst_sobely), // %2
- "+r"(width) // %3
- : "r"(1), // %4
- "r"(6) // %5
- : "cc", "memory", "q0", "q1" // Clobber List
- );
-}
-#endif // __ARM_NEON__
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/row_posix.cc b/drivers/theoraplayer/src/YUV/libyuv/src/row_posix.cc
deleted file mode 100755
index 106fda5689..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/row_posix.cc
+++ /dev/null
@@ -1,6443 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/row.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// This module is for GCC x86 and x64.
-#if !defined(LIBYUV_DISABLE_X86) && (defined(__x86_64__) || defined(__i386__))
-
-#if defined(HAS_ARGBTOYROW_SSSE3) || defined(HAS_ARGBGRAYROW_SSSE3)
-
-// Constants for ARGB
-static vec8 kARGBToY = {
- 13, 65, 33, 0, 13, 65, 33, 0, 13, 65, 33, 0, 13, 65, 33, 0
-};
-
-// JPeg full range.
-static vec8 kARGBToYJ = {
- 15, 75, 38, 0, 15, 75, 38, 0, 15, 75, 38, 0, 15, 75, 38, 0
-};
-#endif // defined(HAS_ARGBTOYROW_SSSE3) || defined(HAS_ARGBGRAYROW_SSSE3)
-
-#if defined(HAS_ARGBTOYROW_SSSE3) || defined(HAS_I422TOARGBROW_SSSE3)
-
-static vec8 kARGBToU = {
- 112, -74, -38, 0, 112, -74, -38, 0, 112, -74, -38, 0, 112, -74, -38, 0
-};
-
-static vec8 kARGBToUJ = {
- 127, -84, -43, 0, 127, -84, -43, 0, 127, -84, -43, 0, 127, -84, -43, 0
-};
-
-static vec8 kARGBToV = {
- -18, -94, 112, 0, -18, -94, 112, 0, -18, -94, 112, 0, -18, -94, 112, 0,
-};
-
-static vec8 kARGBToVJ = {
- -20, -107, 127, 0, -20, -107, 127, 0, -20, -107, 127, 0, -20, -107, 127, 0
-};
-
-// Constants for BGRA
-static vec8 kBGRAToY = {
- 0, 33, 65, 13, 0, 33, 65, 13, 0, 33, 65, 13, 0, 33, 65, 13
-};
-
-static vec8 kBGRAToU = {
- 0, -38, -74, 112, 0, -38, -74, 112, 0, -38, -74, 112, 0, -38, -74, 112
-};
-
-static vec8 kBGRAToV = {
- 0, 112, -94, -18, 0, 112, -94, -18, 0, 112, -94, -18, 0, 112, -94, -18
-};
-
-// Constants for ABGR
-static vec8 kABGRToY = {
- 33, 65, 13, 0, 33, 65, 13, 0, 33, 65, 13, 0, 33, 65, 13, 0
-};
-
-static vec8 kABGRToU = {
- -38, -74, 112, 0, -38, -74, 112, 0, -38, -74, 112, 0, -38, -74, 112, 0
-};
-
-static vec8 kABGRToV = {
- 112, -94, -18, 0, 112, -94, -18, 0, 112, -94, -18, 0, 112, -94, -18, 0
-};
-
-// Constants for RGBA.
-static vec8 kRGBAToY = {
- 0, 13, 65, 33, 0, 13, 65, 33, 0, 13, 65, 33, 0, 13, 65, 33
-};
-
-static vec8 kRGBAToU = {
- 0, 112, -74, -38, 0, 112, -74, -38, 0, 112, -74, -38, 0, 112, -74, -38
-};
-
-static vec8 kRGBAToV = {
- 0, -18, -94, 112, 0, -18, -94, 112, 0, -18, -94, 112, 0, -18, -94, 112
-};
-
-static uvec8 kAddY16 = {
- 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u
-};
-
-static vec16 kAddYJ64 = {
- 64, 64, 64, 64, 64, 64, 64, 64
-};
-
-static uvec8 kAddUV128 = {
- 128u, 128u, 128u, 128u, 128u, 128u, 128u, 128u,
- 128u, 128u, 128u, 128u, 128u, 128u, 128u, 128u
-};
-
-static uvec16 kAddUVJ128 = {
- 0x8080u, 0x8080u, 0x8080u, 0x8080u, 0x8080u, 0x8080u, 0x8080u, 0x8080u
-};
-#endif // defined(HAS_ARGBTOYROW_SSSE3) || defined(HAS_I422TOARGBROW_SSSE3)
-
-#ifdef HAS_RGB24TOARGBROW_SSSE3
-
-// Shuffle table for converting RGB24 to ARGB.
-static uvec8 kShuffleMaskRGB24ToARGB = {
- 0u, 1u, 2u, 12u, 3u, 4u, 5u, 13u, 6u, 7u, 8u, 14u, 9u, 10u, 11u, 15u
-};
-
-// Shuffle table for converting RAW to ARGB.
-static uvec8 kShuffleMaskRAWToARGB = {
- 2u, 1u, 0u, 12u, 5u, 4u, 3u, 13u, 8u, 7u, 6u, 14u, 11u, 10u, 9u, 15u
-};
-
-// Shuffle table for converting ARGB to RGB24.
-static uvec8 kShuffleMaskARGBToRGB24 = {
- 0u, 1u, 2u, 4u, 5u, 6u, 8u, 9u, 10u, 12u, 13u, 14u, 128u, 128u, 128u, 128u
-};
-
-// Shuffle table for converting ARGB to RAW.
-static uvec8 kShuffleMaskARGBToRAW = {
- 2u, 1u, 0u, 6u, 5u, 4u, 10u, 9u, 8u, 14u, 13u, 12u, 128u, 128u, 128u, 128u
-};
-
-// Shuffle table for converting ARGBToRGB24 for I422ToRGB24. First 8 + next 4
-static uvec8 kShuffleMaskARGBToRGB24_0 = {
- 0u, 1u, 2u, 4u, 5u, 6u, 8u, 9u, 128u, 128u, 128u, 128u, 10u, 12u, 13u, 14u
-};
-
-// Shuffle table for converting ARGB to RAW.
-static uvec8 kShuffleMaskARGBToRAW_0 = {
- 2u, 1u, 0u, 6u, 5u, 4u, 10u, 9u, 128u, 128u, 128u, 128u, 8u, 14u, 13u, 12u
-};
-#endif // HAS_RGB24TOARGBROW_SSSE3
-
-#if defined(TESTING) && defined(__x86_64__)
-void TestRow_SSE2(const uint8* src_y, uint8* dst_argb, int pix) {
- asm volatile (
- ".p2align 5 \n"
- "mov %%eax,%%eax \n"
- "mov %%ebx,%%ebx \n"
- "mov %%ecx,%%ecx \n"
- "mov %%edx,%%edx \n"
- "mov %%esi,%%esi \n"
- "mov %%edi,%%edi \n"
- "mov %%ebp,%%ebp \n"
- "mov %%esp,%%esp \n"
- ".p2align 5 \n"
- "mov %%r8d,%%r8d \n"
- "mov %%r9d,%%r9d \n"
- "mov %%r10d,%%r10d \n"
- "mov %%r11d,%%r11d \n"
- "mov %%r12d,%%r12d \n"
- "mov %%r13d,%%r13d \n"
- "mov %%r14d,%%r14d \n"
- "mov %%r15d,%%r15d \n"
- ".p2align 5 \n"
- "lea (%%rax),%%eax \n"
- "lea (%%rbx),%%ebx \n"
- "lea (%%rcx),%%ecx \n"
- "lea (%%rdx),%%edx \n"
- "lea (%%rsi),%%esi \n"
- "lea (%%rdi),%%edi \n"
- "lea (%%rbp),%%ebp \n"
- "lea (%%rsp),%%esp \n"
- ".p2align 5 \n"
- "lea (%%r8),%%r8d \n"
- "lea (%%r9),%%r9d \n"
- "lea (%%r10),%%r10d \n"
- "lea (%%r11),%%r11d \n"
- "lea (%%r12),%%r12d \n"
- "lea (%%r13),%%r13d \n"
- "lea (%%r14),%%r14d \n"
- "lea (%%r15),%%r15d \n"
-
- ".p2align 5 \n"
- "lea 0x10(%%rax),%%eax \n"
- "lea 0x10(%%rbx),%%ebx \n"
- "lea 0x10(%%rcx),%%ecx \n"
- "lea 0x10(%%rdx),%%edx \n"
- "lea 0x10(%%rsi),%%esi \n"
- "lea 0x10(%%rdi),%%edi \n"
- "lea 0x10(%%rbp),%%ebp \n"
- "lea 0x10(%%rsp),%%esp \n"
- ".p2align 5 \n"
- "lea 0x10(%%r8),%%r8d \n"
- "lea 0x10(%%r9),%%r9d \n"
- "lea 0x10(%%r10),%%r10d \n"
- "lea 0x10(%%r11),%%r11d \n"
- "lea 0x10(%%r12),%%r12d \n"
- "lea 0x10(%%r13),%%r13d \n"
- "lea 0x10(%%r14),%%r14d \n"
- "lea 0x10(%%r15),%%r15d \n"
-
- ".p2align 5 \n"
- "add 0x10,%%eax \n"
- "add 0x10,%%ebx \n"
- "add 0x10,%%ecx \n"
- "add 0x10,%%edx \n"
- "add 0x10,%%esi \n"
- "add 0x10,%%edi \n"
- "add 0x10,%%ebp \n"
- "add 0x10,%%esp \n"
- ".p2align 5 \n"
- "add 0x10,%%r8d \n"
- "add 0x10,%%r9d \n"
- "add 0x10,%%r10d \n"
- "add 0x10,%%r11d \n"
- "add 0x10,%%r12d \n"
- "add 0x10,%%r13d \n"
- "add 0x10,%%r14d \n"
- "add 0x10,%%r15d \n"
-
- ".p2align 2 \n"
- "1: \n"
- "movq " MEMACCESS(0) ",%%xmm0 \n"
- "lea " MEMLEA(0x8,0) ",%0 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x20,1) ",%1 \n"
- "sub $0x8,%2 \n"
- "jg 1b \n"
- : "+r"(src_y), // %0
- "+r"(dst_argb), // %1
- "+r"(pix) // %2
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm5"
-#endif
- );
-}
-#endif // TESTING
-
-#ifdef HAS_I400TOARGBROW_SSE2
-void I400ToARGBRow_SSE2(const uint8* src_y, uint8* dst_argb, int pix) {
- asm volatile (
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "pslld $0x18,%%xmm5 \n"
- LABELALIGN
- "1: \n"
- "movq " MEMACCESS(0) ",%%xmm0 \n"
- "lea " MEMLEA(0x8,0) ",%0 \n"
- "punpcklbw %%xmm0,%%xmm0 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "punpcklwd %%xmm0,%%xmm0 \n"
- "punpckhwd %%xmm1,%%xmm1 \n"
- "por %%xmm5,%%xmm0 \n"
- "por %%xmm5,%%xmm1 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "movdqa %%xmm1," MEMACCESS2(0x10,1) " \n"
- "lea " MEMLEA(0x20,1) ",%1 \n"
- "sub $0x8,%2 \n"
- "jg 1b \n"
- : "+r"(src_y), // %0
- "+r"(dst_argb), // %1
- "+r"(pix) // %2
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm5"
-#endif
- );
-}
-
-void I400ToARGBRow_Unaligned_SSE2(const uint8* src_y, uint8* dst_argb,
- int pix) {
- asm volatile (
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "pslld $0x18,%%xmm5 \n"
- LABELALIGN
- "1: \n"
- "movq " MEMACCESS(0) ",%%xmm0 \n"
- "lea " MEMLEA(0x8,0) ",%0 \n"
- "punpcklbw %%xmm0,%%xmm0 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "punpcklwd %%xmm0,%%xmm0 \n"
- "punpckhwd %%xmm1,%%xmm1 \n"
- "por %%xmm5,%%xmm0 \n"
- "por %%xmm5,%%xmm1 \n"
- "movdqu %%xmm0," MEMACCESS(1) " \n"
- "movdqu %%xmm1," MEMACCESS2(0x10,1) " \n"
- "lea " MEMLEA(0x20,1) ",%1 \n"
- "sub $0x8,%2 \n"
- "jg 1b \n"
- : "+r"(src_y), // %0
- "+r"(dst_argb), // %1
- "+r"(pix) // %2
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm5"
-#endif
- );
-}
-#endif // HAS_I400TOARGBROW_SSE2
-
-#ifdef HAS_RGB24TOARGBROW_SSSE3
-void RGB24ToARGBRow_SSSE3(const uint8* src_rgb24, uint8* dst_argb, int pix) {
- asm volatile (
- "pcmpeqb %%xmm5,%%xmm5 \n" // generate mask 0xff000000
- "pslld $0x18,%%xmm5 \n"
- "movdqa %3,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqu " MEMACCESS2(0x20,0) ",%%xmm3 \n"
- "lea " MEMLEA(0x30,0) ",%0 \n"
- "movdqa %%xmm3,%%xmm2 \n"
- "palignr $0x8,%%xmm1,%%xmm2 \n"
- "pshufb %%xmm4,%%xmm2 \n"
- "por %%xmm5,%%xmm2 \n"
- "palignr $0xc,%%xmm0,%%xmm1 \n"
- "pshufb %%xmm4,%%xmm0 \n"
- "movdqa %%xmm2," MEMACCESS2(0x20,1) " \n"
- "por %%xmm5,%%xmm0 \n"
- "pshufb %%xmm4,%%xmm1 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "por %%xmm5,%%xmm1 \n"
- "palignr $0x4,%%xmm3,%%xmm3 \n"
- "pshufb %%xmm4,%%xmm3 \n"
- "movdqa %%xmm1," MEMACCESS2(0x10,1) " \n"
- "por %%xmm5,%%xmm3 \n"
- "sub $0x10,%2 \n"
- "movdqa %%xmm3," MEMACCESS2(0x30,1) " \n"
- "lea " MEMLEA(0x40,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_rgb24), // %0
- "+r"(dst_argb), // %1
- "+r"(pix) // %2
- : "m"(kShuffleMaskRGB24ToARGB) // %3
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void RAWToARGBRow_SSSE3(const uint8* src_raw, uint8* dst_argb, int pix) {
- asm volatile (
- "pcmpeqb %%xmm5,%%xmm5 \n" // generate mask 0xff000000
- "pslld $0x18,%%xmm5 \n"
- "movdqa %3,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqu " MEMACCESS2(0x20,0) ",%%xmm3 \n"
- "lea " MEMLEA(0x30,0) ",%0 \n"
- "movdqa %%xmm3,%%xmm2 \n"
- "palignr $0x8,%%xmm1,%%xmm2 \n"
- "pshufb %%xmm4,%%xmm2 \n"
- "por %%xmm5,%%xmm2 \n"
- "palignr $0xc,%%xmm0,%%xmm1 \n"
- "pshufb %%xmm4,%%xmm0 \n"
- "movdqa %%xmm2," MEMACCESS2(0x20,1) " \n"
- "por %%xmm5,%%xmm0 \n"
- "pshufb %%xmm4,%%xmm1 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "por %%xmm5,%%xmm1 \n"
- "palignr $0x4,%%xmm3,%%xmm3 \n"
- "pshufb %%xmm4,%%xmm3 \n"
- "movdqa %%xmm1," MEMACCESS2(0x10,1) " \n"
- "por %%xmm5,%%xmm3 \n"
- "sub $0x10,%2 \n"
- "movdqa %%xmm3," MEMACCESS2(0x30,1) " \n"
- "lea " MEMLEA(0x40,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_raw), // %0
- "+r"(dst_argb), // %1
- "+r"(pix) // %2
- : "m"(kShuffleMaskRAWToARGB) // %3
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void RGB565ToARGBRow_SSE2(const uint8* src, uint8* dst, int pix) {
- asm volatile (
- "mov $0x1080108,%%eax \n"
- "movd %%eax,%%xmm5 \n"
- "pshufd $0x0,%%xmm5,%%xmm5 \n"
- "mov $0x20802080,%%eax \n"
- "movd %%eax,%%xmm6 \n"
- "pshufd $0x0,%%xmm6,%%xmm6 \n"
- "pcmpeqb %%xmm3,%%xmm3 \n"
- "psllw $0xb,%%xmm3 \n"
- "pcmpeqb %%xmm4,%%xmm4 \n"
- "psllw $0xa,%%xmm4 \n"
- "psrlw $0x5,%%xmm4 \n"
- "pcmpeqb %%xmm7,%%xmm7 \n"
- "psllw $0x8,%%xmm7 \n"
- "sub %0,%1 \n"
- "sub %0,%1 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "movdqa %%xmm0,%%xmm2 \n"
- "pand %%xmm3,%%xmm1 \n"
- "psllw $0xb,%%xmm2 \n"
- "pmulhuw %%xmm5,%%xmm1 \n"
- "pmulhuw %%xmm5,%%xmm2 \n"
- "psllw $0x8,%%xmm1 \n"
- "por %%xmm2,%%xmm1 \n"
- "pand %%xmm4,%%xmm0 \n"
- "pmulhuw %%xmm6,%%xmm0 \n"
- "por %%xmm7,%%xmm0 \n"
- "movdqa %%xmm1,%%xmm2 \n"
- "punpcklbw %%xmm0,%%xmm1 \n"
- "punpckhbw %%xmm0,%%xmm2 \n"
- BUNDLEALIGN
- MEMOPMEM(movdqa,xmm1,0x00,1,0,2) // movdqa %%xmm1,(%1,%0,2)
- MEMOPMEM(movdqa,xmm2,0x10,1,0,2) // movdqa %%xmm2,0x10(%1,%0,2)
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "sub $0x8,%2 \n"
- "jg 1b \n"
- : "+r"(src), // %0
- "+r"(dst), // %1
- "+r"(pix) // %2
- :
- : "memory", "cc", "eax"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
-#endif
- );
-}
-
-void ARGB1555ToARGBRow_SSE2(const uint8* src, uint8* dst, int pix) {
- asm volatile (
- "mov $0x1080108,%%eax \n"
- "movd %%eax,%%xmm5 \n"
- "pshufd $0x0,%%xmm5,%%xmm5 \n"
- "mov $0x42004200,%%eax \n"
- "movd %%eax,%%xmm6 \n"
- "pshufd $0x0,%%xmm6,%%xmm6 \n"
- "pcmpeqb %%xmm3,%%xmm3 \n"
- "psllw $0xb,%%xmm3 \n"
- "movdqa %%xmm3,%%xmm4 \n"
- "psrlw $0x6,%%xmm4 \n"
- "pcmpeqb %%xmm7,%%xmm7 \n"
- "psllw $0x8,%%xmm7 \n"
- "sub %0,%1 \n"
- "sub %0,%1 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "movdqa %%xmm0,%%xmm2 \n"
- "psllw $0x1,%%xmm1 \n"
- "psllw $0xb,%%xmm2 \n"
- "pand %%xmm3,%%xmm1 \n"
- "pmulhuw %%xmm5,%%xmm2 \n"
- "pmulhuw %%xmm5,%%xmm1 \n"
- "psllw $0x8,%%xmm1 \n"
- "por %%xmm2,%%xmm1 \n"
- "movdqa %%xmm0,%%xmm2 \n"
- "pand %%xmm4,%%xmm0 \n"
- "psraw $0x8,%%xmm2 \n"
- "pmulhuw %%xmm6,%%xmm0 \n"
- "pand %%xmm7,%%xmm2 \n"
- "por %%xmm2,%%xmm0 \n"
- "movdqa %%xmm1,%%xmm2 \n"
- "punpcklbw %%xmm0,%%xmm1 \n"
- "punpckhbw %%xmm0,%%xmm2 \n"
- BUNDLEALIGN
- MEMOPMEM(movdqa,xmm1,0x00,1,0,2) // movdqa %%xmm1,(%1,%0,2)
- MEMOPMEM(movdqa,xmm2,0x10,1,0,2) // movdqa %%xmm2,0x10(%1,%0,2)
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "sub $0x8,%2 \n"
- "jg 1b \n"
- : "+r"(src), // %0
- "+r"(dst), // %1
- "+r"(pix) // %2
- :
- : "memory", "cc", "eax"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
-#endif
- );
-}
-
-void ARGB4444ToARGBRow_SSE2(const uint8* src, uint8* dst, int pix) {
- asm volatile (
- "mov $0xf0f0f0f,%%eax \n"
- "movd %%eax,%%xmm4 \n"
- "pshufd $0x0,%%xmm4,%%xmm4 \n"
- "movdqa %%xmm4,%%xmm5 \n"
- "pslld $0x4,%%xmm5 \n"
- "sub %0,%1 \n"
- "sub %0,%1 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa %%xmm0,%%xmm2 \n"
- "pand %%xmm4,%%xmm0 \n"
- "pand %%xmm5,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "movdqa %%xmm2,%%xmm3 \n"
- "psllw $0x4,%%xmm1 \n"
- "psrlw $0x4,%%xmm3 \n"
- "por %%xmm1,%%xmm0 \n"
- "por %%xmm3,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "punpcklbw %%xmm2,%%xmm0 \n"
- "punpckhbw %%xmm2,%%xmm1 \n"
- BUNDLEALIGN
- MEMOPMEM(movdqa,xmm0,0x00,1,0,2) // movdqa %%xmm0,(%1,%0,2)
- MEMOPMEM(movdqa,xmm1,0x10,1,0,2) // movdqa %%xmm1,0x10(%1,%0,2)
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "sub $0x8,%2 \n"
- "jg 1b \n"
- : "+r"(src), // %0
- "+r"(dst), // %1
- "+r"(pix) // %2
- :
- : "memory", "cc", "eax"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void ARGBToRGB24Row_SSSE3(const uint8* src, uint8* dst, int pix) {
- asm volatile (
- "movdqa %3,%%xmm6 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqu " MEMACCESS2(0x30,0) ",%%xmm3 \n"
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "pshufb %%xmm6,%%xmm0 \n"
- "pshufb %%xmm6,%%xmm1 \n"
- "pshufb %%xmm6,%%xmm2 \n"
- "pshufb %%xmm6,%%xmm3 \n"
- "movdqa %%xmm1,%%xmm4 \n"
- "psrldq $0x4,%%xmm1 \n"
- "pslldq $0xc,%%xmm4 \n"
- "movdqa %%xmm2,%%xmm5 \n"
- "por %%xmm4,%%xmm0 \n"
- "pslldq $0x8,%%xmm5 \n"
- "movdqu %%xmm0," MEMACCESS(1) " \n"
- "por %%xmm5,%%xmm1 \n"
- "psrldq $0x8,%%xmm2 \n"
- "pslldq $0x4,%%xmm3 \n"
- "por %%xmm3,%%xmm2 \n"
- "movdqu %%xmm1," MEMACCESS2(0x10,1) " \n"
- "movdqu %%xmm2," MEMACCESS2(0x20,1) " \n"
- "lea " MEMLEA(0x30,1) ",%1 \n"
- "sub $0x10,%2 \n"
- "jg 1b \n"
- : "+r"(src), // %0
- "+r"(dst), // %1
- "+r"(pix) // %2
- : "m"(kShuffleMaskARGBToRGB24) // %3
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"
-#endif
- );
-}
-
-void ARGBToRAWRow_SSSE3(const uint8* src, uint8* dst, int pix) {
- asm volatile (
- "movdqa %3,%%xmm6 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqu " MEMACCESS2(0x30,0) ",%%xmm3 \n"
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "pshufb %%xmm6,%%xmm0 \n"
- "pshufb %%xmm6,%%xmm1 \n"
- "pshufb %%xmm6,%%xmm2 \n"
- "pshufb %%xmm6,%%xmm3 \n"
- "movdqa %%xmm1,%%xmm4 \n"
- "psrldq $0x4,%%xmm1 \n"
- "pslldq $0xc,%%xmm4 \n"
- "movdqa %%xmm2,%%xmm5 \n"
- "por %%xmm4,%%xmm0 \n"
- "pslldq $0x8,%%xmm5 \n"
- "movdqu %%xmm0," MEMACCESS(1) " \n"
- "por %%xmm5,%%xmm1 \n"
- "psrldq $0x8,%%xmm2 \n"
- "pslldq $0x4,%%xmm3 \n"
- "por %%xmm3,%%xmm2 \n"
- "movdqu %%xmm1," MEMACCESS2(0x10,1) " \n"
- "movdqu %%xmm2," MEMACCESS2(0x20,1) " \n"
- "lea " MEMLEA(0x30,1) ",%1 \n"
- "sub $0x10,%2 \n"
- "jg 1b \n"
- : "+r"(src), // %0
- "+r"(dst), // %1
- "+r"(pix) // %2
- : "m"(kShuffleMaskARGBToRAW) // %3
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"
-#endif
- );
-}
-
-void ARGBToRGB565Row_SSE2(const uint8* src, uint8* dst, int pix) {
- asm volatile (
- "pcmpeqb %%xmm3,%%xmm3 \n"
- "psrld $0x1b,%%xmm3 \n"
- "pcmpeqb %%xmm4,%%xmm4 \n"
- "psrld $0x1a,%%xmm4 \n"
- "pslld $0x5,%%xmm4 \n"
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "pslld $0xb,%%xmm5 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "movdqa %%xmm0,%%xmm2 \n"
- "pslld $0x8,%%xmm0 \n"
- "psrld $0x3,%%xmm1 \n"
- "psrld $0x5,%%xmm2 \n"
- "psrad $0x10,%%xmm0 \n"
- "pand %%xmm3,%%xmm1 \n"
- "pand %%xmm4,%%xmm2 \n"
- "pand %%xmm5,%%xmm0 \n"
- "por %%xmm2,%%xmm1 \n"
- "por %%xmm1,%%xmm0 \n"
- "packssdw %%xmm0,%%xmm0 \n"
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "movq %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "sub $0x4,%2 \n"
- "jg 1b \n"
- : "+r"(src), // %0
- "+r"(dst), // %1
- "+r"(pix) // %2
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void ARGBToARGB1555Row_SSE2(const uint8* src, uint8* dst, int pix) {
- asm volatile (
- "pcmpeqb %%xmm4,%%xmm4 \n"
- "psrld $0x1b,%%xmm4 \n"
- "movdqa %%xmm4,%%xmm5 \n"
- "pslld $0x5,%%xmm5 \n"
- "movdqa %%xmm4,%%xmm6 \n"
- "pslld $0xa,%%xmm6 \n"
- "pcmpeqb %%xmm7,%%xmm7 \n"
- "pslld $0xf,%%xmm7 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "movdqa %%xmm0,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm3 \n"
- "psrad $0x10,%%xmm0 \n"
- "psrld $0x3,%%xmm1 \n"
- "psrld $0x6,%%xmm2 \n"
- "psrld $0x9,%%xmm3 \n"
- "pand %%xmm7,%%xmm0 \n"
- "pand %%xmm4,%%xmm1 \n"
- "pand %%xmm5,%%xmm2 \n"
- "pand %%xmm6,%%xmm3 \n"
- "por %%xmm1,%%xmm0 \n"
- "por %%xmm3,%%xmm2 \n"
- "por %%xmm2,%%xmm0 \n"
- "packssdw %%xmm0,%%xmm0 \n"
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "movq %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMACCESS2(0x8,1) ",%1 \n"
- "sub $0x4,%2 \n"
- "jg 1b \n"
- : "+r"(src), // %0
- "+r"(dst), // %1
- "+r"(pix) // %2
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
-#endif
- );
-}
-
-void ARGBToARGB4444Row_SSE2(const uint8* src, uint8* dst, int pix) {
- asm volatile (
- "pcmpeqb %%xmm4,%%xmm4 \n"
- "psllw $0xc,%%xmm4 \n"
- "movdqa %%xmm4,%%xmm3 \n"
- "psrlw $0x8,%%xmm3 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "pand %%xmm3,%%xmm0 \n"
- "pand %%xmm4,%%xmm1 \n"
- "psrlq $0x4,%%xmm0 \n"
- "psrlq $0x8,%%xmm1 \n"
- "por %%xmm1,%%xmm0 \n"
- "packuswb %%xmm0,%%xmm0 \n"
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "movq %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "sub $0x4,%2 \n"
- "jg 1b \n"
- : "+r"(src), // %0
- "+r"(dst), // %1
- "+r"(pix) // %2
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4"
-#endif
- );
-}
-#endif // HAS_RGB24TOARGBROW_SSSE3
-
-#ifdef HAS_ARGBTOYROW_SSSE3
-void ARGBToYRow_SSSE3(const uint8* src_argb, uint8* dst_y, int pix) {
- asm volatile (
- "movdqa %4,%%xmm5 \n"
- "movdqa %3,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqa " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqa " MEMACCESS2(0x30,0) ",%%xmm3 \n"
- "pmaddubsw %%xmm4,%%xmm0 \n"
- "pmaddubsw %%xmm4,%%xmm1 \n"
- "pmaddubsw %%xmm4,%%xmm2 \n"
- "pmaddubsw %%xmm4,%%xmm3 \n"
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "phaddw %%xmm1,%%xmm0 \n"
- "phaddw %%xmm3,%%xmm2 \n"
- "psrlw $0x7,%%xmm0 \n"
- "psrlw $0x7,%%xmm2 \n"
- "packuswb %%xmm2,%%xmm0 \n"
- "paddb %%xmm5,%%xmm0 \n"
- "sub $0x10,%2 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_y), // %1
- "+r"(pix) // %2
- : "m"(kARGBToY), // %3
- "m"(kAddY16) // %4
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void ARGBToYRow_Unaligned_SSSE3(const uint8* src_argb, uint8* dst_y, int pix) {
- asm volatile (
- "movdqa %4,%%xmm5 \n"
- "movdqa %3,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqu " MEMACCESS2(0x30,0) ",%%xmm3 \n"
- "pmaddubsw %%xmm4,%%xmm0 \n"
- "pmaddubsw %%xmm4,%%xmm1 \n"
- "pmaddubsw %%xmm4,%%xmm2 \n"
- "pmaddubsw %%xmm4,%%xmm3 \n"
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "phaddw %%xmm1,%%xmm0 \n"
- "phaddw %%xmm3,%%xmm2 \n"
- "psrlw $0x7,%%xmm0 \n"
- "psrlw $0x7,%%xmm2 \n"
- "packuswb %%xmm2,%%xmm0 \n"
- "paddb %%xmm5,%%xmm0 \n"
- "sub $0x10,%2 \n"
- "movdqu %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_y), // %1
- "+r"(pix) // %2
- : "m"(kARGBToY), // %3
- "m"(kAddY16) // %4
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-#endif // HAS_ARGBTOYROW_SSSE3
-
-#ifdef HAS_ARGBTOYJROW_SSSE3
-void ARGBToYJRow_SSSE3(const uint8* src_argb, uint8* dst_y, int pix) {
- asm volatile (
- "movdqa %3,%%xmm4 \n"
- "movdqa %4,%%xmm5 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqa " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqa " MEMACCESS2(0x30,0) ",%%xmm3 \n"
- "pmaddubsw %%xmm4,%%xmm0 \n"
- "pmaddubsw %%xmm4,%%xmm1 \n"
- "pmaddubsw %%xmm4,%%xmm2 \n"
- "pmaddubsw %%xmm4,%%xmm3 \n"
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "phaddw %%xmm1,%%xmm0 \n"
- "phaddw %%xmm3,%%xmm2 \n"
- "paddw %%xmm5,%%xmm0 \n"
- "paddw %%xmm5,%%xmm2 \n"
- "psrlw $0x7,%%xmm0 \n"
- "psrlw $0x7,%%xmm2 \n"
- "packuswb %%xmm2,%%xmm0 \n"
- "sub $0x10,%2 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_y), // %1
- "+r"(pix) // %2
- : "m"(kARGBToYJ), // %3
- "m"(kAddYJ64) // %4
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void ARGBToYJRow_Unaligned_SSSE3(const uint8* src_argb, uint8* dst_y, int pix) {
- asm volatile (
- "movdqa %3,%%xmm4 \n"
- "movdqa %4,%%xmm5 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqu " MEMACCESS2(0x30,0) ",%%xmm3 \n"
- "pmaddubsw %%xmm4,%%xmm0 \n"
- "pmaddubsw %%xmm4,%%xmm1 \n"
- "pmaddubsw %%xmm4,%%xmm2 \n"
- "pmaddubsw %%xmm4,%%xmm3 \n"
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "phaddw %%xmm1,%%xmm0 \n"
- "phaddw %%xmm3,%%xmm2 \n"
- "paddw %%xmm5,%%xmm0 \n"
- "paddw %%xmm5,%%xmm2 \n"
- "psrlw $0x7,%%xmm0 \n"
- "psrlw $0x7,%%xmm2 \n"
- "packuswb %%xmm2,%%xmm0 \n"
- "sub $0x10,%2 \n"
- "movdqu %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_y), // %1
- "+r"(pix) // %2
- : "m"(kARGBToYJ), // %3
- "m"(kAddYJ64) // %4
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-#endif // HAS_ARGBTOYJROW_SSSE3
-
-#ifdef HAS_ARGBTOUVROW_SSSE3
-// TODO(fbarchard): pass xmm constants to single block of assembly.
-// fpic on GCC 4.2 for OSX runs out of GPR registers. "m" effectively takes
-// 3 registers - ebx, ebp and eax. "m" can be passed with 3 normal registers,
-// or 4 if stack frame is disabled. Doing 2 assembly blocks is a work around
-// and considered unsafe.
-void ARGBToUVRow_SSSE3(const uint8* src_argb0, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width) {
- asm volatile (
- "movdqa %0,%%xmm4 \n"
- "movdqa %1,%%xmm3 \n"
- "movdqa %2,%%xmm5 \n"
- :
- : "m"(kARGBToU), // %0
- "m"(kARGBToV), // %1
- "m"(kAddUV128) // %2
- );
- asm volatile (
- "sub %1,%2 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqa " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqa " MEMACCESS2(0x30,0) ",%%xmm6 \n"
- BUNDLEALIGN
- MEMOPREG(pavgb,0x00,0,4,1,xmm0) // pavgb (%0,%4,1),%%xmm0
- MEMOPREG(pavgb,0x10,0,4,1,xmm1) // pavgb 0x10(%0,%4,1),%%xmm1
- MEMOPREG(pavgb,0x20,0,4,1,xmm2) // pavgb 0x20(%0,%4,1),%%xmm2
- MEMOPREG(pavgb,0x30,0,4,1,xmm6) // pavgb 0x30(%0,%4,1),%%xmm6
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "movdqa %%xmm0,%%xmm7 \n"
- "shufps $0x88,%%xmm1,%%xmm0 \n"
- "shufps $0xdd,%%xmm1,%%xmm7 \n"
- "pavgb %%xmm7,%%xmm0 \n"
- "movdqa %%xmm2,%%xmm7 \n"
- "shufps $0x88,%%xmm6,%%xmm2 \n"
- "shufps $0xdd,%%xmm6,%%xmm7 \n"
- "pavgb %%xmm7,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "movdqa %%xmm2,%%xmm6 \n"
- "pmaddubsw %%xmm4,%%xmm0 \n"
- "pmaddubsw %%xmm4,%%xmm2 \n"
- "pmaddubsw %%xmm3,%%xmm1 \n"
- "pmaddubsw %%xmm3,%%xmm6 \n"
- "phaddw %%xmm2,%%xmm0 \n"
- "phaddw %%xmm6,%%xmm1 \n"
- "psraw $0x8,%%xmm0 \n"
- "psraw $0x8,%%xmm1 \n"
- "packsswb %%xmm1,%%xmm0 \n"
- "paddb %%xmm5,%%xmm0 \n"
- "sub $0x10,%3 \n"
- "movlps %%xmm0," MEMACCESS(1) " \n"
- BUNDLEALIGN
- MEMOPMEM(movhps,xmm0,0x00,1,2,1) // movhps %%xmm0,(%1,%2,1)
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_argb0), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+rm"(width) // %3
- : "r"((intptr_t)(src_stride_argb)) // %4
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm6", "xmm7"
-#endif
- );
-}
-
-// TODO(fbarchard): Share code with ARGBToUVRow_SSSE3.
-void ARGBToUVJRow_SSSE3(const uint8* src_argb0, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width) {
- asm volatile (
- "movdqa %0,%%xmm4 \n"
- "movdqa %1,%%xmm3 \n"
- "movdqa %2,%%xmm5 \n"
- :
- : "m"(kARGBToUJ), // %0
- "m"(kARGBToVJ), // %1
- "m"(kAddUVJ128) // %2
- );
- asm volatile (
- "sub %1,%2 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqa " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqa " MEMACCESS2(0x30,0) ",%%xmm6 \n"
- BUNDLEALIGN
- MEMOPREG(pavgb,0x00,0,4,1,xmm0) // pavgb (%0,%4,1),%%xmm0
- MEMOPREG(pavgb,0x10,0,4,1,xmm1) // pavgb 0x10(%0,%4,1),%%xmm1
- MEMOPREG(pavgb,0x20,0,4,1,xmm2) // pavgb 0x20(%0,%4,1),%%xmm2
- MEMOPREG(pavgb,0x30,0,4,1,xmm6) // pavgb 0x30(%0,%4,1),%%xmm6
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "movdqa %%xmm0,%%xmm7 \n"
- "shufps $0x88,%%xmm1,%%xmm0 \n"
- "shufps $0xdd,%%xmm1,%%xmm7 \n"
- "pavgb %%xmm7,%%xmm0 \n"
- "movdqa %%xmm2,%%xmm7 \n"
- "shufps $0x88,%%xmm6,%%xmm2 \n"
- "shufps $0xdd,%%xmm6,%%xmm7 \n"
- "pavgb %%xmm7,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "movdqa %%xmm2,%%xmm6 \n"
- "pmaddubsw %%xmm4,%%xmm0 \n"
- "pmaddubsw %%xmm4,%%xmm2 \n"
- "pmaddubsw %%xmm3,%%xmm1 \n"
- "pmaddubsw %%xmm3,%%xmm6 \n"
- "phaddw %%xmm2,%%xmm0 \n"
- "phaddw %%xmm6,%%xmm1 \n"
- "paddw %%xmm5,%%xmm0 \n"
- "paddw %%xmm5,%%xmm1 \n"
- "psraw $0x8,%%xmm0 \n"
- "psraw $0x8,%%xmm1 \n"
- "packsswb %%xmm1,%%xmm0 \n"
- "sub $0x10,%3 \n"
- "movlps %%xmm0," MEMACCESS(1) " \n"
- BUNDLEALIGN
- MEMOPMEM(movhps,xmm0,0x00,1,2,1) // movhps %%xmm0,(%1,%2,1)
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_argb0), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+rm"(width) // %3
- : "r"((intptr_t)(src_stride_argb)) // %4
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm6", "xmm7"
-#endif
- );
-}
-
-void ARGBToUVRow_Unaligned_SSSE3(const uint8* src_argb0, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width) {
- asm volatile (
- "movdqa %0,%%xmm4 \n"
- "movdqa %1,%%xmm3 \n"
- "movdqa %2,%%xmm5 \n"
- :
- : "m"(kARGBToU), // %0
- "m"(kARGBToV), // %1
- "m"(kAddUV128) // %2
- );
- asm volatile (
- "sub %1,%2 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqu " MEMACCESS2(0x30,0) ",%%xmm6 \n"
- BUNDLEALIGN
- MEMOPREG(movdqu,0x00,0,4,1,xmm7) // movdqu (%0,%4,1),%%xmm7
- "pavgb %%xmm7,%%xmm0 \n"
- MEMOPREG(movdqu,0x10,0,4,1,xmm7) // movdqu 0x10(%0,%4,1),%%xmm7
- "pavgb %%xmm7,%%xmm1 \n"
- MEMOPREG(movdqu,0x20,0,4,1,xmm7) // movdqu 0x20(%0,%4,1),%%xmm7
- "pavgb %%xmm7,%%xmm2 \n"
- MEMOPREG(movdqu,0x30,0,4,1,xmm7) // movdqu 0x30(%0,%4,1),%%xmm7
- "pavgb %%xmm7,%%xmm6 \n"
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "movdqa %%xmm0,%%xmm7 \n"
- "shufps $0x88,%%xmm1,%%xmm0 \n"
- "shufps $0xdd,%%xmm1,%%xmm7 \n"
- "pavgb %%xmm7,%%xmm0 \n"
- "movdqa %%xmm2,%%xmm7 \n"
- "shufps $0x88,%%xmm6,%%xmm2 \n"
- "shufps $0xdd,%%xmm6,%%xmm7 \n"
- "pavgb %%xmm7,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "movdqa %%xmm2,%%xmm6 \n"
- "pmaddubsw %%xmm4,%%xmm0 \n"
- "pmaddubsw %%xmm4,%%xmm2 \n"
- "pmaddubsw %%xmm3,%%xmm1 \n"
- "pmaddubsw %%xmm3,%%xmm6 \n"
- "phaddw %%xmm2,%%xmm0 \n"
- "phaddw %%xmm6,%%xmm1 \n"
- "psraw $0x8,%%xmm0 \n"
- "psraw $0x8,%%xmm1 \n"
- "packsswb %%xmm1,%%xmm0 \n"
- "paddb %%xmm5,%%xmm0 \n"
- "sub $0x10,%3 \n"
- "movlps %%xmm0," MEMACCESS(1) " \n"
- BUNDLEALIGN
- MEMOPMEM(movhps,xmm0,0x00,1,2,1) // movhps %%xmm0,(%1,%2,1)
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_argb0), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+rm"(width) // %3
- : "r"((intptr_t)(src_stride_argb)) // %4
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm6", "xmm7"
-#endif
- );
-}
-
-void ARGBToUVJRow_Unaligned_SSSE3(const uint8* src_argb0, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width) {
- asm volatile (
- "movdqa %0,%%xmm4 \n"
- "movdqa %1,%%xmm3 \n"
- "movdqa %2,%%xmm5 \n"
- :
- : "m"(kARGBToUJ), // %0
- "m"(kARGBToVJ), // %1
- "m"(kAddUVJ128) // %2
- );
- asm volatile (
- "sub %1,%2 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqu " MEMACCESS2(0x30,0) ",%%xmm6 \n"
- BUNDLEALIGN
- MEMOPREG(movdqu,0x00,0,4,1,xmm7) // movdqu (%0,%4,1),%%xmm7
- "pavgb %%xmm7,%%xmm0 \n"
- MEMOPREG(movdqu,0x10,0,4,1,xmm7) // movdqu 0x10(%0,%4,1),%%xmm7
- "pavgb %%xmm7,%%xmm1 \n"
- MEMOPREG(movdqu,0x20,0,4,1,xmm7) // movdqu 0x20(%0,%4,1),%%xmm7
- "pavgb %%xmm7,%%xmm2 \n"
- MEMOPREG(movdqu,0x30,0,4,1,xmm7) // movdqu 0x30(%0,%4,1),%%xmm7
- "pavgb %%xmm7,%%xmm6 \n"
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "movdqa %%xmm0,%%xmm7 \n"
- "shufps $0x88,%%xmm1,%%xmm0 \n"
- "shufps $0xdd,%%xmm1,%%xmm7 \n"
- "pavgb %%xmm7,%%xmm0 \n"
- "movdqa %%xmm2,%%xmm7 \n"
- "shufps $0x88,%%xmm6,%%xmm2 \n"
- "shufps $0xdd,%%xmm6,%%xmm7 \n"
- "pavgb %%xmm7,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "movdqa %%xmm2,%%xmm6 \n"
- "pmaddubsw %%xmm4,%%xmm0 \n"
- "pmaddubsw %%xmm4,%%xmm2 \n"
- "pmaddubsw %%xmm3,%%xmm1 \n"
- "pmaddubsw %%xmm3,%%xmm6 \n"
- "phaddw %%xmm2,%%xmm0 \n"
- "phaddw %%xmm6,%%xmm1 \n"
- "paddw %%xmm5,%%xmm0 \n"
- "paddw %%xmm5,%%xmm1 \n"
- "psraw $0x8,%%xmm0 \n"
- "psraw $0x8,%%xmm1 \n"
- "packsswb %%xmm1,%%xmm0 \n"
- "sub $0x10,%3 \n"
- "movlps %%xmm0," MEMACCESS(1) " \n"
- BUNDLEALIGN
- MEMOPMEM(movhps,xmm0,0x00,1,2,1) // movhps %%xmm0,(%1,%2,1)
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_argb0), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+rm"(width) // %3
- : "r"((intptr_t)(src_stride_argb))
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm6", "xmm7"
-#endif
- );
-}
-
-void ARGBToUV444Row_SSSE3(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
- int width) {
- asm volatile (
- "movdqa %0,%%xmm4 \n"
- "movdqa %1,%%xmm3 \n"
- "movdqa %2,%%xmm5 \n"
- :
- : "m"(kARGBToU), // %0
- "m"(kARGBToV), // %1
- "m"(kAddUV128) // %2
- );
- asm volatile (
- "sub %1,%2 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqa " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqa " MEMACCESS2(0x30,0) ",%%xmm6 \n"
- "pmaddubsw %%xmm4,%%xmm0 \n"
- "pmaddubsw %%xmm4,%%xmm1 \n"
- "pmaddubsw %%xmm4,%%xmm2 \n"
- "pmaddubsw %%xmm4,%%xmm6 \n"
- "phaddw %%xmm1,%%xmm0 \n"
- "phaddw %%xmm6,%%xmm2 \n"
- "psraw $0x8,%%xmm0 \n"
- "psraw $0x8,%%xmm2 \n"
- "packsswb %%xmm2,%%xmm0 \n"
- "paddb %%xmm5,%%xmm0 \n"
- "sub $0x10,%3 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqa " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqa " MEMACCESS2(0x30,0) ",%%xmm6 \n"
- "pmaddubsw %%xmm3,%%xmm0 \n"
- "pmaddubsw %%xmm3,%%xmm1 \n"
- "pmaddubsw %%xmm3,%%xmm2 \n"
- "pmaddubsw %%xmm3,%%xmm6 \n"
- "phaddw %%xmm1,%%xmm0 \n"
- "phaddw %%xmm6,%%xmm2 \n"
- "psraw $0x8,%%xmm0 \n"
- "psraw $0x8,%%xmm2 \n"
- "packsswb %%xmm2,%%xmm0 \n"
- "paddb %%xmm5,%%xmm0 \n"
- "lea " MEMLEA(0x40,0) ",%0 \n"
- BUNDLEALIGN
- MEMOPMEM(movdqa,xmm0,0x00,1,2,1) // movdqa %%xmm0,(%1,%2,1)
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+rm"(width) // %3
- :
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm6"
-#endif
- );
-}
-
-void ARGBToUV444Row_Unaligned_SSSE3(const uint8* src_argb, uint8* dst_u,
- uint8* dst_v, int width) {
- asm volatile (
- "movdqa %0,%%xmm4 \n"
- "movdqa %1,%%xmm3 \n"
- "movdqa %2,%%xmm5 \n"
- :
- : "m"(kARGBToU), // %0
- "m"(kARGBToV), // %1
- "m"(kAddUV128) // %2
- );
- asm volatile (
- "sub %1,%2 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqu " MEMACCESS2(0x30,0) ",%%xmm6 \n"
- "pmaddubsw %%xmm4,%%xmm0 \n"
- "pmaddubsw %%xmm4,%%xmm1 \n"
- "pmaddubsw %%xmm4,%%xmm2 \n"
- "pmaddubsw %%xmm4,%%xmm6 \n"
- "phaddw %%xmm1,%%xmm0 \n"
- "phaddw %%xmm6,%%xmm2 \n"
- "psraw $0x8,%%xmm0 \n"
- "psraw $0x8,%%xmm2 \n"
- "packsswb %%xmm2,%%xmm0 \n"
- "paddb %%xmm5,%%xmm0 \n"
- "sub $0x10,%3 \n"
- "movdqu %%xmm0," MEMACCESS(1) " \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqu " MEMACCESS2(0x30,0) ",%%xmm6 \n"
- "pmaddubsw %%xmm3,%%xmm0 \n"
- "pmaddubsw %%xmm3,%%xmm1 \n"
- "pmaddubsw %%xmm3,%%xmm2 \n"
- "pmaddubsw %%xmm3,%%xmm6 \n"
- "phaddw %%xmm1,%%xmm0 \n"
- "phaddw %%xmm6,%%xmm2 \n"
- "psraw $0x8,%%xmm0 \n"
- "psraw $0x8,%%xmm2 \n"
- "packsswb %%xmm2,%%xmm0 \n"
- "paddb %%xmm5,%%xmm0 \n"
- "lea " MEMLEA(0x40,0) ",%0 \n"
- BUNDLEALIGN
- MEMOPMEM(movdqu,xmm0,0x00,1,2,1) // movdqu %%xmm0,(%1,%2,1)
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+rm"(width) // %3
- :
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm6"
-#endif
- );
-}
-
-void ARGBToUV422Row_SSSE3(const uint8* src_argb0,
- uint8* dst_u, uint8* dst_v, int width) {
- asm volatile (
- "movdqa %0,%%xmm4 \n"
- "movdqa %1,%%xmm3 \n"
- "movdqa %2,%%xmm5 \n"
- :
- : "m"(kARGBToU), // %0
- "m"(kARGBToV), // %1
- "m"(kAddUV128) // %2
- );
- asm volatile (
- "sub %1,%2 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqa " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqa " MEMACCESS2(0x30,0) ",%%xmm6 \n"
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "movdqa %%xmm0,%%xmm7 \n"
- "shufps $0x88,%%xmm1,%%xmm0 \n"
- "shufps $0xdd,%%xmm1,%%xmm7 \n"
- "pavgb %%xmm7,%%xmm0 \n"
- "movdqa %%xmm2,%%xmm7 \n"
- "shufps $0x88,%%xmm6,%%xmm2 \n"
- "shufps $0xdd,%%xmm6,%%xmm7 \n"
- "pavgb %%xmm7,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "movdqa %%xmm2,%%xmm6 \n"
- "pmaddubsw %%xmm4,%%xmm0 \n"
- "pmaddubsw %%xmm4,%%xmm2 \n"
- "pmaddubsw %%xmm3,%%xmm1 \n"
- "pmaddubsw %%xmm3,%%xmm6 \n"
- "phaddw %%xmm2,%%xmm0 \n"
- "phaddw %%xmm6,%%xmm1 \n"
- "psraw $0x8,%%xmm0 \n"
- "psraw $0x8,%%xmm1 \n"
- "packsswb %%xmm1,%%xmm0 \n"
- "paddb %%xmm5,%%xmm0 \n"
- "sub $0x10,%3 \n"
- "movlps %%xmm0," MEMACCESS(1) " \n"
- BUNDLEALIGN
- MEMOPMEM(movhps,xmm0,0x00,1,2,1) // movhps %%xmm0,(%1,%2,1)
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_argb0), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+rm"(width) // %3
- :
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm6", "xmm7"
-#endif
- );
-}
-
-void ARGBToUV422Row_Unaligned_SSSE3(const uint8* src_argb0,
- uint8* dst_u, uint8* dst_v, int width) {
- asm volatile (
- "movdqa %0,%%xmm4 \n"
- "movdqa %1,%%xmm3 \n"
- "movdqa %2,%%xmm5 \n"
- :
- : "m"(kARGBToU), // %0
- "m"(kARGBToV), // %1
- "m"(kAddUV128) // %2
- );
- asm volatile (
- "sub %1,%2 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqu " MEMACCESS2(0x30,0) ",%%xmm6 \n"
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "movdqa %%xmm0,%%xmm7 \n"
- "shufps $0x88,%%xmm1,%%xmm0 \n"
- "shufps $0xdd,%%xmm1,%%xmm7 \n"
- "pavgb %%xmm7,%%xmm0 \n"
- "movdqa %%xmm2,%%xmm7 \n"
- "shufps $0x88,%%xmm6,%%xmm2 \n"
- "shufps $0xdd,%%xmm6,%%xmm7 \n"
- "pavgb %%xmm7,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "movdqa %%xmm2,%%xmm6 \n"
- "pmaddubsw %%xmm4,%%xmm0 \n"
- "pmaddubsw %%xmm4,%%xmm2 \n"
- "pmaddubsw %%xmm3,%%xmm1 \n"
- "pmaddubsw %%xmm3,%%xmm6 \n"
- "phaddw %%xmm2,%%xmm0 \n"
- "phaddw %%xmm6,%%xmm1 \n"
- "psraw $0x8,%%xmm0 \n"
- "psraw $0x8,%%xmm1 \n"
- "packsswb %%xmm1,%%xmm0 \n"
- "paddb %%xmm5,%%xmm0 \n"
- "sub $0x10,%3 \n"
- "movlps %%xmm0," MEMACCESS(1) " \n"
- BUNDLEALIGN
- MEMOPMEM(movhps,xmm0,0x00,1,2,1) // movhps %%xmm0,(%1,%2,1)
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_argb0), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+rm"(width) // %3
- :
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm6", "xmm7"
-#endif
- );
-}
-
-void BGRAToYRow_SSSE3(const uint8* src_bgra, uint8* dst_y, int pix) {
- asm volatile (
- "movdqa %4,%%xmm5 \n"
- "movdqa %3,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqa " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqa " MEMACCESS2(0x30,0) ",%%xmm3 \n"
- "pmaddubsw %%xmm4,%%xmm0 \n"
- "pmaddubsw %%xmm4,%%xmm1 \n"
- "pmaddubsw %%xmm4,%%xmm2 \n"
- "pmaddubsw %%xmm4,%%xmm3 \n"
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "phaddw %%xmm1,%%xmm0 \n"
- "phaddw %%xmm3,%%xmm2 \n"
- "psrlw $0x7,%%xmm0 \n"
- "psrlw $0x7,%%xmm2 \n"
- "packuswb %%xmm2,%%xmm0 \n"
- "paddb %%xmm5,%%xmm0 \n"
- "sub $0x10,%2 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_bgra), // %0
- "+r"(dst_y), // %1
- "+r"(pix) // %2
- : "m"(kBGRAToY), // %3
- "m"(kAddY16) // %4
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void BGRAToYRow_Unaligned_SSSE3(const uint8* src_bgra, uint8* dst_y, int pix) {
- asm volatile (
- "movdqa %4,%%xmm5 \n"
- "movdqa %3,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqu " MEMACCESS2(0x30,0) ",%%xmm3 \n"
- "pmaddubsw %%xmm4,%%xmm0 \n"
- "pmaddubsw %%xmm4,%%xmm1 \n"
- "pmaddubsw %%xmm4,%%xmm2 \n"
- "pmaddubsw %%xmm4,%%xmm3 \n"
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "phaddw %%xmm1,%%xmm0 \n"
- "phaddw %%xmm3,%%xmm2 \n"
- "psrlw $0x7,%%xmm0 \n"
- "psrlw $0x7,%%xmm2 \n"
- "packuswb %%xmm2,%%xmm0 \n"
- "paddb %%xmm5,%%xmm0 \n"
- "sub $0x10,%2 \n"
- "movdqu %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_bgra), // %0
- "+r"(dst_y), // %1
- "+r"(pix) // %2
- : "m"(kBGRAToY), // %3
- "m"(kAddY16) // %4
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void BGRAToUVRow_SSSE3(const uint8* src_bgra0, int src_stride_bgra,
- uint8* dst_u, uint8* dst_v, int width) {
- asm volatile (
- "movdqa %0,%%xmm4 \n"
- "movdqa %1,%%xmm3 \n"
- "movdqa %2,%%xmm5 \n"
- :
- : "m"(kBGRAToU), // %0
- "m"(kBGRAToV), // %1
- "m"(kAddUV128) // %2
- );
- asm volatile (
- "sub %1,%2 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqa " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqa " MEMACCESS2(0x30,0) ",%%xmm6 \n"
- BUNDLEALIGN
- MEMOPREG(pavgb,0x00,0,4,1,xmm0) // pavgb (%0,%4,1),%%xmm0
- MEMOPREG(pavgb,0x10,0,4,1,xmm1) // pavgb 0x10(%0,%4,1),%%xmm1
- MEMOPREG(pavgb,0x20,0,4,1,xmm2) // pavgb 0x20(%0,%4,1),%%xmm2
- MEMOPREG(pavgb,0x30,0,4,1,xmm6) // pavgb 0x30(%0,%4,1),%%xmm6
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "movdqa %%xmm0,%%xmm7 \n"
- "shufps $0x88,%%xmm1,%%xmm0 \n"
- "shufps $0xdd,%%xmm1,%%xmm7 \n"
- "pavgb %%xmm7,%%xmm0 \n"
- "movdqa %%xmm2,%%xmm7 \n"
- "shufps $0x88,%%xmm6,%%xmm2 \n"
- "shufps $0xdd,%%xmm6,%%xmm7 \n"
- "pavgb %%xmm7,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "movdqa %%xmm2,%%xmm6 \n"
- "pmaddubsw %%xmm4,%%xmm0 \n"
- "pmaddubsw %%xmm4,%%xmm2 \n"
- "pmaddubsw %%xmm3,%%xmm1 \n"
- "pmaddubsw %%xmm3,%%xmm6 \n"
- "phaddw %%xmm2,%%xmm0 \n"
- "phaddw %%xmm6,%%xmm1 \n"
- "psraw $0x8,%%xmm0 \n"
- "psraw $0x8,%%xmm1 \n"
- "packsswb %%xmm1,%%xmm0 \n"
- "paddb %%xmm5,%%xmm0 \n"
- "sub $0x10,%3 \n"
- "movlps %%xmm0," MEMACCESS(1) " \n"
- BUNDLEALIGN
- MEMOPMEM(movhps,xmm0,0x00,1,2,1) // movhps %%xmm0,(%1,%2,1)
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_bgra0), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+rm"(width) // %3
- : "r"((intptr_t)(src_stride_bgra)) // %4
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm6", "xmm7"
-#endif
- );
-}
-
-void BGRAToUVRow_Unaligned_SSSE3(const uint8* src_bgra0, int src_stride_bgra,
- uint8* dst_u, uint8* dst_v, int width) {
- asm volatile (
- "movdqa %0,%%xmm4 \n"
- "movdqa %1,%%xmm3 \n"
- "movdqa %2,%%xmm5 \n"
- :
- : "m"(kBGRAToU), // %0
- "m"(kBGRAToV), // %1
- "m"(kAddUV128) // %2
- );
- asm volatile (
- "sub %1,%2 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqu " MEMACCESS2(0x30,0) ",%%xmm6 \n"
- BUNDLEALIGN
- MEMOPREG(movdqu,0x00,0,4,1,xmm7) // movdqu (%0,%4,1),%%xmm7
- "pavgb %%xmm7,%%xmm0 \n"
- MEMOPREG(movdqu,0x10,0,4,1,xmm7) // movdqu 0x10(%0,%4,1),%%xmm7
- "pavgb %%xmm7,%%xmm1 \n"
- MEMOPREG(movdqu,0x20,0,4,1,xmm7) // movdqu 0x20(%0,%4,1),%%xmm7
- "pavgb %%xmm7,%%xmm2 \n"
- MEMOPREG(movdqu,0x30,0,4,1,xmm7) // movdqu 0x30(%0,%4,1),%%xmm7
- "pavgb %%xmm7,%%xmm6 \n"
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "movdqa %%xmm0,%%xmm7 \n"
- "shufps $0x88,%%xmm1,%%xmm0 \n"
- "shufps $0xdd,%%xmm1,%%xmm7 \n"
- "pavgb %%xmm7,%%xmm0 \n"
- "movdqa %%xmm2,%%xmm7 \n"
- "shufps $0x88,%%xmm6,%%xmm2 \n"
- "shufps $0xdd,%%xmm6,%%xmm7 \n"
- "pavgb %%xmm7,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "movdqa %%xmm2,%%xmm6 \n"
- "pmaddubsw %%xmm4,%%xmm0 \n"
- "pmaddubsw %%xmm4,%%xmm2 \n"
- "pmaddubsw %%xmm3,%%xmm1 \n"
- "pmaddubsw %%xmm3,%%xmm6 \n"
- "phaddw %%xmm2,%%xmm0 \n"
- "phaddw %%xmm6,%%xmm1 \n"
- "psraw $0x8,%%xmm0 \n"
- "psraw $0x8,%%xmm1 \n"
- "packsswb %%xmm1,%%xmm0 \n"
- "paddb %%xmm5,%%xmm0 \n"
- "sub $0x10,%3 \n"
- "movlps %%xmm0," MEMACCESS(1) " \n"
- BUNDLEALIGN
- MEMOPMEM(movhps,xmm0,0x00,1,2,1) // movhps %%xmm0,(%1,%2,1)
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_bgra0), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+rm"(width) // %3
- : "r"((intptr_t)(src_stride_bgra)) // %4
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm6", "xmm7"
-#endif
- );
-}
-
-void ABGRToYRow_SSSE3(const uint8* src_abgr, uint8* dst_y, int pix) {
- asm volatile (
- "movdqa %4,%%xmm5 \n"
- "movdqa %3,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqa " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqa " MEMACCESS2(0x30,0) ",%%xmm3 \n"
- "pmaddubsw %%xmm4,%%xmm0 \n"
- "pmaddubsw %%xmm4,%%xmm1 \n"
- "pmaddubsw %%xmm4,%%xmm2 \n"
- "pmaddubsw %%xmm4,%%xmm3 \n"
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "phaddw %%xmm1,%%xmm0 \n"
- "phaddw %%xmm3,%%xmm2 \n"
- "psrlw $0x7,%%xmm0 \n"
- "psrlw $0x7,%%xmm2 \n"
- "packuswb %%xmm2,%%xmm0 \n"
- "paddb %%xmm5,%%xmm0 \n"
- "sub $0x10,%2 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_abgr), // %0
- "+r"(dst_y), // %1
- "+r"(pix) // %2
- : "m"(kABGRToY), // %3
- "m"(kAddY16) // %4
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void ABGRToYRow_Unaligned_SSSE3(const uint8* src_abgr, uint8* dst_y, int pix) {
- asm volatile (
- "movdqa %4,%%xmm5 \n"
- "movdqa %3,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqu " MEMACCESS2(0x30,0) ",%%xmm3 \n"
- "pmaddubsw %%xmm4,%%xmm0 \n"
- "pmaddubsw %%xmm4,%%xmm1 \n"
- "pmaddubsw %%xmm4,%%xmm2 \n"
- "pmaddubsw %%xmm4,%%xmm3 \n"
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "phaddw %%xmm1,%%xmm0 \n"
- "phaddw %%xmm3,%%xmm2 \n"
- "psrlw $0x7,%%xmm0 \n"
- "psrlw $0x7,%%xmm2 \n"
- "packuswb %%xmm2,%%xmm0 \n"
- "paddb %%xmm5,%%xmm0 \n"
- "sub $0x10,%2 \n"
- "movdqu %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_abgr), // %0
- "+r"(dst_y), // %1
- "+r"(pix) // %2
- : "m"(kABGRToY), // %3
- "m"(kAddY16) // %4
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void RGBAToYRow_SSSE3(const uint8* src_rgba, uint8* dst_y, int pix) {
- asm volatile (
- "movdqa %4,%%xmm5 \n"
- "movdqa %3,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqa " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqa " MEMACCESS2(0x30,0) ",%%xmm3 \n"
- "pmaddubsw %%xmm4,%%xmm0 \n"
- "pmaddubsw %%xmm4,%%xmm1 \n"
- "pmaddubsw %%xmm4,%%xmm2 \n"
- "pmaddubsw %%xmm4,%%xmm3 \n"
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "phaddw %%xmm1,%%xmm0 \n"
- "phaddw %%xmm3,%%xmm2 \n"
- "psrlw $0x7,%%xmm0 \n"
- "psrlw $0x7,%%xmm2 \n"
- "packuswb %%xmm2,%%xmm0 \n"
- "paddb %%xmm5,%%xmm0 \n"
- "sub $0x10,%2 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_rgba), // %0
- "+r"(dst_y), // %1
- "+r"(pix) // %2
- : "m"(kRGBAToY), // %3
- "m"(kAddY16) // %4
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void RGBAToYRow_Unaligned_SSSE3(const uint8* src_rgba, uint8* dst_y, int pix) {
- asm volatile (
- "movdqa %4,%%xmm5 \n"
- "movdqa %3,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqu " MEMACCESS2(0x30,0) ",%%xmm3 \n"
- "pmaddubsw %%xmm4,%%xmm0 \n"
- "pmaddubsw %%xmm4,%%xmm1 \n"
- "pmaddubsw %%xmm4,%%xmm2 \n"
- "pmaddubsw %%xmm4,%%xmm3 \n"
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "phaddw %%xmm1,%%xmm0 \n"
- "phaddw %%xmm3,%%xmm2 \n"
- "psrlw $0x7,%%xmm0 \n"
- "psrlw $0x7,%%xmm2 \n"
- "packuswb %%xmm2,%%xmm0 \n"
- "paddb %%xmm5,%%xmm0 \n"
- "sub $0x10,%2 \n"
- "movdqu %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_rgba), // %0
- "+r"(dst_y), // %1
- "+r"(pix) // %2
- : "m"(kRGBAToY), // %3
- "m"(kAddY16) // %4
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void ABGRToUVRow_SSSE3(const uint8* src_abgr0, int src_stride_abgr,
- uint8* dst_u, uint8* dst_v, int width) {
- asm volatile (
- "movdqa %0,%%xmm4 \n"
- "movdqa %1,%%xmm3 \n"
- "movdqa %2,%%xmm5 \n"
- :
- : "m"(kABGRToU), // %0
- "m"(kABGRToV), // %1
- "m"(kAddUV128) // %2
- );
- asm volatile (
- "sub %1,%2 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqa " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqa " MEMACCESS2(0x30,0) ",%%xmm6 \n"
- BUNDLEALIGN
- MEMOPREG(pavgb,0x00,0,4,1,xmm0) // pavgb (%0,%4,1),%%xmm0
- MEMOPREG(pavgb,0x10,0,4,1,xmm1) // pavgb 0x10(%0,%4,1),%%xmm1
- MEMOPREG(pavgb,0x20,0,4,1,xmm2) // pavgb 0x20(%0,%4,1),%%xmm2
- MEMOPREG(pavgb,0x30,0,4,1,xmm6) // pavgb 0x30(%0,%4,1),%%xmm6
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "movdqa %%xmm0,%%xmm7 \n"
- "shufps $0x88,%%xmm1,%%xmm0 \n"
- "shufps $0xdd,%%xmm1,%%xmm7 \n"
- "pavgb %%xmm7,%%xmm0 \n"
- "movdqa %%xmm2,%%xmm7 \n"
- "shufps $0x88,%%xmm6,%%xmm2 \n"
- "shufps $0xdd,%%xmm6,%%xmm7 \n"
- "pavgb %%xmm7,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "movdqa %%xmm2,%%xmm6 \n"
- "pmaddubsw %%xmm4,%%xmm0 \n"
- "pmaddubsw %%xmm4,%%xmm2 \n"
- "pmaddubsw %%xmm3,%%xmm1 \n"
- "pmaddubsw %%xmm3,%%xmm6 \n"
- "phaddw %%xmm2,%%xmm0 \n"
- "phaddw %%xmm6,%%xmm1 \n"
- "psraw $0x8,%%xmm0 \n"
- "psraw $0x8,%%xmm1 \n"
- "packsswb %%xmm1,%%xmm0 \n"
- "paddb %%xmm5,%%xmm0 \n"
- "sub $0x10,%3 \n"
- "movlps %%xmm0," MEMACCESS(1) " \n"
- BUNDLEALIGN
- MEMOPMEM(movhps,xmm0,0x00,1,2,1) // movhps %%xmm0,(%1,%2,1)
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_abgr0), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+rm"(width) // %3
- : "r"((intptr_t)(src_stride_abgr)) // %4
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm6", "xmm7"
-#endif
- );
-}
-
-void ABGRToUVRow_Unaligned_SSSE3(const uint8* src_abgr0, int src_stride_abgr,
- uint8* dst_u, uint8* dst_v, int width) {
- asm volatile (
- "movdqa %0,%%xmm4 \n"
- "movdqa %1,%%xmm3 \n"
- "movdqa %2,%%xmm5 \n"
- :
- : "m"(kABGRToU), // %0
- "m"(kABGRToV), // %1
- "m"(kAddUV128) // %2
- );
- asm volatile (
- "sub %1,%2 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqu " MEMACCESS2(0x30,0) ",%%xmm6 \n"
- BUNDLEALIGN
- MEMOPREG(movdqu,0x00,0,4,1,xmm7) // movdqu (%0,%4,1),%%xmm7
- "pavgb %%xmm7,%%xmm0 \n"
- MEMOPREG(movdqu,0x10,0,4,1,xmm7) // movdqu 0x10(%0,%4,1),%%xmm7
- "pavgb %%xmm7,%%xmm1 \n"
- MEMOPREG(movdqu,0x20,0,4,1,xmm7) // movdqu 0x20(%0,%4,1),%%xmm7
- "pavgb %%xmm7,%%xmm2 \n"
- MEMOPREG(movdqu,0x30,0,4,1,xmm7) // movdqu 0x30(%0,%4,1),%%xmm7
- "pavgb %%xmm7,%%xmm6 \n"
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "movdqa %%xmm0,%%xmm7 \n"
- "shufps $0x88,%%xmm1,%%xmm0 \n"
- "shufps $0xdd,%%xmm1,%%xmm7 \n"
- "pavgb %%xmm7,%%xmm0 \n"
- "movdqa %%xmm2,%%xmm7 \n"
- "shufps $0x88,%%xmm6,%%xmm2 \n"
- "shufps $0xdd,%%xmm6,%%xmm7 \n"
- "pavgb %%xmm7,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "movdqa %%xmm2,%%xmm6 \n"
- "pmaddubsw %%xmm4,%%xmm0 \n"
- "pmaddubsw %%xmm4,%%xmm2 \n"
- "pmaddubsw %%xmm3,%%xmm1 \n"
- "pmaddubsw %%xmm3,%%xmm6 \n"
- "phaddw %%xmm2,%%xmm0 \n"
- "phaddw %%xmm6,%%xmm1 \n"
- "psraw $0x8,%%xmm0 \n"
- "psraw $0x8,%%xmm1 \n"
- "packsswb %%xmm1,%%xmm0 \n"
- "paddb %%xmm5,%%xmm0 \n"
- "sub $0x10,%3 \n"
- "movlps %%xmm0," MEMACCESS(1) " \n"
- BUNDLEALIGN
- MEMOPMEM(movhps,xmm0,0x00,1,2,1) // movhps %%xmm0,(%1,%2,1)
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_abgr0), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+rm"(width) // %3
- : "r"((intptr_t)(src_stride_abgr)) // %4
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm6", "xmm7"
-#endif
- );
-}
-
-void RGBAToUVRow_SSSE3(const uint8* src_rgba0, int src_stride_rgba,
- uint8* dst_u, uint8* dst_v, int width) {
- asm volatile (
- "movdqa %0,%%xmm4 \n"
- "movdqa %1,%%xmm3 \n"
- "movdqa %2,%%xmm5 \n"
- :
- : "m"(kRGBAToU), // %0
- "m"(kRGBAToV), // %1
- "m"(kAddUV128) // %2
- );
- asm volatile (
- "sub %1,%2 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqa " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqa " MEMACCESS2(0x30,0) ",%%xmm6 \n"
- BUNDLEALIGN
- MEMOPREG(pavgb,0x00,0,4,1,xmm0) // pavgb (%0,%4,1),%%xmm0
- MEMOPREG(pavgb,0x10,0,4,1,xmm1) // pavgb 0x10(%0,%4,1),%%xmm1
- MEMOPREG(pavgb,0x20,0,4,1,xmm2) // pavgb 0x20(%0,%4,1),%%xmm2
- MEMOPREG(pavgb,0x30,0,4,1,xmm6) // pavgb 0x30(%0,%4,1),%%xmm6
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "movdqa %%xmm0,%%xmm7 \n"
- "shufps $0x88,%%xmm1,%%xmm0 \n"
- "shufps $0xdd,%%xmm1,%%xmm7 \n"
- "pavgb %%xmm7,%%xmm0 \n"
- "movdqa %%xmm2,%%xmm7 \n"
- "shufps $0x88,%%xmm6,%%xmm2 \n"
- "shufps $0xdd,%%xmm6,%%xmm7 \n"
- "pavgb %%xmm7,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "movdqa %%xmm2,%%xmm6 \n"
- "pmaddubsw %%xmm4,%%xmm0 \n"
- "pmaddubsw %%xmm4,%%xmm2 \n"
- "pmaddubsw %%xmm3,%%xmm1 \n"
- "pmaddubsw %%xmm3,%%xmm6 \n"
- "phaddw %%xmm2,%%xmm0 \n"
- "phaddw %%xmm6,%%xmm1 \n"
- "psraw $0x8,%%xmm0 \n"
- "psraw $0x8,%%xmm1 \n"
- "packsswb %%xmm1,%%xmm0 \n"
- "paddb %%xmm5,%%xmm0 \n"
- "sub $0x10,%3 \n"
- "movlps %%xmm0," MEMACCESS(1) " \n"
- BUNDLEALIGN
- MEMOPMEM(movhps,xmm0,0x00,1,2,1) // movhps %%xmm0,(%1,%2,1)
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_rgba0), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+rm"(width) // %3
- : "r"((intptr_t)(src_stride_rgba))
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm6", "xmm7"
-#endif
- );
-}
-
-void RGBAToUVRow_Unaligned_SSSE3(const uint8* src_rgba0, int src_stride_rgba,
- uint8* dst_u, uint8* dst_v, int width) {
- asm volatile (
- "movdqa %0,%%xmm4 \n"
- "movdqa %1,%%xmm3 \n"
- "movdqa %2,%%xmm5 \n"
- :
- : "m"(kRGBAToU), // %0
- "m"(kRGBAToV), // %1
- "m"(kAddUV128) // %2
- );
- asm volatile (
- "sub %1,%2 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqu " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqu " MEMACCESS2(0x30,0) ",%%xmm6 \n"
- BUNDLEALIGN
- MEMOPREG(movdqu,0x00,0,4,1,xmm7) // movdqu (%0,%4,1),%%xmm7
- "pavgb %%xmm7,%%xmm0 \n"
- MEMOPREG(movdqu,0x10,0,4,1,xmm7) // movdqu 0x10(%0,%4,1),%%xmm7
- "pavgb %%xmm7,%%xmm1 \n"
- MEMOPREG(movdqu,0x20,0,4,1,xmm7) // movdqu 0x20(%0,%4,1),%%xmm7
- "pavgb %%xmm7,%%xmm2 \n"
- MEMOPREG(movdqu,0x30,0,4,1,xmm7) // movdqu 0x30(%0,%4,1),%%xmm7
- "pavgb %%xmm7,%%xmm6 \n"
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "movdqa %%xmm0,%%xmm7 \n"
- "shufps $0x88,%%xmm1,%%xmm0 \n"
- "shufps $0xdd,%%xmm1,%%xmm7 \n"
- "pavgb %%xmm7,%%xmm0 \n"
- "movdqa %%xmm2,%%xmm7 \n"
- "shufps $0x88,%%xmm6,%%xmm2 \n"
- "shufps $0xdd,%%xmm6,%%xmm7 \n"
- "pavgb %%xmm7,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "movdqa %%xmm2,%%xmm6 \n"
- "pmaddubsw %%xmm4,%%xmm0 \n"
- "pmaddubsw %%xmm4,%%xmm2 \n"
- "pmaddubsw %%xmm3,%%xmm1 \n"
- "pmaddubsw %%xmm3,%%xmm6 \n"
- "phaddw %%xmm2,%%xmm0 \n"
- "phaddw %%xmm6,%%xmm1 \n"
- "psraw $0x8,%%xmm0 \n"
- "psraw $0x8,%%xmm1 \n"
- "packsswb %%xmm1,%%xmm0 \n"
- "paddb %%xmm5,%%xmm0 \n"
- "sub $0x10,%3 \n"
- "movlps %%xmm0," MEMACCESS(1) " \n"
- BUNDLEALIGN
- MEMOPMEM(movhps,xmm0,0x00,1,2,1) // movhps %%xmm0,(%1,%2,1)
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_rgba0), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+rm"(width) // %3
- : "r"((intptr_t)(src_stride_rgba)) // %4
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm6", "xmm7"
-#endif
- );
-}
-#endif // HAS_ARGBTOUVROW_SSSE3
-
-#ifdef HAS_I422TOARGBROW_SSSE3
-#define UB 127 /* min(63,(int8)(2.018 * 64)) */
-#define UG -25 /* (int8)(-0.391 * 64 - 0.5) */
-#define UR 0
-
-#define VB 0
-#define VG -52 /* (int8)(-0.813 * 64 - 0.5) */
-#define VR 102 /* (int8)(1.596 * 64 + 0.5) */
-
-// Bias
-#define BB UB * 128 + VB * 128
-#define BG UG * 128 + VG * 128
-#define BR UR * 128 + VR * 128
-
-#define YG 74 /* (int8)(1.164 * 64 + 0.5) */
-
-struct {
- vec8 kUVToB; // 0
- vec8 kUVToG; // 16
- vec8 kUVToR; // 32
- vec16 kUVBiasB; // 48
- vec16 kUVBiasG; // 64
- vec16 kUVBiasR; // 80
- vec16 kYSub16; // 96
- vec16 kYToRgb; // 112
- vec8 kVUToB; // 128
- vec8 kVUToG; // 144
- vec8 kVUToR; // 160
-} static SIMD_ALIGNED(kYuvConstants) = {
- { UB, VB, UB, VB, UB, VB, UB, VB, UB, VB, UB, VB, UB, VB, UB, VB },
- { UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG },
- { UR, VR, UR, VR, UR, VR, UR, VR, UR, VR, UR, VR, UR, VR, UR, VR },
- { BB, BB, BB, BB, BB, BB, BB, BB },
- { BG, BG, BG, BG, BG, BG, BG, BG },
- { BR, BR, BR, BR, BR, BR, BR, BR },
- { 16, 16, 16, 16, 16, 16, 16, 16 },
- { YG, YG, YG, YG, YG, YG, YG, YG },
- { VB, UB, VB, UB, VB, UB, VB, UB, VB, UB, VB, UB, VB, UB, VB, UB },
- { VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG },
- { VR, UR, VR, UR, VR, UR, VR, UR, VR, UR, VR, UR, VR, UR, VR, UR }
-};
-
-
-// Read 8 UV from 411
-#define READYUV444 \
- "movq " MEMACCESS([u_buf]) ",%%xmm0 \n" \
- BUNDLEALIGN \
- MEMOPREG(movq, 0x00, [u_buf], [v_buf], 1, xmm1) \
- "lea " MEMLEA(0x8, [u_buf]) ",%[u_buf] \n" \
- "punpcklbw %%xmm1,%%xmm0 \n"
-
-// Read 4 UV from 422, upsample to 8 UV
-#define READYUV422 \
- "movd " MEMACCESS([u_buf]) ",%%xmm0 \n" \
- BUNDLEALIGN \
- MEMOPREG(movd, 0x00, [u_buf], [v_buf], 1, xmm1) \
- "lea " MEMLEA(0x4, [u_buf]) ",%[u_buf] \n" \
- "punpcklbw %%xmm1,%%xmm0 \n" \
- "punpcklwd %%xmm0,%%xmm0 \n"
-
-// Read 2 UV from 411, upsample to 8 UV
-#define READYUV411 \
- "movd " MEMACCESS([u_buf]) ",%%xmm0 \n" \
- BUNDLEALIGN \
- MEMOPREG(movd, 0x00, [u_buf], [v_buf], 1, xmm1) \
- "lea " MEMLEA(0x2, [u_buf]) ",%[u_buf] \n" \
- "punpcklbw %%xmm1,%%xmm0 \n" \
- "punpcklwd %%xmm0,%%xmm0 \n" \
- "punpckldq %%xmm0,%%xmm0 \n"
-
-// Read 4 UV from NV12, upsample to 8 UV
-#define READNV12 \
- "movq " MEMACCESS([uv_buf]) ",%%xmm0 \n" \
- "lea " MEMLEA(0x8, [uv_buf]) ",%[uv_buf] \n" \
- "punpcklwd %%xmm0,%%xmm0 \n"
-
-// Convert 8 pixels: 8 UV and 8 Y
-#define YUVTORGB \
- "movdqa %%xmm0,%%xmm1 \n" \
- "movdqa %%xmm0,%%xmm2 \n" \
- "pmaddubsw " MEMACCESS([kYuvConstants]) ",%%xmm0 \n" \
- "pmaddubsw " MEMACCESS2(16, [kYuvConstants]) ",%%xmm1 \n" \
- "pmaddubsw " MEMACCESS2(32, [kYuvConstants]) ",%%xmm2 \n" \
- "psubw " MEMACCESS2(48, [kYuvConstants]) ",%%xmm0 \n" \
- "psubw " MEMACCESS2(64, [kYuvConstants]) ",%%xmm1 \n" \
- "psubw " MEMACCESS2(80, [kYuvConstants]) ",%%xmm2 \n" \
- "movq " MEMACCESS([y_buf]) ",%%xmm3 \n" \
- "lea " MEMLEA(0x8, [y_buf]) ",%[y_buf] \n" \
- "punpcklbw %%xmm4,%%xmm3 \n" \
- "psubsw " MEMACCESS2(96, [kYuvConstants]) ",%%xmm3 \n" \
- "pmullw " MEMACCESS2(112, [kYuvConstants]) ",%%xmm3 \n" \
- "paddsw %%xmm3,%%xmm0 \n" \
- "paddsw %%xmm3,%%xmm1 \n" \
- "paddsw %%xmm3,%%xmm2 \n" \
- "psraw $0x6,%%xmm0 \n" \
- "psraw $0x6,%%xmm1 \n" \
- "psraw $0x6,%%xmm2 \n" \
- "packuswb %%xmm0,%%xmm0 \n" \
- "packuswb %%xmm1,%%xmm1 \n" \
- "packuswb %%xmm2,%%xmm2 \n"
-
-// Convert 8 pixels: 8 VU and 8 Y
-#define YVUTORGB \
- "movdqa %%xmm0,%%xmm1 \n" \
- "movdqa %%xmm0,%%xmm2 \n" \
- "pmaddubsw " MEMACCESS2(128, [kYuvConstants]) ",%%xmm0 \n" \
- "pmaddubsw " MEMACCESS2(144, [kYuvConstants]) ",%%xmm1 \n" \
- "pmaddubsw " MEMACCESS2(160, [kYuvConstants]) ",%%xmm2 \n" \
- "psubw " MEMACCESS2(48, [kYuvConstants]) ",%%xmm0 \n" \
- "psubw " MEMACCESS2(64, [kYuvConstants]) ",%%xmm1 \n" \
- "psubw " MEMACCESS2(80, [kYuvConstants]) ",%%xmm2 \n" \
- "movq " MEMACCESS([y_buf]) ",%%xmm3 \n" \
- "lea " MEMLEA(0x8, [y_buf]) ",%[y_buf] \n" \
- "punpcklbw %%xmm4,%%xmm3 \n" \
- "psubsw " MEMACCESS2(96, [kYuvConstants]) ",%%xmm3 \n" \
- "pmullw " MEMACCESS2(112, [kYuvConstants]) ",%%xmm3 \n" \
- "paddsw %%xmm3,%%xmm0 \n" \
- "paddsw %%xmm3,%%xmm1 \n" \
- "paddsw %%xmm3,%%xmm2 \n" \
- "psraw $0x6,%%xmm0 \n" \
- "psraw $0x6,%%xmm1 \n" \
- "psraw $0x6,%%xmm2 \n" \
- "packuswb %%xmm0,%%xmm0 \n" \
- "packuswb %%xmm1,%%xmm1 \n" \
- "packuswb %%xmm2,%%xmm2 \n"
-
-void OMITFP I444ToARGBRow_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_argb,
- int width) {
- asm volatile (
- "sub %[u_buf],%[v_buf] \n"
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "pxor %%xmm4,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- READYUV444
- YUVTORGB
- "punpcklbw %%xmm1,%%xmm0 \n"
- "punpcklbw %%xmm5,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "punpcklwd %%xmm2,%%xmm0 \n"
- "punpckhwd %%xmm2,%%xmm1 \n"
- "movdqa %%xmm0," MEMACCESS([dst_argb]) " \n"
- "movdqa %%xmm1," MEMACCESS2(0x10,[dst_argb]) " \n"
- "lea " MEMLEA(0x20,[dst_argb]) ",%[dst_argb] \n"
- "sub $0x8,%[width] \n"
- "jg 1b \n"
- : [y_buf]"+r"(y_buf), // %[y_buf]
- [u_buf]"+r"(u_buf), // %[u_buf]
- [v_buf]"+r"(v_buf), // %[v_buf]
- [dst_argb]"+r"(dst_argb), // %[dst_argb]
- [width]"+rm"(width) // %[width]
- : [kYuvConstants]"r"(&kYuvConstants.kUVToB) // %[kYuvConstants]
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void OMITFP I422ToRGB24Row_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_rgb24,
- int width) {
-// fpic 32 bit gcc 4.2 on OSX runs out of GPR regs.
-#if defined(__i386__)
- asm volatile (
- "movdqa %[kShuffleMaskARGBToRGB24_0],%%xmm5 \n"
- "movdqa %[kShuffleMaskARGBToRGB24],%%xmm6 \n"
- :: [kShuffleMaskARGBToRGB24_0]"m"(kShuffleMaskARGBToRGB24_0),
- [kShuffleMaskARGBToRGB24]"m"(kShuffleMaskARGBToRGB24));
-#endif
-
- asm volatile (
-#if !defined(__i386__)
- "movdqa %[kShuffleMaskARGBToRGB24_0],%%xmm5 \n"
- "movdqa %[kShuffleMaskARGBToRGB24],%%xmm6 \n"
-#endif
- "sub %[u_buf],%[v_buf] \n"
- "pxor %%xmm4,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- READYUV422
- YUVTORGB
- "punpcklbw %%xmm1,%%xmm0 \n"
- "punpcklbw %%xmm2,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "punpcklwd %%xmm2,%%xmm0 \n"
- "punpckhwd %%xmm2,%%xmm1 \n"
- "pshufb %%xmm5,%%xmm0 \n"
- "pshufb %%xmm6,%%xmm1 \n"
- "palignr $0xc,%%xmm0,%%xmm1 \n"
- "movq %%xmm0," MEMACCESS([dst_rgb24]) "\n"
- "movdqu %%xmm1," MEMACCESS2(0x8,[dst_rgb24]) "\n"
- "lea " MEMLEA(0x18,[dst_rgb24]) ",%[dst_rgb24] \n"
- "sub $0x8,%[width] \n"
- "jg 1b \n"
- : [y_buf]"+r"(y_buf), // %[y_buf]
- [u_buf]"+r"(u_buf), // %[u_buf]
- [v_buf]"+r"(v_buf), // %[v_buf]
- [dst_rgb24]"+r"(dst_rgb24), // %[dst_rgb24]
- [width]"+rm"(width) // %[width]
- : [kYuvConstants]"r"(&kYuvConstants.kUVToB)
-#if !defined(__i386__)
- , [kShuffleMaskARGBToRGB24_0]"m"(kShuffleMaskARGBToRGB24_0),
- [kShuffleMaskARGBToRGB24]"m"(kShuffleMaskARGBToRGB24)
-#endif
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"
-#endif
- );
-}
-
-void OMITFP I422ToRAWRow_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_raw,
- int width) {
-// fpic 32 bit gcc 4.2 on OSX runs out of GPR regs.
-#if defined(__i386__)
- asm volatile (
- "movdqa %[kShuffleMaskARGBToRAW_0],%%xmm5 \n"
- "movdqa %[kShuffleMaskARGBToRAW],%%xmm6 \n"
- :: [kShuffleMaskARGBToRAW_0]"m"(kShuffleMaskARGBToRAW_0),
- [kShuffleMaskARGBToRAW]"m"(kShuffleMaskARGBToRAW));
-#endif
-
- asm volatile (
-#if !defined(__i386__)
- "movdqa %[kShuffleMaskARGBToRAW_0],%%xmm5 \n"
- "movdqa %[kShuffleMaskARGBToRAW],%%xmm6 \n"
-#endif
- "sub %[u_buf],%[v_buf] \n"
- "pxor %%xmm4,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- READYUV422
- YUVTORGB
- "punpcklbw %%xmm1,%%xmm0 \n"
- "punpcklbw %%xmm2,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "punpcklwd %%xmm2,%%xmm0 \n"
- "punpckhwd %%xmm2,%%xmm1 \n"
- "pshufb %%xmm5,%%xmm0 \n"
- "pshufb %%xmm6,%%xmm1 \n"
- "palignr $0xc,%%xmm0,%%xmm1 \n"
- "movq %%xmm0," MEMACCESS([dst_raw]) " \n"
- "movdqu %%xmm1," MEMACCESS2(0x8,[dst_raw]) "\n"
- "lea " MEMLEA(0x18,[dst_raw]) ",%[dst_raw] \n"
- "sub $0x8,%[width] \n"
- "jg 1b \n"
- : [y_buf]"+r"(y_buf), // %[y_buf]
- [u_buf]"+r"(u_buf), // %[u_buf]
- [v_buf]"+r"(v_buf), // %[v_buf]
- [dst_raw]"+r"(dst_raw), // %[dst_raw]
- [width]"+rm"(width) // %[width]
- : [kYuvConstants]"r"(&kYuvConstants.kUVToB)
-#if !defined(__i386__)
- , [kShuffleMaskARGBToRAW_0]"m"(kShuffleMaskARGBToRAW_0),
- [kShuffleMaskARGBToRAW]"m"(kShuffleMaskARGBToRAW)
-#endif
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"
-#endif
- );
-}
-
-void OMITFP I422ToARGBRow_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_argb,
- int width) {
- asm volatile (
- "sub %[u_buf],%[v_buf] \n"
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "pxor %%xmm4,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- READYUV422
- YUVTORGB
- "punpcklbw %%xmm1,%%xmm0 \n"
- "punpcklbw %%xmm5,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "punpcklwd %%xmm2,%%xmm0 \n"
- "punpckhwd %%xmm2,%%xmm1 \n"
- "movdqa %%xmm0," MEMACCESS([dst_argb]) "\n"
- "movdqa %%xmm1," MEMACCESS2(0x10,[dst_argb]) "\n"
- "lea " MEMLEA(0x20,[dst_argb]) ",%[dst_argb] \n"
- "sub $0x8,%[width] \n"
- "jg 1b \n"
- : [y_buf]"+r"(y_buf), // %[y_buf]
- [u_buf]"+r"(u_buf), // %[u_buf]
- [v_buf]"+r"(v_buf), // %[v_buf]
- [dst_argb]"+r"(dst_argb), // %[dst_argb]
- [width]"+rm"(width) // %[width]
- : [kYuvConstants]"r"(&kYuvConstants.kUVToB) // %[kYuvConstants]
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void OMITFP I411ToARGBRow_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_argb,
- int width) {
- asm volatile (
- "sub %[u_buf],%[v_buf] \n"
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "pxor %%xmm4,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- READYUV411
- YUVTORGB
- "punpcklbw %%xmm1,%%xmm0 \n"
- "punpcklbw %%xmm5,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "punpcklwd %%xmm2,%%xmm0 \n"
- "punpckhwd %%xmm2,%%xmm1 \n"
- "movdqa %%xmm0," MEMACCESS([dst_argb]) "\n"
- "movdqa %%xmm1," MEMACCESS2(0x10,[dst_argb]) "\n"
- "lea " MEMLEA(0x20,[dst_argb]) ",%[dst_argb] \n"
- "sub $0x8,%[width] \n"
- "jg 1b \n"
- : [y_buf]"+r"(y_buf), // %[y_buf]
- [u_buf]"+r"(u_buf), // %[u_buf]
- [v_buf]"+r"(v_buf), // %[v_buf]
- [dst_argb]"+r"(dst_argb), // %[dst_argb]
- [width]"+rm"(width) // %[width]
- : [kYuvConstants]"r"(&kYuvConstants.kUVToB) // %[kYuvConstants]
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void OMITFP NV12ToARGBRow_SSSE3(const uint8* y_buf,
- const uint8* uv_buf,
- uint8* dst_argb,
- int width) {
- asm volatile (
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "pxor %%xmm4,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- READNV12
- YUVTORGB
- "punpcklbw %%xmm1,%%xmm0 \n"
- "punpcklbw %%xmm5,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "punpcklwd %%xmm2,%%xmm0 \n"
- "punpckhwd %%xmm2,%%xmm1 \n"
- "movdqa %%xmm0," MEMACCESS([dst_argb]) "\n"
- "movdqa %%xmm1," MEMACCESS2(0x10,[dst_argb]) "\n"
- "lea " MEMLEA(0x20,[dst_argb]) ",%[dst_argb] \n"
- "sub $0x8,%[width] \n"
- "jg 1b \n"
- : [y_buf]"+r"(y_buf), // %[y_buf]
- [uv_buf]"+r"(uv_buf), // %[uv_buf]
- [dst_argb]"+r"(dst_argb), // %[dst_argb]
- [width]"+rm"(width) // %[width]
- : [kYuvConstants]"r"(&kYuvConstants.kUVToB) // %[kYuvConstants]
- : "memory", "cc"
- // Does not use r14.
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void OMITFP NV21ToARGBRow_SSSE3(const uint8* y_buf,
- const uint8* uv_buf,
- uint8* dst_argb,
- int width) {
- asm volatile (
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "pxor %%xmm4,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- READNV12
- YVUTORGB
- "punpcklbw %%xmm1,%%xmm0 \n"
- "punpcklbw %%xmm5,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "punpcklwd %%xmm2,%%xmm0 \n"
- "punpckhwd %%xmm2,%%xmm1 \n"
- "movdqa %%xmm0," MEMACCESS([dst_argb]) "\n"
- "movdqa %%xmm1," MEMACCESS2(0x10,[dst_argb]) "\n"
- "lea " MEMLEA(0x20,[dst_argb]) ",%[dst_argb] \n"
- "sub $0x8,%[width] \n"
- "jg 1b \n"
- : [y_buf]"+r"(y_buf), // %[y_buf]
- [uv_buf]"+r"(uv_buf), // %[uv_buf]
- [dst_argb]"+r"(dst_argb), // %[dst_argb]
- [width]"+rm"(width) // %[width]
- : [kYuvConstants]"r"(&kYuvConstants.kUVToB) // %[kYuvConstants]
- : "memory", "cc"
- // Does not use r14.
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void OMITFP I444ToARGBRow_Unaligned_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_argb,
- int width) {
- asm volatile (
- "sub %[u_buf],%[v_buf] \n"
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "pxor %%xmm4,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- READYUV444
- YUVTORGB
- "punpcklbw %%xmm1,%%xmm0 \n"
- "punpcklbw %%xmm5,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "punpcklwd %%xmm2,%%xmm0 \n"
- "punpckhwd %%xmm2,%%xmm1 \n"
- "movdqu %%xmm0," MEMACCESS([dst_argb]) "\n"
- "movdqu %%xmm1," MEMACCESS2(0x10,[dst_argb]) "\n"
- "lea " MEMLEA(0x20,[dst_argb]) ",%[dst_argb] \n"
- "sub $0x8,%[width] \n"
- "jg 1b \n"
- : [y_buf]"+r"(y_buf), // %[y_buf]
- [u_buf]"+r"(u_buf), // %[u_buf]
- [v_buf]"+r"(v_buf), // %[v_buf]
- [dst_argb]"+r"(dst_argb), // %[dst_argb]
- [width]"+rm"(width) // %[width]
- : [kYuvConstants]"r"(&kYuvConstants.kUVToB) // %[kYuvConstants]
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void OMITFP I422ToARGBRow_Unaligned_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_argb,
- int width) {
- asm volatile (
- "sub %[u_buf],%[v_buf] \n"
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "pxor %%xmm4,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- READYUV422
- YUVTORGB
- "punpcklbw %%xmm1,%%xmm0 \n"
- "punpcklbw %%xmm5,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "punpcklwd %%xmm2,%%xmm0 \n"
- "punpckhwd %%xmm2,%%xmm1 \n"
- "movdqu %%xmm0," MEMACCESS([dst_argb]) "\n"
- "movdqu %%xmm1," MEMACCESS2(0x10,[dst_argb]) "\n"
- "lea " MEMLEA(0x20,[dst_argb]) ",%[dst_argb] \n"
- "sub $0x8,%[width] \n"
- "jg 1b \n"
- : [y_buf]"+r"(y_buf), // %[y_buf]
- [u_buf]"+r"(u_buf), // %[u_buf]
- [v_buf]"+r"(v_buf), // %[v_buf]
- [dst_argb]"+r"(dst_argb), // %[dst_argb]
- [width]"+rm"(width) // %[width]
- : [kYuvConstants]"r"(&kYuvConstants.kUVToB) // %[kYuvConstants]
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void OMITFP I411ToARGBRow_Unaligned_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_argb,
- int width) {
- asm volatile (
- "sub %[u_buf],%[v_buf] \n"
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "pxor %%xmm4,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- READYUV411
- YUVTORGB
- "punpcklbw %%xmm1,%%xmm0 \n"
- "punpcklbw %%xmm5,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "punpcklwd %%xmm2,%%xmm0 \n"
- "punpckhwd %%xmm2,%%xmm1 \n"
- "movdqu %%xmm0," MEMACCESS([dst_argb]) "\n"
- "movdqu %%xmm1," MEMACCESS2(0x10,[dst_argb]) "\n"
- "lea " MEMLEA(0x20,[dst_argb]) ",%[dst_argb] \n"
- "sub $0x8,%[width] \n"
- "jg 1b \n"
- : [y_buf]"+r"(y_buf), // %[y_buf]
- [u_buf]"+r"(u_buf), // %[u_buf]
- [v_buf]"+r"(v_buf), // %[v_buf]
- [dst_argb]"+r"(dst_argb), // %[dst_argb]
- [width]"+rm"(width) // %[width]
- : [kYuvConstants]"r"(&kYuvConstants.kUVToB) // %[kYuvConstants]
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void OMITFP NV12ToARGBRow_Unaligned_SSSE3(const uint8* y_buf,
- const uint8* uv_buf,
- uint8* dst_argb,
- int width) {
- asm volatile (
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "pxor %%xmm4,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- READNV12
- YUVTORGB
- "punpcklbw %%xmm1,%%xmm0 \n"
- "punpcklbw %%xmm5,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "punpcklwd %%xmm2,%%xmm0 \n"
- "punpckhwd %%xmm2,%%xmm1 \n"
- "movdqu %%xmm0," MEMACCESS([dst_argb]) "\n"
- "movdqu %%xmm1," MEMACCESS2(0x10,[dst_argb]) "\n"
- "lea " MEMLEA(0x20,[dst_argb]) ",%[dst_argb] \n"
- "sub $0x8,%[width] \n"
- "jg 1b \n"
- : [y_buf]"+r"(y_buf), // %[y_buf]
- [uv_buf]"+r"(uv_buf), // %[uv_buf]
- [dst_argb]"+r"(dst_argb), // %[dst_argb]
- [width]"+rm"(width) // %[width]
- : [kYuvConstants]"r"(&kYuvConstants.kUVToB) // %[kYuvConstants]
- : "memory", "cc"
- // Does not use r14.
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void OMITFP NV21ToARGBRow_Unaligned_SSSE3(const uint8* y_buf,
- const uint8* uv_buf,
- uint8* dst_argb,
- int width) {
- asm volatile (
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "pxor %%xmm4,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- READNV12
- YVUTORGB
- "punpcklbw %%xmm1,%%xmm0 \n"
- "punpcklbw %%xmm5,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "punpcklwd %%xmm2,%%xmm0 \n"
- "punpckhwd %%xmm2,%%xmm1 \n"
- "movdqu %%xmm0," MEMACCESS([dst_argb]) "\n"
- "movdqu %%xmm1," MEMACCESS2(0x10,[dst_argb]) "\n"
- "lea " MEMLEA(0x20,[dst_argb]) ",%[dst_argb] \n"
- "sub $0x8,%[width] \n"
- "jg 1b \n"
- : [y_buf]"+r"(y_buf), // %[y_buf]
- [uv_buf]"+r"(uv_buf), // %[uv_buf]
- [dst_argb]"+r"(dst_argb), // %[dst_argb]
- [width]"+rm"(width) // %[width]
- : [kYuvConstants]"r"(&kYuvConstants.kUVToB) // %[kYuvConstants]
- : "memory", "cc"
- // Does not use r14.
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void OMITFP I422ToBGRARow_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_bgra,
- int width) {
- asm volatile (
- "sub %[u_buf],%[v_buf] \n"
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "pxor %%xmm4,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- READYUV422
- YUVTORGB
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "punpcklbw %%xmm0,%%xmm1 \n"
- "punpcklbw %%xmm2,%%xmm5 \n"
- "movdqa %%xmm5,%%xmm0 \n"
- "punpcklwd %%xmm1,%%xmm5 \n"
- "punpckhwd %%xmm1,%%xmm0 \n"
- "movdqa %%xmm5," MEMACCESS([dst_bgra]) "\n"
- "movdqa %%xmm0," MEMACCESS2(0x10,[dst_bgra]) "\n"
- "lea " MEMLEA(0x20,[dst_bgra]) ",%[dst_bgra] \n"
- "sub $0x8,%[width] \n"
- "jg 1b \n"
- : [y_buf]"+r"(y_buf), // %[y_buf]
- [u_buf]"+r"(u_buf), // %[u_buf]
- [v_buf]"+r"(v_buf), // %[v_buf]
- [dst_bgra]"+r"(dst_bgra), // %[dst_bgra]
- [width]"+rm"(width) // %[width]
- : [kYuvConstants]"r"(&kYuvConstants.kUVToB) // %[kYuvConstants]
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void OMITFP I422ToABGRRow_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_abgr,
- int width) {
- asm volatile (
- "sub %[u_buf],%[v_buf] \n"
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "pxor %%xmm4,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- READYUV422
- YUVTORGB
- "punpcklbw %%xmm1,%%xmm2 \n"
- "punpcklbw %%xmm5,%%xmm0 \n"
- "movdqa %%xmm2,%%xmm1 \n"
- "punpcklwd %%xmm0,%%xmm2 \n"
- "punpckhwd %%xmm0,%%xmm1 \n"
- "movdqa %%xmm2," MEMACCESS([dst_abgr]) "\n"
- "movdqa %%xmm1," MEMACCESS2(0x10,[dst_abgr]) "\n"
- "lea " MEMLEA(0x20,[dst_abgr]) ",%[dst_abgr] \n"
- "sub $0x8,%[width] \n"
- "jg 1b \n"
- : [y_buf]"+r"(y_buf), // %[y_buf]
- [u_buf]"+r"(u_buf), // %[u_buf]
- [v_buf]"+r"(v_buf), // %[v_buf]
- [dst_abgr]"+r"(dst_abgr), // %[dst_abgr]
- [width]"+rm"(width) // %[width]
- : [kYuvConstants]"r"(&kYuvConstants.kUVToB) // %[kYuvConstants]
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void OMITFP I422ToRGBARow_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_rgba,
- int width) {
- asm volatile (
- "sub %[u_buf],%[v_buf] \n"
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "pxor %%xmm4,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- READYUV422
- YUVTORGB
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "punpcklbw %%xmm2,%%xmm1 \n"
- "punpcklbw %%xmm0,%%xmm5 \n"
- "movdqa %%xmm5,%%xmm0 \n"
- "punpcklwd %%xmm1,%%xmm5 \n"
- "punpckhwd %%xmm1,%%xmm0 \n"
- "movdqa %%xmm5," MEMACCESS([dst_rgba]) "\n"
- "movdqa %%xmm0," MEMACCESS2(0x10,[dst_rgba]) "\n"
- "lea " MEMLEA(0x20,[dst_rgba]) ",%[dst_rgba] \n"
- "sub $0x8,%[width] \n"
- "jg 1b \n"
- : [y_buf]"+r"(y_buf), // %[y_buf]
- [u_buf]"+r"(u_buf), // %[u_buf]
- [v_buf]"+r"(v_buf), // %[v_buf]
- [dst_rgba]"+r"(dst_rgba), // %[dst_rgba]
- [width]"+rm"(width) // %[width]
- : [kYuvConstants]"r"(&kYuvConstants.kUVToB) // %[kYuvConstants]
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void OMITFP I422ToBGRARow_Unaligned_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_bgra,
- int width) {
- asm volatile (
- "sub %[u_buf],%[v_buf] \n"
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "pxor %%xmm4,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- READYUV422
- YUVTORGB
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "punpcklbw %%xmm0,%%xmm1 \n"
- "punpcklbw %%xmm2,%%xmm5 \n"
- "movdqa %%xmm5,%%xmm0 \n"
- "punpcklwd %%xmm1,%%xmm5 \n"
- "punpckhwd %%xmm1,%%xmm0 \n"
- "movdqu %%xmm5," MEMACCESS([dst_bgra]) "\n"
- "movdqu %%xmm0," MEMACCESS2(0x10,[dst_bgra]) "\n"
- "lea " MEMLEA(0x20,[dst_bgra]) ",%[dst_bgra] \n"
- "sub $0x8,%[width] \n"
- "jg 1b \n"
- : [y_buf]"+r"(y_buf), // %[y_buf]
- [u_buf]"+r"(u_buf), // %[u_buf]
- [v_buf]"+r"(v_buf), // %[v_buf]
- [dst_bgra]"+r"(dst_bgra), // %[dst_bgra]
- [width]"+rm"(width) // %[width]
- : [kYuvConstants]"r"(&kYuvConstants.kUVToB) // %[kYuvConstants]
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void OMITFP I422ToABGRRow_Unaligned_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_abgr,
- int width) {
- asm volatile (
- "sub %[u_buf],%[v_buf] \n"
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "pxor %%xmm4,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- READYUV422
- YUVTORGB
- "punpcklbw %%xmm1,%%xmm2 \n"
- "punpcklbw %%xmm5,%%xmm0 \n"
- "movdqa %%xmm2,%%xmm1 \n"
- "punpcklwd %%xmm0,%%xmm2 \n"
- "punpckhwd %%xmm0,%%xmm1 \n"
- "movdqu %%xmm2," MEMACCESS([dst_abgr]) "\n"
- "movdqu %%xmm1," MEMACCESS2(0x10,[dst_abgr]) "\n"
- "lea " MEMLEA(0x20,[dst_abgr]) ",%[dst_abgr] \n"
- "sub $0x8,%[width] \n"
- "jg 1b \n"
- : [y_buf]"+r"(y_buf), // %[y_buf]
- [u_buf]"+r"(u_buf), // %[u_buf]
- [v_buf]"+r"(v_buf), // %[v_buf]
- [dst_abgr]"+r"(dst_abgr), // %[dst_abgr]
- [width]"+rm"(width) // %[width]
- : [kYuvConstants]"r"(&kYuvConstants.kUVToB) // %[kYuvConstants]
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void OMITFP I422ToRGBARow_Unaligned_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_rgba,
- int width) {
- asm volatile (
- "sub %[u_buf],%[v_buf] \n"
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "pxor %%xmm4,%%xmm4 \n"
- LABELALIGN
- "1: \n"
- READYUV422
- YUVTORGB
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "punpcklbw %%xmm2,%%xmm1 \n"
- "punpcklbw %%xmm0,%%xmm5 \n"
- "movdqa %%xmm5,%%xmm0 \n"
- "punpcklwd %%xmm1,%%xmm5 \n"
- "punpckhwd %%xmm1,%%xmm0 \n"
- "movdqu %%xmm5," MEMACCESS([dst_rgba]) "\n"
- "movdqu %%xmm0," MEMACCESS2(0x10,[dst_rgba]) "\n"
- "lea " MEMLEA(0x20,[dst_rgba]) ",%[dst_rgba] \n"
- "sub $0x8,%[width] \n"
- "jg 1b \n"
- : [y_buf]"+r"(y_buf), // %[y_buf]
- [u_buf]"+r"(u_buf), // %[u_buf]
- [v_buf]"+r"(v_buf), // %[v_buf]
- [dst_rgba]"+r"(dst_rgba), // %[dst_rgba]
- [width]"+rm"(width) // %[width]
- : [kYuvConstants]"r"(&kYuvConstants.kUVToB) // %[kYuvConstants]
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-#endif // HAS_I422TOARGBROW_SSSE3
-
-#ifdef HAS_YTOARGBROW_SSE2
-void YToARGBRow_SSE2(const uint8* y_buf,
- uint8* dst_argb,
- int width) {
- asm volatile (
- "pxor %%xmm5,%%xmm5 \n"
- "pcmpeqb %%xmm4,%%xmm4 \n"
- "pslld $0x18,%%xmm4 \n"
- "mov $0x00100010,%%eax \n"
- "movd %%eax,%%xmm3 \n"
- "pshufd $0x0,%%xmm3,%%xmm3 \n"
- "mov $0x004a004a,%%eax \n"
- "movd %%eax,%%xmm2 \n"
- "pshufd $0x0,%%xmm2,%%xmm2 \n"
- LABELALIGN
- "1: \n"
- // Step 1: Scale Y contribution to 8 G values. G = (y - 16) * 1.164
- "movq " MEMACCESS(0) ",%%xmm0 \n"
- "lea " MEMLEA(0x8,0) ",%0 \n"
- "punpcklbw %%xmm5,%%xmm0 \n"
- "psubusw %%xmm3,%%xmm0 \n"
- "pmullw %%xmm2,%%xmm0 \n"
- "psrlw $6, %%xmm0 \n"
- "packuswb %%xmm0,%%xmm0 \n"
-
- // Step 2: Weave into ARGB
- "punpcklbw %%xmm0,%%xmm0 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "punpcklwd %%xmm0,%%xmm0 \n"
- "punpckhwd %%xmm1,%%xmm1 \n"
- "por %%xmm4,%%xmm0 \n"
- "por %%xmm4,%%xmm1 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "movdqa %%xmm1," MEMACCESS2(0x10,1) " \n"
- "lea " MEMLEA(0x20,1) ",%1 \n"
-
- "sub $0x8,%2 \n"
- "jg 1b \n"
- : "+r"(y_buf), // %0
- "+r"(dst_argb), // %1
- "+rm"(width) // %2
- :
- : "memory", "cc", "eax"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4"
-#endif
- );
-}
-#endif // HAS_YTOARGBROW_SSE2
-
-#ifdef HAS_MIRRORROW_SSSE3
-// Shuffle table for reversing the bytes.
-static uvec8 kShuffleMirror = {
- 15u, 14u, 13u, 12u, 11u, 10u, 9u, 8u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u
-};
-
-void MirrorRow_SSSE3(const uint8* src, uint8* dst, int width) {
- intptr_t temp_width = (intptr_t)(width);
- asm volatile (
- "movdqa %3,%%xmm5 \n"
- "lea " MEMLEA(-0x10,0) ",%0 \n"
- LABELALIGN
- "1: \n"
- MEMOPREG(movdqa,0x00,0,2,1,xmm0) // movdqa (%0,%2),%%xmm0
- "pshufb %%xmm5,%%xmm0 \n"
- "sub $0x10,%2 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src), // %0
- "+r"(dst), // %1
- "+r"(temp_width) // %2
- : "m"(kShuffleMirror) // %3
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm5"
-#endif
- );
-}
-#endif // HAS_MIRRORROW_SSSE3
-
-#ifdef HAS_MIRRORROW_SSE2
-void MirrorRow_SSE2(const uint8* src, uint8* dst, int width) {
- intptr_t temp_width = (intptr_t)(width);
- asm volatile (
- "lea " MEMLEA(-0x10,0) ",%0 \n"
- LABELALIGN
- "1: \n"
- MEMOPREG(movdqu,0x00,0,2,1,xmm0) // movdqu (%0,%2),%%xmm0
- "movdqa %%xmm0,%%xmm1 \n"
- "psllw $0x8,%%xmm0 \n"
- "psrlw $0x8,%%xmm1 \n"
- "por %%xmm1,%%xmm0 \n"
- "pshuflw $0x1b,%%xmm0,%%xmm0 \n"
- "pshufhw $0x1b,%%xmm0,%%xmm0 \n"
- "pshufd $0x4e,%%xmm0,%%xmm0 \n"
- "sub $0x10,%2 \n"
- "movdqu %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1)",%1 \n"
- "jg 1b \n"
- : "+r"(src), // %0
- "+r"(dst), // %1
- "+r"(temp_width) // %2
- :
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1"
-#endif
- );
-}
-#endif // HAS_MIRRORROW_SSE2
-
-#ifdef HAS_MIRRORROW_UV_SSSE3
-// Shuffle table for reversing the bytes of UV channels.
-static uvec8 kShuffleMirrorUV = {
- 14u, 12u, 10u, 8u, 6u, 4u, 2u, 0u, 15u, 13u, 11u, 9u, 7u, 5u, 3u, 1u
-};
-void MirrorUVRow_SSSE3(const uint8* src, uint8* dst_u, uint8* dst_v,
- int width) {
- intptr_t temp_width = (intptr_t)(width);
- asm volatile (
- "movdqa %4,%%xmm1 \n"
- "lea " MEMLEA4(-0x10,0,3,2) ",%0 \n"
- "sub %1,%2 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "lea " MEMLEA(-0x10,0) ",%0 \n"
- "pshufb %%xmm1,%%xmm0 \n"
- "sub $8,%3 \n"
- "movlpd %%xmm0," MEMACCESS(1) " \n"
- BUNDLEALIGN
- MEMOPMEM(movhpd,xmm0,0x00,1,2,1) // movhpd %%xmm0,(%1,%2)
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+r"(temp_width) // %3
- : "m"(kShuffleMirrorUV) // %4
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1"
-#endif
- );
-}
-#endif // HAS_MIRRORROW_UV_SSSE3
-
-#ifdef HAS_ARGBMIRRORROW_SSSE3
-// Shuffle table for reversing the bytes.
-static uvec8 kARGBShuffleMirror = {
- 12u, 13u, 14u, 15u, 8u, 9u, 10u, 11u, 4u, 5u, 6u, 7u, 0u, 1u, 2u, 3u
-};
-
-void ARGBMirrorRow_SSSE3(const uint8* src, uint8* dst, int width) {
- intptr_t temp_width = (intptr_t)(width);
- asm volatile (
- "lea " MEMLEA4(-0x10,0,2,4) ",%0 \n"
- "movdqa %3,%%xmm5 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "pshufb %%xmm5,%%xmm0 \n"
- "lea " MEMLEA(-0x10,0) ",%0 \n"
- "sub $0x4,%2 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src), // %0
- "+r"(dst), // %1
- "+r"(temp_width) // %2
- : "m"(kARGBShuffleMirror) // %3
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm5"
-#endif
- );
-}
-#endif // HAS_ARGBMIRRORROW_SSSE3
-
-#ifdef HAS_SPLITUVROW_SSE2
-void SplitUVRow_SSE2(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int pix) {
- asm volatile (
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "psrlw $0x8,%%xmm5 \n"
- "sub %1,%2 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "movdqa %%xmm0,%%xmm2 \n"
- "movdqa %%xmm1,%%xmm3 \n"
- "pand %%xmm5,%%xmm0 \n"
- "pand %%xmm5,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "psrlw $0x8,%%xmm2 \n"
- "psrlw $0x8,%%xmm3 \n"
- "packuswb %%xmm3,%%xmm2 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- MEMOPMEM(movdqa,xmm2,0x00,1,2,1) // movdqa %%xmm2,(%1,%2)
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "sub $0x10,%3 \n"
- "jg 1b \n"
- : "+r"(src_uv), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+r"(pix) // %3
- :
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"
-#endif
- );
-}
-
-void SplitUVRow_Unaligned_SSE2(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
- int pix) {
- asm volatile (
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "psrlw $0x8,%%xmm5 \n"
- "sub %1,%2 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "movdqa %%xmm0,%%xmm2 \n"
- "movdqa %%xmm1,%%xmm3 \n"
- "pand %%xmm5,%%xmm0 \n"
- "pand %%xmm5,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "psrlw $0x8,%%xmm2 \n"
- "psrlw $0x8,%%xmm3 \n"
- "packuswb %%xmm3,%%xmm2 \n"
- "movdqu %%xmm0," MEMACCESS(1) " \n"
- MEMOPMEM(movdqu,xmm2,0x00,1,2,1) // movdqu %%xmm2,(%1,%2)
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "sub $0x10,%3 \n"
- "jg 1b \n"
- : "+r"(src_uv), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+r"(pix) // %3
- :
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"
-#endif
- );
-}
-#endif // HAS_SPLITUVROW_SSE2
-
-#ifdef HAS_MERGEUVROW_SSE2
-void MergeUVRow_SSE2(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
- int width) {
- asm volatile (
- "sub %0,%1 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- MEMOPREG(movdqa,0x00,0,1,1,xmm1) // movdqa (%0,%1,1),%%xmm1
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "movdqa %%xmm0,%%xmm2 \n"
- "punpcklbw %%xmm1,%%xmm0 \n"
- "punpckhbw %%xmm1,%%xmm2 \n"
- "movdqa %%xmm0," MEMACCESS(2) " \n"
- "movdqa %%xmm2," MEMACCESS2(0x10,2) " \n"
- "lea " MEMLEA(0x20,2) ",%2 \n"
- "sub $0x10,%3 \n"
- "jg 1b \n"
- : "+r"(src_u), // %0
- "+r"(src_v), // %1
- "+r"(dst_uv), // %2
- "+r"(width) // %3
- :
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2"
-#endif
- );
-}
-
-void MergeUVRow_Unaligned_SSE2(const uint8* src_u, const uint8* src_v,
- uint8* dst_uv, int width) {
- asm volatile (
- "sub %0,%1 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- MEMOPREG(movdqu,0x00,0,1,1,xmm1) // movdqu (%0,%1,1),%%xmm1
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "movdqa %%xmm0,%%xmm2 \n"
- "punpcklbw %%xmm1,%%xmm0 \n"
- "punpckhbw %%xmm1,%%xmm2 \n"
- "movdqu %%xmm0," MEMACCESS(2) " \n"
- "movdqu %%xmm2," MEMACCESS2(0x10,2) " \n"
- "lea " MEMLEA(0x20,2) ",%2 \n"
- "sub $0x10,%3 \n"
- "jg 1b \n"
- : "+r"(src_u), // %0
- "+r"(src_v), // %1
- "+r"(dst_uv), // %2
- "+r"(width) // %3
- :
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2"
-#endif
- );
-}
-#endif // HAS_MERGEUVROW_SSE2
-
-#ifdef HAS_COPYROW_SSE2
-void CopyRow_SSE2(const uint8* src, uint8* dst, int count) {
- asm volatile (
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "movdqa %%xmm1," MEMACCESS2(0x10,1) " \n"
- "lea " MEMLEA(0x20,1) ",%1 \n"
- "sub $0x20,%2 \n"
- "jg 1b \n"
- : "+r"(src), // %0
- "+r"(dst), // %1
- "+r"(count) // %2
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1"
-#endif
- );
-}
-#endif // HAS_COPYROW_SSE2
-
-#ifdef HAS_COPYROW_X86
-void CopyRow_X86(const uint8* src, uint8* dst, int width) {
- size_t width_tmp = (size_t)(width);
- asm volatile (
- "shr $0x2,%2 \n"
- "rep movsl " MEMMOVESTRING(0,1) " \n"
- : "+S"(src), // %0
- "+D"(dst), // %1
- "+c"(width_tmp) // %2
- :
- : "memory", "cc"
- );
-}
-#endif // HAS_COPYROW_X86
-
-#ifdef HAS_COPYROW_ERMS
-// Unaligned Multiple of 1.
-void CopyRow_ERMS(const uint8* src, uint8* dst, int width) {
- size_t width_tmp = (size_t)(width);
- asm volatile (
- "rep movsb " MEMMOVESTRING(0,1) " \n"
- : "+S"(src), // %0
- "+D"(dst), // %1
- "+c"(width_tmp) // %2
- :
- : "memory", "cc"
- );
-}
-#endif // HAS_COPYROW_ERMS
-
-#ifdef HAS_ARGBCOPYALPHAROW_SSE2
-// width in pixels
-void ARGBCopyAlphaRow_SSE2(const uint8* src, uint8* dst, int width) {
- asm volatile (
- "pcmpeqb %%xmm0,%%xmm0 \n"
- "pslld $0x18,%%xmm0 \n"
- "pcmpeqb %%xmm1,%%xmm1 \n"
- "psrld $0x8,%%xmm1 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm2 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm3 \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "movdqa " MEMACCESS(1) ",%%xmm4 \n"
- "movdqa " MEMACCESS2(0x10,1) ",%%xmm5 \n"
- "pand %%xmm0,%%xmm2 \n"
- "pand %%xmm0,%%xmm3 \n"
- "pand %%xmm1,%%xmm4 \n"
- "pand %%xmm1,%%xmm5 \n"
- "por %%xmm4,%%xmm2 \n"
- "por %%xmm5,%%xmm3 \n"
- "movdqa %%xmm2," MEMACCESS(1) " \n"
- "movdqa %%xmm3," MEMACCESS2(0x10,1) " \n"
- "lea " MEMLEA(0x20,1) ",%1 \n"
- "sub $0x8,%2 \n"
- "jg 1b \n"
- : "+r"(src), // %0
- "+r"(dst), // %1
- "+r"(width) // %2
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-#endif // HAS_ARGBCOPYALPHAROW_SSE2
-
-#ifdef HAS_ARGBCOPYALPHAROW_AVX2
-// width in pixels
-void ARGBCopyAlphaRow_AVX2(const uint8* src, uint8* dst, int width) {
- asm volatile (
- "vpcmpeqb %%ymm0,%%ymm0,%%ymm0 \n"
- "vpsrld $0x8,%%ymm0,%%ymm0 \n"
- LABELALIGN
- "1: \n"
- "vmovdqu " MEMACCESS(0) ",%%ymm1 \n"
- "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm2 \n"
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "vpblendvb %%ymm0," MEMACCESS(1) ",%%ymm1,%%ymm1 \n"
- "vpblendvb %%ymm0," MEMACCESS2(0x20,1) ",%%ymm2,%%ymm2 \n"
- "vmovdqu %%ymm1," MEMACCESS(1) " \n"
- "vmovdqu %%ymm2," MEMACCESS2(0x20,1) " \n"
- "lea " MEMLEA(0x40,1) ",%1 \n"
- "sub $0x10,%2 \n"
- "jg 1b \n"
- "vzeroupper \n"
- : "+r"(src), // %0
- "+r"(dst), // %1
- "+r"(width) // %2
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2"
-#endif
- );
-}
-#endif // HAS_ARGBCOPYALPHAROW_AVX2
-
-#ifdef HAS_ARGBCOPYYTOALPHAROW_SSE2
-// width in pixels
-void ARGBCopyYToAlphaRow_SSE2(const uint8* src, uint8* dst, int width) {
- asm volatile (
- "pcmpeqb %%xmm0,%%xmm0 \n"
- "pslld $0x18,%%xmm0 \n"
- "pcmpeqb %%xmm1,%%xmm1 \n"
- "psrld $0x8,%%xmm1 \n"
- LABELALIGN
- "1: \n"
- "movq " MEMACCESS(0) ",%%xmm2 \n"
- "lea " MEMLEA(0x8,0) ",%0 \n"
- "punpcklbw %%xmm2,%%xmm2 \n"
- "punpckhwd %%xmm2,%%xmm3 \n"
- "punpcklwd %%xmm2,%%xmm2 \n"
- "movdqa " MEMACCESS(1) ",%%xmm4 \n"
- "movdqa " MEMACCESS2(0x10,1) ",%%xmm5 \n"
- "pand %%xmm0,%%xmm2 \n"
- "pand %%xmm0,%%xmm3 \n"
- "pand %%xmm1,%%xmm4 \n"
- "pand %%xmm1,%%xmm5 \n"
- "por %%xmm4,%%xmm2 \n"
- "por %%xmm5,%%xmm3 \n"
- "movdqa %%xmm2," MEMACCESS(1) " \n"
- "movdqa %%xmm3," MEMACCESS2(0x10,1) " \n"
- "lea " MEMLEA(0x20,1) ",%1 \n"
- "sub $0x8,%2 \n"
- "jg 1b \n"
- : "+r"(src), // %0
- "+r"(dst), // %1
- "+r"(width) // %2
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-#endif // HAS_ARGBCOPYYTOALPHAROW_SSE2
-
-#ifdef HAS_ARGBCOPYYTOALPHAROW_AVX2
-// width in pixels
-void ARGBCopyYToAlphaRow_AVX2(const uint8* src, uint8* dst, int width) {
- asm volatile (
- "vpcmpeqb %%ymm0,%%ymm0,%%ymm0 \n"
- "vpsrld $0x8,%%ymm0,%%ymm0 \n"
- LABELALIGN
- "1: \n"
- "vpmovzxbd " MEMACCESS(0) ",%%ymm1 \n"
- "vpmovzxbd " MEMACCESS2(0x8,0) ",%%ymm2 \n"
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "vpslld $0x18,%%ymm1,%%ymm1 \n"
- "vpslld $0x18,%%ymm2,%%ymm2 \n"
- "vpblendvb %%ymm0," MEMACCESS(1) ",%%ymm1,%%ymm1 \n"
- "vpblendvb %%ymm0," MEMACCESS2(0x20,1) ",%%ymm2,%%ymm2 \n"
- "vmovdqu %%ymm1," MEMACCESS(1) " \n"
- "vmovdqu %%ymm2," MEMACCESS2(0x20,1) " \n"
- "lea " MEMLEA(0x40,1) ",%1 \n"
- "sub $0x10,%2 \n"
- "jg 1b \n"
- "vzeroupper \n"
- : "+r"(src), // %0
- "+r"(dst), // %1
- "+r"(width) // %2
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2"
-#endif
- );
-}
-#endif // HAS_ARGBCOPYYTOALPHAROW_AVX2
-
-#ifdef HAS_SETROW_X86
-void SetRow_X86(uint8* dst, uint32 v32, int width) {
- size_t width_tmp = (size_t)(width);
- asm volatile (
- "shr $0x2,%1 \n"
- "rep stosl " MEMSTORESTRING(eax,0) " \n"
- : "+D"(dst), // %0
- "+c"(width_tmp) // %1
- : "a"(v32) // %2
- : "memory", "cc");
-}
-
-void ARGBSetRows_X86(uint8* dst, uint32 v32, int width,
- int dst_stride, int height) {
- for (int y = 0; y < height; ++y) {
- size_t width_tmp = (size_t)(width);
- uint32* d = (uint32*)(dst);
- asm volatile (
- "rep stosl " MEMSTORESTRING(eax,0) " \n"
- : "+D"(d), // %0
- "+c"(width_tmp) // %1
- : "a"(v32) // %2
- : "memory", "cc");
- dst += dst_stride;
- }
-}
-#endif // HAS_SETROW_X86
-
-#ifdef HAS_YUY2TOYROW_SSE2
-void YUY2ToYRow_SSE2(const uint8* src_yuy2, uint8* dst_y, int pix) {
- asm volatile (
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "psrlw $0x8,%%xmm5 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "pand %%xmm5,%%xmm0 \n"
- "pand %%xmm5,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "sub $0x10,%2 \n"
- "jg 1b \n"
- : "+r"(src_yuy2), // %0
- "+r"(dst_y), // %1
- "+r"(pix) // %2
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm5"
-#endif
- );
-}
-
-void YUY2ToUVRow_SSE2(const uint8* src_yuy2, int stride_yuy2,
- uint8* dst_u, uint8* dst_v, int pix) {
- asm volatile (
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "psrlw $0x8,%%xmm5 \n"
- "sub %1,%2 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- BUNDLEALIGN
- MEMOPREG(movdqa,0x00,0,4,1,xmm2) // movdqa (%0,%4,1),%%xmm2
- MEMOPREG(movdqa,0x10,0,4,1,xmm3) // movdqa 0x10(%0,%4,1),%%xmm3
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "pavgb %%xmm2,%%xmm0 \n"
- "pavgb %%xmm3,%%xmm1 \n"
- "psrlw $0x8,%%xmm0 \n"
- "psrlw $0x8,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "pand %%xmm5,%%xmm0 \n"
- "packuswb %%xmm0,%%xmm0 \n"
- "psrlw $0x8,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm1 \n"
- "movq %%xmm0," MEMACCESS(1) " \n"
- BUNDLEALIGN
- MEMOPMEM(movq,xmm1,0x00,1,2,1) // movq %%xmm1,(%1,%2)
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "sub $0x10,%3 \n"
- "jg 1b \n"
- : "+r"(src_yuy2), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+r"(pix) // %3
- : "r"((intptr_t)(stride_yuy2)) // %4
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"
-#endif
- );
-}
-
-void YUY2ToUV422Row_SSE2(const uint8* src_yuy2,
- uint8* dst_u, uint8* dst_v, int pix) {
- asm volatile (
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "psrlw $0x8,%%xmm5 \n"
- "sub %1,%2 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "psrlw $0x8,%%xmm0 \n"
- "psrlw $0x8,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "pand %%xmm5,%%xmm0 \n"
- "packuswb %%xmm0,%%xmm0 \n"
- "psrlw $0x8,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm1 \n"
- "movq %%xmm0," MEMACCESS(1) " \n"
- BUNDLEALIGN
- MEMOPMEM(movq,xmm1,0x00,1,2,1) // movq %%xmm1,(%1,%2)
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "sub $0x10,%3 \n"
- "jg 1b \n"
- : "+r"(src_yuy2), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+r"(pix) // %3
- :
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm5"
-#endif
- );
-}
-
-void YUY2ToYRow_Unaligned_SSE2(const uint8* src_yuy2,
- uint8* dst_y, int pix) {
- asm volatile (
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "psrlw $0x8,%%xmm5 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "pand %%xmm5,%%xmm0 \n"
- "pand %%xmm5,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "sub $0x10,%2 \n"
- "movdqu %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_yuy2), // %0
- "+r"(dst_y), // %1
- "+r"(pix) // %2
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm5"
-#endif
- );
-}
-
-void YUY2ToUVRow_Unaligned_SSE2(const uint8* src_yuy2,
- int stride_yuy2,
- uint8* dst_u, uint8* dst_v, int pix) {
- asm volatile (
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "psrlw $0x8,%%xmm5 \n"
- "sub %1,%2 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- BUNDLEALIGN
- MEMOPREG(movdqu,0x00,0,4,1,xmm2) // movdqu (%0,%4,1),%%xmm2
- MEMOPREG(movdqu,0x10,0,4,1,xmm3) // movdqu 0x10(%0,%4,1),%%xmm3
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "pavgb %%xmm2,%%xmm0 \n"
- "pavgb %%xmm3,%%xmm1 \n"
- "psrlw $0x8,%%xmm0 \n"
- "psrlw $0x8,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "pand %%xmm5,%%xmm0 \n"
- "packuswb %%xmm0,%%xmm0 \n"
- "psrlw $0x8,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm1 \n"
- "movq %%xmm0," MEMACCESS(1) " \n"
- BUNDLEALIGN
- MEMOPMEM(movq,xmm1,0x00,1,2,1) // movq %%xmm1,(%1,%2)
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "sub $0x10,%3 \n"
- "jg 1b \n"
- : "+r"(src_yuy2), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+r"(pix) // %3
- : "r"((intptr_t)(stride_yuy2)) // %4
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"
-#endif
- );
-}
-
-void YUY2ToUV422Row_Unaligned_SSE2(const uint8* src_yuy2,
- uint8* dst_u, uint8* dst_v, int pix) {
- asm volatile (
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "psrlw $0x8,%%xmm5 \n"
- "sub %1,%2 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "psrlw $0x8,%%xmm0 \n"
- "psrlw $0x8,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "pand %%xmm5,%%xmm0 \n"
- "packuswb %%xmm0,%%xmm0 \n"
- "psrlw $0x8,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm1 \n"
- "movq %%xmm0," MEMACCESS(1) " \n"
- BUNDLEALIGN
- MEMOPMEM(movq,xmm1,0x00,1,2,1) // movq %%xmm1,(%1,%2)
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "sub $0x10,%3 \n"
- "jg 1b \n"
- : "+r"(src_yuy2), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+r"(pix) // %3
- :
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm5"
-#endif
- );
-}
-
-void UYVYToYRow_SSE2(const uint8* src_uyvy, uint8* dst_y, int pix) {
- asm volatile (
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "psrlw $0x8,%%xmm0 \n"
- "psrlw $0x8,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "sub $0x10,%2 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_uyvy), // %0
- "+r"(dst_y), // %1
- "+r"(pix) // %2
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1"
-#endif
- );
-}
-
-void UYVYToUVRow_SSE2(const uint8* src_uyvy, int stride_uyvy,
- uint8* dst_u, uint8* dst_v, int pix) {
- asm volatile (
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "psrlw $0x8,%%xmm5 \n"
- "sub %1,%2 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- BUNDLEALIGN
- MEMOPREG(movdqa,0x00,0,4,1,xmm2) // movdqa (%0,%4,1),%%xmm2
- MEMOPREG(movdqa,0x10,0,4,1,xmm3) // movdqa 0x10(%0,%4,1),%%xmm3
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "pavgb %%xmm2,%%xmm0 \n"
- "pavgb %%xmm3,%%xmm1 \n"
- "pand %%xmm5,%%xmm0 \n"
- "pand %%xmm5,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "pand %%xmm5,%%xmm0 \n"
- "packuswb %%xmm0,%%xmm0 \n"
- "psrlw $0x8,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm1 \n"
- "movq %%xmm0," MEMACCESS(1) " \n"
- BUNDLEALIGN
- MEMOPMEM(movq,xmm1,0x00,1,2,1) // movq %%xmm1,(%1,%2)
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "sub $0x10,%3 \n"
- "jg 1b \n"
- : "+r"(src_uyvy), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+r"(pix) // %3
- : "r"((intptr_t)(stride_uyvy)) // %4
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"
-#endif
- );
-}
-
-void UYVYToUV422Row_SSE2(const uint8* src_uyvy,
- uint8* dst_u, uint8* dst_v, int pix) {
- asm volatile (
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "psrlw $0x8,%%xmm5 \n"
- "sub %1,%2 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "pand %%xmm5,%%xmm0 \n"
- "pand %%xmm5,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "pand %%xmm5,%%xmm0 \n"
- "packuswb %%xmm0,%%xmm0 \n"
- "psrlw $0x8,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm1 \n"
- "movq %%xmm0," MEMACCESS(1) " \n"
- BUNDLEALIGN
- MEMOPMEM(movq,xmm1,0x00,1,2,1) // movq %%xmm1,(%1,%2)
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "sub $0x10,%3 \n"
- "jg 1b \n"
- : "+r"(src_uyvy), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+r"(pix) // %3
- :
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm5"
-#endif
- );
-}
-
-void UYVYToYRow_Unaligned_SSE2(const uint8* src_uyvy,
- uint8* dst_y, int pix) {
- asm volatile (
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "psrlw $0x8,%%xmm0 \n"
- "psrlw $0x8,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "sub $0x10,%2 \n"
- "movdqu %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_uyvy), // %0
- "+r"(dst_y), // %1
- "+r"(pix) // %2
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1"
-#endif
- );
-}
-
-void UYVYToUVRow_Unaligned_SSE2(const uint8* src_uyvy, int stride_uyvy,
- uint8* dst_u, uint8* dst_v, int pix) {
- asm volatile (
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "psrlw $0x8,%%xmm5 \n"
- "sub %1,%2 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- BUNDLEALIGN
- MEMOPREG(movdqu,0x00,0,4,1,xmm2) // movdqu (%0,%4,1),%%xmm2
- MEMOPREG(movdqu,0x10,0,4,1,xmm3) // movdqu 0x10(%0,%4,1),%%xmm3
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "pavgb %%xmm2,%%xmm0 \n"
- "pavgb %%xmm3,%%xmm1 \n"
- "pand %%xmm5,%%xmm0 \n"
- "pand %%xmm5,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "pand %%xmm5,%%xmm0 \n"
- "packuswb %%xmm0,%%xmm0 \n"
- "psrlw $0x8,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm1 \n"
- "movq %%xmm0," MEMACCESS(1) " \n"
- BUNDLEALIGN
- MEMOPMEM(movq,xmm1,0x00,1,2,1) // movq %%xmm1,(%1,%2)
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "sub $0x10,%3 \n"
- "jg 1b \n"
- : "+r"(src_uyvy), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+r"(pix) // %3
- : "r"((intptr_t)(stride_uyvy)) // %4
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"
-#endif
- );
-}
-
-void UYVYToUV422Row_Unaligned_SSE2(const uint8* src_uyvy,
- uint8* dst_u, uint8* dst_v, int pix) {
- asm volatile (
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "psrlw $0x8,%%xmm5 \n"
- "sub %1,%2 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "pand %%xmm5,%%xmm0 \n"
- "pand %%xmm5,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "pand %%xmm5,%%xmm0 \n"
- "packuswb %%xmm0,%%xmm0 \n"
- "psrlw $0x8,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm1 \n"
- "movq %%xmm0," MEMACCESS(1) " \n"
- BUNDLEALIGN
- MEMOPMEM(movq,xmm1,0x00,1,2,1) // movq %%xmm1,(%1,%2)
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "sub $0x10,%3 \n"
- "jg 1b \n"
- : "+r"(src_uyvy), // %0
- "+r"(dst_u), // %1
- "+r"(dst_v), // %2
- "+r"(pix) // %3
- :
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm5"
-#endif
- );
-}
-#endif // HAS_YUY2TOYROW_SSE2
-
-#ifdef HAS_ARGBBLENDROW_SSE2
-// Blend 8 pixels at a time.
-void ARGBBlendRow_SSE2(const uint8* src_argb0, const uint8* src_argb1,
- uint8* dst_argb, int width) {
- asm volatile (
- "pcmpeqb %%xmm7,%%xmm7 \n"
- "psrlw $0xf,%%xmm7 \n"
- "pcmpeqb %%xmm6,%%xmm6 \n"
- "psrlw $0x8,%%xmm6 \n"
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "psllw $0x8,%%xmm5 \n"
- "pcmpeqb %%xmm4,%%xmm4 \n"
- "pslld $0x18,%%xmm4 \n"
- "sub $0x1,%3 \n"
- "je 91f \n"
- "jl 99f \n"
-
- // 1 pixel loop until destination pointer is aligned.
- "10: \n"
- "test $0xf,%2 \n"
- "je 19f \n"
- "movd " MEMACCESS(0) ",%%xmm3 \n"
- "lea " MEMLEA(0x4,0) ",%0 \n"
- "movdqa %%xmm3,%%xmm0 \n"
- "pxor %%xmm4,%%xmm3 \n"
- "movd " MEMACCESS(1) ",%%xmm2 \n"
- "psrlw $0x8,%%xmm3 \n"
- "pshufhw $0xf5,%%xmm3,%%xmm3 \n"
- "pshuflw $0xf5,%%xmm3,%%xmm3 \n"
- "pand %%xmm6,%%xmm2 \n"
- "paddw %%xmm7,%%xmm3 \n"
- "pmullw %%xmm3,%%xmm2 \n"
- "movd " MEMACCESS(1) ",%%xmm1 \n"
- "lea " MEMLEA(0x4,1) ",%1 \n"
- "psrlw $0x8,%%xmm1 \n"
- "por %%xmm4,%%xmm0 \n"
- "pmullw %%xmm3,%%xmm1 \n"
- "psrlw $0x8,%%xmm2 \n"
- "paddusb %%xmm2,%%xmm0 \n"
- "pand %%xmm5,%%xmm1 \n"
- "paddusb %%xmm1,%%xmm0 \n"
- "sub $0x1,%3 \n"
- "movd %%xmm0," MEMACCESS(2) " \n"
- "lea " MEMLEA(0x4,2) ",%2 \n"
- "jge 10b \n"
-
- "19: \n"
- "add $1-4,%3 \n"
- "jl 49f \n"
-
- // 4 pixel loop.
- LABELALIGN
- "41: \n"
- "movdqu " MEMACCESS(0) ",%%xmm3 \n"
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "movdqa %%xmm3,%%xmm0 \n"
- "pxor %%xmm4,%%xmm3 \n"
- "movdqu " MEMACCESS(1) ",%%xmm2 \n"
- "psrlw $0x8,%%xmm3 \n"
- "pshufhw $0xf5,%%xmm3,%%xmm3 \n"
- "pshuflw $0xf5,%%xmm3,%%xmm3 \n"
- "pand %%xmm6,%%xmm2 \n"
- "paddw %%xmm7,%%xmm3 \n"
- "pmullw %%xmm3,%%xmm2 \n"
- "movdqu " MEMACCESS(1) ",%%xmm1 \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "psrlw $0x8,%%xmm1 \n"
- "por %%xmm4,%%xmm0 \n"
- "pmullw %%xmm3,%%xmm1 \n"
- "psrlw $0x8,%%xmm2 \n"
- "paddusb %%xmm2,%%xmm0 \n"
- "pand %%xmm5,%%xmm1 \n"
- "paddusb %%xmm1,%%xmm0 \n"
- "sub $0x4,%3 \n"
- "movdqa %%xmm0," MEMACCESS(2) " \n"
- "lea " MEMLEA(0x10,2) ",%2 \n"
- "jge 41b \n"
-
- "49: \n"
- "add $0x3,%3 \n"
- "jl 99f \n"
-
- // 1 pixel loop.
- "91: \n"
- "movd " MEMACCESS(0) ",%%xmm3 \n"
- "lea " MEMLEA(0x4,0) ",%0 \n"
- "movdqa %%xmm3,%%xmm0 \n"
- "pxor %%xmm4,%%xmm3 \n"
- "movd " MEMACCESS(1) ",%%xmm2 \n"
- "psrlw $0x8,%%xmm3 \n"
- "pshufhw $0xf5,%%xmm3,%%xmm3 \n"
- "pshuflw $0xf5,%%xmm3,%%xmm3 \n"
- "pand %%xmm6,%%xmm2 \n"
- "paddw %%xmm7,%%xmm3 \n"
- "pmullw %%xmm3,%%xmm2 \n"
- "movd " MEMACCESS(1) ",%%xmm1 \n"
- "lea " MEMLEA(0x4,1) ",%1 \n"
- "psrlw $0x8,%%xmm1 \n"
- "por %%xmm4,%%xmm0 \n"
- "pmullw %%xmm3,%%xmm1 \n"
- "psrlw $0x8,%%xmm2 \n"
- "paddusb %%xmm2,%%xmm0 \n"
- "pand %%xmm5,%%xmm1 \n"
- "paddusb %%xmm1,%%xmm0 \n"
- "sub $0x1,%3 \n"
- "movd %%xmm0," MEMACCESS(2) " \n"
- "lea " MEMLEA(0x4,2) ",%2 \n"
- "jge 91b \n"
- "99: \n"
- : "+r"(src_argb0), // %0
- "+r"(src_argb1), // %1
- "+r"(dst_argb), // %2
- "+r"(width) // %3
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
-#endif
- );
-}
-#endif // HAS_ARGBBLENDROW_SSE2
-
-#ifdef HAS_ARGBBLENDROW_SSSE3
-// Shuffle table for isolating alpha.
-static uvec8 kShuffleAlpha = {
- 3u, 0x80, 3u, 0x80, 7u, 0x80, 7u, 0x80,
- 11u, 0x80, 11u, 0x80, 15u, 0x80, 15u, 0x80
-};
-
-// Blend 8 pixels at a time
-// Shuffle table for reversing the bytes.
-
-// Same as SSE2, but replaces
-// psrlw xmm3, 8 // alpha
-// pshufhw xmm3, xmm3,0F5h // 8 alpha words
-// pshuflw xmm3, xmm3,0F5h
-// with..
-// pshufb xmm3, kShuffleAlpha // alpha
-
-void ARGBBlendRow_SSSE3(const uint8* src_argb0, const uint8* src_argb1,
- uint8* dst_argb, int width) {
- asm volatile (
- "pcmpeqb %%xmm7,%%xmm7 \n"
- "psrlw $0xf,%%xmm7 \n"
- "pcmpeqb %%xmm6,%%xmm6 \n"
- "psrlw $0x8,%%xmm6 \n"
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "psllw $0x8,%%xmm5 \n"
- "pcmpeqb %%xmm4,%%xmm4 \n"
- "pslld $0x18,%%xmm4 \n"
- "sub $0x1,%3 \n"
- "je 91f \n"
- "jl 99f \n"
-
- // 1 pixel loop until destination pointer is aligned.
- "10: \n"
- "test $0xf,%2 \n"
- "je 19f \n"
- "movd " MEMACCESS(0) ",%%xmm3 \n"
- "lea " MEMLEA(0x4,0) ",%0 \n"
- "movdqa %%xmm3,%%xmm0 \n"
- "pxor %%xmm4,%%xmm3 \n"
- "movd " MEMACCESS(1) ",%%xmm2 \n"
- "pshufb %4,%%xmm3 \n"
- "pand %%xmm6,%%xmm2 \n"
- "paddw %%xmm7,%%xmm3 \n"
- "pmullw %%xmm3,%%xmm2 \n"
- "movd " MEMACCESS(1) ",%%xmm1 \n"
- "lea " MEMLEA(0x4,1) ",%1 \n"
- "psrlw $0x8,%%xmm1 \n"
- "por %%xmm4,%%xmm0 \n"
- "pmullw %%xmm3,%%xmm1 \n"
- "psrlw $0x8,%%xmm2 \n"
- "paddusb %%xmm2,%%xmm0 \n"
- "pand %%xmm5,%%xmm1 \n"
- "paddusb %%xmm1,%%xmm0 \n"
- "sub $0x1,%3 \n"
- "movd %%xmm0," MEMACCESS(2) " \n"
- "lea " MEMLEA(0x4,2) ",%2 \n"
- "jge 10b \n"
-
- "19: \n"
- "add $1-4,%3 \n"
- "jl 49f \n"
- "test $0xf,%0 \n"
- "jne 41f \n"
- "test $0xf,%1 \n"
- "jne 41f \n"
-
- // 4 pixel loop.
- LABELALIGN
- "40: \n"
- "movdqa " MEMACCESS(0) ",%%xmm3 \n"
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "movdqa %%xmm3,%%xmm0 \n"
- "pxor %%xmm4,%%xmm3 \n"
- "movdqa " MEMACCESS(1) ",%%xmm2 \n"
- "pshufb %4,%%xmm3 \n"
- "pand %%xmm6,%%xmm2 \n"
- "paddw %%xmm7,%%xmm3 \n"
- "pmullw %%xmm3,%%xmm2 \n"
- "movdqa " MEMACCESS(1) ",%%xmm1 \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "psrlw $0x8,%%xmm1 \n"
- "por %%xmm4,%%xmm0 \n"
- "pmullw %%xmm3,%%xmm1 \n"
- "psrlw $0x8,%%xmm2 \n"
- "paddusb %%xmm2,%%xmm0 \n"
- "pand %%xmm5,%%xmm1 \n"
- "paddusb %%xmm1,%%xmm0 \n"
- "sub $0x4,%3 \n"
- "movdqa %%xmm0," MEMACCESS(2) " \n"
- "lea " MEMLEA(0x10,2) ",%2 \n"
- "jge 40b \n"
- "jmp 49f \n"
-
- // 4 pixel unaligned loop.
- LABELALIGN
- "41: \n"
- "movdqu " MEMACCESS(0) ",%%xmm3 \n"
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "movdqa %%xmm3,%%xmm0 \n"
- "pxor %%xmm4,%%xmm3 \n"
- "movdqu " MEMACCESS(1) ",%%xmm2 \n"
- "pshufb %4,%%xmm3 \n"
- "pand %%xmm6,%%xmm2 \n"
- "paddw %%xmm7,%%xmm3 \n"
- "pmullw %%xmm3,%%xmm2 \n"
- "movdqu " MEMACCESS(1) ",%%xmm1 \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "psrlw $0x8,%%xmm1 \n"
- "por %%xmm4,%%xmm0 \n"
- "pmullw %%xmm3,%%xmm1 \n"
- "psrlw $0x8,%%xmm2 \n"
- "paddusb %%xmm2,%%xmm0 \n"
- "pand %%xmm5,%%xmm1 \n"
- "paddusb %%xmm1,%%xmm0 \n"
- "sub $0x4,%3 \n"
- "movdqa %%xmm0," MEMACCESS(2) " \n"
- "lea " MEMLEA(0x10,2) ",%2 \n"
- "jge 41b \n"
-
- "49: \n"
- "add $0x3,%3 \n"
- "jl 99f \n"
-
- // 1 pixel loop.
- "91: \n"
- "movd " MEMACCESS(0) ",%%xmm3 \n"
- "lea " MEMLEA(0x4,0) ",%0 \n"
- "movdqa %%xmm3,%%xmm0 \n"
- "pxor %%xmm4,%%xmm3 \n"
- "movd " MEMACCESS(1) ",%%xmm2 \n"
- "pshufb %4,%%xmm3 \n"
- "pand %%xmm6,%%xmm2 \n"
- "paddw %%xmm7,%%xmm3 \n"
- "pmullw %%xmm3,%%xmm2 \n"
- "movd " MEMACCESS(1) ",%%xmm1 \n"
- "lea " MEMLEA(0x4,1) ",%1 \n"
- "psrlw $0x8,%%xmm1 \n"
- "por %%xmm4,%%xmm0 \n"
- "pmullw %%xmm3,%%xmm1 \n"
- "psrlw $0x8,%%xmm2 \n"
- "paddusb %%xmm2,%%xmm0 \n"
- "pand %%xmm5,%%xmm1 \n"
- "paddusb %%xmm1,%%xmm0 \n"
- "sub $0x1,%3 \n"
- "movd %%xmm0," MEMACCESS(2) " \n"
- "lea " MEMLEA(0x4,2) ",%2 \n"
- "jge 91b \n"
- "99: \n"
- : "+r"(src_argb0), // %0
- "+r"(src_argb1), // %1
- "+r"(dst_argb), // %2
- "+r"(width) // %3
- : "m"(kShuffleAlpha) // %4
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
-#endif
- );
-}
-#endif // HAS_ARGBBLENDROW_SSSE3
-
-#ifdef HAS_ARGBATTENUATEROW_SSE2
-// Attenuate 4 pixels at a time.
-// aligned to 16 bytes
-void ARGBAttenuateRow_SSE2(const uint8* src_argb, uint8* dst_argb, int width) {
- asm volatile (
- "pcmpeqb %%xmm4,%%xmm4 \n"
- "pslld $0x18,%%xmm4 \n"
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "psrld $0x8,%%xmm5 \n"
-
- // 4 pixel loop.
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "punpcklbw %%xmm0,%%xmm0 \n"
- "pshufhw $0xff,%%xmm0,%%xmm2 \n"
- "pshuflw $0xff,%%xmm2,%%xmm2 \n"
- "pmulhuw %%xmm2,%%xmm0 \n"
- "movdqa " MEMACCESS(0) ",%%xmm1 \n"
- "punpckhbw %%xmm1,%%xmm1 \n"
- "pshufhw $0xff,%%xmm1,%%xmm2 \n"
- "pshuflw $0xff,%%xmm2,%%xmm2 \n"
- "pmulhuw %%xmm2,%%xmm1 \n"
- "movdqa " MEMACCESS(0) ",%%xmm2 \n"
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "psrlw $0x8,%%xmm0 \n"
- "pand %%xmm4,%%xmm2 \n"
- "psrlw $0x8,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "pand %%xmm5,%%xmm0 \n"
- "por %%xmm2,%%xmm0 \n"
- "sub $0x4,%2 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_argb), // %1
- "+r"(width) // %2
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-#endif // HAS_ARGBATTENUATEROW_SSE2
-
-#ifdef HAS_ARGBATTENUATEROW_SSSE3
-// Shuffle table duplicating alpha
-static uvec8 kShuffleAlpha0 = {
- 3u, 3u, 3u, 3u, 3u, 3u, 128u, 128u, 7u, 7u, 7u, 7u, 7u, 7u, 128u, 128u,
-};
-static uvec8 kShuffleAlpha1 = {
- 11u, 11u, 11u, 11u, 11u, 11u, 128u, 128u,
- 15u, 15u, 15u, 15u, 15u, 15u, 128u, 128u,
-};
-// Attenuate 4 pixels at a time.
-// aligned to 16 bytes
-void ARGBAttenuateRow_SSSE3(const uint8* src_argb, uint8* dst_argb, int width) {
- asm volatile (
- "pcmpeqb %%xmm3,%%xmm3 \n"
- "pslld $0x18,%%xmm3 \n"
- "movdqa %3,%%xmm4 \n"
- "movdqa %4,%%xmm5 \n"
-
- // 4 pixel loop.
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "pshufb %%xmm4,%%xmm0 \n"
- "movdqu " MEMACCESS(0) ",%%xmm1 \n"
- "punpcklbw %%xmm1,%%xmm1 \n"
- "pmulhuw %%xmm1,%%xmm0 \n"
- "movdqu " MEMACCESS(0) ",%%xmm1 \n"
- "pshufb %%xmm5,%%xmm1 \n"
- "movdqu " MEMACCESS(0) ",%%xmm2 \n"
- "punpckhbw %%xmm2,%%xmm2 \n"
- "pmulhuw %%xmm2,%%xmm1 \n"
- "movdqu " MEMACCESS(0) ",%%xmm2 \n"
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "pand %%xmm3,%%xmm2 \n"
- "psrlw $0x8,%%xmm0 \n"
- "psrlw $0x8,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "por %%xmm2,%%xmm0 \n"
- "sub $0x4,%2 \n"
- "movdqu %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_argb), // %1
- "+r"(width) // %2
- : "m"(kShuffleAlpha0), // %3
- "m"(kShuffleAlpha1) // %4
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-#endif // HAS_ARGBATTENUATEROW_SSSE3
-
-#ifdef HAS_ARGBUNATTENUATEROW_SSE2
-// Unattenuate 4 pixels at a time.
-// aligned to 16 bytes
-void ARGBUnattenuateRow_SSE2(const uint8* src_argb, uint8* dst_argb,
- int width) {
- uintptr_t alpha = 0;
- asm volatile (
- // 4 pixel loop.
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movzb " MEMACCESS2(0x03,0) ",%3 \n"
- "punpcklbw %%xmm0,%%xmm0 \n"
- MEMOPREG(movd,0x00,4,3,4,xmm2) // movd 0x0(%4,%3,4),%%xmm2
- "movzb " MEMACCESS2(0x07,0) ",%3 \n"
- MEMOPREG(movd,0x00,4,3,4,xmm3) // movd 0x0(%4,%3,4),%%xmm3
- "pshuflw $0x40,%%xmm2,%%xmm2 \n"
- "pshuflw $0x40,%%xmm3,%%xmm3 \n"
- "movlhps %%xmm3,%%xmm2 \n"
- "pmulhuw %%xmm2,%%xmm0 \n"
- "movdqu " MEMACCESS(0) ",%%xmm1 \n"
- "movzb " MEMACCESS2(0x0b,0) ",%3 \n"
- "punpckhbw %%xmm1,%%xmm1 \n"
- BUNDLEALIGN
- MEMOPREG(movd,0x00,4,3,4,xmm2) // movd 0x0(%4,%3,4),%%xmm2
- "movzb " MEMACCESS2(0x0f,0) ",%3 \n"
- MEMOPREG(movd,0x00,4,3,4,xmm3) // movd 0x0(%4,%3,4),%%xmm3
- "pshuflw $0x40,%%xmm2,%%xmm2 \n"
- "pshuflw $0x40,%%xmm3,%%xmm3 \n"
- "movlhps %%xmm3,%%xmm2 \n"
- "pmulhuw %%xmm2,%%xmm1 \n"
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "sub $0x4,%2 \n"
- "movdqu %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_argb), // %1
- "+r"(width), // %2
- "+r"(alpha) // %3
- : "r"(fixed_invtbl8) // %4
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-#endif // HAS_ARGBUNATTENUATEROW_SSE2
-
-#ifdef HAS_ARGBGRAYROW_SSSE3
-// Convert 8 ARGB pixels (64 bytes) to 8 Gray ARGB pixels
-void ARGBGrayRow_SSSE3(const uint8* src_argb, uint8* dst_argb, int width) {
- asm volatile (
- "movdqa %3,%%xmm4 \n"
- "movdqa %4,%%xmm5 \n"
-
- // 8 pixel loop.
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "pmaddubsw %%xmm4,%%xmm0 \n"
- "pmaddubsw %%xmm4,%%xmm1 \n"
- "phaddw %%xmm1,%%xmm0 \n"
- "paddw %%xmm5,%%xmm0 \n"
- "psrlw $0x7,%%xmm0 \n"
- "packuswb %%xmm0,%%xmm0 \n"
- "movdqa " MEMACCESS(0) ",%%xmm2 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm3 \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "psrld $0x18,%%xmm2 \n"
- "psrld $0x18,%%xmm3 \n"
- "packuswb %%xmm3,%%xmm2 \n"
- "packuswb %%xmm2,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm3 \n"
- "punpcklbw %%xmm0,%%xmm0 \n"
- "punpcklbw %%xmm2,%%xmm3 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "punpcklwd %%xmm3,%%xmm0 \n"
- "punpckhwd %%xmm3,%%xmm1 \n"
- "sub $0x8,%2 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "movdqa %%xmm1," MEMACCESS2(0x10,1) " \n"
- "lea " MEMLEA(0x20,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_argb), // %1
- "+r"(width) // %2
- : "m"(kARGBToYJ), // %3
- "m"(kAddYJ64) // %4
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-#endif // HAS_ARGBGRAYROW_SSSE3
-
-#ifdef HAS_ARGBSEPIAROW_SSSE3
-// b = (r * 35 + g * 68 + b * 17) >> 7
-// g = (r * 45 + g * 88 + b * 22) >> 7
-// r = (r * 50 + g * 98 + b * 24) >> 7
-// Constant for ARGB color to sepia tone
-static vec8 kARGBToSepiaB = {
- 17, 68, 35, 0, 17, 68, 35, 0, 17, 68, 35, 0, 17, 68, 35, 0
-};
-
-static vec8 kARGBToSepiaG = {
- 22, 88, 45, 0, 22, 88, 45, 0, 22, 88, 45, 0, 22, 88, 45, 0
-};
-
-static vec8 kARGBToSepiaR = {
- 24, 98, 50, 0, 24, 98, 50, 0, 24, 98, 50, 0, 24, 98, 50, 0
-};
-
-// Convert 8 ARGB pixels (32 bytes) to 8 Sepia ARGB pixels.
-void ARGBSepiaRow_SSSE3(uint8* dst_argb, int width) {
- asm volatile (
- "movdqa %2,%%xmm2 \n"
- "movdqa %3,%%xmm3 \n"
- "movdqa %4,%%xmm4 \n"
-
- // 8 pixel loop.
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm6 \n"
- "pmaddubsw %%xmm2,%%xmm0 \n"
- "pmaddubsw %%xmm2,%%xmm6 \n"
- "phaddw %%xmm6,%%xmm0 \n"
- "psrlw $0x7,%%xmm0 \n"
- "packuswb %%xmm0,%%xmm0 \n"
- "movdqa " MEMACCESS(0) ",%%xmm5 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "pmaddubsw %%xmm3,%%xmm5 \n"
- "pmaddubsw %%xmm3,%%xmm1 \n"
- "phaddw %%xmm1,%%xmm5 \n"
- "psrlw $0x7,%%xmm5 \n"
- "packuswb %%xmm5,%%xmm5 \n"
- "punpcklbw %%xmm5,%%xmm0 \n"
- "movdqa " MEMACCESS(0) ",%%xmm5 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "pmaddubsw %%xmm4,%%xmm5 \n"
- "pmaddubsw %%xmm4,%%xmm1 \n"
- "phaddw %%xmm1,%%xmm5 \n"
- "psrlw $0x7,%%xmm5 \n"
- "packuswb %%xmm5,%%xmm5 \n"
- "movdqa " MEMACCESS(0) ",%%xmm6 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "psrld $0x18,%%xmm6 \n"
- "psrld $0x18,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm6 \n"
- "packuswb %%xmm6,%%xmm6 \n"
- "punpcklbw %%xmm6,%%xmm5 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "punpcklwd %%xmm5,%%xmm0 \n"
- "punpckhwd %%xmm5,%%xmm1 \n"
- "sub $0x8,%1 \n"
- "movdqa %%xmm0," MEMACCESS(0) " \n"
- "movdqa %%xmm1," MEMACCESS2(0x10,0) " \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "jg 1b \n"
- : "+r"(dst_argb), // %0
- "+r"(width) // %1
- : "m"(kARGBToSepiaB), // %2
- "m"(kARGBToSepiaG), // %3
- "m"(kARGBToSepiaR) // %4
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"
-#endif
- );
-}
-#endif // HAS_ARGBSEPIAROW_SSSE3
-
-#ifdef HAS_ARGBCOLORMATRIXROW_SSSE3
-// Tranform 8 ARGB pixels (32 bytes) with color matrix.
-// Same as Sepia except matrix is provided.
-void ARGBColorMatrixRow_SSSE3(const uint8* src_argb, uint8* dst_argb,
- const int8* matrix_argb, int width) {
- asm volatile (
- "movdqu " MEMACCESS(3) ",%%xmm5 \n"
- "pshufd $0x00,%%xmm5,%%xmm2 \n"
- "pshufd $0x55,%%xmm5,%%xmm3 \n"
- "pshufd $0xaa,%%xmm5,%%xmm4 \n"
- "pshufd $0xff,%%xmm5,%%xmm5 \n"
-
- // 8 pixel loop.
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm7 \n"
- "pmaddubsw %%xmm2,%%xmm0 \n"
- "pmaddubsw %%xmm2,%%xmm7 \n"
- "movdqa " MEMACCESS(0) ",%%xmm6 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "pmaddubsw %%xmm3,%%xmm6 \n"
- "pmaddubsw %%xmm3,%%xmm1 \n"
- "phaddsw %%xmm7,%%xmm0 \n"
- "phaddsw %%xmm1,%%xmm6 \n"
- "psraw $0x6,%%xmm0 \n"
- "psraw $0x6,%%xmm6 \n"
- "packuswb %%xmm0,%%xmm0 \n"
- "packuswb %%xmm6,%%xmm6 \n"
- "punpcklbw %%xmm6,%%xmm0 \n"
- "movdqa " MEMACCESS(0) ",%%xmm1 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm7 \n"
- "pmaddubsw %%xmm4,%%xmm1 \n"
- "pmaddubsw %%xmm4,%%xmm7 \n"
- "phaddsw %%xmm7,%%xmm1 \n"
- "movdqa " MEMACCESS(0) ",%%xmm6 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm7 \n"
- "pmaddubsw %%xmm5,%%xmm6 \n"
- "pmaddubsw %%xmm5,%%xmm7 \n"
- "phaddsw %%xmm7,%%xmm6 \n"
- "psraw $0x6,%%xmm1 \n"
- "psraw $0x6,%%xmm6 \n"
- "packuswb %%xmm1,%%xmm1 \n"
- "packuswb %%xmm6,%%xmm6 \n"
- "punpcklbw %%xmm6,%%xmm1 \n"
- "movdqa %%xmm0,%%xmm6 \n"
- "punpcklwd %%xmm1,%%xmm0 \n"
- "punpckhwd %%xmm1,%%xmm6 \n"
- "sub $0x8,%2 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "movdqa %%xmm6," MEMACCESS2(0x10,1) " \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "lea " MEMLEA(0x20,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_argb), // %1
- "+r"(width) // %2
- : "r"(matrix_argb) // %3
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
-#endif
- );
-}
-#endif // HAS_ARGBCOLORMATRIXROW_SSSE3
-
-#ifdef HAS_ARGBQUANTIZEROW_SSE2
-// Quantize 4 ARGB pixels (16 bytes).
-// aligned to 16 bytes
-void ARGBQuantizeRow_SSE2(uint8* dst_argb, int scale, int interval_size,
- int interval_offset, int width) {
- asm volatile (
- "movd %2,%%xmm2 \n"
- "movd %3,%%xmm3 \n"
- "movd %4,%%xmm4 \n"
- "pshuflw $0x40,%%xmm2,%%xmm2 \n"
- "pshufd $0x44,%%xmm2,%%xmm2 \n"
- "pshuflw $0x40,%%xmm3,%%xmm3 \n"
- "pshufd $0x44,%%xmm3,%%xmm3 \n"
- "pshuflw $0x40,%%xmm4,%%xmm4 \n"
- "pshufd $0x44,%%xmm4,%%xmm4 \n"
- "pxor %%xmm5,%%xmm5 \n"
- "pcmpeqb %%xmm6,%%xmm6 \n"
- "pslld $0x18,%%xmm6 \n"
-
- // 4 pixel loop.
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "punpcklbw %%xmm5,%%xmm0 \n"
- "pmulhuw %%xmm2,%%xmm0 \n"
- "movdqa " MEMACCESS(0) ",%%xmm1 \n"
- "punpckhbw %%xmm5,%%xmm1 \n"
- "pmulhuw %%xmm2,%%xmm1 \n"
- "pmullw %%xmm3,%%xmm0 \n"
- "movdqa " MEMACCESS(0) ",%%xmm7 \n"
- "pmullw %%xmm3,%%xmm1 \n"
- "pand %%xmm6,%%xmm7 \n"
- "paddw %%xmm4,%%xmm0 \n"
- "paddw %%xmm4,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "por %%xmm7,%%xmm0 \n"
- "sub $0x4,%1 \n"
- "movdqa %%xmm0," MEMACCESS(0) " \n"
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "jg 1b \n"
- : "+r"(dst_argb), // %0
- "+r"(width) // %1
- : "r"(scale), // %2
- "r"(interval_size), // %3
- "r"(interval_offset) // %4
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
-#endif
- );
-}
-#endif // HAS_ARGBQUANTIZEROW_SSE2
-
-#ifdef HAS_ARGBSHADEROW_SSE2
-// Shade 4 pixels at a time by specified value.
-// Aligned to 16 bytes.
-void ARGBShadeRow_SSE2(const uint8* src_argb, uint8* dst_argb, int width,
- uint32 value) {
- asm volatile (
- "movd %3,%%xmm2 \n"
- "punpcklbw %%xmm2,%%xmm2 \n"
- "punpcklqdq %%xmm2,%%xmm2 \n"
-
- // 4 pixel loop.
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "punpcklbw %%xmm0,%%xmm0 \n"
- "punpckhbw %%xmm1,%%xmm1 \n"
- "pmulhuw %%xmm2,%%xmm0 \n"
- "pmulhuw %%xmm2,%%xmm1 \n"
- "psrlw $0x8,%%xmm0 \n"
- "psrlw $0x8,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "sub $0x4,%2 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_argb), // %1
- "+r"(width) // %2
- : "r"(value) // %3
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2"
-#endif
- );
-}
-#endif // HAS_ARGBSHADEROW_SSE2
-
-#ifdef HAS_ARGBMULTIPLYROW_SSE2
-// Multiply 2 rows of ARGB pixels together, 4 pixels at a time.
-void ARGBMultiplyRow_SSE2(const uint8* src_argb0, const uint8* src_argb1,
- uint8* dst_argb, int width) {
- asm volatile (
- "pxor %%xmm5,%%xmm5 \n"
-
- // 4 pixel loop.
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "movdqu " MEMACCESS(1) ",%%xmm2 \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "movdqu %%xmm0,%%xmm1 \n"
- "movdqu %%xmm2,%%xmm3 \n"
- "punpcklbw %%xmm0,%%xmm0 \n"
- "punpckhbw %%xmm1,%%xmm1 \n"
- "punpcklbw %%xmm5,%%xmm2 \n"
- "punpckhbw %%xmm5,%%xmm3 \n"
- "pmulhuw %%xmm2,%%xmm0 \n"
- "pmulhuw %%xmm3,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "sub $0x4,%3 \n"
- "movdqu %%xmm0," MEMACCESS(2) " \n"
- "lea " MEMLEA(0x10,2) ",%2 \n"
- "jg 1b \n"
- : "+r"(src_argb0), // %0
- "+r"(src_argb1), // %1
- "+r"(dst_argb), // %2
- "+r"(width) // %3
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"
-#endif
- );
-}
-#endif // HAS_ARGBMULTIPLYROW_SSE2
-
-#ifdef HAS_ARGBADDROW_SSE2
-// Add 2 rows of ARGB pixels together, 4 pixels at a time.
-void ARGBAddRow_SSE2(const uint8* src_argb0, const uint8* src_argb1,
- uint8* dst_argb, int width) {
- asm volatile (
- // 4 pixel loop.
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "movdqu " MEMACCESS(1) ",%%xmm1 \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "paddusb %%xmm1,%%xmm0 \n"
- "sub $0x4,%3 \n"
- "movdqu %%xmm0," MEMACCESS(2) " \n"
- "lea " MEMLEA(0x10,2) ",%2 \n"
- "jg 1b \n"
- : "+r"(src_argb0), // %0
- "+r"(src_argb1), // %1
- "+r"(dst_argb), // %2
- "+r"(width) // %3
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1"
-#endif
- );
-}
-#endif // HAS_ARGBADDROW_SSE2
-
-#ifdef HAS_ARGBSUBTRACTROW_SSE2
-// Subtract 2 rows of ARGB pixels, 4 pixels at a time.
-void ARGBSubtractRow_SSE2(const uint8* src_argb0, const uint8* src_argb1,
- uint8* dst_argb, int width) {
- asm volatile (
- // 4 pixel loop.
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "movdqu " MEMACCESS(1) ",%%xmm1 \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "psubusb %%xmm1,%%xmm0 \n"
- "sub $0x4,%3 \n"
- "movdqu %%xmm0," MEMACCESS(2) " \n"
- "lea " MEMLEA(0x10,2) ",%2 \n"
- "jg 1b \n"
- : "+r"(src_argb0), // %0
- "+r"(src_argb1), // %1
- "+r"(dst_argb), // %2
- "+r"(width) // %3
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1"
-#endif
- );
-}
-#endif // HAS_ARGBSUBTRACTROW_SSE2
-
-#ifdef HAS_SOBELXROW_SSE2
-// SobelX as a matrix is
-// -1 0 1
-// -2 0 2
-// -1 0 1
-void SobelXRow_SSE2(const uint8* src_y0, const uint8* src_y1,
- const uint8* src_y2, uint8* dst_sobelx, int width) {
- asm volatile (
- "sub %0,%1 \n"
- "sub %0,%2 \n"
- "sub %0,%3 \n"
- "pxor %%xmm5,%%xmm5 \n"
-
- // 8 pixel loop.
- LABELALIGN
- "1: \n"
- "movq " MEMACCESS(0) ",%%xmm0 \n"
- "movq " MEMACCESS2(0x2,0) ",%%xmm1 \n"
- "punpcklbw %%xmm5,%%xmm0 \n"
- "punpcklbw %%xmm5,%%xmm1 \n"
- "psubw %%xmm1,%%xmm0 \n"
- BUNDLEALIGN
- MEMOPREG(movq,0x00,0,1,1,xmm1) // movq (%0,%1,1),%%xmm1
- MEMOPREG(movq,0x02,0,1,1,xmm2) // movq 0x2(%0,%1,1),%%xmm2
- "punpcklbw %%xmm5,%%xmm1 \n"
- "punpcklbw %%xmm5,%%xmm2 \n"
- "psubw %%xmm2,%%xmm1 \n"
- BUNDLEALIGN
- MEMOPREG(movq,0x00,0,2,1,xmm2) // movq (%0,%2,1),%%xmm2
- MEMOPREG(movq,0x02,0,2,1,xmm3) // movq 0x2(%0,%2,1),%%xmm3
- "punpcklbw %%xmm5,%%xmm2 \n"
- "punpcklbw %%xmm5,%%xmm3 \n"
- "psubw %%xmm3,%%xmm2 \n"
- "paddw %%xmm2,%%xmm0 \n"
- "paddw %%xmm1,%%xmm0 \n"
- "paddw %%xmm1,%%xmm0 \n"
- "pxor %%xmm1,%%xmm1 \n"
- "psubw %%xmm0,%%xmm1 \n"
- "pmaxsw %%xmm1,%%xmm0 \n"
- "packuswb %%xmm0,%%xmm0 \n"
- "sub $0x8,%4 \n"
- BUNDLEALIGN
- MEMOPMEM(movq,xmm0,0x00,0,3,1) // movq %%xmm0,(%0,%3,1)
- "lea " MEMLEA(0x8,0) ",%0 \n"
- "jg 1b \n"
- : "+r"(src_y0), // %0
- "+r"(src_y1), // %1
- "+r"(src_y2), // %2
- "+r"(dst_sobelx), // %3
- "+r"(width) // %4
- :
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"
-#endif
- );
-}
-#endif // HAS_SOBELXROW_SSE2
-
-#ifdef HAS_SOBELYROW_SSE2
-// SobelY as a matrix is
-// -1 -2 -1
-// 0 0 0
-// 1 2 1
-void SobelYRow_SSE2(const uint8* src_y0, const uint8* src_y1,
- uint8* dst_sobely, int width) {
- asm volatile (
- "sub %0,%1 \n"
- "sub %0,%2 \n"
- "pxor %%xmm5,%%xmm5 \n"
-
- // 8 pixel loop.
- LABELALIGN
- "1: \n"
- "movq " MEMACCESS(0) ",%%xmm0 \n"
- MEMOPREG(movq,0x00,0,1,1,xmm1) // movq (%0,%1,1),%%xmm1
- "punpcklbw %%xmm5,%%xmm0 \n"
- "punpcklbw %%xmm5,%%xmm1 \n"
- "psubw %%xmm1,%%xmm0 \n"
- BUNDLEALIGN
- "movq " MEMACCESS2(0x1,0) ",%%xmm1 \n"
- MEMOPREG(movq,0x01,0,1,1,xmm2) // movq 0x1(%0,%1,1),%%xmm2
- "punpcklbw %%xmm5,%%xmm1 \n"
- "punpcklbw %%xmm5,%%xmm2 \n"
- "psubw %%xmm2,%%xmm1 \n"
- BUNDLEALIGN
- "movq " MEMACCESS2(0x2,0) ",%%xmm2 \n"
- MEMOPREG(movq,0x02,0,1,1,xmm3) // movq 0x2(%0,%1,1),%%xmm3
- "punpcklbw %%xmm5,%%xmm2 \n"
- "punpcklbw %%xmm5,%%xmm3 \n"
- "psubw %%xmm3,%%xmm2 \n"
- "paddw %%xmm2,%%xmm0 \n"
- "paddw %%xmm1,%%xmm0 \n"
- "paddw %%xmm1,%%xmm0 \n"
- "pxor %%xmm1,%%xmm1 \n"
- "psubw %%xmm0,%%xmm1 \n"
- "pmaxsw %%xmm1,%%xmm0 \n"
- "packuswb %%xmm0,%%xmm0 \n"
- "sub $0x8,%3 \n"
- BUNDLEALIGN
- MEMOPMEM(movq,xmm0,0x00,0,2,1) // movq %%xmm0,(%0,%2,1)
- "lea " MEMLEA(0x8,0) ",%0 \n"
- "jg 1b \n"
- : "+r"(src_y0), // %0
- "+r"(src_y1), // %1
- "+r"(dst_sobely), // %2
- "+r"(width) // %3
- :
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"
-#endif
- );
-}
-#endif // HAS_SOBELYROW_SSE2
-
-#ifdef HAS_SOBELROW_SSE2
-// Adds Sobel X and Sobel Y and stores Sobel into ARGB.
-// A = 255
-// R = Sobel
-// G = Sobel
-// B = Sobel
-void SobelRow_SSE2(const uint8* src_sobelx, const uint8* src_sobely,
- uint8* dst_argb, int width) {
- asm volatile (
- "sub %0,%1 \n"
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "pslld $0x18,%%xmm5 \n"
-
- // 8 pixel loop.
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- MEMOPREG(movdqa,0x00,0,1,1,xmm1) // movdqa (%0,%1,1),%%xmm1
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "paddusb %%xmm1,%%xmm0 \n"
- "movdqa %%xmm0,%%xmm2 \n"
- "punpcklbw %%xmm0,%%xmm2 \n"
- "punpckhbw %%xmm0,%%xmm0 \n"
- "movdqa %%xmm2,%%xmm1 \n"
- "punpcklwd %%xmm2,%%xmm1 \n"
- "punpckhwd %%xmm2,%%xmm2 \n"
- "por %%xmm5,%%xmm1 \n"
- "por %%xmm5,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm3 \n"
- "punpcklwd %%xmm0,%%xmm3 \n"
- "punpckhwd %%xmm0,%%xmm0 \n"
- "por %%xmm5,%%xmm3 \n"
- "por %%xmm5,%%xmm0 \n"
- "sub $0x10,%3 \n"
- "movdqa %%xmm1," MEMACCESS(2) " \n"
- "movdqa %%xmm2," MEMACCESS2(0x10,2) " \n"
- "movdqa %%xmm3," MEMACCESS2(0x20,2) " \n"
- "movdqa %%xmm0," MEMACCESS2(0x30,2) " \n"
- "lea " MEMLEA(0x40,2) ",%2 \n"
- "jg 1b \n"
- : "+r"(src_sobelx), // %0
- "+r"(src_sobely), // %1
- "+r"(dst_argb), // %2
- "+r"(width) // %3
- :
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"
-#endif
- );
-}
-#endif // HAS_SOBELROW_SSE2
-
-#ifdef HAS_SOBELTOPLANEROW_SSE2
-// Adds Sobel X and Sobel Y and stores Sobel into a plane.
-void SobelToPlaneRow_SSE2(const uint8* src_sobelx, const uint8* src_sobely,
- uint8* dst_y, int width) {
- asm volatile (
- "sub %0,%1 \n"
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "pslld $0x18,%%xmm5 \n"
-
- // 8 pixel loop.
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- MEMOPREG(movdqa,0x00,0,1,1,xmm1) // movdqa (%0,%1,1),%%xmm1
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "paddusb %%xmm1,%%xmm0 \n"
- "sub $0x10,%3 \n"
- "movdqa %%xmm0," MEMACCESS(2) " \n"
- "lea " MEMLEA(0x10,2) ",%2 \n"
- "jg 1b \n"
- : "+r"(src_sobelx), // %0
- "+r"(src_sobely), // %1
- "+r"(dst_y), // %2
- "+r"(width) // %3
- :
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1"
-#endif
- );
-}
-#endif // HAS_SOBELTOPLANEROW_SSE2
-
-#ifdef HAS_SOBELXYROW_SSE2
-// Mixes Sobel X, Sobel Y and Sobel into ARGB.
-// A = 255
-// R = Sobel X
-// G = Sobel
-// B = Sobel Y
-void SobelXYRow_SSE2(const uint8* src_sobelx, const uint8* src_sobely,
- uint8* dst_argb, int width) {
- asm volatile (
- "sub %0,%1 \n"
- "pcmpeqb %%xmm5,%%xmm5 \n"
-
- // 8 pixel loop.
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- MEMOPREG(movdqa,0x00,0,1,1,xmm1) // movdqa (%0,%1,1),%%xmm1
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "movdqa %%xmm0,%%xmm2 \n"
- "paddusb %%xmm1,%%xmm2 \n"
- "movdqa %%xmm0,%%xmm3 \n"
- "punpcklbw %%xmm5,%%xmm3 \n"
- "punpckhbw %%xmm5,%%xmm0 \n"
- "movdqa %%xmm1,%%xmm4 \n"
- "punpcklbw %%xmm2,%%xmm4 \n"
- "punpckhbw %%xmm2,%%xmm1 \n"
- "movdqa %%xmm4,%%xmm6 \n"
- "punpcklwd %%xmm3,%%xmm6 \n"
- "punpckhwd %%xmm3,%%xmm4 \n"
- "movdqa %%xmm1,%%xmm7 \n"
- "punpcklwd %%xmm0,%%xmm7 \n"
- "punpckhwd %%xmm0,%%xmm1 \n"
- "sub $0x10,%3 \n"
- "movdqa %%xmm6," MEMACCESS(2) " \n"
- "movdqa %%xmm4," MEMACCESS2(0x10,2) " \n"
- "movdqa %%xmm7," MEMACCESS2(0x20,2) " \n"
- "movdqa %%xmm1," MEMACCESS2(0x30,2) " \n"
- "lea " MEMLEA(0x40,2) ",%2 \n"
- "jg 1b \n"
- : "+r"(src_sobelx), // %0
- "+r"(src_sobely), // %1
- "+r"(dst_argb), // %2
- "+r"(width) // %3
- :
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
-#endif
- );
-}
-#endif // HAS_SOBELXYROW_SSE2
-
-#ifdef HAS_COMPUTECUMULATIVESUMROW_SSE2
-// Creates a table of cumulative sums where each value is a sum of all values
-// above and to the left of the value, inclusive of the value.
-void ComputeCumulativeSumRow_SSE2(const uint8* row, int32* cumsum,
- const int32* previous_cumsum, int width) {
- asm volatile (
- "pxor %%xmm0,%%xmm0 \n"
- "pxor %%xmm1,%%xmm1 \n"
- "sub $0x4,%3 \n"
- "jl 49f \n"
- "test $0xf,%1 \n"
- "jne 49f \n"
-
- // 4 pixel loop \n"
- LABELALIGN
- "40: \n"
- "movdqu " MEMACCESS(0) ",%%xmm2 \n"
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "movdqa %%xmm2,%%xmm4 \n"
- "punpcklbw %%xmm1,%%xmm2 \n"
- "movdqa %%xmm2,%%xmm3 \n"
- "punpcklwd %%xmm1,%%xmm2 \n"
- "punpckhwd %%xmm1,%%xmm3 \n"
- "punpckhbw %%xmm1,%%xmm4 \n"
- "movdqa %%xmm4,%%xmm5 \n"
- "punpcklwd %%xmm1,%%xmm4 \n"
- "punpckhwd %%xmm1,%%xmm5 \n"
- "paddd %%xmm2,%%xmm0 \n"
- "movdqa " MEMACCESS(2) ",%%xmm2 \n"
- "paddd %%xmm0,%%xmm2 \n"
- "paddd %%xmm3,%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,2) ",%%xmm3 \n"
- "paddd %%xmm0,%%xmm3 \n"
- "paddd %%xmm4,%%xmm0 \n"
- "movdqa " MEMACCESS2(0x20,2) ",%%xmm4 \n"
- "paddd %%xmm0,%%xmm4 \n"
- "paddd %%xmm5,%%xmm0 \n"
- "movdqa " MEMACCESS2(0x30,2) ",%%xmm5 \n"
- "lea " MEMLEA(0x40,2) ",%2 \n"
- "paddd %%xmm0,%%xmm5 \n"
- "movdqa %%xmm2," MEMACCESS(1) " \n"
- "movdqa %%xmm3," MEMACCESS2(0x10,1) " \n"
- "movdqa %%xmm4," MEMACCESS2(0x20,1) " \n"
- "movdqa %%xmm5," MEMACCESS2(0x30,1) " \n"
- "lea " MEMLEA(0x40,1) ",%1 \n"
- "sub $0x4,%3 \n"
- "jge 40b \n"
-
- "49: \n"
- "add $0x3,%3 \n"
- "jl 19f \n"
-
- // 1 pixel loop \n"
- LABELALIGN
- "10: \n"
- "movd " MEMACCESS(0) ",%%xmm2 \n"
- "lea " MEMLEA(0x4,0) ",%0 \n"
- "punpcklbw %%xmm1,%%xmm2 \n"
- "punpcklwd %%xmm1,%%xmm2 \n"
- "paddd %%xmm2,%%xmm0 \n"
- "movdqu " MEMACCESS(2) ",%%xmm2 \n"
- "lea " MEMLEA(0x10,2) ",%2 \n"
- "paddd %%xmm0,%%xmm2 \n"
- "movdqu %%xmm2," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "sub $0x1,%3 \n"
- "jge 10b \n"
-
- "19: \n"
- : "+r"(row), // %0
- "+r"(cumsum), // %1
- "+r"(previous_cumsum), // %2
- "+r"(width) // %3
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-#endif // HAS_COMPUTECUMULATIVESUMROW_SSE2
-
-#ifdef HAS_CUMULATIVESUMTOAVERAGEROW_SSE2
-void CumulativeSumToAverageRow_SSE2(const int32* topleft, const int32* botleft,
- int width, int area, uint8* dst,
- int count) {
- asm volatile (
- "movd %5,%%xmm5 \n"
- "cvtdq2ps %%xmm5,%%xmm5 \n"
- "rcpss %%xmm5,%%xmm4 \n"
- "pshufd $0x0,%%xmm4,%%xmm4 \n"
- "sub $0x4,%3 \n"
- "jl 49f \n"
- "cmpl $0x80,%5 \n"
- "ja 40f \n"
-
- "pshufd $0x0,%%xmm5,%%xmm5 \n"
- "pcmpeqb %%xmm6,%%xmm6 \n"
- "psrld $0x10,%%xmm6 \n"
- "cvtdq2ps %%xmm6,%%xmm6 \n"
- "addps %%xmm6,%%xmm5 \n"
- "mulps %%xmm4,%%xmm5 \n"
- "cvtps2dq %%xmm5,%%xmm5 \n"
- "packssdw %%xmm5,%%xmm5 \n"
-
- // 4 pixel small loop \n"
- LABELALIGN
- "4: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqa " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqa " MEMACCESS2(0x30,0) ",%%xmm3 \n"
- BUNDLEALIGN
- MEMOPREG(psubd,0x00,0,4,4,xmm0) // psubd 0x00(%0,%4,4),%%xmm0
- MEMOPREG(psubd,0x10,0,4,4,xmm1) // psubd 0x10(%0,%4,4),%%xmm1
- MEMOPREG(psubd,0x20,0,4,4,xmm2) // psubd 0x20(%0,%4,4),%%xmm2
- MEMOPREG(psubd,0x30,0,4,4,xmm3) // psubd 0x30(%0,%4,4),%%xmm3
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "psubd " MEMACCESS(1) ",%%xmm0 \n"
- "psubd " MEMACCESS2(0x10,1) ",%%xmm1 \n"
- "psubd " MEMACCESS2(0x20,1) ",%%xmm2 \n"
- "psubd " MEMACCESS2(0x30,1) ",%%xmm3 \n"
- BUNDLEALIGN
- MEMOPREG(paddd,0x00,1,4,4,xmm0) // paddd 0x00(%1,%4,4),%%xmm0
- MEMOPREG(paddd,0x10,1,4,4,xmm1) // paddd 0x10(%1,%4,4),%%xmm1
- MEMOPREG(paddd,0x20,1,4,4,xmm2) // paddd 0x20(%1,%4,4),%%xmm2
- MEMOPREG(paddd,0x30,1,4,4,xmm3) // paddd 0x30(%1,%4,4),%%xmm3
- "lea " MEMLEA(0x40,1) ",%1 \n"
- "packssdw %%xmm1,%%xmm0 \n"
- "packssdw %%xmm3,%%xmm2 \n"
- "pmulhuw %%xmm5,%%xmm0 \n"
- "pmulhuw %%xmm5,%%xmm2 \n"
- "packuswb %%xmm2,%%xmm0 \n"
- "movdqu %%xmm0," MEMACCESS(2) " \n"
- "lea " MEMLEA(0x10,2) ",%2 \n"
- "sub $0x4,%3 \n"
- "jge 4b \n"
- "jmp 49f \n"
-
- // 4 pixel loop \n"
- LABELALIGN
- "40: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "movdqa " MEMACCESS2(0x20,0) ",%%xmm2 \n"
- "movdqa " MEMACCESS2(0x30,0) ",%%xmm3 \n"
- BUNDLEALIGN
- MEMOPREG(psubd,0x00,0,4,4,xmm0) // psubd 0x00(%0,%4,4),%%xmm0
- MEMOPREG(psubd,0x10,0,4,4,xmm1) // psubd 0x10(%0,%4,4),%%xmm1
- MEMOPREG(psubd,0x20,0,4,4,xmm2) // psubd 0x20(%0,%4,4),%%xmm2
- MEMOPREG(psubd,0x30,0,4,4,xmm3) // psubd 0x30(%0,%4,4),%%xmm3
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "psubd " MEMACCESS(1) ",%%xmm0 \n"
- "psubd " MEMACCESS2(0x10,1) ",%%xmm1 \n"
- "psubd " MEMACCESS2(0x20,1) ",%%xmm2 \n"
- "psubd " MEMACCESS2(0x30,1) ",%%xmm3 \n"
- BUNDLEALIGN
- MEMOPREG(paddd,0x00,1,4,4,xmm0) // paddd 0x00(%1,%4,4),%%xmm0
- MEMOPREG(paddd,0x10,1,4,4,xmm1) // paddd 0x10(%1,%4,4),%%xmm1
- MEMOPREG(paddd,0x20,1,4,4,xmm2) // paddd 0x20(%1,%4,4),%%xmm2
- MEMOPREG(paddd,0x30,1,4,4,xmm3) // paddd 0x30(%1,%4,4),%%xmm3
- "lea " MEMLEA(0x40,1) ",%1 \n"
- "cvtdq2ps %%xmm0,%%xmm0 \n"
- "cvtdq2ps %%xmm1,%%xmm1 \n"
- "mulps %%xmm4,%%xmm0 \n"
- "mulps %%xmm4,%%xmm1 \n"
- "cvtdq2ps %%xmm2,%%xmm2 \n"
- "cvtdq2ps %%xmm3,%%xmm3 \n"
- "mulps %%xmm4,%%xmm2 \n"
- "mulps %%xmm4,%%xmm3 \n"
- "cvtps2dq %%xmm0,%%xmm0 \n"
- "cvtps2dq %%xmm1,%%xmm1 \n"
- "cvtps2dq %%xmm2,%%xmm2 \n"
- "cvtps2dq %%xmm3,%%xmm3 \n"
- "packssdw %%xmm1,%%xmm0 \n"
- "packssdw %%xmm3,%%xmm2 \n"
- "packuswb %%xmm2,%%xmm0 \n"
- "movdqu %%xmm0," MEMACCESS(2) " \n"
- "lea " MEMLEA(0x10,2) ",%2 \n"
- "sub $0x4,%3 \n"
- "jge 40b \n"
-
- "49: \n"
- "add $0x3,%3 \n"
- "jl 19f \n"
-
- // 1 pixel loop \n"
- LABELALIGN
- "10: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- MEMOPREG(psubd,0x00,0,4,4,xmm0) // psubd 0x00(%0,%4,4),%%xmm0
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "psubd " MEMACCESS(1) ",%%xmm0 \n"
- BUNDLEALIGN
- MEMOPREG(paddd,0x00,1,4,4,xmm0) // paddd 0x00(%1,%4,4),%%xmm0
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "cvtdq2ps %%xmm0,%%xmm0 \n"
- "mulps %%xmm4,%%xmm0 \n"
- "cvtps2dq %%xmm0,%%xmm0 \n"
- "packssdw %%xmm0,%%xmm0 \n"
- "packuswb %%xmm0,%%xmm0 \n"
- "movd %%xmm0," MEMACCESS(2) " \n"
- "lea " MEMLEA(0x4,2) ",%2 \n"
- "sub $0x1,%3 \n"
- "jge 10b \n"
- "19: \n"
- : "+r"(topleft), // %0
- "+r"(botleft), // %1
- "+r"(dst), // %2
- "+rm"(count) // %3
- : "r"((intptr_t)(width)), // %4
- "rm"(area) // %5
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"
-#endif
- );
-}
-#endif // HAS_CUMULATIVESUMTOAVERAGEROW_SSE2
-
-#ifdef HAS_ARGBAFFINEROW_SSE2
-// Copy ARGB pixels from source image with slope to a row of destination.
-LIBYUV_API
-void ARGBAffineRow_SSE2(const uint8* src_argb, int src_argb_stride,
- uint8* dst_argb, const float* src_dudv, int width) {
- intptr_t src_argb_stride_temp = src_argb_stride;
- intptr_t temp = 0;
- asm volatile (
- "movq " MEMACCESS(3) ",%%xmm2 \n"
- "movq " MEMACCESS2(0x08,3) ",%%xmm7 \n"
- "shl $0x10,%1 \n"
- "add $0x4,%1 \n"
- "movd %1,%%xmm5 \n"
- "sub $0x4,%4 \n"
- "jl 49f \n"
-
- "pshufd $0x44,%%xmm7,%%xmm7 \n"
- "pshufd $0x0,%%xmm5,%%xmm5 \n"
- "movdqa %%xmm2,%%xmm0 \n"
- "addps %%xmm7,%%xmm0 \n"
- "movlhps %%xmm0,%%xmm2 \n"
- "movdqa %%xmm7,%%xmm4 \n"
- "addps %%xmm4,%%xmm4 \n"
- "movdqa %%xmm2,%%xmm3 \n"
- "addps %%xmm4,%%xmm3 \n"
- "addps %%xmm4,%%xmm4 \n"
-
- // 4 pixel loop \n"
- LABELALIGN
- "40: \n"
- "cvttps2dq %%xmm2,%%xmm0 \n" // x, y float to int first 2
- "cvttps2dq %%xmm3,%%xmm1 \n" // x, y float to int next 2
- "packssdw %%xmm1,%%xmm0 \n" // x, y as 8 shorts
- "pmaddwd %%xmm5,%%xmm0 \n" // off = x * 4 + y * stride
- "movd %%xmm0,%k1 \n"
- "pshufd $0x39,%%xmm0,%%xmm0 \n"
- "movd %%xmm0,%k5 \n"
- "pshufd $0x39,%%xmm0,%%xmm0 \n"
- BUNDLEALIGN
- MEMOPREG(movd,0x00,0,1,1,xmm1) // movd (%0,%1,1),%%xmm1
- MEMOPREG(movd,0x00,0,5,1,xmm6) // movd (%0,%5,1),%%xmm6
- "punpckldq %%xmm6,%%xmm1 \n"
- "addps %%xmm4,%%xmm2 \n"
- "movq %%xmm1," MEMACCESS(2) " \n"
- "movd %%xmm0,%k1 \n"
- "pshufd $0x39,%%xmm0,%%xmm0 \n"
- "movd %%xmm0,%k5 \n"
- BUNDLEALIGN
- MEMOPREG(movd,0x00,0,1,1,xmm0) // movd (%0,%1,1),%%xmm0
- MEMOPREG(movd,0x00,0,5,1,xmm6) // movd (%0,%5,1),%%xmm6
- "punpckldq %%xmm6,%%xmm0 \n"
- "addps %%xmm4,%%xmm3 \n"
- "sub $0x4,%4 \n"
- "movq %%xmm0," MEMACCESS2(0x08,2) " \n"
- "lea " MEMLEA(0x10,2) ",%2 \n"
- "jge 40b \n"
-
- "49: \n"
- "add $0x3,%4 \n"
- "jl 19f \n"
-
- // 1 pixel loop \n"
- LABELALIGN
- "10: \n"
- "cvttps2dq %%xmm2,%%xmm0 \n"
- "packssdw %%xmm0,%%xmm0 \n"
- "pmaddwd %%xmm5,%%xmm0 \n"
- "addps %%xmm7,%%xmm2 \n"
- "movd %%xmm0,%k1 \n"
- BUNDLEALIGN
- MEMOPREG(movd,0x00,0,1,1,xmm0) // movd (%0,%1,1),%%xmm0
- "sub $0x1,%4 \n"
- "movd %%xmm0," MEMACCESS(2) " \n"
- "lea " MEMLEA(0x04,2) ",%2 \n"
- "jge 10b \n"
- "19: \n"
- : "+r"(src_argb), // %0
- "+r"(src_argb_stride_temp), // %1
- "+r"(dst_argb), // %2
- "+r"(src_dudv), // %3
- "+rm"(width), // %4
- "+r"(temp) // %5
- :
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
-#endif
- );
-}
-#endif // HAS_ARGBAFFINEROW_SSE2
-
-#ifdef HAS_INTERPOLATEROW_SSSE3
-// Bilinear filter 16x2 -> 16x1
-void InterpolateRow_SSSE3(uint8* dst_ptr, const uint8* src_ptr,
- ptrdiff_t src_stride, int dst_width,
- int source_y_fraction) {
- asm volatile (
- "sub %1,%0 \n"
- "shr %3 \n"
- "cmp $0x0,%3 \n"
- "je 100f \n"
- "cmp $0x20,%3 \n"
- "je 75f \n"
- "cmp $0x40,%3 \n"
- "je 50f \n"
- "cmp $0x60,%3 \n"
- "je 25f \n"
-
- "movd %3,%%xmm0 \n"
- "neg %3 \n"
- "add $0x80,%3 \n"
- "movd %3,%%xmm5 \n"
- "punpcklbw %%xmm0,%%xmm5 \n"
- "punpcklwd %%xmm5,%%xmm5 \n"
- "pshufd $0x0,%%xmm5,%%xmm5 \n"
-
- // General purpose row blend.
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(1) ",%%xmm0 \n"
- MEMOPREG(movdqa,0x00,1,4,1,xmm2)
- "movdqa %%xmm0,%%xmm1 \n"
- "punpcklbw %%xmm2,%%xmm0 \n"
- "punpckhbw %%xmm2,%%xmm1 \n"
- "pmaddubsw %%xmm5,%%xmm0 \n"
- "pmaddubsw %%xmm5,%%xmm1 \n"
- "psrlw $0x7,%%xmm0 \n"
- "psrlw $0x7,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "sub $0x10,%2 \n"
- BUNDLEALIGN
- MEMOPMEM(movdqa,xmm0,0x00,1,0,1)
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- "jmp 99f \n"
-
- // Blend 25 / 75.
- LABELALIGN
- "25: \n"
- "movdqa " MEMACCESS(1) ",%%xmm0 \n"
- MEMOPREG(movdqa,0x00,1,4,1,xmm1)
- "pavgb %%xmm1,%%xmm0 \n"
- "pavgb %%xmm1,%%xmm0 \n"
- "sub $0x10,%2 \n"
- BUNDLEALIGN
- MEMOPMEM(movdqa,xmm0,0x00,1,0,1)
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 25b \n"
- "jmp 99f \n"
-
- // Blend 50 / 50.
- LABELALIGN
- "50: \n"
- "movdqa " MEMACCESS(1) ",%%xmm0 \n"
- MEMOPREG(movdqa,0x00,1,4,1,xmm1)
- "pavgb %%xmm1,%%xmm0 \n"
- "sub $0x10,%2 \n"
- BUNDLEALIGN
- MEMOPMEM(movdqa,xmm0,0x00,1,0,1)
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 50b \n"
- "jmp 99f \n"
-
- // Blend 75 / 25.
- LABELALIGN
- "75: \n"
- "movdqa " MEMACCESS(1) ",%%xmm1 \n"
- MEMOPREG(movdqa,0x00,1,4,1,xmm0)
- "pavgb %%xmm1,%%xmm0 \n"
- "pavgb %%xmm1,%%xmm0 \n"
- "sub $0x10,%2 \n"
- BUNDLEALIGN
- MEMOPMEM(movdqa,xmm0,0x00,1,0,1)
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 75b \n"
- "jmp 99f \n"
-
- // Blend 100 / 0 - Copy row unchanged.
- LABELALIGN
- "100: \n"
- "movdqa " MEMACCESS(1) ",%%xmm0 \n"
- "sub $0x10,%2 \n"
- MEMOPMEM(movdqa,xmm0,0x00,1,0,1)
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 100b \n"
-
- "99: \n"
- : "+r"(dst_ptr), // %0
- "+r"(src_ptr), // %1
- "+r"(dst_width), // %2
- "+r"(source_y_fraction) // %3
- : "r"((intptr_t)(src_stride)) // %4
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm5"
-#endif
- );
-}
-#endif // HAS_INTERPOLATEROW_SSSE3
-
-#ifdef HAS_INTERPOLATEROW_SSE2
-// Bilinear filter 16x2 -> 16x1
-void InterpolateRow_SSE2(uint8* dst_ptr, const uint8* src_ptr,
- ptrdiff_t src_stride, int dst_width,
- int source_y_fraction) {
- asm volatile (
- "sub %1,%0 \n"
- "shr %3 \n"
- "cmp $0x0,%3 \n"
- "je 100f \n"
- "cmp $0x20,%3 \n"
- "je 75f \n"
- "cmp $0x40,%3 \n"
- "je 50f \n"
- "cmp $0x60,%3 \n"
- "je 25f \n"
-
- "movd %3,%%xmm0 \n"
- "neg %3 \n"
- "add $0x80,%3 \n"
- "movd %3,%%xmm5 \n"
- "punpcklbw %%xmm0,%%xmm5 \n"
- "punpcklwd %%xmm5,%%xmm5 \n"
- "pshufd $0x0,%%xmm5,%%xmm5 \n"
- "pxor %%xmm4,%%xmm4 \n"
-
- // General purpose row blend.
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(1) ",%%xmm0 \n"
- MEMOPREG(movdqa,0x00,1,4,1,xmm2) // movdqa (%1,%4,1),%%xmm2
- "movdqa %%xmm0,%%xmm1 \n"
- "movdqa %%xmm2,%%xmm3 \n"
- "punpcklbw %%xmm4,%%xmm2 \n"
- "punpckhbw %%xmm4,%%xmm3 \n"
- "punpcklbw %%xmm4,%%xmm0 \n"
- "punpckhbw %%xmm4,%%xmm1 \n"
- "psubw %%xmm0,%%xmm2 \n"
- "psubw %%xmm1,%%xmm3 \n"
- "paddw %%xmm2,%%xmm2 \n"
- "paddw %%xmm3,%%xmm3 \n"
- "pmulhw %%xmm5,%%xmm2 \n"
- "pmulhw %%xmm5,%%xmm3 \n"
- "paddw %%xmm2,%%xmm0 \n"
- "paddw %%xmm3,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "sub $0x10,%2 \n"
- BUNDLEALIGN
- MEMOPMEM(movdqa,xmm0,0x00,1,0,1) // movdqa %%xmm0,(%1,%0,1)
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- "jmp 99f \n"
-
- // Blend 25 / 75.
- LABELALIGN
- "25: \n"
- "movdqa " MEMACCESS(1) ",%%xmm0 \n"
- MEMOPREG(movdqa,0x00,1,4,1,xmm1) // movdqa (%1,%4,1),%%xmm1
- "pavgb %%xmm1,%%xmm0 \n"
- "pavgb %%xmm1,%%xmm0 \n"
- "sub $0x10,%2 \n"
- BUNDLEALIGN
- MEMOPMEM(movdqa,xmm0,0x00,1,0,1) // movdqa %%xmm0,(%1,%0,1)
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 25b \n"
- "jmp 99f \n"
-
- // Blend 50 / 50.
- LABELALIGN
- "50: \n"
- "movdqa " MEMACCESS(1) ",%%xmm0 \n"
- MEMOPREG(movdqa,0x00,1,4,1,xmm1) // movdqa (%1,%4,1),%%xmm1
- "pavgb %%xmm1,%%xmm0 \n"
- "sub $0x10,%2 \n"
- BUNDLEALIGN
- MEMOPMEM(movdqa,xmm0,0x00,1,0,1) // movdqa %%xmm0,(%1,%0,1)
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 50b \n"
- "jmp 99f \n"
-
- // Blend 75 / 25.
- LABELALIGN
- "75: \n"
- "movdqa " MEMACCESS(1) ",%%xmm1 \n"
- MEMOPREG(movdqa,0x00,1,4,1,xmm0) // movdqa (%1,%4,1),%%xmm0
- "pavgb %%xmm1,%%xmm0 \n"
- "pavgb %%xmm1,%%xmm0 \n"
- "sub $0x10,%2 \n"
- BUNDLEALIGN
- MEMOPMEM(movdqa,xmm0,0x00,1,0,1) // movdqa %%xmm0,(%1,%0,1)
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 75b \n"
- "jmp 99f \n"
-
- // Blend 100 / 0 - Copy row unchanged.
- LABELALIGN
- "100: \n"
- "movdqa " MEMACCESS(1) ",%%xmm0 \n"
- "sub $0x10,%2 \n"
- MEMOPMEM(movdqa,xmm0,0x00,1,0,1) // movdqa %%xmm0,(%1,%0,1)
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 100b \n"
-
- "99: \n"
- : "+r"(dst_ptr), // %0
- "+r"(src_ptr), // %1
- "+r"(dst_width), // %2
- "+r"(source_y_fraction) // %3
- : "r"((intptr_t)(src_stride)) // %4
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-#endif // HAS_INTERPOLATEROW_SSE2
-
-#ifdef HAS_INTERPOLATEROW_SSSE3
-// Bilinear filter 16x2 -> 16x1
-void InterpolateRow_Unaligned_SSSE3(uint8* dst_ptr, const uint8* src_ptr,
- ptrdiff_t src_stride, int dst_width,
- int source_y_fraction) {
- asm volatile (
- "sub %1,%0 \n"
- "shr %3 \n"
- "cmp $0x0,%3 \n"
- "je 100f \n"
- "cmp $0x20,%3 \n"
- "je 75f \n"
- "cmp $0x40,%3 \n"
- "je 50f \n"
- "cmp $0x60,%3 \n"
- "je 25f \n"
-
- "movd %3,%%xmm0 \n"
- "neg %3 \n"
- "add $0x80,%3 \n"
- "movd %3,%%xmm5 \n"
- "punpcklbw %%xmm0,%%xmm5 \n"
- "punpcklwd %%xmm5,%%xmm5 \n"
- "pshufd $0x0,%%xmm5,%%xmm5 \n"
-
- // General purpose row blend.
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(1) ",%%xmm0 \n"
- MEMOPREG(movdqu,0x00,1,4,1,xmm2)
- "movdqu %%xmm0,%%xmm1 \n"
- "punpcklbw %%xmm2,%%xmm0 \n"
- "punpckhbw %%xmm2,%%xmm1 \n"
- "pmaddubsw %%xmm5,%%xmm0 \n"
- "pmaddubsw %%xmm5,%%xmm1 \n"
- "psrlw $0x7,%%xmm0 \n"
- "psrlw $0x7,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "sub $0x10,%2 \n"
- BUNDLEALIGN
- MEMOPMEM(movdqu,xmm0,0x00,1,0,1)
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- "jmp 99f \n"
-
- // Blend 25 / 75.
- LABELALIGN
- "25: \n"
- "movdqu " MEMACCESS(1) ",%%xmm0 \n"
- MEMOPREG(movdqu,0x00,1,4,1,xmm1)
- "pavgb %%xmm1,%%xmm0 \n"
- "pavgb %%xmm1,%%xmm0 \n"
- "sub $0x10,%2 \n"
- BUNDLEALIGN
- MEMOPMEM(movdqu,xmm0,0x00,1,0,1)
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 25b \n"
- "jmp 99f \n"
-
- // Blend 50 / 50.
- LABELALIGN
- "50: \n"
- "movdqu " MEMACCESS(1) ",%%xmm0 \n"
- MEMOPREG(movdqu,0x00,1,4,1,xmm1)
- "pavgb %%xmm1,%%xmm0 \n"
- "sub $0x10,%2 \n"
- BUNDLEALIGN
- MEMOPMEM(movdqu,xmm0,0x00,1,0,1)
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 50b \n"
- "jmp 99f \n"
-
- // Blend 75 / 25.
- LABELALIGN
- "75: \n"
- "movdqu " MEMACCESS(1) ",%%xmm1 \n"
- MEMOPREG(movdqu,0x00,1,4,1,xmm0)
- "pavgb %%xmm1,%%xmm0 \n"
- "pavgb %%xmm1,%%xmm0 \n"
- "sub $0x10,%2 \n"
- BUNDLEALIGN
- MEMOPMEM(movdqu,xmm0,0x00,1,0,1)
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 75b \n"
- "jmp 99f \n"
-
- // Blend 100 / 0 - Copy row unchanged.
- LABELALIGN
- "100: \n"
- "movdqu " MEMACCESS(1) ",%%xmm0 \n"
- "sub $0x10,%2 \n"
- MEMOPMEM(movdqu,xmm0,0x00,1,0,1)
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 100b \n"
-
- "99: \n"
- : "+r"(dst_ptr), // %0
- "+r"(src_ptr), // %1
- "+r"(dst_width), // %2
- "+r"(source_y_fraction) // %3
- : "r"((intptr_t)(src_stride)) // %4
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm5"
-#endif
- );
-}
-#endif // HAS_INTERPOLATEROW_SSSE3
-
-#ifdef HAS_INTERPOLATEROW_SSE2
-// Bilinear filter 16x2 -> 16x1
-void InterpolateRow_Unaligned_SSE2(uint8* dst_ptr, const uint8* src_ptr,
- ptrdiff_t src_stride, int dst_width,
- int source_y_fraction) {
- asm volatile (
- "sub %1,%0 \n"
- "shr %3 \n"
- "cmp $0x0,%3 \n"
- "je 100f \n"
- "cmp $0x20,%3 \n"
- "je 75f \n"
- "cmp $0x40,%3 \n"
- "je 50f \n"
- "cmp $0x60,%3 \n"
- "je 25f \n"
-
- "movd %3,%%xmm0 \n"
- "neg %3 \n"
- "add $0x80,%3 \n"
- "movd %3,%%xmm5 \n"
- "punpcklbw %%xmm0,%%xmm5 \n"
- "punpcklwd %%xmm5,%%xmm5 \n"
- "pshufd $0x0,%%xmm5,%%xmm5 \n"
- "pxor %%xmm4,%%xmm4 \n"
-
- // General purpose row blend.
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(1) ",%%xmm0 \n"
- MEMOPREG(movdqu,0x00,1,4,1,xmm2) // movdqu (%1,%4,1),%%xmm2
- "movdqu %%xmm0,%%xmm1 \n"
- "movdqu %%xmm2,%%xmm3 \n"
- "punpcklbw %%xmm4,%%xmm2 \n"
- "punpckhbw %%xmm4,%%xmm3 \n"
- "punpcklbw %%xmm4,%%xmm0 \n"
- "punpckhbw %%xmm4,%%xmm1 \n"
- "psubw %%xmm0,%%xmm2 \n"
- "psubw %%xmm1,%%xmm3 \n"
- "paddw %%xmm2,%%xmm2 \n"
- "paddw %%xmm3,%%xmm3 \n"
- "pmulhw %%xmm5,%%xmm2 \n"
- "pmulhw %%xmm5,%%xmm3 \n"
- "paddw %%xmm2,%%xmm0 \n"
- "paddw %%xmm3,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "sub $0x10,%2 \n"
- BUNDLEALIGN
- MEMOPMEM(movdqu,xmm0,0x00,1,0,1) // movdqu %%xmm0,(%1,%0,1)
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- "jmp 99f \n"
-
- // Blend 25 / 75.
- LABELALIGN
- "25: \n"
- "movdqu " MEMACCESS(1) ",%%xmm0 \n"
- MEMOPREG(movdqu,0x00,1,4,1,xmm1) // movdqu (%1,%4,1),%%xmm1
- "pavgb %%xmm1,%%xmm0 \n"
- "pavgb %%xmm1,%%xmm0 \n"
- "sub $0x10,%2 \n"
- BUNDLEALIGN
- MEMOPMEM(movdqu,xmm0,0x00,1,0,1) // movdqu %%xmm0,(%1,%0,1)
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 25b \n"
- "jmp 99f \n"
-
- // Blend 50 / 50.
- LABELALIGN
- "50: \n"
- "movdqu " MEMACCESS(1) ",%%xmm0 \n"
- MEMOPREG(movdqu,0x00,1,4,1,xmm1) // movdqu (%1,%4,1),%%xmm1
- "pavgb %%xmm1,%%xmm0 \n"
- "sub $0x10,%2 \n"
- BUNDLEALIGN
- MEMOPMEM(movdqu,xmm0,0x00,1,0,1) // movdqu %%xmm0,(%1,%0,1)
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 50b \n"
- "jmp 99f \n"
-
- // Blend 75 / 25.
- LABELALIGN
- "75: \n"
- "movdqu " MEMACCESS(1) ",%%xmm1 \n"
- MEMOPREG(movdqu,0x00,1,4,1,xmm0) // movdqu (%1,%4,1),%%xmm0
- "pavgb %%xmm1,%%xmm0 \n"
- "pavgb %%xmm1,%%xmm0 \n"
- "sub $0x10,%2 \n"
- BUNDLEALIGN
- MEMOPMEM(movdqu,xmm0,0x00,1,0,1) // movdqu %%xmm0,(%1,%0,1)
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 75b \n"
- "jmp 99f \n"
-
- // Blend 100 / 0 - Copy row unchanged.
- LABELALIGN
- "100: \n"
- "movdqu " MEMACCESS(1) ",%%xmm0 \n"
- "sub $0x10,%2 \n"
- MEMOPMEM(movdqu,xmm0,0x00,1,0,1) // movdqu %%xmm0,(%1,%0,1)
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 100b \n"
-
- "99: \n"
- : "+r"(dst_ptr), // %0
- "+r"(src_ptr), // %1
- "+r"(dst_width), // %2
- "+r"(source_y_fraction) // %3
- : "r"((intptr_t)(src_stride)) // %4
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-#endif // HAS_INTERPOLATEROW_SSE2
-
-#ifdef HAS_HALFROW_SSE2
-void HalfRow_SSE2(const uint8* src_uv, int src_uv_stride,
- uint8* dst_uv, int pix) {
- asm volatile (
- "sub %0,%1 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- MEMOPREG(pavgb,0x00,0,3,1,xmm0) // pavgb (%0,%3),%%xmm0
- "sub $0x10,%2 \n"
- MEMOPMEM(movdqa,xmm0,0x00,0,1,1) // movdqa %%xmm0,(%0,%1)
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "jg 1b \n"
- : "+r"(src_uv), // %0
- "+r"(dst_uv), // %1
- "+r"(pix) // %2
- : "r"((intptr_t)(src_uv_stride)) // %3
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0"
-#endif
- );
-}
-#endif // HAS_HALFROW_SSE2
-
-#ifdef HAS_ARGBTOBAYERROW_SSSE3
-void ARGBToBayerRow_SSSE3(const uint8* src_argb, uint8* dst_bayer,
- uint32 selector, int pix) {
- asm volatile (
- // NaCL caveat - assumes movd is from GPR
- "movd %3,%%xmm5 \n"
- "pshufd $0x0,%%xmm5,%%xmm5 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "pshufb %%xmm5,%%xmm0 \n"
- "pshufb %%xmm5,%%xmm1 \n"
- "punpckldq %%xmm1,%%xmm0 \n"
- "sub $0x8,%2 \n"
- "movq %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_bayer), // %1
- "+r"(pix) // %2
- : "g"(selector) // %3
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm5"
-#endif
- );
-}
-#endif // HAS_ARGBTOBAYERROW_SSSE3
-
-#ifdef HAS_ARGBTOBAYERGGROW_SSE2
-void ARGBToBayerGGRow_SSE2(const uint8* src_argb, uint8* dst_bayer,
- uint32 selector, int pix) {
- asm volatile (
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "psrld $0x18,%%xmm5 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "psrld $0x8,%%xmm0 \n"
- "psrld $0x8,%%xmm1 \n"
- "pand %%xmm5,%%xmm0 \n"
- "pand %%xmm5,%%xmm1 \n"
- "packssdw %%xmm1,%%xmm0 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "sub $0x8,%2 \n"
- "movq %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_bayer), // %1
- "+r"(pix) // %2
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm5"
-#endif
- );
-}
-#endif // HAS_ARGBTOBAYERGGROW_SSE2
-
-#ifdef HAS_ARGBSHUFFLEROW_SSSE3
-// For BGRAToARGB, ABGRToARGB, RGBAToARGB, and ARGBToRGBA.
-void ARGBShuffleRow_SSSE3(const uint8* src_argb, uint8* dst_argb,
- const uint8* shuffler, int pix) {
- asm volatile (
- "movdqa " MEMACCESS(3) ",%%xmm5 \n"
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "pshufb %%xmm5,%%xmm0 \n"
- "pshufb %%xmm5,%%xmm1 \n"
- "sub $0x8,%2 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "movdqa %%xmm1," MEMACCESS2(0x10,1) " \n"
- "lea " MEMLEA(0x20,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_argb), // %1
- "+r"(pix) // %2
- : "r"(shuffler) // %3
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm5"
-#endif
- );
-}
-
-void ARGBShuffleRow_Unaligned_SSSE3(const uint8* src_argb, uint8* dst_argb,
- const uint8* shuffler, int pix) {
- asm volatile (
- "movdqa " MEMACCESS(3) ",%%xmm5 \n"
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "pshufb %%xmm5,%%xmm0 \n"
- "pshufb %%xmm5,%%xmm1 \n"
- "sub $0x8,%2 \n"
- "movdqu %%xmm0," MEMACCESS(1) " \n"
- "movdqu %%xmm1," MEMACCESS2(0x10,1) " \n"
- "lea " MEMLEA(0x20,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_argb), // %1
- "+r"(pix) // %2
- : "r"(shuffler) // %3
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm5"
-#endif
- );
-}
-#endif // HAS_ARGBSHUFFLEROW_SSSE3
-
-#ifdef HAS_ARGBSHUFFLEROW_AVX2
-// For BGRAToARGB, ABGRToARGB, RGBAToARGB, and ARGBToRGBA.
-void ARGBShuffleRow_AVX2(const uint8* src_argb, uint8* dst_argb,
- const uint8* shuffler, int pix) {
- asm volatile (
- "vbroadcastf128 " MEMACCESS(3) ",%%ymm5 \n"
- LABELALIGN
- "1: \n"
- "vmovdqu " MEMACCESS(0) ",%%ymm0 \n"
- "vmovdqu " MEMACCESS2(0x20,0) ",%%ymm1 \n"
- "lea " MEMLEA(0x40,0) ",%0 \n"
- "vpshufb %%ymm5,%%ymm0,%%ymm0 \n"
- "vpshufb %%ymm5,%%ymm1,%%ymm1 \n"
- "sub $0x10,%2 \n"
- "vmovdqu %%ymm0," MEMACCESS(1) " \n"
- "vmovdqu %%ymm1," MEMACCESS2(0x20,1) " \n"
- "lea " MEMLEA(0x40,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_argb), // %1
- "+r"(pix) // %2
- : "r"(shuffler) // %3
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm5"
-#endif
- );
-}
-#endif // HAS_ARGBSHUFFLEROW_AVX2
-
-#ifdef HAS_ARGBSHUFFLEROW_SSE2
-// For BGRAToARGB, ABGRToARGB, RGBAToARGB, and ARGBToRGBA.
-void ARGBShuffleRow_SSE2(const uint8* src_argb, uint8* dst_argb,
- const uint8* shuffler, int pix) {
- uintptr_t pixel_temp = 0u;
- asm volatile (
- "pxor %%xmm5,%%xmm5 \n"
- "mov " MEMACCESS(4) ",%k2 \n"
- "cmp $0x3000102,%k2 \n"
- "je 3012f \n"
- "cmp $0x10203,%k2 \n"
- "je 123f \n"
- "cmp $0x30201,%k2 \n"
- "je 321f \n"
- "cmp $0x2010003,%k2 \n"
- "je 2103f \n"
-
- LABELALIGN
- "1: \n"
- "movzb " MEMACCESS(4) ",%2 \n"
- MEMOPARG(movzb,0x00,0,2,1,2) " \n" // movzb (%0,%2,1),%2
- "mov %b2," MEMACCESS(1) " \n"
- "movzb " MEMACCESS2(0x1,4) ",%2 \n"
- MEMOPARG(movzb,0x00,0,2,1,2) " \n" // movzb (%0,%2,1),%2
- "mov %b2," MEMACCESS2(0x1,1) " \n"
- BUNDLEALIGN
- "movzb " MEMACCESS2(0x2,4) ",%2 \n"
- MEMOPARG(movzb,0x00,0,2,1,2) " \n" // movzb (%0,%2,1),%2
- "mov %b2," MEMACCESS2(0x2,1) " \n"
- "movzb " MEMACCESS2(0x3,4) ",%2 \n"
- MEMOPARG(movzb,0x00,0,2,1,2) " \n" // movzb (%0,%2,1),%2
- "mov %b2," MEMACCESS2(0x3,1) " \n"
- "lea " MEMLEA(0x4,0) ",%0 \n"
- "lea " MEMLEA(0x4,1) ",%1 \n"
- "sub $0x1,%3 \n"
- "jg 1b \n"
- "jmp 99f \n"
-
- LABELALIGN
- "123: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "punpcklbw %%xmm5,%%xmm0 \n"
- "punpckhbw %%xmm5,%%xmm1 \n"
- "pshufhw $0x1b,%%xmm0,%%xmm0 \n"
- "pshuflw $0x1b,%%xmm0,%%xmm0 \n"
- "pshufhw $0x1b,%%xmm1,%%xmm1 \n"
- "pshuflw $0x1b,%%xmm1,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "sub $0x4,%3 \n"
- "movdqu %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 123b \n"
- "jmp 99f \n"
-
- LABELALIGN
- "321: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "punpcklbw %%xmm5,%%xmm0 \n"
- "punpckhbw %%xmm5,%%xmm1 \n"
- "pshufhw $0x39,%%xmm0,%%xmm0 \n"
- "pshuflw $0x39,%%xmm0,%%xmm0 \n"
- "pshufhw $0x39,%%xmm1,%%xmm1 \n"
- "pshuflw $0x39,%%xmm1,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "sub $0x4,%3 \n"
- "movdqu %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 321b \n"
- "jmp 99f \n"
-
- LABELALIGN
- "2103: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "punpcklbw %%xmm5,%%xmm0 \n"
- "punpckhbw %%xmm5,%%xmm1 \n"
- "pshufhw $0x93,%%xmm0,%%xmm0 \n"
- "pshuflw $0x93,%%xmm0,%%xmm0 \n"
- "pshufhw $0x93,%%xmm1,%%xmm1 \n"
- "pshuflw $0x93,%%xmm1,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "sub $0x4,%3 \n"
- "movdqu %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 2103b \n"
- "jmp 99f \n"
-
- LABELALIGN
- "3012: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "punpcklbw %%xmm5,%%xmm0 \n"
- "punpckhbw %%xmm5,%%xmm1 \n"
- "pshufhw $0xc6,%%xmm0,%%xmm0 \n"
- "pshuflw $0xc6,%%xmm0,%%xmm0 \n"
- "pshufhw $0xc6,%%xmm1,%%xmm1 \n"
- "pshuflw $0xc6,%%xmm1,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "sub $0x4,%3 \n"
- "movdqu %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 3012b \n"
-
- "99: \n"
- : "+r"(src_argb), // %0
- "+r"(dst_argb), // %1
- "+d"(pixel_temp), // %2
- "+r"(pix) // %3
- : "r"(shuffler) // %4
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm5"
-#endif
- );
-}
-#endif // HAS_ARGBSHUFFLEROW_SSE2
-
-#ifdef HAS_I422TOYUY2ROW_SSE2
-void I422ToYUY2Row_SSE2(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_frame, int width) {
- asm volatile (
- "sub %1,%2 \n"
- LABELALIGN
- "1: \n"
- "movq " MEMACCESS(1) ",%%xmm2 \n"
- MEMOPREG(movq,0x00,1,2,1,xmm3) // movq (%1,%2,1),%%xmm3
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "punpcklbw %%xmm3,%%xmm2 \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "punpcklbw %%xmm2,%%xmm0 \n"
- "punpckhbw %%xmm2,%%xmm1 \n"
- "movdqu %%xmm0," MEMACCESS(3) " \n"
- "movdqu %%xmm1," MEMACCESS2(0x10,3) " \n"
- "lea " MEMLEA(0x20,3) ",%3 \n"
- "sub $0x10,%4 \n"
- "jg 1b \n"
- : "+r"(src_y), // %0
- "+r"(src_u), // %1
- "+r"(src_v), // %2
- "+r"(dst_frame), // %3
- "+rm"(width) // %4
- :
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3"
-#endif
- );
-}
-#endif // HAS_I422TOYUY2ROW_SSE2
-
-#ifdef HAS_I422TOUYVYROW_SSE2
-void I422ToUYVYRow_SSE2(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_frame, int width) {
- asm volatile (
- "sub %1,%2 \n"
- LABELALIGN
- "1: \n"
- "movq " MEMACCESS(1) ",%%xmm2 \n"
- MEMOPREG(movq,0x00,1,2,1,xmm3) // movq (%1,%2,1),%%xmm3
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "punpcklbw %%xmm3,%%xmm2 \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa %%xmm2,%%xmm1 \n"
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "punpcklbw %%xmm0,%%xmm1 \n"
- "punpckhbw %%xmm0,%%xmm2 \n"
- "movdqu %%xmm1," MEMACCESS(3) " \n"
- "movdqu %%xmm2," MEMACCESS2(0x10,3) " \n"
- "lea " MEMLEA(0x20,3) ",%3 \n"
- "sub $0x10,%4 \n"
- "jg 1b \n"
- : "+r"(src_y), // %0
- "+r"(src_u), // %1
- "+r"(src_v), // %2
- "+r"(dst_frame), // %3
- "+rm"(width) // %4
- :
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3"
-#endif
- );
-}
-#endif // HAS_I422TOUYVYROW_SSE2
-
-#ifdef HAS_ARGBPOLYNOMIALROW_SSE2
-void ARGBPolynomialRow_SSE2(const uint8* src_argb,
- uint8* dst_argb, const float* poly,
- int width) {
- asm volatile (
- "pxor %%xmm3,%%xmm3 \n"
-
- // 2 pixel loop.
- LABELALIGN
- "1: \n"
- "movq " MEMACCESS(0) ",%%xmm0 \n"
- "lea " MEMLEA(0x8,0) ",%0 \n"
- "punpcklbw %%xmm3,%%xmm0 \n"
- "movdqa %%xmm0,%%xmm4 \n"
- "punpcklwd %%xmm3,%%xmm0 \n"
- "punpckhwd %%xmm3,%%xmm4 \n"
- "cvtdq2ps %%xmm0,%%xmm0 \n"
- "cvtdq2ps %%xmm4,%%xmm4 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "movdqa %%xmm4,%%xmm5 \n"
- "mulps " MEMACCESS2(0x10,3) ",%%xmm0 \n"
- "mulps " MEMACCESS2(0x10,3) ",%%xmm4 \n"
- "addps " MEMACCESS(3) ",%%xmm0 \n"
- "addps " MEMACCESS(3) ",%%xmm4 \n"
- "movdqa %%xmm1,%%xmm2 \n"
- "movdqa %%xmm5,%%xmm6 \n"
- "mulps %%xmm1,%%xmm2 \n"
- "mulps %%xmm5,%%xmm6 \n"
- "mulps %%xmm2,%%xmm1 \n"
- "mulps %%xmm6,%%xmm5 \n"
- "mulps " MEMACCESS2(0x20,3) ",%%xmm2 \n"
- "mulps " MEMACCESS2(0x20,3) ",%%xmm6 \n"
- "mulps " MEMACCESS2(0x30,3) ",%%xmm1 \n"
- "mulps " MEMACCESS2(0x30,3) ",%%xmm5 \n"
- "addps %%xmm2,%%xmm0 \n"
- "addps %%xmm6,%%xmm4 \n"
- "addps %%xmm1,%%xmm0 \n"
- "addps %%xmm5,%%xmm4 \n"
- "cvttps2dq %%xmm0,%%xmm0 \n"
- "cvttps2dq %%xmm4,%%xmm4 \n"
- "packuswb %%xmm4,%%xmm0 \n"
- "packuswb %%xmm0,%%xmm0 \n"
- "sub $0x2,%2 \n"
- "movq %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_argb), // %1
- "+r"(width) // %2
- : "r"(poly) // %3
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"
-#endif
- );
-}
-#endif // HAS_ARGBPOLYNOMIALROW_SSE2
-
-#ifdef HAS_ARGBPOLYNOMIALROW_AVX2
-void ARGBPolynomialRow_AVX2(const uint8* src_argb,
- uint8* dst_argb, const float* poly,
- int width) {
- asm volatile (
- "vbroadcastf128 " MEMACCESS(3) ",%%ymm4 \n"
- "vbroadcastf128 " MEMACCESS2(0x10,3) ",%%ymm5 \n"
- "vbroadcastf128 " MEMACCESS2(0x20,3) ",%%ymm6 \n"
- "vbroadcastf128 " MEMACCESS2(0x30,3) ",%%ymm7 \n"
-
- // 2 pixel loop.
- LABELALIGN
- "1: \n"
- "vpmovzxbd " MEMACCESS(0) ",%%ymm0 \n" // 2 ARGB pixels
- "lea " MEMLEA(0x8,0) ",%0 \n"
- "vcvtdq2ps %%ymm0,%%ymm0 \n" // X 8 floats
- "vmulps %%ymm0,%%ymm0,%%ymm2 \n" // X * X
- "vmulps %%ymm7,%%ymm0,%%ymm3 \n" // C3 * X
- "vfmadd132ps %%ymm5,%%ymm4,%%ymm0 \n" // result = C0 + C1 * X
- "vfmadd231ps %%ymm6,%%ymm2,%%ymm0 \n" // result += C2 * X * X
- "vfmadd231ps %%ymm3,%%ymm2,%%ymm0 \n" // result += C3 * X * X * X
- "vcvttps2dq %%ymm0,%%ymm0 \n"
- "vpackusdw %%ymm0,%%ymm0,%%ymm0 \n"
- "vpermq $0xd8,%%ymm0,%%ymm0 \n"
- "vpackuswb %%xmm0,%%xmm0,%%xmm0 \n"
- "sub $0x2,%2 \n"
- "vmovq %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "jg 1b \n"
- "vzeroupper \n"
- : "+r"(src_argb), // %0
- "+r"(dst_argb), // %1
- "+r"(width) // %2
- : "r"(poly) // %3
- : "memory", "cc"
-#if defined(__SSE2__)
-// TODO(fbarchard): declare ymm usage when applicable.
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
-#endif
- );
-}
-#endif // HAS_ARGBPOLYNOMIALROW_AVX2
-
-#ifdef HAS_ARGBCOLORTABLEROW_X86
-// Tranform ARGB pixels with color table.
-void ARGBColorTableRow_X86(uint8* dst_argb, const uint8* table_argb,
- int width) {
- uintptr_t pixel_temp = 0u;
- asm volatile (
- // 1 pixel loop.
- LABELALIGN
- "1: \n"
- "movzb " MEMACCESS(0) ",%1 \n"
- "lea " MEMLEA(0x4,0) ",%0 \n"
- MEMOPARG(movzb,0x00,3,1,4,1) " \n" // movzb (%3,%1,4),%1
- "mov %b1," MEMACCESS2(-0x4,0) " \n"
- "movzb " MEMACCESS2(-0x3,0) ",%1 \n"
- MEMOPARG(movzb,0x01,3,1,4,1) " \n" // movzb 0x1(%3,%1,4),%1
- "mov %b1," MEMACCESS2(-0x3,0) " \n"
- "movzb " MEMACCESS2(-0x2,0) ",%1 \n"
- MEMOPARG(movzb,0x02,3,1,4,1) " \n" // movzb 0x2(%3,%1,4),%1
- "mov %b1," MEMACCESS2(-0x2,0) " \n"
- "movzb " MEMACCESS2(-0x1,0) ",%1 \n"
- MEMOPARG(movzb,0x03,3,1,4,1) " \n" // movzb 0x3(%3,%1,4),%1
- "mov %b1," MEMACCESS2(-0x1,0) " \n"
- "dec %2 \n"
- "jg 1b \n"
- : "+r"(dst_argb), // %0
- "+d"(pixel_temp), // %1
- "+r"(width) // %2
- : "r"(table_argb) // %3
- : "memory", "cc");
-}
-#endif // HAS_ARGBCOLORTABLEROW_X86
-
-#ifdef HAS_RGBCOLORTABLEROW_X86
-// Tranform RGB pixels with color table.
-void RGBColorTableRow_X86(uint8* dst_argb, const uint8* table_argb, int width) {
- uintptr_t pixel_temp = 0u;
- asm volatile (
- // 1 pixel loop.
- LABELALIGN
- "1: \n"
- "movzb " MEMACCESS(0) ",%1 \n"
- "lea " MEMLEA(0x4,0) ",%0 \n"
- MEMOPARG(movzb,0x00,3,1,4,1) " \n" // movzb (%3,%1,4),%1
- "mov %b1," MEMACCESS2(-0x4,0) " \n"
- "movzb " MEMACCESS2(-0x3,0) ",%1 \n"
- MEMOPARG(movzb,0x01,3,1,4,1) " \n" // movzb 0x1(%3,%1,4),%1
- "mov %b1," MEMACCESS2(-0x3,0) " \n"
- "movzb " MEMACCESS2(-0x2,0) ",%1 \n"
- MEMOPARG(movzb,0x02,3,1,4,1) " \n" // movzb 0x2(%3,%1,4),%1
- "mov %b1," MEMACCESS2(-0x2,0) " \n"
- "dec %2 \n"
- "jg 1b \n"
- : "+r"(dst_argb), // %0
- "+d"(pixel_temp), // %1
- "+r"(width) // %2
- : "r"(table_argb) // %3
- : "memory", "cc");
-}
-#endif // HAS_RGBCOLORTABLEROW_X86
-
-#ifdef HAS_ARGBLUMACOLORTABLEROW_SSSE3
-// Tranform RGB pixels with luma table.
-void ARGBLumaColorTableRow_SSSE3(const uint8* src_argb, uint8* dst_argb,
- int width,
- const uint8* luma, uint32 lumacoeff) {
- uintptr_t pixel_temp = 0u;
- uintptr_t table_temp = 0u;
- asm volatile (
- "movd %6,%%xmm3 \n"
- "pshufd $0x0,%%xmm3,%%xmm3 \n"
- "pcmpeqb %%xmm4,%%xmm4 \n"
- "psllw $0x8,%%xmm4 \n"
- "pxor %%xmm5,%%xmm5 \n"
-
- // 4 pixel loop.
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(2) ",%%xmm0 \n"
- "pmaddubsw %%xmm3,%%xmm0 \n"
- "phaddw %%xmm0,%%xmm0 \n"
- "pand %%xmm4,%%xmm0 \n"
- "punpcklwd %%xmm5,%%xmm0 \n"
- "movd %%xmm0,%k1 \n" // 32 bit offset
- "add %5,%1 \n"
- "pshufd $0x39,%%xmm0,%%xmm0 \n"
-
- "movzb " MEMACCESS(2) ",%0 \n"
- MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0
- "mov %b0," MEMACCESS(3) " \n"
- "movzb " MEMACCESS2(0x1,2) ",%0 \n"
- MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0
- "mov %b0," MEMACCESS2(0x1,3) " \n"
- "movzb " MEMACCESS2(0x2,2) ",%0 \n"
- MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0
- "mov %b0," MEMACCESS2(0x2,3) " \n"
- "movzb " MEMACCESS2(0x3,2) ",%0 \n"
- "mov %b0," MEMACCESS2(0x3,3) " \n"
-
- "movd %%xmm0,%k1 \n" // 32 bit offset
- "add %5,%1 \n"
- "pshufd $0x39,%%xmm0,%%xmm0 \n"
-
- "movzb " MEMACCESS2(0x4,2) ",%0 \n"
- MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0
- "mov %b0," MEMACCESS2(0x4,3) " \n"
- BUNDLEALIGN
- "movzb " MEMACCESS2(0x5,2) ",%0 \n"
- MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0
- "mov %b0," MEMACCESS2(0x5,3) " \n"
- "movzb " MEMACCESS2(0x6,2) ",%0 \n"
- MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0
- "mov %b0," MEMACCESS2(0x6,3) " \n"
- "movzb " MEMACCESS2(0x7,2) ",%0 \n"
- "mov %b0," MEMACCESS2(0x7,3) " \n"
-
- "movd %%xmm0,%k1 \n" // 32 bit offset
- "add %5,%1 \n"
- "pshufd $0x39,%%xmm0,%%xmm0 \n"
-
- "movzb " MEMACCESS2(0x8,2) ",%0 \n"
- MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0
- "mov %b0," MEMACCESS2(0x8,3) " \n"
- "movzb " MEMACCESS2(0x9,2) ",%0 \n"
- MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0
- "mov %b0," MEMACCESS2(0x9,3) " \n"
- "movzb " MEMACCESS2(0xa,2) ",%0 \n"
- MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0
- "mov %b0," MEMACCESS2(0xa,3) " \n"
- "movzb " MEMACCESS2(0xb,2) ",%0 \n"
- "mov %b0," MEMACCESS2(0xb,3) " \n"
-
- "movd %%xmm0,%k1 \n" // 32 bit offset
- "add %5,%1 \n"
-
- "movzb " MEMACCESS2(0xc,2) ",%0 \n"
- MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0
- "mov %b0," MEMACCESS2(0xc,3) " \n"
- "movzb " MEMACCESS2(0xd,2) ",%0 \n"
- MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0
- "mov %b0," MEMACCESS2(0xd,3) " \n"
- "movzb " MEMACCESS2(0xe,2) ",%0 \n"
- MEMOPARG(movzb,0x00,1,0,1,0) " \n" // movzb (%1,%0,1),%0
- "mov %b0," MEMACCESS2(0xe,3) " \n"
- "movzb " MEMACCESS2(0xf,2) ",%0 \n"
- "mov %b0," MEMACCESS2(0xf,3) " \n"
- "sub $0x4,%4 \n"
- "lea " MEMLEA(0x10,2) ",%2 \n"
- "lea " MEMLEA(0x10,3) ",%3 \n"
- "jg 1b \n"
- : "+d"(pixel_temp), // %0
- "+a"(table_temp), // %1
- "+r"(src_argb), // %2
- "+r"(dst_argb), // %3
- "+rm"(width) // %4
- : "r"(luma), // %5
- "rm"(lumacoeff) // %6
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-#endif // HAS_ARGBLUMACOLORTABLEROW_SSSE3
-
-#endif // defined(__x86_64__) || defined(__i386__)
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/row_win.cc b/drivers/theoraplayer/src/YUV/libyuv/src/row_win.cc
deleted file mode 100755
index f13e4d7ae5..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/row_win.cc
+++ /dev/null
@@ -1,7284 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/row.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// This module is for Visual C x86.
-#if !defined(LIBYUV_DISABLE_X86) && defined(_M_IX86) && defined(_MSC_VER)
-
-#ifdef HAS_ARGBTOYROW_SSSE3
-
-// Constants for ARGB.
-static const vec8 kARGBToY = {
- 13, 65, 33, 0, 13, 65, 33, 0, 13, 65, 33, 0, 13, 65, 33, 0
-};
-
-// JPeg full range.
-static const vec8 kARGBToYJ = {
- 15, 75, 38, 0, 15, 75, 38, 0, 15, 75, 38, 0, 15, 75, 38, 0
-};
-
-static const vec8 kARGBToU = {
- 112, -74, -38, 0, 112, -74, -38, 0, 112, -74, -38, 0, 112, -74, -38, 0
-};
-
-static const vec8 kARGBToUJ = {
- 127, -84, -43, 0, 127, -84, -43, 0, 127, -84, -43, 0, 127, -84, -43, 0
-};
-
-static const vec8 kARGBToV = {
- -18, -94, 112, 0, -18, -94, 112, 0, -18, -94, 112, 0, -18, -94, 112, 0,
-};
-
-static const vec8 kARGBToVJ = {
- -20, -107, 127, 0, -20, -107, 127, 0, -20, -107, 127, 0, -20, -107, 127, 0
-};
-
-// vpermd for vphaddw + vpackuswb vpermd.
-static const lvec32 kPermdARGBToY_AVX = {
- 0, 4, 1, 5, 2, 6, 3, 7
-};
-
-// vpshufb for vphaddw + vpackuswb packed to shorts.
-static const lvec8 kShufARGBToUV_AVX = {
- 0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7, 14, 15,
- 0, 1, 8, 9, 2, 3, 10, 11, 4, 5, 12, 13, 6, 7, 14, 15,
-};
-
-// Constants for BGRA.
-static const vec8 kBGRAToY = {
- 0, 33, 65, 13, 0, 33, 65, 13, 0, 33, 65, 13, 0, 33, 65, 13
-};
-
-static const vec8 kBGRAToU = {
- 0, -38, -74, 112, 0, -38, -74, 112, 0, -38, -74, 112, 0, -38, -74, 112
-};
-
-static const vec8 kBGRAToV = {
- 0, 112, -94, -18, 0, 112, -94, -18, 0, 112, -94, -18, 0, 112, -94, -18
-};
-
-// Constants for ABGR.
-static const vec8 kABGRToY = {
- 33, 65, 13, 0, 33, 65, 13, 0, 33, 65, 13, 0, 33, 65, 13, 0
-};
-
-static const vec8 kABGRToU = {
- -38, -74, 112, 0, -38, -74, 112, 0, -38, -74, 112, 0, -38, -74, 112, 0
-};
-
-static const vec8 kABGRToV = {
- 112, -94, -18, 0, 112, -94, -18, 0, 112, -94, -18, 0, 112, -94, -18, 0
-};
-
-// Constants for RGBA.
-static const vec8 kRGBAToY = {
- 0, 13, 65, 33, 0, 13, 65, 33, 0, 13, 65, 33, 0, 13, 65, 33
-};
-
-static const vec8 kRGBAToU = {
- 0, 112, -74, -38, 0, 112, -74, -38, 0, 112, -74, -38, 0, 112, -74, -38
-};
-
-static const vec8 kRGBAToV = {
- 0, -18, -94, 112, 0, -18, -94, 112, 0, -18, -94, 112, 0, -18, -94, 112
-};
-
-static const uvec8 kAddY16 = {
- 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u, 16u
-};
-
-static const vec16 kAddYJ64 = {
- 64, 64, 64, 64, 64, 64, 64, 64
-};
-
-static const uvec8 kAddUV128 = {
- 128u, 128u, 128u, 128u, 128u, 128u, 128u, 128u,
- 128u, 128u, 128u, 128u, 128u, 128u, 128u, 128u
-};
-
-static const uvec16 kAddUVJ128 = {
- 0x8080u, 0x8080u, 0x8080u, 0x8080u, 0x8080u, 0x8080u, 0x8080u, 0x8080u
-};
-
-// Shuffle table for converting RGB24 to ARGB.
-static const uvec8 kShuffleMaskRGB24ToARGB = {
- 0u, 1u, 2u, 12u, 3u, 4u, 5u, 13u, 6u, 7u, 8u, 14u, 9u, 10u, 11u, 15u
-};
-
-// Shuffle table for converting RAW to ARGB.
-static const uvec8 kShuffleMaskRAWToARGB = {
- 2u, 1u, 0u, 12u, 5u, 4u, 3u, 13u, 8u, 7u, 6u, 14u, 11u, 10u, 9u, 15u
-};
-
-// Shuffle table for converting ARGB to RGB24.
-static const uvec8 kShuffleMaskARGBToRGB24 = {
- 0u, 1u, 2u, 4u, 5u, 6u, 8u, 9u, 10u, 12u, 13u, 14u, 128u, 128u, 128u, 128u
-};
-
-// Shuffle table for converting ARGB to RAW.
-static const uvec8 kShuffleMaskARGBToRAW = {
- 2u, 1u, 0u, 6u, 5u, 4u, 10u, 9u, 8u, 14u, 13u, 12u, 128u, 128u, 128u, 128u
-};
-
-// Shuffle table for converting ARGBToRGB24 for I422ToRGB24. First 8 + next 4
-static const uvec8 kShuffleMaskARGBToRGB24_0 = {
- 0u, 1u, 2u, 4u, 5u, 6u, 8u, 9u, 128u, 128u, 128u, 128u, 10u, 12u, 13u, 14u
-};
-
-// Shuffle table for converting ARGB to RAW.
-static const uvec8 kShuffleMaskARGBToRAW_0 = {
- 2u, 1u, 0u, 6u, 5u, 4u, 10u, 9u, 128u, 128u, 128u, 128u, 8u, 14u, 13u, 12u
-};
-
-// Duplicates gray value 3 times and fills in alpha opaque.
-__declspec(naked) __declspec(align(16))
-void I400ToARGBRow_SSE2(const uint8* src_y, uint8* dst_argb, int pix) {
- __asm {
- mov eax, [esp + 4] // src_y
- mov edx, [esp + 8] // dst_argb
- mov ecx, [esp + 12] // pix
- pcmpeqb xmm5, xmm5 // generate mask 0xff000000
- pslld xmm5, 24
-
- align 4
- convertloop:
- movq xmm0, qword ptr [eax]
- lea eax, [eax + 8]
- punpcklbw xmm0, xmm0
- movdqa xmm1, xmm0
- punpcklwd xmm0, xmm0
- punpckhwd xmm1, xmm1
- por xmm0, xmm5
- por xmm1, xmm5
- movdqa [edx], xmm0
- movdqa [edx + 16], xmm1
- lea edx, [edx + 32]
- sub ecx, 8
- jg convertloop
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void I400ToARGBRow_Unaligned_SSE2(const uint8* src_y, uint8* dst_argb,
- int pix) {
- __asm {
- mov eax, [esp + 4] // src_y
- mov edx, [esp + 8] // dst_argb
- mov ecx, [esp + 12] // pix
- pcmpeqb xmm5, xmm5 // generate mask 0xff000000
- pslld xmm5, 24
-
- align 4
- convertloop:
- movq xmm0, qword ptr [eax]
- lea eax, [eax + 8]
- punpcklbw xmm0, xmm0
- movdqa xmm1, xmm0
- punpcklwd xmm0, xmm0
- punpckhwd xmm1, xmm1
- por xmm0, xmm5
- por xmm1, xmm5
- movdqu [edx], xmm0
- movdqu [edx + 16], xmm1
- lea edx, [edx + 32]
- sub ecx, 8
- jg convertloop
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void RGB24ToARGBRow_SSSE3(const uint8* src_rgb24, uint8* dst_argb, int pix) {
- __asm {
- mov eax, [esp + 4] // src_rgb24
- mov edx, [esp + 8] // dst_argb
- mov ecx, [esp + 12] // pix
- pcmpeqb xmm5, xmm5 // generate mask 0xff000000
- pslld xmm5, 24
- movdqa xmm4, kShuffleMaskRGB24ToARGB
-
- align 4
- convertloop:
- movdqu xmm0, [eax]
- movdqu xmm1, [eax + 16]
- movdqu xmm3, [eax + 32]
- lea eax, [eax + 48]
- movdqa xmm2, xmm3
- palignr xmm2, xmm1, 8 // xmm2 = { xmm3[0:3] xmm1[8:15]}
- pshufb xmm2, xmm4
- por xmm2, xmm5
- palignr xmm1, xmm0, 12 // xmm1 = { xmm3[0:7] xmm0[12:15]}
- pshufb xmm0, xmm4
- movdqa [edx + 32], xmm2
- por xmm0, xmm5
- pshufb xmm1, xmm4
- movdqa [edx], xmm0
- por xmm1, xmm5
- palignr xmm3, xmm3, 4 // xmm3 = { xmm3[4:15]}
- pshufb xmm3, xmm4
- movdqa [edx + 16], xmm1
- por xmm3, xmm5
- sub ecx, 16
- movdqa [edx + 48], xmm3
- lea edx, [edx + 64]
- jg convertloop
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void RAWToARGBRow_SSSE3(const uint8* src_raw, uint8* dst_argb,
- int pix) {
- __asm {
- mov eax, [esp + 4] // src_raw
- mov edx, [esp + 8] // dst_argb
- mov ecx, [esp + 12] // pix
- pcmpeqb xmm5, xmm5 // generate mask 0xff000000
- pslld xmm5, 24
- movdqa xmm4, kShuffleMaskRAWToARGB
-
- align 4
- convertloop:
- movdqu xmm0, [eax]
- movdqu xmm1, [eax + 16]
- movdqu xmm3, [eax + 32]
- lea eax, [eax + 48]
- movdqa xmm2, xmm3
- palignr xmm2, xmm1, 8 // xmm2 = { xmm3[0:3] xmm1[8:15]}
- pshufb xmm2, xmm4
- por xmm2, xmm5
- palignr xmm1, xmm0, 12 // xmm1 = { xmm3[0:7] xmm0[12:15]}
- pshufb xmm0, xmm4
- movdqa [edx + 32], xmm2
- por xmm0, xmm5
- pshufb xmm1, xmm4
- movdqa [edx], xmm0
- por xmm1, xmm5
- palignr xmm3, xmm3, 4 // xmm3 = { xmm3[4:15]}
- pshufb xmm3, xmm4
- movdqa [edx + 16], xmm1
- por xmm3, xmm5
- sub ecx, 16
- movdqa [edx + 48], xmm3
- lea edx, [edx + 64]
- jg convertloop
- ret
- }
-}
-
-// pmul method to replicate bits.
-// Math to replicate bits:
-// (v << 8) | (v << 3)
-// v * 256 + v * 8
-// v * (256 + 8)
-// G shift of 5 is incorporated, so shift is 5 + 8 and 5 + 3
-// 20 instructions.
-__declspec(naked) __declspec(align(16))
-void RGB565ToARGBRow_SSE2(const uint8* src_rgb565, uint8* dst_argb,
- int pix) {
- __asm {
- mov eax, 0x01080108 // generate multiplier to repeat 5 bits
- movd xmm5, eax
- pshufd xmm5, xmm5, 0
- mov eax, 0x20802080 // multiplier shift by 5 and then repeat 6 bits
- movd xmm6, eax
- pshufd xmm6, xmm6, 0
- pcmpeqb xmm3, xmm3 // generate mask 0xf800f800 for Red
- psllw xmm3, 11
- pcmpeqb xmm4, xmm4 // generate mask 0x07e007e0 for Green
- psllw xmm4, 10
- psrlw xmm4, 5
- pcmpeqb xmm7, xmm7 // generate mask 0xff00ff00 for Alpha
- psllw xmm7, 8
-
- mov eax, [esp + 4] // src_rgb565
- mov edx, [esp + 8] // dst_argb
- mov ecx, [esp + 12] // pix
- sub edx, eax
- sub edx, eax
-
- align 4
- convertloop:
- movdqu xmm0, [eax] // fetch 8 pixels of bgr565
- movdqa xmm1, xmm0
- movdqa xmm2, xmm0
- pand xmm1, xmm3 // R in upper 5 bits
- psllw xmm2, 11 // B in upper 5 bits
- pmulhuw xmm1, xmm5 // * (256 + 8)
- pmulhuw xmm2, xmm5 // * (256 + 8)
- psllw xmm1, 8
- por xmm1, xmm2 // RB
- pand xmm0, xmm4 // G in middle 6 bits
- pmulhuw xmm0, xmm6 // << 5 * (256 + 4)
- por xmm0, xmm7 // AG
- movdqa xmm2, xmm1
- punpcklbw xmm1, xmm0
- punpckhbw xmm2, xmm0
- movdqa [eax * 2 + edx], xmm1 // store 4 pixels of ARGB
- movdqa [eax * 2 + edx + 16], xmm2 // store next 4 pixels of ARGB
- lea eax, [eax + 16]
- sub ecx, 8
- jg convertloop
- ret
- }
-}
-
-// 24 instructions
-__declspec(naked) __declspec(align(16))
-void ARGB1555ToARGBRow_SSE2(const uint8* src_argb1555, uint8* dst_argb,
- int pix) {
- __asm {
- mov eax, 0x01080108 // generate multiplier to repeat 5 bits
- movd xmm5, eax
- pshufd xmm5, xmm5, 0
- mov eax, 0x42004200 // multiplier shift by 6 and then repeat 5 bits
- movd xmm6, eax
- pshufd xmm6, xmm6, 0
- pcmpeqb xmm3, xmm3 // generate mask 0xf800f800 for Red
- psllw xmm3, 11
- movdqa xmm4, xmm3 // generate mask 0x03e003e0 for Green
- psrlw xmm4, 6
- pcmpeqb xmm7, xmm7 // generate mask 0xff00ff00 for Alpha
- psllw xmm7, 8
-
- mov eax, [esp + 4] // src_argb1555
- mov edx, [esp + 8] // dst_argb
- mov ecx, [esp + 12] // pix
- sub edx, eax
- sub edx, eax
-
- align 4
- convertloop:
- movdqu xmm0, [eax] // fetch 8 pixels of 1555
- movdqa xmm1, xmm0
- movdqa xmm2, xmm0
- psllw xmm1, 1 // R in upper 5 bits
- psllw xmm2, 11 // B in upper 5 bits
- pand xmm1, xmm3
- pmulhuw xmm2, xmm5 // * (256 + 8)
- pmulhuw xmm1, xmm5 // * (256 + 8)
- psllw xmm1, 8
- por xmm1, xmm2 // RB
- movdqa xmm2, xmm0
- pand xmm0, xmm4 // G in middle 5 bits
- psraw xmm2, 8 // A
- pmulhuw xmm0, xmm6 // << 6 * (256 + 8)
- pand xmm2, xmm7
- por xmm0, xmm2 // AG
- movdqa xmm2, xmm1
- punpcklbw xmm1, xmm0
- punpckhbw xmm2, xmm0
- movdqa [eax * 2 + edx], xmm1 // store 4 pixels of ARGB
- movdqa [eax * 2 + edx + 16], xmm2 // store next 4 pixels of ARGB
- lea eax, [eax + 16]
- sub ecx, 8
- jg convertloop
- ret
- }
-}
-
-// 18 instructions.
-__declspec(naked) __declspec(align(16))
-void ARGB4444ToARGBRow_SSE2(const uint8* src_argb4444, uint8* dst_argb,
- int pix) {
- __asm {
- mov eax, 0x0f0f0f0f // generate mask 0x0f0f0f0f
- movd xmm4, eax
- pshufd xmm4, xmm4, 0
- movdqa xmm5, xmm4 // 0xf0f0f0f0 for high nibbles
- pslld xmm5, 4
- mov eax, [esp + 4] // src_argb4444
- mov edx, [esp + 8] // dst_argb
- mov ecx, [esp + 12] // pix
- sub edx, eax
- sub edx, eax
-
- align 4
- convertloop:
- movdqu xmm0, [eax] // fetch 8 pixels of bgra4444
- movdqa xmm2, xmm0
- pand xmm0, xmm4 // mask low nibbles
- pand xmm2, xmm5 // mask high nibbles
- movdqa xmm1, xmm0
- movdqa xmm3, xmm2
- psllw xmm1, 4
- psrlw xmm3, 4
- por xmm0, xmm1
- por xmm2, xmm3
- movdqa xmm1, xmm0
- punpcklbw xmm0, xmm2
- punpckhbw xmm1, xmm2
- movdqa [eax * 2 + edx], xmm0 // store 4 pixels of ARGB
- movdqa [eax * 2 + edx + 16], xmm1 // store next 4 pixels of ARGB
- lea eax, [eax + 16]
- sub ecx, 8
- jg convertloop
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void ARGBToRGB24Row_SSSE3(const uint8* src_argb, uint8* dst_rgb, int pix) {
- __asm {
- mov eax, [esp + 4] // src_argb
- mov edx, [esp + 8] // dst_rgb
- mov ecx, [esp + 12] // pix
- movdqa xmm6, kShuffleMaskARGBToRGB24
-
- align 4
- convertloop:
- movdqu xmm0, [eax] // fetch 16 pixels of argb
- movdqu xmm1, [eax + 16]
- movdqu xmm2, [eax + 32]
- movdqu xmm3, [eax + 48]
- lea eax, [eax + 64]
- pshufb xmm0, xmm6 // pack 16 bytes of ARGB to 12 bytes of RGB
- pshufb xmm1, xmm6
- pshufb xmm2, xmm6
- pshufb xmm3, xmm6
- movdqa xmm4, xmm1 // 4 bytes from 1 for 0
- psrldq xmm1, 4 // 8 bytes from 1
- pslldq xmm4, 12 // 4 bytes from 1 for 0
- movdqa xmm5, xmm2 // 8 bytes from 2 for 1
- por xmm0, xmm4 // 4 bytes from 1 for 0
- pslldq xmm5, 8 // 8 bytes from 2 for 1
- movdqu [edx], xmm0 // store 0
- por xmm1, xmm5 // 8 bytes from 2 for 1
- psrldq xmm2, 8 // 4 bytes from 2
- pslldq xmm3, 4 // 12 bytes from 3 for 2
- por xmm2, xmm3 // 12 bytes from 3 for 2
- movdqu [edx + 16], xmm1 // store 1
- movdqu [edx + 32], xmm2 // store 2
- lea edx, [edx + 48]
- sub ecx, 16
- jg convertloop
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void ARGBToRAWRow_SSSE3(const uint8* src_argb, uint8* dst_rgb, int pix) {
- __asm {
- mov eax, [esp + 4] // src_argb
- mov edx, [esp + 8] // dst_rgb
- mov ecx, [esp + 12] // pix
- movdqa xmm6, kShuffleMaskARGBToRAW
-
- align 4
- convertloop:
- movdqu xmm0, [eax] // fetch 16 pixels of argb
- movdqu xmm1, [eax + 16]
- movdqu xmm2, [eax + 32]
- movdqu xmm3, [eax + 48]
- lea eax, [eax + 64]
- pshufb xmm0, xmm6 // pack 16 bytes of ARGB to 12 bytes of RGB
- pshufb xmm1, xmm6
- pshufb xmm2, xmm6
- pshufb xmm3, xmm6
- movdqa xmm4, xmm1 // 4 bytes from 1 for 0
- psrldq xmm1, 4 // 8 bytes from 1
- pslldq xmm4, 12 // 4 bytes from 1 for 0
- movdqa xmm5, xmm2 // 8 bytes from 2 for 1
- por xmm0, xmm4 // 4 bytes from 1 for 0
- pslldq xmm5, 8 // 8 bytes from 2 for 1
- movdqu [edx], xmm0 // store 0
- por xmm1, xmm5 // 8 bytes from 2 for 1
- psrldq xmm2, 8 // 4 bytes from 2
- pslldq xmm3, 4 // 12 bytes from 3 for 2
- por xmm2, xmm3 // 12 bytes from 3 for 2
- movdqu [edx + 16], xmm1 // store 1
- movdqu [edx + 32], xmm2 // store 2
- lea edx, [edx + 48]
- sub ecx, 16
- jg convertloop
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void ARGBToRGB565Row_SSE2(const uint8* src_argb, uint8* dst_rgb, int pix) {
- __asm {
- mov eax, [esp + 4] // src_argb
- mov edx, [esp + 8] // dst_rgb
- mov ecx, [esp + 12] // pix
- pcmpeqb xmm3, xmm3 // generate mask 0x0000001f
- psrld xmm3, 27
- pcmpeqb xmm4, xmm4 // generate mask 0x000007e0
- psrld xmm4, 26
- pslld xmm4, 5
- pcmpeqb xmm5, xmm5 // generate mask 0xfffff800
- pslld xmm5, 11
-
- align 4
- convertloop:
- movdqa xmm0, [eax] // fetch 4 pixels of argb
- movdqa xmm1, xmm0 // B
- movdqa xmm2, xmm0 // G
- pslld xmm0, 8 // R
- psrld xmm1, 3 // B
- psrld xmm2, 5 // G
- psrad xmm0, 16 // R
- pand xmm1, xmm3 // B
- pand xmm2, xmm4 // G
- pand xmm0, xmm5 // R
- por xmm1, xmm2 // BG
- por xmm0, xmm1 // BGR
- packssdw xmm0, xmm0
- lea eax, [eax + 16]
- movq qword ptr [edx], xmm0 // store 4 pixels of RGB565
- lea edx, [edx + 8]
- sub ecx, 4
- jg convertloop
- ret
- }
-}
-
-// TODO(fbarchard): Improve sign extension/packing.
-__declspec(naked) __declspec(align(16))
-void ARGBToARGB1555Row_SSE2(const uint8* src_argb, uint8* dst_rgb, int pix) {
- __asm {
- mov eax, [esp + 4] // src_argb
- mov edx, [esp + 8] // dst_rgb
- mov ecx, [esp + 12] // pix
- pcmpeqb xmm4, xmm4 // generate mask 0x0000001f
- psrld xmm4, 27
- movdqa xmm5, xmm4 // generate mask 0x000003e0
- pslld xmm5, 5
- movdqa xmm6, xmm4 // generate mask 0x00007c00
- pslld xmm6, 10
- pcmpeqb xmm7, xmm7 // generate mask 0xffff8000
- pslld xmm7, 15
-
- align 4
- convertloop:
- movdqa xmm0, [eax] // fetch 4 pixels of argb
- movdqa xmm1, xmm0 // B
- movdqa xmm2, xmm0 // G
- movdqa xmm3, xmm0 // R
- psrad xmm0, 16 // A
- psrld xmm1, 3 // B
- psrld xmm2, 6 // G
- psrld xmm3, 9 // R
- pand xmm0, xmm7 // A
- pand xmm1, xmm4 // B
- pand xmm2, xmm5 // G
- pand xmm3, xmm6 // R
- por xmm0, xmm1 // BA
- por xmm2, xmm3 // GR
- por xmm0, xmm2 // BGRA
- packssdw xmm0, xmm0
- lea eax, [eax + 16]
- movq qword ptr [edx], xmm0 // store 4 pixels of ARGB1555
- lea edx, [edx + 8]
- sub ecx, 4
- jg convertloop
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void ARGBToARGB4444Row_SSE2(const uint8* src_argb, uint8* dst_rgb, int pix) {
- __asm {
- mov eax, [esp + 4] // src_argb
- mov edx, [esp + 8] // dst_rgb
- mov ecx, [esp + 12] // pix
- pcmpeqb xmm4, xmm4 // generate mask 0xf000f000
- psllw xmm4, 12
- movdqa xmm3, xmm4 // generate mask 0x00f000f0
- psrlw xmm3, 8
-
- align 4
- convertloop:
- movdqa xmm0, [eax] // fetch 4 pixels of argb
- movdqa xmm1, xmm0
- pand xmm0, xmm3 // low nibble
- pand xmm1, xmm4 // high nibble
- psrl xmm0, 4
- psrl xmm1, 8
- por xmm0, xmm1
- packuswb xmm0, xmm0
- lea eax, [eax + 16]
- movq qword ptr [edx], xmm0 // store 4 pixels of ARGB4444
- lea edx, [edx + 8]
- sub ecx, 4
- jg convertloop
- ret
- }
-}
-
-// Convert 16 ARGB pixels (64 bytes) to 16 Y values.
-__declspec(naked) __declspec(align(16))
-void ARGBToYRow_SSSE3(const uint8* src_argb, uint8* dst_y, int pix) {
- __asm {
- mov eax, [esp + 4] /* src_argb */
- mov edx, [esp + 8] /* dst_y */
- mov ecx, [esp + 12] /* pix */
- movdqa xmm5, kAddY16
- movdqa xmm4, kARGBToY
-
- align 4
- convertloop:
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- movdqa xmm2, [eax + 32]
- movdqa xmm3, [eax + 48]
- pmaddubsw xmm0, xmm4
- pmaddubsw xmm1, xmm4
- pmaddubsw xmm2, xmm4
- pmaddubsw xmm3, xmm4
- lea eax, [eax + 64]
- phaddw xmm0, xmm1
- phaddw xmm2, xmm3
- psrlw xmm0, 7
- psrlw xmm2, 7
- packuswb xmm0, xmm2
- paddb xmm0, xmm5
- sub ecx, 16
- movdqa [edx], xmm0
- lea edx, [edx + 16]
- jg convertloop
- ret
- }
-}
-
-// Convert 16 ARGB pixels (64 bytes) to 16 Y values.
-__declspec(naked) __declspec(align(16))
-void ARGBToYJRow_SSSE3(const uint8* src_argb, uint8* dst_y, int pix) {
- __asm {
- mov eax, [esp + 4] /* src_argb */
- mov edx, [esp + 8] /* dst_y */
- mov ecx, [esp + 12] /* pix */
- movdqa xmm4, kARGBToYJ
- movdqa xmm5, kAddYJ64
-
- align 4
- convertloop:
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- movdqa xmm2, [eax + 32]
- movdqa xmm3, [eax + 48]
- pmaddubsw xmm0, xmm4
- pmaddubsw xmm1, xmm4
- pmaddubsw xmm2, xmm4
- pmaddubsw xmm3, xmm4
- lea eax, [eax + 64]
- phaddw xmm0, xmm1
- phaddw xmm2, xmm3
- paddw xmm0, xmm5 // Add .5 for rounding.
- paddw xmm2, xmm5
- psrlw xmm0, 7
- psrlw xmm2, 7
- packuswb xmm0, xmm2
- sub ecx, 16
- movdqa [edx], xmm0
- lea edx, [edx + 16]
- jg convertloop
- ret
- }
-}
-
-#ifdef HAS_ARGBTOYROW_AVX2
-// Convert 32 ARGB pixels (128 bytes) to 32 Y values.
-__declspec(naked) __declspec(align(32))
-void ARGBToYRow_AVX2(const uint8* src_argb, uint8* dst_y, int pix) {
- __asm {
- mov eax, [esp + 4] /* src_argb */
- mov edx, [esp + 8] /* dst_y */
- mov ecx, [esp + 12] /* pix */
- vbroadcastf128 ymm4, kARGBToY
- vbroadcastf128 ymm5, kAddY16
- vmovdqa ymm6, kPermdARGBToY_AVX
-
- align 4
- convertloop:
- vmovdqu ymm0, [eax]
- vmovdqu ymm1, [eax + 32]
- vmovdqu ymm2, [eax + 64]
- vmovdqu ymm3, [eax + 96]
- vpmaddubsw ymm0, ymm0, ymm4
- vpmaddubsw ymm1, ymm1, ymm4
- vpmaddubsw ymm2, ymm2, ymm4
- vpmaddubsw ymm3, ymm3, ymm4
- lea eax, [eax + 128]
- vphaddw ymm0, ymm0, ymm1 // mutates.
- vphaddw ymm2, ymm2, ymm3
- vpsrlw ymm0, ymm0, 7
- vpsrlw ymm2, ymm2, 7
- vpackuswb ymm0, ymm0, ymm2 // mutates.
- vpermd ymm0, ymm6, ymm0 // For vphaddw + vpackuswb mutation.
- vpaddb ymm0, ymm0, ymm5
- sub ecx, 32
- vmovdqu [edx], ymm0
- lea edx, [edx + 32]
- jg convertloop
- vzeroupper
- ret
- }
-}
-#endif // HAS_ARGBTOYROW_AVX2
-
-#ifdef HAS_ARGBTOYROW_AVX2
-// Convert 32 ARGB pixels (128 bytes) to 32 Y values.
-__declspec(naked) __declspec(align(32))
-void ARGBToYJRow_AVX2(const uint8* src_argb, uint8* dst_y, int pix) {
- __asm {
- mov eax, [esp + 4] /* src_argb */
- mov edx, [esp + 8] /* dst_y */
- mov ecx, [esp + 12] /* pix */
- vbroadcastf128 ymm4, kARGBToYJ
- vbroadcastf128 ymm5, kAddYJ64
- vmovdqa ymm6, kPermdARGBToY_AVX
-
- align 4
- convertloop:
- vmovdqu ymm0, [eax]
- vmovdqu ymm1, [eax + 32]
- vmovdqu ymm2, [eax + 64]
- vmovdqu ymm3, [eax + 96]
- vpmaddubsw ymm0, ymm0, ymm4
- vpmaddubsw ymm1, ymm1, ymm4
- vpmaddubsw ymm2, ymm2, ymm4
- vpmaddubsw ymm3, ymm3, ymm4
- lea eax, [eax + 128]
- vphaddw ymm0, ymm0, ymm1 // mutates.
- vphaddw ymm2, ymm2, ymm3
- vpaddw ymm0, ymm0, ymm5 // Add .5 for rounding.
- vpaddw ymm2, ymm2, ymm5
- vpsrlw ymm0, ymm0, 7
- vpsrlw ymm2, ymm2, 7
- vpackuswb ymm0, ymm0, ymm2 // mutates.
- vpermd ymm0, ymm6, ymm0 // For vphaddw + vpackuswb mutation.
- sub ecx, 32
- vmovdqu [edx], ymm0
- lea edx, [edx + 32]
- jg convertloop
-
- vzeroupper
- ret
- }
-}
-#endif // HAS_ARGBTOYJROW_AVX2
-
-__declspec(naked) __declspec(align(16))
-void ARGBToYRow_Unaligned_SSSE3(const uint8* src_argb, uint8* dst_y, int pix) {
- __asm {
- mov eax, [esp + 4] /* src_argb */
- mov edx, [esp + 8] /* dst_y */
- mov ecx, [esp + 12] /* pix */
- movdqa xmm5, kAddY16
- movdqa xmm4, kARGBToY
-
- align 4
- convertloop:
- movdqu xmm0, [eax]
- movdqu xmm1, [eax + 16]
- movdqu xmm2, [eax + 32]
- movdqu xmm3, [eax + 48]
- pmaddubsw xmm0, xmm4
- pmaddubsw xmm1, xmm4
- pmaddubsw xmm2, xmm4
- pmaddubsw xmm3, xmm4
- lea eax, [eax + 64]
- phaddw xmm0, xmm1
- phaddw xmm2, xmm3
- psrlw xmm0, 7
- psrlw xmm2, 7
- packuswb xmm0, xmm2
- paddb xmm0, xmm5
- sub ecx, 16
- movdqu [edx], xmm0
- lea edx, [edx + 16]
- jg convertloop
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void ARGBToYJRow_Unaligned_SSSE3(const uint8* src_argb, uint8* dst_y, int pix) {
- __asm {
- mov eax, [esp + 4] /* src_argb */
- mov edx, [esp + 8] /* dst_y */
- mov ecx, [esp + 12] /* pix */
- movdqa xmm4, kARGBToYJ
- movdqa xmm5, kAddYJ64
-
- align 4
- convertloop:
- movdqu xmm0, [eax]
- movdqu xmm1, [eax + 16]
- movdqu xmm2, [eax + 32]
- movdqu xmm3, [eax + 48]
- pmaddubsw xmm0, xmm4
- pmaddubsw xmm1, xmm4
- pmaddubsw xmm2, xmm4
- pmaddubsw xmm3, xmm4
- lea eax, [eax + 64]
- phaddw xmm0, xmm1
- phaddw xmm2, xmm3
- paddw xmm0, xmm5
- paddw xmm2, xmm5
- psrlw xmm0, 7
- psrlw xmm2, 7
- packuswb xmm0, xmm2
- sub ecx, 16
- movdqu [edx], xmm0
- lea edx, [edx + 16]
- jg convertloop
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void BGRAToYRow_SSSE3(const uint8* src_argb, uint8* dst_y, int pix) {
- __asm {
- mov eax, [esp + 4] /* src_argb */
- mov edx, [esp + 8] /* dst_y */
- mov ecx, [esp + 12] /* pix */
- movdqa xmm5, kAddY16
- movdqa xmm4, kBGRAToY
-
- align 4
- convertloop:
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- movdqa xmm2, [eax + 32]
- movdqa xmm3, [eax + 48]
- pmaddubsw xmm0, xmm4
- pmaddubsw xmm1, xmm4
- pmaddubsw xmm2, xmm4
- pmaddubsw xmm3, xmm4
- lea eax, [eax + 64]
- phaddw xmm0, xmm1
- phaddw xmm2, xmm3
- psrlw xmm0, 7
- psrlw xmm2, 7
- packuswb xmm0, xmm2
- paddb xmm0, xmm5
- sub ecx, 16
- movdqa [edx], xmm0
- lea edx, [edx + 16]
- jg convertloop
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void BGRAToYRow_Unaligned_SSSE3(const uint8* src_argb, uint8* dst_y, int pix) {
- __asm {
- mov eax, [esp + 4] /* src_argb */
- mov edx, [esp + 8] /* dst_y */
- mov ecx, [esp + 12] /* pix */
- movdqa xmm5, kAddY16
- movdqa xmm4, kBGRAToY
-
- align 4
- convertloop:
- movdqu xmm0, [eax]
- movdqu xmm1, [eax + 16]
- movdqu xmm2, [eax + 32]
- movdqu xmm3, [eax + 48]
- pmaddubsw xmm0, xmm4
- pmaddubsw xmm1, xmm4
- pmaddubsw xmm2, xmm4
- pmaddubsw xmm3, xmm4
- lea eax, [eax + 64]
- phaddw xmm0, xmm1
- phaddw xmm2, xmm3
- psrlw xmm0, 7
- psrlw xmm2, 7
- packuswb xmm0, xmm2
- paddb xmm0, xmm5
- sub ecx, 16
- movdqu [edx], xmm0
- lea edx, [edx + 16]
- jg convertloop
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void ABGRToYRow_SSSE3(const uint8* src_argb, uint8* dst_y, int pix) {
- __asm {
- mov eax, [esp + 4] /* src_argb */
- mov edx, [esp + 8] /* dst_y */
- mov ecx, [esp + 12] /* pix */
- movdqa xmm5, kAddY16
- movdqa xmm4, kABGRToY
-
- align 4
- convertloop:
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- movdqa xmm2, [eax + 32]
- movdqa xmm3, [eax + 48]
- pmaddubsw xmm0, xmm4
- pmaddubsw xmm1, xmm4
- pmaddubsw xmm2, xmm4
- pmaddubsw xmm3, xmm4
- lea eax, [eax + 64]
- phaddw xmm0, xmm1
- phaddw xmm2, xmm3
- psrlw xmm0, 7
- psrlw xmm2, 7
- packuswb xmm0, xmm2
- paddb xmm0, xmm5
- sub ecx, 16
- movdqa [edx], xmm0
- lea edx, [edx + 16]
- jg convertloop
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void ABGRToYRow_Unaligned_SSSE3(const uint8* src_argb, uint8* dst_y, int pix) {
- __asm {
- mov eax, [esp + 4] /* src_argb */
- mov edx, [esp + 8] /* dst_y */
- mov ecx, [esp + 12] /* pix */
- movdqa xmm5, kAddY16
- movdqa xmm4, kABGRToY
-
- align 4
- convertloop:
- movdqu xmm0, [eax]
- movdqu xmm1, [eax + 16]
- movdqu xmm2, [eax + 32]
- movdqu xmm3, [eax + 48]
- pmaddubsw xmm0, xmm4
- pmaddubsw xmm1, xmm4
- pmaddubsw xmm2, xmm4
- pmaddubsw xmm3, xmm4
- lea eax, [eax + 64]
- phaddw xmm0, xmm1
- phaddw xmm2, xmm3
- psrlw xmm0, 7
- psrlw xmm2, 7
- packuswb xmm0, xmm2
- paddb xmm0, xmm5
- sub ecx, 16
- movdqu [edx], xmm0
- lea edx, [edx + 16]
- jg convertloop
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void RGBAToYRow_SSSE3(const uint8* src_argb, uint8* dst_y, int pix) {
- __asm {
- mov eax, [esp + 4] /* src_argb */
- mov edx, [esp + 8] /* dst_y */
- mov ecx, [esp + 12] /* pix */
- movdqa xmm5, kAddY16
- movdqa xmm4, kRGBAToY
-
- align 4
- convertloop:
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- movdqa xmm2, [eax + 32]
- movdqa xmm3, [eax + 48]
- pmaddubsw xmm0, xmm4
- pmaddubsw xmm1, xmm4
- pmaddubsw xmm2, xmm4
- pmaddubsw xmm3, xmm4
- lea eax, [eax + 64]
- phaddw xmm0, xmm1
- phaddw xmm2, xmm3
- psrlw xmm0, 7
- psrlw xmm2, 7
- packuswb xmm0, xmm2
- paddb xmm0, xmm5
- sub ecx, 16
- movdqa [edx], xmm0
- lea edx, [edx + 16]
- jg convertloop
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void RGBAToYRow_Unaligned_SSSE3(const uint8* src_argb, uint8* dst_y, int pix) {
- __asm {
- mov eax, [esp + 4] /* src_argb */
- mov edx, [esp + 8] /* dst_y */
- mov ecx, [esp + 12] /* pix */
- movdqa xmm5, kAddY16
- movdqa xmm4, kRGBAToY
-
- align 4
- convertloop:
- movdqu xmm0, [eax]
- movdqu xmm1, [eax + 16]
- movdqu xmm2, [eax + 32]
- movdqu xmm3, [eax + 48]
- pmaddubsw xmm0, xmm4
- pmaddubsw xmm1, xmm4
- pmaddubsw xmm2, xmm4
- pmaddubsw xmm3, xmm4
- lea eax, [eax + 64]
- phaddw xmm0, xmm1
- phaddw xmm2, xmm3
- psrlw xmm0, 7
- psrlw xmm2, 7
- packuswb xmm0, xmm2
- paddb xmm0, xmm5
- sub ecx, 16
- movdqu [edx], xmm0
- lea edx, [edx + 16]
- jg convertloop
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void ARGBToUVRow_SSSE3(const uint8* src_argb0, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // src_argb
- mov esi, [esp + 8 + 8] // src_stride_argb
- mov edx, [esp + 8 + 12] // dst_u
- mov edi, [esp + 8 + 16] // dst_v
- mov ecx, [esp + 8 + 20] // pix
- movdqa xmm7, kARGBToU
- movdqa xmm6, kARGBToV
- movdqa xmm5, kAddUV128
- sub edi, edx // stride from u to v
-
- align 4
- convertloop:
- /* step 1 - subsample 16x2 argb pixels to 8x1 */
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- movdqa xmm2, [eax + 32]
- movdqa xmm3, [eax + 48]
- pavgb xmm0, [eax + esi]
- pavgb xmm1, [eax + esi + 16]
- pavgb xmm2, [eax + esi + 32]
- pavgb xmm3, [eax + esi + 48]
- lea eax, [eax + 64]
- movdqa xmm4, xmm0
- shufps xmm0, xmm1, 0x88
- shufps xmm4, xmm1, 0xdd
- pavgb xmm0, xmm4
- movdqa xmm4, xmm2
- shufps xmm2, xmm3, 0x88
- shufps xmm4, xmm3, 0xdd
- pavgb xmm2, xmm4
-
- // step 2 - convert to U and V
- // from here down is very similar to Y code except
- // instead of 16 different pixels, its 8 pixels of U and 8 of V
- movdqa xmm1, xmm0
- movdqa xmm3, xmm2
- pmaddubsw xmm0, xmm7 // U
- pmaddubsw xmm2, xmm7
- pmaddubsw xmm1, xmm6 // V
- pmaddubsw xmm3, xmm6
- phaddw xmm0, xmm2
- phaddw xmm1, xmm3
- psraw xmm0, 8
- psraw xmm1, 8
- packsswb xmm0, xmm1
- paddb xmm0, xmm5 // -> unsigned
-
- // step 3 - store 8 U and 8 V values
- sub ecx, 16
- movlps qword ptr [edx], xmm0 // U
- movhps qword ptr [edx + edi], xmm0 // V
- lea edx, [edx + 8]
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void ARGBToUVJRow_SSSE3(const uint8* src_argb0, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // src_argb
- mov esi, [esp + 8 + 8] // src_stride_argb
- mov edx, [esp + 8 + 12] // dst_u
- mov edi, [esp + 8 + 16] // dst_v
- mov ecx, [esp + 8 + 20] // pix
- movdqa xmm7, kARGBToUJ
- movdqa xmm6, kARGBToVJ
- movdqa xmm5, kAddUVJ128
- sub edi, edx // stride from u to v
-
- align 4
- convertloop:
- /* step 1 - subsample 16x2 argb pixels to 8x1 */
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- movdqa xmm2, [eax + 32]
- movdqa xmm3, [eax + 48]
- pavgb xmm0, [eax + esi]
- pavgb xmm1, [eax + esi + 16]
- pavgb xmm2, [eax + esi + 32]
- pavgb xmm3, [eax + esi + 48]
- lea eax, [eax + 64]
- movdqa xmm4, xmm0
- shufps xmm0, xmm1, 0x88
- shufps xmm4, xmm1, 0xdd
- pavgb xmm0, xmm4
- movdqa xmm4, xmm2
- shufps xmm2, xmm3, 0x88
- shufps xmm4, xmm3, 0xdd
- pavgb xmm2, xmm4
-
- // step 2 - convert to U and V
- // from here down is very similar to Y code except
- // instead of 16 different pixels, its 8 pixels of U and 8 of V
- movdqa xmm1, xmm0
- movdqa xmm3, xmm2
- pmaddubsw xmm0, xmm7 // U
- pmaddubsw xmm2, xmm7
- pmaddubsw xmm1, xmm6 // V
- pmaddubsw xmm3, xmm6
- phaddw xmm0, xmm2
- phaddw xmm1, xmm3
- paddw xmm0, xmm5 // +.5 rounding -> unsigned
- paddw xmm1, xmm5
- psraw xmm0, 8
- psraw xmm1, 8
- packsswb xmm0, xmm1
-
- // step 3 - store 8 U and 8 V values
- sub ecx, 16
- movlps qword ptr [edx], xmm0 // U
- movhps qword ptr [edx + edi], xmm0 // V
- lea edx, [edx + 8]
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-#ifdef HAS_ARGBTOUVROW_AVX2
-__declspec(naked) __declspec(align(32))
-void ARGBToUVRow_AVX2(const uint8* src_argb0, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // src_argb
- mov esi, [esp + 8 + 8] // src_stride_argb
- mov edx, [esp + 8 + 12] // dst_u
- mov edi, [esp + 8 + 16] // dst_v
- mov ecx, [esp + 8 + 20] // pix
- vbroadcastf128 ymm5, kAddUV128
- vbroadcastf128 ymm6, kARGBToV
- vbroadcastf128 ymm7, kARGBToU
- sub edi, edx // stride from u to v
-
- align 4
- convertloop:
- /* step 1 - subsample 32x2 argb pixels to 16x1 */
- vmovdqu ymm0, [eax]
- vmovdqu ymm1, [eax + 32]
- vmovdqu ymm2, [eax + 64]
- vmovdqu ymm3, [eax + 96]
- vpavgb ymm0, ymm0, [eax + esi]
- vpavgb ymm1, ymm1, [eax + esi + 32]
- vpavgb ymm2, ymm2, [eax + esi + 64]
- vpavgb ymm3, ymm3, [eax + esi + 96]
- lea eax, [eax + 128]
- vshufps ymm4, ymm0, ymm1, 0x88
- vshufps ymm0, ymm0, ymm1, 0xdd
- vpavgb ymm0, ymm0, ymm4 // mutated by vshufps
- vshufps ymm4, ymm2, ymm3, 0x88
- vshufps ymm2, ymm2, ymm3, 0xdd
- vpavgb ymm2, ymm2, ymm4 // mutated by vshufps
-
- // step 2 - convert to U and V
- // from here down is very similar to Y code except
- // instead of 32 different pixels, its 16 pixels of U and 16 of V
- vpmaddubsw ymm1, ymm0, ymm7 // U
- vpmaddubsw ymm3, ymm2, ymm7
- vpmaddubsw ymm0, ymm0, ymm6 // V
- vpmaddubsw ymm2, ymm2, ymm6
- vphaddw ymm1, ymm1, ymm3 // mutates
- vphaddw ymm0, ymm0, ymm2
- vpsraw ymm1, ymm1, 8
- vpsraw ymm0, ymm0, 8
- vpacksswb ymm0, ymm1, ymm0 // mutates
- vpermq ymm0, ymm0, 0xd8 // For vpacksswb
- vpshufb ymm0, ymm0, kShufARGBToUV_AVX // For vshufps + vphaddw
- vpaddb ymm0, ymm0, ymm5 // -> unsigned
-
- // step 3 - store 16 U and 16 V values
- sub ecx, 32
- vextractf128 [edx], ymm0, 0 // U
- vextractf128 [edx + edi], ymm0, 1 // V
- lea edx, [edx + 16]
- jg convertloop
-
- pop edi
- pop esi
- vzeroupper
- ret
- }
-}
-#endif // HAS_ARGBTOUVROW_AVX2
-
-__declspec(naked) __declspec(align(16))
-void ARGBToUVRow_Unaligned_SSSE3(const uint8* src_argb0, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // src_argb
- mov esi, [esp + 8 + 8] // src_stride_argb
- mov edx, [esp + 8 + 12] // dst_u
- mov edi, [esp + 8 + 16] // dst_v
- mov ecx, [esp + 8 + 20] // pix
- movdqa xmm7, kARGBToU
- movdqa xmm6, kARGBToV
- movdqa xmm5, kAddUV128
- sub edi, edx // stride from u to v
-
- align 4
- convertloop:
- /* step 1 - subsample 16x2 argb pixels to 8x1 */
- movdqu xmm0, [eax]
- movdqu xmm1, [eax + 16]
- movdqu xmm2, [eax + 32]
- movdqu xmm3, [eax + 48]
- movdqu xmm4, [eax + esi]
- pavgb xmm0, xmm4
- movdqu xmm4, [eax + esi + 16]
- pavgb xmm1, xmm4
- movdqu xmm4, [eax + esi + 32]
- pavgb xmm2, xmm4
- movdqu xmm4, [eax + esi + 48]
- pavgb xmm3, xmm4
- lea eax, [eax + 64]
- movdqa xmm4, xmm0
- shufps xmm0, xmm1, 0x88
- shufps xmm4, xmm1, 0xdd
- pavgb xmm0, xmm4
- movdqa xmm4, xmm2
- shufps xmm2, xmm3, 0x88
- shufps xmm4, xmm3, 0xdd
- pavgb xmm2, xmm4
-
- // step 2 - convert to U and V
- // from here down is very similar to Y code except
- // instead of 16 different pixels, its 8 pixels of U and 8 of V
- movdqa xmm1, xmm0
- movdqa xmm3, xmm2
- pmaddubsw xmm0, xmm7 // U
- pmaddubsw xmm2, xmm7
- pmaddubsw xmm1, xmm6 // V
- pmaddubsw xmm3, xmm6
- phaddw xmm0, xmm2
- phaddw xmm1, xmm3
- psraw xmm0, 8
- psraw xmm1, 8
- packsswb xmm0, xmm1
- paddb xmm0, xmm5 // -> unsigned
-
- // step 3 - store 8 U and 8 V values
- sub ecx, 16
- movlps qword ptr [edx], xmm0 // U
- movhps qword ptr [edx + edi], xmm0 // V
- lea edx, [edx + 8]
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void ARGBToUVJRow_Unaligned_SSSE3(const uint8* src_argb0, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // src_argb
- mov esi, [esp + 8 + 8] // src_stride_argb
- mov edx, [esp + 8 + 12] // dst_u
- mov edi, [esp + 8 + 16] // dst_v
- mov ecx, [esp + 8 + 20] // pix
- movdqa xmm7, kARGBToUJ
- movdqa xmm6, kARGBToVJ
- movdqa xmm5, kAddUVJ128
- sub edi, edx // stride from u to v
-
- align 4
- convertloop:
- /* step 1 - subsample 16x2 argb pixels to 8x1 */
- movdqu xmm0, [eax]
- movdqu xmm1, [eax + 16]
- movdqu xmm2, [eax + 32]
- movdqu xmm3, [eax + 48]
- movdqu xmm4, [eax + esi]
- pavgb xmm0, xmm4
- movdqu xmm4, [eax + esi + 16]
- pavgb xmm1, xmm4
- movdqu xmm4, [eax + esi + 32]
- pavgb xmm2, xmm4
- movdqu xmm4, [eax + esi + 48]
- pavgb xmm3, xmm4
- lea eax, [eax + 64]
- movdqa xmm4, xmm0
- shufps xmm0, xmm1, 0x88
- shufps xmm4, xmm1, 0xdd
- pavgb xmm0, xmm4
- movdqa xmm4, xmm2
- shufps xmm2, xmm3, 0x88
- shufps xmm4, xmm3, 0xdd
- pavgb xmm2, xmm4
-
- // step 2 - convert to U and V
- // from here down is very similar to Y code except
- // instead of 16 different pixels, its 8 pixels of U and 8 of V
- movdqa xmm1, xmm0
- movdqa xmm3, xmm2
- pmaddubsw xmm0, xmm7 // U
- pmaddubsw xmm2, xmm7
- pmaddubsw xmm1, xmm6 // V
- pmaddubsw xmm3, xmm6
- phaddw xmm0, xmm2
- phaddw xmm1, xmm3
- paddw xmm0, xmm5 // +.5 rounding -> unsigned
- paddw xmm1, xmm5
- psraw xmm0, 8
- psraw xmm1, 8
- packsswb xmm0, xmm1
-
- // step 3 - store 8 U and 8 V values
- sub ecx, 16
- movlps qword ptr [edx], xmm0 // U
- movhps qword ptr [edx + edi], xmm0 // V
- lea edx, [edx + 8]
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void ARGBToUV444Row_SSSE3(const uint8* src_argb0,
- uint8* dst_u, uint8* dst_v, int width) {
- __asm {
- push edi
- mov eax, [esp + 4 + 4] // src_argb
- mov edx, [esp + 4 + 8] // dst_u
- mov edi, [esp + 4 + 12] // dst_v
- mov ecx, [esp + 4 + 16] // pix
- movdqa xmm7, kARGBToU
- movdqa xmm6, kARGBToV
- movdqa xmm5, kAddUV128
- sub edi, edx // stride from u to v
-
- align 4
- convertloop:
- /* convert to U and V */
- movdqa xmm0, [eax] // U
- movdqa xmm1, [eax + 16]
- movdqa xmm2, [eax + 32]
- movdqa xmm3, [eax + 48]
- pmaddubsw xmm0, xmm7
- pmaddubsw xmm1, xmm7
- pmaddubsw xmm2, xmm7
- pmaddubsw xmm3, xmm7
- phaddw xmm0, xmm1
- phaddw xmm2, xmm3
- psraw xmm0, 8
- psraw xmm2, 8
- packsswb xmm0, xmm2
- paddb xmm0, xmm5
- sub ecx, 16
- movdqa [edx], xmm0
-
- movdqa xmm0, [eax] // V
- movdqa xmm1, [eax + 16]
- movdqa xmm2, [eax + 32]
- movdqa xmm3, [eax + 48]
- pmaddubsw xmm0, xmm6
- pmaddubsw xmm1, xmm6
- pmaddubsw xmm2, xmm6
- pmaddubsw xmm3, xmm6
- phaddw xmm0, xmm1
- phaddw xmm2, xmm3
- psraw xmm0, 8
- psraw xmm2, 8
- packsswb xmm0, xmm2
- paddb xmm0, xmm5
- lea eax, [eax + 64]
- movdqa [edx + edi], xmm0
- lea edx, [edx + 16]
- jg convertloop
-
- pop edi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void ARGBToUV444Row_Unaligned_SSSE3(const uint8* src_argb0,
- uint8* dst_u, uint8* dst_v, int width) {
- __asm {
- push edi
- mov eax, [esp + 4 + 4] // src_argb
- mov edx, [esp + 4 + 8] // dst_u
- mov edi, [esp + 4 + 12] // dst_v
- mov ecx, [esp + 4 + 16] // pix
- movdqa xmm7, kARGBToU
- movdqa xmm6, kARGBToV
- movdqa xmm5, kAddUV128
- sub edi, edx // stride from u to v
-
- align 4
- convertloop:
- /* convert to U and V */
- movdqu xmm0, [eax] // U
- movdqu xmm1, [eax + 16]
- movdqu xmm2, [eax + 32]
- movdqu xmm3, [eax + 48]
- pmaddubsw xmm0, xmm7
- pmaddubsw xmm1, xmm7
- pmaddubsw xmm2, xmm7
- pmaddubsw xmm3, xmm7
- phaddw xmm0, xmm1
- phaddw xmm2, xmm3
- psraw xmm0, 8
- psraw xmm2, 8
- packsswb xmm0, xmm2
- paddb xmm0, xmm5
- sub ecx, 16
- movdqu [edx], xmm0
-
- movdqu xmm0, [eax] // V
- movdqu xmm1, [eax + 16]
- movdqu xmm2, [eax + 32]
- movdqu xmm3, [eax + 48]
- pmaddubsw xmm0, xmm6
- pmaddubsw xmm1, xmm6
- pmaddubsw xmm2, xmm6
- pmaddubsw xmm3, xmm6
- phaddw xmm0, xmm1
- phaddw xmm2, xmm3
- psraw xmm0, 8
- psraw xmm2, 8
- packsswb xmm0, xmm2
- paddb xmm0, xmm5
- lea eax, [eax + 64]
- movdqu [edx + edi], xmm0
- lea edx, [edx + 16]
- jg convertloop
-
- pop edi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void ARGBToUV422Row_SSSE3(const uint8* src_argb0,
- uint8* dst_u, uint8* dst_v, int width) {
- __asm {
- push edi
- mov eax, [esp + 4 + 4] // src_argb
- mov edx, [esp + 4 + 8] // dst_u
- mov edi, [esp + 4 + 12] // dst_v
- mov ecx, [esp + 4 + 16] // pix
- movdqa xmm7, kARGBToU
- movdqa xmm6, kARGBToV
- movdqa xmm5, kAddUV128
- sub edi, edx // stride from u to v
-
- align 4
- convertloop:
- /* step 1 - subsample 16x2 argb pixels to 8x1 */
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- movdqa xmm2, [eax + 32]
- movdqa xmm3, [eax + 48]
- lea eax, [eax + 64]
- movdqa xmm4, xmm0
- shufps xmm0, xmm1, 0x88
- shufps xmm4, xmm1, 0xdd
- pavgb xmm0, xmm4
- movdqa xmm4, xmm2
- shufps xmm2, xmm3, 0x88
- shufps xmm4, xmm3, 0xdd
- pavgb xmm2, xmm4
-
- // step 2 - convert to U and V
- // from here down is very similar to Y code except
- // instead of 16 different pixels, its 8 pixels of U and 8 of V
- movdqa xmm1, xmm0
- movdqa xmm3, xmm2
- pmaddubsw xmm0, xmm7 // U
- pmaddubsw xmm2, xmm7
- pmaddubsw xmm1, xmm6 // V
- pmaddubsw xmm3, xmm6
- phaddw xmm0, xmm2
- phaddw xmm1, xmm3
- psraw xmm0, 8
- psraw xmm1, 8
- packsswb xmm0, xmm1
- paddb xmm0, xmm5 // -> unsigned
-
- // step 3 - store 8 U and 8 V values
- sub ecx, 16
- movlps qword ptr [edx], xmm0 // U
- movhps qword ptr [edx + edi], xmm0 // V
- lea edx, [edx + 8]
- jg convertloop
-
- pop edi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void ARGBToUV422Row_Unaligned_SSSE3(const uint8* src_argb0,
- uint8* dst_u, uint8* dst_v, int width) {
- __asm {
- push edi
- mov eax, [esp + 4 + 4] // src_argb
- mov edx, [esp + 4 + 8] // dst_u
- mov edi, [esp + 4 + 12] // dst_v
- mov ecx, [esp + 4 + 16] // pix
- movdqa xmm7, kARGBToU
- movdqa xmm6, kARGBToV
- movdqa xmm5, kAddUV128
- sub edi, edx // stride from u to v
-
- align 4
- convertloop:
- /* step 1 - subsample 16x2 argb pixels to 8x1 */
- movdqu xmm0, [eax]
- movdqu xmm1, [eax + 16]
- movdqu xmm2, [eax + 32]
- movdqu xmm3, [eax + 48]
- lea eax, [eax + 64]
- movdqa xmm4, xmm0
- shufps xmm0, xmm1, 0x88
- shufps xmm4, xmm1, 0xdd
- pavgb xmm0, xmm4
- movdqa xmm4, xmm2
- shufps xmm2, xmm3, 0x88
- shufps xmm4, xmm3, 0xdd
- pavgb xmm2, xmm4
-
- // step 2 - convert to U and V
- // from here down is very similar to Y code except
- // instead of 16 different pixels, its 8 pixels of U and 8 of V
- movdqa xmm1, xmm0
- movdqa xmm3, xmm2
- pmaddubsw xmm0, xmm7 // U
- pmaddubsw xmm2, xmm7
- pmaddubsw xmm1, xmm6 // V
- pmaddubsw xmm3, xmm6
- phaddw xmm0, xmm2
- phaddw xmm1, xmm3
- psraw xmm0, 8
- psraw xmm1, 8
- packsswb xmm0, xmm1
- paddb xmm0, xmm5 // -> unsigned
-
- // step 3 - store 8 U and 8 V values
- sub ecx, 16
- movlps qword ptr [edx], xmm0 // U
- movhps qword ptr [edx + edi], xmm0 // V
- lea edx, [edx + 8]
- jg convertloop
-
- pop edi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void BGRAToUVRow_SSSE3(const uint8* src_argb0, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // src_argb
- mov esi, [esp + 8 + 8] // src_stride_argb
- mov edx, [esp + 8 + 12] // dst_u
- mov edi, [esp + 8 + 16] // dst_v
- mov ecx, [esp + 8 + 20] // pix
- movdqa xmm7, kBGRAToU
- movdqa xmm6, kBGRAToV
- movdqa xmm5, kAddUV128
- sub edi, edx // stride from u to v
-
- align 4
- convertloop:
- /* step 1 - subsample 16x2 argb pixels to 8x1 */
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- movdqa xmm2, [eax + 32]
- movdqa xmm3, [eax + 48]
- pavgb xmm0, [eax + esi]
- pavgb xmm1, [eax + esi + 16]
- pavgb xmm2, [eax + esi + 32]
- pavgb xmm3, [eax + esi + 48]
- lea eax, [eax + 64]
- movdqa xmm4, xmm0
- shufps xmm0, xmm1, 0x88
- shufps xmm4, xmm1, 0xdd
- pavgb xmm0, xmm4
- movdqa xmm4, xmm2
- shufps xmm2, xmm3, 0x88
- shufps xmm4, xmm3, 0xdd
- pavgb xmm2, xmm4
-
- // step 2 - convert to U and V
- // from here down is very similar to Y code except
- // instead of 16 different pixels, its 8 pixels of U and 8 of V
- movdqa xmm1, xmm0
- movdqa xmm3, xmm2
- pmaddubsw xmm0, xmm7 // U
- pmaddubsw xmm2, xmm7
- pmaddubsw xmm1, xmm6 // V
- pmaddubsw xmm3, xmm6
- phaddw xmm0, xmm2
- phaddw xmm1, xmm3
- psraw xmm0, 8
- psraw xmm1, 8
- packsswb xmm0, xmm1
- paddb xmm0, xmm5 // -> unsigned
-
- // step 3 - store 8 U and 8 V values
- sub ecx, 16
- movlps qword ptr [edx], xmm0 // U
- movhps qword ptr [edx + edi], xmm0 // V
- lea edx, [edx + 8]
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void BGRAToUVRow_Unaligned_SSSE3(const uint8* src_argb0, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // src_argb
- mov esi, [esp + 8 + 8] // src_stride_argb
- mov edx, [esp + 8 + 12] // dst_u
- mov edi, [esp + 8 + 16] // dst_v
- mov ecx, [esp + 8 + 20] // pix
- movdqa xmm7, kBGRAToU
- movdqa xmm6, kBGRAToV
- movdqa xmm5, kAddUV128
- sub edi, edx // stride from u to v
-
- align 4
- convertloop:
- /* step 1 - subsample 16x2 argb pixels to 8x1 */
- movdqu xmm0, [eax]
- movdqu xmm1, [eax + 16]
- movdqu xmm2, [eax + 32]
- movdqu xmm3, [eax + 48]
- movdqu xmm4, [eax + esi]
- pavgb xmm0, xmm4
- movdqu xmm4, [eax + esi + 16]
- pavgb xmm1, xmm4
- movdqu xmm4, [eax + esi + 32]
- pavgb xmm2, xmm4
- movdqu xmm4, [eax + esi + 48]
- pavgb xmm3, xmm4
- lea eax, [eax + 64]
- movdqa xmm4, xmm0
- shufps xmm0, xmm1, 0x88
- shufps xmm4, xmm1, 0xdd
- pavgb xmm0, xmm4
- movdqa xmm4, xmm2
- shufps xmm2, xmm3, 0x88
- shufps xmm4, xmm3, 0xdd
- pavgb xmm2, xmm4
-
- // step 2 - convert to U and V
- // from here down is very similar to Y code except
- // instead of 16 different pixels, its 8 pixels of U and 8 of V
- movdqa xmm1, xmm0
- movdqa xmm3, xmm2
- pmaddubsw xmm0, xmm7 // U
- pmaddubsw xmm2, xmm7
- pmaddubsw xmm1, xmm6 // V
- pmaddubsw xmm3, xmm6
- phaddw xmm0, xmm2
- phaddw xmm1, xmm3
- psraw xmm0, 8
- psraw xmm1, 8
- packsswb xmm0, xmm1
- paddb xmm0, xmm5 // -> unsigned
-
- // step 3 - store 8 U and 8 V values
- sub ecx, 16
- movlps qword ptr [edx], xmm0 // U
- movhps qword ptr [edx + edi], xmm0 // V
- lea edx, [edx + 8]
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void ABGRToUVRow_SSSE3(const uint8* src_argb0, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // src_argb
- mov esi, [esp + 8 + 8] // src_stride_argb
- mov edx, [esp + 8 + 12] // dst_u
- mov edi, [esp + 8 + 16] // dst_v
- mov ecx, [esp + 8 + 20] // pix
- movdqa xmm7, kABGRToU
- movdqa xmm6, kABGRToV
- movdqa xmm5, kAddUV128
- sub edi, edx // stride from u to v
-
- align 4
- convertloop:
- /* step 1 - subsample 16x2 argb pixels to 8x1 */
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- movdqa xmm2, [eax + 32]
- movdqa xmm3, [eax + 48]
- pavgb xmm0, [eax + esi]
- pavgb xmm1, [eax + esi + 16]
- pavgb xmm2, [eax + esi + 32]
- pavgb xmm3, [eax + esi + 48]
- lea eax, [eax + 64]
- movdqa xmm4, xmm0
- shufps xmm0, xmm1, 0x88
- shufps xmm4, xmm1, 0xdd
- pavgb xmm0, xmm4
- movdqa xmm4, xmm2
- shufps xmm2, xmm3, 0x88
- shufps xmm4, xmm3, 0xdd
- pavgb xmm2, xmm4
-
- // step 2 - convert to U and V
- // from here down is very similar to Y code except
- // instead of 16 different pixels, its 8 pixels of U and 8 of V
- movdqa xmm1, xmm0
- movdqa xmm3, xmm2
- pmaddubsw xmm0, xmm7 // U
- pmaddubsw xmm2, xmm7
- pmaddubsw xmm1, xmm6 // V
- pmaddubsw xmm3, xmm6
- phaddw xmm0, xmm2
- phaddw xmm1, xmm3
- psraw xmm0, 8
- psraw xmm1, 8
- packsswb xmm0, xmm1
- paddb xmm0, xmm5 // -> unsigned
-
- // step 3 - store 8 U and 8 V values
- sub ecx, 16
- movlps qword ptr [edx], xmm0 // U
- movhps qword ptr [edx + edi], xmm0 // V
- lea edx, [edx + 8]
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void ABGRToUVRow_Unaligned_SSSE3(const uint8* src_argb0, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // src_argb
- mov esi, [esp + 8 + 8] // src_stride_argb
- mov edx, [esp + 8 + 12] // dst_u
- mov edi, [esp + 8 + 16] // dst_v
- mov ecx, [esp + 8 + 20] // pix
- movdqa xmm7, kABGRToU
- movdqa xmm6, kABGRToV
- movdqa xmm5, kAddUV128
- sub edi, edx // stride from u to v
-
- align 4
- convertloop:
- /* step 1 - subsample 16x2 argb pixels to 8x1 */
- movdqu xmm0, [eax]
- movdqu xmm1, [eax + 16]
- movdqu xmm2, [eax + 32]
- movdqu xmm3, [eax + 48]
- movdqu xmm4, [eax + esi]
- pavgb xmm0, xmm4
- movdqu xmm4, [eax + esi + 16]
- pavgb xmm1, xmm4
- movdqu xmm4, [eax + esi + 32]
- pavgb xmm2, xmm4
- movdqu xmm4, [eax + esi + 48]
- pavgb xmm3, xmm4
- lea eax, [eax + 64]
- movdqa xmm4, xmm0
- shufps xmm0, xmm1, 0x88
- shufps xmm4, xmm1, 0xdd
- pavgb xmm0, xmm4
- movdqa xmm4, xmm2
- shufps xmm2, xmm3, 0x88
- shufps xmm4, xmm3, 0xdd
- pavgb xmm2, xmm4
-
- // step 2 - convert to U and V
- // from here down is very similar to Y code except
- // instead of 16 different pixels, its 8 pixels of U and 8 of V
- movdqa xmm1, xmm0
- movdqa xmm3, xmm2
- pmaddubsw xmm0, xmm7 // U
- pmaddubsw xmm2, xmm7
- pmaddubsw xmm1, xmm6 // V
- pmaddubsw xmm3, xmm6
- phaddw xmm0, xmm2
- phaddw xmm1, xmm3
- psraw xmm0, 8
- psraw xmm1, 8
- packsswb xmm0, xmm1
- paddb xmm0, xmm5 // -> unsigned
-
- // step 3 - store 8 U and 8 V values
- sub ecx, 16
- movlps qword ptr [edx], xmm0 // U
- movhps qword ptr [edx + edi], xmm0 // V
- lea edx, [edx + 8]
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void RGBAToUVRow_SSSE3(const uint8* src_argb0, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // src_argb
- mov esi, [esp + 8 + 8] // src_stride_argb
- mov edx, [esp + 8 + 12] // dst_u
- mov edi, [esp + 8 + 16] // dst_v
- mov ecx, [esp + 8 + 20] // pix
- movdqa xmm7, kRGBAToU
- movdqa xmm6, kRGBAToV
- movdqa xmm5, kAddUV128
- sub edi, edx // stride from u to v
-
- align 4
- convertloop:
- /* step 1 - subsample 16x2 argb pixels to 8x1 */
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- movdqa xmm2, [eax + 32]
- movdqa xmm3, [eax + 48]
- pavgb xmm0, [eax + esi]
- pavgb xmm1, [eax + esi + 16]
- pavgb xmm2, [eax + esi + 32]
- pavgb xmm3, [eax + esi + 48]
- lea eax, [eax + 64]
- movdqa xmm4, xmm0
- shufps xmm0, xmm1, 0x88
- shufps xmm4, xmm1, 0xdd
- pavgb xmm0, xmm4
- movdqa xmm4, xmm2
- shufps xmm2, xmm3, 0x88
- shufps xmm4, xmm3, 0xdd
- pavgb xmm2, xmm4
-
- // step 2 - convert to U and V
- // from here down is very similar to Y code except
- // instead of 16 different pixels, its 8 pixels of U and 8 of V
- movdqa xmm1, xmm0
- movdqa xmm3, xmm2
- pmaddubsw xmm0, xmm7 // U
- pmaddubsw xmm2, xmm7
- pmaddubsw xmm1, xmm6 // V
- pmaddubsw xmm3, xmm6
- phaddw xmm0, xmm2
- phaddw xmm1, xmm3
- psraw xmm0, 8
- psraw xmm1, 8
- packsswb xmm0, xmm1
- paddb xmm0, xmm5 // -> unsigned
-
- // step 3 - store 8 U and 8 V values
- sub ecx, 16
- movlps qword ptr [edx], xmm0 // U
- movhps qword ptr [edx + edi], xmm0 // V
- lea edx, [edx + 8]
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void RGBAToUVRow_Unaligned_SSSE3(const uint8* src_argb0, int src_stride_argb,
- uint8* dst_u, uint8* dst_v, int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // src_argb
- mov esi, [esp + 8 + 8] // src_stride_argb
- mov edx, [esp + 8 + 12] // dst_u
- mov edi, [esp + 8 + 16] // dst_v
- mov ecx, [esp + 8 + 20] // pix
- movdqa xmm7, kRGBAToU
- movdqa xmm6, kRGBAToV
- movdqa xmm5, kAddUV128
- sub edi, edx // stride from u to v
-
- align 4
- convertloop:
- /* step 1 - subsample 16x2 argb pixels to 8x1 */
- movdqu xmm0, [eax]
- movdqu xmm1, [eax + 16]
- movdqu xmm2, [eax + 32]
- movdqu xmm3, [eax + 48]
- movdqu xmm4, [eax + esi]
- pavgb xmm0, xmm4
- movdqu xmm4, [eax + esi + 16]
- pavgb xmm1, xmm4
- movdqu xmm4, [eax + esi + 32]
- pavgb xmm2, xmm4
- movdqu xmm4, [eax + esi + 48]
- pavgb xmm3, xmm4
- lea eax, [eax + 64]
- movdqa xmm4, xmm0
- shufps xmm0, xmm1, 0x88
- shufps xmm4, xmm1, 0xdd
- pavgb xmm0, xmm4
- movdqa xmm4, xmm2
- shufps xmm2, xmm3, 0x88
- shufps xmm4, xmm3, 0xdd
- pavgb xmm2, xmm4
-
- // step 2 - convert to U and V
- // from here down is very similar to Y code except
- // instead of 16 different pixels, its 8 pixels of U and 8 of V
- movdqa xmm1, xmm0
- movdqa xmm3, xmm2
- pmaddubsw xmm0, xmm7 // U
- pmaddubsw xmm2, xmm7
- pmaddubsw xmm1, xmm6 // V
- pmaddubsw xmm3, xmm6
- phaddw xmm0, xmm2
- phaddw xmm1, xmm3
- psraw xmm0, 8
- psraw xmm1, 8
- packsswb xmm0, xmm1
- paddb xmm0, xmm5 // -> unsigned
-
- // step 3 - store 8 U and 8 V values
- sub ecx, 16
- movlps qword ptr [edx], xmm0 // U
- movhps qword ptr [edx + edi], xmm0 // V
- lea edx, [edx + 8]
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-#endif // HAS_ARGBTOYROW_SSSE3
-
-#define YG 74 /* (int8)(1.164 * 64 + 0.5) */
-
-#define UB 127 /* min(63,(int8)(2.018 * 64)) */
-#define UG -25 /* (int8)(-0.391 * 64 - 0.5) */
-#define UR 0
-
-#define VB 0
-#define VG -52 /* (int8)(-0.813 * 64 - 0.5) */
-#define VR 102 /* (int8)(1.596 * 64 + 0.5) */
-
-// Bias
-#define BB UB * 128 + VB * 128
-#define BG UG * 128 + VG * 128
-#define BR UR * 128 + VR * 128
-
-#ifdef HAS_I422TOARGBROW_AVX2
-
-static const lvec8 kUVToB_AVX = {
- UB, VB, UB, VB, UB, VB, UB, VB, UB, VB, UB, VB, UB, VB, UB, VB,
- UB, VB, UB, VB, UB, VB, UB, VB, UB, VB, UB, VB, UB, VB, UB, VB
-};
-static const lvec8 kUVToR_AVX = {
- UR, VR, UR, VR, UR, VR, UR, VR, UR, VR, UR, VR, UR, VR, UR, VR,
- UR, VR, UR, VR, UR, VR, UR, VR, UR, VR, UR, VR, UR, VR, UR, VR
-};
-static const lvec8 kUVToG_AVX = {
- UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG,
- UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG
-};
-static const lvec16 kYToRgb_AVX = {
- YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG, YG
-};
-static const lvec16 kYSub16_AVX = {
- 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16
-};
-static const lvec16 kUVBiasB_AVX = {
- BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB, BB
-};
-static const lvec16 kUVBiasG_AVX = {
- BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG, BG
-};
-static const lvec16 kUVBiasR_AVX = {
- BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR, BR
-};
-
-// 16 pixels
-// 8 UV values upsampled to 16 UV, mixed with 16 Y producing 16 ARGB (64 bytes).
-__declspec(naked) __declspec(align(16))
-void I422ToARGBRow_AVX2(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_argb,
- int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // Y
- mov esi, [esp + 8 + 8] // U
- mov edi, [esp + 8 + 12] // V
- mov edx, [esp + 8 + 16] // argb
- mov ecx, [esp + 8 + 20] // width
- sub edi, esi
- vpcmpeqb ymm5, ymm5, ymm5 // generate 0xffffffffffffffff for alpha
- vpxor ymm4, ymm4, ymm4
-
- align 4
- convertloop:
- vmovq xmm0, qword ptr [esi] // U
- vmovq xmm1, qword ptr [esi + edi] // V
- lea esi, [esi + 8]
- vpunpcklbw ymm0, ymm0, ymm1 // UV
- vpermq ymm0, ymm0, 0xd8
- vpunpcklwd ymm0, ymm0, ymm0 // UVUV
- vpmaddubsw ymm2, ymm0, kUVToB_AVX // scale B UV
- vpmaddubsw ymm1, ymm0, kUVToG_AVX // scale G UV
- vpmaddubsw ymm0, ymm0, kUVToR_AVX // scale R UV
- vpsubw ymm2, ymm2, kUVBiasB_AVX // unbias back to signed
- vpsubw ymm1, ymm1, kUVBiasG_AVX
- vpsubw ymm0, ymm0, kUVBiasR_AVX
-
- // Step 2: Find Y contribution to 16 R,G,B values
- vmovdqu xmm3, [eax] // NOLINT
- lea eax, [eax + 16]
- vpermq ymm3, ymm3, 0xd8
- vpunpcklbw ymm3, ymm3, ymm4
- vpsubsw ymm3, ymm3, kYSub16_AVX
- vpmullw ymm3, ymm3, kYToRgb_AVX
- vpaddsw ymm2, ymm2, ymm3 // B += Y
- vpaddsw ymm1, ymm1, ymm3 // G += Y
- vpaddsw ymm0, ymm0, ymm3 // R += Y
- vpsraw ymm2, ymm2, 6
- vpsraw ymm1, ymm1, 6
- vpsraw ymm0, ymm0, 6
- vpackuswb ymm2, ymm2, ymm2 // B
- vpackuswb ymm1, ymm1, ymm1 // G
- vpackuswb ymm0, ymm0, ymm0 // R
-
- // Step 3: Weave into ARGB
- vpunpcklbw ymm2, ymm2, ymm1 // BG
- vpermq ymm2, ymm2, 0xd8
- vpunpcklbw ymm0, ymm0, ymm5 // RA
- vpermq ymm0, ymm0, 0xd8
- vpunpcklwd ymm1, ymm2, ymm0 // BGRA first 8 pixels
- vpunpckhwd ymm2, ymm2, ymm0 // BGRA next 8 pixels
- vmovdqu [edx], ymm1
- vmovdqu [edx + 32], ymm2
- lea edx, [edx + 64]
- sub ecx, 16
- jg convertloop
- vzeroupper
-
- pop edi
- pop esi
- ret
- }
-}
-#endif // HAS_I422TOARGBROW_AVX2
-
-#ifdef HAS_I422TOARGBROW_SSSE3
-
-static const vec8 kUVToB = {
- UB, VB, UB, VB, UB, VB, UB, VB, UB, VB, UB, VB, UB, VB, UB, VB
-};
-
-static const vec8 kUVToR = {
- UR, VR, UR, VR, UR, VR, UR, VR, UR, VR, UR, VR, UR, VR, UR, VR
-};
-
-static const vec8 kUVToG = {
- UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG
-};
-
-static const vec8 kVUToB = {
- VB, UB, VB, UB, VB, UB, VB, UB, VB, UB, VB, UB, VB, UB, VB, UB,
-};
-
-static const vec8 kVUToR = {
- VR, UR, VR, UR, VR, UR, VR, UR, VR, UR, VR, UR, VR, UR, VR, UR,
-};
-
-static const vec8 kVUToG = {
- VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG, VG, UG,
-};
-
-static const vec16 kYToRgb = { YG, YG, YG, YG, YG, YG, YG, YG };
-static const vec16 kYSub16 = { 16, 16, 16, 16, 16, 16, 16, 16 };
-static const vec16 kUVBiasB = { BB, BB, BB, BB, BB, BB, BB, BB };
-static const vec16 kUVBiasG = { BG, BG, BG, BG, BG, BG, BG, BG };
-static const vec16 kUVBiasR = { BR, BR, BR, BR, BR, BR, BR, BR };
-
-// TODO(fbarchard): Read that does half size on Y and treats 420 as 444.
-
-// Read 8 UV from 444.
-#define READYUV444 __asm { \
- __asm movq xmm0, qword ptr [esi] /* U */ /* NOLINT */ \
- __asm movq xmm1, qword ptr [esi + edi] /* V */ /* NOLINT */ \
- __asm lea esi, [esi + 8] \
- __asm punpcklbw xmm0, xmm1 /* UV */ \
- }
-
-// Read 4 UV from 422, upsample to 8 UV.
-#define READYUV422 __asm { \
- __asm movd xmm0, [esi] /* U */ \
- __asm movd xmm1, [esi + edi] /* V */ \
- __asm lea esi, [esi + 4] \
- __asm punpcklbw xmm0, xmm1 /* UV */ \
- __asm punpcklwd xmm0, xmm0 /* UVUV (upsample) */ \
- }
-
-// Read 2 UV from 411, upsample to 8 UV.
-#define READYUV411 __asm { \
- __asm movzx ebx, word ptr [esi] /* U */ /* NOLINT */ \
- __asm movd xmm0, ebx \
- __asm movzx ebx, word ptr [esi + edi] /* V */ /* NOLINT */ \
- __asm movd xmm1, ebx \
- __asm lea esi, [esi + 2] \
- __asm punpcklbw xmm0, xmm1 /* UV */ \
- __asm punpcklwd xmm0, xmm0 /* UVUV (upsample) */ \
- __asm punpckldq xmm0, xmm0 /* UVUV (upsample) */ \
- }
-
-// Read 4 UV from NV12, upsample to 8 UV.
-#define READNV12 __asm { \
- __asm movq xmm0, qword ptr [esi] /* UV */ /* NOLINT */ \
- __asm lea esi, [esi + 8] \
- __asm punpcklwd xmm0, xmm0 /* UVUV (upsample) */ \
- }
-
-// Convert 8 pixels: 8 UV and 8 Y.
-#define YUVTORGB __asm { \
- /* Step 1: Find 4 UV contributions to 8 R,G,B values */ \
- __asm movdqa xmm1, xmm0 \
- __asm movdqa xmm2, xmm0 \
- __asm pmaddubsw xmm0, kUVToB /* scale B UV */ \
- __asm pmaddubsw xmm1, kUVToG /* scale G UV */ \
- __asm pmaddubsw xmm2, kUVToR /* scale R UV */ \
- __asm psubw xmm0, kUVBiasB /* unbias back to signed */ \
- __asm psubw xmm1, kUVBiasG \
- __asm psubw xmm2, kUVBiasR \
- /* Step 2: Find Y contribution to 8 R,G,B values */ \
- __asm movq xmm3, qword ptr [eax] /* NOLINT */ \
- __asm lea eax, [eax + 8] \
- __asm punpcklbw xmm3, xmm4 \
- __asm psubsw xmm3, kYSub16 \
- __asm pmullw xmm3, kYToRgb \
- __asm paddsw xmm0, xmm3 /* B += Y */ \
- __asm paddsw xmm1, xmm3 /* G += Y */ \
- __asm paddsw xmm2, xmm3 /* R += Y */ \
- __asm psraw xmm0, 6 \
- __asm psraw xmm1, 6 \
- __asm psraw xmm2, 6 \
- __asm packuswb xmm0, xmm0 /* B */ \
- __asm packuswb xmm1, xmm1 /* G */ \
- __asm packuswb xmm2, xmm2 /* R */ \
- }
-
-// Convert 8 pixels: 8 VU and 8 Y.
-#define YVUTORGB __asm { \
- /* Step 1: Find 4 UV contributions to 8 R,G,B values */ \
- __asm movdqa xmm1, xmm0 \
- __asm movdqa xmm2, xmm0 \
- __asm pmaddubsw xmm0, kVUToB /* scale B UV */ \
- __asm pmaddubsw xmm1, kVUToG /* scale G UV */ \
- __asm pmaddubsw xmm2, kVUToR /* scale R UV */ \
- __asm psubw xmm0, kUVBiasB /* unbias back to signed */ \
- __asm psubw xmm1, kUVBiasG \
- __asm psubw xmm2, kUVBiasR \
- /* Step 2: Find Y contribution to 8 R,G,B values */ \
- __asm movq xmm3, qword ptr [eax] /* NOLINT */ \
- __asm lea eax, [eax + 8] \
- __asm punpcklbw xmm3, xmm4 \
- __asm psubsw xmm3, kYSub16 \
- __asm pmullw xmm3, kYToRgb \
- __asm paddsw xmm0, xmm3 /* B += Y */ \
- __asm paddsw xmm1, xmm3 /* G += Y */ \
- __asm paddsw xmm2, xmm3 /* R += Y */ \
- __asm psraw xmm0, 6 \
- __asm psraw xmm1, 6 \
- __asm psraw xmm2, 6 \
- __asm packuswb xmm0, xmm0 /* B */ \
- __asm packuswb xmm1, xmm1 /* G */ \
- __asm packuswb xmm2, xmm2 /* R */ \
- }
-
-// 8 pixels, dest aligned 16.
-// 8 UV values, mixed with 8 Y producing 8 ARGB (32 bytes).
-__declspec(naked) __declspec(align(16))
-void I444ToARGBRow_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_argb,
- int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // Y
- mov esi, [esp + 8 + 8] // U
- mov edi, [esp + 8 + 12] // V
- mov edx, [esp + 8 + 16] // argb
- mov ecx, [esp + 8 + 20] // width
- sub edi, esi
- pcmpeqb xmm5, xmm5 // generate 0xffffffff for alpha
- pxor xmm4, xmm4
-
- align 4
- convertloop:
- READYUV444
- YUVTORGB
-
- // Step 3: Weave into ARGB
- punpcklbw xmm0, xmm1 // BG
- punpcklbw xmm2, xmm5 // RA
- movdqa xmm1, xmm0
- punpcklwd xmm0, xmm2 // BGRA first 4 pixels
- punpckhwd xmm1, xmm2 // BGRA next 4 pixels
- movdqa [edx], xmm0
- movdqa [edx + 16], xmm1
- lea edx, [edx + 32]
- sub ecx, 8
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-// 8 pixels, dest aligned 16.
-// 4 UV values upsampled to 8 UV, mixed with 8 Y producing 8 ARGB (32 bytes).
-__declspec(naked) __declspec(align(16))
-void I422ToRGB24Row_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_rgb24,
- int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // Y
- mov esi, [esp + 8 + 8] // U
- mov edi, [esp + 8 + 12] // V
- mov edx, [esp + 8 + 16] // rgb24
- mov ecx, [esp + 8 + 20] // width
- sub edi, esi
- pxor xmm4, xmm4
- movdqa xmm5, kShuffleMaskARGBToRGB24_0
- movdqa xmm6, kShuffleMaskARGBToRGB24
-
- align 4
- convertloop:
- READYUV422
- YUVTORGB
-
- // Step 3: Weave into RRGB
- punpcklbw xmm0, xmm1 // BG
- punpcklbw xmm2, xmm2 // RR
- movdqa xmm1, xmm0
- punpcklwd xmm0, xmm2 // BGRR first 4 pixels
- punpckhwd xmm1, xmm2 // BGRR next 4 pixels
- pshufb xmm0, xmm5 // Pack into first 8 and last 4 bytes.
- pshufb xmm1, xmm6 // Pack into first 12 bytes.
- palignr xmm1, xmm0, 12 // last 4 bytes of xmm0 + 12 from xmm1
- movq qword ptr [edx], xmm0 // First 8 bytes
- movdqu [edx + 8], xmm1 // Last 16 bytes. = 24 bytes, 8 RGB pixels.
- lea edx, [edx + 24]
- sub ecx, 8
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-// 8 pixels, dest aligned 16.
-// 4 UV values upsampled to 8 UV, mixed with 8 Y producing 8 ARGB (32 bytes).
-__declspec(naked) __declspec(align(16))
-void I422ToRAWRow_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_raw,
- int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // Y
- mov esi, [esp + 8 + 8] // U
- mov edi, [esp + 8 + 12] // V
- mov edx, [esp + 8 + 16] // raw
- mov ecx, [esp + 8 + 20] // width
- sub edi, esi
- pxor xmm4, xmm4
- movdqa xmm5, kShuffleMaskARGBToRAW_0
- movdqa xmm6, kShuffleMaskARGBToRAW
-
- align 4
- convertloop:
- READYUV422
- YUVTORGB
-
- // Step 3: Weave into RRGB
- punpcklbw xmm0, xmm1 // BG
- punpcklbw xmm2, xmm2 // RR
- movdqa xmm1, xmm0
- punpcklwd xmm0, xmm2 // BGRR first 4 pixels
- punpckhwd xmm1, xmm2 // BGRR next 4 pixels
- pshufb xmm0, xmm5 // Pack into first 8 and last 4 bytes.
- pshufb xmm1, xmm6 // Pack into first 12 bytes.
- palignr xmm1, xmm0, 12 // last 4 bytes of xmm0 + 12 from xmm1
- movq qword ptr [edx], xmm0 // First 8 bytes
- movdqu [edx + 8], xmm1 // Last 16 bytes. = 24 bytes, 8 RGB pixels.
- lea edx, [edx + 24]
- sub ecx, 8
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-// 8 pixels, dest unaligned.
-// 4 UV values upsampled to 8 UV, mixed with 8 Y producing 8 ARGB (32 bytes).
-__declspec(naked) __declspec(align(16))
-void I422ToRGB565Row_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* rgb565_buf,
- int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // Y
- mov esi, [esp + 8 + 8] // U
- mov edi, [esp + 8 + 12] // V
- mov edx, [esp + 8 + 16] // rgb565
- mov ecx, [esp + 8 + 20] // width
- sub edi, esi
- pxor xmm4, xmm4
- pcmpeqb xmm5, xmm5 // generate mask 0x0000001f
- psrld xmm5, 27
- pcmpeqb xmm6, xmm6 // generate mask 0x000007e0
- psrld xmm6, 26
- pslld xmm6, 5
- pcmpeqb xmm7, xmm7 // generate mask 0xfffff800
- pslld xmm7, 11
-
- align 4
- convertloop:
- READYUV422
- YUVTORGB
-
- // Step 3: Weave into RRGB
- punpcklbw xmm0, xmm1 // BG
- punpcklbw xmm2, xmm2 // RR
- movdqa xmm1, xmm0
- punpcklwd xmm0, xmm2 // BGRR first 4 pixels
- punpckhwd xmm1, xmm2 // BGRR next 4 pixels
-
- // Step 3b: RRGB -> RGB565
- movdqa xmm3, xmm0 // B first 4 pixels of argb
- movdqa xmm2, xmm0 // G
- pslld xmm0, 8 // R
- psrld xmm3, 3 // B
- psrld xmm2, 5 // G
- psrad xmm0, 16 // R
- pand xmm3, xmm5 // B
- pand xmm2, xmm6 // G
- pand xmm0, xmm7 // R
- por xmm3, xmm2 // BG
- por xmm0, xmm3 // BGR
- movdqa xmm3, xmm1 // B next 4 pixels of argb
- movdqa xmm2, xmm1 // G
- pslld xmm1, 8 // R
- psrld xmm3, 3 // B
- psrld xmm2, 5 // G
- psrad xmm1, 16 // R
- pand xmm3, xmm5 // B
- pand xmm2, xmm6 // G
- pand xmm1, xmm7 // R
- por xmm3, xmm2 // BG
- por xmm1, xmm3 // BGR
- packssdw xmm0, xmm1
- sub ecx, 8
- movdqu [edx], xmm0 // store 8 pixels of RGB565
- lea edx, [edx + 16]
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-// 8 pixels, dest aligned 16.
-// 4 UV values upsampled to 8 UV, mixed with 8 Y producing 8 ARGB (32 bytes).
-__declspec(naked) __declspec(align(16))
-void I422ToARGBRow_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_argb,
- int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // Y
- mov esi, [esp + 8 + 8] // U
- mov edi, [esp + 8 + 12] // V
- mov edx, [esp + 8 + 16] // argb
- mov ecx, [esp + 8 + 20] // width
- sub edi, esi
- pcmpeqb xmm5, xmm5 // generate 0xffffffff for alpha
- pxor xmm4, xmm4
-
- align 4
- convertloop:
- READYUV422
- YUVTORGB
-
- // Step 3: Weave into ARGB
- punpcklbw xmm0, xmm1 // BG
- punpcklbw xmm2, xmm5 // RA
- movdqa xmm1, xmm0
- punpcklwd xmm0, xmm2 // BGRA first 4 pixels
- punpckhwd xmm1, xmm2 // BGRA next 4 pixels
- movdqa [edx], xmm0
- movdqa [edx + 16], xmm1
- lea edx, [edx + 32]
- sub ecx, 8
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-// 8 pixels, dest aligned 16.
-// 2 UV values upsampled to 8 UV, mixed with 8 Y producing 8 ARGB (32 bytes).
-// Similar to I420 but duplicate UV once more.
-__declspec(naked) __declspec(align(16))
-void I411ToARGBRow_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_argb,
- int width) {
- __asm {
- push ebx
- push esi
- push edi
- mov eax, [esp + 12 + 4] // Y
- mov esi, [esp + 12 + 8] // U
- mov edi, [esp + 12 + 12] // V
- mov edx, [esp + 12 + 16] // argb
- mov ecx, [esp + 12 + 20] // width
- sub edi, esi
- pcmpeqb xmm5, xmm5 // generate 0xffffffff for alpha
- pxor xmm4, xmm4
-
- align 4
- convertloop:
- READYUV411 // modifies EBX
- YUVTORGB
-
- // Step 3: Weave into ARGB
- punpcklbw xmm0, xmm1 // BG
- punpcklbw xmm2, xmm5 // RA
- movdqa xmm1, xmm0
- punpcklwd xmm0, xmm2 // BGRA first 4 pixels
- punpckhwd xmm1, xmm2 // BGRA next 4 pixels
- movdqa [edx], xmm0
- movdqa [edx + 16], xmm1
- lea edx, [edx + 32]
- sub ecx, 8
- jg convertloop
-
- pop edi
- pop esi
- pop ebx
- ret
- }
-}
-
-// 8 pixels, dest aligned 16.
-// 4 UV values upsampled to 8 UV, mixed with 8 Y producing 8 ARGB (32 bytes).
-__declspec(naked) __declspec(align(16))
-void NV12ToARGBRow_SSSE3(const uint8* y_buf,
- const uint8* uv_buf,
- uint8* dst_argb,
- int width) {
- __asm {
- push esi
- mov eax, [esp + 4 + 4] // Y
- mov esi, [esp + 4 + 8] // UV
- mov edx, [esp + 4 + 12] // argb
- mov ecx, [esp + 4 + 16] // width
- pcmpeqb xmm5, xmm5 // generate 0xffffffff for alpha
- pxor xmm4, xmm4
-
- align 4
- convertloop:
- READNV12
- YUVTORGB
-
- // Step 3: Weave into ARGB
- punpcklbw xmm0, xmm1 // BG
- punpcklbw xmm2, xmm5 // RA
- movdqa xmm1, xmm0
- punpcklwd xmm0, xmm2 // BGRA first 4 pixels
- punpckhwd xmm1, xmm2 // BGRA next 4 pixels
- movdqa [edx], xmm0
- movdqa [edx + 16], xmm1
- lea edx, [edx + 32]
- sub ecx, 8
- jg convertloop
-
- pop esi
- ret
- }
-}
-
-// 8 pixels, dest aligned 16.
-// 4 UV values upsampled to 8 UV, mixed with 8 Y producing 8 ARGB (32 bytes).
-__declspec(naked) __declspec(align(16))
-void NV21ToARGBRow_SSSE3(const uint8* y_buf,
- const uint8* uv_buf,
- uint8* dst_argb,
- int width) {
- __asm {
- push esi
- mov eax, [esp + 4 + 4] // Y
- mov esi, [esp + 4 + 8] // VU
- mov edx, [esp + 4 + 12] // argb
- mov ecx, [esp + 4 + 16] // width
- pcmpeqb xmm5, xmm5 // generate 0xffffffff for alpha
- pxor xmm4, xmm4
-
- align 4
- convertloop:
- READNV12
- YVUTORGB
-
- // Step 3: Weave into ARGB
- punpcklbw xmm0, xmm1 // BG
- punpcklbw xmm2, xmm5 // RA
- movdqa xmm1, xmm0
- punpcklwd xmm0, xmm2 // BGRA first 4 pixels
- punpckhwd xmm1, xmm2 // BGRA next 4 pixels
- movdqa [edx], xmm0
- movdqa [edx + 16], xmm1
- lea edx, [edx + 32]
- sub ecx, 8
- jg convertloop
-
- pop esi
- ret
- }
-}
-
-// 8 pixels, unaligned.
-// 8 UV values, mixed with 8 Y producing 8 ARGB (32 bytes).
-__declspec(naked) __declspec(align(16))
-void I444ToARGBRow_Unaligned_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_argb,
- int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // Y
- mov esi, [esp + 8 + 8] // U
- mov edi, [esp + 8 + 12] // V
- mov edx, [esp + 8 + 16] // argb
- mov ecx, [esp + 8 + 20] // width
- sub edi, esi
- pcmpeqb xmm5, xmm5 // generate 0xffffffff for alpha
- pxor xmm4, xmm4
-
- align 4
- convertloop:
- READYUV444
- YUVTORGB
-
- // Step 3: Weave into ARGB
- punpcklbw xmm0, xmm1 // BG
- punpcklbw xmm2, xmm5 // RA
- movdqa xmm1, xmm0
- punpcklwd xmm0, xmm2 // BGRA first 4 pixels
- punpckhwd xmm1, xmm2 // BGRA next 4 pixels
- movdqu [edx], xmm0
- movdqu [edx + 16], xmm1
- lea edx, [edx + 32]
- sub ecx, 8
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-// 8 pixels, unaligned.
-// 4 UV values upsampled to 8 UV, mixed with 8 Y producing 8 ARGB (32 bytes).
-__declspec(naked) __declspec(align(16))
-void I422ToARGBRow_Unaligned_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_argb,
- int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // Y
- mov esi, [esp + 8 + 8] // U
- mov edi, [esp + 8 + 12] // V
- mov edx, [esp + 8 + 16] // argb
- mov ecx, [esp + 8 + 20] // width
- sub edi, esi
- pcmpeqb xmm5, xmm5 // generate 0xffffffff for alpha
- pxor xmm4, xmm4
-
- align 4
- convertloop:
- READYUV422
- YUVTORGB
-
- // Step 3: Weave into ARGB
- punpcklbw xmm0, xmm1 // BG
- punpcklbw xmm2, xmm5 // RA
- movdqa xmm1, xmm0
- punpcklwd xmm0, xmm2 // BGRA first 4 pixels
- punpckhwd xmm1, xmm2 // BGRA next 4 pixels
- movdqu [edx], xmm0
- movdqu [edx + 16], xmm1
- lea edx, [edx + 32]
- sub ecx, 8
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-// 8 pixels, unaligned.
-// 2 UV values upsampled to 8 UV, mixed with 8 Y producing 8 ARGB (32 bytes).
-// Similar to I420 but duplicate UV once more.
-__declspec(naked) __declspec(align(16))
-void I411ToARGBRow_Unaligned_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_argb,
- int width) {
- __asm {
- push ebx
- push esi
- push edi
- mov eax, [esp + 12 + 4] // Y
- mov esi, [esp + 12 + 8] // U
- mov edi, [esp + 12 + 12] // V
- mov edx, [esp + 12 + 16] // argb
- mov ecx, [esp + 12 + 20] // width
- sub edi, esi
- pcmpeqb xmm5, xmm5 // generate 0xffffffff for alpha
- pxor xmm4, xmm4
-
- align 4
- convertloop:
- READYUV411 // modifies EBX
- YUVTORGB
-
- // Step 3: Weave into ARGB
- punpcklbw xmm0, xmm1 // BG
- punpcklbw xmm2, xmm5 // RA
- movdqa xmm1, xmm0
- punpcklwd xmm0, xmm2 // BGRA first 4 pixels
- punpckhwd xmm1, xmm2 // BGRA next 4 pixels
- movdqu [edx], xmm0
- movdqu [edx + 16], xmm1
- lea edx, [edx + 32]
- sub ecx, 8
- jg convertloop
-
- pop edi
- pop esi
- pop ebx
- ret
- }
-}
-
-// 8 pixels, dest aligned 16.
-// 4 UV values upsampled to 8 UV, mixed with 8 Y producing 8 ARGB (32 bytes).
-__declspec(naked) __declspec(align(16))
-void NV12ToARGBRow_Unaligned_SSSE3(const uint8* y_buf,
- const uint8* uv_buf,
- uint8* dst_argb,
- int width) {
- __asm {
- push esi
- mov eax, [esp + 4 + 4] // Y
- mov esi, [esp + 4 + 8] // UV
- mov edx, [esp + 4 + 12] // argb
- mov ecx, [esp + 4 + 16] // width
- pcmpeqb xmm5, xmm5 // generate 0xffffffff for alpha
- pxor xmm4, xmm4
-
- align 4
- convertloop:
- READNV12
- YUVTORGB
-
- // Step 3: Weave into ARGB
- punpcklbw xmm0, xmm1 // BG
- punpcklbw xmm2, xmm5 // RA
- movdqa xmm1, xmm0
- punpcklwd xmm0, xmm2 // BGRA first 4 pixels
- punpckhwd xmm1, xmm2 // BGRA next 4 pixels
- movdqu [edx], xmm0
- movdqu [edx + 16], xmm1
- lea edx, [edx + 32]
- sub ecx, 8
- jg convertloop
-
- pop esi
- ret
- }
-}
-
-// 8 pixels, dest aligned 16.
-// 4 UV values upsampled to 8 UV, mixed with 8 Y producing 8 ARGB (32 bytes).
-__declspec(naked) __declspec(align(16))
-void NV21ToARGBRow_Unaligned_SSSE3(const uint8* y_buf,
- const uint8* uv_buf,
- uint8* dst_argb,
- int width) {
- __asm {
- push esi
- mov eax, [esp + 4 + 4] // Y
- mov esi, [esp + 4 + 8] // VU
- mov edx, [esp + 4 + 12] // argb
- mov ecx, [esp + 4 + 16] // width
- pcmpeqb xmm5, xmm5 // generate 0xffffffff for alpha
- pxor xmm4, xmm4
-
- align 4
- convertloop:
- READNV12
- YVUTORGB
-
- // Step 3: Weave into ARGB
- punpcklbw xmm0, xmm1 // BG
- punpcklbw xmm2, xmm5 // RA
- movdqa xmm1, xmm0
- punpcklwd xmm0, xmm2 // BGRA first 4 pixels
- punpckhwd xmm1, xmm2 // BGRA next 4 pixels
- movdqu [edx], xmm0
- movdqu [edx + 16], xmm1
- lea edx, [edx + 32]
- sub ecx, 8
- jg convertloop
-
- pop esi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void I422ToBGRARow_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_bgra,
- int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // Y
- mov esi, [esp + 8 + 8] // U
- mov edi, [esp + 8 + 12] // V
- mov edx, [esp + 8 + 16] // bgra
- mov ecx, [esp + 8 + 20] // width
- sub edi, esi
- pxor xmm4, xmm4
-
- align 4
- convertloop:
- READYUV422
- YUVTORGB
-
- // Step 3: Weave into BGRA
- pcmpeqb xmm5, xmm5 // generate 0xffffffff for alpha
- punpcklbw xmm1, xmm0 // GB
- punpcklbw xmm5, xmm2 // AR
- movdqa xmm0, xmm5
- punpcklwd xmm5, xmm1 // BGRA first 4 pixels
- punpckhwd xmm0, xmm1 // BGRA next 4 pixels
- movdqa [edx], xmm5
- movdqa [edx + 16], xmm0
- lea edx, [edx + 32]
- sub ecx, 8
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void I422ToBGRARow_Unaligned_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_bgra,
- int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // Y
- mov esi, [esp + 8 + 8] // U
- mov edi, [esp + 8 + 12] // V
- mov edx, [esp + 8 + 16] // bgra
- mov ecx, [esp + 8 + 20] // width
- sub edi, esi
- pxor xmm4, xmm4
-
- align 4
- convertloop:
- READYUV422
- YUVTORGB
-
- // Step 3: Weave into BGRA
- pcmpeqb xmm5, xmm5 // generate 0xffffffff for alpha
- punpcklbw xmm1, xmm0 // GB
- punpcklbw xmm5, xmm2 // AR
- movdqa xmm0, xmm5
- punpcklwd xmm5, xmm1 // BGRA first 4 pixels
- punpckhwd xmm0, xmm1 // BGRA next 4 pixels
- movdqu [edx], xmm5
- movdqu [edx + 16], xmm0
- lea edx, [edx + 32]
- sub ecx, 8
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void I422ToABGRRow_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_abgr,
- int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // Y
- mov esi, [esp + 8 + 8] // U
- mov edi, [esp + 8 + 12] // V
- mov edx, [esp + 8 + 16] // abgr
- mov ecx, [esp + 8 + 20] // width
- sub edi, esi
- pcmpeqb xmm5, xmm5 // generate 0xffffffff for alpha
- pxor xmm4, xmm4
-
- align 4
- convertloop:
- READYUV422
- YUVTORGB
-
- // Step 3: Weave into ARGB
- punpcklbw xmm2, xmm1 // RG
- punpcklbw xmm0, xmm5 // BA
- movdqa xmm1, xmm2
- punpcklwd xmm2, xmm0 // RGBA first 4 pixels
- punpckhwd xmm1, xmm0 // RGBA next 4 pixels
- movdqa [edx], xmm2
- movdqa [edx + 16], xmm1
- lea edx, [edx + 32]
- sub ecx, 8
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void I422ToABGRRow_Unaligned_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_abgr,
- int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // Y
- mov esi, [esp + 8 + 8] // U
- mov edi, [esp + 8 + 12] // V
- mov edx, [esp + 8 + 16] // abgr
- mov ecx, [esp + 8 + 20] // width
- sub edi, esi
- pcmpeqb xmm5, xmm5 // generate 0xffffffff for alpha
- pxor xmm4, xmm4
-
- align 4
- convertloop:
- READYUV422
- YUVTORGB
-
- // Step 3: Weave into ARGB
- punpcklbw xmm2, xmm1 // RG
- punpcklbw xmm0, xmm5 // BA
- movdqa xmm1, xmm2
- punpcklwd xmm2, xmm0 // RGBA first 4 pixels
- punpckhwd xmm1, xmm0 // RGBA next 4 pixels
- movdqu [edx], xmm2
- movdqu [edx + 16], xmm1
- lea edx, [edx + 32]
- sub ecx, 8
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void I422ToRGBARow_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_rgba,
- int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // Y
- mov esi, [esp + 8 + 8] // U
- mov edi, [esp + 8 + 12] // V
- mov edx, [esp + 8 + 16] // rgba
- mov ecx, [esp + 8 + 20] // width
- sub edi, esi
- pxor xmm4, xmm4
-
- align 4
- convertloop:
- READYUV422
- YUVTORGB
-
- // Step 3: Weave into RGBA
- pcmpeqb xmm5, xmm5 // generate 0xffffffff for alpha
- punpcklbw xmm1, xmm2 // GR
- punpcklbw xmm5, xmm0 // AB
- movdqa xmm0, xmm5
- punpcklwd xmm5, xmm1 // RGBA first 4 pixels
- punpckhwd xmm0, xmm1 // RGBA next 4 pixels
- movdqa [edx], xmm5
- movdqa [edx + 16], xmm0
- lea edx, [edx + 32]
- sub ecx, 8
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void I422ToRGBARow_Unaligned_SSSE3(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* dst_rgba,
- int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // Y
- mov esi, [esp + 8 + 8] // U
- mov edi, [esp + 8 + 12] // V
- mov edx, [esp + 8 + 16] // rgba
- mov ecx, [esp + 8 + 20] // width
- sub edi, esi
- pxor xmm4, xmm4
-
- align 4
- convertloop:
- READYUV422
- YUVTORGB
-
- // Step 3: Weave into RGBA
- pcmpeqb xmm5, xmm5 // generate 0xffffffff for alpha
- punpcklbw xmm1, xmm2 // GR
- punpcklbw xmm5, xmm0 // AB
- movdqa xmm0, xmm5
- punpcklwd xmm5, xmm1 // RGBA first 4 pixels
- punpckhwd xmm0, xmm1 // RGBA next 4 pixels
- movdqu [edx], xmm5
- movdqu [edx + 16], xmm0
- lea edx, [edx + 32]
- sub ecx, 8
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-#endif // HAS_I422TOARGBROW_SSSE3
-
-#ifdef HAS_YTOARGBROW_SSE2
-__declspec(naked) __declspec(align(16))
-void YToARGBRow_SSE2(const uint8* y_buf,
- uint8* rgb_buf,
- int width) {
- __asm {
- pxor xmm5, xmm5
- pcmpeqb xmm4, xmm4 // generate mask 0xff000000
- pslld xmm4, 24
- mov eax, 0x00100010
- movd xmm3, eax
- pshufd xmm3, xmm3, 0
- mov eax, 0x004a004a // 74
- movd xmm2, eax
- pshufd xmm2, xmm2,0
- mov eax, [esp + 4] // Y
- mov edx, [esp + 8] // rgb
- mov ecx, [esp + 12] // width
-
- align 4
- convertloop:
- // Step 1: Scale Y contribution to 8 G values. G = (y - 16) * 1.164
- movq xmm0, qword ptr [eax]
- lea eax, [eax + 8]
- punpcklbw xmm0, xmm5 // 0.Y
- psubusw xmm0, xmm3
- pmullw xmm0, xmm2
- psrlw xmm0, 6
- packuswb xmm0, xmm0 // G
-
- // Step 2: Weave into ARGB
- punpcklbw xmm0, xmm0 // GG
- movdqa xmm1, xmm0
- punpcklwd xmm0, xmm0 // BGRA first 4 pixels
- punpckhwd xmm1, xmm1 // BGRA next 4 pixels
- por xmm0, xmm4
- por xmm1, xmm4
- movdqa [edx], xmm0
- movdqa [edx + 16], xmm1
- lea edx, [edx + 32]
- sub ecx, 8
- jg convertloop
-
- ret
- }
-}
-#endif // HAS_YTOARGBROW_SSE2
-
-#ifdef HAS_MIRRORROW_SSSE3
-// Shuffle table for reversing the bytes.
-static const uvec8 kShuffleMirror = {
- 15u, 14u, 13u, 12u, 11u, 10u, 9u, 8u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u
-};
-
-__declspec(naked) __declspec(align(16))
-void MirrorRow_SSSE3(const uint8* src, uint8* dst, int width) {
- __asm {
- mov eax, [esp + 4] // src
- mov edx, [esp + 8] // dst
- mov ecx, [esp + 12] // width
- movdqa xmm5, kShuffleMirror
- lea eax, [eax - 16]
-
- align 4
- convertloop:
- movdqa xmm0, [eax + ecx]
- pshufb xmm0, xmm5
- sub ecx, 16
- movdqa [edx], xmm0
- lea edx, [edx + 16]
- jg convertloop
- ret
- }
-}
-#endif // HAS_MIRRORROW_SSSE3
-
-#ifdef HAS_MIRRORROW_AVX2
-// Shuffle table for reversing the bytes.
-static const ulvec8 kShuffleMirror_AVX2 = {
- 15u, 14u, 13u, 12u, 11u, 10u, 9u, 8u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u,
- 15u, 14u, 13u, 12u, 11u, 10u, 9u, 8u, 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u
-};
-
-__declspec(naked) __declspec(align(16))
-void MirrorRow_AVX2(const uint8* src, uint8* dst, int width) {
- __asm {
- mov eax, [esp + 4] // src
- mov edx, [esp + 8] // dst
- mov ecx, [esp + 12] // width
- vmovdqa ymm5, kShuffleMirror_AVX2
- lea eax, [eax - 32]
-
- align 4
- convertloop:
- vmovdqu ymm0, [eax + ecx]
- vpshufb ymm0, ymm0, ymm5
- vpermq ymm0, ymm0, 0x4e // swap high and low halfs
- sub ecx, 32
- vmovdqu [edx], ymm0
- lea edx, [edx + 32]
- jg convertloop
- vzeroupper
- ret
- }
-}
-#endif // HAS_MIRRORROW_AVX2
-
-#ifdef HAS_MIRRORROW_SSE2
-// SSE2 version has movdqu so it can be used on unaligned buffers when SSSE3
-// version can not.
-__declspec(naked) __declspec(align(16))
-void MirrorRow_SSE2(const uint8* src, uint8* dst, int width) {
- __asm {
- mov eax, [esp + 4] // src
- mov edx, [esp + 8] // dst
- mov ecx, [esp + 12] // width
- lea eax, [eax - 16]
-
- align 4
- convertloop:
- movdqu xmm0, [eax + ecx]
- movdqa xmm1, xmm0 // swap bytes
- psllw xmm0, 8
- psrlw xmm1, 8
- por xmm0, xmm1
- pshuflw xmm0, xmm0, 0x1b // swap words
- pshufhw xmm0, xmm0, 0x1b
- pshufd xmm0, xmm0, 0x4e // swap qwords
- sub ecx, 16
- movdqu [edx], xmm0
- lea edx, [edx + 16]
- jg convertloop
- ret
- }
-}
-#endif // HAS_MIRRORROW_SSE2
-
-#ifdef HAS_MIRRORROW_UV_SSSE3
-// Shuffle table for reversing the bytes of UV channels.
-static const uvec8 kShuffleMirrorUV = {
- 14u, 12u, 10u, 8u, 6u, 4u, 2u, 0u, 15u, 13u, 11u, 9u, 7u, 5u, 3u, 1u
-};
-
-__declspec(naked) __declspec(align(16))
-void MirrorUVRow_SSSE3(const uint8* src, uint8* dst_u, uint8* dst_v,
- int width) {
- __asm {
- push edi
- mov eax, [esp + 4 + 4] // src
- mov edx, [esp + 4 + 8] // dst_u
- mov edi, [esp + 4 + 12] // dst_v
- mov ecx, [esp + 4 + 16] // width
- movdqa xmm1, kShuffleMirrorUV
- lea eax, [eax + ecx * 2 - 16]
- sub edi, edx
-
- align 4
- convertloop:
- movdqa xmm0, [eax]
- lea eax, [eax - 16]
- pshufb xmm0, xmm1
- sub ecx, 8
- movlpd qword ptr [edx], xmm0
- movhpd qword ptr [edx + edi], xmm0
- lea edx, [edx + 8]
- jg convertloop
-
- pop edi
- ret
- }
-}
-#endif // HAS_MIRRORROW_UV_SSSE3
-
-#ifdef HAS_ARGBMIRRORROW_SSSE3
-// Shuffle table for reversing the bytes.
-static const uvec8 kARGBShuffleMirror = {
- 12u, 13u, 14u, 15u, 8u, 9u, 10u, 11u, 4u, 5u, 6u, 7u, 0u, 1u, 2u, 3u
-};
-
-__declspec(naked) __declspec(align(16))
-void ARGBMirrorRow_SSSE3(const uint8* src, uint8* dst, int width) {
- __asm {
- mov eax, [esp + 4] // src
- mov edx, [esp + 8] // dst
- mov ecx, [esp + 12] // width
- lea eax, [eax - 16 + ecx * 4] // last 4 pixels.
- movdqa xmm5, kARGBShuffleMirror
-
- align 4
- convertloop:
- movdqa xmm0, [eax]
- lea eax, [eax - 16]
- pshufb xmm0, xmm5
- sub ecx, 4
- movdqa [edx], xmm0
- lea edx, [edx + 16]
- jg convertloop
- ret
- }
-}
-#endif // HAS_ARGBMIRRORROW_SSSE3
-
-#ifdef HAS_ARGBMIRRORROW_AVX2
-// Shuffle table for reversing the bytes.
-static const ulvec32 kARGBShuffleMirror_AVX2 = {
- 7u, 6u, 5u, 4u, 3u, 2u, 1u, 0u
-};
-
-__declspec(naked) __declspec(align(16))
-void ARGBMirrorRow_AVX2(const uint8* src, uint8* dst, int width) {
- __asm {
- mov eax, [esp + 4] // src
- mov edx, [esp + 8] // dst
- mov ecx, [esp + 12] // width
- lea eax, [eax - 32]
- vmovdqa ymm5, kARGBShuffleMirror_AVX2
-
- align 4
- convertloop:
- vpermd ymm0, ymm5, [eax + ecx * 4] // permute dword order
- sub ecx, 8
- vmovdqu [edx], ymm0
- lea edx, [edx + 32]
- jg convertloop
- vzeroupper
- ret
- }
-}
-#endif // HAS_ARGBMIRRORROW_AVX2
-
-#ifdef HAS_SPLITUVROW_SSE2
-__declspec(naked) __declspec(align(16))
-void SplitUVRow_SSE2(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int pix) {
- __asm {
- push edi
- mov eax, [esp + 4 + 4] // src_uv
- mov edx, [esp + 4 + 8] // dst_u
- mov edi, [esp + 4 + 12] // dst_v
- mov ecx, [esp + 4 + 16] // pix
- pcmpeqb xmm5, xmm5 // generate mask 0x00ff00ff
- psrlw xmm5, 8
- sub edi, edx
-
- align 4
- convertloop:
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- lea eax, [eax + 32]
- movdqa xmm2, xmm0
- movdqa xmm3, xmm1
- pand xmm0, xmm5 // even bytes
- pand xmm1, xmm5
- packuswb xmm0, xmm1
- psrlw xmm2, 8 // odd bytes
- psrlw xmm3, 8
- packuswb xmm2, xmm3
- movdqa [edx], xmm0
- movdqa [edx + edi], xmm2
- lea edx, [edx + 16]
- sub ecx, 16
- jg convertloop
-
- pop edi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void SplitUVRow_Unaligned_SSE2(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
- int pix) {
- __asm {
- push edi
- mov eax, [esp + 4 + 4] // src_uv
- mov edx, [esp + 4 + 8] // dst_u
- mov edi, [esp + 4 + 12] // dst_v
- mov ecx, [esp + 4 + 16] // pix
- pcmpeqb xmm5, xmm5 // generate mask 0x00ff00ff
- psrlw xmm5, 8
- sub edi, edx
-
- align 4
- convertloop:
- movdqu xmm0, [eax]
- movdqu xmm1, [eax + 16]
- lea eax, [eax + 32]
- movdqa xmm2, xmm0
- movdqa xmm3, xmm1
- pand xmm0, xmm5 // even bytes
- pand xmm1, xmm5
- packuswb xmm0, xmm1
- psrlw xmm2, 8 // odd bytes
- psrlw xmm3, 8
- packuswb xmm2, xmm3
- movdqu [edx], xmm0
- movdqu [edx + edi], xmm2
- lea edx, [edx + 16]
- sub ecx, 16
- jg convertloop
-
- pop edi
- ret
- }
-}
-#endif // HAS_SPLITUVROW_SSE2
-
-#ifdef HAS_SPLITUVROW_AVX2
-__declspec(naked) __declspec(align(16))
-void SplitUVRow_AVX2(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int pix) {
- __asm {
- push edi
- mov eax, [esp + 4 + 4] // src_uv
- mov edx, [esp + 4 + 8] // dst_u
- mov edi, [esp + 4 + 12] // dst_v
- mov ecx, [esp + 4 + 16] // pix
- vpcmpeqb ymm5, ymm5, ymm5 // generate mask 0x00ff00ff
- vpsrlw ymm5, ymm5, 8
- sub edi, edx
-
- align 4
- convertloop:
- vmovdqu ymm0, [eax]
- vmovdqu ymm1, [eax + 32]
- lea eax, [eax + 64]
- vpsrlw ymm2, ymm0, 8 // odd bytes
- vpsrlw ymm3, ymm1, 8
- vpand ymm0, ymm0, ymm5 // even bytes
- vpand ymm1, ymm1, ymm5
- vpackuswb ymm0, ymm0, ymm1
- vpackuswb ymm2, ymm2, ymm3
- vpermq ymm0, ymm0, 0xd8
- vpermq ymm2, ymm2, 0xd8
- vmovdqu [edx], ymm0
- vmovdqu [edx + edi], ymm2
- lea edx, [edx + 32]
- sub ecx, 32
- jg convertloop
-
- pop edi
- vzeroupper
- ret
- }
-}
-#endif // HAS_SPLITUVROW_AVX2
-
-#ifdef HAS_MERGEUVROW_SSE2
-__declspec(naked) __declspec(align(16))
-void MergeUVRow_SSE2(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
- int width) {
- __asm {
- push edi
- mov eax, [esp + 4 + 4] // src_u
- mov edx, [esp + 4 + 8] // src_v
- mov edi, [esp + 4 + 12] // dst_uv
- mov ecx, [esp + 4 + 16] // width
- sub edx, eax
-
- align 4
- convertloop:
- movdqa xmm0, [eax] // read 16 U's
- movdqa xmm1, [eax + edx] // and 16 V's
- lea eax, [eax + 16]
- movdqa xmm2, xmm0
- punpcklbw xmm0, xmm1 // first 8 UV pairs
- punpckhbw xmm2, xmm1 // next 8 UV pairs
- movdqa [edi], xmm0
- movdqa [edi + 16], xmm2
- lea edi, [edi + 32]
- sub ecx, 16
- jg convertloop
-
- pop edi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void MergeUVRow_Unaligned_SSE2(const uint8* src_u, const uint8* src_v,
- uint8* dst_uv, int width) {
- __asm {
- push edi
- mov eax, [esp + 4 + 4] // src_u
- mov edx, [esp + 4 + 8] // src_v
- mov edi, [esp + 4 + 12] // dst_uv
- mov ecx, [esp + 4 + 16] // width
- sub edx, eax
-
- align 4
- convertloop:
- movdqu xmm0, [eax] // read 16 U's
- movdqu xmm1, [eax + edx] // and 16 V's
- lea eax, [eax + 16]
- movdqa xmm2, xmm0
- punpcklbw xmm0, xmm1 // first 8 UV pairs
- punpckhbw xmm2, xmm1 // next 8 UV pairs
- movdqu [edi], xmm0
- movdqu [edi + 16], xmm2
- lea edi, [edi + 32]
- sub ecx, 16
- jg convertloop
-
- pop edi
- ret
- }
-}
-#endif // HAS_MERGEUVROW_SSE2
-
-#ifdef HAS_MERGEUVROW_AVX2
-__declspec(naked) __declspec(align(16))
-void MergeUVRow_AVX2(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
- int width) {
- __asm {
- push edi
- mov eax, [esp + 4 + 4] // src_u
- mov edx, [esp + 4 + 8] // src_v
- mov edi, [esp + 4 + 12] // dst_uv
- mov ecx, [esp + 4 + 16] // width
- sub edx, eax
-
- align 4
- convertloop:
- vmovdqu ymm0, [eax] // read 32 U's
- vmovdqu ymm1, [eax + edx] // and 32 V's
- lea eax, [eax + 32]
- vpunpcklbw ymm2, ymm0, ymm1 // low 16 UV pairs. mutated qqword 0,2
- vpunpckhbw ymm0, ymm0, ymm1 // high 16 UV pairs. mutated qqword 1,3
- vperm2i128 ymm1, ymm2, ymm0, 0x20 // low 128 of ymm2 and low 128 of ymm0
- vperm2i128 ymm2, ymm2, ymm0, 0x31 // high 128 of ymm2 and high 128 of ymm0
- vmovdqu [edi], ymm1
- vmovdqu [edi + 32], ymm2
- lea edi, [edi + 64]
- sub ecx, 32
- jg convertloop
-
- pop edi
- vzeroupper
- ret
- }
-}
-#endif // HAS_MERGEUVROW_AVX2
-
-#ifdef HAS_COPYROW_SSE2
-// CopyRow copys 'count' bytes using a 16 byte load/store, 32 bytes at time.
-__declspec(naked) __declspec(align(16))
-void CopyRow_SSE2(const uint8* src, uint8* dst, int count) {
- __asm {
- mov eax, [esp + 4] // src
- mov edx, [esp + 8] // dst
- mov ecx, [esp + 12] // count
-
- align 4
- convertloop:
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- lea eax, [eax + 32]
- movdqa [edx], xmm0
- movdqa [edx + 16], xmm1
- lea edx, [edx + 32]
- sub ecx, 32
- jg convertloop
- ret
- }
-}
-#endif // HAS_COPYROW_SSE2
-
-// Unaligned Multiple of 1.
-__declspec(naked) __declspec(align(16))
-void CopyRow_ERMS(const uint8* src, uint8* dst, int count) {
- __asm {
- mov eax, esi
- mov edx, edi
- mov esi, [esp + 4] // src
- mov edi, [esp + 8] // dst
- mov ecx, [esp + 12] // count
- rep movsb
- mov edi, edx
- mov esi, eax
- ret
- }
-}
-
-#ifdef HAS_COPYROW_X86
-__declspec(naked) __declspec(align(16))
-void CopyRow_X86(const uint8* src, uint8* dst, int count) {
- __asm {
- mov eax, esi
- mov edx, edi
- mov esi, [esp + 4] // src
- mov edi, [esp + 8] // dst
- mov ecx, [esp + 12] // count
- shr ecx, 2
- rep movsd
- mov edi, edx
- mov esi, eax
- ret
- }
-}
-#endif // HAS_COPYROW_X86
-
-#ifdef HAS_ARGBCOPYALPHAROW_SSE2
-// width in pixels
-__declspec(naked) __declspec(align(16))
-void ARGBCopyAlphaRow_SSE2(const uint8* src, uint8* dst, int width) {
- __asm {
- mov eax, [esp + 4] // src
- mov edx, [esp + 8] // dst
- mov ecx, [esp + 12] // count
- pcmpeqb xmm0, xmm0 // generate mask 0xff000000
- pslld xmm0, 24
- pcmpeqb xmm1, xmm1 // generate mask 0x00ffffff
- psrld xmm1, 8
-
- align 4
- convertloop:
- movdqa xmm2, [eax]
- movdqa xmm3, [eax + 16]
- lea eax, [eax + 32]
- movdqa xmm4, [edx]
- movdqa xmm5, [edx + 16]
- pand xmm2, xmm0
- pand xmm3, xmm0
- pand xmm4, xmm1
- pand xmm5, xmm1
- por xmm2, xmm4
- por xmm3, xmm5
- movdqa [edx], xmm2
- movdqa [edx + 16], xmm3
- lea edx, [edx + 32]
- sub ecx, 8
- jg convertloop
-
- ret
- }
-}
-#endif // HAS_ARGBCOPYALPHAROW_SSE2
-
-#ifdef HAS_ARGBCOPYALPHAROW_AVX2
-// width in pixels
-__declspec(naked) __declspec(align(16))
-void ARGBCopyAlphaRow_AVX2(const uint8* src, uint8* dst, int width) {
- __asm {
- mov eax, [esp + 4] // src
- mov edx, [esp + 8] // dst
- mov ecx, [esp + 12] // count
- vpcmpeqb ymm0, ymm0, ymm0
- vpsrld ymm0, ymm0, 8 // generate mask 0x00ffffff
-
- align 4
- convertloop:
- vmovdqu ymm1, [eax]
- vmovdqu ymm2, [eax + 32]
- lea eax, [eax + 64]
- vpblendvb ymm1, ymm1, [edx], ymm0
- vpblendvb ymm2, ymm2, [edx + 32], ymm0
- vmovdqu [edx], ymm1
- vmovdqu [edx + 32], ymm2
- lea edx, [edx + 64]
- sub ecx, 16
- jg convertloop
-
- vzeroupper
- ret
- }
-}
-#endif // HAS_ARGBCOPYALPHAROW_AVX2
-
-#ifdef HAS_ARGBCOPYYTOALPHAROW_SSE2
-// width in pixels
-__declspec(naked) __declspec(align(16))
-void ARGBCopyYToAlphaRow_SSE2(const uint8* src, uint8* dst, int width) {
- __asm {
- mov eax, [esp + 4] // src
- mov edx, [esp + 8] // dst
- mov ecx, [esp + 12] // count
- pcmpeqb xmm0, xmm0 // generate mask 0xff000000
- pslld xmm0, 24
- pcmpeqb xmm1, xmm1 // generate mask 0x00ffffff
- psrld xmm1, 8
-
- align 4
- convertloop:
- movq xmm2, qword ptr [eax] // 8 Y's
- lea eax, [eax + 8]
- punpcklbw xmm2, xmm2
- punpckhwd xmm3, xmm2
- punpcklwd xmm2, xmm2
- movdqa xmm4, [edx]
- movdqa xmm5, [edx + 16]
- pand xmm2, xmm0
- pand xmm3, xmm0
- pand xmm4, xmm1
- pand xmm5, xmm1
- por xmm2, xmm4
- por xmm3, xmm5
- movdqa [edx], xmm2
- movdqa [edx + 16], xmm3
- lea edx, [edx + 32]
- sub ecx, 8
- jg convertloop
-
- ret
- }
-}
-#endif // HAS_ARGBCOPYYTOALPHAROW_SSE2
-
-#ifdef HAS_ARGBCOPYYTOALPHAROW_AVX2
-// width in pixels
-__declspec(naked) __declspec(align(16))
-void ARGBCopyYToAlphaRow_AVX2(const uint8* src, uint8* dst, int width) {
- __asm {
- mov eax, [esp + 4] // src
- mov edx, [esp + 8] // dst
- mov ecx, [esp + 12] // count
- vpcmpeqb ymm0, ymm0, ymm0
- vpsrld ymm0, ymm0, 8 // generate mask 0x00ffffff
-
- align 4
- convertloop:
- vpmovzxbd ymm1, qword ptr [eax]
- vpmovzxbd ymm2, qword ptr [eax + 8]
- lea eax, [eax + 16]
- vpslld ymm1, ymm1, 24
- vpslld ymm2, ymm2, 24
- vpblendvb ymm1, ymm1, [edx], ymm0
- vpblendvb ymm2, ymm2, [edx + 32], ymm0
- vmovdqu [edx], ymm1
- vmovdqu [edx + 32], ymm2
- lea edx, [edx + 64]
- sub ecx, 16
- jg convertloop
-
- vzeroupper
- ret
- }
-}
-#endif // HAS_ARGBCOPYYTOALPHAROW_AVX2
-
-#ifdef HAS_SETROW_X86
-// SetRow8 writes 'count' bytes using a 32 bit value repeated.
-__declspec(naked) __declspec(align(16))
-void SetRow_X86(uint8* dst, uint32 v32, int count) {
- __asm {
- mov edx, edi
- mov edi, [esp + 4] // dst
- mov eax, [esp + 8] // v32
- mov ecx, [esp + 12] // count
- shr ecx, 2
- rep stosd
- mov edi, edx
- ret
- }
-}
-
-// SetRow32 writes 'count' words using a 32 bit value repeated.
-__declspec(naked) __declspec(align(16))
-void ARGBSetRows_X86(uint8* dst, uint32 v32, int width,
- int dst_stride, int height) {
- __asm {
- push esi
- push edi
- push ebp
- mov edi, [esp + 12 + 4] // dst
- mov eax, [esp + 12 + 8] // v32
- mov ebp, [esp + 12 + 12] // width
- mov edx, [esp + 12 + 16] // dst_stride
- mov esi, [esp + 12 + 20] // height
- lea ecx, [ebp * 4]
- sub edx, ecx // stride - width * 4
-
- align 4
- convertloop:
- mov ecx, ebp
- rep stosd
- add edi, edx
- sub esi, 1
- jg convertloop
-
- pop ebp
- pop edi
- pop esi
- ret
- }
-}
-#endif // HAS_SETROW_X86
-
-#ifdef HAS_YUY2TOYROW_AVX2
-__declspec(naked) __declspec(align(16))
-void YUY2ToYRow_AVX2(const uint8* src_yuy2,
- uint8* dst_y, int pix) {
- __asm {
- mov eax, [esp + 4] // src_yuy2
- mov edx, [esp + 8] // dst_y
- mov ecx, [esp + 12] // pix
- vpcmpeqb ymm5, ymm5, ymm5 // generate mask 0x00ff00ff
- vpsrlw ymm5, ymm5, 8
-
- align 4
- convertloop:
- vmovdqu ymm0, [eax]
- vmovdqu ymm1, [eax + 32]
- lea eax, [eax + 64]
- vpand ymm0, ymm0, ymm5 // even bytes are Y
- vpand ymm1, ymm1, ymm5
- vpackuswb ymm0, ymm0, ymm1 // mutates.
- vpermq ymm0, ymm0, 0xd8
- sub ecx, 32
- vmovdqu [edx], ymm0
- lea edx, [edx + 32]
- jg convertloop
- vzeroupper
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void YUY2ToUVRow_AVX2(const uint8* src_yuy2, int stride_yuy2,
- uint8* dst_u, uint8* dst_v, int pix) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // src_yuy2
- mov esi, [esp + 8 + 8] // stride_yuy2
- mov edx, [esp + 8 + 12] // dst_u
- mov edi, [esp + 8 + 16] // dst_v
- mov ecx, [esp + 8 + 20] // pix
- vpcmpeqb ymm5, ymm5, ymm5 // generate mask 0x00ff00ff
- vpsrlw ymm5, ymm5, 8
- sub edi, edx
-
- align 4
- convertloop:
- vmovdqu ymm0, [eax]
- vmovdqu ymm1, [eax + 32]
- vpavgb ymm0, ymm0, [eax + esi]
- vpavgb ymm1, ymm1, [eax + esi + 32]
- lea eax, [eax + 64]
- vpsrlw ymm0, ymm0, 8 // YUYV -> UVUV
- vpsrlw ymm1, ymm1, 8
- vpackuswb ymm0, ymm0, ymm1 // mutates.
- vpermq ymm0, ymm0, 0xd8
- vpand ymm1, ymm0, ymm5 // U
- vpsrlw ymm0, ymm0, 8 // V
- vpackuswb ymm1, ymm1, ymm1 // mutates.
- vpackuswb ymm0, ymm0, ymm0 // mutates.
- vpermq ymm1, ymm1, 0xd8
- vpermq ymm0, ymm0, 0xd8
- vextractf128 [edx], ymm1, 0 // U
- vextractf128 [edx + edi], ymm0, 0 // V
- lea edx, [edx + 16]
- sub ecx, 32
- jg convertloop
-
- pop edi
- pop esi
- vzeroupper
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void YUY2ToUV422Row_AVX2(const uint8* src_yuy2,
- uint8* dst_u, uint8* dst_v, int pix) {
- __asm {
- push edi
- mov eax, [esp + 4 + 4] // src_yuy2
- mov edx, [esp + 4 + 8] // dst_u
- mov edi, [esp + 4 + 12] // dst_v
- mov ecx, [esp + 4 + 16] // pix
- vpcmpeqb ymm5, ymm5, ymm5 // generate mask 0x00ff00ff
- vpsrlw ymm5, ymm5, 8
- sub edi, edx
-
- align 4
- convertloop:
- vmovdqu ymm0, [eax]
- vmovdqu ymm1, [eax + 32]
- lea eax, [eax + 64]
- vpsrlw ymm0, ymm0, 8 // YUYV -> UVUV
- vpsrlw ymm1, ymm1, 8
- vpackuswb ymm0, ymm0, ymm1 // mutates.
- vpermq ymm0, ymm0, 0xd8
- vpand ymm1, ymm0, ymm5 // U
- vpsrlw ymm0, ymm0, 8 // V
- vpackuswb ymm1, ymm1, ymm1 // mutates.
- vpackuswb ymm0, ymm0, ymm0 // mutates.
- vpermq ymm1, ymm1, 0xd8
- vpermq ymm0, ymm0, 0xd8
- vextractf128 [edx], ymm1, 0 // U
- vextractf128 [edx + edi], ymm0, 0 // V
- lea edx, [edx + 16]
- sub ecx, 32
- jg convertloop
-
- pop edi
- vzeroupper
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void UYVYToYRow_AVX2(const uint8* src_uyvy,
- uint8* dst_y, int pix) {
- __asm {
- mov eax, [esp + 4] // src_uyvy
- mov edx, [esp + 8] // dst_y
- mov ecx, [esp + 12] // pix
-
- align 4
- convertloop:
- vmovdqu ymm0, [eax]
- vmovdqu ymm1, [eax + 32]
- lea eax, [eax + 64]
- vpsrlw ymm0, ymm0, 8 // odd bytes are Y
- vpsrlw ymm1, ymm1, 8
- vpackuswb ymm0, ymm0, ymm1 // mutates.
- vpermq ymm0, ymm0, 0xd8
- sub ecx, 32
- vmovdqu [edx], ymm0
- lea edx, [edx + 32]
- jg convertloop
- ret
- vzeroupper
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void UYVYToUVRow_AVX2(const uint8* src_uyvy, int stride_uyvy,
- uint8* dst_u, uint8* dst_v, int pix) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // src_yuy2
- mov esi, [esp + 8 + 8] // stride_yuy2
- mov edx, [esp + 8 + 12] // dst_u
- mov edi, [esp + 8 + 16] // dst_v
- mov ecx, [esp + 8 + 20] // pix
- vpcmpeqb ymm5, ymm5, ymm5 // generate mask 0x00ff00ff
- vpsrlw ymm5, ymm5, 8
- sub edi, edx
-
- align 4
- convertloop:
- vmovdqu ymm0, [eax]
- vmovdqu ymm1, [eax + 32]
- vpavgb ymm0, ymm0, [eax + esi]
- vpavgb ymm1, ymm1, [eax + esi + 32]
- lea eax, [eax + 64]
- vpand ymm0, ymm0, ymm5 // UYVY -> UVUV
- vpand ymm1, ymm1, ymm5
- vpackuswb ymm0, ymm0, ymm1 // mutates.
- vpermq ymm0, ymm0, 0xd8
- vpand ymm1, ymm0, ymm5 // U
- vpsrlw ymm0, ymm0, 8 // V
- vpackuswb ymm1, ymm1, ymm1 // mutates.
- vpackuswb ymm0, ymm0, ymm0 // mutates.
- vpermq ymm1, ymm1, 0xd8
- vpermq ymm0, ymm0, 0xd8
- vextractf128 [edx], ymm1, 0 // U
- vextractf128 [edx + edi], ymm0, 0 // V
- lea edx, [edx + 16]
- sub ecx, 32
- jg convertloop
-
- pop edi
- pop esi
- vzeroupper
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void UYVYToUV422Row_AVX2(const uint8* src_uyvy,
- uint8* dst_u, uint8* dst_v, int pix) {
- __asm {
- push edi
- mov eax, [esp + 4 + 4] // src_yuy2
- mov edx, [esp + 4 + 8] // dst_u
- mov edi, [esp + 4 + 12] // dst_v
- mov ecx, [esp + 4 + 16] // pix
- vpcmpeqb ymm5, ymm5, ymm5 // generate mask 0x00ff00ff
- vpsrlw ymm5, ymm5, 8
- sub edi, edx
-
- align 4
- convertloop:
- vmovdqu ymm0, [eax]
- vmovdqu ymm1, [eax + 32]
- lea eax, [eax + 64]
- vpand ymm0, ymm0, ymm5 // UYVY -> UVUV
- vpand ymm1, ymm1, ymm5
- vpackuswb ymm0, ymm0, ymm1 // mutates.
- vpermq ymm0, ymm0, 0xd8
- vpand ymm1, ymm0, ymm5 // U
- vpsrlw ymm0, ymm0, 8 // V
- vpackuswb ymm1, ymm1, ymm1 // mutates.
- vpackuswb ymm0, ymm0, ymm0 // mutates.
- vpermq ymm1, ymm1, 0xd8
- vpermq ymm0, ymm0, 0xd8
- vextractf128 [edx], ymm1, 0 // U
- vextractf128 [edx + edi], ymm0, 0 // V
- lea edx, [edx + 16]
- sub ecx, 32
- jg convertloop
-
- pop edi
- vzeroupper
- ret
- }
-}
-#endif // HAS_YUY2TOYROW_AVX2
-
-#ifdef HAS_YUY2TOYROW_SSE2
-__declspec(naked) __declspec(align(16))
-void YUY2ToYRow_SSE2(const uint8* src_yuy2,
- uint8* dst_y, int pix) {
- __asm {
- mov eax, [esp + 4] // src_yuy2
- mov edx, [esp + 8] // dst_y
- mov ecx, [esp + 12] // pix
- pcmpeqb xmm5, xmm5 // generate mask 0x00ff00ff
- psrlw xmm5, 8
-
- align 4
- convertloop:
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- lea eax, [eax + 32]
- pand xmm0, xmm5 // even bytes are Y
- pand xmm1, xmm5
- packuswb xmm0, xmm1
- sub ecx, 16
- movdqa [edx], xmm0
- lea edx, [edx + 16]
- jg convertloop
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void YUY2ToUVRow_SSE2(const uint8* src_yuy2, int stride_yuy2,
- uint8* dst_u, uint8* dst_v, int pix) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // src_yuy2
- mov esi, [esp + 8 + 8] // stride_yuy2
- mov edx, [esp + 8 + 12] // dst_u
- mov edi, [esp + 8 + 16] // dst_v
- mov ecx, [esp + 8 + 20] // pix
- pcmpeqb xmm5, xmm5 // generate mask 0x00ff00ff
- psrlw xmm5, 8
- sub edi, edx
-
- align 4
- convertloop:
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- movdqa xmm2, [eax + esi]
- movdqa xmm3, [eax + esi + 16]
- lea eax, [eax + 32]
- pavgb xmm0, xmm2
- pavgb xmm1, xmm3
- psrlw xmm0, 8 // YUYV -> UVUV
- psrlw xmm1, 8
- packuswb xmm0, xmm1
- movdqa xmm1, xmm0
- pand xmm0, xmm5 // U
- packuswb xmm0, xmm0
- psrlw xmm1, 8 // V
- packuswb xmm1, xmm1
- movq qword ptr [edx], xmm0
- movq qword ptr [edx + edi], xmm1
- lea edx, [edx + 8]
- sub ecx, 16
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void YUY2ToUV422Row_SSE2(const uint8* src_yuy2,
- uint8* dst_u, uint8* dst_v, int pix) {
- __asm {
- push edi
- mov eax, [esp + 4 + 4] // src_yuy2
- mov edx, [esp + 4 + 8] // dst_u
- mov edi, [esp + 4 + 12] // dst_v
- mov ecx, [esp + 4 + 16] // pix
- pcmpeqb xmm5, xmm5 // generate mask 0x00ff00ff
- psrlw xmm5, 8
- sub edi, edx
-
- align 4
- convertloop:
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- lea eax, [eax + 32]
- psrlw xmm0, 8 // YUYV -> UVUV
- psrlw xmm1, 8
- packuswb xmm0, xmm1
- movdqa xmm1, xmm0
- pand xmm0, xmm5 // U
- packuswb xmm0, xmm0
- psrlw xmm1, 8 // V
- packuswb xmm1, xmm1
- movq qword ptr [edx], xmm0
- movq qword ptr [edx + edi], xmm1
- lea edx, [edx + 8]
- sub ecx, 16
- jg convertloop
-
- pop edi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void YUY2ToYRow_Unaligned_SSE2(const uint8* src_yuy2,
- uint8* dst_y, int pix) {
- __asm {
- mov eax, [esp + 4] // src_yuy2
- mov edx, [esp + 8] // dst_y
- mov ecx, [esp + 12] // pix
- pcmpeqb xmm5, xmm5 // generate mask 0x00ff00ff
- psrlw xmm5, 8
-
- align 4
- convertloop:
- movdqu xmm0, [eax]
- movdqu xmm1, [eax + 16]
- lea eax, [eax + 32]
- pand xmm0, xmm5 // even bytes are Y
- pand xmm1, xmm5
- packuswb xmm0, xmm1
- sub ecx, 16
- movdqu [edx], xmm0
- lea edx, [edx + 16]
- jg convertloop
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void YUY2ToUVRow_Unaligned_SSE2(const uint8* src_yuy2, int stride_yuy2,
- uint8* dst_u, uint8* dst_v, int pix) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // src_yuy2
- mov esi, [esp + 8 + 8] // stride_yuy2
- mov edx, [esp + 8 + 12] // dst_u
- mov edi, [esp + 8 + 16] // dst_v
- mov ecx, [esp + 8 + 20] // pix
- pcmpeqb xmm5, xmm5 // generate mask 0x00ff00ff
- psrlw xmm5, 8
- sub edi, edx
-
- align 4
- convertloop:
- movdqu xmm0, [eax]
- movdqu xmm1, [eax + 16]
- movdqu xmm2, [eax + esi]
- movdqu xmm3, [eax + esi + 16]
- lea eax, [eax + 32]
- pavgb xmm0, xmm2
- pavgb xmm1, xmm3
- psrlw xmm0, 8 // YUYV -> UVUV
- psrlw xmm1, 8
- packuswb xmm0, xmm1
- movdqa xmm1, xmm0
- pand xmm0, xmm5 // U
- packuswb xmm0, xmm0
- psrlw xmm1, 8 // V
- packuswb xmm1, xmm1
- movq qword ptr [edx], xmm0
- movq qword ptr [edx + edi], xmm1
- lea edx, [edx + 8]
- sub ecx, 16
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void YUY2ToUV422Row_Unaligned_SSE2(const uint8* src_yuy2,
- uint8* dst_u, uint8* dst_v, int pix) {
- __asm {
- push edi
- mov eax, [esp + 4 + 4] // src_yuy2
- mov edx, [esp + 4 + 8] // dst_u
- mov edi, [esp + 4 + 12] // dst_v
- mov ecx, [esp + 4 + 16] // pix
- pcmpeqb xmm5, xmm5 // generate mask 0x00ff00ff
- psrlw xmm5, 8
- sub edi, edx
-
- align 4
- convertloop:
- movdqu xmm0, [eax]
- movdqu xmm1, [eax + 16]
- lea eax, [eax + 32]
- psrlw xmm0, 8 // YUYV -> UVUV
- psrlw xmm1, 8
- packuswb xmm0, xmm1
- movdqa xmm1, xmm0
- pand xmm0, xmm5 // U
- packuswb xmm0, xmm0
- psrlw xmm1, 8 // V
- packuswb xmm1, xmm1
- movq qword ptr [edx], xmm0
- movq qword ptr [edx + edi], xmm1
- lea edx, [edx + 8]
- sub ecx, 16
- jg convertloop
-
- pop edi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void UYVYToYRow_SSE2(const uint8* src_uyvy,
- uint8* dst_y, int pix) {
- __asm {
- mov eax, [esp + 4] // src_uyvy
- mov edx, [esp + 8] // dst_y
- mov ecx, [esp + 12] // pix
-
- align 4
- convertloop:
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- lea eax, [eax + 32]
- psrlw xmm0, 8 // odd bytes are Y
- psrlw xmm1, 8
- packuswb xmm0, xmm1
- sub ecx, 16
- movdqa [edx], xmm0
- lea edx, [edx + 16]
- jg convertloop
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void UYVYToUVRow_SSE2(const uint8* src_uyvy, int stride_uyvy,
- uint8* dst_u, uint8* dst_v, int pix) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // src_yuy2
- mov esi, [esp + 8 + 8] // stride_yuy2
- mov edx, [esp + 8 + 12] // dst_u
- mov edi, [esp + 8 + 16] // dst_v
- mov ecx, [esp + 8 + 20] // pix
- pcmpeqb xmm5, xmm5 // generate mask 0x00ff00ff
- psrlw xmm5, 8
- sub edi, edx
-
- align 4
- convertloop:
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- movdqa xmm2, [eax + esi]
- movdqa xmm3, [eax + esi + 16]
- lea eax, [eax + 32]
- pavgb xmm0, xmm2
- pavgb xmm1, xmm3
- pand xmm0, xmm5 // UYVY -> UVUV
- pand xmm1, xmm5
- packuswb xmm0, xmm1
- movdqa xmm1, xmm0
- pand xmm0, xmm5 // U
- packuswb xmm0, xmm0
- psrlw xmm1, 8 // V
- packuswb xmm1, xmm1
- movq qword ptr [edx], xmm0
- movq qword ptr [edx + edi], xmm1
- lea edx, [edx + 8]
- sub ecx, 16
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void UYVYToUV422Row_SSE2(const uint8* src_uyvy,
- uint8* dst_u, uint8* dst_v, int pix) {
- __asm {
- push edi
- mov eax, [esp + 4 + 4] // src_yuy2
- mov edx, [esp + 4 + 8] // dst_u
- mov edi, [esp + 4 + 12] // dst_v
- mov ecx, [esp + 4 + 16] // pix
- pcmpeqb xmm5, xmm5 // generate mask 0x00ff00ff
- psrlw xmm5, 8
- sub edi, edx
-
- align 4
- convertloop:
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- lea eax, [eax + 32]
- pand xmm0, xmm5 // UYVY -> UVUV
- pand xmm1, xmm5
- packuswb xmm0, xmm1
- movdqa xmm1, xmm0
- pand xmm0, xmm5 // U
- packuswb xmm0, xmm0
- psrlw xmm1, 8 // V
- packuswb xmm1, xmm1
- movq qword ptr [edx], xmm0
- movq qword ptr [edx + edi], xmm1
- lea edx, [edx + 8]
- sub ecx, 16
- jg convertloop
-
- pop edi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void UYVYToYRow_Unaligned_SSE2(const uint8* src_uyvy,
- uint8* dst_y, int pix) {
- __asm {
- mov eax, [esp + 4] // src_uyvy
- mov edx, [esp + 8] // dst_y
- mov ecx, [esp + 12] // pix
-
- align 4
- convertloop:
- movdqu xmm0, [eax]
- movdqu xmm1, [eax + 16]
- lea eax, [eax + 32]
- psrlw xmm0, 8 // odd bytes are Y
- psrlw xmm1, 8
- packuswb xmm0, xmm1
- sub ecx, 16
- movdqu [edx], xmm0
- lea edx, [edx + 16]
- jg convertloop
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void UYVYToUVRow_Unaligned_SSE2(const uint8* src_uyvy, int stride_uyvy,
- uint8* dst_u, uint8* dst_v, int pix) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // src_yuy2
- mov esi, [esp + 8 + 8] // stride_yuy2
- mov edx, [esp + 8 + 12] // dst_u
- mov edi, [esp + 8 + 16] // dst_v
- mov ecx, [esp + 8 + 20] // pix
- pcmpeqb xmm5, xmm5 // generate mask 0x00ff00ff
- psrlw xmm5, 8
- sub edi, edx
-
- align 4
- convertloop:
- movdqu xmm0, [eax]
- movdqu xmm1, [eax + 16]
- movdqu xmm2, [eax + esi]
- movdqu xmm3, [eax + esi + 16]
- lea eax, [eax + 32]
- pavgb xmm0, xmm2
- pavgb xmm1, xmm3
- pand xmm0, xmm5 // UYVY -> UVUV
- pand xmm1, xmm5
- packuswb xmm0, xmm1
- movdqa xmm1, xmm0
- pand xmm0, xmm5 // U
- packuswb xmm0, xmm0
- psrlw xmm1, 8 // V
- packuswb xmm1, xmm1
- movq qword ptr [edx], xmm0
- movq qword ptr [edx + edi], xmm1
- lea edx, [edx + 8]
- sub ecx, 16
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void UYVYToUV422Row_Unaligned_SSE2(const uint8* src_uyvy,
- uint8* dst_u, uint8* dst_v, int pix) {
- __asm {
- push edi
- mov eax, [esp + 4 + 4] // src_yuy2
- mov edx, [esp + 4 + 8] // dst_u
- mov edi, [esp + 4 + 12] // dst_v
- mov ecx, [esp + 4 + 16] // pix
- pcmpeqb xmm5, xmm5 // generate mask 0x00ff00ff
- psrlw xmm5, 8
- sub edi, edx
-
- align 4
- convertloop:
- movdqu xmm0, [eax]
- movdqu xmm1, [eax + 16]
- lea eax, [eax + 32]
- pand xmm0, xmm5 // UYVY -> UVUV
- pand xmm1, xmm5
- packuswb xmm0, xmm1
- movdqa xmm1, xmm0
- pand xmm0, xmm5 // U
- packuswb xmm0, xmm0
- psrlw xmm1, 8 // V
- packuswb xmm1, xmm1
- movq qword ptr [edx], xmm0
- movq qword ptr [edx + edi], xmm1
- lea edx, [edx + 8]
- sub ecx, 16
- jg convertloop
-
- pop edi
- ret
- }
-}
-#endif // HAS_YUY2TOYROW_SSE2
-
-#ifdef HAS_ARGBBLENDROW_SSE2
-// Blend 8 pixels at a time.
-__declspec(naked) __declspec(align(16))
-void ARGBBlendRow_SSE2(const uint8* src_argb0, const uint8* src_argb1,
- uint8* dst_argb, int width) {
- __asm {
- push esi
- mov eax, [esp + 4 + 4] // src_argb0
- mov esi, [esp + 4 + 8] // src_argb1
- mov edx, [esp + 4 + 12] // dst_argb
- mov ecx, [esp + 4 + 16] // width
- pcmpeqb xmm7, xmm7 // generate constant 1
- psrlw xmm7, 15
- pcmpeqb xmm6, xmm6 // generate mask 0x00ff00ff
- psrlw xmm6, 8
- pcmpeqb xmm5, xmm5 // generate mask 0xff00ff00
- psllw xmm5, 8
- pcmpeqb xmm4, xmm4 // generate mask 0xff000000
- pslld xmm4, 24
-
- sub ecx, 1
- je convertloop1 // only 1 pixel?
- jl convertloop1b
-
- // 1 pixel loop until destination pointer is aligned.
- alignloop1:
- test edx, 15 // aligned?
- je alignloop1b
- movd xmm3, [eax]
- lea eax, [eax + 4]
- movdqa xmm0, xmm3 // src argb
- pxor xmm3, xmm4 // ~alpha
- movd xmm2, [esi] // _r_b
- psrlw xmm3, 8 // alpha
- pshufhw xmm3, xmm3, 0F5h // 8 alpha words
- pshuflw xmm3, xmm3, 0F5h
- pand xmm2, xmm6 // _r_b
- paddw xmm3, xmm7 // 256 - alpha
- pmullw xmm2, xmm3 // _r_b * alpha
- movd xmm1, [esi] // _a_g
- lea esi, [esi + 4]
- psrlw xmm1, 8 // _a_g
- por xmm0, xmm4 // set alpha to 255
- pmullw xmm1, xmm3 // _a_g * alpha
- psrlw xmm2, 8 // _r_b convert to 8 bits again
- paddusb xmm0, xmm2 // + src argb
- pand xmm1, xmm5 // a_g_ convert to 8 bits again
- paddusb xmm0, xmm1 // + src argb
- sub ecx, 1
- movd [edx], xmm0
- lea edx, [edx + 4]
- jge alignloop1
-
- alignloop1b:
- add ecx, 1 - 4
- jl convertloop4b
-
- // 4 pixel loop.
- convertloop4:
- movdqu xmm3, [eax] // src argb
- lea eax, [eax + 16]
- movdqa xmm0, xmm3 // src argb
- pxor xmm3, xmm4 // ~alpha
- movdqu xmm2, [esi] // _r_b
- psrlw xmm3, 8 // alpha
- pshufhw xmm3, xmm3, 0F5h // 8 alpha words
- pshuflw xmm3, xmm3, 0F5h
- pand xmm2, xmm6 // _r_b
- paddw xmm3, xmm7 // 256 - alpha
- pmullw xmm2, xmm3 // _r_b * alpha
- movdqu xmm1, [esi] // _a_g
- lea esi, [esi + 16]
- psrlw xmm1, 8 // _a_g
- por xmm0, xmm4 // set alpha to 255
- pmullw xmm1, xmm3 // _a_g * alpha
- psrlw xmm2, 8 // _r_b convert to 8 bits again
- paddusb xmm0, xmm2 // + src argb
- pand xmm1, xmm5 // a_g_ convert to 8 bits again
- paddusb xmm0, xmm1 // + src argb
- sub ecx, 4
- movdqa [edx], xmm0
- lea edx, [edx + 16]
- jge convertloop4
-
- convertloop4b:
- add ecx, 4 - 1
- jl convertloop1b
-
- // 1 pixel loop.
- convertloop1:
- movd xmm3, [eax] // src argb
- lea eax, [eax + 4]
- movdqa xmm0, xmm3 // src argb
- pxor xmm3, xmm4 // ~alpha
- movd xmm2, [esi] // _r_b
- psrlw xmm3, 8 // alpha
- pshufhw xmm3, xmm3, 0F5h // 8 alpha words
- pshuflw xmm3, xmm3, 0F5h
- pand xmm2, xmm6 // _r_b
- paddw xmm3, xmm7 // 256 - alpha
- pmullw xmm2, xmm3 // _r_b * alpha
- movd xmm1, [esi] // _a_g
- lea esi, [esi + 4]
- psrlw xmm1, 8 // _a_g
- por xmm0, xmm4 // set alpha to 255
- pmullw xmm1, xmm3 // _a_g * alpha
- psrlw xmm2, 8 // _r_b convert to 8 bits again
- paddusb xmm0, xmm2 // + src argb
- pand xmm1, xmm5 // a_g_ convert to 8 bits again
- paddusb xmm0, xmm1 // + src argb
- sub ecx, 1
- movd [edx], xmm0
- lea edx, [edx + 4]
- jge convertloop1
-
- convertloop1b:
- pop esi
- ret
- }
-}
-#endif // HAS_ARGBBLENDROW_SSE2
-
-#ifdef HAS_ARGBBLENDROW_SSSE3
-// Shuffle table for isolating alpha.
-static const uvec8 kShuffleAlpha = {
- 3u, 0x80, 3u, 0x80, 7u, 0x80, 7u, 0x80,
- 11u, 0x80, 11u, 0x80, 15u, 0x80, 15u, 0x80
-};
-// Same as SSE2, but replaces:
-// psrlw xmm3, 8 // alpha
-// pshufhw xmm3, xmm3, 0F5h // 8 alpha words
-// pshuflw xmm3, xmm3, 0F5h
-// with..
-// pshufb xmm3, kShuffleAlpha // alpha
-// Blend 8 pixels at a time.
-
-__declspec(naked) __declspec(align(16))
-void ARGBBlendRow_SSSE3(const uint8* src_argb0, const uint8* src_argb1,
- uint8* dst_argb, int width) {
- __asm {
- push esi
- mov eax, [esp + 4 + 4] // src_argb0
- mov esi, [esp + 4 + 8] // src_argb1
- mov edx, [esp + 4 + 12] // dst_argb
- mov ecx, [esp + 4 + 16] // width
- pcmpeqb xmm7, xmm7 // generate constant 0x0001
- psrlw xmm7, 15
- pcmpeqb xmm6, xmm6 // generate mask 0x00ff00ff
- psrlw xmm6, 8
- pcmpeqb xmm5, xmm5 // generate mask 0xff00ff00
- psllw xmm5, 8
- pcmpeqb xmm4, xmm4 // generate mask 0xff000000
- pslld xmm4, 24
-
- sub ecx, 1
- je convertloop1 // only 1 pixel?
- jl convertloop1b
-
- // 1 pixel loop until destination pointer is aligned.
- alignloop1:
- test edx, 15 // aligned?
- je alignloop1b
- movd xmm3, [eax]
- lea eax, [eax + 4]
- movdqa xmm0, xmm3 // src argb
- pxor xmm3, xmm4 // ~alpha
- movd xmm2, [esi] // _r_b
- pshufb xmm3, kShuffleAlpha // alpha
- pand xmm2, xmm6 // _r_b
- paddw xmm3, xmm7 // 256 - alpha
- pmullw xmm2, xmm3 // _r_b * alpha
- movd xmm1, [esi] // _a_g
- lea esi, [esi + 4]
- psrlw xmm1, 8 // _a_g
- por xmm0, xmm4 // set alpha to 255
- pmullw xmm1, xmm3 // _a_g * alpha
- psrlw xmm2, 8 // _r_b convert to 8 bits again
- paddusb xmm0, xmm2 // + src argb
- pand xmm1, xmm5 // a_g_ convert to 8 bits again
- paddusb xmm0, xmm1 // + src argb
- sub ecx, 1
- movd [edx], xmm0
- lea edx, [edx + 4]
- jge alignloop1
-
- alignloop1b:
- add ecx, 1 - 4
- jl convertloop4b
-
- test eax, 15 // unaligned?
- jne convertuloop4
- test esi, 15 // unaligned?
- jne convertuloop4
-
- // 4 pixel loop.
- convertloop4:
- movdqa xmm3, [eax] // src argb
- lea eax, [eax + 16]
- movdqa xmm0, xmm3 // src argb
- pxor xmm3, xmm4 // ~alpha
- movdqa xmm2, [esi] // _r_b
- pshufb xmm3, kShuffleAlpha // alpha
- pand xmm2, xmm6 // _r_b
- paddw xmm3, xmm7 // 256 - alpha
- pmullw xmm2, xmm3 // _r_b * alpha
- movdqa xmm1, [esi] // _a_g
- lea esi, [esi + 16]
- psrlw xmm1, 8 // _a_g
- por xmm0, xmm4 // set alpha to 255
- pmullw xmm1, xmm3 // _a_g * alpha
- psrlw xmm2, 8 // _r_b convert to 8 bits again
- paddusb xmm0, xmm2 // + src argb
- pand xmm1, xmm5 // a_g_ convert to 8 bits again
- paddusb xmm0, xmm1 // + src argb
- sub ecx, 4
- movdqa [edx], xmm0
- lea edx, [edx + 16]
- jge convertloop4
- jmp convertloop4b
-
- // 4 pixel unaligned loop.
- convertuloop4:
- movdqu xmm3, [eax] // src argb
- lea eax, [eax + 16]
- movdqa xmm0, xmm3 // src argb
- pxor xmm3, xmm4 // ~alpha
- movdqu xmm2, [esi] // _r_b
- pshufb xmm3, kShuffleAlpha // alpha
- pand xmm2, xmm6 // _r_b
- paddw xmm3, xmm7 // 256 - alpha
- pmullw xmm2, xmm3 // _r_b * alpha
- movdqu xmm1, [esi] // _a_g
- lea esi, [esi + 16]
- psrlw xmm1, 8 // _a_g
- por xmm0, xmm4 // set alpha to 255
- pmullw xmm1, xmm3 // _a_g * alpha
- psrlw xmm2, 8 // _r_b convert to 8 bits again
- paddusb xmm0, xmm2 // + src argb
- pand xmm1, xmm5 // a_g_ convert to 8 bits again
- paddusb xmm0, xmm1 // + src argb
- sub ecx, 4
- movdqa [edx], xmm0
- lea edx, [edx + 16]
- jge convertuloop4
-
- convertloop4b:
- add ecx, 4 - 1
- jl convertloop1b
-
- // 1 pixel loop.
- convertloop1:
- movd xmm3, [eax] // src argb
- lea eax, [eax + 4]
- movdqa xmm0, xmm3 // src argb
- pxor xmm3, xmm4 // ~alpha
- movd xmm2, [esi] // _r_b
- pshufb xmm3, kShuffleAlpha // alpha
- pand xmm2, xmm6 // _r_b
- paddw xmm3, xmm7 // 256 - alpha
- pmullw xmm2, xmm3 // _r_b * alpha
- movd xmm1, [esi] // _a_g
- lea esi, [esi + 4]
- psrlw xmm1, 8 // _a_g
- por xmm0, xmm4 // set alpha to 255
- pmullw xmm1, xmm3 // _a_g * alpha
- psrlw xmm2, 8 // _r_b convert to 8 bits again
- paddusb xmm0, xmm2 // + src argb
- pand xmm1, xmm5 // a_g_ convert to 8 bits again
- paddusb xmm0, xmm1 // + src argb
- sub ecx, 1
- movd [edx], xmm0
- lea edx, [edx + 4]
- jge convertloop1
-
- convertloop1b:
- pop esi
- ret
- }
-}
-#endif // HAS_ARGBBLENDROW_SSSE3
-
-#ifdef HAS_ARGBATTENUATEROW_SSE2
-// Attenuate 4 pixels at a time.
-// Aligned to 16 bytes.
-__declspec(naked) __declspec(align(16))
-void ARGBAttenuateRow_SSE2(const uint8* src_argb, uint8* dst_argb, int width) {
- __asm {
- mov eax, [esp + 4] // src_argb0
- mov edx, [esp + 8] // dst_argb
- mov ecx, [esp + 12] // width
- pcmpeqb xmm4, xmm4 // generate mask 0xff000000
- pslld xmm4, 24
- pcmpeqb xmm5, xmm5 // generate mask 0x00ffffff
- psrld xmm5, 8
-
- align 4
- convertloop:
- movdqa xmm0, [eax] // read 4 pixels
- punpcklbw xmm0, xmm0 // first 2
- pshufhw xmm2, xmm0, 0FFh // 8 alpha words
- pshuflw xmm2, xmm2, 0FFh
- pmulhuw xmm0, xmm2 // rgb * a
- movdqa xmm1, [eax] // read 4 pixels
- punpckhbw xmm1, xmm1 // next 2 pixels
- pshufhw xmm2, xmm1, 0FFh // 8 alpha words
- pshuflw xmm2, xmm2, 0FFh
- pmulhuw xmm1, xmm2 // rgb * a
- movdqa xmm2, [eax] // alphas
- lea eax, [eax + 16]
- psrlw xmm0, 8
- pand xmm2, xmm4
- psrlw xmm1, 8
- packuswb xmm0, xmm1
- pand xmm0, xmm5 // keep original alphas
- por xmm0, xmm2
- sub ecx, 4
- movdqa [edx], xmm0
- lea edx, [edx + 16]
- jg convertloop
-
- ret
- }
-}
-#endif // HAS_ARGBATTENUATEROW_SSE2
-
-#ifdef HAS_ARGBATTENUATEROW_SSSE3
-// Shuffle table duplicating alpha.
-static const uvec8 kShuffleAlpha0 = {
- 3u, 3u, 3u, 3u, 3u, 3u, 128u, 128u, 7u, 7u, 7u, 7u, 7u, 7u, 128u, 128u,
-};
-static const uvec8 kShuffleAlpha1 = {
- 11u, 11u, 11u, 11u, 11u, 11u, 128u, 128u,
- 15u, 15u, 15u, 15u, 15u, 15u, 128u, 128u,
-};
-__declspec(naked) __declspec(align(16))
-void ARGBAttenuateRow_SSSE3(const uint8* src_argb, uint8* dst_argb, int width) {
- __asm {
- mov eax, [esp + 4] // src_argb0
- mov edx, [esp + 8] // dst_argb
- mov ecx, [esp + 12] // width
- pcmpeqb xmm3, xmm3 // generate mask 0xff000000
- pslld xmm3, 24
- movdqa xmm4, kShuffleAlpha0
- movdqa xmm5, kShuffleAlpha1
-
- align 4
- convertloop:
- movdqu xmm0, [eax] // read 4 pixels
- pshufb xmm0, xmm4 // isolate first 2 alphas
- movdqu xmm1, [eax] // read 4 pixels
- punpcklbw xmm1, xmm1 // first 2 pixel rgbs
- pmulhuw xmm0, xmm1 // rgb * a
- movdqu xmm1, [eax] // read 4 pixels
- pshufb xmm1, xmm5 // isolate next 2 alphas
- movdqu xmm2, [eax] // read 4 pixels
- punpckhbw xmm2, xmm2 // next 2 pixel rgbs
- pmulhuw xmm1, xmm2 // rgb * a
- movdqu xmm2, [eax] // mask original alpha
- lea eax, [eax + 16]
- pand xmm2, xmm3
- psrlw xmm0, 8
- psrlw xmm1, 8
- packuswb xmm0, xmm1
- por xmm0, xmm2 // copy original alpha
- sub ecx, 4
- movdqu [edx], xmm0
- lea edx, [edx + 16]
- jg convertloop
-
- ret
- }
-}
-#endif // HAS_ARGBATTENUATEROW_SSSE3
-
-#ifdef HAS_ARGBATTENUATEROW_AVX2
-// Shuffle table duplicating alpha.
-static const ulvec8 kShuffleAlpha_AVX2 = {
- 6u, 7u, 6u, 7u, 6u, 7u, 128u, 128u,
- 14u, 15u, 14u, 15u, 14u, 15u, 128u, 128u,
- 6u, 7u, 6u, 7u, 6u, 7u, 128u, 128u,
- 14u, 15u, 14u, 15u, 14u, 15u, 128u, 128u,
-};
-__declspec(naked) __declspec(align(16))
-void ARGBAttenuateRow_AVX2(const uint8* src_argb, uint8* dst_argb, int width) {
- __asm {
- mov eax, [esp + 4] // src_argb0
- mov edx, [esp + 8] // dst_argb
- mov ecx, [esp + 12] // width
- sub edx, eax
- vmovdqa ymm4, kShuffleAlpha_AVX2
- vpcmpeqb ymm5, ymm5, ymm5 // generate mask 0xff000000
- vpslld ymm5, ymm5, 24
-
- align 4
- convertloop:
- vmovdqu ymm6, [eax] // read 8 pixels.
- vpunpcklbw ymm0, ymm6, ymm6 // low 4 pixels. mutated.
- vpunpckhbw ymm1, ymm6, ymm6 // high 4 pixels. mutated.
- vpshufb ymm2, ymm0, ymm4 // low 4 alphas
- vpshufb ymm3, ymm1, ymm4 // high 4 alphas
- vpmulhuw ymm0, ymm0, ymm2 // rgb * a
- vpmulhuw ymm1, ymm1, ymm3 // rgb * a
- vpand ymm6, ymm6, ymm5 // isolate alpha
- vpsrlw ymm0, ymm0, 8
- vpsrlw ymm1, ymm1, 8
- vpackuswb ymm0, ymm0, ymm1 // unmutated.
- vpor ymm0, ymm0, ymm6 // copy original alpha
- sub ecx, 8
- vmovdqu [eax + edx], ymm0
- lea eax, [eax + 32]
- jg convertloop
-
- vzeroupper
- ret
- }
-}
-#endif // HAS_ARGBATTENUATEROW_AVX2
-
-#ifdef HAS_ARGBUNATTENUATEROW_SSE2
-// Unattenuate 4 pixels at a time.
-// Aligned to 16 bytes.
-__declspec(naked) __declspec(align(16))
-void ARGBUnattenuateRow_SSE2(const uint8* src_argb, uint8* dst_argb,
- int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // src_argb0
- mov edx, [esp + 8 + 8] // dst_argb
- mov ecx, [esp + 8 + 12] // width
-
- align 4
- convertloop:
- movdqu xmm0, [eax] // read 4 pixels
- movzx esi, byte ptr [eax + 3] // first alpha
- movzx edi, byte ptr [eax + 7] // second alpha
- punpcklbw xmm0, xmm0 // first 2
- movd xmm2, dword ptr fixed_invtbl8[esi * 4]
- movd xmm3, dword ptr fixed_invtbl8[edi * 4]
- pshuflw xmm2, xmm2, 040h // first 4 inv_alpha words. 1, a, a, a
- pshuflw xmm3, xmm3, 040h // next 4 inv_alpha words
- movlhps xmm2, xmm3
- pmulhuw xmm0, xmm2 // rgb * a
-
- movdqu xmm1, [eax] // read 4 pixels
- movzx esi, byte ptr [eax + 11] // third alpha
- movzx edi, byte ptr [eax + 15] // forth alpha
- punpckhbw xmm1, xmm1 // next 2
- movd xmm2, dword ptr fixed_invtbl8[esi * 4]
- movd xmm3, dword ptr fixed_invtbl8[edi * 4]
- pshuflw xmm2, xmm2, 040h // first 4 inv_alpha words
- pshuflw xmm3, xmm3, 040h // next 4 inv_alpha words
- movlhps xmm2, xmm3
- pmulhuw xmm1, xmm2 // rgb * a
- lea eax, [eax + 16]
-
- packuswb xmm0, xmm1
- sub ecx, 4
- movdqu [edx], xmm0
- lea edx, [edx + 16]
- jg convertloop
- pop edi
- pop esi
- ret
- }
-}
-#endif // HAS_ARGBUNATTENUATEROW_SSE2
-
-#ifdef HAS_ARGBUNATTENUATEROW_AVX2
-// Shuffle table duplicating alpha.
-static const ulvec8 kUnattenShuffleAlpha_AVX2 = {
- 0u, 1u, 0u, 1u, 0u, 1u, 6u, 7u, 8u, 9u, 8u, 9u, 8u, 9u, 14u, 15,
- 0u, 1u, 0u, 1u, 0u, 1u, 6u, 7u, 8u, 9u, 8u, 9u, 8u, 9u, 14u, 15,
-};
-// TODO(fbarchard): Enable USE_GATHER for future hardware if faster.
-// USE_GATHER is not on by default, due to being a slow instruction.
-#ifdef USE_GATHER
-__declspec(naked) __declspec(align(16))
-void ARGBUnattenuateRow_AVX2(const uint8* src_argb, uint8* dst_argb,
- int width) {
- __asm {
- mov eax, [esp + 4] // src_argb0
- mov edx, [esp + 8] // dst_argb
- mov ecx, [esp + 12] // width
- sub edx, eax
- vmovdqa ymm4, kUnattenShuffleAlpha_AVX2
-
- align 4
- convertloop:
- vmovdqu ymm6, [eax] // read 8 pixels.
- vpcmpeqb ymm5, ymm5, ymm5 // generate mask 0xffffffff for gather.
- vpsrld ymm2, ymm6, 24 // alpha in low 8 bits.
- vpunpcklbw ymm0, ymm6, ymm6 // low 4 pixels. mutated.
- vpunpckhbw ymm1, ymm6, ymm6 // high 4 pixels. mutated.
- vpgatherdd ymm3, [ymm2 * 4 + fixed_invtbl8], ymm5 // ymm5 cleared. 1, a
- vpunpcklwd ymm2, ymm3, ymm3 // low 4 inverted alphas. mutated. 1, 1, a, a
- vpunpckhwd ymm3, ymm3, ymm3 // high 4 inverted alphas. mutated.
- vpshufb ymm2, ymm2, ymm4 // replicate low 4 alphas. 1, a, a, a
- vpshufb ymm3, ymm3, ymm4 // replicate high 4 alphas
- vpmulhuw ymm0, ymm0, ymm2 // rgb * ia
- vpmulhuw ymm1, ymm1, ymm3 // rgb * ia
- vpackuswb ymm0, ymm0, ymm1 // unmutated.
- sub ecx, 8
- vmovdqu [eax + edx], ymm0
- lea eax, [eax + 32]
- jg convertloop
-
- vzeroupper
- ret
- }
-}
-#else // USE_GATHER
-__declspec(naked) __declspec(align(16))
-void ARGBUnattenuateRow_AVX2(const uint8* src_argb, uint8* dst_argb,
- int width) {
- __asm {
-
- mov eax, [esp + 4] // src_argb0
- mov edx, [esp + 8] // dst_argb
- mov ecx, [esp + 12] // width
- sub edx, eax
- vmovdqa ymm5, kUnattenShuffleAlpha_AVX2
-
- push esi
- push edi
-
- align 4
- convertloop:
- // replace VPGATHER
- movzx esi, byte ptr [eax + 3] // alpha0
- movzx edi, byte ptr [eax + 7] // alpha1
- vmovd xmm0, dword ptr fixed_invtbl8[esi * 4] // [1,a0]
- vmovd xmm1, dword ptr fixed_invtbl8[edi * 4] // [1,a1]
- movzx esi, byte ptr [eax + 11] // alpha2
- movzx edi, byte ptr [eax + 15] // alpha3
- vpunpckldq xmm6, xmm0, xmm1 // [1,a1,1,a0]
- vmovd xmm2, dword ptr fixed_invtbl8[esi * 4] // [1,a2]
- vmovd xmm3, dword ptr fixed_invtbl8[edi * 4] // [1,a3]
- movzx esi, byte ptr [eax + 19] // alpha4
- movzx edi, byte ptr [eax + 23] // alpha5
- vpunpckldq xmm7, xmm2, xmm3 // [1,a3,1,a2]
- vmovd xmm0, dword ptr fixed_invtbl8[esi * 4] // [1,a4]
- vmovd xmm1, dword ptr fixed_invtbl8[edi * 4] // [1,a5]
- movzx esi, byte ptr [eax + 27] // alpha6
- movzx edi, byte ptr [eax + 31] // alpha7
- vpunpckldq xmm0, xmm0, xmm1 // [1,a5,1,a4]
- vmovd xmm2, dword ptr fixed_invtbl8[esi * 4] // [1,a6]
- vmovd xmm3, dword ptr fixed_invtbl8[edi * 4] // [1,a7]
- vpunpckldq xmm2, xmm2, xmm3 // [1,a7,1,a6]
- vpunpcklqdq xmm3, xmm6, xmm7 // [1,a3,1,a2,1,a1,1,a0]
- vpunpcklqdq xmm0, xmm0, xmm2 // [1,a7,1,a6,1,a5,1,a4]
- vinserti128 ymm3, ymm3, xmm0, 1 // [1,a7,1,a6,1,a5,1,a4,1,a3,1,a2,1,a1,1,a0]
- // end of VPGATHER
-
- vmovdqu ymm6, [eax] // read 8 pixels.
- vpunpcklbw ymm0, ymm6, ymm6 // low 4 pixels. mutated.
- vpunpckhbw ymm1, ymm6, ymm6 // high 4 pixels. mutated.
- vpunpcklwd ymm2, ymm3, ymm3 // low 4 inverted alphas. mutated. 1, 1, a, a
- vpunpckhwd ymm3, ymm3, ymm3 // high 4 inverted alphas. mutated.
- vpshufb ymm2, ymm2, ymm5 // replicate low 4 alphas. 1, a, a, a
- vpshufb ymm3, ymm3, ymm5 // replicate high 4 alphas
- vpmulhuw ymm0, ymm0, ymm2 // rgb * ia
- vpmulhuw ymm1, ymm1, ymm3 // rgb * ia
- vpackuswb ymm0, ymm0, ymm1 // unmutated.
- sub ecx, 8
- vmovdqu [eax + edx], ymm0
- lea eax, [eax + 32]
- jg convertloop
-
- pop edi
- pop esi
- vzeroupper
- ret
- }
-}
-#endif // USE_GATHER
-#endif // HAS_ARGBATTENUATEROW_AVX2
-
-#ifdef HAS_ARGBGRAYROW_SSSE3
-// Convert 8 ARGB pixels (64 bytes) to 8 Gray ARGB pixels.
-__declspec(naked) __declspec(align(16))
-void ARGBGrayRow_SSSE3(const uint8* src_argb, uint8* dst_argb, int width) {
- __asm {
- mov eax, [esp + 4] /* src_argb */
- mov edx, [esp + 8] /* dst_argb */
- mov ecx, [esp + 12] /* width */
- movdqa xmm4, kARGBToYJ
- movdqa xmm5, kAddYJ64
-
- align 4
- convertloop:
- movdqa xmm0, [eax] // G
- movdqa xmm1, [eax + 16]
- pmaddubsw xmm0, xmm4
- pmaddubsw xmm1, xmm4
- phaddw xmm0, xmm1
- paddw xmm0, xmm5 // Add .5 for rounding.
- psrlw xmm0, 7
- packuswb xmm0, xmm0 // 8 G bytes
- movdqa xmm2, [eax] // A
- movdqa xmm3, [eax + 16]
- lea eax, [eax + 32]
- psrld xmm2, 24
- psrld xmm3, 24
- packuswb xmm2, xmm3
- packuswb xmm2, xmm2 // 8 A bytes
- movdqa xmm3, xmm0 // Weave into GG, GA, then GGGA
- punpcklbw xmm0, xmm0 // 8 GG words
- punpcklbw xmm3, xmm2 // 8 GA words
- movdqa xmm1, xmm0
- punpcklwd xmm0, xmm3 // GGGA first 4
- punpckhwd xmm1, xmm3 // GGGA next 4
- sub ecx, 8
- movdqa [edx], xmm0
- movdqa [edx + 16], xmm1
- lea edx, [edx + 32]
- jg convertloop
- ret
- }
-}
-#endif // HAS_ARGBGRAYROW_SSSE3
-
-#ifdef HAS_ARGBSEPIAROW_SSSE3
-// b = (r * 35 + g * 68 + b * 17) >> 7
-// g = (r * 45 + g * 88 + b * 22) >> 7
-// r = (r * 50 + g * 98 + b * 24) >> 7
-// Constant for ARGB color to sepia tone.
-static const vec8 kARGBToSepiaB = {
- 17, 68, 35, 0, 17, 68, 35, 0, 17, 68, 35, 0, 17, 68, 35, 0
-};
-
-static const vec8 kARGBToSepiaG = {
- 22, 88, 45, 0, 22, 88, 45, 0, 22, 88, 45, 0, 22, 88, 45, 0
-};
-
-static const vec8 kARGBToSepiaR = {
- 24, 98, 50, 0, 24, 98, 50, 0, 24, 98, 50, 0, 24, 98, 50, 0
-};
-
-// Convert 8 ARGB pixels (32 bytes) to 8 Sepia ARGB pixels.
-__declspec(naked) __declspec(align(16))
-void ARGBSepiaRow_SSSE3(uint8* dst_argb, int width) {
- __asm {
- mov eax, [esp + 4] /* dst_argb */
- mov ecx, [esp + 8] /* width */
- movdqa xmm2, kARGBToSepiaB
- movdqa xmm3, kARGBToSepiaG
- movdqa xmm4, kARGBToSepiaR
-
- align 4
- convertloop:
- movdqa xmm0, [eax] // B
- movdqa xmm6, [eax + 16]
- pmaddubsw xmm0, xmm2
- pmaddubsw xmm6, xmm2
- phaddw xmm0, xmm6
- psrlw xmm0, 7
- packuswb xmm0, xmm0 // 8 B values
- movdqa xmm5, [eax] // G
- movdqa xmm1, [eax + 16]
- pmaddubsw xmm5, xmm3
- pmaddubsw xmm1, xmm3
- phaddw xmm5, xmm1
- psrlw xmm5, 7
- packuswb xmm5, xmm5 // 8 G values
- punpcklbw xmm0, xmm5 // 8 BG values
- movdqa xmm5, [eax] // R
- movdqa xmm1, [eax + 16]
- pmaddubsw xmm5, xmm4
- pmaddubsw xmm1, xmm4
- phaddw xmm5, xmm1
- psrlw xmm5, 7
- packuswb xmm5, xmm5 // 8 R values
- movdqa xmm6, [eax] // A
- movdqa xmm1, [eax + 16]
- psrld xmm6, 24
- psrld xmm1, 24
- packuswb xmm6, xmm1
- packuswb xmm6, xmm6 // 8 A values
- punpcklbw xmm5, xmm6 // 8 RA values
- movdqa xmm1, xmm0 // Weave BG, RA together
- punpcklwd xmm0, xmm5 // BGRA first 4
- punpckhwd xmm1, xmm5 // BGRA next 4
- sub ecx, 8
- movdqa [eax], xmm0
- movdqa [eax + 16], xmm1
- lea eax, [eax + 32]
- jg convertloop
- ret
- }
-}
-#endif // HAS_ARGBSEPIAROW_SSSE3
-
-#ifdef HAS_ARGBCOLORMATRIXROW_SSSE3
-// Tranform 8 ARGB pixels (32 bytes) with color matrix.
-// Same as Sepia except matrix is provided.
-// TODO(fbarchard): packuswbs only use half of the reg. To make RGBA, combine R
-// and B into a high and low, then G/A, unpackl/hbw and then unpckl/hwd.
-__declspec(naked) __declspec(align(16))
-void ARGBColorMatrixRow_SSSE3(const uint8* src_argb, uint8* dst_argb,
- const int8* matrix_argb, int width) {
- __asm {
- mov eax, [esp + 4] /* src_argb */
- mov edx, [esp + 8] /* dst_argb */
- mov ecx, [esp + 12] /* matrix_argb */
- movdqu xmm5, [ecx]
- pshufd xmm2, xmm5, 0x00
- pshufd xmm3, xmm5, 0x55
- pshufd xmm4, xmm5, 0xaa
- pshufd xmm5, xmm5, 0xff
- mov ecx, [esp + 16] /* width */
-
- align 4
- convertloop:
- movdqa xmm0, [eax] // B
- movdqa xmm7, [eax + 16]
- pmaddubsw xmm0, xmm2
- pmaddubsw xmm7, xmm2
- movdqa xmm6, [eax] // G
- movdqa xmm1, [eax + 16]
- pmaddubsw xmm6, xmm3
- pmaddubsw xmm1, xmm3
- phaddsw xmm0, xmm7 // B
- phaddsw xmm6, xmm1 // G
- psraw xmm0, 6 // B
- psraw xmm6, 6 // G
- packuswb xmm0, xmm0 // 8 B values
- packuswb xmm6, xmm6 // 8 G values
- punpcklbw xmm0, xmm6 // 8 BG values
- movdqa xmm1, [eax] // R
- movdqa xmm7, [eax + 16]
- pmaddubsw xmm1, xmm4
- pmaddubsw xmm7, xmm4
- phaddsw xmm1, xmm7 // R
- movdqa xmm6, [eax] // A
- movdqa xmm7, [eax + 16]
- pmaddubsw xmm6, xmm5
- pmaddubsw xmm7, xmm5
- phaddsw xmm6, xmm7 // A
- psraw xmm1, 6 // R
- psraw xmm6, 6 // A
- packuswb xmm1, xmm1 // 8 R values
- packuswb xmm6, xmm6 // 8 A values
- punpcklbw xmm1, xmm6 // 8 RA values
- movdqa xmm6, xmm0 // Weave BG, RA together
- punpcklwd xmm0, xmm1 // BGRA first 4
- punpckhwd xmm6, xmm1 // BGRA next 4
- sub ecx, 8
- movdqa [edx], xmm0
- movdqa [edx + 16], xmm6
- lea eax, [eax + 32]
- lea edx, [edx + 32]
- jg convertloop
- ret
- }
-}
-#endif // HAS_ARGBCOLORMATRIXROW_SSSE3
-
-#ifdef HAS_ARGBQUANTIZEROW_SSE2
-// Quantize 4 ARGB pixels (16 bytes).
-// Aligned to 16 bytes.
-__declspec(naked) __declspec(align(16))
-void ARGBQuantizeRow_SSE2(uint8* dst_argb, int scale, int interval_size,
- int interval_offset, int width) {
- __asm {
- mov eax, [esp + 4] /* dst_argb */
- movd xmm2, [esp + 8] /* scale */
- movd xmm3, [esp + 12] /* interval_size */
- movd xmm4, [esp + 16] /* interval_offset */
- mov ecx, [esp + 20] /* width */
- pshuflw xmm2, xmm2, 040h
- pshufd xmm2, xmm2, 044h
- pshuflw xmm3, xmm3, 040h
- pshufd xmm3, xmm3, 044h
- pshuflw xmm4, xmm4, 040h
- pshufd xmm4, xmm4, 044h
- pxor xmm5, xmm5 // constant 0
- pcmpeqb xmm6, xmm6 // generate mask 0xff000000
- pslld xmm6, 24
-
- align 4
- convertloop:
- movdqa xmm0, [eax] // read 4 pixels
- punpcklbw xmm0, xmm5 // first 2 pixels
- pmulhuw xmm0, xmm2 // pixel * scale >> 16
- movdqa xmm1, [eax] // read 4 pixels
- punpckhbw xmm1, xmm5 // next 2 pixels
- pmulhuw xmm1, xmm2
- pmullw xmm0, xmm3 // * interval_size
- movdqa xmm7, [eax] // read 4 pixels
- pmullw xmm1, xmm3
- pand xmm7, xmm6 // mask alpha
- paddw xmm0, xmm4 // + interval_size / 2
- paddw xmm1, xmm4
- packuswb xmm0, xmm1
- por xmm0, xmm7
- sub ecx, 4
- movdqa [eax], xmm0
- lea eax, [eax + 16]
- jg convertloop
- ret
- }
-}
-#endif // HAS_ARGBQUANTIZEROW_SSE2
-
-#ifdef HAS_ARGBSHADEROW_SSE2
-// Shade 4 pixels at a time by specified value.
-// Aligned to 16 bytes.
-__declspec(naked) __declspec(align(16))
-void ARGBShadeRow_SSE2(const uint8* src_argb, uint8* dst_argb, int width,
- uint32 value) {
- __asm {
- mov eax, [esp + 4] // src_argb
- mov edx, [esp + 8] // dst_argb
- mov ecx, [esp + 12] // width
- movd xmm2, [esp + 16] // value
- punpcklbw xmm2, xmm2
- punpcklqdq xmm2, xmm2
-
- align 4
- convertloop:
- movdqa xmm0, [eax] // read 4 pixels
- lea eax, [eax + 16]
- movdqa xmm1, xmm0
- punpcklbw xmm0, xmm0 // first 2
- punpckhbw xmm1, xmm1 // next 2
- pmulhuw xmm0, xmm2 // argb * value
- pmulhuw xmm1, xmm2 // argb * value
- psrlw xmm0, 8
- psrlw xmm1, 8
- packuswb xmm0, xmm1
- sub ecx, 4
- movdqa [edx], xmm0
- lea edx, [edx + 16]
- jg convertloop
-
- ret
- }
-}
-#endif // HAS_ARGBSHADEROW_SSE2
-
-#ifdef HAS_ARGBMULTIPLYROW_SSE2
-// Multiply 2 rows of ARGB pixels together, 4 pixels at a time.
-__declspec(naked) __declspec(align(16))
-void ARGBMultiplyRow_SSE2(const uint8* src_argb0, const uint8* src_argb1,
- uint8* dst_argb, int width) {
- __asm {
- push esi
- mov eax, [esp + 4 + 4] // src_argb0
- mov esi, [esp + 4 + 8] // src_argb1
- mov edx, [esp + 4 + 12] // dst_argb
- mov ecx, [esp + 4 + 16] // width
- pxor xmm5, xmm5 // constant 0
-
- align 4
- convertloop:
- movdqu xmm0, [eax] // read 4 pixels from src_argb0
- movdqu xmm2, [esi] // read 4 pixels from src_argb1
- movdqu xmm1, xmm0
- movdqu xmm3, xmm2
- punpcklbw xmm0, xmm0 // first 2
- punpckhbw xmm1, xmm1 // next 2
- punpcklbw xmm2, xmm5 // first 2
- punpckhbw xmm3, xmm5 // next 2
- pmulhuw xmm0, xmm2 // src_argb0 * src_argb1 first 2
- pmulhuw xmm1, xmm3 // src_argb0 * src_argb1 next 2
- lea eax, [eax + 16]
- lea esi, [esi + 16]
- packuswb xmm0, xmm1
- sub ecx, 4
- movdqu [edx], xmm0
- lea edx, [edx + 16]
- jg convertloop
-
- pop esi
- ret
- }
-}
-#endif // HAS_ARGBMULTIPLYROW_SSE2
-
-#ifdef HAS_ARGBADDROW_SSE2
-// Add 2 rows of ARGB pixels together, 4 pixels at a time.
-// TODO(fbarchard): Port this to posix, neon and other math functions.
-__declspec(naked) __declspec(align(16))
-void ARGBAddRow_SSE2(const uint8* src_argb0, const uint8* src_argb1,
- uint8* dst_argb, int width) {
- __asm {
- push esi
- mov eax, [esp + 4 + 4] // src_argb0
- mov esi, [esp + 4 + 8] // src_argb1
- mov edx, [esp + 4 + 12] // dst_argb
- mov ecx, [esp + 4 + 16] // width
-
- sub ecx, 4
- jl convertloop49
-
- align 4
- convertloop4:
- movdqu xmm0, [eax] // read 4 pixels from src_argb0
- lea eax, [eax + 16]
- movdqu xmm1, [esi] // read 4 pixels from src_argb1
- lea esi, [esi + 16]
- paddusb xmm0, xmm1 // src_argb0 + src_argb1
- sub ecx, 4
- movdqu [edx], xmm0
- lea edx, [edx + 16]
- jge convertloop4
-
- convertloop49:
- add ecx, 4 - 1
- jl convertloop19
-
- convertloop1:
- movd xmm0, [eax] // read 1 pixels from src_argb0
- lea eax, [eax + 4]
- movd xmm1, [esi] // read 1 pixels from src_argb1
- lea esi, [esi + 4]
- paddusb xmm0, xmm1 // src_argb0 + src_argb1
- sub ecx, 1
- movd [edx], xmm0
- lea edx, [edx + 4]
- jge convertloop1
-
- convertloop19:
- pop esi
- ret
- }
-}
-#endif // HAS_ARGBADDROW_SSE2
-
-#ifdef HAS_ARGBSUBTRACTROW_SSE2
-// Subtract 2 rows of ARGB pixels together, 4 pixels at a time.
-__declspec(naked) __declspec(align(16))
-void ARGBSubtractRow_SSE2(const uint8* src_argb0, const uint8* src_argb1,
- uint8* dst_argb, int width) {
- __asm {
- push esi
- mov eax, [esp + 4 + 4] // src_argb0
- mov esi, [esp + 4 + 8] // src_argb1
- mov edx, [esp + 4 + 12] // dst_argb
- mov ecx, [esp + 4 + 16] // width
-
- align 4
- convertloop:
- movdqu xmm0, [eax] // read 4 pixels from src_argb0
- lea eax, [eax + 16]
- movdqu xmm1, [esi] // read 4 pixels from src_argb1
- lea esi, [esi + 16]
- psubusb xmm0, xmm1 // src_argb0 - src_argb1
- sub ecx, 4
- movdqu [edx], xmm0
- lea edx, [edx + 16]
- jg convertloop
-
- pop esi
- ret
- }
-}
-#endif // HAS_ARGBSUBTRACTROW_SSE2
-
-#ifdef HAS_ARGBMULTIPLYROW_AVX2
-// Multiply 2 rows of ARGB pixels together, 8 pixels at a time.
-__declspec(naked) __declspec(align(16))
-void ARGBMultiplyRow_AVX2(const uint8* src_argb0, const uint8* src_argb1,
- uint8* dst_argb, int width) {
- __asm {
- push esi
- mov eax, [esp + 4 + 4] // src_argb0
- mov esi, [esp + 4 + 8] // src_argb1
- mov edx, [esp + 4 + 12] // dst_argb
- mov ecx, [esp + 4 + 16] // width
- vpxor ymm5, ymm5, ymm5 // constant 0
-
- align 4
- convertloop:
- vmovdqu ymm1, [eax] // read 8 pixels from src_argb0
- lea eax, [eax + 32]
- vmovdqu ymm3, [esi] // read 8 pixels from src_argb1
- lea esi, [esi + 32]
- vpunpcklbw ymm0, ymm1, ymm1 // low 4
- vpunpckhbw ymm1, ymm1, ymm1 // high 4
- vpunpcklbw ymm2, ymm3, ymm5 // low 4
- vpunpckhbw ymm3, ymm3, ymm5 // high 4
- vpmulhuw ymm0, ymm0, ymm2 // src_argb0 * src_argb1 low 4
- vpmulhuw ymm1, ymm1, ymm3 // src_argb0 * src_argb1 high 4
- vpackuswb ymm0, ymm0, ymm1
- vmovdqu [edx], ymm0
- lea edx, [edx + 32]
- sub ecx, 8
- jg convertloop
-
- pop esi
- vzeroupper
- ret
- }
-}
-#endif // HAS_ARGBMULTIPLYROW_AVX2
-
-#ifdef HAS_ARGBADDROW_AVX2
-// Add 2 rows of ARGB pixels together, 8 pixels at a time.
-__declspec(naked) __declspec(align(16))
-void ARGBAddRow_AVX2(const uint8* src_argb0, const uint8* src_argb1,
- uint8* dst_argb, int width) {
- __asm {
- push esi
- mov eax, [esp + 4 + 4] // src_argb0
- mov esi, [esp + 4 + 8] // src_argb1
- mov edx, [esp + 4 + 12] // dst_argb
- mov ecx, [esp + 4 + 16] // width
-
- align 4
- convertloop:
- vmovdqu ymm0, [eax] // read 8 pixels from src_argb0
- lea eax, [eax + 32]
- vpaddusb ymm0, ymm0, [esi] // add 8 pixels from src_argb1
- lea esi, [esi + 32]
- vmovdqu [edx], ymm0
- lea edx, [edx + 32]
- sub ecx, 8
- jg convertloop
-
- pop esi
- vzeroupper
- ret
- }
-}
-#endif // HAS_ARGBADDROW_AVX2
-
-#ifdef HAS_ARGBSUBTRACTROW_AVX2
-// Subtract 2 rows of ARGB pixels together, 8 pixels at a time.
-__declspec(naked) __declspec(align(16))
-void ARGBSubtractRow_AVX2(const uint8* src_argb0, const uint8* src_argb1,
- uint8* dst_argb, int width) {
- __asm {
- push esi
- mov eax, [esp + 4 + 4] // src_argb0
- mov esi, [esp + 4 + 8] // src_argb1
- mov edx, [esp + 4 + 12] // dst_argb
- mov ecx, [esp + 4 + 16] // width
-
- align 4
- convertloop:
- vmovdqu ymm0, [eax] // read 8 pixels from src_argb0
- lea eax, [eax + 32]
- vpsubusb ymm0, ymm0, [esi] // src_argb0 - src_argb1
- lea esi, [esi + 32]
- vmovdqu [edx], ymm0
- lea edx, [edx + 32]
- sub ecx, 8
- jg convertloop
-
- pop esi
- vzeroupper
- ret
- }
-}
-#endif // HAS_ARGBSUBTRACTROW_AVX2
-
-#ifdef HAS_SOBELXROW_SSE2
-// SobelX as a matrix is
-// -1 0 1
-// -2 0 2
-// -1 0 1
-__declspec(naked) __declspec(align(16))
-void SobelXRow_SSE2(const uint8* src_y0, const uint8* src_y1,
- const uint8* src_y2, uint8* dst_sobelx, int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // src_y0
- mov esi, [esp + 8 + 8] // src_y1
- mov edi, [esp + 8 + 12] // src_y2
- mov edx, [esp + 8 + 16] // dst_sobelx
- mov ecx, [esp + 8 + 20] // width
- sub esi, eax
- sub edi, eax
- sub edx, eax
- pxor xmm5, xmm5 // constant 0
-
- align 4
- convertloop:
- movq xmm0, qword ptr [eax] // read 8 pixels from src_y0[0]
- movq xmm1, qword ptr [eax + 2] // read 8 pixels from src_y0[2]
- punpcklbw xmm0, xmm5
- punpcklbw xmm1, xmm5
- psubw xmm0, xmm1
- movq xmm1, qword ptr [eax + esi] // read 8 pixels from src_y1[0]
- movq xmm2, qword ptr [eax + esi + 2] // read 8 pixels from src_y1[2]
- punpcklbw xmm1, xmm5
- punpcklbw xmm2, xmm5
- psubw xmm1, xmm2
- movq xmm2, qword ptr [eax + edi] // read 8 pixels from src_y2[0]
- movq xmm3, qword ptr [eax + edi + 2] // read 8 pixels from src_y2[2]
- punpcklbw xmm2, xmm5
- punpcklbw xmm3, xmm5
- psubw xmm2, xmm3
- paddw xmm0, xmm2
- paddw xmm0, xmm1
- paddw xmm0, xmm1
- pxor xmm1, xmm1 // abs = max(xmm0, -xmm0). SSSE3 could use pabsw
- psubw xmm1, xmm0
- pmaxsw xmm0, xmm1
- packuswb xmm0, xmm0
- sub ecx, 8
- movq qword ptr [eax + edx], xmm0
- lea eax, [eax + 8]
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-#endif // HAS_SOBELXROW_SSE2
-
-#ifdef HAS_SOBELYROW_SSE2
-// SobelY as a matrix is
-// -1 -2 -1
-// 0 0 0
-// 1 2 1
-__declspec(naked) __declspec(align(16))
-void SobelYRow_SSE2(const uint8* src_y0, const uint8* src_y1,
- uint8* dst_sobely, int width) {
- __asm {
- push esi
- mov eax, [esp + 4 + 4] // src_y0
- mov esi, [esp + 4 + 8] // src_y1
- mov edx, [esp + 4 + 12] // dst_sobely
- mov ecx, [esp + 4 + 16] // width
- sub esi, eax
- sub edx, eax
- pxor xmm5, xmm5 // constant 0
-
- align 4
- convertloop:
- movq xmm0, qword ptr [eax] // read 8 pixels from src_y0[0]
- movq xmm1, qword ptr [eax + esi] // read 8 pixels from src_y1[0]
- punpcklbw xmm0, xmm5
- punpcklbw xmm1, xmm5
- psubw xmm0, xmm1
- movq xmm1, qword ptr [eax + 1] // read 8 pixels from src_y0[1]
- movq xmm2, qword ptr [eax + esi + 1] // read 8 pixels from src_y1[1]
- punpcklbw xmm1, xmm5
- punpcklbw xmm2, xmm5
- psubw xmm1, xmm2
- movq xmm2, qword ptr [eax + 2] // read 8 pixels from src_y0[2]
- movq xmm3, qword ptr [eax + esi + 2] // read 8 pixels from src_y1[2]
- punpcklbw xmm2, xmm5
- punpcklbw xmm3, xmm5
- psubw xmm2, xmm3
- paddw xmm0, xmm2
- paddw xmm0, xmm1
- paddw xmm0, xmm1
- pxor xmm1, xmm1 // abs = max(xmm0, -xmm0). SSSE3 could use pabsw
- psubw xmm1, xmm0
- pmaxsw xmm0, xmm1
- packuswb xmm0, xmm0
- sub ecx, 8
- movq qword ptr [eax + edx], xmm0
- lea eax, [eax + 8]
- jg convertloop
-
- pop esi
- ret
- }
-}
-#endif // HAS_SOBELYROW_SSE2
-
-#ifdef HAS_SOBELROW_SSE2
-// Adds Sobel X and Sobel Y and stores Sobel into ARGB.
-// A = 255
-// R = Sobel
-// G = Sobel
-// B = Sobel
-__declspec(naked) __declspec(align(16))
-void SobelRow_SSE2(const uint8* src_sobelx, const uint8* src_sobely,
- uint8* dst_argb, int width) {
- __asm {
- push esi
- mov eax, [esp + 4 + 4] // src_sobelx
- mov esi, [esp + 4 + 8] // src_sobely
- mov edx, [esp + 4 + 12] // dst_argb
- mov ecx, [esp + 4 + 16] // width
- sub esi, eax
- pcmpeqb xmm5, xmm5 // alpha 255
- pslld xmm5, 24 // 0xff000000
-
- align 4
- convertloop:
- movdqa xmm0, [eax] // read 16 pixels src_sobelx
- movdqa xmm1, [eax + esi] // read 16 pixels src_sobely
- lea eax, [eax + 16]
- paddusb xmm0, xmm1 // sobel = sobelx + sobely
- movdqa xmm2, xmm0 // GG
- punpcklbw xmm2, xmm0 // First 8
- punpckhbw xmm0, xmm0 // Next 8
- movdqa xmm1, xmm2 // GGGG
- punpcklwd xmm1, xmm2 // First 4
- punpckhwd xmm2, xmm2 // Next 4
- por xmm1, xmm5 // GGGA
- por xmm2, xmm5
- movdqa xmm3, xmm0 // GGGG
- punpcklwd xmm3, xmm0 // Next 4
- punpckhwd xmm0, xmm0 // Last 4
- por xmm3, xmm5 // GGGA
- por xmm0, xmm5
- sub ecx, 16
- movdqa [edx], xmm1
- movdqa [edx + 16], xmm2
- movdqa [edx + 32], xmm3
- movdqa [edx + 48], xmm0
- lea edx, [edx + 64]
- jg convertloop
-
- pop esi
- ret
- }
-}
-#endif // HAS_SOBELROW_SSE2
-
-#ifdef HAS_SOBELTOPLANEROW_SSE2
-// Adds Sobel X and Sobel Y and stores Sobel into a plane.
-__declspec(naked) __declspec(align(16))
-void SobelToPlaneRow_SSE2(const uint8* src_sobelx, const uint8* src_sobely,
- uint8* dst_y, int width) {
- __asm {
- push esi
- mov eax, [esp + 4 + 4] // src_sobelx
- mov esi, [esp + 4 + 8] // src_sobely
- mov edx, [esp + 4 + 12] // dst_argb
- mov ecx, [esp + 4 + 16] // width
- sub esi, eax
-
- align 4
- convertloop:
- movdqa xmm0, [eax] // read 16 pixels src_sobelx
- movdqa xmm1, [eax + esi] // read 16 pixels src_sobely
- lea eax, [eax + 16]
- paddusb xmm0, xmm1 // sobel = sobelx + sobely
- sub ecx, 16
- movdqa [edx], xmm0
- lea edx, [edx + 16]
- jg convertloop
-
- pop esi
- ret
- }
-}
-#endif // HAS_SOBELTOPLANEROW_SSE2
-
-#ifdef HAS_SOBELXYROW_SSE2
-// Mixes Sobel X, Sobel Y and Sobel into ARGB.
-// A = 255
-// R = Sobel X
-// G = Sobel
-// B = Sobel Y
-__declspec(naked) __declspec(align(16))
-void SobelXYRow_SSE2(const uint8* src_sobelx, const uint8* src_sobely,
- uint8* dst_argb, int width) {
- __asm {
- push esi
- mov eax, [esp + 4 + 4] // src_sobelx
- mov esi, [esp + 4 + 8] // src_sobely
- mov edx, [esp + 4 + 12] // dst_argb
- mov ecx, [esp + 4 + 16] // width
- sub esi, eax
- pcmpeqb xmm5, xmm5 // alpha 255
-
- align 4
- convertloop:
- movdqa xmm0, [eax] // read 16 pixels src_sobelx
- movdqa xmm1, [eax + esi] // read 16 pixels src_sobely
- lea eax, [eax + 16]
- movdqa xmm2, xmm0
- paddusb xmm2, xmm1 // sobel = sobelx + sobely
- movdqa xmm3, xmm0 // XA
- punpcklbw xmm3, xmm5
- punpckhbw xmm0, xmm5
- movdqa xmm4, xmm1 // YS
- punpcklbw xmm4, xmm2
- punpckhbw xmm1, xmm2
- movdqa xmm6, xmm4 // YSXA
- punpcklwd xmm6, xmm3 // First 4
- punpckhwd xmm4, xmm3 // Next 4
- movdqa xmm7, xmm1 // YSXA
- punpcklwd xmm7, xmm0 // Next 4
- punpckhwd xmm1, xmm0 // Last 4
- sub ecx, 16
- movdqa [edx], xmm6
- movdqa [edx + 16], xmm4
- movdqa [edx + 32], xmm7
- movdqa [edx + 48], xmm1
- lea edx, [edx + 64]
- jg convertloop
-
- pop esi
- ret
- }
-}
-#endif // HAS_SOBELXYROW_SSE2
-
-#ifdef HAS_CUMULATIVESUMTOAVERAGEROW_SSE2
-// Consider float CumulativeSum.
-// Consider calling CumulativeSum one row at time as needed.
-// Consider circular CumulativeSum buffer of radius * 2 + 1 height.
-// Convert cumulative sum for an area to an average for 1 pixel.
-// topleft is pointer to top left of CumulativeSum buffer for area.
-// botleft is pointer to bottom left of CumulativeSum buffer.
-// width is offset from left to right of area in CumulativeSum buffer measured
-// in number of ints.
-// area is the number of pixels in the area being averaged.
-// dst points to pixel to store result to.
-// count is number of averaged pixels to produce.
-// Does 4 pixels at a time, requires CumulativeSum pointers to be 16 byte
-// aligned.
-void CumulativeSumToAverageRow_SSE2(const int32* topleft, const int32* botleft,
- int width, int area, uint8* dst,
- int count) {
- __asm {
- mov eax, topleft // eax topleft
- mov esi, botleft // esi botleft
- mov edx, width
- movd xmm5, area
- mov edi, dst
- mov ecx, count
- cvtdq2ps xmm5, xmm5
- rcpss xmm4, xmm5 // 1.0f / area
- pshufd xmm4, xmm4, 0
- sub ecx, 4
- jl l4b
-
- cmp area, 128 // 128 pixels will not overflow 15 bits.
- ja l4
-
- pshufd xmm5, xmm5, 0 // area
- pcmpeqb xmm6, xmm6 // constant of 65536.0 - 1 = 65535.0
- psrld xmm6, 16
- cvtdq2ps xmm6, xmm6
- addps xmm5, xmm6 // (65536.0 + area - 1)
- mulps xmm5, xmm4 // (65536.0 + area - 1) * 1 / area
- cvtps2dq xmm5, xmm5 // 0.16 fixed point
- packssdw xmm5, xmm5 // 16 bit shorts
-
- // 4 pixel loop small blocks.
- align 4
- s4:
- // top left
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- movdqa xmm2, [eax + 32]
- movdqa xmm3, [eax + 48]
-
- // - top right
- psubd xmm0, [eax + edx * 4]
- psubd xmm1, [eax + edx * 4 + 16]
- psubd xmm2, [eax + edx * 4 + 32]
- psubd xmm3, [eax + edx * 4 + 48]
- lea eax, [eax + 64]
-
- // - bottom left
- psubd xmm0, [esi]
- psubd xmm1, [esi + 16]
- psubd xmm2, [esi + 32]
- psubd xmm3, [esi + 48]
-
- // + bottom right
- paddd xmm0, [esi + edx * 4]
- paddd xmm1, [esi + edx * 4 + 16]
- paddd xmm2, [esi + edx * 4 + 32]
- paddd xmm3, [esi + edx * 4 + 48]
- lea esi, [esi + 64]
-
- packssdw xmm0, xmm1 // pack 4 pixels into 2 registers
- packssdw xmm2, xmm3
-
- pmulhuw xmm0, xmm5
- pmulhuw xmm2, xmm5
-
- packuswb xmm0, xmm2
- movdqu [edi], xmm0
- lea edi, [edi + 16]
- sub ecx, 4
- jge s4
-
- jmp l4b
-
- // 4 pixel loop
- align 4
- l4:
- // top left
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- movdqa xmm2, [eax + 32]
- movdqa xmm3, [eax + 48]
-
- // - top right
- psubd xmm0, [eax + edx * 4]
- psubd xmm1, [eax + edx * 4 + 16]
- psubd xmm2, [eax + edx * 4 + 32]
- psubd xmm3, [eax + edx * 4 + 48]
- lea eax, [eax + 64]
-
- // - bottom left
- psubd xmm0, [esi]
- psubd xmm1, [esi + 16]
- psubd xmm2, [esi + 32]
- psubd xmm3, [esi + 48]
-
- // + bottom right
- paddd xmm0, [esi + edx * 4]
- paddd xmm1, [esi + edx * 4 + 16]
- paddd xmm2, [esi + edx * 4 + 32]
- paddd xmm3, [esi + edx * 4 + 48]
- lea esi, [esi + 64]
-
- cvtdq2ps xmm0, xmm0 // Average = Sum * 1 / Area
- cvtdq2ps xmm1, xmm1
- mulps xmm0, xmm4
- mulps xmm1, xmm4
- cvtdq2ps xmm2, xmm2
- cvtdq2ps xmm3, xmm3
- mulps xmm2, xmm4
- mulps xmm3, xmm4
- cvtps2dq xmm0, xmm0
- cvtps2dq xmm1, xmm1
- cvtps2dq xmm2, xmm2
- cvtps2dq xmm3, xmm3
- packssdw xmm0, xmm1
- packssdw xmm2, xmm3
- packuswb xmm0, xmm2
- movdqu [edi], xmm0
- lea edi, [edi + 16]
- sub ecx, 4
- jge l4
-
- l4b:
- add ecx, 4 - 1
- jl l1b
-
- // 1 pixel loop
- align 4
- l1:
- movdqa xmm0, [eax]
- psubd xmm0, [eax + edx * 4]
- lea eax, [eax + 16]
- psubd xmm0, [esi]
- paddd xmm0, [esi + edx * 4]
- lea esi, [esi + 16]
- cvtdq2ps xmm0, xmm0
- mulps xmm0, xmm4
- cvtps2dq xmm0, xmm0
- packssdw xmm0, xmm0
- packuswb xmm0, xmm0
- movd dword ptr [edi], xmm0
- lea edi, [edi + 4]
- sub ecx, 1
- jge l1
- l1b:
- }
-}
-#endif // HAS_CUMULATIVESUMTOAVERAGEROW_SSE2
-
-#ifdef HAS_COMPUTECUMULATIVESUMROW_SSE2
-// Creates a table of cumulative sums where each value is a sum of all values
-// above and to the left of the value.
-void ComputeCumulativeSumRow_SSE2(const uint8* row, int32* cumsum,
- const int32* previous_cumsum, int width) {
- __asm {
- mov eax, row
- mov edx, cumsum
- mov esi, previous_cumsum
- mov ecx, width
- pxor xmm0, xmm0
- pxor xmm1, xmm1
-
- sub ecx, 4
- jl l4b
- test edx, 15
- jne l4b
-
- // 4 pixel loop
- align 4
- l4:
- movdqu xmm2, [eax] // 4 argb pixels 16 bytes.
- lea eax, [eax + 16]
- movdqa xmm4, xmm2
-
- punpcklbw xmm2, xmm1
- movdqa xmm3, xmm2
- punpcklwd xmm2, xmm1
- punpckhwd xmm3, xmm1
-
- punpckhbw xmm4, xmm1
- movdqa xmm5, xmm4
- punpcklwd xmm4, xmm1
- punpckhwd xmm5, xmm1
-
- paddd xmm0, xmm2
- movdqa xmm2, [esi] // previous row above.
- paddd xmm2, xmm0
-
- paddd xmm0, xmm3
- movdqa xmm3, [esi + 16]
- paddd xmm3, xmm0
-
- paddd xmm0, xmm4
- movdqa xmm4, [esi + 32]
- paddd xmm4, xmm0
-
- paddd xmm0, xmm5
- movdqa xmm5, [esi + 48]
- lea esi, [esi + 64]
- paddd xmm5, xmm0
-
- movdqa [edx], xmm2
- movdqa [edx + 16], xmm3
- movdqa [edx + 32], xmm4
- movdqa [edx + 48], xmm5
-
- lea edx, [edx + 64]
- sub ecx, 4
- jge l4
-
- l4b:
- add ecx, 4 - 1
- jl l1b
-
- // 1 pixel loop
- align 4
- l1:
- movd xmm2, dword ptr [eax] // 1 argb pixel 4 bytes.
- lea eax, [eax + 4]
- punpcklbw xmm2, xmm1
- punpcklwd xmm2, xmm1
- paddd xmm0, xmm2
- movdqu xmm2, [esi]
- lea esi, [esi + 16]
- paddd xmm2, xmm0
- movdqu [edx], xmm2
- lea edx, [edx + 16]
- sub ecx, 1
- jge l1
-
- l1b:
- }
-}
-#endif // HAS_COMPUTECUMULATIVESUMROW_SSE2
-
-#ifdef HAS_ARGBAFFINEROW_SSE2
-// Copy ARGB pixels from source image with slope to a row of destination.
-__declspec(naked) __declspec(align(16))
-LIBYUV_API
-void ARGBAffineRow_SSE2(const uint8* src_argb, int src_argb_stride,
- uint8* dst_argb, const float* uv_dudv, int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 12] // src_argb
- mov esi, [esp + 16] // stride
- mov edx, [esp + 20] // dst_argb
- mov ecx, [esp + 24] // pointer to uv_dudv
- movq xmm2, qword ptr [ecx] // uv
- movq xmm7, qword ptr [ecx + 8] // dudv
- mov ecx, [esp + 28] // width
- shl esi, 16 // 4, stride
- add esi, 4
- movd xmm5, esi
- sub ecx, 4
- jl l4b
-
- // setup for 4 pixel loop
- pshufd xmm7, xmm7, 0x44 // dup dudv
- pshufd xmm5, xmm5, 0 // dup 4, stride
- movdqa xmm0, xmm2 // x0, y0, x1, y1
- addps xmm0, xmm7
- movlhps xmm2, xmm0
- movdqa xmm4, xmm7
- addps xmm4, xmm4 // dudv *= 2
- movdqa xmm3, xmm2 // x2, y2, x3, y3
- addps xmm3, xmm4
- addps xmm4, xmm4 // dudv *= 4
-
- // 4 pixel loop
- align 4
- l4:
- cvttps2dq xmm0, xmm2 // x, y float to int first 2
- cvttps2dq xmm1, xmm3 // x, y float to int next 2
- packssdw xmm0, xmm1 // x, y as 8 shorts
- pmaddwd xmm0, xmm5 // offsets = x * 4 + y * stride.
- movd esi, xmm0
- pshufd xmm0, xmm0, 0x39 // shift right
- movd edi, xmm0
- pshufd xmm0, xmm0, 0x39 // shift right
- movd xmm1, [eax + esi] // read pixel 0
- movd xmm6, [eax + edi] // read pixel 1
- punpckldq xmm1, xmm6 // combine pixel 0 and 1
- addps xmm2, xmm4 // x, y += dx, dy first 2
- movq qword ptr [edx], xmm1
- movd esi, xmm0
- pshufd xmm0, xmm0, 0x39 // shift right
- movd edi, xmm0
- movd xmm6, [eax + esi] // read pixel 2
- movd xmm0, [eax + edi] // read pixel 3
- punpckldq xmm6, xmm0 // combine pixel 2 and 3
- addps xmm3, xmm4 // x, y += dx, dy next 2
- sub ecx, 4
- movq qword ptr 8[edx], xmm6
- lea edx, [edx + 16]
- jge l4
-
- l4b:
- add ecx, 4 - 1
- jl l1b
-
- // 1 pixel loop
- align 4
- l1:
- cvttps2dq xmm0, xmm2 // x, y float to int
- packssdw xmm0, xmm0 // x, y as shorts
- pmaddwd xmm0, xmm5 // offset = x * 4 + y * stride
- addps xmm2, xmm7 // x, y += dx, dy
- movd esi, xmm0
- movd xmm0, [eax + esi] // copy a pixel
- sub ecx, 1
- movd [edx], xmm0
- lea edx, [edx + 4]
- jge l1
- l1b:
- pop edi
- pop esi
- ret
- }
-}
-#endif // HAS_ARGBAFFINEROW_SSE2
-
-#ifdef HAS_INTERPOLATEROW_AVX2
-// Bilinear filter 16x2 -> 16x1
-__declspec(naked) __declspec(align(16))
-void InterpolateRow_AVX2(uint8* dst_ptr, const uint8* src_ptr,
- ptrdiff_t src_stride, int dst_width,
- int source_y_fraction) {
- __asm {
- push esi
- push edi
- mov edi, [esp + 8 + 4] // dst_ptr
- mov esi, [esp + 8 + 8] // src_ptr
- mov edx, [esp + 8 + 12] // src_stride
- mov ecx, [esp + 8 + 16] // dst_width
- mov eax, [esp + 8 + 20] // source_y_fraction (0..255)
- shr eax, 1
- // Dispatch to specialized filters if applicable.
- cmp eax, 0
- je xloop100 // 0 / 128. Blend 100 / 0.
- sub edi, esi
- cmp eax, 32
- je xloop75 // 32 / 128 is 0.25. Blend 75 / 25.
- cmp eax, 64
- je xloop50 // 64 / 128 is 0.50. Blend 50 / 50.
- cmp eax, 96
- je xloop25 // 96 / 128 is 0.75. Blend 25 / 75.
-
- vmovd xmm0, eax // high fraction 0..127
- neg eax
- add eax, 128
- vmovd xmm5, eax // low fraction 128..1
- vpunpcklbw xmm5, xmm5, xmm0
- vpunpcklwd xmm5, xmm5, xmm5
- vpxor ymm0, ymm0, ymm0
- vpermd ymm5, ymm0, ymm5
-
- align 4
- xloop:
- vmovdqu ymm0, [esi]
- vmovdqu ymm2, [esi + edx]
- vpunpckhbw ymm1, ymm0, ymm2 // mutates
- vpunpcklbw ymm0, ymm0, ymm2 // mutates
- vpmaddubsw ymm0, ymm0, ymm5
- vpmaddubsw ymm1, ymm1, ymm5
- vpsrlw ymm0, ymm0, 7
- vpsrlw ymm1, ymm1, 7
- vpackuswb ymm0, ymm0, ymm1 // unmutates
- sub ecx, 32
- vmovdqu [esi + edi], ymm0
- lea esi, [esi + 32]
- jg xloop
- jmp xloop99
-
- // Blend 25 / 75.
- align 4
- xloop25:
- vmovdqu ymm0, [esi]
- vpavgb ymm0, ymm0, [esi + edx]
- vpavgb ymm0, ymm0, [esi + edx]
- sub ecx, 32
- vmovdqu [esi + edi], ymm0
- lea esi, [esi + 32]
- jg xloop25
- jmp xloop99
-
- // Blend 50 / 50.
- align 4
- xloop50:
- vmovdqu ymm0, [esi]
- vpavgb ymm0, ymm0, [esi + edx]
- sub ecx, 32
- vmovdqu [esi + edi], ymm0
- lea esi, [esi + 32]
- jg xloop50
- jmp xloop99
-
- // Blend 75 / 25.
- align 4
- xloop75:
- vmovdqu ymm0, [esi + edx]
- vpavgb ymm0, ymm0, [esi]
- vpavgb ymm0, ymm0, [esi]
- sub ecx, 32
- vmovdqu [esi + edi], ymm0
- lea esi, [esi + 32]
- jg xloop75
- jmp xloop99
-
- // Blend 100 / 0 - Copy row unchanged.
- align 4
- xloop100:
- rep movsb
-
- xloop99:
- pop edi
- pop esi
- vzeroupper
- ret
- }
-}
-#endif // HAS_INTERPOLATEROW_AVX2
-
-#ifdef HAS_INTERPOLATEROW_SSSE3
-// Bilinear filter 16x2 -> 16x1
-__declspec(naked) __declspec(align(16))
-void InterpolateRow_SSSE3(uint8* dst_ptr, const uint8* src_ptr,
- ptrdiff_t src_stride, int dst_width,
- int source_y_fraction) {
- __asm {
- push esi
- push edi
- mov edi, [esp + 8 + 4] // dst_ptr
- mov esi, [esp + 8 + 8] // src_ptr
- mov edx, [esp + 8 + 12] // src_stride
- mov ecx, [esp + 8 + 16] // dst_width
- mov eax, [esp + 8 + 20] // source_y_fraction (0..255)
- sub edi, esi
- shr eax, 1
- // Dispatch to specialized filters if applicable.
- cmp eax, 0
- je xloop100 // 0 / 128. Blend 100 / 0.
- cmp eax, 32
- je xloop75 // 32 / 128 is 0.25. Blend 75 / 25.
- cmp eax, 64
- je xloop50 // 64 / 128 is 0.50. Blend 50 / 50.
- cmp eax, 96
- je xloop25 // 96 / 128 is 0.75. Blend 25 / 75.
-
- movd xmm0, eax // high fraction 0..127
- neg eax
- add eax, 128
- movd xmm5, eax // low fraction 128..1
- punpcklbw xmm5, xmm0
- punpcklwd xmm5, xmm5
- pshufd xmm5, xmm5, 0
-
- align 4
- xloop:
- movdqa xmm0, [esi]
- movdqa xmm2, [esi + edx]
- movdqa xmm1, xmm0
- punpcklbw xmm0, xmm2
- punpckhbw xmm1, xmm2
- pmaddubsw xmm0, xmm5
- pmaddubsw xmm1, xmm5
- psrlw xmm0, 7
- psrlw xmm1, 7
- packuswb xmm0, xmm1
- sub ecx, 16
- movdqa [esi + edi], xmm0
- lea esi, [esi + 16]
- jg xloop
- jmp xloop99
-
- // Blend 25 / 75.
- align 4
- xloop25:
- movdqa xmm0, [esi]
- movdqa xmm1, [esi + edx]
- pavgb xmm0, xmm1
- pavgb xmm0, xmm1
- sub ecx, 16
- movdqa [esi + edi], xmm0
- lea esi, [esi + 16]
- jg xloop25
- jmp xloop99
-
- // Blend 50 / 50.
- align 4
- xloop50:
- movdqa xmm0, [esi]
- movdqa xmm1, [esi + edx]
- pavgb xmm0, xmm1
- sub ecx, 16
- movdqa [esi + edi], xmm0
- lea esi, [esi + 16]
- jg xloop50
- jmp xloop99
-
- // Blend 75 / 25.
- align 4
- xloop75:
- movdqa xmm1, [esi]
- movdqa xmm0, [esi + edx]
- pavgb xmm0, xmm1
- pavgb xmm0, xmm1
- sub ecx, 16
- movdqa [esi + edi], xmm0
- lea esi, [esi + 16]
- jg xloop75
- jmp xloop99
-
- // Blend 100 / 0 - Copy row unchanged.
- align 4
- xloop100:
- movdqa xmm0, [esi]
- sub ecx, 16
- movdqa [esi + edi], xmm0
- lea esi, [esi + 16]
- jg xloop100
-
- xloop99:
- pop edi
- pop esi
- ret
- }
-}
-#endif // HAS_INTERPOLATEROW_SSSE3
-
-#ifdef HAS_INTERPOLATEROW_SSE2
-// Bilinear filter 16x2 -> 16x1
-__declspec(naked) __declspec(align(16))
-void InterpolateRow_SSE2(uint8* dst_ptr, const uint8* src_ptr,
- ptrdiff_t src_stride, int dst_width,
- int source_y_fraction) {
- __asm {
- push esi
- push edi
- mov edi, [esp + 8 + 4] // dst_ptr
- mov esi, [esp + 8 + 8] // src_ptr
- mov edx, [esp + 8 + 12] // src_stride
- mov ecx, [esp + 8 + 16] // dst_width
- mov eax, [esp + 8 + 20] // source_y_fraction (0..255)
- sub edi, esi
- // Dispatch to specialized filters if applicable.
- cmp eax, 0
- je xloop100 // 0 / 256. Blend 100 / 0.
- cmp eax, 64
- je xloop75 // 64 / 256 is 0.25. Blend 75 / 25.
- cmp eax, 128
- je xloop50 // 128 / 256 is 0.50. Blend 50 / 50.
- cmp eax, 192
- je xloop25 // 192 / 256 is 0.75. Blend 25 / 75.
-
- movd xmm5, eax // xmm5 = y fraction
- punpcklbw xmm5, xmm5
- psrlw xmm5, 1
- punpcklwd xmm5, xmm5
- punpckldq xmm5, xmm5
- punpcklqdq xmm5, xmm5
- pxor xmm4, xmm4
-
- align 4
- xloop:
- movdqa xmm0, [esi] // row0
- movdqa xmm2, [esi + edx] // row1
- movdqa xmm1, xmm0
- movdqa xmm3, xmm2
- punpcklbw xmm2, xmm4
- punpckhbw xmm3, xmm4
- punpcklbw xmm0, xmm4
- punpckhbw xmm1, xmm4
- psubw xmm2, xmm0 // row1 - row0
- psubw xmm3, xmm1
- paddw xmm2, xmm2 // 9 bits * 15 bits = 8.16
- paddw xmm3, xmm3
- pmulhw xmm2, xmm5 // scale diff
- pmulhw xmm3, xmm5
- paddw xmm0, xmm2 // sum rows
- paddw xmm1, xmm3
- packuswb xmm0, xmm1
- sub ecx, 16
- movdqa [esi + edi], xmm0
- lea esi, [esi + 16]
- jg xloop
- jmp xloop99
-
- // Blend 25 / 75.
- align 4
- xloop25:
- movdqa xmm0, [esi]
- movdqa xmm1, [esi + edx]
- pavgb xmm0, xmm1
- pavgb xmm0, xmm1
- sub ecx, 16
- movdqa [esi + edi], xmm0
- lea esi, [esi + 16]
- jg xloop25
- jmp xloop99
-
- // Blend 50 / 50.
- align 4
- xloop50:
- movdqa xmm0, [esi]
- movdqa xmm1, [esi + edx]
- pavgb xmm0, xmm1
- sub ecx, 16
- movdqa [esi + edi], xmm0
- lea esi, [esi + 16]
- jg xloop50
- jmp xloop99
-
- // Blend 75 / 25.
- align 4
- xloop75:
- movdqa xmm1, [esi]
- movdqa xmm0, [esi + edx]
- pavgb xmm0, xmm1
- pavgb xmm0, xmm1
- sub ecx, 16
- movdqa [esi + edi], xmm0
- lea esi, [esi + 16]
- jg xloop75
- jmp xloop99
-
- // Blend 100 / 0 - Copy row unchanged.
- align 4
- xloop100:
- movdqa xmm0, [esi]
- sub ecx, 16
- movdqa [esi + edi], xmm0
- lea esi, [esi + 16]
- jg xloop100
-
- xloop99:
- pop edi
- pop esi
- ret
- }
-}
-#endif // HAS_INTERPOLATEROW_SSE2
-
-// Bilinear filter 16x2 -> 16x1
-__declspec(naked) __declspec(align(16))
-void InterpolateRow_Unaligned_SSSE3(uint8* dst_ptr, const uint8* src_ptr,
- ptrdiff_t src_stride, int dst_width,
- int source_y_fraction) {
- __asm {
- push esi
- push edi
- mov edi, [esp + 8 + 4] // dst_ptr
- mov esi, [esp + 8 + 8] // src_ptr
- mov edx, [esp + 8 + 12] // src_stride
- mov ecx, [esp + 8 + 16] // dst_width
- mov eax, [esp + 8 + 20] // source_y_fraction (0..255)
- sub edi, esi
- shr eax, 1
- // Dispatch to specialized filters if applicable.
- cmp eax, 0
- je xloop100 // 0 / 128. Blend 100 / 0.
- cmp eax, 32
- je xloop75 // 32 / 128 is 0.25. Blend 75 / 25.
- cmp eax, 64
- je xloop50 // 64 / 128 is 0.50. Blend 50 / 50.
- cmp eax, 96
- je xloop25 // 96 / 128 is 0.75. Blend 25 / 75.
-
- movd xmm0, eax // high fraction 0..127
- neg eax
- add eax, 128
- movd xmm5, eax // low fraction 128..1
- punpcklbw xmm5, xmm0
- punpcklwd xmm5, xmm5
- pshufd xmm5, xmm5, 0
-
- align 4
- xloop:
- movdqu xmm0, [esi]
- movdqu xmm2, [esi + edx]
- movdqu xmm1, xmm0
- punpcklbw xmm0, xmm2
- punpckhbw xmm1, xmm2
- pmaddubsw xmm0, xmm5
- pmaddubsw xmm1, xmm5
- psrlw xmm0, 7
- psrlw xmm1, 7
- packuswb xmm0, xmm1
- sub ecx, 16
- movdqu [esi + edi], xmm0
- lea esi, [esi + 16]
- jg xloop
- jmp xloop99
-
- // Blend 25 / 75.
- align 4
- xloop25:
- movdqu xmm0, [esi]
- movdqu xmm1, [esi + edx]
- pavgb xmm0, xmm1
- pavgb xmm0, xmm1
- sub ecx, 16
- movdqu [esi + edi], xmm0
- lea esi, [esi + 16]
- jg xloop25
- jmp xloop99
-
- // Blend 50 / 50.
- align 4
- xloop50:
- movdqu xmm0, [esi]
- movdqu xmm1, [esi + edx]
- pavgb xmm0, xmm1
- sub ecx, 16
- movdqu [esi + edi], xmm0
- lea esi, [esi + 16]
- jg xloop50
- jmp xloop99
-
- // Blend 75 / 25.
- align 4
- xloop75:
- movdqu xmm1, [esi]
- movdqu xmm0, [esi + edx]
- pavgb xmm0, xmm1
- pavgb xmm0, xmm1
- sub ecx, 16
- movdqu [esi + edi], xmm0
- lea esi, [esi + 16]
- jg xloop75
- jmp xloop99
-
- // Blend 100 / 0 - Copy row unchanged.
- align 4
- xloop100:
- movdqu xmm0, [esi]
- sub ecx, 16
- movdqu [esi + edi], xmm0
- lea esi, [esi + 16]
- jg xloop100
-
- xloop99:
- pop edi
- pop esi
- ret
- }
-}
-
-#ifdef HAS_INTERPOLATEROW_SSE2
-// Bilinear filter 16x2 -> 16x1
-__declspec(naked) __declspec(align(16))
-void InterpolateRow_Unaligned_SSE2(uint8* dst_ptr, const uint8* src_ptr,
- ptrdiff_t src_stride, int dst_width,
- int source_y_fraction) {
- __asm {
- push esi
- push edi
- mov edi, [esp + 8 + 4] // dst_ptr
- mov esi, [esp + 8 + 8] // src_ptr
- mov edx, [esp + 8 + 12] // src_stride
- mov ecx, [esp + 8 + 16] // dst_width
- mov eax, [esp + 8 + 20] // source_y_fraction (0..255)
- sub edi, esi
- // Dispatch to specialized filters if applicable.
- cmp eax, 0
- je xloop100 // 0 / 256. Blend 100 / 0.
- cmp eax, 64
- je xloop75 // 64 / 256 is 0.25. Blend 75 / 25.
- cmp eax, 128
- je xloop50 // 128 / 256 is 0.50. Blend 50 / 50.
- cmp eax, 192
- je xloop25 // 192 / 256 is 0.75. Blend 25 / 75.
-
- movd xmm5, eax // xmm5 = y fraction
- punpcklbw xmm5, xmm5
- psrlw xmm5, 1
- punpcklwd xmm5, xmm5
- punpckldq xmm5, xmm5
- punpcklqdq xmm5, xmm5
- pxor xmm4, xmm4
-
- align 4
- xloop:
- movdqu xmm0, [esi] // row0
- movdqu xmm2, [esi + edx] // row1
- movdqu xmm1, xmm0
- movdqu xmm3, xmm2
- punpcklbw xmm2, xmm4
- punpckhbw xmm3, xmm4
- punpcklbw xmm0, xmm4
- punpckhbw xmm1, xmm4
- psubw xmm2, xmm0 // row1 - row0
- psubw xmm3, xmm1
- paddw xmm2, xmm2 // 9 bits * 15 bits = 8.16
- paddw xmm3, xmm3
- pmulhw xmm2, xmm5 // scale diff
- pmulhw xmm3, xmm5
- paddw xmm0, xmm2 // sum rows
- paddw xmm1, xmm3
- packuswb xmm0, xmm1
- sub ecx, 16
- movdqu [esi + edi], xmm0
- lea esi, [esi + 16]
- jg xloop
- jmp xloop99
-
- // Blend 25 / 75.
- align 4
- xloop25:
- movdqu xmm0, [esi]
- movdqu xmm1, [esi + edx]
- pavgb xmm0, xmm1
- pavgb xmm0, xmm1
- sub ecx, 16
- movdqu [esi + edi], xmm0
- lea esi, [esi + 16]
- jg xloop25
- jmp xloop99
-
- // Blend 50 / 50.
- align 4
- xloop50:
- movdqu xmm0, [esi]
- movdqu xmm1, [esi + edx]
- pavgb xmm0, xmm1
- sub ecx, 16
- movdqu [esi + edi], xmm0
- lea esi, [esi + 16]
- jg xloop50
- jmp xloop99
-
- // Blend 75 / 25.
- align 4
- xloop75:
- movdqu xmm1, [esi]
- movdqu xmm0, [esi + edx]
- pavgb xmm0, xmm1
- pavgb xmm0, xmm1
- sub ecx, 16
- movdqu [esi + edi], xmm0
- lea esi, [esi + 16]
- jg xloop75
- jmp xloop99
-
- // Blend 100 / 0 - Copy row unchanged.
- align 4
- xloop100:
- movdqu xmm0, [esi]
- sub ecx, 16
- movdqu [esi + edi], xmm0
- lea esi, [esi + 16]
- jg xloop100
-
- xloop99:
- pop edi
- pop esi
- ret
- }
-}
-#endif // HAS_INTERPOLATEROW_SSE2
-
-__declspec(naked) __declspec(align(16))
-void HalfRow_SSE2(const uint8* src_uv, int src_uv_stride,
- uint8* dst_uv, int pix) {
- __asm {
- push edi
- mov eax, [esp + 4 + 4] // src_uv
- mov edx, [esp + 4 + 8] // src_uv_stride
- mov edi, [esp + 4 + 12] // dst_v
- mov ecx, [esp + 4 + 16] // pix
- sub edi, eax
-
- align 4
- convertloop:
- movdqa xmm0, [eax]
- pavgb xmm0, [eax + edx]
- sub ecx, 16
- movdqa [eax + edi], xmm0
- lea eax, [eax + 16]
- jg convertloop
- pop edi
- ret
- }
-}
-
-#ifdef HAS_HALFROW_AVX2
-__declspec(naked) __declspec(align(16))
-void HalfRow_AVX2(const uint8* src_uv, int src_uv_stride,
- uint8* dst_uv, int pix) {
- __asm {
- push edi
- mov eax, [esp + 4 + 4] // src_uv
- mov edx, [esp + 4 + 8] // src_uv_stride
- mov edi, [esp + 4 + 12] // dst_v
- mov ecx, [esp + 4 + 16] // pix
- sub edi, eax
-
- align 4
- convertloop:
- vmovdqu ymm0, [eax]
- vpavgb ymm0, ymm0, [eax + edx]
- sub ecx, 32
- vmovdqu [eax + edi], ymm0
- lea eax, [eax + 32]
- jg convertloop
-
- pop edi
- vzeroupper
- ret
- }
-}
-#endif // HAS_HALFROW_AVX2
-
-__declspec(naked) __declspec(align(16))
-void ARGBToBayerRow_SSSE3(const uint8* src_argb, uint8* dst_bayer,
- uint32 selector, int pix) {
- __asm {
- mov eax, [esp + 4] // src_argb
- mov edx, [esp + 8] // dst_bayer
- movd xmm5, [esp + 12] // selector
- mov ecx, [esp + 16] // pix
- pshufd xmm5, xmm5, 0
-
- align 4
- wloop:
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- lea eax, [eax + 32]
- pshufb xmm0, xmm5
- pshufb xmm1, xmm5
- punpckldq xmm0, xmm1
- sub ecx, 8
- movq qword ptr [edx], xmm0
- lea edx, [edx + 8]
- jg wloop
- ret
- }
-}
-
-// Specialized ARGB to Bayer that just isolates G channel.
-__declspec(naked) __declspec(align(16))
-void ARGBToBayerGGRow_SSE2(const uint8* src_argb, uint8* dst_bayer,
- uint32 selector, int pix) {
- __asm {
- mov eax, [esp + 4] // src_argb
- mov edx, [esp + 8] // dst_bayer
- // selector
- mov ecx, [esp + 16] // pix
- pcmpeqb xmm5, xmm5 // generate mask 0x000000ff
- psrld xmm5, 24
-
- align 4
- wloop:
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- lea eax, [eax + 32]
- psrld xmm0, 8 // Move green to bottom.
- psrld xmm1, 8
- pand xmm0, xmm5
- pand xmm1, xmm5
- packssdw xmm0, xmm1
- packuswb xmm0, xmm1
- sub ecx, 8
- movq qword ptr [edx], xmm0
- lea edx, [edx + 8]
- jg wloop
- ret
- }
-}
-
-// For BGRAToARGB, ABGRToARGB, RGBAToARGB, and ARGBToRGBA.
-__declspec(naked) __declspec(align(16))
-void ARGBShuffleRow_SSSE3(const uint8* src_argb, uint8* dst_argb,
- const uint8* shuffler, int pix) {
- __asm {
- mov eax, [esp + 4] // src_argb
- mov edx, [esp + 8] // dst_argb
- mov ecx, [esp + 12] // shuffler
- movdqa xmm5, [ecx]
- mov ecx, [esp + 16] // pix
-
- align 4
- wloop:
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- lea eax, [eax + 32]
- pshufb xmm0, xmm5
- pshufb xmm1, xmm5
- sub ecx, 8
- movdqa [edx], xmm0
- movdqa [edx + 16], xmm1
- lea edx, [edx + 32]
- jg wloop
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void ARGBShuffleRow_Unaligned_SSSE3(const uint8* src_argb, uint8* dst_argb,
- const uint8* shuffler, int pix) {
- __asm {
- mov eax, [esp + 4] // src_argb
- mov edx, [esp + 8] // dst_argb
- mov ecx, [esp + 12] // shuffler
- movdqa xmm5, [ecx]
- mov ecx, [esp + 16] // pix
-
- align 4
- wloop:
- movdqu xmm0, [eax]
- movdqu xmm1, [eax + 16]
- lea eax, [eax + 32]
- pshufb xmm0, xmm5
- pshufb xmm1, xmm5
- sub ecx, 8
- movdqu [edx], xmm0
- movdqu [edx + 16], xmm1
- lea edx, [edx + 32]
- jg wloop
- ret
- }
-}
-
-#ifdef HAS_ARGBSHUFFLEROW_AVX2
-__declspec(naked) __declspec(align(16))
-void ARGBShuffleRow_AVX2(const uint8* src_argb, uint8* dst_argb,
- const uint8* shuffler, int pix) {
- __asm {
- mov eax, [esp + 4] // src_argb
- mov edx, [esp + 8] // dst_argb
- mov ecx, [esp + 12] // shuffler
- vbroadcastf128 ymm5, [ecx] // same shuffle in high as low.
- mov ecx, [esp + 16] // pix
-
- align 4
- wloop:
- vmovdqu ymm0, [eax]
- vmovdqu ymm1, [eax + 32]
- lea eax, [eax + 64]
- vpshufb ymm0, ymm0, ymm5
- vpshufb ymm1, ymm1, ymm5
- sub ecx, 16
- vmovdqu [edx], ymm0
- vmovdqu [edx + 32], ymm1
- lea edx, [edx + 64]
- jg wloop
-
- vzeroupper
- ret
- }
-}
-#endif // HAS_ARGBSHUFFLEROW_AVX2
-
-__declspec(naked) __declspec(align(16))
-void ARGBShuffleRow_SSE2(const uint8* src_argb, uint8* dst_argb,
- const uint8* shuffler, int pix) {
- __asm {
- push ebx
- push esi
- mov eax, [esp + 8 + 4] // src_argb
- mov edx, [esp + 8 + 8] // dst_argb
- mov esi, [esp + 8 + 12] // shuffler
- mov ecx, [esp + 8 + 16] // pix
- pxor xmm5, xmm5
-
- mov ebx, [esi] // shuffler
- cmp ebx, 0x03000102
- je shuf_3012
- cmp ebx, 0x00010203
- je shuf_0123
- cmp ebx, 0x00030201
- je shuf_0321
- cmp ebx, 0x02010003
- je shuf_2103
-
- // TODO(fbarchard): Use one source pointer and 3 offsets.
- shuf_any1:
- movzx ebx, byte ptr [esi]
- movzx ebx, byte ptr [eax + ebx]
- mov [edx], bl
- movzx ebx, byte ptr [esi + 1]
- movzx ebx, byte ptr [eax + ebx]
- mov [edx + 1], bl
- movzx ebx, byte ptr [esi + 2]
- movzx ebx, byte ptr [eax + ebx]
- mov [edx + 2], bl
- movzx ebx, byte ptr [esi + 3]
- movzx ebx, byte ptr [eax + ebx]
- mov [edx + 3], bl
- lea eax, [eax + 4]
- lea edx, [edx + 4]
- sub ecx, 1
- jg shuf_any1
- jmp shuf99
-
- align 4
- shuf_0123:
- movdqu xmm0, [eax]
- lea eax, [eax + 16]
- movdqa xmm1, xmm0
- punpcklbw xmm0, xmm5
- punpckhbw xmm1, xmm5
- pshufhw xmm0, xmm0, 01Bh // 1B = 00011011 = 0x0123 = BGRAToARGB
- pshuflw xmm0, xmm0, 01Bh
- pshufhw xmm1, xmm1, 01Bh
- pshuflw xmm1, xmm1, 01Bh
- packuswb xmm0, xmm1
- sub ecx, 4
- movdqu [edx], xmm0
- lea edx, [edx + 16]
- jg shuf_0123
- jmp shuf99
-
- align 4
- shuf_0321:
- movdqu xmm0, [eax]
- lea eax, [eax + 16]
- movdqa xmm1, xmm0
- punpcklbw xmm0, xmm5
- punpckhbw xmm1, xmm5
- pshufhw xmm0, xmm0, 039h // 39 = 00111001 = 0x0321 = RGBAToARGB
- pshuflw xmm0, xmm0, 039h
- pshufhw xmm1, xmm1, 039h
- pshuflw xmm1, xmm1, 039h
- packuswb xmm0, xmm1
- sub ecx, 4
- movdqu [edx], xmm0
- lea edx, [edx + 16]
- jg shuf_0321
- jmp shuf99
-
- align 4
- shuf_2103:
- movdqu xmm0, [eax]
- lea eax, [eax + 16]
- movdqa xmm1, xmm0
- punpcklbw xmm0, xmm5
- punpckhbw xmm1, xmm5
- pshufhw xmm0, xmm0, 093h // 93 = 10010011 = 0x2103 = ARGBToRGBA
- pshuflw xmm0, xmm0, 093h
- pshufhw xmm1, xmm1, 093h
- pshuflw xmm1, xmm1, 093h
- packuswb xmm0, xmm1
- sub ecx, 4
- movdqu [edx], xmm0
- lea edx, [edx + 16]
- jg shuf_2103
- jmp shuf99
-
- align 4
- shuf_3012:
- movdqu xmm0, [eax]
- lea eax, [eax + 16]
- movdqa xmm1, xmm0
- punpcklbw xmm0, xmm5
- punpckhbw xmm1, xmm5
- pshufhw xmm0, xmm0, 0C6h // C6 = 11000110 = 0x3012 = ABGRToARGB
- pshuflw xmm0, xmm0, 0C6h
- pshufhw xmm1, xmm1, 0C6h
- pshuflw xmm1, xmm1, 0C6h
- packuswb xmm0, xmm1
- sub ecx, 4
- movdqu [edx], xmm0
- lea edx, [edx + 16]
- jg shuf_3012
-
- shuf99:
- pop esi
- pop ebx
- ret
- }
-}
-
-// YUY2 - Macro-pixel = 2 image pixels
-// Y0U0Y1V0....Y2U2Y3V2...Y4U4Y5V4....
-
-// UYVY - Macro-pixel = 2 image pixels
-// U0Y0V0Y1
-
-__declspec(naked) __declspec(align(16))
-void I422ToYUY2Row_SSE2(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_frame, int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // src_y
- mov esi, [esp + 8 + 8] // src_u
- mov edx, [esp + 8 + 12] // src_v
- mov edi, [esp + 8 + 16] // dst_frame
- mov ecx, [esp + 8 + 20] // width
- sub edx, esi
-
- align 4
- convertloop:
- movq xmm2, qword ptr [esi] // U
- movq xmm3, qword ptr [esi + edx] // V
- lea esi, [esi + 8]
- punpcklbw xmm2, xmm3 // UV
- movdqu xmm0, [eax] // Y
- lea eax, [eax + 16]
- movdqa xmm1, xmm0
- punpcklbw xmm0, xmm2 // YUYV
- punpckhbw xmm1, xmm2
- movdqu [edi], xmm0
- movdqu [edi + 16], xmm1
- lea edi, [edi + 32]
- sub ecx, 16
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-__declspec(naked) __declspec(align(16))
-void I422ToUYVYRow_SSE2(const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_frame, int width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // src_y
- mov esi, [esp + 8 + 8] // src_u
- mov edx, [esp + 8 + 12] // src_v
- mov edi, [esp + 8 + 16] // dst_frame
- mov ecx, [esp + 8 + 20] // width
- sub edx, esi
-
- align 4
- convertloop:
- movq xmm2, qword ptr [esi] // U
- movq xmm3, qword ptr [esi + edx] // V
- lea esi, [esi + 8]
- punpcklbw xmm2, xmm3 // UV
- movdqu xmm0, [eax] // Y
- movdqa xmm1, xmm2
- lea eax, [eax + 16]
- punpcklbw xmm1, xmm0 // UYVY
- punpckhbw xmm2, xmm0
- movdqu [edi], xmm1
- movdqu [edi + 16], xmm2
- lea edi, [edi + 32]
- sub ecx, 16
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-#ifdef HAS_ARGBPOLYNOMIALROW_SSE2
-__declspec(naked) __declspec(align(16))
-void ARGBPolynomialRow_SSE2(const uint8* src_argb,
- uint8* dst_argb, const float* poly,
- int width) {
- __asm {
- push esi
- mov eax, [esp + 4 + 4] /* src_argb */
- mov edx, [esp + 4 + 8] /* dst_argb */
- mov esi, [esp + 4 + 12] /* poly */
- mov ecx, [esp + 4 + 16] /* width */
- pxor xmm3, xmm3 // 0 constant for zero extending bytes to ints.
-
- // 2 pixel loop.
- align 4
- convertloop:
-// pmovzxbd xmm0, dword ptr [eax] // BGRA pixel
-// pmovzxbd xmm4, dword ptr [eax + 4] // BGRA pixel
- movq xmm0, qword ptr [eax] // BGRABGRA
- lea eax, [eax + 8]
- punpcklbw xmm0, xmm3
- movdqa xmm4, xmm0
- punpcklwd xmm0, xmm3 // pixel 0
- punpckhwd xmm4, xmm3 // pixel 1
- cvtdq2ps xmm0, xmm0 // 4 floats
- cvtdq2ps xmm4, xmm4
- movdqa xmm1, xmm0 // X
- movdqa xmm5, xmm4
- mulps xmm0, [esi + 16] // C1 * X
- mulps xmm4, [esi + 16]
- addps xmm0, [esi] // result = C0 + C1 * X
- addps xmm4, [esi]
- movdqa xmm2, xmm1
- movdqa xmm6, xmm5
- mulps xmm2, xmm1 // X * X
- mulps xmm6, xmm5
- mulps xmm1, xmm2 // X * X * X
- mulps xmm5, xmm6
- mulps xmm2, [esi + 32] // C2 * X * X
- mulps xmm6, [esi + 32]
- mulps xmm1, [esi + 48] // C3 * X * X * X
- mulps xmm5, [esi + 48]
- addps xmm0, xmm2 // result += C2 * X * X
- addps xmm4, xmm6
- addps xmm0, xmm1 // result += C3 * X * X * X
- addps xmm4, xmm5
- cvttps2dq xmm0, xmm0
- cvttps2dq xmm4, xmm4
- packuswb xmm0, xmm4
- packuswb xmm0, xmm0
- sub ecx, 2
- movq qword ptr [edx], xmm0
- lea edx, [edx + 8]
- jg convertloop
- pop esi
- ret
- }
-}
-#endif // HAS_ARGBPOLYNOMIALROW_SSE2
-
-#ifdef HAS_ARGBPOLYNOMIALROW_AVX2
-__declspec(naked) __declspec(align(16))
-void ARGBPolynomialRow_AVX2(const uint8* src_argb,
- uint8* dst_argb, const float* poly,
- int width) {
- __asm {
- mov eax, [esp + 4] /* src_argb */
- mov edx, [esp + 8] /* dst_argb */
- mov ecx, [esp + 12] /* poly */
- vbroadcastf128 ymm4, [ecx] // C0
- vbroadcastf128 ymm5, [ecx + 16] // C1
- vbroadcastf128 ymm6, [ecx + 32] // C2
- vbroadcastf128 ymm7, [ecx + 48] // C3
- mov ecx, [esp + 16] /* width */
-
- // 2 pixel loop.
- align 4
- convertloop:
- vpmovzxbd ymm0, qword ptr [eax] // 2 BGRA pixels
- lea eax, [eax + 8]
- vcvtdq2ps ymm0, ymm0 // X 8 floats
- vmulps ymm2, ymm0, ymm0 // X * X
- vmulps ymm3, ymm0, ymm7 // C3 * X
- vfmadd132ps ymm0, ymm4, ymm5 // result = C0 + C1 * X
- vfmadd231ps ymm0, ymm2, ymm6 // result += C2 * X * X
- vfmadd231ps ymm0, ymm2, ymm3 // result += C3 * X * X * X
- vcvttps2dq ymm0, ymm0
- vpackusdw ymm0, ymm0, ymm0 // b0g0r0a0_00000000_b0g0r0a0_00000000
- vpermq ymm0, ymm0, 0xd8 // b0g0r0a0_b0g0r0a0_00000000_00000000
- vpackuswb xmm0, xmm0, xmm0 // bgrabgra_00000000_00000000_00000000
- sub ecx, 2
- vmovq qword ptr [edx], xmm0
- lea edx, [edx + 8]
- jg convertloop
- vzeroupper
- ret
- }
-}
-#endif // HAS_ARGBPOLYNOMIALROW_AVX2
-
-#ifdef HAS_ARGBCOLORTABLEROW_X86
-// Tranform ARGB pixels with color table.
-__declspec(naked) __declspec(align(16))
-void ARGBColorTableRow_X86(uint8* dst_argb, const uint8* table_argb,
- int width) {
- __asm {
- push esi
- mov eax, [esp + 4 + 4] /* dst_argb */
- mov esi, [esp + 4 + 8] /* table_argb */
- mov ecx, [esp + 4 + 12] /* width */
-
- // 1 pixel loop.
- align 4
- convertloop:
- movzx edx, byte ptr [eax]
- lea eax, [eax + 4]
- movzx edx, byte ptr [esi + edx * 4]
- mov byte ptr [eax - 4], dl
- movzx edx, byte ptr [eax - 4 + 1]
- movzx edx, byte ptr [esi + edx * 4 + 1]
- mov byte ptr [eax - 4 + 1], dl
- movzx edx, byte ptr [eax - 4 + 2]
- movzx edx, byte ptr [esi + edx * 4 + 2]
- mov byte ptr [eax - 4 + 2], dl
- movzx edx, byte ptr [eax - 4 + 3]
- movzx edx, byte ptr [esi + edx * 4 + 3]
- mov byte ptr [eax - 4 + 3], dl
- dec ecx
- jg convertloop
- pop esi
- ret
- }
-}
-#endif // HAS_ARGBCOLORTABLEROW_X86
-
-#ifdef HAS_RGBCOLORTABLEROW_X86
-// Tranform RGB pixels with color table.
-__declspec(naked) __declspec(align(16))
-void RGBColorTableRow_X86(uint8* dst_argb, const uint8* table_argb, int width) {
- __asm {
- push esi
- mov eax, [esp + 4 + 4] /* dst_argb */
- mov esi, [esp + 4 + 8] /* table_argb */
- mov ecx, [esp + 4 + 12] /* width */
-
- // 1 pixel loop.
- align 4
- convertloop:
- movzx edx, byte ptr [eax]
- lea eax, [eax + 4]
- movzx edx, byte ptr [esi + edx * 4]
- mov byte ptr [eax - 4], dl
- movzx edx, byte ptr [eax - 4 + 1]
- movzx edx, byte ptr [esi + edx * 4 + 1]
- mov byte ptr [eax - 4 + 1], dl
- movzx edx, byte ptr [eax - 4 + 2]
- movzx edx, byte ptr [esi + edx * 4 + 2]
- mov byte ptr [eax - 4 + 2], dl
- dec ecx
- jg convertloop
-
- pop esi
- ret
- }
-}
-#endif // HAS_RGBCOLORTABLEROW_X86
-
-#ifdef HAS_ARGBLUMACOLORTABLEROW_SSSE3
-// Tranform RGB pixels with luma table.
-__declspec(naked) __declspec(align(16))
-void ARGBLumaColorTableRow_SSSE3(const uint8* src_argb, uint8* dst_argb,
- int width,
- const uint8* luma, uint32 lumacoeff) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] /* src_argb */
- mov edi, [esp + 8 + 8] /* dst_argb */
- mov ecx, [esp + 8 + 12] /* width */
- movd xmm2, dword ptr [esp + 8 + 16] // luma table
- movd xmm3, dword ptr [esp + 8 + 20] // lumacoeff
- pshufd xmm2, xmm2, 0
- pshufd xmm3, xmm3, 0
- pcmpeqb xmm4, xmm4 // generate mask 0xff00ff00
- psllw xmm4, 8
- pxor xmm5, xmm5
-
- // 4 pixel loop.
- align 4
- convertloop:
- movdqu xmm0, qword ptr [eax] // generate luma ptr
- pmaddubsw xmm0, xmm3
- phaddw xmm0, xmm0
- pand xmm0, xmm4 // mask out low bits
- punpcklwd xmm0, xmm5
- paddd xmm0, xmm2 // add table base
- movd esi, xmm0
- pshufd xmm0, xmm0, 0x39 // 00111001 to rotate right 32
-
- movzx edx, byte ptr [eax]
- movzx edx, byte ptr [esi + edx]
- mov byte ptr [edi], dl
- movzx edx, byte ptr [eax + 1]
- movzx edx, byte ptr [esi + edx]
- mov byte ptr [edi + 1], dl
- movzx edx, byte ptr [eax + 2]
- movzx edx, byte ptr [esi + edx]
- mov byte ptr [edi + 2], dl
- movzx edx, byte ptr [eax + 3] // copy alpha.
- mov byte ptr [edi + 3], dl
-
- movd esi, xmm0
- pshufd xmm0, xmm0, 0x39 // 00111001 to rotate right 32
-
- movzx edx, byte ptr [eax + 4]
- movzx edx, byte ptr [esi + edx]
- mov byte ptr [edi + 4], dl
- movzx edx, byte ptr [eax + 5]
- movzx edx, byte ptr [esi + edx]
- mov byte ptr [edi + 5], dl
- movzx edx, byte ptr [eax + 6]
- movzx edx, byte ptr [esi + edx]
- mov byte ptr [edi + 6], dl
- movzx edx, byte ptr [eax + 7] // copy alpha.
- mov byte ptr [edi + 7], dl
-
- movd esi, xmm0
- pshufd xmm0, xmm0, 0x39 // 00111001 to rotate right 32
-
- movzx edx, byte ptr [eax + 8]
- movzx edx, byte ptr [esi + edx]
- mov byte ptr [edi + 8], dl
- movzx edx, byte ptr [eax + 9]
- movzx edx, byte ptr [esi + edx]
- mov byte ptr [edi + 9], dl
- movzx edx, byte ptr [eax + 10]
- movzx edx, byte ptr [esi + edx]
- mov byte ptr [edi + 10], dl
- movzx edx, byte ptr [eax + 11] // copy alpha.
- mov byte ptr [edi + 11], dl
-
- movd esi, xmm0
-
- movzx edx, byte ptr [eax + 12]
- movzx edx, byte ptr [esi + edx]
- mov byte ptr [edi + 12], dl
- movzx edx, byte ptr [eax + 13]
- movzx edx, byte ptr [esi + edx]
- mov byte ptr [edi + 13], dl
- movzx edx, byte ptr [eax + 14]
- movzx edx, byte ptr [esi + edx]
- mov byte ptr [edi + 14], dl
- movzx edx, byte ptr [eax + 15] // copy alpha.
- mov byte ptr [edi + 15], dl
-
- sub ecx, 4
- lea eax, [eax + 16]
- lea edi, [edi + 16]
- jg convertloop
-
- pop edi
- pop esi
- ret
- }
-}
-#endif // HAS_ARGBLUMACOLORTABLEROW_SSSE3
-
-#endif // !defined(LIBYUV_DISABLE_X86) && defined(_M_IX86) && defined(_MSC_VER)
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/row_x86.asm b/drivers/theoraplayer/src/YUV/libyuv/src/row_x86.asm
deleted file mode 100755
index 0cb326f8e5..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/row_x86.asm
+++ /dev/null
@@ -1,146 +0,0 @@
-;
-; Copyright 2012 The LibYuv Project Authors. All rights reserved.
-;
-; Use of this source code is governed by a BSD-style license
-; that can be found in the LICENSE file in the root of the source
-; tree. An additional intellectual property rights grant can be found
-; in the file PATENTS. All contributing project authors may
-; be found in the AUTHORS file in the root of the source tree.
-;
-
-%ifdef __YASM_VERSION_ID__
-%if __YASM_VERSION_ID__ < 01020000h
-%error AVX2 is supported only by yasm 1.2.0 or later.
-%endif
-%endif
-%include "x86inc.asm"
-
-SECTION .text
-
-; cglobal numeric constants are parameters, gpr regs, mm regs
-
-; void YUY2ToYRow_SSE2(const uint8* src_yuy2, uint8* dst_y, int pix)
-
-%macro YUY2TOYROW 2-3
-cglobal %1ToYRow%3, 3, 3, 3, src_yuy2, dst_y, pix
-%ifidn %1,YUY2
- pcmpeqb m2, m2, m2 ; generate mask 0x00ff00ff
- psrlw m2, m2, 8
-%endif
-
- ALIGN 4
-.convertloop:
- mov%2 m0, [src_yuy2q]
- mov%2 m1, [src_yuy2q + mmsize]
- lea src_yuy2q, [src_yuy2q + mmsize * 2]
-%ifidn %1,YUY2
- pand m0, m0, m2 ; YUY2 even bytes are Y
- pand m1, m1, m2
-%else
- psrlw m0, m0, 8 ; UYVY odd bytes are Y
- psrlw m1, m1, 8
-%endif
- packuswb m0, m0, m1
-%if cpuflag(AVX2)
- vpermq m0, m0, 0xd8
-%endif
- sub pixd, mmsize
- mov%2 [dst_yq], m0
- lea dst_yq, [dst_yq + mmsize]
- jg .convertloop
- REP_RET
-%endmacro
-
-; TODO(fbarchard): Remove MMX. Add SSSE3 pshufb version.
-INIT_MMX MMX
-YUY2TOYROW YUY2,a,
-YUY2TOYROW YUY2,u,_Unaligned
-YUY2TOYROW UYVY,a,
-YUY2TOYROW UYVY,u,_Unaligned
-INIT_XMM SSE2
-YUY2TOYROW YUY2,a,
-YUY2TOYROW YUY2,u,_Unaligned
-YUY2TOYROW UYVY,a,
-YUY2TOYROW UYVY,u,_Unaligned
-INIT_YMM AVX2
-YUY2TOYROW YUY2,a,
-YUY2TOYROW UYVY,a,
-
-; void SplitUVRow_SSE2(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int pix)
-
-%macro SplitUVRow 1-2
-cglobal SplitUVRow%2, 4, 4, 5, src_uv, dst_u, dst_v, pix
- pcmpeqb m4, m4, m4 ; generate mask 0x00ff00ff
- psrlw m4, m4, 8
- sub dst_vq, dst_uq
-
- ALIGN 4
-.convertloop:
- mov%1 m0, [src_uvq]
- mov%1 m1, [src_uvq + mmsize]
- lea src_uvq, [src_uvq + mmsize * 2]
- psrlw m2, m0, 8 ; odd bytes
- psrlw m3, m1, 8
- pand m0, m0, m4 ; even bytes
- pand m1, m1, m4
- packuswb m0, m0, m1
- packuswb m2, m2, m3
-%if cpuflag(AVX2)
- vpermq m0, m0, 0xd8
- vpermq m2, m2, 0xd8
-%endif
- mov%1 [dst_uq], m0
- mov%1 [dst_uq + dst_vq], m2
- lea dst_uq, [dst_uq + mmsize]
- sub pixd, mmsize
- jg .convertloop
- REP_RET
-%endmacro
-
-INIT_MMX MMX
-SplitUVRow a,
-SplitUVRow u,_Unaligned
-INIT_XMM SSE2
-SplitUVRow a,
-SplitUVRow u,_Unaligned
-INIT_YMM AVX2
-SplitUVRow a,
-
-; void MergeUVRow_SSE2(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
-; int width);
-
-%macro MergeUVRow_ 1-2
-cglobal MergeUVRow_%2, 4, 4, 3, src_u, src_v, dst_uv, pix
- sub src_vq, src_uq
-
- ALIGN 4
-.convertloop:
- mov%1 m0, [src_uq]
- mov%1 m1, [src_vq]
- lea src_uq, [src_uq + mmsize]
- punpcklbw m2, m0, m1 // first 8 UV pairs
- punpckhbw m0, m0, m1 // next 8 UV pairs
-%if cpuflag(AVX2)
- vperm2i128 m1, m2, m0, 0x20 // low 128 of ymm2 and low 128 of ymm0
- vperm2i128 m2, m2, m0, 0x31 // high 128 of ymm2 and high 128 of ymm0
- mov%1 [dst_uvq], m1
- mov%1 [dst_uvq + mmsize], m2
-%else
- mov%1 [dst_uvq], m2
- mov%1 [dst_uvq + mmsize], m0
-%endif
- lea dst_uvq, [dst_uvq + mmsize * 2]
- sub pixd, mmsize
- jg .convertloop
- REP_RET
-%endmacro
-
-INIT_MMX MMX
-MergeUVRow_ a,
-MergeUVRow_ u,_Unaligned
-INIT_XMM SSE2
-MergeUVRow_ a,
-MergeUVRow_ u,_Unaligned
-INIT_YMM AVX2
-MergeUVRow_ a,
-
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/scale.cc b/drivers/theoraplayer/src/YUV/libyuv/src/scale.cc
deleted file mode 100755
index b3893cc00c..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/scale.cc
+++ /dev/null
@@ -1,926 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/scale.h"
-
-#include <assert.h>
-#include <string.h>
-
-#include "libyuv/cpu_id.h"
-#include "libyuv/planar_functions.h" // For CopyPlane
-#include "libyuv/row.h"
-#include "libyuv/scale_row.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// Remove this macro if OVERREAD is safe.
-#define AVOID_OVERREAD 1
-
-static __inline int Abs(int v) {
- return v >= 0 ? v : -v;
-}
-
-#define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
-
-// Scale plane, 1/2
-// This is an optimized version for scaling down a plane to 1/2 of
-// its original size.
-
-static void ScalePlaneDown2(int src_width, int src_height,
- int dst_width, int dst_height,
- int src_stride, int dst_stride,
- const uint8* src_ptr, uint8* dst_ptr,
- enum FilterMode filtering) {
- int y;
- void (*ScaleRowDown2)(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) =
- filtering == kFilterNone ? ScaleRowDown2_C :
- (filtering == kFilterLinear ? ScaleRowDown2Linear_C :
- ScaleRowDown2Box_C);
- int row_stride = src_stride << 1;
- if (!filtering) {
- src_ptr += src_stride; // Point to odd rows.
- src_stride = 0;
- }
-
-#if defined(HAS_SCALEROWDOWN2_NEON)
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(dst_width, 16)) {
- ScaleRowDown2 = filtering ? ScaleRowDown2Box_NEON : ScaleRowDown2_NEON;
- }
-#elif defined(HAS_SCALEROWDOWN2_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 16)) {
- ScaleRowDown2 = filtering == kFilterNone ? ScaleRowDown2_Unaligned_SSE2 :
- (filtering == kFilterLinear ? ScaleRowDown2Linear_Unaligned_SSE2 :
- ScaleRowDown2Box_Unaligned_SSE2);
- if (IS_ALIGNED(src_ptr, 16) &&
- IS_ALIGNED(src_stride, 16) && IS_ALIGNED(row_stride, 16) &&
- IS_ALIGNED(dst_ptr, 16) && IS_ALIGNED(dst_stride, 16)) {
- ScaleRowDown2 = filtering == kFilterNone ? ScaleRowDown2_SSE2 :
- (filtering == kFilterLinear ? ScaleRowDown2Linear_SSE2 :
- ScaleRowDown2Box_SSE2);
- }
- }
-#elif defined(HAS_SCALEROWDOWN2_MIPS_DSPR2)
- if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(src_ptr, 4) &&
- IS_ALIGNED(src_stride, 4) && IS_ALIGNED(row_stride, 4) &&
- IS_ALIGNED(dst_ptr, 4) && IS_ALIGNED(dst_stride, 4)) {
- ScaleRowDown2 = filtering ?
- ScaleRowDown2Box_MIPS_DSPR2 : ScaleRowDown2_MIPS_DSPR2;
- }
-#endif
-
- if (filtering == kFilterLinear) {
- src_stride = 0;
- }
- // TODO(fbarchard): Loop through source height to allow odd height.
- for (y = 0; y < dst_height; ++y) {
- ScaleRowDown2(src_ptr, src_stride, dst_ptr, dst_width);
- src_ptr += row_stride;
- dst_ptr += dst_stride;
- }
-}
-
-// Scale plane, 1/4
-// This is an optimized version for scaling down a plane to 1/4 of
-// its original size.
-
-static void ScalePlaneDown4(int src_width, int src_height,
- int dst_width, int dst_height,
- int src_stride, int dst_stride,
- const uint8* src_ptr, uint8* dst_ptr,
- enum FilterMode filtering) {
- int y;
- void (*ScaleRowDown4)(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) =
- filtering ? ScaleRowDown4Box_C : ScaleRowDown4_C;
- int row_stride = src_stride << 2;
- if (!filtering) {
- src_ptr += src_stride * 2; // Point to row 2.
- src_stride = 0;
- }
-#if defined(HAS_SCALEROWDOWN4_NEON)
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(dst_width, 8)) {
- ScaleRowDown4 = filtering ? ScaleRowDown4Box_NEON : ScaleRowDown4_NEON;
- }
-#elif defined(HAS_SCALEROWDOWN4_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) &&
- IS_ALIGNED(dst_width, 8) && IS_ALIGNED(row_stride, 16) &&
- IS_ALIGNED(src_ptr, 16) && IS_ALIGNED(src_stride, 16)) {
- ScaleRowDown4 = filtering ? ScaleRowDown4Box_SSE2 : ScaleRowDown4_SSE2;
- }
-#elif defined(HAS_SCALEROWDOWN4_MIPS_DSPR2)
- if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(row_stride, 4) &&
- IS_ALIGNED(src_ptr, 4) && IS_ALIGNED(src_stride, 4) &&
- IS_ALIGNED(dst_ptr, 4) && IS_ALIGNED(dst_stride, 4)) {
- ScaleRowDown4 = filtering ?
- ScaleRowDown4Box_MIPS_DSPR2 : ScaleRowDown4_MIPS_DSPR2;
- }
-#endif
-
- if (filtering == kFilterLinear) {
- src_stride = 0;
- }
- for (y = 0; y < dst_height; ++y) {
- ScaleRowDown4(src_ptr, src_stride, dst_ptr, dst_width);
- src_ptr += row_stride;
- dst_ptr += dst_stride;
- }
-}
-
-// Scale plane down, 3/4
-
-static void ScalePlaneDown34(int src_width, int src_height,
- int dst_width, int dst_height,
- int src_stride, int dst_stride,
- const uint8* src_ptr, uint8* dst_ptr,
- enum FilterMode filtering) {
- int y;
- void (*ScaleRowDown34_0)(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
- void (*ScaleRowDown34_1)(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
- const int filter_stride = (filtering == kFilterLinear) ? 0 : src_stride;
- assert(dst_width % 3 == 0);
- if (!filtering) {
- ScaleRowDown34_0 = ScaleRowDown34_C;
- ScaleRowDown34_1 = ScaleRowDown34_C;
- } else {
- ScaleRowDown34_0 = ScaleRowDown34_0_Box_C;
- ScaleRowDown34_1 = ScaleRowDown34_1_Box_C;
- }
-#if defined(HAS_SCALEROWDOWN34_NEON)
- if (TestCpuFlag(kCpuHasNEON) && (dst_width % 24 == 0)) {
- if (!filtering) {
- ScaleRowDown34_0 = ScaleRowDown34_NEON;
- ScaleRowDown34_1 = ScaleRowDown34_NEON;
- } else {
- ScaleRowDown34_0 = ScaleRowDown34_0_Box_NEON;
- ScaleRowDown34_1 = ScaleRowDown34_1_Box_NEON;
- }
- }
-#endif
-#if defined(HAS_SCALEROWDOWN34_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && (dst_width % 24 == 0) &&
- IS_ALIGNED(src_ptr, 16) && IS_ALIGNED(src_stride, 16)) {
- if (!filtering) {
- ScaleRowDown34_0 = ScaleRowDown34_SSSE3;
- ScaleRowDown34_1 = ScaleRowDown34_SSSE3;
- } else {
- ScaleRowDown34_0 = ScaleRowDown34_0_Box_SSSE3;
- ScaleRowDown34_1 = ScaleRowDown34_1_Box_SSSE3;
- }
- }
-#endif
-#if defined(HAS_SCALEROWDOWN34_MIPS_DSPR2)
- if (TestCpuFlag(kCpuHasMIPS_DSPR2) && (dst_width % 24 == 0) &&
- IS_ALIGNED(src_ptr, 4) && IS_ALIGNED(src_stride, 4) &&
- IS_ALIGNED(dst_ptr, 4) && IS_ALIGNED(dst_stride, 4)) {
- if (!filtering) {
- ScaleRowDown34_0 = ScaleRowDown34_MIPS_DSPR2;
- ScaleRowDown34_1 = ScaleRowDown34_MIPS_DSPR2;
- } else {
- ScaleRowDown34_0 = ScaleRowDown34_0_Box_MIPS_DSPR2;
- ScaleRowDown34_1 = ScaleRowDown34_1_Box_MIPS_DSPR2;
- }
- }
-#endif
-
- for (y = 0; y < dst_height - 2; y += 3) {
- ScaleRowDown34_0(src_ptr, filter_stride, dst_ptr, dst_width);
- src_ptr += src_stride;
- dst_ptr += dst_stride;
- ScaleRowDown34_1(src_ptr, filter_stride, dst_ptr, dst_width);
- src_ptr += src_stride;
- dst_ptr += dst_stride;
- ScaleRowDown34_0(src_ptr + src_stride, -filter_stride,
- dst_ptr, dst_width);
- src_ptr += src_stride * 2;
- dst_ptr += dst_stride;
- }
-
- // Remainder 1 or 2 rows with last row vertically unfiltered
- if ((dst_height % 3) == 2) {
- ScaleRowDown34_0(src_ptr, filter_stride, dst_ptr, dst_width);
- src_ptr += src_stride;
- dst_ptr += dst_stride;
- ScaleRowDown34_1(src_ptr, 0, dst_ptr, dst_width);
- } else if ((dst_height % 3) == 1) {
- ScaleRowDown34_0(src_ptr, 0, dst_ptr, dst_width);
- }
-}
-
-
-// Scale plane, 3/8
-// This is an optimized version for scaling down a plane to 3/8
-// of its original size.
-//
-// Uses box filter arranges like this
-// aaabbbcc -> abc
-// aaabbbcc def
-// aaabbbcc ghi
-// dddeeeff
-// dddeeeff
-// dddeeeff
-// ggghhhii
-// ggghhhii
-// Boxes are 3x3, 2x3, 3x2 and 2x2
-
-static void ScalePlaneDown38(int src_width, int src_height,
- int dst_width, int dst_height,
- int src_stride, int dst_stride,
- const uint8* src_ptr, uint8* dst_ptr,
- enum FilterMode filtering) {
- int y;
- void (*ScaleRowDown38_3)(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
- void (*ScaleRowDown38_2)(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width);
- const int filter_stride = (filtering == kFilterLinear) ? 0 : src_stride;
- assert(dst_width % 3 == 0);
- if (!filtering) {
- ScaleRowDown38_3 = ScaleRowDown38_C;
- ScaleRowDown38_2 = ScaleRowDown38_C;
- } else {
- ScaleRowDown38_3 = ScaleRowDown38_3_Box_C;
- ScaleRowDown38_2 = ScaleRowDown38_2_Box_C;
- }
-#if defined(HAS_SCALEROWDOWN38_NEON)
- if (TestCpuFlag(kCpuHasNEON) && (dst_width % 12 == 0)) {
- if (!filtering) {
- ScaleRowDown38_3 = ScaleRowDown38_NEON;
- ScaleRowDown38_2 = ScaleRowDown38_NEON;
- } else {
- ScaleRowDown38_3 = ScaleRowDown38_3_Box_NEON;
- ScaleRowDown38_2 = ScaleRowDown38_2_Box_NEON;
- }
- }
-#elif defined(HAS_SCALEROWDOWN38_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && (dst_width % 24 == 0) &&
- IS_ALIGNED(src_ptr, 16) && IS_ALIGNED(src_stride, 16)) {
- if (!filtering) {
- ScaleRowDown38_3 = ScaleRowDown38_SSSE3;
- ScaleRowDown38_2 = ScaleRowDown38_SSSE3;
- } else {
- ScaleRowDown38_3 = ScaleRowDown38_3_Box_SSSE3;
- ScaleRowDown38_2 = ScaleRowDown38_2_Box_SSSE3;
- }
- }
-#elif defined(HAS_SCALEROWDOWN38_MIPS_DSPR2)
- if (TestCpuFlag(kCpuHasMIPS_DSPR2) && (dst_width % 12 == 0) &&
- IS_ALIGNED(src_ptr, 4) && IS_ALIGNED(src_stride, 4) &&
- IS_ALIGNED(dst_ptr, 4) && IS_ALIGNED(dst_stride, 4)) {
- if (!filtering) {
- ScaleRowDown38_3 = ScaleRowDown38_MIPS_DSPR2;
- ScaleRowDown38_2 = ScaleRowDown38_MIPS_DSPR2;
- } else {
- ScaleRowDown38_3 = ScaleRowDown38_3_Box_MIPS_DSPR2;
- ScaleRowDown38_2 = ScaleRowDown38_2_Box_MIPS_DSPR2;
- }
- }
-#endif
-
- for (y = 0; y < dst_height - 2; y += 3) {
- ScaleRowDown38_3(src_ptr, filter_stride, dst_ptr, dst_width);
- src_ptr += src_stride * 3;
- dst_ptr += dst_stride;
- ScaleRowDown38_3(src_ptr, filter_stride, dst_ptr, dst_width);
- src_ptr += src_stride * 3;
- dst_ptr += dst_stride;
- ScaleRowDown38_2(src_ptr, filter_stride, dst_ptr, dst_width);
- src_ptr += src_stride * 2;
- dst_ptr += dst_stride;
- }
-
- // Remainder 1 or 2 rows with last row vertically unfiltered
- if ((dst_height % 3) == 2) {
- ScaleRowDown38_3(src_ptr, filter_stride, dst_ptr, dst_width);
- src_ptr += src_stride * 3;
- dst_ptr += dst_stride;
- ScaleRowDown38_3(src_ptr, 0, dst_ptr, dst_width);
- } else if ((dst_height % 3) == 1) {
- ScaleRowDown38_3(src_ptr, 0, dst_ptr, dst_width);
- }
-}
-
-static __inline uint32 SumBox(int iboxwidth, int iboxheight,
- ptrdiff_t src_stride, const uint8* src_ptr) {
- uint32 sum = 0u;
- int y;
- assert(iboxwidth > 0);
- assert(iboxheight > 0);
- for (y = 0; y < iboxheight; ++y) {
- int x;
- for (x = 0; x < iboxwidth; ++x) {
- sum += src_ptr[x];
- }
- src_ptr += src_stride;
- }
- return sum;
-}
-
-static void ScalePlaneBoxRow_C(int dst_width, int boxheight,
- int x, int dx, ptrdiff_t src_stride,
- const uint8* src_ptr, uint8* dst_ptr) {
- int i;
- int boxwidth;
- for (i = 0; i < dst_width; ++i) {
- int ix = x >> 16;
- x += dx;
- boxwidth = (x >> 16) - ix;
- *dst_ptr++ = SumBox(boxwidth, boxheight, src_stride, src_ptr + ix) /
- (boxwidth * boxheight);
- }
-}
-
-static __inline uint32 SumPixels(int iboxwidth, const uint16* src_ptr) {
- uint32 sum = 0u;
- int x;
- assert(iboxwidth > 0);
- for (x = 0; x < iboxwidth; ++x) {
- sum += src_ptr[x];
- }
- return sum;
-}
-
-static void ScaleAddCols2_C(int dst_width, int boxheight, int x, int dx,
- const uint16* src_ptr, uint8* dst_ptr) {
- int i;
- int scaletbl[2];
- int minboxwidth = (dx >> 16);
- int* scaleptr = scaletbl - minboxwidth;
- int boxwidth;
- scaletbl[0] = 65536 / (minboxwidth * boxheight);
- scaletbl[1] = 65536 / ((minboxwidth + 1) * boxheight);
- for (i = 0; i < dst_width; ++i) {
- int ix = x >> 16;
- x += dx;
- boxwidth = (x >> 16) - ix;
- *dst_ptr++ = SumPixels(boxwidth, src_ptr + ix) * scaleptr[boxwidth] >> 16;
- }
-}
-
-static void ScaleAddCols1_C(int dst_width, int boxheight, int x, int dx,
- const uint16* src_ptr, uint8* dst_ptr) {
- int boxwidth = (dx >> 16);
- int scaleval = 65536 / (boxwidth * boxheight);
- int i;
- for (i = 0; i < dst_width; ++i) {
- *dst_ptr++ = SumPixels(boxwidth, src_ptr + x) * scaleval >> 16;
- x += boxwidth;
- }
-}
-
-// Scale plane down to any dimensions, with interpolation.
-// (boxfilter).
-//
-// Same method as SimpleScale, which is fixed point, outputting
-// one pixel of destination using fixed point (16.16) to step
-// through source, sampling a box of pixel with simple
-// averaging.
-static void ScalePlaneBox(int src_width, int src_height,
- int dst_width, int dst_height,
- int src_stride, int dst_stride,
- const uint8* src_ptr, uint8* dst_ptr) {
- int j;
- // Initial source x/y coordinate and step values as 16.16 fixed point.
- int x = 0;
- int y = 0;
- int dx = 0;
- int dy = 0;
- const int max_y = (src_height << 16);
- ScaleSlope(src_width, src_height, dst_width, dst_height, kFilterBox,
- &x, &y, &dx, &dy);
- src_width = Abs(src_width);
- // TODO(fbarchard): Remove this and make AddRows handle boxheight 1.
- if (!IS_ALIGNED(src_width, 16) || dst_height * 2 > src_height) {
- uint8* dst = dst_ptr;
- int j;
- for (j = 0; j < dst_height; ++j) {
- int boxheight;
- int iy = y >> 16;
- const uint8* src = src_ptr + iy * src_stride;
- y += dy;
- if (y > max_y) {
- y = max_y;
- }
- boxheight = (y >> 16) - iy;
- ScalePlaneBoxRow_C(dst_width, boxheight,
- x, dx, src_stride,
- src, dst);
- dst += dst_stride;
- }
- return;
- }
- {
- // Allocate a row buffer of uint16.
- align_buffer_64(row16, src_width * 2);
- void (*ScaleAddCols)(int dst_width, int boxheight, int x, int dx,
- const uint16* src_ptr, uint8* dst_ptr) =
- (dx & 0xffff) ? ScaleAddCols2_C: ScaleAddCols1_C;
- void (*ScaleAddRows)(const uint8* src_ptr, ptrdiff_t src_stride,
- uint16* dst_ptr, int src_width, int src_height) = ScaleAddRows_C;
-
-#if defined(HAS_SCALEADDROWS_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) &&
-#ifdef AVOID_OVERREAD
- IS_ALIGNED(src_width, 16) &&
-#endif
- IS_ALIGNED(src_ptr, 16) && IS_ALIGNED(src_stride, 16)) {
- ScaleAddRows = ScaleAddRows_SSE2;
- }
-#endif
-
- for (j = 0; j < dst_height; ++j) {
- int boxheight;
- int iy = y >> 16;
- const uint8* src = src_ptr + iy * src_stride;
- y += dy;
- if (y > (src_height << 16)) {
- y = (src_height << 16);
- }
- boxheight = (y >> 16) - iy;
- ScaleAddRows(src, src_stride, (uint16*)(row16),
- src_width, boxheight);
- ScaleAddCols(dst_width, boxheight, x, dx, (uint16*)(row16),
- dst_ptr);
- dst_ptr += dst_stride;
- }
- free_aligned_buffer_64(row16);
- }
-}
-
-// Scale plane down with bilinear interpolation.
-void ScalePlaneBilinearDown(int src_width, int src_height,
- int dst_width, int dst_height,
- int src_stride, int dst_stride,
- const uint8* src_ptr, uint8* dst_ptr,
- enum FilterMode filtering) {
- // Initial source x/y coordinate and step values as 16.16 fixed point.
- int x = 0;
- int y = 0;
- int dx = 0;
- int dy = 0;
- // TODO(fbarchard): Consider not allocating row buffer for kFilterLinear.
- // Allocate a row buffer.
- align_buffer_64(row, src_width);
-
- const int max_y = (src_height - 1) << 16;
- int j;
- void (*ScaleFilterCols)(uint8* dst_ptr, const uint8* src_ptr,
- int dst_width, int x, int dx) =
- (src_width >= 32768) ? ScaleFilterCols64_C : ScaleFilterCols_C;
- void (*InterpolateRow)(uint8* dst_ptr, const uint8* src_ptr,
- ptrdiff_t src_stride, int dst_width, int source_y_fraction) =
- InterpolateRow_C;
- ScaleSlope(src_width, src_height, dst_width, dst_height, filtering,
- &x, &y, &dx, &dy);
- src_width = Abs(src_width);
-
-#if defined(HAS_INTERPOLATEROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && src_width >= 16) {
- InterpolateRow = InterpolateRow_Any_SSE2;
- if (IS_ALIGNED(src_width, 16)) {
- InterpolateRow = InterpolateRow_Unaligned_SSE2;
- if (IS_ALIGNED(src_ptr, 16) && IS_ALIGNED(src_stride, 16)) {
- InterpolateRow = InterpolateRow_SSE2;
- }
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && src_width >= 16) {
- InterpolateRow = InterpolateRow_Any_SSSE3;
- if (IS_ALIGNED(src_width, 16)) {
- InterpolateRow = InterpolateRow_Unaligned_SSSE3;
- if (IS_ALIGNED(src_ptr, 16) && IS_ALIGNED(src_stride, 16)) {
- InterpolateRow = InterpolateRow_SSSE3;
- }
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && src_width >= 32) {
- InterpolateRow = InterpolateRow_Any_AVX2;
- if (IS_ALIGNED(src_width, 32)) {
- InterpolateRow = InterpolateRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && src_width >= 16) {
- InterpolateRow = InterpolateRow_Any_NEON;
- if (IS_ALIGNED(src_width, 16)) {
- InterpolateRow = InterpolateRow_NEON;
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROW_MIPS_DSPR2)
- if (TestCpuFlag(kCpuHasMIPS_DSPR2) && src_width >= 4) {
- InterpolateRow = InterpolateRow_Any_MIPS_DSPR2;
- if (IS_ALIGNED(src_width, 4)) {
- InterpolateRow = InterpolateRow_MIPS_DSPR2;
- }
- }
-#endif
-
-
-#if defined(HAS_SCALEFILTERCOLS_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && src_width < 32768) {
- ScaleFilterCols = ScaleFilterCols_SSSE3;
- }
-#endif
- if (y > max_y) {
- y = max_y;
- }
-
- for (j = 0; j < dst_height; ++j) {
- int yi = y >> 16;
- const uint8* src = src_ptr + yi * src_stride;
- if (filtering == kFilterLinear) {
- ScaleFilterCols(dst_ptr, src, dst_width, x, dx);
- } else {
- int yf = (y >> 8) & 255;
- InterpolateRow(row, src, src_stride, src_width, yf);
- ScaleFilterCols(dst_ptr, row, dst_width, x, dx);
- }
- dst_ptr += dst_stride;
- y += dy;
- if (y > max_y) {
- y = max_y;
- }
- }
- free_aligned_buffer_64(row);
-}
-
-// Scale up down with bilinear interpolation.
-void ScalePlaneBilinearUp(int src_width, int src_height,
- int dst_width, int dst_height,
- int src_stride, int dst_stride,
- const uint8* src_ptr, uint8* dst_ptr,
- enum FilterMode filtering) {
- int j;
- // Initial source x/y coordinate and step values as 16.16 fixed point.
- int x = 0;
- int y = 0;
- int dx = 0;
- int dy = 0;
- const int max_y = (src_height - 1) << 16;
- void (*InterpolateRow)(uint8* dst_ptr, const uint8* src_ptr,
- ptrdiff_t src_stride, int dst_width, int source_y_fraction) =
- InterpolateRow_C;
- void (*ScaleFilterCols)(uint8* dst_ptr, const uint8* src_ptr,
- int dst_width, int x, int dx) =
- filtering ? ScaleFilterCols_C : ScaleCols_C;
- ScaleSlope(src_width, src_height, dst_width, dst_height, filtering,
- &x, &y, &dx, &dy);
- src_width = Abs(src_width);
-
-#if defined(HAS_INTERPOLATEROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && dst_width >= 16) {
- InterpolateRow = InterpolateRow_Any_SSE2;
- if (IS_ALIGNED(dst_width, 16)) {
- InterpolateRow = InterpolateRow_Unaligned_SSE2;
- if (IS_ALIGNED(dst_ptr, 16) && IS_ALIGNED(dst_stride, 16)) {
- InterpolateRow = InterpolateRow_SSE2;
- }
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && dst_width >= 16) {
- InterpolateRow = InterpolateRow_Any_SSSE3;
- if (IS_ALIGNED(dst_width, 16)) {
- InterpolateRow = InterpolateRow_Unaligned_SSSE3;
- if (IS_ALIGNED(dst_ptr, 16) && IS_ALIGNED(dst_stride, 16)) {
- InterpolateRow = InterpolateRow_SSSE3;
- }
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && dst_width >= 32) {
- InterpolateRow = InterpolateRow_Any_AVX2;
- if (IS_ALIGNED(dst_width, 32)) {
- InterpolateRow = InterpolateRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && dst_width >= 16) {
- InterpolateRow = InterpolateRow_Any_NEON;
- if (IS_ALIGNED(dst_width, 16)) {
- InterpolateRow = InterpolateRow_NEON;
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROW_MIPS_DSPR2)
- if (TestCpuFlag(kCpuHasMIPS_DSPR2) && dst_width >= 4) {
- InterpolateRow = InterpolateRow_Any_MIPS_DSPR2;
- if (IS_ALIGNED(dst_width, 4)) {
- InterpolateRow = InterpolateRow_MIPS_DSPR2;
- }
- }
-#endif
-
- if (filtering && src_width >= 32768) {
- ScaleFilterCols = ScaleFilterCols64_C;
- }
-#if defined(HAS_SCALEFILTERCOLS_SSSE3)
- if (filtering && TestCpuFlag(kCpuHasSSSE3) && src_width < 32768) {
- ScaleFilterCols = ScaleFilterCols_SSSE3;
- }
-#endif
- if (!filtering && src_width * 2 == dst_width && x < 0x8000) {
- ScaleFilterCols = ScaleColsUp2_C;
-#if defined(HAS_SCALECOLS_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 8) &&
- IS_ALIGNED(src_ptr, 16) && IS_ALIGNED(src_stride, 16) &&
- IS_ALIGNED(dst_ptr, 16) && IS_ALIGNED(dst_stride, 16)) {
- ScaleFilterCols = ScaleColsUp2_SSE2;
- }
-#endif
- }
-
- if (y > max_y) {
- y = max_y;
- }
- {
- int yi = y >> 16;
- const uint8* src = src_ptr + yi * src_stride;
-
- // Allocate 2 row buffers.
- const int kRowSize = (dst_width + 15) & ~15;
- align_buffer_64(row, kRowSize * 2);
-
- uint8* rowptr = row;
- int rowstride = kRowSize;
- int lasty = yi;
-
- ScaleFilterCols(rowptr, src, dst_width, x, dx);
- if (src_height > 1) {
- src += src_stride;
- }
- ScaleFilterCols(rowptr + rowstride, src, dst_width, x, dx);
- src += src_stride;
-
- for (j = 0; j < dst_height; ++j) {
- yi = y >> 16;
- if (yi != lasty) {
- if (y > max_y) {
- y = max_y;
- yi = y >> 16;
- src = src_ptr + yi * src_stride;
- }
- if (yi != lasty) {
- ScaleFilterCols(rowptr, src, dst_width, x, dx);
- rowptr += rowstride;
- rowstride = -rowstride;
- lasty = yi;
- src += src_stride;
- }
- }
- if (filtering == kFilterLinear) {
- InterpolateRow(dst_ptr, rowptr, 0, dst_width, 0);
- } else {
- int yf = (y >> 8) & 255;
- InterpolateRow(dst_ptr, rowptr, rowstride, dst_width, yf);
- }
- dst_ptr += dst_stride;
- y += dy;
- }
- free_aligned_buffer_64(row);
- }
-}
-
-// Scale Plane to/from any dimensions, without interpolation.
-// Fixed point math is used for performance: The upper 16 bits
-// of x and dx is the integer part of the source position and
-// the lower 16 bits are the fixed decimal part.
-
-static void ScalePlaneSimple(int src_width, int src_height,
- int dst_width, int dst_height,
- int src_stride, int dst_stride,
- const uint8* src_ptr, uint8* dst_ptr) {
- int i;
- void (*ScaleCols)(uint8* dst_ptr, const uint8* src_ptr,
- int dst_width, int x, int dx) = ScaleCols_C;
- // Initial source x/y coordinate and step values as 16.16 fixed point.
- int x = 0;
- int y = 0;
- int dx = 0;
- int dy = 0;
- ScaleSlope(src_width, src_height, dst_width, dst_height, kFilterNone,
- &x, &y, &dx, &dy);
- src_width = Abs(src_width);
-
- if (src_width * 2 == dst_width && x < 0x8000) {
- ScaleCols = ScaleColsUp2_C;
-#if defined(HAS_SCALECOLS_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 8) &&
- IS_ALIGNED(src_ptr, 16) && IS_ALIGNED(src_stride, 16) &&
- IS_ALIGNED(dst_ptr, 16) && IS_ALIGNED(dst_stride, 16)) {
- ScaleCols = ScaleColsUp2_SSE2;
- }
-#endif
- }
-
- for (i = 0; i < dst_height; ++i) {
- ScaleCols(dst_ptr, src_ptr + (y >> 16) * src_stride,
- dst_width, x, dx);
- dst_ptr += dst_stride;
- y += dy;
- }
-}
-
-// Scale a plane.
-// This function dispatches to a specialized scaler based on scale factor.
-
-LIBYUV_API
-void ScalePlane(const uint8* src, int src_stride,
- int src_width, int src_height,
- uint8* dst, int dst_stride,
- int dst_width, int dst_height,
- enum FilterMode filtering) {
- // Simplify filtering when possible.
- filtering = ScaleFilterReduce(src_width, src_height,
- dst_width, dst_height,
- filtering);
-
- // Negative height means invert the image.
- if (src_height < 0) {
- src_height = -src_height;
- src = src + (src_height - 1) * src_stride;
- src_stride = -src_stride;
- }
-
- // Use specialized scales to improve performance for common resolutions.
- // For example, all the 1/2 scalings will use ScalePlaneDown2()
- if (dst_width == src_width && dst_height == src_height) {
- // Straight copy.
- CopyPlane(src, src_stride, dst, dst_stride, dst_width, dst_height);
- return;
- }
- if (dst_width == src_width) {
- int dy = FixedDiv(src_height, dst_height);
- // Arbitrary scale vertically, but unscaled vertically.
- ScalePlaneVertical(src_height,
- dst_width, dst_height,
- src_stride, dst_stride, src, dst,
- 0, 0, dy, 1, filtering);
- return;
- }
- if (dst_width <= Abs(src_width) && dst_height <= src_height) {
- // Scale down.
- if (4 * dst_width == 3 * src_width &&
- 4 * dst_height == 3 * src_height) {
- // optimized, 3/4
- ScalePlaneDown34(src_width, src_height, dst_width, dst_height,
- src_stride, dst_stride, src, dst, filtering);
- return;
- }
- if (2 * dst_width == src_width && 2 * dst_height == src_height) {
- // optimized, 1/2
- ScalePlaneDown2(src_width, src_height, dst_width, dst_height,
- src_stride, dst_stride, src, dst, filtering);
- return;
- }
- // 3/8 rounded up for odd sized chroma height.
- if (8 * dst_width == 3 * src_width &&
- dst_height == ((src_height * 3 + 7) / 8)) {
- // optimized, 3/8
- ScalePlaneDown38(src_width, src_height, dst_width, dst_height,
- src_stride, dst_stride, src, dst, filtering);
- return;
- }
- if (4 * dst_width == src_width && 4 * dst_height == src_height &&
- filtering != kFilterBilinear) {
- // optimized, 1/4
- ScalePlaneDown4(src_width, src_height, dst_width, dst_height,
- src_stride, dst_stride, src, dst, filtering);
- return;
- }
- }
- if (filtering == kFilterBox && dst_height * 2 < src_height) {
- ScalePlaneBox(src_width, src_height, dst_width, dst_height,
- src_stride, dst_stride, src, dst);
- return;
- }
- if (filtering && dst_height > src_height) {
- ScalePlaneBilinearUp(src_width, src_height, dst_width, dst_height,
- src_stride, dst_stride, src, dst, filtering);
- return;
- }
- if (filtering) {
- ScalePlaneBilinearDown(src_width, src_height, dst_width, dst_height,
- src_stride, dst_stride, src, dst, filtering);
- return;
- }
- ScalePlaneSimple(src_width, src_height, dst_width, dst_height,
- src_stride, dst_stride, src, dst);
-}
-
-// Scale an I420 image.
-// This function in turn calls a scaling function for each plane.
-
-LIBYUV_API
-int I420Scale(const uint8* src_y, int src_stride_y,
- const uint8* src_u, int src_stride_u,
- const uint8* src_v, int src_stride_v,
- int src_width, int src_height,
- uint8* dst_y, int dst_stride_y,
- uint8* dst_u, int dst_stride_u,
- uint8* dst_v, int dst_stride_v,
- int dst_width, int dst_height,
- enum FilterMode filtering) {
- int src_halfwidth = SUBSAMPLE(src_width, 1, 1);
- int src_halfheight = SUBSAMPLE(src_height, 1, 1);
- int dst_halfwidth = SUBSAMPLE(dst_width, 1, 1);
- int dst_halfheight = SUBSAMPLE(dst_height, 1, 1);
- if (!src_y || !src_u || !src_v || src_width == 0 || src_height == 0 ||
- !dst_y || !dst_u || !dst_v || dst_width <= 0 || dst_height <= 0) {
- return -1;
- }
-
- ScalePlane(src_y, src_stride_y, src_width, src_height,
- dst_y, dst_stride_y, dst_width, dst_height,
- filtering);
- ScalePlane(src_u, src_stride_u, src_halfwidth, src_halfheight,
- dst_u, dst_stride_u, dst_halfwidth, dst_halfheight,
- filtering);
- ScalePlane(src_v, src_stride_v, src_halfwidth, src_halfheight,
- dst_v, dst_stride_v, dst_halfwidth, dst_halfheight,
- filtering);
- return 0;
-}
-
-// Deprecated api
-LIBYUV_API
-int Scale(const uint8* src_y, const uint8* src_u, const uint8* src_v,
- int src_stride_y, int src_stride_u, int src_stride_v,
- int src_width, int src_height,
- uint8* dst_y, uint8* dst_u, uint8* dst_v,
- int dst_stride_y, int dst_stride_u, int dst_stride_v,
- int dst_width, int dst_height,
- LIBYUV_BOOL interpolate) {
- return I420Scale(src_y, src_stride_y,
- src_u, src_stride_u,
- src_v, src_stride_v,
- src_width, src_height,
- dst_y, dst_stride_y,
- dst_u, dst_stride_u,
- dst_v, dst_stride_v,
- dst_width, dst_height,
- interpolate ? kFilterBox : kFilterNone);
-}
-
-// Deprecated api
-LIBYUV_API
-int ScaleOffset(const uint8* src, int src_width, int src_height,
- uint8* dst, int dst_width, int dst_height, int dst_yoffset,
- LIBYUV_BOOL interpolate) {
- // Chroma requires offset to multiple of 2.
- int dst_yoffset_even = dst_yoffset & ~1;
- int src_halfwidth = SUBSAMPLE(src_width, 1, 1);
- int src_halfheight = SUBSAMPLE(src_height, 1, 1);
- int dst_halfwidth = SUBSAMPLE(dst_width, 1, 1);
- int dst_halfheight = SUBSAMPLE(dst_height, 1, 1);
- int aheight = dst_height - dst_yoffset_even * 2; // actual output height
- const uint8* src_y = src;
- const uint8* src_u = src + src_width * src_height;
- const uint8* src_v = src + src_width * src_height +
- src_halfwidth * src_halfheight;
- uint8* dst_y = dst + dst_yoffset_even * dst_width;
- uint8* dst_u = dst + dst_width * dst_height +
- (dst_yoffset_even >> 1) * dst_halfwidth;
- uint8* dst_v = dst + dst_width * dst_height + dst_halfwidth * dst_halfheight +
- (dst_yoffset_even >> 1) * dst_halfwidth;
- if (!src || src_width <= 0 || src_height <= 0 ||
- !dst || dst_width <= 0 || dst_height <= 0 || dst_yoffset_even < 0 ||
- dst_yoffset_even >= dst_height) {
- return -1;
- }
- return I420Scale(src_y, src_width,
- src_u, src_halfwidth,
- src_v, src_halfwidth,
- src_width, src_height,
- dst_y, dst_width,
- dst_u, dst_halfwidth,
- dst_v, dst_halfwidth,
- dst_width, aheight,
- interpolate ? kFilterBox : kFilterNone);
-}
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/scale_argb.cc b/drivers/theoraplayer/src/YUV/libyuv/src/scale_argb.cc
deleted file mode 100755
index e339cd7c79..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/scale_argb.cc
+++ /dev/null
@@ -1,809 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/scale.h"
-
-#include <assert.h>
-#include <string.h>
-
-#include "libyuv/cpu_id.h"
-#include "libyuv/planar_functions.h" // For CopyARGB
-#include "libyuv/row.h"
-#include "libyuv/scale_row.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-static __inline int Abs(int v) {
- return v >= 0 ? v : -v;
-}
-
-// ScaleARGB ARGB, 1/2
-// This is an optimized version for scaling down a ARGB to 1/2 of
-// its original size.
-static void ScaleARGBDown2(int src_width, int src_height,
- int dst_width, int dst_height,
- int src_stride, int dst_stride,
- const uint8* src_argb, uint8* dst_argb,
- int x, int dx, int y, int dy,
- enum FilterMode filtering) {
- int j;
- int row_stride = src_stride * (dy >> 16);
- void (*ScaleARGBRowDown2)(const uint8* src_argb, ptrdiff_t src_stride,
- uint8* dst_argb, int dst_width) =
- filtering == kFilterNone ? ScaleARGBRowDown2_C :
- (filtering == kFilterLinear ? ScaleARGBRowDown2Linear_C :
- ScaleARGBRowDown2Box_C);
- assert(dx == 65536 * 2); // Test scale factor of 2.
- assert((dy & 0x1ffff) == 0); // Test vertical scale is multiple of 2.
- // Advance to odd row, even column.
- if (filtering == kFilterBilinear) {
- src_argb += (y >> 16) * src_stride + (x >> 16) * 4;
- } else {
- src_argb += (y >> 16) * src_stride + ((x >> 16) - 1) * 4;
- }
-
-#if defined(HAS_SCALEARGBROWDOWN2_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 4) &&
- IS_ALIGNED(src_argb, 16) && IS_ALIGNED(row_stride, 16) &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride, 16)) {
- ScaleARGBRowDown2 = filtering == kFilterNone ? ScaleARGBRowDown2_SSE2 :
- (filtering == kFilterLinear ? ScaleARGBRowDown2Linear_SSE2 :
- ScaleARGBRowDown2Box_SSE2);
- }
-#elif defined(HAS_SCALEARGBROWDOWN2_NEON)
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(dst_width, 8) &&
- IS_ALIGNED(src_argb, 4) && IS_ALIGNED(row_stride, 4)) {
- ScaleARGBRowDown2 = filtering ? ScaleARGBRowDown2Box_NEON :
- ScaleARGBRowDown2_NEON;
- }
-#endif
-
- if (filtering == kFilterLinear) {
- src_stride = 0;
- }
- for (j = 0; j < dst_height; ++j) {
- ScaleARGBRowDown2(src_argb, src_stride, dst_argb, dst_width);
- src_argb += row_stride;
- dst_argb += dst_stride;
- }
-}
-
-// ScaleARGB ARGB, 1/4
-// This is an optimized version for scaling down a ARGB to 1/4 of
-// its original size.
-static void ScaleARGBDown4Box(int src_width, int src_height,
- int dst_width, int dst_height,
- int src_stride, int dst_stride,
- const uint8* src_argb, uint8* dst_argb,
- int x, int dx, int y, int dy) {
- int j;
- // Allocate 2 rows of ARGB.
- const int kRowSize = (dst_width * 2 * 4 + 15) & ~15;
- align_buffer_64(row, kRowSize * 2);
- int row_stride = src_stride * (dy >> 16);
- void (*ScaleARGBRowDown2)(const uint8* src_argb, ptrdiff_t src_stride,
- uint8* dst_argb, int dst_width) = ScaleARGBRowDown2Box_C;
- // Advance to odd row, even column.
- src_argb += (y >> 16) * src_stride + (x >> 16) * 4;
- assert(dx == 65536 * 4); // Test scale factor of 4.
- assert((dy & 0x3ffff) == 0); // Test vertical scale is multiple of 4.
-#if defined(HAS_SCALEARGBROWDOWN2_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 4) &&
- IS_ALIGNED(src_argb, 16) && IS_ALIGNED(row_stride, 16) &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride, 16)) {
- ScaleARGBRowDown2 = ScaleARGBRowDown2Box_SSE2;
- }
-#elif defined(HAS_SCALEARGBROWDOWN2_NEON)
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(dst_width, 8) &&
- IS_ALIGNED(src_argb, 4) && IS_ALIGNED(row_stride, 4)) {
- ScaleARGBRowDown2 = ScaleARGBRowDown2Box_NEON;
- }
-#endif
- for (j = 0; j < dst_height; ++j) {
- ScaleARGBRowDown2(src_argb, src_stride, row, dst_width * 2);
- ScaleARGBRowDown2(src_argb + src_stride * 2, src_stride,
- row + kRowSize, dst_width * 2);
- ScaleARGBRowDown2(row, kRowSize, dst_argb, dst_width);
- src_argb += row_stride;
- dst_argb += dst_stride;
- }
- free_aligned_buffer_64(row);
-}
-
-// ScaleARGB ARGB Even
-// This is an optimized version for scaling down a ARGB to even
-// multiple of its original size.
-static void ScaleARGBDownEven(int src_width, int src_height,
- int dst_width, int dst_height,
- int src_stride, int dst_stride,
- const uint8* src_argb, uint8* dst_argb,
- int x, int dx, int y, int dy,
- enum FilterMode filtering) {
- int j;
- int col_step = dx >> 16;
- int row_stride = (dy >> 16) * src_stride;
- void (*ScaleARGBRowDownEven)(const uint8* src_argb, ptrdiff_t src_stride,
- int src_step, uint8* dst_argb, int dst_width) =
- filtering ? ScaleARGBRowDownEvenBox_C : ScaleARGBRowDownEven_C;
- assert(IS_ALIGNED(src_width, 2));
- assert(IS_ALIGNED(src_height, 2));
- src_argb += (y >> 16) * src_stride + (x >> 16) * 4;
-#if defined(HAS_SCALEARGBROWDOWNEVEN_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 4) &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride, 16)) {
- ScaleARGBRowDownEven = filtering ? ScaleARGBRowDownEvenBox_SSE2 :
- ScaleARGBRowDownEven_SSE2;
- }
-#elif defined(HAS_SCALEARGBROWDOWNEVEN_NEON)
- if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(dst_width, 4) &&
- IS_ALIGNED(src_argb, 4)) {
- ScaleARGBRowDownEven = filtering ? ScaleARGBRowDownEvenBox_NEON :
- ScaleARGBRowDownEven_NEON;
- }
-#endif
-
- if (filtering == kFilterLinear) {
- src_stride = 0;
- }
- for (j = 0; j < dst_height; ++j) {
- ScaleARGBRowDownEven(src_argb, src_stride, col_step, dst_argb, dst_width);
- src_argb += row_stride;
- dst_argb += dst_stride;
- }
-}
-
-// Scale ARGB down with bilinear interpolation.
-static void ScaleARGBBilinearDown(int src_width, int src_height,
- int dst_width, int dst_height,
- int src_stride, int dst_stride,
- const uint8* src_argb, uint8* dst_argb,
- int x, int dx, int y, int dy,
- enum FilterMode filtering) {
- int j;
- void (*InterpolateRow)(uint8* dst_argb, const uint8* src_argb,
- ptrdiff_t src_stride, int dst_width, int source_y_fraction) =
- InterpolateRow_C;
- void (*ScaleARGBFilterCols)(uint8* dst_argb, const uint8* src_argb,
- int dst_width, int x, int dx) =
- (src_width >= 32768) ? ScaleARGBFilterCols64_C : ScaleARGBFilterCols_C;
- int64 xlast = x + (int64)(dst_width - 1) * dx;
- int64 xl = (dx >= 0) ? x : xlast;
- int64 xr = (dx >= 0) ? xlast : x;
- int clip_src_width;
- xl = (xl >> 16) & ~3; // Left edge aligned.
- xr = (xr >> 16) + 1; // Right most pixel used. Bilinear uses 2 pixels.
- xr = (xr + 1 + 3) & ~3; // 1 beyond 4 pixel aligned right most pixel.
- if (xr > src_width) {
- xr = src_width;
- }
- clip_src_width = (int)(xr - xl) * 4; // Width aligned to 4.
- src_argb += xl * 4;
- x -= (int)(xl << 16);
-#if defined(HAS_INTERPOLATEROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && clip_src_width >= 16) {
- InterpolateRow = InterpolateRow_Any_SSE2;
- if (IS_ALIGNED(clip_src_width, 16)) {
- InterpolateRow = InterpolateRow_Unaligned_SSE2;
- if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride, 16)) {
- InterpolateRow = InterpolateRow_SSE2;
- }
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && clip_src_width >= 16) {
- InterpolateRow = InterpolateRow_Any_SSSE3;
- if (IS_ALIGNED(clip_src_width, 16)) {
- InterpolateRow = InterpolateRow_Unaligned_SSSE3;
- if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride, 16)) {
- InterpolateRow = InterpolateRow_SSSE3;
- }
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && clip_src_width >= 32) {
- InterpolateRow = InterpolateRow_Any_AVX2;
- if (IS_ALIGNED(clip_src_width, 32)) {
- InterpolateRow = InterpolateRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && clip_src_width >= 16) {
- InterpolateRow = InterpolateRow_Any_NEON;
- if (IS_ALIGNED(clip_src_width, 16)) {
- InterpolateRow = InterpolateRow_NEON;
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROWS_MIPS_DSPR2)
- if (TestCpuFlag(kCpuHasMIPS_DSPR2) && clip_src_width >= 4 &&
- IS_ALIGNED(src_argb, 4) && IS_ALIGNED(src_stride, 4)) {
- InterpolateRow = InterpolateRow_Any_MIPS_DSPR2;
- if (IS_ALIGNED(clip_src_width, 4)) {
- InterpolateRow = InterpolateRow_MIPS_DSPR2;
- }
- }
-#endif
-#if defined(HAS_SCALEARGBFILTERCOLS_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && src_width < 32768) {
- ScaleARGBFilterCols = ScaleARGBFilterCols_SSSE3;
- }
-#endif
- // TODO(fbarchard): Consider not allocating row buffer for kFilterLinear.
- // Allocate a row of ARGB.
- {
- align_buffer_64(row, clip_src_width * 4);
-
- const int max_y = (src_height - 1) << 16;
- if (y > max_y) {
- y = max_y;
- }
- for (j = 0; j < dst_height; ++j) {
- int yi = y >> 16;
- const uint8* src = src_argb + yi * src_stride;
- if (filtering == kFilterLinear) {
- ScaleARGBFilterCols(dst_argb, src, dst_width, x, dx);
- } else {
- int yf = (y >> 8) & 255;
- InterpolateRow(row, src, src_stride, clip_src_width, yf);
- ScaleARGBFilterCols(dst_argb, row, dst_width, x, dx);
- }
- dst_argb += dst_stride;
- y += dy;
- if (y > max_y) {
- y = max_y;
- }
- }
- free_aligned_buffer_64(row);
- }
-}
-
-// Scale ARGB up with bilinear interpolation.
-static void ScaleARGBBilinearUp(int src_width, int src_height,
- int dst_width, int dst_height,
- int src_stride, int dst_stride,
- const uint8* src_argb, uint8* dst_argb,
- int x, int dx, int y, int dy,
- enum FilterMode filtering) {
- int j;
- void (*InterpolateRow)(uint8* dst_argb, const uint8* src_argb,
- ptrdiff_t src_stride, int dst_width, int source_y_fraction) =
- InterpolateRow_C;
- void (*ScaleARGBFilterCols)(uint8* dst_argb, const uint8* src_argb,
- int dst_width, int x, int dx) =
- filtering ? ScaleARGBFilterCols_C : ScaleARGBCols_C;
- const int max_y = (src_height - 1) << 16;
-#if defined(HAS_INTERPOLATEROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && dst_width >= 4) {
- InterpolateRow = InterpolateRow_Any_SSE2;
- if (IS_ALIGNED(dst_width, 4)) {
- InterpolateRow = InterpolateRow_Unaligned_SSE2;
- if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride, 16)) {
- InterpolateRow = InterpolateRow_SSE2;
- }
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && dst_width >= 4) {
- InterpolateRow = InterpolateRow_Any_SSSE3;
- if (IS_ALIGNED(dst_width, 4)) {
- InterpolateRow = InterpolateRow_Unaligned_SSSE3;
- if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride, 16)) {
- InterpolateRow = InterpolateRow_SSSE3;
- }
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && dst_width >= 8) {
- InterpolateRow = InterpolateRow_Any_AVX2;
- if (IS_ALIGNED(dst_width, 8)) {
- InterpolateRow = InterpolateRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && dst_width >= 4) {
- InterpolateRow = InterpolateRow_Any_NEON;
- if (IS_ALIGNED(dst_width, 4)) {
- InterpolateRow = InterpolateRow_NEON;
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROWS_MIPS_DSPR2)
- if (TestCpuFlag(kCpuHasMIPS_DSPR2) && dst_width >= 1 &&
- IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride, 4)) {
- InterpolateRow = InterpolateRow_MIPS_DSPR2;
- }
-#endif
- if (src_width >= 32768) {
- ScaleARGBFilterCols = filtering ?
- ScaleARGBFilterCols64_C : ScaleARGBCols64_C;
- }
-#if defined(HAS_SCALEARGBFILTERCOLS_SSSE3)
- if (filtering && TestCpuFlag(kCpuHasSSSE3) && src_width < 32768) {
- ScaleARGBFilterCols = ScaleARGBFilterCols_SSSE3;
- }
-#endif
-#if defined(HAS_SCALEARGBCOLS_SSE2)
- if (!filtering && TestCpuFlag(kCpuHasSSE2) && src_width < 32768) {
- ScaleARGBFilterCols = ScaleARGBCols_SSE2;
- }
-#endif
- if (!filtering && src_width * 2 == dst_width && x < 0x8000) {
- ScaleARGBFilterCols = ScaleARGBColsUp2_C;
-#if defined(HAS_SCALEARGBCOLSUP2_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 8) &&
- IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride, 16) &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride, 16)) {
- ScaleARGBFilterCols = ScaleARGBColsUp2_SSE2;
- }
-#endif
- }
-
- if (y > max_y) {
- y = max_y;
- }
-
- {
- int yi = y >> 16;
- const uint8* src = src_argb + yi * src_stride;
-
- // Allocate 2 rows of ARGB.
- const int kRowSize = (dst_width * 4 + 15) & ~15;
- align_buffer_64(row, kRowSize * 2);
-
- uint8* rowptr = row;
- int rowstride = kRowSize;
- int lasty = yi;
-
- ScaleARGBFilterCols(rowptr, src, dst_width, x, dx);
- if (src_height > 1) {
- src += src_stride;
- }
- ScaleARGBFilterCols(rowptr + rowstride, src, dst_width, x, dx);
- src += src_stride;
-
- for (j = 0; j < dst_height; ++j) {
- yi = y >> 16;
- if (yi != lasty) {
- if (y > max_y) {
- y = max_y;
- yi = y >> 16;
- src = src_argb + yi * src_stride;
- }
- if (yi != lasty) {
- ScaleARGBFilterCols(rowptr, src, dst_width, x, dx);
- rowptr += rowstride;
- rowstride = -rowstride;
- lasty = yi;
- src += src_stride;
- }
- }
- if (filtering == kFilterLinear) {
- InterpolateRow(dst_argb, rowptr, 0, dst_width * 4, 0);
- } else {
- int yf = (y >> 8) & 255;
- InterpolateRow(dst_argb, rowptr, rowstride, dst_width * 4, yf);
- }
- dst_argb += dst_stride;
- y += dy;
- }
- free_aligned_buffer_64(row);
- }
-}
-
-#ifdef YUVSCALEUP
-// Scale YUV to ARGB up with bilinear interpolation.
-static void ScaleYUVToARGBBilinearUp(int src_width, int src_height,
- int dst_width, int dst_height,
- int src_stride_y,
- int src_stride_u,
- int src_stride_v,
- int dst_stride_argb,
- const uint8* src_y,
- const uint8* src_u,
- const uint8* src_v,
- uint8* dst_argb,
- int x, int dx, int y, int dy,
- enum FilterMode filtering) {
- int j;
- void (*I422ToARGBRow)(const uint8* y_buf,
- const uint8* u_buf,
- const uint8* v_buf,
- uint8* rgb_buf,
- int width) = I422ToARGBRow_C;
-#if defined(HAS_I422TOARGBROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && src_width >= 8) {
- I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
- if (IS_ALIGNED(src_width, 8)) {
- I422ToARGBRow = I422ToARGBRow_Unaligned_SSSE3;
- if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- I422ToARGBRow = I422ToARGBRow_SSSE3;
- }
- }
- }
-#endif
-#if defined(HAS_I422TOARGBROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && src_width >= 16) {
- I422ToARGBRow = I422ToARGBRow_Any_AVX2;
- if (IS_ALIGNED(src_width, 16)) {
- I422ToARGBRow = I422ToARGBRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_I422TOARGBROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && src_width >= 8) {
- I422ToARGBRow = I422ToARGBRow_Any_NEON;
- if (IS_ALIGNED(src_width, 8)) {
- I422ToARGBRow = I422ToARGBRow_NEON;
- }
- }
-#endif
-#if defined(HAS_I422TOARGBROW_MIPS_DSPR2)
- if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(src_width, 4) &&
- IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
- IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
- IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) &&
- IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) {
- I422ToARGBRow = I422ToARGBRow_MIPS_DSPR2;
- }
-#endif
-
- void (*InterpolateRow)(uint8* dst_argb, const uint8* src_argb,
- ptrdiff_t src_stride, int dst_width, int source_y_fraction) =
- InterpolateRow_C;
-#if defined(HAS_INTERPOLATEROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && dst_width >= 4) {
- InterpolateRow = InterpolateRow_Any_SSE2;
- if (IS_ALIGNED(dst_width, 4)) {
- InterpolateRow = InterpolateRow_Unaligned_SSE2;
- if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- InterpolateRow = InterpolateRow_SSE2;
- }
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && dst_width >= 4) {
- InterpolateRow = InterpolateRow_Any_SSSE3;
- if (IS_ALIGNED(dst_width, 4)) {
- InterpolateRow = InterpolateRow_Unaligned_SSSE3;
- if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
- InterpolateRow = InterpolateRow_SSSE3;
- }
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && dst_width >= 8) {
- InterpolateRow = InterpolateRow_Any_AVX2;
- if (IS_ALIGNED(dst_width, 8)) {
- InterpolateRow = InterpolateRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && dst_width >= 4) {
- InterpolateRow = InterpolateRow_Any_NEON;
- if (IS_ALIGNED(dst_width, 4)) {
- InterpolateRow = InterpolateRow_NEON;
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROWS_MIPS_DSPR2)
- if (TestCpuFlag(kCpuHasMIPS_DSPR2) && dst_width >= 1 &&
- IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) {
- InterpolateRow = InterpolateRow_MIPS_DSPR2;
- }
-#endif
-
- void (*ScaleARGBFilterCols)(uint8* dst_argb, const uint8* src_argb,
- int dst_width, int x, int dx) =
- filtering ? ScaleARGBFilterCols_C : ScaleARGBCols_C;
- if (src_width >= 32768) {
- ScaleARGBFilterCols = filtering ?
- ScaleARGBFilterCols64_C : ScaleARGBCols64_C;
- }
-#if defined(HAS_SCALEARGBFILTERCOLS_SSSE3)
- if (filtering && TestCpuFlag(kCpuHasSSSE3) && src_width < 32768) {
- ScaleARGBFilterCols = ScaleARGBFilterCols_SSSE3;
- }
-#endif
-#if defined(HAS_SCALEARGBCOLS_SSE2)
- if (!filtering && TestCpuFlag(kCpuHasSSE2) && src_width < 32768) {
- ScaleARGBFilterCols = ScaleARGBCols_SSE2;
- }
-#endif
- if (!filtering && src_width * 2 == dst_width && x < 0x8000) {
- ScaleARGBFilterCols = ScaleARGBColsUp2_C;
-#if defined(HAS_SCALEARGBCOLSUP2_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 8) &&
- IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride, 16) &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride, 16)) {
- ScaleARGBFilterCols = ScaleARGBColsUp2_SSE2;
- }
-#endif
- }
-
- const int max_y = (src_height - 1) << 16;
- if (y > max_y) {
- y = max_y;
- }
- const int kYShift = 1; // Shift Y by 1 to convert Y plane to UV coordinate.
- int yi = y >> 16;
- int uv_yi = yi >> kYShift;
- const uint8* src_row_y = src_y + yi * src_stride_y;
- const uint8* src_row_u = src_u + uv_yi * src_stride_u;
- const uint8* src_row_v = src_v + uv_yi * src_stride_v;
-
- // Allocate 2 rows of ARGB.
- const int kRowSize = (dst_width * 4 + 15) & ~15;
- align_buffer_64(row, kRowSize * 2);
-
- // Allocate 1 row of ARGB for source conversion.
- align_buffer_64(argb_row, src_width * 4);
-
- uint8* rowptr = row;
- int rowstride = kRowSize;
- int lasty = yi;
-
- // TODO(fbarchard): Convert first 2 rows of YUV to ARGB.
- ScaleARGBFilterCols(rowptr, src_row_y, dst_width, x, dx);
- if (src_height > 1) {
- src_row_y += src_stride_y;
- if (yi & 1) {
- src_row_u += src_stride_u;
- src_row_v += src_stride_v;
- }
- }
- ScaleARGBFilterCols(rowptr + rowstride, src_row_y, dst_width, x, dx);
- if (src_height > 2) {
- src_row_y += src_stride_y;
- if (!(yi & 1)) {
- src_row_u += src_stride_u;
- src_row_v += src_stride_v;
- }
- }
-
- for (j = 0; j < dst_height; ++j) {
- yi = y >> 16;
- if (yi != lasty) {
- if (y > max_y) {
- y = max_y;
- yi = y >> 16;
- uv_yi = yi >> kYShift;
- src_row_y = src_y + yi * src_stride_y;
- src_row_u = src_u + uv_yi * src_stride_u;
- src_row_v = src_v + uv_yi * src_stride_v;
- }
- if (yi != lasty) {
- // TODO(fbarchard): Convert the clipped region of row.
- I422ToARGBRow(src_row_y, src_row_u, src_row_v, argb_row, src_width);
- ScaleARGBFilterCols(rowptr, argb_row, dst_width, x, dx);
- rowptr += rowstride;
- rowstride = -rowstride;
- lasty = yi;
- src_row_y += src_stride_y;
- if (yi & 1) {
- src_row_u += src_stride_u;
- src_row_v += src_stride_v;
- }
- }
- }
- if (filtering == kFilterLinear) {
- InterpolateRow(dst_argb, rowptr, 0, dst_width * 4, 0);
- } else {
- int yf = (y >> 8) & 255;
- InterpolateRow(dst_argb, rowptr, rowstride, dst_width * 4, yf);
- }
- dst_argb += dst_stride_argb;
- y += dy;
- }
- free_aligned_buffer_64(row);
- free_aligned_buffer_64(row_argb);
-}
-#endif
-
-// Scale ARGB to/from any dimensions, without interpolation.
-// Fixed point math is used for performance: The upper 16 bits
-// of x and dx is the integer part of the source position and
-// the lower 16 bits are the fixed decimal part.
-
-static void ScaleARGBSimple(int src_width, int src_height,
- int dst_width, int dst_height,
- int src_stride, int dst_stride,
- const uint8* src_argb, uint8* dst_argb,
- int x, int dx, int y, int dy) {
- int j;
- void (*ScaleARGBCols)(uint8* dst_argb, const uint8* src_argb,
- int dst_width, int x, int dx) =
- (src_width >= 32768) ? ScaleARGBCols64_C : ScaleARGBCols_C;
-#if defined(HAS_SCALEARGBCOLS_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && src_width < 32768) {
- ScaleARGBCols = ScaleARGBCols_SSE2;
- }
-#endif
- if (src_width * 2 == dst_width && x < 0x8000) {
- ScaleARGBCols = ScaleARGBColsUp2_C;
-#if defined(HAS_SCALEARGBCOLSUP2_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 8) &&
- IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride, 16) &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride, 16)) {
- ScaleARGBCols = ScaleARGBColsUp2_SSE2;
- }
-#endif
- }
-
- for (j = 0; j < dst_height; ++j) {
- ScaleARGBCols(dst_argb, src_argb + (y >> 16) * src_stride,
- dst_width, x, dx);
- dst_argb += dst_stride;
- y += dy;
- }
-}
-
-// ScaleARGB a ARGB.
-// This function in turn calls a scaling function
-// suitable for handling the desired resolutions.
-static void ScaleARGB(const uint8* src, int src_stride,
- int src_width, int src_height,
- uint8* dst, int dst_stride,
- int dst_width, int dst_height,
- int clip_x, int clip_y, int clip_width, int clip_height,
- enum FilterMode filtering) {
- // Initial source x/y coordinate and step values as 16.16 fixed point.
- int x = 0;
- int y = 0;
- int dx = 0;
- int dy = 0;
- // ARGB does not support box filter yet, but allow the user to pass it.
- // Simplify filtering when possible.
- filtering = ScaleFilterReduce(src_width, src_height,
- dst_width, dst_height,
- filtering);
-
- // Negative src_height means invert the image.
- if (src_height < 0) {
- src_height = -src_height;
- src = src + (src_height - 1) * src_stride;
- src_stride = -src_stride;
- }
- ScaleSlope(src_width, src_height, dst_width, dst_height, filtering,
- &x, &y, &dx, &dy);
- src_width = Abs(src_width);
- if (clip_x) {
- int64 clipf = (int64)(clip_x) * dx;
- x += (clipf & 0xffff);
- src += (clipf >> 16) * 4;
- dst += clip_x * 4;
- }
- if (clip_y) {
- int64 clipf = (int64)(clip_y) * dy;
- y += (clipf & 0xffff);
- src += (clipf >> 16) * src_stride;
- dst += clip_y * dst_stride;
- }
-
- // Special case for integer step values.
- if (((dx | dy) & 0xffff) == 0) {
- if (!dx || !dy) { // 1 pixel wide and/or tall.
- filtering = kFilterNone;
- } else {
- // Optimized even scale down. ie 2, 4, 6, 8, 10x.
- if (!(dx & 0x10000) && !(dy & 0x10000)) {
- if (dx == 0x20000) {
- // Optimized 1/2 downsample.
- ScaleARGBDown2(src_width, src_height,
- clip_width, clip_height,
- src_stride, dst_stride, src, dst,
- x, dx, y, dy, filtering);
- return;
- }
- if (dx == 0x40000 && filtering == kFilterBox) {
- // Optimized 1/4 box downsample.
- ScaleARGBDown4Box(src_width, src_height,
- clip_width, clip_height,
- src_stride, dst_stride, src, dst,
- x, dx, y, dy);
- return;
- }
- ScaleARGBDownEven(src_width, src_height,
- clip_width, clip_height,
- src_stride, dst_stride, src, dst,
- x, dx, y, dy, filtering);
- return;
- }
- // Optimized odd scale down. ie 3, 5, 7, 9x.
- if ((dx & 0x10000) && (dy & 0x10000)) {
- filtering = kFilterNone;
- if (dx == 0x10000 && dy == 0x10000) {
- // Straight copy.
- ARGBCopy(src + (y >> 16) * src_stride + (x >> 16) * 4, src_stride,
- dst, dst_stride, clip_width, clip_height);
- return;
- }
- }
- }
- }
- if (dx == 0x10000 && (x & 0xffff) == 0) {
- // Arbitrary scale vertically, but unscaled vertically.
- ScalePlaneVertical(src_height,
- clip_width, clip_height,
- src_stride, dst_stride, src, dst,
- x, y, dy, 4, filtering);
- return;
- }
- if (filtering && dy < 65536) {
- ScaleARGBBilinearUp(src_width, src_height,
- clip_width, clip_height,
- src_stride, dst_stride, src, dst,
- x, dx, y, dy, filtering);
- return;
- }
- if (filtering) {
- ScaleARGBBilinearDown(src_width, src_height,
- clip_width, clip_height,
- src_stride, dst_stride, src, dst,
- x, dx, y, dy, filtering);
- return;
- }
- ScaleARGBSimple(src_width, src_height, clip_width, clip_height,
- src_stride, dst_stride, src, dst,
- x, dx, y, dy);
-}
-
-LIBYUV_API
-int ARGBScaleClip(const uint8* src_argb, int src_stride_argb,
- int src_width, int src_height,
- uint8* dst_argb, int dst_stride_argb,
- int dst_width, int dst_height,
- int clip_x, int clip_y, int clip_width, int clip_height,
- enum FilterMode filtering) {
- if (!src_argb || src_width == 0 || src_height == 0 ||
- !dst_argb || dst_width <= 0 || dst_height <= 0 ||
- clip_x < 0 || clip_y < 0 ||
- (clip_x + clip_width) > dst_width ||
- (clip_y + clip_height) > dst_height) {
- return -1;
- }
- ScaleARGB(src_argb, src_stride_argb, src_width, src_height,
- dst_argb, dst_stride_argb, dst_width, dst_height,
- clip_x, clip_y, clip_width, clip_height, filtering);
- return 0;
-}
-
-// Scale an ARGB image.
-LIBYUV_API
-int ARGBScale(const uint8* src_argb, int src_stride_argb,
- int src_width, int src_height,
- uint8* dst_argb, int dst_stride_argb,
- int dst_width, int dst_height,
- enum FilterMode filtering) {
- if (!src_argb || src_width == 0 || src_height == 0 ||
- !dst_argb || dst_width <= 0 || dst_height <= 0) {
- return -1;
- }
- ScaleARGB(src_argb, src_stride_argb, src_width, src_height,
- dst_argb, dst_stride_argb, dst_width, dst_height,
- 0, 0, dst_width, dst_height, filtering);
- return 0;
-}
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/scale_argb_neon.cc b/drivers/theoraplayer/src/YUV/libyuv/src/scale_argb_neon.cc
deleted file mode 100755
index c0b5433239..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/scale_argb_neon.cc
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright 2012 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/basic_types.h"
-#include "libyuv/row.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// This module is for GCC Neon
-#if !defined(LIBYUV_DISABLE_NEON) && defined(__ARM_NEON__)
-
-void ScaleARGBRowDown2_NEON(const uint8* src_ptr, ptrdiff_t /* src_stride */,
- uint8* dst, int dst_width) {
- asm volatile (
-#ifdef _ANDROID
- ".fpu neon\n"
-#endif
- "1: \n"
- // load even pixels into q0, odd into q1
- "vld2.32 {q0, q1}, [%0]! \n"
- "vld2.32 {q2, q3}, [%0]! \n"
- "subs %2, %2, #8 \n" // 8 processed per loop
- "vst1.8 {q1}, [%1]! \n" // store odd pixels
- "vst1.8 {q3}, [%1]! \n"
- "bgt 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(dst), // %1
- "+r"(dst_width) // %2
- :
- : "memory", "cc", "q0", "q1", "q2", "q3" // Clobber List
- );
-}
-
-void ScaleARGBRowDown2Box_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width) {
- asm volatile (
- // change the stride to row 2 pointer
- "add %1, %1, %0 \n"
- "1: \n"
- "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 ARGB pixels.
- "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 ARGB pixels.
- "subs %3, %3, #8 \n" // 8 processed per loop.
- "vpaddl.u8 q0, q0 \n" // B 16 bytes -> 8 shorts.
- "vpaddl.u8 q1, q1 \n" // G 16 bytes -> 8 shorts.
- "vpaddl.u8 q2, q2 \n" // R 16 bytes -> 8 shorts.
- "vpaddl.u8 q3, q3 \n" // A 16 bytes -> 8 shorts.
- "vld4.8 {d16, d18, d20, d22}, [%1]! \n" // load 8 more ARGB pixels.
- "vld4.8 {d17, d19, d21, d23}, [%1]! \n" // load last 8 ARGB pixels.
- "vpadal.u8 q0, q8 \n" // B 16 bytes -> 8 shorts.
- "vpadal.u8 q1, q9 \n" // G 16 bytes -> 8 shorts.
- "vpadal.u8 q2, q10 \n" // R 16 bytes -> 8 shorts.
- "vpadal.u8 q3, q11 \n" // A 16 bytes -> 8 shorts.
- "vrshrn.u16 d0, q0, #2 \n" // downshift, round and pack
- "vrshrn.u16 d1, q1, #2 \n"
- "vrshrn.u16 d2, q2, #2 \n"
- "vrshrn.u16 d3, q3, #2 \n"
- "vst4.8 {d0, d1, d2, d3}, [%2]! \n"
- "bgt 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(src_stride), // %1
- "+r"(dst), // %2
- "+r"(dst_width) // %3
- :
- : "memory", "cc", "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11"
- );
-}
-
-// Reads 4 pixels at a time.
-// Alignment requirement: src_argb 4 byte aligned.
-void ScaleARGBRowDownEven_NEON(const uint8* src_argb, ptrdiff_t, int src_stepx,
- uint8* dst_argb, int dst_width) {
- asm volatile (
- "mov r12, %3, lsl #2 \n"
- ".p2align 2 \n"
- "1: \n"
- "vld1.32 {d0[0]}, [%0], r12 \n"
- "vld1.32 {d0[1]}, [%0], r12 \n"
- "vld1.32 {d1[0]}, [%0], r12 \n"
- "vld1.32 {d1[1]}, [%0], r12 \n"
- "subs %2, %2, #4 \n" // 4 pixels per loop.
- "vst1.8 {q0}, [%1]! \n"
- "bgt 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_argb), // %1
- "+r"(dst_width) // %2
- : "r"(src_stepx) // %3
- : "memory", "cc", "r12", "q0"
- );
-}
-
-// Reads 4 pixels at a time.
-// Alignment requirement: src_argb 4 byte aligned.
-void ScaleARGBRowDownEvenBox_NEON(const uint8* src_argb, ptrdiff_t src_stride,
- int src_stepx,
- uint8* dst_argb, int dst_width) {
- asm volatile (
- "mov r12, %4, lsl #2 \n"
- "add %1, %1, %0 \n"
- ".p2align 2 \n"
- "1: \n"
- "vld1.8 {d0}, [%0], r12 \n" // Read 4 2x2 blocks -> 2x1
- "vld1.8 {d1}, [%1], r12 \n"
- "vld1.8 {d2}, [%0], r12 \n"
- "vld1.8 {d3}, [%1], r12 \n"
- "vld1.8 {d4}, [%0], r12 \n"
- "vld1.8 {d5}, [%1], r12 \n"
- "vld1.8 {d6}, [%0], r12 \n"
- "vld1.8 {d7}, [%1], r12 \n"
- "vaddl.u8 q0, d0, d1 \n"
- "vaddl.u8 q1, d2, d3 \n"
- "vaddl.u8 q2, d4, d5 \n"
- "vaddl.u8 q3, d6, d7 \n"
- "vswp.8 d1, d2 \n" // ab_cd -> ac_bd
- "vswp.8 d5, d6 \n" // ef_gh -> eg_fh
- "vadd.u16 q0, q0, q1 \n" // (a+b)_(c+d)
- "vadd.u16 q2, q2, q3 \n" // (e+f)_(g+h)
- "vrshrn.u16 d0, q0, #2 \n" // first 2 pixels.
- "vrshrn.u16 d1, q2, #2 \n" // next 2 pixels.
- "subs %3, %3, #4 \n" // 4 pixels per loop.
- "vst1.8 {q0}, [%2]! \n"
- "bgt 1b \n"
- : "+r"(src_argb), // %0
- "+r"(src_stride), // %1
- "+r"(dst_argb), // %2
- "+r"(dst_width) // %3
- : "r"(src_stepx) // %4
- : "memory", "cc", "r12", "q0", "q1", "q2", "q3"
- );
-}
-#endif // __ARM_NEON__
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/scale_common.cc b/drivers/theoraplayer/src/YUV/libyuv/src/scale_common.cc
deleted file mode 100644
index 6ed8bfaf97..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/scale_common.cc
+++ /dev/null
@@ -1,772 +0,0 @@
-/*
- * Copyright 2013 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/scale.h"
-
-#include <assert.h>
-#include <string.h>
-
-#include "libyuv/cpu_id.h"
-#include "libyuv/planar_functions.h" // For CopyARGB
-#include "libyuv/row.h"
-#include "libyuv/scale_row.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-static __inline int Abs(int v) {
- return v >= 0 ? v : -v;
-}
-
-// CPU agnostic row functions
-void ScaleRowDown2_C(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width) {
- int x;
- for (x = 0; x < dst_width - 1; x += 2) {
- dst[0] = src_ptr[1];
- dst[1] = src_ptr[3];
- dst += 2;
- src_ptr += 4;
- }
- if (dst_width & 1) {
- dst[0] = src_ptr[1];
- }
-}
-
-void ScaleRowDown2Linear_C(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width) {
- const uint8* s = src_ptr;
- int x;
- for (x = 0; x < dst_width - 1; x += 2) {
- dst[0] = (s[0] + s[1] + 1) >> 1;
- dst[1] = (s[2] + s[3] + 1) >> 1;
- dst += 2;
- s += 4;
- }
- if (dst_width & 1) {
- dst[0] = (s[0] + s[1] + 1) >> 1;
- }
-}
-
-void ScaleRowDown2Box_C(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width) {
- const uint8* s = src_ptr;
- const uint8* t = src_ptr + src_stride;
- int x;
- for (x = 0; x < dst_width - 1; x += 2) {
- dst[0] = (s[0] + s[1] + t[0] + t[1] + 2) >> 2;
- dst[1] = (s[2] + s[3] + t[2] + t[3] + 2) >> 2;
- dst += 2;
- s += 4;
- t += 4;
- }
- if (dst_width & 1) {
- dst[0] = (s[0] + s[1] + t[0] + t[1] + 2) >> 2;
- }
-}
-
-void ScaleRowDown4_C(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width) {
- int x;
- for (x = 0; x < dst_width - 1; x += 2) {
- dst[0] = src_ptr[2];
- dst[1] = src_ptr[6];
- dst += 2;
- src_ptr += 8;
- }
- if (dst_width & 1) {
- dst[0] = src_ptr[2];
- }
-}
-
-void ScaleRowDown4Box_C(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width) {
- intptr_t stride = src_stride;
- int x;
- for (x = 0; x < dst_width - 1; x += 2) {
- dst[0] = (src_ptr[0] + src_ptr[1] + src_ptr[2] + src_ptr[3] +
- src_ptr[stride + 0] + src_ptr[stride + 1] +
- src_ptr[stride + 2] + src_ptr[stride + 3] +
- src_ptr[stride * 2 + 0] + src_ptr[stride * 2 + 1] +
- src_ptr[stride * 2 + 2] + src_ptr[stride * 2 + 3] +
- src_ptr[stride * 3 + 0] + src_ptr[stride * 3 + 1] +
- src_ptr[stride * 3 + 2] + src_ptr[stride * 3 + 3] +
- 8) >> 4;
- dst[1] = (src_ptr[4] + src_ptr[5] + src_ptr[6] + src_ptr[7] +
- src_ptr[stride + 4] + src_ptr[stride + 5] +
- src_ptr[stride + 6] + src_ptr[stride + 7] +
- src_ptr[stride * 2 + 4] + src_ptr[stride * 2 + 5] +
- src_ptr[stride * 2 + 6] + src_ptr[stride * 2 + 7] +
- src_ptr[stride * 3 + 4] + src_ptr[stride * 3 + 5] +
- src_ptr[stride * 3 + 6] + src_ptr[stride * 3 + 7] +
- 8) >> 4;
- dst += 2;
- src_ptr += 8;
- }
- if (dst_width & 1) {
- dst[0] = (src_ptr[0] + src_ptr[1] + src_ptr[2] + src_ptr[3] +
- src_ptr[stride + 0] + src_ptr[stride + 1] +
- src_ptr[stride + 2] + src_ptr[stride + 3] +
- src_ptr[stride * 2 + 0] + src_ptr[stride * 2 + 1] +
- src_ptr[stride * 2 + 2] + src_ptr[stride * 2 + 3] +
- src_ptr[stride * 3 + 0] + src_ptr[stride * 3 + 1] +
- src_ptr[stride * 3 + 2] + src_ptr[stride * 3 + 3] +
- 8) >> 4;
- }
-}
-
-void ScaleRowDown34_C(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width) {
- int x;
- assert((dst_width % 3 == 0) && (dst_width > 0));
- for (x = 0; x < dst_width; x += 3) {
- dst[0] = src_ptr[0];
- dst[1] = src_ptr[1];
- dst[2] = src_ptr[3];
- dst += 3;
- src_ptr += 4;
- }
-}
-
-// Filter rows 0 and 1 together, 3 : 1
-void ScaleRowDown34_0_Box_C(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* d, int dst_width) {
- const uint8* s = src_ptr;
- const uint8* t = src_ptr + src_stride;
- int x;
- assert((dst_width % 3 == 0) && (dst_width > 0));
- for (x = 0; x < dst_width; x += 3) {
- uint8 a0 = (s[0] * 3 + s[1] * 1 + 2) >> 2;
- uint8 a1 = (s[1] * 1 + s[2] * 1 + 1) >> 1;
- uint8 a2 = (s[2] * 1 + s[3] * 3 + 2) >> 2;
- uint8 b0 = (t[0] * 3 + t[1] * 1 + 2) >> 2;
- uint8 b1 = (t[1] * 1 + t[2] * 1 + 1) >> 1;
- uint8 b2 = (t[2] * 1 + t[3] * 3 + 2) >> 2;
- d[0] = (a0 * 3 + b0 + 2) >> 2;
- d[1] = (a1 * 3 + b1 + 2) >> 2;
- d[2] = (a2 * 3 + b2 + 2) >> 2;
- d += 3;
- s += 4;
- t += 4;
- }
-}
-
-// Filter rows 1 and 2 together, 1 : 1
-void ScaleRowDown34_1_Box_C(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* d, int dst_width) {
- const uint8* s = src_ptr;
- const uint8* t = src_ptr + src_stride;
- int x;
- assert((dst_width % 3 == 0) && (dst_width > 0));
- for (x = 0; x < dst_width; x += 3) {
- uint8 a0 = (s[0] * 3 + s[1] * 1 + 2) >> 2;
- uint8 a1 = (s[1] * 1 + s[2] * 1 + 1) >> 1;
- uint8 a2 = (s[2] * 1 + s[3] * 3 + 2) >> 2;
- uint8 b0 = (t[0] * 3 + t[1] * 1 + 2) >> 2;
- uint8 b1 = (t[1] * 1 + t[2] * 1 + 1) >> 1;
- uint8 b2 = (t[2] * 1 + t[3] * 3 + 2) >> 2;
- d[0] = (a0 + b0 + 1) >> 1;
- d[1] = (a1 + b1 + 1) >> 1;
- d[2] = (a2 + b2 + 1) >> 1;
- d += 3;
- s += 4;
- t += 4;
- }
-}
-
-// Scales a single row of pixels using point sampling.
-void ScaleCols_C(uint8* dst_ptr, const uint8* src_ptr,
- int dst_width, int x, int dx) {
- int j;
- for (j = 0; j < dst_width - 1; j += 2) {
- dst_ptr[0] = src_ptr[x >> 16];
- x += dx;
- dst_ptr[1] = src_ptr[x >> 16];
- x += dx;
- dst_ptr += 2;
- }
- if (dst_width & 1) {
- dst_ptr[0] = src_ptr[x >> 16];
- }
-}
-
-// Scales a single row of pixels up by 2x using point sampling.
-void ScaleColsUp2_C(uint8* dst_ptr, const uint8* src_ptr,
- int dst_width, int x, int dx) {
- int j;
- for (j = 0; j < dst_width - 1; j += 2) {
- dst_ptr[1] = dst_ptr[0] = src_ptr[0];
- src_ptr += 1;
- dst_ptr += 2;
- }
- if (dst_width & 1) {
- dst_ptr[0] = src_ptr[0];
- }
-}
-
-// (1-f)a + fb can be replaced with a + f(b-a)
-#define BLENDER(a, b, f) (uint8)((int)(a) + \
- ((int)(f) * ((int)(b) - (int)(a)) >> 16))
-
-void ScaleFilterCols_C(uint8* dst_ptr, const uint8* src_ptr,
- int dst_width, int x, int dx) {
- int j;
- for (j = 0; j < dst_width - 1; j += 2) {
- int xi = x >> 16;
- int a = src_ptr[xi];
- int b = src_ptr[xi + 1];
- dst_ptr[0] = BLENDER(a, b, x & 0xffff);
- x += dx;
- xi = x >> 16;
- a = src_ptr[xi];
- b = src_ptr[xi + 1];
- dst_ptr[1] = BLENDER(a, b, x & 0xffff);
- x += dx;
- dst_ptr += 2;
- }
- if (dst_width & 1) {
- int xi = x >> 16;
- int a = src_ptr[xi];
- int b = src_ptr[xi + 1];
- dst_ptr[0] = BLENDER(a, b, x & 0xffff);
- }
-}
-
-void ScaleFilterCols64_C(uint8* dst_ptr, const uint8* src_ptr,
- int dst_width, int x32, int dx) {
- int64 x = (int64)(x32);
- int j;
- for (j = 0; j < dst_width - 1; j += 2) {
- int64 xi = x >> 16;
- int a = src_ptr[xi];
- int b = src_ptr[xi + 1];
- dst_ptr[0] = BLENDER(a, b, x & 0xffff);
- x += dx;
- xi = x >> 16;
- a = src_ptr[xi];
- b = src_ptr[xi + 1];
- dst_ptr[1] = BLENDER(a, b, x & 0xffff);
- x += dx;
- dst_ptr += 2;
- }
- if (dst_width & 1) {
- int64 xi = x >> 16;
- int a = src_ptr[xi];
- int b = src_ptr[xi + 1];
- dst_ptr[0] = BLENDER(a, b, x & 0xffff);
- }
-}
-#undef BLENDER
-
-void ScaleRowDown38_C(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width) {
- int x;
- assert(dst_width % 3 == 0);
- for (x = 0; x < dst_width; x += 3) {
- dst[0] = src_ptr[0];
- dst[1] = src_ptr[3];
- dst[2] = src_ptr[6];
- dst += 3;
- src_ptr += 8;
- }
-}
-
-// 8x3 -> 3x1
-void ScaleRowDown38_3_Box_C(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- intptr_t stride = src_stride;
- int i;
- assert((dst_width % 3 == 0) && (dst_width > 0));
- for (i = 0; i < dst_width; i += 3) {
- dst_ptr[0] = (src_ptr[0] + src_ptr[1] + src_ptr[2] +
- src_ptr[stride + 0] + src_ptr[stride + 1] +
- src_ptr[stride + 2] + src_ptr[stride * 2 + 0] +
- src_ptr[stride * 2 + 1] + src_ptr[stride * 2 + 2]) *
- (65536 / 9) >> 16;
- dst_ptr[1] = (src_ptr[3] + src_ptr[4] + src_ptr[5] +
- src_ptr[stride + 3] + src_ptr[stride + 4] +
- src_ptr[stride + 5] + src_ptr[stride * 2 + 3] +
- src_ptr[stride * 2 + 4] + src_ptr[stride * 2 + 5]) *
- (65536 / 9) >> 16;
- dst_ptr[2] = (src_ptr[6] + src_ptr[7] +
- src_ptr[stride + 6] + src_ptr[stride + 7] +
- src_ptr[stride * 2 + 6] + src_ptr[stride * 2 + 7]) *
- (65536 / 6) >> 16;
- src_ptr += 8;
- dst_ptr += 3;
- }
-}
-
-// 8x2 -> 3x1
-void ScaleRowDown38_2_Box_C(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- intptr_t stride = src_stride;
- int i;
- assert((dst_width % 3 == 0) && (dst_width > 0));
- for (i = 0; i < dst_width; i += 3) {
- dst_ptr[0] = (src_ptr[0] + src_ptr[1] + src_ptr[2] +
- src_ptr[stride + 0] + src_ptr[stride + 1] +
- src_ptr[stride + 2]) * (65536 / 6) >> 16;
- dst_ptr[1] = (src_ptr[3] + src_ptr[4] + src_ptr[5] +
- src_ptr[stride + 3] + src_ptr[stride + 4] +
- src_ptr[stride + 5]) * (65536 / 6) >> 16;
- dst_ptr[2] = (src_ptr[6] + src_ptr[7] +
- src_ptr[stride + 6] + src_ptr[stride + 7]) *
- (65536 / 4) >> 16;
- src_ptr += 8;
- dst_ptr += 3;
- }
-}
-
-void ScaleAddRows_C(const uint8* src_ptr, ptrdiff_t src_stride,
- uint16* dst_ptr, int src_width, int src_height) {
- int x;
- assert(src_width > 0);
- assert(src_height > 0);
- for (x = 0; x < src_width; ++x) {
- const uint8* s = src_ptr + x;
- unsigned int sum = 0u;
- int y;
- for (y = 0; y < src_height; ++y) {
- sum += s[0];
- s += src_stride;
- }
- // TODO(fbarchard): Consider limitting height to 256 to avoid overflow.
- dst_ptr[x] = sum < 65535u ? sum : 65535u;
- }
-}
-
-void ScaleARGBRowDown2_C(const uint8* src_argb,
- ptrdiff_t src_stride,
- uint8* dst_argb, int dst_width) {
- const uint32* src = (const uint32*)(src_argb);
- uint32* dst = (uint32*)(dst_argb);
-
- int x;
- for (x = 0; x < dst_width - 1; x += 2) {
- dst[0] = src[1];
- dst[1] = src[3];
- src += 4;
- dst += 2;
- }
- if (dst_width & 1) {
- dst[0] = src[1];
- }
-}
-
-void ScaleARGBRowDown2Linear_C(const uint8* src_argb,
- ptrdiff_t src_stride,
- uint8* dst_argb, int dst_width) {
- int x;
- for (x = 0; x < dst_width; ++x) {
- dst_argb[0] = (src_argb[0] + src_argb[4] + 1) >> 1;
- dst_argb[1] = (src_argb[1] + src_argb[5] + 1) >> 1;
- dst_argb[2] = (src_argb[2] + src_argb[6] + 1) >> 1;
- dst_argb[3] = (src_argb[3] + src_argb[7] + 1) >> 1;
- src_argb += 8;
- dst_argb += 4;
- }
-}
-
-void ScaleARGBRowDown2Box_C(const uint8* src_argb, ptrdiff_t src_stride,
- uint8* dst_argb, int dst_width) {
- int x;
- for (x = 0; x < dst_width; ++x) {
- dst_argb[0] = (src_argb[0] + src_argb[4] +
- src_argb[src_stride] + src_argb[src_stride + 4] + 2) >> 2;
- dst_argb[1] = (src_argb[1] + src_argb[5] +
- src_argb[src_stride + 1] + src_argb[src_stride + 5] + 2) >> 2;
- dst_argb[2] = (src_argb[2] + src_argb[6] +
- src_argb[src_stride + 2] + src_argb[src_stride + 6] + 2) >> 2;
- dst_argb[3] = (src_argb[3] + src_argb[7] +
- src_argb[src_stride + 3] + src_argb[src_stride + 7] + 2) >> 2;
- src_argb += 8;
- dst_argb += 4;
- }
-}
-
-void ScaleARGBRowDownEven_C(const uint8* src_argb, ptrdiff_t src_stride,
- int src_stepx,
- uint8* dst_argb, int dst_width) {
- const uint32* src = (const uint32*)(src_argb);
- uint32* dst = (uint32*)(dst_argb);
-
- int x;
- for (x = 0; x < dst_width - 1; x += 2) {
- dst[0] = src[0];
- dst[1] = src[src_stepx];
- src += src_stepx * 2;
- dst += 2;
- }
- if (dst_width & 1) {
- dst[0] = src[0];
- }
-}
-
-void ScaleARGBRowDownEvenBox_C(const uint8* src_argb,
- ptrdiff_t src_stride,
- int src_stepx,
- uint8* dst_argb, int dst_width) {
- int x;
- for (x = 0; x < dst_width; ++x) {
- dst_argb[0] = (src_argb[0] + src_argb[4] +
- src_argb[src_stride] + src_argb[src_stride + 4] + 2) >> 2;
- dst_argb[1] = (src_argb[1] + src_argb[5] +
- src_argb[src_stride + 1] + src_argb[src_stride + 5] + 2) >> 2;
- dst_argb[2] = (src_argb[2] + src_argb[6] +
- src_argb[src_stride + 2] + src_argb[src_stride + 6] + 2) >> 2;
- dst_argb[3] = (src_argb[3] + src_argb[7] +
- src_argb[src_stride + 3] + src_argb[src_stride + 7] + 2) >> 2;
- src_argb += src_stepx * 4;
- dst_argb += 4;
- }
-}
-
-// Scales a single row of pixels using point sampling.
-void ScaleARGBCols_C(uint8* dst_argb, const uint8* src_argb,
- int dst_width, int x, int dx) {
- const uint32* src = (const uint32*)(src_argb);
- uint32* dst = (uint32*)(dst_argb);
- int j;
- for (j = 0; j < dst_width - 1; j += 2) {
- dst[0] = src[x >> 16];
- x += dx;
- dst[1] = src[x >> 16];
- x += dx;
- dst += 2;
- }
- if (dst_width & 1) {
- dst[0] = src[x >> 16];
- }
-}
-
-void ScaleARGBCols64_C(uint8* dst_argb, const uint8* src_argb,
- int dst_width, int x32, int dx) {
- int64 x = (int64)(x32);
- const uint32* src = (const uint32*)(src_argb);
- uint32* dst = (uint32*)(dst_argb);
- int j;
- for (j = 0; j < dst_width - 1; j += 2) {
- dst[0] = src[x >> 16];
- x += dx;
- dst[1] = src[x >> 16];
- x += dx;
- dst += 2;
- }
- if (dst_width & 1) {
- dst[0] = src[x >> 16];
- }
-}
-
-// Scales a single row of pixels up by 2x using point sampling.
-void ScaleARGBColsUp2_C(uint8* dst_argb, const uint8* src_argb,
- int dst_width, int x, int dx) {
- const uint32* src = (const uint32*)(src_argb);
- uint32* dst = (uint32*)(dst_argb);
- int j;
- for (j = 0; j < dst_width - 1; j += 2) {
- dst[1] = dst[0] = src[0];
- src += 1;
- dst += 2;
- }
- if (dst_width & 1) {
- dst[0] = src[0];
- }
-}
-
-// Mimics SSSE3 blender
-#define BLENDER1(a, b, f) ((a) * (0x7f ^ f) + (b) * f) >> 7
-#define BLENDERC(a, b, f, s) (uint32)( \
- BLENDER1(((a) >> s) & 255, ((b) >> s) & 255, f) << s)
-#define BLENDER(a, b, f) \
- BLENDERC(a, b, f, 24) | BLENDERC(a, b, f, 16) | \
- BLENDERC(a, b, f, 8) | BLENDERC(a, b, f, 0)
-
-void ScaleARGBFilterCols_C(uint8* dst_argb, const uint8* src_argb,
- int dst_width, int x, int dx) {
- const uint32* src = (const uint32*)(src_argb);
- uint32* dst = (uint32*)(dst_argb);
- int j;
- for (j = 0; j < dst_width - 1; j += 2) {
- int xi = x >> 16;
- int xf = (x >> 9) & 0x7f;
- uint32 a = src[xi];
- uint32 b = src[xi + 1];
- dst[0] = BLENDER(a, b, xf);
- x += dx;
- xi = x >> 16;
- xf = (x >> 9) & 0x7f;
- a = src[xi];
- b = src[xi + 1];
- dst[1] = BLENDER(a, b, xf);
- x += dx;
- dst += 2;
- }
- if (dst_width & 1) {
- int xi = x >> 16;
- int xf = (x >> 9) & 0x7f;
- uint32 a = src[xi];
- uint32 b = src[xi + 1];
- dst[0] = BLENDER(a, b, xf);
- }
-}
-
-void ScaleARGBFilterCols64_C(uint8* dst_argb, const uint8* src_argb,
- int dst_width, int x32, int dx) {
- int64 x = (int64)(x32);
- const uint32* src = (const uint32*)(src_argb);
- uint32* dst = (uint32*)(dst_argb);
- int j;
- for (j = 0; j < dst_width - 1; j += 2) {
- int64 xi = x >> 16;
- int xf = (x >> 9) & 0x7f;
- uint32 a = src[xi];
- uint32 b = src[xi + 1];
- dst[0] = BLENDER(a, b, xf);
- x += dx;
- xi = x >> 16;
- xf = (x >> 9) & 0x7f;
- a = src[xi];
- b = src[xi + 1];
- dst[1] = BLENDER(a, b, xf);
- x += dx;
- dst += 2;
- }
- if (dst_width & 1) {
- int64 xi = x >> 16;
- int xf = (x >> 9) & 0x7f;
- uint32 a = src[xi];
- uint32 b = src[xi + 1];
- dst[0] = BLENDER(a, b, xf);
- }
-}
-#undef BLENDER1
-#undef BLENDERC
-#undef BLENDER
-
-// Scale plane vertically with bilinear interpolation.
-void ScalePlaneVertical(int src_height,
- int dst_width, int dst_height,
- int src_stride, int dst_stride,
- const uint8* src_argb, uint8* dst_argb,
- int x, int y, int dy,
- int bpp, enum FilterMode filtering) {
- // TODO(fbarchard): Allow higher bpp.
- int dst_width_bytes = dst_width * bpp;
- void (*InterpolateRow)(uint8* dst_argb, const uint8* src_argb,
- ptrdiff_t src_stride, int dst_width, int source_y_fraction) =
- InterpolateRow_C;
- const int max_y = (src_height > 1) ? ((src_height - 1) << 16) - 1 : 0;
- int j;
- assert(bpp >= 1 && bpp <= 4);
- assert(src_height != 0);
- assert(dst_width > 0);
- assert(dst_height > 0);
- src_argb += (x >> 16) * bpp;
-#if defined(HAS_INTERPOLATEROW_SSE2)
- if (TestCpuFlag(kCpuHasSSE2) && dst_width_bytes >= 16) {
- InterpolateRow = InterpolateRow_Any_SSE2;
- if (IS_ALIGNED(dst_width_bytes, 16)) {
- InterpolateRow = InterpolateRow_Unaligned_SSE2;
- if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride, 16) &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride, 16)) {
- InterpolateRow = InterpolateRow_SSE2;
- }
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROW_SSSE3)
- if (TestCpuFlag(kCpuHasSSSE3) && dst_width_bytes >= 16) {
- InterpolateRow = InterpolateRow_Any_SSSE3;
- if (IS_ALIGNED(dst_width_bytes, 16)) {
- InterpolateRow = InterpolateRow_Unaligned_SSSE3;
- if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride, 16) &&
- IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride, 16)) {
- InterpolateRow = InterpolateRow_SSSE3;
- }
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROW_AVX2)
- if (TestCpuFlag(kCpuHasAVX2) && dst_width_bytes >= 32) {
- InterpolateRow = InterpolateRow_Any_AVX2;
- if (IS_ALIGNED(dst_width_bytes, 32)) {
- InterpolateRow = InterpolateRow_AVX2;
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROW_NEON)
- if (TestCpuFlag(kCpuHasNEON) && dst_width_bytes >= 16) {
- InterpolateRow = InterpolateRow_Any_NEON;
- if (IS_ALIGNED(dst_width_bytes, 16)) {
- InterpolateRow = InterpolateRow_NEON;
- }
- }
-#endif
-#if defined(HAS_INTERPOLATEROWS_MIPS_DSPR2)
- if (TestCpuFlag(kCpuHasMIPS_DSPR2) && dst_width_bytes >= 4 &&
- IS_ALIGNED(src_argb, 4) && IS_ALIGNED(src_stride, 4) &&
- IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride, 4)) {
- InterpolateRow = InterpolateRow_Any_MIPS_DSPR2;
- if (IS_ALIGNED(dst_width_bytes, 4)) {
- InterpolateRow = InterpolateRow_MIPS_DSPR2;
- }
- }
-#endif
- for (j = 0; j < dst_height; ++j) {
- int yi;
- int yf;
- if (y > max_y) {
- y = max_y;
- }
- yi = y >> 16;
- yf = filtering ? ((y >> 8) & 255) : 0;
- InterpolateRow(dst_argb, src_argb + yi * src_stride,
- src_stride, dst_width_bytes, yf);
- dst_argb += dst_stride;
- y += dy;
- }
-}
-
-// Simplify the filtering based on scale factors.
-enum FilterMode ScaleFilterReduce(int src_width, int src_height,
- int dst_width, int dst_height,
- enum FilterMode filtering) {
- if (src_width < 0) {
- src_width = -src_width;
- }
- if (src_height < 0) {
- src_height = -src_height;
- }
- if (filtering == kFilterBox) {
- // If scaling both axis to 0.5 or larger, switch from Box to Bilinear.
- if (dst_width * 2 >= src_width && dst_height * 2 >= src_height) {
- filtering = kFilterBilinear;
- }
- // If scaling to larger, switch from Box to Bilinear.
- if (dst_width >= src_width || dst_height >= src_height) {
- filtering = kFilterBilinear;
- }
- }
- if (filtering == kFilterBilinear) {
- if (src_height == 1) {
- filtering = kFilterLinear;
- }
- // TODO(fbarchard): Detect any odd scale factor and reduce to Linear.
- if (dst_height == src_height || dst_height * 3 == src_height) {
- filtering = kFilterLinear;
- }
- // TODO(fbarchard): Remove 1 pixel wide filter restriction, which is to
- // avoid reading 2 pixels horizontally that causes memory exception.
- if (src_width == 1) {
- filtering = kFilterNone;
- }
- }
- if (filtering == kFilterLinear) {
- if (src_width == 1) {
- filtering = kFilterNone;
- }
- // TODO(fbarchard): Detect any odd scale factor and reduce to None.
- if (dst_width == src_width || dst_width * 3 == src_width) {
- filtering = kFilterNone;
- }
- }
- return filtering;
-}
-
-// Divide num by div and return as 16.16 fixed point result.
-int FixedDiv_C(int num, int div) {
- return (int)(((int64)(num) << 16) / div);
-}
-
-// Divide num by div and return as 16.16 fixed point result.
-int FixedDiv1_C(int num, int div) {
- return (int)((((int64)(num) << 16) - 0x00010001) /
- (div - 1));
-}
-
-#define CENTERSTART(dx, s) (dx < 0) ? -((-dx >> 1) + s) : ((dx >> 1) + s)
-
-// Compute slope values for stepping.
-void ScaleSlope(int src_width, int src_height,
- int dst_width, int dst_height,
- enum FilterMode filtering,
- int* x, int* y, int* dx, int* dy) {
- assert(x != NULL);
- assert(y != NULL);
- assert(dx != NULL);
- assert(dy != NULL);
- assert(src_width != 0);
- assert(src_height != 0);
- assert(dst_width > 0);
- assert(dst_height > 0);
- // Check for 1 pixel and avoid FixedDiv overflow.
- if (dst_width == 1 && src_width >= 32768) {
- dst_width = src_width;
- }
- if (dst_height == 1 && src_height >= 32768) {
- dst_height = src_height;
- }
- if (filtering == kFilterBox) {
- // Scale step for point sampling duplicates all pixels equally.
- *dx = FixedDiv(Abs(src_width), dst_width);
- *dy = FixedDiv(src_height, dst_height);
- *x = 0;
- *y = 0;
- } else if (filtering == kFilterBilinear) {
- // Scale step for bilinear sampling renders last pixel once for upsample.
- if (dst_width <= Abs(src_width)) {
- *dx = FixedDiv(Abs(src_width), dst_width);
- *x = CENTERSTART(*dx, -32768); // Subtract 0.5 (32768) to center filter.
- } else if (dst_width > 1) {
- *dx = FixedDiv1(Abs(src_width), dst_width);
- *x = 0;
- }
- if (dst_height <= src_height) {
- *dy = FixedDiv(src_height, dst_height);
- *y = CENTERSTART(*dy, -32768); // Subtract 0.5 (32768) to center filter.
- } else if (dst_height > 1) {
- *dy = FixedDiv1(src_height, dst_height);
- *y = 0;
- }
- } else if (filtering == kFilterLinear) {
- // Scale step for bilinear sampling renders last pixel once for upsample.
- if (dst_width <= Abs(src_width)) {
- *dx = FixedDiv(Abs(src_width), dst_width);
- *x = CENTERSTART(*dx, -32768); // Subtract 0.5 (32768) to center filter.
- } else if (dst_width > 1) {
- *dx = FixedDiv1(Abs(src_width), dst_width);
- *x = 0;
- }
- *dy = FixedDiv(src_height, dst_height);
- *y = *dy >> 1;
- } else {
- // Scale step for point sampling duplicates all pixels equally.
- *dx = FixedDiv(Abs(src_width), dst_width);
- *dy = FixedDiv(src_height, dst_height);
- *x = CENTERSTART(*dx, 0);
- *y = CENTERSTART(*dy, 0);
- }
- // Negative src_width means horizontally mirror.
- if (src_width < 0) {
- *x += (dst_width - 1) * *dx;
- *dx = -*dx;
- // src_width = -src_width; // Caller must do this.
- }
-}
-#undef CENTERSTART
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/scale_mips.cc b/drivers/theoraplayer/src/YUV/libyuv/src/scale_mips.cc
deleted file mode 100755
index 4572f4504e..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/scale_mips.cc
+++ /dev/null
@@ -1,653 +0,0 @@
-/*
- * Copyright 2012 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/basic_types.h"
-#include "libyuv/row.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// This module is for GCC MIPS DSPR2
-#if !defined(LIBYUV_DISABLE_MIPS) && \
- defined(__mips_dsp) && (__mips_dsp_rev >= 2)
-
-void ScaleRowDown2_MIPS_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width) {
- __asm__ __volatile__(
- ".set push \n"
- ".set noreorder \n"
-
- "srl $t9, %[dst_width], 4 \n" // iterations -> by 16
- "beqz $t9, 2f \n"
- " nop \n"
-
- ".p2align 2 \n"
- "1: \n"
- "lw $t0, 0(%[src_ptr]) \n" // |3|2|1|0|
- "lw $t1, 4(%[src_ptr]) \n" // |7|6|5|4|
- "lw $t2, 8(%[src_ptr]) \n" // |11|10|9|8|
- "lw $t3, 12(%[src_ptr]) \n" // |15|14|13|12|
- "lw $t4, 16(%[src_ptr]) \n" // |19|18|17|16|
- "lw $t5, 20(%[src_ptr]) \n" // |23|22|21|20|
- "lw $t6, 24(%[src_ptr]) \n" // |27|26|25|24|
- "lw $t7, 28(%[src_ptr]) \n" // |31|30|29|28|
- // TODO(fbarchard): Use odd pixels instead of even.
- "precr.qb.ph $t8, $t1, $t0 \n" // |6|4|2|0|
- "precr.qb.ph $t0, $t3, $t2 \n" // |14|12|10|8|
- "precr.qb.ph $t1, $t5, $t4 \n" // |22|20|18|16|
- "precr.qb.ph $t2, $t7, $t6 \n" // |30|28|26|24|
- "addiu %[src_ptr], %[src_ptr], 32 \n"
- "addiu $t9, $t9, -1 \n"
- "sw $t8, 0(%[dst]) \n"
- "sw $t0, 4(%[dst]) \n"
- "sw $t1, 8(%[dst]) \n"
- "sw $t2, 12(%[dst]) \n"
- "bgtz $t9, 1b \n"
- " addiu %[dst], %[dst], 16 \n"
-
- "2: \n"
- "andi $t9, %[dst_width], 0xf \n" // residue
- "beqz $t9, 3f \n"
- " nop \n"
-
- "21: \n"
- "lbu $t0, 0(%[src_ptr]) \n"
- "addiu %[src_ptr], %[src_ptr], 2 \n"
- "addiu $t9, $t9, -1 \n"
- "sb $t0, 0(%[dst]) \n"
- "bgtz $t9, 21b \n"
- " addiu %[dst], %[dst], 1 \n"
-
- "3: \n"
- ".set pop \n"
- : [src_ptr] "+r" (src_ptr),
- [dst] "+r" (dst)
- : [dst_width] "r" (dst_width)
- : "t0", "t1", "t2", "t3", "t4", "t5",
- "t6", "t7", "t8", "t9"
- );
-}
-
-void ScaleRowDown2Box_MIPS_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width) {
- const uint8* t = src_ptr + src_stride;
-
- __asm__ __volatile__ (
- ".set push \n"
- ".set noreorder \n"
-
- "srl $t9, %[dst_width], 3 \n" // iterations -> step 8
- "bltz $t9, 2f \n"
- " nop \n"
-
- ".p2align 2 \n"
- "1: \n"
- "lw $t0, 0(%[src_ptr]) \n" // |3|2|1|0|
- "lw $t1, 4(%[src_ptr]) \n" // |7|6|5|4|
- "lw $t2, 8(%[src_ptr]) \n" // |11|10|9|8|
- "lw $t3, 12(%[src_ptr]) \n" // |15|14|13|12|
- "lw $t4, 0(%[t]) \n" // |19|18|17|16|
- "lw $t5, 4(%[t]) \n" // |23|22|21|20|
- "lw $t6, 8(%[t]) \n" // |27|26|25|24|
- "lw $t7, 12(%[t]) \n" // |31|30|29|28|
- "addiu $t9, $t9, -1 \n"
- "srl $t8, $t0, 16 \n" // |X|X|3|2|
- "ins $t0, $t4, 16, 16 \n" // |17|16|1|0|
- "ins $t4, $t8, 0, 16 \n" // |19|18|3|2|
- "raddu.w.qb $t0, $t0 \n" // |17+16+1+0|
- "raddu.w.qb $t4, $t4 \n" // |19+18+3+2|
- "shra_r.w $t0, $t0, 2 \n" // |t0+2|>>2
- "shra_r.w $t4, $t4, 2 \n" // |t4+2|>>2
- "srl $t8, $t1, 16 \n" // |X|X|7|6|
- "ins $t1, $t5, 16, 16 \n" // |21|20|5|4|
- "ins $t5, $t8, 0, 16 \n" // |22|23|7|6|
- "raddu.w.qb $t1, $t1 \n" // |21+20+5+4|
- "raddu.w.qb $t5, $t5 \n" // |23+22+7+6|
- "shra_r.w $t1, $t1, 2 \n" // |t1+2|>>2
- "shra_r.w $t5, $t5, 2 \n" // |t5+2|>>2
- "srl $t8, $t2, 16 \n" // |X|X|11|10|
- "ins $t2, $t6, 16, 16 \n" // |25|24|9|8|
- "ins $t6, $t8, 0, 16 \n" // |27|26|11|10|
- "raddu.w.qb $t2, $t2 \n" // |25+24+9+8|
- "raddu.w.qb $t6, $t6 \n" // |27+26+11+10|
- "shra_r.w $t2, $t2, 2 \n" // |t2+2|>>2
- "shra_r.w $t6, $t6, 2 \n" // |t5+2|>>2
- "srl $t8, $t3, 16 \n" // |X|X|15|14|
- "ins $t3, $t7, 16, 16 \n" // |29|28|13|12|
- "ins $t7, $t8, 0, 16 \n" // |31|30|15|14|
- "raddu.w.qb $t3, $t3 \n" // |29+28+13+12|
- "raddu.w.qb $t7, $t7 \n" // |31+30+15+14|
- "shra_r.w $t3, $t3, 2 \n" // |t3+2|>>2
- "shra_r.w $t7, $t7, 2 \n" // |t7+2|>>2
- "addiu %[src_ptr], %[src_ptr], 16 \n"
- "addiu %[t], %[t], 16 \n"
- "sb $t0, 0(%[dst]) \n"
- "sb $t4, 1(%[dst]) \n"
- "sb $t1, 2(%[dst]) \n"
- "sb $t5, 3(%[dst]) \n"
- "sb $t2, 4(%[dst]) \n"
- "sb $t6, 5(%[dst]) \n"
- "sb $t3, 6(%[dst]) \n"
- "sb $t7, 7(%[dst]) \n"
- "bgtz $t9, 1b \n"
- " addiu %[dst], %[dst], 8 \n"
-
- "2: \n"
- "andi $t9, %[dst_width], 0x7 \n" // x = residue
- "beqz $t9, 3f \n"
- " nop \n"
-
- "21: \n"
- "lwr $t1, 0(%[src_ptr]) \n"
- "lwl $t1, 3(%[src_ptr]) \n"
- "lwr $t2, 0(%[t]) \n"
- "lwl $t2, 3(%[t]) \n"
- "srl $t8, $t1, 16 \n"
- "ins $t1, $t2, 16, 16 \n"
- "ins $t2, $t8, 0, 16 \n"
- "raddu.w.qb $t1, $t1 \n"
- "raddu.w.qb $t2, $t2 \n"
- "shra_r.w $t1, $t1, 2 \n"
- "shra_r.w $t2, $t2, 2 \n"
- "sb $t1, 0(%[dst]) \n"
- "sb $t2, 1(%[dst]) \n"
- "addiu %[src_ptr], %[src_ptr], 4 \n"
- "addiu $t9, $t9, -2 \n"
- "addiu %[t], %[t], 4 \n"
- "bgtz $t9, 21b \n"
- " addiu %[dst], %[dst], 2 \n"
-
- "3: \n"
- ".set pop \n"
-
- : [src_ptr] "+r" (src_ptr),
- [dst] "+r" (dst), [t] "+r" (t)
- : [dst_width] "r" (dst_width)
- : "t0", "t1", "t2", "t3", "t4", "t5",
- "t6", "t7", "t8", "t9"
- );
-}
-
-void ScaleRowDown4_MIPS_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width) {
- __asm__ __volatile__ (
- ".set push \n"
- ".set noreorder \n"
-
- "srl $t9, %[dst_width], 3 \n"
- "beqz $t9, 2f \n"
- " nop \n"
-
- ".p2align 2 \n"
- "1: \n"
- "lw $t1, 0(%[src_ptr]) \n" // |3|2|1|0|
- "lw $t2, 4(%[src_ptr]) \n" // |7|6|5|4|
- "lw $t3, 8(%[src_ptr]) \n" // |11|10|9|8|
- "lw $t4, 12(%[src_ptr]) \n" // |15|14|13|12|
- "lw $t5, 16(%[src_ptr]) \n" // |19|18|17|16|
- "lw $t6, 20(%[src_ptr]) \n" // |23|22|21|20|
- "lw $t7, 24(%[src_ptr]) \n" // |27|26|25|24|
- "lw $t8, 28(%[src_ptr]) \n" // |31|30|29|28|
- "precr.qb.ph $t1, $t2, $t1 \n" // |6|4|2|0|
- "precr.qb.ph $t2, $t4, $t3 \n" // |14|12|10|8|
- "precr.qb.ph $t5, $t6, $t5 \n" // |22|20|18|16|
- "precr.qb.ph $t6, $t8, $t7 \n" // |30|28|26|24|
- "precr.qb.ph $t1, $t2, $t1 \n" // |12|8|4|0|
- "precr.qb.ph $t5, $t6, $t5 \n" // |28|24|20|16|
- "addiu %[src_ptr], %[src_ptr], 32 \n"
- "addiu $t9, $t9, -1 \n"
- "sw $t1, 0(%[dst]) \n"
- "sw $t5, 4(%[dst]) \n"
- "bgtz $t9, 1b \n"
- " addiu %[dst], %[dst], 8 \n"
-
- "2: \n"
- "andi $t9, %[dst_width], 7 \n" // residue
- "beqz $t9, 3f \n"
- " nop \n"
-
- "21: \n"
- "lbu $t1, 0(%[src_ptr]) \n"
- "addiu %[src_ptr], %[src_ptr], 4 \n"
- "addiu $t9, $t9, -1 \n"
- "sb $t1, 0(%[dst]) \n"
- "bgtz $t9, 21b \n"
- " addiu %[dst], %[dst], 1 \n"
-
- "3: \n"
- ".set pop \n"
- : [src_ptr] "+r" (src_ptr),
- [dst] "+r" (dst)
- : [dst_width] "r" (dst_width)
- : "t1", "t2", "t3", "t4", "t5",
- "t6", "t7", "t8", "t9"
- );
-}
-
-void ScaleRowDown4Box_MIPS_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width) {
- intptr_t stride = src_stride;
- const uint8* s1 = src_ptr + stride;
- const uint8* s2 = s1 + stride;
- const uint8* s3 = s2 + stride;
-
- __asm__ __volatile__ (
- ".set push \n"
- ".set noreorder \n"
-
- "srl $t9, %[dst_width], 1 \n"
- "andi $t8, %[dst_width], 1 \n"
-
- ".p2align 2 \n"
- "1: \n"
- "lw $t0, 0(%[src_ptr]) \n" // |3|2|1|0|
- "lw $t1, 0(%[s1]) \n" // |7|6|5|4|
- "lw $t2, 0(%[s2]) \n" // |11|10|9|8|
- "lw $t3, 0(%[s3]) \n" // |15|14|13|12|
- "lw $t4, 4(%[src_ptr]) \n" // |19|18|17|16|
- "lw $t5, 4(%[s1]) \n" // |23|22|21|20|
- "lw $t6, 4(%[s2]) \n" // |27|26|25|24|
- "lw $t7, 4(%[s3]) \n" // |31|30|29|28|
- "raddu.w.qb $t0, $t0 \n" // |3 + 2 + 1 + 0|
- "raddu.w.qb $t1, $t1 \n" // |7 + 6 + 5 + 4|
- "raddu.w.qb $t2, $t2 \n" // |11 + 10 + 9 + 8|
- "raddu.w.qb $t3, $t3 \n" // |15 + 14 + 13 + 12|
- "raddu.w.qb $t4, $t4 \n" // |19 + 18 + 17 + 16|
- "raddu.w.qb $t5, $t5 \n" // |23 + 22 + 21 + 20|
- "raddu.w.qb $t6, $t6 \n" // |27 + 26 + 25 + 24|
- "raddu.w.qb $t7, $t7 \n" // |31 + 30 + 29 + 28|
- "add $t0, $t0, $t1 \n"
- "add $t1, $t2, $t3 \n"
- "add $t0, $t0, $t1 \n"
- "add $t4, $t4, $t5 \n"
- "add $t6, $t6, $t7 \n"
- "add $t4, $t4, $t6 \n"
- "shra_r.w $t0, $t0, 4 \n"
- "shra_r.w $t4, $t4, 4 \n"
- "sb $t0, 0(%[dst]) \n"
- "sb $t4, 1(%[dst]) \n"
- "addiu %[src_ptr], %[src_ptr], 8 \n"
- "addiu %[s1], %[s1], 8 \n"
- "addiu %[s2], %[s2], 8 \n"
- "addiu %[s3], %[s3], 8 \n"
- "addiu $t9, $t9, -1 \n"
- "bgtz $t9, 1b \n"
- " addiu %[dst], %[dst], 2 \n"
- "beqz $t8, 2f \n"
- " nop \n"
-
- "lw $t0, 0(%[src_ptr]) \n" // |3|2|1|0|
- "lw $t1, 0(%[s1]) \n" // |7|6|5|4|
- "lw $t2, 0(%[s2]) \n" // |11|10|9|8|
- "lw $t3, 0(%[s3]) \n" // |15|14|13|12|
- "raddu.w.qb $t0, $t0 \n" // |3 + 2 + 1 + 0|
- "raddu.w.qb $t1, $t1 \n" // |7 + 6 + 5 + 4|
- "raddu.w.qb $t2, $t2 \n" // |11 + 10 + 9 + 8|
- "raddu.w.qb $t3, $t3 \n" // |15 + 14 + 13 + 12|
- "add $t0, $t0, $t1 \n"
- "add $t1, $t2, $t3 \n"
- "add $t0, $t0, $t1 \n"
- "shra_r.w $t0, $t0, 4 \n"
- "sb $t0, 0(%[dst]) \n"
-
- "2: \n"
- ".set pop \n"
-
- : [src_ptr] "+r" (src_ptr),
- [dst] "+r" (dst),
- [s1] "+r" (s1),
- [s2] "+r" (s2),
- [s3] "+r" (s3)
- : [dst_width] "r" (dst_width)
- : "t0", "t1", "t2", "t3", "t4", "t5",
- "t6","t7", "t8", "t9"
- );
-}
-
-void ScaleRowDown34_MIPS_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width) {
- __asm__ __volatile__ (
- ".set push \n"
- ".set noreorder \n"
- ".p2align 2 \n"
- "1: \n"
- "lw $t1, 0(%[src_ptr]) \n" // |3|2|1|0|
- "lw $t2, 4(%[src_ptr]) \n" // |7|6|5|4|
- "lw $t3, 8(%[src_ptr]) \n" // |11|10|9|8|
- "lw $t4, 12(%[src_ptr]) \n" // |15|14|13|12|
- "lw $t5, 16(%[src_ptr]) \n" // |19|18|17|16|
- "lw $t6, 20(%[src_ptr]) \n" // |23|22|21|20|
- "lw $t7, 24(%[src_ptr]) \n" // |27|26|25|24|
- "lw $t8, 28(%[src_ptr]) \n" // |31|30|29|28|
- "precrq.qb.ph $t0, $t2, $t4 \n" // |7|5|15|13|
- "precrq.qb.ph $t9, $t6, $t8 \n" // |23|21|31|30|
- "addiu %[dst_width], %[dst_width], -24 \n"
- "ins $t1, $t1, 8, 16 \n" // |3|1|0|X|
- "ins $t4, $t0, 8, 16 \n" // |X|15|13|12|
- "ins $t5, $t5, 8, 16 \n" // |19|17|16|X|
- "ins $t8, $t9, 8, 16 \n" // |X|31|29|28|
- "addiu %[src_ptr], %[src_ptr], 32 \n"
- "packrl.ph $t0, $t3, $t0 \n" // |9|8|7|5|
- "packrl.ph $t9, $t7, $t9 \n" // |25|24|23|21|
- "prepend $t1, $t2, 8 \n" // |4|3|1|0|
- "prepend $t3, $t4, 24 \n" // |15|13|12|11|
- "prepend $t5, $t6, 8 \n" // |20|19|17|16|
- "prepend $t7, $t8, 24 \n" // |31|29|28|27|
- "sw $t1, 0(%[dst]) \n"
- "sw $t0, 4(%[dst]) \n"
- "sw $t3, 8(%[dst]) \n"
- "sw $t5, 12(%[dst]) \n"
- "sw $t9, 16(%[dst]) \n"
- "sw $t7, 20(%[dst]) \n"
- "bnez %[dst_width], 1b \n"
- " addiu %[dst], %[dst], 24 \n"
- ".set pop \n"
- : [src_ptr] "+r" (src_ptr),
- [dst] "+r" (dst),
- [dst_width] "+r" (dst_width)
- :
- : "t0", "t1", "t2", "t3", "t4", "t5",
- "t6","t7", "t8", "t9"
- );
-}
-
-void ScaleRowDown34_0_Box_MIPS_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* d, int dst_width) {
- __asm__ __volatile__ (
- ".set push \n"
- ".set noreorder \n"
- "repl.ph $t3, 3 \n" // 0x00030003
-
- ".p2align 2 \n"
- "1: \n"
- "lw $t0, 0(%[src_ptr]) \n" // |S3|S2|S1|S0|
- "lwx $t1, %[src_stride](%[src_ptr]) \n" // |T3|T2|T1|T0|
- "rotr $t2, $t0, 8 \n" // |S0|S3|S2|S1|
- "rotr $t6, $t1, 8 \n" // |T0|T3|T2|T1|
- "muleu_s.ph.qbl $t4, $t2, $t3 \n" // |S0*3|S3*3|
- "muleu_s.ph.qbl $t5, $t6, $t3 \n" // |T0*3|T3*3|
- "andi $t0, $t2, 0xFFFF \n" // |0|0|S2|S1|
- "andi $t1, $t6, 0xFFFF \n" // |0|0|T2|T1|
- "raddu.w.qb $t0, $t0 \n"
- "raddu.w.qb $t1, $t1 \n"
- "shra_r.w $t0, $t0, 1 \n"
- "shra_r.w $t1, $t1, 1 \n"
- "preceu.ph.qbr $t2, $t2 \n" // |0|S2|0|S1|
- "preceu.ph.qbr $t6, $t6 \n" // |0|T2|0|T1|
- "rotr $t2, $t2, 16 \n" // |0|S1|0|S2|
- "rotr $t6, $t6, 16 \n" // |0|T1|0|T2|
- "addu.ph $t2, $t2, $t4 \n"
- "addu.ph $t6, $t6, $t5 \n"
- "sll $t5, $t0, 1 \n"
- "add $t0, $t5, $t0 \n"
- "shra_r.ph $t2, $t2, 2 \n"
- "shra_r.ph $t6, $t6, 2 \n"
- "shll.ph $t4, $t2, 1 \n"
- "addq.ph $t4, $t4, $t2 \n"
- "addu $t0, $t0, $t1 \n"
- "addiu %[src_ptr], %[src_ptr], 4 \n"
- "shra_r.w $t0, $t0, 2 \n"
- "addu.ph $t6, $t6, $t4 \n"
- "shra_r.ph $t6, $t6, 2 \n"
- "srl $t1, $t6, 16 \n"
- "addiu %[dst_width], %[dst_width], -3 \n"
- "sb $t1, 0(%[d]) \n"
- "sb $t0, 1(%[d]) \n"
- "sb $t6, 2(%[d]) \n"
- "bgtz %[dst_width], 1b \n"
- " addiu %[d], %[d], 3 \n"
- "3: \n"
- ".set pop \n"
- : [src_ptr] "+r" (src_ptr),
- [src_stride] "+r" (src_stride),
- [d] "+r" (d),
- [dst_width] "+r" (dst_width)
- :
- : "t0", "t1", "t2", "t3",
- "t4", "t5", "t6"
- );
-}
-
-void ScaleRowDown34_1_Box_MIPS_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* d, int dst_width) {
- __asm__ __volatile__ (
- ".set push \n"
- ".set noreorder \n"
- "repl.ph $t2, 3 \n" // 0x00030003
-
- ".p2align 2 \n"
- "1: \n"
- "lw $t0, 0(%[src_ptr]) \n" // |S3|S2|S1|S0|
- "lwx $t1, %[src_stride](%[src_ptr]) \n" // |T3|T2|T1|T0|
- "rotr $t4, $t0, 8 \n" // |S0|S3|S2|S1|
- "rotr $t6, $t1, 8 \n" // |T0|T3|T2|T1|
- "muleu_s.ph.qbl $t3, $t4, $t2 \n" // |S0*3|S3*3|
- "muleu_s.ph.qbl $t5, $t6, $t2 \n" // |T0*3|T3*3|
- "andi $t0, $t4, 0xFFFF \n" // |0|0|S2|S1|
- "andi $t1, $t6, 0xFFFF \n" // |0|0|T2|T1|
- "raddu.w.qb $t0, $t0 \n"
- "raddu.w.qb $t1, $t1 \n"
- "shra_r.w $t0, $t0, 1 \n"
- "shra_r.w $t1, $t1, 1 \n"
- "preceu.ph.qbr $t4, $t4 \n" // |0|S2|0|S1|
- "preceu.ph.qbr $t6, $t6 \n" // |0|T2|0|T1|
- "rotr $t4, $t4, 16 \n" // |0|S1|0|S2|
- "rotr $t6, $t6, 16 \n" // |0|T1|0|T2|
- "addu.ph $t4, $t4, $t3 \n"
- "addu.ph $t6, $t6, $t5 \n"
- "shra_r.ph $t6, $t6, 2 \n"
- "shra_r.ph $t4, $t4, 2 \n"
- "addu.ph $t6, $t6, $t4 \n"
- "addiu %[src_ptr], %[src_ptr], 4 \n"
- "shra_r.ph $t6, $t6, 1 \n"
- "addu $t0, $t0, $t1 \n"
- "addiu %[dst_width], %[dst_width], -3 \n"
- "shra_r.w $t0, $t0, 1 \n"
- "srl $t1, $t6, 16 \n"
- "sb $t1, 0(%[d]) \n"
- "sb $t0, 1(%[d]) \n"
- "sb $t6, 2(%[d]) \n"
- "bgtz %[dst_width], 1b \n"
- " addiu %[d], %[d], 3 \n"
- "3: \n"
- ".set pop \n"
- : [src_ptr] "+r" (src_ptr),
- [src_stride] "+r" (src_stride),
- [d] "+r" (d),
- [dst_width] "+r" (dst_width)
- :
- : "t0", "t1", "t2", "t3",
- "t4", "t5", "t6"
- );
-}
-
-void ScaleRowDown38_MIPS_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width) {
- __asm__ __volatile__ (
- ".set push \n"
- ".set noreorder \n"
-
- ".p2align 2 \n"
- "1: \n"
- "lw $t0, 0(%[src_ptr]) \n" // |3|2|1|0|
- "lw $t1, 4(%[src_ptr]) \n" // |7|6|5|4|
- "lw $t2, 8(%[src_ptr]) \n" // |11|10|9|8|
- "lw $t3, 12(%[src_ptr]) \n" // |15|14|13|12|
- "lw $t4, 16(%[src_ptr]) \n" // |19|18|17|16|
- "lw $t5, 20(%[src_ptr]) \n" // |23|22|21|20|
- "lw $t6, 24(%[src_ptr]) \n" // |27|26|25|24|
- "lw $t7, 28(%[src_ptr]) \n" // |31|30|29|28|
- "wsbh $t0, $t0 \n" // |2|3|0|1|
- "wsbh $t6, $t6 \n" // |26|27|24|25|
- "srl $t0, $t0, 8 \n" // |X|2|3|0|
- "srl $t3, $t3, 16 \n" // |X|X|15|14|
- "srl $t5, $t5, 16 \n" // |X|X|23|22|
- "srl $t7, $t7, 16 \n" // |X|X|31|30|
- "ins $t1, $t2, 24, 8 \n" // |8|6|5|4|
- "ins $t6, $t5, 0, 8 \n" // |26|27|24|22|
- "ins $t1, $t0, 0, 16 \n" // |8|6|3|0|
- "ins $t6, $t7, 24, 8 \n" // |30|27|24|22|
- "prepend $t2, $t3, 24 \n" // |X|15|14|11|
- "ins $t4, $t4, 16, 8 \n" // |19|16|17|X|
- "ins $t4, $t2, 0, 16 \n" // |19|16|14|11|
- "addiu %[src_ptr], %[src_ptr], 32 \n"
- "addiu %[dst_width], %[dst_width], -12 \n"
- "addiu $t8,%[dst_width], -12 \n"
- "sw $t1, 0(%[dst]) \n"
- "sw $t4, 4(%[dst]) \n"
- "sw $t6, 8(%[dst]) \n"
- "bgez $t8, 1b \n"
- " addiu %[dst], %[dst], 12 \n"
- ".set pop \n"
- : [src_ptr] "+r" (src_ptr),
- [dst] "+r" (dst),
- [dst_width] "+r" (dst_width)
- :
- : "t0", "t1", "t2", "t3", "t4",
- "t5", "t6", "t7", "t8"
- );
-}
-
-void ScaleRowDown38_2_Box_MIPS_DSPR2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- intptr_t stride = src_stride;
- const uint8* t = src_ptr + stride;
- const int c = 0x2AAA;
-
- __asm__ __volatile__ (
- ".set push \n"
- ".set noreorder \n"
-
- ".p2align 2 \n"
- "1: \n"
- "lw $t0, 0(%[src_ptr]) \n" // |S3|S2|S1|S0|
- "lw $t1, 4(%[src_ptr]) \n" // |S7|S6|S5|S4|
- "lw $t2, 0(%[t]) \n" // |T3|T2|T1|T0|
- "lw $t3, 4(%[t]) \n" // |T7|T6|T5|T4|
- "rotr $t1, $t1, 16 \n" // |S5|S4|S7|S6|
- "packrl.ph $t4, $t1, $t3 \n" // |S7|S6|T7|T6|
- "packrl.ph $t5, $t3, $t1 \n" // |T5|T4|S5|S4|
- "raddu.w.qb $t4, $t4 \n" // S7+S6+T7+T6
- "raddu.w.qb $t5, $t5 \n" // T5+T4+S5+S4
- "precrq.qb.ph $t6, $t0, $t2 \n" // |S3|S1|T3|T1|
- "precrq.qb.ph $t6, $t6, $t6 \n" // |S3|T3|S3|T3|
- "srl $t4, $t4, 2 \n" // t4 / 4
- "srl $t6, $t6, 16 \n" // |0|0|S3|T3|
- "raddu.w.qb $t6, $t6 \n" // 0+0+S3+T3
- "addu $t6, $t5, $t6 \n"
- "mul $t6, $t6, %[c] \n" // t6 * 0x2AAA
- "sll $t0, $t0, 8 \n" // |S2|S1|S0|0|
- "sll $t2, $t2, 8 \n" // |T2|T1|T0|0|
- "raddu.w.qb $t0, $t0 \n" // S2+S1+S0+0
- "raddu.w.qb $t2, $t2 \n" // T2+T1+T0+0
- "addu $t0, $t0, $t2 \n"
- "mul $t0, $t0, %[c] \n" // t0 * 0x2AAA
- "addiu %[src_ptr], %[src_ptr], 8 \n"
- "addiu %[t], %[t], 8 \n"
- "addiu %[dst_width], %[dst_width], -3 \n"
- "addiu %[dst_ptr], %[dst_ptr], 3 \n"
- "srl $t6, $t6, 16 \n"
- "srl $t0, $t0, 16 \n"
- "sb $t4, -1(%[dst_ptr]) \n"
- "sb $t6, -2(%[dst_ptr]) \n"
- "bgtz %[dst_width], 1b \n"
- " sb $t0, -3(%[dst_ptr]) \n"
- ".set pop \n"
- : [src_ptr] "+r" (src_ptr),
- [dst_ptr] "+r" (dst_ptr),
- [t] "+r" (t),
- [dst_width] "+r" (dst_width)
- : [c] "r" (c)
- : "t0", "t1", "t2", "t3", "t4", "t5", "t6"
- );
-}
-
-void ScaleRowDown38_3_Box_MIPS_DSPR2(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- intptr_t stride = src_stride;
- const uint8* s1 = src_ptr + stride;
- stride += stride;
- const uint8* s2 = src_ptr + stride;
- const int c1 = 0x1C71;
- const int c2 = 0x2AAA;
-
- __asm__ __volatile__ (
- ".set push \n"
- ".set noreorder \n"
-
- ".p2align 2 \n"
- "1: \n"
- "lw $t0, 0(%[src_ptr]) \n" // |S3|S2|S1|S0|
- "lw $t1, 4(%[src_ptr]) \n" // |S7|S6|S5|S4|
- "lw $t2, 0(%[s1]) \n" // |T3|T2|T1|T0|
- "lw $t3, 4(%[s1]) \n" // |T7|T6|T5|T4|
- "lw $t4, 0(%[s2]) \n" // |R3|R2|R1|R0|
- "lw $t5, 4(%[s2]) \n" // |R7|R6|R5|R4|
- "rotr $t1, $t1, 16 \n" // |S5|S4|S7|S6|
- "packrl.ph $t6, $t1, $t3 \n" // |S7|S6|T7|T6|
- "raddu.w.qb $t6, $t6 \n" // S7+S6+T7+T6
- "packrl.ph $t7, $t3, $t1 \n" // |T5|T4|S5|S4|
- "raddu.w.qb $t7, $t7 \n" // T5+T4+S5+S4
- "sll $t8, $t5, 16 \n" // |R5|R4|0|0|
- "raddu.w.qb $t8, $t8 \n" // R5+R4
- "addu $t7, $t7, $t8 \n"
- "srl $t8, $t5, 16 \n" // |0|0|R7|R6|
- "raddu.w.qb $t8, $t8 \n" // R7 + R6
- "addu $t6, $t6, $t8 \n"
- "mul $t6, $t6, %[c2] \n" // t6 * 0x2AAA
- "precrq.qb.ph $t8, $t0, $t2 \n" // |S3|S1|T3|T1|
- "precrq.qb.ph $t8, $t8, $t4 \n" // |S3|T3|R3|R1|
- "srl $t8, $t8, 8 \n" // |0|S3|T3|R3|
- "raddu.w.qb $t8, $t8 \n" // S3 + T3 + R3
- "addu $t7, $t7, $t8 \n"
- "mul $t7, $t7, %[c1] \n" // t7 * 0x1C71
- "sll $t0, $t0, 8 \n" // |S2|S1|S0|0|
- "sll $t2, $t2, 8 \n" // |T2|T1|T0|0|
- "sll $t4, $t4, 8 \n" // |R2|R1|R0|0|
- "raddu.w.qb $t0, $t0 \n"
- "raddu.w.qb $t2, $t2 \n"
- "raddu.w.qb $t4, $t4 \n"
- "addu $t0, $t0, $t2 \n"
- "addu $t0, $t0, $t4 \n"
- "mul $t0, $t0, %[c1] \n" // t0 * 0x1C71
- "addiu %[src_ptr], %[src_ptr], 8 \n"
- "addiu %[s1], %[s1], 8 \n"
- "addiu %[s2], %[s2], 8 \n"
- "addiu %[dst_width], %[dst_width], -3 \n"
- "addiu %[dst_ptr], %[dst_ptr], 3 \n"
- "srl $t6, $t6, 16 \n"
- "srl $t7, $t7, 16 \n"
- "srl $t0, $t0, 16 \n"
- "sb $t6, -1(%[dst_ptr]) \n"
- "sb $t7, -2(%[dst_ptr]) \n"
- "bgtz %[dst_width], 1b \n"
- " sb $t0, -3(%[dst_ptr]) \n"
- ".set pop \n"
- : [src_ptr] "+r" (src_ptr),
- [dst_ptr] "+r" (dst_ptr),
- [s1] "+r" (s1),
- [s2] "+r" (s2),
- [dst_width] "+r" (dst_width)
- : [c1] "r" (c1), [c2] "r" (c2)
- : "t0", "t1", "t2", "t3", "t4",
- "t5", "t6", "t7", "t8"
- );
-}
-
-#endif // defined(__mips_dsp) && (__mips_dsp_rev >= 2)
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
-
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/scale_neon.cc b/drivers/theoraplayer/src/YUV/libyuv/src/scale_neon.cc
deleted file mode 100755
index a9df93c055..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/scale_neon.cc
+++ /dev/null
@@ -1,699 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/row.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// This module is for GCC Neon.
-#if !defined(LIBYUV_DISABLE_NEON) && defined(__ARM_NEON__)
-
-// NEON downscalers with interpolation.
-// Provided by Fritz Koenig
-
-// Read 32x1 throw away even pixels, and write 16x1.
-void ScaleRowDown2_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width) {
- asm volatile (
-#ifdef _ANDROID
- ".fpu neon\n"
-#endif
- ".p2align 2 \n"
- "1: \n"
- // load even pixels into q0, odd into q1
- "vld2.8 {q0, q1}, [%0]! \n"
- "subs %2, %2, #16 \n" // 16 processed per loop
- "vst1.8 {q1}, [%1]! \n" // store odd pixels
- "bgt 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(dst), // %1
- "+r"(dst_width) // %2
- :
- : "q0", "q1" // Clobber List
- );
-}
-
-// Read 32x2 average down and write 16x1.
-void ScaleRowDown2Box_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width) {
- asm volatile (
-#ifdef _ANDROID
- ".fpu neon\n"
-#endif
- // change the stride to row 2 pointer
- "add %1, %0 \n"
- ".p2align 2 \n"
- "1: \n"
- "vld1.8 {q0, q1}, [%0]! \n" // load row 1 and post inc
- "vld1.8 {q2, q3}, [%1]! \n" // load row 2 and post inc
- "subs %3, %3, #16 \n" // 16 processed per loop
- "vpaddl.u8 q0, q0 \n" // row 1 add adjacent
- "vpaddl.u8 q1, q1 \n"
- "vpadal.u8 q0, q2 \n" // row 2 add adjacent + row1
- "vpadal.u8 q1, q3 \n"
- "vrshrn.u16 d0, q0, #2 \n" // downshift, round and pack
- "vrshrn.u16 d1, q1, #2 \n"
- "vst1.8 {q0}, [%2]! \n"
- "bgt 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(src_stride), // %1
- "+r"(dst), // %2
- "+r"(dst_width) // %3
- :
- : "q0", "q1", "q2", "q3" // Clobber List
- );
-}
-
-void ScaleRowDown4_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- asm volatile (
-#ifdef _ANDROID
- ".fpu neon\n"
-#endif
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // src line 0
- "subs %2, %2, #8 \n" // 8 processed per loop
- "vst1.8 {d2}, [%1]! \n"
- "bgt 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(dst_ptr), // %1
- "+r"(dst_width) // %2
- :
- : "q0", "q1", "memory", "cc"
- );
-}
-
-void ScaleRowDown4Box_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- asm volatile (
-#ifdef _ANDROID
- ".fpu neon\n"
-#endif
- "add r4, %0, %3 \n"
- "add r5, r4, %3 \n"
- "add %3, r5, %3 \n"
- ".p2align 2 \n"
- "1: \n"
- "vld1.8 {q0}, [%0]! \n" // load up 16x4
- "vld1.8 {q1}, [r4]! \n"
- "vld1.8 {q2}, [r5]! \n"
- "vld1.8 {q3}, [%3]! \n"
- "subs %2, %2, #4 \n"
- "vpaddl.u8 q0, q0 \n"
- "vpadal.u8 q0, q1 \n"
- "vpadal.u8 q0, q2 \n"
- "vpadal.u8 q0, q3 \n"
- "vpaddl.u16 q0, q0 \n"
- "vrshrn.u32 d0, q0, #4 \n" // divide by 16 w/rounding
- "vmovn.u16 d0, q0 \n"
- "vst1.32 {d0[0]}, [%1]! \n"
- "bgt 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(dst_ptr), // %1
- "+r"(dst_width) // %2
- : "r"(src_stride) // %3
- : "r4", "r5", "q0", "q1", "q2", "q3", "memory", "cc"
- );
-}
-
-// Down scale from 4 to 3 pixels. Use the neon multilane read/write
-// to load up the every 4th pixel into a 4 different registers.
-// Point samples 32 pixels to 24 pixels.
-void ScaleRowDown34_NEON(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- asm volatile (
-#ifdef _ANDROID
- ".fpu neon\n"
-#endif
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // src line 0
- "subs %2, %2, #24 \n"
- "vmov d2, d3 \n" // order d0, d1, d2
- "vst3.8 {d0, d1, d2}, [%1]! \n"
- "bgt 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(dst_ptr), // %1
- "+r"(dst_width) // %2
- :
- : "d0", "d1", "d2", "d3", "memory", "cc"
- );
-}
-
-void ScaleRowDown34_0_Box_NEON(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- asm volatile (
- "vmov.u8 d24, #3 \n"
- "add %3, %0 \n"
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // src line 0
- "vld4.8 {d4, d5, d6, d7}, [%3]! \n" // src line 1
- "subs %2, %2, #24 \n"
-
- // filter src line 0 with src line 1
- // expand chars to shorts to allow for room
- // when adding lines together
- "vmovl.u8 q8, d4 \n"
- "vmovl.u8 q9, d5 \n"
- "vmovl.u8 q10, d6 \n"
- "vmovl.u8 q11, d7 \n"
-
- // 3 * line_0 + line_1
- "vmlal.u8 q8, d0, d24 \n"
- "vmlal.u8 q9, d1, d24 \n"
- "vmlal.u8 q10, d2, d24 \n"
- "vmlal.u8 q11, d3, d24 \n"
-
- // (3 * line_0 + line_1) >> 2
- "vqrshrn.u16 d0, q8, #2 \n"
- "vqrshrn.u16 d1, q9, #2 \n"
- "vqrshrn.u16 d2, q10, #2 \n"
- "vqrshrn.u16 d3, q11, #2 \n"
-
- // a0 = (src[0] * 3 + s[1] * 1) >> 2
- "vmovl.u8 q8, d1 \n"
- "vmlal.u8 q8, d0, d24 \n"
- "vqrshrn.u16 d0, q8, #2 \n"
-
- // a1 = (src[1] * 1 + s[2] * 1) >> 1
- "vrhadd.u8 d1, d1, d2 \n"
-
- // a2 = (src[2] * 1 + s[3] * 3) >> 2
- "vmovl.u8 q8, d2 \n"
- "vmlal.u8 q8, d3, d24 \n"
- "vqrshrn.u16 d2, q8, #2 \n"
-
- "vst3.8 {d0, d1, d2}, [%1]! \n"
-
- "bgt 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(dst_ptr), // %1
- "+r"(dst_width), // %2
- "+r"(src_stride) // %3
- :
- : "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11", "d24", "memory", "cc"
- );
-}
-
-void ScaleRowDown34_1_Box_NEON(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- asm volatile (
- "vmov.u8 d24, #3 \n"
- "add %3, %0 \n"
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d1, d2, d3}, [%0]! \n" // src line 0
- "vld4.8 {d4, d5, d6, d7}, [%3]! \n" // src line 1
- "subs %2, %2, #24 \n"
- // average src line 0 with src line 1
- "vrhadd.u8 q0, q0, q2 \n"
- "vrhadd.u8 q1, q1, q3 \n"
-
- // a0 = (src[0] * 3 + s[1] * 1) >> 2
- "vmovl.u8 q3, d1 \n"
- "vmlal.u8 q3, d0, d24 \n"
- "vqrshrn.u16 d0, q3, #2 \n"
-
- // a1 = (src[1] * 1 + s[2] * 1) >> 1
- "vrhadd.u8 d1, d1, d2 \n"
-
- // a2 = (src[2] * 1 + s[3] * 3) >> 2
- "vmovl.u8 q3, d2 \n"
- "vmlal.u8 q3, d3, d24 \n"
- "vqrshrn.u16 d2, q3, #2 \n"
-
- "vst3.8 {d0, d1, d2}, [%1]! \n"
- "bgt 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(dst_ptr), // %1
- "+r"(dst_width), // %2
- "+r"(src_stride) // %3
- :
- : "r4", "q0", "q1", "q2", "q3", "d24", "memory", "cc"
- );
-}
-
-#define HAS_SCALEROWDOWN38_NEON
-static uvec8 kShuf38 =
- { 0, 3, 6, 8, 11, 14, 16, 19, 22, 24, 27, 30, 0, 0, 0, 0 };
-static uvec8 kShuf38_2 =
- { 0, 8, 16, 2, 10, 17, 4, 12, 18, 6, 14, 19, 0, 0, 0, 0 };
-static vec16 kMult38_Div6 =
- { 65536 / 12, 65536 / 12, 65536 / 12, 65536 / 12,
- 65536 / 12, 65536 / 12, 65536 / 12, 65536 / 12 };
-static vec16 kMult38_Div9 =
- { 65536 / 18, 65536 / 18, 65536 / 18, 65536 / 18,
- 65536 / 18, 65536 / 18, 65536 / 18, 65536 / 18 };
-
-// 32 -> 12
-void ScaleRowDown38_NEON(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- asm volatile (
- "vld1.8 {q3}, [%3] \n"
- ".p2align 2 \n"
- "1: \n"
- "vld1.8 {d0, d1, d2, d3}, [%0]! \n"
- "subs %2, %2, #12 \n"
- "vtbl.u8 d4, {d0, d1, d2, d3}, d6 \n"
- "vtbl.u8 d5, {d0, d1, d2, d3}, d7 \n"
- "vst1.8 {d4}, [%1]! \n"
- "vst1.32 {d5[0]}, [%1]! \n"
- "bgt 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(dst_ptr), // %1
- "+r"(dst_width) // %2
- : "r"(&kShuf38) // %3
- : "d0", "d1", "d2", "d3", "d4", "d5", "memory", "cc"
- );
-}
-
-// 32x3 -> 12x1
-void OMITFP ScaleRowDown38_3_Box_NEON(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- asm volatile (
- "vld1.16 {q13}, [%4] \n"
- "vld1.8 {q14}, [%5] \n"
- "vld1.8 {q15}, [%6] \n"
- "add r4, %0, %3, lsl #1 \n"
- "add %3, %0 \n"
- ".p2align 2 \n"
- "1: \n"
-
- // d0 = 00 40 01 41 02 42 03 43
- // d1 = 10 50 11 51 12 52 13 53
- // d2 = 20 60 21 61 22 62 23 63
- // d3 = 30 70 31 71 32 72 33 73
- "vld4.8 {d0, d1, d2, d3}, [%0]! \n"
- "vld4.8 {d4, d5, d6, d7}, [%3]! \n"
- "vld4.8 {d16, d17, d18, d19}, [r4]! \n"
- "subs %2, %2, #12 \n"
-
- // Shuffle the input data around to get align the data
- // so adjacent data can be added. 0,1 - 2,3 - 4,5 - 6,7
- // d0 = 00 10 01 11 02 12 03 13
- // d1 = 40 50 41 51 42 52 43 53
- "vtrn.u8 d0, d1 \n"
- "vtrn.u8 d4, d5 \n"
- "vtrn.u8 d16, d17 \n"
-
- // d2 = 20 30 21 31 22 32 23 33
- // d3 = 60 70 61 71 62 72 63 73
- "vtrn.u8 d2, d3 \n"
- "vtrn.u8 d6, d7 \n"
- "vtrn.u8 d18, d19 \n"
-
- // d0 = 00+10 01+11 02+12 03+13
- // d2 = 40+50 41+51 42+52 43+53
- "vpaddl.u8 q0, q0 \n"
- "vpaddl.u8 q2, q2 \n"
- "vpaddl.u8 q8, q8 \n"
-
- // d3 = 60+70 61+71 62+72 63+73
- "vpaddl.u8 d3, d3 \n"
- "vpaddl.u8 d7, d7 \n"
- "vpaddl.u8 d19, d19 \n"
-
- // combine source lines
- "vadd.u16 q0, q2 \n"
- "vadd.u16 q0, q8 \n"
- "vadd.u16 d4, d3, d7 \n"
- "vadd.u16 d4, d19 \n"
-
- // dst_ptr[3] = (s[6 + st * 0] + s[7 + st * 0]
- // + s[6 + st * 1] + s[7 + st * 1]
- // + s[6 + st * 2] + s[7 + st * 2]) / 6
- "vqrdmulh.s16 q2, q2, q13 \n"
- "vmovn.u16 d4, q2 \n"
-
- // Shuffle 2,3 reg around so that 2 can be added to the
- // 0,1 reg and 3 can be added to the 4,5 reg. This
- // requires expanding from u8 to u16 as the 0,1 and 4,5
- // registers are already expanded. Then do transposes
- // to get aligned.
- // q2 = xx 20 xx 30 xx 21 xx 31 xx 22 xx 32 xx 23 xx 33
- "vmovl.u8 q1, d2 \n"
- "vmovl.u8 q3, d6 \n"
- "vmovl.u8 q9, d18 \n"
-
- // combine source lines
- "vadd.u16 q1, q3 \n"
- "vadd.u16 q1, q9 \n"
-
- // d4 = xx 20 xx 30 xx 22 xx 32
- // d5 = xx 21 xx 31 xx 23 xx 33
- "vtrn.u32 d2, d3 \n"
-
- // d4 = xx 20 xx 21 xx 22 xx 23
- // d5 = xx 30 xx 31 xx 32 xx 33
- "vtrn.u16 d2, d3 \n"
-
- // 0+1+2, 3+4+5
- "vadd.u16 q0, q1 \n"
-
- // Need to divide, but can't downshift as the the value
- // isn't a power of 2. So multiply by 65536 / n
- // and take the upper 16 bits.
- "vqrdmulh.s16 q0, q0, q15 \n"
-
- // Align for table lookup, vtbl requires registers to
- // be adjacent
- "vmov.u8 d2, d4 \n"
-
- "vtbl.u8 d3, {d0, d1, d2}, d28 \n"
- "vtbl.u8 d4, {d0, d1, d2}, d29 \n"
-
- "vst1.8 {d3}, [%1]! \n"
- "vst1.32 {d4[0]}, [%1]! \n"
- "bgt 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(dst_ptr), // %1
- "+r"(dst_width), // %2
- "+r"(src_stride) // %3
- : "r"(&kMult38_Div6), // %4
- "r"(&kShuf38_2), // %5
- "r"(&kMult38_Div9) // %6
- : "r4", "q0", "q1", "q2", "q3", "q8", "q9",
- "q13", "q14", "q15", "memory", "cc"
- );
-}
-
-// 32x2 -> 12x1
-void ScaleRowDown38_2_Box_NEON(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- asm volatile (
- "vld1.16 {q13}, [%4] \n"
- "vld1.8 {q14}, [%5] \n"
- "add %3, %0 \n"
- ".p2align 2 \n"
- "1: \n"
-
- // d0 = 00 40 01 41 02 42 03 43
- // d1 = 10 50 11 51 12 52 13 53
- // d2 = 20 60 21 61 22 62 23 63
- // d3 = 30 70 31 71 32 72 33 73
- "vld4.8 {d0, d1, d2, d3}, [%0]! \n"
- "vld4.8 {d4, d5, d6, d7}, [%3]! \n"
- "subs %2, %2, #12 \n"
-
- // Shuffle the input data around to get align the data
- // so adjacent data can be added. 0,1 - 2,3 - 4,5 - 6,7
- // d0 = 00 10 01 11 02 12 03 13
- // d1 = 40 50 41 51 42 52 43 53
- "vtrn.u8 d0, d1 \n"
- "vtrn.u8 d4, d5 \n"
-
- // d2 = 20 30 21 31 22 32 23 33
- // d3 = 60 70 61 71 62 72 63 73
- "vtrn.u8 d2, d3 \n"
- "vtrn.u8 d6, d7 \n"
-
- // d0 = 00+10 01+11 02+12 03+13
- // d2 = 40+50 41+51 42+52 43+53
- "vpaddl.u8 q0, q0 \n"
- "vpaddl.u8 q2, q2 \n"
-
- // d3 = 60+70 61+71 62+72 63+73
- "vpaddl.u8 d3, d3 \n"
- "vpaddl.u8 d7, d7 \n"
-
- // combine source lines
- "vadd.u16 q0, q2 \n"
- "vadd.u16 d4, d3, d7 \n"
-
- // dst_ptr[3] = (s[6] + s[7] + s[6+st] + s[7+st]) / 4
- "vqrshrn.u16 d4, q2, #2 \n"
-
- // Shuffle 2,3 reg around so that 2 can be added to the
- // 0,1 reg and 3 can be added to the 4,5 reg. This
- // requires expanding from u8 to u16 as the 0,1 and 4,5
- // registers are already expanded. Then do transposes
- // to get aligned.
- // q2 = xx 20 xx 30 xx 21 xx 31 xx 22 xx 32 xx 23 xx 33
- "vmovl.u8 q1, d2 \n"
- "vmovl.u8 q3, d6 \n"
-
- // combine source lines
- "vadd.u16 q1, q3 \n"
-
- // d4 = xx 20 xx 30 xx 22 xx 32
- // d5 = xx 21 xx 31 xx 23 xx 33
- "vtrn.u32 d2, d3 \n"
-
- // d4 = xx 20 xx 21 xx 22 xx 23
- // d5 = xx 30 xx 31 xx 32 xx 33
- "vtrn.u16 d2, d3 \n"
-
- // 0+1+2, 3+4+5
- "vadd.u16 q0, q1 \n"
-
- // Need to divide, but can't downshift as the the value
- // isn't a power of 2. So multiply by 65536 / n
- // and take the upper 16 bits.
- "vqrdmulh.s16 q0, q0, q13 \n"
-
- // Align for table lookup, vtbl requires registers to
- // be adjacent
- "vmov.u8 d2, d4 \n"
-
- "vtbl.u8 d3, {d0, d1, d2}, d28 \n"
- "vtbl.u8 d4, {d0, d1, d2}, d29 \n"
-
- "vst1.8 {d3}, [%1]! \n"
- "vst1.32 {d4[0]}, [%1]! \n"
- "bgt 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(dst_ptr), // %1
- "+r"(dst_width), // %2
- "+r"(src_stride) // %3
- : "r"(&kMult38_Div6), // %4
- "r"(&kShuf38_2) // %5
- : "q0", "q1", "q2", "q3", "q13", "q14", "memory", "cc"
- );
-}
-
-// 16x2 -> 16x1
-void ScaleFilterRows_NEON(uint8* dst_ptr,
- const uint8* src_ptr, ptrdiff_t src_stride,
- int dst_width, int source_y_fraction) {
- asm volatile (
- "cmp %4, #0 \n"
- "beq 100f \n"
- "add %2, %1 \n"
- "cmp %4, #64 \n"
- "beq 75f \n"
- "cmp %4, #128 \n"
- "beq 50f \n"
- "cmp %4, #192 \n"
- "beq 25f \n"
-
- "vdup.8 d5, %4 \n"
- "rsb %4, #256 \n"
- "vdup.8 d4, %4 \n"
- // General purpose row blend.
- "1: \n"
- "vld1.8 {q0}, [%1]! \n"
- "vld1.8 {q1}, [%2]! \n"
- "subs %3, %3, #16 \n"
- "vmull.u8 q13, d0, d4 \n"
- "vmull.u8 q14, d1, d4 \n"
- "vmlal.u8 q13, d2, d5 \n"
- "vmlal.u8 q14, d3, d5 \n"
- "vrshrn.u16 d0, q13, #8 \n"
- "vrshrn.u16 d1, q14, #8 \n"
- "vst1.8 {q0}, [%0]! \n"
- "bgt 1b \n"
- "b 99f \n"
-
- // Blend 25 / 75.
- "25: \n"
- "vld1.8 {q0}, [%1]! \n"
- "vld1.8 {q1}, [%2]! \n"
- "subs %3, %3, #16 \n"
- "vrhadd.u8 q0, q1 \n"
- "vrhadd.u8 q0, q1 \n"
- "vst1.8 {q0}, [%0]! \n"
- "bgt 25b \n"
- "b 99f \n"
-
- // Blend 50 / 50.
- "50: \n"
- "vld1.8 {q0}, [%1]! \n"
- "vld1.8 {q1}, [%2]! \n"
- "subs %3, %3, #16 \n"
- "vrhadd.u8 q0, q1 \n"
- "vst1.8 {q0}, [%0]! \n"
- "bgt 50b \n"
- "b 99f \n"
-
- // Blend 75 / 25.
- "75: \n"
- "vld1.8 {q1}, [%1]! \n"
- "vld1.8 {q0}, [%2]! \n"
- "subs %3, %3, #16 \n"
- "vrhadd.u8 q0, q1 \n"
- "vrhadd.u8 q0, q1 \n"
- "vst1.8 {q0}, [%0]! \n"
- "bgt 75b \n"
- "b 99f \n"
-
- // Blend 100 / 0 - Copy row unchanged.
- "100: \n"
- "vld1.8 {q0}, [%1]! \n"
- "subs %3, %3, #16 \n"
- "vst1.8 {q0}, [%0]! \n"
- "bgt 100b \n"
-
- "99: \n"
- "vst1.8 {d1[7]}, [%0] \n"
- : "+r"(dst_ptr), // %0
- "+r"(src_ptr), // %1
- "+r"(src_stride), // %2
- "+r"(dst_width), // %3
- "+r"(source_y_fraction) // %4
- :
- : "q0", "q1", "d4", "d5", "q13", "q14", "memory", "cc"
- );
-}
-
-void ScaleARGBRowDown2_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width) {
- asm volatile (
- ".p2align 2 \n"
- "1: \n"
- // load even pixels into q0, odd into q1
- "vld2.32 {q0, q1}, [%0]! \n"
- "vld2.32 {q2, q3}, [%0]! \n"
- "subs %2, %2, #8 \n" // 8 processed per loop
- "vst1.8 {q1}, [%1]! \n" // store odd pixels
- "vst1.8 {q3}, [%1]! \n"
- "bgt 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(dst), // %1
- "+r"(dst_width) // %2
- :
- : "memory", "cc", "q0", "q1", "q2", "q3" // Clobber List
- );
-}
-
-void ScaleARGBRowDown2Box_NEON(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst, int dst_width) {
- asm volatile (
- // change the stride to row 2 pointer
- "add %1, %1, %0 \n"
- ".p2align 2 \n"
- "1: \n"
- "vld4.8 {d0, d2, d4, d6}, [%0]! \n" // load 8 ARGB pixels.
- "vld4.8 {d1, d3, d5, d7}, [%0]! \n" // load next 8 ARGB pixels.
- "subs %3, %3, #8 \n" // 8 processed per loop.
- "vpaddl.u8 q0, q0 \n" // B 16 bytes -> 8 shorts.
- "vpaddl.u8 q1, q1 \n" // G 16 bytes -> 8 shorts.
- "vpaddl.u8 q2, q2 \n" // R 16 bytes -> 8 shorts.
- "vpaddl.u8 q3, q3 \n" // A 16 bytes -> 8 shorts.
- "vld4.8 {d16, d18, d20, d22}, [%1]! \n" // load 8 more ARGB pixels.
- "vld4.8 {d17, d19, d21, d23}, [%1]! \n" // load last 8 ARGB pixels.
- "vpadal.u8 q0, q8 \n" // B 16 bytes -> 8 shorts.
- "vpadal.u8 q1, q9 \n" // G 16 bytes -> 8 shorts.
- "vpadal.u8 q2, q10 \n" // R 16 bytes -> 8 shorts.
- "vpadal.u8 q3, q11 \n" // A 16 bytes -> 8 shorts.
- "vrshrn.u16 d0, q0, #2 \n" // downshift, round and pack
- "vrshrn.u16 d1, q1, #2 \n"
- "vrshrn.u16 d2, q2, #2 \n"
- "vrshrn.u16 d3, q3, #2 \n"
- "vst4.8 {d0, d1, d2, d3}, [%2]! \n"
- "bgt 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(src_stride), // %1
- "+r"(dst), // %2
- "+r"(dst_width) // %3
- :
- : "memory", "cc", "q0", "q1", "q2", "q3", "q8", "q9", "q10", "q11"
- );
-}
-
-// Reads 4 pixels at a time.
-// Alignment requirement: src_argb 4 byte aligned.
-void ScaleARGBRowDownEven_NEON(const uint8* src_argb, ptrdiff_t src_stride,
- int src_stepx, uint8* dst_argb, int dst_width) {
- asm volatile (
- "mov r12, %3, lsl #2 \n"
- ".p2align 2 \n"
- "1: \n"
- "vld1.32 {d0[0]}, [%0], r12 \n"
- "vld1.32 {d0[1]}, [%0], r12 \n"
- "vld1.32 {d1[0]}, [%0], r12 \n"
- "vld1.32 {d1[1]}, [%0], r12 \n"
- "subs %2, %2, #4 \n" // 4 pixels per loop.
- "vst1.8 {q0}, [%1]! \n"
- "bgt 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_argb), // %1
- "+r"(dst_width) // %2
- : "r"(src_stepx) // %3
- : "memory", "cc", "r12", "q0"
- );
-}
-
-// Reads 4 pixels at a time.
-// Alignment requirement: src_argb 4 byte aligned.
-void ScaleARGBRowDownEvenBox_NEON(const uint8* src_argb, ptrdiff_t src_stride,
- int src_stepx,
- uint8* dst_argb, int dst_width) {
- asm volatile (
- "mov r12, %4, lsl #2 \n"
- "add %1, %1, %0 \n"
- ".p2align 2 \n"
- "1: \n"
- "vld1.8 {d0}, [%0], r12 \n" // Read 4 2x2 blocks -> 2x1
- "vld1.8 {d1}, [%1], r12 \n"
- "vld1.8 {d2}, [%0], r12 \n"
- "vld1.8 {d3}, [%1], r12 \n"
- "vld1.8 {d4}, [%0], r12 \n"
- "vld1.8 {d5}, [%1], r12 \n"
- "vld1.8 {d6}, [%0], r12 \n"
- "vld1.8 {d7}, [%1], r12 \n"
- "vaddl.u8 q0, d0, d1 \n"
- "vaddl.u8 q1, d2, d3 \n"
- "vaddl.u8 q2, d4, d5 \n"
- "vaddl.u8 q3, d6, d7 \n"
- "vswp.8 d1, d2 \n" // ab_cd -> ac_bd
- "vswp.8 d5, d6 \n" // ef_gh -> eg_fh
- "vadd.u16 q0, q0, q1 \n" // (a+b)_(c+d)
- "vadd.u16 q2, q2, q3 \n" // (e+f)_(g+h)
- "vrshrn.u16 d0, q0, #2 \n" // first 2 pixels.
- "vrshrn.u16 d1, q2, #2 \n" // next 2 pixels.
- "subs %3, %3, #4 \n" // 4 pixels per loop.
- "vst1.8 {q0}, [%2]! \n"
- "bgt 1b \n"
- : "+r"(src_argb), // %0
- "+r"(src_stride), // %1
- "+r"(dst_argb), // %2
- "+r"(dst_width) // %3
- : "r"(src_stepx) // %4
- : "memory", "cc", "r12", "q0", "q1", "q2", "q3"
- );
-}
-
-#endif // __ARM_NEON__
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/scale_posix.cc b/drivers/theoraplayer/src/YUV/libyuv/src/scale_posix.cc
deleted file mode 100644
index 352e667822..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/scale_posix.cc
+++ /dev/null
@@ -1,1315 +0,0 @@
-/*
- * Copyright 2013 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/row.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// This module is for GCC x86 and x64.
-#if !defined(LIBYUV_DISABLE_X86) && (defined(__x86_64__) || defined(__i386__))
-
-// Offsets for source bytes 0 to 9
-static uvec8 kShuf0 =
- { 0, 1, 3, 4, 5, 7, 8, 9, 128, 128, 128, 128, 128, 128, 128, 128 };
-
-// Offsets for source bytes 11 to 20 with 8 subtracted = 3 to 12.
-static uvec8 kShuf1 =
- { 3, 4, 5, 7, 8, 9, 11, 12, 128, 128, 128, 128, 128, 128, 128, 128 };
-
-// Offsets for source bytes 21 to 31 with 16 subtracted = 5 to 31.
-static uvec8 kShuf2 =
- { 5, 7, 8, 9, 11, 12, 13, 15, 128, 128, 128, 128, 128, 128, 128, 128 };
-
-// Offsets for source bytes 0 to 10
-static uvec8 kShuf01 =
- { 0, 1, 1, 2, 2, 3, 4, 5, 5, 6, 6, 7, 8, 9, 9, 10 };
-
-// Offsets for source bytes 10 to 21 with 8 subtracted = 3 to 13.
-static uvec8 kShuf11 =
- { 2, 3, 4, 5, 5, 6, 6, 7, 8, 9, 9, 10, 10, 11, 12, 13 };
-
-// Offsets for source bytes 21 to 31 with 16 subtracted = 5 to 31.
-static uvec8 kShuf21 =
- { 5, 6, 6, 7, 8, 9, 9, 10, 10, 11, 12, 13, 13, 14, 14, 15 };
-
-// Coefficients for source bytes 0 to 10
-static uvec8 kMadd01 =
- { 3, 1, 2, 2, 1, 3, 3, 1, 2, 2, 1, 3, 3, 1, 2, 2 };
-
-// Coefficients for source bytes 10 to 21
-static uvec8 kMadd11 =
- { 1, 3, 3, 1, 2, 2, 1, 3, 3, 1, 2, 2, 1, 3, 3, 1 };
-
-// Coefficients for source bytes 21 to 31
-static uvec8 kMadd21 =
- { 2, 2, 1, 3, 3, 1, 2, 2, 1, 3, 3, 1, 2, 2, 1, 3 };
-
-// Coefficients for source bytes 21 to 31
-static vec16 kRound34 =
- { 2, 2, 2, 2, 2, 2, 2, 2 };
-
-static uvec8 kShuf38a =
- { 0, 3, 6, 8, 11, 14, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 };
-
-static uvec8 kShuf38b =
- { 128, 128, 128, 128, 128, 128, 0, 3, 6, 8, 11, 14, 128, 128, 128, 128 };
-
-// Arrange words 0,3,6 into 0,1,2
-static uvec8 kShufAc =
- { 0, 1, 6, 7, 12, 13, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 };
-
-// Arrange words 0,3,6 into 3,4,5
-static uvec8 kShufAc3 =
- { 128, 128, 128, 128, 128, 128, 0, 1, 6, 7, 12, 13, 128, 128, 128, 128 };
-
-// Scaling values for boxes of 3x3 and 2x3
-static uvec16 kScaleAc33 =
- { 65536 / 9, 65536 / 9, 65536 / 6, 65536 / 9, 65536 / 9, 65536 / 6, 0, 0 };
-
-// Arrange first value for pixels 0,1,2,3,4,5
-static uvec8 kShufAb0 =
- { 0, 128, 3, 128, 6, 128, 8, 128, 11, 128, 14, 128, 128, 128, 128, 128 };
-
-// Arrange second value for pixels 0,1,2,3,4,5
-static uvec8 kShufAb1 =
- { 1, 128, 4, 128, 7, 128, 9, 128, 12, 128, 15, 128, 128, 128, 128, 128 };
-
-// Arrange third value for pixels 0,1,2,3,4,5
-static uvec8 kShufAb2 =
- { 2, 128, 5, 128, 128, 128, 10, 128, 13, 128, 128, 128, 128, 128, 128, 128 };
-
-// Scaling values for boxes of 3x2 and 2x2
-static uvec16 kScaleAb2 =
- { 65536 / 3, 65536 / 3, 65536 / 2, 65536 / 3, 65536 / 3, 65536 / 2, 0, 0 };
-
-// GCC versions of row functions are verbatim conversions from Visual C.
-// Generated using gcc disassembly on Visual C object file:
-// objdump -D yuvscaler.obj >yuvscaler.txt
-
-void ScaleRowDown2_SSE2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- asm volatile (
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "psrlw $0x8,%%xmm0 \n"
- "psrlw $0x8,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "sub $0x10,%2 \n"
- "jg 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(dst_ptr), // %1
- "+r"(dst_width) // %2
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1"
-#endif
- );
-}
-
-void ScaleRowDown2Linear_SSE2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- asm volatile (
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "psrlw $0x8,%%xmm5 \n"
-
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10, 0) ",%%xmm1 \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "movdqa %%xmm0,%%xmm2 \n"
- "psrlw $0x8,%%xmm0 \n"
- "movdqa %%xmm1,%%xmm3 \n"
- "psrlw $0x8,%%xmm1 \n"
- "pand %%xmm5,%%xmm2 \n"
- "pand %%xmm5,%%xmm3 \n"
- "pavgw %%xmm2,%%xmm0 \n"
- "pavgw %%xmm3,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "sub $0x10,%2 \n"
- "jg 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(dst_ptr), // %1
- "+r"(dst_width) // %2
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm5"
-#endif
- );
-}
-
-void ScaleRowDown2Box_SSE2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- asm volatile (
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "psrlw $0x8,%%xmm5 \n"
-
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- MEMOPREG(movdqa,0x00,0,3,1,xmm2) // movdqa (%0,%3,1),%%xmm2
- BUNDLEALIGN
- MEMOPREG(movdqa,0x10,0,3,1,xmm3) // movdqa 0x10(%0,%3,1),%%xmm3
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "pavgb %%xmm2,%%xmm0 \n"
- "pavgb %%xmm3,%%xmm1 \n"
- "movdqa %%xmm0,%%xmm2 \n"
- "psrlw $0x8,%%xmm0 \n"
- "movdqa %%xmm1,%%xmm3 \n"
- "psrlw $0x8,%%xmm1 \n"
- "pand %%xmm5,%%xmm2 \n"
- "pand %%xmm5,%%xmm3 \n"
- "pavgw %%xmm2,%%xmm0 \n"
- "pavgw %%xmm3,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "sub $0x10,%2 \n"
- "jg 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(dst_ptr), // %1
- "+r"(dst_width) // %2
- : "r"((intptr_t)(src_stride)) // %3
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"
-#endif
- );
-}
-
-void ScaleRowDown2_Unaligned_SSE2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- asm volatile (
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "psrlw $0x8,%%xmm0 \n"
- "psrlw $0x8,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "movdqu %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "sub $0x10,%2 \n"
- "jg 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(dst_ptr), // %1
- "+r"(dst_width) // %2
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1"
-#endif
- );
-}
-
-void ScaleRowDown2Linear_Unaligned_SSE2(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- asm volatile (
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "psrlw $0x8,%%xmm5 \n"
-
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "movdqa %%xmm0,%%xmm2 \n"
- "psrlw $0x8,%%xmm0 \n"
- "movdqa %%xmm1,%%xmm3 \n"
- "psrlw $0x8,%%xmm1 \n"
- "pand %%xmm5,%%xmm2 \n"
- "pand %%xmm5,%%xmm3 \n"
- "pavgw %%xmm2,%%xmm0 \n"
- "pavgw %%xmm3,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "movdqu %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "sub $0x10,%2 \n"
- "jg 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(dst_ptr), // %1
- "+r"(dst_width) // %2
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm5"
-#endif
- );
-}
-
-void ScaleRowDown2Box_Unaligned_SSE2(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- asm volatile (
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "psrlw $0x8,%%xmm5 \n"
-
- LABELALIGN
- "1: \n"
- "movdqu " MEMACCESS(0) ",%%xmm0 \n"
- "movdqu " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- MEMOPREG(movdqu,0x00,0,3,1,xmm2) // movdqu (%0,%3,1),%%xmm2
- BUNDLEALIGN
- MEMOPREG(movdqu,0x10,0,3,1,xmm3) // movdqu 0x10(%0,%3,1),%%xmm3
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "pavgb %%xmm2,%%xmm0 \n"
- "pavgb %%xmm3,%%xmm1 \n"
- "movdqa %%xmm0,%%xmm2 \n"
- "psrlw $0x8,%%xmm0 \n"
- "movdqa %%xmm1,%%xmm3 \n"
- "psrlw $0x8,%%xmm1 \n"
- "pand %%xmm5,%%xmm2 \n"
- "pand %%xmm5,%%xmm3 \n"
- "pavgw %%xmm2,%%xmm0 \n"
- "pavgw %%xmm3,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "movdqu %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "sub $0x10,%2 \n"
- "jg 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(dst_ptr), // %1
- "+r"(dst_width) // %2
- : "r"((intptr_t)(src_stride)) // %3
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm5"
-#endif
- );
-}
-
-void ScaleRowDown4_SSE2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- asm volatile (
- "pcmpeqb %%xmm5,%%xmm5 \n"
- "psrld $0x18,%%xmm5 \n"
- "pslld $0x10,%%xmm5 \n"
-
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "pand %%xmm5,%%xmm0 \n"
- "pand %%xmm5,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "psrlw $0x8,%%xmm0 \n"
- "packuswb %%xmm0,%%xmm0 \n"
- "movq %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "sub $0x8,%2 \n"
- "jg 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(dst_ptr), // %1
- "+r"(dst_width) // %2
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm5"
-#endif
- );
-}
-
-void ScaleRowDown4Box_SSE2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- intptr_t stridex3 = 0;
- asm volatile (
- "pcmpeqb %%xmm7,%%xmm7 \n"
- "psrlw $0x8,%%xmm7 \n"
- "lea " MEMLEA4(0x00,4,4,2) ",%3 \n"
-
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- MEMOPREG(movdqa,0x00,0,4,1,xmm2) // movdqa (%0,%4,1),%%xmm2
- BUNDLEALIGN
- MEMOPREG(movdqa,0x10,0,4,1,xmm3) // movdqa 0x10(%0,%4,1),%%xmm3
- "pavgb %%xmm2,%%xmm0 \n"
- "pavgb %%xmm3,%%xmm1 \n"
- MEMOPREG(movdqa,0x00,0,4,2,xmm2) // movdqa (%0,%4,2),%%xmm2
- BUNDLEALIGN
- MEMOPREG(movdqa,0x10,0,4,2,xmm3) // movdqa 0x10(%0,%4,2),%%xmm3
- MEMOPREG(movdqa,0x00,0,3,1,xmm4) // movdqa (%0,%3,1),%%xmm4
- MEMOPREG(movdqa,0x10,0,3,1,xmm5) // movdqa 0x10(%0,%3,1),%%xmm5
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "pavgb %%xmm4,%%xmm2 \n"
- "pavgb %%xmm2,%%xmm0 \n"
- "pavgb %%xmm5,%%xmm3 \n"
- "pavgb %%xmm3,%%xmm1 \n"
- "movdqa %%xmm0,%%xmm2 \n"
- "psrlw $0x8,%%xmm0 \n"
- "movdqa %%xmm1,%%xmm3 \n"
- "psrlw $0x8,%%xmm1 \n"
- "pand %%xmm7,%%xmm2 \n"
- "pand %%xmm7,%%xmm3 \n"
- "pavgw %%xmm2,%%xmm0 \n"
- "pavgw %%xmm3,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm0 \n"
- "movdqa %%xmm0,%%xmm2 \n"
- "psrlw $0x8,%%xmm0 \n"
- "pand %%xmm7,%%xmm2 \n"
- "pavgw %%xmm2,%%xmm0 \n"
- "packuswb %%xmm0,%%xmm0 \n"
- "movq %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x8,1) ",%1 \n"
- "sub $0x8,%2 \n"
- "jg 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(dst_ptr), // %1
- "+r"(dst_width), // %2
- "+r"(stridex3) // %3
- : "r"((intptr_t)(src_stride)) // %4
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm7"
-#endif
- );
-}
-
-void ScaleRowDown34_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- asm volatile (
- "movdqa %0,%%xmm3 \n"
- "movdqa %1,%%xmm4 \n"
- "movdqa %2,%%xmm5 \n"
- :
- : "m"(kShuf0), // %0
- "m"(kShuf1), // %1
- "m"(kShuf2) // %2
- );
- asm volatile (
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm2 \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "movdqa %%xmm2,%%xmm1 \n"
- "palignr $0x8,%%xmm0,%%xmm1 \n"
- "pshufb %%xmm3,%%xmm0 \n"
- "pshufb %%xmm4,%%xmm1 \n"
- "pshufb %%xmm5,%%xmm2 \n"
- "movq %%xmm0," MEMACCESS(1) " \n"
- "movq %%xmm1," MEMACCESS2(0x8,1) " \n"
- "movq %%xmm2," MEMACCESS2(0x10,1) " \n"
- "lea " MEMLEA(0x18,1) ",%1 \n"
- "sub $0x18,%2 \n"
- "jg 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(dst_ptr), // %1
- "+r"(dst_width) // %2
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5"
-#endif
- );
-}
-
-void ScaleRowDown34_1_Box_SSSE3(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- asm volatile (
- "movdqa %0,%%xmm2 \n" // kShuf01
- "movdqa %1,%%xmm3 \n" // kShuf11
- "movdqa %2,%%xmm4 \n" // kShuf21
- :
- : "m"(kShuf01), // %0
- "m"(kShuf11), // %1
- "m"(kShuf21) // %2
- );
- asm volatile (
- "movdqa %0,%%xmm5 \n" // kMadd01
- "movdqa %1,%%xmm0 \n" // kMadd11
- "movdqa %2,%%xmm1 \n" // kRound34
- :
- : "m"(kMadd01), // %0
- "m"(kMadd11), // %1
- "m"(kRound34) // %2
- );
- asm volatile (
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm6 \n"
- MEMOPREG(movdqa,0x00,0,3,1,xmm7) // movdqa (%0,%3),%%xmm7
- "pavgb %%xmm7,%%xmm6 \n"
- "pshufb %%xmm2,%%xmm6 \n"
- "pmaddubsw %%xmm5,%%xmm6 \n"
- "paddsw %%xmm1,%%xmm6 \n"
- "psrlw $0x2,%%xmm6 \n"
- "packuswb %%xmm6,%%xmm6 \n"
- "movq %%xmm6," MEMACCESS(1) " \n"
- "movdqu " MEMACCESS2(0x8,0) ",%%xmm6 \n"
- MEMOPREG(movdqu,0x8,0,3,1,xmm7) // movdqu 0x8(%0,%3),%%xmm7
- "pavgb %%xmm7,%%xmm6 \n"
- "pshufb %%xmm3,%%xmm6 \n"
- "pmaddubsw %%xmm0,%%xmm6 \n"
- "paddsw %%xmm1,%%xmm6 \n"
- "psrlw $0x2,%%xmm6 \n"
- "packuswb %%xmm6,%%xmm6 \n"
- "movq %%xmm6," MEMACCESS2(0x8,1) " \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm6 \n"
- BUNDLEALIGN
- MEMOPREG(movdqa,0x10,0,3,1,xmm7) // movdqa 0x10(%0,%3),%%xmm7
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "pavgb %%xmm7,%%xmm6 \n"
- "pshufb %%xmm4,%%xmm6 \n"
- "pmaddubsw %4,%%xmm6 \n"
- "paddsw %%xmm1,%%xmm6 \n"
- "psrlw $0x2,%%xmm6 \n"
- "packuswb %%xmm6,%%xmm6 \n"
- "movq %%xmm6," MEMACCESS2(0x10,1) " \n"
- "lea " MEMLEA(0x18,1) ",%1 \n"
- "sub $0x18,%2 \n"
- "jg 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(dst_ptr), // %1
- "+r"(dst_width) // %2
- : "r"((intptr_t)(src_stride)), // %3
- "m"(kMadd21) // %4
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
-#endif
- );
-}
-
-void ScaleRowDown34_0_Box_SSSE3(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- asm volatile (
- "movdqa %0,%%xmm2 \n" // kShuf01
- "movdqa %1,%%xmm3 \n" // kShuf11
- "movdqa %2,%%xmm4 \n" // kShuf21
- :
- : "m"(kShuf01), // %0
- "m"(kShuf11), // %1
- "m"(kShuf21) // %2
- );
- asm volatile (
- "movdqa %0,%%xmm5 \n" // kMadd01
- "movdqa %1,%%xmm0 \n" // kMadd11
- "movdqa %2,%%xmm1 \n" // kRound34
- :
- : "m"(kMadd01), // %0
- "m"(kMadd11), // %1
- "m"(kRound34) // %2
- );
-
- asm volatile (
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm6 \n"
- MEMOPREG(movdqa,0x00,0,3,1,xmm7) // movdqa (%0,%3,1),%%xmm7
- "pavgb %%xmm6,%%xmm7 \n"
- "pavgb %%xmm7,%%xmm6 \n"
- "pshufb %%xmm2,%%xmm6 \n"
- "pmaddubsw %%xmm5,%%xmm6 \n"
- "paddsw %%xmm1,%%xmm6 \n"
- "psrlw $0x2,%%xmm6 \n"
- "packuswb %%xmm6,%%xmm6 \n"
- "movq %%xmm6," MEMACCESS(1) " \n"
- "movdqu " MEMACCESS2(0x8,0) ",%%xmm6 \n"
- MEMOPREG(movdqu,0x8,0,3,1,xmm7) // movdqu 0x8(%0,%3,1),%%xmm7
- "pavgb %%xmm6,%%xmm7 \n"
- "pavgb %%xmm7,%%xmm6 \n"
- "pshufb %%xmm3,%%xmm6 \n"
- "pmaddubsw %%xmm0,%%xmm6 \n"
- "paddsw %%xmm1,%%xmm6 \n"
- "psrlw $0x2,%%xmm6 \n"
- "packuswb %%xmm6,%%xmm6 \n"
- "movq %%xmm6," MEMACCESS2(0x8,1) " \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm6 \n"
- MEMOPREG(movdqa,0x10,0,3,1,xmm7) // movdqa 0x10(%0,%3,1),%%xmm7
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "pavgb %%xmm6,%%xmm7 \n"
- "pavgb %%xmm7,%%xmm6 \n"
- "pshufb %%xmm4,%%xmm6 \n"
- "pmaddubsw %4,%%xmm6 \n"
- "paddsw %%xmm1,%%xmm6 \n"
- "psrlw $0x2,%%xmm6 \n"
- "packuswb %%xmm6,%%xmm6 \n"
- "movq %%xmm6," MEMACCESS2(0x10,1) " \n"
- "lea " MEMLEA(0x18,1) ",%1 \n"
- "sub $0x18,%2 \n"
- "jg 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(dst_ptr), // %1
- "+r"(dst_width) // %2
- : "r"((intptr_t)(src_stride)), // %3
- "m"(kMadd21) // %4
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
-#endif
- );
-}
-
-void ScaleRowDown38_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- asm volatile (
- "movdqa %3,%%xmm4 \n"
- "movdqa %4,%%xmm5 \n"
-
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "pshufb %%xmm4,%%xmm0 \n"
- "pshufb %%xmm5,%%xmm1 \n"
- "paddusb %%xmm1,%%xmm0 \n"
- "movq %%xmm0," MEMACCESS(1) " \n"
- "movhlps %%xmm0,%%xmm1 \n"
- "movd %%xmm1," MEMACCESS2(0x8,1) " \n"
- "lea " MEMLEA(0xc,1) ",%1 \n"
- "sub $0xc,%2 \n"
- "jg 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(dst_ptr), // %1
- "+r"(dst_width) // %2
- : "m"(kShuf38a), // %3
- "m"(kShuf38b) // %4
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm4", "xmm5"
-#endif
- );
-}
-
-void ScaleRowDown38_2_Box_SSSE3(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- asm volatile (
- "movdqa %0,%%xmm2 \n"
- "movdqa %1,%%xmm3 \n"
- "movdqa %2,%%xmm4 \n"
- "movdqa %3,%%xmm5 \n"
- :
- : "m"(kShufAb0), // %0
- "m"(kShufAb1), // %1
- "m"(kShufAb2), // %2
- "m"(kScaleAb2) // %3
- );
- asm volatile (
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- MEMOPREG(pavgb,0x00,0,3,1,xmm0) // pavgb (%0,%3,1),%%xmm0
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "pshufb %%xmm2,%%xmm1 \n"
- "movdqa %%xmm0,%%xmm6 \n"
- "pshufb %%xmm3,%%xmm6 \n"
- "paddusw %%xmm6,%%xmm1 \n"
- "pshufb %%xmm4,%%xmm0 \n"
- "paddusw %%xmm0,%%xmm1 \n"
- "pmulhuw %%xmm5,%%xmm1 \n"
- "packuswb %%xmm1,%%xmm1 \n"
- "sub $0x6,%2 \n"
- "movd %%xmm1," MEMACCESS(1) " \n"
- "psrlq $0x10,%%xmm1 \n"
- "movd %%xmm1," MEMACCESS2(0x2,1) " \n"
- "lea " MEMLEA(0x6,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(dst_ptr), // %1
- "+r"(dst_width) // %2
- : "r"((intptr_t)(src_stride)) // %3
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"
-#endif
- );
-}
-
-void ScaleRowDown38_3_Box_SSSE3(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- asm volatile (
- "movdqa %0,%%xmm2 \n"
- "movdqa %1,%%xmm3 \n"
- "movdqa %2,%%xmm4 \n"
- "pxor %%xmm5,%%xmm5 \n"
- :
- : "m"(kShufAc), // %0
- "m"(kShufAc3), // %1
- "m"(kScaleAc33) // %2
- );
- asm volatile (
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- MEMOPREG(movdqa,0x00,0,3,1,xmm6) // movdqa (%0,%3,1),%%xmm6
- "movhlps %%xmm0,%%xmm1 \n"
- "movhlps %%xmm6,%%xmm7 \n"
- "punpcklbw %%xmm5,%%xmm0 \n"
- "punpcklbw %%xmm5,%%xmm1 \n"
- "punpcklbw %%xmm5,%%xmm6 \n"
- "punpcklbw %%xmm5,%%xmm7 \n"
- "paddusw %%xmm6,%%xmm0 \n"
- "paddusw %%xmm7,%%xmm1 \n"
- MEMOPREG(movdqa,0x00,0,3,2,xmm6) // movdqa (%0,%3,2),%%xmm6
- "lea " MEMLEA(0x10,0) ",%0 \n"
- "movhlps %%xmm6,%%xmm7 \n"
- "punpcklbw %%xmm5,%%xmm6 \n"
- "punpcklbw %%xmm5,%%xmm7 \n"
- "paddusw %%xmm6,%%xmm0 \n"
- "paddusw %%xmm7,%%xmm1 \n"
- "movdqa %%xmm0,%%xmm6 \n"
- "psrldq $0x2,%%xmm0 \n"
- "paddusw %%xmm0,%%xmm6 \n"
- "psrldq $0x2,%%xmm0 \n"
- "paddusw %%xmm0,%%xmm6 \n"
- "pshufb %%xmm2,%%xmm6 \n"
- "movdqa %%xmm1,%%xmm7 \n"
- "psrldq $0x2,%%xmm1 \n"
- "paddusw %%xmm1,%%xmm7 \n"
- "psrldq $0x2,%%xmm1 \n"
- "paddusw %%xmm1,%%xmm7 \n"
- "pshufb %%xmm3,%%xmm7 \n"
- "paddusw %%xmm7,%%xmm6 \n"
- "pmulhuw %%xmm4,%%xmm6 \n"
- "packuswb %%xmm6,%%xmm6 \n"
- "sub $0x6,%2 \n"
- "movd %%xmm6," MEMACCESS(1) " \n"
- "psrlq $0x10,%%xmm6 \n"
- "movd %%xmm6," MEMACCESS2(0x2,1) " \n"
- "lea " MEMLEA(0x6,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(dst_ptr), // %1
- "+r"(dst_width) // %2
- : "r"((intptr_t)(src_stride)) // %3
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
-#endif
- );
-}
-
-void ScaleAddRows_SSE2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint16* dst_ptr, int src_width, int src_height) {
- int tmp_height = 0;
- intptr_t tmp_src = 0;
- asm volatile (
- "pxor %%xmm4,%%xmm4 \n"
- "sub $0x1,%5 \n"
-
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "mov %0,%3 \n"
- "add %6,%0 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "punpcklbw %%xmm4,%%xmm0 \n"
- "punpckhbw %%xmm4,%%xmm1 \n"
- "mov %5,%2 \n"
- "test %2,%2 \n"
- "je 3f \n"
-
- LABELALIGN
- "2: \n"
- "movdqa " MEMACCESS(0) ",%%xmm2 \n"
- "add %6,%0 \n"
- "movdqa %%xmm2,%%xmm3 \n"
- "punpcklbw %%xmm4,%%xmm2 \n"
- "punpckhbw %%xmm4,%%xmm3 \n"
- "paddusw %%xmm2,%%xmm0 \n"
- "paddusw %%xmm3,%%xmm1 \n"
- "sub $0x1,%2 \n"
- "jg 2b \n"
-
- LABELALIGN
- "3: \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "movdqa %%xmm1," MEMACCESS2(0x10,1) " \n"
- "lea " MEMLEA(0x10,3) ",%0 \n"
- "lea " MEMLEA(0x20,1) ",%1 \n"
- "sub $0x10,%4 \n"
- "jg 1b \n"
- : "+r"(src_ptr), // %0
- "+r"(dst_ptr), // %1
- "+r"(tmp_height), // %2
- "+r"(tmp_src), // %3
- "+r"(src_width), // %4
- "+rm"(src_height) // %5
- : "rm"((intptr_t)(src_stride)) // %6
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4"
-#endif
- );
-}
-
-// Bilinear column filtering. SSSE3 version.
-void ScaleFilterCols_SSSE3(uint8* dst_ptr, const uint8* src_ptr,
- int dst_width, int x, int dx) {
- intptr_t x0 = 0, x1 = 0, temp_pixel = 0;
- asm volatile (
- "movd %6,%%xmm2 \n"
- "movd %7,%%xmm3 \n"
- "movl $0x04040000,%k2 \n"
- "movd %k2,%%xmm5 \n"
- "pcmpeqb %%xmm6,%%xmm6 \n"
- "psrlw $0x9,%%xmm6 \n"
- "pextrw $0x1,%%xmm2,%k3 \n"
- "subl $0x2,%5 \n"
- "jl 29f \n"
- "movdqa %%xmm2,%%xmm0 \n"
- "paddd %%xmm3,%%xmm0 \n"
- "punpckldq %%xmm0,%%xmm2 \n"
- "punpckldq %%xmm3,%%xmm3 \n"
- "paddd %%xmm3,%%xmm3 \n"
- "pextrw $0x3,%%xmm2,%k4 \n"
-
- LABELALIGN
- "2: \n"
- "movdqa %%xmm2,%%xmm1 \n"
- "paddd %%xmm3,%%xmm2 \n"
- MEMOPARG(movzwl,0x00,1,3,1,k2) // movzwl (%1,%3,1),%k2
- "movd %k2,%%xmm0 \n"
- "psrlw $0x9,%%xmm1 \n"
- BUNDLEALIGN
- MEMOPARG(movzwl,0x00,1,4,1,k2) // movzwl (%1,%4,1),%k2
- "movd %k2,%%xmm4 \n"
- "pshufb %%xmm5,%%xmm1 \n"
- "punpcklwd %%xmm4,%%xmm0 \n"
- "pxor %%xmm6,%%xmm1 \n"
- "pmaddubsw %%xmm1,%%xmm0 \n"
- "pextrw $0x1,%%xmm2,%k3 \n"
- "pextrw $0x3,%%xmm2,%k4 \n"
- "psrlw $0x7,%%xmm0 \n"
- "packuswb %%xmm0,%%xmm0 \n"
- "movd %%xmm0,%k2 \n"
- "mov %w2," MEMACCESS(0) " \n"
- "lea " MEMLEA(0x2,0) ",%0 \n"
- "sub $0x2,%5 \n"
- "jge 2b \n"
-
- LABELALIGN
- "29: \n"
- "addl $0x1,%5 \n"
- "jl 99f \n"
- MEMOPARG(movzwl,0x00,1,3,1,k2) // movzwl (%1,%3,1),%k2
- "movd %k2,%%xmm0 \n"
- "psrlw $0x9,%%xmm2 \n"
- "pshufb %%xmm5,%%xmm2 \n"
- "pxor %%xmm6,%%xmm2 \n"
- "pmaddubsw %%xmm2,%%xmm0 \n"
- "psrlw $0x7,%%xmm0 \n"
- "packuswb %%xmm0,%%xmm0 \n"
- "movd %%xmm0,%k2 \n"
- "mov %b2," MEMACCESS(0) " \n"
- "99: \n"
- : "+r"(dst_ptr), // %0
- "+r"(src_ptr), // %1
- "+a"(temp_pixel), // %2
- "+r"(x0), // %3
- "+r"(x1), // %4
- "+rm"(dst_width) // %5
- : "rm"(x), // %6
- "rm"(dx) // %7
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"
-#endif
- );
-}
-
-// Reads 4 pixels, duplicates them and writes 8 pixels.
-// Alignment requirement: src_argb 16 byte aligned, dst_argb 16 byte aligned.
-void ScaleColsUp2_SSE2(uint8* dst_ptr, const uint8* src_ptr,
- int dst_width, int x, int dx) {
- asm volatile (
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(1) ",%%xmm0 \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "punpcklbw %%xmm0,%%xmm0 \n"
- "punpckhbw %%xmm1,%%xmm1 \n"
- "sub $0x20,%2 \n"
- "movdqa %%xmm0," MEMACCESS(0) " \n"
- "movdqa %%xmm1," MEMACCESS2(0x10,0) " \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "jg 1b \n"
-
- : "+r"(dst_ptr), // %0
- "+r"(src_ptr), // %1
- "+r"(dst_width) // %2
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1"
-#endif
- );
-}
-
-void ScaleARGBRowDown2_SSE2(const uint8* src_argb,
- ptrdiff_t src_stride,
- uint8* dst_argb, int dst_width) {
- asm volatile (
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "shufps $0xdd,%%xmm1,%%xmm0 \n"
- "sub $0x4,%2 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_argb), // %1
- "+r"(dst_width) // %2
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1"
-#endif
- );
-}
-
-void ScaleARGBRowDown2Linear_SSE2(const uint8* src_argb,
- ptrdiff_t src_stride,
- uint8* dst_argb, int dst_width) {
- asm volatile (
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "movdqa %%xmm0,%%xmm2 \n"
- "shufps $0x88,%%xmm1,%%xmm0 \n"
- "shufps $0xdd,%%xmm1,%%xmm2 \n"
- "pavgb %%xmm2,%%xmm0 \n"
- "sub $0x4,%2 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_argb), // %1
- "+r"(dst_width) // %2
- :
- : "memory", "cc"
-#if defined(__SSE2__)
- , "xmm0", "xmm1"
-#endif
- );
-}
-
-void ScaleARGBRowDown2Box_SSE2(const uint8* src_argb,
- ptrdiff_t src_stride,
- uint8* dst_argb, int dst_width) {
- asm volatile (
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(0) ",%%xmm0 \n"
- "movdqa " MEMACCESS2(0x10,0) ",%%xmm1 \n"
- BUNDLEALIGN
- MEMOPREG(movdqa,0x00,0,3,1,xmm2) // movdqa (%0,%3,1),%%xmm2
- MEMOPREG(movdqa,0x10,0,3,1,xmm3) // movdqa 0x10(%0,%3,1),%%xmm3
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "pavgb %%xmm2,%%xmm0 \n"
- "pavgb %%xmm3,%%xmm1 \n"
- "movdqa %%xmm0,%%xmm2 \n"
- "shufps $0x88,%%xmm1,%%xmm0 \n"
- "shufps $0xdd,%%xmm1,%%xmm2 \n"
- "pavgb %%xmm2,%%xmm0 \n"
- "sub $0x4,%2 \n"
- "movdqa %%xmm0," MEMACCESS(1) " \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "jg 1b \n"
- : "+r"(src_argb), // %0
- "+r"(dst_argb), // %1
- "+r"(dst_width) // %2
- : "r"((intptr_t)(src_stride)) // %3
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3"
-#endif
- );
-}
-
-// Reads 4 pixels at a time.
-// Alignment requirement: dst_argb 16 byte aligned.
-void ScaleARGBRowDownEven_SSE2(const uint8* src_argb, ptrdiff_t src_stride,
- int src_stepx,
- uint8* dst_argb, int dst_width) {
- intptr_t src_stepx_x4 = (intptr_t)(src_stepx);
- intptr_t src_stepx_x12 = 0;
- asm volatile (
- "lea " MEMLEA3(0x00,1,4) ",%1 \n"
- "lea " MEMLEA4(0x00,1,1,2) ",%4 \n"
- LABELALIGN
- "1: \n"
- "movd " MEMACCESS(0) ",%%xmm0 \n"
- MEMOPREG(movd,0x00,0,1,1,xmm1) // movd (%0,%1,1),%%xmm1
- "punpckldq %%xmm1,%%xmm0 \n"
- BUNDLEALIGN
- MEMOPREG(movd,0x00,0,1,2,xmm2) // movd (%0,%1,2),%%xmm2
- MEMOPREG(movd,0x00,0,4,1,xmm3) // movd (%0,%4,1),%%xmm3
- "lea " MEMLEA4(0x00,0,1,4) ",%0 \n"
- "punpckldq %%xmm3,%%xmm2 \n"
- "punpcklqdq %%xmm2,%%xmm0 \n"
- "sub $0x4,%3 \n"
- "movdqa %%xmm0," MEMACCESS(2) " \n"
- "lea " MEMLEA(0x10,2) ",%2 \n"
- "jg 1b \n"
- : "+r"(src_argb), // %0
- "+r"(src_stepx_x4), // %1
- "+r"(dst_argb), // %2
- "+r"(dst_width), // %3
- "+r"(src_stepx_x12) // %4
- :
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3"
-#endif
- );
-}
-
-// Blends four 2x2 to 4x1.
-// Alignment requirement: dst_argb 16 byte aligned.
-void ScaleARGBRowDownEvenBox_SSE2(const uint8* src_argb,
- ptrdiff_t src_stride, int src_stepx,
- uint8* dst_argb, int dst_width) {
- intptr_t src_stepx_x4 = (intptr_t)(src_stepx);
- intptr_t src_stepx_x12 = 0;
- intptr_t row1 = (intptr_t)(src_stride);
- asm volatile (
- "lea " MEMLEA3(0x00,1,4) ",%1 \n"
- "lea " MEMLEA4(0x00,1,1,2) ",%4 \n"
- "lea " MEMLEA4(0x00,0,5,1) ",%5 \n"
-
- LABELALIGN
- "1: \n"
- "movq " MEMACCESS(0) ",%%xmm0 \n"
- MEMOPREG(movhps,0x00,0,1,1,xmm0) // movhps (%0,%1,1),%%xmm0
- MEMOPREG(movq,0x00,0,1,2,xmm1) // movq (%0,%1,2),%%xmm1
- BUNDLEALIGN
- MEMOPREG(movhps,0x00,0,4,1,xmm1) // movhps (%0,%4,1),%%xmm1
- "lea " MEMLEA4(0x00,0,1,4) ",%0 \n"
- "movq " MEMACCESS(5) ",%%xmm2 \n"
- BUNDLEALIGN
- MEMOPREG(movhps,0x00,5,1,1,xmm2) // movhps (%5,%1,1),%%xmm2
- MEMOPREG(movq,0x00,5,1,2,xmm3) // movq (%5,%1,2),%%xmm3
- MEMOPREG(movhps,0x00,5,4,1,xmm3) // movhps (%5,%4,1),%%xmm3
- "lea " MEMLEA4(0x00,5,1,4) ",%5 \n"
- "pavgb %%xmm2,%%xmm0 \n"
- "pavgb %%xmm3,%%xmm1 \n"
- "movdqa %%xmm0,%%xmm2 \n"
- "shufps $0x88,%%xmm1,%%xmm0 \n"
- "shufps $0xdd,%%xmm1,%%xmm2 \n"
- "pavgb %%xmm2,%%xmm0 \n"
- "sub $0x4,%3 \n"
- "movdqa %%xmm0," MEMACCESS(2) " \n"
- "lea " MEMLEA(0x10,2) ",%2 \n"
- "jg 1b \n"
- : "+r"(src_argb), // %0
- "+r"(src_stepx_x4), // %1
- "+r"(dst_argb), // %2
- "+rm"(dst_width), // %3
- "+r"(src_stepx_x12), // %4
- "+r"(row1) // %5
- :
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3"
-#endif
- );
-}
-
-void ScaleARGBCols_SSE2(uint8* dst_argb, const uint8* src_argb,
- int dst_width, int x, int dx) {
- intptr_t x0 = 0, x1 = 0;
- asm volatile (
- "movd %5,%%xmm2 \n"
- "movd %6,%%xmm3 \n"
- "pshufd $0x0,%%xmm2,%%xmm2 \n"
- "pshufd $0x11,%%xmm3,%%xmm0 \n"
- "paddd %%xmm0,%%xmm2 \n"
- "paddd %%xmm3,%%xmm3 \n"
- "pshufd $0x5,%%xmm3,%%xmm0 \n"
- "paddd %%xmm0,%%xmm2 \n"
- "paddd %%xmm3,%%xmm3 \n"
- "pshufd $0x0,%%xmm3,%%xmm3 \n"
- "pextrw $0x1,%%xmm2,%k0 \n"
- "pextrw $0x3,%%xmm2,%k1 \n"
- "cmp $0x0,%4 \n"
- "jl 99f \n"
- "sub $0x4,%4 \n"
- "jl 49f \n"
-
- LABELALIGN
- "40: \n"
- MEMOPREG(movd,0x00,3,0,4,xmm0) // movd (%3,%0,4),%%xmm0
- MEMOPREG(movd,0x00,3,1,4,xmm1) // movd (%3,%1,4),%%xmm1
- "pextrw $0x5,%%xmm2,%k0 \n"
- "pextrw $0x7,%%xmm2,%k1 \n"
- "paddd %%xmm3,%%xmm2 \n"
- "punpckldq %%xmm1,%%xmm0 \n"
- MEMOPREG(movd,0x00,3,0,4,xmm1) // movd (%3,%0,4),%%xmm1
- MEMOPREG(movd,0x00,3,1,4,xmm4) // movd (%3,%1,4),%%xmm4
- "pextrw $0x1,%%xmm2,%k0 \n"
- "pextrw $0x3,%%xmm2,%k1 \n"
- "punpckldq %%xmm4,%%xmm1 \n"
- "punpcklqdq %%xmm1,%%xmm0 \n"
- "sub $0x4,%4 \n"
- "movdqu %%xmm0," MEMACCESS(2) " \n"
- "lea " MEMLEA(0x10,2) ",%2 \n"
- "jge 40b \n"
-
- "49: \n"
- "test $0x2,%4 \n"
- "je 29f \n"
- BUNDLEALIGN
- MEMOPREG(movd,0x00,3,0,4,xmm0) // movd (%3,%0,4),%%xmm0
- MEMOPREG(movd,0x00,3,1,4,xmm1) // movd (%3,%1,4),%%xmm1
- "pextrw $0x5,%%xmm2,%k0 \n"
- "punpckldq %%xmm1,%%xmm0 \n"
- "movq %%xmm0," MEMACCESS(2) " \n"
- "lea " MEMLEA(0x8,2) ",%2 \n"
- "29: \n"
- "test $0x1,%4 \n"
- "je 99f \n"
- MEMOPREG(movd,0x00,3,0,4,xmm0) // movd (%3,%0,4),%%xmm0
- "movd %%xmm0," MEMACCESS(2) " \n"
- "99: \n"
- : "+a"(x0), // %0
- "+d"(x1), // %1
- "+r"(dst_argb), // %2
- "+r"(src_argb), // %3
- "+r"(dst_width) // %4
- : "rm"(x), // %5
- "rm"(dx) // %6
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4"
-#endif
- );
-}
-
-// Reads 4 pixels, duplicates them and writes 8 pixels.
-// Alignment requirement: src_argb 16 byte aligned, dst_argb 16 byte aligned.
-void ScaleARGBColsUp2_SSE2(uint8* dst_argb, const uint8* src_argb,
- int dst_width, int x, int dx) {
- asm volatile (
- LABELALIGN
- "1: \n"
- "movdqa " MEMACCESS(1) ",%%xmm0 \n"
- "lea " MEMLEA(0x10,1) ",%1 \n"
- "movdqa %%xmm0,%%xmm1 \n"
- "punpckldq %%xmm0,%%xmm0 \n"
- "punpckhdq %%xmm1,%%xmm1 \n"
- "sub $0x8,%2 \n"
- "movdqa %%xmm0," MEMACCESS(0) " \n"
- "movdqa %%xmm1," MEMACCESS2(0x10,0) " \n"
- "lea " MEMLEA(0x20,0) ",%0 \n"
- "jg 1b \n"
-
- : "+r"(dst_argb), // %0
- "+r"(src_argb), // %1
- "+r"(dst_width) // %2
- :
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1"
-#endif
- );
-}
-
-// Shuffle table for arranging 2 pixels into pairs for pmaddubsw
-static uvec8 kShuffleColARGB = {
- 0u, 4u, 1u, 5u, 2u, 6u, 3u, 7u, // bbggrraa 1st pixel
- 8u, 12u, 9u, 13u, 10u, 14u, 11u, 15u // bbggrraa 2nd pixel
-};
-
-// Shuffle table for duplicating 2 fractions into 8 bytes each
-static uvec8 kShuffleFractions = {
- 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u,
-};
-
-// Bilinear row filtering combines 4x2 -> 4x1. SSSE3 version
-void ScaleARGBFilterCols_SSSE3(uint8* dst_argb, const uint8* src_argb,
- int dst_width, int x, int dx) {
- intptr_t x0 = 0, x1 = 0;
- asm volatile (
- "movdqa %0,%%xmm4 \n"
- "movdqa %1,%%xmm5 \n"
- :
- : "m"(kShuffleColARGB), // %0
- "m"(kShuffleFractions) // %1
- );
-
- asm volatile (
- "movd %5,%%xmm2 \n"
- "movd %6,%%xmm3 \n"
- "pcmpeqb %%xmm6,%%xmm6 \n"
- "psrlw $0x9,%%xmm6 \n"
- "pextrw $0x1,%%xmm2,%k3 \n"
- "sub $0x2,%2 \n"
- "jl 29f \n"
- "movdqa %%xmm2,%%xmm0 \n"
- "paddd %%xmm3,%%xmm0 \n"
- "punpckldq %%xmm0,%%xmm2 \n"
- "punpckldq %%xmm3,%%xmm3 \n"
- "paddd %%xmm3,%%xmm3 \n"
- "pextrw $0x3,%%xmm2,%k4 \n"
-
- LABELALIGN
- "2: \n"
- "movdqa %%xmm2,%%xmm1 \n"
- "paddd %%xmm3,%%xmm2 \n"
- MEMOPREG(movq,0x00,1,3,4,xmm0) // movq (%1,%3,4),%%xmm0
- "psrlw $0x9,%%xmm1 \n"
- BUNDLEALIGN
- MEMOPREG(movhps,0x00,1,4,4,xmm0) // movhps (%1,%4,4),%%xmm0
- "pshufb %%xmm5,%%xmm1 \n"
- "pshufb %%xmm4,%%xmm0 \n"
- "pxor %%xmm6,%%xmm1 \n"
- "pmaddubsw %%xmm1,%%xmm0 \n"
- "psrlw $0x7,%%xmm0 \n"
- "pextrw $0x1,%%xmm2,%k3 \n"
- "pextrw $0x3,%%xmm2,%k4 \n"
- "packuswb %%xmm0,%%xmm0 \n"
- "movq %%xmm0," MEMACCESS(0) " \n"
- "lea " MEMLEA(0x8,0) ",%0 \n"
- "sub $0x2,%2 \n"
- "jge 2b \n"
-
- LABELALIGN
- "29: \n"
- "add $0x1,%2 \n"
- "jl 99f \n"
- "psrlw $0x9,%%xmm2 \n"
- BUNDLEALIGN
- MEMOPREG(movq,0x00,1,3,4,xmm0) // movq (%1,%3,4),%%xmm0
- "pshufb %%xmm5,%%xmm2 \n"
- "pshufb %%xmm4,%%xmm0 \n"
- "pxor %%xmm6,%%xmm2 \n"
- "pmaddubsw %%xmm2,%%xmm0 \n"
- "psrlw $0x7,%%xmm0 \n"
- "packuswb %%xmm0,%%xmm0 \n"
- "movd %%xmm0," MEMACCESS(0) " \n"
-
- LABELALIGN
- "99: \n"
- : "+r"(dst_argb), // %0
- "+r"(src_argb), // %1
- "+rm"(dst_width), // %2
- "+r"(x0), // %3
- "+r"(x1) // %4
- : "rm"(x), // %5
- "rm"(dx) // %6
- : "memory", "cc"
-#if defined(__native_client__) && defined(__x86_64__)
- , "r14"
-#endif
-#if defined(__SSE2__)
- , "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6"
-#endif
- );
-}
-
-// Divide num by div and return as 16.16 fixed point result.
-int FixedDiv_X86(int num, int div) {
- asm volatile (
- "cdq \n"
- "shld $0x10,%%eax,%%edx \n"
- "shl $0x10,%%eax \n"
- "idiv %1 \n"
- "mov %0, %%eax \n"
- : "+a"(num) // %0
- : "c"(div) // %1
- : "memory", "cc", "edx"
- );
- return num;
-}
-
-// Divide num - 1 by div - 1 and return as 16.16 fixed point result.
-int FixedDiv1_X86(int num, int div) {
- asm volatile (
- "cdq \n"
- "shld $0x10,%%eax,%%edx \n"
- "shl $0x10,%%eax \n"
- "sub $0x10001,%%eax \n"
- "sbb $0x0,%%edx \n"
- "sub $0x1,%1 \n"
- "idiv %1 \n"
- "mov %0, %%eax \n"
- : "+a"(num) // %0
- : "c"(div) // %1
- : "memory", "cc", "edx"
- );
- return num;
-}
-
-#endif // defined(__x86_64__) || defined(__i386__)
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/scale_win.cc b/drivers/theoraplayer/src/YUV/libyuv/src/scale_win.cc
deleted file mode 100644
index 840b9738da..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/scale_win.cc
+++ /dev/null
@@ -1,1320 +0,0 @@
-/*
- * Copyright 2013 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-#include "libyuv/row.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-// This module is for Visual C x86.
-#if !defined(LIBYUV_DISABLE_X86) && defined(_M_IX86) && defined(_MSC_VER)
-
-// Offsets for source bytes 0 to 9
-static uvec8 kShuf0 =
- { 0, 1, 3, 4, 5, 7, 8, 9, 128, 128, 128, 128, 128, 128, 128, 128 };
-
-// Offsets for source bytes 11 to 20 with 8 subtracted = 3 to 12.
-static uvec8 kShuf1 =
- { 3, 4, 5, 7, 8, 9, 11, 12, 128, 128, 128, 128, 128, 128, 128, 128 };
-
-// Offsets for source bytes 21 to 31 with 16 subtracted = 5 to 31.
-static uvec8 kShuf2 =
- { 5, 7, 8, 9, 11, 12, 13, 15, 128, 128, 128, 128, 128, 128, 128, 128 };
-
-// Offsets for source bytes 0 to 10
-static uvec8 kShuf01 =
- { 0, 1, 1, 2, 2, 3, 4, 5, 5, 6, 6, 7, 8, 9, 9, 10 };
-
-// Offsets for source bytes 10 to 21 with 8 subtracted = 3 to 13.
-static uvec8 kShuf11 =
- { 2, 3, 4, 5, 5, 6, 6, 7, 8, 9, 9, 10, 10, 11, 12, 13 };
-
-// Offsets for source bytes 21 to 31 with 16 subtracted = 5 to 31.
-static uvec8 kShuf21 =
- { 5, 6, 6, 7, 8, 9, 9, 10, 10, 11, 12, 13, 13, 14, 14, 15 };
-
-// Coefficients for source bytes 0 to 10
-static uvec8 kMadd01 =
- { 3, 1, 2, 2, 1, 3, 3, 1, 2, 2, 1, 3, 3, 1, 2, 2 };
-
-// Coefficients for source bytes 10 to 21
-static uvec8 kMadd11 =
- { 1, 3, 3, 1, 2, 2, 1, 3, 3, 1, 2, 2, 1, 3, 3, 1 };
-
-// Coefficients for source bytes 21 to 31
-static uvec8 kMadd21 =
- { 2, 2, 1, 3, 3, 1, 2, 2, 1, 3, 3, 1, 2, 2, 1, 3 };
-
-// Coefficients for source bytes 21 to 31
-static vec16 kRound34 =
- { 2, 2, 2, 2, 2, 2, 2, 2 };
-
-static uvec8 kShuf38a =
- { 0, 3, 6, 8, 11, 14, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 };
-
-static uvec8 kShuf38b =
- { 128, 128, 128, 128, 128, 128, 0, 3, 6, 8, 11, 14, 128, 128, 128, 128 };
-
-// Arrange words 0,3,6 into 0,1,2
-static uvec8 kShufAc =
- { 0, 1, 6, 7, 12, 13, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 };
-
-// Arrange words 0,3,6 into 3,4,5
-static uvec8 kShufAc3 =
- { 128, 128, 128, 128, 128, 128, 0, 1, 6, 7, 12, 13, 128, 128, 128, 128 };
-
-// Scaling values for boxes of 3x3 and 2x3
-static uvec16 kScaleAc33 =
- { 65536 / 9, 65536 / 9, 65536 / 6, 65536 / 9, 65536 / 9, 65536 / 6, 0, 0 };
-
-// Arrange first value for pixels 0,1,2,3,4,5
-static uvec8 kShufAb0 =
- { 0, 128, 3, 128, 6, 128, 8, 128, 11, 128, 14, 128, 128, 128, 128, 128 };
-
-// Arrange second value for pixels 0,1,2,3,4,5
-static uvec8 kShufAb1 =
- { 1, 128, 4, 128, 7, 128, 9, 128, 12, 128, 15, 128, 128, 128, 128, 128 };
-
-// Arrange third value for pixels 0,1,2,3,4,5
-static uvec8 kShufAb2 =
- { 2, 128, 5, 128, 128, 128, 10, 128, 13, 128, 128, 128, 128, 128, 128, 128 };
-
-// Scaling values for boxes of 3x2 and 2x2
-static uvec16 kScaleAb2 =
- { 65536 / 3, 65536 / 3, 65536 / 2, 65536 / 3, 65536 / 3, 65536 / 2, 0, 0 };
-
-// Reads 32 pixels, throws half away and writes 16 pixels.
-// Alignment requirement: src_ptr 16 byte aligned, dst_ptr 16 byte aligned.
-__declspec(naked) __declspec(align(16))
-void ScaleRowDown2_SSE2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- __asm {
- mov eax, [esp + 4] // src_ptr
- // src_stride ignored
- mov edx, [esp + 12] // dst_ptr
- mov ecx, [esp + 16] // dst_width
-
- align 4
- wloop:
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- lea eax, [eax + 32]
- psrlw xmm0, 8 // isolate odd pixels.
- psrlw xmm1, 8
- packuswb xmm0, xmm1
- sub ecx, 16
- movdqa [edx], xmm0
- lea edx, [edx + 16]
- jg wloop
-
- ret
- }
-}
-
-// Blends 32x1 rectangle to 16x1.
-// Alignment requirement: src_ptr 16 byte aligned, dst_ptr 16 byte aligned.
-__declspec(naked) __declspec(align(16))
-void ScaleRowDown2Linear_SSE2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- __asm {
- mov eax, [esp + 4] // src_ptr
- // src_stride
- mov edx, [esp + 12] // dst_ptr
- mov ecx, [esp + 16] // dst_width
- pcmpeqb xmm5, xmm5 // generate mask 0x00ff00ff
- psrlw xmm5, 8
-
- align 4
- wloop:
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- lea eax, [eax + 32]
-
- movdqa xmm2, xmm0 // average columns (32 to 16 pixels)
- psrlw xmm0, 8
- movdqa xmm3, xmm1
- psrlw xmm1, 8
- pand xmm2, xmm5
- pand xmm3, xmm5
- pavgw xmm0, xmm2
- pavgw xmm1, xmm3
- packuswb xmm0, xmm1
-
- sub ecx, 16
- movdqa [edx], xmm0
- lea edx, [edx + 16]
- jg wloop
-
- ret
- }
-}
-
-// Blends 32x2 rectangle to 16x1.
-// Alignment requirement: src_ptr 16 byte aligned, dst_ptr 16 byte aligned.
-__declspec(naked) __declspec(align(16))
-void ScaleRowDown2Box_SSE2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- __asm {
- push esi
- mov eax, [esp + 4 + 4] // src_ptr
- mov esi, [esp + 4 + 8] // src_stride
- mov edx, [esp + 4 + 12] // dst_ptr
- mov ecx, [esp + 4 + 16] // dst_width
- pcmpeqb xmm5, xmm5 // generate mask 0x00ff00ff
- psrlw xmm5, 8
-
- align 4
- wloop:
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- movdqa xmm2, [eax + esi]
- movdqa xmm3, [eax + esi + 16]
- lea eax, [eax + 32]
- pavgb xmm0, xmm2 // average rows
- pavgb xmm1, xmm3
-
- movdqa xmm2, xmm0 // average columns (32 to 16 pixels)
- psrlw xmm0, 8
- movdqa xmm3, xmm1
- psrlw xmm1, 8
- pand xmm2, xmm5
- pand xmm3, xmm5
- pavgw xmm0, xmm2
- pavgw xmm1, xmm3
- packuswb xmm0, xmm1
-
- sub ecx, 16
- movdqa [edx], xmm0
- lea edx, [edx + 16]
- jg wloop
-
- pop esi
- ret
- }
-}
-
-// Reads 32 pixels, throws half away and writes 16 pixels.
-// Alignment requirement: src_ptr 16 byte aligned, dst_ptr 16 byte aligned.
-__declspec(naked) __declspec(align(16))
-void ScaleRowDown2_Unaligned_SSE2(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- __asm {
- mov eax, [esp + 4] // src_ptr
- // src_stride ignored
- mov edx, [esp + 12] // dst_ptr
- mov ecx, [esp + 16] // dst_width
-
- align 4
- wloop:
- movdqu xmm0, [eax]
- movdqu xmm1, [eax + 16]
- lea eax, [eax + 32]
- psrlw xmm0, 8 // isolate odd pixels.
- psrlw xmm1, 8
- packuswb xmm0, xmm1
- sub ecx, 16
- movdqu [edx], xmm0
- lea edx, [edx + 16]
- jg wloop
-
- ret
- }
-}
-
-// Blends 32x1 rectangle to 16x1.
-// Alignment requirement: src_ptr 16 byte aligned, dst_ptr 16 byte aligned.
-__declspec(naked) __declspec(align(16))
-void ScaleRowDown2Linear_Unaligned_SSE2(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- __asm {
- mov eax, [esp + 4] // src_ptr
- // src_stride
- mov edx, [esp + 12] // dst_ptr
- mov ecx, [esp + 16] // dst_width
- pcmpeqb xmm5, xmm5 // generate mask 0x00ff00ff
- psrlw xmm5, 8
-
- align 4
- wloop:
- movdqu xmm0, [eax]
- movdqu xmm1, [eax + 16]
- lea eax, [eax + 32]
-
- movdqa xmm2, xmm0 // average columns (32 to 16 pixels)
- psrlw xmm0, 8
- movdqa xmm3, xmm1
- psrlw xmm1, 8
- pand xmm2, xmm5
- pand xmm3, xmm5
- pavgw xmm0, xmm2
- pavgw xmm1, xmm3
- packuswb xmm0, xmm1
-
- sub ecx, 16
- movdqu [edx], xmm0
- lea edx, [edx + 16]
- jg wloop
-
- ret
- }
-}
-
-// Blends 32x2 rectangle to 16x1.
-// Alignment requirement: src_ptr 16 byte aligned, dst_ptr 16 byte aligned.
-__declspec(naked) __declspec(align(16))
-void ScaleRowDown2Box_Unaligned_SSE2(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- __asm {
- push esi
- mov eax, [esp + 4 + 4] // src_ptr
- mov esi, [esp + 4 + 8] // src_stride
- mov edx, [esp + 4 + 12] // dst_ptr
- mov ecx, [esp + 4 + 16] // dst_width
- pcmpeqb xmm5, xmm5 // generate mask 0x00ff00ff
- psrlw xmm5, 8
-
- align 4
- wloop:
- movdqu xmm0, [eax]
- movdqu xmm1, [eax + 16]
- movdqu xmm2, [eax + esi]
- movdqu xmm3, [eax + esi + 16]
- lea eax, [eax + 32]
- pavgb xmm0, xmm2 // average rows
- pavgb xmm1, xmm3
-
- movdqa xmm2, xmm0 // average columns (32 to 16 pixels)
- psrlw xmm0, 8
- movdqa xmm3, xmm1
- psrlw xmm1, 8
- pand xmm2, xmm5
- pand xmm3, xmm5
- pavgw xmm0, xmm2
- pavgw xmm1, xmm3
- packuswb xmm0, xmm1
-
- sub ecx, 16
- movdqu [edx], xmm0
- lea edx, [edx + 16]
- jg wloop
-
- pop esi
- ret
- }
-}
-
-// Point samples 32 pixels to 8 pixels.
-// Alignment requirement: src_ptr 16 byte aligned, dst_ptr 8 byte aligned.
-__declspec(naked) __declspec(align(16))
-void ScaleRowDown4_SSE2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- __asm {
- mov eax, [esp + 4] // src_ptr
- // src_stride ignored
- mov edx, [esp + 12] // dst_ptr
- mov ecx, [esp + 16] // dst_width
- pcmpeqb xmm5, xmm5 // generate mask 0x00ff0000
- psrld xmm5, 24
- pslld xmm5, 16
-
- align 4
- wloop:
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- lea eax, [eax + 32]
- pand xmm0, xmm5
- pand xmm1, xmm5
- packuswb xmm0, xmm1
- psrlw xmm0, 8
- packuswb xmm0, xmm0
- sub ecx, 8
- movq qword ptr [edx], xmm0
- lea edx, [edx + 8]
- jg wloop
-
- ret
- }
-}
-
-// Blends 32x4 rectangle to 8x1.
-// Alignment requirement: src_ptr 16 byte aligned, dst_ptr 8 byte aligned.
-__declspec(naked) __declspec(align(16))
-void ScaleRowDown4Box_SSE2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- __asm {
- push esi
- push edi
- mov eax, [esp + 8 + 4] // src_ptr
- mov esi, [esp + 8 + 8] // src_stride
- mov edx, [esp + 8 + 12] // dst_ptr
- mov ecx, [esp + 8 + 16] // dst_width
- lea edi, [esi + esi * 2] // src_stride * 3
- pcmpeqb xmm7, xmm7 // generate mask 0x00ff00ff
- psrlw xmm7, 8
-
- align 4
- wloop:
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- movdqa xmm2, [eax + esi]
- movdqa xmm3, [eax + esi + 16]
- pavgb xmm0, xmm2 // average rows
- pavgb xmm1, xmm3
- movdqa xmm2, [eax + esi * 2]
- movdqa xmm3, [eax + esi * 2 + 16]
- movdqa xmm4, [eax + edi]
- movdqa xmm5, [eax + edi + 16]
- lea eax, [eax + 32]
- pavgb xmm2, xmm4
- pavgb xmm3, xmm5
- pavgb xmm0, xmm2
- pavgb xmm1, xmm3
-
- movdqa xmm2, xmm0 // average columns (32 to 16 pixels)
- psrlw xmm0, 8
- movdqa xmm3, xmm1
- psrlw xmm1, 8
- pand xmm2, xmm7
- pand xmm3, xmm7
- pavgw xmm0, xmm2
- pavgw xmm1, xmm3
- packuswb xmm0, xmm1
-
- movdqa xmm2, xmm0 // average columns (16 to 8 pixels)
- psrlw xmm0, 8
- pand xmm2, xmm7
- pavgw xmm0, xmm2
- packuswb xmm0, xmm0
-
- sub ecx, 8
- movq qword ptr [edx], xmm0
- lea edx, [edx + 8]
- jg wloop
-
- pop edi
- pop esi
- ret
- }
-}
-
-// Point samples 32 pixels to 24 pixels.
-// Produces three 8 byte values. For each 8 bytes, 16 bytes are read.
-// Then shuffled to do the scaling.
-
-// Note that movdqa+palign may be better than movdqu.
-// Alignment requirement: src_ptr 16 byte aligned, dst_ptr 8 byte aligned.
-__declspec(naked) __declspec(align(16))
-void ScaleRowDown34_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- __asm {
- mov eax, [esp + 4] // src_ptr
- // src_stride ignored
- mov edx, [esp + 12] // dst_ptr
- mov ecx, [esp + 16] // dst_width
- movdqa xmm3, kShuf0
- movdqa xmm4, kShuf1
- movdqa xmm5, kShuf2
-
- align 4
- wloop:
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- lea eax, [eax + 32]
- movdqa xmm2, xmm1
- palignr xmm1, xmm0, 8
- pshufb xmm0, xmm3
- pshufb xmm1, xmm4
- pshufb xmm2, xmm5
- movq qword ptr [edx], xmm0
- movq qword ptr [edx + 8], xmm1
- movq qword ptr [edx + 16], xmm2
- lea edx, [edx + 24]
- sub ecx, 24
- jg wloop
-
- ret
- }
-}
-
-// Blends 32x2 rectangle to 24x1
-// Produces three 8 byte values. For each 8 bytes, 16 bytes are read.
-// Then shuffled to do the scaling.
-
-// Register usage:
-// xmm0 src_row 0
-// xmm1 src_row 1
-// xmm2 shuf 0
-// xmm3 shuf 1
-// xmm4 shuf 2
-// xmm5 madd 0
-// xmm6 madd 1
-// xmm7 kRound34
-
-// Note that movdqa+palign may be better than movdqu.
-// Alignment requirement: src_ptr 16 byte aligned, dst_ptr 8 byte aligned.
-__declspec(naked) __declspec(align(16))
-void ScaleRowDown34_1_Box_SSSE3(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- __asm {
- push esi
- mov eax, [esp + 4 + 4] // src_ptr
- mov esi, [esp + 4 + 8] // src_stride
- mov edx, [esp + 4 + 12] // dst_ptr
- mov ecx, [esp + 4 + 16] // dst_width
- movdqa xmm2, kShuf01
- movdqa xmm3, kShuf11
- movdqa xmm4, kShuf21
- movdqa xmm5, kMadd01
- movdqa xmm6, kMadd11
- movdqa xmm7, kRound34
-
- align 4
- wloop:
- movdqa xmm0, [eax] // pixels 0..7
- movdqa xmm1, [eax + esi]
- pavgb xmm0, xmm1
- pshufb xmm0, xmm2
- pmaddubsw xmm0, xmm5
- paddsw xmm0, xmm7
- psrlw xmm0, 2
- packuswb xmm0, xmm0
- movq qword ptr [edx], xmm0
- movdqu xmm0, [eax + 8] // pixels 8..15
- movdqu xmm1, [eax + esi + 8]
- pavgb xmm0, xmm1
- pshufb xmm0, xmm3
- pmaddubsw xmm0, xmm6
- paddsw xmm0, xmm7
- psrlw xmm0, 2
- packuswb xmm0, xmm0
- movq qword ptr [edx + 8], xmm0
- movdqa xmm0, [eax + 16] // pixels 16..23
- movdqa xmm1, [eax + esi + 16]
- lea eax, [eax + 32]
- pavgb xmm0, xmm1
- pshufb xmm0, xmm4
- movdqa xmm1, kMadd21
- pmaddubsw xmm0, xmm1
- paddsw xmm0, xmm7
- psrlw xmm0, 2
- packuswb xmm0, xmm0
- sub ecx, 24
- movq qword ptr [edx + 16], xmm0
- lea edx, [edx + 24]
- jg wloop
-
- pop esi
- ret
- }
-}
-
-// Note that movdqa+palign may be better than movdqu.
-// Alignment requirement: src_ptr 16 byte aligned, dst_ptr 8 byte aligned.
-__declspec(naked) __declspec(align(16))
-void ScaleRowDown34_0_Box_SSSE3(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- __asm {
- push esi
- mov eax, [esp + 4 + 4] // src_ptr
- mov esi, [esp + 4 + 8] // src_stride
- mov edx, [esp + 4 + 12] // dst_ptr
- mov ecx, [esp + 4 + 16] // dst_width
- movdqa xmm2, kShuf01
- movdqa xmm3, kShuf11
- movdqa xmm4, kShuf21
- movdqa xmm5, kMadd01
- movdqa xmm6, kMadd11
- movdqa xmm7, kRound34
-
- align 4
- wloop:
- movdqa xmm0, [eax] // pixels 0..7
- movdqa xmm1, [eax + esi]
- pavgb xmm1, xmm0
- pavgb xmm0, xmm1
- pshufb xmm0, xmm2
- pmaddubsw xmm0, xmm5
- paddsw xmm0, xmm7
- psrlw xmm0, 2
- packuswb xmm0, xmm0
- movq qword ptr [edx], xmm0
- movdqu xmm0, [eax + 8] // pixels 8..15
- movdqu xmm1, [eax + esi + 8]
- pavgb xmm1, xmm0
- pavgb xmm0, xmm1
- pshufb xmm0, xmm3
- pmaddubsw xmm0, xmm6
- paddsw xmm0, xmm7
- psrlw xmm0, 2
- packuswb xmm0, xmm0
- movq qword ptr [edx + 8], xmm0
- movdqa xmm0, [eax + 16] // pixels 16..23
- movdqa xmm1, [eax + esi + 16]
- lea eax, [eax + 32]
- pavgb xmm1, xmm0
- pavgb xmm0, xmm1
- pshufb xmm0, xmm4
- movdqa xmm1, kMadd21
- pmaddubsw xmm0, xmm1
- paddsw xmm0, xmm7
- psrlw xmm0, 2
- packuswb xmm0, xmm0
- sub ecx, 24
- movq qword ptr [edx + 16], xmm0
- lea edx, [edx+24]
- jg wloop
-
- pop esi
- ret
- }
-}
-
-// 3/8 point sampler
-
-// Scale 32 pixels to 12
-__declspec(naked) __declspec(align(16))
-void ScaleRowDown38_SSSE3(const uint8* src_ptr, ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- __asm {
- mov eax, [esp + 4] // src_ptr
- // src_stride ignored
- mov edx, [esp + 12] // dst_ptr
- mov ecx, [esp + 16] // dst_width
- movdqa xmm4, kShuf38a
- movdqa xmm5, kShuf38b
-
- align 4
- xloop:
- movdqa xmm0, [eax] // 16 pixels -> 0,1,2,3,4,5
- movdqa xmm1, [eax + 16] // 16 pixels -> 6,7,8,9,10,11
- lea eax, [eax + 32]
- pshufb xmm0, xmm4
- pshufb xmm1, xmm5
- paddusb xmm0, xmm1
-
- sub ecx, 12
- movq qword ptr [edx], xmm0 // write 12 pixels
- movhlps xmm1, xmm0
- movd [edx + 8], xmm1
- lea edx, [edx + 12]
- jg xloop
-
- ret
- }
-}
-
-// Scale 16x3 pixels to 6x1 with interpolation
-__declspec(naked) __declspec(align(16))
-void ScaleRowDown38_3_Box_SSSE3(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- __asm {
- push esi
- mov eax, [esp + 4 + 4] // src_ptr
- mov esi, [esp + 4 + 8] // src_stride
- mov edx, [esp + 4 + 12] // dst_ptr
- mov ecx, [esp + 4 + 16] // dst_width
- movdqa xmm2, kShufAc
- movdqa xmm3, kShufAc3
- movdqa xmm4, kScaleAc33
- pxor xmm5, xmm5
-
- align 4
- xloop:
- movdqa xmm0, [eax] // sum up 3 rows into xmm0/1
- movdqa xmm6, [eax + esi]
- movhlps xmm1, xmm0
- movhlps xmm7, xmm6
- punpcklbw xmm0, xmm5
- punpcklbw xmm1, xmm5
- punpcklbw xmm6, xmm5
- punpcklbw xmm7, xmm5
- paddusw xmm0, xmm6
- paddusw xmm1, xmm7
- movdqa xmm6, [eax + esi * 2]
- lea eax, [eax + 16]
- movhlps xmm7, xmm6
- punpcklbw xmm6, xmm5
- punpcklbw xmm7, xmm5
- paddusw xmm0, xmm6
- paddusw xmm1, xmm7
-
- movdqa xmm6, xmm0 // 8 pixels -> 0,1,2 of xmm6
- psrldq xmm0, 2
- paddusw xmm6, xmm0
- psrldq xmm0, 2
- paddusw xmm6, xmm0
- pshufb xmm6, xmm2
-
- movdqa xmm7, xmm1 // 8 pixels -> 3,4,5 of xmm6
- psrldq xmm1, 2
- paddusw xmm7, xmm1
- psrldq xmm1, 2
- paddusw xmm7, xmm1
- pshufb xmm7, xmm3
- paddusw xmm6, xmm7
-
- pmulhuw xmm6, xmm4 // divide by 9,9,6, 9,9,6
- packuswb xmm6, xmm6
-
- sub ecx, 6
- movd [edx], xmm6 // write 6 pixels
- psrlq xmm6, 16
- movd [edx + 2], xmm6
- lea edx, [edx + 6]
- jg xloop
-
- pop esi
- ret
- }
-}
-
-// Scale 16x2 pixels to 6x1 with interpolation
-__declspec(naked) __declspec(align(16))
-void ScaleRowDown38_2_Box_SSSE3(const uint8* src_ptr,
- ptrdiff_t src_stride,
- uint8* dst_ptr, int dst_width) {
- __asm {
- push esi
- mov eax, [esp + 4 + 4] // src_ptr
- mov esi, [esp + 4 + 8] // src_stride
- mov edx, [esp + 4 + 12] // dst_ptr
- mov ecx, [esp + 4 + 16] // dst_width
- movdqa xmm2, kShufAb0
- movdqa xmm3, kShufAb1
- movdqa xmm4, kShufAb2
- movdqa xmm5, kScaleAb2
-
- align 4
- xloop:
- movdqa xmm0, [eax] // average 2 rows into xmm0
- pavgb xmm0, [eax + esi]
- lea eax, [eax + 16]
-
- movdqa xmm1, xmm0 // 16 pixels -> 0,1,2,3,4,5 of xmm1
- pshufb xmm1, xmm2
- movdqa xmm6, xmm0
- pshufb xmm6, xmm3
- paddusw xmm1, xmm6
- pshufb xmm0, xmm4
- paddusw xmm1, xmm0
-
- pmulhuw xmm1, xmm5 // divide by 3,3,2, 3,3,2
- packuswb xmm1, xmm1
-
- sub ecx, 6
- movd [edx], xmm1 // write 6 pixels
- psrlq xmm1, 16
- movd [edx + 2], xmm1
- lea edx, [edx + 6]
- jg xloop
-
- pop esi
- ret
- }
-}
-
-// Reads 16xN bytes and produces 16 shorts at a time.
-// TODO(fbarchard): Make this handle 4xN bytes for any width ARGB.
-__declspec(naked) __declspec(align(16))
-void ScaleAddRows_SSE2(const uint8* src_ptr, ptrdiff_t src_stride,
- uint16* dst_ptr, int src_width,
- int src_height) {
- __asm {
- push esi
- push edi
- push ebx
- push ebp
- mov esi, [esp + 16 + 4] // src_ptr
- mov edx, [esp + 16 + 8] // src_stride
- mov edi, [esp + 16 + 12] // dst_ptr
- mov ecx, [esp + 16 + 16] // dst_width
- mov ebx, [esp + 16 + 20] // height
- pxor xmm4, xmm4
- dec ebx
-
- align 4
- xloop:
- // first row
- movdqa xmm0, [esi]
- lea eax, [esi + edx]
- movdqa xmm1, xmm0
- punpcklbw xmm0, xmm4
- punpckhbw xmm1, xmm4
- lea esi, [esi + 16]
- mov ebp, ebx
- test ebp, ebp
- je ydone
-
- // sum remaining rows
- align 4
- yloop:
- movdqa xmm2, [eax] // read 16 pixels
- lea eax, [eax + edx] // advance to next row
- movdqa xmm3, xmm2
- punpcklbw xmm2, xmm4
- punpckhbw xmm3, xmm4
- paddusw xmm0, xmm2 // sum 16 words
- paddusw xmm1, xmm3
- sub ebp, 1
- jg yloop
-
- align 4
- ydone:
- movdqa [edi], xmm0
- movdqa [edi + 16], xmm1
- lea edi, [edi + 32]
-
- sub ecx, 16
- jg xloop
-
- pop ebp
- pop ebx
- pop edi
- pop esi
- ret
- }
-}
-
-// Bilinear column filtering. SSSE3 version.
-// TODO(fbarchard): Port to Neon
-// TODO(fbarchard): Switch the following:
-// xor ebx, ebx
-// mov bx, word ptr [esi + eax] // 2 source x0 pixels
-// To
-// movzx ebx, word ptr [esi + eax] // 2 source x0 pixels
-// when drmemory bug fixed.
-// https://code.google.com/p/drmemory/issues/detail?id=1396
-
-__declspec(naked) __declspec(align(16))
-void ScaleFilterCols_SSSE3(uint8* dst_ptr, const uint8* src_ptr,
- int dst_width, int x, int dx) {
- __asm {
- push ebx
- push esi
- push edi
- mov edi, [esp + 12 + 4] // dst_ptr
- mov esi, [esp + 12 + 8] // src_ptr
- mov ecx, [esp + 12 + 12] // dst_width
- movd xmm2, [esp + 12 + 16] // x
- movd xmm3, [esp + 12 + 20] // dx
- mov eax, 0x04040000 // shuffle to line up fractions with pixel.
- movd xmm5, eax
- pcmpeqb xmm6, xmm6 // generate 0x007f for inverting fraction.
- psrlw xmm6, 9
- pextrw eax, xmm2, 1 // get x0 integer. preroll
- sub ecx, 2
- jl xloop29
-
- movdqa xmm0, xmm2 // x1 = x0 + dx
- paddd xmm0, xmm3
- punpckldq xmm2, xmm0 // x0 x1
- punpckldq xmm3, xmm3 // dx dx
- paddd xmm3, xmm3 // dx * 2, dx * 2
- pextrw edx, xmm2, 3 // get x1 integer. preroll
-
- // 2 Pixel loop.
- align 4
- xloop2:
- movdqa xmm1, xmm2 // x0, x1 fractions.
- paddd xmm2, xmm3 // x += dx
- movzx ebx, word ptr [esi + eax] // 2 source x0 pixels
- movd xmm0, ebx
- psrlw xmm1, 9 // 7 bit fractions.
- movzx ebx, word ptr [esi + edx] // 2 source x1 pixels
- movd xmm4, ebx
- pshufb xmm1, xmm5 // 0011
- punpcklwd xmm0, xmm4
- pxor xmm1, xmm6 // 0..7f and 7f..0
- pmaddubsw xmm0, xmm1 // 16 bit, 2 pixels.
- pextrw eax, xmm2, 1 // get x0 integer. next iteration.
- pextrw edx, xmm2, 3 // get x1 integer. next iteration.
- psrlw xmm0, 7 // 8.7 fixed point to low 8 bits.
- packuswb xmm0, xmm0 // 8 bits, 2 pixels.
- movd ebx, xmm0
- mov [edi], bx
- lea edi, [edi + 2]
- sub ecx, 2 // 2 pixels
- jge xloop2
-
- align 4
- xloop29:
-
- add ecx, 2 - 1
- jl xloop99
-
- // 1 pixel remainder
- movzx ebx, word ptr [esi + eax] // 2 source x0 pixels
- movd xmm0, ebx
- psrlw xmm2, 9 // 7 bit fractions.
- pshufb xmm2, xmm5 // 0011
- pxor xmm2, xmm6 // 0..7f and 7f..0
- pmaddubsw xmm0, xmm2 // 16 bit
- psrlw xmm0, 7 // 8.7 fixed point to low 8 bits.
- packuswb xmm0, xmm0 // 8 bits
- movd ebx, xmm0
- mov [edi], bl
-
- align 4
- xloop99:
-
- pop edi
- pop esi
- pop ebx
- ret
- }
-}
-
-// Reads 16 pixels, duplicates them and writes 32 pixels.
-// Alignment requirement: src_argb 16 byte aligned, dst_argb 16 byte aligned.
-__declspec(naked) __declspec(align(16))
-void ScaleColsUp2_SSE2(uint8* dst_ptr, const uint8* src_ptr,
- int dst_width, int x, int dx) {
- __asm {
- mov edx, [esp + 4] // dst_ptr
- mov eax, [esp + 8] // src_ptr
- mov ecx, [esp + 12] // dst_width
-
- align 4
- wloop:
- movdqa xmm0, [eax]
- lea eax, [eax + 16]
- movdqa xmm1, xmm0
- punpcklbw xmm0, xmm0
- punpckhbw xmm1, xmm1
- sub ecx, 32
- movdqa [edx], xmm0
- movdqa [edx + 16], xmm1
- lea edx, [edx + 32]
- jg wloop
-
- ret
- }
-}
-
-// Reads 8 pixels, throws half away and writes 4 even pixels (0, 2, 4, 6)
-// Alignment requirement: src_argb 16 byte aligned, dst_argb 16 byte aligned.
-__declspec(naked) __declspec(align(16))
-void ScaleARGBRowDown2_SSE2(const uint8* src_argb,
- ptrdiff_t src_stride,
- uint8* dst_argb, int dst_width) {
- __asm {
- mov eax, [esp + 4] // src_argb
- // src_stride ignored
- mov edx, [esp + 12] // dst_argb
- mov ecx, [esp + 16] // dst_width
-
- align 4
- wloop:
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- lea eax, [eax + 32]
- shufps xmm0, xmm1, 0xdd
- sub ecx, 4
- movdqa [edx], xmm0
- lea edx, [edx + 16]
- jg wloop
-
- ret
- }
-}
-
-// Blends 8x1 rectangle to 4x1.
-// Alignment requirement: src_argb 16 byte aligned, dst_argb 16 byte aligned.
-__declspec(naked) __declspec(align(16))
-void ScaleARGBRowDown2Linear_SSE2(const uint8* src_argb,
- ptrdiff_t src_stride,
- uint8* dst_argb, int dst_width) {
- __asm {
- mov eax, [esp + 4] // src_argb
- // src_stride ignored
- mov edx, [esp + 12] // dst_argb
- mov ecx, [esp + 16] // dst_width
-
- align 4
- wloop:
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- lea eax, [eax + 32]
- movdqa xmm2, xmm0
- shufps xmm0, xmm1, 0x88 // even pixels
- shufps xmm2, xmm1, 0xdd // odd pixels
- pavgb xmm0, xmm2
- sub ecx, 4
- movdqa [edx], xmm0
- lea edx, [edx + 16]
- jg wloop
-
- ret
- }
-}
-
-// Blends 8x2 rectangle to 4x1.
-// Alignment requirement: src_argb 16 byte aligned, dst_argb 16 byte aligned.
-__declspec(naked) __declspec(align(16))
-void ScaleARGBRowDown2Box_SSE2(const uint8* src_argb,
- ptrdiff_t src_stride,
- uint8* dst_argb, int dst_width) {
- __asm {
- push esi
- mov eax, [esp + 4 + 4] // src_argb
- mov esi, [esp + 4 + 8] // src_stride
- mov edx, [esp + 4 + 12] // dst_argb
- mov ecx, [esp + 4 + 16] // dst_width
-
- align 4
- wloop:
- movdqa xmm0, [eax]
- movdqa xmm1, [eax + 16]
- movdqa xmm2, [eax + esi]
- movdqa xmm3, [eax + esi + 16]
- lea eax, [eax + 32]
- pavgb xmm0, xmm2 // average rows
- pavgb xmm1, xmm3
- movdqa xmm2, xmm0 // average columns (8 to 4 pixels)
- shufps xmm0, xmm1, 0x88 // even pixels
- shufps xmm2, xmm1, 0xdd // odd pixels
- pavgb xmm0, xmm2
- sub ecx, 4
- movdqa [edx], xmm0
- lea edx, [edx + 16]
- jg wloop
-
- pop esi
- ret
- }
-}
-
-// Reads 4 pixels at a time.
-// Alignment requirement: dst_argb 16 byte aligned.
-__declspec(naked) __declspec(align(16))
-void ScaleARGBRowDownEven_SSE2(const uint8* src_argb, ptrdiff_t src_stride,
- int src_stepx,
- uint8* dst_argb, int dst_width) {
- __asm {
- push ebx
- push edi
- mov eax, [esp + 8 + 4] // src_argb
- // src_stride ignored
- mov ebx, [esp + 8 + 12] // src_stepx
- mov edx, [esp + 8 + 16] // dst_argb
- mov ecx, [esp + 8 + 20] // dst_width
- lea ebx, [ebx * 4]
- lea edi, [ebx + ebx * 2]
-
- align 4
- wloop:
- movd xmm0, [eax]
- movd xmm1, [eax + ebx]
- punpckldq xmm0, xmm1
- movd xmm2, [eax + ebx * 2]
- movd xmm3, [eax + edi]
- lea eax, [eax + ebx * 4]
- punpckldq xmm2, xmm3
- punpcklqdq xmm0, xmm2
- sub ecx, 4
- movdqa [edx], xmm0
- lea edx, [edx + 16]
- jg wloop
-
- pop edi
- pop ebx
- ret
- }
-}
-
-// Blends four 2x2 to 4x1.
-// Alignment requirement: dst_argb 16 byte aligned.
-__declspec(naked) __declspec(align(16))
-void ScaleARGBRowDownEvenBox_SSE2(const uint8* src_argb,
- ptrdiff_t src_stride,
- int src_stepx,
- uint8* dst_argb, int dst_width) {
- __asm {
- push ebx
- push esi
- push edi
- mov eax, [esp + 12 + 4] // src_argb
- mov esi, [esp + 12 + 8] // src_stride
- mov ebx, [esp + 12 + 12] // src_stepx
- mov edx, [esp + 12 + 16] // dst_argb
- mov ecx, [esp + 12 + 20] // dst_width
- lea esi, [eax + esi] // row1 pointer
- lea ebx, [ebx * 4]
- lea edi, [ebx + ebx * 2]
-
- align 4
- wloop:
- movq xmm0, qword ptr [eax] // row0 4 pairs
- movhps xmm0, qword ptr [eax + ebx]
- movq xmm1, qword ptr [eax + ebx * 2]
- movhps xmm1, qword ptr [eax + edi]
- lea eax, [eax + ebx * 4]
- movq xmm2, qword ptr [esi] // row1 4 pairs
- movhps xmm2, qword ptr [esi + ebx]
- movq xmm3, qword ptr [esi + ebx * 2]
- movhps xmm3, qword ptr [esi + edi]
- lea esi, [esi + ebx * 4]
- pavgb xmm0, xmm2 // average rows
- pavgb xmm1, xmm3
- movdqa xmm2, xmm0 // average columns (8 to 4 pixels)
- shufps xmm0, xmm1, 0x88 // even pixels
- shufps xmm2, xmm1, 0xdd // odd pixels
- pavgb xmm0, xmm2
- sub ecx, 4
- movdqa [edx], xmm0
- lea edx, [edx + 16]
- jg wloop
-
- pop edi
- pop esi
- pop ebx
- ret
- }
-}
-
-// Column scaling unfiltered. SSE2 version.
-__declspec(naked) __declspec(align(16))
-void ScaleARGBCols_SSE2(uint8* dst_argb, const uint8* src_argb,
- int dst_width, int x, int dx) {
- __asm {
- push edi
- push esi
- mov edi, [esp + 8 + 4] // dst_argb
- mov esi, [esp + 8 + 8] // src_argb
- mov ecx, [esp + 8 + 12] // dst_width
- movd xmm2, [esp + 8 + 16] // x
- movd xmm3, [esp + 8 + 20] // dx
-
- pshufd xmm2, xmm2, 0 // x0 x0 x0 x0
- pshufd xmm0, xmm3, 0x11 // dx 0 dx 0
- paddd xmm2, xmm0
- paddd xmm3, xmm3 // 0, 0, 0, dx * 2
- pshufd xmm0, xmm3, 0x05 // dx * 2, dx * 2, 0, 0
- paddd xmm2, xmm0 // x3 x2 x1 x0
- paddd xmm3, xmm3 // 0, 0, 0, dx * 4
- pshufd xmm3, xmm3, 0 // dx * 4, dx * 4, dx * 4, dx * 4
-
- pextrw eax, xmm2, 1 // get x0 integer.
- pextrw edx, xmm2, 3 // get x1 integer.
-
- cmp ecx, 0
- jle xloop99
- sub ecx, 4
- jl xloop49
-
- // 4 Pixel loop.
- align 4
- xloop4:
- movd xmm0, [esi + eax * 4] // 1 source x0 pixels
- movd xmm1, [esi + edx * 4] // 1 source x1 pixels
- pextrw eax, xmm2, 5 // get x2 integer.
- pextrw edx, xmm2, 7 // get x3 integer.
- paddd xmm2, xmm3 // x += dx
- punpckldq xmm0, xmm1 // x0 x1
-
- movd xmm1, [esi + eax * 4] // 1 source x2 pixels
- movd xmm4, [esi + edx * 4] // 1 source x3 pixels
- pextrw eax, xmm2, 1 // get x0 integer. next iteration.
- pextrw edx, xmm2, 3 // get x1 integer. next iteration.
- punpckldq xmm1, xmm4 // x2 x3
- punpcklqdq xmm0, xmm1 // x0 x1 x2 x3
- sub ecx, 4 // 4 pixels
- movdqu [edi], xmm0
- lea edi, [edi + 16]
- jge xloop4
-
- align 4
- xloop49:
- test ecx, 2
- je xloop29
-
- // 2 Pixels.
- movd xmm0, [esi + eax * 4] // 1 source x0 pixels
- movd xmm1, [esi + edx * 4] // 1 source x1 pixels
- pextrw eax, xmm2, 5 // get x2 integer.
- punpckldq xmm0, xmm1 // x0 x1
-
- movq qword ptr [edi], xmm0
- lea edi, [edi + 8]
-
- xloop29:
- test ecx, 1
- je xloop99
-
- // 1 Pixels.
- movd xmm0, [esi + eax * 4] // 1 source x2 pixels
- movd dword ptr [edi], xmm0
- align 4
- xloop99:
-
- pop esi
- pop edi
- ret
- }
-}
-
-// Bilinear row filtering combines 2x1 -> 1x1. SSSE3 version.
-// TODO(fbarchard): Port to Neon
-
-// Shuffle table for arranging 2 pixels into pairs for pmaddubsw
-static uvec8 kShuffleColARGB = {
- 0u, 4u, 1u, 5u, 2u, 6u, 3u, 7u, // bbggrraa 1st pixel
- 8u, 12u, 9u, 13u, 10u, 14u, 11u, 15u // bbggrraa 2nd pixel
-};
-
-// Shuffle table for duplicating 2 fractions into 8 bytes each
-static uvec8 kShuffleFractions = {
- 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 4u, 4u, 4u, 4u, 4u, 4u, 4u, 4u,
-};
-
-__declspec(naked) __declspec(align(16))
-void ScaleARGBFilterCols_SSSE3(uint8* dst_argb, const uint8* src_argb,
- int dst_width, int x, int dx) {
- __asm {
- push esi
- push edi
- mov edi, [esp + 8 + 4] // dst_argb
- mov esi, [esp + 8 + 8] // src_argb
- mov ecx, [esp + 8 + 12] // dst_width
- movd xmm2, [esp + 8 + 16] // x
- movd xmm3, [esp + 8 + 20] // dx
- movdqa xmm4, kShuffleColARGB
- movdqa xmm5, kShuffleFractions
- pcmpeqb xmm6, xmm6 // generate 0x007f for inverting fraction.
- psrlw xmm6, 9
- pextrw eax, xmm2, 1 // get x0 integer. preroll
- sub ecx, 2
- jl xloop29
-
- movdqa xmm0, xmm2 // x1 = x0 + dx
- paddd xmm0, xmm3
- punpckldq xmm2, xmm0 // x0 x1
- punpckldq xmm3, xmm3 // dx dx
- paddd xmm3, xmm3 // dx * 2, dx * 2
- pextrw edx, xmm2, 3 // get x1 integer. preroll
-
- // 2 Pixel loop.
- align 4
- xloop2:
- movdqa xmm1, xmm2 // x0, x1 fractions.
- paddd xmm2, xmm3 // x += dx
- movq xmm0, qword ptr [esi + eax * 4] // 2 source x0 pixels
- psrlw xmm1, 9 // 7 bit fractions.
- movhps xmm0, qword ptr [esi + edx * 4] // 2 source x1 pixels
- pshufb xmm1, xmm5 // 0000000011111111
- pshufb xmm0, xmm4 // arrange pixels into pairs
- pxor xmm1, xmm6 // 0..7f and 7f..0
- pmaddubsw xmm0, xmm1 // argb_argb 16 bit, 2 pixels.
- pextrw eax, xmm2, 1 // get x0 integer. next iteration.
- pextrw edx, xmm2, 3 // get x1 integer. next iteration.
- psrlw xmm0, 7 // argb 8.7 fixed point to low 8 bits.
- packuswb xmm0, xmm0 // argb_argb 8 bits, 2 pixels.
- movq qword ptr [edi], xmm0
- lea edi, [edi + 8]
- sub ecx, 2 // 2 pixels
- jge xloop2
-
- align 4
- xloop29:
-
- add ecx, 2 - 1
- jl xloop99
-
- // 1 pixel remainder
- psrlw xmm2, 9 // 7 bit fractions.
- movq xmm0, qword ptr [esi + eax * 4] // 2 source x0 pixels
- pshufb xmm2, xmm5 // 00000000
- pshufb xmm0, xmm4 // arrange pixels into pairs
- pxor xmm2, xmm6 // 0..7f and 7f..0
- pmaddubsw xmm0, xmm2 // argb 16 bit, 1 pixel.
- psrlw xmm0, 7
- packuswb xmm0, xmm0 // argb 8 bits, 1 pixel.
- movd [edi], xmm0
-
- align 4
- xloop99:
-
- pop edi
- pop esi
- ret
- }
-}
-
-// Reads 4 pixels, duplicates them and writes 8 pixels.
-// Alignment requirement: src_argb 16 byte aligned, dst_argb 16 byte aligned.
-__declspec(naked) __declspec(align(16))
-void ScaleARGBColsUp2_SSE2(uint8* dst_argb, const uint8* src_argb,
- int dst_width, int x, int dx) {
- __asm {
- mov edx, [esp + 4] // dst_argb
- mov eax, [esp + 8] // src_argb
- mov ecx, [esp + 12] // dst_width
-
- align 4
- wloop:
- movdqa xmm0, [eax]
- lea eax, [eax + 16]
- movdqa xmm1, xmm0
- punpckldq xmm0, xmm0
- punpckhdq xmm1, xmm1
- sub ecx, 8
- movdqa [edx], xmm0
- movdqa [edx + 16], xmm1
- lea edx, [edx + 32]
- jg wloop
-
- ret
- }
-}
-
-// Divide num by div and return as 16.16 fixed point result.
-__declspec(naked) __declspec(align(16))
-int FixedDiv_X86(int num, int div) {
- __asm {
- mov eax, [esp + 4] // num
- cdq // extend num to 64 bits
- shld edx, eax, 16 // 32.16
- shl eax, 16
- idiv dword ptr [esp + 8]
- ret
- }
-}
-
-// Divide num by div and return as 16.16 fixed point result.
-__declspec(naked) __declspec(align(16))
-int FixedDiv1_X86(int num, int div) {
- __asm {
- mov eax, [esp + 4] // num
- mov ecx, [esp + 8] // denom
- cdq // extend num to 64 bits
- shld edx, eax, 16 // 32.16
- shl eax, 16
- sub eax, 0x00010001
- sbb edx, 0
- sub ecx, 1
- idiv ecx
- ret
- }
-}
-
-#endif // !defined(LIBYUV_DISABLE_X86) && defined(_M_IX86) && defined(_MSC_VER)
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/video_common.cc b/drivers/theoraplayer/src/YUV/libyuv/src/video_common.cc
deleted file mode 100755
index efbedf46e2..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/video_common.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2011 The LibYuv Project Authors. All rights reserved.
- *
- * Use of this source code is governed by a BSD-style license
- * that can be found in the LICENSE file in the root of the source
- * tree. An additional intellectual property rights grant can be found
- * in the file PATENTS. All contributing project authors may
- * be found in the AUTHORS file in the root of the source tree.
- */
-
-
-#include "libyuv/video_common.h"
-
-#ifdef __cplusplus
-namespace libyuv {
-extern "C" {
-#endif
-
-#define ARRAY_SIZE(x) (int)(sizeof(x) / sizeof(x[0]))
-
-struct FourCCAliasEntry {
- uint32 alias;
- uint32 canonical;
-};
-
-static const struct FourCCAliasEntry kFourCCAliases[] = {
- {FOURCC_IYUV, FOURCC_I420},
- {FOURCC_YU16, FOURCC_I422},
- {FOURCC_YU24, FOURCC_I444},
- {FOURCC_YUYV, FOURCC_YUY2},
- {FOURCC_YUVS, FOURCC_YUY2}, // kCMPixelFormat_422YpCbCr8_yuvs
- {FOURCC_HDYC, FOURCC_UYVY},
- {FOURCC_2VUY, FOURCC_UYVY}, // kCMPixelFormat_422YpCbCr8
- {FOURCC_JPEG, FOURCC_MJPG}, // Note: JPEG has DHT while MJPG does not.
- {FOURCC_DMB1, FOURCC_MJPG},
- {FOURCC_BA81, FOURCC_BGGR},
- {FOURCC_RGB3, FOURCC_RAW },
- {FOURCC_BGR3, FOURCC_24BG},
- {FOURCC_CM32, FOURCC_BGRA}, // kCMPixelFormat_32ARGB
- {FOURCC_CM24, FOURCC_RAW }, // kCMPixelFormat_24RGB
- {FOURCC_L555, FOURCC_RGBO}, // kCMPixelFormat_16LE555
- {FOURCC_L565, FOURCC_RGBP}, // kCMPixelFormat_16LE565
- {FOURCC_5551, FOURCC_RGBO}, // kCMPixelFormat_16LE5551
-};
-// TODO(fbarchard): Consider mapping kCMPixelFormat_32BGRA to FOURCC_ARGB.
-// {FOURCC_BGRA, FOURCC_ARGB}, // kCMPixelFormat_32BGRA
-
-LIBYUV_API
-uint32 CanonicalFourCC(uint32 fourcc) {
- int i;
- for (i = 0; i < ARRAY_SIZE(kFourCCAliases); ++i) {
- if (kFourCCAliases[i].alias == fourcc) {
- return kFourCCAliases[i].canonical;
- }
- }
- // Not an alias, so return it as-is.
- return fourcc;
-}
-
-#ifdef __cplusplus
-} // extern "C"
-} // namespace libyuv
-#endif
-
diff --git a/drivers/theoraplayer/src/YUV/libyuv/src/x86inc.asm b/drivers/theoraplayer/src/YUV/libyuv/src/x86inc.asm
deleted file mode 100755
index cb5c32df3a..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/src/x86inc.asm
+++ /dev/null
@@ -1,1136 +0,0 @@
-;*****************************************************************************
-;* x86inc.asm: x264asm abstraction layer
-;*****************************************************************************
-;* Copyright (C) 2005-2012 x264 project
-;*
-;* Authors: Loren Merritt <lorenm@u.washington.edu>
-;* Anton Mitrofanov <BugMaster@narod.ru>
-;* Jason Garrett-Glaser <darkshikari@gmail.com>
-;* Henrik Gramner <hengar-6@student.ltu.se>
-;*
-;* Permission to use, copy, modify, and/or distribute this software for any
-;* purpose with or without fee is hereby granted, provided that the above
-;* copyright notice and this permission notice appear in all copies.
-;*
-;* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-;* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-;* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-;* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-;* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-;* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-;* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-;*****************************************************************************
-
-; This is a header file for the x264ASM assembly language, which uses
-; NASM/YASM syntax combined with a large number of macros to provide easy
-; abstraction between different calling conventions (x86_32, win64, linux64).
-; It also has various other useful features to simplify writing the kind of
-; DSP functions that are most often used in x264.
-
-; Unlike the rest of x264, this file is available under an ISC license, as it
-; has significant usefulness outside of x264 and we want it to be available
-; to the largest audience possible. Of course, if you modify it for your own
-; purposes to add a new feature, we strongly encourage contributing a patch
-; as this feature might be useful for others as well. Send patches or ideas
-; to x264-devel@videolan.org .
-
-; Local changes for libyuv:
-; remove %define program_name and references in labels
-; rename cpus to uppercase
-
-%define WIN64 0
-%define UNIX64 0
-%if ARCH_X86_64
- %ifidn __OUTPUT_FORMAT__,win32
- %define WIN64 1
- %elifidn __OUTPUT_FORMAT__,win64
- %define WIN64 1
- %else
- %define UNIX64 1
- %endif
-%endif
-
-%ifdef PREFIX
- %define mangle(x) _ %+ x
-%else
- %define mangle(x) x
-%endif
-
-; Name of the .rodata section.
-; Kludge: Something on OS X fails to align .rodata even given an align attribute,
-; so use a different read-only section.
-%macro SECTION_RODATA 0-1 16
- %ifidn __OUTPUT_FORMAT__,macho64
- SECTION .text align=%1
- %elifidn __OUTPUT_FORMAT__,macho
- SECTION .text align=%1
- fakegot:
- %elifidn __OUTPUT_FORMAT__,aout
- section .text
- %else
- SECTION .rodata align=%1
- %endif
-%endmacro
-
-; aout does not support align=
-%macro SECTION_TEXT 0-1 16
- %ifidn __OUTPUT_FORMAT__,aout
- SECTION .text
- %else
- SECTION .text align=%1
- %endif
-%endmacro
-
-%if WIN64
- %define PIC
-%elif ARCH_X86_64 == 0
-; x86_32 doesn't require PIC.
-; Some distros prefer shared objects to be PIC, but nothing breaks if
-; the code contains a few textrels, so we'll skip that complexity.
- %undef PIC
-%endif
-%ifdef PIC
- default rel
-%endif
-
-; Always use long nops (reduces 0x90 spam in disassembly on x86_32)
-CPU amdnop
-
-; Macros to eliminate most code duplication between x86_32 and x86_64:
-; Currently this works only for leaf functions which load all their arguments
-; into registers at the start, and make no other use of the stack. Luckily that
-; covers most of x264's asm.
-
-; PROLOGUE:
-; %1 = number of arguments. loads them from stack if needed.
-; %2 = number of registers used. pushes callee-saved regs if needed.
-; %3 = number of xmm registers used. pushes callee-saved xmm regs if needed.
-; %4 = list of names to define to registers
-; PROLOGUE can also be invoked by adding the same options to cglobal
-
-; e.g.
-; cglobal foo, 2,3,0, dst, src, tmp
-; declares a function (foo), taking two args (dst and src) and one local variable (tmp)
-
-; TODO Some functions can use some args directly from the stack. If they're the
-; last args then you can just not declare them, but if they're in the middle
-; we need more flexible macro.
-
-; RET:
-; Pops anything that was pushed by PROLOGUE, and returns.
-
-; REP_RET:
-; Same, but if it doesn't pop anything it becomes a 2-byte ret, for athlons
-; which are slow when a normal ret follows a branch.
-
-; registers:
-; rN and rNq are the native-size register holding function argument N
-; rNd, rNw, rNb are dword, word, and byte size
-; rNh is the high 8 bits of the word size
-; rNm is the original location of arg N (a register or on the stack), dword
-; rNmp is native size
-
-%macro DECLARE_REG 2-3
- %define r%1q %2
- %define r%1d %2d
- %define r%1w %2w
- %define r%1b %2b
- %define r%1h %2h
- %if %0 == 2
- %define r%1m %2d
- %define r%1mp %2
- %elif ARCH_X86_64 ; memory
- %define r%1m [rsp + stack_offset + %3]
- %define r%1mp qword r %+ %1m
- %else
- %define r%1m [esp + stack_offset + %3]
- %define r%1mp dword r %+ %1m
- %endif
- %define r%1 %2
-%endmacro
-
-%macro DECLARE_REG_SIZE 3
- %define r%1q r%1
- %define e%1q r%1
- %define r%1d e%1
- %define e%1d e%1
- %define r%1w %1
- %define e%1w %1
- %define r%1h %3
- %define e%1h %3
- %define r%1b %2
- %define e%1b %2
-%if ARCH_X86_64 == 0
- %define r%1 e%1
-%endif
-%endmacro
-
-DECLARE_REG_SIZE ax, al, ah
-DECLARE_REG_SIZE bx, bl, bh
-DECLARE_REG_SIZE cx, cl, ch
-DECLARE_REG_SIZE dx, dl, dh
-DECLARE_REG_SIZE si, sil, null
-DECLARE_REG_SIZE di, dil, null
-DECLARE_REG_SIZE bp, bpl, null
-
-; t# defines for when per-arch register allocation is more complex than just function arguments
-
-%macro DECLARE_REG_TMP 1-*
- %assign %%i 0
- %rep %0
- CAT_XDEFINE t, %%i, r%1
- %assign %%i %%i+1
- %rotate 1
- %endrep
-%endmacro
-
-%macro DECLARE_REG_TMP_SIZE 0-*
- %rep %0
- %define t%1q t%1 %+ q
- %define t%1d t%1 %+ d
- %define t%1w t%1 %+ w
- %define t%1h t%1 %+ h
- %define t%1b t%1 %+ b
- %rotate 1
- %endrep
-%endmacro
-
-DECLARE_REG_TMP_SIZE 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14
-
-%if ARCH_X86_64
- %define gprsize 8
-%else
- %define gprsize 4
-%endif
-
-%macro PUSH 1
- push %1
- %assign stack_offset stack_offset+gprsize
-%endmacro
-
-%macro POP 1
- pop %1
- %assign stack_offset stack_offset-gprsize
-%endmacro
-
-%macro PUSH_IF_USED 1-*
- %rep %0
- %if %1 < regs_used
- PUSH r%1
- %endif
- %rotate 1
- %endrep
-%endmacro
-
-%macro POP_IF_USED 1-*
- %rep %0
- %if %1 < regs_used
- pop r%1
- %endif
- %rotate 1
- %endrep
-%endmacro
-
-%macro LOAD_IF_USED 1-*
- %rep %0
- %if %1 < num_args
- mov r%1, r %+ %1 %+ mp
- %endif
- %rotate 1
- %endrep
-%endmacro
-
-%macro SUB 2
- sub %1, %2
- %ifidn %1, rsp
- %assign stack_offset stack_offset+(%2)
- %endif
-%endmacro
-
-%macro ADD 2
- add %1, %2
- %ifidn %1, rsp
- %assign stack_offset stack_offset-(%2)
- %endif
-%endmacro
-
-%macro movifnidn 2
- %ifnidn %1, %2
- mov %1, %2
- %endif
-%endmacro
-
-%macro movsxdifnidn 2
- %ifnidn %1, %2
- movsxd %1, %2
- %endif
-%endmacro
-
-%macro ASSERT 1
- %if (%1) == 0
- %error assert failed
- %endif
-%endmacro
-
-%macro DEFINE_ARGS 0-*
- %ifdef n_arg_names
- %assign %%i 0
- %rep n_arg_names
- CAT_UNDEF arg_name %+ %%i, q
- CAT_UNDEF arg_name %+ %%i, d
- CAT_UNDEF arg_name %+ %%i, w
- CAT_UNDEF arg_name %+ %%i, h
- CAT_UNDEF arg_name %+ %%i, b
- CAT_UNDEF arg_name %+ %%i, m
- CAT_UNDEF arg_name %+ %%i, mp
- CAT_UNDEF arg_name, %%i
- %assign %%i %%i+1
- %endrep
- %endif
-
- %xdefine %%stack_offset stack_offset
- %undef stack_offset ; so that the current value of stack_offset doesn't get baked in by xdefine
- %assign %%i 0
- %rep %0
- %xdefine %1q r %+ %%i %+ q
- %xdefine %1d r %+ %%i %+ d
- %xdefine %1w r %+ %%i %+ w
- %xdefine %1h r %+ %%i %+ h
- %xdefine %1b r %+ %%i %+ b
- %xdefine %1m r %+ %%i %+ m
- %xdefine %1mp r %+ %%i %+ mp
- CAT_XDEFINE arg_name, %%i, %1
- %assign %%i %%i+1
- %rotate 1
- %endrep
- %xdefine stack_offset %%stack_offset
- %assign n_arg_names %0
-%endmacro
-
-%if WIN64 ; Windows x64 ;=================================================
-
-DECLARE_REG 0, rcx
-DECLARE_REG 1, rdx
-DECLARE_REG 2, R8
-DECLARE_REG 3, R9
-DECLARE_REG 4, R10, 40
-DECLARE_REG 5, R11, 48
-DECLARE_REG 6, rax, 56
-DECLARE_REG 7, rdi, 64
-DECLARE_REG 8, rsi, 72
-DECLARE_REG 9, rbx, 80
-DECLARE_REG 10, rbp, 88
-DECLARE_REG 11, R12, 96
-DECLARE_REG 12, R13, 104
-DECLARE_REG 13, R14, 112
-DECLARE_REG 14, R15, 120
-
-%macro PROLOGUE 2-4+ 0 ; #args, #regs, #xmm_regs, arg_names...
- %assign num_args %1
- %assign regs_used %2
- ASSERT regs_used >= num_args
- ASSERT regs_used <= 15
- PUSH_IF_USED 7, 8, 9, 10, 11, 12, 13, 14
- %if mmsize == 8
- %assign xmm_regs_used 0
- %else
- WIN64_SPILL_XMM %3
- %endif
- LOAD_IF_USED 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
- DEFINE_ARGS %4
-%endmacro
-
-%macro WIN64_SPILL_XMM 1
- %assign xmm_regs_used %1
- ASSERT xmm_regs_used <= 16
- %if xmm_regs_used > 6
- SUB rsp, (xmm_regs_used-6)*16+16
- %assign %%i xmm_regs_used
- %rep (xmm_regs_used-6)
- %assign %%i %%i-1
- movdqa [rsp + (%%i-6)*16+(~stack_offset&8)], xmm %+ %%i
- %endrep
- %endif
-%endmacro
-
-%macro WIN64_RESTORE_XMM_INTERNAL 1
- %if xmm_regs_used > 6
- %assign %%i xmm_regs_used
- %rep (xmm_regs_used-6)
- %assign %%i %%i-1
- movdqa xmm %+ %%i, [%1 + (%%i-6)*16+(~stack_offset&8)]
- %endrep
- add %1, (xmm_regs_used-6)*16+16
- %endif
-%endmacro
-
-%macro WIN64_RESTORE_XMM 1
- WIN64_RESTORE_XMM_INTERNAL %1
- %assign stack_offset stack_offset-(xmm_regs_used-6)*16+16
- %assign xmm_regs_used 0
-%endmacro
-
-%define has_epilogue regs_used > 7 || xmm_regs_used > 6 || mmsize == 32
-
-%macro RET 0
- WIN64_RESTORE_XMM_INTERNAL rsp
- POP_IF_USED 14, 13, 12, 11, 10, 9, 8, 7
-%if mmsize == 32
- vzeroupper
-%endif
- ret
-%endmacro
-
-%elif ARCH_X86_64 ; *nix x64 ;=============================================
-
-DECLARE_REG 0, rdi
-DECLARE_REG 1, rsi
-DECLARE_REG 2, rdx
-DECLARE_REG 3, rcx
-DECLARE_REG 4, R8
-DECLARE_REG 5, R9
-DECLARE_REG 6, rax, 8
-DECLARE_REG 7, R10, 16
-DECLARE_REG 8, R11, 24
-DECLARE_REG 9, rbx, 32
-DECLARE_REG 10, rbp, 40
-DECLARE_REG 11, R12, 48
-DECLARE_REG 12, R13, 56
-DECLARE_REG 13, R14, 64
-DECLARE_REG 14, R15, 72
-
-%macro PROLOGUE 2-4+ ; #args, #regs, #xmm_regs, arg_names...
- %assign num_args %1
- %assign regs_used %2
- ASSERT regs_used >= num_args
- ASSERT regs_used <= 15
- PUSH_IF_USED 9, 10, 11, 12, 13, 14
- LOAD_IF_USED 6, 7, 8, 9, 10, 11, 12, 13, 14
- DEFINE_ARGS %4
-%endmacro
-
-%define has_epilogue regs_used > 9 || mmsize == 32
-
-%macro RET 0
- POP_IF_USED 14, 13, 12, 11, 10, 9
-%if mmsize == 32
- vzeroupper
-%endif
- ret
-%endmacro
-
-%else ; X86_32 ;==============================================================
-
-DECLARE_REG 0, eax, 4
-DECLARE_REG 1, ecx, 8
-DECLARE_REG 2, edx, 12
-DECLARE_REG 3, ebx, 16
-DECLARE_REG 4, esi, 20
-DECLARE_REG 5, edi, 24
-DECLARE_REG 6, ebp, 28
-%define rsp esp
-
-%macro DECLARE_ARG 1-*
- %rep %0
- %define r%1m [esp + stack_offset + 4*%1 + 4]
- %define r%1mp dword r%1m
- %rotate 1
- %endrep
-%endmacro
-
-DECLARE_ARG 7, 8, 9, 10, 11, 12, 13, 14
-
-%macro PROLOGUE 2-4+ ; #args, #regs, #xmm_regs, arg_names...
- %assign num_args %1
- %assign regs_used %2
- %if regs_used > 7
- %assign regs_used 7
- %endif
- ASSERT regs_used >= num_args
- PUSH_IF_USED 3, 4, 5, 6
- LOAD_IF_USED 0, 1, 2, 3, 4, 5, 6
- DEFINE_ARGS %4
-%endmacro
-
-%define has_epilogue regs_used > 3 || mmsize == 32
-
-%macro RET 0
- POP_IF_USED 6, 5, 4, 3
-%if mmsize == 32
- vzeroupper
-%endif
- ret
-%endmacro
-
-%endif ;======================================================================
-
-%if WIN64 == 0
-%macro WIN64_SPILL_XMM 1
-%endmacro
-%macro WIN64_RESTORE_XMM 1
-%endmacro
-%endif
-
-%macro REP_RET 0
- %if has_epilogue
- RET
- %else
- rep ret
- %endif
-%endmacro
-
-%macro TAIL_CALL 2 ; callee, is_nonadjacent
- %if has_epilogue
- call %1
- RET
- %elif %2
- jmp %1
- %endif
-%endmacro
-
-;=============================================================================
-; arch-independent part
-;=============================================================================
-
-%assign function_align 16
-
-; Begin a function.
-; Applies any symbol mangling needed for C linkage, and sets up a define such that
-; subsequent uses of the function name automatically refer to the mangled version.
-; Appends cpuflags to the function name if cpuflags has been specified.
-%macro cglobal 1-2+ ; name, [PROLOGUE args]
-%if %0 == 1
- cglobal_internal %1 %+ SUFFIX
-%else
- cglobal_internal %1 %+ SUFFIX, %2
-%endif
-%endmacro
-%macro cglobal_internal 1-2+
- %ifndef cglobaled_%1
- %xdefine %1 mangle(%1)
- %xdefine %1.skip_prologue %1 %+ .skip_prologue
- CAT_XDEFINE cglobaled_, %1, 1
- %endif
- %xdefine current_function %1
- %ifidn __OUTPUT_FORMAT__,elf
- global %1:function hidden
- %else
- global %1
- %endif
- align function_align
- %1:
- RESET_MM_PERMUTATION ; not really needed, but makes disassembly somewhat nicer
- %assign stack_offset 0
- %if %0 > 1
- PROLOGUE %2
- %endif
-%endmacro
-
-%macro cextern 1
- %xdefine %1 mangle(%1)
- CAT_XDEFINE cglobaled_, %1, 1
- extern %1
-%endmacro
-
-; like cextern, but without the prefix
-%macro cextern_naked 1
- %xdefine %1 mangle(%1)
- CAT_XDEFINE cglobaled_, %1, 1
- extern %1
-%endmacro
-
-%macro const 2+
- %xdefine %1 mangle(%1)
- global %1
- %1: %2
-%endmacro
-
-; This is needed for ELF, otherwise the GNU linker assumes the stack is
-; executable by default.
-%ifidn __OUTPUT_FORMAT__,elf
-SECTION .note.GNU-stack noalloc noexec nowrite progbits
-%endif
-%ifidn __OUTPUT_FORMAT__,elf32
-section .note.GNU-stack noalloc noexec nowrite progbits
-%endif
-%ifidn __OUTPUT_FORMAT__,elf64
-section .note.GNU-stack noalloc noexec nowrite progbits
-%endif
-
-; cpuflags
-
-%assign cpuflags_MMX (1<<0)
-%assign cpuflags_MMX2 (1<<1) | cpuflags_MMX
-%assign cpuflags_3dnow (1<<2) | cpuflags_MMX
-%assign cpuflags_3dnow2 (1<<3) | cpuflags_3dnow
-%assign cpuflags_SSE (1<<4) | cpuflags_MMX2
-%assign cpuflags_SSE2 (1<<5) | cpuflags_SSE
-%assign cpuflags_SSE2slow (1<<6) | cpuflags_SSE2
-%assign cpuflags_SSE3 (1<<7) | cpuflags_SSE2
-%assign cpuflags_SSSE3 (1<<8) | cpuflags_SSE3
-%assign cpuflags_SSE4 (1<<9) | cpuflags_SSSE3
-%assign cpuflags_SSE42 (1<<10)| cpuflags_SSE4
-%assign cpuflags_AVX (1<<11)| cpuflags_SSE42
-%assign cpuflags_xop (1<<12)| cpuflags_AVX
-%assign cpuflags_fma4 (1<<13)| cpuflags_AVX
-%assign cpuflags_AVX2 (1<<14)| cpuflags_AVX
-%assign cpuflags_fma3 (1<<15)| cpuflags_AVX
-
-%assign cpuflags_cache32 (1<<16)
-%assign cpuflags_cache64 (1<<17)
-%assign cpuflags_slowctz (1<<18)
-%assign cpuflags_lzcnt (1<<19)
-%assign cpuflags_misalign (1<<20)
-%assign cpuflags_aligned (1<<21) ; not a cpu feature, but a function variant
-%assign cpuflags_atom (1<<22)
-%assign cpuflags_bmi1 (1<<23)
-%assign cpuflags_bmi2 (1<<24)|cpuflags_bmi1
-%assign cpuflags_tbm (1<<25)|cpuflags_bmi1
-
-%define cpuflag(x) ((cpuflags & (cpuflags_ %+ x)) == (cpuflags_ %+ x))
-%define notcpuflag(x) ((cpuflags & (cpuflags_ %+ x)) != (cpuflags_ %+ x))
-
-; Takes up to 2 cpuflags from the above list.
-; All subsequent functions (up to the next INIT_CPUFLAGS) is built for the specified cpu.
-; You shouldn't need to invoke this macro directly, it's a subroutine for INIT_MMX &co.
-%macro INIT_CPUFLAGS 0-2
- %if %0 >= 1
- %xdefine cpuname %1
- %assign cpuflags cpuflags_%1
- %if %0 >= 2
- %xdefine cpuname %1_%2
- %assign cpuflags cpuflags | cpuflags_%2
- %endif
- %xdefine SUFFIX _ %+ cpuname
- %if cpuflag(AVX)
- %assign AVX_enabled 1
- %endif
- %if mmsize == 16 && notcpuflag(SSE2)
- %define mova movaps
- %define movu movups
- %define movnta movntps
- %endif
- %if cpuflag(aligned)
- %define movu mova
- %elifidn %1, SSE3
- %define movu lddqu
- %endif
- %else
- %xdefine SUFFIX
- %undef cpuname
- %undef cpuflags
- %endif
-%endmacro
-
-; merge MMX and SSE*
-
-%macro CAT_XDEFINE 3
- %xdefine %1%2 %3
-%endmacro
-
-%macro CAT_UNDEF 2
- %undef %1%2
-%endmacro
-
-%macro INIT_MMX 0-1+
- %assign AVX_enabled 0
- %define RESET_MM_PERMUTATION INIT_MMX %1
- %define mmsize 8
- %define num_mmregs 8
- %define mova movq
- %define movu movq
- %define movh movd
- %define movnta movntq
- %assign %%i 0
- %rep 8
- CAT_XDEFINE m, %%i, mm %+ %%i
- CAT_XDEFINE nmm, %%i, %%i
- %assign %%i %%i+1
- %endrep
- %rep 8
- CAT_UNDEF m, %%i
- CAT_UNDEF nmm, %%i
- %assign %%i %%i+1
- %endrep
- INIT_CPUFLAGS %1
-%endmacro
-
-%macro INIT_XMM 0-1+
- %assign AVX_enabled 0
- %define RESET_MM_PERMUTATION INIT_XMM %1
- %define mmsize 16
- %define num_mmregs 8
- %if ARCH_X86_64
- %define num_mmregs 16
- %endif
- %define mova movdqa
- %define movu movdqu
- %define movh movq
- %define movnta movntdq
- %assign %%i 0
- %rep num_mmregs
- CAT_XDEFINE m, %%i, xmm %+ %%i
- CAT_XDEFINE nxmm, %%i, %%i
- %assign %%i %%i+1
- %endrep
- INIT_CPUFLAGS %1
-%endmacro
-
-%macro INIT_YMM 0-1+
- %assign AVX_enabled 1
- %define RESET_MM_PERMUTATION INIT_YMM %1
- %define mmsize 32
- %define num_mmregs 8
- %if ARCH_X86_64
- %define num_mmregs 16
- %endif
- %define mova vmovaps
- %define movu vmovups
- %undef movh
- %define movnta vmovntps
- %assign %%i 0
- %rep num_mmregs
- CAT_XDEFINE m, %%i, ymm %+ %%i
- CAT_XDEFINE nymm, %%i, %%i
- %assign %%i %%i+1
- %endrep
- INIT_CPUFLAGS %1
-%endmacro
-
-INIT_XMM
-
-; I often want to use macros that permute their arguments. e.g. there's no
-; efficient way to implement butterfly or transpose or dct without swapping some
-; arguments.
-;
-; I would like to not have to manually keep track of the permutations:
-; If I insert a permutation in the middle of a function, it should automatically
-; change everything that follows. For more complex macros I may also have multiple
-; implementations, e.g. the SSE2 and SSSE3 versions may have different permutations.
-;
-; Hence these macros. Insert a PERMUTE or some SWAPs at the end of a macro that
-; permutes its arguments. It's equivalent to exchanging the contents of the
-; registers, except that this way you exchange the register names instead, so it
-; doesn't cost any cycles.
-
-%macro PERMUTE 2-* ; takes a list of pairs to swap
-%rep %0/2
- %xdefine tmp%2 m%2
- %xdefine ntmp%2 nm%2
- %rotate 2
-%endrep
-%rep %0/2
- %xdefine m%1 tmp%2
- %xdefine nm%1 ntmp%2
- %undef tmp%2
- %undef ntmp%2
- %rotate 2
-%endrep
-%endmacro
-
-%macro SWAP 2-* ; swaps a single chain (sometimes more concise than pairs)
-%rep %0-1
-%ifdef m%1
- %xdefine tmp m%1
- %xdefine m%1 m%2
- %xdefine m%2 tmp
- CAT_XDEFINE n, m%1, %1
- CAT_XDEFINE n, m%2, %2
-%else
- ; If we were called as "SWAP m0,m1" rather than "SWAP 0,1" infer the original numbers here.
- ; Be careful using this mode in nested macros though, as in some cases there may be
- ; other copies of m# that have already been dereferenced and don't get updated correctly.
- %xdefine %%n1 n %+ %1
- %xdefine %%n2 n %+ %2
- %xdefine tmp m %+ %%n1
- CAT_XDEFINE m, %%n1, m %+ %%n2
- CAT_XDEFINE m, %%n2, tmp
- CAT_XDEFINE n, m %+ %%n1, %%n1
- CAT_XDEFINE n, m %+ %%n2, %%n2
-%endif
- %undef tmp
- %rotate 1
-%endrep
-%endmacro
-
-; If SAVE_MM_PERMUTATION is placed at the end of a function, then any later
-; calls to that function will automatically load the permutation, so values can
-; be returned in mmregs.
-%macro SAVE_MM_PERMUTATION 0-1
- %if %0
- %xdefine %%f %1_m
- %else
- %xdefine %%f current_function %+ _m
- %endif
- %assign %%i 0
- %rep num_mmregs
- CAT_XDEFINE %%f, %%i, m %+ %%i
- %assign %%i %%i+1
- %endrep
-%endmacro
-
-%macro LOAD_MM_PERMUTATION 1 ; name to load from
- %ifdef %1_m0
- %assign %%i 0
- %rep num_mmregs
- CAT_XDEFINE m, %%i, %1_m %+ %%i
- CAT_XDEFINE n, m %+ %%i, %%i
- %assign %%i %%i+1
- %endrep
- %endif
-%endmacro
-
-; Append cpuflags to the callee's name iff the appended name is known and the plain name isn't
-%macro call 1
- call_internal %1, %1 %+ SUFFIX
-%endmacro
-%macro call_internal 2
- %xdefine %%i %1
- %ifndef cglobaled_%1
- %ifdef cglobaled_%2
- %xdefine %%i %2
- %endif
- %endif
- call %%i
- LOAD_MM_PERMUTATION %%i
-%endmacro
-
-; Substitutions that reduce instruction size but are functionally equivalent
-%macro add 2
- %ifnum %2
- %if %2==128
- sub %1, -128
- %else
- add %1, %2
- %endif
- %else
- add %1, %2
- %endif
-%endmacro
-
-%macro sub 2
- %ifnum %2
- %if %2==128
- add %1, -128
- %else
- sub %1, %2
- %endif
- %else
- sub %1, %2
- %endif
-%endmacro
-
-;=============================================================================
-; AVX abstraction layer
-;=============================================================================
-
-%assign i 0
-%rep 16
- %if i < 8
- CAT_XDEFINE sizeofmm, i, 8
- %endif
- CAT_XDEFINE sizeofxmm, i, 16
- CAT_XDEFINE sizeofymm, i, 32
-%assign i i+1
-%endrep
-%undef i
-
-%macro CHECK_AVX_INSTR_EMU 3-*
- %xdefine %%opcode %1
- %xdefine %%dst %2
- %rep %0-2
- %ifidn %%dst, %3
- %error non-AVX emulation of ``%%opcode'' is not supported
- %endif
- %rotate 1
- %endrep
-%endmacro
-
-;%1 == instruction
-;%2 == 1 if float, 0 if int
-;%3 == 1 if 4-operand (xmm, xmm, xmm, imm), 0 if 2- or 3-operand (xmm, xmm, xmm)
-;%4 == number of operands given
-;%5+: operands
-%macro RUN_AVX_INSTR 6-7+
- %ifid %6
- %define %%sizeofreg sizeof%6
- %elifid %5
- %define %%sizeofreg sizeof%5
- %else
- %define %%sizeofreg mmsize
- %endif
- %if %%sizeofreg==32
- %if %4>=3
- v%1 %5, %6, %7
- %else
- v%1 %5, %6
- %endif
- %else
- %if %%sizeofreg==8
- %define %%regmov movq
- %elif %2
- %define %%regmov movaps
- %else
- %define %%regmov movdqa
- %endif
-
- %if %4>=3+%3
- %ifnidn %5, %6
- %if AVX_enabled && %%sizeofreg==16
- v%1 %5, %6, %7
- %else
- CHECK_AVX_INSTR_EMU {%1 %5, %6, %7}, %5, %7
- %%regmov %5, %6
- %1 %5, %7
- %endif
- %else
- %1 %5, %7
- %endif
- %elif %4>=3
- %1 %5, %6, %7
- %else
- %1 %5, %6
- %endif
- %endif
-%endmacro
-
-; 3arg AVX ops with a memory arg can only have it in src2,
-; whereas SSE emulation of 3arg prefers to have it in src1 (i.e. the mov).
-; So, if the op is symmetric and the wrong one is memory, swap them.
-%macro RUN_AVX_INSTR1 8
- %assign %%swap 0
- %if AVX_enabled
- %ifnid %6
- %assign %%swap 1
- %endif
- %elifnidn %5, %6
- %ifnid %7
- %assign %%swap 1
- %endif
- %endif
- %if %%swap && %3 == 0 && %8 == 1
- RUN_AVX_INSTR %1, %2, %3, %4, %5, %7, %6
- %else
- RUN_AVX_INSTR %1, %2, %3, %4, %5, %6, %7
- %endif
-%endmacro
-
-;%1 == instruction
-;%2 == 1 if float, 0 if int
-;%3 == 1 if 4-operand (xmm, xmm, xmm, imm), 0 if 2- or 3-operand (xmm, xmm, xmm)
-;%4 == 1 if symmetric (i.e. doesn't matter which src arg is which), 0 if not
-%macro AVX_INSTR 4
- %macro %1 2-9 fnord, fnord, fnord, %1, %2, %3, %4
- %ifidn %3, fnord
- RUN_AVX_INSTR %6, %7, %8, 2, %1, %2
- %elifidn %4, fnord
- RUN_AVX_INSTR1 %6, %7, %8, 3, %1, %2, %3, %9
- %elifidn %5, fnord
- RUN_AVX_INSTR %6, %7, %8, 4, %1, %2, %3, %4
- %else
- RUN_AVX_INSTR %6, %7, %8, 5, %1, %2, %3, %4, %5
- %endif
- %endmacro
-%endmacro
-
-AVX_INSTR addpd, 1, 0, 1
-AVX_INSTR addps, 1, 0, 1
-AVX_INSTR addsd, 1, 0, 1
-AVX_INSTR addss, 1, 0, 1
-AVX_INSTR addsubpd, 1, 0, 0
-AVX_INSTR addsubps, 1, 0, 0
-AVX_INSTR andpd, 1, 0, 1
-AVX_INSTR andps, 1, 0, 1
-AVX_INSTR andnpd, 1, 0, 0
-AVX_INSTR andnps, 1, 0, 0
-AVX_INSTR blendpd, 1, 0, 0
-AVX_INSTR blendps, 1, 0, 0
-AVX_INSTR blendvpd, 1, 0, 0
-AVX_INSTR blendvps, 1, 0, 0
-AVX_INSTR cmppd, 1, 0, 0
-AVX_INSTR cmpps, 1, 0, 0
-AVX_INSTR cmpsd, 1, 0, 0
-AVX_INSTR cmpss, 1, 0, 0
-AVX_INSTR cvtdq2ps, 1, 0, 0
-AVX_INSTR cvtps2dq, 1, 0, 0
-AVX_INSTR divpd, 1, 0, 0
-AVX_INSTR divps, 1, 0, 0
-AVX_INSTR divsd, 1, 0, 0
-AVX_INSTR divss, 1, 0, 0
-AVX_INSTR dppd, 1, 1, 0
-AVX_INSTR dpps, 1, 1, 0
-AVX_INSTR haddpd, 1, 0, 0
-AVX_INSTR haddps, 1, 0, 0
-AVX_INSTR hsubpd, 1, 0, 0
-AVX_INSTR hsubps, 1, 0, 0
-AVX_INSTR maxpd, 1, 0, 1
-AVX_INSTR maxps, 1, 0, 1
-AVX_INSTR maxsd, 1, 0, 1
-AVX_INSTR maxss, 1, 0, 1
-AVX_INSTR minpd, 1, 0, 1
-AVX_INSTR minps, 1, 0, 1
-AVX_INSTR minsd, 1, 0, 1
-AVX_INSTR minss, 1, 0, 1
-AVX_INSTR movhlps, 1, 0, 0
-AVX_INSTR movlhps, 1, 0, 0
-AVX_INSTR movsd, 1, 0, 0
-AVX_INSTR movss, 1, 0, 0
-AVX_INSTR mpsadbw, 0, 1, 0
-AVX_INSTR mulpd, 1, 0, 1
-AVX_INSTR mulps, 1, 0, 1
-AVX_INSTR mulsd, 1, 0, 1
-AVX_INSTR mulss, 1, 0, 1
-AVX_INSTR orpd, 1, 0, 1
-AVX_INSTR orps, 1, 0, 1
-AVX_INSTR pabsb, 0, 0, 0
-AVX_INSTR pabsw, 0, 0, 0
-AVX_INSTR pabsd, 0, 0, 0
-AVX_INSTR packsswb, 0, 0, 0
-AVX_INSTR packssdw, 0, 0, 0
-AVX_INSTR packuswb, 0, 0, 0
-AVX_INSTR packusdw, 0, 0, 0
-AVX_INSTR paddb, 0, 0, 1
-AVX_INSTR paddw, 0, 0, 1
-AVX_INSTR paddd, 0, 0, 1
-AVX_INSTR paddq, 0, 0, 1
-AVX_INSTR paddsb, 0, 0, 1
-AVX_INSTR paddsw, 0, 0, 1
-AVX_INSTR paddusb, 0, 0, 1
-AVX_INSTR paddusw, 0, 0, 1
-AVX_INSTR palignr, 0, 1, 0
-AVX_INSTR pand, 0, 0, 1
-AVX_INSTR pandn, 0, 0, 0
-AVX_INSTR pavgb, 0, 0, 1
-AVX_INSTR pavgw, 0, 0, 1
-AVX_INSTR pblendvb, 0, 0, 0
-AVX_INSTR pblendw, 0, 1, 0
-AVX_INSTR pcmpestri, 0, 0, 0
-AVX_INSTR pcmpestrm, 0, 0, 0
-AVX_INSTR pcmpistri, 0, 0, 0
-AVX_INSTR pcmpistrm, 0, 0, 0
-AVX_INSTR pcmpeqb, 0, 0, 1
-AVX_INSTR pcmpeqw, 0, 0, 1
-AVX_INSTR pcmpeqd, 0, 0, 1
-AVX_INSTR pcmpeqq, 0, 0, 1
-AVX_INSTR pcmpgtb, 0, 0, 0
-AVX_INSTR pcmpgtw, 0, 0, 0
-AVX_INSTR pcmpgtd, 0, 0, 0
-AVX_INSTR pcmpgtq, 0, 0, 0
-AVX_INSTR phaddw, 0, 0, 0
-AVX_INSTR phaddd, 0, 0, 0
-AVX_INSTR phaddsw, 0, 0, 0
-AVX_INSTR phsubw, 0, 0, 0
-AVX_INSTR phsubd, 0, 0, 0
-AVX_INSTR phsubsw, 0, 0, 0
-AVX_INSTR pmaddwd, 0, 0, 1
-AVX_INSTR pmaddubsw, 0, 0, 0
-AVX_INSTR pmaxsb, 0, 0, 1
-AVX_INSTR pmaxsw, 0, 0, 1
-AVX_INSTR pmaxsd, 0, 0, 1
-AVX_INSTR pmaxub, 0, 0, 1
-AVX_INSTR pmaxuw, 0, 0, 1
-AVX_INSTR pmaxud, 0, 0, 1
-AVX_INSTR pminsb, 0, 0, 1
-AVX_INSTR pminsw, 0, 0, 1
-AVX_INSTR pminsd, 0, 0, 1
-AVX_INSTR pminub, 0, 0, 1
-AVX_INSTR pminuw, 0, 0, 1
-AVX_INSTR pminud, 0, 0, 1
-AVX_INSTR pmovmskb, 0, 0, 0
-AVX_INSTR pmulhuw, 0, 0, 1
-AVX_INSTR pmulhrsw, 0, 0, 1
-AVX_INSTR pmulhw, 0, 0, 1
-AVX_INSTR pmullw, 0, 0, 1
-AVX_INSTR pmulld, 0, 0, 1
-AVX_INSTR pmuludq, 0, 0, 1
-AVX_INSTR pmuldq, 0, 0, 1
-AVX_INSTR por, 0, 0, 1
-AVX_INSTR psadbw, 0, 0, 1
-AVX_INSTR pshufb, 0, 0, 0
-AVX_INSTR pshufd, 0, 1, 0
-AVX_INSTR pshufhw, 0, 1, 0
-AVX_INSTR pshuflw, 0, 1, 0
-AVX_INSTR psignb, 0, 0, 0
-AVX_INSTR psignw, 0, 0, 0
-AVX_INSTR psignd, 0, 0, 0
-AVX_INSTR psllw, 0, 0, 0
-AVX_INSTR pslld, 0, 0, 0
-AVX_INSTR psllq, 0, 0, 0
-AVX_INSTR pslldq, 0, 0, 0
-AVX_INSTR psraw, 0, 0, 0
-AVX_INSTR psrad, 0, 0, 0
-AVX_INSTR psrlw, 0, 0, 0
-AVX_INSTR psrld, 0, 0, 0
-AVX_INSTR psrlq, 0, 0, 0
-AVX_INSTR psrldq, 0, 0, 0
-AVX_INSTR psubb, 0, 0, 0
-AVX_INSTR psubw, 0, 0, 0
-AVX_INSTR psubd, 0, 0, 0
-AVX_INSTR psubq, 0, 0, 0
-AVX_INSTR psubsb, 0, 0, 0
-AVX_INSTR psubsw, 0, 0, 0
-AVX_INSTR psubusb, 0, 0, 0
-AVX_INSTR psubusw, 0, 0, 0
-AVX_INSTR ptest, 0, 0, 0
-AVX_INSTR punpckhbw, 0, 0, 0
-AVX_INSTR punpckhwd, 0, 0, 0
-AVX_INSTR punpckhdq, 0, 0, 0
-AVX_INSTR punpckhqdq, 0, 0, 0
-AVX_INSTR punpcklbw, 0, 0, 0
-AVX_INSTR punpcklwd, 0, 0, 0
-AVX_INSTR punpckldq, 0, 0, 0
-AVX_INSTR punpcklqdq, 0, 0, 0
-AVX_INSTR pxor, 0, 0, 1
-AVX_INSTR shufps, 1, 1, 0
-AVX_INSTR subpd, 1, 0, 0
-AVX_INSTR subps, 1, 0, 0
-AVX_INSTR subsd, 1, 0, 0
-AVX_INSTR subss, 1, 0, 0
-AVX_INSTR unpckhpd, 1, 0, 0
-AVX_INSTR unpckhps, 1, 0, 0
-AVX_INSTR unpcklpd, 1, 0, 0
-AVX_INSTR unpcklps, 1, 0, 0
-AVX_INSTR xorpd, 1, 0, 1
-AVX_INSTR xorps, 1, 0, 1
-
-; 3DNow instructions, for sharing code between AVX, SSE and 3DN
-AVX_INSTR pfadd, 1, 0, 1
-AVX_INSTR pfsub, 1, 0, 0
-AVX_INSTR pfmul, 1, 0, 1
-
-; base-4 constants for shuffles
-%assign i 0
-%rep 256
- %assign j ((i>>6)&3)*1000 + ((i>>4)&3)*100 + ((i>>2)&3)*10 + (i&3)
- %if j < 10
- CAT_XDEFINE q000, j, i
- %elif j < 100
- CAT_XDEFINE q00, j, i
- %elif j < 1000
- CAT_XDEFINE q0, j, i
- %else
- CAT_XDEFINE q, j, i
- %endif
-%assign i i+1
-%endrep
-%undef i
-%undef j
-
-%macro FMA_INSTR 3
- %macro %1 4-7 %1, %2, %3
- %if cpuflag(xop)
- v%5 %1, %2, %3, %4
- %else
- %6 %1, %2, %3
- %7 %1, %4
- %endif
- %endmacro
-%endmacro
-
-FMA_INSTR pmacsdd, pmulld, paddd
-FMA_INSTR pmacsww, pmullw, paddw
-FMA_INSTR pmadcswd, pmaddwd, paddd
-
-; tzcnt is equivalent to "rep bsf" and is backwards-compatible with bsf.
-; This lets us use tzcnt without bumping the yasm version requirement yet.
-%define tzcnt rep bsf
diff --git a/drivers/theoraplayer/src/YUV/libyuv/yuv_libyuv.c b/drivers/theoraplayer/src/YUV/libyuv/yuv_libyuv.c
deleted file mode 100755
index 3712a3b6d6..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/yuv_libyuv.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#ifdef _YUV_LIBYUV
-#include <libyuv.h>
-#include "yuv_util.h"
-#include "yuv_libyuv.h"
-
-void decodeRGB(struct TheoraPixelTransform* t)
-{
- I420ToRAW(t->y, t->yStride, t->u, t->uStride, t->v, t->vStride, t->out, t->w * 3, t->w, t->h);
-}
-
-void decodeRGBA(struct TheoraPixelTransform* t)
-{
- I420ToABGR(t->y, t->yStride, t->u, t->uStride, t->v, t->vStride, t->out, t->w * 4, t->w, t->h);
- _decodeAlpha(incOut(t, 3), t->w * 4);
-}
-
-void decodeRGBX(struct TheoraPixelTransform* t)
-{
- I420ToABGR(t->y, t->yStride, t->u, t->uStride, t->v, t->vStride, t->out, t->w * 4, t->w, t->h);
-}
-
-void decodeARGB(struct TheoraPixelTransform* t)
-{
- I420ToBGRA(t->y, t->yStride, t->u, t->uStride, t->v, t->vStride, t->out, t->w * 4, t->w, t->h);
- _decodeAlpha(t, t->w * 4);
-}
-
-void decodeXRGB(struct TheoraPixelTransform* t)
-{
- I420ToBGRA(t->y, t->yStride, t->u, t->uStride, t->v, t->vStride, t->out, t->w * 4, t->w, t->h);
-}
-
-void decodeBGR(struct TheoraPixelTransform* t)
-{
- I420ToRGB24(t->y, t->yStride, t->u, t->uStride, t->v, t->vStride, t->out, t->w * 3, t->w, t->h);
-}
-
-void decodeBGRA(struct TheoraPixelTransform* t)
-{
- I420ToARGB(t->y, t->yStride, t->u, t->uStride, t->v, t->vStride, t->out, t->w * 4, t->w, t->h);
- _decodeAlpha(incOut(t, 3), t->w * 4);
-}
-
-void decodeBGRX(struct TheoraPixelTransform* t)
-{
- I420ToARGB(t->y, t->yStride, t->u, t->uStride, t->v, t->vStride, t->out, t->w * 4, t->w, t->h);
-}
-
-void decodeABGR(struct TheoraPixelTransform* t)
-{
- I420ToRGBA(t->y, t->yStride, t->u, t->uStride, t->v, t->vStride, t->out, t->w * 4, t->w, t->h);
- _decodeAlpha(t, t->w * 4);
-}
-
-void decodeXBGR(struct TheoraPixelTransform* t)
-{
- I420ToRGBA(t->y, t->yStride, t->u, t->uStride, t->v, t->vStride, t->out, t->w * 4, t->w, t->h);
-}
-
-void initYUVConversionModule()
-{
-
-}
-#endif
diff --git a/drivers/theoraplayer/src/YUV/libyuv/yuv_libyuv.h b/drivers/theoraplayer/src/YUV/libyuv/yuv_libyuv.h
deleted file mode 100755
index f621af0c5f..0000000000
--- a/drivers/theoraplayer/src/YUV/libyuv/yuv_libyuv.h
+++ /dev/null
@@ -1,14 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#ifndef _YUV_LIBYUV_h
-#define _YUV_LIBYUV_h
-
-#include "TheoraPixelTransform.h"
-
-#endif
diff --git a/drivers/theoraplayer/src/YUV/yuv_util.c b/drivers/theoraplayer/src/YUV/yuv_util.c
deleted file mode 100644
index f5bf3e5f9e..0000000000
--- a/drivers/theoraplayer/src/YUV/yuv_util.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#include "yuv_util.h"
-
-struct TheoraPixelTransform* incOut(struct TheoraPixelTransform* t, int n)
-{
- // used for XRGB, XBGR and similar
- t->out += n;
- return t;
-}
-
-void _decodeAlpha(struct TheoraPixelTransform* t, int stride)
-{
- int width = t->w;
- unsigned char *ySrc, *yLineEnd, *out;
- int luma;
- unsigned int y;
- for (y = 0; y < t->h; y++)
- {
- ySrc = t->y + y * t->yStride + width;
- out = t->out + y * stride;
-
- for (yLineEnd = ySrc + width; ySrc != yLineEnd; ++ySrc, out += 4)
- {
- luma = (*ySrc);
- // because in YCbCr specification, luma values are in the range of [16, 235]
- // account for 'footroom' and 'headroom' ranges while using luma values as alpha channel
- if (luma <= 16) *out = 0;
- else if (luma >= 235) *out = 255;
- else *out = (unsigned char) (((luma - 16) * 255) / 219);
- }
- }
-}
diff --git a/drivers/theoraplayer/src/YUV/yuv_util.h b/drivers/theoraplayer/src/YUV/yuv_util.h
deleted file mode 100644
index 1f9d76634a..0000000000
--- a/drivers/theoraplayer/src/YUV/yuv_util.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/************************************************************************************
-This source file is part of the Theora Video Playback Library
-For latest info, see http://libtheoraplayer.googlecode.com
-*************************************************************************************
-Copyright (c) 2008-2014 Kresimir Spes (kspes@cateia.com)
-This program is free software; you can redistribute it and/or modify it under
-the terms of the BSD license: http://opensource.org/licenses/BSD-3-Clause
-*************************************************************************************/
-#ifndef _YUV_UTIL_h
-#define _YUV_UTIL_h
-
-#include "TheoraPixelTransform.h"
-
-struct TheoraPixelTransform* incOut(struct TheoraPixelTransform* t, int n);
-void _decodeAlpha(struct TheoraPixelTransform* t, int stride);
-
-#endif
diff --git a/drivers/theoraplayer/theoraplayer.xcodeproj/project.pbxproj b/drivers/theoraplayer/theoraplayer.xcodeproj/project.pbxproj
deleted file mode 100644
index 23f875fe0c..0000000000
--- a/drivers/theoraplayer/theoraplayer.xcodeproj/project.pbxproj
+++ /dev/null
@@ -1,2606 +0,0 @@
-// !$*UTF8*$!
-{
- archiveVersion = 1;
- classes = {
- };
- objectVersion = 46;
- objects = {
-
-/* Begin PBXBuildFile section */
- D139462D17C0ED450091F4A4 /* yuv_libyuv.c in Sources */ = {isa = PBXBuildFile; fileRef = D139462B17C0ED450091F4A4 /* yuv_libyuv.c */; };
- D139462E17C0ED450091F4A4 /* yuv_libyuv.c in Sources */ = {isa = PBXBuildFile; fileRef = D139462B17C0ED450091F4A4 /* yuv_libyuv.c */; };
- D139462F17C0ED450091F4A4 /* yuv_libyuv.c in Sources */ = {isa = PBXBuildFile; fileRef = D139462B17C0ED450091F4A4 /* yuv_libyuv.c */; };
- D139463017C0ED450091F4A4 /* yuv_libyuv.c in Sources */ = {isa = PBXBuildFile; fileRef = D139462B17C0ED450091F4A4 /* yuv_libyuv.c */; };
- D139463117C0ED450091F4A4 /* yuv_libyuv.c in Sources */ = {isa = PBXBuildFile; fileRef = D139462B17C0ED450091F4A4 /* yuv_libyuv.c */; };
- D139463217C0ED450091F4A4 /* yuv_libyuv.c in Sources */ = {isa = PBXBuildFile; fileRef = D139462B17C0ED450091F4A4 /* yuv_libyuv.c */; };
- D139463317C0ED450091F4A4 /* yuv_libyuv.c in Sources */ = {isa = PBXBuildFile; fileRef = D139462B17C0ED450091F4A4 /* yuv_libyuv.c */; };
- D139463417C0ED450091F4A4 /* yuv_libyuv.c in Sources */ = {isa = PBXBuildFile; fileRef = D139462B17C0ED450091F4A4 /* yuv_libyuv.c */; };
- D139463617C0ED450091F4A4 /* yuv_libyuv.h in Headers */ = {isa = PBXBuildFile; fileRef = D139462C17C0ED450091F4A4 /* yuv_libyuv.h */; };
- D139463717C0ED450091F4A4 /* yuv_libyuv.h in Headers */ = {isa = PBXBuildFile; fileRef = D139462C17C0ED450091F4A4 /* yuv_libyuv.h */; };
- D139463817C0ED450091F4A4 /* yuv_libyuv.h in Headers */ = {isa = PBXBuildFile; fileRef = D139462C17C0ED450091F4A4 /* yuv_libyuv.h */; };
- D139463917C0ED450091F4A4 /* yuv_libyuv.h in Headers */ = {isa = PBXBuildFile; fileRef = D139462C17C0ED450091F4A4 /* yuv_libyuv.h */; };
- D139463A17C0ED450091F4A4 /* yuv_libyuv.h in Headers */ = {isa = PBXBuildFile; fileRef = D139462C17C0ED450091F4A4 /* yuv_libyuv.h */; };
- D139463B17C0ED450091F4A4 /* yuv_libyuv.h in Headers */ = {isa = PBXBuildFile; fileRef = D139462C17C0ED450091F4A4 /* yuv_libyuv.h */; };
- D139463C17C0ED450091F4A4 /* yuv_libyuv.h in Headers */ = {isa = PBXBuildFile; fileRef = D139462C17C0ED450091F4A4 /* yuv_libyuv.h */; };
- D139463D17C0ED450091F4A4 /* yuv_libyuv.h in Headers */ = {isa = PBXBuildFile; fileRef = D139462C17C0ED450091F4A4 /* yuv_libyuv.h */; };
- D139463E17C0ED450091F4A4 /* yuv_libyuv.h in Headers */ = {isa = PBXBuildFile; fileRef = D139462C17C0ED450091F4A4 /* yuv_libyuv.h */; };
- D13946C617C110670091F4A4 /* yuv_libyuv.c in Sources */ = {isa = PBXBuildFile; fileRef = D139462B17C0ED450091F4A4 /* yuv_libyuv.c */; };
- D13946CC17C119B40091F4A4 /* yuv_util.c in Sources */ = {isa = PBXBuildFile; fileRef = D13946CA17C119B30091F4A4 /* yuv_util.c */; };
- D13946CD17C119B40091F4A4 /* yuv_util.c in Sources */ = {isa = PBXBuildFile; fileRef = D13946CA17C119B30091F4A4 /* yuv_util.c */; };
- D13946CE17C119B40091F4A4 /* yuv_util.c in Sources */ = {isa = PBXBuildFile; fileRef = D13946CA17C119B30091F4A4 /* yuv_util.c */; };
- D13946CF17C119B40091F4A4 /* yuv_util.c in Sources */ = {isa = PBXBuildFile; fileRef = D13946CA17C119B30091F4A4 /* yuv_util.c */; };
- D13946D017C119B40091F4A4 /* yuv_util.c in Sources */ = {isa = PBXBuildFile; fileRef = D13946CA17C119B30091F4A4 /* yuv_util.c */; };
- D13946D117C119B40091F4A4 /* yuv_util.c in Sources */ = {isa = PBXBuildFile; fileRef = D13946CA17C119B30091F4A4 /* yuv_util.c */; };
- D13946D217C119B40091F4A4 /* yuv_util.c in Sources */ = {isa = PBXBuildFile; fileRef = D13946CA17C119B30091F4A4 /* yuv_util.c */; };
- D13946D317C119B40091F4A4 /* yuv_util.c in Sources */ = {isa = PBXBuildFile; fileRef = D13946CA17C119B30091F4A4 /* yuv_util.c */; };
- D13946D417C119B40091F4A4 /* yuv_util.c in Sources */ = {isa = PBXBuildFile; fileRef = D13946CA17C119B30091F4A4 /* yuv_util.c */; };
- D13946D517C119B40091F4A4 /* yuv_util.h in Headers */ = {isa = PBXBuildFile; fileRef = D13946CB17C119B30091F4A4 /* yuv_util.h */; };
- D13946D617C119B40091F4A4 /* yuv_util.h in Headers */ = {isa = PBXBuildFile; fileRef = D13946CB17C119B30091F4A4 /* yuv_util.h */; };
- D13946D717C119B40091F4A4 /* yuv_util.h in Headers */ = {isa = PBXBuildFile; fileRef = D13946CB17C119B30091F4A4 /* yuv_util.h */; };
- D13946D817C119B40091F4A4 /* yuv_util.h in Headers */ = {isa = PBXBuildFile; fileRef = D13946CB17C119B30091F4A4 /* yuv_util.h */; };
- D13946D917C119B40091F4A4 /* yuv_util.h in Headers */ = {isa = PBXBuildFile; fileRef = D13946CB17C119B30091F4A4 /* yuv_util.h */; };
- D13946DA17C119B40091F4A4 /* yuv_util.h in Headers */ = {isa = PBXBuildFile; fileRef = D13946CB17C119B30091F4A4 /* yuv_util.h */; };
- D13946DB17C119B40091F4A4 /* yuv_util.h in Headers */ = {isa = PBXBuildFile; fileRef = D13946CB17C119B30091F4A4 /* yuv_util.h */; };
- D13946DC17C119B40091F4A4 /* yuv_util.h in Headers */ = {isa = PBXBuildFile; fileRef = D13946CB17C119B30091F4A4 /* yuv_util.h */; };
- D13946DD17C119B40091F4A4 /* yuv_util.h in Headers */ = {isa = PBXBuildFile; fileRef = D13946CB17C119B30091F4A4 /* yuv_util.h */; };
- D159BCB017C227F30030FAB6 /* convert_from.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05617C157CD00CA0FD2 /* convert_from.cc */; };
- D159BCB117C227F40030FAB6 /* convert_from.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05617C157CD00CA0FD2 /* convert_from.cc */; };
- D159BCB217C227F40030FAB6 /* convert_from.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05617C157CD00CA0FD2 /* convert_from.cc */; };
- D159BCB317C227F40030FAB6 /* convert_from.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05617C157CD00CA0FD2 /* convert_from.cc */; };
- D159BCB417C227F50030FAB6 /* convert_from.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05617C157CD00CA0FD2 /* convert_from.cc */; };
- D159BCB517C227F50030FAB6 /* convert_from.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05617C157CD00CA0FD2 /* convert_from.cc */; };
- D159BCB617C227F60030FAB6 /* convert_from.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05617C157CD00CA0FD2 /* convert_from.cc */; };
- D159BCB717C227F60030FAB6 /* convert_from.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05617C157CD00CA0FD2 /* convert_from.cc */; };
- D159BCB817C227F70030FAB6 /* convert_from.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05617C157CD00CA0FD2 /* convert_from.cc */; };
- D159BCB917C228310030FAB6 /* rotate_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06017C157CD00CA0FD2 /* rotate_argb.cc */; };
- D159BCBA17C228320030FAB6 /* rotate_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06017C157CD00CA0FD2 /* rotate_argb.cc */; };
- D159BCBB17C228320030FAB6 /* rotate_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06017C157CD00CA0FD2 /* rotate_argb.cc */; };
- D159BCBC17C228330030FAB6 /* rotate_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06017C157CD00CA0FD2 /* rotate_argb.cc */; };
- D159BCBD17C228330030FAB6 /* rotate_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06017C157CD00CA0FD2 /* rotate_argb.cc */; };
- D159BCBE17C228340030FAB6 /* rotate_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06017C157CD00CA0FD2 /* rotate_argb.cc */; };
- D159BCBF17C228340030FAB6 /* rotate_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06017C157CD00CA0FD2 /* rotate_argb.cc */; };
- D159BCC017C228340030FAB6 /* rotate_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06017C157CD00CA0FD2 /* rotate_argb.cc */; };
- D159BCC117C228350030FAB6 /* rotate_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06017C157CD00CA0FD2 /* rotate_argb.cc */; };
- D159BCC217C2286D0030FAB6 /* scale.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06F17C157CD00CA0FD2 /* scale.cc */; };
- D159BCC317C2286D0030FAB6 /* scale.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06F17C157CD00CA0FD2 /* scale.cc */; };
- D159BCC417C2286D0030FAB6 /* scale.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06F17C157CD00CA0FD2 /* scale.cc */; };
- D159BCC517C2286E0030FAB6 /* scale.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06F17C157CD00CA0FD2 /* scale.cc */; };
- D159BCC617C2286E0030FAB6 /* scale.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06F17C157CD00CA0FD2 /* scale.cc */; };
- D159BCC717C2286F0030FAB6 /* scale.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06F17C157CD00CA0FD2 /* scale.cc */; };
- D159BCC817C2286F0030FAB6 /* scale.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06F17C157CD00CA0FD2 /* scale.cc */; };
- D159BCC917C2286F0030FAB6 /* scale.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06F17C157CD00CA0FD2 /* scale.cc */; };
- D159BCCA17C228700030FAB6 /* scale.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06F17C157CD00CA0FD2 /* scale.cc */; };
- D15D361017C386A600F40439 /* row_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06817C157CD00CA0FD2 /* row_posix.cc */; };
- D15D361117C386A600F40439 /* row_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06817C157CD00CA0FD2 /* row_posix.cc */; };
- D15D361217C386A700F40439 /* row_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06817C157CD00CA0FD2 /* row_posix.cc */; };
- D15D361317C386B100F40439 /* compare_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05117C157CD00CA0FD2 /* compare_posix.cc */; };
- D15D361517C386B300F40439 /* compare_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05117C157CD00CA0FD2 /* compare_posix.cc */; };
- D15D361617C386B400F40439 /* compare_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05117C157CD00CA0FD2 /* compare_posix.cc */; };
- D16775AB155C501D0050EC64 /* TheoraAsync.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D167759E155C501D0050EC64 /* TheoraAsync.cpp */; };
- D16775AC155C501D0050EC64 /* TheoraAsync.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D167759E155C501D0050EC64 /* TheoraAsync.cpp */; };
- D16775AD155C501D0050EC64 /* TheoraAudioInterface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D167759F155C501D0050EC64 /* TheoraAudioInterface.cpp */; };
- D16775AE155C501D0050EC64 /* TheoraAudioInterface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D167759F155C501D0050EC64 /* TheoraAudioInterface.cpp */; };
- D16775AF155C501D0050EC64 /* TheoraDataSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A0155C501D0050EC64 /* TheoraDataSource.cpp */; };
- D16775B0155C501D0050EC64 /* TheoraDataSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A0155C501D0050EC64 /* TheoraDataSource.cpp */; };
- D16775B1155C501D0050EC64 /* TheoraException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A1155C501D0050EC64 /* TheoraException.cpp */; };
- D16775B2155C501D0050EC64 /* TheoraException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A1155C501D0050EC64 /* TheoraException.cpp */; };
- D16775B3155C501D0050EC64 /* TheoraFrameQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A2155C501D0050EC64 /* TheoraFrameQueue.cpp */; };
- D16775B4155C501D0050EC64 /* TheoraFrameQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A2155C501D0050EC64 /* TheoraFrameQueue.cpp */; };
- D16775B5155C501D0050EC64 /* TheoraTimer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A3155C501D0050EC64 /* TheoraTimer.cpp */; };
- D16775B6155C501D0050EC64 /* TheoraTimer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A3155C501D0050EC64 /* TheoraTimer.cpp */; };
- D16775B7155C501D0050EC64 /* TheoraUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A4155C501D0050EC64 /* TheoraUtil.cpp */; };
- D16775B8155C501D0050EC64 /* TheoraUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A4155C501D0050EC64 /* TheoraUtil.cpp */; };
- D16775B9155C501D0050EC64 /* TheoraVideoClip.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A5155C501D0050EC64 /* TheoraVideoClip.cpp */; };
- D16775BA155C501D0050EC64 /* TheoraVideoClip.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A5155C501D0050EC64 /* TheoraVideoClip.cpp */; };
- D16775BB155C501D0050EC64 /* TheoraVideoFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A6155C501D0050EC64 /* TheoraVideoFrame.cpp */; };
- D16775BC155C501D0050EC64 /* TheoraVideoFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A6155C501D0050EC64 /* TheoraVideoFrame.cpp */; };
- D16775BD155C501D0050EC64 /* TheoraVideoManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A7155C501D0050EC64 /* TheoraVideoManager.cpp */; };
- D16775BE155C501D0050EC64 /* TheoraVideoManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A7155C501D0050EC64 /* TheoraVideoManager.cpp */; };
- D16775BF155C501D0050EC64 /* TheoraWorkerThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A8155C501D0050EC64 /* TheoraWorkerThread.cpp */; };
- D16775C0155C501D0050EC64 /* TheoraWorkerThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A8155C501D0050EC64 /* TheoraWorkerThread.cpp */; };
- D16775CE155C50280050EC64 /* TheoraAsync.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C1155C50280050EC64 /* TheoraAsync.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D16775CF155C50280050EC64 /* TheoraAsync.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C1155C50280050EC64 /* TheoraAsync.h */; };
- D16775D0155C50280050EC64 /* TheoraAudioInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C2155C50280050EC64 /* TheoraAudioInterface.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D16775D1155C50280050EC64 /* TheoraAudioInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C2155C50280050EC64 /* TheoraAudioInterface.h */; };
- D16775D2155C50280050EC64 /* TheoraDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C3155C50280050EC64 /* TheoraDataSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D16775D3155C50280050EC64 /* TheoraDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C3155C50280050EC64 /* TheoraDataSource.h */; };
- D16775D4155C50280050EC64 /* TheoraException.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C4155C50280050EC64 /* TheoraException.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D16775D5155C50280050EC64 /* TheoraException.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C4155C50280050EC64 /* TheoraException.h */; };
- D16775D6155C50280050EC64 /* TheoraExport.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C5155C50280050EC64 /* TheoraExport.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D16775D7155C50280050EC64 /* TheoraExport.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C5155C50280050EC64 /* TheoraExport.h */; };
- D16775D8155C50280050EC64 /* TheoraFrameQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C6155C50280050EC64 /* TheoraFrameQueue.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D16775D9155C50280050EC64 /* TheoraFrameQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C6155C50280050EC64 /* TheoraFrameQueue.h */; };
- D16775DA155C50280050EC64 /* TheoraPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C7155C50280050EC64 /* TheoraPlayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D16775DB155C50280050EC64 /* TheoraPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C7155C50280050EC64 /* TheoraPlayer.h */; };
- D16775DC155C50280050EC64 /* TheoraTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C8155C50280050EC64 /* TheoraTimer.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D16775DD155C50280050EC64 /* TheoraTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C8155C50280050EC64 /* TheoraTimer.h */; };
- D16775DE155C50280050EC64 /* TheoraUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C9155C50280050EC64 /* TheoraUtil.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D16775DF155C50280050EC64 /* TheoraUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C9155C50280050EC64 /* TheoraUtil.h */; };
- D16775E0155C50280050EC64 /* TheoraVideoClip.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CA155C50280050EC64 /* TheoraVideoClip.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D16775E1155C50280050EC64 /* TheoraVideoClip.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CA155C50280050EC64 /* TheoraVideoClip.h */; };
- D16775E2155C50280050EC64 /* TheoraVideoFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CB155C50280050EC64 /* TheoraVideoFrame.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D16775E3155C50280050EC64 /* TheoraVideoFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CB155C50280050EC64 /* TheoraVideoFrame.h */; };
- D16775E4155C50280050EC64 /* TheoraVideoManager.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CC155C50280050EC64 /* TheoraVideoManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D16775E5155C50280050EC64 /* TheoraVideoManager.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CC155C50280050EC64 /* TheoraVideoManager.h */; };
- D16775E6155C50280050EC64 /* TheoraWorkerThread.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CD155C50280050EC64 /* TheoraWorkerThread.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D16775E7155C50280050EC64 /* TheoraWorkerThread.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CD155C50280050EC64 /* TheoraWorkerThread.h */; };
- D198F952177A31FC002942E3 /* TheoraAsync.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D167759E155C501D0050EC64 /* TheoraAsync.cpp */; };
- D198F953177A31FC002942E3 /* TheoraAudioInterface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D167759F155C501D0050EC64 /* TheoraAudioInterface.cpp */; };
- D198F954177A31FC002942E3 /* TheoraDataSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A0155C501D0050EC64 /* TheoraDataSource.cpp */; };
- D198F955177A31FC002942E3 /* TheoraException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A1155C501D0050EC64 /* TheoraException.cpp */; };
- D198F956177A31FC002942E3 /* TheoraFrameQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A2155C501D0050EC64 /* TheoraFrameQueue.cpp */; };
- D198F957177A31FC002942E3 /* TheoraTimer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A3155C501D0050EC64 /* TheoraTimer.cpp */; };
- D198F958177A31FC002942E3 /* TheoraUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A4155C501D0050EC64 /* TheoraUtil.cpp */; };
- D198F959177A31FC002942E3 /* TheoraVideoClip.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A5155C501D0050EC64 /* TheoraVideoClip.cpp */; };
- D198F95A177A31FC002942E3 /* TheoraVideoFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A6155C501D0050EC64 /* TheoraVideoFrame.cpp */; };
- D198F95B177A31FC002942E3 /* TheoraVideoManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A7155C501D0050EC64 /* TheoraVideoManager.cpp */; };
- D198F95C177A31FC002942E3 /* TheoraWorkerThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A8155C501D0050EC64 /* TheoraWorkerThread.cpp */; };
- D198F95D177A31FC002942E3 /* TheoraVideoClip_Theora.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D1CDFF941696D0F000609AB0 /* TheoraVideoClip_Theora.cpp */; };
- D198F95F177A31FC002942E3 /* yuv420_grey_c.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E2718A16B46F640046C00C /* yuv420_grey_c.c */; };
- D198F960177A31FC002942E3 /* yuv420_yuv_c.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E2718C16B46F640046C00C /* yuv420_yuv_c.c */; };
- D198F961177A31FC002942E3 /* yuv420_rgb_c.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E271AB16B470210046C00C /* yuv420_rgb_c.c */; };
- D198F962177A31FC002942E3 /* TheoraAudioPacketQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D1D465D916C2D070007A45AA /* TheoraAudioPacketQueue.cpp */; };
- D198F965177A31FC002942E3 /* TheoraAsync.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C1155C50280050EC64 /* TheoraAsync.h */; };
- D198F966177A31FC002942E3 /* TheoraAudioInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C2155C50280050EC64 /* TheoraAudioInterface.h */; };
- D198F967177A31FC002942E3 /* TheoraDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C3155C50280050EC64 /* TheoraDataSource.h */; };
- D198F968177A31FC002942E3 /* TheoraException.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C4155C50280050EC64 /* TheoraException.h */; };
- D198F969177A31FC002942E3 /* TheoraExport.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C5155C50280050EC64 /* TheoraExport.h */; };
- D198F96A177A31FC002942E3 /* TheoraFrameQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C6155C50280050EC64 /* TheoraFrameQueue.h */; };
- D198F96B177A31FC002942E3 /* TheoraPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C7155C50280050EC64 /* TheoraPlayer.h */; };
- D198F96C177A31FC002942E3 /* TheoraTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C8155C50280050EC64 /* TheoraTimer.h */; };
- D198F96D177A31FC002942E3 /* TheoraUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C9155C50280050EC64 /* TheoraUtil.h */; };
- D198F96E177A31FC002942E3 /* TheoraVideoClip.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CA155C50280050EC64 /* TheoraVideoClip.h */; };
- D198F96F177A31FC002942E3 /* TheoraVideoFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CB155C50280050EC64 /* TheoraVideoFrame.h */; };
- D198F970177A31FC002942E3 /* TheoraVideoManager.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CC155C50280050EC64 /* TheoraVideoManager.h */; };
- D198F971177A31FC002942E3 /* TheoraWorkerThread.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CD155C50280050EC64 /* TheoraWorkerThread.h */; };
- D198F972177A31FC002942E3 /* TheoraVideoClip_Theora.h in Headers */ = {isa = PBXBuildFile; fileRef = D1CDFF951696D0F000609AB0 /* TheoraVideoClip_Theora.h */; };
- D198F974177A31FC002942E3 /* TheoraPixelTransform.h in Headers */ = {isa = PBXBuildFile; fileRef = D1E271B216B471E80046C00C /* TheoraPixelTransform.h */; };
- D198F97E177A31FE002942E3 /* TheoraAsync.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D167759E155C501D0050EC64 /* TheoraAsync.cpp */; };
- D198F97F177A31FE002942E3 /* TheoraAudioInterface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D167759F155C501D0050EC64 /* TheoraAudioInterface.cpp */; };
- D198F980177A31FE002942E3 /* TheoraDataSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A0155C501D0050EC64 /* TheoraDataSource.cpp */; };
- D198F981177A31FE002942E3 /* TheoraException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A1155C501D0050EC64 /* TheoraException.cpp */; };
- D198F982177A31FE002942E3 /* TheoraFrameQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A2155C501D0050EC64 /* TheoraFrameQueue.cpp */; };
- D198F983177A31FE002942E3 /* TheoraTimer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A3155C501D0050EC64 /* TheoraTimer.cpp */; };
- D198F984177A31FE002942E3 /* TheoraUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A4155C501D0050EC64 /* TheoraUtil.cpp */; };
- D198F985177A31FE002942E3 /* TheoraVideoClip.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A5155C501D0050EC64 /* TheoraVideoClip.cpp */; };
- D198F986177A31FE002942E3 /* TheoraVideoFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A6155C501D0050EC64 /* TheoraVideoFrame.cpp */; };
- D198F987177A31FE002942E3 /* TheoraVideoManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A7155C501D0050EC64 /* TheoraVideoManager.cpp */; };
- D198F988177A31FE002942E3 /* TheoraWorkerThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A8155C501D0050EC64 /* TheoraWorkerThread.cpp */; };
- D198F989177A31FE002942E3 /* TheoraVideoClip_AVFoundation.mm in Sources */ = {isa = PBXBuildFile; fileRef = D1CDFF9C1696D0FA00609AB0 /* TheoraVideoClip_AVFoundation.mm */; };
- D198F98B177A31FE002942E3 /* yuv420_grey_c.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E2718A16B46F640046C00C /* yuv420_grey_c.c */; };
- D198F98C177A31FE002942E3 /* yuv420_yuv_c.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E2718C16B46F640046C00C /* yuv420_yuv_c.c */; };
- D198F98D177A31FE002942E3 /* yuv420_rgb_c.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E271AB16B470210046C00C /* yuv420_rgb_c.c */; };
- D198F98E177A31FE002942E3 /* TheoraAudioPacketQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D1D465D916C2D070007A45AA /* TheoraAudioPacketQueue.cpp */; };
- D198F991177A31FE002942E3 /* TheoraAsync.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C1155C50280050EC64 /* TheoraAsync.h */; };
- D198F992177A31FE002942E3 /* TheoraAudioInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C2155C50280050EC64 /* TheoraAudioInterface.h */; };
- D198F993177A31FE002942E3 /* TheoraDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C3155C50280050EC64 /* TheoraDataSource.h */; };
- D198F994177A31FE002942E3 /* TheoraException.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C4155C50280050EC64 /* TheoraException.h */; };
- D198F995177A31FE002942E3 /* TheoraExport.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C5155C50280050EC64 /* TheoraExport.h */; };
- D198F996177A31FE002942E3 /* TheoraFrameQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C6155C50280050EC64 /* TheoraFrameQueue.h */; };
- D198F997177A31FE002942E3 /* TheoraPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C7155C50280050EC64 /* TheoraPlayer.h */; };
- D198F998177A31FE002942E3 /* TheoraTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C8155C50280050EC64 /* TheoraTimer.h */; };
- D198F999177A31FE002942E3 /* TheoraUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C9155C50280050EC64 /* TheoraUtil.h */; };
- D198F99A177A31FE002942E3 /* TheoraVideoClip.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CA155C50280050EC64 /* TheoraVideoClip.h */; };
- D198F99B177A31FE002942E3 /* TheoraVideoFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CB155C50280050EC64 /* TheoraVideoFrame.h */; };
- D198F99C177A31FE002942E3 /* TheoraVideoManager.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CC155C50280050EC64 /* TheoraVideoManager.h */; };
- D198F99D177A31FE002942E3 /* TheoraWorkerThread.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CD155C50280050EC64 /* TheoraWorkerThread.h */; };
- D198F99E177A31FE002942E3 /* TheoraVideoClip_Theora.h in Headers */ = {isa = PBXBuildFile; fileRef = D1CDFF951696D0F000609AB0 /* TheoraVideoClip_Theora.h */; };
- D198F9A0177A31FE002942E3 /* TheoraPixelTransform.h in Headers */ = {isa = PBXBuildFile; fileRef = D1E271B216B471E80046C00C /* TheoraPixelTransform.h */; };
- D198F9AA177A3200002942E3 /* TheoraAsync.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D167759E155C501D0050EC64 /* TheoraAsync.cpp */; };
- D198F9AB177A3200002942E3 /* TheoraAudioInterface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D167759F155C501D0050EC64 /* TheoraAudioInterface.cpp */; };
- D198F9AC177A3200002942E3 /* TheoraDataSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A0155C501D0050EC64 /* TheoraDataSource.cpp */; };
- D198F9AD177A3200002942E3 /* TheoraException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A1155C501D0050EC64 /* TheoraException.cpp */; };
- D198F9AE177A3200002942E3 /* TheoraFrameQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A2155C501D0050EC64 /* TheoraFrameQueue.cpp */; };
- D198F9AF177A3200002942E3 /* TheoraTimer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A3155C501D0050EC64 /* TheoraTimer.cpp */; };
- D198F9B0177A3200002942E3 /* TheoraUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A4155C501D0050EC64 /* TheoraUtil.cpp */; };
- D198F9B1177A3200002942E3 /* TheoraVideoClip.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A5155C501D0050EC64 /* TheoraVideoClip.cpp */; };
- D198F9B2177A3200002942E3 /* TheoraVideoFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A6155C501D0050EC64 /* TheoraVideoFrame.cpp */; };
- D198F9B3177A3200002942E3 /* TheoraVideoManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A7155C501D0050EC64 /* TheoraVideoManager.cpp */; };
- D198F9B4177A3200002942E3 /* TheoraWorkerThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A8155C501D0050EC64 /* TheoraWorkerThread.cpp */; };
- D198F9B5177A3200002942E3 /* TheoraVideoClip_Theora.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D1CDFF941696D0F000609AB0 /* TheoraVideoClip_Theora.cpp */; };
- D198F9B6177A3200002942E3 /* TheoraVideoClip_AVFoundation.mm in Sources */ = {isa = PBXBuildFile; fileRef = D1CDFF9C1696D0FA00609AB0 /* TheoraVideoClip_AVFoundation.mm */; };
- D198F9B8177A3200002942E3 /* yuv420_grey_c.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E2718A16B46F640046C00C /* yuv420_grey_c.c */; };
- D198F9B9177A3200002942E3 /* yuv420_yuv_c.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E2718C16B46F640046C00C /* yuv420_yuv_c.c */; };
- D198F9BA177A3200002942E3 /* yuv420_rgb_c.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E271AB16B470210046C00C /* yuv420_rgb_c.c */; };
- D198F9BB177A3200002942E3 /* TheoraAudioPacketQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D1D465D916C2D070007A45AA /* TheoraAudioPacketQueue.cpp */; };
- D198F9BE177A3200002942E3 /* TheoraAsync.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C1155C50280050EC64 /* TheoraAsync.h */; };
- D198F9BF177A3200002942E3 /* TheoraAudioInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C2155C50280050EC64 /* TheoraAudioInterface.h */; };
- D198F9C0177A3200002942E3 /* TheoraDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C3155C50280050EC64 /* TheoraDataSource.h */; };
- D198F9C1177A3200002942E3 /* TheoraException.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C4155C50280050EC64 /* TheoraException.h */; };
- D198F9C2177A3200002942E3 /* TheoraExport.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C5155C50280050EC64 /* TheoraExport.h */; };
- D198F9C3177A3200002942E3 /* TheoraFrameQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C6155C50280050EC64 /* TheoraFrameQueue.h */; };
- D198F9C4177A3200002942E3 /* TheoraPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C7155C50280050EC64 /* TheoraPlayer.h */; };
- D198F9C5177A3200002942E3 /* TheoraTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C8155C50280050EC64 /* TheoraTimer.h */; };
- D198F9C6177A3200002942E3 /* TheoraUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C9155C50280050EC64 /* TheoraUtil.h */; };
- D198F9C7177A3200002942E3 /* TheoraVideoClip.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CA155C50280050EC64 /* TheoraVideoClip.h */; };
- D198F9C8177A3200002942E3 /* TheoraVideoFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CB155C50280050EC64 /* TheoraVideoFrame.h */; };
- D198F9C9177A3200002942E3 /* TheoraVideoManager.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CC155C50280050EC64 /* TheoraVideoManager.h */; };
- D198F9CA177A3200002942E3 /* TheoraWorkerThread.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CD155C50280050EC64 /* TheoraWorkerThread.h */; };
- D198F9CB177A3200002942E3 /* TheoraVideoClip_Theora.h in Headers */ = {isa = PBXBuildFile; fileRef = D1CDFF951696D0F000609AB0 /* TheoraVideoClip_Theora.h */; };
- D198F9CD177A3200002942E3 /* TheoraPixelTransform.h in Headers */ = {isa = PBXBuildFile; fileRef = D1E271B216B471E80046C00C /* TheoraPixelTransform.h */; };
- D1BCE05A18F3F7FE00C83470 /* scale_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1BCE05818F3F7FE00C83470 /* scale_common.cc */; };
- D1BCE05B18F3F7FE00C83470 /* scale_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1BCE05818F3F7FE00C83470 /* scale_common.cc */; };
- D1BCE05C18F3F7FE00C83470 /* scale_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1BCE05818F3F7FE00C83470 /* scale_common.cc */; };
- D1BCE05D18F3F7FE00C83470 /* scale_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1BCE05818F3F7FE00C83470 /* scale_common.cc */; };
- D1BCE05E18F3F7FE00C83470 /* scale_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1BCE05818F3F7FE00C83470 /* scale_common.cc */; };
- D1BCE05F18F3F7FE00C83470 /* scale_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1BCE05818F3F7FE00C83470 /* scale_common.cc */; };
- D1BCE06018F3F7FE00C83470 /* scale_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1BCE05818F3F7FE00C83470 /* scale_common.cc */; };
- D1BCE06118F3F7FE00C83470 /* scale_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1BCE05818F3F7FE00C83470 /* scale_common.cc */; };
- D1BCE06218F3F7FE00C83470 /* scale_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1BCE05818F3F7FE00C83470 /* scale_common.cc */; };
- D1BCE06318F3F7FE00C83470 /* scale_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1BCE05918F3F7FE00C83470 /* scale_posix.cc */; };
- D1BCE06418F3F7FE00C83470 /* scale_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1BCE05918F3F7FE00C83470 /* scale_posix.cc */; };
- D1BCE06518F3F7FE00C83470 /* scale_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1BCE05918F3F7FE00C83470 /* scale_posix.cc */; };
- D1BCE06618F3F7FE00C83470 /* scale_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1BCE05918F3F7FE00C83470 /* scale_posix.cc */; };
- D1BCE06718F3F7FE00C83470 /* scale_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1BCE05918F3F7FE00C83470 /* scale_posix.cc */; };
- D1BCE06818F3F7FE00C83470 /* scale_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1BCE05918F3F7FE00C83470 /* scale_posix.cc */; };
- D1BCE06918F3F7FE00C83470 /* scale_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1BCE05918F3F7FE00C83470 /* scale_posix.cc */; };
- D1BCE06A18F3F7FE00C83470 /* scale_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1BCE05918F3F7FE00C83470 /* scale_posix.cc */; };
- D1BCE06B18F3F7FE00C83470 /* scale_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1BCE05918F3F7FE00C83470 /* scale_posix.cc */; };
- D1C3D07217C157CD00CA0FD2 /* compare_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D04F17C157CD00CA0FD2 /* compare_common.cc */; };
- D1C3D07317C157CD00CA0FD2 /* compare_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D04F17C157CD00CA0FD2 /* compare_common.cc */; };
- D1C3D07417C157CD00CA0FD2 /* compare_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D04F17C157CD00CA0FD2 /* compare_common.cc */; };
- D1C3D07517C157CD00CA0FD2 /* compare_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D04F17C157CD00CA0FD2 /* compare_common.cc */; };
- D1C3D07617C157CD00CA0FD2 /* compare_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D04F17C157CD00CA0FD2 /* compare_common.cc */; };
- D1C3D07717C157CD00CA0FD2 /* compare_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D04F17C157CD00CA0FD2 /* compare_common.cc */; };
- D1C3D07817C157CD00CA0FD2 /* compare_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D04F17C157CD00CA0FD2 /* compare_common.cc */; };
- D1C3D07917C157CD00CA0FD2 /* compare_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D04F17C157CD00CA0FD2 /* compare_common.cc */; };
- D1C3D07A17C157CD00CA0FD2 /* compare_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D04F17C157CD00CA0FD2 /* compare_common.cc */; };
- D1C3D08117C157CD00CA0FD2 /* compare_neon.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05017C157CD00CA0FD2 /* compare_neon.cc */; };
- D1C3D08217C157CD00CA0FD2 /* compare_neon.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05017C157CD00CA0FD2 /* compare_neon.cc */; };
- D1C3D08317C157CD00CA0FD2 /* compare_neon.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05017C157CD00CA0FD2 /* compare_neon.cc */; };
- D1C3D08417C157CD00CA0FD2 /* compare_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05117C157CD00CA0FD2 /* compare_posix.cc */; };
- D1C3D08517C157CD00CA0FD2 /* compare_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05117C157CD00CA0FD2 /* compare_posix.cc */; };
- D1C3D08617C157CD00CA0FD2 /* compare_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05117C157CD00CA0FD2 /* compare_posix.cc */; };
- D1C3D08717C157CD00CA0FD2 /* compare_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05117C157CD00CA0FD2 /* compare_posix.cc */; };
- D1C3D08817C157CD00CA0FD2 /* compare_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05117C157CD00CA0FD2 /* compare_posix.cc */; };
- D1C3D08917C157CD00CA0FD2 /* compare_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05117C157CD00CA0FD2 /* compare_posix.cc */; };
- D1C3D09617C157CD00CA0FD2 /* compare.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05317C157CD00CA0FD2 /* compare.cc */; };
- D1C3D09717C157CD00CA0FD2 /* compare.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05317C157CD00CA0FD2 /* compare.cc */; };
- D1C3D09817C157CD00CA0FD2 /* compare.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05317C157CD00CA0FD2 /* compare.cc */; };
- D1C3D09917C157CD00CA0FD2 /* compare.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05317C157CD00CA0FD2 /* compare.cc */; };
- D1C3D09A17C157CD00CA0FD2 /* compare.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05317C157CD00CA0FD2 /* compare.cc */; };
- D1C3D09B17C157CD00CA0FD2 /* compare.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05317C157CD00CA0FD2 /* compare.cc */; };
- D1C3D09C17C157CD00CA0FD2 /* compare.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05317C157CD00CA0FD2 /* compare.cc */; };
- D1C3D09D17C157CD00CA0FD2 /* compare.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05317C157CD00CA0FD2 /* compare.cc */; };
- D1C3D09E17C157CD00CA0FD2 /* compare.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05317C157CD00CA0FD2 /* compare.cc */; };
- D1C3D09F17C157CD00CA0FD2 /* convert_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05417C157CD00CA0FD2 /* convert_argb.cc */; };
- D1C3D0A017C157CD00CA0FD2 /* convert_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05417C157CD00CA0FD2 /* convert_argb.cc */; };
- D1C3D0A117C157CD00CA0FD2 /* convert_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05417C157CD00CA0FD2 /* convert_argb.cc */; };
- D1C3D0A217C157CD00CA0FD2 /* convert_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05417C157CD00CA0FD2 /* convert_argb.cc */; };
- D1C3D0A317C157CD00CA0FD2 /* convert_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05417C157CD00CA0FD2 /* convert_argb.cc */; };
- D1C3D0A417C157CD00CA0FD2 /* convert_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05417C157CD00CA0FD2 /* convert_argb.cc */; };
- D1C3D0A517C157CD00CA0FD2 /* convert_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05417C157CD00CA0FD2 /* convert_argb.cc */; };
- D1C3D0A617C157CD00CA0FD2 /* convert_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05417C157CD00CA0FD2 /* convert_argb.cc */; };
- D1C3D0A717C157CD00CA0FD2 /* convert_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05417C157CD00CA0FD2 /* convert_argb.cc */; };
- D1C3D0C317C157CD00CA0FD2 /* convert_to_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05817C157CD00CA0FD2 /* convert_to_argb.cc */; };
- D1C3D0C417C157CD00CA0FD2 /* convert_to_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05817C157CD00CA0FD2 /* convert_to_argb.cc */; };
- D1C3D0C517C157CD00CA0FD2 /* convert_to_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05817C157CD00CA0FD2 /* convert_to_argb.cc */; };
- D1C3D0C617C157CD00CA0FD2 /* convert_to_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05817C157CD00CA0FD2 /* convert_to_argb.cc */; };
- D1C3D0C717C157CD00CA0FD2 /* convert_to_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05817C157CD00CA0FD2 /* convert_to_argb.cc */; };
- D1C3D0C817C157CD00CA0FD2 /* convert_to_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05817C157CD00CA0FD2 /* convert_to_argb.cc */; };
- D1C3D0C917C157CD00CA0FD2 /* convert_to_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05817C157CD00CA0FD2 /* convert_to_argb.cc */; };
- D1C3D0CA17C157CD00CA0FD2 /* convert_to_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05817C157CD00CA0FD2 /* convert_to_argb.cc */; };
- D1C3D0CB17C157CD00CA0FD2 /* convert_to_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05817C157CD00CA0FD2 /* convert_to_argb.cc */; };
- D1C3D0CC17C157CD00CA0FD2 /* convert_to_i420.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05917C157CD00CA0FD2 /* convert_to_i420.cc */; };
- D1C3D0CD17C157CD00CA0FD2 /* convert_to_i420.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05917C157CD00CA0FD2 /* convert_to_i420.cc */; };
- D1C3D0CE17C157CD00CA0FD2 /* convert_to_i420.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05917C157CD00CA0FD2 /* convert_to_i420.cc */; };
- D1C3D0CF17C157CD00CA0FD2 /* convert_to_i420.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05917C157CD00CA0FD2 /* convert_to_i420.cc */; };
- D1C3D0D017C157CD00CA0FD2 /* convert_to_i420.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05917C157CD00CA0FD2 /* convert_to_i420.cc */; };
- D1C3D0D117C157CD00CA0FD2 /* convert_to_i420.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05917C157CD00CA0FD2 /* convert_to_i420.cc */; };
- D1C3D0D217C157CD00CA0FD2 /* convert_to_i420.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05917C157CD00CA0FD2 /* convert_to_i420.cc */; };
- D1C3D0D317C157CD00CA0FD2 /* convert_to_i420.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05917C157CD00CA0FD2 /* convert_to_i420.cc */; };
- D1C3D0D417C157CD00CA0FD2 /* convert_to_i420.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05917C157CD00CA0FD2 /* convert_to_i420.cc */; };
- D1C3D0D517C157CD00CA0FD2 /* convert.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05A17C157CD00CA0FD2 /* convert.cc */; };
- D1C3D0D617C157CD00CA0FD2 /* convert.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05A17C157CD00CA0FD2 /* convert.cc */; };
- D1C3D0D717C157CD00CA0FD2 /* convert.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05A17C157CD00CA0FD2 /* convert.cc */; };
- D1C3D0D817C157CD00CA0FD2 /* convert.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05A17C157CD00CA0FD2 /* convert.cc */; };
- D1C3D0D917C157CD00CA0FD2 /* convert.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05A17C157CD00CA0FD2 /* convert.cc */; };
- D1C3D0DA17C157CD00CA0FD2 /* convert.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05A17C157CD00CA0FD2 /* convert.cc */; };
- D1C3D0DB17C157CD00CA0FD2 /* convert.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05A17C157CD00CA0FD2 /* convert.cc */; };
- D1C3D0DC17C157CD00CA0FD2 /* convert.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05A17C157CD00CA0FD2 /* convert.cc */; };
- D1C3D0DD17C157CD00CA0FD2 /* convert.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05A17C157CD00CA0FD2 /* convert.cc */; };
- D1C3D0DE17C157CD00CA0FD2 /* cpu_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05B17C157CD00CA0FD2 /* cpu_id.cc */; };
- D1C3D0DF17C157CD00CA0FD2 /* cpu_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05B17C157CD00CA0FD2 /* cpu_id.cc */; };
- D1C3D0E017C157CD00CA0FD2 /* cpu_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05B17C157CD00CA0FD2 /* cpu_id.cc */; };
- D1C3D0E117C157CD00CA0FD2 /* cpu_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05B17C157CD00CA0FD2 /* cpu_id.cc */; };
- D1C3D0E217C157CD00CA0FD2 /* cpu_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05B17C157CD00CA0FD2 /* cpu_id.cc */; };
- D1C3D0E317C157CD00CA0FD2 /* cpu_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05B17C157CD00CA0FD2 /* cpu_id.cc */; };
- D1C3D0E417C157CD00CA0FD2 /* cpu_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05B17C157CD00CA0FD2 /* cpu_id.cc */; };
- D1C3D0E517C157CD00CA0FD2 /* cpu_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05B17C157CD00CA0FD2 /* cpu_id.cc */; };
- D1C3D0E617C157CD00CA0FD2 /* cpu_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05B17C157CD00CA0FD2 /* cpu_id.cc */; };
- D1C3D0E717C157CD00CA0FD2 /* format_conversion.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05C17C157CD00CA0FD2 /* format_conversion.cc */; };
- D1C3D0E817C157CD00CA0FD2 /* format_conversion.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05C17C157CD00CA0FD2 /* format_conversion.cc */; };
- D1C3D0E917C157CD00CA0FD2 /* format_conversion.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05C17C157CD00CA0FD2 /* format_conversion.cc */; };
- D1C3D0EA17C157CD00CA0FD2 /* format_conversion.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05C17C157CD00CA0FD2 /* format_conversion.cc */; };
- D1C3D0EB17C157CD00CA0FD2 /* format_conversion.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05C17C157CD00CA0FD2 /* format_conversion.cc */; };
- D1C3D0EC17C157CD00CA0FD2 /* format_conversion.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05C17C157CD00CA0FD2 /* format_conversion.cc */; };
- D1C3D0ED17C157CD00CA0FD2 /* format_conversion.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05C17C157CD00CA0FD2 /* format_conversion.cc */; };
- D1C3D0EE17C157CD00CA0FD2 /* format_conversion.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05C17C157CD00CA0FD2 /* format_conversion.cc */; };
- D1C3D0EF17C157CD00CA0FD2 /* format_conversion.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05C17C157CD00CA0FD2 /* format_conversion.cc */; };
- D1C3D10217C157CD00CA0FD2 /* planar_functions.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05F17C157CD00CA0FD2 /* planar_functions.cc */; };
- D1C3D10317C157CD00CA0FD2 /* planar_functions.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05F17C157CD00CA0FD2 /* planar_functions.cc */; };
- D1C3D10417C157CD00CA0FD2 /* planar_functions.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05F17C157CD00CA0FD2 /* planar_functions.cc */; };
- D1C3D10517C157CD00CA0FD2 /* planar_functions.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05F17C157CD00CA0FD2 /* planar_functions.cc */; };
- D1C3D10617C157CD00CA0FD2 /* planar_functions.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05F17C157CD00CA0FD2 /* planar_functions.cc */; };
- D1C3D10717C157CD00CA0FD2 /* planar_functions.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05F17C157CD00CA0FD2 /* planar_functions.cc */; };
- D1C3D10817C157CD00CA0FD2 /* planar_functions.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05F17C157CD00CA0FD2 /* planar_functions.cc */; };
- D1C3D10917C157CD00CA0FD2 /* planar_functions.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05F17C157CD00CA0FD2 /* planar_functions.cc */; };
- D1C3D10A17C157CD00CA0FD2 /* planar_functions.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D05F17C157CD00CA0FD2 /* planar_functions.cc */; };
- D1C3D12317C157CD00CA0FD2 /* rotate_neon.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06217C157CD00CA0FD2 /* rotate_neon.cc */; };
- D1C3D12417C157CD00CA0FD2 /* rotate_neon.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06217C157CD00CA0FD2 /* rotate_neon.cc */; };
- D1C3D12517C157CD00CA0FD2 /* rotate_neon.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06217C157CD00CA0FD2 /* rotate_neon.cc */; };
- D1C3D12617C157CD00CA0FD2 /* rotate.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06317C157CD00CA0FD2 /* rotate.cc */; };
- D1C3D12717C157CD00CA0FD2 /* rotate.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06317C157CD00CA0FD2 /* rotate.cc */; };
- D1C3D12817C157CD00CA0FD2 /* rotate.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06317C157CD00CA0FD2 /* rotate.cc */; };
- D1C3D12917C157CD00CA0FD2 /* rotate.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06317C157CD00CA0FD2 /* rotate.cc */; };
- D1C3D12A17C157CD00CA0FD2 /* rotate.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06317C157CD00CA0FD2 /* rotate.cc */; };
- D1C3D12B17C157CD00CA0FD2 /* rotate.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06317C157CD00CA0FD2 /* rotate.cc */; };
- D1C3D12C17C157CD00CA0FD2 /* rotate.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06317C157CD00CA0FD2 /* rotate.cc */; };
- D1C3D12D17C157CD00CA0FD2 /* rotate.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06317C157CD00CA0FD2 /* rotate.cc */; };
- D1C3D12E17C157CD00CA0FD2 /* rotate.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06317C157CD00CA0FD2 /* rotate.cc */; };
- D1C3D12F17C157CD00CA0FD2 /* row_any.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06417C157CD00CA0FD2 /* row_any.cc */; };
- D1C3D13017C157CD00CA0FD2 /* row_any.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06417C157CD00CA0FD2 /* row_any.cc */; };
- D1C3D13117C157CD00CA0FD2 /* row_any.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06417C157CD00CA0FD2 /* row_any.cc */; };
- D1C3D13217C157CD00CA0FD2 /* row_any.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06417C157CD00CA0FD2 /* row_any.cc */; };
- D1C3D13317C157CD00CA0FD2 /* row_any.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06417C157CD00CA0FD2 /* row_any.cc */; };
- D1C3D13417C157CD00CA0FD2 /* row_any.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06417C157CD00CA0FD2 /* row_any.cc */; };
- D1C3D13517C157CD00CA0FD2 /* row_any.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06417C157CD00CA0FD2 /* row_any.cc */; };
- D1C3D13617C157CD00CA0FD2 /* row_any.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06417C157CD00CA0FD2 /* row_any.cc */; };
- D1C3D13717C157CD00CA0FD2 /* row_any.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06417C157CD00CA0FD2 /* row_any.cc */; };
- D1C3D13817C157CD00CA0FD2 /* row_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06517C157CD00CA0FD2 /* row_common.cc */; };
- D1C3D13917C157CD00CA0FD2 /* row_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06517C157CD00CA0FD2 /* row_common.cc */; };
- D1C3D13A17C157CD00CA0FD2 /* row_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06517C157CD00CA0FD2 /* row_common.cc */; };
- D1C3D13B17C157CD00CA0FD2 /* row_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06517C157CD00CA0FD2 /* row_common.cc */; };
- D1C3D13C17C157CD00CA0FD2 /* row_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06517C157CD00CA0FD2 /* row_common.cc */; };
- D1C3D13D17C157CD00CA0FD2 /* row_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06517C157CD00CA0FD2 /* row_common.cc */; };
- D1C3D13E17C157CD00CA0FD2 /* row_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06517C157CD00CA0FD2 /* row_common.cc */; };
- D1C3D13F17C157CD00CA0FD2 /* row_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06517C157CD00CA0FD2 /* row_common.cc */; };
- D1C3D14017C157CD00CA0FD2 /* row_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06517C157CD00CA0FD2 /* row_common.cc */; };
- D1C3D15017C157CD00CA0FD2 /* row_neon.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06717C157CD00CA0FD2 /* row_neon.cc */; };
- D1C3D15117C157CD00CA0FD2 /* row_neon.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06717C157CD00CA0FD2 /* row_neon.cc */; };
- D1C3D15217C157CD00CA0FD2 /* row_neon.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06717C157CD00CA0FD2 /* row_neon.cc */; };
- D1C3D15317C157CD00CA0FD2 /* row_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06817C157CD00CA0FD2 /* row_posix.cc */; };
- D1C3D15417C157CD00CA0FD2 /* row_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06817C157CD00CA0FD2 /* row_posix.cc */; };
- D1C3D15517C157CD00CA0FD2 /* row_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06817C157CD00CA0FD2 /* row_posix.cc */; };
- D1C3D15617C157CD00CA0FD2 /* row_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06817C157CD00CA0FD2 /* row_posix.cc */; };
- D1C3D15717C157CD00CA0FD2 /* row_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06817C157CD00CA0FD2 /* row_posix.cc */; };
- D1C3D15817C157CD00CA0FD2 /* row_posix.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06817C157CD00CA0FD2 /* row_posix.cc */; };
- D1C3D17417C157CD00CA0FD2 /* scale_argb_neon.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06B17C157CD00CA0FD2 /* scale_argb_neon.cc */; };
- D1C3D17517C157CD00CA0FD2 /* scale_argb_neon.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06B17C157CD00CA0FD2 /* scale_argb_neon.cc */; };
- D1C3D17617C157CD00CA0FD2 /* scale_argb_neon.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06B17C157CD00CA0FD2 /* scale_argb_neon.cc */; };
- D1C3D17717C157CD00CA0FD2 /* scale_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06C17C157CD00CA0FD2 /* scale_argb.cc */; };
- D1C3D17817C157CD00CA0FD2 /* scale_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06C17C157CD00CA0FD2 /* scale_argb.cc */; };
- D1C3D17917C157CD00CA0FD2 /* scale_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06C17C157CD00CA0FD2 /* scale_argb.cc */; };
- D1C3D17A17C157CD00CA0FD2 /* scale_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06C17C157CD00CA0FD2 /* scale_argb.cc */; };
- D1C3D17B17C157CD00CA0FD2 /* scale_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06C17C157CD00CA0FD2 /* scale_argb.cc */; };
- D1C3D17C17C157CD00CA0FD2 /* scale_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06C17C157CD00CA0FD2 /* scale_argb.cc */; };
- D1C3D17D17C157CD00CA0FD2 /* scale_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06C17C157CD00CA0FD2 /* scale_argb.cc */; };
- D1C3D17E17C157CD00CA0FD2 /* scale_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06C17C157CD00CA0FD2 /* scale_argb.cc */; };
- D1C3D17F17C157CD00CA0FD2 /* scale_argb.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06C17C157CD00CA0FD2 /* scale_argb.cc */; };
- D1C3D18F17C157CD00CA0FD2 /* scale_neon.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06E17C157CD00CA0FD2 /* scale_neon.cc */; };
- D1C3D19017C157CD00CA0FD2 /* scale_neon.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06E17C157CD00CA0FD2 /* scale_neon.cc */; };
- D1C3D19117C157CD00CA0FD2 /* scale_neon.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D06E17C157CD00CA0FD2 /* scale_neon.cc */; };
- D1C3D19B17C157CD00CA0FD2 /* video_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D07017C157CD00CA0FD2 /* video_common.cc */; };
- D1C3D19C17C157CD00CA0FD2 /* video_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D07017C157CD00CA0FD2 /* video_common.cc */; };
- D1C3D19D17C157CD00CA0FD2 /* video_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D07017C157CD00CA0FD2 /* video_common.cc */; };
- D1C3D19E17C157CD00CA0FD2 /* video_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D07017C157CD00CA0FD2 /* video_common.cc */; };
- D1C3D19F17C157CD00CA0FD2 /* video_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D07017C157CD00CA0FD2 /* video_common.cc */; };
- D1C3D1A017C157CD00CA0FD2 /* video_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D07017C157CD00CA0FD2 /* video_common.cc */; };
- D1C3D1A117C157CD00CA0FD2 /* video_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D07017C157CD00CA0FD2 /* video_common.cc */; };
- D1C3D1A217C157CD00CA0FD2 /* video_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D07017C157CD00CA0FD2 /* video_common.cc */; };
- D1C3D1A317C157CD00CA0FD2 /* video_common.cc in Sources */ = {isa = PBXBuildFile; fileRef = D1C3D07017C157CD00CA0FD2 /* video_common.cc */; };
- D1CD00001696FC0B00609AB0 /* Theora.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D1CDFFFB1696FC0100609AB0 /* Theora.framework */; };
- D1CD00011696FC0B00609AB0 /* Vorbis.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D1CDFFF91696FBF700609AB0 /* Vorbis.framework */; };
- D1CD00021696FC0B00609AB0 /* Ogg.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D1CDFFF71696FBF400609AB0 /* Ogg.framework */; };
- D1CD00041696FF9400609AB0 /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D1CD00031696FF9400609AB0 /* CoreMedia.framework */; };
- D1CD00051696FF9600609AB0 /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D1CD00031696FF9400609AB0 /* CoreMedia.framework */; };
- D1CDFF241696C77A00609AB0 /* TheoraAsync.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D167759E155C501D0050EC64 /* TheoraAsync.cpp */; };
- D1CDFF251696C77A00609AB0 /* TheoraAudioInterface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D167759F155C501D0050EC64 /* TheoraAudioInterface.cpp */; };
- D1CDFF261696C77A00609AB0 /* TheoraDataSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A0155C501D0050EC64 /* TheoraDataSource.cpp */; };
- D1CDFF271696C77A00609AB0 /* TheoraException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A1155C501D0050EC64 /* TheoraException.cpp */; };
- D1CDFF281696C77A00609AB0 /* TheoraFrameQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A2155C501D0050EC64 /* TheoraFrameQueue.cpp */; };
- D1CDFF291696C77A00609AB0 /* TheoraTimer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A3155C501D0050EC64 /* TheoraTimer.cpp */; };
- D1CDFF2A1696C77A00609AB0 /* TheoraUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A4155C501D0050EC64 /* TheoraUtil.cpp */; };
- D1CDFF2B1696C77A00609AB0 /* TheoraVideoClip.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A5155C501D0050EC64 /* TheoraVideoClip.cpp */; };
- D1CDFF2C1696C77A00609AB0 /* TheoraVideoFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A6155C501D0050EC64 /* TheoraVideoFrame.cpp */; };
- D1CDFF2D1696C77A00609AB0 /* TheoraVideoManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A7155C501D0050EC64 /* TheoraVideoManager.cpp */; };
- D1CDFF2E1696C77A00609AB0 /* TheoraWorkerThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A8155C501D0050EC64 /* TheoraWorkerThread.cpp */; };
- D1CDFF341696C77A00609AB0 /* TheoraAsync.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C1155C50280050EC64 /* TheoraAsync.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1CDFF351696C77A00609AB0 /* TheoraAudioInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C2155C50280050EC64 /* TheoraAudioInterface.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1CDFF361696C77A00609AB0 /* TheoraDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C3155C50280050EC64 /* TheoraDataSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1CDFF371696C77A00609AB0 /* TheoraException.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C4155C50280050EC64 /* TheoraException.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1CDFF381696C77A00609AB0 /* TheoraExport.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C5155C50280050EC64 /* TheoraExport.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1CDFF391696C77A00609AB0 /* TheoraFrameQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C6155C50280050EC64 /* TheoraFrameQueue.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1CDFF3A1696C77A00609AB0 /* TheoraPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C7155C50280050EC64 /* TheoraPlayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1CDFF3B1696C77A00609AB0 /* TheoraTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C8155C50280050EC64 /* TheoraTimer.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1CDFF3C1696C77A00609AB0 /* TheoraUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C9155C50280050EC64 /* TheoraUtil.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1CDFF3D1696C77A00609AB0 /* TheoraVideoClip.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CA155C50280050EC64 /* TheoraVideoClip.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1CDFF3E1696C77A00609AB0 /* TheoraVideoFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CB155C50280050EC64 /* TheoraVideoFrame.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1CDFF3F1696C77A00609AB0 /* TheoraVideoManager.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CC155C50280050EC64 /* TheoraVideoManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1CDFF401696C77A00609AB0 /* TheoraWorkerThread.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CD155C50280050EC64 /* TheoraWorkerThread.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1CDFF4C1696C79700609AB0 /* TheoraAsync.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D167759E155C501D0050EC64 /* TheoraAsync.cpp */; };
- D1CDFF4D1696C79700609AB0 /* TheoraAudioInterface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D167759F155C501D0050EC64 /* TheoraAudioInterface.cpp */; };
- D1CDFF4E1696C79700609AB0 /* TheoraDataSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A0155C501D0050EC64 /* TheoraDataSource.cpp */; };
- D1CDFF4F1696C79700609AB0 /* TheoraException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A1155C501D0050EC64 /* TheoraException.cpp */; };
- D1CDFF501696C79700609AB0 /* TheoraFrameQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A2155C501D0050EC64 /* TheoraFrameQueue.cpp */; };
- D1CDFF511696C79700609AB0 /* TheoraTimer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A3155C501D0050EC64 /* TheoraTimer.cpp */; };
- D1CDFF521696C79700609AB0 /* TheoraUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A4155C501D0050EC64 /* TheoraUtil.cpp */; };
- D1CDFF531696C79700609AB0 /* TheoraVideoClip.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A5155C501D0050EC64 /* TheoraVideoClip.cpp */; };
- D1CDFF541696C79700609AB0 /* TheoraVideoFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A6155C501D0050EC64 /* TheoraVideoFrame.cpp */; };
- D1CDFF551696C79700609AB0 /* TheoraVideoManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A7155C501D0050EC64 /* TheoraVideoManager.cpp */; };
- D1CDFF561696C79700609AB0 /* TheoraWorkerThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A8155C501D0050EC64 /* TheoraWorkerThread.cpp */; };
- D1CDFF5C1696C79700609AB0 /* TheoraAsync.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C1155C50280050EC64 /* TheoraAsync.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1CDFF5D1696C79700609AB0 /* TheoraAudioInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C2155C50280050EC64 /* TheoraAudioInterface.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1CDFF5E1696C79700609AB0 /* TheoraDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C3155C50280050EC64 /* TheoraDataSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1CDFF5F1696C79700609AB0 /* TheoraException.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C4155C50280050EC64 /* TheoraException.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1CDFF601696C79700609AB0 /* TheoraExport.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C5155C50280050EC64 /* TheoraExport.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1CDFF611696C79700609AB0 /* TheoraFrameQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C6155C50280050EC64 /* TheoraFrameQueue.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1CDFF621696C79700609AB0 /* TheoraPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C7155C50280050EC64 /* TheoraPlayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1CDFF631696C79700609AB0 /* TheoraTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C8155C50280050EC64 /* TheoraTimer.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1CDFF641696C79700609AB0 /* TheoraUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C9155C50280050EC64 /* TheoraUtil.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1CDFF651696C79700609AB0 /* TheoraVideoClip.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CA155C50280050EC64 /* TheoraVideoClip.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1CDFF661696C79700609AB0 /* TheoraVideoFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CB155C50280050EC64 /* TheoraVideoFrame.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1CDFF671696C79700609AB0 /* TheoraVideoManager.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CC155C50280050EC64 /* TheoraVideoManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1CDFF681696C79700609AB0 /* TheoraWorkerThread.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CD155C50280050EC64 /* TheoraWorkerThread.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1CDFF961696D0F000609AB0 /* TheoraVideoClip_Theora.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D1CDFF941696D0F000609AB0 /* TheoraVideoClip_Theora.cpp */; };
- D1CDFF971696D0F000609AB0 /* TheoraVideoClip_Theora.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D1CDFF941696D0F000609AB0 /* TheoraVideoClip_Theora.cpp */; };
- D1CDFF981696D0F000609AB0 /* TheoraVideoClip_Theora.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D1CDFF941696D0F000609AB0 /* TheoraVideoClip_Theora.cpp */; };
- D1CDFF991696D0F000609AB0 /* TheoraVideoClip_Theora.h in Headers */ = {isa = PBXBuildFile; fileRef = D1CDFF951696D0F000609AB0 /* TheoraVideoClip_Theora.h */; };
- D1CDFF9A1696D0F000609AB0 /* TheoraVideoClip_Theora.h in Headers */ = {isa = PBXBuildFile; fileRef = D1CDFF951696D0F000609AB0 /* TheoraVideoClip_Theora.h */; };
- D1CDFF9B1696D0F000609AB0 /* TheoraVideoClip_Theora.h in Headers */ = {isa = PBXBuildFile; fileRef = D1CDFF951696D0F000609AB0 /* TheoraVideoClip_Theora.h */; };
- D1CDFF9E1696D0FA00609AB0 /* TheoraVideoClip_AVFoundation.mm in Sources */ = {isa = PBXBuildFile; fileRef = D1CDFF9C1696D0FA00609AB0 /* TheoraVideoClip_AVFoundation.mm */; };
- D1CDFF9F1696D0FA00609AB0 /* TheoraVideoClip_AVFoundation.h in Headers */ = {isa = PBXBuildFile; fileRef = D1CDFF9D1696D0FA00609AB0 /* TheoraVideoClip_AVFoundation.h */; };
- D1CDFFA21696E1CA00609AB0 /* TheoraAsync.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D167759E155C501D0050EC64 /* TheoraAsync.cpp */; };
- D1CDFFA31696E1CA00609AB0 /* TheoraAudioInterface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D167759F155C501D0050EC64 /* TheoraAudioInterface.cpp */; };
- D1CDFFA41696E1CA00609AB0 /* TheoraDataSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A0155C501D0050EC64 /* TheoraDataSource.cpp */; };
- D1CDFFA51696E1CA00609AB0 /* TheoraException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A1155C501D0050EC64 /* TheoraException.cpp */; };
- D1CDFFA61696E1CA00609AB0 /* TheoraFrameQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A2155C501D0050EC64 /* TheoraFrameQueue.cpp */; };
- D1CDFFA71696E1CA00609AB0 /* TheoraTimer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A3155C501D0050EC64 /* TheoraTimer.cpp */; };
- D1CDFFA81696E1CA00609AB0 /* TheoraUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A4155C501D0050EC64 /* TheoraUtil.cpp */; };
- D1CDFFA91696E1CA00609AB0 /* TheoraVideoClip.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A5155C501D0050EC64 /* TheoraVideoClip.cpp */; };
- D1CDFFAA1696E1CA00609AB0 /* TheoraVideoFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A6155C501D0050EC64 /* TheoraVideoFrame.cpp */; };
- D1CDFFAB1696E1CA00609AB0 /* TheoraVideoManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A7155C501D0050EC64 /* TheoraVideoManager.cpp */; };
- D1CDFFAC1696E1CA00609AB0 /* TheoraWorkerThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A8155C501D0050EC64 /* TheoraWorkerThread.cpp */; };
- D1CDFFB01696E1CA00609AB0 /* TheoraAsync.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C1155C50280050EC64 /* TheoraAsync.h */; };
- D1CDFFB11696E1CA00609AB0 /* TheoraAudioInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C2155C50280050EC64 /* TheoraAudioInterface.h */; };
- D1CDFFB21696E1CA00609AB0 /* TheoraDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C3155C50280050EC64 /* TheoraDataSource.h */; };
- D1CDFFB31696E1CA00609AB0 /* TheoraException.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C4155C50280050EC64 /* TheoraException.h */; };
- D1CDFFB41696E1CA00609AB0 /* TheoraExport.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C5155C50280050EC64 /* TheoraExport.h */; };
- D1CDFFB51696E1CA00609AB0 /* TheoraFrameQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C6155C50280050EC64 /* TheoraFrameQueue.h */; };
- D1CDFFB61696E1CA00609AB0 /* TheoraPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C7155C50280050EC64 /* TheoraPlayer.h */; };
- D1CDFFB71696E1CA00609AB0 /* TheoraTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C8155C50280050EC64 /* TheoraTimer.h */; };
- D1CDFFB81696E1CA00609AB0 /* TheoraUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C9155C50280050EC64 /* TheoraUtil.h */; };
- D1CDFFB91696E1CA00609AB0 /* TheoraVideoClip.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CA155C50280050EC64 /* TheoraVideoClip.h */; };
- D1CDFFBA1696E1CA00609AB0 /* TheoraVideoFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CB155C50280050EC64 /* TheoraVideoFrame.h */; };
- D1CDFFBB1696E1CA00609AB0 /* TheoraVideoManager.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CC155C50280050EC64 /* TheoraVideoManager.h */; };
- D1CDFFBC1696E1CA00609AB0 /* TheoraWorkerThread.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CD155C50280050EC64 /* TheoraWorkerThread.h */; };
- D1CDFFBD1696E1CA00609AB0 /* TheoraVideoClip_Theora.h in Headers */ = {isa = PBXBuildFile; fileRef = D1CDFF951696D0F000609AB0 /* TheoraVideoClip_Theora.h */; };
- D1CDFFC71696E1D700609AB0 /* TheoraAsync.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D167759E155C501D0050EC64 /* TheoraAsync.cpp */; };
- D1CDFFC81696E1D700609AB0 /* TheoraAudioInterface.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D167759F155C501D0050EC64 /* TheoraAudioInterface.cpp */; };
- D1CDFFC91696E1D700609AB0 /* TheoraDataSource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A0155C501D0050EC64 /* TheoraDataSource.cpp */; };
- D1CDFFCA1696E1D700609AB0 /* TheoraException.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A1155C501D0050EC64 /* TheoraException.cpp */; };
- D1CDFFCB1696E1D700609AB0 /* TheoraFrameQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A2155C501D0050EC64 /* TheoraFrameQueue.cpp */; };
- D1CDFFCC1696E1D700609AB0 /* TheoraTimer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A3155C501D0050EC64 /* TheoraTimer.cpp */; };
- D1CDFFCD1696E1D700609AB0 /* TheoraUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A4155C501D0050EC64 /* TheoraUtil.cpp */; };
- D1CDFFCE1696E1D700609AB0 /* TheoraVideoClip.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A5155C501D0050EC64 /* TheoraVideoClip.cpp */; };
- D1CDFFCF1696E1D700609AB0 /* TheoraVideoFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A6155C501D0050EC64 /* TheoraVideoFrame.cpp */; };
- D1CDFFD01696E1D700609AB0 /* TheoraVideoManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A7155C501D0050EC64 /* TheoraVideoManager.cpp */; };
- D1CDFFD11696E1D700609AB0 /* TheoraWorkerThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D16775A8155C501D0050EC64 /* TheoraWorkerThread.cpp */; };
- D1CDFFD21696E1D700609AB0 /* TheoraVideoClip_Theora.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D1CDFF941696D0F000609AB0 /* TheoraVideoClip_Theora.cpp */; };
- D1CDFFD51696E1D700609AB0 /* TheoraAsync.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C1155C50280050EC64 /* TheoraAsync.h */; };
- D1CDFFD61696E1D700609AB0 /* TheoraAudioInterface.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C2155C50280050EC64 /* TheoraAudioInterface.h */; };
- D1CDFFD71696E1D700609AB0 /* TheoraDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C3155C50280050EC64 /* TheoraDataSource.h */; };
- D1CDFFD81696E1D700609AB0 /* TheoraException.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C4155C50280050EC64 /* TheoraException.h */; };
- D1CDFFD91696E1D700609AB0 /* TheoraExport.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C5155C50280050EC64 /* TheoraExport.h */; };
- D1CDFFDA1696E1D700609AB0 /* TheoraFrameQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C6155C50280050EC64 /* TheoraFrameQueue.h */; };
- D1CDFFDB1696E1D700609AB0 /* TheoraPlayer.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C7155C50280050EC64 /* TheoraPlayer.h */; };
- D1CDFFDC1696E1D700609AB0 /* TheoraTimer.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C8155C50280050EC64 /* TheoraTimer.h */; };
- D1CDFFDD1696E1D700609AB0 /* TheoraUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775C9155C50280050EC64 /* TheoraUtil.h */; };
- D1CDFFDE1696E1D700609AB0 /* TheoraVideoClip.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CA155C50280050EC64 /* TheoraVideoClip.h */; };
- D1CDFFDF1696E1D700609AB0 /* TheoraVideoFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CB155C50280050EC64 /* TheoraVideoFrame.h */; };
- D1CDFFE01696E1D700609AB0 /* TheoraVideoManager.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CC155C50280050EC64 /* TheoraVideoManager.h */; };
- D1CDFFE11696E1D700609AB0 /* TheoraWorkerThread.h in Headers */ = {isa = PBXBuildFile; fileRef = D16775CD155C50280050EC64 /* TheoraWorkerThread.h */; };
- D1CDFFE21696E1D700609AB0 /* TheoraVideoClip_Theora.h in Headers */ = {isa = PBXBuildFile; fileRef = D1CDFF951696D0F000609AB0 /* TheoraVideoClip_Theora.h */; };
- D1CDFFEA1696E24B00609AB0 /* TheoraVideoClip_AVFoundation.mm in Sources */ = {isa = PBXBuildFile; fileRef = D1CDFF9C1696D0FA00609AB0 /* TheoraVideoClip_AVFoundation.mm */; };
- D1CDFFEB1696E24C00609AB0 /* TheoraVideoClip_AVFoundation.mm in Sources */ = {isa = PBXBuildFile; fileRef = D1CDFF9C1696D0FA00609AB0 /* TheoraVideoClip_AVFoundation.mm */; };
- D1CDFFEC1696E24F00609AB0 /* TheoraVideoClip_AVFoundation.mm in Sources */ = {isa = PBXBuildFile; fileRef = D1CDFF9C1696D0FA00609AB0 /* TheoraVideoClip_AVFoundation.mm */; };
- D1CDFFEE1696FB7200609AB0 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D1CDFFED1696FB7200609AB0 /* AVFoundation.framework */; };
- D1CDFFF11696FB8900609AB0 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D1CDFFF01696FB8900609AB0 /* CoreVideo.framework */; };
- D1CDFFF31696FBA800609AB0 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D1CDFFF21696FBA800609AB0 /* Foundation.framework */; };
- D1CDFFF41696FBB200609AB0 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D1CDFFF01696FB8900609AB0 /* CoreVideo.framework */; };
- D1CDFFF51696FBB200609AB0 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D1CDFFED1696FB7200609AB0 /* AVFoundation.framework */; };
- D1CDFFF61696FBB200609AB0 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D1CDFFF21696FBA800609AB0 /* Foundation.framework */; };
- D1CDFFFD1696FC0800609AB0 /* Theora.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D1CDFFFB1696FC0100609AB0 /* Theora.framework */; };
- D1CDFFFE1696FC0800609AB0 /* Vorbis.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D1CDFFF91696FBF700609AB0 /* Vorbis.framework */; };
- D1CDFFFF1696FC0800609AB0 /* Ogg.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D1CDFFF71696FBF400609AB0 /* Ogg.framework */; };
- D1D465D616C2D063007A45AA /* TheoraAudioPacketQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = D1D465D516C2D063007A45AA /* TheoraAudioPacketQueue.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1D465D716C2D063007A45AA /* TheoraAudioPacketQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = D1D465D516C2D063007A45AA /* TheoraAudioPacketQueue.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1D465D816C2D063007A45AA /* TheoraAudioPacketQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = D1D465D516C2D063007A45AA /* TheoraAudioPacketQueue.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1D465DA16C2D070007A45AA /* TheoraAudioPacketQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D1D465D916C2D070007A45AA /* TheoraAudioPacketQueue.cpp */; };
- D1D465DB16C2D070007A45AA /* TheoraAudioPacketQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D1D465D916C2D070007A45AA /* TheoraAudioPacketQueue.cpp */; };
- D1D465DC16C2D070007A45AA /* TheoraAudioPacketQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D1D465D916C2D070007A45AA /* TheoraAudioPacketQueue.cpp */; };
- D1D465DD16C2D070007A45AA /* TheoraAudioPacketQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D1D465D916C2D070007A45AA /* TheoraAudioPacketQueue.cpp */; };
- D1D465DE16C2D070007A45AA /* TheoraAudioPacketQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D1D465D916C2D070007A45AA /* TheoraAudioPacketQueue.cpp */; };
- D1D465DF16C2D070007A45AA /* TheoraAudioPacketQueue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D1D465D916C2D070007A45AA /* TheoraAudioPacketQueue.cpp */; };
- D1E2719916B46F640046C00C /* yuv420_grey_c.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E2718A16B46F640046C00C /* yuv420_grey_c.c */; };
- D1E2719A16B46F640046C00C /* yuv420_grey_c.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E2718A16B46F640046C00C /* yuv420_grey_c.c */; };
- D1E2719B16B46F640046C00C /* yuv420_grey_c.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E2718A16B46F640046C00C /* yuv420_grey_c.c */; };
- D1E2719C16B46F640046C00C /* yuv420_grey_c.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E2718A16B46F640046C00C /* yuv420_grey_c.c */; };
- D1E2719D16B46F640046C00C /* yuv420_grey_c.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E2718A16B46F640046C00C /* yuv420_grey_c.c */; };
- D1E2719E16B46F640046C00C /* yuv420_grey_c.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E2718A16B46F640046C00C /* yuv420_grey_c.c */; };
- D1E271A516B46F640046C00C /* yuv420_yuv_c.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E2718C16B46F640046C00C /* yuv420_yuv_c.c */; };
- D1E271A616B46F640046C00C /* yuv420_yuv_c.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E2718C16B46F640046C00C /* yuv420_yuv_c.c */; };
- D1E271A716B46F640046C00C /* yuv420_yuv_c.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E2718C16B46F640046C00C /* yuv420_yuv_c.c */; };
- D1E271A816B46F640046C00C /* yuv420_yuv_c.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E2718C16B46F640046C00C /* yuv420_yuv_c.c */; };
- D1E271A916B46F640046C00C /* yuv420_yuv_c.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E2718C16B46F640046C00C /* yuv420_yuv_c.c */; };
- D1E271AA16B46F640046C00C /* yuv420_yuv_c.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E2718C16B46F640046C00C /* yuv420_yuv_c.c */; };
- D1E271AC16B470210046C00C /* yuv420_rgb_c.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E271AB16B470210046C00C /* yuv420_rgb_c.c */; };
- D1E271AD16B470210046C00C /* yuv420_rgb_c.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E271AB16B470210046C00C /* yuv420_rgb_c.c */; };
- D1E271AE16B470210046C00C /* yuv420_rgb_c.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E271AB16B470210046C00C /* yuv420_rgb_c.c */; };
- D1E271AF16B470210046C00C /* yuv420_rgb_c.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E271AB16B470210046C00C /* yuv420_rgb_c.c */; };
- D1E271B016B470210046C00C /* yuv420_rgb_c.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E271AB16B470210046C00C /* yuv420_rgb_c.c */; };
- D1E271B116B470210046C00C /* yuv420_rgb_c.c in Sources */ = {isa = PBXBuildFile; fileRef = D1E271AB16B470210046C00C /* yuv420_rgb_c.c */; };
- D1E271B316B471E80046C00C /* TheoraPixelTransform.h in Headers */ = {isa = PBXBuildFile; fileRef = D1E271B216B471E80046C00C /* TheoraPixelTransform.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1E271B416B471E80046C00C /* TheoraPixelTransform.h in Headers */ = {isa = PBXBuildFile; fileRef = D1E271B216B471E80046C00C /* TheoraPixelTransform.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1E271B516B471E80046C00C /* TheoraPixelTransform.h in Headers */ = {isa = PBXBuildFile; fileRef = D1E271B216B471E80046C00C /* TheoraPixelTransform.h */; settings = {ATTRIBUTES = (Public, ); }; };
- D1E271B616B471E80046C00C /* TheoraPixelTransform.h in Headers */ = {isa = PBXBuildFile; fileRef = D1E271B216B471E80046C00C /* TheoraPixelTransform.h */; };
- D1E271B716B471E80046C00C /* TheoraPixelTransform.h in Headers */ = {isa = PBXBuildFile; fileRef = D1E271B216B471E80046C00C /* TheoraPixelTransform.h */; };
- D1E271B816B471E80046C00C /* TheoraPixelTransform.h in Headers */ = {isa = PBXBuildFile; fileRef = D1E271B216B471E80046C00C /* TheoraPixelTransform.h */; };
- D1F09EB1169AFEFB00DEEC63 /* TheoraVideoClip_AVFoundation.h in Headers */ = {isa = PBXBuildFile; fileRef = D1CDFF9D1696D0FA00609AB0 /* TheoraVideoClip_AVFoundation.h */; };
-/* End PBXBuildFile section */
-
-/* Begin PBXFileReference section */
- D12CA55517734B4200412E5B /* TheoraVideoClip_FFmpeg.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = TheoraVideoClip_FFmpeg.cpp; path = src/FFmpeg/TheoraVideoClip_FFmpeg.cpp; sourceTree = "<group>"; };
- D12CA55617734B4200412E5B /* TheoraVideoClip_FFmpeg.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TheoraVideoClip_FFmpeg.h; path = src/FFmpeg/TheoraVideoClip_FFmpeg.h; sourceTree = "<group>"; };
- D1358BC218D7777200A36FDC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
- D1358BC318D7777800A36FDC /* iOS.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = iOS.xcconfig; path = xcconfig/iOS.xcconfig; sourceTree = "<group>"; };
- D1358BC418D7777800A36FDC /* Mac.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Mac.xcconfig; path = xcconfig/Mac.xcconfig; sourceTree = "<group>"; };
- D139462B17C0ED450091F4A4 /* yuv_libyuv.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = yuv_libyuv.c; path = src/YUV/libyuv/yuv_libyuv.c; sourceTree = "<group>"; };
- D139462C17C0ED450091F4A4 /* yuv_libyuv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = yuv_libyuv.h; path = src/YUV/libyuv/yuv_libyuv.h; sourceTree = "<group>"; };
- D13946CA17C119B30091F4A4 /* yuv_util.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = yuv_util.c; path = src/YUV/yuv_util.c; sourceTree = "<group>"; };
- D13946CB17C119B30091F4A4 /* yuv_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = yuv_util.h; path = src/YUV/yuv_util.h; sourceTree = "<group>"; };
- D1473F2A150CA69B00B20490 /* theoraplayer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = theoraplayer.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- D159BCAB17C227940030FAB6 /* compare_win.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = compare_win.cc; path = src/YUV/libyuv/src/compare_win.cc; sourceTree = "<group>"; };
- D159BCAC17C227940030FAB6 /* row_win.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = row_win.cc; path = src/YUV/libyuv/src/row_win.cc; sourceTree = "<group>"; };
- D159BCAD17C227940030FAB6 /* row_x86.asm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm.asm; name = row_x86.asm; path = src/YUV/libyuv/src/row_x86.asm; sourceTree = "<group>"; };
- D159BCAE17C227940030FAB6 /* x86inc.asm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm.asm; name = x86inc.asm; path = src/YUV/libyuv/src/x86inc.asm; sourceTree = "<group>"; };
- D167759E155C501D0050EC64 /* TheoraAsync.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TheoraAsync.cpp; path = src/TheoraAsync.cpp; sourceTree = "<group>"; };
- D167759F155C501D0050EC64 /* TheoraAudioInterface.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TheoraAudioInterface.cpp; path = src/TheoraAudioInterface.cpp; sourceTree = "<group>"; };
- D16775A0155C501D0050EC64 /* TheoraDataSource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TheoraDataSource.cpp; path = src/TheoraDataSource.cpp; sourceTree = "<group>"; };
- D16775A1155C501D0050EC64 /* TheoraException.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TheoraException.cpp; path = src/TheoraException.cpp; sourceTree = "<group>"; };
- D16775A2155C501D0050EC64 /* TheoraFrameQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TheoraFrameQueue.cpp; path = src/TheoraFrameQueue.cpp; sourceTree = "<group>"; };
- D16775A3155C501D0050EC64 /* TheoraTimer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TheoraTimer.cpp; path = src/TheoraTimer.cpp; sourceTree = "<group>"; };
- D16775A4155C501D0050EC64 /* TheoraUtil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TheoraUtil.cpp; path = src/TheoraUtil.cpp; sourceTree = "<group>"; };
- D16775A5155C501D0050EC64 /* TheoraVideoClip.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TheoraVideoClip.cpp; path = src/TheoraVideoClip.cpp; sourceTree = "<group>"; };
- D16775A6155C501D0050EC64 /* TheoraVideoFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TheoraVideoFrame.cpp; path = src/TheoraVideoFrame.cpp; sourceTree = "<group>"; };
- D16775A7155C501D0050EC64 /* TheoraVideoManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TheoraVideoManager.cpp; path = src/TheoraVideoManager.cpp; sourceTree = "<group>"; };
- D16775A8155C501D0050EC64 /* TheoraWorkerThread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TheoraWorkerThread.cpp; path = src/TheoraWorkerThread.cpp; sourceTree = "<group>"; };
- D16775C1155C50280050EC64 /* TheoraAsync.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TheoraAsync.h; path = include/theoraplayer/TheoraAsync.h; sourceTree = "<group>"; };
- D16775C2155C50280050EC64 /* TheoraAudioInterface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TheoraAudioInterface.h; path = include/theoraplayer/TheoraAudioInterface.h; sourceTree = "<group>"; };
- D16775C3155C50280050EC64 /* TheoraDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TheoraDataSource.h; path = include/theoraplayer/TheoraDataSource.h; sourceTree = "<group>"; };
- D16775C4155C50280050EC64 /* TheoraException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TheoraException.h; path = include/theoraplayer/TheoraException.h; sourceTree = "<group>"; };
- D16775C5155C50280050EC64 /* TheoraExport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TheoraExport.h; path = include/theoraplayer/TheoraExport.h; sourceTree = "<group>"; };
- D16775C6155C50280050EC64 /* TheoraFrameQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TheoraFrameQueue.h; path = include/theoraplayer/TheoraFrameQueue.h; sourceTree = "<group>"; };
- D16775C7155C50280050EC64 /* TheoraPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TheoraPlayer.h; path = include/theoraplayer/TheoraPlayer.h; sourceTree = "<group>"; };
- D16775C8155C50280050EC64 /* TheoraTimer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TheoraTimer.h; path = include/theoraplayer/TheoraTimer.h; sourceTree = "<group>"; };
- D16775C9155C50280050EC64 /* TheoraUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TheoraUtil.h; path = include/theoraplayer/TheoraUtil.h; sourceTree = "<group>"; };
- D16775CA155C50280050EC64 /* TheoraVideoClip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TheoraVideoClip.h; path = include/theoraplayer/TheoraVideoClip.h; sourceTree = "<group>"; };
- D16775CB155C50280050EC64 /* TheoraVideoFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TheoraVideoFrame.h; path = include/theoraplayer/TheoraVideoFrame.h; sourceTree = "<group>"; };
- D16775CC155C50280050EC64 /* TheoraVideoManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TheoraVideoManager.h; path = include/theoraplayer/TheoraVideoManager.h; sourceTree = "<group>"; };
- D16775CD155C50280050EC64 /* TheoraWorkerThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TheoraWorkerThread.h; path = include/theoraplayer/TheoraWorkerThread.h; sourceTree = "<group>"; };
- D198F97B177A31FC002942E3 /* libtheoraplayer.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libtheoraplayer.a; sourceTree = BUILT_PRODUCTS_DIR; };
- D198F9A7177A31FE002942E3 /* libtheoraplayer_avfoundation.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libtheoraplayer_avfoundation.a; sourceTree = BUILT_PRODUCTS_DIR; };
- D198F9D4177A3200002942E3 /* libtheoraplayer_theora_avfoundation.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libtheoraplayer_theora_avfoundation.a; sourceTree = BUILT_PRODUCTS_DIR; };
- D1BB6FAE150E9E7100EF9400 /* libtheoraplayer.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libtheoraplayer.a; sourceTree = BUILT_PRODUCTS_DIR; };
- D1BCE05718F3F7D800C83470 /* scale_row.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = scale_row.h; path = src/YUV/libyuv/include/libyuv/scale_row.h; sourceTree = "<group>"; };
- D1BCE05818F3F7FE00C83470 /* scale_common.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = scale_common.cc; path = src/YUV/libyuv/src/scale_common.cc; sourceTree = "<group>"; };
- D1BCE05918F3F7FE00C83470 /* scale_posix.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = scale_posix.cc; path = src/YUV/libyuv/src/scale_posix.cc; sourceTree = "<group>"; };
- D1BCE06C18F3F80800C83470 /* scale_win.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = scale_win.cc; path = src/YUV/libyuv/src/scale_win.cc; sourceTree = "<group>"; };
- D1C3D04F17C157CD00CA0FD2 /* compare_common.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = compare_common.cc; path = src/YUV/libyuv/src/compare_common.cc; sourceTree = "<group>"; };
- D1C3D05017C157CD00CA0FD2 /* compare_neon.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = compare_neon.cc; path = src/YUV/libyuv/src/compare_neon.cc; sourceTree = "<group>"; };
- D1C3D05117C157CD00CA0FD2 /* compare_posix.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = compare_posix.cc; path = src/YUV/libyuv/src/compare_posix.cc; sourceTree = "<group>"; };
- D1C3D05317C157CD00CA0FD2 /* compare.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = compare.cc; path = src/YUV/libyuv/src/compare.cc; sourceTree = "<group>"; };
- D1C3D05417C157CD00CA0FD2 /* convert_argb.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = convert_argb.cc; path = src/YUV/libyuv/src/convert_argb.cc; sourceTree = "<group>"; };
- D1C3D05517C157CD00CA0FD2 /* convert_from_argb.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = convert_from_argb.cc; path = src/YUV/libyuv/src/convert_from_argb.cc; sourceTree = "<group>"; };
- D1C3D05617C157CD00CA0FD2 /* convert_from.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = convert_from.cc; path = src/YUV/libyuv/src/convert_from.cc; sourceTree = "<group>"; };
- D1C3D05717C157CD00CA0FD2 /* convert_jpeg.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = convert_jpeg.cc; path = src/YUV/libyuv/src/convert_jpeg.cc; sourceTree = "<group>"; };
- D1C3D05817C157CD00CA0FD2 /* convert_to_argb.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = convert_to_argb.cc; path = src/YUV/libyuv/src/convert_to_argb.cc; sourceTree = "<group>"; };
- D1C3D05917C157CD00CA0FD2 /* convert_to_i420.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = convert_to_i420.cc; path = src/YUV/libyuv/src/convert_to_i420.cc; sourceTree = "<group>"; };
- D1C3D05A17C157CD00CA0FD2 /* convert.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = convert.cc; path = src/YUV/libyuv/src/convert.cc; sourceTree = "<group>"; };
- D1C3D05B17C157CD00CA0FD2 /* cpu_id.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cpu_id.cc; path = src/YUV/libyuv/src/cpu_id.cc; sourceTree = "<group>"; };
- D1C3D05C17C157CD00CA0FD2 /* format_conversion.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = format_conversion.cc; path = src/YUV/libyuv/src/format_conversion.cc; sourceTree = "<group>"; };
- D1C3D05D17C157CD00CA0FD2 /* mjpeg_decoder.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = mjpeg_decoder.cc; path = src/YUV/libyuv/src/mjpeg_decoder.cc; sourceTree = "<group>"; };
- D1C3D05E17C157CD00CA0FD2 /* mjpeg_validate.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = mjpeg_validate.cc; path = src/YUV/libyuv/src/mjpeg_validate.cc; sourceTree = "<group>"; };
- D1C3D05F17C157CD00CA0FD2 /* planar_functions.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = planar_functions.cc; path = src/YUV/libyuv/src/planar_functions.cc; sourceTree = "<group>"; };
- D1C3D06017C157CD00CA0FD2 /* rotate_argb.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = rotate_argb.cc; path = src/YUV/libyuv/src/rotate_argb.cc; sourceTree = "<group>"; };
- D1C3D06117C157CD00CA0FD2 /* rotate_mips.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = rotate_mips.cc; path = src/YUV/libyuv/src/rotate_mips.cc; sourceTree = "<group>"; };
- D1C3D06217C157CD00CA0FD2 /* rotate_neon.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = rotate_neon.cc; path = src/YUV/libyuv/src/rotate_neon.cc; sourceTree = "<group>"; };
- D1C3D06317C157CD00CA0FD2 /* rotate.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = rotate.cc; path = src/YUV/libyuv/src/rotate.cc; sourceTree = "<group>"; };
- D1C3D06417C157CD00CA0FD2 /* row_any.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = row_any.cc; path = src/YUV/libyuv/src/row_any.cc; sourceTree = "<group>"; };
- D1C3D06517C157CD00CA0FD2 /* row_common.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = row_common.cc; path = src/YUV/libyuv/src/row_common.cc; sourceTree = "<group>"; };
- D1C3D06617C157CD00CA0FD2 /* row_mips.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = row_mips.cc; path = src/YUV/libyuv/src/row_mips.cc; sourceTree = "<group>"; };
- D1C3D06717C157CD00CA0FD2 /* row_neon.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = row_neon.cc; path = src/YUV/libyuv/src/row_neon.cc; sourceTree = "<group>"; };
- D1C3D06817C157CD00CA0FD2 /* row_posix.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = row_posix.cc; path = src/YUV/libyuv/src/row_posix.cc; sourceTree = "<group>"; };
- D1C3D06B17C157CD00CA0FD2 /* scale_argb_neon.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = scale_argb_neon.cc; path = src/YUV/libyuv/src/scale_argb_neon.cc; sourceTree = "<group>"; };
- D1C3D06C17C157CD00CA0FD2 /* scale_argb.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = scale_argb.cc; path = src/YUV/libyuv/src/scale_argb.cc; sourceTree = "<group>"; };
- D1C3D06D17C157CD00CA0FD2 /* scale_mips.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = scale_mips.cc; path = src/YUV/libyuv/src/scale_mips.cc; sourceTree = "<group>"; };
- D1C3D06E17C157CD00CA0FD2 /* scale_neon.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = scale_neon.cc; path = src/YUV/libyuv/src/scale_neon.cc; sourceTree = "<group>"; };
- D1C3D06F17C157CD00CA0FD2 /* scale.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = scale.cc; path = src/YUV/libyuv/src/scale.cc; sourceTree = "<group>"; };
- D1C3D07017C157CD00CA0FD2 /* video_common.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = video_common.cc; path = src/YUV/libyuv/src/video_common.cc; sourceTree = "<group>"; };
- D1C3D1CE17C15BB400CA0FD2 /* libyuv.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = libyuv.h; path = src/YUV/libyuv/include/libyuv.h; sourceTree = "<group>"; };
- D1C3D1CF17C15BC100CA0FD2 /* basic_types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = basic_types.h; path = src/YUV/libyuv/include/libyuv/basic_types.h; sourceTree = "<group>"; };
- D1C3D1D017C15BC100CA0FD2 /* compare.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = compare.h; path = src/YUV/libyuv/include/libyuv/compare.h; sourceTree = "<group>"; };
- D1C3D1D117C15BC100CA0FD2 /* convert_argb.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = convert_argb.h; path = src/YUV/libyuv/include/libyuv/convert_argb.h; sourceTree = "<group>"; };
- D1C3D1D217C15BC100CA0FD2 /* convert_from_argb.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = convert_from_argb.h; path = src/YUV/libyuv/include/libyuv/convert_from_argb.h; sourceTree = "<group>"; };
- D1C3D1D317C15BC100CA0FD2 /* convert_from.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = convert_from.h; path = src/YUV/libyuv/include/libyuv/convert_from.h; sourceTree = "<group>"; };
- D1C3D1D417C15BC100CA0FD2 /* convert.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = convert.h; path = src/YUV/libyuv/include/libyuv/convert.h; sourceTree = "<group>"; };
- D1C3D1D517C15BC100CA0FD2 /* cpu_id.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = cpu_id.h; path = src/YUV/libyuv/include/libyuv/cpu_id.h; sourceTree = "<group>"; };
- D1C3D1D617C15BC100CA0FD2 /* format_conversion.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = format_conversion.h; path = src/YUV/libyuv/include/libyuv/format_conversion.h; sourceTree = "<group>"; };
- D1C3D1D717C15BC100CA0FD2 /* mjpeg_decoder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = mjpeg_decoder.h; path = src/YUV/libyuv/include/libyuv/mjpeg_decoder.h; sourceTree = "<group>"; };
- D1C3D1D817C15BC100CA0FD2 /* planar_functions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = planar_functions.h; path = src/YUV/libyuv/include/libyuv/planar_functions.h; sourceTree = "<group>"; };
- D1C3D1D917C15BC100CA0FD2 /* rotate_argb.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = rotate_argb.h; path = src/YUV/libyuv/include/libyuv/rotate_argb.h; sourceTree = "<group>"; };
- D1C3D1DA17C15BC100CA0FD2 /* rotate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = rotate.h; path = src/YUV/libyuv/include/libyuv/rotate.h; sourceTree = "<group>"; };
- D1C3D1DB17C15BC100CA0FD2 /* row.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = row.h; path = src/YUV/libyuv/include/libyuv/row.h; sourceTree = "<group>"; };
- D1C3D1DC17C15BC100CA0FD2 /* scale_argb.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = scale_argb.h; path = src/YUV/libyuv/include/libyuv/scale_argb.h; sourceTree = "<group>"; };
- D1C3D1DD17C15BC100CA0FD2 /* scale.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = scale.h; path = src/YUV/libyuv/include/libyuv/scale.h; sourceTree = "<group>"; };
- D1C3D1DE17C15BC100CA0FD2 /* version.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = version.h; path = src/YUV/libyuv/include/libyuv/version.h; sourceTree = "<group>"; };
- D1C3D1DF17C15BC100CA0FD2 /* video_common.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = video_common.h; path = src/YUV/libyuv/include/libyuv/video_common.h; sourceTree = "<group>"; };
- D1CD00031696FF9400609AB0 /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
- D1CDFF481696C77A00609AB0 /* theoraplayer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = theoraplayer.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- D1CDFF701696C79700609AB0 /* theoraplayer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = theoraplayer.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- D1CDFF941696D0F000609AB0 /* TheoraVideoClip_Theora.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TheoraVideoClip_Theora.cpp; path = src/Theora/TheoraVideoClip_Theora.cpp; sourceTree = "<group>"; };
- D1CDFF951696D0F000609AB0 /* TheoraVideoClip_Theora.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TheoraVideoClip_Theora.h; path = src/Theora/TheoraVideoClip_Theora.h; sourceTree = "<group>"; };
- D1CDFF9C1696D0FA00609AB0 /* TheoraVideoClip_AVFoundation.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = TheoraVideoClip_AVFoundation.mm; path = src/AVFoundation/TheoraVideoClip_AVFoundation.mm; sourceTree = "<group>"; };
- D1CDFF9D1696D0FA00609AB0 /* TheoraVideoClip_AVFoundation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TheoraVideoClip_AVFoundation.h; path = src/AVFoundation/TheoraVideoClip_AVFoundation.h; sourceTree = "<group>"; };
- D1CDFFC41696E1CA00609AB0 /* libtheoraplayer.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libtheoraplayer.a; sourceTree = BUILT_PRODUCTS_DIR; };
- D1CDFFE91696E1D700609AB0 /* libtheoraplayer.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libtheoraplayer.a; sourceTree = BUILT_PRODUCTS_DIR; };
- D1CDFFED1696FB7200609AB0 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
- D1CDFFF01696FB8900609AB0 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; };
- D1CDFFF21696FBA800609AB0 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
- D1CDFFF71696FBF400609AB0 /* Ogg.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Ogg.framework; path = ../__build__/products/Debug/Ogg.framework; sourceTree = "<group>"; };
- D1CDFFF91696FBF700609AB0 /* Vorbis.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Vorbis.framework; path = ../__build__/products/Debug/Vorbis.framework; sourceTree = "<group>"; };
- D1CDFFFB1696FC0100609AB0 /* Theora.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Theora.framework; path = ../__build__/products/Debug/Theora.framework; sourceTree = "<group>"; };
- D1D465D516C2D063007A45AA /* TheoraAudioPacketQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TheoraAudioPacketQueue.h; path = include/theoraplayer/TheoraAudioPacketQueue.h; sourceTree = "<group>"; };
- D1D465D916C2D070007A45AA /* TheoraAudioPacketQueue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TheoraAudioPacketQueue.cpp; path = src/TheoraAudioPacketQueue.cpp; sourceTree = "<group>"; };
- D1E2718A16B46F640046C00C /* yuv420_grey_c.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = yuv420_grey_c.c; path = src/YUV/C/yuv420_grey_c.c; sourceTree = "<group>"; };
- D1E2718C16B46F640046C00C /* yuv420_yuv_c.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = yuv420_yuv_c.c; path = src/YUV/C/yuv420_yuv_c.c; sourceTree = "<group>"; };
- D1E271AB16B470210046C00C /* yuv420_rgb_c.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = yuv420_rgb_c.c; path = src/YUV/C/yuv420_rgb_c.c; sourceTree = "<group>"; };
- D1E271B216B471E80046C00C /* TheoraPixelTransform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TheoraPixelTransform.h; path = include/theoraplayer/TheoraPixelTransform.h; sourceTree = "<group>"; };
- D1F4DA1D18FECACE007C1968 /* cpu-features.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "cpu-features.c"; path = "src/YUV/android/cpu-features.c"; sourceTree = "<group>"; };
- D1F4DA1E18FECACE007C1968 /* cpu-features.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "cpu-features.h"; path = "src/YUV/android/cpu-features.h"; sourceTree = "<group>"; };
-/* End PBXFileReference section */
-
-/* Begin PBXFrameworksBuildPhase section */
- D1473F26150CA69B00B20490 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D1CD00001696FC0B00609AB0 /* Theora.framework in Frameworks */,
- D1CD00011696FC0B00609AB0 /* Vorbis.framework in Frameworks */,
- D1CD00021696FC0B00609AB0 /* Ogg.framework in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D198F963177A31FC002942E3 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D198F98F177A31FE002942E3 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D198F9BC177A3200002942E3 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D1BB6FAB150E9E7100EF9400 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D1CDFF2F1696C77A00609AB0 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D1CDFFF41696FBB200609AB0 /* CoreVideo.framework in Frameworks */,
- D1CDFFF51696FBB200609AB0 /* AVFoundation.framework in Frameworks */,
- D1CDFFF61696FBB200609AB0 /* Foundation.framework in Frameworks */,
- D1CD00051696FF9600609AB0 /* CoreMedia.framework in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D1CDFF571696C79700609AB0 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D1CD00041696FF9400609AB0 /* CoreMedia.framework in Frameworks */,
- D1CDFFF31696FBA800609AB0 /* Foundation.framework in Frameworks */,
- D1CDFFF11696FB8900609AB0 /* CoreVideo.framework in Frameworks */,
- D1CDFFEE1696FB7200609AB0 /* AVFoundation.framework in Frameworks */,
- D1CDFFFD1696FC0800609AB0 /* Theora.framework in Frameworks */,
- D1CDFFFE1696FC0800609AB0 /* Vorbis.framework in Frameworks */,
- D1CDFFFF1696FC0800609AB0 /* Ogg.framework in Frameworks */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D1CDFFAE1696E1CA00609AB0 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D1CDFFD31696E1D700609AB0 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
- D12CA55417734B2400412E5B /* FFmpeg */ = {
- isa = PBXGroup;
- children = (
- D12CA55517734B4200412E5B /* TheoraVideoClip_FFmpeg.cpp */,
- D12CA55617734B4200412E5B /* TheoraVideoClip_FFmpeg.h */,
- );
- name = FFmpeg;
- sourceTree = "<group>";
- };
- D1358BC118D7776700A36FDC /* config */ = {
- isa = PBXGroup;
- children = (
- D1358BC318D7777800A36FDC /* iOS.xcconfig */,
- D1358BC418D7777800A36FDC /* Mac.xcconfig */,
- D1358BC218D7777200A36FDC /* Info.plist */,
- );
- name = config;
- sourceTree = "<group>";
- };
- D139462A17C0ED2F0091F4A4 /* libyuv */ = {
- isa = PBXGroup;
- children = (
- D1C3D04E17C157AC00CA0FD2 /* include */,
- D1C3D04D17C157A800CA0FD2 /* src */,
- D139462B17C0ED450091F4A4 /* yuv_libyuv.c */,
- D139462C17C0ED450091F4A4 /* yuv_libyuv.h */,
- );
- name = libyuv;
- sourceTree = "<group>";
- };
- D1473F1E150CA69B00B20490 = {
- isa = PBXGroup;
- children = (
- D1358BC118D7776700A36FDC /* config */,
- D147401F150CAE9600B20490 /* include */,
- D1473F42150CA6C000B20490 /* src */,
- D1473F2C150CA69B00B20490 /* Frameworks */,
- D1473F2B150CA69B00B20490 /* Products */,
- );
- sourceTree = "<group>";
- };
- D1473F2B150CA69B00B20490 /* Products */ = {
- isa = PBXGroup;
- children = (
- D1473F2A150CA69B00B20490 /* theoraplayer.framework */,
- D1BB6FAE150E9E7100EF9400 /* libtheoraplayer.a */,
- D1CDFF481696C77A00609AB0 /* theoraplayer.framework */,
- D1CDFF701696C79700609AB0 /* theoraplayer.framework */,
- D1CDFFC41696E1CA00609AB0 /* libtheoraplayer.a */,
- D1CDFFE91696E1D700609AB0 /* libtheoraplayer.a */,
- D198F97B177A31FC002942E3 /* libtheoraplayer.a */,
- D198F9A7177A31FE002942E3 /* libtheoraplayer_avfoundation.a */,
- D198F9D4177A3200002942E3 /* libtheoraplayer_theora_avfoundation.a */,
- );
- name = Products;
- sourceTree = "<group>";
- };
- D1473F2C150CA69B00B20490 /* Frameworks */ = {
- isa = PBXGroup;
- children = (
- D1473F82150CA7F300B20490 /* mac */,
- );
- name = Frameworks;
- sourceTree = "<group>";
- };
- D1473F42150CA6C000B20490 /* src */ = {
- isa = PBXGroup;
- children = (
- D1E2718516B46F370046C00C /* YUV */,
- D1CDFF921696CEFA00609AB0 /* Theora */,
- D1CDFF931696CF0000609AB0 /* AVFoundation */,
- D12CA55417734B2400412E5B /* FFmpeg */,
- D16775A5155C501D0050EC64 /* TheoraVideoClip.cpp */,
- D167759E155C501D0050EC64 /* TheoraAsync.cpp */,
- D1D465D916C2D070007A45AA /* TheoraAudioPacketQueue.cpp */,
- D167759F155C501D0050EC64 /* TheoraAudioInterface.cpp */,
- D16775A0155C501D0050EC64 /* TheoraDataSource.cpp */,
- D16775A1155C501D0050EC64 /* TheoraException.cpp */,
- D16775A2155C501D0050EC64 /* TheoraFrameQueue.cpp */,
- D16775A3155C501D0050EC64 /* TheoraTimer.cpp */,
- D16775A4155C501D0050EC64 /* TheoraUtil.cpp */,
- D16775A6155C501D0050EC64 /* TheoraVideoFrame.cpp */,
- D16775A7155C501D0050EC64 /* TheoraVideoManager.cpp */,
- D16775A8155C501D0050EC64 /* TheoraWorkerThread.cpp */,
- );
- name = src;
- sourceTree = "<group>";
- };
- D1473F82150CA7F300B20490 /* mac */ = {
- isa = PBXGroup;
- children = (
- D1CD00031696FF9400609AB0 /* CoreMedia.framework */,
- D1CDFFFB1696FC0100609AB0 /* Theora.framework */,
- D1CDFFF91696FBF700609AB0 /* Vorbis.framework */,
- D1CDFFF71696FBF400609AB0 /* Ogg.framework */,
- D1CDFFF01696FB8900609AB0 /* CoreVideo.framework */,
- D1CDFFED1696FB7200609AB0 /* AVFoundation.framework */,
- D1CDFFF21696FBA800609AB0 /* Foundation.framework */,
- );
- name = mac;
- sourceTree = "<group>";
- };
- D147401F150CAE9600B20490 /* include */ = {
- isa = PBXGroup;
- children = (
- D16775C1155C50280050EC64 /* TheoraAsync.h */,
- D16775C2155C50280050EC64 /* TheoraAudioInterface.h */,
- D16775C3155C50280050EC64 /* TheoraDataSource.h */,
- D16775C4155C50280050EC64 /* TheoraException.h */,
- D16775C5155C50280050EC64 /* TheoraExport.h */,
- D1E271B216B471E80046C00C /* TheoraPixelTransform.h */,
- D16775CB155C50280050EC64 /* TheoraVideoFrame.h */,
- D16775C6155C50280050EC64 /* TheoraFrameQueue.h */,
- D16775C7155C50280050EC64 /* TheoraPlayer.h */,
- D16775C8155C50280050EC64 /* TheoraTimer.h */,
- D16775C9155C50280050EC64 /* TheoraUtil.h */,
- D16775CA155C50280050EC64 /* TheoraVideoClip.h */,
- D16775CC155C50280050EC64 /* TheoraVideoManager.h */,
- D1D465D516C2D063007A45AA /* TheoraAudioPacketQueue.h */,
- D16775CD155C50280050EC64 /* TheoraWorkerThread.h */,
- );
- name = include;
- sourceTree = "<group>";
- };
- D1C3D04D17C157A800CA0FD2 /* src */ = {
- isa = PBXGroup;
- children = (
- D1C3D04F17C157CD00CA0FD2 /* compare_common.cc */,
- D1C3D05017C157CD00CA0FD2 /* compare_neon.cc */,
- D1C3D05117C157CD00CA0FD2 /* compare_posix.cc */,
- D159BCAB17C227940030FAB6 /* compare_win.cc */,
- D1C3D05317C157CD00CA0FD2 /* compare.cc */,
- D1C3D05417C157CD00CA0FD2 /* convert_argb.cc */,
- D1C3D05517C157CD00CA0FD2 /* convert_from_argb.cc */,
- D1C3D05617C157CD00CA0FD2 /* convert_from.cc */,
- D1C3D05717C157CD00CA0FD2 /* convert_jpeg.cc */,
- D1C3D05817C157CD00CA0FD2 /* convert_to_argb.cc */,
- D1C3D05917C157CD00CA0FD2 /* convert_to_i420.cc */,
- D1C3D05A17C157CD00CA0FD2 /* convert.cc */,
- D1C3D05B17C157CD00CA0FD2 /* cpu_id.cc */,
- D1C3D05C17C157CD00CA0FD2 /* format_conversion.cc */,
- D1C3D05D17C157CD00CA0FD2 /* mjpeg_decoder.cc */,
- D1C3D05E17C157CD00CA0FD2 /* mjpeg_validate.cc */,
- D1C3D05F17C157CD00CA0FD2 /* planar_functions.cc */,
- D1C3D06017C157CD00CA0FD2 /* rotate_argb.cc */,
- D1C3D06117C157CD00CA0FD2 /* rotate_mips.cc */,
- D1C3D06217C157CD00CA0FD2 /* rotate_neon.cc */,
- D1C3D06317C157CD00CA0FD2 /* rotate.cc */,
- D1C3D06417C157CD00CA0FD2 /* row_any.cc */,
- D1C3D06517C157CD00CA0FD2 /* row_common.cc */,
- D1C3D06617C157CD00CA0FD2 /* row_mips.cc */,
- D1C3D06717C157CD00CA0FD2 /* row_neon.cc */,
- D1C3D06817C157CD00CA0FD2 /* row_posix.cc */,
- D159BCAC17C227940030FAB6 /* row_win.cc */,
- D1C3D06B17C157CD00CA0FD2 /* scale_argb_neon.cc */,
- D1C3D06C17C157CD00CA0FD2 /* scale_argb.cc */,
- D1C3D06D17C157CD00CA0FD2 /* scale_mips.cc */,
- D1C3D06E17C157CD00CA0FD2 /* scale_neon.cc */,
- D1BCE06C18F3F80800C83470 /* scale_win.cc */,
- D1C3D06F17C157CD00CA0FD2 /* scale.cc */,
- D1BCE05818F3F7FE00C83470 /* scale_common.cc */,
- D1BCE05918F3F7FE00C83470 /* scale_posix.cc */,
- D1C3D07017C157CD00CA0FD2 /* video_common.cc */,
- D159BCAD17C227940030FAB6 /* row_x86.asm */,
- D159BCAE17C227940030FAB6 /* x86inc.asm */,
- );
- name = src;
- sourceTree = "<group>";
- };
- D1C3D04E17C157AC00CA0FD2 /* include */ = {
- isa = PBXGroup;
- children = (
- D1C3D1CD17C15BA900CA0FD2 /* libyuv */,
- D1C3D1CE17C15BB400CA0FD2 /* libyuv.h */,
- );
- name = include;
- sourceTree = "<group>";
- };
- D1C3D1CD17C15BA900CA0FD2 /* libyuv */ = {
- isa = PBXGroup;
- children = (
- D1C3D1CF17C15BC100CA0FD2 /* basic_types.h */,
- D1C3D1D017C15BC100CA0FD2 /* compare.h */,
- D1C3D1D117C15BC100CA0FD2 /* convert_argb.h */,
- D1C3D1D217C15BC100CA0FD2 /* convert_from_argb.h */,
- D1C3D1D317C15BC100CA0FD2 /* convert_from.h */,
- D1C3D1D417C15BC100CA0FD2 /* convert.h */,
- D1C3D1D517C15BC100CA0FD2 /* cpu_id.h */,
- D1C3D1D617C15BC100CA0FD2 /* format_conversion.h */,
- D1C3D1D717C15BC100CA0FD2 /* mjpeg_decoder.h */,
- D1C3D1D817C15BC100CA0FD2 /* planar_functions.h */,
- D1C3D1D917C15BC100CA0FD2 /* rotate_argb.h */,
- D1C3D1DA17C15BC100CA0FD2 /* rotate.h */,
- D1C3D1DB17C15BC100CA0FD2 /* row.h */,
- D1C3D1DC17C15BC100CA0FD2 /* scale_argb.h */,
- D1BCE05718F3F7D800C83470 /* scale_row.h */,
- D1C3D1DD17C15BC100CA0FD2 /* scale.h */,
- D1C3D1DE17C15BC100CA0FD2 /* version.h */,
- D1C3D1DF17C15BC100CA0FD2 /* video_common.h */,
- );
- name = libyuv;
- sourceTree = "<group>";
- };
- D1CDFF921696CEFA00609AB0 /* Theora */ = {
- isa = PBXGroup;
- children = (
- D1CDFF951696D0F000609AB0 /* TheoraVideoClip_Theora.h */,
- D1CDFF941696D0F000609AB0 /* TheoraVideoClip_Theora.cpp */,
- );
- name = Theora;
- sourceTree = "<group>";
- };
- D1CDFF931696CF0000609AB0 /* AVFoundation */ = {
- isa = PBXGroup;
- children = (
- D1CDFF9D1696D0FA00609AB0 /* TheoraVideoClip_AVFoundation.h */,
- D1CDFF9C1696D0FA00609AB0 /* TheoraVideoClip_AVFoundation.mm */,
- );
- name = AVFoundation;
- sourceTree = "<group>";
- };
- D1E2718516B46F370046C00C /* YUV */ = {
- isa = PBXGroup;
- children = (
- D1F4DA1C18FECABC007C1968 /* android */,
- D139462A17C0ED2F0091F4A4 /* libyuv */,
- D1E2718716B46F4F0046C00C /* C */,
- D13946CA17C119B30091F4A4 /* yuv_util.c */,
- D13946CB17C119B30091F4A4 /* yuv_util.h */,
- );
- name = YUV;
- sourceTree = "<group>";
- };
- D1E2718716B46F4F0046C00C /* C */ = {
- isa = PBXGroup;
- children = (
- D1E271AB16B470210046C00C /* yuv420_rgb_c.c */,
- D1E2718C16B46F640046C00C /* yuv420_yuv_c.c */,
- D1E2718A16B46F640046C00C /* yuv420_grey_c.c */,
- );
- name = C;
- sourceTree = "<group>";
- };
- D1F4DA1C18FECABC007C1968 /* android */ = {
- isa = PBXGroup;
- children = (
- D1F4DA1D18FECACE007C1968 /* cpu-features.c */,
- D1F4DA1E18FECACE007C1968 /* cpu-features.h */,
- );
- name = android;
- sourceTree = "<group>";
- };
-/* End PBXGroup section */
-
-/* Begin PBXHeadersBuildPhase section */
- D1473F27150CA69B00B20490 /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D16775CE155C50280050EC64 /* TheoraAsync.h in Headers */,
- D16775D0155C50280050EC64 /* TheoraAudioInterface.h in Headers */,
- D16775D2155C50280050EC64 /* TheoraDataSource.h in Headers */,
- D16775D4155C50280050EC64 /* TheoraException.h in Headers */,
- D16775D6155C50280050EC64 /* TheoraExport.h in Headers */,
- D16775D8155C50280050EC64 /* TheoraFrameQueue.h in Headers */,
- D16775DA155C50280050EC64 /* TheoraPlayer.h in Headers */,
- D16775DC155C50280050EC64 /* TheoraTimer.h in Headers */,
- D16775DE155C50280050EC64 /* TheoraUtil.h in Headers */,
- D16775E0155C50280050EC64 /* TheoraVideoClip.h in Headers */,
- D16775E2155C50280050EC64 /* TheoraVideoFrame.h in Headers */,
- D16775E4155C50280050EC64 /* TheoraVideoManager.h in Headers */,
- D16775E6155C50280050EC64 /* TheoraWorkerThread.h in Headers */,
- D1D465D616C2D063007A45AA /* TheoraAudioPacketQueue.h in Headers */,
- D1E271B316B471E80046C00C /* TheoraPixelTransform.h in Headers */,
- D1CDFF991696D0F000609AB0 /* TheoraVideoClip_Theora.h in Headers */,
- D139463617C0ED450091F4A4 /* yuv_libyuv.h in Headers */,
- D13946D517C119B40091F4A4 /* yuv_util.h in Headers */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D198F964177A31FC002942E3 /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D198F965177A31FC002942E3 /* TheoraAsync.h in Headers */,
- D198F966177A31FC002942E3 /* TheoraAudioInterface.h in Headers */,
- D198F967177A31FC002942E3 /* TheoraDataSource.h in Headers */,
- D198F968177A31FC002942E3 /* TheoraException.h in Headers */,
- D198F969177A31FC002942E3 /* TheoraExport.h in Headers */,
- D198F96A177A31FC002942E3 /* TheoraFrameQueue.h in Headers */,
- D198F96B177A31FC002942E3 /* TheoraPlayer.h in Headers */,
- D198F96C177A31FC002942E3 /* TheoraTimer.h in Headers */,
- D198F96D177A31FC002942E3 /* TheoraUtil.h in Headers */,
- D198F96E177A31FC002942E3 /* TheoraVideoClip.h in Headers */,
- D198F96F177A31FC002942E3 /* TheoraVideoFrame.h in Headers */,
- D198F970177A31FC002942E3 /* TheoraVideoManager.h in Headers */,
- D198F971177A31FC002942E3 /* TheoraWorkerThread.h in Headers */,
- D198F972177A31FC002942E3 /* TheoraVideoClip_Theora.h in Headers */,
- D198F974177A31FC002942E3 /* TheoraPixelTransform.h in Headers */,
- D139463917C0ED450091F4A4 /* yuv_libyuv.h in Headers */,
- D13946D817C119B40091F4A4 /* yuv_util.h in Headers */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D198F990177A31FE002942E3 /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D198F991177A31FE002942E3 /* TheoraAsync.h in Headers */,
- D198F992177A31FE002942E3 /* TheoraAudioInterface.h in Headers */,
- D198F993177A31FE002942E3 /* TheoraDataSource.h in Headers */,
- D198F994177A31FE002942E3 /* TheoraException.h in Headers */,
- D198F995177A31FE002942E3 /* TheoraExport.h in Headers */,
- D198F996177A31FE002942E3 /* TheoraFrameQueue.h in Headers */,
- D198F997177A31FE002942E3 /* TheoraPlayer.h in Headers */,
- D198F998177A31FE002942E3 /* TheoraTimer.h in Headers */,
- D198F999177A31FE002942E3 /* TheoraUtil.h in Headers */,
- D198F99A177A31FE002942E3 /* TheoraVideoClip.h in Headers */,
- D198F99B177A31FE002942E3 /* TheoraVideoFrame.h in Headers */,
- D198F99C177A31FE002942E3 /* TheoraVideoManager.h in Headers */,
- D198F99D177A31FE002942E3 /* TheoraWorkerThread.h in Headers */,
- D198F99E177A31FE002942E3 /* TheoraVideoClip_Theora.h in Headers */,
- D198F9A0177A31FE002942E3 /* TheoraPixelTransform.h in Headers */,
- D139463A17C0ED450091F4A4 /* yuv_libyuv.h in Headers */,
- D13946D917C119B40091F4A4 /* yuv_util.h in Headers */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D198F9BD177A3200002942E3 /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D198F9BE177A3200002942E3 /* TheoraAsync.h in Headers */,
- D198F9BF177A3200002942E3 /* TheoraAudioInterface.h in Headers */,
- D198F9C0177A3200002942E3 /* TheoraDataSource.h in Headers */,
- D198F9C1177A3200002942E3 /* TheoraException.h in Headers */,
- D198F9C2177A3200002942E3 /* TheoraExport.h in Headers */,
- D198F9C3177A3200002942E3 /* TheoraFrameQueue.h in Headers */,
- D198F9C4177A3200002942E3 /* TheoraPlayer.h in Headers */,
- D198F9C5177A3200002942E3 /* TheoraTimer.h in Headers */,
- D198F9C6177A3200002942E3 /* TheoraUtil.h in Headers */,
- D198F9C7177A3200002942E3 /* TheoraVideoClip.h in Headers */,
- D198F9C8177A3200002942E3 /* TheoraVideoFrame.h in Headers */,
- D198F9C9177A3200002942E3 /* TheoraVideoManager.h in Headers */,
- D198F9CA177A3200002942E3 /* TheoraWorkerThread.h in Headers */,
- D198F9CB177A3200002942E3 /* TheoraVideoClip_Theora.h in Headers */,
- D198F9CD177A3200002942E3 /* TheoraPixelTransform.h in Headers */,
- D139463B17C0ED450091F4A4 /* yuv_libyuv.h in Headers */,
- D13946DA17C119B40091F4A4 /* yuv_util.h in Headers */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D1BB6FAC150E9E7100EF9400 /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D16775CF155C50280050EC64 /* TheoraAsync.h in Headers */,
- D16775D1155C50280050EC64 /* TheoraAudioInterface.h in Headers */,
- D16775D3155C50280050EC64 /* TheoraDataSource.h in Headers */,
- D16775D5155C50280050EC64 /* TheoraException.h in Headers */,
- D16775D7155C50280050EC64 /* TheoraExport.h in Headers */,
- D16775D9155C50280050EC64 /* TheoraFrameQueue.h in Headers */,
- D16775DB155C50280050EC64 /* TheoraPlayer.h in Headers */,
- D16775DD155C50280050EC64 /* TheoraTimer.h in Headers */,
- D16775DF155C50280050EC64 /* TheoraUtil.h in Headers */,
- D16775E1155C50280050EC64 /* TheoraVideoClip.h in Headers */,
- D16775E3155C50280050EC64 /* TheoraVideoFrame.h in Headers */,
- D16775E5155C50280050EC64 /* TheoraVideoManager.h in Headers */,
- D16775E7155C50280050EC64 /* TheoraWorkerThread.h in Headers */,
- D1CDFF9B1696D0F000609AB0 /* TheoraVideoClip_Theora.h in Headers */,
- D1E271B616B471E80046C00C /* TheoraPixelTransform.h in Headers */,
- D139463C17C0ED450091F4A4 /* yuv_libyuv.h in Headers */,
- D13946DB17C119B40091F4A4 /* yuv_util.h in Headers */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D1CDFF331696C77A00609AB0 /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D1CDFF341696C77A00609AB0 /* TheoraAsync.h in Headers */,
- D1CDFF351696C77A00609AB0 /* TheoraAudioInterface.h in Headers */,
- D1CDFF361696C77A00609AB0 /* TheoraDataSource.h in Headers */,
- D1CDFF371696C77A00609AB0 /* TheoraException.h in Headers */,
- D1CDFF381696C77A00609AB0 /* TheoraExport.h in Headers */,
- D1CDFF391696C77A00609AB0 /* TheoraFrameQueue.h in Headers */,
- D1CDFF3A1696C77A00609AB0 /* TheoraPlayer.h in Headers */,
- D1CDFF3B1696C77A00609AB0 /* TheoraTimer.h in Headers */,
- D1CDFF3C1696C77A00609AB0 /* TheoraUtil.h in Headers */,
- D1CDFF3D1696C77A00609AB0 /* TheoraVideoClip.h in Headers */,
- D1CDFF3E1696C77A00609AB0 /* TheoraVideoFrame.h in Headers */,
- D1CDFF3F1696C77A00609AB0 /* TheoraVideoManager.h in Headers */,
- D1CDFF401696C77A00609AB0 /* TheoraWorkerThread.h in Headers */,
- D1E271B416B471E80046C00C /* TheoraPixelTransform.h in Headers */,
- D1D465D716C2D063007A45AA /* TheoraAudioPacketQueue.h in Headers */,
- D1CDFF9F1696D0FA00609AB0 /* TheoraVideoClip_AVFoundation.h in Headers */,
- D139463717C0ED450091F4A4 /* yuv_libyuv.h in Headers */,
- D13946D617C119B40091F4A4 /* yuv_util.h in Headers */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D1CDFF5B1696C79700609AB0 /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D1CDFF5C1696C79700609AB0 /* TheoraAsync.h in Headers */,
- D1CDFF5D1696C79700609AB0 /* TheoraAudioInterface.h in Headers */,
- D1CDFF5E1696C79700609AB0 /* TheoraDataSource.h in Headers */,
- D1CDFF5F1696C79700609AB0 /* TheoraException.h in Headers */,
- D1CDFF601696C79700609AB0 /* TheoraExport.h in Headers */,
- D1CDFF611696C79700609AB0 /* TheoraFrameQueue.h in Headers */,
- D1CDFF621696C79700609AB0 /* TheoraPlayer.h in Headers */,
- D1CDFF631696C79700609AB0 /* TheoraTimer.h in Headers */,
- D1CDFF641696C79700609AB0 /* TheoraUtil.h in Headers */,
- D1CDFF651696C79700609AB0 /* TheoraVideoClip.h in Headers */,
- D1CDFF661696C79700609AB0 /* TheoraVideoFrame.h in Headers */,
- D1CDFF671696C79700609AB0 /* TheoraVideoManager.h in Headers */,
- D1CDFF681696C79700609AB0 /* TheoraWorkerThread.h in Headers */,
- D1E271B516B471E80046C00C /* TheoraPixelTransform.h in Headers */,
- D1D465D816C2D063007A45AA /* TheoraAudioPacketQueue.h in Headers */,
- D1CDFF9A1696D0F000609AB0 /* TheoraVideoClip_Theora.h in Headers */,
- D1F09EB1169AFEFB00DEEC63 /* TheoraVideoClip_AVFoundation.h in Headers */,
- D139463817C0ED450091F4A4 /* yuv_libyuv.h in Headers */,
- D13946D717C119B40091F4A4 /* yuv_util.h in Headers */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D1CDFFAF1696E1CA00609AB0 /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D1CDFFB01696E1CA00609AB0 /* TheoraAsync.h in Headers */,
- D1CDFFB11696E1CA00609AB0 /* TheoraAudioInterface.h in Headers */,
- D1CDFFB21696E1CA00609AB0 /* TheoraDataSource.h in Headers */,
- D1CDFFB31696E1CA00609AB0 /* TheoraException.h in Headers */,
- D1CDFFB41696E1CA00609AB0 /* TheoraExport.h in Headers */,
- D1CDFFB51696E1CA00609AB0 /* TheoraFrameQueue.h in Headers */,
- D1CDFFB61696E1CA00609AB0 /* TheoraPlayer.h in Headers */,
- D1CDFFB71696E1CA00609AB0 /* TheoraTimer.h in Headers */,
- D1CDFFB81696E1CA00609AB0 /* TheoraUtil.h in Headers */,
- D1CDFFB91696E1CA00609AB0 /* TheoraVideoClip.h in Headers */,
- D1CDFFBA1696E1CA00609AB0 /* TheoraVideoFrame.h in Headers */,
- D1CDFFBB1696E1CA00609AB0 /* TheoraVideoManager.h in Headers */,
- D1CDFFBC1696E1CA00609AB0 /* TheoraWorkerThread.h in Headers */,
- D1CDFFBD1696E1CA00609AB0 /* TheoraVideoClip_Theora.h in Headers */,
- D1E271B716B471E80046C00C /* TheoraPixelTransform.h in Headers */,
- D139463D17C0ED450091F4A4 /* yuv_libyuv.h in Headers */,
- D13946DC17C119B40091F4A4 /* yuv_util.h in Headers */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D1CDFFD41696E1D700609AB0 /* Headers */ = {
- isa = PBXHeadersBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D1CDFFD51696E1D700609AB0 /* TheoraAsync.h in Headers */,
- D1CDFFD61696E1D700609AB0 /* TheoraAudioInterface.h in Headers */,
- D1CDFFD71696E1D700609AB0 /* TheoraDataSource.h in Headers */,
- D1CDFFD81696E1D700609AB0 /* TheoraException.h in Headers */,
- D1CDFFD91696E1D700609AB0 /* TheoraExport.h in Headers */,
- D1CDFFDA1696E1D700609AB0 /* TheoraFrameQueue.h in Headers */,
- D1CDFFDB1696E1D700609AB0 /* TheoraPlayer.h in Headers */,
- D1CDFFDC1696E1D700609AB0 /* TheoraTimer.h in Headers */,
- D1CDFFDD1696E1D700609AB0 /* TheoraUtil.h in Headers */,
- D1CDFFDE1696E1D700609AB0 /* TheoraVideoClip.h in Headers */,
- D1CDFFDF1696E1D700609AB0 /* TheoraVideoFrame.h in Headers */,
- D1CDFFE01696E1D700609AB0 /* TheoraVideoManager.h in Headers */,
- D1CDFFE11696E1D700609AB0 /* TheoraWorkerThread.h in Headers */,
- D1CDFFE21696E1D700609AB0 /* TheoraVideoClip_Theora.h in Headers */,
- D1E271B816B471E80046C00C /* TheoraPixelTransform.h in Headers */,
- D139463E17C0ED450091F4A4 /* yuv_libyuv.h in Headers */,
- D13946DD17C119B40091F4A4 /* yuv_util.h in Headers */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXHeadersBuildPhase section */
-
-/* Begin PBXNativeTarget section */
- D1473F29150CA69B00B20490 /* theoraplayer (Theora) */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = D1473F3F150CA69B00B20490 /* Build configuration list for PBXNativeTarget "theoraplayer (Theora)" */;
- buildPhases = (
- D1473F25150CA69B00B20490 /* Sources */,
- D1473F26150CA69B00B20490 /* Frameworks */,
- D1473F27150CA69B00B20490 /* Headers */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = "theoraplayer (Theora)";
- productName = theoraplayer;
- productReference = D1473F2A150CA69B00B20490 /* theoraplayer.framework */;
- productType = "com.apple.product-type.framework";
- };
- D198F950177A31FC002942E3 /* theoraplayer (Mac Theora) */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = D198F975177A31FC002942E3 /* Build configuration list for PBXNativeTarget "theoraplayer (Mac Theora)" */;
- buildPhases = (
- D198F951177A31FC002942E3 /* Sources */,
- D198F963177A31FC002942E3 /* Frameworks */,
- D198F964177A31FC002942E3 /* Headers */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = "theoraplayer (Mac Theora)";
- productName = libtheoraplayer;
- productReference = D198F97B177A31FC002942E3 /* libtheoraplayer.a */;
- productType = "com.apple.product-type.library.static";
- };
- D198F97C177A31FE002942E3 /* theoraplayer (Mac AVFoundation) */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = D198F9A1177A31FE002942E3 /* Build configuration list for PBXNativeTarget "theoraplayer (Mac AVFoundation)" */;
- buildPhases = (
- D198F97D177A31FE002942E3 /* Sources */,
- D198F98F177A31FE002942E3 /* Frameworks */,
- D198F990177A31FE002942E3 /* Headers */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = "theoraplayer (Mac AVFoundation)";
- productName = libtheoraplayer;
- productReference = D198F9A7177A31FE002942E3 /* libtheoraplayer_avfoundation.a */;
- productType = "com.apple.product-type.library.static";
- };
- D198F9A8177A3200002942E3 /* theoraplayer (Mac Theora AVFoundation) */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = D198F9CE177A3200002942E3 /* Build configuration list for PBXNativeTarget "theoraplayer (Mac Theora AVFoundation)" */;
- buildPhases = (
- D198F9A9177A3200002942E3 /* Sources */,
- D198F9BC177A3200002942E3 /* Frameworks */,
- D198F9BD177A3200002942E3 /* Headers */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = "theoraplayer (Mac Theora AVFoundation)";
- productName = libtheoraplayer;
- productReference = D198F9D4177A3200002942E3 /* libtheoraplayer_theora_avfoundation.a */;
- productType = "com.apple.product-type.library.static";
- };
- D1BB6FAD150E9E7100EF9400 /* theoraplayer (iOS Theora) */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = D1BB6FBC150E9E7100EF9400 /* Build configuration list for PBXNativeTarget "theoraplayer (iOS Theora)" */;
- buildPhases = (
- D1BB6FAA150E9E7100EF9400 /* Sources */,
- D1BB6FAB150E9E7100EF9400 /* Frameworks */,
- D1BB6FAC150E9E7100EF9400 /* Headers */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = "theoraplayer (iOS Theora)";
- productName = libtheoraplayer;
- productReference = D1BB6FAE150E9E7100EF9400 /* libtheoraplayer.a */;
- productType = "com.apple.product-type.library.static";
- };
- D1CDFF221696C77A00609AB0 /* theoraplayer (AVFoundation) */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = D1CDFF421696C77A00609AB0 /* Build configuration list for PBXNativeTarget "theoraplayer (AVFoundation)" */;
- buildPhases = (
- D1CDFF231696C77A00609AB0 /* Sources */,
- D1CDFF2F1696C77A00609AB0 /* Frameworks */,
- D1CDFF331696C77A00609AB0 /* Headers */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = "theoraplayer (AVFoundation)";
- productName = theoraplayer;
- productReference = D1CDFF481696C77A00609AB0 /* theoraplayer.framework */;
- productType = "com.apple.product-type.framework";
- };
- D1CDFF4A1696C79700609AB0 /* theoraplayer (Theora AVFoundation) */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = D1CDFF6A1696C79700609AB0 /* Build configuration list for PBXNativeTarget "theoraplayer (Theora AVFoundation)" */;
- buildPhases = (
- D1CDFF4B1696C79700609AB0 /* Sources */,
- D1CDFF571696C79700609AB0 /* Frameworks */,
- D1CDFF5B1696C79700609AB0 /* Headers */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = "theoraplayer (Theora AVFoundation)";
- productName = theoraplayer;
- productReference = D1CDFF701696C79700609AB0 /* theoraplayer.framework */;
- productType = "com.apple.product-type.framework";
- };
- D1CDFFA01696E1CA00609AB0 /* theoraplayer (iOS AVFoundation) */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = D1CDFFBE1696E1CA00609AB0 /* Build configuration list for PBXNativeTarget "theoraplayer (iOS AVFoundation)" */;
- buildPhases = (
- D1CDFFA11696E1CA00609AB0 /* Sources */,
- D1CDFFAE1696E1CA00609AB0 /* Frameworks */,
- D1CDFFAF1696E1CA00609AB0 /* Headers */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = "theoraplayer (iOS AVFoundation)";
- productName = libtheoraplayer;
- productReference = D1CDFFC41696E1CA00609AB0 /* libtheoraplayer.a */;
- productType = "com.apple.product-type.library.static";
- };
- D1CDFFC51696E1D700609AB0 /* theoraplayer (iOS Theora AVFoundation) */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = D1CDFFE31696E1D700609AB0 /* Build configuration list for PBXNativeTarget "theoraplayer (iOS Theora AVFoundation)" */;
- buildPhases = (
- D1CDFFC61696E1D700609AB0 /* Sources */,
- D1CDFFD31696E1D700609AB0 /* Frameworks */,
- D1CDFFD41696E1D700609AB0 /* Headers */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = "theoraplayer (iOS Theora AVFoundation)";
- productName = libtheoraplayer;
- productReference = D1CDFFE91696E1D700609AB0 /* libtheoraplayer.a */;
- productType = "com.apple.product-type.library.static";
- };
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
- D1473F20150CA69B00B20490 /* Project object */ = {
- isa = PBXProject;
- attributes = {
- LastUpgradeCheck = 0510;
- };
- buildConfigurationList = D1473F23150CA69B00B20490 /* Build configuration list for PBXProject "theoraplayer" */;
- compatibilityVersion = "Xcode 3.2";
- developmentRegion = English;
- hasScannedForEncodings = 0;
- knownRegions = (
- en,
- );
- mainGroup = D1473F1E150CA69B00B20490;
- productRefGroup = D1473F2B150CA69B00B20490 /* Products */;
- projectDirPath = "";
- projectRoot = "";
- targets = (
- D1473F29150CA69B00B20490 /* theoraplayer (Theora) */,
- D1CDFF221696C77A00609AB0 /* theoraplayer (AVFoundation) */,
- D1CDFF4A1696C79700609AB0 /* theoraplayer (Theora AVFoundation) */,
- D198F950177A31FC002942E3 /* theoraplayer (Mac Theora) */,
- D198F97C177A31FE002942E3 /* theoraplayer (Mac AVFoundation) */,
- D198F9A8177A3200002942E3 /* theoraplayer (Mac Theora AVFoundation) */,
- D1BB6FAD150E9E7100EF9400 /* theoraplayer (iOS Theora) */,
- D1CDFFA01696E1CA00609AB0 /* theoraplayer (iOS AVFoundation) */,
- D1CDFFC51696E1D700609AB0 /* theoraplayer (iOS Theora AVFoundation) */,
- );
- };
-/* End PBXProject section */
-
-/* Begin PBXSourcesBuildPhase section */
- D1473F25150CA69B00B20490 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D16775AB155C501D0050EC64 /* TheoraAsync.cpp in Sources */,
- D16775AD155C501D0050EC64 /* TheoraAudioInterface.cpp in Sources */,
- D16775AF155C501D0050EC64 /* TheoraDataSource.cpp in Sources */,
- D16775B1155C501D0050EC64 /* TheoraException.cpp in Sources */,
- D16775B3155C501D0050EC64 /* TheoraFrameQueue.cpp in Sources */,
- D16775B5155C501D0050EC64 /* TheoraTimer.cpp in Sources */,
- D16775B7155C501D0050EC64 /* TheoraUtil.cpp in Sources */,
- D16775B9155C501D0050EC64 /* TheoraVideoClip.cpp in Sources */,
- D16775BB155C501D0050EC64 /* TheoraVideoFrame.cpp in Sources */,
- D16775BD155C501D0050EC64 /* TheoraVideoManager.cpp in Sources */,
- D16775BF155C501D0050EC64 /* TheoraWorkerThread.cpp in Sources */,
- D1CDFF961696D0F000609AB0 /* TheoraVideoClip_Theora.cpp in Sources */,
- D1E2719916B46F640046C00C /* yuv420_grey_c.c in Sources */,
- D1E271A516B46F640046C00C /* yuv420_yuv_c.c in Sources */,
- D1E271AC16B470210046C00C /* yuv420_rgb_c.c in Sources */,
- D1BCE05A18F3F7FE00C83470 /* scale_common.cc in Sources */,
- D1D465DA16C2D070007A45AA /* TheoraAudioPacketQueue.cpp in Sources */,
- D139462D17C0ED450091F4A4 /* yuv_libyuv.c in Sources */,
- D13946CC17C119B40091F4A4 /* yuv_util.c in Sources */,
- D1C3D07217C157CD00CA0FD2 /* compare_common.cc in Sources */,
- D1C3D08417C157CD00CA0FD2 /* compare_posix.cc in Sources */,
- D1BCE06318F3F7FE00C83470 /* scale_posix.cc in Sources */,
- D1C3D09617C157CD00CA0FD2 /* compare.cc in Sources */,
- D1C3D09F17C157CD00CA0FD2 /* convert_argb.cc in Sources */,
- D1C3D0C317C157CD00CA0FD2 /* convert_to_argb.cc in Sources */,
- D1C3D0CC17C157CD00CA0FD2 /* convert_to_i420.cc in Sources */,
- D1C3D0D517C157CD00CA0FD2 /* convert.cc in Sources */,
- D1C3D0DE17C157CD00CA0FD2 /* cpu_id.cc in Sources */,
- D1C3D0E717C157CD00CA0FD2 /* format_conversion.cc in Sources */,
- D1C3D10217C157CD00CA0FD2 /* planar_functions.cc in Sources */,
- D1C3D12617C157CD00CA0FD2 /* rotate.cc in Sources */,
- D1C3D12F17C157CD00CA0FD2 /* row_any.cc in Sources */,
- D1C3D13817C157CD00CA0FD2 /* row_common.cc in Sources */,
- D1C3D15317C157CD00CA0FD2 /* row_posix.cc in Sources */,
- D1C3D17717C157CD00CA0FD2 /* scale_argb.cc in Sources */,
- D1C3D19B17C157CD00CA0FD2 /* video_common.cc in Sources */,
- D159BCB017C227F30030FAB6 /* convert_from.cc in Sources */,
- D159BCB917C228310030FAB6 /* rotate_argb.cc in Sources */,
- D159BCC217C2286D0030FAB6 /* scale.cc in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D198F951177A31FC002942E3 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D198F952177A31FC002942E3 /* TheoraAsync.cpp in Sources */,
- D198F953177A31FC002942E3 /* TheoraAudioInterface.cpp in Sources */,
- D198F954177A31FC002942E3 /* TheoraDataSource.cpp in Sources */,
- D198F955177A31FC002942E3 /* TheoraException.cpp in Sources */,
- D198F956177A31FC002942E3 /* TheoraFrameQueue.cpp in Sources */,
- D198F957177A31FC002942E3 /* TheoraTimer.cpp in Sources */,
- D198F958177A31FC002942E3 /* TheoraUtil.cpp in Sources */,
- D198F959177A31FC002942E3 /* TheoraVideoClip.cpp in Sources */,
- D198F95A177A31FC002942E3 /* TheoraVideoFrame.cpp in Sources */,
- D198F95B177A31FC002942E3 /* TheoraVideoManager.cpp in Sources */,
- D198F95C177A31FC002942E3 /* TheoraWorkerThread.cpp in Sources */,
- D198F95D177A31FC002942E3 /* TheoraVideoClip_Theora.cpp in Sources */,
- D198F95F177A31FC002942E3 /* yuv420_grey_c.c in Sources */,
- D198F960177A31FC002942E3 /* yuv420_yuv_c.c in Sources */,
- D198F961177A31FC002942E3 /* yuv420_rgb_c.c in Sources */,
- D1BCE05D18F3F7FE00C83470 /* scale_common.cc in Sources */,
- D198F962177A31FC002942E3 /* TheoraAudioPacketQueue.cpp in Sources */,
- D139463017C0ED450091F4A4 /* yuv_libyuv.c in Sources */,
- D13946CF17C119B40091F4A4 /* yuv_util.c in Sources */,
- D1C3D07517C157CD00CA0FD2 /* compare_common.cc in Sources */,
- D1C3D08717C157CD00CA0FD2 /* compare_posix.cc in Sources */,
- D1BCE06618F3F7FE00C83470 /* scale_posix.cc in Sources */,
- D1C3D09917C157CD00CA0FD2 /* compare.cc in Sources */,
- D1C3D0A217C157CD00CA0FD2 /* convert_argb.cc in Sources */,
- D1C3D0C617C157CD00CA0FD2 /* convert_to_argb.cc in Sources */,
- D1C3D0CF17C157CD00CA0FD2 /* convert_to_i420.cc in Sources */,
- D1C3D0D817C157CD00CA0FD2 /* convert.cc in Sources */,
- D1C3D0E117C157CD00CA0FD2 /* cpu_id.cc in Sources */,
- D1C3D0EA17C157CD00CA0FD2 /* format_conversion.cc in Sources */,
- D1C3D10517C157CD00CA0FD2 /* planar_functions.cc in Sources */,
- D1C3D12917C157CD00CA0FD2 /* rotate.cc in Sources */,
- D1C3D13217C157CD00CA0FD2 /* row_any.cc in Sources */,
- D1C3D13B17C157CD00CA0FD2 /* row_common.cc in Sources */,
- D1C3D15617C157CD00CA0FD2 /* row_posix.cc in Sources */,
- D1C3D17A17C157CD00CA0FD2 /* scale_argb.cc in Sources */,
- D1C3D19E17C157CD00CA0FD2 /* video_common.cc in Sources */,
- D159BCB317C227F40030FAB6 /* convert_from.cc in Sources */,
- D159BCBC17C228330030FAB6 /* rotate_argb.cc in Sources */,
- D159BCC517C2286E0030FAB6 /* scale.cc in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D198F97D177A31FE002942E3 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D198F97E177A31FE002942E3 /* TheoraAsync.cpp in Sources */,
- D198F97F177A31FE002942E3 /* TheoraAudioInterface.cpp in Sources */,
- D198F980177A31FE002942E3 /* TheoraDataSource.cpp in Sources */,
- D198F981177A31FE002942E3 /* TheoraException.cpp in Sources */,
- D198F982177A31FE002942E3 /* TheoraFrameQueue.cpp in Sources */,
- D198F983177A31FE002942E3 /* TheoraTimer.cpp in Sources */,
- D198F984177A31FE002942E3 /* TheoraUtil.cpp in Sources */,
- D198F985177A31FE002942E3 /* TheoraVideoClip.cpp in Sources */,
- D198F986177A31FE002942E3 /* TheoraVideoFrame.cpp in Sources */,
- D198F987177A31FE002942E3 /* TheoraVideoManager.cpp in Sources */,
- D198F988177A31FE002942E3 /* TheoraWorkerThread.cpp in Sources */,
- D198F989177A31FE002942E3 /* TheoraVideoClip_AVFoundation.mm in Sources */,
- D198F98B177A31FE002942E3 /* yuv420_grey_c.c in Sources */,
- D198F98C177A31FE002942E3 /* yuv420_yuv_c.c in Sources */,
- D198F98D177A31FE002942E3 /* yuv420_rgb_c.c in Sources */,
- D1BCE05E18F3F7FE00C83470 /* scale_common.cc in Sources */,
- D198F98E177A31FE002942E3 /* TheoraAudioPacketQueue.cpp in Sources */,
- D139463117C0ED450091F4A4 /* yuv_libyuv.c in Sources */,
- D13946D017C119B40091F4A4 /* yuv_util.c in Sources */,
- D1C3D07617C157CD00CA0FD2 /* compare_common.cc in Sources */,
- D1C3D08817C157CD00CA0FD2 /* compare_posix.cc in Sources */,
- D1BCE06718F3F7FE00C83470 /* scale_posix.cc in Sources */,
- D1C3D09A17C157CD00CA0FD2 /* compare.cc in Sources */,
- D1C3D0A317C157CD00CA0FD2 /* convert_argb.cc in Sources */,
- D1C3D0C717C157CD00CA0FD2 /* convert_to_argb.cc in Sources */,
- D1C3D0D017C157CD00CA0FD2 /* convert_to_i420.cc in Sources */,
- D1C3D0D917C157CD00CA0FD2 /* convert.cc in Sources */,
- D1C3D0E217C157CD00CA0FD2 /* cpu_id.cc in Sources */,
- D1C3D0EB17C157CD00CA0FD2 /* format_conversion.cc in Sources */,
- D1C3D10617C157CD00CA0FD2 /* planar_functions.cc in Sources */,
- D1C3D12A17C157CD00CA0FD2 /* rotate.cc in Sources */,
- D1C3D13317C157CD00CA0FD2 /* row_any.cc in Sources */,
- D1C3D13C17C157CD00CA0FD2 /* row_common.cc in Sources */,
- D1C3D15717C157CD00CA0FD2 /* row_posix.cc in Sources */,
- D1C3D17B17C157CD00CA0FD2 /* scale_argb.cc in Sources */,
- D1C3D19F17C157CD00CA0FD2 /* video_common.cc in Sources */,
- D159BCB417C227F50030FAB6 /* convert_from.cc in Sources */,
- D159BCBD17C228330030FAB6 /* rotate_argb.cc in Sources */,
- D159BCC617C2286E0030FAB6 /* scale.cc in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D198F9A9177A3200002942E3 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D198F9AA177A3200002942E3 /* TheoraAsync.cpp in Sources */,
- D198F9AB177A3200002942E3 /* TheoraAudioInterface.cpp in Sources */,
- D198F9AC177A3200002942E3 /* TheoraDataSource.cpp in Sources */,
- D198F9AD177A3200002942E3 /* TheoraException.cpp in Sources */,
- D198F9AE177A3200002942E3 /* TheoraFrameQueue.cpp in Sources */,
- D198F9AF177A3200002942E3 /* TheoraTimer.cpp in Sources */,
- D198F9B0177A3200002942E3 /* TheoraUtil.cpp in Sources */,
- D198F9B1177A3200002942E3 /* TheoraVideoClip.cpp in Sources */,
- D198F9B2177A3200002942E3 /* TheoraVideoFrame.cpp in Sources */,
- D198F9B3177A3200002942E3 /* TheoraVideoManager.cpp in Sources */,
- D198F9B4177A3200002942E3 /* TheoraWorkerThread.cpp in Sources */,
- D198F9B5177A3200002942E3 /* TheoraVideoClip_Theora.cpp in Sources */,
- D1BCE06818F3F7FE00C83470 /* scale_posix.cc in Sources */,
- D198F9B6177A3200002942E3 /* TheoraVideoClip_AVFoundation.mm in Sources */,
- D198F9B8177A3200002942E3 /* yuv420_grey_c.c in Sources */,
- D198F9B9177A3200002942E3 /* yuv420_yuv_c.c in Sources */,
- D198F9BA177A3200002942E3 /* yuv420_rgb_c.c in Sources */,
- D198F9BB177A3200002942E3 /* TheoraAudioPacketQueue.cpp in Sources */,
- D139463217C0ED450091F4A4 /* yuv_libyuv.c in Sources */,
- D13946D117C119B40091F4A4 /* yuv_util.c in Sources */,
- D1C3D07717C157CD00CA0FD2 /* compare_common.cc in Sources */,
- D1C3D08917C157CD00CA0FD2 /* compare_posix.cc in Sources */,
- D1C3D09B17C157CD00CA0FD2 /* compare.cc in Sources */,
- D1C3D0A417C157CD00CA0FD2 /* convert_argb.cc in Sources */,
- D1C3D0C817C157CD00CA0FD2 /* convert_to_argb.cc in Sources */,
- D1C3D0D117C157CD00CA0FD2 /* convert_to_i420.cc in Sources */,
- D1C3D0DA17C157CD00CA0FD2 /* convert.cc in Sources */,
- D1C3D0E317C157CD00CA0FD2 /* cpu_id.cc in Sources */,
- D1C3D0EC17C157CD00CA0FD2 /* format_conversion.cc in Sources */,
- D1C3D10717C157CD00CA0FD2 /* planar_functions.cc in Sources */,
- D1C3D12B17C157CD00CA0FD2 /* rotate.cc in Sources */,
- D1C3D13417C157CD00CA0FD2 /* row_any.cc in Sources */,
- D1C3D13D17C157CD00CA0FD2 /* row_common.cc in Sources */,
- D1C3D15817C157CD00CA0FD2 /* row_posix.cc in Sources */,
- D1C3D17C17C157CD00CA0FD2 /* scale_argb.cc in Sources */,
- D1C3D1A017C157CD00CA0FD2 /* video_common.cc in Sources */,
- D159BCB517C227F50030FAB6 /* convert_from.cc in Sources */,
- D159BCBE17C228340030FAB6 /* rotate_argb.cc in Sources */,
- D1BCE05F18F3F7FE00C83470 /* scale_common.cc in Sources */,
- D159BCC717C2286F0030FAB6 /* scale.cc in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D1BB6FAA150E9E7100EF9400 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D16775AC155C501D0050EC64 /* TheoraAsync.cpp in Sources */,
- D1BCE06018F3F7FE00C83470 /* scale_common.cc in Sources */,
- D16775AE155C501D0050EC64 /* TheoraAudioInterface.cpp in Sources */,
- D16775B0155C501D0050EC64 /* TheoraDataSource.cpp in Sources */,
- D16775B2155C501D0050EC64 /* TheoraException.cpp in Sources */,
- D16775B4155C501D0050EC64 /* TheoraFrameQueue.cpp in Sources */,
- D16775B6155C501D0050EC64 /* TheoraTimer.cpp in Sources */,
- D16775B8155C501D0050EC64 /* TheoraUtil.cpp in Sources */,
- D16775BA155C501D0050EC64 /* TheoraVideoClip.cpp in Sources */,
- D16775BC155C501D0050EC64 /* TheoraVideoFrame.cpp in Sources */,
- D16775BE155C501D0050EC64 /* TheoraVideoManager.cpp in Sources */,
- D16775C0155C501D0050EC64 /* TheoraWorkerThread.cpp in Sources */,
- D1BCE06918F3F7FE00C83470 /* scale_posix.cc in Sources */,
- D1CDFF981696D0F000609AB0 /* TheoraVideoClip_Theora.cpp in Sources */,
- D1E2719C16B46F640046C00C /* yuv420_grey_c.c in Sources */,
- D1E271A816B46F640046C00C /* yuv420_yuv_c.c in Sources */,
- D1E271AF16B470210046C00C /* yuv420_rgb_c.c in Sources */,
- D139463317C0ED450091F4A4 /* yuv_libyuv.c in Sources */,
- D1D465DD16C2D070007A45AA /* TheoraAudioPacketQueue.cpp in Sources */,
- D13946D217C119B40091F4A4 /* yuv_util.c in Sources */,
- D1C3D07817C157CD00CA0FD2 /* compare_common.cc in Sources */,
- D1C3D08117C157CD00CA0FD2 /* compare_neon.cc in Sources */,
- D1C3D09C17C157CD00CA0FD2 /* compare.cc in Sources */,
- D1C3D0A517C157CD00CA0FD2 /* convert_argb.cc in Sources */,
- D1C3D0C917C157CD00CA0FD2 /* convert_to_argb.cc in Sources */,
- D1C3D0D217C157CD00CA0FD2 /* convert_to_i420.cc in Sources */,
- D1C3D0DB17C157CD00CA0FD2 /* convert.cc in Sources */,
- D1C3D0E417C157CD00CA0FD2 /* cpu_id.cc in Sources */,
- D1C3D0ED17C157CD00CA0FD2 /* format_conversion.cc in Sources */,
- D1C3D10817C157CD00CA0FD2 /* planar_functions.cc in Sources */,
- D1C3D12317C157CD00CA0FD2 /* rotate_neon.cc in Sources */,
- D1C3D12C17C157CD00CA0FD2 /* rotate.cc in Sources */,
- D1C3D13517C157CD00CA0FD2 /* row_any.cc in Sources */,
- D1C3D13E17C157CD00CA0FD2 /* row_common.cc in Sources */,
- D1C3D15017C157CD00CA0FD2 /* row_neon.cc in Sources */,
- D1C3D17417C157CD00CA0FD2 /* scale_argb_neon.cc in Sources */,
- D1C3D17D17C157CD00CA0FD2 /* scale_argb.cc in Sources */,
- D1C3D18F17C157CD00CA0FD2 /* scale_neon.cc in Sources */,
- D1C3D1A117C157CD00CA0FD2 /* video_common.cc in Sources */,
- D159BCB617C227F60030FAB6 /* convert_from.cc in Sources */,
- D159BCBF17C228340030FAB6 /* rotate_argb.cc in Sources */,
- D159BCC817C2286F0030FAB6 /* scale.cc in Sources */,
- D15D361017C386A600F40439 /* row_posix.cc in Sources */,
- D15D361317C386B100F40439 /* compare_posix.cc in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D1CDFF231696C77A00609AB0 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D1CDFF241696C77A00609AB0 /* TheoraAsync.cpp in Sources */,
- D1CDFF251696C77A00609AB0 /* TheoraAudioInterface.cpp in Sources */,
- D1CDFF261696C77A00609AB0 /* TheoraDataSource.cpp in Sources */,
- D1CDFF271696C77A00609AB0 /* TheoraException.cpp in Sources */,
- D1CDFF281696C77A00609AB0 /* TheoraFrameQueue.cpp in Sources */,
- D1CDFF291696C77A00609AB0 /* TheoraTimer.cpp in Sources */,
- D1CDFF2A1696C77A00609AB0 /* TheoraUtil.cpp in Sources */,
- D1CDFF2B1696C77A00609AB0 /* TheoraVideoClip.cpp in Sources */,
- D1CDFF2C1696C77A00609AB0 /* TheoraVideoFrame.cpp in Sources */,
- D1CDFF2D1696C77A00609AB0 /* TheoraVideoManager.cpp in Sources */,
- D1CDFF2E1696C77A00609AB0 /* TheoraWorkerThread.cpp in Sources */,
- D1CDFF9E1696D0FA00609AB0 /* TheoraVideoClip_AVFoundation.mm in Sources */,
- D1E2719A16B46F640046C00C /* yuv420_grey_c.c in Sources */,
- D1E271A616B46F640046C00C /* yuv420_yuv_c.c in Sources */,
- D1E271AD16B470210046C00C /* yuv420_rgb_c.c in Sources */,
- D1BCE05B18F3F7FE00C83470 /* scale_common.cc in Sources */,
- D1D465DB16C2D070007A45AA /* TheoraAudioPacketQueue.cpp in Sources */,
- D139462E17C0ED450091F4A4 /* yuv_libyuv.c in Sources */,
- D13946CD17C119B40091F4A4 /* yuv_util.c in Sources */,
- D1C3D07317C157CD00CA0FD2 /* compare_common.cc in Sources */,
- D1C3D08517C157CD00CA0FD2 /* compare_posix.cc in Sources */,
- D1BCE06418F3F7FE00C83470 /* scale_posix.cc in Sources */,
- D1C3D09717C157CD00CA0FD2 /* compare.cc in Sources */,
- D1C3D0A017C157CD00CA0FD2 /* convert_argb.cc in Sources */,
- D1C3D0C417C157CD00CA0FD2 /* convert_to_argb.cc in Sources */,
- D1C3D0CD17C157CD00CA0FD2 /* convert_to_i420.cc in Sources */,
- D1C3D0D617C157CD00CA0FD2 /* convert.cc in Sources */,
- D1C3D0DF17C157CD00CA0FD2 /* cpu_id.cc in Sources */,
- D1C3D0E817C157CD00CA0FD2 /* format_conversion.cc in Sources */,
- D1C3D10317C157CD00CA0FD2 /* planar_functions.cc in Sources */,
- D1C3D12717C157CD00CA0FD2 /* rotate.cc in Sources */,
- D1C3D13017C157CD00CA0FD2 /* row_any.cc in Sources */,
- D1C3D13917C157CD00CA0FD2 /* row_common.cc in Sources */,
- D1C3D15417C157CD00CA0FD2 /* row_posix.cc in Sources */,
- D1C3D17817C157CD00CA0FD2 /* scale_argb.cc in Sources */,
- D1C3D19C17C157CD00CA0FD2 /* video_common.cc in Sources */,
- D159BCB117C227F40030FAB6 /* convert_from.cc in Sources */,
- D159BCBA17C228320030FAB6 /* rotate_argb.cc in Sources */,
- D159BCC317C2286D0030FAB6 /* scale.cc in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D1CDFF4B1696C79700609AB0 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D1CDFF4C1696C79700609AB0 /* TheoraAsync.cpp in Sources */,
- D1CDFF4D1696C79700609AB0 /* TheoraAudioInterface.cpp in Sources */,
- D1CDFF4E1696C79700609AB0 /* TheoraDataSource.cpp in Sources */,
- D1CDFF4F1696C79700609AB0 /* TheoraException.cpp in Sources */,
- D1CDFF501696C79700609AB0 /* TheoraFrameQueue.cpp in Sources */,
- D1CDFF511696C79700609AB0 /* TheoraTimer.cpp in Sources */,
- D1CDFF521696C79700609AB0 /* TheoraUtil.cpp in Sources */,
- D1CDFF531696C79700609AB0 /* TheoraVideoClip.cpp in Sources */,
- D1CDFF541696C79700609AB0 /* TheoraVideoFrame.cpp in Sources */,
- D1CDFF551696C79700609AB0 /* TheoraVideoManager.cpp in Sources */,
- D1CDFF561696C79700609AB0 /* TheoraWorkerThread.cpp in Sources */,
- D1CDFF971696D0F000609AB0 /* TheoraVideoClip_Theora.cpp in Sources */,
- D1BCE06518F3F7FE00C83470 /* scale_posix.cc in Sources */,
- D1CDFFEC1696E24F00609AB0 /* TheoraVideoClip_AVFoundation.mm in Sources */,
- D1E2719B16B46F640046C00C /* yuv420_grey_c.c in Sources */,
- D1E271A716B46F640046C00C /* yuv420_yuv_c.c in Sources */,
- D1E271AE16B470210046C00C /* yuv420_rgb_c.c in Sources */,
- D1D465DC16C2D070007A45AA /* TheoraAudioPacketQueue.cpp in Sources */,
- D139462F17C0ED450091F4A4 /* yuv_libyuv.c in Sources */,
- D13946CE17C119B40091F4A4 /* yuv_util.c in Sources */,
- D1C3D07417C157CD00CA0FD2 /* compare_common.cc in Sources */,
- D1C3D08617C157CD00CA0FD2 /* compare_posix.cc in Sources */,
- D1C3D09817C157CD00CA0FD2 /* compare.cc in Sources */,
- D1C3D0A117C157CD00CA0FD2 /* convert_argb.cc in Sources */,
- D1C3D0C517C157CD00CA0FD2 /* convert_to_argb.cc in Sources */,
- D1C3D0CE17C157CD00CA0FD2 /* convert_to_i420.cc in Sources */,
- D1C3D0D717C157CD00CA0FD2 /* convert.cc in Sources */,
- D1C3D0E017C157CD00CA0FD2 /* cpu_id.cc in Sources */,
- D1C3D0E917C157CD00CA0FD2 /* format_conversion.cc in Sources */,
- D1C3D10417C157CD00CA0FD2 /* planar_functions.cc in Sources */,
- D1C3D12817C157CD00CA0FD2 /* rotate.cc in Sources */,
- D1C3D13117C157CD00CA0FD2 /* row_any.cc in Sources */,
- D1C3D13A17C157CD00CA0FD2 /* row_common.cc in Sources */,
- D1C3D15517C157CD00CA0FD2 /* row_posix.cc in Sources */,
- D1C3D17917C157CD00CA0FD2 /* scale_argb.cc in Sources */,
- D1C3D19D17C157CD00CA0FD2 /* video_common.cc in Sources */,
- D159BCB217C227F40030FAB6 /* convert_from.cc in Sources */,
- D159BCBB17C228320030FAB6 /* rotate_argb.cc in Sources */,
- D1BCE05C18F3F7FE00C83470 /* scale_common.cc in Sources */,
- D159BCC417C2286D0030FAB6 /* scale.cc in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D1CDFFA11696E1CA00609AB0 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D1CDFFA21696E1CA00609AB0 /* TheoraAsync.cpp in Sources */,
- D1BCE06118F3F7FE00C83470 /* scale_common.cc in Sources */,
- D1CDFFA31696E1CA00609AB0 /* TheoraAudioInterface.cpp in Sources */,
- D1CDFFA41696E1CA00609AB0 /* TheoraDataSource.cpp in Sources */,
- D1CDFFA51696E1CA00609AB0 /* TheoraException.cpp in Sources */,
- D1CDFFA61696E1CA00609AB0 /* TheoraFrameQueue.cpp in Sources */,
- D1CDFFA71696E1CA00609AB0 /* TheoraTimer.cpp in Sources */,
- D1CDFFA81696E1CA00609AB0 /* TheoraUtil.cpp in Sources */,
- D1CDFFA91696E1CA00609AB0 /* TheoraVideoClip.cpp in Sources */,
- D1CDFFAA1696E1CA00609AB0 /* TheoraVideoFrame.cpp in Sources */,
- D1CDFFAB1696E1CA00609AB0 /* TheoraVideoManager.cpp in Sources */,
- D1CDFFAC1696E1CA00609AB0 /* TheoraWorkerThread.cpp in Sources */,
- D1BCE06A18F3F7FE00C83470 /* scale_posix.cc in Sources */,
- D1CDFFEA1696E24B00609AB0 /* TheoraVideoClip_AVFoundation.mm in Sources */,
- D1E2719D16B46F640046C00C /* yuv420_grey_c.c in Sources */,
- D1E271A916B46F640046C00C /* yuv420_yuv_c.c in Sources */,
- D1E271B016B470210046C00C /* yuv420_rgb_c.c in Sources */,
- D139463417C0ED450091F4A4 /* yuv_libyuv.c in Sources */,
- D1D465DE16C2D070007A45AA /* TheoraAudioPacketQueue.cpp in Sources */,
- D13946D317C119B40091F4A4 /* yuv_util.c in Sources */,
- D1C3D07917C157CD00CA0FD2 /* compare_common.cc in Sources */,
- D1C3D08217C157CD00CA0FD2 /* compare_neon.cc in Sources */,
- D1C3D09D17C157CD00CA0FD2 /* compare.cc in Sources */,
- D1C3D0A617C157CD00CA0FD2 /* convert_argb.cc in Sources */,
- D1C3D0CA17C157CD00CA0FD2 /* convert_to_argb.cc in Sources */,
- D1C3D0D317C157CD00CA0FD2 /* convert_to_i420.cc in Sources */,
- D1C3D0DC17C157CD00CA0FD2 /* convert.cc in Sources */,
- D1C3D0E517C157CD00CA0FD2 /* cpu_id.cc in Sources */,
- D1C3D0EE17C157CD00CA0FD2 /* format_conversion.cc in Sources */,
- D1C3D10917C157CD00CA0FD2 /* planar_functions.cc in Sources */,
- D1C3D12417C157CD00CA0FD2 /* rotate_neon.cc in Sources */,
- D1C3D12D17C157CD00CA0FD2 /* rotate.cc in Sources */,
- D1C3D13617C157CD00CA0FD2 /* row_any.cc in Sources */,
- D1C3D13F17C157CD00CA0FD2 /* row_common.cc in Sources */,
- D1C3D15117C157CD00CA0FD2 /* row_neon.cc in Sources */,
- D1C3D17517C157CD00CA0FD2 /* scale_argb_neon.cc in Sources */,
- D1C3D17E17C157CD00CA0FD2 /* scale_argb.cc in Sources */,
- D1C3D19017C157CD00CA0FD2 /* scale_neon.cc in Sources */,
- D1C3D1A217C157CD00CA0FD2 /* video_common.cc in Sources */,
- D159BCB717C227F60030FAB6 /* convert_from.cc in Sources */,
- D159BCC017C228340030FAB6 /* rotate_argb.cc in Sources */,
- D159BCC917C2286F0030FAB6 /* scale.cc in Sources */,
- D15D361117C386A600F40439 /* row_posix.cc in Sources */,
- D15D361617C386B400F40439 /* compare_posix.cc in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
- D1CDFFC61696E1D700609AB0 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- D1CDFFC71696E1D700609AB0 /* TheoraAsync.cpp in Sources */,
- D1CDFFC81696E1D700609AB0 /* TheoraAudioInterface.cpp in Sources */,
- D1CDFFC91696E1D700609AB0 /* TheoraDataSource.cpp in Sources */,
- D1CDFFCA1696E1D700609AB0 /* TheoraException.cpp in Sources */,
- D1CDFFCB1696E1D700609AB0 /* TheoraFrameQueue.cpp in Sources */,
- D1CDFFCC1696E1D700609AB0 /* TheoraTimer.cpp in Sources */,
- D1CDFFCD1696E1D700609AB0 /* TheoraUtil.cpp in Sources */,
- D1CDFFCE1696E1D700609AB0 /* TheoraVideoClip.cpp in Sources */,
- D1CDFFCF1696E1D700609AB0 /* TheoraVideoFrame.cpp in Sources */,
- D1CDFFD01696E1D700609AB0 /* TheoraVideoManager.cpp in Sources */,
- D1CDFFD11696E1D700609AB0 /* TheoraWorkerThread.cpp in Sources */,
- D1CDFFD21696E1D700609AB0 /* TheoraVideoClip_Theora.cpp in Sources */,
- D1CDFFEB1696E24C00609AB0 /* TheoraVideoClip_AVFoundation.mm in Sources */,
- D1E2719E16B46F640046C00C /* yuv420_grey_c.c in Sources */,
- D1E271AA16B46F640046C00C /* yuv420_yuv_c.c in Sources */,
- D1E271B116B470210046C00C /* yuv420_rgb_c.c in Sources */,
- D13946C617C110670091F4A4 /* yuv_libyuv.c in Sources */,
- D1D465DF16C2D070007A45AA /* TheoraAudioPacketQueue.cpp in Sources */,
- D13946D417C119B40091F4A4 /* yuv_util.c in Sources */,
- D1C3D07A17C157CD00CA0FD2 /* compare_common.cc in Sources */,
- D1C3D08317C157CD00CA0FD2 /* compare_neon.cc in Sources */,
- D1C3D09E17C157CD00CA0FD2 /* compare.cc in Sources */,
- D1C3D0A717C157CD00CA0FD2 /* convert_argb.cc in Sources */,
- D1C3D0CB17C157CD00CA0FD2 /* convert_to_argb.cc in Sources */,
- D1C3D0D417C157CD00CA0FD2 /* convert_to_i420.cc in Sources */,
- D1C3D0DD17C157CD00CA0FD2 /* convert.cc in Sources */,
- D1C3D0E617C157CD00CA0FD2 /* cpu_id.cc in Sources */,
- D1C3D0EF17C157CD00CA0FD2 /* format_conversion.cc in Sources */,
- D1C3D10A17C157CD00CA0FD2 /* planar_functions.cc in Sources */,
- D1C3D12517C157CD00CA0FD2 /* rotate_neon.cc in Sources */,
- D1C3D12E17C157CD00CA0FD2 /* rotate.cc in Sources */,
- D1C3D13717C157CD00CA0FD2 /* row_any.cc in Sources */,
- D1C3D14017C157CD00CA0FD2 /* row_common.cc in Sources */,
- D1C3D15217C157CD00CA0FD2 /* row_neon.cc in Sources */,
- D1C3D17617C157CD00CA0FD2 /* scale_argb_neon.cc in Sources */,
- D1C3D17F17C157CD00CA0FD2 /* scale_argb.cc in Sources */,
- D1C3D19117C157CD00CA0FD2 /* scale_neon.cc in Sources */,
- D1C3D1A317C157CD00CA0FD2 /* video_common.cc in Sources */,
- D159BCB817C227F70030FAB6 /* convert_from.cc in Sources */,
- D1BCE06218F3F7FE00C83470 /* scale_common.cc in Sources */,
- D159BCC117C228350030FAB6 /* rotate_argb.cc in Sources */,
- D159BCCA17C228700030FAB6 /* scale.cc in Sources */,
- D1BCE06B18F3F7FE00C83470 /* scale_posix.cc in Sources */,
- D15D361217C386A700F40439 /* row_posix.cc in Sources */,
- D15D361517C386B300F40439 /* compare_posix.cc in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXSourcesBuildPhase section */
-
-/* Begin XCBuildConfiguration section */
- D1473F43150CA6CE00B20490 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- COPY_PHASE_STRIP = NO;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_ENABLE_OBJC_EXCEPTIONS = YES;
- GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
- GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
- GCC_OPTIMIZATION_LEVEL = 0;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
- _DEBUG,
- "$(inherited)",
- );
- "GCC_PREPROCESSOR_DEFINITIONS[sdk=iphoneos*]" = (
- "$(LIBYUV_PREPROCESSOR_IOS)",
- "$(inherited)",
- );
- "GCC_PREPROCESSOR_DEFINITIONS[sdk=iphonesimulator*]" = "$(inherited)";
- "GCC_PREPROCESSOR_DEFINITIONS[sdk=macosx*]" = (
- "$(LIBYUV_PREPROCESSOR_MAC)",
- "$(inherited)",
- );
- GCC_SYMBOLS_PRIVATE_EXTERN = YES;
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- HEADER_SEARCH_PATHS = (
- "$(SRCROOT)/../ogg/include",
- "$(SRCROOT)/../vorbis/include",
- "$(SRCROOT)/../xal/lib/ogg/include",
- "$(SRCROOT)/../xal/lib/vorbis/include",
- "$(SRCROOT)/../theora/include",
- "$(SRCROOT)/src/YUV/libyuv/include",
- );
- LIBYUV_PREPROCESSOR_IOS = "LIBYUV_NEON __ARM_NEON__";
- LIBYUV_PREPROCESSOR_MAC = __SSSE3__;
- ONLY_ACTIVE_ARCH = YES;
- SKIP_INSTALL = YES;
- };
- name = Debug;
- };
- D1473F44150CA6CE00B20490 /* Debug */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D1358BC418D7777800A36FDC /* Mac.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = (
- __THEORA,
- _YUV_LIBYUV,
- "$(inherited)",
- );
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_VARIABLE = NO;
- INFOPLIST_FILE = Info.plist;
- LD_DYLIB_INSTALL_NAME = "@executable_path/../Frameworks/$(EXECUTABLE_PATH)";
- PRODUCT_NAME = theoraplayer;
- WRAPPER_EXTENSION = framework;
- };
- name = Debug;
- };
- D1473F45150CA6D600B20490 /* App Store */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- COPY_PHASE_STRIP = YES;
- GCC_ENABLE_OBJC_EXCEPTIONS = YES;
- GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
- GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
- GCC_OPTIMIZATION_LEVEL = 3;
- "GCC_PREPROCESSOR_DEFINITIONS[sdk=iphoneos*]" = (
- "$(LIBYUV_PREPROCESSOR_IOS)",
- "$(inherited)",
- );
- "GCC_PREPROCESSOR_DEFINITIONS[sdk=iphonesimulator*]" = "$(inherited)";
- "GCC_PREPROCESSOR_DEFINITIONS[sdk=macosx*]" = (
- "$(LIBYUV_PREPROCESSOR_MAC)",
- "$(inherited)",
- );
- GCC_SYMBOLS_PRIVATE_EXTERN = YES;
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- HEADER_SEARCH_PATHS = (
- "$(SRCROOT)/../ogg/include",
- "$(SRCROOT)/../vorbis/include",
- "$(SRCROOT)/../xal/lib/ogg/include",
- "$(SRCROOT)/../xal/lib/vorbis/include",
- "$(SRCROOT)/../theora/include",
- "$(SRCROOT)/src/YUV/libyuv/include",
- );
- LIBYUV_PREPROCESSOR_IOS = "LIBYUV_NEON __ARM_NEON__";
- LIBYUV_PREPROCESSOR_MAC = __SSSE3__;
- SKIP_INSTALL = YES;
- };
- name = "App Store";
- };
- D1473F46150CA6D600B20490 /* App Store */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D1358BC418D7777800A36FDC /* Mac.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = (
- __THEORA,
- _YUV_LIBYUV,
- "$(inherited)",
- );
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_VARIABLE = NO;
- INFOPLIST_FILE = Info.plist;
- LD_DYLIB_INSTALL_NAME = "@executable_path/../Frameworks/$(EXECUTABLE_PATH)";
- PRODUCT_NAME = theoraplayer;
- WRAPPER_EXTENSION = framework;
- };
- name = "App Store";
- };
- D1473F47150CA6E200B20490 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- COPY_PHASE_STRIP = YES;
- GCC_ENABLE_OBJC_EXCEPTIONS = YES;
- GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
- GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
- GCC_OPTIMIZATION_LEVEL = 3;
- "GCC_PREPROCESSOR_DEFINITIONS[sdk=iphoneos*]" = (
- "$(LIBYUV_PREPROCESSOR_IOS)",
- "$(inherited)",
- );
- "GCC_PREPROCESSOR_DEFINITIONS[sdk=iphonesimulator*]" = "$(inherited)";
- "GCC_PREPROCESSOR_DEFINITIONS[sdk=macosx*]" = (
- "$(LIBYUV_PREPROCESSOR_MAC)",
- "$(inherited)",
- );
- GCC_SYMBOLS_PRIVATE_EXTERN = YES;
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- HEADER_SEARCH_PATHS = (
- "$(SRCROOT)/../ogg/include",
- "$(SRCROOT)/../vorbis/include",
- "$(SRCROOT)/../xal/lib/ogg/include",
- "$(SRCROOT)/../xal/lib/vorbis/include",
- "$(SRCROOT)/../theora/include",
- "$(SRCROOT)/src/YUV/libyuv/include",
- );
- LIBYUV_PREPROCESSOR_IOS = "LIBYUV_NEON __ARM_NEON__";
- LIBYUV_PREPROCESSOR_MAC = __SSSE3__;
- SKIP_INSTALL = YES;
- };
- name = Release;
- };
- D1473F48150CA6E200B20490 /* Release */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D1358BC418D7777800A36FDC /* Mac.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = (
- __THEORA,
- _YUV_LIBYUV,
- "$(inherited)",
- );
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_VARIABLE = NO;
- INFOPLIST_FILE = Info.plist;
- LD_DYLIB_INSTALL_NAME = "@executable_path/../Frameworks/$(EXECUTABLE_PATH)";
- PRODUCT_NAME = theoraplayer;
- WRAPPER_EXTENSION = framework;
- };
- name = Release;
- };
- D198F977177A31FC002942E3 /* Debug */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D1358BC418D7777800A36FDC /* Mac.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = (
- _MAC,
- __THEORA,
- _YUV_LIBYUV,
- "$(inherited)",
- );
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_VALUE = NO;
- GCC_WARN_UNUSED_VARIABLE = NO;
- PRODUCT_NAME = theoraplayer;
- SKIP_INSTALL = YES;
- };
- name = Debug;
- };
- D198F979177A31FC002942E3 /* Release */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D1358BC418D7777800A36FDC /* Mac.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = (
- _MAC,
- __THEORA,
- _YUV_LIBYUV,
- "$(inherited)",
- );
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_VALUE = NO;
- GCC_WARN_UNUSED_VARIABLE = NO;
- PRODUCT_NAME = theoraplayer;
- SKIP_INSTALL = YES;
- };
- name = Release;
- };
- D198F97A177A31FC002942E3 /* App Store */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D1358BC418D7777800A36FDC /* Mac.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = (
- _MAC,
- __THEORA,
- _YUV_LIBYUV,
- "$(inherited)",
- );
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_VALUE = NO;
- GCC_WARN_UNUSED_VARIABLE = NO;
- PRODUCT_NAME = theoraplayer;
- SKIP_INSTALL = YES;
- };
- name = "App Store";
- };
- D198F9A3177A31FE002942E3 /* Debug */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D1358BC418D7777800A36FDC /* Mac.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = (
- _MAC,
- __AVFOUNDATION,
- _YUV_LIBYUV,
- "$(inherited)",
- );
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_VALUE = NO;
- GCC_WARN_UNUSED_VARIABLE = NO;
- PRODUCT_NAME = theoraplayer_avfoundation;
- SKIP_INSTALL = YES;
- };
- name = Debug;
- };
- D198F9A5177A31FE002942E3 /* Release */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D1358BC418D7777800A36FDC /* Mac.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = (
- _MAC,
- __AVFOUNDATION,
- _YUV_LIBYUV,
- "$(inherited)",
- );
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_VALUE = NO;
- GCC_WARN_UNUSED_VARIABLE = NO;
- PRODUCT_NAME = theoraplayer_avfoundation;
- SKIP_INSTALL = YES;
- };
- name = Release;
- };
- D198F9A6177A31FE002942E3 /* App Store */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D1358BC418D7777800A36FDC /* Mac.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = (
- _MAC,
- __AVFOUNDATION,
- _YUV_LIBYUV,
- "$(inherited)",
- );
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_VALUE = NO;
- GCC_WARN_UNUSED_VARIABLE = NO;
- PRODUCT_NAME = theoraplayer_avfoundation;
- SKIP_INSTALL = YES;
- };
- name = "App Store";
- };
- D198F9D0177A3200002942E3 /* Debug */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D1358BC418D7777800A36FDC /* Mac.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = (
- _MAC,
- __THEORA,
- __AVFOUNDATION,
- YUV_LIBYUV,
- "$(inherited)",
- );
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_VALUE = NO;
- GCC_WARN_UNUSED_VARIABLE = NO;
- PRODUCT_NAME = theoraplayer_theora_avfoundation;
- SKIP_INSTALL = YES;
- };
- name = Debug;
- };
- D198F9D2177A3200002942E3 /* Release */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D1358BC418D7777800A36FDC /* Mac.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = (
- _MAC,
- __THEORA,
- __AVFOUNDATION,
- YUV_LIBYUV,
- "$(inherited)",
- );
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_VALUE = NO;
- GCC_WARN_UNUSED_VARIABLE = NO;
- PRODUCT_NAME = theoraplayer_theora_avfoundation;
- SKIP_INSTALL = YES;
- };
- name = Release;
- };
- D198F9D3177A3200002942E3 /* App Store */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D1358BC418D7777800A36FDC /* Mac.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = (
- _MAC,
- __THEORA,
- __AVFOUNDATION,
- YUV_LIBYUV,
- "$(inherited)",
- );
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_VALUE = NO;
- GCC_WARN_UNUSED_VARIABLE = NO;
- PRODUCT_NAME = theoraplayer_theora_avfoundation;
- SKIP_INSTALL = YES;
- };
- name = "App Store";
- };
- D1BB6FB8150E9E7100EF9400 /* Debug */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D1358BC318D7777800A36FDC /* iOS.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = (
- _IOS,
- __THEORA,
- _YUV_LIBYUV,
- "$(inherited)",
- );
- "GCC_PREPROCESSOR_DEFINITIONS[arch=arm64]" = LIBYUV_DISABLE_NEON;
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_VALUE = NO;
- GCC_WARN_UNUSED_VARIABLE = NO;
- PRODUCT_NAME = theoraplayer;
- SKIP_INSTALL = YES;
- };
- name = Debug;
- };
- D1BB6FBA150E9E7100EF9400 /* Release */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D1358BC318D7777800A36FDC /* iOS.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = (
- _IOS,
- __THEORA,
- _YUV_LIBYUV,
- "$(inherited)",
- );
- "GCC_PREPROCESSOR_DEFINITIONS[arch=arm64]" = LIBYUV_DISABLE_NEON;
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_VALUE = NO;
- GCC_WARN_UNUSED_VARIABLE = NO;
- PRODUCT_NAME = theoraplayer;
- SKIP_INSTALL = YES;
- };
- name = Release;
- };
- D1BB6FBB150E9E7100EF9400 /* App Store */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D1358BC318D7777800A36FDC /* iOS.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = (
- _IOS,
- __THEORA,
- _YUV_LIBYUV,
- "$(inherited)",
- );
- "GCC_PREPROCESSOR_DEFINITIONS[arch=arm64]" = LIBYUV_DISABLE_NEON;
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_VALUE = NO;
- GCC_WARN_UNUSED_VARIABLE = NO;
- PRODUCT_NAME = theoraplayer;
- SKIP_INSTALL = YES;
- };
- name = "App Store";
- };
- D1CDFF441696C77A00609AB0 /* Debug */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D1358BC418D7777800A36FDC /* Mac.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = (
- __AVFOUNDATION,
- _YUV_LIBYUV,
- "$(inherited)",
- );
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_VARIABLE = NO;
- INFOPLIST_FILE = Info.plist;
- LD_DYLIB_INSTALL_NAME = "@executable_path/../Frameworks/$(EXECUTABLE_PATH)";
- PRODUCT_NAME = theoraplayer;
- WRAPPER_EXTENSION = framework;
- };
- name = Debug;
- };
- D1CDFF461696C77A00609AB0 /* Release */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D1358BC418D7777800A36FDC /* Mac.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = (
- __AVFOUNDATION,
- _YUV_LIBYUV,
- "$(inherited)",
- );
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_VARIABLE = NO;
- INFOPLIST_FILE = Info.plist;
- LD_DYLIB_INSTALL_NAME = "@executable_path/../Frameworks/$(EXECUTABLE_PATH)";
- PRODUCT_NAME = theoraplayer;
- WRAPPER_EXTENSION = framework;
- };
- name = Release;
- };
- D1CDFF471696C77A00609AB0 /* App Store */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D1358BC418D7777800A36FDC /* Mac.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = (
- __AVFOUNDATION,
- _YUV_LIBYUV,
- "$(inherited)",
- );
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_VARIABLE = NO;
- INFOPLIST_FILE = Info.plist;
- LD_DYLIB_INSTALL_NAME = "@executable_path/../Frameworks/$(EXECUTABLE_PATH)";
- PRODUCT_NAME = theoraplayer;
- WRAPPER_EXTENSION = framework;
- };
- name = "App Store";
- };
- D1CDFF6C1696C79700609AB0 /* Debug */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D1358BC418D7777800A36FDC /* Mac.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = (
- __THEORA,
- __AVFOUNDATION,
- _YUV_LIBYUV,
- "$(inherited)",
- );
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_VARIABLE = NO;
- INFOPLIST_FILE = Info.plist;
- LD_DYLIB_INSTALL_NAME = "@executable_path/../Frameworks/$(EXECUTABLE_PATH)";
- PRODUCT_NAME = theoraplayer;
- WRAPPER_EXTENSION = framework;
- };
- name = Debug;
- };
- D1CDFF6E1696C79700609AB0 /* Release */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D1358BC418D7777800A36FDC /* Mac.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = (
- __THEORA,
- __AVFOUNDATION,
- _YUV_LIBYUV,
- "$(inherited)",
- );
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_VARIABLE = NO;
- INFOPLIST_FILE = Info.plist;
- LD_DYLIB_INSTALL_NAME = "@executable_path/../Frameworks/$(EXECUTABLE_PATH)";
- PRODUCT_NAME = theoraplayer;
- WRAPPER_EXTENSION = framework;
- };
- name = Release;
- };
- D1CDFF6F1696C79700609AB0 /* App Store */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D1358BC418D7777800A36FDC /* Mac.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = (
- __THEORA,
- __AVFOUNDATION,
- _YUV_LIBYUV,
- "$(inherited)",
- );
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_VARIABLE = NO;
- INFOPLIST_FILE = Info.plist;
- LD_DYLIB_INSTALL_NAME = "@executable_path/../Frameworks/$(EXECUTABLE_PATH)";
- PRODUCT_NAME = theoraplayer;
- WRAPPER_EXTENSION = framework;
- };
- name = "App Store";
- };
- D1CDFFC01696E1CA00609AB0 /* Debug */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D1358BC318D7777800A36FDC /* iOS.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = (
- _IOS,
- __AVFOUNDATION,
- _YUV_LIBYUV,
- "$(inherited)",
- );
- "GCC_PREPROCESSOR_DEFINITIONS[arch=arm64]" = LIBYUV_DISABLE_NEON;
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_VALUE = NO;
- GCC_WARN_UNUSED_VARIABLE = NO;
- PRODUCT_NAME = theoraplayer;
- SKIP_INSTALL = YES;
- };
- name = Debug;
- };
- D1CDFFC21696E1CA00609AB0 /* Release */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D1358BC318D7777800A36FDC /* iOS.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = (
- _IOS,
- __AVFOUNDATION,
- _YUV_LIBYUV,
- "$(inherited)",
- );
- "GCC_PREPROCESSOR_DEFINITIONS[arch=arm64]" = LIBYUV_DISABLE_NEON;
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_VALUE = NO;
- GCC_WARN_UNUSED_VARIABLE = NO;
- PRODUCT_NAME = theoraplayer;
- SKIP_INSTALL = YES;
- };
- name = Release;
- };
- D1CDFFC31696E1CA00609AB0 /* App Store */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D1358BC318D7777800A36FDC /* iOS.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = (
- _IOS,
- __AVFOUNDATION,
- _YUV_LIBYUV,
- "$(inherited)",
- );
- "GCC_PREPROCESSOR_DEFINITIONS[arch=arm64]" = LIBYUV_DISABLE_NEON;
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_VALUE = NO;
- GCC_WARN_UNUSED_VARIABLE = NO;
- PRODUCT_NAME = theoraplayer;
- SKIP_INSTALL = YES;
- };
- name = "App Store";
- };
- D1CDFFE51696E1D700609AB0 /* Debug */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D1358BC318D7777800A36FDC /* iOS.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = (
- _IOS,
- __THEORA,
- __AVFOUNDATION,
- _YUV_LIBYUV,
- "$(inherited)",
- );
- "GCC_PREPROCESSOR_DEFINITIONS[arch=arm64]" = LIBYUV_DISABLE_NEON;
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_VALUE = NO;
- GCC_WARN_UNUSED_VARIABLE = NO;
- PRODUCT_NAME = theoraplayer;
- SKIP_INSTALL = YES;
- };
- name = Debug;
- };
- D1CDFFE71696E1D700609AB0 /* Release */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D1358BC318D7777800A36FDC /* iOS.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = (
- _IOS,
- __THEORA,
- __AVFOUNDATION,
- _YUV_LIBYUV,
- "$(inherited)",
- );
- "GCC_PREPROCESSOR_DEFINITIONS[arch=arm64]" = LIBYUV_DISABLE_NEON;
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_VALUE = NO;
- GCC_WARN_UNUSED_VARIABLE = NO;
- PRODUCT_NAME = theoraplayer;
- SKIP_INSTALL = YES;
- };
- name = Release;
- };
- D1CDFFE81696E1D700609AB0 /* App Store */ = {
- isa = XCBuildConfiguration;
- baseConfigurationReference = D1358BC318D7777800A36FDC /* iOS.xcconfig */;
- buildSettings = {
- GCC_PREPROCESSOR_DEFINITIONS = (
- _IOS,
- __THEORA,
- __AVFOUNDATION,
- _YUV_LIBYUV,
- "$(inherited)",
- );
- "GCC_PREPROCESSOR_DEFINITIONS[arch=arm64]" = LIBYUV_DISABLE_NEON;
- GCC_WARN_UNINITIALIZED_AUTOS = NO;
- GCC_WARN_UNUSED_VALUE = NO;
- GCC_WARN_UNUSED_VARIABLE = NO;
- PRODUCT_NAME = theoraplayer;
- SKIP_INSTALL = YES;
- };
- name = "App Store";
- };
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
- D1473F23150CA69B00B20490 /* Build configuration list for PBXProject "theoraplayer" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- D1473F43150CA6CE00B20490 /* Debug */,
- D1473F47150CA6E200B20490 /* Release */,
- D1473F45150CA6D600B20490 /* App Store */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Debug;
- };
- D1473F3F150CA69B00B20490 /* Build configuration list for PBXNativeTarget "theoraplayer (Theora)" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- D1473F44150CA6CE00B20490 /* Debug */,
- D1473F48150CA6E200B20490 /* Release */,
- D1473F46150CA6D600B20490 /* App Store */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Debug;
- };
- D198F975177A31FC002942E3 /* Build configuration list for PBXNativeTarget "theoraplayer (Mac Theora)" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- D198F977177A31FC002942E3 /* Debug */,
- D198F979177A31FC002942E3 /* Release */,
- D198F97A177A31FC002942E3 /* App Store */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Debug;
- };
- D198F9A1177A31FE002942E3 /* Build configuration list for PBXNativeTarget "theoraplayer (Mac AVFoundation)" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- D198F9A3177A31FE002942E3 /* Debug */,
- D198F9A5177A31FE002942E3 /* Release */,
- D198F9A6177A31FE002942E3 /* App Store */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Debug;
- };
- D198F9CE177A3200002942E3 /* Build configuration list for PBXNativeTarget "theoraplayer (Mac Theora AVFoundation)" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- D198F9D0177A3200002942E3 /* Debug */,
- D198F9D2177A3200002942E3 /* Release */,
- D198F9D3177A3200002942E3 /* App Store */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Debug;
- };
- D1BB6FBC150E9E7100EF9400 /* Build configuration list for PBXNativeTarget "theoraplayer (iOS Theora)" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- D1BB6FB8150E9E7100EF9400 /* Debug */,
- D1BB6FBA150E9E7100EF9400 /* Release */,
- D1BB6FBB150E9E7100EF9400 /* App Store */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Debug;
- };
- D1CDFF421696C77A00609AB0 /* Build configuration list for PBXNativeTarget "theoraplayer (AVFoundation)" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- D1CDFF441696C77A00609AB0 /* Debug */,
- D1CDFF461696C77A00609AB0 /* Release */,
- D1CDFF471696C77A00609AB0 /* App Store */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Debug;
- };
- D1CDFF6A1696C79700609AB0 /* Build configuration list for PBXNativeTarget "theoraplayer (Theora AVFoundation)" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- D1CDFF6C1696C79700609AB0 /* Debug */,
- D1CDFF6E1696C79700609AB0 /* Release */,
- D1CDFF6F1696C79700609AB0 /* App Store */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Debug;
- };
- D1CDFFBE1696E1CA00609AB0 /* Build configuration list for PBXNativeTarget "theoraplayer (iOS AVFoundation)" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- D1CDFFC01696E1CA00609AB0 /* Debug */,
- D1CDFFC21696E1CA00609AB0 /* Release */,
- D1CDFFC31696E1CA00609AB0 /* App Store */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Debug;
- };
- D1CDFFE31696E1D700609AB0 /* Build configuration list for PBXNativeTarget "theoraplayer (iOS Theora AVFoundation)" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- D1CDFFE51696E1D700609AB0 /* Debug */,
- D1CDFFE71696E1D700609AB0 /* Release */,
- D1CDFFE81696E1D700609AB0 /* App Store */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Debug;
- };
-/* End XCConfigurationList section */
- };
- rootObject = D1473F20150CA69B00B20490 /* Project object */;
-}
diff --git a/drivers/theoraplayer/video_stream_theoraplayer.cpp b/drivers/theoraplayer/video_stream_theoraplayer.cpp
deleted file mode 100644
index ef1f5651ab..0000000000
--- a/drivers/theoraplayer/video_stream_theoraplayer.cpp
+++ /dev/null
@@ -1,554 +0,0 @@
-/*************************************************************************/
-/* video_stream.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* http://www.godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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. */
-/*************************************************************************/
-#include "video_stream_theoraplayer.h"
-
-#include "core/os/file_access.h"
-
-#include "include/theoraplayer/TheoraPlayer.h"
-#include "include/theoraplayer/TheoraTimer.h"
-#include "include/theoraplayer/TheoraAudioInterface.h"
-#include "include/theoraplayer/TheoraDataSource.h"
-#include "include/theoraplayer/TheoraException.h"
-
-#include "core/ring_buffer.h"
-#include "core/os/thread_safe.h"
-
-#include "core/globals.h"
-
-static TheoraVideoManager* mgr = NULL;
-
-class TPDataFA : public TheoraDataSource {
-
- FileAccess* fa;
- String data_name;
-
-public:
-
- int read(void* output,int nBytes) {
-
- if (!fa)
- return -1;
-
- return fa->get_buffer((uint8_t*)output, nBytes);
- };
-
- //! returns a string representation of the DataSource, eg 'File: source.ogg'
- virtual std::string repr() {
- return data_name.utf8().get_data();
- };
-
- //! position the source pointer to byte_index from the start of the source
- virtual void seek(unsigned long byte_index) {
-
- if (!fa)
- return;
-
- fa->seek(byte_index);
- };
-
-
- //! return the size of the stream in bytes
- virtual unsigned long size() {
-
- if (!fa)
- return 0;
-
- return fa->get_len();
- };
-
- //! return the current position of the source pointer
- virtual unsigned long tell() {
-
- if (!fa)
- return 0;
-
- return fa->get_pos();
- };
-
- TPDataFA(const String& p_path) {
-
- fa = FileAccess::open(p_path, FileAccess::READ);
- data_name = "File: " + p_path;
- };
-
- TPDataFA(FileAccess* p_fa, const String& p_path) {
-
- fa = p_fa;
- data_name = "File: " + p_path;
- };
-
- ~TPDataFA() {
-
- if (fa)
- memdelete(fa);
- };
-};
-
-class AudioStreamInput : public AudioStreamResampled {
-
- _THREAD_SAFE_CLASS_;
-
- int channels;
- int freq;
-
- RID stream_rid;
- mutable RingBuffer<float> rb;
- int rb_power;
- int total_wrote;
- bool playing;
- bool paused;
-
-public:
-
- virtual void play() {
-
- _THREAD_SAFE_METHOD_
- _setup(channels, freq, 256);
- stream_rid=AudioServer::get_singleton()->audio_stream_create(get_audio_stream());
- AudioServer::get_singleton()->stream_set_active(stream_rid,true);
- AudioServer::get_singleton()->stream_set_volume_scale(stream_rid,1);
- playing = true;
- paused = false;
- };
- virtual void stop() {
-
- _THREAD_SAFE_METHOD_
-
- AudioServer::get_singleton()->stream_set_active(stream_rid,false);
- //_clear_stream();
- playing=false;
- _clear();
- };
-
- virtual bool is_playing() const { return true; };
-
- virtual void set_paused(bool p_paused) { paused = p_paused; };
- virtual bool is_paused(bool p_paused) const { return paused; };
-
- virtual void set_loop(bool p_enable) {};
- virtual bool has_loop() const { return false; };
-
- virtual float get_length() const { return 0; };
-
- virtual String get_stream_name() const { return "Theora Audio Stream"; };
-
- virtual int get_loop_count() const { return 1; };
-
- virtual float get_pos() const { return 0; };
- virtual void seek_pos(float p_time) {};
-
- virtual UpdateMode get_update_mode() const { return UPDATE_THREAD; };
-
- virtual bool _can_mix() const { return true; };
-
- void input(float* p_data, int p_samples) {
-
-
- _THREAD_SAFE_METHOD_;
- //printf("input %i samples from %p\n", p_samples, p_data);
- if (rb.space_left() < p_samples) {
- rb_power += 1;
- rb.resize(rb_power);
- }
- rb.write(p_data, p_samples);
-
- update(); //update too here for less latency
- };
-
- void update() {
-
- _THREAD_SAFE_METHOD_;
- int todo = get_todo();
- int16_t* buffer = get_write_buffer();
- int frames = rb.data_left()/channels;
- const int to_write = MIN(todo, frames);
-
- for (int i=0; i<to_write*channels; i++) {
-
- int v = rb.read() * 32767;
- int16_t sample = CLAMP(v,-32768,32767);
- buffer[i] = sample;
- };
- write(to_write);
- total_wrote += to_write;
- };
-
- int get_pending() const {
- return rb.data_left();
- };
-
- int get_total_wrote() {
-
- return total_wrote - (get_total() - get_todo());
- };
-
- AudioStreamInput(int p_channels, int p_freq) {
-
- playing = false;
- paused = true;
- channels = p_channels;
- freq = p_freq;
- total_wrote = 0;
- rb_power = 22;
- rb.resize(rb_power);
- };
-
- ~AudioStreamInput() {
-
- stop();
- };
-};
-
-class TPAudioGodot : public TheoraAudioInterface, TheoraTimer {
-
- Ref<AudioStreamInput> stream;
- int sample_count;
- int channels;
- int freq;
-
-public:
-
- void insertData(float* data, int nSamples) {
-
- stream->input(data, nSamples);
- };
-
- TPAudioGodot(TheoraVideoClip* owner, int nChannels, int p_freq)
- : TheoraAudioInterface(owner, nChannels, p_freq), TheoraTimer() {
-
- printf("***************** audio interface constructor freq %i\n", p_freq);
- channels = nChannels;
- freq = p_freq;
- stream = Ref<AudioStreamInput>(memnew(AudioStreamInput(nChannels, p_freq)));
- stream->play();
- sample_count = 0;
- owner->setTimer(this);
- };
-
- void stop() {
-
- stream->stop();
- };
-
- void update(float time_increase)
- {
- float prev_time = mTime;
- //mTime = (float)(stream->get_total_wrote()) / freq;
- //mTime = MAX(0,mTime-AudioServer::get_singleton()->get_output_delay());
- //mTime = (float)sample_count / channels / freq;
- mTime += time_increase;
- if (mTime - prev_time > .02) printf("time increase %f secs\n", mTime - prev_time);
- //float duration=mClip->getDuration();
- //if (mTime > duration) mTime=duration;
- //printf("time at timer is %f, %f, samples %i\n", mTime, time_increase, sample_count);
- }
-};
-
-class TPAudioGodotFactory : public TheoraAudioInterfaceFactory {
-
-public:
- TheoraAudioInterface* createInstance(TheoraVideoClip* owner, int nChannels, int freq) {
-
- printf("************** creating audio output\n");
- TheoraAudioInterface* ta = new TPAudioGodot(owner, nChannels, freq);
- return ta;
- };
-};
-
-static TPAudioGodotFactory* audio_factory = NULL;
-
-void VideoStreamTheoraplayer::stop() {
-
- playing = false;
- if (clip) {
- clip->stop();
- clip->seek(0);
- };
- started = true;
-};
-
-void VideoStreamTheoraplayer::play() {
- if (clip)
- playing = true;
-};
-
-bool VideoStreamTheoraplayer::is_playing() const {
-
- return playing;
-};
-
-void VideoStreamTheoraplayer::set_paused(bool p_paused) {
-
- paused = p_paused;
- if (paused) {
- clip->pause();
- } else {
- if (clip && playing && !started)
- clip->play();
- }
-};
-
-bool VideoStreamTheoraplayer::is_paused(bool p_paused) const {
-
- return !playing;
-};
-
-void VideoStreamTheoraplayer::set_loop(bool p_enable) {
-
- loop = p_enable;
-};
-
-bool VideoStreamTheoraplayer::has_loop() const {
-
- return loop;
-};
-
-float VideoStreamTheoraplayer::get_length() const {
-
- if (!clip)
- return 0;
-
- return clip->getDuration();
-};
-
-
-float VideoStreamTheoraplayer::get_pos() const {
-
- if (!clip)
- return 0;
-
- return clip->getTimer()->getTime();
-};
-
-void VideoStreamTheoraplayer::seek_pos(float p_time) {
-
- if (!clip)
- return;
-
- clip->seek(p_time);
-};
-
-int VideoStreamTheoraplayer::get_pending_frame_count() const {
-
- if (!clip)
- return 0;
-
- TheoraVideoFrame* f = clip->getNextFrame();
- return f ? 1 : 0;
-};
-
-
-void VideoStreamTheoraplayer::pop_frame(Ref<ImageTexture> p_tex) {
-
- if (!clip)
- return;
-
- TheoraVideoFrame* f = clip->getNextFrame();
- if (!f) {
- return;
- };
-
-#ifdef GLES2_ENABLED
-// RasterizerGLES2* r = RasterizerGLES2::get_singleton();
-// r->_texture_set_data(p_tex, f->mBpp == 3 ? Image::Format_RGB : Image::Format_RGBA, f->mBpp, w, h, f->getBuffer());
-
-#endif
-
- float w=clip->getWidth(),h=clip->getHeight();
- int imgsize = w * h * f->mBpp;
-
- int size = f->getStride() * f->getHeight() * f->mBpp;
- data.resize(imgsize);
- {
- DVector<uint8_t>::Write wr = data.write();
- uint8_t* ptr = wr.ptr();
- copymem(ptr, f->getBuffer(), imgsize);
- }
- /*
- for (int i=0; i<h; i++) {
- int dstofs = i * w * f->mBpp;
- int srcofs = i * f->getStride() * f->mBpp;
- copymem(ptr + dstofs, f->getBuffer() + dstofs, w * f->mBpp);
- };
- */
- Image frame = Image();
- frame.create(w, h, 0, f->mBpp == 3 ? Image::FORMAT_RGB : Image::FORMAT_RGBA, data);
-
- clip->popFrame();
-
- if (p_tex->get_width() == 0) {
- p_tex->create(frame.get_width(),frame.get_height(),frame.get_format(),Texture::FLAG_VIDEO_SURFACE|Texture::FLAG_FILTER);
- p_tex->set_data(frame);
- } else {
-
- p_tex->set_data(frame);
- };
-};
-
-/*
-Image VideoStreamTheoraplayer::pop_frame() {
-
- Image ret = frame;
- frame = Image();
- return ret;
-};
-*/
-
-Image VideoStreamTheoraplayer::peek_frame() const {
-
- return Image();
-};
-
-void VideoStreamTheoraplayer::update(float p_time) {
-
- if (!mgr)
- return;
-
- if (!clip)
- return;
-
- if (!playing || paused)
- return;
-
- //printf("video update!\n");
- if (started) {
- if (clip->getNumReadyFrames() < 2) {
- printf("frames not ready, returning!\n");
- return;
- };
- started = false;
- //printf("playing clip!\n");
- clip->play();
- } else if (clip->isDone()) {
- playing = false;
- };
-
- mgr->update(p_time);
-};
-
-
-void VideoStreamTheoraplayer::set_audio_track(int p_idx) {
- audio_track=p_idx;
- if (clip)
- clip->set_audio_track(audio_track);
-}
-
-void VideoStreamTheoraplayer::set_file(const String& p_file) {
-
- FileAccess* f = FileAccess::open(p_file, FileAccess::READ);
- if (!f || !f->is_open())
- return;
-
- if (!audio_factory) {
- audio_factory = memnew(TPAudioGodotFactory);
- };
-
- if (mgr == NULL) {
- mgr = memnew(TheoraVideoManager);
- mgr->setAudioInterfaceFactory(audio_factory);
- };
-
- int track = GLOBAL_DEF("theora/audio_track", 0); // hack
-
- if (p_file.find(".mp4") != -1) {
-
- std::string file = p_file.replace("res://", "").utf8().get_data();
- clip = mgr->createVideoClip(file, TH_RGBX, 2, false, track);
- //clip->set_audio_track(audio_track);
- memdelete(f);
-
- } else {
-
- TheoraDataSource* ds = memnew(TPDataFA(f, p_file));
-
- try {
- clip = mgr->createVideoClip(ds);
- clip->set_audio_track(audio_track);
- } catch (_TheoraGenericException e) {
- printf("exception ocurred! %s\n", e.repr().c_str());
- clip = NULL;
- };
- };
-
- clip->pause();
- started = true;
-};
-
-VideoStreamTheoraplayer::~VideoStreamTheoraplayer() {
-
- stop();
- //if (mgr) { // this should be a singleton or static or something
- // memdelete(mgr);
- //};
- //mgr = NULL;
- if (clip) {
- mgr->destroyVideoClip(clip);
- clip = NULL;
- };
-};
-
-VideoStreamTheoraplayer::VideoStreamTheoraplayer() {
-
- //mgr = NULL;
- clip = NULL;
- started = false;
- playing = false;
- paused = false;
- loop = false;
- audio_track=0;
-};
-
-
-RES ResourceFormatLoaderVideoStreamTheoraplayer::load(const String &p_path,const String& p_original_path) {
-
- VideoStreamTheoraplayer *stream = memnew(VideoStreamTheoraplayer);
- stream->set_file(p_path);
- return Ref<VideoStreamTheoraplayer>(stream);
-}
-
-void ResourceFormatLoaderVideoStreamTheoraplayer::get_recognized_extensions(List<String> *p_extensions) const {
-
- p_extensions->push_back("ogm");
- p_extensions->push_back("ogv");
- p_extensions->push_back("mp4");
-}
-bool ResourceFormatLoaderVideoStreamTheoraplayer::handles_type(const String& p_type) const {
- return p_type=="VideoStream" || p_type == "VideoStreamTheoraplayer";
-}
-
-String ResourceFormatLoaderVideoStreamTheoraplayer::get_resource_type(const String &p_path) const {
-
- String exl=p_path.extension().to_lower();
- if (exl=="ogm" || exl=="ogv" || exl=="mp4")
- return "VideoStream";
- return "";
-}
-
-
-
diff --git a/drivers/theoraplayer/video_stream_theoraplayer.h b/drivers/theoraplayer/video_stream_theoraplayer.h
deleted file mode 100644
index d43c12609f..0000000000
--- a/drivers/theoraplayer/video_stream_theoraplayer.h
+++ /dev/null
@@ -1,66 +0,0 @@
-#ifndef VIDEO_STREAM_THEORAPLAYER_H
-#define VIDEO_STREAM_THEORAPLAYER_H
-
-#include "scene/resources/video_stream.h"
-#include "io/resource_loader.h"
-#include "scene/resources/texture.h"
-
-class TheoraVideoManager;
-class TheoraVideoClip;
-
-class VideoStreamTheoraplayer : public VideoStream {
-
- OBJ_TYPE(VideoStreamTheoraplayer,VideoStream);
-
- mutable DVector<uint8_t> data;
- TheoraVideoClip* clip;
- bool started;
- bool playing;
- bool loop;
- bool paused;
-
- int audio_track;
-
-public:
-
- virtual void stop();
- virtual void play();
-
- virtual bool is_playing() const;
-
- virtual void set_paused(bool p_paused);
- virtual bool is_paused(bool p_paused) const;
-
- virtual void set_loop(bool p_enable);
- virtual bool has_loop() const;
-
- virtual float get_pos() const;
- virtual void seek_pos(float p_time);
-
- virtual float get_length() const;
-
- virtual int get_pending_frame_count() const;
- virtual void pop_frame(Ref<ImageTexture> p_tex);
- virtual Image peek_frame() const;
-
- void update(float p_time);
-
- void set_file(const String& p_file);
- void set_audio_track(int p_idx);
-
- ~VideoStreamTheoraplayer();
- VideoStreamTheoraplayer();
-};
-
-class ResourceFormatLoaderVideoStreamTheoraplayer : public ResourceFormatLoader {
-public:
- virtual RES load(const String &p_path,const String& p_original_path="");
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
- virtual bool handles_type(const String& p_type) const;
- virtual String get_resource_type(const String &p_path) const;
-
-};
-
-
-#endif
-
diff --git a/drivers/trex/SCsub b/drivers/trex/SCsub
deleted file mode 100644
index 877be8e3d9..0000000000
--- a/drivers/trex/SCsub
+++ /dev/null
@@ -1,10 +0,0 @@
-
-Import('env')
-
-sources = [
-
- 'trex.c',
- 'regex.cpp',
-]
-env.add_source_files(env.drivers_sources, sources)
-
diff --git a/drivers/trex/TRexpp.h b/drivers/trex/TRexpp.h
deleted file mode 100644
index 8391e47414..0000000000
--- a/drivers/trex/TRexpp.h
+++ /dev/null
@@ -1,75 +0,0 @@
-#ifndef _TREXPP_H_
-#define _TREXPP_H_
-/***************************************************************
- T-Rex a tiny regular expression library
-
- Copyright (C) 2003-2004 Alberto Demichelis
-
- This software is provided 'as-is', without any express
- or implied warranty. In no event will the authors be held
- liable for any damages arising from the use of this software.
-
- Permission is granted to anyone to use this software for
- any purpose, including commercial applications, and to alter
- it and redistribute it freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented;
- you must not claim that you wrote the original software.
- If you use this software in a product, an acknowledgment
- in the product documentation would be appreciated but
- is not required.
-
- 2. Altered source versions must be plainly marked as such,
- and must not be misrepresented as being the original software.
-
- 3. This notice may not be removed or altered from any
- source distribution.
-
-****************************************************************/
-
-extern "C" {
-#include "trex.h"
-}
-
-struct TRexParseException{TRexParseException(const TRexChar *c):desc(c){}const TRexChar *desc;};
-
-class TRexpp {
-public:
- TRexpp() { _exp = (TRex *)0; }
- ~TRexpp() { CleanUp(); }
- // compiles a regular expression
- void Compile(const TRexChar *pattern) {
- const TRexChar *error;
- CleanUp();
- if(!(_exp = trex_compile(pattern,&error)))
- throw TRexParseException(error);
- }
- // return true if the given text match the expression
- bool Match(const TRexChar* text) {
- return _exp?(trex_match(_exp,text) != 0):false;
- }
- // Searches for the first match of the expression in a zero terminated string
- bool Search(const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end) {
- return _exp?(trex_search(_exp,text,out_begin,out_end) != 0):false;
- }
- // Searches for the first match of the expression in a string sarting at text_begin and ending at text_end
- bool SearchRange(const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end) {
- return _exp?(trex_searchrange(_exp,text_begin,text_end,out_begin,out_end) != 0):false;
- }
- bool GetSubExp(int n, const TRexChar** out_begin, int *out_len)
- {
- TRexMatch match;
- TRexBool res = _exp?(trex_getsubexp(_exp,n,&match)):TRex_False;
- if(res) {
- *out_begin = match.begin;
- *out_len = match.len;
- return true;
- }
- return false;
- }
- int GetSubExpCount() { return _exp?trex_getsubexpcount(_exp):0; }
-private:
- void CleanUp() { if(_exp) trex_free(_exp); _exp = (TRex *)0; }
- TRex *_exp;
-};
-#endif //_TREXPP_H_ \ No newline at end of file
diff --git a/drivers/trex/history.txt b/drivers/trex/history.txt
deleted file mode 100644
index 5cfe8770b4..0000000000
--- a/drivers/trex/history.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-===version 1.3
--fixed a bug for GCC users(thx Brendan)
-
-===version 1.2
--added word boundary match \b and \B
--added vertical tab escape \v
--\w now also matches '_' (underscore)
--fixed greediness for * and +
-
-===version 1.1 , April 1, 2004
--fixed some minor bug
--added predefined character classes(\w,\W,\s,\S etc...)
-
-===version 1.0 , February 23, 2004
--first public realase \ No newline at end of file
diff --git a/drivers/trex/readme.txt b/drivers/trex/readme.txt
deleted file mode 100644
index 1d93558e92..0000000000
--- a/drivers/trex/readme.txt
+++ /dev/null
@@ -1,171 +0,0 @@
-T-REX 1.3 http://tiny-rex.sourceforge.net
-----------------------------------------------------------------------
- T-Rex a tiny regular expression library
-
- Copyright (C) 2003-2006 Alberto Demichelis
-
- This software is provided 'as-is', without any express
- or implied warranty. In no event will the authors be held
- liable for any damages arising from the use of this software.
-
- Permission is granted to anyone to use this software for
- any purpose, including commercial applications, and to alter
- it and redistribute it freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented;
- you must not claim that you wrote the original software.
- If you use this software in a product, an acknowledgment
- in the product documentation would be appreciated but
- is not required.
-
- 2. Altered source versions must be plainly marked as such,
- and must not be misrepresented as being the original software.
-
- 3. This notice may not be removed or altered from any
- source distribution.
-
-----------------------------------------------------------------------
-TRex implements the following expressions
-
-\ Quote the next metacharacter
-^ Match the beginning of the string
-. Match any character
-$ Match the end of the string
-| Alternation
-() Grouping (creates a capture)
-[] Character class
-
-==GREEDY CLOSURES==
-* Match 0 or more times
-+ Match 1 or more times
-? Match 1 or 0 times
-{n} Match exactly n times
-{n,} Match at least n times
-{n,m} Match at least n but not more than m times
-
-==ESCAPE CHARACTERS==
-\t tab (HT, TAB)
-\n newline (LF, NL)
-\r return (CR)
-\f form feed (FF)
-
-==PREDEFINED CLASSES==
-\l lowercase next char
-\u uppercase next char
-\a letters
-\A non letters
-\w alphanimeric [0-9a-zA-Z]
-\W non alphanimeric
-\s space
-\S non space
-\d digits
-\D non nondigits
-\x exadecimal digits
-\X non exadecimal digits
-\c control charactrs
-\C non control charactrs
-\p punctation
-\P non punctation
-\b word boundary
-\B non word boundary
-
-----------------------------------------------------------------------
-API DOC
-----------------------------------------------------------------------
-TRex *trex_compile(const TRexChar *pattern,const TRexChar **error);
-
-compiles an expression and returns a pointer to the compiled version.
-in case of failure returns NULL.The returned object has to be deleted
-through the function trex_free().
-
-pattern
- a pointer to a zero terminated string containing the pattern that
- has to be compiled.
-error
- apointer to a string pointer that will be set with an error string
- in case of failure.
-
-----------------------------------------------------------------------
-void trex_free(TRex *exp)
-
-deletes a expression structure created with trex_compile()
-
-exp
- the expression structure that has to be deleted
-
-----------------------------------------------------------------------
-TRexBool trex_match(TRex* exp,const TRexChar* text)
-
-returns TRex_True if the string specified in the parameter text is an
-exact match of the expression, otherwise returns TRex_False.
-
-exp
- the compiled expression
-text
- the string that has to be tested
-
-----------------------------------------------------------------------
-TRexBool trex_search(TRex* exp,const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end)
-
-searches the first match of the expressin in the string specified in the parameter text.
-if the match is found returns TRex_True and the sets out_begin to the beginning of the
-match and out_end at the end of the match; otherwise returns TRex_False.
-
-exp
- the compiled expression
-text
- the string that has to be tested
-out_begin
- a pointer to a string pointer that will be set with the beginning of the match
-out_end
- a pointer to a string pointer that will be set with the end of the match
-
-----------------------------------------------------------------------
-TREX_API TRexBool trex_searchrange(TRex* exp,const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end)
-
-searches the first match of the expressin in the string delimited
-by the parameter text_begin and text_end.
-if the match is found returns TRex_True and the sets out_begin to the beginning of the
-match and out_end at the end of the match; otherwise returns TRex_False.
-
-exp
- the compiled expression
-text_begin
- a pointer to the beginnning of the string that has to be tested
-text_end
- a pointer to the end of the string that has to be tested
-out_begin
- a pointer to a string pointer that will be set with the beginning of the match
-out_end
- a pointer to a string pointer that will be set with the end of the match
-
-----------------------------------------------------------------------
-int trex_getsubexpcount(TRex* exp)
-
-returns the number of sub expressions matched by the expression
-
-exp
- the compiled expression
-
----------------------------------------------------------------------
-TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *submatch)
-
-retrieve the begin and and pointer to the length of the sub expression indexed
-by n. The result is passed trhough the struct TRexMatch:
-
-typedef struct {
- const TRexChar *begin;
- int len;
-} TRexMatch;
-
-the function returns TRex_True if n is valid index otherwise TRex_False.
-
-exp
- the compiled expression
-n
- the index of the submatch
-submatch
- a pointer to structure that will store the result
-
-this function works also after a match operation has been performend.
-
diff --git a/drivers/trex/regex.cpp b/drivers/trex/regex.cpp
deleted file mode 100644
index 11cd6256e2..0000000000
--- a/drivers/trex/regex.cpp
+++ /dev/null
@@ -1,163 +0,0 @@
-/*************************************************/
-/* regex.cpp */
-/*************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/*************************************************/
-/* Source code within this file is: */
-/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
-/* All Rights Reserved. */
-/*************************************************/
-
-#include "regex.h"
-
-extern "C" {
-
-#define _UNICODE
-#include "trex.h"
-
-};
-
-void RegEx::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("compile","pattern"),&RegEx::compile);
- ObjectTypeDB::bind_method(_MD("find","text", "start","end"),&RegEx::_bind_find, DEFVAL(0), DEFVAL(-1));
- ObjectTypeDB::bind_method(_MD("get_captures"),&RegEx::_bind_get_captures);
-};
-
-Error RegEx::compile(const String& p_pattern) {
-
- clear();
- const TRexChar* error;
- exp = trex_compile(p_pattern.c_str(), &error);
- ERR_FAIL_COND_V(!exp, FAILED);
- return OK;
-};
-
-
-int RegEx::_bind_find(const String& p_text, int p_start, int p_end) const {
-
- int start, end;
- bool ret = find(p_text, start, end, NULL, p_start, p_end);
-
- return ret?start:-1;
-};
-
-bool RegEx::find(const String& p_text, int& p_rstart, int &p_rend, List<String>* p_captures, int p_start, int p_end) const {
-
- ERR_FAIL_COND_V( !exp, false );
- text=p_text;
-
- const CharType* str = p_text.c_str();
- const CharType* start = str + p_start;
- const CharType* end = str + (p_end == -1?p_text.size():p_end);
-
- const CharType* out_begin;
- const CharType* out_end;
-
- bool ret = trex_searchrange(exp, start, end, &out_begin, &out_end);
- if (ret) {
-
- p_rstart = out_begin - str;
- p_rend = out_end - str;
-
- if (p_captures) {
-
- int count = get_capture_count();
- for (int i=0; i<count; i++) {
-
- int start, len;
- get_capture_limits(i, start, len);
- p_captures->push_back(p_text.substr(start, len));
- };
- };
- } else {
-
- p_rstart = -1;
- };
-
- return ret;
-};
-
-
-bool RegEx::match(const String& p_text, List<String>* p_captures, int p_start, int p_end) const {
-
- ERR_FAIL_COND_V( !exp, false );
-
- int start, end;
- return find(p_text, start, end, p_captures, p_start, p_end);
-};
-
-int RegEx::get_capture_count() const {
-
- ERR_FAIL_COND_V( exp == NULL, -1 );
-
- return trex_getsubexpcount(exp);
-};
-
-Error RegEx::get_capture_limits(int p_capture, int& p_start, int& p_len) const {
-
- ERR_FAIL_COND_V( exp == NULL, ERR_UNCONFIGURED );
-
- TRexMatch match;
- TRexBool res = trex_getsubexp(exp, p_capture, &match);
- ERR_FAIL_COND_V( !res, FAILED );
- p_start = (int)(match.begin - text.c_str());
- p_len = match.len;
-
- return OK;
-};
-
-String RegEx::get_capture(int p_idx) const {
-
- ERR_FAIL_COND_V( exp == NULL, "" );
- int start, len;
- Error ret = get_capture_limits(p_idx, start, len);
- ERR_FAIL_COND_V(ret != OK, "");
- if (len == 0)
- return "";
- return text.substr(start, len);
-};
-
-StringArray RegEx::_bind_get_captures() const {
-
- StringArray ret;
- int count = get_capture_count();
- for (int i=0; i<count; i++) {
-
- String c = get_capture(i);
- ret.push_back(c);
- };
-
- return ret;
-};
-
-bool RegEx::is_valid() const {
-
- return exp != NULL;
-};
-
-void RegEx::clear() {
-
- if (exp) {
-
- trex_free(exp);
- exp = NULL;
- };
-};
-
-RegEx::RegEx(const String& p_pattern) {
-
- exp = NULL;
- compile(p_pattern);
-};
-
-RegEx::RegEx() {
-
- exp = NULL;
-};
-
-RegEx::~RegEx() {
-
- clear();
-};
diff --git a/drivers/trex/regex.h b/drivers/trex/regex.h
deleted file mode 100644
index 899bfd0189..0000000000
--- a/drivers/trex/regex.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*************************************************/
-/* regex.h */
-/*************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/*************************************************/
-/* Source code within this file is: */
-/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
-/* All Rights Reserved. */
-/*************************************************/
-
-#ifndef REGEX_H
-#define REGEX_H
-
-#include "ustring.h"
-#include "list.h"
-#include "core/reference.h"
-struct TRex;
-
-class RegEx : public Reference {
-
- OBJ_TYPE(RegEx, Reference);
-
- mutable String text;
- TRex *exp;
-
-protected:
-
- static void _bind_methods();
-
- int _bind_find(const String& p_text, int p_start = 0, int p_end = -1) const;
- StringArray _bind_get_captures() const;
-public:
-
- void clear();
-
- Error compile(const String& p_pattern);
- bool is_valid() const;
- bool match(const String& p_text, List<String>* p_captures = NULL, int p_start = 0, int p_end = -1) const;
- bool find(const String& p_text, int& p_rstart, int &p_rend, List<String>* p_captures = NULL, int p_start = 0, int p_end = -1) const;
- int get_capture_count() const;
- Error get_capture_limits(int p_capture, int& p_start, int& p_len) const;
- String get_capture(int p_idx) const;
-
- RegEx();
- RegEx(const String& p_pattern);
- ~RegEx();
-};
-
-#endif // REGEX_H
diff --git a/drivers/trex/test.c b/drivers/trex/test.c
deleted file mode 100644
index 69db49c1af..0000000000
--- a/drivers/trex/test.c
+++ /dev/null
@@ -1,41 +0,0 @@
-#include "trex.h"
-#include <stdio.h>
-#include <string.h>
-
-#ifdef _UNICODE
-#define trex_sprintf swprintf
-#else
-#define trex_sprintf sprintf
-#endif
-
-int main(int argc, char* argv[])
-{
- const TRexChar *begin,*end;
- TRexChar sTemp[200];
- const TRexChar *error = NULL;
- TRex *x = trex_compile(_TREXC("(x{1,5})xx"),&error);
- if(x) {
- trex_sprintf(sTemp,_TREXC("xxxxxxx"));
- if(trex_search(x,sTemp,&begin,&end))
- {
- int i,n = trex_getsubexpcount(x);
- TRexMatch match;
- for(i = 0; i < n; i++)
- {
- TRexChar t[200];
- trex_getsubexp(x,i,&match);
- trex_sprintf(t,_TREXC("[%%d]%%.%ds\n"),match.len);
- trex_printf(t,i,match.begin);
- }
- trex_printf(_TREXC("match! %d sub matches\n"),trex_getsubexpcount(x));
- }
- else {
- trex_printf(_TREXC("no match!\n"));
- }
- trex_free(x);
- }
- else {
- trex_printf(_TREXC("compilation error [%s]!\n"),error?error:_TREXC("undefined"));
- }
- return 0;
-}
diff --git a/drivers/trex/trex.c b/drivers/trex/trex.c
deleted file mode 100644
index b3668c3a11..0000000000
--- a/drivers/trex/trex.c
+++ /dev/null
@@ -1,643 +0,0 @@
- /* see copyright notice in trex.h */
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <setjmp.h>
-#include "trex.h"
-
-#ifdef _UINCODE
-#define scisprint iswprint
-#define scstrlen wcslen
-#define scprintf wprintf
-#define _SC(x) L##c
-#else
-#define scisprint isprint
-#define scstrlen strlen
-#define scprintf printf
-#define _SC(x) (x)
-#endif
-
-#ifdef _DEBUG
-#include <stdio.h>
-
-static const TRexChar *g_nnames[] =
-{
- _SC("NONE"),_SC("OP_GREEDY"), _SC("OP_OR"),
- _SC("OP_EXPR"),_SC("OP_NOCAPEXPR"),_SC("OP_DOT"), _SC("OP_CLASS"),
- _SC("OP_CCLASS"),_SC("OP_NCLASS"),_SC("OP_RANGE"),_SC("OP_CHAR"),
- _SC("OP_EOL"),_SC("OP_BOL"),_SC("OP_WB")
-};
-
-#endif
-#define OP_GREEDY (MAX_CHAR+1) // * + ? {n}
-#define OP_OR (MAX_CHAR+2)
-#define OP_EXPR (MAX_CHAR+3) //parentesis ()
-#define OP_NOCAPEXPR (MAX_CHAR+4) //parentesis (?:)
-#define OP_DOT (MAX_CHAR+5)
-#define OP_CLASS (MAX_CHAR+6)
-#define OP_CCLASS (MAX_CHAR+7)
-#define OP_NCLASS (MAX_CHAR+8) //negates class the [^
-#define OP_RANGE (MAX_CHAR+9)
-#define OP_CHAR (MAX_CHAR+10)
-#define OP_EOL (MAX_CHAR+11)
-#define OP_BOL (MAX_CHAR+12)
-#define OP_WB (MAX_CHAR+13)
-
-#define TREX_SYMBOL_ANY_CHAR ('.')
-#define TREX_SYMBOL_GREEDY_ONE_OR_MORE ('+')
-#define TREX_SYMBOL_GREEDY_ZERO_OR_MORE ('*')
-#define TREX_SYMBOL_GREEDY_ZERO_OR_ONE ('?')
-#define TREX_SYMBOL_BRANCH ('|')
-#define TREX_SYMBOL_END_OF_STRING ('$')
-#define TREX_SYMBOL_BEGINNING_OF_STRING ('^')
-#define TREX_SYMBOL_ESCAPE_CHAR ('\\')
-
-
-typedef int TRexNodeType;
-
-typedef struct tagTRexNode{
- TRexNodeType type;
- int left;
- int right;
- int next;
-}TRexNode;
-
-struct TRex{
- const TRexChar *_eol;
- const TRexChar *_bol;
- const TRexChar *_p;
- int _first;
- int _op;
- TRexNode *_nodes;
- int _nallocated;
- int _nsize;
- int _nsubexpr;
- TRexMatch *_matches;
- int _currsubexp;
- void *_jmpbuf;
- const TRexChar **_error;
-};
-
-static int trex_list(TRex *exp);
-
-static int trex_newnode(TRex *exp, TRexNodeType type)
-{
- TRexNode n;
- int newid;
- n.type = type;
- n.next = n.right = n.left = -1;
- if(type == OP_EXPR)
- n.right = exp->_nsubexpr++;
- if(exp->_nallocated < (exp->_nsize + 1)) {
- //int oldsize = exp->_nallocated;
- exp->_nallocated *= 2;
- exp->_nodes = (TRexNode *)realloc(exp->_nodes, exp->_nallocated * sizeof(TRexNode));
- }
- exp->_nodes[exp->_nsize++] = n;
- newid = exp->_nsize - 1;
- return (int)newid;
-}
-
-static void trex_error(TRex *exp,const TRexChar *error)
-{
- if(exp->_error) *exp->_error = error;
- longjmp(*((jmp_buf*)exp->_jmpbuf),-1);
-}
-
-static void trex_expect(TRex *exp, int n){
- if((*exp->_p) != n)
- trex_error(exp, _SC("expected paren"));
- exp->_p++;
-}
-
-static TRexChar trex_escapechar(TRex *exp)
-{
- if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR){
- exp->_p++;
- switch(*exp->_p) {
- case 'v': exp->_p++; return '\v';
- case 'n': exp->_p++; return '\n';
- case 't': exp->_p++; return '\t';
- case 'r': exp->_p++; return '\r';
- case 'f': exp->_p++; return '\f';
- default: return (*exp->_p++);
- }
- } else if(!scisprint(*exp->_p)) trex_error(exp,_SC("letter expected"));
- return (*exp->_p++);
-}
-
-static int trex_charclass(TRex *exp,int classid)
-{
- int n = trex_newnode(exp,OP_CCLASS);
- exp->_nodes[n].left = classid;
- return n;
-}
-
-static int trex_charnode(TRex *exp,TRexBool isclass)
-{
- TRexChar t;
- if(*exp->_p == TREX_SYMBOL_ESCAPE_CHAR) {
- exp->_p++;
- switch(*exp->_p) {
- case 'n': exp->_p++; return trex_newnode(exp,'\n');
- case 't': exp->_p++; return trex_newnode(exp,'\t');
- case 'r': exp->_p++; return trex_newnode(exp,'\r');
- case 'f': exp->_p++; return trex_newnode(exp,'\f');
- case 'v': exp->_p++; return trex_newnode(exp,'\v');
- case 'a': case 'A': case 'w': case 'W': case 's': case 'S':
- case 'd': case 'D': case 'x': case 'X': case 'c': case 'C':
- case 'p': case 'P': case 'l': case 'u':
- {
- t = *exp->_p; exp->_p++;
- return trex_charclass(exp,t);
- }
- case 'b':
- case 'B':
- if(!isclass) {
- int node = trex_newnode(exp,OP_WB);
- exp->_nodes[node].left = *exp->_p;
- exp->_p++;
- return node;
- } //else default
- default:
- t = *exp->_p; exp->_p++;
- return trex_newnode(exp,t);
- }
- }
- else if(!scisprint(*exp->_p)) {
-
- trex_error(exp,_SC("letter expected"));
- }
- t = *exp->_p; exp->_p++;
- return trex_newnode(exp,t);
-}
-static int trex_class(TRex *exp)
-{
- int ret = -1;
- int first = -1,chain;
- if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING){
- ret = trex_newnode(exp,OP_NCLASS);
- exp->_p++;
- }else ret = trex_newnode(exp,OP_CLASS);
-
- if(*exp->_p == ']') trex_error(exp,_SC("empty class"));
- chain = ret;
- while(*exp->_p != ']' && exp->_p != exp->_eol) {
- if(*exp->_p == '-' && first != -1){
- int r,t;
- if(*exp->_p++ == ']') trex_error(exp,_SC("unfinished range"));
- r = trex_newnode(exp,OP_RANGE);
- if(first>*exp->_p) trex_error(exp,_SC("invalid range"));
- if(exp->_nodes[first].type == OP_CCLASS) trex_error(exp,_SC("cannot use character classes in ranges"));
- exp->_nodes[r].left = exp->_nodes[first].type;
- t = trex_escapechar(exp);
- exp->_nodes[r].right = t;
- exp->_nodes[chain].next = r;
- chain = r;
- first = -1;
- }
- else{
- if(first!=-1){
- int c = first;
- exp->_nodes[chain].next = c;
- chain = c;
- first = trex_charnode(exp,TRex_True);
- }
- else{
- first = trex_charnode(exp,TRex_True);
- }
- }
- }
- if(first!=-1){
- int c = first;
- exp->_nodes[chain].next = c;
- chain = c;
- first = -1;
- }
- /* hack? */
- exp->_nodes[ret].left = exp->_nodes[ret].next;
- exp->_nodes[ret].next = -1;
- return ret;
-}
-
-static int trex_parsenumber(TRex *exp)
-{
- int ret = *exp->_p-'0';
- int positions = 10;
- exp->_p++;
- while(isdigit(*exp->_p)) {
- ret = ret*10+(*exp->_p++-'0');
- if(positions==1000000000) trex_error(exp,_SC("overflow in numeric constant"));
- positions *= 10;
- };
- return ret;
-}
-
-static int trex_element(TRex *exp)
-{
- int ret = -1;
- switch(*exp->_p)
- {
- case '(': {
- int expr,newn;
- exp->_p++;
-
-
- if(*exp->_p =='?') {
- exp->_p++;
- trex_expect(exp,':');
- expr = trex_newnode(exp,OP_NOCAPEXPR);
- }
- else
- expr = trex_newnode(exp,OP_EXPR);
- newn = trex_list(exp);
- exp->_nodes[expr].left = newn;
- ret = expr;
- trex_expect(exp,')');
- }
- break;
- case '[':
- exp->_p++;
- ret = trex_class(exp);
- trex_expect(exp,']');
- break;
- case TREX_SYMBOL_END_OF_STRING: exp->_p++; ret = trex_newnode(exp,OP_EOL);break;
- case TREX_SYMBOL_ANY_CHAR: exp->_p++; ret = trex_newnode(exp,OP_DOT);break;
- default:
- ret = trex_charnode(exp,TRex_False);
- break;
- }
-
- {
- int op;
- TRexBool isgreedy = TRex_False;
- unsigned short p0 = 0, p1 = 0;
- switch(*exp->_p){
- case TREX_SYMBOL_GREEDY_ZERO_OR_MORE: p0 = 0; p1 = 0xFFFF; exp->_p++; isgreedy = TRex_True; break;
- case TREX_SYMBOL_GREEDY_ONE_OR_MORE: p0 = 1; p1 = 0xFFFF; exp->_p++; isgreedy = TRex_True; break;
- case TREX_SYMBOL_GREEDY_ZERO_OR_ONE: p0 = 0; p1 = 1; exp->_p++; isgreedy = TRex_True; break;
- case '{':
- exp->_p++;
- if(!isdigit(*exp->_p)) trex_error(exp,_SC("number expected"));
- p0 = (unsigned short)trex_parsenumber(exp);
- /*******************************/
- switch(*exp->_p) {
- case '}':
- p1 = p0; exp->_p++;
- break;
- case ',':
- exp->_p++;
- p1 = 0xFFFF;
- if(isdigit(*exp->_p)){
- p1 = (unsigned short)trex_parsenumber(exp);
- }
- trex_expect(exp,'}');
- break;
- default:
- trex_error(exp,_SC(", or } expected"));
- }
- /*******************************/
- isgreedy = TRex_True;
- break;
-
- }
- if(isgreedy) {
- int nnode = trex_newnode(exp,OP_GREEDY);
- op = OP_GREEDY;
- exp->_nodes[nnode].left = ret;
- exp->_nodes[nnode].right = ((p0)<<16)|p1;
- ret = nnode;
- }
- }
- if((*exp->_p != TREX_SYMBOL_BRANCH) && (*exp->_p != ')') && (*exp->_p != TREX_SYMBOL_GREEDY_ZERO_OR_MORE) && (*exp->_p != TREX_SYMBOL_GREEDY_ONE_OR_MORE) && (*exp->_p != '\0')) {
- int nnode = trex_element(exp);
- exp->_nodes[ret].next = nnode;
- }
-
- return ret;
-}
-
-static int trex_list(TRex *exp)
-{
- int ret=-1,e;
- if(*exp->_p == TREX_SYMBOL_BEGINNING_OF_STRING) {
- exp->_p++;
- ret = trex_newnode(exp,OP_BOL);
- }
- e = trex_element(exp);
- if(ret != -1) {
- exp->_nodes[ret].next = e;
- }
- else ret = e;
-
- if(*exp->_p == TREX_SYMBOL_BRANCH) {
- int temp,tright;
- exp->_p++;
- temp = trex_newnode(exp,OP_OR);
- exp->_nodes[temp].left = ret;
- tright = trex_list(exp);
- exp->_nodes[temp].right = tright;
- ret = temp;
- }
- return ret;
-}
-
-static TRexBool trex_matchcclass(int cclass,TRexChar c)
-{
- switch(cclass) {
- case 'a': return isalpha(c)?TRex_True:TRex_False;
- case 'A': return !isalpha(c)?TRex_True:TRex_False;
- case 'w': return (isalnum(c) || c == '_')?TRex_True:TRex_False;
- case 'W': return (!isalnum(c) && c != '_')?TRex_True:TRex_False;
- case 's': return isspace(c)?TRex_True:TRex_False;
- case 'S': return !isspace(c)?TRex_True:TRex_False;
- case 'd': return isdigit(c)?TRex_True:TRex_False;
- case 'D': return !isdigit(c)?TRex_True:TRex_False;
- case 'x': return isxdigit(c)?TRex_True:TRex_False;
- case 'X': return !isxdigit(c)?TRex_True:TRex_False;
- case 'c': return iscntrl(c)?TRex_True:TRex_False;
- case 'C': return !iscntrl(c)?TRex_True:TRex_False;
- case 'p': return ispunct(c)?TRex_True:TRex_False;
- case 'P': return !ispunct(c)?TRex_True:TRex_False;
- case 'l': return islower(c)?TRex_True:TRex_False;
- case 'u': return isupper(c)?TRex_True:TRex_False;
- }
- return TRex_False; /*cannot happen*/
-}
-
-static TRexBool trex_matchclass(TRex* exp,TRexNode *node,TRexChar c)
-{
- do {
- switch(node->type) {
- case OP_RANGE:
- if(c >= node->left && c <= node->right) return TRex_True;
- break;
- case OP_CCLASS:
- if(trex_matchcclass(node->left,c)) return TRex_True;
- break;
- default:
- if(c == node->type)return TRex_True;
- }
- } while((node->next != -1) && (node = &exp->_nodes[node->next]));
- return TRex_False;
-}
-
-static const TRexChar *trex_matchnode(TRex* exp,TRexNode *node,const TRexChar *str,TRexNode *next)
-{
-
- TRexNodeType type = node->type;
- switch(type) {
- case OP_GREEDY: {
- //TRexNode *greedystop = (node->next != -1) ? &exp->_nodes[node->next] : NULL;
- TRexNode *greedystop = NULL;
- int p0 = (node->right >> 16)&0x0000FFFF, p1 = node->right&0x0000FFFF, nmaches = 0;
- const TRexChar *s=str, *good = str;
-
- if(node->next != -1) {
- greedystop = &exp->_nodes[node->next];
- }
- else {
- greedystop = next;
- }
-
- while((nmaches == 0xFFFF || nmaches < p1)) {
-
- const TRexChar *stop;
- if(!(s = trex_matchnode(exp,&exp->_nodes[node->left],s,greedystop)))
- break;
- nmaches++;
- good=s;
- if(greedystop) {
- //checks that 0 matches satisfy the expression(if so skips)
- //if not would always stop(for instance if is a '?')
- if(greedystop->type != OP_GREEDY ||
- (greedystop->type == OP_GREEDY && ((greedystop->right >> 16)&0x0000FFFF) != 0))
- {
- TRexNode *gnext = NULL;
- if(greedystop->next != -1) {
- gnext = &exp->_nodes[greedystop->next];
- }else if(next && next->next != -1){
- gnext = &exp->_nodes[next->next];
- }
- stop = trex_matchnode(exp,greedystop,s,gnext);
- if(stop) {
- //if satisfied stop it
- if(p0 == p1 && p0 == nmaches) break;
- else if(nmaches >= p0 && p1 == 0xFFFF) break;
- else if(nmaches >= p0 && nmaches <= p1) break;
- }
- }
- }
-
- if(s >= exp->_eol)
- break;
- }
- if(p0 == p1 && p0 == nmaches) return good;
- else if(nmaches >= p0 && p1 == 0xFFFF) return good;
- else if(nmaches >= p0 && nmaches <= p1) return good;
- return NULL;
- }
- case OP_OR: {
- const TRexChar *asd = str;
- TRexNode *temp=&exp->_nodes[node->left];
- while( (asd = trex_matchnode(exp,temp,asd,NULL)) ) {
- if(temp->next != -1)
- temp = &exp->_nodes[temp->next];
- else
- return asd;
- }
- asd = str;
- temp = &exp->_nodes[node->right];
- while( (asd = trex_matchnode(exp,temp,asd,NULL)) ) {
- if(temp->next != -1)
- temp = &exp->_nodes[temp->next];
- else
- return asd;
- }
- return NULL;
- break;
- }
- case OP_EXPR:
- case OP_NOCAPEXPR:{
- TRexNode *n = &exp->_nodes[node->left];
- const TRexChar *cur = str;
- int capture = -1;
- if(node->type != OP_NOCAPEXPR && node->right == exp->_currsubexp) {
- capture = exp->_currsubexp;
- exp->_matches[capture].begin = cur;
- exp->_currsubexp++;
- }
-
- do {
- TRexNode *subnext = NULL;
- if(n->next != -1) {
- subnext = &exp->_nodes[n->next];
- }else {
- subnext = next;
- }
- if(!(cur = trex_matchnode(exp,n,cur,subnext))) {
- if(capture != -1){
- exp->_matches[capture].begin = 0;
- exp->_matches[capture].len = 0;
- }
- return NULL;
- }
- } while((n->next != -1) && (n = &exp->_nodes[n->next]));
-
- if(capture != -1)
- exp->_matches[capture].len = cur - exp->_matches[capture].begin;
- return cur;
- }
- case OP_WB:
- if((str == exp->_bol && !isspace(*str))
- || (str == exp->_eol && !isspace(*(str-1)))
- || (!isspace(*str) && isspace(*(str+1)))
- || (isspace(*str) && !isspace(*(str+1))) ) {
- return (node->left == 'b')?str:NULL;
- }
- return (node->left == 'b')?NULL:str;
- case OP_BOL:
- if(str == exp->_bol) return str;
- return NULL;
- case OP_EOL:
- if(str == exp->_eol) return str;
- return NULL;
- case OP_DOT:{
- *str++;
- }
- return str;
- case OP_NCLASS:
- case OP_CLASS:
- if(trex_matchclass(exp,&exp->_nodes[node->left],*str)?(type == OP_CLASS?TRex_True:TRex_False):(type == OP_NCLASS?TRex_True:TRex_False)) {
- *str++;
- return str;
- }
- return NULL;
- case OP_CCLASS:
- if(trex_matchcclass(node->left,*str)) {
- *str++;
- return str;
- }
- return NULL;
- default: /* char */
- if(*str != node->type) return NULL;
- *str++;
- return str;
- }
- return NULL;
-}
-
-/* public api */
-TRex *trex_compile(const TRexChar *pattern,const TRexChar **error)
-{
- TRex *exp = (TRex *)malloc(sizeof(TRex));
- exp->_eol = exp->_bol = NULL;
- exp->_p = pattern;
- exp->_nallocated = (int)scstrlen(pattern) * sizeof(TRexChar);
- exp->_nodes = (TRexNode *)malloc(exp->_nallocated * sizeof(TRexNode));
- exp->_nsize = 0;
- exp->_matches = 0;
- exp->_nsubexpr = 0;
- exp->_first = trex_newnode(exp,OP_EXPR);
- exp->_error = error;
- exp->_jmpbuf = malloc(sizeof(jmp_buf));
- if(setjmp(*((jmp_buf*)exp->_jmpbuf)) == 0) {
- int res = trex_list(exp);
- exp->_nodes[exp->_first].left = res;
- if(*exp->_p!='\0')
- trex_error(exp,_SC("unexpected character"));
-#ifdef _DEBUG
- {
- int nsize,i;
- TRexNode *t;
- nsize = exp->_nsize;
- t = &exp->_nodes[0];
- scprintf(_SC("\n"));
- for(i = 0;i < nsize; i++) {
- if(exp->_nodes[i].type>MAX_CHAR)
- scprintf(_SC("[%02d] %10s "),i,g_nnames[exp->_nodes[i].type-MAX_CHAR]);
- else
- scprintf(_SC("[%02d] %10c "),i,exp->_nodes[i].type);
- scprintf(_SC("left %02d right %02d next %02d\n"),exp->_nodes[i].left,exp->_nodes[i].right,exp->_nodes[i].next);
- }
- scprintf(_SC("\n"));
- }
-#endif
- exp->_matches = (TRexMatch *) malloc(exp->_nsubexpr * sizeof(TRexMatch));
- memset(exp->_matches,0,exp->_nsubexpr * sizeof(TRexMatch));
- }
- else{
- trex_free(exp);
- return NULL;
- }
- return exp;
-}
-
-void trex_free(TRex *exp)
-{
- if(exp) {
- if(exp->_nodes) free(exp->_nodes);
- if(exp->_jmpbuf) free(exp->_jmpbuf);
- if(exp->_matches) free(exp->_matches);
- free(exp);
- }
-}
-
-TRexBool trex_match(TRex* exp,const TRexChar* text)
-{
- const TRexChar* res = NULL;
- exp->_bol = text;
- exp->_eol = text + scstrlen(text);
- exp->_currsubexp = 0;
- res = trex_matchnode(exp,exp->_nodes,text,NULL);
- if(res == NULL || res != exp->_eol)
- return TRex_False;
- return TRex_True;
-}
-
-TRexBool trex_searchrange(TRex* exp,const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end)
-{
- const TRexChar *cur = NULL;
- int node = exp->_first;
- if(text_begin >= text_end) return TRex_False;
- exp->_bol = text_begin;
- exp->_eol = text_end;
- do {
- cur = text_begin;
- while(node != -1) {
- exp->_currsubexp = 0;
- cur = trex_matchnode(exp,&exp->_nodes[node],cur,NULL);
- if(!cur)
- break;
- node = exp->_nodes[node].next;
- }
- *text_begin++;
- } while(cur == NULL && text_begin != text_end);
-
- if(cur == NULL)
- return TRex_False;
-
- --text_begin;
-
- if(out_begin) *out_begin = text_begin;
- if(out_end) *out_end = cur;
- return TRex_True;
-}
-
-TRexBool trex_search(TRex* exp,const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end)
-{
- return trex_searchrange(exp,text,text + scstrlen(text),out_begin,out_end);
-}
-
-int trex_getsubexpcount(TRex* exp)
-{
- return exp->_nsubexpr;
-}
-
-TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp)
-{
- if( n<0 || n >= exp->_nsubexpr) return TRex_False;
- *subexp = exp->_matches[n];
- return TRex_True;
-}
-
diff --git a/drivers/trex/trex.h b/drivers/trex/trex.h
deleted file mode 100644
index 46e2e73fd5..0000000000
--- a/drivers/trex/trex.h
+++ /dev/null
@@ -1,70 +0,0 @@
-#ifndef _TREX_H_
-#define _TREX_H_
-/***************************************************************
- T-Rex a tiny regular expression library
-
- Copyright (C) 2003-2006 Alberto Demichelis
-
- This software is provided 'as-is', without any express
- or implied warranty. In no event will the authors be held
- liable for any damages arising from the use of this software.
-
- Permission is granted to anyone to use this software for
- any purpose, including commercial applications, and to alter
- it and redistribute it freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented;
- you must not claim that you wrote the original software.
- If you use this software in a product, an acknowledgment
- in the product documentation would be appreciated but
- is not required.
-
- 2. Altered source versions must be plainly marked as such,
- and must not be misrepresented as being the original software.
-
- 3. This notice may not be removed or altered from any
- source distribution.
-
-****************************************************************/
-
-#define _UNICODE
-
-
-#ifdef _UNICODE
-#define TRexChar wchar_t
-#define MAX_CHAR 0xFFFF
-#define _TREXC(c) L##c
-#define trex_strlen wcslen
-#define trex_printf wprintf
-#else
-#define TRexChar char
-#define MAX_CHAR 0xFF
-#define _TREXC(c) (c)
-#define trex_strlen strlen
-#define trex_printf printf
-#endif
-
-#ifndef TREX_API
-#define TREX_API extern
-#endif
-
-#define TRex_True 1
-#define TRex_False 0
-
-typedef unsigned int TRexBool;
-typedef struct TRex TRex;
-
-typedef struct {
- const TRexChar *begin;
- int len;
-} TRexMatch;
-
-TREX_API TRex *trex_compile(const TRexChar *pattern,const TRexChar **error);
-TREX_API void trex_free(TRex *exp);
-TREX_API TRexBool trex_match(TRex* exp,const TRexChar* text);
-TREX_API TRexBool trex_search(TRex* exp,const TRexChar* text, const TRexChar** out_begin, const TRexChar** out_end);
-TREX_API TRexBool trex_searchrange(TRex* exp,const TRexChar* text_begin,const TRexChar* text_end,const TRexChar** out_begin, const TRexChar** out_end);
-TREX_API int trex_getsubexpcount(TRex* exp);
-TREX_API TRexBool trex_getsubexp(TRex* exp, int n, TRexMatch *subexp);
-
-#endif
diff --git a/drivers/unix/SCsub b/drivers/unix/SCsub
index bcd231579c..3d46a85cdf 100644
--- a/drivers/unix/SCsub
+++ b/drivers/unix/SCsub
@@ -1,7 +1,15 @@
Import('env')
+g_set_p='#ifdef UNIX_ENABLED\n'
+g_set_p+='#include "os_unix.h"\n'
+g_set_p+='String OS_Unix::get_global_settings_path() const {\n'
+g_set_p+='\treturn "' + env["unix_global_settings_path"]+'";\n'
+g_set_p+='}\n'
+g_set_p+='#endif'
+f = open("os_unix_global_settings_path.cpp","wb")
+f.write(g_set_p)
+f.close()
+
env.add_source_files(env.drivers_sources,"*.cpp")
Export('env')
-
-
diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp
index 0c0867e030..23a63be339 100644
--- a/drivers/unix/dir_access_unix.cpp
+++ b/drivers/unix/dir_access_unix.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/unix/dir_access_unix.h b/drivers/unix/dir_access_unix.h
index 3091e01511..9cba1ed3e0 100644
--- a/drivers/unix/dir_access_unix.h
+++ b/drivers/unix/dir_access_unix.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp
index 76042089ff..9f24633bd4 100644
--- a/drivers/unix/file_access_unix.cpp
+++ b/drivers/unix/file_access_unix.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -63,7 +63,7 @@ Error FileAccessUnix::_open(const String& p_path, int p_mode_flags) {
fclose(f);
f=NULL;
- String path=fix_path(p_path);
+ path=fix_path(p_path);
//printf("opening %ls, %i\n", path.c_str(), Memory::get_static_mem_usage());
ERR_FAIL_COND_V(f,ERR_ALREADY_IN_USE);
@@ -75,6 +75,8 @@ Error FileAccessUnix::_open(const String& p_path, int p_mode_flags) {
mode_string="wb";
else if (p_mode_flags==READ_WRITE)
mode_string="rb+";
+ else if (p_mode_flags==WRITE_READ)
+ mode_string="wb+";
else
return ERR_INVALID_PARAMETER;
@@ -114,6 +116,9 @@ void FileAccessUnix::close() {
return;
fclose(f);
f = NULL;
+ if (close_notification_func) {
+ close_notification_func(path,flags);
+ }
if (save_path!="") {
//unlink(save_path.utf8().get_data());
@@ -240,6 +245,7 @@ FileAccess * FileAccessUnix::create_libc() {
return memnew( FileAccessUnix );
}
+CloseNotificationFunc FileAccessUnix::close_notification_func=NULL;
FileAccessUnix::FileAccessUnix() {
diff --git a/drivers/unix/file_access_unix.h b/drivers/unix/file_access_unix.h
index 5b0f0e7cb7..d6a172bf47 100644
--- a/drivers/unix/file_access_unix.h
+++ b/drivers/unix/file_access_unix.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -38,6 +38,10 @@
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
+
+
+typedef void (*CloseNotificationFunc)(const String& p_file,int p_flags);
+
class FileAccessUnix : public FileAccess {
FILE *f;
@@ -45,10 +49,13 @@ class FileAccessUnix : public FileAccess {
void check_errors() const;
mutable Error last_error;
String save_path;
+ String path;
- static FileAccess* create_libc();
+ static FileAccess* create_libc();
public:
+ static CloseNotificationFunc close_notification_func;
+
virtual Error _open(const String& p_path, int p_mode_flags); ///< open a file
virtual void close(); ///< close a file
virtual bool is_open() const; ///< true when file is open
diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp
index 989aba52bb..535a425302 100644
--- a/drivers/unix/ip_unix.cpp
+++ b/drivers/unix/ip_unix.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/unix/ip_unix.h b/drivers/unix/ip_unix.h
index 5798ac8137..c0034c9a3a 100644
--- a/drivers/unix/ip_unix.h
+++ b/drivers/unix/ip_unix.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/unix/memory_pool_static_malloc.cpp b/drivers/unix/memory_pool_static_malloc.cpp
index e0bab27a63..1a79272dc1 100644
--- a/drivers/unix/memory_pool_static_malloc.cpp
+++ b/drivers/unix/memory_pool_static_malloc.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/unix/memory_pool_static_malloc.h b/drivers/unix/memory_pool_static_malloc.h
index a96259556d..78ad82ee22 100644
--- a/drivers/unix/memory_pool_static_malloc.h
+++ b/drivers/unix/memory_pool_static_malloc.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/unix/mutex_posix.cpp b/drivers/unix/mutex_posix.cpp
index 73563ea538..fb4fa4a891 100644
--- a/drivers/unix/mutex_posix.cpp
+++ b/drivers/unix/mutex_posix.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/unix/mutex_posix.h b/drivers/unix/mutex_posix.h
index 9b50d7963e..a1993be221 100644
--- a/drivers/unix/mutex_posix.h
+++ b/drivers/unix/mutex_posix.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index 8ba56490d7..a004a116e0 100644
--- a/drivers/unix/os_unix.cpp
+++ b/drivers/unix/os_unix.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -57,17 +57,33 @@
#include <errno.h>
#include <assert.h>
#include "globals.h"
-void OS_Unix::print_error(const char* p_function,const char* p_file,int p_line,const char *p_code,const char*p_rationale,ErrorType p_type) {
- if (p_rationale && p_rationale[0]) {
+extern bool _print_error_enabled;
- print("\E[1;31;40mERROR: %s: \E[1;37;40m%s\n",p_function,p_rationale);
- print("\E[0;31;40m At: %s:%i.\E[0;0;37m\n",p_file,p_line);
+void OS_Unix::print_error(const char* p_function,const char* p_file,int p_line,const char *p_code,const char*p_rationale,ErrorType p_type) {
- } else {
- print("\E[1;31;40mERROR: %s: \E[1;37;40m%s\n",p_function,p_code);
- print("\E[0;31;40m At: %s:%i.\E[0;0;37m\n",p_file,p_line);
+ if (!_print_error_enabled)
+ return;
+ const char* err_details;
+ if (p_rationale && p_rationale[0])
+ err_details=p_rationale;
+ else
+ err_details=p_code;
+
+ switch(p_type) {
+ case ERR_ERROR:
+ print("\E[1;31mERROR: %s: \E[0m\E[1m%s\n",p_function,err_details);
+ print("\E[0;31m At: %s:%i.\E[0m\n",p_file,p_line);
+ break;
+ case ERR_WARNING:
+ print("\E[1;33mWARNING: %s: \E[0m\E[1m%s\n",p_function,err_details);
+ print("\E[0;33m At: %s:%i.\E[0m\n",p_file,p_line);
+ break;
+ case ERR_SCRIPT:
+ print("\E[1;35mSCRIPT ERROR: %s: \E[0m\E[1m%s\n",p_function,err_details);
+ print("\E[0;35m At: %s:%i.\E[0m\n",p_file,p_line);
+ break;
}
}
@@ -133,8 +149,7 @@ void OS_Unix::finalize_core() {
if (mempool_dynamic)
memdelete( mempool_dynamic );
- if (mempool_static)
- delete mempool_static;
+ delete mempool_static;
}
@@ -217,6 +232,14 @@ uint64_t OS_Unix::get_unix_time() const {
return time(NULL);
};
+uint64_t OS_Unix::get_system_time_secs() const {
+ struct timeval tv_now;
+ gettimeofday(&tv_now, NULL);
+ //localtime(&tv_now.tv_usec);
+ //localtime((const long *)&tv_now.tv_usec);
+ return uint64_t(tv_now.tv_sec);
+}
+
OS::Date OS_Unix::get_date(bool utc) const {
@@ -228,7 +251,7 @@ OS::Date OS_Unix::get_date(bool utc) const {
lt=localtime(&t);
Date ret;
ret.year=1900+lt->tm_year;
- ret.month=(Month)lt->tm_mon;
+ ret.month=(Month)(lt->tm_mon + 1);
ret.day=lt->tm_mday;
ret.weekday=(Weekday)lt->tm_wday;
ret.dst=lt->tm_isdst;
@@ -452,6 +475,14 @@ String OS_Unix::get_data_dir() const {
}
+String OS_Unix::get_installed_templates_path() const {
+ String p=get_global_settings_path();
+ if (p!="")
+ return p+"/templates/";
+ else
+ return "";
+}
+
String OS_Unix::get_executable_path() const {
#ifdef __linux__
diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h
index 8bb57eda12..a889bba0ff 100644
--- a/drivers/unix/os_unix.h
+++ b/drivers/unix/os_unix.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -64,6 +64,8 @@ protected:
String stdin_buf;
+ String get_global_settings_path() const;
+
public:
@@ -93,6 +95,7 @@ public:
virtual TimeZoneInfo get_time_zone_info() const;
virtual uint64_t get_unix_time() const;
+ virtual uint64_t get_system_time_secs() const;
virtual void delay_usec(uint32_t p_usec) const;
virtual uint64_t get_ticks_usec() const;
@@ -110,6 +113,7 @@ public:
virtual void debug_break();
+ virtual String get_installed_templates_path() const;
virtual String get_executable_path() const;
virtual String get_data_dir() const;
diff --git a/drivers/unix/packet_peer_udp_posix.cpp b/drivers/unix/packet_peer_udp_posix.cpp
index 26a0b29228..2111619080 100644
--- a/drivers/unix/packet_peer_udp_posix.cpp
+++ b/drivers/unix/packet_peer_udp_posix.cpp
@@ -13,7 +13,11 @@
#include <stdio.h>
#ifndef NO_FCNTL
-#include <sys/fcntl.h>
+ #ifdef __HAIKU__
+ #include <fcntl.h>
+ #else
+ #include <sys/fcntl.h>
+ #endif
#else
#include <sys/ioctl.h>
#endif
@@ -117,7 +121,7 @@ Error PacketPeerUDPPosix::_poll(bool p_wait) {
struct sockaddr_in from = {0};
socklen_t len = sizeof(struct sockaddr_in);
int ret;
- while ( (ret = recvfrom(sockfd, recv_buffer, MIN(sizeof(recv_buffer),rb.data_left()-12), p_wait?0:MSG_DONTWAIT, (struct sockaddr*)&from, &len)) > 0) {
+ while ( (ret = recvfrom(sockfd, recv_buffer, MIN((int)sizeof(recv_buffer),MAX(rb.space_left()-12, 0)), p_wait?0:MSG_DONTWAIT, (struct sockaddr*)&from, &len)) > 0) {
rb.write((uint8_t*)&from.sin_addr, 4);
uint32_t port = ntohs(from.sin_port);
rb.write((uint8_t*)&port, 4);
@@ -127,6 +131,8 @@ Error PacketPeerUDPPosix::_poll(bool p_wait) {
++queue_count;
};
+
+ // TODO: Should ECONNRESET be handled here?
if (ret == 0 || (ret == -1 && errno != EAGAIN) ) {
close();
return FAILED;
diff --git a/drivers/unix/semaphore_posix.cpp b/drivers/unix/semaphore_posix.cpp
index fba4cd3641..3ae94ae5d9 100644
--- a/drivers/unix/semaphore_posix.cpp
+++ b/drivers/unix/semaphore_posix.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -42,7 +42,7 @@ Error SemaphorePosix::wait() {
errno=0;
continue;
} else {
-perror("sem waiting");
+ perror("sem waiting");
return ERR_BUSY;
}
}
diff --git a/drivers/unix/semaphore_posix.h b/drivers/unix/semaphore_posix.h
index 6f938455b3..0a3cf36749 100644
--- a/drivers/unix/semaphore_posix.h
+++ b/drivers/unix/semaphore_posix.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/unix/stream_peer_tcp_posix.cpp b/drivers/unix/stream_peer_tcp_posix.cpp
index 2301d8b6c4..45a4b934c1 100644
--- a/drivers/unix/stream_peer_tcp_posix.cpp
+++ b/drivers/unix/stream_peer_tcp_posix.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -38,8 +38,13 @@
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
+#include <sys/ioctl.h>
#ifndef NO_FCNTL
-#include <sys/fcntl.h>
+ #ifdef __HAIKU__
+ #include <fcntl.h>
+ #else
+ #include <sys/fcntl.h>
+ #endif
#else
#include <sys/ioctl.h>
#endif
@@ -363,6 +368,14 @@ Error StreamPeerTCPPosix::get_partial_data(uint8_t* p_buffer, int p_bytes,int &r
return read(p_buffer, p_bytes, r_received, false);
};
+int StreamPeerTCPPosix::get_available_bytes() const {
+
+ unsigned long len;
+ int ret = ioctl(sockfd,FIONREAD,&len);
+ ERR_FAIL_COND_V(ret==-1,0)
+ return len;
+
+}
IP_Address StreamPeerTCPPosix::get_connected_host() const {
return peer_host;
diff --git a/drivers/unix/stream_peer_tcp_posix.h b/drivers/unix/stream_peer_tcp_posix.h
index 9b1716ac42..a379efe3ca 100644
--- a/drivers/unix/stream_peer_tcp_posix.h
+++ b/drivers/unix/stream_peer_tcp_posix.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -67,6 +67,8 @@ public:
virtual Error get_data(uint8_t* p_buffer, int p_bytes);
virtual Error get_partial_data(uint8_t* p_buffer, int p_bytes,int &r_received);
+ virtual int get_available_bytes() const;
+
void set_socket(int p_sockfd, IP_Address p_host, int p_port);
virtual IP_Address get_connected_host() const;
diff --git a/drivers/unix/tcp_server_posix.cpp b/drivers/unix/tcp_server_posix.cpp
index 4f9ee62cde..98451957fd 100644
--- a/drivers/unix/tcp_server_posix.cpp
+++ b/drivers/unix/tcp_server_posix.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -41,7 +41,11 @@
#include <netdb.h>
#include <sys/types.h>
#ifndef NO_FCNTL
-#include <sys/fcntl.h>
+ #ifdef __HAIKU__
+ #include <fcntl.h>
+ #else
+ #include <sys/fcntl.h>
+ #endif
#else
#include <sys/ioctl.h>
#endif
diff --git a/drivers/unix/tcp_server_posix.h b/drivers/unix/tcp_server_posix.h
index 17a9fd1d98..570bcaab12 100644
--- a/drivers/unix/tcp_server_posix.h
+++ b/drivers/unix/tcp_server_posix.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/unix/thread_posix.cpp b/drivers/unix/thread_posix.cpp
index 03963a9756..bd33c81298 100644
--- a/drivers/unix/thread_posix.cpp
+++ b/drivers/unix/thread_posix.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,6 +30,10 @@
#if defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED)
+#ifdef PTHREAD_BSD_SET_NAME
+#include <pthread_np.h>
+#endif
+
#include "os/memory.h"
Thread::ID ThreadPosix::get_ID() const {
@@ -45,8 +49,8 @@ Thread* ThreadPosix::create_thread_posix() {
void *ThreadPosix::thread_callback(void *userdata) {
ThreadPosix *t=reinterpret_cast<ThreadPosix*>(userdata);
- t->callback(t->user);
t->id=(ID)pthread_self();
+ t->callback(t->user);
return NULL;
}
@@ -77,6 +81,42 @@ void ThreadPosix::wait_to_finish_func_posix(Thread* p_thread) {
tp->pthread=0;
}
+Error ThreadPosix::set_name(const String& p_name) {
+
+ ERR_FAIL_COND_V(pthread == 0, ERR_UNCONFIGURED);
+
+ #ifdef PTHREAD_NO_RENAME
+ return ERR_UNAVAILABLE;
+
+ #else
+
+ #ifdef PTHREAD_RENAME_SELF
+
+ // check if thread is the same as caller
+ int caller = Thread::get_caller_ID();
+ int self = get_ID();
+ if (caller != self) {
+ ERR_EXPLAIN("On this platform, thread can only be renamed with calls from the threads to be renamed.");
+ ERR_FAIL_V(ERR_UNAVAILABLE);
+ return ERR_UNAVAILABLE;
+ };
+ int err = pthread_setname_np(p_name.utf8().get_data());
+
+ #else
+
+ #ifdef PTHREAD_BSD_SET_NAME
+ pthread_set_name_np(pthread, p_name.utf8().get_data());
+ int err = 0; // Open/FreeBSD ignore errors in this function
+ #else
+ int err = pthread_setname_np(pthread, p_name.utf8().get_data());
+ #endif // PTHREAD_BSD_SET_NAME
+
+ #endif // PTHREAD_RENAME_SELF
+
+ return err == 0 ? OK : ERR_INVALID_PARAMETER;
+
+ #endif // PTHREAD_NO_RENAME
+};
void ThreadPosix::make_default() {
diff --git a/drivers/unix/thread_posix.h b/drivers/unix/thread_posix.h
index 4f76f3d7b3..179d56d5bd 100644
--- a/drivers/unix/thread_posix.h
+++ b/drivers/unix/thread_posix.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -61,6 +61,7 @@ public:
virtual ID get_ID() const;
+ Error set_name(const String& p_name);
static void make_default();
diff --git a/drivers/vorbis/SCsub b/drivers/vorbis/SCsub
index 2c137629ac..87805cc2d8 100644
--- a/drivers/vorbis/SCsub
+++ b/drivers/vorbis/SCsub
@@ -1,4 +1,3 @@
-
Import('env')
sources = [
@@ -34,7 +33,4 @@ sources_lib = [
]
env.drivers_sources += sources
-
-if env['theora'] != "yes" or env['use_theoraplayer_binary'] != "yes":
- env.drivers_sources += sources_lib
-
+env.drivers_sources += sources_lib
diff --git a/drivers/vorbis/audio_stream_ogg_vorbis.cpp b/drivers/vorbis/audio_stream_ogg_vorbis.cpp
index ed292621e9..4ce7940a01 100644
--- a/drivers/vorbis/audio_stream_ogg_vorbis.cpp
+++ b/drivers/vorbis/audio_stream_ogg_vorbis.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,7 +30,7 @@
-size_t AudioStreamOGGVorbis::_ov_read_func(void *p_dst,size_t p_data, size_t p_count, void *_f) {
+size_t AudioStreamPlaybackOGGVorbis::_ov_read_func(void *p_dst,size_t p_data, size_t p_count, void *_f) {
//printf("read to %p, %i bytes, %i nmemb, %p\n",p_dst,p_data,p_count,_f);
FileAccess *fa=(FileAccess*)_f;
@@ -46,7 +46,7 @@ size_t AudioStreamOGGVorbis::_ov_read_func(void *p_dst,size_t p_data, size_t p_c
return read;
}
-int AudioStreamOGGVorbis::_ov_seek_func(void *_f,ogg_int64_t offs, int whence) {
+int AudioStreamPlaybackOGGVorbis::_ov_seek_func(void *_f,ogg_int64_t offs, int whence) {
//printf("seek to %p, offs %i, whence %i\n",_f,(int)offs,whence);
@@ -76,7 +76,7 @@ int AudioStreamOGGVorbis::_ov_seek_func(void *_f,ogg_int64_t offs, int whence) {
#endif
}
-int AudioStreamOGGVorbis::_ov_close_func(void *_f) {
+int AudioStreamPlaybackOGGVorbis::_ov_close_func(void *_f) {
// printf("close %p\n",_f);
if (!_f)
@@ -86,7 +86,7 @@ int AudioStreamOGGVorbis::_ov_close_func(void *_f) {
fa->close();
return 0;
}
-long AudioStreamOGGVorbis::_ov_tell_func(void *_f) {
+long AudioStreamPlaybackOGGVorbis::_ov_tell_func(void *_f) {
//printf("close %p\n",_f);
@@ -95,38 +95,32 @@ long AudioStreamOGGVorbis::_ov_tell_func(void *_f) {
}
-bool AudioStreamOGGVorbis::_can_mix() const {
- return /*playing &&*/ !paused;
-}
-
-
-void AudioStreamOGGVorbis::update() {
+int AudioStreamPlaybackOGGVorbis::mix(int16_t* p_bufer,int p_frames) {
- _THREAD_SAFE_METHOD_
-
- if (!playing && !setting_up)
- return;
+ if (!playing)
+ return 0;
+ int total=p_frames;
while (true) {
- int todo = get_todo();
+ int todo = p_frames;
- if (todo==0 || todo<MIN_MIX)
+ if (todo==0 || todo<MIN_MIX) {
break;
+ }
//printf("to mix %i - mix me %i bytes\n",to_mix,to_mix*stream_channels*sizeof(int16_t));
#ifdef BIG_ENDIAN_ENABLED
- long ret=ov_read(&vf,(char*)get_write_buffer(),todo*stream_channels*sizeof(int16_t), 1, 2, 1, &current_section);
+ long ret=ov_read(&vf,(char*)p_bufer,todo*stream_channels*sizeof(int16_t), 1, 2, 1, &current_section);
#else
- long ret=ov_read(&vf,(char*)get_write_buffer(),todo*stream_channels*sizeof(int16_t), 0, 2, 1, &current_section);
+ long ret=ov_read(&vf,(char*)p_bufer,todo*stream_channels*sizeof(int16_t), 0, 2, 1, &current_section);
#endif
+
if (ret<0) {
playing = false;
- setting_up=false;
-
ERR_EXPLAIN("Error reading OGG Vorbis File: "+file);
ERR_BREAK(ret<0);
} else if (ret==0) { // end of song, reload?
@@ -138,9 +132,8 @@ void AudioStreamOGGVorbis::update() {
if (!has_loop()) {
playing=false;
- setting_up=false;
repeats=1;
- return;
+ break;
}
f=FileAccess::open(file,FileAccess::READ);
@@ -148,11 +141,22 @@ void AudioStreamOGGVorbis::update() {
int errv = ov_open_callbacks(f,&vf,NULL,0,_ov_callbacks);
if (errv!=0) {
playing=false;
- setting_up=false;
- return; // :(
+ break;; // :(
}
- frames_mixed=0;
+ if (loop_restart_time) {
+ bool ok = ov_time_seek(&vf,loop_restart_time)==0;
+ if (!ok) {
+ playing=false;
+ //ERR_EXPLAIN("loop restart time rejected");
+ ERR_PRINT("loop restart time rejected")
+ }
+
+ frames_mixed=stream_srate*loop_restart_time;
+ } else {
+
+ frames_mixed=0;
+ }
repeats++;
continue;
@@ -162,16 +166,19 @@ void AudioStreamOGGVorbis::update() {
ret/=sizeof(int16_t);
frames_mixed+=ret;
- write(ret);
+
+ p_bufer+=ret*stream_channels;
+ p_frames-=ret;
+
}
-}
+ return total-p_frames;
+}
-void AudioStreamOGGVorbis::play() {
- _THREAD_SAFE_METHOD_
+void AudioStreamPlaybackOGGVorbis::play(float p_from) {
if (playing)
stop();
@@ -179,143 +186,154 @@ void AudioStreamOGGVorbis::play() {
if (_load_stream()!=OK)
return;
+
frames_mixed=0;
- playing=false;
- setting_up=true;
- update();
- if (!setting_up)
- return;
- setting_up=false;
playing=true;
+ if (p_from>0) {
+ seek_pos(p_from);
+ }
}
-void AudioStreamOGGVorbis::_close_file() {
+void AudioStreamPlaybackOGGVorbis::_close_file() {
if (f) {
+
memdelete(f);
f=NULL;
}
}
-void AudioStreamOGGVorbis::stop() {
-
- _THREAD_SAFE_METHOD_
+bool AudioStreamPlaybackOGGVorbis::is_playing() const {
+ return playing;
+}
+void AudioStreamPlaybackOGGVorbis::stop() {
_clear_stream();
playing=false;
- _clear();
-}
-
-AudioStreamOGGVorbis::UpdateMode AudioStreamOGGVorbis::get_update_mode() const {
-
- return UPDATE_THREAD;
+ //_clear();
}
-bool AudioStreamOGGVorbis::is_playing() const {
-
- return playing || (get_total() - get_todo() -1 > 0);
-}
+float AudioStreamPlaybackOGGVorbis::get_pos() const {
-float AudioStreamOGGVorbis::get_pos() const {
-
- int32_t frames = int32_t(frames_mixed) - (int32_t(get_total()) - get_todo());
+ int32_t frames = int32_t(frames_mixed);
if (frames < 0)
frames=0;
return double(frames) / stream_srate;
}
-void AudioStreamOGGVorbis::seek_pos(float p_time) {
+void AudioStreamPlaybackOGGVorbis::seek_pos(float p_time) {
+
- _THREAD_SAFE_METHOD_
if (!playing)
return;
- bool ok = ov_time_seek(&vf,p_time*1000)==0;
+ bool ok = ov_time_seek(&vf,p_time)==0;
ERR_FAIL_COND(!ok);
frames_mixed=stream_srate*p_time;
}
-String AudioStreamOGGVorbis::get_stream_name() const {
+String AudioStreamPlaybackOGGVorbis::get_stream_name() const {
return "";
}
-void AudioStreamOGGVorbis::set_loop(bool p_enable) {
+void AudioStreamPlaybackOGGVorbis::set_loop(bool p_enable) {
loops=p_enable;
}
-bool AudioStreamOGGVorbis::has_loop() const {
+bool AudioStreamPlaybackOGGVorbis::has_loop() const {
return loops;
}
-int AudioStreamOGGVorbis::get_loop_count() const {
+int AudioStreamPlaybackOGGVorbis::get_loop_count() const {
return repeats;
}
-void AudioStreamOGGVorbis::set_file(const String& p_file) {
+Error AudioStreamPlaybackOGGVorbis::set_file(const String& p_file) {
file=p_file;
-}
-
-Error AudioStreamOGGVorbis::_load_stream() {
-
- _clear_stream();
- if (file=="")
- return ERR_INVALID_DATA;
-
+ stream_valid=false;
Error err;
f=FileAccess::open(file,FileAccess::READ,&err);
-
if (err) {
ERR_FAIL_COND_V( err, err );
}
int errv = ov_open_callbacks(f,&vf,NULL,0,_ov_callbacks);
+ switch(errv) {
-
+ case OV_EREAD: { // - A read from media returned an error.
+ memdelete(f); f=NULL;
+ ERR_FAIL_V( ERR_FILE_CANT_READ );
+ } break;
+ case OV_EVERSION: // - Vorbis version mismatch.
+ case OV_ENOTVORBIS: { // - Bitstream is not Vorbis data.
+ memdelete(f); f=NULL;
+ ERR_FAIL_V( ERR_FILE_UNRECOGNIZED );
+ } break;
+ case OV_EBADHEADER: { // - Invalid Vorbis bitstream header.
+ memdelete(f); f=NULL;
+ ERR_FAIL_V( ERR_FILE_CORRUPT );
+ } break;
+ case OV_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption.
+ memdelete(f); f=NULL;
+ ERR_FAIL_V( ERR_BUG );
+ } break;
+ }
const vorbis_info *vinfo=ov_info(&vf,-1);
stream_channels=vinfo->channels;
stream_srate=vinfo->rate;
- Error serr = _setup(stream_channels,stream_srate);
+ length = ov_time_total(&vf,-1);
+ ov_clear(&vf);
+ memdelete(f);
+ f=NULL;
+ stream_valid=true;
+
+
+ return OK;
+}
+
+Error AudioStreamPlaybackOGGVorbis::_load_stream() {
- if (serr) {
- _close_file();
- ERR_FAIL_V( ERR_INVALID_DATA );
+ ERR_FAIL_COND_V(!stream_valid,ERR_UNCONFIGURED);
+
+ _clear_stream();
+ if (file=="")
+ return ERR_INVALID_DATA;
+
+ Error err;
+ f=FileAccess::open(file,FileAccess::READ,&err);
+ if (err) {
+ ERR_FAIL_COND_V( err, err );
}
+ int errv = ov_open_callbacks(f,&vf,NULL,0,_ov_callbacks);
switch(errv) {
case OV_EREAD: { // - A read from media returned an error.
- _close_file();
+ memdelete(f); f=NULL;
ERR_FAIL_V( ERR_FILE_CANT_READ );
} break;
case OV_EVERSION: // - Vorbis version mismatch.
case OV_ENOTVORBIS: { // - Bitstream is not Vorbis data.
- _close_file();
+ memdelete(f); f=NULL;
ERR_FAIL_V( ERR_FILE_UNRECOGNIZED );
} break;
case OV_EBADHEADER: { // - Invalid Vorbis bitstream header.
- _close_file();
+ memdelete(f); f=NULL;
ERR_FAIL_V( ERR_FILE_CORRUPT );
} break;
case OV_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption.
-
- _close_file();
+ memdelete(f); f=NULL;
ERR_FAIL_V( ERR_BUG );
} break;
}
-
-
- ogg_int64_t len = ov_time_total(&vf,-1);
-
- length=len/1000.0;
-
repeats=0;
stream_loaded=true;
@@ -324,16 +342,16 @@ Error AudioStreamOGGVorbis::_load_stream() {
}
-float AudioStreamOGGVorbis::get_length() const {
+float AudioStreamPlaybackOGGVorbis::get_length() const {
if (!stream_loaded) {
- if (const_cast<AudioStreamOGGVorbis*>(this)->_load_stream()!=OK)
+ if (const_cast<AudioStreamPlaybackOGGVorbis*>(this)->_load_stream()!=OK)
return 0;
}
return length;
}
-void AudioStreamOGGVorbis::_clear_stream() {
+void AudioStreamPlaybackOGGVorbis::_clear_stream() {
if (!stream_loaded)
return;
@@ -342,22 +360,22 @@ void AudioStreamOGGVorbis::_clear_stream() {
_close_file();
stream_loaded=false;
- stream_channels=1;
+ //stream_channels=1;
playing=false;
}
-void AudioStreamOGGVorbis::set_paused(bool p_paused) {
+void AudioStreamPlaybackOGGVorbis::set_paused(bool p_paused) {
paused=p_paused;
}
-bool AudioStreamOGGVorbis::is_paused(bool p_paused) const {
+bool AudioStreamPlaybackOGGVorbis::is_paused(bool p_paused) const {
return paused;
}
-AudioStreamOGGVorbis::AudioStreamOGGVorbis() {
+AudioStreamPlaybackOGGVorbis::AudioStreamPlaybackOGGVorbis() {
loops=false;
playing=false;
@@ -367,17 +385,18 @@ AudioStreamOGGVorbis::AudioStreamOGGVorbis() {
_ov_callbacks.tell_func=_ov_tell_func;
f = NULL;
stream_loaded=false;
- repeats=0;
- setting_up=false;
+ stream_valid=false;
+ repeats=0;
paused=true;
stream_channels=0;
stream_srate=0;
current_section=0;
length=0;
+ loop_restart_time=0;
}
-AudioStreamOGGVorbis::~AudioStreamOGGVorbis() {
+AudioStreamPlaybackOGGVorbis::~AudioStreamPlaybackOGGVorbis() {
_clear_stream();
@@ -385,7 +404,9 @@ AudioStreamOGGVorbis::~AudioStreamOGGVorbis() {
-RES ResourceFormatLoaderAudioStreamOGGVorbis::load(const String &p_path,const String& p_original_path) {
+RES ResourceFormatLoaderAudioStreamOGGVorbis::load(const String &p_path, const String& p_original_path, Error *r_error) {
+ if (r_error)
+ *r_error=OK;
AudioStreamOGGVorbis *ogg_stream = memnew(AudioStreamOGGVorbis);
ogg_stream->set_file(p_path);
diff --git a/drivers/vorbis/audio_stream_ogg_vorbis.h b/drivers/vorbis/audio_stream_ogg_vorbis.h
index 8a35fc09cb..bb4d521c1e 100644
--- a/drivers/vorbis/audio_stream_ogg_vorbis.h
+++ b/drivers/vorbis/audio_stream_ogg_vorbis.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,17 +29,16 @@
#ifndef AUDIO_STREAM_OGG_VORBIS_H
#define AUDIO_STREAM_OGG_VORBIS_H
-#include "scene/resources/audio_stream_resampled.h"
+#include "scene/resources/audio_stream.h"
#include "vorbis/vorbisfile.h"
#include "os/file_access.h"
#include "io/resource_loader.h"
#include "os/thread_safe.h"
-class AudioStreamOGGVorbis : public AudioStreamResampled {
- OBJ_TYPE(AudioStreamOGGVorbis,AudioStreamResampled);
- _THREAD_SAFE_CLASS_
+class AudioStreamPlaybackOGGVorbis : public AudioStreamPlayback {
+ OBJ_TYPE(AudioStreamPlaybackOGGVorbis,AudioStreamPlayback);
enum {
MIN_MIX=1024
@@ -54,9 +53,6 @@ class AudioStreamOGGVorbis : public AudioStreamResampled {
static int _ov_close_func(void *_f);
static long _ov_tell_func(void *_f);
-
- virtual bool _can_mix() const;
-
String file;
int64_t frames_mixed;
@@ -67,7 +63,7 @@ class AudioStreamOGGVorbis : public AudioStreamResampled {
int stream_srate;
int current_section;
- volatile bool setting_up;
+
bool paused;
bool loops;
int repeats;
@@ -76,17 +72,21 @@ class AudioStreamOGGVorbis : public AudioStreamResampled {
void _clear_stream();
void _close_file();
+ bool stream_valid;
+ float loop_restart_time;
-public:
+public:
- void set_file(const String& p_file);
+ Error set_file(const String& p_file);
- virtual void play();
+ virtual void play(float p_from=0);
virtual void stop();
virtual bool is_playing() const;
+ virtual void set_loop_restart_time(float p_time) { loop_restart_time=p_time; }
+
virtual void set_paused(bool p_paused);
virtual bool is_paused(bool p_paused) const;
@@ -102,16 +102,37 @@ public:
virtual float get_pos() const;
virtual void seek_pos(float p_time);
- virtual UpdateMode get_update_mode() const;
- virtual void update();
+ virtual int get_channels() const { return stream_channels; }
+ virtual int get_mix_rate() const { return stream_srate; }
+
+ virtual int get_minimum_buffer_size() const { return 0; }
+ virtual int mix(int16_t* p_bufer,int p_frames);
+
+ AudioStreamPlaybackOGGVorbis();
+ ~AudioStreamPlaybackOGGVorbis();
+};
+
+
+class AudioStreamOGGVorbis : public AudioStream {
+
+ OBJ_TYPE(AudioStreamOGGVorbis,AudioStream);
+
+ String file;
+public:
+
+ Ref<AudioStreamPlayback> instance_playback() {
+ Ref<AudioStreamPlaybackOGGVorbis> pb = memnew( AudioStreamPlaybackOGGVorbis );
+ pb->set_file(file);
+ return pb;
+ }
+
+ void set_file(const String& p_file) { file=p_file; }
- AudioStreamOGGVorbis();
- ~AudioStreamOGGVorbis();
};
class ResourceFormatLoaderAudioStreamOGGVorbis : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path,const String& p_original_path="");
+ virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String& p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/drivers/webp/SCsub b/drivers/webp/SCsub
index 3ae046ff79..f65bd13dba 100644
--- a/drivers/webp/SCsub
+++ b/drivers/webp/SCsub
@@ -1,64 +1,115 @@
Import('env')
-
webp_sources = [
- "webp/mux/muxedit.c",
- "webp/mux/muxread.c",
- "webp/mux/muxinternal.c",
- "webp/mux/demux.c",
- "webp/enc/tree.c",
- "webp/enc/analysis.c",
- "webp/enc/backward_references.c",
- "webp/enc/alpha.c",
- "webp/enc/picture.c",
- "webp/enc/frame.c",
- "webp/enc/webpenc.c",
- "webp/enc/cost.c",
- "webp/enc/filter.c",
- "webp/enc/vp8l.c",
- "webp/enc/quant.c",
- "webp/enc/histogram.c",
- "webp/enc/syntax.c",
- "webp/enc/config.c",
- "webp/enc/layer.c",
- "webp/enc/iterator.c",
- "webp/dsp/dec_sse2.c",
- "webp/dsp/upsampling_sse2.c",
- "webp/dsp/dec_neon.c",
- "webp/dsp/enc.c",
- "webp/dsp/enc_sse2.c",
- "webp/dsp/upsampling.c",
- "webp/dsp/lossless.c",
- "webp/dsp/cpu.c",
- "webp/dsp/dec.c",
- "webp/dsp/yuv.c",
- "webp/utils/bit_reader.c",
- "webp/utils/filters.c",
- "webp/utils/bit_writer.c",
- "webp/utils/thread.c",
- "webp/utils/quant_levels.c",
- "webp/utils/color_cache.c",
- "webp/utils/rescaler.c",
- "webp/utils/utils.c",
- "webp/utils/huffman.c",
- "webp/utils/huffman_encode.c",
- "webp/dec/tree.c",
- "webp/dec/alpha.c",
- "webp/dec/frame.c",
- "webp/dec/vp8l.c",
- "webp/dec/vp8.c",
- "webp/dec/quant.c",
- "webp/dec/webp.c",
- "webp/dec/buffer.c",
- "webp/dec/io.c",
- "webp/dec/layer.c",
- "webp/dec/idec.c",
- "webp/image_loader_webp.cpp"
+"webp/enc/webpenc.c",\
+"webp/enc/near_lossless.c",\
+"webp/enc/frame.c",\
+"webp/enc/alpha.c",\
+"webp/enc/picture_csp.c",\
+"webp/enc/vp8l.c",\
+"webp/enc/picture_psnr.c",\
+"webp/enc/delta_palettization.c",\
+"webp/enc/syntax.c",\
+"webp/enc/backward_references.c",\
+"webp/enc/token.c",\
+"webp/enc/analysis.c",\
+"webp/enc/iterator.c",\
+"webp/enc/picture_tools.c",\
+"webp/enc/picture_rescale.c",\
+"webp/enc/config.c",\
+"webp/enc/tree.c",\
+"webp/enc/cost.c",\
+"webp/enc/picture.c",\
+"webp/enc/quant.c",\
+"webp/enc/filter.c",\
+"webp/enc/histogram.c",\
+"webp/image_loader_webp.cpp",\
+"webp/utils/rescaler.c",\
+"webp/utils/filters.c",\
+"webp/utils/quant_levels_dec.c",\
+"webp/utils/huffman.c",\
+"webp/utils/thread.c",\
+"webp/utils/quant_levels.c",\
+"webp/utils/bit_writer.c",\
+"webp/utils/bit_reader.c",\
+"webp/utils/random.c",\
+"webp/utils/utils.c",\
+"webp/utils/huffman_encode.c",\
+"webp/utils/color_cache.c",\
+"webp/mux/muxinternal.c",\
+"webp/mux/muxread.c",\
+"webp/mux/anim_encode.c",\
+"webp/mux/muxedit.c",\
+"webp/dec/webp.c",\
+"webp/dec/frame.c",\
+"webp/dec/alpha.c",\
+"webp/dec/vp8l.c",\
+"webp/dec/io.c",\
+"webp/dec/vp8.c",\
+"webp/dec/idec.c",\
+"webp/dec/tree.c",\
+"webp/dec/buffer.c",\
+"webp/dec/quant.c",\
+"webp/demux/demux.c",\
+"webp/demux/anim_decode.c",\
+"webp/dsp/yuv.c",\
+"webp/dsp/filters_sse2.c",\
+"webp/dsp/dec_sse41.c",\
+"webp/dsp/rescaler.c",\
+"webp/dsp/lossless_sse2.c",\
+"webp/dsp/alpha_processing_sse41.c",\
+"webp/dsp/alpha_processing_sse2.c",\
+"webp/dsp/filters.c",\
+"webp/dsp/upsampling_mips_dsp_r2.c",\
+"webp/dsp/dec_neon.c",\
+"webp/dsp/enc_neon.c",\
+"webp/dsp/lossless_enc_mips32.c",\
+"webp/dsp/lossless_enc_sse2.c",\
+"webp/dsp/upsampling.c",\
+"webp/dsp/lossless_enc_neon.c",\
+"webp/dsp/alpha_processing.c",\
+"webp/dsp/cost_sse2.c",\
+"webp/dsp/dec_mips32.c",\
+"webp/dsp/enc_avx2.c",\
+"webp/dsp/rescaler_mips32.c",\
+"webp/dsp/enc.c",\
+"webp/dsp/lossless_enc_sse41.c",\
+"webp/dsp/cost_mips32.c",\
+"webp/dsp/lossless_mips_dsp_r2.c",\
+"webp/dsp/filters_mips_dsp_r2.c",\
+"webp/dsp/upsampling_neon.c",\
+"webp/dsp/alpha_processing_mips_dsp_r2.c",\
+"webp/dsp/enc_mips_dsp_r2.c",\
+"webp/dsp/lossless.c",\
+"webp/dsp/yuv_mips_dsp_r2.c",\
+"webp/dsp/cost_mips_dsp_r2.c",\
+"webp/dsp/argb.c",\
+"webp/dsp/dec_sse2.c",\
+"webp/dsp/rescaler_sse2.c",\
+"webp/dsp/enc_sse41.c",\
+"webp/dsp/argb_mips_dsp_r2.c",\
+"webp/dsp/lossless_enc_mips_dsp_r2.c",\
+"webp/dsp/dec_clip_tables.c",\
+"webp/dsp/yuv_mips32.c",\
+"webp/dsp/cpu.c",\
+"webp/dsp/dec.c",\
+"webp/dsp/argb_sse2.c",\
+"webp/dsp/lossless_neon.c",\
+"webp/dsp/lossless_enc.c",\
+"webp/dsp/enc_mips32.c",\
+"webp/dsp/cost.c",\
+"webp/dsp/rescaler_mips_dsp_r2.c",\
+"webp/dsp/dec_mips_dsp_r2.c",\
+"webp/dsp/rescaler_neon.c",\
+"webp/dsp/yuv_sse2.c",\
+"webp/dsp/enc_sse2.c",\
+"webp/dsp/upsampling_sse2.c"
]
env.drivers_sources+=webp_sources
#env.add_source_files(env.drivers_sources, webp_sources)
+
Export('env')
diff --git a/drivers/webp/config.h b/drivers/webp/config.h
new file mode 100644
index 0000000000..d85e5d1da6
--- /dev/null
+++ b/drivers/webp/config.h
@@ -0,0 +1,145 @@
+/* src/webp/config.h. Generated from config.h.in by configure. */
+/* src/webp/config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define if building universal (internal helper macro) */
+/* #undef AC_APPLE_UNIVERSAL_BUILD */
+
+/* Set to 1 if __builtin_bswap16 is available */
+#define HAVE_BUILTIN_BSWAP16 1
+
+/* Set to 1 if __builtin_bswap32 is available */
+#define HAVE_BUILTIN_BSWAP32 1
+
+/* Set to 1 if __builtin_bswap64 is available */
+#define HAVE_BUILTIN_BSWAP64 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <GLUT/glut.h> header file. */
+/* #undef HAVE_GLUT_GLUT_H */
+
+/* Define to 1 if you have the <GL/glut.h> header file. */
+#define HAVE_GL_GLUT_H 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <OpenGL/glut.h> header file. */
+/* #undef HAVE_OPENGL_GLUT_H */
+
+/* Have PTHREAD_PRIO_INHERIT. */
+#define HAVE_PTHREAD_PRIO_INHERIT 1
+
+/* Define to 1 if you have the <shlwapi.h> header file. */
+/* #undef HAVE_SHLWAPI_H */
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the <wincodec.h> header file. */
+/* #undef HAVE_WINCODEC_H */
+
+/* Define to 1 if you have the <windows.h> header file. */
+/* #undef HAVE_WINDOWS_H */
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#define LT_OBJDIR ".libs/"
+
+/* Name of package */
+#define PACKAGE "libwebp"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "http://code.google.com/p/webp/issues"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "libwebp"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "libwebp 0.4.4"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "libwebp"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL "http://developers.google.com/speed/webp"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "0.4.4"
+
+/* Define to necessary symbol if this constant uses a non-standard name on
+ your system. */
+/* #undef PTHREAD_CREATE_JOINABLE */
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Version number of package */
+#define VERSION "0.4.4"
+
+/* Enable experimental code */
+/* #undef WEBP_EXPERIMENTAL_FEATURES */
+
+/* Define to 1 to force aligned memory operations */
+/* #undef WEBP_FORCE_ALIGNED */
+
+/* Set to 1 if AVX2 is supported */
+#define WEBP_HAVE_AVX2 1
+
+/* Set to 1 if GIF library is installed */
+/* #undef WEBP_HAVE_GIF */
+
+/* Set to 1 if OpenGL is supported */
+#define WEBP_HAVE_GL 1
+
+/* Set to 1 if JPEG library is installed */
+/* #undef WEBP_HAVE_JPEG */
+
+/* Set to 1 if PNG library is installed */
+#define WEBP_HAVE_PNG 1
+
+/* Set to 1 if SSE2 is supported */
+#define WEBP_HAVE_SSE2 1
+
+/* Set to 1 if SSE4.1 is supported */
+#define WEBP_HAVE_SSE41 1
+
+/* Set to 1 if TIFF library is installed */
+/* #undef WEBP_HAVE_TIFF */
+
+/* Undefine this to disable thread support. */
+#define WEBP_USE_THREAD 1
+
+/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
+ significant byte first (like Motorola and SPARC, unlike Intel). */
+#if defined AC_APPLE_UNIVERSAL_BUILD
+# if defined __BIG_ENDIAN__
+# define WORDS_BIGENDIAN 1
+# endif
+#else
+# ifndef WORDS_BIGENDIAN
+/* # undef WORDS_BIGENDIAN */
+# endif
+#endif
diff --git a/drivers/webp/dec/alpha.c b/drivers/webp/dec/alpha.c
index d1095fa555..1d029b0e6a 100644
--- a/drivers/webp/dec/alpha.c
+++ b/drivers/webp/dec/alpha.c
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Alpha-plane decompression.
@@ -10,131 +12,156 @@
// Author: Skal (pascal.massimino@gmail.com)
#include <stdlib.h>
+#include "./alphai.h"
#include "./vp8i.h"
#include "./vp8li.h"
-#include "../utils/filters.h"
-#include "../utils/quant_levels.h"
-#include "../format_constants.h"
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-// TODO(skal): move to dsp/ ?
-static void CopyPlane(const uint8_t* src, int src_stride,
- uint8_t* dst, int dst_stride, int width, int height) {
- while (height-- > 0) {
- memcpy(dst, src, width);
- src += src_stride;
- dst += dst_stride;
+#include "../dsp/dsp.h"
+#include "../utils/quant_levels_dec.h"
+#include "../utils/utils.h"
+#include "webp/format_constants.h"
+
+//------------------------------------------------------------------------------
+// ALPHDecoder object.
+
+ALPHDecoder* ALPHNew(void) {
+ ALPHDecoder* const dec = (ALPHDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
+ return dec;
+}
+
+void ALPHDelete(ALPHDecoder* const dec) {
+ if (dec != NULL) {
+ VP8LDelete(dec->vp8l_dec_);
+ dec->vp8l_dec_ = NULL;
+ WebPSafeFree(dec);
}
}
//------------------------------------------------------------------------------
-// Decodes the compressed data 'data' of size 'data_size' into the 'output'.
-// The 'output' buffer should be pre-allocated and must be of the same
-// dimension 'height'x'stride', as that of the image.
-//
-// Returns 1 on successfully decoding the compressed alpha and
-// 0 if either:
-// error in bit-stream header (invalid compression mode or filter), or
-// error returned by appropriate compression method.
-
-static int DecodeAlpha(const uint8_t* data, size_t data_size,
- int width, int height, int stride, uint8_t* output) {
- uint8_t* decoded_data = NULL;
- const size_t decoded_size = height * width;
- uint8_t* unfiltered_data = NULL;
- WEBP_FILTER_TYPE filter;
- int pre_processing;
- int rsrv;
+// Decoding.
+
+// Initialize alpha decoding by parsing the alpha header and decoding the image
+// header for alpha data stored using lossless compression.
+// Returns false in case of error in alpha header (data too short, invalid
+// compression method or filter, error in lossless header data etc).
+static int ALPHInit(ALPHDecoder* const dec, const uint8_t* data,
+ size_t data_size, int width, int height, uint8_t* output) {
int ok = 0;
- int method;
+ const uint8_t* const alpha_data = data + ALPHA_HEADER_LEN;
+ const size_t alpha_data_size = data_size - ALPHA_HEADER_LEN;
+ int rsrv;
- assert(width > 0 && height > 0 && stride >= width);
+ assert(width > 0 && height > 0);
assert(data != NULL && output != NULL);
+ dec->width_ = width;
+ dec->height_ = height;
+
if (data_size <= ALPHA_HEADER_LEN) {
return 0;
}
- method = (data[0] >> 0) & 0x03;
- filter = (data[0] >> 2) & 0x03;
- pre_processing = (data[0] >> 4) & 0x03;
+ dec->method_ = (data[0] >> 0) & 0x03;
+ dec->filter_ = (data[0] >> 2) & 0x03;
+ dec->pre_processing_ = (data[0] >> 4) & 0x03;
rsrv = (data[0] >> 6) & 0x03;
- if (method < ALPHA_NO_COMPRESSION ||
- method > ALPHA_LOSSLESS_COMPRESSION ||
- filter >= WEBP_FILTER_LAST ||
- pre_processing > ALPHA_PREPROCESSED_LEVELS ||
+ if (dec->method_ < ALPHA_NO_COMPRESSION ||
+ dec->method_ > ALPHA_LOSSLESS_COMPRESSION ||
+ dec->filter_ >= WEBP_FILTER_LAST ||
+ dec->pre_processing_ > ALPHA_PREPROCESSED_LEVELS ||
rsrv != 0) {
return 0;
}
- if (method == ALPHA_NO_COMPRESSION) {
- ok = (data_size >= decoded_size);
- decoded_data = (uint8_t*)data + ALPHA_HEADER_LEN;
+ if (dec->method_ == ALPHA_NO_COMPRESSION) {
+ const size_t alpha_decoded_size = dec->width_ * dec->height_;
+ ok = (alpha_data_size >= alpha_decoded_size);
} else {
- decoded_data = (uint8_t*)malloc(decoded_size);
- if (decoded_data == NULL) return 0;
- ok = VP8LDecodeAlphaImageStream(width, height,
- data + ALPHA_HEADER_LEN,
- data_size - ALPHA_HEADER_LEN,
- decoded_data);
+ assert(dec->method_ == ALPHA_LOSSLESS_COMPRESSION);
+ ok = VP8LDecodeAlphaHeader(dec, alpha_data, alpha_data_size, output);
}
+ VP8FiltersInit();
+ return ok;
+}
- if (ok) {
- WebPFilterFunc unfilter_func = WebPUnfilters[filter];
- if (unfilter_func != NULL) {
- unfiltered_data = (uint8_t*)malloc(decoded_size);
- if (unfiltered_data == NULL) {
- ok = 0;
- goto Error;
- }
- // TODO(vikas): Implement on-the-fly decoding & filter mechanism to decode
- // and apply filter per image-row.
- unfilter_func(decoded_data, width, height, 1, width, unfiltered_data);
- // Construct raw_data (height x stride) from alpha data (height x width).
- CopyPlane(unfiltered_data, width, output, stride, width, height);
- free(unfiltered_data);
- } else {
- // Construct raw_data (height x stride) from alpha data (height x width).
- CopyPlane(decoded_data, width, output, stride, width, height);
- }
- if (pre_processing == ALPHA_PREPROCESSED_LEVELS) {
- ok = DequantizeLevels(decoded_data, width, height);
+// Decodes, unfilters and dequantizes *at least* 'num_rows' rows of alpha
+// starting from row number 'row'. It assumes that rows up to (row - 1) have
+// already been decoded.
+// Returns false in case of bitstream error.
+static int ALPHDecode(VP8Decoder* const dec, int row, int num_rows) {
+ ALPHDecoder* const alph_dec = dec->alph_dec_;
+ const int width = alph_dec->width_;
+ const int height = alph_dec->height_;
+ WebPUnfilterFunc unfilter_func = WebPUnfilters[alph_dec->filter_];
+ uint8_t* const output = dec->alpha_plane_;
+ if (alph_dec->method_ == ALPHA_NO_COMPRESSION) {
+ const size_t offset = row * width;
+ const size_t num_pixels = num_rows * width;
+ assert(dec->alpha_data_size_ >= ALPHA_HEADER_LEN + offset + num_pixels);
+ memcpy(dec->alpha_plane_ + offset,
+ dec->alpha_data_ + ALPHA_HEADER_LEN + offset, num_pixels);
+ } else { // alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION
+ assert(alph_dec->vp8l_dec_ != NULL);
+ if (!VP8LDecodeAlphaImageStream(alph_dec, row + num_rows)) {
+ return 0;
}
}
- Error:
- if (method != ALPHA_NO_COMPRESSION) {
- free(decoded_data);
+ if (unfilter_func != NULL) {
+ unfilter_func(width, height, width, row, num_rows, output);
}
- return ok;
+
+ if (row + num_rows == dec->pic_hdr_.height_) {
+ dec->is_alpha_decoded_ = 1;
+ }
+ return 1;
}
//------------------------------------------------------------------------------
+// Main entry point.
const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
int row, int num_rows) {
- const int stride = dec->pic_hdr_.width_;
+ const int width = dec->pic_hdr_.width_;
+ const int height = dec->pic_hdr_.height_;
- if (row < 0 || num_rows < 0 || row + num_rows > dec->pic_hdr_.height_) {
+ if (row < 0 || num_rows <= 0 || row + num_rows > height) {
return NULL; // sanity check.
}
if (row == 0) {
- // Decode everything during the first call.
- if (!DecodeAlpha(dec->alpha_data_, (size_t)dec->alpha_data_size_,
- dec->pic_hdr_.width_, dec->pic_hdr_.height_, stride,
- dec->alpha_plane_)) {
- return NULL; // Error.
+ // Initialize decoding.
+ assert(dec->alpha_plane_ != NULL);
+ dec->alph_dec_ = ALPHNew();
+ if (dec->alph_dec_ == NULL) return NULL;
+ if (!ALPHInit(dec->alph_dec_, dec->alpha_data_, dec->alpha_data_size_,
+ width, height, dec->alpha_plane_)) {
+ ALPHDelete(dec->alph_dec_);
+ dec->alph_dec_ = NULL;
+ return NULL;
+ }
+ // if we allowed use of alpha dithering, check whether it's needed at all
+ if (dec->alph_dec_->pre_processing_ != ALPHA_PREPROCESSED_LEVELS) {
+ dec->alpha_dithering_ = 0; // disable dithering
+ } else {
+ num_rows = height; // decode everything in one pass
}
}
+ if (!dec->is_alpha_decoded_) {
+ int ok = 0;
+ assert(dec->alph_dec_ != NULL);
+ ok = ALPHDecode(dec, row, num_rows);
+ if (ok && dec->alpha_dithering_ > 0) {
+ ok = WebPDequantizeLevels(dec->alpha_plane_, width, height,
+ dec->alpha_dithering_);
+ }
+ if (!ok || dec->is_alpha_decoded_) {
+ ALPHDelete(dec->alph_dec_);
+ dec->alph_dec_ = NULL;
+ }
+ if (!ok) return NULL; // Error.
+ }
+
// Return a pointer to the current decoded row.
- return dec->alpha_plane_ + row * stride;
+ return dec->alpha_plane_ + row * width;
}
-
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/dec/alphai.h b/drivers/webp/dec/alphai.h
new file mode 100644
index 0000000000..5fa230ca82
--- /dev/null
+++ b/drivers/webp/dec/alphai.h
@@ -0,0 +1,55 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Alpha decoder: internal header.
+//
+// Author: Urvang (urvang@google.com)
+
+#ifndef WEBP_DEC_ALPHAI_H_
+#define WEBP_DEC_ALPHAI_H_
+
+#include "./webpi.h"
+#include "../utils/filters.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct VP8LDecoder; // Defined in dec/vp8li.h.
+
+typedef struct ALPHDecoder ALPHDecoder;
+struct ALPHDecoder {
+ int width_;
+ int height_;
+ int method_;
+ WEBP_FILTER_TYPE filter_;
+ int pre_processing_;
+ struct VP8LDecoder* vp8l_dec_;
+ VP8Io io_;
+ int use_8b_decode; // Although alpha channel requires only 1 byte per
+ // pixel, sometimes VP8LDecoder may need to allocate
+ // 4 bytes per pixel internally during decode.
+};
+
+//------------------------------------------------------------------------------
+// internal functions. Not public.
+
+// Allocates a new alpha decoder instance.
+ALPHDecoder* ALPHNew(void);
+
+// Clears and deallocates an alpha decoder instance.
+void ALPHDelete(ALPHDecoder* const dec);
+
+//------------------------------------------------------------------------------
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* WEBP_DEC_ALPHAI_H_ */
diff --git a/drivers/webp/dec/buffer.c b/drivers/webp/dec/buffer.c
index c159f6f248..9ed2b3fe1a 100644
--- a/drivers/webp/dec/buffer.c
+++ b/drivers/webp/dec/buffer.c
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Everything about WebPDecBuffer
@@ -15,10 +17,6 @@
#include "./webpi.h"
#include "../utils/utils.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
//------------------------------------------------------------------------------
// WebPDecBuffer
@@ -35,6 +33,11 @@ static int IsValidColorspace(int webp_csp_mode) {
return (webp_csp_mode >= MODE_RGB && webp_csp_mode < MODE_LAST);
}
+// strictly speaking, the very last (or first, if flipped) row
+// doesn't require padding.
+#define MIN_BUFFER_SIZE(WIDTH, HEIGHT, STRIDE) \
+ (uint64_t)(STRIDE) * ((HEIGHT) - 1) + (WIDTH)
+
static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
int ok = 1;
const WEBP_CSP_MODE mode = buffer->colorspace;
@@ -44,33 +47,41 @@ static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
ok = 0;
} else if (!WebPIsRGBMode(mode)) { // YUV checks
const WebPYUVABuffer* const buf = &buffer->u.YUVA;
- const uint64_t y_size = (uint64_t)buf->y_stride * height;
- const uint64_t u_size = (uint64_t)buf->u_stride * ((height + 1) / 2);
- const uint64_t v_size = (uint64_t)buf->v_stride * ((height + 1) / 2);
- const uint64_t a_size = (uint64_t)buf->a_stride * height;
+ const int uv_width = (width + 1) / 2;
+ const int uv_height = (height + 1) / 2;
+ const int y_stride = abs(buf->y_stride);
+ const int u_stride = abs(buf->u_stride);
+ const int v_stride = abs(buf->v_stride);
+ const int a_stride = abs(buf->a_stride);
+ const uint64_t y_size = MIN_BUFFER_SIZE(width, height, y_stride);
+ const uint64_t u_size = MIN_BUFFER_SIZE(uv_width, uv_height, u_stride);
+ const uint64_t v_size = MIN_BUFFER_SIZE(uv_width, uv_height, v_stride);
+ const uint64_t a_size = MIN_BUFFER_SIZE(width, height, a_stride);
ok &= (y_size <= buf->y_size);
ok &= (u_size <= buf->u_size);
ok &= (v_size <= buf->v_size);
- ok &= (buf->y_stride >= width);
- ok &= (buf->u_stride >= (width + 1) / 2);
- ok &= (buf->v_stride >= (width + 1) / 2);
+ ok &= (y_stride >= width);
+ ok &= (u_stride >= uv_width);
+ ok &= (v_stride >= uv_width);
ok &= (buf->y != NULL);
ok &= (buf->u != NULL);
ok &= (buf->v != NULL);
if (mode == MODE_YUVA) {
- ok &= (buf->a_stride >= width);
+ ok &= (a_stride >= width);
ok &= (a_size <= buf->a_size);
ok &= (buf->a != NULL);
}
} else { // RGB checks
const WebPRGBABuffer* const buf = &buffer->u.RGBA;
- const uint64_t size = (uint64_t)buf->stride * height;
+ const int stride = abs(buf->stride);
+ const uint64_t size = MIN_BUFFER_SIZE(width, height, stride);
ok &= (size <= buf->size);
- ok &= (buf->stride >= width * kModeBpp[mode]);
+ ok &= (stride >= width * kModeBpp[mode]);
ok &= (buf->rgba != NULL);
}
return ok ? VP8_STATUS_OK : VP8_STATUS_INVALID_PARAM;
}
+#undef MIN_BUFFER_SIZE
static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {
const int w = buffer->width;
@@ -133,9 +144,35 @@ static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {
return CheckDecBuffer(buffer);
}
+VP8StatusCode WebPFlipBuffer(WebPDecBuffer* const buffer) {
+ if (buffer == NULL) {
+ return VP8_STATUS_INVALID_PARAM;
+ }
+ if (WebPIsRGBMode(buffer->colorspace)) {
+ WebPRGBABuffer* const buf = &buffer->u.RGBA;
+ buf->rgba += (buffer->height - 1) * buf->stride;
+ buf->stride = -buf->stride;
+ } else {
+ WebPYUVABuffer* const buf = &buffer->u.YUVA;
+ const int H = buffer->height;
+ buf->y += (H - 1) * buf->y_stride;
+ buf->y_stride = -buf->y_stride;
+ buf->u += ((H - 1) >> 1) * buf->u_stride;
+ buf->u_stride = -buf->u_stride;
+ buf->v += ((H - 1) >> 1) * buf->v_stride;
+ buf->v_stride = -buf->v_stride;
+ if (buf->a != NULL) {
+ buf->a += (H - 1) * buf->a_stride;
+ buf->a_stride = -buf->a_stride;
+ }
+ }
+ return VP8_STATUS_OK;
+}
+
VP8StatusCode WebPAllocateDecBuffer(int w, int h,
const WebPDecoderOptions* const options,
WebPDecBuffer* const out) {
+ VP8StatusCode status;
if (out == NULL || w <= 0 || h <= 0) {
return VP8_STATUS_INVALID_PARAM;
}
@@ -152,18 +189,28 @@ VP8StatusCode WebPAllocateDecBuffer(int w, int h,
h = ch;
}
if (options->use_scaling) {
- if (options->scaled_width <= 0 || options->scaled_height <= 0) {
+ int scaled_width = options->scaled_width;
+ int scaled_height = options->scaled_height;
+ if (!WebPRescalerGetScaledDimensions(
+ w, h, &scaled_width, &scaled_height)) {
return VP8_STATUS_INVALID_PARAM;
}
- w = options->scaled_width;
- h = options->scaled_height;
+ w = scaled_width;
+ h = scaled_height;
}
}
out->width = w;
out->height = h;
- // Then, allocate buffer for real
- return AllocateBuffer(out);
+ // Then, allocate buffer for real.
+ status = AllocateBuffer(out);
+ if (status != VP8_STATUS_OK) return status;
+
+ // Use the stride trick if vertical flip is needed.
+ if (options != NULL && options->flip) {
+ status = WebPFlipBuffer(out);
+ }
+ return status;
}
//------------------------------------------------------------------------------
@@ -180,8 +227,9 @@ int WebPInitDecBufferInternal(WebPDecBuffer* buffer, int version) {
void WebPFreeDecBuffer(WebPDecBuffer* buffer) {
if (buffer != NULL) {
- if (!buffer->is_external_memory)
- free(buffer->private_memory);
+ if (!buffer->is_external_memory) {
+ WebPSafeFree(buffer->private_memory);
+ }
buffer->private_memory = NULL;
}
}
@@ -210,6 +258,3 @@ void WebPGrabDecBuffer(WebPDecBuffer* const src, WebPDecBuffer* const dst) {
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/dec/common.h b/drivers/webp/dec/common.h
new file mode 100644
index 0000000000..6961e22470
--- /dev/null
+++ b/drivers/webp/dec/common.h
@@ -0,0 +1,54 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Definitions and macros common to encoding and decoding
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#ifndef WEBP_DEC_COMMON_H_
+#define WEBP_DEC_COMMON_H_
+
+// intra prediction modes
+enum { B_DC_PRED = 0, // 4x4 modes
+ B_TM_PRED = 1,
+ B_VE_PRED = 2,
+ B_HE_PRED = 3,
+ B_RD_PRED = 4,
+ B_VR_PRED = 5,
+ B_LD_PRED = 6,
+ B_VL_PRED = 7,
+ B_HD_PRED = 8,
+ B_HU_PRED = 9,
+ NUM_BMODES = B_HU_PRED + 1 - B_DC_PRED, // = 10
+
+ // Luma16 or UV modes
+ DC_PRED = B_DC_PRED, V_PRED = B_VE_PRED,
+ H_PRED = B_HE_PRED, TM_PRED = B_TM_PRED,
+ B_PRED = NUM_BMODES, // refined I4x4 mode
+ NUM_PRED_MODES = 4,
+
+ // special modes
+ B_DC_PRED_NOTOP = 4,
+ B_DC_PRED_NOLEFT = 5,
+ B_DC_PRED_NOTOPLEFT = 6,
+ NUM_B_DC_MODES = 7 };
+
+enum { MB_FEATURE_TREE_PROBS = 3,
+ NUM_MB_SEGMENTS = 4,
+ NUM_REF_LF_DELTAS = 4,
+ NUM_MODE_LF_DELTAS = 4, // I4x4, ZERO, *, SPLIT
+ MAX_NUM_PARTITIONS = 8,
+ // Probabilities
+ NUM_TYPES = 4, // 0: i16-AC, 1: i16-DC, 2:chroma-AC, 3:i4-AC
+ NUM_BANDS = 8,
+ NUM_CTX = 3,
+ NUM_PROBAS = 11
+ };
+
+#endif // WEBP_DEC_COMMON_H_
diff --git a/drivers/webp/dec/decode_vp8.h b/drivers/webp/dec/decode_vp8.h
index c26a9fc891..2bf1bdbbf5 100644
--- a/drivers/webp/dec/decode_vp8.h
+++ b/drivers/webp/dec/decode_vp8.h
@@ -1,8 +1,10 @@
// Copyright 2010 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Low-level API for VP8 decoder
@@ -12,9 +14,9 @@
#ifndef WEBP_WEBP_DECODE_VP8_H_
#define WEBP_WEBP_DECODE_VP8_H_
-#include "../decode.h"
+#include "webp/decode.h"
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
extern "C" {
#endif
@@ -130,7 +132,8 @@ static WEBP_INLINE int VP8InitIo(VP8Io* const io) {
return VP8InitIoInternal(io, WEBP_DECODER_ABI_VERSION);
}
-// Start decoding a new picture. Returns true if ok.
+// Decode the VP8 frame header. Returns true if ok.
+// Note: 'io->data' must be pointing to the start of the VP8 frame header.
int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io);
// Decode a picture. Will call VP8GetHeaders() if it wasn't done already.
@@ -175,7 +178,7 @@ WEBP_EXTERN(int) VP8LGetInfo(
const uint8_t* data, size_t data_size, // data available so far
int* const width, int* const height, int* const has_alpha);
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/drivers/webp/dec/frame.c b/drivers/webp/dec/frame.c
index 9c91a48e17..b882133eab 100644
--- a/drivers/webp/dec/frame.c
+++ b/drivers/webp/dec/frame.c
@@ -1,8 +1,10 @@
// Copyright 2010 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Frame-reconstruction function. Memory allocation.
@@ -13,11 +15,180 @@
#include "./vp8i.h"
#include "../utils/utils.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
+//------------------------------------------------------------------------------
+// Main reconstruction function.
+
+static const int kScan[16] = {
+ 0 + 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS,
+ 0 + 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS,
+ 0 + 8 * BPS, 4 + 8 * BPS, 8 + 8 * BPS, 12 + 8 * BPS,
+ 0 + 12 * BPS, 4 + 12 * BPS, 8 + 12 * BPS, 12 + 12 * BPS
+};
+
+static int CheckMode(int mb_x, int mb_y, int mode) {
+ if (mode == B_DC_PRED) {
+ if (mb_x == 0) {
+ return (mb_y == 0) ? B_DC_PRED_NOTOPLEFT : B_DC_PRED_NOLEFT;
+ } else {
+ return (mb_y == 0) ? B_DC_PRED_NOTOP : B_DC_PRED;
+ }
+ }
+ return mode;
+}
-#define ALIGN_MASK (32 - 1)
+static void Copy32b(uint8_t* const dst, const uint8_t* const src) {
+ memcpy(dst, src, 4);
+}
+
+static WEBP_INLINE void DoTransform(uint32_t bits, const int16_t* const src,
+ uint8_t* const dst) {
+ switch (bits >> 30) {
+ case 3:
+ VP8Transform(src, dst, 0);
+ break;
+ case 2:
+ VP8TransformAC3(src, dst);
+ break;
+ case 1:
+ VP8TransformDC(src, dst);
+ break;
+ default:
+ break;
+ }
+}
+
+static void DoUVTransform(uint32_t bits, const int16_t* const src,
+ uint8_t* const dst) {
+ if (bits & 0xff) { // any non-zero coeff at all?
+ if (bits & 0xaa) { // any non-zero AC coefficient?
+ VP8TransformUV(src, dst); // note we don't use the AC3 variant for U/V
+ } else {
+ VP8TransformDCUV(src, dst);
+ }
+ }
+}
+
+static void ReconstructRow(const VP8Decoder* const dec,
+ const VP8ThreadContext* ctx) {
+ int j;
+ int mb_x;
+ const int mb_y = ctx->mb_y_;
+ const int cache_id = ctx->id_;
+ uint8_t* const y_dst = dec->yuv_b_ + Y_OFF;
+ uint8_t* const u_dst = dec->yuv_b_ + U_OFF;
+ uint8_t* const v_dst = dec->yuv_b_ + V_OFF;
+
+ // Initialize left-most block.
+ for (j = 0; j < 16; ++j) {
+ y_dst[j * BPS - 1] = 129;
+ }
+ for (j = 0; j < 8; ++j) {
+ u_dst[j * BPS - 1] = 129;
+ v_dst[j * BPS - 1] = 129;
+ }
+
+ // Init top-left sample on left column too.
+ if (mb_y > 0) {
+ y_dst[-1 - BPS] = u_dst[-1 - BPS] = v_dst[-1 - BPS] = 129;
+ } else {
+ // we only need to do this init once at block (0,0).
+ // Afterward, it remains valid for the whole topmost row.
+ memset(y_dst - BPS - 1, 127, 16 + 4 + 1);
+ memset(u_dst - BPS - 1, 127, 8 + 1);
+ memset(v_dst - BPS - 1, 127, 8 + 1);
+ }
+
+ // Reconstruct one row.
+ for (mb_x = 0; mb_x < dec->mb_w_; ++mb_x) {
+ const VP8MBData* const block = ctx->mb_data_ + mb_x;
+
+ // Rotate in the left samples from previously decoded block. We move four
+ // pixels at a time for alignment reason, and because of in-loop filter.
+ if (mb_x > 0) {
+ for (j = -1; j < 16; ++j) {
+ Copy32b(&y_dst[j * BPS - 4], &y_dst[j * BPS + 12]);
+ }
+ for (j = -1; j < 8; ++j) {
+ Copy32b(&u_dst[j * BPS - 4], &u_dst[j * BPS + 4]);
+ Copy32b(&v_dst[j * BPS - 4], &v_dst[j * BPS + 4]);
+ }
+ }
+ {
+ // bring top samples into the cache
+ VP8TopSamples* const top_yuv = dec->yuv_t_ + mb_x;
+ const int16_t* const coeffs = block->coeffs_;
+ uint32_t bits = block->non_zero_y_;
+ int n;
+
+ if (mb_y > 0) {
+ memcpy(y_dst - BPS, top_yuv[0].y, 16);
+ memcpy(u_dst - BPS, top_yuv[0].u, 8);
+ memcpy(v_dst - BPS, top_yuv[0].v, 8);
+ }
+
+ // predict and add residuals
+ if (block->is_i4x4_) { // 4x4
+ uint32_t* const top_right = (uint32_t*)(y_dst - BPS + 16);
+
+ if (mb_y > 0) {
+ if (mb_x >= dec->mb_w_ - 1) { // on rightmost border
+ memset(top_right, top_yuv[0].y[15], sizeof(*top_right));
+ } else {
+ memcpy(top_right, top_yuv[1].y, sizeof(*top_right));
+ }
+ }
+ // replicate the top-right pixels below
+ top_right[BPS] = top_right[2 * BPS] = top_right[3 * BPS] = top_right[0];
+
+ // predict and add residuals for all 4x4 blocks in turn.
+ for (n = 0; n < 16; ++n, bits <<= 2) {
+ uint8_t* const dst = y_dst + kScan[n];
+ VP8PredLuma4[block->imodes_[n]](dst);
+ DoTransform(bits, coeffs + n * 16, dst);
+ }
+ } else { // 16x16
+ const int pred_func = CheckMode(mb_x, mb_y, block->imodes_[0]);
+ VP8PredLuma16[pred_func](y_dst);
+ if (bits != 0) {
+ for (n = 0; n < 16; ++n, bits <<= 2) {
+ DoTransform(bits, coeffs + n * 16, y_dst + kScan[n]);
+ }
+ }
+ }
+ {
+ // Chroma
+ const uint32_t bits_uv = block->non_zero_uv_;
+ const int pred_func = CheckMode(mb_x, mb_y, block->uvmode_);
+ VP8PredChroma8[pred_func](u_dst);
+ VP8PredChroma8[pred_func](v_dst);
+ DoUVTransform(bits_uv >> 0, coeffs + 16 * 16, u_dst);
+ DoUVTransform(bits_uv >> 8, coeffs + 20 * 16, v_dst);
+ }
+
+ // stash away top samples for next block
+ if (mb_y < dec->mb_h_ - 1) {
+ memcpy(top_yuv[0].y, y_dst + 15 * BPS, 16);
+ memcpy(top_yuv[0].u, u_dst + 7 * BPS, 8);
+ memcpy(top_yuv[0].v, v_dst + 7 * BPS, 8);
+ }
+ }
+ // Transfer reconstructed samples from yuv_b_ cache to final destination.
+ {
+ const int y_offset = cache_id * 16 * dec->cache_y_stride_;
+ const int uv_offset = cache_id * 8 * dec->cache_uv_stride_;
+ uint8_t* const y_out = dec->cache_y_ + mb_x * 16 + y_offset;
+ uint8_t* const u_out = dec->cache_u_ + mb_x * 8 + uv_offset;
+ uint8_t* const v_out = dec->cache_v_ + mb_x * 8 + uv_offset;
+ for (j = 0; j < 16; ++j) {
+ memcpy(y_out + j * dec->cache_y_stride_, y_dst + j * BPS, 16);
+ }
+ for (j = 0; j < 8; ++j) {
+ memcpy(u_out + j * dec->cache_uv_stride_, u_dst + j * BPS, 8);
+ memcpy(v_out + j * dec->cache_uv_stride_, v_dst + j * BPS, 8);
+ }
+ }
+ }
+}
//------------------------------------------------------------------------------
// Filtering
@@ -29,25 +200,18 @@ extern "C" {
// U/V, so it's 8 samples total (because of the 2x upsampling).
static const uint8_t kFilterExtraRows[3] = { 0, 2, 8 };
-static WEBP_INLINE int hev_thresh_from_level(int level, int keyframe) {
- if (keyframe) {
- return (level >= 40) ? 2 : (level >= 15) ? 1 : 0;
- } else {
- return (level >= 40) ? 3 : (level >= 20) ? 2 : (level >= 15) ? 1 : 0;
- }
-}
-
static void DoFilter(const VP8Decoder* const dec, int mb_x, int mb_y) {
const VP8ThreadContext* const ctx = &dec->thread_ctx_;
+ const int cache_id = ctx->id_;
const int y_bps = dec->cache_y_stride_;
- VP8FInfo* const f_info = ctx->f_info_ + mb_x;
- uint8_t* const y_dst = dec->cache_y_ + ctx->id_ * 16 * y_bps + mb_x * 16;
- const int level = f_info->f_level_;
+ const VP8FInfo* const f_info = ctx->f_info_ + mb_x;
+ uint8_t* const y_dst = dec->cache_y_ + cache_id * 16 * y_bps + mb_x * 16;
const int ilevel = f_info->f_ilevel_;
- const int limit = 2 * level + ilevel;
- if (level == 0) {
+ const int limit = f_info->f_limit_;
+ if (limit == 0) {
return;
}
+ assert(limit >= 3);
if (dec->filter_type_ == 1) { // simple
if (mb_x > 0) {
VP8SimpleHFilter16(y_dst, y_bps, limit + 4);
@@ -63,10 +227,9 @@ static void DoFilter(const VP8Decoder* const dec, int mb_x, int mb_y) {
}
} else { // complex
const int uv_bps = dec->cache_uv_stride_;
- uint8_t* const u_dst = dec->cache_u_ + ctx->id_ * 8 * uv_bps + mb_x * 8;
- uint8_t* const v_dst = dec->cache_v_ + ctx->id_ * 8 * uv_bps + mb_x * 8;
- const int hev_thresh =
- hev_thresh_from_level(level, dec->frm_hdr_.key_frame_);
+ uint8_t* const u_dst = dec->cache_u_ + cache_id * 8 * uv_bps + mb_x * 8;
+ uint8_t* const v_dst = dec->cache_v_ + cache_id * 8 * uv_bps + mb_x * 8;
+ const int hev_thresh = f_info->hev_thresh_;
if (mb_x > 0) {
VP8HFilter16(y_dst, y_bps, limit + 4, ilevel, hev_thresh);
VP8HFilter8(u_dst, v_dst, uv_bps, limit + 4, ilevel, hev_thresh);
@@ -97,53 +260,138 @@ static void FilterRow(const VP8Decoder* const dec) {
}
//------------------------------------------------------------------------------
+// Precompute the filtering strength for each segment and each i4x4/i16x16 mode.
-void VP8StoreBlock(VP8Decoder* const dec) {
+static void PrecomputeFilterStrengths(VP8Decoder* const dec) {
if (dec->filter_type_ > 0) {
- VP8FInfo* const info = dec->f_info_ + dec->mb_x_;
- const int skip = dec->mb_info_[dec->mb_x_].skip_;
- int level = dec->filter_levels_[dec->segment_];
- if (dec->filter_hdr_.use_lf_delta_) {
- // TODO(skal): only CURRENT is handled for now.
- level += dec->filter_hdr_.ref_lf_delta_[0];
- if (dec->is_i4x4_) {
- level += dec->filter_hdr_.mode_lf_delta_[0];
+ int s;
+ const VP8FilterHeader* const hdr = &dec->filter_hdr_;
+ for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
+ int i4x4;
+ // First, compute the initial level
+ int base_level;
+ if (dec->segment_hdr_.use_segment_) {
+ base_level = dec->segment_hdr_.filter_strength_[s];
+ if (!dec->segment_hdr_.absolute_delta_) {
+ base_level += hdr->level_;
+ }
+ } else {
+ base_level = hdr->level_;
+ }
+ for (i4x4 = 0; i4x4 <= 1; ++i4x4) {
+ VP8FInfo* const info = &dec->fstrengths_[s][i4x4];
+ int level = base_level;
+ if (hdr->use_lf_delta_) {
+ level += hdr->ref_lf_delta_[0];
+ if (i4x4) {
+ level += hdr->mode_lf_delta_[0];
+ }
+ }
+ level = (level < 0) ? 0 : (level > 63) ? 63 : level;
+ if (level > 0) {
+ int ilevel = level;
+ if (hdr->sharpness_ > 0) {
+ if (hdr->sharpness_ > 4) {
+ ilevel >>= 2;
+ } else {
+ ilevel >>= 1;
+ }
+ if (ilevel > 9 - hdr->sharpness_) {
+ ilevel = 9 - hdr->sharpness_;
+ }
+ }
+ if (ilevel < 1) ilevel = 1;
+ info->f_ilevel_ = ilevel;
+ info->f_limit_ = 2 * level + ilevel;
+ info->hev_thresh_ = (level >= 40) ? 2 : (level >= 15) ? 1 : 0;
+ } else {
+ info->f_limit_ = 0; // no filtering
+ }
+ info->f_inner_ = i4x4;
}
}
- level = (level < 0) ? 0 : (level > 63) ? 63 : level;
- info->f_level_ = level;
+ }
+}
- if (dec->filter_hdr_.sharpness_ > 0) {
- if (dec->filter_hdr_.sharpness_ > 4) {
- level >>= 2;
- } else {
- level >>= 1;
+//------------------------------------------------------------------------------
+// Dithering
+
+#define DITHER_AMP_TAB_SIZE 12
+static const int kQuantToDitherAmp[DITHER_AMP_TAB_SIZE] = {
+ // roughly, it's dqm->uv_mat_[1]
+ 8, 7, 6, 4, 4, 2, 2, 2, 1, 1, 1, 1
+};
+
+void VP8InitDithering(const WebPDecoderOptions* const options,
+ VP8Decoder* const dec) {
+ assert(dec != NULL);
+ if (options != NULL) {
+ const int d = options->dithering_strength;
+ const int max_amp = (1 << VP8_RANDOM_DITHER_FIX) - 1;
+ const int f = (d < 0) ? 0 : (d > 100) ? max_amp : (d * max_amp / 100);
+ if (f > 0) {
+ int s;
+ int all_amp = 0;
+ for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
+ VP8QuantMatrix* const dqm = &dec->dqm_[s];
+ if (dqm->uv_quant_ < DITHER_AMP_TAB_SIZE) {
+ // TODO(skal): should we specially dither more for uv_quant_ < 0?
+ const int idx = (dqm->uv_quant_ < 0) ? 0 : dqm->uv_quant_;
+ dqm->dither_ = (f * kQuantToDitherAmp[idx]) >> 3;
+ }
+ all_amp |= dqm->dither_;
}
- if (level > 9 - dec->filter_hdr_.sharpness_) {
- level = 9 - dec->filter_hdr_.sharpness_;
+ if (all_amp != 0) {
+ VP8InitRandom(&dec->dithering_rg_, 1.0f);
+ dec->dither_ = 1;
}
}
+ // potentially allow alpha dithering
+ dec->alpha_dithering_ = options->alpha_dithering_strength;
+ if (dec->alpha_dithering_ > 100) {
+ dec->alpha_dithering_ = 100;
+ } else if (dec->alpha_dithering_ < 0) {
+ dec->alpha_dithering_ = 0;
+ }
+ }
+}
- info->f_ilevel_ = (level < 1) ? 1 : level;
- info->f_inner_ = (!skip || dec->is_i4x4_);
+// minimal amp that will provide a non-zero dithering effect
+#define MIN_DITHER_AMP 4
+#define DITHER_DESCALE 4
+#define DITHER_DESCALE_ROUNDER (1 << (DITHER_DESCALE - 1))
+#define DITHER_AMP_BITS 8
+#define DITHER_AMP_CENTER (1 << DITHER_AMP_BITS)
+
+static void Dither8x8(VP8Random* const rg, uint8_t* dst, int bps, int amp) {
+ int i, j;
+ for (j = 0; j < 8; ++j) {
+ for (i = 0; i < 8; ++i) {
+ // TODO: could be made faster with SSE2
+ const int bits =
+ VP8RandomBits2(rg, DITHER_AMP_BITS + 1, amp) - DITHER_AMP_CENTER;
+ // Convert to range: [-2,2] for dither=50, [-4,4] for dither=100
+ const int delta = (bits + DITHER_DESCALE_ROUNDER) >> DITHER_DESCALE;
+ const int v = (int)dst[i] + delta;
+ dst[i] = (v < 0) ? 0 : (v > 255) ? 255u : (uint8_t)v;
+ }
+ dst += bps;
}
- {
- // Transfer samples to row cache
- int y;
- const int y_offset = dec->cache_id_ * 16 * dec->cache_y_stride_;
- const int uv_offset = dec->cache_id_ * 8 * dec->cache_uv_stride_;
- uint8_t* const ydst = dec->cache_y_ + dec->mb_x_ * 16 + y_offset;
- uint8_t* const udst = dec->cache_u_ + dec->mb_x_ * 8 + uv_offset;
- uint8_t* const vdst = dec->cache_v_ + dec->mb_x_ * 8 + uv_offset;
- for (y = 0; y < 16; ++y) {
- memcpy(ydst + y * dec->cache_y_stride_,
- dec->yuv_b_ + Y_OFF + y * BPS, 16);
- }
- for (y = 0; y < 8; ++y) {
- memcpy(udst + y * dec->cache_uv_stride_,
- dec->yuv_b_ + U_OFF + y * BPS, 8);
- memcpy(vdst + y * dec->cache_uv_stride_,
- dec->yuv_b_ + V_OFF + y * BPS, 8);
+}
+
+static void DitherRow(VP8Decoder* const dec) {
+ int mb_x;
+ assert(dec->dither_);
+ for (mb_x = dec->tl_mb_x_; mb_x < dec->br_mb_x_; ++mb_x) {
+ const VP8ThreadContext* const ctx = &dec->thread_ctx_;
+ const VP8MBData* const data = ctx->mb_data_ + mb_x;
+ const int cache_id = ctx->id_;
+ const int uv_bps = dec->cache_uv_stride_;
+ if (data->dither_ >= MIN_DITHER_AMP) {
+ uint8_t* const u_dst = dec->cache_u_ + cache_id * 8 * uv_bps + mb_x * 8;
+ uint8_t* const v_dst = dec->cache_v_ + cache_id * 8 * uv_bps + mb_x * 8;
+ Dither8x8(&dec->dithering_rg_, u_dst, uv_bps, data->dither_);
+ Dither8x8(&dec->dithering_rg_, v_dst, uv_bps, data->dither_);
}
}
}
@@ -165,25 +413,35 @@ void VP8StoreBlock(VP8Decoder* const dec) {
static int FinishRow(VP8Decoder* const dec, VP8Io* const io) {
int ok = 1;
const VP8ThreadContext* const ctx = &dec->thread_ctx_;
+ const int cache_id = ctx->id_;
const int extra_y_rows = kFilterExtraRows[dec->filter_type_];
const int ysize = extra_y_rows * dec->cache_y_stride_;
const int uvsize = (extra_y_rows / 2) * dec->cache_uv_stride_;
- const int y_offset = ctx->id_ * 16 * dec->cache_y_stride_;
- const int uv_offset = ctx->id_ * 8 * dec->cache_uv_stride_;
+ const int y_offset = cache_id * 16 * dec->cache_y_stride_;
+ const int uv_offset = cache_id * 8 * dec->cache_uv_stride_;
uint8_t* const ydst = dec->cache_y_ - ysize + y_offset;
uint8_t* const udst = dec->cache_u_ - uvsize + uv_offset;
uint8_t* const vdst = dec->cache_v_ - uvsize + uv_offset;
- const int first_row = (ctx->mb_y_ == 0);
- const int last_row = (ctx->mb_y_ >= dec->br_mb_y_ - 1);
- int y_start = MACROBLOCK_VPOS(ctx->mb_y_);
- int y_end = MACROBLOCK_VPOS(ctx->mb_y_ + 1);
+ const int mb_y = ctx->mb_y_;
+ const int is_first_row = (mb_y == 0);
+ const int is_last_row = (mb_y >= dec->br_mb_y_ - 1);
+
+ if (dec->mt_method_ == 2) {
+ ReconstructRow(dec, ctx);
+ }
if (ctx->filter_row_) {
FilterRow(dec);
}
- if (io->put) {
- if (!first_row) {
+ if (dec->dither_) {
+ DitherRow(dec);
+ }
+
+ if (io->put != NULL) {
+ int y_start = MACROBLOCK_VPOS(mb_y);
+ int y_end = MACROBLOCK_VPOS(mb_y + 1);
+ if (!is_first_row) {
y_start -= extra_y_rows;
io->y = ydst;
io->u = udst;
@@ -194,7 +452,7 @@ static int FinishRow(VP8Decoder* const dec, VP8Io* const io) {
io->v = dec->cache_v_ + uv_offset;
}
- if (!last_row) {
+ if (!is_last_row) {
y_end -= extra_y_rows;
}
if (y_end > io->crop_bottom) {
@@ -202,11 +460,8 @@ static int FinishRow(VP8Decoder* const dec, VP8Io* const io) {
}
io->a = NULL;
if (dec->alpha_data_ != NULL && y_start < y_end) {
- // TODO(skal): several things to correct here:
- // * testing presence of alpha with dec->alpha_data_ is not a good idea
- // * we're actually decompressing the full plane only once. It should be
- // more obvious from signature.
- // * we could free alpha_data_ right after this call, but we don't own.
+ // TODO(skal): testing presence of alpha with dec->alpha_data_ is not a
+ // good idea.
io->a = VP8DecompressAlphaRows(dec, y_start, y_end - y_start);
if (io->a == NULL) {
return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
@@ -238,8 +493,8 @@ static int FinishRow(VP8Decoder* const dec, VP8Io* const io) {
}
}
// rotate top samples if needed
- if (ctx->id_ + 1 == dec->num_caches_) {
- if (!last_row) {
+ if (cache_id + 1 == dec->num_caches_) {
+ if (!is_last_row) {
memcpy(dec->cache_y_ - ysize, ydst + 16 * dec->cache_y_stride_, ysize);
memcpy(dec->cache_u_ - uvsize, udst + 8 * dec->cache_uv_stride_, uvsize);
memcpy(dec->cache_v_ - uvsize, vdst + 8 * dec->cache_uv_stride_, uvsize);
@@ -256,27 +511,40 @@ static int FinishRow(VP8Decoder* const dec, VP8Io* const io) {
int VP8ProcessRow(VP8Decoder* const dec, VP8Io* const io) {
int ok = 1;
VP8ThreadContext* const ctx = &dec->thread_ctx_;
- if (!dec->use_threads_) {
+ const int filter_row =
+ (dec->filter_type_ > 0) &&
+ (dec->mb_y_ >= dec->tl_mb_y_) && (dec->mb_y_ <= dec->br_mb_y_);
+ if (dec->mt_method_ == 0) {
// ctx->id_ and ctx->f_info_ are already set
ctx->mb_y_ = dec->mb_y_;
- ctx->filter_row_ = dec->filter_row_;
+ ctx->filter_row_ = filter_row;
+ ReconstructRow(dec, ctx);
ok = FinishRow(dec, io);
} else {
WebPWorker* const worker = &dec->worker_;
// Finish previous job *before* updating context
- ok &= WebPWorkerSync(worker);
+ ok &= WebPGetWorkerInterface()->Sync(worker);
assert(worker->status_ == OK);
if (ok) { // spawn a new deblocking/output job
ctx->io_ = *io;
ctx->id_ = dec->cache_id_;
ctx->mb_y_ = dec->mb_y_;
- ctx->filter_row_ = dec->filter_row_;
- if (ctx->filter_row_) { // just swap filter info
+ ctx->filter_row_ = filter_row;
+ if (dec->mt_method_ == 2) { // swap macroblock data
+ VP8MBData* const tmp = ctx->mb_data_;
+ ctx->mb_data_ = dec->mb_data_;
+ dec->mb_data_ = tmp;
+ } else {
+ // perform reconstruction directly in main thread
+ ReconstructRow(dec, ctx);
+ }
+ if (filter_row) { // swap filter info
VP8FInfo* const tmp = ctx->f_info_;
ctx->f_info_ = dec->f_info_;
dec->f_info_ = tmp;
}
- WebPWorkerLaunch(worker);
+ // (reconstruct)+filter in parallel
+ WebPGetWorkerInterface()->Launch(worker);
if (++dec->cache_id_ == dec->num_caches_) {
dec->cache_id_ = 0;
}
@@ -290,8 +558,8 @@ int VP8ProcessRow(VP8Decoder* const dec, VP8Io* const io) {
VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io) {
// Call setup() first. This may trigger additional decoding features on 'io'.
- // Note: Afterward, we must call teardown() not matter what.
- if (io->setup && !io->setup(io)) {
+ // Note: Afterward, we must call teardown() no matter what.
+ if (io->setup != NULL && !io->setup(io)) {
VP8SetError(dec, VP8_STATUS_USER_ABORT, "Frame setup failed");
return dec->status_;
}
@@ -304,7 +572,7 @@ VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io) {
// Define the area where we can skip in-loop filtering, in case of cropping.
//
- // 'Simple' filter reads two luma samples outside of the macroblock and
+ // 'Simple' filter reads two luma samples outside of the macroblock
// and filters one. It doesn't filter the chroma samples. Hence, we can
// avoid doing the in-loop filtering before crop_top/crop_left position.
// For the 'Complex' filter, 3 samples are read and up to 3 are filtered.
@@ -339,16 +607,17 @@ VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io) {
dec->br_mb_y_ = dec->mb_h_;
}
}
+ PrecomputeFilterStrengths(dec);
return VP8_STATUS_OK;
}
int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io) {
int ok = 1;
- if (dec->use_threads_) {
- ok = WebPWorkerSync(&dec->worker_);
+ if (dec->mt_method_ > 0) {
+ ok = WebPGetWorkerInterface()->Sync(&dec->worker_);
}
- if (io->teardown) {
+ if (io->teardown != NULL) {
io->teardown(io);
}
return ok;
@@ -384,9 +653,9 @@ int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io) {
// Initialize multi/single-thread worker
static int InitThreadContext(VP8Decoder* const dec) {
dec->cache_id_ = 0;
- if (dec->use_threads_) {
+ if (dec->mt_method_ > 0) {
WebPWorker* const worker = &dec->worker_;
- if (!WebPWorkerReset(worker)) {
+ if (!WebPGetWorkerInterface()->Reset(worker)) {
return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,
"thread initialization failed.");
}
@@ -401,6 +670,28 @@ static int InitThreadContext(VP8Decoder* const dec) {
return 1;
}
+int VP8GetThreadMethod(const WebPDecoderOptions* const options,
+ const WebPHeaderStructure* const headers,
+ int width, int height) {
+ if (options == NULL || options->use_threads == 0) {
+ return 0;
+ }
+ (void)headers;
+ (void)width;
+ (void)height;
+ assert(headers == NULL || !headers->is_lossless);
+#if defined(WEBP_USE_THREAD)
+ if (width < MIN_WIDTH_FOR_THREADS) return 0;
+ // TODO(skal): tune the heuristic further
+#if 0
+ if (height < 2 * width) return 2;
+#endif
+ return 2;
+#else // !WEBP_USE_THREAD
+ return 0;
+#endif
+}
+
#undef MT_CACHE_LINES
#undef ST_CACHE_LINES
@@ -412,14 +703,15 @@ static int AllocateMemory(VP8Decoder* const dec) {
const int mb_w = dec->mb_w_;
// Note: we use 'size_t' when there's no overflow risk, uint64_t otherwise.
const size_t intra_pred_mode_size = 4 * mb_w * sizeof(uint8_t);
- const size_t top_size = (16 + 8 + 8) * mb_w;
+ const size_t top_size = sizeof(VP8TopSamples) * mb_w;
const size_t mb_info_size = (mb_w + 1) * sizeof(VP8MB);
const size_t f_info_size =
(dec->filter_type_ > 0) ?
- mb_w * (dec->use_threads_ ? 2 : 1) * sizeof(VP8FInfo)
+ mb_w * (dec->mt_method_ > 0 ? 2 : 1) * sizeof(VP8FInfo)
: 0;
const size_t yuv_size = YUV_SIZE * sizeof(*dec->yuv_b_);
- const size_t coeffs_size = 384 * sizeof(*dec->coeffs_);
+ const size_t mb_data_size =
+ (dec->mt_method_ == 2 ? 2 : 1) * mb_w * sizeof(*dec->mb_data_);
const size_t cache_height = (16 * num_caches
+ kFilterExtraRows[dec->filter_type_]) * 3 / 2;
const size_t cache_size = top_size * cache_height;
@@ -428,13 +720,13 @@ static int AllocateMemory(VP8Decoder* const dec) {
(uint64_t)dec->pic_hdr_.width_ * dec->pic_hdr_.height_ : 0ULL;
const uint64_t needed = (uint64_t)intra_pred_mode_size
+ top_size + mb_info_size + f_info_size
- + yuv_size + coeffs_size
- + cache_size + alpha_size + ALIGN_MASK;
+ + yuv_size + mb_data_size
+ + cache_size + alpha_size + WEBP_ALIGN_CST;
uint8_t* mem;
if (needed != (size_t)needed) return 0; // check for overflow
if (needed > dec->mem_size_) {
- free(dec->mem_);
+ WebPSafeFree(dec->mem_);
dec->mem_size_ = 0;
dec->mem_ = WebPSafeMalloc(needed, sizeof(uint8_t));
if (dec->mem_ == NULL) {
@@ -449,12 +741,8 @@ static int AllocateMemory(VP8Decoder* const dec) {
dec->intra_t_ = (uint8_t*)mem;
mem += intra_pred_mode_size;
- dec->y_t_ = (uint8_t*)mem;
- mem += 16 * mb_w;
- dec->u_t_ = (uint8_t*)mem;
- mem += 8 * mb_w;
- dec->v_t_ = (uint8_t*)mem;
- mem += 8 * mb_w;
+ dec->yuv_t_ = (VP8TopSamples*)mem;
+ mem += top_size;
dec->mb_info_ = ((VP8MB*)mem) + 1;
mem += mb_info_size;
@@ -463,20 +751,24 @@ static int AllocateMemory(VP8Decoder* const dec) {
mem += f_info_size;
dec->thread_ctx_.id_ = 0;
dec->thread_ctx_.f_info_ = dec->f_info_;
- if (dec->use_threads_) {
+ if (dec->mt_method_ > 0) {
// secondary cache line. The deblocking process need to make use of the
// filtering strength from previous macroblock row, while the new ones
// are being decoded in parallel. We'll just swap the pointers.
dec->thread_ctx_.f_info_ += mb_w;
}
- mem = (uint8_t*)((uintptr_t)(mem + ALIGN_MASK) & ~ALIGN_MASK);
- assert((yuv_size & ALIGN_MASK) == 0);
+ mem = (uint8_t*)WEBP_ALIGN(mem);
+ assert((yuv_size & WEBP_ALIGN_CST) == 0);
dec->yuv_b_ = (uint8_t*)mem;
mem += yuv_size;
- dec->coeffs_ = (int16_t*)mem;
- mem += coeffs_size;
+ dec->mb_data_ = (VP8MBData*)mem;
+ dec->thread_ctx_.mb_data_ = (VP8MBData*)mem;
+ if (dec->mt_method_ == 2) {
+ dec->thread_ctx_.mb_data_ += mb_w;
+ }
+ mem += mb_data_size;
dec->cache_y_stride_ = 16 * mb_w;
dec->cache_uv_stride_ = 8 * mb_w;
@@ -496,9 +788,11 @@ static int AllocateMemory(VP8Decoder* const dec) {
// alpha plane
dec->alpha_plane_ = alpha_size ? (uint8_t*)mem : NULL;
mem += alpha_size;
+ assert(mem <= (uint8_t*)dec->mem_ + dec->mem_size_);
- // note: left-info is initialized once for all.
+ // note: left/top-info is initialized once for all.
memset(dec->mb_info_ - 1, 0, mb_info_size);
+ VP8InitScanline(dec); // initialize left too.
// initialize top
memset(dec->intra_t_, B_DC_PRED, intra_pred_mode_size);
@@ -517,7 +811,7 @@ static void InitIo(VP8Decoder* const dec, VP8Io* io) {
io->a = NULL;
}
-int VP8InitFrame(VP8Decoder* const dec, VP8Io* io) {
+int VP8InitFrame(VP8Decoder* const dec, VP8Io* const io) {
if (!InitThreadContext(dec)) return 0; // call first. Sets dec->num_caches_.
if (!AllocateMemory(dec)) return 0;
InitIo(dec, io);
@@ -526,154 +820,3 @@ int VP8InitFrame(VP8Decoder* const dec, VP8Io* io) {
}
//------------------------------------------------------------------------------
-// Main reconstruction function.
-
-static const int kScan[16] = {
- 0 + 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS,
- 0 + 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS,
- 0 + 8 * BPS, 4 + 8 * BPS, 8 + 8 * BPS, 12 + 8 * BPS,
- 0 + 12 * BPS, 4 + 12 * BPS, 8 + 12 * BPS, 12 + 12 * BPS
-};
-
-static WEBP_INLINE int CheckMode(VP8Decoder* const dec, int mode) {
- if (mode == B_DC_PRED) {
- if (dec->mb_x_ == 0) {
- return (dec->mb_y_ == 0) ? B_DC_PRED_NOTOPLEFT : B_DC_PRED_NOLEFT;
- } else {
- return (dec->mb_y_ == 0) ? B_DC_PRED_NOTOP : B_DC_PRED;
- }
- }
- return mode;
-}
-
-static WEBP_INLINE void Copy32b(uint8_t* dst, uint8_t* src) {
- *(uint32_t*)dst = *(uint32_t*)src;
-}
-
-void VP8ReconstructBlock(VP8Decoder* const dec) {
- uint8_t* const y_dst = dec->yuv_b_ + Y_OFF;
- uint8_t* const u_dst = dec->yuv_b_ + U_OFF;
- uint8_t* const v_dst = dec->yuv_b_ + V_OFF;
-
- // Rotate in the left samples from previously decoded block. We move four
- // pixels at a time for alignment reason, and because of in-loop filter.
- if (dec->mb_x_ > 0) {
- int j;
- for (j = -1; j < 16; ++j) {
- Copy32b(&y_dst[j * BPS - 4], &y_dst[j * BPS + 12]);
- }
- for (j = -1; j < 8; ++j) {
- Copy32b(&u_dst[j * BPS - 4], &u_dst[j * BPS + 4]);
- Copy32b(&v_dst[j * BPS - 4], &v_dst[j * BPS + 4]);
- }
- } else {
- int j;
- for (j = 0; j < 16; ++j) {
- y_dst[j * BPS - 1] = 129;
- }
- for (j = 0; j < 8; ++j) {
- u_dst[j * BPS - 1] = 129;
- v_dst[j * BPS - 1] = 129;
- }
- // Init top-left sample on left column too
- if (dec->mb_y_ > 0) {
- y_dst[-1 - BPS] = u_dst[-1 - BPS] = v_dst[-1 - BPS] = 129;
- }
- }
- {
- // bring top samples into the cache
- uint8_t* const top_y = dec->y_t_ + dec->mb_x_ * 16;
- uint8_t* const top_u = dec->u_t_ + dec->mb_x_ * 8;
- uint8_t* const top_v = dec->v_t_ + dec->mb_x_ * 8;
- const int16_t* coeffs = dec->coeffs_;
- int n;
-
- if (dec->mb_y_ > 0) {
- memcpy(y_dst - BPS, top_y, 16);
- memcpy(u_dst - BPS, top_u, 8);
- memcpy(v_dst - BPS, top_v, 8);
- } else if (dec->mb_x_ == 0) {
- // we only need to do this init once at block (0,0).
- // Afterward, it remains valid for the whole topmost row.
- memset(y_dst - BPS - 1, 127, 16 + 4 + 1);
- memset(u_dst - BPS - 1, 127, 8 + 1);
- memset(v_dst - BPS - 1, 127, 8 + 1);
- }
-
- // predict and add residuals
-
- if (dec->is_i4x4_) { // 4x4
- uint32_t* const top_right = (uint32_t*)(y_dst - BPS + 16);
-
- if (dec->mb_y_ > 0) {
- if (dec->mb_x_ >= dec->mb_w_ - 1) { // on rightmost border
- top_right[0] = top_y[15] * 0x01010101u;
- } else {
- memcpy(top_right, top_y + 16, sizeof(*top_right));
- }
- }
- // replicate the top-right pixels below
- top_right[BPS] = top_right[2 * BPS] = top_right[3 * BPS] = top_right[0];
-
- // predict and add residues for all 4x4 blocks in turn.
- for (n = 0; n < 16; n++) {
- uint8_t* const dst = y_dst + kScan[n];
- VP8PredLuma4[dec->imodes_[n]](dst);
- if (dec->non_zero_ac_ & (1 << n)) {
- VP8Transform(coeffs + n * 16, dst, 0);
- } else if (dec->non_zero_ & (1 << n)) { // only DC is present
- VP8TransformDC(coeffs + n * 16, dst);
- }
- }
- } else { // 16x16
- const int pred_func = CheckMode(dec, dec->imodes_[0]);
- VP8PredLuma16[pred_func](y_dst);
- if (dec->non_zero_) {
- for (n = 0; n < 16; n++) {
- uint8_t* const dst = y_dst + kScan[n];
- if (dec->non_zero_ac_ & (1 << n)) {
- VP8Transform(coeffs + n * 16, dst, 0);
- } else if (dec->non_zero_ & (1 << n)) { // only DC is present
- VP8TransformDC(coeffs + n * 16, dst);
- }
- }
- }
- }
- {
- // Chroma
- const int pred_func = CheckMode(dec, dec->uvmode_);
- VP8PredChroma8[pred_func](u_dst);
- VP8PredChroma8[pred_func](v_dst);
-
- if (dec->non_zero_ & 0x0f0000) { // chroma-U
- const int16_t* const u_coeffs = dec->coeffs_ + 16 * 16;
- if (dec->non_zero_ac_ & 0x0f0000) {
- VP8TransformUV(u_coeffs, u_dst);
- } else {
- VP8TransformDCUV(u_coeffs, u_dst);
- }
- }
- if (dec->non_zero_ & 0xf00000) { // chroma-V
- const int16_t* const v_coeffs = dec->coeffs_ + 20 * 16;
- if (dec->non_zero_ac_ & 0xf00000) {
- VP8TransformUV(v_coeffs, v_dst);
- } else {
- VP8TransformDCUV(v_coeffs, v_dst);
- }
- }
-
- // stash away top samples for next block
- if (dec->mb_y_ < dec->mb_h_ - 1) {
- memcpy(top_y, y_dst + 15 * BPS, 16);
- memcpy(top_u, u_dst + 7 * BPS, 8);
- memcpy(top_v, v_dst + 7 * BPS, 8);
- }
- }
- }
-}
-
-//------------------------------------------------------------------------------
-
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/dec/idec.c b/drivers/webp/dec/idec.c
index 7df790ced8..abafb9f3d1 100644
--- a/drivers/webp/dec/idec.c
+++ b/drivers/webp/dec/idec.c
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Incremental decoding
@@ -13,14 +15,11 @@
#include <string.h>
#include <stdlib.h>
+#include "./alphai.h"
#include "./webpi.h"
#include "./vp8i.h"
#include "../utils/utils.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
// In append mode, buffer allocations increase as multiples of this value.
// Needs to be a power of 2.
#define CHUNK_SIZE 4096
@@ -29,11 +28,13 @@ extern "C" {
//------------------------------------------------------------------------------
// Data structures for memory and states
-// Decoding states. State normally flows like HEADER->PARTS0->DATA->DONE.
+// Decoding states. State normally flows as:
+// WEBP_HEADER->VP8_HEADER->VP8_PARTS0->VP8_DATA->DONE for a lossy image, and
+// WEBP_HEADER->VP8L_HEADER->VP8L_DATA->DONE for a lossless image.
// If there is any error the decoder goes into state ERROR.
typedef enum {
- STATE_PRE_VP8, // All data before that of the first VP8 chunk.
- STATE_VP8_FRAME_HEADER, // For VP8 Frame header (within VP8 chunk).
+ STATE_WEBP_HEADER, // All the data before that of the VP8/VP8L chunk.
+ STATE_VP8_HEADER, // The VP8 Frame header (within the VP8 chunk).
STATE_VP8_PARTS0,
STATE_VP8_DATA,
STATE_VP8L_HEADER,
@@ -71,32 +72,41 @@ struct WebPIDecoder {
MemBuffer mem_; // input memory buffer.
WebPDecBuffer output_; // output buffer (when no external one is supplied)
size_t chunk_size_; // Compressed VP8/VP8L size extracted from Header.
+
+ int last_mb_y_; // last row reached for intra-mode decoding
};
// MB context to restore in case VP8DecodeMB() fails
typedef struct {
VP8MB left_;
VP8MB info_;
- uint8_t intra_t_[4];
- uint8_t intra_l_[4];
- VP8BitReader br_;
VP8BitReader token_br_;
} MBContext;
//------------------------------------------------------------------------------
// MemBuffer: incoming data handling
-static void RemapBitReader(VP8BitReader* const br, ptrdiff_t offset) {
- if (br->buf_ != NULL) {
- br->buf_ += offset;
- br->buf_end_ += offset;
- }
-}
-
static WEBP_INLINE size_t MemDataSize(const MemBuffer* mem) {
return (mem->end_ - mem->start_);
}
+// Check if we need to preserve the compressed alpha data, as it may not have
+// been decoded yet.
+static int NeedCompressedAlpha(const WebPIDecoder* const idec) {
+ if (idec->state_ == STATE_WEBP_HEADER) {
+ // We haven't parsed the headers yet, so we don't know whether the image is
+ // lossy or lossless. This also means that we haven't parsed the ALPH chunk.
+ return 0;
+ }
+ if (idec->is_lossless_) {
+ return 0; // ALPH chunk is not present for lossless images.
+ } else {
+ const VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
+ assert(dec != NULL); // Must be true as idec->state_ != STATE_WEBP_HEADER.
+ return (dec->alpha_data_ != NULL) && !dec->is_alpha_decoded_;
+ }
+}
+
static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) {
MemBuffer* const mem = &idec->mem_;
const uint8_t* const new_base = mem->buf_ + mem->start_;
@@ -112,16 +122,36 @@ static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) {
if (offset != 0) {
int p;
for (p = 0; p <= last_part; ++p) {
- RemapBitReader(dec->parts_ + p, offset);
+ VP8RemapBitReader(dec->parts_ + p, offset);
}
// Remap partition #0 data pointer to new offset, but only in MAP
// mode (in APPEND mode, partition #0 is copied into a fixed memory).
if (mem->mode_ == MEM_MODE_MAP) {
- RemapBitReader(&dec->br_, offset);
+ VP8RemapBitReader(&dec->br_, offset);
+ }
+ }
+ {
+ const uint8_t* const last_start = dec->parts_[last_part].buf_;
+ assert(last_part >= 0);
+ VP8BitReaderSetBuffer(&dec->parts_[last_part], last_start,
+ mem->buf_ + mem->end_ - last_start);
+ }
+ if (NeedCompressedAlpha(idec)) {
+ ALPHDecoder* const alph_dec = dec->alph_dec_;
+ dec->alpha_data_ += offset;
+ if (alph_dec != NULL) {
+ if (alph_dec->method_ == ALPHA_LOSSLESS_COMPRESSION) {
+ VP8LDecoder* const alph_vp8l_dec = alph_dec->vp8l_dec_;
+ assert(alph_vp8l_dec != NULL);
+ assert(dec->alpha_data_size_ >= ALPHA_HEADER_LEN);
+ VP8LBitReaderSetBuffer(&alph_vp8l_dec->br_,
+ dec->alpha_data_ + ALPHA_HEADER_LEN,
+ dec->alpha_data_size_ - ALPHA_HEADER_LEN);
+ } else { // alph_dec->method_ == ALPHA_NO_COMPRESSION
+ // Nothing special to do in this case.
+ }
}
}
- assert(last_part >= 0);
- dec->parts_[last_part].buf_end_ = mem->buf_ + mem->end_;
} else { // Resize lossless bitreader
VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_;
VP8LBitReaderSetBuffer(&dec->br_, new_base, MemDataSize(mem));
@@ -133,8 +163,12 @@ static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) {
// size if required and also updates VP8BitReader's if new memory is allocated.
static int AppendToMemBuffer(WebPIDecoder* const idec,
const uint8_t* const data, size_t data_size) {
+ VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
MemBuffer* const mem = &idec->mem_;
- const uint8_t* const old_base = mem->buf_ + mem->start_;
+ const int need_compressed_alpha = NeedCompressedAlpha(idec);
+ const uint8_t* const old_start = mem->buf_ + mem->start_;
+ const uint8_t* const old_base =
+ need_compressed_alpha ? dec->alpha_data_ : old_start;
assert(mem->mode_ == MEM_MODE_APPEND);
if (data_size > MAX_CHUNK_PAYLOAD) {
// security safeguard: trying to allocate more than what the format
@@ -143,17 +177,18 @@ static int AppendToMemBuffer(WebPIDecoder* const idec,
}
if (mem->end_ + data_size > mem->buf_size_) { // Need some free memory
- const size_t current_size = MemDataSize(mem);
+ const size_t new_mem_start = old_start - old_base;
+ const size_t current_size = MemDataSize(mem) + new_mem_start;
const uint64_t new_size = (uint64_t)current_size + data_size;
const uint64_t extra_size = (new_size + CHUNK_SIZE - 1) & ~(CHUNK_SIZE - 1);
uint8_t* const new_buf =
(uint8_t*)WebPSafeMalloc(extra_size, sizeof(*new_buf));
if (new_buf == NULL) return 0;
memcpy(new_buf, old_base, current_size);
- free(mem->buf_);
+ WebPSafeFree(mem->buf_);
mem->buf_ = new_buf;
mem->buf_size_ = (size_t)extra_size;
- mem->start_ = 0;
+ mem->start_ = new_mem_start;
mem->end_ = current_size;
}
@@ -161,14 +196,15 @@ static int AppendToMemBuffer(WebPIDecoder* const idec,
mem->end_ += data_size;
assert(mem->end_ <= mem->buf_size_);
- DoRemap(idec, mem->buf_ + mem->start_ - old_base);
+ DoRemap(idec, mem->buf_ + mem->start_ - old_start);
return 1;
}
static int RemapMemBuffer(WebPIDecoder* const idec,
const uint8_t* const data, size_t data_size) {
MemBuffer* const mem = &idec->mem_;
- const uint8_t* const old_base = mem->buf_ + mem->start_;
+ const uint8_t* const old_buf = mem->buf_;
+ const uint8_t* const old_start = old_buf + mem->start_;
assert(mem->mode_ == MEM_MODE_MAP);
if (data_size < mem->buf_size_) return 0; // can't remap to a shorter buffer!
@@ -176,7 +212,7 @@ static int RemapMemBuffer(WebPIDecoder* const idec,
mem->buf_ = (uint8_t*)data;
mem->end_ = mem->buf_size_ = data_size;
- DoRemap(idec, mem->buf_ + mem->start_ - old_base);
+ DoRemap(idec, mem->buf_ + mem->start_ - old_start);
return 1;
}
@@ -191,8 +227,8 @@ static void InitMemBuffer(MemBuffer* const mem) {
static void ClearMemBuffer(MemBuffer* const mem) {
assert(mem);
if (mem->mode_ == MEM_MODE_APPEND) {
- free(mem->buf_);
- free((void*)mem->part0_buf_);
+ WebPSafeFree(mem->buf_);
+ WebPSafeFree((void*)mem->part0_buf_);
}
}
@@ -206,35 +242,34 @@ static int CheckMemBufferMode(MemBuffer* const mem, MemBufferMode expected) {
return 1;
}
+// To be called last.
+static VP8StatusCode FinishDecoding(WebPIDecoder* const idec) {
+ const WebPDecoderOptions* const options = idec->params_.options;
+ WebPDecBuffer* const output = idec->params_.output;
+
+ idec->state_ = STATE_DONE;
+ if (options != NULL && options->flip) {
+ return WebPFlipBuffer(output);
+ } else {
+ return VP8_STATUS_OK;
+ }
+}
+
//------------------------------------------------------------------------------
// Macroblock-decoding contexts
static void SaveContext(const VP8Decoder* dec, const VP8BitReader* token_br,
MBContext* const context) {
- const VP8BitReader* const br = &dec->br_;
- const VP8MB* const left = dec->mb_info_ - 1;
- const VP8MB* const info = dec->mb_info_ + dec->mb_x_;
-
- context->left_ = *left;
- context->info_ = *info;
- context->br_ = *br;
+ context->left_ = dec->mb_info_[-1];
+ context->info_ = dec->mb_info_[dec->mb_x_];
context->token_br_ = *token_br;
- memcpy(context->intra_t_, dec->intra_t_ + 4 * dec->mb_x_, 4);
- memcpy(context->intra_l_, dec->intra_l_, 4);
}
static void RestoreContext(const MBContext* context, VP8Decoder* const dec,
VP8BitReader* const token_br) {
- VP8BitReader* const br = &dec->br_;
- VP8MB* const left = dec->mb_info_ - 1;
- VP8MB* const info = dec->mb_info_ + dec->mb_x_;
-
- *left = context->left_;
- *info = context->info_;
- *br = context->br_;
+ dec->mb_info_[-1] = context->left_;
+ dec->mb_info_[dec->mb_x_] = context->info_;
*token_br = context->token_br_;
- memcpy(dec->intra_t_ + 4 * dec->mb_x_, context->intra_t_, 4);
- memcpy(dec->intra_l_, context->intra_l_, 4);
}
//------------------------------------------------------------------------------
@@ -242,7 +277,7 @@ static void RestoreContext(const MBContext* context, VP8Decoder* const dec,
static VP8StatusCode IDecError(WebPIDecoder* const idec, VP8StatusCode error) {
if (idec->state_ == STATE_VP8_DATA) {
VP8Io* const io = &idec->io_;
- if (io->teardown) {
+ if (io->teardown != NULL) {
io->teardown(io);
}
}
@@ -270,6 +305,7 @@ static VP8StatusCode DecodeWebPHeaders(WebPIDecoder* const idec) {
headers.data = data;
headers.data_size = curr_size;
+ headers.have_all_data = 0;
status = WebPParseHeaders(&headers);
if (status == VP8_STATUS_NOT_ENOUGH_DATA) {
return VP8_STATUS_SUSPENDED; // We haven't found a VP8 chunk yet.
@@ -285,15 +321,9 @@ static VP8StatusCode DecodeWebPHeaders(WebPIDecoder* const idec) {
return VP8_STATUS_OUT_OF_MEMORY;
}
idec->dec_ = dec;
-#ifdef WEBP_USE_THREAD
- dec->use_threads_ = (idec->params_.options != NULL) &&
- (idec->params_.options->use_threads > 0);
-#else
- dec->use_threads_ = 0;
-#endif
dec->alpha_data_ = headers.alpha_data;
dec->alpha_data_size_ = headers.alpha_data_size;
- ChangeState(idec, STATE_VP8_FRAME_HEADER, headers.offset);
+ ChangeState(idec, STATE_VP8_HEADER, headers.offset);
} else {
VP8LDecoder* const dec = VP8LNew();
if (dec == NULL) {
@@ -308,13 +338,14 @@ static VP8StatusCode DecodeWebPHeaders(WebPIDecoder* const idec) {
static VP8StatusCode DecodeVP8FrameHeader(WebPIDecoder* const idec) {
const uint8_t* data = idec->mem_.buf_ + idec->mem_.start_;
const size_t curr_size = MemDataSize(&idec->mem_);
+ int width, height;
uint32_t bits;
if (curr_size < VP8_FRAME_HEADER_SIZE) {
// Not enough data bytes to extract VP8 Frame Header.
return VP8_STATUS_SUSPENDED;
}
- if (!VP8GetInfo(data, curr_size, idec->chunk_size_, NULL, NULL)) {
+ if (!VP8GetInfo(data, curr_size, idec->chunk_size_, &width, &height)) {
return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
}
@@ -328,30 +359,32 @@ static VP8StatusCode DecodeVP8FrameHeader(WebPIDecoder* const idec) {
}
// Partition #0
-static int CopyParts0Data(WebPIDecoder* const idec) {
+static VP8StatusCode CopyParts0Data(WebPIDecoder* const idec) {
VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
VP8BitReader* const br = &dec->br_;
- const size_t psize = br->buf_end_ - br->buf_;
+ const size_t part_size = br->buf_end_ - br->buf_;
MemBuffer* const mem = &idec->mem_;
assert(!idec->is_lossless_);
assert(mem->part0_buf_ == NULL);
- assert(psize > 0);
- assert(psize <= mem->part0_size_); // Format limit: no need for runtime check
+ // the following is a format limitation, no need for runtime check:
+ assert(part_size <= mem->part0_size_);
+ if (part_size == 0) { // can't have zero-size partition #0
+ return VP8_STATUS_BITSTREAM_ERROR;
+ }
if (mem->mode_ == MEM_MODE_APPEND) {
// We copy and grab ownership of the partition #0 data.
- uint8_t* const part0_buf = (uint8_t*)malloc(psize);
+ uint8_t* const part0_buf = (uint8_t*)WebPSafeMalloc(1ULL, part_size);
if (part0_buf == NULL) {
- return 0;
+ return VP8_STATUS_OUT_OF_MEMORY;
}
- memcpy(part0_buf, br->buf_, psize);
+ memcpy(part0_buf, br->buf_, part_size);
mem->part0_buf_ = part0_buf;
- br->buf_ = part0_buf;
- br->buf_end_ = part0_buf + psize;
+ VP8BitReaderSetBuffer(br, part0_buf, part_size);
} else {
// Else: just keep pointers to the partition #0's data in dec_->br_.
}
- mem->start_ += psize;
- return 1;
+ mem->start_ += part_size;
+ return VP8_STATUS_OK;
}
static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) {
@@ -381,9 +414,14 @@ static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) {
if (dec->status_ != VP8_STATUS_OK) {
return IDecError(idec, dec->status_);
}
+ // This change must be done before calling VP8InitFrame()
+ dec->mt_method_ = VP8GetThreadMethod(params->options, NULL,
+ io->width, io->height);
+ VP8InitDithering(params->options, dec);
- if (!CopyParts0Data(idec)) {
- return IDecError(idec, VP8_STATUS_OUT_OF_MEMORY);
+ dec->status_ = CopyParts0Data(idec);
+ if (dec->status_ != VP8_STATUS_OK) {
+ return IDecError(idec, dec->status_);
}
// Finish setting up the decoding parameters. Will call io->setup().
@@ -407,50 +445,52 @@ static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
VP8Io* const io = &idec->io_;
assert(dec->ready_);
-
for (; dec->mb_y_ < dec->mb_h_; ++dec->mb_y_) {
- VP8BitReader* token_br = &dec->parts_[dec->mb_y_ & (dec->num_parts_ - 1)];
- if (dec->mb_x_ == 0) {
- VP8InitScanline(dec);
+ if (idec->last_mb_y_ != dec->mb_y_) {
+ if (!VP8ParseIntraModeRow(&dec->br_, dec)) {
+ // note: normally, error shouldn't occur since we already have the whole
+ // partition0 available here in DecodeRemaining(). Reaching EOF while
+ // reading intra modes really means a BITSTREAM_ERROR.
+ return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
+ }
+ idec->last_mb_y_ = dec->mb_y_;
}
- for (; dec->mb_x_ < dec->mb_w_; dec->mb_x_++) {
+ for (; dec->mb_x_ < dec->mb_w_; ++dec->mb_x_) {
+ VP8BitReader* const token_br =
+ &dec->parts_[dec->mb_y_ & (dec->num_parts_ - 1)];
MBContext context;
SaveContext(dec, token_br, &context);
-
if (!VP8DecodeMB(dec, token_br)) {
- RestoreContext(&context, dec, token_br);
// We shouldn't fail when MAX_MB data was available
if (dec->num_parts_ == 1 && MemDataSize(&idec->mem_) > MAX_MB_SIZE) {
return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
}
+ RestoreContext(&context, dec, token_br);
return VP8_STATUS_SUSPENDED;
}
- VP8ReconstructBlock(dec);
- // Store data and save block's filtering params
- VP8StoreBlock(dec);
-
// Release buffer only if there is only one partition
if (dec->num_parts_ == 1) {
idec->mem_.start_ = token_br->buf_ - idec->mem_.buf_;
assert(idec->mem_.start_ <= idec->mem_.end_);
}
}
+ VP8InitScanline(dec); // Prepare for next scanline
+
+ // Reconstruct, filter and emit the row.
if (!VP8ProcessRow(dec, io)) {
return IDecError(idec, VP8_STATUS_USER_ABORT);
}
- dec->mb_x_ = 0;
}
// Synchronize the thread and check for errors.
if (!VP8ExitCritical(dec, io)) {
return IDecError(idec, VP8_STATUS_USER_ABORT);
}
dec->ready_ = 0;
- idec->state_ = STATE_DONE;
-
- return VP8_STATUS_OK;
+ return FinishDecoding(idec);
}
-static int ErrorStatusLossless(WebPIDecoder* const idec, VP8StatusCode status) {
+static VP8StatusCode ErrorStatusLossless(WebPIDecoder* const idec,
+ VP8StatusCode status) {
if (status == VP8_STATUS_SUSPENDED || status == VP8_STATUS_NOT_ENOUGH_DATA) {
return VP8_STATUS_SUSPENDED;
}
@@ -467,9 +507,15 @@ static VP8StatusCode DecodeVP8LHeader(WebPIDecoder* const idec) {
// Wait until there's enough data for decoding header.
if (curr_size < (idec->chunk_size_ >> 3)) {
- return VP8_STATUS_SUSPENDED;
+ dec->status_ = VP8_STATUS_SUSPENDED;
+ return ErrorStatusLossless(idec, dec->status_);
}
+
if (!VP8LDecodeHeader(dec, io)) {
+ if (dec->status_ == VP8_STATUS_BITSTREAM_ERROR &&
+ curr_size < idec->chunk_size_) {
+ dec->status_ = VP8_STATUS_SUSPENDED;
+ }
return ErrorStatusLossless(idec, dec->status_);
}
// Allocate/verify output buffer now.
@@ -488,33 +534,29 @@ static VP8StatusCode DecodeVP8LData(WebPIDecoder* const idec) {
const size_t curr_size = MemDataSize(&idec->mem_);
assert(idec->is_lossless_);
- // At present Lossless decoder can't decode image incrementally. So wait till
- // all the image data is aggregated before image can be decoded.
- if (curr_size < idec->chunk_size_) {
- return VP8_STATUS_SUSPENDED;
- }
+ // Switch to incremental decoding if we don't have all the bytes available.
+ dec->incremental_ = (curr_size < idec->chunk_size_);
if (!VP8LDecodeImage(dec)) {
return ErrorStatusLossless(idec, dec->status_);
}
-
- idec->state_ = STATE_DONE;
-
- return VP8_STATUS_OK;
+ assert(dec->status_ == VP8_STATUS_OK || dec->status_ == VP8_STATUS_SUSPENDED);
+ return (dec->status_ == VP8_STATUS_SUSPENDED) ? dec->status_
+ : FinishDecoding(idec);
}
// Main decoding loop
static VP8StatusCode IDecode(WebPIDecoder* idec) {
VP8StatusCode status = VP8_STATUS_SUSPENDED;
- if (idec->state_ == STATE_PRE_VP8) {
+ if (idec->state_ == STATE_WEBP_HEADER) {
status = DecodeWebPHeaders(idec);
} else {
if (idec->dec_ == NULL) {
return VP8_STATUS_SUSPENDED; // can't continue if we have no decoder.
}
}
- if (idec->state_ == STATE_VP8_FRAME_HEADER) {
+ if (idec->state_ == STATE_VP8_HEADER) {
status = DecodeVP8FrameHeader(idec);
}
if (idec->state_ == STATE_VP8_PARTS0) {
@@ -536,20 +578,23 @@ static VP8StatusCode IDecode(WebPIDecoder* idec) {
// Public functions
WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) {
- WebPIDecoder* idec = (WebPIDecoder*)calloc(1, sizeof(*idec));
+ WebPIDecoder* idec = (WebPIDecoder*)WebPSafeCalloc(1ULL, sizeof(*idec));
if (idec == NULL) {
return NULL;
}
- idec->state_ = STATE_PRE_VP8;
+ idec->state_ = STATE_WEBP_HEADER;
idec->chunk_size_ = 0;
+ idec->last_mb_y_ = -1;
+
InitMemBuffer(&idec->mem_);
WebPInitDecBuffer(&idec->output_);
VP8InitIo(&idec->io_);
WebPResetDecParams(&idec->params_);
- idec->params_.output = output_buffer ? output_buffer : &idec->output_;
+ idec->params_.output = (output_buffer != NULL) ? output_buffer
+ : &idec->output_;
WebPInitCustomIo(&idec->params_, &idec->io_); // Plug the I/O functions.
return idec;
@@ -581,14 +626,18 @@ void WebPIDelete(WebPIDecoder* idec) {
if (idec == NULL) return;
if (idec->dec_ != NULL) {
if (!idec->is_lossless_) {
- VP8Delete(idec->dec_);
+ if (idec->state_ == STATE_VP8_DATA) {
+ // Synchronize the thread, clean-up and check for errors.
+ VP8ExitCritical((VP8Decoder*)idec->dec_, &idec->io_);
+ }
+ VP8Delete((VP8Decoder*)idec->dec_);
} else {
- VP8LDelete(idec->dec_);
+ VP8LDelete((VP8LDecoder*)idec->dec_);
}
}
ClearMemBuffer(&idec->mem_);
WebPFreeDecBuffer(&idec->output_);
- free(idec);
+ WebPSafeFree(idec);
}
//------------------------------------------------------------------------------
@@ -596,12 +645,22 @@ void WebPIDelete(WebPIDecoder* idec) {
WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE mode, uint8_t* output_buffer,
size_t output_buffer_size, int output_stride) {
+ const int is_external_memory = (output_buffer != NULL);
WebPIDecoder* idec;
+
if (mode >= MODE_YUV) return NULL;
+ if (!is_external_memory) { // Overwrite parameters to sane values.
+ output_buffer_size = 0;
+ output_stride = 0;
+ } else { // A buffer was passed. Validate the other params.
+ if (output_stride == 0 || output_buffer_size == 0) {
+ return NULL; // invalid parameter.
+ }
+ }
idec = WebPINewDecoder(NULL);
if (idec == NULL) return NULL;
idec->output_.colorspace = mode;
- idec->output_.is_external_memory = 1;
+ idec->output_.is_external_memory = is_external_memory;
idec->output_.u.RGBA.rgba = output_buffer;
idec->output_.u.RGBA.stride = output_stride;
idec->output_.u.RGBA.size = output_buffer_size;
@@ -612,10 +671,30 @@ WebPIDecoder* WebPINewYUVA(uint8_t* luma, size_t luma_size, int luma_stride,
uint8_t* u, size_t u_size, int u_stride,
uint8_t* v, size_t v_size, int v_stride,
uint8_t* a, size_t a_size, int a_stride) {
- WebPIDecoder* const idec = WebPINewDecoder(NULL);
+ const int is_external_memory = (luma != NULL);
+ WebPIDecoder* idec;
+ WEBP_CSP_MODE colorspace;
+
+ if (!is_external_memory) { // Overwrite parameters to sane values.
+ luma_size = u_size = v_size = a_size = 0;
+ luma_stride = u_stride = v_stride = a_stride = 0;
+ u = v = a = NULL;
+ colorspace = MODE_YUVA;
+ } else { // A luma buffer was passed. Validate the other parameters.
+ if (u == NULL || v == NULL) return NULL;
+ if (luma_size == 0 || u_size == 0 || v_size == 0) return NULL;
+ if (luma_stride == 0 || u_stride == 0 || v_stride == 0) return NULL;
+ if (a != NULL) {
+ if (a_size == 0 || a_stride == 0) return NULL;
+ }
+ colorspace = (a == NULL) ? MODE_YUV : MODE_YUVA;
+ }
+
+ idec = WebPINewDecoder(NULL);
if (idec == NULL) return NULL;
- idec->output_.colorspace = (a == NULL) ? MODE_YUV : MODE_YUVA;
- idec->output_.is_external_memory = 1;
+
+ idec->output_.colorspace = colorspace;
+ idec->output_.is_external_memory = is_external_memory;
idec->output_.u.YUVA.y = luma;
idec->output_.u.YUVA.y_stride = luma_stride;
idec->output_.u.YUVA.y_size = luma_size;
@@ -768,7 +847,7 @@ int WebPISetIOHooks(WebPIDecoder* const idec,
VP8IoSetupHook setup,
VP8IoTeardownHook teardown,
void* user_data) {
- if (idec == NULL || idec->state_ > STATE_PRE_VP8) {
+ if (idec == NULL || idec->state_ > STATE_WEBP_HEADER) {
return 0;
}
@@ -779,7 +858,3 @@ int WebPISetIOHooks(WebPIDecoder* const idec,
return 1;
}
-
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/dec/io.c b/drivers/webp/dec/io.c
index 594804c2e6..13e469ab73 100644
--- a/drivers/webp/dec/io.c
+++ b/drivers/webp/dec/io.c
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// functions for sample output.
@@ -15,10 +17,7 @@
#include "./webpi.h"
#include "../dsp/dsp.h"
#include "../dsp/yuv.h"
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
+#include "../utils/utils.h"
//------------------------------------------------------------------------------
// Main YUV<->RGB conversion functions
@@ -46,57 +45,17 @@ static int EmitYUV(const VP8Io* const io, WebPDecParams* const p) {
// Point-sampling U/V sampler.
static int EmitSampledRGB(const VP8Io* const io, WebPDecParams* const p) {
- WebPDecBuffer* output = p->output;
- const WebPRGBABuffer* const buf = &output->u.RGBA;
- uint8_t* dst = buf->rgba + io->mb_y * buf->stride;
- const uint8_t* y_src = io->y;
- const uint8_t* u_src = io->u;
- const uint8_t* v_src = io->v;
- const WebPSampleLinePairFunc sample = WebPSamplers[output->colorspace];
- const int mb_w = io->mb_w;
- const int last = io->mb_h - 1;
- int j;
- for (j = 0; j < last; j += 2) {
- sample(y_src, y_src + io->y_stride, u_src, v_src,
- dst, dst + buf->stride, mb_w);
- y_src += 2 * io->y_stride;
- u_src += io->uv_stride;
- v_src += io->uv_stride;
- dst += 2 * buf->stride;
- }
- if (j == last) { // Just do the last line twice
- sample(y_src, y_src, u_src, v_src, dst, dst, mb_w);
- }
+ WebPDecBuffer* const output = p->output;
+ WebPRGBABuffer* const buf = &output->u.RGBA;
+ uint8_t* const dst = buf->rgba + io->mb_y * buf->stride;
+ WebPSamplerProcessPlane(io->y, io->y_stride,
+ io->u, io->v, io->uv_stride,
+ dst, buf->stride, io->mb_w, io->mb_h,
+ WebPSamplers[output->colorspace]);
return io->mb_h;
}
//------------------------------------------------------------------------------
-// YUV444 -> RGB conversion
-
-#if 0 // TODO(skal): this is for future rescaling.
-static int EmitRGB(const VP8Io* const io, WebPDecParams* const p) {
- WebPDecBuffer* output = p->output;
- const WebPRGBABuffer* const buf = &output->u.RGBA;
- uint8_t* dst = buf->rgba + io->mb_y * buf->stride;
- const uint8_t* y_src = io->y;
- const uint8_t* u_src = io->u;
- const uint8_t* v_src = io->v;
- const WebPYUV444Converter convert = WebPYUV444Converters[output->colorspace];
- const int mb_w = io->mb_w;
- const int last = io->mb_h;
- int j;
- for (j = 0; j < last; ++j) {
- convert(y_src, u_src, v_src, dst, mb_w);
- y_src += io->y_stride;
- u_src += io->uv_stride;
- v_src += io->uv_stride;
- dst += buf->stride;
- }
- return io->mb_h;
-}
-#endif
-
-//------------------------------------------------------------------------------
// Fancy upsampling
#ifdef FANCY_UPSAMPLING
@@ -117,7 +76,7 @@ static int EmitFancyRGB(const VP8Io* const io, WebPDecParams* const p) {
if (y == 0) {
// First line is special cased. We mirror the u/v samples at boundary.
- upsample(NULL, cur_y, cur_u, cur_v, cur_u, cur_v, NULL, dst, mb_w);
+ upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, dst, NULL, mb_w);
} else {
// We can finish the left-over line from previous call.
upsample(p->tmp_y, cur_y, top_u, top_v, cur_u, cur_v,
@@ -160,14 +119,16 @@ static int EmitFancyRGB(const VP8Io* const io, WebPDecParams* const p) {
//------------------------------------------------------------------------------
-static int EmitAlphaYUV(const VP8Io* const io, WebPDecParams* const p) {
+static int EmitAlphaYUV(const VP8Io* const io, WebPDecParams* const p,
+ int expected_num_lines_out) {
const uint8_t* alpha = io->a;
const WebPYUVABuffer* const buf = &p->output->u.YUVA;
const int mb_w = io->mb_w;
const int mb_h = io->mb_h;
uint8_t* dst = buf->a + io->mb_y * buf->a_stride;
int j;
-
+ (void)expected_num_lines_out;
+ assert(expected_num_lines_out == mb_h);
if (alpha != NULL) {
for (j = 0; j < mb_h; ++j) {
memcpy(dst, alpha, mb_w * sizeof(*dst));
@@ -210,7 +171,8 @@ static int GetAlphaSourceRow(const VP8Io* const io,
return start_y;
}
-static int EmitAlphaRGB(const VP8Io* const io, WebPDecParams* const p) {
+static int EmitAlphaRGB(const VP8Io* const io, WebPDecParams* const p,
+ int expected_num_lines_out) {
const uint8_t* alpha = io->a;
if (alpha != NULL) {
const int mb_w = io->mb_w;
@@ -221,21 +183,13 @@ static int EmitAlphaRGB(const VP8Io* const io, WebPDecParams* const p) {
int num_rows;
const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
uint8_t* const base_rgba = buf->rgba + start_y * buf->stride;
- uint8_t* dst = base_rgba + (alpha_first ? 0 : 3);
- uint32_t alpha_mask = 0xff;
- int i, j;
-
- for (j = 0; j < num_rows; ++j) {
- for (i = 0; i < mb_w; ++i) {
- const uint32_t alpha_value = alpha[i];
- dst[4 * i] = alpha_value;
- alpha_mask &= alpha_value;
- }
- alpha += io->width;
- dst += buf->stride;
- }
- // alpha_mask is < 0xff if there's non-trivial alpha to premultiply with.
- if (alpha_mask != 0xff && WebPIsPremultipliedMode(colorspace)) {
+ uint8_t* const dst = base_rgba + (alpha_first ? 0 : 3);
+ const int has_alpha = WebPDispatchAlpha(alpha, io->width, mb_w,
+ num_rows, dst, buf->stride);
+ (void)expected_num_lines_out;
+ assert(expected_num_lines_out == num_rows);
+ // has_alpha is true if there's non-trivial alpha to premultiply with.
+ if (has_alpha && WebPIsPremultipliedMode(colorspace)) {
WebPApplyAlphaMultiply(base_rgba, alpha_first,
mb_w, num_rows, buf->stride);
}
@@ -243,7 +197,8 @@ static int EmitAlphaRGB(const VP8Io* const io, WebPDecParams* const p) {
return 0;
}
-static int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p) {
+static int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p,
+ int expected_num_lines_out) {
const uint8_t* alpha = io->a;
if (alpha != NULL) {
const int mb_w = io->mb_w;
@@ -252,10 +207,13 @@ static int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p) {
int num_rows;
const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
uint8_t* const base_rgba = buf->rgba + start_y * buf->stride;
+#ifdef WEBP_SWAP_16BIT_CSP
+ uint8_t* alpha_dst = base_rgba;
+#else
uint8_t* alpha_dst = base_rgba + 1;
+#endif
uint32_t alpha_mask = 0x0f;
int i, j;
-
for (j = 0; j < num_rows; ++j) {
for (i = 0; i < mb_w; ++i) {
// Fill in the alpha value (converted to 4 bits).
@@ -266,6 +224,8 @@ static int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p) {
alpha += io->width;
alpha_dst += buf->stride;
}
+ (void)expected_num_lines_out;
+ assert(expected_num_lines_out == num_rows);
if (alpha_mask != 0x0f && WebPIsPremultipliedMode(colorspace)) {
WebPApplyAlphaMultiply4444(base_rgba, mb_w, num_rows, buf->stride);
}
@@ -291,15 +251,35 @@ static int Rescale(const uint8_t* src, int src_stride,
static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) {
const int mb_h = io->mb_h;
const int uv_mb_h = (mb_h + 1) >> 1;
- const int num_lines_out = Rescale(io->y, io->y_stride, mb_h, &p->scaler_y);
+ WebPRescaler* const scaler = &p->scaler_y;
+ int num_lines_out = 0;
+ if (WebPIsAlphaMode(p->output->colorspace) && io->a != NULL) {
+ // Before rescaling, we premultiply the luma directly into the io->y
+ // internal buffer. This is OK since these samples are not used for
+ // intra-prediction (the top samples are saved in cache_y_/u_/v_).
+ // But we need to cast the const away, though.
+ WebPMultRows((uint8_t*)io->y, io->y_stride,
+ io->a, io->width, io->mb_w, mb_h, 0);
+ }
+ num_lines_out = Rescale(io->y, io->y_stride, mb_h, scaler);
Rescale(io->u, io->uv_stride, uv_mb_h, &p->scaler_u);
Rescale(io->v, io->uv_stride, uv_mb_h, &p->scaler_v);
return num_lines_out;
}
-static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p) {
+static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p,
+ int expected_num_lines_out) {
if (io->a != NULL) {
- Rescale(io->a, io->width, io->mb_h, &p->scaler_a);
+ const WebPYUVABuffer* const buf = &p->output->u.YUVA;
+ uint8_t* dst_y = buf->y + p->last_y * buf->y_stride;
+ const uint8_t* src_a = buf->a + p->last_y * buf->a_stride;
+ const int num_lines_out = Rescale(io->a, io->width, io->mb_h, &p->scaler_a);
+ (void)expected_num_lines_out;
+ assert(expected_num_lines_out == num_lines_out);
+ if (num_lines_out > 0) { // unmultiply the Y
+ WebPMultRows(dst_y, buf->y_stride, src_a, buf->a_stride,
+ p->scaler_a.dst_width, num_lines_out, 1);
+ }
}
return 0;
}
@@ -316,39 +296,34 @@ static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
const size_t work_size = 2 * out_width; // scratch memory for luma rescaler
const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones
size_t tmp_size;
- int32_t* work;
+ rescaler_t* work;
- tmp_size = work_size + 2 * uv_work_size;
+ tmp_size = (work_size + 2 * uv_work_size) * sizeof(*work);
if (has_alpha) {
- tmp_size += work_size;
+ tmp_size += work_size * sizeof(*work);
}
- p->memory = calloc(1, tmp_size * sizeof(*work));
+ p->memory = WebPSafeMalloc(1ULL, tmp_size);
if (p->memory == NULL) {
return 0; // memory error
}
- work = (int32_t*)p->memory;
+ work = (rescaler_t*)p->memory;
WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h,
buf->y, out_width, out_height, buf->y_stride, 1,
- io->mb_w, out_width, io->mb_h, out_height,
work);
WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height,
buf->u, uv_out_width, uv_out_height, buf->u_stride, 1,
- uv_in_width, uv_out_width,
- uv_in_height, uv_out_height,
work + work_size);
WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height,
buf->v, uv_out_width, uv_out_height, buf->v_stride, 1,
- uv_in_width, uv_out_width,
- uv_in_height, uv_out_height,
work + work_size + uv_work_size);
p->emit = EmitRescaledYUV;
if (has_alpha) {
WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h,
buf->a, out_width, out_height, buf->a_stride, 1,
- io->mb_w, out_width, io->mb_h, out_height,
work + work_size + 2 * uv_work_size);
p->emit_alpha = EmitRescaledAlphaYUV;
+ WebPInitAlphaProcessing();
}
return 1;
}
@@ -360,13 +335,13 @@ static int ExportRGB(WebPDecParams* const p, int y_pos) {
const WebPYUV444Converter convert =
WebPYUV444Converters[p->output->colorspace];
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
- uint8_t* dst = buf->rgba + (p->last_y + y_pos) * buf->stride;
+ uint8_t* dst = buf->rgba + y_pos * buf->stride;
int num_lines_out = 0;
// For RGB rescaling, because of the YUV420, current scan position
// U/V can be +1/-1 line from the Y one. Hence the double test.
while (WebPRescalerHasPendingOutput(&p->scaler_y) &&
WebPRescalerHasPendingOutput(&p->scaler_u)) {
- assert(p->last_y + y_pos + num_lines_out < p->output->height);
+ assert(y_pos + num_lines_out < p->output->height);
assert(p->scaler_u.y_accum == p->scaler_v.y_accum);
WebPRescalerExportRow(&p->scaler_y);
WebPRescalerExportRow(&p->scaler_u);
@@ -388,65 +363,69 @@ static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) {
const int y_lines_in =
WebPRescalerImport(&p->scaler_y, mb_h - j,
io->y + j * io->y_stride, io->y_stride);
- const int u_lines_in =
- WebPRescalerImport(&p->scaler_u, uv_mb_h - uv_j,
- io->u + uv_j * io->uv_stride, io->uv_stride);
- const int v_lines_in =
- WebPRescalerImport(&p->scaler_v, uv_mb_h - uv_j,
- io->v + uv_j * io->uv_stride, io->uv_stride);
- (void)v_lines_in; // remove a gcc warning
- assert(u_lines_in == v_lines_in);
j += y_lines_in;
- uv_j += u_lines_in;
- num_lines_out += ExportRGB(p, num_lines_out);
+ if (WebPRescaleNeededLines(&p->scaler_u, uv_mb_h - uv_j)) {
+ const int u_lines_in =
+ WebPRescalerImport(&p->scaler_u, uv_mb_h - uv_j,
+ io->u + uv_j * io->uv_stride, io->uv_stride);
+ const int v_lines_in =
+ WebPRescalerImport(&p->scaler_v, uv_mb_h - uv_j,
+ io->v + uv_j * io->uv_stride, io->uv_stride);
+ (void)v_lines_in; // remove a gcc warning
+ assert(u_lines_in == v_lines_in);
+ uv_j += u_lines_in;
+ }
+ num_lines_out += ExportRGB(p, p->last_y + num_lines_out);
}
return num_lines_out;
}
-static int ExportAlpha(WebPDecParams* const p, int y_pos) {
+static int ExportAlpha(WebPDecParams* const p, int y_pos, int max_lines_out) {
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
- uint8_t* const base_rgba = buf->rgba + (p->last_y + y_pos) * buf->stride;
+ uint8_t* const base_rgba = buf->rgba + y_pos * buf->stride;
const WEBP_CSP_MODE colorspace = p->output->colorspace;
const int alpha_first =
(colorspace == MODE_ARGB || colorspace == MODE_Argb);
uint8_t* dst = base_rgba + (alpha_first ? 0 : 3);
int num_lines_out = 0;
const int is_premult_alpha = WebPIsPremultipliedMode(colorspace);
- uint32_t alpha_mask = 0xff;
+ uint32_t non_opaque = 0;
const int width = p->scaler_a.dst_width;
- while (WebPRescalerHasPendingOutput(&p->scaler_a)) {
- int i;
- assert(p->last_y + y_pos + num_lines_out < p->output->height);
+ while (WebPRescalerHasPendingOutput(&p->scaler_a) &&
+ num_lines_out < max_lines_out) {
+ assert(y_pos + num_lines_out < p->output->height);
WebPRescalerExportRow(&p->scaler_a);
- for (i = 0; i < width; ++i) {
- const uint32_t alpha_value = p->scaler_a.dst[i];
- dst[4 * i] = alpha_value;
- alpha_mask &= alpha_value;
- }
+ non_opaque |= WebPDispatchAlpha(p->scaler_a.dst, 0, width, 1, dst, 0);
dst += buf->stride;
++num_lines_out;
}
- if (is_premult_alpha && alpha_mask != 0xff) {
+ if (is_premult_alpha && non_opaque) {
WebPApplyAlphaMultiply(base_rgba, alpha_first,
width, num_lines_out, buf->stride);
}
return num_lines_out;
}
-static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos) {
+static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos,
+ int max_lines_out) {
const WebPRGBABuffer* const buf = &p->output->u.RGBA;
- uint8_t* const base_rgba = buf->rgba + (p->last_y + y_pos) * buf->stride;
+ uint8_t* const base_rgba = buf->rgba + y_pos * buf->stride;
+#ifdef WEBP_SWAP_16BIT_CSP
+ uint8_t* alpha_dst = base_rgba;
+#else
uint8_t* alpha_dst = base_rgba + 1;
+#endif
int num_lines_out = 0;
const WEBP_CSP_MODE colorspace = p->output->colorspace;
const int width = p->scaler_a.dst_width;
const int is_premult_alpha = WebPIsPremultipliedMode(colorspace);
uint32_t alpha_mask = 0x0f;
- while (WebPRescalerHasPendingOutput(&p->scaler_a)) {
+ while (WebPRescalerHasPendingOutput(&p->scaler_a) &&
+ num_lines_out < max_lines_out) {
int i;
- assert(p->last_y + y_pos + num_lines_out < p->output->height);
+ assert(y_pos + num_lines_out < p->output->height);
WebPRescalerExportRow(&p->scaler_a);
for (i = 0; i < width; ++i) {
// Fill in the alpha value (converted to 4 bits).
@@ -463,15 +442,17 @@ static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos) {
return num_lines_out;
}
-static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p) {
+static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p,
+ int expected_num_out_lines) {
if (io->a != NULL) {
WebPRescaler* const scaler = &p->scaler_a;
- int j = 0;
- int pos = 0;
- while (j < io->mb_h) {
- j += WebPRescalerImport(scaler, io->mb_h - j,
- io->a + j * io->width, io->width);
- pos += p->emit_alpha_row(p, pos);
+ int lines_left = expected_num_out_lines;
+ const int y_end = p->last_y + lines_left;
+ while (lines_left > 0) {
+ const int row_offset = scaler->src_y - io->mb_y;
+ WebPRescalerImport(scaler, io->mb_h + io->mb_y - scaler->src_y,
+ io->a + row_offset * io->width, io->width);
+ lines_left -= p->emit_alpha_row(p, y_end - lines_left, lines_left);
}
}
return 0;
@@ -484,9 +465,9 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
const int uv_in_width = (io->mb_w + 1) >> 1;
const int uv_in_height = (io->mb_h + 1) >> 1;
const size_t work_size = 2 * out_width; // scratch memory for one rescaler
- int32_t* work; // rescalers work area
+ rescaler_t* work; // rescalers work area
uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion
- size_t tmp_size1, tmp_size2;
+ size_t tmp_size1, tmp_size2, total_size;
tmp_size1 = 3 * work_size;
tmp_size2 = 3 * out_width;
@@ -494,30 +475,28 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
tmp_size1 += work_size;
tmp_size2 += out_width;
}
- p->memory = calloc(1, tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp));
+ total_size = tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp);
+ p->memory = WebPSafeMalloc(1ULL, total_size);
if (p->memory == NULL) {
return 0; // memory error
}
- work = (int32_t*)p->memory;
+ work = (rescaler_t*)p->memory;
tmp = (uint8_t*)(work + tmp_size1);
WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h,
tmp + 0 * out_width, out_width, out_height, 0, 1,
- io->mb_w, out_width, io->mb_h, out_height,
work + 0 * work_size);
WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height,
tmp + 1 * out_width, out_width, out_height, 0, 1,
- io->mb_w, 2 * out_width, io->mb_h, 2 * out_height,
work + 1 * work_size);
WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height,
tmp + 2 * out_width, out_width, out_height, 0, 1,
- io->mb_w, 2 * out_width, io->mb_h, 2 * out_height,
work + 2 * work_size);
p->emit = EmitRescaledRGB;
+ WebPInitYUV444Converters();
if (has_alpha) {
WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h,
tmp + 3 * out_width, out_width, out_height, 0, 1,
- io->mb_w, out_width, io->mb_h, out_height,
work + 3 * work_size);
p->emit_alpha = EmitRescaledAlphaRGB;
if (p->output->colorspace == MODE_RGBA_4444 ||
@@ -526,6 +505,7 @@ static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
} else {
p->emit_alpha_row = ExportAlpha;
}
+ WebPInitAlphaProcessing();
}
return 1;
}
@@ -546,7 +526,9 @@ static int CustomSetup(VP8Io* io) {
if (!WebPIoInitFromOptions(p->options, io, is_alpha ? MODE_YUV : MODE_YUVA)) {
return 0;
}
-
+ if (is_alpha && WebPIsPremultipliedMode(colorspace)) {
+ WebPInitUpsamplers();
+ }
if (io->use_scaling) {
const int ok = is_rgb ? InitRGBRescaler(io, p) : InitYUVRescaler(io, p);
if (!ok) {
@@ -554,11 +536,12 @@ static int CustomSetup(VP8Io* io) {
}
} else {
if (is_rgb) {
+ WebPInitSamplers();
p->emit = EmitSampledRGB; // default
-#ifdef FANCY_UPSAMPLING
if (io->fancy_upsampling) {
+#ifdef FANCY_UPSAMPLING
const int uv_width = (io->mb_w + 1) >> 1;
- p->memory = malloc(io->mb_w + 2 * uv_width);
+ p->memory = WebPSafeMalloc(1ULL, (size_t)(io->mb_w + 2 * uv_width));
if (p->memory == NULL) {
return 0; // memory error.
}
@@ -567,18 +550,20 @@ static int CustomSetup(VP8Io* io) {
p->tmp_v = p->tmp_u + uv_width;
p->emit = EmitFancyRGB;
WebPInitUpsamplers();
- }
#endif
+ }
} else {
p->emit = EmitYUV;
}
if (is_alpha) { // need transparency output
- if (WebPIsPremultipliedMode(colorspace)) WebPInitPremultiply();
p->emit_alpha =
(colorspace == MODE_RGBA_4444 || colorspace == MODE_rgbA_4444) ?
EmitAlphaRGBA4444
: is_rgb ? EmitAlphaRGB
: EmitAlphaYUV;
+ if (is_rgb) {
+ WebPInitAlphaProcessing();
+ }
}
}
@@ -601,8 +586,8 @@ static int CustomPut(const VP8Io* io) {
return 0;
}
num_lines_out = p->emit(io, p);
- if (p->emit_alpha) {
- p->emit_alpha(io, p);
+ if (p->emit_alpha != NULL) {
+ p->emit_alpha(io, p, num_lines_out);
}
p->last_y += num_lines_out;
return 1;
@@ -612,7 +597,7 @@ static int CustomPut(const VP8Io* io) {
static void CustomTeardown(const VP8Io* io) {
WebPDecParams* const p = (WebPDecParams*)io->opaque;
- free(p->memory);
+ WebPSafeFree(p->memory);
p->memory = NULL;
}
@@ -627,7 +612,3 @@ void WebPInitCustomIo(WebPDecParams* const params, VP8Io* const io) {
}
//------------------------------------------------------------------------------
-
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/dec/quant.c b/drivers/webp/dec/quant.c
index d54097af0d..5b648f942c 100644
--- a/drivers/webp/dec/quant.c
+++ b/drivers/webp/dec/quant.c
@@ -1,8 +1,10 @@
// Copyright 2010 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Quantizer initialization
@@ -11,10 +13,6 @@
#include "./vp8i.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
static WEBP_INLINE int clip(int v, int M) {
return v < 0 ? 0 : v > M ? M : v;
}
@@ -102,12 +100,11 @@ void VP8ParseQuant(VP8Decoder* const dec) {
m->uv_mat_[0] = kDcTable[clip(q + dquv_dc, 117)];
m->uv_mat_[1] = kAcTable[clip(q + dquv_ac, 127)];
+
+ m->uv_quant_ = q + dquv_ac; // for dithering strength evaluation
}
}
}
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/dec/tree.c b/drivers/webp/dec/tree.c
index 82484e4c55..c2007ea733 100644
--- a/drivers/webp/dec/tree.c
+++ b/drivers/webp/dec/tree.c
@@ -1,22 +1,21 @@
// Copyright 2010 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Coding trees and probas
//
// Author: Skal (pascal.massimino@gmail.com)
-#include "vp8i.h"
+#include "./vp8i.h"
+#include "../utils/bit_reader_inl.h"
#define USE_GENERIC_TREE
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
#ifdef USE_GENERIC_TREE
static const int8_t kYModesIntra4[18] = {
-B_DC_PRED, 1,
@@ -31,61 +30,12 @@ static const int8_t kYModesIntra4[18] = {
};
#endif
-#ifndef ONLY_KEYFRAME_CODE
-
-// inter prediction modes
-enum {
- LEFT4 = 0, ABOVE4 = 1, ZERO4 = 2, NEW4 = 3,
- NEARESTMV, NEARMV, ZEROMV, NEWMV, SPLITMV };
-
-static const int8_t kYModesInter[8] = {
- -DC_PRED, 1,
- 2, 3,
- -V_PRED, -H_PRED,
- -TM_PRED, -B_PRED
-};
-
-static const int8_t kMBSplit[6] = {
- -3, 1,
- -2, 2,
- -0, -1
-};
-
-static const int8_t kMVRef[8] = {
- -ZEROMV, 1,
- -NEARESTMV, 2,
- -NEARMV, 3,
- -NEWMV, -SPLITMV
-};
-
-static const int8_t kMVRef4[6] = {
- -LEFT4, 1,
- -ABOVE4, 2,
- -ZERO4, -NEW4
-};
-#endif
-
//------------------------------------------------------------------------------
// Default probabilities
-// Inter
-#ifndef ONLY_KEYFRAME_CODE
-static const uint8_t kYModeProbaInter0[4] = { 112, 86, 140, 37 };
-static const uint8_t kUVModeProbaInter0[3] = { 162, 101, 204 };
-static const uint8_t kMVProba0[2][NUM_MV_PROBAS] = {
- { 162, 128, 225, 146, 172, 147, 214, 39,
- 156, 128, 129, 132, 75, 145, 178, 206,
- 239, 254, 254 },
- { 164, 128, 204, 170, 119, 235, 140, 230,
- 228, 128, 130, 130, 74, 148, 180, 203,
- 236, 254, 254 }
-};
-#endif
-
// Paragraph 13.5
static const uint8_t
CoeffsProba0[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS] = {
- // genereated using vp8_default_coef_probs() in entropy.c:129
{ { { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
{ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
{ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }
@@ -326,28 +276,38 @@ static const uint8_t kBModesProba[NUM_BMODES][NUM_BMODES][NUM_BMODES - 1] = {
void VP8ResetProba(VP8Proba* const proba) {
memset(proba->segments_, 255u, sizeof(proba->segments_));
- memcpy(proba->coeffs_, CoeffsProba0, sizeof(CoeffsProba0));
-#ifndef ONLY_KEYFRAME_CODE
- memcpy(proba->mv_, kMVProba0, sizeof(kMVProba0));
- memcpy(proba->ymode_, kYModeProbaInter0, sizeof(kYModeProbaInter0));
- memcpy(proba->uvmode_, kUVModeProbaInter0, sizeof(kUVModeProbaInter0));
-#endif
+ // proba->bands_[][] is initialized later
}
-void VP8ParseIntraMode(VP8BitReader* const br, VP8Decoder* const dec) {
- uint8_t* const top = dec->intra_t_ + 4 * dec->mb_x_;
+static void ParseIntraMode(VP8BitReader* const br,
+ VP8Decoder* const dec, int mb_x) {
+ uint8_t* const top = dec->intra_t_ + 4 * mb_x;
uint8_t* const left = dec->intra_l_;
- // Hardcoded 16x16 intra-mode decision tree.
- dec->is_i4x4_ = !VP8GetBit(br, 145); // decide for B_PRED first
- if (!dec->is_i4x4_) {
+ VP8MBData* const block = dec->mb_data_ + mb_x;
+
+ // Note: we don't save segment map (yet), as we don't expect
+ // to decode more than 1 keyframe.
+ if (dec->segment_hdr_.update_map_) {
+ // Hardcoded tree parsing
+ block->segment_ = !VP8GetBit(br, dec->proba_.segments_[0])
+ ? VP8GetBit(br, dec->proba_.segments_[1])
+ : 2 + VP8GetBit(br, dec->proba_.segments_[2]);
+ } else {
+ block->segment_ = 0; // default for intra
+ }
+ if (dec->use_skip_proba_) block->skip_ = VP8GetBit(br, dec->skip_p_);
+
+ block->is_i4x4_ = !VP8GetBit(br, 145); // decide for B_PRED first
+ if (!block->is_i4x4_) {
+ // Hardcoded 16x16 intra-mode decision tree.
const int ymode =
VP8GetBit(br, 156) ? (VP8GetBit(br, 128) ? TM_PRED : H_PRED)
: (VP8GetBit(br, 163) ? V_PRED : DC_PRED);
- dec->imodes_[0] = ymode;
- memset(top, ymode, 4 * sizeof(top[0]));
- memset(left, ymode, 4 * sizeof(left[0]));
+ block->imodes_[0] = ymode;
+ memset(top, ymode, 4 * sizeof(*top));
+ memset(left, ymode, 4 * sizeof(*left));
} else {
- uint8_t* modes = dec->imodes_;
+ uint8_t* modes = block->imodes_;
int y;
for (y = 0; y < 4; ++y) {
int ymode = left[y];
@@ -356,10 +316,10 @@ void VP8ParseIntraMode(VP8BitReader* const br, VP8Decoder* const dec) {
const uint8_t* const prob = kBModesProba[top[x]][ymode];
#ifdef USE_GENERIC_TREE
// Generic tree-parsing
- int i = 0;
- do {
+ int i = kYModesIntra4[VP8GetBit(br, prob[0])];
+ while (i > 0) {
i = kYModesIntra4[2 * i + VP8GetBit(br, prob[i])];
- } while (i > 0);
+ }
ymode = -i;
#else
// Hardcoded tree parsing
@@ -374,15 +334,24 @@ void VP8ParseIntraMode(VP8BitReader* const br, VP8Decoder* const dec) {
(!VP8GetBit(br, prob[8]) ? B_HD_PRED : B_HU_PRED)));
#endif // USE_GENERIC_TREE
top[x] = ymode;
- *modes++ = ymode;
}
+ memcpy(modes, top, 4 * sizeof(*top));
+ modes += 4;
left[y] = ymode;
}
}
// Hardcoded UVMode decision tree
- dec->uvmode_ = !VP8GetBit(br, 142) ? DC_PRED
- : !VP8GetBit(br, 114) ? V_PRED
- : VP8GetBit(br, 183) ? TM_PRED : H_PRED;
+ block->uvmode_ = !VP8GetBit(br, 142) ? DC_PRED
+ : !VP8GetBit(br, 114) ? V_PRED
+ : VP8GetBit(br, 183) ? TM_PRED : H_PRED;
+}
+
+int VP8ParseIntraModeRow(VP8BitReader* const br, VP8Decoder* const dec) {
+ int mb_x;
+ for (mb_x = 0; mb_x < dec->mb_w_; ++mb_x) {
+ ParseIntraMode(br, dec, mb_x);
+ }
+ return !dec->br_.eof_;
}
//------------------------------------------------------------------------------
@@ -524,18 +493,13 @@ static const uint8_t
}
};
-#ifndef ONLY_KEYFRAME_CODE
-static const uint8_t MVUpdateProba[2][NUM_MV_PROBAS] = {
- { 237, 246, 253, 253, 254, 254, 254, 254,
- 254, 254, 254, 254, 254, 254, 250, 250,
- 252, 254, 254 },
- { 231, 243, 245, 253, 254, 254, 254, 254,
- 254, 254, 254, 254, 254, 254, 251, 251,
- 254, 254, 254 }
+// Paragraph 9.9
+
+static const int kBands[16 + 1] = {
+ 0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7,
+ 0 // extra entry as sentinel
};
-#endif
-// Paragraph 9.9
void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec) {
VP8Proba* const proba = &dec->proba_;
int t, b, c, p;
@@ -543,47 +507,19 @@ void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec) {
for (b = 0; b < NUM_BANDS; ++b) {
for (c = 0; c < NUM_CTX; ++c) {
for (p = 0; p < NUM_PROBAS; ++p) {
- if (VP8GetBit(br, CoeffsUpdateProba[t][b][c][p])) {
- proba->coeffs_[t][b][c][p] = VP8GetValue(br, 8);
- }
+ const int v = VP8GetBit(br, CoeffsUpdateProba[t][b][c][p]) ?
+ VP8GetValue(br, 8) : CoeffsProba0[t][b][c][p];
+ proba->bands_[t][b].probas_[c][p] = v;
}
}
}
+ for (b = 0; b < 16 + 1; ++b) {
+ proba->bands_ptr_[t][b] = &proba->bands_[t][kBands[b]];
+ }
}
dec->use_skip_proba_ = VP8Get(br);
if (dec->use_skip_proba_) {
dec->skip_p_ = VP8GetValue(br, 8);
}
-#ifndef ONLY_KEYFRAME_CODE
- if (!dec->frm_hdr_.key_frame_) {
- int i;
- dec->intra_p_ = VP8GetValue(br, 8);
- dec->last_p_ = VP8GetValue(br, 8);
- dec->golden_p_ = VP8GetValue(br, 8);
- if (VP8Get(br)) { // update y-mode
- for (i = 0; i < 4; ++i) {
- proba->ymode_[i] = VP8GetValue(br, 8);
- }
- }
- if (VP8Get(br)) { // update uv-mode
- for (i = 0; i < 3; ++i) {
- proba->uvmode_[i] = VP8GetValue(br, 8);
- }
- }
- // update MV
- for (i = 0; i < 2; ++i) {
- int k;
- for (k = 0; k < NUM_MV_PROBAS; ++k) {
- if (VP8GetBit(br, MVUpdateProba[i][k])) {
- const int v = VP8GetValue(br, 7);
- proba->mv_[i][k] = v ? v << 1 : 1;
- }
- }
- }
- }
-#endif
}
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/dec/vp8.c b/drivers/webp/dec/vp8.c
index b0ccfa2a06..d89eb1c59e 100644
--- a/drivers/webp/dec/vp8.c
+++ b/drivers/webp/dec/vp8.c
@@ -1,8 +1,10 @@
// Copyright 2010 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// main entry for the decoder
@@ -11,14 +13,12 @@
#include <stdlib.h>
+#include "./alphai.h"
#include "./vp8i.h"
#include "./vp8li.h"
#include "./webpi.h"
-#include "../utils/bit_reader.h"
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
+#include "../utils/bit_reader_inl.h"
+#include "../utils/utils.h"
//------------------------------------------------------------------------------
@@ -45,10 +45,10 @@ int VP8InitIoInternal(VP8Io* const io, int version) {
}
VP8Decoder* VP8New(void) {
- VP8Decoder* const dec = (VP8Decoder*)calloc(1, sizeof(*dec));
+ VP8Decoder* const dec = (VP8Decoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
if (dec != NULL) {
SetOk(dec);
- WebPWorkerInit(&dec->worker_);
+ WebPGetWorkerInterface()->Init(&dec->worker_);
dec->ready_ = 0;
dec->num_parts_ = 1;
}
@@ -69,16 +69,13 @@ const char* VP8StatusMessage(VP8Decoder* const dec) {
void VP8Delete(VP8Decoder* const dec) {
if (dec != NULL) {
VP8Clear(dec);
- free(dec);
+ WebPSafeFree(dec);
}
}
int VP8SetError(VP8Decoder* const dec,
VP8StatusCode error, const char* const msg) {
- // TODO This check would be unnecessary if alpha decompression was separated
- // from VP8ProcessRow/FinishRow. This avoids setting 'dec->status_' to
- // something other than VP8_STATUS_BITSTREAM_ERROR on alpha decompression
- // failure.
+ // The oldest error reported takes precedence over the new one.
if (dec->status_ == VP8_STATUS_OK) {
dec->status_ = error;
dec->error_msg_ = msg;
@@ -121,6 +118,9 @@ int VP8GetInfo(const uint8_t* data, size_t data_size, size_t chunk_size,
if (((bits >> 5)) >= chunk_size) { // partition_length
return 0; // inconsistent size information.
}
+ if (w == 0 || h == 0) {
+ return 0; // We don't support both width and height to be zero.
+ }
if (width) {
*width = w;
@@ -190,25 +190,27 @@ static VP8StatusCode ParsePartitions(VP8Decoder* const dec,
const uint8_t* sz = buf;
const uint8_t* buf_end = buf + size;
const uint8_t* part_start;
- int last_part;
- int p;
+ size_t size_left = size;
+ size_t last_part;
+ size_t p;
dec->num_parts_ = 1 << VP8GetValue(br, 2);
last_part = dec->num_parts_ - 1;
- part_start = buf + last_part * 3;
- if (buf_end < part_start) {
+ if (size < 3 * last_part) {
// we can't even read the sizes with sz[]! That's a failure.
return VP8_STATUS_NOT_ENOUGH_DATA;
}
+ part_start = buf + last_part * 3;
+ size_left -= last_part * 3;
for (p = 0; p < last_part; ++p) {
- const uint32_t psize = sz[0] | (sz[1] << 8) | (sz[2] << 16);
- const uint8_t* part_end = part_start + psize;
- if (part_end > buf_end) part_end = buf_end;
- VP8InitBitReader(dec->parts_ + p, part_start, part_end);
- part_start = part_end;
+ size_t psize = sz[0] | (sz[1] << 8) | (sz[2] << 16);
+ if (psize > size_left) psize = size_left;
+ VP8InitBitReader(dec->parts_ + p, part_start, psize);
+ part_start += psize;
+ size_left -= psize;
sz += 3;
}
- VP8InitBitReader(dec->parts_ + last_part, part_start, buf_end);
+ VP8InitBitReader(dec->parts_ + last_part, part_start, size_left);
return (part_start < buf_end) ? VP8_STATUS_OK :
VP8_STATUS_SUSPENDED; // Init is ok, but there's not enough data
}
@@ -236,20 +238,6 @@ static int ParseFilterHeader(VP8BitReader* br, VP8Decoder* const dec) {
}
}
dec->filter_type_ = (hdr->level_ == 0) ? 0 : hdr->simple_ ? 1 : 2;
- if (dec->filter_type_ > 0) { // precompute filter levels per segment
- if (dec->segment_hdr_.use_segment_) {
- int s;
- for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
- int strength = dec->segment_hdr_.filter_strength_[s];
- if (!dec->segment_hdr_.absolute_delta_) {
- strength += hdr->level_;
- }
- dec->filter_levels_[s] = strength;
- }
- } else {
- dec->filter_levels_[0] = hdr->level_;
- }
- }
return !br->eof_;
}
@@ -261,7 +249,6 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
VP8PictureHeader* pic_hdr;
VP8BitReader* br;
VP8StatusCode status;
- WebPHeaderStructure headers;
if (dec == NULL) {
return 0;
@@ -271,33 +258,8 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
return VP8SetError(dec, VP8_STATUS_INVALID_PARAM,
"null VP8Io passed to VP8GetHeaders()");
}
-
- // Process Pre-VP8 chunks.
- headers.data = io->data;
- headers.data_size = io->data_size;
- status = WebPParseHeaders(&headers);
- if (status != VP8_STATUS_OK) {
- return VP8SetError(dec, status, "Incorrect/incomplete header.");
- }
- if (headers.is_lossless) {
- return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
- "Unexpected lossless format encountered.");
- }
-
- if (dec->alpha_data_ == NULL) {
- assert(dec->alpha_data_size_ == 0);
- // We have NOT set alpha data yet. Set it now.
- // (This is to ensure that dec->alpha_data_ is NOT reset to NULL if
- // WebPParseHeaders() is called more than once, as in incremental decoding
- // case.)
- dec->alpha_data_ = headers.alpha_data;
- dec->alpha_data_size_ = headers.alpha_data_size;
- }
-
- // Process the VP8 frame header.
- buf = headers.data + headers.offset;
- buf_size = headers.data_size - headers.offset;
- assert(headers.data_size >= headers.offset); // WebPParseHeaders' guarantee
+ buf = io->data;
+ buf_size = io->data_size;
if (buf_size < 4) {
return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
"Truncated header.");
@@ -355,7 +317,6 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
VP8ResetProba(&dec->proba_);
ResetSegmentHeader(&dec->segment_hdr_);
- dec->segment_ = 0; // default for intra
}
// Check if we have all the partition #0 available, and initialize dec->br_
@@ -366,7 +327,7 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
}
br = &dec->br_;
- VP8InitBitReader(br, buf, buf + frm_hdr->partition_length_);
+ VP8InitBitReader(br, buf, frm_hdr->partition_length_);
buf += frm_hdr->partition_length_;
buf_size -= frm_hdr->partition_length_;
@@ -393,63 +354,14 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
// Frame buffer marking
if (!frm_hdr->key_frame_) {
- // Paragraph 9.7
-#ifndef ONLY_KEYFRAME_CODE
- dec->buffer_flags_ = VP8Get(br) << 0; // update golden
- dec->buffer_flags_ |= VP8Get(br) << 1; // update alt ref
- if (!(dec->buffer_flags_ & 1)) {
- dec->buffer_flags_ |= VP8GetValue(br, 2) << 2;
- }
- if (!(dec->buffer_flags_ & 2)) {
- dec->buffer_flags_ |= VP8GetValue(br, 2) << 4;
- }
- dec->buffer_flags_ |= VP8Get(br) << 6; // sign bias golden
- dec->buffer_flags_ |= VP8Get(br) << 7; // sign bias alt ref
-#else
return VP8SetError(dec, VP8_STATUS_UNSUPPORTED_FEATURE,
"Not a key frame.");
-#endif
- } else {
- dec->buffer_flags_ = 0x003 | 0x100;
}
- // Paragraph 9.8
-#ifndef ONLY_KEYFRAME_CODE
- dec->update_proba_ = VP8Get(br);
- if (!dec->update_proba_) { // save for later restore
- dec->proba_saved_ = dec->proba_;
- }
- dec->buffer_flags_ &= 1 << 8;
- dec->buffer_flags_ |=
- (frm_hdr->key_frame_ || VP8Get(br)) << 8; // refresh last frame
-#else
- VP8Get(br); // just ignore the value of update_proba_
-#endif
+ VP8Get(br); // ignore the value of update_proba_
VP8ParseProba(br, dec);
-#ifdef WEBP_EXPERIMENTAL_FEATURES
- // Extensions
- if (dec->pic_hdr_.colorspace_) {
- const size_t kTrailerSize = 8;
- const uint8_t kTrailerMarker = 0x01;
- const uint8_t* ext_buf = buf - kTrailerSize;
- size_t size;
-
- if (frm_hdr->partition_length_ < kTrailerSize ||
- ext_buf[kTrailerSize - 1] != kTrailerMarker) {
- return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
- "RIFF: Inconsistent extra information.");
- }
-
- // Layer
- size = (ext_buf[0] << 0) | (ext_buf[1] << 8) | (ext_buf[2] << 16);
- dec->layer_data_size_ = size;
- dec->layer_data_ = NULL; // will be set later
- dec->layer_colorspace_ = ext_buf[3];
- }
-#endif
-
// sanitized state
dec->ready_ = 1;
return 1;
@@ -458,11 +370,6 @@ int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
//------------------------------------------------------------------------------
// Residual decoding (Paragraph 13.2 / 13.3)
-static const uint8_t kBands[16 + 1] = {
- 0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7,
- 0 // extra entry as sentinel
-};
-
static const uint8_t kCat3[] = { 173, 148, 140, 0 };
static const uint8_t kCat4[] = { 176, 155, 140, 135, 0 };
static const uint8_t kCat5[] = { 180, 157, 141, 134, 130, 0 };
@@ -473,253 +380,226 @@ static const uint8_t kZigzag[16] = {
0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15
};
-typedef const uint8_t (*ProbaArray)[NUM_CTX][NUM_PROBAS]; // for const-casting
+// See section 13-2: http://tools.ietf.org/html/rfc6386#section-13.2
+static int GetLargeValue(VP8BitReader* const br, const uint8_t* const p) {
+ int v;
+ if (!VP8GetBit(br, p[3])) {
+ if (!VP8GetBit(br, p[4])) {
+ v = 2;
+ } else {
+ v = 3 + VP8GetBit(br, p[5]);
+ }
+ } else {
+ if (!VP8GetBit(br, p[6])) {
+ if (!VP8GetBit(br, p[7])) {
+ v = 5 + VP8GetBit(br, 159);
+ } else {
+ v = 7 + 2 * VP8GetBit(br, 165);
+ v += VP8GetBit(br, 145);
+ }
+ } else {
+ const uint8_t* tab;
+ const int bit1 = VP8GetBit(br, p[8]);
+ const int bit0 = VP8GetBit(br, p[9 + bit1]);
+ const int cat = 2 * bit1 + bit0;
+ v = 0;
+ for (tab = kCat3456[cat]; *tab; ++tab) {
+ v += v + VP8GetBit(br, *tab);
+ }
+ v += 3 + (8 << cat);
+ }
+ }
+ return v;
+}
// Returns the position of the last non-zero coeff plus one
-// (and 0 if there's no coeff at all)
-static int GetCoeffs(VP8BitReader* const br, ProbaArray prob,
+static int GetCoeffs(VP8BitReader* const br, const VP8BandProbas* const prob[],
int ctx, const quant_t dq, int n, int16_t* out) {
- // n is either 0 or 1 here. kBands[n] is not necessary for extracting '*p'.
- const uint8_t* p = prob[n][ctx];
- if (!VP8GetBit(br, p[0])) { // first EOB is more a 'CBP' bit.
- return 0;
- }
- while (1) {
- ++n;
- if (!VP8GetBit(br, p[1])) {
- p = prob[kBands[n]][0];
- } else { // non zero coeff
- int v, j;
+ const uint8_t* p = prob[n]->probas_[ctx];
+ for (; n < 16; ++n) {
+ if (!VP8GetBit(br, p[0])) {
+ return n; // previous coeff was last non-zero coeff
+ }
+ while (!VP8GetBit(br, p[1])) { // sequence of zero coeffs
+ p = prob[++n]->probas_[0];
+ if (n == 16) return 16;
+ }
+ { // non zero coeff
+ const VP8ProbaArray* const p_ctx = &prob[n + 1]->probas_[0];
+ int v;
if (!VP8GetBit(br, p[2])) {
- p = prob[kBands[n]][1];
v = 1;
+ p = p_ctx[1];
} else {
- if (!VP8GetBit(br, p[3])) {
- if (!VP8GetBit(br, p[4])) {
- v = 2;
- } else {
- v = 3 + VP8GetBit(br, p[5]);
- }
- } else {
- if (!VP8GetBit(br, p[6])) {
- if (!VP8GetBit(br, p[7])) {
- v = 5 + VP8GetBit(br, 159);
- } else {
- v = 7 + 2 * VP8GetBit(br, 165);
- v += VP8GetBit(br, 145);
- }
- } else {
- const uint8_t* tab;
- const int bit1 = VP8GetBit(br, p[8]);
- const int bit0 = VP8GetBit(br, p[9 + bit1]);
- const int cat = 2 * bit1 + bit0;
- v = 0;
- for (tab = kCat3456[cat]; *tab; ++tab) {
- v += v + VP8GetBit(br, *tab);
- }
- v += 3 + (8 << cat);
- }
- }
- p = prob[kBands[n]][2];
+ v = GetLargeValue(br, p);
+ p = p_ctx[2];
}
- j = kZigzag[n - 1];
- out[j] = VP8GetSigned(br, v) * dq[j > 0];
- if (n == 16 || !VP8GetBit(br, p[0])) { // EOB
- return n;
- }
- }
- if (n == 16) {
- return 16;
+ out[kZigzag[n]] = VP8GetSigned(br, v) * dq[n > 0];
}
}
+ return 16;
}
-// Alias-safe way of converting 4bytes to 32bits.
-typedef union {
- uint8_t i8[4];
- uint32_t i32;
-} PackedNz;
-
-// Table to unpack four bits into four bytes
-static const PackedNz kUnpackTab[16] = {
- {{0, 0, 0, 0}}, {{1, 0, 0, 0}}, {{0, 1, 0, 0}}, {{1, 1, 0, 0}},
- {{0, 0, 1, 0}}, {{1, 0, 1, 0}}, {{0, 1, 1, 0}}, {{1, 1, 1, 0}},
- {{0, 0, 0, 1}}, {{1, 0, 0, 1}}, {{0, 1, 0, 1}}, {{1, 1, 0, 1}},
- {{0, 0, 1, 1}}, {{1, 0, 1, 1}}, {{0, 1, 1, 1}}, {{1, 1, 1, 1}} };
-
-// Macro to pack four LSB of four bytes into four bits.
-#if defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || \
- defined(__BIG_ENDIAN__)
-#define PACK_CST 0x08040201U
-#else
-#define PACK_CST 0x01020408U
-#endif
-#define PACK(X, S) ((((X).i32 * PACK_CST) & 0xff000000) >> (S))
-
-static void ParseResiduals(VP8Decoder* const dec,
- VP8MB* const mb, VP8BitReader* const token_br) {
- int out_t_nz, out_l_nz, first;
- ProbaArray ac_prob;
- const VP8QuantMatrix* q = &dec->dqm_[dec->segment_];
- int16_t* dst = dec->coeffs_;
+static WEBP_INLINE uint32_t NzCodeBits(uint32_t nz_coeffs, int nz, int dc_nz) {
+ nz_coeffs <<= 2;
+ nz_coeffs |= (nz > 3) ? 3 : (nz > 1) ? 2 : dc_nz;
+ return nz_coeffs;
+}
+
+static int ParseResiduals(VP8Decoder* const dec,
+ VP8MB* const mb, VP8BitReader* const token_br) {
+ const VP8BandProbas* (* const bands)[16 + 1] = dec->proba_.bands_ptr_;
+ const VP8BandProbas* const * ac_proba;
+ VP8MBData* const block = dec->mb_data_ + dec->mb_x_;
+ const VP8QuantMatrix* const q = &dec->dqm_[block->segment_];
+ int16_t* dst = block->coeffs_;
VP8MB* const left_mb = dec->mb_info_ - 1;
- PackedNz nz_ac, nz_dc;
- PackedNz tnz, lnz;
- uint32_t non_zero_ac = 0;
- uint32_t non_zero_dc = 0;
+ uint8_t tnz, lnz;
+ uint32_t non_zero_y = 0;
+ uint32_t non_zero_uv = 0;
int x, y, ch;
+ uint32_t out_t_nz, out_l_nz;
+ int first;
- nz_dc.i32 = nz_ac.i32 = 0;
memset(dst, 0, 384 * sizeof(*dst));
- if (!dec->is_i4x4_) { // parse DC
+ if (!block->is_i4x4_) { // parse DC
int16_t dc[16] = { 0 };
- const int ctx = mb->dc_nz_ + left_mb->dc_nz_;
- mb->dc_nz_ = left_mb->dc_nz_ =
- (GetCoeffs(token_br, (ProbaArray)dec->proba_.coeffs_[1],
- ctx, q->y2_mat_, 0, dc) > 0);
+ const int ctx = mb->nz_dc_ + left_mb->nz_dc_;
+ const int nz = GetCoeffs(token_br, bands[1], ctx, q->y2_mat_, 0, dc);
+ mb->nz_dc_ = left_mb->nz_dc_ = (nz > 0);
+ if (nz > 1) { // more than just the DC -> perform the full transform
+ VP8TransformWHT(dc, dst);
+ } else { // only DC is non-zero -> inlined simplified transform
+ int i;
+ const int dc0 = (dc[0] + 3) >> 3;
+ for (i = 0; i < 16 * 16; i += 16) dst[i] = dc0;
+ }
first = 1;
- ac_prob = (ProbaArray)dec->proba_.coeffs_[0];
- VP8TransformWHT(dc, dst);
+ ac_proba = bands[0];
} else {
first = 0;
- ac_prob = (ProbaArray)dec->proba_.coeffs_[3];
+ ac_proba = bands[3];
}
- tnz = kUnpackTab[mb->nz_ & 0xf];
- lnz = kUnpackTab[left_mb->nz_ & 0xf];
+ tnz = mb->nz_ & 0x0f;
+ lnz = left_mb->nz_ & 0x0f;
for (y = 0; y < 4; ++y) {
- int l = lnz.i8[y];
+ int l = lnz & 1;
+ uint32_t nz_coeffs = 0;
for (x = 0; x < 4; ++x) {
- const int ctx = l + tnz.i8[x];
- const int nz = GetCoeffs(token_br, ac_prob, ctx,
- q->y1_mat_, first, dst);
- tnz.i8[x] = l = (nz > 0);
- nz_dc.i8[x] = (dst[0] != 0);
- nz_ac.i8[x] = (nz > 1);
+ const int ctx = l + (tnz & 1);
+ const int nz = GetCoeffs(token_br, ac_proba, ctx, q->y1_mat_, first, dst);
+ l = (nz > first);
+ tnz = (tnz >> 1) | (l << 7);
+ nz_coeffs = NzCodeBits(nz_coeffs, nz, dst[0] != 0);
dst += 16;
}
- lnz.i8[y] = l;
- non_zero_dc |= PACK(nz_dc, 24 - y * 4);
- non_zero_ac |= PACK(nz_ac, 24 - y * 4);
+ tnz >>= 4;
+ lnz = (lnz >> 1) | (l << 7);
+ non_zero_y = (non_zero_y << 8) | nz_coeffs;
}
- out_t_nz = PACK(tnz, 24);
- out_l_nz = PACK(lnz, 24);
+ out_t_nz = tnz;
+ out_l_nz = lnz >> 4;
- tnz = kUnpackTab[mb->nz_ >> 4];
- lnz = kUnpackTab[left_mb->nz_ >> 4];
for (ch = 0; ch < 4; ch += 2) {
+ uint32_t nz_coeffs = 0;
+ tnz = mb->nz_ >> (4 + ch);
+ lnz = left_mb->nz_ >> (4 + ch);
for (y = 0; y < 2; ++y) {
- int l = lnz.i8[ch + y];
+ int l = lnz & 1;
for (x = 0; x < 2; ++x) {
- const int ctx = l + tnz.i8[ch + x];
- const int nz =
- GetCoeffs(token_br, (ProbaArray)dec->proba_.coeffs_[2],
- ctx, q->uv_mat_, 0, dst);
- tnz.i8[ch + x] = l = (nz > 0);
- nz_dc.i8[y * 2 + x] = (dst[0] != 0);
- nz_ac.i8[y * 2 + x] = (nz > 1);
+ const int ctx = l + (tnz & 1);
+ const int nz = GetCoeffs(token_br, bands[2], ctx, q->uv_mat_, 0, dst);
+ l = (nz > 0);
+ tnz = (tnz >> 1) | (l << 3);
+ nz_coeffs = NzCodeBits(nz_coeffs, nz, dst[0] != 0);
dst += 16;
}
- lnz.i8[ch + y] = l;
+ tnz >>= 2;
+ lnz = (lnz >> 1) | (l << 5);
}
- non_zero_dc |= PACK(nz_dc, 8 - ch * 2);
- non_zero_ac |= PACK(nz_ac, 8 - ch * 2);
+ // Note: we don't really need the per-4x4 details for U/V blocks.
+ non_zero_uv |= nz_coeffs << (4 * ch);
+ out_t_nz |= (tnz << 4) << ch;
+ out_l_nz |= (lnz & 0xf0) << ch;
}
- out_t_nz |= PACK(tnz, 20);
- out_l_nz |= PACK(lnz, 20);
mb->nz_ = out_t_nz;
left_mb->nz_ = out_l_nz;
- dec->non_zero_ac_ = non_zero_ac;
- dec->non_zero_ = non_zero_ac | non_zero_dc;
- mb->skip_ = !dec->non_zero_;
+ block->non_zero_y_ = non_zero_y;
+ block->non_zero_uv_ = non_zero_uv;
+
+ // We look at the mode-code of each block and check if some blocks have less
+ // than three non-zero coeffs (code < 2). This is to avoid dithering flat and
+ // empty blocks.
+ block->dither_ = (non_zero_uv & 0xaaaa) ? 0 : q->dither_;
+
+ return !(non_zero_y | non_zero_uv); // will be used for further optimization
}
-#undef PACK
//------------------------------------------------------------------------------
// Main loop
int VP8DecodeMB(VP8Decoder* const dec, VP8BitReader* const token_br) {
- VP8BitReader* const br = &dec->br_;
VP8MB* const left = dec->mb_info_ - 1;
- VP8MB* const info = dec->mb_info_ + dec->mb_x_;
-
- // Note: we don't save segment map (yet), as we don't expect
- // to decode more than 1 keyframe.
- if (dec->segment_hdr_.update_map_) {
- // Hardcoded tree parsing
- dec->segment_ = !VP8GetBit(br, dec->proba_.segments_[0]) ?
- VP8GetBit(br, dec->proba_.segments_[1]) :
- 2 + VP8GetBit(br, dec->proba_.segments_[2]);
- }
- info->skip_ = dec->use_skip_proba_ ? VP8GetBit(br, dec->skip_p_) : 0;
+ VP8MB* const mb = dec->mb_info_ + dec->mb_x_;
+ VP8MBData* const block = dec->mb_data_ + dec->mb_x_;
+ int skip = dec->use_skip_proba_ ? block->skip_ : 0;
- VP8ParseIntraMode(br, dec);
- if (br->eof_) {
- return 0;
- }
-
- if (!info->skip_) {
- ParseResiduals(dec, info, token_br);
+ if (!skip) {
+ skip = ParseResiduals(dec, mb, token_br);
} else {
- left->nz_ = info->nz_ = 0;
- if (!dec->is_i4x4_) {
- left->dc_nz_ = info->dc_nz_ = 0;
+ left->nz_ = mb->nz_ = 0;
+ if (!block->is_i4x4_) {
+ left->nz_dc_ = mb->nz_dc_ = 0;
}
- dec->non_zero_ = 0;
- dec->non_zero_ac_ = 0;
+ block->non_zero_y_ = 0;
+ block->non_zero_uv_ = 0;
+ block->dither_ = 0;
+ }
+
+ if (dec->filter_type_ > 0) { // store filter info
+ VP8FInfo* const finfo = dec->f_info_ + dec->mb_x_;
+ *finfo = dec->fstrengths_[block->segment_][block->is_i4x4_];
+ finfo->f_inner_ |= !skip;
}
- return (!token_br->eof_);
+ return !token_br->eof_;
}
void VP8InitScanline(VP8Decoder* const dec) {
VP8MB* const left = dec->mb_info_ - 1;
left->nz_ = 0;
- left->dc_nz_ = 0;
+ left->nz_dc_ = 0;
memset(dec->intra_l_, B_DC_PRED, sizeof(dec->intra_l_));
- dec->filter_row_ =
- (dec->filter_type_ > 0) &&
- (dec->mb_y_ >= dec->tl_mb_y_) && (dec->mb_y_ <= dec->br_mb_y_);
+ dec->mb_x_ = 0;
}
static int ParseFrame(VP8Decoder* const dec, VP8Io* io) {
for (dec->mb_y_ = 0; dec->mb_y_ < dec->br_mb_y_; ++dec->mb_y_) {
+ // Parse bitstream for this row.
VP8BitReader* const token_br =
&dec->parts_[dec->mb_y_ & (dec->num_parts_ - 1)];
- VP8InitScanline(dec);
- for (dec->mb_x_ = 0; dec->mb_x_ < dec->mb_w_; dec->mb_x_++) {
+ if (!VP8ParseIntraModeRow(&dec->br_, dec)) {
+ return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
+ "Premature end-of-partition0 encountered.");
+ }
+ for (; dec->mb_x_ < dec->mb_w_; ++dec->mb_x_) {
if (!VP8DecodeMB(dec, token_br)) {
return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
"Premature end-of-file encountered.");
}
- VP8ReconstructBlock(dec);
-
- // Store data and save block's filtering params
- VP8StoreBlock(dec);
}
+ VP8InitScanline(dec); // Prepare for next scanline
+
+ // Reconstruct, filter and emit the row.
if (!VP8ProcessRow(dec, io)) {
return VP8SetError(dec, VP8_STATUS_USER_ABORT, "Output aborted.");
}
}
- if (dec->use_threads_ && !WebPWorkerSync(&dec->worker_)) {
- return 0;
- }
-
- // Finish
-#ifndef ONLY_KEYFRAME_CODE
- if (!dec->update_proba_) {
- dec->proba_ = dec->proba_saved_;
+ if (dec->mt_method_ > 0) {
+ if (!WebPGetWorkerInterface()->Sync(&dec->worker_)) return 0;
}
-#endif
-
-#ifdef WEBP_EXPERIMENTAL_FEATURES
- if (dec->layer_data_size_ > 0) {
- if (!VP8DecodeLayer(dec)) {
- return 0;
- }
- }
-#endif
return 1;
}
@@ -768,12 +648,10 @@ void VP8Clear(VP8Decoder* const dec) {
if (dec == NULL) {
return;
}
- if (dec->use_threads_) {
- WebPWorkerEnd(&dec->worker_);
- }
- if (dec->mem_) {
- free(dec->mem_);
- }
+ WebPGetWorkerInterface()->End(&dec->worker_);
+ ALPHDelete(dec->alph_dec_);
+ dec->alph_dec_ = NULL;
+ WebPSafeFree(dec->mem_);
dec->mem_ = NULL;
dec->mem_size_ = 0;
memset(&dec->br_, 0, sizeof(dec->br_));
@@ -782,6 +660,3 @@ void VP8Clear(VP8Decoder* const dec) {
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/dec/vp8i.h b/drivers/webp/dec/vp8i.h
index 4382edfd8e..b5f2b23009 100644
--- a/drivers/webp/dec/vp8i.h
+++ b/drivers/webp/dec/vp8i.h
@@ -1,8 +1,10 @@
// Copyright 2010 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// VP8 decoder: internal header.
@@ -13,12 +15,14 @@
#define WEBP_DEC_VP8I_H_
#include <string.h> // for memcpy()
+#include "./common.h"
#include "./vp8li.h"
#include "../utils/bit_reader.h"
+#include "../utils/random.h"
#include "../utils/thread.h"
#include "../dsp/dsp.h"
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
extern "C" {
#endif
@@ -27,48 +31,10 @@ extern "C" {
// version numbers
#define DEC_MAJ_VERSION 0
-#define DEC_MIN_VERSION 2
-#define DEC_REV_VERSION 0
-
-#define ONLY_KEYFRAME_CODE // to remove any code related to P-Frames
-
-// intra prediction modes
-enum { B_DC_PRED = 0, // 4x4 modes
- B_TM_PRED,
- B_VE_PRED,
- B_HE_PRED,
- B_RD_PRED,
- B_VR_PRED,
- B_LD_PRED,
- B_VL_PRED,
- B_HD_PRED,
- B_HU_PRED,
- NUM_BMODES = B_HU_PRED + 1 - B_DC_PRED, // = 10
-
- // Luma16 or UV modes
- DC_PRED = B_DC_PRED, V_PRED = B_VE_PRED,
- H_PRED = B_HE_PRED, TM_PRED = B_TM_PRED,
- B_PRED = NUM_BMODES, // refined I4x4 mode
-
- // special modes
- B_DC_PRED_NOTOP = 4,
- B_DC_PRED_NOLEFT = 5,
- B_DC_PRED_NOTOPLEFT = 6,
- NUM_B_DC_MODES = 7 };
-
-enum { MB_FEATURE_TREE_PROBS = 3,
- NUM_MB_SEGMENTS = 4,
- NUM_REF_LF_DELTAS = 4,
- NUM_MODE_LF_DELTAS = 4, // I4x4, ZERO, *, SPLIT
- MAX_NUM_PARTITIONS = 8,
- // Probabilities
- NUM_TYPES = 4,
- NUM_BANDS = 8,
- NUM_CTX = 3,
- NUM_PROBAS = 11,
- NUM_MV_PROBAS = 19 };
-
-// YUV-cache parameters.
+#define DEC_MIN_VERSION 4
+#define DEC_REV_VERSION 4
+
+// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
// Constraints are: We need to store one 16x16 block of luma samples (y),
// and two 8x8 chroma blocks (u/v). These are better be 16-bytes aligned,
// in order to be SIMD-friendly. We also need to store the top, left and
@@ -90,14 +56,15 @@ enum { MB_FEATURE_TREE_PROBS = 3,
// 'y' = y-samples 'u' = u-samples 'v' = u-samples
// '|' = left sample, '-' = top sample, '+' = top-left sample
// 't' = extra top-right sample for 4x4 modes
-// With this layout, BPS (=Bytes Per Scan-line) is one cacheline size.
-#define BPS 32 // this is the common stride used by yuv[]
#define YUV_SIZE (BPS * 17 + BPS * 9)
#define Y_SIZE (BPS * 17)
#define Y_OFF (BPS * 1 + 8)
#define U_OFF (Y_OFF + BPS * 16 + BPS)
#define V_OFF (U_OFF + 16)
+// minimal width under which lossy multi-threading is always disabled
+#define MIN_WIDTH_FOR_THREADS 512
+
//------------------------------------------------------------------------------
// Headers
@@ -126,15 +93,19 @@ typedef struct {
int8_t filter_strength_[NUM_MB_SEGMENTS]; // filter strength for segments
} VP8SegmentHeader;
+// probas associated to one of the contexts
+typedef uint8_t VP8ProbaArray[NUM_PROBAS];
+
+typedef struct { // all the probas associated to one band
+ VP8ProbaArray probas_[NUM_CTX];
+} VP8BandProbas;
+
// Struct collecting all frame-persistent probabilities.
typedef struct {
uint8_t segments_[MB_FEATURE_TREE_PROBS];
// Type: 0:Intra16-AC 1:Intra16-DC 2:Chroma 3:Intra4
- uint8_t coeffs_[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS];
-#ifndef ONLY_KEYFRAME_CODE
- uint8_t ymode_[4], uvmode_[3];
- uint8_t mv_[2][NUM_MV_PROBAS];
-#endif
+ VP8BandProbas bands_[NUM_TYPES][NUM_BANDS];
+ const VP8BandProbas* bands_ptr_[NUM_TYPES][16 + 1];
} VP8Proba;
// Filter parameters
@@ -151,32 +122,61 @@ typedef struct {
// Informations about the macroblocks.
typedef struct { // filter specs
- unsigned int f_level_:6; // filter strength: 0..63
- unsigned int f_ilevel_:6; // inner limit: 1..63
- unsigned int f_inner_:1; // do inner filtering?
+ uint8_t f_limit_; // filter limit in [3..189], or 0 if no filtering
+ uint8_t f_ilevel_; // inner limit in [1..63]
+ uint8_t f_inner_; // do inner filtering?
+ uint8_t hev_thresh_; // high edge variance threshold in [0..2]
} VP8FInfo;
-typedef struct { // used for syntax-parsing
- unsigned int nz_; // non-zero AC/DC coeffs
- unsigned int dc_nz_:1; // non-zero DC coeffs
- unsigned int skip_:1; // block type
+typedef struct { // Top/Left Contexts used for syntax-parsing
+ uint8_t nz_; // non-zero AC/DC coeffs (4bit for luma + 4bit for chroma)
+ uint8_t nz_dc_; // non-zero DC coeff (1bit)
} VP8MB;
// Dequantization matrices
typedef int quant_t[2]; // [DC / AC]. Can be 'uint16_t[2]' too (~slower).
typedef struct {
quant_t y1_mat_, y2_mat_, uv_mat_;
+
+ int uv_quant_; // U/V quantizer value
+ int dither_; // dithering amplitude (0 = off, max=255)
} VP8QuantMatrix;
+// Data needed to reconstruct a macroblock
+typedef struct {
+ int16_t coeffs_[384]; // 384 coeffs = (16+4+4) * 4*4
+ uint8_t is_i4x4_; // true if intra4x4
+ uint8_t imodes_[16]; // one 16x16 mode (#0) or sixteen 4x4 modes
+ uint8_t uvmode_; // chroma prediction mode
+ // bit-wise info about the content of each sub-4x4 blocks (in decoding order).
+ // Each of the 4x4 blocks for y/u/v is associated with a 2b code according to:
+ // code=0 -> no coefficient
+ // code=1 -> only DC
+ // code=2 -> first three coefficients are non-zero
+ // code=3 -> more than three coefficients are non-zero
+ // This allows to call specialized transform functions.
+ uint32_t non_zero_y_;
+ uint32_t non_zero_uv_;
+ uint8_t dither_; // local dithering strength (deduced from non_zero_*)
+ uint8_t skip_;
+ uint8_t segment_;
+} VP8MBData;
+
// Persistent information needed by the parallel processing
typedef struct {
- int id_; // cache row to process (in [0..2])
- int mb_y_; // macroblock position of the row
- int filter_row_; // true if row-filtering is needed
- VP8FInfo* f_info_; // filter strengths
- VP8Io io_; // copy of the VP8Io to pass to put()
+ int id_; // cache row to process (in [0..2])
+ int mb_y_; // macroblock position of the row
+ int filter_row_; // true if row-filtering is needed
+ VP8FInfo* f_info_; // filter strengths (swapped with dec->f_info_)
+ VP8MBData* mb_data_; // reconstruction data (swapped with dec->mb_data_)
+ VP8Io io_; // copy of the VP8Io to pass to put()
} VP8ThreadContext;
+// Saved top samples, per macroblock. Fits into a cache-line.
+typedef struct {
+ uint8_t y[16], u[8], v[8];
+} VP8TopSamples;
+
//------------------------------------------------------------------------------
// VP8Decoder: the main opaque structure handed over to user
@@ -196,7 +196,8 @@ struct VP8Decoder {
// Worker
WebPWorker worker_;
- int use_threads_; // use multi-thread
+ int mt_method_; // multi-thread method: 0=off, 1=[parse+recon][filter]
+ // 2=[parse][recon+filter]
int cache_id_; // current cache row
int num_caches_; // number of cached rows of 16 pixels (1, 2 or 3)
VP8ThreadContext thread_ctx_; // Thread context
@@ -213,12 +214,9 @@ struct VP8Decoder {
// per-partition boolean decoders.
VP8BitReader parts_[MAX_NUM_PARTITIONS];
- // buffer refresh flags
- // bit 0: refresh Gold, bit 1: refresh Alt
- // bit 2-3: copy to Gold, bit 4-5: copy to Alt
- // bit 6: Gold sign bias, bit 7: Alt sign bias
- // bit 8: refresh last frame
- uint32_t buffer_flags_;
+ // Dithering strength, deduced from decoding options
+ int dither_; // whether to use dithering or not
+ VP8Random dithering_rg_; // random generator for dithering
// dequantization (one set of DC/AC dequant factor per segment)
VP8QuantMatrix dqm_[NUM_MB_SEGMENTS];
@@ -227,24 +225,18 @@ struct VP8Decoder {
VP8Proba proba_;
int use_skip_proba_;
uint8_t skip_p_;
-#ifndef ONLY_KEYFRAME_CODE
- uint8_t intra_p_, last_p_, golden_p_;
- VP8Proba proba_saved_;
- int update_proba_;
-#endif
// Boundary data cache and persistent buffers.
- uint8_t* intra_t_; // top intra modes values: 4 * mb_w_
- uint8_t intra_l_[4]; // left intra modes values
- uint8_t* y_t_; // top luma samples: 16 * mb_w_
- uint8_t* u_t_, *v_t_; // top u/v samples: 8 * mb_w_ each
+ uint8_t* intra_t_; // top intra modes values: 4 * mb_w_
+ uint8_t intra_l_[4]; // left intra modes values
- VP8MB* mb_info_; // contextual macroblock info (mb_w_ + 1)
- VP8FInfo* f_info_; // filter strength info
- uint8_t* yuv_b_; // main block for Y/U/V (size = YUV_SIZE)
- int16_t* coeffs_; // 384 coeffs = (16+8+8) * 4*4
+ VP8TopSamples* yuv_t_; // top y/u/v samples
- uint8_t* cache_y_; // macroblock row for storing unfiltered samples
+ VP8MB* mb_info_; // contextual macroblock info (mb_w_ + 1)
+ VP8FInfo* f_info_; // filter strength info
+ uint8_t* yuv_b_; // main block for Y/U/V (size = YUV_SIZE)
+
+ uint8_t* cache_y_; // macroblock row for storing unfiltered samples
uint8_t* cache_u_;
uint8_t* cache_v_;
int cache_y_stride_;
@@ -256,31 +248,19 @@ struct VP8Decoder {
// Per macroblock non-persistent infos.
int mb_x_, mb_y_; // current position, in macroblock units
- uint8_t is_i4x4_; // true if intra4x4
- uint8_t imodes_[16]; // one 16x16 mode (#0) or sixteen 4x4 modes
- uint8_t uvmode_; // chroma prediction mode
- uint8_t segment_; // block's segment
-
- // bit-wise info about the content of each sub-4x4 blocks: there are 16 bits
- // for luma (bits #0->#15), then 4 bits for chroma-u (#16->#19) and 4 bits for
- // chroma-v (#20->#23), each corresponding to one 4x4 block in decoding order.
- // If the bit is set, the 4x4 block contains some non-zero coefficients.
- uint32_t non_zero_;
- uint32_t non_zero_ac_;
+ VP8MBData* mb_data_; // parsed reconstruction data
// Filtering side-info
- int filter_type_; // 0=off, 1=simple, 2=complex
- int filter_row_; // per-row flag
- uint8_t filter_levels_[NUM_MB_SEGMENTS]; // precalculated per-segment
+ int filter_type_; // 0=off, 1=simple, 2=complex
+ VP8FInfo fstrengths_[NUM_MB_SEGMENTS][2]; // precalculated per-segment/type
- // extensions
- const uint8_t* alpha_data_; // compressed alpha data (if present)
+ // Alpha
+ struct ALPHDecoder* alph_dec_; // alpha-plane decoder object
+ const uint8_t* alpha_data_; // compressed alpha data (if present)
size_t alpha_data_size_;
- uint8_t* alpha_plane_; // output. Persistent, contains the whole data.
-
- int layer_colorspace_;
- const uint8_t* layer_data_; // compressed layer data (if present)
- size_t layer_data_size_;
+ int is_alpha_decoded_; // true if alpha_data_ is decoded in alpha_plane_
+ uint8_t* alpha_plane_; // output. Persistent, contains the whole data.
+ int alpha_dithering_; // derived from decoding options (0=off, 100=full).
};
//------------------------------------------------------------------------------
@@ -293,15 +273,14 @@ int VP8SetError(VP8Decoder* const dec,
// in tree.c
void VP8ResetProba(VP8Proba* const proba);
void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec);
-void VP8ParseIntraMode(VP8BitReader* const br, VP8Decoder* const dec);
+// parses one row of intra mode data in partition 0, returns !eof
+int VP8ParseIntraModeRow(VP8BitReader* const br, VP8Decoder* const dec);
// in quant.c
void VP8ParseQuant(VP8Decoder* const dec);
// in frame.c
-int VP8InitFrame(VP8Decoder* const dec, VP8Io* io);
-// Predict a block and add residual
-void VP8ReconstructBlock(VP8Decoder* const dec);
+int VP8InitFrame(VP8Decoder* const dec, VP8Io* const io);
// Call io->setup() and finish setting up scan parameters.
// After this call returns, one must always call VP8ExitCritical() with the
// same parameters. Both functions should be used in pair. Returns VP8_STATUS_OK
@@ -310,10 +289,16 @@ VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io);
// Must always be called in pair with VP8EnterCritical().
// Returns false in case of error.
int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io);
-// Process the last decoded row (filtering + output)
+// Return the multi-threading method to use (0=off), depending
+// on options and bitstream size. Only for lossy decoding.
+int VP8GetThreadMethod(const WebPDecoderOptions* const options,
+ const WebPHeaderStructure* const headers,
+ int width, int height);
+// Initialize dithering post-process if needed.
+void VP8InitDithering(const WebPDecoderOptions* const options,
+ VP8Decoder* const dec);
+// Process the last decoded row (filtering + output).
int VP8ProcessRow(VP8Decoder* const dec, VP8Io* const io);
-// Store a block, along with filtering params
-void VP8StoreBlock(VP8Decoder* const dec);
// To be called at the start of a new scanline, to initialize predictors.
void VP8InitScanline(VP8Decoder* const dec);
// Decode one macroblock. Returns false if there is not enough data.
@@ -323,12 +308,9 @@ int VP8DecodeMB(VP8Decoder* const dec, VP8BitReader* const token_br);
const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
int row, int num_rows);
-// in layer.c
-int VP8DecodeLayer(VP8Decoder* const dec);
-
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/drivers/webp/dec/vp8l.c b/drivers/webp/dec/vp8l.c
index 897e4395c7..19665a007d 100644
--- a/drivers/webp/dec/vp8l.c
+++ b/drivers/webp/dec/vp8l.c
@@ -1,8 +1,10 @@
// Copyright 2012 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// main entry for the decoder
@@ -10,18 +12,17 @@
// Authors: Vikas Arora (vikaas.arora@gmail.com)
// Jyrki Alakuijala (jyrki@google.com)
-#include <stdio.h>
#include <stdlib.h>
+
+#include "./alphai.h"
#include "./vp8li.h"
+#include "../dsp/dsp.h"
#include "../dsp/lossless.h"
#include "../dsp/yuv.h"
+#include "../utils/endian_inl.h"
#include "../utils/huffman.h"
#include "../utils/utils.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
#define NUM_ARGB_CACHE_ROWS 16
static const int kCodeLengthLiterals = 16;
@@ -50,6 +51,9 @@ static const uint16_t kAlphabetSize[HUFFMAN_CODES_PER_META_CODE] = {
NUM_DISTANCE_CODES
};
+static const uint8_t kLiteralMap[HUFFMAN_CODES_PER_META_CODE] = {
+ 0, 1, 1, 1, 0
+};
#define NUM_CODE_LENGTH_CODES 19
static const uint8_t kCodeLengthCodeOrder[NUM_CODE_LENGTH_CODES] = {
@@ -57,19 +61,43 @@ static const uint8_t kCodeLengthCodeOrder[NUM_CODE_LENGTH_CODES] = {
};
#define CODE_TO_PLANE_CODES 120
-static const uint8_t code_to_plane_lut[CODE_TO_PLANE_CODES] = {
- 0x18, 0x07, 0x17, 0x19, 0x28, 0x06, 0x27, 0x29, 0x16, 0x1a,
- 0x26, 0x2a, 0x38, 0x05, 0x37, 0x39, 0x15, 0x1b, 0x36, 0x3a,
- 0x25, 0x2b, 0x48, 0x04, 0x47, 0x49, 0x14, 0x1c, 0x35, 0x3b,
- 0x46, 0x4a, 0x24, 0x2c, 0x58, 0x45, 0x4b, 0x34, 0x3c, 0x03,
- 0x57, 0x59, 0x13, 0x1d, 0x56, 0x5a, 0x23, 0x2d, 0x44, 0x4c,
- 0x55, 0x5b, 0x33, 0x3d, 0x68, 0x02, 0x67, 0x69, 0x12, 0x1e,
- 0x66, 0x6a, 0x22, 0x2e, 0x54, 0x5c, 0x43, 0x4d, 0x65, 0x6b,
- 0x32, 0x3e, 0x78, 0x01, 0x77, 0x79, 0x53, 0x5d, 0x11, 0x1f,
- 0x64, 0x6c, 0x42, 0x4e, 0x76, 0x7a, 0x21, 0x2f, 0x75, 0x7b,
- 0x31, 0x3f, 0x63, 0x6d, 0x52, 0x5e, 0x00, 0x74, 0x7c, 0x41,
- 0x4f, 0x10, 0x20, 0x62, 0x6e, 0x30, 0x73, 0x7d, 0x51, 0x5f,
- 0x40, 0x72, 0x7e, 0x61, 0x6f, 0x50, 0x71, 0x7f, 0x60, 0x70
+static const uint8_t kCodeToPlane[CODE_TO_PLANE_CODES] = {
+ 0x18, 0x07, 0x17, 0x19, 0x28, 0x06, 0x27, 0x29, 0x16, 0x1a,
+ 0x26, 0x2a, 0x38, 0x05, 0x37, 0x39, 0x15, 0x1b, 0x36, 0x3a,
+ 0x25, 0x2b, 0x48, 0x04, 0x47, 0x49, 0x14, 0x1c, 0x35, 0x3b,
+ 0x46, 0x4a, 0x24, 0x2c, 0x58, 0x45, 0x4b, 0x34, 0x3c, 0x03,
+ 0x57, 0x59, 0x13, 0x1d, 0x56, 0x5a, 0x23, 0x2d, 0x44, 0x4c,
+ 0x55, 0x5b, 0x33, 0x3d, 0x68, 0x02, 0x67, 0x69, 0x12, 0x1e,
+ 0x66, 0x6a, 0x22, 0x2e, 0x54, 0x5c, 0x43, 0x4d, 0x65, 0x6b,
+ 0x32, 0x3e, 0x78, 0x01, 0x77, 0x79, 0x53, 0x5d, 0x11, 0x1f,
+ 0x64, 0x6c, 0x42, 0x4e, 0x76, 0x7a, 0x21, 0x2f, 0x75, 0x7b,
+ 0x31, 0x3f, 0x63, 0x6d, 0x52, 0x5e, 0x00, 0x74, 0x7c, 0x41,
+ 0x4f, 0x10, 0x20, 0x62, 0x6e, 0x30, 0x73, 0x7d, 0x51, 0x5f,
+ 0x40, 0x72, 0x7e, 0x61, 0x6f, 0x50, 0x71, 0x7f, 0x60, 0x70
+};
+
+// Memory needed for lookup tables of one Huffman tree group. Red, blue, alpha
+// and distance alphabets are constant (256 for red, blue and alpha, 40 for
+// distance) and lookup table sizes for them in worst case are 630 and 410
+// respectively. Size of green alphabet depends on color cache size and is equal
+// to 256 (green component values) + 24 (length prefix values)
+// + color_cache_size (between 0 and 2048).
+// All values computed for 8-bit first level lookup with Mark Adler's tool:
+// http://www.hdfgroup.org/ftp/lib-external/zlib/zlib-1.2.5/examples/enough.c
+#define FIXED_TABLE_SIZE (630 * 3 + 410)
+static const int kTableSize[12] = {
+ FIXED_TABLE_SIZE + 654,
+ FIXED_TABLE_SIZE + 656,
+ FIXED_TABLE_SIZE + 658,
+ FIXED_TABLE_SIZE + 662,
+ FIXED_TABLE_SIZE + 670,
+ FIXED_TABLE_SIZE + 686,
+ FIXED_TABLE_SIZE + 718,
+ FIXED_TABLE_SIZE + 782,
+ FIXED_TABLE_SIZE + 912,
+ FIXED_TABLE_SIZE + 1168,
+ FIXED_TABLE_SIZE + 1680,
+ FIXED_TABLE_SIZE + 2704
};
static int DecodeImageStream(int xsize, int ysize,
@@ -80,27 +108,28 @@ static int DecodeImageStream(int xsize, int ysize,
//------------------------------------------------------------------------------
int VP8LCheckSignature(const uint8_t* const data, size_t size) {
- return (size >= 1) && (data[0] == VP8L_MAGIC_BYTE);
+ return (size >= VP8L_FRAME_HEADER_SIZE &&
+ data[0] == VP8L_MAGIC_BYTE &&
+ (data[4] >> 5) == 0); // version
}
static int ReadImageInfo(VP8LBitReader* const br,
int* const width, int* const height,
int* const has_alpha) {
- const uint8_t signature = VP8LReadBits(br, 8);
- if (!VP8LCheckSignature(&signature, 1)) {
- return 0;
- }
+ if (VP8LReadBits(br, 8) != VP8L_MAGIC_BYTE) return 0;
*width = VP8LReadBits(br, VP8L_IMAGE_SIZE_BITS) + 1;
*height = VP8LReadBits(br, VP8L_IMAGE_SIZE_BITS) + 1;
*has_alpha = VP8LReadBits(br, 1);
- VP8LReadBits(br, VP8L_VERSION_BITS); // Read/ignore the version number.
- return 1;
+ if (VP8LReadBits(br, VP8L_VERSION_BITS) != 0) return 0;
+ return !br->eos_;
}
int VP8LGetInfo(const uint8_t* data, size_t data_size,
int* const width, int* const height, int* const has_alpha) {
if (data == NULL || data_size < VP8L_FRAME_HEADER_SIZE) {
return 0; // not enough data
+ } else if (!VP8LCheckSignature(data, data_size)) {
+ return 0; // bad signature
} else {
int w, h, a;
VP8LBitReader br;
@@ -138,39 +167,80 @@ static WEBP_INLINE int PlaneCodeToDistance(int xsize, int plane_code) {
if (plane_code > CODE_TO_PLANE_CODES) {
return plane_code - CODE_TO_PLANE_CODES;
} else {
- const int dist_code = code_to_plane_lut[plane_code - 1];
+ const int dist_code = kCodeToPlane[plane_code - 1];
const int yoffset = dist_code >> 4;
const int xoffset = 8 - (dist_code & 0xf);
const int dist = yoffset * xsize + xoffset;
- return (dist >= 1) ? dist : 1;
+ return (dist >= 1) ? dist : 1; // dist<1 can happen if xsize is very small
}
}
//------------------------------------------------------------------------------
// Decodes the next Huffman code from bit-stream.
// FillBitWindow(br) needs to be called at minimum every second call
-// to ReadSymbolUnsafe.
-static int ReadSymbolUnsafe(const HuffmanTree* tree, VP8LBitReader* const br) {
- const HuffmanTreeNode* node = tree->root_;
- assert(node != NULL);
- while (!HuffmanTreeNodeIsLeaf(node)) {
- node = HuffmanTreeNextNode(node, VP8LReadOneBitUnsafe(br));
- }
- return node->symbol_;
+// to ReadSymbol, in order to pre-fetch enough bits.
+static WEBP_INLINE int ReadSymbol(const HuffmanCode* table,
+ VP8LBitReader* const br) {
+ int nbits;
+ uint32_t val = VP8LPrefetchBits(br);
+ table += val & HUFFMAN_TABLE_MASK;
+ nbits = table->bits - HUFFMAN_TABLE_BITS;
+ if (nbits > 0) {
+ VP8LSetBitPos(br, br->bit_pos_ + HUFFMAN_TABLE_BITS);
+ val = VP8LPrefetchBits(br);
+ table += table->value;
+ table += val & ((1 << nbits) - 1);
+ }
+ VP8LSetBitPos(br, br->bit_pos_ + table->bits);
+ return table->value;
}
-static WEBP_INLINE int ReadSymbol(const HuffmanTree* tree,
- VP8LBitReader* const br) {
- const int read_safe = (br->pos_ + 8 > br->len_);
- if (!read_safe) {
- return ReadSymbolUnsafe(tree, br);
+// Reads packed symbol depending on GREEN channel
+#define BITS_SPECIAL_MARKER 0x100 // something large enough (and a bit-mask)
+#define PACKED_NON_LITERAL_CODE 0 // must be < NUM_LITERAL_CODES
+static WEBP_INLINE int ReadPackedSymbols(const HTreeGroup* group,
+ VP8LBitReader* const br,
+ uint32_t* const dst) {
+ const uint32_t val = VP8LPrefetchBits(br) & (HUFFMAN_PACKED_TABLE_SIZE - 1);
+ const HuffmanCode32 code = group->packed_table[val];
+ assert(group->use_packed_table);
+ if (code.bits < BITS_SPECIAL_MARKER) {
+ VP8LSetBitPos(br, br->bit_pos_ + code.bits);
+ *dst = code.value;
+ return PACKED_NON_LITERAL_CODE;
} else {
- const HuffmanTreeNode* node = tree->root_;
- assert(node != NULL);
- while (!HuffmanTreeNodeIsLeaf(node)) {
- node = HuffmanTreeNextNode(node, VP8LReadOneBit(br));
+ VP8LSetBitPos(br, br->bit_pos_ + code.bits - BITS_SPECIAL_MARKER);
+ assert(code.value >= NUM_LITERAL_CODES);
+ return code.value;
+ }
+}
+
+static int AccumulateHCode(HuffmanCode hcode, int shift,
+ HuffmanCode32* const huff) {
+ huff->bits += hcode.bits;
+ huff->value |= (uint32_t)hcode.value << shift;
+ assert(huff->bits <= HUFFMAN_TABLE_BITS);
+ return hcode.bits;
+}
+
+static void BuildPackedTable(HTreeGroup* const htree_group) {
+ uint32_t code;
+ for (code = 0; code < HUFFMAN_PACKED_TABLE_SIZE; ++code) {
+ uint32_t bits = code;
+ HuffmanCode32* const huff = &htree_group->packed_table[bits];
+ HuffmanCode hcode = htree_group->htrees[GREEN][bits];
+ if (hcode.value >= NUM_LITERAL_CODES) {
+ huff->bits = hcode.bits + BITS_SPECIAL_MARKER;
+ huff->value = hcode.value;
+ } else {
+ huff->bits = 0;
+ huff->value = 0;
+ bits >>= AccumulateHCode(hcode, 8, huff);
+ bits >>= AccumulateHCode(htree_group->htrees[RED][bits], 16, huff);
+ bits >>= AccumulateHCode(htree_group->htrees[BLUE][bits], 0, huff);
+ bits >>= AccumulateHCode(htree_group->htrees[ALPHA][bits], 24, huff);
+ (void)bits;
}
- return node->symbol_;
}
}
@@ -182,19 +252,18 @@ static int ReadHuffmanCodeLengths(
int symbol;
int max_symbol;
int prev_code_len = DEFAULT_CODE_LENGTH;
- HuffmanTree tree;
+ HuffmanCode table[1 << LENGTHS_TABLE_BITS];
- if (!HuffmanTreeBuildImplicit(&tree, code_length_code_lengths,
- NUM_CODE_LENGTH_CODES)) {
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
- return 0;
+ if (!VP8LBuildHuffmanTable(table, LENGTHS_TABLE_BITS,
+ code_length_code_lengths,
+ NUM_CODE_LENGTH_CODES)) {
+ goto End;
}
if (VP8LReadBits(br, 1)) { // use length
const int length_nbits = 2 + 2 * VP8LReadBits(br, 3);
max_symbol = 2 + VP8LReadBits(br, length_nbits);
if (max_symbol > num_symbols) {
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
goto End;
}
} else {
@@ -203,10 +272,13 @@ static int ReadHuffmanCodeLengths(
symbol = 0;
while (symbol < num_symbols) {
+ const HuffmanCode* p;
int code_len;
if (max_symbol-- == 0) break;
VP8LFillBitWindow(br);
- code_len = ReadSymbol(&tree, br);
+ p = &table[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK];
+ VP8LSetBitPos(br, br->bit_pos_ + p->bits);
+ code_len = p->value;
if (code_len < kCodeLengthLiterals) {
code_lengths[symbol++] = code_len;
if (code_len != 0) prev_code_len = code_len;
@@ -217,7 +289,6 @@ static int ReadHuffmanCodeLengths(
const int repeat_offset = kCodeLengthRepeatOffsets[slot];
int repeat = VP8LReadBits(br, extra_bits) + repeat_offset;
if (symbol + repeat > num_symbols) {
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
goto End;
} else {
const int length = use_prev ? prev_code_len : 0;
@@ -228,36 +299,34 @@ static int ReadHuffmanCodeLengths(
ok = 1;
End:
- HuffmanTreeRelease(&tree);
+ if (!ok) dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
return ok;
}
+// 'code_lengths' is pre-allocated temporary buffer, used for creating Huffman
+// tree.
static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
- HuffmanTree* const tree) {
+ int* const code_lengths, HuffmanCode* const table) {
int ok = 0;
+ int size = 0;
VP8LBitReader* const br = &dec->br_;
const int simple_code = VP8LReadBits(br, 1);
+ memset(code_lengths, 0, alphabet_size * sizeof(*code_lengths));
+
if (simple_code) { // Read symbols, codes & code lengths directly.
- int symbols[2];
- int codes[2];
- int code_lengths[2];
const int num_symbols = VP8LReadBits(br, 1) + 1;
const int first_symbol_len_code = VP8LReadBits(br, 1);
// The first code is either 1 bit or 8 bit code.
- symbols[0] = VP8LReadBits(br, (first_symbol_len_code == 0) ? 1 : 8);
- codes[0] = 0;
- code_lengths[0] = num_symbols - 1;
+ int symbol = VP8LReadBits(br, (first_symbol_len_code == 0) ? 1 : 8);
+ code_lengths[symbol] = 1;
// The second code (if present), is always 8 bit long.
if (num_symbols == 2) {
- symbols[1] = VP8LReadBits(br, 8);
- codes[1] = 1;
- code_lengths[1] = num_symbols - 1;
+ symbol = VP8LReadBits(br, 8);
+ code_lengths[symbol] = 1;
}
- ok = HuffmanTreeBuildExplicit(tree, code_lengths, codes, symbols,
- alphabet_size, num_symbols);
+ ok = 1;
} else { // Decode Huffman-coded code lengths.
- int* code_lengths = NULL;
int i;
int code_length_code_lengths[NUM_CODE_LENGTH_CODES] = { 0 };
const int num_codes = VP8LReadBits(br, 4) + 4;
@@ -266,42 +335,23 @@ static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
return 0;
}
- code_lengths =
- (int*)WebPSafeCalloc((uint64_t)alphabet_size, sizeof(*code_lengths));
- if (code_lengths == NULL) {
- dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
- return 0;
- }
-
for (i = 0; i < num_codes; ++i) {
code_length_code_lengths[kCodeLengthCodeOrder[i]] = VP8LReadBits(br, 3);
}
ok = ReadHuffmanCodeLengths(dec, code_length_code_lengths, alphabet_size,
code_lengths);
- if (ok) {
- ok = HuffmanTreeBuildImplicit(tree, code_lengths, alphabet_size);
- }
- free(code_lengths);
}
- ok = ok && !br->error_;
- if (!ok) {
+
+ ok = ok && !br->eos_;
+ if (ok) {
+ size = VP8LBuildHuffmanTable(table, HUFFMAN_TABLE_BITS,
+ code_lengths, alphabet_size);
+ }
+ if (!ok || size == 0) {
dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
return 0;
}
- return 1;
-}
-
-static void DeleteHtreeGroups(HTreeGroup* htree_groups, int num_htree_groups) {
- if (htree_groups != NULL) {
- int i, j;
- for (i = 0; i < num_htree_groups; ++i) {
- HuffmanTree* const htrees = htree_groups[i].htrees_;
- for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
- HuffmanTreeRelease(&htrees[j]);
- }
- }
- free(htree_groups);
- }
+ return size;
}
static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
@@ -311,7 +361,12 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
VP8LMetadata* const hdr = &dec->hdr_;
uint32_t* huffman_image = NULL;
HTreeGroup* htree_groups = NULL;
+ HuffmanCode* huffman_tables = NULL;
+ HuffmanCode* next = NULL;
int num_htree_groups = 1;
+ int max_alphabet_size = 0;
+ int* code_lengths = NULL;
+ const int table_size = kTableSize[color_cache_bits];
if (allow_recursion && VP8LReadBits(br, 1)) {
// use meta Huffman codes.
@@ -321,51 +376,108 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
const int huffman_pixs = huffman_xsize * huffman_ysize;
if (!DecodeImageStream(huffman_xsize, huffman_ysize, 0, dec,
&huffman_image)) {
- dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
goto Error;
}
hdr->huffman_subsample_bits_ = huffman_precision;
for (i = 0; i < huffman_pixs; ++i) {
// The huffman data is stored in red and green bytes.
- const int index = (huffman_image[i] >> 8) & 0xffff;
- huffman_image[i] = index;
- if (index >= num_htree_groups) {
- num_htree_groups = index + 1;
+ const int group = (huffman_image[i] >> 8) & 0xffff;
+ huffman_image[i] = group;
+ if (group >= num_htree_groups) {
+ num_htree_groups = group + 1;
}
}
}
- if (br->error_) goto Error;
+ if (br->eos_) goto Error;
+
+ // Find maximum alphabet size for the htree group.
+ for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
+ int alphabet_size = kAlphabetSize[j];
+ if (j == 0 && color_cache_bits > 0) {
+ alphabet_size += 1 << color_cache_bits;
+ }
+ if (max_alphabet_size < alphabet_size) {
+ max_alphabet_size = alphabet_size;
+ }
+ }
+
+ huffman_tables = (HuffmanCode*)WebPSafeMalloc(num_htree_groups * table_size,
+ sizeof(*huffman_tables));
+ htree_groups = VP8LHtreeGroupsNew(num_htree_groups);
+ code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size,
+ sizeof(*code_lengths));
- assert(num_htree_groups <= 0x10000);
- htree_groups =
- (HTreeGroup*)WebPSafeCalloc((uint64_t)num_htree_groups,
- sizeof(*htree_groups));
- if (htree_groups == NULL) {
+ if (htree_groups == NULL || code_lengths == NULL || huffman_tables == NULL) {
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
goto Error;
}
+ next = huffman_tables;
for (i = 0; i < num_htree_groups; ++i) {
- HuffmanTree* const htrees = htree_groups[i].htrees_;
+ HTreeGroup* const htree_group = &htree_groups[i];
+ HuffmanCode** const htrees = htree_group->htrees;
+ int size;
+ int total_size = 0;
+ int is_trivial_literal = 1;
+ int max_bits = 0;
for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
int alphabet_size = kAlphabetSize[j];
+ htrees[j] = next;
if (j == 0 && color_cache_bits > 0) {
alphabet_size += 1 << color_cache_bits;
}
- if (!ReadHuffmanCode(alphabet_size, dec, htrees + j)) goto Error;
+ size = ReadHuffmanCode(alphabet_size, dec, code_lengths, next);
+ if (is_trivial_literal && kLiteralMap[j] == 1) {
+ is_trivial_literal = (next->bits == 0);
+ }
+ total_size += next->bits;
+ next += size;
+ if (size == 0) {
+ goto Error;
+ }
+ if (j <= ALPHA) {
+ int local_max_bits = code_lengths[0];
+ int k;
+ for (k = 1; k < alphabet_size; ++k) {
+ if (code_lengths[k] > local_max_bits) {
+ local_max_bits = code_lengths[k];
+ }
+ }
+ max_bits += local_max_bits;
+ }
}
+ htree_group->is_trivial_literal = is_trivial_literal;
+ htree_group->is_trivial_code = 0;
+ if (is_trivial_literal) {
+ const int red = htrees[RED][0].value;
+ const int blue = htrees[BLUE][0].value;
+ const int alpha = htrees[ALPHA][0].value;
+ htree_group->literal_arb =
+ ((uint32_t)alpha << 24) | (red << 16) | blue;
+ if (total_size == 0 && htrees[GREEN][0].value < NUM_LITERAL_CODES) {
+ htree_group->is_trivial_code = 1;
+ htree_group->literal_arb |= htrees[GREEN][0].value << 8;
+ }
+ }
+ htree_group->use_packed_table = !htree_group->is_trivial_code &&
+ (max_bits < HUFFMAN_PACKED_BITS);
+ if (htree_group->use_packed_table) BuildPackedTable(htree_group);
}
+ WebPSafeFree(code_lengths);
// All OK. Finalize pointers and return.
hdr->huffman_image_ = huffman_image;
hdr->num_htree_groups_ = num_htree_groups;
hdr->htree_groups_ = htree_groups;
+ hdr->huffman_tables_ = huffman_tables;
return 1;
Error:
- free(huffman_image);
- DeleteHtreeGroups(htree_groups, num_htree_groups);
+ WebPSafeFree(code_lengths);
+ WebPSafeFree(huffman_image);
+ WebPSafeFree(huffman_tables);
+ VP8LHtreeGroupsFree(htree_groups);
return 0;
}
@@ -379,13 +491,13 @@ static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
const int in_height = io->mb_h;
const int out_height = io->scaled_height;
const uint64_t work_size = 2 * num_channels * (uint64_t)out_width;
- int32_t* work; // Rescaler work area.
- const uint64_t scaled_data_size = num_channels * (uint64_t)out_width;
+ rescaler_t* work; // Rescaler work area.
+ const uint64_t scaled_data_size = (uint64_t)out_width;
uint32_t* scaled_data; // Temporary storage for scaled BGRA data.
const uint64_t memory_size = sizeof(*dec->rescaler) +
work_size * sizeof(*work) +
scaled_data_size * sizeof(*scaled_data);
- uint8_t* memory = (uint8_t*)WebPSafeCalloc(memory_size, sizeof(*memory));
+ uint8_t* memory = (uint8_t*)WebPSafeMalloc(memory_size, sizeof(*memory));
if (memory == NULL) {
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
return 0;
@@ -395,13 +507,12 @@ static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
dec->rescaler = (WebPRescaler*)memory;
memory += sizeof(*dec->rescaler);
- work = (int32_t*)memory;
+ work = (rescaler_t*)memory;
memory += work_size * sizeof(*work);
scaled_data = (uint32_t*)memory;
WebPRescalerInit(dec->rescaler, in_width, in_height, (uint8_t*)scaled_data,
- out_width, out_height, 0, num_channels,
- in_width, out_width, in_height, out_height, work);
+ out_width, out_height, 0, num_channels, work);
return 1;
}
@@ -411,12 +522,13 @@ static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
// We have special "export" function since we need to convert from BGRA
static int Export(WebPRescaler* const rescaler, WEBP_CSP_MODE colorspace,
int rgba_stride, uint8_t* const rgba) {
- const uint32_t* const src = (const uint32_t*)rescaler->dst;
+ uint32_t* const src = (uint32_t*)rescaler->dst;
const int dst_width = rescaler->dst_width;
int num_lines_out = 0;
while (WebPRescalerHasPendingOutput(rescaler)) {
uint8_t* const dst = rgba + num_lines_out * rgba_stride;
WebPRescalerExportRow(rescaler);
+ WebPMultARGBRow(src, dst_width, 1);
VP8LConvertFromBGRA(src, dst_width, colorspace, dst);
++num_lines_out;
}
@@ -424,18 +536,22 @@ static int Export(WebPRescaler* const rescaler, WEBP_CSP_MODE colorspace,
}
// Emit scaled rows.
-static int EmitRescaledRows(const VP8LDecoder* const dec,
- const uint32_t* const data, int in_stride, int mb_h,
- uint8_t* const out, int out_stride) {
+static int EmitRescaledRowsRGBA(const VP8LDecoder* const dec,
+ uint8_t* in, int in_stride, int mb_h,
+ uint8_t* const out, int out_stride) {
const WEBP_CSP_MODE colorspace = dec->output_->colorspace;
- const uint8_t* const in = (const uint8_t*)data;
int num_lines_in = 0;
int num_lines_out = 0;
while (num_lines_in < mb_h) {
- const uint8_t* const row_in = in + num_lines_in * in_stride;
+ uint8_t* const row_in = in + num_lines_in * in_stride;
uint8_t* const row_out = out + num_lines_out * out_stride;
- num_lines_in += WebPRescalerImport(dec->rescaler, mb_h - num_lines_in,
- row_in, in_stride);
+ const int lines_left = mb_h - num_lines_in;
+ const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left);
+ assert(needed_lines > 0 && needed_lines <= lines_left);
+ WebPMultARGBRows(row_in, in_stride,
+ dec->rescaler->src_width, needed_lines, 0);
+ WebPRescalerImport(dec->rescaler, lines_left, row_in, in_stride);
+ num_lines_in += needed_lines;
num_lines_out += Export(dec->rescaler, colorspace, out_stride, row_out);
}
return num_lines_out;
@@ -443,11 +559,10 @@ static int EmitRescaledRows(const VP8LDecoder* const dec,
// Emit rows without any scaling.
static int EmitRows(WEBP_CSP_MODE colorspace,
- const uint32_t* const data, int in_stride,
+ const uint8_t* row_in, int in_stride,
int mb_w, int mb_h,
uint8_t* const out, int out_stride) {
int lines = mb_h;
- const uint8_t* row_in = (const uint8_t*)data;
uint8_t* row_out = out;
while (lines-- > 0) {
VP8LConvertFromBGRA((const uint32_t*)row_in, mb_w, colorspace, row_out);
@@ -463,72 +578,37 @@ static int EmitRows(WEBP_CSP_MODE colorspace,
static void ConvertToYUVA(const uint32_t* const src, int width, int y_pos,
const WebPDecBuffer* const output) {
const WebPYUVABuffer* const buf = &output->u.YUVA;
+
// first, the luma plane
- {
- int i;
- uint8_t* const y = buf->y + y_pos * buf->y_stride;
- for (i = 0; i < width; ++i) {
- const uint32_t p = src[i];
- y[i] = VP8RGBToY((p >> 16) & 0xff, (p >> 8) & 0xff, (p >> 0) & 0xff);
- }
- }
+ WebPConvertARGBToY(src, buf->y + y_pos * buf->y_stride, width);
// then U/V planes
{
uint8_t* const u = buf->u + (y_pos >> 1) * buf->u_stride;
uint8_t* const v = buf->v + (y_pos >> 1) * buf->v_stride;
- const int uv_width = width >> 1;
- int i;
- for (i = 0; i < uv_width; ++i) {
- const uint32_t v0 = src[2 * i + 0];
- const uint32_t v1 = src[2 * i + 1];
- // VP8RGBToU/V expects four accumulated pixels. Hence we need to
- // scale r/g/b value by a factor 2. We just shift v0/v1 one bit less.
- const int r = ((v0 >> 15) & 0x1fe) + ((v1 >> 15) & 0x1fe);
- const int g = ((v0 >> 7) & 0x1fe) + ((v1 >> 7) & 0x1fe);
- const int b = ((v0 << 1) & 0x1fe) + ((v1 << 1) & 0x1fe);
- if (!(y_pos & 1)) { // even lines: store values
- u[i] = VP8RGBToU(r, g, b);
- v[i] = VP8RGBToV(r, g, b);
- } else { // odd lines: average with previous values
- const int tmp_u = VP8RGBToU(r, g, b);
- const int tmp_v = VP8RGBToV(r, g, b);
- // Approximated average-of-four. But it's an acceptable diff.
- u[i] = (u[i] + tmp_u + 1) >> 1;
- v[i] = (v[i] + tmp_v + 1) >> 1;
- }
- }
- if (width & 1) { // last pixel
- const uint32_t v0 = src[2 * i + 0];
- const int r = (v0 >> 14) & 0x3fc;
- const int g = (v0 >> 6) & 0x3fc;
- const int b = (v0 << 2) & 0x3fc;
- if (!(y_pos & 1)) { // even lines
- u[i] = VP8RGBToU(r, g, b);
- v[i] = VP8RGBToV(r, g, b);
- } else { // odd lines (note: we could just skip this)
- const int tmp_u = VP8RGBToU(r, g, b);
- const int tmp_v = VP8RGBToV(r, g, b);
- u[i] = (u[i] + tmp_u + 1) >> 1;
- v[i] = (v[i] + tmp_v + 1) >> 1;
- }
- }
+ // even lines: store values
+ // odd lines: average with previous values
+ WebPConvertARGBToUV(src, u, v, width, !(y_pos & 1));
}
// Lastly, store alpha if needed.
if (buf->a != NULL) {
- int i;
uint8_t* const a = buf->a + y_pos * buf->a_stride;
- for (i = 0; i < width; ++i) a[i] = (src[i] >> 24);
+#if defined(WORDS_BIGENDIAN)
+ WebPExtractAlpha((uint8_t*)src + 0, 0, width, 1, a, 0);
+#else
+ WebPExtractAlpha((uint8_t*)src + 3, 0, width, 1, a, 0);
+#endif
}
}
static int ExportYUVA(const VP8LDecoder* const dec, int y_pos) {
WebPRescaler* const rescaler = dec->rescaler;
- const uint32_t* const src = (const uint32_t*)rescaler->dst;
+ uint32_t* const src = (uint32_t*)rescaler->dst;
const int dst_width = rescaler->dst_width;
int num_lines_out = 0;
while (WebPRescalerHasPendingOutput(rescaler)) {
WebPRescalerExportRow(rescaler);
+ WebPMultARGBRow(src, dst_width, 1);
ConvertToYUVA(src, dst_width, y_pos, dec->output_);
++y_pos;
++num_lines_out;
@@ -537,28 +617,28 @@ static int ExportYUVA(const VP8LDecoder* const dec, int y_pos) {
}
static int EmitRescaledRowsYUVA(const VP8LDecoder* const dec,
- const uint32_t* const data,
- int in_stride, int mb_h) {
- const uint8_t* const in = (const uint8_t*)data;
+ uint8_t* in, int in_stride, int mb_h) {
int num_lines_in = 0;
int y_pos = dec->last_out_row_;
while (num_lines_in < mb_h) {
- const uint8_t* const row_in = in + num_lines_in * in_stride;
- num_lines_in += WebPRescalerImport(dec->rescaler, mb_h - num_lines_in,
- row_in, in_stride);
+ const int lines_left = mb_h - num_lines_in;
+ const int needed_lines = WebPRescaleNeededLines(dec->rescaler, lines_left);
+ WebPMultARGBRows(in, in_stride, dec->rescaler->src_width, needed_lines, 0);
+ WebPRescalerImport(dec->rescaler, lines_left, in, in_stride);
+ num_lines_in += needed_lines;
+ in += needed_lines * in_stride;
y_pos += ExportYUVA(dec, y_pos);
}
return y_pos;
}
static int EmitRowsYUVA(const VP8LDecoder* const dec,
- const uint32_t* const data, int in_stride,
+ const uint8_t* in, int in_stride,
int mb_w, int num_rows) {
int y_pos = dec->last_out_row_;
- const uint8_t* row_in = (const uint8_t*)data;
while (num_rows-- > 0) {
- ConvertToYUVA((const uint32_t*)row_in, mb_w, y_pos, dec->output_);
- row_in += in_stride;
+ ConvertToYUVA((const uint32_t*)in, mb_w, y_pos, dec->output_);
+ in += in_stride;
++y_pos;
}
return y_pos;
@@ -569,11 +649,11 @@ static int EmitRowsYUVA(const VP8LDecoder* const dec,
// Sets io->mb_y, io->mb_h & io->mb_w according to start row, end row and
// crop options. Also updates the input data pointer, so that it points to the
-// start of the cropped window.
-// Note that 'pixel_stride' is in units of 'uint32_t' (and not 'bytes).
+// start of the cropped window. Note that pixels are in ARGB format even if
+// 'in_data' is uint8_t*.
// Returns true if the crop window is not empty.
static int SetCropWindow(VP8Io* const io, int y_start, int y_end,
- const uint32_t** const in_data, int pixel_stride) {
+ uint8_t** const in_data, int pixel_stride) {
assert(y_start < y_end);
assert(io->crop_left < io->crop_right);
if (y_end > io->crop_bottom) {
@@ -582,11 +662,11 @@ static int SetCropWindow(VP8Io* const io, int y_start, int y_end,
if (y_start < io->crop_top) {
const int delta = io->crop_top - y_start;
y_start = io->crop_top;
- *in_data += pixel_stride * delta;
+ *in_data += delta * pixel_stride;
}
if (y_start >= y_end) return 0; // Crop window is empty.
- *in_data += io->crop_left;
+ *in_data += io->crop_left * sizeof(uint32_t);
io->mb_y = y_start - io->crop_top;
io->mb_w = io->crop_right - io->crop_left;
@@ -634,10 +714,24 @@ static void ApplyInverseTransforms(VP8LDecoder* const dec, int num_rows,
}
}
+// Special method for paletted alpha data.
+static void ApplyInverseTransformsAlpha(VP8LDecoder* const dec, int num_rows,
+ const uint8_t* const rows) {
+ const int start_row = dec->last_row_;
+ const int end_row = start_row + num_rows;
+ const uint8_t* rows_in = rows;
+ uint8_t* rows_out = (uint8_t*)dec->io_->opaque + dec->io_->width * start_row;
+ VP8LTransform* const transform = &dec->transforms_[0];
+ assert(dec->next_transform_ == 1);
+ assert(transform->type_ == COLOR_INDEXING_TRANSFORM);
+ VP8LColorIndexInverseTransformAlpha(transform, start_row, end_row, rows_in,
+ rows_out);
+}
+
// Processes (transforms, scales & color-converts) the rows decoded after the
// last call.
static void ProcessRows(VP8LDecoder* const dec, int row) {
- const uint32_t* const rows = dec->argb_ + dec->width_ * dec->last_row_;
+ const uint32_t* const rows = dec->pixels_ + dec->width_ * dec->last_row_;
const int num_rows = row - dec->last_row_;
if (num_rows <= 0) return; // Nothing to be done.
@@ -646,18 +740,18 @@ static void ProcessRows(VP8LDecoder* const dec, int row) {
// Emit output.
{
VP8Io* const io = dec->io_;
- const uint32_t* rows_data = dec->argb_cache_;
- if (!SetCropWindow(io, dec->last_row_, row, &rows_data, io->width)) {
+ uint8_t* rows_data = (uint8_t*)dec->argb_cache_;
+ const int in_stride = io->width * sizeof(uint32_t); // in unit of RGBA
+ if (!SetCropWindow(io, dec->last_row_, row, &rows_data, in_stride)) {
// Nothing to output (this time).
} else {
const WebPDecBuffer* const output = dec->output_;
- const int in_stride = io->width * sizeof(*rows_data);
- if (output->colorspace < MODE_YUV) { // convert to RGBA
+ if (WebPIsRGBMode(output->colorspace)) { // convert to RGBA
const WebPRGBABuffer* const buf = &output->u.RGBA;
uint8_t* const rgba = buf->rgba + dec->last_out_row_ * buf->stride;
const int num_rows_out = io->use_scaling ?
- EmitRescaledRows(dec, rows_data, in_stride, io->mb_h,
- rgba, buf->stride) :
+ EmitRescaledRowsRGBA(dec, rows_data, in_stride, io->mb_h,
+ rgba, buf->stride) :
EmitRows(output->colorspace, rows_data, in_stride,
io->mb_w, io->mb_h, rgba, buf->stride);
// Update 'last_out_row_'.
@@ -676,50 +770,317 @@ static void ProcessRows(VP8LDecoder* const dec, int row) {
assert(dec->last_row_ <= dec->height_);
}
-static int DecodeImageData(VP8LDecoder* const dec,
- uint32_t* const data, int width, int height,
- ProcessRowsFunc process_func) {
+// Row-processing for the special case when alpha data contains only one
+// transform (color indexing), and trivial non-green literals.
+static int Is8bOptimizable(const VP8LMetadata* const hdr) {
+ int i;
+ if (hdr->color_cache_size_ > 0) return 0;
+ // When the Huffman tree contains only one symbol, we can skip the
+ // call to ReadSymbol() for red/blue/alpha channels.
+ for (i = 0; i < hdr->num_htree_groups_; ++i) {
+ HuffmanCode** const htrees = hdr->htree_groups_[i].htrees;
+ if (htrees[RED][0].bits > 0) return 0;
+ if (htrees[BLUE][0].bits > 0) return 0;
+ if (htrees[ALPHA][0].bits > 0) return 0;
+ }
+ return 1;
+}
+
+static void ExtractPalettedAlphaRows(VP8LDecoder* const dec, int row) {
+ const int num_rows = row - dec->last_row_;
+ const uint8_t* const in =
+ (uint8_t*)dec->pixels_ + dec->width_ * dec->last_row_;
+ if (num_rows > 0) {
+ ApplyInverseTransformsAlpha(dec, num_rows, in);
+ }
+ dec->last_row_ = dec->last_out_row_ = row;
+}
+
+//------------------------------------------------------------------------------
+// Helper functions for fast pattern copy (8b and 32b)
+
+// cyclic rotation of pattern word
+static WEBP_INLINE uint32_t Rotate8b(uint32_t V) {
+#if defined(WORDS_BIGENDIAN)
+ return ((V & 0xff000000u) >> 24) | (V << 8);
+#else
+ return ((V & 0xffu) << 24) | (V >> 8);
+#endif
+}
+
+// copy 1, 2 or 4-bytes pattern
+static WEBP_INLINE void CopySmallPattern8b(const uint8_t* src, uint8_t* dst,
+ int length, uint32_t pattern) {
+ int i;
+ // align 'dst' to 4-bytes boundary. Adjust the pattern along the way.
+ while ((uintptr_t)dst & 3) {
+ *dst++ = *src++;
+ pattern = Rotate8b(pattern);
+ --length;
+ }
+ // Copy the pattern 4 bytes at a time.
+ for (i = 0; i < (length >> 2); ++i) {
+ ((uint32_t*)dst)[i] = pattern;
+ }
+ // Finish with left-overs. 'pattern' is still correctly positioned,
+ // so no Rotate8b() call is needed.
+ for (i <<= 2; i < length; ++i) {
+ dst[i] = src[i];
+ }
+}
+
+static WEBP_INLINE void CopyBlock8b(uint8_t* const dst, int dist, int length) {
+ const uint8_t* src = dst - dist;
+ if (length >= 8) {
+ uint32_t pattern = 0;
+ switch (dist) {
+ case 1:
+ pattern = src[0];
+#if defined(__arm__) || defined(_M_ARM) // arm doesn't like multiply that much
+ pattern |= pattern << 8;
+ pattern |= pattern << 16;
+#elif defined(WEBP_USE_MIPS_DSP_R2)
+ __asm__ volatile ("replv.qb %0, %0" : "+r"(pattern));
+#else
+ pattern = 0x01010101u * pattern;
+#endif
+ break;
+ case 2:
+ memcpy(&pattern, src, sizeof(uint16_t));
+#if defined(__arm__) || defined(_M_ARM)
+ pattern |= pattern << 16;
+#elif defined(WEBP_USE_MIPS_DSP_R2)
+ __asm__ volatile ("replv.ph %0, %0" : "+r"(pattern));
+#else
+ pattern = 0x00010001u * pattern;
+#endif
+ break;
+ case 4:
+ memcpy(&pattern, src, sizeof(uint32_t));
+ break;
+ default:
+ goto Copy;
+ break;
+ }
+ CopySmallPattern8b(src, dst, length, pattern);
+ return;
+ }
+ Copy:
+ if (dist >= length) { // no overlap -> use memcpy()
+ memcpy(dst, src, length * sizeof(*dst));
+ } else {
+ int i;
+ for (i = 0; i < length; ++i) dst[i] = src[i];
+ }
+}
+
+// copy pattern of 1 or 2 uint32_t's
+static WEBP_INLINE void CopySmallPattern32b(const uint32_t* src,
+ uint32_t* dst,
+ int length, uint64_t pattern) {
+ int i;
+ if ((uintptr_t)dst & 4) { // Align 'dst' to 8-bytes boundary.
+ *dst++ = *src++;
+ pattern = (pattern >> 32) | (pattern << 32);
+ --length;
+ }
+ assert(0 == ((uintptr_t)dst & 7));
+ for (i = 0; i < (length >> 1); ++i) {
+ ((uint64_t*)dst)[i] = pattern; // Copy the pattern 8 bytes at a time.
+ }
+ if (length & 1) { // Finish with left-over.
+ dst[i << 1] = src[i << 1];
+ }
+}
+
+static WEBP_INLINE void CopyBlock32b(uint32_t* const dst,
+ int dist, int length) {
+ const uint32_t* const src = dst - dist;
+ if (dist <= 2 && length >= 4 && ((uintptr_t)dst & 3) == 0) {
+ uint64_t pattern;
+ if (dist == 1) {
+ pattern = (uint64_t)src[0];
+ pattern |= pattern << 32;
+ } else {
+ memcpy(&pattern, src, sizeof(pattern));
+ }
+ CopySmallPattern32b(src, dst, length, pattern);
+ } else if (dist >= length) { // no overlap
+ memcpy(dst, src, length * sizeof(*dst));
+ } else {
+ int i;
+ for (i = 0; i < length; ++i) dst[i] = src[i];
+ }
+}
+
+//------------------------------------------------------------------------------
+
+static int DecodeAlphaData(VP8LDecoder* const dec, uint8_t* const data,
+ int width, int height, int last_row) {
int ok = 1;
- int col = 0, row = 0;
+ int row = dec->last_pixel_ / width;
+ int col = dec->last_pixel_ % width;
VP8LBitReader* const br = &dec->br_;
VP8LMetadata* const hdr = &dec->hdr_;
- HTreeGroup* htree_group = hdr->htree_groups_;
- uint32_t* src = data;
- uint32_t* last_cached = data;
- uint32_t* const src_end = data + width * height;
+ const HTreeGroup* htree_group = GetHtreeGroupForPos(hdr, col, row);
+ int pos = dec->last_pixel_; // current position
+ const int end = width * height; // End of data
+ const int last = width * last_row; // Last pixel to decode
const int len_code_limit = NUM_LITERAL_CODES + NUM_LENGTH_CODES;
- const int color_cache_limit = len_code_limit + hdr->color_cache_size_;
- VP8LColorCache* const color_cache =
- (hdr->color_cache_size_ > 0) ? &hdr->color_cache_ : NULL;
const int mask = hdr->huffman_mask_;
-
assert(htree_group != NULL);
+ assert(pos < end);
+ assert(last_row <= height);
+ assert(Is8bOptimizable(hdr));
- while (!br->eos_ && src < src_end) {
+ while (!br->eos_ && pos < last) {
int code;
- // Only update when changing tile. Note we could use the following test:
- // if "((((prev_col ^ col) | prev_row ^ row)) > mask)" -> tile changed
- // but that's actually slower and requires storing the previous col/row
+ // Only update when changing tile.
if ((col & mask) == 0) {
htree_group = GetHtreeGroupForPos(hdr, col, row);
}
VP8LFillBitWindow(br);
- code = ReadSymbol(&htree_group->htrees_[GREEN], br);
- if (code < NUM_LITERAL_CODES) { // Literal.
- int red, green, blue, alpha;
- red = ReadSymbol(&htree_group->htrees_[RED], br);
- green = code;
+ code = ReadSymbol(htree_group->htrees[GREEN], br);
+ if (code < NUM_LITERAL_CODES) { // Literal
+ data[pos] = code;
+ ++pos;
+ ++col;
+ if (col >= width) {
+ col = 0;
+ ++row;
+ if (row % NUM_ARGB_CACHE_ROWS == 0) {
+ ExtractPalettedAlphaRows(dec, row);
+ }
+ }
+ } else if (code < len_code_limit) { // Backward reference
+ int dist_code, dist;
+ const int length_sym = code - NUM_LITERAL_CODES;
+ const int length = GetCopyLength(length_sym, br);
+ const int dist_symbol = ReadSymbol(htree_group->htrees[DIST], br);
VP8LFillBitWindow(br);
- blue = ReadSymbol(&htree_group->htrees_[BLUE], br);
- alpha = ReadSymbol(&htree_group->htrees_[ALPHA], br);
- *src = (alpha << 24) + (red << 16) + (green << 8) + blue;
- AdvanceByOne:
+ dist_code = GetCopyDistance(dist_symbol, br);
+ dist = PlaneCodeToDistance(width, dist_code);
+ if (pos >= dist && end - pos >= length) {
+ CopyBlock8b(data + pos, dist, length);
+ } else {
+ ok = 0;
+ goto End;
+ }
+ pos += length;
+ col += length;
+ while (col >= width) {
+ col -= width;
+ ++row;
+ if (row % NUM_ARGB_CACHE_ROWS == 0) {
+ ExtractPalettedAlphaRows(dec, row);
+ }
+ }
+ if (pos < last && (col & mask)) {
+ htree_group = GetHtreeGroupForPos(hdr, col, row);
+ }
+ } else { // Not reached
+ ok = 0;
+ goto End;
+ }
+ assert(br->eos_ == VP8LIsEndOfStream(br));
+ }
+ // Process the remaining rows corresponding to last row-block.
+ ExtractPalettedAlphaRows(dec, row);
+
+ End:
+ if (!ok || (br->eos_ && pos < end)) {
+ ok = 0;
+ dec->status_ = br->eos_ ? VP8_STATUS_SUSPENDED
+ : VP8_STATUS_BITSTREAM_ERROR;
+ } else {
+ dec->last_pixel_ = pos;
+ }
+ return ok;
+}
+
+static void SaveState(VP8LDecoder* const dec, int last_pixel) {
+ assert(dec->incremental_);
+ dec->saved_br_ = dec->br_;
+ dec->saved_last_pixel_ = last_pixel;
+ if (dec->hdr_.color_cache_size_ > 0) {
+ VP8LColorCacheCopy(&dec->hdr_.color_cache_, &dec->hdr_.saved_color_cache_);
+ }
+}
+
+static void RestoreState(VP8LDecoder* const dec) {
+ assert(dec->br_.eos_);
+ dec->status_ = VP8_STATUS_SUSPENDED;
+ dec->br_ = dec->saved_br_;
+ dec->last_pixel_ = dec->saved_last_pixel_;
+ if (dec->hdr_.color_cache_size_ > 0) {
+ VP8LColorCacheCopy(&dec->hdr_.saved_color_cache_, &dec->hdr_.color_cache_);
+ }
+}
+
+#define SYNC_EVERY_N_ROWS 8 // minimum number of rows between check-points
+static int DecodeImageData(VP8LDecoder* const dec, uint32_t* const data,
+ int width, int height, int last_row,
+ ProcessRowsFunc process_func) {
+ int row = dec->last_pixel_ / width;
+ int col = dec->last_pixel_ % width;
+ VP8LBitReader* const br = &dec->br_;
+ VP8LMetadata* const hdr = &dec->hdr_;
+ HTreeGroup* htree_group = GetHtreeGroupForPos(hdr, col, row);
+ uint32_t* src = data + dec->last_pixel_;
+ uint32_t* last_cached = src;
+ uint32_t* const src_end = data + width * height; // End of data
+ uint32_t* const src_last = data + width * last_row; // Last pixel to decode
+ const int len_code_limit = NUM_LITERAL_CODES + NUM_LENGTH_CODES;
+ const int color_cache_limit = len_code_limit + hdr->color_cache_size_;
+ int next_sync_row = dec->incremental_ ? row : 1 << 24;
+ VP8LColorCache* const color_cache =
+ (hdr->color_cache_size_ > 0) ? &hdr->color_cache_ : NULL;
+ const int mask = hdr->huffman_mask_;
+ assert(htree_group != NULL);
+ assert(src < src_end);
+ assert(src_last <= src_end);
+
+ while (src < src_last) {
+ int code;
+ if (row >= next_sync_row) {
+ SaveState(dec, (int)(src - data));
+ next_sync_row = row + SYNC_EVERY_N_ROWS;
+ }
+ // Only update when changing tile. Note we could use this test:
+ // if "((((prev_col ^ col) | prev_row ^ row)) > mask)" -> tile changed
+ // but that's actually slower and needs storing the previous col/row.
+ if ((col & mask) == 0) htree_group = GetHtreeGroupForPos(hdr, col, row);
+ if (htree_group->is_trivial_code) {
+ *src = htree_group->literal_arb;
+ goto AdvanceByOne;
+ }
+ VP8LFillBitWindow(br);
+ if (htree_group->use_packed_table) {
+ code = ReadPackedSymbols(htree_group, br, src);
+ if (code == PACKED_NON_LITERAL_CODE) goto AdvanceByOne;
+ } else {
+ code = ReadSymbol(htree_group->htrees[GREEN], br);
+ }
+ if (br->eos_) break; // early out
+ if (code < NUM_LITERAL_CODES) { // Literal
+ if (htree_group->is_trivial_literal) {
+ *src = htree_group->literal_arb | (code << 8);
+ } else {
+ int red, blue, alpha;
+ red = ReadSymbol(htree_group->htrees[RED], br);
+ VP8LFillBitWindow(br);
+ blue = ReadSymbol(htree_group->htrees[BLUE], br);
+ alpha = ReadSymbol(htree_group->htrees[ALPHA], br);
+ if (br->eos_) break;
+ *src = ((uint32_t)alpha << 24) | (red << 16) | (code << 8) | blue;
+ }
+ AdvanceByOne:
++src;
++col;
if (col >= width) {
col = 0;
++row;
- if ((process_func != NULL) && (row % NUM_ARGB_CACHE_ROWS == 0)) {
+ if ((row % NUM_ARGB_CACHE_ROWS == 0) && (process_func != NULL)) {
process_func(dec, row);
}
if (color_cache != NULL) {
@@ -728,40 +1089,39 @@ static int DecodeImageData(VP8LDecoder* const dec,
}
}
}
- } else if (code < len_code_limit) { // Backward reference
+ } else if (code < len_code_limit) { // Backward reference
int dist_code, dist;
const int length_sym = code - NUM_LITERAL_CODES;
const int length = GetCopyLength(length_sym, br);
- const int dist_symbol = ReadSymbol(&htree_group->htrees_[DIST], br);
+ const int dist_symbol = ReadSymbol(htree_group->htrees[DIST], br);
VP8LFillBitWindow(br);
dist_code = GetCopyDistance(dist_symbol, br);
dist = PlaneCodeToDistance(width, dist_code);
- if (src - data < dist || src_end - src < length) {
- ok = 0;
- goto End;
- }
- {
- int i;
- for (i = 0; i < length; ++i) src[i] = src[i - dist];
- src += length;
+ if (br->eos_) break;
+ if (src - data < (ptrdiff_t)dist || src_end - src < (ptrdiff_t)length) {
+ goto Error;
+ } else {
+ CopyBlock32b(src, dist, length);
}
+ src += length;
col += length;
while (col >= width) {
col -= width;
++row;
- if ((process_func != NULL) && (row % NUM_ARGB_CACHE_ROWS == 0)) {
+ if ((row % NUM_ARGB_CACHE_ROWS == 0) && (process_func != NULL)) {
process_func(dec, row);
}
}
- if (src < src_end) {
- htree_group = GetHtreeGroupForPos(hdr, col, row);
- if (color_cache != NULL) {
- while (last_cached < src) {
- VP8LColorCacheInsert(color_cache, *last_cached++);
- }
+ // Because of the check done above (before 'src' was incremented by
+ // 'length'), the following holds true.
+ assert(src <= src_end);
+ if (col & mask) htree_group = GetHtreeGroupForPos(hdr, col, row);
+ if (color_cache != NULL) {
+ while (last_cached < src) {
+ VP8LColorCacheInsert(color_cache, *last_cached++);
}
}
- } else if (code < color_cache_limit) { // Color cache.
+ } else if (code < color_cache_limit) { // Color cache
const int key = code - len_code_limit;
assert(color_cache != NULL);
while (last_cached < src) {
@@ -769,33 +1129,38 @@ static int DecodeImageData(VP8LDecoder* const dec,
}
*src = VP8LColorCacheLookup(color_cache, key);
goto AdvanceByOne;
- } else { // Not reached.
- ok = 0;
- goto End;
+ } else { // Not reached
+ goto Error;
}
- ok = !br->error_;
- if (!ok) goto End;
+ assert(br->eos_ == VP8LIsEndOfStream(br));
}
- // Process the remaining rows corresponding to last row-block.
- if (process_func != NULL) process_func(dec, row);
- End:
- if (br->error_ || !ok || (br->eos_ && src < src_end)) {
- ok = 0;
- dec->status_ = (!br->eos_) ?
- VP8_STATUS_BITSTREAM_ERROR : VP8_STATUS_SUSPENDED;
- } else if (src == src_end) {
- dec->state_ = READ_DATA;
+ if (dec->incremental_ && br->eos_ && src < src_end) {
+ RestoreState(dec);
+ } else if (!br->eos_) {
+ // Process the remaining rows corresponding to last row-block.
+ if (process_func != NULL) {
+ process_func(dec, row);
+ }
+ dec->status_ = VP8_STATUS_OK;
+ dec->last_pixel_ = (int)(src - data); // end-of-scan marker
+ } else {
+ // if not incremental, and we are past the end of buffer (eos_=1), then this
+ // is a real bitstream error.
+ goto Error;
}
+ return 1;
- return ok;
+ Error:
+ dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
+ return 0;
}
// -----------------------------------------------------------------------------
// VP8LTransform
static void ClearTransform(VP8LTransform* const transform) {
- free(transform->data_);
+ WebPSafeFree(transform->data_);
transform->data_ = NULL;
}
@@ -819,7 +1184,7 @@ static int ExpandColorMap(int num_colors, VP8LTransform* const transform) {
}
for (; i < 4 * final_num_colors; ++i)
new_data[i] = 0; // black tail.
- free(transform->data_);
+ WebPSafeFree(transform->data_);
transform->data_ = new_color_map;
}
return 1;
@@ -882,16 +1247,18 @@ static int ReadTransform(int* const xsize, int const* ysize,
// VP8LMetadata
static void InitMetadata(VP8LMetadata* const hdr) {
- assert(hdr);
+ assert(hdr != NULL);
memset(hdr, 0, sizeof(*hdr));
}
static void ClearMetadata(VP8LMetadata* const hdr) {
- assert(hdr);
+ assert(hdr != NULL);
- free(hdr->huffman_image_);
- DeleteHtreeGroups(hdr->htree_groups_, hdr->num_htree_groups_);
+ WebPSafeFree(hdr->huffman_image_);
+ WebPSafeFree(hdr->huffman_tables_);
+ VP8LHtreeGroupsFree(hdr->htree_groups_);
VP8LColorCacheClear(&hdr->color_cache_);
+ VP8LColorCacheClear(&hdr->saved_color_cache_);
InitMetadata(hdr);
}
@@ -899,11 +1266,13 @@ static void ClearMetadata(VP8LMetadata* const hdr) {
// VP8LDecoder
VP8LDecoder* VP8LNew(void) {
- VP8LDecoder* const dec = (VP8LDecoder*)calloc(1, sizeof(*dec));
+ VP8LDecoder* const dec = (VP8LDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
if (dec == NULL) return NULL;
dec->status_ = VP8_STATUS_OK;
- dec->action_ = READ_DIM;
dec->state_ = READ_DIM;
+
+ VP8LDspInit(); // Init critical function pointers.
+
return dec;
}
@@ -912,15 +1281,15 @@ void VP8LClear(VP8LDecoder* const dec) {
if (dec == NULL) return;
ClearMetadata(&dec->hdr_);
- free(dec->argb_);
- dec->argb_ = NULL;
+ WebPSafeFree(dec->pixels_);
+ dec->pixels_ = NULL;
for (i = 0; i < dec->next_transform_; ++i) {
ClearTransform(&dec->transforms_[i]);
}
dec->next_transform_ = 0;
dec->transforms_seen_ = 0;
- free(dec->rescaler_memory);
+ WebPSafeFree(dec->rescaler_memory);
dec->rescaler_memory = NULL;
dec->output_ = NULL; // leave no trace behind
@@ -929,7 +1298,7 @@ void VP8LClear(VP8LDecoder* const dec) {
void VP8LDelete(VP8LDecoder* const dec) {
if (dec != NULL) {
VP8LClear(dec);
- free(dec);
+ WebPSafeFree(dec);
}
}
@@ -1009,19 +1378,14 @@ static int DecodeImageStream(int xsize, int ysize,
}
// Use the Huffman trees to decode the LZ77 encoded data.
- ok = DecodeImageData(dec, data, transform_xsize, transform_ysize, NULL);
- ok = ok && !br->error_;
+ ok = DecodeImageData(dec, data, transform_xsize, transform_ysize,
+ transform_ysize, NULL);
+ ok = ok && !br->eos_;
End:
-
if (!ok) {
- free(data);
+ WebPSafeFree(data);
ClearMetadata(hdr);
- // If not enough data (br.eos_) resulted in BIT_STREAM_ERROR, update the
- // status appropriately.
- if (dec->status_ == VP8_STATUS_BITSTREAM_ERROR && dec->br_.eos_) {
- dec->status_ = VP8_STATUS_SUSPENDED;
- }
} else {
if (decoded_data != NULL) {
*decoded_data = data;
@@ -1031,41 +1395,52 @@ static int DecodeImageStream(int xsize, int ysize,
assert(data == NULL);
assert(is_level0);
}
+ dec->last_pixel_ = 0; // Reset for future DECODE_DATA_FUNC() calls.
if (!is_level0) ClearMetadata(hdr); // Clean up temporary data behind.
}
return ok;
}
//------------------------------------------------------------------------------
-// Allocate dec->argb_ and dec->argb_cache_ using dec->width_ and dec->height_
-
-static int AllocateARGBBuffers(VP8LDecoder* const dec, int final_width) {
+// Allocate internal buffers dec->pixels_ and dec->argb_cache_.
+static int AllocateInternalBuffers32b(VP8LDecoder* const dec, int final_width) {
const uint64_t num_pixels = (uint64_t)dec->width_ * dec->height_;
// Scratch buffer corresponding to top-prediction row for transforming the
- // first row in the row-blocks.
- const uint64_t cache_top_pixels = final_width;
- // Scratch buffer for temporary BGRA storage.
+ // first row in the row-blocks. Not needed for paletted alpha.
+ const uint64_t cache_top_pixels = (uint16_t)final_width;
+ // Scratch buffer for temporary BGRA storage. Not needed for paletted alpha.
const uint64_t cache_pixels = (uint64_t)final_width * NUM_ARGB_CACHE_ROWS;
const uint64_t total_num_pixels =
num_pixels + cache_top_pixels + cache_pixels;
assert(dec->width_ <= final_width);
- dec->argb_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(*dec->argb_));
- if (dec->argb_ == NULL) {
+ dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint32_t));
+ if (dec->pixels_ == NULL) {
dec->argb_cache_ = NULL; // for sanity check
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
return 0;
}
- dec->argb_cache_ = dec->argb_ + num_pixels + cache_top_pixels;
+ dec->argb_cache_ = dec->pixels_ + num_pixels + cache_top_pixels;
+ return 1;
+}
+
+static int AllocateInternalBuffers8b(VP8LDecoder* const dec) {
+ const uint64_t total_num_pixels = (uint64_t)dec->width_ * dec->height_;
+ dec->argb_cache_ = NULL; // for sanity check
+ dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(uint8_t));
+ if (dec->pixels_ == NULL) {
+ dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
+ return 0;
+ }
return 1;
}
//------------------------------------------------------------------------------
-// Special row-processing that only stores the alpha data.
+// Special row-processing that only stores the alpha data.
static void ExtractAlphaRows(VP8LDecoder* const dec, int row) {
const int num_rows = row - dec->last_row_;
- const uint32_t* const in = dec->argb_ + dec->width_ * dec->last_row_;
+ const uint32_t* const in = dec->pixels_ + dec->width_ * dec->last_row_;
if (num_rows <= 0) return; // Nothing to be done.
ApplyInverseTransforms(dec, num_rows, in);
@@ -1079,44 +1454,77 @@ static void ExtractAlphaRows(VP8LDecoder* const dec, int row) {
int i;
for (i = 0; i < cache_pixs; ++i) dst[i] = (src[i] >> 8) & 0xff;
}
-
dec->last_row_ = dec->last_out_row_ = row;
}
-int VP8LDecodeAlphaImageStream(int width, int height, const uint8_t* const data,
- size_t data_size, uint8_t* const output) {
- VP8Io io;
+int VP8LDecodeAlphaHeader(ALPHDecoder* const alph_dec,
+ const uint8_t* const data, size_t data_size,
+ uint8_t* const output) {
int ok = 0;
- VP8LDecoder* const dec = VP8LNew();
- if (dec == NULL) return 0;
-
- dec->width_ = width;
- dec->height_ = height;
- dec->io_ = &io;
+ VP8LDecoder* dec;
+ VP8Io* io;
+ assert(alph_dec != NULL);
+ alph_dec->vp8l_dec_ = VP8LNew();
+ if (alph_dec->vp8l_dec_ == NULL) return 0;
+ dec = alph_dec->vp8l_dec_;
+
+ dec->width_ = alph_dec->width_;
+ dec->height_ = alph_dec->height_;
+ dec->io_ = &alph_dec->io_;
+ io = dec->io_;
- VP8InitIo(&io);
- WebPInitCustomIo(NULL, &io); // Just a sanity Init. io won't be used.
- io.opaque = output;
- io.width = width;
- io.height = height;
+ VP8InitIo(io);
+ WebPInitCustomIo(NULL, io); // Just a sanity Init. io won't be used.
+ io->opaque = output;
+ io->width = alph_dec->width_;
+ io->height = alph_dec->height_;
dec->status_ = VP8_STATUS_OK;
VP8LInitBitReader(&dec->br_, data, data_size);
- dec->action_ = READ_HDR;
- if (!DecodeImageStream(width, height, 1, dec, NULL)) goto Err;
+ if (!DecodeImageStream(alph_dec->width_, alph_dec->height_, 1, dec, NULL)) {
+ goto Err;
+ }
- // Allocate output (note that dec->width_ may have changed here).
- if (!AllocateARGBBuffers(dec, width)) goto Err;
+ // Special case: if alpha data uses only the color indexing transform and
+ // doesn't use color cache (a frequent case), we will use DecodeAlphaData()
+ // method that only needs allocation of 1 byte per pixel (alpha channel).
+ if (dec->next_transform_ == 1 &&
+ dec->transforms_[0].type_ == COLOR_INDEXING_TRANSFORM &&
+ Is8bOptimizable(&dec->hdr_)) {
+ alph_dec->use_8b_decode = 1;
+ ok = AllocateInternalBuffers8b(dec);
+ } else {
+ // Allocate internal buffers (note that dec->width_ may have changed here).
+ alph_dec->use_8b_decode = 0;
+ ok = AllocateInternalBuffers32b(dec, alph_dec->width_);
+ }
- // Decode (with special row processing).
- dec->action_ = READ_DATA;
- ok = DecodeImageData(dec, dec->argb_, dec->width_, dec->height_,
- ExtractAlphaRows);
+ if (!ok) goto Err;
+
+ return 1;
Err:
- VP8LDelete(dec);
- return ok;
+ VP8LDelete(alph_dec->vp8l_dec_);
+ alph_dec->vp8l_dec_ = NULL;
+ return 0;
+}
+
+int VP8LDecodeAlphaImageStream(ALPHDecoder* const alph_dec, int last_row) {
+ VP8LDecoder* const dec = alph_dec->vp8l_dec_;
+ assert(dec != NULL);
+ assert(last_row <= dec->height_);
+
+ if (dec->last_pixel_ == dec->width_ * dec->height_) {
+ return 1; // done
+ }
+
+ // Decode (with special row processing).
+ return alph_dec->use_8b_decode ?
+ DecodeAlphaData(dec, (uint8_t*)dec->pixels_, dec->width_, dec->height_,
+ last_row) :
+ DecodeImageData(dec, dec->pixels_, dec->width_, dec->height_,
+ last_row, ExtractAlphaRows);
}
//------------------------------------------------------------------------------
@@ -1141,14 +1549,13 @@ int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io) {
io->width = width;
io->height = height;
- dec->action_ = READ_HDR;
if (!DecodeImageStream(width, height, 1, dec, NULL)) goto Error;
return 1;
Error:
- VP8LClear(dec);
- assert(dec->status_ != VP8_STATUS_OK);
- return 0;
+ VP8LClear(dec);
+ assert(dec->status_ != VP8_STATUS_OK);
+ return 0;
}
int VP8LDecodeImage(VP8LDecoder* const dec) {
@@ -1158,33 +1565,57 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
// Sanity checks.
if (dec == NULL) return 0;
+ assert(dec->hdr_.huffman_tables_ != NULL);
+ assert(dec->hdr_.htree_groups_ != NULL);
+ assert(dec->hdr_.num_htree_groups_ > 0);
+
io = dec->io_;
assert(io != NULL);
params = (WebPDecParams*)io->opaque;
assert(params != NULL);
- dec->output_ = params->output;
- assert(dec->output_ != NULL);
// Initialization.
- if (!WebPIoInitFromOptions(params->options, io, MODE_BGRA)) {
- dec->status_ = VP8_STATUS_INVALID_PARAM;
- goto Err;
- }
+ if (dec->state_ != READ_DATA) {
+ dec->output_ = params->output;
+ assert(dec->output_ != NULL);
+
+ if (!WebPIoInitFromOptions(params->options, io, MODE_BGRA)) {
+ dec->status_ = VP8_STATUS_INVALID_PARAM;
+ goto Err;
+ }
- if (!AllocateARGBBuffers(dec, io->width)) goto Err;
+ if (!AllocateInternalBuffers32b(dec, io->width)) goto Err;
- if (io->use_scaling && !AllocateAndInitRescaler(dec, io)) goto Err;
+ if (io->use_scaling && !AllocateAndInitRescaler(dec, io)) goto Err;
+
+ if (io->use_scaling || WebPIsPremultipliedMode(dec->output_->colorspace)) {
+ // need the alpha-multiply functions for premultiplied output or rescaling
+ WebPInitAlphaProcessing();
+ }
+ if (!WebPIsRGBMode(dec->output_->colorspace)) {
+ WebPInitConvertARGBToYUV();
+ if (dec->output_->u.YUVA.a != NULL) WebPInitAlphaProcessing();
+ }
+ if (dec->incremental_) {
+ if (dec->hdr_.color_cache_size_ > 0 &&
+ dec->hdr_.saved_color_cache_.colors_ == NULL) {
+ if (!VP8LColorCacheInit(&dec->hdr_.saved_color_cache_,
+ dec->hdr_.color_cache_.hash_bits_)) {
+ dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
+ goto Err;
+ }
+ }
+ }
+ dec->state_ = READ_DATA;
+ }
// Decode.
- dec->action_ = READ_DATA;
- if (!DecodeImageData(dec, dec->argb_, dec->width_, dec->height_,
- ProcessRows)) {
+ if (!DecodeImageData(dec, dec->pixels_, dec->width_, dec->height_,
+ dec->height_, ProcessRows)) {
goto Err;
}
- // Cleanup.
params->last_y = dec->last_out_row_;
- VP8LClear(dec);
return 1;
Err:
@@ -1194,7 +1625,3 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
}
//------------------------------------------------------------------------------
-
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/dec/vp8li.h b/drivers/webp/dec/vp8li.h
index 5f6cd6a01c..8886e47f62 100644
--- a/drivers/webp/dec/vp8li.h
+++ b/drivers/webp/dec/vp8li.h
@@ -1,8 +1,10 @@
// Copyright 2012 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Lossless decoder: internal header.
@@ -18,9 +20,8 @@
#include "../utils/bit_reader.h"
#include "../utils/color_cache.h"
#include "../utils/huffman.h"
-#include "../format_constants.h"
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
extern "C" {
#endif
@@ -40,12 +41,9 @@ struct VP8LTransform {
};
typedef struct {
- HuffmanTree htrees_[HUFFMAN_CODES_PER_META_CODE];
-} HTreeGroup;
-
-typedef struct {
int color_cache_size_;
VP8LColorCache color_cache_;
+ VP8LColorCache saved_color_cache_; // for incremental
int huffman_mask_;
int huffman_subsample_bits_;
@@ -53,24 +51,32 @@ typedef struct {
uint32_t *huffman_image_;
int num_htree_groups_;
HTreeGroup *htree_groups_;
+ HuffmanCode *huffman_tables_;
} VP8LMetadata;
-typedef struct {
+typedef struct VP8LDecoder VP8LDecoder;
+struct VP8LDecoder {
VP8StatusCode status_;
- VP8LDecodeState action_;
VP8LDecodeState state_;
VP8Io *io_;
const WebPDecBuffer *output_; // shortcut to io->opaque->output
- uint32_t *argb_; // Internal data: always in BGRA color mode.
+ uint32_t *pixels_; // Internal data: either uint8_t* for alpha
+ // or uint32_t* for BGRA.
uint32_t *argb_cache_; // Scratch buffer for temporary BGRA storage.
VP8LBitReader br_;
+ int incremental_; // if true, incremental decoding is expected
+ VP8LBitReader saved_br_; // note: could be local variables too
+ int saved_last_pixel_;
int width_;
int height_;
int last_row_; // last input row decoded so far.
+ int last_pixel_; // last pixel decoded so far. However, it may
+ // not be transformed, scaled and
+ // color-converted yet.
int last_out_row_; // last row output so far.
VP8LMetadata hdr_;
@@ -82,18 +88,27 @@ typedef struct {
uint8_t *rescaler_memory; // Working memory for rescaling work.
WebPRescaler *rescaler; // Common rescaler for all channels.
-} VP8LDecoder;
+};
//------------------------------------------------------------------------------
// internal functions. Not public.
+struct ALPHDecoder; // Defined in dec/alphai.h.
+
// in vp8l.c
-// Decodes a raw image stream (without header) and store the alpha data
-// into *output, which must be of size width x height. Returns false in case
-// of error.
-int VP8LDecodeAlphaImageStream(int width, int height, const uint8_t* const data,
- size_t data_size, uint8_t* const output);
+// Decodes image header for alpha data stored using lossless compression.
+// Returns false in case of error.
+int VP8LDecodeAlphaHeader(struct ALPHDecoder* const alph_dec,
+ const uint8_t* const data, size_t data_size,
+ uint8_t* const output);
+
+// Decodes *at least* 'last_row' rows of alpha. If some of the initial rows are
+// already decoded in previous call(s), it will resume decoding from where it
+// was paused.
+// Returns false in case of bitstream error.
+int VP8LDecodeAlphaImageStream(struct ALPHDecoder* const alph_dec,
+ int last_row);
// Allocates and initialize a new lossless decoder instance.
VP8LDecoder* VP8LNew(void);
@@ -114,7 +129,7 @@ void VP8LDelete(VP8LDecoder* const dec);
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/drivers/webp/dec/webp.c b/drivers/webp/dec/webp.c
index f44bc2b8ae..93a113a48d 100644
--- a/drivers/webp/dec/webp.c
+++ b/drivers/webp/dec/webp.c
@@ -1,8 +1,10 @@
// Copyright 2010 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Main decoding functions for WEBP images.
@@ -14,11 +16,8 @@
#include "./vp8i.h"
#include "./vp8li.h"
#include "./webpi.h"
-#include "../format_constants.h"
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
+#include "../utils/utils.h"
+#include "webp/mux_types.h" // ALPHA_FLAG
//------------------------------------------------------------------------------
// RIFF layout is:
@@ -40,27 +39,20 @@ extern "C" {
// 20..23 VP8X flags bit-map corresponding to the chunk-types present.
// 24..26 Width of the Canvas Image.
// 27..29 Height of the Canvas Image.
-// There can be extra chunks after the "VP8X" chunk (ICCP, TILE, FRM, VP8,
-// META ...)
+// There can be extra chunks after the "VP8X" chunk (ICCP, FRGM, ANMF, VP8,
+// VP8L, XMP, EXIF ...)
// All sizes are in little-endian order.
// Note: chunk data size must be padded to multiple of 2 when written.
-static WEBP_INLINE uint32_t get_le24(const uint8_t* const data) {
- return data[0] | (data[1] << 8) | (data[2] << 16);
-}
-
-static WEBP_INLINE uint32_t get_le32(const uint8_t* const data) {
- return (uint32_t)get_le24(data) | (data[3] << 24);
-}
-
// Validates the RIFF container (if detected) and skips over it.
-// If a RIFF container is detected,
-// Returns VP8_STATUS_BITSTREAM_ERROR for invalid header, and
-// VP8_STATUS_OK otherwise.
+// If a RIFF container is detected, returns:
+// VP8_STATUS_BITSTREAM_ERROR for invalid header,
+// VP8_STATUS_NOT_ENOUGH_DATA for truncated data if have_all_data is true,
+// and VP8_STATUS_OK otherwise.
// In case there are not enough bytes (partial RIFF container), return 0 for
// *riff_size. Else return the RIFF size extracted from the header.
static VP8StatusCode ParseRIFF(const uint8_t** const data,
- size_t* const data_size,
+ size_t* const data_size, int have_all_data,
size_t* const riff_size) {
assert(data != NULL);
assert(data_size != NULL);
@@ -71,11 +63,17 @@ static VP8StatusCode ParseRIFF(const uint8_t** const data,
if (memcmp(*data + 8, "WEBP", TAG_SIZE)) {
return VP8_STATUS_BITSTREAM_ERROR; // Wrong image file signature.
} else {
- const uint32_t size = get_le32(*data + TAG_SIZE);
+ const uint32_t size = GetLE32(*data + TAG_SIZE);
// Check that we have at least one chunk (i.e "WEBP" + "VP8?nnnn").
if (size < TAG_SIZE + CHUNK_HEADER_SIZE) {
return VP8_STATUS_BITSTREAM_ERROR;
}
+ if (size > MAX_CHUNK_PAYLOAD) {
+ return VP8_STATUS_BITSTREAM_ERROR;
+ }
+ if (have_all_data && (size > *data_size - CHUNK_HEADER_SIZE)) {
+ return VP8_STATUS_NOT_ENOUGH_DATA; // Truncated bitstream.
+ }
// We have a RIFF container. Skip it.
*riff_size = size;
*data += RIFF_HEADER_SIZE;
@@ -111,7 +109,7 @@ static VP8StatusCode ParseVP8X(const uint8_t** const data,
if (!memcmp(*data, "VP8X", TAG_SIZE)) {
int width, height;
uint32_t flags;
- const uint32_t chunk_size = get_le32(*data + TAG_SIZE);
+ const uint32_t chunk_size = GetLE32(*data + TAG_SIZE);
if (chunk_size != VP8X_CHUNK_SIZE) {
return VP8_STATUS_BITSTREAM_ERROR; // Wrong chunk size.
}
@@ -120,9 +118,9 @@ static VP8StatusCode ParseVP8X(const uint8_t** const data,
if (*data_size < vp8x_size) {
return VP8_STATUS_NOT_ENOUGH_DATA; // Insufficient data.
}
- flags = get_le32(*data + 8);
- width = 1 + get_le24(*data + 12);
- height = 1 + get_le24(*data + 15);
+ flags = GetLE32(*data + 8);
+ width = 1 + GetLE24(*data + 12);
+ height = 1 + GetLE24(*data + 15);
if (width * (uint64_t)height >= MAX_IMAGE_AREA) {
return VP8_STATUS_BITSTREAM_ERROR; // image is too large
}
@@ -176,7 +174,10 @@ static VP8StatusCode ParseOptionalChunks(const uint8_t** const data,
return VP8_STATUS_NOT_ENOUGH_DATA;
}
- chunk_size = get_le32(buf + TAG_SIZE);
+ chunk_size = GetLE32(buf + TAG_SIZE);
+ if (chunk_size > MAX_CHUNK_PAYLOAD) {
+ return VP8_STATUS_BITSTREAM_ERROR; // Not a valid chunk size.
+ }
// For odd-sized chunk-payload, there's one byte padding at the end.
disk_chunk_size = (CHUNK_HEADER_SIZE + chunk_size + 1) & ~1;
total_size += disk_chunk_size;
@@ -186,6 +187,15 @@ static VP8StatusCode ParseOptionalChunks(const uint8_t** const data,
return VP8_STATUS_BITSTREAM_ERROR; // Not a valid chunk size.
}
+ // Start of a (possibly incomplete) VP8/VP8L chunk implies that we have
+ // parsed all the optional chunks.
+ // Note: This check must occur before the check 'buf_size < disk_chunk_size'
+ // below to allow incomplete VP8/VP8L chunks.
+ if (!memcmp(buf, "VP8 ", TAG_SIZE) ||
+ !memcmp(buf, "VP8L", TAG_SIZE)) {
+ return VP8_STATUS_OK;
+ }
+
if (buf_size < disk_chunk_size) { // Insufficient data.
return VP8_STATUS_NOT_ENOUGH_DATA;
}
@@ -193,9 +203,6 @@ static VP8StatusCode ParseOptionalChunks(const uint8_t** const data,
if (!memcmp(buf, "ALPH", TAG_SIZE)) { // A valid ALPH header.
*alpha_data = buf + CHUNK_HEADER_SIZE;
*alpha_size = chunk_size;
- } else if (!memcmp(buf, "VP8 ", TAG_SIZE) ||
- !memcmp(buf, "VP8L", TAG_SIZE)) { // A valid VP8/VP8L header.
- return VP8_STATUS_OK; // Found.
}
// We have a full and valid chunk; skip it.
@@ -213,9 +220,8 @@ static VP8StatusCode ParseOptionalChunks(const uint8_t** const data,
// extracted from the VP8/VP8L chunk header.
// The flag '*is_lossless' is set to 1 in case of VP8L chunk / raw VP8L data.
static VP8StatusCode ParseVP8Header(const uint8_t** const data_ptr,
- size_t* const data_size,
- size_t riff_size,
- size_t* const chunk_size,
+ size_t* const data_size, int have_all_data,
+ size_t riff_size, size_t* const chunk_size,
int* const is_lossless) {
const uint8_t* const data = *data_ptr;
const int is_vp8 = !memcmp(data, "VP8 ", TAG_SIZE);
@@ -234,10 +240,13 @@ static VP8StatusCode ParseVP8Header(const uint8_t** const data_ptr,
if (is_vp8 || is_vp8l) {
// Bitstream contains VP8/VP8L header.
- const uint32_t size = get_le32(data + TAG_SIZE);
+ const uint32_t size = GetLE32(data + TAG_SIZE);
if ((riff_size >= minimal_size) && (size > riff_size - minimal_size)) {
return VP8_STATUS_BITSTREAM_ERROR; // Inconsistent size information.
}
+ if (have_all_data && (size > *data_size - CHUNK_HEADER_SIZE)) {
+ return VP8_STATUS_NOT_ENOUGH_DATA; // Truncated bitstream.
+ }
// Skip over CHUNK_HEADER_SIZE bytes from VP8/VP8L Header.
*chunk_size = size;
*data_ptr += CHUNK_HEADER_SIZE;
@@ -270,9 +279,19 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
int* const width,
int* const height,
int* const has_alpha,
+ int* const has_animation,
+ int* const format,
WebPHeaderStructure* const headers) {
+ int canvas_width = 0;
+ int canvas_height = 0;
+ int image_width = 0;
+ int image_height = 0;
int found_riff = 0;
int found_vp8x = 0;
+ int animation_present = 0;
+ int fragments_present = 0;
+ const int have_all_data = (headers != NULL) ? headers->have_all_data : 0;
+
VP8StatusCode status;
WebPHeaderStructure hdrs;
@@ -284,7 +303,7 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
hdrs.data_size = data_size;
// Skip over RIFF header.
- status = ParseRIFF(&data, &data_size, &hdrs.riff_size);
+ status = ParseRIFF(&data, &data_size, have_all_data, &hdrs.riff_size);
if (status != VP8_STATUS_OK) {
return status; // Wrong RIFF header / insufficient data.
}
@@ -293,22 +312,35 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
// Skip over VP8X.
{
uint32_t flags = 0;
- status = ParseVP8X(&data, &data_size, &found_vp8x, width, height, &flags);
+ status = ParseVP8X(&data, &data_size, &found_vp8x,
+ &canvas_width, &canvas_height, &flags);
if (status != VP8_STATUS_OK) {
return status; // Wrong VP8X / insufficient data.
}
+ animation_present = !!(flags & ANIMATION_FLAG);
+ fragments_present = !!(flags & FRAGMENTS_FLAG);
if (!found_riff && found_vp8x) {
// Note: This restriction may be removed in the future, if it becomes
// necessary to send VP8X chunk to the decoder.
return VP8_STATUS_BITSTREAM_ERROR;
}
- if (has_alpha != NULL) *has_alpha = !!(flags & ALPHA_FLAG_BIT);
- if (found_vp8x && headers == NULL) {
- return VP8_STATUS_OK; // Return features from VP8X header.
+ if (has_alpha != NULL) *has_alpha = !!(flags & ALPHA_FLAG);
+ if (has_animation != NULL) *has_animation = animation_present;
+ if (format != NULL) *format = 0; // default = undefined
+
+ image_width = canvas_width;
+ image_height = canvas_height;
+ if (found_vp8x && (animation_present || fragments_present) &&
+ headers == NULL) {
+ status = VP8_STATUS_OK;
+ goto ReturnWidthHeight; // Just return features from VP8X header.
}
}
- if (data_size < TAG_SIZE) return VP8_STATUS_NOT_ENOUGH_DATA;
+ if (data_size < TAG_SIZE) {
+ status = VP8_STATUS_NOT_ENOUGH_DATA;
+ goto ReturnWidthHeight;
+ }
// Skip over optional chunks if data started with "RIFF + VP8X" or "ALPH".
if ((found_riff && found_vp8x) ||
@@ -316,43 +348,49 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
status = ParseOptionalChunks(&data, &data_size, hdrs.riff_size,
&hdrs.alpha_data, &hdrs.alpha_data_size);
if (status != VP8_STATUS_OK) {
- return status; // Found an invalid chunk size / insufficient data.
+ goto ReturnWidthHeight; // Invalid chunk size / insufficient data.
}
}
// Skip over VP8/VP8L header.
- status = ParseVP8Header(&data, &data_size, hdrs.riff_size,
+ status = ParseVP8Header(&data, &data_size, have_all_data, hdrs.riff_size,
&hdrs.compressed_size, &hdrs.is_lossless);
if (status != VP8_STATUS_OK) {
- return status; // Wrong VP8/VP8L chunk-header / insufficient data.
+ goto ReturnWidthHeight; // Wrong VP8/VP8L chunk-header / insufficient data.
}
if (hdrs.compressed_size > MAX_CHUNK_PAYLOAD) {
return VP8_STATUS_BITSTREAM_ERROR;
}
+ if (format != NULL && !(animation_present || fragments_present)) {
+ *format = hdrs.is_lossless ? 2 : 1;
+ }
+
if (!hdrs.is_lossless) {
if (data_size < VP8_FRAME_HEADER_SIZE) {
- return VP8_STATUS_NOT_ENOUGH_DATA;
+ status = VP8_STATUS_NOT_ENOUGH_DATA;
+ goto ReturnWidthHeight;
}
// Validates raw VP8 data.
- if (!VP8GetInfo(data, data_size,
- (uint32_t)hdrs.compressed_size, width, height)) {
+ if (!VP8GetInfo(data, data_size, (uint32_t)hdrs.compressed_size,
+ &image_width, &image_height)) {
return VP8_STATUS_BITSTREAM_ERROR;
}
} else {
if (data_size < VP8L_FRAME_HEADER_SIZE) {
- return VP8_STATUS_NOT_ENOUGH_DATA;
+ status = VP8_STATUS_NOT_ENOUGH_DATA;
+ goto ReturnWidthHeight;
}
// Validates raw VP8L data.
- if (!VP8LGetInfo(data, data_size, width, height, has_alpha)) {
+ if (!VP8LGetInfo(data, data_size, &image_width, &image_height, has_alpha)) {
return VP8_STATUS_BITSTREAM_ERROR;
}
}
-
- if (has_alpha != NULL) {
- // If the data did not contain a VP8X/VP8L chunk the only definitive way
- // to set this is by looking for alpha data (from an ALPH chunk).
- *has_alpha |= (hdrs.alpha_data != NULL);
+ // Validates image size coherency.
+ if (found_vp8x) {
+ if (canvas_width != image_width || canvas_height != image_height) {
+ return VP8_STATUS_BITSTREAM_ERROR;
+ }
}
if (headers != NULL) {
*headers = hdrs;
@@ -360,21 +398,44 @@ static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
assert((uint64_t)(data - headers->data) < MAX_CHUNK_PAYLOAD);
assert(headers->offset == headers->data_size - data_size);
}
- return VP8_STATUS_OK; // Return features from VP8 header.
+ ReturnWidthHeight:
+ if (status == VP8_STATUS_OK ||
+ (status == VP8_STATUS_NOT_ENOUGH_DATA && found_vp8x && headers == NULL)) {
+ if (has_alpha != NULL) {
+ // If the data did not contain a VP8X/VP8L chunk the only definitive way
+ // to set this is by looking for alpha data (from an ALPH chunk).
+ *has_alpha |= (hdrs.alpha_data != NULL);
+ }
+ if (width != NULL) *width = image_width;
+ if (height != NULL) *height = image_height;
+ return VP8_STATUS_OK;
+ } else {
+ return status;
+ }
}
VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers) {
+ VP8StatusCode status;
+ int has_animation = 0;
assert(headers != NULL);
// fill out headers, ignore width/height/has_alpha.
- return ParseHeadersInternal(headers->data, headers->data_size,
- NULL, NULL, NULL, headers);
+ status = ParseHeadersInternal(headers->data, headers->data_size,
+ NULL, NULL, NULL, &has_animation,
+ NULL, headers);
+ if (status == VP8_STATUS_OK || status == VP8_STATUS_NOT_ENOUGH_DATA) {
+ // TODO(jzern): full support of animation frames will require API additions.
+ if (has_animation) {
+ status = VP8_STATUS_UNSUPPORTED_FEATURE;
+ }
+ }
+ return status;
}
//------------------------------------------------------------------------------
// WebPDecParams
void WebPResetDecParams(WebPDecParams* const params) {
- if (params) {
+ if (params != NULL) {
memset(params, 0, sizeof(*params));
}
}
@@ -391,6 +452,7 @@ static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size,
headers.data = data;
headers.data_size = data_size;
+ headers.have_all_data = 1;
status = WebPParseHeaders(&headers); // Process Pre-VP8 chunks.
if (status != VP8_STATUS_OK) {
return status;
@@ -407,11 +469,6 @@ static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size,
if (dec == NULL) {
return VP8_STATUS_OUT_OF_MEMORY;
}
-#ifdef WEBP_USE_THREAD
- dec->use_threads_ = params->options && (params->options->use_threads > 0);
-#else
- dec->use_threads_ = 0;
-#endif
dec->alpha_data_ = headers.alpha_data;
dec->alpha_data_size_ = headers.alpha_data_size;
@@ -423,6 +480,10 @@ static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size,
status = WebPAllocateDecBuffer(io.width, io.height, params->options,
params->output);
if (status == VP8_STATUS_OK) { // Decode
+ // This change must be done before calling VP8Decode()
+ dec->mt_method_ = VP8GetThreadMethod(params->options, &headers,
+ io.width, io.height);
+ VP8InitDithering(params->options, dec);
if (!VP8Decode(dec, &io)) {
status = dec->status_;
}
@@ -452,6 +513,10 @@ static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size,
if (status != VP8_STATUS_OK) {
WebPFreeDecBuffer(params->output);
}
+
+ if (params->options != NULL && params->options->flip) {
+ status = WebPFlipBuffer(params->output);
+ }
return status;
}
@@ -609,7 +674,6 @@ uint8_t* WebPDecodeYUV(const uint8_t* data, size_t data_size,
static void DefaultFeatures(WebPBitstreamFeatures* const features) {
assert(features != NULL);
memset(features, 0, sizeof(*features));
- features->bitstream_version = 0;
}
static VP8StatusCode GetFeatures(const uint8_t* const data, size_t data_size,
@@ -619,10 +683,11 @@ static VP8StatusCode GetFeatures(const uint8_t* const data, size_t data_size,
}
DefaultFeatures(features);
- // Only parse enough of the data to retrieve width/height/has_alpha.
+ // Only parse enough of the data to retrieve the features.
return ParseHeadersInternal(data, data_size,
&features->width, &features->height,
- &features->has_alpha, NULL);
+ &features->has_alpha, &features->has_animation,
+ &features->format, NULL);
}
//------------------------------------------------------------------------------
@@ -666,19 +731,13 @@ int WebPInitDecoderConfigInternal(WebPDecoderConfig* config,
VP8StatusCode WebPGetFeaturesInternal(const uint8_t* data, size_t data_size,
WebPBitstreamFeatures* features,
int version) {
- VP8StatusCode status;
if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) {
return VP8_STATUS_INVALID_PARAM; // version mismatch
}
if (features == NULL) {
return VP8_STATUS_INVALID_PARAM;
}
-
- status = GetFeatures(data, data_size, features);
- if (status == VP8_STATUS_NOT_ENOUGH_DATA) {
- return VP8_STATUS_BITSTREAM_ERROR; // Not-enough-data treated as error.
- }
- return status;
+ return GetFeatures(data, data_size, features);
}
VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
@@ -722,9 +781,9 @@ int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
h = options->crop_height;
x = options->crop_left;
y = options->crop_top;
- if (!WebPIsRGBMode(src_colorspace)) { // only snap for YUV420 or YUV422
+ if (!WebPIsRGBMode(src_colorspace)) { // only snap for YUV420
x &= ~1;
- y &= ~1; // TODO(later): only for YUV420, not YUV422.
+ y &= ~1;
}
if (x < 0 || y < 0 || w <= 0 || h <= 0 || x + w > W || y + h > H) {
return 0; // out of frame boundary error
@@ -740,11 +799,13 @@ int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
// Scaling
io->use_scaling = (options != NULL) && (options->use_scaling > 0);
if (io->use_scaling) {
- if (options->scaled_width <= 0 || options->scaled_height <= 0) {
+ int scaled_width = options->scaled_width;
+ int scaled_height = options->scaled_height;
+ if (!WebPRescalerGetScaledDimensions(w, h, &scaled_width, &scaled_height)) {
return 0;
}
- io->scaled_width = options->scaled_width;
- io->scaled_height = options->scaled_height;
+ io->scaled_width = scaled_width;
+ io->scaled_height = scaled_height;
}
// Filter
@@ -766,6 +827,3 @@ int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/dec/webpi.h b/drivers/webp/dec/webpi.h
index 44e5744411..c75a2e4a5b 100644
--- a/drivers/webp/dec/webpi.h
+++ b/drivers/webp/dec/webpi.h
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Internal header: WebP decoding parameters and custom IO on buffer
@@ -12,7 +14,7 @@
#ifndef WEBP_DEC_WEBPI_H_
#define WEBP_DEC_WEBPI_H_
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
extern "C" {
#endif
@@ -24,7 +26,10 @@ extern "C" {
typedef struct WebPDecParams WebPDecParams;
typedef int (*OutputFunc)(const VP8Io* const io, WebPDecParams* const p);
-typedef int (*OutputRowFunc)(WebPDecParams* const p, int y_pos);
+typedef int (*OutputAlphaFunc)(const VP8Io* const io, WebPDecParams* const p,
+ int expected_num_out_lines);
+typedef int (*OutputRowFunc)(WebPDecParams* const p, int y_pos,
+ int max_out_lines);
struct WebPDecParams {
WebPDecBuffer* output; // output buffer.
@@ -38,7 +43,7 @@ struct WebPDecParams {
void* memory; // overall scratch memory for the output work.
OutputFunc emit; // output RGB or YUV samples
- OutputFunc emit_alpha; // output alpha channel
+ OutputAlphaFunc emit_alpha; // output alpha channel
OutputRowFunc emit_alpha_row; // output one line of rescaled alpha values
};
@@ -52,6 +57,7 @@ void WebPResetDecParams(WebPDecParams* const params);
typedef struct {
const uint8_t* data; // input buffer
size_t data_size; // input buffer size
+ int have_all_data; // true if all data is known to be available
size_t offset; // offset to main data chunk (VP8 or VP8L)
const uint8_t* alpha_data; // points to alpha chunk (if present)
size_t alpha_data_size; // alpha chunk size
@@ -61,10 +67,10 @@ typedef struct {
} WebPHeaderStructure;
// Skips over all valid chunks prior to the first VP8/VP8L frame header.
-// Returns VP8_STATUS_OK on success,
-// VP8_STATUS_BITSTREAM_ERROR if an invalid header/chunk is found, and
-// VP8_STATUS_NOT_ENOUGH_DATA if case of insufficient data.
-// In 'headers', compressed_size, offset, alpha_data, alpha_size and lossless
+// Returns: VP8_STATUS_OK, VP8_STATUS_BITSTREAM_ERROR (invalid header/chunk),
+// VP8_STATUS_NOT_ENOUGH_DATA (partial input) or VP8_STATUS_UNSUPPORTED_FEATURE
+// in the case of non-decodable features (animation for instance).
+// In 'headers', compressed_size, offset, alpha_data, alpha_size, and lossless
// fields are updated appropriately upon success.
VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers);
@@ -91,10 +97,15 @@ int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
// dimension / etc.). If *options is not NULL, also verify that the options'
// parameters are valid and apply them to the width/height dimensions of the
// output buffer. This takes cropping / scaling / rotation into account.
+// Also incorporates the options->flip flag to flip the buffer parameters if
+// needed.
VP8StatusCode WebPAllocateDecBuffer(int width, int height,
const WebPDecoderOptions* const options,
WebPDecBuffer* const buffer);
+// Flip buffer vertically by negating the various strides.
+VP8StatusCode WebPFlipBuffer(WebPDecBuffer* const buffer);
+
// Copy 'src' into 'dst' buffer, making sure 'dst' is not marked as owner of the
// memory (still held by 'src').
void WebPCopyDecBuffer(const WebPDecBuffer* const src,
@@ -103,11 +114,9 @@ void WebPCopyDecBuffer(const WebPDecBuffer* const src,
// Copy and transfer ownership from src to dst (beware of parameter order!)
void WebPGrabDecBuffer(WebPDecBuffer* const src, WebPDecBuffer* const dst);
-
-
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/drivers/webp/decode.h b/drivers/webp/decode.h
index 43b6c58f4f..fa4b13411d 100644
--- a/drivers/webp/decode.h
+++ b/drivers/webp/decode.h
@@ -1,8 +1,10 @@
// Copyright 2010 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Main decoding functions for WebP images.
@@ -14,11 +16,23 @@
#include "./types.h"
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
extern "C" {
#endif
-#define WEBP_DECODER_ABI_VERSION 0x0200 // MAJOR(8b) + MINOR(8b)
+#define WEBP_DECODER_ABI_VERSION 0x0207 // MAJOR(8b) + MINOR(8b)
+
+// Note: forward declaring enumerations is not allowed in (strict) C and C++,
+// the types are left here for reference.
+// typedef enum VP8StatusCode VP8StatusCode;
+// typedef enum WEBP_CSP_MODE WEBP_CSP_MODE;
+typedef struct WebPRGBABuffer WebPRGBABuffer;
+typedef struct WebPYUVABuffer WebPYUVABuffer;
+typedef struct WebPDecBuffer WebPDecBuffer;
+typedef struct WebPIDecoder WebPIDecoder;
+typedef struct WebPBitstreamFeatures WebPBitstreamFeatures;
+typedef struct WebPDecoderOptions WebPDecoderOptions;
+typedef struct WebPDecoderConfig WebPDecoderConfig;
// Return the decoder's version number, packed in hexadecimal using 8bits for
// each of major/minor/revision. E.g: v2.5.7 is 0x020507.
@@ -34,7 +48,7 @@ WEBP_EXTERN(int) WebPGetInfo(const uint8_t* data, size_t data_size,
// Decodes WebP images pointed to by 'data' and returns RGBA samples, along
// with the dimensions in *width and *height. The ordering of samples in
// memory is R, G, B, A, R, G, B, A... in scan order (endian-independent).
-// The returned pointer should be deleted calling free().
+// The returned pointer should be deleted calling WebPFree().
// Returns NULL in case of error.
WEBP_EXTERN(uint8_t*) WebPDecodeRGBA(const uint8_t* data, size_t data_size,
int* width, int* height);
@@ -59,9 +73,9 @@ WEBP_EXTERN(uint8_t*) WebPDecodeBGR(const uint8_t* data, size_t data_size,
// Decode WebP images pointed to by 'data' to Y'UV format(*). The pointer
// returned is the Y samples buffer. Upon return, *u and *v will point to
-// the U and V chroma data. These U and V buffers need NOT be free()'d,
-// unlike the returned Y luma one. The dimension of the U and V planes
-// are both (*width + 1) / 2 and (*height + 1)/ 2.
+// the U and V chroma data. These U and V buffers need NOT be passed to
+// WebPFree(), unlike the returned Y luma one. The dimension of the U and V
+// planes are both (*width + 1) / 2 and (*height + 1)/ 2.
// Upon return, the Y buffer has a stride returned as '*stride', while U and V
// have a common stride returned as '*uv_stride'.
// Return NULL in case of error.
@@ -71,6 +85,9 @@ WEBP_EXTERN(uint8_t*) WebPDecodeYUV(const uint8_t* data, size_t data_size,
uint8_t** u, uint8_t** v,
int* stride, int* uv_stride);
+// Releases memory returned by the WebPDecode*() functions above.
+WEBP_EXTERN(void) WebPFree(void* ptr);
+
// These five functions are variants of the above ones, that decode the image
// directly into a pre-allocated buffer 'output_buffer'. The maximum storage
// available in this buffer is indicated by 'output_buffer_size'. If this
@@ -118,20 +135,28 @@ WEBP_EXTERN(uint8_t*) WebPDecodeYUVInto(
// Note: the naming describes the byte-ordering of packed samples in memory.
// For instance, MODE_BGRA relates to samples ordered as B,G,R,A,B,G,R,A,...
// Non-capital names (e.g.:MODE_Argb) relates to pre-multiplied RGB channels.
-// RGB-565 and RGBA-4444 are also endian-agnostic and byte-oriented.
-typedef enum { MODE_RGB = 0, MODE_RGBA = 1,
- MODE_BGR = 2, MODE_BGRA = 3,
- MODE_ARGB = 4, MODE_RGBA_4444 = 5,
- MODE_RGB_565 = 6,
- // RGB-premultiplied transparent modes (alpha value is preserved)
- MODE_rgbA = 7,
- MODE_bgrA = 8,
- MODE_Argb = 9,
- MODE_rgbA_4444 = 10,
- // YUV modes must come after RGB ones.
- MODE_YUV = 11, MODE_YUVA = 12, // yuv 4:2:0
- MODE_LAST = 13
- } WEBP_CSP_MODE;
+// RGBA-4444 and RGB-565 colorspaces are represented by following byte-order:
+// RGBA-4444: [r3 r2 r1 r0 g3 g2 g1 g0], [b3 b2 b1 b0 a3 a2 a1 a0], ...
+// RGB-565: [r4 r3 r2 r1 r0 g5 g4 g3], [g2 g1 g0 b4 b3 b2 b1 b0], ...
+// In the case WEBP_SWAP_16BITS_CSP is defined, the bytes are swapped for
+// these two modes:
+// RGBA-4444: [b3 b2 b1 b0 a3 a2 a1 a0], [r3 r2 r1 r0 g3 g2 g1 g0], ...
+// RGB-565: [g2 g1 g0 b4 b3 b2 b1 b0], [r4 r3 r2 r1 r0 g5 g4 g3], ...
+
+typedef enum WEBP_CSP_MODE {
+ MODE_RGB = 0, MODE_RGBA = 1,
+ MODE_BGR = 2, MODE_BGRA = 3,
+ MODE_ARGB = 4, MODE_RGBA_4444 = 5,
+ MODE_RGB_565 = 6,
+ // RGB-premultiplied transparent modes (alpha value is preserved)
+ MODE_rgbA = 7,
+ MODE_bgrA = 8,
+ MODE_Argb = 9,
+ MODE_rgbA_4444 = 10,
+ // YUV modes must come after RGB ones.
+ MODE_YUV = 11, MODE_YUVA = 12, // yuv 4:2:0
+ MODE_LAST = 13
+} WEBP_CSP_MODE;
// Some useful macros:
static WEBP_INLINE int WebPIsPremultipliedMode(WEBP_CSP_MODE mode) {
@@ -152,13 +177,13 @@ static WEBP_INLINE int WebPIsRGBMode(WEBP_CSP_MODE mode) {
//------------------------------------------------------------------------------
// WebPDecBuffer: Generic structure for describing the output sample buffer.
-typedef struct { // view as RGBA
+struct WebPRGBABuffer { // view as RGBA
uint8_t* rgba; // pointer to RGBA samples
int stride; // stride in bytes from one scanline to the next.
size_t size; // total size of the *rgba buffer.
-} WebPRGBABuffer;
+};
-typedef struct { // view as YUVA
+struct WebPYUVABuffer { // view as YUVA
uint8_t* y, *u, *v, *a; // pointer to luma, chroma U/V, alpha samples
int y_stride; // luma stride
int u_stride, v_stride; // chroma strides
@@ -166,10 +191,10 @@ typedef struct { // view as YUVA
size_t y_size; // luma plane size
size_t u_size, v_size; // chroma planes size
size_t a_size; // alpha-plane size
-} WebPYUVABuffer;
+};
// Output buffer
-typedef struct {
+struct WebPDecBuffer {
WEBP_CSP_MODE colorspace; // Colorspace.
int width, height; // Dimensions.
int is_external_memory; // If true, 'internal_memory' pointer is not used.
@@ -182,7 +207,7 @@ typedef struct {
uint8_t* private_memory; // Internally allocated memory (only when
// is_external_memory is false). Should not be used
// externally, but accessed via the buffer union.
-} WebPDecBuffer;
+};
// Internal, version-checked, entry point
WEBP_EXTERN(int) WebPInitDecBufferInternal(WebPDecBuffer*, int);
@@ -200,7 +225,7 @@ WEBP_EXTERN(void) WebPFreeDecBuffer(WebPDecBuffer* buffer);
//------------------------------------------------------------------------------
// Enumeration of the status codes
-typedef enum {
+typedef enum VP8StatusCode {
VP8_STATUS_OK = 0,
VP8_STATUS_OUT_OF_MEMORY,
VP8_STATUS_INVALID_PARAM,
@@ -237,13 +262,17 @@ typedef enum {
// }
// WebPIDelete(idec);
-typedef struct WebPIDecoder WebPIDecoder;
-
// Creates a new incremental decoder with the supplied buffer parameter.
// This output_buffer can be passed NULL, in which case a default output buffer
// is used (with MODE_RGB). Otherwise, an internal reference to 'output_buffer'
// is kept, which means that the lifespan of 'output_buffer' must be larger than
// that of the returned WebPIDecoder object.
+// The supplied 'output_buffer' content MUST NOT be changed between calls to
+// WebPIAppend() or WebPIUpdate() unless 'output_buffer.is_external_memory' is
+// set to 1. In such a case, it is allowed to modify the pointers, size and
+// stride of output_buffer.u.RGBA or output_buffer.u.YUVA, provided they remain
+// within valid bounds.
+// All other fields of WebPDecBuffer MUST remain constant between calls.
// Returns NULL if the allocation failed.
WEBP_EXTERN(WebPIDecoder*) WebPINewDecoder(WebPDecBuffer* output_buffer);
@@ -251,19 +280,27 @@ WEBP_EXTERN(WebPIDecoder*) WebPINewDecoder(WebPDecBuffer* output_buffer);
// will output the RGB/A samples specified by 'csp' into a preallocated
// buffer 'output_buffer'. The size of this buffer is at least
// 'output_buffer_size' and the stride (distance in bytes between two scanlines)
-// is specified by 'output_stride'. Returns NULL if the allocation failed.
+// is specified by 'output_stride'.
+// Additionally, output_buffer can be passed NULL in which case the output
+// buffer will be allocated automatically when the decoding starts. The
+// colorspace 'csp' is taken into account for allocating this buffer. All other
+// parameters are ignored.
+// Returns NULL if the allocation failed, or if some parameters are invalid.
WEBP_EXTERN(WebPIDecoder*) WebPINewRGB(
WEBP_CSP_MODE csp,
uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
// This function allocates and initializes an incremental-decoder object, which
-// will output the raw luma/chroma samples into a preallocated planes. The luma
-// plane is specified by its pointer 'luma', its size 'luma_size' and its stride
-// 'luma_stride'. Similarly, the chroma-u plane is specified by the 'u',
-// 'u_size' and 'u_stride' parameters, and the chroma-v plane by 'v'
-// and 'v_size'. And same for the alpha-plane. The 'a' pointer can be pass
-// NULL in case one is not interested in the transparency plane.
-// Returns NULL if the allocation failed.
+// will output the raw luma/chroma samples into a preallocated planes if
+// supplied. The luma plane is specified by its pointer 'luma', its size
+// 'luma_size' and its stride 'luma_stride'. Similarly, the chroma-u plane
+// is specified by the 'u', 'u_size' and 'u_stride' parameters, and the chroma-v
+// plane by 'v' and 'v_size'. And same for the alpha-plane. The 'a' pointer
+// can be pass NULL in case one is not interested in the transparency plane.
+// Conversely, 'luma' can be passed NULL if no preallocated planes are supplied.
+// In this case, the output buffer will be automatically allocated (using
+// MODE_YUVA) when decoding starts. All parameters are then ignored.
+// Returns NULL if the allocation failed or if a parameter is invalid.
WEBP_EXTERN(WebPIDecoder*) WebPINewYUVA(
uint8_t* luma, size_t luma_size, int luma_stride,
uint8_t* u, size_t u_size, int u_stride,
@@ -344,7 +381,7 @@ WEBP_EXTERN(const WebPDecBuffer*) WebPIDecodedArea(
CHECK(WebPGetFeatures(data, data_size, &config.input) == VP8_STATUS_OK);
// C) Adjust 'config', if needed
- config.no_fancy = 1;
+ config.no_fancy_upsampling = 1;
config.output.colorspace = MODE_BGRA;
// etc.
@@ -365,19 +402,15 @@ WEBP_EXTERN(const WebPDecBuffer*) WebPIDecodedArea(
*/
// Features gathered from the bitstream
-typedef struct {
- int width; // Width in pixels, as read from the bitstream.
- int height; // Height in pixels, as read from the bitstream.
- int has_alpha; // True if the bitstream contains an alpha channel.
-
- // Unused for now:
- int bitstream_version; // should be 0 for now. TODO(later)
- int no_incremental_decoding; // if true, using incremental decoding is not
- // recommended.
- int rotate; // TODO(later)
- int uv_sampling; // should be 0 for now. TODO(later)
- uint32_t pad[3]; // padding for later use
-} WebPBitstreamFeatures;
+struct WebPBitstreamFeatures {
+ int width; // Width in pixels, as read from the bitstream.
+ int height; // Height in pixels, as read from the bitstream.
+ int has_alpha; // True if the bitstream contains an alpha channel.
+ int has_animation; // True if the bitstream is an animation.
+ int format; // 0 = undefined (/mixed), 1 = lossy, 2 = lossless
+
+ uint32_t pad[5]; // padding for later use
+};
// Internal, version-checked, entry point
WEBP_EXTERN(VP8StatusCode) WebPGetFeaturesInternal(
@@ -385,8 +418,9 @@ WEBP_EXTERN(VP8StatusCode) WebPGetFeaturesInternal(
// Retrieve features from the bitstream. The *features structure is filled
// with information gathered from the bitstream.
-// Returns false in case of error or version mismatch.
-// In case of error, features->bitstream_status will reflect the error code.
+// Returns VP8_STATUS_OK when the features are successfully retrieved. Returns
+// VP8_STATUS_NOT_ENOUGH_DATA when more data is needed to retrieve the
+// features from headers. Returns error in other cases.
static WEBP_INLINE VP8StatusCode WebPGetFeatures(
const uint8_t* data, size_t data_size,
WebPBitstreamFeatures* features) {
@@ -395,7 +429,7 @@ static WEBP_INLINE VP8StatusCode WebPGetFeatures(
}
// Decoding options
-typedef struct {
+struct WebPDecoderOptions {
int bypass_filtering; // if true, skip the in-loop filtering
int no_fancy_upsampling; // if true, use faster pointwise upsampler
int use_cropping; // if true, cropping is applied _first_
@@ -405,19 +439,19 @@ typedef struct {
int use_scaling; // if true, scaling is applied _afterward_
int scaled_width, scaled_height; // final resolution
int use_threads; // if true, use multi-threaded decoding
+ int dithering_strength; // dithering strength (0=Off, 100=full)
+ int flip; // flip output vertically
+ int alpha_dithering_strength; // alpha dithering strength in [0..100]
- // Unused for now:
- int force_rotation; // forced rotation (to be applied _last_)
- int no_enhancement; // if true, discard enhancement layer
- uint32_t pad[6]; // padding for later use
-} WebPDecoderOptions;
+ uint32_t pad[5]; // padding for later use
+};
// Main object storing the configuration for advanced decoding.
-typedef struct {
+struct WebPDecoderConfig {
WebPBitstreamFeatures input; // Immutable bitstream features (optional)
WebPDecBuffer output; // Output buffer (can point to external mem)
WebPDecoderOptions options; // Decoding options
-} WebPDecoderConfig;
+};
// Internal, version-checked, entry point
WEBP_EXTERN(int) WebPInitDecoderConfigInternal(WebPDecoderConfig*, int);
@@ -447,7 +481,7 @@ WEBP_EXTERN(WebPIDecoder*) WebPIDecode(const uint8_t* data, size_t data_size,
WEBP_EXTERN(VP8StatusCode) WebPDecode(const uint8_t* data, size_t data_size,
WebPDecoderConfig* config);
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/drivers/webp/demux.h b/drivers/webp/demux.h
new file mode 100644
index 0000000000..6fbe775851
--- /dev/null
+++ b/drivers/webp/demux.h
@@ -0,0 +1,364 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Demux API.
+// Enables extraction of image and extended format data from WebP files.
+
+// Code Example: Demuxing WebP data to extract all the frames, ICC profile
+// and EXIF/XMP metadata.
+/*
+ WebPDemuxer* demux = WebPDemux(&webp_data);
+
+ uint32_t width = WebPDemuxGetI(demux, WEBP_FF_CANVAS_WIDTH);
+ uint32_t height = WebPDemuxGetI(demux, WEBP_FF_CANVAS_HEIGHT);
+ // ... (Get information about the features present in the WebP file).
+ uint32_t flags = WebPDemuxGetI(demux, WEBP_FF_FORMAT_FLAGS);
+
+ // ... (Iterate over all frames).
+ WebPIterator iter;
+ if (WebPDemuxGetFrame(demux, 1, &iter)) {
+ do {
+ // ... (Consume 'iter'; e.g. Decode 'iter.fragment' with WebPDecode(),
+ // ... and get other frame properties like width, height, offsets etc.
+ // ... see 'struct WebPIterator' below for more info).
+ } while (WebPDemuxNextFrame(&iter));
+ WebPDemuxReleaseIterator(&iter);
+ }
+
+ // ... (Extract metadata).
+ WebPChunkIterator chunk_iter;
+ if (flags & ICCP_FLAG) WebPDemuxGetChunk(demux, "ICCP", 1, &chunk_iter);
+ // ... (Consume the ICC profile in 'chunk_iter.chunk').
+ WebPDemuxReleaseChunkIterator(&chunk_iter);
+ if (flags & EXIF_FLAG) WebPDemuxGetChunk(demux, "EXIF", 1, &chunk_iter);
+ // ... (Consume the EXIF metadata in 'chunk_iter.chunk').
+ WebPDemuxReleaseChunkIterator(&chunk_iter);
+ if (flags & XMP_FLAG) WebPDemuxGetChunk(demux, "XMP ", 1, &chunk_iter);
+ // ... (Consume the XMP metadata in 'chunk_iter.chunk').
+ WebPDemuxReleaseChunkIterator(&chunk_iter);
+ WebPDemuxDelete(demux);
+*/
+
+#ifndef WEBP_WEBP_DEMUX_H_
+#define WEBP_WEBP_DEMUX_H_
+
+#include "./decode.h" // for WEBP_CSP_MODE
+#include "./mux_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define WEBP_DEMUX_ABI_VERSION 0x0105 // MAJOR(8b) + MINOR(8b)
+
+// Note: forward declaring enumerations is not allowed in (strict) C and C++,
+// the types are left here for reference.
+// typedef enum WebPDemuxState WebPDemuxState;
+// typedef enum WebPFormatFeature WebPFormatFeature;
+typedef struct WebPDemuxer WebPDemuxer;
+typedef struct WebPIterator WebPIterator;
+typedef struct WebPChunkIterator WebPChunkIterator;
+typedef struct WebPAnimInfo WebPAnimInfo;
+typedef struct WebPAnimDecoderOptions WebPAnimDecoderOptions;
+
+//------------------------------------------------------------------------------
+
+// Returns the version number of the demux library, packed in hexadecimal using
+// 8bits for each of major/minor/revision. E.g: v2.5.7 is 0x020507.
+WEBP_EXTERN(int) WebPGetDemuxVersion(void);
+
+//------------------------------------------------------------------------------
+// Life of a Demux object
+
+typedef enum WebPDemuxState {
+ WEBP_DEMUX_PARSE_ERROR = -1, // An error occurred while parsing.
+ WEBP_DEMUX_PARSING_HEADER = 0, // Not enough data to parse full header.
+ WEBP_DEMUX_PARSED_HEADER = 1, // Header parsing complete,
+ // data may be available.
+ WEBP_DEMUX_DONE = 2 // Entire file has been parsed.
+} WebPDemuxState;
+
+// Internal, version-checked, entry point
+WEBP_EXTERN(WebPDemuxer*) WebPDemuxInternal(
+ const WebPData*, int, WebPDemuxState*, int);
+
+// Parses the full WebP file given by 'data'.
+// Returns a WebPDemuxer object on successful parse, NULL otherwise.
+static WEBP_INLINE WebPDemuxer* WebPDemux(const WebPData* data) {
+ return WebPDemuxInternal(data, 0, NULL, WEBP_DEMUX_ABI_VERSION);
+}
+
+// Parses the possibly incomplete WebP file given by 'data'.
+// If 'state' is non-NULL it will be set to indicate the status of the demuxer.
+// Returns NULL in case of error or if there isn't enough data to start parsing;
+// and a WebPDemuxer object on successful parse.
+// Note that WebPDemuxer keeps internal pointers to 'data' memory segment.
+// If this data is volatile, the demuxer object should be deleted (by calling
+// WebPDemuxDelete()) and WebPDemuxPartial() called again on the new data.
+// This is usually an inexpensive operation.
+static WEBP_INLINE WebPDemuxer* WebPDemuxPartial(
+ const WebPData* data, WebPDemuxState* state) {
+ return WebPDemuxInternal(data, 1, state, WEBP_DEMUX_ABI_VERSION);
+}
+
+// Frees memory associated with 'dmux'.
+WEBP_EXTERN(void) WebPDemuxDelete(WebPDemuxer* dmux);
+
+//------------------------------------------------------------------------------
+// Data/information extraction.
+
+typedef enum WebPFormatFeature {
+ WEBP_FF_FORMAT_FLAGS, // Extended format flags present in the 'VP8X' chunk.
+ WEBP_FF_CANVAS_WIDTH,
+ WEBP_FF_CANVAS_HEIGHT,
+ WEBP_FF_LOOP_COUNT,
+ WEBP_FF_BACKGROUND_COLOR,
+ WEBP_FF_FRAME_COUNT // Number of frames present in the demux object.
+ // In case of a partial demux, this is the number of
+ // frames seen so far, with the last frame possibly
+ // being partial.
+} WebPFormatFeature;
+
+// Get the 'feature' value from the 'dmux'.
+// NOTE: values are only valid if WebPDemux() was used or WebPDemuxPartial()
+// returned a state > WEBP_DEMUX_PARSING_HEADER.
+WEBP_EXTERN(uint32_t) WebPDemuxGetI(
+ const WebPDemuxer* dmux, WebPFormatFeature feature);
+
+//------------------------------------------------------------------------------
+// Frame iteration.
+
+struct WebPIterator {
+ int frame_num;
+ int num_frames; // equivalent to WEBP_FF_FRAME_COUNT.
+ int fragment_num;
+ int num_fragments;
+ int x_offset, y_offset; // offset relative to the canvas.
+ int width, height; // dimensions of this frame or fragment.
+ int duration; // display duration in milliseconds.
+ WebPMuxAnimDispose dispose_method; // dispose method for the frame.
+ int complete; // true if 'fragment' contains a full frame. partial images
+ // may still be decoded with the WebP incremental decoder.
+ WebPData fragment; // The frame or fragment given by 'frame_num' and
+ // 'fragment_num'.
+ int has_alpha; // True if the frame or fragment contains transparency.
+ WebPMuxAnimBlend blend_method; // Blend operation for the frame.
+
+ uint32_t pad[2]; // padding for later use.
+ void* private_; // for internal use only.
+};
+
+// Retrieves frame 'frame_number' from 'dmux'.
+// 'iter->fragment' points to the first fragment on return from this function.
+// Individual fragments may be extracted using WebPDemuxSelectFragment().
+// Setting 'frame_number' equal to 0 will return the last frame of the image.
+// Returns false if 'dmux' is NULL or frame 'frame_number' is not present.
+// Call WebPDemuxReleaseIterator() when use of the iterator is complete.
+// NOTE: 'dmux' must persist for the lifetime of 'iter'.
+WEBP_EXTERN(int) WebPDemuxGetFrame(
+ const WebPDemuxer* dmux, int frame_number, WebPIterator* iter);
+
+// Sets 'iter->fragment' to point to the next ('iter->frame_num' + 1) or
+// previous ('iter->frame_num' - 1) frame. These functions do not loop.
+// Returns true on success, false otherwise.
+WEBP_EXTERN(int) WebPDemuxNextFrame(WebPIterator* iter);
+WEBP_EXTERN(int) WebPDemuxPrevFrame(WebPIterator* iter);
+
+// Sets 'iter->fragment' to reflect fragment number 'fragment_num'.
+// Returns true if fragment 'fragment_num' is present, false otherwise.
+WEBP_EXTERN(int) WebPDemuxSelectFragment(WebPIterator* iter, int fragment_num);
+
+// Releases any memory associated with 'iter'.
+// Must be called before any subsequent calls to WebPDemuxGetChunk() on the same
+// iter. Also, must be called before destroying the associated WebPDemuxer with
+// WebPDemuxDelete().
+WEBP_EXTERN(void) WebPDemuxReleaseIterator(WebPIterator* iter);
+
+//------------------------------------------------------------------------------
+// Chunk iteration.
+
+struct WebPChunkIterator {
+ // The current and total number of chunks with the fourcc given to
+ // WebPDemuxGetChunk().
+ int chunk_num;
+ int num_chunks;
+ WebPData chunk; // The payload of the chunk.
+
+ uint32_t pad[6]; // padding for later use
+ void* private_;
+};
+
+// Retrieves the 'chunk_number' instance of the chunk with id 'fourcc' from
+// 'dmux'.
+// 'fourcc' is a character array containing the fourcc of the chunk to return,
+// e.g., "ICCP", "XMP ", "EXIF", etc.
+// Setting 'chunk_number' equal to 0 will return the last chunk in a set.
+// Returns true if the chunk is found, false otherwise. Image related chunk
+// payloads are accessed through WebPDemuxGetFrame() and related functions.
+// Call WebPDemuxReleaseChunkIterator() when use of the iterator is complete.
+// NOTE: 'dmux' must persist for the lifetime of the iterator.
+WEBP_EXTERN(int) WebPDemuxGetChunk(const WebPDemuxer* dmux,
+ const char fourcc[4], int chunk_number,
+ WebPChunkIterator* iter);
+
+// Sets 'iter->chunk' to point to the next ('iter->chunk_num' + 1) or previous
+// ('iter->chunk_num' - 1) chunk. These functions do not loop.
+// Returns true on success, false otherwise.
+WEBP_EXTERN(int) WebPDemuxNextChunk(WebPChunkIterator* iter);
+WEBP_EXTERN(int) WebPDemuxPrevChunk(WebPChunkIterator* iter);
+
+// Releases any memory associated with 'iter'.
+// Must be called before destroying the associated WebPDemuxer with
+// WebPDemuxDelete().
+WEBP_EXTERN(void) WebPDemuxReleaseChunkIterator(WebPChunkIterator* iter);
+
+//------------------------------------------------------------------------------
+// WebPAnimDecoder API
+//
+// This API allows decoding (possibly) animated WebP images.
+//
+// Code Example:
+/*
+ WebPAnimDecoderOptions dec_options;
+ WebPAnimDecoderOptionsInit(&dec_options);
+ // Tune 'dec_options' as needed.
+ WebPAnimDecoder* dec = WebPAnimDecoderNew(webp_data, &dec_options);
+ WebPAnimInfo anim_info;
+ WebPAnimDecoderGetInfo(dec, &anim_info);
+ for (uint32_t i = 0; i < anim_info.loop_count; ++i) {
+ while (WebPAnimDecoderHasMoreFrames(dec)) {
+ uint8_t* buf;
+ int timestamp;
+ WebPAnimDecoderGetNext(dec, &buf, &timestamp);
+ // ... (Render 'buf' based on 'timestamp').
+ // ... (Do NOT free 'buf', as it is owned by 'dec').
+ }
+ WebPAnimDecoderReset(dec);
+ }
+ const WebPDemuxer* demuxer = WebPAnimDecoderGetDemuxer(dec);
+ // ... (Do something using 'demuxer'; e.g. get EXIF/XMP/ICC data).
+ WebPAnimDecoderDelete(dec);
+*/
+
+typedef struct WebPAnimDecoder WebPAnimDecoder; // Main opaque object.
+
+// Global options.
+struct WebPAnimDecoderOptions {
+ // Output colorspace. Only the following modes are supported:
+ // MODE_RGBA, MODE_BGRA, MODE_rgbA and MODE_bgrA.
+ WEBP_CSP_MODE color_mode;
+ int use_threads; // If true, use multi-threaded decoding.
+ uint32_t padding[7]; // Padding for later use.
+};
+
+// Internal, version-checked, entry point.
+WEBP_EXTERN(int) WebPAnimDecoderOptionsInitInternal(
+ WebPAnimDecoderOptions*, int);
+
+// Should always be called, to initialize a fresh WebPAnimDecoderOptions
+// structure before modification. Returns false in case of version mismatch.
+// WebPAnimDecoderOptionsInit() must have succeeded before using the
+// 'dec_options' object.
+static WEBP_INLINE int WebPAnimDecoderOptionsInit(
+ WebPAnimDecoderOptions* dec_options) {
+ return WebPAnimDecoderOptionsInitInternal(dec_options,
+ WEBP_DEMUX_ABI_VERSION);
+}
+
+// Internal, version-checked, entry point.
+WEBP_EXTERN(WebPAnimDecoder*) WebPAnimDecoderNewInternal(
+ const WebPData*, const WebPAnimDecoderOptions*, int);
+
+// Creates and initializes a WebPAnimDecoder object.
+// Parameters:
+// webp_data - (in) WebP bitstream. This should remain unchanged during the
+// lifetime of the output WebPAnimDecoder object.
+// dec_options - (in) decoding options. Can be passed NULL to choose
+// reasonable defaults (in particular, color mode MODE_RGBA
+// will be picked).
+// Returns:
+// A pointer to the newly created WebPAnimDecoder object, or NULL in case of
+// parsing error, invalid option or memory error.
+static WEBP_INLINE WebPAnimDecoder* WebPAnimDecoderNew(
+ const WebPData* webp_data, const WebPAnimDecoderOptions* dec_options) {
+ return WebPAnimDecoderNewInternal(webp_data, dec_options,
+ WEBP_DEMUX_ABI_VERSION);
+}
+
+// Global information about the animation..
+struct WebPAnimInfo {
+ uint32_t canvas_width;
+ uint32_t canvas_height;
+ uint32_t loop_count;
+ uint32_t bgcolor;
+ uint32_t frame_count;
+ uint32_t pad[4]; // padding for later use
+};
+
+// Get global information about the animation.
+// Parameters:
+// dec - (in) decoder instance to get information from.
+// info - (out) global information fetched from the animation.
+// Returns:
+// True on success.
+WEBP_EXTERN(int) WebPAnimDecoderGetInfo(const WebPAnimDecoder* dec,
+ WebPAnimInfo* info);
+
+// Fetch the next frame from 'dec' based on options supplied to
+// WebPAnimDecoderNew(). This will be a fully reconstructed canvas of size
+// 'canvas_width * 4 * canvas_height', and not just the frame sub-rectangle. The
+// returned buffer 'buf' is valid only until the next call to
+// WebPAnimDecoderGetNext(), WebPAnimDecoderReset() or WebPAnimDecoderDelete().
+// Parameters:
+// dec - (in/out) decoder instance from which the next frame is to be fetched.
+// buf - (out) decoded frame.
+// timestamp - (out) timestamp of the frame in milliseconds.
+// Returns:
+// False if any of the arguments are NULL, or if there is a parsing or
+// decoding error, or if there are no more frames. Otherwise, returns true.
+WEBP_EXTERN(int) WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
+ uint8_t** buf, int* timestamp);
+
+// Check if there are more frames left to decode.
+// Parameters:
+// dec - (in) decoder instance to be checked.
+// Returns:
+// True if 'dec' is not NULL and some frames are yet to be decoded.
+// Otherwise, returns false.
+WEBP_EXTERN(int) WebPAnimDecoderHasMoreFrames(const WebPAnimDecoder* dec);
+
+// Resets the WebPAnimDecoder object, so that next call to
+// WebPAnimDecoderGetNext() will restart decoding from 1st frame. This would be
+// helpful when all frames need to be decoded multiple times (e.g.
+// info.loop_count times) without destroying and recreating the 'dec' object.
+// Parameters:
+// dec - (in/out) decoder instance to be reset
+WEBP_EXTERN(void) WebPAnimDecoderReset(WebPAnimDecoder* dec);
+
+// Grab the internal demuxer object.
+// Getting the demuxer object can be useful if one wants to use operations only
+// available through demuxer; e.g. to get XMP/EXIF/ICC metadata. The returned
+// demuxer object is owned by 'dec' and is valid only until the next call to
+// WebPAnimDecoderDelete().
+//
+// Parameters:
+// dec - (in) decoder instance from which the demuxer object is to be fetched.
+WEBP_EXTERN(const WebPDemuxer*) WebPAnimDecoderGetDemuxer(
+ const WebPAnimDecoder* dec);
+
+// Deletes the WebPAnimDecoder object.
+// Parameters:
+// dec - (in/out) decoder instance to be deleted
+WEBP_EXTERN(void) WebPAnimDecoderDelete(WebPAnimDecoder* dec);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* WEBP_WEBP_DEMUX_H_ */
diff --git a/drivers/webp/demux/anim_decode.c b/drivers/webp/demux/anim_decode.c
new file mode 100644
index 0000000000..c81cedfba0
--- /dev/null
+++ b/drivers/webp/demux/anim_decode.c
@@ -0,0 +1,442 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// AnimDecoder implementation.
+//
+
+#ifdef HAVE_CONFIG_H
+#include "webp/config.h"
+#endif
+
+#include <assert.h>
+#include <string.h>
+
+#include "../utils/utils.h"
+#include "webp/decode.h"
+#include "webp/demux.h"
+
+#define NUM_CHANNELS 4
+
+typedef void (*BlendRowFunc)(uint32_t* const, const uint32_t* const, int);
+static void BlendPixelRowNonPremult(uint32_t* const src,
+ const uint32_t* const dst, int num_pixels);
+static void BlendPixelRowPremult(uint32_t* const src, const uint32_t* const dst,
+ int num_pixels);
+
+struct WebPAnimDecoder {
+ WebPDemuxer* demux_; // Demuxer created from given WebP bitstream.
+ WebPDecoderConfig config_; // Decoder config.
+ // Note: we use a pointer to a function blending multiple pixels at a time to
+ // allow possible inlining of per-pixel blending function.
+ BlendRowFunc blend_func_; // Pointer to the chose blend row function.
+ WebPAnimInfo info_; // Global info about the animation.
+ uint8_t* curr_frame_; // Current canvas (not disposed).
+ uint8_t* prev_frame_disposed_; // Previous canvas (properly disposed).
+ int prev_frame_timestamp_; // Previous frame timestamp (milliseconds).
+ WebPIterator prev_iter_; // Iterator object for previous frame.
+ int prev_frame_was_keyframe_; // True if previous frame was a keyframe.
+ int next_frame_; // Index of the next frame to be decoded
+ // (starting from 1).
+};
+
+static void DefaultDecoderOptions(WebPAnimDecoderOptions* const dec_options) {
+ dec_options->color_mode = MODE_RGBA;
+ dec_options->use_threads = 0;
+}
+
+int WebPAnimDecoderOptionsInitInternal(WebPAnimDecoderOptions* dec_options,
+ int abi_version) {
+ if (dec_options == NULL ||
+ WEBP_ABI_IS_INCOMPATIBLE(abi_version, WEBP_DEMUX_ABI_VERSION)) {
+ return 0;
+ }
+ DefaultDecoderOptions(dec_options);
+ return 1;
+}
+
+static int ApplyDecoderOptions(const WebPAnimDecoderOptions* const dec_options,
+ WebPAnimDecoder* const dec) {
+ WEBP_CSP_MODE mode;
+ WebPDecoderConfig* config = &dec->config_;
+ assert(dec_options != NULL);
+
+ mode = dec_options->color_mode;
+ if (mode != MODE_RGBA && mode != MODE_BGRA &&
+ mode != MODE_rgbA && mode != MODE_bgrA) {
+ return 0;
+ }
+ dec->blend_func_ = (mode == MODE_RGBA || mode == MODE_BGRA)
+ ? &BlendPixelRowNonPremult
+ : &BlendPixelRowPremult;
+ WebPInitDecoderConfig(config);
+ config->output.colorspace = mode;
+ config->output.is_external_memory = 1;
+ config->options.use_threads = dec_options->use_threads;
+ // Note: config->output.u.RGBA is set at the time of decoding each frame.
+ return 1;
+}
+
+WebPAnimDecoder* WebPAnimDecoderNewInternal(
+ const WebPData* webp_data, const WebPAnimDecoderOptions* dec_options,
+ int abi_version) {
+ WebPAnimDecoderOptions options;
+ WebPAnimDecoder* dec = NULL;
+ if (webp_data == NULL ||
+ WEBP_ABI_IS_INCOMPATIBLE(abi_version, WEBP_DEMUX_ABI_VERSION)) {
+ return NULL;
+ }
+
+ // Note: calloc() so that the pointer members are initialized to NULL.
+ dec = (WebPAnimDecoder*)WebPSafeCalloc(1ULL, sizeof(*dec));
+ if (dec == NULL) goto Error;
+
+ if (dec_options != NULL) {
+ options = *dec_options;
+ } else {
+ DefaultDecoderOptions(&options);
+ }
+ if (!ApplyDecoderOptions(&options, dec)) goto Error;
+
+ dec->demux_ = WebPDemux(webp_data);
+ if (dec->demux_ == NULL) goto Error;
+
+ dec->info_.canvas_width = WebPDemuxGetI(dec->demux_, WEBP_FF_CANVAS_WIDTH);
+ dec->info_.canvas_height = WebPDemuxGetI(dec->demux_, WEBP_FF_CANVAS_HEIGHT);
+ dec->info_.loop_count = WebPDemuxGetI(dec->demux_, WEBP_FF_LOOP_COUNT);
+ dec->info_.bgcolor = WebPDemuxGetI(dec->demux_, WEBP_FF_BACKGROUND_COLOR);
+ dec->info_.frame_count = WebPDemuxGetI(dec->demux_, WEBP_FF_FRAME_COUNT);
+
+ {
+ const int canvas_bytes =
+ dec->info_.canvas_width * NUM_CHANNELS * dec->info_.canvas_height;
+ // Note: calloc() because we fill frame with zeroes as well.
+ dec->curr_frame_ = WebPSafeCalloc(1ULL, canvas_bytes);
+ if (dec->curr_frame_ == NULL) goto Error;
+ dec->prev_frame_disposed_ = WebPSafeCalloc(1ULL, canvas_bytes);
+ if (dec->prev_frame_disposed_ == NULL) goto Error;
+ }
+
+ WebPAnimDecoderReset(dec);
+
+ return dec;
+
+ Error:
+ WebPAnimDecoderDelete(dec);
+ return NULL;
+}
+
+int WebPAnimDecoderGetInfo(const WebPAnimDecoder* dec, WebPAnimInfo* info) {
+ if (dec == NULL || info == NULL) return 0;
+ *info = dec->info_;
+ return 1;
+}
+
+// Returns true if the frame covers the full canvas.
+static int IsFullFrame(int width, int height, int canvas_width,
+ int canvas_height) {
+ return (width == canvas_width && height == canvas_height);
+}
+
+// Clear the canvas to transparent.
+static void ZeroFillCanvas(uint8_t* buf, uint32_t canvas_width,
+ uint32_t canvas_height) {
+ memset(buf, 0, canvas_width * NUM_CHANNELS * canvas_height);
+}
+
+// Clear given frame rectangle to transparent.
+static void ZeroFillFrameRect(uint8_t* buf, int buf_stride, int x_offset,
+ int y_offset, int width, int height) {
+ int j;
+ assert(width * NUM_CHANNELS <= buf_stride);
+ buf += y_offset * buf_stride + x_offset * NUM_CHANNELS;
+ for (j = 0; j < height; ++j) {
+ memset(buf, 0, width * NUM_CHANNELS);
+ buf += buf_stride;
+ }
+}
+
+// Copy width * height pixels from 'src' to 'dst'.
+static void CopyCanvas(const uint8_t* src, uint8_t* dst,
+ uint32_t width, uint32_t height) {
+ assert(src != NULL && dst != NULL);
+ memcpy(dst, src, width * NUM_CHANNELS * height);
+}
+
+// Returns true if the current frame is a key-frame.
+static int IsKeyFrame(const WebPIterator* const curr,
+ const WebPIterator* const prev,
+ int prev_frame_was_key_frame,
+ int canvas_width, int canvas_height) {
+ if (curr->frame_num == 1) {
+ return 1;
+ } else if ((!curr->has_alpha || curr->blend_method == WEBP_MUX_NO_BLEND) &&
+ IsFullFrame(curr->width, curr->height,
+ canvas_width, canvas_height)) {
+ return 1;
+ } else {
+ return (prev->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) &&
+ (IsFullFrame(prev->width, prev->height, canvas_width,
+ canvas_height) ||
+ prev_frame_was_key_frame);
+ }
+}
+
+
+// Blend a single channel of 'src' over 'dst', given their alpha channel values.
+// 'src' and 'dst' are assumed to be NOT pre-multiplied by alpha.
+static uint8_t BlendChannelNonPremult(uint32_t src, uint8_t src_a,
+ uint32_t dst, uint8_t dst_a,
+ uint32_t scale, int shift) {
+ const uint8_t src_channel = (src >> shift) & 0xff;
+ const uint8_t dst_channel = (dst >> shift) & 0xff;
+ const uint32_t blend_unscaled = src_channel * src_a + dst_channel * dst_a;
+ assert(blend_unscaled < (1ULL << 32) / scale);
+ return (blend_unscaled * scale) >> 24;
+}
+
+// Blend 'src' over 'dst' assuming they are NOT pre-multiplied by alpha.
+static uint32_t BlendPixelNonPremult(uint32_t src, uint32_t dst) {
+ const uint8_t src_a = (src >> 24) & 0xff;
+
+ if (src_a == 0) {
+ return dst;
+ } else {
+ const uint8_t dst_a = (dst >> 24) & 0xff;
+ // This is the approximate integer arithmetic for the actual formula:
+ // dst_factor_a = (dst_a * (255 - src_a)) / 255.
+ const uint8_t dst_factor_a = (dst_a * (256 - src_a)) >> 8;
+ const uint8_t blend_a = src_a + dst_factor_a;
+ const uint32_t scale = (1UL << 24) / blend_a;
+
+ const uint8_t blend_r =
+ BlendChannelNonPremult(src, src_a, dst, dst_factor_a, scale, 0);
+ const uint8_t blend_g =
+ BlendChannelNonPremult(src, src_a, dst, dst_factor_a, scale, 8);
+ const uint8_t blend_b =
+ BlendChannelNonPremult(src, src_a, dst, dst_factor_a, scale, 16);
+ assert(src_a + dst_factor_a < 256);
+
+ return (blend_r << 0) |
+ (blend_g << 8) |
+ (blend_b << 16) |
+ ((uint32_t)blend_a << 24);
+ }
+}
+
+// Blend 'num_pixels' in 'src' over 'dst' assuming they are NOT pre-multiplied
+// by alpha.
+static void BlendPixelRowNonPremult(uint32_t* const src,
+ const uint32_t* const dst, int num_pixels) {
+ int i;
+ for (i = 0; i < num_pixels; ++i) {
+ const uint8_t src_alpha = (src[i] >> 24) & 0xff;
+ if (src_alpha != 0xff) {
+ src[i] = BlendPixelNonPremult(src[i], dst[i]);
+ }
+ }
+}
+
+// Individually multiply each channel in 'pix' by 'scale'.
+static WEBP_INLINE uint32_t ChannelwiseMultiply(uint32_t pix, uint32_t scale) {
+ uint32_t mask = 0x00FF00FF;
+ uint32_t rb = ((pix & mask) * scale) >> 8;
+ uint32_t ag = ((pix >> 8) & mask) * scale;
+ return (rb & mask) | (ag & ~mask);
+}
+
+// Blend 'src' over 'dst' assuming they are pre-multiplied by alpha.
+static uint32_t BlendPixelPremult(uint32_t src, uint32_t dst) {
+ const uint8_t src_a = (src >> 24) & 0xff;
+ return src + ChannelwiseMultiply(dst, 256 - src_a);
+}
+
+// Blend 'num_pixels' in 'src' over 'dst' assuming they are pre-multiplied by
+// alpha.
+static void BlendPixelRowPremult(uint32_t* const src, const uint32_t* const dst,
+ int num_pixels) {
+ int i;
+ for (i = 0; i < num_pixels; ++i) {
+ const uint8_t src_alpha = (src[i] >> 24) & 0xff;
+ if (src_alpha != 0xff) {
+ src[i] = BlendPixelPremult(src[i], dst[i]);
+ }
+ }
+}
+
+// Returns two ranges (<left, width> pairs) at row 'canvas_y', that belong to
+// 'src' but not 'dst'. A point range is empty if the corresponding width is 0.
+static void FindBlendRangeAtRow(const WebPIterator* const src,
+ const WebPIterator* const dst, int canvas_y,
+ int* const left1, int* const width1,
+ int* const left2, int* const width2) {
+ const int src_max_x = src->x_offset + src->width;
+ const int dst_max_x = dst->x_offset + dst->width;
+ const int dst_max_y = dst->y_offset + dst->height;
+ assert(canvas_y >= src->y_offset && canvas_y < (src->y_offset + src->height));
+ *left1 = -1;
+ *width1 = 0;
+ *left2 = -1;
+ *width2 = 0;
+
+ if (canvas_y < dst->y_offset || canvas_y >= dst_max_y ||
+ src->x_offset >= dst_max_x || src_max_x <= dst->x_offset) {
+ *left1 = src->x_offset;
+ *width1 = src->width;
+ return;
+ }
+
+ if (src->x_offset < dst->x_offset) {
+ *left1 = src->x_offset;
+ *width1 = dst->x_offset - src->x_offset;
+ }
+
+ if (src_max_x > dst_max_x) {
+ *left2 = dst_max_x;
+ *width2 = src_max_x - dst_max_x;
+ }
+}
+
+int WebPAnimDecoderGetNext(WebPAnimDecoder* dec,
+ uint8_t** buf_ptr, int* timestamp_ptr) {
+ WebPIterator iter;
+ uint32_t width;
+ uint32_t height;
+ int is_key_frame;
+ int timestamp;
+ BlendRowFunc blend_row;
+
+ if (dec == NULL || buf_ptr == NULL || timestamp_ptr == NULL) return 0;
+ if (!WebPAnimDecoderHasMoreFrames(dec)) return 0;
+
+ width = dec->info_.canvas_width;
+ height = dec->info_.canvas_height;
+ blend_row = dec->blend_func_;
+
+ // Get compressed frame.
+ if (!WebPDemuxGetFrame(dec->demux_, dec->next_frame_, &iter)) {
+ return 0;
+ }
+ timestamp = dec->prev_frame_timestamp_ + iter.duration;
+
+ // Initialize.
+ is_key_frame = IsKeyFrame(&iter, &dec->prev_iter_,
+ dec->prev_frame_was_keyframe_, width, height);
+ if (is_key_frame) {
+ ZeroFillCanvas(dec->curr_frame_, width, height);
+ } else {
+ CopyCanvas(dec->prev_frame_disposed_, dec->curr_frame_, width, height);
+ }
+
+ // Decode.
+ {
+ const uint8_t* in = iter.fragment.bytes;
+ const size_t in_size = iter.fragment.size;
+ const size_t out_offset =
+ (iter.y_offset * width + iter.x_offset) * NUM_CHANNELS;
+ WebPDecoderConfig* const config = &dec->config_;
+ WebPRGBABuffer* const buf = &config->output.u.RGBA;
+ buf->stride = NUM_CHANNELS * width;
+ buf->size = buf->stride * iter.height;
+ buf->rgba = dec->curr_frame_ + out_offset;
+
+ if (WebPDecode(in, in_size, config) != VP8_STATUS_OK) {
+ goto Error;
+ }
+ }
+
+ // During the decoding of current frame, we may have set some pixels to be
+ // transparent (i.e. alpha < 255). However, the value of each of these
+ // pixels should have been determined by blending it against the value of
+ // that pixel in the previous frame if blending method of is WEBP_MUX_BLEND.
+ if (iter.frame_num > 1 && iter.blend_method == WEBP_MUX_BLEND &&
+ !is_key_frame) {
+ if (dec->prev_iter_.dispose_method == WEBP_MUX_DISPOSE_NONE) {
+ int y;
+ // Blend transparent pixels with pixels in previous canvas.
+ for (y = 0; y < iter.height; ++y) {
+ const size_t offset =
+ (iter.y_offset + y) * width + iter.x_offset;
+ blend_row((uint32_t*)dec->curr_frame_ + offset,
+ (uint32_t*)dec->prev_frame_disposed_ + offset, iter.width);
+ }
+ } else {
+ int y;
+ assert(dec->prev_iter_.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND);
+ // We need to blend a transparent pixel with its value just after
+ // initialization. That is, blend it with:
+ // * Fully transparent pixel if it belongs to prevRect <-- No-op.
+ // * The pixel in the previous canvas otherwise <-- Need alpha-blending.
+ for (y = 0; y < iter.height; ++y) {
+ const int canvas_y = iter.y_offset + y;
+ int left1, width1, left2, width2;
+ FindBlendRangeAtRow(&iter, &dec->prev_iter_, canvas_y, &left1, &width1,
+ &left2, &width2);
+ if (width1 > 0) {
+ const size_t offset1 = canvas_y * width + left1;
+ blend_row((uint32_t*)dec->curr_frame_ + offset1,
+ (uint32_t*)dec->prev_frame_disposed_ + offset1, width1);
+ }
+ if (width2 > 0) {
+ const size_t offset2 = canvas_y * width + left2;
+ blend_row((uint32_t*)dec->curr_frame_ + offset2,
+ (uint32_t*)dec->prev_frame_disposed_ + offset2, width2);
+ }
+ }
+ }
+ }
+
+ // Update info of the previous frame and dispose it for the next iteration.
+ dec->prev_frame_timestamp_ = timestamp;
+ dec->prev_iter_ = iter;
+ dec->prev_frame_was_keyframe_ = is_key_frame;
+ CopyCanvas(dec->curr_frame_, dec->prev_frame_disposed_, width, height);
+ if (dec->prev_iter_.dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
+ ZeroFillFrameRect(dec->prev_frame_disposed_, width * NUM_CHANNELS,
+ dec->prev_iter_.x_offset, dec->prev_iter_.y_offset,
+ dec->prev_iter_.width, dec->prev_iter_.height);
+ }
+ ++dec->next_frame_;
+
+ // All OK, fill in the values.
+ *buf_ptr = dec->curr_frame_;
+ *timestamp_ptr = timestamp;
+ return 1;
+
+ Error:
+ WebPDemuxReleaseIterator(&iter);
+ return 0;
+}
+
+int WebPAnimDecoderHasMoreFrames(const WebPAnimDecoder* dec) {
+ if (dec == NULL) return 0;
+ return (dec->next_frame_ <= (int)dec->info_.frame_count);
+}
+
+void WebPAnimDecoderReset(WebPAnimDecoder* dec) {
+ if (dec != NULL) {
+ dec->prev_frame_timestamp_ = 0;
+ memset(&dec->prev_iter_, 0, sizeof(dec->prev_iter_));
+ dec->prev_frame_was_keyframe_ = 0;
+ dec->next_frame_ = 1;
+ }
+}
+
+const WebPDemuxer* WebPAnimDecoderGetDemuxer(const WebPAnimDecoder* dec) {
+ if (dec == NULL) return NULL;
+ return dec->demux_;
+}
+
+void WebPAnimDecoderDelete(WebPAnimDecoder* dec) {
+ if (dec != NULL) {
+ WebPDemuxDelete(dec->demux_);
+ WebPSafeFree(dec->curr_frame_);
+ WebPSafeFree(dec->prev_frame_disposed_);
+ WebPSafeFree(dec);
+ }
+}
diff --git a/drivers/webp/demux/demux.c b/drivers/webp/demux/demux.c
new file mode 100644
index 0000000000..3717e21165
--- /dev/null
+++ b/drivers/webp/demux/demux.c
@@ -0,0 +1,957 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// WebP container demux.
+//
+
+#ifdef HAVE_CONFIG_H
+#include "webp/config.h"
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../utils/utils.h"
+#include "webp/decode.h" // WebPGetFeatures
+#include "webp/demux.h"
+#include "webp/format_constants.h"
+
+#define DMUX_MAJ_VERSION 0
+#define DMUX_MIN_VERSION 2
+#define DMUX_REV_VERSION 2
+
+typedef struct {
+ size_t start_; // start location of the data
+ size_t end_; // end location
+ size_t riff_end_; // riff chunk end location, can be > end_.
+ size_t buf_size_; // size of the buffer
+ const uint8_t* buf_;
+} MemBuffer;
+
+typedef struct {
+ size_t offset_;
+ size_t size_;
+} ChunkData;
+
+typedef struct Frame {
+ int x_offset_, y_offset_;
+ int width_, height_;
+ int has_alpha_;
+ int duration_;
+ WebPMuxAnimDispose dispose_method_;
+ WebPMuxAnimBlend blend_method_;
+ int is_fragment_; // this is a frame fragment (and not a full frame).
+ int frame_num_; // the referent frame number for use in assembling fragments.
+ int complete_; // img_components_ contains a full image.
+ ChunkData img_components_[2]; // 0=VP8{,L} 1=ALPH
+ struct Frame* next_;
+} Frame;
+
+typedef struct Chunk {
+ ChunkData data_;
+ struct Chunk* next_;
+} Chunk;
+
+struct WebPDemuxer {
+ MemBuffer mem_;
+ WebPDemuxState state_;
+ int is_ext_format_;
+ uint32_t feature_flags_;
+ int canvas_width_, canvas_height_;
+ int loop_count_;
+ uint32_t bgcolor_;
+ int num_frames_;
+ Frame* frames_;
+ Frame** frames_tail_;
+ Chunk* chunks_; // non-image chunks
+ Chunk** chunks_tail_;
+};
+
+typedef enum {
+ PARSE_OK,
+ PARSE_NEED_MORE_DATA,
+ PARSE_ERROR
+} ParseStatus;
+
+typedef struct ChunkParser {
+ uint8_t id[4];
+ ParseStatus (*parse)(WebPDemuxer* const dmux);
+ int (*valid)(const WebPDemuxer* const dmux);
+} ChunkParser;
+
+static ParseStatus ParseSingleImage(WebPDemuxer* const dmux);
+static ParseStatus ParseVP8X(WebPDemuxer* const dmux);
+static int IsValidSimpleFormat(const WebPDemuxer* const dmux);
+static int IsValidExtendedFormat(const WebPDemuxer* const dmux);
+
+static const ChunkParser kMasterChunks[] = {
+ { { 'V', 'P', '8', ' ' }, ParseSingleImage, IsValidSimpleFormat },
+ { { 'V', 'P', '8', 'L' }, ParseSingleImage, IsValidSimpleFormat },
+ { { 'V', 'P', '8', 'X' }, ParseVP8X, IsValidExtendedFormat },
+ { { '0', '0', '0', '0' }, NULL, NULL },
+};
+
+//------------------------------------------------------------------------------
+
+int WebPGetDemuxVersion(void) {
+ return (DMUX_MAJ_VERSION << 16) | (DMUX_MIN_VERSION << 8) | DMUX_REV_VERSION;
+}
+
+// -----------------------------------------------------------------------------
+// MemBuffer
+
+static int RemapMemBuffer(MemBuffer* const mem,
+ const uint8_t* data, size_t size) {
+ if (size < mem->buf_size_) return 0; // can't remap to a shorter buffer!
+
+ mem->buf_ = data;
+ mem->end_ = mem->buf_size_ = size;
+ return 1;
+}
+
+static int InitMemBuffer(MemBuffer* const mem,
+ const uint8_t* data, size_t size) {
+ memset(mem, 0, sizeof(*mem));
+ return RemapMemBuffer(mem, data, size);
+}
+
+// Return the remaining data size available in 'mem'.
+static WEBP_INLINE size_t MemDataSize(const MemBuffer* const mem) {
+ return (mem->end_ - mem->start_);
+}
+
+// Return true if 'size' exceeds the end of the RIFF chunk.
+static WEBP_INLINE int SizeIsInvalid(const MemBuffer* const mem, size_t size) {
+ return (size > mem->riff_end_ - mem->start_);
+}
+
+static WEBP_INLINE void Skip(MemBuffer* const mem, size_t size) {
+ mem->start_ += size;
+}
+
+static WEBP_INLINE void Rewind(MemBuffer* const mem, size_t size) {
+ mem->start_ -= size;
+}
+
+static WEBP_INLINE const uint8_t* GetBuffer(MemBuffer* const mem) {
+ return mem->buf_ + mem->start_;
+}
+
+// Read from 'mem' and skip the read bytes.
+static WEBP_INLINE uint8_t ReadByte(MemBuffer* const mem) {
+ const uint8_t byte = mem->buf_[mem->start_];
+ Skip(mem, 1);
+ return byte;
+}
+
+static WEBP_INLINE int ReadLE16s(MemBuffer* const mem) {
+ const uint8_t* const data = mem->buf_ + mem->start_;
+ const int val = GetLE16(data);
+ Skip(mem, 2);
+ return val;
+}
+
+static WEBP_INLINE int ReadLE24s(MemBuffer* const mem) {
+ const uint8_t* const data = mem->buf_ + mem->start_;
+ const int val = GetLE24(data);
+ Skip(mem, 3);
+ return val;
+}
+
+static WEBP_INLINE uint32_t ReadLE32(MemBuffer* const mem) {
+ const uint8_t* const data = mem->buf_ + mem->start_;
+ const uint32_t val = GetLE32(data);
+ Skip(mem, 4);
+ return val;
+}
+
+// -----------------------------------------------------------------------------
+// Secondary chunk parsing
+
+static void AddChunk(WebPDemuxer* const dmux, Chunk* const chunk) {
+ *dmux->chunks_tail_ = chunk;
+ chunk->next_ = NULL;
+ dmux->chunks_tail_ = &chunk->next_;
+}
+
+// Add a frame to the end of the list, ensuring the last frame is complete.
+// Returns true on success, false otherwise.
+static int AddFrame(WebPDemuxer* const dmux, Frame* const frame) {
+ const Frame* const last_frame = *dmux->frames_tail_;
+ if (last_frame != NULL && !last_frame->complete_) return 0;
+
+ *dmux->frames_tail_ = frame;
+ frame->next_ = NULL;
+ dmux->frames_tail_ = &frame->next_;
+ return 1;
+}
+
+// Store image bearing chunks to 'frame'.
+static ParseStatus StoreFrame(int frame_num, uint32_t min_size,
+ MemBuffer* const mem, Frame* const frame) {
+ int alpha_chunks = 0;
+ int image_chunks = 0;
+ int done = (MemDataSize(mem) < min_size);
+ ParseStatus status = PARSE_OK;
+
+ if (done) return PARSE_NEED_MORE_DATA;
+
+ do {
+ const size_t chunk_start_offset = mem->start_;
+ const uint32_t fourcc = ReadLE32(mem);
+ const uint32_t payload_size = ReadLE32(mem);
+ const uint32_t payload_size_padded = payload_size + (payload_size & 1);
+ const size_t payload_available = (payload_size_padded > MemDataSize(mem))
+ ? MemDataSize(mem) : payload_size_padded;
+ const size_t chunk_size = CHUNK_HEADER_SIZE + payload_available;
+
+ if (payload_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR;
+ if (SizeIsInvalid(mem, payload_size_padded)) return PARSE_ERROR;
+ if (payload_size_padded > MemDataSize(mem)) status = PARSE_NEED_MORE_DATA;
+
+ switch (fourcc) {
+ case MKFOURCC('A', 'L', 'P', 'H'):
+ if (alpha_chunks == 0) {
+ ++alpha_chunks;
+ frame->img_components_[1].offset_ = chunk_start_offset;
+ frame->img_components_[1].size_ = chunk_size;
+ frame->has_alpha_ = 1;
+ frame->frame_num_ = frame_num;
+ Skip(mem, payload_available);
+ } else {
+ goto Done;
+ }
+ break;
+ case MKFOURCC('V', 'P', '8', 'L'):
+ if (alpha_chunks > 0) return PARSE_ERROR; // VP8L has its own alpha
+ // fall through
+ case MKFOURCC('V', 'P', '8', ' '):
+ if (image_chunks == 0) {
+ // Extract the bitstream features, tolerating failures when the data
+ // is incomplete.
+ WebPBitstreamFeatures features;
+ const VP8StatusCode vp8_status =
+ WebPGetFeatures(mem->buf_ + chunk_start_offset, chunk_size,
+ &features);
+ if (status == PARSE_NEED_MORE_DATA &&
+ vp8_status == VP8_STATUS_NOT_ENOUGH_DATA) {
+ return PARSE_NEED_MORE_DATA;
+ } else if (vp8_status != VP8_STATUS_OK) {
+ // We have enough data, and yet WebPGetFeatures() failed.
+ return PARSE_ERROR;
+ }
+ ++image_chunks;
+ frame->img_components_[0].offset_ = chunk_start_offset;
+ frame->img_components_[0].size_ = chunk_size;
+ frame->width_ = features.width;
+ frame->height_ = features.height;
+ frame->has_alpha_ |= features.has_alpha;
+ frame->frame_num_ = frame_num;
+ frame->complete_ = (status == PARSE_OK);
+ Skip(mem, payload_available);
+ } else {
+ goto Done;
+ }
+ break;
+ Done:
+ default:
+ // Restore fourcc/size when moving up one level in parsing.
+ Rewind(mem, CHUNK_HEADER_SIZE);
+ done = 1;
+ break;
+ }
+
+ if (mem->start_ == mem->riff_end_) {
+ done = 1;
+ } else if (MemDataSize(mem) < CHUNK_HEADER_SIZE) {
+ status = PARSE_NEED_MORE_DATA;
+ }
+ } while (!done && status == PARSE_OK);
+
+ return status;
+}
+
+// Creates a new Frame if 'actual_size' is within bounds and 'mem' contains
+// enough data ('min_size') to parse the payload.
+// Returns PARSE_OK on success with *frame pointing to the new Frame.
+// Returns PARSE_NEED_MORE_DATA with insufficient data, PARSE_ERROR otherwise.
+static ParseStatus NewFrame(const MemBuffer* const mem,
+ uint32_t min_size, uint32_t actual_size,
+ Frame** frame) {
+ if (SizeIsInvalid(mem, min_size)) return PARSE_ERROR;
+ if (actual_size < min_size) return PARSE_ERROR;
+ if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA;
+
+ *frame = (Frame*)WebPSafeCalloc(1ULL, sizeof(**frame));
+ return (*frame == NULL) ? PARSE_ERROR : PARSE_OK;
+}
+
+// Parse a 'ANMF' chunk and any image bearing chunks that immediately follow.
+// 'frame_chunk_size' is the previously validated, padded chunk size.
+static ParseStatus ParseAnimationFrame(
+ WebPDemuxer* const dmux, uint32_t frame_chunk_size) {
+ const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG);
+ const uint32_t anmf_payload_size = frame_chunk_size - ANMF_CHUNK_SIZE;
+ int added_frame = 0;
+ int bits;
+ MemBuffer* const mem = &dmux->mem_;
+ Frame* frame;
+ ParseStatus status =
+ NewFrame(mem, ANMF_CHUNK_SIZE, frame_chunk_size, &frame);
+ if (status != PARSE_OK) return status;
+
+ frame->x_offset_ = 2 * ReadLE24s(mem);
+ frame->y_offset_ = 2 * ReadLE24s(mem);
+ frame->width_ = 1 + ReadLE24s(mem);
+ frame->height_ = 1 + ReadLE24s(mem);
+ frame->duration_ = ReadLE24s(mem);
+ bits = ReadByte(mem);
+ frame->dispose_method_ =
+ (bits & 1) ? WEBP_MUX_DISPOSE_BACKGROUND : WEBP_MUX_DISPOSE_NONE;
+ frame->blend_method_ = (bits & 2) ? WEBP_MUX_NO_BLEND : WEBP_MUX_BLEND;
+ if (frame->width_ * (uint64_t)frame->height_ >= MAX_IMAGE_AREA) {
+ WebPSafeFree(frame);
+ return PARSE_ERROR;
+ }
+
+ // Store a frame only if the animation flag is set there is some data for
+ // this frame is available.
+ status = StoreFrame(dmux->num_frames_ + 1, anmf_payload_size, mem, frame);
+ if (status != PARSE_ERROR && is_animation && frame->frame_num_ > 0) {
+ added_frame = AddFrame(dmux, frame);
+ if (added_frame) {
+ ++dmux->num_frames_;
+ } else {
+ status = PARSE_ERROR;
+ }
+ }
+
+ if (!added_frame) WebPSafeFree(frame);
+ return status;
+}
+
+// General chunk storage, starting with the header at 'start_offset', allowing
+// the user to request the payload via a fourcc string. 'size' includes the
+// header and the unpadded payload size.
+// Returns true on success, false otherwise.
+static int StoreChunk(WebPDemuxer* const dmux,
+ size_t start_offset, uint32_t size) {
+ Chunk* const chunk = (Chunk*)WebPSafeCalloc(1ULL, sizeof(*chunk));
+ if (chunk == NULL) return 0;
+
+ chunk->data_.offset_ = start_offset;
+ chunk->data_.size_ = size;
+ AddChunk(dmux, chunk);
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+// Primary chunk parsing
+
+static ParseStatus ReadHeader(MemBuffer* const mem) {
+ const size_t min_size = RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE;
+ uint32_t riff_size;
+
+ // Basic file level validation.
+ if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA;
+ if (memcmp(GetBuffer(mem), "RIFF", CHUNK_SIZE_BYTES) ||
+ memcmp(GetBuffer(mem) + CHUNK_HEADER_SIZE, "WEBP", CHUNK_SIZE_BYTES)) {
+ return PARSE_ERROR;
+ }
+
+ riff_size = GetLE32(GetBuffer(mem) + TAG_SIZE);
+ if (riff_size < CHUNK_HEADER_SIZE) return PARSE_ERROR;
+ if (riff_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR;
+
+ // There's no point in reading past the end of the RIFF chunk
+ mem->riff_end_ = riff_size + CHUNK_HEADER_SIZE;
+ if (mem->buf_size_ > mem->riff_end_) {
+ mem->buf_size_ = mem->end_ = mem->riff_end_;
+ }
+
+ Skip(mem, RIFF_HEADER_SIZE);
+ return PARSE_OK;
+}
+
+static ParseStatus ParseSingleImage(WebPDemuxer* const dmux) {
+ const size_t min_size = CHUNK_HEADER_SIZE;
+ MemBuffer* const mem = &dmux->mem_;
+ Frame* frame;
+ ParseStatus status;
+ int image_added = 0;
+
+ if (dmux->frames_ != NULL) return PARSE_ERROR;
+ if (SizeIsInvalid(mem, min_size)) return PARSE_ERROR;
+ if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA;
+
+ frame = (Frame*)WebPSafeCalloc(1ULL, sizeof(*frame));
+ if (frame == NULL) return PARSE_ERROR;
+
+ // For the single image case we allow parsing of a partial frame, but we need
+ // at least CHUNK_HEADER_SIZE for parsing.
+ status = StoreFrame(1, CHUNK_HEADER_SIZE, &dmux->mem_, frame);
+ if (status != PARSE_ERROR) {
+ const int has_alpha = !!(dmux->feature_flags_ & ALPHA_FLAG);
+ // Clear any alpha when the alpha flag is missing.
+ if (!has_alpha && frame->img_components_[1].size_ > 0) {
+ frame->img_components_[1].offset_ = 0;
+ frame->img_components_[1].size_ = 0;
+ frame->has_alpha_ = 0;
+ }
+
+ // Use the frame width/height as the canvas values for non-vp8x files.
+ // Also, set ALPHA_FLAG if this is a lossless image with alpha.
+ if (!dmux->is_ext_format_ && frame->width_ > 0 && frame->height_ > 0) {
+ dmux->state_ = WEBP_DEMUX_PARSED_HEADER;
+ dmux->canvas_width_ = frame->width_;
+ dmux->canvas_height_ = frame->height_;
+ dmux->feature_flags_ |= frame->has_alpha_ ? ALPHA_FLAG : 0;
+ }
+ if (!AddFrame(dmux, frame)) {
+ status = PARSE_ERROR; // last frame was left incomplete
+ } else {
+ image_added = 1;
+ dmux->num_frames_ = 1;
+ }
+ }
+
+ if (!image_added) WebPSafeFree(frame);
+ return status;
+}
+
+static ParseStatus ParseVP8XChunks(WebPDemuxer* const dmux) {
+ const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG);
+ MemBuffer* const mem = &dmux->mem_;
+ int anim_chunks = 0;
+ ParseStatus status = PARSE_OK;
+
+ do {
+ int store_chunk = 1;
+ const size_t chunk_start_offset = mem->start_;
+ const uint32_t fourcc = ReadLE32(mem);
+ const uint32_t chunk_size = ReadLE32(mem);
+ const uint32_t chunk_size_padded = chunk_size + (chunk_size & 1);
+
+ if (chunk_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR;
+ if (SizeIsInvalid(mem, chunk_size_padded)) return PARSE_ERROR;
+
+ switch (fourcc) {
+ case MKFOURCC('V', 'P', '8', 'X'): {
+ return PARSE_ERROR;
+ }
+ case MKFOURCC('A', 'L', 'P', 'H'):
+ case MKFOURCC('V', 'P', '8', ' '):
+ case MKFOURCC('V', 'P', '8', 'L'): {
+ // check that this isn't an animation (all frames should be in an ANMF).
+ if (anim_chunks > 0 || is_animation) return PARSE_ERROR;
+
+ Rewind(mem, CHUNK_HEADER_SIZE);
+ status = ParseSingleImage(dmux);
+ break;
+ }
+ case MKFOURCC('A', 'N', 'I', 'M'): {
+ if (chunk_size_padded < ANIM_CHUNK_SIZE) return PARSE_ERROR;
+
+ if (MemDataSize(mem) < chunk_size_padded) {
+ status = PARSE_NEED_MORE_DATA;
+ } else if (anim_chunks == 0) {
+ ++anim_chunks;
+ dmux->bgcolor_ = ReadLE32(mem);
+ dmux->loop_count_ = ReadLE16s(mem);
+ Skip(mem, chunk_size_padded - ANIM_CHUNK_SIZE);
+ } else {
+ store_chunk = 0;
+ goto Skip;
+ }
+ break;
+ }
+ case MKFOURCC('A', 'N', 'M', 'F'): {
+ if (anim_chunks == 0) return PARSE_ERROR; // 'ANIM' precedes frames.
+ status = ParseAnimationFrame(dmux, chunk_size_padded);
+ break;
+ }
+ case MKFOURCC('I', 'C', 'C', 'P'): {
+ store_chunk = !!(dmux->feature_flags_ & ICCP_FLAG);
+ goto Skip;
+ }
+ case MKFOURCC('E', 'X', 'I', 'F'): {
+ store_chunk = !!(dmux->feature_flags_ & EXIF_FLAG);
+ goto Skip;
+ }
+ case MKFOURCC('X', 'M', 'P', ' '): {
+ store_chunk = !!(dmux->feature_flags_ & XMP_FLAG);
+ goto Skip;
+ }
+ Skip:
+ default: {
+ if (chunk_size_padded <= MemDataSize(mem)) {
+ if (store_chunk) {
+ // Store only the chunk header and unpadded size as only the payload
+ // will be returned to the user.
+ if (!StoreChunk(dmux, chunk_start_offset,
+ CHUNK_HEADER_SIZE + chunk_size)) {
+ return PARSE_ERROR;
+ }
+ }
+ Skip(mem, chunk_size_padded);
+ } else {
+ status = PARSE_NEED_MORE_DATA;
+ }
+ }
+ }
+
+ if (mem->start_ == mem->riff_end_) {
+ break;
+ } else if (MemDataSize(mem) < CHUNK_HEADER_SIZE) {
+ status = PARSE_NEED_MORE_DATA;
+ }
+ } while (status == PARSE_OK);
+
+ return status;
+}
+
+static ParseStatus ParseVP8X(WebPDemuxer* const dmux) {
+ MemBuffer* const mem = &dmux->mem_;
+ uint32_t vp8x_size;
+
+ if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA;
+
+ dmux->is_ext_format_ = 1;
+ Skip(mem, TAG_SIZE); // VP8X
+ vp8x_size = ReadLE32(mem);
+ if (vp8x_size > MAX_CHUNK_PAYLOAD) return PARSE_ERROR;
+ if (vp8x_size < VP8X_CHUNK_SIZE) return PARSE_ERROR;
+ vp8x_size += vp8x_size & 1;
+ if (SizeIsInvalid(mem, vp8x_size)) return PARSE_ERROR;
+ if (MemDataSize(mem) < vp8x_size) return PARSE_NEED_MORE_DATA;
+
+ dmux->feature_flags_ = ReadByte(mem);
+ Skip(mem, 3); // Reserved.
+ dmux->canvas_width_ = 1 + ReadLE24s(mem);
+ dmux->canvas_height_ = 1 + ReadLE24s(mem);
+ if (dmux->canvas_width_ * (uint64_t)dmux->canvas_height_ >= MAX_IMAGE_AREA) {
+ return PARSE_ERROR; // image final dimension is too large
+ }
+ Skip(mem, vp8x_size - VP8X_CHUNK_SIZE); // skip any trailing data.
+ dmux->state_ = WEBP_DEMUX_PARSED_HEADER;
+
+ if (SizeIsInvalid(mem, CHUNK_HEADER_SIZE)) return PARSE_ERROR;
+ if (MemDataSize(mem) < CHUNK_HEADER_SIZE) return PARSE_NEED_MORE_DATA;
+
+ return ParseVP8XChunks(dmux);
+}
+
+// -----------------------------------------------------------------------------
+// Format validation
+
+static int IsValidSimpleFormat(const WebPDemuxer* const dmux) {
+ const Frame* const frame = dmux->frames_;
+ if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1;
+
+ if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0;
+ if (dmux->state_ == WEBP_DEMUX_DONE && frame == NULL) return 0;
+
+ if (frame->width_ <= 0 || frame->height_ <= 0) return 0;
+ return 1;
+}
+
+// If 'exact' is true, check that the image resolution matches the canvas.
+// If 'exact' is false, check that the x/y offsets do not exceed the canvas.
+// TODO(jzern): this is insufficient in the fragmented image case if the
+// expectation is that the fragments completely cover the canvas.
+static int CheckFrameBounds(const Frame* const frame, int exact,
+ int canvas_width, int canvas_height) {
+ if (exact) {
+ if (frame->x_offset_ != 0 || frame->y_offset_ != 0) {
+ return 0;
+ }
+ if (frame->width_ != canvas_width || frame->height_ != canvas_height) {
+ return 0;
+ }
+ } else {
+ if (frame->x_offset_ < 0 || frame->y_offset_ < 0) return 0;
+ if (frame->width_ + frame->x_offset_ > canvas_width) return 0;
+ if (frame->height_ + frame->y_offset_ > canvas_height) return 0;
+ }
+ return 1;
+}
+
+static int IsValidExtendedFormat(const WebPDemuxer* const dmux) {
+ const int is_animation = !!(dmux->feature_flags_ & ANIMATION_FLAG);
+ const int is_fragmented = !!(dmux->feature_flags_ & FRAGMENTS_FLAG);
+ const Frame* f = dmux->frames_;
+
+ if (dmux->state_ == WEBP_DEMUX_PARSING_HEADER) return 1;
+
+ if (dmux->canvas_width_ <= 0 || dmux->canvas_height_ <= 0) return 0;
+ if (dmux->loop_count_ < 0) return 0;
+ if (dmux->state_ == WEBP_DEMUX_DONE && dmux->frames_ == NULL) return 0;
+ if (is_fragmented) return 0;
+
+ while (f != NULL) {
+ const int cur_frame_set = f->frame_num_;
+ int frame_count = 0, fragment_count = 0;
+
+ // Check frame properties and if the image is composed of fragments that
+ // each fragment came from a fragment.
+ for (; f != NULL && f->frame_num_ == cur_frame_set; f = f->next_) {
+ const ChunkData* const image = f->img_components_;
+ const ChunkData* const alpha = f->img_components_ + 1;
+
+ if (is_fragmented && !f->is_fragment_) return 0;
+ if (!is_fragmented && f->is_fragment_) return 0;
+ if (!is_animation && f->frame_num_ > 1) return 0;
+
+ if (f->complete_) {
+ if (alpha->size_ == 0 && image->size_ == 0) return 0;
+ // Ensure alpha precedes image bitstream.
+ if (alpha->size_ > 0 && alpha->offset_ > image->offset_) {
+ return 0;
+ }
+
+ if (f->width_ <= 0 || f->height_ <= 0) return 0;
+ } else {
+ // There shouldn't be a partial frame in a complete file.
+ if (dmux->state_ == WEBP_DEMUX_DONE) return 0;
+
+ // Ensure alpha precedes image bitstream.
+ if (alpha->size_ > 0 && image->size_ > 0 &&
+ alpha->offset_ > image->offset_) {
+ return 0;
+ }
+ // There shouldn't be any frames after an incomplete one.
+ if (f->next_ != NULL) return 0;
+ }
+
+ if (f->width_ > 0 && f->height_ > 0 &&
+ !CheckFrameBounds(f, !(is_animation || is_fragmented),
+ dmux->canvas_width_, dmux->canvas_height_)) {
+ return 0;
+ }
+
+ fragment_count += f->is_fragment_;
+ ++frame_count;
+ }
+ if (!is_fragmented && frame_count > 1) return 0;
+ if (fragment_count > 0 && frame_count != fragment_count) return 0;
+ }
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+// WebPDemuxer object
+
+static void InitDemux(WebPDemuxer* const dmux, const MemBuffer* const mem) {
+ dmux->state_ = WEBP_DEMUX_PARSING_HEADER;
+ dmux->loop_count_ = 1;
+ dmux->bgcolor_ = 0xFFFFFFFF; // White background by default.
+ dmux->canvas_width_ = -1;
+ dmux->canvas_height_ = -1;
+ dmux->frames_tail_ = &dmux->frames_;
+ dmux->chunks_tail_ = &dmux->chunks_;
+ dmux->mem_ = *mem;
+}
+
+WebPDemuxer* WebPDemuxInternal(const WebPData* data, int allow_partial,
+ WebPDemuxState* state, int version) {
+ const ChunkParser* parser;
+ int partial;
+ ParseStatus status = PARSE_ERROR;
+ MemBuffer mem;
+ WebPDemuxer* dmux;
+
+ if (state != NULL) *state = WEBP_DEMUX_PARSE_ERROR;
+
+ if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DEMUX_ABI_VERSION)) return NULL;
+ if (data == NULL || data->bytes == NULL || data->size == 0) return NULL;
+
+ if (!InitMemBuffer(&mem, data->bytes, data->size)) return NULL;
+ status = ReadHeader(&mem);
+ if (status != PARSE_OK) {
+ if (state != NULL) {
+ *state = (status == PARSE_NEED_MORE_DATA) ? WEBP_DEMUX_PARSING_HEADER
+ : WEBP_DEMUX_PARSE_ERROR;
+ }
+ return NULL;
+ }
+
+ partial = (mem.buf_size_ < mem.riff_end_);
+ if (!allow_partial && partial) return NULL;
+
+ dmux = (WebPDemuxer*)WebPSafeCalloc(1ULL, sizeof(*dmux));
+ if (dmux == NULL) return NULL;
+ InitDemux(dmux, &mem);
+
+ status = PARSE_ERROR;
+ for (parser = kMasterChunks; parser->parse != NULL; ++parser) {
+ if (!memcmp(parser->id, GetBuffer(&dmux->mem_), TAG_SIZE)) {
+ status = parser->parse(dmux);
+ if (status == PARSE_OK) dmux->state_ = WEBP_DEMUX_DONE;
+ if (status == PARSE_NEED_MORE_DATA && !partial) status = PARSE_ERROR;
+ if (status != PARSE_ERROR && !parser->valid(dmux)) status = PARSE_ERROR;
+ if (status == PARSE_ERROR) dmux->state_ = WEBP_DEMUX_PARSE_ERROR;
+ break;
+ }
+ }
+ if (state != NULL) *state = dmux->state_;
+
+ if (status == PARSE_ERROR) {
+ WebPDemuxDelete(dmux);
+ return NULL;
+ }
+ return dmux;
+}
+
+void WebPDemuxDelete(WebPDemuxer* dmux) {
+ Chunk* c;
+ Frame* f;
+ if (dmux == NULL) return;
+
+ for (f = dmux->frames_; f != NULL;) {
+ Frame* const cur_frame = f;
+ f = f->next_;
+ WebPSafeFree(cur_frame);
+ }
+ for (c = dmux->chunks_; c != NULL;) {
+ Chunk* const cur_chunk = c;
+ c = c->next_;
+ WebPSafeFree(cur_chunk);
+ }
+ WebPSafeFree(dmux);
+}
+
+// -----------------------------------------------------------------------------
+
+uint32_t WebPDemuxGetI(const WebPDemuxer* dmux, WebPFormatFeature feature) {
+ if (dmux == NULL) return 0;
+
+ switch (feature) {
+ case WEBP_FF_FORMAT_FLAGS: return dmux->feature_flags_;
+ case WEBP_FF_CANVAS_WIDTH: return (uint32_t)dmux->canvas_width_;
+ case WEBP_FF_CANVAS_HEIGHT: return (uint32_t)dmux->canvas_height_;
+ case WEBP_FF_LOOP_COUNT: return (uint32_t)dmux->loop_count_;
+ case WEBP_FF_BACKGROUND_COLOR: return dmux->bgcolor_;
+ case WEBP_FF_FRAME_COUNT: return (uint32_t)dmux->num_frames_;
+ }
+ return 0;
+}
+
+// -----------------------------------------------------------------------------
+// Frame iteration
+
+// Find the first 'frame_num' frame. There may be multiple such frames in a
+// fragmented frame.
+static const Frame* GetFrame(const WebPDemuxer* const dmux, int frame_num) {
+ const Frame* f;
+ for (f = dmux->frames_; f != NULL; f = f->next_) {
+ if (frame_num == f->frame_num_) break;
+ }
+ return f;
+}
+
+// Returns fragment 'fragment_num' and the total count.
+static const Frame* GetFragment(
+ const Frame* const frame_set, int fragment_num, int* const count) {
+ const int this_frame = frame_set->frame_num_;
+ const Frame* f = frame_set;
+ const Frame* fragment = NULL;
+ int total;
+
+ for (total = 0; f != NULL && f->frame_num_ == this_frame; f = f->next_) {
+ if (++total == fragment_num) fragment = f;
+ }
+ *count = total;
+ return fragment;
+}
+
+static const uint8_t* GetFramePayload(const uint8_t* const mem_buf,
+ const Frame* const frame,
+ size_t* const data_size) {
+ *data_size = 0;
+ if (frame != NULL) {
+ const ChunkData* const image = frame->img_components_;
+ const ChunkData* const alpha = frame->img_components_ + 1;
+ size_t start_offset = image->offset_;
+ *data_size = image->size_;
+
+ // if alpha exists it precedes image, update the size allowing for
+ // intervening chunks.
+ if (alpha->size_ > 0) {
+ const size_t inter_size = (image->offset_ > 0)
+ ? image->offset_ - (alpha->offset_ + alpha->size_)
+ : 0;
+ start_offset = alpha->offset_;
+ *data_size += alpha->size_ + inter_size;
+ }
+ return mem_buf + start_offset;
+ }
+ return NULL;
+}
+
+// Create a whole 'frame' from VP8 (+ alpha) or lossless.
+static int SynthesizeFrame(const WebPDemuxer* const dmux,
+ const Frame* const first_frame,
+ int fragment_num, WebPIterator* const iter) {
+ const uint8_t* const mem_buf = dmux->mem_.buf_;
+ int num_fragments;
+ size_t payload_size = 0;
+ const Frame* const fragment =
+ GetFragment(first_frame, fragment_num, &num_fragments);
+ const uint8_t* const payload =
+ GetFramePayload(mem_buf, fragment, &payload_size);
+ if (payload == NULL) return 0;
+ assert(first_frame != NULL);
+
+ iter->frame_num = first_frame->frame_num_;
+ iter->num_frames = dmux->num_frames_;
+ iter->fragment_num = fragment_num;
+ iter->num_fragments = num_fragments;
+ iter->x_offset = fragment->x_offset_;
+ iter->y_offset = fragment->y_offset_;
+ iter->width = fragment->width_;
+ iter->height = fragment->height_;
+ iter->has_alpha = fragment->has_alpha_;
+ iter->duration = fragment->duration_;
+ iter->dispose_method = fragment->dispose_method_;
+ iter->blend_method = fragment->blend_method_;
+ iter->complete = fragment->complete_;
+ iter->fragment.bytes = payload;
+ iter->fragment.size = payload_size;
+ return 1;
+}
+
+static int SetFrame(int frame_num, WebPIterator* const iter) {
+ const Frame* frame;
+ const WebPDemuxer* const dmux = (WebPDemuxer*)iter->private_;
+ if (dmux == NULL || frame_num < 0) return 0;
+ if (frame_num > dmux->num_frames_) return 0;
+ if (frame_num == 0) frame_num = dmux->num_frames_;
+
+ frame = GetFrame(dmux, frame_num);
+ if (frame == NULL) return 0;
+
+ return SynthesizeFrame(dmux, frame, 1, iter);
+}
+
+int WebPDemuxGetFrame(const WebPDemuxer* dmux, int frame, WebPIterator* iter) {
+ if (iter == NULL) return 0;
+
+ memset(iter, 0, sizeof(*iter));
+ iter->private_ = (void*)dmux;
+ return SetFrame(frame, iter);
+}
+
+int WebPDemuxNextFrame(WebPIterator* iter) {
+ if (iter == NULL) return 0;
+ return SetFrame(iter->frame_num + 1, iter);
+}
+
+int WebPDemuxPrevFrame(WebPIterator* iter) {
+ if (iter == NULL) return 0;
+ if (iter->frame_num <= 1) return 0;
+ return SetFrame(iter->frame_num - 1, iter);
+}
+
+int WebPDemuxSelectFragment(WebPIterator* iter, int fragment_num) {
+ if (iter != NULL && iter->private_ != NULL && fragment_num > 0) {
+ const WebPDemuxer* const dmux = (WebPDemuxer*)iter->private_;
+ const Frame* const frame = GetFrame(dmux, iter->frame_num);
+ if (frame == NULL) return 0;
+
+ return SynthesizeFrame(dmux, frame, fragment_num, iter);
+ }
+ return 0;
+}
+
+void WebPDemuxReleaseIterator(WebPIterator* iter) {
+ (void)iter;
+}
+
+// -----------------------------------------------------------------------------
+// Chunk iteration
+
+static int ChunkCount(const WebPDemuxer* const dmux, const char fourcc[4]) {
+ const uint8_t* const mem_buf = dmux->mem_.buf_;
+ const Chunk* c;
+ int count = 0;
+ for (c = dmux->chunks_; c != NULL; c = c->next_) {
+ const uint8_t* const header = mem_buf + c->data_.offset_;
+ if (!memcmp(header, fourcc, TAG_SIZE)) ++count;
+ }
+ return count;
+}
+
+static const Chunk* GetChunk(const WebPDemuxer* const dmux,
+ const char fourcc[4], int chunk_num) {
+ const uint8_t* const mem_buf = dmux->mem_.buf_;
+ const Chunk* c;
+ int count = 0;
+ for (c = dmux->chunks_; c != NULL; c = c->next_) {
+ const uint8_t* const header = mem_buf + c->data_.offset_;
+ if (!memcmp(header, fourcc, TAG_SIZE)) ++count;
+ if (count == chunk_num) break;
+ }
+ return c;
+}
+
+static int SetChunk(const char fourcc[4], int chunk_num,
+ WebPChunkIterator* const iter) {
+ const WebPDemuxer* const dmux = (WebPDemuxer*)iter->private_;
+ int count;
+
+ if (dmux == NULL || fourcc == NULL || chunk_num < 0) return 0;
+ count = ChunkCount(dmux, fourcc);
+ if (count == 0) return 0;
+ if (chunk_num == 0) chunk_num = count;
+
+ if (chunk_num <= count) {
+ const uint8_t* const mem_buf = dmux->mem_.buf_;
+ const Chunk* const chunk = GetChunk(dmux, fourcc, chunk_num);
+ iter->chunk.bytes = mem_buf + chunk->data_.offset_ + CHUNK_HEADER_SIZE;
+ iter->chunk.size = chunk->data_.size_ - CHUNK_HEADER_SIZE;
+ iter->num_chunks = count;
+ iter->chunk_num = chunk_num;
+ return 1;
+ }
+ return 0;
+}
+
+int WebPDemuxGetChunk(const WebPDemuxer* dmux,
+ const char fourcc[4], int chunk_num,
+ WebPChunkIterator* iter) {
+ if (iter == NULL) return 0;
+
+ memset(iter, 0, sizeof(*iter));
+ iter->private_ = (void*)dmux;
+ return SetChunk(fourcc, chunk_num, iter);
+}
+
+int WebPDemuxNextChunk(WebPChunkIterator* iter) {
+ if (iter != NULL) {
+ const char* const fourcc =
+ (const char*)iter->chunk.bytes - CHUNK_HEADER_SIZE;
+ return SetChunk(fourcc, iter->chunk_num + 1, iter);
+ }
+ return 0;
+}
+
+int WebPDemuxPrevChunk(WebPChunkIterator* iter) {
+ if (iter != NULL && iter->chunk_num > 1) {
+ const char* const fourcc =
+ (const char*)iter->chunk.bytes - CHUNK_HEADER_SIZE;
+ return SetChunk(fourcc, iter->chunk_num - 1, iter);
+ }
+ return 0;
+}
+
+void WebPDemuxReleaseChunkIterator(WebPChunkIterator* iter) {
+ (void)iter;
+}
+
diff --git a/drivers/webp/dsp/alpha_processing.c b/drivers/webp/dsp/alpha_processing.c
new file mode 100644
index 0000000000..1716cace8d
--- /dev/null
+++ b/drivers/webp/dsp/alpha_processing.c
@@ -0,0 +1,383 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Utilities for processing transparent channel.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <assert.h>
+#include "./dsp.h"
+
+// Tables can be faster on some platform but incur some extra binary size (~2k).
+// #define USE_TABLES_FOR_ALPHA_MULT
+
+// -----------------------------------------------------------------------------
+
+#define MFIX 24 // 24bit fixed-point arithmetic
+#define HALF ((1u << MFIX) >> 1)
+#define KINV_255 ((1u << MFIX) / 255u)
+
+static uint32_t Mult(uint8_t x, uint32_t mult) {
+ const uint32_t v = (x * mult + HALF) >> MFIX;
+ assert(v <= 255); // <- 24bit precision is enough to ensure that.
+ return v;
+}
+
+#ifdef USE_TABLES_FOR_ALPHA_MULT
+
+static const uint32_t kMultTables[2][256] = {
+ { // (255u << MFIX) / alpha
+ 0x00000000, 0xff000000, 0x7f800000, 0x55000000, 0x3fc00000, 0x33000000,
+ 0x2a800000, 0x246db6db, 0x1fe00000, 0x1c555555, 0x19800000, 0x172e8ba2,
+ 0x15400000, 0x139d89d8, 0x1236db6d, 0x11000000, 0x0ff00000, 0x0f000000,
+ 0x0e2aaaaa, 0x0d6bca1a, 0x0cc00000, 0x0c249249, 0x0b9745d1, 0x0b1642c8,
+ 0x0aa00000, 0x0a333333, 0x09cec4ec, 0x0971c71c, 0x091b6db6, 0x08cb08d3,
+ 0x08800000, 0x0839ce73, 0x07f80000, 0x07ba2e8b, 0x07800000, 0x07492492,
+ 0x07155555, 0x06e45306, 0x06b5e50d, 0x0689d89d, 0x06600000, 0x063831f3,
+ 0x06124924, 0x05ee23b8, 0x05cba2e8, 0x05aaaaaa, 0x058b2164, 0x056cefa8,
+ 0x05500000, 0x05343eb1, 0x05199999, 0x05000000, 0x04e76276, 0x04cfb2b7,
+ 0x04b8e38e, 0x04a2e8ba, 0x048db6db, 0x0479435e, 0x04658469, 0x045270d0,
+ 0x04400000, 0x042e29f7, 0x041ce739, 0x040c30c3, 0x03fc0000, 0x03ec4ec4,
+ 0x03dd1745, 0x03ce540f, 0x03c00000, 0x03b21642, 0x03a49249, 0x03976fc6,
+ 0x038aaaaa, 0x037e3f1f, 0x03722983, 0x03666666, 0x035af286, 0x034fcace,
+ 0x0344ec4e, 0x033a5440, 0x03300000, 0x0325ed09, 0x031c18f9, 0x0312818a,
+ 0x03092492, 0x03000000, 0x02f711dc, 0x02ee5846, 0x02e5d174, 0x02dd7baf,
+ 0x02d55555, 0x02cd5cd5, 0x02c590b2, 0x02bdef7b, 0x02b677d4, 0x02af286b,
+ 0x02a80000, 0x02a0fd5c, 0x029a1f58, 0x029364d9, 0x028ccccc, 0x0286562d,
+ 0x02800000, 0x0279c952, 0x0273b13b, 0x026db6db, 0x0267d95b, 0x026217ec,
+ 0x025c71c7, 0x0256e62a, 0x0251745d, 0x024c1bac, 0x0246db6d, 0x0241b2f9,
+ 0x023ca1af, 0x0237a6f4, 0x0232c234, 0x022df2df, 0x02293868, 0x02249249,
+ 0x02200000, 0x021b810e, 0x021714fb, 0x0212bb51, 0x020e739c, 0x020a3d70,
+ 0x02061861, 0x02020408, 0x01fe0000, 0x01fa0be8, 0x01f62762, 0x01f25213,
+ 0x01ee8ba2, 0x01ead3ba, 0x01e72a07, 0x01e38e38, 0x01e00000, 0x01dc7f10,
+ 0x01d90b21, 0x01d5a3e9, 0x01d24924, 0x01cefa8d, 0x01cbb7e3, 0x01c880e5,
+ 0x01c55555, 0x01c234f7, 0x01bf1f8f, 0x01bc14e5, 0x01b914c1, 0x01b61eed,
+ 0x01b33333, 0x01b05160, 0x01ad7943, 0x01aaaaaa, 0x01a7e567, 0x01a5294a,
+ 0x01a27627, 0x019fcbd2, 0x019d2a20, 0x019a90e7, 0x01980000, 0x01957741,
+ 0x0192f684, 0x01907da4, 0x018e0c7c, 0x018ba2e8, 0x018940c5, 0x0186e5f0,
+ 0x01849249, 0x018245ae, 0x01800000, 0x017dc11f, 0x017b88ee, 0x0179574e,
+ 0x01772c23, 0x01750750, 0x0172e8ba, 0x0170d045, 0x016ebdd7, 0x016cb157,
+ 0x016aaaaa, 0x0168a9b9, 0x0166ae6a, 0x0164b8a7, 0x0162c859, 0x0160dd67,
+ 0x015ef7bd, 0x015d1745, 0x015b3bea, 0x01596596, 0x01579435, 0x0155c7b4,
+ 0x01540000, 0x01523d03, 0x01507eae, 0x014ec4ec, 0x014d0fac, 0x014b5edc,
+ 0x0149b26c, 0x01480a4a, 0x01466666, 0x0144c6af, 0x01432b16, 0x0141938b,
+ 0x01400000, 0x013e7063, 0x013ce4a9, 0x013b5cc0, 0x0139d89d, 0x01385830,
+ 0x0136db6d, 0x01356246, 0x0133ecad, 0x01327a97, 0x01310bf6, 0x012fa0be,
+ 0x012e38e3, 0x012cd459, 0x012b7315, 0x012a150a, 0x0128ba2e, 0x01276276,
+ 0x01260dd6, 0x0124bc44, 0x01236db6, 0x01222222, 0x0120d97c, 0x011f93bc,
+ 0x011e50d7, 0x011d10c4, 0x011bd37a, 0x011a98ef, 0x0119611a, 0x01182bf2,
+ 0x0116f96f, 0x0115c988, 0x01149c34, 0x0113716a, 0x01124924, 0x01112358,
+ 0x01100000, 0x010edf12, 0x010dc087, 0x010ca458, 0x010b8a7d, 0x010a72f0,
+ 0x01095da8, 0x01084a9f, 0x010739ce, 0x01062b2e, 0x01051eb8, 0x01041465,
+ 0x01030c30, 0x01020612, 0x01010204, 0x01000000 },
+ { // alpha * KINV_255
+ 0x00000000, 0x00010101, 0x00020202, 0x00030303, 0x00040404, 0x00050505,
+ 0x00060606, 0x00070707, 0x00080808, 0x00090909, 0x000a0a0a, 0x000b0b0b,
+ 0x000c0c0c, 0x000d0d0d, 0x000e0e0e, 0x000f0f0f, 0x00101010, 0x00111111,
+ 0x00121212, 0x00131313, 0x00141414, 0x00151515, 0x00161616, 0x00171717,
+ 0x00181818, 0x00191919, 0x001a1a1a, 0x001b1b1b, 0x001c1c1c, 0x001d1d1d,
+ 0x001e1e1e, 0x001f1f1f, 0x00202020, 0x00212121, 0x00222222, 0x00232323,
+ 0x00242424, 0x00252525, 0x00262626, 0x00272727, 0x00282828, 0x00292929,
+ 0x002a2a2a, 0x002b2b2b, 0x002c2c2c, 0x002d2d2d, 0x002e2e2e, 0x002f2f2f,
+ 0x00303030, 0x00313131, 0x00323232, 0x00333333, 0x00343434, 0x00353535,
+ 0x00363636, 0x00373737, 0x00383838, 0x00393939, 0x003a3a3a, 0x003b3b3b,
+ 0x003c3c3c, 0x003d3d3d, 0x003e3e3e, 0x003f3f3f, 0x00404040, 0x00414141,
+ 0x00424242, 0x00434343, 0x00444444, 0x00454545, 0x00464646, 0x00474747,
+ 0x00484848, 0x00494949, 0x004a4a4a, 0x004b4b4b, 0x004c4c4c, 0x004d4d4d,
+ 0x004e4e4e, 0x004f4f4f, 0x00505050, 0x00515151, 0x00525252, 0x00535353,
+ 0x00545454, 0x00555555, 0x00565656, 0x00575757, 0x00585858, 0x00595959,
+ 0x005a5a5a, 0x005b5b5b, 0x005c5c5c, 0x005d5d5d, 0x005e5e5e, 0x005f5f5f,
+ 0x00606060, 0x00616161, 0x00626262, 0x00636363, 0x00646464, 0x00656565,
+ 0x00666666, 0x00676767, 0x00686868, 0x00696969, 0x006a6a6a, 0x006b6b6b,
+ 0x006c6c6c, 0x006d6d6d, 0x006e6e6e, 0x006f6f6f, 0x00707070, 0x00717171,
+ 0x00727272, 0x00737373, 0x00747474, 0x00757575, 0x00767676, 0x00777777,
+ 0x00787878, 0x00797979, 0x007a7a7a, 0x007b7b7b, 0x007c7c7c, 0x007d7d7d,
+ 0x007e7e7e, 0x007f7f7f, 0x00808080, 0x00818181, 0x00828282, 0x00838383,
+ 0x00848484, 0x00858585, 0x00868686, 0x00878787, 0x00888888, 0x00898989,
+ 0x008a8a8a, 0x008b8b8b, 0x008c8c8c, 0x008d8d8d, 0x008e8e8e, 0x008f8f8f,
+ 0x00909090, 0x00919191, 0x00929292, 0x00939393, 0x00949494, 0x00959595,
+ 0x00969696, 0x00979797, 0x00989898, 0x00999999, 0x009a9a9a, 0x009b9b9b,
+ 0x009c9c9c, 0x009d9d9d, 0x009e9e9e, 0x009f9f9f, 0x00a0a0a0, 0x00a1a1a1,
+ 0x00a2a2a2, 0x00a3a3a3, 0x00a4a4a4, 0x00a5a5a5, 0x00a6a6a6, 0x00a7a7a7,
+ 0x00a8a8a8, 0x00a9a9a9, 0x00aaaaaa, 0x00ababab, 0x00acacac, 0x00adadad,
+ 0x00aeaeae, 0x00afafaf, 0x00b0b0b0, 0x00b1b1b1, 0x00b2b2b2, 0x00b3b3b3,
+ 0x00b4b4b4, 0x00b5b5b5, 0x00b6b6b6, 0x00b7b7b7, 0x00b8b8b8, 0x00b9b9b9,
+ 0x00bababa, 0x00bbbbbb, 0x00bcbcbc, 0x00bdbdbd, 0x00bebebe, 0x00bfbfbf,
+ 0x00c0c0c0, 0x00c1c1c1, 0x00c2c2c2, 0x00c3c3c3, 0x00c4c4c4, 0x00c5c5c5,
+ 0x00c6c6c6, 0x00c7c7c7, 0x00c8c8c8, 0x00c9c9c9, 0x00cacaca, 0x00cbcbcb,
+ 0x00cccccc, 0x00cdcdcd, 0x00cecece, 0x00cfcfcf, 0x00d0d0d0, 0x00d1d1d1,
+ 0x00d2d2d2, 0x00d3d3d3, 0x00d4d4d4, 0x00d5d5d5, 0x00d6d6d6, 0x00d7d7d7,
+ 0x00d8d8d8, 0x00d9d9d9, 0x00dadada, 0x00dbdbdb, 0x00dcdcdc, 0x00dddddd,
+ 0x00dedede, 0x00dfdfdf, 0x00e0e0e0, 0x00e1e1e1, 0x00e2e2e2, 0x00e3e3e3,
+ 0x00e4e4e4, 0x00e5e5e5, 0x00e6e6e6, 0x00e7e7e7, 0x00e8e8e8, 0x00e9e9e9,
+ 0x00eaeaea, 0x00ebebeb, 0x00ececec, 0x00ededed, 0x00eeeeee, 0x00efefef,
+ 0x00f0f0f0, 0x00f1f1f1, 0x00f2f2f2, 0x00f3f3f3, 0x00f4f4f4, 0x00f5f5f5,
+ 0x00f6f6f6, 0x00f7f7f7, 0x00f8f8f8, 0x00f9f9f9, 0x00fafafa, 0x00fbfbfb,
+ 0x00fcfcfc, 0x00fdfdfd, 0x00fefefe, 0x00ffffff }
+};
+
+static WEBP_INLINE uint32_t GetScale(uint32_t a, int inverse) {
+ return kMultTables[!inverse][a];
+}
+
+#else
+
+static WEBP_INLINE uint32_t GetScale(uint32_t a, int inverse) {
+ return inverse ? (255u << MFIX) / a : a * KINV_255;
+}
+
+#endif // USE_TABLES_FOR_ALPHA_MULT
+
+void WebPMultARGBRowC(uint32_t* const ptr, int width, int inverse) {
+ int x;
+ for (x = 0; x < width; ++x) {
+ const uint32_t argb = ptr[x];
+ if (argb < 0xff000000u) { // alpha < 255
+ if (argb <= 0x00ffffffu) { // alpha == 0
+ ptr[x] = 0;
+ } else {
+ const uint32_t alpha = (argb >> 24) & 0xff;
+ const uint32_t scale = GetScale(alpha, inverse);
+ uint32_t out = argb & 0xff000000u;
+ out |= Mult(argb >> 0, scale) << 0;
+ out |= Mult(argb >> 8, scale) << 8;
+ out |= Mult(argb >> 16, scale) << 16;
+ ptr[x] = out;
+ }
+ }
+ }
+}
+
+void WebPMultRowC(uint8_t* const ptr, const uint8_t* const alpha,
+ int width, int inverse) {
+ int x;
+ for (x = 0; x < width; ++x) {
+ const uint32_t a = alpha[x];
+ if (a != 255) {
+ if (a == 0) {
+ ptr[x] = 0;
+ } else {
+ const uint32_t scale = GetScale(a, inverse);
+ ptr[x] = Mult(ptr[x], scale);
+ }
+ }
+ }
+}
+
+#undef KINV_255
+#undef HALF
+#undef MFIX
+
+void (*WebPMultARGBRow)(uint32_t* const ptr, int width, int inverse);
+void (*WebPMultRow)(uint8_t* const ptr, const uint8_t* const alpha,
+ int width, int inverse);
+
+//------------------------------------------------------------------------------
+// Generic per-plane calls
+
+void WebPMultARGBRows(uint8_t* ptr, int stride, int width, int num_rows,
+ int inverse) {
+ int n;
+ for (n = 0; n < num_rows; ++n) {
+ WebPMultARGBRow((uint32_t*)ptr, width, inverse);
+ ptr += stride;
+ }
+}
+
+void WebPMultRows(uint8_t* ptr, int stride,
+ const uint8_t* alpha, int alpha_stride,
+ int width, int num_rows, int inverse) {
+ int n;
+ for (n = 0; n < num_rows; ++n) {
+ WebPMultRow(ptr, alpha, width, inverse);
+ ptr += stride;
+ alpha += alpha_stride;
+ }
+}
+
+//------------------------------------------------------------------------------
+// Premultiplied modes
+
+// non dithered-modes
+
+// (x * a * 32897) >> 23 is bit-wise equivalent to (int)(x * a / 255.)
+// for all 8bit x or a. For bit-wise equivalence to (int)(x * a / 255. + .5),
+// one can use instead: (x * a * 65793 + (1 << 23)) >> 24
+#if 1 // (int)(x * a / 255.)
+#define MULTIPLIER(a) ((a) * 32897U)
+#define PREMULTIPLY(x, m) (((x) * (m)) >> 23)
+#else // (int)(x * a / 255. + .5)
+#define MULTIPLIER(a) ((a) * 65793U)
+#define PREMULTIPLY(x, m) (((x) * (m) + (1U << 23)) >> 24)
+#endif
+
+static void ApplyAlphaMultiply(uint8_t* rgba, int alpha_first,
+ int w, int h, int stride) {
+ while (h-- > 0) {
+ uint8_t* const rgb = rgba + (alpha_first ? 1 : 0);
+ const uint8_t* const alpha = rgba + (alpha_first ? 0 : 3);
+ int i;
+ for (i = 0; i < w; ++i) {
+ const uint32_t a = alpha[4 * i];
+ if (a != 0xff) {
+ const uint32_t mult = MULTIPLIER(a);
+ rgb[4 * i + 0] = PREMULTIPLY(rgb[4 * i + 0], mult);
+ rgb[4 * i + 1] = PREMULTIPLY(rgb[4 * i + 1], mult);
+ rgb[4 * i + 2] = PREMULTIPLY(rgb[4 * i + 2], mult);
+ }
+ }
+ rgba += stride;
+ }
+}
+#undef MULTIPLIER
+#undef PREMULTIPLY
+
+// rgbA4444
+
+#define MULTIPLIER(a) ((a) * 0x1111) // 0x1111 ~= (1 << 16) / 15
+
+static WEBP_INLINE uint8_t dither_hi(uint8_t x) {
+ return (x & 0xf0) | (x >> 4);
+}
+
+static WEBP_INLINE uint8_t dither_lo(uint8_t x) {
+ return (x & 0x0f) | (x << 4);
+}
+
+static WEBP_INLINE uint8_t multiply(uint8_t x, uint32_t m) {
+ return (x * m) >> 16;
+}
+
+static WEBP_INLINE void ApplyAlphaMultiply4444(uint8_t* rgba4444,
+ int w, int h, int stride,
+ int rg_byte_pos /* 0 or 1 */) {
+ while (h-- > 0) {
+ int i;
+ for (i = 0; i < w; ++i) {
+ const uint32_t rg = rgba4444[2 * i + rg_byte_pos];
+ const uint32_t ba = rgba4444[2 * i + (rg_byte_pos ^ 1)];
+ const uint8_t a = ba & 0x0f;
+ const uint32_t mult = MULTIPLIER(a);
+ const uint8_t r = multiply(dither_hi(rg), mult);
+ const uint8_t g = multiply(dither_lo(rg), mult);
+ const uint8_t b = multiply(dither_hi(ba), mult);
+ rgba4444[2 * i + rg_byte_pos] = (r & 0xf0) | ((g >> 4) & 0x0f);
+ rgba4444[2 * i + (rg_byte_pos ^ 1)] = (b & 0xf0) | a;
+ }
+ rgba4444 += stride;
+ }
+}
+#undef MULTIPLIER
+
+static void ApplyAlphaMultiply_16b(uint8_t* rgba4444,
+ int w, int h, int stride) {
+#ifdef WEBP_SWAP_16BIT_CSP
+ ApplyAlphaMultiply4444(rgba4444, w, h, stride, 1);
+#else
+ ApplyAlphaMultiply4444(rgba4444, w, h, stride, 0);
+#endif
+}
+
+static int DispatchAlpha(const uint8_t* alpha, int alpha_stride,
+ int width, int height,
+ uint8_t* dst, int dst_stride) {
+ uint32_t alpha_mask = 0xff;
+ int i, j;
+
+ for (j = 0; j < height; ++j) {
+ for (i = 0; i < width; ++i) {
+ const uint32_t alpha_value = alpha[i];
+ dst[4 * i] = alpha_value;
+ alpha_mask &= alpha_value;
+ }
+ alpha += alpha_stride;
+ dst += dst_stride;
+ }
+
+ return (alpha_mask != 0xff);
+}
+
+static void DispatchAlphaToGreen(const uint8_t* alpha, int alpha_stride,
+ int width, int height,
+ uint32_t* dst, int dst_stride) {
+ int i, j;
+ for (j = 0; j < height; ++j) {
+ for (i = 0; i < width; ++i) {
+ dst[i] = alpha[i] << 8; // leave A/R/B channels zero'd.
+ }
+ alpha += alpha_stride;
+ dst += dst_stride;
+ }
+}
+
+static int ExtractAlpha(const uint8_t* argb, int argb_stride,
+ int width, int height,
+ uint8_t* alpha, int alpha_stride) {
+ uint8_t alpha_mask = 0xff;
+ int i, j;
+
+ for (j = 0; j < height; ++j) {
+ for (i = 0; i < width; ++i) {
+ const uint8_t alpha_value = argb[4 * i];
+ alpha[i] = alpha_value;
+ alpha_mask &= alpha_value;
+ }
+ argb += argb_stride;
+ alpha += alpha_stride;
+ }
+ return (alpha_mask == 0xff);
+}
+
+void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int);
+void (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int);
+int (*WebPDispatchAlpha)(const uint8_t*, int, int, int, uint8_t*, int);
+void (*WebPDispatchAlphaToGreen)(const uint8_t*, int, int, int, uint32_t*, int);
+int (*WebPExtractAlpha)(const uint8_t*, int, int, int, uint8_t*, int);
+
+//------------------------------------------------------------------------------
+// Init function
+
+extern void WebPInitAlphaProcessingMIPSdspR2(void);
+extern void WebPInitAlphaProcessingSSE2(void);
+extern void WebPInitAlphaProcessingSSE41(void);
+
+static volatile VP8CPUInfo alpha_processing_last_cpuinfo_used =
+ (VP8CPUInfo)&alpha_processing_last_cpuinfo_used;
+
+WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessing(void) {
+ if (alpha_processing_last_cpuinfo_used == VP8GetCPUInfo) return;
+
+ WebPMultARGBRow = WebPMultARGBRowC;
+ WebPMultRow = WebPMultRowC;
+ WebPApplyAlphaMultiply = ApplyAlphaMultiply;
+ WebPApplyAlphaMultiply4444 = ApplyAlphaMultiply_16b;
+ WebPDispatchAlpha = DispatchAlpha;
+ WebPDispatchAlphaToGreen = DispatchAlphaToGreen;
+ WebPExtractAlpha = ExtractAlpha;
+
+ // If defined, use CPUInfo() to overwrite some pointers with faster versions.
+ if (VP8GetCPUInfo != NULL) {
+#if defined(WEBP_USE_SSE2)
+ if (VP8GetCPUInfo(kSSE2)) {
+ WebPInitAlphaProcessingSSE2();
+#if defined(WEBP_USE_SSE41)
+ if (VP8GetCPUInfo(kSSE4_1)) {
+ WebPInitAlphaProcessingSSE41();
+ }
+#endif
+ }
+#endif
+#if defined(WEBP_USE_MIPS_DSP_R2)
+ if (VP8GetCPUInfo(kMIPSdspR2)) {
+ WebPInitAlphaProcessingMIPSdspR2();
+ }
+#endif
+ }
+ alpha_processing_last_cpuinfo_used = VP8GetCPUInfo;
+}
diff --git a/drivers/webp/dsp/alpha_processing_mips_dsp_r2.c b/drivers/webp/dsp/alpha_processing_mips_dsp_r2.c
new file mode 100644
index 0000000000..c631d78905
--- /dev/null
+++ b/drivers/webp/dsp/alpha_processing_mips_dsp_r2.c
@@ -0,0 +1,141 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Utilities for processing transparent channel.
+//
+// Author(s): Branimir Vasic (branimir.vasic@imgtec.com)
+// Djordje Pesut (djordje.pesut@imgtec.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_MIPS_DSP_R2)
+
+static int DispatchAlpha(const uint8_t* alpha, int alpha_stride,
+ int width, int height,
+ uint8_t* dst, int dst_stride) {
+ uint32_t alpha_mask = 0xffffffff;
+ int i, j, temp0;
+
+ for (j = 0; j < height; ++j) {
+ uint8_t* pdst = dst;
+ const uint8_t* palpha = alpha;
+ for (i = 0; i < (width >> 2); ++i) {
+ int temp1, temp2, temp3;
+
+ __asm__ volatile (
+ "ulw %[temp0], 0(%[palpha]) \n\t"
+ "addiu %[palpha], %[palpha], 4 \n\t"
+ "addiu %[pdst], %[pdst], 16 \n\t"
+ "srl %[temp1], %[temp0], 8 \n\t"
+ "srl %[temp2], %[temp0], 16 \n\t"
+ "srl %[temp3], %[temp0], 24 \n\t"
+ "and %[alpha_mask], %[alpha_mask], %[temp0] \n\t"
+ "sb %[temp0], -16(%[pdst]) \n\t"
+ "sb %[temp1], -12(%[pdst]) \n\t"
+ "sb %[temp2], -8(%[pdst]) \n\t"
+ "sb %[temp3], -4(%[pdst]) \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [palpha]"+r"(palpha), [pdst]"+r"(pdst),
+ [alpha_mask]"+r"(alpha_mask)
+ :
+ : "memory"
+ );
+ }
+
+ for (i = 0; i < (width & 3); ++i) {
+ __asm__ volatile (
+ "lbu %[temp0], 0(%[palpha]) \n\t"
+ "addiu %[palpha], %[palpha], 1 \n\t"
+ "sb %[temp0], 0(%[pdst]) \n\t"
+ "and %[alpha_mask], %[alpha_mask], %[temp0] \n\t"
+ "addiu %[pdst], %[pdst], 4 \n\t"
+ : [temp0]"=&r"(temp0), [palpha]"+r"(palpha), [pdst]"+r"(pdst),
+ [alpha_mask]"+r"(alpha_mask)
+ :
+ : "memory"
+ );
+ }
+ alpha += alpha_stride;
+ dst += dst_stride;
+ }
+
+ __asm__ volatile (
+ "ext %[temp0], %[alpha_mask], 0, 16 \n\t"
+ "srl %[alpha_mask], %[alpha_mask], 16 \n\t"
+ "and %[alpha_mask], %[alpha_mask], %[temp0] \n\t"
+ "ext %[temp0], %[alpha_mask], 0, 8 \n\t"
+ "srl %[alpha_mask], %[alpha_mask], 8 \n\t"
+ "and %[alpha_mask], %[alpha_mask], %[temp0] \n\t"
+ : [temp0]"=&r"(temp0), [alpha_mask]"+r"(alpha_mask)
+ :
+ );
+
+ return (alpha_mask != 0xff);
+}
+
+static void MultARGBRow(uint32_t* const ptr, int width, int inverse) {
+ int x;
+ const uint32_t c_00ffffff = 0x00ffffffu;
+ const uint32_t c_ff000000 = 0xff000000u;
+ const uint32_t c_8000000 = 0x00800000u;
+ const uint32_t c_8000080 = 0x00800080u;
+ for (x = 0; x < width; ++x) {
+ const uint32_t argb = ptr[x];
+ if (argb < 0xff000000u) { // alpha < 255
+ if (argb <= 0x00ffffffu) { // alpha == 0
+ ptr[x] = 0;
+ } else {
+ int temp0, temp1, temp2, temp3, alpha;
+ __asm__ volatile (
+ "srl %[alpha], %[argb], 24 \n\t"
+ "replv.qb %[temp0], %[alpha] \n\t"
+ "and %[temp0], %[temp0], %[c_00ffffff] \n\t"
+ "beqz %[inverse], 0f \n\t"
+ "divu $zero, %[c_ff000000], %[alpha] \n\t"
+ "mflo %[temp0] \n\t"
+ "0: \n\t"
+ "andi %[temp1], %[argb], 0xff \n\t"
+ "ext %[temp2], %[argb], 8, 8 \n\t"
+ "ext %[temp3], %[argb], 16, 8 \n\t"
+ "mul %[temp1], %[temp1], %[temp0] \n\t"
+ "mul %[temp2], %[temp2], %[temp0] \n\t"
+ "mul %[temp3], %[temp3], %[temp0] \n\t"
+ "precrq.ph.w %[temp1], %[temp2], %[temp1] \n\t"
+ "addu %[temp3], %[temp3], %[c_8000000] \n\t"
+ "addu %[temp1], %[temp1], %[c_8000080] \n\t"
+ "precrq.ph.w %[temp3], %[argb], %[temp3] \n\t"
+ "precrq.qb.ph %[temp1], %[temp3], %[temp1] \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [alpha]"=&r"(alpha)
+ : [inverse]"r"(inverse), [c_00ffffff]"r"(c_00ffffff),
+ [c_8000000]"r"(c_8000000), [c_8000080]"r"(c_8000080),
+ [c_ff000000]"r"(c_ff000000), [argb]"r"(argb)
+ : "memory", "hi", "lo"
+ );
+ ptr[x] = temp1;
+ }
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void WebPInitAlphaProcessingMIPSdspR2(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessingMIPSdspR2(void) {
+ WebPDispatchAlpha = DispatchAlpha;
+ WebPMultARGBRow = MultARGBRow;
+}
+
+#else // !WEBP_USE_MIPS_DSP_R2
+
+WEBP_DSP_INIT_STUB(WebPInitAlphaProcessingMIPSdspR2)
+
+#endif // WEBP_USE_MIPS_DSP_R2
diff --git a/drivers/webp/dsp/alpha_processing_sse2.c b/drivers/webp/dsp/alpha_processing_sse2.c
new file mode 100644
index 0000000000..5acb481dcd
--- /dev/null
+++ b/drivers/webp/dsp/alpha_processing_sse2.c
@@ -0,0 +1,298 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Utilities for processing transparent channel.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_SSE2)
+#include <emmintrin.h>
+
+//------------------------------------------------------------------------------
+
+static int DispatchAlpha(const uint8_t* alpha, int alpha_stride,
+ int width, int height,
+ uint8_t* dst, int dst_stride) {
+ // alpha_and stores an 'and' operation of all the alpha[] values. The final
+ // value is not 0xff if any of the alpha[] is not equal to 0xff.
+ uint32_t alpha_and = 0xff;
+ int i, j;
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i rgb_mask = _mm_set1_epi32(0xffffff00u); // to preserve RGB
+ const __m128i all_0xff = _mm_set_epi32(0, 0, ~0u, ~0u);
+ __m128i all_alphas = all_0xff;
+
+ // We must be able to access 3 extra bytes after the last written byte
+ // 'dst[4 * width - 4]', because we don't know if alpha is the first or the
+ // last byte of the quadruplet.
+ const int limit = (width - 1) & ~7;
+
+ for (j = 0; j < height; ++j) {
+ __m128i* out = (__m128i*)dst;
+ for (i = 0; i < limit; i += 8) {
+ // load 8 alpha bytes
+ const __m128i a0 = _mm_loadl_epi64((const __m128i*)&alpha[i]);
+ const __m128i a1 = _mm_unpacklo_epi8(a0, zero);
+ const __m128i a2_lo = _mm_unpacklo_epi16(a1, zero);
+ const __m128i a2_hi = _mm_unpackhi_epi16(a1, zero);
+ // load 8 dst pixels (32 bytes)
+ const __m128i b0_lo = _mm_loadu_si128(out + 0);
+ const __m128i b0_hi = _mm_loadu_si128(out + 1);
+ // mask dst alpha values
+ const __m128i b1_lo = _mm_and_si128(b0_lo, rgb_mask);
+ const __m128i b1_hi = _mm_and_si128(b0_hi, rgb_mask);
+ // combine
+ const __m128i b2_lo = _mm_or_si128(b1_lo, a2_lo);
+ const __m128i b2_hi = _mm_or_si128(b1_hi, a2_hi);
+ // store
+ _mm_storeu_si128(out + 0, b2_lo);
+ _mm_storeu_si128(out + 1, b2_hi);
+ // accumulate eight alpha 'and' in parallel
+ all_alphas = _mm_and_si128(all_alphas, a0);
+ out += 2;
+ }
+ for (; i < width; ++i) {
+ const uint32_t alpha_value = alpha[i];
+ dst[4 * i] = alpha_value;
+ alpha_and &= alpha_value;
+ }
+ alpha += alpha_stride;
+ dst += dst_stride;
+ }
+ // Combine the eight alpha 'and' into a 8-bit mask.
+ alpha_and &= _mm_movemask_epi8(_mm_cmpeq_epi8(all_alphas, all_0xff));
+ return (alpha_and != 0xff);
+}
+
+static void DispatchAlphaToGreen(const uint8_t* alpha, int alpha_stride,
+ int width, int height,
+ uint32_t* dst, int dst_stride) {
+ int i, j;
+ const __m128i zero = _mm_setzero_si128();
+ const int limit = width & ~15;
+ for (j = 0; j < height; ++j) {
+ for (i = 0; i < limit; i += 16) { // process 16 alpha bytes
+ const __m128i a0 = _mm_loadu_si128((const __m128i*)&alpha[i]);
+ const __m128i a1 = _mm_unpacklo_epi8(zero, a0); // note the 'zero' first!
+ const __m128i b1 = _mm_unpackhi_epi8(zero, a0);
+ const __m128i a2_lo = _mm_unpacklo_epi16(a1, zero);
+ const __m128i b2_lo = _mm_unpacklo_epi16(b1, zero);
+ const __m128i a2_hi = _mm_unpackhi_epi16(a1, zero);
+ const __m128i b2_hi = _mm_unpackhi_epi16(b1, zero);
+ _mm_storeu_si128((__m128i*)&dst[i + 0], a2_lo);
+ _mm_storeu_si128((__m128i*)&dst[i + 4], a2_hi);
+ _mm_storeu_si128((__m128i*)&dst[i + 8], b2_lo);
+ _mm_storeu_si128((__m128i*)&dst[i + 12], b2_hi);
+ }
+ for (; i < width; ++i) dst[i] = alpha[i] << 8;
+ alpha += alpha_stride;
+ dst += dst_stride;
+ }
+}
+
+static int ExtractAlpha(const uint8_t* argb, int argb_stride,
+ int width, int height,
+ uint8_t* alpha, int alpha_stride) {
+ // alpha_and stores an 'and' operation of all the alpha[] values. The final
+ // value is not 0xff if any of the alpha[] is not equal to 0xff.
+ uint32_t alpha_and = 0xff;
+ int i, j;
+ const __m128i a_mask = _mm_set1_epi32(0xffu); // to preserve alpha
+ const __m128i all_0xff = _mm_set_epi32(0, 0, ~0u, ~0u);
+ __m128i all_alphas = all_0xff;
+
+ // We must be able to access 3 extra bytes after the last written byte
+ // 'src[4 * width - 4]', because we don't know if alpha is the first or the
+ // last byte of the quadruplet.
+ const int limit = (width - 1) & ~7;
+
+ for (j = 0; j < height; ++j) {
+ const __m128i* src = (const __m128i*)argb;
+ for (i = 0; i < limit; i += 8) {
+ // load 32 argb bytes
+ const __m128i a0 = _mm_loadu_si128(src + 0);
+ const __m128i a1 = _mm_loadu_si128(src + 1);
+ const __m128i b0 = _mm_and_si128(a0, a_mask);
+ const __m128i b1 = _mm_and_si128(a1, a_mask);
+ const __m128i c0 = _mm_packs_epi32(b0, b1);
+ const __m128i d0 = _mm_packus_epi16(c0, c0);
+ // store
+ _mm_storel_epi64((__m128i*)&alpha[i], d0);
+ // accumulate eight alpha 'and' in parallel
+ all_alphas = _mm_and_si128(all_alphas, d0);
+ src += 2;
+ }
+ for (; i < width; ++i) {
+ const uint32_t alpha_value = argb[4 * i];
+ alpha[i] = alpha_value;
+ alpha_and &= alpha_value;
+ }
+ argb += argb_stride;
+ alpha += alpha_stride;
+ }
+ // Combine the eight alpha 'and' into a 8-bit mask.
+ alpha_and &= _mm_movemask_epi8(_mm_cmpeq_epi8(all_alphas, all_0xff));
+ return (alpha_and == 0xff);
+}
+
+//------------------------------------------------------------------------------
+// Non-dither premultiplied modes
+
+#define MULTIPLIER(a) ((a) * 0x8081)
+#define PREMULTIPLY(x, m) (((x) * (m)) >> 23)
+
+// We can't use a 'const int' for the SHUFFLE value, because it has to be an
+// immediate in the _mm_shufflexx_epi16() instruction. We really a macro here.
+#define APPLY_ALPHA(RGBX, SHUFFLE, MASK, MULT) do { \
+ const __m128i argb0 = _mm_loadl_epi64((__m128i*)&(RGBX)); \
+ const __m128i argb1 = _mm_unpacklo_epi8(argb0, zero); \
+ const __m128i alpha0 = _mm_and_si128(argb1, MASK); \
+ const __m128i alpha1 = _mm_shufflelo_epi16(alpha0, SHUFFLE); \
+ const __m128i alpha2 = _mm_shufflehi_epi16(alpha1, SHUFFLE); \
+ /* alpha2 = [0 a0 a0 a0][0 a1 a1 a1] */ \
+ const __m128i scale0 = _mm_mullo_epi16(alpha2, MULT); \
+ const __m128i scale1 = _mm_mulhi_epu16(alpha2, MULT); \
+ const __m128i argb2 = _mm_mulhi_epu16(argb1, scale0); \
+ const __m128i argb3 = _mm_mullo_epi16(argb1, scale1); \
+ const __m128i argb4 = _mm_adds_epu16(argb2, argb3); \
+ const __m128i argb5 = _mm_srli_epi16(argb4, 7); \
+ const __m128i argb6 = _mm_or_si128(argb5, alpha0); \
+ const __m128i argb7 = _mm_packus_epi16(argb6, zero); \
+ _mm_storel_epi64((__m128i*)&(RGBX), argb7); \
+} while (0)
+
+static void ApplyAlphaMultiply(uint8_t* rgba, int alpha_first,
+ int w, int h, int stride) {
+ const __m128i zero = _mm_setzero_si128();
+ const int kSpan = 2;
+ const int w2 = w & ~(kSpan - 1);
+ while (h-- > 0) {
+ uint32_t* const rgbx = (uint32_t*)rgba;
+ int i;
+ if (!alpha_first) {
+ const __m128i kMask = _mm_set_epi16(0xff, 0, 0, 0, 0xff, 0, 0, 0);
+ const __m128i kMult =
+ _mm_set_epi16(0, 0x8081, 0x8081, 0x8081, 0, 0x8081, 0x8081, 0x8081);
+ for (i = 0; i < w2; i += kSpan) {
+ APPLY_ALPHA(rgbx[i], _MM_SHUFFLE(0, 3, 3, 3), kMask, kMult);
+ }
+ } else {
+ const __m128i kMask = _mm_set_epi16(0, 0, 0, 0xff, 0, 0, 0, 0xff);
+ const __m128i kMult =
+ _mm_set_epi16(0x8081, 0x8081, 0x8081, 0, 0x8081, 0x8081, 0x8081, 0);
+ for (i = 0; i < w2; i += kSpan) {
+ APPLY_ALPHA(rgbx[i], _MM_SHUFFLE(0, 0, 0, 3), kMask, kMult);
+ }
+ }
+ // Finish with left-overs.
+ for (; i < w; ++i) {
+ uint8_t* const rgb = rgba + (alpha_first ? 1 : 0);
+ const uint8_t* const alpha = rgba + (alpha_first ? 0 : 3);
+ const uint32_t a = alpha[4 * i];
+ if (a != 0xff) {
+ const uint32_t mult = MULTIPLIER(a);
+ rgb[4 * i + 0] = PREMULTIPLY(rgb[4 * i + 0], mult);
+ rgb[4 * i + 1] = PREMULTIPLY(rgb[4 * i + 1], mult);
+ rgb[4 * i + 2] = PREMULTIPLY(rgb[4 * i + 2], mult);
+ }
+ }
+ rgba += stride;
+ }
+}
+#undef MULTIPLIER
+#undef PREMULTIPLY
+
+// -----------------------------------------------------------------------------
+// Apply alpha value to rows
+
+// We use: kINV255 = (1 << 24) / 255 = 0x010101
+// So: a * kINV255 = (a << 16) | [(a << 8) | a]
+// -> _mm_mulhi_epu16() takes care of the (a<<16) part,
+// and _mm_mullo_epu16(a * 0x0101,...) takes care of the "(a << 8) | a" one.
+
+static void MultARGBRow(uint32_t* const ptr, int width, int inverse) {
+ int x = 0;
+ if (!inverse) {
+ const int kSpan = 2;
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i kRound =
+ _mm_set_epi16(0, 1 << 7, 1 << 7, 1 << 7, 0, 1 << 7, 1 << 7, 1 << 7);
+ const __m128i kMult =
+ _mm_set_epi16(0, 0x0101, 0x0101, 0x0101, 0, 0x0101, 0x0101, 0x0101);
+ const __m128i kOne64 = _mm_set_epi16(1u << 8, 0, 0, 0, 1u << 8, 0, 0, 0);
+ const int w2 = width & ~(kSpan - 1);
+ for (x = 0; x < w2; x += kSpan) {
+ const __m128i argb0 = _mm_loadl_epi64((__m128i*)&ptr[x]);
+ const __m128i argb1 = _mm_unpacklo_epi8(argb0, zero);
+ const __m128i tmp0 = _mm_shufflelo_epi16(argb1, _MM_SHUFFLE(3, 3, 3, 3));
+ const __m128i tmp1 = _mm_shufflehi_epi16(tmp0, _MM_SHUFFLE(3, 3, 3, 3));
+ const __m128i tmp2 = _mm_srli_epi64(tmp1, 16);
+ const __m128i scale0 = _mm_mullo_epi16(tmp1, kMult);
+ const __m128i scale1 = _mm_or_si128(tmp2, kOne64);
+ const __m128i argb2 = _mm_mulhi_epu16(argb1, scale0);
+ const __m128i argb3 = _mm_mullo_epi16(argb1, scale1);
+ const __m128i argb4 = _mm_adds_epu16(argb2, argb3);
+ const __m128i argb5 = _mm_adds_epu16(argb4, kRound);
+ const __m128i argb6 = _mm_srli_epi16(argb5, 8);
+ const __m128i argb7 = _mm_packus_epi16(argb6, zero);
+ _mm_storel_epi64((__m128i*)&ptr[x], argb7);
+ }
+ }
+ width -= x;
+ if (width > 0) WebPMultARGBRowC(ptr + x, width, inverse);
+}
+
+static void MultRow(uint8_t* const ptr, const uint8_t* const alpha,
+ int width, int inverse) {
+ int x = 0;
+ if (!inverse) {
+ const int kSpan = 8;
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i kRound = _mm_set1_epi16(1 << 7);
+ const int w2 = width & ~(kSpan - 1);
+ for (x = 0; x < w2; x += kSpan) {
+ const __m128i v0 = _mm_loadl_epi64((__m128i*)&ptr[x]);
+ const __m128i v1 = _mm_unpacklo_epi8(v0, zero);
+ const __m128i alpha0 = _mm_loadl_epi64((const __m128i*)&alpha[x]);
+ const __m128i alpha1 = _mm_unpacklo_epi8(alpha0, zero);
+ const __m128i alpha2 = _mm_unpacklo_epi8(alpha0, alpha0);
+ const __m128i v2 = _mm_mulhi_epu16(v1, alpha2);
+ const __m128i v3 = _mm_mullo_epi16(v1, alpha1);
+ const __m128i v4 = _mm_adds_epu16(v2, v3);
+ const __m128i v5 = _mm_adds_epu16(v4, kRound);
+ const __m128i v6 = _mm_srli_epi16(v5, 8);
+ const __m128i v7 = _mm_packus_epi16(v6, zero);
+ _mm_storel_epi64((__m128i*)&ptr[x], v7);
+ }
+ }
+ width -= x;
+ if (width > 0) WebPMultRowC(ptr + x, alpha + x, width, inverse);
+}
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void WebPInitAlphaProcessingSSE2(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessingSSE2(void) {
+ WebPMultARGBRow = MultARGBRow;
+ WebPMultRow = MultRow;
+ WebPApplyAlphaMultiply = ApplyAlphaMultiply;
+ WebPDispatchAlpha = DispatchAlpha;
+ WebPDispatchAlphaToGreen = DispatchAlphaToGreen;
+ WebPExtractAlpha = ExtractAlpha;
+}
+
+#else // !WEBP_USE_SSE2
+
+WEBP_DSP_INIT_STUB(WebPInitAlphaProcessingSSE2)
+
+#endif // WEBP_USE_SSE2
diff --git a/drivers/webp/dsp/alpha_processing_sse41.c b/drivers/webp/dsp/alpha_processing_sse41.c
new file mode 100644
index 0000000000..986fde94ed
--- /dev/null
+++ b/drivers/webp/dsp/alpha_processing_sse41.c
@@ -0,0 +1,92 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Utilities for processing transparent channel, SSE4.1 variant.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_SSE41)
+
+#include <smmintrin.h>
+
+//------------------------------------------------------------------------------
+
+static int ExtractAlpha(const uint8_t* argb, int argb_stride,
+ int width, int height,
+ uint8_t* alpha, int alpha_stride) {
+ // alpha_and stores an 'and' operation of all the alpha[] values. The final
+ // value is not 0xff if any of the alpha[] is not equal to 0xff.
+ uint32_t alpha_and = 0xff;
+ int i, j;
+ const __m128i all_0xff = _mm_set1_epi32(~0u);
+ __m128i all_alphas = all_0xff;
+
+ // We must be able to access 3 extra bytes after the last written byte
+ // 'src[4 * width - 4]', because we don't know if alpha is the first or the
+ // last byte of the quadruplet.
+ const int limit = (width - 1) & ~15;
+ const __m128i kCstAlpha0 = _mm_set_epi8(-1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 12, 8, 4, 0);
+ const __m128i kCstAlpha1 = _mm_set_epi8(-1, -1, -1, -1, -1, -1, -1, -1,
+ 12, 8, 4, 0, -1, -1, -1, -1);
+ const __m128i kCstAlpha2 = _mm_set_epi8(-1, -1, -1, -1, 12, 8, 4, 0,
+ -1, -1, -1, -1, -1, -1, -1, -1);
+ const __m128i kCstAlpha3 = _mm_set_epi8(12, 8, 4, 0, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1);
+ for (j = 0; j < height; ++j) {
+ const __m128i* src = (const __m128i*)argb;
+ for (i = 0; i < limit; i += 16) {
+ // load 64 argb bytes
+ const __m128i a0 = _mm_loadu_si128(src + 0);
+ const __m128i a1 = _mm_loadu_si128(src + 1);
+ const __m128i a2 = _mm_loadu_si128(src + 2);
+ const __m128i a3 = _mm_loadu_si128(src + 3);
+ const __m128i b0 = _mm_shuffle_epi8(a0, kCstAlpha0);
+ const __m128i b1 = _mm_shuffle_epi8(a1, kCstAlpha1);
+ const __m128i b2 = _mm_shuffle_epi8(a2, kCstAlpha2);
+ const __m128i b3 = _mm_shuffle_epi8(a3, kCstAlpha3);
+ const __m128i c0 = _mm_or_si128(b0, b1);
+ const __m128i c1 = _mm_or_si128(b2, b3);
+ const __m128i d0 = _mm_or_si128(c0, c1);
+ // store
+ _mm_storeu_si128((__m128i*)&alpha[i], d0);
+ // accumulate sixteen alpha 'and' in parallel
+ all_alphas = _mm_and_si128(all_alphas, d0);
+ src += 4;
+ }
+ for (; i < width; ++i) {
+ const uint32_t alpha_value = argb[4 * i];
+ alpha[i] = alpha_value;
+ alpha_and &= alpha_value;
+ }
+ argb += argb_stride;
+ alpha += alpha_stride;
+ }
+ // Combine the sixteen alpha 'and' into an 8-bit mask.
+ alpha_and |= 0xff00u; // pretend the upper bits [8..15] were tested ok.
+ alpha_and &= _mm_movemask_epi8(_mm_cmpeq_epi8(all_alphas, all_0xff));
+ return (alpha_and == 0xffffu);
+}
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void WebPInitAlphaProcessingSSE41(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void WebPInitAlphaProcessingSSE41(void) {
+ WebPExtractAlpha = ExtractAlpha;
+}
+
+#else // !WEBP_USE_SSE41
+
+WEBP_DSP_INIT_STUB(WebPInitAlphaProcessingSSE41)
+
+#endif // WEBP_USE_SSE41
diff --git a/drivers/webp/dsp/argb.c b/drivers/webp/dsp/argb.c
new file mode 100644
index 0000000000..cc1f9a96c3
--- /dev/null
+++ b/drivers/webp/dsp/argb.c
@@ -0,0 +1,68 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// ARGB making functions.
+//
+// Author: Djordje Pesut (djordje.pesut@imgtec.com)
+
+#include "./dsp.h"
+
+static WEBP_INLINE uint32_t MakeARGB32(int a, int r, int g, int b) {
+ return (((uint32_t)a << 24) | (r << 16) | (g << 8) | b);
+}
+
+static void PackARGB(const uint8_t* a, const uint8_t* r, const uint8_t* g,
+ const uint8_t* b, int len, uint32_t* out) {
+ int i;
+ for (i = 0; i < len; ++i) {
+ out[i] = MakeARGB32(a[4 * i], r[4 * i], g[4 * i], b[4 * i]);
+ }
+}
+
+static void PackRGB(const uint8_t* r, const uint8_t* g, const uint8_t* b,
+ int len, int step, uint32_t* out) {
+ int i, offset = 0;
+ for (i = 0; i < len; ++i) {
+ out[i] = MakeARGB32(0xff, r[offset], g[offset], b[offset]);
+ offset += step;
+ }
+}
+
+void (*VP8PackARGB)(const uint8_t*, const uint8_t*, const uint8_t*,
+ const uint8_t*, int, uint32_t*);
+void (*VP8PackRGB)(const uint8_t*, const uint8_t*, const uint8_t*,
+ int, int, uint32_t*);
+
+extern void VP8EncDspARGBInitMIPSdspR2(void);
+extern void VP8EncDspARGBInitSSE2(void);
+
+static volatile VP8CPUInfo argb_last_cpuinfo_used =
+ (VP8CPUInfo)&argb_last_cpuinfo_used;
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspARGBInit(void) {
+ if (argb_last_cpuinfo_used == VP8GetCPUInfo) return;
+
+ VP8PackARGB = PackARGB;
+ VP8PackRGB = PackRGB;
+
+ // If defined, use CPUInfo() to overwrite some pointers with faster versions.
+ if (VP8GetCPUInfo != NULL) {
+#if defined(WEBP_USE_SSE2)
+ if (VP8GetCPUInfo(kSSE2)) {
+ VP8EncDspARGBInitSSE2();
+ }
+#endif
+#if defined(WEBP_USE_MIPS_DSP_R2)
+ if (VP8GetCPUInfo(kMIPSdspR2)) {
+ VP8EncDspARGBInitMIPSdspR2();
+ }
+#endif
+ }
+ argb_last_cpuinfo_used = VP8GetCPUInfo;
+}
diff --git a/drivers/webp/dsp/argb_mips_dsp_r2.c b/drivers/webp/dsp/argb_mips_dsp_r2.c
new file mode 100644
index 0000000000..af65acb8ff
--- /dev/null
+++ b/drivers/webp/dsp/argb_mips_dsp_r2.c
@@ -0,0 +1,110 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// ARGB making functions (mips version).
+//
+// Author: Djordje Pesut (djordje.pesut@imgtec.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_MIPS_DSP_R2)
+
+static void PackARGB(const uint8_t* a, const uint8_t* r, const uint8_t* g,
+ const uint8_t* b, int len, uint32_t* out) {
+ int temp0, temp1, temp2, temp3, offset;
+ const int rest = len & 1;
+ const uint32_t* const loop_end = out + len - rest;
+ const int step = 4;
+ __asm__ volatile (
+ "xor %[offset], %[offset], %[offset] \n\t"
+ "beq %[loop_end], %[out], 0f \n\t"
+ "2: \n\t"
+ "lbux %[temp0], %[offset](%[a]) \n\t"
+ "lbux %[temp1], %[offset](%[r]) \n\t"
+ "lbux %[temp2], %[offset](%[g]) \n\t"
+ "lbux %[temp3], %[offset](%[b]) \n\t"
+ "ins %[temp1], %[temp0], 16, 16 \n\t"
+ "ins %[temp3], %[temp2], 16, 16 \n\t"
+ "addiu %[out], %[out], 4 \n\t"
+ "precr.qb.ph %[temp0], %[temp1], %[temp3] \n\t"
+ "sw %[temp0], -4(%[out]) \n\t"
+ "addu %[offset], %[offset], %[step] \n\t"
+ "bne %[loop_end], %[out], 2b \n\t"
+ "0: \n\t"
+ "beq %[rest], $zero, 1f \n\t"
+ "lbux %[temp0], %[offset](%[a]) \n\t"
+ "lbux %[temp1], %[offset](%[r]) \n\t"
+ "lbux %[temp2], %[offset](%[g]) \n\t"
+ "lbux %[temp3], %[offset](%[b]) \n\t"
+ "ins %[temp1], %[temp0], 16, 16 \n\t"
+ "ins %[temp3], %[temp2], 16, 16 \n\t"
+ "precr.qb.ph %[temp0], %[temp1], %[temp3] \n\t"
+ "sw %[temp0], 0(%[out]) \n\t"
+ "1: \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [offset]"=&r"(offset), [out]"+&r"(out)
+ : [a]"r"(a), [r]"r"(r), [g]"r"(g), [b]"r"(b), [step]"r"(step),
+ [loop_end]"r"(loop_end), [rest]"r"(rest)
+ : "memory"
+ );
+}
+
+static void PackRGB(const uint8_t* r, const uint8_t* g, const uint8_t* b,
+ int len, int step, uint32_t* out) {
+ int temp0, temp1, temp2, offset;
+ const int rest = len & 1;
+ const int a = 0xff;
+ const uint32_t* const loop_end = out + len - rest;
+ __asm__ volatile (
+ "xor %[offset], %[offset], %[offset] \n\t"
+ "beq %[loop_end], %[out], 0f \n\t"
+ "2: \n\t"
+ "lbux %[temp0], %[offset](%[r]) \n\t"
+ "lbux %[temp1], %[offset](%[g]) \n\t"
+ "lbux %[temp2], %[offset](%[b]) \n\t"
+ "ins %[temp0], %[a], 16, 16 \n\t"
+ "ins %[temp2], %[temp1], 16, 16 \n\t"
+ "addiu %[out], %[out], 4 \n\t"
+ "precr.qb.ph %[temp0], %[temp0], %[temp2] \n\t"
+ "sw %[temp0], -4(%[out]) \n\t"
+ "addu %[offset], %[offset], %[step] \n\t"
+ "bne %[loop_end], %[out], 2b \n\t"
+ "0: \n\t"
+ "beq %[rest], $zero, 1f \n\t"
+ "lbux %[temp0], %[offset](%[r]) \n\t"
+ "lbux %[temp1], %[offset](%[g]) \n\t"
+ "lbux %[temp2], %[offset](%[b]) \n\t"
+ "ins %[temp0], %[a], 16, 16 \n\t"
+ "ins %[temp2], %[temp1], 16, 16 \n\t"
+ "precr.qb.ph %[temp0], %[temp0], %[temp2] \n\t"
+ "sw %[temp0], 0(%[out]) \n\t"
+ "1: \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [offset]"=&r"(offset), [out]"+&r"(out)
+ : [a]"r"(a), [r]"r"(r), [g]"r"(g), [b]"r"(b), [step]"r"(step),
+ [loop_end]"r"(loop_end), [rest]"r"(rest)
+ : "memory"
+ );
+}
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8EncDspARGBInitMIPSdspR2(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspARGBInitMIPSdspR2(void) {
+ VP8PackARGB = PackARGB;
+ VP8PackRGB = PackRGB;
+}
+
+#else // !WEBP_USE_MIPS_DSP_R2
+
+WEBP_DSP_INIT_STUB(VP8EncDspARGBInitMIPSdspR2)
+
+#endif // WEBP_USE_MIPS_DSP_R2
diff --git a/drivers/webp/dsp/argb_sse2.c b/drivers/webp/dsp/argb_sse2.c
new file mode 100644
index 0000000000..afcb1957e7
--- /dev/null
+++ b/drivers/webp/dsp/argb_sse2.c
@@ -0,0 +1,67 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// ARGB making functions (SSE2 version).
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_SSE2)
+
+#include <assert.h>
+#include <emmintrin.h>
+#include <string.h>
+
+static WEBP_INLINE uint32_t MakeARGB32(int a, int r, int g, int b) {
+ return (((uint32_t)a << 24) | (r << 16) | (g << 8) | b);
+}
+
+static void PackARGB(const uint8_t* a, const uint8_t* r, const uint8_t* g,
+ const uint8_t* b, int len, uint32_t* out) {
+ if (g == r + 1) { // RGBA input order. Need to swap R and B.
+ int i = 0;
+ const int len_max = len & ~3; // max length processed in main loop
+ const __m128i red_blue_mask = _mm_set1_epi32(0x00ff00ffu);
+ assert(b == r + 2);
+ assert(a == r + 3);
+ for (; i < len_max; i += 4) {
+ const __m128i A = _mm_loadu_si128((const __m128i*)(r + 4 * i));
+ const __m128i B = _mm_and_si128(A, red_blue_mask); // R 0 B 0
+ const __m128i C = _mm_andnot_si128(red_blue_mask, A); // 0 G 0 A
+ const __m128i D = _mm_shufflelo_epi16(B, _MM_SHUFFLE(2, 3, 0, 1));
+ const __m128i E = _mm_shufflehi_epi16(D, _MM_SHUFFLE(2, 3, 0, 1));
+ const __m128i F = _mm_or_si128(E, C);
+ _mm_storeu_si128((__m128i*)(out + i), F);
+ }
+ for (; i < len; ++i) {
+ out[i] = MakeARGB32(a[4 * i], r[4 * i], g[4 * i], b[4 * i]);
+ }
+ } else {
+ assert(g == b + 1);
+ assert(r == b + 2);
+ assert(a == b + 3);
+ memcpy(out, b, len * 4);
+ }
+}
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8EncDspARGBInitSSE2(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspARGBInitSSE2(void) {
+ VP8PackARGB = PackARGB;
+}
+
+#else // !WEBP_USE_SSE2
+
+WEBP_DSP_INIT_STUB(VP8EncDspARGBInitSSE2)
+
+#endif // WEBP_USE_SSE2
diff --git a/drivers/webp/dsp/cost.c b/drivers/webp/dsp/cost.c
new file mode 100644
index 0000000000..fe72d26e79
--- /dev/null
+++ b/drivers/webp/dsp/cost.c
@@ -0,0 +1,412 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./dsp.h"
+#include "../enc/cost.h"
+
+//------------------------------------------------------------------------------
+// Boolean-cost cost table
+
+const uint16_t VP8EntropyCost[256] = {
+ 1792, 1792, 1792, 1536, 1536, 1408, 1366, 1280, 1280, 1216,
+ 1178, 1152, 1110, 1076, 1061, 1024, 1024, 992, 968, 951,
+ 939, 911, 896, 878, 871, 854, 838, 820, 811, 794,
+ 786, 768, 768, 752, 740, 732, 720, 709, 704, 690,
+ 683, 672, 666, 655, 647, 640, 631, 622, 615, 607,
+ 598, 592, 586, 576, 572, 564, 559, 555, 547, 541,
+ 534, 528, 522, 512, 512, 504, 500, 494, 488, 483,
+ 477, 473, 467, 461, 458, 452, 448, 443, 438, 434,
+ 427, 424, 419, 415, 410, 406, 403, 399, 394, 390,
+ 384, 384, 377, 374, 370, 366, 362, 359, 355, 351,
+ 347, 342, 342, 336, 333, 330, 326, 323, 320, 316,
+ 312, 308, 305, 302, 299, 296, 293, 288, 287, 283,
+ 280, 277, 274, 272, 268, 266, 262, 256, 256, 256,
+ 251, 248, 245, 242, 240, 237, 234, 232, 228, 226,
+ 223, 221, 218, 216, 214, 211, 208, 205, 203, 201,
+ 198, 196, 192, 191, 188, 187, 183, 181, 179, 176,
+ 175, 171, 171, 168, 165, 163, 160, 159, 156, 154,
+ 152, 150, 148, 146, 144, 142, 139, 138, 135, 133,
+ 131, 128, 128, 125, 123, 121, 119, 117, 115, 113,
+ 111, 110, 107, 105, 103, 102, 100, 98, 96, 94,
+ 92, 91, 89, 86, 86, 83, 82, 80, 77, 76,
+ 74, 73, 71, 69, 67, 66, 64, 63, 61, 59,
+ 57, 55, 54, 52, 51, 49, 47, 46, 44, 43,
+ 41, 40, 38, 36, 35, 33, 32, 30, 29, 27,
+ 25, 24, 22, 21, 19, 18, 16, 15, 13, 12,
+ 10, 9, 7, 6, 4, 3
+};
+
+//------------------------------------------------------------------------------
+// Level cost tables
+
+// fixed costs for coding levels, deduce from the coding tree.
+// This is only the part that doesn't depend on the probability state.
+const uint16_t VP8LevelFixedCosts[MAX_LEVEL + 1] = {
+ 0, 256, 256, 256, 256, 432, 618, 630,
+ 731, 640, 640, 828, 901, 948, 1021, 1101,
+ 1174, 1221, 1294, 1042, 1085, 1115, 1158, 1202,
+ 1245, 1275, 1318, 1337, 1380, 1410, 1453, 1497,
+ 1540, 1570, 1613, 1280, 1295, 1317, 1332, 1358,
+ 1373, 1395, 1410, 1454, 1469, 1491, 1506, 1532,
+ 1547, 1569, 1584, 1601, 1616, 1638, 1653, 1679,
+ 1694, 1716, 1731, 1775, 1790, 1812, 1827, 1853,
+ 1868, 1890, 1905, 1727, 1733, 1742, 1748, 1759,
+ 1765, 1774, 1780, 1800, 1806, 1815, 1821, 1832,
+ 1838, 1847, 1853, 1878, 1884, 1893, 1899, 1910,
+ 1916, 1925, 1931, 1951, 1957, 1966, 1972, 1983,
+ 1989, 1998, 2004, 2027, 2033, 2042, 2048, 2059,
+ 2065, 2074, 2080, 2100, 2106, 2115, 2121, 2132,
+ 2138, 2147, 2153, 2178, 2184, 2193, 2199, 2210,
+ 2216, 2225, 2231, 2251, 2257, 2266, 2272, 2283,
+ 2289, 2298, 2304, 2168, 2174, 2183, 2189, 2200,
+ 2206, 2215, 2221, 2241, 2247, 2256, 2262, 2273,
+ 2279, 2288, 2294, 2319, 2325, 2334, 2340, 2351,
+ 2357, 2366, 2372, 2392, 2398, 2407, 2413, 2424,
+ 2430, 2439, 2445, 2468, 2474, 2483, 2489, 2500,
+ 2506, 2515, 2521, 2541, 2547, 2556, 2562, 2573,
+ 2579, 2588, 2594, 2619, 2625, 2634, 2640, 2651,
+ 2657, 2666, 2672, 2692, 2698, 2707, 2713, 2724,
+ 2730, 2739, 2745, 2540, 2546, 2555, 2561, 2572,
+ 2578, 2587, 2593, 2613, 2619, 2628, 2634, 2645,
+ 2651, 2660, 2666, 2691, 2697, 2706, 2712, 2723,
+ 2729, 2738, 2744, 2764, 2770, 2779, 2785, 2796,
+ 2802, 2811, 2817, 2840, 2846, 2855, 2861, 2872,
+ 2878, 2887, 2893, 2913, 2919, 2928, 2934, 2945,
+ 2951, 2960, 2966, 2991, 2997, 3006, 3012, 3023,
+ 3029, 3038, 3044, 3064, 3070, 3079, 3085, 3096,
+ 3102, 3111, 3117, 2981, 2987, 2996, 3002, 3013,
+ 3019, 3028, 3034, 3054, 3060, 3069, 3075, 3086,
+ 3092, 3101, 3107, 3132, 3138, 3147, 3153, 3164,
+ 3170, 3179, 3185, 3205, 3211, 3220, 3226, 3237,
+ 3243, 3252, 3258, 3281, 3287, 3296, 3302, 3313,
+ 3319, 3328, 3334, 3354, 3360, 3369, 3375, 3386,
+ 3392, 3401, 3407, 3432, 3438, 3447, 3453, 3464,
+ 3470, 3479, 3485, 3505, 3511, 3520, 3526, 3537,
+ 3543, 3552, 3558, 2816, 2822, 2831, 2837, 2848,
+ 2854, 2863, 2869, 2889, 2895, 2904, 2910, 2921,
+ 2927, 2936, 2942, 2967, 2973, 2982, 2988, 2999,
+ 3005, 3014, 3020, 3040, 3046, 3055, 3061, 3072,
+ 3078, 3087, 3093, 3116, 3122, 3131, 3137, 3148,
+ 3154, 3163, 3169, 3189, 3195, 3204, 3210, 3221,
+ 3227, 3236, 3242, 3267, 3273, 3282, 3288, 3299,
+ 3305, 3314, 3320, 3340, 3346, 3355, 3361, 3372,
+ 3378, 3387, 3393, 3257, 3263, 3272, 3278, 3289,
+ 3295, 3304, 3310, 3330, 3336, 3345, 3351, 3362,
+ 3368, 3377, 3383, 3408, 3414, 3423, 3429, 3440,
+ 3446, 3455, 3461, 3481, 3487, 3496, 3502, 3513,
+ 3519, 3528, 3534, 3557, 3563, 3572, 3578, 3589,
+ 3595, 3604, 3610, 3630, 3636, 3645, 3651, 3662,
+ 3668, 3677, 3683, 3708, 3714, 3723, 3729, 3740,
+ 3746, 3755, 3761, 3781, 3787, 3796, 3802, 3813,
+ 3819, 3828, 3834, 3629, 3635, 3644, 3650, 3661,
+ 3667, 3676, 3682, 3702, 3708, 3717, 3723, 3734,
+ 3740, 3749, 3755, 3780, 3786, 3795, 3801, 3812,
+ 3818, 3827, 3833, 3853, 3859, 3868, 3874, 3885,
+ 3891, 3900, 3906, 3929, 3935, 3944, 3950, 3961,
+ 3967, 3976, 3982, 4002, 4008, 4017, 4023, 4034,
+ 4040, 4049, 4055, 4080, 4086, 4095, 4101, 4112,
+ 4118, 4127, 4133, 4153, 4159, 4168, 4174, 4185,
+ 4191, 4200, 4206, 4070, 4076, 4085, 4091, 4102,
+ 4108, 4117, 4123, 4143, 4149, 4158, 4164, 4175,
+ 4181, 4190, 4196, 4221, 4227, 4236, 4242, 4253,
+ 4259, 4268, 4274, 4294, 4300, 4309, 4315, 4326,
+ 4332, 4341, 4347, 4370, 4376, 4385, 4391, 4402,
+ 4408, 4417, 4423, 4443, 4449, 4458, 4464, 4475,
+ 4481, 4490, 4496, 4521, 4527, 4536, 4542, 4553,
+ 4559, 4568, 4574, 4594, 4600, 4609, 4615, 4626,
+ 4632, 4641, 4647, 3515, 3521, 3530, 3536, 3547,
+ 3553, 3562, 3568, 3588, 3594, 3603, 3609, 3620,
+ 3626, 3635, 3641, 3666, 3672, 3681, 3687, 3698,
+ 3704, 3713, 3719, 3739, 3745, 3754, 3760, 3771,
+ 3777, 3786, 3792, 3815, 3821, 3830, 3836, 3847,
+ 3853, 3862, 3868, 3888, 3894, 3903, 3909, 3920,
+ 3926, 3935, 3941, 3966, 3972, 3981, 3987, 3998,
+ 4004, 4013, 4019, 4039, 4045, 4054, 4060, 4071,
+ 4077, 4086, 4092, 3956, 3962, 3971, 3977, 3988,
+ 3994, 4003, 4009, 4029, 4035, 4044, 4050, 4061,
+ 4067, 4076, 4082, 4107, 4113, 4122, 4128, 4139,
+ 4145, 4154, 4160, 4180, 4186, 4195, 4201, 4212,
+ 4218, 4227, 4233, 4256, 4262, 4271, 4277, 4288,
+ 4294, 4303, 4309, 4329, 4335, 4344, 4350, 4361,
+ 4367, 4376, 4382, 4407, 4413, 4422, 4428, 4439,
+ 4445, 4454, 4460, 4480, 4486, 4495, 4501, 4512,
+ 4518, 4527, 4533, 4328, 4334, 4343, 4349, 4360,
+ 4366, 4375, 4381, 4401, 4407, 4416, 4422, 4433,
+ 4439, 4448, 4454, 4479, 4485, 4494, 4500, 4511,
+ 4517, 4526, 4532, 4552, 4558, 4567, 4573, 4584,
+ 4590, 4599, 4605, 4628, 4634, 4643, 4649, 4660,
+ 4666, 4675, 4681, 4701, 4707, 4716, 4722, 4733,
+ 4739, 4748, 4754, 4779, 4785, 4794, 4800, 4811,
+ 4817, 4826, 4832, 4852, 4858, 4867, 4873, 4884,
+ 4890, 4899, 4905, 4769, 4775, 4784, 4790, 4801,
+ 4807, 4816, 4822, 4842, 4848, 4857, 4863, 4874,
+ 4880, 4889, 4895, 4920, 4926, 4935, 4941, 4952,
+ 4958, 4967, 4973, 4993, 4999, 5008, 5014, 5025,
+ 5031, 5040, 5046, 5069, 5075, 5084, 5090, 5101,
+ 5107, 5116, 5122, 5142, 5148, 5157, 5163, 5174,
+ 5180, 5189, 5195, 5220, 5226, 5235, 5241, 5252,
+ 5258, 5267, 5273, 5293, 5299, 5308, 5314, 5325,
+ 5331, 5340, 5346, 4604, 4610, 4619, 4625, 4636,
+ 4642, 4651, 4657, 4677, 4683, 4692, 4698, 4709,
+ 4715, 4724, 4730, 4755, 4761, 4770, 4776, 4787,
+ 4793, 4802, 4808, 4828, 4834, 4843, 4849, 4860,
+ 4866, 4875, 4881, 4904, 4910, 4919, 4925, 4936,
+ 4942, 4951, 4957, 4977, 4983, 4992, 4998, 5009,
+ 5015, 5024, 5030, 5055, 5061, 5070, 5076, 5087,
+ 5093, 5102, 5108, 5128, 5134, 5143, 5149, 5160,
+ 5166, 5175, 5181, 5045, 5051, 5060, 5066, 5077,
+ 5083, 5092, 5098, 5118, 5124, 5133, 5139, 5150,
+ 5156, 5165, 5171, 5196, 5202, 5211, 5217, 5228,
+ 5234, 5243, 5249, 5269, 5275, 5284, 5290, 5301,
+ 5307, 5316, 5322, 5345, 5351, 5360, 5366, 5377,
+ 5383, 5392, 5398, 5418, 5424, 5433, 5439, 5450,
+ 5456, 5465, 5471, 5496, 5502, 5511, 5517, 5528,
+ 5534, 5543, 5549, 5569, 5575, 5584, 5590, 5601,
+ 5607, 5616, 5622, 5417, 5423, 5432, 5438, 5449,
+ 5455, 5464, 5470, 5490, 5496, 5505, 5511, 5522,
+ 5528, 5537, 5543, 5568, 5574, 5583, 5589, 5600,
+ 5606, 5615, 5621, 5641, 5647, 5656, 5662, 5673,
+ 5679, 5688, 5694, 5717, 5723, 5732, 5738, 5749,
+ 5755, 5764, 5770, 5790, 5796, 5805, 5811, 5822,
+ 5828, 5837, 5843, 5868, 5874, 5883, 5889, 5900,
+ 5906, 5915, 5921, 5941, 5947, 5956, 5962, 5973,
+ 5979, 5988, 5994, 5858, 5864, 5873, 5879, 5890,
+ 5896, 5905, 5911, 5931, 5937, 5946, 5952, 5963,
+ 5969, 5978, 5984, 6009, 6015, 6024, 6030, 6041,
+ 6047, 6056, 6062, 6082, 6088, 6097, 6103, 6114,
+ 6120, 6129, 6135, 6158, 6164, 6173, 6179, 6190,
+ 6196, 6205, 6211, 6231, 6237, 6246, 6252, 6263,
+ 6269, 6278, 6284, 6309, 6315, 6324, 6330, 6341,
+ 6347, 6356, 6362, 6382, 6388, 6397, 6403, 6414,
+ 6420, 6429, 6435, 3515, 3521, 3530, 3536, 3547,
+ 3553, 3562, 3568, 3588, 3594, 3603, 3609, 3620,
+ 3626, 3635, 3641, 3666, 3672, 3681, 3687, 3698,
+ 3704, 3713, 3719, 3739, 3745, 3754, 3760, 3771,
+ 3777, 3786, 3792, 3815, 3821, 3830, 3836, 3847,
+ 3853, 3862, 3868, 3888, 3894, 3903, 3909, 3920,
+ 3926, 3935, 3941, 3966, 3972, 3981, 3987, 3998,
+ 4004, 4013, 4019, 4039, 4045, 4054, 4060, 4071,
+ 4077, 4086, 4092, 3956, 3962, 3971, 3977, 3988,
+ 3994, 4003, 4009, 4029, 4035, 4044, 4050, 4061,
+ 4067, 4076, 4082, 4107, 4113, 4122, 4128, 4139,
+ 4145, 4154, 4160, 4180, 4186, 4195, 4201, 4212,
+ 4218, 4227, 4233, 4256, 4262, 4271, 4277, 4288,
+ 4294, 4303, 4309, 4329, 4335, 4344, 4350, 4361,
+ 4367, 4376, 4382, 4407, 4413, 4422, 4428, 4439,
+ 4445, 4454, 4460, 4480, 4486, 4495, 4501, 4512,
+ 4518, 4527, 4533, 4328, 4334, 4343, 4349, 4360,
+ 4366, 4375, 4381, 4401, 4407, 4416, 4422, 4433,
+ 4439, 4448, 4454, 4479, 4485, 4494, 4500, 4511,
+ 4517, 4526, 4532, 4552, 4558, 4567, 4573, 4584,
+ 4590, 4599, 4605, 4628, 4634, 4643, 4649, 4660,
+ 4666, 4675, 4681, 4701, 4707, 4716, 4722, 4733,
+ 4739, 4748, 4754, 4779, 4785, 4794, 4800, 4811,
+ 4817, 4826, 4832, 4852, 4858, 4867, 4873, 4884,
+ 4890, 4899, 4905, 4769, 4775, 4784, 4790, 4801,
+ 4807, 4816, 4822, 4842, 4848, 4857, 4863, 4874,
+ 4880, 4889, 4895, 4920, 4926, 4935, 4941, 4952,
+ 4958, 4967, 4973, 4993, 4999, 5008, 5014, 5025,
+ 5031, 5040, 5046, 5069, 5075, 5084, 5090, 5101,
+ 5107, 5116, 5122, 5142, 5148, 5157, 5163, 5174,
+ 5180, 5189, 5195, 5220, 5226, 5235, 5241, 5252,
+ 5258, 5267, 5273, 5293, 5299, 5308, 5314, 5325,
+ 5331, 5340, 5346, 4604, 4610, 4619, 4625, 4636,
+ 4642, 4651, 4657, 4677, 4683, 4692, 4698, 4709,
+ 4715, 4724, 4730, 4755, 4761, 4770, 4776, 4787,
+ 4793, 4802, 4808, 4828, 4834, 4843, 4849, 4860,
+ 4866, 4875, 4881, 4904, 4910, 4919, 4925, 4936,
+ 4942, 4951, 4957, 4977, 4983, 4992, 4998, 5009,
+ 5015, 5024, 5030, 5055, 5061, 5070, 5076, 5087,
+ 5093, 5102, 5108, 5128, 5134, 5143, 5149, 5160,
+ 5166, 5175, 5181, 5045, 5051, 5060, 5066, 5077,
+ 5083, 5092, 5098, 5118, 5124, 5133, 5139, 5150,
+ 5156, 5165, 5171, 5196, 5202, 5211, 5217, 5228,
+ 5234, 5243, 5249, 5269, 5275, 5284, 5290, 5301,
+ 5307, 5316, 5322, 5345, 5351, 5360, 5366, 5377,
+ 5383, 5392, 5398, 5418, 5424, 5433, 5439, 5450,
+ 5456, 5465, 5471, 5496, 5502, 5511, 5517, 5528,
+ 5534, 5543, 5549, 5569, 5575, 5584, 5590, 5601,
+ 5607, 5616, 5622, 5417, 5423, 5432, 5438, 5449,
+ 5455, 5464, 5470, 5490, 5496, 5505, 5511, 5522,
+ 5528, 5537, 5543, 5568, 5574, 5583, 5589, 5600,
+ 5606, 5615, 5621, 5641, 5647, 5656, 5662, 5673,
+ 5679, 5688, 5694, 5717, 5723, 5732, 5738, 5749,
+ 5755, 5764, 5770, 5790, 5796, 5805, 5811, 5822,
+ 5828, 5837, 5843, 5868, 5874, 5883, 5889, 5900,
+ 5906, 5915, 5921, 5941, 5947, 5956, 5962, 5973,
+ 5979, 5988, 5994, 5858, 5864, 5873, 5879, 5890,
+ 5896, 5905, 5911, 5931, 5937, 5946, 5952, 5963,
+ 5969, 5978, 5984, 6009, 6015, 6024, 6030, 6041,
+ 6047, 6056, 6062, 6082, 6088, 6097, 6103, 6114,
+ 6120, 6129, 6135, 6158, 6164, 6173, 6179, 6190,
+ 6196, 6205, 6211, 6231, 6237, 6246, 6252, 6263,
+ 6269, 6278, 6284, 6309, 6315, 6324, 6330, 6341,
+ 6347, 6356, 6362, 6382, 6388, 6397, 6403, 6414,
+ 6420, 6429, 6435, 5303, 5309, 5318, 5324, 5335,
+ 5341, 5350, 5356, 5376, 5382, 5391, 5397, 5408,
+ 5414, 5423, 5429, 5454, 5460, 5469, 5475, 5486,
+ 5492, 5501, 5507, 5527, 5533, 5542, 5548, 5559,
+ 5565, 5574, 5580, 5603, 5609, 5618, 5624, 5635,
+ 5641, 5650, 5656, 5676, 5682, 5691, 5697, 5708,
+ 5714, 5723, 5729, 5754, 5760, 5769, 5775, 5786,
+ 5792, 5801, 5807, 5827, 5833, 5842, 5848, 5859,
+ 5865, 5874, 5880, 5744, 5750, 5759, 5765, 5776,
+ 5782, 5791, 5797, 5817, 5823, 5832, 5838, 5849,
+ 5855, 5864, 5870, 5895, 5901, 5910, 5916, 5927,
+ 5933, 5942, 5948, 5968, 5974, 5983, 5989, 6000,
+ 6006, 6015, 6021, 6044, 6050, 6059, 6065, 6076,
+ 6082, 6091, 6097, 6117, 6123, 6132, 6138, 6149,
+ 6155, 6164, 6170, 6195, 6201, 6210, 6216, 6227,
+ 6233, 6242, 6248, 6268, 6274, 6283, 6289, 6300,
+ 6306, 6315, 6321, 6116, 6122, 6131, 6137, 6148,
+ 6154, 6163, 6169, 6189, 6195, 6204, 6210, 6221,
+ 6227, 6236, 6242, 6267, 6273, 6282, 6288, 6299,
+ 6305, 6314, 6320, 6340, 6346, 6355, 6361, 6372,
+ 6378, 6387, 6393, 6416, 6422, 6431, 6437, 6448,
+ 6454, 6463, 6469, 6489, 6495, 6504, 6510, 6521,
+ 6527, 6536, 6542, 6567, 6573, 6582, 6588, 6599,
+ 6605, 6614, 6620, 6640, 6646, 6655, 6661, 6672,
+ 6678, 6687, 6693, 6557, 6563, 6572, 6578, 6589,
+ 6595, 6604, 6610, 6630, 6636, 6645, 6651, 6662,
+ 6668, 6677, 6683, 6708, 6714, 6723, 6729, 6740,
+ 6746, 6755, 6761, 6781, 6787, 6796, 6802, 6813,
+ 6819, 6828, 6834, 6857, 6863, 6872, 6878, 6889,
+ 6895, 6904, 6910, 6930, 6936, 6945, 6951, 6962,
+ 6968, 6977, 6983, 7008, 7014, 7023, 7029, 7040,
+ 7046, 7055, 7061, 7081, 7087, 7096, 7102, 7113,
+ 7119, 7128, 7134, 6392, 6398, 6407, 6413, 6424,
+ 6430, 6439, 6445, 6465, 6471, 6480, 6486, 6497,
+ 6503, 6512, 6518, 6543, 6549, 6558, 6564, 6575,
+ 6581, 6590, 6596, 6616, 6622, 6631, 6637, 6648,
+ 6654, 6663, 6669, 6692, 6698, 6707, 6713, 6724,
+ 6730, 6739, 6745, 6765, 6771, 6780, 6786, 6797,
+ 6803, 6812, 6818, 6843, 6849, 6858, 6864, 6875,
+ 6881, 6890, 6896, 6916, 6922, 6931, 6937, 6948,
+ 6954, 6963, 6969, 6833, 6839, 6848, 6854, 6865,
+ 6871, 6880, 6886, 6906, 6912, 6921, 6927, 6938,
+ 6944, 6953, 6959, 6984, 6990, 6999, 7005, 7016,
+ 7022, 7031, 7037, 7057, 7063, 7072, 7078, 7089,
+ 7095, 7104, 7110, 7133, 7139, 7148, 7154, 7165,
+ 7171, 7180, 7186, 7206, 7212, 7221, 7227, 7238,
+ 7244, 7253, 7259, 7284, 7290, 7299, 7305, 7316,
+ 7322, 7331, 7337, 7357, 7363, 7372, 7378, 7389,
+ 7395, 7404, 7410, 7205, 7211, 7220, 7226, 7237,
+ 7243, 7252, 7258, 7278, 7284, 7293, 7299, 7310,
+ 7316, 7325, 7331, 7356, 7362, 7371, 7377, 7388,
+ 7394, 7403, 7409, 7429, 7435, 7444, 7450, 7461,
+ 7467, 7476, 7482, 7505, 7511, 7520, 7526, 7537,
+ 7543, 7552, 7558, 7578, 7584, 7593, 7599, 7610,
+ 7616, 7625, 7631, 7656, 7662, 7671, 7677, 7688,
+ 7694, 7703, 7709, 7729, 7735, 7744, 7750, 7761
+};
+
+//------------------------------------------------------------------------------
+// Tables for level coding
+
+const uint8_t VP8EncBands[16 + 1] = {
+ 0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7,
+ 0 // sentinel
+};
+
+//------------------------------------------------------------------------------
+// Mode costs
+
+static int GetResidualCost(int ctx0, const VP8Residual* const res) {
+ int n = res->first;
+ // should be prob[VP8EncBands[n]], but it's equivalent for n=0 or 1
+ const int p0 = res->prob[n][ctx0][0];
+ CostArrayPtr const costs = res->costs;
+ const uint16_t* t = costs[n][ctx0];
+ // bit_cost(1, p0) is already incorporated in t[] tables, but only if ctx != 0
+ // (as required by the syntax). For ctx0 == 0, we need to add it here or it'll
+ // be missing during the loop.
+ int cost = (ctx0 == 0) ? VP8BitCost(1, p0) : 0;
+
+ if (res->last < 0) {
+ return VP8BitCost(0, p0);
+ }
+ for (; n < res->last; ++n) {
+ const int v = abs(res->coeffs[n]);
+ const int ctx = (v >= 2) ? 2 : v;
+ cost += VP8LevelCost(t, v);
+ t = costs[n + 1][ctx];
+ }
+ // Last coefficient is always non-zero
+ {
+ const int v = abs(res->coeffs[n]);
+ assert(v != 0);
+ cost += VP8LevelCost(t, v);
+ if (n < 15) {
+ const int b = VP8EncBands[n + 1];
+ const int ctx = (v == 1) ? 1 : 2;
+ const int last_p0 = res->prob[b][ctx][0];
+ cost += VP8BitCost(0, last_p0);
+ }
+ }
+ return cost;
+}
+
+static void SetResidualCoeffs(const int16_t* const coeffs,
+ VP8Residual* const res) {
+ int n;
+ res->last = -1;
+ assert(res->first == 0 || coeffs[0] == 0);
+ for (n = 15; n >= 0; --n) {
+ if (coeffs[n]) {
+ res->last = n;
+ break;
+ }
+ }
+ res->coeffs = coeffs;
+}
+
+//------------------------------------------------------------------------------
+// init function
+
+VP8GetResidualCostFunc VP8GetResidualCost;
+VP8SetResidualCoeffsFunc VP8SetResidualCoeffs;
+
+extern void VP8EncDspCostInitMIPS32(void);
+extern void VP8EncDspCostInitMIPSdspR2(void);
+extern void VP8EncDspCostInitSSE2(void);
+
+static volatile VP8CPUInfo cost_last_cpuinfo_used =
+ (VP8CPUInfo)&cost_last_cpuinfo_used;
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspCostInit(void) {
+ if (cost_last_cpuinfo_used == VP8GetCPUInfo) return;
+
+ VP8GetResidualCost = GetResidualCost;
+ VP8SetResidualCoeffs = SetResidualCoeffs;
+
+ // If defined, use CPUInfo() to overwrite some pointers with faster versions.
+ if (VP8GetCPUInfo != NULL) {
+#if defined(WEBP_USE_MIPS32)
+ if (VP8GetCPUInfo(kMIPS32)) {
+ VP8EncDspCostInitMIPS32();
+ }
+#endif
+#if defined(WEBP_USE_MIPS_DSP_R2)
+ if (VP8GetCPUInfo(kMIPSdspR2)) {
+ VP8EncDspCostInitMIPSdspR2();
+ }
+#endif
+#if defined(WEBP_USE_SSE2)
+ if (VP8GetCPUInfo(kSSE2)) {
+ VP8EncDspCostInitSSE2();
+ }
+#endif
+ }
+
+ cost_last_cpuinfo_used = VP8GetCPUInfo;
+}
+
+//------------------------------------------------------------------------------
diff --git a/drivers/webp/dsp/cost_mips32.c b/drivers/webp/dsp/cost_mips32.c
new file mode 100644
index 0000000000..d1e240e191
--- /dev/null
+++ b/drivers/webp/dsp/cost_mips32.c
@@ -0,0 +1,154 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Author: Djordje Pesut (djordje.pesut@imgtec.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_MIPS32)
+
+#include "../enc/cost.h"
+
+static int GetResidualCost(int ctx0, const VP8Residual* const res) {
+ int temp0, temp1;
+ int v_reg, ctx_reg;
+ int n = res->first;
+ // should be prob[VP8EncBands[n]], but it's equivalent for n=0 or 1
+ int p0 = res->prob[n][ctx0][0];
+ CostArrayPtr const costs = res->costs;
+ const uint16_t* t = costs[n][ctx0];
+ // bit_cost(1, p0) is already incorporated in t[] tables, but only if ctx != 0
+ // (as required by the syntax). For ctx0 == 0, we need to add it here or it'll
+ // be missing during the loop.
+ int cost = (ctx0 == 0) ? VP8BitCost(1, p0) : 0;
+ const int16_t* res_coeffs = res->coeffs;
+ const int res_last = res->last;
+ const int const_max_level = MAX_VARIABLE_LEVEL;
+ const int const_2 = 2;
+ const uint16_t** p_costs = &costs[n][0];
+ const size_t inc_p_costs = NUM_CTX * sizeof(*p_costs);
+
+ if (res->last < 0) {
+ return VP8BitCost(0, p0);
+ }
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "subu %[temp1], %[res_last], %[n] \n\t"
+ "sll %[temp0], %[n], 1 \n\t"
+ "blez %[temp1], 2f \n\t"
+ " addu %[res_coeffs], %[res_coeffs], %[temp0] \n\t"
+ "1: \n\t"
+ "lh %[v_reg], 0(%[res_coeffs]) \n\t"
+ "addiu %[n], %[n], 1 \n\t"
+ "negu %[temp0], %[v_reg] \n\t"
+ "slti %[temp1], %[v_reg], 0 \n\t"
+ "movn %[v_reg], %[temp0], %[temp1] \n\t"
+ "sltiu %[temp0], %[v_reg], 2 \n\t"
+ "move %[ctx_reg], %[v_reg] \n\t"
+ "movz %[ctx_reg], %[const_2], %[temp0] \n\t"
+ "sll %[temp1], %[v_reg], 1 \n\t"
+ "addu %[temp1], %[temp1], %[VP8LevelFixedCosts] \n\t"
+ "lhu %[temp1], 0(%[temp1]) \n\t"
+ "slt %[temp0], %[v_reg], %[const_max_level] \n\t"
+ "movz %[v_reg], %[const_max_level], %[temp0] \n\t"
+ "addu %[cost], %[cost], %[temp1] \n\t"
+ "sll %[v_reg], %[v_reg], 1 \n\t"
+ "sll %[ctx_reg], %[ctx_reg], 2 \n\t"
+ "addu %[v_reg], %[v_reg], %[t] \n\t"
+ "lhu %[temp0], 0(%[v_reg]) \n\t"
+ "addu %[p_costs], %[p_costs], %[inc_p_costs] \n\t"
+ "addu %[t], %[p_costs], %[ctx_reg] \n\t"
+ "addu %[cost], %[cost], %[temp0] \n\t"
+ "addiu %[res_coeffs], %[res_coeffs], 2 \n\t"
+ "bne %[n], %[res_last], 1b \n\t"
+ " lw %[t], 0(%[t]) \n\t"
+ "2: \n\t"
+ ".set pop \n\t"
+ : [cost]"+&r"(cost), [t]"+&r"(t), [n]"+&r"(n), [v_reg]"=&r"(v_reg),
+ [ctx_reg]"=&r"(ctx_reg), [p_costs]"+&r"(p_costs), [temp0]"=&r"(temp0),
+ [temp1]"=&r"(temp1), [res_coeffs]"+&r"(res_coeffs)
+ : [const_2]"r"(const_2), [const_max_level]"r"(const_max_level),
+ [VP8LevelFixedCosts]"r"(VP8LevelFixedCosts), [res_last]"r"(res_last),
+ [inc_p_costs]"r"(inc_p_costs)
+ : "memory"
+ );
+
+ // Last coefficient is always non-zero
+ {
+ const int v = abs(res->coeffs[n]);
+ assert(v != 0);
+ cost += VP8LevelCost(t, v);
+ if (n < 15) {
+ const int b = VP8EncBands[n + 1];
+ const int ctx = (v == 1) ? 1 : 2;
+ const int last_p0 = res->prob[b][ctx][0];
+ cost += VP8BitCost(0, last_p0);
+ }
+ }
+ return cost;
+}
+
+static void SetResidualCoeffs(const int16_t* const coeffs,
+ VP8Residual* const res) {
+ const int16_t* p_coeffs = (int16_t*)coeffs;
+ int temp0, temp1, temp2, n, n1;
+ assert(res->first == 0 || coeffs[0] == 0);
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "addiu %[p_coeffs], %[p_coeffs], 28 \n\t"
+ "li %[n], 15 \n\t"
+ "li %[temp2], -1 \n\t"
+ "0: \n\t"
+ "ulw %[temp0], 0(%[p_coeffs]) \n\t"
+ "beqz %[temp0], 1f \n\t"
+#if defined(WORDS_BIGENDIAN)
+ " sll %[temp1], %[temp0], 16 \n\t"
+#else
+ " srl %[temp1], %[temp0], 16 \n\t"
+#endif
+ "addiu %[n1], %[n], -1 \n\t"
+ "movz %[temp0], %[n1], %[temp1] \n\t"
+ "movn %[temp0], %[n], %[temp1] \n\t"
+ "j 2f \n\t"
+ " addiu %[temp2], %[temp0], 0 \n\t"
+ "1: \n\t"
+ "addiu %[n], %[n], -2 \n\t"
+ "bgtz %[n], 0b \n\t"
+ " addiu %[p_coeffs], %[p_coeffs], -4 \n\t"
+ "2: \n\t"
+ ".set pop \n\t"
+ : [p_coeffs]"+&r"(p_coeffs), [temp0]"=&r"(temp0),
+ [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [n]"=&r"(n), [n1]"=&r"(n1)
+ :
+ : "memory"
+ );
+ res->last = temp2;
+ res->coeffs = coeffs;
+}
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8EncDspCostInitMIPS32(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspCostInitMIPS32(void) {
+ VP8GetResidualCost = GetResidualCost;
+ VP8SetResidualCoeffs = SetResidualCoeffs;
+}
+
+#else // !WEBP_USE_MIPS32
+
+WEBP_DSP_INIT_STUB(VP8EncDspCostInitMIPS32)
+
+#endif // WEBP_USE_MIPS32
diff --git a/drivers/webp/dsp/cost_mips_dsp_r2.c b/drivers/webp/dsp/cost_mips_dsp_r2.c
new file mode 100644
index 0000000000..ce64067756
--- /dev/null
+++ b/drivers/webp/dsp/cost_mips_dsp_r2.c
@@ -0,0 +1,107 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Author: Djordje Pesut (djordje.pesut@imgtec.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_MIPS_DSP_R2)
+
+#include "../enc/cost.h"
+
+static int GetResidualCost(int ctx0, const VP8Residual* const res) {
+ int temp0, temp1;
+ int v_reg, ctx_reg;
+ int n = res->first;
+ // should be prob[VP8EncBands[n]], but it's equivalent for n=0 or 1
+ int p0 = res->prob[n][ctx0][0];
+ CostArrayPtr const costs = res->costs;
+ const uint16_t* t = costs[n][ctx0];
+ // bit_cost(1, p0) is already incorporated in t[] tables, but only if ctx != 0
+ // (as required by the syntax). For ctx0 == 0, we need to add it here or it'll
+ // be missing during the loop.
+ int cost = (ctx0 == 0) ? VP8BitCost(1, p0) : 0;
+ const int16_t* res_coeffs = res->coeffs;
+ const int res_last = res->last;
+ const int const_max_level = MAX_VARIABLE_LEVEL;
+ const int const_2 = 2;
+ const uint16_t** p_costs = &costs[n][0];
+ const size_t inc_p_costs = NUM_CTX * sizeof(*p_costs);
+
+ if (res->last < 0) {
+ return VP8BitCost(0, p0);
+ }
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "subu %[temp1], %[res_last], %[n] \n\t"
+ "blez %[temp1], 2f \n\t"
+ " nop \n\t"
+ "1: \n\t"
+ "sll %[temp0], %[n], 1 \n\t"
+ "lhx %[v_reg], %[temp0](%[res_coeffs]) \n\t"
+ "addiu %[n], %[n], 1 \n\t"
+ "absq_s.w %[v_reg], %[v_reg] \n\t"
+ "sltiu %[temp0], %[v_reg], 2 \n\t"
+ "move %[ctx_reg], %[v_reg] \n\t"
+ "movz %[ctx_reg], %[const_2], %[temp0] \n\t"
+ "sll %[temp1], %[v_reg], 1 \n\t"
+ "lhx %[temp1], %[temp1](%[VP8LevelFixedCosts]) \n\t"
+ "slt %[temp0], %[v_reg], %[const_max_level] \n\t"
+ "movz %[v_reg], %[const_max_level], %[temp0] \n\t"
+ "addu %[cost], %[cost], %[temp1] \n\t"
+ "sll %[v_reg], %[v_reg], 1 \n\t"
+ "sll %[ctx_reg], %[ctx_reg], 2 \n\t"
+ "lhx %[temp0], %[v_reg](%[t]) \n\t"
+ "addu %[p_costs], %[p_costs], %[inc_p_costs] \n\t"
+ "addu %[t], %[p_costs], %[ctx_reg] \n\t"
+ "addu %[cost], %[cost], %[temp0] \n\t"
+ "bne %[n], %[res_last], 1b \n\t"
+ " lw %[t], 0(%[t]) \n\t"
+ "2: \n\t"
+ ".set pop \n\t"
+ : [cost]"+&r"(cost), [t]"+&r"(t), [n]"+&r"(n), [v_reg]"=&r"(v_reg),
+ [ctx_reg]"=&r"(ctx_reg), [p_costs]"+&r"(p_costs), [temp0]"=&r"(temp0),
+ [temp1]"=&r"(temp1)
+ : [const_2]"r"(const_2), [const_max_level]"r"(const_max_level),
+ [VP8LevelFixedCosts]"r"(VP8LevelFixedCosts), [res_last]"r"(res_last),
+ [res_coeffs]"r"(res_coeffs), [inc_p_costs]"r"(inc_p_costs)
+ : "memory"
+ );
+
+ // Last coefficient is always non-zero
+ {
+ const int v = abs(res->coeffs[n]);
+ assert(v != 0);
+ cost += VP8LevelCost(t, v);
+ if (n < 15) {
+ const int b = VP8EncBands[n + 1];
+ const int ctx = (v == 1) ? 1 : 2;
+ const int last_p0 = res->prob[b][ctx][0];
+ cost += VP8BitCost(0, last_p0);
+ }
+ }
+ return cost;
+}
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8EncDspCostInitMIPSdspR2(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspCostInitMIPSdspR2(void) {
+ VP8GetResidualCost = GetResidualCost;
+}
+
+#else // !WEBP_USE_MIPS_DSP_R2
+
+WEBP_DSP_INIT_STUB(VP8EncDspCostInitMIPSdspR2)
+
+#endif // WEBP_USE_MIPS_DSP_R2
diff --git a/drivers/webp/dsp/cost_sse2.c b/drivers/webp/dsp/cost_sse2.c
new file mode 100644
index 0000000000..0cb1c1fa04
--- /dev/null
+++ b/drivers/webp/dsp/cost_sse2.c
@@ -0,0 +1,119 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// SSE2 version of cost functions
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_SSE2)
+#include <emmintrin.h>
+
+#include "../enc/cost.h"
+#include "../enc/vp8enci.h"
+#include "../utils/utils.h"
+
+//------------------------------------------------------------------------------
+
+static void SetResidualCoeffsSSE2(const int16_t* const coeffs,
+ VP8Residual* const res) {
+ const __m128i c0 = _mm_loadu_si128((const __m128i*)(coeffs + 0));
+ const __m128i c1 = _mm_loadu_si128((const __m128i*)(coeffs + 8));
+ // Use SSE2 to compare 16 values with a single instruction.
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i m0 = _mm_packs_epi16(c0, c1);
+ const __m128i m1 = _mm_cmpeq_epi8(m0, zero);
+ // Get the comparison results as a bitmask into 16bits. Negate the mask to get
+ // the position of entries that are not equal to zero. We don't need to mask
+ // out least significant bits according to res->first, since coeffs[0] is 0
+ // if res->first > 0.
+ const uint32_t mask = 0x0000ffffu ^ (uint32_t)_mm_movemask_epi8(m1);
+ // The position of the most significant non-zero bit indicates the position of
+ // the last non-zero value.
+ assert(res->first == 0 || coeffs[0] == 0);
+ res->last = mask ? BitsLog2Floor(mask) : -1;
+ res->coeffs = coeffs;
+}
+
+static int GetResidualCostSSE2(int ctx0, const VP8Residual* const res) {
+ uint8_t levels[16], ctxs[16];
+ uint16_t abs_levels[16];
+ int n = res->first;
+ // should be prob[VP8EncBands[n]], but it's equivalent for n=0 or 1
+ const int p0 = res->prob[n][ctx0][0];
+ CostArrayPtr const costs = res->costs;
+ const uint16_t* t = costs[n][ctx0];
+ // bit_cost(1, p0) is already incorporated in t[] tables, but only if ctx != 0
+ // (as required by the syntax). For ctx0 == 0, we need to add it here or it'll
+ // be missing during the loop.
+ int cost = (ctx0 == 0) ? VP8BitCost(1, p0) : 0;
+
+ if (res->last < 0) {
+ return VP8BitCost(0, p0);
+ }
+
+ { // precompute clamped levels and contexts, packed to 8b.
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i kCst2 = _mm_set1_epi8(2);
+ const __m128i kCst67 = _mm_set1_epi8(MAX_VARIABLE_LEVEL);
+ const __m128i c0 = _mm_loadu_si128((const __m128i*)&res->coeffs[0]);
+ const __m128i c1 = _mm_loadu_si128((const __m128i*)&res->coeffs[8]);
+ const __m128i D0 = _mm_sub_epi16(zero, c0);
+ const __m128i D1 = _mm_sub_epi16(zero, c1);
+ const __m128i E0 = _mm_max_epi16(c0, D0); // abs(v), 16b
+ const __m128i E1 = _mm_max_epi16(c1, D1);
+ const __m128i F = _mm_packs_epi16(E0, E1);
+ const __m128i G = _mm_min_epu8(F, kCst2); // context = 0,1,2
+ const __m128i H = _mm_min_epu8(F, kCst67); // clamp_level in [0..67]
+
+ _mm_storeu_si128((__m128i*)&ctxs[0], G);
+ _mm_storeu_si128((__m128i*)&levels[0], H);
+
+ _mm_storeu_si128((__m128i*)&abs_levels[0], E0);
+ _mm_storeu_si128((__m128i*)&abs_levels[8], E1);
+ }
+ for (; n < res->last; ++n) {
+ const int ctx = ctxs[n];
+ const int level = levels[n];
+ const int flevel = abs_levels[n]; // full level
+ cost += VP8LevelFixedCosts[flevel] + t[level]; // simplified VP8LevelCost()
+ t = costs[n + 1][ctx];
+ }
+ // Last coefficient is always non-zero
+ {
+ const int level = levels[n];
+ const int flevel = abs_levels[n];
+ assert(flevel != 0);
+ cost += VP8LevelFixedCosts[flevel] + t[level];
+ if (n < 15) {
+ const int b = VP8EncBands[n + 1];
+ const int ctx = ctxs[n];
+ const int last_p0 = res->prob[b][ctx][0];
+ cost += VP8BitCost(0, last_p0);
+ }
+ }
+ return cost;
+}
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8EncDspCostInitSSE2(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspCostInitSSE2(void) {
+ VP8SetResidualCoeffs = SetResidualCoeffsSSE2;
+ VP8GetResidualCost = GetResidualCostSSE2;
+}
+
+#else // !WEBP_USE_SSE2
+
+WEBP_DSP_INIT_STUB(VP8EncDspCostInitSSE2)
+
+#endif // WEBP_USE_SSE2
diff --git a/drivers/webp/dsp/cpu.c b/drivers/webp/dsp/cpu.c
index 0228734457..35c2af7f58 100644
--- a/drivers/webp/dsp/cpu.c
+++ b/drivers/webp/dsp/cpu.c
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// CPU detection
@@ -11,14 +13,10 @@
#include "./dsp.h"
-#if defined(__ANDROID__)
+#if defined(WEBP_ANDROID_NEON)
#include <cpu-features.h>
#endif
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
//------------------------------------------------------------------------------
// SSE2 detection.
//
@@ -31,22 +29,66 @@ static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) {
"cpuid\n"
"xchg %%edi, %%ebx\n"
: "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
- : "a"(info_type));
+ : "a"(info_type), "c"(0));
}
#elif defined(__i386__) || defined(__x86_64__)
static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) {
__asm__ volatile (
"cpuid\n"
: "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
- : "a"(info_type));
+ : "a"(info_type), "c"(0));
}
+#elif (defined(_M_X64) || defined(_M_IX86)) && \
+ defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 150030729 // >= VS2008 SP1
+#include <intrin.h>
+#define GetCPUInfo(info, type) __cpuidex(info, type, 0) // set ecx=0
#elif defined(WEBP_MSC_SSE2)
#define GetCPUInfo __cpuid
#endif
+// NaCl has no support for xgetbv or the raw opcode.
+#if !defined(__native_client__) && (defined(__i386__) || defined(__x86_64__))
+static WEBP_INLINE uint64_t xgetbv(void) {
+ const uint32_t ecx = 0;
+ uint32_t eax, edx;
+ // Use the raw opcode for xgetbv for compatibility with older toolchains.
+ __asm__ volatile (
+ ".byte 0x0f, 0x01, 0xd0\n"
+ : "=a"(eax), "=d"(edx) : "c" (ecx));
+ return ((uint64_t)edx << 32) | eax;
+}
+#elif (defined(_M_X64) || defined(_M_IX86)) && \
+ defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 160040219 // >= VS2010 SP1
+#include <immintrin.h>
+#define xgetbv() _xgetbv(0)
+#elif defined(_MSC_VER) && defined(_M_IX86)
+static WEBP_INLINE uint64_t xgetbv(void) {
+ uint32_t eax_, edx_;
+ __asm {
+ xor ecx, ecx // ecx = 0
+ // Use the raw opcode for xgetbv for compatibility with older toolchains.
+ __asm _emit 0x0f __asm _emit 0x01 __asm _emit 0xd0
+ mov eax_, eax
+ mov edx_, edx
+ }
+ return ((uint64_t)edx_ << 32) | eax_;
+}
+#else
+#define xgetbv() 0U // no AVX for older x64 or unrecognized toolchains.
+#endif
+
#if defined(__i386__) || defined(__x86_64__) || defined(WEBP_MSC_SSE2)
static int x86CPUInfo(CPUFeature feature) {
+ int max_cpuid_value;
int cpu_info[4];
+
+ // get the highest feature value cpuid supports
+ GetCPUInfo(cpu_info, 0);
+ max_cpuid_value = cpu_info[0];
+ if (max_cpuid_value < 1) {
+ return 0;
+ }
+
GetCPUInfo(cpu_info, 1);
if (feature == kSSE2) {
return 0 != (cpu_info[3] & 0x04000000);
@@ -54,10 +96,26 @@ static int x86CPUInfo(CPUFeature feature) {
if (feature == kSSE3) {
return 0 != (cpu_info[2] & 0x00000001);
}
+ if (feature == kSSE4_1) {
+ return 0 != (cpu_info[2] & 0x00080000);
+ }
+ if (feature == kAVX) {
+ // bits 27 (OSXSAVE) & 28 (256-bit AVX)
+ if ((cpu_info[2] & 0x18000000) == 0x18000000) {
+ // XMM state and YMM state enabled by the OS.
+ return (xgetbv() & 0x6) == 0x6;
+ }
+ }
+ if (feature == kAVX2) {
+ if (x86CPUInfo(kAVX) && max_cpuid_value >= 7) {
+ GetCPUInfo(cpu_info, 7);
+ return ((cpu_info[1] & 0x00000020) == 0x00000020);
+ }
+ }
return 0;
}
VP8CPUInfo VP8GetCPUInfo = x86CPUInfo;
-#elif defined(WEBP_ANDROID_NEON)
+#elif defined(WEBP_ANDROID_NEON) // NB: needs to be before generic NEON test.
static int AndroidCPUInfo(CPUFeature feature) {
const AndroidCpuFamily cpu_family = android_getCpuFamily();
const uint64_t cpu_features = android_getCpuFeatures();
@@ -68,7 +126,7 @@ static int AndroidCPUInfo(CPUFeature feature) {
return 0;
}
VP8CPUInfo VP8GetCPUInfo = AndroidCPUInfo;
-#elif defined(__ARM_NEON__)
+#elif defined(WEBP_USE_NEON)
// define a dummy function to enable turning off NEON at runtime by setting
// VP8DecGetCPUInfo = NULL
static int armCPUInfo(CPUFeature feature) {
@@ -76,10 +134,17 @@ static int armCPUInfo(CPUFeature feature) {
return 1;
}
VP8CPUInfo VP8GetCPUInfo = armCPUInfo;
+#elif defined(WEBP_USE_MIPS32) || defined(WEBP_USE_MIPS_DSP_R2)
+static int mipsCPUInfo(CPUFeature feature) {
+ if ((feature == kMIPS32) || (feature == kMIPSdspR2)) {
+ return 1;
+ } else {
+ return 0;
+ }
+
+}
+VP8CPUInfo VP8GetCPUInfo = mipsCPUInfo;
#else
VP8CPUInfo VP8GetCPUInfo = NULL;
#endif
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/dsp/dec.c b/drivers/webp/dsp/dec.c
index 9ae7b6fa76..77a00381c5 100644
--- a/drivers/webp/dsp/dec.c
+++ b/drivers/webp/dsp/dec.c
@@ -1,53 +1,20 @@
// Copyright 2010 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
-// Speed-critical decoding functions.
+// Speed-critical decoding functions, default plain-C implementations.
//
// Author: Skal (pascal.massimino@gmail.com)
#include "./dsp.h"
#include "../dec/vp8i.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
//------------------------------------------------------------------------------
-// run-time tables (~4k)
-
-static uint8_t abs0[255 + 255 + 1]; // abs(i)
-static uint8_t abs1[255 + 255 + 1]; // abs(i)>>1
-static int8_t sclip1[1020 + 1020 + 1]; // clips [-1020, 1020] to [-128, 127]
-static int8_t sclip2[112 + 112 + 1]; // clips [-112, 112] to [-16, 15]
-static uint8_t clip1[255 + 510 + 1]; // clips [-255,510] to [0,255]
-
-// We declare this variable 'volatile' to prevent instruction reordering
-// and make sure it's set to true _last_ (so as to be thread-safe)
-static volatile int tables_ok = 0;
-
-static void DspInitTables(void) {
- if (!tables_ok) {
- int i;
- for (i = -255; i <= 255; ++i) {
- abs0[255 + i] = (i < 0) ? -i : i;
- abs1[255 + i] = abs0[255 + i] >> 1;
- }
- for (i = -1020; i <= 1020; ++i) {
- sclip1[1020 + i] = (i < -128) ? -128 : (i > 127) ? 127 : i;
- }
- for (i = -112; i <= 112; ++i) {
- sclip2[112 + i] = (i < -16) ? -16 : (i > 15) ? 15 : i;
- }
- for (i = -255; i <= 255 + 255; ++i) {
- clip1[255 + i] = (i < 0) ? 0 : (i > 255) ? 255 : i;
- }
- tables_ok = 1;
- }
-}
static WEBP_INLINE uint8_t clip_8b(int v) {
return (!(v & ~0xff)) ? v : (v < 0) ? 0 : 255;
@@ -59,9 +26,16 @@ static WEBP_INLINE uint8_t clip_8b(int v) {
#define STORE(x, y, v) \
dst[x + y * BPS] = clip_8b(dst[x + y * BPS] + ((v) >> 3))
-static const int kC1 = 20091 + (1 << 16);
-static const int kC2 = 35468;
-#define MUL(a, b) (((a) * (b)) >> 16)
+#define STORE2(y, dc, d, c) do { \
+ const int DC = (dc); \
+ STORE(0, y, DC + (d)); \
+ STORE(1, y, DC + (c)); \
+ STORE(2, y, DC - (c)); \
+ STORE(3, y, DC - (d)); \
+} while (0)
+
+#define MUL1(a) ((((a) * 20091) >> 16) + (a))
+#define MUL2(a) (((a) * 35468) >> 16)
static void TransformOne(const int16_t* in, uint8_t* dst) {
int C[4 * 4], *tmp;
@@ -70,8 +44,8 @@ static void TransformOne(const int16_t* in, uint8_t* dst) {
for (i = 0; i < 4; ++i) { // vertical pass
const int a = in[0] + in[8]; // [-4096, 4094]
const int b = in[0] - in[8]; // [-4095, 4095]
- const int c = MUL(in[4], kC2) - MUL(in[12], kC1); // [-3783, 3783]
- const int d = MUL(in[4], kC1) + MUL(in[12], kC2); // [-3785, 3781]
+ const int c = MUL2(in[4]) - MUL1(in[12]); // [-3783, 3783]
+ const int d = MUL1(in[4]) + MUL2(in[12]); // [-3785, 3781]
tmp[0] = a + d; // [-7881, 7875]
tmp[1] = b + c; // [-7878, 7878]
tmp[2] = b - c; // [-7878, 7878]
@@ -80,7 +54,7 @@ static void TransformOne(const int16_t* in, uint8_t* dst) {
in++;
}
// Each pass is expanding the dynamic range by ~3.85 (upper bound).
- // The exact value is (2. + (kC1 + kC2) / 65536).
+ // The exact value is (2. + (20091 + 35468) / 65536).
// After the second pass, maximum interval is [-3794, 3794], assuming
// an input in [-2048, 2047] interval. We then need to add a dst value
// in the [0, 255] range.
@@ -91,8 +65,8 @@ static void TransformOne(const int16_t* in, uint8_t* dst) {
const int dc = tmp[0] + 4;
const int a = dc + tmp[8];
const int b = dc - tmp[8];
- const int c = MUL(tmp[4], kC2) - MUL(tmp[12], kC1);
- const int d = MUL(tmp[4], kC1) + MUL(tmp[12], kC2);
+ const int c = MUL2(tmp[4]) - MUL1(tmp[12]);
+ const int d = MUL1(tmp[4]) + MUL2(tmp[12]);
STORE(0, 0, a + d);
STORE(1, 0, b + c);
STORE(2, 0, b - c);
@@ -101,7 +75,22 @@ static void TransformOne(const int16_t* in, uint8_t* dst) {
dst += BPS;
}
}
-#undef MUL
+
+// Simplified transform when only in[0], in[1] and in[4] are non-zero
+static void TransformAC3(const int16_t* in, uint8_t* dst) {
+ const int a = in[0] + 4;
+ const int c4 = MUL2(in[4]);
+ const int d4 = MUL1(in[4]);
+ const int c1 = MUL2(in[1]);
+ const int d1 = MUL1(in[1]);
+ STORE2(0, a + d4, d1, c1);
+ STORE2(1, a + c4, d1, c1);
+ STORE2(2, a - c4, d1, c1);
+ STORE2(3, a - d4, d1, c1);
+}
+#undef MUL1
+#undef MUL2
+#undef STORE2
static void TransformTwo(const int16_t* in, uint8_t* dst, int do_two) {
TransformOne(in, dst);
@@ -115,7 +104,7 @@ static void TransformUV(const int16_t* in, uint8_t* dst) {
VP8Transform(in + 2 * 16, dst + 4 * BPS, 1);
}
-static void TransformDC(const int16_t *in, uint8_t* dst) {
+static void TransformDC(const int16_t* in, uint8_t* dst) {
const int DC = in[0] + 4;
int i, j;
for (j = 0; j < 4; ++j) {
@@ -126,10 +115,10 @@ static void TransformDC(const int16_t *in, uint8_t* dst) {
}
static void TransformDCUV(const int16_t* in, uint8_t* dst) {
- if (in[0 * 16]) TransformDC(in + 0 * 16, dst);
- if (in[1 * 16]) TransformDC(in + 1 * 16, dst + 4);
- if (in[2 * 16]) TransformDC(in + 2 * 16, dst + 4 * BPS);
- if (in[3 * 16]) TransformDC(in + 3 * 16, dst + 4 * BPS + 4);
+ if (in[0 * 16]) VP8TransformDC(in + 0 * 16, dst);
+ if (in[1 * 16]) VP8TransformDC(in + 1 * 16, dst + 4);
+ if (in[2 * 16]) VP8TransformDC(in + 2 * 16, dst + 4 * BPS);
+ if (in[3 * 16]) VP8TransformDC(in + 3 * 16, dst + 4 * BPS + 4);
}
#undef STORE
@@ -164,16 +153,16 @@ static void TransformWHT(const int16_t* in, int16_t* out) {
}
}
-void (*VP8TransformWHT)(const int16_t* in, int16_t* out) = TransformWHT;
+void (*VP8TransformWHT)(const int16_t* in, int16_t* out);
//------------------------------------------------------------------------------
// Intra predictions
#define DST(x, y) dst[(x) + (y) * BPS]
-static WEBP_INLINE void TrueMotion(uint8_t *dst, int size) {
+static WEBP_INLINE void TrueMotion(uint8_t* dst, int size) {
const uint8_t* top = dst - BPS;
- const uint8_t* const clip0 = clip1 + 255 - top[-1];
+ const uint8_t* const clip0 = VP8kclip1 - top[-1];
int y;
for (y = 0; y < size; ++y) {
const uint8_t* const clip = clip0 + dst[-1];
@@ -184,21 +173,21 @@ static WEBP_INLINE void TrueMotion(uint8_t *dst, int size) {
dst += BPS;
}
}
-static void TM4(uint8_t *dst) { TrueMotion(dst, 4); }
-static void TM8uv(uint8_t *dst) { TrueMotion(dst, 8); }
-static void TM16(uint8_t *dst) { TrueMotion(dst, 16); }
+static void TM4(uint8_t* dst) { TrueMotion(dst, 4); }
+static void TM8uv(uint8_t* dst) { TrueMotion(dst, 8); }
+static void TM16(uint8_t* dst) { TrueMotion(dst, 16); }
//------------------------------------------------------------------------------
// 16x16
-static void VE16(uint8_t *dst) { // vertical
+static void VE16(uint8_t* dst) { // vertical
int j;
for (j = 0; j < 16; ++j) {
memcpy(dst + j * BPS, dst - BPS, 16);
}
}
-static void HE16(uint8_t *dst) { // horizontal
+static void HE16(uint8_t* dst) { // horizontal
int j;
for (j = 16; j > 0; --j) {
memset(dst, dst[-1], 16);
@@ -213,7 +202,7 @@ static WEBP_INLINE void Put16(int v, uint8_t* dst) {
}
}
-static void DC16(uint8_t *dst) { // DC
+static void DC16(uint8_t* dst) { // DC
int DC = 16;
int j;
for (j = 0; j < 16; ++j) {
@@ -222,7 +211,7 @@ static void DC16(uint8_t *dst) { // DC
Put16(DC >> 5, dst);
}
-static void DC16NoTop(uint8_t *dst) { // DC with top samples not available
+static void DC16NoTop(uint8_t* dst) { // DC with top samples not available
int DC = 8;
int j;
for (j = 0; j < 16; ++j) {
@@ -231,7 +220,7 @@ static void DC16NoTop(uint8_t *dst) { // DC with top samples not available
Put16(DC >> 4, dst);
}
-static void DC16NoLeft(uint8_t *dst) { // DC with left samples not available
+static void DC16NoLeft(uint8_t* dst) { // DC with left samples not available
int DC = 8;
int i;
for (i = 0; i < 16; ++i) {
@@ -240,17 +229,19 @@ static void DC16NoLeft(uint8_t *dst) { // DC with left samples not available
Put16(DC >> 4, dst);
}
-static void DC16NoTopLeft(uint8_t *dst) { // DC with no top and left samples
+static void DC16NoTopLeft(uint8_t* dst) { // DC with no top and left samples
Put16(0x80, dst);
}
+VP8PredFunc VP8PredLuma16[NUM_B_DC_MODES];
+
//------------------------------------------------------------------------------
// 4x4
#define AVG3(a, b, c) (((a) + 2 * (b) + (c) + 2) >> 2)
#define AVG2(a, b) (((a) + (b) + 1) >> 1)
-static void VE4(uint8_t *dst) { // vertical
+static void VE4(uint8_t* dst) { // vertical
const uint8_t* top = dst - BPS;
const uint8_t vals[4] = {
AVG3(top[-1], top[0], top[1]),
@@ -264,7 +255,7 @@ static void VE4(uint8_t *dst) { // vertical
}
}
-static void HE4(uint8_t *dst) { // horizontal
+static void HE4(uint8_t* dst) { // horizontal
const int A = dst[-1 - BPS];
const int B = dst[-1];
const int C = dst[-1 + BPS];
@@ -276,7 +267,7 @@ static void HE4(uint8_t *dst) { // horizontal
*(uint32_t*)(dst + 3 * BPS) = 0x01010101U * AVG3(D, E, E);
}
-static void DC4(uint8_t *dst) { // DC
+static void DC4(uint8_t* dst) { // DC
uint32_t dc = 4;
int i;
for (i = 0; i < 4; ++i) dc += dst[i - BPS] + dst[-1 + i * BPS];
@@ -284,7 +275,7 @@ static void DC4(uint8_t *dst) { // DC
for (i = 0; i < 4; ++i) memset(dst + i * BPS, dc, 4);
}
-static void RD4(uint8_t *dst) { // Down-right
+static void RD4(uint8_t* dst) { // Down-right
const int I = dst[-1 + 0 * BPS];
const int J = dst[-1 + 1 * BPS];
const int K = dst[-1 + 2 * BPS];
@@ -295,15 +286,15 @@ static void RD4(uint8_t *dst) { // Down-right
const int C = dst[2 - BPS];
const int D = dst[3 - BPS];
DST(0, 3) = AVG3(J, K, L);
- DST(0, 2) = DST(1, 3) = AVG3(I, J, K);
- DST(0, 1) = DST(1, 2) = DST(2, 3) = AVG3(X, I, J);
- DST(0, 0) = DST(1, 1) = DST(2, 2) = DST(3, 3) = AVG3(A, X, I);
- DST(1, 0) = DST(2, 1) = DST(3, 2) = AVG3(B, A, X);
- DST(2, 0) = DST(3, 1) = AVG3(C, B, A);
- DST(3, 0) = AVG3(D, C, B);
+ DST(1, 3) = DST(0, 2) = AVG3(I, J, K);
+ DST(2, 3) = DST(1, 2) = DST(0, 1) = AVG3(X, I, J);
+ DST(3, 3) = DST(2, 2) = DST(1, 1) = DST(0, 0) = AVG3(A, X, I);
+ DST(3, 2) = DST(2, 1) = DST(1, 0) = AVG3(B, A, X);
+ DST(3, 1) = DST(2, 0) = AVG3(C, B, A);
+ DST(3, 0) = AVG3(D, C, B);
}
-static void LD4(uint8_t *dst) { // Down-Left
+static void LD4(uint8_t* dst) { // Down-Left
const int A = dst[0 - BPS];
const int B = dst[1 - BPS];
const int C = dst[2 - BPS];
@@ -316,12 +307,12 @@ static void LD4(uint8_t *dst) { // Down-Left
DST(1, 0) = DST(0, 1) = AVG3(B, C, D);
DST(2, 0) = DST(1, 1) = DST(0, 2) = AVG3(C, D, E);
DST(3, 0) = DST(2, 1) = DST(1, 2) = DST(0, 3) = AVG3(D, E, F);
- DST(3, 1) = DST(2, 2) = DST(1, 3) = AVG3(E, F, G);
- DST(3, 2) = DST(2, 3) = AVG3(F, G, H);
- DST(3, 3) = AVG3(G, H, H);
+ DST(3, 1) = DST(2, 2) = DST(1, 3) = AVG3(E, F, G);
+ DST(3, 2) = DST(2, 3) = AVG3(F, G, H);
+ DST(3, 3) = AVG3(G, H, H);
}
-static void VR4(uint8_t *dst) { // Vertical-Right
+static void VR4(uint8_t* dst) { // Vertical-Right
const int I = dst[-1 + 0 * BPS];
const int J = dst[-1 + 1 * BPS];
const int K = dst[-1 + 2 * BPS];
@@ -343,7 +334,7 @@ static void VR4(uint8_t *dst) { // Vertical-Right
DST(3, 1) = AVG3(B, C, D);
}
-static void VL4(uint8_t *dst) { // Vertical-Left
+static void VL4(uint8_t* dst) { // Vertical-Left
const int A = dst[0 - BPS];
const int B = dst[1 - BPS];
const int C = dst[2 - BPS];
@@ -365,7 +356,7 @@ static void VL4(uint8_t *dst) { // Vertical-Left
DST(3, 3) = AVG3(F, G, H);
}
-static void HU4(uint8_t *dst) { // Horizontal-Up
+static void HU4(uint8_t* dst) { // Horizontal-Up
const int I = dst[-1 + 0 * BPS];
const int J = dst[-1 + 1 * BPS];
const int K = dst[-1 + 2 * BPS];
@@ -380,7 +371,7 @@ static void HU4(uint8_t *dst) { // Horizontal-Up
DST(0, 3) = DST(1, 3) = DST(2, 3) = DST(3, 3) = L;
}
-static void HD4(uint8_t *dst) { // Horizontal-Down
+static void HD4(uint8_t* dst) { // Horizontal-Down
const int I = dst[-1 + 0 * BPS];
const int J = dst[-1 + 1 * BPS];
const int K = dst[-1 + 2 * BPS];
@@ -407,17 +398,19 @@ static void HD4(uint8_t *dst) { // Horizontal-Down
#undef AVG3
#undef AVG2
+VP8PredFunc VP8PredLuma4[NUM_BMODES];
+
//------------------------------------------------------------------------------
// Chroma
-static void VE8uv(uint8_t *dst) { // vertical
+static void VE8uv(uint8_t* dst) { // vertical
int j;
for (j = 0; j < 8; ++j) {
memcpy(dst + j * BPS, dst - BPS, 8);
}
}
-static void HE8uv(uint8_t *dst) { // horizontal
+static void HE8uv(uint8_t* dst) { // horizontal
int j;
for (j = 0; j < 8; ++j) {
memset(dst, dst[-1], 8);
@@ -426,60 +419,45 @@ static void HE8uv(uint8_t *dst) { // horizontal
}
// helper for chroma-DC predictions
-static WEBP_INLINE void Put8x8uv(uint64_t v, uint8_t* dst) {
+static WEBP_INLINE void Put8x8uv(uint8_t value, uint8_t* dst) {
int j;
for (j = 0; j < 8; ++j) {
- *(uint64_t*)(dst + j * BPS) = v;
+ memset(dst + j * BPS, value, 8);
}
}
-static void DC8uv(uint8_t *dst) { // DC
+static void DC8uv(uint8_t* dst) { // DC
int dc0 = 8;
int i;
for (i = 0; i < 8; ++i) {
dc0 += dst[i - BPS] + dst[-1 + i * BPS];
}
- Put8x8uv((uint64_t)((dc0 >> 4) * 0x0101010101010101ULL), dst);
+ Put8x8uv(dc0 >> 4, dst);
}
-static void DC8uvNoLeft(uint8_t *dst) { // DC with no left samples
+static void DC8uvNoLeft(uint8_t* dst) { // DC with no left samples
int dc0 = 4;
int i;
for (i = 0; i < 8; ++i) {
dc0 += dst[i - BPS];
}
- Put8x8uv((uint64_t)((dc0 >> 3) * 0x0101010101010101ULL), dst);
+ Put8x8uv(dc0 >> 3, dst);
}
-static void DC8uvNoTop(uint8_t *dst) { // DC with no top samples
+static void DC8uvNoTop(uint8_t* dst) { // DC with no top samples
int dc0 = 4;
int i;
for (i = 0; i < 8; ++i) {
dc0 += dst[-1 + i * BPS];
}
- Put8x8uv((uint64_t)((dc0 >> 3) * 0x0101010101010101ULL), dst);
+ Put8x8uv(dc0 >> 3, dst);
}
-static void DC8uvNoTopLeft(uint8_t *dst) { // DC with nothing
- Put8x8uv(0x8080808080808080ULL, dst);
+static void DC8uvNoTopLeft(uint8_t* dst) { // DC with nothing
+ Put8x8uv(0x80, dst);
}
-//------------------------------------------------------------------------------
-// default C implementations
-
-const VP8PredFunc VP8PredLuma4[NUM_BMODES] = {
- DC4, TM4, VE4, HE4, RD4, VR4, LD4, VL4, HD4, HU4
-};
-
-const VP8PredFunc VP8PredLuma16[NUM_B_DC_MODES] = {
- DC16, TM16, VE16, HE16,
- DC16NoTop, DC16NoLeft, DC16NoTopLeft
-};
-
-const VP8PredFunc VP8PredChroma8[NUM_B_DC_MODES] = {
- DC8uv, TM8uv, VE8uv, HE8uv,
- DC8uvNoTop, DC8uvNoLeft, DC8uvNoTopLeft
-};
+VP8PredFunc VP8PredChroma8[NUM_B_DC_MODES];
//------------------------------------------------------------------------------
// Edge filtering functions
@@ -487,61 +465,62 @@ const VP8PredFunc VP8PredChroma8[NUM_B_DC_MODES] = {
// 4 pixels in, 2 pixels out
static WEBP_INLINE void do_filter2(uint8_t* p, int step) {
const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
- const int a = 3 * (q0 - p0) + sclip1[1020 + p1 - q1];
- const int a1 = sclip2[112 + ((a + 4) >> 3)];
- const int a2 = sclip2[112 + ((a + 3) >> 3)];
- p[-step] = clip1[255 + p0 + a2];
- p[ 0] = clip1[255 + q0 - a1];
+ const int a = 3 * (q0 - p0) + VP8ksclip1[p1 - q1]; // in [-893,892]
+ const int a1 = VP8ksclip2[(a + 4) >> 3]; // in [-16,15]
+ const int a2 = VP8ksclip2[(a + 3) >> 3];
+ p[-step] = VP8kclip1[p0 + a2];
+ p[ 0] = VP8kclip1[q0 - a1];
}
// 4 pixels in, 4 pixels out
static WEBP_INLINE void do_filter4(uint8_t* p, int step) {
const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
const int a = 3 * (q0 - p0);
- const int a1 = sclip2[112 + ((a + 4) >> 3)];
- const int a2 = sclip2[112 + ((a + 3) >> 3)];
+ const int a1 = VP8ksclip2[(a + 4) >> 3];
+ const int a2 = VP8ksclip2[(a + 3) >> 3];
const int a3 = (a1 + 1) >> 1;
- p[-2*step] = clip1[255 + p1 + a3];
- p[- step] = clip1[255 + p0 + a2];
- p[ 0] = clip1[255 + q0 - a1];
- p[ step] = clip1[255 + q1 - a3];
+ p[-2*step] = VP8kclip1[p1 + a3];
+ p[- step] = VP8kclip1[p0 + a2];
+ p[ 0] = VP8kclip1[q0 - a1];
+ p[ step] = VP8kclip1[q1 - a3];
}
// 6 pixels in, 6 pixels out
static WEBP_INLINE void do_filter6(uint8_t* p, int step) {
const int p2 = p[-3*step], p1 = p[-2*step], p0 = p[-step];
const int q0 = p[0], q1 = p[step], q2 = p[2*step];
- const int a = sclip1[1020 + 3 * (q0 - p0) + sclip1[1020 + p1 - q1]];
+ const int a = VP8ksclip1[3 * (q0 - p0) + VP8ksclip1[p1 - q1]];
+ // a is in [-128,127], a1 in [-27,27], a2 in [-18,18] and a3 in [-9,9]
const int a1 = (27 * a + 63) >> 7; // eq. to ((3 * a + 7) * 9) >> 7
const int a2 = (18 * a + 63) >> 7; // eq. to ((2 * a + 7) * 9) >> 7
const int a3 = (9 * a + 63) >> 7; // eq. to ((1 * a + 7) * 9) >> 7
- p[-3*step] = clip1[255 + p2 + a3];
- p[-2*step] = clip1[255 + p1 + a2];
- p[- step] = clip1[255 + p0 + a1];
- p[ 0] = clip1[255 + q0 - a1];
- p[ step] = clip1[255 + q1 - a2];
- p[ 2*step] = clip1[255 + q2 - a3];
+ p[-3*step] = VP8kclip1[p2 + a3];
+ p[-2*step] = VP8kclip1[p1 + a2];
+ p[- step] = VP8kclip1[p0 + a1];
+ p[ 0] = VP8kclip1[q0 - a1];
+ p[ step] = VP8kclip1[q1 - a2];
+ p[ 2*step] = VP8kclip1[q2 - a3];
}
static WEBP_INLINE int hev(const uint8_t* p, int step, int thresh) {
const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
- return (abs0[255 + p1 - p0] > thresh) || (abs0[255 + q1 - q0] > thresh);
+ return (VP8kabs0[p1 - p0] > thresh) || (VP8kabs0[q1 - q0] > thresh);
}
-static WEBP_INLINE int needs_filter(const uint8_t* p, int step, int thresh) {
- const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
- return (2 * abs0[255 + p0 - q0] + abs1[255 + p1 - q1]) <= thresh;
+static WEBP_INLINE int needs_filter(const uint8_t* p, int step, int t) {
+ const int p1 = p[-2 * step], p0 = p[-step], q0 = p[0], q1 = p[step];
+ return ((4 * VP8kabs0[p0 - q0] + VP8kabs0[p1 - q1]) <= t);
}
static WEBP_INLINE int needs_filter2(const uint8_t* p,
int step, int t, int it) {
- const int p3 = p[-4*step], p2 = p[-3*step], p1 = p[-2*step], p0 = p[-step];
- const int q0 = p[0], q1 = p[step], q2 = p[2*step], q3 = p[3*step];
- if ((2 * abs0[255 + p0 - q0] + abs1[255 + p1 - q1]) > t)
- return 0;
- return abs0[255 + p3 - p2] <= it && abs0[255 + p2 - p1] <= it &&
- abs0[255 + p1 - p0] <= it && abs0[255 + q3 - q2] <= it &&
- abs0[255 + q2 - q1] <= it && abs0[255 + q1 - q0] <= it;
+ const int p3 = p[-4 * step], p2 = p[-3 * step], p1 = p[-2 * step];
+ const int p0 = p[-step], q0 = p[0];
+ const int q1 = p[step], q2 = p[2 * step], q3 = p[3 * step];
+ if ((4 * VP8kabs0[p0 - q0] + VP8kabs0[p1 - q1]) > t) return 0;
+ return VP8kabs0[p3 - p2] <= it && VP8kabs0[p2 - p1] <= it &&
+ VP8kabs0[p1 - p0] <= it && VP8kabs0[q3 - q2] <= it &&
+ VP8kabs0[q2 - q1] <= it && VP8kabs0[q1 - q0] <= it;
}
//------------------------------------------------------------------------------
@@ -549,8 +528,9 @@ static WEBP_INLINE int needs_filter2(const uint8_t* p,
static void SimpleVFilter16(uint8_t* p, int stride, int thresh) {
int i;
+ const int thresh2 = 2 * thresh + 1;
for (i = 0; i < 16; ++i) {
- if (needs_filter(p + i, stride, thresh)) {
+ if (needs_filter(p + i, stride, thresh2)) {
do_filter2(p + i, stride);
}
}
@@ -558,8 +538,9 @@ static void SimpleVFilter16(uint8_t* p, int stride, int thresh) {
static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
int i;
+ const int thresh2 = 2 * thresh + 1;
for (i = 0; i < 16; ++i) {
- if (needs_filter(p + i * stride, 1, thresh)) {
+ if (needs_filter(p + i * stride, 1, thresh2)) {
do_filter2(p + i * stride, 1);
}
}
@@ -587,8 +568,9 @@ static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) {
static WEBP_INLINE void FilterLoop26(uint8_t* p,
int hstride, int vstride, int size,
int thresh, int ithresh, int hev_thresh) {
+ const int thresh2 = 2 * thresh + 1;
while (size-- > 0) {
- if (needs_filter2(p, hstride, thresh, ithresh)) {
+ if (needs_filter2(p, hstride, thresh2, ithresh)) {
if (hev(p, hstride, hev_thresh)) {
do_filter2(p, hstride);
} else {
@@ -602,8 +584,9 @@ static WEBP_INLINE void FilterLoop26(uint8_t* p,
static WEBP_INLINE void FilterLoop24(uint8_t* p,
int hstride, int vstride, int size,
int thresh, int ithresh, int hev_thresh) {
+ const int thresh2 = 2 * thresh + 1;
while (size-- > 0) {
- if (needs_filter2(p, hstride, thresh, ithresh)) {
+ if (needs_filter2(p, hstride, thresh2, ithresh)) {
if (hev(p, hstride, hev_thresh)) {
do_filter2(p, hstride);
} else {
@@ -672,6 +655,7 @@ static void HFilter8i(uint8_t* u, uint8_t* v, int stride,
//------------------------------------------------------------------------------
VP8DecIdct2 VP8Transform;
+VP8DecIdct VP8TransformAC3;
VP8DecIdct VP8TransformUV;
VP8DecIdct VP8TransformDC;
VP8DecIdct VP8TransformDCUV;
@@ -690,15 +674,25 @@ VP8SimpleFilterFunc VP8SimpleVFilter16i;
VP8SimpleFilterFunc VP8SimpleHFilter16i;
extern void VP8DspInitSSE2(void);
+extern void VP8DspInitSSE41(void);
extern void VP8DspInitNEON(void);
+extern void VP8DspInitMIPS32(void);
+extern void VP8DspInitMIPSdspR2(void);
+
+static volatile VP8CPUInfo dec_last_cpuinfo_used =
+ (VP8CPUInfo)&dec_last_cpuinfo_used;
-void VP8DspInit(void) {
- DspInitTables();
+WEBP_TSAN_IGNORE_FUNCTION void VP8DspInit(void) {
+ if (dec_last_cpuinfo_used == VP8GetCPUInfo) return;
+ VP8InitClipTables();
+
+ VP8TransformWHT = TransformWHT;
VP8Transform = TransformTwo;
VP8TransformUV = TransformUV;
VP8TransformDC = TransformDC;
VP8TransformDCUV = TransformDCUV;
+ VP8TransformAC3 = TransformAC3;
VP8VFilter16 = VFilter16;
VP8HFilter16 = HFilter16;
@@ -713,20 +707,60 @@ void VP8DspInit(void) {
VP8SimpleVFilter16i = SimpleVFilter16i;
VP8SimpleHFilter16i = SimpleHFilter16i;
+ VP8PredLuma4[0] = DC4;
+ VP8PredLuma4[1] = TM4;
+ VP8PredLuma4[2] = VE4;
+ VP8PredLuma4[3] = HE4;
+ VP8PredLuma4[4] = RD4;
+ VP8PredLuma4[5] = VR4;
+ VP8PredLuma4[6] = LD4;
+ VP8PredLuma4[7] = VL4;
+ VP8PredLuma4[8] = HD4;
+ VP8PredLuma4[9] = HU4;
+
+ VP8PredLuma16[0] = DC16;
+ VP8PredLuma16[1] = TM16;
+ VP8PredLuma16[2] = VE16;
+ VP8PredLuma16[3] = HE16;
+ VP8PredLuma16[4] = DC16NoTop;
+ VP8PredLuma16[5] = DC16NoLeft;
+ VP8PredLuma16[6] = DC16NoTopLeft;
+
+ VP8PredChroma8[0] = DC8uv;
+ VP8PredChroma8[1] = TM8uv;
+ VP8PredChroma8[2] = VE8uv;
+ VP8PredChroma8[3] = HE8uv;
+ VP8PredChroma8[4] = DC8uvNoTop;
+ VP8PredChroma8[5] = DC8uvNoLeft;
+ VP8PredChroma8[6] = DC8uvNoTopLeft;
+
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
- if (VP8GetCPUInfo) {
+ if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_USE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
VP8DspInitSSE2();
+#if defined(WEBP_USE_SSE41)
+ if (VP8GetCPUInfo(kSSE4_1)) {
+ VP8DspInitSSE41();
+ }
+#endif
}
-#elif defined(WEBP_USE_NEON)
+#endif
+#if defined(WEBP_USE_NEON)
if (VP8GetCPUInfo(kNEON)) {
VP8DspInitNEON();
}
#endif
+#if defined(WEBP_USE_MIPS32)
+ if (VP8GetCPUInfo(kMIPS32)) {
+ VP8DspInitMIPS32();
+ }
+#endif
+#if defined(WEBP_USE_MIPS_DSP_R2)
+ if (VP8GetCPUInfo(kMIPSdspR2)) {
+ VP8DspInitMIPSdspR2();
+ }
+#endif
}
+ dec_last_cpuinfo_used = VP8GetCPUInfo;
}
-
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/dsp/dec_clip_tables.c b/drivers/webp/dsp/dec_clip_tables.c
new file mode 100644
index 0000000000..3b6dde86ba
--- /dev/null
+++ b/drivers/webp/dsp/dec_clip_tables.c
@@ -0,0 +1,366 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Clipping tables for filtering
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./dsp.h"
+
+#define USE_STATIC_TABLES // undefine to have run-time table initialization
+
+#ifdef USE_STATIC_TABLES
+
+static const uint8_t abs0[255 + 255 + 1] = {
+ 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8, 0xf7, 0xf6, 0xf5, 0xf4,
+ 0xf3, 0xf2, 0xf1, 0xf0, 0xef, 0xee, 0xed, 0xec, 0xeb, 0xea, 0xe9, 0xe8,
+ 0xe7, 0xe6, 0xe5, 0xe4, 0xe3, 0xe2, 0xe1, 0xe0, 0xdf, 0xde, 0xdd, 0xdc,
+ 0xdb, 0xda, 0xd9, 0xd8, 0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0,
+ 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc9, 0xc8, 0xc7, 0xc6, 0xc5, 0xc4,
+ 0xc3, 0xc2, 0xc1, 0xc0, 0xbf, 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8,
+ 0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1, 0xb0, 0xaf, 0xae, 0xad, 0xac,
+ 0xab, 0xaa, 0xa9, 0xa8, 0xa7, 0xa6, 0xa5, 0xa4, 0xa3, 0xa2, 0xa1, 0xa0,
+ 0x9f, 0x9e, 0x9d, 0x9c, 0x9b, 0x9a, 0x99, 0x98, 0x97, 0x96, 0x95, 0x94,
+ 0x93, 0x92, 0x91, 0x90, 0x8f, 0x8e, 0x8d, 0x8c, 0x8b, 0x8a, 0x89, 0x88,
+ 0x87, 0x86, 0x85, 0x84, 0x83, 0x82, 0x81, 0x80, 0x7f, 0x7e, 0x7d, 0x7c,
+ 0x7b, 0x7a, 0x79, 0x78, 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70,
+ 0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 0x67, 0x66, 0x65, 0x64,
+ 0x63, 0x62, 0x61, 0x60, 0x5f, 0x5e, 0x5d, 0x5c, 0x5b, 0x5a, 0x59, 0x58,
+ 0x57, 0x56, 0x55, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4f, 0x4e, 0x4d, 0x4c,
+ 0x4b, 0x4a, 0x49, 0x48, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0x41, 0x40,
+ 0x3f, 0x3e, 0x3d, 0x3c, 0x3b, 0x3a, 0x39, 0x38, 0x37, 0x36, 0x35, 0x34,
+ 0x33, 0x32, 0x31, 0x30, 0x2f, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x28,
+ 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1f, 0x1e, 0x1d, 0x1c,
+ 0x1b, 0x1a, 0x19, 0x18, 0x17, 0x16, 0x15, 0x14, 0x13, 0x12, 0x11, 0x10,
+ 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04,
+ 0x03, 0x02, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c,
+ 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44,
+ 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
+ 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c,
+ 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74,
+ 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80,
+ 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c,
+ 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
+ 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0,
+ 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc,
+ 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
+ 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0,
+ 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec,
+ 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+};
+
+static const int8_t sclip1[1020 + 1020 + 1] = {
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+ 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93,
+ 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab,
+ 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
+ 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb,
+ 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
+ 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3,
+ 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
+ 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
+ 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+ 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53,
+ 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
+ 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f
+};
+
+static const int8_t sclip2[112 + 112 + 1] = {
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,
+ 0xfc, 0xfd, 0xfe, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
+ 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f
+};
+
+static const uint8_t clip1[255 + 511 + 1] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c,
+ 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44,
+ 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50,
+ 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c,
+ 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74,
+ 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80,
+ 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c,
+ 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
+ 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0,
+ 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc,
+ 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8,
+ 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0,
+ 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec,
+ 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+#else
+
+// uninitialized tables
+static uint8_t abs0[255 + 255 + 1];
+static int8_t sclip1[1020 + 1020 + 1];
+static int8_t sclip2[112 + 112 + 1];
+static uint8_t clip1[255 + 511 + 1];
+
+// We declare this variable 'volatile' to prevent instruction reordering
+// and make sure it's set to true _last_ (so as to be thread-safe)
+static volatile int tables_ok = 0;
+
+#endif
+
+const int8_t* const VP8ksclip1 = &sclip1[1020];
+const int8_t* const VP8ksclip2 = &sclip2[112];
+const uint8_t* const VP8kclip1 = &clip1[255];
+const uint8_t* const VP8kabs0 = &abs0[255];
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8InitClipTables(void) {
+#if !defined(USE_STATIC_TABLES)
+ int i;
+ if (!tables_ok) {
+ for (i = -255; i <= 255; ++i) {
+ abs0[255 + i] = (i < 0) ? -i : i;
+ }
+ for (i = -1020; i <= 1020; ++i) {
+ sclip1[1020 + i] = (i < -128) ? -128 : (i > 127) ? 127 : i;
+ }
+ for (i = -112; i <= 112; ++i) {
+ sclip2[112 + i] = (i < -16) ? -16 : (i > 15) ? 15 : i;
+ }
+ for (i = -255; i <= 255 + 255; ++i) {
+ clip1[255 + i] = (i < 0) ? 0 : (i > 255) ? 255 : i;
+ }
+ tables_ok = 1;
+ }
+#endif // USE_STATIC_TABLES
+}
diff --git a/drivers/webp/dsp/dec_mips32.c b/drivers/webp/dsp/dec_mips32.c
new file mode 100644
index 0000000000..4e9ef42605
--- /dev/null
+++ b/drivers/webp/dsp/dec_mips32.c
@@ -0,0 +1,587 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// MIPS version of dsp functions
+//
+// Author(s): Djordje Pesut (djordje.pesut@imgtec.com)
+// Jovan Zelincevic (jovan.zelincevic@imgtec.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_MIPS32)
+
+#include "./mips_macro.h"
+
+static const int kC1 = 20091 + (1 << 16);
+static const int kC2 = 35468;
+
+static WEBP_INLINE int abs_mips32(int x) {
+ const int sign = x >> 31;
+ return (x ^ sign) - sign;
+}
+
+// 4 pixels in, 2 pixels out
+static WEBP_INLINE void do_filter2(uint8_t* p, int step) {
+ const int p1 = p[-2 * step], p0 = p[-step], q0 = p[0], q1 = p[step];
+ const int a = 3 * (q0 - p0) + VP8ksclip1[p1 - q1];
+ const int a1 = VP8ksclip2[(a + 4) >> 3];
+ const int a2 = VP8ksclip2[(a + 3) >> 3];
+ p[-step] = VP8kclip1[p0 + a2];
+ p[ 0] = VP8kclip1[q0 - a1];
+}
+
+// 4 pixels in, 4 pixels out
+static WEBP_INLINE void do_filter4(uint8_t* p, int step) {
+ const int p1 = p[-2 * step], p0 = p[-step], q0 = p[0], q1 = p[step];
+ const int a = 3 * (q0 - p0);
+ const int a1 = VP8ksclip2[(a + 4) >> 3];
+ const int a2 = VP8ksclip2[(a + 3) >> 3];
+ const int a3 = (a1 + 1) >> 1;
+ p[-2 * step] = VP8kclip1[p1 + a3];
+ p[- step] = VP8kclip1[p0 + a2];
+ p[ 0] = VP8kclip1[q0 - a1];
+ p[ step] = VP8kclip1[q1 - a3];
+}
+
+// 6 pixels in, 6 pixels out
+static WEBP_INLINE void do_filter6(uint8_t* p, int step) {
+ const int p2 = p[-3 * step], p1 = p[-2 * step], p0 = p[-step];
+ const int q0 = p[0], q1 = p[step], q2 = p[2 * step];
+ const int a = VP8ksclip1[3 * (q0 - p0) + VP8ksclip1[p1 - q1]];
+ // a is in [-128,127], a1 in [-27,27], a2 in [-18,18] and a3 in [-9,9]
+ const int a1 = (27 * a + 63) >> 7; // eq. to ((3 * a + 7) * 9) >> 7
+ const int a2 = (18 * a + 63) >> 7; // eq. to ((2 * a + 7) * 9) >> 7
+ const int a3 = (9 * a + 63) >> 7; // eq. to ((1 * a + 7) * 9) >> 7
+ p[-3 * step] = VP8kclip1[p2 + a3];
+ p[-2 * step] = VP8kclip1[p1 + a2];
+ p[- step] = VP8kclip1[p0 + a1];
+ p[ 0] = VP8kclip1[q0 - a1];
+ p[ step] = VP8kclip1[q1 - a2];
+ p[ 2 * step] = VP8kclip1[q2 - a3];
+}
+
+static WEBP_INLINE int hev(const uint8_t* p, int step, int thresh) {
+ const int p1 = p[-2 * step], p0 = p[-step], q0 = p[0], q1 = p[step];
+ return (abs_mips32(p1 - p0) > thresh) || (abs_mips32(q1 - q0) > thresh);
+}
+
+static WEBP_INLINE int needs_filter(const uint8_t* p, int step, int t) {
+ const int p1 = p[-2 * step], p0 = p[-step], q0 = p[0], q1 = p[step];
+ return ((4 * abs_mips32(p0 - q0) + abs_mips32(p1 - q1)) <= t);
+}
+
+static WEBP_INLINE int needs_filter2(const uint8_t* p,
+ int step, int t, int it) {
+ const int p3 = p[-4 * step], p2 = p[-3 * step];
+ const int p1 = p[-2 * step], p0 = p[-step];
+ const int q0 = p[0], q1 = p[step], q2 = p[2 * step], q3 = p[3 * step];
+ if ((4 * abs_mips32(p0 - q0) + abs_mips32(p1 - q1)) > t) {
+ return 0;
+ }
+ return abs_mips32(p3 - p2) <= it && abs_mips32(p2 - p1) <= it &&
+ abs_mips32(p1 - p0) <= it && abs_mips32(q3 - q2) <= it &&
+ abs_mips32(q2 - q1) <= it && abs_mips32(q1 - q0) <= it;
+}
+
+static WEBP_INLINE void FilterLoop26(uint8_t* p,
+ int hstride, int vstride, int size,
+ int thresh, int ithresh, int hev_thresh) {
+ const int thresh2 = 2 * thresh + 1;
+ while (size-- > 0) {
+ if (needs_filter2(p, hstride, thresh2, ithresh)) {
+ if (hev(p, hstride, hev_thresh)) {
+ do_filter2(p, hstride);
+ } else {
+ do_filter6(p, hstride);
+ }
+ }
+ p += vstride;
+ }
+}
+
+static WEBP_INLINE void FilterLoop24(uint8_t* p,
+ int hstride, int vstride, int size,
+ int thresh, int ithresh, int hev_thresh) {
+ const int thresh2 = 2 * thresh + 1;
+ while (size-- > 0) {
+ if (needs_filter2(p, hstride, thresh2, ithresh)) {
+ if (hev(p, hstride, hev_thresh)) {
+ do_filter2(p, hstride);
+ } else {
+ do_filter4(p, hstride);
+ }
+ }
+ p += vstride;
+ }
+}
+
+// on macroblock edges
+static void VFilter16(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop26(p, stride, 1, 16, thresh, ithresh, hev_thresh);
+}
+
+static void HFilter16(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop26(p, 1, stride, 16, thresh, ithresh, hev_thresh);
+}
+
+// 8-pixels wide variant, for chroma filtering
+static void VFilter8(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop26(u, stride, 1, 8, thresh, ithresh, hev_thresh);
+ FilterLoop26(v, stride, 1, 8, thresh, ithresh, hev_thresh);
+}
+
+static void HFilter8(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop26(u, 1, stride, 8, thresh, ithresh, hev_thresh);
+ FilterLoop26(v, 1, stride, 8, thresh, ithresh, hev_thresh);
+}
+
+static void VFilter8i(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop24(u + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh);
+ FilterLoop24(v + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh);
+}
+
+static void HFilter8i(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop24(u + 4, 1, stride, 8, thresh, ithresh, hev_thresh);
+ FilterLoop24(v + 4, 1, stride, 8, thresh, ithresh, hev_thresh);
+}
+
+// on three inner edges
+static void VFilter16i(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ int k;
+ for (k = 3; k > 0; --k) {
+ p += 4 * stride;
+ FilterLoop24(p, stride, 1, 16, thresh, ithresh, hev_thresh);
+ }
+}
+
+static void HFilter16i(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ int k;
+ for (k = 3; k > 0; --k) {
+ p += 4;
+ FilterLoop24(p, 1, stride, 16, thresh, ithresh, hev_thresh);
+ }
+}
+
+//------------------------------------------------------------------------------
+// Simple In-loop filtering (Paragraph 15.2)
+
+static void SimpleVFilter16(uint8_t* p, int stride, int thresh) {
+ int i;
+ const int thresh2 = 2 * thresh + 1;
+ for (i = 0; i < 16; ++i) {
+ if (needs_filter(p + i, stride, thresh2)) {
+ do_filter2(p + i, stride);
+ }
+ }
+}
+
+static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
+ int i;
+ const int thresh2 = 2 * thresh + 1;
+ for (i = 0; i < 16; ++i) {
+ if (needs_filter(p + i * stride, 1, thresh2)) {
+ do_filter2(p + i * stride, 1);
+ }
+ }
+}
+
+static void SimpleVFilter16i(uint8_t* p, int stride, int thresh) {
+ int k;
+ for (k = 3; k > 0; --k) {
+ p += 4 * stride;
+ SimpleVFilter16(p, stride, thresh);
+ }
+}
+
+static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) {
+ int k;
+ for (k = 3; k > 0; --k) {
+ p += 4;
+ SimpleHFilter16(p, stride, thresh);
+ }
+}
+
+static void TransformOne(const int16_t* in, uint8_t* dst) {
+ int temp0, temp1, temp2, temp3, temp4;
+ int temp5, temp6, temp7, temp8, temp9;
+ int temp10, temp11, temp12, temp13, temp14;
+ int temp15, temp16, temp17, temp18;
+ int16_t* p_in = (int16_t*)in;
+
+ // loops unrolled and merged to avoid usage of tmp buffer
+ // and to reduce number of stalls. MUL macro is written
+ // in assembler and inlined
+ __asm__ volatile(
+ "lh %[temp0], 0(%[in]) \n\t"
+ "lh %[temp8], 16(%[in]) \n\t"
+ "lh %[temp4], 8(%[in]) \n\t"
+ "lh %[temp12], 24(%[in]) \n\t"
+ "addu %[temp16], %[temp0], %[temp8] \n\t"
+ "subu %[temp0], %[temp0], %[temp8] \n\t"
+ "mul %[temp8], %[temp4], %[kC2] \n\t"
+ "mul %[temp17], %[temp12], %[kC1] \n\t"
+ "mul %[temp4], %[temp4], %[kC1] \n\t"
+ "mul %[temp12], %[temp12], %[kC2] \n\t"
+ "lh %[temp1], 2(%[in]) \n\t"
+ "lh %[temp5], 10(%[in]) \n\t"
+ "lh %[temp9], 18(%[in]) \n\t"
+ "lh %[temp13], 26(%[in]) \n\t"
+ "sra %[temp8], %[temp8], 16 \n\t"
+ "sra %[temp17], %[temp17], 16 \n\t"
+ "sra %[temp4], %[temp4], 16 \n\t"
+ "sra %[temp12], %[temp12], 16 \n\t"
+ "lh %[temp2], 4(%[in]) \n\t"
+ "lh %[temp6], 12(%[in]) \n\t"
+ "lh %[temp10], 20(%[in]) \n\t"
+ "lh %[temp14], 28(%[in]) \n\t"
+ "subu %[temp17], %[temp8], %[temp17] \n\t"
+ "addu %[temp4], %[temp4], %[temp12] \n\t"
+ "addu %[temp8], %[temp16], %[temp4] \n\t"
+ "subu %[temp4], %[temp16], %[temp4] \n\t"
+ "addu %[temp16], %[temp1], %[temp9] \n\t"
+ "subu %[temp1], %[temp1], %[temp9] \n\t"
+ "lh %[temp3], 6(%[in]) \n\t"
+ "lh %[temp7], 14(%[in]) \n\t"
+ "lh %[temp11], 22(%[in]) \n\t"
+ "lh %[temp15], 30(%[in]) \n\t"
+ "addu %[temp12], %[temp0], %[temp17] \n\t"
+ "subu %[temp0], %[temp0], %[temp17] \n\t"
+ "mul %[temp9], %[temp5], %[kC2] \n\t"
+ "mul %[temp17], %[temp13], %[kC1] \n\t"
+ "mul %[temp5], %[temp5], %[kC1] \n\t"
+ "mul %[temp13], %[temp13], %[kC2] \n\t"
+ "sra %[temp9], %[temp9], 16 \n\t"
+ "sra %[temp17], %[temp17], 16 \n\t"
+ "subu %[temp17], %[temp9], %[temp17] \n\t"
+ "sra %[temp5], %[temp5], 16 \n\t"
+ "sra %[temp13], %[temp13], 16 \n\t"
+ "addu %[temp5], %[temp5], %[temp13] \n\t"
+ "addu %[temp13], %[temp1], %[temp17] \n\t"
+ "subu %[temp1], %[temp1], %[temp17] \n\t"
+ "mul %[temp17], %[temp14], %[kC1] \n\t"
+ "mul %[temp14], %[temp14], %[kC2] \n\t"
+ "addu %[temp9], %[temp16], %[temp5] \n\t"
+ "subu %[temp5], %[temp16], %[temp5] \n\t"
+ "addu %[temp16], %[temp2], %[temp10] \n\t"
+ "subu %[temp2], %[temp2], %[temp10] \n\t"
+ "mul %[temp10], %[temp6], %[kC2] \n\t"
+ "mul %[temp6], %[temp6], %[kC1] \n\t"
+ "sra %[temp17], %[temp17], 16 \n\t"
+ "sra %[temp14], %[temp14], 16 \n\t"
+ "sra %[temp10], %[temp10], 16 \n\t"
+ "sra %[temp6], %[temp6], 16 \n\t"
+ "subu %[temp17], %[temp10], %[temp17] \n\t"
+ "addu %[temp6], %[temp6], %[temp14] \n\t"
+ "addu %[temp10], %[temp16], %[temp6] \n\t"
+ "subu %[temp6], %[temp16], %[temp6] \n\t"
+ "addu %[temp14], %[temp2], %[temp17] \n\t"
+ "subu %[temp2], %[temp2], %[temp17] \n\t"
+ "mul %[temp17], %[temp15], %[kC1] \n\t"
+ "mul %[temp15], %[temp15], %[kC2] \n\t"
+ "addu %[temp16], %[temp3], %[temp11] \n\t"
+ "subu %[temp3], %[temp3], %[temp11] \n\t"
+ "mul %[temp11], %[temp7], %[kC2] \n\t"
+ "mul %[temp7], %[temp7], %[kC1] \n\t"
+ "addiu %[temp8], %[temp8], 4 \n\t"
+ "addiu %[temp12], %[temp12], 4 \n\t"
+ "addiu %[temp0], %[temp0], 4 \n\t"
+ "addiu %[temp4], %[temp4], 4 \n\t"
+ "sra %[temp17], %[temp17], 16 \n\t"
+ "sra %[temp15], %[temp15], 16 \n\t"
+ "sra %[temp11], %[temp11], 16 \n\t"
+ "sra %[temp7], %[temp7], 16 \n\t"
+ "subu %[temp17], %[temp11], %[temp17] \n\t"
+ "addu %[temp7], %[temp7], %[temp15] \n\t"
+ "addu %[temp15], %[temp3], %[temp17] \n\t"
+ "subu %[temp3], %[temp3], %[temp17] \n\t"
+ "addu %[temp11], %[temp16], %[temp7] \n\t"
+ "subu %[temp7], %[temp16], %[temp7] \n\t"
+ "addu %[temp16], %[temp8], %[temp10] \n\t"
+ "subu %[temp8], %[temp8], %[temp10] \n\t"
+ "mul %[temp10], %[temp9], %[kC2] \n\t"
+ "mul %[temp17], %[temp11], %[kC1] \n\t"
+ "mul %[temp9], %[temp9], %[kC1] \n\t"
+ "mul %[temp11], %[temp11], %[kC2] \n\t"
+ "sra %[temp10], %[temp10], 16 \n\t"
+ "sra %[temp17], %[temp17], 16 \n\t"
+ "sra %[temp9], %[temp9], 16 \n\t"
+ "sra %[temp11], %[temp11], 16 \n\t"
+ "subu %[temp17], %[temp10], %[temp17] \n\t"
+ "addu %[temp11], %[temp9], %[temp11] \n\t"
+ "addu %[temp10], %[temp12], %[temp14] \n\t"
+ "subu %[temp12], %[temp12], %[temp14] \n\t"
+ "mul %[temp14], %[temp13], %[kC2] \n\t"
+ "mul %[temp9], %[temp15], %[kC1] \n\t"
+ "mul %[temp13], %[temp13], %[kC1] \n\t"
+ "mul %[temp15], %[temp15], %[kC2] \n\t"
+ "sra %[temp14], %[temp14], 16 \n\t"
+ "sra %[temp9], %[temp9], 16 \n\t"
+ "sra %[temp13], %[temp13], 16 \n\t"
+ "sra %[temp15], %[temp15], 16 \n\t"
+ "subu %[temp9], %[temp14], %[temp9] \n\t"
+ "addu %[temp15], %[temp13], %[temp15] \n\t"
+ "addu %[temp14], %[temp0], %[temp2] \n\t"
+ "subu %[temp0], %[temp0], %[temp2] \n\t"
+ "mul %[temp2], %[temp1], %[kC2] \n\t"
+ "mul %[temp13], %[temp3], %[kC1] \n\t"
+ "mul %[temp1], %[temp1], %[kC1] \n\t"
+ "mul %[temp3], %[temp3], %[kC2] \n\t"
+ "sra %[temp2], %[temp2], 16 \n\t"
+ "sra %[temp13], %[temp13], 16 \n\t"
+ "sra %[temp1], %[temp1], 16 \n\t"
+ "sra %[temp3], %[temp3], 16 \n\t"
+ "subu %[temp13], %[temp2], %[temp13] \n\t"
+ "addu %[temp3], %[temp1], %[temp3] \n\t"
+ "addu %[temp2], %[temp4], %[temp6] \n\t"
+ "subu %[temp4], %[temp4], %[temp6] \n\t"
+ "mul %[temp6], %[temp5], %[kC2] \n\t"
+ "mul %[temp1], %[temp7], %[kC1] \n\t"
+ "mul %[temp5], %[temp5], %[kC1] \n\t"
+ "mul %[temp7], %[temp7], %[kC2] \n\t"
+ "sra %[temp6], %[temp6], 16 \n\t"
+ "sra %[temp1], %[temp1], 16 \n\t"
+ "sra %[temp5], %[temp5], 16 \n\t"
+ "sra %[temp7], %[temp7], 16 \n\t"
+ "subu %[temp1], %[temp6], %[temp1] \n\t"
+ "addu %[temp7], %[temp5], %[temp7] \n\t"
+ "addu %[temp5], %[temp16], %[temp11] \n\t"
+ "subu %[temp16], %[temp16], %[temp11] \n\t"
+ "addu %[temp11], %[temp8], %[temp17] \n\t"
+ "subu %[temp8], %[temp8], %[temp17] \n\t"
+ "sra %[temp5], %[temp5], 3 \n\t"
+ "sra %[temp16], %[temp16], 3 \n\t"
+ "sra %[temp11], %[temp11], 3 \n\t"
+ "sra %[temp8], %[temp8], 3 \n\t"
+ "addu %[temp17], %[temp10], %[temp15] \n\t"
+ "subu %[temp10], %[temp10], %[temp15] \n\t"
+ "addu %[temp15], %[temp12], %[temp9] \n\t"
+ "subu %[temp12], %[temp12], %[temp9] \n\t"
+ "sra %[temp17], %[temp17], 3 \n\t"
+ "sra %[temp10], %[temp10], 3 \n\t"
+ "sra %[temp15], %[temp15], 3 \n\t"
+ "sra %[temp12], %[temp12], 3 \n\t"
+ "addu %[temp9], %[temp14], %[temp3] \n\t"
+ "subu %[temp14], %[temp14], %[temp3] \n\t"
+ "addu %[temp3], %[temp0], %[temp13] \n\t"
+ "subu %[temp0], %[temp0], %[temp13] \n\t"
+ "sra %[temp9], %[temp9], 3 \n\t"
+ "sra %[temp14], %[temp14], 3 \n\t"
+ "sra %[temp3], %[temp3], 3 \n\t"
+ "sra %[temp0], %[temp0], 3 \n\t"
+ "addu %[temp13], %[temp2], %[temp7] \n\t"
+ "subu %[temp2], %[temp2], %[temp7] \n\t"
+ "addu %[temp7], %[temp4], %[temp1] \n\t"
+ "subu %[temp4], %[temp4], %[temp1] \n\t"
+ "sra %[temp13], %[temp13], 3 \n\t"
+ "sra %[temp2], %[temp2], 3 \n\t"
+ "sra %[temp7], %[temp7], 3 \n\t"
+ "sra %[temp4], %[temp4], 3 \n\t"
+ "addiu %[temp6], $zero, 255 \n\t"
+ "lbu %[temp1], 0+0*" XSTR(BPS) "(%[dst]) \n\t"
+ "addu %[temp1], %[temp1], %[temp5] \n\t"
+ "sra %[temp5], %[temp1], 8 \n\t"
+ "sra %[temp18], %[temp1], 31 \n\t"
+ "beqz %[temp5], 1f \n\t"
+ "xor %[temp1], %[temp1], %[temp1] \n\t"
+ "movz %[temp1], %[temp6], %[temp18] \n\t"
+ "1: \n\t"
+ "lbu %[temp18], 1+0*" XSTR(BPS) "(%[dst]) \n\t"
+ "sb %[temp1], 0+0*" XSTR(BPS) "(%[dst]) \n\t"
+ "addu %[temp18], %[temp18], %[temp11] \n\t"
+ "sra %[temp11], %[temp18], 8 \n\t"
+ "sra %[temp1], %[temp18], 31 \n\t"
+ "beqz %[temp11], 2f \n\t"
+ "xor %[temp18], %[temp18], %[temp18] \n\t"
+ "movz %[temp18], %[temp6], %[temp1] \n\t"
+ "2: \n\t"
+ "lbu %[temp1], 2+0*" XSTR(BPS) "(%[dst]) \n\t"
+ "sb %[temp18], 1+0*" XSTR(BPS) "(%[dst]) \n\t"
+ "addu %[temp1], %[temp1], %[temp8] \n\t"
+ "sra %[temp8], %[temp1], 8 \n\t"
+ "sra %[temp18], %[temp1], 31 \n\t"
+ "beqz %[temp8], 3f \n\t"
+ "xor %[temp1], %[temp1], %[temp1] \n\t"
+ "movz %[temp1], %[temp6], %[temp18] \n\t"
+ "3: \n\t"
+ "lbu %[temp18], 3+0*" XSTR(BPS) "(%[dst]) \n\t"
+ "sb %[temp1], 2+0*" XSTR(BPS) "(%[dst]) \n\t"
+ "addu %[temp18], %[temp18], %[temp16] \n\t"
+ "sra %[temp16], %[temp18], 8 \n\t"
+ "sra %[temp1], %[temp18], 31 \n\t"
+ "beqz %[temp16], 4f \n\t"
+ "xor %[temp18], %[temp18], %[temp18] \n\t"
+ "movz %[temp18], %[temp6], %[temp1] \n\t"
+ "4: \n\t"
+ "sb %[temp18], 3+0*" XSTR(BPS) "(%[dst]) \n\t"
+ "lbu %[temp5], 0+1*" XSTR(BPS) "(%[dst]) \n\t"
+ "lbu %[temp8], 1+1*" XSTR(BPS) "(%[dst]) \n\t"
+ "lbu %[temp11], 2+1*" XSTR(BPS) "(%[dst]) \n\t"
+ "lbu %[temp16], 3+1*" XSTR(BPS) "(%[dst]) \n\t"
+ "addu %[temp5], %[temp5], %[temp17] \n\t"
+ "addu %[temp8], %[temp8], %[temp15] \n\t"
+ "addu %[temp11], %[temp11], %[temp12] \n\t"
+ "addu %[temp16], %[temp16], %[temp10] \n\t"
+ "sra %[temp18], %[temp5], 8 \n\t"
+ "sra %[temp1], %[temp5], 31 \n\t"
+ "beqz %[temp18], 5f \n\t"
+ "xor %[temp5], %[temp5], %[temp5] \n\t"
+ "movz %[temp5], %[temp6], %[temp1] \n\t"
+ "5: \n\t"
+ "sra %[temp18], %[temp8], 8 \n\t"
+ "sra %[temp1], %[temp8], 31 \n\t"
+ "beqz %[temp18], 6f \n\t"
+ "xor %[temp8], %[temp8], %[temp8] \n\t"
+ "movz %[temp8], %[temp6], %[temp1] \n\t"
+ "6: \n\t"
+ "sra %[temp18], %[temp11], 8 \n\t"
+ "sra %[temp1], %[temp11], 31 \n\t"
+ "sra %[temp17], %[temp16], 8 \n\t"
+ "sra %[temp15], %[temp16], 31 \n\t"
+ "beqz %[temp18], 7f \n\t"
+ "xor %[temp11], %[temp11], %[temp11] \n\t"
+ "movz %[temp11], %[temp6], %[temp1] \n\t"
+ "7: \n\t"
+ "beqz %[temp17], 8f \n\t"
+ "xor %[temp16], %[temp16], %[temp16] \n\t"
+ "movz %[temp16], %[temp6], %[temp15] \n\t"
+ "8: \n\t"
+ "sb %[temp5], 0+1*" XSTR(BPS) "(%[dst]) \n\t"
+ "sb %[temp8], 1+1*" XSTR(BPS) "(%[dst]) \n\t"
+ "sb %[temp11], 2+1*" XSTR(BPS) "(%[dst]) \n\t"
+ "sb %[temp16], 3+1*" XSTR(BPS) "(%[dst]) \n\t"
+ "lbu %[temp5], 0+2*" XSTR(BPS) "(%[dst]) \n\t"
+ "lbu %[temp8], 1+2*" XSTR(BPS) "(%[dst]) \n\t"
+ "lbu %[temp11], 2+2*" XSTR(BPS) "(%[dst]) \n\t"
+ "lbu %[temp16], 3+2*" XSTR(BPS) "(%[dst]) \n\t"
+ "addu %[temp5], %[temp5], %[temp9] \n\t"
+ "addu %[temp8], %[temp8], %[temp3] \n\t"
+ "addu %[temp11], %[temp11], %[temp0] \n\t"
+ "addu %[temp16], %[temp16], %[temp14] \n\t"
+ "sra %[temp18], %[temp5], 8 \n\t"
+ "sra %[temp1], %[temp5], 31 \n\t"
+ "sra %[temp17], %[temp8], 8 \n\t"
+ "sra %[temp15], %[temp8], 31 \n\t"
+ "sra %[temp12], %[temp11], 8 \n\t"
+ "sra %[temp10], %[temp11], 31 \n\t"
+ "sra %[temp9], %[temp16], 8 \n\t"
+ "sra %[temp3], %[temp16], 31 \n\t"
+ "beqz %[temp18], 9f \n\t"
+ "xor %[temp5], %[temp5], %[temp5] \n\t"
+ "movz %[temp5], %[temp6], %[temp1] \n\t"
+ "9: \n\t"
+ "beqz %[temp17], 10f \n\t"
+ "xor %[temp8], %[temp8], %[temp8] \n\t"
+ "movz %[temp8], %[temp6], %[temp15] \n\t"
+ "10: \n\t"
+ "beqz %[temp12], 11f \n\t"
+ "xor %[temp11], %[temp11], %[temp11] \n\t"
+ "movz %[temp11], %[temp6], %[temp10] \n\t"
+ "11: \n\t"
+ "beqz %[temp9], 12f \n\t"
+ "xor %[temp16], %[temp16], %[temp16] \n\t"
+ "movz %[temp16], %[temp6], %[temp3] \n\t"
+ "12: \n\t"
+ "sb %[temp5], 0+2*" XSTR(BPS) "(%[dst]) \n\t"
+ "sb %[temp8], 1+2*" XSTR(BPS) "(%[dst]) \n\t"
+ "sb %[temp11], 2+2*" XSTR(BPS) "(%[dst]) \n\t"
+ "sb %[temp16], 3+2*" XSTR(BPS) "(%[dst]) \n\t"
+ "lbu %[temp5], 0+3*" XSTR(BPS) "(%[dst]) \n\t"
+ "lbu %[temp8], 1+3*" XSTR(BPS) "(%[dst]) \n\t"
+ "lbu %[temp11], 2+3*" XSTR(BPS) "(%[dst]) \n\t"
+ "lbu %[temp16], 3+3*" XSTR(BPS) "(%[dst]) \n\t"
+ "addu %[temp5], %[temp5], %[temp13] \n\t"
+ "addu %[temp8], %[temp8], %[temp7] \n\t"
+ "addu %[temp11], %[temp11], %[temp4] \n\t"
+ "addu %[temp16], %[temp16], %[temp2] \n\t"
+ "sra %[temp18], %[temp5], 8 \n\t"
+ "sra %[temp1], %[temp5], 31 \n\t"
+ "sra %[temp17], %[temp8], 8 \n\t"
+ "sra %[temp15], %[temp8], 31 \n\t"
+ "sra %[temp12], %[temp11], 8 \n\t"
+ "sra %[temp10], %[temp11], 31 \n\t"
+ "sra %[temp9], %[temp16], 8 \n\t"
+ "sra %[temp3], %[temp16], 31 \n\t"
+ "beqz %[temp18], 13f \n\t"
+ "xor %[temp5], %[temp5], %[temp5] \n\t"
+ "movz %[temp5], %[temp6], %[temp1] \n\t"
+ "13: \n\t"
+ "beqz %[temp17], 14f \n\t"
+ "xor %[temp8], %[temp8], %[temp8] \n\t"
+ "movz %[temp8], %[temp6], %[temp15] \n\t"
+ "14: \n\t"
+ "beqz %[temp12], 15f \n\t"
+ "xor %[temp11], %[temp11], %[temp11] \n\t"
+ "movz %[temp11], %[temp6], %[temp10] \n\t"
+ "15: \n\t"
+ "beqz %[temp9], 16f \n\t"
+ "xor %[temp16], %[temp16], %[temp16] \n\t"
+ "movz %[temp16], %[temp6], %[temp3] \n\t"
+ "16: \n\t"
+ "sb %[temp5], 0+3*" XSTR(BPS) "(%[dst]) \n\t"
+ "sb %[temp8], 1+3*" XSTR(BPS) "(%[dst]) \n\t"
+ "sb %[temp11], 2+3*" XSTR(BPS) "(%[dst]) \n\t"
+ "sb %[temp16], 3+3*" XSTR(BPS) "(%[dst]) \n\t"
+
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8),
+ [temp9]"=&r"(temp9), [temp10]"=&r"(temp10), [temp11]"=&r"(temp11),
+ [temp12]"=&r"(temp12), [temp13]"=&r"(temp13), [temp14]"=&r"(temp14),
+ [temp15]"=&r"(temp15), [temp16]"=&r"(temp16), [temp17]"=&r"(temp17),
+ [temp18]"=&r"(temp18)
+ : [in]"r"(p_in), [kC1]"r"(kC1), [kC2]"r"(kC2), [dst]"r"(dst)
+ : "memory", "hi", "lo"
+ );
+}
+
+static void TransformTwo(const int16_t* in, uint8_t* dst, int do_two) {
+ TransformOne(in, dst);
+ if (do_two) {
+ TransformOne(in + 16, dst + 4);
+ }
+}
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8DspInitMIPS32(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8DspInitMIPS32(void) {
+ VP8InitClipTables();
+
+ VP8Transform = TransformTwo;
+
+ VP8VFilter16 = VFilter16;
+ VP8HFilter16 = HFilter16;
+ VP8VFilter8 = VFilter8;
+ VP8HFilter8 = HFilter8;
+ VP8VFilter16i = VFilter16i;
+ VP8HFilter16i = HFilter16i;
+ VP8VFilter8i = VFilter8i;
+ VP8HFilter8i = HFilter8i;
+
+ VP8SimpleVFilter16 = SimpleVFilter16;
+ VP8SimpleHFilter16 = SimpleHFilter16;
+ VP8SimpleVFilter16i = SimpleVFilter16i;
+ VP8SimpleHFilter16i = SimpleHFilter16i;
+}
+
+#else // !WEBP_USE_MIPS32
+
+WEBP_DSP_INIT_STUB(VP8DspInitMIPS32)
+
+#endif // WEBP_USE_MIPS32
diff --git a/drivers/webp/dsp/dec_mips_dsp_r2.c b/drivers/webp/dsp/dec_mips_dsp_r2.c
new file mode 100644
index 0000000000..db5c657228
--- /dev/null
+++ b/drivers/webp/dsp/dec_mips_dsp_r2.c
@@ -0,0 +1,994 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// MIPS version of dsp functions
+//
+// Author(s): Djordje Pesut (djordje.pesut@imgtec.com)
+// Jovan Zelincevic (jovan.zelincevic@imgtec.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_MIPS_DSP_R2)
+
+#include "./mips_macro.h"
+
+static const int kC1 = 20091 + (1 << 16);
+static const int kC2 = 35468;
+
+#define MUL(a, b) (((a) * (b)) >> 16)
+
+static void TransformDC(const int16_t* in, uint8_t* dst) {
+ int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9, temp10;
+
+ __asm__ volatile (
+ LOAD_WITH_OFFSET_X4(temp1, temp2, temp3, temp4, dst,
+ 0, 0, 0, 0,
+ 0, 1, 2, 3,
+ BPS)
+ "lh %[temp5], 0(%[in]) \n\t"
+ "addiu %[temp5], %[temp5], 4 \n\t"
+ "ins %[temp5], %[temp5], 16, 16 \n\t"
+ "shra.ph %[temp5], %[temp5], 3 \n\t"
+ CONVERT_2_BYTES_TO_HALF(temp6, temp7, temp8, temp9, temp10, temp1, temp2,
+ temp3, temp1, temp2, temp3, temp4)
+ STORE_SAT_SUM_X2(temp6, temp7, temp8, temp9, temp10, temp1, temp2, temp3,
+ temp5, temp5, temp5, temp5, temp5, temp5, temp5, temp5,
+ dst, 0, 1, 2, 3, BPS)
+
+ OUTPUT_EARLY_CLOBBER_REGS_10()
+ : [in]"r"(in), [dst]"r"(dst)
+ : "memory"
+ );
+}
+
+static void TransformAC3(const int16_t* in, uint8_t* dst) {
+ const int a = in[0] + 4;
+ int c4 = MUL(in[4], kC2);
+ const int d4 = MUL(in[4], kC1);
+ const int c1 = MUL(in[1], kC2);
+ const int d1 = MUL(in[1], kC1);
+ int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9;
+ int temp10, temp11, temp12, temp13, temp14, temp15, temp16, temp17, temp18;
+
+ __asm__ volatile (
+ "ins %[c4], %[d4], 16, 16 \n\t"
+ "replv.ph %[temp1], %[a] \n\t"
+ "replv.ph %[temp4], %[d1] \n\t"
+ ADD_SUB_HALVES(temp2, temp3, temp1, c4)
+ "replv.ph %[temp5], %[c1] \n\t"
+ SHIFT_R_SUM_X2(temp1, temp6, temp7, temp8, temp2, temp9, temp10, temp4,
+ temp2, temp2, temp3, temp3, temp4, temp5, temp4, temp5)
+ LOAD_WITH_OFFSET_X4(temp3, temp5, temp11, temp12, dst,
+ 0, 0, 0, 0,
+ 0, 1, 2, 3,
+ BPS)
+ CONVERT_2_BYTES_TO_HALF(temp13, temp14, temp3, temp15, temp5, temp16,
+ temp11, temp17, temp3, temp5, temp11, temp12)
+ PACK_2_HALVES_TO_WORD(temp12, temp18, temp7, temp6, temp1, temp8, temp2,
+ temp4, temp7, temp6, temp10, temp9)
+ STORE_SAT_SUM_X2(temp13, temp14, temp3, temp15, temp5, temp16, temp11,
+ temp17, temp12, temp18, temp1, temp8, temp2, temp4,
+ temp7, temp6, dst, 0, 1, 2, 3, BPS)
+
+ OUTPUT_EARLY_CLOBBER_REGS_18(),
+ [c4]"+&r"(c4)
+ : [dst]"r"(dst), [a]"r"(a), [d1]"r"(d1), [d4]"r"(d4), [c1]"r"(c1)
+ : "memory"
+ );
+}
+
+static void TransformOne(const int16_t* in, uint8_t* dst) {
+ int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9;
+ int temp10, temp11, temp12, temp13, temp14, temp15, temp16, temp17, temp18;
+
+ __asm__ volatile (
+ "ulw %[temp1], 0(%[in]) \n\t"
+ "ulw %[temp2], 16(%[in]) \n\t"
+ LOAD_IN_X2(temp5, temp6, 24, 26)
+ ADD_SUB_HALVES(temp3, temp4, temp1, temp2)
+ LOAD_IN_X2(temp1, temp2, 8, 10)
+ MUL_SHIFT_SUM(temp7, temp8, temp9, temp10, temp11, temp12, temp13, temp14,
+ temp10, temp8, temp9, temp7, temp1, temp2, temp5, temp6,
+ temp13, temp11, temp14, temp12)
+ INSERT_HALF_X2(temp8, temp7, temp10, temp9)
+ "ulw %[temp17], 4(%[in]) \n\t"
+ "ulw %[temp18], 20(%[in]) \n\t"
+ ADD_SUB_HALVES(temp1, temp2, temp3, temp8)
+ ADD_SUB_HALVES(temp5, temp6, temp4, temp7)
+ ADD_SUB_HALVES(temp7, temp8, temp17, temp18)
+ LOAD_IN_X2(temp17, temp18, 12, 14)
+ LOAD_IN_X2(temp9, temp10, 28, 30)
+ MUL_SHIFT_SUM(temp11, temp12, temp13, temp14, temp15, temp16, temp4, temp17,
+ temp12, temp14, temp11, temp13, temp17, temp18, temp9, temp10,
+ temp15, temp4, temp16, temp17)
+ INSERT_HALF_X2(temp11, temp12, temp13, temp14)
+ ADD_SUB_HALVES(temp17, temp8, temp8, temp11)
+ ADD_SUB_HALVES(temp3, temp4, temp7, temp12)
+
+ // horizontal
+ SRA_16(temp9, temp10, temp11, temp12, temp1, temp2, temp5, temp6)
+ INSERT_HALF_X2(temp1, temp6, temp5, temp2)
+ SRA_16(temp13, temp14, temp15, temp16, temp3, temp4, temp17, temp8)
+ "repl.ph %[temp2], 0x4 \n\t"
+ INSERT_HALF_X2(temp3, temp8, temp17, temp4)
+ "addq.ph %[temp1], %[temp1], %[temp2] \n\t"
+ "addq.ph %[temp6], %[temp6], %[temp2] \n\t"
+ ADD_SUB_HALVES(temp2, temp4, temp1, temp3)
+ ADD_SUB_HALVES(temp5, temp7, temp6, temp8)
+ MUL_SHIFT_SUM(temp1, temp3, temp6, temp8, temp9, temp13, temp17, temp18,
+ temp3, temp13, temp1, temp9, temp9, temp13, temp11, temp15,
+ temp6, temp17, temp8, temp18)
+ MUL_SHIFT_SUM(temp6, temp8, temp18, temp17, temp11, temp15, temp12, temp16,
+ temp8, temp15, temp6, temp11, temp12, temp16, temp10, temp14,
+ temp18, temp12, temp17, temp16)
+ INSERT_HALF_X2(temp1, temp3, temp9, temp13)
+ INSERT_HALF_X2(temp6, temp8, temp11, temp15)
+ SHIFT_R_SUM_X2(temp9, temp10, temp11, temp12, temp13, temp14, temp15,
+ temp16, temp2, temp4, temp5, temp7, temp3, temp1, temp8,
+ temp6)
+ PACK_2_HALVES_TO_WORD(temp1, temp2, temp3, temp4, temp9, temp12, temp13,
+ temp16, temp11, temp10, temp15, temp14)
+ LOAD_WITH_OFFSET_X4(temp10, temp11, temp14, temp15, dst,
+ 0, 0, 0, 0,
+ 0, 1, 2, 3,
+ BPS)
+ CONVERT_2_BYTES_TO_HALF(temp5, temp6, temp7, temp8, temp17, temp18, temp10,
+ temp11, temp10, temp11, temp14, temp15)
+ STORE_SAT_SUM_X2(temp5, temp6, temp7, temp8, temp17, temp18, temp10, temp11,
+ temp9, temp12, temp1, temp2, temp13, temp16, temp3, temp4,
+ dst, 0, 1, 2, 3, BPS)
+
+ OUTPUT_EARLY_CLOBBER_REGS_18()
+ : [dst]"r"(dst), [in]"r"(in), [kC1]"r"(kC1), [kC2]"r"(kC2)
+ : "memory", "hi", "lo"
+ );
+}
+
+static void TransformTwo(const int16_t* in, uint8_t* dst, int do_two) {
+ TransformOne(in, dst);
+ if (do_two) {
+ TransformOne(in + 16, dst + 4);
+ }
+}
+
+static WEBP_INLINE void FilterLoop26(uint8_t* p,
+ int hstride, int vstride, int size,
+ int thresh, int ithresh, int hev_thresh) {
+ const int thresh2 = 2 * thresh + 1;
+ int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9;
+ int temp10, temp11, temp12, temp13, temp14, temp15;
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "1: \n\t"
+ "negu %[temp1], %[hstride] \n\t"
+ "addiu %[size], %[size], -1 \n\t"
+ "sll %[temp2], %[hstride], 1 \n\t"
+ "sll %[temp3], %[temp1], 1 \n\t"
+ "addu %[temp4], %[temp2], %[hstride] \n\t"
+ "addu %[temp5], %[temp3], %[temp1] \n\t"
+ "lbu %[temp7], 0(%[p]) \n\t"
+ "sll %[temp6], %[temp3], 1 \n\t"
+ "lbux %[temp8], %[temp5](%[p]) \n\t"
+ "lbux %[temp9], %[temp3](%[p]) \n\t"
+ "lbux %[temp10], %[temp1](%[p]) \n\t"
+ "lbux %[temp11], %[temp6](%[p]) \n\t"
+ "lbux %[temp12], %[hstride](%[p]) \n\t"
+ "lbux %[temp13], %[temp2](%[p]) \n\t"
+ "lbux %[temp14], %[temp4](%[p]) \n\t"
+ "subu %[temp1], %[temp10], %[temp7] \n\t"
+ "subu %[temp2], %[temp9], %[temp12] \n\t"
+ "absq_s.w %[temp3], %[temp1] \n\t"
+ "absq_s.w %[temp4], %[temp2] \n\t"
+ "negu %[temp1], %[temp1] \n\t"
+ "sll %[temp3], %[temp3], 2 \n\t"
+ "addu %[temp15], %[temp3], %[temp4] \n\t"
+ "subu %[temp3], %[temp15], %[thresh2] \n\t"
+ "sll %[temp6], %[temp1], 1 \n\t"
+ "bgtz %[temp3], 3f \n\t"
+ " subu %[temp4], %[temp11], %[temp8] \n\t"
+ "absq_s.w %[temp4], %[temp4] \n\t"
+ "shll_s.w %[temp2], %[temp2], 24 \n\t"
+ "subu %[temp4], %[temp4], %[ithresh] \n\t"
+ "bgtz %[temp4], 3f \n\t"
+ " subu %[temp3], %[temp8], %[temp9] \n\t"
+ "absq_s.w %[temp3], %[temp3] \n\t"
+ "subu %[temp3], %[temp3], %[ithresh] \n\t"
+ "bgtz %[temp3], 3f \n\t"
+ " subu %[temp5], %[temp9], %[temp10] \n\t"
+ "absq_s.w %[temp3], %[temp5] \n\t"
+ "absq_s.w %[temp5], %[temp5] \n\t"
+ "subu %[temp3], %[temp3], %[ithresh] \n\t"
+ "bgtz %[temp3], 3f \n\t"
+ " subu %[temp3], %[temp14], %[temp13] \n\t"
+ "absq_s.w %[temp3], %[temp3] \n\t"
+ "slt %[temp5], %[hev_thresh], %[temp5] \n\t"
+ "subu %[temp3], %[temp3], %[ithresh] \n\t"
+ "bgtz %[temp3], 3f \n\t"
+ " subu %[temp3], %[temp13], %[temp12] \n\t"
+ "absq_s.w %[temp3], %[temp3] \n\t"
+ "sra %[temp4], %[temp2], 24 \n\t"
+ "subu %[temp3], %[temp3], %[ithresh] \n\t"
+ "bgtz %[temp3], 3f \n\t"
+ " subu %[temp15], %[temp12], %[temp7] \n\t"
+ "absq_s.w %[temp3], %[temp15] \n\t"
+ "absq_s.w %[temp15], %[temp15] \n\t"
+ "subu %[temp3], %[temp3], %[ithresh] \n\t"
+ "bgtz %[temp3], 3f \n\t"
+ " slt %[temp15], %[hev_thresh], %[temp15] \n\t"
+ "addu %[temp3], %[temp6], %[temp1] \n\t"
+ "or %[temp2], %[temp5], %[temp15] \n\t"
+ "addu %[temp5], %[temp4], %[temp3] \n\t"
+ "beqz %[temp2], 4f \n\t"
+ " shra_r.w %[temp1], %[temp5], 3 \n\t"
+ "addiu %[temp2], %[temp5], 3 \n\t"
+ "sra %[temp2], %[temp2], 3 \n\t"
+ "shll_s.w %[temp1], %[temp1], 27 \n\t"
+ "shll_s.w %[temp2], %[temp2], 27 \n\t"
+ "subu %[temp3], %[p], %[hstride] \n\t"
+ "sra %[temp1], %[temp1], 27 \n\t"
+ "sra %[temp2], %[temp2], 27 \n\t"
+ "subu %[temp1], %[temp7], %[temp1] \n\t"
+ "addu %[temp2], %[temp10], %[temp2] \n\t"
+ "lbux %[temp2], %[temp2](%[VP8kclip1]) \n\t"
+ "lbux %[temp1], %[temp1](%[VP8kclip1]) \n\t"
+ "sb %[temp2], 0(%[temp3]) \n\t"
+ "j 3f \n\t"
+ " sb %[temp1], 0(%[p]) \n\t"
+ "4: \n\t"
+ "shll_s.w %[temp5], %[temp5], 24 \n\t"
+ "subu %[temp14], %[p], %[hstride] \n\t"
+ "subu %[temp11], %[temp14], %[hstride] \n\t"
+ "sra %[temp6], %[temp5], 24 \n\t"
+ "sll %[temp1], %[temp6], 3 \n\t"
+ "subu %[temp15], %[temp11], %[hstride] \n\t"
+ "addu %[temp2], %[temp6], %[temp1] \n\t"
+ "sll %[temp3], %[temp2], 1 \n\t"
+ "addu %[temp4], %[temp3], %[temp2] \n\t"
+ "addiu %[temp2], %[temp2], 63 \n\t"
+ "addiu %[temp3], %[temp3], 63 \n\t"
+ "addiu %[temp4], %[temp4], 63 \n\t"
+ "sra %[temp2], %[temp2], 7 \n\t"
+ "sra %[temp3], %[temp3], 7 \n\t"
+ "sra %[temp4], %[temp4], 7 \n\t"
+ "addu %[temp1], %[temp8], %[temp2] \n\t"
+ "addu %[temp5], %[temp9], %[temp3] \n\t"
+ "addu %[temp6], %[temp10], %[temp4] \n\t"
+ "subu %[temp8], %[temp7], %[temp4] \n\t"
+ "subu %[temp7], %[temp12], %[temp3] \n\t"
+ "addu %[temp10], %[p], %[hstride] \n\t"
+ "subu %[temp9], %[temp13], %[temp2] \n\t"
+ "addu %[temp12], %[temp10], %[hstride] \n\t"
+ "lbux %[temp2], %[temp1](%[VP8kclip1]) \n\t"
+ "lbux %[temp3], %[temp5](%[VP8kclip1]) \n\t"
+ "lbux %[temp4], %[temp6](%[VP8kclip1]) \n\t"
+ "lbux %[temp5], %[temp8](%[VP8kclip1]) \n\t"
+ "lbux %[temp6], %[temp7](%[VP8kclip1]) \n\t"
+ "lbux %[temp8], %[temp9](%[VP8kclip1]) \n\t"
+ "sb %[temp2], 0(%[temp15]) \n\t"
+ "sb %[temp3], 0(%[temp11]) \n\t"
+ "sb %[temp4], 0(%[temp14]) \n\t"
+ "sb %[temp5], 0(%[p]) \n\t"
+ "sb %[temp6], 0(%[temp10]) \n\t"
+ "sb %[temp8], 0(%[temp12]) \n\t"
+ "3: \n\t"
+ "bgtz %[size], 1b \n\t"
+ " addu %[p], %[p], %[vstride] \n\t"
+ ".set pop \n\t"
+ : [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),[temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [temp6]"=&r"(temp6),
+ [temp7]"=&r"(temp7),[temp8]"=&r"(temp8),[temp9]"=&r"(temp9),
+ [temp10]"=&r"(temp10),[temp11]"=&r"(temp11),[temp12]"=&r"(temp12),
+ [temp13]"=&r"(temp13),[temp14]"=&r"(temp14),[temp15]"=&r"(temp15),
+ [size]"+&r"(size), [p]"+&r"(p)
+ : [hstride]"r"(hstride), [thresh2]"r"(thresh2),
+ [ithresh]"r"(ithresh),[vstride]"r"(vstride), [hev_thresh]"r"(hev_thresh),
+ [VP8kclip1]"r"(VP8kclip1)
+ : "memory"
+ );
+}
+
+static WEBP_INLINE void FilterLoop24(uint8_t* p,
+ int hstride, int vstride, int size,
+ int thresh, int ithresh, int hev_thresh) {
+ int p0, q0, p1, q1, p2, q2, p3, q3;
+ int step1, step2, temp1, temp2, temp3, temp4;
+ uint8_t* pTemp0;
+ uint8_t* pTemp1;
+ const int thresh2 = 2 * thresh + 1;
+
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "bltz %[size], 3f \n\t"
+ " nop \n\t"
+ "2: \n\t"
+ "negu %[step1], %[hstride] \n\t"
+ "lbu %[q0], 0(%[p]) \n\t"
+ "lbux %[p0], %[step1](%[p]) \n\t"
+ "subu %[step1], %[step1], %[hstride] \n\t"
+ "lbux %[q1], %[hstride](%[p]) \n\t"
+ "subu %[temp1], %[p0], %[q0] \n\t"
+ "lbux %[p1], %[step1](%[p]) \n\t"
+ "addu %[step2], %[hstride], %[hstride] \n\t"
+ "absq_s.w %[temp2], %[temp1] \n\t"
+ "subu %[temp3], %[p1], %[q1] \n\t"
+ "absq_s.w %[temp4], %[temp3] \n\t"
+ "sll %[temp2], %[temp2], 2 \n\t"
+ "addu %[temp2], %[temp2], %[temp4] \n\t"
+ "subu %[temp4], %[temp2], %[thresh2] \n\t"
+ "subu %[step1], %[step1], %[hstride] \n\t"
+ "bgtz %[temp4], 0f \n\t"
+ " lbux %[p2], %[step1](%[p]) \n\t"
+ "subu %[step1], %[step1], %[hstride] \n\t"
+ "lbux %[q2], %[step2](%[p]) \n\t"
+ "lbux %[p3], %[step1](%[p]) \n\t"
+ "subu %[temp4], %[p2], %[p1] \n\t"
+ "addu %[step2], %[step2], %[hstride] \n\t"
+ "subu %[temp2], %[p3], %[p2] \n\t"
+ "absq_s.w %[temp4], %[temp4] \n\t"
+ "absq_s.w %[temp2], %[temp2] \n\t"
+ "lbux %[q3], %[step2](%[p]) \n\t"
+ "subu %[temp4], %[temp4], %[ithresh] \n\t"
+ "negu %[temp1], %[temp1] \n\t"
+ "bgtz %[temp4], 0f \n\t"
+ " subu %[temp2], %[temp2], %[ithresh] \n\t"
+ "subu %[p3], %[p1], %[p0] \n\t"
+ "bgtz %[temp2], 0f \n\t"
+ " absq_s.w %[p3], %[p3] \n\t"
+ "subu %[temp4], %[q3], %[q2] \n\t"
+ "subu %[pTemp0], %[p], %[hstride] \n\t"
+ "absq_s.w %[temp4], %[temp4] \n\t"
+ "subu %[temp2], %[p3], %[ithresh] \n\t"
+ "sll %[step1], %[temp1], 1 \n\t"
+ "bgtz %[temp2], 0f \n\t"
+ " subu %[temp4], %[temp4], %[ithresh] \n\t"
+ "subu %[temp2], %[q2], %[q1] \n\t"
+ "bgtz %[temp4], 0f \n\t"
+ " absq_s.w %[temp2], %[temp2] \n\t"
+ "subu %[q3], %[q1], %[q0] \n\t"
+ "absq_s.w %[q3], %[q3] \n\t"
+ "subu %[temp2], %[temp2], %[ithresh] \n\t"
+ "addu %[temp1], %[temp1], %[step1] \n\t"
+ "bgtz %[temp2], 0f \n\t"
+ " subu %[temp4], %[q3], %[ithresh] \n\t"
+ "slt %[p3], %[hev_thresh], %[p3] \n\t"
+ "bgtz %[temp4], 0f \n\t"
+ " slt %[q3], %[hev_thresh], %[q3] \n\t"
+ "or %[q3], %[q3], %[p3] \n\t"
+ "bgtz %[q3], 1f \n\t"
+ " shra_r.w %[temp2], %[temp1], 3 \n\t"
+ "addiu %[temp1], %[temp1], 3 \n\t"
+ "sra %[temp1], %[temp1], 3 \n\t"
+ "shll_s.w %[temp2], %[temp2], 27 \n\t"
+ "shll_s.w %[temp1], %[temp1], 27 \n\t"
+ "addu %[pTemp1], %[p], %[hstride] \n\t"
+ "sra %[temp2], %[temp2], 27 \n\t"
+ "sra %[temp1], %[temp1], 27 \n\t"
+ "addiu %[step1], %[temp2], 1 \n\t"
+ "sra %[step1], %[step1], 1 \n\t"
+ "addu %[p0], %[p0], %[temp1] \n\t"
+ "addu %[p1], %[p1], %[step1] \n\t"
+ "subu %[q0], %[q0], %[temp2] \n\t"
+ "subu %[q1], %[q1], %[step1] \n\t"
+ "lbux %[temp2], %[p0](%[VP8kclip1]) \n\t"
+ "lbux %[temp3], %[q0](%[VP8kclip1]) \n\t"
+ "lbux %[temp4], %[q1](%[VP8kclip1]) \n\t"
+ "sb %[temp2], 0(%[pTemp0]) \n\t"
+ "lbux %[temp1], %[p1](%[VP8kclip1]) \n\t"
+ "subu %[pTemp0], %[pTemp0], %[hstride] \n\t"
+ "sb %[temp3], 0(%[p]) \n\t"
+ "sb %[temp4], 0(%[pTemp1]) \n\t"
+ "j 0f \n\t"
+ " sb %[temp1], 0(%[pTemp0]) \n\t"
+ "1: \n\t"
+ "shll_s.w %[temp3], %[temp3], 24 \n\t"
+ "sra %[temp3], %[temp3], 24 \n\t"
+ "addu %[temp1], %[temp1], %[temp3] \n\t"
+ "shra_r.w %[temp2], %[temp1], 3 \n\t"
+ "addiu %[temp1], %[temp1], 3 \n\t"
+ "shll_s.w %[temp2], %[temp2], 27 \n\t"
+ "sra %[temp1], %[temp1], 3 \n\t"
+ "shll_s.w %[temp1], %[temp1], 27 \n\t"
+ "sra %[temp2], %[temp2], 27 \n\t"
+ "sra %[temp1], %[temp1], 27 \n\t"
+ "addu %[p0], %[p0], %[temp1] \n\t"
+ "subu %[q0], %[q0], %[temp2] \n\t"
+ "lbux %[temp1], %[p0](%[VP8kclip1]) \n\t"
+ "lbux %[temp2], %[q0](%[VP8kclip1]) \n\t"
+ "sb %[temp2], 0(%[p]) \n\t"
+ "sb %[temp1], 0(%[pTemp0]) \n\t"
+ "0: \n\t"
+ "subu %[size], %[size], 1 \n\t"
+ "bgtz %[size], 2b \n\t"
+ " addu %[p], %[p], %[vstride] \n\t"
+ "3: \n\t"
+ ".set pop \n\t"
+ : [p0]"=&r"(p0), [q0]"=&r"(q0), [p1]"=&r"(p1), [q1]"=&r"(q1),
+ [p2]"=&r"(p2), [q2]"=&r"(q2), [p3]"=&r"(p3), [q3]"=&r"(q3),
+ [step2]"=&r"(step2), [step1]"=&r"(step1), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), [temp4]"=&r"(temp4),
+ [pTemp0]"=&r"(pTemp0), [pTemp1]"=&r"(pTemp1), [p]"+&r"(p),
+ [size]"+&r"(size)
+ : [vstride]"r"(vstride), [ithresh]"r"(ithresh),
+ [hev_thresh]"r"(hev_thresh), [hstride]"r"(hstride),
+ [VP8kclip1]"r"(VP8kclip1), [thresh2]"r"(thresh2)
+ : "memory"
+ );
+}
+
+// on macroblock edges
+static void VFilter16(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop26(p, stride, 1, 16, thresh, ithresh, hev_thresh);
+}
+
+static void HFilter16(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop26(p, 1, stride, 16, thresh, ithresh, hev_thresh);
+}
+
+// 8-pixels wide variant, for chroma filtering
+static void VFilter8(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop26(u, stride, 1, 8, thresh, ithresh, hev_thresh);
+ FilterLoop26(v, stride, 1, 8, thresh, ithresh, hev_thresh);
+}
+
+static void HFilter8(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop26(u, 1, stride, 8, thresh, ithresh, hev_thresh);
+ FilterLoop26(v, 1, stride, 8, thresh, ithresh, hev_thresh);
+}
+
+// on three inner edges
+static void VFilter16i(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ int k;
+ for (k = 3; k > 0; --k) {
+ p += 4 * stride;
+ FilterLoop24(p, stride, 1, 16, thresh, ithresh, hev_thresh);
+ }
+}
+
+static void HFilter16i(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ int k;
+ for (k = 3; k > 0; --k) {
+ p += 4;
+ FilterLoop24(p, 1, stride, 16, thresh, ithresh, hev_thresh);
+ }
+}
+
+static void VFilter8i(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop24(u + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh);
+ FilterLoop24(v + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh);
+}
+
+static void HFilter8i(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop24(u + 4, 1, stride, 8, thresh, ithresh, hev_thresh);
+ FilterLoop24(v + 4, 1, stride, 8, thresh, ithresh, hev_thresh);
+}
+
+#undef MUL
+
+//------------------------------------------------------------------------------
+// Simple In-loop filtering (Paragraph 15.2)
+
+static void SimpleVFilter16(uint8_t* p, int stride, int thresh) {
+ int i;
+ const int thresh2 = 2 * thresh + 1;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8;
+ uint8_t* p1 = p - stride;
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "li %[i], 16 \n\t"
+ "0: \n\t"
+ "negu %[temp4], %[stride] \n\t"
+ "sll %[temp5], %[temp4], 1 \n\t"
+ "lbu %[temp2], 0(%[p]) \n\t"
+ "lbux %[temp3], %[stride](%[p]) \n\t"
+ "lbux %[temp1], %[temp4](%[p]) \n\t"
+ "lbux %[temp0], %[temp5](%[p]) \n\t"
+ "subu %[temp7], %[temp1], %[temp2] \n\t"
+ "subu %[temp6], %[temp0], %[temp3] \n\t"
+ "absq_s.w %[temp4], %[temp7] \n\t"
+ "absq_s.w %[temp5], %[temp6] \n\t"
+ "sll %[temp4], %[temp4], 2 \n\t"
+ "subu %[temp5], %[temp5], %[thresh2] \n\t"
+ "addu %[temp5], %[temp4], %[temp5] \n\t"
+ "negu %[temp8], %[temp7] \n\t"
+ "bgtz %[temp5], 1f \n\t"
+ " addiu %[i], %[i], -1 \n\t"
+ "sll %[temp4], %[temp8], 1 \n\t"
+ "shll_s.w %[temp5], %[temp6], 24 \n\t"
+ "addu %[temp3], %[temp4], %[temp8] \n\t"
+ "sra %[temp5], %[temp5], 24 \n\t"
+ "addu %[temp3], %[temp3], %[temp5] \n\t"
+ "addiu %[temp7], %[temp3], 3 \n\t"
+ "sra %[temp7], %[temp7], 3 \n\t"
+ "shra_r.w %[temp8], %[temp3], 3 \n\t"
+ "shll_s.w %[temp0], %[temp7], 27 \n\t"
+ "shll_s.w %[temp4], %[temp8], 27 \n\t"
+ "sra %[temp0], %[temp0], 27 \n\t"
+ "sra %[temp4], %[temp4], 27 \n\t"
+ "addu %[temp7], %[temp1], %[temp0] \n\t"
+ "subu %[temp2], %[temp2], %[temp4] \n\t"
+ "lbux %[temp3], %[temp7](%[VP8kclip1]) \n\t"
+ "lbux %[temp4], %[temp2](%[VP8kclip1]) \n\t"
+ "sb %[temp3], 0(%[p1]) \n\t"
+ "sb %[temp4], 0(%[p]) \n\t"
+ "1: \n\t"
+ "addiu %[p1], %[p1], 1 \n\t"
+ "bgtz %[i], 0b \n\t"
+ " addiu %[p], %[p], 1 \n\t"
+ " .set pop \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8),
+ [p]"+&r"(p), [i]"=&r"(i), [p1]"+&r"(p1)
+ : [stride]"r"(stride), [VP8kclip1]"r"(VP8kclip1), [thresh2]"r"(thresh2)
+ : "memory"
+ );
+}
+
+// TEMP0 = SRC[A + A1 * BPS]
+// TEMP1 = SRC[B + B1 * BPS]
+// TEMP2 = SRC[C + C1 * BPS]
+// TEMP3 = SRC[D + D1 * BPS]
+#define LOAD_4_BYTES(TEMP0, TEMP1, TEMP2, TEMP3, \
+ A, A1, B, B1, C, C1, D, D1, SRC) \
+ "lbu %[" #TEMP0 "], " #A "+" #A1 "*" XSTR(BPS) "(%[" #SRC "]) \n\t" \
+ "lbu %[" #TEMP1 "], " #B "+" #B1 "*" XSTR(BPS) "(%[" #SRC "]) \n\t" \
+ "lbu %[" #TEMP2 "], " #C "+" #C1 "*" XSTR(BPS) "(%[" #SRC "]) \n\t" \
+ "lbu %[" #TEMP3 "], " #D "+" #D1 "*" XSTR(BPS) "(%[" #SRC "]) \n\t" \
+
+static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
+ int i;
+ const int thresh2 = 2 * thresh + 1;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8;
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "li %[i], 16 \n\t"
+ "0: \n\t"
+ LOAD_4_BYTES(temp0, temp1, temp2, temp3, -2, 0, -1, 0, 0, 0, 1, 0, p)
+ "subu %[temp7], %[temp1], %[temp2] \n\t"
+ "subu %[temp6], %[temp0], %[temp3] \n\t"
+ "absq_s.w %[temp4], %[temp7] \n\t"
+ "absq_s.w %[temp5], %[temp6] \n\t"
+ "sll %[temp4], %[temp4], 2 \n\t"
+ "addu %[temp5], %[temp4], %[temp5] \n\t"
+ "subu %[temp5], %[temp5], %[thresh2] \n\t"
+ "negu %[temp8], %[temp7] \n\t"
+ "bgtz %[temp5], 1f \n\t"
+ " addiu %[i], %[i], -1 \n\t"
+ "sll %[temp4], %[temp8], 1 \n\t"
+ "shll_s.w %[temp5], %[temp6], 24 \n\t"
+ "addu %[temp3], %[temp4], %[temp8] \n\t"
+ "sra %[temp5], %[temp5], 24 \n\t"
+ "addu %[temp3], %[temp3], %[temp5] \n\t"
+ "addiu %[temp7], %[temp3], 3 \n\t"
+ "sra %[temp7], %[temp7], 3 \n\t"
+ "shra_r.w %[temp8], %[temp3], 3 \n\t"
+ "shll_s.w %[temp0], %[temp7], 27 \n\t"
+ "shll_s.w %[temp4], %[temp8], 27 \n\t"
+ "sra %[temp0], %[temp0], 27 \n\t"
+ "sra %[temp4], %[temp4], 27 \n\t"
+ "addu %[temp7], %[temp1], %[temp0] \n\t"
+ "subu %[temp2], %[temp2], %[temp4] \n\t"
+ "lbux %[temp3], %[temp7](%[VP8kclip1]) \n\t"
+ "lbux %[temp4], %[temp2](%[VP8kclip1]) \n\t"
+ "sb %[temp3], -1(%[p]) \n\t"
+ "sb %[temp4], 0(%[p]) \n\t"
+ "1: \n\t"
+ "bgtz %[i], 0b \n\t"
+ " addu %[p], %[p], %[stride] \n\t"
+ ".set pop \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8),
+ [p]"+&r"(p), [i]"=&r"(i)
+ : [stride]"r"(stride), [VP8kclip1]"r"(VP8kclip1), [thresh2]"r"(thresh2)
+ : "memory"
+ );
+}
+
+static void SimpleVFilter16i(uint8_t* p, int stride, int thresh) {
+ int k;
+ for (k = 3; k > 0; --k) {
+ p += 4 * stride;
+ SimpleVFilter16(p, stride, thresh);
+ }
+}
+
+static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) {
+ int k;
+ for (k = 3; k > 0; --k) {
+ p += 4;
+ SimpleHFilter16(p, stride, thresh);
+ }
+}
+
+// DST[A * BPS] = TEMP0
+// DST[B + C * BPS] = TEMP1
+#define STORE_8_BYTES(TEMP0, TEMP1, A, B, C, DST) \
+ "usw %[" #TEMP0 "], " #A "*" XSTR(BPS) "(%[" #DST "]) \n\t" \
+ "usw %[" #TEMP1 "], " #B "+" #C "*" XSTR(BPS) "(%[" #DST "]) \n\t"
+
+static void VE4(uint8_t* dst) { // vertical
+ const uint8_t* top = dst - BPS;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6;
+ __asm__ volatile (
+ "ulw %[temp0], -1(%[top]) \n\t"
+ "ulh %[temp1], 3(%[top]) \n\t"
+ "preceu.ph.qbr %[temp2], %[temp0] \n\t"
+ "preceu.ph.qbl %[temp3], %[temp0] \n\t"
+ "preceu.ph.qbr %[temp4], %[temp1] \n\t"
+ "packrl.ph %[temp5], %[temp3], %[temp2] \n\t"
+ "packrl.ph %[temp6], %[temp4], %[temp3] \n\t"
+ "shll.ph %[temp5], %[temp5], 1 \n\t"
+ "shll.ph %[temp6], %[temp6], 1 \n\t"
+ "addq.ph %[temp2], %[temp5], %[temp2] \n\t"
+ "addq.ph %[temp6], %[temp6], %[temp4] \n\t"
+ "addq.ph %[temp2], %[temp2], %[temp3] \n\t"
+ "addq.ph %[temp6], %[temp6], %[temp3] \n\t"
+ "shra_r.ph %[temp2], %[temp2], 2 \n\t"
+ "shra_r.ph %[temp6], %[temp6], 2 \n\t"
+ "precr.qb.ph %[temp4], %[temp6], %[temp2] \n\t"
+ STORE_8_BYTES(temp4, temp4, 0, 0, 1, dst)
+ STORE_8_BYTES(temp4, temp4, 2, 0, 3, dst)
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6)
+ : [top]"r"(top), [dst]"r"(dst)
+ : "memory"
+ );
+}
+
+static void DC4(uint8_t* dst) { // DC
+ int temp0, temp1, temp2, temp3, temp4;
+ __asm__ volatile (
+ "ulw %[temp0], -1*" XSTR(BPS) "(%[dst]) \n\t"
+ LOAD_4_BYTES(temp1, temp2, temp3, temp4, -1, 0, -1, 1, -1, 2, -1, 3, dst)
+ "ins %[temp1], %[temp2], 8, 8 \n\t"
+ "ins %[temp1], %[temp3], 16, 8 \n\t"
+ "ins %[temp1], %[temp4], 24, 8 \n\t"
+ "raddu.w.qb %[temp0], %[temp0] \n\t"
+ "raddu.w.qb %[temp1], %[temp1] \n\t"
+ "addu %[temp0], %[temp0], %[temp1] \n\t"
+ "shra_r.w %[temp0], %[temp0], 3 \n\t"
+ "replv.qb %[temp0], %[temp0] \n\t"
+ STORE_8_BYTES(temp0, temp0, 0, 0, 1, dst)
+ STORE_8_BYTES(temp0, temp0, 2, 0, 3, dst)
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4)
+ : [dst]"r"(dst)
+ : "memory"
+ );
+}
+
+static void RD4(uint8_t* dst) { // Down-right
+ int temp0, temp1, temp2, temp3, temp4;
+ int temp5, temp6, temp7, temp8;
+ __asm__ volatile (
+ LOAD_4_BYTES(temp0, temp1, temp2, temp3, -1, 0, -1, 1, -1, 2, -1, 3, dst)
+ "ulw %[temp7], -1-" XSTR(BPS) "(%[dst]) \n\t"
+ "ins %[temp1], %[temp0], 16, 16 \n\t"
+ "preceu.ph.qbr %[temp5], %[temp7] \n\t"
+ "ins %[temp2], %[temp1], 16, 16 \n\t"
+ "preceu.ph.qbl %[temp4], %[temp7] \n\t"
+ "ins %[temp3], %[temp2], 16, 16 \n\t"
+ "shll.ph %[temp2], %[temp2], 1 \n\t"
+ "addq.ph %[temp3], %[temp3], %[temp1] \n\t"
+ "packrl.ph %[temp6], %[temp5], %[temp1] \n\t"
+ "addq.ph %[temp3], %[temp3], %[temp2] \n\t"
+ "addq.ph %[temp1], %[temp1], %[temp5] \n\t"
+ "shll.ph %[temp6], %[temp6], 1 \n\t"
+ "addq.ph %[temp1], %[temp1], %[temp6] \n\t"
+ "packrl.ph %[temp0], %[temp4], %[temp5] \n\t"
+ "addq.ph %[temp8], %[temp5], %[temp4] \n\t"
+ "shra_r.ph %[temp3], %[temp3], 2 \n\t"
+ "shll.ph %[temp0], %[temp0], 1 \n\t"
+ "shra_r.ph %[temp1], %[temp1], 2 \n\t"
+ "addq.ph %[temp8], %[temp0], %[temp8] \n\t"
+ "lbu %[temp5], 3-" XSTR(BPS) "(%[dst]) \n\t"
+ "precrq.ph.w %[temp7], %[temp7], %[temp7] \n\t"
+ "shra_r.ph %[temp8], %[temp8], 2 \n\t"
+ "ins %[temp7], %[temp5], 0, 8 \n\t"
+ "precr.qb.ph %[temp2], %[temp1], %[temp3] \n\t"
+ "raddu.w.qb %[temp4], %[temp7] \n\t"
+ "precr.qb.ph %[temp6], %[temp8], %[temp1] \n\t"
+ "shra_r.w %[temp4], %[temp4], 2 \n\t"
+ STORE_8_BYTES(temp2, temp6, 3, 0, 1, dst)
+ "prepend %[temp2], %[temp8], 8 \n\t"
+ "prepend %[temp6], %[temp4], 8 \n\t"
+ STORE_8_BYTES(temp2, temp6, 2, 0, 0, dst)
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8)
+ : [dst]"r"(dst)
+ : "memory"
+ );
+}
+
+// TEMP0 = SRC[A * BPS]
+// TEMP1 = SRC[B + C * BPS]
+#define LOAD_8_BYTES(TEMP0, TEMP1, A, B, C, SRC) \
+ "ulw %[" #TEMP0 "], " #A "*" XSTR(BPS) "(%[" #SRC "]) \n\t" \
+ "ulw %[" #TEMP1 "], " #B "+" #C "*" XSTR(BPS) "(%[" #SRC "]) \n\t"
+
+static void LD4(uint8_t* dst) { // Down-Left
+ int temp0, temp1, temp2, temp3, temp4;
+ int temp5, temp6, temp7, temp8, temp9;
+ __asm__ volatile (
+ LOAD_8_BYTES(temp0, temp1, -1, 4, -1, dst)
+ "preceu.ph.qbl %[temp2], %[temp0] \n\t"
+ "preceu.ph.qbr %[temp3], %[temp0] \n\t"
+ "preceu.ph.qbr %[temp4], %[temp1] \n\t"
+ "preceu.ph.qbl %[temp5], %[temp1] \n\t"
+ "packrl.ph %[temp6], %[temp2], %[temp3] \n\t"
+ "packrl.ph %[temp7], %[temp4], %[temp2] \n\t"
+ "packrl.ph %[temp8], %[temp5], %[temp4] \n\t"
+ "shll.ph %[temp6], %[temp6], 1 \n\t"
+ "addq.ph %[temp9], %[temp2], %[temp6] \n\t"
+ "shll.ph %[temp7], %[temp7], 1 \n\t"
+ "addq.ph %[temp9], %[temp9], %[temp3] \n\t"
+ "shll.ph %[temp8], %[temp8], 1 \n\t"
+ "shra_r.ph %[temp9], %[temp9], 2 \n\t"
+ "addq.ph %[temp3], %[temp4], %[temp7] \n\t"
+ "addq.ph %[temp0], %[temp5], %[temp8] \n\t"
+ "addq.ph %[temp3], %[temp3], %[temp2] \n\t"
+ "addq.ph %[temp0], %[temp0], %[temp4] \n\t"
+ "shra_r.ph %[temp3], %[temp3], 2 \n\t"
+ "shra_r.ph %[temp0], %[temp0], 2 \n\t"
+ "srl %[temp1], %[temp1], 24 \n\t"
+ "sll %[temp1], %[temp1], 1 \n\t"
+ "raddu.w.qb %[temp5], %[temp5] \n\t"
+ "precr.qb.ph %[temp9], %[temp3], %[temp9] \n\t"
+ "precr.qb.ph %[temp3], %[temp0], %[temp3] \n\t"
+ "addu %[temp1], %[temp1], %[temp5] \n\t"
+ "shra_r.w %[temp1], %[temp1], 2 \n\t"
+ STORE_8_BYTES(temp9, temp3, 0, 0, 2, dst)
+ "prepend %[temp9], %[temp0], 8 \n\t"
+ "prepend %[temp3], %[temp1], 8 \n\t"
+ STORE_8_BYTES(temp9, temp3, 1, 0, 3, dst)
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8),
+ [temp9]"=&r"(temp9)
+ : [dst]"r"(dst)
+ : "memory"
+ );
+}
+
+//------------------------------------------------------------------------------
+// Chroma
+
+static void DC8uv(uint8_t* dst) { // DC
+ int temp0, temp1, temp2, temp3, temp4;
+ int temp5, temp6, temp7, temp8, temp9;
+ __asm__ volatile (
+ LOAD_8_BYTES(temp0, temp1, -1, 4, -1, dst)
+ LOAD_4_BYTES(temp2, temp3, temp4, temp5, -1, 0, -1, 1, -1, 2, -1, 3, dst)
+ LOAD_4_BYTES(temp6, temp7, temp8, temp9, -1, 4, -1, 5, -1, 6, -1, 7, dst)
+ "raddu.w.qb %[temp0], %[temp0] \n\t"
+ "raddu.w.qb %[temp1], %[temp1] \n\t"
+ "addu %[temp2], %[temp2], %[temp3] \n\t"
+ "addu %[temp4], %[temp4], %[temp5] \n\t"
+ "addu %[temp6], %[temp6], %[temp7] \n\t"
+ "addu %[temp8], %[temp8], %[temp9] \n\t"
+ "addu %[temp0], %[temp0], %[temp1] \n\t"
+ "addu %[temp2], %[temp2], %[temp4] \n\t"
+ "addu %[temp6], %[temp6], %[temp8] \n\t"
+ "addu %[temp0], %[temp0], %[temp2] \n\t"
+ "addu %[temp0], %[temp0], %[temp6] \n\t"
+ "shra_r.w %[temp0], %[temp0], 4 \n\t"
+ "replv.qb %[temp0], %[temp0] \n\t"
+ STORE_8_BYTES(temp0, temp0, 0, 4, 0, dst)
+ STORE_8_BYTES(temp0, temp0, 1, 4, 1, dst)
+ STORE_8_BYTES(temp0, temp0, 2, 4, 2, dst)
+ STORE_8_BYTES(temp0, temp0, 3, 4, 3, dst)
+ STORE_8_BYTES(temp0, temp0, 4, 4, 4, dst)
+ STORE_8_BYTES(temp0, temp0, 5, 4, 5, dst)
+ STORE_8_BYTES(temp0, temp0, 6, 4, 6, dst)
+ STORE_8_BYTES(temp0, temp0, 7, 4, 7, dst)
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8),
+ [temp9]"=&r"(temp9)
+ : [dst]"r"(dst)
+ : "memory"
+ );
+}
+
+static void DC8uvNoLeft(uint8_t* dst) { // DC with no left samples
+ int temp0, temp1;
+ __asm__ volatile (
+ LOAD_8_BYTES(temp0, temp1, -1, 4, -1, dst)
+ "raddu.w.qb %[temp0], %[temp0] \n\t"
+ "raddu.w.qb %[temp1], %[temp1] \n\t"
+ "addu %[temp0], %[temp0], %[temp1] \n\t"
+ "shra_r.w %[temp0], %[temp0], 3 \n\t"
+ "replv.qb %[temp0], %[temp0] \n\t"
+ STORE_8_BYTES(temp0, temp0, 0, 4, 0, dst)
+ STORE_8_BYTES(temp0, temp0, 1, 4, 1, dst)
+ STORE_8_BYTES(temp0, temp0, 2, 4, 2, dst)
+ STORE_8_BYTES(temp0, temp0, 3, 4, 3, dst)
+ STORE_8_BYTES(temp0, temp0, 4, 4, 4, dst)
+ STORE_8_BYTES(temp0, temp0, 5, 4, 5, dst)
+ STORE_8_BYTES(temp0, temp0, 6, 4, 6, dst)
+ STORE_8_BYTES(temp0, temp0, 7, 4, 7, dst)
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1)
+ : [dst]"r"(dst)
+ : "memory"
+ );
+}
+
+static void DC8uvNoTop(uint8_t* dst) { // DC with no top samples
+ int temp0, temp1, temp2, temp3, temp4;
+ int temp5, temp6, temp7, temp8;
+ __asm__ volatile (
+ LOAD_4_BYTES(temp2, temp3, temp4, temp5, -1, 0, -1, 1, -1, 2, -1, 3, dst)
+ LOAD_4_BYTES(temp6, temp7, temp8, temp1, -1, 4, -1, 5, -1, 6, -1, 7, dst)
+ "addu %[temp2], %[temp2], %[temp3] \n\t"
+ "addu %[temp4], %[temp4], %[temp5] \n\t"
+ "addu %[temp6], %[temp6], %[temp7] \n\t"
+ "addu %[temp8], %[temp8], %[temp1] \n\t"
+ "addu %[temp2], %[temp2], %[temp4] \n\t"
+ "addu %[temp6], %[temp6], %[temp8] \n\t"
+ "addu %[temp0], %[temp6], %[temp2] \n\t"
+ "shra_r.w %[temp0], %[temp0], 3 \n\t"
+ "replv.qb %[temp0], %[temp0] \n\t"
+ STORE_8_BYTES(temp0, temp0, 0, 4, 0, dst)
+ STORE_8_BYTES(temp0, temp0, 1, 4, 1, dst)
+ STORE_8_BYTES(temp0, temp0, 2, 4, 2, dst)
+ STORE_8_BYTES(temp0, temp0, 3, 4, 3, dst)
+ STORE_8_BYTES(temp0, temp0, 4, 4, 4, dst)
+ STORE_8_BYTES(temp0, temp0, 5, 4, 5, dst)
+ STORE_8_BYTES(temp0, temp0, 6, 4, 6, dst)
+ STORE_8_BYTES(temp0, temp0, 7, 4, 7, dst)
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8)
+ : [dst]"r"(dst)
+ : "memory"
+ );
+}
+
+#undef LOAD_8_BYTES
+#undef STORE_8_BYTES
+#undef LOAD_4_BYTES
+
+#define CLIPPING(SIZE) \
+ "preceu.ph.qbl %[temp2], %[temp0] \n\t" \
+ "preceu.ph.qbr %[temp0], %[temp0] \n\t" \
+".if " #SIZE " == 8 \n\t" \
+ "preceu.ph.qbl %[temp3], %[temp1] \n\t" \
+ "preceu.ph.qbr %[temp1], %[temp1] \n\t" \
+".endif \n\t" \
+ "addu.ph %[temp2], %[temp2], %[dst_1] \n\t" \
+ "addu.ph %[temp0], %[temp0], %[dst_1] \n\t" \
+".if " #SIZE " == 8 \n\t" \
+ "addu.ph %[temp3], %[temp3], %[dst_1] \n\t" \
+ "addu.ph %[temp1], %[temp1], %[dst_1] \n\t" \
+".endif \n\t" \
+ "shll_s.ph %[temp2], %[temp2], 7 \n\t" \
+ "shll_s.ph %[temp0], %[temp0], 7 \n\t" \
+".if " #SIZE " == 8 \n\t" \
+ "shll_s.ph %[temp3], %[temp3], 7 \n\t" \
+ "shll_s.ph %[temp1], %[temp1], 7 \n\t" \
+".endif \n\t" \
+ "precrqu_s.qb.ph %[temp0], %[temp2], %[temp0] \n\t" \
+".if " #SIZE " == 8 \n\t" \
+ "precrqu_s.qb.ph %[temp1], %[temp3], %[temp1] \n\t" \
+".endif \n\t"
+
+
+#define CLIP_8B_TO_DST(DST, TOP, SIZE) do { \
+ int dst_1 = ((int)(DST)[-1] << 16) + (DST)[-1]; \
+ int temp0, temp1, temp2, temp3; \
+ __asm__ volatile ( \
+ ".if " #SIZE " < 8 \n\t" \
+ "ulw %[temp0], 0(%[top]) \n\t" \
+ "subu.ph %[dst_1], %[dst_1], %[top_1] \n\t" \
+ CLIPPING(4) \
+ "usw %[temp0], 0(%[dst]) \n\t" \
+ ".else \n\t" \
+ "ulw %[temp0], 0(%[top]) \n\t" \
+ "ulw %[temp1], 4(%[top]) \n\t" \
+ "subu.ph %[dst_1], %[dst_1], %[top_1] \n\t" \
+ CLIPPING(8) \
+ "usw %[temp0], 0(%[dst]) \n\t" \
+ "usw %[temp1], 4(%[dst]) \n\t" \
+ ".if " #SIZE " == 16 \n\t" \
+ "ulw %[temp0], 8(%[top]) \n\t" \
+ "ulw %[temp1], 12(%[top]) \n\t" \
+ CLIPPING(8) \
+ "usw %[temp0], 8(%[dst]) \n\t" \
+ "usw %[temp1], 12(%[dst]) \n\t" \
+ ".endif \n\t" \
+ ".endif \n\t" \
+ : [dst_1]"+&r"(dst_1), [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), \
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3) \
+ : [top_1]"r"(top_1), [top]"r"((TOP)), [dst]"r"((DST)) \
+ : "memory" \
+ ); \
+} while (0)
+
+#define CLIP_TO_DST(DST, SIZE) do { \
+ int y; \
+ const uint8_t* top = (DST) - BPS; \
+ const int top_1 = ((int)top[-1] << 16) + top[-1]; \
+ for (y = 0; y < (SIZE); ++y) { \
+ CLIP_8B_TO_DST((DST), top, (SIZE)); \
+ (DST) += BPS; \
+ } \
+} while (0)
+
+#define TRUE_MOTION(DST, SIZE) \
+static void TrueMotion##SIZE(uint8_t* (DST)) { \
+ CLIP_TO_DST((DST), (SIZE)); \
+}
+
+TRUE_MOTION(dst, 4)
+TRUE_MOTION(dst, 8)
+TRUE_MOTION(dst, 16)
+
+#undef TRUE_MOTION
+#undef CLIP_TO_DST
+#undef CLIP_8B_TO_DST
+#undef CLIPPING
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8DspInitMIPSdspR2(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8DspInitMIPSdspR2(void) {
+ VP8TransformDC = TransformDC;
+ VP8TransformAC3 = TransformAC3;
+ VP8Transform = TransformTwo;
+
+ VP8VFilter16 = VFilter16;
+ VP8HFilter16 = HFilter16;
+ VP8VFilter8 = VFilter8;
+ VP8HFilter8 = HFilter8;
+ VP8VFilter16i = VFilter16i;
+ VP8HFilter16i = HFilter16i;
+ VP8VFilter8i = VFilter8i;
+ VP8HFilter8i = HFilter8i;
+ VP8SimpleVFilter16 = SimpleVFilter16;
+ VP8SimpleHFilter16 = SimpleHFilter16;
+ VP8SimpleVFilter16i = SimpleVFilter16i;
+ VP8SimpleHFilter16i = SimpleHFilter16i;
+
+ VP8PredLuma4[0] = DC4;
+ VP8PredLuma4[1] = TrueMotion4;
+ VP8PredLuma4[2] = VE4;
+ VP8PredLuma4[4] = RD4;
+ VP8PredLuma4[6] = LD4;
+
+ VP8PredChroma8[0] = DC8uv;
+ VP8PredChroma8[1] = TrueMotion8;
+ VP8PredChroma8[4] = DC8uvNoTop;
+ VP8PredChroma8[5] = DC8uvNoLeft;
+
+ VP8PredLuma16[1] = TrueMotion16;
+}
+
+#else // !WEBP_USE_MIPS_DSP_R2
+
+WEBP_DSP_INIT_STUB(VP8DspInitMIPSdspR2)
+
+#endif // WEBP_USE_MIPS_DSP_R2
diff --git a/drivers/webp/dsp/dec_neon.c b/drivers/webp/dsp/dec_neon.c
index ec824b790b..a63f43fe17 100644
--- a/drivers/webp/dsp/dec_neon.c
+++ b/drivers/webp/dsp/dec_neon.c
@@ -1,8 +1,10 @@
// Copyright 2012 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// ARM NEON version of dsp functions and loop filtering.
@@ -14,13 +16,535 @@
#if defined(WEBP_USE_NEON)
+#include "./neon.h"
#include "../dec/vp8i.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
+//------------------------------------------------------------------------------
+// NxM Loading functions
+
+// Load/Store vertical edge
+#define LOAD8x4(c1, c2, c3, c4, b1, b2, stride) \
+ "vld4.8 {" #c1 "[0]," #c2 "[0]," #c3 "[0]," #c4 "[0]}," #b1 "," #stride "\n" \
+ "vld4.8 {" #c1 "[1]," #c2 "[1]," #c3 "[1]," #c4 "[1]}," #b2 "," #stride "\n" \
+ "vld4.8 {" #c1 "[2]," #c2 "[2]," #c3 "[2]," #c4 "[2]}," #b1 "," #stride "\n" \
+ "vld4.8 {" #c1 "[3]," #c2 "[3]," #c3 "[3]," #c4 "[3]}," #b2 "," #stride "\n" \
+ "vld4.8 {" #c1 "[4]," #c2 "[4]," #c3 "[4]," #c4 "[4]}," #b1 "," #stride "\n" \
+ "vld4.8 {" #c1 "[5]," #c2 "[5]," #c3 "[5]," #c4 "[5]}," #b2 "," #stride "\n" \
+ "vld4.8 {" #c1 "[6]," #c2 "[6]," #c3 "[6]," #c4 "[6]}," #b1 "," #stride "\n" \
+ "vld4.8 {" #c1 "[7]," #c2 "[7]," #c3 "[7]," #c4 "[7]}," #b2 "," #stride "\n"
+
+#define STORE8x2(c1, c2, p, stride) \
+ "vst2.8 {" #c1 "[0], " #c2 "[0]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1 "[1], " #c2 "[1]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1 "[2], " #c2 "[2]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1 "[3], " #c2 "[3]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1 "[4], " #c2 "[4]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1 "[5], " #c2 "[5]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1 "[6], " #c2 "[6]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1 "[7], " #c2 "[7]}," #p "," #stride " \n"
+
+#if !defined(WORK_AROUND_GCC)
+
+// This intrinsics version makes gcc-4.6.3 crash during Load4x??() compilation
+// (register alloc, probably). The variants somewhat mitigate the problem, but
+// not quite. HFilter16i() remains problematic.
+static WEBP_INLINE uint8x8x4_t Load4x8(const uint8_t* const src, int stride) {
+ const uint8x8_t zero = vdup_n_u8(0);
+ uint8x8x4_t out;
+ INIT_VECTOR4(out, zero, zero, zero, zero);
+ out = vld4_lane_u8(src + 0 * stride, out, 0);
+ out = vld4_lane_u8(src + 1 * stride, out, 1);
+ out = vld4_lane_u8(src + 2 * stride, out, 2);
+ out = vld4_lane_u8(src + 3 * stride, out, 3);
+ out = vld4_lane_u8(src + 4 * stride, out, 4);
+ out = vld4_lane_u8(src + 5 * stride, out, 5);
+ out = vld4_lane_u8(src + 6 * stride, out, 6);
+ out = vld4_lane_u8(src + 7 * stride, out, 7);
+ return out;
+}
+
+static WEBP_INLINE void Load4x16(const uint8_t* const src, int stride,
+ uint8x16_t* const p1, uint8x16_t* const p0,
+ uint8x16_t* const q0, uint8x16_t* const q1) {
+ // row0 = p1[0..7]|p0[0..7]|q0[0..7]|q1[0..7]
+ // row8 = p1[8..15]|p0[8..15]|q0[8..15]|q1[8..15]
+ const uint8x8x4_t row0 = Load4x8(src - 2 + 0 * stride, stride);
+ const uint8x8x4_t row8 = Load4x8(src - 2 + 8 * stride, stride);
+ *p1 = vcombine_u8(row0.val[0], row8.val[0]);
+ *p0 = vcombine_u8(row0.val[1], row8.val[1]);
+ *q0 = vcombine_u8(row0.val[2], row8.val[2]);
+ *q1 = vcombine_u8(row0.val[3], row8.val[3]);
+}
+
+#else // WORK_AROUND_GCC
+
+#define LOADQ_LANE_32b(VALUE, LANE) do { \
+ (VALUE) = vld1q_lane_u32((const uint32_t*)src, (VALUE), (LANE)); \
+ src += stride; \
+} while (0)
+
+static WEBP_INLINE void Load4x16(const uint8_t* src, int stride,
+ uint8x16_t* const p1, uint8x16_t* const p0,
+ uint8x16_t* const q0, uint8x16_t* const q1) {
+ const uint32x4_t zero = vdupq_n_u32(0);
+ uint32x4x4_t in;
+ INIT_VECTOR4(in, zero, zero, zero, zero);
+ src -= 2;
+ LOADQ_LANE_32b(in.val[0], 0);
+ LOADQ_LANE_32b(in.val[1], 0);
+ LOADQ_LANE_32b(in.val[2], 0);
+ LOADQ_LANE_32b(in.val[3], 0);
+ LOADQ_LANE_32b(in.val[0], 1);
+ LOADQ_LANE_32b(in.val[1], 1);
+ LOADQ_LANE_32b(in.val[2], 1);
+ LOADQ_LANE_32b(in.val[3], 1);
+ LOADQ_LANE_32b(in.val[0], 2);
+ LOADQ_LANE_32b(in.val[1], 2);
+ LOADQ_LANE_32b(in.val[2], 2);
+ LOADQ_LANE_32b(in.val[3], 2);
+ LOADQ_LANE_32b(in.val[0], 3);
+ LOADQ_LANE_32b(in.val[1], 3);
+ LOADQ_LANE_32b(in.val[2], 3);
+ LOADQ_LANE_32b(in.val[3], 3);
+ // Transpose four 4x4 parts:
+ {
+ const uint8x16x2_t row01 = vtrnq_u8(vreinterpretq_u8_u32(in.val[0]),
+ vreinterpretq_u8_u32(in.val[1]));
+ const uint8x16x2_t row23 = vtrnq_u8(vreinterpretq_u8_u32(in.val[2]),
+ vreinterpretq_u8_u32(in.val[3]));
+ const uint16x8x2_t row02 = vtrnq_u16(vreinterpretq_u16_u8(row01.val[0]),
+ vreinterpretq_u16_u8(row23.val[0]));
+ const uint16x8x2_t row13 = vtrnq_u16(vreinterpretq_u16_u8(row01.val[1]),
+ vreinterpretq_u16_u8(row23.val[1]));
+ *p1 = vreinterpretq_u8_u16(row02.val[0]);
+ *p0 = vreinterpretq_u8_u16(row13.val[0]);
+ *q0 = vreinterpretq_u8_u16(row02.val[1]);
+ *q1 = vreinterpretq_u8_u16(row13.val[1]);
+ }
+}
+#undef LOADQ_LANE_32b
+
+#endif // !WORK_AROUND_GCC
+
+static WEBP_INLINE void Load8x16(const uint8_t* const src, int stride,
+ uint8x16_t* const p3, uint8x16_t* const p2,
+ uint8x16_t* const p1, uint8x16_t* const p0,
+ uint8x16_t* const q0, uint8x16_t* const q1,
+ uint8x16_t* const q2, uint8x16_t* const q3) {
+ Load4x16(src - 2, stride, p3, p2, p1, p0);
+ Load4x16(src + 2, stride, q0, q1, q2, q3);
+}
+
+static WEBP_INLINE void Load16x4(const uint8_t* const src, int stride,
+ uint8x16_t* const p1, uint8x16_t* const p0,
+ uint8x16_t* const q0, uint8x16_t* const q1) {
+ *p1 = vld1q_u8(src - 2 * stride);
+ *p0 = vld1q_u8(src - 1 * stride);
+ *q0 = vld1q_u8(src + 0 * stride);
+ *q1 = vld1q_u8(src + 1 * stride);
+}
+
+static WEBP_INLINE void Load16x8(const uint8_t* const src, int stride,
+ uint8x16_t* const p3, uint8x16_t* const p2,
+ uint8x16_t* const p1, uint8x16_t* const p0,
+ uint8x16_t* const q0, uint8x16_t* const q1,
+ uint8x16_t* const q2, uint8x16_t* const q3) {
+ Load16x4(src - 2 * stride, stride, p3, p2, p1, p0);
+ Load16x4(src + 2 * stride, stride, q0, q1, q2, q3);
+}
+
+static WEBP_INLINE void Load8x8x2(const uint8_t* const u,
+ const uint8_t* const v,
+ int stride,
+ uint8x16_t* const p3, uint8x16_t* const p2,
+ uint8x16_t* const p1, uint8x16_t* const p0,
+ uint8x16_t* const q0, uint8x16_t* const q1,
+ uint8x16_t* const q2, uint8x16_t* const q3) {
+ // We pack the 8x8 u-samples in the lower half of the uint8x16_t destination
+ // and the v-samples on the higher half.
+ *p3 = vcombine_u8(vld1_u8(u - 4 * stride), vld1_u8(v - 4 * stride));
+ *p2 = vcombine_u8(vld1_u8(u - 3 * stride), vld1_u8(v - 3 * stride));
+ *p1 = vcombine_u8(vld1_u8(u - 2 * stride), vld1_u8(v - 2 * stride));
+ *p0 = vcombine_u8(vld1_u8(u - 1 * stride), vld1_u8(v - 1 * stride));
+ *q0 = vcombine_u8(vld1_u8(u + 0 * stride), vld1_u8(v + 0 * stride));
+ *q1 = vcombine_u8(vld1_u8(u + 1 * stride), vld1_u8(v + 1 * stride));
+ *q2 = vcombine_u8(vld1_u8(u + 2 * stride), vld1_u8(v + 2 * stride));
+ *q3 = vcombine_u8(vld1_u8(u + 3 * stride), vld1_u8(v + 3 * stride));
+}
+
+#if !defined(WORK_AROUND_GCC)
+
+#define LOAD_UV_8(ROW) \
+ vcombine_u8(vld1_u8(u - 4 + (ROW) * stride), vld1_u8(v - 4 + (ROW) * stride))
+
+static WEBP_INLINE void Load8x8x2T(const uint8_t* const u,
+ const uint8_t* const v,
+ int stride,
+ uint8x16_t* const p3, uint8x16_t* const p2,
+ uint8x16_t* const p1, uint8x16_t* const p0,
+ uint8x16_t* const q0, uint8x16_t* const q1,
+ uint8x16_t* const q2, uint8x16_t* const q3) {
+ // We pack the 8x8 u-samples in the lower half of the uint8x16_t destination
+ // and the v-samples on the higher half.
+ const uint8x16_t row0 = LOAD_UV_8(0);
+ const uint8x16_t row1 = LOAD_UV_8(1);
+ const uint8x16_t row2 = LOAD_UV_8(2);
+ const uint8x16_t row3 = LOAD_UV_8(3);
+ const uint8x16_t row4 = LOAD_UV_8(4);
+ const uint8x16_t row5 = LOAD_UV_8(5);
+ const uint8x16_t row6 = LOAD_UV_8(6);
+ const uint8x16_t row7 = LOAD_UV_8(7);
+ // Perform two side-by-side 8x8 transposes
+ // u00 u01 u02 u03 u04 u05 u06 u07 | v00 v01 v02 v03 v04 v05 v06 v07
+ // u10 u11 u12 u13 u14 u15 u16 u17 | v10 v11 v12 ...
+ // u20 u21 u22 u23 u24 u25 u26 u27 | v20 v21 ...
+ // u30 u31 u32 u33 u34 u35 u36 u37 | ...
+ // u40 u41 u42 u43 u44 u45 u46 u47 | ...
+ // u50 u51 u52 u53 u54 u55 u56 u57 | ...
+ // u60 u61 u62 u63 u64 u65 u66 u67 | v60 ...
+ // u70 u71 u72 u73 u74 u75 u76 u77 | v70 v71 v72 ...
+ const uint8x16x2_t row01 = vtrnq_u8(row0, row1); // u00 u10 u02 u12 ...
+ // u01 u11 u03 u13 ...
+ const uint8x16x2_t row23 = vtrnq_u8(row2, row3); // u20 u30 u22 u32 ...
+ // u21 u31 u23 u33 ...
+ const uint8x16x2_t row45 = vtrnq_u8(row4, row5); // ...
+ const uint8x16x2_t row67 = vtrnq_u8(row6, row7); // ...
+ const uint16x8x2_t row02 = vtrnq_u16(vreinterpretq_u16_u8(row01.val[0]),
+ vreinterpretq_u16_u8(row23.val[0]));
+ const uint16x8x2_t row13 = vtrnq_u16(vreinterpretq_u16_u8(row01.val[1]),
+ vreinterpretq_u16_u8(row23.val[1]));
+ const uint16x8x2_t row46 = vtrnq_u16(vreinterpretq_u16_u8(row45.val[0]),
+ vreinterpretq_u16_u8(row67.val[0]));
+ const uint16x8x2_t row57 = vtrnq_u16(vreinterpretq_u16_u8(row45.val[1]),
+ vreinterpretq_u16_u8(row67.val[1]));
+ const uint32x4x2_t row04 = vtrnq_u32(vreinterpretq_u32_u16(row02.val[0]),
+ vreinterpretq_u32_u16(row46.val[0]));
+ const uint32x4x2_t row26 = vtrnq_u32(vreinterpretq_u32_u16(row02.val[1]),
+ vreinterpretq_u32_u16(row46.val[1]));
+ const uint32x4x2_t row15 = vtrnq_u32(vreinterpretq_u32_u16(row13.val[0]),
+ vreinterpretq_u32_u16(row57.val[0]));
+ const uint32x4x2_t row37 = vtrnq_u32(vreinterpretq_u32_u16(row13.val[1]),
+ vreinterpretq_u32_u16(row57.val[1]));
+ *p3 = vreinterpretq_u8_u32(row04.val[0]);
+ *p2 = vreinterpretq_u8_u32(row15.val[0]);
+ *p1 = vreinterpretq_u8_u32(row26.val[0]);
+ *p0 = vreinterpretq_u8_u32(row37.val[0]);
+ *q0 = vreinterpretq_u8_u32(row04.val[1]);
+ *q1 = vreinterpretq_u8_u32(row15.val[1]);
+ *q2 = vreinterpretq_u8_u32(row26.val[1]);
+ *q3 = vreinterpretq_u8_u32(row37.val[1]);
+}
+#undef LOAD_UV_8
+
+#endif // !WORK_AROUND_GCC
+
+static WEBP_INLINE void Store2x8(const uint8x8x2_t v,
+ uint8_t* const dst, int stride) {
+ vst2_lane_u8(dst + 0 * stride, v, 0);
+ vst2_lane_u8(dst + 1 * stride, v, 1);
+ vst2_lane_u8(dst + 2 * stride, v, 2);
+ vst2_lane_u8(dst + 3 * stride, v, 3);
+ vst2_lane_u8(dst + 4 * stride, v, 4);
+ vst2_lane_u8(dst + 5 * stride, v, 5);
+ vst2_lane_u8(dst + 6 * stride, v, 6);
+ vst2_lane_u8(dst + 7 * stride, v, 7);
+}
-#define QRegs "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", \
+static WEBP_INLINE void Store2x16(const uint8x16_t p0, const uint8x16_t q0,
+ uint8_t* const dst, int stride) {
+ uint8x8x2_t lo, hi;
+ lo.val[0] = vget_low_u8(p0);
+ lo.val[1] = vget_low_u8(q0);
+ hi.val[0] = vget_high_u8(p0);
+ hi.val[1] = vget_high_u8(q0);
+ Store2x8(lo, dst - 1 + 0 * stride, stride);
+ Store2x8(hi, dst - 1 + 8 * stride, stride);
+}
+
+#if !defined(WORK_AROUND_GCC)
+static WEBP_INLINE void Store4x8(const uint8x8x4_t v,
+ uint8_t* const dst, int stride) {
+ vst4_lane_u8(dst + 0 * stride, v, 0);
+ vst4_lane_u8(dst + 1 * stride, v, 1);
+ vst4_lane_u8(dst + 2 * stride, v, 2);
+ vst4_lane_u8(dst + 3 * stride, v, 3);
+ vst4_lane_u8(dst + 4 * stride, v, 4);
+ vst4_lane_u8(dst + 5 * stride, v, 5);
+ vst4_lane_u8(dst + 6 * stride, v, 6);
+ vst4_lane_u8(dst + 7 * stride, v, 7);
+}
+
+static WEBP_INLINE void Store4x16(const uint8x16_t p1, const uint8x16_t p0,
+ const uint8x16_t q0, const uint8x16_t q1,
+ uint8_t* const dst, int stride) {
+ uint8x8x4_t lo, hi;
+ INIT_VECTOR4(lo,
+ vget_low_u8(p1), vget_low_u8(p0),
+ vget_low_u8(q0), vget_low_u8(q1));
+ INIT_VECTOR4(hi,
+ vget_high_u8(p1), vget_high_u8(p0),
+ vget_high_u8(q0), vget_high_u8(q1));
+ Store4x8(lo, dst - 2 + 0 * stride, stride);
+ Store4x8(hi, dst - 2 + 8 * stride, stride);
+}
+#endif // !WORK_AROUND_GCC
+
+static WEBP_INLINE void Store16x2(const uint8x16_t p0, const uint8x16_t q0,
+ uint8_t* const dst, int stride) {
+ vst1q_u8(dst - stride, p0);
+ vst1q_u8(dst, q0);
+}
+
+static WEBP_INLINE void Store16x4(const uint8x16_t p1, const uint8x16_t p0,
+ const uint8x16_t q0, const uint8x16_t q1,
+ uint8_t* const dst, int stride) {
+ Store16x2(p1, p0, dst - stride, stride);
+ Store16x2(q0, q1, dst + stride, stride);
+}
+
+static WEBP_INLINE void Store8x2x2(const uint8x16_t p0, const uint8x16_t q0,
+ uint8_t* const u, uint8_t* const v,
+ int stride) {
+ // p0 and q0 contain the u+v samples packed in low/high halves.
+ vst1_u8(u - stride, vget_low_u8(p0));
+ vst1_u8(u, vget_low_u8(q0));
+ vst1_u8(v - stride, vget_high_u8(p0));
+ vst1_u8(v, vget_high_u8(q0));
+}
+
+static WEBP_INLINE void Store8x4x2(const uint8x16_t p1, const uint8x16_t p0,
+ const uint8x16_t q0, const uint8x16_t q1,
+ uint8_t* const u, uint8_t* const v,
+ int stride) {
+ // The p1...q1 registers contain the u+v samples packed in low/high halves.
+ Store8x2x2(p1, p0, u - stride, v - stride, stride);
+ Store8x2x2(q0, q1, u + stride, v + stride, stride);
+}
+
+#if !defined(WORK_AROUND_GCC)
+
+#define STORE6_LANE(DST, VAL0, VAL1, LANE) do { \
+ vst3_lane_u8((DST) - 3, (VAL0), (LANE)); \
+ vst3_lane_u8((DST) + 0, (VAL1), (LANE)); \
+ (DST) += stride; \
+} while (0)
+
+static WEBP_INLINE void Store6x8x2(const uint8x16_t p2, const uint8x16_t p1,
+ const uint8x16_t p0, const uint8x16_t q0,
+ const uint8x16_t q1, const uint8x16_t q2,
+ uint8_t* u, uint8_t* v,
+ int stride) {
+ uint8x8x3_t u0, u1, v0, v1;
+ INIT_VECTOR3(u0, vget_low_u8(p2), vget_low_u8(p1), vget_low_u8(p0));
+ INIT_VECTOR3(u1, vget_low_u8(q0), vget_low_u8(q1), vget_low_u8(q2));
+ INIT_VECTOR3(v0, vget_high_u8(p2), vget_high_u8(p1), vget_high_u8(p0));
+ INIT_VECTOR3(v1, vget_high_u8(q0), vget_high_u8(q1), vget_high_u8(q2));
+ STORE6_LANE(u, u0, u1, 0);
+ STORE6_LANE(u, u0, u1, 1);
+ STORE6_LANE(u, u0, u1, 2);
+ STORE6_LANE(u, u0, u1, 3);
+ STORE6_LANE(u, u0, u1, 4);
+ STORE6_LANE(u, u0, u1, 5);
+ STORE6_LANE(u, u0, u1, 6);
+ STORE6_LANE(u, u0, u1, 7);
+ STORE6_LANE(v, v0, v1, 0);
+ STORE6_LANE(v, v0, v1, 1);
+ STORE6_LANE(v, v0, v1, 2);
+ STORE6_LANE(v, v0, v1, 3);
+ STORE6_LANE(v, v0, v1, 4);
+ STORE6_LANE(v, v0, v1, 5);
+ STORE6_LANE(v, v0, v1, 6);
+ STORE6_LANE(v, v0, v1, 7);
+}
+#undef STORE6_LANE
+
+static WEBP_INLINE void Store4x8x2(const uint8x16_t p1, const uint8x16_t p0,
+ const uint8x16_t q0, const uint8x16_t q1,
+ uint8_t* const u, uint8_t* const v,
+ int stride) {
+ uint8x8x4_t u0, v0;
+ INIT_VECTOR4(u0,
+ vget_low_u8(p1), vget_low_u8(p0),
+ vget_low_u8(q0), vget_low_u8(q1));
+ INIT_VECTOR4(v0,
+ vget_high_u8(p1), vget_high_u8(p0),
+ vget_high_u8(q0), vget_high_u8(q1));
+ vst4_lane_u8(u - 2 + 0 * stride, u0, 0);
+ vst4_lane_u8(u - 2 + 1 * stride, u0, 1);
+ vst4_lane_u8(u - 2 + 2 * stride, u0, 2);
+ vst4_lane_u8(u - 2 + 3 * stride, u0, 3);
+ vst4_lane_u8(u - 2 + 4 * stride, u0, 4);
+ vst4_lane_u8(u - 2 + 5 * stride, u0, 5);
+ vst4_lane_u8(u - 2 + 6 * stride, u0, 6);
+ vst4_lane_u8(u - 2 + 7 * stride, u0, 7);
+ vst4_lane_u8(v - 2 + 0 * stride, v0, 0);
+ vst4_lane_u8(v - 2 + 1 * stride, v0, 1);
+ vst4_lane_u8(v - 2 + 2 * stride, v0, 2);
+ vst4_lane_u8(v - 2 + 3 * stride, v0, 3);
+ vst4_lane_u8(v - 2 + 4 * stride, v0, 4);
+ vst4_lane_u8(v - 2 + 5 * stride, v0, 5);
+ vst4_lane_u8(v - 2 + 6 * stride, v0, 6);
+ vst4_lane_u8(v - 2 + 7 * stride, v0, 7);
+}
+
+#endif // !WORK_AROUND_GCC
+
+// Zero extend 'v' to an int16x8_t.
+static WEBP_INLINE int16x8_t ConvertU8ToS16(uint8x8_t v) {
+ return vreinterpretq_s16_u16(vmovl_u8(v));
+}
+
+// Performs unsigned 8b saturation on 'dst01' and 'dst23' storing the result
+// to the corresponding rows of 'dst'.
+static WEBP_INLINE void SaturateAndStore4x4(uint8_t* const dst,
+ const int16x8_t dst01,
+ const int16x8_t dst23) {
+ // Unsigned saturate to 8b.
+ const uint8x8_t dst01_u8 = vqmovun_s16(dst01);
+ const uint8x8_t dst23_u8 = vqmovun_s16(dst23);
+
+ // Store the results.
+ vst1_lane_u32((uint32_t*)(dst + 0 * BPS), vreinterpret_u32_u8(dst01_u8), 0);
+ vst1_lane_u32((uint32_t*)(dst + 1 * BPS), vreinterpret_u32_u8(dst01_u8), 1);
+ vst1_lane_u32((uint32_t*)(dst + 2 * BPS), vreinterpret_u32_u8(dst23_u8), 0);
+ vst1_lane_u32((uint32_t*)(dst + 3 * BPS), vreinterpret_u32_u8(dst23_u8), 1);
+}
+
+static WEBP_INLINE void Add4x4(const int16x8_t row01, const int16x8_t row23,
+ uint8_t* const dst) {
+ uint32x2_t dst01 = vdup_n_u32(0);
+ uint32x2_t dst23 = vdup_n_u32(0);
+
+ // Load the source pixels.
+ dst01 = vld1_lane_u32((uint32_t*)(dst + 0 * BPS), dst01, 0);
+ dst23 = vld1_lane_u32((uint32_t*)(dst + 2 * BPS), dst23, 0);
+ dst01 = vld1_lane_u32((uint32_t*)(dst + 1 * BPS), dst01, 1);
+ dst23 = vld1_lane_u32((uint32_t*)(dst + 3 * BPS), dst23, 1);
+
+ {
+ // Convert to 16b.
+ const int16x8_t dst01_s16 = ConvertU8ToS16(vreinterpret_u8_u32(dst01));
+ const int16x8_t dst23_s16 = ConvertU8ToS16(vreinterpret_u8_u32(dst23));
+
+ // Descale with rounding.
+ const int16x8_t out01 = vrsraq_n_s16(dst01_s16, row01, 3);
+ const int16x8_t out23 = vrsraq_n_s16(dst23_s16, row23, 3);
+ // Add the inverse transform.
+ SaturateAndStore4x4(dst, out01, out23);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Simple In-loop filtering (Paragraph 15.2)
+
+static uint8x16_t NeedsFilter(const uint8x16_t p1, const uint8x16_t p0,
+ const uint8x16_t q0, const uint8x16_t q1,
+ int thresh) {
+ const uint8x16_t thresh_v = vdupq_n_u8((uint8_t)thresh);
+ const uint8x16_t a_p0_q0 = vabdq_u8(p0, q0); // abs(p0-q0)
+ const uint8x16_t a_p1_q1 = vabdq_u8(p1, q1); // abs(p1-q1)
+ const uint8x16_t a_p0_q0_2 = vqaddq_u8(a_p0_q0, a_p0_q0); // 2 * abs(p0-q0)
+ const uint8x16_t a_p1_q1_2 = vshrq_n_u8(a_p1_q1, 1); // abs(p1-q1) / 2
+ const uint8x16_t sum = vqaddq_u8(a_p0_q0_2, a_p1_q1_2);
+ const uint8x16_t mask = vcgeq_u8(thresh_v, sum);
+ return mask;
+}
+
+static int8x16_t FlipSign(const uint8x16_t v) {
+ const uint8x16_t sign_bit = vdupq_n_u8(0x80);
+ return vreinterpretq_s8_u8(veorq_u8(v, sign_bit));
+}
+
+static uint8x16_t FlipSignBack(const int8x16_t v) {
+ const int8x16_t sign_bit = vdupq_n_s8(0x80);
+ return vreinterpretq_u8_s8(veorq_s8(v, sign_bit));
+}
+
+static int8x16_t GetBaseDelta(const int8x16_t p1, const int8x16_t p0,
+ const int8x16_t q0, const int8x16_t q1) {
+ const int8x16_t q0_p0 = vqsubq_s8(q0, p0); // (q0-p0)
+ const int8x16_t p1_q1 = vqsubq_s8(p1, q1); // (p1-q1)
+ const int8x16_t s1 = vqaddq_s8(p1_q1, q0_p0); // (p1-q1) + 1 * (q0 - p0)
+ const int8x16_t s2 = vqaddq_s8(q0_p0, s1); // (p1-q1) + 2 * (q0 - p0)
+ const int8x16_t s3 = vqaddq_s8(q0_p0, s2); // (p1-q1) + 3 * (q0 - p0)
+ return s3;
+}
+
+static int8x16_t GetBaseDelta0(const int8x16_t p0, const int8x16_t q0) {
+ const int8x16_t q0_p0 = vqsubq_s8(q0, p0); // (q0-p0)
+ const int8x16_t s1 = vqaddq_s8(q0_p0, q0_p0); // 2 * (q0 - p0)
+ const int8x16_t s2 = vqaddq_s8(q0_p0, s1); // 3 * (q0 - p0)
+ return s2;
+}
+
+//------------------------------------------------------------------------------
+
+static void ApplyFilter2NoFlip(const int8x16_t p0s, const int8x16_t q0s,
+ const int8x16_t delta,
+ int8x16_t* const op0, int8x16_t* const oq0) {
+ const int8x16_t kCst3 = vdupq_n_s8(0x03);
+ const int8x16_t kCst4 = vdupq_n_s8(0x04);
+ const int8x16_t delta_p3 = vqaddq_s8(delta, kCst3);
+ const int8x16_t delta_p4 = vqaddq_s8(delta, kCst4);
+ const int8x16_t delta3 = vshrq_n_s8(delta_p3, 3);
+ const int8x16_t delta4 = vshrq_n_s8(delta_p4, 3);
+ *op0 = vqaddq_s8(p0s, delta3);
+ *oq0 = vqsubq_s8(q0s, delta4);
+}
+
+#if defined(WEBP_USE_INTRINSICS)
+
+static void ApplyFilter2(const int8x16_t p0s, const int8x16_t q0s,
+ const int8x16_t delta,
+ uint8x16_t* const op0, uint8x16_t* const oq0) {
+ const int8x16_t kCst3 = vdupq_n_s8(0x03);
+ const int8x16_t kCst4 = vdupq_n_s8(0x04);
+ const int8x16_t delta_p3 = vqaddq_s8(delta, kCst3);
+ const int8x16_t delta_p4 = vqaddq_s8(delta, kCst4);
+ const int8x16_t delta3 = vshrq_n_s8(delta_p3, 3);
+ const int8x16_t delta4 = vshrq_n_s8(delta_p4, 3);
+ const int8x16_t sp0 = vqaddq_s8(p0s, delta3);
+ const int8x16_t sq0 = vqsubq_s8(q0s, delta4);
+ *op0 = FlipSignBack(sp0);
+ *oq0 = FlipSignBack(sq0);
+}
+
+static void DoFilter2(const uint8x16_t p1, const uint8x16_t p0,
+ const uint8x16_t q0, const uint8x16_t q1,
+ const uint8x16_t mask,
+ uint8x16_t* const op0, uint8x16_t* const oq0) {
+ const int8x16_t p1s = FlipSign(p1);
+ const int8x16_t p0s = FlipSign(p0);
+ const int8x16_t q0s = FlipSign(q0);
+ const int8x16_t q1s = FlipSign(q1);
+ const int8x16_t delta0 = GetBaseDelta(p1s, p0s, q0s, q1s);
+ const int8x16_t delta1 = vandq_s8(delta0, vreinterpretq_s8_u8(mask));
+ ApplyFilter2(p0s, q0s, delta1, op0, oq0);
+}
+
+static void SimpleVFilter16(uint8_t* p, int stride, int thresh) {
+ uint8x16_t p1, p0, q0, q1, op0, oq0;
+ Load16x4(p, stride, &p1, &p0, &q0, &q1);
+ {
+ const uint8x16_t mask = NeedsFilter(p1, p0, q0, q1, thresh);
+ DoFilter2(p1, p0, q0, q1, mask, &op0, &oq0);
+ }
+ Store16x2(op0, oq0, p, stride);
+}
+
+static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
+ uint8x16_t p1, p0, q0, q1, oq0, op0;
+ Load4x16(p, stride, &p1, &p0, &q0, &q1);
+ {
+ const uint8x16_t mask = NeedsFilter(p1, p0, q0, q1, thresh);
+ DoFilter2(p1, p0, q0, q1, mask, &op0, &oq0);
+ }
+ Store2x16(op0, oq0, p, stride);
+}
+
+#else
+
+#define QRegs "q0", "q1", "q2", "q3", \
"q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
#define FLIP_SIGN_BIT2(a, b, s) \
@@ -68,40 +592,16 @@ extern "C" {
DO_SIMPLE_FILTER(p0, q0, q9) /* apply filter */ \
FLIP_SIGN_BIT2(p0, q0, q10)
-// Load/Store vertical edge
-#define LOAD8x4(c1, c2, c3, c4, b1, b2, stride) \
- "vld4.8 {" #c1"[0], " #c2"[0], " #c3"[0], " #c4"[0]}," #b1 "," #stride"\n" \
- "vld4.8 {" #c1"[1], " #c2"[1], " #c3"[1], " #c4"[1]}," #b2 "," #stride"\n" \
- "vld4.8 {" #c1"[2], " #c2"[2], " #c3"[2], " #c4"[2]}," #b1 "," #stride"\n" \
- "vld4.8 {" #c1"[3], " #c2"[3], " #c3"[3], " #c4"[3]}," #b2 "," #stride"\n" \
- "vld4.8 {" #c1"[4], " #c2"[4], " #c3"[4], " #c4"[4]}," #b1 "," #stride"\n" \
- "vld4.8 {" #c1"[5], " #c2"[5], " #c3"[5], " #c4"[5]}," #b2 "," #stride"\n" \
- "vld4.8 {" #c1"[6], " #c2"[6], " #c3"[6], " #c4"[6]}," #b1 "," #stride"\n" \
- "vld4.8 {" #c1"[7], " #c2"[7], " #c3"[7], " #c4"[7]}," #b2 "," #stride"\n"
-
-#define STORE8x2(c1, c2, p,stride) \
- "vst2.8 {" #c1"[0], " #c2"[0]}," #p "," #stride " \n" \
- "vst2.8 {" #c1"[1], " #c2"[1]}," #p "," #stride " \n" \
- "vst2.8 {" #c1"[2], " #c2"[2]}," #p "," #stride " \n" \
- "vst2.8 {" #c1"[3], " #c2"[3]}," #p "," #stride " \n" \
- "vst2.8 {" #c1"[4], " #c2"[4]}," #p "," #stride " \n" \
- "vst2.8 {" #c1"[5], " #c2"[5]}," #p "," #stride " \n" \
- "vst2.8 {" #c1"[6], " #c2"[6]}," #p "," #stride " \n" \
- "vst2.8 {" #c1"[7], " #c2"[7]}," #p "," #stride " \n"
-
-//-----------------------------------------------------------------------------
-// Simple In-loop filtering (Paragraph 15.2)
-
-static void SimpleVFilter16NEON(uint8_t* p, int stride, int thresh) {
+static void SimpleVFilter16(uint8_t* p, int stride, int thresh) {
__asm__ volatile (
"sub %[p], %[p], %[stride], lsl #1 \n" // p -= 2 * stride
"vld1.u8 {q1}, [%[p]], %[stride] \n" // p1
"vld1.u8 {q2}, [%[p]], %[stride] \n" // p0
"vld1.u8 {q3}, [%[p]], %[stride] \n" // q0
- "vld1.u8 {q4}, [%[p]] \n" // q1
+ "vld1.u8 {q12}, [%[p]] \n" // q1
- DO_FILTER2(q1, q2, q3, q4, %[thresh])
+ DO_FILTER2(q1, q2, q3, q12, %[thresh])
"sub %[p], %[p], %[stride], lsl #1 \n" // p -= 2 * stride
@@ -113,25 +613,25 @@ static void SimpleVFilter16NEON(uint8_t* p, int stride, int thresh) {
);
}
-static void SimpleHFilter16NEON(uint8_t* p, int stride, int thresh) {
+static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
__asm__ volatile (
"sub r4, %[p], #2 \n" // base1 = p - 2
"lsl r6, %[stride], #1 \n" // r6 = 2 * stride
"add r5, r4, %[stride] \n" // base2 = base1 + stride
LOAD8x4(d2, d3, d4, d5, [r4], [r5], r6)
- LOAD8x4(d6, d7, d8, d9, [r4], [r5], r6)
- "vswp d3, d6 \n" // p1:q1 p0:q3
- "vswp d5, d8 \n" // q0:q2 q1:q4
- "vswp q2, q3 \n" // p1:q1 p0:q2 q0:q3 q1:q4
+ LOAD8x4(d24, d25, d26, d27, [r4], [r5], r6)
+ "vswp d3, d24 \n" // p1:q1 p0:q3
+ "vswp d5, d26 \n" // q0:q2 q1:q4
+ "vswp q2, q12 \n" // p1:q1 p0:q2 q0:q3 q1:q4
- DO_FILTER2(q1, q2, q3, q4, %[thresh])
+ DO_FILTER2(q1, q2, q12, q13, %[thresh])
"sub %[p], %[p], #1 \n" // p - 1
- "vswp d5, d6 \n"
+ "vswp d5, d24 \n"
STORE8x2(d4, d5, [%[p]], %[stride])
- STORE8x2(d6, d7, [%[p]], %[stride])
+ STORE8x2(d24, d25, [%[p]], %[stride])
: [p] "+r"(p)
: [stride] "r"(stride), [thresh] "r"(thresh)
@@ -139,44 +639,408 @@ static void SimpleHFilter16NEON(uint8_t* p, int stride, int thresh) {
);
}
-static void SimpleVFilter16iNEON(uint8_t* p, int stride, int thresh) {
- int k;
- for (k = 3; k > 0; --k) {
+#endif // WEBP_USE_INTRINSICS
+
+static void SimpleVFilter16i(uint8_t* p, int stride, int thresh) {
+ uint32_t k;
+ for (k = 3; k != 0; --k) {
p += 4 * stride;
- SimpleVFilter16NEON(p, stride, thresh);
+ SimpleVFilter16(p, stride, thresh);
}
}
-static void SimpleHFilter16iNEON(uint8_t* p, int stride, int thresh) {
- int k;
- for (k = 3; k > 0; --k) {
+static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) {
+ uint32_t k;
+ for (k = 3; k != 0; --k) {
p += 4;
- SimpleHFilter16NEON(p, stride, thresh);
+ SimpleHFilter16(p, stride, thresh);
}
}
-static void TransformOneNEON(const int16_t *in, uint8_t *dst) {
- const int kBPS = BPS;
- const int16_t constants[] = {20091, 17734, 0, 0};
- /* kC1, kC2. Padded because vld1.16 loads 8 bytes
- * Technically these are unsigned but vqdmulh is only available in signed.
- * vqdmulh returns high half (effectively >> 16) but also doubles the value,
- * changing the >> 16 to >> 15 and requiring an additional >> 1.
- * We use this to our advantage with kC2. The canonical value is 35468.
- * However, the high bit is set so treating it as signed will give incorrect
- * results. We avoid this by down shifting by 1 here to clear the highest bit.
- * Combined with the doubling effect of vqdmulh we get >> 16.
- * This can not be applied to kC1 because the lowest bit is set. Down shifting
- * the constant would reduce precision.
- */
-
- /* libwebp uses a trick to avoid some extra addition that libvpx does.
- * Instead of:
- * temp2 = ip[12] + ((ip[12] * cospi8sqrt2minus1) >> 16);
- * libwebp adds 1 << 16 to cospi8sqrt2minus1 (kC1). However, this causes the
- * same issue with kC1 and vqdmulh that we work around by down shifting kC2
- */
+//------------------------------------------------------------------------------
+// Complex In-loop filtering (Paragraph 15.3)
+
+static uint8x16_t NeedsHev(const uint8x16_t p1, const uint8x16_t p0,
+ const uint8x16_t q0, const uint8x16_t q1,
+ int hev_thresh) {
+ const uint8x16_t hev_thresh_v = vdupq_n_u8((uint8_t)hev_thresh);
+ const uint8x16_t a_p1_p0 = vabdq_u8(p1, p0); // abs(p1 - p0)
+ const uint8x16_t a_q1_q0 = vabdq_u8(q1, q0); // abs(q1 - q0)
+ const uint8x16_t mask1 = vcgtq_u8(a_p1_p0, hev_thresh_v);
+ const uint8x16_t mask2 = vcgtq_u8(a_q1_q0, hev_thresh_v);
+ const uint8x16_t mask = vorrq_u8(mask1, mask2);
+ return mask;
+}
+
+static uint8x16_t NeedsFilter2(const uint8x16_t p3, const uint8x16_t p2,
+ const uint8x16_t p1, const uint8x16_t p0,
+ const uint8x16_t q0, const uint8x16_t q1,
+ const uint8x16_t q2, const uint8x16_t q3,
+ int ithresh, int thresh) {
+ const uint8x16_t ithresh_v = vdupq_n_u8((uint8_t)ithresh);
+ const uint8x16_t a_p3_p2 = vabdq_u8(p3, p2); // abs(p3 - p2)
+ const uint8x16_t a_p2_p1 = vabdq_u8(p2, p1); // abs(p2 - p1)
+ const uint8x16_t a_p1_p0 = vabdq_u8(p1, p0); // abs(p1 - p0)
+ const uint8x16_t a_q3_q2 = vabdq_u8(q3, q2); // abs(q3 - q2)
+ const uint8x16_t a_q2_q1 = vabdq_u8(q2, q1); // abs(q2 - q1)
+ const uint8x16_t a_q1_q0 = vabdq_u8(q1, q0); // abs(q1 - q0)
+ const uint8x16_t max1 = vmaxq_u8(a_p3_p2, a_p2_p1);
+ const uint8x16_t max2 = vmaxq_u8(a_p1_p0, a_q3_q2);
+ const uint8x16_t max3 = vmaxq_u8(a_q2_q1, a_q1_q0);
+ const uint8x16_t max12 = vmaxq_u8(max1, max2);
+ const uint8x16_t max123 = vmaxq_u8(max12, max3);
+ const uint8x16_t mask2 = vcgeq_u8(ithresh_v, max123);
+ const uint8x16_t mask1 = NeedsFilter(p1, p0, q0, q1, thresh);
+ const uint8x16_t mask = vandq_u8(mask1, mask2);
+ return mask;
+}
+
+// 4-points filter
+
+static void ApplyFilter4(
+ const int8x16_t p1, const int8x16_t p0,
+ const int8x16_t q0, const int8x16_t q1,
+ const int8x16_t delta0,
+ uint8x16_t* const op1, uint8x16_t* const op0,
+ uint8x16_t* const oq0, uint8x16_t* const oq1) {
+ const int8x16_t kCst3 = vdupq_n_s8(0x03);
+ const int8x16_t kCst4 = vdupq_n_s8(0x04);
+ const int8x16_t delta1 = vqaddq_s8(delta0, kCst4);
+ const int8x16_t delta2 = vqaddq_s8(delta0, kCst3);
+ const int8x16_t a1 = vshrq_n_s8(delta1, 3);
+ const int8x16_t a2 = vshrq_n_s8(delta2, 3);
+ const int8x16_t a3 = vrshrq_n_s8(a1, 1); // a3 = (a1 + 1) >> 1
+ *op0 = FlipSignBack(vqaddq_s8(p0, a2)); // clip(p0 + a2)
+ *oq0 = FlipSignBack(vqsubq_s8(q0, a1)); // clip(q0 - a1)
+ *op1 = FlipSignBack(vqaddq_s8(p1, a3)); // clip(p1 + a3)
+ *oq1 = FlipSignBack(vqsubq_s8(q1, a3)); // clip(q1 - a3)
+}
+
+static void DoFilter4(
+ const uint8x16_t p1, const uint8x16_t p0,
+ const uint8x16_t q0, const uint8x16_t q1,
+ const uint8x16_t mask, const uint8x16_t hev_mask,
+ uint8x16_t* const op1, uint8x16_t* const op0,
+ uint8x16_t* const oq0, uint8x16_t* const oq1) {
+ // This is a fused version of DoFilter2() calling ApplyFilter2 directly
+ const int8x16_t p1s = FlipSign(p1);
+ int8x16_t p0s = FlipSign(p0);
+ int8x16_t q0s = FlipSign(q0);
+ const int8x16_t q1s = FlipSign(q1);
+ const uint8x16_t simple_lf_mask = vandq_u8(mask, hev_mask);
+
+ // do_filter2 part (simple loopfilter on pixels with hev)
+ {
+ const int8x16_t delta = GetBaseDelta(p1s, p0s, q0s, q1s);
+ const int8x16_t simple_lf_delta =
+ vandq_s8(delta, vreinterpretq_s8_u8(simple_lf_mask));
+ ApplyFilter2NoFlip(p0s, q0s, simple_lf_delta, &p0s, &q0s);
+ }
+
+ // do_filter4 part (complex loopfilter on pixels without hev)
+ {
+ const int8x16_t delta0 = GetBaseDelta0(p0s, q0s);
+ // we use: (mask & hev_mask) ^ mask = mask & !hev_mask
+ const uint8x16_t complex_lf_mask = veorq_u8(simple_lf_mask, mask);
+ const int8x16_t complex_lf_delta =
+ vandq_s8(delta0, vreinterpretq_s8_u8(complex_lf_mask));
+ ApplyFilter4(p1s, p0s, q0s, q1s, complex_lf_delta, op1, op0, oq0, oq1);
+ }
+}
+
+// 6-points filter
+
+static void ApplyFilter6(
+ const int8x16_t p2, const int8x16_t p1, const int8x16_t p0,
+ const int8x16_t q0, const int8x16_t q1, const int8x16_t q2,
+ const int8x16_t delta,
+ uint8x16_t* const op2, uint8x16_t* const op1, uint8x16_t* const op0,
+ uint8x16_t* const oq0, uint8x16_t* const oq1, uint8x16_t* const oq2) {
+ const int16x8_t kCst63 = vdupq_n_s16(63);
+ const int8x8_t kCst27 = vdup_n_s8(27);
+ const int8x8_t kCst18 = vdup_n_s8(18);
+ const int8x8_t kCst9 = vdup_n_s8(9);
+ const int8x8_t delta_lo = vget_low_s8(delta);
+ const int8x8_t delta_hi = vget_high_s8(delta);
+ const int16x8_t s1_lo = vmlal_s8(kCst63, kCst27, delta_lo); // 63 + 27 * a
+ const int16x8_t s1_hi = vmlal_s8(kCst63, kCst27, delta_hi); // 63 + 27 * a
+ const int16x8_t s2_lo = vmlal_s8(kCst63, kCst18, delta_lo); // 63 + 18 * a
+ const int16x8_t s2_hi = vmlal_s8(kCst63, kCst18, delta_hi); // 63 + 18 * a
+ const int16x8_t s3_lo = vmlal_s8(kCst63, kCst9, delta_lo); // 63 + 9 * a
+ const int16x8_t s3_hi = vmlal_s8(kCst63, kCst9, delta_hi); // 63 + 9 * a
+ const int8x8_t a1_lo = vqshrn_n_s16(s1_lo, 7);
+ const int8x8_t a1_hi = vqshrn_n_s16(s1_hi, 7);
+ const int8x8_t a2_lo = vqshrn_n_s16(s2_lo, 7);
+ const int8x8_t a2_hi = vqshrn_n_s16(s2_hi, 7);
+ const int8x8_t a3_lo = vqshrn_n_s16(s3_lo, 7);
+ const int8x8_t a3_hi = vqshrn_n_s16(s3_hi, 7);
+ const int8x16_t a1 = vcombine_s8(a1_lo, a1_hi);
+ const int8x16_t a2 = vcombine_s8(a2_lo, a2_hi);
+ const int8x16_t a3 = vcombine_s8(a3_lo, a3_hi);
+
+ *op0 = FlipSignBack(vqaddq_s8(p0, a1)); // clip(p0 + a1)
+ *oq0 = FlipSignBack(vqsubq_s8(q0, a1)); // clip(q0 - q1)
+ *oq1 = FlipSignBack(vqsubq_s8(q1, a2)); // clip(q1 - a2)
+ *op1 = FlipSignBack(vqaddq_s8(p1, a2)); // clip(p1 + a2)
+ *oq2 = FlipSignBack(vqsubq_s8(q2, a3)); // clip(q2 - a3)
+ *op2 = FlipSignBack(vqaddq_s8(p2, a3)); // clip(p2 + a3)
+}
+
+static void DoFilter6(
+ const uint8x16_t p2, const uint8x16_t p1, const uint8x16_t p0,
+ const uint8x16_t q0, const uint8x16_t q1, const uint8x16_t q2,
+ const uint8x16_t mask, const uint8x16_t hev_mask,
+ uint8x16_t* const op2, uint8x16_t* const op1, uint8x16_t* const op0,
+ uint8x16_t* const oq0, uint8x16_t* const oq1, uint8x16_t* const oq2) {
+ // This is a fused version of DoFilter2() calling ApplyFilter2 directly
+ const int8x16_t p2s = FlipSign(p2);
+ const int8x16_t p1s = FlipSign(p1);
+ int8x16_t p0s = FlipSign(p0);
+ int8x16_t q0s = FlipSign(q0);
+ const int8x16_t q1s = FlipSign(q1);
+ const int8x16_t q2s = FlipSign(q2);
+ const uint8x16_t simple_lf_mask = vandq_u8(mask, hev_mask);
+ const int8x16_t delta0 = GetBaseDelta(p1s, p0s, q0s, q1s);
+
+ // do_filter2 part (simple loopfilter on pixels with hev)
+ {
+ const int8x16_t simple_lf_delta =
+ vandq_s8(delta0, vreinterpretq_s8_u8(simple_lf_mask));
+ ApplyFilter2NoFlip(p0s, q0s, simple_lf_delta, &p0s, &q0s);
+ }
+
+ // do_filter6 part (complex loopfilter on pixels without hev)
+ {
+ // we use: (mask & hev_mask) ^ mask = mask & !hev_mask
+ const uint8x16_t complex_lf_mask = veorq_u8(simple_lf_mask, mask);
+ const int8x16_t complex_lf_delta =
+ vandq_s8(delta0, vreinterpretq_s8_u8(complex_lf_mask));
+ ApplyFilter6(p2s, p1s, p0s, q0s, q1s, q2s, complex_lf_delta,
+ op2, op1, op0, oq0, oq1, oq2);
+ }
+}
+
+// on macroblock edges
+
+static void VFilter16(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3;
+ Load16x8(p, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
+ {
+ const uint8x16_t mask = NeedsFilter2(p3, p2, p1, p0, q0, q1, q2, q3,
+ ithresh, thresh);
+ const uint8x16_t hev_mask = NeedsHev(p1, p0, q0, q1, hev_thresh);
+ uint8x16_t op2, op1, op0, oq0, oq1, oq2;
+ DoFilter6(p2, p1, p0, q0, q1, q2, mask, hev_mask,
+ &op2, &op1, &op0, &oq0, &oq1, &oq2);
+ Store16x2(op2, op1, p - 2 * stride, stride);
+ Store16x2(op0, oq0, p + 0 * stride, stride);
+ Store16x2(oq1, oq2, p + 2 * stride, stride);
+ }
+}
+
+static void HFilter16(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3;
+ Load8x16(p, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
+ {
+ const uint8x16_t mask = NeedsFilter2(p3, p2, p1, p0, q0, q1, q2, q3,
+ ithresh, thresh);
+ const uint8x16_t hev_mask = NeedsHev(p1, p0, q0, q1, hev_thresh);
+ uint8x16_t op2, op1, op0, oq0, oq1, oq2;
+ DoFilter6(p2, p1, p0, q0, q1, q2, mask, hev_mask,
+ &op2, &op1, &op0, &oq0, &oq1, &oq2);
+ Store2x16(op2, op1, p - 2, stride);
+ Store2x16(op0, oq0, p + 0, stride);
+ Store2x16(oq1, oq2, p + 2, stride);
+ }
+}
+
+// on three inner edges
+static void VFilter16i(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ uint32_t k;
+ uint8x16_t p3, p2, p1, p0;
+ Load16x4(p + 2 * stride, stride, &p3, &p2, &p1, &p0);
+ for (k = 3; k != 0; --k) {
+ uint8x16_t q0, q1, q2, q3;
+ p += 4 * stride;
+ Load16x4(p + 2 * stride, stride, &q0, &q1, &q2, &q3);
+ {
+ const uint8x16_t mask =
+ NeedsFilter2(p3, p2, p1, p0, q0, q1, q2, q3, ithresh, thresh);
+ const uint8x16_t hev_mask = NeedsHev(p1, p0, q0, q1, hev_thresh);
+ // p3 and p2 are not just temporary variables here: they will be
+ // re-used for next span. And q2/q3 will become p1/p0 accordingly.
+ DoFilter4(p1, p0, q0, q1, mask, hev_mask, &p1, &p0, &p3, &p2);
+ Store16x4(p1, p0, p3, p2, p, stride);
+ p1 = q2;
+ p0 = q3;
+ }
+ }
+}
+
+#if !defined(WORK_AROUND_GCC)
+static void HFilter16i(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ uint32_t k;
+ uint8x16_t p3, p2, p1, p0;
+ Load4x16(p + 2, stride, &p3, &p2, &p1, &p0);
+ for (k = 3; k != 0; --k) {
+ uint8x16_t q0, q1, q2, q3;
+ p += 4;
+ Load4x16(p + 2, stride, &q0, &q1, &q2, &q3);
+ {
+ const uint8x16_t mask =
+ NeedsFilter2(p3, p2, p1, p0, q0, q1, q2, q3, ithresh, thresh);
+ const uint8x16_t hev_mask = NeedsHev(p1, p0, q0, q1, hev_thresh);
+ DoFilter4(p1, p0, q0, q1, mask, hev_mask, &p1, &p0, &p3, &p2);
+ Store4x16(p1, p0, p3, p2, p, stride);
+ p1 = q2;
+ p0 = q3;
+ }
+ }
+}
+#endif // !WORK_AROUND_GCC
+
+// 8-pixels wide variant, for chroma filtering
+static void VFilter8(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3;
+ Load8x8x2(u, v, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
+ {
+ const uint8x16_t mask = NeedsFilter2(p3, p2, p1, p0, q0, q1, q2, q3,
+ ithresh, thresh);
+ const uint8x16_t hev_mask = NeedsHev(p1, p0, q0, q1, hev_thresh);
+ uint8x16_t op2, op1, op0, oq0, oq1, oq2;
+ DoFilter6(p2, p1, p0, q0, q1, q2, mask, hev_mask,
+ &op2, &op1, &op0, &oq0, &oq1, &oq2);
+ Store8x2x2(op2, op1, u - 2 * stride, v - 2 * stride, stride);
+ Store8x2x2(op0, oq0, u + 0 * stride, v + 0 * stride, stride);
+ Store8x2x2(oq1, oq2, u + 2 * stride, v + 2 * stride, stride);
+ }
+}
+static void VFilter8i(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3;
+ u += 4 * stride;
+ v += 4 * stride;
+ Load8x8x2(u, v, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
+ {
+ const uint8x16_t mask = NeedsFilter2(p3, p2, p1, p0, q0, q1, q2, q3,
+ ithresh, thresh);
+ const uint8x16_t hev_mask = NeedsHev(p1, p0, q0, q1, hev_thresh);
+ uint8x16_t op1, op0, oq0, oq1;
+ DoFilter4(p1, p0, q0, q1, mask, hev_mask, &op1, &op0, &oq0, &oq1);
+ Store8x4x2(op1, op0, oq0, oq1, u, v, stride);
+ }
+}
+
+#if !defined(WORK_AROUND_GCC)
+static void HFilter8(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3;
+ Load8x8x2T(u, v, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
+ {
+ const uint8x16_t mask = NeedsFilter2(p3, p2, p1, p0, q0, q1, q2, q3,
+ ithresh, thresh);
+ const uint8x16_t hev_mask = NeedsHev(p1, p0, q0, q1, hev_thresh);
+ uint8x16_t op2, op1, op0, oq0, oq1, oq2;
+ DoFilter6(p2, p1, p0, q0, q1, q2, mask, hev_mask,
+ &op2, &op1, &op0, &oq0, &oq1, &oq2);
+ Store6x8x2(op2, op1, op0, oq0, oq1, oq2, u, v, stride);
+ }
+}
+
+static void HFilter8i(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ uint8x16_t p3, p2, p1, p0, q0, q1, q2, q3;
+ u += 4;
+ v += 4;
+ Load8x8x2T(u, v, stride, &p3, &p2, &p1, &p0, &q0, &q1, &q2, &q3);
+ {
+ const uint8x16_t mask = NeedsFilter2(p3, p2, p1, p0, q0, q1, q2, q3,
+ ithresh, thresh);
+ const uint8x16_t hev_mask = NeedsHev(p1, p0, q0, q1, hev_thresh);
+ uint8x16_t op1, op0, oq0, oq1;
+ DoFilter4(p1, p0, q0, q1, mask, hev_mask, &op1, &op0, &oq0, &oq1);
+ Store4x8x2(op1, op0, oq0, oq1, u, v, stride);
+ }
+}
+#endif // !WORK_AROUND_GCC
+
+//-----------------------------------------------------------------------------
+// Inverse transforms (Paragraph 14.4)
+
+// Technically these are unsigned but vqdmulh is only available in signed.
+// vqdmulh returns high half (effectively >> 16) but also doubles the value,
+// changing the >> 16 to >> 15 and requiring an additional >> 1.
+// We use this to our advantage with kC2. The canonical value is 35468.
+// However, the high bit is set so treating it as signed will give incorrect
+// results. We avoid this by down shifting by 1 here to clear the highest bit.
+// Combined with the doubling effect of vqdmulh we get >> 16.
+// This can not be applied to kC1 because the lowest bit is set. Down shifting
+// the constant would reduce precision.
+
+// libwebp uses a trick to avoid some extra addition that libvpx does.
+// Instead of:
+// temp2 = ip[12] + ((ip[12] * cospi8sqrt2minus1) >> 16);
+// libwebp adds 1 << 16 to cospi8sqrt2minus1 (kC1). However, this causes the
+// same issue with kC1 and vqdmulh that we work around by down shifting kC2
+static const int16_t kC1 = 20091;
+static const int16_t kC2 = 17734; // half of kC2, actually. See comment above.
+
+#if defined(WEBP_USE_INTRINSICS)
+static WEBP_INLINE void Transpose8x2(const int16x8_t in0, const int16x8_t in1,
+ int16x8x2_t* const out) {
+ // a0 a1 a2 a3 | b0 b1 b2 b3 => a0 b0 c0 d0 | a1 b1 c1 d1
+ // c0 c1 c2 c3 | d0 d1 d2 d3 a2 b2 c2 d2 | a3 b3 c3 d3
+ const int16x8x2_t tmp0 = vzipq_s16(in0, in1); // a0 c0 a1 c1 a2 c2 ...
+ // b0 d0 b1 d1 b2 d2 ...
+ *out = vzipq_s16(tmp0.val[0], tmp0.val[1]);
+}
+
+static WEBP_INLINE void TransformPass(int16x8x2_t* const rows) {
+ // {rows} = in0 | in4
+ // in8 | in12
+ // B1 = in4 | in12
+ const int16x8_t B1 =
+ vcombine_s16(vget_high_s16(rows->val[0]), vget_high_s16(rows->val[1]));
+ // C0 = kC1 * in4 | kC1 * in12
+ // C1 = kC2 * in4 | kC2 * in12
+ const int16x8_t C0 = vsraq_n_s16(B1, vqdmulhq_n_s16(B1, kC1), 1);
+ const int16x8_t C1 = vqdmulhq_n_s16(B1, kC2);
+ const int16x4_t a = vqadd_s16(vget_low_s16(rows->val[0]),
+ vget_low_s16(rows->val[1])); // in0 + in8
+ const int16x4_t b = vqsub_s16(vget_low_s16(rows->val[0]),
+ vget_low_s16(rows->val[1])); // in0 - in8
+ // c = kC2 * in4 - kC1 * in12
+ // d = kC1 * in4 + kC2 * in12
+ const int16x4_t c = vqsub_s16(vget_low_s16(C1), vget_high_s16(C0));
+ const int16x4_t d = vqadd_s16(vget_low_s16(C0), vget_high_s16(C1));
+ const int16x8_t D0 = vcombine_s16(a, b); // D0 = a | b
+ const int16x8_t D1 = vcombine_s16(d, c); // D1 = d | c
+ const int16x8_t E0 = vqaddq_s16(D0, D1); // a+d | b+c
+ const int16x8_t E_tmp = vqsubq_s16(D0, D1); // a-d | b-c
+ const int16x8_t E1 = vcombine_s16(vget_high_s16(E_tmp), vget_low_s16(E_tmp));
+ Transpose8x2(E0, E1, rows);
+}
+
+static void TransformOne(const int16_t* in, uint8_t* dst) {
+ int16x8x2_t rows;
+ INIT_VECTOR2(rows, vld1q_s16(in + 0), vld1q_s16(in + 8));
+ TransformPass(&rows);
+ TransformPass(&rows);
+ Add4x4(rows.val[0], rows.val[1], dst);
+}
+
+#else
+
+static void TransformOne(const int16_t* in, uint8_t* dst) {
+ const int kBPS = BPS;
+ // kC1, kC2. Padded because vld1.16 loads 8 bytes
+ const int16_t constants[4] = { kC1, kC2, 0, 0 };
/* Adapted from libvpx: vp8/common/arm/neon/shortidct4x4llm_neon.asm */
__asm__ volatile (
"vld1.16 {q1, q2}, [%[in]] \n"
@@ -304,26 +1168,472 @@ static void TransformOneNEON(const int16_t *in, uint8_t *dst) {
);
}
-static void TransformTwoNEON(const int16_t* in, uint8_t* dst, int do_two) {
- TransformOneNEON(in, dst);
+#endif // WEBP_USE_INTRINSICS
+
+static void TransformTwo(const int16_t* in, uint8_t* dst, int do_two) {
+ TransformOne(in, dst);
if (do_two) {
- TransformOneNEON(in + 16, dst + 4);
+ TransformOne(in + 16, dst + 4);
}
}
-extern void VP8DspInitNEON(void);
+static void TransformDC(const int16_t* in, uint8_t* dst) {
+ const int16x8_t DC = vdupq_n_s16(in[0]);
+ Add4x4(DC, DC, dst);
+}
+
+//------------------------------------------------------------------------------
+
+#define STORE_WHT(dst, col, rows) do { \
+ *dst = vgetq_lane_s32(rows.val[0], col); (dst) += 16; \
+ *dst = vgetq_lane_s32(rows.val[1], col); (dst) += 16; \
+ *dst = vgetq_lane_s32(rows.val[2], col); (dst) += 16; \
+ *dst = vgetq_lane_s32(rows.val[3], col); (dst) += 16; \
+} while (0)
+
+static void TransformWHT(const int16_t* in, int16_t* out) {
+ int32x4x4_t tmp;
-void VP8DspInitNEON(void) {
- VP8Transform = TransformTwoNEON;
+ {
+ // Load the source.
+ const int16x4_t in00_03 = vld1_s16(in + 0);
+ const int16x4_t in04_07 = vld1_s16(in + 4);
+ const int16x4_t in08_11 = vld1_s16(in + 8);
+ const int16x4_t in12_15 = vld1_s16(in + 12);
+ const int32x4_t a0 = vaddl_s16(in00_03, in12_15); // in[0..3] + in[12..15]
+ const int32x4_t a1 = vaddl_s16(in04_07, in08_11); // in[4..7] + in[8..11]
+ const int32x4_t a2 = vsubl_s16(in04_07, in08_11); // in[4..7] - in[8..11]
+ const int32x4_t a3 = vsubl_s16(in00_03, in12_15); // in[0..3] - in[12..15]
+ tmp.val[0] = vaddq_s32(a0, a1);
+ tmp.val[1] = vaddq_s32(a3, a2);
+ tmp.val[2] = vsubq_s32(a0, a1);
+ tmp.val[3] = vsubq_s32(a3, a2);
+ // Arrange the temporary results column-wise.
+ tmp = Transpose4x4(tmp);
+ }
+
+ {
+ const int32x4_t kCst3 = vdupq_n_s32(3);
+ const int32x4_t dc = vaddq_s32(tmp.val[0], kCst3); // add rounder
+ const int32x4_t a0 = vaddq_s32(dc, tmp.val[3]);
+ const int32x4_t a1 = vaddq_s32(tmp.val[1], tmp.val[2]);
+ const int32x4_t a2 = vsubq_s32(tmp.val[1], tmp.val[2]);
+ const int32x4_t a3 = vsubq_s32(dc, tmp.val[3]);
+
+ tmp.val[0] = vaddq_s32(a0, a1);
+ tmp.val[1] = vaddq_s32(a3, a2);
+ tmp.val[2] = vsubq_s32(a0, a1);
+ tmp.val[3] = vsubq_s32(a3, a2);
+
+ // right shift the results by 3.
+ tmp.val[0] = vshrq_n_s32(tmp.val[0], 3);
+ tmp.val[1] = vshrq_n_s32(tmp.val[1], 3);
+ tmp.val[2] = vshrq_n_s32(tmp.val[2], 3);
+ tmp.val[3] = vshrq_n_s32(tmp.val[3], 3);
- VP8SimpleVFilter16 = SimpleVFilter16NEON;
- VP8SimpleHFilter16 = SimpleHFilter16NEON;
- VP8SimpleVFilter16i = SimpleVFilter16iNEON;
- VP8SimpleHFilter16i = SimpleHFilter16iNEON;
+ STORE_WHT(out, 0, tmp);
+ STORE_WHT(out, 1, tmp);
+ STORE_WHT(out, 2, tmp);
+ STORE_WHT(out, 3, tmp);
+ }
}
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
+#undef STORE_WHT
+
+//------------------------------------------------------------------------------
+
+#define MUL(a, b) (((a) * (b)) >> 16)
+static void TransformAC3(const int16_t* in, uint8_t* dst) {
+ static const int kC1_full = 20091 + (1 << 16);
+ static const int kC2_full = 35468;
+ const int16x4_t A = vld1_dup_s16(in);
+ const int16x4_t c4 = vdup_n_s16(MUL(in[4], kC2_full));
+ const int16x4_t d4 = vdup_n_s16(MUL(in[4], kC1_full));
+ const int c1 = MUL(in[1], kC2_full);
+ const int d1 = MUL(in[1], kC1_full);
+ const uint64_t cd = (uint64_t)( d1 & 0xffff) << 0 |
+ (uint64_t)( c1 & 0xffff) << 16 |
+ (uint64_t)(-c1 & 0xffff) << 32 |
+ (uint64_t)(-d1 & 0xffff) << 48;
+ const int16x4_t CD = vcreate_s16(cd);
+ const int16x4_t B = vqadd_s16(A, CD);
+ const int16x8_t m0_m1 = vcombine_s16(vqadd_s16(B, d4), vqadd_s16(B, c4));
+ const int16x8_t m2_m3 = vcombine_s16(vqsub_s16(B, c4), vqsub_s16(B, d4));
+ Add4x4(m0_m1, m2_m3, dst);
+}
+#undef MUL
+
+//------------------------------------------------------------------------------
+// 4x4
+
+static void DC4(uint8_t* dst) { // DC
+ const uint8x8_t A = vld1_u8(dst - BPS); // top row
+ const uint16x4_t p0 = vpaddl_u8(A); // cascading summation of the top
+ const uint16x4_t p1 = vpadd_u16(p0, p0);
+ const uint16x8_t L0 = vmovl_u8(vld1_u8(dst + 0 * BPS - 1));
+ const uint16x8_t L1 = vmovl_u8(vld1_u8(dst + 1 * BPS - 1));
+ const uint16x8_t L2 = vmovl_u8(vld1_u8(dst + 2 * BPS - 1));
+ const uint16x8_t L3 = vmovl_u8(vld1_u8(dst + 3 * BPS - 1));
+ const uint16x8_t s0 = vaddq_u16(L0, L1);
+ const uint16x8_t s1 = vaddq_u16(L2, L3);
+ const uint16x8_t s01 = vaddq_u16(s0, s1);
+ const uint16x8_t sum = vaddq_u16(s01, vcombine_u16(p1, p1));
+ const uint8x8_t dc0 = vrshrn_n_u16(sum, 3); // (sum + 4) >> 3
+ const uint8x8_t dc = vdup_lane_u8(dc0, 0);
+ int i;
+ for (i = 0; i < 4; ++i) {
+ vst1_lane_u32((uint32_t*)(dst + i * BPS), vreinterpret_u32_u8(dc), 0);
+ }
+}
+
+// TrueMotion (4x4 + 8x8)
+static WEBP_INLINE void TrueMotion(uint8_t* dst, int size) {
+ const uint8x8_t TL = vld1_dup_u8(dst - BPS - 1); // top-left pixel 'A[-1]'
+ const uint8x8_t T = vld1_u8(dst - BPS); // top row 'A[0..3]'
+ const int16x8_t d = vreinterpretq_s16_u16(vsubl_u8(T, TL)); // A[c] - A[-1]
+ int y;
+ for (y = 0; y < size; y += 4) {
+ // left edge
+ const int16x8_t L0 = ConvertU8ToS16(vld1_dup_u8(dst + 0 * BPS - 1));
+ const int16x8_t L1 = ConvertU8ToS16(vld1_dup_u8(dst + 1 * BPS - 1));
+ const int16x8_t L2 = ConvertU8ToS16(vld1_dup_u8(dst + 2 * BPS - 1));
+ const int16x8_t L3 = ConvertU8ToS16(vld1_dup_u8(dst + 3 * BPS - 1));
+ const int16x8_t r0 = vaddq_s16(L0, d); // L[r] + A[c] - A[-1]
+ const int16x8_t r1 = vaddq_s16(L1, d);
+ const int16x8_t r2 = vaddq_s16(L2, d);
+ const int16x8_t r3 = vaddq_s16(L3, d);
+ // Saturate and store the result.
+ const uint32x2_t r0_u32 = vreinterpret_u32_u8(vqmovun_s16(r0));
+ const uint32x2_t r1_u32 = vreinterpret_u32_u8(vqmovun_s16(r1));
+ const uint32x2_t r2_u32 = vreinterpret_u32_u8(vqmovun_s16(r2));
+ const uint32x2_t r3_u32 = vreinterpret_u32_u8(vqmovun_s16(r3));
+ if (size == 4) {
+ vst1_lane_u32((uint32_t*)(dst + 0 * BPS), r0_u32, 0);
+ vst1_lane_u32((uint32_t*)(dst + 1 * BPS), r1_u32, 0);
+ vst1_lane_u32((uint32_t*)(dst + 2 * BPS), r2_u32, 0);
+ vst1_lane_u32((uint32_t*)(dst + 3 * BPS), r3_u32, 0);
+ } else {
+ vst1_u32((uint32_t*)(dst + 0 * BPS), r0_u32);
+ vst1_u32((uint32_t*)(dst + 1 * BPS), r1_u32);
+ vst1_u32((uint32_t*)(dst + 2 * BPS), r2_u32);
+ vst1_u32((uint32_t*)(dst + 3 * BPS), r3_u32);
+ }
+ dst += 4 * BPS;
+ }
+}
+
+static void TM4(uint8_t* dst) { TrueMotion(dst, 4); }
+
+static void VE4(uint8_t* dst) { // vertical
+ // NB: avoid vld1_u64 here as an alignment hint may be added -> SIGBUS.
+ const uint64x1_t A0 = vreinterpret_u64_u8(vld1_u8(dst - BPS - 1)); // top row
+ const uint64x1_t A1 = vshr_n_u64(A0, 8);
+ const uint64x1_t A2 = vshr_n_u64(A0, 16);
+ const uint8x8_t ABCDEFGH = vreinterpret_u8_u64(A0);
+ const uint8x8_t BCDEFGH0 = vreinterpret_u8_u64(A1);
+ const uint8x8_t CDEFGH00 = vreinterpret_u8_u64(A2);
+ const uint8x8_t b = vhadd_u8(ABCDEFGH, CDEFGH00);
+ const uint8x8_t avg = vrhadd_u8(b, BCDEFGH0);
+ int i;
+ for (i = 0; i < 4; ++i) {
+ vst1_lane_u32((uint32_t*)(dst + i * BPS), vreinterpret_u32_u8(avg), 0);
+ }
+}
+
+static void RD4(uint8_t* dst) { // Down-right
+ const uint8x8_t XABCD_u8 = vld1_u8(dst - BPS - 1);
+ const uint64x1_t XABCD = vreinterpret_u64_u8(XABCD_u8);
+ const uint64x1_t ____XABC = vshl_n_u64(XABCD, 32);
+ const uint32_t I = dst[-1 + 0 * BPS];
+ const uint32_t J = dst[-1 + 1 * BPS];
+ const uint32_t K = dst[-1 + 2 * BPS];
+ const uint32_t L = dst[-1 + 3 * BPS];
+ const uint64x1_t LKJI____ = vcreate_u64(L | (K << 8) | (J << 16) | (I << 24));
+ const uint64x1_t LKJIXABC = vorr_u64(LKJI____, ____XABC);
+ const uint8x8_t KJIXABC_ = vreinterpret_u8_u64(vshr_n_u64(LKJIXABC, 8));
+ const uint8x8_t JIXABC__ = vreinterpret_u8_u64(vshr_n_u64(LKJIXABC, 16));
+ const uint8_t D = vget_lane_u8(XABCD_u8, 4);
+ const uint8x8_t JIXABCD_ = vset_lane_u8(D, JIXABC__, 6);
+ const uint8x8_t LKJIXABC_u8 = vreinterpret_u8_u64(LKJIXABC);
+ const uint8x8_t avg1 = vhadd_u8(JIXABCD_, LKJIXABC_u8);
+ const uint8x8_t avg2 = vrhadd_u8(avg1, KJIXABC_);
+ const uint64x1_t avg2_u64 = vreinterpret_u64_u8(avg2);
+ const uint32x2_t r3 = vreinterpret_u32_u8(avg2);
+ const uint32x2_t r2 = vreinterpret_u32_u64(vshr_n_u64(avg2_u64, 8));
+ const uint32x2_t r1 = vreinterpret_u32_u64(vshr_n_u64(avg2_u64, 16));
+ const uint32x2_t r0 = vreinterpret_u32_u64(vshr_n_u64(avg2_u64, 24));
+ vst1_lane_u32((uint32_t*)(dst + 0 * BPS), r0, 0);
+ vst1_lane_u32((uint32_t*)(dst + 1 * BPS), r1, 0);
+ vst1_lane_u32((uint32_t*)(dst + 2 * BPS), r2, 0);
+ vst1_lane_u32((uint32_t*)(dst + 3 * BPS), r3, 0);
+}
+
+static void LD4(uint8_t* dst) { // Down-left
+ // Note using the same shift trick as VE4() is slower here.
+ const uint8x8_t ABCDEFGH = vld1_u8(dst - BPS + 0);
+ const uint8x8_t BCDEFGH0 = vld1_u8(dst - BPS + 1);
+ const uint8x8_t CDEFGH00 = vld1_u8(dst - BPS + 2);
+ const uint8x8_t CDEFGHH0 = vset_lane_u8(dst[-BPS + 7], CDEFGH00, 6);
+ const uint8x8_t avg1 = vhadd_u8(ABCDEFGH, CDEFGHH0);
+ const uint8x8_t avg2 = vrhadd_u8(avg1, BCDEFGH0);
+ const uint64x1_t avg2_u64 = vreinterpret_u64_u8(avg2);
+ const uint32x2_t r0 = vreinterpret_u32_u8(avg2);
+ const uint32x2_t r1 = vreinterpret_u32_u64(vshr_n_u64(avg2_u64, 8));
+ const uint32x2_t r2 = vreinterpret_u32_u64(vshr_n_u64(avg2_u64, 16));
+ const uint32x2_t r3 = vreinterpret_u32_u64(vshr_n_u64(avg2_u64, 24));
+ vst1_lane_u32((uint32_t*)(dst + 0 * BPS), r0, 0);
+ vst1_lane_u32((uint32_t*)(dst + 1 * BPS), r1, 0);
+ vst1_lane_u32((uint32_t*)(dst + 2 * BPS), r2, 0);
+ vst1_lane_u32((uint32_t*)(dst + 3 * BPS), r3, 0);
+}
+
+//------------------------------------------------------------------------------
+// Chroma
+
+static void VE8uv(uint8_t* dst) { // vertical
+ const uint8x8_t top = vld1_u8(dst - BPS);
+ int j;
+ for (j = 0; j < 8; ++j) {
+ vst1_u8(dst + j * BPS, top);
+ }
+}
+
+static void HE8uv(uint8_t* dst) { // horizontal
+ int j;
+ for (j = 0; j < 8; ++j) {
+ const uint8x8_t left = vld1_dup_u8(dst - 1);
+ vst1_u8(dst, left);
+ dst += BPS;
+ }
+}
+
+static WEBP_INLINE void DC8(uint8_t* dst, int do_top, int do_left) {
+ uint16x8_t sum_top;
+ uint16x8_t sum_left;
+ uint8x8_t dc0;
+
+ if (do_top) {
+ const uint8x8_t A = vld1_u8(dst - BPS); // top row
+ const uint16x4_t p0 = vpaddl_u8(A); // cascading summation of the top
+ const uint16x4_t p1 = vpadd_u16(p0, p0);
+ const uint16x4_t p2 = vpadd_u16(p1, p1);
+ sum_top = vcombine_u16(p2, p2);
+ }
+
+ if (do_left) {
+ const uint16x8_t L0 = vmovl_u8(vld1_u8(dst + 0 * BPS - 1));
+ const uint16x8_t L1 = vmovl_u8(vld1_u8(dst + 1 * BPS - 1));
+ const uint16x8_t L2 = vmovl_u8(vld1_u8(dst + 2 * BPS - 1));
+ const uint16x8_t L3 = vmovl_u8(vld1_u8(dst + 3 * BPS - 1));
+ const uint16x8_t L4 = vmovl_u8(vld1_u8(dst + 4 * BPS - 1));
+ const uint16x8_t L5 = vmovl_u8(vld1_u8(dst + 5 * BPS - 1));
+ const uint16x8_t L6 = vmovl_u8(vld1_u8(dst + 6 * BPS - 1));
+ const uint16x8_t L7 = vmovl_u8(vld1_u8(dst + 7 * BPS - 1));
+ const uint16x8_t s0 = vaddq_u16(L0, L1);
+ const uint16x8_t s1 = vaddq_u16(L2, L3);
+ const uint16x8_t s2 = vaddq_u16(L4, L5);
+ const uint16x8_t s3 = vaddq_u16(L6, L7);
+ const uint16x8_t s01 = vaddq_u16(s0, s1);
+ const uint16x8_t s23 = vaddq_u16(s2, s3);
+ sum_left = vaddq_u16(s01, s23);
+ }
+
+ if (do_top && do_left) {
+ const uint16x8_t sum = vaddq_u16(sum_left, sum_top);
+ dc0 = vrshrn_n_u16(sum, 4);
+ } else if (do_top) {
+ dc0 = vrshrn_n_u16(sum_top, 3);
+ } else if (do_left) {
+ dc0 = vrshrn_n_u16(sum_left, 3);
+ } else {
+ dc0 = vdup_n_u8(0x80);
+ }
+
+ {
+ const uint8x8_t dc = vdup_lane_u8(dc0, 0);
+ int i;
+ for (i = 0; i < 8; ++i) {
+ vst1_u32((uint32_t*)(dst + i * BPS), vreinterpret_u32_u8(dc));
+ }
+ }
+}
+
+static void DC8uv(uint8_t* dst) { DC8(dst, 1, 1); }
+static void DC8uvNoTop(uint8_t* dst) { DC8(dst, 0, 1); }
+static void DC8uvNoLeft(uint8_t* dst) { DC8(dst, 1, 0); }
+static void DC8uvNoTopLeft(uint8_t* dst) { DC8(dst, 0, 0); }
+
+static void TM8uv(uint8_t* dst) { TrueMotion(dst, 8); }
+
+//------------------------------------------------------------------------------
+// 16x16
+
+static void VE16(uint8_t* dst) { // vertical
+ const uint8x16_t top = vld1q_u8(dst - BPS);
+ int j;
+ for (j = 0; j < 16; ++j) {
+ vst1q_u8(dst + j * BPS, top);
+ }
+}
+
+static void HE16(uint8_t* dst) { // horizontal
+ int j;
+ for (j = 0; j < 16; ++j) {
+ const uint8x16_t left = vld1q_dup_u8(dst - 1);
+ vst1q_u8(dst, left);
+ dst += BPS;
+ }
+}
+
+static WEBP_INLINE void DC16(uint8_t* dst, int do_top, int do_left) {
+ uint16x8_t sum_top;
+ uint16x8_t sum_left;
+ uint8x8_t dc0;
+
+ if (do_top) {
+ const uint8x16_t A = vld1q_u8(dst - BPS); // top row
+ const uint16x8_t p0 = vpaddlq_u8(A); // cascading summation of the top
+ const uint16x4_t p1 = vadd_u16(vget_low_u16(p0), vget_high_u16(p0));
+ const uint16x4_t p2 = vpadd_u16(p1, p1);
+ const uint16x4_t p3 = vpadd_u16(p2, p2);
+ sum_top = vcombine_u16(p3, p3);
+ }
+
+ if (do_left) {
+ int i;
+ sum_left = vdupq_n_u16(0);
+ for (i = 0; i < 16; i += 8) {
+ const uint16x8_t L0 = vmovl_u8(vld1_u8(dst + (i + 0) * BPS - 1));
+ const uint16x8_t L1 = vmovl_u8(vld1_u8(dst + (i + 1) * BPS - 1));
+ const uint16x8_t L2 = vmovl_u8(vld1_u8(dst + (i + 2) * BPS - 1));
+ const uint16x8_t L3 = vmovl_u8(vld1_u8(dst + (i + 3) * BPS - 1));
+ const uint16x8_t L4 = vmovl_u8(vld1_u8(dst + (i + 4) * BPS - 1));
+ const uint16x8_t L5 = vmovl_u8(vld1_u8(dst + (i + 5) * BPS - 1));
+ const uint16x8_t L6 = vmovl_u8(vld1_u8(dst + (i + 6) * BPS - 1));
+ const uint16x8_t L7 = vmovl_u8(vld1_u8(dst + (i + 7) * BPS - 1));
+ const uint16x8_t s0 = vaddq_u16(L0, L1);
+ const uint16x8_t s1 = vaddq_u16(L2, L3);
+ const uint16x8_t s2 = vaddq_u16(L4, L5);
+ const uint16x8_t s3 = vaddq_u16(L6, L7);
+ const uint16x8_t s01 = vaddq_u16(s0, s1);
+ const uint16x8_t s23 = vaddq_u16(s2, s3);
+ const uint16x8_t sum = vaddq_u16(s01, s23);
+ sum_left = vaddq_u16(sum_left, sum);
+ }
+ }
+
+ if (do_top && do_left) {
+ const uint16x8_t sum = vaddq_u16(sum_left, sum_top);
+ dc0 = vrshrn_n_u16(sum, 5);
+ } else if (do_top) {
+ dc0 = vrshrn_n_u16(sum_top, 4);
+ } else if (do_left) {
+ dc0 = vrshrn_n_u16(sum_left, 4);
+ } else {
+ dc0 = vdup_n_u8(0x80);
+ }
+
+ {
+ const uint8x16_t dc = vdupq_lane_u8(dc0, 0);
+ int i;
+ for (i = 0; i < 16; ++i) {
+ vst1q_u8(dst + i * BPS, dc);
+ }
+ }
+}
+
+static void DC16TopLeft(uint8_t* dst) { DC16(dst, 1, 1); }
+static void DC16NoTop(uint8_t* dst) { DC16(dst, 0, 1); }
+static void DC16NoLeft(uint8_t* dst) { DC16(dst, 1, 0); }
+static void DC16NoTopLeft(uint8_t* dst) { DC16(dst, 0, 0); }
+
+static void TM16(uint8_t* dst) {
+ const uint8x8_t TL = vld1_dup_u8(dst - BPS - 1); // top-left pixel 'A[-1]'
+ const uint8x16_t T = vld1q_u8(dst - BPS); // top row 'A[0..15]'
+ // A[c] - A[-1]
+ const int16x8_t d_lo = vreinterpretq_s16_u16(vsubl_u8(vget_low_u8(T), TL));
+ const int16x8_t d_hi = vreinterpretq_s16_u16(vsubl_u8(vget_high_u8(T), TL));
+ int y;
+ for (y = 0; y < 16; y += 4) {
+ // left edge
+ const int16x8_t L0 = ConvertU8ToS16(vld1_dup_u8(dst + 0 * BPS - 1));
+ const int16x8_t L1 = ConvertU8ToS16(vld1_dup_u8(dst + 1 * BPS - 1));
+ const int16x8_t L2 = ConvertU8ToS16(vld1_dup_u8(dst + 2 * BPS - 1));
+ const int16x8_t L3 = ConvertU8ToS16(vld1_dup_u8(dst + 3 * BPS - 1));
+ const int16x8_t r0_lo = vaddq_s16(L0, d_lo); // L[r] + A[c] - A[-1]
+ const int16x8_t r1_lo = vaddq_s16(L1, d_lo);
+ const int16x8_t r2_lo = vaddq_s16(L2, d_lo);
+ const int16x8_t r3_lo = vaddq_s16(L3, d_lo);
+ const int16x8_t r0_hi = vaddq_s16(L0, d_hi);
+ const int16x8_t r1_hi = vaddq_s16(L1, d_hi);
+ const int16x8_t r2_hi = vaddq_s16(L2, d_hi);
+ const int16x8_t r3_hi = vaddq_s16(L3, d_hi);
+ // Saturate and store the result.
+ const uint8x16_t row0 = vcombine_u8(vqmovun_s16(r0_lo), vqmovun_s16(r0_hi));
+ const uint8x16_t row1 = vcombine_u8(vqmovun_s16(r1_lo), vqmovun_s16(r1_hi));
+ const uint8x16_t row2 = vcombine_u8(vqmovun_s16(r2_lo), vqmovun_s16(r2_hi));
+ const uint8x16_t row3 = vcombine_u8(vqmovun_s16(r3_lo), vqmovun_s16(r3_hi));
+ vst1q_u8(dst + 0 * BPS, row0);
+ vst1q_u8(dst + 1 * BPS, row1);
+ vst1q_u8(dst + 2 * BPS, row2);
+ vst1q_u8(dst + 3 * BPS, row3);
+ dst += 4 * BPS;
+ }
+}
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8DspInitNEON(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8DspInitNEON(void) {
+ VP8Transform = TransformTwo;
+ VP8TransformAC3 = TransformAC3;
+ VP8TransformDC = TransformDC;
+ VP8TransformWHT = TransformWHT;
+
+ VP8VFilter16 = VFilter16;
+ VP8VFilter16i = VFilter16i;
+ VP8HFilter16 = HFilter16;
+#if !defined(WORK_AROUND_GCC)
+ VP8HFilter16i = HFilter16i;
#endif
+ VP8VFilter8 = VFilter8;
+ VP8VFilter8i = VFilter8i;
+#if !defined(WORK_AROUND_GCC)
+ VP8HFilter8 = HFilter8;
+ VP8HFilter8i = HFilter8i;
+#endif
+ VP8SimpleVFilter16 = SimpleVFilter16;
+ VP8SimpleHFilter16 = SimpleHFilter16;
+ VP8SimpleVFilter16i = SimpleVFilter16i;
+ VP8SimpleHFilter16i = SimpleHFilter16i;
+
+ VP8PredLuma4[0] = DC4;
+ VP8PredLuma4[1] = TM4;
+ VP8PredLuma4[2] = VE4;
+ VP8PredLuma4[4] = RD4;
+ VP8PredLuma4[6] = LD4;
+
+ VP8PredLuma16[0] = DC16TopLeft;
+ VP8PredLuma16[1] = TM16;
+ VP8PredLuma16[2] = VE16;
+ VP8PredLuma16[3] = HE16;
+ VP8PredLuma16[4] = DC16NoTop;
+ VP8PredLuma16[5] = DC16NoLeft;
+ VP8PredLuma16[6] = DC16NoTopLeft;
+
+ VP8PredChroma8[0] = DC8uv;
+ VP8PredChroma8[1] = TM8uv;
+ VP8PredChroma8[2] = VE8uv;
+ VP8PredChroma8[3] = HE8uv;
+ VP8PredChroma8[4] = DC8uvNoTop;
+ VP8PredChroma8[5] = DC8uvNoLeft;
+ VP8PredChroma8[6] = DC8uvNoTopLeft;
+}
+
+#else // !WEBP_USE_NEON
+
+WEBP_DSP_INIT_STUB(VP8DspInitNEON)
-#endif // WEBP_USE_NEON
+#endif // WEBP_USE_NEON
diff --git a/drivers/webp/dsp/dec_sse2.c b/drivers/webp/dsp/dec_sse2.c
index 472b68ecb8..d4838b9210 100644
--- a/drivers/webp/dsp/dec_sse2.c
+++ b/drivers/webp/dsp/dec_sse2.c
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// SSE2 version of some decoding functions (idct, loop filtering).
@@ -14,17 +16,17 @@
#if defined(WEBP_USE_SSE2)
+// The 3-coeff sparse transform in SSE2 is not really faster than the plain-C
+// one it seems => disable it by default. Uncomment the following to enable:
+// #define USE_TRANSFORM_AC3
+
#include <emmintrin.h>
#include "../dec/vp8i.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
//------------------------------------------------------------------------------
// Transforms (Paragraph 14.4)
-static void TransformSSE2(const int16_t* in, uint8_t* dst, int do_two) {
+static void Transform(const int16_t* in, uint8_t* dst, int do_two) {
// This implementation makes use of 16-bit fixed point versions of two
// multiply constants:
// K1 = sqrt(2) * cos (pi/8) ~= 85627 / 2^16
@@ -50,19 +52,19 @@ static void TransformSSE2(const int16_t* in, uint8_t* dst, int do_two) {
// vectors will just contain random value we'll never use nor store.
__m128i in0, in1, in2, in3;
{
- in0 = _mm_loadl_epi64((__m128i*)&in[0]);
- in1 = _mm_loadl_epi64((__m128i*)&in[4]);
- in2 = _mm_loadl_epi64((__m128i*)&in[8]);
- in3 = _mm_loadl_epi64((__m128i*)&in[12]);
+ in0 = _mm_loadl_epi64((const __m128i*)&in[0]);
+ in1 = _mm_loadl_epi64((const __m128i*)&in[4]);
+ in2 = _mm_loadl_epi64((const __m128i*)&in[8]);
+ in3 = _mm_loadl_epi64((const __m128i*)&in[12]);
// a00 a10 a20 a30 x x x x
// a01 a11 a21 a31 x x x x
// a02 a12 a22 a32 x x x x
// a03 a13 a23 a33 x x x x
if (do_two) {
- const __m128i inB0 = _mm_loadl_epi64((__m128i*)&in[16]);
- const __m128i inB1 = _mm_loadl_epi64((__m128i*)&in[20]);
- const __m128i inB2 = _mm_loadl_epi64((__m128i*)&in[24]);
- const __m128i inB3 = _mm_loadl_epi64((__m128i*)&in[28]);
+ const __m128i inB0 = _mm_loadl_epi64((const __m128i*)&in[16]);
+ const __m128i inB1 = _mm_loadl_epi64((const __m128i*)&in[20]);
+ const __m128i inB2 = _mm_loadl_epi64((const __m128i*)&in[24]);
+ const __m128i inB3 = _mm_loadl_epi64((const __m128i*)&in[28]);
in0 = _mm_unpacklo_epi64(in0, inB0);
in1 = _mm_unpacklo_epi64(in1, inB1);
in2 = _mm_unpacklo_epi64(in2, inB2);
@@ -194,21 +196,21 @@ static void TransformSSE2(const int16_t* in, uint8_t* dst, int do_two) {
// Add inverse transform to 'dst' and store.
{
- const __m128i zero = _mm_set1_epi16(0);
+ const __m128i zero = _mm_setzero_si128();
// Load the reference(s).
__m128i dst0, dst1, dst2, dst3;
if (do_two) {
// Load eight bytes/pixels per line.
- dst0 = _mm_loadl_epi64((__m128i*)&dst[0 * BPS]);
- dst1 = _mm_loadl_epi64((__m128i*)&dst[1 * BPS]);
- dst2 = _mm_loadl_epi64((__m128i*)&dst[2 * BPS]);
- dst3 = _mm_loadl_epi64((__m128i*)&dst[3 * BPS]);
+ dst0 = _mm_loadl_epi64((__m128i*)(dst + 0 * BPS));
+ dst1 = _mm_loadl_epi64((__m128i*)(dst + 1 * BPS));
+ dst2 = _mm_loadl_epi64((__m128i*)(dst + 2 * BPS));
+ dst3 = _mm_loadl_epi64((__m128i*)(dst + 3 * BPS));
} else {
// Load four bytes/pixels per line.
- dst0 = _mm_cvtsi32_si128(*(int*)&dst[0 * BPS]);
- dst1 = _mm_cvtsi32_si128(*(int*)&dst[1 * BPS]);
- dst2 = _mm_cvtsi32_si128(*(int*)&dst[2 * BPS]);
- dst3 = _mm_cvtsi32_si128(*(int*)&dst[3 * BPS]);
+ dst0 = _mm_cvtsi32_si128(*(int*)(dst + 0 * BPS));
+ dst1 = _mm_cvtsi32_si128(*(int*)(dst + 1 * BPS));
+ dst2 = _mm_cvtsi32_si128(*(int*)(dst + 2 * BPS));
+ dst3 = _mm_cvtsi32_si128(*(int*)(dst + 3 * BPS));
}
// Convert to 16b.
dst0 = _mm_unpacklo_epi8(dst0, zero);
@@ -228,20 +230,66 @@ static void TransformSSE2(const int16_t* in, uint8_t* dst, int do_two) {
// Store the results.
if (do_two) {
// Store eight bytes/pixels per line.
- _mm_storel_epi64((__m128i*)&dst[0 * BPS], dst0);
- _mm_storel_epi64((__m128i*)&dst[1 * BPS], dst1);
- _mm_storel_epi64((__m128i*)&dst[2 * BPS], dst2);
- _mm_storel_epi64((__m128i*)&dst[3 * BPS], dst3);
+ _mm_storel_epi64((__m128i*)(dst + 0 * BPS), dst0);
+ _mm_storel_epi64((__m128i*)(dst + 1 * BPS), dst1);
+ _mm_storel_epi64((__m128i*)(dst + 2 * BPS), dst2);
+ _mm_storel_epi64((__m128i*)(dst + 3 * BPS), dst3);
} else {
// Store four bytes/pixels per line.
- *((int32_t *)&dst[0 * BPS]) = _mm_cvtsi128_si32(dst0);
- *((int32_t *)&dst[1 * BPS]) = _mm_cvtsi128_si32(dst1);
- *((int32_t *)&dst[2 * BPS]) = _mm_cvtsi128_si32(dst2);
- *((int32_t *)&dst[3 * BPS]) = _mm_cvtsi128_si32(dst3);
+ *(int*)(dst + 0 * BPS) = _mm_cvtsi128_si32(dst0);
+ *(int*)(dst + 1 * BPS) = _mm_cvtsi128_si32(dst1);
+ *(int*)(dst + 2 * BPS) = _mm_cvtsi128_si32(dst2);
+ *(int*)(dst + 3 * BPS) = _mm_cvtsi128_si32(dst3);
}
}
}
+#if defined(USE_TRANSFORM_AC3)
+#define MUL(a, b) (((a) * (b)) >> 16)
+static void TransformAC3(const int16_t* in, uint8_t* dst) {
+ static const int kC1 = 20091 + (1 << 16);
+ static const int kC2 = 35468;
+ const __m128i A = _mm_set1_epi16(in[0] + 4);
+ const __m128i c4 = _mm_set1_epi16(MUL(in[4], kC2));
+ const __m128i d4 = _mm_set1_epi16(MUL(in[4], kC1));
+ const int c1 = MUL(in[1], kC2);
+ const int d1 = MUL(in[1], kC1);
+ const __m128i CD = _mm_set_epi16(0, 0, 0, 0, -d1, -c1, c1, d1);
+ const __m128i B = _mm_adds_epi16(A, CD);
+ const __m128i m0 = _mm_adds_epi16(B, d4);
+ const __m128i m1 = _mm_adds_epi16(B, c4);
+ const __m128i m2 = _mm_subs_epi16(B, c4);
+ const __m128i m3 = _mm_subs_epi16(B, d4);
+ const __m128i zero = _mm_setzero_si128();
+ // Load the source pixels.
+ __m128i dst0 = _mm_cvtsi32_si128(*(int*)(dst + 0 * BPS));
+ __m128i dst1 = _mm_cvtsi32_si128(*(int*)(dst + 1 * BPS));
+ __m128i dst2 = _mm_cvtsi32_si128(*(int*)(dst + 2 * BPS));
+ __m128i dst3 = _mm_cvtsi32_si128(*(int*)(dst + 3 * BPS));
+ // Convert to 16b.
+ dst0 = _mm_unpacklo_epi8(dst0, zero);
+ dst1 = _mm_unpacklo_epi8(dst1, zero);
+ dst2 = _mm_unpacklo_epi8(dst2, zero);
+ dst3 = _mm_unpacklo_epi8(dst3, zero);
+ // Add the inverse transform.
+ dst0 = _mm_adds_epi16(dst0, _mm_srai_epi16(m0, 3));
+ dst1 = _mm_adds_epi16(dst1, _mm_srai_epi16(m1, 3));
+ dst2 = _mm_adds_epi16(dst2, _mm_srai_epi16(m2, 3));
+ dst3 = _mm_adds_epi16(dst3, _mm_srai_epi16(m3, 3));
+ // Unsigned saturate to 8b.
+ dst0 = _mm_packus_epi16(dst0, dst0);
+ dst1 = _mm_packus_epi16(dst1, dst1);
+ dst2 = _mm_packus_epi16(dst2, dst2);
+ dst3 = _mm_packus_epi16(dst3, dst3);
+ // Store the results.
+ *(int*)(dst + 0 * BPS) = _mm_cvtsi128_si32(dst0);
+ *(int*)(dst + 1 * BPS) = _mm_cvtsi128_si32(dst1);
+ *(int*)(dst + 2 * BPS) = _mm_cvtsi128_si32(dst2);
+ *(int*)(dst + 3 * BPS) = _mm_cvtsi128_si32(dst3);
+}
+#undef MUL
+#endif // USE_TRANSFORM_AC3
+
//------------------------------------------------------------------------------
// Loop Filter (Paragraph 15)
@@ -250,20 +298,14 @@ static void TransformSSE2(const int16_t* in, uint8_t* dst, int do_two) {
_mm_subs_epu8((q), (p)), \
_mm_subs_epu8((p), (q)))
-// Shift each byte of "a" by N bits while preserving by the sign bit.
-//
-// It first shifts the lower bytes of the words and then the upper bytes and
-// then merges the results together.
-#define SIGNED_SHIFT_N(a, N) { \
- __m128i t = a; \
- t = _mm_slli_epi16(t, 8); \
- t = _mm_srai_epi16(t, N); \
- t = _mm_srli_epi16(t, 8); \
- \
- a = _mm_srai_epi16(a, N + 8); \
- a = _mm_slli_epi16(a, 8); \
- \
- a = _mm_or_si128(t, a); \
+// Shift each byte of "x" by 3 bits while preserving by the sign bit.
+static WEBP_INLINE void SignedShift8b(__m128i* const x) {
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i lo_0 = _mm_unpacklo_epi8(zero, *x);
+ const __m128i hi_0 = _mm_unpackhi_epi8(zero, *x);
+ const __m128i lo_1 = _mm_srai_epi16(lo_0, 3 + 8);
+ const __m128i hi_1 = _mm_srai_epi16(hi_0, 3 + 8);
+ *x = _mm_packs_epi16(lo_1, hi_1);
}
#define FLIP_SIGN_BIT2(a, b) { \
@@ -276,103 +318,124 @@ static void TransformSSE2(const int16_t* in, uint8_t* dst, int do_two) {
FLIP_SIGN_BIT2(c, d); \
}
-#define GET_NOTHEV(p1, p0, q0, q1, hev_thresh, not_hev) { \
- const __m128i zero = _mm_setzero_si128(); \
- const __m128i t1 = MM_ABS(p1, p0); \
- const __m128i t2 = MM_ABS(q1, q0); \
- \
- const __m128i h = _mm_set1_epi8(hev_thresh); \
- const __m128i t3 = _mm_subs_epu8(t1, h); /* abs(p1 - p0) - hev_tresh */ \
- const __m128i t4 = _mm_subs_epu8(t2, h); /* abs(q1 - q0) - hev_tresh */ \
- \
- not_hev = _mm_or_si128(t3, t4); \
- not_hev = _mm_cmpeq_epi8(not_hev, zero); /* not_hev <= t1 && not_hev <= t2 */\
-}
-
-#define GET_BASE_DELTA(p1, p0, q0, q1, o) { \
- const __m128i qp0 = _mm_subs_epi8(q0, p0); /* q0 - p0 */ \
- o = _mm_subs_epi8(p1, q1); /* p1 - q1 */ \
- o = _mm_adds_epi8(o, qp0); /* p1 - q1 + 1 * (q0 - p0) */ \
- o = _mm_adds_epi8(o, qp0); /* p1 - q1 + 2 * (q0 - p0) */ \
- o = _mm_adds_epi8(o, qp0); /* p1 - q1 + 3 * (q0 - p0) */ \
-}
-
-#define DO_SIMPLE_FILTER(p0, q0, fl) { \
- const __m128i three = _mm_set1_epi8(3); \
- const __m128i four = _mm_set1_epi8(4); \
- __m128i v3 = _mm_adds_epi8(fl, three); \
- __m128i v4 = _mm_adds_epi8(fl, four); \
- \
- /* Do +4 side */ \
- SIGNED_SHIFT_N(v4, 3); /* v4 >> 3 */ \
- q0 = _mm_subs_epi8(q0, v4); /* q0 -= v4 */ \
- \
- /* Now do +3 side */ \
- SIGNED_SHIFT_N(v3, 3); /* v3 >> 3 */ \
- p0 = _mm_adds_epi8(p0, v3); /* p0 += v3 */ \
+// input/output is uint8_t
+static WEBP_INLINE void GetNotHEV(const __m128i* const p1,
+ const __m128i* const p0,
+ const __m128i* const q0,
+ const __m128i* const q1,
+ int hev_thresh, __m128i* const not_hev) {
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i t_1 = MM_ABS(*p1, *p0);
+ const __m128i t_2 = MM_ABS(*q1, *q0);
+
+ const __m128i h = _mm_set1_epi8(hev_thresh);
+ const __m128i t_max = _mm_max_epu8(t_1, t_2);
+
+ const __m128i t_max_h = _mm_subs_epu8(t_max, h);
+ *not_hev = _mm_cmpeq_epi8(t_max_h, zero); // not_hev <= t1 && not_hev <= t2
}
-// Updates values of 2 pixels at MB edge during complex filtering.
-// Update operations:
-// q = q - a and p = p + a; where a = [(a_hi >> 7), (a_lo >> 7)]
-#define UPDATE_2PIXELS(pi, qi, a_lo, a_hi) { \
- const __m128i a_lo7 = _mm_srai_epi16(a_lo, 7); \
- const __m128i a_hi7 = _mm_srai_epi16(a_hi, 7); \
- const __m128i a = _mm_packs_epi16(a_lo7, a_hi7); \
- pi = _mm_adds_epi8(pi, a); \
- qi = _mm_subs_epi8(qi, a); \
+// input pixels are int8_t
+static WEBP_INLINE void GetBaseDelta(const __m128i* const p1,
+ const __m128i* const p0,
+ const __m128i* const q0,
+ const __m128i* const q1,
+ __m128i* const delta) {
+ // beware of addition order, for saturation!
+ const __m128i p1_q1 = _mm_subs_epi8(*p1, *q1); // p1 - q1
+ const __m128i q0_p0 = _mm_subs_epi8(*q0, *p0); // q0 - p0
+ const __m128i s1 = _mm_adds_epi8(p1_q1, q0_p0); // p1 - q1 + 1 * (q0 - p0)
+ const __m128i s2 = _mm_adds_epi8(q0_p0, s1); // p1 - q1 + 2 * (q0 - p0)
+ const __m128i s3 = _mm_adds_epi8(q0_p0, s2); // p1 - q1 + 3 * (q0 - p0)
+ *delta = s3;
}
-static void NeedsFilter(const __m128i* p1, const __m128i* p0, const __m128i* q0,
- const __m128i* q1, int thresh, __m128i *mask) {
- __m128i t1 = MM_ABS(*p1, *q1); // abs(p1 - q1)
- *mask = _mm_set1_epi8(0xFE);
- t1 = _mm_and_si128(t1, *mask); // set lsb of each byte to zero
- t1 = _mm_srli_epi16(t1, 1); // abs(p1 - q1) / 2
+// input and output are int8_t
+static WEBP_INLINE void DoSimpleFilter(__m128i* const p0, __m128i* const q0,
+ const __m128i* const fl) {
+ const __m128i k3 = _mm_set1_epi8(3);
+ const __m128i k4 = _mm_set1_epi8(4);
+ __m128i v3 = _mm_adds_epi8(*fl, k3);
+ __m128i v4 = _mm_adds_epi8(*fl, k4);
+
+ SignedShift8b(&v4); // v4 >> 3
+ SignedShift8b(&v3); // v3 >> 3
+ *q0 = _mm_subs_epi8(*q0, v4); // q0 -= v4
+ *p0 = _mm_adds_epi8(*p0, v3); // p0 += v3
+}
- *mask = MM_ABS(*p0, *q0); // abs(p0 - q0)
- *mask = _mm_adds_epu8(*mask, *mask); // abs(p0 - q0) * 2
- *mask = _mm_adds_epu8(*mask, t1); // abs(p0 - q0) * 2 + abs(p1 - q1) / 2
+// Updates values of 2 pixels at MB edge during complex filtering.
+// Update operations:
+// q = q - delta and p = p + delta; where delta = [(a_hi >> 7), (a_lo >> 7)]
+// Pixels 'pi' and 'qi' are int8_t on input, uint8_t on output (sign flip).
+static WEBP_INLINE void Update2Pixels(__m128i* const pi, __m128i* const qi,
+ const __m128i* const a0_lo,
+ const __m128i* const a0_hi) {
+ const __m128i a1_lo = _mm_srai_epi16(*a0_lo, 7);
+ const __m128i a1_hi = _mm_srai_epi16(*a0_hi, 7);
+ const __m128i delta = _mm_packs_epi16(a1_lo, a1_hi);
+ const __m128i sign_bit = _mm_set1_epi8(0x80);
+ *pi = _mm_adds_epi8(*pi, delta);
+ *qi = _mm_subs_epi8(*qi, delta);
+ FLIP_SIGN_BIT2(*pi, *qi);
+}
- t1 = _mm_set1_epi8(thresh);
- *mask = _mm_subs_epu8(*mask, t1); // mask <= thresh
- *mask = _mm_cmpeq_epi8(*mask, _mm_setzero_si128());
+// input pixels are uint8_t
+static WEBP_INLINE void NeedsFilter(const __m128i* const p1,
+ const __m128i* const p0,
+ const __m128i* const q0,
+ const __m128i* const q1,
+ int thresh, __m128i* const mask) {
+ const __m128i m_thresh = _mm_set1_epi8(thresh);
+ const __m128i t1 = MM_ABS(*p1, *q1); // abs(p1 - q1)
+ const __m128i kFE = _mm_set1_epi8(0xFE);
+ const __m128i t2 = _mm_and_si128(t1, kFE); // set lsb of each byte to zero
+ const __m128i t3 = _mm_srli_epi16(t2, 1); // abs(p1 - q1) / 2
+
+ const __m128i t4 = MM_ABS(*p0, *q0); // abs(p0 - q0)
+ const __m128i t5 = _mm_adds_epu8(t4, t4); // abs(p0 - q0) * 2
+ const __m128i t6 = _mm_adds_epu8(t5, t3); // abs(p0-q0)*2 + abs(p1-q1)/2
+
+ const __m128i t7 = _mm_subs_epu8(t6, m_thresh); // mask <= m_thresh
+ *mask = _mm_cmpeq_epi8(t7, _mm_setzero_si128());
}
//------------------------------------------------------------------------------
// Edge filtering functions
// Applies filter on 2 pixels (p0 and q0)
-static WEBP_INLINE void DoFilter2(const __m128i* p1, __m128i* p0, __m128i* q0,
- const __m128i* q1, int thresh) {
+static WEBP_INLINE void DoFilter2(__m128i* const p1, __m128i* const p0,
+ __m128i* const q0, __m128i* const q1,
+ int thresh) {
__m128i a, mask;
const __m128i sign_bit = _mm_set1_epi8(0x80);
+ // convert p1/q1 to int8_t (for GetBaseDelta)
const __m128i p1s = _mm_xor_si128(*p1, sign_bit);
const __m128i q1s = _mm_xor_si128(*q1, sign_bit);
NeedsFilter(p1, p0, q0, q1, thresh, &mask);
- // convert to signed values
FLIP_SIGN_BIT2(*p0, *q0);
-
- GET_BASE_DELTA(p1s, *p0, *q0, q1s, a);
+ GetBaseDelta(&p1s, p0, q0, &q1s, &a);
a = _mm_and_si128(a, mask); // mask filter values we don't care about
- DO_SIMPLE_FILTER(*p0, *q0, a);
-
- // unoffset
+ DoSimpleFilter(p0, q0, &a);
FLIP_SIGN_BIT2(*p0, *q0);
}
// Applies filter on 4 pixels (p1, p0, q0 and q1)
-static WEBP_INLINE void DoFilter4(__m128i* p1, __m128i *p0,
- __m128i* q0, __m128i* q1,
- const __m128i* mask, int hev_thresh) {
+static WEBP_INLINE void DoFilter4(__m128i* const p1, __m128i* const p0,
+ __m128i* const q0, __m128i* const q1,
+ const __m128i* const mask, int hev_thresh) {
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i sign_bit = _mm_set1_epi8(0x80);
+ const __m128i k64 = _mm_set1_epi8(64);
+ const __m128i k3 = _mm_set1_epi8(3);
+ const __m128i k4 = _mm_set1_epi8(4);
__m128i not_hev;
__m128i t1, t2, t3;
- const __m128i sign_bit = _mm_set1_epi8(0x80);
// compute hev mask
- GET_NOTHEV(*p1, *p0, *q0, *q1, hev_thresh, not_hev);
+ GetNotHEV(p1, p0, q0, q1, hev_thresh, &not_hev);
// convert to signed values
FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1);
@@ -385,135 +448,115 @@ static WEBP_INLINE void DoFilter4(__m128i* p1, __m128i *p0,
t1 = _mm_adds_epi8(t1, t2); // hev(p1 - q1) + 3 * (q0 - p0)
t1 = _mm_and_si128(t1, *mask); // mask filter values we don't care about
- // Do +4 side
- t2 = _mm_set1_epi8(4);
- t2 = _mm_adds_epi8(t1, t2); // 3 * (q0 - p0) + (p1 - q1) + 4
- SIGNED_SHIFT_N(t2, 3); // (3 * (q0 - p0) + hev(p1 - q1) + 4) >> 3
- t3 = t2; // save t2
- *q0 = _mm_subs_epi8(*q0, t2); // q0 -= t2
-
- // Now do +3 side
- t2 = _mm_set1_epi8(3);
- t2 = _mm_adds_epi8(t1, t2); // +3 instead of +4
- SIGNED_SHIFT_N(t2, 3); // (3 * (q0 - p0) + hev(p1 - q1) + 3) >> 3
+ t2 = _mm_adds_epi8(t1, k3); // 3 * (q0 - p0) + hev(p1 - q1) + 3
+ t3 = _mm_adds_epi8(t1, k4); // 3 * (q0 - p0) + hev(p1 - q1) + 4
+ SignedShift8b(&t2); // (3 * (q0 - p0) + hev(p1 - q1) + 3) >> 3
+ SignedShift8b(&t3); // (3 * (q0 - p0) + hev(p1 - q1) + 4) >> 3
*p0 = _mm_adds_epi8(*p0, t2); // p0 += t2
+ *q0 = _mm_subs_epi8(*q0, t3); // q0 -= t3
+ FLIP_SIGN_BIT2(*p0, *q0);
- t2 = _mm_set1_epi8(1);
- t3 = _mm_adds_epi8(t3, t2);
- SIGNED_SHIFT_N(t3, 1); // (3 * (q0 - p0) + hev(p1 - q1) + 4) >> 4
+ // this is equivalent to signed (a + 1) >> 1 calculation
+ t2 = _mm_add_epi8(t3, sign_bit);
+ t3 = _mm_avg_epu8(t2, zero);
+ t3 = _mm_sub_epi8(t3, k64);
t3 = _mm_and_si128(not_hev, t3); // if !hev
*q1 = _mm_subs_epi8(*q1, t3); // q1 -= t3
*p1 = _mm_adds_epi8(*p1, t3); // p1 += t3
-
- // unoffset
- FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1);
+ FLIP_SIGN_BIT2(*p1, *q1);
}
// Applies filter on 6 pixels (p2, p1, p0, q0, q1 and q2)
-static WEBP_INLINE void DoFilter6(__m128i *p2, __m128i* p1, __m128i *p0,
- __m128i* q0, __m128i* q1, __m128i *q2,
- const __m128i* mask, int hev_thresh) {
- __m128i a, not_hev;
+static WEBP_INLINE void DoFilter6(__m128i* const p2, __m128i* const p1,
+ __m128i* const p0, __m128i* const q0,
+ __m128i* const q1, __m128i* const q2,
+ const __m128i* const mask, int hev_thresh) {
+ const __m128i zero = _mm_setzero_si128();
const __m128i sign_bit = _mm_set1_epi8(0x80);
+ __m128i a, not_hev;
// compute hev mask
- GET_NOTHEV(*p1, *p0, *q0, *q1, hev_thresh, not_hev);
+ GetNotHEV(p1, p0, q0, q1, hev_thresh, &not_hev);
- // convert to signed values
FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1);
FLIP_SIGN_BIT2(*p2, *q2);
-
- GET_BASE_DELTA(*p1, *p0, *q0, *q1, a);
+ GetBaseDelta(p1, p0, q0, q1, &a);
{ // do simple filter on pixels with hev
const __m128i m = _mm_andnot_si128(not_hev, *mask);
const __m128i f = _mm_and_si128(a, m);
- DO_SIMPLE_FILTER(*p0, *q0, f);
+ DoSimpleFilter(p0, q0, &f);
}
+
{ // do strong filter on pixels with not hev
- const __m128i zero = _mm_setzero_si128();
- const __m128i nine = _mm_set1_epi16(0x0900);
- const __m128i sixty_three = _mm_set1_epi16(63);
+ const __m128i k9 = _mm_set1_epi16(0x0900);
+ const __m128i k63 = _mm_set1_epi16(63);
const __m128i m = _mm_and_si128(not_hev, *mask);
const __m128i f = _mm_and_si128(a, m);
+
const __m128i f_lo = _mm_unpacklo_epi8(zero, f);
const __m128i f_hi = _mm_unpackhi_epi8(zero, f);
- const __m128i f9_lo = _mm_mulhi_epi16(f_lo, nine); // Filter (lo) * 9
- const __m128i f9_hi = _mm_mulhi_epi16(f_hi, nine); // Filter (hi) * 9
- const __m128i f18_lo = _mm_add_epi16(f9_lo, f9_lo); // Filter (lo) * 18
- const __m128i f18_hi = _mm_add_epi16(f9_hi, f9_hi); // Filter (hi) * 18
+ const __m128i f9_lo = _mm_mulhi_epi16(f_lo, k9); // Filter (lo) * 9
+ const __m128i f9_hi = _mm_mulhi_epi16(f_hi, k9); // Filter (hi) * 9
- const __m128i a2_lo = _mm_add_epi16(f9_lo, sixty_three); // Filter * 9 + 63
- const __m128i a2_hi = _mm_add_epi16(f9_hi, sixty_three); // Filter * 9 + 63
+ const __m128i a2_lo = _mm_add_epi16(f9_lo, k63); // Filter * 9 + 63
+ const __m128i a2_hi = _mm_add_epi16(f9_hi, k63); // Filter * 9 + 63
- const __m128i a1_lo = _mm_add_epi16(f18_lo, sixty_three); // F... * 18 + 63
- const __m128i a1_hi = _mm_add_epi16(f18_hi, sixty_three); // F... * 18 + 63
+ const __m128i a1_lo = _mm_add_epi16(a2_lo, f9_lo); // Filter * 18 + 63
+ const __m128i a1_hi = _mm_add_epi16(a2_hi, f9_hi); // Filter * 18 + 63
- const __m128i a0_lo = _mm_add_epi16(f18_lo, a2_lo); // Filter * 27 + 63
- const __m128i a0_hi = _mm_add_epi16(f18_hi, a2_hi); // Filter * 27 + 63
+ const __m128i a0_lo = _mm_add_epi16(a1_lo, f9_lo); // Filter * 27 + 63
+ const __m128i a0_hi = _mm_add_epi16(a1_hi, f9_hi); // Filter * 27 + 63
- UPDATE_2PIXELS(*p2, *q2, a2_lo, a2_hi);
- UPDATE_2PIXELS(*p1, *q1, a1_lo, a1_hi);
- UPDATE_2PIXELS(*p0, *q0, a0_lo, a0_hi);
+ Update2Pixels(p2, q2, &a2_lo, &a2_hi);
+ Update2Pixels(p1, q1, &a1_lo, &a1_hi);
+ Update2Pixels(p0, q0, &a0_lo, &a0_hi);
}
+}
- // unoffset
- FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1);
- FLIP_SIGN_BIT2(*p2, *q2);
+// memcpy() is the safe way of moving potentially unaligned 32b memory.
+static WEBP_INLINE uint32_t MemToUint32(const uint8_t* const ptr) {
+ uint32_t A;
+ memcpy(&A, (const int*)ptr, sizeof(A));
+ return A;
}
// reads 8 rows across a vertical edge.
-//
-// TODO(somnath): Investigate _mm_shuffle* also see if it can be broken into
-// two Load4x4() to avoid code duplication.
-static WEBP_INLINE void Load8x4(const uint8_t* b, int stride,
- __m128i* p, __m128i* q) {
- __m128i t1, t2;
-
- // Load 0th, 1st, 4th and 5th rows
- __m128i r0 = _mm_cvtsi32_si128(*((int*)&b[0 * stride])); // 03 02 01 00
- __m128i r1 = _mm_cvtsi32_si128(*((int*)&b[1 * stride])); // 13 12 11 10
- __m128i r4 = _mm_cvtsi32_si128(*((int*)&b[4 * stride])); // 43 42 41 40
- __m128i r5 = _mm_cvtsi32_si128(*((int*)&b[5 * stride])); // 53 52 51 50
-
- r0 = _mm_unpacklo_epi32(r0, r4); // 43 42 41 40 03 02 01 00
- r1 = _mm_unpacklo_epi32(r1, r5); // 53 52 51 50 13 12 11 10
-
- // t1 = 53 43 52 42 51 41 50 40 13 03 12 02 11 01 10 00
- t1 = _mm_unpacklo_epi8(r0, r1);
-
- // Load 2nd, 3rd, 6th and 7th rows
- r0 = _mm_cvtsi32_si128(*((int*)&b[2 * stride])); // 23 22 21 22
- r1 = _mm_cvtsi32_si128(*((int*)&b[3 * stride])); // 33 32 31 30
- r4 = _mm_cvtsi32_si128(*((int*)&b[6 * stride])); // 63 62 61 60
- r5 = _mm_cvtsi32_si128(*((int*)&b[7 * stride])); // 73 72 71 70
-
- r0 = _mm_unpacklo_epi32(r0, r4); // 63 62 61 60 23 22 21 20
- r1 = _mm_unpacklo_epi32(r1, r5); // 73 72 71 70 33 32 31 30
-
- // t2 = 73 63 72 62 71 61 70 60 33 23 32 22 31 21 30 20
- t2 = _mm_unpacklo_epi8(r0, r1);
-
- // t1 = 33 23 13 03 32 22 12 02 31 21 11 01 30 20 10 00
- // t2 = 73 63 53 43 72 62 52 42 71 61 51 41 70 60 50 40
- r0 = t1;
- t1 = _mm_unpacklo_epi16(t1, t2);
- t2 = _mm_unpackhi_epi16(r0, t2);
+static WEBP_INLINE void Load8x4(const uint8_t* const b, int stride,
+ __m128i* const p, __m128i* const q) {
+ // A0 = 63 62 61 60 23 22 21 20 43 42 41 40 03 02 01 00
+ // A1 = 73 72 71 70 33 32 31 30 53 52 51 50 13 12 11 10
+ const __m128i A0 = _mm_set_epi32(
+ MemToUint32(&b[6 * stride]), MemToUint32(&b[2 * stride]),
+ MemToUint32(&b[4 * stride]), MemToUint32(&b[0 * stride]));
+ const __m128i A1 = _mm_set_epi32(
+ MemToUint32(&b[7 * stride]), MemToUint32(&b[3 * stride]),
+ MemToUint32(&b[5 * stride]), MemToUint32(&b[1 * stride]));
+
+ // B0 = 53 43 52 42 51 41 50 40 13 03 12 02 11 01 10 00
+ // B1 = 73 63 72 62 71 61 70 60 33 23 32 22 31 21 30 20
+ const __m128i B0 = _mm_unpacklo_epi8(A0, A1);
+ const __m128i B1 = _mm_unpackhi_epi8(A0, A1);
+
+ // C0 = 33 23 13 03 32 22 12 02 31 21 11 01 30 20 10 00
+ // C1 = 73 63 53 43 72 62 52 42 71 61 51 41 70 60 50 40
+ const __m128i C0 = _mm_unpacklo_epi16(B0, B1);
+ const __m128i C1 = _mm_unpackhi_epi16(B0, B1);
// *p = 71 61 51 41 31 21 11 01 70 60 50 40 30 20 10 00
// *q = 73 63 53 43 33 23 13 03 72 62 52 42 32 22 12 02
- *p = _mm_unpacklo_epi32(t1, t2);
- *q = _mm_unpackhi_epi32(t1, t2);
+ *p = _mm_unpacklo_epi32(C0, C1);
+ *q = _mm_unpackhi_epi32(C0, C1);
}
-static WEBP_INLINE void Load16x4(const uint8_t* r0, const uint8_t* r8,
+static WEBP_INLINE void Load16x4(const uint8_t* const r0,
+ const uint8_t* const r8,
int stride,
- __m128i* p1, __m128i* p0,
- __m128i* q0, __m128i* q1) {
- __m128i t1, t2;
+ __m128i* const p1, __m128i* const p0,
+ __m128i* const q0, __m128i* const q1) {
// Assume the pixels around the edge (|) are numbered as follows
// 00 01 | 02 03
// 10 11 | 12 13
@@ -532,19 +575,21 @@ static WEBP_INLINE void Load16x4(const uint8_t* r0, const uint8_t* r8,
Load8x4(r0, stride, p1, q0);
Load8x4(r8, stride, p0, q1);
- t1 = *p1;
- t2 = *q0;
- // p1 = f0 e0 d0 c0 b0 a0 90 80 70 60 50 40 30 20 10 00
- // p0 = f1 e1 d1 c1 b1 a1 91 81 71 61 51 41 31 21 11 01
- // q0 = f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02
- // q1 = f3 e3 d3 c3 b3 a3 93 83 73 63 53 43 33 23 13 03
- *p1 = _mm_unpacklo_epi64(t1, *p0);
- *p0 = _mm_unpackhi_epi64(t1, *p0);
- *q0 = _mm_unpacklo_epi64(t2, *q1);
- *q1 = _mm_unpackhi_epi64(t2, *q1);
+ {
+ // p1 = f0 e0 d0 c0 b0 a0 90 80 70 60 50 40 30 20 10 00
+ // p0 = f1 e1 d1 c1 b1 a1 91 81 71 61 51 41 31 21 11 01
+ // q0 = f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02
+ // q1 = f3 e3 d3 c3 b3 a3 93 83 73 63 53 43 33 23 13 03
+ const __m128i t1 = *p1;
+ const __m128i t2 = *q0;
+ *p1 = _mm_unpacklo_epi64(t1, *p0);
+ *p0 = _mm_unpackhi_epi64(t1, *p0);
+ *q0 = _mm_unpacklo_epi64(t2, *q1);
+ *q1 = _mm_unpackhi_epi64(t2, *q1);
+ }
}
-static WEBP_INLINE void Store4x4(__m128i* x, uint8_t* dst, int stride) {
+static WEBP_INLINE void Store4x4(__m128i* const x, uint8_t* dst, int stride) {
int i;
for (i = 0; i < 4; ++i, dst += stride) {
*((int32_t*)dst) = _mm_cvtsi128_si32(*x);
@@ -553,48 +598,51 @@ static WEBP_INLINE void Store4x4(__m128i* x, uint8_t* dst, int stride) {
}
// Transpose back and store
-static WEBP_INLINE void Store16x4(uint8_t* r0, uint8_t* r8, int stride,
- __m128i* p1, __m128i* p0,
- __m128i* q0, __m128i* q1) {
- __m128i t1;
+static WEBP_INLINE void Store16x4(const __m128i* const p1,
+ const __m128i* const p0,
+ const __m128i* const q0,
+ const __m128i* const q1,
+ uint8_t* r0, uint8_t* r8,
+ int stride) {
+ __m128i t1, p1_s, p0_s, q0_s, q1_s;
// p0 = 71 70 61 60 51 50 41 40 31 30 21 20 11 10 01 00
// p1 = f1 f0 e1 e0 d1 d0 c1 c0 b1 b0 a1 a0 91 90 81 80
t1 = *p0;
- *p0 = _mm_unpacklo_epi8(*p1, t1);
- *p1 = _mm_unpackhi_epi8(*p1, t1);
+ p0_s = _mm_unpacklo_epi8(*p1, t1);
+ p1_s = _mm_unpackhi_epi8(*p1, t1);
// q0 = 73 72 63 62 53 52 43 42 33 32 23 22 13 12 03 02
// q1 = f3 f2 e3 e2 d3 d2 c3 c2 b3 b2 a3 a2 93 92 83 82
t1 = *q0;
- *q0 = _mm_unpacklo_epi8(t1, *q1);
- *q1 = _mm_unpackhi_epi8(t1, *q1);
+ q0_s = _mm_unpacklo_epi8(t1, *q1);
+ q1_s = _mm_unpackhi_epi8(t1, *q1);
// p0 = 33 32 31 30 23 22 21 20 13 12 11 10 03 02 01 00
// q0 = 73 72 71 70 63 62 61 60 53 52 51 50 43 42 41 40
- t1 = *p0;
- *p0 = _mm_unpacklo_epi16(t1, *q0);
- *q0 = _mm_unpackhi_epi16(t1, *q0);
+ t1 = p0_s;
+ p0_s = _mm_unpacklo_epi16(t1, q0_s);
+ q0_s = _mm_unpackhi_epi16(t1, q0_s);
// p1 = b3 b2 b1 b0 a3 a2 a1 a0 93 92 91 90 83 82 81 80
// q1 = f3 f2 f1 f0 e3 e2 e1 e0 d3 d2 d1 d0 c3 c2 c1 c0
- t1 = *p1;
- *p1 = _mm_unpacklo_epi16(t1, *q1);
- *q1 = _mm_unpackhi_epi16(t1, *q1);
+ t1 = p1_s;
+ p1_s = _mm_unpacklo_epi16(t1, q1_s);
+ q1_s = _mm_unpackhi_epi16(t1, q1_s);
- Store4x4(p0, r0, stride);
+ Store4x4(&p0_s, r0, stride);
r0 += 4 * stride;
- Store4x4(q0, r0, stride);
+ Store4x4(&q0_s, r0, stride);
- Store4x4(p1, r8, stride);
+ Store4x4(&p1_s, r8, stride);
r8 += 4 * stride;
- Store4x4(q1, r8, stride);
+ Store4x4(&q1_s, r8, stride);
}
//------------------------------------------------------------------------------
// Simple In-loop filtering (Paragraph 15.2)
-static void SimpleVFilter16SSE2(uint8_t* p, int stride, int thresh) {
+static void SimpleVFilter16(uint8_t* p, int stride, int thresh) {
// Load
__m128i p1 = _mm_loadu_si128((__m128i*)&p[-2 * stride]);
__m128i p0 = _mm_loadu_si128((__m128i*)&p[-stride]);
@@ -605,49 +653,49 @@ static void SimpleVFilter16SSE2(uint8_t* p, int stride, int thresh) {
// Store
_mm_storeu_si128((__m128i*)&p[-stride], p0);
- _mm_storeu_si128((__m128i*)p, q0);
+ _mm_storeu_si128((__m128i*)&p[0], q0);
}
-static void SimpleHFilter16SSE2(uint8_t* p, int stride, int thresh) {
+static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
__m128i p1, p0, q0, q1;
p -= 2; // beginning of p1
- Load16x4(p, p + 8 * stride, stride, &p1, &p0, &q0, &q1);
+ Load16x4(p, p + 8 * stride, stride, &p1, &p0, &q0, &q1);
DoFilter2(&p1, &p0, &q0, &q1, thresh);
- Store16x4(p, p + 8 * stride, stride, &p1, &p0, &q0, &q1);
+ Store16x4(&p1, &p0, &q0, &q1, p, p + 8 * stride, stride);
}
-static void SimpleVFilter16iSSE2(uint8_t* p, int stride, int thresh) {
+static void SimpleVFilter16i(uint8_t* p, int stride, int thresh) {
int k;
for (k = 3; k > 0; --k) {
p += 4 * stride;
- SimpleVFilter16SSE2(p, stride, thresh);
+ SimpleVFilter16(p, stride, thresh);
}
}
-static void SimpleHFilter16iSSE2(uint8_t* p, int stride, int thresh) {
+static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) {
int k;
for (k = 3; k > 0; --k) {
p += 4;
- SimpleHFilter16SSE2(p, stride, thresh);
+ SimpleHFilter16(p, stride, thresh);
}
}
//------------------------------------------------------------------------------
// Complex In-loop filtering (Paragraph 15.3)
-#define MAX_DIFF1(p3, p2, p1, p0, m) { \
- m = MM_ABS(p3, p2); \
+#define MAX_DIFF1(p3, p2, p1, p0, m) do { \
+ m = MM_ABS(p1, p0); \
+ m = _mm_max_epu8(m, MM_ABS(p3, p2)); \
m = _mm_max_epu8(m, MM_ABS(p2, p1)); \
- m = _mm_max_epu8(m, MM_ABS(p1, p0)); \
-}
+} while (0)
-#define MAX_DIFF2(p3, p2, p1, p0, m) { \
+#define MAX_DIFF2(p3, p2, p1, p0, m) do { \
+ m = _mm_max_epu8(m, MM_ABS(p1, p0)); \
m = _mm_max_epu8(m, MM_ABS(p3, p2)); \
m = _mm_max_epu8(m, MM_ABS(p2, p1)); \
- m = _mm_max_epu8(m, MM_ABS(p1, p0)); \
-}
+} while (0)
#define LOAD_H_EDGES4(p, stride, e1, e2, e3, e4) { \
e1 = _mm_loadu_si128((__m128i*)&(p)[0 * stride]); \
@@ -656,10 +704,11 @@ static void SimpleHFilter16iSSE2(uint8_t* p, int stride, int thresh) {
e4 = _mm_loadu_si128((__m128i*)&(p)[3 * stride]); \
}
-#define LOADUV_H_EDGE(p, u, v, stride) { \
- p = _mm_loadl_epi64((__m128i*)&(u)[(stride)]); \
- p = _mm_unpacklo_epi64(p, _mm_loadl_epi64((__m128i*)&(v)[(stride)])); \
-}
+#define LOADUV_H_EDGE(p, u, v, stride) do { \
+ const __m128i U = _mm_loadl_epi64((__m128i*)&(u)[(stride)]); \
+ const __m128i V = _mm_loadl_epi64((__m128i*)&(v)[(stride)]); \
+ p = _mm_unpacklo_epi64(U, V); \
+} while (0)
#define LOADUV_H_EDGES4(u, v, stride, e1, e2, e3, e4) { \
LOADUV_H_EDGE(e1, u, v, 0 * stride); \
@@ -674,18 +723,23 @@ static void SimpleHFilter16iSSE2(uint8_t* p, int stride, int thresh) {
_mm_storel_epi64((__m128i*)&v[(stride)], p); \
}
-#define COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask) { \
- __m128i fl_yes; \
- const __m128i it = _mm_set1_epi8(ithresh); \
- mask = _mm_subs_epu8(mask, it); \
- mask = _mm_cmpeq_epi8(mask, _mm_setzero_si128()); \
- NeedsFilter(&p1, &p0, &q0, &q1, thresh, &fl_yes); \
- mask = _mm_and_si128(mask, fl_yes); \
+static WEBP_INLINE void ComplexMask(const __m128i* const p1,
+ const __m128i* const p0,
+ const __m128i* const q0,
+ const __m128i* const q1,
+ int thresh, int ithresh,
+ __m128i* const mask) {
+ const __m128i it = _mm_set1_epi8(ithresh);
+ const __m128i diff = _mm_subs_epu8(*mask, it);
+ const __m128i thresh_mask = _mm_cmpeq_epi8(diff, _mm_setzero_si128());
+ __m128i filter_mask;
+ NeedsFilter(p1, p0, q0, q1, thresh, &filter_mask);
+ *mask = _mm_and_si128(thresh_mask, filter_mask);
}
// on macroblock edges
-static void VFilter16SSE2(uint8_t* p, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void VFilter16(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
__m128i t1;
__m128i mask;
__m128i p2, p1, p0, q0, q1, q2;
@@ -698,20 +752,20 @@ static void VFilter16SSE2(uint8_t* p, int stride,
LOAD_H_EDGES4(p, stride, q0, q1, q2, t1);
MAX_DIFF2(t1, q2, q1, q0, mask);
- COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
+ ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
// Store
_mm_storeu_si128((__m128i*)&p[-3 * stride], p2);
_mm_storeu_si128((__m128i*)&p[-2 * stride], p1);
_mm_storeu_si128((__m128i*)&p[-1 * stride], p0);
- _mm_storeu_si128((__m128i*)&p[0 * stride], q0);
- _mm_storeu_si128((__m128i*)&p[1 * stride], q1);
- _mm_storeu_si128((__m128i*)&p[2 * stride], q2);
+ _mm_storeu_si128((__m128i*)&p[+0 * stride], q0);
+ _mm_storeu_si128((__m128i*)&p[+1 * stride], q1);
+ _mm_storeu_si128((__m128i*)&p[+2 * stride], q2);
}
-static void HFilter16SSE2(uint8_t* p, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void HFilter16(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
__m128i mask;
__m128i p3, p2, p1, p0, q0, q1, q2, q3;
@@ -722,71 +776,78 @@ static void HFilter16SSE2(uint8_t* p, int stride,
Load16x4(p, p + 8 * stride, stride, &q0, &q1, &q2, &q3); // q0, q1, q2, q3
MAX_DIFF2(q3, q2, q1, q0, mask);
- COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
+ ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
- Store16x4(b, b + 8 * stride, stride, &p3, &p2, &p1, &p0);
- Store16x4(p, p + 8 * stride, stride, &q0, &q1, &q2, &q3);
+ Store16x4(&p3, &p2, &p1, &p0, b, b + 8 * stride, stride);
+ Store16x4(&q0, &q1, &q2, &q3, p, p + 8 * stride, stride);
}
// on three inner edges
-static void VFilter16iSSE2(uint8_t* p, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void VFilter16i(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
int k;
- __m128i mask;
- __m128i t1, t2, p1, p0, q0, q1;
+ __m128i p3, p2, p1, p0; // loop invariants
- for (k = 3; k > 0; --k) {
- // Load p3, p2, p1, p0
- LOAD_H_EDGES4(p, stride, t2, t1, p1, p0);
- MAX_DIFF1(t2, t1, p1, p0, mask);
+ LOAD_H_EDGES4(p, stride, p3, p2, p1, p0); // prologue
+ for (k = 3; k > 0; --k) {
+ __m128i mask, tmp1, tmp2;
+ uint8_t* const b = p + 2 * stride; // beginning of p1
p += 4 * stride;
- // Load q0, q1, q2, q3
- LOAD_H_EDGES4(p, stride, q0, q1, t1, t2);
- MAX_DIFF2(t2, t1, q1, q0, mask);
+ MAX_DIFF1(p3, p2, p1, p0, mask); // compute partial mask
+ LOAD_H_EDGES4(p, stride, p3, p2, tmp1, tmp2);
+ MAX_DIFF2(p3, p2, tmp1, tmp2, mask);
- COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
- DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh);
+ // p3 and p2 are not just temporary variables here: they will be
+ // re-used for next span. And q2/q3 will become p1/p0 accordingly.
+ ComplexMask(&p1, &p0, &p3, &p2, thresh, ithresh, &mask);
+ DoFilter4(&p1, &p0, &p3, &p2, &mask, hev_thresh);
// Store
- _mm_storeu_si128((__m128i*)&p[-2 * stride], p1);
- _mm_storeu_si128((__m128i*)&p[-1 * stride], p0);
- _mm_storeu_si128((__m128i*)&p[0 * stride], q0);
- _mm_storeu_si128((__m128i*)&p[1 * stride], q1);
+ _mm_storeu_si128((__m128i*)&b[0 * stride], p1);
+ _mm_storeu_si128((__m128i*)&b[1 * stride], p0);
+ _mm_storeu_si128((__m128i*)&b[2 * stride], p3);
+ _mm_storeu_si128((__m128i*)&b[3 * stride], p2);
+
+ // rotate samples
+ p1 = tmp1;
+ p0 = tmp2;
}
}
-static void HFilter16iSSE2(uint8_t* p, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void HFilter16i(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
int k;
- uint8_t* b;
- __m128i mask;
- __m128i t1, t2, p1, p0, q0, q1;
+ __m128i p3, p2, p1, p0; // loop invariants
+
+ Load16x4(p, p + 8 * stride, stride, &p3, &p2, &p1, &p0); // prologue
for (k = 3; k > 0; --k) {
- b = p;
- Load16x4(b, b + 8 * stride, stride, &t2, &t1, &p1, &p0); // p3, p2, p1, p0
- MAX_DIFF1(t2, t1, p1, p0, mask);
+ __m128i mask, tmp1, tmp2;
+ uint8_t* const b = p + 2; // beginning of p1
- b += 4; // beginning of q0
- Load16x4(b, b + 8 * stride, stride, &q0, &q1, &t1, &t2); // q0, q1, q2, q3
- MAX_DIFF2(t2, t1, q1, q0, mask);
+ p += 4; // beginning of q0 (and next span)
- COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
- DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh);
+ MAX_DIFF1(p3, p2, p1, p0, mask); // compute partial mask
+ Load16x4(p, p + 8 * stride, stride, &p3, &p2, &tmp1, &tmp2);
+ MAX_DIFF2(p3, p2, tmp1, tmp2, mask);
- b -= 2; // beginning of p1
- Store16x4(b, b + 8 * stride, stride, &p1, &p0, &q0, &q1);
+ ComplexMask(&p1, &p0, &p3, &p2, thresh, ithresh, &mask);
+ DoFilter4(&p1, &p0, &p3, &p2, &mask, hev_thresh);
- p += 4;
+ Store16x4(&p1, &p0, &p3, &p2, b, b + 8 * stride, stride);
+
+ // rotate samples
+ p1 = tmp1;
+ p0 = tmp2;
}
}
// 8-pixels wide variant, for chroma filtering
-static void VFilter8SSE2(uint8_t* u, uint8_t* v, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void VFilter8(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
__m128i mask;
__m128i t1, p2, p1, p0, q0, q1, q2;
@@ -798,7 +859,7 @@ static void VFilter8SSE2(uint8_t* u, uint8_t* v, int stride,
LOADUV_H_EDGES4(u, v, stride, q0, q1, q2, t1);
MAX_DIFF2(t1, q2, q1, q0, mask);
- COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
+ ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
// Store
@@ -810,8 +871,8 @@ static void VFilter8SSE2(uint8_t* u, uint8_t* v, int stride,
STOREUV(q2, u, v, 2 * stride);
}
-static void HFilter8SSE2(uint8_t* u, uint8_t* v, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void HFilter8(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
__m128i mask;
__m128i p3, p2, p1, p0, q0, q1, q2, q3;
@@ -823,15 +884,15 @@ static void HFilter8SSE2(uint8_t* u, uint8_t* v, int stride,
Load16x4(u, v, stride, &q0, &q1, &q2, &q3); // q0, q1, q2, q3
MAX_DIFF2(q3, q2, q1, q0, mask);
- COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
+ ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
- Store16x4(tu, tv, stride, &p3, &p2, &p1, &p0);
- Store16x4(u, v, stride, &q0, &q1, &q2, &q3);
+ Store16x4(&p3, &p2, &p1, &p0, tu, tv, stride);
+ Store16x4(&q0, &q1, &q2, &q3, u, v, stride);
}
-static void VFilter8iSSE2(uint8_t* u, uint8_t* v, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void VFilter8i(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
__m128i mask;
__m128i t1, t2, p1, p0, q0, q1;
@@ -846,7 +907,7 @@ static void VFilter8iSSE2(uint8_t* u, uint8_t* v, int stride,
LOADUV_H_EDGES4(u, v, stride, q0, q1, t1, t2);
MAX_DIFF2(t2, t1, q1, q0, mask);
- COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
+ ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh);
// Store
@@ -856,8 +917,8 @@ static void VFilter8iSSE2(uint8_t* u, uint8_t* v, int stride,
STOREUV(q1, u, v, 1 * stride);
}
-static void HFilter8iSSE2(uint8_t* u, uint8_t* v, int stride,
- int thresh, int ithresh, int hev_thresh) {
+static void HFilter8i(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
__m128i mask;
__m128i t1, t2, p1, p0, q0, q1;
Load16x4(u, v, stride, &t2, &t1, &p1, &p0); // p3, p2, p1, p0
@@ -868,36 +929,361 @@ static void HFilter8iSSE2(uint8_t* u, uint8_t* v, int stride,
Load16x4(u, v, stride, &q0, &q1, &t1, &t2); // q0, q1, q2, q3
MAX_DIFF2(t2, t1, q1, q0, mask);
- COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
+ ComplexMask(&p1, &p0, &q0, &q1, thresh, ithresh, &mask);
DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh);
u -= 2; // beginning of p1
v -= 2;
- Store16x4(u, v, stride, &p1, &p0, &q0, &q1);
+ Store16x4(&p1, &p0, &q0, &q1, u, v, stride);
}
-extern void VP8DspInitSSE2(void);
+//------------------------------------------------------------------------------
+// 4x4 predictions
+
+#define DST(x, y) dst[(x) + (y) * BPS]
+#define AVG3(a, b, c) (((a) + 2 * (b) + (c) + 2) >> 2)
+
+// We use the following 8b-arithmetic tricks:
+// (a + 2 * b + c + 2) >> 2 = (AC + b + 1) >> 1
+// where: AC = (a + c) >> 1 = [(a + c + 1) >> 1] - [(a^c) & 1]
+// and:
+// (a + 2 * b + c + 2) >> 2 = (AB + BC + 1) >> 1 - (ab|bc)&lsb
+// where: AC = (a + b + 1) >> 1, BC = (b + c + 1) >> 1
+// and ab = a ^ b, bc = b ^ c, lsb = (AC^BC)&1
+
+static void VE4(uint8_t* dst) { // vertical
+ const __m128i one = _mm_set1_epi8(1);
+ const __m128i ABCDEFGH = _mm_loadl_epi64((__m128i*)(dst - BPS - 1));
+ const __m128i BCDEFGH0 = _mm_srli_si128(ABCDEFGH, 1);
+ const __m128i CDEFGH00 = _mm_srli_si128(ABCDEFGH, 2);
+ const __m128i a = _mm_avg_epu8(ABCDEFGH, CDEFGH00);
+ const __m128i lsb = _mm_and_si128(_mm_xor_si128(ABCDEFGH, CDEFGH00), one);
+ const __m128i b = _mm_subs_epu8(a, lsb);
+ const __m128i avg = _mm_avg_epu8(b, BCDEFGH0);
+ const uint32_t vals = _mm_cvtsi128_si32(avg);
+ int i;
+ for (i = 0; i < 4; ++i) {
+ *(uint32_t*)(dst + i * BPS) = vals;
+ }
+}
+
+static void LD4(uint8_t* dst) { // Down-Left
+ const __m128i one = _mm_set1_epi8(1);
+ const __m128i ABCDEFGH = _mm_loadl_epi64((__m128i*)(dst - BPS));
+ const __m128i BCDEFGH0 = _mm_srli_si128(ABCDEFGH, 1);
+ const __m128i CDEFGH00 = _mm_srli_si128(ABCDEFGH, 2);
+ const __m128i CDEFGHH0 = _mm_insert_epi16(CDEFGH00, dst[-BPS + 7], 3);
+ const __m128i avg1 = _mm_avg_epu8(ABCDEFGH, CDEFGHH0);
+ const __m128i lsb = _mm_and_si128(_mm_xor_si128(ABCDEFGH, CDEFGHH0), one);
+ const __m128i avg2 = _mm_subs_epu8(avg1, lsb);
+ const __m128i abcdefg = _mm_avg_epu8(avg2, BCDEFGH0);
+ *(uint32_t*)(dst + 0 * BPS) = _mm_cvtsi128_si32( abcdefg );
+ *(uint32_t*)(dst + 1 * BPS) = _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 1));
+ *(uint32_t*)(dst + 2 * BPS) = _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 2));
+ *(uint32_t*)(dst + 3 * BPS) = _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 3));
+}
+
+static void VR4(uint8_t* dst) { // Vertical-Right
+ const __m128i one = _mm_set1_epi8(1);
+ const int I = dst[-1 + 0 * BPS];
+ const int J = dst[-1 + 1 * BPS];
+ const int K = dst[-1 + 2 * BPS];
+ const int X = dst[-1 - BPS];
+ const __m128i XABCD = _mm_loadl_epi64((__m128i*)(dst - BPS - 1));
+ const __m128i ABCD0 = _mm_srli_si128(XABCD, 1);
+ const __m128i abcd = _mm_avg_epu8(XABCD, ABCD0);
+ const __m128i _XABCD = _mm_slli_si128(XABCD, 1);
+ const __m128i IXABCD = _mm_insert_epi16(_XABCD, I | (X << 8), 0);
+ const __m128i avg1 = _mm_avg_epu8(IXABCD, ABCD0);
+ const __m128i lsb = _mm_and_si128(_mm_xor_si128(IXABCD, ABCD0), one);
+ const __m128i avg2 = _mm_subs_epu8(avg1, lsb);
+ const __m128i efgh = _mm_avg_epu8(avg2, XABCD);
+ *(uint32_t*)(dst + 0 * BPS) = _mm_cvtsi128_si32( abcd );
+ *(uint32_t*)(dst + 1 * BPS) = _mm_cvtsi128_si32( efgh );
+ *(uint32_t*)(dst + 2 * BPS) = _mm_cvtsi128_si32(_mm_slli_si128(abcd, 1));
+ *(uint32_t*)(dst + 3 * BPS) = _mm_cvtsi128_si32(_mm_slli_si128(efgh, 1));
+
+ // these two are hard to implement in SSE2, so we keep the C-version:
+ DST(0, 2) = AVG3(J, I, X);
+ DST(0, 3) = AVG3(K, J, I);
+}
-void VP8DspInitSSE2(void) {
- VP8Transform = TransformSSE2;
+static void VL4(uint8_t* dst) { // Vertical-Left
+ const __m128i one = _mm_set1_epi8(1);
+ const __m128i ABCDEFGH = _mm_loadl_epi64((__m128i*)(dst - BPS));
+ const __m128i BCDEFGH_ = _mm_srli_si128(ABCDEFGH, 1);
+ const __m128i CDEFGH__ = _mm_srli_si128(ABCDEFGH, 2);
+ const __m128i avg1 = _mm_avg_epu8(ABCDEFGH, BCDEFGH_);
+ const __m128i avg2 = _mm_avg_epu8(CDEFGH__, BCDEFGH_);
+ const __m128i avg3 = _mm_avg_epu8(avg1, avg2);
+ const __m128i lsb1 = _mm_and_si128(_mm_xor_si128(avg1, avg2), one);
+ const __m128i ab = _mm_xor_si128(ABCDEFGH, BCDEFGH_);
+ const __m128i bc = _mm_xor_si128(CDEFGH__, BCDEFGH_);
+ const __m128i abbc = _mm_or_si128(ab, bc);
+ const __m128i lsb2 = _mm_and_si128(abbc, lsb1);
+ const __m128i avg4 = _mm_subs_epu8(avg3, lsb2);
+ const uint32_t extra_out = _mm_cvtsi128_si32(_mm_srli_si128(avg4, 4));
+ *(uint32_t*)(dst + 0 * BPS) = _mm_cvtsi128_si32( avg1 );
+ *(uint32_t*)(dst + 1 * BPS) = _mm_cvtsi128_si32( avg4 );
+ *(uint32_t*)(dst + 2 * BPS) = _mm_cvtsi128_si32(_mm_srli_si128(avg1, 1));
+ *(uint32_t*)(dst + 3 * BPS) = _mm_cvtsi128_si32(_mm_srli_si128(avg4, 1));
+
+ // these two are hard to get and irregular
+ DST(3, 2) = (extra_out >> 0) & 0xff;
+ DST(3, 3) = (extra_out >> 8) & 0xff;
+}
+
+static void RD4(uint8_t* dst) { // Down-right
+ const __m128i one = _mm_set1_epi8(1);
+ const __m128i XABCD = _mm_loadl_epi64((__m128i*)(dst - BPS - 1));
+ const __m128i ____XABCD = _mm_slli_si128(XABCD, 4);
+ const uint32_t I = dst[-1 + 0 * BPS];
+ const uint32_t J = dst[-1 + 1 * BPS];
+ const uint32_t K = dst[-1 + 2 * BPS];
+ const uint32_t L = dst[-1 + 3 * BPS];
+ const __m128i LKJI_____ =
+ _mm_cvtsi32_si128(L | (K << 8) | (J << 16) | (I << 24));
+ const __m128i LKJIXABCD = _mm_or_si128(LKJI_____, ____XABCD);
+ const __m128i KJIXABCD_ = _mm_srli_si128(LKJIXABCD, 1);
+ const __m128i JIXABCD__ = _mm_srli_si128(LKJIXABCD, 2);
+ const __m128i avg1 = _mm_avg_epu8(JIXABCD__, LKJIXABCD);
+ const __m128i lsb = _mm_and_si128(_mm_xor_si128(JIXABCD__, LKJIXABCD), one);
+ const __m128i avg2 = _mm_subs_epu8(avg1, lsb);
+ const __m128i abcdefg = _mm_avg_epu8(avg2, KJIXABCD_);
+ *(uint32_t*)(dst + 3 * BPS) = _mm_cvtsi128_si32( abcdefg );
+ *(uint32_t*)(dst + 2 * BPS) = _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 1));
+ *(uint32_t*)(dst + 1 * BPS) = _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 2));
+ *(uint32_t*)(dst + 0 * BPS) = _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 3));
+}
+
+#undef DST
+#undef AVG3
+
+//------------------------------------------------------------------------------
+// Luma 16x16
+
+static WEBP_INLINE void TrueMotion(uint8_t* dst, int size) {
+ const uint8_t* top = dst - BPS;
+ const __m128i zero = _mm_setzero_si128();
+ int y;
+ if (size == 4) {
+ const __m128i top_values = _mm_cvtsi32_si128(MemToUint32(top));
+ const __m128i top_base = _mm_unpacklo_epi8(top_values, zero);
+ for (y = 0; y < 4; ++y, dst += BPS) {
+ const int val = dst[-1] - top[-1];
+ const __m128i base = _mm_set1_epi16(val);
+ const __m128i out = _mm_packus_epi16(_mm_add_epi16(base, top_base), zero);
+ *(int*)dst = _mm_cvtsi128_si32(out);
+ }
+ } else if (size == 8) {
+ const __m128i top_values = _mm_loadl_epi64((const __m128i*)top);
+ const __m128i top_base = _mm_unpacklo_epi8(top_values, zero);
+ for (y = 0; y < 8; ++y, dst += BPS) {
+ const int val = dst[-1] - top[-1];
+ const __m128i base = _mm_set1_epi16(val);
+ const __m128i out = _mm_packus_epi16(_mm_add_epi16(base, top_base), zero);
+ _mm_storel_epi64((__m128i*)dst, out);
+ }
+ } else {
+ const __m128i top_values = _mm_loadu_si128((const __m128i*)top);
+ const __m128i top_base_0 = _mm_unpacklo_epi8(top_values, zero);
+ const __m128i top_base_1 = _mm_unpackhi_epi8(top_values, zero);
+ for (y = 0; y < 16; ++y, dst += BPS) {
+ const int val = dst[-1] - top[-1];
+ const __m128i base = _mm_set1_epi16(val);
+ const __m128i out_0 = _mm_add_epi16(base, top_base_0);
+ const __m128i out_1 = _mm_add_epi16(base, top_base_1);
+ const __m128i out = _mm_packus_epi16(out_0, out_1);
+ _mm_storeu_si128((__m128i*)dst, out);
+ }
+ }
+}
+
+static void TM4(uint8_t* dst) { TrueMotion(dst, 4); }
+static void TM8uv(uint8_t* dst) { TrueMotion(dst, 8); }
+static void TM16(uint8_t* dst) { TrueMotion(dst, 16); }
+
+static void VE16(uint8_t* dst) {
+ const __m128i top = _mm_loadu_si128((const __m128i*)(dst - BPS));
+ int j;
+ for (j = 0; j < 16; ++j) {
+ _mm_storeu_si128((__m128i*)(dst + j * BPS), top);
+ }
+}
+
+static void HE16(uint8_t* dst) { // horizontal
+ int j;
+ for (j = 16; j > 0; --j) {
+ const __m128i values = _mm_set1_epi8(dst[-1]);
+ _mm_storeu_si128((__m128i*)dst, values);
+ dst += BPS;
+ }
+}
+
+static WEBP_INLINE void Put16(uint8_t v, uint8_t* dst) {
+ int j;
+ const __m128i values = _mm_set1_epi8(v);
+ for (j = 0; j < 16; ++j) {
+ _mm_storeu_si128((__m128i*)(dst + j * BPS), values);
+ }
+}
+
+static void DC16(uint8_t* dst) { // DC
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i top = _mm_loadu_si128((const __m128i*)(dst - BPS));
+ const __m128i sad8x2 = _mm_sad_epu8(top, zero);
+ // sum the two sads: sad8x2[0:1] + sad8x2[8:9]
+ const __m128i sum = _mm_add_epi16(sad8x2, _mm_shuffle_epi32(sad8x2, 2));
+ int left = 0;
+ int j;
+ for (j = 0; j < 16; ++j) {
+ left += dst[-1 + j * BPS];
+ }
+ {
+ const int DC = _mm_cvtsi128_si32(sum) + left + 16;
+ Put16(DC >> 5, dst);
+ }
+}
+
+static void DC16NoTop(uint8_t* dst) { // DC with top samples not available
+ int DC = 8;
+ int j;
+ for (j = 0; j < 16; ++j) {
+ DC += dst[-1 + j * BPS];
+ }
+ Put16(DC >> 4, dst);
+}
+
+static void DC16NoLeft(uint8_t* dst) { // DC with left samples not available
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i top = _mm_loadu_si128((const __m128i*)(dst - BPS));
+ const __m128i sad8x2 = _mm_sad_epu8(top, zero);
+ // sum the two sads: sad8x2[0:1] + sad8x2[8:9]
+ const __m128i sum = _mm_add_epi16(sad8x2, _mm_shuffle_epi32(sad8x2, 2));
+ const int DC = _mm_cvtsi128_si32(sum) + 8;
+ Put16(DC >> 4, dst);
+}
- VP8VFilter16 = VFilter16SSE2;
- VP8HFilter16 = HFilter16SSE2;
- VP8VFilter8 = VFilter8SSE2;
- VP8HFilter8 = HFilter8SSE2;
- VP8VFilter16i = VFilter16iSSE2;
- VP8HFilter16i = HFilter16iSSE2;
- VP8VFilter8i = VFilter8iSSE2;
- VP8HFilter8i = HFilter8iSSE2;
+static void DC16NoTopLeft(uint8_t* dst) { // DC with no top and left samples
+ Put16(0x80, dst);
+}
+
+//------------------------------------------------------------------------------
+// Chroma
+
+static void VE8uv(uint8_t* dst) { // vertical
+ int j;
+ const __m128i top = _mm_loadl_epi64((const __m128i*)(dst - BPS));
+ for (j = 0; j < 8; ++j) {
+ _mm_storel_epi64((__m128i*)(dst + j * BPS), top);
+ }
+}
+
+static void HE8uv(uint8_t* dst) { // horizontal
+ int j;
+ for (j = 0; j < 8; ++j) {
+ const __m128i values = _mm_set1_epi8(dst[-1]);
+ _mm_storel_epi64((__m128i*)dst, values);
+ dst += BPS;
+ }
+}
+
+// helper for chroma-DC predictions
+static WEBP_INLINE void Put8x8uv(uint8_t v, uint8_t* dst) {
+ int j;
+ const __m128i values = _mm_set1_epi8(v);
+ for (j = 0; j < 8; ++j) {
+ _mm_storel_epi64((__m128i*)(dst + j * BPS), values);
+ }
+}
- VP8SimpleVFilter16 = SimpleVFilter16SSE2;
- VP8SimpleHFilter16 = SimpleHFilter16SSE2;
- VP8SimpleVFilter16i = SimpleVFilter16iSSE2;
- VP8SimpleHFilter16i = SimpleHFilter16iSSE2;
+static void DC8uv(uint8_t* dst) { // DC
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i top = _mm_loadl_epi64((const __m128i*)(dst - BPS));
+ const __m128i sum = _mm_sad_epu8(top, zero);
+ int left = 0;
+ int j;
+ for (j = 0; j < 8; ++j) {
+ left += dst[-1 + j * BPS];
+ }
+ {
+ const int DC = _mm_cvtsi128_si32(sum) + left + 8;
+ Put8x8uv(DC >> 4, dst);
+ }
}
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
+static void DC8uvNoLeft(uint8_t* dst) { // DC with no left samples
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i top = _mm_loadl_epi64((const __m128i*)(dst - BPS));
+ const __m128i sum = _mm_sad_epu8(top, zero);
+ const int DC = _mm_cvtsi128_si32(sum) + 4;
+ Put8x8uv(DC >> 3, dst);
+}
+
+static void DC8uvNoTop(uint8_t* dst) { // DC with no top samples
+ int dc0 = 4;
+ int i;
+ for (i = 0; i < 8; ++i) {
+ dc0 += dst[-1 + i * BPS];
+ }
+ Put8x8uv(dc0 >> 3, dst);
+}
+
+static void DC8uvNoTopLeft(uint8_t* dst) { // DC with nothing
+ Put8x8uv(0x80, dst);
+}
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8DspInitSSE2(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8DspInitSSE2(void) {
+ VP8Transform = Transform;
+#if defined(USE_TRANSFORM_AC3)
+ VP8TransformAC3 = TransformAC3;
#endif
-#endif // WEBP_USE_SSE2
+ VP8VFilter16 = VFilter16;
+ VP8HFilter16 = HFilter16;
+ VP8VFilter8 = VFilter8;
+ VP8HFilter8 = HFilter8;
+ VP8VFilter16i = VFilter16i;
+ VP8HFilter16i = HFilter16i;
+ VP8VFilter8i = VFilter8i;
+ VP8HFilter8i = HFilter8i;
+
+ VP8SimpleVFilter16 = SimpleVFilter16;
+ VP8SimpleHFilter16 = SimpleHFilter16;
+ VP8SimpleVFilter16i = SimpleVFilter16i;
+ VP8SimpleHFilter16i = SimpleHFilter16i;
+
+ VP8PredLuma4[1] = TM4;
+ VP8PredLuma4[2] = VE4;
+ VP8PredLuma4[4] = RD4;
+ VP8PredLuma4[5] = VR4;
+ VP8PredLuma4[6] = LD4;
+ VP8PredLuma4[7] = VL4;
+
+ VP8PredLuma16[0] = DC16;
+ VP8PredLuma16[1] = TM16;
+ VP8PredLuma16[2] = VE16;
+ VP8PredLuma16[3] = HE16;
+ VP8PredLuma16[4] = DC16NoTop;
+ VP8PredLuma16[5] = DC16NoLeft;
+ VP8PredLuma16[6] = DC16NoTopLeft;
+
+ VP8PredChroma8[0] = DC8uv;
+ VP8PredChroma8[1] = TM8uv;
+ VP8PredChroma8[2] = VE8uv;
+ VP8PredChroma8[3] = HE8uv;
+ VP8PredChroma8[4] = DC8uvNoTop;
+ VP8PredChroma8[5] = DC8uvNoLeft;
+ VP8PredChroma8[6] = DC8uvNoTopLeft;
+}
+
+#else // !WEBP_USE_SSE2
+
+WEBP_DSP_INIT_STUB(VP8DspInitSSE2)
+
+#endif // WEBP_USE_SSE2
diff --git a/drivers/webp/dsp/dec_sse41.c b/drivers/webp/dsp/dec_sse41.c
new file mode 100644
index 0000000000..dc1e70428d
--- /dev/null
+++ b/drivers/webp/dsp/dec_sse41.c
@@ -0,0 +1,45 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// SSE4 version of some decoding functions.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_SSE41)
+
+#include <smmintrin.h>
+#include "../dec/vp8i.h"
+
+static void HE16(uint8_t* dst) { // horizontal
+ int j;
+ const __m128i kShuffle3 = _mm_set1_epi8(3);
+ for (j = 16; j > 0; --j) {
+ const __m128i in = _mm_cvtsi32_si128(*(int*)(dst - 4));
+ const __m128i values = _mm_shuffle_epi8(in, kShuffle3);
+ _mm_storeu_si128((__m128i*)dst, values);
+ dst += BPS;
+ }
+}
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8DspInitSSE41(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8DspInitSSE41(void) {
+ VP8PredLuma16[3] = HE16;
+}
+
+#else // !WEBP_USE_SSE41
+
+WEBP_DSP_INIT_STUB(VP8DspInitSSE41)
+
+#endif // WEBP_USE_SSE41
diff --git a/drivers/webp/dsp/dsp.h b/drivers/webp/dsp/dsp.h
index afe30413c6..4613d9c3ff 100644
--- a/drivers/webp/dsp/dsp.h
+++ b/drivers/webp/dsp/dsp.h
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Speed-critical functions.
@@ -12,44 +14,121 @@
#ifndef WEBP_DSP_DSP_H_
#define WEBP_DSP_DSP_H_
-#include "../types.h"
+#ifdef HAVE_CONFIG_H
+#include "webp/config.h"
+#endif
+
+#include "webp/types.h"
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
extern "C" {
#endif
+#define BPS 32 // this is the common stride for enc/dec
+
//------------------------------------------------------------------------------
// CPU detection
-#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))
+#if defined(__GNUC__)
+# define LOCAL_GCC_VERSION ((__GNUC__ << 8) | __GNUC_MINOR__)
+# define LOCAL_GCC_PREREQ(maj, min) \
+ (LOCAL_GCC_VERSION >= (((maj) << 8) | (min)))
+#else
+# define LOCAL_GCC_VERSION 0
+# define LOCAL_GCC_PREREQ(maj, min) 0
+#endif
+
+#ifndef __has_builtin
+# define __has_builtin(x) 0
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER > 1310 && \
+ (defined(_M_X64) || defined(_M_IX86))
#define WEBP_MSC_SSE2 // Visual C++ SSE2 targets
#endif
-#if defined(__SSE2__) || defined(WEBP_MSC_SSE2)
+#if defined(_MSC_VER) && _MSC_VER >= 1500 && \
+ (defined(_M_X64) || defined(_M_IX86))
+#define WEBP_MSC_SSE41 // Visual C++ SSE4.1 targets
+#endif
+
+// WEBP_HAVE_* are used to indicate the presence of the instruction set in dsp
+// files without intrinsics, allowing the corresponding Init() to be called.
+// Files containing intrinsics will need to be built targeting the instruction
+// set so should succeed on one of the earlier tests.
+#if defined(__SSE2__) || defined(WEBP_MSC_SSE2) || defined(WEBP_HAVE_SSE2)
#define WEBP_USE_SSE2
#endif
+#if defined(__SSE4_1__) || defined(WEBP_MSC_SSE41) || defined(WEBP_HAVE_SSE41)
+#define WEBP_USE_SSE41
+#endif
+
+#if defined(__AVX2__) || defined(WEBP_HAVE_AVX2)
+#define WEBP_USE_AVX2
+#endif
+
#if defined(__ANDROID__) && defined(__ARM_ARCH_7A__)
#define WEBP_ANDROID_NEON // Android targets that might support NEON
#endif
-#if ( (defined(__ARM_NEON__) && !defined(__aarch64__)) || defined(WEBP_ANDROID_NEON)) && !defined(PSP2_ENABLED)
+// The intrinsics currently cause compiler errors with arm-nacl-gcc and the
+// inline assembly would need to be modified for use with Native Client.
+#if (defined(__ARM_NEON__) || defined(WEBP_ANDROID_NEON) || \
+ defined(__aarch64__)) && !defined(__native_client__)
+#define WEBP_USE_NEON
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_M_ARM)
#define WEBP_USE_NEON
+#define WEBP_USE_INTRINSICS
+#endif
+
+#if defined(__mips__) && !defined(__mips64) && \
+ defined(__mips_isa_rev) && (__mips_isa_rev >= 1) && (__mips_isa_rev < 6)
+#define WEBP_USE_MIPS32
+#if (__mips_isa_rev >= 2)
+#define WEBP_USE_MIPS32_R2
+#if defined(__mips_dspr2) || (__mips_dsp_rev >= 2)
+#define WEBP_USE_MIPS_DSP_R2
+#endif
+#endif
+#endif
+
+// This macro prevents thread_sanitizer from reporting known concurrent writes.
+#define WEBP_TSAN_IGNORE_FUNCTION
+#if defined(__has_feature)
+#if __has_feature(thread_sanitizer)
+#undef WEBP_TSAN_IGNORE_FUNCTION
+#define WEBP_TSAN_IGNORE_FUNCTION __attribute__((no_sanitize_thread))
+#endif
#endif
typedef enum {
kSSE2,
kSSE3,
- kNEON
+ kSSE4_1,
+ kAVX,
+ kAVX2,
+ kNEON,
+ kMIPS32,
+ kMIPSdspR2
} CPUFeature;
// returns true if the CPU supports the feature.
typedef int (*VP8CPUInfo)(CPUFeature feature);
-extern VP8CPUInfo VP8GetCPUInfo;
+WEBP_EXTERN(VP8CPUInfo) VP8GetCPUInfo;
//------------------------------------------------------------------------------
-// Encoding
+// Init stub generator
-int VP8GetAlpha(const int histo[]);
+// Defines an init function stub to ensure each module exposes a symbol,
+// avoiding a compiler warning.
+#define WEBP_DSP_INIT_STUB(func) \
+ extern void func(void); \
+ WEBP_TSAN_IGNORE_FUNCTION void func(void) {}
+
+//------------------------------------------------------------------------------
+// Encoding
// Transforms
// VP8Idct: Does one of two inverse transforms. If do_two is set, the transforms
@@ -60,7 +139,7 @@ typedef void (*VP8Fdct)(const uint8_t* src, const uint8_t* ref, int16_t* out);
typedef void (*VP8WHT)(const int16_t* in, int16_t* out);
extern VP8Idct VP8ITransform;
extern VP8Fdct VP8FTransform;
-extern VP8WHT VP8ITransformWHT;
+extern VP8Fdct VP8FTransform2; // performs two transforms at a time
extern VP8WHT VP8FTransformWHT;
// Predictions
// *dst is the destination block. *top and *left can be NULL.
@@ -79,20 +158,63 @@ extern VP8WMetric VP8TDisto4x4, VP8TDisto16x16;
typedef void (*VP8BlockCopy)(const uint8_t* src, uint8_t* dst);
extern VP8BlockCopy VP8Copy4x4;
+extern VP8BlockCopy VP8Copy16x8;
// Quantization
struct VP8Matrix; // forward declaration
typedef int (*VP8QuantizeBlock)(int16_t in[16], int16_t out[16],
- int n, const struct VP8Matrix* const mtx);
+ const struct VP8Matrix* const mtx);
+// Same as VP8QuantizeBlock, but quantizes two consecutive blocks.
+typedef int (*VP8Quantize2Blocks)(int16_t in[32], int16_t out[32],
+ const struct VP8Matrix* const mtx);
+
extern VP8QuantizeBlock VP8EncQuantizeBlock;
+extern VP8Quantize2Blocks VP8EncQuantize2Blocks;
+
+// specific to 2nd transform:
+typedef int (*VP8QuantizeBlockWHT)(int16_t in[16], int16_t out[16],
+ const struct VP8Matrix* const mtx);
+extern VP8QuantizeBlockWHT VP8EncQuantizeBlockWHT;
-// Compute susceptibility based on DCT-coeff histograms:
-// the higher, the "easier" the macroblock is to compress.
-typedef int (*VP8CHisto)(const uint8_t* ref, const uint8_t* pred,
- int start_block, int end_block);
extern const int VP8DspScan[16 + 4 + 4];
+
+// Collect histogram for susceptibility calculation.
+#define MAX_COEFF_THRESH 31 // size of histogram used by CollectHistogram.
+typedef struct {
+ // We only need to store max_value and last_non_zero, not the distribution.
+ int max_value;
+ int last_non_zero;
+} VP8Histogram;
+typedef void (*VP8CHisto)(const uint8_t* ref, const uint8_t* pred,
+ int start_block, int end_block,
+ VP8Histogram* const histo);
extern VP8CHisto VP8CollectHistogram;
+// General-purpose util function to help VP8CollectHistogram().
+void VP8SetHistogramData(const int distribution[MAX_COEFF_THRESH + 1],
+ VP8Histogram* const histo);
+
+// must be called before using any of the above
+void VP8EncDspInit(void);
+
+//------------------------------------------------------------------------------
+// cost functions (encoding)
+
+extern const uint16_t VP8EntropyCost[256]; // 8bit fixed-point log(p)
+// approximate cost per level:
+extern const uint16_t VP8LevelFixedCosts[2047 /*MAX_LEVEL*/ + 1];
+extern const uint8_t VP8EncBands[16 + 1];
+
+struct VP8Residual;
+typedef void (*VP8SetResidualCoeffsFunc)(const int16_t* const coeffs,
+ struct VP8Residual* const res);
+extern VP8SetResidualCoeffsFunc VP8SetResidualCoeffs;
-void VP8EncDspInit(void); // must be called before using any of the above
+// Cost calculation function.
+typedef int (*VP8GetResidualCostFunc)(int ctx0,
+ const struct VP8Residual* const res);
+extern VP8GetResidualCostFunc VP8GetResidualCost;
+
+// must be called before anything using the above
+void VP8EncDspCostInit(void);
//------------------------------------------------------------------------------
// Decoding
@@ -101,17 +223,26 @@ typedef void (*VP8DecIdct)(const int16_t* coeffs, uint8_t* dst);
// when doing two transforms, coeffs is actually int16_t[2][16].
typedef void (*VP8DecIdct2)(const int16_t* coeffs, uint8_t* dst, int do_two);
extern VP8DecIdct2 VP8Transform;
+extern VP8DecIdct VP8TransformAC3;
extern VP8DecIdct VP8TransformUV;
extern VP8DecIdct VP8TransformDC;
extern VP8DecIdct VP8TransformDCUV;
-extern void (*VP8TransformWHT)(const int16_t* in, int16_t* out);
+extern VP8WHT VP8TransformWHT;
// *dst is the destination block, with stride BPS. Boundary samples are
// assumed accessible when needed.
typedef void (*VP8PredFunc)(uint8_t* dst);
-extern const VP8PredFunc VP8PredLuma16[/* NUM_B_DC_MODES */];
-extern const VP8PredFunc VP8PredChroma8[/* NUM_B_DC_MODES */];
-extern const VP8PredFunc VP8PredLuma4[/* NUM_BMODES */];
+extern VP8PredFunc VP8PredLuma16[/* NUM_B_DC_MODES */];
+extern VP8PredFunc VP8PredChroma8[/* NUM_B_DC_MODES */];
+extern VP8PredFunc VP8PredLuma4[/* NUM_BMODES */];
+
+// clipping tables (for filtering)
+extern const int8_t* const VP8ksclip1; // clips [-1020, 1020] to [-128, 127]
+extern const int8_t* const VP8ksclip2; // clips [-112, 112] to [-16, 15]
+extern const uint8_t* const VP8kclip1; // clips [-255,511] to [0,255]
+extern const uint8_t* const VP8kabs0; // abs(x) for x in [-255,255]
+// must be called first
+void VP8InitClipTables(void);
// simple filter (only for luma)
typedef void (*VP8SimpleFilterFunc)(uint8_t* p, int stride, int thresh);
@@ -145,6 +276,8 @@ void VP8DspInit(void);
#define FANCY_UPSAMPLING // undefined to remove fancy upsampling support
+// Convert a pair of y/u/v lines together to the output rgb/a colorspace.
+// bottom_y can be NULL if only one line of output is needed (at top/bottom).
typedef void (*WebPUpsampleLinePairFunc)(
const uint8_t* top_y, const uint8_t* bottom_y,
const uint8_t* top_u, const uint8_t* top_v,
@@ -156,18 +289,20 @@ typedef void (*WebPUpsampleLinePairFunc)(
// Fancy upsampling functions to convert YUV to RGB(A) modes
extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */];
-// Initializes SSE2 version of the fancy upsamplers.
-void WebPInitUpsamplersSSE2(void);
-
#endif // FANCY_UPSAMPLING
-// Point-sampling methods.
-typedef void (*WebPSampleLinePairFunc)(
- const uint8_t* top_y, const uint8_t* bottom_y,
- const uint8_t* u, const uint8_t* v,
- uint8_t* top_dst, uint8_t* bottom_dst, int len);
+// Per-row point-sampling methods.
+typedef void (*WebPSamplerRowFunc)(const uint8_t* y,
+ const uint8_t* u, const uint8_t* v,
+ uint8_t* dst, int len);
+// Generic function to apply 'WebPSamplerRowFunc' to the whole plane:
+void WebPSamplerProcessPlane(const uint8_t* y, int y_stride,
+ const uint8_t* u, const uint8_t* v, int uv_stride,
+ uint8_t* dst, int dst_stride,
+ int width, int height, WebPSamplerRowFunc func);
-extern const WebPSampleLinePairFunc WebPSamplers[/* MODE_LAST */];
+// Sampling functions to convert rows of YUV to RGB(A)
+extern WebPSamplerRowFunc WebPSamplers[/* MODE_LAST */];
// General function for converting two lines of ARGB or RGBA.
// 'alpha_is_last' should be true if 0xff000000 is stored in memory as
@@ -179,13 +314,84 @@ typedef void (*WebPYUV444Converter)(const uint8_t* y,
const uint8_t* u, const uint8_t* v,
uint8_t* dst, int len);
-extern const WebPYUV444Converter WebPYUV444Converters[/* MODE_LAST */];
+extern WebPYUV444Converter WebPYUV444Converters[/* MODE_LAST */];
-// Main function to be called
+// Must be called before using the WebPUpsamplers[] (and for premultiplied
+// colorspaces like rgbA, rgbA4444, etc)
void WebPInitUpsamplers(void);
+// Must be called before using WebPSamplers[]
+void WebPInitSamplers(void);
+// Must be called before using WebPYUV444Converters[]
+void WebPInitYUV444Converters(void);
//------------------------------------------------------------------------------
-// Pre-multiply planes with alpha values
+// ARGB -> YUV converters
+
+// Convert ARGB samples to luma Y.
+extern void (*WebPConvertARGBToY)(const uint32_t* argb, uint8_t* y, int width);
+// Convert ARGB samples to U/V with downsampling. do_store should be '1' for
+// even lines and '0' for odd ones. 'src_width' is the original width, not
+// the U/V one.
+extern void (*WebPConvertARGBToUV)(const uint32_t* argb, uint8_t* u, uint8_t* v,
+ int src_width, int do_store);
+
+// Convert a row of accumulated (four-values) of rgba32 toward U/V
+extern void (*WebPConvertRGBA32ToUV)(const uint16_t* rgb,
+ uint8_t* u, uint8_t* v, int width);
+
+// Convert RGB or BGR to Y
+extern void (*WebPConvertRGB24ToY)(const uint8_t* rgb, uint8_t* y, int width);
+extern void (*WebPConvertBGR24ToY)(const uint8_t* bgr, uint8_t* y, int width);
+
+// used for plain-C fallback.
+extern void WebPConvertARGBToUV_C(const uint32_t* argb, uint8_t* u, uint8_t* v,
+ int src_width, int do_store);
+extern void WebPConvertRGBA32ToUV_C(const uint16_t* rgb,
+ uint8_t* u, uint8_t* v, int width);
+
+// Must be called before using the above.
+void WebPInitConvertARGBToYUV(void);
+
+//------------------------------------------------------------------------------
+// Rescaler
+
+struct WebPRescaler;
+
+// Import a row of data and save its contribution in the rescaler.
+// 'channel' denotes the channel number to be imported. 'Expand' corresponds to
+// the wrk->x_expand case. Otherwise, 'Shrink' is to be used.
+typedef void (*WebPRescalerImportRowFunc)(struct WebPRescaler* const wrk,
+ const uint8_t* src);
+
+extern WebPRescalerImportRowFunc WebPRescalerImportRowExpand;
+extern WebPRescalerImportRowFunc WebPRescalerImportRowShrink;
+
+// Export one row (starting at x_out position) from rescaler.
+// 'Expand' corresponds to the wrk->y_expand case.
+// Otherwise 'Shrink' is to be used
+typedef void (*WebPRescalerExportRowFunc)(struct WebPRescaler* const wrk);
+extern WebPRescalerExportRowFunc WebPRescalerExportRowExpand;
+extern WebPRescalerExportRowFunc WebPRescalerExportRowShrink;
+
+// Plain-C implementation, as fall-back.
+extern void WebPRescalerImportRowExpandC(struct WebPRescaler* const wrk,
+ const uint8_t* src);
+extern void WebPRescalerImportRowShrinkC(struct WebPRescaler* const wrk,
+ const uint8_t* src);
+extern void WebPRescalerExportRowExpandC(struct WebPRescaler* const wrk);
+extern void WebPRescalerExportRowShrinkC(struct WebPRescaler* const wrk);
+
+// Main entry calls:
+extern void WebPRescalerImportRow(struct WebPRescaler* const wrk,
+ const uint8_t* src);
+// Export one row (starting at x_out position) from rescaler.
+extern void WebPRescalerExportRow(struct WebPRescaler* const wrk);
+
+// Must be called first before using the above.
+void WebPRescalerDspInit(void);
+
+//------------------------------------------------------------------------------
+// Utilities for processing transparent channel.
// Apply alpha pre-multiply on an rgba, bgra or argb plane of size w * h.
// alpha_first should be 0 for argb, 1 for rgba or bgra (where alpha is last).
@@ -196,14 +402,98 @@ extern void (*WebPApplyAlphaMultiply)(
extern void (*WebPApplyAlphaMultiply4444)(
uint8_t* rgba4444, int w, int h, int stride);
+// Dispatch the values from alpha[] plane to the ARGB destination 'dst'.
+// Returns true if alpha[] plane has non-trivial values different from 0xff.
+extern int (*WebPDispatchAlpha)(const uint8_t* alpha, int alpha_stride,
+ int width, int height,
+ uint8_t* dst, int dst_stride);
+
+// Transfer packed 8b alpha[] values to green channel in dst[], zero'ing the
+// A/R/B values. 'dst_stride' is the stride for dst[] in uint32_t units.
+extern void (*WebPDispatchAlphaToGreen)(const uint8_t* alpha, int alpha_stride,
+ int width, int height,
+ uint32_t* dst, int dst_stride);
+
+// Extract the alpha values from 32b values in argb[] and pack them into alpha[]
+// (this is the opposite of WebPDispatchAlpha).
+// Returns true if there's only trivial 0xff alpha values.
+extern int (*WebPExtractAlpha)(const uint8_t* argb, int argb_stride,
+ int width, int height,
+ uint8_t* alpha, int alpha_stride);
+
+// Pre-Multiply operation transforms x into x * A / 255 (where x=Y,R,G or B).
+// Un-Multiply operation transforms x into x * 255 / A.
+
+// Pre-Multiply or Un-Multiply (if 'inverse' is true) argb values in a row.
+extern void (*WebPMultARGBRow)(uint32_t* const ptr, int width, int inverse);
+
+// Same a WebPMultARGBRow(), but for several rows.
+void WebPMultARGBRows(uint8_t* ptr, int stride, int width, int num_rows,
+ int inverse);
+
+// Same for a row of single values, with side alpha values.
+extern void (*WebPMultRow)(uint8_t* const ptr, const uint8_t* const alpha,
+ int width, int inverse);
+
+// Same a WebPMultRow(), but for several 'num_rows' rows.
+void WebPMultRows(uint8_t* ptr, int stride,
+ const uint8_t* alpha, int alpha_stride,
+ int width, int num_rows, int inverse);
+
+// Plain-C versions, used as fallback by some implementations.
+void WebPMultRowC(uint8_t* const ptr, const uint8_t* const alpha,
+ int width, int inverse);
+void WebPMultARGBRowC(uint32_t* const ptr, int width, int inverse);
+
// To be called first before using the above.
-void WebPInitPremultiply(void);
+void WebPInitAlphaProcessing(void);
+
+// ARGB packing function: a/r/g/b input is rgba or bgra order.
+extern void (*VP8PackARGB)(const uint8_t* a, const uint8_t* r,
+ const uint8_t* g, const uint8_t* b, int len,
+ uint32_t* out);
+
+// RGB packing function. 'step' can be 3 or 4. r/g/b input is rgb or bgr order.
+extern void (*VP8PackRGB)(const uint8_t* r, const uint8_t* g, const uint8_t* b,
+ int len, int step, uint32_t* out);
-void WebPInitPremultiplySSE2(void); // should not be called directly.
+// To be called first before using the above.
+void VP8EncDspARGBInit(void);
//------------------------------------------------------------------------------
+// Filter functions
+
+typedef enum { // Filter types.
+ WEBP_FILTER_NONE = 0,
+ WEBP_FILTER_HORIZONTAL,
+ WEBP_FILTER_VERTICAL,
+ WEBP_FILTER_GRADIENT,
+ WEBP_FILTER_LAST = WEBP_FILTER_GRADIENT + 1, // end marker
+ WEBP_FILTER_BEST, // meta-types
+ WEBP_FILTER_FAST
+} WEBP_FILTER_TYPE;
+
+typedef void (*WebPFilterFunc)(const uint8_t* in, int width, int height,
+ int stride, uint8_t* out);
+typedef void (*WebPUnfilterFunc)(int width, int height, int stride,
+ int row, int num_rows, uint8_t* data);
+
+// Filter the given data using the given predictor.
+// 'in' corresponds to a 2-dimensional pixel array of size (stride * height)
+// in raster order.
+// 'stride' is number of bytes per scan line (with possible padding).
+// 'out' should be pre-allocated.
+extern WebPFilterFunc WebPFilters[WEBP_FILTER_LAST];
+
+// In-place reconstruct the original data from the given filtered data.
+// The reconstruction will be done for 'num_rows' rows starting from 'row'
+// (assuming rows upto 'row - 1' are already reconstructed).
+extern WebPUnfilterFunc WebPUnfilters[WEBP_FILTER_LAST];
+
+// To be called first before using the above.
+void VP8FiltersInit(void);
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/drivers/webp/dsp/enc.c b/drivers/webp/dsp/enc.c
index 02234564be..95e63f89ab 100644
--- a/drivers/webp/dsp/enc.c
+++ b/drivers/webp/dsp/enc.c
@@ -1,47 +1,34 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Speed-critical encoding functions.
//
// Author: Skal (pascal.massimino@gmail.com)
+#include <assert.h>
#include <stdlib.h> // for abs()
+
#include "./dsp.h"
#include "../enc/vp8enci.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
+static WEBP_INLINE uint8_t clip_8b(int v) {
+ return (!(v & ~0xff)) ? v : (v < 0) ? 0 : 255;
+}
+
+static WEBP_INLINE int clip_max(int v, int max) {
+ return (v > max) ? max : v;
+}
//------------------------------------------------------------------------------
// Compute susceptibility based on DCT-coeff histograms:
// the higher, the "easier" the macroblock is to compress.
-static int ClipAlpha(int alpha) {
- return alpha < 0 ? 0 : alpha > 255 ? 255 : alpha;
-}
-
-int VP8GetAlpha(const int histo[MAX_COEFF_THRESH + 1]) {
- int num = 0, den = 0, val = 0;
- int k;
- int alpha;
- // note: changing this loop to avoid the numerous "k + 1" slows things down.
- for (k = 0; k < MAX_COEFF_THRESH; ++k) {
- if (histo[k + 1]) {
- val += histo[k + 1];
- num += val * (k + 1);
- den += (k + 1) * (k + 1);
- }
- }
- // we scale the value to a usable [0..255] range
- alpha = den ? 10 * num / den - 5 : 0;
- return ClipAlpha(alpha);
-}
-
const int VP8DspScan[16 + 4 + 4] = {
// Luma
0 + 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS,
@@ -53,27 +40,41 @@ const int VP8DspScan[16 + 4 + 4] = {
8 + 0 * BPS, 12 + 0 * BPS, 8 + 4 * BPS, 12 + 4 * BPS // V
};
-static int CollectHistogram(const uint8_t* ref, const uint8_t* pred,
- int start_block, int end_block) {
- int histo[MAX_COEFF_THRESH + 1] = { 0 };
- int16_t out[16];
- int j, k;
+// general-purpose util function
+void VP8SetHistogramData(const int distribution[MAX_COEFF_THRESH + 1],
+ VP8Histogram* const histo) {
+ int max_value = 0, last_non_zero = 1;
+ int k;
+ for (k = 0; k <= MAX_COEFF_THRESH; ++k) {
+ const int value = distribution[k];
+ if (value > 0) {
+ if (value > max_value) max_value = value;
+ last_non_zero = k;
+ }
+ }
+ histo->max_value = max_value;
+ histo->last_non_zero = last_non_zero;
+}
+
+static void CollectHistogram(const uint8_t* ref, const uint8_t* pred,
+ int start_block, int end_block,
+ VP8Histogram* const histo) {
+ int j;
+ int distribution[MAX_COEFF_THRESH + 1] = { 0 };
for (j = start_block; j < end_block; ++j) {
- VP8FTransform(ref + VP8DspScan[j], pred + VP8DspScan[j], out);
+ int k;
+ int16_t out[16];
- // Convert coefficients to bin (within out[]).
- for (k = 0; k < 16; ++k) {
- const int v = abs(out[k]) >> 2;
- out[k] = (v > MAX_COEFF_THRESH) ? MAX_COEFF_THRESH : v;
- }
+ VP8FTransform(ref + VP8DspScan[j], pred + VP8DspScan[j], out);
- // Use bin to update histogram.
+ // Convert coefficients to bin.
for (k = 0; k < 16; ++k) {
- histo[out[k]]++;
+ const int v = abs(out[k]) >> 3; // TODO(skal): add rounding?
+ const int clipped_value = clip_max(v, MAX_COEFF_THRESH);
+ ++distribution[clipped_value];
}
}
-
- return VP8GetAlpha(histo);
+ VP8SetHistogramData(distribution, histo);
}
//------------------------------------------------------------------------------
@@ -85,19 +86,16 @@ static uint8_t clip1[255 + 510 + 1]; // clips [-255,510] to [0,255]
// and make sure it's set to true _last_ (so as to be thread-safe)
static volatile int tables_ok = 0;
-static void InitTables(void) {
+static WEBP_TSAN_IGNORE_FUNCTION void InitTables(void) {
if (!tables_ok) {
int i;
for (i = -255; i <= 255 + 255; ++i) {
- clip1[255 + i] = (i < 0) ? 0 : (i > 255) ? 255 : i;
+ clip1[255 + i] = clip_8b(i);
}
tables_ok = 1;
}
}
-static WEBP_INLINE uint8_t clip_8b(int v) {
- return (!(v & ~0xff)) ? v : v < 0 ? 0 : 255;
-}
//------------------------------------------------------------------------------
// Transforms (Paragraph 14.4)
@@ -154,84 +152,63 @@ static void FTransform(const uint8_t* src, const uint8_t* ref, int16_t* out) {
int i;
int tmp[16];
for (i = 0; i < 4; ++i, src += BPS, ref += BPS) {
- const int d0 = src[0] - ref[0];
+ const int d0 = src[0] - ref[0]; // 9bit dynamic range ([-255,255])
const int d1 = src[1] - ref[1];
const int d2 = src[2] - ref[2];
const int d3 = src[3] - ref[3];
- const int a0 = (d0 + d3) << 3;
- const int a1 = (d1 + d2) << 3;
- const int a2 = (d1 - d2) << 3;
- const int a3 = (d0 - d3) << 3;
- tmp[0 + i * 4] = (a0 + a1);
- tmp[1 + i * 4] = (a2 * 2217 + a3 * 5352 + 14500) >> 12;
- tmp[2 + i * 4] = (a0 - a1);
- tmp[3 + i * 4] = (a3 * 2217 - a2 * 5352 + 7500) >> 12;
+ const int a0 = (d0 + d3); // 10b [-510,510]
+ const int a1 = (d1 + d2);
+ const int a2 = (d1 - d2);
+ const int a3 = (d0 - d3);
+ tmp[0 + i * 4] = (a0 + a1) * 8; // 14b [-8160,8160]
+ tmp[1 + i * 4] = (a2 * 2217 + a3 * 5352 + 1812) >> 9; // [-7536,7542]
+ tmp[2 + i * 4] = (a0 - a1) * 8;
+ tmp[3 + i * 4] = (a3 * 2217 - a2 * 5352 + 937) >> 9;
}
for (i = 0; i < 4; ++i) {
- const int a0 = (tmp[0 + i] + tmp[12 + i]);
+ const int a0 = (tmp[0 + i] + tmp[12 + i]); // 15b
const int a1 = (tmp[4 + i] + tmp[ 8 + i]);
const int a2 = (tmp[4 + i] - tmp[ 8 + i]);
const int a3 = (tmp[0 + i] - tmp[12 + i]);
- out[0 + i] = (a0 + a1 + 7) >> 4;
+ out[0 + i] = (a0 + a1 + 7) >> 4; // 12b
out[4 + i] = ((a2 * 2217 + a3 * 5352 + 12000) >> 16) + (a3 != 0);
out[8 + i] = (a0 - a1 + 7) >> 4;
out[12+ i] = ((a3 * 2217 - a2 * 5352 + 51000) >> 16);
}
}
-static void ITransformWHT(const int16_t* in, int16_t* out) {
- int tmp[16];
- int i;
- for (i = 0; i < 4; ++i) {
- const int a0 = in[0 + i] + in[12 + i];
- const int a1 = in[4 + i] + in[ 8 + i];
- const int a2 = in[4 + i] - in[ 8 + i];
- const int a3 = in[0 + i] - in[12 + i];
- tmp[0 + i] = a0 + a1;
- tmp[8 + i] = a0 - a1;
- tmp[4 + i] = a3 + a2;
- tmp[12 + i] = a3 - a2;
- }
- for (i = 0; i < 4; ++i) {
- const int dc = tmp[0 + i * 4] + 3; // w/ rounder
- const int a0 = dc + tmp[3 + i * 4];
- const int a1 = tmp[1 + i * 4] + tmp[2 + i * 4];
- const int a2 = tmp[1 + i * 4] - tmp[2 + i * 4];
- const int a3 = dc - tmp[3 + i * 4];
- out[ 0] = (a0 + a1) >> 3;
- out[16] = (a3 + a2) >> 3;
- out[32] = (a0 - a1) >> 3;
- out[48] = (a3 - a2) >> 3;
- out += 64;
- }
+static void FTransform2(const uint8_t* src, const uint8_t* ref, int16_t* out) {
+ VP8FTransform(src, ref, out);
+ VP8FTransform(src + 4, ref + 4, out + 16);
}
static void FTransformWHT(const int16_t* in, int16_t* out) {
- int tmp[16];
+ // input is 12b signed
+ int32_t tmp[16];
int i;
for (i = 0; i < 4; ++i, in += 64) {
- const int a0 = (in[0 * 16] + in[2 * 16]) << 2;
- const int a1 = (in[1 * 16] + in[3 * 16]) << 2;
- const int a2 = (in[1 * 16] - in[3 * 16]) << 2;
- const int a3 = (in[0 * 16] - in[2 * 16]) << 2;
- tmp[0 + i * 4] = (a0 + a1) + (a0 != 0);
+ const int a0 = (in[0 * 16] + in[2 * 16]); // 13b
+ const int a1 = (in[1 * 16] + in[3 * 16]);
+ const int a2 = (in[1 * 16] - in[3 * 16]);
+ const int a3 = (in[0 * 16] - in[2 * 16]);
+ tmp[0 + i * 4] = a0 + a1; // 14b
tmp[1 + i * 4] = a3 + a2;
tmp[2 + i * 4] = a3 - a2;
tmp[3 + i * 4] = a0 - a1;
}
for (i = 0; i < 4; ++i) {
- const int a0 = (tmp[0 + i] + tmp[8 + i]);
+ const int a0 = (tmp[0 + i] + tmp[8 + i]); // 15b
const int a1 = (tmp[4 + i] + tmp[12+ i]);
const int a2 = (tmp[4 + i] - tmp[12+ i]);
const int a3 = (tmp[0 + i] - tmp[8 + i]);
- const int b0 = a0 + a1;
+ const int b0 = a0 + a1; // 16b
const int b1 = a3 + a2;
const int b2 = a3 - a2;
const int b3 = a0 - a1;
- out[ 0 + i] = (b0 + (b0 > 0) + 3) >> 3;
- out[ 4 + i] = (b1 + (b1 > 0) + 3) >> 3;
- out[ 8 + i] = (b2 + (b2 > 0) + 3) >> 3;
- out[12 + i] = (b3 + (b3 > 0) + 3) >> 3;
+ out[ 0 + i] = b0 >> 1; // 15b
+ out[ 4 + i] = b1 >> 1;
+ out[ 8 + i] = b2 >> 1;
+ out[12 + i] = b3 >> 1;
}
}
@@ -241,8 +218,6 @@ static void FTransformWHT(const int16_t* in, int16_t* out) {
//------------------------------------------------------------------------------
// Intra predictions
-#define DST(x, y) dst[(x) + (y) * BPS]
-
static WEBP_INLINE void Fill(uint8_t* dst, int value, int size) {
int j;
for (j = 0; j < size; ++j) {
@@ -253,7 +228,7 @@ static WEBP_INLINE void Fill(uint8_t* dst, int value, int size) {
static WEBP_INLINE void VerticalPred(uint8_t* dst,
const uint8_t* top, int size) {
int j;
- if (top) {
+ if (top != NULL) {
for (j = 0; j < size; ++j) memcpy(dst + j * BPS, top, size);
} else {
Fill(dst, 127, size);
@@ -262,7 +237,7 @@ static WEBP_INLINE void VerticalPred(uint8_t* dst,
static WEBP_INLINE void HorizontalPred(uint8_t* dst,
const uint8_t* left, int size) {
- if (left) {
+ if (left != NULL) {
int j;
for (j = 0; j < size; ++j) {
memset(dst + j * BPS, left[j], size);
@@ -275,8 +250,8 @@ static WEBP_INLINE void HorizontalPred(uint8_t* dst,
static WEBP_INLINE void TrueMotion(uint8_t* dst, const uint8_t* left,
const uint8_t* top, int size) {
int y;
- if (left) {
- if (top) {
+ if (left != NULL) {
+ if (top != NULL) {
const uint8_t* const clip = clip1 + 255 - left[-1];
for (y = 0; y < size; ++y) {
const uint8_t* const clip_table = clip + left[y];
@@ -294,7 +269,7 @@ static WEBP_INLINE void TrueMotion(uint8_t* dst, const uint8_t* left,
// is equivalent to VE prediction where you just copy the top samples.
// Note that if top samples are not available, the default value is
// then 129, and not 127 as in the VerticalPred case.
- if (top) {
+ if (top != NULL) {
VerticalPred(dst, top, size);
} else {
Fill(dst, 129, size);
@@ -307,15 +282,15 @@ static WEBP_INLINE void DCMode(uint8_t* dst, const uint8_t* left,
int size, int round, int shift) {
int DC = 0;
int j;
- if (top) {
+ if (top != NULL) {
for (j = 0; j < size; ++j) DC += top[j];
- if (left) { // top and left present
+ if (left != NULL) { // top and left present
for (j = 0; j < size; ++j) DC += left[j];
} else { // top, but no left
DC += DC;
}
DC = (DC + round) >> shift;
- } else if (left) { // left but no top
+ } else if (left != NULL) { // left but no top
for (j = 0; j < size; ++j) DC += left[j];
DC += DC;
DC = (DC + round) >> shift;
@@ -337,8 +312,8 @@ static void IntraChromaPreds(uint8_t* dst, const uint8_t* left,
TrueMotion(C8TM8 + dst, left, top, 8);
// V block
dst += 8;
- if (top) top += 8;
- if (left) left += 16;
+ if (top != NULL) top += 8;
+ if (left != NULL) left += 16;
DCMode(C8DC8 + dst, left, top, 8, 8, 4);
VerticalPred(C8VE8 + dst, top, 8);
HorizontalPred(C8HE8 + dst, left, 8);
@@ -359,6 +334,7 @@ static void Intra16Preds(uint8_t* dst,
//------------------------------------------------------------------------------
// luma 4x4 prediction
+#define DST(x, y) dst[(x) + (y) * BPS]
#define AVG3(a, b, c) (((a) + 2 * (b) + (c) + 2) >> 2)
#define AVG2(a, b) (((a) + (b) + 1) >> 1)
@@ -589,30 +565,30 @@ static int TTransform(const uint8_t* in, const uint16_t* w) {
int i;
// horizontal pass
for (i = 0; i < 4; ++i, in += BPS) {
- const int a0 = (in[0] + in[2]) << 2;
- const int a1 = (in[1] + in[3]) << 2;
- const int a2 = (in[1] - in[3]) << 2;
- const int a3 = (in[0] - in[2]) << 2;
- tmp[0 + i * 4] = a0 + a1 + (a0 != 0);
+ const int a0 = in[0] + in[2];
+ const int a1 = in[1] + in[3];
+ const int a2 = in[1] - in[3];
+ const int a3 = in[0] - in[2];
+ tmp[0 + i * 4] = a0 + a1;
tmp[1 + i * 4] = a3 + a2;
tmp[2 + i * 4] = a3 - a2;
tmp[3 + i * 4] = a0 - a1;
}
// vertical pass
for (i = 0; i < 4; ++i, ++w) {
- const int a0 = (tmp[0 + i] + tmp[8 + i]);
- const int a1 = (tmp[4 + i] + tmp[12+ i]);
- const int a2 = (tmp[4 + i] - tmp[12+ i]);
- const int a3 = (tmp[0 + i] - tmp[8 + i]);
+ const int a0 = tmp[0 + i] + tmp[8 + i];
+ const int a1 = tmp[4 + i] + tmp[12+ i];
+ const int a2 = tmp[4 + i] - tmp[12+ i];
+ const int a3 = tmp[0 + i] - tmp[8 + i];
const int b0 = a0 + a1;
const int b1 = a3 + a2;
const int b2 = a3 - a2;
const int b3 = a0 - a1;
- // abs((b + (b<0) + 3) >> 3) = (abs(b) + 3) >> 3
- sum += w[ 0] * ((abs(b0) + 3) >> 3);
- sum += w[ 4] * ((abs(b1) + 3) >> 3);
- sum += w[ 8] * ((abs(b2) + 3) >> 3);
- sum += w[12] * ((abs(b3) + 3) >> 3);
+
+ sum += w[ 0] * abs(b0);
+ sum += w[ 4] * abs(b1);
+ sum += w[ 8] * abs(b2);
+ sum += w[12] * abs(b3);
}
return sum;
}
@@ -621,7 +597,7 @@ static int Disto4x4(const uint8_t* const a, const uint8_t* const b,
const uint16_t* const w) {
const int sum1 = TTransform(a, w);
const int sum2 = TTransform(b, w);
- return (abs(sum2 - sum1) + 8) >> 4;
+ return abs(sum2 - sum1) >> 5;
}
static int Disto16x16(const uint8_t* const a, const uint8_t* const b,
@@ -646,21 +622,57 @@ static const uint8_t kZigzag[16] = {
// Simple quantization
static int QuantizeBlock(int16_t in[16], int16_t out[16],
- int n, const VP8Matrix* const mtx) {
+ const VP8Matrix* const mtx) {
int last = -1;
- for (; n < 16; ++n) {
+ int n;
+ for (n = 0; n < 16; ++n) {
+ const int j = kZigzag[n];
+ const int sign = (in[j] < 0);
+ const uint32_t coeff = (sign ? -in[j] : in[j]) + mtx->sharpen_[j];
+ if (coeff > mtx->zthresh_[j]) {
+ const uint32_t Q = mtx->q_[j];
+ const uint32_t iQ = mtx->iq_[j];
+ const uint32_t B = mtx->bias_[j];
+ int level = QUANTDIV(coeff, iQ, B);
+ if (level > MAX_LEVEL) level = MAX_LEVEL;
+ if (sign) level = -level;
+ in[j] = level * Q;
+ out[n] = level;
+ if (level) last = n;
+ } else {
+ out[n] = 0;
+ in[j] = 0;
+ }
+ }
+ return (last >= 0);
+}
+
+static int Quantize2Blocks(int16_t in[32], int16_t out[32],
+ const VP8Matrix* const mtx) {
+ int nz;
+ nz = VP8EncQuantizeBlock(in + 0 * 16, out + 0 * 16, mtx) << 0;
+ nz |= VP8EncQuantizeBlock(in + 1 * 16, out + 1 * 16, mtx) << 1;
+ return nz;
+}
+
+static int QuantizeBlockWHT(int16_t in[16], int16_t out[16],
+ const VP8Matrix* const mtx) {
+ int n, last = -1;
+ for (n = 0; n < 16; ++n) {
const int j = kZigzag[n];
const int sign = (in[j] < 0);
- int coeff = (sign ? -in[j] : in[j]) + mtx->sharpen_[j];
- if (coeff > 2047) coeff = 2047;
+ const uint32_t coeff = sign ? -in[j] : in[j];
+ assert(mtx->sharpen_[j] == 0);
if (coeff > mtx->zthresh_[j]) {
- const int Q = mtx->q_[j];
- const int iQ = mtx->iq_[j];
- const int B = mtx->bias_[j];
- out[n] = QUANTDIV(coeff, iQ, B);
- if (sign) out[n] = -out[n];
- in[j] = out[n] * Q;
- if (out[n]) last = n;
+ const uint32_t Q = mtx->q_[j];
+ const uint32_t iQ = mtx->iq_[j];
+ const uint32_t B = mtx->bias_[j];
+ int level = QUANTDIV(coeff, iQ, B);
+ if (level > MAX_LEVEL) level = MAX_LEVEL;
+ if (sign) level = -level;
+ in[j] = level * Q;
+ out[n] = level;
+ if (level) last = n;
} else {
out[n] = 0;
in[j] = 0;
@@ -672,16 +684,22 @@ static int QuantizeBlock(int16_t in[16], int16_t out[16],
//------------------------------------------------------------------------------
// Block copy
-static WEBP_INLINE void Copy(const uint8_t* src, uint8_t* dst, int size) {
+static WEBP_INLINE void Copy(const uint8_t* src, uint8_t* dst, int w, int h) {
int y;
- for (y = 0; y < size; ++y) {
- memcpy(dst, src, size);
+ for (y = 0; y < h; ++y) {
+ memcpy(dst, src, w);
src += BPS;
dst += BPS;
}
}
-static void Copy4x4(const uint8_t* src, uint8_t* dst) { Copy(src, dst, 4); }
+static void Copy4x4(const uint8_t* src, uint8_t* dst) {
+ Copy(src, dst, 4, 4);
+}
+
+static void Copy16x8(const uint8_t* src, uint8_t* dst) {
+ Copy(src, dst, 16, 8);
+}
//------------------------------------------------------------------------------
// Initialization
@@ -691,7 +709,7 @@ static void Copy4x4(const uint8_t* src, uint8_t* dst) { Copy(src, dst, 4); }
VP8CHisto VP8CollectHistogram;
VP8Idct VP8ITransform;
VP8Fdct VP8FTransform;
-VP8WHT VP8ITransformWHT;
+VP8Fdct VP8FTransform2;
VP8WHT VP8FTransformWHT;
VP8Intra4Preds VP8EncPredLuma4;
VP8IntraPreds VP8EncPredLuma16;
@@ -703,18 +721,32 @@ VP8Metric VP8SSE4x4;
VP8WMetric VP8TDisto4x4;
VP8WMetric VP8TDisto16x16;
VP8QuantizeBlock VP8EncQuantizeBlock;
+VP8Quantize2Blocks VP8EncQuantize2Blocks;
+VP8QuantizeBlockWHT VP8EncQuantizeBlockWHT;
VP8BlockCopy VP8Copy4x4;
+VP8BlockCopy VP8Copy16x8;
extern void VP8EncDspInitSSE2(void);
+extern void VP8EncDspInitSSE41(void);
+extern void VP8EncDspInitAVX2(void);
+extern void VP8EncDspInitNEON(void);
+extern void VP8EncDspInitMIPS32(void);
+extern void VP8EncDspInitMIPSdspR2(void);
+
+static volatile VP8CPUInfo enc_last_cpuinfo_used =
+ (VP8CPUInfo)&enc_last_cpuinfo_used;
-void VP8EncDspInit(void) {
+WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspInit(void) {
+ if (enc_last_cpuinfo_used == VP8GetCPUInfo) return;
+
+ VP8DspInit(); // common inverse transforms
InitTables();
// default C implementations
VP8CollectHistogram = CollectHistogram;
VP8ITransform = ITransform;
VP8FTransform = FTransform;
- VP8ITransformWHT = ITransformWHT;
+ VP8FTransform2 = FTransform2;
VP8FTransformWHT = FTransformWHT;
VP8EncPredLuma4 = Intra4Preds;
VP8EncPredLuma16 = Intra16Preds;
@@ -726,18 +758,43 @@ void VP8EncDspInit(void) {
VP8TDisto4x4 = Disto4x4;
VP8TDisto16x16 = Disto16x16;
VP8EncQuantizeBlock = QuantizeBlock;
+ VP8EncQuantize2Blocks = Quantize2Blocks;
+ VP8EncQuantizeBlockWHT = QuantizeBlockWHT;
VP8Copy4x4 = Copy4x4;
+ VP8Copy16x8 = Copy16x8;
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
- if (VP8GetCPUInfo) {
+ if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_USE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
VP8EncDspInitSSE2();
+#if defined(WEBP_USE_SSE41)
+ if (VP8GetCPUInfo(kSSE4_1)) {
+ VP8EncDspInitSSE41();
+ }
+#endif
+ }
+#endif
+#if defined(WEBP_USE_AVX2)
+ if (VP8GetCPUInfo(kAVX2)) {
+ VP8EncDspInitAVX2();
+ }
+#endif
+#if defined(WEBP_USE_NEON)
+ if (VP8GetCPUInfo(kNEON)) {
+ VP8EncDspInitNEON();
+ }
+#endif
+#if defined(WEBP_USE_MIPS32)
+ if (VP8GetCPUInfo(kMIPS32)) {
+ VP8EncDspInitMIPS32();
+ }
+#endif
+#if defined(WEBP_USE_MIPS_DSP_R2)
+ if (VP8GetCPUInfo(kMIPSdspR2)) {
+ VP8EncDspInitMIPSdspR2();
}
#endif
}
+ enc_last_cpuinfo_used = VP8GetCPUInfo;
}
-
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/dsp/enc_avx2.c b/drivers/webp/dsp/enc_avx2.c
new file mode 100644
index 0000000000..93efb30b10
--- /dev/null
+++ b/drivers/webp/dsp/enc_avx2.c
@@ -0,0 +1,21 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// AVX2 version of speed-critical encoding functions.
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_AVX2)
+
+#endif // WEBP_USE_AVX2
+
+//------------------------------------------------------------------------------
+// Entry point
+
+WEBP_DSP_INIT_STUB(VP8EncDspInitAVX2)
diff --git a/drivers/webp/dsp/enc_mips32.c b/drivers/webp/dsp/enc_mips32.c
new file mode 100644
index 0000000000..fd10143de9
--- /dev/null
+++ b/drivers/webp/dsp/enc_mips32.c
@@ -0,0 +1,672 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// MIPS version of speed-critical encoding functions.
+//
+// Author(s): Djordje Pesut (djordje.pesut@imgtec.com)
+// Jovan Zelincevic (jovan.zelincevic@imgtec.com)
+// Slobodan Prijic (slobodan.prijic@imgtec.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_MIPS32)
+
+#include "./mips_macro.h"
+#include "../enc/vp8enci.h"
+#include "../enc/cost.h"
+
+static const int kC1 = 20091 + (1 << 16);
+static const int kC2 = 35468;
+
+// macro for one vertical pass in ITransformOne
+// MUL macro inlined
+// temp0..temp15 holds tmp[0]..tmp[15]
+// A..D - offsets in bytes to load from in buffer
+// TEMP0..TEMP3 - registers for corresponding tmp elements
+// TEMP4..TEMP5 - temporary registers
+#define VERTICAL_PASS(A, B, C, D, TEMP4, TEMP0, TEMP1, TEMP2, TEMP3) \
+ "lh %[temp16], " #A "(%[temp20]) \n\t" \
+ "lh %[temp18], " #B "(%[temp20]) \n\t" \
+ "lh %[temp17], " #C "(%[temp20]) \n\t" \
+ "lh %[temp19], " #D "(%[temp20]) \n\t" \
+ "addu %[" #TEMP4 "], %[temp16], %[temp18] \n\t" \
+ "subu %[temp16], %[temp16], %[temp18] \n\t" \
+ "mul %[" #TEMP0 "], %[temp17], %[kC2] \n\t" \
+ "mul %[temp18], %[temp19], %[kC1] \n\t" \
+ "mul %[temp17], %[temp17], %[kC1] \n\t" \
+ "mul %[temp19], %[temp19], %[kC2] \n\t" \
+ "sra %[" #TEMP0 "], %[" #TEMP0 "], 16 \n\n" \
+ "sra %[temp18], %[temp18], 16 \n\n" \
+ "sra %[temp17], %[temp17], 16 \n\n" \
+ "sra %[temp19], %[temp19], 16 \n\n" \
+ "subu %[" #TEMP2 "], %[" #TEMP0 "], %[temp18] \n\t" \
+ "addu %[" #TEMP3 "], %[temp17], %[temp19] \n\t" \
+ "addu %[" #TEMP0 "], %[" #TEMP4 "], %[" #TEMP3 "] \n\t" \
+ "addu %[" #TEMP1 "], %[temp16], %[" #TEMP2 "] \n\t" \
+ "subu %[" #TEMP2 "], %[temp16], %[" #TEMP2 "] \n\t" \
+ "subu %[" #TEMP3 "], %[" #TEMP4 "], %[" #TEMP3 "] \n\t"
+
+// macro for one horizontal pass in ITransformOne
+// MUL and STORE macros inlined
+// a = clip_8b(a) is replaced with: a = max(a, 0); a = min(a, 255)
+// temp0..temp15 holds tmp[0]..tmp[15]
+// A - offset in bytes to load from ref and store to dst buffer
+// TEMP0, TEMP4, TEMP8 and TEMP12 - registers for corresponding tmp elements
+#define HORIZONTAL_PASS(A, TEMP0, TEMP4, TEMP8, TEMP12) \
+ "addiu %[" #TEMP0 "], %[" #TEMP0 "], 4 \n\t" \
+ "addu %[temp16], %[" #TEMP0 "], %[" #TEMP8 "] \n\t" \
+ "subu %[temp17], %[" #TEMP0 "], %[" #TEMP8 "] \n\t" \
+ "mul %[" #TEMP0 "], %[" #TEMP4 "], %[kC2] \n\t" \
+ "mul %[" #TEMP8 "], %[" #TEMP12 "], %[kC1] \n\t" \
+ "mul %[" #TEMP4 "], %[" #TEMP4 "], %[kC1] \n\t" \
+ "mul %[" #TEMP12 "], %[" #TEMP12 "], %[kC2] \n\t" \
+ "sra %[" #TEMP0 "], %[" #TEMP0 "], 16 \n\t" \
+ "sra %[" #TEMP8 "], %[" #TEMP8 "], 16 \n\t" \
+ "sra %[" #TEMP4 "], %[" #TEMP4 "], 16 \n\t" \
+ "sra %[" #TEMP12 "], %[" #TEMP12 "], 16 \n\t" \
+ "subu %[temp18], %[" #TEMP0 "], %[" #TEMP8 "] \n\t" \
+ "addu %[temp19], %[" #TEMP4 "], %[" #TEMP12 "] \n\t" \
+ "addu %[" #TEMP0 "], %[temp16], %[temp19] \n\t" \
+ "addu %[" #TEMP4 "], %[temp17], %[temp18] \n\t" \
+ "subu %[" #TEMP8 "], %[temp17], %[temp18] \n\t" \
+ "subu %[" #TEMP12 "], %[temp16], %[temp19] \n\t" \
+ "lw %[temp20], 0(%[args]) \n\t" \
+ "sra %[" #TEMP0 "], %[" #TEMP0 "], 3 \n\t" \
+ "sra %[" #TEMP4 "], %[" #TEMP4 "], 3 \n\t" \
+ "sra %[" #TEMP8 "], %[" #TEMP8 "], 3 \n\t" \
+ "sra %[" #TEMP12 "], %[" #TEMP12 "], 3 \n\t" \
+ "lbu %[temp16], 0+" XSTR(BPS) "*" #A "(%[temp20]) \n\t" \
+ "lbu %[temp17], 1+" XSTR(BPS) "*" #A "(%[temp20]) \n\t" \
+ "lbu %[temp18], 2+" XSTR(BPS) "*" #A "(%[temp20]) \n\t" \
+ "lbu %[temp19], 3+" XSTR(BPS) "*" #A "(%[temp20]) \n\t" \
+ "addu %[" #TEMP0 "], %[temp16], %[" #TEMP0 "] \n\t" \
+ "addu %[" #TEMP4 "], %[temp17], %[" #TEMP4 "] \n\t" \
+ "addu %[" #TEMP8 "], %[temp18], %[" #TEMP8 "] \n\t" \
+ "addu %[" #TEMP12 "], %[temp19], %[" #TEMP12 "] \n\t" \
+ "slt %[temp16], %[" #TEMP0 "], $zero \n\t" \
+ "slt %[temp17], %[" #TEMP4 "], $zero \n\t" \
+ "slt %[temp18], %[" #TEMP8 "], $zero \n\t" \
+ "slt %[temp19], %[" #TEMP12 "], $zero \n\t" \
+ "movn %[" #TEMP0 "], $zero, %[temp16] \n\t" \
+ "movn %[" #TEMP4 "], $zero, %[temp17] \n\t" \
+ "movn %[" #TEMP8 "], $zero, %[temp18] \n\t" \
+ "movn %[" #TEMP12 "], $zero, %[temp19] \n\t" \
+ "addiu %[temp20], $zero, 255 \n\t" \
+ "slt %[temp16], %[" #TEMP0 "], %[temp20] \n\t" \
+ "slt %[temp17], %[" #TEMP4 "], %[temp20] \n\t" \
+ "slt %[temp18], %[" #TEMP8 "], %[temp20] \n\t" \
+ "slt %[temp19], %[" #TEMP12 "], %[temp20] \n\t" \
+ "movz %[" #TEMP0 "], %[temp20], %[temp16] \n\t" \
+ "movz %[" #TEMP4 "], %[temp20], %[temp17] \n\t" \
+ "lw %[temp16], 8(%[args]) \n\t" \
+ "movz %[" #TEMP8 "], %[temp20], %[temp18] \n\t" \
+ "movz %[" #TEMP12 "], %[temp20], %[temp19] \n\t" \
+ "sb %[" #TEMP0 "], 0+" XSTR(BPS) "*" #A "(%[temp16]) \n\t" \
+ "sb %[" #TEMP4 "], 1+" XSTR(BPS) "*" #A "(%[temp16]) \n\t" \
+ "sb %[" #TEMP8 "], 2+" XSTR(BPS) "*" #A "(%[temp16]) \n\t" \
+ "sb %[" #TEMP12 "], 3+" XSTR(BPS) "*" #A "(%[temp16]) \n\t"
+
+// Does one or two inverse transforms.
+static WEBP_INLINE void ITransformOne(const uint8_t* ref, const int16_t* in,
+ uint8_t* dst) {
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6;
+ int temp7, temp8, temp9, temp10, temp11, temp12, temp13;
+ int temp14, temp15, temp16, temp17, temp18, temp19, temp20;
+ const int* args[3] = {(const int*)ref, (const int*)in, (const int*)dst};
+
+ __asm__ volatile(
+ "lw %[temp20], 4(%[args]) \n\t"
+ VERTICAL_PASS(0, 16, 8, 24, temp4, temp0, temp1, temp2, temp3)
+ VERTICAL_PASS(2, 18, 10, 26, temp8, temp4, temp5, temp6, temp7)
+ VERTICAL_PASS(4, 20, 12, 28, temp12, temp8, temp9, temp10, temp11)
+ VERTICAL_PASS(6, 22, 14, 30, temp20, temp12, temp13, temp14, temp15)
+
+ HORIZONTAL_PASS(0, temp0, temp4, temp8, temp12)
+ HORIZONTAL_PASS(1, temp1, temp5, temp9, temp13)
+ HORIZONTAL_PASS(2, temp2, temp6, temp10, temp14)
+ HORIZONTAL_PASS(3, temp3, temp7, temp11, temp15)
+
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8),
+ [temp9]"=&r"(temp9), [temp10]"=&r"(temp10), [temp11]"=&r"(temp11),
+ [temp12]"=&r"(temp12), [temp13]"=&r"(temp13), [temp14]"=&r"(temp14),
+ [temp15]"=&r"(temp15), [temp16]"=&r"(temp16), [temp17]"=&r"(temp17),
+ [temp18]"=&r"(temp18), [temp19]"=&r"(temp19), [temp20]"=&r"(temp20)
+ : [args]"r"(args), [kC1]"r"(kC1), [kC2]"r"(kC2)
+ : "memory", "hi", "lo"
+ );
+}
+
+static void ITransform(const uint8_t* ref, const int16_t* in,
+ uint8_t* dst, int do_two) {
+ ITransformOne(ref, in, dst);
+ if (do_two) {
+ ITransformOne(ref + 4, in + 16, dst + 4);
+ }
+}
+
+#undef VERTICAL_PASS
+#undef HORIZONTAL_PASS
+
+// macro for one pass through for loop in QuantizeBlock
+// QUANTDIV macro inlined
+// J - offset in bytes (kZigzag[n] * 2)
+// K - offset in bytes (kZigzag[n] * 4)
+// N - offset in bytes (n * 2)
+#define QUANTIZE_ONE(J, K, N) \
+ "lh %[temp0], " #J "(%[ppin]) \n\t" \
+ "lhu %[temp1], " #J "(%[ppsharpen]) \n\t" \
+ "lw %[temp2], " #K "(%[ppzthresh]) \n\t" \
+ "sra %[sign], %[temp0], 15 \n\t" \
+ "xor %[coeff], %[temp0], %[sign] \n\t" \
+ "subu %[coeff], %[coeff], %[sign] \n\t" \
+ "addu %[coeff], %[coeff], %[temp1] \n\t" \
+ "slt %[temp4], %[temp2], %[coeff] \n\t" \
+ "addiu %[temp5], $zero, 0 \n\t" \
+ "addiu %[level], $zero, 0 \n\t" \
+ "beqz %[temp4], 2f \n\t" \
+ "lhu %[temp1], " #J "(%[ppiq]) \n\t" \
+ "lw %[temp2], " #K "(%[ppbias]) \n\t" \
+ "lhu %[temp3], " #J "(%[ppq]) \n\t" \
+ "mul %[level], %[coeff], %[temp1] \n\t" \
+ "addu %[level], %[level], %[temp2] \n\t" \
+ "sra %[level], %[level], 17 \n\t" \
+ "slt %[temp4], %[max_level], %[level] \n\t" \
+ "movn %[level], %[max_level], %[temp4] \n\t" \
+ "xor %[level], %[level], %[sign] \n\t" \
+ "subu %[level], %[level], %[sign] \n\t" \
+ "mul %[temp5], %[level], %[temp3] \n\t" \
+"2: \n\t" \
+ "sh %[temp5], " #J "(%[ppin]) \n\t" \
+ "sh %[level], " #N "(%[pout]) \n\t"
+
+static int QuantizeBlock(int16_t in[16], int16_t out[16],
+ const VP8Matrix* const mtx) {
+ int temp0, temp1, temp2, temp3, temp4, temp5;
+ int sign, coeff, level, i;
+ int max_level = MAX_LEVEL;
+
+ int16_t* ppin = &in[0];
+ int16_t* pout = &out[0];
+ const uint16_t* ppsharpen = &mtx->sharpen_[0];
+ const uint32_t* ppzthresh = &mtx->zthresh_[0];
+ const uint16_t* ppq = &mtx->q_[0];
+ const uint16_t* ppiq = &mtx->iq_[0];
+ const uint32_t* ppbias = &mtx->bias_[0];
+
+ __asm__ volatile(
+ QUANTIZE_ONE( 0, 0, 0)
+ QUANTIZE_ONE( 2, 4, 2)
+ QUANTIZE_ONE( 8, 16, 4)
+ QUANTIZE_ONE(16, 32, 6)
+ QUANTIZE_ONE(10, 20, 8)
+ QUANTIZE_ONE( 4, 8, 10)
+ QUANTIZE_ONE( 6, 12, 12)
+ QUANTIZE_ONE(12, 24, 14)
+ QUANTIZE_ONE(18, 36, 16)
+ QUANTIZE_ONE(24, 48, 18)
+ QUANTIZE_ONE(26, 52, 20)
+ QUANTIZE_ONE(20, 40, 22)
+ QUANTIZE_ONE(14, 28, 24)
+ QUANTIZE_ONE(22, 44, 26)
+ QUANTIZE_ONE(28, 56, 28)
+ QUANTIZE_ONE(30, 60, 30)
+
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [sign]"=&r"(sign), [coeff]"=&r"(coeff),
+ [level]"=&r"(level)
+ : [pout]"r"(pout), [ppin]"r"(ppin),
+ [ppiq]"r"(ppiq), [max_level]"r"(max_level),
+ [ppbias]"r"(ppbias), [ppzthresh]"r"(ppzthresh),
+ [ppsharpen]"r"(ppsharpen), [ppq]"r"(ppq)
+ : "memory", "hi", "lo"
+ );
+
+ // moved out from macro to increase possibility for earlier breaking
+ for (i = 15; i >= 0; i--) {
+ if (out[i]) return 1;
+ }
+ return 0;
+}
+
+static int Quantize2Blocks(int16_t in[32], int16_t out[32],
+ const VP8Matrix* const mtx) {
+ int nz;
+ nz = QuantizeBlock(in + 0 * 16, out + 0 * 16, mtx) << 0;
+ nz |= QuantizeBlock(in + 1 * 16, out + 1 * 16, mtx) << 1;
+ return nz;
+}
+
+#undef QUANTIZE_ONE
+
+// macro for one horizontal pass in Disto4x4 (TTransform)
+// two calls of function TTransform are merged into single one
+// A - offset in bytes to load from a and b buffers
+// E..H - offsets in bytes to store first results to tmp buffer
+// E1..H1 - offsets in bytes to store second results to tmp buffer
+#define HORIZONTAL_PASS(A, E, F, G, H, E1, F1, G1, H1) \
+ "lbu %[temp0], 0+" XSTR(BPS) "*" #A "(%[a]) \n\t" \
+ "lbu %[temp1], 1+" XSTR(BPS) "*" #A "(%[a]) \n\t" \
+ "lbu %[temp2], 2+" XSTR(BPS) "*" #A "(%[a]) \n\t" \
+ "lbu %[temp3], 3+" XSTR(BPS) "*" #A "(%[a]) \n\t" \
+ "lbu %[temp4], 0+" XSTR(BPS) "*" #A "(%[b]) \n\t" \
+ "lbu %[temp5], 1+" XSTR(BPS) "*" #A "(%[b]) \n\t" \
+ "lbu %[temp6], 2+" XSTR(BPS) "*" #A "(%[b]) \n\t" \
+ "lbu %[temp7], 3+" XSTR(BPS) "*" #A "(%[b]) \n\t" \
+ "addu %[temp8], %[temp0], %[temp2] \n\t" \
+ "subu %[temp0], %[temp0], %[temp2] \n\t" \
+ "addu %[temp2], %[temp1], %[temp3] \n\t" \
+ "subu %[temp1], %[temp1], %[temp3] \n\t" \
+ "addu %[temp3], %[temp4], %[temp6] \n\t" \
+ "subu %[temp4], %[temp4], %[temp6] \n\t" \
+ "addu %[temp6], %[temp5], %[temp7] \n\t" \
+ "subu %[temp5], %[temp5], %[temp7] \n\t" \
+ "addu %[temp7], %[temp8], %[temp2] \n\t" \
+ "subu %[temp2], %[temp8], %[temp2] \n\t" \
+ "addu %[temp8], %[temp0], %[temp1] \n\t" \
+ "subu %[temp0], %[temp0], %[temp1] \n\t" \
+ "addu %[temp1], %[temp3], %[temp6] \n\t" \
+ "subu %[temp3], %[temp3], %[temp6] \n\t" \
+ "addu %[temp6], %[temp4], %[temp5] \n\t" \
+ "subu %[temp4], %[temp4], %[temp5] \n\t" \
+ "sw %[temp7], " #E "(%[tmp]) \n\t" \
+ "sw %[temp2], " #H "(%[tmp]) \n\t" \
+ "sw %[temp8], " #F "(%[tmp]) \n\t" \
+ "sw %[temp0], " #G "(%[tmp]) \n\t" \
+ "sw %[temp1], " #E1 "(%[tmp]) \n\t" \
+ "sw %[temp3], " #H1 "(%[tmp]) \n\t" \
+ "sw %[temp6], " #F1 "(%[tmp]) \n\t" \
+ "sw %[temp4], " #G1 "(%[tmp]) \n\t"
+
+// macro for one vertical pass in Disto4x4 (TTransform)
+// two calls of function TTransform are merged into single one
+// since only one accu is available in mips32r1 instruction set
+// first is done second call of function TTransform and after
+// that first one.
+// const int sum1 = TTransform(a, w);
+// const int sum2 = TTransform(b, w);
+// return abs(sum2 - sum1) >> 5;
+// (sum2 - sum1) is calculated with madds (sub2) and msubs (sub1)
+// A..D - offsets in bytes to load first results from tmp buffer
+// A1..D1 - offsets in bytes to load second results from tmp buffer
+// E..H - offsets in bytes to load from w buffer
+#define VERTICAL_PASS(A, B, C, D, A1, B1, C1, D1, E, F, G, H) \
+ "lw %[temp0], " #A1 "(%[tmp]) \n\t" \
+ "lw %[temp1], " #C1 "(%[tmp]) \n\t" \
+ "lw %[temp2], " #B1 "(%[tmp]) \n\t" \
+ "lw %[temp3], " #D1 "(%[tmp]) \n\t" \
+ "addu %[temp8], %[temp0], %[temp1] \n\t" \
+ "subu %[temp0], %[temp0], %[temp1] \n\t" \
+ "addu %[temp1], %[temp2], %[temp3] \n\t" \
+ "subu %[temp2], %[temp2], %[temp3] \n\t" \
+ "addu %[temp3], %[temp8], %[temp1] \n\t" \
+ "subu %[temp8], %[temp8], %[temp1] \n\t" \
+ "addu %[temp1], %[temp0], %[temp2] \n\t" \
+ "subu %[temp0], %[temp0], %[temp2] \n\t" \
+ "sra %[temp4], %[temp3], 31 \n\t" \
+ "sra %[temp5], %[temp1], 31 \n\t" \
+ "sra %[temp6], %[temp0], 31 \n\t" \
+ "sra %[temp7], %[temp8], 31 \n\t" \
+ "xor %[temp3], %[temp3], %[temp4] \n\t" \
+ "xor %[temp1], %[temp1], %[temp5] \n\t" \
+ "xor %[temp0], %[temp0], %[temp6] \n\t" \
+ "xor %[temp8], %[temp8], %[temp7] \n\t" \
+ "subu %[temp3], %[temp3], %[temp4] \n\t" \
+ "subu %[temp1], %[temp1], %[temp5] \n\t" \
+ "subu %[temp0], %[temp0], %[temp6] \n\t" \
+ "subu %[temp8], %[temp8], %[temp7] \n\t" \
+ "lhu %[temp4], " #E "(%[w]) \n\t" \
+ "lhu %[temp5], " #F "(%[w]) \n\t" \
+ "lhu %[temp6], " #G "(%[w]) \n\t" \
+ "lhu %[temp7], " #H "(%[w]) \n\t" \
+ "madd %[temp4], %[temp3] \n\t" \
+ "madd %[temp5], %[temp1] \n\t" \
+ "madd %[temp6], %[temp0] \n\t" \
+ "madd %[temp7], %[temp8] \n\t" \
+ "lw %[temp0], " #A "(%[tmp]) \n\t" \
+ "lw %[temp1], " #C "(%[tmp]) \n\t" \
+ "lw %[temp2], " #B "(%[tmp]) \n\t" \
+ "lw %[temp3], " #D "(%[tmp]) \n\t" \
+ "addu %[temp8], %[temp0], %[temp1] \n\t" \
+ "subu %[temp0], %[temp0], %[temp1] \n\t" \
+ "addu %[temp1], %[temp2], %[temp3] \n\t" \
+ "subu %[temp2], %[temp2], %[temp3] \n\t" \
+ "addu %[temp3], %[temp8], %[temp1] \n\t" \
+ "subu %[temp1], %[temp8], %[temp1] \n\t" \
+ "addu %[temp8], %[temp0], %[temp2] \n\t" \
+ "subu %[temp0], %[temp0], %[temp2] \n\t" \
+ "sra %[temp2], %[temp3], 31 \n\t" \
+ "xor %[temp3], %[temp3], %[temp2] \n\t" \
+ "subu %[temp3], %[temp3], %[temp2] \n\t" \
+ "msub %[temp4], %[temp3] \n\t" \
+ "sra %[temp2], %[temp8], 31 \n\t" \
+ "sra %[temp3], %[temp0], 31 \n\t" \
+ "sra %[temp4], %[temp1], 31 \n\t" \
+ "xor %[temp8], %[temp8], %[temp2] \n\t" \
+ "xor %[temp0], %[temp0], %[temp3] \n\t" \
+ "xor %[temp1], %[temp1], %[temp4] \n\t" \
+ "subu %[temp8], %[temp8], %[temp2] \n\t" \
+ "subu %[temp0], %[temp0], %[temp3] \n\t" \
+ "subu %[temp1], %[temp1], %[temp4] \n\t" \
+ "msub %[temp5], %[temp8] \n\t" \
+ "msub %[temp6], %[temp0] \n\t" \
+ "msub %[temp7], %[temp1] \n\t"
+
+static int Disto4x4(const uint8_t* const a, const uint8_t* const b,
+ const uint16_t* const w) {
+ int tmp[32];
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8;
+
+ __asm__ volatile(
+ HORIZONTAL_PASS(0, 0, 4, 8, 12, 64, 68, 72, 76)
+ HORIZONTAL_PASS(1, 16, 20, 24, 28, 80, 84, 88, 92)
+ HORIZONTAL_PASS(2, 32, 36, 40, 44, 96, 100, 104, 108)
+ HORIZONTAL_PASS(3, 48, 52, 56, 60, 112, 116, 120, 124)
+ "mthi $zero \n\t"
+ "mtlo $zero \n\t"
+ VERTICAL_PASS( 0, 16, 32, 48, 64, 80, 96, 112, 0, 8, 16, 24)
+ VERTICAL_PASS( 4, 20, 36, 52, 68, 84, 100, 116, 2, 10, 18, 26)
+ VERTICAL_PASS( 8, 24, 40, 56, 72, 88, 104, 120, 4, 12, 20, 28)
+ VERTICAL_PASS(12, 28, 44, 60, 76, 92, 108, 124, 6, 14, 22, 30)
+ "mflo %[temp0] \n\t"
+ "sra %[temp1], %[temp0], 31 \n\t"
+ "xor %[temp0], %[temp0], %[temp1] \n\t"
+ "subu %[temp0], %[temp0], %[temp1] \n\t"
+ "sra %[temp0], %[temp0], 5 \n\t"
+
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8)
+ : [a]"r"(a), [b]"r"(b), [w]"r"(w), [tmp]"r"(tmp)
+ : "memory", "hi", "lo"
+ );
+
+ return temp0;
+}
+
+#undef VERTICAL_PASS
+#undef HORIZONTAL_PASS
+
+static int Disto16x16(const uint8_t* const a, const uint8_t* const b,
+ const uint16_t* const w) {
+ int D = 0;
+ int x, y;
+ for (y = 0; y < 16 * BPS; y += 4 * BPS) {
+ for (x = 0; x < 16; x += 4) {
+ D += Disto4x4(a + x + y, b + x + y, w);
+ }
+ }
+ return D;
+}
+
+// macro for one horizontal pass in FTransform
+// temp0..temp15 holds tmp[0]..tmp[15]
+// A - offset in bytes to load from src and ref buffers
+// TEMP0..TEMP3 - registers for corresponding tmp elements
+#define HORIZONTAL_PASS(A, TEMP0, TEMP1, TEMP2, TEMP3) \
+ "lw %[" #TEMP1 "], 0(%[args]) \n\t" \
+ "lw %[" #TEMP2 "], 4(%[args]) \n\t" \
+ "lbu %[temp16], 0+" XSTR(BPS) "*" #A "(%[" #TEMP1 "]) \n\t" \
+ "lbu %[temp17], 0+" XSTR(BPS) "*" #A "(%[" #TEMP2 "]) \n\t" \
+ "lbu %[temp18], 1+" XSTR(BPS) "*" #A "(%[" #TEMP1 "]) \n\t" \
+ "lbu %[temp19], 1+" XSTR(BPS) "*" #A "(%[" #TEMP2 "]) \n\t" \
+ "subu %[temp20], %[temp16], %[temp17] \n\t" \
+ "lbu %[temp16], 2+" XSTR(BPS) "*" #A "(%[" #TEMP1 "]) \n\t" \
+ "lbu %[temp17], 2+" XSTR(BPS) "*" #A "(%[" #TEMP2 "]) \n\t" \
+ "subu %[" #TEMP0 "], %[temp18], %[temp19] \n\t" \
+ "lbu %[temp18], 3+" XSTR(BPS) "*" #A "(%[" #TEMP1 "]) \n\t" \
+ "lbu %[temp19], 3+" XSTR(BPS) "*" #A "(%[" #TEMP2 "]) \n\t" \
+ "subu %[" #TEMP1 "], %[temp16], %[temp17] \n\t" \
+ "subu %[" #TEMP2 "], %[temp18], %[temp19] \n\t" \
+ "addu %[" #TEMP3 "], %[temp20], %[" #TEMP2 "] \n\t" \
+ "subu %[" #TEMP2 "], %[temp20], %[" #TEMP2 "] \n\t" \
+ "addu %[temp20], %[" #TEMP0 "], %[" #TEMP1 "] \n\t" \
+ "subu %[" #TEMP0 "], %[" #TEMP0 "], %[" #TEMP1 "] \n\t" \
+ "mul %[temp16], %[" #TEMP2 "], %[c5352] \n\t" \
+ "mul %[temp17], %[" #TEMP2 "], %[c2217] \n\t" \
+ "mul %[temp18], %[" #TEMP0 "], %[c5352] \n\t" \
+ "mul %[temp19], %[" #TEMP0 "], %[c2217] \n\t" \
+ "addu %[" #TEMP1 "], %[" #TEMP3 "], %[temp20] \n\t" \
+ "subu %[temp20], %[" #TEMP3 "], %[temp20] \n\t" \
+ "sll %[" #TEMP0 "], %[" #TEMP1 "], 3 \n\t" \
+ "sll %[" #TEMP2 "], %[temp20], 3 \n\t" \
+ "addiu %[temp16], %[temp16], 1812 \n\t" \
+ "addiu %[temp17], %[temp17], 937 \n\t" \
+ "addu %[temp16], %[temp16], %[temp19] \n\t" \
+ "subu %[temp17], %[temp17], %[temp18] \n\t" \
+ "sra %[" #TEMP1 "], %[temp16], 9 \n\t" \
+ "sra %[" #TEMP3 "], %[temp17], 9 \n\t"
+
+// macro for one vertical pass in FTransform
+// temp0..temp15 holds tmp[0]..tmp[15]
+// A..D - offsets in bytes to store to out buffer
+// TEMP0, TEMP4, TEMP8 and TEMP12 - registers for corresponding tmp elements
+#define VERTICAL_PASS(A, B, C, D, TEMP0, TEMP4, TEMP8, TEMP12) \
+ "addu %[temp16], %[" #TEMP0 "], %[" #TEMP12 "] \n\t" \
+ "subu %[temp19], %[" #TEMP0 "], %[" #TEMP12 "] \n\t" \
+ "addu %[temp17], %[" #TEMP4 "], %[" #TEMP8 "] \n\t" \
+ "subu %[temp18], %[" #TEMP4 "], %[" #TEMP8 "] \n\t" \
+ "mul %[" #TEMP8 "], %[temp19], %[c2217] \n\t" \
+ "mul %[" #TEMP12 "], %[temp18], %[c2217] \n\t" \
+ "mul %[" #TEMP4 "], %[temp19], %[c5352] \n\t" \
+ "mul %[temp18], %[temp18], %[c5352] \n\t" \
+ "addiu %[temp16], %[temp16], 7 \n\t" \
+ "addu %[" #TEMP0 "], %[temp16], %[temp17] \n\t" \
+ "sra %[" #TEMP0 "], %[" #TEMP0 "], 4 \n\t" \
+ "addu %[" #TEMP12 "], %[" #TEMP12 "], %[" #TEMP4 "] \n\t" \
+ "subu %[" #TEMP4 "], %[temp16], %[temp17] \n\t" \
+ "sra %[" #TEMP4 "], %[" #TEMP4 "], 4 \n\t" \
+ "addiu %[" #TEMP8 "], %[" #TEMP8 "], 30000 \n\t" \
+ "addiu %[" #TEMP12 "], %[" #TEMP12 "], 12000 \n\t" \
+ "addiu %[" #TEMP8 "], %[" #TEMP8 "], 21000 \n\t" \
+ "subu %[" #TEMP8 "], %[" #TEMP8 "], %[temp18] \n\t" \
+ "sra %[" #TEMP12 "], %[" #TEMP12 "], 16 \n\t" \
+ "sra %[" #TEMP8 "], %[" #TEMP8 "], 16 \n\t" \
+ "addiu %[temp16], %[" #TEMP12 "], 1 \n\t" \
+ "movn %[" #TEMP12 "], %[temp16], %[temp19] \n\t" \
+ "sh %[" #TEMP0 "], " #A "(%[temp20]) \n\t" \
+ "sh %[" #TEMP4 "], " #C "(%[temp20]) \n\t" \
+ "sh %[" #TEMP8 "], " #D "(%[temp20]) \n\t" \
+ "sh %[" #TEMP12 "], " #B "(%[temp20]) \n\t"
+
+static void FTransform(const uint8_t* src, const uint8_t* ref, int16_t* out) {
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8;
+ int temp9, temp10, temp11, temp12, temp13, temp14, temp15, temp16;
+ int temp17, temp18, temp19, temp20;
+ const int c2217 = 2217;
+ const int c5352 = 5352;
+ const int* const args[3] =
+ { (const int*)src, (const int*)ref, (const int*)out };
+
+ __asm__ volatile(
+ HORIZONTAL_PASS(0, temp0, temp1, temp2, temp3)
+ HORIZONTAL_PASS(1, temp4, temp5, temp6, temp7)
+ HORIZONTAL_PASS(2, temp8, temp9, temp10, temp11)
+ HORIZONTAL_PASS(3, temp12, temp13, temp14, temp15)
+ "lw %[temp20], 8(%[args]) \n\t"
+ VERTICAL_PASS(0, 8, 16, 24, temp0, temp4, temp8, temp12)
+ VERTICAL_PASS(2, 10, 18, 26, temp1, temp5, temp9, temp13)
+ VERTICAL_PASS(4, 12, 20, 28, temp2, temp6, temp10, temp14)
+ VERTICAL_PASS(6, 14, 22, 30, temp3, temp7, temp11, temp15)
+
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8),
+ [temp9]"=&r"(temp9), [temp10]"=&r"(temp10), [temp11]"=&r"(temp11),
+ [temp12]"=&r"(temp12), [temp13]"=&r"(temp13), [temp14]"=&r"(temp14),
+ [temp15]"=&r"(temp15), [temp16]"=&r"(temp16), [temp17]"=&r"(temp17),
+ [temp18]"=&r"(temp18), [temp19]"=&r"(temp19), [temp20]"=&r"(temp20)
+ : [args]"r"(args), [c2217]"r"(c2217), [c5352]"r"(c5352)
+ : "memory", "hi", "lo"
+ );
+}
+
+#undef VERTICAL_PASS
+#undef HORIZONTAL_PASS
+
+#if !defined(WORK_AROUND_GCC)
+
+#define GET_SSE_INNER(A, B, C, D) \
+ "lbu %[temp0], " #A "(%[a]) \n\t" \
+ "lbu %[temp1], " #A "(%[b]) \n\t" \
+ "lbu %[temp2], " #B "(%[a]) \n\t" \
+ "lbu %[temp3], " #B "(%[b]) \n\t" \
+ "lbu %[temp4], " #C "(%[a]) \n\t" \
+ "lbu %[temp5], " #C "(%[b]) \n\t" \
+ "lbu %[temp6], " #D "(%[a]) \n\t" \
+ "lbu %[temp7], " #D "(%[b]) \n\t" \
+ "subu %[temp0], %[temp0], %[temp1] \n\t" \
+ "subu %[temp2], %[temp2], %[temp3] \n\t" \
+ "subu %[temp4], %[temp4], %[temp5] \n\t" \
+ "subu %[temp6], %[temp6], %[temp7] \n\t" \
+ "madd %[temp0], %[temp0] \n\t" \
+ "madd %[temp2], %[temp2] \n\t" \
+ "madd %[temp4], %[temp4] \n\t" \
+ "madd %[temp6], %[temp6] \n\t"
+
+#define GET_SSE(A, B, C, D) \
+ GET_SSE_INNER(A, A + 1, A + 2, A + 3) \
+ GET_SSE_INNER(B, B + 1, B + 2, B + 3) \
+ GET_SSE_INNER(C, C + 1, C + 2, C + 3) \
+ GET_SSE_INNER(D, D + 1, D + 2, D + 3)
+
+static int SSE16x16(const uint8_t* a, const uint8_t* b) {
+ int count;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+
+ __asm__ volatile(
+ "mult $zero, $zero \n\t"
+
+ GET_SSE( 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS)
+ GET_SSE( 1 * BPS, 4 + 1 * BPS, 8 + 1 * BPS, 12 + 1 * BPS)
+ GET_SSE( 2 * BPS, 4 + 2 * BPS, 8 + 2 * BPS, 12 + 2 * BPS)
+ GET_SSE( 3 * BPS, 4 + 3 * BPS, 8 + 3 * BPS, 12 + 3 * BPS)
+ GET_SSE( 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS)
+ GET_SSE( 5 * BPS, 4 + 5 * BPS, 8 + 5 * BPS, 12 + 5 * BPS)
+ GET_SSE( 6 * BPS, 4 + 6 * BPS, 8 + 6 * BPS, 12 + 6 * BPS)
+ GET_SSE( 7 * BPS, 4 + 7 * BPS, 8 + 7 * BPS, 12 + 7 * BPS)
+ GET_SSE( 8 * BPS, 4 + 8 * BPS, 8 + 8 * BPS, 12 + 8 * BPS)
+ GET_SSE( 9 * BPS, 4 + 9 * BPS, 8 + 9 * BPS, 12 + 9 * BPS)
+ GET_SSE(10 * BPS, 4 + 10 * BPS, 8 + 10 * BPS, 12 + 10 * BPS)
+ GET_SSE(11 * BPS, 4 + 11 * BPS, 8 + 11 * BPS, 12 + 11 * BPS)
+ GET_SSE(12 * BPS, 4 + 12 * BPS, 8 + 12 * BPS, 12 + 12 * BPS)
+ GET_SSE(13 * BPS, 4 + 13 * BPS, 8 + 13 * BPS, 12 + 13 * BPS)
+ GET_SSE(14 * BPS, 4 + 14 * BPS, 8 + 14 * BPS, 12 + 14 * BPS)
+ GET_SSE(15 * BPS, 4 + 15 * BPS, 8 + 15 * BPS, 12 + 15 * BPS)
+
+ "mflo %[count] \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [count]"=&r"(count)
+ : [a]"r"(a), [b]"r"(b)
+ : "memory", "hi", "lo"
+ );
+ return count;
+}
+
+static int SSE16x8(const uint8_t* a, const uint8_t* b) {
+ int count;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+
+ __asm__ volatile(
+ "mult $zero, $zero \n\t"
+
+ GET_SSE( 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS)
+ GET_SSE( 1 * BPS, 4 + 1 * BPS, 8 + 1 * BPS, 12 + 1 * BPS)
+ GET_SSE( 2 * BPS, 4 + 2 * BPS, 8 + 2 * BPS, 12 + 2 * BPS)
+ GET_SSE( 3 * BPS, 4 + 3 * BPS, 8 + 3 * BPS, 12 + 3 * BPS)
+ GET_SSE( 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS)
+ GET_SSE( 5 * BPS, 4 + 5 * BPS, 8 + 5 * BPS, 12 + 5 * BPS)
+ GET_SSE( 6 * BPS, 4 + 6 * BPS, 8 + 6 * BPS, 12 + 6 * BPS)
+ GET_SSE( 7 * BPS, 4 + 7 * BPS, 8 + 7 * BPS, 12 + 7 * BPS)
+
+ "mflo %[count] \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [count]"=&r"(count)
+ : [a]"r"(a), [b]"r"(b)
+ : "memory", "hi", "lo"
+ );
+ return count;
+}
+
+static int SSE8x8(const uint8_t* a, const uint8_t* b) {
+ int count;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+
+ __asm__ volatile(
+ "mult $zero, $zero \n\t"
+
+ GET_SSE(0 * BPS, 4 + 0 * BPS, 1 * BPS, 4 + 1 * BPS)
+ GET_SSE(2 * BPS, 4 + 2 * BPS, 3 * BPS, 4 + 3 * BPS)
+ GET_SSE(4 * BPS, 4 + 4 * BPS, 5 * BPS, 4 + 5 * BPS)
+ GET_SSE(6 * BPS, 4 + 6 * BPS, 7 * BPS, 4 + 7 * BPS)
+
+ "mflo %[count] \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [count]"=&r"(count)
+ : [a]"r"(a), [b]"r"(b)
+ : "memory", "hi", "lo"
+ );
+ return count;
+}
+
+static int SSE4x4(const uint8_t* a, const uint8_t* b) {
+ int count;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+
+ __asm__ volatile(
+ "mult $zero, $zero \n\t"
+
+ GET_SSE(0 * BPS, 1 * BPS, 2 * BPS, 3 * BPS)
+
+ "mflo %[count] \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [count]"=&r"(count)
+ : [a]"r"(a), [b]"r"(b)
+ : "memory", "hi", "lo"
+ );
+ return count;
+}
+
+#undef GET_SSE
+#undef GET_SSE_INNER
+
+#endif // !WORK_AROUND_GCC
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8EncDspInitMIPS32(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspInitMIPS32(void) {
+ VP8ITransform = ITransform;
+ VP8FTransform = FTransform;
+ VP8EncQuantizeBlock = QuantizeBlock;
+ VP8EncQuantize2Blocks = Quantize2Blocks;
+ VP8TDisto4x4 = Disto4x4;
+ VP8TDisto16x16 = Disto16x16;
+#if !defined(WORK_AROUND_GCC)
+ VP8SSE16x16 = SSE16x16;
+ VP8SSE8x8 = SSE8x8;
+ VP8SSE16x8 = SSE16x8;
+ VP8SSE4x4 = SSE4x4;
+#endif
+}
+
+#else // !WEBP_USE_MIPS32
+
+WEBP_DSP_INIT_STUB(VP8EncDspInitMIPS32)
+
+#endif // WEBP_USE_MIPS32
diff --git a/drivers/webp/dsp/enc_mips_dsp_r2.c b/drivers/webp/dsp/enc_mips_dsp_r2.c
new file mode 100644
index 0000000000..7c814fa04a
--- /dev/null
+++ b/drivers/webp/dsp/enc_mips_dsp_r2.c
@@ -0,0 +1,1512 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// MIPS version of speed-critical encoding functions.
+//
+// Author(s): Darko Laus (darko.laus@imgtec.com)
+// Mirko Raus (mirko.raus@imgtec.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_MIPS_DSP_R2)
+
+#include "./mips_macro.h"
+#include "../enc/cost.h"
+#include "../enc/vp8enci.h"
+
+static const int kC1 = 20091 + (1 << 16);
+static const int kC2 = 35468;
+
+// O - output
+// I - input (macro doesn't change it)
+#define ADD_SUB_HALVES_X4(O0, O1, O2, O3, O4, O5, O6, O7, \
+ I0, I1, I2, I3, I4, I5, I6, I7) \
+ "addq.ph %[" #O0 "], %[" #I0 "], %[" #I1 "] \n\t" \
+ "subq.ph %[" #O1 "], %[" #I0 "], %[" #I1 "] \n\t" \
+ "addq.ph %[" #O2 "], %[" #I2 "], %[" #I3 "] \n\t" \
+ "subq.ph %[" #O3 "], %[" #I2 "], %[" #I3 "] \n\t" \
+ "addq.ph %[" #O4 "], %[" #I4 "], %[" #I5 "] \n\t" \
+ "subq.ph %[" #O5 "], %[" #I4 "], %[" #I5 "] \n\t" \
+ "addq.ph %[" #O6 "], %[" #I6 "], %[" #I7 "] \n\t" \
+ "subq.ph %[" #O7 "], %[" #I6 "], %[" #I7 "] \n\t"
+
+// IO - input/output
+#define ABS_X8(IO0, IO1, IO2, IO3, IO4, IO5, IO6, IO7) \
+ "absq_s.ph %[" #IO0 "], %[" #IO0 "] \n\t" \
+ "absq_s.ph %[" #IO1 "], %[" #IO1 "] \n\t" \
+ "absq_s.ph %[" #IO2 "], %[" #IO2 "] \n\t" \
+ "absq_s.ph %[" #IO3 "], %[" #IO3 "] \n\t" \
+ "absq_s.ph %[" #IO4 "], %[" #IO4 "] \n\t" \
+ "absq_s.ph %[" #IO5 "], %[" #IO5 "] \n\t" \
+ "absq_s.ph %[" #IO6 "], %[" #IO6 "] \n\t" \
+ "absq_s.ph %[" #IO7 "], %[" #IO7 "] \n\t"
+
+// dpa.w.ph $ac0 temp0 ,temp1
+// $ac += temp0[31..16] * temp1[31..16] + temp0[15..0] * temp1[15..0]
+// dpax.w.ph $ac0 temp0 ,temp1
+// $ac += temp0[31..16] * temp1[15..0] + temp0[15..0] * temp1[31..16]
+// O - output
+// I - input (macro doesn't change it)
+#define MUL_HALF(O0, I0, I1, I2, I3, I4, I5, I6, I7, \
+ I8, I9, I10, I11, I12, I13, I14, I15) \
+ "mult $ac0, $zero, $zero \n\t" \
+ "dpa.w.ph $ac0, %[" #I2 "], %[" #I0 "] \n\t" \
+ "dpax.w.ph $ac0, %[" #I5 "], %[" #I6 "] \n\t" \
+ "dpa.w.ph $ac0, %[" #I8 "], %[" #I9 "] \n\t" \
+ "dpax.w.ph $ac0, %[" #I11 "], %[" #I4 "] \n\t" \
+ "dpa.w.ph $ac0, %[" #I12 "], %[" #I7 "] \n\t" \
+ "dpax.w.ph $ac0, %[" #I13 "], %[" #I1 "] \n\t" \
+ "dpa.w.ph $ac0, %[" #I14 "], %[" #I3 "] \n\t" \
+ "dpax.w.ph $ac0, %[" #I15 "], %[" #I10 "] \n\t" \
+ "mflo %[" #O0 "], $ac0 \n\t"
+
+#define OUTPUT_EARLY_CLOBBER_REGS_17() \
+ OUTPUT_EARLY_CLOBBER_REGS_10(), \
+ [temp11]"=&r"(temp11), [temp12]"=&r"(temp12), [temp13]"=&r"(temp13), \
+ [temp14]"=&r"(temp14), [temp15]"=&r"(temp15), [temp16]"=&r"(temp16), \
+ [temp17]"=&r"(temp17)
+
+// macro for one horizontal pass in FTransform
+// temp0..temp15 holds tmp[0]..tmp[15]
+// A - offset in bytes to load from src and ref buffers
+// TEMP0..TEMP3 - registers for corresponding tmp elements
+#define HORIZONTAL_PASS(A, TEMP0, TEMP1, TEMP2, TEMP3) \
+ "lw %[" #TEMP0 "], 0(%[args]) \n\t" \
+ "lw %[" #TEMP1 "], 4(%[args]) \n\t" \
+ "lw %[" #TEMP2 "], " XSTR(BPS) "*" #A "(%[" #TEMP0 "]) \n\t" \
+ "lw %[" #TEMP3 "], " XSTR(BPS) "*" #A "(%[" #TEMP1 "]) \n\t" \
+ "preceu.ph.qbl %[" #TEMP0 "], %[" #TEMP2 "] \n\t" \
+ "preceu.ph.qbl %[" #TEMP1 "], %[" #TEMP3 "] \n\t" \
+ "preceu.ph.qbr %[" #TEMP2 "], %[" #TEMP2 "] \n\t" \
+ "preceu.ph.qbr %[" #TEMP3 "], %[" #TEMP3 "] \n\t" \
+ "subq.ph %[" #TEMP0 "], %[" #TEMP0 "], %[" #TEMP1 "] \n\t" \
+ "subq.ph %[" #TEMP2 "], %[" #TEMP2 "], %[" #TEMP3 "] \n\t" \
+ "rotr %[" #TEMP0 "], %[" #TEMP0 "], 16 \n\t" \
+ "addq.ph %[" #TEMP1 "], %[" #TEMP2 "], %[" #TEMP0 "] \n\t" \
+ "subq.ph %[" #TEMP3 "], %[" #TEMP2 "], %[" #TEMP0 "] \n\t" \
+ "seh %[" #TEMP0 "], %[" #TEMP1 "] \n\t" \
+ "sra %[temp16], %[" #TEMP1 "], 16 \n\t" \
+ "seh %[temp19], %[" #TEMP3 "] \n\t" \
+ "sra %[" #TEMP3 "], %[" #TEMP3 "], 16 \n\t" \
+ "subu %[" #TEMP2 "], %[" #TEMP0 "], %[temp16] \n\t" \
+ "addu %[" #TEMP0 "], %[" #TEMP0 "], %[temp16] \n\t" \
+ "mul %[temp17], %[temp19], %[c2217] \n\t" \
+ "mul %[temp18], %[" #TEMP3 "], %[c5352] \n\t" \
+ "mul %[" #TEMP1 "], %[temp19], %[c5352] \n\t" \
+ "mul %[temp16], %[" #TEMP3 "], %[c2217] \n\t" \
+ "sll %[" #TEMP2 "], %[" #TEMP2 "], 3 \n\t" \
+ "sll %[" #TEMP0 "], %[" #TEMP0 "], 3 \n\t" \
+ "subu %[" #TEMP3 "], %[temp17], %[temp18] \n\t" \
+ "addu %[" #TEMP1 "], %[temp16], %[" #TEMP1 "] \n\t" \
+ "addiu %[" #TEMP3 "], %[" #TEMP3 "], 937 \n\t" \
+ "addiu %[" #TEMP1 "], %[" #TEMP1 "], 1812 \n\t" \
+ "sra %[" #TEMP3 "], %[" #TEMP3 "], 9 \n\t" \
+ "sra %[" #TEMP1 "], %[" #TEMP1 "], 9 \n\t"
+
+// macro for one vertical pass in FTransform
+// temp0..temp15 holds tmp[0]..tmp[15]
+// A..D - offsets in bytes to store to out buffer
+// TEMP0, TEMP4, TEMP8 and TEMP12 - registers for corresponding tmp elements
+#define VERTICAL_PASS(A, B, C, D, TEMP0, TEMP4, TEMP8, TEMP12) \
+ "addu %[temp16], %[" #TEMP0 "], %[" #TEMP12 "] \n\t" \
+ "subu %[temp19], %[" #TEMP0 "], %[" #TEMP12 "] \n\t" \
+ "addu %[temp17], %[" #TEMP4 "], %[" #TEMP8 "] \n\t" \
+ "subu %[temp18], %[" #TEMP4 "], %[" #TEMP8 "] \n\t" \
+ "mul %[" #TEMP8 "], %[temp19], %[c2217] \n\t" \
+ "mul %[" #TEMP12 "], %[temp18], %[c2217] \n\t" \
+ "mul %[" #TEMP4 "], %[temp19], %[c5352] \n\t" \
+ "mul %[temp18], %[temp18], %[c5352] \n\t" \
+ "addiu %[temp16], %[temp16], 7 \n\t" \
+ "addu %[" #TEMP0 "], %[temp16], %[temp17] \n\t" \
+ "sra %[" #TEMP0 "], %[" #TEMP0 "], 4 \n\t" \
+ "addu %[" #TEMP12 "], %[" #TEMP12 "], %[" #TEMP4 "] \n\t" \
+ "subu %[" #TEMP4 "], %[temp16], %[temp17] \n\t" \
+ "sra %[" #TEMP4 "], %[" #TEMP4 "], 4 \n\t" \
+ "addiu %[" #TEMP8 "], %[" #TEMP8 "], 30000 \n\t" \
+ "addiu %[" #TEMP12 "], %[" #TEMP12 "], 12000 \n\t" \
+ "addiu %[" #TEMP8 "], %[" #TEMP8 "], 21000 \n\t" \
+ "subu %[" #TEMP8 "], %[" #TEMP8 "], %[temp18] \n\t" \
+ "sra %[" #TEMP12 "], %[" #TEMP12 "], 16 \n\t" \
+ "sra %[" #TEMP8 "], %[" #TEMP8 "], 16 \n\t" \
+ "addiu %[temp16], %[" #TEMP12 "], 1 \n\t" \
+ "movn %[" #TEMP12 "], %[temp16], %[temp19] \n\t" \
+ "sh %[" #TEMP0 "], " #A "(%[temp20]) \n\t" \
+ "sh %[" #TEMP4 "], " #C "(%[temp20]) \n\t" \
+ "sh %[" #TEMP8 "], " #D "(%[temp20]) \n\t" \
+ "sh %[" #TEMP12 "], " #B "(%[temp20]) \n\t"
+
+static void FTransform(const uint8_t* src, const uint8_t* ref, int16_t* out) {
+ const int c2217 = 2217;
+ const int c5352 = 5352;
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8;
+ int temp9, temp10, temp11, temp12, temp13, temp14, temp15, temp16;
+ int temp17, temp18, temp19, temp20;
+ const int* const args[3] =
+ { (const int*)src, (const int*)ref, (const int*)out };
+
+ __asm__ volatile (
+ HORIZONTAL_PASS(0, temp0, temp1, temp2, temp3)
+ HORIZONTAL_PASS(1, temp4, temp5, temp6, temp7)
+ HORIZONTAL_PASS(2, temp8, temp9, temp10, temp11)
+ HORIZONTAL_PASS(3, temp12, temp13, temp14, temp15)
+ "lw %[temp20], 8(%[args]) \n\t"
+ VERTICAL_PASS(0, 8, 16, 24, temp0, temp4, temp8, temp12)
+ VERTICAL_PASS(2, 10, 18, 26, temp1, temp5, temp9, temp13)
+ VERTICAL_PASS(4, 12, 20, 28, temp2, temp6, temp10, temp14)
+ VERTICAL_PASS(6, 14, 22, 30, temp3, temp7, temp11, temp15)
+ OUTPUT_EARLY_CLOBBER_REGS_18(),
+ [temp0]"=&r"(temp0), [temp19]"=&r"(temp19), [temp20]"=&r"(temp20)
+ : [args]"r"(args), [c2217]"r"(c2217), [c5352]"r"(c5352)
+ : "memory", "hi", "lo"
+ );
+}
+
+#undef VERTICAL_PASS
+#undef HORIZONTAL_PASS
+
+static WEBP_INLINE void ITransformOne(const uint8_t* ref, const int16_t* in,
+ uint8_t* dst) {
+ int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9;
+ int temp10, temp11, temp12, temp13, temp14, temp15, temp16, temp17, temp18;
+
+ __asm__ volatile (
+ "ulw %[temp1], 0(%[in]) \n\t"
+ "ulw %[temp2], 16(%[in]) \n\t"
+ LOAD_IN_X2(temp5, temp6, 24, 26)
+ ADD_SUB_HALVES(temp3, temp4, temp1, temp2)
+ LOAD_IN_X2(temp1, temp2, 8, 10)
+ MUL_SHIFT_SUM(temp7, temp8, temp9, temp10, temp11, temp12, temp13, temp14,
+ temp10, temp8, temp9, temp7, temp1, temp2, temp5, temp6,
+ temp13, temp11, temp14, temp12)
+ INSERT_HALF_X2(temp8, temp7, temp10, temp9)
+ "ulw %[temp17], 4(%[in]) \n\t"
+ "ulw %[temp18], 20(%[in]) \n\t"
+ ADD_SUB_HALVES(temp1, temp2, temp3, temp8)
+ ADD_SUB_HALVES(temp5, temp6, temp4, temp7)
+ ADD_SUB_HALVES(temp7, temp8, temp17, temp18)
+ LOAD_IN_X2(temp17, temp18, 12, 14)
+ LOAD_IN_X2(temp9, temp10, 28, 30)
+ MUL_SHIFT_SUM(temp11, temp12, temp13, temp14, temp15, temp16, temp4, temp17,
+ temp12, temp14, temp11, temp13, temp17, temp18, temp9, temp10,
+ temp15, temp4, temp16, temp17)
+ INSERT_HALF_X2(temp11, temp12, temp13, temp14)
+ ADD_SUB_HALVES(temp17, temp8, temp8, temp11)
+ ADD_SUB_HALVES(temp3, temp4, temp7, temp12)
+
+ // horizontal
+ SRA_16(temp9, temp10, temp11, temp12, temp1, temp2, temp5, temp6)
+ INSERT_HALF_X2(temp1, temp6, temp5, temp2)
+ SRA_16(temp13, temp14, temp15, temp16, temp3, temp4, temp17, temp8)
+ "repl.ph %[temp2], 0x4 \n\t"
+ INSERT_HALF_X2(temp3, temp8, temp17, temp4)
+ "addq.ph %[temp1], %[temp1], %[temp2] \n\t"
+ "addq.ph %[temp6], %[temp6], %[temp2] \n\t"
+ ADD_SUB_HALVES(temp2, temp4, temp1, temp3)
+ ADD_SUB_HALVES(temp5, temp7, temp6, temp8)
+ MUL_SHIFT_SUM(temp1, temp3, temp6, temp8, temp9, temp13, temp17, temp18,
+ temp3, temp13, temp1, temp9, temp9, temp13, temp11, temp15,
+ temp6, temp17, temp8, temp18)
+ MUL_SHIFT_SUM(temp6, temp8, temp18, temp17, temp11, temp15, temp12, temp16,
+ temp8, temp15, temp6, temp11, temp12, temp16, temp10, temp14,
+ temp18, temp12, temp17, temp16)
+ INSERT_HALF_X2(temp1, temp3, temp9, temp13)
+ INSERT_HALF_X2(temp6, temp8, temp11, temp15)
+ SHIFT_R_SUM_X2(temp9, temp10, temp11, temp12, temp13, temp14, temp15,
+ temp16, temp2, temp4, temp5, temp7, temp3, temp1, temp8,
+ temp6)
+ PACK_2_HALVES_TO_WORD(temp1, temp2, temp3, temp4, temp9, temp12, temp13,
+ temp16, temp11, temp10, temp15, temp14)
+ LOAD_WITH_OFFSET_X4(temp10, temp11, temp14, temp15, ref,
+ 0, 0, 0, 0,
+ 0, 1, 2, 3,
+ BPS)
+ CONVERT_2_BYTES_TO_HALF(temp5, temp6, temp7, temp8, temp17, temp18, temp10,
+ temp11, temp10, temp11, temp14, temp15)
+ STORE_SAT_SUM_X2(temp5, temp6, temp7, temp8, temp17, temp18, temp10, temp11,
+ temp9, temp12, temp1, temp2, temp13, temp16, temp3, temp4,
+ dst, 0, 1, 2, 3, BPS)
+
+ OUTPUT_EARLY_CLOBBER_REGS_18()
+ : [dst]"r"(dst), [in]"r"(in), [kC1]"r"(kC1), [kC2]"r"(kC2), [ref]"r"(ref)
+ : "memory", "hi", "lo"
+ );
+}
+
+static void ITransform(const uint8_t* ref, const int16_t* in, uint8_t* dst,
+ int do_two) {
+ ITransformOne(ref, in, dst);
+ if (do_two) {
+ ITransformOne(ref + 4, in + 16, dst + 4);
+ }
+}
+
+static int Disto4x4(const uint8_t* const a, const uint8_t* const b,
+ const uint16_t* const w) {
+ int temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8, temp9;
+ int temp10, temp11, temp12, temp13, temp14, temp15, temp16, temp17;
+
+ __asm__ volatile (
+ LOAD_WITH_OFFSET_X4(temp1, temp2, temp3, temp4, a,
+ 0, 0, 0, 0,
+ 0, 1, 2, 3,
+ BPS)
+ CONVERT_2_BYTES_TO_HALF(temp5, temp6, temp7, temp8, temp9,temp10, temp11,
+ temp12, temp1, temp2, temp3, temp4)
+ ADD_SUB_HALVES_X4(temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8,
+ temp5, temp6, temp7, temp8, temp9, temp10, temp11, temp12)
+ PACK_2_HALVES_TO_WORD(temp9, temp10, temp11, temp12, temp1, temp3, temp5,
+ temp7, temp2, temp4, temp6, temp8)
+ ADD_SUB_HALVES_X4(temp2, temp4, temp6, temp8, temp9, temp1, temp3, temp10,
+ temp1, temp9, temp3, temp10, temp5, temp11, temp7, temp12)
+ ADD_SUB_HALVES_X4(temp5, temp11, temp7, temp2, temp9, temp3, temp6, temp12,
+ temp2, temp9, temp6, temp3, temp4, temp1, temp8, temp10)
+ ADD_SUB_HALVES_X4(temp1, temp4, temp10, temp8, temp7, temp11, temp5, temp2,
+ temp5, temp7, temp11, temp2, temp9, temp6, temp3, temp12)
+ ABS_X8(temp1, temp4, temp10, temp8, temp7, temp11, temp5, temp2)
+ LOAD_WITH_OFFSET_X4(temp3, temp6, temp9, temp12, w,
+ 0, 4, 8, 12,
+ 0, 0, 0, 0,
+ 0)
+ LOAD_WITH_OFFSET_X4(temp13, temp14, temp15, temp16, w,
+ 0, 4, 8, 12,
+ 1, 1, 1, 1,
+ 16)
+ MUL_HALF(temp17, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8,
+ temp9, temp10, temp11, temp12, temp13, temp14, temp15, temp16)
+ LOAD_WITH_OFFSET_X4(temp1, temp2, temp3, temp4, b,
+ 0, 0, 0, 0,
+ 0, 1, 2, 3,
+ BPS)
+ CONVERT_2_BYTES_TO_HALF(temp5,temp6, temp7, temp8, temp9,temp10, temp11,
+ temp12, temp1, temp2, temp3, temp4)
+ ADD_SUB_HALVES_X4(temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8,
+ temp5, temp6, temp7, temp8, temp9, temp10, temp11, temp12)
+ PACK_2_HALVES_TO_WORD(temp9, temp10, temp11, temp12, temp1, temp3, temp5,
+ temp7, temp2, temp4, temp6, temp8)
+ ADD_SUB_HALVES_X4(temp2, temp4, temp6, temp8, temp9, temp1, temp3, temp10,
+ temp1, temp9, temp3, temp10, temp5, temp11, temp7, temp12)
+ ADD_SUB_HALVES_X4(temp5, temp11, temp7, temp2, temp9, temp3, temp6, temp12,
+ temp2, temp9, temp6, temp3, temp4, temp1, temp8, temp10)
+ ADD_SUB_HALVES_X4(temp1, temp4, temp10, temp8, temp7, temp11, temp5, temp2,
+ temp5, temp7, temp11, temp2, temp9, temp6, temp3, temp12)
+ ABS_X8(temp1, temp4, temp10, temp8, temp7, temp11, temp5, temp2)
+ LOAD_WITH_OFFSET_X4(temp3, temp6, temp9, temp12, w,
+ 0, 4, 8, 12,
+ 0, 0, 0, 0,
+ 0)
+ LOAD_WITH_OFFSET_X4(temp13, temp14, temp15, temp16, w,
+ 0, 4, 8, 12,
+ 1, 1, 1, 1,
+ 16)
+ MUL_HALF(temp3, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8,
+ temp9, temp10, temp11, temp12, temp13, temp14, temp15, temp16)
+ OUTPUT_EARLY_CLOBBER_REGS_17()
+ : [a]"r"(a), [b]"r"(b), [w]"r"(w)
+ : "memory", "hi", "lo"
+ );
+ return abs(temp3 - temp17) >> 5;
+}
+
+static int Disto16x16(const uint8_t* const a, const uint8_t* const b,
+ const uint16_t* const w) {
+ int D = 0;
+ int x, y;
+ for (y = 0; y < 16 * BPS; y += 4 * BPS) {
+ for (x = 0; x < 16; x += 4) {
+ D += Disto4x4(a + x + y, b + x + y, w);
+ }
+ }
+ return D;
+}
+
+//------------------------------------------------------------------------------
+// Intra predictions
+
+#define FILL_PART(J, SIZE) \
+ "usw %[value], 0+" #J "*" XSTR(BPS) "(%[dst]) \n\t" \
+ "usw %[value], 4+" #J "*" XSTR(BPS) "(%[dst]) \n\t" \
+ ".if " #SIZE " == 16 \n\t" \
+ "usw %[value], 8+" #J "*" XSTR(BPS) "(%[dst]) \n\t" \
+ "usw %[value], 12+" #J "*" XSTR(BPS) "(%[dst]) \n\t" \
+ ".endif \n\t"
+
+#define FILL_8_OR_16(DST, VALUE, SIZE) do { \
+ int value = (VALUE); \
+ __asm__ volatile ( \
+ "replv.qb %[value], %[value] \n\t" \
+ FILL_PART( 0, SIZE) \
+ FILL_PART( 1, SIZE) \
+ FILL_PART( 2, SIZE) \
+ FILL_PART( 3, SIZE) \
+ FILL_PART( 4, SIZE) \
+ FILL_PART( 5, SIZE) \
+ FILL_PART( 6, SIZE) \
+ FILL_PART( 7, SIZE) \
+ ".if " #SIZE " == 16 \n\t" \
+ FILL_PART( 8, 16) \
+ FILL_PART( 9, 16) \
+ FILL_PART(10, 16) \
+ FILL_PART(11, 16) \
+ FILL_PART(12, 16) \
+ FILL_PART(13, 16) \
+ FILL_PART(14, 16) \
+ FILL_PART(15, 16) \
+ ".endif \n\t" \
+ : [value]"+&r"(value) \
+ : [dst]"r"((DST)) \
+ : "memory" \
+ ); \
+} while (0)
+
+#define VERTICAL_PRED(DST, TOP, SIZE) \
+static WEBP_INLINE void VerticalPred##SIZE(uint8_t* (DST), \
+ const uint8_t* (TOP)) { \
+ int j; \
+ if ((TOP)) { \
+ for (j = 0; j < (SIZE); ++j) memcpy((DST) + j * BPS, (TOP), (SIZE)); \
+ } else { \
+ FILL_8_OR_16((DST), 127, (SIZE)); \
+ } \
+}
+
+VERTICAL_PRED(dst, top, 8)
+VERTICAL_PRED(dst, top, 16)
+
+#undef VERTICAL_PRED
+
+#define HORIZONTAL_PRED(DST, LEFT, SIZE) \
+static WEBP_INLINE void HorizontalPred##SIZE(uint8_t* (DST), \
+ const uint8_t* (LEFT)) { \
+ if (LEFT) { \
+ int j; \
+ for (j = 0; j < (SIZE); ++j) { \
+ memset((DST) + j * BPS, (LEFT)[j], (SIZE)); \
+ } \
+ } else { \
+ FILL_8_OR_16((DST), 129, (SIZE)); \
+ } \
+}
+
+HORIZONTAL_PRED(dst, left, 8)
+HORIZONTAL_PRED(dst, left, 16)
+
+#undef HORIZONTAL_PRED
+
+#define CLIPPING() \
+ "preceu.ph.qbl %[temp2], %[temp0] \n\t" \
+ "preceu.ph.qbr %[temp0], %[temp0] \n\t" \
+ "preceu.ph.qbl %[temp3], %[temp1] \n\t" \
+ "preceu.ph.qbr %[temp1], %[temp1] \n\t" \
+ "addu.ph %[temp2], %[temp2], %[leftY_1] \n\t" \
+ "addu.ph %[temp0], %[temp0], %[leftY_1] \n\t" \
+ "addu.ph %[temp3], %[temp3], %[leftY_1] \n\t" \
+ "addu.ph %[temp1], %[temp1], %[leftY_1] \n\t" \
+ "shll_s.ph %[temp2], %[temp2], 7 \n\t" \
+ "shll_s.ph %[temp0], %[temp0], 7 \n\t" \
+ "shll_s.ph %[temp3], %[temp3], 7 \n\t" \
+ "shll_s.ph %[temp1], %[temp1], 7 \n\t" \
+ "precrqu_s.qb.ph %[temp0], %[temp2], %[temp0] \n\t" \
+ "precrqu_s.qb.ph %[temp1], %[temp3], %[temp1] \n\t"
+
+#define CLIP_8B_TO_DST(DST, LEFT, TOP, SIZE) do { \
+ int leftY_1 = ((int)(LEFT)[y] << 16) + (LEFT)[y]; \
+ int temp0, temp1, temp2, temp3; \
+ __asm__ volatile ( \
+ "replv.ph %[leftY_1], %[leftY_1] \n\t" \
+ "ulw %[temp0], 0(%[top]) \n\t" \
+ "ulw %[temp1], 4(%[top]) \n\t" \
+ "subu.ph %[leftY_1], %[leftY_1], %[left_1] \n\t" \
+ CLIPPING() \
+ "usw %[temp0], 0(%[dst]) \n\t" \
+ "usw %[temp1], 4(%[dst]) \n\t" \
+ ".if " #SIZE " == 16 \n\t" \
+ "ulw %[temp0], 8(%[top]) \n\t" \
+ "ulw %[temp1], 12(%[top]) \n\t" \
+ CLIPPING() \
+ "usw %[temp0], 8(%[dst]) \n\t" \
+ "usw %[temp1], 12(%[dst]) \n\t" \
+ ".endif \n\t" \
+ : [leftY_1]"+&r"(leftY_1), [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), \
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3) \
+ : [left_1]"r"(left_1), [top]"r"((TOP)), [dst]"r"((DST)) \
+ : "memory" \
+ ); \
+} while (0)
+
+#define CLIP_TO_DST(DST, LEFT, TOP, SIZE) do { \
+ int y; \
+ const int left_1 = ((int)(LEFT)[-1] << 16) + (LEFT)[-1]; \
+ for (y = 0; y < (SIZE); ++y) { \
+ CLIP_8B_TO_DST((DST), (LEFT), (TOP), (SIZE)); \
+ (DST) += BPS; \
+ } \
+} while (0)
+
+#define TRUE_MOTION(DST, LEFT, TOP, SIZE) \
+static WEBP_INLINE void TrueMotion##SIZE(uint8_t* (DST), const uint8_t* (LEFT),\
+ const uint8_t* (TOP)) { \
+ if ((LEFT) != NULL) { \
+ if ((TOP) != NULL) { \
+ CLIP_TO_DST((DST), (LEFT), (TOP), (SIZE)); \
+ } else { \
+ HorizontalPred##SIZE((DST), (LEFT)); \
+ } \
+ } else { \
+ /* true motion without left samples (hence: with default 129 value) */ \
+ /* is equivalent to VE prediction where you just copy the top samples. */ \
+ /* Note that if top samples are not available, the default value is */ \
+ /* then 129, and not 127 as in the VerticalPred case. */ \
+ if ((TOP) != NULL) { \
+ VerticalPred##SIZE((DST), (TOP)); \
+ } else { \
+ FILL_8_OR_16((DST), 129, (SIZE)); \
+ } \
+ } \
+}
+
+TRUE_MOTION(dst, left, top, 8)
+TRUE_MOTION(dst, left, top, 16)
+
+#undef TRUE_MOTION
+#undef CLIP_TO_DST
+#undef CLIP_8B_TO_DST
+#undef CLIPPING
+
+static WEBP_INLINE void DCMode16(uint8_t* dst, const uint8_t* left,
+ const uint8_t* top) {
+ int DC, DC1;
+ int temp0, temp1, temp2, temp3;
+
+ __asm__ volatile(
+ "beqz %[top], 2f \n\t"
+ LOAD_WITH_OFFSET_X4(temp0, temp1, temp2, temp3, top,
+ 0, 4, 8, 12,
+ 0, 0, 0, 0,
+ 0)
+ "raddu.w.qb %[temp0], %[temp0] \n\t"
+ "raddu.w.qb %[temp1], %[temp1] \n\t"
+ "raddu.w.qb %[temp2], %[temp2] \n\t"
+ "raddu.w.qb %[temp3], %[temp3] \n\t"
+ "addu %[temp0], %[temp0], %[temp1] \n\t"
+ "addu %[temp2], %[temp2], %[temp3] \n\t"
+ "addu %[DC], %[temp0], %[temp2] \n\t"
+ "move %[DC1], %[DC] \n\t"
+ "beqz %[left], 1f \n\t"
+ LOAD_WITH_OFFSET_X4(temp0, temp1, temp2, temp3, left,
+ 0, 4, 8, 12,
+ 0, 0, 0, 0,
+ 0)
+ "raddu.w.qb %[temp0], %[temp0] \n\t"
+ "raddu.w.qb %[temp1], %[temp1] \n\t"
+ "raddu.w.qb %[temp2], %[temp2] \n\t"
+ "raddu.w.qb %[temp3], %[temp3] \n\t"
+ "addu %[temp0], %[temp0], %[temp1] \n\t"
+ "addu %[temp2], %[temp2], %[temp3] \n\t"
+ "addu %[DC1], %[temp0], %[temp2] \n\t"
+ "1: \n\t"
+ "addu %[DC], %[DC], %[DC1] \n\t"
+ "j 3f \n\t"
+ "2: \n\t"
+ "beqz %[left], 4f \n\t"
+ LOAD_WITH_OFFSET_X4(temp0, temp1, temp2, temp3, left,
+ 0, 4, 8, 12,
+ 0, 0, 0, 0,
+ 0)
+ "raddu.w.qb %[temp0], %[temp0] \n\t"
+ "raddu.w.qb %[temp1], %[temp1] \n\t"
+ "raddu.w.qb %[temp2], %[temp2] \n\t"
+ "raddu.w.qb %[temp3], %[temp3] \n\t"
+ "addu %[temp0], %[temp0], %[temp1] \n\t"
+ "addu %[temp2], %[temp2], %[temp3] \n\t"
+ "addu %[DC], %[temp0], %[temp2] \n\t"
+ "addu %[DC], %[DC], %[DC] \n\t"
+ "3: \n\t"
+ "shra_r.w %[DC], %[DC], 5 \n\t"
+ "j 5f \n\t"
+ "4: \n\t"
+ "li %[DC], 0x80 \n\t"
+ "5: \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [DC]"=&r"(DC),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), [DC1]"=&r"(DC1)
+ : [left]"r"(left), [top]"r"(top)
+ : "memory"
+ );
+
+ FILL_8_OR_16(dst, DC, 16);
+}
+
+static WEBP_INLINE void DCMode8(uint8_t* dst, const uint8_t* left,
+ const uint8_t* top) {
+ int DC, DC1;
+ int temp0, temp1, temp2, temp3;
+
+ __asm__ volatile(
+ "beqz %[top], 2f \n\t"
+ "ulw %[temp0], 0(%[top]) \n\t"
+ "ulw %[temp1], 4(%[top]) \n\t"
+ "raddu.w.qb %[temp0], %[temp0] \n\t"
+ "raddu.w.qb %[temp1], %[temp1] \n\t"
+ "addu %[DC], %[temp0], %[temp1] \n\t"
+ "move %[DC1], %[DC] \n\t"
+ "beqz %[left], 1f \n\t"
+ "ulw %[temp2], 0(%[left]) \n\t"
+ "ulw %[temp3], 4(%[left]) \n\t"
+ "raddu.w.qb %[temp2], %[temp2] \n\t"
+ "raddu.w.qb %[temp3], %[temp3] \n\t"
+ "addu %[DC1], %[temp2], %[temp3] \n\t"
+ "1: \n\t"
+ "addu %[DC], %[DC], %[DC1] \n\t"
+ "j 3f \n\t"
+ "2: \n\t"
+ "beqz %[left], 4f \n\t"
+ "ulw %[temp2], 0(%[left]) \n\t"
+ "ulw %[temp3], 4(%[left]) \n\t"
+ "raddu.w.qb %[temp2], %[temp2] \n\t"
+ "raddu.w.qb %[temp3], %[temp3] \n\t"
+ "addu %[DC], %[temp2], %[temp3] \n\t"
+ "addu %[DC], %[DC], %[DC] \n\t"
+ "3: \n\t"
+ "shra_r.w %[DC], %[DC], 4 \n\t"
+ "j 5f \n\t"
+ "4: \n\t"
+ "li %[DC], 0x80 \n\t"
+ "5: \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [DC]"=&r"(DC),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), [DC1]"=&r"(DC1)
+ : [left]"r"(left), [top]"r"(top)
+ : "memory"
+ );
+
+ FILL_8_OR_16(dst, DC, 8);
+}
+
+static void DC4(uint8_t* dst, const uint8_t* top) {
+ int temp0, temp1;
+ __asm__ volatile(
+ "ulw %[temp0], 0(%[top]) \n\t"
+ "ulw %[temp1], -5(%[top]) \n\t"
+ "raddu.w.qb %[temp0], %[temp0] \n\t"
+ "raddu.w.qb %[temp1], %[temp1] \n\t"
+ "addu %[temp0], %[temp0], %[temp1] \n\t"
+ "addiu %[temp0], %[temp0], 4 \n\t"
+ "srl %[temp0], %[temp0], 3 \n\t"
+ "replv.qb %[temp0], %[temp0] \n\t"
+ "usw %[temp0], 0*" XSTR(BPS) "(%[dst]) \n\t"
+ "usw %[temp0], 1*" XSTR(BPS) "(%[dst]) \n\t"
+ "usw %[temp0], 2*" XSTR(BPS) "(%[dst]) \n\t"
+ "usw %[temp0], 3*" XSTR(BPS) "(%[dst]) \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1)
+ : [top]"r"(top), [dst]"r"(dst)
+ : "memory"
+ );
+}
+
+static void TM4(uint8_t* dst, const uint8_t* top) {
+ int a10, a32, temp0, temp1, temp2, temp3, temp4, temp5;
+ const int c35 = 0xff00ff;
+ __asm__ volatile (
+ "lbu %[temp1], 0(%[top]) \n\t"
+ "lbu %[a10], 1(%[top]) \n\t"
+ "lbu %[temp2], 2(%[top]) \n\t"
+ "lbu %[a32], 3(%[top]) \n\t"
+ "ulw %[temp0], -5(%[top]) \n\t"
+ "lbu %[temp4], -1(%[top]) \n\t"
+ "append %[a10], %[temp1], 16 \n\t"
+ "append %[a32], %[temp2], 16 \n\t"
+ "replv.ph %[temp4], %[temp4] \n\t"
+ "shrl.ph %[temp1], %[temp0], 8 \n\t"
+ "and %[temp0], %[temp0], %[c35] \n\t"
+ "subu.ph %[temp1], %[temp1], %[temp4] \n\t"
+ "subu.ph %[temp0], %[temp0], %[temp4] \n\t"
+ "srl %[temp2], %[temp1], 16 \n\t"
+ "srl %[temp3], %[temp0], 16 \n\t"
+ "replv.ph %[temp2], %[temp2] \n\t"
+ "replv.ph %[temp3], %[temp3] \n\t"
+ "replv.ph %[temp4], %[temp1] \n\t"
+ "replv.ph %[temp5], %[temp0] \n\t"
+ "addu.ph %[temp0], %[temp3], %[a10] \n\t"
+ "addu.ph %[temp1], %[temp3], %[a32] \n\t"
+ "addu.ph %[temp3], %[temp2], %[a10] \n\t"
+ "addu.ph %[temp2], %[temp2], %[a32] \n\t"
+ "shll_s.ph %[temp0], %[temp0], 7 \n\t"
+ "shll_s.ph %[temp1], %[temp1], 7 \n\t"
+ "shll_s.ph %[temp3], %[temp3], 7 \n\t"
+ "shll_s.ph %[temp2], %[temp2], 7 \n\t"
+ "precrqu_s.qb.ph %[temp0], %[temp1], %[temp0] \n\t"
+ "precrqu_s.qb.ph %[temp1], %[temp2], %[temp3] \n\t"
+ "addu.ph %[temp2], %[temp5], %[a10] \n\t"
+ "addu.ph %[temp3], %[temp5], %[a32] \n\t"
+ "addu.ph %[temp5], %[temp4], %[a10] \n\t"
+ "addu.ph %[temp4], %[temp4], %[a32] \n\t"
+ "shll_s.ph %[temp2], %[temp2], 7 \n\t"
+ "shll_s.ph %[temp3], %[temp3], 7 \n\t"
+ "shll_s.ph %[temp4], %[temp4], 7 \n\t"
+ "shll_s.ph %[temp5], %[temp5], 7 \n\t"
+ "precrqu_s.qb.ph %[temp2], %[temp3], %[temp2] \n\t"
+ "precrqu_s.qb.ph %[temp3], %[temp4], %[temp5] \n\t"
+ "usw %[temp1], 0*" XSTR(BPS) "(%[dst]) \n\t"
+ "usw %[temp0], 1*" XSTR(BPS) "(%[dst]) \n\t"
+ "usw %[temp3], 2*" XSTR(BPS) "(%[dst]) \n\t"
+ "usw %[temp2], 3*" XSTR(BPS) "(%[dst]) \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [a10]"=&r"(a10), [a32]"=&r"(a32)
+ : [c35]"r"(c35), [top]"r"(top), [dst]"r"(dst)
+ : "memory"
+ );
+}
+
+static void VE4(uint8_t* dst, const uint8_t* top) {
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6;
+ __asm__ volatile(
+ "ulw %[temp0], -1(%[top]) \n\t"
+ "ulh %[temp1], 3(%[top]) \n\t"
+ "preceu.ph.qbr %[temp2], %[temp0] \n\t"
+ "preceu.ph.qbl %[temp3], %[temp0] \n\t"
+ "preceu.ph.qbr %[temp4], %[temp1] \n\t"
+ "packrl.ph %[temp5], %[temp3], %[temp2] \n\t"
+ "packrl.ph %[temp6], %[temp4], %[temp3] \n\t"
+ "shll.ph %[temp5], %[temp5], 1 \n\t"
+ "shll.ph %[temp6], %[temp6], 1 \n\t"
+ "addq.ph %[temp2], %[temp5], %[temp2] \n\t"
+ "addq.ph %[temp6], %[temp6], %[temp4] \n\t"
+ "addq.ph %[temp2], %[temp2], %[temp3] \n\t"
+ "addq.ph %[temp6], %[temp6], %[temp3] \n\t"
+ "shra_r.ph %[temp2], %[temp2], 2 \n\t"
+ "shra_r.ph %[temp6], %[temp6], 2 \n\t"
+ "precr.qb.ph %[temp4], %[temp6], %[temp2] \n\t"
+ "usw %[temp4], 0*" XSTR(BPS) "(%[dst]) \n\t"
+ "usw %[temp4], 1*" XSTR(BPS) "(%[dst]) \n\t"
+ "usw %[temp4], 2*" XSTR(BPS) "(%[dst]) \n\t"
+ "usw %[temp4], 3*" XSTR(BPS) "(%[dst]) \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6)
+ : [top]"r"(top), [dst]"r"(dst)
+ : "memory"
+ );
+}
+
+static void HE4(uint8_t* dst, const uint8_t* top) {
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6;
+ __asm__ volatile(
+ "ulw %[temp0], -4(%[top]) \n\t"
+ "lbu %[temp1], -5(%[top]) \n\t"
+ "preceu.ph.qbr %[temp2], %[temp0] \n\t"
+ "preceu.ph.qbl %[temp3], %[temp0] \n\t"
+ "replv.ph %[temp4], %[temp1] \n\t"
+ "packrl.ph %[temp5], %[temp3], %[temp2] \n\t"
+ "packrl.ph %[temp6], %[temp2], %[temp4] \n\t"
+ "shll.ph %[temp5], %[temp5], 1 \n\t"
+ "shll.ph %[temp6], %[temp6], 1 \n\t"
+ "addq.ph %[temp3], %[temp3], %[temp5] \n\t"
+ "addq.ph %[temp3], %[temp3], %[temp2] \n\t"
+ "addq.ph %[temp2], %[temp2], %[temp6] \n\t"
+ "addq.ph %[temp2], %[temp2], %[temp4] \n\t"
+ "shra_r.ph %[temp3], %[temp3], 2 \n\t"
+ "shra_r.ph %[temp2], %[temp2], 2 \n\t"
+ "replv.qb %[temp0], %[temp3] \n\t"
+ "replv.qb %[temp1], %[temp2] \n\t"
+ "srl %[temp3], %[temp3], 16 \n\t"
+ "srl %[temp2], %[temp2], 16 \n\t"
+ "replv.qb %[temp3], %[temp3] \n\t"
+ "replv.qb %[temp2], %[temp2] \n\t"
+ "usw %[temp3], 0*" XSTR(BPS) "(%[dst]) \n\t"
+ "usw %[temp0], 1*" XSTR(BPS) "(%[dst]) \n\t"
+ "usw %[temp2], 2*" XSTR(BPS) "(%[dst]) \n\t"
+ "usw %[temp1], 3*" XSTR(BPS) "(%[dst]) \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6)
+ : [top]"r"(top), [dst]"r"(dst)
+ : "memory"
+ );
+}
+
+static void RD4(uint8_t* dst, const uint8_t* top) {
+ int temp0, temp1, temp2, temp3, temp4, temp5;
+ int temp6, temp7, temp8, temp9, temp10, temp11;
+ __asm__ volatile(
+ "ulw %[temp0], -5(%[top]) \n\t"
+ "ulw %[temp1], -1(%[top]) \n\t"
+ "preceu.ph.qbl %[temp2], %[temp0] \n\t"
+ "preceu.ph.qbr %[temp3], %[temp0] \n\t"
+ "preceu.ph.qbr %[temp4], %[temp1] \n\t"
+ "preceu.ph.qbl %[temp5], %[temp1] \n\t"
+ "packrl.ph %[temp6], %[temp2], %[temp3] \n\t"
+ "packrl.ph %[temp7], %[temp4], %[temp2] \n\t"
+ "packrl.ph %[temp8], %[temp5], %[temp4] \n\t"
+ "shll.ph %[temp6], %[temp6], 1 \n\t"
+ "addq.ph %[temp9], %[temp2], %[temp6] \n\t"
+ "shll.ph %[temp7], %[temp7], 1 \n\t"
+ "addq.ph %[temp9], %[temp9], %[temp3] \n\t"
+ "shll.ph %[temp8], %[temp8], 1 \n\t"
+ "shra_r.ph %[temp9], %[temp9], 2 \n\t"
+ "addq.ph %[temp10], %[temp4], %[temp7] \n\t"
+ "addq.ph %[temp11], %[temp5], %[temp8] \n\t"
+ "addq.ph %[temp10], %[temp10], %[temp2] \n\t"
+ "addq.ph %[temp11], %[temp11], %[temp4] \n\t"
+ "shra_r.ph %[temp10], %[temp10], 2 \n\t"
+ "shra_r.ph %[temp11], %[temp11], 2 \n\t"
+ "lbu %[temp0], 3(%[top]) \n\t"
+ "lbu %[temp1], 2(%[top]) \n\t"
+ "lbu %[temp2], 1(%[top]) \n\t"
+ "sll %[temp1], %[temp1], 1 \n\t"
+ "addu %[temp0], %[temp0], %[temp1] \n\t"
+ "addu %[temp0], %[temp0], %[temp2] \n\t"
+ "precr.qb.ph %[temp9], %[temp10], %[temp9] \n\t"
+ "shra_r.w %[temp0], %[temp0], 2 \n\t"
+ "precr.qb.ph %[temp10], %[temp11], %[temp10] \n\t"
+ "usw %[temp9], 3*" XSTR(BPS) "(%[dst]) \n\t"
+ "usw %[temp10], 1*" XSTR(BPS) "(%[dst]) \n\t"
+ "prepend %[temp9], %[temp11], 8 \n\t"
+ "prepend %[temp10], %[temp0], 8 \n\t"
+ "usw %[temp9], 2*" XSTR(BPS) "(%[dst]) \n\t"
+ "usw %[temp10], 0*" XSTR(BPS) "(%[dst]) \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8),
+ [temp9]"=&r"(temp9), [temp10]"=&r"(temp10), [temp11]"=&r"(temp11)
+ : [top]"r"(top), [dst]"r"(dst)
+ : "memory"
+ );
+}
+
+static void VR4(uint8_t* dst, const uint8_t* top) {
+ int temp0, temp1, temp2, temp3, temp4;
+ int temp5, temp6, temp7, temp8, temp9;
+ __asm__ volatile (
+ "ulw %[temp0], -4(%[top]) \n\t"
+ "ulw %[temp1], 0(%[top]) \n\t"
+ "preceu.ph.qbl %[temp2], %[temp0] \n\t"
+ "preceu.ph.qbr %[temp0], %[temp0] \n\t"
+ "preceu.ph.qbla %[temp3], %[temp1] \n\t"
+ "preceu.ph.qbra %[temp1], %[temp1] \n\t"
+ "packrl.ph %[temp7], %[temp3], %[temp2] \n\t"
+ "addqh_r.ph %[temp4], %[temp1], %[temp3] \n\t"
+ "move %[temp6], %[temp1] \n\t"
+ "append %[temp1], %[temp2], 16 \n\t"
+ "shll.ph %[temp9], %[temp6], 1 \n\t"
+ "addqh_r.ph %[temp5], %[temp7], %[temp6] \n\t"
+ "shll.ph %[temp8], %[temp7], 1 \n\t"
+ "addu.ph %[temp3], %[temp7], %[temp3] \n\t"
+ "addu.ph %[temp1], %[temp1], %[temp6] \n\t"
+ "packrl.ph %[temp7], %[temp2], %[temp0] \n\t"
+ "addu.ph %[temp6], %[temp0], %[temp2] \n\t"
+ "addu.ph %[temp3], %[temp3], %[temp9] \n\t"
+ "addu.ph %[temp1], %[temp1], %[temp8] \n\t"
+ "shll.ph %[temp7], %[temp7], 1 \n\t"
+ "shra_r.ph %[temp3], %[temp3], 2 \n\t"
+ "shra_r.ph %[temp1], %[temp1], 2 \n\t"
+ "addu.ph %[temp6], %[temp6], %[temp7] \n\t"
+ "shra_r.ph %[temp6], %[temp6], 2 \n\t"
+ "precrq.ph.w %[temp8], %[temp4], %[temp5] \n\t"
+ "append %[temp4], %[temp5], 16 \n\t"
+ "precrq.ph.w %[temp2], %[temp3], %[temp1] \n\t"
+ "append %[temp3], %[temp1], 16 \n\t"
+ "precr.qb.ph %[temp8], %[temp8], %[temp4] \n\t"
+ "precr.qb.ph %[temp3], %[temp2], %[temp3] \n\t"
+ "usw %[temp8], 0*" XSTR(BPS) "(%[dst]) \n\t"
+ "usw %[temp3], 1*" XSTR(BPS) "(%[dst]) \n\t"
+ "append %[temp3], %[temp6], 8 \n\t"
+ "srl %[temp6], %[temp6], 16 \n\t"
+ "append %[temp8], %[temp6], 8 \n\t"
+ "usw %[temp3], 3*" XSTR(BPS) "(%[dst]) \n\t"
+ "usw %[temp8], 2*" XSTR(BPS) "(%[dst]) \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8),
+ [temp9]"=&r"(temp9)
+ : [top]"r"(top), [dst]"r"(dst)
+ : "memory"
+ );
+}
+
+static void LD4(uint8_t* dst, const uint8_t* top) {
+ int temp0, temp1, temp2, temp3, temp4, temp5;
+ int temp6, temp7, temp8, temp9, temp10, temp11;
+ __asm__ volatile(
+ "ulw %[temp0], 0(%[top]) \n\t"
+ "ulw %[temp1], 4(%[top]) \n\t"
+ "preceu.ph.qbl %[temp2], %[temp0] \n\t"
+ "preceu.ph.qbr %[temp3], %[temp0] \n\t"
+ "preceu.ph.qbr %[temp4], %[temp1] \n\t"
+ "preceu.ph.qbl %[temp5], %[temp1] \n\t"
+ "packrl.ph %[temp6], %[temp2], %[temp3] \n\t"
+ "packrl.ph %[temp7], %[temp4], %[temp2] \n\t"
+ "packrl.ph %[temp8], %[temp5], %[temp4] \n\t"
+ "shll.ph %[temp6], %[temp6], 1 \n\t"
+ "addq.ph %[temp9], %[temp2], %[temp6] \n\t"
+ "shll.ph %[temp7], %[temp7], 1 \n\t"
+ "addq.ph %[temp9], %[temp9], %[temp3] \n\t"
+ "shll.ph %[temp8], %[temp8], 1 \n\t"
+ "shra_r.ph %[temp9], %[temp9], 2 \n\t"
+ "addq.ph %[temp10], %[temp4], %[temp7] \n\t"
+ "addq.ph %[temp11], %[temp5], %[temp8] \n\t"
+ "addq.ph %[temp10], %[temp10], %[temp2] \n\t"
+ "addq.ph %[temp11], %[temp11], %[temp4] \n\t"
+ "shra_r.ph %[temp10], %[temp10], 2 \n\t"
+ "shra_r.ph %[temp11], %[temp11], 2 \n\t"
+ "srl %[temp1], %[temp1], 24 \n\t"
+ "sll %[temp1], %[temp1], 1 \n\t"
+ "raddu.w.qb %[temp5], %[temp5] \n\t"
+ "precr.qb.ph %[temp9], %[temp10], %[temp9] \n\t"
+ "precr.qb.ph %[temp10], %[temp11], %[temp10] \n\t"
+ "addu %[temp1], %[temp1], %[temp5] \n\t"
+ "shra_r.w %[temp1], %[temp1], 2 \n\t"
+ "usw %[temp9], 0*" XSTR(BPS) "(%[dst]) \n\t"
+ "usw %[temp10], 2*" XSTR(BPS) "(%[dst]) \n\t"
+ "prepend %[temp9], %[temp11], 8 \n\t"
+ "prepend %[temp10], %[temp1], 8 \n\t"
+ "usw %[temp9], 1*" XSTR(BPS) "(%[dst]) \n\t"
+ "usw %[temp10], 3*" XSTR(BPS) "(%[dst]) \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8),
+ [temp9]"=&r"(temp9), [temp10]"=&r"(temp10), [temp11]"=&r"(temp11)
+ : [top]"r"(top), [dst]"r"(dst)
+ : "memory"
+ );
+}
+
+static void VL4(uint8_t* dst, const uint8_t* top) {
+ int temp0, temp1, temp2, temp3, temp4;
+ int temp5, temp6, temp7, temp8, temp9;
+ __asm__ volatile (
+ "ulw %[temp0], 0(%[top]) \n\t"
+ "ulw %[temp1], 4(%[top]) \n\t"
+ "preceu.ph.qbla %[temp2], %[temp0] \n\t"
+ "preceu.ph.qbra %[temp0], %[temp0] \n\t"
+ "preceu.ph.qbl %[temp3], %[temp1] \n\t"
+ "preceu.ph.qbr %[temp1], %[temp1] \n\t"
+ "addqh_r.ph %[temp4], %[temp0], %[temp2] \n\t"
+ "packrl.ph %[temp7], %[temp1], %[temp0] \n\t"
+ "precrq.ph.w %[temp6], %[temp1], %[temp2] \n\t"
+ "shll.ph %[temp9], %[temp2], 1 \n\t"
+ "addqh_r.ph %[temp5], %[temp7], %[temp2] \n\t"
+ "shll.ph %[temp8], %[temp7], 1 \n\t"
+ "addu.ph %[temp2], %[temp2], %[temp6] \n\t"
+ "addu.ph %[temp0], %[temp0], %[temp7] \n\t"
+ "packrl.ph %[temp7], %[temp3], %[temp1] \n\t"
+ "addu.ph %[temp6], %[temp1], %[temp3] \n\t"
+ "addu.ph %[temp2], %[temp2], %[temp8] \n\t"
+ "addu.ph %[temp0], %[temp0], %[temp9] \n\t"
+ "shll.ph %[temp7], %[temp7], 1 \n\t"
+ "shra_r.ph %[temp2], %[temp2], 2 \n\t"
+ "shra_r.ph %[temp0], %[temp0], 2 \n\t"
+ "addu.ph %[temp6], %[temp6], %[temp7] \n\t"
+ "shra_r.ph %[temp6], %[temp6], 2 \n\t"
+ "precrq.ph.w %[temp8], %[temp5], %[temp4] \n\t"
+ "append %[temp5], %[temp4], 16 \n\t"
+ "precrq.ph.w %[temp3], %[temp2], %[temp0] \n\t"
+ "append %[temp2], %[temp0], 16 \n\t"
+ "precr.qb.ph %[temp8], %[temp8], %[temp5] \n\t"
+ "precr.qb.ph %[temp3], %[temp3], %[temp2] \n\t"
+ "usw %[temp8], 0*" XSTR(BPS) "(%[dst]) \n\t"
+ "prepend %[temp8], %[temp6], 8 \n\t"
+ "usw %[temp3], 1*" XSTR(BPS) "(%[dst]) \n\t"
+ "srl %[temp6], %[temp6], 16 \n\t"
+ "prepend %[temp3], %[temp6], 8 \n\t"
+ "usw %[temp8], 2*" XSTR(BPS) "(%[dst]) \n\t"
+ "usw %[temp3], 3*" XSTR(BPS) "(%[dst]) \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8),
+ [temp9]"=&r"(temp9)
+ : [top]"r"(top), [dst]"r"(dst)
+ : "memory"
+ );
+}
+
+static void HD4(uint8_t* dst, const uint8_t* top) {
+ int temp0, temp1, temp2, temp3, temp4;
+ int temp5, temp6, temp7, temp8, temp9;
+ __asm__ volatile (
+ "ulw %[temp0], -5(%[top]) \n\t"
+ "ulw %[temp1], -1(%[top]) \n\t"
+ "preceu.ph.qbla %[temp2], %[temp0] \n\t"
+ "preceu.ph.qbra %[temp0], %[temp0] \n\t"
+ "preceu.ph.qbl %[temp3], %[temp1] \n\t"
+ "preceu.ph.qbr %[temp1], %[temp1] \n\t"
+ "addqh_r.ph %[temp4], %[temp0], %[temp2] \n\t"
+ "packrl.ph %[temp7], %[temp1], %[temp0] \n\t"
+ "precrq.ph.w %[temp6], %[temp1], %[temp2] \n\t"
+ "shll.ph %[temp9], %[temp2], 1 \n\t"
+ "addqh_r.ph %[temp5], %[temp7], %[temp2] \n\t"
+ "shll.ph %[temp8], %[temp7], 1 \n\t"
+ "addu.ph %[temp2], %[temp2], %[temp6] \n\t"
+ "addu.ph %[temp0], %[temp0], %[temp7] \n\t"
+ "packrl.ph %[temp7], %[temp3], %[temp1] \n\t"
+ "addu.ph %[temp6], %[temp1], %[temp3] \n\t"
+ "addu.ph %[temp2], %[temp2], %[temp8] \n\t"
+ "addu.ph %[temp0], %[temp0], %[temp9] \n\t"
+ "shll.ph %[temp7], %[temp7], 1 \n\t"
+ "shra_r.ph %[temp2], %[temp2], 2 \n\t"
+ "shra_r.ph %[temp0], %[temp0], 2 \n\t"
+ "addu.ph %[temp6], %[temp6], %[temp7] \n\t"
+ "shra_r.ph %[temp6], %[temp6], 2 \n\t"
+ "precrq.ph.w %[temp1], %[temp2], %[temp5] \n\t"
+ "precrq.ph.w %[temp3], %[temp0], %[temp4] \n\t"
+ "precr.qb.ph %[temp7], %[temp6], %[temp1] \n\t"
+ "precr.qb.ph %[temp6], %[temp1], %[temp3] \n\t"
+ "usw %[temp7], 0*" XSTR(BPS) "(%[dst]) \n\t"
+ "usw %[temp6], 1*" XSTR(BPS) "(%[dst]) \n\t"
+ "append %[temp2], %[temp5], 16 \n\t"
+ "append %[temp0], %[temp4], 16 \n\t"
+ "precr.qb.ph %[temp5], %[temp3], %[temp2] \n\t"
+ "precr.qb.ph %[temp4], %[temp2], %[temp0] \n\t"
+ "usw %[temp5], 2*" XSTR(BPS) "(%[dst]) \n\t"
+ "usw %[temp4], 3*" XSTR(BPS) "(%[dst]) \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8),
+ [temp9]"=&r"(temp9)
+ : [top]"r"(top), [dst]"r"(dst)
+ : "memory"
+ );
+}
+
+static void HU4(uint8_t* dst, const uint8_t* top) {
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+ __asm__ volatile (
+ "ulw %[temp0], -5(%[top]) \n\t"
+ "preceu.ph.qbl %[temp1], %[temp0] \n\t"
+ "preceu.ph.qbr %[temp2], %[temp0] \n\t"
+ "packrl.ph %[temp3], %[temp1], %[temp2] \n\t"
+ "replv.qb %[temp7], %[temp2] \n\t"
+ "addqh_r.ph %[temp4], %[temp1], %[temp3] \n\t"
+ "addqh_r.ph %[temp5], %[temp3], %[temp2] \n\t"
+ "shll.ph %[temp6], %[temp3], 1 \n\t"
+ "addu.ph %[temp3], %[temp2], %[temp3] \n\t"
+ "addu.ph %[temp6], %[temp1], %[temp6] \n\t"
+ "shll.ph %[temp0], %[temp2], 1 \n\t"
+ "addu.ph %[temp6], %[temp6], %[temp2] \n\t"
+ "addu.ph %[temp0], %[temp3], %[temp0] \n\t"
+ "shra_r.ph %[temp6], %[temp6], 2 \n\t"
+ "shra_r.ph %[temp0], %[temp0], 2 \n\t"
+ "packrl.ph %[temp3], %[temp6], %[temp5] \n\t"
+ "precrq.ph.w %[temp2], %[temp6], %[temp4] \n\t"
+ "append %[temp0], %[temp5], 16 \n\t"
+ "precr.qb.ph %[temp3], %[temp3], %[temp2] \n\t"
+ "usw %[temp3], 0*" XSTR(BPS) "(%[dst]) \n\t"
+ "precr.qb.ph %[temp1], %[temp7], %[temp0] \n\t"
+ "usw %[temp7], 3*" XSTR(BPS) "(%[dst]) \n\t"
+ "packrl.ph %[temp2], %[temp1], %[temp3] \n\t"
+ "usw %[temp1], 2*" XSTR(BPS) "(%[dst]) \n\t"
+ "usw %[temp2], 1*" XSTR(BPS) "(%[dst]) \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7)
+ : [top]"r"(top), [dst]"r"(dst)
+ : "memory"
+ );
+}
+
+//------------------------------------------------------------------------------
+// Chroma 8x8 prediction (paragraph 12.2)
+
+static void IntraChromaPreds(uint8_t* dst, const uint8_t* left,
+ const uint8_t* top) {
+ // U block
+ DCMode8(C8DC8 + dst, left, top);
+ VerticalPred8(C8VE8 + dst, top);
+ HorizontalPred8(C8HE8 + dst, left);
+ TrueMotion8(C8TM8 + dst, left, top);
+ // V block
+ dst += 8;
+ if (top) top += 8;
+ if (left) left += 16;
+ DCMode8(C8DC8 + dst, left, top);
+ VerticalPred8(C8VE8 + dst, top);
+ HorizontalPred8(C8HE8 + dst, left);
+ TrueMotion8(C8TM8 + dst, left, top);
+}
+
+//------------------------------------------------------------------------------
+// luma 16x16 prediction (paragraph 12.3)
+
+static void Intra16Preds(uint8_t* dst,
+ const uint8_t* left, const uint8_t* top) {
+ DCMode16(I16DC16 + dst, left, top);
+ VerticalPred16(I16VE16 + dst, top);
+ HorizontalPred16(I16HE16 + dst, left);
+ TrueMotion16(I16TM16 + dst, left, top);
+}
+
+// Left samples are top[-5 .. -2], top_left is top[-1], top are
+// located at top[0..3], and top right is top[4..7]
+static void Intra4Preds(uint8_t* dst, const uint8_t* top) {
+ DC4(I4DC4 + dst, top);
+ TM4(I4TM4 + dst, top);
+ VE4(I4VE4 + dst, top);
+ HE4(I4HE4 + dst, top);
+ RD4(I4RD4 + dst, top);
+ VR4(I4VR4 + dst, top);
+ LD4(I4LD4 + dst, top);
+ VL4(I4VL4 + dst, top);
+ HD4(I4HD4 + dst, top);
+ HU4(I4HU4 + dst, top);
+}
+
+//------------------------------------------------------------------------------
+// Metric
+
+#if !defined(WORK_AROUND_GCC)
+
+#define GET_SSE_INNER(A) \
+ "lw %[temp0], " #A "(%[a]) \n\t" \
+ "lw %[temp1], " #A "(%[b]) \n\t" \
+ "preceu.ph.qbr %[temp2], %[temp0] \n\t" \
+ "preceu.ph.qbl %[temp0], %[temp0] \n\t" \
+ "preceu.ph.qbr %[temp3], %[temp1] \n\t" \
+ "preceu.ph.qbl %[temp1], %[temp1] \n\t" \
+ "subq.ph %[temp2], %[temp2], %[temp3] \n\t" \
+ "subq.ph %[temp0], %[temp0], %[temp1] \n\t" \
+ "dpa.w.ph $ac0, %[temp2], %[temp2] \n\t" \
+ "dpa.w.ph $ac0, %[temp0], %[temp0] \n\t"
+
+#define GET_SSE(A, B, C, D) \
+ GET_SSE_INNER(A) \
+ GET_SSE_INNER(B) \
+ GET_SSE_INNER(C) \
+ GET_SSE_INNER(D)
+
+static int SSE16x16(const uint8_t* a, const uint8_t* b) {
+ int count;
+ int temp0, temp1, temp2, temp3;
+ __asm__ volatile (
+ "mult $zero, $zero \n\t"
+ GET_SSE( 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS)
+ GET_SSE( 1 * BPS, 4 + 1 * BPS, 8 + 1 * BPS, 12 + 1 * BPS)
+ GET_SSE( 2 * BPS, 4 + 2 * BPS, 8 + 2 * BPS, 12 + 2 * BPS)
+ GET_SSE( 3 * BPS, 4 + 3 * BPS, 8 + 3 * BPS, 12 + 3 * BPS)
+ GET_SSE( 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS)
+ GET_SSE( 5 * BPS, 4 + 5 * BPS, 8 + 5 * BPS, 12 + 5 * BPS)
+ GET_SSE( 6 * BPS, 4 + 6 * BPS, 8 + 6 * BPS, 12 + 6 * BPS)
+ GET_SSE( 7 * BPS, 4 + 7 * BPS, 8 + 7 * BPS, 12 + 7 * BPS)
+ GET_SSE( 8 * BPS, 4 + 8 * BPS, 8 + 8 * BPS, 12 + 8 * BPS)
+ GET_SSE( 9 * BPS, 4 + 9 * BPS, 8 + 9 * BPS, 12 + 9 * BPS)
+ GET_SSE(10 * BPS, 4 + 10 * BPS, 8 + 10 * BPS, 12 + 10 * BPS)
+ GET_SSE(11 * BPS, 4 + 11 * BPS, 8 + 11 * BPS, 12 + 11 * BPS)
+ GET_SSE(12 * BPS, 4 + 12 * BPS, 8 + 12 * BPS, 12 + 12 * BPS)
+ GET_SSE(13 * BPS, 4 + 13 * BPS, 8 + 13 * BPS, 12 + 13 * BPS)
+ GET_SSE(14 * BPS, 4 + 14 * BPS, 8 + 14 * BPS, 12 + 14 * BPS)
+ GET_SSE(15 * BPS, 4 + 15 * BPS, 8 + 15 * BPS, 12 + 15 * BPS)
+ "mflo %[count] \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [count]"=&r"(count)
+ : [a]"r"(a), [b]"r"(b)
+ : "memory", "hi", "lo"
+ );
+ return count;
+}
+
+static int SSE16x8(const uint8_t* a, const uint8_t* b) {
+ int count;
+ int temp0, temp1, temp2, temp3;
+ __asm__ volatile (
+ "mult $zero, $zero \n\t"
+ GET_SSE( 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS)
+ GET_SSE( 1 * BPS, 4 + 1 * BPS, 8 + 1 * BPS, 12 + 1 * BPS)
+ GET_SSE( 2 * BPS, 4 + 2 * BPS, 8 + 2 * BPS, 12 + 2 * BPS)
+ GET_SSE( 3 * BPS, 4 + 3 * BPS, 8 + 3 * BPS, 12 + 3 * BPS)
+ GET_SSE( 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS)
+ GET_SSE( 5 * BPS, 4 + 5 * BPS, 8 + 5 * BPS, 12 + 5 * BPS)
+ GET_SSE( 6 * BPS, 4 + 6 * BPS, 8 + 6 * BPS, 12 + 6 * BPS)
+ GET_SSE( 7 * BPS, 4 + 7 * BPS, 8 + 7 * BPS, 12 + 7 * BPS)
+ "mflo %[count] \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [count]"=&r"(count)
+ : [a]"r"(a), [b]"r"(b)
+ : "memory", "hi", "lo"
+ );
+ return count;
+}
+
+static int SSE8x8(const uint8_t* a, const uint8_t* b) {
+ int count;
+ int temp0, temp1, temp2, temp3;
+ __asm__ volatile (
+ "mult $zero, $zero \n\t"
+ GET_SSE(0 * BPS, 4 + 0 * BPS, 1 * BPS, 4 + 1 * BPS)
+ GET_SSE(2 * BPS, 4 + 2 * BPS, 3 * BPS, 4 + 3 * BPS)
+ GET_SSE(4 * BPS, 4 + 4 * BPS, 5 * BPS, 4 + 5 * BPS)
+ GET_SSE(6 * BPS, 4 + 6 * BPS, 7 * BPS, 4 + 7 * BPS)
+ "mflo %[count] \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [count]"=&r"(count)
+ : [a]"r"(a), [b]"r"(b)
+ : "memory", "hi", "lo"
+ );
+ return count;
+}
+
+static int SSE4x4(const uint8_t* a, const uint8_t* b) {
+ int count;
+ int temp0, temp1, temp2, temp3;
+ __asm__ volatile (
+ "mult $zero, $zero \n\t"
+ GET_SSE(0 * BPS, 1 * BPS, 2 * BPS, 3 * BPS)
+ "mflo %[count] \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [count]"=&r"(count)
+ : [a]"r"(a), [b]"r"(b)
+ : "memory", "hi", "lo"
+ );
+ return count;
+}
+
+#undef GET_SSE
+#undef GET_SSE_INNER
+
+#endif // !WORK_AROUND_GCC
+
+#undef FILL_8_OR_16
+#undef FILL_PART
+#undef OUTPUT_EARLY_CLOBBER_REGS_17
+#undef MUL_HALF
+#undef ABS_X8
+#undef ADD_SUB_HALVES_X4
+
+//------------------------------------------------------------------------------
+// Quantization
+//
+
+// macro for one pass through for loop in QuantizeBlock reading 2 values at time
+// QUANTDIV macro inlined
+// J - offset in bytes (kZigzag[n] * 2)
+// K - offset in bytes (kZigzag[n] * 4)
+// N - offset in bytes (n * 2)
+// N1 - offset in bytes ((n + 1) * 2)
+#define QUANTIZE_ONE(J, K, N, N1) \
+ "ulw %[temp1], " #J "(%[ppin]) \n\t" \
+ "ulw %[temp2], " #J "(%[ppsharpen]) \n\t" \
+ "lhu %[temp3], " #K "(%[ppzthresh]) \n\t" \
+ "lhu %[temp6], " #K "+4(%[ppzthresh]) \n\t" \
+ "absq_s.ph %[temp4], %[temp1] \n\t" \
+ "ins %[temp3], %[temp6], 16, 16 \n\t" \
+ "addu.ph %[coeff], %[temp4], %[temp2] \n\t" \
+ "shra.ph %[sign], %[temp1], 15 \n\t" \
+ "li %[level], 0x10001 \n\t" \
+ "cmp.lt.ph %[temp3], %[coeff] \n\t" \
+ "lhu %[temp1], " #J "(%[ppiq]) \n\t" \
+ "pick.ph %[temp5], %[level], $0 \n\t" \
+ "lw %[temp2], " #K "(%[ppbias]) \n\t" \
+ "beqz %[temp5], 0f \n\t" \
+ "lhu %[temp3], " #J "(%[ppq]) \n\t" \
+ "beq %[temp5], %[level], 1f \n\t" \
+ "andi %[temp5], %[temp5], 0x1 \n\t" \
+ "andi %[temp4], %[coeff], 0xffff \n\t" \
+ "beqz %[temp5], 2f \n\t" \
+ "mul %[level], %[temp4], %[temp1] \n\t" \
+ "sh $0, " #J "+2(%[ppin]) \n\t" \
+ "sh $0, " #N1 "(%[pout]) \n\t" \
+ "addu %[level], %[level], %[temp2] \n\t" \
+ "sra %[level], %[level], 17 \n\t" \
+ "slt %[temp4], %[max_level], %[level] \n\t" \
+ "movn %[level], %[max_level], %[temp4] \n\t" \
+ "andi %[temp6], %[sign], 0xffff \n\t" \
+ "xor %[level], %[level], %[temp6] \n\t" \
+ "subu %[level], %[level], %[temp6] \n\t" \
+ "mul %[temp5], %[level], %[temp3] \n\t" \
+ "or %[ret], %[ret], %[level] \n\t" \
+ "sh %[level], " #N "(%[pout]) \n\t" \
+ "sh %[temp5], " #J "(%[ppin]) \n\t" \
+ "j 3f \n\t" \
+"2: \n\t" \
+ "lhu %[temp1], " #J "+2(%[ppiq]) \n\t" \
+ "srl %[temp5], %[coeff], 16 \n\t" \
+ "mul %[level], %[temp5], %[temp1] \n\t" \
+ "lw %[temp2], " #K "+4(%[ppbias]) \n\t" \
+ "lhu %[temp3], " #J "+2(%[ppq]) \n\t" \
+ "addu %[level], %[level], %[temp2] \n\t" \
+ "sra %[level], %[level], 17 \n\t" \
+ "srl %[temp6], %[sign], 16 \n\t" \
+ "slt %[temp4], %[max_level], %[level] \n\t" \
+ "movn %[level], %[max_level], %[temp4] \n\t" \
+ "xor %[level], %[level], %[temp6] \n\t" \
+ "subu %[level], %[level], %[temp6] \n\t" \
+ "mul %[temp5], %[level], %[temp3] \n\t" \
+ "sh $0, " #J "(%[ppin]) \n\t" \
+ "sh $0, " #N "(%[pout]) \n\t" \
+ "or %[ret], %[ret], %[level] \n\t" \
+ "sh %[temp5], " #J "+2(%[ppin]) \n\t" \
+ "sh %[level], " #N1 "(%[pout]) \n\t" \
+ "j 3f \n\t" \
+"1: \n\t" \
+ "lhu %[temp1], " #J "(%[ppiq]) \n\t" \
+ "lw %[temp2], " #K "(%[ppbias]) \n\t" \
+ "ulw %[temp3], " #J "(%[ppq]) \n\t" \
+ "andi %[temp5], %[coeff], 0xffff \n\t" \
+ "srl %[temp0], %[coeff], 16 \n\t" \
+ "lhu %[temp6], " #J "+2(%[ppiq]) \n\t" \
+ "lw %[coeff], " #K "+4(%[ppbias]) \n\t" \
+ "mul %[level], %[temp5], %[temp1] \n\t" \
+ "mul %[temp4], %[temp0], %[temp6] \n\t" \
+ "addu %[level], %[level], %[temp2] \n\t" \
+ "addu %[temp4], %[temp4], %[coeff] \n\t" \
+ "precrq.ph.w %[level], %[temp4], %[level] \n\t" \
+ "shra.ph %[level], %[level], 1 \n\t" \
+ "cmp.lt.ph %[max_level1],%[level] \n\t" \
+ "pick.ph %[level], %[max_level], %[level] \n\t" \
+ "xor %[level], %[level], %[sign] \n\t" \
+ "subu.ph %[level], %[level], %[sign] \n\t" \
+ "mul.ph %[temp3], %[level], %[temp3] \n\t" \
+ "or %[ret], %[ret], %[level] \n\t" \
+ "sh %[level], " #N "(%[pout]) \n\t" \
+ "srl %[level], %[level], 16 \n\t" \
+ "sh %[level], " #N1 "(%[pout]) \n\t" \
+ "usw %[temp3], " #J "(%[ppin]) \n\t" \
+ "j 3f \n\t" \
+"0: \n\t" \
+ "sh $0, " #N "(%[pout]) \n\t" \
+ "sh $0, " #N1 "(%[pout]) \n\t" \
+ "usw $0, " #J "(%[ppin]) \n\t" \
+"3: \n\t"
+
+static int QuantizeBlock(int16_t in[16], int16_t out[16],
+ const VP8Matrix* const mtx) {
+ int temp0, temp1, temp2, temp3, temp4, temp5,temp6;
+ int sign, coeff, level;
+ int max_level = MAX_LEVEL;
+ int max_level1 = max_level << 16 | max_level;
+ int ret = 0;
+
+ int16_t* ppin = &in[0];
+ int16_t* pout = &out[0];
+ const uint16_t* ppsharpen = &mtx->sharpen_[0];
+ const uint32_t* ppzthresh = &mtx->zthresh_[0];
+ const uint16_t* ppq = &mtx->q_[0];
+ const uint16_t* ppiq = &mtx->iq_[0];
+ const uint32_t* ppbias = &mtx->bias_[0];
+
+ __asm__ volatile (
+ QUANTIZE_ONE( 0, 0, 0, 2)
+ QUANTIZE_ONE( 4, 8, 10, 12)
+ QUANTIZE_ONE( 8, 16, 4, 8)
+ QUANTIZE_ONE(12, 24, 14, 24)
+ QUANTIZE_ONE(16, 32, 6, 16)
+ QUANTIZE_ONE(20, 40, 22, 26)
+ QUANTIZE_ONE(24, 48, 18, 20)
+ QUANTIZE_ONE(28, 56, 28, 30)
+
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [sign]"=&r"(sign), [coeff]"=&r"(coeff),
+ [level]"=&r"(level), [temp6]"=&r"(temp6), [ret]"+&r"(ret)
+ : [ppin]"r"(ppin), [pout]"r"(pout), [max_level1]"r"(max_level1),
+ [ppiq]"r"(ppiq), [max_level]"r"(max_level),
+ [ppbias]"r"(ppbias), [ppzthresh]"r"(ppzthresh),
+ [ppsharpen]"r"(ppsharpen), [ppq]"r"(ppq)
+ : "memory", "hi", "lo"
+ );
+
+ return (ret != 0);
+}
+
+static int Quantize2Blocks(int16_t in[32], int16_t out[32],
+ const VP8Matrix* const mtx) {
+ int nz;
+ nz = QuantizeBlock(in + 0 * 16, out + 0 * 16, mtx) << 0;
+ nz |= QuantizeBlock(in + 1 * 16, out + 1 * 16, mtx) << 1;
+ return nz;
+}
+
+#undef QUANTIZE_ONE
+
+// macro for one horizontal pass in FTransformWHT
+// temp0..temp7 holds tmp[0]..tmp[15]
+// A, B, C, D - offset in bytes to load from in buffer
+// TEMP0, TEMP1 - registers for corresponding tmp elements
+#define HORIZONTAL_PASS_WHT(A, B, C, D, TEMP0, TEMP1) \
+ "lh %[" #TEMP0 "], " #A "(%[in]) \n\t" \
+ "lh %[" #TEMP1 "], " #B "(%[in]) \n\t" \
+ "lh %[temp8], " #C "(%[in]) \n\t" \
+ "lh %[temp9], " #D "(%[in]) \n\t" \
+ "ins %[" #TEMP1 "], %[" #TEMP0 "], 16, 16 \n\t" \
+ "ins %[temp9], %[temp8], 16, 16 \n\t" \
+ "subq.ph %[temp8], %[" #TEMP1 "], %[temp9] \n\t" \
+ "addq.ph %[temp9], %[" #TEMP1 "], %[temp9] \n\t" \
+ "precrq.ph.w %[" #TEMP0 "], %[temp8], %[temp9] \n\t" \
+ "append %[temp8], %[temp9], 16 \n\t" \
+ "subq.ph %[" #TEMP1 "], %[" #TEMP0 "], %[temp8] \n\t" \
+ "addq.ph %[" #TEMP0 "], %[" #TEMP0 "], %[temp8] \n\t" \
+ "rotr %[" #TEMP1 "], %[" #TEMP1 "], 16 \n\t"
+
+// macro for one vertical pass in FTransformWHT
+// temp0..temp7 holds tmp[0]..tmp[15]
+// A, B, C, D - offsets in bytes to store to out buffer
+// TEMP0, TEMP2, TEMP4 and TEMP6 - registers for corresponding tmp elements
+#define VERTICAL_PASS_WHT(A, B, C, D, TEMP0, TEMP2, TEMP4, TEMP6) \
+ "addq.ph %[temp8], %[" #TEMP0 "], %[" #TEMP4 "] \n\t" \
+ "addq.ph %[temp9], %[" #TEMP2 "], %[" #TEMP6 "] \n\t" \
+ "subq.ph %[" #TEMP2 "], %[" #TEMP2 "], %[" #TEMP6 "] \n\t" \
+ "subq.ph %[" #TEMP6 "], %[" #TEMP0 "], %[" #TEMP4 "] \n\t" \
+ "addqh.ph %[" #TEMP0 "], %[temp8], %[temp9] \n\t" \
+ "subqh.ph %[" #TEMP4 "], %[" #TEMP6 "], %[" #TEMP2 "] \n\t" \
+ "addqh.ph %[" #TEMP2 "], %[" #TEMP2 "], %[" #TEMP6 "] \n\t" \
+ "subqh.ph %[" #TEMP6 "], %[temp8], %[temp9] \n\t" \
+ "usw %[" #TEMP0 "], " #A "(%[out]) \n\t" \
+ "usw %[" #TEMP2 "], " #B "(%[out]) \n\t" \
+ "usw %[" #TEMP4 "], " #C "(%[out]) \n\t" \
+ "usw %[" #TEMP6 "], " #D "(%[out]) \n\t"
+
+static void FTransformWHT(const int16_t* in, int16_t* out) {
+ int temp0, temp1, temp2, temp3, temp4;
+ int temp5, temp6, temp7, temp8, temp9;
+
+ __asm__ volatile (
+ HORIZONTAL_PASS_WHT( 0, 32, 64, 96, temp0, temp1)
+ HORIZONTAL_PASS_WHT(128, 160, 192, 224, temp2, temp3)
+ HORIZONTAL_PASS_WHT(256, 288, 320, 352, temp4, temp5)
+ HORIZONTAL_PASS_WHT(384, 416, 448, 480, temp6, temp7)
+ VERTICAL_PASS_WHT(0, 8, 16, 24, temp0, temp2, temp4, temp6)
+ VERTICAL_PASS_WHT(4, 12, 20, 28, temp1, temp3, temp5, temp7)
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8),
+ [temp9]"=&r"(temp9)
+ : [in]"r"(in), [out]"r"(out)
+ : "memory"
+ );
+}
+
+#undef VERTICAL_PASS_WHT
+#undef HORIZONTAL_PASS_WHT
+
+// macro for converting coefficients to bin
+// convert 8 coeffs at time
+// A, B, C, D - offsets in bytes to load from out buffer
+#define CONVERT_COEFFS_TO_BIN(A, B, C, D) \
+ "ulw %[temp0], " #A "(%[out]) \n\t" \
+ "ulw %[temp1], " #B "(%[out]) \n\t" \
+ "ulw %[temp2], " #C "(%[out]) \n\t" \
+ "ulw %[temp3], " #D "(%[out]) \n\t" \
+ "absq_s.ph %[temp0], %[temp0] \n\t" \
+ "absq_s.ph %[temp1], %[temp1] \n\t" \
+ "absq_s.ph %[temp2], %[temp2] \n\t" \
+ "absq_s.ph %[temp3], %[temp3] \n\t" \
+ /* TODO(skal): add rounding ? shra_r.ph : shra.ph */ \
+ /* for following 4 instructions */ \
+ "shra.ph %[temp0], %[temp0], 3 \n\t" \
+ "shra.ph %[temp1], %[temp1], 3 \n\t" \
+ "shra.ph %[temp2], %[temp2], 3 \n\t" \
+ "shra.ph %[temp3], %[temp3], 3 \n\t" \
+ "shll_s.ph %[temp0], %[temp0], 10 \n\t" \
+ "shll_s.ph %[temp1], %[temp1], 10 \n\t" \
+ "shll_s.ph %[temp2], %[temp2], 10 \n\t" \
+ "shll_s.ph %[temp3], %[temp3], 10 \n\t" \
+ "shrl.ph %[temp0], %[temp0], 10 \n\t" \
+ "shrl.ph %[temp1], %[temp1], 10 \n\t" \
+ "shrl.ph %[temp2], %[temp2], 10 \n\t" \
+ "shrl.ph %[temp3], %[temp3], 10 \n\t" \
+ "shll.ph %[temp0], %[temp0], 2 \n\t" \
+ "shll.ph %[temp1], %[temp1], 2 \n\t" \
+ "shll.ph %[temp2], %[temp2], 2 \n\t" \
+ "shll.ph %[temp3], %[temp3], 2 \n\t" \
+ "ext %[temp4], %[temp0], 0, 16 \n\t" \
+ "ext %[temp0], %[temp0], 16, 16 \n\t" \
+ "addu %[temp4], %[temp4], %[dist] \n\t" \
+ "addu %[temp0], %[temp0], %[dist] \n\t" \
+ "ext %[temp5], %[temp1], 0, 16 \n\t" \
+ "lw %[temp8], 0(%[temp4]) \n\t" \
+ "ext %[temp1], %[temp1], 16, 16 \n\t" \
+ "addu %[temp5], %[temp5], %[dist] \n\t" \
+ "addiu %[temp8], %[temp8], 1 \n\t" \
+ "sw %[temp8], 0(%[temp4]) \n\t" \
+ "lw %[temp8], 0(%[temp0]) \n\t" \
+ "addu %[temp1], %[temp1], %[dist] \n\t" \
+ "ext %[temp6], %[temp2], 0, 16 \n\t" \
+ "addiu %[temp8], %[temp8], 1 \n\t" \
+ "sw %[temp8], 0(%[temp0]) \n\t" \
+ "lw %[temp8], 0(%[temp5]) \n\t" \
+ "ext %[temp2], %[temp2], 16, 16 \n\t" \
+ "addu %[temp6], %[temp6], %[dist] \n\t" \
+ "addiu %[temp8], %[temp8], 1 \n\t" \
+ "sw %[temp8], 0(%[temp5]) \n\t" \
+ "lw %[temp8], 0(%[temp1]) \n\t" \
+ "addu %[temp2], %[temp2], %[dist] \n\t" \
+ "ext %[temp7], %[temp3], 0, 16 \n\t" \
+ "addiu %[temp8], %[temp8], 1 \n\t" \
+ "sw %[temp8], 0(%[temp1]) \n\t" \
+ "lw %[temp8], 0(%[temp6]) \n\t" \
+ "ext %[temp3], %[temp3], 16, 16 \n\t" \
+ "addu %[temp7], %[temp7], %[dist] \n\t" \
+ "addiu %[temp8], %[temp8], 1 \n\t" \
+ "sw %[temp8], 0(%[temp6]) \n\t" \
+ "lw %[temp8], 0(%[temp2]) \n\t" \
+ "addu %[temp3], %[temp3], %[dist] \n\t" \
+ "addiu %[temp8], %[temp8], 1 \n\t" \
+ "sw %[temp8], 0(%[temp2]) \n\t" \
+ "lw %[temp8], 0(%[temp7]) \n\t" \
+ "addiu %[temp8], %[temp8], 1 \n\t" \
+ "sw %[temp8], 0(%[temp7]) \n\t" \
+ "lw %[temp8], 0(%[temp3]) \n\t" \
+ "addiu %[temp8], %[temp8], 1 \n\t" \
+ "sw %[temp8], 0(%[temp3]) \n\t"
+
+static void CollectHistogram(const uint8_t* ref, const uint8_t* pred,
+ int start_block, int end_block,
+ VP8Histogram* const histo) {
+ int j;
+ int distribution[MAX_COEFF_THRESH + 1] = { 0 };
+ const int max_coeff = (MAX_COEFF_THRESH << 16) + MAX_COEFF_THRESH;
+ for (j = start_block; j < end_block; ++j) {
+ int16_t out[16];
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8;
+
+ VP8FTransform(ref + VP8DspScan[j], pred + VP8DspScan[j], out);
+
+ // Convert coefficients to bin.
+ __asm__ volatile (
+ CONVERT_COEFFS_TO_BIN( 0, 4, 8, 12)
+ CONVERT_COEFFS_TO_BIN(16, 20, 24, 28)
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [temp8]"=&r"(temp8)
+ : [dist]"r"(distribution), [out]"r"(out), [max_coeff]"r"(max_coeff)
+ : "memory"
+ );
+ }
+ VP8SetHistogramData(distribution, histo);
+}
+
+#undef CONVERT_COEFFS_TO_BIN
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8EncDspInitMIPSdspR2(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspInitMIPSdspR2(void) {
+ VP8FTransform = FTransform;
+ VP8ITransform = ITransform;
+ VP8TDisto4x4 = Disto4x4;
+ VP8TDisto16x16 = Disto16x16;
+ VP8EncPredLuma16 = Intra16Preds;
+ VP8EncPredChroma8 = IntraChromaPreds;
+ VP8EncPredLuma4 = Intra4Preds;
+#if !defined(WORK_AROUND_GCC)
+ VP8SSE16x16 = SSE16x16;
+ VP8SSE8x8 = SSE8x8;
+ VP8SSE16x8 = SSE16x8;
+ VP8SSE4x4 = SSE4x4;
+#endif
+ VP8EncQuantizeBlock = QuantizeBlock;
+ VP8EncQuantize2Blocks = Quantize2Blocks;
+ VP8FTransformWHT = FTransformWHT;
+ VP8CollectHistogram = CollectHistogram;
+}
+
+#else // !WEBP_USE_MIPS_DSP_R2
+
+WEBP_DSP_INIT_STUB(VP8EncDspInitMIPSdspR2)
+
+#endif // WEBP_USE_MIPS_DSP_R2
diff --git a/drivers/webp/dsp/enc_neon.c b/drivers/webp/dsp/enc_neon.c
new file mode 100644
index 0000000000..c2aef58e70
--- /dev/null
+++ b/drivers/webp/dsp/enc_neon.c
@@ -0,0 +1,934 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// ARM NEON version of speed-critical encoding functions.
+//
+// adapted from libvpx (http://www.webmproject.org/code/)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_NEON)
+
+#include <assert.h>
+
+#include "./neon.h"
+#include "../enc/vp8enci.h"
+
+//------------------------------------------------------------------------------
+// Transforms (Paragraph 14.4)
+
+// Inverse transform.
+// This code is pretty much the same as TransformOne in the dec_neon.c, except
+// for subtraction to *ref. See the comments there for algorithmic explanations.
+
+static const int16_t kC1 = 20091;
+static const int16_t kC2 = 17734; // half of kC2, actually. See comment above.
+
+// This code works but is *slower* than the inlined-asm version below
+// (with gcc-4.6). So we disable it for now. Later, it'll be conditional to
+// WEBP_USE_INTRINSICS define.
+// With gcc-4.8, it's a little faster speed than inlined-assembly.
+#if defined(WEBP_USE_INTRINSICS)
+
+// Treats 'v' as an uint8x8_t and zero extends to an int16x8_t.
+static WEBP_INLINE int16x8_t ConvertU8ToS16(uint32x2_t v) {
+ return vreinterpretq_s16_u16(vmovl_u8(vreinterpret_u8_u32(v)));
+}
+
+// Performs unsigned 8b saturation on 'dst01' and 'dst23' storing the result
+// to the corresponding rows of 'dst'.
+static WEBP_INLINE void SaturateAndStore4x4(uint8_t* const dst,
+ const int16x8_t dst01,
+ const int16x8_t dst23) {
+ // Unsigned saturate to 8b.
+ const uint8x8_t dst01_u8 = vqmovun_s16(dst01);
+ const uint8x8_t dst23_u8 = vqmovun_s16(dst23);
+
+ // Store the results.
+ vst1_lane_u32((uint32_t*)(dst + 0 * BPS), vreinterpret_u32_u8(dst01_u8), 0);
+ vst1_lane_u32((uint32_t*)(dst + 1 * BPS), vreinterpret_u32_u8(dst01_u8), 1);
+ vst1_lane_u32((uint32_t*)(dst + 2 * BPS), vreinterpret_u32_u8(dst23_u8), 0);
+ vst1_lane_u32((uint32_t*)(dst + 3 * BPS), vreinterpret_u32_u8(dst23_u8), 1);
+}
+
+static WEBP_INLINE void Add4x4(const int16x8_t row01, const int16x8_t row23,
+ const uint8_t* const ref, uint8_t* const dst) {
+ uint32x2_t dst01 = vdup_n_u32(0);
+ uint32x2_t dst23 = vdup_n_u32(0);
+
+ // Load the source pixels.
+ dst01 = vld1_lane_u32((uint32_t*)(ref + 0 * BPS), dst01, 0);
+ dst23 = vld1_lane_u32((uint32_t*)(ref + 2 * BPS), dst23, 0);
+ dst01 = vld1_lane_u32((uint32_t*)(ref + 1 * BPS), dst01, 1);
+ dst23 = vld1_lane_u32((uint32_t*)(ref + 3 * BPS), dst23, 1);
+
+ {
+ // Convert to 16b.
+ const int16x8_t dst01_s16 = ConvertU8ToS16(dst01);
+ const int16x8_t dst23_s16 = ConvertU8ToS16(dst23);
+
+ // Descale with rounding.
+ const int16x8_t out01 = vrsraq_n_s16(dst01_s16, row01, 3);
+ const int16x8_t out23 = vrsraq_n_s16(dst23_s16, row23, 3);
+ // Add the inverse transform.
+ SaturateAndStore4x4(dst, out01, out23);
+ }
+}
+
+static WEBP_INLINE void Transpose8x2(const int16x8_t in0, const int16x8_t in1,
+ int16x8x2_t* const out) {
+ // a0 a1 a2 a3 | b0 b1 b2 b3 => a0 b0 c0 d0 | a1 b1 c1 d1
+ // c0 c1 c2 c3 | d0 d1 d2 d3 a2 b2 c2 d2 | a3 b3 c3 d3
+ const int16x8x2_t tmp0 = vzipq_s16(in0, in1); // a0 c0 a1 c1 a2 c2 ...
+ // b0 d0 b1 d1 b2 d2 ...
+ *out = vzipq_s16(tmp0.val[0], tmp0.val[1]);
+}
+
+static WEBP_INLINE void TransformPass(int16x8x2_t* const rows) {
+ // {rows} = in0 | in4
+ // in8 | in12
+ // B1 = in4 | in12
+ const int16x8_t B1 =
+ vcombine_s16(vget_high_s16(rows->val[0]), vget_high_s16(rows->val[1]));
+ // C0 = kC1 * in4 | kC1 * in12
+ // C1 = kC2 * in4 | kC2 * in12
+ const int16x8_t C0 = vsraq_n_s16(B1, vqdmulhq_n_s16(B1, kC1), 1);
+ const int16x8_t C1 = vqdmulhq_n_s16(B1, kC2);
+ const int16x4_t a = vqadd_s16(vget_low_s16(rows->val[0]),
+ vget_low_s16(rows->val[1])); // in0 + in8
+ const int16x4_t b = vqsub_s16(vget_low_s16(rows->val[0]),
+ vget_low_s16(rows->val[1])); // in0 - in8
+ // c = kC2 * in4 - kC1 * in12
+ // d = kC1 * in4 + kC2 * in12
+ const int16x4_t c = vqsub_s16(vget_low_s16(C1), vget_high_s16(C0));
+ const int16x4_t d = vqadd_s16(vget_low_s16(C0), vget_high_s16(C1));
+ const int16x8_t D0 = vcombine_s16(a, b); // D0 = a | b
+ const int16x8_t D1 = vcombine_s16(d, c); // D1 = d | c
+ const int16x8_t E0 = vqaddq_s16(D0, D1); // a+d | b+c
+ const int16x8_t E_tmp = vqsubq_s16(D0, D1); // a-d | b-c
+ const int16x8_t E1 = vcombine_s16(vget_high_s16(E_tmp), vget_low_s16(E_tmp));
+ Transpose8x2(E0, E1, rows);
+}
+
+static void ITransformOne(const uint8_t* ref,
+ const int16_t* in, uint8_t* dst) {
+ int16x8x2_t rows;
+ INIT_VECTOR2(rows, vld1q_s16(in + 0), vld1q_s16(in + 8));
+ TransformPass(&rows);
+ TransformPass(&rows);
+ Add4x4(rows.val[0], rows.val[1], ref, dst);
+}
+
+#else
+
+static void ITransformOne(const uint8_t* ref,
+ const int16_t* in, uint8_t* dst) {
+ const int kBPS = BPS;
+ const int16_t kC1C2[] = { kC1, kC2, 0, 0 };
+
+ __asm__ volatile (
+ "vld1.16 {q1, q2}, [%[in]] \n"
+ "vld1.16 {d0}, [%[kC1C2]] \n"
+
+ // d2: in[0]
+ // d3: in[8]
+ // d4: in[4]
+ // d5: in[12]
+ "vswp d3, d4 \n"
+
+ // q8 = {in[4], in[12]} * kC1 * 2 >> 16
+ // q9 = {in[4], in[12]} * kC2 >> 16
+ "vqdmulh.s16 q8, q2, d0[0] \n"
+ "vqdmulh.s16 q9, q2, d0[1] \n"
+
+ // d22 = a = in[0] + in[8]
+ // d23 = b = in[0] - in[8]
+ "vqadd.s16 d22, d2, d3 \n"
+ "vqsub.s16 d23, d2, d3 \n"
+
+ // q8 = in[4]/[12] * kC1 >> 16
+ "vshr.s16 q8, q8, #1 \n"
+
+ // Add {in[4], in[12]} back after the multiplication.
+ "vqadd.s16 q8, q2, q8 \n"
+
+ // d20 = c = in[4]*kC2 - in[12]*kC1
+ // d21 = d = in[4]*kC1 + in[12]*kC2
+ "vqsub.s16 d20, d18, d17 \n"
+ "vqadd.s16 d21, d19, d16 \n"
+
+ // d2 = tmp[0] = a + d
+ // d3 = tmp[1] = b + c
+ // d4 = tmp[2] = b - c
+ // d5 = tmp[3] = a - d
+ "vqadd.s16 d2, d22, d21 \n"
+ "vqadd.s16 d3, d23, d20 \n"
+ "vqsub.s16 d4, d23, d20 \n"
+ "vqsub.s16 d5, d22, d21 \n"
+
+ "vzip.16 q1, q2 \n"
+ "vzip.16 q1, q2 \n"
+
+ "vswp d3, d4 \n"
+
+ // q8 = {tmp[4], tmp[12]} * kC1 * 2 >> 16
+ // q9 = {tmp[4], tmp[12]} * kC2 >> 16
+ "vqdmulh.s16 q8, q2, d0[0] \n"
+ "vqdmulh.s16 q9, q2, d0[1] \n"
+
+ // d22 = a = tmp[0] + tmp[8]
+ // d23 = b = tmp[0] - tmp[8]
+ "vqadd.s16 d22, d2, d3 \n"
+ "vqsub.s16 d23, d2, d3 \n"
+
+ "vshr.s16 q8, q8, #1 \n"
+ "vqadd.s16 q8, q2, q8 \n"
+
+ // d20 = c = in[4]*kC2 - in[12]*kC1
+ // d21 = d = in[4]*kC1 + in[12]*kC2
+ "vqsub.s16 d20, d18, d17 \n"
+ "vqadd.s16 d21, d19, d16 \n"
+
+ // d2 = tmp[0] = a + d
+ // d3 = tmp[1] = b + c
+ // d4 = tmp[2] = b - c
+ // d5 = tmp[3] = a - d
+ "vqadd.s16 d2, d22, d21 \n"
+ "vqadd.s16 d3, d23, d20 \n"
+ "vqsub.s16 d4, d23, d20 \n"
+ "vqsub.s16 d5, d22, d21 \n"
+
+ "vld1.32 d6[0], [%[ref]], %[kBPS] \n"
+ "vld1.32 d6[1], [%[ref]], %[kBPS] \n"
+ "vld1.32 d7[0], [%[ref]], %[kBPS] \n"
+ "vld1.32 d7[1], [%[ref]], %[kBPS] \n"
+
+ "sub %[ref], %[ref], %[kBPS], lsl #2 \n"
+
+ // (val) + 4 >> 3
+ "vrshr.s16 d2, d2, #3 \n"
+ "vrshr.s16 d3, d3, #3 \n"
+ "vrshr.s16 d4, d4, #3 \n"
+ "vrshr.s16 d5, d5, #3 \n"
+
+ "vzip.16 q1, q2 \n"
+ "vzip.16 q1, q2 \n"
+
+ // Must accumulate before saturating
+ "vmovl.u8 q8, d6 \n"
+ "vmovl.u8 q9, d7 \n"
+
+ "vqadd.s16 q1, q1, q8 \n"
+ "vqadd.s16 q2, q2, q9 \n"
+
+ "vqmovun.s16 d0, q1 \n"
+ "vqmovun.s16 d1, q2 \n"
+
+ "vst1.32 d0[0], [%[dst]], %[kBPS] \n"
+ "vst1.32 d0[1], [%[dst]], %[kBPS] \n"
+ "vst1.32 d1[0], [%[dst]], %[kBPS] \n"
+ "vst1.32 d1[1], [%[dst]] \n"
+
+ : [in] "+r"(in), [dst] "+r"(dst) // modified registers
+ : [kBPS] "r"(kBPS), [kC1C2] "r"(kC1C2), [ref] "r"(ref) // constants
+ : "memory", "q0", "q1", "q2", "q8", "q9", "q10", "q11" // clobbered
+ );
+}
+
+#endif // WEBP_USE_INTRINSICS
+
+static void ITransform(const uint8_t* ref,
+ const int16_t* in, uint8_t* dst, int do_two) {
+ ITransformOne(ref, in, dst);
+ if (do_two) {
+ ITransformOne(ref + 4, in + 16, dst + 4);
+ }
+}
+
+// Load all 4x4 pixels into a single uint8x16_t variable.
+static uint8x16_t Load4x4(const uint8_t* src) {
+ uint32x4_t out = vdupq_n_u32(0);
+ out = vld1q_lane_u32((const uint32_t*)(src + 0 * BPS), out, 0);
+ out = vld1q_lane_u32((const uint32_t*)(src + 1 * BPS), out, 1);
+ out = vld1q_lane_u32((const uint32_t*)(src + 2 * BPS), out, 2);
+ out = vld1q_lane_u32((const uint32_t*)(src + 3 * BPS), out, 3);
+ return vreinterpretq_u8_u32(out);
+}
+
+// Forward transform.
+
+#if defined(WEBP_USE_INTRINSICS)
+
+static WEBP_INLINE void Transpose4x4_S16(const int16x4_t A, const int16x4_t B,
+ const int16x4_t C, const int16x4_t D,
+ int16x8_t* const out01,
+ int16x8_t* const out32) {
+ const int16x4x2_t AB = vtrn_s16(A, B);
+ const int16x4x2_t CD = vtrn_s16(C, D);
+ const int32x2x2_t tmp02 = vtrn_s32(vreinterpret_s32_s16(AB.val[0]),
+ vreinterpret_s32_s16(CD.val[0]));
+ const int32x2x2_t tmp13 = vtrn_s32(vreinterpret_s32_s16(AB.val[1]),
+ vreinterpret_s32_s16(CD.val[1]));
+ *out01 = vreinterpretq_s16_s64(
+ vcombine_s64(vreinterpret_s64_s32(tmp02.val[0]),
+ vreinterpret_s64_s32(tmp13.val[0])));
+ *out32 = vreinterpretq_s16_s64(
+ vcombine_s64(vreinterpret_s64_s32(tmp13.val[1]),
+ vreinterpret_s64_s32(tmp02.val[1])));
+}
+
+static WEBP_INLINE int16x8_t DiffU8ToS16(const uint8x8_t a,
+ const uint8x8_t b) {
+ return vreinterpretq_s16_u16(vsubl_u8(a, b));
+}
+
+static void FTransform(const uint8_t* src, const uint8_t* ref,
+ int16_t* out) {
+ int16x8_t d0d1, d3d2; // working 4x4 int16 variables
+ {
+ const uint8x16_t S0 = Load4x4(src);
+ const uint8x16_t R0 = Load4x4(ref);
+ const int16x8_t D0D1 = DiffU8ToS16(vget_low_u8(S0), vget_low_u8(R0));
+ const int16x8_t D2D3 = DiffU8ToS16(vget_high_u8(S0), vget_high_u8(R0));
+ const int16x4_t D0 = vget_low_s16(D0D1);
+ const int16x4_t D1 = vget_high_s16(D0D1);
+ const int16x4_t D2 = vget_low_s16(D2D3);
+ const int16x4_t D3 = vget_high_s16(D2D3);
+ Transpose4x4_S16(D0, D1, D2, D3, &d0d1, &d3d2);
+ }
+ { // 1rst pass
+ const int32x4_t kCst937 = vdupq_n_s32(937);
+ const int32x4_t kCst1812 = vdupq_n_s32(1812);
+ const int16x8_t a0a1 = vaddq_s16(d0d1, d3d2); // d0+d3 | d1+d2 (=a0|a1)
+ const int16x8_t a3a2 = vsubq_s16(d0d1, d3d2); // d0-d3 | d1-d2 (=a3|a2)
+ const int16x8_t a0a1_2 = vshlq_n_s16(a0a1, 3);
+ const int16x4_t tmp0 = vadd_s16(vget_low_s16(a0a1_2),
+ vget_high_s16(a0a1_2));
+ const int16x4_t tmp2 = vsub_s16(vget_low_s16(a0a1_2),
+ vget_high_s16(a0a1_2));
+ const int32x4_t a3_2217 = vmull_n_s16(vget_low_s16(a3a2), 2217);
+ const int32x4_t a2_2217 = vmull_n_s16(vget_high_s16(a3a2), 2217);
+ const int32x4_t a2_p_a3 = vmlal_n_s16(a2_2217, vget_low_s16(a3a2), 5352);
+ const int32x4_t a3_m_a2 = vmlsl_n_s16(a3_2217, vget_high_s16(a3a2), 5352);
+ const int16x4_t tmp1 = vshrn_n_s32(vaddq_s32(a2_p_a3, kCst1812), 9);
+ const int16x4_t tmp3 = vshrn_n_s32(vaddq_s32(a3_m_a2, kCst937), 9);
+ Transpose4x4_S16(tmp0, tmp1, tmp2, tmp3, &d0d1, &d3d2);
+ }
+ { // 2nd pass
+ // the (1<<16) addition is for the replacement: a3!=0 <-> 1-(a3==0)
+ const int32x4_t kCst12000 = vdupq_n_s32(12000 + (1 << 16));
+ const int32x4_t kCst51000 = vdupq_n_s32(51000);
+ const int16x8_t a0a1 = vaddq_s16(d0d1, d3d2); // d0+d3 | d1+d2 (=a0|a1)
+ const int16x8_t a3a2 = vsubq_s16(d0d1, d3d2); // d0-d3 | d1-d2 (=a3|a2)
+ const int16x4_t a0_k7 = vadd_s16(vget_low_s16(a0a1), vdup_n_s16(7));
+ const int16x4_t out0 = vshr_n_s16(vadd_s16(a0_k7, vget_high_s16(a0a1)), 4);
+ const int16x4_t out2 = vshr_n_s16(vsub_s16(a0_k7, vget_high_s16(a0a1)), 4);
+ const int32x4_t a3_2217 = vmull_n_s16(vget_low_s16(a3a2), 2217);
+ const int32x4_t a2_2217 = vmull_n_s16(vget_high_s16(a3a2), 2217);
+ const int32x4_t a2_p_a3 = vmlal_n_s16(a2_2217, vget_low_s16(a3a2), 5352);
+ const int32x4_t a3_m_a2 = vmlsl_n_s16(a3_2217, vget_high_s16(a3a2), 5352);
+ const int16x4_t tmp1 = vaddhn_s32(a2_p_a3, kCst12000);
+ const int16x4_t out3 = vaddhn_s32(a3_m_a2, kCst51000);
+ const int16x4_t a3_eq_0 =
+ vreinterpret_s16_u16(vceq_s16(vget_low_s16(a3a2), vdup_n_s16(0)));
+ const int16x4_t out1 = vadd_s16(tmp1, a3_eq_0);
+ vst1_s16(out + 0, out0);
+ vst1_s16(out + 4, out1);
+ vst1_s16(out + 8, out2);
+ vst1_s16(out + 12, out3);
+ }
+}
+
+#else
+
+// adapted from vp8/encoder/arm/neon/shortfdct_neon.asm
+static const int16_t kCoeff16[] = {
+ 5352, 5352, 5352, 5352, 2217, 2217, 2217, 2217
+};
+static const int32_t kCoeff32[] = {
+ 1812, 1812, 1812, 1812,
+ 937, 937, 937, 937,
+ 12000, 12000, 12000, 12000,
+ 51000, 51000, 51000, 51000
+};
+
+static void FTransform(const uint8_t* src, const uint8_t* ref,
+ int16_t* out) {
+ const int kBPS = BPS;
+ const uint8_t* src_ptr = src;
+ const uint8_t* ref_ptr = ref;
+ const int16_t* coeff16 = kCoeff16;
+ const int32_t* coeff32 = kCoeff32;
+
+ __asm__ volatile (
+ // load src into q4, q5 in high half
+ "vld1.8 {d8}, [%[src_ptr]], %[kBPS] \n"
+ "vld1.8 {d10}, [%[src_ptr]], %[kBPS] \n"
+ "vld1.8 {d9}, [%[src_ptr]], %[kBPS] \n"
+ "vld1.8 {d11}, [%[src_ptr]] \n"
+
+ // load ref into q6, q7 in high half
+ "vld1.8 {d12}, [%[ref_ptr]], %[kBPS] \n"
+ "vld1.8 {d14}, [%[ref_ptr]], %[kBPS] \n"
+ "vld1.8 {d13}, [%[ref_ptr]], %[kBPS] \n"
+ "vld1.8 {d15}, [%[ref_ptr]] \n"
+
+ // Pack the high values in to q4 and q6
+ "vtrn.32 q4, q5 \n"
+ "vtrn.32 q6, q7 \n"
+
+ // d[0-3] = src - ref
+ "vsubl.u8 q0, d8, d12 \n"
+ "vsubl.u8 q1, d9, d13 \n"
+
+ // load coeff16 into q8(d16=5352, d17=2217)
+ "vld1.16 {q8}, [%[coeff16]] \n"
+
+ // load coeff32 high half into q9 = 1812, q10 = 937
+ "vld1.32 {q9, q10}, [%[coeff32]]! \n"
+
+ // load coeff32 low half into q11=12000, q12=51000
+ "vld1.32 {q11,q12}, [%[coeff32]] \n"
+
+ // part 1
+ // Transpose. Register dN is the same as dN in C
+ "vtrn.32 d0, d2 \n"
+ "vtrn.32 d1, d3 \n"
+ "vtrn.16 d0, d1 \n"
+ "vtrn.16 d2, d3 \n"
+
+ "vadd.s16 d4, d0, d3 \n" // a0 = d0 + d3
+ "vadd.s16 d5, d1, d2 \n" // a1 = d1 + d2
+ "vsub.s16 d6, d1, d2 \n" // a2 = d1 - d2
+ "vsub.s16 d7, d0, d3 \n" // a3 = d0 - d3
+
+ "vadd.s16 d0, d4, d5 \n" // a0 + a1
+ "vshl.s16 d0, d0, #3 \n" // temp[0+i*4] = (a0+a1) << 3
+ "vsub.s16 d2, d4, d5 \n" // a0 - a1
+ "vshl.s16 d2, d2, #3 \n" // (temp[2+i*4] = (a0-a1) << 3
+
+ "vmlal.s16 q9, d7, d16 \n" // a3*5352 + 1812
+ "vmlal.s16 q10, d7, d17 \n" // a3*2217 + 937
+ "vmlal.s16 q9, d6, d17 \n" // a2*2217 + a3*5352 + 1812
+ "vmlsl.s16 q10, d6, d16 \n" // a3*2217 + 937 - a2*5352
+
+ // temp[1+i*4] = (d2*2217 + d3*5352 + 1812) >> 9
+ // temp[3+i*4] = (d3*2217 + 937 - d2*5352) >> 9
+ "vshrn.s32 d1, q9, #9 \n"
+ "vshrn.s32 d3, q10, #9 \n"
+
+ // part 2
+ // transpose d0=ip[0], d1=ip[4], d2=ip[8], d3=ip[12]
+ "vtrn.32 d0, d2 \n"
+ "vtrn.32 d1, d3 \n"
+ "vtrn.16 d0, d1 \n"
+ "vtrn.16 d2, d3 \n"
+
+ "vmov.s16 d26, #7 \n"
+
+ "vadd.s16 d4, d0, d3 \n" // a1 = ip[0] + ip[12]
+ "vadd.s16 d5, d1, d2 \n" // b1 = ip[4] + ip[8]
+ "vsub.s16 d6, d1, d2 \n" // c1 = ip[4] - ip[8]
+ "vadd.s16 d4, d4, d26 \n" // a1 + 7
+ "vsub.s16 d7, d0, d3 \n" // d1 = ip[0] - ip[12]
+
+ "vadd.s16 d0, d4, d5 \n" // op[0] = a1 + b1 + 7
+ "vsub.s16 d2, d4, d5 \n" // op[8] = a1 - b1 + 7
+
+ "vmlal.s16 q11, d7, d16 \n" // d1*5352 + 12000
+ "vmlal.s16 q12, d7, d17 \n" // d1*2217 + 51000
+
+ "vceq.s16 d4, d7, #0 \n"
+
+ "vshr.s16 d0, d0, #4 \n"
+ "vshr.s16 d2, d2, #4 \n"
+
+ "vmlal.s16 q11, d6, d17 \n" // c1*2217 + d1*5352 + 12000
+ "vmlsl.s16 q12, d6, d16 \n" // d1*2217 - c1*5352 + 51000
+
+ "vmvn d4, d4 \n" // !(d1 == 0)
+ // op[4] = (c1*2217 + d1*5352 + 12000)>>16
+ "vshrn.s32 d1, q11, #16 \n"
+ // op[4] += (d1!=0)
+ "vsub.s16 d1, d1, d4 \n"
+ // op[12]= (d1*2217 - c1*5352 + 51000)>>16
+ "vshrn.s32 d3, q12, #16 \n"
+
+ // set result to out array
+ "vst1.16 {q0, q1}, [%[out]] \n"
+ : [src_ptr] "+r"(src_ptr), [ref_ptr] "+r"(ref_ptr),
+ [coeff32] "+r"(coeff32) // modified registers
+ : [kBPS] "r"(kBPS), [coeff16] "r"(coeff16),
+ [out] "r"(out) // constants
+ : "memory", "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", "q8", "q9",
+ "q10", "q11", "q12", "q13" // clobbered
+ );
+}
+
+#endif
+
+#define LOAD_LANE_16b(VALUE, LANE) do { \
+ (VALUE) = vld1_lane_s16(src, (VALUE), (LANE)); \
+ src += stride; \
+} while (0)
+
+static void FTransformWHT(const int16_t* src, int16_t* out) {
+ const int stride = 16;
+ const int16x4_t zero = vdup_n_s16(0);
+ int32x4x4_t tmp0;
+ int16x4x4_t in;
+ INIT_VECTOR4(in, zero, zero, zero, zero);
+ LOAD_LANE_16b(in.val[0], 0);
+ LOAD_LANE_16b(in.val[1], 0);
+ LOAD_LANE_16b(in.val[2], 0);
+ LOAD_LANE_16b(in.val[3], 0);
+ LOAD_LANE_16b(in.val[0], 1);
+ LOAD_LANE_16b(in.val[1], 1);
+ LOAD_LANE_16b(in.val[2], 1);
+ LOAD_LANE_16b(in.val[3], 1);
+ LOAD_LANE_16b(in.val[0], 2);
+ LOAD_LANE_16b(in.val[1], 2);
+ LOAD_LANE_16b(in.val[2], 2);
+ LOAD_LANE_16b(in.val[3], 2);
+ LOAD_LANE_16b(in.val[0], 3);
+ LOAD_LANE_16b(in.val[1], 3);
+ LOAD_LANE_16b(in.val[2], 3);
+ LOAD_LANE_16b(in.val[3], 3);
+
+ {
+ // a0 = in[0 * 16] + in[2 * 16]
+ // a1 = in[1 * 16] + in[3 * 16]
+ // a2 = in[1 * 16] - in[3 * 16]
+ // a3 = in[0 * 16] - in[2 * 16]
+ const int32x4_t a0 = vaddl_s16(in.val[0], in.val[2]);
+ const int32x4_t a1 = vaddl_s16(in.val[1], in.val[3]);
+ const int32x4_t a2 = vsubl_s16(in.val[1], in.val[3]);
+ const int32x4_t a3 = vsubl_s16(in.val[0], in.val[2]);
+ tmp0.val[0] = vaddq_s32(a0, a1);
+ tmp0.val[1] = vaddq_s32(a3, a2);
+ tmp0.val[2] = vsubq_s32(a3, a2);
+ tmp0.val[3] = vsubq_s32(a0, a1);
+ }
+ {
+ const int32x4x4_t tmp1 = Transpose4x4(tmp0);
+ // a0 = tmp[0 + i] + tmp[ 8 + i]
+ // a1 = tmp[4 + i] + tmp[12 + i]
+ // a2 = tmp[4 + i] - tmp[12 + i]
+ // a3 = tmp[0 + i] - tmp[ 8 + i]
+ const int32x4_t a0 = vaddq_s32(tmp1.val[0], tmp1.val[2]);
+ const int32x4_t a1 = vaddq_s32(tmp1.val[1], tmp1.val[3]);
+ const int32x4_t a2 = vsubq_s32(tmp1.val[1], tmp1.val[3]);
+ const int32x4_t a3 = vsubq_s32(tmp1.val[0], tmp1.val[2]);
+ const int32x4_t b0 = vhaddq_s32(a0, a1); // (a0 + a1) >> 1
+ const int32x4_t b1 = vhaddq_s32(a3, a2); // (a3 + a2) >> 1
+ const int32x4_t b2 = vhsubq_s32(a3, a2); // (a3 - a2) >> 1
+ const int32x4_t b3 = vhsubq_s32(a0, a1); // (a0 - a1) >> 1
+ const int16x4_t out0 = vmovn_s32(b0);
+ const int16x4_t out1 = vmovn_s32(b1);
+ const int16x4_t out2 = vmovn_s32(b2);
+ const int16x4_t out3 = vmovn_s32(b3);
+
+ vst1_s16(out + 0, out0);
+ vst1_s16(out + 4, out1);
+ vst1_s16(out + 8, out2);
+ vst1_s16(out + 12, out3);
+ }
+}
+#undef LOAD_LANE_16b
+
+//------------------------------------------------------------------------------
+// Texture distortion
+//
+// We try to match the spectral content (weighted) between source and
+// reconstructed samples.
+
+// a 0123, b 0123
+// a 4567, b 4567
+// a 89ab, b 89ab
+// a cdef, b cdef
+//
+// transpose
+//
+// a 048c, b 048c
+// a 159d, b 159d
+// a 26ae, b 26ae
+// a 37bf, b 37bf
+//
+static WEBP_INLINE uint8x8x4_t DistoTranspose4x4U8(uint8x8x4_t d4_in) {
+ const uint8x8x2_t d2_tmp0 = vtrn_u8(d4_in.val[0], d4_in.val[1]);
+ const uint8x8x2_t d2_tmp1 = vtrn_u8(d4_in.val[2], d4_in.val[3]);
+ const uint16x4x2_t d2_tmp2 = vtrn_u16(vreinterpret_u16_u8(d2_tmp0.val[0]),
+ vreinterpret_u16_u8(d2_tmp1.val[0]));
+ const uint16x4x2_t d2_tmp3 = vtrn_u16(vreinterpret_u16_u8(d2_tmp0.val[1]),
+ vreinterpret_u16_u8(d2_tmp1.val[1]));
+
+ d4_in.val[0] = vreinterpret_u8_u16(d2_tmp2.val[0]);
+ d4_in.val[2] = vreinterpret_u8_u16(d2_tmp2.val[1]);
+ d4_in.val[1] = vreinterpret_u8_u16(d2_tmp3.val[0]);
+ d4_in.val[3] = vreinterpret_u8_u16(d2_tmp3.val[1]);
+ return d4_in;
+}
+
+static WEBP_INLINE int16x8x4_t DistoTranspose4x4S16(int16x8x4_t q4_in) {
+ const int16x8x2_t q2_tmp0 = vtrnq_s16(q4_in.val[0], q4_in.val[1]);
+ const int16x8x2_t q2_tmp1 = vtrnq_s16(q4_in.val[2], q4_in.val[3]);
+ const int32x4x2_t q2_tmp2 = vtrnq_s32(vreinterpretq_s32_s16(q2_tmp0.val[0]),
+ vreinterpretq_s32_s16(q2_tmp1.val[0]));
+ const int32x4x2_t q2_tmp3 = vtrnq_s32(vreinterpretq_s32_s16(q2_tmp0.val[1]),
+ vreinterpretq_s32_s16(q2_tmp1.val[1]));
+ q4_in.val[0] = vreinterpretq_s16_s32(q2_tmp2.val[0]);
+ q4_in.val[2] = vreinterpretq_s16_s32(q2_tmp2.val[1]);
+ q4_in.val[1] = vreinterpretq_s16_s32(q2_tmp3.val[0]);
+ q4_in.val[3] = vreinterpretq_s16_s32(q2_tmp3.val[1]);
+ return q4_in;
+}
+
+static WEBP_INLINE int16x8x4_t DistoHorizontalPass(const uint8x8x4_t d4_in) {
+ // {a0, a1} = {in[0] + in[2], in[1] + in[3]}
+ // {a3, a2} = {in[0] - in[2], in[1] - in[3]}
+ const int16x8_t q_a0 = vreinterpretq_s16_u16(vaddl_u8(d4_in.val[0],
+ d4_in.val[2]));
+ const int16x8_t q_a1 = vreinterpretq_s16_u16(vaddl_u8(d4_in.val[1],
+ d4_in.val[3]));
+ const int16x8_t q_a3 = vreinterpretq_s16_u16(vsubl_u8(d4_in.val[0],
+ d4_in.val[2]));
+ const int16x8_t q_a2 = vreinterpretq_s16_u16(vsubl_u8(d4_in.val[1],
+ d4_in.val[3]));
+ int16x8x4_t q4_out;
+ // tmp[0] = a0 + a1
+ // tmp[1] = a3 + a2
+ // tmp[2] = a3 - a2
+ // tmp[3] = a0 - a1
+ INIT_VECTOR4(q4_out,
+ vaddq_s16(q_a0, q_a1), vaddq_s16(q_a3, q_a2),
+ vsubq_s16(q_a3, q_a2), vsubq_s16(q_a0, q_a1));
+ return q4_out;
+}
+
+static WEBP_INLINE int16x8x4_t DistoVerticalPass(int16x8x4_t q4_in) {
+ const int16x8_t q_a0 = vaddq_s16(q4_in.val[0], q4_in.val[2]);
+ const int16x8_t q_a1 = vaddq_s16(q4_in.val[1], q4_in.val[3]);
+ const int16x8_t q_a2 = vsubq_s16(q4_in.val[1], q4_in.val[3]);
+ const int16x8_t q_a3 = vsubq_s16(q4_in.val[0], q4_in.val[2]);
+
+ q4_in.val[0] = vaddq_s16(q_a0, q_a1);
+ q4_in.val[1] = vaddq_s16(q_a3, q_a2);
+ q4_in.val[2] = vabdq_s16(q_a3, q_a2);
+ q4_in.val[3] = vabdq_s16(q_a0, q_a1);
+ q4_in.val[0] = vabsq_s16(q4_in.val[0]);
+ q4_in.val[1] = vabsq_s16(q4_in.val[1]);
+ return q4_in;
+}
+
+static WEBP_INLINE int16x4x4_t DistoLoadW(const uint16_t* w) {
+ const uint16x8_t q_w07 = vld1q_u16(&w[0]);
+ const uint16x8_t q_w8f = vld1q_u16(&w[8]);
+ int16x4x4_t d4_w;
+ INIT_VECTOR4(d4_w,
+ vget_low_s16(vreinterpretq_s16_u16(q_w07)),
+ vget_high_s16(vreinterpretq_s16_u16(q_w07)),
+ vget_low_s16(vreinterpretq_s16_u16(q_w8f)),
+ vget_high_s16(vreinterpretq_s16_u16(q_w8f)));
+ return d4_w;
+}
+
+static WEBP_INLINE int32x2_t DistoSum(const int16x8x4_t q4_in,
+ const int16x4x4_t d4_w) {
+ int32x2_t d_sum;
+ // sum += w[ 0] * abs(b0);
+ // sum += w[ 4] * abs(b1);
+ // sum += w[ 8] * abs(b2);
+ // sum += w[12] * abs(b3);
+ int32x4_t q_sum0 = vmull_s16(d4_w.val[0], vget_low_s16(q4_in.val[0]));
+ int32x4_t q_sum1 = vmull_s16(d4_w.val[1], vget_low_s16(q4_in.val[1]));
+ int32x4_t q_sum2 = vmull_s16(d4_w.val[2], vget_low_s16(q4_in.val[2]));
+ int32x4_t q_sum3 = vmull_s16(d4_w.val[3], vget_low_s16(q4_in.val[3]));
+ q_sum0 = vmlsl_s16(q_sum0, d4_w.val[0], vget_high_s16(q4_in.val[0]));
+ q_sum1 = vmlsl_s16(q_sum1, d4_w.val[1], vget_high_s16(q4_in.val[1]));
+ q_sum2 = vmlsl_s16(q_sum2, d4_w.val[2], vget_high_s16(q4_in.val[2]));
+ q_sum3 = vmlsl_s16(q_sum3, d4_w.val[3], vget_high_s16(q4_in.val[3]));
+
+ q_sum0 = vaddq_s32(q_sum0, q_sum1);
+ q_sum2 = vaddq_s32(q_sum2, q_sum3);
+ q_sum2 = vaddq_s32(q_sum0, q_sum2);
+ d_sum = vpadd_s32(vget_low_s32(q_sum2), vget_high_s32(q_sum2));
+ d_sum = vpadd_s32(d_sum, d_sum);
+ return d_sum;
+}
+
+#define LOAD_LANE_32b(src, VALUE, LANE) \
+ (VALUE) = vld1_lane_u32((const uint32_t*)(src), (VALUE), (LANE))
+
+// Hadamard transform
+// Returns the weighted sum of the absolute value of transformed coefficients.
+static int Disto4x4(const uint8_t* const a, const uint8_t* const b,
+ const uint16_t* const w) {
+ uint32x2_t d_in_ab_0123 = vdup_n_u32(0);
+ uint32x2_t d_in_ab_4567 = vdup_n_u32(0);
+ uint32x2_t d_in_ab_89ab = vdup_n_u32(0);
+ uint32x2_t d_in_ab_cdef = vdup_n_u32(0);
+ uint8x8x4_t d4_in;
+
+ // load data a, b
+ LOAD_LANE_32b(a + 0 * BPS, d_in_ab_0123, 0);
+ LOAD_LANE_32b(a + 1 * BPS, d_in_ab_4567, 0);
+ LOAD_LANE_32b(a + 2 * BPS, d_in_ab_89ab, 0);
+ LOAD_LANE_32b(a + 3 * BPS, d_in_ab_cdef, 0);
+ LOAD_LANE_32b(b + 0 * BPS, d_in_ab_0123, 1);
+ LOAD_LANE_32b(b + 1 * BPS, d_in_ab_4567, 1);
+ LOAD_LANE_32b(b + 2 * BPS, d_in_ab_89ab, 1);
+ LOAD_LANE_32b(b + 3 * BPS, d_in_ab_cdef, 1);
+ INIT_VECTOR4(d4_in,
+ vreinterpret_u8_u32(d_in_ab_0123),
+ vreinterpret_u8_u32(d_in_ab_4567),
+ vreinterpret_u8_u32(d_in_ab_89ab),
+ vreinterpret_u8_u32(d_in_ab_cdef));
+
+ {
+ // horizontal pass
+ const uint8x8x4_t d4_t = DistoTranspose4x4U8(d4_in);
+ const int16x8x4_t q4_h = DistoHorizontalPass(d4_t);
+ const int16x4x4_t d4_w = DistoLoadW(w);
+ // vertical pass
+ const int16x8x4_t q4_t = DistoTranspose4x4S16(q4_h);
+ const int16x8x4_t q4_v = DistoVerticalPass(q4_t);
+ int32x2_t d_sum = DistoSum(q4_v, d4_w);
+
+ // abs(sum2 - sum1) >> 5
+ d_sum = vabs_s32(d_sum);
+ d_sum = vshr_n_s32(d_sum, 5);
+ return vget_lane_s32(d_sum, 0);
+ }
+}
+#undef LOAD_LANE_32b
+
+static int Disto16x16(const uint8_t* const a, const uint8_t* const b,
+ const uint16_t* const w) {
+ int D = 0;
+ int x, y;
+ for (y = 0; y < 16 * BPS; y += 4 * BPS) {
+ for (x = 0; x < 16; x += 4) {
+ D += Disto4x4(a + x + y, b + x + y, w);
+ }
+ }
+ return D;
+}
+
+//------------------------------------------------------------------------------
+
+static void CollectHistogram(const uint8_t* ref, const uint8_t* pred,
+ int start_block, int end_block,
+ VP8Histogram* const histo) {
+ const uint16x8_t max_coeff_thresh = vdupq_n_u16(MAX_COEFF_THRESH);
+ int j;
+ int distribution[MAX_COEFF_THRESH + 1] = { 0 };
+ for (j = start_block; j < end_block; ++j) {
+ int16_t out[16];
+ FTransform(ref + VP8DspScan[j], pred + VP8DspScan[j], out);
+ {
+ int k;
+ const int16x8_t a0 = vld1q_s16(out + 0);
+ const int16x8_t b0 = vld1q_s16(out + 8);
+ const uint16x8_t a1 = vreinterpretq_u16_s16(vabsq_s16(a0));
+ const uint16x8_t b1 = vreinterpretq_u16_s16(vabsq_s16(b0));
+ const uint16x8_t a2 = vshrq_n_u16(a1, 3);
+ const uint16x8_t b2 = vshrq_n_u16(b1, 3);
+ const uint16x8_t a3 = vminq_u16(a2, max_coeff_thresh);
+ const uint16x8_t b3 = vminq_u16(b2, max_coeff_thresh);
+ vst1q_s16(out + 0, vreinterpretq_s16_u16(a3));
+ vst1q_s16(out + 8, vreinterpretq_s16_u16(b3));
+ // Convert coefficients to bin.
+ for (k = 0; k < 16; ++k) {
+ ++distribution[out[k]];
+ }
+ }
+ }
+ VP8SetHistogramData(distribution, histo);
+}
+
+//------------------------------------------------------------------------------
+
+static WEBP_INLINE void AccumulateSSE16(const uint8_t* const a,
+ const uint8_t* const b,
+ uint32x4_t* const sum) {
+ const uint8x16_t a0 = vld1q_u8(a);
+ const uint8x16_t b0 = vld1q_u8(b);
+ const uint8x16_t abs_diff = vabdq_u8(a0, b0);
+ uint16x8_t prod = vmull_u8(vget_low_u8(abs_diff), vget_low_u8(abs_diff));
+ prod = vmlal_u8(prod, vget_high_u8(abs_diff), vget_high_u8(abs_diff));
+ *sum = vpadalq_u16(*sum, prod); // pair-wise add and accumulate
+}
+
+// Horizontal sum of all four uint32_t values in 'sum'.
+static int SumToInt(uint32x4_t sum) {
+ const uint64x2_t sum2 = vpaddlq_u32(sum);
+ const uint64_t sum3 = vgetq_lane_u64(sum2, 0) + vgetq_lane_u64(sum2, 1);
+ return (int)sum3;
+}
+
+static int SSE16x16(const uint8_t* a, const uint8_t* b) {
+ uint32x4_t sum = vdupq_n_u32(0);
+ int y;
+ for (y = 0; y < 16; ++y) {
+ AccumulateSSE16(a + y * BPS, b + y * BPS, &sum);
+ }
+ return SumToInt(sum);
+}
+
+static int SSE16x8(const uint8_t* a, const uint8_t* b) {
+ uint32x4_t sum = vdupq_n_u32(0);
+ int y;
+ for (y = 0; y < 8; ++y) {
+ AccumulateSSE16(a + y * BPS, b + y * BPS, &sum);
+ }
+ return SumToInt(sum);
+}
+
+static int SSE8x8(const uint8_t* a, const uint8_t* b) {
+ uint32x4_t sum = vdupq_n_u32(0);
+ int y;
+ for (y = 0; y < 8; ++y) {
+ const uint8x8_t a0 = vld1_u8(a + y * BPS);
+ const uint8x8_t b0 = vld1_u8(b + y * BPS);
+ const uint8x8_t abs_diff = vabd_u8(a0, b0);
+ const uint16x8_t prod = vmull_u8(abs_diff, abs_diff);
+ sum = vpadalq_u16(sum, prod);
+ }
+ return SumToInt(sum);
+}
+
+static int SSE4x4(const uint8_t* a, const uint8_t* b) {
+ const uint8x16_t a0 = Load4x4(a);
+ const uint8x16_t b0 = Load4x4(b);
+ const uint8x16_t abs_diff = vabdq_u8(a0, b0);
+ uint16x8_t prod = vmull_u8(vget_low_u8(abs_diff), vget_low_u8(abs_diff));
+ prod = vmlal_u8(prod, vget_high_u8(abs_diff), vget_high_u8(abs_diff));
+ return SumToInt(vpaddlq_u16(prod));
+}
+
+//------------------------------------------------------------------------------
+
+// Compilation with gcc-4.6.x is problematic for now.
+#if !defined(WORK_AROUND_GCC)
+
+static int16x8_t Quantize(int16_t* const in,
+ const VP8Matrix* const mtx, int offset) {
+ const uint16x8_t sharp = vld1q_u16(&mtx->sharpen_[offset]);
+ const uint16x8_t q = vld1q_u16(&mtx->q_[offset]);
+ const uint16x8_t iq = vld1q_u16(&mtx->iq_[offset]);
+ const uint32x4_t bias0 = vld1q_u32(&mtx->bias_[offset + 0]);
+ const uint32x4_t bias1 = vld1q_u32(&mtx->bias_[offset + 4]);
+
+ const int16x8_t a = vld1q_s16(in + offset); // in
+ const uint16x8_t b = vreinterpretq_u16_s16(vabsq_s16(a)); // coeff = abs(in)
+ const int16x8_t sign = vshrq_n_s16(a, 15); // sign
+ const uint16x8_t c = vaddq_u16(b, sharp); // + sharpen
+ const uint32x4_t m0 = vmull_u16(vget_low_u16(c), vget_low_u16(iq));
+ const uint32x4_t m1 = vmull_u16(vget_high_u16(c), vget_high_u16(iq));
+ const uint32x4_t m2 = vhaddq_u32(m0, bias0);
+ const uint32x4_t m3 = vhaddq_u32(m1, bias1); // (coeff * iQ + bias) >> 1
+ const uint16x8_t c0 = vcombine_u16(vshrn_n_u32(m2, 16),
+ vshrn_n_u32(m3, 16)); // QFIX=17 = 16+1
+ const uint16x8_t c1 = vminq_u16(c0, vdupq_n_u16(MAX_LEVEL));
+ const int16x8_t c2 = veorq_s16(vreinterpretq_s16_u16(c1), sign);
+ const int16x8_t c3 = vsubq_s16(c2, sign); // restore sign
+ const int16x8_t c4 = vmulq_s16(c3, vreinterpretq_s16_u16(q));
+ vst1q_s16(in + offset, c4);
+ assert(QFIX == 17); // this function can't work as is if QFIX != 16+1
+ return c3;
+}
+
+static const uint8_t kShuffles[4][8] = {
+ { 0, 1, 2, 3, 8, 9, 16, 17 },
+ { 10, 11, 4, 5, 6, 7, 12, 13 },
+ { 18, 19, 24, 25, 26, 27, 20, 21 },
+ { 14, 15, 22, 23, 28, 29, 30, 31 }
+};
+
+static int QuantizeBlock(int16_t in[16], int16_t out[16],
+ const VP8Matrix* const mtx) {
+ const int16x8_t out0 = Quantize(in, mtx, 0);
+ const int16x8_t out1 = Quantize(in, mtx, 8);
+ uint8x8x4_t shuffles;
+ // vtbl?_u8 are marked unavailable for iOS arm64 with Xcode < 6.3, use
+ // non-standard versions there.
+#if defined(__APPLE__) && defined(__aarch64__) && \
+ defined(__apple_build_version__) && (__apple_build_version__< 6020037)
+ uint8x16x2_t all_out;
+ INIT_VECTOR2(all_out, vreinterpretq_u8_s16(out0), vreinterpretq_u8_s16(out1));
+ INIT_VECTOR4(shuffles,
+ vtbl2q_u8(all_out, vld1_u8(kShuffles[0])),
+ vtbl2q_u8(all_out, vld1_u8(kShuffles[1])),
+ vtbl2q_u8(all_out, vld1_u8(kShuffles[2])),
+ vtbl2q_u8(all_out, vld1_u8(kShuffles[3])));
+#else
+ uint8x8x4_t all_out;
+ INIT_VECTOR4(all_out,
+ vreinterpret_u8_s16(vget_low_s16(out0)),
+ vreinterpret_u8_s16(vget_high_s16(out0)),
+ vreinterpret_u8_s16(vget_low_s16(out1)),
+ vreinterpret_u8_s16(vget_high_s16(out1)));
+ INIT_VECTOR4(shuffles,
+ vtbl4_u8(all_out, vld1_u8(kShuffles[0])),
+ vtbl4_u8(all_out, vld1_u8(kShuffles[1])),
+ vtbl4_u8(all_out, vld1_u8(kShuffles[2])),
+ vtbl4_u8(all_out, vld1_u8(kShuffles[3])));
+#endif
+ // Zigzag reordering
+ vst1_u8((uint8_t*)(out + 0), shuffles.val[0]);
+ vst1_u8((uint8_t*)(out + 4), shuffles.val[1]);
+ vst1_u8((uint8_t*)(out + 8), shuffles.val[2]);
+ vst1_u8((uint8_t*)(out + 12), shuffles.val[3]);
+ // test zeros
+ if (*(uint64_t*)(out + 0) != 0) return 1;
+ if (*(uint64_t*)(out + 4) != 0) return 1;
+ if (*(uint64_t*)(out + 8) != 0) return 1;
+ if (*(uint64_t*)(out + 12) != 0) return 1;
+ return 0;
+}
+
+static int Quantize2Blocks(int16_t in[32], int16_t out[32],
+ const VP8Matrix* const mtx) {
+ int nz;
+ nz = QuantizeBlock(in + 0 * 16, out + 0 * 16, mtx) << 0;
+ nz |= QuantizeBlock(in + 1 * 16, out + 1 * 16, mtx) << 1;
+ return nz;
+}
+
+#endif // !WORK_AROUND_GCC
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8EncDspInitNEON(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspInitNEON(void) {
+ VP8ITransform = ITransform;
+ VP8FTransform = FTransform;
+
+ VP8FTransformWHT = FTransformWHT;
+
+ VP8TDisto4x4 = Disto4x4;
+ VP8TDisto16x16 = Disto16x16;
+ VP8CollectHistogram = CollectHistogram;
+ VP8SSE16x16 = SSE16x16;
+ VP8SSE16x8 = SSE16x8;
+ VP8SSE8x8 = SSE8x8;
+ VP8SSE4x4 = SSE4x4;
+#if !defined(WORK_AROUND_GCC)
+ VP8EncQuantizeBlock = QuantizeBlock;
+ VP8EncQuantize2Blocks = Quantize2Blocks;
+#endif
+}
+
+#else // !WEBP_USE_NEON
+
+WEBP_DSP_INIT_STUB(VP8EncDspInitNEON)
+
+#endif // WEBP_USE_NEON
diff --git a/drivers/webp/dsp/enc_sse2.c b/drivers/webp/dsp/enc_sse2.c
index b046761dc1..63d9cecd85 100644
--- a/drivers/webp/dsp/enc_sse2.c
+++ b/drivers/webp/dsp/enc_sse2.c
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// SSE2 version of speed-critical encoding functions.
@@ -15,64 +17,55 @@
#include <stdlib.h> // for abs()
#include <emmintrin.h>
+#include "../enc/cost.h"
#include "../enc/vp8enci.h"
+#include "../utils/utils.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
+//------------------------------------------------------------------------------
+// Quite useful macro for debugging. Left here for convenience.
+
+#if 0
+#include <stdio.h>
+static void PrintReg(const __m128i r, const char* const name, int size) {
+ int n;
+ union {
+ __m128i r;
+ uint8_t i8[16];
+ uint16_t i16[8];
+ uint32_t i32[4];
+ uint64_t i64[2];
+ } tmp;
+ tmp.r = r;
+ fprintf(stderr, "%s\t: ", name);
+ if (size == 8) {
+ for (n = 0; n < 16; ++n) fprintf(stderr, "%.2x ", tmp.i8[n]);
+ } else if (size == 16) {
+ for (n = 0; n < 8; ++n) fprintf(stderr, "%.4x ", tmp.i16[n]);
+ } else if (size == 32) {
+ for (n = 0; n < 4; ++n) fprintf(stderr, "%.8x ", tmp.i32[n]);
+ } else {
+ for (n = 0; n < 2; ++n) fprintf(stderr, "%.16lx ", tmp.i64[n]);
+ }
+ fprintf(stderr, "\n");
+}
#endif
//------------------------------------------------------------------------------
-// Compute susceptibility based on DCT-coeff histograms:
-// the higher, the "easier" the macroblock is to compress.
-
-static int CollectHistogramSSE2(const uint8_t* ref, const uint8_t* pred,
- int start_block, int end_block) {
- int histo[MAX_COEFF_THRESH + 1] = { 0 };
- int16_t out[16];
- int j, k;
- const __m128i max_coeff_thresh = _mm_set1_epi16(MAX_COEFF_THRESH);
- for (j = start_block; j < end_block; ++j) {
- VP8FTransform(ref + VP8DspScan[j], pred + VP8DspScan[j], out);
-
- // Convert coefficients to bin (within out[]).
- {
- // Load.
- const __m128i out0 = _mm_loadu_si128((__m128i*)&out[0]);
- const __m128i out1 = _mm_loadu_si128((__m128i*)&out[8]);
- // sign(out) = out >> 15 (0x0000 if positive, 0xffff if negative)
- const __m128i sign0 = _mm_srai_epi16(out0, 15);
- const __m128i sign1 = _mm_srai_epi16(out1, 15);
- // abs(out) = (out ^ sign) - sign
- const __m128i xor0 = _mm_xor_si128(out0, sign0);
- const __m128i xor1 = _mm_xor_si128(out1, sign1);
- const __m128i abs0 = _mm_sub_epi16(xor0, sign0);
- const __m128i abs1 = _mm_sub_epi16(xor1, sign1);
- // v = abs(out) >> 2
- const __m128i v0 = _mm_srai_epi16(abs0, 2);
- const __m128i v1 = _mm_srai_epi16(abs1, 2);
- // bin = min(v, MAX_COEFF_THRESH)
- const __m128i bin0 = _mm_min_epi16(v0, max_coeff_thresh);
- const __m128i bin1 = _mm_min_epi16(v1, max_coeff_thresh);
- // Store.
- _mm_storeu_si128((__m128i*)&out[0], bin0);
- _mm_storeu_si128((__m128i*)&out[8], bin1);
- }
+// util for unaligned loads.
- // Use bin to update histogram.
- for (k = 0; k < 16; ++k) {
- histo[out[k]]++;
- }
- }
-
- return VP8GetAlpha(histo);
+// memcpy() is the safe way of moving potentially unaligned 32b memory.
+static WEBP_INLINE uint32_t MemToUint32(const uint8_t* const ptr) {
+ uint32_t A;
+ memcpy(&A, (const int*)ptr, sizeof(A));
+ return A;
}
//------------------------------------------------------------------------------
// Transforms (Paragraph 14.4)
// Does one or two inverse transforms.
-static void ITransformSSE2(const uint8_t* ref, const int16_t* in, uint8_t* dst,
- int do_two) {
+static void ITransform(const uint8_t* ref, const int16_t* in, uint8_t* dst,
+ int do_two) {
// This implementation makes use of 16-bit fixed point versions of two
// multiply constants:
// K1 = sqrt(2) * cos (pi/8) ~= 85627 / 2^16
@@ -99,19 +92,19 @@ static void ITransformSSE2(const uint8_t* ref, const int16_t* in, uint8_t* dst,
// use nor store.
__m128i in0, in1, in2, in3;
{
- in0 = _mm_loadl_epi64((__m128i*)&in[0]);
- in1 = _mm_loadl_epi64((__m128i*)&in[4]);
- in2 = _mm_loadl_epi64((__m128i*)&in[8]);
- in3 = _mm_loadl_epi64((__m128i*)&in[12]);
+ in0 = _mm_loadl_epi64((const __m128i*)&in[0]);
+ in1 = _mm_loadl_epi64((const __m128i*)&in[4]);
+ in2 = _mm_loadl_epi64((const __m128i*)&in[8]);
+ in3 = _mm_loadl_epi64((const __m128i*)&in[12]);
// a00 a10 a20 a30 x x x x
// a01 a11 a21 a31 x x x x
// a02 a12 a22 a32 x x x x
// a03 a13 a23 a33 x x x x
if (do_two) {
- const __m128i inB0 = _mm_loadl_epi64((__m128i*)&in[16]);
- const __m128i inB1 = _mm_loadl_epi64((__m128i*)&in[20]);
- const __m128i inB2 = _mm_loadl_epi64((__m128i*)&in[24]);
- const __m128i inB3 = _mm_loadl_epi64((__m128i*)&in[28]);
+ const __m128i inB0 = _mm_loadl_epi64((const __m128i*)&in[16]);
+ const __m128i inB1 = _mm_loadl_epi64((const __m128i*)&in[20]);
+ const __m128i inB2 = _mm_loadl_epi64((const __m128i*)&in[24]);
+ const __m128i inB3 = _mm_loadl_epi64((const __m128i*)&in[28]);
in0 = _mm_unpacklo_epi64(in0, inB0);
in1 = _mm_unpacklo_epi64(in1, inB1);
in2 = _mm_unpacklo_epi64(in2, inB2);
@@ -243,21 +236,21 @@ static void ITransformSSE2(const uint8_t* ref, const int16_t* in, uint8_t* dst,
// Add inverse transform to 'ref' and store.
{
- const __m128i zero = _mm_set1_epi16(0);
+ const __m128i zero = _mm_setzero_si128();
// Load the reference(s).
__m128i ref0, ref1, ref2, ref3;
if (do_two) {
// Load eight bytes/pixels per line.
- ref0 = _mm_loadl_epi64((__m128i*)&ref[0 * BPS]);
- ref1 = _mm_loadl_epi64((__m128i*)&ref[1 * BPS]);
- ref2 = _mm_loadl_epi64((__m128i*)&ref[2 * BPS]);
- ref3 = _mm_loadl_epi64((__m128i*)&ref[3 * BPS]);
+ ref0 = _mm_loadl_epi64((const __m128i*)&ref[0 * BPS]);
+ ref1 = _mm_loadl_epi64((const __m128i*)&ref[1 * BPS]);
+ ref2 = _mm_loadl_epi64((const __m128i*)&ref[2 * BPS]);
+ ref3 = _mm_loadl_epi64((const __m128i*)&ref[3 * BPS]);
} else {
// Load four bytes/pixels per line.
- ref0 = _mm_cvtsi32_si128(*(int*)&ref[0 * BPS]);
- ref1 = _mm_cvtsi32_si128(*(int*)&ref[1 * BPS]);
- ref2 = _mm_cvtsi32_si128(*(int*)&ref[2 * BPS]);
- ref3 = _mm_cvtsi32_si128(*(int*)&ref[3 * BPS]);
+ ref0 = _mm_cvtsi32_si128(MemToUint32(&ref[0 * BPS]));
+ ref1 = _mm_cvtsi32_si128(MemToUint32(&ref[1 * BPS]));
+ ref2 = _mm_cvtsi32_si128(MemToUint32(&ref[2 * BPS]));
+ ref3 = _mm_cvtsi32_si128(MemToUint32(&ref[3 * BPS]));
}
// Convert to 16b.
ref0 = _mm_unpacklo_epi8(ref0, zero);
@@ -291,200 +284,865 @@ static void ITransformSSE2(const uint8_t* ref, const int16_t* in, uint8_t* dst,
}
}
-static void FTransformSSE2(const uint8_t* src, const uint8_t* ref,
- int16_t* out) {
+static void FTransformPass1(const __m128i* const in01,
+ const __m128i* const in23,
+ __m128i* const out01,
+ __m128i* const out32) {
+ const __m128i k937 = _mm_set1_epi32(937);
+ const __m128i k1812 = _mm_set1_epi32(1812);
+
+ const __m128i k88p = _mm_set_epi16(8, 8, 8, 8, 8, 8, 8, 8);
+ const __m128i k88m = _mm_set_epi16(-8, 8, -8, 8, -8, 8, -8, 8);
+ const __m128i k5352_2217p = _mm_set_epi16(2217, 5352, 2217, 5352,
+ 2217, 5352, 2217, 5352);
+ const __m128i k5352_2217m = _mm_set_epi16(-5352, 2217, -5352, 2217,
+ -5352, 2217, -5352, 2217);
+
+ // *in01 = 00 01 10 11 02 03 12 13
+ // *in23 = 20 21 30 31 22 23 32 33
+ const __m128i shuf01_p = _mm_shufflehi_epi16(*in01, _MM_SHUFFLE(2, 3, 0, 1));
+ const __m128i shuf23_p = _mm_shufflehi_epi16(*in23, _MM_SHUFFLE(2, 3, 0, 1));
+ // 00 01 10 11 03 02 13 12
+ // 20 21 30 31 23 22 33 32
+ const __m128i s01 = _mm_unpacklo_epi64(shuf01_p, shuf23_p);
+ const __m128i s32 = _mm_unpackhi_epi64(shuf01_p, shuf23_p);
+ // 00 01 10 11 20 21 30 31
+ // 03 02 13 12 23 22 33 32
+ const __m128i a01 = _mm_add_epi16(s01, s32);
+ const __m128i a32 = _mm_sub_epi16(s01, s32);
+ // [d0 + d3 | d1 + d2 | ...] = [a0 a1 | a0' a1' | ... ]
+ // [d0 - d3 | d1 - d2 | ...] = [a3 a2 | a3' a2' | ... ]
+
+ const __m128i tmp0 = _mm_madd_epi16(a01, k88p); // [ (a0 + a1) << 3, ... ]
+ const __m128i tmp2 = _mm_madd_epi16(a01, k88m); // [ (a0 - a1) << 3, ... ]
+ const __m128i tmp1_1 = _mm_madd_epi16(a32, k5352_2217p);
+ const __m128i tmp3_1 = _mm_madd_epi16(a32, k5352_2217m);
+ const __m128i tmp1_2 = _mm_add_epi32(tmp1_1, k1812);
+ const __m128i tmp3_2 = _mm_add_epi32(tmp3_1, k937);
+ const __m128i tmp1 = _mm_srai_epi32(tmp1_2, 9);
+ const __m128i tmp3 = _mm_srai_epi32(tmp3_2, 9);
+ const __m128i s03 = _mm_packs_epi32(tmp0, tmp2);
+ const __m128i s12 = _mm_packs_epi32(tmp1, tmp3);
+ const __m128i s_lo = _mm_unpacklo_epi16(s03, s12); // 0 1 0 1 0 1...
+ const __m128i s_hi = _mm_unpackhi_epi16(s03, s12); // 2 3 2 3 2 3
+ const __m128i v23 = _mm_unpackhi_epi32(s_lo, s_hi);
+ *out01 = _mm_unpacklo_epi32(s_lo, s_hi);
+ *out32 = _mm_shuffle_epi32(v23, _MM_SHUFFLE(1, 0, 3, 2)); // 3 2 3 2 3 2..
+}
+
+static void FTransformPass2(const __m128i* const v01, const __m128i* const v32,
+ int16_t* out) {
const __m128i zero = _mm_setzero_si128();
const __m128i seven = _mm_set1_epi16(7);
- const __m128i k7500 = _mm_set1_epi32(7500);
- const __m128i k14500 = _mm_set1_epi32(14500);
- const __m128i k51000 = _mm_set1_epi32(51000);
- const __m128i k12000_plus_one = _mm_set1_epi32(12000 + (1 << 16));
const __m128i k5352_2217 = _mm_set_epi16(5352, 2217, 5352, 2217,
5352, 2217, 5352, 2217);
const __m128i k2217_5352 = _mm_set_epi16(2217, -5352, 2217, -5352,
2217, -5352, 2217, -5352);
+ const __m128i k12000_plus_one = _mm_set1_epi32(12000 + (1 << 16));
+ const __m128i k51000 = _mm_set1_epi32(51000);
+
+ // Same operations are done on the (0,3) and (1,2) pairs.
+ // a0 = v0 + v3
+ // a1 = v1 + v2
+ // a3 = v0 - v3
+ // a2 = v1 - v2
+ const __m128i a01 = _mm_add_epi16(*v01, *v32);
+ const __m128i a32 = _mm_sub_epi16(*v01, *v32);
+ const __m128i a11 = _mm_unpackhi_epi64(a01, a01);
+ const __m128i a22 = _mm_unpackhi_epi64(a32, a32);
+ const __m128i a01_plus_7 = _mm_add_epi16(a01, seven);
+
+ // d0 = (a0 + a1 + 7) >> 4;
+ // d2 = (a0 - a1 + 7) >> 4;
+ const __m128i c0 = _mm_add_epi16(a01_plus_7, a11);
+ const __m128i c2 = _mm_sub_epi16(a01_plus_7, a11);
+ const __m128i d0 = _mm_srai_epi16(c0, 4);
+ const __m128i d2 = _mm_srai_epi16(c2, 4);
+
+ // f1 = ((b3 * 5352 + b2 * 2217 + 12000) >> 16)
+ // f3 = ((b3 * 2217 - b2 * 5352 + 51000) >> 16)
+ const __m128i b23 = _mm_unpacklo_epi16(a22, a32);
+ const __m128i c1 = _mm_madd_epi16(b23, k5352_2217);
+ const __m128i c3 = _mm_madd_epi16(b23, k2217_5352);
+ const __m128i d1 = _mm_add_epi32(c1, k12000_plus_one);
+ const __m128i d3 = _mm_add_epi32(c3, k51000);
+ const __m128i e1 = _mm_srai_epi32(d1, 16);
+ const __m128i e3 = _mm_srai_epi32(d3, 16);
+ const __m128i f1 = _mm_packs_epi32(e1, e1);
+ const __m128i f3 = _mm_packs_epi32(e3, e3);
+ // f1 = f1 + (a3 != 0);
+ // The compare will return (0xffff, 0) for (==0, !=0). To turn that into the
+ // desired (0, 1), we add one earlier through k12000_plus_one.
+ // -> f1 = f1 + 1 - (a3 == 0)
+ const __m128i g1 = _mm_add_epi16(f1, _mm_cmpeq_epi16(a32, zero));
+
+ const __m128i d0_g1 = _mm_unpacklo_epi64(d0, g1);
+ const __m128i d2_f3 = _mm_unpacklo_epi64(d2, f3);
+ _mm_storeu_si128((__m128i*)&out[0], d0_g1);
+ _mm_storeu_si128((__m128i*)&out[8], d2_f3);
+}
+
+static void FTransform(const uint8_t* src, const uint8_t* ref, int16_t* out) {
+ const __m128i zero = _mm_setzero_si128();
+ // Load src and convert to 16b.
+ const __m128i src0 = _mm_loadl_epi64((const __m128i*)&src[0 * BPS]);
+ const __m128i src1 = _mm_loadl_epi64((const __m128i*)&src[1 * BPS]);
+ const __m128i src2 = _mm_loadl_epi64((const __m128i*)&src[2 * BPS]);
+ const __m128i src3 = _mm_loadl_epi64((const __m128i*)&src[3 * BPS]);
+ const __m128i src_0 = _mm_unpacklo_epi8(src0, zero);
+ const __m128i src_1 = _mm_unpacklo_epi8(src1, zero);
+ const __m128i src_2 = _mm_unpacklo_epi8(src2, zero);
+ const __m128i src_3 = _mm_unpacklo_epi8(src3, zero);
+ // Load ref and convert to 16b.
+ const __m128i ref0 = _mm_loadl_epi64((const __m128i*)&ref[0 * BPS]);
+ const __m128i ref1 = _mm_loadl_epi64((const __m128i*)&ref[1 * BPS]);
+ const __m128i ref2 = _mm_loadl_epi64((const __m128i*)&ref[2 * BPS]);
+ const __m128i ref3 = _mm_loadl_epi64((const __m128i*)&ref[3 * BPS]);
+ const __m128i ref_0 = _mm_unpacklo_epi8(ref0, zero);
+ const __m128i ref_1 = _mm_unpacklo_epi8(ref1, zero);
+ const __m128i ref_2 = _mm_unpacklo_epi8(ref2, zero);
+ const __m128i ref_3 = _mm_unpacklo_epi8(ref3, zero);
+ // Compute difference. -> 00 01 02 03 00 00 00 00
+ const __m128i diff0 = _mm_sub_epi16(src_0, ref_0);
+ const __m128i diff1 = _mm_sub_epi16(src_1, ref_1);
+ const __m128i diff2 = _mm_sub_epi16(src_2, ref_2);
+ const __m128i diff3 = _mm_sub_epi16(src_3, ref_3);
+
+ // Unpack and shuffle
+ // 00 01 02 03 0 0 0 0
+ // 10 11 12 13 0 0 0 0
+ // 20 21 22 23 0 0 0 0
+ // 30 31 32 33 0 0 0 0
+ const __m128i shuf01 = _mm_unpacklo_epi32(diff0, diff1);
+ const __m128i shuf23 = _mm_unpacklo_epi32(diff2, diff3);
__m128i v01, v32;
- // Difference between src and ref and initial transpose.
- {
- // Load src and convert to 16b.
- const __m128i src0 = _mm_loadl_epi64((__m128i*)&src[0 * BPS]);
- const __m128i src1 = _mm_loadl_epi64((__m128i*)&src[1 * BPS]);
- const __m128i src2 = _mm_loadl_epi64((__m128i*)&src[2 * BPS]);
- const __m128i src3 = _mm_loadl_epi64((__m128i*)&src[3 * BPS]);
- const __m128i src_0 = _mm_unpacklo_epi8(src0, zero);
- const __m128i src_1 = _mm_unpacklo_epi8(src1, zero);
- const __m128i src_2 = _mm_unpacklo_epi8(src2, zero);
- const __m128i src_3 = _mm_unpacklo_epi8(src3, zero);
- // Load ref and convert to 16b.
- const __m128i ref0 = _mm_loadl_epi64((__m128i*)&ref[0 * BPS]);
- const __m128i ref1 = _mm_loadl_epi64((__m128i*)&ref[1 * BPS]);
- const __m128i ref2 = _mm_loadl_epi64((__m128i*)&ref[2 * BPS]);
- const __m128i ref3 = _mm_loadl_epi64((__m128i*)&ref[3 * BPS]);
- const __m128i ref_0 = _mm_unpacklo_epi8(ref0, zero);
- const __m128i ref_1 = _mm_unpacklo_epi8(ref1, zero);
- const __m128i ref_2 = _mm_unpacklo_epi8(ref2, zero);
- const __m128i ref_3 = _mm_unpacklo_epi8(ref3, zero);
- // Compute difference.
- const __m128i diff0 = _mm_sub_epi16(src_0, ref_0);
- const __m128i diff1 = _mm_sub_epi16(src_1, ref_1);
- const __m128i diff2 = _mm_sub_epi16(src_2, ref_2);
- const __m128i diff3 = _mm_sub_epi16(src_3, ref_3);
-
- // Transpose.
- // 00 01 02 03 0 0 0 0
- // 10 11 12 13 0 0 0 0
- // 20 21 22 23 0 0 0 0
- // 30 31 32 33 0 0 0 0
- const __m128i transpose0_0 = _mm_unpacklo_epi16(diff0, diff1);
- const __m128i transpose0_1 = _mm_unpacklo_epi16(diff2, diff3);
- // 00 10 01 11 02 12 03 13
- // 20 30 21 31 22 32 23 33
- const __m128i v23 = _mm_unpackhi_epi32(transpose0_0, transpose0_1);
- v01 = _mm_unpacklo_epi32(transpose0_0, transpose0_1);
- v32 = _mm_shuffle_epi32(v23, _MM_SHUFFLE(1, 0, 3, 2));
- // a02 a12 a22 a32 a03 a13 a23 a33
- // a00 a10 a20 a30 a01 a11 a21 a31
- // a03 a13 a23 a33 a02 a12 a22 a32
- }
-
- // First pass and subsequent transpose.
- {
- // Same operations are done on the (0,3) and (1,2) pairs.
- // b0 = (a0 + a3) << 3
- // b1 = (a1 + a2) << 3
- // b3 = (a0 - a3) << 3
- // b2 = (a1 - a2) << 3
- const __m128i a01 = _mm_add_epi16(v01, v32);
- const __m128i a32 = _mm_sub_epi16(v01, v32);
- const __m128i b01 = _mm_slli_epi16(a01, 3);
- const __m128i b32 = _mm_slli_epi16(a32, 3);
- const __m128i b11 = _mm_unpackhi_epi64(b01, b01);
- const __m128i b22 = _mm_unpackhi_epi64(b32, b32);
-
- // e0 = b0 + b1
- // e2 = b0 - b1
- const __m128i e0 = _mm_add_epi16(b01, b11);
- const __m128i e2 = _mm_sub_epi16(b01, b11);
- const __m128i e02 = _mm_unpacklo_epi64(e0, e2);
-
- // e1 = (b3 * 5352 + b2 * 2217 + 14500) >> 12
- // e3 = (b3 * 2217 - b2 * 5352 + 7500) >> 12
- const __m128i b23 = _mm_unpacklo_epi16(b22, b32);
- const __m128i c1 = _mm_madd_epi16(b23, k5352_2217);
- const __m128i c3 = _mm_madd_epi16(b23, k2217_5352);
- const __m128i d1 = _mm_add_epi32(c1, k14500);
- const __m128i d3 = _mm_add_epi32(c3, k7500);
- const __m128i e1 = _mm_srai_epi32(d1, 12);
- const __m128i e3 = _mm_srai_epi32(d3, 12);
- const __m128i e13 = _mm_packs_epi32(e1, e3);
-
- // Transpose.
- // 00 01 02 03 20 21 22 23
- // 10 11 12 13 30 31 32 33
- const __m128i transpose0_0 = _mm_unpacklo_epi16(e02, e13);
- const __m128i transpose0_1 = _mm_unpackhi_epi16(e02, e13);
- // 00 10 01 11 02 12 03 13
- // 20 30 21 31 22 32 23 33
- const __m128i v23 = _mm_unpackhi_epi32(transpose0_0, transpose0_1);
- v01 = _mm_unpacklo_epi32(transpose0_0, transpose0_1);
- v32 = _mm_shuffle_epi32(v23, _MM_SHUFFLE(1, 0, 3, 2));
- // 02 12 22 32 03 13 23 33
- // 00 10 20 30 01 11 21 31
- // 03 13 23 33 02 12 22 32
- }
+ // First pass
+ FTransformPass1(&shuf01, &shuf23, &v01, &v32);
// Second pass
+ FTransformPass2(&v01, &v32, out);
+}
+
+static void FTransform2(const uint8_t* src, const uint8_t* ref, int16_t* out) {
+ const __m128i zero = _mm_setzero_si128();
+
+ // Load src and convert to 16b.
+ const __m128i src0 = _mm_loadl_epi64((const __m128i*)&src[0 * BPS]);
+ const __m128i src1 = _mm_loadl_epi64((const __m128i*)&src[1 * BPS]);
+ const __m128i src2 = _mm_loadl_epi64((const __m128i*)&src[2 * BPS]);
+ const __m128i src3 = _mm_loadl_epi64((const __m128i*)&src[3 * BPS]);
+ const __m128i src_0 = _mm_unpacklo_epi8(src0, zero);
+ const __m128i src_1 = _mm_unpacklo_epi8(src1, zero);
+ const __m128i src_2 = _mm_unpacklo_epi8(src2, zero);
+ const __m128i src_3 = _mm_unpacklo_epi8(src3, zero);
+ // Load ref and convert to 16b.
+ const __m128i ref0 = _mm_loadl_epi64((const __m128i*)&ref[0 * BPS]);
+ const __m128i ref1 = _mm_loadl_epi64((const __m128i*)&ref[1 * BPS]);
+ const __m128i ref2 = _mm_loadl_epi64((const __m128i*)&ref[2 * BPS]);
+ const __m128i ref3 = _mm_loadl_epi64((const __m128i*)&ref[3 * BPS]);
+ const __m128i ref_0 = _mm_unpacklo_epi8(ref0, zero);
+ const __m128i ref_1 = _mm_unpacklo_epi8(ref1, zero);
+ const __m128i ref_2 = _mm_unpacklo_epi8(ref2, zero);
+ const __m128i ref_3 = _mm_unpacklo_epi8(ref3, zero);
+ // Compute difference. -> 00 01 02 03 00' 01' 02' 03'
+ const __m128i diff0 = _mm_sub_epi16(src_0, ref_0);
+ const __m128i diff1 = _mm_sub_epi16(src_1, ref_1);
+ const __m128i diff2 = _mm_sub_epi16(src_2, ref_2);
+ const __m128i diff3 = _mm_sub_epi16(src_3, ref_3);
+
+ // Unpack and shuffle
+ // 00 01 02 03 0 0 0 0
+ // 10 11 12 13 0 0 0 0
+ // 20 21 22 23 0 0 0 0
+ // 30 31 32 33 0 0 0 0
+ const __m128i shuf01l = _mm_unpacklo_epi32(diff0, diff1);
+ const __m128i shuf23l = _mm_unpacklo_epi32(diff2, diff3);
+ const __m128i shuf01h = _mm_unpackhi_epi32(diff0, diff1);
+ const __m128i shuf23h = _mm_unpackhi_epi32(diff2, diff3);
+ __m128i v01l, v32l;
+ __m128i v01h, v32h;
+
+ // First pass
+ FTransformPass1(&shuf01l, &shuf23l, &v01l, &v32l);
+ FTransformPass1(&shuf01h, &shuf23h, &v01h, &v32h);
+
+ // Second pass
+ FTransformPass2(&v01l, &v32l, out + 0);
+ FTransformPass2(&v01h, &v32h, out + 16);
+}
+
+static void FTransformWHTRow(const int16_t* const in, __m128i* const out) {
+ const __m128i kMult1 = _mm_set_epi16(0, 0, 0, 0, 1, 1, 1, 1);
+ const __m128i kMult2 = _mm_set_epi16(0, 0, 0, 0, -1, 1, -1, 1);
+ const __m128i src0 = _mm_loadl_epi64((__m128i*)&in[0 * 16]);
+ const __m128i src1 = _mm_loadl_epi64((__m128i*)&in[1 * 16]);
+ const __m128i src2 = _mm_loadl_epi64((__m128i*)&in[2 * 16]);
+ const __m128i src3 = _mm_loadl_epi64((__m128i*)&in[3 * 16]);
+ const __m128i A01 = _mm_unpacklo_epi16(src0, src1); // A0 A1 | ...
+ const __m128i A23 = _mm_unpacklo_epi16(src2, src3); // A2 A3 | ...
+ const __m128i B0 = _mm_adds_epi16(A01, A23); // a0 | a1 | ...
+ const __m128i B1 = _mm_subs_epi16(A01, A23); // a3 | a2 | ...
+ const __m128i C0 = _mm_unpacklo_epi32(B0, B1); // a0 | a1 | a3 | a2
+ const __m128i C1 = _mm_unpacklo_epi32(B1, B0); // a3 | a2 | a0 | a1
+ const __m128i D0 = _mm_madd_epi16(C0, kMult1); // out0, out1
+ const __m128i D1 = _mm_madd_epi16(C1, kMult2); // out2, out3
+ *out = _mm_unpacklo_epi64(D0, D1);
+}
+
+static void FTransformWHT(const int16_t* in, int16_t* out) {
+ __m128i row0, row1, row2, row3;
+ FTransformWHTRow(in + 0 * 64, &row0);
+ FTransformWHTRow(in + 1 * 64, &row1);
+ FTransformWHTRow(in + 2 * 64, &row2);
+ FTransformWHTRow(in + 3 * 64, &row3);
+
{
- // Same operations are done on the (0,3) and (1,2) pairs.
- // a0 = v0 + v3
- // a1 = v1 + v2
- // a3 = v0 - v3
- // a2 = v1 - v2
- const __m128i a01 = _mm_add_epi16(v01, v32);
- const __m128i a32 = _mm_sub_epi16(v01, v32);
- const __m128i a11 = _mm_unpackhi_epi64(a01, a01);
- const __m128i a22 = _mm_unpackhi_epi64(a32, a32);
-
- // d0 = (a0 + a1 + 7) >> 4;
- // d2 = (a0 - a1 + 7) >> 4;
- const __m128i b0 = _mm_add_epi16(a01, a11);
- const __m128i b2 = _mm_sub_epi16(a01, a11);
- const __m128i c0 = _mm_add_epi16(b0, seven);
- const __m128i c2 = _mm_add_epi16(b2, seven);
- const __m128i d0 = _mm_srai_epi16(c0, 4);
- const __m128i d2 = _mm_srai_epi16(c2, 4);
-
- // f1 = ((b3 * 5352 + b2 * 2217 + 12000) >> 16)
- // f3 = ((b3 * 2217 - b2 * 5352 + 51000) >> 16)
- const __m128i b23 = _mm_unpacklo_epi16(a22, a32);
- const __m128i c1 = _mm_madd_epi16(b23, k5352_2217);
- const __m128i c3 = _mm_madd_epi16(b23, k2217_5352);
- const __m128i d1 = _mm_add_epi32(c1, k12000_plus_one);
- const __m128i d3 = _mm_add_epi32(c3, k51000);
- const __m128i e1 = _mm_srai_epi32(d1, 16);
- const __m128i e3 = _mm_srai_epi32(d3, 16);
- const __m128i f1 = _mm_packs_epi32(e1, e1);
- const __m128i f3 = _mm_packs_epi32(e3, e3);
- // f1 = f1 + (a3 != 0);
- // The compare will return (0xffff, 0) for (==0, !=0). To turn that into the
- // desired (0, 1), we add one earlier through k12000_plus_one.
- const __m128i g1 = _mm_add_epi16(f1, _mm_cmpeq_epi16(a32, zero));
-
- _mm_storel_epi64((__m128i*)&out[ 0], d0);
- _mm_storel_epi64((__m128i*)&out[ 4], g1);
- _mm_storel_epi64((__m128i*)&out[ 8], d2);
- _mm_storel_epi64((__m128i*)&out[12], f3);
+ const __m128i a0 = _mm_add_epi32(row0, row2);
+ const __m128i a1 = _mm_add_epi32(row1, row3);
+ const __m128i a2 = _mm_sub_epi32(row1, row3);
+ const __m128i a3 = _mm_sub_epi32(row0, row2);
+ const __m128i b0 = _mm_srai_epi32(_mm_add_epi32(a0, a1), 1);
+ const __m128i b1 = _mm_srai_epi32(_mm_add_epi32(a3, a2), 1);
+ const __m128i b2 = _mm_srai_epi32(_mm_sub_epi32(a3, a2), 1);
+ const __m128i b3 = _mm_srai_epi32(_mm_sub_epi32(a0, a1), 1);
+ const __m128i out0 = _mm_packs_epi32(b0, b1);
+ const __m128i out1 = _mm_packs_epi32(b2, b3);
+ _mm_storeu_si128((__m128i*)&out[0], out0);
+ _mm_storeu_si128((__m128i*)&out[8], out1);
+ }
+}
+
+//------------------------------------------------------------------------------
+// Compute susceptibility based on DCT-coeff histograms:
+// the higher, the "easier" the macroblock is to compress.
+
+static void CollectHistogram(const uint8_t* ref, const uint8_t* pred,
+ int start_block, int end_block,
+ VP8Histogram* const histo) {
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i max_coeff_thresh = _mm_set1_epi16(MAX_COEFF_THRESH);
+ int j;
+ int distribution[MAX_COEFF_THRESH + 1] = { 0 };
+ for (j = start_block; j < end_block; ++j) {
+ int16_t out[16];
+ int k;
+
+ FTransform(ref + VP8DspScan[j], pred + VP8DspScan[j], out);
+
+ // Convert coefficients to bin (within out[]).
+ {
+ // Load.
+ const __m128i out0 = _mm_loadu_si128((__m128i*)&out[0]);
+ const __m128i out1 = _mm_loadu_si128((__m128i*)&out[8]);
+ const __m128i d0 = _mm_sub_epi16(zero, out0);
+ const __m128i d1 = _mm_sub_epi16(zero, out1);
+ const __m128i abs0 = _mm_max_epi16(out0, d0); // abs(v), 16b
+ const __m128i abs1 = _mm_max_epi16(out1, d1);
+ // v = abs(out) >> 3
+ const __m128i v0 = _mm_srai_epi16(abs0, 3);
+ const __m128i v1 = _mm_srai_epi16(abs1, 3);
+ // bin = min(v, MAX_COEFF_THRESH)
+ const __m128i bin0 = _mm_min_epi16(v0, max_coeff_thresh);
+ const __m128i bin1 = _mm_min_epi16(v1, max_coeff_thresh);
+ // Store.
+ _mm_storeu_si128((__m128i*)&out[0], bin0);
+ _mm_storeu_si128((__m128i*)&out[8], bin1);
+ }
+
+ // Convert coefficients to bin.
+ for (k = 0; k < 16; ++k) {
+ ++distribution[out[k]];
+ }
}
+ VP8SetHistogramData(distribution, histo);
+}
+
+//------------------------------------------------------------------------------
+// Intra predictions
+
+// helper for chroma-DC predictions
+static WEBP_INLINE void Put8x8uv(uint8_t v, uint8_t* dst) {
+ int j;
+ const __m128i values = _mm_set1_epi8(v);
+ for (j = 0; j < 8; ++j) {
+ _mm_storel_epi64((__m128i*)(dst + j * BPS), values);
+ }
+}
+
+static WEBP_INLINE void Put16(uint8_t v, uint8_t* dst) {
+ int j;
+ const __m128i values = _mm_set1_epi8(v);
+ for (j = 0; j < 16; ++j) {
+ _mm_store_si128((__m128i*)(dst + j * BPS), values);
+ }
+}
+
+static WEBP_INLINE void Fill(uint8_t* dst, int value, int size) {
+ if (size == 4) {
+ int j;
+ for (j = 0; j < 4; ++j) {
+ memset(dst + j * BPS, value, 4);
+ }
+ } else if (size == 8) {
+ Put8x8uv(value, dst);
+ } else {
+ Put16(value, dst);
+ }
+}
+
+static WEBP_INLINE void VE8uv(uint8_t* dst, const uint8_t* top) {
+ int j;
+ const __m128i top_values = _mm_loadl_epi64((const __m128i*)top);
+ for (j = 0; j < 8; ++j) {
+ _mm_storel_epi64((__m128i*)(dst + j * BPS), top_values);
+ }
+}
+
+static WEBP_INLINE void VE16(uint8_t* dst, const uint8_t* top) {
+ const __m128i top_values = _mm_load_si128((const __m128i*)top);
+ int j;
+ for (j = 0; j < 16; ++j) {
+ _mm_store_si128((__m128i*)(dst + j * BPS), top_values);
+ }
+}
+
+static WEBP_INLINE void VerticalPred(uint8_t* dst,
+ const uint8_t* top, int size) {
+ if (top != NULL) {
+ if (size == 8) {
+ VE8uv(dst, top);
+ } else {
+ VE16(dst, top);
+ }
+ } else {
+ Fill(dst, 127, size);
+ }
+}
+
+static WEBP_INLINE void HE8uv(uint8_t* dst, const uint8_t* left) {
+ int j;
+ for (j = 0; j < 8; ++j) {
+ const __m128i values = _mm_set1_epi8(left[j]);
+ _mm_storel_epi64((__m128i*)dst, values);
+ dst += BPS;
+ }
+}
+
+static WEBP_INLINE void HE16(uint8_t* dst, const uint8_t* left) {
+ int j;
+ for (j = 0; j < 16; ++j) {
+ const __m128i values = _mm_set1_epi8(left[j]);
+ _mm_store_si128((__m128i*)dst, values);
+ dst += BPS;
+ }
+}
+
+static WEBP_INLINE void HorizontalPred(uint8_t* dst,
+ const uint8_t* left, int size) {
+ if (left != NULL) {
+ if (size == 8) {
+ HE8uv(dst, left);
+ } else {
+ HE16(dst, left);
+ }
+ } else {
+ Fill(dst, 129, size);
+ }
+}
+
+static WEBP_INLINE void TM(uint8_t* dst, const uint8_t* left,
+ const uint8_t* top, int size) {
+ const __m128i zero = _mm_setzero_si128();
+ int y;
+ if (size == 8) {
+ const __m128i top_values = _mm_loadl_epi64((const __m128i*)top);
+ const __m128i top_base = _mm_unpacklo_epi8(top_values, zero);
+ for (y = 0; y < 8; ++y, dst += BPS) {
+ const int val = left[y] - left[-1];
+ const __m128i base = _mm_set1_epi16(val);
+ const __m128i out = _mm_packus_epi16(_mm_add_epi16(base, top_base), zero);
+ _mm_storel_epi64((__m128i*)dst, out);
+ }
+ } else {
+ const __m128i top_values = _mm_load_si128((const __m128i*)top);
+ const __m128i top_base_0 = _mm_unpacklo_epi8(top_values, zero);
+ const __m128i top_base_1 = _mm_unpackhi_epi8(top_values, zero);
+ for (y = 0; y < 16; ++y, dst += BPS) {
+ const int val = left[y] - left[-1];
+ const __m128i base = _mm_set1_epi16(val);
+ const __m128i out_0 = _mm_add_epi16(base, top_base_0);
+ const __m128i out_1 = _mm_add_epi16(base, top_base_1);
+ const __m128i out = _mm_packus_epi16(out_0, out_1);
+ _mm_store_si128((__m128i*)dst, out);
+ }
+ }
+}
+
+static WEBP_INLINE void TrueMotion(uint8_t* dst, const uint8_t* left,
+ const uint8_t* top, int size) {
+ if (left != NULL) {
+ if (top != NULL) {
+ TM(dst, left, top, size);
+ } else {
+ HorizontalPred(dst, left, size);
+ }
+ } else {
+ // true motion without left samples (hence: with default 129 value)
+ // is equivalent to VE prediction where you just copy the top samples.
+ // Note that if top samples are not available, the default value is
+ // then 129, and not 127 as in the VerticalPred case.
+ if (top != NULL) {
+ VerticalPred(dst, top, size);
+ } else {
+ Fill(dst, 129, size);
+ }
+ }
+}
+
+static WEBP_INLINE void DC8uv(uint8_t* dst, const uint8_t* left,
+ const uint8_t* top) {
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i top_values = _mm_loadl_epi64((const __m128i*)top);
+ const __m128i left_values = _mm_loadl_epi64((const __m128i*)left);
+ const __m128i sum_top = _mm_sad_epu8(top_values, zero);
+ const __m128i sum_left = _mm_sad_epu8(left_values, zero);
+ const int DC = _mm_cvtsi128_si32(sum_top) + _mm_cvtsi128_si32(sum_left) + 8;
+ Put8x8uv(DC >> 4, dst);
+}
+
+static WEBP_INLINE void DC8uvNoLeft(uint8_t* dst, const uint8_t* top) {
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i top_values = _mm_loadl_epi64((const __m128i*)top);
+ const __m128i sum = _mm_sad_epu8(top_values, zero);
+ const int DC = _mm_cvtsi128_si32(sum) + 4;
+ Put8x8uv(DC >> 3, dst);
+}
+
+static WEBP_INLINE void DC8uvNoTop(uint8_t* dst, const uint8_t* left) {
+ // 'left' is contiguous so we can reuse the top summation.
+ DC8uvNoLeft(dst, left);
+}
+
+static WEBP_INLINE void DC8uvNoTopLeft(uint8_t* dst) {
+ Put8x8uv(0x80, dst);
+}
+
+static WEBP_INLINE void DC8uvMode(uint8_t* dst, const uint8_t* left,
+ const uint8_t* top) {
+ if (top != NULL) {
+ if (left != NULL) { // top and left present
+ DC8uv(dst, left, top);
+ } else { // top, but no left
+ DC8uvNoLeft(dst, top);
+ }
+ } else if (left != NULL) { // left but no top
+ DC8uvNoTop(dst, left);
+ } else { // no top, no left, nothing.
+ DC8uvNoTopLeft(dst);
+ }
+}
+
+static WEBP_INLINE void DC16(uint8_t* dst, const uint8_t* left,
+ const uint8_t* top) {
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i top_row = _mm_load_si128((const __m128i*)top);
+ const __m128i left_row = _mm_load_si128((const __m128i*)left);
+ const __m128i sad8x2 = _mm_sad_epu8(top_row, zero);
+ // sum the two sads: sad8x2[0:1] + sad8x2[8:9]
+ const __m128i sum_top = _mm_add_epi16(sad8x2, _mm_shuffle_epi32(sad8x2, 2));
+ const __m128i sad8x2_left = _mm_sad_epu8(left_row, zero);
+ // sum the two sads: sad8x2[0:1] + sad8x2[8:9]
+ const __m128i sum_left =
+ _mm_add_epi16(sad8x2_left, _mm_shuffle_epi32(sad8x2_left, 2));
+ const int DC = _mm_cvtsi128_si32(sum_top) + _mm_cvtsi128_si32(sum_left) + 16;
+ Put16(DC >> 5, dst);
+}
+
+static WEBP_INLINE void DC16NoLeft(uint8_t* dst, const uint8_t* top) {
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i top_row = _mm_load_si128((const __m128i*)top);
+ const __m128i sad8x2 = _mm_sad_epu8(top_row, zero);
+ // sum the two sads: sad8x2[0:1] + sad8x2[8:9]
+ const __m128i sum = _mm_add_epi16(sad8x2, _mm_shuffle_epi32(sad8x2, 2));
+ const int DC = _mm_cvtsi128_si32(sum) + 8;
+ Put16(DC >> 4, dst);
+}
+
+static WEBP_INLINE void DC16NoTop(uint8_t* dst, const uint8_t* left) {
+ // 'left' is contiguous so we can reuse the top summation.
+ DC16NoLeft(dst, left);
+}
+
+static WEBP_INLINE void DC16NoTopLeft(uint8_t* dst) {
+ Put16(0x80, dst);
+}
+
+static WEBP_INLINE void DC16Mode(uint8_t* dst, const uint8_t* left,
+ const uint8_t* top) {
+ if (top != NULL) {
+ if (left != NULL) { // top and left present
+ DC16(dst, left, top);
+ } else { // top, but no left
+ DC16NoLeft(dst, top);
+ }
+ } else if (left != NULL) { // left but no top
+ DC16NoTop(dst, left);
+ } else { // no top, no left, nothing.
+ DC16NoTopLeft(dst);
+ }
+}
+
+//------------------------------------------------------------------------------
+// 4x4 predictions
+
+#define DST(x, y) dst[(x) + (y) * BPS]
+#define AVG3(a, b, c) (((a) + 2 * (b) + (c) + 2) >> 2)
+#define AVG2(a, b) (((a) + (b) + 1) >> 1)
+
+// We use the following 8b-arithmetic tricks:
+// (a + 2 * b + c + 2) >> 2 = (AC + b + 1) >> 1
+// where: AC = (a + c) >> 1 = [(a + c + 1) >> 1] - [(a^c) & 1]
+// and:
+// (a + 2 * b + c + 2) >> 2 = (AB + BC + 1) >> 1 - (ab|bc)&lsb
+// where: AC = (a + b + 1) >> 1, BC = (b + c + 1) >> 1
+// and ab = a ^ b, bc = b ^ c, lsb = (AC^BC)&1
+
+static WEBP_INLINE void VE4(uint8_t* dst, const uint8_t* top) { // vertical
+ const __m128i one = _mm_set1_epi8(1);
+ const __m128i ABCDEFGH = _mm_loadl_epi64((__m128i*)(top - 1));
+ const __m128i BCDEFGH0 = _mm_srli_si128(ABCDEFGH, 1);
+ const __m128i CDEFGH00 = _mm_srli_si128(ABCDEFGH, 2);
+ const __m128i a = _mm_avg_epu8(ABCDEFGH, CDEFGH00);
+ const __m128i lsb = _mm_and_si128(_mm_xor_si128(ABCDEFGH, CDEFGH00), one);
+ const __m128i b = _mm_subs_epu8(a, lsb);
+ const __m128i avg = _mm_avg_epu8(b, BCDEFGH0);
+ const uint32_t vals = _mm_cvtsi128_si32(avg);
+ int i;
+ for (i = 0; i < 4; ++i) {
+ *(uint32_t*)(dst + i * BPS) = vals;
+ }
+}
+
+static WEBP_INLINE void HE4(uint8_t* dst, const uint8_t* top) { // horizontal
+ const int X = top[-1];
+ const int I = top[-2];
+ const int J = top[-3];
+ const int K = top[-4];
+ const int L = top[-5];
+ *(uint32_t*)(dst + 0 * BPS) = 0x01010101U * AVG3(X, I, J);
+ *(uint32_t*)(dst + 1 * BPS) = 0x01010101U * AVG3(I, J, K);
+ *(uint32_t*)(dst + 2 * BPS) = 0x01010101U * AVG3(J, K, L);
+ *(uint32_t*)(dst + 3 * BPS) = 0x01010101U * AVG3(K, L, L);
+}
+
+static WEBP_INLINE void DC4(uint8_t* dst, const uint8_t* top) {
+ uint32_t dc = 4;
+ int i;
+ for (i = 0; i < 4; ++i) dc += top[i] + top[-5 + i];
+ Fill(dst, dc >> 3, 4);
+}
+
+static WEBP_INLINE void LD4(uint8_t* dst, const uint8_t* top) { // Down-Left
+ const __m128i one = _mm_set1_epi8(1);
+ const __m128i ABCDEFGH = _mm_loadl_epi64((const __m128i*)top);
+ const __m128i BCDEFGH0 = _mm_srli_si128(ABCDEFGH, 1);
+ const __m128i CDEFGH00 = _mm_srli_si128(ABCDEFGH, 2);
+ const __m128i CDEFGHH0 = _mm_insert_epi16(CDEFGH00, top[7], 3);
+ const __m128i avg1 = _mm_avg_epu8(ABCDEFGH, CDEFGHH0);
+ const __m128i lsb = _mm_and_si128(_mm_xor_si128(ABCDEFGH, CDEFGHH0), one);
+ const __m128i avg2 = _mm_subs_epu8(avg1, lsb);
+ const __m128i abcdefg = _mm_avg_epu8(avg2, BCDEFGH0);
+ *(uint32_t*)(dst + 0 * BPS) = _mm_cvtsi128_si32( abcdefg );
+ *(uint32_t*)(dst + 1 * BPS) = _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 1));
+ *(uint32_t*)(dst + 2 * BPS) = _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 2));
+ *(uint32_t*)(dst + 3 * BPS) = _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 3));
+}
+
+static WEBP_INLINE void VR4(uint8_t* dst,
+ const uint8_t* top) { // Vertical-Right
+ const __m128i one = _mm_set1_epi8(1);
+ const int I = top[-2];
+ const int J = top[-3];
+ const int K = top[-4];
+ const int X = top[-1];
+ const __m128i XABCD = _mm_loadl_epi64((const __m128i*)(top - 1));
+ const __m128i ABCD0 = _mm_srli_si128(XABCD, 1);
+ const __m128i abcd = _mm_avg_epu8(XABCD, ABCD0);
+ const __m128i _XABCD = _mm_slli_si128(XABCD, 1);
+ const __m128i IXABCD = _mm_insert_epi16(_XABCD, I | (X << 8), 0);
+ const __m128i avg1 = _mm_avg_epu8(IXABCD, ABCD0);
+ const __m128i lsb = _mm_and_si128(_mm_xor_si128(IXABCD, ABCD0), one);
+ const __m128i avg2 = _mm_subs_epu8(avg1, lsb);
+ const __m128i efgh = _mm_avg_epu8(avg2, XABCD);
+ *(uint32_t*)(dst + 0 * BPS) = _mm_cvtsi128_si32( abcd );
+ *(uint32_t*)(dst + 1 * BPS) = _mm_cvtsi128_si32( efgh );
+ *(uint32_t*)(dst + 2 * BPS) = _mm_cvtsi128_si32(_mm_slli_si128(abcd, 1));
+ *(uint32_t*)(dst + 3 * BPS) = _mm_cvtsi128_si32(_mm_slli_si128(efgh, 1));
+
+ // these two are hard to implement in SSE2, so we keep the C-version:
+ DST(0, 2) = AVG3(J, I, X);
+ DST(0, 3) = AVG3(K, J, I);
+}
+
+static WEBP_INLINE void VL4(uint8_t* dst,
+ const uint8_t* top) { // Vertical-Left
+ const __m128i one = _mm_set1_epi8(1);
+ const __m128i ABCDEFGH = _mm_loadl_epi64((const __m128i*)top);
+ const __m128i BCDEFGH_ = _mm_srli_si128(ABCDEFGH, 1);
+ const __m128i CDEFGH__ = _mm_srli_si128(ABCDEFGH, 2);
+ const __m128i avg1 = _mm_avg_epu8(ABCDEFGH, BCDEFGH_);
+ const __m128i avg2 = _mm_avg_epu8(CDEFGH__, BCDEFGH_);
+ const __m128i avg3 = _mm_avg_epu8(avg1, avg2);
+ const __m128i lsb1 = _mm_and_si128(_mm_xor_si128(avg1, avg2), one);
+ const __m128i ab = _mm_xor_si128(ABCDEFGH, BCDEFGH_);
+ const __m128i bc = _mm_xor_si128(CDEFGH__, BCDEFGH_);
+ const __m128i abbc = _mm_or_si128(ab, bc);
+ const __m128i lsb2 = _mm_and_si128(abbc, lsb1);
+ const __m128i avg4 = _mm_subs_epu8(avg3, lsb2);
+ const uint32_t extra_out = _mm_cvtsi128_si32(_mm_srli_si128(avg4, 4));
+ *(uint32_t*)(dst + 0 * BPS) = _mm_cvtsi128_si32( avg1 );
+ *(uint32_t*)(dst + 1 * BPS) = _mm_cvtsi128_si32( avg4 );
+ *(uint32_t*)(dst + 2 * BPS) = _mm_cvtsi128_si32(_mm_srli_si128(avg1, 1));
+ *(uint32_t*)(dst + 3 * BPS) = _mm_cvtsi128_si32(_mm_srli_si128(avg4, 1));
+
+ // these two are hard to get and irregular
+ DST(3, 2) = (extra_out >> 0) & 0xff;
+ DST(3, 3) = (extra_out >> 8) & 0xff;
+}
+
+static WEBP_INLINE void RD4(uint8_t* dst, const uint8_t* top) { // Down-right
+ const __m128i one = _mm_set1_epi8(1);
+ const __m128i LKJIXABC = _mm_loadl_epi64((const __m128i*)(top - 5));
+ const __m128i LKJIXABCD = _mm_insert_epi16(LKJIXABC, top[3], 4);
+ const __m128i KJIXABCD_ = _mm_srli_si128(LKJIXABCD, 1);
+ const __m128i JIXABCD__ = _mm_srli_si128(LKJIXABCD, 2);
+ const __m128i avg1 = _mm_avg_epu8(JIXABCD__, LKJIXABCD);
+ const __m128i lsb = _mm_and_si128(_mm_xor_si128(JIXABCD__, LKJIXABCD), one);
+ const __m128i avg2 = _mm_subs_epu8(avg1, lsb);
+ const __m128i abcdefg = _mm_avg_epu8(avg2, KJIXABCD_);
+ *(uint32_t*)(dst + 3 * BPS) = _mm_cvtsi128_si32( abcdefg );
+ *(uint32_t*)(dst + 2 * BPS) = _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 1));
+ *(uint32_t*)(dst + 1 * BPS) = _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 2));
+ *(uint32_t*)(dst + 0 * BPS) = _mm_cvtsi128_si32(_mm_srli_si128(abcdefg, 3));
+}
+
+static WEBP_INLINE void HU4(uint8_t* dst, const uint8_t* top) {
+ const int I = top[-2];
+ const int J = top[-3];
+ const int K = top[-4];
+ const int L = top[-5];
+ DST(0, 0) = AVG2(I, J);
+ DST(2, 0) = DST(0, 1) = AVG2(J, K);
+ DST(2, 1) = DST(0, 2) = AVG2(K, L);
+ DST(1, 0) = AVG3(I, J, K);
+ DST(3, 0) = DST(1, 1) = AVG3(J, K, L);
+ DST(3, 1) = DST(1, 2) = AVG3(K, L, L);
+ DST(3, 2) = DST(2, 2) =
+ DST(0, 3) = DST(1, 3) = DST(2, 3) = DST(3, 3) = L;
+}
+
+static WEBP_INLINE void HD4(uint8_t* dst, const uint8_t* top) {
+ const int X = top[-1];
+ const int I = top[-2];
+ const int J = top[-3];
+ const int K = top[-4];
+ const int L = top[-5];
+ const int A = top[0];
+ const int B = top[1];
+ const int C = top[2];
+
+ DST(0, 0) = DST(2, 1) = AVG2(I, X);
+ DST(0, 1) = DST(2, 2) = AVG2(J, I);
+ DST(0, 2) = DST(2, 3) = AVG2(K, J);
+ DST(0, 3) = AVG2(L, K);
+
+ DST(3, 0) = AVG3(A, B, C);
+ DST(2, 0) = AVG3(X, A, B);
+ DST(1, 0) = DST(3, 1) = AVG3(I, X, A);
+ DST(1, 1) = DST(3, 2) = AVG3(J, I, X);
+ DST(1, 2) = DST(3, 3) = AVG3(K, J, I);
+ DST(1, 3) = AVG3(L, K, J);
+}
+
+static WEBP_INLINE void TM4(uint8_t* dst, const uint8_t* top) {
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i top_values = _mm_cvtsi32_si128(MemToUint32(top));
+ const __m128i top_base = _mm_unpacklo_epi8(top_values, zero);
+ int y;
+ for (y = 0; y < 4; ++y, dst += BPS) {
+ const int val = top[-2 - y] - top[-1];
+ const __m128i base = _mm_set1_epi16(val);
+ const __m128i out = _mm_packus_epi16(_mm_add_epi16(base, top_base), zero);
+ *(int*)dst = _mm_cvtsi128_si32(out);
+ }
+}
+
+#undef DST
+#undef AVG3
+#undef AVG2
+
+//------------------------------------------------------------------------------
+// luma 4x4 prediction
+
+// Left samples are top[-5 .. -2], top_left is top[-1], top are
+// located at top[0..3], and top right is top[4..7]
+static void Intra4Preds(uint8_t* dst, const uint8_t* top) {
+ DC4(I4DC4 + dst, top);
+ TM4(I4TM4 + dst, top);
+ VE4(I4VE4 + dst, top);
+ HE4(I4HE4 + dst, top);
+ RD4(I4RD4 + dst, top);
+ VR4(I4VR4 + dst, top);
+ LD4(I4LD4 + dst, top);
+ VL4(I4VL4 + dst, top);
+ HD4(I4HD4 + dst, top);
+ HU4(I4HU4 + dst, top);
+}
+
+//------------------------------------------------------------------------------
+// Chroma 8x8 prediction (paragraph 12.2)
+
+static void IntraChromaPreds(uint8_t* dst, const uint8_t* left,
+ const uint8_t* top) {
+ // U block
+ DC8uvMode(C8DC8 + dst, left, top);
+ VerticalPred(C8VE8 + dst, top, 8);
+ HorizontalPred(C8HE8 + dst, left, 8);
+ TrueMotion(C8TM8 + dst, left, top, 8);
+ // V block
+ dst += 8;
+ if (top != NULL) top += 8;
+ if (left != NULL) left += 16;
+ DC8uvMode(C8DC8 + dst, left, top);
+ VerticalPred(C8VE8 + dst, top, 8);
+ HorizontalPred(C8HE8 + dst, left, 8);
+ TrueMotion(C8TM8 + dst, left, top, 8);
+}
+
+//------------------------------------------------------------------------------
+// luma 16x16 prediction (paragraph 12.3)
+
+static void Intra16Preds(uint8_t* dst,
+ const uint8_t* left, const uint8_t* top) {
+ DC16Mode(I16DC16 + dst, left, top);
+ VerticalPred(I16VE16 + dst, top, 16);
+ HorizontalPred(I16HE16 + dst, left, 16);
+ TrueMotion(I16TM16 + dst, left, top, 16);
}
//------------------------------------------------------------------------------
// Metric
-static int SSE4x4SSE2(const uint8_t* a, const uint8_t* b) {
- const __m128i zero = _mm_set1_epi16(0);
+static WEBP_INLINE void SubtractAndAccumulate(const __m128i a, const __m128i b,
+ __m128i* const sum) {
+ // take abs(a-b) in 8b
+ const __m128i a_b = _mm_subs_epu8(a, b);
+ const __m128i b_a = _mm_subs_epu8(b, a);
+ const __m128i abs_a_b = _mm_or_si128(a_b, b_a);
+ // zero-extend to 16b
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i C0 = _mm_unpacklo_epi8(abs_a_b, zero);
+ const __m128i C1 = _mm_unpackhi_epi8(abs_a_b, zero);
+ // multiply with self
+ const __m128i sum1 = _mm_madd_epi16(C0, C0);
+ const __m128i sum2 = _mm_madd_epi16(C1, C1);
+ *sum = _mm_add_epi32(sum1, sum2);
+}
- // Load values.
- const __m128i a0 = _mm_loadl_epi64((__m128i*)&a[BPS * 0]);
- const __m128i a1 = _mm_loadl_epi64((__m128i*)&a[BPS * 1]);
- const __m128i a2 = _mm_loadl_epi64((__m128i*)&a[BPS * 2]);
- const __m128i a3 = _mm_loadl_epi64((__m128i*)&a[BPS * 3]);
- const __m128i b0 = _mm_loadl_epi64((__m128i*)&b[BPS * 0]);
- const __m128i b1 = _mm_loadl_epi64((__m128i*)&b[BPS * 1]);
- const __m128i b2 = _mm_loadl_epi64((__m128i*)&b[BPS * 2]);
- const __m128i b3 = _mm_loadl_epi64((__m128i*)&b[BPS * 3]);
+static WEBP_INLINE int SSE_16xN(const uint8_t* a, const uint8_t* b,
+ int num_pairs) {
+ __m128i sum = _mm_setzero_si128();
+ int32_t tmp[4];
+ int i;
+
+ for (i = 0; i < num_pairs; ++i) {
+ const __m128i a0 = _mm_loadu_si128((const __m128i*)&a[BPS * 0]);
+ const __m128i b0 = _mm_loadu_si128((const __m128i*)&b[BPS * 0]);
+ const __m128i a1 = _mm_loadu_si128((const __m128i*)&a[BPS * 1]);
+ const __m128i b1 = _mm_loadu_si128((const __m128i*)&b[BPS * 1]);
+ __m128i sum1, sum2;
+ SubtractAndAccumulate(a0, b0, &sum1);
+ SubtractAndAccumulate(a1, b1, &sum2);
+ sum = _mm_add_epi32(sum, _mm_add_epi32(sum1, sum2));
+ a += 2 * BPS;
+ b += 2 * BPS;
+ }
+ _mm_storeu_si128((__m128i*)tmp, sum);
+ return (tmp[3] + tmp[2] + tmp[1] + tmp[0]);
+}
+
+static int SSE16x16(const uint8_t* a, const uint8_t* b) {
+ return SSE_16xN(a, b, 8);
+}
- // Combine pair of lines and convert to 16b.
+static int SSE16x8(const uint8_t* a, const uint8_t* b) {
+ return SSE_16xN(a, b, 4);
+}
+
+#define LOAD_8x16b(ptr) \
+ _mm_unpacklo_epi8(_mm_loadl_epi64((const __m128i*)(ptr)), zero)
+
+static int SSE8x8(const uint8_t* a, const uint8_t* b) {
+ const __m128i zero = _mm_setzero_si128();
+ int num_pairs = 4;
+ __m128i sum = zero;
+ int32_t tmp[4];
+ while (num_pairs-- > 0) {
+ const __m128i a0 = LOAD_8x16b(&a[BPS * 0]);
+ const __m128i a1 = LOAD_8x16b(&a[BPS * 1]);
+ const __m128i b0 = LOAD_8x16b(&b[BPS * 0]);
+ const __m128i b1 = LOAD_8x16b(&b[BPS * 1]);
+ // subtract
+ const __m128i c0 = _mm_subs_epi16(a0, b0);
+ const __m128i c1 = _mm_subs_epi16(a1, b1);
+ // multiply/accumulate with self
+ const __m128i d0 = _mm_madd_epi16(c0, c0);
+ const __m128i d1 = _mm_madd_epi16(c1, c1);
+ // collect
+ const __m128i sum01 = _mm_add_epi32(d0, d1);
+ sum = _mm_add_epi32(sum, sum01);
+ a += 2 * BPS;
+ b += 2 * BPS;
+ }
+ _mm_storeu_si128((__m128i*)tmp, sum);
+ return (tmp[3] + tmp[2] + tmp[1] + tmp[0]);
+}
+#undef LOAD_8x16b
+
+static int SSE4x4(const uint8_t* a, const uint8_t* b) {
+ const __m128i zero = _mm_setzero_si128();
+
+ // Load values. Note that we read 8 pixels instead of 4,
+ // but the a/b buffers are over-allocated to that effect.
+ const __m128i a0 = _mm_loadl_epi64((const __m128i*)&a[BPS * 0]);
+ const __m128i a1 = _mm_loadl_epi64((const __m128i*)&a[BPS * 1]);
+ const __m128i a2 = _mm_loadl_epi64((const __m128i*)&a[BPS * 2]);
+ const __m128i a3 = _mm_loadl_epi64((const __m128i*)&a[BPS * 3]);
+ const __m128i b0 = _mm_loadl_epi64((const __m128i*)&b[BPS * 0]);
+ const __m128i b1 = _mm_loadl_epi64((const __m128i*)&b[BPS * 1]);
+ const __m128i b2 = _mm_loadl_epi64((const __m128i*)&b[BPS * 2]);
+ const __m128i b3 = _mm_loadl_epi64((const __m128i*)&b[BPS * 3]);
+ // Combine pair of lines.
const __m128i a01 = _mm_unpacklo_epi32(a0, a1);
const __m128i a23 = _mm_unpacklo_epi32(a2, a3);
const __m128i b01 = _mm_unpacklo_epi32(b0, b1);
const __m128i b23 = _mm_unpacklo_epi32(b2, b3);
+ // Convert to 16b.
const __m128i a01s = _mm_unpacklo_epi8(a01, zero);
const __m128i a23s = _mm_unpacklo_epi8(a23, zero);
const __m128i b01s = _mm_unpacklo_epi8(b01, zero);
const __m128i b23s = _mm_unpacklo_epi8(b23, zero);
+ // subtract, square and accumulate
+ const __m128i d0 = _mm_subs_epi16(a01s, b01s);
+ const __m128i d1 = _mm_subs_epi16(a23s, b23s);
+ const __m128i e0 = _mm_madd_epi16(d0, d0);
+ const __m128i e1 = _mm_madd_epi16(d1, d1);
+ const __m128i sum = _mm_add_epi32(e0, e1);
- // Compute differences; (a-b)^2 = (abs(a-b))^2 = (sat8(a-b) + sat8(b-a))^2
- // TODO(cduvivier): Dissassemble and figure out why this is fastest. We don't
- // need absolute values, there is no need to do calculation
- // in 8bit as we are already in 16bit, ... Yet this is what
- // benchmarks the fastest!
- const __m128i d0 = _mm_subs_epu8(a01s, b01s);
- const __m128i d1 = _mm_subs_epu8(b01s, a01s);
- const __m128i d2 = _mm_subs_epu8(a23s, b23s);
- const __m128i d3 = _mm_subs_epu8(b23s, a23s);
-
- // Square and add them all together.
- const __m128i madd0 = _mm_madd_epi16(d0, d0);
- const __m128i madd1 = _mm_madd_epi16(d1, d1);
- const __m128i madd2 = _mm_madd_epi16(d2, d2);
- const __m128i madd3 = _mm_madd_epi16(d3, d3);
- const __m128i sum0 = _mm_add_epi32(madd0, madd1);
- const __m128i sum1 = _mm_add_epi32(madd2, madd3);
- const __m128i sum2 = _mm_add_epi32(sum0, sum1);
int32_t tmp[4];
- _mm_storeu_si128((__m128i*)tmp, sum2);
+ _mm_storeu_si128((__m128i*)tmp, sum);
return (tmp[3] + tmp[2] + tmp[1] + tmp[0]);
}
@@ -497,24 +1155,22 @@ static int SSE4x4SSE2(const uint8_t* a, const uint8_t* b) {
// Hadamard transform
// Returns the difference between the weighted sum of the absolute value of
// transformed coefficients.
-static int TTransformSSE2(const uint8_t* inA, const uint8_t* inB,
- const uint16_t* const w) {
+static int TTransform(const uint8_t* inA, const uint8_t* inB,
+ const uint16_t* const w) {
int32_t sum[4];
__m128i tmp_0, tmp_1, tmp_2, tmp_3;
const __m128i zero = _mm_setzero_si128();
- const __m128i one = _mm_set1_epi16(1);
- const __m128i three = _mm_set1_epi16(3);
- // Load, combine and tranpose inputs.
+ // Load, combine and transpose inputs.
{
- const __m128i inA_0 = _mm_loadl_epi64((__m128i*)&inA[BPS * 0]);
- const __m128i inA_1 = _mm_loadl_epi64((__m128i*)&inA[BPS * 1]);
- const __m128i inA_2 = _mm_loadl_epi64((__m128i*)&inA[BPS * 2]);
- const __m128i inA_3 = _mm_loadl_epi64((__m128i*)&inA[BPS * 3]);
- const __m128i inB_0 = _mm_loadl_epi64((__m128i*)&inB[BPS * 0]);
- const __m128i inB_1 = _mm_loadl_epi64((__m128i*)&inB[BPS * 1]);
- const __m128i inB_2 = _mm_loadl_epi64((__m128i*)&inB[BPS * 2]);
- const __m128i inB_3 = _mm_loadl_epi64((__m128i*)&inB[BPS * 3]);
+ const __m128i inA_0 = _mm_loadl_epi64((const __m128i*)&inA[BPS * 0]);
+ const __m128i inA_1 = _mm_loadl_epi64((const __m128i*)&inA[BPS * 1]);
+ const __m128i inA_2 = _mm_loadl_epi64((const __m128i*)&inA[BPS * 2]);
+ const __m128i inA_3 = _mm_loadl_epi64((const __m128i*)&inA[BPS * 3]);
+ const __m128i inB_0 = _mm_loadl_epi64((const __m128i*)&inB[BPS * 0]);
+ const __m128i inB_1 = _mm_loadl_epi64((const __m128i*)&inB[BPS * 1]);
+ const __m128i inB_2 = _mm_loadl_epi64((const __m128i*)&inB[BPS * 2]);
+ const __m128i inB_3 = _mm_loadl_epi64((const __m128i*)&inB[BPS * 3]);
// Combine inA and inB (we'll do two transforms in parallel).
const __m128i inAB_0 = _mm_unpacklo_epi8(inA_0, inB_0);
@@ -550,17 +1206,14 @@ static int TTransformSSE2(const uint8_t* inA, const uint8_t* inB,
// Horizontal pass and subsequent transpose.
{
// Calculate a and b (two 4x4 at once).
- const __m128i a0 = _mm_slli_epi16(_mm_add_epi16(tmp_0, tmp_2), 2);
- const __m128i a1 = _mm_slli_epi16(_mm_add_epi16(tmp_1, tmp_3), 2);
- const __m128i a2 = _mm_slli_epi16(_mm_sub_epi16(tmp_1, tmp_3), 2);
- const __m128i a3 = _mm_slli_epi16(_mm_sub_epi16(tmp_0, tmp_2), 2);
- // b0_extra = (a0 != 0);
- const __m128i b0_extra = _mm_andnot_si128(_mm_cmpeq_epi16 (a0, zero), one);
- const __m128i b0_base = _mm_add_epi16(a0, a1);
+ const __m128i a0 = _mm_add_epi16(tmp_0, tmp_2);
+ const __m128i a1 = _mm_add_epi16(tmp_1, tmp_3);
+ const __m128i a2 = _mm_sub_epi16(tmp_1, tmp_3);
+ const __m128i a3 = _mm_sub_epi16(tmp_0, tmp_2);
+ const __m128i b0 = _mm_add_epi16(a0, a1);
const __m128i b1 = _mm_add_epi16(a3, a2);
const __m128i b2 = _mm_sub_epi16(a3, a2);
const __m128i b3 = _mm_sub_epi16(a0, a1);
- const __m128i b0 = _mm_add_epi16(b0_base, b0_extra);
// a00 a01 a02 a03 b00 b01 b02 b03
// a10 a11 a12 a13 b10 b11 b12 b13
// a20 a21 a22 a23 b20 b21 b22 b23
@@ -598,8 +1251,8 @@ static int TTransformSSE2(const uint8_t* inA, const uint8_t* inB,
// Load all inputs.
// TODO(cduvivier): Make variable declarations and allocations aligned so
// we can use _mm_load_si128 instead of _mm_loadu_si128.
- const __m128i w_0 = _mm_loadu_si128((__m128i*)&w[0]);
- const __m128i w_8 = _mm_loadu_si128((__m128i*)&w[8]);
+ const __m128i w_0 = _mm_loadu_si128((const __m128i*)&w[0]);
+ const __m128i w_8 = _mm_loadu_si128((const __m128i*)&w[8]);
// Calculate a and b (two 4x4 at once).
const __m128i a0 = _mm_add_epi16(tmp_0, tmp_2);
@@ -618,36 +1271,16 @@ static int TTransformSSE2(const uint8_t* inA, const uint8_t* inB,
__m128i B_b2 = _mm_unpackhi_epi64(b2, b3);
{
- // sign(b) = b >> 15 (0x0000 if positive, 0xffff if negative)
- const __m128i sign_A_b0 = _mm_srai_epi16(A_b0, 15);
- const __m128i sign_A_b2 = _mm_srai_epi16(A_b2, 15);
- const __m128i sign_B_b0 = _mm_srai_epi16(B_b0, 15);
- const __m128i sign_B_b2 = _mm_srai_epi16(B_b2, 15);
-
- // b = abs(b) = (b ^ sign) - sign
- A_b0 = _mm_xor_si128(A_b0, sign_A_b0);
- A_b2 = _mm_xor_si128(A_b2, sign_A_b2);
- B_b0 = _mm_xor_si128(B_b0, sign_B_b0);
- B_b2 = _mm_xor_si128(B_b2, sign_B_b2);
- A_b0 = _mm_sub_epi16(A_b0, sign_A_b0);
- A_b2 = _mm_sub_epi16(A_b2, sign_A_b2);
- B_b0 = _mm_sub_epi16(B_b0, sign_B_b0);
- B_b2 = _mm_sub_epi16(B_b2, sign_B_b2);
+ const __m128i d0 = _mm_sub_epi16(zero, A_b0);
+ const __m128i d1 = _mm_sub_epi16(zero, A_b2);
+ const __m128i d2 = _mm_sub_epi16(zero, B_b0);
+ const __m128i d3 = _mm_sub_epi16(zero, B_b2);
+ A_b0 = _mm_max_epi16(A_b0, d0); // abs(v), 16b
+ A_b2 = _mm_max_epi16(A_b2, d1);
+ B_b0 = _mm_max_epi16(B_b0, d2);
+ B_b2 = _mm_max_epi16(B_b2, d3);
}
- // b = abs(b) + 3
- A_b0 = _mm_add_epi16(A_b0, three);
- A_b2 = _mm_add_epi16(A_b2, three);
- B_b0 = _mm_add_epi16(B_b0, three);
- B_b2 = _mm_add_epi16(B_b2, three);
-
- // abs((b + (b<0) + 3) >> 3) = (abs(b) + 3) >> 3
- // b = (abs(b) + 3) >> 3
- A_b0 = _mm_srai_epi16(A_b0, 3);
- A_b2 = _mm_srai_epi16(A_b2, 3);
- B_b0 = _mm_srai_epi16(B_b0, 3);
- B_b2 = _mm_srai_epi16(B_b2, 3);
-
// weighted sums
A_b0 = _mm_madd_epi16(A_b0, w_0);
A_b2 = _mm_madd_epi16(A_b2, w_8);
@@ -663,35 +1296,33 @@ static int TTransformSSE2(const uint8_t* inA, const uint8_t* inB,
return sum[0] + sum[1] + sum[2] + sum[3];
}
-static int Disto4x4SSE2(const uint8_t* const a, const uint8_t* const b,
- const uint16_t* const w) {
- const int diff_sum = TTransformSSE2(a, b, w);
- return (abs(diff_sum) + 8) >> 4;
+static int Disto4x4(const uint8_t* const a, const uint8_t* const b,
+ const uint16_t* const w) {
+ const int diff_sum = TTransform(a, b, w);
+ return abs(diff_sum) >> 5;
}
-static int Disto16x16SSE2(const uint8_t* const a, const uint8_t* const b,
- const uint16_t* const w) {
+static int Disto16x16(const uint8_t* const a, const uint8_t* const b,
+ const uint16_t* const w) {
int D = 0;
int x, y;
for (y = 0; y < 16 * BPS; y += 4 * BPS) {
for (x = 0; x < 16; x += 4) {
- D += Disto4x4SSE2(a + x + y, b + x + y, w);
+ D += Disto4x4(a + x + y, b + x + y, w);
}
}
return D;
}
-
//------------------------------------------------------------------------------
// Quantization
//
-// Simple quantization
-static int QuantizeBlockSSE2(int16_t in[16], int16_t out[16],
- int n, const VP8Matrix* const mtx) {
- const __m128i max_coeff_2047 = _mm_set1_epi16(2047);
- const __m128i zero = _mm_set1_epi16(0);
- __m128i sign0, sign8;
+static WEBP_INLINE int DoQuantizeBlock(int16_t in[16], int16_t out[16],
+ const uint16_t* const sharpen,
+ const VP8Matrix* const mtx) {
+ const __m128i max_coeff_2047 = _mm_set1_epi16(MAX_LEVEL);
+ const __m128i zero = _mm_setzero_si128();
__m128i coeff0, coeff8;
__m128i out0, out8;
__m128i packed_out;
@@ -701,20 +1332,14 @@ static int QuantizeBlockSSE2(int16_t in[16], int16_t out[16],
// we can use _mm_load_si128 instead of _mm_loadu_si128.
__m128i in0 = _mm_loadu_si128((__m128i*)&in[0]);
__m128i in8 = _mm_loadu_si128((__m128i*)&in[8]);
- const __m128i sharpen0 = _mm_loadu_si128((__m128i*)&mtx->sharpen_[0]);
- const __m128i sharpen8 = _mm_loadu_si128((__m128i*)&mtx->sharpen_[8]);
- const __m128i iq0 = _mm_loadu_si128((__m128i*)&mtx->iq_[0]);
- const __m128i iq8 = _mm_loadu_si128((__m128i*)&mtx->iq_[8]);
- const __m128i bias0 = _mm_loadu_si128((__m128i*)&mtx->bias_[0]);
- const __m128i bias8 = _mm_loadu_si128((__m128i*)&mtx->bias_[8]);
- const __m128i q0 = _mm_loadu_si128((__m128i*)&mtx->q_[0]);
- const __m128i q8 = _mm_loadu_si128((__m128i*)&mtx->q_[8]);
- const __m128i zthresh0 = _mm_loadu_si128((__m128i*)&mtx->zthresh_[0]);
- const __m128i zthresh8 = _mm_loadu_si128((__m128i*)&mtx->zthresh_[8]);
-
- // sign(in) = in >> 15 (0x0000 if positive, 0xffff if negative)
- sign0 = _mm_srai_epi16(in0, 15);
- sign8 = _mm_srai_epi16(in8, 15);
+ const __m128i iq0 = _mm_loadu_si128((const __m128i*)&mtx->iq_[0]);
+ const __m128i iq8 = _mm_loadu_si128((const __m128i*)&mtx->iq_[8]);
+ const __m128i q0 = _mm_loadu_si128((const __m128i*)&mtx->q_[0]);
+ const __m128i q8 = _mm_loadu_si128((const __m128i*)&mtx->q_[8]);
+
+ // extract sign(in) (0x0000 if positive, 0xffff if negative)
+ const __m128i sign0 = _mm_cmpgt_epi16(zero, in0);
+ const __m128i sign8 = _mm_cmpgt_epi16(zero, in8);
// coeff = abs(in) = (in ^ sign) - sign
coeff0 = _mm_xor_si128(in0, sign0);
@@ -723,43 +1348,47 @@ static int QuantizeBlockSSE2(int16_t in[16], int16_t out[16],
coeff8 = _mm_sub_epi16(coeff8, sign8);
// coeff = abs(in) + sharpen
- coeff0 = _mm_add_epi16(coeff0, sharpen0);
- coeff8 = _mm_add_epi16(coeff8, sharpen8);
-
- // if (coeff > 2047) coeff = 2047
- coeff0 = _mm_min_epi16(coeff0, max_coeff_2047);
- coeff8 = _mm_min_epi16(coeff8, max_coeff_2047);
+ if (sharpen != NULL) {
+ const __m128i sharpen0 = _mm_loadu_si128((const __m128i*)&sharpen[0]);
+ const __m128i sharpen8 = _mm_loadu_si128((const __m128i*)&sharpen[8]);
+ coeff0 = _mm_add_epi16(coeff0, sharpen0);
+ coeff8 = _mm_add_epi16(coeff8, sharpen8);
+ }
- // out = (coeff * iQ + B) >> QFIX;
+ // out = (coeff * iQ + B) >> QFIX
{
// doing calculations with 32b precision (QFIX=17)
// out = (coeff * iQ)
- __m128i coeff_iQ0H = _mm_mulhi_epu16(coeff0, iq0);
- __m128i coeff_iQ0L = _mm_mullo_epi16(coeff0, iq0);
- __m128i coeff_iQ8H = _mm_mulhi_epu16(coeff8, iq8);
- __m128i coeff_iQ8L = _mm_mullo_epi16(coeff8, iq8);
+ const __m128i coeff_iQ0H = _mm_mulhi_epu16(coeff0, iq0);
+ const __m128i coeff_iQ0L = _mm_mullo_epi16(coeff0, iq0);
+ const __m128i coeff_iQ8H = _mm_mulhi_epu16(coeff8, iq8);
+ const __m128i coeff_iQ8L = _mm_mullo_epi16(coeff8, iq8);
__m128i out_00 = _mm_unpacklo_epi16(coeff_iQ0L, coeff_iQ0H);
__m128i out_04 = _mm_unpackhi_epi16(coeff_iQ0L, coeff_iQ0H);
__m128i out_08 = _mm_unpacklo_epi16(coeff_iQ8L, coeff_iQ8H);
__m128i out_12 = _mm_unpackhi_epi16(coeff_iQ8L, coeff_iQ8H);
- // expand bias from 16b to 32b
- __m128i bias_00 = _mm_unpacklo_epi16(bias0, zero);
- __m128i bias_04 = _mm_unpackhi_epi16(bias0, zero);
- __m128i bias_08 = _mm_unpacklo_epi16(bias8, zero);
- __m128i bias_12 = _mm_unpackhi_epi16(bias8, zero);
// out = (coeff * iQ + B)
+ const __m128i bias_00 = _mm_loadu_si128((const __m128i*)&mtx->bias_[0]);
+ const __m128i bias_04 = _mm_loadu_si128((const __m128i*)&mtx->bias_[4]);
+ const __m128i bias_08 = _mm_loadu_si128((const __m128i*)&mtx->bias_[8]);
+ const __m128i bias_12 = _mm_loadu_si128((const __m128i*)&mtx->bias_[12]);
out_00 = _mm_add_epi32(out_00, bias_00);
out_04 = _mm_add_epi32(out_04, bias_04);
out_08 = _mm_add_epi32(out_08, bias_08);
out_12 = _mm_add_epi32(out_12, bias_12);
- // out = (coeff * iQ + B) >> QFIX;
+ // out = QUANTDIV(coeff, iQ, B, QFIX)
out_00 = _mm_srai_epi32(out_00, QFIX);
out_04 = _mm_srai_epi32(out_04, QFIX);
out_08 = _mm_srai_epi32(out_08, QFIX);
out_12 = _mm_srai_epi32(out_12, QFIX);
+
// pack result as 16b
out0 = _mm_packs_epi32(out_00, out_04);
out8 = _mm_packs_epi32(out_08, out_12);
+
+ // if (coeff > 2047) coeff = 2047
+ out0 = _mm_min_epi16(out0, max_coeff_2047);
+ out8 = _mm_min_epi16(out8, max_coeff_2047);
}
// get sign back (if (sign[j]) out_n = -out_n)
@@ -772,17 +1401,8 @@ static int QuantizeBlockSSE2(int16_t in[16], int16_t out[16],
in0 = _mm_mullo_epi16(out0, q0);
in8 = _mm_mullo_epi16(out8, q8);
- // if (coeff <= mtx->zthresh_) {in=0; out=0;}
- {
- __m128i cmp0 = _mm_cmpgt_epi16(coeff0, zthresh0);
- __m128i cmp8 = _mm_cmpgt_epi16(coeff8, zthresh8);
- in0 = _mm_and_si128(in0, cmp0);
- in8 = _mm_and_si128(in8, cmp8);
- _mm_storeu_si128((__m128i*)&in[0], in0);
- _mm_storeu_si128((__m128i*)&in[8], in8);
- out0 = _mm_and_si128(out0, cmp0);
- out8 = _mm_and_si128(out8, cmp8);
- }
+ _mm_storeu_si128((__m128i*)&in[0], in0);
+ _mm_storeu_si128((__m128i*)&in[8], in8);
// zigzag the output before storing it.
//
@@ -809,29 +1429,55 @@ static int QuantizeBlockSSE2(int16_t in[16], int16_t out[16],
}
// detect if all 'out' values are zeroes or not
- {
- int32_t tmp[4];
- _mm_storeu_si128((__m128i*)tmp, packed_out);
- if (n) {
- tmp[0] &= ~0xff;
- }
- return (tmp[3] || tmp[2] || tmp[1] || tmp[0]);
- }
+ return (_mm_movemask_epi8(_mm_cmpeq_epi8(packed_out, zero)) != 0xffff);
+}
+
+static int QuantizeBlock(int16_t in[16], int16_t out[16],
+ const VP8Matrix* const mtx) {
+ return DoQuantizeBlock(in, out, &mtx->sharpen_[0], mtx);
+}
+
+static int QuantizeBlockWHT(int16_t in[16], int16_t out[16],
+ const VP8Matrix* const mtx) {
+ return DoQuantizeBlock(in, out, NULL, mtx);
+}
+
+static int Quantize2Blocks(int16_t in[32], int16_t out[32],
+ const VP8Matrix* const mtx) {
+ int nz;
+ const uint16_t* const sharpen = &mtx->sharpen_[0];
+ nz = DoQuantizeBlock(in + 0 * 16, out + 0 * 16, sharpen, mtx) << 0;
+ nz |= DoQuantizeBlock(in + 1 * 16, out + 1 * 16, sharpen, mtx) << 1;
+ return nz;
}
+//------------------------------------------------------------------------------
+// Entry point
+
extern void VP8EncDspInitSSE2(void);
-void VP8EncDspInitSSE2(void) {
- VP8CollectHistogram = CollectHistogramSSE2;
- VP8EncQuantizeBlock = QuantizeBlockSSE2;
- VP8ITransform = ITransformSSE2;
- VP8FTransform = FTransformSSE2;
- VP8SSE4x4 = SSE4x4SSE2;
- VP8TDisto4x4 = Disto4x4SSE2;
- VP8TDisto16x16 = Disto16x16SSE2;
-}
-
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
-#endif // WEBP_USE_SSE2
+WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspInitSSE2(void) {
+ VP8CollectHistogram = CollectHistogram;
+ VP8EncPredLuma16 = Intra16Preds;
+ VP8EncPredChroma8 = IntraChromaPreds;
+ VP8EncPredLuma4 = Intra4Preds;
+ VP8EncQuantizeBlock = QuantizeBlock;
+ VP8EncQuantize2Blocks = Quantize2Blocks;
+ VP8EncQuantizeBlockWHT = QuantizeBlockWHT;
+ VP8ITransform = ITransform;
+ VP8FTransform = FTransform;
+ VP8FTransform2 = FTransform2;
+ VP8FTransformWHT = FTransformWHT;
+ VP8SSE16x16 = SSE16x16;
+ VP8SSE16x8 = SSE16x8;
+ VP8SSE8x8 = SSE8x8;
+ VP8SSE4x4 = SSE4x4;
+ VP8TDisto4x4 = Disto4x4;
+ VP8TDisto16x16 = Disto16x16;
+}
+
+#else // !WEBP_USE_SSE2
+
+WEBP_DSP_INIT_STUB(VP8EncDspInitSSE2)
+
+#endif // WEBP_USE_SSE2
diff --git a/drivers/webp/dsp/enc_sse41.c b/drivers/webp/dsp/enc_sse41.c
new file mode 100644
index 0000000000..27f4189833
--- /dev/null
+++ b/drivers/webp/dsp/enc_sse41.c
@@ -0,0 +1,375 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// SSE4 version of some encoding functions.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_SSE41)
+#include <smmintrin.h>
+#include <stdlib.h> // for abs()
+
+#include "../enc/vp8enci.h"
+
+//------------------------------------------------------------------------------
+// Compute susceptibility based on DCT-coeff histograms.
+
+static void CollectHistogram(const uint8_t* ref, const uint8_t* pred,
+ int start_block, int end_block,
+ VP8Histogram* const histo) {
+ const __m128i max_coeff_thresh = _mm_set1_epi16(MAX_COEFF_THRESH);
+ int j;
+ int distribution[MAX_COEFF_THRESH + 1] = { 0 };
+ for (j = start_block; j < end_block; ++j) {
+ int16_t out[16];
+ int k;
+
+ VP8FTransform(ref + VP8DspScan[j], pred + VP8DspScan[j], out);
+
+ // Convert coefficients to bin (within out[]).
+ {
+ // Load.
+ const __m128i out0 = _mm_loadu_si128((__m128i*)&out[0]);
+ const __m128i out1 = _mm_loadu_si128((__m128i*)&out[8]);
+ // v = abs(out) >> 3
+ const __m128i abs0 = _mm_abs_epi16(out0);
+ const __m128i abs1 = _mm_abs_epi16(out1);
+ const __m128i v0 = _mm_srai_epi16(abs0, 3);
+ const __m128i v1 = _mm_srai_epi16(abs1, 3);
+ // bin = min(v, MAX_COEFF_THRESH)
+ const __m128i bin0 = _mm_min_epi16(v0, max_coeff_thresh);
+ const __m128i bin1 = _mm_min_epi16(v1, max_coeff_thresh);
+ // Store.
+ _mm_storeu_si128((__m128i*)&out[0], bin0);
+ _mm_storeu_si128((__m128i*)&out[8], bin1);
+ }
+
+ // Convert coefficients to bin.
+ for (k = 0; k < 16; ++k) {
+ ++distribution[out[k]];
+ }
+ }
+ VP8SetHistogramData(distribution, histo);
+}
+
+//------------------------------------------------------------------------------
+// Texture distortion
+//
+// We try to match the spectral content (weighted) between source and
+// reconstructed samples.
+
+// Hadamard transform
+// Returns the difference between the weighted sum of the absolute value of
+// transformed coefficients.
+static int TTransform(const uint8_t* inA, const uint8_t* inB,
+ const uint16_t* const w) {
+ __m128i tmp_0, tmp_1, tmp_2, tmp_3;
+
+ // Load, combine and transpose inputs.
+ {
+ const __m128i inA_0 = _mm_loadl_epi64((const __m128i*)&inA[BPS * 0]);
+ const __m128i inA_1 = _mm_loadl_epi64((const __m128i*)&inA[BPS * 1]);
+ const __m128i inA_2 = _mm_loadl_epi64((const __m128i*)&inA[BPS * 2]);
+ const __m128i inA_3 = _mm_loadl_epi64((const __m128i*)&inA[BPS * 3]);
+ const __m128i inB_0 = _mm_loadl_epi64((const __m128i*)&inB[BPS * 0]);
+ const __m128i inB_1 = _mm_loadl_epi64((const __m128i*)&inB[BPS * 1]);
+ const __m128i inB_2 = _mm_loadl_epi64((const __m128i*)&inB[BPS * 2]);
+ const __m128i inB_3 = _mm_loadl_epi64((const __m128i*)&inB[BPS * 3]);
+
+ // Combine inA and inB (we'll do two transforms in parallel).
+ const __m128i inAB_0 = _mm_unpacklo_epi8(inA_0, inB_0);
+ const __m128i inAB_1 = _mm_unpacklo_epi8(inA_1, inB_1);
+ const __m128i inAB_2 = _mm_unpacklo_epi8(inA_2, inB_2);
+ const __m128i inAB_3 = _mm_unpacklo_epi8(inA_3, inB_3);
+ // a00 b00 a01 b01 a02 b03 a03 b03 0 0 0 0 0 0 0 0
+ // a10 b10 a11 b11 a12 b12 a13 b13 0 0 0 0 0 0 0 0
+ // a20 b20 a21 b21 a22 b22 a23 b23 0 0 0 0 0 0 0 0
+ // a30 b30 a31 b31 a32 b32 a33 b33 0 0 0 0 0 0 0 0
+
+ // Transpose the two 4x4, discarding the filling zeroes.
+ const __m128i transpose0_0 = _mm_unpacklo_epi8(inAB_0, inAB_2);
+ const __m128i transpose0_1 = _mm_unpacklo_epi8(inAB_1, inAB_3);
+ // a00 a20 b00 b20 a01 a21 b01 b21 a02 a22 b02 b22 a03 a23 b03 b23
+ // a10 a30 b10 b30 a11 a31 b11 b31 a12 a32 b12 b32 a13 a33 b13 b33
+ const __m128i transpose1_0 = _mm_unpacklo_epi8(transpose0_0, transpose0_1);
+ const __m128i transpose1_1 = _mm_unpackhi_epi8(transpose0_0, transpose0_1);
+ // a00 a10 a20 a30 b00 b10 b20 b30 a01 a11 a21 a31 b01 b11 b21 b31
+ // a02 a12 a22 a32 b02 b12 b22 b32 a03 a13 a23 a33 b03 b13 b23 b33
+
+ // Convert to 16b.
+ tmp_0 = _mm_cvtepu8_epi16(transpose1_0);
+ tmp_1 = _mm_cvtepu8_epi16(_mm_srli_si128(transpose1_0, 8));
+ tmp_2 = _mm_cvtepu8_epi16(transpose1_1);
+ tmp_3 = _mm_cvtepu8_epi16(_mm_srli_si128(transpose1_1, 8));
+ // a00 a10 a20 a30 b00 b10 b20 b30
+ // a01 a11 a21 a31 b01 b11 b21 b31
+ // a02 a12 a22 a32 b02 b12 b22 b32
+ // a03 a13 a23 a33 b03 b13 b23 b33
+ }
+
+ // Horizontal pass and subsequent transpose.
+ {
+ // Calculate a and b (two 4x4 at once).
+ const __m128i a0 = _mm_add_epi16(tmp_0, tmp_2);
+ const __m128i a1 = _mm_add_epi16(tmp_1, tmp_3);
+ const __m128i a2 = _mm_sub_epi16(tmp_1, tmp_3);
+ const __m128i a3 = _mm_sub_epi16(tmp_0, tmp_2);
+ const __m128i b0 = _mm_add_epi16(a0, a1);
+ const __m128i b1 = _mm_add_epi16(a3, a2);
+ const __m128i b2 = _mm_sub_epi16(a3, a2);
+ const __m128i b3 = _mm_sub_epi16(a0, a1);
+ // a00 a01 a02 a03 b00 b01 b02 b03
+ // a10 a11 a12 a13 b10 b11 b12 b13
+ // a20 a21 a22 a23 b20 b21 b22 b23
+ // a30 a31 a32 a33 b30 b31 b32 b33
+
+ // Transpose the two 4x4.
+ const __m128i transpose0_0 = _mm_unpacklo_epi16(b0, b1);
+ const __m128i transpose0_1 = _mm_unpacklo_epi16(b2, b3);
+ const __m128i transpose0_2 = _mm_unpackhi_epi16(b0, b1);
+ const __m128i transpose0_3 = _mm_unpackhi_epi16(b2, b3);
+ // a00 a10 a01 a11 a02 a12 a03 a13
+ // a20 a30 a21 a31 a22 a32 a23 a33
+ // b00 b10 b01 b11 b02 b12 b03 b13
+ // b20 b30 b21 b31 b22 b32 b23 b33
+ const __m128i transpose1_0 = _mm_unpacklo_epi32(transpose0_0, transpose0_1);
+ const __m128i transpose1_1 = _mm_unpacklo_epi32(transpose0_2, transpose0_3);
+ const __m128i transpose1_2 = _mm_unpackhi_epi32(transpose0_0, transpose0_1);
+ const __m128i transpose1_3 = _mm_unpackhi_epi32(transpose0_2, transpose0_3);
+ // a00 a10 a20 a30 a01 a11 a21 a31
+ // b00 b10 b20 b30 b01 b11 b21 b31
+ // a02 a12 a22 a32 a03 a13 a23 a33
+ // b02 b12 a22 b32 b03 b13 b23 b33
+ tmp_0 = _mm_unpacklo_epi64(transpose1_0, transpose1_1);
+ tmp_1 = _mm_unpackhi_epi64(transpose1_0, transpose1_1);
+ tmp_2 = _mm_unpacklo_epi64(transpose1_2, transpose1_3);
+ tmp_3 = _mm_unpackhi_epi64(transpose1_2, transpose1_3);
+ // a00 a10 a20 a30 b00 b10 b20 b30
+ // a01 a11 a21 a31 b01 b11 b21 b31
+ // a02 a12 a22 a32 b02 b12 b22 b32
+ // a03 a13 a23 a33 b03 b13 b23 b33
+ }
+
+ // Vertical pass and difference of weighted sums.
+ {
+ // Load all inputs.
+ const __m128i w_0 = _mm_loadu_si128((const __m128i*)&w[0]);
+ const __m128i w_8 = _mm_loadu_si128((const __m128i*)&w[8]);
+
+ // Calculate a and b (two 4x4 at once).
+ const __m128i a0 = _mm_add_epi16(tmp_0, tmp_2);
+ const __m128i a1 = _mm_add_epi16(tmp_1, tmp_3);
+ const __m128i a2 = _mm_sub_epi16(tmp_1, tmp_3);
+ const __m128i a3 = _mm_sub_epi16(tmp_0, tmp_2);
+ const __m128i b0 = _mm_add_epi16(a0, a1);
+ const __m128i b1 = _mm_add_epi16(a3, a2);
+ const __m128i b2 = _mm_sub_epi16(a3, a2);
+ const __m128i b3 = _mm_sub_epi16(a0, a1);
+
+ // Separate the transforms of inA and inB.
+ __m128i A_b0 = _mm_unpacklo_epi64(b0, b1);
+ __m128i A_b2 = _mm_unpacklo_epi64(b2, b3);
+ __m128i B_b0 = _mm_unpackhi_epi64(b0, b1);
+ __m128i B_b2 = _mm_unpackhi_epi64(b2, b3);
+
+ A_b0 = _mm_abs_epi16(A_b0);
+ A_b2 = _mm_abs_epi16(A_b2);
+ B_b0 = _mm_abs_epi16(B_b0);
+ B_b2 = _mm_abs_epi16(B_b2);
+
+ // weighted sums
+ A_b0 = _mm_madd_epi16(A_b0, w_0);
+ A_b2 = _mm_madd_epi16(A_b2, w_8);
+ B_b0 = _mm_madd_epi16(B_b0, w_0);
+ B_b2 = _mm_madd_epi16(B_b2, w_8);
+ A_b0 = _mm_add_epi32(A_b0, A_b2);
+ B_b0 = _mm_add_epi32(B_b0, B_b2);
+
+ // difference of weighted sums
+ A_b2 = _mm_sub_epi32(A_b0, B_b0);
+ // cascading summation of the differences
+ B_b0 = _mm_hadd_epi32(A_b2, A_b2);
+ B_b2 = _mm_hadd_epi32(B_b0, B_b0);
+ return _mm_cvtsi128_si32(B_b2);
+ }
+}
+
+static int Disto4x4(const uint8_t* const a, const uint8_t* const b,
+ const uint16_t* const w) {
+ const int diff_sum = TTransform(a, b, w);
+ return abs(diff_sum) >> 5;
+}
+
+static int Disto16x16(const uint8_t* const a, const uint8_t* const b,
+ const uint16_t* const w) {
+ int D = 0;
+ int x, y;
+ for (y = 0; y < 16 * BPS; y += 4 * BPS) {
+ for (x = 0; x < 16; x += 4) {
+ D += Disto4x4(a + x + y, b + x + y, w);
+ }
+ }
+ return D;
+}
+
+//------------------------------------------------------------------------------
+// Quantization
+//
+
+// Generates a pshufb constant for shuffling 16b words.
+#define PSHUFB_CST(A,B,C,D,E,F,G,H) \
+ _mm_set_epi8(2 * (H) + 1, 2 * (H) + 0, 2 * (G) + 1, 2 * (G) + 0, \
+ 2 * (F) + 1, 2 * (F) + 0, 2 * (E) + 1, 2 * (E) + 0, \
+ 2 * (D) + 1, 2 * (D) + 0, 2 * (C) + 1, 2 * (C) + 0, \
+ 2 * (B) + 1, 2 * (B) + 0, 2 * (A) + 1, 2 * (A) + 0)
+
+static WEBP_INLINE int DoQuantizeBlock(int16_t in[16], int16_t out[16],
+ const uint16_t* const sharpen,
+ const VP8Matrix* const mtx) {
+ const __m128i max_coeff_2047 = _mm_set1_epi16(MAX_LEVEL);
+ const __m128i zero = _mm_setzero_si128();
+ __m128i out0, out8;
+ __m128i packed_out;
+
+ // Load all inputs.
+ // TODO(cduvivier): Make variable declarations and allocations aligned so that
+ // we can use _mm_load_si128 instead of _mm_loadu_si128.
+ __m128i in0 = _mm_loadu_si128((__m128i*)&in[0]);
+ __m128i in8 = _mm_loadu_si128((__m128i*)&in[8]);
+ const __m128i iq0 = _mm_loadu_si128((const __m128i*)&mtx->iq_[0]);
+ const __m128i iq8 = _mm_loadu_si128((const __m128i*)&mtx->iq_[8]);
+ const __m128i q0 = _mm_loadu_si128((const __m128i*)&mtx->q_[0]);
+ const __m128i q8 = _mm_loadu_si128((const __m128i*)&mtx->q_[8]);
+
+ // coeff = abs(in)
+ __m128i coeff0 = _mm_abs_epi16(in0);
+ __m128i coeff8 = _mm_abs_epi16(in8);
+
+ // coeff = abs(in) + sharpen
+ if (sharpen != NULL) {
+ const __m128i sharpen0 = _mm_loadu_si128((const __m128i*)&sharpen[0]);
+ const __m128i sharpen8 = _mm_loadu_si128((const __m128i*)&sharpen[8]);
+ coeff0 = _mm_add_epi16(coeff0, sharpen0);
+ coeff8 = _mm_add_epi16(coeff8, sharpen8);
+ }
+
+ // out = (coeff * iQ + B) >> QFIX
+ {
+ // doing calculations with 32b precision (QFIX=17)
+ // out = (coeff * iQ)
+ const __m128i coeff_iQ0H = _mm_mulhi_epu16(coeff0, iq0);
+ const __m128i coeff_iQ0L = _mm_mullo_epi16(coeff0, iq0);
+ const __m128i coeff_iQ8H = _mm_mulhi_epu16(coeff8, iq8);
+ const __m128i coeff_iQ8L = _mm_mullo_epi16(coeff8, iq8);
+ __m128i out_00 = _mm_unpacklo_epi16(coeff_iQ0L, coeff_iQ0H);
+ __m128i out_04 = _mm_unpackhi_epi16(coeff_iQ0L, coeff_iQ0H);
+ __m128i out_08 = _mm_unpacklo_epi16(coeff_iQ8L, coeff_iQ8H);
+ __m128i out_12 = _mm_unpackhi_epi16(coeff_iQ8L, coeff_iQ8H);
+ // out = (coeff * iQ + B)
+ const __m128i bias_00 = _mm_loadu_si128((const __m128i*)&mtx->bias_[0]);
+ const __m128i bias_04 = _mm_loadu_si128((const __m128i*)&mtx->bias_[4]);
+ const __m128i bias_08 = _mm_loadu_si128((const __m128i*)&mtx->bias_[8]);
+ const __m128i bias_12 = _mm_loadu_si128((const __m128i*)&mtx->bias_[12]);
+ out_00 = _mm_add_epi32(out_00, bias_00);
+ out_04 = _mm_add_epi32(out_04, bias_04);
+ out_08 = _mm_add_epi32(out_08, bias_08);
+ out_12 = _mm_add_epi32(out_12, bias_12);
+ // out = QUANTDIV(coeff, iQ, B, QFIX)
+ out_00 = _mm_srai_epi32(out_00, QFIX);
+ out_04 = _mm_srai_epi32(out_04, QFIX);
+ out_08 = _mm_srai_epi32(out_08, QFIX);
+ out_12 = _mm_srai_epi32(out_12, QFIX);
+
+ // pack result as 16b
+ out0 = _mm_packs_epi32(out_00, out_04);
+ out8 = _mm_packs_epi32(out_08, out_12);
+
+ // if (coeff > 2047) coeff = 2047
+ out0 = _mm_min_epi16(out0, max_coeff_2047);
+ out8 = _mm_min_epi16(out8, max_coeff_2047);
+ }
+
+ // put sign back
+ out0 = _mm_sign_epi16(out0, in0);
+ out8 = _mm_sign_epi16(out8, in8);
+
+ // in = out * Q
+ in0 = _mm_mullo_epi16(out0, q0);
+ in8 = _mm_mullo_epi16(out8, q8);
+
+ _mm_storeu_si128((__m128i*)&in[0], in0);
+ _mm_storeu_si128((__m128i*)&in[8], in8);
+
+ // zigzag the output before storing it. The re-ordering is:
+ // 0 1 2 3 4 5 6 7 | 8 9 10 11 12 13 14 15
+ // -> 0 1 4[8]5 2 3 6 | 9 12 13 10 [7]11 14 15
+ // There's only two misplaced entries ([8] and [7]) that are crossing the
+ // reg's boundaries.
+ // We use pshufb instead of pshuflo/pshufhi.
+ {
+ const __m128i kCst_lo = PSHUFB_CST(0, 1, 4, -1, 5, 2, 3, 6);
+ const __m128i kCst_7 = PSHUFB_CST(-1, -1, -1, -1, 7, -1, -1, -1);
+ const __m128i tmp_lo = _mm_shuffle_epi8(out0, kCst_lo);
+ const __m128i tmp_7 = _mm_shuffle_epi8(out0, kCst_7); // extract #7
+ const __m128i kCst_hi = PSHUFB_CST(1, 4, 5, 2, -1, 3, 6, 7);
+ const __m128i kCst_8 = PSHUFB_CST(-1, -1, -1, 0, -1, -1, -1, -1);
+ const __m128i tmp_hi = _mm_shuffle_epi8(out8, kCst_hi);
+ const __m128i tmp_8 = _mm_shuffle_epi8(out8, kCst_8); // extract #8
+ const __m128i out_z0 = _mm_or_si128(tmp_lo, tmp_8);
+ const __m128i out_z8 = _mm_or_si128(tmp_hi, tmp_7);
+ _mm_storeu_si128((__m128i*)&out[0], out_z0);
+ _mm_storeu_si128((__m128i*)&out[8], out_z8);
+ packed_out = _mm_packs_epi16(out_z0, out_z8);
+ }
+
+ // detect if all 'out' values are zeroes or not
+ return (_mm_movemask_epi8(_mm_cmpeq_epi8(packed_out, zero)) != 0xffff);
+}
+
+#undef PSHUFB_CST
+
+static int QuantizeBlock(int16_t in[16], int16_t out[16],
+ const VP8Matrix* const mtx) {
+ return DoQuantizeBlock(in, out, &mtx->sharpen_[0], mtx);
+}
+
+static int QuantizeBlockWHT(int16_t in[16], int16_t out[16],
+ const VP8Matrix* const mtx) {
+ return DoQuantizeBlock(in, out, NULL, mtx);
+}
+
+static int Quantize2Blocks(int16_t in[32], int16_t out[32],
+ const VP8Matrix* const mtx) {
+ int nz;
+ const uint16_t* const sharpen = &mtx->sharpen_[0];
+ nz = DoQuantizeBlock(in + 0 * 16, out + 0 * 16, sharpen, mtx) << 0;
+ nz |= DoQuantizeBlock(in + 1 * 16, out + 1 * 16, sharpen, mtx) << 1;
+ return nz;
+}
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8EncDspInitSSE41(void);
+WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspInitSSE41(void) {
+ VP8CollectHistogram = CollectHistogram;
+ VP8EncQuantizeBlock = QuantizeBlock;
+ VP8EncQuantize2Blocks = Quantize2Blocks;
+ VP8EncQuantizeBlockWHT = QuantizeBlockWHT;
+ VP8TDisto4x4 = Disto4x4;
+ VP8TDisto16x16 = Disto16x16;
+}
+
+#else // !WEBP_USE_SSE41
+
+WEBP_DSP_INIT_STUB(VP8EncDspInitSSE41)
+
+#endif // WEBP_USE_SSE41
diff --git a/drivers/webp/dsp/filters.c b/drivers/webp/dsp/filters.c
new file mode 100644
index 0000000000..5c30f2e457
--- /dev/null
+++ b/drivers/webp/dsp/filters.c
@@ -0,0 +1,240 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Spatial prediction using various filters
+//
+// Author: Urvang (urvang@google.com)
+
+#include "./dsp.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// Helpful macro.
+
+# define SANITY_CHECK(in, out) \
+ assert(in != NULL); \
+ assert(out != NULL); \
+ assert(width > 0); \
+ assert(height > 0); \
+ assert(stride >= width); \
+ assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \
+ (void)height; // Silence unused warning.
+
+static WEBP_INLINE void PredictLine(const uint8_t* src, const uint8_t* pred,
+ uint8_t* dst, int length, int inverse) {
+ int i;
+ if (inverse) {
+ for (i = 0; i < length; ++i) dst[i] = src[i] + pred[i];
+ } else {
+ for (i = 0; i < length; ++i) dst[i] = src[i] - pred[i];
+ }
+}
+
+//------------------------------------------------------------------------------
+// Horizontal filter.
+
+static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in,
+ int width, int height, int stride,
+ int row, int num_rows,
+ int inverse, uint8_t* out) {
+ const uint8_t* preds;
+ const size_t start_offset = row * stride;
+ const int last_row = row + num_rows;
+ SANITY_CHECK(in, out);
+ in += start_offset;
+ out += start_offset;
+ preds = inverse ? out : in;
+
+ if (row == 0) {
+ // Leftmost pixel is the same as input for topmost scanline.
+ out[0] = in[0];
+ PredictLine(in + 1, preds, out + 1, width - 1, inverse);
+ row = 1;
+ preds += stride;
+ in += stride;
+ out += stride;
+ }
+
+ // Filter line-by-line.
+ while (row < last_row) {
+ // Leftmost pixel is predicted from above.
+ PredictLine(in, preds - stride, out, 1, inverse);
+ PredictLine(in + 1, preds, out + 1, width - 1, inverse);
+ ++row;
+ preds += stride;
+ in += stride;
+ out += stride;
+ }
+}
+
+//------------------------------------------------------------------------------
+// Vertical filter.
+
+static WEBP_INLINE void DoVerticalFilter(const uint8_t* in,
+ int width, int height, int stride,
+ int row, int num_rows,
+ int inverse, uint8_t* out) {
+ const uint8_t* preds;
+ const size_t start_offset = row * stride;
+ const int last_row = row + num_rows;
+ SANITY_CHECK(in, out);
+ in += start_offset;
+ out += start_offset;
+ preds = inverse ? out : in;
+
+ if (row == 0) {
+ // Very first top-left pixel is copied.
+ out[0] = in[0];
+ // Rest of top scan-line is left-predicted.
+ PredictLine(in + 1, preds, out + 1, width - 1, inverse);
+ row = 1;
+ in += stride;
+ out += stride;
+ } else {
+ // We are starting from in-between. Make sure 'preds' points to prev row.
+ preds -= stride;
+ }
+
+ // Filter line-by-line.
+ while (row < last_row) {
+ PredictLine(in, preds, out, width, inverse);
+ ++row;
+ preds += stride;
+ in += stride;
+ out += stride;
+ }
+}
+
+//------------------------------------------------------------------------------
+// Gradient filter.
+
+static WEBP_INLINE int GradientPredictor(uint8_t a, uint8_t b, uint8_t c) {
+ const int g = a + b - c;
+ return ((g & ~0xff) == 0) ? g : (g < 0) ? 0 : 255; // clip to 8bit
+}
+
+static WEBP_INLINE void DoGradientFilter(const uint8_t* in,
+ int width, int height, int stride,
+ int row, int num_rows,
+ int inverse, uint8_t* out) {
+ const uint8_t* preds;
+ const size_t start_offset = row * stride;
+ const int last_row = row + num_rows;
+ SANITY_CHECK(in, out);
+ in += start_offset;
+ out += start_offset;
+ preds = inverse ? out : in;
+
+ // left prediction for top scan-line
+ if (row == 0) {
+ out[0] = in[0];
+ PredictLine(in + 1, preds, out + 1, width - 1, inverse);
+ row = 1;
+ preds += stride;
+ in += stride;
+ out += stride;
+ }
+
+ // Filter line-by-line.
+ while (row < last_row) {
+ int w;
+ // leftmost pixel: predict from above.
+ PredictLine(in, preds - stride, out, 1, inverse);
+ for (w = 1; w < width; ++w) {
+ const int pred = GradientPredictor(preds[w - 1],
+ preds[w - stride],
+ preds[w - stride - 1]);
+ out[w] = in[w] + (inverse ? pred : -pred);
+ }
+ ++row;
+ preds += stride;
+ in += stride;
+ out += stride;
+ }
+}
+
+#undef SANITY_CHECK
+
+//------------------------------------------------------------------------------
+
+static void HorizontalFilter(const uint8_t* data, int width, int height,
+ int stride, uint8_t* filtered_data) {
+ DoHorizontalFilter(data, width, height, stride, 0, height, 0, filtered_data);
+}
+
+static void VerticalFilter(const uint8_t* data, int width, int height,
+ int stride, uint8_t* filtered_data) {
+ DoVerticalFilter(data, width, height, stride, 0, height, 0, filtered_data);
+}
+
+
+static void GradientFilter(const uint8_t* data, int width, int height,
+ int stride, uint8_t* filtered_data) {
+ DoGradientFilter(data, width, height, stride, 0, height, 0, filtered_data);
+}
+
+
+//------------------------------------------------------------------------------
+
+static void VerticalUnfilter(int width, int height, int stride, int row,
+ int num_rows, uint8_t* data) {
+ DoVerticalFilter(data, width, height, stride, row, num_rows, 1, data);
+}
+
+static void HorizontalUnfilter(int width, int height, int stride, int row,
+ int num_rows, uint8_t* data) {
+ DoHorizontalFilter(data, width, height, stride, row, num_rows, 1, data);
+}
+
+static void GradientUnfilter(int width, int height, int stride, int row,
+ int num_rows, uint8_t* data) {
+ DoGradientFilter(data, width, height, stride, row, num_rows, 1, data);
+}
+
+//------------------------------------------------------------------------------
+// Init function
+
+WebPFilterFunc WebPFilters[WEBP_FILTER_LAST];
+WebPUnfilterFunc WebPUnfilters[WEBP_FILTER_LAST];
+
+extern void VP8FiltersInitMIPSdspR2(void);
+extern void VP8FiltersInitSSE2(void);
+
+static volatile VP8CPUInfo filters_last_cpuinfo_used =
+ (VP8CPUInfo)&filters_last_cpuinfo_used;
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInit(void) {
+ if (filters_last_cpuinfo_used == VP8GetCPUInfo) return;
+
+ WebPUnfilters[WEBP_FILTER_NONE] = NULL;
+ WebPUnfilters[WEBP_FILTER_HORIZONTAL] = HorizontalUnfilter;
+ WebPUnfilters[WEBP_FILTER_VERTICAL] = VerticalUnfilter;
+ WebPUnfilters[WEBP_FILTER_GRADIENT] = GradientUnfilter;
+
+ WebPFilters[WEBP_FILTER_NONE] = NULL;
+ WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter;
+ WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter;
+ WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter;
+
+ if (VP8GetCPUInfo != NULL) {
+#if defined(WEBP_USE_SSE2)
+ if (VP8GetCPUInfo(kSSE2)) {
+ VP8FiltersInitSSE2();
+ }
+#endif
+#if defined(WEBP_USE_MIPS_DSP_R2)
+ if (VP8GetCPUInfo(kMIPSdspR2)) {
+ VP8FiltersInitMIPSdspR2();
+ }
+#endif
+ }
+ filters_last_cpuinfo_used = VP8GetCPUInfo;
+}
diff --git a/drivers/webp/dsp/filters_mips_dsp_r2.c b/drivers/webp/dsp/filters_mips_dsp_r2.c
new file mode 100644
index 0000000000..8134af511b
--- /dev/null
+++ b/drivers/webp/dsp/filters_mips_dsp_r2.c
@@ -0,0 +1,405 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Spatial prediction using various filters
+//
+// Author(s): Branimir Vasic (branimir.vasic@imgtec.com)
+// Djordje Pesut (djordje.pesut@imgtec.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_MIPS_DSP_R2)
+
+#include "../dsp/dsp.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// Helpful macro.
+
+# define SANITY_CHECK(in, out) \
+ assert(in != NULL); \
+ assert(out != NULL); \
+ assert(width > 0); \
+ assert(height > 0); \
+ assert(stride >= width); \
+ assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \
+ (void)height; // Silence unused warning.
+
+// if INVERSE
+// preds == &dst[-1] == &src[-1]
+// else
+// preds == &src[-1] != &dst[-1]
+#define DO_PREDICT_LINE(SRC, DST, LENGTH, INVERSE) do { \
+ const uint8_t* psrc = (uint8_t*)(SRC); \
+ uint8_t* pdst = (uint8_t*)(DST); \
+ const int ilength = (int)(LENGTH); \
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6; \
+ __asm__ volatile ( \
+ ".set push \n\t" \
+ ".set noreorder \n\t" \
+ "srl %[temp0], %[length], 0x2 \n\t" \
+ "beqz %[temp0], 4f \n\t" \
+ " andi %[temp6], %[length], 0x3 \n\t" \
+ ".if " #INVERSE " \n\t" \
+ "lbu %[temp1], -1(%[src]) \n\t" \
+ "1: \n\t" \
+ "lbu %[temp2], 0(%[src]) \n\t" \
+ "lbu %[temp3], 1(%[src]) \n\t" \
+ "lbu %[temp4], 2(%[src]) \n\t" \
+ "lbu %[temp5], 3(%[src]) \n\t" \
+ "addiu %[src], %[src], 4 \n\t" \
+ "addiu %[temp0], %[temp0], -1 \n\t" \
+ "addu %[temp2], %[temp2], %[temp1] \n\t" \
+ "addu %[temp3], %[temp3], %[temp2] \n\t" \
+ "addu %[temp4], %[temp4], %[temp3] \n\t" \
+ "addu %[temp1], %[temp5], %[temp4] \n\t" \
+ "sb %[temp2], -4(%[src]) \n\t" \
+ "sb %[temp3], -3(%[src]) \n\t" \
+ "sb %[temp4], -2(%[src]) \n\t" \
+ "bnez %[temp0], 1b \n\t" \
+ " sb %[temp1], -1(%[src]) \n\t" \
+ ".else \n\t" \
+ "1: \n\t" \
+ "ulw %[temp1], -1(%[src]) \n\t" \
+ "ulw %[temp2], 0(%[src]) \n\t" \
+ "addiu %[src], %[src], 4 \n\t" \
+ "addiu %[temp0], %[temp0], -1 \n\t" \
+ "subu.qb %[temp3], %[temp2], %[temp1] \n\t" \
+ "usw %[temp3], 0(%[dst]) \n\t" \
+ "bnez %[temp0], 1b \n\t" \
+ " addiu %[dst], %[dst], 4 \n\t" \
+ ".endif \n\t" \
+ "4: \n\t" \
+ "beqz %[temp6], 3f \n\t" \
+ " nop \n\t" \
+ "2: \n\t" \
+ "lbu %[temp1], -1(%[src]) \n\t" \
+ "lbu %[temp2], 0(%[src]) \n\t" \
+ "addiu %[src], %[src], 1 \n\t" \
+ ".if " #INVERSE " \n\t" \
+ "addu %[temp3], %[temp1], %[temp2] \n\t" \
+ "sb %[temp3], -1(%[src]) \n\t" \
+ ".else \n\t" \
+ "subu %[temp3], %[temp1], %[temp2] \n\t" \
+ "sb %[temp3], 0(%[dst]) \n\t" \
+ ".endif \n\t" \
+ "addiu %[temp6], %[temp6], -1 \n\t" \
+ "bnez %[temp6], 2b \n\t" \
+ " addiu %[dst], %[dst], 1 \n\t" \
+ "3: \n\t" \
+ ".set pop \n\t" \
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), \
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), \
+ [temp6]"=&r"(temp6), [dst]"+&r"(pdst), [src]"+&r"(psrc) \
+ : [length]"r"(ilength) \
+ : "memory" \
+ ); \
+ } while (0)
+
+static WEBP_INLINE void PredictLine(const uint8_t* src, uint8_t* dst,
+ int length, int inverse) {
+ if (inverse) {
+ DO_PREDICT_LINE(src, dst, length, 1);
+ } else {
+ DO_PREDICT_LINE(src, dst, length, 0);
+ }
+}
+
+#define DO_PREDICT_LINE_VERTICAL(SRC, PRED, DST, LENGTH, INVERSE) do { \
+ const uint8_t* psrc = (uint8_t*)(SRC); \
+ const uint8_t* ppred = (uint8_t*)(PRED); \
+ uint8_t* pdst = (uint8_t*)(DST); \
+ const int ilength = (int)(LENGTH); \
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; \
+ __asm__ volatile ( \
+ ".set push \n\t" \
+ ".set noreorder \n\t" \
+ "srl %[temp0], %[length], 0x3 \n\t" \
+ "beqz %[temp0], 4f \n\t" \
+ " andi %[temp7], %[length], 0x7 \n\t" \
+ "1: \n\t" \
+ "ulw %[temp1], 0(%[src]) \n\t" \
+ "ulw %[temp2], 0(%[pred]) \n\t" \
+ "ulw %[temp3], 4(%[src]) \n\t" \
+ "ulw %[temp4], 4(%[pred]) \n\t" \
+ "addiu %[src], %[src], 8 \n\t" \
+ ".if " #INVERSE " \n\t" \
+ "addu.qb %[temp5], %[temp1], %[temp2] \n\t" \
+ "addu.qb %[temp6], %[temp3], %[temp4] \n\t" \
+ ".else \n\t" \
+ "subu.qb %[temp5], %[temp1], %[temp2] \n\t" \
+ "subu.qb %[temp6], %[temp3], %[temp4] \n\t" \
+ ".endif \n\t" \
+ "addiu %[pred], %[pred], 8 \n\t" \
+ "usw %[temp5], 0(%[dst]) \n\t" \
+ "usw %[temp6], 4(%[dst]) \n\t" \
+ "addiu %[temp0], %[temp0], -1 \n\t" \
+ "bnez %[temp0], 1b \n\t" \
+ " addiu %[dst], %[dst], 8 \n\t" \
+ "4: \n\t" \
+ "beqz %[temp7], 3f \n\t" \
+ " nop \n\t" \
+ "2: \n\t" \
+ "lbu %[temp1], 0(%[src]) \n\t" \
+ "lbu %[temp2], 0(%[pred]) \n\t" \
+ "addiu %[src], %[src], 1 \n\t" \
+ "addiu %[pred], %[pred], 1 \n\t" \
+ ".if " #INVERSE " \n\t" \
+ "addu %[temp3], %[temp1], %[temp2] \n\t" \
+ ".else \n\t" \
+ "subu %[temp3], %[temp1], %[temp2] \n\t" \
+ ".endif \n\t" \
+ "sb %[temp3], 0(%[dst]) \n\t" \
+ "addiu %[temp7], %[temp7], -1 \n\t" \
+ "bnez %[temp7], 2b \n\t" \
+ " addiu %[dst], %[dst], 1 \n\t" \
+ "3: \n\t" \
+ ".set pop \n\t" \
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), \
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), \
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), [pred]"+&r"(ppred), \
+ [dst]"+&r"(pdst), [src]"+&r"(psrc) \
+ : [length]"r"(ilength) \
+ : "memory" \
+ ); \
+ } while (0)
+
+#define PREDICT_LINE_ONE_PASS(SRC, PRED, DST, INVERSE) do { \
+ int temp1, temp2, temp3; \
+ __asm__ volatile ( \
+ "lbu %[temp1], 0(%[src]) \n\t" \
+ "lbu %[temp2], 0(%[pred]) \n\t" \
+ ".if " #INVERSE " \n\t" \
+ "addu %[temp3], %[temp1], %[temp2] \n\t" \
+ ".else \n\t" \
+ "subu %[temp3], %[temp1], %[temp2] \n\t" \
+ ".endif \n\t" \
+ "sb %[temp3], 0(%[dst]) \n\t" \
+ : [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), [temp3]"=&r"(temp3) \
+ : [pred]"r"((PRED)), [dst]"r"((DST)), [src]"r"((SRC)) \
+ : "memory" \
+ ); \
+ } while (0)
+
+//------------------------------------------------------------------------------
+// Horizontal filter.
+
+#define FILTER_LINE_BY_LINE(INVERSE) do { \
+ while (row < last_row) { \
+ PREDICT_LINE_ONE_PASS(in, preds - stride, out, INVERSE); \
+ DO_PREDICT_LINE(in + 1, out + 1, width - 1, INVERSE); \
+ ++row; \
+ preds += stride; \
+ in += stride; \
+ out += stride; \
+ } \
+ } while (0)
+
+static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in,
+ int width, int height, int stride,
+ int row, int num_rows,
+ int inverse, uint8_t* out) {
+ const uint8_t* preds;
+ const size_t start_offset = row * stride;
+ const int last_row = row + num_rows;
+ SANITY_CHECK(in, out);
+ in += start_offset;
+ out += start_offset;
+ preds = inverse ? out : in;
+
+ if (row == 0) {
+ // Leftmost pixel is the same as input for topmost scanline.
+ out[0] = in[0];
+ PredictLine(in + 1, out + 1, width - 1, inverse);
+ row = 1;
+ preds += stride;
+ in += stride;
+ out += stride;
+ }
+
+ // Filter line-by-line.
+ if (inverse) {
+ FILTER_LINE_BY_LINE(1);
+ } else {
+ FILTER_LINE_BY_LINE(0);
+ }
+}
+
+#undef FILTER_LINE_BY_LINE
+
+static void HorizontalFilter(const uint8_t* data, int width, int height,
+ int stride, uint8_t* filtered_data) {
+ DoHorizontalFilter(data, width, height, stride, 0, height, 0, filtered_data);
+}
+
+static void HorizontalUnfilter(int width, int height, int stride, int row,
+ int num_rows, uint8_t* data) {
+ DoHorizontalFilter(data, width, height, stride, row, num_rows, 1, data);
+}
+
+//------------------------------------------------------------------------------
+// Vertical filter.
+
+#define FILTER_LINE_BY_LINE(INVERSE) do { \
+ while (row < last_row) { \
+ DO_PREDICT_LINE_VERTICAL(in, preds, out, width, INVERSE); \
+ ++row; \
+ preds += stride; \
+ in += stride; \
+ out += stride; \
+ } \
+ } while (0)
+
+static WEBP_INLINE void DoVerticalFilter(const uint8_t* in,
+ int width, int height, int stride,
+ int row, int num_rows,
+ int inverse, uint8_t* out) {
+ const uint8_t* preds;
+ const size_t start_offset = row * stride;
+ const int last_row = row + num_rows;
+ SANITY_CHECK(in, out);
+ in += start_offset;
+ out += start_offset;
+ preds = inverse ? out : in;
+
+ if (row == 0) {
+ // Very first top-left pixel is copied.
+ out[0] = in[0];
+ // Rest of top scan-line is left-predicted.
+ PredictLine(in + 1, out + 1, width - 1, inverse);
+ row = 1;
+ in += stride;
+ out += stride;
+ } else {
+ // We are starting from in-between. Make sure 'preds' points to prev row.
+ preds -= stride;
+ }
+
+ // Filter line-by-line.
+ if (inverse) {
+ FILTER_LINE_BY_LINE(1);
+ } else {
+ FILTER_LINE_BY_LINE(0);
+ }
+}
+
+#undef FILTER_LINE_BY_LINE
+#undef DO_PREDICT_LINE_VERTICAL
+
+static void VerticalFilter(const uint8_t* data, int width, int height,
+ int stride, uint8_t* filtered_data) {
+ DoVerticalFilter(data, width, height, stride, 0, height, 0, filtered_data);
+}
+
+static void VerticalUnfilter(int width, int height, int stride, int row,
+ int num_rows, uint8_t* data) {
+ DoVerticalFilter(data, width, height, stride, row, num_rows, 1, data);
+}
+
+//------------------------------------------------------------------------------
+// Gradient filter.
+
+static WEBP_INLINE int GradientPredictor(uint8_t a, uint8_t b, uint8_t c) {
+ int temp0;
+ __asm__ volatile (
+ "addu %[temp0], %[a], %[b] \n\t"
+ "subu %[temp0], %[temp0], %[c] \n\t"
+ "shll_s.w %[temp0], %[temp0], 23 \n\t"
+ "precrqu_s.qb.ph %[temp0], %[temp0], $zero \n\t"
+ "srl %[temp0], %[temp0], 24 \n\t"
+ : [temp0]"=&r"(temp0)
+ : [a]"r"(a),[b]"r"(b),[c]"r"(c)
+ );
+ return temp0;
+}
+
+#define FILTER_LINE_BY_LINE(INVERSE, PREDS, OPERATION) do { \
+ while (row < last_row) { \
+ int w; \
+ PREDICT_LINE_ONE_PASS(in, PREDS - stride, out, INVERSE); \
+ for (w = 1; w < width; ++w) { \
+ const int pred = GradientPredictor(PREDS[w - 1], \
+ PREDS[w - stride], \
+ PREDS[w - stride - 1]); \
+ out[w] = in[w] OPERATION pred; \
+ } \
+ ++row; \
+ in += stride; \
+ out += stride; \
+ } \
+ } while (0)
+
+static WEBP_INLINE void DoGradientFilter(const uint8_t* in,
+ int width, int height, int stride,
+ int row, int num_rows,
+ int inverse, uint8_t* out) {
+ const uint8_t* preds;
+ const size_t start_offset = row * stride;
+ const int last_row = row + num_rows;
+ SANITY_CHECK(in, out);
+ in += start_offset;
+ out += start_offset;
+ preds = inverse ? out : in;
+
+ // left prediction for top scan-line
+ if (row == 0) {
+ out[0] = in[0];
+ PredictLine(in + 1, out + 1, width - 1, inverse);
+ row = 1;
+ preds += stride;
+ in += stride;
+ out += stride;
+ }
+
+ // Filter line-by-line.
+ if (inverse) {
+ FILTER_LINE_BY_LINE(1, out, +);
+ } else {
+ FILTER_LINE_BY_LINE(0, in, -);
+ }
+}
+
+#undef FILTER_LINE_BY_LINE
+
+static void GradientFilter(const uint8_t* data, int width, int height,
+ int stride, uint8_t* filtered_data) {
+ DoGradientFilter(data, width, height, stride, 0, height, 0, filtered_data);
+}
+
+static void GradientUnfilter(int width, int height, int stride, int row,
+ int num_rows, uint8_t* data) {
+ DoGradientFilter(data, width, height, stride, row, num_rows, 1, data);
+}
+
+#undef PREDICT_LINE_ONE_PASS
+#undef DO_PREDICT_LINE
+#undef SANITY_CHECK
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8FiltersInitMIPSdspR2(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInitMIPSdspR2(void) {
+ WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter;
+ WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter;
+ WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter;
+
+ WebPUnfilters[WEBP_FILTER_HORIZONTAL] = HorizontalUnfilter;
+ WebPUnfilters[WEBP_FILTER_VERTICAL] = VerticalUnfilter;
+ WebPUnfilters[WEBP_FILTER_GRADIENT] = GradientUnfilter;
+}
+
+#else // !WEBP_USE_MIPS_DSP_R2
+
+WEBP_DSP_INIT_STUB(VP8FiltersInitMIPSdspR2)
+
+#endif // WEBP_USE_MIPS_DSP_R2
diff --git a/drivers/webp/dsp/filters_sse2.c b/drivers/webp/dsp/filters_sse2.c
new file mode 100644
index 0000000000..bf93342eb7
--- /dev/null
+++ b/drivers/webp/dsp/filters_sse2.c
@@ -0,0 +1,352 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// SSE2 variant of alpha filters
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_SSE2)
+
+#include <assert.h>
+#include <emmintrin.h>
+#include <stdlib.h>
+#include <string.h>
+
+//------------------------------------------------------------------------------
+// Helpful macro.
+
+# define SANITY_CHECK(in, out) \
+ assert(in != NULL); \
+ assert(out != NULL); \
+ assert(width > 0); \
+ assert(height > 0); \
+ assert(stride >= width); \
+ assert(row >= 0 && num_rows > 0 && row + num_rows <= height); \
+ (void)height; // Silence unused warning.
+
+static void PredictLineTop(const uint8_t* src, const uint8_t* pred,
+ uint8_t* dst, int length, int inverse) {
+ int i;
+ const int max_pos = length & ~31;
+ assert(length >= 0);
+ if (inverse) {
+ for (i = 0; i < max_pos; i += 32) {
+ const __m128i A0 = _mm_loadu_si128((const __m128i*)&src[i + 0]);
+ const __m128i A1 = _mm_loadu_si128((const __m128i*)&src[i + 16]);
+ const __m128i B0 = _mm_loadu_si128((const __m128i*)&pred[i + 0]);
+ const __m128i B1 = _mm_loadu_si128((const __m128i*)&pred[i + 16]);
+ const __m128i C0 = _mm_add_epi8(A0, B0);
+ const __m128i C1 = _mm_add_epi8(A1, B1);
+ _mm_storeu_si128((__m128i*)&dst[i + 0], C0);
+ _mm_storeu_si128((__m128i*)&dst[i + 16], C1);
+ }
+ for (; i < length; ++i) dst[i] = src[i] + pred[i];
+ } else {
+ for (i = 0; i < max_pos; i += 32) {
+ const __m128i A0 = _mm_loadu_si128((const __m128i*)&src[i + 0]);
+ const __m128i A1 = _mm_loadu_si128((const __m128i*)&src[i + 16]);
+ const __m128i B0 = _mm_loadu_si128((const __m128i*)&pred[i + 0]);
+ const __m128i B1 = _mm_loadu_si128((const __m128i*)&pred[i + 16]);
+ const __m128i C0 = _mm_sub_epi8(A0, B0);
+ const __m128i C1 = _mm_sub_epi8(A1, B1);
+ _mm_storeu_si128((__m128i*)&dst[i + 0], C0);
+ _mm_storeu_si128((__m128i*)&dst[i + 16], C1);
+ }
+ for (; i < length; ++i) dst[i] = src[i] - pred[i];
+ }
+}
+
+// Special case for left-based prediction (when preds==dst-1 or preds==src-1).
+static void PredictLineLeft(const uint8_t* src, uint8_t* dst, int length,
+ int inverse) {
+ int i;
+ if (length <= 0) return;
+ if (inverse) {
+ const int max_pos = length & ~7;
+ __m128i last = _mm_set_epi32(0, 0, 0, dst[-1]);
+ for (i = 0; i < max_pos; i += 8) {
+ const __m128i A0 = _mm_loadl_epi64((const __m128i*)(src + i));
+ const __m128i A1 = _mm_add_epi8(A0, last);
+ const __m128i A2 = _mm_slli_si128(A1, 1);
+ const __m128i A3 = _mm_add_epi8(A1, A2);
+ const __m128i A4 = _mm_slli_si128(A3, 2);
+ const __m128i A5 = _mm_add_epi8(A3, A4);
+ const __m128i A6 = _mm_slli_si128(A5, 4);
+ const __m128i A7 = _mm_add_epi8(A5, A6);
+ _mm_storel_epi64((__m128i*)(dst + i), A7);
+ last = _mm_srli_epi64(A7, 56);
+ }
+ for (; i < length; ++i) dst[i] = src[i] + dst[i - 1];
+ } else {
+ const int max_pos = length & ~31;
+ for (i = 0; i < max_pos; i += 32) {
+ const __m128i A0 = _mm_loadu_si128((const __m128i*)(src + i + 0 ));
+ const __m128i B0 = _mm_loadu_si128((const __m128i*)(src + i + 0 - 1));
+ const __m128i A1 = _mm_loadu_si128((const __m128i*)(src + i + 16 ));
+ const __m128i B1 = _mm_loadu_si128((const __m128i*)(src + i + 16 - 1));
+ const __m128i C0 = _mm_sub_epi8(A0, B0);
+ const __m128i C1 = _mm_sub_epi8(A1, B1);
+ _mm_storeu_si128((__m128i*)(dst + i + 0), C0);
+ _mm_storeu_si128((__m128i*)(dst + i + 16), C1);
+ }
+ for (; i < length; ++i) dst[i] = src[i] - src[i - 1];
+ }
+}
+
+static void PredictLineC(const uint8_t* src, const uint8_t* pred,
+ uint8_t* dst, int length, int inverse) {
+ int i;
+ if (inverse) {
+ for (i = 0; i < length; ++i) dst[i] = src[i] + pred[i];
+ } else {
+ for (i = 0; i < length; ++i) dst[i] = src[i] - pred[i];
+ }
+}
+
+//------------------------------------------------------------------------------
+// Horizontal filter.
+
+static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in,
+ int width, int height, int stride,
+ int row, int num_rows,
+ int inverse, uint8_t* out) {
+ const uint8_t* preds;
+ const size_t start_offset = row * stride;
+ const int last_row = row + num_rows;
+ SANITY_CHECK(in, out);
+ in += start_offset;
+ out += start_offset;
+ preds = inverse ? out : in;
+
+ if (row == 0) {
+ // Leftmost pixel is the same as input for topmost scanline.
+ out[0] = in[0];
+ PredictLineLeft(in + 1, out + 1, width - 1, inverse);
+ row = 1;
+ preds += stride;
+ in += stride;
+ out += stride;
+ }
+
+ // Filter line-by-line.
+ while (row < last_row) {
+ // Leftmost pixel is predicted from above.
+ PredictLineC(in, preds - stride, out, 1, inverse);
+ PredictLineLeft(in + 1, out + 1, width - 1, inverse);
+ ++row;
+ preds += stride;
+ in += stride;
+ out += stride;
+ }
+}
+
+//------------------------------------------------------------------------------
+// Vertical filter.
+
+static WEBP_INLINE void DoVerticalFilter(const uint8_t* in,
+ int width, int height, int stride,
+ int row, int num_rows,
+ int inverse, uint8_t* out) {
+ const uint8_t* preds;
+ const size_t start_offset = row * stride;
+ const int last_row = row + num_rows;
+ SANITY_CHECK(in, out);
+ in += start_offset;
+ out += start_offset;
+ preds = inverse ? out : in;
+
+ if (row == 0) {
+ // Very first top-left pixel is copied.
+ out[0] = in[0];
+ // Rest of top scan-line is left-predicted.
+ PredictLineLeft(in + 1, out + 1, width - 1, inverse);
+ row = 1;
+ in += stride;
+ out += stride;
+ } else {
+ // We are starting from in-between. Make sure 'preds' points to prev row.
+ preds -= stride;
+ }
+
+ // Filter line-by-line.
+ while (row < last_row) {
+ PredictLineTop(in, preds, out, width, inverse);
+ ++row;
+ preds += stride;
+ in += stride;
+ out += stride;
+ }
+}
+
+//------------------------------------------------------------------------------
+// Gradient filter.
+
+static WEBP_INLINE int GradientPredictorC(uint8_t a, uint8_t b, uint8_t c) {
+ const int g = a + b - c;
+ return ((g & ~0xff) == 0) ? g : (g < 0) ? 0 : 255; // clip to 8bit
+}
+
+static void GradientPredictDirect(const uint8_t* const row,
+ const uint8_t* const top,
+ uint8_t* const out, int length) {
+ const int max_pos = length & ~7;
+ int i;
+ const __m128i zero = _mm_setzero_si128();
+ for (i = 0; i < max_pos; i += 8) {
+ const __m128i A0 = _mm_loadl_epi64((const __m128i*)&row[i - 1]);
+ const __m128i B0 = _mm_loadl_epi64((const __m128i*)&top[i]);
+ const __m128i C0 = _mm_loadl_epi64((const __m128i*)&top[i - 1]);
+ const __m128i D = _mm_loadl_epi64((const __m128i*)&row[i]);
+ const __m128i A1 = _mm_unpacklo_epi8(A0, zero);
+ const __m128i B1 = _mm_unpacklo_epi8(B0, zero);
+ const __m128i C1 = _mm_unpacklo_epi8(C0, zero);
+ const __m128i E = _mm_add_epi16(A1, B1);
+ const __m128i F = _mm_sub_epi16(E, C1);
+ const __m128i G = _mm_packus_epi16(F, zero);
+ const __m128i H = _mm_sub_epi8(D, G);
+ _mm_storel_epi64((__m128i*)(out + i), H);
+ }
+ for (; i < length; ++i) {
+ out[i] = row[i] - GradientPredictorC(row[i - 1], top[i], top[i - 1]);
+ }
+}
+
+static void GradientPredictInverse(const uint8_t* const in,
+ const uint8_t* const top,
+ uint8_t* const row, int length) {
+ if (length > 0) {
+ int i;
+ const int max_pos = length & ~7;
+ const __m128i zero = _mm_setzero_si128();
+ __m128i A = _mm_set_epi32(0, 0, 0, row[-1]); // left sample
+ for (i = 0; i < max_pos; i += 8) {
+ const __m128i tmp0 = _mm_loadl_epi64((const __m128i*)&top[i]);
+ const __m128i tmp1 = _mm_loadl_epi64((const __m128i*)&top[i - 1]);
+ const __m128i B = _mm_unpacklo_epi8(tmp0, zero);
+ const __m128i C = _mm_unpacklo_epi8(tmp1, zero);
+ const __m128i tmp2 = _mm_loadl_epi64((const __m128i*)&in[i]);
+ const __m128i D = _mm_unpacklo_epi8(tmp2, zero); // base input
+ const __m128i E = _mm_sub_epi16(B, C); // unclipped gradient basis B - C
+ __m128i out = zero; // accumulator for output
+ __m128i mask_hi = _mm_set_epi32(0, 0, 0, 0xff);
+ int k = 8;
+ while (1) {
+ const __m128i tmp3 = _mm_add_epi16(A, E); // delta = A + B - C
+ const __m128i tmp4 = _mm_min_epi16(tmp3, mask_hi);
+ const __m128i tmp5 = _mm_max_epi16(tmp4, zero); // clipped delta
+ const __m128i tmp6 = _mm_add_epi16(tmp5, D); // add to in[] values
+ A = _mm_and_si128(tmp6, mask_hi); // 1-complement clip
+ out = _mm_or_si128(out, A); // accumulate output
+ if (--k == 0) break;
+ A = _mm_slli_si128(A, 2); // rotate left sample
+ mask_hi = _mm_slli_si128(mask_hi, 2); // rotate mask
+ }
+ A = _mm_srli_si128(A, 14); // prepare left sample for next iteration
+ _mm_storel_epi64((__m128i*)&row[i], _mm_packus_epi16(out, zero));
+ }
+ for (; i < length; ++i) {
+ row[i] = in[i] + GradientPredictorC(row[i - 1], top[i], top[i - 1]);
+ }
+ }
+}
+
+static WEBP_INLINE void DoGradientFilter(const uint8_t* in,
+ int width, int height, int stride,
+ int row, int num_rows,
+ int inverse, uint8_t* out) {
+ const size_t start_offset = row * stride;
+ const int last_row = row + num_rows;
+ SANITY_CHECK(in, out);
+ in += start_offset;
+ out += start_offset;
+
+ // left prediction for top scan-line
+ if (row == 0) {
+ out[0] = in[0];
+ PredictLineLeft(in + 1, out + 1, width - 1, inverse);
+ row = 1;
+ in += stride;
+ out += stride;
+ }
+
+ // Filter line-by-line.
+ while (row < last_row) {
+ if (inverse) {
+ PredictLineC(in, out - stride, out, 1, inverse); // predict from above
+ GradientPredictInverse(in + 1, out + 1 - stride, out + 1, width - 1);
+ } else {
+ PredictLineC(in, in - stride, out, 1, inverse);
+ GradientPredictDirect(in + 1, in + 1 - stride, out + 1, width - 1);
+ }
+ ++row;
+ in += stride;
+ out += stride;
+ }
+}
+
+#undef SANITY_CHECK
+
+//------------------------------------------------------------------------------
+
+static void HorizontalFilter(const uint8_t* data, int width, int height,
+ int stride, uint8_t* filtered_data) {
+ DoHorizontalFilter(data, width, height, stride, 0, height, 0, filtered_data);
+}
+
+static void VerticalFilter(const uint8_t* data, int width, int height,
+ int stride, uint8_t* filtered_data) {
+ DoVerticalFilter(data, width, height, stride, 0, height, 0, filtered_data);
+}
+
+
+static void GradientFilter(const uint8_t* data, int width, int height,
+ int stride, uint8_t* filtered_data) {
+ DoGradientFilter(data, width, height, stride, 0, height, 0, filtered_data);
+}
+
+
+//------------------------------------------------------------------------------
+
+static void VerticalUnfilter(int width, int height, int stride, int row,
+ int num_rows, uint8_t* data) {
+ DoVerticalFilter(data, width, height, stride, row, num_rows, 1, data);
+}
+
+static void HorizontalUnfilter(int width, int height, int stride, int row,
+ int num_rows, uint8_t* data) {
+ DoHorizontalFilter(data, width, height, stride, row, num_rows, 1, data);
+}
+
+static void GradientUnfilter(int width, int height, int stride, int row,
+ int num_rows, uint8_t* data) {
+ DoGradientFilter(data, width, height, stride, row, num_rows, 1, data);
+}
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8FiltersInitSSE2(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8FiltersInitSSE2(void) {
+ WebPUnfilters[WEBP_FILTER_HORIZONTAL] = HorizontalUnfilter;
+ WebPUnfilters[WEBP_FILTER_VERTICAL] = VerticalUnfilter;
+ WebPUnfilters[WEBP_FILTER_GRADIENT] = GradientUnfilter;
+
+ WebPFilters[WEBP_FILTER_HORIZONTAL] = HorizontalFilter;
+ WebPFilters[WEBP_FILTER_VERTICAL] = VerticalFilter;
+ WebPFilters[WEBP_FILTER_GRADIENT] = GradientFilter;
+}
+
+#else // !WEBP_USE_SSE2
+
+WEBP_DSP_INIT_STUB(VP8FiltersInitSSE2)
+
+#endif // WEBP_USE_SSE2
diff --git a/drivers/webp/dsp/lossless.c b/drivers/webp/dsp/lossless.c
index 62a6b7b15a..5702eb3b17 100644
--- a/drivers/webp/dsp/lossless.c
+++ b/drivers/webp/dsp/lossless.c
@@ -1,8 +1,10 @@
// Copyright 2012 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Image transforms and color space conversion methods for lossless decoder.
@@ -11,170 +13,16 @@
// Jyrki Alakuijala (jyrki@google.com)
// Urvang Joshi (urvang@google.com)
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
+#include "./dsp.h"
#include <math.h>
#include <stdlib.h>
-#include "./lossless.h"
#include "../dec/vp8li.h"
-#include "../dsp/yuv.h"
-#include "../dsp/dsp.h"
-#include "../enc/histogram.h"
+#include "../utils/endian_inl.h"
+#include "./lossless.h"
#define MAX_DIFF_COST (1e30f)
-// lookup table for small values of log2(int)
-#define APPROX_LOG_MAX 4096
-#define LOG_2_RECIPROCAL 1.44269504088896338700465094007086
-#define LOG_LOOKUP_IDX_MAX 256
-static const float kLog2Table[LOG_LOOKUP_IDX_MAX] = {
- 0.0000000000000000f, 0.0000000000000000f,
- 1.0000000000000000f, 1.5849625007211560f,
- 2.0000000000000000f, 2.3219280948873621f,
- 2.5849625007211560f, 2.8073549220576041f,
- 3.0000000000000000f, 3.1699250014423121f,
- 3.3219280948873621f, 3.4594316186372973f,
- 3.5849625007211560f, 3.7004397181410921f,
- 3.8073549220576041f, 3.9068905956085187f,
- 4.0000000000000000f, 4.0874628412503390f,
- 4.1699250014423121f, 4.2479275134435852f,
- 4.3219280948873626f, 4.3923174227787606f,
- 4.4594316186372973f, 4.5235619560570130f,
- 4.5849625007211560f, 4.6438561897747243f,
- 4.7004397181410917f, 4.7548875021634682f,
- 4.8073549220576037f, 4.8579809951275718f,
- 4.9068905956085187f, 4.9541963103868749f,
- 5.0000000000000000f, 5.0443941193584533f,
- 5.0874628412503390f, 5.1292830169449663f,
- 5.1699250014423121f, 5.2094533656289501f,
- 5.2479275134435852f, 5.2854022188622487f,
- 5.3219280948873626f, 5.3575520046180837f,
- 5.3923174227787606f, 5.4262647547020979f,
- 5.4594316186372973f, 5.4918530963296747f,
- 5.5235619560570130f, 5.5545888516776376f,
- 5.5849625007211560f, 5.6147098441152083f,
- 5.6438561897747243f, 5.6724253419714951f,
- 5.7004397181410917f, 5.7279204545631987f,
- 5.7548875021634682f, 5.7813597135246599f,
- 5.8073549220576037f, 5.8328900141647412f,
- 5.8579809951275718f, 5.8826430493618415f,
- 5.9068905956085187f, 5.9307373375628866f,
- 5.9541963103868749f, 5.9772799234999167f,
- 6.0000000000000000f, 6.0223678130284543f,
- 6.0443941193584533f, 6.0660891904577720f,
- 6.0874628412503390f, 6.1085244567781691f,
- 6.1292830169449663f, 6.1497471195046822f,
- 6.1699250014423121f, 6.1898245588800175f,
- 6.2094533656289501f, 6.2288186904958804f,
- 6.2479275134435852f, 6.2667865406949010f,
- 6.2854022188622487f, 6.3037807481771030f,
- 6.3219280948873626f, 6.3398500028846243f,
- 6.3575520046180837f, 6.3750394313469245f,
- 6.3923174227787606f, 6.4093909361377017f,
- 6.4262647547020979f, 6.4429434958487279f,
- 6.4594316186372973f, 6.4757334309663976f,
- 6.4918530963296747f, 6.5077946401986963f,
- 6.5235619560570130f, 6.5391588111080309f,
- 6.5545888516776376f, 6.5698556083309478f,
- 6.5849625007211560f, 6.5999128421871278f,
- 6.6147098441152083f, 6.6293566200796094f,
- 6.6438561897747243f, 6.6582114827517946f,
- 6.6724253419714951f, 6.6865005271832185f,
- 6.7004397181410917f, 6.7142455176661224f,
- 6.7279204545631987f, 6.7414669864011464f,
- 6.7548875021634682f, 6.7681843247769259f,
- 6.7813597135246599f, 6.7944158663501061f,
- 6.8073549220576037f, 6.8201789624151878f,
- 6.8328900141647412f, 6.8454900509443747f,
- 6.8579809951275718f, 6.8703647195834047f,
- 6.8826430493618415f, 6.8948177633079437f,
- 6.9068905956085187f, 6.9188632372745946f,
- 6.9307373375628866f, 6.9425145053392398f,
- 6.9541963103868749f, 6.9657842846620869f,
- 6.9772799234999167f, 6.9886846867721654f,
- 7.0000000000000000f, 7.0112272554232539f,
- 7.0223678130284543f, 7.0334230015374501f,
- 7.0443941193584533f, 7.0552824355011898f,
- 7.0660891904577720f, 7.0768155970508308f,
- 7.0874628412503390f, 7.0980320829605263f,
- 7.1085244567781691f, 7.1189410727235076f,
- 7.1292830169449663f, 7.1395513523987936f,
- 7.1497471195046822f, 7.1598713367783890f,
- 7.1699250014423121f, 7.1799090900149344f,
- 7.1898245588800175f, 7.1996723448363644f,
- 7.2094533656289501f, 7.2191685204621611f,
- 7.2288186904958804f, 7.2384047393250785f,
- 7.2479275134435852f, 7.2573878426926521f,
- 7.2667865406949010f, 7.2761244052742375f,
- 7.2854022188622487f, 7.2946207488916270f,
- 7.3037807481771030f, 7.3128829552843557f,
- 7.3219280948873626f, 7.3309168781146167f,
- 7.3398500028846243f, 7.3487281542310771f,
- 7.3575520046180837f, 7.3663222142458160f,
- 7.3750394313469245f, 7.3837042924740519f,
- 7.3923174227787606f, 7.4008794362821843f,
- 7.4093909361377017f, 7.4178525148858982f,
- 7.4262647547020979f, 7.4346282276367245f,
- 7.4429434958487279f, 7.4512111118323289f,
- 7.4594316186372973f, 7.4676055500829976f,
- 7.4757334309663976f, 7.4838157772642563f,
- 7.4918530963296747f, 7.4998458870832056f,
- 7.5077946401986963f, 7.5156998382840427f,
- 7.5235619560570130f, 7.5313814605163118f,
- 7.5391588111080309f, 7.5468944598876364f,
- 7.5545888516776376f, 7.5622424242210728f,
- 7.5698556083309478f, 7.5774288280357486f,
- 7.5849625007211560f, 7.5924570372680806f,
- 7.5999128421871278f, 7.6073303137496104f,
- 7.6147098441152083f, 7.6220518194563764f,
- 7.6293566200796094f, 7.6366246205436487f,
- 7.6438561897747243f, 7.6510516911789281f,
- 7.6582114827517946f, 7.6653359171851764f,
- 7.6724253419714951f, 7.6794800995054464f,
- 7.6865005271832185f, 7.6934869574993252f,
- 7.7004397181410917f, 7.7073591320808825f,
- 7.7142455176661224f, 7.7210991887071855f,
- 7.7279204545631987f, 7.7347096202258383f,
- 7.7414669864011464f, 7.7481928495894605f,
- 7.7548875021634682f, 7.7615512324444795f,
- 7.7681843247769259f, 7.7747870596011736f,
- 7.7813597135246599f, 7.7879025593914317f,
- 7.7944158663501061f, 7.8008998999203047f,
- 7.8073549220576037f, 7.8137811912170374f,
- 7.8201789624151878f, 7.8265484872909150f,
- 7.8328900141647412f, 7.8392037880969436f,
- 7.8454900509443747f, 7.8517490414160571f,
- 7.8579809951275718f, 7.8641861446542797f,
- 7.8703647195834047f, 7.8765169465649993f,
- 7.8826430493618415f, 7.8887432488982591f,
- 7.8948177633079437f, 7.9008668079807486f,
- 7.9068905956085187f, 7.9128893362299619f,
- 7.9188632372745946f, 7.9248125036057812f,
- 7.9307373375628866f, 7.9366379390025709f,
- 7.9425145053392398f, 7.9483672315846778f,
- 7.9541963103868749f, 7.9600019320680805f,
- 7.9657842846620869f, 7.9715435539507719f,
- 7.9772799234999167f, 7.9829935746943103f,
- 7.9886846867721654f, 7.9943534368588577f
-};
-
-float VP8LFastLog2(int v) {
- if (v < LOG_LOOKUP_IDX_MAX) {
- return kLog2Table[v];
- } else if (v < APPROX_LOG_MAX) {
- int log_cnt = 0;
- while (v >= LOG_LOOKUP_IDX_MAX) {
- ++log_cnt;
- v = v >> 1;
- }
- return kLog2Table[v] + (float)log_cnt;
- } else {
- return (float)(LOG_2_RECIPROCAL * log((double)v));
- }
-}
-
//------------------------------------------------------------------------------
// Image transforms.
@@ -186,7 +34,7 @@ static WEBP_INLINE void AddPixelsEq(uint32_t* a, uint32_t b) {
}
static WEBP_INLINE uint32_t Average2(uint32_t a0, uint32_t a1) {
- return (((a0 ^ a1) & 0xfefefefeL) >> 1) + (a0 & a1);
+ return (((a0 ^ a1) & 0xfefefefeu) >> 1) + (a0 & a1);
}
static WEBP_INLINE uint32_t Average3(uint32_t a0, uint32_t a1, uint32_t a2) {
@@ -221,7 +69,7 @@ static WEBP_INLINE uint32_t ClampedAddSubtractFull(uint32_t c0, uint32_t c1,
(c1 >> 8) & 0xff,
(c2 >> 8) & 0xff);
const int b = AddSubtractComponentFull(c0 & 0xff, c1 & 0xff, c2 & 0xff);
- return (a << 24) | (r << 16) | (g << 8) | b;
+ return ((uint32_t)a << 24) | (r << 16) | (g << 8) | b;
}
static WEBP_INLINE int AddSubtractComponentHalf(int a, int b) {
@@ -235,22 +83,30 @@ static WEBP_INLINE uint32_t ClampedAddSubtractHalf(uint32_t c0, uint32_t c1,
const int r = AddSubtractComponentHalf((ave >> 16) & 0xff, (c2 >> 16) & 0xff);
const int g = AddSubtractComponentHalf((ave >> 8) & 0xff, (c2 >> 8) & 0xff);
const int b = AddSubtractComponentHalf((ave >> 0) & 0xff, (c2 >> 0) & 0xff);
- return (a << 24) | (r << 16) | (g << 8) | b;
+ return ((uint32_t)a << 24) | (r << 16) | (g << 8) | b;
}
-static WEBP_INLINE int Sub3(int a, int b, int c) {
- const int pa = b - c;
- const int pb = a - c;
- return abs(pa) - abs(pb);
+// gcc-4.9 on ARM generates incorrect code in Select() when Sub3() is inlined.
+#if defined(__arm__) && LOCAL_GCC_VERSION == 0x409
+# define LOCAL_INLINE __attribute__ ((noinline))
+#else
+# define LOCAL_INLINE WEBP_INLINE
+#endif
+
+static LOCAL_INLINE int Sub3(int a, int b, int c) {
+ const int pb = b - c;
+ const int pa = a - c;
+ return abs(pb) - abs(pa);
}
+#undef LOCAL_INLINE
+
static WEBP_INLINE uint32_t Select(uint32_t a, uint32_t b, uint32_t c) {
const int pa_minus_pb =
Sub3((a >> 24) , (b >> 24) , (c >> 24) ) +
Sub3((a >> 16) & 0xff, (b >> 16) & 0xff, (c >> 16) & 0xff) +
Sub3((a >> 8) & 0xff, (b >> 8) & 0xff, (c >> 8) & 0xff) +
Sub3((a ) & 0xff, (b ) & 0xff, (c ) & 0xff);
-
return (pa_minus_pb <= 0) ? a : b;
}
@@ -317,208 +173,7 @@ static uint32_t Predictor13(uint32_t left, const uint32_t* const top) {
return pred;
}
-typedef uint32_t (*PredictorFunc)(uint32_t left, const uint32_t* const top);
-static const PredictorFunc kPredictors[16] = {
- Predictor0, Predictor1, Predictor2, Predictor3,
- Predictor4, Predictor5, Predictor6, Predictor7,
- Predictor8, Predictor9, Predictor10, Predictor11,
- Predictor12, Predictor13,
- Predictor0, Predictor0 // <- padding security sentinels
-};
-
-// TODO(vikasa): Replace 256 etc with defines.
-static float PredictionCostSpatial(const int* counts,
- int weight_0, double exp_val) {
- const int significant_symbols = 16;
- const double exp_decay_factor = 0.6;
- double bits = weight_0 * counts[0];
- int i;
- for (i = 1; i < significant_symbols; ++i) {
- bits += exp_val * (counts[i] + counts[256 - i]);
- exp_val *= exp_decay_factor;
- }
- return (float)(-0.1 * bits);
-}
-
-// Compute the Shanon's entropy: Sum(p*log2(p))
-static float ShannonEntropy(const int* const array, int n) {
- int i;
- float retval = 0.f;
- int sum = 0;
- for (i = 0; i < n; ++i) {
- if (array[i] != 0) {
- sum += array[i];
- retval -= VP8LFastSLog2(array[i]);
- }
- }
- retval += VP8LFastSLog2(sum);
- return retval;
-}
-
-static float PredictionCostSpatialHistogram(int accumulated[4][256],
- int tile[4][256]) {
- int i;
- int k;
- int combo[256];
- double retval = 0;
- for (i = 0; i < 4; ++i) {
- const double exp_val = 0.94;
- retval += PredictionCostSpatial(&tile[i][0], 1, exp_val);
- retval += ShannonEntropy(&tile[i][0], 256);
- for (k = 0; k < 256; ++k) {
- combo[k] = accumulated[i][k] + tile[i][k];
- }
- retval += ShannonEntropy(&combo[0], 256);
- }
- return (float)retval;
-}
-
-static int GetBestPredictorForTile(int width, int height,
- int tile_x, int tile_y, int bits,
- int accumulated[4][256],
- const uint32_t* const argb_scratch) {
- const int kNumPredModes = 14;
- const int col_start = tile_x << bits;
- const int row_start = tile_y << bits;
- const int tile_size = 1 << bits;
- const int ymax = (tile_size <= height - row_start) ?
- tile_size : height - row_start;
- const int xmax = (tile_size <= width - col_start) ?
- tile_size : width - col_start;
- int histo[4][256];
- float best_diff = MAX_DIFF_COST;
- int best_mode = 0;
-
- int mode;
- for (mode = 0; mode < kNumPredModes; ++mode) {
- const uint32_t* current_row = argb_scratch;
- const PredictorFunc pred_func = kPredictors[mode];
- float cur_diff;
- int y;
- memset(&histo[0][0], 0, sizeof(histo));
- for (y = 0; y < ymax; ++y) {
- int x;
- const int row = row_start + y;
- const uint32_t* const upper_row = current_row;
- current_row = upper_row + width;
- for (x = 0; x < xmax; ++x) {
- const int col = col_start + x;
- uint32_t predict;
- uint32_t predict_diff;
- if (row == 0) {
- predict = (col == 0) ? ARGB_BLACK : current_row[col - 1]; // Left.
- } else if (col == 0) {
- predict = upper_row[col]; // Top.
- } else {
- predict = pred_func(current_row[col - 1], upper_row + col);
- }
- predict_diff = VP8LSubPixels(current_row[col], predict);
- ++histo[0][predict_diff >> 24];
- ++histo[1][((predict_diff >> 16) & 0xff)];
- ++histo[2][((predict_diff >> 8) & 0xff)];
- ++histo[3][(predict_diff & 0xff)];
- }
- }
- cur_diff = PredictionCostSpatialHistogram(accumulated, histo);
- if (cur_diff < best_diff) {
- best_diff = cur_diff;
- best_mode = mode;
- }
- }
-
- return best_mode;
-}
-
-static void CopyTileWithPrediction(int width, int height,
- int tile_x, int tile_y, int bits, int mode,
- const uint32_t* const argb_scratch,
- uint32_t* const argb) {
- const int col_start = tile_x << bits;
- const int row_start = tile_y << bits;
- const int tile_size = 1 << bits;
- const int ymax = (tile_size <= height - row_start) ?
- tile_size : height - row_start;
- const int xmax = (tile_size <= width - col_start) ?
- tile_size : width - col_start;
- const PredictorFunc pred_func = kPredictors[mode];
- const uint32_t* current_row = argb_scratch;
-
- int y;
- for (y = 0; y < ymax; ++y) {
- int x;
- const int row = row_start + y;
- const uint32_t* const upper_row = current_row;
- current_row = upper_row + width;
- for (x = 0; x < xmax; ++x) {
- const int col = col_start + x;
- const int pix = row * width + col;
- uint32_t predict;
- if (row == 0) {
- predict = (col == 0) ? ARGB_BLACK : current_row[col - 1]; // Left.
- } else if (col == 0) {
- predict = upper_row[col]; // Top.
- } else {
- predict = pred_func(current_row[col - 1], upper_row + col);
- }
- argb[pix] = VP8LSubPixels(current_row[col], predict);
- }
- }
-}
-
-void VP8LResidualImage(int width, int height, int bits,
- uint32_t* const argb, uint32_t* const argb_scratch,
- uint32_t* const image) {
- const int max_tile_size = 1 << bits;
- const int tiles_per_row = VP8LSubSampleSize(width, bits);
- const int tiles_per_col = VP8LSubSampleSize(height, bits);
- uint32_t* const upper_row = argb_scratch;
- uint32_t* const current_tile_rows = argb_scratch + width;
- int tile_y;
- int histo[4][256];
- memset(histo, 0, sizeof(histo));
- for (tile_y = 0; tile_y < tiles_per_col; ++tile_y) {
- const int tile_y_offset = tile_y * max_tile_size;
- const int this_tile_height =
- (tile_y < tiles_per_col - 1) ? max_tile_size : height - tile_y_offset;
- int tile_x;
- if (tile_y > 0) {
- memcpy(upper_row, current_tile_rows + (max_tile_size - 1) * width,
- width * sizeof(*upper_row));
- }
- memcpy(current_tile_rows, &argb[tile_y_offset * width],
- this_tile_height * width * sizeof(*current_tile_rows));
- for (tile_x = 0; tile_x < tiles_per_row; ++tile_x) {
- int pred;
- int y;
- const int tile_x_offset = tile_x * max_tile_size;
- int all_x_max = tile_x_offset + max_tile_size;
- if (all_x_max > width) {
- all_x_max = width;
- }
- pred = GetBestPredictorForTile(width, height, tile_x, tile_y, bits, histo,
- argb_scratch);
- image[tile_y * tiles_per_row + tile_x] = 0xff000000u | (pred << 8);
- CopyTileWithPrediction(width, height, tile_x, tile_y, bits, pred,
- argb_scratch, argb);
- for (y = 0; y < max_tile_size; ++y) {
- int ix;
- int all_x;
- int all_y = tile_y_offset + y;
- if (all_y >= height) {
- break;
- }
- ix = all_y * width + tile_x_offset;
- for (all_x = tile_x_offset; all_x < all_x_max; ++all_x, ++ix) {
- const uint32_t a = argb[ix];
- ++histo[0][a >> 24];
- ++histo[1][((a >> 16) & 0xff)];
- ++histo[2][((a >> 8) & 0xff)];
- ++histo[3][(a & 0xff)];
- }
- }
- }
- }
-}
+//------------------------------------------------------------------------------
// Inverse prediction.
static void PredictorInverseTransform(const VP8LTransform* const transform,
@@ -538,29 +193,36 @@ static void PredictorInverseTransform(const VP8LTransform* const transform,
{
int y = y_start;
- const int mask = (1 << transform->bits_) - 1;
+ const int tile_width = 1 << transform->bits_;
+ const int mask = tile_width - 1;
+ const int safe_width = width & ~mask;
const int tiles_per_row = VP8LSubSampleSize(width, transform->bits_);
const uint32_t* pred_mode_base =
transform->data_ + (y >> transform->bits_) * tiles_per_row;
while (y < y_end) {
- int x;
const uint32_t pred2 = Predictor2(data[-1], data - width);
const uint32_t* pred_mode_src = pred_mode_base;
- PredictorFunc pred_func;
-
+ VP8LPredictorFunc pred_func;
+ int x = 1;
+ int t = 1;
// First pixel follows the T (mode=2) mode.
AddPixelsEq(data, pred2);
-
// .. the rest:
- pred_func = kPredictors[((*pred_mode_src++) >> 8) & 0xf];
- for (x = 1; x < width; ++x) {
- uint32_t pred;
- if ((x & mask) == 0) { // start of tile. Read predictor function.
- pred_func = kPredictors[((*pred_mode_src++) >> 8) & 0xf];
+ while (x < safe_width) {
+ pred_func = VP8LPredictors[((*pred_mode_src++) >> 8) & 0xf];
+ for (; t < tile_width; ++t, ++x) {
+ const uint32_t pred = pred_func(data[x - 1], data + x - width);
+ AddPixelsEq(data + x, pred);
+ }
+ t = 0;
+ }
+ if (x < width) {
+ pred_func = VP8LPredictors[((*pred_mode_src++) >> 8) & 0xf];
+ for (; x < width; ++x) {
+ const uint32_t pred = pred_func(data[x - 1], data + x - width);
+ AddPixelsEq(data + x, pred);
}
- pred = pred_func(data[x - 1], data + x - width);
- AddPixelsEq(data + x, pred);
}
data += width;
++y;
@@ -571,326 +233,47 @@ static void PredictorInverseTransform(const VP8LTransform* const transform,
}
}
-void VP8LSubtractGreenFromBlueAndRed(uint32_t* argb_data, int num_pixs) {
- int i;
- for (i = 0; i < num_pixs; ++i) {
- const uint32_t argb = argb_data[i];
- const uint32_t green = (argb >> 8) & 0xff;
- const uint32_t new_r = (((argb >> 16) & 0xff) - green) & 0xff;
- const uint32_t new_b = ((argb & 0xff) - green) & 0xff;
- argb_data[i] = (argb & 0xff00ff00) | (new_r << 16) | new_b;
- }
-}
-
// Add green to blue and red channels (i.e. perform the inverse transform of
// 'subtract green').
-static void AddGreenToBlueAndRed(const VP8LTransform* const transform,
- int y_start, int y_end, uint32_t* data) {
- const int width = transform->xsize_;
- const uint32_t* const data_end = data + (y_end - y_start) * width;
- while (data < data_end) {
- const uint32_t argb = *data;
- // "* 0001001u" is equivalent to "(green << 16) + green)"
+void VP8LAddGreenToBlueAndRed_C(uint32_t* data, int num_pixels) {
+ int i;
+ for (i = 0; i < num_pixels; ++i) {
+ const uint32_t argb = data[i];
const uint32_t green = ((argb >> 8) & 0xff);
uint32_t red_blue = (argb & 0x00ff00ffu);
red_blue += (green << 16) | green;
red_blue &= 0x00ff00ffu;
- *data++ = (argb & 0xff00ff00u) | red_blue;
+ data[i] = (argb & 0xff00ff00u) | red_blue;
}
}
-typedef struct {
- // Note: the members are uint8_t, so that any negative values are
- // automatically converted to "mod 256" values.
- uint8_t green_to_red_;
- uint8_t green_to_blue_;
- uint8_t red_to_blue_;
-} Multipliers;
-
-static WEBP_INLINE void MultipliersClear(Multipliers* m) {
- m->green_to_red_ = 0;
- m->green_to_blue_ = 0;
- m->red_to_blue_ = 0;
-}
-
static WEBP_INLINE uint32_t ColorTransformDelta(int8_t color_pred,
int8_t color) {
return (uint32_t)((int)(color_pred) * color) >> 5;
}
static WEBP_INLINE void ColorCodeToMultipliers(uint32_t color_code,
- Multipliers* const m) {
+ VP8LMultipliers* const m) {
m->green_to_red_ = (color_code >> 0) & 0xff;
m->green_to_blue_ = (color_code >> 8) & 0xff;
m->red_to_blue_ = (color_code >> 16) & 0xff;
}
-static WEBP_INLINE uint32_t MultipliersToColorCode(Multipliers* const m) {
- return 0xff000000u |
- ((uint32_t)(m->red_to_blue_) << 16) |
- ((uint32_t)(m->green_to_blue_) << 8) |
- m->green_to_red_;
-}
-
-static WEBP_INLINE uint32_t TransformColor(const Multipliers* const m,
- uint32_t argb, int inverse) {
- const uint32_t green = argb >> 8;
- const uint32_t red = argb >> 16;
- uint32_t new_red = red;
- uint32_t new_blue = argb;
-
- if (inverse) {
+void VP8LTransformColorInverse_C(const VP8LMultipliers* const m, uint32_t* data,
+ int num_pixels) {
+ int i;
+ for (i = 0; i < num_pixels; ++i) {
+ const uint32_t argb = data[i];
+ const uint32_t green = argb >> 8;
+ const uint32_t red = argb >> 16;
+ uint32_t new_red = red;
+ uint32_t new_blue = argb;
new_red += ColorTransformDelta(m->green_to_red_, green);
new_red &= 0xff;
new_blue += ColorTransformDelta(m->green_to_blue_, green);
new_blue += ColorTransformDelta(m->red_to_blue_, new_red);
new_blue &= 0xff;
- } else {
- new_red -= ColorTransformDelta(m->green_to_red_, green);
- new_red &= 0xff;
- new_blue -= ColorTransformDelta(m->green_to_blue_, green);
- new_blue -= ColorTransformDelta(m->red_to_blue_, red);
- new_blue &= 0xff;
- }
- return (argb & 0xff00ff00u) | (new_red << 16) | (new_blue);
-}
-
-static WEBP_INLINE int SkipRepeatedPixels(const uint32_t* const argb,
- int ix, int xsize) {
- const uint32_t v = argb[ix];
- if (ix >= xsize + 3) {
- if (v == argb[ix - xsize] &&
- argb[ix - 1] == argb[ix - xsize - 1] &&
- argb[ix - 2] == argb[ix - xsize - 2] &&
- argb[ix - 3] == argb[ix - xsize - 3]) {
- return 1;
- }
- return v == argb[ix - 3] && v == argb[ix - 2] && v == argb[ix - 1];
- } else if (ix >= 3) {
- return v == argb[ix - 3] && v == argb[ix - 2] && v == argb[ix - 1];
- }
- return 0;
-}
-
-static float PredictionCostCrossColor(const int accumulated[256],
- const int counts[256]) {
- // Favor low entropy, locally and globally.
- int i;
- int combo[256];
- for (i = 0; i < 256; ++i) {
- combo[i] = accumulated[i] + counts[i];
- }
- return ShannonEntropy(combo, 256) +
- ShannonEntropy(counts, 256) +
- PredictionCostSpatial(counts, 3, 2.4); // Favor small absolute values.
-}
-
-static Multipliers GetBestColorTransformForTile(
- int tile_x, int tile_y, int bits,
- Multipliers prevX,
- Multipliers prevY,
- int step, int xsize, int ysize,
- int* accumulated_red_histo,
- int* accumulated_blue_histo,
- const uint32_t* const argb) {
- float best_diff = MAX_DIFF_COST;
- float cur_diff;
- const int halfstep = step / 2;
- const int max_tile_size = 1 << bits;
- const int tile_y_offset = tile_y * max_tile_size;
- const int tile_x_offset = tile_x * max_tile_size;
- int green_to_red;
- int green_to_blue;
- int red_to_blue;
- int all_x_max = tile_x_offset + max_tile_size;
- int all_y_max = tile_y_offset + max_tile_size;
- Multipliers best_tx;
- MultipliersClear(&best_tx);
- if (all_x_max > xsize) {
- all_x_max = xsize;
- }
- if (all_y_max > ysize) {
- all_y_max = ysize;
- }
- for (green_to_red = -64; green_to_red <= 64; green_to_red += halfstep) {
- int histo[256] = { 0 };
- int all_y;
- Multipliers tx;
- MultipliersClear(&tx);
- tx.green_to_red_ = green_to_red & 0xff;
-
- for (all_y = tile_y_offset; all_y < all_y_max; ++all_y) {
- uint32_t predict;
- int ix = all_y * xsize + tile_x_offset;
- int all_x;
- for (all_x = tile_x_offset; all_x < all_x_max; ++all_x, ++ix) {
- if (SkipRepeatedPixels(argb, ix, xsize)) {
- continue;
- }
- predict = TransformColor(&tx, argb[ix], 0);
- ++histo[(predict >> 16) & 0xff]; // red.
- }
- }
- cur_diff = PredictionCostCrossColor(&accumulated_red_histo[0], &histo[0]);
- if (tx.green_to_red_ == prevX.green_to_red_) {
- cur_diff -= 3; // favor keeping the areas locally similar
- }
- if (tx.green_to_red_ == prevY.green_to_red_) {
- cur_diff -= 3; // favor keeping the areas locally similar
- }
- if (tx.green_to_red_ == 0) {
- cur_diff -= 3;
- }
- if (cur_diff < best_diff) {
- best_diff = cur_diff;
- best_tx = tx;
- }
- }
- best_diff = MAX_DIFF_COST;
- green_to_red = best_tx.green_to_red_;
- for (green_to_blue = -32; green_to_blue <= 32; green_to_blue += step) {
- for (red_to_blue = -32; red_to_blue <= 32; red_to_blue += step) {
- int all_y;
- int histo[256] = { 0 };
- Multipliers tx;
- tx.green_to_red_ = green_to_red;
- tx.green_to_blue_ = green_to_blue;
- tx.red_to_blue_ = red_to_blue;
- for (all_y = tile_y_offset; all_y < all_y_max; ++all_y) {
- uint32_t predict;
- int all_x;
- int ix = all_y * xsize + tile_x_offset;
- for (all_x = tile_x_offset; all_x < all_x_max; ++all_x, ++ix) {
- if (SkipRepeatedPixels(argb, ix, xsize)) {
- continue;
- }
- predict = TransformColor(&tx, argb[ix], 0);
- ++histo[predict & 0xff]; // blue.
- }
- }
- cur_diff =
- PredictionCostCrossColor(&accumulated_blue_histo[0], &histo[0]);
- if (tx.green_to_blue_ == prevX.green_to_blue_) {
- cur_diff -= 3; // favor keeping the areas locally similar
- }
- if (tx.green_to_blue_ == prevY.green_to_blue_) {
- cur_diff -= 3; // favor keeping the areas locally similar
- }
- if (tx.red_to_blue_ == prevX.red_to_blue_) {
- cur_diff -= 3; // favor keeping the areas locally similar
- }
- if (tx.red_to_blue_ == prevY.red_to_blue_) {
- cur_diff -= 3; // favor keeping the areas locally similar
- }
- if (tx.green_to_blue_ == 0) {
- cur_diff -= 3;
- }
- if (tx.red_to_blue_ == 0) {
- cur_diff -= 3;
- }
- if (cur_diff < best_diff) {
- best_diff = cur_diff;
- best_tx = tx;
- }
- }
- }
- return best_tx;
-}
-
-static void CopyTileWithColorTransform(int xsize, int ysize,
- int tile_x, int tile_y, int bits,
- Multipliers color_transform,
- uint32_t* const argb) {
- int y;
- int xscan = 1 << bits;
- int yscan = 1 << bits;
- tile_x <<= bits;
- tile_y <<= bits;
- if (xscan > xsize - tile_x) {
- xscan = xsize - tile_x;
- }
- if (yscan > ysize - tile_y) {
- yscan = ysize - tile_y;
- }
- yscan += tile_y;
- for (y = tile_y; y < yscan; ++y) {
- int ix = y * xsize + tile_x;
- const int end_ix = ix + xscan;
- for (; ix < end_ix; ++ix) {
- argb[ix] = TransformColor(&color_transform, argb[ix], 0);
- }
- }
-}
-
-void VP8LColorSpaceTransform(int width, int height, int bits, int step,
- uint32_t* const argb, uint32_t* image) {
- const int max_tile_size = 1 << bits;
- int tile_xsize = VP8LSubSampleSize(width, bits);
- int tile_ysize = VP8LSubSampleSize(height, bits);
- int accumulated_red_histo[256] = { 0 };
- int accumulated_blue_histo[256] = { 0 };
- int tile_y;
- int tile_x;
- Multipliers prevX;
- Multipliers prevY;
- MultipliersClear(&prevY);
- MultipliersClear(&prevX);
- for (tile_y = 0; tile_y < tile_ysize; ++tile_y) {
- for (tile_x = 0; tile_x < tile_xsize; ++tile_x) {
- Multipliers color_transform;
- int all_x_max;
- int y;
- const int tile_y_offset = tile_y * max_tile_size;
- const int tile_x_offset = tile_x * max_tile_size;
- if (tile_y != 0) {
- ColorCodeToMultipliers(image[tile_y * tile_xsize + tile_x - 1], &prevX);
- ColorCodeToMultipliers(image[(tile_y - 1) * tile_xsize + tile_x],
- &prevY);
- } else if (tile_x != 0) {
- ColorCodeToMultipliers(image[tile_y * tile_xsize + tile_x - 1], &prevX);
- }
- color_transform =
- GetBestColorTransformForTile(tile_x, tile_y, bits,
- prevX, prevY,
- step, width, height,
- &accumulated_red_histo[0],
- &accumulated_blue_histo[0],
- argb);
- image[tile_y * tile_xsize + tile_x] =
- MultipliersToColorCode(&color_transform);
- CopyTileWithColorTransform(width, height, tile_x, tile_y, bits,
- color_transform, argb);
-
- // Gather accumulated histogram data.
- all_x_max = tile_x_offset + max_tile_size;
- if (all_x_max > width) {
- all_x_max = width;
- }
- for (y = 0; y < max_tile_size; ++y) {
- int ix;
- int all_x;
- int all_y = tile_y_offset + y;
- if (all_y >= height) {
- break;
- }
- ix = all_y * width + tile_x_offset;
- for (all_x = tile_x_offset; all_x < all_x_max; ++all_x, ++ix) {
- if (ix >= 2 &&
- argb[ix] == argb[ix - 2] &&
- argb[ix] == argb[ix - 1]) {
- continue; // repeated pixels are handled by backward references
- }
- if (ix >= width + 2 &&
- argb[ix - 2] == argb[ix - width - 2] &&
- argb[ix - 1] == argb[ix - width - 1] &&
- argb[ix] == argb[ix - width]) {
- continue; // repeated pixels are handled by backward references
- }
- ++accumulated_red_histo[(argb[ix] >> 16) & 0xff];
- ++accumulated_blue_histo[argb[ix] & 0xff];
- }
- }
- }
+ data[i] = (argb & 0xff00ff00u) | (new_red << 16) | (new_blue);
}
}
@@ -898,7 +281,10 @@ void VP8LColorSpaceTransform(int width, int height, int bits, int step,
static void ColorSpaceInverseTransform(const VP8LTransform* const transform,
int y_start, int y_end, uint32_t* data) {
const int width = transform->xsize_;
- const int mask = (1 << transform->bits_) - 1;
+ const int tile_width = 1 << transform->bits_;
+ const int mask = tile_width - 1;
+ const int safe_width = width & ~mask;
+ const int remaining_width = width - safe_width;
const int tiles_per_row = VP8LSubSampleSize(width, transform->bits_);
int y = y_start;
const uint32_t* pred_row =
@@ -906,68 +292,89 @@ static void ColorSpaceInverseTransform(const VP8LTransform* const transform,
while (y < y_end) {
const uint32_t* pred = pred_row;
- Multipliers m = { 0, 0, 0 };
- int x;
-
- for (x = 0; x < width; ++x) {
- if ((x & mask) == 0) ColorCodeToMultipliers(*pred++, &m);
- data[x] = TransformColor(&m, data[x], 1);
+ VP8LMultipliers m = { 0, 0, 0 };
+ const uint32_t* const data_safe_end = data + safe_width;
+ const uint32_t* const data_end = data + width;
+ while (data < data_safe_end) {
+ ColorCodeToMultipliers(*pred++, &m);
+ VP8LTransformColorInverse(&m, data, tile_width);
+ data += tile_width;
+ }
+ if (data < data_end) { // Left-overs using C-version.
+ ColorCodeToMultipliers(*pred++, &m);
+ VP8LTransformColorInverse(&m, data, remaining_width);
+ data += remaining_width;
}
- data += width;
++y;
- if ((y & mask) == 0) pred_row += tiles_per_row;;
+ if ((y & mask) == 0) pred_row += tiles_per_row;
}
}
// Separate out pixels packed together using pixel-bundling.
-static void ColorIndexInverseTransform(
- const VP8LTransform* const transform,
- int y_start, int y_end, const uint32_t* src, uint32_t* dst) {
- int y;
- const int bits_per_pixel = 8 >> transform->bits_;
- const int width = transform->xsize_;
- const uint32_t* const color_map = transform->data_;
- if (bits_per_pixel < 8) {
- const int pixels_per_byte = 1 << transform->bits_;
- const int count_mask = pixels_per_byte - 1;
- const uint32_t bit_mask = (1 << bits_per_pixel) - 1;
- for (y = y_start; y < y_end; ++y) {
- uint32_t packed_pixels = 0;
- int x;
- for (x = 0; x < width; ++x) {
- // We need to load fresh 'packed_pixels' once every 'pixels_per_byte'
- // increments of x. Fortunately, pixels_per_byte is a power of 2, so
- // can just use a mask for that, instead of decrementing a counter.
- if ((x & count_mask) == 0) packed_pixels = ((*src++) >> 8) & 0xff;
- *dst++ = color_map[packed_pixels & bit_mask];
- packed_pixels >>= bits_per_pixel;
- }
- }
- } else {
- for (y = y_start; y < y_end; ++y) {
- int x;
- for (x = 0; x < width; ++x) {
- *dst++ = color_map[((*src++) >> 8) & 0xff];
- }
- }
- }
-}
+// We define two methods for ARGB data (uint32_t) and alpha-only data (uint8_t).
+#define COLOR_INDEX_INVERSE(FUNC_NAME, F_NAME, STATIC_DECL, TYPE, BIT_SUFFIX, \
+ GET_INDEX, GET_VALUE) \
+static void F_NAME(const TYPE* src, const uint32_t* const color_map, \
+ TYPE* dst, int y_start, int y_end, int width) { \
+ int y; \
+ for (y = y_start; y < y_end; ++y) { \
+ int x; \
+ for (x = 0; x < width; ++x) { \
+ *dst++ = GET_VALUE(color_map[GET_INDEX(*src++)]); \
+ } \
+ } \
+} \
+STATIC_DECL void FUNC_NAME(const VP8LTransform* const transform, \
+ int y_start, int y_end, const TYPE* src, \
+ TYPE* dst) { \
+ int y; \
+ const int bits_per_pixel = 8 >> transform->bits_; \
+ const int width = transform->xsize_; \
+ const uint32_t* const color_map = transform->data_; \
+ if (bits_per_pixel < 8) { \
+ const int pixels_per_byte = 1 << transform->bits_; \
+ const int count_mask = pixels_per_byte - 1; \
+ const uint32_t bit_mask = (1 << bits_per_pixel) - 1; \
+ for (y = y_start; y < y_end; ++y) { \
+ uint32_t packed_pixels = 0; \
+ int x; \
+ for (x = 0; x < width; ++x) { \
+ /* We need to load fresh 'packed_pixels' once every */ \
+ /* 'pixels_per_byte' increments of x. Fortunately, pixels_per_byte */ \
+ /* is a power of 2, so can just use a mask for that, instead of */ \
+ /* decrementing a counter. */ \
+ if ((x & count_mask) == 0) packed_pixels = GET_INDEX(*src++); \
+ *dst++ = GET_VALUE(color_map[packed_pixels & bit_mask]); \
+ packed_pixels >>= bits_per_pixel; \
+ } \
+ } \
+ } else { \
+ VP8LMapColor##BIT_SUFFIX(src, color_map, dst, y_start, y_end, width); \
+ } \
+}
+
+COLOR_INDEX_INVERSE(ColorIndexInverseTransform, MapARGB, static, uint32_t, 32b,
+ VP8GetARGBIndex, VP8GetARGBValue)
+COLOR_INDEX_INVERSE(VP8LColorIndexInverseTransformAlpha, MapAlpha, , uint8_t,
+ 8b, VP8GetAlphaIndex, VP8GetAlphaValue)
+
+#undef COLOR_INDEX_INVERSE
void VP8LInverseTransform(const VP8LTransform* const transform,
int row_start, int row_end,
const uint32_t* const in, uint32_t* const out) {
+ const int width = transform->xsize_;
assert(row_start < row_end);
assert(row_end <= transform->ysize_);
switch (transform->type_) {
case SUBTRACT_GREEN:
- AddGreenToBlueAndRed(transform, row_start, row_end, out);
+ VP8LAddGreenToBlueAndRed(out, (row_end - row_start) * width);
break;
case PREDICTOR_TRANSFORM:
PredictorInverseTransform(transform, row_start, row_end, out);
if (row_end != transform->ysize_) {
// The last predicted row in this iteration will be the top-pred row
// for the first row in next iteration.
- const int width = transform->xsize_;
memcpy(out - width, out + (row_end - row_start - 1) * width,
width * sizeof(*out));
}
@@ -982,7 +389,7 @@ void VP8LInverseTransform(const VP8LTransform* const transform,
// Also, note that this is the only transform that applies on
// the effective width of VP8LSubSampleSize(xsize_, bits_). All other
// transforms work on effective width of xsize_.
- const int out_stride = (row_end - row_start) * transform->xsize_;
+ const int out_stride = (row_end - row_start) * width;
const int in_stride = (row_end - row_start) *
VP8LSubSampleSize(transform->xsize_, transform->bits_);
uint32_t* const src = out + out_stride - in_stride;
@@ -1006,8 +413,8 @@ static int is_big_endian(void) {
return (tmp.b[0] != 1);
}
-static void ConvertBGRAToRGB(const uint32_t* src,
- int num_pixels, uint8_t* dst) {
+void VP8LConvertBGRAToRGB_C(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
const uint32_t* const src_end = src + num_pixels;
while (src < src_end) {
const uint32_t argb = *src++;
@@ -1017,8 +424,8 @@ static void ConvertBGRAToRGB(const uint32_t* src,
}
}
-static void ConvertBGRAToRGBA(const uint32_t* src,
- int num_pixels, uint8_t* dst) {
+void VP8LConvertBGRAToRGBA_C(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
const uint32_t* const src_end = src + num_pixels;
while (src < src_end) {
const uint32_t argb = *src++;
@@ -1029,28 +436,42 @@ static void ConvertBGRAToRGBA(const uint32_t* src,
}
}
-static void ConvertBGRAToRGBA4444(const uint32_t* src,
- int num_pixels, uint8_t* dst) {
+void VP8LConvertBGRAToRGBA4444_C(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
const uint32_t* const src_end = src + num_pixels;
while (src < src_end) {
const uint32_t argb = *src++;
- *dst++ = ((argb >> 16) & 0xf0) | ((argb >> 12) & 0xf);
- *dst++ = ((argb >> 0) & 0xf0) | ((argb >> 28) & 0xf);
+ const uint8_t rg = ((argb >> 16) & 0xf0) | ((argb >> 12) & 0xf);
+ const uint8_t ba = ((argb >> 0) & 0xf0) | ((argb >> 28) & 0xf);
+#ifdef WEBP_SWAP_16BIT_CSP
+ *dst++ = ba;
+ *dst++ = rg;
+#else
+ *dst++ = rg;
+ *dst++ = ba;
+#endif
}
}
-static void ConvertBGRAToRGB565(const uint32_t* src,
- int num_pixels, uint8_t* dst) {
+void VP8LConvertBGRAToRGB565_C(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
const uint32_t* const src_end = src + num_pixels;
while (src < src_end) {
const uint32_t argb = *src++;
- *dst++ = ((argb >> 16) & 0xf8) | ((argb >> 13) & 0x7);
- *dst++ = ((argb >> 5) & 0xe0) | ((argb >> 3) & 0x1f);
+ const uint8_t rg = ((argb >> 16) & 0xf8) | ((argb >> 13) & 0x7);
+ const uint8_t gb = ((argb >> 5) & 0xe0) | ((argb >> 3) & 0x1f);
+#ifdef WEBP_SWAP_16BIT_CSP
+ *dst++ = gb;
+ *dst++ = rg;
+#else
+ *dst++ = rg;
+ *dst++ = gb;
+#endif
}
}
-static void ConvertBGRAToBGR(const uint32_t* src,
- int num_pixels, uint8_t* dst) {
+void VP8LConvertBGRAToBGR_C(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
const uint32_t* const src_end = src + num_pixels;
while (src < src_end) {
const uint32_t argb = *src++;
@@ -1065,21 +486,24 @@ static void CopyOrSwap(const uint32_t* src, int num_pixels, uint8_t* dst,
if (is_big_endian() == swap_on_big_endian) {
const uint32_t* const src_end = src + num_pixels;
while (src < src_end) {
- uint32_t argb = *src++;
-#if !defined(__BIG_ENDIAN__) && (defined(__i386__) || defined(__x86_64__))
- __asm__ volatile("bswap %0" : "=r"(argb) : "0"(argb));
- *(uint32_t*)dst = argb;
- dst += sizeof(argb);
-#elif !defined(__BIG_ENDIAN__) && defined(_MSC_VER)
- argb = _byteswap_ulong(argb);
- *(uint32_t*)dst = argb;
- dst += sizeof(argb);
-#else
- *dst++ = (argb >> 24) & 0xff;
- *dst++ = (argb >> 16) & 0xff;
- *dst++ = (argb >> 8) & 0xff;
- *dst++ = (argb >> 0) & 0xff;
+ const uint32_t argb = *src++;
+
+#if !defined(WORDS_BIGENDIAN)
+#if !defined(WEBP_REFERENCE_IMPLEMENTATION)
+ *(uint32_t*)dst = BSwap32(argb);
+#else // WEBP_REFERENCE_IMPLEMENTATION
+ dst[0] = (argb >> 24) & 0xff;
+ dst[1] = (argb >> 16) & 0xff;
+ dst[2] = (argb >> 8) & 0xff;
+ dst[3] = (argb >> 0) & 0xff;
#endif
+#else // WORDS_BIGENDIAN
+ dst[0] = (argb >> 0) & 0xff;
+ dst[1] = (argb >> 8) & 0xff;
+ dst[2] = (argb >> 16) & 0xff;
+ dst[3] = (argb >> 24) & 0xff;
+#endif
+ dst += sizeof(argb);
}
} else {
memcpy(dst, src, num_pixels * sizeof(*src));
@@ -1090,17 +514,17 @@ void VP8LConvertFromBGRA(const uint32_t* const in_data, int num_pixels,
WEBP_CSP_MODE out_colorspace, uint8_t* const rgba) {
switch (out_colorspace) {
case MODE_RGB:
- ConvertBGRAToRGB(in_data, num_pixels, rgba);
+ VP8LConvertBGRAToRGB(in_data, num_pixels, rgba);
break;
case MODE_RGBA:
- ConvertBGRAToRGBA(in_data, num_pixels, rgba);
+ VP8LConvertBGRAToRGBA(in_data, num_pixels, rgba);
break;
case MODE_rgbA:
- ConvertBGRAToRGBA(in_data, num_pixels, rgba);
+ VP8LConvertBGRAToRGBA(in_data, num_pixels, rgba);
WebPApplyAlphaMultiply(rgba, 0, num_pixels, 1, 0);
break;
case MODE_BGR:
- ConvertBGRAToBGR(in_data, num_pixels, rgba);
+ VP8LConvertBGRAToBGR(in_data, num_pixels, rgba);
break;
case MODE_BGRA:
CopyOrSwap(in_data, num_pixels, rgba, 1);
@@ -1117,14 +541,14 @@ void VP8LConvertFromBGRA(const uint32_t* const in_data, int num_pixels,
WebPApplyAlphaMultiply(rgba, 1, num_pixels, 1, 0);
break;
case MODE_RGBA_4444:
- ConvertBGRAToRGBA4444(in_data, num_pixels, rgba);
+ VP8LConvertBGRAToRGBA4444(in_data, num_pixels, rgba);
break;
case MODE_rgbA_4444:
- ConvertBGRAToRGBA4444(in_data, num_pixels, rgba);
+ VP8LConvertBGRAToRGBA4444(in_data, num_pixels, rgba);
WebPApplyAlphaMultiply4444(rgba, num_pixels, 1, 0);
break;
case MODE_RGB_565:
- ConvertBGRAToRGB565(in_data, num_pixels, rgba);
+ VP8LConvertBGRAToRGB565(in_data, num_pixels, rgba);
break;
default:
assert(0); // Code flow should not reach here.
@@ -1133,6 +557,79 @@ void VP8LConvertFromBGRA(const uint32_t* const in_data, int num_pixels,
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
+VP8LProcessBlueAndRedFunc VP8LAddGreenToBlueAndRed;
+VP8LPredictorFunc VP8LPredictors[16];
+
+VP8LTransformColorFunc VP8LTransformColorInverse;
+
+VP8LConvertFunc VP8LConvertBGRAToRGB;
+VP8LConvertFunc VP8LConvertBGRAToRGBA;
+VP8LConvertFunc VP8LConvertBGRAToRGBA4444;
+VP8LConvertFunc VP8LConvertBGRAToRGB565;
+VP8LConvertFunc VP8LConvertBGRAToBGR;
+
+VP8LMapARGBFunc VP8LMapColor32b;
+VP8LMapAlphaFunc VP8LMapColor8b;
+
+extern void VP8LDspInitSSE2(void);
+extern void VP8LDspInitNEON(void);
+extern void VP8LDspInitMIPSdspR2(void);
+
+static volatile VP8CPUInfo lossless_last_cpuinfo_used =
+ (VP8CPUInfo)&lossless_last_cpuinfo_used;
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInit(void) {
+ if (lossless_last_cpuinfo_used == VP8GetCPUInfo) return;
+
+ VP8LPredictors[0] = Predictor0;
+ VP8LPredictors[1] = Predictor1;
+ VP8LPredictors[2] = Predictor2;
+ VP8LPredictors[3] = Predictor3;
+ VP8LPredictors[4] = Predictor4;
+ VP8LPredictors[5] = Predictor5;
+ VP8LPredictors[6] = Predictor6;
+ VP8LPredictors[7] = Predictor7;
+ VP8LPredictors[8] = Predictor8;
+ VP8LPredictors[9] = Predictor9;
+ VP8LPredictors[10] = Predictor10;
+ VP8LPredictors[11] = Predictor11;
+ VP8LPredictors[12] = Predictor12;
+ VP8LPredictors[13] = Predictor13;
+ VP8LPredictors[14] = Predictor0; // <- padding security sentinels
+ VP8LPredictors[15] = Predictor0;
+
+ VP8LAddGreenToBlueAndRed = VP8LAddGreenToBlueAndRed_C;
+
+ VP8LTransformColorInverse = VP8LTransformColorInverse_C;
+
+ VP8LConvertBGRAToRGB = VP8LConvertBGRAToRGB_C;
+ VP8LConvertBGRAToRGBA = VP8LConvertBGRAToRGBA_C;
+ VP8LConvertBGRAToRGBA4444 = VP8LConvertBGRAToRGBA4444_C;
+ VP8LConvertBGRAToRGB565 = VP8LConvertBGRAToRGB565_C;
+ VP8LConvertBGRAToBGR = VP8LConvertBGRAToBGR_C;
+
+ VP8LMapColor32b = MapARGB;
+ VP8LMapColor8b = MapAlpha;
+
+ // If defined, use CPUInfo() to overwrite some pointers with faster versions.
+ if (VP8GetCPUInfo != NULL) {
+#if defined(WEBP_USE_SSE2)
+ if (VP8GetCPUInfo(kSSE2)) {
+ VP8LDspInitSSE2();
+ }
+#endif
+#if defined(WEBP_USE_NEON)
+ if (VP8GetCPUInfo(kNEON)) {
+ VP8LDspInitNEON();
+ }
+#endif
+#if defined(WEBP_USE_MIPS_DSP_R2)
+ if (VP8GetCPUInfo(kMIPSdspR2)) {
+ VP8LDspInitMIPSdspR2();
+ }
#endif
+ }
+ lossless_last_cpuinfo_used = VP8GetCPUInfo;
+}
+
+//------------------------------------------------------------------------------
diff --git a/drivers/webp/dsp/lossless.h b/drivers/webp/dsp/lossless.h
index 7c7d5555ed..149c6a01d3 100644
--- a/drivers/webp/dsp/lossless.h
+++ b/drivers/webp/dsp/lossless.h
@@ -1,8 +1,10 @@
// Copyright 2012 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Image transforms and color space conversion methods for lossless decoder.
@@ -13,15 +15,42 @@
#ifndef WEBP_DSP_LOSSLESS_H_
#define WEBP_DSP_LOSSLESS_H_
-#include "../types.h"
-#include "../decode.h"
+#include "webp/types.h"
+#include "webp/decode.h"
-#if defined(__cplusplus) || defined(c_plusplus)
+#include "../enc/histogram.h"
+#include "../utils/utils.h"
+
+#ifdef __cplusplus
extern "C" {
#endif
+#ifdef WEBP_EXPERIMENTAL_FEATURES
+#include "../enc/delta_palettization.h"
+#endif // WEBP_EXPERIMENTAL_FEATURES
+
+// Not a trivial literal symbol.
+#define VP8L_NON_TRIVIAL_SYM (0xffffffff)
+
//------------------------------------------------------------------------------
-// Image transforms.
+// Decoding
+
+typedef uint32_t (*VP8LPredictorFunc)(uint32_t left, const uint32_t* const top);
+extern VP8LPredictorFunc VP8LPredictors[16];
+
+typedef void (*VP8LProcessBlueAndRedFunc)(uint32_t* argb_data, int num_pixels);
+extern VP8LProcessBlueAndRedFunc VP8LAddGreenToBlueAndRed;
+
+typedef struct {
+ // Note: the members are uint8_t, so that any negative values are
+ // automatically converted to "mod 256" values.
+ uint8_t green_to_red_;
+ uint8_t green_to_blue_;
+ uint8_t red_to_blue_;
+} VP8LMultipliers;
+typedef void (*VP8LTransformColorFunc)(const VP8LMultipliers* const m,
+ uint32_t* argb_data, int num_pixels);
+extern VP8LTransformColorFunc VP8LTransformColorInverse;
struct VP8LTransform; // Defined in dec/vp8li.h.
@@ -33,23 +62,110 @@ void VP8LInverseTransform(const struct VP8LTransform* const transform,
int row_start, int row_end,
const uint32_t* const in, uint32_t* const out);
-// Subtracts green from blue and red channels.
-void VP8LSubtractGreenFromBlueAndRed(uint32_t* argb_data, int num_pixs);
-
-void VP8LResidualImage(int width, int height, int bits,
- uint32_t* const argb, uint32_t* const argb_scratch,
- uint32_t* const image);
-
-void VP8LColorSpaceTransform(int width, int height, int bits, int step,
- uint32_t* const argb, uint32_t* image);
-
-//------------------------------------------------------------------------------
// Color space conversion.
+typedef void (*VP8LConvertFunc)(const uint32_t* src, int num_pixels,
+ uint8_t* dst);
+extern VP8LConvertFunc VP8LConvertBGRAToRGB;
+extern VP8LConvertFunc VP8LConvertBGRAToRGBA;
+extern VP8LConvertFunc VP8LConvertBGRAToRGBA4444;
+extern VP8LConvertFunc VP8LConvertBGRAToRGB565;
+extern VP8LConvertFunc VP8LConvertBGRAToBGR;
// Converts from BGRA to other color spaces.
void VP8LConvertFromBGRA(const uint32_t* const in_data, int num_pixels,
WEBP_CSP_MODE out_colorspace, uint8_t* const rgba);
+// color mapping related functions.
+static WEBP_INLINE uint32_t VP8GetARGBIndex(uint32_t idx) {
+ return (idx >> 8) & 0xff;
+}
+
+static WEBP_INLINE uint8_t VP8GetAlphaIndex(uint8_t idx) {
+ return idx;
+}
+
+static WEBP_INLINE uint32_t VP8GetARGBValue(uint32_t val) {
+ return val;
+}
+
+static WEBP_INLINE uint8_t VP8GetAlphaValue(uint32_t val) {
+ return (val >> 8) & 0xff;
+}
+
+typedef void (*VP8LMapARGBFunc)(const uint32_t* src,
+ const uint32_t* const color_map,
+ uint32_t* dst, int y_start,
+ int y_end, int width);
+typedef void (*VP8LMapAlphaFunc)(const uint8_t* src,
+ const uint32_t* const color_map,
+ uint8_t* dst, int y_start,
+ int y_end, int width);
+
+extern VP8LMapARGBFunc VP8LMapColor32b;
+extern VP8LMapAlphaFunc VP8LMapColor8b;
+
+// Similar to the static method ColorIndexInverseTransform() that is part of
+// lossless.c, but used only for alpha decoding. It takes uint8_t (rather than
+// uint32_t) arguments for 'src' and 'dst'.
+void VP8LColorIndexInverseTransformAlpha(
+ const struct VP8LTransform* const transform, int y_start, int y_end,
+ const uint8_t* src, uint8_t* dst);
+
+// Expose some C-only fallback functions
+void VP8LTransformColorInverse_C(const VP8LMultipliers* const m,
+ uint32_t* data, int num_pixels);
+
+void VP8LConvertBGRAToRGB_C(const uint32_t* src, int num_pixels, uint8_t* dst);
+void VP8LConvertBGRAToRGBA_C(const uint32_t* src, int num_pixels, uint8_t* dst);
+void VP8LConvertBGRAToRGBA4444_C(const uint32_t* src,
+ int num_pixels, uint8_t* dst);
+void VP8LConvertBGRAToRGB565_C(const uint32_t* src,
+ int num_pixels, uint8_t* dst);
+void VP8LConvertBGRAToBGR_C(const uint32_t* src, int num_pixels, uint8_t* dst);
+void VP8LAddGreenToBlueAndRed_C(uint32_t* data, int num_pixels);
+
+// Must be called before calling any of the above methods.
+void VP8LDspInit(void);
+
+//------------------------------------------------------------------------------
+// Encoding
+
+extern VP8LProcessBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed;
+extern VP8LTransformColorFunc VP8LTransformColor;
+typedef void (*VP8LCollectColorBlueTransformsFunc)(
+ const uint32_t* argb, int stride,
+ int tile_width, int tile_height,
+ int green_to_blue, int red_to_blue, int histo[]);
+extern VP8LCollectColorBlueTransformsFunc VP8LCollectColorBlueTransforms;
+
+typedef void (*VP8LCollectColorRedTransformsFunc)(
+ const uint32_t* argb, int stride,
+ int tile_width, int tile_height,
+ int green_to_red, int histo[]);
+extern VP8LCollectColorRedTransformsFunc VP8LCollectColorRedTransforms;
+
+// Expose some C-only fallback functions
+void VP8LTransformColor_C(const VP8LMultipliers* const m,
+ uint32_t* data, int num_pixels);
+void VP8LSubtractGreenFromBlueAndRed_C(uint32_t* argb_data, int num_pixels);
+void VP8LCollectColorRedTransforms_C(const uint32_t* argb, int stride,
+ int tile_width, int tile_height,
+ int green_to_red, int histo[]);
+void VP8LCollectColorBlueTransforms_C(const uint32_t* argb, int stride,
+ int tile_width, int tile_height,
+ int green_to_blue, int red_to_blue,
+ int histo[]);
+
+//------------------------------------------------------------------------------
+// Image transforms.
+
+void VP8LResidualImage(int width, int height, int bits, int low_effort,
+ uint32_t* const argb, uint32_t* const argb_scratch,
+ uint32_t* const image);
+
+void VP8LColorSpaceTransform(int width, int height, int bits, int quality,
+ uint32_t* const argb, uint32_t* image);
+
//------------------------------------------------------------------------------
// Misc methods.
@@ -59,10 +175,136 @@ static WEBP_INLINE uint32_t VP8LSubSampleSize(uint32_t size,
return (size + (1 << sampling_bits) - 1) >> sampling_bits;
}
-// Faster logarithm for integers, with the property of log2(0) == 0.
-float VP8LFastLog2(int v);
+// -----------------------------------------------------------------------------
+// Faster logarithm for integers. Small values use a look-up table.
+#define LOG_LOOKUP_IDX_MAX 256
+extern const float kLog2Table[LOG_LOOKUP_IDX_MAX];
+extern const float kSLog2Table[LOG_LOOKUP_IDX_MAX];
+typedef float (*VP8LFastLog2SlowFunc)(uint32_t v);
+
+extern VP8LFastLog2SlowFunc VP8LFastLog2Slow;
+extern VP8LFastLog2SlowFunc VP8LFastSLog2Slow;
+
+static WEBP_INLINE float VP8LFastLog2(uint32_t v) {
+ return (v < LOG_LOOKUP_IDX_MAX) ? kLog2Table[v] : VP8LFastLog2Slow(v);
+}
// Fast calculation of v * log2(v) for integer input.
-static WEBP_INLINE float VP8LFastSLog2(int v) { return VP8LFastLog2(v) * v; }
+static WEBP_INLINE float VP8LFastSLog2(uint32_t v) {
+ return (v < LOG_LOOKUP_IDX_MAX) ? kSLog2Table[v] : VP8LFastSLog2Slow(v);
+}
+
+// -----------------------------------------------------------------------------
+// Huffman-cost related functions.
+
+typedef double (*VP8LCostFunc)(const uint32_t* population, int length);
+typedef double (*VP8LCostCombinedFunc)(const uint32_t* X, const uint32_t* Y,
+ int length);
+
+extern VP8LCostFunc VP8LExtraCost;
+extern VP8LCostCombinedFunc VP8LExtraCostCombined;
+
+typedef struct { // small struct to hold counters
+ int counts[2]; // index: 0=zero steak, 1=non-zero streak
+ int streaks[2][2]; // [zero/non-zero][streak<3 / streak>=3]
+} VP8LStreaks;
+
+typedef VP8LStreaks (*VP8LCostCountFunc)(const uint32_t* population,
+ int length);
+typedef VP8LStreaks (*VP8LCostCombinedCountFunc)(const uint32_t* X,
+ const uint32_t* Y, int length);
+
+extern VP8LCostCountFunc VP8LHuffmanCostCount;
+extern VP8LCostCombinedCountFunc VP8LHuffmanCostCombinedCount;
+
+// Get the symbol entropy for the distribution 'population'.
+// Set 'trivial_sym', if there's only one symbol present in the distribution.
+double VP8LPopulationCost(const uint32_t* const population, int length,
+ uint32_t* const trivial_sym);
+
+// Get the combined symbol entropy for the distributions 'X' and 'Y'.
+double VP8LGetCombinedEntropy(const uint32_t* const X,
+ const uint32_t* const Y, int length);
+
+double VP8LBitsEntropy(const uint32_t* const array, int n,
+ uint32_t* const trivial_symbol);
+
+// Estimate how many bits the combined entropy of literals and distance
+// approximately maps to.
+double VP8LHistogramEstimateBits(const VP8LHistogram* const p);
+
+// This function estimates the cost in bits excluding the bits needed to
+// represent the entropy code itself.
+double VP8LHistogramEstimateBitsBulk(const VP8LHistogram* const p);
+
+typedef void (*VP8LHistogramAddFunc)(const VP8LHistogram* const a,
+ const VP8LHistogram* const b,
+ VP8LHistogram* const out);
+extern VP8LHistogramAddFunc VP8LHistogramAdd;
+
+// -----------------------------------------------------------------------------
+// PrefixEncode()
+
+static WEBP_INLINE int VP8LBitsLog2Ceiling(uint32_t n) {
+ const int log_floor = BitsLog2Floor(n);
+ if (n == (n & ~(n - 1))) // zero or a power of two.
+ return log_floor;
+ else
+ return log_floor + 1;
+}
+
+// Splitting of distance and length codes into prefixes and
+// extra bits. The prefixes are encoded with an entropy code
+// while the extra bits are stored just as normal bits.
+static WEBP_INLINE void VP8LPrefixEncodeBitsNoLUT(int distance, int* const code,
+ int* const extra_bits) {
+ const int highest_bit = BitsLog2Floor(--distance);
+ const int second_highest_bit = (distance >> (highest_bit - 1)) & 1;
+ *extra_bits = highest_bit - 1;
+ *code = 2 * highest_bit + second_highest_bit;
+}
+
+static WEBP_INLINE void VP8LPrefixEncodeNoLUT(int distance, int* const code,
+ int* const extra_bits,
+ int* const extra_bits_value) {
+ const int highest_bit = BitsLog2Floor(--distance);
+ const int second_highest_bit = (distance >> (highest_bit - 1)) & 1;
+ *extra_bits = highest_bit - 1;
+ *extra_bits_value = distance & ((1 << *extra_bits) - 1);
+ *code = 2 * highest_bit + second_highest_bit;
+}
+
+#define PREFIX_LOOKUP_IDX_MAX 512
+typedef struct {
+ int8_t code_;
+ int8_t extra_bits_;
+} VP8LPrefixCode;
+
+// These tables are derived using VP8LPrefixEncodeNoLUT.
+extern const VP8LPrefixCode kPrefixEncodeCode[PREFIX_LOOKUP_IDX_MAX];
+extern const uint8_t kPrefixEncodeExtraBitsValue[PREFIX_LOOKUP_IDX_MAX];
+static WEBP_INLINE void VP8LPrefixEncodeBits(int distance, int* const code,
+ int* const extra_bits) {
+ if (distance < PREFIX_LOOKUP_IDX_MAX) {
+ const VP8LPrefixCode prefix_code = kPrefixEncodeCode[distance];
+ *code = prefix_code.code_;
+ *extra_bits = prefix_code.extra_bits_;
+ } else {
+ VP8LPrefixEncodeBitsNoLUT(distance, code, extra_bits);
+ }
+}
+
+static WEBP_INLINE void VP8LPrefixEncode(int distance, int* const code,
+ int* const extra_bits,
+ int* const extra_bits_value) {
+ if (distance < PREFIX_LOOKUP_IDX_MAX) {
+ const VP8LPrefixCode prefix_code = kPrefixEncodeCode[distance];
+ *code = prefix_code.code_;
+ *extra_bits = prefix_code.extra_bits_;
+ *extra_bits_value = kPrefixEncodeExtraBitsValue[distance];
+ } else {
+ VP8LPrefixEncodeNoLUT(distance, code, extra_bits, extra_bits_value);
+ }
+}
// In-place difference of each component with mod 256.
static WEBP_INLINE uint32_t VP8LSubPixels(uint32_t a, uint32_t b) {
@@ -73,9 +315,15 @@ static WEBP_INLINE uint32_t VP8LSubPixels(uint32_t a, uint32_t b) {
return (alpha_and_green & 0xff00ff00u) | (red_and_blue & 0x00ff00ffu);
}
+void VP8LBundleColorMap(const uint8_t* const row, int width,
+ int xbits, uint32_t* const dst);
+
+// Must be called before calling any of the above methods.
+void VP8LEncDspInit(void);
+
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/drivers/webp/dsp/lossless_enc.c b/drivers/webp/dsp/lossless_enc.c
new file mode 100644
index 0000000000..b3036f5384
--- /dev/null
+++ b/drivers/webp/dsp/lossless_enc.c
@@ -0,0 +1,1305 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Image transform methods for lossless encoder.
+//
+// Authors: Vikas Arora (vikaas.arora@gmail.com)
+// Jyrki Alakuijala (jyrki@google.com)
+// Urvang Joshi (urvang@google.com)
+
+#include "./dsp.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include "../dec/vp8li.h"
+#include "../utils/endian_inl.h"
+#include "./lossless.h"
+#include "./yuv.h"
+
+#define MAX_DIFF_COST (1e30f)
+
+// lookup table for small values of log2(int)
+const float kLog2Table[LOG_LOOKUP_IDX_MAX] = {
+ 0.0000000000000000f, 0.0000000000000000f,
+ 1.0000000000000000f, 1.5849625007211560f,
+ 2.0000000000000000f, 2.3219280948873621f,
+ 2.5849625007211560f, 2.8073549220576041f,
+ 3.0000000000000000f, 3.1699250014423121f,
+ 3.3219280948873621f, 3.4594316186372973f,
+ 3.5849625007211560f, 3.7004397181410921f,
+ 3.8073549220576041f, 3.9068905956085187f,
+ 4.0000000000000000f, 4.0874628412503390f,
+ 4.1699250014423121f, 4.2479275134435852f,
+ 4.3219280948873626f, 4.3923174227787606f,
+ 4.4594316186372973f, 4.5235619560570130f,
+ 4.5849625007211560f, 4.6438561897747243f,
+ 4.7004397181410917f, 4.7548875021634682f,
+ 4.8073549220576037f, 4.8579809951275718f,
+ 4.9068905956085187f, 4.9541963103868749f,
+ 5.0000000000000000f, 5.0443941193584533f,
+ 5.0874628412503390f, 5.1292830169449663f,
+ 5.1699250014423121f, 5.2094533656289501f,
+ 5.2479275134435852f, 5.2854022188622487f,
+ 5.3219280948873626f, 5.3575520046180837f,
+ 5.3923174227787606f, 5.4262647547020979f,
+ 5.4594316186372973f, 5.4918530963296747f,
+ 5.5235619560570130f, 5.5545888516776376f,
+ 5.5849625007211560f, 5.6147098441152083f,
+ 5.6438561897747243f, 5.6724253419714951f,
+ 5.7004397181410917f, 5.7279204545631987f,
+ 5.7548875021634682f, 5.7813597135246599f,
+ 5.8073549220576037f, 5.8328900141647412f,
+ 5.8579809951275718f, 5.8826430493618415f,
+ 5.9068905956085187f, 5.9307373375628866f,
+ 5.9541963103868749f, 5.9772799234999167f,
+ 6.0000000000000000f, 6.0223678130284543f,
+ 6.0443941193584533f, 6.0660891904577720f,
+ 6.0874628412503390f, 6.1085244567781691f,
+ 6.1292830169449663f, 6.1497471195046822f,
+ 6.1699250014423121f, 6.1898245588800175f,
+ 6.2094533656289501f, 6.2288186904958804f,
+ 6.2479275134435852f, 6.2667865406949010f,
+ 6.2854022188622487f, 6.3037807481771030f,
+ 6.3219280948873626f, 6.3398500028846243f,
+ 6.3575520046180837f, 6.3750394313469245f,
+ 6.3923174227787606f, 6.4093909361377017f,
+ 6.4262647547020979f, 6.4429434958487279f,
+ 6.4594316186372973f, 6.4757334309663976f,
+ 6.4918530963296747f, 6.5077946401986963f,
+ 6.5235619560570130f, 6.5391588111080309f,
+ 6.5545888516776376f, 6.5698556083309478f,
+ 6.5849625007211560f, 6.5999128421871278f,
+ 6.6147098441152083f, 6.6293566200796094f,
+ 6.6438561897747243f, 6.6582114827517946f,
+ 6.6724253419714951f, 6.6865005271832185f,
+ 6.7004397181410917f, 6.7142455176661224f,
+ 6.7279204545631987f, 6.7414669864011464f,
+ 6.7548875021634682f, 6.7681843247769259f,
+ 6.7813597135246599f, 6.7944158663501061f,
+ 6.8073549220576037f, 6.8201789624151878f,
+ 6.8328900141647412f, 6.8454900509443747f,
+ 6.8579809951275718f, 6.8703647195834047f,
+ 6.8826430493618415f, 6.8948177633079437f,
+ 6.9068905956085187f, 6.9188632372745946f,
+ 6.9307373375628866f, 6.9425145053392398f,
+ 6.9541963103868749f, 6.9657842846620869f,
+ 6.9772799234999167f, 6.9886846867721654f,
+ 7.0000000000000000f, 7.0112272554232539f,
+ 7.0223678130284543f, 7.0334230015374501f,
+ 7.0443941193584533f, 7.0552824355011898f,
+ 7.0660891904577720f, 7.0768155970508308f,
+ 7.0874628412503390f, 7.0980320829605263f,
+ 7.1085244567781691f, 7.1189410727235076f,
+ 7.1292830169449663f, 7.1395513523987936f,
+ 7.1497471195046822f, 7.1598713367783890f,
+ 7.1699250014423121f, 7.1799090900149344f,
+ 7.1898245588800175f, 7.1996723448363644f,
+ 7.2094533656289501f, 7.2191685204621611f,
+ 7.2288186904958804f, 7.2384047393250785f,
+ 7.2479275134435852f, 7.2573878426926521f,
+ 7.2667865406949010f, 7.2761244052742375f,
+ 7.2854022188622487f, 7.2946207488916270f,
+ 7.3037807481771030f, 7.3128829552843557f,
+ 7.3219280948873626f, 7.3309168781146167f,
+ 7.3398500028846243f, 7.3487281542310771f,
+ 7.3575520046180837f, 7.3663222142458160f,
+ 7.3750394313469245f, 7.3837042924740519f,
+ 7.3923174227787606f, 7.4008794362821843f,
+ 7.4093909361377017f, 7.4178525148858982f,
+ 7.4262647547020979f, 7.4346282276367245f,
+ 7.4429434958487279f, 7.4512111118323289f,
+ 7.4594316186372973f, 7.4676055500829976f,
+ 7.4757334309663976f, 7.4838157772642563f,
+ 7.4918530963296747f, 7.4998458870832056f,
+ 7.5077946401986963f, 7.5156998382840427f,
+ 7.5235619560570130f, 7.5313814605163118f,
+ 7.5391588111080309f, 7.5468944598876364f,
+ 7.5545888516776376f, 7.5622424242210728f,
+ 7.5698556083309478f, 7.5774288280357486f,
+ 7.5849625007211560f, 7.5924570372680806f,
+ 7.5999128421871278f, 7.6073303137496104f,
+ 7.6147098441152083f, 7.6220518194563764f,
+ 7.6293566200796094f, 7.6366246205436487f,
+ 7.6438561897747243f, 7.6510516911789281f,
+ 7.6582114827517946f, 7.6653359171851764f,
+ 7.6724253419714951f, 7.6794800995054464f,
+ 7.6865005271832185f, 7.6934869574993252f,
+ 7.7004397181410917f, 7.7073591320808825f,
+ 7.7142455176661224f, 7.7210991887071855f,
+ 7.7279204545631987f, 7.7347096202258383f,
+ 7.7414669864011464f, 7.7481928495894605f,
+ 7.7548875021634682f, 7.7615512324444795f,
+ 7.7681843247769259f, 7.7747870596011736f,
+ 7.7813597135246599f, 7.7879025593914317f,
+ 7.7944158663501061f, 7.8008998999203047f,
+ 7.8073549220576037f, 7.8137811912170374f,
+ 7.8201789624151878f, 7.8265484872909150f,
+ 7.8328900141647412f, 7.8392037880969436f,
+ 7.8454900509443747f, 7.8517490414160571f,
+ 7.8579809951275718f, 7.8641861446542797f,
+ 7.8703647195834047f, 7.8765169465649993f,
+ 7.8826430493618415f, 7.8887432488982591f,
+ 7.8948177633079437f, 7.9008668079807486f,
+ 7.9068905956085187f, 7.9128893362299619f,
+ 7.9188632372745946f, 7.9248125036057812f,
+ 7.9307373375628866f, 7.9366379390025709f,
+ 7.9425145053392398f, 7.9483672315846778f,
+ 7.9541963103868749f, 7.9600019320680805f,
+ 7.9657842846620869f, 7.9715435539507719f,
+ 7.9772799234999167f, 7.9829935746943103f,
+ 7.9886846867721654f, 7.9943534368588577f
+};
+
+const float kSLog2Table[LOG_LOOKUP_IDX_MAX] = {
+ 0.00000000f, 0.00000000f, 2.00000000f, 4.75488750f,
+ 8.00000000f, 11.60964047f, 15.50977500f, 19.65148445f,
+ 24.00000000f, 28.52932501f, 33.21928095f, 38.05374781f,
+ 43.01955001f, 48.10571634f, 53.30296891f, 58.60335893f,
+ 64.00000000f, 69.48686830f, 75.05865003f, 80.71062276f,
+ 86.43856190f, 92.23866588f, 98.10749561f, 104.04192499f,
+ 110.03910002f, 116.09640474f, 122.21143267f, 128.38196256f,
+ 134.60593782f, 140.88144886f, 147.20671787f, 153.58008562f,
+ 160.00000000f, 166.46500594f, 172.97373660f, 179.52490559f,
+ 186.11730005f, 192.74977453f, 199.42124551f, 206.13068654f,
+ 212.87712380f, 219.65963219f, 226.47733176f, 233.32938445f,
+ 240.21499122f, 247.13338933f, 254.08384998f, 261.06567603f,
+ 268.07820003f, 275.12078236f, 282.19280949f, 289.29369244f,
+ 296.42286534f, 303.57978409f, 310.76392512f, 317.97478424f,
+ 325.21187564f, 332.47473081f, 339.76289772f, 347.07593991f,
+ 354.41343574f, 361.77497759f, 369.16017124f, 376.56863518f,
+ 384.00000000f, 391.45390785f, 398.93001188f, 406.42797576f,
+ 413.94747321f, 421.48818752f, 429.04981119f, 436.63204548f,
+ 444.23460010f, 451.85719280f, 459.49954906f, 467.16140179f,
+ 474.84249102f, 482.54256363f, 490.26137307f, 497.99867911f,
+ 505.75424759f, 513.52785023f, 521.31926438f, 529.12827280f,
+ 536.95466351f, 544.79822957f, 552.65876890f, 560.53608414f,
+ 568.42998244f, 576.34027536f, 584.26677867f, 592.20931226f,
+ 600.16769996f, 608.14176943f, 616.13135206f, 624.13628279f,
+ 632.15640007f, 640.19154569f, 648.24156472f, 656.30630539f,
+ 664.38561898f, 672.47935976f, 680.58738488f, 688.70955430f,
+ 696.84573069f, 704.99577935f, 713.15956818f, 721.33696754f,
+ 729.52785023f, 737.73209140f, 745.94956849f, 754.18016116f,
+ 762.42375127f, 770.68022275f, 778.94946161f, 787.23135586f,
+ 795.52579543f, 803.83267219f, 812.15187982f, 820.48331383f,
+ 828.82687147f, 837.18245171f, 845.54995518f, 853.92928416f,
+ 862.32034249f, 870.72303558f, 879.13727036f, 887.56295522f,
+ 896.00000000f, 904.44831595f, 912.90781569f, 921.37841320f,
+ 929.86002376f, 938.35256392f, 946.85595152f, 955.37010560f,
+ 963.89494641f, 972.43039537f, 980.97637504f, 989.53280911f,
+ 998.09962237f, 1006.67674069f, 1015.26409097f, 1023.86160116f,
+ 1032.46920021f, 1041.08681805f, 1049.71438560f, 1058.35183469f,
+ 1066.99909811f, 1075.65610955f, 1084.32280357f, 1092.99911564f,
+ 1101.68498204f, 1110.38033993f, 1119.08512727f, 1127.79928282f,
+ 1136.52274614f, 1145.25545758f, 1153.99735821f, 1162.74838989f,
+ 1171.50849518f, 1180.27761738f, 1189.05570047f, 1197.84268914f,
+ 1206.63852876f, 1215.44316535f, 1224.25654560f, 1233.07861684f,
+ 1241.90932703f, 1250.74862473f, 1259.59645914f, 1268.45278005f,
+ 1277.31753781f, 1286.19068338f, 1295.07216828f, 1303.96194457f,
+ 1312.85996488f, 1321.76618236f, 1330.68055071f, 1339.60302413f,
+ 1348.53355734f, 1357.47210556f, 1366.41862452f, 1375.37307041f,
+ 1384.33539991f, 1393.30557020f, 1402.28353887f, 1411.26926400f,
+ 1420.26270412f, 1429.26381818f, 1438.27256558f, 1447.28890615f,
+ 1456.31280014f, 1465.34420819f, 1474.38309138f, 1483.42941118f,
+ 1492.48312945f, 1501.54420843f, 1510.61261078f, 1519.68829949f,
+ 1528.77123795f, 1537.86138993f, 1546.95871952f, 1556.06319119f,
+ 1565.17476976f, 1574.29342040f, 1583.41910860f, 1592.55180020f,
+ 1601.69146137f, 1610.83805860f, 1619.99155871f, 1629.15192882f,
+ 1638.31913637f, 1647.49314911f, 1656.67393509f, 1665.86146266f,
+ 1675.05570047f, 1684.25661744f, 1693.46418280f, 1702.67836605f,
+ 1711.89913698f, 1721.12646563f, 1730.36032233f, 1739.60067768f,
+ 1748.84750254f, 1758.10076802f, 1767.36044551f, 1776.62650662f,
+ 1785.89892323f, 1795.17766747f, 1804.46271172f, 1813.75402857f,
+ 1823.05159087f, 1832.35537170f, 1841.66534438f, 1850.98148244f,
+ 1860.30375965f, 1869.63214999f, 1878.96662767f, 1888.30716711f,
+ 1897.65374295f, 1907.00633003f, 1916.36490342f, 1925.72943838f,
+ 1935.09991037f, 1944.47629506f, 1953.85856831f, 1963.24670620f,
+ 1972.64068498f, 1982.04048108f, 1991.44607117f, 2000.85743204f,
+ 2010.27454072f, 2019.69737440f, 2029.12591044f, 2038.56012640f
+};
+
+const VP8LPrefixCode kPrefixEncodeCode[PREFIX_LOOKUP_IDX_MAX] = {
+ { 0, 0}, { 0, 0}, { 1, 0}, { 2, 0}, { 3, 0}, { 4, 1}, { 4, 1}, { 5, 1},
+ { 5, 1}, { 6, 2}, { 6, 2}, { 6, 2}, { 6, 2}, { 7, 2}, { 7, 2}, { 7, 2},
+ { 7, 2}, { 8, 3}, { 8, 3}, { 8, 3}, { 8, 3}, { 8, 3}, { 8, 3}, { 8, 3},
+ { 8, 3}, { 9, 3}, { 9, 3}, { 9, 3}, { 9, 3}, { 9, 3}, { 9, 3}, { 9, 3},
+ { 9, 3}, {10, 4}, {10, 4}, {10, 4}, {10, 4}, {10, 4}, {10, 4}, {10, 4},
+ {10, 4}, {10, 4}, {10, 4}, {10, 4}, {10, 4}, {10, 4}, {10, 4}, {10, 4},
+ {10, 4}, {11, 4}, {11, 4}, {11, 4}, {11, 4}, {11, 4}, {11, 4}, {11, 4},
+ {11, 4}, {11, 4}, {11, 4}, {11, 4}, {11, 4}, {11, 4}, {11, 4}, {11, 4},
+ {11, 4}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5},
+ {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5},
+ {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5},
+ {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5}, {12, 5},
+ {12, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5},
+ {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5},
+ {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5},
+ {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5}, {13, 5},
+ {13, 5}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6},
+ {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6},
+ {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6},
+ {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6},
+ {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6},
+ {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6},
+ {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6},
+ {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6}, {14, 6},
+ {14, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6},
+ {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6},
+ {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6},
+ {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6},
+ {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6},
+ {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6},
+ {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6},
+ {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6}, {15, 6},
+ {15, 6}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7},
+ {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7},
+ {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7},
+ {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7},
+ {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7},
+ {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7},
+ {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7},
+ {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7},
+ {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7},
+ {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7},
+ {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7},
+ {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7},
+ {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7},
+ {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7},
+ {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7},
+ {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7}, {16, 7},
+ {16, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7},
+ {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7},
+ {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7},
+ {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7},
+ {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7},
+ {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7},
+ {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7},
+ {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7},
+ {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7},
+ {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7},
+ {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7},
+ {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7},
+ {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7},
+ {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7},
+ {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7},
+ {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7}, {17, 7},
+};
+
+const uint8_t kPrefixEncodeExtraBitsValue[PREFIX_LOOKUP_IDX_MAX] = {
+ 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 2, 3, 0, 1, 2, 3,
+ 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
+ 127,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126
+};
+
+// The threshold till approximate version of log_2 can be used.
+// Practically, we can get rid of the call to log() as the two values match to
+// very high degree (the ratio of these two is 0.99999x).
+// Keeping a high threshold for now.
+#define APPROX_LOG_WITH_CORRECTION_MAX 65536
+#define APPROX_LOG_MAX 4096
+#define LOG_2_RECIPROCAL 1.44269504088896338700465094007086
+static float FastSLog2Slow(uint32_t v) {
+ assert(v >= LOG_LOOKUP_IDX_MAX);
+ if (v < APPROX_LOG_WITH_CORRECTION_MAX) {
+ int log_cnt = 0;
+ uint32_t y = 1;
+ int correction = 0;
+ const float v_f = (float)v;
+ const uint32_t orig_v = v;
+ do {
+ ++log_cnt;
+ v = v >> 1;
+ y = y << 1;
+ } while (v >= LOG_LOOKUP_IDX_MAX);
+ // vf = (2^log_cnt) * Xf; where y = 2^log_cnt and Xf < 256
+ // Xf = floor(Xf) * (1 + (v % y) / v)
+ // log2(Xf) = log2(floor(Xf)) + log2(1 + (v % y) / v)
+ // The correction factor: log(1 + d) ~ d; for very small d values, so
+ // log2(1 + (v % y) / v) ~ LOG_2_RECIPROCAL * (v % y)/v
+ // LOG_2_RECIPROCAL ~ 23/16
+ correction = (23 * (orig_v & (y - 1))) >> 4;
+ return v_f * (kLog2Table[v] + log_cnt) + correction;
+ } else {
+ return (float)(LOG_2_RECIPROCAL * v * log((double)v));
+ }
+}
+
+static float FastLog2Slow(uint32_t v) {
+ assert(v >= LOG_LOOKUP_IDX_MAX);
+ if (v < APPROX_LOG_WITH_CORRECTION_MAX) {
+ int log_cnt = 0;
+ uint32_t y = 1;
+ const uint32_t orig_v = v;
+ double log_2;
+ do {
+ ++log_cnt;
+ v = v >> 1;
+ y = y << 1;
+ } while (v >= LOG_LOOKUP_IDX_MAX);
+ log_2 = kLog2Table[v] + log_cnt;
+ if (orig_v >= APPROX_LOG_MAX) {
+ // Since the division is still expensive, add this correction factor only
+ // for large values of 'v'.
+ const int correction = (23 * (orig_v & (y - 1))) >> 4;
+ log_2 += (double)correction / orig_v;
+ }
+ return (float)log_2;
+ } else {
+ return (float)(LOG_2_RECIPROCAL * log((double)v));
+ }
+}
+
+// Mostly used to reduce code size + readability
+static WEBP_INLINE int GetMin(int a, int b) { return (a > b) ? b : a; }
+
+//------------------------------------------------------------------------------
+// Methods to calculate Entropy (Shannon).
+
+static float PredictionCostSpatial(const int counts[256], int weight_0,
+ double exp_val) {
+ const int significant_symbols = 256 >> 4;
+ const double exp_decay_factor = 0.6;
+ double bits = weight_0 * counts[0];
+ int i;
+ for (i = 1; i < significant_symbols; ++i) {
+ bits += exp_val * (counts[i] + counts[256 - i]);
+ exp_val *= exp_decay_factor;
+ }
+ return (float)(-0.1 * bits);
+}
+
+// Compute the combined Shanon's entropy for distribution {X} and {X+Y}
+static float CombinedShannonEntropy(const int X[256], const int Y[256]) {
+ int i;
+ double retval = 0.;
+ int sumX = 0, sumXY = 0;
+ for (i = 0; i < 256; ++i) {
+ const int x = X[i];
+ const int xy = x + Y[i];
+ if (x != 0) {
+ sumX += x;
+ retval -= VP8LFastSLog2(x);
+ sumXY += xy;
+ retval -= VP8LFastSLog2(xy);
+ } else if (xy != 0) {
+ sumXY += xy;
+ retval -= VP8LFastSLog2(xy);
+ }
+ }
+ retval += VP8LFastSLog2(sumX) + VP8LFastSLog2(sumXY);
+ return (float)retval;
+}
+
+static float PredictionCostSpatialHistogram(const int accumulated[4][256],
+ const int tile[4][256]) {
+ int i;
+ double retval = 0;
+ for (i = 0; i < 4; ++i) {
+ const double kExpValue = 0.94;
+ retval += PredictionCostSpatial(tile[i], 1, kExpValue);
+ retval += CombinedShannonEntropy(tile[i], accumulated[i]);
+ }
+ return (float)retval;
+}
+
+static WEBP_INLINE double BitsEntropyRefine(int nonzeros, int sum, int max_val,
+ double retval) {
+ double mix;
+ if (nonzeros < 5) {
+ if (nonzeros <= 1) {
+ return 0;
+ }
+ // Two symbols, they will be 0 and 1 in a Huffman code.
+ // Let's mix in a bit of entropy to favor good clustering when
+ // distributions of these are combined.
+ if (nonzeros == 2) {
+ return 0.99 * sum + 0.01 * retval;
+ }
+ // No matter what the entropy says, we cannot be better than min_limit
+ // with Huffman coding. I am mixing a bit of entropy into the
+ // min_limit since it produces much better (~0.5 %) compression results
+ // perhaps because of better entropy clustering.
+ if (nonzeros == 3) {
+ mix = 0.95;
+ } else {
+ mix = 0.7; // nonzeros == 4.
+ }
+ } else {
+ mix = 0.627;
+ }
+
+ {
+ double min_limit = 2 * sum - max_val;
+ min_limit = mix * min_limit + (1.0 - mix) * retval;
+ return (retval < min_limit) ? min_limit : retval;
+ }
+}
+
+// Returns the entropy for the symbols in the input array.
+// Also sets trivial_symbol to the code value, if the array has only one code
+// value. Otherwise, set it to VP8L_NON_TRIVIAL_SYM.
+double VP8LBitsEntropy(const uint32_t* const array, int n,
+ uint32_t* const trivial_symbol) {
+ double retval = 0.;
+ uint32_t sum = 0;
+ uint32_t nonzero_code = VP8L_NON_TRIVIAL_SYM;
+ int nonzeros = 0;
+ uint32_t max_val = 0;
+ int i;
+ for (i = 0; i < n; ++i) {
+ if (array[i] != 0) {
+ sum += array[i];
+ nonzero_code = i;
+ ++nonzeros;
+ retval -= VP8LFastSLog2(array[i]);
+ if (max_val < array[i]) {
+ max_val = array[i];
+ }
+ }
+ }
+ retval += VP8LFastSLog2(sum);
+ if (trivial_symbol != NULL) {
+ *trivial_symbol = (nonzeros == 1) ? nonzero_code : VP8L_NON_TRIVIAL_SYM;
+ }
+ return BitsEntropyRefine(nonzeros, sum, max_val, retval);
+}
+
+static double InitialHuffmanCost(void) {
+ // Small bias because Huffman code length is typically not stored in
+ // full length.
+ static const int kHuffmanCodeOfHuffmanCodeSize = CODE_LENGTH_CODES * 3;
+ static const double kSmallBias = 9.1;
+ return kHuffmanCodeOfHuffmanCodeSize - kSmallBias;
+}
+
+// Finalize the Huffman cost based on streak numbers and length type (<3 or >=3)
+static double FinalHuffmanCost(const VP8LStreaks* const stats) {
+ double retval = InitialHuffmanCost();
+ retval += stats->counts[0] * 1.5625 + 0.234375 * stats->streaks[0][1];
+ retval += stats->counts[1] * 2.578125 + 0.703125 * stats->streaks[1][1];
+ retval += 1.796875 * stats->streaks[0][0];
+ retval += 3.28125 * stats->streaks[1][0];
+ return retval;
+}
+
+// Trampolines
+static double HuffmanCost(const uint32_t* const population, int length) {
+ const VP8LStreaks stats = VP8LHuffmanCostCount(population, length);
+ return FinalHuffmanCost(&stats);
+}
+
+// Aggregated costs
+double VP8LPopulationCost(const uint32_t* const population, int length,
+ uint32_t* const trivial_sym) {
+ return
+ VP8LBitsEntropy(population, length, trivial_sym) +
+ HuffmanCost(population, length);
+}
+
+double VP8LGetCombinedEntropy(const uint32_t* const X,
+ const uint32_t* const Y, int length) {
+ double bits_entropy_combined;
+ double huffman_cost_combined;
+ int i;
+
+ // Bit entropy variables.
+ double retval = 0.;
+ int sum = 0;
+ int nonzeros = 0;
+ uint32_t max_val = 0;
+ int i_prev;
+ uint32_t xy;
+
+ // Huffman cost variables.
+ int streak = 0;
+ uint32_t xy_prev;
+ VP8LStreaks stats;
+ memset(&stats, 0, sizeof(stats));
+
+ // Treat the first value for the huffman cost: this is keeping the original
+ // behavior, even though there is no first streak.
+ // TODO(vrabaud): study proper behavior
+ xy = X[0] + Y[0];
+ ++stats.streaks[xy != 0][0];
+ xy_prev = xy;
+ i_prev = 0;
+
+ for (i = 1; i < length; ++i) {
+ xy = X[i] + Y[i];
+
+ // Process data by streaks for both bit entropy and huffman cost.
+ if (xy != xy_prev) {
+ streak = i - i_prev;
+
+ // Gather info for the bit entropy.
+ if (xy_prev != 0) {
+ sum += xy_prev * streak;
+ nonzeros += streak;
+ retval -= VP8LFastSLog2(xy_prev) * streak;
+ if (max_val < xy_prev) {
+ max_val = xy_prev;
+ }
+ }
+
+ // Gather info for the huffman cost.
+ stats.counts[xy != 0] += (streak > 3);
+ stats.streaks[xy != 0][(streak > 3)] += streak;
+
+ xy_prev = xy;
+ i_prev = i;
+ }
+ }
+
+ // Finish off the last streak for bit entropy.
+ if (xy != 0) {
+ streak = i - i_prev;
+ sum += xy * streak;
+ nonzeros += streak;
+ retval -= VP8LFastSLog2(xy) * streak;
+ if (max_val < xy) {
+ max_val = xy;
+ }
+ }
+ // Huffman cost is not updated with the last streak to keep original behavior.
+ // TODO(vrabaud): study proper behavior
+
+ retval += VP8LFastSLog2(sum);
+ bits_entropy_combined = BitsEntropyRefine(nonzeros, sum, max_val, retval);
+
+ huffman_cost_combined = FinalHuffmanCost(&stats);
+
+ return bits_entropy_combined + huffman_cost_combined;
+}
+
+// Estimates the Entropy + Huffman + other block overhead size cost.
+double VP8LHistogramEstimateBits(const VP8LHistogram* const p) {
+ return
+ VP8LPopulationCost(
+ p->literal_, VP8LHistogramNumCodes(p->palette_code_bits_), NULL)
+ + VP8LPopulationCost(p->red_, NUM_LITERAL_CODES, NULL)
+ + VP8LPopulationCost(p->blue_, NUM_LITERAL_CODES, NULL)
+ + VP8LPopulationCost(p->alpha_, NUM_LITERAL_CODES, NULL)
+ + VP8LPopulationCost(p->distance_, NUM_DISTANCE_CODES, NULL)
+ + VP8LExtraCost(p->literal_ + NUM_LITERAL_CODES, NUM_LENGTH_CODES)
+ + VP8LExtraCost(p->distance_, NUM_DISTANCE_CODES);
+}
+
+double VP8LHistogramEstimateBitsBulk(const VP8LHistogram* const p) {
+ return
+ VP8LBitsEntropy(p->literal_, VP8LHistogramNumCodes(p->palette_code_bits_),
+ NULL)
+ + VP8LBitsEntropy(p->red_, NUM_LITERAL_CODES, NULL)
+ + VP8LBitsEntropy(p->blue_, NUM_LITERAL_CODES, NULL)
+ + VP8LBitsEntropy(p->alpha_, NUM_LITERAL_CODES, NULL)
+ + VP8LBitsEntropy(p->distance_, NUM_DISTANCE_CODES, NULL)
+ + VP8LExtraCost(p->literal_ + NUM_LITERAL_CODES, NUM_LENGTH_CODES)
+ + VP8LExtraCost(p->distance_, NUM_DISTANCE_CODES);
+}
+
+static WEBP_INLINE void UpdateHisto(int histo_argb[4][256], uint32_t argb) {
+ ++histo_argb[0][argb >> 24];
+ ++histo_argb[1][(argb >> 16) & 0xff];
+ ++histo_argb[2][(argb >> 8) & 0xff];
+ ++histo_argb[3][argb & 0xff];
+}
+
+//------------------------------------------------------------------------------
+
+// Returns best predictor and updates the accumulated histogram.
+static int GetBestPredictorForTile(int width, int height,
+ int tile_x, int tile_y, int bits,
+ int accumulated[4][256],
+ const uint32_t* const argb_scratch) {
+ const int kNumPredModes = 14;
+ const int col_start = tile_x << bits;
+ const int row_start = tile_y << bits;
+ const int tile_size = 1 << bits;
+ const int max_y = GetMin(tile_size, height - row_start);
+ const int max_x = GetMin(tile_size, width - col_start);
+ float best_diff = MAX_DIFF_COST;
+ int best_mode = 0;
+ int mode;
+ int histo_stack_1[4][256];
+ int histo_stack_2[4][256];
+ // Need pointers to be able to swap arrays.
+ int (*histo_argb)[256] = histo_stack_1;
+ int (*best_histo)[256] = histo_stack_2;
+
+ int i, j;
+ for (mode = 0; mode < kNumPredModes; ++mode) {
+ const uint32_t* current_row = argb_scratch;
+ const VP8LPredictorFunc pred_func = VP8LPredictors[mode];
+ float cur_diff;
+ int y;
+ memset(histo_argb, 0, sizeof(histo_stack_1));
+ for (y = 0; y < max_y; ++y) {
+ int x;
+ const int row = row_start + y;
+ const uint32_t* const upper_row = current_row;
+ current_row = upper_row + width;
+ for (x = 0; x < max_x; ++x) {
+ const int col = col_start + x;
+ uint32_t predict;
+ if (row == 0) {
+ predict = (col == 0) ? ARGB_BLACK : current_row[col - 1]; // Left.
+ } else if (col == 0) {
+ predict = upper_row[col]; // Top.
+ } else {
+ predict = pred_func(current_row[col - 1], upper_row + col);
+ }
+ UpdateHisto(histo_argb, VP8LSubPixels(current_row[col], predict));
+ }
+ }
+ cur_diff = PredictionCostSpatialHistogram(
+ (const int (*)[256])accumulated, (const int (*)[256])histo_argb);
+ if (cur_diff < best_diff) {
+ int (*tmp)[256] = histo_argb;
+ histo_argb = best_histo;
+ best_histo = tmp;
+ best_diff = cur_diff;
+ best_mode = mode;
+ }
+ }
+
+ for (i = 0; i < 4; i++) {
+ for (j = 0; j < 256; j++) {
+ accumulated[i][j] += best_histo[i][j];
+ }
+ }
+
+ return best_mode;
+}
+
+static void CopyImageWithPrediction(int width, int height,
+ int bits, uint32_t* const modes,
+ uint32_t* const argb_scratch,
+ uint32_t* const argb) {
+ const int tiles_per_row = VP8LSubSampleSize(width, bits);
+ const int mask = (1 << bits) - 1;
+ // The row size is one pixel longer to allow the top right pixel to point to
+ // the leftmost pixel of the next row when at the right edge.
+ uint32_t* current_row = argb_scratch;
+ uint32_t* upper_row = argb_scratch + width + 1;
+ int y;
+ VP8LPredictorFunc pred_func = 0;
+
+ for (y = 0; y < height; ++y) {
+ int x;
+ uint32_t* tmp = upper_row;
+ upper_row = current_row;
+ current_row = tmp;
+ memcpy(current_row, argb + y * width, sizeof(*current_row) * width);
+ current_row[width] = (y + 1 < height) ? argb[(y + 1) * width] : ARGB_BLACK;
+ for (x = 0; x < width; ++x) {
+ uint32_t predict;
+ if ((x & mask) == 0) {
+ const int mode =
+ (modes[(y >> bits) * tiles_per_row + (x >> bits)] >> 8) & 0xff;
+ pred_func = VP8LPredictors[mode];
+ }
+ if (y == 0) {
+ predict = (x == 0) ? ARGB_BLACK : current_row[x - 1]; // Left.
+ } else if (x == 0) {
+ predict = upper_row[x]; // Top.
+ } else {
+ predict = pred_func(current_row[x - 1], upper_row + x);
+ }
+ argb[y * width + x] = VP8LSubPixels(current_row[x], predict);
+ }
+ }
+}
+
+void VP8LResidualImage(int width, int height, int bits, int low_effort,
+ uint32_t* const argb, uint32_t* const argb_scratch,
+ uint32_t* const image) {
+ const int max_tile_size = 1 << bits;
+ const int tiles_per_row = VP8LSubSampleSize(width, bits);
+ const int tiles_per_col = VP8LSubSampleSize(height, bits);
+ const int kPredLowEffort = 11;
+ uint32_t* const upper_row = argb_scratch;
+ uint32_t* const current_tile_rows = argb_scratch + width;
+ int tile_y;
+ int histo[4][256];
+ if (!low_effort) memset(histo, 0, sizeof(histo));
+ for (tile_y = 0; tile_y < tiles_per_col; ++tile_y) {
+ const int tile_y_offset = tile_y * max_tile_size;
+ const int this_tile_height =
+ (tile_y < tiles_per_col - 1) ? max_tile_size : height - tile_y_offset;
+ int tile_x;
+ if (tile_y > 0) {
+ memcpy(upper_row, current_tile_rows + (max_tile_size - 1) * width,
+ width * sizeof(*upper_row));
+ }
+ memcpy(current_tile_rows, &argb[tile_y_offset * width],
+ this_tile_height * width * sizeof(*current_tile_rows));
+ for (tile_x = 0; tile_x < tiles_per_row; ++tile_x) {
+ const int pred =
+ low_effort ? kPredLowEffort :
+ GetBestPredictorForTile(width, height,
+ tile_x, tile_y, bits,
+ (int (*)[256])histo,
+ argb_scratch);
+ image[tile_y * tiles_per_row + tile_x] = 0xff000000u | (pred << 8);
+ }
+ }
+
+ CopyImageWithPrediction(width, height, bits, image, argb_scratch, argb);
+}
+
+void VP8LSubtractGreenFromBlueAndRed_C(uint32_t* argb_data, int num_pixels) {
+ int i;
+ for (i = 0; i < num_pixels; ++i) {
+ const uint32_t argb = argb_data[i];
+ const uint32_t green = (argb >> 8) & 0xff;
+ const uint32_t new_r = (((argb >> 16) & 0xff) - green) & 0xff;
+ const uint32_t new_b = ((argb & 0xff) - green) & 0xff;
+ argb_data[i] = (argb & 0xff00ff00) | (new_r << 16) | new_b;
+ }
+}
+
+static WEBP_INLINE void MultipliersClear(VP8LMultipliers* const m) {
+ m->green_to_red_ = 0;
+ m->green_to_blue_ = 0;
+ m->red_to_blue_ = 0;
+}
+
+static WEBP_INLINE uint32_t ColorTransformDelta(int8_t color_pred,
+ int8_t color) {
+ return (uint32_t)((int)(color_pred) * color) >> 5;
+}
+
+static WEBP_INLINE void ColorCodeToMultipliers(uint32_t color_code,
+ VP8LMultipliers* const m) {
+ m->green_to_red_ = (color_code >> 0) & 0xff;
+ m->green_to_blue_ = (color_code >> 8) & 0xff;
+ m->red_to_blue_ = (color_code >> 16) & 0xff;
+}
+
+static WEBP_INLINE uint32_t MultipliersToColorCode(
+ const VP8LMultipliers* const m) {
+ return 0xff000000u |
+ ((uint32_t)(m->red_to_blue_) << 16) |
+ ((uint32_t)(m->green_to_blue_) << 8) |
+ m->green_to_red_;
+}
+
+void VP8LTransformColor_C(const VP8LMultipliers* const m, uint32_t* data,
+ int num_pixels) {
+ int i;
+ for (i = 0; i < num_pixels; ++i) {
+ const uint32_t argb = data[i];
+ const uint32_t green = argb >> 8;
+ const uint32_t red = argb >> 16;
+ uint32_t new_red = red;
+ uint32_t new_blue = argb;
+ new_red -= ColorTransformDelta(m->green_to_red_, green);
+ new_red &= 0xff;
+ new_blue -= ColorTransformDelta(m->green_to_blue_, green);
+ new_blue -= ColorTransformDelta(m->red_to_blue_, red);
+ new_blue &= 0xff;
+ data[i] = (argb & 0xff00ff00u) | (new_red << 16) | (new_blue);
+ }
+}
+
+static WEBP_INLINE uint8_t TransformColorRed(uint8_t green_to_red,
+ uint32_t argb) {
+ const uint32_t green = argb >> 8;
+ uint32_t new_red = argb >> 16;
+ new_red -= ColorTransformDelta(green_to_red, green);
+ return (new_red & 0xff);
+}
+
+static WEBP_INLINE uint8_t TransformColorBlue(uint8_t green_to_blue,
+ uint8_t red_to_blue,
+ uint32_t argb) {
+ const uint32_t green = argb >> 8;
+ const uint32_t red = argb >> 16;
+ uint8_t new_blue = argb;
+ new_blue -= ColorTransformDelta(green_to_blue, green);
+ new_blue -= ColorTransformDelta(red_to_blue, red);
+ return (new_blue & 0xff);
+}
+
+static float PredictionCostCrossColor(const int accumulated[256],
+ const int counts[256]) {
+ // Favor low entropy, locally and globally.
+ // Favor small absolute values for PredictionCostSpatial
+ static const double kExpValue = 2.4;
+ return CombinedShannonEntropy(counts, accumulated) +
+ PredictionCostSpatial(counts, 3, kExpValue);
+}
+
+void VP8LCollectColorRedTransforms_C(const uint32_t* argb, int stride,
+ int tile_width, int tile_height,
+ int green_to_red, int histo[]) {
+ while (tile_height-- > 0) {
+ int x;
+ for (x = 0; x < tile_width; ++x) {
+ ++histo[TransformColorRed(green_to_red, argb[x])];
+ }
+ argb += stride;
+ }
+}
+
+static float GetPredictionCostCrossColorRed(
+ const uint32_t* argb, int stride, int tile_width, int tile_height,
+ VP8LMultipliers prev_x, VP8LMultipliers prev_y, int green_to_red,
+ const int accumulated_red_histo[256]) {
+ int histo[256] = { 0 };
+ float cur_diff;
+
+ VP8LCollectColorRedTransforms(argb, stride, tile_width, tile_height,
+ green_to_red, histo);
+
+ cur_diff = PredictionCostCrossColor(accumulated_red_histo, histo);
+ if ((uint8_t)green_to_red == prev_x.green_to_red_) {
+ cur_diff -= 3; // favor keeping the areas locally similar
+ }
+ if ((uint8_t)green_to_red == prev_y.green_to_red_) {
+ cur_diff -= 3; // favor keeping the areas locally similar
+ }
+ if (green_to_red == 0) {
+ cur_diff -= 3;
+ }
+ return cur_diff;
+}
+
+static void GetBestGreenToRed(
+ const uint32_t* argb, int stride, int tile_width, int tile_height,
+ VP8LMultipliers prev_x, VP8LMultipliers prev_y, int quality,
+ const int accumulated_red_histo[256], VP8LMultipliers* const best_tx) {
+ const int kMaxIters = 4 + ((7 * quality) >> 8); // in range [4..6]
+ int green_to_red_best = 0;
+ int iter, offset;
+ float best_diff = GetPredictionCostCrossColorRed(
+ argb, stride, tile_width, tile_height, prev_x, prev_y,
+ green_to_red_best, accumulated_red_histo);
+ for (iter = 0; iter < kMaxIters; ++iter) {
+ // ColorTransformDelta is a 3.5 bit fixed point, so 32 is equal to
+ // one in color computation. Having initial delta here as 1 is sufficient
+ // to explore the range of (-2, 2).
+ const int delta = 32 >> iter;
+ // Try a negative and a positive delta from the best known value.
+ for (offset = -delta; offset <= delta; offset += 2 * delta) {
+ const int green_to_red_cur = offset + green_to_red_best;
+ const float cur_diff = GetPredictionCostCrossColorRed(
+ argb, stride, tile_width, tile_height, prev_x, prev_y,
+ green_to_red_cur, accumulated_red_histo);
+ if (cur_diff < best_diff) {
+ best_diff = cur_diff;
+ green_to_red_best = green_to_red_cur;
+ }
+ }
+ }
+ best_tx->green_to_red_ = green_to_red_best;
+}
+
+void VP8LCollectColorBlueTransforms_C(const uint32_t* argb, int stride,
+ int tile_width, int tile_height,
+ int green_to_blue, int red_to_blue,
+ int histo[]) {
+ while (tile_height-- > 0) {
+ int x;
+ for (x = 0; x < tile_width; ++x) {
+ ++histo[TransformColorBlue(green_to_blue, red_to_blue, argb[x])];
+ }
+ argb += stride;
+ }
+}
+
+static float GetPredictionCostCrossColorBlue(
+ const uint32_t* argb, int stride, int tile_width, int tile_height,
+ VP8LMultipliers prev_x, VP8LMultipliers prev_y,
+ int green_to_blue, int red_to_blue, const int accumulated_blue_histo[256]) {
+ int histo[256] = { 0 };
+ float cur_diff;
+
+ VP8LCollectColorBlueTransforms(argb, stride, tile_width, tile_height,
+ green_to_blue, red_to_blue, histo);
+
+ cur_diff = PredictionCostCrossColor(accumulated_blue_histo, histo);
+ if ((uint8_t)green_to_blue == prev_x.green_to_blue_) {
+ cur_diff -= 3; // favor keeping the areas locally similar
+ }
+ if ((uint8_t)green_to_blue == prev_y.green_to_blue_) {
+ cur_diff -= 3; // favor keeping the areas locally similar
+ }
+ if ((uint8_t)red_to_blue == prev_x.red_to_blue_) {
+ cur_diff -= 3; // favor keeping the areas locally similar
+ }
+ if ((uint8_t)red_to_blue == prev_y.red_to_blue_) {
+ cur_diff -= 3; // favor keeping the areas locally similar
+ }
+ if (green_to_blue == 0) {
+ cur_diff -= 3;
+ }
+ if (red_to_blue == 0) {
+ cur_diff -= 3;
+ }
+ return cur_diff;
+}
+
+#define kGreenRedToBlueNumAxis 8
+#define kGreenRedToBlueMaxIters 7
+static void GetBestGreenRedToBlue(
+ const uint32_t* argb, int stride, int tile_width, int tile_height,
+ VP8LMultipliers prev_x, VP8LMultipliers prev_y, int quality,
+ const int accumulated_blue_histo[256],
+ VP8LMultipliers* const best_tx) {
+ const int8_t offset[kGreenRedToBlueNumAxis][2] =
+ {{0, -1}, {0, 1}, {-1, 0}, {1, 0}, {-1, -1}, {-1, 1}, {1, -1}, {1, 1}};
+ const int8_t delta_lut[kGreenRedToBlueMaxIters] = { 16, 16, 8, 4, 2, 2, 2 };
+ const int iters =
+ (quality < 25) ? 1 : (quality > 50) ? kGreenRedToBlueMaxIters : 4;
+ int green_to_blue_best = 0;
+ int red_to_blue_best = 0;
+ int iter;
+ // Initial value at origin:
+ float best_diff = GetPredictionCostCrossColorBlue(
+ argb, stride, tile_width, tile_height, prev_x, prev_y,
+ green_to_blue_best, red_to_blue_best, accumulated_blue_histo);
+ for (iter = 0; iter < iters; ++iter) {
+ const int delta = delta_lut[iter];
+ int axis;
+ for (axis = 0; axis < kGreenRedToBlueNumAxis; ++axis) {
+ const int green_to_blue_cur =
+ offset[axis][0] * delta + green_to_blue_best;
+ const int red_to_blue_cur = offset[axis][1] * delta + red_to_blue_best;
+ const float cur_diff = GetPredictionCostCrossColorBlue(
+ argb, stride, tile_width, tile_height, prev_x, prev_y,
+ green_to_blue_cur, red_to_blue_cur, accumulated_blue_histo);
+ if (cur_diff < best_diff) {
+ best_diff = cur_diff;
+ green_to_blue_best = green_to_blue_cur;
+ red_to_blue_best = red_to_blue_cur;
+ }
+ if (quality < 25 && iter == 4) {
+ // Only axis aligned diffs for lower quality.
+ break; // next iter.
+ }
+ }
+ if (delta == 2 && green_to_blue_best == 0 && red_to_blue_best == 0) {
+ // Further iterations would not help.
+ break; // out of iter-loop.
+ }
+ }
+ best_tx->green_to_blue_ = green_to_blue_best;
+ best_tx->red_to_blue_ = red_to_blue_best;
+}
+#undef kGreenRedToBlueMaxIters
+#undef kGreenRedToBlueNumAxis
+
+static VP8LMultipliers GetBestColorTransformForTile(
+ int tile_x, int tile_y, int bits,
+ VP8LMultipliers prev_x,
+ VP8LMultipliers prev_y,
+ int quality, int xsize, int ysize,
+ const int accumulated_red_histo[256],
+ const int accumulated_blue_histo[256],
+ const uint32_t* const argb) {
+ const int max_tile_size = 1 << bits;
+ const int tile_y_offset = tile_y * max_tile_size;
+ const int tile_x_offset = tile_x * max_tile_size;
+ const int all_x_max = GetMin(tile_x_offset + max_tile_size, xsize);
+ const int all_y_max = GetMin(tile_y_offset + max_tile_size, ysize);
+ const int tile_width = all_x_max - tile_x_offset;
+ const int tile_height = all_y_max - tile_y_offset;
+ const uint32_t* const tile_argb = argb + tile_y_offset * xsize
+ + tile_x_offset;
+ VP8LMultipliers best_tx;
+ MultipliersClear(&best_tx);
+
+ GetBestGreenToRed(tile_argb, xsize, tile_width, tile_height,
+ prev_x, prev_y, quality, accumulated_red_histo, &best_tx);
+ GetBestGreenRedToBlue(tile_argb, xsize, tile_width, tile_height,
+ prev_x, prev_y, quality, accumulated_blue_histo,
+ &best_tx);
+ return best_tx;
+}
+
+static void CopyTileWithColorTransform(int xsize, int ysize,
+ int tile_x, int tile_y,
+ int max_tile_size,
+ VP8LMultipliers color_transform,
+ uint32_t* argb) {
+ const int xscan = GetMin(max_tile_size, xsize - tile_x);
+ int yscan = GetMin(max_tile_size, ysize - tile_y);
+ argb += tile_y * xsize + tile_x;
+ while (yscan-- > 0) {
+ VP8LTransformColor(&color_transform, argb, xscan);
+ argb += xsize;
+ }
+}
+
+void VP8LColorSpaceTransform(int width, int height, int bits, int quality,
+ uint32_t* const argb, uint32_t* image) {
+ const int max_tile_size = 1 << bits;
+ const int tile_xsize = VP8LSubSampleSize(width, bits);
+ const int tile_ysize = VP8LSubSampleSize(height, bits);
+ int accumulated_red_histo[256] = { 0 };
+ int accumulated_blue_histo[256] = { 0 };
+ int tile_x, tile_y;
+ VP8LMultipliers prev_x, prev_y;
+ MultipliersClear(&prev_y);
+ MultipliersClear(&prev_x);
+ for (tile_y = 0; tile_y < tile_ysize; ++tile_y) {
+ for (tile_x = 0; tile_x < tile_xsize; ++tile_x) {
+ int y;
+ const int tile_x_offset = tile_x * max_tile_size;
+ const int tile_y_offset = tile_y * max_tile_size;
+ const int all_x_max = GetMin(tile_x_offset + max_tile_size, width);
+ const int all_y_max = GetMin(tile_y_offset + max_tile_size, height);
+ const int offset = tile_y * tile_xsize + tile_x;
+ if (tile_y != 0) {
+ ColorCodeToMultipliers(image[offset - tile_xsize], &prev_y);
+ }
+ prev_x = GetBestColorTransformForTile(tile_x, tile_y, bits,
+ prev_x, prev_y,
+ quality, width, height,
+ accumulated_red_histo,
+ accumulated_blue_histo,
+ argb);
+ image[offset] = MultipliersToColorCode(&prev_x);
+ CopyTileWithColorTransform(width, height, tile_x_offset, tile_y_offset,
+ max_tile_size, prev_x, argb);
+
+ // Gather accumulated histogram data.
+ for (y = tile_y_offset; y < all_y_max; ++y) {
+ int ix = y * width + tile_x_offset;
+ const int ix_end = ix + all_x_max - tile_x_offset;
+ for (; ix < ix_end; ++ix) {
+ const uint32_t pix = argb[ix];
+ if (ix >= 2 &&
+ pix == argb[ix - 2] &&
+ pix == argb[ix - 1]) {
+ continue; // repeated pixels are handled by backward references
+ }
+ if (ix >= width + 2 &&
+ argb[ix - 2] == argb[ix - width - 2] &&
+ argb[ix - 1] == argb[ix - width - 1] &&
+ pix == argb[ix - width]) {
+ continue; // repeated pixels are handled by backward references
+ }
+ ++accumulated_red_histo[(pix >> 16) & 0xff];
+ ++accumulated_blue_histo[(pix >> 0) & 0xff];
+ }
+ }
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+// Bundles multiple (1, 2, 4 or 8) pixels into a single pixel.
+void VP8LBundleColorMap(const uint8_t* const row, int width,
+ int xbits, uint32_t* const dst) {
+ int x;
+ if (xbits > 0) {
+ const int bit_depth = 1 << (3 - xbits);
+ const int mask = (1 << xbits) - 1;
+ uint32_t code = 0xff000000;
+ for (x = 0; x < width; ++x) {
+ const int xsub = x & mask;
+ if (xsub == 0) {
+ code = 0xff000000;
+ }
+ code |= row[x] << (8 + bit_depth * xsub);
+ dst[x >> xbits] = code;
+ }
+ } else {
+ for (x = 0; x < width; ++x) dst[x] = 0xff000000 | (row[x] << 8);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+static double ExtraCost(const uint32_t* population, int length) {
+ int i;
+ double cost = 0.;
+ for (i = 2; i < length - 2; ++i) cost += (i >> 1) * population[i + 2];
+ return cost;
+}
+
+static double ExtraCostCombined(const uint32_t* X, const uint32_t* Y,
+ int length) {
+ int i;
+ double cost = 0.;
+ for (i = 2; i < length - 2; ++i) {
+ const int xy = X[i + 2] + Y[i + 2];
+ cost += (i >> 1) * xy;
+ }
+ return cost;
+}
+
+// Returns the various RLE counts
+static VP8LStreaks HuffmanCostCount(const uint32_t* population, int length) {
+ int i;
+ int streak = 0;
+ VP8LStreaks stats;
+ memset(&stats, 0, sizeof(stats));
+ for (i = 0; i < length - 1; ++i) {
+ ++streak;
+ if (population[i] == population[i + 1]) {
+ continue;
+ }
+ stats.counts[population[i] != 0] += (streak > 3);
+ stats.streaks[population[i] != 0][(streak > 3)] += streak;
+ streak = 0;
+ }
+ ++streak;
+ stats.counts[population[i] != 0] += (streak > 3);
+ stats.streaks[population[i] != 0][(streak > 3)] += streak;
+ return stats;
+}
+
+//------------------------------------------------------------------------------
+
+static void HistogramAdd(const VP8LHistogram* const a,
+ const VP8LHistogram* const b,
+ VP8LHistogram* const out) {
+ int i;
+ const int literal_size = VP8LHistogramNumCodes(a->palette_code_bits_);
+ assert(a->palette_code_bits_ == b->palette_code_bits_);
+ if (b != out) {
+ for (i = 0; i < literal_size; ++i) {
+ out->literal_[i] = a->literal_[i] + b->literal_[i];
+ }
+ for (i = 0; i < NUM_DISTANCE_CODES; ++i) {
+ out->distance_[i] = a->distance_[i] + b->distance_[i];
+ }
+ for (i = 0; i < NUM_LITERAL_CODES; ++i) {
+ out->red_[i] = a->red_[i] + b->red_[i];
+ out->blue_[i] = a->blue_[i] + b->blue_[i];
+ out->alpha_[i] = a->alpha_[i] + b->alpha_[i];
+ }
+ } else {
+ for (i = 0; i < literal_size; ++i) {
+ out->literal_[i] += a->literal_[i];
+ }
+ for (i = 0; i < NUM_DISTANCE_CODES; ++i) {
+ out->distance_[i] += a->distance_[i];
+ }
+ for (i = 0; i < NUM_LITERAL_CODES; ++i) {
+ out->red_[i] += a->red_[i];
+ out->blue_[i] += a->blue_[i];
+ out->alpha_[i] += a->alpha_[i];
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+
+VP8LProcessBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed;
+
+VP8LTransformColorFunc VP8LTransformColor;
+
+VP8LCollectColorBlueTransformsFunc VP8LCollectColorBlueTransforms;
+VP8LCollectColorRedTransformsFunc VP8LCollectColorRedTransforms;
+
+VP8LFastLog2SlowFunc VP8LFastLog2Slow;
+VP8LFastLog2SlowFunc VP8LFastSLog2Slow;
+
+VP8LCostFunc VP8LExtraCost;
+VP8LCostCombinedFunc VP8LExtraCostCombined;
+
+VP8LCostCountFunc VP8LHuffmanCostCount;
+
+VP8LHistogramAddFunc VP8LHistogramAdd;
+
+extern void VP8LEncDspInitSSE2(void);
+extern void VP8LEncDspInitSSE41(void);
+extern void VP8LEncDspInitNEON(void);
+extern void VP8LEncDspInitMIPS32(void);
+extern void VP8LEncDspInitMIPSdspR2(void);
+
+static volatile VP8CPUInfo lossless_enc_last_cpuinfo_used =
+ (VP8CPUInfo)&lossless_enc_last_cpuinfo_used;
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInit(void) {
+ if (lossless_enc_last_cpuinfo_used == VP8GetCPUInfo) return;
+
+ VP8LDspInit();
+
+ VP8LSubtractGreenFromBlueAndRed = VP8LSubtractGreenFromBlueAndRed_C;
+
+ VP8LTransformColor = VP8LTransformColor_C;
+
+ VP8LCollectColorBlueTransforms = VP8LCollectColorBlueTransforms_C;
+ VP8LCollectColorRedTransforms = VP8LCollectColorRedTransforms_C;
+
+ VP8LFastLog2Slow = FastLog2Slow;
+ VP8LFastSLog2Slow = FastSLog2Slow;
+
+ VP8LExtraCost = ExtraCost;
+ VP8LExtraCostCombined = ExtraCostCombined;
+
+ VP8LHuffmanCostCount = HuffmanCostCount;
+
+ VP8LHistogramAdd = HistogramAdd;
+
+ // If defined, use CPUInfo() to overwrite some pointers with faster versions.
+ if (VP8GetCPUInfo != NULL) {
+#if defined(WEBP_USE_SSE2)
+ if (VP8GetCPUInfo(kSSE2)) {
+ VP8LEncDspInitSSE2();
+#if defined(WEBP_USE_SSE41)
+ if (VP8GetCPUInfo(kSSE4_1)) {
+ VP8LEncDspInitSSE41();
+ }
+#endif
+ }
+#endif
+#if defined(WEBP_USE_NEON)
+ if (VP8GetCPUInfo(kNEON)) {
+ VP8LEncDspInitNEON();
+ }
+#endif
+#if defined(WEBP_USE_MIPS32)
+ if (VP8GetCPUInfo(kMIPS32)) {
+ VP8LEncDspInitMIPS32();
+ }
+#endif
+#if defined(WEBP_USE_MIPS_DSP_R2)
+ if (VP8GetCPUInfo(kMIPSdspR2)) {
+ VP8LEncDspInitMIPSdspR2();
+ }
+#endif
+ }
+ lossless_enc_last_cpuinfo_used = VP8GetCPUInfo;
+}
+
+//------------------------------------------------------------------------------
diff --git a/drivers/webp/dsp/lossless_enc_mips32.c b/drivers/webp/dsp/lossless_enc_mips32.c
new file mode 100644
index 0000000000..0468a5aac2
--- /dev/null
+++ b/drivers/webp/dsp/lossless_enc_mips32.c
@@ -0,0 +1,417 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// MIPS version of lossless functions
+//
+// Author(s): Djordje Pesut (djordje.pesut@imgtec.com)
+// Jovan Zelincevic (jovan.zelincevic@imgtec.com)
+
+#include "./dsp.h"
+#include "./lossless.h"
+
+#if defined(WEBP_USE_MIPS32)
+
+#include <assert.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define APPROX_LOG_WITH_CORRECTION_MAX 65536
+#define APPROX_LOG_MAX 4096
+#define LOG_2_RECIPROCAL 1.44269504088896338700465094007086
+
+static float FastSLog2Slow(uint32_t v) {
+ assert(v >= LOG_LOOKUP_IDX_MAX);
+ if (v < APPROX_LOG_WITH_CORRECTION_MAX) {
+ uint32_t log_cnt, y, correction;
+ const int c24 = 24;
+ const float v_f = (float)v;
+ uint32_t temp;
+
+ // Xf = 256 = 2^8
+ // log_cnt is index of leading one in upper 24 bits
+ __asm__ volatile(
+ "clz %[log_cnt], %[v] \n\t"
+ "addiu %[y], $zero, 1 \n\t"
+ "subu %[log_cnt], %[c24], %[log_cnt] \n\t"
+ "sllv %[y], %[y], %[log_cnt] \n\t"
+ "srlv %[temp], %[v], %[log_cnt] \n\t"
+ : [log_cnt]"=&r"(log_cnt), [y]"=&r"(y),
+ [temp]"=r"(temp)
+ : [c24]"r"(c24), [v]"r"(v)
+ );
+
+ // vf = (2^log_cnt) * Xf; where y = 2^log_cnt and Xf < 256
+ // Xf = floor(Xf) * (1 + (v % y) / v)
+ // log2(Xf) = log2(floor(Xf)) + log2(1 + (v % y) / v)
+ // The correction factor: log(1 + d) ~ d; for very small d values, so
+ // log2(1 + (v % y) / v) ~ LOG_2_RECIPROCAL * (v % y)/v
+ // LOG_2_RECIPROCAL ~ 23/16
+
+ // (v % y) = (v % 2^log_cnt) = v & (2^log_cnt - 1)
+ correction = (23 * (v & (y - 1))) >> 4;
+ return v_f * (kLog2Table[temp] + log_cnt) + correction;
+ } else {
+ return (float)(LOG_2_RECIPROCAL * v * log((double)v));
+ }
+}
+
+static float FastLog2Slow(uint32_t v) {
+ assert(v >= LOG_LOOKUP_IDX_MAX);
+ if (v < APPROX_LOG_WITH_CORRECTION_MAX) {
+ uint32_t log_cnt, y;
+ const int c24 = 24;
+ double log_2;
+ uint32_t temp;
+
+ __asm__ volatile(
+ "clz %[log_cnt], %[v] \n\t"
+ "addiu %[y], $zero, 1 \n\t"
+ "subu %[log_cnt], %[c24], %[log_cnt] \n\t"
+ "sllv %[y], %[y], %[log_cnt] \n\t"
+ "srlv %[temp], %[v], %[log_cnt] \n\t"
+ : [log_cnt]"=&r"(log_cnt), [y]"=&r"(y),
+ [temp]"=r"(temp)
+ : [c24]"r"(c24), [v]"r"(v)
+ );
+
+ log_2 = kLog2Table[temp] + log_cnt;
+ if (v >= APPROX_LOG_MAX) {
+ // Since the division is still expensive, add this correction factor only
+ // for large values of 'v'.
+
+ const uint32_t correction = (23 * (v & (y - 1))) >> 4;
+ log_2 += (double)correction / v;
+ }
+ return (float)log_2;
+ } else {
+ return (float)(LOG_2_RECIPROCAL * log((double)v));
+ }
+}
+
+// C version of this function:
+// int i = 0;
+// int64_t cost = 0;
+// const uint32_t* pop = &population[4];
+// const uint32_t* LoopEnd = &population[length];
+// while (pop != LoopEnd) {
+// ++i;
+// cost += i * *pop;
+// cost += i * *(pop + 1);
+// pop += 2;
+// }
+// return (double)cost;
+static double ExtraCost(const uint32_t* const population, int length) {
+ int i, temp0, temp1;
+ const uint32_t* pop = &population[4];
+ const uint32_t* const LoopEnd = &population[length];
+
+ __asm__ volatile(
+ "mult $zero, $zero \n\t"
+ "xor %[i], %[i], %[i] \n\t"
+ "beq %[pop], %[LoopEnd], 2f \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[pop]) \n\t"
+ "lw %[temp1], 4(%[pop]) \n\t"
+ "addiu %[i], %[i], 1 \n\t"
+ "addiu %[pop], %[pop], 8 \n\t"
+ "madd %[i], %[temp0] \n\t"
+ "madd %[i], %[temp1] \n\t"
+ "bne %[pop], %[LoopEnd], 1b \n\t"
+ "2: \n\t"
+ "mfhi %[temp0] \n\t"
+ "mflo %[temp1] \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [i]"=&r"(i), [pop]"+r"(pop)
+ : [LoopEnd]"r"(LoopEnd)
+ : "memory", "hi", "lo"
+ );
+
+ return (double)((int64_t)temp0 << 32 | temp1);
+}
+
+// C version of this function:
+// int i = 0;
+// int64_t cost = 0;
+// const uint32_t* pX = &X[4];
+// const uint32_t* pY = &Y[4];
+// const uint32_t* LoopEnd = &X[length];
+// while (pX != LoopEnd) {
+// const uint32_t xy0 = *pX + *pY;
+// const uint32_t xy1 = *(pX + 1) + *(pY + 1);
+// ++i;
+// cost += i * xy0;
+// cost += i * xy1;
+// pX += 2;
+// pY += 2;
+// }
+// return (double)cost;
+static double ExtraCostCombined(const uint32_t* const X,
+ const uint32_t* const Y, int length) {
+ int i, temp0, temp1, temp2, temp3;
+ const uint32_t* pX = &X[4];
+ const uint32_t* pY = &Y[4];
+ const uint32_t* const LoopEnd = &X[length];
+
+ __asm__ volatile(
+ "mult $zero, $zero \n\t"
+ "xor %[i], %[i], %[i] \n\t"
+ "beq %[pX], %[LoopEnd], 2f \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[pX]) \n\t"
+ "lw %[temp1], 0(%[pY]) \n\t"
+ "lw %[temp2], 4(%[pX]) \n\t"
+ "lw %[temp3], 4(%[pY]) \n\t"
+ "addiu %[i], %[i], 1 \n\t"
+ "addu %[temp0], %[temp0], %[temp1] \n\t"
+ "addu %[temp2], %[temp2], %[temp3] \n\t"
+ "addiu %[pX], %[pX], 8 \n\t"
+ "addiu %[pY], %[pY], 8 \n\t"
+ "madd %[i], %[temp0] \n\t"
+ "madd %[i], %[temp2] \n\t"
+ "bne %[pX], %[LoopEnd], 1b \n\t"
+ "2: \n\t"
+ "mfhi %[temp0] \n\t"
+ "mflo %[temp1] \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
+ [i]"=&r"(i), [pX]"+r"(pX), [pY]"+r"(pY)
+ : [LoopEnd]"r"(LoopEnd)
+ : "memory", "hi", "lo"
+ );
+
+ return (double)((int64_t)temp0 << 32 | temp1);
+}
+
+#define HUFFMAN_COST_PASS \
+ __asm__ volatile( \
+ "sll %[temp1], %[temp0], 3 \n\t" \
+ "addiu %[temp3], %[streak], -3 \n\t" \
+ "addu %[temp2], %[pstreaks], %[temp1] \n\t" \
+ "blez %[temp3], 1f \n\t" \
+ "srl %[temp1], %[temp1], 1 \n\t" \
+ "addu %[temp3], %[pcnts], %[temp1] \n\t" \
+ "lw %[temp0], 4(%[temp2]) \n\t" \
+ "lw %[temp1], 0(%[temp3]) \n\t" \
+ "addu %[temp0], %[temp0], %[streak] \n\t" \
+ "addiu %[temp1], %[temp1], 1 \n\t" \
+ "sw %[temp0], 4(%[temp2]) \n\t" \
+ "sw %[temp1], 0(%[temp3]) \n\t" \
+ "b 2f \n\t" \
+ "1: \n\t" \
+ "lw %[temp0], 0(%[temp2]) \n\t" \
+ "addu %[temp0], %[temp0], %[streak] \n\t" \
+ "sw %[temp0], 0(%[temp2]) \n\t" \
+ "2: \n\t" \
+ : [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), \
+ [temp3]"=&r"(temp3), [temp0]"+r"(temp0) \
+ : [pstreaks]"r"(pstreaks), [pcnts]"r"(pcnts), \
+ [streak]"r"(streak) \
+ : "memory" \
+ );
+
+// Returns the various RLE counts
+static VP8LStreaks HuffmanCostCount(const uint32_t* population, int length) {
+ int i;
+ int streak = 0;
+ VP8LStreaks stats;
+ int* const pstreaks = &stats.streaks[0][0];
+ int* const pcnts = &stats.counts[0];
+ int temp0, temp1, temp2, temp3;
+ memset(&stats, 0, sizeof(stats));
+ for (i = 0; i < length - 1; ++i) {
+ ++streak;
+ if (population[i] == population[i + 1]) {
+ continue;
+ }
+ temp0 = (population[i] != 0);
+ HUFFMAN_COST_PASS
+ streak = 0;
+ }
+ ++streak;
+ temp0 = (population[i] != 0);
+ HUFFMAN_COST_PASS
+
+ return stats;
+}
+
+static VP8LStreaks HuffmanCostCombinedCount(const uint32_t* X,
+ const uint32_t* Y, int length) {
+ int i;
+ int streak = 0;
+ uint32_t xy_prev = 0xffffffff;
+ VP8LStreaks stats;
+ int* const pstreaks = &stats.streaks[0][0];
+ int* const pcnts = &stats.counts[0];
+ int temp0, temp1, temp2, temp3;
+ memset(&stats, 0, sizeof(stats));
+ for (i = 0; i < length; ++i) {
+ const uint32_t xy = X[i] + Y[i];
+ ++streak;
+ if (xy != xy_prev) {
+ temp0 = (xy != 0);
+ HUFFMAN_COST_PASS
+ streak = 0;
+ xy_prev = xy;
+ }
+ }
+ return stats;
+}
+
+#define ASM_START \
+ __asm__ volatile( \
+ ".set push \n\t" \
+ ".set at \n\t" \
+ ".set macro \n\t" \
+ "1: \n\t"
+
+// P2 = P0 + P1
+// A..D - offsets
+// E - temp variable to tell macro
+// if pointer should be incremented
+// literal_ and successive histograms could be unaligned
+// so we must use ulw and usw
+#define ADD_TO_OUT(A, B, C, D, E, P0, P1, P2) \
+ "ulw %[temp0], " #A "(%[" #P0 "]) \n\t" \
+ "ulw %[temp1], " #B "(%[" #P0 "]) \n\t" \
+ "ulw %[temp2], " #C "(%[" #P0 "]) \n\t" \
+ "ulw %[temp3], " #D "(%[" #P0 "]) \n\t" \
+ "ulw %[temp4], " #A "(%[" #P1 "]) \n\t" \
+ "ulw %[temp5], " #B "(%[" #P1 "]) \n\t" \
+ "ulw %[temp6], " #C "(%[" #P1 "]) \n\t" \
+ "ulw %[temp7], " #D "(%[" #P1 "]) \n\t" \
+ "addu %[temp4], %[temp4], %[temp0] \n\t" \
+ "addu %[temp5], %[temp5], %[temp1] \n\t" \
+ "addu %[temp6], %[temp6], %[temp2] \n\t" \
+ "addu %[temp7], %[temp7], %[temp3] \n\t" \
+ "addiu %[" #P0 "], %[" #P0 "], 16 \n\t" \
+ ".if " #E " == 1 \n\t" \
+ "addiu %[" #P1 "], %[" #P1 "], 16 \n\t" \
+ ".endif \n\t" \
+ "usw %[temp4], " #A "(%[" #P2 "]) \n\t" \
+ "usw %[temp5], " #B "(%[" #P2 "]) \n\t" \
+ "usw %[temp6], " #C "(%[" #P2 "]) \n\t" \
+ "usw %[temp7], " #D "(%[" #P2 "]) \n\t" \
+ "addiu %[" #P2 "], %[" #P2 "], 16 \n\t" \
+ "bne %[" #P0 "], %[LoopEnd], 1b \n\t" \
+ ".set pop \n\t" \
+
+#define ASM_END_COMMON_0 \
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), \
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), \
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), \
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7), \
+ [pa]"+r"(pa), [pout]"+r"(pout)
+
+#define ASM_END_COMMON_1 \
+ : [LoopEnd]"r"(LoopEnd) \
+ : "memory", "at" \
+ );
+
+#define ASM_END_0 \
+ ASM_END_COMMON_0 \
+ , [pb]"+r"(pb) \
+ ASM_END_COMMON_1
+
+#define ASM_END_1 \
+ ASM_END_COMMON_0 \
+ ASM_END_COMMON_1
+
+#define ADD_VECTOR(A, B, OUT, SIZE, EXTRA_SIZE) do { \
+ const uint32_t* pa = (const uint32_t*)(A); \
+ const uint32_t* pb = (const uint32_t*)(B); \
+ uint32_t* pout = (uint32_t*)(OUT); \
+ const uint32_t* const LoopEnd = pa + (SIZE); \
+ assert((SIZE) % 4 == 0); \
+ ASM_START \
+ ADD_TO_OUT(0, 4, 8, 12, 1, pa, pb, pout) \
+ ASM_END_0 \
+ if ((EXTRA_SIZE) > 0) { \
+ const int last = (EXTRA_SIZE); \
+ int i; \
+ for (i = 0; i < last; ++i) pout[i] = pa[i] + pb[i]; \
+ } \
+} while (0)
+
+#define ADD_VECTOR_EQ(A, OUT, SIZE, EXTRA_SIZE) do { \
+ const uint32_t* pa = (const uint32_t*)(A); \
+ uint32_t* pout = (uint32_t*)(OUT); \
+ const uint32_t* const LoopEnd = pa + (SIZE); \
+ assert((SIZE) % 4 == 0); \
+ ASM_START \
+ ADD_TO_OUT(0, 4, 8, 12, 0, pa, pout, pout) \
+ ASM_END_1 \
+ if ((EXTRA_SIZE) > 0) { \
+ const int last = (EXTRA_SIZE); \
+ int i; \
+ for (i = 0; i < last; ++i) pout[i] += pa[i]; \
+ } \
+} while (0)
+
+static void HistogramAdd(const VP8LHistogram* const a,
+ const VP8LHistogram* const b,
+ VP8LHistogram* const out) {
+ uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+ const int extra_cache_size = VP8LHistogramNumCodes(a->palette_code_bits_)
+ - (NUM_LITERAL_CODES + NUM_LENGTH_CODES);
+ assert(a->palette_code_bits_ == b->palette_code_bits_);
+
+ if (b != out) {
+ ADD_VECTOR(a->literal_, b->literal_, out->literal_,
+ NUM_LITERAL_CODES + NUM_LENGTH_CODES, extra_cache_size);
+ ADD_VECTOR(a->distance_, b->distance_, out->distance_,
+ NUM_DISTANCE_CODES, 0);
+ ADD_VECTOR(a->red_, b->red_, out->red_, NUM_LITERAL_CODES, 0);
+ ADD_VECTOR(a->blue_, b->blue_, out->blue_, NUM_LITERAL_CODES, 0);
+ ADD_VECTOR(a->alpha_, b->alpha_, out->alpha_, NUM_LITERAL_CODES, 0);
+ } else {
+ ADD_VECTOR_EQ(a->literal_, out->literal_,
+ NUM_LITERAL_CODES + NUM_LENGTH_CODES, extra_cache_size);
+ ADD_VECTOR_EQ(a->distance_, out->distance_, NUM_DISTANCE_CODES, 0);
+ ADD_VECTOR_EQ(a->red_, out->red_, NUM_LITERAL_CODES, 0);
+ ADD_VECTOR_EQ(a->blue_, out->blue_, NUM_LITERAL_CODES, 0);
+ ADD_VECTOR_EQ(a->alpha_, out->alpha_, NUM_LITERAL_CODES, 0);
+ }
+}
+
+#undef ADD_VECTOR_EQ
+#undef ADD_VECTOR
+#undef ASM_END_1
+#undef ASM_END_0
+#undef ASM_END_COMMON_1
+#undef ASM_END_COMMON_0
+#undef ADD_TO_OUT
+#undef ASM_START
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8LEncDspInitMIPS32(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitMIPS32(void) {
+ VP8LFastSLog2Slow = FastSLog2Slow;
+ VP8LFastLog2Slow = FastLog2Slow;
+ VP8LExtraCost = ExtraCost;
+ VP8LExtraCostCombined = ExtraCostCombined;
+ VP8LHuffmanCostCount = HuffmanCostCount;
+// TODO(mips team): rewrite VP8LGetCombinedEntropy (which used to use
+// HuffmanCostCombinedCount) with MIPS optimizations
+#if 0
+ VP8LHuffmanCostCombinedCount = HuffmanCostCombinedCount;
+#else
+ (void)HuffmanCostCombinedCount;
+#endif
+ VP8LHistogramAdd = HistogramAdd;
+}
+
+#else // !WEBP_USE_MIPS32
+
+WEBP_DSP_INIT_STUB(VP8LEncDspInitMIPS32)
+
+#endif // WEBP_USE_MIPS32
diff --git a/drivers/webp/dsp/lossless_enc_mips_dsp_r2.c b/drivers/webp/dsp/lossless_enc_mips_dsp_r2.c
new file mode 100644
index 0000000000..0abf3c4f36
--- /dev/null
+++ b/drivers/webp/dsp/lossless_enc_mips_dsp_r2.c
@@ -0,0 +1,275 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Image transform methods for lossless encoder.
+//
+// Author(s): Djordje Pesut (djordje.pesut@imgtec.com)
+// Jovan Zelincevic (jovan.zelincevic@imgtec.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_MIPS_DSP_R2)
+
+#include "./lossless.h"
+
+static void SubtractGreenFromBlueAndRed(uint32_t* argb_data,
+ int num_pixels) {
+ uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+ uint32_t* const p_loop1_end = argb_data + (num_pixels & ~3);
+ uint32_t* const p_loop2_end = p_loop1_end + (num_pixels & 3);
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "beq %[argb_data], %[p_loop1_end], 3f \n\t"
+ " nop \n\t"
+ "0: \n\t"
+ "lw %[temp0], 0(%[argb_data]) \n\t"
+ "lw %[temp1], 4(%[argb_data]) \n\t"
+ "lw %[temp2], 8(%[argb_data]) \n\t"
+ "lw %[temp3], 12(%[argb_data]) \n\t"
+ "ext %[temp4], %[temp0], 8, 8 \n\t"
+ "ext %[temp5], %[temp1], 8, 8 \n\t"
+ "ext %[temp6], %[temp2], 8, 8 \n\t"
+ "ext %[temp7], %[temp3], 8, 8 \n\t"
+ "addiu %[argb_data], %[argb_data], 16 \n\t"
+ "replv.ph %[temp4], %[temp4] \n\t"
+ "replv.ph %[temp5], %[temp5] \n\t"
+ "replv.ph %[temp6], %[temp6] \n\t"
+ "replv.ph %[temp7], %[temp7] \n\t"
+ "subu.qb %[temp0], %[temp0], %[temp4] \n\t"
+ "subu.qb %[temp1], %[temp1], %[temp5] \n\t"
+ "subu.qb %[temp2], %[temp2], %[temp6] \n\t"
+ "subu.qb %[temp3], %[temp3], %[temp7] \n\t"
+ "sw %[temp0], -16(%[argb_data]) \n\t"
+ "sw %[temp1], -12(%[argb_data]) \n\t"
+ "sw %[temp2], -8(%[argb_data]) \n\t"
+ "bne %[argb_data], %[p_loop1_end], 0b \n\t"
+ " sw %[temp3], -4(%[argb_data]) \n\t"
+ "3: \n\t"
+ "beq %[argb_data], %[p_loop2_end], 2f \n\t"
+ " nop \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[argb_data]) \n\t"
+ "addiu %[argb_data], %[argb_data], 4 \n\t"
+ "ext %[temp4], %[temp0], 8, 8 \n\t"
+ "replv.ph %[temp4], %[temp4] \n\t"
+ "subu.qb %[temp0], %[temp0], %[temp4] \n\t"
+ "bne %[argb_data], %[p_loop2_end], 1b \n\t"
+ " sw %[temp0], -4(%[argb_data]) \n\t"
+ "2: \n\t"
+ ".set pop \n\t"
+ : [argb_data]"+&r"(argb_data), [temp0]"=&r"(temp0),
+ [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [temp6]"=&r"(temp6),
+ [temp7]"=&r"(temp7)
+ : [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end)
+ : "memory"
+ );
+}
+
+static WEBP_INLINE uint32_t ColorTransformDelta(int8_t color_pred,
+ int8_t color) {
+ return (uint32_t)((int)(color_pred) * color) >> 5;
+}
+
+static void TransformColor(const VP8LMultipliers* const m, uint32_t* data,
+ int num_pixels) {
+ int temp0, temp1, temp2, temp3, temp4, temp5;
+ uint32_t argb, argb1, new_red, new_red1;
+ const uint32_t G_to_R = m->green_to_red_;
+ const uint32_t G_to_B = m->green_to_blue_;
+ const uint32_t R_to_B = m->red_to_blue_;
+ uint32_t* const p_loop_end = data + (num_pixels & ~1);
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "beq %[data], %[p_loop_end], 1f \n\t"
+ " nop \n\t"
+ "replv.ph %[temp0], %[G_to_R] \n\t"
+ "replv.ph %[temp1], %[G_to_B] \n\t"
+ "replv.ph %[temp2], %[R_to_B] \n\t"
+ "shll.ph %[temp0], %[temp0], 8 \n\t"
+ "shll.ph %[temp1], %[temp1], 8 \n\t"
+ "shll.ph %[temp2], %[temp2], 8 \n\t"
+ "shra.ph %[temp0], %[temp0], 8 \n\t"
+ "shra.ph %[temp1], %[temp1], 8 \n\t"
+ "shra.ph %[temp2], %[temp2], 8 \n\t"
+ "0: \n\t"
+ "lw %[argb], 0(%[data]) \n\t"
+ "lw %[argb1], 4(%[data]) \n\t"
+ "lhu %[new_red], 2(%[data]) \n\t"
+ "lhu %[new_red1], 6(%[data]) \n\t"
+ "precrq.qb.ph %[temp3], %[argb], %[argb1] \n\t"
+ "precr.qb.ph %[temp4], %[argb], %[argb1] \n\t"
+ "preceu.ph.qbra %[temp3], %[temp3] \n\t"
+ "preceu.ph.qbla %[temp4], %[temp4] \n\t"
+ "shll.ph %[temp3], %[temp3], 8 \n\t"
+ "shll.ph %[temp4], %[temp4], 8 \n\t"
+ "shra.ph %[temp3], %[temp3], 8 \n\t"
+ "shra.ph %[temp4], %[temp4], 8 \n\t"
+ "mul.ph %[temp5], %[temp3], %[temp0] \n\t"
+ "mul.ph %[temp3], %[temp3], %[temp1] \n\t"
+ "mul.ph %[temp4], %[temp4], %[temp2] \n\t"
+ "addiu %[data], %[data], 8 \n\t"
+ "ins %[new_red1], %[new_red], 16, 16 \n\t"
+ "ins %[argb1], %[argb], 16, 16 \n\t"
+ "shra.ph %[temp5], %[temp5], 5 \n\t"
+ "shra.ph %[temp3], %[temp3], 5 \n\t"
+ "shra.ph %[temp4], %[temp4], 5 \n\t"
+ "subu.ph %[new_red1], %[new_red1], %[temp5] \n\t"
+ "subu.ph %[argb1], %[argb1], %[temp3] \n\t"
+ "preceu.ph.qbra %[temp5], %[new_red1] \n\t"
+ "subu.ph %[argb1], %[argb1], %[temp4] \n\t"
+ "preceu.ph.qbra %[temp3], %[argb1] \n\t"
+ "sb %[temp5], -2(%[data]) \n\t"
+ "sb %[temp3], -4(%[data]) \n\t"
+ "sra %[temp5], %[temp5], 16 \n\t"
+ "sra %[temp3], %[temp3], 16 \n\t"
+ "sb %[temp5], -6(%[data]) \n\t"
+ "bne %[data], %[p_loop_end], 0b \n\t"
+ " sb %[temp3], -8(%[data]) \n\t"
+ "1: \n\t"
+ ".set pop \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [new_red1]"=&r"(new_red1), [new_red]"=&r"(new_red),
+ [argb]"=&r"(argb), [argb1]"=&r"(argb1), [data]"+&r"(data)
+ : [G_to_R]"r"(G_to_R), [R_to_B]"r"(R_to_B),
+ [G_to_B]"r"(G_to_B), [p_loop_end]"r"(p_loop_end)
+ : "memory", "hi", "lo"
+ );
+
+ if (num_pixels & 1) {
+ const uint32_t argb_ = data[0];
+ const uint32_t green = argb_ >> 8;
+ const uint32_t red = argb_ >> 16;
+ uint32_t new_blue = argb_;
+ new_red = red;
+ new_red -= ColorTransformDelta(m->green_to_red_, green);
+ new_red &= 0xff;
+ new_blue -= ColorTransformDelta(m->green_to_blue_, green);
+ new_blue -= ColorTransformDelta(m->red_to_blue_, red);
+ new_blue &= 0xff;
+ data[0] = (argb_ & 0xff00ff00u) | (new_red << 16) | (new_blue);
+ }
+}
+
+static WEBP_INLINE uint8_t TransformColorBlue(uint8_t green_to_blue,
+ uint8_t red_to_blue,
+ uint32_t argb) {
+ const uint32_t green = argb >> 8;
+ const uint32_t red = argb >> 16;
+ uint8_t new_blue = argb;
+ new_blue -= ColorTransformDelta(green_to_blue, green);
+ new_blue -= ColorTransformDelta(red_to_blue, red);
+ return (new_blue & 0xff);
+}
+
+static void CollectColorBlueTransforms(const uint32_t* argb, int stride,
+ int tile_width, int tile_height,
+ int green_to_blue, int red_to_blue,
+ int histo[]) {
+ const int rtb = (red_to_blue << 16) | (red_to_blue & 0xffff);
+ const int gtb = (green_to_blue << 16) | (green_to_blue & 0xffff);
+ const uint32_t mask = 0xff00ffu;
+ while (tile_height-- > 0) {
+ int x;
+ const uint32_t* p_argb = argb;
+ argb += stride;
+ for (x = 0; x < (tile_width >> 1); ++x) {
+ int temp0, temp1, temp2, temp3, temp4, temp5, temp6;
+ __asm__ volatile (
+ "lw %[temp0], 0(%[p_argb]) \n\t"
+ "lw %[temp1], 4(%[p_argb]) \n\t"
+ "precr.qb.ph %[temp2], %[temp0], %[temp1] \n\t"
+ "ins %[temp1], %[temp0], 16, 16 \n\t"
+ "shra.ph %[temp2], %[temp2], 8 \n\t"
+ "shra.ph %[temp3], %[temp1], 8 \n\t"
+ "mul.ph %[temp5], %[temp2], %[rtb] \n\t"
+ "mul.ph %[temp6], %[temp3], %[gtb] \n\t"
+ "and %[temp4], %[temp1], %[mask] \n\t"
+ "addiu %[p_argb], %[p_argb], 8 \n\t"
+ "shra.ph %[temp5], %[temp5], 5 \n\t"
+ "shra.ph %[temp6], %[temp6], 5 \n\t"
+ "subu.qb %[temp2], %[temp4], %[temp5] \n\t"
+ "subu.qb %[temp2], %[temp2], %[temp6] \n\t"
+ : [p_argb]"+&r"(p_argb), [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), [temp4]"=&r"(temp4),
+ [temp5]"=&r"(temp5), [temp6]"=&r"(temp6)
+ : [rtb]"r"(rtb), [gtb]"r"(gtb), [mask]"r"(mask)
+ : "memory", "hi", "lo"
+ );
+ ++histo[(uint8_t)(temp2 >> 16)];
+ ++histo[(uint8_t)temp2];
+ }
+ if (tile_width & 1) {
+ ++histo[TransformColorBlue(green_to_blue, red_to_blue, *p_argb)];
+ }
+ }
+}
+
+static WEBP_INLINE uint8_t TransformColorRed(uint8_t green_to_red,
+ uint32_t argb) {
+ const uint32_t green = argb >> 8;
+ uint32_t new_red = argb >> 16;
+ new_red -= ColorTransformDelta(green_to_red, green);
+ return (new_red & 0xff);
+}
+
+static void CollectColorRedTransforms(const uint32_t* argb, int stride,
+ int tile_width, int tile_height,
+ int green_to_red, int histo[]) {
+ const int gtr = (green_to_red << 16) | (green_to_red & 0xffff);
+ while (tile_height-- > 0) {
+ int x;
+ const uint32_t* p_argb = argb;
+ argb += stride;
+ for (x = 0; x < (tile_width >> 1); ++x) {
+ int temp0, temp1, temp2, temp3, temp4;
+ __asm__ volatile (
+ "lw %[temp0], 0(%[p_argb]) \n\t"
+ "lw %[temp1], 4(%[p_argb]) \n\t"
+ "precrq.ph.w %[temp4], %[temp0], %[temp1] \n\t"
+ "ins %[temp1], %[temp0], 16, 16 \n\t"
+ "shra.ph %[temp3], %[temp1], 8 \n\t"
+ "mul.ph %[temp2], %[temp3], %[gtr] \n\t"
+ "addiu %[p_argb], %[p_argb], 8 \n\t"
+ "shra.ph %[temp2], %[temp2], 5 \n\t"
+ "subu.qb %[temp2], %[temp4], %[temp2] \n\t"
+ : [p_argb]"+&r"(p_argb), [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), [temp4]"=&r"(temp4)
+ : [gtr]"r"(gtr)
+ : "memory", "hi", "lo"
+ );
+ ++histo[(uint8_t)(temp2 >> 16)];
+ ++histo[(uint8_t)temp2];
+ }
+ if (tile_width & 1) {
+ ++histo[TransformColorRed(green_to_red, *p_argb)];
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8LEncDspInitMIPSdspR2(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitMIPSdspR2(void) {
+ VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRed;
+ VP8LTransformColor = TransformColor;
+ VP8LCollectColorBlueTransforms = CollectColorBlueTransforms;
+ VP8LCollectColorRedTransforms = CollectColorRedTransforms;
+}
+
+#else // !WEBP_USE_MIPS_DSP_R2
+
+WEBP_DSP_INIT_STUB(VP8LEncDspInitMIPSdspR2)
+
+#endif // WEBP_USE_MIPS_DSP_R2
diff --git a/drivers/webp/dsp/lossless_enc_neon.c b/drivers/webp/dsp/lossless_enc_neon.c
new file mode 100644
index 0000000000..4c56f2594b
--- /dev/null
+++ b/drivers/webp/dsp/lossless_enc_neon.c
@@ -0,0 +1,143 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// NEON variant of methods for lossless encoder
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_NEON)
+
+#include <arm_neon.h>
+
+#include "./lossless.h"
+#include "./neon.h"
+
+//------------------------------------------------------------------------------
+// Subtract-Green Transform
+
+// vtbl?_u8 are marked unavailable for iOS arm64 with Xcode < 6.3, use
+// non-standard versions there.
+#if defined(__APPLE__) && defined(__aarch64__) && \
+ defined(__apple_build_version__) && (__apple_build_version__< 6020037)
+#define USE_VTBLQ
+#endif
+
+#ifdef USE_VTBLQ
+// 255 = byte will be zeroed
+static const uint8_t kGreenShuffle[16] = {
+ 1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, 13, 255, 13, 255
+};
+
+static WEBP_INLINE uint8x16_t DoGreenShuffle(const uint8x16_t argb,
+ const uint8x16_t shuffle) {
+ return vcombine_u8(vtbl1q_u8(argb, vget_low_u8(shuffle)),
+ vtbl1q_u8(argb, vget_high_u8(shuffle)));
+}
+#else // !USE_VTBLQ
+// 255 = byte will be zeroed
+static const uint8_t kGreenShuffle[8] = { 1, 255, 1, 255, 5, 255, 5, 255 };
+
+static WEBP_INLINE uint8x16_t DoGreenShuffle(const uint8x16_t argb,
+ const uint8x8_t shuffle) {
+ return vcombine_u8(vtbl1_u8(vget_low_u8(argb), shuffle),
+ vtbl1_u8(vget_high_u8(argb), shuffle));
+}
+#endif // USE_VTBLQ
+
+static void SubtractGreenFromBlueAndRed(uint32_t* argb_data, int num_pixels) {
+ const uint32_t* const end = argb_data + (num_pixels & ~3);
+#ifdef USE_VTBLQ
+ const uint8x16_t shuffle = vld1q_u8(kGreenShuffle);
+#else
+ const uint8x8_t shuffle = vld1_u8(kGreenShuffle);
+#endif
+ for (; argb_data < end; argb_data += 4) {
+ const uint8x16_t argb = vld1q_u8((uint8_t*)argb_data);
+ const uint8x16_t greens = DoGreenShuffle(argb, shuffle);
+ vst1q_u8((uint8_t*)argb_data, vsubq_u8(argb, greens));
+ }
+ // fallthrough and finish off with plain-C
+ VP8LSubtractGreenFromBlueAndRed_C(argb_data, num_pixels & 3);
+}
+
+//------------------------------------------------------------------------------
+// Color Transform
+
+static void TransformColor(const VP8LMultipliers* const m,
+ uint32_t* argb_data, int num_pixels) {
+ // sign-extended multiplying constants, pre-shifted by 6.
+#define CST(X) (((int16_t)(m->X << 8)) >> 6)
+ const int16_t rb[8] = {
+ CST(green_to_blue_), CST(green_to_red_),
+ CST(green_to_blue_), CST(green_to_red_),
+ CST(green_to_blue_), CST(green_to_red_),
+ CST(green_to_blue_), CST(green_to_red_)
+ };
+ const int16x8_t mults_rb = vld1q_s16(rb);
+ const int16_t b2[8] = {
+ 0, CST(red_to_blue_), 0, CST(red_to_blue_),
+ 0, CST(red_to_blue_), 0, CST(red_to_blue_),
+ };
+ const int16x8_t mults_b2 = vld1q_s16(b2);
+#undef CST
+#ifdef USE_VTBLQ
+ static const uint8_t kg0g0[16] = {
+ 255, 1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, 13, 255, 13
+ };
+ const uint8x16_t shuffle = vld1q_u8(kg0g0);
+#else
+ static const uint8_t k0g0g[8] = { 255, 1, 255, 1, 255, 5, 255, 5 };
+ const uint8x8_t shuffle = vld1_u8(k0g0g);
+#endif
+ const uint32x4_t mask_rb = vdupq_n_u32(0x00ff00ffu); // red-blue masks
+ int i;
+ for (i = 0; i + 4 <= num_pixels; i += 4) {
+ const uint8x16_t in = vld1q_u8((uint8_t*)(argb_data + i));
+ // 0 g 0 g
+ const uint8x16_t greens = DoGreenShuffle(in, shuffle);
+ // x dr x db1
+ const int16x8_t A = vqdmulhq_s16(vreinterpretq_s16_u8(greens), mults_rb);
+ // r 0 b 0
+ const int16x8_t B = vshlq_n_s16(vreinterpretq_s16_u8(in), 8);
+ // x db2 0 0
+ const int16x8_t C = vqdmulhq_s16(B, mults_b2);
+ // 0 0 x db2
+ const uint32x4_t D = vshrq_n_u32(vreinterpretq_u32_s16(C), 16);
+ // x dr x db
+ const int8x16_t E = vaddq_s8(vreinterpretq_s8_u32(D),
+ vreinterpretq_s8_s16(A));
+ // 0 dr 0 db
+ const uint32x4_t F = vandq_u32(vreinterpretq_u32_s8(E), mask_rb);
+ const int8x16_t out = vsubq_s8(vreinterpretq_s8_u8(in),
+ vreinterpretq_s8_u32(F));
+ vst1q_s8((int8_t*)(argb_data + i), out);
+ }
+ // fallthrough and finish off with plain-C
+ VP8LTransformColor_C(m, argb_data + i, num_pixels - i);
+}
+
+#undef USE_VTBLQ
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8LEncDspInitNEON(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitNEON(void) {
+ VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRed;
+ VP8LTransformColor = TransformColor;
+}
+
+#else // !WEBP_USE_NEON
+
+WEBP_DSP_INIT_STUB(VP8LEncDspInitNEON)
+
+#endif // WEBP_USE_NEON
diff --git a/drivers/webp/dsp/lossless_enc_sse2.c b/drivers/webp/dsp/lossless_enc_sse2.c
new file mode 100644
index 0000000000..1374b3ef64
--- /dev/null
+++ b/drivers/webp/dsp/lossless_enc_sse2.c
@@ -0,0 +1,270 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// SSE2 variant of methods for lossless encoder
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_SSE2)
+#include <assert.h>
+#include <emmintrin.h>
+#include "./lossless.h"
+
+// For sign-extended multiplying constants, pre-shifted by 5:
+#define CST_5b(X) (((int16_t)((uint16_t)X << 8)) >> 5)
+
+//------------------------------------------------------------------------------
+// Subtract-Green Transform
+
+static void SubtractGreenFromBlueAndRed(uint32_t* argb_data, int num_pixels) {
+ int i;
+ for (i = 0; i + 4 <= num_pixels; i += 4) {
+ const __m128i in = _mm_loadu_si128((__m128i*)&argb_data[i]); // argb
+ const __m128i A = _mm_srli_epi16(in, 8); // 0 a 0 g
+ const __m128i B = _mm_shufflelo_epi16(A, _MM_SHUFFLE(2, 2, 0, 0));
+ const __m128i C = _mm_shufflehi_epi16(B, _MM_SHUFFLE(2, 2, 0, 0)); // 0g0g
+ const __m128i out = _mm_sub_epi8(in, C);
+ _mm_storeu_si128((__m128i*)&argb_data[i], out);
+ }
+ // fallthrough and finish off with plain-C
+ VP8LSubtractGreenFromBlueAndRed_C(argb_data + i, num_pixels - i);
+}
+
+//------------------------------------------------------------------------------
+// Color Transform
+
+static void TransformColor(const VP8LMultipliers* const m,
+ uint32_t* argb_data, int num_pixels) {
+ const __m128i mults_rb = _mm_set_epi16(
+ CST_5b(m->green_to_red_), CST_5b(m->green_to_blue_),
+ CST_5b(m->green_to_red_), CST_5b(m->green_to_blue_),
+ CST_5b(m->green_to_red_), CST_5b(m->green_to_blue_),
+ CST_5b(m->green_to_red_), CST_5b(m->green_to_blue_));
+ const __m128i mults_b2 = _mm_set_epi16(
+ CST_5b(m->red_to_blue_), 0, CST_5b(m->red_to_blue_), 0,
+ CST_5b(m->red_to_blue_), 0, CST_5b(m->red_to_blue_), 0);
+ const __m128i mask_ag = _mm_set1_epi32(0xff00ff00); // alpha-green masks
+ const __m128i mask_rb = _mm_set1_epi32(0x00ff00ff); // red-blue masks
+ int i;
+ for (i = 0; i + 4 <= num_pixels; i += 4) {
+ const __m128i in = _mm_loadu_si128((__m128i*)&argb_data[i]); // argb
+ const __m128i A = _mm_and_si128(in, mask_ag); // a 0 g 0
+ const __m128i B = _mm_shufflelo_epi16(A, _MM_SHUFFLE(2, 2, 0, 0));
+ const __m128i C = _mm_shufflehi_epi16(B, _MM_SHUFFLE(2, 2, 0, 0)); // g0g0
+ const __m128i D = _mm_mulhi_epi16(C, mults_rb); // x dr x db1
+ const __m128i E = _mm_slli_epi16(in, 8); // r 0 b 0
+ const __m128i F = _mm_mulhi_epi16(E, mults_b2); // x db2 0 0
+ const __m128i G = _mm_srli_epi32(F, 16); // 0 0 x db2
+ const __m128i H = _mm_add_epi8(G, D); // x dr x db
+ const __m128i I = _mm_and_si128(H, mask_rb); // 0 dr 0 db
+ const __m128i out = _mm_sub_epi8(in, I);
+ _mm_storeu_si128((__m128i*)&argb_data[i], out);
+ }
+ // fallthrough and finish off with plain-C
+ VP8LTransformColor_C(m, argb_data + i, num_pixels - i);
+}
+
+//------------------------------------------------------------------------------
+#define SPAN 8
+static void CollectColorBlueTransforms(const uint32_t* argb, int stride,
+ int tile_width, int tile_height,
+ int green_to_blue, int red_to_blue,
+ int histo[]) {
+ const __m128i mults_r = _mm_set_epi16(
+ CST_5b(red_to_blue), 0, CST_5b(red_to_blue), 0,
+ CST_5b(red_to_blue), 0, CST_5b(red_to_blue), 0);
+ const __m128i mults_g = _mm_set_epi16(
+ 0, CST_5b(green_to_blue), 0, CST_5b(green_to_blue),
+ 0, CST_5b(green_to_blue), 0, CST_5b(green_to_blue));
+ const __m128i mask_g = _mm_set1_epi32(0x00ff00); // green mask
+ const __m128i mask_b = _mm_set1_epi32(0x0000ff); // blue mask
+ int y;
+ for (y = 0; y < tile_height; ++y) {
+ const uint32_t* const src = argb + y * stride;
+ int i, x;
+ for (x = 0; x + SPAN <= tile_width; x += SPAN) {
+ uint16_t values[SPAN];
+ const __m128i in0 = _mm_loadu_si128((__m128i*)&src[x + 0]);
+ const __m128i in1 = _mm_loadu_si128((__m128i*)&src[x + SPAN / 2]);
+ const __m128i A0 = _mm_slli_epi16(in0, 8); // r 0 | b 0
+ const __m128i A1 = _mm_slli_epi16(in1, 8);
+ const __m128i B0 = _mm_and_si128(in0, mask_g); // 0 0 | g 0
+ const __m128i B1 = _mm_and_si128(in1, mask_g);
+ const __m128i C0 = _mm_mulhi_epi16(A0, mults_r); // x db | 0 0
+ const __m128i C1 = _mm_mulhi_epi16(A1, mults_r);
+ const __m128i D0 = _mm_mulhi_epi16(B0, mults_g); // 0 0 | x db
+ const __m128i D1 = _mm_mulhi_epi16(B1, mults_g);
+ const __m128i E0 = _mm_sub_epi8(in0, D0); // x x | x b'
+ const __m128i E1 = _mm_sub_epi8(in1, D1);
+ const __m128i F0 = _mm_srli_epi32(C0, 16); // 0 0 | x db
+ const __m128i F1 = _mm_srli_epi32(C1, 16);
+ const __m128i G0 = _mm_sub_epi8(E0, F0); // 0 0 | x b'
+ const __m128i G1 = _mm_sub_epi8(E1, F1);
+ const __m128i H0 = _mm_and_si128(G0, mask_b); // 0 0 | 0 b
+ const __m128i H1 = _mm_and_si128(G1, mask_b);
+ const __m128i I = _mm_packs_epi32(H0, H1); // 0 b' | 0 b'
+ _mm_storeu_si128((__m128i*)values, I);
+ for (i = 0; i < SPAN; ++i) ++histo[values[i]];
+ }
+ }
+ {
+ const int left_over = tile_width & (SPAN - 1);
+ if (left_over > 0) {
+ VP8LCollectColorBlueTransforms_C(argb + tile_width - left_over, stride,
+ left_over, tile_height,
+ green_to_blue, red_to_blue, histo);
+ }
+ }
+}
+
+static void CollectColorRedTransforms(const uint32_t* argb, int stride,
+ int tile_width, int tile_height,
+ int green_to_red, int histo[]) {
+ const __m128i mults_g = _mm_set_epi16(
+ 0, CST_5b(green_to_red), 0, CST_5b(green_to_red),
+ 0, CST_5b(green_to_red), 0, CST_5b(green_to_red));
+ const __m128i mask_g = _mm_set1_epi32(0x00ff00); // green mask
+ const __m128i mask = _mm_set1_epi32(0xff);
+
+ int y;
+ for (y = 0; y < tile_height; ++y) {
+ const uint32_t* const src = argb + y * stride;
+ int i, x;
+ for (x = 0; x + SPAN <= tile_width; x += SPAN) {
+ uint16_t values[SPAN];
+ const __m128i in0 = _mm_loadu_si128((__m128i*)&src[x + 0]);
+ const __m128i in1 = _mm_loadu_si128((__m128i*)&src[x + SPAN / 2]);
+ const __m128i A0 = _mm_and_si128(in0, mask_g); // 0 0 | g 0
+ const __m128i A1 = _mm_and_si128(in1, mask_g);
+ const __m128i B0 = _mm_srli_epi32(in0, 16); // 0 0 | x r
+ const __m128i B1 = _mm_srli_epi32(in1, 16);
+ const __m128i C0 = _mm_mulhi_epi16(A0, mults_g); // 0 0 | x dr
+ const __m128i C1 = _mm_mulhi_epi16(A1, mults_g);
+ const __m128i E0 = _mm_sub_epi8(B0, C0); // x x | x r'
+ const __m128i E1 = _mm_sub_epi8(B1, C1);
+ const __m128i F0 = _mm_and_si128(E0, mask); // 0 0 | 0 r'
+ const __m128i F1 = _mm_and_si128(E1, mask);
+ const __m128i I = _mm_packs_epi32(F0, F1);
+ _mm_storeu_si128((__m128i*)values, I);
+ for (i = 0; i < SPAN; ++i) ++histo[values[i]];
+ }
+ }
+ {
+ const int left_over = tile_width & (SPAN - 1);
+ if (left_over > 0) {
+ VP8LCollectColorRedTransforms_C(argb + tile_width - left_over, stride,
+ left_over, tile_height,
+ green_to_red, histo);
+ }
+ }
+}
+#undef SPAN
+
+//------------------------------------------------------------------------------
+
+#define LINE_SIZE 16 // 8 or 16
+static void AddVector(const uint32_t* a, const uint32_t* b, uint32_t* out,
+ int size) {
+ int i;
+ assert(size % LINE_SIZE == 0);
+ for (i = 0; i < size; i += LINE_SIZE) {
+ const __m128i a0 = _mm_loadu_si128((const __m128i*)&a[i + 0]);
+ const __m128i a1 = _mm_loadu_si128((const __m128i*)&a[i + 4]);
+#if (LINE_SIZE == 16)
+ const __m128i a2 = _mm_loadu_si128((const __m128i*)&a[i + 8]);
+ const __m128i a3 = _mm_loadu_si128((const __m128i*)&a[i + 12]);
+#endif
+ const __m128i b0 = _mm_loadu_si128((const __m128i*)&b[i + 0]);
+ const __m128i b1 = _mm_loadu_si128((const __m128i*)&b[i + 4]);
+#if (LINE_SIZE == 16)
+ const __m128i b2 = _mm_loadu_si128((const __m128i*)&b[i + 8]);
+ const __m128i b3 = _mm_loadu_si128((const __m128i*)&b[i + 12]);
+#endif
+ _mm_storeu_si128((__m128i*)&out[i + 0], _mm_add_epi32(a0, b0));
+ _mm_storeu_si128((__m128i*)&out[i + 4], _mm_add_epi32(a1, b1));
+#if (LINE_SIZE == 16)
+ _mm_storeu_si128((__m128i*)&out[i + 8], _mm_add_epi32(a2, b2));
+ _mm_storeu_si128((__m128i*)&out[i + 12], _mm_add_epi32(a3, b3));
+#endif
+ }
+}
+
+static void AddVectorEq(const uint32_t* a, uint32_t* out, int size) {
+ int i;
+ assert(size % LINE_SIZE == 0);
+ for (i = 0; i < size; i += LINE_SIZE) {
+ const __m128i a0 = _mm_loadu_si128((const __m128i*)&a[i + 0]);
+ const __m128i a1 = _mm_loadu_si128((const __m128i*)&a[i + 4]);
+#if (LINE_SIZE == 16)
+ const __m128i a2 = _mm_loadu_si128((const __m128i*)&a[i + 8]);
+ const __m128i a3 = _mm_loadu_si128((const __m128i*)&a[i + 12]);
+#endif
+ const __m128i b0 = _mm_loadu_si128((const __m128i*)&out[i + 0]);
+ const __m128i b1 = _mm_loadu_si128((const __m128i*)&out[i + 4]);
+#if (LINE_SIZE == 16)
+ const __m128i b2 = _mm_loadu_si128((const __m128i*)&out[i + 8]);
+ const __m128i b3 = _mm_loadu_si128((const __m128i*)&out[i + 12]);
+#endif
+ _mm_storeu_si128((__m128i*)&out[i + 0], _mm_add_epi32(a0, b0));
+ _mm_storeu_si128((__m128i*)&out[i + 4], _mm_add_epi32(a1, b1));
+#if (LINE_SIZE == 16)
+ _mm_storeu_si128((__m128i*)&out[i + 8], _mm_add_epi32(a2, b2));
+ _mm_storeu_si128((__m128i*)&out[i + 12], _mm_add_epi32(a3, b3));
+#endif
+ }
+}
+#undef LINE_SIZE
+
+// Note we are adding uint32_t's as *signed* int32's (using _mm_add_epi32). But
+// that's ok since the histogram values are less than 1<<28 (max picture size).
+static void HistogramAdd(const VP8LHistogram* const a,
+ const VP8LHistogram* const b,
+ VP8LHistogram* const out) {
+ int i;
+ const int literal_size = VP8LHistogramNumCodes(a->palette_code_bits_);
+ assert(a->palette_code_bits_ == b->palette_code_bits_);
+ if (b != out) {
+ AddVector(a->literal_, b->literal_, out->literal_, NUM_LITERAL_CODES);
+ AddVector(a->red_, b->red_, out->red_, NUM_LITERAL_CODES);
+ AddVector(a->blue_, b->blue_, out->blue_, NUM_LITERAL_CODES);
+ AddVector(a->alpha_, b->alpha_, out->alpha_, NUM_LITERAL_CODES);
+ } else {
+ AddVectorEq(a->literal_, out->literal_, NUM_LITERAL_CODES);
+ AddVectorEq(a->red_, out->red_, NUM_LITERAL_CODES);
+ AddVectorEq(a->blue_, out->blue_, NUM_LITERAL_CODES);
+ AddVectorEq(a->alpha_, out->alpha_, NUM_LITERAL_CODES);
+ }
+ for (i = NUM_LITERAL_CODES; i < literal_size; ++i) {
+ out->literal_[i] = a->literal_[i] + b->literal_[i];
+ }
+ for (i = 0; i < NUM_DISTANCE_CODES; ++i) {
+ out->distance_[i] = a->distance_[i] + b->distance_[i];
+ }
+}
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8LEncDspInitSSE2(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitSSE2(void) {
+ VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRed;
+ VP8LTransformColor = TransformColor;
+ VP8LCollectColorBlueTransforms = CollectColorBlueTransforms;
+ VP8LCollectColorRedTransforms = CollectColorRedTransforms;
+ VP8LHistogramAdd = HistogramAdd;
+}
+
+#else // !WEBP_USE_SSE2
+
+WEBP_DSP_INIT_STUB(VP8LEncDspInitSSE2)
+
+#endif // WEBP_USE_SSE2
diff --git a/drivers/webp/dsp/lossless_enc_sse41.c b/drivers/webp/dsp/lossless_enc_sse41.c
new file mode 100644
index 0000000000..3e493198db
--- /dev/null
+++ b/drivers/webp/dsp/lossless_enc_sse41.c
@@ -0,0 +1,51 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// SSE4.1 variant of methods for lossless encoder
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_SSE41)
+#include <assert.h>
+#include <smmintrin.h>
+#include "./lossless.h"
+
+//------------------------------------------------------------------------------
+// Subtract-Green Transform
+
+static void SubtractGreenFromBlueAndRed(uint32_t* argb_data, int num_pixels) {
+ int i;
+ const __m128i kCstShuffle = _mm_set_epi8(-1, 13, -1, 13, -1, 9, -1, 9,
+ -1, 5, -1, 5, -1, 1, -1, 1);
+ for (i = 0; i + 4 <= num_pixels; i += 4) {
+ const __m128i in = _mm_loadu_si128((__m128i*)&argb_data[i]);
+ const __m128i in_0g0g = _mm_shuffle_epi8(in, kCstShuffle);
+ const __m128i out = _mm_sub_epi8(in, in_0g0g);
+ _mm_storeu_si128((__m128i*)&argb_data[i], out);
+ }
+ // fallthrough and finish off with plain-C
+ VP8LSubtractGreenFromBlueAndRed_C(argb_data + i, num_pixels - i);
+}
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8LEncDspInitSSE41(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInitSSE41(void) {
+ VP8LSubtractGreenFromBlueAndRed = SubtractGreenFromBlueAndRed;
+}
+
+#else // !WEBP_USE_SSE41
+
+WEBP_DSP_INIT_STUB(VP8LEncDspInitSSE41)
+
+#endif // WEBP_USE_SSE41
diff --git a/drivers/webp/dsp/lossless_mips_dsp_r2.c b/drivers/webp/dsp/lossless_mips_dsp_r2.c
new file mode 100644
index 0000000000..90aed7f151
--- /dev/null
+++ b/drivers/webp/dsp/lossless_mips_dsp_r2.c
@@ -0,0 +1,680 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Image transforms and color space conversion methods for lossless decoder.
+//
+// Author(s): Djordje Pesut (djordje.pesut@imgtec.com)
+// Jovan Zelincevic (jovan.zelincevic@imgtec.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_MIPS_DSP_R2)
+
+#include "./lossless.h"
+
+#define MAP_COLOR_FUNCS(FUNC_NAME, TYPE, GET_INDEX, GET_VALUE) \
+static void FUNC_NAME(const TYPE* src, \
+ const uint32_t* const color_map, \
+ TYPE* dst, int y_start, int y_end, \
+ int width) { \
+ int y; \
+ for (y = y_start; y < y_end; ++y) { \
+ int x; \
+ for (x = 0; x < (width >> 2); ++x) { \
+ int tmp1, tmp2, tmp3, tmp4; \
+ __asm__ volatile ( \
+ ".ifc " #TYPE ", uint8_t \n\t" \
+ "lbu %[tmp1], 0(%[src]) \n\t" \
+ "lbu %[tmp2], 1(%[src]) \n\t" \
+ "lbu %[tmp3], 2(%[src]) \n\t" \
+ "lbu %[tmp4], 3(%[src]) \n\t" \
+ "addiu %[src], %[src], 4 \n\t" \
+ ".endif \n\t" \
+ ".ifc " #TYPE ", uint32_t \n\t" \
+ "lw %[tmp1], 0(%[src]) \n\t" \
+ "lw %[tmp2], 4(%[src]) \n\t" \
+ "lw %[tmp3], 8(%[src]) \n\t" \
+ "lw %[tmp4], 12(%[src]) \n\t" \
+ "ext %[tmp1], %[tmp1], 8, 8 \n\t" \
+ "ext %[tmp2], %[tmp2], 8, 8 \n\t" \
+ "ext %[tmp3], %[tmp3], 8, 8 \n\t" \
+ "ext %[tmp4], %[tmp4], 8, 8 \n\t" \
+ "addiu %[src], %[src], 16 \n\t" \
+ ".endif \n\t" \
+ "sll %[tmp1], %[tmp1], 2 \n\t" \
+ "sll %[tmp2], %[tmp2], 2 \n\t" \
+ "sll %[tmp3], %[tmp3], 2 \n\t" \
+ "sll %[tmp4], %[tmp4], 2 \n\t" \
+ "lwx %[tmp1], %[tmp1](%[color_map]) \n\t" \
+ "lwx %[tmp2], %[tmp2](%[color_map]) \n\t" \
+ "lwx %[tmp3], %[tmp3](%[color_map]) \n\t" \
+ "lwx %[tmp4], %[tmp4](%[color_map]) \n\t" \
+ ".ifc " #TYPE ", uint8_t \n\t" \
+ "ext %[tmp1], %[tmp1], 8, 8 \n\t" \
+ "ext %[tmp2], %[tmp2], 8, 8 \n\t" \
+ "ext %[tmp3], %[tmp3], 8, 8 \n\t" \
+ "ext %[tmp4], %[tmp4], 8, 8 \n\t" \
+ "sb %[tmp1], 0(%[dst]) \n\t" \
+ "sb %[tmp2], 1(%[dst]) \n\t" \
+ "sb %[tmp3], 2(%[dst]) \n\t" \
+ "sb %[tmp4], 3(%[dst]) \n\t" \
+ "addiu %[dst], %[dst], 4 \n\t" \
+ ".endif \n\t" \
+ ".ifc " #TYPE ", uint32_t \n\t" \
+ "sw %[tmp1], 0(%[dst]) \n\t" \
+ "sw %[tmp2], 4(%[dst]) \n\t" \
+ "sw %[tmp3], 8(%[dst]) \n\t" \
+ "sw %[tmp4], 12(%[dst]) \n\t" \
+ "addiu %[dst], %[dst], 16 \n\t" \
+ ".endif \n\t" \
+ : [tmp1]"=&r"(tmp1), [tmp2]"=&r"(tmp2), [tmp3]"=&r"(tmp3), \
+ [tmp4]"=&r"(tmp4), [src]"+&r"(src), [dst]"+r"(dst) \
+ : [color_map]"r"(color_map) \
+ : "memory" \
+ ); \
+ } \
+ for (x = 0; x < (width & 3); ++x) { \
+ *dst++ = GET_VALUE(color_map[GET_INDEX(*src++)]); \
+ } \
+ } \
+}
+
+MAP_COLOR_FUNCS(MapARGB, uint32_t, VP8GetARGBIndex, VP8GetARGBValue)
+MAP_COLOR_FUNCS(MapAlpha, uint8_t, VP8GetAlphaIndex, VP8GetAlphaValue)
+
+#undef MAP_COLOR_FUNCS
+
+static WEBP_INLINE uint32_t ClampedAddSubtractFull(uint32_t c0, uint32_t c1,
+ uint32_t c2) {
+ int temp0, temp1, temp2, temp3, temp4, temp5;
+ __asm__ volatile (
+ "preceu.ph.qbr %[temp1], %[c0] \n\t"
+ "preceu.ph.qbl %[temp2], %[c0] \n\t"
+ "preceu.ph.qbr %[temp3], %[c1] \n\t"
+ "preceu.ph.qbl %[temp4], %[c1] \n\t"
+ "preceu.ph.qbr %[temp5], %[c2] \n\t"
+ "preceu.ph.qbl %[temp0], %[c2] \n\t"
+ "subq.ph %[temp3], %[temp3], %[temp5] \n\t"
+ "subq.ph %[temp4], %[temp4], %[temp0] \n\t"
+ "addq.ph %[temp1], %[temp1], %[temp3] \n\t"
+ "addq.ph %[temp2], %[temp2], %[temp4] \n\t"
+ "shll_s.ph %[temp1], %[temp1], 7 \n\t"
+ "shll_s.ph %[temp2], %[temp2], 7 \n\t"
+ "precrqu_s.qb.ph %[temp2], %[temp2], %[temp1] \n\t"
+ : [temp0]"=r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5)
+ : [c0]"r"(c0), [c1]"r"(c1), [c2]"r"(c2)
+ : "memory"
+ );
+ return temp2;
+}
+
+static WEBP_INLINE uint32_t ClampedAddSubtractHalf(uint32_t c0, uint32_t c1,
+ uint32_t c2) {
+ int temp0, temp1, temp2, temp3, temp4, temp5;
+ __asm__ volatile (
+ "adduh.qb %[temp5], %[c0], %[c1] \n\t"
+ "preceu.ph.qbr %[temp3], %[c2] \n\t"
+ "preceu.ph.qbr %[temp1], %[temp5] \n\t"
+ "preceu.ph.qbl %[temp2], %[temp5] \n\t"
+ "preceu.ph.qbl %[temp4], %[c2] \n\t"
+ "subq.ph %[temp3], %[temp1], %[temp3] \n\t"
+ "subq.ph %[temp4], %[temp2], %[temp4] \n\t"
+ "shrl.ph %[temp5], %[temp3], 15 \n\t"
+ "shrl.ph %[temp0], %[temp4], 15 \n\t"
+ "addq.ph %[temp3], %[temp3], %[temp5] \n\t"
+ "addq.ph %[temp4], %[temp0], %[temp4] \n\t"
+ "shra.ph %[temp3], %[temp3], 1 \n\t"
+ "shra.ph %[temp4], %[temp4], 1 \n\t"
+ "addq.ph %[temp1], %[temp1], %[temp3] \n\t"
+ "addq.ph %[temp2], %[temp2], %[temp4] \n\t"
+ "shll_s.ph %[temp1], %[temp1], 7 \n\t"
+ "shll_s.ph %[temp2], %[temp2], 7 \n\t"
+ "precrqu_s.qb.ph %[temp1], %[temp2], %[temp1] \n\t"
+ : [temp0]"=r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=r"(temp4), [temp5]"=&r"(temp5)
+ : [c0]"r"(c0), [c1]"r"(c1), [c2]"r"(c2)
+ : "memory"
+ );
+ return temp1;
+}
+
+static WEBP_INLINE uint32_t Select(uint32_t a, uint32_t b, uint32_t c) {
+ int temp0, temp1, temp2, temp3, temp4, temp5;
+ __asm__ volatile (
+ "cmpgdu.lt.qb %[temp1], %[c], %[b] \n\t"
+ "pick.qb %[temp1], %[b], %[c] \n\t"
+ "pick.qb %[temp2], %[c], %[b] \n\t"
+ "cmpgdu.lt.qb %[temp4], %[c], %[a] \n\t"
+ "pick.qb %[temp4], %[a], %[c] \n\t"
+ "pick.qb %[temp5], %[c], %[a] \n\t"
+ "subu.qb %[temp3], %[temp1], %[temp2] \n\t"
+ "subu.qb %[temp0], %[temp4], %[temp5] \n\t"
+ "raddu.w.qb %[temp3], %[temp3] \n\t"
+ "raddu.w.qb %[temp0], %[temp0] \n\t"
+ "subu %[temp3], %[temp3], %[temp0] \n\t"
+ "slti %[temp0], %[temp3], 0x1 \n\t"
+ "movz %[a], %[b], %[temp0] \n\t"
+ : [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [temp0]"=&r"(temp0),
+ [a]"+&r"(a)
+ : [b]"r"(b), [c]"r"(c)
+ );
+ return a;
+}
+
+static WEBP_INLINE uint32_t Average2(uint32_t a0, uint32_t a1) {
+ __asm__ volatile (
+ "adduh.qb %[a0], %[a0], %[a1] \n\t"
+ : [a0]"+r"(a0)
+ : [a1]"r"(a1)
+ );
+ return a0;
+}
+
+static WEBP_INLINE uint32_t Average3(uint32_t a0, uint32_t a1, uint32_t a2) {
+ return Average2(Average2(a0, a2), a1);
+}
+
+static WEBP_INLINE uint32_t Average4(uint32_t a0, uint32_t a1,
+ uint32_t a2, uint32_t a3) {
+ return Average2(Average2(a0, a1), Average2(a2, a3));
+}
+
+static uint32_t Predictor5(uint32_t left, const uint32_t* const top) {
+ return Average3(left, top[0], top[1]);
+}
+
+static uint32_t Predictor6(uint32_t left, const uint32_t* const top) {
+ return Average2(left, top[-1]);
+}
+
+static uint32_t Predictor7(uint32_t left, const uint32_t* const top) {
+ return Average2(left, top[0]);
+}
+
+static uint32_t Predictor8(uint32_t left, const uint32_t* const top) {
+ (void)left;
+ return Average2(top[-1], top[0]);
+}
+
+static uint32_t Predictor9(uint32_t left, const uint32_t* const top) {
+ (void)left;
+ return Average2(top[0], top[1]);
+}
+
+static uint32_t Predictor10(uint32_t left, const uint32_t* const top) {
+ return Average4(left, top[-1], top[0], top[1]);
+}
+
+static uint32_t Predictor11(uint32_t left, const uint32_t* const top) {
+ return Select(top[0], left, top[-1]);
+}
+
+static uint32_t Predictor12(uint32_t left, const uint32_t* const top) {
+ return ClampedAddSubtractFull(left, top[0], top[-1]);
+}
+
+static uint32_t Predictor13(uint32_t left, const uint32_t* const top) {
+ return ClampedAddSubtractHalf(left, top[0], top[-1]);
+}
+
+// Add green to blue and red channels (i.e. perform the inverse transform of
+// 'subtract green').
+static void AddGreenToBlueAndRed(uint32_t* data, int num_pixels) {
+ uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7;
+ uint32_t* const p_loop1_end = data + (num_pixels & ~3);
+ uint32_t* const p_loop2_end = data + num_pixels;
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "beq %[data], %[p_loop1_end], 3f \n\t"
+ " nop \n\t"
+ "0: \n\t"
+ "lw %[temp0], 0(%[data]) \n\t"
+ "lw %[temp1], 4(%[data]) \n\t"
+ "lw %[temp2], 8(%[data]) \n\t"
+ "lw %[temp3], 12(%[data]) \n\t"
+ "ext %[temp4], %[temp0], 8, 8 \n\t"
+ "ext %[temp5], %[temp1], 8, 8 \n\t"
+ "ext %[temp6], %[temp2], 8, 8 \n\t"
+ "ext %[temp7], %[temp3], 8, 8 \n\t"
+ "addiu %[data], %[data], 16 \n\t"
+ "replv.ph %[temp4], %[temp4] \n\t"
+ "replv.ph %[temp5], %[temp5] \n\t"
+ "replv.ph %[temp6], %[temp6] \n\t"
+ "replv.ph %[temp7], %[temp7] \n\t"
+ "addu.qb %[temp0], %[temp0], %[temp4] \n\t"
+ "addu.qb %[temp1], %[temp1], %[temp5] \n\t"
+ "addu.qb %[temp2], %[temp2], %[temp6] \n\t"
+ "addu.qb %[temp3], %[temp3], %[temp7] \n\t"
+ "sw %[temp0], -16(%[data]) \n\t"
+ "sw %[temp1], -12(%[data]) \n\t"
+ "sw %[temp2], -8(%[data]) \n\t"
+ "bne %[data], %[p_loop1_end], 0b \n\t"
+ " sw %[temp3], -4(%[data]) \n\t"
+ "3: \n\t"
+ "beq %[data], %[p_loop2_end], 2f \n\t"
+ " nop \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[data]) \n\t"
+ "addiu %[data], %[data], 4 \n\t"
+ "ext %[temp4], %[temp0], 8, 8 \n\t"
+ "replv.ph %[temp4], %[temp4] \n\t"
+ "addu.qb %[temp0], %[temp0], %[temp4] \n\t"
+ "bne %[data], %[p_loop2_end], 1b \n\t"
+ " sw %[temp0], -4(%[data]) \n\t"
+ "2: \n\t"
+ ".set pop \n\t"
+ : [data]"+&r"(data), [temp0]"=&r"(temp0), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), [temp4]"=&r"(temp4),
+ [temp5]"=&r"(temp5), [temp6]"=&r"(temp6), [temp7]"=&r"(temp7)
+ : [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end)
+ : "memory"
+ );
+}
+
+static void TransformColorInverse(const VP8LMultipliers* const m,
+ uint32_t* data, int num_pixels) {
+ int temp0, temp1, temp2, temp3, temp4, temp5;
+ uint32_t argb, argb1, new_red;
+ const uint32_t G_to_R = m->green_to_red_;
+ const uint32_t G_to_B = m->green_to_blue_;
+ const uint32_t R_to_B = m->red_to_blue_;
+ uint32_t* const p_loop_end = data + (num_pixels & ~1);
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "beq %[data], %[p_loop_end], 1f \n\t"
+ " nop \n\t"
+ "replv.ph %[temp0], %[G_to_R] \n\t"
+ "replv.ph %[temp1], %[G_to_B] \n\t"
+ "replv.ph %[temp2], %[R_to_B] \n\t"
+ "shll.ph %[temp0], %[temp0], 8 \n\t"
+ "shll.ph %[temp1], %[temp1], 8 \n\t"
+ "shll.ph %[temp2], %[temp2], 8 \n\t"
+ "shra.ph %[temp0], %[temp0], 8 \n\t"
+ "shra.ph %[temp1], %[temp1], 8 \n\t"
+ "shra.ph %[temp2], %[temp2], 8 \n\t"
+ "0: \n\t"
+ "lw %[argb], 0(%[data]) \n\t"
+ "lw %[argb1], 4(%[data]) \n\t"
+ "addiu %[data], %[data], 8 \n\t"
+ "precrq.qb.ph %[temp3], %[argb], %[argb1] \n\t"
+ "preceu.ph.qbra %[temp3], %[temp3] \n\t"
+ "shll.ph %[temp3], %[temp3], 8 \n\t"
+ "shra.ph %[temp3], %[temp3], 8 \n\t"
+ "mul.ph %[temp5], %[temp3], %[temp0] \n\t"
+ "mul.ph %[temp3], %[temp3], %[temp1] \n\t"
+ "precrq.ph.w %[new_red], %[argb], %[argb1] \n\t"
+ "ins %[argb1], %[argb], 16, 16 \n\t"
+ "shra.ph %[temp5], %[temp5], 5 \n\t"
+ "shra.ph %[temp3], %[temp3], 5 \n\t"
+ "addu.ph %[new_red], %[new_red], %[temp5] \n\t"
+ "addu.ph %[argb1], %[argb1], %[temp3] \n\t"
+ "preceu.ph.qbra %[temp5], %[new_red] \n\t"
+ "shll.ph %[temp4], %[temp5], 8 \n\t"
+ "shra.ph %[temp4], %[temp4], 8 \n\t"
+ "mul.ph %[temp4], %[temp4], %[temp2] \n\t"
+ "sb %[temp5], -2(%[data]) \n\t"
+ "sra %[temp5], %[temp5], 16 \n\t"
+ "shra.ph %[temp4], %[temp4], 5 \n\t"
+ "addu.ph %[argb1], %[argb1], %[temp4] \n\t"
+ "preceu.ph.qbra %[temp3], %[argb1] \n\t"
+ "sb %[temp5], -6(%[data]) \n\t"
+ "sb %[temp3], -4(%[data]) \n\t"
+ "sra %[temp3], %[temp3], 16 \n\t"
+ "bne %[data], %[p_loop_end], 0b \n\t"
+ " sb %[temp3], -8(%[data]) \n\t"
+ "1: \n\t"
+ ".set pop \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [new_red]"=&r"(new_red), [argb]"=&r"(argb),
+ [argb1]"=&r"(argb1), [data]"+&r"(data)
+ : [G_to_R]"r"(G_to_R), [R_to_B]"r"(R_to_B),
+ [G_to_B]"r"(G_to_B), [p_loop_end]"r"(p_loop_end)
+ : "memory", "hi", "lo"
+ );
+
+ // Fall-back to C-version for left-overs.
+ if (num_pixels & 1) VP8LTransformColorInverse_C(m, data, 1);
+}
+
+static void ConvertBGRAToRGB(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ int temp0, temp1, temp2, temp3;
+ const uint32_t* const p_loop1_end = src + (num_pixels & ~3);
+ const uint32_t* const p_loop2_end = src + num_pixels;
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "beq %[src], %[p_loop1_end], 3f \n\t"
+ " nop \n\t"
+ "0: \n\t"
+ "lw %[temp3], 12(%[src]) \n\t"
+ "lw %[temp2], 8(%[src]) \n\t"
+ "lw %[temp1], 4(%[src]) \n\t"
+ "lw %[temp0], 0(%[src]) \n\t"
+ "ins %[temp3], %[temp2], 24, 8 \n\t"
+ "sll %[temp2], %[temp2], 8 \n\t"
+ "rotr %[temp3], %[temp3], 16 \n\t"
+ "ins %[temp2], %[temp1], 0, 16 \n\t"
+ "sll %[temp1], %[temp1], 8 \n\t"
+ "wsbh %[temp3], %[temp3] \n\t"
+ "balign %[temp0], %[temp1], 1 \n\t"
+ "wsbh %[temp2], %[temp2] \n\t"
+ "wsbh %[temp0], %[temp0] \n\t"
+ "usw %[temp3], 8(%[dst]) \n\t"
+ "rotr %[temp0], %[temp0], 16 \n\t"
+ "usw %[temp2], 4(%[dst]) \n\t"
+ "addiu %[src], %[src], 16 \n\t"
+ "usw %[temp0], 0(%[dst]) \n\t"
+ "bne %[src], %[p_loop1_end], 0b \n\t"
+ " addiu %[dst], %[dst], 12 \n\t"
+ "3: \n\t"
+ "beq %[src], %[p_loop2_end], 2f \n\t"
+ " nop \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[src]) \n\t"
+ "addiu %[src], %[src], 4 \n\t"
+ "wsbh %[temp1], %[temp0] \n\t"
+ "addiu %[dst], %[dst], 3 \n\t"
+ "ush %[temp1], -2(%[dst]) \n\t"
+ "sra %[temp0], %[temp0], 16 \n\t"
+ "bne %[src], %[p_loop2_end], 1b \n\t"
+ " sb %[temp0], -3(%[dst]) \n\t"
+ "2: \n\t"
+ ".set pop \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [dst]"+&r"(dst), [src]"+&r"(src)
+ : [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end)
+ : "memory"
+ );
+}
+
+static void ConvertBGRAToRGBA(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ int temp0, temp1, temp2, temp3;
+ const uint32_t* const p_loop1_end = src + (num_pixels & ~3);
+ const uint32_t* const p_loop2_end = src + num_pixels;
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "beq %[src], %[p_loop1_end], 3f \n\t"
+ " nop \n\t"
+ "0: \n\t"
+ "lw %[temp0], 0(%[src]) \n\t"
+ "lw %[temp1], 4(%[src]) \n\t"
+ "lw %[temp2], 8(%[src]) \n\t"
+ "lw %[temp3], 12(%[src]) \n\t"
+ "wsbh %[temp0], %[temp0] \n\t"
+ "wsbh %[temp1], %[temp1] \n\t"
+ "wsbh %[temp2], %[temp2] \n\t"
+ "wsbh %[temp3], %[temp3] \n\t"
+ "addiu %[src], %[src], 16 \n\t"
+ "balign %[temp0], %[temp0], 1 \n\t"
+ "balign %[temp1], %[temp1], 1 \n\t"
+ "balign %[temp2], %[temp2], 1 \n\t"
+ "balign %[temp3], %[temp3], 1 \n\t"
+ "usw %[temp0], 0(%[dst]) \n\t"
+ "usw %[temp1], 4(%[dst]) \n\t"
+ "usw %[temp2], 8(%[dst]) \n\t"
+ "usw %[temp3], 12(%[dst]) \n\t"
+ "bne %[src], %[p_loop1_end], 0b \n\t"
+ " addiu %[dst], %[dst], 16 \n\t"
+ "3: \n\t"
+ "beq %[src], %[p_loop2_end], 2f \n\t"
+ " nop \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[src]) \n\t"
+ "wsbh %[temp0], %[temp0] \n\t"
+ "addiu %[src], %[src], 4 \n\t"
+ "balign %[temp0], %[temp0], 1 \n\t"
+ "usw %[temp0], 0(%[dst]) \n\t"
+ "bne %[src], %[p_loop2_end], 1b \n\t"
+ " addiu %[dst], %[dst], 4 \n\t"
+ "2: \n\t"
+ ".set pop \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [dst]"+&r"(dst), [src]"+&r"(src)
+ : [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end)
+ : "memory"
+ );
+}
+
+static void ConvertBGRAToRGBA4444(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ int temp0, temp1, temp2, temp3, temp4, temp5;
+ const uint32_t* const p_loop1_end = src + (num_pixels & ~3);
+ const uint32_t* const p_loop2_end = src + num_pixels;
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "beq %[src], %[p_loop1_end], 3f \n\t"
+ " nop \n\t"
+ "0: \n\t"
+ "lw %[temp0], 0(%[src]) \n\t"
+ "lw %[temp1], 4(%[src]) \n\t"
+ "lw %[temp2], 8(%[src]) \n\t"
+ "lw %[temp3], 12(%[src]) \n\t"
+ "ext %[temp4], %[temp0], 28, 4 \n\t"
+ "ext %[temp5], %[temp0], 12, 4 \n\t"
+ "ins %[temp0], %[temp4], 0, 4 \n\t"
+ "ext %[temp4], %[temp1], 28, 4 \n\t"
+ "ins %[temp0], %[temp5], 16, 4 \n\t"
+ "ext %[temp5], %[temp1], 12, 4 \n\t"
+ "ins %[temp1], %[temp4], 0, 4 \n\t"
+ "ext %[temp4], %[temp2], 28, 4 \n\t"
+ "ins %[temp1], %[temp5], 16, 4 \n\t"
+ "ext %[temp5], %[temp2], 12, 4 \n\t"
+ "ins %[temp2], %[temp4], 0, 4 \n\t"
+ "ext %[temp4], %[temp3], 28, 4 \n\t"
+ "ins %[temp2], %[temp5], 16, 4 \n\t"
+ "ext %[temp5], %[temp3], 12, 4 \n\t"
+ "ins %[temp3], %[temp4], 0, 4 \n\t"
+ "precr.qb.ph %[temp1], %[temp1], %[temp0] \n\t"
+ "ins %[temp3], %[temp5], 16, 4 \n\t"
+ "addiu %[src], %[src], 16 \n\t"
+ "precr.qb.ph %[temp3], %[temp3], %[temp2] \n\t"
+#ifdef WEBP_SWAP_16BIT_CSP
+ "usw %[temp1], 0(%[dst]) \n\t"
+ "usw %[temp3], 4(%[dst]) \n\t"
+#else
+ "wsbh %[temp1], %[temp1] \n\t"
+ "wsbh %[temp3], %[temp3] \n\t"
+ "usw %[temp1], 0(%[dst]) \n\t"
+ "usw %[temp3], 4(%[dst]) \n\t"
+#endif
+ "bne %[src], %[p_loop1_end], 0b \n\t"
+ " addiu %[dst], %[dst], 8 \n\t"
+ "3: \n\t"
+ "beq %[src], %[p_loop2_end], 2f \n\t"
+ " nop \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[src]) \n\t"
+ "ext %[temp4], %[temp0], 28, 4 \n\t"
+ "ext %[temp5], %[temp0], 12, 4 \n\t"
+ "ins %[temp0], %[temp4], 0, 4 \n\t"
+ "ins %[temp0], %[temp5], 16, 4 \n\t"
+ "addiu %[src], %[src], 4 \n\t"
+ "precr.qb.ph %[temp0], %[temp0], %[temp0] \n\t"
+#ifdef WEBP_SWAP_16BIT_CSP
+ "ush %[temp0], 0(%[dst]) \n\t"
+#else
+ "wsbh %[temp0], %[temp0] \n\t"
+ "ush %[temp0], 0(%[dst]) \n\t"
+#endif
+ "bne %[src], %[p_loop2_end], 1b \n\t"
+ " addiu %[dst], %[dst], 2 \n\t"
+ "2: \n\t"
+ ".set pop \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [dst]"+&r"(dst), [src]"+&r"(src)
+ : [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end)
+ : "memory"
+ );
+}
+
+static void ConvertBGRAToRGB565(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ int temp0, temp1, temp2, temp3, temp4, temp5;
+ const uint32_t* const p_loop1_end = src + (num_pixels & ~3);
+ const uint32_t* const p_loop2_end = src + num_pixels;
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "beq %[src], %[p_loop1_end], 3f \n\t"
+ " nop \n\t"
+ "0: \n\t"
+ "lw %[temp0], 0(%[src]) \n\t"
+ "lw %[temp1], 4(%[src]) \n\t"
+ "lw %[temp2], 8(%[src]) \n\t"
+ "lw %[temp3], 12(%[src]) \n\t"
+ "ext %[temp4], %[temp0], 8, 16 \n\t"
+ "ext %[temp5], %[temp0], 5, 11 \n\t"
+ "ext %[temp0], %[temp0], 3, 5 \n\t"
+ "ins %[temp4], %[temp5], 0, 11 \n\t"
+ "ext %[temp5], %[temp1], 5, 11 \n\t"
+ "ins %[temp4], %[temp0], 0, 5 \n\t"
+ "ext %[temp0], %[temp1], 8, 16 \n\t"
+ "ext %[temp1], %[temp1], 3, 5 \n\t"
+ "ins %[temp0], %[temp5], 0, 11 \n\t"
+ "ext %[temp5], %[temp2], 5, 11 \n\t"
+ "ins %[temp0], %[temp1], 0, 5 \n\t"
+ "ext %[temp1], %[temp2], 8, 16 \n\t"
+ "ext %[temp2], %[temp2], 3, 5 \n\t"
+ "ins %[temp1], %[temp5], 0, 11 \n\t"
+ "ext %[temp5], %[temp3], 5, 11 \n\t"
+ "ins %[temp1], %[temp2], 0, 5 \n\t"
+ "ext %[temp2], %[temp3], 8, 16 \n\t"
+ "ext %[temp3], %[temp3], 3, 5 \n\t"
+ "ins %[temp2], %[temp5], 0, 11 \n\t"
+ "append %[temp0], %[temp4], 16 \n\t"
+ "ins %[temp2], %[temp3], 0, 5 \n\t"
+ "addiu %[src], %[src], 16 \n\t"
+ "append %[temp2], %[temp1], 16 \n\t"
+#ifdef WEBP_SWAP_16BIT_CSP
+ "usw %[temp0], 0(%[dst]) \n\t"
+ "usw %[temp2], 4(%[dst]) \n\t"
+#else
+ "wsbh %[temp0], %[temp0] \n\t"
+ "wsbh %[temp2], %[temp2] \n\t"
+ "usw %[temp0], 0(%[dst]) \n\t"
+ "usw %[temp2], 4(%[dst]) \n\t"
+#endif
+ "bne %[src], %[p_loop1_end], 0b \n\t"
+ " addiu %[dst], %[dst], 8 \n\t"
+ "3: \n\t"
+ "beq %[src], %[p_loop2_end], 2f \n\t"
+ " nop \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[src]) \n\t"
+ "ext %[temp4], %[temp0], 8, 16 \n\t"
+ "ext %[temp5], %[temp0], 5, 11 \n\t"
+ "ext %[temp0], %[temp0], 3, 5 \n\t"
+ "ins %[temp4], %[temp5], 0, 11 \n\t"
+ "addiu %[src], %[src], 4 \n\t"
+ "ins %[temp4], %[temp0], 0, 5 \n\t"
+#ifdef WEBP_SWAP_16BIT_CSP
+ "ush %[temp4], 0(%[dst]) \n\t"
+#else
+ "wsbh %[temp4], %[temp4] \n\t"
+ "ush %[temp4], 0(%[dst]) \n\t"
+#endif
+ "bne %[src], %[p_loop2_end], 1b \n\t"
+ " addiu %[dst], %[dst], 2 \n\t"
+ "2: \n\t"
+ ".set pop \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5),
+ [dst]"+&r"(dst), [src]"+&r"(src)
+ : [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end)
+ : "memory"
+ );
+}
+
+static void ConvertBGRAToBGR(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ int temp0, temp1, temp2, temp3;
+ const uint32_t* const p_loop1_end = src + (num_pixels & ~3);
+ const uint32_t* const p_loop2_end = src + num_pixels;
+ __asm__ volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "beq %[src], %[p_loop1_end], 3f \n\t"
+ " nop \n\t"
+ "0: \n\t"
+ "lw %[temp0], 0(%[src]) \n\t"
+ "lw %[temp1], 4(%[src]) \n\t"
+ "lw %[temp2], 8(%[src]) \n\t"
+ "lw %[temp3], 12(%[src]) \n\t"
+ "ins %[temp0], %[temp1], 24, 8 \n\t"
+ "sra %[temp1], %[temp1], 8 \n\t"
+ "ins %[temp1], %[temp2], 16, 16 \n\t"
+ "sll %[temp2], %[temp2], 8 \n\t"
+ "balign %[temp3], %[temp2], 1 \n\t"
+ "addiu %[src], %[src], 16 \n\t"
+ "usw %[temp0], 0(%[dst]) \n\t"
+ "usw %[temp1], 4(%[dst]) \n\t"
+ "usw %[temp3], 8(%[dst]) \n\t"
+ "bne %[src], %[p_loop1_end], 0b \n\t"
+ " addiu %[dst], %[dst], 12 \n\t"
+ "3: \n\t"
+ "beq %[src], %[p_loop2_end], 2f \n\t"
+ " nop \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[src]) \n\t"
+ "addiu %[src], %[src], 4 \n\t"
+ "addiu %[dst], %[dst], 3 \n\t"
+ "ush %[temp0], -3(%[dst]) \n\t"
+ "sra %[temp0], %[temp0], 16 \n\t"
+ "bne %[src], %[p_loop2_end], 1b \n\t"
+ " sb %[temp0], -1(%[dst]) \n\t"
+ "2: \n\t"
+ ".set pop \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2),
+ [temp3]"=&r"(temp3), [dst]"+&r"(dst), [src]"+&r"(src)
+ : [p_loop1_end]"r"(p_loop1_end), [p_loop2_end]"r"(p_loop2_end)
+ : "memory"
+ );
+}
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8LDspInitMIPSdspR2(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitMIPSdspR2(void) {
+ VP8LMapColor32b = MapARGB;
+ VP8LMapColor8b = MapAlpha;
+ VP8LPredictors[5] = Predictor5;
+ VP8LPredictors[6] = Predictor6;
+ VP8LPredictors[7] = Predictor7;
+ VP8LPredictors[8] = Predictor8;
+ VP8LPredictors[9] = Predictor9;
+ VP8LPredictors[10] = Predictor10;
+ VP8LPredictors[11] = Predictor11;
+ VP8LPredictors[12] = Predictor12;
+ VP8LPredictors[13] = Predictor13;
+ VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed;
+ VP8LTransformColorInverse = TransformColorInverse;
+ VP8LConvertBGRAToRGB = ConvertBGRAToRGB;
+ VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA;
+ VP8LConvertBGRAToRGBA4444 = ConvertBGRAToRGBA4444;
+ VP8LConvertBGRAToRGB565 = ConvertBGRAToRGB565;
+ VP8LConvertBGRAToBGR = ConvertBGRAToBGR;
+}
+
+#else // !WEBP_USE_MIPS_DSP_R2
+
+WEBP_DSP_INIT_STUB(VP8LDspInitMIPSdspR2)
+
+#endif // WEBP_USE_MIPS_DSP_R2
diff --git a/drivers/webp/dsp/lossless_neon.c b/drivers/webp/dsp/lossless_neon.c
new file mode 100644
index 0000000000..6faccb8f97
--- /dev/null
+++ b/drivers/webp/dsp/lossless_neon.c
@@ -0,0 +1,269 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// NEON variant of methods for lossless decoder
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_NEON)
+
+#include <arm_neon.h>
+
+#include "./lossless.h"
+#include "./neon.h"
+
+//------------------------------------------------------------------------------
+// Colorspace conversion functions
+
+#if !defined(WORK_AROUND_GCC)
+// gcc 4.6.0 had some trouble (NDK-r9) with this code. We only use it for
+// gcc-4.8.x at least.
+static void ConvertBGRAToRGBA(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ const uint32_t* const end = src + (num_pixels & ~15);
+ for (; src < end; src += 16) {
+ uint8x16x4_t pixel = vld4q_u8((uint8_t*)src);
+ // swap B and R. (VSWP d0,d2 has no intrinsics equivalent!)
+ const uint8x16_t tmp = pixel.val[0];
+ pixel.val[0] = pixel.val[2];
+ pixel.val[2] = tmp;
+ vst4q_u8(dst, pixel);
+ dst += 64;
+ }
+ VP8LConvertBGRAToRGBA_C(src, num_pixels & 15, dst); // left-overs
+}
+
+static void ConvertBGRAToBGR(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ const uint32_t* const end = src + (num_pixels & ~15);
+ for (; src < end; src += 16) {
+ const uint8x16x4_t pixel = vld4q_u8((uint8_t*)src);
+ const uint8x16x3_t tmp = { { pixel.val[0], pixel.val[1], pixel.val[2] } };
+ vst3q_u8(dst, tmp);
+ dst += 48;
+ }
+ VP8LConvertBGRAToBGR_C(src, num_pixels & 15, dst); // left-overs
+}
+
+static void ConvertBGRAToRGB(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ const uint32_t* const end = src + (num_pixels & ~15);
+ for (; src < end; src += 16) {
+ const uint8x16x4_t pixel = vld4q_u8((uint8_t*)src);
+ const uint8x16x3_t tmp = { { pixel.val[2], pixel.val[1], pixel.val[0] } };
+ vst3q_u8(dst, tmp);
+ dst += 48;
+ }
+ VP8LConvertBGRAToRGB_C(src, num_pixels & 15, dst); // left-overs
+}
+
+#else // WORK_AROUND_GCC
+
+// gcc-4.6.0 fallback
+
+static const uint8_t kRGBAShuffle[8] = { 2, 1, 0, 3, 6, 5, 4, 7 };
+
+static void ConvertBGRAToRGBA(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ const uint32_t* const end = src + (num_pixels & ~1);
+ const uint8x8_t shuffle = vld1_u8(kRGBAShuffle);
+ for (; src < end; src += 2) {
+ const uint8x8_t pixels = vld1_u8((uint8_t*)src);
+ vst1_u8(dst, vtbl1_u8(pixels, shuffle));
+ dst += 8;
+ }
+ VP8LConvertBGRAToRGBA_C(src, num_pixels & 1, dst); // left-overs
+}
+
+static const uint8_t kBGRShuffle[3][8] = {
+ { 0, 1, 2, 4, 5, 6, 8, 9 },
+ { 10, 12, 13, 14, 16, 17, 18, 20 },
+ { 21, 22, 24, 25, 26, 28, 29, 30 }
+};
+
+static void ConvertBGRAToBGR(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ const uint32_t* const end = src + (num_pixels & ~7);
+ const uint8x8_t shuffle0 = vld1_u8(kBGRShuffle[0]);
+ const uint8x8_t shuffle1 = vld1_u8(kBGRShuffle[1]);
+ const uint8x8_t shuffle2 = vld1_u8(kBGRShuffle[2]);
+ for (; src < end; src += 8) {
+ uint8x8x4_t pixels;
+ INIT_VECTOR4(pixels,
+ vld1_u8((const uint8_t*)(src + 0)),
+ vld1_u8((const uint8_t*)(src + 2)),
+ vld1_u8((const uint8_t*)(src + 4)),
+ vld1_u8((const uint8_t*)(src + 6)));
+ vst1_u8(dst + 0, vtbl4_u8(pixels, shuffle0));
+ vst1_u8(dst + 8, vtbl4_u8(pixels, shuffle1));
+ vst1_u8(dst + 16, vtbl4_u8(pixels, shuffle2));
+ dst += 8 * 3;
+ }
+ VP8LConvertBGRAToBGR_C(src, num_pixels & 7, dst); // left-overs
+}
+
+static const uint8_t kRGBShuffle[3][8] = {
+ { 2, 1, 0, 6, 5, 4, 10, 9 },
+ { 8, 14, 13, 12, 18, 17, 16, 22 },
+ { 21, 20, 26, 25, 24, 30, 29, 28 }
+};
+
+static void ConvertBGRAToRGB(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ const uint32_t* const end = src + (num_pixels & ~7);
+ const uint8x8_t shuffle0 = vld1_u8(kRGBShuffle[0]);
+ const uint8x8_t shuffle1 = vld1_u8(kRGBShuffle[1]);
+ const uint8x8_t shuffle2 = vld1_u8(kRGBShuffle[2]);
+ for (; src < end; src += 8) {
+ uint8x8x4_t pixels;
+ INIT_VECTOR4(pixels,
+ vld1_u8((const uint8_t*)(src + 0)),
+ vld1_u8((const uint8_t*)(src + 2)),
+ vld1_u8((const uint8_t*)(src + 4)),
+ vld1_u8((const uint8_t*)(src + 6)));
+ vst1_u8(dst + 0, vtbl4_u8(pixels, shuffle0));
+ vst1_u8(dst + 8, vtbl4_u8(pixels, shuffle1));
+ vst1_u8(dst + 16, vtbl4_u8(pixels, shuffle2));
+ dst += 8 * 3;
+ }
+ VP8LConvertBGRAToRGB_C(src, num_pixels & 7, dst); // left-overs
+}
+
+#endif // !WORK_AROUND_GCC
+
+//------------------------------------------------------------------------------
+// Subtract-Green Transform
+
+// vtbl?_u8 are marked unavailable for iOS arm64 with Xcode < 6.3, use
+// non-standard versions there.
+#if defined(__APPLE__) && defined(__aarch64__) && \
+ defined(__apple_build_version__) && (__apple_build_version__< 6020037)
+#define USE_VTBLQ
+#endif
+
+#ifdef USE_VTBLQ
+// 255 = byte will be zeroed
+static const uint8_t kGreenShuffle[16] = {
+ 1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, 13, 255, 13, 255
+};
+
+static WEBP_INLINE uint8x16_t DoGreenShuffle(const uint8x16_t argb,
+ const uint8x16_t shuffle) {
+ return vcombine_u8(vtbl1q_u8(argb, vget_low_u8(shuffle)),
+ vtbl1q_u8(argb, vget_high_u8(shuffle)));
+}
+#else // !USE_VTBLQ
+// 255 = byte will be zeroed
+static const uint8_t kGreenShuffle[8] = { 1, 255, 1, 255, 5, 255, 5, 255 };
+
+static WEBP_INLINE uint8x16_t DoGreenShuffle(const uint8x16_t argb,
+ const uint8x8_t shuffle) {
+ return vcombine_u8(vtbl1_u8(vget_low_u8(argb), shuffle),
+ vtbl1_u8(vget_high_u8(argb), shuffle));
+}
+#endif // USE_VTBLQ
+
+static void AddGreenToBlueAndRed(uint32_t* argb_data, int num_pixels) {
+ const uint32_t* const end = argb_data + (num_pixels & ~3);
+#ifdef USE_VTBLQ
+ const uint8x16_t shuffle = vld1q_u8(kGreenShuffle);
+#else
+ const uint8x8_t shuffle = vld1_u8(kGreenShuffle);
+#endif
+ for (; argb_data < end; argb_data += 4) {
+ const uint8x16_t argb = vld1q_u8((uint8_t*)argb_data);
+ const uint8x16_t greens = DoGreenShuffle(argb, shuffle);
+ vst1q_u8((uint8_t*)argb_data, vaddq_u8(argb, greens));
+ }
+ // fallthrough and finish off with plain-C
+ VP8LAddGreenToBlueAndRed_C(argb_data, num_pixels & 3);
+}
+
+//------------------------------------------------------------------------------
+// Color Transform
+
+static void TransformColorInverse(const VP8LMultipliers* const m,
+ uint32_t* argb_data, int num_pixels) {
+ // sign-extended multiplying constants, pre-shifted by 6.
+#define CST(X) (((int16_t)(m->X << 8)) >> 6)
+ const int16_t rb[8] = {
+ CST(green_to_blue_), CST(green_to_red_),
+ CST(green_to_blue_), CST(green_to_red_),
+ CST(green_to_blue_), CST(green_to_red_),
+ CST(green_to_blue_), CST(green_to_red_)
+ };
+ const int16x8_t mults_rb = vld1q_s16(rb);
+ const int16_t b2[8] = {
+ 0, CST(red_to_blue_), 0, CST(red_to_blue_),
+ 0, CST(red_to_blue_), 0, CST(red_to_blue_),
+ };
+ const int16x8_t mults_b2 = vld1q_s16(b2);
+#undef CST
+#ifdef USE_VTBLQ
+ static const uint8_t kg0g0[16] = {
+ 255, 1, 255, 1, 255, 5, 255, 5, 255, 9, 255, 9, 255, 13, 255, 13
+ };
+ const uint8x16_t shuffle = vld1q_u8(kg0g0);
+#else
+ static const uint8_t k0g0g[8] = { 255, 1, 255, 1, 255, 5, 255, 5 };
+ const uint8x8_t shuffle = vld1_u8(k0g0g);
+#endif
+ const uint32x4_t mask_ag = vdupq_n_u32(0xff00ff00u);
+ int i;
+ for (i = 0; i + 4 <= num_pixels; i += 4) {
+ const uint8x16_t in = vld1q_u8((uint8_t*)(argb_data + i));
+ const uint32x4_t a0g0 = vandq_u32(vreinterpretq_u32_u8(in), mask_ag);
+ // 0 g 0 g
+ const uint8x16_t greens = DoGreenShuffle(in, shuffle);
+ // x dr x db1
+ const int16x8_t A = vqdmulhq_s16(vreinterpretq_s16_u8(greens), mults_rb);
+ // x r' x b'
+ const int8x16_t B = vaddq_s8(vreinterpretq_s8_u8(in),
+ vreinterpretq_s8_s16(A));
+ // r' 0 b' 0
+ const int16x8_t C = vshlq_n_s16(vreinterpretq_s16_s8(B), 8);
+ // x db2 0 0
+ const int16x8_t D = vqdmulhq_s16(C, mults_b2);
+ // 0 x db2 0
+ const uint32x4_t E = vshrq_n_u32(vreinterpretq_u32_s16(D), 8);
+ // r' x b'' 0
+ const int8x16_t F = vaddq_s8(vreinterpretq_s8_u32(E),
+ vreinterpretq_s8_s16(C));
+ // 0 r' 0 b''
+ const uint16x8_t G = vshrq_n_u16(vreinterpretq_u16_s8(F), 8);
+ const uint32x4_t out = vorrq_u32(vreinterpretq_u32_u16(G), a0g0);
+ vst1q_u32(argb_data + i, out);
+ }
+ // Fall-back to C-version for left-overs.
+ VP8LTransformColorInverse_C(m, argb_data + i, num_pixels - i);
+}
+
+#undef USE_VTBLQ
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8LDspInitNEON(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitNEON(void) {
+ VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA;
+ VP8LConvertBGRAToBGR = ConvertBGRAToBGR;
+ VP8LConvertBGRAToRGB = ConvertBGRAToRGB;
+
+ VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed;
+ VP8LTransformColorInverse = TransformColorInverse;
+}
+
+#else // !WEBP_USE_NEON
+
+WEBP_DSP_INIT_STUB(VP8LDspInitNEON)
+
+#endif // WEBP_USE_NEON
diff --git a/drivers/webp/dsp/lossless_sse2.c b/drivers/webp/dsp/lossless_sse2.c
new file mode 100644
index 0000000000..2d016c2911
--- /dev/null
+++ b/drivers/webp/dsp/lossless_sse2.c
@@ -0,0 +1,372 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// SSE2 variant of methods for lossless decoder
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_SSE2)
+#include <assert.h>
+#include <emmintrin.h>
+#include "./lossless.h"
+
+//------------------------------------------------------------------------------
+// Predictor Transform
+
+static WEBP_INLINE uint32_t ClampedAddSubtractFull(uint32_t c0, uint32_t c1,
+ uint32_t c2) {
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i C0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c0), zero);
+ const __m128i C1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c1), zero);
+ const __m128i C2 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c2), zero);
+ const __m128i V1 = _mm_add_epi16(C0, C1);
+ const __m128i V2 = _mm_sub_epi16(V1, C2);
+ const __m128i b = _mm_packus_epi16(V2, V2);
+ const uint32_t output = _mm_cvtsi128_si32(b);
+ return output;
+}
+
+static WEBP_INLINE uint32_t ClampedAddSubtractHalf(uint32_t c0, uint32_t c1,
+ uint32_t c2) {
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i C0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c0), zero);
+ const __m128i C1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c1), zero);
+ const __m128i B0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(c2), zero);
+ const __m128i avg = _mm_add_epi16(C1, C0);
+ const __m128i A0 = _mm_srli_epi16(avg, 1);
+ const __m128i A1 = _mm_sub_epi16(A0, B0);
+ const __m128i BgtA = _mm_cmpgt_epi16(B0, A0);
+ const __m128i A2 = _mm_sub_epi16(A1, BgtA);
+ const __m128i A3 = _mm_srai_epi16(A2, 1);
+ const __m128i A4 = _mm_add_epi16(A0, A3);
+ const __m128i A5 = _mm_packus_epi16(A4, A4);
+ const uint32_t output = _mm_cvtsi128_si32(A5);
+ return output;
+}
+
+static WEBP_INLINE uint32_t Select(uint32_t a, uint32_t b, uint32_t c) {
+ int pa_minus_pb;
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i A0 = _mm_cvtsi32_si128(a);
+ const __m128i B0 = _mm_cvtsi32_si128(b);
+ const __m128i C0 = _mm_cvtsi32_si128(c);
+ const __m128i AC0 = _mm_subs_epu8(A0, C0);
+ const __m128i CA0 = _mm_subs_epu8(C0, A0);
+ const __m128i BC0 = _mm_subs_epu8(B0, C0);
+ const __m128i CB0 = _mm_subs_epu8(C0, B0);
+ const __m128i AC = _mm_or_si128(AC0, CA0);
+ const __m128i BC = _mm_or_si128(BC0, CB0);
+ const __m128i pa = _mm_unpacklo_epi8(AC, zero); // |a - c|
+ const __m128i pb = _mm_unpacklo_epi8(BC, zero); // |b - c|
+ const __m128i diff = _mm_sub_epi16(pb, pa);
+ {
+ int16_t out[8];
+ _mm_storeu_si128((__m128i*)out, diff);
+ pa_minus_pb = out[0] + out[1] + out[2] + out[3];
+ }
+ return (pa_minus_pb <= 0) ? a : b;
+}
+
+static WEBP_INLINE __m128i Average2_128i(uint32_t a0, uint32_t a1) {
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i A0 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(a0), zero);
+ const __m128i A1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(a1), zero);
+ const __m128i sum = _mm_add_epi16(A1, A0);
+ const __m128i avg = _mm_srli_epi16(sum, 1);
+ return avg;
+}
+
+static WEBP_INLINE uint32_t Average2(uint32_t a0, uint32_t a1) {
+ const __m128i avg = Average2_128i(a0, a1);
+ const __m128i A2 = _mm_packus_epi16(avg, avg);
+ const uint32_t output = _mm_cvtsi128_si32(A2);
+ return output;
+}
+
+static WEBP_INLINE uint32_t Average3(uint32_t a0, uint32_t a1, uint32_t a2) {
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i avg1 = Average2_128i(a0, a2);
+ const __m128i A1 = _mm_unpacklo_epi8(_mm_cvtsi32_si128(a1), zero);
+ const __m128i sum = _mm_add_epi16(avg1, A1);
+ const __m128i avg2 = _mm_srli_epi16(sum, 1);
+ const __m128i A2 = _mm_packus_epi16(avg2, avg2);
+ const uint32_t output = _mm_cvtsi128_si32(A2);
+ return output;
+}
+
+static WEBP_INLINE uint32_t Average4(uint32_t a0, uint32_t a1,
+ uint32_t a2, uint32_t a3) {
+ const __m128i avg1 = Average2_128i(a0, a1);
+ const __m128i avg2 = Average2_128i(a2, a3);
+ const __m128i sum = _mm_add_epi16(avg2, avg1);
+ const __m128i avg3 = _mm_srli_epi16(sum, 1);
+ const __m128i A0 = _mm_packus_epi16(avg3, avg3);
+ const uint32_t output = _mm_cvtsi128_si32(A0);
+ return output;
+}
+
+static uint32_t Predictor5(uint32_t left, const uint32_t* const top) {
+ const uint32_t pred = Average3(left, top[0], top[1]);
+ return pred;
+}
+static uint32_t Predictor6(uint32_t left, const uint32_t* const top) {
+ const uint32_t pred = Average2(left, top[-1]);
+ return pred;
+}
+static uint32_t Predictor7(uint32_t left, const uint32_t* const top) {
+ const uint32_t pred = Average2(left, top[0]);
+ return pred;
+}
+static uint32_t Predictor8(uint32_t left, const uint32_t* const top) {
+ const uint32_t pred = Average2(top[-1], top[0]);
+ (void)left;
+ return pred;
+}
+static uint32_t Predictor9(uint32_t left, const uint32_t* const top) {
+ const uint32_t pred = Average2(top[0], top[1]);
+ (void)left;
+ return pred;
+}
+static uint32_t Predictor10(uint32_t left, const uint32_t* const top) {
+ const uint32_t pred = Average4(left, top[-1], top[0], top[1]);
+ return pred;
+}
+static uint32_t Predictor11(uint32_t left, const uint32_t* const top) {
+ const uint32_t pred = Select(top[0], left, top[-1]);
+ return pred;
+}
+static uint32_t Predictor12(uint32_t left, const uint32_t* const top) {
+ const uint32_t pred = ClampedAddSubtractFull(left, top[0], top[-1]);
+ return pred;
+}
+static uint32_t Predictor13(uint32_t left, const uint32_t* const top) {
+ const uint32_t pred = ClampedAddSubtractHalf(left, top[0], top[-1]);
+ return pred;
+}
+
+//------------------------------------------------------------------------------
+// Subtract-Green Transform
+
+static void AddGreenToBlueAndRed(uint32_t* argb_data, int num_pixels) {
+ int i;
+ for (i = 0; i + 4 <= num_pixels; i += 4) {
+ const __m128i in = _mm_loadu_si128((__m128i*)&argb_data[i]); // argb
+ const __m128i A = _mm_srli_epi16(in, 8); // 0 a 0 g
+ const __m128i B = _mm_shufflelo_epi16(A, _MM_SHUFFLE(2, 2, 0, 0));
+ const __m128i C = _mm_shufflehi_epi16(B, _MM_SHUFFLE(2, 2, 0, 0)); // 0g0g
+ const __m128i out = _mm_add_epi8(in, C);
+ _mm_storeu_si128((__m128i*)&argb_data[i], out);
+ }
+ // fallthrough and finish off with plain-C
+ VP8LAddGreenToBlueAndRed_C(argb_data + i, num_pixels - i);
+}
+
+//------------------------------------------------------------------------------
+// Color Transform
+
+static void TransformColorInverse(const VP8LMultipliers* const m,
+ uint32_t* argb_data, int num_pixels) {
+ // sign-extended multiplying constants, pre-shifted by 5.
+#define CST(X) (((int16_t)(m->X << 8)) >> 5) // sign-extend
+ const __m128i mults_rb = _mm_set_epi16(
+ CST(green_to_red_), CST(green_to_blue_),
+ CST(green_to_red_), CST(green_to_blue_),
+ CST(green_to_red_), CST(green_to_blue_),
+ CST(green_to_red_), CST(green_to_blue_));
+ const __m128i mults_b2 = _mm_set_epi16(
+ CST(red_to_blue_), 0, CST(red_to_blue_), 0,
+ CST(red_to_blue_), 0, CST(red_to_blue_), 0);
+#undef CST
+ const __m128i mask_ag = _mm_set1_epi32(0xff00ff00); // alpha-green masks
+ int i;
+ for (i = 0; i + 4 <= num_pixels; i += 4) {
+ const __m128i in = _mm_loadu_si128((__m128i*)&argb_data[i]); // argb
+ const __m128i A = _mm_and_si128(in, mask_ag); // a 0 g 0
+ const __m128i B = _mm_shufflelo_epi16(A, _MM_SHUFFLE(2, 2, 0, 0));
+ const __m128i C = _mm_shufflehi_epi16(B, _MM_SHUFFLE(2, 2, 0, 0)); // g0g0
+ const __m128i D = _mm_mulhi_epi16(C, mults_rb); // x dr x db1
+ const __m128i E = _mm_add_epi8(in, D); // x r' x b'
+ const __m128i F = _mm_slli_epi16(E, 8); // r' 0 b' 0
+ const __m128i G = _mm_mulhi_epi16(F, mults_b2); // x db2 0 0
+ const __m128i H = _mm_srli_epi32(G, 8); // 0 x db2 0
+ const __m128i I = _mm_add_epi8(H, F); // r' x b'' 0
+ const __m128i J = _mm_srli_epi16(I, 8); // 0 r' 0 b''
+ const __m128i out = _mm_or_si128(J, A);
+ _mm_storeu_si128((__m128i*)&argb_data[i], out);
+ }
+ // Fall-back to C-version for left-overs.
+ VP8LTransformColorInverse_C(m, argb_data + i, num_pixels - i);
+}
+
+//------------------------------------------------------------------------------
+// Color-space conversion functions
+
+static void ConvertBGRAToRGBA(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ const __m128i* in = (const __m128i*)src;
+ __m128i* out = (__m128i*)dst;
+ while (num_pixels >= 8) {
+ const __m128i bgra0 = _mm_loadu_si128(in++); // bgra0|bgra1|bgra2|bgra3
+ const __m128i bgra4 = _mm_loadu_si128(in++); // bgra4|bgra5|bgra6|bgra7
+ const __m128i v0l = _mm_unpacklo_epi8(bgra0, bgra4); // b0b4g0g4r0r4a0a4...
+ const __m128i v0h = _mm_unpackhi_epi8(bgra0, bgra4); // b2b6g2g6r2r6a2a6...
+ const __m128i v1l = _mm_unpacklo_epi8(v0l, v0h); // b0b2b4b6g0g2g4g6...
+ const __m128i v1h = _mm_unpackhi_epi8(v0l, v0h); // b1b3b5b7g1g3g5g7...
+ const __m128i v2l = _mm_unpacklo_epi8(v1l, v1h); // b0...b7 | g0...g7
+ const __m128i v2h = _mm_unpackhi_epi8(v1l, v1h); // r0...r7 | a0...a7
+ const __m128i ga0 = _mm_unpackhi_epi64(v2l, v2h); // g0...g7 | a0...a7
+ const __m128i rb0 = _mm_unpacklo_epi64(v2h, v2l); // r0...r7 | b0...b7
+ const __m128i rg0 = _mm_unpacklo_epi8(rb0, ga0); // r0g0r1g1 ... r6g6r7g7
+ const __m128i ba0 = _mm_unpackhi_epi8(rb0, ga0); // b0a0b1a1 ... b6a6b7a7
+ const __m128i rgba0 = _mm_unpacklo_epi16(rg0, ba0); // rgba0|rgba1...
+ const __m128i rgba4 = _mm_unpackhi_epi16(rg0, ba0); // rgba4|rgba5...
+ _mm_storeu_si128(out++, rgba0);
+ _mm_storeu_si128(out++, rgba4);
+ num_pixels -= 8;
+ }
+ // left-overs
+ VP8LConvertBGRAToRGBA_C((const uint32_t*)in, num_pixels, (uint8_t*)out);
+}
+
+static void ConvertBGRAToRGBA4444(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ const __m128i mask_0x0f = _mm_set1_epi8(0x0f);
+ const __m128i mask_0xf0 = _mm_set1_epi8(0xf0);
+ const __m128i* in = (const __m128i*)src;
+ __m128i* out = (__m128i*)dst;
+ while (num_pixels >= 8) {
+ const __m128i bgra0 = _mm_loadu_si128(in++); // bgra0|bgra1|bgra2|bgra3
+ const __m128i bgra4 = _mm_loadu_si128(in++); // bgra4|bgra5|bgra6|bgra7
+ const __m128i v0l = _mm_unpacklo_epi8(bgra0, bgra4); // b0b4g0g4r0r4a0a4...
+ const __m128i v0h = _mm_unpackhi_epi8(bgra0, bgra4); // b2b6g2g6r2r6a2a6...
+ const __m128i v1l = _mm_unpacklo_epi8(v0l, v0h); // b0b2b4b6g0g2g4g6...
+ const __m128i v1h = _mm_unpackhi_epi8(v0l, v0h); // b1b3b5b7g1g3g5g7...
+ const __m128i v2l = _mm_unpacklo_epi8(v1l, v1h); // b0...b7 | g0...g7
+ const __m128i v2h = _mm_unpackhi_epi8(v1l, v1h); // r0...r7 | a0...a7
+ const __m128i ga0 = _mm_unpackhi_epi64(v2l, v2h); // g0...g7 | a0...a7
+ const __m128i rb0 = _mm_unpacklo_epi64(v2h, v2l); // r0...r7 | b0...b7
+ const __m128i ga1 = _mm_srli_epi16(ga0, 4); // g0-|g1-|...|a6-|a7-
+ const __m128i rb1 = _mm_and_si128(rb0, mask_0xf0); // -r0|-r1|...|-b6|-a7
+ const __m128i ga2 = _mm_and_si128(ga1, mask_0x0f); // g0-|g1-|...|a6-|a7-
+ const __m128i rgba0 = _mm_or_si128(ga2, rb1); // rg0..rg7 | ba0..ba7
+ const __m128i rgba1 = _mm_srli_si128(rgba0, 8); // ba0..ba7 | 0
+#ifdef WEBP_SWAP_16BIT_CSP
+ const __m128i rgba = _mm_unpacklo_epi8(rgba1, rgba0); // barg0...barg7
+#else
+ const __m128i rgba = _mm_unpacklo_epi8(rgba0, rgba1); // rgba0...rgba7
+#endif
+ _mm_storeu_si128(out++, rgba);
+ num_pixels -= 8;
+ }
+ // left-overs
+ VP8LConvertBGRAToRGBA4444_C((const uint32_t*)in, num_pixels, (uint8_t*)out);
+}
+
+static void ConvertBGRAToRGB565(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ const __m128i mask_0xe0 = _mm_set1_epi8(0xe0);
+ const __m128i mask_0xf8 = _mm_set1_epi8(0xf8);
+ const __m128i mask_0x07 = _mm_set1_epi8(0x07);
+ const __m128i* in = (const __m128i*)src;
+ __m128i* out = (__m128i*)dst;
+ while (num_pixels >= 8) {
+ const __m128i bgra0 = _mm_loadu_si128(in++); // bgra0|bgra1|bgra2|bgra3
+ const __m128i bgra4 = _mm_loadu_si128(in++); // bgra4|bgra5|bgra6|bgra7
+ const __m128i v0l = _mm_unpacklo_epi8(bgra0, bgra4); // b0b4g0g4r0r4a0a4...
+ const __m128i v0h = _mm_unpackhi_epi8(bgra0, bgra4); // b2b6g2g6r2r6a2a6...
+ const __m128i v1l = _mm_unpacklo_epi8(v0l, v0h); // b0b2b4b6g0g2g4g6...
+ const __m128i v1h = _mm_unpackhi_epi8(v0l, v0h); // b1b3b5b7g1g3g5g7...
+ const __m128i v2l = _mm_unpacklo_epi8(v1l, v1h); // b0...b7 | g0...g7
+ const __m128i v2h = _mm_unpackhi_epi8(v1l, v1h); // r0...r7 | a0...a7
+ const __m128i ga0 = _mm_unpackhi_epi64(v2l, v2h); // g0...g7 | a0...a7
+ const __m128i rb0 = _mm_unpacklo_epi64(v2h, v2l); // r0...r7 | b0...b7
+ const __m128i rb1 = _mm_and_si128(rb0, mask_0xf8); // -r0..-r7|-b0..-b7
+ const __m128i g_lo1 = _mm_srli_epi16(ga0, 5);
+ const __m128i g_lo2 = _mm_and_si128(g_lo1, mask_0x07); // g0-...g7-|xx (3b)
+ const __m128i g_hi1 = _mm_slli_epi16(ga0, 3);
+ const __m128i g_hi2 = _mm_and_si128(g_hi1, mask_0xe0); // -g0...-g7|xx (3b)
+ const __m128i b0 = _mm_srli_si128(rb1, 8); // -b0...-b7|0
+ const __m128i rg1 = _mm_or_si128(rb1, g_lo2); // gr0...gr7|xx
+ const __m128i b1 = _mm_srli_epi16(b0, 3);
+ const __m128i gb1 = _mm_or_si128(b1, g_hi2); // bg0...bg7|xx
+#ifdef WEBP_SWAP_16BIT_CSP
+ const __m128i rgba = _mm_unpacklo_epi8(gb1, rg1); // rggb0...rggb7
+#else
+ const __m128i rgba = _mm_unpacklo_epi8(rg1, gb1); // bgrb0...bgrb7
+#endif
+ _mm_storeu_si128(out++, rgba);
+ num_pixels -= 8;
+ }
+ // left-overs
+ VP8LConvertBGRAToRGB565_C((const uint32_t*)in, num_pixels, (uint8_t*)out);
+}
+
+static void ConvertBGRAToBGR(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ const __m128i mask_l = _mm_set_epi32(0, 0x00ffffff, 0, 0x00ffffff);
+ const __m128i mask_h = _mm_set_epi32(0x00ffffff, 0, 0x00ffffff, 0);
+ const __m128i* in = (const __m128i*)src;
+ const uint8_t* const end = dst + num_pixels * 3;
+ // the last storel_epi64 below writes 8 bytes starting at offset 18
+ while (dst + 26 <= end) {
+ const __m128i bgra0 = _mm_loadu_si128(in++); // bgra0|bgra1|bgra2|bgra3
+ const __m128i bgra4 = _mm_loadu_si128(in++); // bgra4|bgra5|bgra6|bgra7
+ const __m128i a0l = _mm_and_si128(bgra0, mask_l); // bgr0|0|bgr0|0
+ const __m128i a4l = _mm_and_si128(bgra4, mask_l); // bgr0|0|bgr0|0
+ const __m128i a0h = _mm_and_si128(bgra0, mask_h); // 0|bgr0|0|bgr0
+ const __m128i a4h = _mm_and_si128(bgra4, mask_h); // 0|bgr0|0|bgr0
+ const __m128i b0h = _mm_srli_epi64(a0h, 8); // 000b|gr00|000b|gr00
+ const __m128i b4h = _mm_srli_epi64(a4h, 8); // 000b|gr00|000b|gr00
+ const __m128i c0 = _mm_or_si128(a0l, b0h); // rgbrgb00|rgbrgb00
+ const __m128i c4 = _mm_or_si128(a4l, b4h); // rgbrgb00|rgbrgb00
+ const __m128i c2 = _mm_srli_si128(c0, 8);
+ const __m128i c6 = _mm_srli_si128(c4, 8);
+ _mm_storel_epi64((__m128i*)(dst + 0), c0);
+ _mm_storel_epi64((__m128i*)(dst + 6), c2);
+ _mm_storel_epi64((__m128i*)(dst + 12), c4);
+ _mm_storel_epi64((__m128i*)(dst + 18), c6);
+ dst += 24;
+ num_pixels -= 8;
+ }
+ // left-overs
+ VP8LConvertBGRAToBGR_C((const uint32_t*)in, num_pixels, dst);
+}
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void VP8LDspInitSSE2(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitSSE2(void) {
+ VP8LPredictors[5] = Predictor5;
+ VP8LPredictors[6] = Predictor6;
+ VP8LPredictors[7] = Predictor7;
+ VP8LPredictors[8] = Predictor8;
+ VP8LPredictors[9] = Predictor9;
+ VP8LPredictors[10] = Predictor10;
+ VP8LPredictors[11] = Predictor11;
+ VP8LPredictors[12] = Predictor12;
+ VP8LPredictors[13] = Predictor13;
+
+ VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed;
+ VP8LTransformColorInverse = TransformColorInverse;
+
+ VP8LConvertBGRAToRGBA = ConvertBGRAToRGBA;
+ VP8LConvertBGRAToRGBA4444 = ConvertBGRAToRGBA4444;
+ VP8LConvertBGRAToRGB565 = ConvertBGRAToRGB565;
+ VP8LConvertBGRAToBGR = ConvertBGRAToBGR;
+}
+
+#else // !WEBP_USE_SSE2
+
+WEBP_DSP_INIT_STUB(VP8LDspInitSSE2)
+
+#endif // WEBP_USE_SSE2
diff --git a/drivers/webp/dsp/mips_macro.h b/drivers/webp/dsp/mips_macro.h
new file mode 100644
index 0000000000..44aba9b71d
--- /dev/null
+++ b/drivers/webp/dsp/mips_macro.h
@@ -0,0 +1,200 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// MIPS common macros
+
+#ifndef WEBP_DSP_MIPS_MACRO_H_
+#define WEBP_DSP_MIPS_MACRO_H_
+
+#if defined(__GNUC__) && defined(__ANDROID__) && LOCAL_GCC_VERSION == 0x409
+#define WORK_AROUND_GCC
+#endif
+
+#define STR(s) #s
+#define XSTR(s) STR(s)
+
+// O0[31..16 | 15..0] = I0[31..16 | 15..0] + I1[31..16 | 15..0]
+// O1[31..16 | 15..0] = I0[31..16 | 15..0] - I1[31..16 | 15..0]
+// O - output
+// I - input (macro doesn't change it)
+#define ADD_SUB_HALVES(O0, O1, \
+ I0, I1) \
+ "addq.ph %[" #O0 "], %[" #I0 "], %[" #I1 "] \n\t" \
+ "subq.ph %[" #O1 "], %[" #I0 "], %[" #I1 "] \n\t"
+
+// O - output
+// I - input (macro doesn't change it)
+// I[0/1] - offset in bytes
+#define LOAD_IN_X2(O0, O1, \
+ I0, I1) \
+ "lh %[" #O0 "], " #I0 "(%[in]) \n\t" \
+ "lh %[" #O1 "], " #I1 "(%[in]) \n\t"
+
+// I0 - location
+// I1..I9 - offsets in bytes
+#define LOAD_WITH_OFFSET_X4(O0, O1, O2, O3, \
+ I0, I1, I2, I3, I4, I5, I6, I7, I8, I9) \
+ "ulw %[" #O0 "], " #I1 "+" XSTR(I9) "*" #I5 "(%[" #I0 "]) \n\t" \
+ "ulw %[" #O1 "], " #I2 "+" XSTR(I9) "*" #I6 "(%[" #I0 "]) \n\t" \
+ "ulw %[" #O2 "], " #I3 "+" XSTR(I9) "*" #I7 "(%[" #I0 "]) \n\t" \
+ "ulw %[" #O3 "], " #I4 "+" XSTR(I9) "*" #I8 "(%[" #I0 "]) \n\t"
+
+// O - output
+// IO - input/output
+// I - input (macro doesn't change it)
+#define MUL_SHIFT_SUM(O0, O1, O2, O3, O4, O5, O6, O7, \
+ IO0, IO1, IO2, IO3, \
+ I0, I1, I2, I3, I4, I5, I6, I7) \
+ "mul %[" #O0 "], %[" #I0 "], %[kC2] \n\t" \
+ "mul %[" #O1 "], %[" #I0 "], %[kC1] \n\t" \
+ "mul %[" #O2 "], %[" #I1 "], %[kC2] \n\t" \
+ "mul %[" #O3 "], %[" #I1 "], %[kC1] \n\t" \
+ "mul %[" #O4 "], %[" #I2 "], %[kC2] \n\t" \
+ "mul %[" #O5 "], %[" #I2 "], %[kC1] \n\t" \
+ "mul %[" #O6 "], %[" #I3 "], %[kC2] \n\t" \
+ "mul %[" #O7 "], %[" #I3 "], %[kC1] \n\t" \
+ "sra %[" #O0 "], %[" #O0 "], 16 \n\t" \
+ "sra %[" #O1 "], %[" #O1 "], 16 \n\t" \
+ "sra %[" #O2 "], %[" #O2 "], 16 \n\t" \
+ "sra %[" #O3 "], %[" #O3 "], 16 \n\t" \
+ "sra %[" #O4 "], %[" #O4 "], 16 \n\t" \
+ "sra %[" #O5 "], %[" #O5 "], 16 \n\t" \
+ "sra %[" #O6 "], %[" #O6 "], 16 \n\t" \
+ "sra %[" #O7 "], %[" #O7 "], 16 \n\t" \
+ "addu %[" #IO0 "], %[" #IO0 "], %[" #I4 "] \n\t" \
+ "addu %[" #IO1 "], %[" #IO1 "], %[" #I5 "] \n\t" \
+ "subu %[" #IO2 "], %[" #IO2 "], %[" #I6 "] \n\t" \
+ "subu %[" #IO3 "], %[" #IO3 "], %[" #I7 "] \n\t"
+
+// O - output
+// I - input (macro doesn't change it)
+#define INSERT_HALF_X2(O0, O1, \
+ I0, I1) \
+ "ins %[" #O0 "], %[" #I0 "], 16, 16 \n\t" \
+ "ins %[" #O1 "], %[" #I1 "], 16, 16 \n\t"
+
+// O - output
+// I - input (macro doesn't change it)
+#define SRA_16(O0, O1, O2, O3, \
+ I0, I1, I2, I3) \
+ "sra %[" #O0 "], %[" #I0 "], 16 \n\t" \
+ "sra %[" #O1 "], %[" #I1 "], 16 \n\t" \
+ "sra %[" #O2 "], %[" #I2 "], 16 \n\t" \
+ "sra %[" #O3 "], %[" #I3 "], 16 \n\t"
+
+// temp0[31..16 | 15..0] = temp8[31..16 | 15..0] + temp12[31..16 | 15..0]
+// temp1[31..16 | 15..0] = temp8[31..16 | 15..0] - temp12[31..16 | 15..0]
+// temp0[31..16 | 15..0] = temp0[31..16 >> 3 | 15..0 >> 3]
+// temp1[31..16 | 15..0] = temp1[31..16 >> 3 | 15..0 >> 3]
+// O - output
+// I - input (macro doesn't change it)
+#define SHIFT_R_SUM_X2(O0, O1, O2, O3, O4, O5, O6, O7, \
+ I0, I1, I2, I3, I4, I5, I6, I7) \
+ "addq.ph %[" #O0 "], %[" #I0 "], %[" #I4 "] \n\t" \
+ "subq.ph %[" #O1 "], %[" #I0 "], %[" #I4 "] \n\t" \
+ "addq.ph %[" #O2 "], %[" #I1 "], %[" #I5 "] \n\t" \
+ "subq.ph %[" #O3 "], %[" #I1 "], %[" #I5 "] \n\t" \
+ "addq.ph %[" #O4 "], %[" #I2 "], %[" #I6 "] \n\t" \
+ "subq.ph %[" #O5 "], %[" #I2 "], %[" #I6 "] \n\t" \
+ "addq.ph %[" #O6 "], %[" #I3 "], %[" #I7 "] \n\t" \
+ "subq.ph %[" #O7 "], %[" #I3 "], %[" #I7 "] \n\t" \
+ "shra.ph %[" #O0 "], %[" #O0 "], 3 \n\t" \
+ "shra.ph %[" #O1 "], %[" #O1 "], 3 \n\t" \
+ "shra.ph %[" #O2 "], %[" #O2 "], 3 \n\t" \
+ "shra.ph %[" #O3 "], %[" #O3 "], 3 \n\t" \
+ "shra.ph %[" #O4 "], %[" #O4 "], 3 \n\t" \
+ "shra.ph %[" #O5 "], %[" #O5 "], 3 \n\t" \
+ "shra.ph %[" #O6 "], %[" #O6 "], 3 \n\t" \
+ "shra.ph %[" #O7 "], %[" #O7 "], 3 \n\t"
+
+// precrq.ph.w temp0, temp8, temp2
+// temp0 = temp8[31..16] | temp2[31..16]
+// ins temp2, temp8, 16, 16
+// temp2 = temp8[31..16] | temp2[15..0]
+// O - output
+// IO - input/output
+// I - input (macro doesn't change it)
+#define PACK_2_HALVES_TO_WORD(O0, O1, O2, O3, \
+ IO0, IO1, IO2, IO3, \
+ I0, I1, I2, I3) \
+ "precrq.ph.w %[" #O0 "], %[" #I0 "], %[" #IO0 "] \n\t" \
+ "precrq.ph.w %[" #O1 "], %[" #I1 "], %[" #IO1 "] \n\t" \
+ "ins %[" #IO0 "], %[" #I0 "], 16, 16 \n\t" \
+ "ins %[" #IO1 "], %[" #I1 "], 16, 16 \n\t" \
+ "precrq.ph.w %[" #O2 "], %[" #I2 "], %[" #IO2 "] \n\t" \
+ "precrq.ph.w %[" #O3 "], %[" #I3 "], %[" #IO3 "] \n\t" \
+ "ins %[" #IO2 "], %[" #I2 "], 16, 16 \n\t" \
+ "ins %[" #IO3 "], %[" #I3 "], 16, 16 \n\t"
+
+// preceu.ph.qbr temp0, temp8
+// temp0 = 0 | 0 | temp8[23..16] | temp8[7..0]
+// preceu.ph.qbl temp1, temp8
+// temp1 = temp8[23..16] | temp8[7..0] | 0 | 0
+// O - output
+// I - input (macro doesn't change it)
+#define CONVERT_2_BYTES_TO_HALF(O0, O1, O2, O3, O4, O5, O6, O7, \
+ I0, I1, I2, I3) \
+ "preceu.ph.qbr %[" #O0 "], %[" #I0 "] \n\t" \
+ "preceu.ph.qbl %[" #O1 "], %[" #I0 "] \n\t" \
+ "preceu.ph.qbr %[" #O2 "], %[" #I1 "] \n\t" \
+ "preceu.ph.qbl %[" #O3 "], %[" #I1 "] \n\t" \
+ "preceu.ph.qbr %[" #O4 "], %[" #I2 "] \n\t" \
+ "preceu.ph.qbl %[" #O5 "], %[" #I2 "] \n\t" \
+ "preceu.ph.qbr %[" #O6 "], %[" #I3 "] \n\t" \
+ "preceu.ph.qbl %[" #O7 "], %[" #I3 "] \n\t"
+
+// temp0[31..16 | 15..0] = temp0[31..16 | 15..0] + temp8[31..16 | 15..0]
+// temp0[31..16 | 15..0] = temp0[31..16 <<(s) 7 | 15..0 <<(s) 7]
+// temp1..temp7 same as temp0
+// precrqu_s.qb.ph temp0, temp1, temp0:
+// temp0 = temp1[31..24] | temp1[15..8] | temp0[31..24] | temp0[15..8]
+// store temp0 to dst
+// IO - input/output
+// I - input (macro doesn't change it)
+#define STORE_SAT_SUM_X2(IO0, IO1, IO2, IO3, IO4, IO5, IO6, IO7, \
+ I0, I1, I2, I3, I4, I5, I6, I7, \
+ I8, I9, I10, I11, I12, I13) \
+ "addq.ph %[" #IO0 "], %[" #IO0 "], %[" #I0 "] \n\t" \
+ "addq.ph %[" #IO1 "], %[" #IO1 "], %[" #I1 "] \n\t" \
+ "addq.ph %[" #IO2 "], %[" #IO2 "], %[" #I2 "] \n\t" \
+ "addq.ph %[" #IO3 "], %[" #IO3 "], %[" #I3 "] \n\t" \
+ "addq.ph %[" #IO4 "], %[" #IO4 "], %[" #I4 "] \n\t" \
+ "addq.ph %[" #IO5 "], %[" #IO5 "], %[" #I5 "] \n\t" \
+ "addq.ph %[" #IO6 "], %[" #IO6 "], %[" #I6 "] \n\t" \
+ "addq.ph %[" #IO7 "], %[" #IO7 "], %[" #I7 "] \n\t" \
+ "shll_s.ph %[" #IO0 "], %[" #IO0 "], 7 \n\t" \
+ "shll_s.ph %[" #IO1 "], %[" #IO1 "], 7 \n\t" \
+ "shll_s.ph %[" #IO2 "], %[" #IO2 "], 7 \n\t" \
+ "shll_s.ph %[" #IO3 "], %[" #IO3 "], 7 \n\t" \
+ "shll_s.ph %[" #IO4 "], %[" #IO4 "], 7 \n\t" \
+ "shll_s.ph %[" #IO5 "], %[" #IO5 "], 7 \n\t" \
+ "shll_s.ph %[" #IO6 "], %[" #IO6 "], 7 \n\t" \
+ "shll_s.ph %[" #IO7 "], %[" #IO7 "], 7 \n\t" \
+ "precrqu_s.qb.ph %[" #IO0 "], %[" #IO1 "], %[" #IO0 "] \n\t" \
+ "precrqu_s.qb.ph %[" #IO2 "], %[" #IO3 "], %[" #IO2 "] \n\t" \
+ "precrqu_s.qb.ph %[" #IO4 "], %[" #IO5 "], %[" #IO4 "] \n\t" \
+ "precrqu_s.qb.ph %[" #IO6 "], %[" #IO7 "], %[" #IO6 "] \n\t" \
+ "usw %[" #IO0 "], " XSTR(I13) "*" #I9 "(%[" #I8 "]) \n\t" \
+ "usw %[" #IO2 "], " XSTR(I13) "*" #I10 "(%[" #I8 "]) \n\t" \
+ "usw %[" #IO4 "], " XSTR(I13) "*" #I11 "(%[" #I8 "]) \n\t" \
+ "usw %[" #IO6 "], " XSTR(I13) "*" #I12 "(%[" #I8 "]) \n\t"
+
+#define OUTPUT_EARLY_CLOBBER_REGS_10() \
+ : [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), \
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [temp6]"=&r"(temp6), \
+ [temp7]"=&r"(temp7), [temp8]"=&r"(temp8), [temp9]"=&r"(temp9), \
+ [temp10]"=&r"(temp10)
+
+#define OUTPUT_EARLY_CLOBBER_REGS_18() \
+ OUTPUT_EARLY_CLOBBER_REGS_10(), \
+ [temp11]"=&r"(temp11), [temp12]"=&r"(temp12), [temp13]"=&r"(temp13), \
+ [temp14]"=&r"(temp14), [temp15]"=&r"(temp15), [temp16]"=&r"(temp16), \
+ [temp17]"=&r"(temp17), [temp18]"=&r"(temp18)
+
+#endif // WEBP_DSP_MIPS_MACRO_H_
diff --git a/drivers/webp/dsp/neon.h b/drivers/webp/dsp/neon.h
new file mode 100644
index 0000000000..0a06266848
--- /dev/null
+++ b/drivers/webp/dsp/neon.h
@@ -0,0 +1,82 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// NEON common code.
+
+#ifndef WEBP_DSP_NEON_H_
+#define WEBP_DSP_NEON_H_
+
+#include <arm_neon.h>
+
+#include "./dsp.h"
+
+// Right now, some intrinsics functions seem slower, so we disable them
+// everywhere except aarch64 where the inline assembly is incompatible.
+#if defined(__aarch64__)
+#define WEBP_USE_INTRINSICS // use intrinsics when possible
+#endif
+
+#define INIT_VECTOR2(v, a, b) do { \
+ v.val[0] = a; \
+ v.val[1] = b; \
+} while (0)
+
+#define INIT_VECTOR3(v, a, b, c) do { \
+ v.val[0] = a; \
+ v.val[1] = b; \
+ v.val[2] = c; \
+} while (0)
+
+#define INIT_VECTOR4(v, a, b, c, d) do { \
+ v.val[0] = a; \
+ v.val[1] = b; \
+ v.val[2] = c; \
+ v.val[3] = d; \
+} while (0)
+
+// if using intrinsics, this flag avoids some functions that make gcc-4.6.3
+// crash ("internal compiler error: in immed_double_const, at emit-rtl.").
+// (probably similar to gcc.gnu.org/bugzilla/show_bug.cgi?id=48183)
+#if !(LOCAL_GCC_PREREQ(4,8) || defined(__aarch64__))
+#define WORK_AROUND_GCC
+#endif
+
+static WEBP_INLINE int32x4x4_t Transpose4x4(const int32x4x4_t rows) {
+ uint64x2x2_t row01, row23;
+
+ row01.val[0] = vreinterpretq_u64_s32(rows.val[0]);
+ row01.val[1] = vreinterpretq_u64_s32(rows.val[1]);
+ row23.val[0] = vreinterpretq_u64_s32(rows.val[2]);
+ row23.val[1] = vreinterpretq_u64_s32(rows.val[3]);
+ // Transpose 64-bit values (there's no vswp equivalent)
+ {
+ const uint64x1_t row0h = vget_high_u64(row01.val[0]);
+ const uint64x1_t row2l = vget_low_u64(row23.val[0]);
+ const uint64x1_t row1h = vget_high_u64(row01.val[1]);
+ const uint64x1_t row3l = vget_low_u64(row23.val[1]);
+ row01.val[0] = vcombine_u64(vget_low_u64(row01.val[0]), row2l);
+ row23.val[0] = vcombine_u64(row0h, vget_high_u64(row23.val[0]));
+ row01.val[1] = vcombine_u64(vget_low_u64(row01.val[1]), row3l);
+ row23.val[1] = vcombine_u64(row1h, vget_high_u64(row23.val[1]));
+ }
+ {
+ const int32x4x2_t out01 = vtrnq_s32(vreinterpretq_s32_u64(row01.val[0]),
+ vreinterpretq_s32_u64(row01.val[1]));
+ const int32x4x2_t out23 = vtrnq_s32(vreinterpretq_s32_u64(row23.val[0]),
+ vreinterpretq_s32_u64(row23.val[1]));
+ int32x4x4_t out;
+ out.val[0] = out01.val[0];
+ out.val[1] = out01.val[1];
+ out.val[2] = out23.val[0];
+ out.val[3] = out23.val[1];
+ return out;
+ }
+}
+
+#endif // WEBP_DSP_NEON_H_
diff --git a/drivers/webp/dsp/rescaler.c b/drivers/webp/dsp/rescaler.c
new file mode 100644
index 0000000000..bc743d5dc5
--- /dev/null
+++ b/drivers/webp/dsp/rescaler.c
@@ -0,0 +1,238 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Rescaling functions
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <assert.h>
+
+#include "./dsp.h"
+#include "../utils/rescaler.h"
+
+//------------------------------------------------------------------------------
+// Implementations of critical functions ImportRow / ExportRow
+
+#define ROUNDER (WEBP_RESCALER_ONE >> 1)
+#define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
+
+//------------------------------------------------------------------------------
+// Row import
+
+void WebPRescalerImportRowExpandC(WebPRescaler* const wrk, const uint8_t* src) {
+ const int x_stride = wrk->num_channels;
+ const int x_out_max = wrk->dst_width * wrk->num_channels;
+ int channel;
+ assert(!WebPRescalerInputDone(wrk));
+ assert(wrk->x_expand);
+ for (channel = 0; channel < x_stride; ++channel) {
+ int x_in = channel;
+ int x_out = channel;
+ // simple bilinear interpolation
+ int accum = wrk->x_add;
+ int left = src[x_in];
+ int right = (wrk->src_width > 1) ? src[x_in + x_stride] : left;
+ x_in += x_stride;
+ while (1) {
+ wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum;
+ x_out += x_stride;
+ if (x_out >= x_out_max) break;
+ accum -= wrk->x_sub;
+ if (accum < 0) {
+ left = right;
+ x_in += x_stride;
+ assert(x_in < wrk->src_width * x_stride);
+ right = src[x_in];
+ accum += wrk->x_add;
+ }
+ }
+ assert(wrk->x_sub == 0 /* <- special case for src_width=1 */ || accum == 0);
+ }
+}
+
+void WebPRescalerImportRowShrinkC(WebPRescaler* const wrk, const uint8_t* src) {
+ const int x_stride = wrk->num_channels;
+ const int x_out_max = wrk->dst_width * wrk->num_channels;
+ int channel;
+ assert(!WebPRescalerInputDone(wrk));
+ assert(!wrk->x_expand);
+ for (channel = 0; channel < x_stride; ++channel) {
+ int x_in = channel;
+ int x_out = channel;
+ uint32_t sum = 0;
+ int accum = 0;
+ while (x_out < x_out_max) {
+ uint32_t base = 0;
+ accum += wrk->x_add;
+ while (accum > 0) {
+ accum -= wrk->x_sub;
+ assert(x_in < wrk->src_width * x_stride);
+ base = src[x_in];
+ sum += base;
+ x_in += x_stride;
+ }
+ { // Emit next horizontal pixel.
+ const rescaler_t frac = base * (-accum);
+ wrk->frow[x_out] = sum * wrk->x_sub - frac;
+ // fresh fractional start for next pixel
+ sum = (int)MULT_FIX(frac, wrk->fx_scale);
+ }
+ x_out += x_stride;
+ }
+ assert(accum == 0);
+ }
+}
+
+//------------------------------------------------------------------------------
+// Row export
+
+void WebPRescalerExportRowExpandC(WebPRescaler* const wrk) {
+ int x_out;
+ uint8_t* const dst = wrk->dst;
+ rescaler_t* const irow = wrk->irow;
+ const int x_out_max = wrk->dst_width * wrk->num_channels;
+ const rescaler_t* const frow = wrk->frow;
+ assert(!WebPRescalerOutputDone(wrk));
+ assert(wrk->y_accum <= 0);
+ assert(wrk->y_expand);
+ assert(wrk->y_sub != 0);
+ if (wrk->y_accum == 0) {
+ for (x_out = 0; x_out < x_out_max; ++x_out) {
+ const uint32_t J = frow[x_out];
+ const int v = (int)MULT_FIX(J, wrk->fy_scale);
+ assert(v >= 0 && v <= 255);
+ dst[x_out] = v;
+ }
+ } else {
+ const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
+ const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B);
+ for (x_out = 0; x_out < x_out_max; ++x_out) {
+ const uint64_t I = (uint64_t)A * frow[x_out]
+ + (uint64_t)B * irow[x_out];
+ const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
+ const int v = (int)MULT_FIX(J, wrk->fy_scale);
+ assert(v >= 0 && v <= 255);
+ dst[x_out] = v;
+ }
+ }
+}
+
+void WebPRescalerExportRowShrinkC(WebPRescaler* const wrk) {
+ int x_out;
+ uint8_t* const dst = wrk->dst;
+ rescaler_t* const irow = wrk->irow;
+ const int x_out_max = wrk->dst_width * wrk->num_channels;
+ const rescaler_t* const frow = wrk->frow;
+ const uint32_t yscale = wrk->fy_scale * (-wrk->y_accum);
+ assert(!WebPRescalerOutputDone(wrk));
+ assert(wrk->y_accum <= 0);
+ assert(!wrk->y_expand);
+ if (yscale) {
+ for (x_out = 0; x_out < x_out_max; ++x_out) {
+ const uint32_t frac = (uint32_t)MULT_FIX(frow[x_out], yscale);
+ const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
+ assert(v >= 0 && v <= 255);
+ dst[x_out] = v;
+ irow[x_out] = frac; // new fractional start
+ }
+ } else {
+ for (x_out = 0; x_out < x_out_max; ++x_out) {
+ const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale);
+ assert(v >= 0 && v <= 255);
+ dst[x_out] = v;
+ irow[x_out] = 0;
+ }
+ }
+}
+
+#undef MULT_FIX
+#undef ROUNDER
+
+//------------------------------------------------------------------------------
+// Main entry calls
+
+void WebPRescalerImportRow(WebPRescaler* const wrk, const uint8_t* src) {
+ assert(!WebPRescalerInputDone(wrk));
+ if (!wrk->x_expand) {
+ WebPRescalerImportRowShrink(wrk, src);
+ } else {
+ WebPRescalerImportRowExpand(wrk, src);
+ }
+}
+
+void WebPRescalerExportRow(WebPRescaler* const wrk) {
+ if (wrk->y_accum <= 0) {
+ assert(!WebPRescalerOutputDone(wrk));
+ if (wrk->y_expand) {
+ WebPRescalerExportRowExpand(wrk);
+ } else if (wrk->fxy_scale) {
+ WebPRescalerExportRowShrink(wrk);
+ } else { // very special case for src = dst = 1x1
+ int i;
+ assert(wrk->src_width == 1 && wrk->dst_width <= 2);
+ assert(wrk->src_height == 1 && wrk->dst_height == 1);
+ for (i = 0; i < wrk->num_channels * wrk->dst_width; ++i) {
+ wrk->dst[i] = wrk->irow[i];
+ wrk->irow[i] = 0;
+ }
+ }
+ wrk->y_accum += wrk->y_add;
+ wrk->dst += wrk->dst_stride;
+ ++wrk->dst_y;
+ }
+}
+
+//------------------------------------------------------------------------------
+
+WebPRescalerImportRowFunc WebPRescalerImportRowExpand;
+WebPRescalerImportRowFunc WebPRescalerImportRowShrink;
+
+WebPRescalerExportRowFunc WebPRescalerExportRowExpand;
+WebPRescalerExportRowFunc WebPRescalerExportRowShrink;
+
+extern void WebPRescalerDspInitSSE2(void);
+extern void WebPRescalerDspInitMIPS32(void);
+extern void WebPRescalerDspInitMIPSdspR2(void);
+extern void WebPRescalerDspInitNEON(void);
+
+static volatile VP8CPUInfo rescaler_last_cpuinfo_used =
+ (VP8CPUInfo)&rescaler_last_cpuinfo_used;
+
+WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInit(void) {
+ if (rescaler_last_cpuinfo_used == VP8GetCPUInfo) return;
+
+ WebPRescalerImportRowExpand = WebPRescalerImportRowExpandC;
+ WebPRescalerImportRowShrink = WebPRescalerImportRowShrinkC;
+ WebPRescalerExportRowExpand = WebPRescalerExportRowExpandC;
+ WebPRescalerExportRowShrink = WebPRescalerExportRowShrinkC;
+
+ if (VP8GetCPUInfo != NULL) {
+#if defined(WEBP_USE_SSE2)
+ if (VP8GetCPUInfo(kSSE2)) {
+ WebPRescalerDspInitSSE2();
+ }
+#endif
+#if defined(WEBP_USE_NEON)
+ if (VP8GetCPUInfo(kNEON)) {
+ WebPRescalerDspInitNEON();
+ }
+#endif
+#if defined(WEBP_USE_MIPS32)
+ if (VP8GetCPUInfo(kMIPS32)) {
+ WebPRescalerDspInitMIPS32();
+ }
+#endif
+#if defined(WEBP_USE_MIPS_DSP_R2)
+ if (VP8GetCPUInfo(kMIPSdspR2)) {
+ WebPRescalerDspInitMIPSdspR2();
+ }
+#endif
+ }
+ rescaler_last_cpuinfo_used = VP8GetCPUInfo;
+}
diff --git a/drivers/webp/dsp/rescaler_mips32.c b/drivers/webp/dsp/rescaler_mips32.c
new file mode 100644
index 0000000000..ddaa391336
--- /dev/null
+++ b/drivers/webp/dsp/rescaler_mips32.c
@@ -0,0 +1,291 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// MIPS version of rescaling functions
+//
+// Author(s): Djordje Pesut (djordje.pesut@imgtec.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_MIPS32)
+
+#include <assert.h>
+#include "../utils/rescaler.h"
+
+//------------------------------------------------------------------------------
+// Row import
+
+static void ImportRowShrink(WebPRescaler* const wrk, const uint8_t* src) {
+ const int x_stride = wrk->num_channels;
+ const int x_out_max = wrk->dst_width * wrk->num_channels;
+ const int fx_scale = wrk->fx_scale;
+ const int x_add = wrk->x_add;
+ const int x_sub = wrk->x_sub;
+ const int x_stride1 = x_stride << 2;
+ int channel;
+ assert(!wrk->x_expand);
+ assert(!WebPRescalerInputDone(wrk));
+
+ for (channel = 0; channel < x_stride; ++channel) {
+ const uint8_t* src1 = src + channel;
+ rescaler_t* frow = wrk->frow + channel;
+ int temp1, temp2, temp3;
+ int base, frac, sum;
+ int accum, accum1;
+ int loop_c = x_out_max - channel;
+
+ __asm__ volatile (
+ "li %[temp1], 0x8000 \n\t"
+ "li %[temp2], 0x10000 \n\t"
+ "li %[sum], 0 \n\t"
+ "li %[accum], 0 \n\t"
+ "1: \n\t"
+ "addu %[accum], %[accum], %[x_add] \n\t"
+ "li %[base], 0 \n\t"
+ "blez %[accum], 3f \n\t"
+ "2: \n\t"
+ "lbu %[base], 0(%[src1]) \n\t"
+ "subu %[accum], %[accum], %[x_sub] \n\t"
+ "addu %[src1], %[src1], %[x_stride] \n\t"
+ "addu %[sum], %[sum], %[base] \n\t"
+ "bgtz %[accum], 2b \n\t"
+ "3: \n\t"
+ "negu %[accum1], %[accum] \n\t"
+ "mul %[frac], %[base], %[accum1] \n\t"
+ "mul %[temp3], %[sum], %[x_sub] \n\t"
+ "subu %[loop_c], %[loop_c], %[x_stride] \n\t"
+ "mult %[temp1], %[temp2] \n\t"
+ "maddu %[frac], %[fx_scale] \n\t"
+ "mfhi %[sum] \n\t"
+ "subu %[temp3], %[temp3], %[frac] \n\t"
+ "sw %[temp3], 0(%[frow]) \n\t"
+ "addu %[frow], %[frow], %[x_stride1] \n\t"
+ "bgtz %[loop_c], 1b \n\t"
+ : [accum]"=&r"(accum), [src1]"+r"(src1), [temp3]"=&r"(temp3),
+ [sum]"=&r"(sum), [base]"=&r"(base), [frac]"=&r"(frac),
+ [frow]"+r"(frow), [accum1]"=&r"(accum1),
+ [temp2]"=&r"(temp2), [temp1]"=&r"(temp1)
+ : [x_stride]"r"(x_stride), [fx_scale]"r"(fx_scale),
+ [x_sub]"r"(x_sub), [x_add]"r"(x_add),
+ [loop_c]"r"(loop_c), [x_stride1]"r"(x_stride1)
+ : "memory", "hi", "lo"
+ );
+ assert(accum == 0);
+ }
+}
+
+static void ImportRowExpand(WebPRescaler* const wrk, const uint8_t* src) {
+ const int x_stride = wrk->num_channels;
+ const int x_out_max = wrk->dst_width * wrk->num_channels;
+ const int x_add = wrk->x_add;
+ const int x_sub = wrk->x_sub;
+ const int src_width = wrk->src_width;
+ const int x_stride1 = x_stride << 2;
+ int channel;
+ assert(wrk->x_expand);
+ assert(!WebPRescalerInputDone(wrk));
+
+ for (channel = 0; channel < x_stride; ++channel) {
+ const uint8_t* src1 = src + channel;
+ rescaler_t* frow = wrk->frow + channel;
+ int temp1, temp2, temp3, temp4;
+ int frac;
+ int accum;
+ int x_out = channel;
+
+ __asm__ volatile (
+ "addiu %[temp3], %[src_width], -1 \n\t"
+ "lbu %[temp2], 0(%[src1]) \n\t"
+ "addu %[src1], %[src1], %[x_stride] \n\t"
+ "bgtz %[temp3], 0f \n\t"
+ "addiu %[temp1], %[temp2], 0 \n\t"
+ "b 3f \n\t"
+ "0: \n\t"
+ "lbu %[temp1], 0(%[src1]) \n\t"
+ "3: \n\t"
+ "addiu %[accum], %[x_add], 0 \n\t"
+ "1: \n\t"
+ "subu %[temp3], %[temp2], %[temp1] \n\t"
+ "mul %[temp3], %[temp3], %[accum] \n\t"
+ "mul %[temp4], %[temp1], %[x_add] \n\t"
+ "addu %[temp3], %[temp4], %[temp3] \n\t"
+ "sw %[temp3], 0(%[frow]) \n\t"
+ "addu %[frow], %[frow], %[x_stride1] \n\t"
+ "addu %[x_out], %[x_out], %[x_stride] \n\t"
+ "subu %[temp3], %[x_out], %[x_out_max] \n\t"
+ "bgez %[temp3], 2f \n\t"
+ "subu %[accum], %[accum], %[x_sub] \n\t"
+ "bgez %[accum], 4f \n\t"
+ "addiu %[temp2], %[temp1], 0 \n\t"
+ "addu %[src1], %[src1], %[x_stride] \n\t"
+ "lbu %[temp1], 0(%[src1]) \n\t"
+ "addu %[accum], %[accum], %[x_add] \n\t"
+ "4: \n\t"
+ "b 1b \n\t"
+ "2: \n\t"
+ : [src1]"+r"(src1), [accum]"=&r"(accum), [temp1]"=&r"(temp1),
+ [temp2]"=&r"(temp2), [temp3]"=&r"(temp3), [temp4]"=&r"(temp4),
+ [x_out]"+r"(x_out), [frac]"=&r"(frac), [frow]"+r"(frow)
+ : [x_stride]"r"(x_stride), [x_add]"r"(x_add), [x_sub]"r"(x_sub),
+ [x_stride1]"r"(x_stride1), [src_width]"r"(src_width),
+ [x_out_max]"r"(x_out_max)
+ : "memory", "hi", "lo"
+ );
+ assert(wrk->x_sub == 0 /* <- special case for src_width=1 */ || accum == 0);
+ }
+}
+
+//------------------------------------------------------------------------------
+// Row export
+
+static void ExportRowExpand(WebPRescaler* const wrk) {
+ uint8_t* dst = wrk->dst;
+ rescaler_t* irow = wrk->irow;
+ const int x_out_max = wrk->dst_width * wrk->num_channels;
+ const rescaler_t* frow = wrk->frow;
+ int temp0, temp1, temp3, temp4, temp5, loop_end;
+ const int temp2 = (int)wrk->fy_scale;
+ const int temp6 = x_out_max << 2;
+ assert(!WebPRescalerOutputDone(wrk));
+ assert(wrk->y_accum <= 0);
+ assert(wrk->y_expand);
+ assert(wrk->y_sub != 0);
+ if (wrk->y_accum == 0) {
+ __asm__ volatile (
+ "li %[temp3], 0x10000 \n\t"
+ "li %[temp4], 0x8000 \n\t"
+ "addu %[loop_end], %[frow], %[temp6] \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[frow]) \n\t"
+ "addiu %[dst], %[dst], 1 \n\t"
+ "addiu %[frow], %[frow], 4 \n\t"
+ "mult %[temp3], %[temp4] \n\t"
+ "maddu %[temp0], %[temp2] \n\t"
+ "mfhi %[temp5] \n\t"
+ "sb %[temp5], -1(%[dst]) \n\t"
+ "bne %[frow], %[loop_end], 1b \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [frow]"+r"(frow),
+ [dst]"+r"(dst), [loop_end]"=&r"(loop_end)
+ : [temp2]"r"(temp2), [temp6]"r"(temp6)
+ : "memory", "hi", "lo"
+ );
+ } else {
+ const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
+ const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B);
+ __asm__ volatile (
+ "li %[temp3], 0x10000 \n\t"
+ "li %[temp4], 0x8000 \n\t"
+ "addu %[loop_end], %[frow], %[temp6] \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[frow]) \n\t"
+ "lw %[temp1], 0(%[irow]) \n\t"
+ "addiu %[dst], %[dst], 1 \n\t"
+ "mult %[temp3], %[temp4] \n\t"
+ "maddu %[A], %[temp0] \n\t"
+ "maddu %[B], %[temp1] \n\t"
+ "addiu %[frow], %[frow], 4 \n\t"
+ "addiu %[irow], %[irow], 4 \n\t"
+ "mfhi %[temp5] \n\t"
+ "mult %[temp3], %[temp4] \n\t"
+ "maddu %[temp5], %[temp2] \n\t"
+ "mfhi %[temp5] \n\t"
+ "sb %[temp5], -1(%[dst]) \n\t"
+ "bne %[frow], %[loop_end], 1b \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [frow]"+r"(frow),
+ [irow]"+r"(irow), [dst]"+r"(dst), [loop_end]"=&r"(loop_end)
+ : [temp2]"r"(temp2), [temp6]"r"(temp6), [A]"r"(A), [B]"r"(B)
+ : "memory", "hi", "lo"
+ );
+ }
+}
+
+static void ExportRowShrink(WebPRescaler* const wrk) {
+ const int x_out_max = wrk->dst_width * wrk->num_channels;
+ uint8_t* dst = wrk->dst;
+ rescaler_t* irow = wrk->irow;
+ const rescaler_t* frow = wrk->frow;
+ const int yscale = wrk->fy_scale * (-wrk->y_accum);
+ int temp0, temp1, temp3, temp4, temp5, loop_end;
+ const int temp2 = (int)wrk->fxy_scale;
+ const int temp6 = x_out_max << 2;
+
+ assert(!WebPRescalerOutputDone(wrk));
+ assert(wrk->y_accum <= 0);
+ assert(!wrk->y_expand);
+ assert(wrk->fxy_scale != 0);
+ if (yscale) {
+ __asm__ volatile (
+ "li %[temp3], 0x10000 \n\t"
+ "li %[temp4], 0x8000 \n\t"
+ "addu %[loop_end], %[frow], %[temp6] \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[frow]) \n\t"
+ "mult %[temp3], %[temp4] \n\t"
+ "addiu %[frow], %[frow], 4 \n\t"
+ "maddu %[temp0], %[yscale] \n\t"
+ "mfhi %[temp1] \n\t"
+ "lw %[temp0], 0(%[irow]) \n\t"
+ "addiu %[dst], %[dst], 1 \n\t"
+ "addiu %[irow], %[irow], 4 \n\t"
+ "subu %[temp0], %[temp0], %[temp1] \n\t"
+ "mult %[temp3], %[temp4] \n\t"
+ "maddu %[temp0], %[temp2] \n\t"
+ "mfhi %[temp5] \n\t"
+ "sw %[temp1], -4(%[irow]) \n\t"
+ "sb %[temp5], -1(%[dst]) \n\t"
+ "bne %[frow], %[loop_end], 1b \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [frow]"+r"(frow),
+ [irow]"+r"(irow), [dst]"+r"(dst), [loop_end]"=&r"(loop_end)
+ : [temp2]"r"(temp2), [yscale]"r"(yscale), [temp6]"r"(temp6)
+ : "memory", "hi", "lo"
+ );
+ } else {
+ __asm__ volatile (
+ "li %[temp3], 0x10000 \n\t"
+ "li %[temp4], 0x8000 \n\t"
+ "addu %[loop_end], %[irow], %[temp6] \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[irow]) \n\t"
+ "addiu %[dst], %[dst], 1 \n\t"
+ "addiu %[irow], %[irow], 4 \n\t"
+ "mult %[temp3], %[temp4] \n\t"
+ "maddu %[temp0], %[temp2] \n\t"
+ "mfhi %[temp5] \n\t"
+ "sw $zero, -4(%[irow]) \n\t"
+ "sb %[temp5], -1(%[dst]) \n\t"
+ "bne %[irow], %[loop_end], 1b \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [irow]"+r"(irow),
+ [dst]"+r"(dst), [loop_end]"=&r"(loop_end)
+ : [temp2]"r"(temp2), [temp6]"r"(temp6)
+ : "memory", "hi", "lo"
+ );
+ }
+}
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void WebPRescalerDspInitMIPS32(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitMIPS32(void) {
+ WebPRescalerImportRowExpand = ImportRowExpand;
+ WebPRescalerImportRowShrink = ImportRowShrink;
+ WebPRescalerExportRowExpand = ExportRowExpand;
+ WebPRescalerExportRowShrink = ExportRowShrink;
+}
+
+#else // !WEBP_USE_MIPS32
+
+WEBP_DSP_INIT_STUB(WebPRescalerDspInitMIPS32)
+
+#endif // WEBP_USE_MIPS32
diff --git a/drivers/webp/dsp/rescaler_mips_dsp_r2.c b/drivers/webp/dsp/rescaler_mips_dsp_r2.c
new file mode 100644
index 0000000000..b457d0a30a
--- /dev/null
+++ b/drivers/webp/dsp/rescaler_mips_dsp_r2.c
@@ -0,0 +1,314 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// MIPS version of rescaling functions
+//
+// Author(s): Djordje Pesut (djordje.pesut@imgtec.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_MIPS_DSP_R2)
+
+#include <assert.h>
+#include "../utils/rescaler.h"
+
+#define ROUNDER (WEBP_RESCALER_ONE >> 1)
+#define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
+
+//------------------------------------------------------------------------------
+// Row export
+
+static void ExportRowShrink(WebPRescaler* const wrk) {
+ int i;
+ const int x_out_max = wrk->dst_width * wrk->num_channels;
+ uint8_t* dst = wrk->dst;
+ rescaler_t* irow = wrk->irow;
+ const rescaler_t* frow = wrk->frow;
+ const int yscale = wrk->fy_scale * (-wrk->y_accum);
+ int temp0, temp1, temp2, temp3, temp4, temp5, loop_end;
+ const int temp7 = (int)wrk->fxy_scale;
+ const int temp6 = (x_out_max & ~0x3) << 2;
+ assert(!WebPRescalerOutputDone(wrk));
+ assert(wrk->y_accum <= 0);
+ assert(!wrk->y_expand);
+ assert(wrk->fxy_scale != 0);
+ if (yscale) {
+ if (x_out_max >= 4) {
+ int temp8, temp9, temp10, temp11;
+ __asm__ volatile (
+ "li %[temp3], 0x10000 \n\t"
+ "li %[temp4], 0x8000 \n\t"
+ "addu %[loop_end], %[frow], %[temp6] \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[frow]) \n\t"
+ "lw %[temp1], 4(%[frow]) \n\t"
+ "lw %[temp2], 8(%[frow]) \n\t"
+ "lw %[temp5], 12(%[frow]) \n\t"
+ "mult $ac0, %[temp3], %[temp4] \n\t"
+ "maddu $ac0, %[temp0], %[yscale] \n\t"
+ "mult $ac1, %[temp3], %[temp4] \n\t"
+ "maddu $ac1, %[temp1], %[yscale] \n\t"
+ "mult $ac2, %[temp3], %[temp4] \n\t"
+ "maddu $ac2, %[temp2], %[yscale] \n\t"
+ "mult $ac3, %[temp3], %[temp4] \n\t"
+ "maddu $ac3, %[temp5], %[yscale] \n\t"
+ "addiu %[frow], %[frow], 16 \n\t"
+ "mfhi %[temp0], $ac0 \n\t"
+ "mfhi %[temp1], $ac1 \n\t"
+ "mfhi %[temp2], $ac2 \n\t"
+ "mfhi %[temp5], $ac3 \n\t"
+ "lw %[temp8], 0(%[irow]) \n\t"
+ "lw %[temp9], 4(%[irow]) \n\t"
+ "lw %[temp10], 8(%[irow]) \n\t"
+ "lw %[temp11], 12(%[irow]) \n\t"
+ "addiu %[dst], %[dst], 4 \n\t"
+ "addiu %[irow], %[irow], 16 \n\t"
+ "subu %[temp8], %[temp8], %[temp0] \n\t"
+ "subu %[temp9], %[temp9], %[temp1] \n\t"
+ "subu %[temp10], %[temp10], %[temp2] \n\t"
+ "subu %[temp11], %[temp11], %[temp5] \n\t"
+ "mult $ac0, %[temp3], %[temp4] \n\t"
+ "maddu $ac0, %[temp8], %[temp7] \n\t"
+ "mult $ac1, %[temp3], %[temp4] \n\t"
+ "maddu $ac1, %[temp9], %[temp7] \n\t"
+ "mult $ac2, %[temp3], %[temp4] \n\t"
+ "maddu $ac2, %[temp10], %[temp7] \n\t"
+ "mult $ac3, %[temp3], %[temp4] \n\t"
+ "maddu $ac3, %[temp11], %[temp7] \n\t"
+ "mfhi %[temp8], $ac0 \n\t"
+ "mfhi %[temp9], $ac1 \n\t"
+ "mfhi %[temp10], $ac2 \n\t"
+ "mfhi %[temp11], $ac3 \n\t"
+ "sw %[temp0], -16(%[irow]) \n\t"
+ "sw %[temp1], -12(%[irow]) \n\t"
+ "sw %[temp2], -8(%[irow]) \n\t"
+ "sw %[temp5], -4(%[irow]) \n\t"
+ "sb %[temp8], -4(%[dst]) \n\t"
+ "sb %[temp9], -3(%[dst]) \n\t"
+ "sb %[temp10], -2(%[dst]) \n\t"
+ "sb %[temp11], -1(%[dst]) \n\t"
+ "bne %[frow], %[loop_end], 1b \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [frow]"+r"(frow),
+ [irow]"+r"(irow), [dst]"+r"(dst), [loop_end]"=&r"(loop_end),
+ [temp8]"=&r"(temp8), [temp9]"=&r"(temp9), [temp10]"=&r"(temp10),
+ [temp11]"=&r"(temp11), [temp2]"=&r"(temp2)
+ : [temp7]"r"(temp7), [yscale]"r"(yscale), [temp6]"r"(temp6)
+ : "memory", "hi", "lo", "$ac1hi", "$ac1lo",
+ "$ac2hi", "$ac2lo", "$ac3hi", "$ac3lo"
+ );
+ }
+ for (i = 0; i < (x_out_max & 0x3); ++i) {
+ const uint32_t frac = (uint32_t)MULT_FIX(*frow++, yscale);
+ const int v = (int)MULT_FIX(*irow - frac, wrk->fxy_scale);
+ assert(v >= 0 && v <= 255);
+ *dst++ = v;
+ *irow++ = frac; // new fractional start
+ }
+ } else {
+ if (x_out_max >= 4) {
+ __asm__ volatile (
+ "li %[temp3], 0x10000 \n\t"
+ "li %[temp4], 0x8000 \n\t"
+ "addu %[loop_end], %[irow], %[temp6] \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[irow]) \n\t"
+ "lw %[temp1], 4(%[irow]) \n\t"
+ "lw %[temp2], 8(%[irow]) \n\t"
+ "lw %[temp5], 12(%[irow]) \n\t"
+ "addiu %[dst], %[dst], 4 \n\t"
+ "addiu %[irow], %[irow], 16 \n\t"
+ "mult $ac0, %[temp3], %[temp4] \n\t"
+ "maddu $ac0, %[temp0], %[temp7] \n\t"
+ "mult $ac1, %[temp3], %[temp4] \n\t"
+ "maddu $ac1, %[temp1], %[temp7] \n\t"
+ "mult $ac2, %[temp3], %[temp4] \n\t"
+ "maddu $ac2, %[temp2], %[temp7] \n\t"
+ "mult $ac3, %[temp3], %[temp4] \n\t"
+ "maddu $ac3, %[temp5], %[temp7] \n\t"
+ "mfhi %[temp0], $ac0 \n\t"
+ "mfhi %[temp1], $ac1 \n\t"
+ "mfhi %[temp2], $ac2 \n\t"
+ "mfhi %[temp5], $ac3 \n\t"
+ "sw $zero, -16(%[irow]) \n\t"
+ "sw $zero, -12(%[irow]) \n\t"
+ "sw $zero, -8(%[irow]) \n\t"
+ "sw $zero, -4(%[irow]) \n\t"
+ "sb %[temp0], -4(%[dst]) \n\t"
+ "sb %[temp1], -3(%[dst]) \n\t"
+ "sb %[temp2], -2(%[dst]) \n\t"
+ "sb %[temp5], -1(%[dst]) \n\t"
+ "bne %[irow], %[loop_end], 1b \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [irow]"+r"(irow),
+ [dst]"+r"(dst), [loop_end]"=&r"(loop_end), [temp2]"=&r"(temp2)
+ : [temp7]"r"(temp7), [temp6]"r"(temp6)
+ : "memory", "hi", "lo", "$ac1hi", "$ac1lo",
+ "$ac2hi", "$ac2lo", "$ac3hi", "$ac3lo"
+ );
+ }
+ for (i = 0; i < (x_out_max & 0x3); ++i) {
+ const int v = (int)MULT_FIX(*irow, wrk->fxy_scale);
+ assert(v >= 0 && v <= 255);
+ *dst++ = v;
+ *irow++ = 0;
+ }
+ }
+}
+
+static void ExportRowExpand(WebPRescaler* const wrk) {
+ int i;
+ uint8_t* dst = wrk->dst;
+ rescaler_t* irow = wrk->irow;
+ const int x_out_max = wrk->dst_width * wrk->num_channels;
+ const rescaler_t* frow = wrk->frow;
+ int temp0, temp1, temp2, temp3, temp4, temp5, loop_end;
+ const int temp6 = (x_out_max & ~0x3) << 2;
+ const int temp7 = (int)wrk->fy_scale;
+ assert(!WebPRescalerOutputDone(wrk));
+ assert(wrk->y_accum <= 0);
+ assert(wrk->y_expand);
+ assert(wrk->y_sub != 0);
+ if (wrk->y_accum == 0) {
+ if (x_out_max >= 4) {
+ __asm__ volatile (
+ "li %[temp4], 0x10000 \n\t"
+ "li %[temp5], 0x8000 \n\t"
+ "addu %[loop_end], %[frow], %[temp6] \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[frow]) \n\t"
+ "lw %[temp1], 4(%[frow]) \n\t"
+ "lw %[temp2], 8(%[frow]) \n\t"
+ "lw %[temp3], 12(%[frow]) \n\t"
+ "addiu %[dst], %[dst], 4 \n\t"
+ "addiu %[frow], %[frow], 16 \n\t"
+ "mult $ac0, %[temp4], %[temp5] \n\t"
+ "maddu $ac0, %[temp0], %[temp7] \n\t"
+ "mult $ac1, %[temp4], %[temp5] \n\t"
+ "maddu $ac1, %[temp1], %[temp7] \n\t"
+ "mult $ac2, %[temp4], %[temp5] \n\t"
+ "maddu $ac2, %[temp2], %[temp7] \n\t"
+ "mult $ac3, %[temp4], %[temp5] \n\t"
+ "maddu $ac3, %[temp3], %[temp7] \n\t"
+ "mfhi %[temp0], $ac0 \n\t"
+ "mfhi %[temp1], $ac1 \n\t"
+ "mfhi %[temp2], $ac2 \n\t"
+ "mfhi %[temp3], $ac3 \n\t"
+ "sb %[temp0], -4(%[dst]) \n\t"
+ "sb %[temp1], -3(%[dst]) \n\t"
+ "sb %[temp2], -2(%[dst]) \n\t"
+ "sb %[temp3], -1(%[dst]) \n\t"
+ "bne %[frow], %[loop_end], 1b \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [frow]"+r"(frow),
+ [dst]"+r"(dst), [loop_end]"=&r"(loop_end), [temp2]"=&r"(temp2)
+ : [temp7]"r"(temp7), [temp6]"r"(temp6)
+ : "memory", "hi", "lo", "$ac1hi", "$ac1lo",
+ "$ac2hi", "$ac2lo", "$ac3hi", "$ac3lo"
+ );
+ }
+ for (i = 0; i < (x_out_max & 0x3); ++i) {
+ const uint32_t J = *frow++;
+ const int v = (int)MULT_FIX(J, wrk->fy_scale);
+ assert(v >= 0 && v <= 255);
+ *dst++ = v;
+ }
+ } else {
+ const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
+ const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B);
+ if (x_out_max >= 4) {
+ int temp8, temp9, temp10, temp11;
+ __asm__ volatile (
+ "li %[temp8], 0x10000 \n\t"
+ "li %[temp9], 0x8000 \n\t"
+ "addu %[loop_end], %[frow], %[temp6] \n\t"
+ "1: \n\t"
+ "lw %[temp0], 0(%[frow]) \n\t"
+ "lw %[temp1], 4(%[frow]) \n\t"
+ "lw %[temp2], 8(%[frow]) \n\t"
+ "lw %[temp3], 12(%[frow]) \n\t"
+ "lw %[temp4], 0(%[irow]) \n\t"
+ "lw %[temp5], 4(%[irow]) \n\t"
+ "lw %[temp10], 8(%[irow]) \n\t"
+ "lw %[temp11], 12(%[irow]) \n\t"
+ "addiu %[dst], %[dst], 4 \n\t"
+ "mult $ac0, %[temp8], %[temp9] \n\t"
+ "maddu $ac0, %[A], %[temp0] \n\t"
+ "maddu $ac0, %[B], %[temp4] \n\t"
+ "mult $ac1, %[temp8], %[temp9] \n\t"
+ "maddu $ac1, %[A], %[temp1] \n\t"
+ "maddu $ac1, %[B], %[temp5] \n\t"
+ "mult $ac2, %[temp8], %[temp9] \n\t"
+ "maddu $ac2, %[A], %[temp2] \n\t"
+ "maddu $ac2, %[B], %[temp10] \n\t"
+ "mult $ac3, %[temp8], %[temp9] \n\t"
+ "maddu $ac3, %[A], %[temp3] \n\t"
+ "maddu $ac3, %[B], %[temp11] \n\t"
+ "addiu %[frow], %[frow], 16 \n\t"
+ "addiu %[irow], %[irow], 16 \n\t"
+ "mfhi %[temp0], $ac0 \n\t"
+ "mfhi %[temp1], $ac1 \n\t"
+ "mfhi %[temp2], $ac2 \n\t"
+ "mfhi %[temp3], $ac3 \n\t"
+ "mult $ac0, %[temp8], %[temp9] \n\t"
+ "maddu $ac0, %[temp0], %[temp7] \n\t"
+ "mult $ac1, %[temp8], %[temp9] \n\t"
+ "maddu $ac1, %[temp1], %[temp7] \n\t"
+ "mult $ac2, %[temp8], %[temp9] \n\t"
+ "maddu $ac2, %[temp2], %[temp7] \n\t"
+ "mult $ac3, %[temp8], %[temp9] \n\t"
+ "maddu $ac3, %[temp3], %[temp7] \n\t"
+ "mfhi %[temp0], $ac0 \n\t"
+ "mfhi %[temp1], $ac1 \n\t"
+ "mfhi %[temp2], $ac2 \n\t"
+ "mfhi %[temp3], $ac3 \n\t"
+ "sb %[temp0], -4(%[dst]) \n\t"
+ "sb %[temp1], -3(%[dst]) \n\t"
+ "sb %[temp2], -2(%[dst]) \n\t"
+ "sb %[temp3], -1(%[dst]) \n\t"
+ "bne %[frow], %[loop_end], 1b \n\t"
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp3]"=&r"(temp3),
+ [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), [frow]"+r"(frow),
+ [irow]"+r"(irow), [dst]"+r"(dst), [loop_end]"=&r"(loop_end),
+ [temp8]"=&r"(temp8), [temp9]"=&r"(temp9), [temp10]"=&r"(temp10),
+ [temp11]"=&r"(temp11), [temp2]"=&r"(temp2)
+ : [temp7]"r"(temp7), [temp6]"r"(temp6), [A]"r"(A), [B]"r"(B)
+ : "memory", "hi", "lo", "$ac1hi", "$ac1lo",
+ "$ac2hi", "$ac2lo", "$ac3hi", "$ac3lo"
+ );
+ }
+ for (i = 0; i < (x_out_max & 0x3); ++i) {
+ const uint64_t I = (uint64_t)A * *frow++
+ + (uint64_t)B * *irow++;
+ const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
+ const int v = (int)MULT_FIX(J, wrk->fy_scale);
+ assert(v >= 0 && v <= 255);
+ *dst++ = v;
+ }
+ }
+}
+
+#undef MULT_FIX
+#undef ROUNDER
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void WebPRescalerDspInitMIPSdspR2(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitMIPSdspR2(void) {
+ WebPRescalerExportRowExpand = ExportRowExpand;
+ WebPRescalerExportRowShrink = ExportRowShrink;
+}
+
+#else // !WEBP_USE_MIPS_DSP_R2
+
+WEBP_DSP_INIT_STUB(WebPRescalerDspInitMIPSdspR2)
+
+#endif // WEBP_USE_MIPS_DSP_R2
diff --git a/drivers/webp/dsp/rescaler_neon.c b/drivers/webp/dsp/rescaler_neon.c
new file mode 100644
index 0000000000..16fd450ea3
--- /dev/null
+++ b/drivers/webp/dsp/rescaler_neon.c
@@ -0,0 +1,186 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// NEON version of rescaling functions
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_NEON)
+
+#include <arm_neon.h>
+#include <assert.h>
+#include "./neon.h"
+#include "../utils/rescaler.h"
+
+#define ROUNDER (WEBP_RESCALER_ONE >> 1)
+#define MULT_FIX_C(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
+
+#define LOAD_32x4(SRC, DST) const uint32x4_t DST = vld1q_u32((SRC))
+#define LOAD_32x8(SRC, DST0, DST1) \
+ LOAD_32x4(SRC + 0, DST0); \
+ LOAD_32x4(SRC + 4, DST1)
+
+#define STORE_32x8(SRC0, SRC1, DST) do { \
+ vst1q_u32((DST) + 0, SRC0); \
+ vst1q_u32((DST) + 4, SRC1); \
+} while (0);
+
+#if (WEBP_RESCALER_RFIX == 32)
+#define MAKE_HALF_CST(C) vdupq_n_s32((int32_t)((C) >> 1))
+#define MULT_FIX(A, B) /* note: B is actualy scale>>1. See MAKE_HALF_CST */ \
+ vreinterpretq_u32_s32(vqrdmulhq_s32(vreinterpretq_s32_u32((A)), (B)))
+#else
+#error "MULT_FIX/WEBP_RESCALER_RFIX need some more work"
+#endif
+
+static uint32x4_t Interpolate(const rescaler_t* const frow,
+ const rescaler_t* const irow,
+ uint32_t A, uint32_t B) {
+ LOAD_32x4(frow, A0);
+ LOAD_32x4(irow, B0);
+ const uint64x2_t C0 = vmull_n_u32(vget_low_u32(A0), A);
+ const uint64x2_t C1 = vmull_n_u32(vget_high_u32(A0), A);
+ const uint64x2_t D0 = vmlal_n_u32(C0, vget_low_u32(B0), B);
+ const uint64x2_t D1 = vmlal_n_u32(C1, vget_high_u32(B0), B);
+ const uint32x4_t E = vcombine_u32(
+ vrshrn_n_u64(D0, WEBP_RESCALER_RFIX),
+ vrshrn_n_u64(D1, WEBP_RESCALER_RFIX));
+ return E;
+}
+
+static void RescalerExportRowExpand(WebPRescaler* const wrk) {
+ int x_out;
+ uint8_t* const dst = wrk->dst;
+ rescaler_t* const irow = wrk->irow;
+ const int x_out_max = wrk->dst_width * wrk->num_channels;
+ const int max_span = x_out_max & ~7;
+ const rescaler_t* const frow = wrk->frow;
+ const uint32_t fy_scale = wrk->fy_scale;
+ const int32x4_t fy_scale_half = MAKE_HALF_CST(fy_scale);
+ assert(!WebPRescalerOutputDone(wrk));
+ assert(wrk->y_accum <= 0);
+ assert(wrk->y_expand);
+ assert(wrk->y_sub != 0);
+ if (wrk->y_accum == 0) {
+ for (x_out = 0; x_out < max_span; x_out += 8) {
+ LOAD_32x4(frow + x_out + 0, A0);
+ LOAD_32x4(frow + x_out + 4, A1);
+ const uint32x4_t B0 = MULT_FIX(A0, fy_scale_half);
+ const uint32x4_t B1 = MULT_FIX(A1, fy_scale_half);
+ const uint16x4_t C0 = vmovn_u32(B0);
+ const uint16x4_t C1 = vmovn_u32(B1);
+ const uint8x8_t D = vmovn_u16(vcombine_u16(C0, C1));
+ vst1_u8(dst + x_out, D);
+ }
+ for (; x_out < x_out_max; ++x_out) {
+ const uint32_t J = frow[x_out];
+ const int v = (int)MULT_FIX_C(J, fy_scale);
+ assert(v >= 0 && v <= 255);
+ dst[x_out] = v;
+ }
+ } else {
+ const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
+ const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B);
+ for (x_out = 0; x_out < max_span; x_out += 8) {
+ const uint32x4_t C0 =
+ Interpolate(frow + x_out + 0, irow + x_out + 0, A, B);
+ const uint32x4_t C1 =
+ Interpolate(frow + x_out + 4, irow + x_out + 4, A, B);
+ const uint32x4_t D0 = MULT_FIX(C0, fy_scale_half);
+ const uint32x4_t D1 = MULT_FIX(C1, fy_scale_half);
+ const uint16x4_t E0 = vmovn_u32(D0);
+ const uint16x4_t E1 = vmovn_u32(D1);
+ const uint8x8_t F = vmovn_u16(vcombine_u16(E0, E1));
+ vst1_u8(dst + x_out, F);
+ }
+ for (; x_out < x_out_max; ++x_out) {
+ const uint64_t I = (uint64_t)A * frow[x_out]
+ + (uint64_t)B * irow[x_out];
+ const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
+ const int v = (int)MULT_FIX_C(J, fy_scale);
+ assert(v >= 0 && v <= 255);
+ dst[x_out] = v;
+ }
+ }
+}
+
+static void RescalerExportRowShrink(WebPRescaler* const wrk) {
+ int x_out;
+ uint8_t* const dst = wrk->dst;
+ rescaler_t* const irow = wrk->irow;
+ const int x_out_max = wrk->dst_width * wrk->num_channels;
+ const int max_span = x_out_max & ~7;
+ const rescaler_t* const frow = wrk->frow;
+ const uint32_t yscale = wrk->fy_scale * (-wrk->y_accum);
+ const uint32_t fxy_scale = wrk->fxy_scale;
+ const uint32x4_t zero = vdupq_n_u32(0);
+ const int32x4_t yscale_half = MAKE_HALF_CST(yscale);
+ const int32x4_t fxy_scale_half = MAKE_HALF_CST(fxy_scale);
+ assert(!WebPRescalerOutputDone(wrk));
+ assert(wrk->y_accum <= 0);
+ assert(!wrk->y_expand);
+ if (yscale) {
+ for (x_out = 0; x_out < max_span; x_out += 8) {
+ LOAD_32x8(frow + x_out, in0, in1);
+ LOAD_32x8(irow + x_out, in2, in3);
+ const uint32x4_t A0 = MULT_FIX(in0, yscale_half);
+ const uint32x4_t A1 = MULT_FIX(in1, yscale_half);
+ const uint32x4_t B0 = vqsubq_u32(in2, A0);
+ const uint32x4_t B1 = vqsubq_u32(in3, A1);
+ const uint32x4_t C0 = MULT_FIX(B0, fxy_scale_half);
+ const uint32x4_t C1 = MULT_FIX(B1, fxy_scale_half);
+ const uint16x4_t D0 = vmovn_u32(C0);
+ const uint16x4_t D1 = vmovn_u32(C1);
+ const uint8x8_t E = vmovn_u16(vcombine_u16(D0, D1));
+ vst1_u8(dst + x_out, E);
+ STORE_32x8(A0, A1, irow + x_out);
+ }
+ for (; x_out < x_out_max; ++x_out) {
+ const uint32_t frac = (uint32_t)MULT_FIX_C(frow[x_out], yscale);
+ const int v = (int)MULT_FIX_C(irow[x_out] - frac, wrk->fxy_scale);
+ assert(v >= 0 && v <= 255);
+ dst[x_out] = v;
+ irow[x_out] = frac; // new fractional start
+ }
+ } else {
+ for (x_out = 0; x_out < max_span; x_out += 8) {
+ LOAD_32x8(irow + x_out, in0, in1);
+ const uint32x4_t A0 = MULT_FIX(in0, fxy_scale_half);
+ const uint32x4_t A1 = MULT_FIX(in1, fxy_scale_half);
+ const uint16x4_t B0 = vmovn_u32(A0);
+ const uint16x4_t B1 = vmovn_u32(A1);
+ const uint8x8_t C = vmovn_u16(vcombine_u16(B0, B1));
+ vst1_u8(dst + x_out, C);
+ STORE_32x8(zero, zero, irow + x_out);
+ }
+ for (; x_out < x_out_max; ++x_out) {
+ const int v = (int)MULT_FIX_C(irow[x_out], fxy_scale);
+ assert(v >= 0 && v <= 255);
+ dst[x_out] = v;
+ irow[x_out] = 0;
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+
+extern void WebPRescalerDspInitNEON(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitNEON(void) {
+ WebPRescalerExportRowExpand = RescalerExportRowExpand;
+ WebPRescalerExportRowShrink = RescalerExportRowShrink;
+}
+
+#else // !WEBP_USE_NEON
+
+WEBP_DSP_INIT_STUB(WebPRescalerDspInitNEON)
+
+#endif // WEBP_USE_NEON
diff --git a/drivers/webp/dsp/rescaler_sse2.c b/drivers/webp/dsp/rescaler_sse2.c
new file mode 100644
index 0000000000..186edb653e
--- /dev/null
+++ b/drivers/webp/dsp/rescaler_sse2.c
@@ -0,0 +1,373 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// SSE2 Rescaling functions
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_SSE2)
+#include <emmintrin.h>
+
+#include <assert.h>
+#include "../utils/rescaler.h"
+
+//------------------------------------------------------------------------------
+// Implementations of critical functions ImportRow / ExportRow
+
+#define ROUNDER (WEBP_RESCALER_ONE >> 1)
+#define MULT_FIX(x, y) (((uint64_t)(x) * (y) + ROUNDER) >> WEBP_RESCALER_RFIX)
+
+// input: 8 bytes ABCDEFGH -> output: A0E0B0F0C0G0D0H0
+static void LoadTwoPixels(const uint8_t* const src, __m128i* out) {
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i A = _mm_loadl_epi64((const __m128i*)(src)); // ABCDEFGH
+ const __m128i B = _mm_unpacklo_epi8(A, zero); // A0B0C0D0E0F0G0H0
+ const __m128i C = _mm_srli_si128(B, 8); // E0F0G0H0
+ *out = _mm_unpacklo_epi16(B, C);
+}
+
+// input: 8 bytes ABCDEFGH -> output: A0B0C0D0E0F0G0H0
+static void LoadHeightPixels(const uint8_t* const src, __m128i* out) {
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i A = _mm_loadl_epi64((const __m128i*)(src)); // ABCDEFGH
+ *out = _mm_unpacklo_epi8(A, zero);
+}
+
+static void RescalerImportRowExpandSSE2(WebPRescaler* const wrk,
+ const uint8_t* src) {
+ rescaler_t* frow = wrk->frow;
+ const rescaler_t* const frow_end = frow + wrk->dst_width * wrk->num_channels;
+ const int x_add = wrk->x_add;
+ int accum = x_add;
+ __m128i cur_pixels;
+
+ assert(!WebPRescalerInputDone(wrk));
+ assert(wrk->x_expand);
+ if (wrk->num_channels == 4) {
+ if (wrk->src_width < 2) {
+ WebPRescalerImportRowExpandC(wrk, src);
+ return;
+ }
+ LoadTwoPixels(src, &cur_pixels);
+ src += 4;
+ while (1) {
+ const __m128i mult = _mm_set1_epi32(((x_add - accum) << 16) | accum);
+ const __m128i out = _mm_madd_epi16(cur_pixels, mult);
+ _mm_storeu_si128((__m128i*)frow, out);
+ frow += 4;
+ if (frow >= frow_end) break;
+ accum -= wrk->x_sub;
+ if (accum < 0) {
+ LoadTwoPixels(src, &cur_pixels);
+ src += 4;
+ accum += x_add;
+ }
+ }
+ } else {
+ int left;
+ const uint8_t* const src_limit = src + wrk->src_width - 8;
+ if (wrk->src_width < 8) {
+ WebPRescalerImportRowExpandC(wrk, src);
+ return;
+ }
+ LoadHeightPixels(src, &cur_pixels);
+ src += 7;
+ left = 7;
+ while (1) {
+ const __m128i mult = _mm_cvtsi32_si128(((x_add - accum) << 16) | accum);
+ const __m128i out = _mm_madd_epi16(cur_pixels, mult);
+ *(uint32_t*)frow = _mm_cvtsi128_si32(out);
+ frow += 1;
+ if (frow >= frow_end) break;
+ accum -= wrk->x_sub;
+ if (accum < 0) {
+ if (--left) {
+ cur_pixels = _mm_srli_si128(cur_pixels, 2);
+ } else if (src <= src_limit) {
+ LoadHeightPixels(src, &cur_pixels);
+ src += 7;
+ left = 7;
+ } else { // tail
+ cur_pixels = _mm_srli_si128(cur_pixels, 2);
+ cur_pixels = _mm_insert_epi16(cur_pixels, src[1], 1);
+ src += 1;
+ left = 1;
+ }
+ accum += x_add;
+ }
+ }
+ }
+ assert(accum == 0);
+}
+
+static void RescalerImportRowShrinkSSE2(WebPRescaler* const wrk,
+ const uint8_t* src) {
+ const int x_sub = wrk->x_sub;
+ int accum = 0;
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i mult0 = _mm_set1_epi16(x_sub);
+ const __m128i mult1 = _mm_set1_epi32(wrk->fx_scale);
+ const __m128i rounder = _mm_set_epi32(0, ROUNDER, 0, ROUNDER);
+ __m128i sum = zero;
+ rescaler_t* frow = wrk->frow;
+ const rescaler_t* const frow_end = wrk->frow + 4 * wrk->dst_width;
+
+ if (wrk->num_channels != 4 || wrk->x_add > (x_sub << 7)) {
+ WebPRescalerImportRowShrinkC(wrk, src);
+ return;
+ }
+ assert(!WebPRescalerInputDone(wrk));
+ assert(!wrk->x_expand);
+
+ for (; frow < frow_end; frow += 4) {
+ __m128i base = zero;
+ accum += wrk->x_add;
+ while (accum > 0) {
+ const __m128i A = _mm_cvtsi32_si128(*(int*)src);
+ src += 4;
+ base = _mm_unpacklo_epi8(A, zero);
+ // To avoid overflow, we need: base * x_add / x_sub < 32768
+ // => x_add < x_sub << 7. That's a 1/128 reduction ratio limit.
+ sum = _mm_add_epi16(sum, base);
+ accum -= x_sub;
+ }
+ { // Emit next horizontal pixel.
+ const __m128i mult = _mm_set1_epi16(-accum);
+ const __m128i frac0 = _mm_mullo_epi16(base, mult); // 16b x 16b -> 32b
+ const __m128i frac1 = _mm_mulhi_epu16(base, mult);
+ const __m128i frac = _mm_unpacklo_epi16(frac0, frac1); // frac is 32b
+ const __m128i A0 = _mm_mullo_epi16(sum, mult0);
+ const __m128i A1 = _mm_mulhi_epu16(sum, mult0);
+ const __m128i B0 = _mm_unpacklo_epi16(A0, A1); // sum * x_sub
+ const __m128i frow_out = _mm_sub_epi32(B0, frac); // sum * x_sub - frac
+ const __m128i D0 = _mm_srli_epi64(frac, 32);
+ const __m128i D1 = _mm_mul_epu32(frac, mult1); // 32b x 16b -> 64b
+ const __m128i D2 = _mm_mul_epu32(D0, mult1);
+ const __m128i E1 = _mm_add_epi64(D1, rounder);
+ const __m128i E2 = _mm_add_epi64(D2, rounder);
+ const __m128i F1 = _mm_shuffle_epi32(E1, 1 | (3 << 2));
+ const __m128i F2 = _mm_shuffle_epi32(E2, 1 | (3 << 2));
+ const __m128i G = _mm_unpacklo_epi32(F1, F2);
+ sum = _mm_packs_epi32(G, zero);
+ _mm_storeu_si128((__m128i*)frow, frow_out);
+ }
+ }
+ assert(accum == 0);
+}
+
+//------------------------------------------------------------------------------
+// Row export
+
+// load *src as epi64, multiply by mult and store result in [out0 ... out3]
+static WEBP_INLINE void LoadDispatchAndMult(const rescaler_t* const src,
+ const __m128i* const mult,
+ __m128i* const out0,
+ __m128i* const out1,
+ __m128i* const out2,
+ __m128i* const out3) {
+ const __m128i A0 = _mm_loadu_si128((const __m128i*)(src + 0));
+ const __m128i A1 = _mm_loadu_si128((const __m128i*)(src + 4));
+ const __m128i A2 = _mm_srli_epi64(A0, 32);
+ const __m128i A3 = _mm_srli_epi64(A1, 32);
+ if (mult != NULL) {
+ *out0 = _mm_mul_epu32(A0, *mult);
+ *out1 = _mm_mul_epu32(A1, *mult);
+ *out2 = _mm_mul_epu32(A2, *mult);
+ *out3 = _mm_mul_epu32(A3, *mult);
+ } else {
+ *out0 = A0;
+ *out1 = A1;
+ *out2 = A2;
+ *out3 = A3;
+ }
+}
+
+static WEBP_INLINE void ProcessRow(const __m128i* const A0,
+ const __m128i* const A1,
+ const __m128i* const A2,
+ const __m128i* const A3,
+ const __m128i* const mult,
+ uint8_t* const dst) {
+ const __m128i rounder = _mm_set_epi32(0, ROUNDER, 0, ROUNDER);
+ const __m128i mask = _mm_set_epi32(0xffffffffu, 0, 0xffffffffu, 0);
+ const __m128i B0 = _mm_mul_epu32(*A0, *mult);
+ const __m128i B1 = _mm_mul_epu32(*A1, *mult);
+ const __m128i B2 = _mm_mul_epu32(*A2, *mult);
+ const __m128i B3 = _mm_mul_epu32(*A3, *mult);
+ const __m128i C0 = _mm_add_epi64(B0, rounder);
+ const __m128i C1 = _mm_add_epi64(B1, rounder);
+ const __m128i C2 = _mm_add_epi64(B2, rounder);
+ const __m128i C3 = _mm_add_epi64(B3, rounder);
+ const __m128i D0 = _mm_srli_epi64(C0, WEBP_RESCALER_RFIX);
+ const __m128i D1 = _mm_srli_epi64(C1, WEBP_RESCALER_RFIX);
+#if (WEBP_RESCALER_FIX < 32)
+ const __m128i D2 =
+ _mm_and_si128(_mm_slli_epi64(C2, 32 - WEBP_RESCALER_RFIX), mask);
+ const __m128i D3 =
+ _mm_and_si128(_mm_slli_epi64(C3, 32 - WEBP_RESCALER_RFIX), mask);
+#else
+ const __m128i D2 = _mm_and_si128(C2, mask);
+ const __m128i D3 = _mm_and_si128(C3, mask);
+#endif
+ const __m128i E0 = _mm_or_si128(D0, D2);
+ const __m128i E1 = _mm_or_si128(D1, D3);
+ const __m128i F = _mm_packs_epi32(E0, E1);
+ const __m128i G = _mm_packus_epi16(F, F);
+ _mm_storel_epi64((__m128i*)dst, G);
+}
+
+static void RescalerExportRowExpandSSE2(WebPRescaler* const wrk) {
+ int x_out;
+ uint8_t* const dst = wrk->dst;
+ rescaler_t* const irow = wrk->irow;
+ const int x_out_max = wrk->dst_width * wrk->num_channels;
+ const rescaler_t* const frow = wrk->frow;
+ const __m128i mult = _mm_set_epi32(0, wrk->fy_scale, 0, wrk->fy_scale);
+
+ assert(!WebPRescalerOutputDone(wrk));
+ assert(wrk->y_accum <= 0 && wrk->y_sub + wrk->y_accum >= 0);
+ assert(wrk->y_expand);
+ if (wrk->y_accum == 0) {
+ for (x_out = 0; x_out + 8 <= x_out_max; x_out += 8) {
+ __m128i A0, A1, A2, A3;
+ LoadDispatchAndMult(frow + x_out, NULL, &A0, &A1, &A2, &A3);
+ ProcessRow(&A0, &A1, &A2, &A3, &mult, dst + x_out);
+ }
+ for (; x_out < x_out_max; ++x_out) {
+ const uint32_t J = frow[x_out];
+ const int v = (int)MULT_FIX(J, wrk->fy_scale);
+ assert(v >= 0 && v <= 255);
+ dst[x_out] = v;
+ }
+ } else {
+ const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
+ const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B);
+ const __m128i mA = _mm_set_epi32(0, A, 0, A);
+ const __m128i mB = _mm_set_epi32(0, B, 0, B);
+ const __m128i rounder = _mm_set_epi32(0, ROUNDER, 0, ROUNDER);
+ for (x_out = 0; x_out + 8 <= x_out_max; x_out += 8) {
+ __m128i A0, A1, A2, A3, B0, B1, B2, B3;
+ LoadDispatchAndMult(frow + x_out, &mA, &A0, &A1, &A2, &A3);
+ LoadDispatchAndMult(irow + x_out, &mB, &B0, &B1, &B2, &B3);
+ {
+ const __m128i C0 = _mm_add_epi64(A0, B0);
+ const __m128i C1 = _mm_add_epi64(A1, B1);
+ const __m128i C2 = _mm_add_epi64(A2, B2);
+ const __m128i C3 = _mm_add_epi64(A3, B3);
+ const __m128i D0 = _mm_add_epi64(C0, rounder);
+ const __m128i D1 = _mm_add_epi64(C1, rounder);
+ const __m128i D2 = _mm_add_epi64(C2, rounder);
+ const __m128i D3 = _mm_add_epi64(C3, rounder);
+ const __m128i E0 = _mm_srli_epi64(D0, WEBP_RESCALER_RFIX);
+ const __m128i E1 = _mm_srli_epi64(D1, WEBP_RESCALER_RFIX);
+ const __m128i E2 = _mm_srli_epi64(D2, WEBP_RESCALER_RFIX);
+ const __m128i E3 = _mm_srli_epi64(D3, WEBP_RESCALER_RFIX);
+ ProcessRow(&E0, &E1, &E2, &E3, &mult, dst + x_out);
+ }
+ }
+ for (; x_out < x_out_max; ++x_out) {
+ const uint64_t I = (uint64_t)A * frow[x_out]
+ + (uint64_t)B * irow[x_out];
+ const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
+ const int v = (int)MULT_FIX(J, wrk->fy_scale);
+ assert(v >= 0 && v <= 255);
+ dst[x_out] = v;
+ }
+ }
+}
+
+static void RescalerExportRowShrinkSSE2(WebPRescaler* const wrk) {
+ int x_out;
+ uint8_t* const dst = wrk->dst;
+ rescaler_t* const irow = wrk->irow;
+ const int x_out_max = wrk->dst_width * wrk->num_channels;
+ const rescaler_t* const frow = wrk->frow;
+ const uint32_t yscale = wrk->fy_scale * (-wrk->y_accum);
+ assert(!WebPRescalerOutputDone(wrk));
+ assert(wrk->y_accum <= 0);
+ assert(!wrk->y_expand);
+ if (yscale) {
+ const int scale_xy = wrk->fxy_scale;
+ const __m128i mult_xy = _mm_set_epi32(0, scale_xy, 0, scale_xy);
+ const __m128i mult_y = _mm_set_epi32(0, yscale, 0, yscale);
+ const __m128i rounder = _mm_set_epi32(0, ROUNDER, 0, ROUNDER);
+ for (x_out = 0; x_out + 8 <= x_out_max; x_out += 8) {
+ __m128i A0, A1, A2, A3, B0, B1, B2, B3;
+ LoadDispatchAndMult(irow + x_out, NULL, &A0, &A1, &A2, &A3);
+ LoadDispatchAndMult(frow + x_out, &mult_y, &B0, &B1, &B2, &B3);
+ {
+ const __m128i C0 = _mm_add_epi64(B0, rounder);
+ const __m128i C1 = _mm_add_epi64(B1, rounder);
+ const __m128i C2 = _mm_add_epi64(B2, rounder);
+ const __m128i C3 = _mm_add_epi64(B3, rounder);
+ const __m128i D0 = _mm_srli_epi64(C0, WEBP_RESCALER_RFIX); // = frac
+ const __m128i D1 = _mm_srli_epi64(C1, WEBP_RESCALER_RFIX);
+ const __m128i D2 = _mm_srli_epi64(C2, WEBP_RESCALER_RFIX);
+ const __m128i D3 = _mm_srli_epi64(C3, WEBP_RESCALER_RFIX);
+ const __m128i E0 = _mm_sub_epi64(A0, D0); // irow[x] - frac
+ const __m128i E1 = _mm_sub_epi64(A1, D1);
+ const __m128i E2 = _mm_sub_epi64(A2, D2);
+ const __m128i E3 = _mm_sub_epi64(A3, D3);
+ const __m128i F2 = _mm_slli_epi64(D2, 32);
+ const __m128i F3 = _mm_slli_epi64(D3, 32);
+ const __m128i G0 = _mm_or_si128(D0, F2);
+ const __m128i G1 = _mm_or_si128(D1, F3);
+ _mm_storeu_si128((__m128i*)(irow + x_out + 0), G0);
+ _mm_storeu_si128((__m128i*)(irow + x_out + 4), G1);
+ ProcessRow(&E0, &E1, &E2, &E3, &mult_xy, dst + x_out);
+ }
+ }
+ for (; x_out < x_out_max; ++x_out) {
+ const uint32_t frac = (int)MULT_FIX(frow[x_out], yscale);
+ const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
+ assert(v >= 0 && v <= 255);
+ dst[x_out] = v;
+ irow[x_out] = frac; // new fractional start
+ }
+ } else {
+ const uint32_t scale = wrk->fxy_scale;
+ const __m128i mult = _mm_set_epi32(0, scale, 0, scale);
+ const __m128i zero = _mm_setzero_si128();
+ for (x_out = 0; x_out + 8 <= x_out_max; x_out += 8) {
+ __m128i A0, A1, A2, A3;
+ LoadDispatchAndMult(irow + x_out, NULL, &A0, &A1, &A2, &A3);
+ _mm_storeu_si128((__m128i*)(irow + x_out + 0), zero);
+ _mm_storeu_si128((__m128i*)(irow + x_out + 4), zero);
+ ProcessRow(&A0, &A1, &A2, &A3, &mult, dst + x_out);
+ }
+ for (; x_out < x_out_max; ++x_out) {
+ const int v = (int)MULT_FIX(irow[x_out], scale);
+ assert(v >= 0 && v <= 255);
+ dst[x_out] = v;
+ irow[x_out] = 0;
+ }
+ }
+}
+
+#undef MULT_FIX
+#undef ROUNDER
+
+//------------------------------------------------------------------------------
+
+extern void WebPRescalerDspInitSSE2(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitSSE2(void) {
+ WebPRescalerImportRowExpand = RescalerImportRowExpandSSE2;
+ WebPRescalerImportRowShrink = RescalerImportRowShrinkSSE2;
+ WebPRescalerExportRowExpand = RescalerExportRowExpandSSE2;
+ WebPRescalerExportRowShrink = RescalerExportRowShrinkSSE2;
+}
+
+#else // !WEBP_USE_SSE2
+
+WEBP_DSP_INIT_STUB(WebPRescalerDspInitSSE2)
+
+#endif // WEBP_USE_SSE2
diff --git a/drivers/webp/dsp/upsampling.c b/drivers/webp/dsp/upsampling.c
index 4855eb1432..651274fcee 100644
--- a/drivers/webp/dsp/upsampling.c
+++ b/drivers/webp/dsp/upsampling.c
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// YUV to RGB upsampling functions.
@@ -12,9 +14,7 @@
#include "./dsp.h"
#include "./yuv.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
+#include <assert.h>
//------------------------------------------------------------------------------
// Fancy upsampler
@@ -32,7 +32,7 @@ WebPUpsampleLinePairFunc WebPUpsamplers[MODE_LAST];
// ([3*a + b + 9*c + 3*d a + 3*b + 3*c + 9*d] [8 8]) / 16
// We process u and v together stashed into 32bit (16bit each).
-#define LOAD_UV(u,v) ((u) | ((v) << 16))
+#define LOAD_UV(u, v) ((u) | ((v) << 16))
#define UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \
static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
@@ -43,11 +43,12 @@ static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
const int last_pixel_pair = (len - 1) >> 1; \
uint32_t tl_uv = LOAD_UV(top_u[0], top_v[0]); /* top-left sample */ \
uint32_t l_uv = LOAD_UV(cur_u[0], cur_v[0]); /* left-sample */ \
- if (top_y) { \
+ assert(top_y != NULL); \
+ { \
const uint32_t uv0 = (3 * tl_uv + l_uv + 0x00020002u) >> 2; \
FUNC(top_y[0], uv0 & 0xff, (uv0 >> 16), top_dst); \
} \
- if (bottom_y) { \
+ if (bottom_y != NULL) { \
const uint32_t uv0 = (3 * l_uv + tl_uv + 0x00020002u) >> 2; \
FUNC(bottom_y[0], uv0 & 0xff, (uv0 >> 16), bottom_dst); \
} \
@@ -58,7 +59,7 @@ static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
const uint32_t avg = tl_uv + t_uv + l_uv + uv + 0x00080008u; \
const uint32_t diag_12 = (avg + 2 * (t_uv + l_uv)) >> 3; \
const uint32_t diag_03 = (avg + 2 * (tl_uv + uv)) >> 3; \
- if (top_y) { \
+ { \
const uint32_t uv0 = (diag_12 + tl_uv) >> 1; \
const uint32_t uv1 = (diag_03 + t_uv) >> 1; \
FUNC(top_y[2 * x - 1], uv0 & 0xff, (uv0 >> 16), \
@@ -66,7 +67,7 @@ static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
FUNC(top_y[2 * x - 0], uv1 & 0xff, (uv1 >> 16), \
top_dst + (2 * x - 0) * XSTEP); \
} \
- if (bottom_y) { \
+ if (bottom_y != NULL) { \
const uint32_t uv0 = (diag_03 + l_uv) >> 1; \
const uint32_t uv1 = (diag_12 + uv) >> 1; \
FUNC(bottom_y[2 * x - 1], uv0 & 0xff, (uv0 >> 16), \
@@ -78,12 +79,12 @@ static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
l_uv = uv; \
} \
if (!(len & 1)) { \
- if (top_y) { \
+ { \
const uint32_t uv0 = (3 * tl_uv + l_uv + 0x00020002u) >> 2; \
FUNC(top_y[len - 1], uv0 & 0xff, (uv0 >> 16), \
top_dst + (len - 1) * XSTEP); \
} \
- if (bottom_y) { \
+ if (bottom_y != NULL) { \
const uint32_t uv0 = (3 * l_uv + tl_uv + 0x00020002u) >> 2; \
FUNC(bottom_y[len - 1], uv0 & 0xff, (uv0 >> 16), \
bottom_dst + (len - 1) * XSTEP); \
@@ -106,57 +107,6 @@ UPSAMPLE_FUNC(UpsampleRgb565LinePair, VP8YuvToRgb565, 2)
#endif // FANCY_UPSAMPLING
//------------------------------------------------------------------------------
-// simple point-sampling
-
-#define SAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \
-static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
- const uint8_t* u, const uint8_t* v, \
- uint8_t* top_dst, uint8_t* bottom_dst, int len) { \
- int i; \
- for (i = 0; i < len - 1; i += 2) { \
- FUNC(top_y[0], u[0], v[0], top_dst); \
- FUNC(top_y[1], u[0], v[0], top_dst + XSTEP); \
- FUNC(bottom_y[0], u[0], v[0], bottom_dst); \
- FUNC(bottom_y[1], u[0], v[0], bottom_dst + XSTEP); \
- top_y += 2; \
- bottom_y += 2; \
- u++; \
- v++; \
- top_dst += 2 * XSTEP; \
- bottom_dst += 2 * XSTEP; \
- } \
- if (i == len - 1) { /* last one */ \
- FUNC(top_y[0], u[0], v[0], top_dst); \
- FUNC(bottom_y[0], u[0], v[0], bottom_dst); \
- } \
-}
-
-// All variants implemented.
-SAMPLE_FUNC(SampleRgbLinePair, VP8YuvToRgb, 3)
-SAMPLE_FUNC(SampleBgrLinePair, VP8YuvToBgr, 3)
-SAMPLE_FUNC(SampleRgbaLinePair, VP8YuvToRgba, 4)
-SAMPLE_FUNC(SampleBgraLinePair, VP8YuvToBgra, 4)
-SAMPLE_FUNC(SampleArgbLinePair, VP8YuvToArgb, 4)
-SAMPLE_FUNC(SampleRgba4444LinePair, VP8YuvToRgba4444, 2)
-SAMPLE_FUNC(SampleRgb565LinePair, VP8YuvToRgb565, 2)
-
-#undef SAMPLE_FUNC
-
-const WebPSampleLinePairFunc WebPSamplers[MODE_LAST] = {
- SampleRgbLinePair, // MODE_RGB
- SampleRgbaLinePair, // MODE_RGBA
- SampleBgrLinePair, // MODE_BGR
- SampleBgraLinePair, // MODE_BGRA
- SampleArgbLinePair, // MODE_ARGB
- SampleRgba4444LinePair, // MODE_RGBA_4444
- SampleRgb565LinePair, // MODE_RGB_565
- SampleRgbaLinePair, // MODE_rgbA
- SampleBgraLinePair, // MODE_bgrA
- SampleArgbLinePair, // MODE_Argb
- SampleRgba4444LinePair // MODE_rgbA_4444
-};
-
-//------------------------------------------------------------------------------
#if !defined(FANCY_UPSAMPLING)
#define DUAL_SAMPLE_FUNC(FUNC_NAME, FUNC) \
@@ -166,7 +116,8 @@ static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bot_y, \
uint8_t* top_dst, uint8_t* bot_dst, int len) { \
const int half_len = len >> 1; \
int x; \
- if (top_dst != NULL) { \
+ assert(top_dst != NULL); \
+ { \
for (x = 0; x < half_len; ++x) { \
FUNC(top_y[2 * x + 0], top_u[x], top_v[x], top_dst + 8 * x + 0); \
FUNC(top_y[2 * x + 1], top_u[x], top_v[x], top_dst + 8 * x + 4); \
@@ -202,116 +153,75 @@ WebPUpsampleLinePairFunc WebPGetLinePairConverter(int alpha_is_last) {
// YUV444 converter
#define YUV444_FUNC(FUNC_NAME, FUNC, XSTEP) \
-static void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
- uint8_t* dst, int len) { \
+extern void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
+ uint8_t* dst, int len); \
+void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
+ uint8_t* dst, int len) { \
int i; \
for (i = 0; i < len; ++i) FUNC(y[i], u[i], v[i], &dst[i * XSTEP]); \
}
-YUV444_FUNC(Yuv444ToRgb, VP8YuvToRgb, 3)
-YUV444_FUNC(Yuv444ToBgr, VP8YuvToBgr, 3)
-YUV444_FUNC(Yuv444ToRgba, VP8YuvToRgba, 4)
-YUV444_FUNC(Yuv444ToBgra, VP8YuvToBgra, 4)
-YUV444_FUNC(Yuv444ToArgb, VP8YuvToArgb, 4)
-YUV444_FUNC(Yuv444ToRgba4444, VP8YuvToRgba4444, 2)
-YUV444_FUNC(Yuv444ToRgb565, VP8YuvToRgb565, 2)
+YUV444_FUNC(WebPYuv444ToRgbC, VP8YuvToRgb, 3)
+YUV444_FUNC(WebPYuv444ToBgrC, VP8YuvToBgr, 3)
+YUV444_FUNC(WebPYuv444ToRgbaC, VP8YuvToRgba, 4)
+YUV444_FUNC(WebPYuv444ToBgraC, VP8YuvToBgra, 4)
+YUV444_FUNC(WebPYuv444ToArgbC, VP8YuvToArgb, 4)
+YUV444_FUNC(WebPYuv444ToRgba4444C, VP8YuvToRgba4444, 2)
+YUV444_FUNC(WebPYuv444ToRgb565C, VP8YuvToRgb565, 2)
#undef YUV444_FUNC
-const WebPYUV444Converter WebPYUV444Converters[MODE_LAST] = {
- Yuv444ToRgb, // MODE_RGB
- Yuv444ToRgba, // MODE_RGBA
- Yuv444ToBgr, // MODE_BGR
- Yuv444ToBgra, // MODE_BGRA
- Yuv444ToArgb, // MODE_ARGB
- Yuv444ToRgba4444, // MODE_RGBA_4444
- Yuv444ToRgb565, // MODE_RGB_565
- Yuv444ToRgba, // MODE_rgbA
- Yuv444ToBgra, // MODE_bgrA
- Yuv444ToArgb, // MODE_Argb
- Yuv444ToRgba4444 // MODE_rgbA_4444
-};
-
-//------------------------------------------------------------------------------
-// Premultiplied modes
-
-// non dithered-modes
-
-// (x * a * 32897) >> 23 is bit-wise equivalent to (int)(x * a / 255.)
-// for all 8bit x or a. For bit-wise equivalence to (int)(x * a / 255. + .5),
-// one can use instead: (x * a * 65793 + (1 << 23)) >> 24
-#if 1 // (int)(x * a / 255.)
-#define MULTIPLIER(a) ((a) * 32897UL)
-#define PREMULTIPLY(x, m) (((x) * (m)) >> 23)
-#else // (int)(x * a / 255. + .5)
-#define MULTIPLIER(a) ((a) * 65793UL)
-#define PREMULTIPLY(x, m) (((x) * (m) + (1UL << 23)) >> 24)
-#endif
-
-static void ApplyAlphaMultiply(uint8_t* rgba, int alpha_first,
- int w, int h, int stride) {
- while (h-- > 0) {
- uint8_t* const rgb = rgba + (alpha_first ? 1 : 0);
- const uint8_t* const alpha = rgba + (alpha_first ? 0 : 3);
- int i;
- for (i = 0; i < w; ++i) {
- const uint32_t a = alpha[4 * i];
- if (a != 0xff) {
- const uint32_t mult = MULTIPLIER(a);
- rgb[4 * i + 0] = PREMULTIPLY(rgb[4 * i + 0], mult);
- rgb[4 * i + 1] = PREMULTIPLY(rgb[4 * i + 1], mult);
- rgb[4 * i + 2] = PREMULTIPLY(rgb[4 * i + 2], mult);
- }
- }
- rgba += stride;
- }
-}
-#undef MULTIPLIER
-#undef PREMULTIPLY
-
-// rgbA4444
+WebPYUV444Converter WebPYUV444Converters[MODE_LAST];
-#define MULTIPLIER(a) ((a) * 0x1111) // 0x1111 ~= (1 << 16) / 15
+extern void WebPInitYUV444ConvertersMIPSdspR2(void);
+extern void WebPInitYUV444ConvertersSSE2(void);
-static WEBP_INLINE uint8_t dither_hi(uint8_t x) {
- return (x & 0xf0) | (x >> 4);
-}
+static volatile VP8CPUInfo upsampling_last_cpuinfo_used1 =
+ (VP8CPUInfo)&upsampling_last_cpuinfo_used1;
-static WEBP_INLINE uint8_t dither_lo(uint8_t x) {
- return (x & 0x0f) | (x << 4);
-}
+WEBP_TSAN_IGNORE_FUNCTION void WebPInitYUV444Converters(void) {
+ if (upsampling_last_cpuinfo_used1 == VP8GetCPUInfo) return;
-static WEBP_INLINE uint8_t multiply(uint8_t x, uint32_t m) {
- return (x * m) >> 16;
-}
+ WebPYUV444Converters[MODE_RGB] = WebPYuv444ToRgbC;
+ WebPYUV444Converters[MODE_RGBA] = WebPYuv444ToRgbaC;
+ WebPYUV444Converters[MODE_BGR] = WebPYuv444ToBgrC;
+ WebPYUV444Converters[MODE_BGRA] = WebPYuv444ToBgraC;
+ WebPYUV444Converters[MODE_ARGB] = WebPYuv444ToArgbC;
+ WebPYUV444Converters[MODE_RGBA_4444] = WebPYuv444ToRgba4444C;
+ WebPYUV444Converters[MODE_RGB_565] = WebPYuv444ToRgb565C;
+ WebPYUV444Converters[MODE_rgbA] = WebPYuv444ToRgbaC;
+ WebPYUV444Converters[MODE_bgrA] = WebPYuv444ToBgraC;
+ WebPYUV444Converters[MODE_Argb] = WebPYuv444ToArgbC;
+ WebPYUV444Converters[MODE_rgbA_4444] = WebPYuv444ToRgba4444C;
-static void ApplyAlphaMultiply4444(uint8_t* rgba4444,
- int w, int h, int stride) {
- while (h-- > 0) {
- int i;
- for (i = 0; i < w; ++i) {
- const uint8_t a = (rgba4444[2 * i + 1] & 0x0f);
- const uint32_t mult = MULTIPLIER(a);
- const uint8_t r = multiply(dither_hi(rgba4444[2 * i + 0]), mult);
- const uint8_t g = multiply(dither_lo(rgba4444[2 * i + 0]), mult);
- const uint8_t b = multiply(dither_hi(rgba4444[2 * i + 1]), mult);
- rgba4444[2 * i + 0] = (r & 0xf0) | ((g >> 4) & 0x0f);
- rgba4444[2 * i + 1] = (b & 0xf0) | a;
+ if (VP8GetCPUInfo != NULL) {
+#if defined(WEBP_USE_SSE2)
+ if (VP8GetCPUInfo(kSSE2)) {
+ WebPInitYUV444ConvertersSSE2();
+ }
+#endif
+#if defined(WEBP_USE_MIPS_DSP_R2)
+ if (VP8GetCPUInfo(kMIPSdspR2)) {
+ WebPInitYUV444ConvertersMIPSdspR2();
}
- rgba4444 += stride;
+#endif
}
+ upsampling_last_cpuinfo_used1 = VP8GetCPUInfo;
}
-#undef MULTIPLIER
-
-void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int)
- = ApplyAlphaMultiply;
-void (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int)
- = ApplyAlphaMultiply4444;
//------------------------------------------------------------------------------
-// Main call
+// Main calls
+
+extern void WebPInitUpsamplersSSE2(void);
+extern void WebPInitUpsamplersNEON(void);
+extern void WebPInitUpsamplersMIPSdspR2(void);
+
+static volatile VP8CPUInfo upsampling_last_cpuinfo_used2 =
+ (VP8CPUInfo)&upsampling_last_cpuinfo_used2;
+
+WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplers(void) {
+ if (upsampling_last_cpuinfo_used2 == VP8GetCPUInfo) return;
-void WebPInitUpsamplers(void) {
#ifdef FANCY_UPSAMPLING
WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair;
WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair;
@@ -320,38 +230,31 @@ void WebPInitUpsamplers(void) {
WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair;
WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair;
WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair;
-
- // If defined, use CPUInfo() to overwrite some pointers with faster versions.
- if (VP8GetCPUInfo != NULL) {
-#if defined(WEBP_USE_SSE2)
- if (VP8GetCPUInfo(kSSE2)) {
- WebPInitUpsamplersSSE2();
- }
-#endif
- }
-#endif // FANCY_UPSAMPLING
-}
-
-void WebPInitPremultiply(void) {
- WebPApplyAlphaMultiply = ApplyAlphaMultiply;
- WebPApplyAlphaMultiply4444 = ApplyAlphaMultiply4444;
-
-#ifdef FANCY_UPSAMPLING
WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair;
WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair;
WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair;
WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair;
+ // If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_USE_SSE2)
if (VP8GetCPUInfo(kSSE2)) {
- WebPInitPremultiplySSE2();
+ WebPInitUpsamplersSSE2();
+ }
+#endif
+#if defined(WEBP_USE_NEON)
+ if (VP8GetCPUInfo(kNEON)) {
+ WebPInitUpsamplersNEON();
+ }
+#endif
+#if defined(WEBP_USE_MIPS_DSP_R2)
+ if (VP8GetCPUInfo(kMIPSdspR2)) {
+ WebPInitUpsamplersMIPSdspR2();
}
#endif
}
#endif // FANCY_UPSAMPLING
+ upsampling_last_cpuinfo_used2 = VP8GetCPUInfo;
}
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
+//------------------------------------------------------------------------------
diff --git a/drivers/webp/dsp/upsampling_mips_dsp_r2.c b/drivers/webp/dsp/upsampling_mips_dsp_r2.c
new file mode 100644
index 0000000000..46f207b43e
--- /dev/null
+++ b/drivers/webp/dsp/upsampling_mips_dsp_r2.c
@@ -0,0 +1,282 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// YUV to RGB upsampling functions.
+//
+// Author(s): Branimir Vasic (branimir.vasic@imgtec.com)
+// Djordje Pesut (djordje.pesut@imgtec.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_MIPS_DSP_R2)
+
+#include <assert.h>
+#include "./yuv.h"
+
+#if !defined(WEBP_YUV_USE_TABLE)
+
+#define YUV_TO_RGB(Y, U, V, R, G, B) do { \
+ const int t1 = kYScale * Y; \
+ const int t2 = kVToG * V; \
+ R = kVToR * V; \
+ G = kUToG * U; \
+ B = kUToB * U; \
+ R = t1 + R; \
+ G = t1 - G; \
+ B = t1 + B; \
+ R = R + kRCst; \
+ G = G - t2 + kGCst; \
+ B = B + kBCst; \
+ __asm__ volatile ( \
+ "shll_s.w %[" #R "], %[" #R "], 9 \n\t" \
+ "shll_s.w %[" #G "], %[" #G "], 9 \n\t" \
+ "shll_s.w %[" #B "], %[" #B "], 9 \n\t" \
+ "precrqu_s.qb.ph %[" #R "], %[" #R "], $zero \n\t" \
+ "precrqu_s.qb.ph %[" #G "], %[" #G "], $zero \n\t" \
+ "precrqu_s.qb.ph %[" #B "], %[" #B "], $zero \n\t" \
+ "srl %[" #R "], %[" #R "], 24 \n\t" \
+ "srl %[" #G "], %[" #G "], 24 \n\t" \
+ "srl %[" #B "], %[" #B "], 24 \n\t" \
+ : [R]"+r"(R), [G]"+r"(G), [B]"+r"(B) \
+ : \
+ ); \
+ } while (0)
+
+static WEBP_INLINE void YuvToRgb(int y, int u, int v, uint8_t* const rgb) {
+ int r, g, b;
+ YUV_TO_RGB(y, u, v, r, g, b);
+ rgb[0] = r;
+ rgb[1] = g;
+ rgb[2] = b;
+}
+static WEBP_INLINE void YuvToBgr(int y, int u, int v, uint8_t* const bgr) {
+ int r, g, b;
+ YUV_TO_RGB(y, u, v, r, g, b);
+ bgr[0] = b;
+ bgr[1] = g;
+ bgr[2] = r;
+}
+static WEBP_INLINE void YuvToRgb565(int y, int u, int v, uint8_t* const rgb) {
+ int r, g, b;
+ YUV_TO_RGB(y, u, v, r, g, b);
+ {
+ const int rg = (r & 0xf8) | (g >> 5);
+ const int gb = ((g << 3) & 0xe0) | (b >> 3);
+#ifdef WEBP_SWAP_16BIT_CSP
+ rgb[0] = gb;
+ rgb[1] = rg;
+#else
+ rgb[0] = rg;
+ rgb[1] = gb;
+#endif
+ }
+}
+static WEBP_INLINE void YuvToRgba4444(int y, int u, int v,
+ uint8_t* const argb) {
+ int r, g, b;
+ YUV_TO_RGB(y, u, v, r, g, b);
+ {
+ const int rg = (r & 0xf0) | (g >> 4);
+ const int ba = (b & 0xf0) | 0x0f; // overwrite the lower 4 bits
+#ifdef WEBP_SWAP_16BIT_CSP
+ argb[0] = ba;
+ argb[1] = rg;
+#else
+ argb[0] = rg;
+ argb[1] = ba;
+#endif
+ }
+}
+#endif // WEBP_YUV_USE_TABLE
+
+//-----------------------------------------------------------------------------
+// Alpha handling variants
+
+static WEBP_INLINE void YuvToArgb(uint8_t y, uint8_t u, uint8_t v,
+ uint8_t* const argb) {
+ int r, g, b;
+ YUV_TO_RGB(y, u, v, r, g, b);
+ argb[0] = 0xff;
+ argb[1] = r;
+ argb[2] = g;
+ argb[3] = b;
+}
+static WEBP_INLINE void YuvToBgra(uint8_t y, uint8_t u, uint8_t v,
+ uint8_t* const bgra) {
+ int r, g, b;
+ YUV_TO_RGB(y, u, v, r, g, b);
+ bgra[0] = b;
+ bgra[1] = g;
+ bgra[2] = r;
+ bgra[3] = 0xff;
+}
+static WEBP_INLINE void YuvToRgba(uint8_t y, uint8_t u, uint8_t v,
+ uint8_t* const rgba) {
+ int r, g, b;
+ YUV_TO_RGB(y, u, v, r, g, b);
+ rgba[0] = r;
+ rgba[1] = g;
+ rgba[2] = b;
+ rgba[3] = 0xff;
+}
+
+//------------------------------------------------------------------------------
+// Fancy upsampler
+
+#ifdef FANCY_UPSAMPLING
+
+// Given samples laid out in a square as:
+// [a b]
+// [c d]
+// we interpolate u/v as:
+// ([9*a + 3*b + 3*c + d 3*a + 9*b + 3*c + d] + [8 8]) / 16
+// ([3*a + b + 9*c + 3*d a + 3*b + 3*c + 9*d] [8 8]) / 16
+
+// We process u and v together stashed into 32bit (16bit each).
+#define LOAD_UV(u, v) ((u) | ((v) << 16))
+
+#define UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \
+static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
+ const uint8_t* top_u, const uint8_t* top_v, \
+ const uint8_t* cur_u, const uint8_t* cur_v, \
+ uint8_t* top_dst, uint8_t* bottom_dst, int len) { \
+ int x; \
+ const int last_pixel_pair = (len - 1) >> 1; \
+ uint32_t tl_uv = LOAD_UV(top_u[0], top_v[0]); /* top-left sample */ \
+ uint32_t l_uv = LOAD_UV(cur_u[0], cur_v[0]); /* left-sample */ \
+ assert(top_y != NULL); \
+ { \
+ const uint32_t uv0 = (3 * tl_uv + l_uv + 0x00020002u) >> 2; \
+ FUNC(top_y[0], uv0 & 0xff, (uv0 >> 16), top_dst); \
+ } \
+ if (bottom_y != NULL) { \
+ const uint32_t uv0 = (3 * l_uv + tl_uv + 0x00020002u) >> 2; \
+ FUNC(bottom_y[0], uv0 & 0xff, (uv0 >> 16), bottom_dst); \
+ } \
+ for (x = 1; x <= last_pixel_pair; ++x) { \
+ const uint32_t t_uv = LOAD_UV(top_u[x], top_v[x]); /* top sample */ \
+ const uint32_t uv = LOAD_UV(cur_u[x], cur_v[x]); /* sample */ \
+ /* precompute invariant values associated with first and second diagonals*/\
+ const uint32_t avg = tl_uv + t_uv + l_uv + uv + 0x00080008u; \
+ const uint32_t diag_12 = (avg + 2 * (t_uv + l_uv)) >> 3; \
+ const uint32_t diag_03 = (avg + 2 * (tl_uv + uv)) >> 3; \
+ { \
+ const uint32_t uv0 = (diag_12 + tl_uv) >> 1; \
+ const uint32_t uv1 = (diag_03 + t_uv) >> 1; \
+ FUNC(top_y[2 * x - 1], uv0 & 0xff, (uv0 >> 16), \
+ top_dst + (2 * x - 1) * XSTEP); \
+ FUNC(top_y[2 * x - 0], uv1 & 0xff, (uv1 >> 16), \
+ top_dst + (2 * x - 0) * XSTEP); \
+ } \
+ if (bottom_y != NULL) { \
+ const uint32_t uv0 = (diag_03 + l_uv) >> 1; \
+ const uint32_t uv1 = (diag_12 + uv) >> 1; \
+ FUNC(bottom_y[2 * x - 1], uv0 & 0xff, (uv0 >> 16), \
+ bottom_dst + (2 * x - 1) * XSTEP); \
+ FUNC(bottom_y[2 * x + 0], uv1 & 0xff, (uv1 >> 16), \
+ bottom_dst + (2 * x + 0) * XSTEP); \
+ } \
+ tl_uv = t_uv; \
+ l_uv = uv; \
+ } \
+ if (!(len & 1)) { \
+ { \
+ const uint32_t uv0 = (3 * tl_uv + l_uv + 0x00020002u) >> 2; \
+ FUNC(top_y[len - 1], uv0 & 0xff, (uv0 >> 16), \
+ top_dst + (len - 1) * XSTEP); \
+ } \
+ if (bottom_y != NULL) { \
+ const uint32_t uv0 = (3 * l_uv + tl_uv + 0x00020002u) >> 2; \
+ FUNC(bottom_y[len - 1], uv0 & 0xff, (uv0 >> 16), \
+ bottom_dst + (len - 1) * XSTEP); \
+ } \
+ } \
+}
+
+// All variants implemented.
+UPSAMPLE_FUNC(UpsampleRgbLinePair, YuvToRgb, 3)
+UPSAMPLE_FUNC(UpsampleBgrLinePair, YuvToBgr, 3)
+UPSAMPLE_FUNC(UpsampleRgbaLinePair, YuvToRgba, 4)
+UPSAMPLE_FUNC(UpsampleBgraLinePair, YuvToBgra, 4)
+UPSAMPLE_FUNC(UpsampleArgbLinePair, YuvToArgb, 4)
+UPSAMPLE_FUNC(UpsampleRgba4444LinePair, YuvToRgba4444, 2)
+UPSAMPLE_FUNC(UpsampleRgb565LinePair, YuvToRgb565, 2)
+
+#undef LOAD_UV
+#undef UPSAMPLE_FUNC
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void WebPInitUpsamplersMIPSdspR2(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplersMIPSdspR2(void) {
+ WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair;
+ WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair;
+ WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair;
+ WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair;
+ WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair;
+ WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair;
+ WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair;
+ WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair;
+ WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair;
+ WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair;
+ WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair;
+}
+
+#endif // FANCY_UPSAMPLING
+
+//------------------------------------------------------------------------------
+// YUV444 converter
+
+#define YUV444_FUNC(FUNC_NAME, FUNC, XSTEP) \
+static void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
+ uint8_t* dst, int len) { \
+ int i; \
+ for (i = 0; i < len; ++i) FUNC(y[i], u[i], v[i], &dst[i * XSTEP]); \
+}
+
+YUV444_FUNC(Yuv444ToRgb, YuvToRgb, 3)
+YUV444_FUNC(Yuv444ToBgr, YuvToBgr, 3)
+YUV444_FUNC(Yuv444ToRgba, YuvToRgba, 4)
+YUV444_FUNC(Yuv444ToBgra, YuvToBgra, 4)
+YUV444_FUNC(Yuv444ToArgb, YuvToArgb, 4)
+YUV444_FUNC(Yuv444ToRgba4444, YuvToRgba4444, 2)
+YUV444_FUNC(Yuv444ToRgb565, YuvToRgb565, 2)
+
+#undef YUV444_FUNC
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void WebPInitYUV444ConvertersMIPSdspR2(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void WebPInitYUV444ConvertersMIPSdspR2(void) {
+ WebPYUV444Converters[MODE_RGB] = Yuv444ToRgb;
+ WebPYUV444Converters[MODE_RGBA] = Yuv444ToRgba;
+ WebPYUV444Converters[MODE_BGR] = Yuv444ToBgr;
+ WebPYUV444Converters[MODE_BGRA] = Yuv444ToBgra;
+ WebPYUV444Converters[MODE_ARGB] = Yuv444ToArgb;
+ WebPYUV444Converters[MODE_RGBA_4444] = Yuv444ToRgba4444;
+ WebPYUV444Converters[MODE_RGB_565] = Yuv444ToRgb565;
+ WebPYUV444Converters[MODE_rgbA] = Yuv444ToRgba;
+ WebPYUV444Converters[MODE_bgrA] = Yuv444ToBgra;
+ WebPYUV444Converters[MODE_Argb] = Yuv444ToArgb;
+ WebPYUV444Converters[MODE_rgbA_4444] = Yuv444ToRgba4444;
+}
+
+#else // !WEBP_USE_MIPS_DSP_R2
+
+WEBP_DSP_INIT_STUB(WebPInitYUV444ConvertersMIPSdspR2)
+
+#endif // WEBP_USE_MIPS_DSP_R2
+
+#if !(defined(FANCY_UPSAMPLING) && defined(WEBP_USE_MIPS_DSP_R2))
+WEBP_DSP_INIT_STUB(WebPInitUpsamplersMIPSdspR2)
+#endif
diff --git a/drivers/webp/dsp/upsampling_neon.c b/drivers/webp/dsp/upsampling_neon.c
new file mode 100644
index 0000000000..a8384c2149
--- /dev/null
+++ b/drivers/webp/dsp/upsampling_neon.c
@@ -0,0 +1,261 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// NEON version of YUV to RGB upsampling functions.
+//
+// Author: mans@mansr.com (Mans Rullgard)
+// Based on SSE code by: somnath@google.com (Somnath Banerjee)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_NEON)
+
+#include <assert.h>
+#include <arm_neon.h>
+#include <string.h>
+#include "./neon.h"
+#include "./yuv.h"
+
+#ifdef FANCY_UPSAMPLING
+
+//-----------------------------------------------------------------------------
+// U/V upsampling
+
+// Loads 9 pixels each from rows r1 and r2 and generates 16 pixels.
+#define UPSAMPLE_16PIXELS(r1, r2, out) { \
+ uint8x8_t a = vld1_u8(r1); \
+ uint8x8_t b = vld1_u8(r1 + 1); \
+ uint8x8_t c = vld1_u8(r2); \
+ uint8x8_t d = vld1_u8(r2 + 1); \
+ \
+ uint16x8_t al = vshll_n_u8(a, 1); \
+ uint16x8_t bl = vshll_n_u8(b, 1); \
+ uint16x8_t cl = vshll_n_u8(c, 1); \
+ uint16x8_t dl = vshll_n_u8(d, 1); \
+ \
+ uint8x8_t diag1, diag2; \
+ uint16x8_t sl; \
+ \
+ /* a + b + c + d */ \
+ sl = vaddl_u8(a, b); \
+ sl = vaddw_u8(sl, c); \
+ sl = vaddw_u8(sl, d); \
+ \
+ al = vaddq_u16(sl, al); /* 3a + b + c + d */ \
+ bl = vaddq_u16(sl, bl); /* a + 3b + c + d */ \
+ \
+ al = vaddq_u16(al, dl); /* 3a + b + c + 3d */ \
+ bl = vaddq_u16(bl, cl); /* a + 3b + 3c + d */ \
+ \
+ diag2 = vshrn_n_u16(al, 3); \
+ diag1 = vshrn_n_u16(bl, 3); \
+ \
+ a = vrhadd_u8(a, diag1); \
+ b = vrhadd_u8(b, diag2); \
+ c = vrhadd_u8(c, diag2); \
+ d = vrhadd_u8(d, diag1); \
+ \
+ { \
+ uint8x8x2_t a_b, c_d; \
+ INIT_VECTOR2(a_b, a, b); \
+ INIT_VECTOR2(c_d, c, d); \
+ vst2_u8(out, a_b); \
+ vst2_u8(out + 32, c_d); \
+ } \
+}
+
+// Turn the macro into a function for reducing code-size when non-critical
+static void Upsample16Pixels(const uint8_t *r1, const uint8_t *r2,
+ uint8_t *out) {
+ UPSAMPLE_16PIXELS(r1, r2, out);
+}
+
+#define UPSAMPLE_LAST_BLOCK(tb, bb, num_pixels, out) { \
+ uint8_t r1[9], r2[9]; \
+ memcpy(r1, (tb), (num_pixels)); \
+ memcpy(r2, (bb), (num_pixels)); \
+ /* replicate last byte */ \
+ memset(r1 + (num_pixels), r1[(num_pixels) - 1], 9 - (num_pixels)); \
+ memset(r2 + (num_pixels), r2[(num_pixels) - 1], 9 - (num_pixels)); \
+ Upsample16Pixels(r1, r2, out); \
+}
+
+//-----------------------------------------------------------------------------
+// YUV->RGB conversion
+
+static const int16_t kCoeffs[4] = { kYScale, kVToR, kUToG, kVToG };
+
+#define v255 vdup_n_u8(255)
+
+#define STORE_Rgb(out, r, g, b) do { \
+ uint8x8x3_t r_g_b; \
+ INIT_VECTOR3(r_g_b, r, g, b); \
+ vst3_u8(out, r_g_b); \
+} while (0)
+
+#define STORE_Bgr(out, r, g, b) do { \
+ uint8x8x3_t b_g_r; \
+ INIT_VECTOR3(b_g_r, b, g, r); \
+ vst3_u8(out, b_g_r); \
+} while (0)
+
+#define STORE_Rgba(out, r, g, b) do { \
+ uint8x8x4_t r_g_b_v255; \
+ INIT_VECTOR4(r_g_b_v255, r, g, b, v255); \
+ vst4_u8(out, r_g_b_v255); \
+} while (0)
+
+#define STORE_Bgra(out, r, g, b) do { \
+ uint8x8x4_t b_g_r_v255; \
+ INIT_VECTOR4(b_g_r_v255, b, g, r, v255); \
+ vst4_u8(out, b_g_r_v255); \
+} while (0)
+
+#define CONVERT8(FMT, XSTEP, N, src_y, src_uv, out, cur_x) { \
+ int i; \
+ for (i = 0; i < N; i += 8) { \
+ const int off = ((cur_x) + i) * XSTEP; \
+ uint8x8_t y = vld1_u8((src_y) + (cur_x) + i); \
+ uint8x8_t u = vld1_u8((src_uv) + i); \
+ uint8x8_t v = vld1_u8((src_uv) + i + 16); \
+ const int16x8_t yy = vreinterpretq_s16_u16(vsubl_u8(y, u16)); \
+ const int16x8_t uu = vreinterpretq_s16_u16(vsubl_u8(u, u128)); \
+ const int16x8_t vv = vreinterpretq_s16_u16(vsubl_u8(v, u128)); \
+ int32x4_t yl = vmull_lane_s16(vget_low_s16(yy), cf16, 0); \
+ int32x4_t yh = vmull_lane_s16(vget_high_s16(yy), cf16, 0); \
+ const int32x4_t rl = vmlal_lane_s16(yl, vget_low_s16(vv), cf16, 1);\
+ const int32x4_t rh = vmlal_lane_s16(yh, vget_high_s16(vv), cf16, 1);\
+ int32x4_t gl = vmlsl_lane_s16(yl, vget_low_s16(uu), cf16, 2); \
+ int32x4_t gh = vmlsl_lane_s16(yh, vget_high_s16(uu), cf16, 2); \
+ const int32x4_t bl = vmovl_s16(vget_low_s16(uu)); \
+ const int32x4_t bh = vmovl_s16(vget_high_s16(uu)); \
+ gl = vmlsl_lane_s16(gl, vget_low_s16(vv), cf16, 3); \
+ gh = vmlsl_lane_s16(gh, vget_high_s16(vv), cf16, 3); \
+ yl = vmlaq_lane_s32(yl, bl, cf32, 0); \
+ yh = vmlaq_lane_s32(yh, bh, cf32, 0); \
+ /* vrshrn_n_s32() already incorporates the rounding constant */ \
+ y = vqmovun_s16(vcombine_s16(vrshrn_n_s32(rl, YUV_FIX2), \
+ vrshrn_n_s32(rh, YUV_FIX2))); \
+ u = vqmovun_s16(vcombine_s16(vrshrn_n_s32(gl, YUV_FIX2), \
+ vrshrn_n_s32(gh, YUV_FIX2))); \
+ v = vqmovun_s16(vcombine_s16(vrshrn_n_s32(yl, YUV_FIX2), \
+ vrshrn_n_s32(yh, YUV_FIX2))); \
+ STORE_ ## FMT(out + off, y, u, v); \
+ } \
+}
+
+#define CONVERT1(FUNC, XSTEP, N, src_y, src_uv, rgb, cur_x) { \
+ int i; \
+ for (i = 0; i < N; i++) { \
+ const int off = ((cur_x) + i) * XSTEP; \
+ const int y = src_y[(cur_x) + i]; \
+ const int u = (src_uv)[i]; \
+ const int v = (src_uv)[i + 16]; \
+ FUNC(y, u, v, rgb + off); \
+ } \
+}
+
+#define CONVERT2RGB_8(FMT, XSTEP, top_y, bottom_y, uv, \
+ top_dst, bottom_dst, cur_x, len) { \
+ CONVERT8(FMT, XSTEP, len, top_y, uv, top_dst, cur_x) \
+ if (bottom_y != NULL) { \
+ CONVERT8(FMT, XSTEP, len, bottom_y, (uv) + 32, bottom_dst, cur_x) \
+ } \
+}
+
+#define CONVERT2RGB_1(FUNC, XSTEP, top_y, bottom_y, uv, \
+ top_dst, bottom_dst, cur_x, len) { \
+ CONVERT1(FUNC, XSTEP, len, top_y, uv, top_dst, cur_x); \
+ if (bottom_y != NULL) { \
+ CONVERT1(FUNC, XSTEP, len, bottom_y, (uv) + 32, bottom_dst, cur_x); \
+ } \
+}
+
+#define NEON_UPSAMPLE_FUNC(FUNC_NAME, FMT, XSTEP) \
+static void FUNC_NAME(const uint8_t *top_y, const uint8_t *bottom_y, \
+ const uint8_t *top_u, const uint8_t *top_v, \
+ const uint8_t *cur_u, const uint8_t *cur_v, \
+ uint8_t *top_dst, uint8_t *bottom_dst, int len) { \
+ int block; \
+ /* 16 byte aligned array to cache reconstructed u and v */ \
+ uint8_t uv_buf[2 * 32 + 15]; \
+ uint8_t *const r_uv = (uint8_t*)((uintptr_t)(uv_buf + 15) & ~15); \
+ const int uv_len = (len + 1) >> 1; \
+ /* 9 pixels must be read-able for each block */ \
+ const int num_blocks = (uv_len - 1) >> 3; \
+ const int leftover = uv_len - num_blocks * 8; \
+ const int last_pos = 1 + 16 * num_blocks; \
+ \
+ const int u_diag = ((top_u[0] + cur_u[0]) >> 1) + 1; \
+ const int v_diag = ((top_v[0] + cur_v[0]) >> 1) + 1; \
+ \
+ const int16x4_t cf16 = vld1_s16(kCoeffs); \
+ const int32x2_t cf32 = vdup_n_s32(kUToB); \
+ const uint8x8_t u16 = vdup_n_u8(16); \
+ const uint8x8_t u128 = vdup_n_u8(128); \
+ \
+ /* Treat the first pixel in regular way */ \
+ assert(top_y != NULL); \
+ { \
+ const int u0 = (top_u[0] + u_diag) >> 1; \
+ const int v0 = (top_v[0] + v_diag) >> 1; \
+ VP8YuvTo ## FMT(top_y[0], u0, v0, top_dst); \
+ } \
+ if (bottom_y != NULL) { \
+ const int u0 = (cur_u[0] + u_diag) >> 1; \
+ const int v0 = (cur_v[0] + v_diag) >> 1; \
+ VP8YuvTo ## FMT(bottom_y[0], u0, v0, bottom_dst); \
+ } \
+ \
+ for (block = 0; block < num_blocks; ++block) { \
+ UPSAMPLE_16PIXELS(top_u, cur_u, r_uv); \
+ UPSAMPLE_16PIXELS(top_v, cur_v, r_uv + 16); \
+ CONVERT2RGB_8(FMT, XSTEP, top_y, bottom_y, r_uv, \
+ top_dst, bottom_dst, 16 * block + 1, 16); \
+ top_u += 8; \
+ cur_u += 8; \
+ top_v += 8; \
+ cur_v += 8; \
+ } \
+ \
+ UPSAMPLE_LAST_BLOCK(top_u, cur_u, leftover, r_uv); \
+ UPSAMPLE_LAST_BLOCK(top_v, cur_v, leftover, r_uv + 16); \
+ CONVERT2RGB_1(VP8YuvTo ## FMT, XSTEP, top_y, bottom_y, r_uv, \
+ top_dst, bottom_dst, last_pos, len - last_pos); \
+}
+
+// NEON variants of the fancy upsampler.
+NEON_UPSAMPLE_FUNC(UpsampleRgbLinePair, Rgb, 3)
+NEON_UPSAMPLE_FUNC(UpsampleBgrLinePair, Bgr, 3)
+NEON_UPSAMPLE_FUNC(UpsampleRgbaLinePair, Rgba, 4)
+NEON_UPSAMPLE_FUNC(UpsampleBgraLinePair, Bgra, 4)
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */];
+
+extern void WebPInitUpsamplersNEON(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplersNEON(void) {
+ WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair;
+ WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair;
+ WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair;
+ WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair;
+ WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair;
+ WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair;
+}
+
+#endif // FANCY_UPSAMPLING
+
+#endif // WEBP_USE_NEON
+
+#if !(defined(FANCY_UPSAMPLING) && defined(WEBP_USE_NEON))
+WEBP_DSP_INIT_STUB(WebPInitUpsamplersNEON)
+#endif
diff --git a/drivers/webp/dsp/upsampling_sse2.c b/drivers/webp/dsp/upsampling_sse2.c
index 8cb275a02b..b85808e271 100644
--- a/drivers/webp/dsp/upsampling_sse2.c
+++ b/drivers/webp/dsp/upsampling_sse2.c
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// SSE2 version of YUV to RGB upsampling functions.
@@ -18,10 +20,6 @@
#include <string.h>
#include "./yuv.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
#ifdef FANCY_UPSAMPLING
// We compute (9*a + 3*b + 3*c + d + 8) / 16 as follows
@@ -49,23 +47,23 @@ extern "C" {
(out) = _mm_sub_epi8(tmp0, tmp4); /* (k + in + 1) / 2 - lsb_correction */ \
} while (0)
-// pack and store two alterning pixel rows
+// pack and store two alternating pixel rows
#define PACK_AND_STORE(a, b, da, db, out) do { \
- const __m128i ta = _mm_avg_epu8(a, da); /* (9a + 3b + 3c + d + 8) / 16 */ \
- const __m128i tb = _mm_avg_epu8(b, db); /* (3a + 9b + c + 3d + 8) / 16 */ \
- const __m128i t1 = _mm_unpacklo_epi8(ta, tb); \
- const __m128i t2 = _mm_unpackhi_epi8(ta, tb); \
- _mm_store_si128(((__m128i*)(out)) + 0, t1); \
- _mm_store_si128(((__m128i*)(out)) + 1, t2); \
+ const __m128i t_a = _mm_avg_epu8(a, da); /* (9a + 3b + 3c + d + 8) / 16 */ \
+ const __m128i t_b = _mm_avg_epu8(b, db); /* (3a + 9b + c + 3d + 8) / 16 */ \
+ const __m128i t_1 = _mm_unpacklo_epi8(t_a, t_b); \
+ const __m128i t_2 = _mm_unpackhi_epi8(t_a, t_b); \
+ _mm_store_si128(((__m128i*)(out)) + 0, t_1); \
+ _mm_store_si128(((__m128i*)(out)) + 1, t_2); \
} while (0)
// Loads 17 pixels each from rows r1 and r2 and generates 32 pixels.
#define UPSAMPLE_32PIXELS(r1, r2, out) { \
const __m128i one = _mm_set1_epi8(1); \
- const __m128i a = _mm_loadu_si128((__m128i*)&(r1)[0]); \
- const __m128i b = _mm_loadu_si128((__m128i*)&(r1)[1]); \
- const __m128i c = _mm_loadu_si128((__m128i*)&(r2)[0]); \
- const __m128i d = _mm_loadu_si128((__m128i*)&(r2)[1]); \
+ const __m128i a = _mm_loadu_si128((const __m128i*)&(r1)[0]); \
+ const __m128i b = _mm_loadu_si128((const __m128i*)&(r1)[1]); \
+ const __m128i c = _mm_loadu_si128((const __m128i*)&(r2)[0]); \
+ const __m128i d = _mm_loadu_si128((const __m128i*)&(r2)[1]); \
\
const __m128i s = _mm_avg_epu8(a, d); /* s = (a + d + 1) / 2 */ \
const __m128i t = _mm_avg_epu8(b, c); /* t = (b + c + 1) / 2 */ \
@@ -85,8 +83,8 @@ extern "C" {
GET_M(ad, s, diag2); /* diag2 = (3a + b + c + 3d) / 8 */ \
\
/* pack the alternate pixels */ \
- PACK_AND_STORE(a, b, diag1, diag2, &(out)[0 * 32]); \
- PACK_AND_STORE(c, d, diag2, diag1, &(out)[2 * 32]); \
+ PACK_AND_STORE(a, b, diag1, diag2, out + 0); /* store top */ \
+ PACK_AND_STORE(c, d, diag2, diag1, out + 2 * 32); /* store bottom */ \
}
// Turn the macro into a function for reducing code-size when non-critical
@@ -106,104 +104,140 @@ static void Upsample32Pixels(const uint8_t r1[], const uint8_t r2[],
Upsample32Pixels(r1, r2, out); \
}
-#define CONVERT2RGB(FUNC, XSTEP, top_y, bottom_y, uv, \
+#define CONVERT2RGB(FUNC, XSTEP, top_y, bottom_y, \
top_dst, bottom_dst, cur_x, num_pixels) { \
int n; \
- if (top_y) { \
- for (n = 0; n < (num_pixels); ++n) { \
- FUNC(top_y[(cur_x) + n], (uv)[n], (uv)[32 + n], \
- top_dst + ((cur_x) + n) * XSTEP); \
- } \
+ for (n = 0; n < (num_pixels); ++n) { \
+ FUNC(top_y[(cur_x) + n], r_u[n], r_v[n], \
+ top_dst + ((cur_x) + n) * XSTEP); \
} \
- if (bottom_y) { \
+ if (bottom_y != NULL) { \
for (n = 0; n < (num_pixels); ++n) { \
- FUNC(bottom_y[(cur_x) + n], (uv)[64 + n], (uv)[64 + 32 + n], \
+ FUNC(bottom_y[(cur_x) + n], r_u[64 + n], r_v[64 + n], \
bottom_dst + ((cur_x) + n) * XSTEP); \
} \
} \
}
+#define CONVERT2RGB_32(FUNC, XSTEP, top_y, bottom_y, \
+ top_dst, bottom_dst, cur_x) do { \
+ FUNC##32(top_y + (cur_x), r_u, r_v, top_dst + (cur_x) * XSTEP); \
+ if (bottom_y != NULL) { \
+ FUNC##32(bottom_y + (cur_x), r_u + 64, r_v + 64, \
+ bottom_dst + (cur_x) * XSTEP); \
+ } \
+} while (0)
+
#define SSE2_UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \
static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
const uint8_t* top_u, const uint8_t* top_v, \
const uint8_t* cur_u, const uint8_t* cur_v, \
uint8_t* top_dst, uint8_t* bottom_dst, int len) { \
- int b; \
- /* 16 byte aligned array to cache reconstructed u and v */ \
+ int uv_pos, pos; \
+ /* 16byte-aligned array to cache reconstructed u and v */ \
uint8_t uv_buf[4 * 32 + 15]; \
- uint8_t* const r_uv = (uint8_t*)((uintptr_t)(uv_buf + 15) & ~15); \
- const int uv_len = (len + 1) >> 1; \
- /* 17 pixels must be read-able for each block */ \
- const int num_blocks = (uv_len - 1) >> 4; \
- const int leftover = uv_len - num_blocks * 16; \
- const int last_pos = 1 + 32 * num_blocks; \
- \
- const int u_diag = ((top_u[0] + cur_u[0]) >> 1) + 1; \
- const int v_diag = ((top_v[0] + cur_v[0]) >> 1) + 1; \
+ uint8_t* const r_u = (uint8_t*)((uintptr_t)(uv_buf + 15) & ~15); \
+ uint8_t* const r_v = r_u + 32; \
\
- assert(len > 0); \
- /* Treat the first pixel in regular way */ \
- if (top_y) { \
- const int u0 = (top_u[0] + u_diag) >> 1; \
- const int v0 = (top_v[0] + v_diag) >> 1; \
- FUNC(top_y[0], u0, v0, top_dst); \
+ assert(top_y != NULL); \
+ { /* Treat the first pixel in regular way */ \
+ const int u_diag = ((top_u[0] + cur_u[0]) >> 1) + 1; \
+ const int v_diag = ((top_v[0] + cur_v[0]) >> 1) + 1; \
+ const int u0_t = (top_u[0] + u_diag) >> 1; \
+ const int v0_t = (top_v[0] + v_diag) >> 1; \
+ FUNC(top_y[0], u0_t, v0_t, top_dst); \
+ if (bottom_y != NULL) { \
+ const int u0_b = (cur_u[0] + u_diag) >> 1; \
+ const int v0_b = (cur_v[0] + v_diag) >> 1; \
+ FUNC(bottom_y[0], u0_b, v0_b, bottom_dst); \
+ } \
} \
- if (bottom_y) { \
- const int u0 = (cur_u[0] + u_diag) >> 1; \
- const int v0 = (cur_v[0] + v_diag) >> 1; \
- FUNC(bottom_y[0], u0, v0, bottom_dst); \
+ /* For UPSAMPLE_32PIXELS, 17 u/v values must be read-able for each block */ \
+ for (pos = 1, uv_pos = 0; pos + 32 + 1 <= len; pos += 32, uv_pos += 16) { \
+ UPSAMPLE_32PIXELS(top_u + uv_pos, cur_u + uv_pos, r_u); \
+ UPSAMPLE_32PIXELS(top_v + uv_pos, cur_v + uv_pos, r_v); \
+ CONVERT2RGB_32(FUNC, XSTEP, top_y, bottom_y, top_dst, bottom_dst, pos); \
} \
- \
- for (b = 0; b < num_blocks; ++b) { \
- UPSAMPLE_32PIXELS(top_u, cur_u, r_uv + 0 * 32); \
- UPSAMPLE_32PIXELS(top_v, cur_v, r_uv + 1 * 32); \
- CONVERT2RGB(FUNC, XSTEP, top_y, bottom_y, r_uv, top_dst, bottom_dst, \
- 32 * b + 1, 32) \
- top_u += 16; \
- cur_u += 16; \
- top_v += 16; \
- cur_v += 16; \
+ if (len > 1) { \
+ const int left_over = ((len + 1) >> 1) - (pos >> 1); \
+ assert(left_over > 0); \
+ UPSAMPLE_LAST_BLOCK(top_u + uv_pos, cur_u + uv_pos, left_over, r_u); \
+ UPSAMPLE_LAST_BLOCK(top_v + uv_pos, cur_v + uv_pos, left_over, r_v); \
+ CONVERT2RGB(FUNC, XSTEP, top_y, bottom_y, top_dst, bottom_dst, \
+ pos, len - pos); \
} \
- \
- UPSAMPLE_LAST_BLOCK(top_u, cur_u, leftover, r_uv + 0 * 32); \
- UPSAMPLE_LAST_BLOCK(top_v, cur_v, leftover, r_uv + 1 * 32); \
- CONVERT2RGB(FUNC, XSTEP, top_y, bottom_y, r_uv, top_dst, bottom_dst, \
- last_pos, len - last_pos); \
}
// SSE2 variants of the fancy upsampler.
-SSE2_UPSAMPLE_FUNC(UpsampleRgbLinePairSSE2, VP8YuvToRgb, 3)
-SSE2_UPSAMPLE_FUNC(UpsampleBgrLinePairSSE2, VP8YuvToBgr, 3)
-SSE2_UPSAMPLE_FUNC(UpsampleRgbaLinePairSSE2, VP8YuvToRgba, 4)
-SSE2_UPSAMPLE_FUNC(UpsampleBgraLinePairSSE2, VP8YuvToBgra, 4)
+SSE2_UPSAMPLE_FUNC(UpsampleRgbLinePair, VP8YuvToRgb, 3)
+SSE2_UPSAMPLE_FUNC(UpsampleBgrLinePair, VP8YuvToBgr, 3)
+SSE2_UPSAMPLE_FUNC(UpsampleRgbaLinePair, VP8YuvToRgba, 4)
+SSE2_UPSAMPLE_FUNC(UpsampleBgraLinePair, VP8YuvToBgra, 4)
#undef GET_M
#undef PACK_AND_STORE
#undef UPSAMPLE_32PIXELS
#undef UPSAMPLE_LAST_BLOCK
#undef CONVERT2RGB
+#undef CONVERT2RGB_32
#undef SSE2_UPSAMPLE_FUNC
//------------------------------------------------------------------------------
+// Entry point
extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */];
-void WebPInitUpsamplersSSE2(void) {
- WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePairSSE2;
- WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePairSSE2;
- WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePairSSE2;
- WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePairSSE2;
-}
+extern void WebPInitUpsamplersSSE2(void);
-void WebPInitPremultiplySSE2(void) {
- WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePairSSE2;
- WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePairSSE2;
+WEBP_TSAN_IGNORE_FUNCTION void WebPInitUpsamplersSSE2(void) {
+ VP8YUVInitSSE2();
+ WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair;
+ WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair;
+ WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair;
+ WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair;
+ WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair;
+ WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair;
}
#endif // FANCY_UPSAMPLING
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
+//------------------------------------------------------------------------------
+
+extern WebPYUV444Converter WebPYUV444Converters[/* MODE_LAST */];
+extern void WebPInitYUV444ConvertersSSE2(void);
+
+#define YUV444_FUNC(FUNC_NAME, CALL, XSTEP) \
+extern void WebP##FUNC_NAME##C(const uint8_t* y, const uint8_t* u, \
+ const uint8_t* v, uint8_t* dst, int len); \
+static void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
+ uint8_t* dst, int len) { \
+ int i; \
+ const int max_len = len & ~31; \
+ for (i = 0; i < max_len; i += 32) CALL(y + i, u + i, v + i, dst + i * XSTEP);\
+ if (i < len) { /* C-fallback */ \
+ WebP##FUNC_NAME##C(y + i, u + i, v + i, dst + i * XSTEP, len - i); \
+ } \
+}
-#endif // WEBP_USE_SSE2
+YUV444_FUNC(Yuv444ToRgba, VP8YuvToRgba32, 4);
+YUV444_FUNC(Yuv444ToBgra, VP8YuvToBgra32, 4);
+YUV444_FUNC(Yuv444ToRgb, VP8YuvToRgb32, 3);
+YUV444_FUNC(Yuv444ToBgr, VP8YuvToBgr32, 3);
+
+WEBP_TSAN_IGNORE_FUNCTION void WebPInitYUV444ConvertersSSE2(void) {
+ VP8YUVInitSSE2();
+ WebPYUV444Converters[MODE_RGBA] = Yuv444ToRgba;
+ WebPYUV444Converters[MODE_BGRA] = Yuv444ToBgra;
+ WebPYUV444Converters[MODE_RGB] = Yuv444ToRgb;
+ WebPYUV444Converters[MODE_BGR] = Yuv444ToBgr;
+}
+
+#else
+
+WEBP_DSP_INIT_STUB(WebPInitYUV444ConvertersSSE2)
+
+#endif // WEBP_USE_SSE2
+
+#if !(defined(FANCY_UPSAMPLING) && defined(WEBP_USE_SSE2))
+WEBP_DSP_INIT_STUB(WebPInitUpsamplersSSE2)
+#endif
diff --git a/drivers/webp/dsp/yuv.c b/drivers/webp/dsp/yuv.c
index 7f05f9a3aa..f50a253168 100644
--- a/drivers/webp/dsp/yuv.c
+++ b/drivers/webp/dsp/yuv.c
@@ -1,26 +1,19 @@
// Copyright 2010 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
-// YUV->RGB conversion function
+// YUV->RGB conversion functions
//
// Author: Skal (pascal.massimino@gmail.com)
#include "./yuv.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-enum { YUV_HALF = 1 << (YUV_FIX - 1) };
-
-int16_t VP8kVToR[256], VP8kUToB[256];
-int32_t VP8kVToG[256], VP8kUToG[256];
-uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN];
-uint8_t VP8kClip4Bits[YUV_RANGE_MAX - YUV_RANGE_MIN];
+#if defined(WEBP_YUV_USE_TABLE)
static int done = 0;
@@ -28,11 +21,17 @@ static WEBP_INLINE uint8_t clip(int v, int max_value) {
return v < 0 ? 0 : v > max_value ? max_value : v;
}
-void VP8YUVInit(void) {
+int16_t VP8kVToR[256], VP8kUToB[256];
+int32_t VP8kVToG[256], VP8kUToG[256];
+uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN];
+uint8_t VP8kClip4Bits[YUV_RANGE_MAX - YUV_RANGE_MIN];
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8YUVInit(void) {
int i;
if (done) {
return;
}
+#ifndef USE_YUVj
for (i = 0; i < 256; ++i) {
VP8kVToR[i] = (89858 * (i - 128) + YUV_HALF) >> YUV_FIX;
VP8kUToG[i] = -22014 * (i - 128) + YUV_HALF;
@@ -44,9 +43,238 @@ void VP8YUVInit(void) {
VP8kClip[i - YUV_RANGE_MIN] = clip(k, 255);
VP8kClip4Bits[i - YUV_RANGE_MIN] = clip((k + 8) >> 4, 15);
}
+#else
+ for (i = 0; i < 256; ++i) {
+ VP8kVToR[i] = (91881 * (i - 128) + YUV_HALF) >> YUV_FIX;
+ VP8kUToG[i] = -22554 * (i - 128) + YUV_HALF;
+ VP8kVToG[i] = -46802 * (i - 128);
+ VP8kUToB[i] = (116130 * (i - 128) + YUV_HALF) >> YUV_FIX;
+ }
+ for (i = YUV_RANGE_MIN; i < YUV_RANGE_MAX; ++i) {
+ const int k = i;
+ VP8kClip[i - YUV_RANGE_MIN] = clip(k, 255);
+ VP8kClip4Bits[i - YUV_RANGE_MIN] = clip((k + 8) >> 4, 15);
+ }
+#endif
+
done = 1;
}
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
+#else
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8YUVInit(void) {}
+
+#endif // WEBP_YUV_USE_TABLE
+
+//-----------------------------------------------------------------------------
+// Plain-C version
+
+#define ROW_FUNC(FUNC_NAME, FUNC, XSTEP) \
+static void FUNC_NAME(const uint8_t* y, \
+ const uint8_t* u, const uint8_t* v, \
+ uint8_t* dst, int len) { \
+ const uint8_t* const end = dst + (len & ~1) * XSTEP; \
+ while (dst != end) { \
+ FUNC(y[0], u[0], v[0], dst); \
+ FUNC(y[1], u[0], v[0], dst + XSTEP); \
+ y += 2; \
+ ++u; \
+ ++v; \
+ dst += 2 * XSTEP; \
+ } \
+ if (len & 1) { \
+ FUNC(y[0], u[0], v[0], dst); \
+ } \
+} \
+
+// All variants implemented.
+ROW_FUNC(YuvToRgbRow, VP8YuvToRgb, 3)
+ROW_FUNC(YuvToBgrRow, VP8YuvToBgr, 3)
+ROW_FUNC(YuvToRgbaRow, VP8YuvToRgba, 4)
+ROW_FUNC(YuvToBgraRow, VP8YuvToBgra, 4)
+ROW_FUNC(YuvToArgbRow, VP8YuvToArgb, 4)
+ROW_FUNC(YuvToRgba4444Row, VP8YuvToRgba4444, 2)
+ROW_FUNC(YuvToRgb565Row, VP8YuvToRgb565, 2)
+
+#undef ROW_FUNC
+
+// Main call for processing a plane with a WebPSamplerRowFunc function:
+void WebPSamplerProcessPlane(const uint8_t* y, int y_stride,
+ const uint8_t* u, const uint8_t* v, int uv_stride,
+ uint8_t* dst, int dst_stride,
+ int width, int height, WebPSamplerRowFunc func) {
+ int j;
+ for (j = 0; j < height; ++j) {
+ func(y, u, v, dst, width);
+ y += y_stride;
+ if (j & 1) {
+ u += uv_stride;
+ v += uv_stride;
+ }
+ dst += dst_stride;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Main call
+
+WebPSamplerRowFunc WebPSamplers[MODE_LAST];
+
+extern void WebPInitSamplersSSE2(void);
+extern void WebPInitSamplersMIPS32(void);
+extern void WebPInitSamplersMIPSdspR2(void);
+
+static volatile VP8CPUInfo yuv_last_cpuinfo_used =
+ (VP8CPUInfo)&yuv_last_cpuinfo_used;
+
+WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplers(void) {
+ if (yuv_last_cpuinfo_used == VP8GetCPUInfo) return;
+
+ WebPSamplers[MODE_RGB] = YuvToRgbRow;
+ WebPSamplers[MODE_RGBA] = YuvToRgbaRow;
+ WebPSamplers[MODE_BGR] = YuvToBgrRow;
+ WebPSamplers[MODE_BGRA] = YuvToBgraRow;
+ WebPSamplers[MODE_ARGB] = YuvToArgbRow;
+ WebPSamplers[MODE_RGBA_4444] = YuvToRgba4444Row;
+ WebPSamplers[MODE_RGB_565] = YuvToRgb565Row;
+ WebPSamplers[MODE_rgbA] = YuvToRgbaRow;
+ WebPSamplers[MODE_bgrA] = YuvToBgraRow;
+ WebPSamplers[MODE_Argb] = YuvToArgbRow;
+ WebPSamplers[MODE_rgbA_4444] = YuvToRgba4444Row;
+
+ // If defined, use CPUInfo() to overwrite some pointers with faster versions.
+ if (VP8GetCPUInfo != NULL) {
+#if defined(WEBP_USE_SSE2)
+ if (VP8GetCPUInfo(kSSE2)) {
+ WebPInitSamplersSSE2();
+ }
+#endif // WEBP_USE_SSE2
+#if defined(WEBP_USE_MIPS32)
+ if (VP8GetCPUInfo(kMIPS32)) {
+ WebPInitSamplersMIPS32();
+ }
+#endif // WEBP_USE_MIPS32
+#if defined(WEBP_USE_MIPS_DSP_R2)
+ if (VP8GetCPUInfo(kMIPSdspR2)) {
+ WebPInitSamplersMIPSdspR2();
+ }
+#endif // WEBP_USE_MIPS_DSP_R2
+ }
+ yuv_last_cpuinfo_used = VP8GetCPUInfo;
+}
+
+//-----------------------------------------------------------------------------
+// ARGB -> YUV converters
+
+static void ConvertARGBToY(const uint32_t* argb, uint8_t* y, int width) {
+ int i;
+ for (i = 0; i < width; ++i) {
+ const uint32_t p = argb[i];
+ y[i] = VP8RGBToY((p >> 16) & 0xff, (p >> 8) & 0xff, (p >> 0) & 0xff,
+ YUV_HALF);
+ }
+}
+
+void WebPConvertARGBToUV_C(const uint32_t* argb, uint8_t* u, uint8_t* v,
+ int src_width, int do_store) {
+ // No rounding. Last pixel is dealt with separately.
+ const int uv_width = src_width >> 1;
+ int i;
+ for (i = 0; i < uv_width; ++i) {
+ const uint32_t v0 = argb[2 * i + 0];
+ const uint32_t v1 = argb[2 * i + 1];
+ // VP8RGBToU/V expects four accumulated pixels. Hence we need to
+ // scale r/g/b value by a factor 2. We just shift v0/v1 one bit less.
+ const int r = ((v0 >> 15) & 0x1fe) + ((v1 >> 15) & 0x1fe);
+ const int g = ((v0 >> 7) & 0x1fe) + ((v1 >> 7) & 0x1fe);
+ const int b = ((v0 << 1) & 0x1fe) + ((v1 << 1) & 0x1fe);
+ const int tmp_u = VP8RGBToU(r, g, b, YUV_HALF << 2);
+ const int tmp_v = VP8RGBToV(r, g, b, YUV_HALF << 2);
+ if (do_store) {
+ u[i] = tmp_u;
+ v[i] = tmp_v;
+ } else {
+ // Approximated average-of-four. But it's an acceptable diff.
+ u[i] = (u[i] + tmp_u + 1) >> 1;
+ v[i] = (v[i] + tmp_v + 1) >> 1;
+ }
+ }
+ if (src_width & 1) { // last pixel
+ const uint32_t v0 = argb[2 * i + 0];
+ const int r = (v0 >> 14) & 0x3fc;
+ const int g = (v0 >> 6) & 0x3fc;
+ const int b = (v0 << 2) & 0x3fc;
+ const int tmp_u = VP8RGBToU(r, g, b, YUV_HALF << 2);
+ const int tmp_v = VP8RGBToV(r, g, b, YUV_HALF << 2);
+ if (do_store) {
+ u[i] = tmp_u;
+ v[i] = tmp_v;
+ } else {
+ u[i] = (u[i] + tmp_u + 1) >> 1;
+ v[i] = (v[i] + tmp_v + 1) >> 1;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+static void ConvertRGB24ToY(const uint8_t* rgb, uint8_t* y, int width) {
+ int i;
+ for (i = 0; i < width; ++i, rgb += 3) {
+ y[i] = VP8RGBToY(rgb[0], rgb[1], rgb[2], YUV_HALF);
+ }
+}
+
+static void ConvertBGR24ToY(const uint8_t* bgr, uint8_t* y, int width) {
+ int i;
+ for (i = 0; i < width; ++i, bgr += 3) {
+ y[i] = VP8RGBToY(bgr[2], bgr[1], bgr[0], YUV_HALF);
+ }
+}
+
+void WebPConvertRGBA32ToUV_C(const uint16_t* rgb,
+ uint8_t* u, uint8_t* v, int width) {
+ int i;
+ for (i = 0; i < width; i += 1, rgb += 4) {
+ const int r = rgb[0], g = rgb[1], b = rgb[2];
+ u[i] = VP8RGBToU(r, g, b, YUV_HALF << 2);
+ v[i] = VP8RGBToV(r, g, b, YUV_HALF << 2);
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+void (*WebPConvertRGB24ToY)(const uint8_t* rgb, uint8_t* y, int width);
+void (*WebPConvertBGR24ToY)(const uint8_t* bgr, uint8_t* y, int width);
+void (*WebPConvertRGBA32ToUV)(const uint16_t* rgb,
+ uint8_t* u, uint8_t* v, int width);
+
+void (*WebPConvertARGBToY)(const uint32_t* argb, uint8_t* y, int width);
+void (*WebPConvertARGBToUV)(const uint32_t* argb, uint8_t* u, uint8_t* v,
+ int src_width, int do_store);
+
+static volatile VP8CPUInfo rgba_to_yuv_last_cpuinfo_used =
+ (VP8CPUInfo)&rgba_to_yuv_last_cpuinfo_used;
+
+extern void WebPInitConvertARGBToYUVSSE2(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUV(void) {
+ if (rgba_to_yuv_last_cpuinfo_used == VP8GetCPUInfo) return;
+
+ WebPConvertARGBToY = ConvertARGBToY;
+ WebPConvertARGBToUV = WebPConvertARGBToUV_C;
+
+ WebPConvertRGB24ToY = ConvertRGB24ToY;
+ WebPConvertBGR24ToY = ConvertBGR24ToY;
+
+ WebPConvertRGBA32ToUV = WebPConvertRGBA32ToUV_C;
+
+ if (VP8GetCPUInfo != NULL) {
+#if defined(WEBP_USE_SSE2)
+ if (VP8GetCPUInfo(kSSE2)) {
+ WebPInitConvertARGBToYUVSSE2();
+ }
+#endif // WEBP_USE_SSE2
+ }
+ rgba_to_yuv_last_cpuinfo_used = VP8GetCPUInfo;
+}
diff --git a/drivers/webp/dsp/yuv.h b/drivers/webp/dsp/yuv.h
index a569109c54..af435a5b3e 100644
--- a/drivers/webp/dsp/yuv.h
+++ b/drivers/webp/dsp/yuv.h
@@ -1,36 +1,165 @@
// Copyright 2010 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// inline YUV<->RGB conversion function
//
+// The exact naming is Y'CbCr, following the ITU-R BT.601 standard.
+// More information at: http://en.wikipedia.org/wiki/YCbCr
+// Y = 0.2569 * R + 0.5044 * G + 0.0979 * B + 16
+// U = -0.1483 * R - 0.2911 * G + 0.4394 * B + 128
+// V = 0.4394 * R - 0.3679 * G - 0.0715 * B + 128
+// We use 16bit fixed point operations for RGB->YUV conversion (YUV_FIX).
+//
+// For the Y'CbCr to RGB conversion, the BT.601 specification reads:
+// R = 1.164 * (Y-16) + 1.596 * (V-128)
+// G = 1.164 * (Y-16) - 0.813 * (V-128) - 0.391 * (U-128)
+// B = 1.164 * (Y-16) + 2.018 * (U-128)
+// where Y is in the [16,235] range, and U/V in the [16,240] range.
+// In the table-lookup version (WEBP_YUV_USE_TABLE), the common factor
+// "1.164 * (Y-16)" can be handled as an offset in the VP8kClip[] table.
+// So in this case the formulae should read:
+// R = 1.164 * [Y + 1.371 * (V-128) ] - 18.624
+// G = 1.164 * [Y - 0.698 * (V-128) - 0.336 * (U-128)] - 18.624
+// B = 1.164 * [Y + 1.733 * (U-128)] - 18.624
+// once factorized.
+// For YUV->RGB conversion, only 14bit fixed precision is used (YUV_FIX2).
+// That's the maximum possible for a convenient ARM implementation.
+//
// Author: Skal (pascal.massimino@gmail.com)
#ifndef WEBP_DSP_YUV_H_
#define WEBP_DSP_YUV_H_
+#include "./dsp.h"
#include "../dec/decode_vp8.h"
+// Define the following to use the LUT-based code:
+// #define WEBP_YUV_USE_TABLE
+
+#if defined(WEBP_EXPERIMENTAL_FEATURES)
+// Do NOT activate this feature for real compression. This is only experimental!
+// This flag is for comparison purpose against JPEG's "YUVj" natural colorspace.
+// This colorspace is close to Rec.601's Y'CbCr model with the notable
+// difference of allowing larger range for luma/chroma.
+// See http://en.wikipedia.org/wiki/YCbCr#JPEG_conversion paragraph, and its
+// difference with http://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion
+// #define USE_YUVj
+#endif
+
//------------------------------------------------------------------------------
// YUV -> RGB conversion
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
extern "C" {
#endif
-enum { YUV_FIX = 16, // fixed-point precision
- YUV_RANGE_MIN = -227, // min value of r/g/b output
- YUV_RANGE_MAX = 256 + 226 // max value of r/g/b output
+enum {
+ YUV_FIX = 16, // fixed-point precision for RGB->YUV
+ YUV_HALF = 1 << (YUV_FIX - 1),
+ YUV_MASK = (256 << YUV_FIX) - 1,
+ YUV_RANGE_MIN = -227, // min value of r/g/b output
+ YUV_RANGE_MAX = 256 + 226, // max value of r/g/b output
+
+ YUV_FIX2 = 14, // fixed-point precision for YUV->RGB
+ YUV_HALF2 = 1 << (YUV_FIX2 - 1),
+ YUV_MASK2 = (256 << YUV_FIX2) - 1
};
+
+// These constants are 14b fixed-point version of ITU-R BT.601 constants.
+#define kYScale 19077 // 1.164 = 255 / 219
+#define kVToR 26149 // 1.596 = 255 / 112 * 0.701
+#define kUToG 6419 // 0.391 = 255 / 112 * 0.886 * 0.114 / 0.587
+#define kVToG 13320 // 0.813 = 255 / 112 * 0.701 * 0.299 / 0.587
+#define kUToB 33050 // 2.018 = 255 / 112 * 0.886
+#define kRCst (-kYScale * 16 - kVToR * 128 + YUV_HALF2)
+#define kGCst (-kYScale * 16 + kUToG * 128 + kVToG * 128 + YUV_HALF2)
+#define kBCst (-kYScale * 16 - kUToB * 128 + YUV_HALF2)
+
+//------------------------------------------------------------------------------
+
+#if !defined(WEBP_YUV_USE_TABLE)
+
+// slower on x86 by ~7-8%, but bit-exact with the SSE2 version
+
+static WEBP_INLINE int VP8Clip8(int v) {
+ return ((v & ~YUV_MASK2) == 0) ? (v >> YUV_FIX2) : (v < 0) ? 0 : 255;
+}
+
+static WEBP_INLINE int VP8YUVToR(int y, int v) {
+ return VP8Clip8(kYScale * y + kVToR * v + kRCst);
+}
+
+static WEBP_INLINE int VP8YUVToG(int y, int u, int v) {
+ return VP8Clip8(kYScale * y - kUToG * u - kVToG * v + kGCst);
+}
+
+static WEBP_INLINE int VP8YUVToB(int y, int u) {
+ return VP8Clip8(kYScale * y + kUToB * u + kBCst);
+}
+
+static WEBP_INLINE void VP8YuvToRgb(int y, int u, int v,
+ uint8_t* const rgb) {
+ rgb[0] = VP8YUVToR(y, v);
+ rgb[1] = VP8YUVToG(y, u, v);
+ rgb[2] = VP8YUVToB(y, u);
+}
+
+static WEBP_INLINE void VP8YuvToBgr(int y, int u, int v,
+ uint8_t* const bgr) {
+ bgr[0] = VP8YUVToB(y, u);
+ bgr[1] = VP8YUVToG(y, u, v);
+ bgr[2] = VP8YUVToR(y, v);
+}
+
+static WEBP_INLINE void VP8YuvToRgb565(int y, int u, int v,
+ uint8_t* const rgb) {
+ const int r = VP8YUVToR(y, v); // 5 usable bits
+ const int g = VP8YUVToG(y, u, v); // 6 usable bits
+ const int b = VP8YUVToB(y, u); // 5 usable bits
+ const int rg = (r & 0xf8) | (g >> 5);
+ const int gb = ((g << 3) & 0xe0) | (b >> 3);
+#ifdef WEBP_SWAP_16BIT_CSP
+ rgb[0] = gb;
+ rgb[1] = rg;
+#else
+ rgb[0] = rg;
+ rgb[1] = gb;
+#endif
+}
+
+static WEBP_INLINE void VP8YuvToRgba4444(int y, int u, int v,
+ uint8_t* const argb) {
+ const int r = VP8YUVToR(y, v); // 4 usable bits
+ const int g = VP8YUVToG(y, u, v); // 4 usable bits
+ const int b = VP8YUVToB(y, u); // 4 usable bits
+ const int rg = (r & 0xf0) | (g >> 4);
+ const int ba = (b & 0xf0) | 0x0f; // overwrite the lower 4 bits
+#ifdef WEBP_SWAP_16BIT_CSP
+ argb[0] = ba;
+ argb[1] = rg;
+#else
+ argb[0] = rg;
+ argb[1] = ba;
+#endif
+}
+
+#else
+
+// Table-based version, not totally equivalent to the SSE2 version.
+// Rounding diff is only +/-1 though.
+
extern int16_t VP8kVToR[256], VP8kUToB[256];
extern int32_t VP8kVToG[256], VP8kUToG[256];
extern uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN];
extern uint8_t VP8kClip4Bits[YUV_RANGE_MAX - YUV_RANGE_MIN];
-static WEBP_INLINE void VP8YuvToRgb(uint8_t y, uint8_t u, uint8_t v,
+static WEBP_INLINE void VP8YuvToRgb(int y, int u, int v,
uint8_t* const rgb) {
const int r_off = VP8kVToR[v];
const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
@@ -40,42 +169,60 @@ static WEBP_INLINE void VP8YuvToRgb(uint8_t y, uint8_t u, uint8_t v,
rgb[2] = VP8kClip[y + b_off - YUV_RANGE_MIN];
}
-static WEBP_INLINE void VP8YuvToRgb565(uint8_t y, uint8_t u, uint8_t v,
- uint8_t* const rgb) {
+static WEBP_INLINE void VP8YuvToBgr(int y, int u, int v,
+ uint8_t* const bgr) {
const int r_off = VP8kVToR[v];
const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
const int b_off = VP8kUToB[u];
- rgb[0] = ((VP8kClip[y + r_off - YUV_RANGE_MIN] & 0xf8) |
- (VP8kClip[y + g_off - YUV_RANGE_MIN] >> 5));
- rgb[1] = (((VP8kClip[y + g_off - YUV_RANGE_MIN] << 3) & 0xe0) |
- (VP8kClip[y + b_off - YUV_RANGE_MIN] >> 3));
-}
-
-static WEBP_INLINE void VP8YuvToArgb(uint8_t y, uint8_t u, uint8_t v,
- uint8_t* const argb) {
- argb[0] = 0xff;
- VP8YuvToRgb(y, u, v, argb + 1);
+ bgr[0] = VP8kClip[y + b_off - YUV_RANGE_MIN];
+ bgr[1] = VP8kClip[y + g_off - YUV_RANGE_MIN];
+ bgr[2] = VP8kClip[y + r_off - YUV_RANGE_MIN];
}
-static WEBP_INLINE void VP8YuvToRgba4444(uint8_t y, uint8_t u, uint8_t v,
- uint8_t* const argb) {
+static WEBP_INLINE void VP8YuvToRgb565(int y, int u, int v,
+ uint8_t* const rgb) {
const int r_off = VP8kVToR[v];
const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
const int b_off = VP8kUToB[u];
- // Don't update alpha (last 4 bits of argb[1])
- argb[0] = ((VP8kClip4Bits[y + r_off - YUV_RANGE_MIN] << 4) |
- VP8kClip4Bits[y + g_off - YUV_RANGE_MIN]);
- argb[1] = 0x0f | (VP8kClip4Bits[y + b_off - YUV_RANGE_MIN] << 4);
+ const int rg = ((VP8kClip[y + r_off - YUV_RANGE_MIN] & 0xf8) |
+ (VP8kClip[y + g_off - YUV_RANGE_MIN] >> 5));
+ const int gb = (((VP8kClip[y + g_off - YUV_RANGE_MIN] << 3) & 0xe0) |
+ (VP8kClip[y + b_off - YUV_RANGE_MIN] >> 3));
+#ifdef WEBP_SWAP_16BIT_CSP
+ rgb[0] = gb;
+ rgb[1] = rg;
+#else
+ rgb[0] = rg;
+ rgb[1] = gb;
+#endif
}
-static WEBP_INLINE void VP8YuvToBgr(uint8_t y, uint8_t u, uint8_t v,
- uint8_t* const bgr) {
+static WEBP_INLINE void VP8YuvToRgba4444(int y, int u, int v,
+ uint8_t* const argb) {
const int r_off = VP8kVToR[v];
const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
const int b_off = VP8kUToB[u];
- bgr[0] = VP8kClip[y + b_off - YUV_RANGE_MIN];
- bgr[1] = VP8kClip[y + g_off - YUV_RANGE_MIN];
- bgr[2] = VP8kClip[y + r_off - YUV_RANGE_MIN];
+ const int rg = ((VP8kClip4Bits[y + r_off - YUV_RANGE_MIN] << 4) |
+ VP8kClip4Bits[y + g_off - YUV_RANGE_MIN]);
+ const int ba = (VP8kClip4Bits[y + b_off - YUV_RANGE_MIN] << 4) | 0x0f;
+#ifdef WEBP_SWAP_16BIT_CSP
+ argb[0] = ba;
+ argb[1] = rg;
+#else
+ argb[0] = rg;
+ argb[1] = ba;
+#endif
+}
+
+#endif // WEBP_YUV_USE_TABLE
+
+//-----------------------------------------------------------------------------
+// Alpha handling variants
+
+static WEBP_INLINE void VP8YuvToArgb(uint8_t y, uint8_t u, uint8_t v,
+ uint8_t* const argb) {
+ argb[0] = 0xff;
+ VP8YuvToRgb(y, u, v, argb + 1);
}
static WEBP_INLINE void VP8YuvToBgra(uint8_t y, uint8_t u, uint8_t v,
@@ -93,35 +240,79 @@ static WEBP_INLINE void VP8YuvToRgba(uint8_t y, uint8_t u, uint8_t v,
// Must be called before everything, to initialize the tables.
void VP8YUVInit(void);
+//-----------------------------------------------------------------------------
+// SSE2 extra functions (mostly for upsampling_sse2.c)
+
+#if defined(WEBP_USE_SSE2)
+
+// When the following is defined, tables are initialized statically, adding ~12k
+// to the binary size. Otherwise, they are initialized at run-time (small cost).
+#define WEBP_YUV_USE_SSE2_TABLES
+
+// Process 32 pixels and store the result (24b or 32b per pixel) in *dst.
+void VP8YuvToRgba32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst);
+void VP8YuvToRgb32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst);
+void VP8YuvToBgra32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst);
+void VP8YuvToBgr32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst);
+
+// Must be called to initialize tables before using the functions.
+void VP8YUVInitSSE2(void);
+
+#endif // WEBP_USE_SSE2
+
//------------------------------------------------------------------------------
// RGB -> YUV conversion
-// The exact naming is Y'CbCr, following the ITU-R BT.601 standard.
-// More information at: http://en.wikipedia.org/wiki/YCbCr
-// Y = 0.2569 * R + 0.5044 * G + 0.0979 * B + 16
-// U = -0.1483 * R - 0.2911 * G + 0.4394 * B + 128
-// V = 0.4394 * R - 0.3679 * G - 0.0715 * B + 128
-// We use 16bit fixed point operations.
-static WEBP_INLINE int VP8ClipUV(int v) {
- v = (v + (257 << (YUV_FIX + 2 - 1))) >> (YUV_FIX + 2);
- return ((v & ~0xff) == 0) ? v : (v < 0) ? 0 : 255;
+// Stub functions that can be called with various rounding values:
+static WEBP_INLINE int VP8ClipUV(int uv, int rounding) {
+ uv = (uv + rounding + (128 << (YUV_FIX + 2))) >> (YUV_FIX + 2);
+ return ((uv & ~0xff) == 0) ? uv : (uv < 0) ? 0 : 255;
}
-static WEBP_INLINE int VP8RGBToY(int r, int g, int b) {
- const int kRound = (1 << (YUV_FIX - 1)) + (16 << YUV_FIX);
+#ifndef USE_YUVj
+
+static WEBP_INLINE int VP8RGBToY(int r, int g, int b, int rounding) {
const int luma = 16839 * r + 33059 * g + 6420 * b;
- return (luma + kRound) >> YUV_FIX; // no need to clip
+ return (luma + rounding + (16 << YUV_FIX)) >> YUV_FIX; // no need to clip
}
-static WEBP_INLINE int VP8RGBToU(int r, int g, int b) {
- return VP8ClipUV(-9719 * r - 19081 * g + 28800 * b);
+static WEBP_INLINE int VP8RGBToU(int r, int g, int b, int rounding) {
+ const int u = -9719 * r - 19081 * g + 28800 * b;
+ return VP8ClipUV(u, rounding);
}
-static WEBP_INLINE int VP8RGBToV(int r, int g, int b) {
- return VP8ClipUV(+28800 * r - 24116 * g - 4684 * b);
+static WEBP_INLINE int VP8RGBToV(int r, int g, int b, int rounding) {
+ const int v = +28800 * r - 24116 * g - 4684 * b;
+ return VP8ClipUV(v, rounding);
+}
+
+#else
+
+// This JPEG-YUV colorspace, only for comparison!
+// These are also 16bit precision coefficients from Rec.601, but with full
+// [0..255] output range.
+static WEBP_INLINE int VP8RGBToY(int r, int g, int b, int rounding) {
+ const int luma = 19595 * r + 38470 * g + 7471 * b;
+ return (luma + rounding) >> YUV_FIX; // no need to clip
}
-#if defined(__cplusplus) || defined(c_plusplus)
+static WEBP_INLINE int VP8RGBToU(int r, int g, int b, int rounding) {
+ const int u = -11058 * r - 21710 * g + 32768 * b;
+ return VP8ClipUV(u, rounding);
+}
+
+static WEBP_INLINE int VP8RGBToV(int r, int g, int b, int rounding) {
+ const int v = 32768 * r - 27439 * g - 5329 * b;
+ return VP8ClipUV(v, rounding);
+}
+
+#endif // USE_YUVj
+
+#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/drivers/webp/dsp/yuv_mips32.c b/drivers/webp/dsp/yuv_mips32.c
new file mode 100644
index 0000000000..018f8ab774
--- /dev/null
+++ b/drivers/webp/dsp/yuv_mips32.c
@@ -0,0 +1,103 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// MIPS version of YUV to RGB upsampling functions.
+//
+// Author(s): Djordje Pesut (djordje.pesut@imgtec.com)
+// Jovan Zelincevic (jovan.zelincevic@imgtec.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_MIPS32)
+
+#include "./yuv.h"
+
+//------------------------------------------------------------------------------
+// simple point-sampling
+
+#define ROW_FUNC(FUNC_NAME, XSTEP, R, G, B, A) \
+static void FUNC_NAME(const uint8_t* y, \
+ const uint8_t* u, const uint8_t* v, \
+ uint8_t* dst, int len) { \
+ int i, r, g, b; \
+ int temp0, temp1, temp2, temp3, temp4; \
+ for (i = 0; i < (len >> 1); i++) { \
+ temp1 = kVToR * v[0]; \
+ temp3 = kVToG * v[0]; \
+ temp2 = kUToG * u[0]; \
+ temp4 = kUToB * u[0]; \
+ temp0 = kYScale * y[0]; \
+ temp1 += kRCst; \
+ temp3 -= kGCst; \
+ temp2 += temp3; \
+ temp4 += kBCst; \
+ r = VP8Clip8(temp0 + temp1); \
+ g = VP8Clip8(temp0 - temp2); \
+ b = VP8Clip8(temp0 + temp4); \
+ temp0 = kYScale * y[1]; \
+ dst[R] = r; \
+ dst[G] = g; \
+ dst[B] = b; \
+ if (A) dst[A] = 0xff; \
+ r = VP8Clip8(temp0 + temp1); \
+ g = VP8Clip8(temp0 - temp2); \
+ b = VP8Clip8(temp0 + temp4); \
+ dst[R + XSTEP] = r; \
+ dst[G + XSTEP] = g; \
+ dst[B + XSTEP] = b; \
+ if (A) dst[A + XSTEP] = 0xff; \
+ y += 2; \
+ ++u; \
+ ++v; \
+ dst += 2 * XSTEP; \
+ } \
+ if (len & 1) { \
+ temp1 = kVToR * v[0]; \
+ temp3 = kVToG * v[0]; \
+ temp2 = kUToG * u[0]; \
+ temp4 = kUToB * u[0]; \
+ temp0 = kYScale * y[0]; \
+ temp1 += kRCst; \
+ temp3 -= kGCst; \
+ temp2 += temp3; \
+ temp4 += kBCst; \
+ r = VP8Clip8(temp0 + temp1); \
+ g = VP8Clip8(temp0 - temp2); \
+ b = VP8Clip8(temp0 + temp4); \
+ dst[R] = r; \
+ dst[G] = g; \
+ dst[B] = b; \
+ if (A) dst[A] = 0xff; \
+ } \
+}
+
+ROW_FUNC(YuvToRgbRow, 3, 0, 1, 2, 0)
+ROW_FUNC(YuvToRgbaRow, 4, 0, 1, 2, 3)
+ROW_FUNC(YuvToBgrRow, 3, 2, 1, 0, 0)
+ROW_FUNC(YuvToBgraRow, 4, 2, 1, 0, 3)
+
+#undef ROW_FUNC
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void WebPInitSamplersMIPS32(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplersMIPS32(void) {
+ WebPSamplers[MODE_RGB] = YuvToRgbRow;
+ WebPSamplers[MODE_RGBA] = YuvToRgbaRow;
+ WebPSamplers[MODE_BGR] = YuvToBgrRow;
+ WebPSamplers[MODE_BGRA] = YuvToBgraRow;
+}
+
+#else // !WEBP_USE_MIPS32
+
+WEBP_DSP_INIT_STUB(WebPInitSamplersMIPS32)
+
+#endif // WEBP_USE_MIPS32
diff --git a/drivers/webp/dsp/yuv_mips_dsp_r2.c b/drivers/webp/dsp/yuv_mips_dsp_r2.c
new file mode 100644
index 0000000000..45a2200352
--- /dev/null
+++ b/drivers/webp/dsp/yuv_mips_dsp_r2.c
@@ -0,0 +1,134 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// MIPS DSPr2 version of YUV to RGB upsampling functions.
+//
+// Author(s): Branimir Vasic (branimir.vasic@imgtec.com)
+// Djordje Pesut (djordje.pesut@imgtec.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_MIPS_DSP_R2)
+
+#include "./yuv.h"
+
+//------------------------------------------------------------------------------
+// simple point-sampling
+
+#define ROW_FUNC_PART_1() \
+ "lbu %[temp3], 0(%[v]) \n\t" \
+ "lbu %[temp4], 0(%[u]) \n\t" \
+ "lbu %[temp0], 0(%[y]) \n\t" \
+ "mul %[temp1], %[t_con_1], %[temp3] \n\t" \
+ "mul %[temp3], %[t_con_2], %[temp3] \n\t" \
+ "mul %[temp2], %[t_con_3], %[temp4] \n\t" \
+ "mul %[temp4], %[t_con_4], %[temp4] \n\t" \
+ "mul %[temp0], %[t_con_5], %[temp0] \n\t" \
+ "addu %[temp1], %[temp1], %[t_con_6] \n\t" \
+ "subu %[temp3], %[temp3], %[t_con_7] \n\t" \
+ "addu %[temp2], %[temp2], %[temp3] \n\t" \
+ "addu %[temp4], %[temp4], %[t_con_8] \n\t" \
+
+#define ROW_FUNC_PART_2(R, G, B, K) \
+ "addu %[temp5], %[temp0], %[temp1] \n\t" \
+ "subu %[temp6], %[temp0], %[temp2] \n\t" \
+ "addu %[temp7], %[temp0], %[temp4] \n\t" \
+".if " #K " \n\t" \
+ "lbu %[temp0], 1(%[y]) \n\t" \
+".endif \n\t" \
+ "shll_s.w %[temp5], %[temp5], 9 \n\t" \
+ "shll_s.w %[temp6], %[temp6], 9 \n\t" \
+".if " #K " \n\t" \
+ "mul %[temp0], %[t_con_5], %[temp0] \n\t" \
+".endif \n\t" \
+ "shll_s.w %[temp7], %[temp7], 9 \n\t" \
+ "precrqu_s.qb.ph %[temp5], %[temp5], $zero \n\t" \
+ "precrqu_s.qb.ph %[temp6], %[temp6], $zero \n\t" \
+ "precrqu_s.qb.ph %[temp7], %[temp7], $zero \n\t" \
+ "srl %[temp5], %[temp5], 24 \n\t" \
+ "srl %[temp6], %[temp6], 24 \n\t" \
+ "srl %[temp7], %[temp7], 24 \n\t" \
+ "sb %[temp5], " #R "(%[dst]) \n\t" \
+ "sb %[temp6], " #G "(%[dst]) \n\t" \
+ "sb %[temp7], " #B "(%[dst]) \n\t" \
+
+#define ASM_CLOBBER_LIST() \
+ : [temp0]"=&r"(temp0), [temp1]"=&r"(temp1), [temp2]"=&r"(temp2), \
+ [temp3]"=&r"(temp3), [temp4]"=&r"(temp4), [temp5]"=&r"(temp5), \
+ [temp6]"=&r"(temp6), [temp7]"=&r"(temp7) \
+ : [t_con_1]"r"(t_con_1), [t_con_2]"r"(t_con_2), [t_con_3]"r"(t_con_3), \
+ [t_con_4]"r"(t_con_4), [t_con_5]"r"(t_con_5), [t_con_6]"r"(t_con_6), \
+ [u]"r"(u), [v]"r"(v), [y]"r"(y), [dst]"r"(dst), \
+ [t_con_7]"r"(t_con_7), [t_con_8]"r"(t_con_8) \
+ : "memory", "hi", "lo" \
+
+#define ROW_FUNC(FUNC_NAME, XSTEP, R, G, B, A) \
+static void FUNC_NAME(const uint8_t* y, \
+ const uint8_t* u, const uint8_t* v, \
+ uint8_t* dst, int len) { \
+ int i; \
+ uint32_t temp0, temp1, temp2, temp3, temp4, temp5, temp6, temp7; \
+ const int t_con_1 = kVToR; \
+ const int t_con_2 = kVToG; \
+ const int t_con_3 = kUToG; \
+ const int t_con_4 = kUToB; \
+ const int t_con_5 = kYScale; \
+ const int t_con_6 = kRCst; \
+ const int t_con_7 = kGCst; \
+ const int t_con_8 = kBCst; \
+ for (i = 0; i < (len >> 1); i++) { \
+ __asm__ volatile ( \
+ ROW_FUNC_PART_1() \
+ ROW_FUNC_PART_2(R, G, B, 1) \
+ ROW_FUNC_PART_2(R + XSTEP, G + XSTEP, B + XSTEP, 0) \
+ ASM_CLOBBER_LIST() \
+ ); \
+ if (A) dst[A] = dst[A + XSTEP] = 0xff; \
+ y += 2; \
+ ++u; \
+ ++v; \
+ dst += 2 * XSTEP; \
+ } \
+ if (len & 1) { \
+ __asm__ volatile ( \
+ ROW_FUNC_PART_1() \
+ ROW_FUNC_PART_2(R, G, B, 0) \
+ ASM_CLOBBER_LIST() \
+ ); \
+ if (A) dst[A] = 0xff; \
+ } \
+}
+
+ROW_FUNC(YuvToRgbRow, 3, 0, 1, 2, 0)
+ROW_FUNC(YuvToRgbaRow, 4, 0, 1, 2, 3)
+ROW_FUNC(YuvToBgrRow, 3, 2, 1, 0, 0)
+ROW_FUNC(YuvToBgraRow, 4, 2, 1, 0, 3)
+
+#undef ROW_FUNC
+#undef ASM_CLOBBER_LIST
+#undef ROW_FUNC_PART_2
+#undef ROW_FUNC_PART_1
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void WebPInitSamplersMIPSdspR2(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplersMIPSdspR2(void) {
+ WebPSamplers[MODE_RGB] = YuvToRgbRow;
+ WebPSamplers[MODE_RGBA] = YuvToRgbaRow;
+ WebPSamplers[MODE_BGR] = YuvToBgrRow;
+ WebPSamplers[MODE_BGRA] = YuvToBgraRow;
+}
+
+#else // !WEBP_USE_MIPS_DSP_R2
+
+WEBP_DSP_INIT_STUB(WebPInitSamplersMIPSdspR2)
+
+#endif // WEBP_USE_MIPS_DSP_R2
diff --git a/drivers/webp/dsp/yuv_sse2.c b/drivers/webp/dsp/yuv_sse2.c
new file mode 100644
index 0000000000..283b3af228
--- /dev/null
+++ b/drivers/webp/dsp/yuv_sse2.c
@@ -0,0 +1,606 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// YUV->RGB conversion functions
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./yuv.h"
+
+#if defined(WEBP_USE_SSE2)
+
+#include <emmintrin.h>
+#include <string.h> // for memcpy
+
+typedef union { // handy struct for converting SSE2 registers
+ int32_t i32[4];
+ uint8_t u8[16];
+ __m128i m;
+} VP8kCstSSE2;
+
+#if defined(WEBP_YUV_USE_SSE2_TABLES)
+
+#include "./yuv_tables_sse2.h"
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8YUVInitSSE2(void) {}
+
+#else
+
+static int done_sse2 = 0;
+static VP8kCstSSE2 VP8kUtoRGBA[256], VP8kVtoRGBA[256], VP8kYtoRGBA[256];
+
+WEBP_TSAN_IGNORE_FUNCTION void VP8YUVInitSSE2(void) {
+ if (!done_sse2) {
+ int i;
+ for (i = 0; i < 256; ++i) {
+ VP8kYtoRGBA[i].i32[0] =
+ VP8kYtoRGBA[i].i32[1] =
+ VP8kYtoRGBA[i].i32[2] = (i - 16) * kYScale + YUV_HALF2;
+ VP8kYtoRGBA[i].i32[3] = 0xff << YUV_FIX2;
+
+ VP8kUtoRGBA[i].i32[0] = 0;
+ VP8kUtoRGBA[i].i32[1] = -kUToG * (i - 128);
+ VP8kUtoRGBA[i].i32[2] = kUToB * (i - 128);
+ VP8kUtoRGBA[i].i32[3] = 0;
+
+ VP8kVtoRGBA[i].i32[0] = kVToR * (i - 128);
+ VP8kVtoRGBA[i].i32[1] = -kVToG * (i - 128);
+ VP8kVtoRGBA[i].i32[2] = 0;
+ VP8kVtoRGBA[i].i32[3] = 0;
+ }
+ done_sse2 = 1;
+
+#if 0 // code used to generate 'yuv_tables_sse2.h'
+ printf("static const VP8kCstSSE2 VP8kYtoRGBA[256] = {\n");
+ for (i = 0; i < 256; ++i) {
+ printf(" {{0x%.8x, 0x%.8x, 0x%.8x, 0x%.8x}},\n",
+ VP8kYtoRGBA[i].i32[0], VP8kYtoRGBA[i].i32[1],
+ VP8kYtoRGBA[i].i32[2], VP8kYtoRGBA[i].i32[3]);
+ }
+ printf("};\n\n");
+ printf("static const VP8kCstSSE2 VP8kUtoRGBA[256] = {\n");
+ for (i = 0; i < 256; ++i) {
+ printf(" {{0, 0x%.8x, 0x%.8x, 0}},\n",
+ VP8kUtoRGBA[i].i32[1], VP8kUtoRGBA[i].i32[2]);
+ }
+ printf("};\n\n");
+ printf("static VP8kCstSSE2 VP8kVtoRGBA[256] = {\n");
+ for (i = 0; i < 256; ++i) {
+ printf(" {{0x%.8x, 0x%.8x, 0, 0}},\n",
+ VP8kVtoRGBA[i].i32[0], VP8kVtoRGBA[i].i32[1]);
+ }
+ printf("};\n\n");
+#endif
+ }
+}
+
+#endif // WEBP_YUV_USE_SSE2_TABLES
+
+//-----------------------------------------------------------------------------
+
+static WEBP_INLINE __m128i LoadUVPart(int u, int v) {
+ const __m128i u_part = _mm_loadu_si128(&VP8kUtoRGBA[u].m);
+ const __m128i v_part = _mm_loadu_si128(&VP8kVtoRGBA[v].m);
+ const __m128i uv_part = _mm_add_epi32(u_part, v_part);
+ return uv_part;
+}
+
+static WEBP_INLINE __m128i GetRGBA32bWithUV(int y, const __m128i uv_part) {
+ const __m128i y_part = _mm_loadu_si128(&VP8kYtoRGBA[y].m);
+ const __m128i rgba1 = _mm_add_epi32(y_part, uv_part);
+ const __m128i rgba2 = _mm_srai_epi32(rgba1, YUV_FIX2);
+ return rgba2;
+}
+
+static WEBP_INLINE __m128i GetRGBA32b(int y, int u, int v) {
+ const __m128i uv_part = LoadUVPart(u, v);
+ return GetRGBA32bWithUV(y, uv_part);
+}
+
+static WEBP_INLINE void YuvToRgbSSE2(uint8_t y, uint8_t u, uint8_t v,
+ uint8_t* const rgb) {
+ const __m128i tmp0 = GetRGBA32b(y, u, v);
+ const __m128i tmp1 = _mm_packs_epi32(tmp0, tmp0);
+ const __m128i tmp2 = _mm_packus_epi16(tmp1, tmp1);
+ // Note: we store 8 bytes at a time, not 3 bytes! -> memory stomp
+ _mm_storel_epi64((__m128i*)rgb, tmp2);
+}
+
+static WEBP_INLINE void YuvToBgrSSE2(uint8_t y, uint8_t u, uint8_t v,
+ uint8_t* const bgr) {
+ const __m128i tmp0 = GetRGBA32b(y, u, v);
+ const __m128i tmp1 = _mm_shuffle_epi32(tmp0, _MM_SHUFFLE(3, 0, 1, 2));
+ const __m128i tmp2 = _mm_packs_epi32(tmp1, tmp1);
+ const __m128i tmp3 = _mm_packus_epi16(tmp2, tmp2);
+ // Note: we store 8 bytes at a time, not 3 bytes! -> memory stomp
+ _mm_storel_epi64((__m128i*)bgr, tmp3);
+}
+
+//-----------------------------------------------------------------------------
+// Convert spans of 32 pixels to various RGB formats for the fancy upsampler.
+
+void VP8YuvToRgba32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst) {
+ int n;
+ for (n = 0; n < 32; n += 4) {
+ const __m128i tmp0_1 = GetRGBA32b(y[n + 0], u[n + 0], v[n + 0]);
+ const __m128i tmp0_2 = GetRGBA32b(y[n + 1], u[n + 1], v[n + 1]);
+ const __m128i tmp0_3 = GetRGBA32b(y[n + 2], u[n + 2], v[n + 2]);
+ const __m128i tmp0_4 = GetRGBA32b(y[n + 3], u[n + 3], v[n + 3]);
+ const __m128i tmp1_1 = _mm_packs_epi32(tmp0_1, tmp0_2);
+ const __m128i tmp1_2 = _mm_packs_epi32(tmp0_3, tmp0_4);
+ const __m128i tmp2 = _mm_packus_epi16(tmp1_1, tmp1_2);
+ _mm_storeu_si128((__m128i*)dst, tmp2);
+ dst += 4 * 4;
+ }
+}
+
+void VP8YuvToBgra32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst) {
+ int n;
+ for (n = 0; n < 32; n += 2) {
+ const __m128i tmp0_1 = GetRGBA32b(y[n + 0], u[n + 0], v[n + 0]);
+ const __m128i tmp0_2 = GetRGBA32b(y[n + 1], u[n + 1], v[n + 1]);
+ const __m128i tmp1_1 = _mm_shuffle_epi32(tmp0_1, _MM_SHUFFLE(3, 0, 1, 2));
+ const __m128i tmp1_2 = _mm_shuffle_epi32(tmp0_2, _MM_SHUFFLE(3, 0, 1, 2));
+ const __m128i tmp2_1 = _mm_packs_epi32(tmp1_1, tmp1_2);
+ const __m128i tmp3 = _mm_packus_epi16(tmp2_1, tmp2_1);
+ _mm_storel_epi64((__m128i*)dst, tmp3);
+ dst += 4 * 2;
+ }
+}
+
+void VP8YuvToRgb32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst) {
+ int n;
+ uint8_t tmp0[2 * 3 + 5 + 15];
+ uint8_t* const tmp = (uint8_t*)((uintptr_t)(tmp0 + 15) & ~15); // align
+ for (n = 0; n < 30; ++n) { // we directly stomp the *dst memory
+ YuvToRgbSSE2(y[n], u[n], v[n], dst + n * 3);
+ }
+ // Last two pixels are special: we write in a tmp buffer before sending
+ // to dst.
+ YuvToRgbSSE2(y[n + 0], u[n + 0], v[n + 0], tmp + 0);
+ YuvToRgbSSE2(y[n + 1], u[n + 1], v[n + 1], tmp + 3);
+ memcpy(dst + n * 3, tmp, 2 * 3);
+}
+
+void VP8YuvToBgr32(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst) {
+ int n;
+ uint8_t tmp0[2 * 3 + 5 + 15];
+ uint8_t* const tmp = (uint8_t*)((uintptr_t)(tmp0 + 15) & ~15); // align
+ for (n = 0; n < 30; ++n) {
+ YuvToBgrSSE2(y[n], u[n], v[n], dst + n * 3);
+ }
+ YuvToBgrSSE2(y[n + 0], u[n + 0], v[n + 0], tmp + 0);
+ YuvToBgrSSE2(y[n + 1], u[n + 1], v[n + 1], tmp + 3);
+ memcpy(dst + n * 3, tmp, 2 * 3);
+}
+
+//-----------------------------------------------------------------------------
+// Arbitrary-length row conversion functions
+
+static void YuvToRgbaRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst, int len) {
+ int n;
+ for (n = 0; n + 4 <= len; n += 4) {
+ const __m128i uv_0 = LoadUVPart(u[0], v[0]);
+ const __m128i uv_1 = LoadUVPart(u[1], v[1]);
+ const __m128i tmp0_1 = GetRGBA32bWithUV(y[0], uv_0);
+ const __m128i tmp0_2 = GetRGBA32bWithUV(y[1], uv_0);
+ const __m128i tmp0_3 = GetRGBA32bWithUV(y[2], uv_1);
+ const __m128i tmp0_4 = GetRGBA32bWithUV(y[3], uv_1);
+ const __m128i tmp1_1 = _mm_packs_epi32(tmp0_1, tmp0_2);
+ const __m128i tmp1_2 = _mm_packs_epi32(tmp0_3, tmp0_4);
+ const __m128i tmp2 = _mm_packus_epi16(tmp1_1, tmp1_2);
+ _mm_storeu_si128((__m128i*)dst, tmp2);
+ dst += 4 * 4;
+ y += 4;
+ u += 2;
+ v += 2;
+ }
+ // Finish off
+ while (n < len) {
+ VP8YuvToRgba(y[0], u[0], v[0], dst);
+ dst += 4;
+ ++y;
+ u += (n & 1);
+ v += (n & 1);
+ ++n;
+ }
+}
+
+static void YuvToBgraRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst, int len) {
+ int n;
+ for (n = 0; n + 2 <= len; n += 2) {
+ const __m128i uv_0 = LoadUVPart(u[0], v[0]);
+ const __m128i tmp0_1 = GetRGBA32bWithUV(y[0], uv_0);
+ const __m128i tmp0_2 = GetRGBA32bWithUV(y[1], uv_0);
+ const __m128i tmp1_1 = _mm_shuffle_epi32(tmp0_1, _MM_SHUFFLE(3, 0, 1, 2));
+ const __m128i tmp1_2 = _mm_shuffle_epi32(tmp0_2, _MM_SHUFFLE(3, 0, 1, 2));
+ const __m128i tmp2_1 = _mm_packs_epi32(tmp1_1, tmp1_2);
+ const __m128i tmp3 = _mm_packus_epi16(tmp2_1, tmp2_1);
+ _mm_storel_epi64((__m128i*)dst, tmp3);
+ dst += 4 * 2;
+ y += 2;
+ ++u;
+ ++v;
+ }
+ // Finish off
+ if (len & 1) {
+ VP8YuvToBgra(y[0], u[0], v[0], dst);
+ }
+}
+
+static void YuvToArgbRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst, int len) {
+ int n;
+ for (n = 0; n + 2 <= len; n += 2) {
+ const __m128i uv_0 = LoadUVPart(u[0], v[0]);
+ const __m128i tmp0_1 = GetRGBA32bWithUV(y[0], uv_0);
+ const __m128i tmp0_2 = GetRGBA32bWithUV(y[1], uv_0);
+ const __m128i tmp1_1 = _mm_shuffle_epi32(tmp0_1, _MM_SHUFFLE(2, 1, 0, 3));
+ const __m128i tmp1_2 = _mm_shuffle_epi32(tmp0_2, _MM_SHUFFLE(2, 1, 0, 3));
+ const __m128i tmp2_1 = _mm_packs_epi32(tmp1_1, tmp1_2);
+ const __m128i tmp3 = _mm_packus_epi16(tmp2_1, tmp2_1);
+ _mm_storel_epi64((__m128i*)dst, tmp3);
+ dst += 4 * 2;
+ y += 2;
+ ++u;
+ ++v;
+ }
+ // Finish off
+ if (len & 1) {
+ VP8YuvToArgb(y[0], u[0], v[0], dst);
+ }
+}
+
+static void YuvToRgbRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst, int len) {
+ int n;
+ for (n = 0; n + 2 < len; ++n) { // we directly stomp the *dst memory
+ YuvToRgbSSE2(y[0], u[0], v[0], dst); // stomps 8 bytes
+ dst += 3;
+ ++y;
+ u += (n & 1);
+ v += (n & 1);
+ }
+ VP8YuvToRgb(y[0], u[0], v[0], dst);
+ if (len > 1) {
+ VP8YuvToRgb(y[1], u[n & 1], v[n & 1], dst + 3);
+ }
+}
+
+static void YuvToBgrRow(const uint8_t* y, const uint8_t* u, const uint8_t* v,
+ uint8_t* dst, int len) {
+ int n;
+ for (n = 0; n + 2 < len; ++n) { // we directly stomp the *dst memory
+ YuvToBgrSSE2(y[0], u[0], v[0], dst); // stomps 8 bytes
+ dst += 3;
+ ++y;
+ u += (n & 1);
+ v += (n & 1);
+ }
+ VP8YuvToBgr(y[0], u[0], v[0], dst + 0);
+ if (len > 1) {
+ VP8YuvToBgr(y[1], u[n & 1], v[n & 1], dst + 3);
+ }
+}
+
+//------------------------------------------------------------------------------
+// Entry point
+
+extern void WebPInitSamplersSSE2(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void WebPInitSamplersSSE2(void) {
+ WebPSamplers[MODE_RGB] = YuvToRgbRow;
+ WebPSamplers[MODE_RGBA] = YuvToRgbaRow;
+ WebPSamplers[MODE_BGR] = YuvToBgrRow;
+ WebPSamplers[MODE_BGRA] = YuvToBgraRow;
+ WebPSamplers[MODE_ARGB] = YuvToArgbRow;
+}
+
+//------------------------------------------------------------------------------
+// RGB24/32 -> YUV converters
+
+// Load eight 16b-words from *src.
+#define LOAD_16(src) _mm_loadu_si128((const __m128i*)(src))
+// Store either 16b-words into *dst
+#define STORE_16(V, dst) _mm_storeu_si128((__m128i*)(dst), (V))
+
+// Convert 8 packed RGB or BGR samples to r[], g[], b[]
+static WEBP_INLINE void RGB24PackedToPlanar(const uint8_t* const rgb,
+ __m128i* const r,
+ __m128i* const g,
+ __m128i* const b,
+ int input_is_bgr) {
+ const __m128i zero = _mm_setzero_si128();
+ // in0: r0 g0 b0 r1 | g1 b1 r2 g2 | b2 r3 g3 b3 | r4 g4 b4 r5
+ // in1: b2 r3 g3 b3 | r4 g4 b4 r5 | g5 b5 r6 g6 | b6 r7 g7 b7
+ const __m128i in0 = LOAD_16(rgb + 0);
+ const __m128i in1 = LOAD_16(rgb + 8);
+ // A0: | r2 g2 b2 r3 | g3 b3 r4 g4 | b4 r5 ...
+ // A1: ... b2 r3 | g3 b3 r4 g4 | b4 r5 g5 b5 |
+ const __m128i A0 = _mm_srli_si128(in0, 6);
+ const __m128i A1 = _mm_slli_si128(in1, 6);
+ // B0: r0 r2 g0 g2 | b0 b2 r1 r3 | g1 g3 b1 b3 | r2 r4 b2 b4
+ // B1: g3 g5 b3 b5 | r4 r6 g4 g6 | b4 b6 r5 r7 | g5 g7 b5 b7
+ const __m128i B0 = _mm_unpacklo_epi8(in0, A0);
+ const __m128i B1 = _mm_unpackhi_epi8(A1, in1);
+ // C0: r1 r3 g1 g3 | b1 b3 r2 r4 | b2 b4 ...
+ // C1: ... g3 g5 | b3 b5 r4 r6 | g4 g6 b4 b6
+ const __m128i C0 = _mm_srli_si128(B0, 6);
+ const __m128i C1 = _mm_slli_si128(B1, 6);
+ // D0: r0 r1 r2 r3 | g0 g1 g2 g3 | b0 b1 b2 b3 | r1 r2 r3 r4
+ // D1: b3 b4 b5 b6 | r4 r5 r6 r7 | g4 g5 g6 g7 | b4 b5 b6 b7 |
+ const __m128i D0 = _mm_unpacklo_epi8(B0, C0);
+ const __m128i D1 = _mm_unpackhi_epi8(C1, B1);
+ // r4 r5 r6 r7 | g4 g5 g6 g7 | b4 b5 b6 b7 | 0
+ const __m128i D2 = _mm_srli_si128(D1, 4);
+ // r0 r1 r2 r3 | r4 r5 r6 r7 | g0 g1 g2 g3 | g4 g5 g6 g7
+ const __m128i E0 = _mm_unpacklo_epi32(D0, D2);
+ // b0 b1 b2 b3 | b4 b5 b6 b7 | r1 r2 r3 r4 | 0
+ const __m128i E1 = _mm_unpackhi_epi32(D0, D2);
+ // g0 g1 g2 g3 | g4 g5 g6 g7 | 0
+ const __m128i E2 = _mm_srli_si128(E0, 8);
+ const __m128i F0 = _mm_unpacklo_epi8(E0, zero); // -> R
+ const __m128i F1 = _mm_unpacklo_epi8(E1, zero); // -> B
+ const __m128i F2 = _mm_unpacklo_epi8(E2, zero); // -> G
+ *g = F2;
+ if (input_is_bgr) {
+ *r = F1;
+ *b = F0;
+ } else {
+ *r = F0;
+ *b = F1;
+ }
+}
+
+// Convert 8 packed ARGB to r[], g[], b[]
+static WEBP_INLINE void RGB32PackedToPlanar(const uint32_t* const argb,
+ __m128i* const r,
+ __m128i* const g,
+ __m128i* const b) {
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i in0 = LOAD_16(argb + 0); // argb3 | argb2 | argb1 | argb0
+ const __m128i in1 = LOAD_16(argb + 4); // argb7 | argb6 | argb5 | argb4
+ // column-wise transpose
+ const __m128i A0 = _mm_unpacklo_epi8(in0, in1);
+ const __m128i A1 = _mm_unpackhi_epi8(in0, in1);
+ const __m128i B0 = _mm_unpacklo_epi8(A0, A1);
+ const __m128i B1 = _mm_unpackhi_epi8(A0, A1);
+ // C0 = g7 g6 ... g1 g0 | b7 b6 ... b1 b0
+ // C1 = a7 a6 ... a1 a0 | r7 r6 ... r1 r0
+ const __m128i C0 = _mm_unpacklo_epi8(B0, B1);
+ const __m128i C1 = _mm_unpackhi_epi8(B0, B1);
+ // store 16b
+ *r = _mm_unpacklo_epi8(C1, zero);
+ *g = _mm_unpackhi_epi8(C0, zero);
+ *b = _mm_unpacklo_epi8(C0, zero);
+}
+
+// This macro computes (RG * MULT_RG + GB * MULT_GB + ROUNDER) >> DESCALE_FIX
+// It's a macro and not a function because we need to use immediate values with
+// srai_epi32, e.g.
+#define TRANSFORM(RG_LO, RG_HI, GB_LO, GB_HI, MULT_RG, MULT_GB, \
+ ROUNDER, DESCALE_FIX, OUT) do { \
+ const __m128i V0_lo = _mm_madd_epi16(RG_LO, MULT_RG); \
+ const __m128i V0_hi = _mm_madd_epi16(RG_HI, MULT_RG); \
+ const __m128i V1_lo = _mm_madd_epi16(GB_LO, MULT_GB); \
+ const __m128i V1_hi = _mm_madd_epi16(GB_HI, MULT_GB); \
+ const __m128i V2_lo = _mm_add_epi32(V0_lo, V1_lo); \
+ const __m128i V2_hi = _mm_add_epi32(V0_hi, V1_hi); \
+ const __m128i V3_lo = _mm_add_epi32(V2_lo, ROUNDER); \
+ const __m128i V3_hi = _mm_add_epi32(V2_hi, ROUNDER); \
+ const __m128i V5_lo = _mm_srai_epi32(V3_lo, DESCALE_FIX); \
+ const __m128i V5_hi = _mm_srai_epi32(V3_hi, DESCALE_FIX); \
+ (OUT) = _mm_packs_epi32(V5_lo, V5_hi); \
+} while (0)
+
+#define MK_CST_16(A, B) _mm_set_epi16((B), (A), (B), (A), (B), (A), (B), (A))
+static WEBP_INLINE void ConvertRGBToY(const __m128i* const R,
+ const __m128i* const G,
+ const __m128i* const B,
+ __m128i* const Y) {
+ const __m128i kRG_y = MK_CST_16(16839, 33059 - 16384);
+ const __m128i kGB_y = MK_CST_16(16384, 6420);
+ const __m128i kHALF_Y = _mm_set1_epi32((16 << YUV_FIX) + YUV_HALF);
+
+ const __m128i RG_lo = _mm_unpacklo_epi16(*R, *G);
+ const __m128i RG_hi = _mm_unpackhi_epi16(*R, *G);
+ const __m128i GB_lo = _mm_unpacklo_epi16(*G, *B);
+ const __m128i GB_hi = _mm_unpackhi_epi16(*G, *B);
+ TRANSFORM(RG_lo, RG_hi, GB_lo, GB_hi, kRG_y, kGB_y, kHALF_Y, YUV_FIX, *Y);
+}
+
+static WEBP_INLINE void ConvertRGBToUV(const __m128i* const R,
+ const __m128i* const G,
+ const __m128i* const B,
+ __m128i* const U, __m128i* const V) {
+ const __m128i kRG_u = MK_CST_16(-9719, -19081);
+ const __m128i kGB_u = MK_CST_16(0, 28800);
+ const __m128i kRG_v = MK_CST_16(28800, 0);
+ const __m128i kGB_v = MK_CST_16(-24116, -4684);
+ const __m128i kHALF_UV = _mm_set1_epi32(((128 << YUV_FIX) + YUV_HALF) << 2);
+
+ const __m128i RG_lo = _mm_unpacklo_epi16(*R, *G);
+ const __m128i RG_hi = _mm_unpackhi_epi16(*R, *G);
+ const __m128i GB_lo = _mm_unpacklo_epi16(*G, *B);
+ const __m128i GB_hi = _mm_unpackhi_epi16(*G, *B);
+ TRANSFORM(RG_lo, RG_hi, GB_lo, GB_hi, kRG_u, kGB_u,
+ kHALF_UV, YUV_FIX + 2, *U);
+ TRANSFORM(RG_lo, RG_hi, GB_lo, GB_hi, kRG_v, kGB_v,
+ kHALF_UV, YUV_FIX + 2, *V);
+}
+
+#undef MK_CST_16
+#undef TRANSFORM
+
+static void ConvertRGB24ToY(const uint8_t* rgb, uint8_t* y, int width) {
+ const int max_width = width & ~15;
+ int i;
+ for (i = 0; i < max_width; i += 16, rgb += 3 * 16) {
+ __m128i r, g, b, Y0, Y1;
+ RGB24PackedToPlanar(rgb + 0 * 8, &r, &g, &b, 0);
+ ConvertRGBToY(&r, &g, &b, &Y0);
+ RGB24PackedToPlanar(rgb + 3 * 8, &r, &g, &b, 0);
+ ConvertRGBToY(&r, &g, &b, &Y1);
+ STORE_16(_mm_packus_epi16(Y0, Y1), y + i);
+ }
+ for (; i < width; ++i, rgb += 3) { // left-over
+ y[i] = VP8RGBToY(rgb[0], rgb[1], rgb[2], YUV_HALF);
+ }
+}
+
+static void ConvertBGR24ToY(const uint8_t* bgr, uint8_t* y, int width) {
+ int i;
+ const int max_width = width & ~15;
+ for (i = 0; i < max_width; i += 16, bgr += 3 * 16) {
+ __m128i r, g, b, Y0, Y1;
+ RGB24PackedToPlanar(bgr + 0 * 8, &r, &g, &b, 1);
+ ConvertRGBToY(&r, &g, &b, &Y0);
+ RGB24PackedToPlanar(bgr + 3 * 8, &r, &g, &b, 1);
+ ConvertRGBToY(&r, &g, &b, &Y1);
+ STORE_16(_mm_packus_epi16(Y0, Y1), y + i);
+ }
+ for (; i < width; ++i, bgr += 3) { // left-over
+ y[i] = VP8RGBToY(bgr[2], bgr[1], bgr[0], YUV_HALF);
+ }
+}
+
+static void ConvertARGBToY(const uint32_t* argb, uint8_t* y, int width) {
+ const int max_width = width & ~15;
+ int i;
+ for (i = 0; i < max_width; i += 16) {
+ __m128i r, g, b, Y0, Y1;
+ RGB32PackedToPlanar(&argb[i + 0], &r, &g, &b);
+ ConvertRGBToY(&r, &g, &b, &Y0);
+ RGB32PackedToPlanar(&argb[i + 8], &r, &g, &b);
+ ConvertRGBToY(&r, &g, &b, &Y1);
+ STORE_16(_mm_packus_epi16(Y0, Y1), y + i);
+ }
+ for (; i < width; ++i) { // left-over
+ const uint32_t p = argb[i];
+ y[i] = VP8RGBToY((p >> 16) & 0xff, (p >> 8) & 0xff, (p >> 0) & 0xff,
+ YUV_HALF);
+ }
+}
+
+// Horizontal add (doubled) of two 16b values, result is 16b.
+// in: A | B | C | D | ... -> out: 2*(A+B) | 2*(C+D) | ...
+static void HorizontalAddPack(const __m128i* const A, const __m128i* const B,
+ __m128i* const out) {
+ const __m128i k2 = _mm_set1_epi16(2);
+ const __m128i C = _mm_madd_epi16(*A, k2);
+ const __m128i D = _mm_madd_epi16(*B, k2);
+ *out = _mm_packs_epi32(C, D);
+}
+
+static void ConvertARGBToUV(const uint32_t* argb, uint8_t* u, uint8_t* v,
+ int src_width, int do_store) {
+ const int max_width = src_width & ~31;
+ int i;
+ for (i = 0; i < max_width; i += 32, u += 16, v += 16) {
+ __m128i r0, g0, b0, r1, g1, b1, U0, V0, U1, V1;
+ RGB32PackedToPlanar(&argb[i + 0], &r0, &g0, &b0);
+ RGB32PackedToPlanar(&argb[i + 8], &r1, &g1, &b1);
+ HorizontalAddPack(&r0, &r1, &r0);
+ HorizontalAddPack(&g0, &g1, &g0);
+ HorizontalAddPack(&b0, &b1, &b0);
+ ConvertRGBToUV(&r0, &g0, &b0, &U0, &V0);
+
+ RGB32PackedToPlanar(&argb[i + 16], &r0, &g0, &b0);
+ RGB32PackedToPlanar(&argb[i + 24], &r1, &g1, &b1);
+ HorizontalAddPack(&r0, &r1, &r0);
+ HorizontalAddPack(&g0, &g1, &g0);
+ HorizontalAddPack(&b0, &b1, &b0);
+ ConvertRGBToUV(&r0, &g0, &b0, &U1, &V1);
+
+ U0 = _mm_packus_epi16(U0, U1);
+ V0 = _mm_packus_epi16(V0, V1);
+ if (!do_store) {
+ const __m128i prev_u = LOAD_16(u);
+ const __m128i prev_v = LOAD_16(v);
+ U0 = _mm_avg_epu8(U0, prev_u);
+ V0 = _mm_avg_epu8(V0, prev_v);
+ }
+ STORE_16(U0, u);
+ STORE_16(V0, v);
+ }
+ if (i < src_width) { // left-over
+ WebPConvertARGBToUV_C(argb + i, u, v, src_width - i, do_store);
+ }
+}
+
+// Convert 16 packed ARGB 16b-values to r[], g[], b[]
+static WEBP_INLINE void RGBA32PackedToPlanar_16b(const uint16_t* const rgbx,
+ __m128i* const r,
+ __m128i* const g,
+ __m128i* const b) {
+ const __m128i in0 = LOAD_16(rgbx + 0); // r0 | g0 | b0 |x| r1 | g1 | b1 |x
+ const __m128i in1 = LOAD_16(rgbx + 8); // r2 | g2 | b2 |x| r3 | g3 | b3 |x
+ const __m128i in2 = LOAD_16(rgbx + 16); // r4 | ...
+ const __m128i in3 = LOAD_16(rgbx + 24); // r6 | ...
+ // column-wise transpose
+ const __m128i A0 = _mm_unpacklo_epi16(in0, in1);
+ const __m128i A1 = _mm_unpackhi_epi16(in0, in1);
+ const __m128i A2 = _mm_unpacklo_epi16(in2, in3);
+ const __m128i A3 = _mm_unpackhi_epi16(in2, in3);
+ const __m128i B0 = _mm_unpacklo_epi16(A0, A1); // r0 r1 r2 r3 | g0 g1 ..
+ const __m128i B1 = _mm_unpackhi_epi16(A0, A1); // b0 b1 b2 b3 | x x x x
+ const __m128i B2 = _mm_unpacklo_epi16(A2, A3); // r4 r5 r6 r7 | g4 g5 ..
+ const __m128i B3 = _mm_unpackhi_epi16(A2, A3); // b4 b5 b6 b7 | x x x x
+ *r = _mm_unpacklo_epi64(B0, B2);
+ *g = _mm_unpackhi_epi64(B0, B2);
+ *b = _mm_unpacklo_epi64(B1, B3);
+}
+
+static void ConvertRGBA32ToUV(const uint16_t* rgb,
+ uint8_t* u, uint8_t* v, int width) {
+ const int max_width = width & ~15;
+ const uint16_t* const last_rgb = rgb + 4 * max_width;
+ while (rgb < last_rgb) {
+ __m128i r, g, b, U0, V0, U1, V1;
+ RGBA32PackedToPlanar_16b(rgb + 0, &r, &g, &b);
+ ConvertRGBToUV(&r, &g, &b, &U0, &V0);
+ RGBA32PackedToPlanar_16b(rgb + 32, &r, &g, &b);
+ ConvertRGBToUV(&r, &g, &b, &U1, &V1);
+ STORE_16(_mm_packus_epi16(U0, U1), u);
+ STORE_16(_mm_packus_epi16(V0, V1), v);
+ u += 16;
+ v += 16;
+ rgb += 2 * 32;
+ }
+ if (max_width < width) { // left-over
+ WebPConvertRGBA32ToUV_C(rgb, u, v, width - max_width);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+extern void WebPInitConvertARGBToYUVSSE2(void);
+
+WEBP_TSAN_IGNORE_FUNCTION void WebPInitConvertARGBToYUVSSE2(void) {
+ WebPConvertARGBToY = ConvertARGBToY;
+ WebPConvertARGBToUV = ConvertARGBToUV;
+
+ WebPConvertRGB24ToY = ConvertRGB24ToY;
+ WebPConvertBGR24ToY = ConvertBGR24ToY;
+
+ WebPConvertRGBA32ToUV = ConvertRGBA32ToUV;
+}
+
+#else // !WEBP_USE_SSE2
+
+WEBP_DSP_INIT_STUB(WebPInitSamplersSSE2)
+WEBP_DSP_INIT_STUB(WebPInitConvertARGBToYUVSSE2)
+
+#endif // WEBP_USE_SSE2
diff --git a/drivers/webp/dsp/yuv_tables_sse2.h b/drivers/webp/dsp/yuv_tables_sse2.h
new file mode 100644
index 0000000000..2b0f057518
--- /dev/null
+++ b/drivers/webp/dsp/yuv_tables_sse2.h
@@ -0,0 +1,536 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// SSE2 tables for YUV->RGB conversion (12kB overall)
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+// This file is not compiled, but #include'd directly from yuv.c
+// Only used if WEBP_YUV_USE_SSE2_TABLES is defined.
+
+static const VP8kCstSSE2 VP8kYtoRGBA[256] = {
+ {{0xfffb77b0, 0xfffb77b0, 0xfffb77b0, 0x003fc000}},
+ {{0xfffbc235, 0xfffbc235, 0xfffbc235, 0x003fc000}},
+ {{0xfffc0cba, 0xfffc0cba, 0xfffc0cba, 0x003fc000}},
+ {{0xfffc573f, 0xfffc573f, 0xfffc573f, 0x003fc000}},
+ {{0xfffca1c4, 0xfffca1c4, 0xfffca1c4, 0x003fc000}},
+ {{0xfffcec49, 0xfffcec49, 0xfffcec49, 0x003fc000}},
+ {{0xfffd36ce, 0xfffd36ce, 0xfffd36ce, 0x003fc000}},
+ {{0xfffd8153, 0xfffd8153, 0xfffd8153, 0x003fc000}},
+ {{0xfffdcbd8, 0xfffdcbd8, 0xfffdcbd8, 0x003fc000}},
+ {{0xfffe165d, 0xfffe165d, 0xfffe165d, 0x003fc000}},
+ {{0xfffe60e2, 0xfffe60e2, 0xfffe60e2, 0x003fc000}},
+ {{0xfffeab67, 0xfffeab67, 0xfffeab67, 0x003fc000}},
+ {{0xfffef5ec, 0xfffef5ec, 0xfffef5ec, 0x003fc000}},
+ {{0xffff4071, 0xffff4071, 0xffff4071, 0x003fc000}},
+ {{0xffff8af6, 0xffff8af6, 0xffff8af6, 0x003fc000}},
+ {{0xffffd57b, 0xffffd57b, 0xffffd57b, 0x003fc000}},
+ {{0x00002000, 0x00002000, 0x00002000, 0x003fc000}},
+ {{0x00006a85, 0x00006a85, 0x00006a85, 0x003fc000}},
+ {{0x0000b50a, 0x0000b50a, 0x0000b50a, 0x003fc000}},
+ {{0x0000ff8f, 0x0000ff8f, 0x0000ff8f, 0x003fc000}},
+ {{0x00014a14, 0x00014a14, 0x00014a14, 0x003fc000}},
+ {{0x00019499, 0x00019499, 0x00019499, 0x003fc000}},
+ {{0x0001df1e, 0x0001df1e, 0x0001df1e, 0x003fc000}},
+ {{0x000229a3, 0x000229a3, 0x000229a3, 0x003fc000}},
+ {{0x00027428, 0x00027428, 0x00027428, 0x003fc000}},
+ {{0x0002bead, 0x0002bead, 0x0002bead, 0x003fc000}},
+ {{0x00030932, 0x00030932, 0x00030932, 0x003fc000}},
+ {{0x000353b7, 0x000353b7, 0x000353b7, 0x003fc000}},
+ {{0x00039e3c, 0x00039e3c, 0x00039e3c, 0x003fc000}},
+ {{0x0003e8c1, 0x0003e8c1, 0x0003e8c1, 0x003fc000}},
+ {{0x00043346, 0x00043346, 0x00043346, 0x003fc000}},
+ {{0x00047dcb, 0x00047dcb, 0x00047dcb, 0x003fc000}},
+ {{0x0004c850, 0x0004c850, 0x0004c850, 0x003fc000}},
+ {{0x000512d5, 0x000512d5, 0x000512d5, 0x003fc000}},
+ {{0x00055d5a, 0x00055d5a, 0x00055d5a, 0x003fc000}},
+ {{0x0005a7df, 0x0005a7df, 0x0005a7df, 0x003fc000}},
+ {{0x0005f264, 0x0005f264, 0x0005f264, 0x003fc000}},
+ {{0x00063ce9, 0x00063ce9, 0x00063ce9, 0x003fc000}},
+ {{0x0006876e, 0x0006876e, 0x0006876e, 0x003fc000}},
+ {{0x0006d1f3, 0x0006d1f3, 0x0006d1f3, 0x003fc000}},
+ {{0x00071c78, 0x00071c78, 0x00071c78, 0x003fc000}},
+ {{0x000766fd, 0x000766fd, 0x000766fd, 0x003fc000}},
+ {{0x0007b182, 0x0007b182, 0x0007b182, 0x003fc000}},
+ {{0x0007fc07, 0x0007fc07, 0x0007fc07, 0x003fc000}},
+ {{0x0008468c, 0x0008468c, 0x0008468c, 0x003fc000}},
+ {{0x00089111, 0x00089111, 0x00089111, 0x003fc000}},
+ {{0x0008db96, 0x0008db96, 0x0008db96, 0x003fc000}},
+ {{0x0009261b, 0x0009261b, 0x0009261b, 0x003fc000}},
+ {{0x000970a0, 0x000970a0, 0x000970a0, 0x003fc000}},
+ {{0x0009bb25, 0x0009bb25, 0x0009bb25, 0x003fc000}},
+ {{0x000a05aa, 0x000a05aa, 0x000a05aa, 0x003fc000}},
+ {{0x000a502f, 0x000a502f, 0x000a502f, 0x003fc000}},
+ {{0x000a9ab4, 0x000a9ab4, 0x000a9ab4, 0x003fc000}},
+ {{0x000ae539, 0x000ae539, 0x000ae539, 0x003fc000}},
+ {{0x000b2fbe, 0x000b2fbe, 0x000b2fbe, 0x003fc000}},
+ {{0x000b7a43, 0x000b7a43, 0x000b7a43, 0x003fc000}},
+ {{0x000bc4c8, 0x000bc4c8, 0x000bc4c8, 0x003fc000}},
+ {{0x000c0f4d, 0x000c0f4d, 0x000c0f4d, 0x003fc000}},
+ {{0x000c59d2, 0x000c59d2, 0x000c59d2, 0x003fc000}},
+ {{0x000ca457, 0x000ca457, 0x000ca457, 0x003fc000}},
+ {{0x000ceedc, 0x000ceedc, 0x000ceedc, 0x003fc000}},
+ {{0x000d3961, 0x000d3961, 0x000d3961, 0x003fc000}},
+ {{0x000d83e6, 0x000d83e6, 0x000d83e6, 0x003fc000}},
+ {{0x000dce6b, 0x000dce6b, 0x000dce6b, 0x003fc000}},
+ {{0x000e18f0, 0x000e18f0, 0x000e18f0, 0x003fc000}},
+ {{0x000e6375, 0x000e6375, 0x000e6375, 0x003fc000}},
+ {{0x000eadfa, 0x000eadfa, 0x000eadfa, 0x003fc000}},
+ {{0x000ef87f, 0x000ef87f, 0x000ef87f, 0x003fc000}},
+ {{0x000f4304, 0x000f4304, 0x000f4304, 0x003fc000}},
+ {{0x000f8d89, 0x000f8d89, 0x000f8d89, 0x003fc000}},
+ {{0x000fd80e, 0x000fd80e, 0x000fd80e, 0x003fc000}},
+ {{0x00102293, 0x00102293, 0x00102293, 0x003fc000}},
+ {{0x00106d18, 0x00106d18, 0x00106d18, 0x003fc000}},
+ {{0x0010b79d, 0x0010b79d, 0x0010b79d, 0x003fc000}},
+ {{0x00110222, 0x00110222, 0x00110222, 0x003fc000}},
+ {{0x00114ca7, 0x00114ca7, 0x00114ca7, 0x003fc000}},
+ {{0x0011972c, 0x0011972c, 0x0011972c, 0x003fc000}},
+ {{0x0011e1b1, 0x0011e1b1, 0x0011e1b1, 0x003fc000}},
+ {{0x00122c36, 0x00122c36, 0x00122c36, 0x003fc000}},
+ {{0x001276bb, 0x001276bb, 0x001276bb, 0x003fc000}},
+ {{0x0012c140, 0x0012c140, 0x0012c140, 0x003fc000}},
+ {{0x00130bc5, 0x00130bc5, 0x00130bc5, 0x003fc000}},
+ {{0x0013564a, 0x0013564a, 0x0013564a, 0x003fc000}},
+ {{0x0013a0cf, 0x0013a0cf, 0x0013a0cf, 0x003fc000}},
+ {{0x0013eb54, 0x0013eb54, 0x0013eb54, 0x003fc000}},
+ {{0x001435d9, 0x001435d9, 0x001435d9, 0x003fc000}},
+ {{0x0014805e, 0x0014805e, 0x0014805e, 0x003fc000}},
+ {{0x0014cae3, 0x0014cae3, 0x0014cae3, 0x003fc000}},
+ {{0x00151568, 0x00151568, 0x00151568, 0x003fc000}},
+ {{0x00155fed, 0x00155fed, 0x00155fed, 0x003fc000}},
+ {{0x0015aa72, 0x0015aa72, 0x0015aa72, 0x003fc000}},
+ {{0x0015f4f7, 0x0015f4f7, 0x0015f4f7, 0x003fc000}},
+ {{0x00163f7c, 0x00163f7c, 0x00163f7c, 0x003fc000}},
+ {{0x00168a01, 0x00168a01, 0x00168a01, 0x003fc000}},
+ {{0x0016d486, 0x0016d486, 0x0016d486, 0x003fc000}},
+ {{0x00171f0b, 0x00171f0b, 0x00171f0b, 0x003fc000}},
+ {{0x00176990, 0x00176990, 0x00176990, 0x003fc000}},
+ {{0x0017b415, 0x0017b415, 0x0017b415, 0x003fc000}},
+ {{0x0017fe9a, 0x0017fe9a, 0x0017fe9a, 0x003fc000}},
+ {{0x0018491f, 0x0018491f, 0x0018491f, 0x003fc000}},
+ {{0x001893a4, 0x001893a4, 0x001893a4, 0x003fc000}},
+ {{0x0018de29, 0x0018de29, 0x0018de29, 0x003fc000}},
+ {{0x001928ae, 0x001928ae, 0x001928ae, 0x003fc000}},
+ {{0x00197333, 0x00197333, 0x00197333, 0x003fc000}},
+ {{0x0019bdb8, 0x0019bdb8, 0x0019bdb8, 0x003fc000}},
+ {{0x001a083d, 0x001a083d, 0x001a083d, 0x003fc000}},
+ {{0x001a52c2, 0x001a52c2, 0x001a52c2, 0x003fc000}},
+ {{0x001a9d47, 0x001a9d47, 0x001a9d47, 0x003fc000}},
+ {{0x001ae7cc, 0x001ae7cc, 0x001ae7cc, 0x003fc000}},
+ {{0x001b3251, 0x001b3251, 0x001b3251, 0x003fc000}},
+ {{0x001b7cd6, 0x001b7cd6, 0x001b7cd6, 0x003fc000}},
+ {{0x001bc75b, 0x001bc75b, 0x001bc75b, 0x003fc000}},
+ {{0x001c11e0, 0x001c11e0, 0x001c11e0, 0x003fc000}},
+ {{0x001c5c65, 0x001c5c65, 0x001c5c65, 0x003fc000}},
+ {{0x001ca6ea, 0x001ca6ea, 0x001ca6ea, 0x003fc000}},
+ {{0x001cf16f, 0x001cf16f, 0x001cf16f, 0x003fc000}},
+ {{0x001d3bf4, 0x001d3bf4, 0x001d3bf4, 0x003fc000}},
+ {{0x001d8679, 0x001d8679, 0x001d8679, 0x003fc000}},
+ {{0x001dd0fe, 0x001dd0fe, 0x001dd0fe, 0x003fc000}},
+ {{0x001e1b83, 0x001e1b83, 0x001e1b83, 0x003fc000}},
+ {{0x001e6608, 0x001e6608, 0x001e6608, 0x003fc000}},
+ {{0x001eb08d, 0x001eb08d, 0x001eb08d, 0x003fc000}},
+ {{0x001efb12, 0x001efb12, 0x001efb12, 0x003fc000}},
+ {{0x001f4597, 0x001f4597, 0x001f4597, 0x003fc000}},
+ {{0x001f901c, 0x001f901c, 0x001f901c, 0x003fc000}},
+ {{0x001fdaa1, 0x001fdaa1, 0x001fdaa1, 0x003fc000}},
+ {{0x00202526, 0x00202526, 0x00202526, 0x003fc000}},
+ {{0x00206fab, 0x00206fab, 0x00206fab, 0x003fc000}},
+ {{0x0020ba30, 0x0020ba30, 0x0020ba30, 0x003fc000}},
+ {{0x002104b5, 0x002104b5, 0x002104b5, 0x003fc000}},
+ {{0x00214f3a, 0x00214f3a, 0x00214f3a, 0x003fc000}},
+ {{0x002199bf, 0x002199bf, 0x002199bf, 0x003fc000}},
+ {{0x0021e444, 0x0021e444, 0x0021e444, 0x003fc000}},
+ {{0x00222ec9, 0x00222ec9, 0x00222ec9, 0x003fc000}},
+ {{0x0022794e, 0x0022794e, 0x0022794e, 0x003fc000}},
+ {{0x0022c3d3, 0x0022c3d3, 0x0022c3d3, 0x003fc000}},
+ {{0x00230e58, 0x00230e58, 0x00230e58, 0x003fc000}},
+ {{0x002358dd, 0x002358dd, 0x002358dd, 0x003fc000}},
+ {{0x0023a362, 0x0023a362, 0x0023a362, 0x003fc000}},
+ {{0x0023ede7, 0x0023ede7, 0x0023ede7, 0x003fc000}},
+ {{0x0024386c, 0x0024386c, 0x0024386c, 0x003fc000}},
+ {{0x002482f1, 0x002482f1, 0x002482f1, 0x003fc000}},
+ {{0x0024cd76, 0x0024cd76, 0x0024cd76, 0x003fc000}},
+ {{0x002517fb, 0x002517fb, 0x002517fb, 0x003fc000}},
+ {{0x00256280, 0x00256280, 0x00256280, 0x003fc000}},
+ {{0x0025ad05, 0x0025ad05, 0x0025ad05, 0x003fc000}},
+ {{0x0025f78a, 0x0025f78a, 0x0025f78a, 0x003fc000}},
+ {{0x0026420f, 0x0026420f, 0x0026420f, 0x003fc000}},
+ {{0x00268c94, 0x00268c94, 0x00268c94, 0x003fc000}},
+ {{0x0026d719, 0x0026d719, 0x0026d719, 0x003fc000}},
+ {{0x0027219e, 0x0027219e, 0x0027219e, 0x003fc000}},
+ {{0x00276c23, 0x00276c23, 0x00276c23, 0x003fc000}},
+ {{0x0027b6a8, 0x0027b6a8, 0x0027b6a8, 0x003fc000}},
+ {{0x0028012d, 0x0028012d, 0x0028012d, 0x003fc000}},
+ {{0x00284bb2, 0x00284bb2, 0x00284bb2, 0x003fc000}},
+ {{0x00289637, 0x00289637, 0x00289637, 0x003fc000}},
+ {{0x0028e0bc, 0x0028e0bc, 0x0028e0bc, 0x003fc000}},
+ {{0x00292b41, 0x00292b41, 0x00292b41, 0x003fc000}},
+ {{0x002975c6, 0x002975c6, 0x002975c6, 0x003fc000}},
+ {{0x0029c04b, 0x0029c04b, 0x0029c04b, 0x003fc000}},
+ {{0x002a0ad0, 0x002a0ad0, 0x002a0ad0, 0x003fc000}},
+ {{0x002a5555, 0x002a5555, 0x002a5555, 0x003fc000}},
+ {{0x002a9fda, 0x002a9fda, 0x002a9fda, 0x003fc000}},
+ {{0x002aea5f, 0x002aea5f, 0x002aea5f, 0x003fc000}},
+ {{0x002b34e4, 0x002b34e4, 0x002b34e4, 0x003fc000}},
+ {{0x002b7f69, 0x002b7f69, 0x002b7f69, 0x003fc000}},
+ {{0x002bc9ee, 0x002bc9ee, 0x002bc9ee, 0x003fc000}},
+ {{0x002c1473, 0x002c1473, 0x002c1473, 0x003fc000}},
+ {{0x002c5ef8, 0x002c5ef8, 0x002c5ef8, 0x003fc000}},
+ {{0x002ca97d, 0x002ca97d, 0x002ca97d, 0x003fc000}},
+ {{0x002cf402, 0x002cf402, 0x002cf402, 0x003fc000}},
+ {{0x002d3e87, 0x002d3e87, 0x002d3e87, 0x003fc000}},
+ {{0x002d890c, 0x002d890c, 0x002d890c, 0x003fc000}},
+ {{0x002dd391, 0x002dd391, 0x002dd391, 0x003fc000}},
+ {{0x002e1e16, 0x002e1e16, 0x002e1e16, 0x003fc000}},
+ {{0x002e689b, 0x002e689b, 0x002e689b, 0x003fc000}},
+ {{0x002eb320, 0x002eb320, 0x002eb320, 0x003fc000}},
+ {{0x002efda5, 0x002efda5, 0x002efda5, 0x003fc000}},
+ {{0x002f482a, 0x002f482a, 0x002f482a, 0x003fc000}},
+ {{0x002f92af, 0x002f92af, 0x002f92af, 0x003fc000}},
+ {{0x002fdd34, 0x002fdd34, 0x002fdd34, 0x003fc000}},
+ {{0x003027b9, 0x003027b9, 0x003027b9, 0x003fc000}},
+ {{0x0030723e, 0x0030723e, 0x0030723e, 0x003fc000}},
+ {{0x0030bcc3, 0x0030bcc3, 0x0030bcc3, 0x003fc000}},
+ {{0x00310748, 0x00310748, 0x00310748, 0x003fc000}},
+ {{0x003151cd, 0x003151cd, 0x003151cd, 0x003fc000}},
+ {{0x00319c52, 0x00319c52, 0x00319c52, 0x003fc000}},
+ {{0x0031e6d7, 0x0031e6d7, 0x0031e6d7, 0x003fc000}},
+ {{0x0032315c, 0x0032315c, 0x0032315c, 0x003fc000}},
+ {{0x00327be1, 0x00327be1, 0x00327be1, 0x003fc000}},
+ {{0x0032c666, 0x0032c666, 0x0032c666, 0x003fc000}},
+ {{0x003310eb, 0x003310eb, 0x003310eb, 0x003fc000}},
+ {{0x00335b70, 0x00335b70, 0x00335b70, 0x003fc000}},
+ {{0x0033a5f5, 0x0033a5f5, 0x0033a5f5, 0x003fc000}},
+ {{0x0033f07a, 0x0033f07a, 0x0033f07a, 0x003fc000}},
+ {{0x00343aff, 0x00343aff, 0x00343aff, 0x003fc000}},
+ {{0x00348584, 0x00348584, 0x00348584, 0x003fc000}},
+ {{0x0034d009, 0x0034d009, 0x0034d009, 0x003fc000}},
+ {{0x00351a8e, 0x00351a8e, 0x00351a8e, 0x003fc000}},
+ {{0x00356513, 0x00356513, 0x00356513, 0x003fc000}},
+ {{0x0035af98, 0x0035af98, 0x0035af98, 0x003fc000}},
+ {{0x0035fa1d, 0x0035fa1d, 0x0035fa1d, 0x003fc000}},
+ {{0x003644a2, 0x003644a2, 0x003644a2, 0x003fc000}},
+ {{0x00368f27, 0x00368f27, 0x00368f27, 0x003fc000}},
+ {{0x0036d9ac, 0x0036d9ac, 0x0036d9ac, 0x003fc000}},
+ {{0x00372431, 0x00372431, 0x00372431, 0x003fc000}},
+ {{0x00376eb6, 0x00376eb6, 0x00376eb6, 0x003fc000}},
+ {{0x0037b93b, 0x0037b93b, 0x0037b93b, 0x003fc000}},
+ {{0x003803c0, 0x003803c0, 0x003803c0, 0x003fc000}},
+ {{0x00384e45, 0x00384e45, 0x00384e45, 0x003fc000}},
+ {{0x003898ca, 0x003898ca, 0x003898ca, 0x003fc000}},
+ {{0x0038e34f, 0x0038e34f, 0x0038e34f, 0x003fc000}},
+ {{0x00392dd4, 0x00392dd4, 0x00392dd4, 0x003fc000}},
+ {{0x00397859, 0x00397859, 0x00397859, 0x003fc000}},
+ {{0x0039c2de, 0x0039c2de, 0x0039c2de, 0x003fc000}},
+ {{0x003a0d63, 0x003a0d63, 0x003a0d63, 0x003fc000}},
+ {{0x003a57e8, 0x003a57e8, 0x003a57e8, 0x003fc000}},
+ {{0x003aa26d, 0x003aa26d, 0x003aa26d, 0x003fc000}},
+ {{0x003aecf2, 0x003aecf2, 0x003aecf2, 0x003fc000}},
+ {{0x003b3777, 0x003b3777, 0x003b3777, 0x003fc000}},
+ {{0x003b81fc, 0x003b81fc, 0x003b81fc, 0x003fc000}},
+ {{0x003bcc81, 0x003bcc81, 0x003bcc81, 0x003fc000}},
+ {{0x003c1706, 0x003c1706, 0x003c1706, 0x003fc000}},
+ {{0x003c618b, 0x003c618b, 0x003c618b, 0x003fc000}},
+ {{0x003cac10, 0x003cac10, 0x003cac10, 0x003fc000}},
+ {{0x003cf695, 0x003cf695, 0x003cf695, 0x003fc000}},
+ {{0x003d411a, 0x003d411a, 0x003d411a, 0x003fc000}},
+ {{0x003d8b9f, 0x003d8b9f, 0x003d8b9f, 0x003fc000}},
+ {{0x003dd624, 0x003dd624, 0x003dd624, 0x003fc000}},
+ {{0x003e20a9, 0x003e20a9, 0x003e20a9, 0x003fc000}},
+ {{0x003e6b2e, 0x003e6b2e, 0x003e6b2e, 0x003fc000}},
+ {{0x003eb5b3, 0x003eb5b3, 0x003eb5b3, 0x003fc000}},
+ {{0x003f0038, 0x003f0038, 0x003f0038, 0x003fc000}},
+ {{0x003f4abd, 0x003f4abd, 0x003f4abd, 0x003fc000}},
+ {{0x003f9542, 0x003f9542, 0x003f9542, 0x003fc000}},
+ {{0x003fdfc7, 0x003fdfc7, 0x003fdfc7, 0x003fc000}},
+ {{0x00402a4c, 0x00402a4c, 0x00402a4c, 0x003fc000}},
+ {{0x004074d1, 0x004074d1, 0x004074d1, 0x003fc000}},
+ {{0x0040bf56, 0x0040bf56, 0x0040bf56, 0x003fc000}},
+ {{0x004109db, 0x004109db, 0x004109db, 0x003fc000}},
+ {{0x00415460, 0x00415460, 0x00415460, 0x003fc000}},
+ {{0x00419ee5, 0x00419ee5, 0x00419ee5, 0x003fc000}},
+ {{0x0041e96a, 0x0041e96a, 0x0041e96a, 0x003fc000}},
+ {{0x004233ef, 0x004233ef, 0x004233ef, 0x003fc000}},
+ {{0x00427e74, 0x00427e74, 0x00427e74, 0x003fc000}},
+ {{0x0042c8f9, 0x0042c8f9, 0x0042c8f9, 0x003fc000}},
+ {{0x0043137e, 0x0043137e, 0x0043137e, 0x003fc000}},
+ {{0x00435e03, 0x00435e03, 0x00435e03, 0x003fc000}},
+ {{0x0043a888, 0x0043a888, 0x0043a888, 0x003fc000}},
+ {{0x0043f30d, 0x0043f30d, 0x0043f30d, 0x003fc000}},
+ {{0x00443d92, 0x00443d92, 0x00443d92, 0x003fc000}},
+ {{0x00448817, 0x00448817, 0x00448817, 0x003fc000}},
+ {{0x0044d29c, 0x0044d29c, 0x0044d29c, 0x003fc000}},
+ {{0x00451d21, 0x00451d21, 0x00451d21, 0x003fc000}},
+ {{0x004567a6, 0x004567a6, 0x004567a6, 0x003fc000}},
+ {{0x0045b22b, 0x0045b22b, 0x0045b22b, 0x003fc000}}
+};
+
+static const VP8kCstSSE2 VP8kUtoRGBA[256] = {
+ {{0, 0x000c8980, 0xffbf7300, 0}}, {{0, 0x000c706d, 0xffbff41a, 0}},
+ {{0, 0x000c575a, 0xffc07534, 0}}, {{0, 0x000c3e47, 0xffc0f64e, 0}},
+ {{0, 0x000c2534, 0xffc17768, 0}}, {{0, 0x000c0c21, 0xffc1f882, 0}},
+ {{0, 0x000bf30e, 0xffc2799c, 0}}, {{0, 0x000bd9fb, 0xffc2fab6, 0}},
+ {{0, 0x000bc0e8, 0xffc37bd0, 0}}, {{0, 0x000ba7d5, 0xffc3fcea, 0}},
+ {{0, 0x000b8ec2, 0xffc47e04, 0}}, {{0, 0x000b75af, 0xffc4ff1e, 0}},
+ {{0, 0x000b5c9c, 0xffc58038, 0}}, {{0, 0x000b4389, 0xffc60152, 0}},
+ {{0, 0x000b2a76, 0xffc6826c, 0}}, {{0, 0x000b1163, 0xffc70386, 0}},
+ {{0, 0x000af850, 0xffc784a0, 0}}, {{0, 0x000adf3d, 0xffc805ba, 0}},
+ {{0, 0x000ac62a, 0xffc886d4, 0}}, {{0, 0x000aad17, 0xffc907ee, 0}},
+ {{0, 0x000a9404, 0xffc98908, 0}}, {{0, 0x000a7af1, 0xffca0a22, 0}},
+ {{0, 0x000a61de, 0xffca8b3c, 0}}, {{0, 0x000a48cb, 0xffcb0c56, 0}},
+ {{0, 0x000a2fb8, 0xffcb8d70, 0}}, {{0, 0x000a16a5, 0xffcc0e8a, 0}},
+ {{0, 0x0009fd92, 0xffcc8fa4, 0}}, {{0, 0x0009e47f, 0xffcd10be, 0}},
+ {{0, 0x0009cb6c, 0xffcd91d8, 0}}, {{0, 0x0009b259, 0xffce12f2, 0}},
+ {{0, 0x00099946, 0xffce940c, 0}}, {{0, 0x00098033, 0xffcf1526, 0}},
+ {{0, 0x00096720, 0xffcf9640, 0}}, {{0, 0x00094e0d, 0xffd0175a, 0}},
+ {{0, 0x000934fa, 0xffd09874, 0}}, {{0, 0x00091be7, 0xffd1198e, 0}},
+ {{0, 0x000902d4, 0xffd19aa8, 0}}, {{0, 0x0008e9c1, 0xffd21bc2, 0}},
+ {{0, 0x0008d0ae, 0xffd29cdc, 0}}, {{0, 0x0008b79b, 0xffd31df6, 0}},
+ {{0, 0x00089e88, 0xffd39f10, 0}}, {{0, 0x00088575, 0xffd4202a, 0}},
+ {{0, 0x00086c62, 0xffd4a144, 0}}, {{0, 0x0008534f, 0xffd5225e, 0}},
+ {{0, 0x00083a3c, 0xffd5a378, 0}}, {{0, 0x00082129, 0xffd62492, 0}},
+ {{0, 0x00080816, 0xffd6a5ac, 0}}, {{0, 0x0007ef03, 0xffd726c6, 0}},
+ {{0, 0x0007d5f0, 0xffd7a7e0, 0}}, {{0, 0x0007bcdd, 0xffd828fa, 0}},
+ {{0, 0x0007a3ca, 0xffd8aa14, 0}}, {{0, 0x00078ab7, 0xffd92b2e, 0}},
+ {{0, 0x000771a4, 0xffd9ac48, 0}}, {{0, 0x00075891, 0xffda2d62, 0}},
+ {{0, 0x00073f7e, 0xffdaae7c, 0}}, {{0, 0x0007266b, 0xffdb2f96, 0}},
+ {{0, 0x00070d58, 0xffdbb0b0, 0}}, {{0, 0x0006f445, 0xffdc31ca, 0}},
+ {{0, 0x0006db32, 0xffdcb2e4, 0}}, {{0, 0x0006c21f, 0xffdd33fe, 0}},
+ {{0, 0x0006a90c, 0xffddb518, 0}}, {{0, 0x00068ff9, 0xffde3632, 0}},
+ {{0, 0x000676e6, 0xffdeb74c, 0}}, {{0, 0x00065dd3, 0xffdf3866, 0}},
+ {{0, 0x000644c0, 0xffdfb980, 0}}, {{0, 0x00062bad, 0xffe03a9a, 0}},
+ {{0, 0x0006129a, 0xffe0bbb4, 0}}, {{0, 0x0005f987, 0xffe13cce, 0}},
+ {{0, 0x0005e074, 0xffe1bde8, 0}}, {{0, 0x0005c761, 0xffe23f02, 0}},
+ {{0, 0x0005ae4e, 0xffe2c01c, 0}}, {{0, 0x0005953b, 0xffe34136, 0}},
+ {{0, 0x00057c28, 0xffe3c250, 0}}, {{0, 0x00056315, 0xffe4436a, 0}},
+ {{0, 0x00054a02, 0xffe4c484, 0}}, {{0, 0x000530ef, 0xffe5459e, 0}},
+ {{0, 0x000517dc, 0xffe5c6b8, 0}}, {{0, 0x0004fec9, 0xffe647d2, 0}},
+ {{0, 0x0004e5b6, 0xffe6c8ec, 0}}, {{0, 0x0004cca3, 0xffe74a06, 0}},
+ {{0, 0x0004b390, 0xffe7cb20, 0}}, {{0, 0x00049a7d, 0xffe84c3a, 0}},
+ {{0, 0x0004816a, 0xffe8cd54, 0}}, {{0, 0x00046857, 0xffe94e6e, 0}},
+ {{0, 0x00044f44, 0xffe9cf88, 0}}, {{0, 0x00043631, 0xffea50a2, 0}},
+ {{0, 0x00041d1e, 0xffead1bc, 0}}, {{0, 0x0004040b, 0xffeb52d6, 0}},
+ {{0, 0x0003eaf8, 0xffebd3f0, 0}}, {{0, 0x0003d1e5, 0xffec550a, 0}},
+ {{0, 0x0003b8d2, 0xffecd624, 0}}, {{0, 0x00039fbf, 0xffed573e, 0}},
+ {{0, 0x000386ac, 0xffedd858, 0}}, {{0, 0x00036d99, 0xffee5972, 0}},
+ {{0, 0x00035486, 0xffeeda8c, 0}}, {{0, 0x00033b73, 0xffef5ba6, 0}},
+ {{0, 0x00032260, 0xffefdcc0, 0}}, {{0, 0x0003094d, 0xfff05dda, 0}},
+ {{0, 0x0002f03a, 0xfff0def4, 0}}, {{0, 0x0002d727, 0xfff1600e, 0}},
+ {{0, 0x0002be14, 0xfff1e128, 0}}, {{0, 0x0002a501, 0xfff26242, 0}},
+ {{0, 0x00028bee, 0xfff2e35c, 0}}, {{0, 0x000272db, 0xfff36476, 0}},
+ {{0, 0x000259c8, 0xfff3e590, 0}}, {{0, 0x000240b5, 0xfff466aa, 0}},
+ {{0, 0x000227a2, 0xfff4e7c4, 0}}, {{0, 0x00020e8f, 0xfff568de, 0}},
+ {{0, 0x0001f57c, 0xfff5e9f8, 0}}, {{0, 0x0001dc69, 0xfff66b12, 0}},
+ {{0, 0x0001c356, 0xfff6ec2c, 0}}, {{0, 0x0001aa43, 0xfff76d46, 0}},
+ {{0, 0x00019130, 0xfff7ee60, 0}}, {{0, 0x0001781d, 0xfff86f7a, 0}},
+ {{0, 0x00015f0a, 0xfff8f094, 0}}, {{0, 0x000145f7, 0xfff971ae, 0}},
+ {{0, 0x00012ce4, 0xfff9f2c8, 0}}, {{0, 0x000113d1, 0xfffa73e2, 0}},
+ {{0, 0x0000fabe, 0xfffaf4fc, 0}}, {{0, 0x0000e1ab, 0xfffb7616, 0}},
+ {{0, 0x0000c898, 0xfffbf730, 0}}, {{0, 0x0000af85, 0xfffc784a, 0}},
+ {{0, 0x00009672, 0xfffcf964, 0}}, {{0, 0x00007d5f, 0xfffd7a7e, 0}},
+ {{0, 0x0000644c, 0xfffdfb98, 0}}, {{0, 0x00004b39, 0xfffe7cb2, 0}},
+ {{0, 0x00003226, 0xfffefdcc, 0}}, {{0, 0x00001913, 0xffff7ee6, 0}},
+ {{0, 0x00000000, 0x00000000, 0}}, {{0, 0xffffe6ed, 0x0000811a, 0}},
+ {{0, 0xffffcdda, 0x00010234, 0}}, {{0, 0xffffb4c7, 0x0001834e, 0}},
+ {{0, 0xffff9bb4, 0x00020468, 0}}, {{0, 0xffff82a1, 0x00028582, 0}},
+ {{0, 0xffff698e, 0x0003069c, 0}}, {{0, 0xffff507b, 0x000387b6, 0}},
+ {{0, 0xffff3768, 0x000408d0, 0}}, {{0, 0xffff1e55, 0x000489ea, 0}},
+ {{0, 0xffff0542, 0x00050b04, 0}}, {{0, 0xfffeec2f, 0x00058c1e, 0}},
+ {{0, 0xfffed31c, 0x00060d38, 0}}, {{0, 0xfffeba09, 0x00068e52, 0}},
+ {{0, 0xfffea0f6, 0x00070f6c, 0}}, {{0, 0xfffe87e3, 0x00079086, 0}},
+ {{0, 0xfffe6ed0, 0x000811a0, 0}}, {{0, 0xfffe55bd, 0x000892ba, 0}},
+ {{0, 0xfffe3caa, 0x000913d4, 0}}, {{0, 0xfffe2397, 0x000994ee, 0}},
+ {{0, 0xfffe0a84, 0x000a1608, 0}}, {{0, 0xfffdf171, 0x000a9722, 0}},
+ {{0, 0xfffdd85e, 0x000b183c, 0}}, {{0, 0xfffdbf4b, 0x000b9956, 0}},
+ {{0, 0xfffda638, 0x000c1a70, 0}}, {{0, 0xfffd8d25, 0x000c9b8a, 0}},
+ {{0, 0xfffd7412, 0x000d1ca4, 0}}, {{0, 0xfffd5aff, 0x000d9dbe, 0}},
+ {{0, 0xfffd41ec, 0x000e1ed8, 0}}, {{0, 0xfffd28d9, 0x000e9ff2, 0}},
+ {{0, 0xfffd0fc6, 0x000f210c, 0}}, {{0, 0xfffcf6b3, 0x000fa226, 0}},
+ {{0, 0xfffcdda0, 0x00102340, 0}}, {{0, 0xfffcc48d, 0x0010a45a, 0}},
+ {{0, 0xfffcab7a, 0x00112574, 0}}, {{0, 0xfffc9267, 0x0011a68e, 0}},
+ {{0, 0xfffc7954, 0x001227a8, 0}}, {{0, 0xfffc6041, 0x0012a8c2, 0}},
+ {{0, 0xfffc472e, 0x001329dc, 0}}, {{0, 0xfffc2e1b, 0x0013aaf6, 0}},
+ {{0, 0xfffc1508, 0x00142c10, 0}}, {{0, 0xfffbfbf5, 0x0014ad2a, 0}},
+ {{0, 0xfffbe2e2, 0x00152e44, 0}}, {{0, 0xfffbc9cf, 0x0015af5e, 0}},
+ {{0, 0xfffbb0bc, 0x00163078, 0}}, {{0, 0xfffb97a9, 0x0016b192, 0}},
+ {{0, 0xfffb7e96, 0x001732ac, 0}}, {{0, 0xfffb6583, 0x0017b3c6, 0}},
+ {{0, 0xfffb4c70, 0x001834e0, 0}}, {{0, 0xfffb335d, 0x0018b5fa, 0}},
+ {{0, 0xfffb1a4a, 0x00193714, 0}}, {{0, 0xfffb0137, 0x0019b82e, 0}},
+ {{0, 0xfffae824, 0x001a3948, 0}}, {{0, 0xfffacf11, 0x001aba62, 0}},
+ {{0, 0xfffab5fe, 0x001b3b7c, 0}}, {{0, 0xfffa9ceb, 0x001bbc96, 0}},
+ {{0, 0xfffa83d8, 0x001c3db0, 0}}, {{0, 0xfffa6ac5, 0x001cbeca, 0}},
+ {{0, 0xfffa51b2, 0x001d3fe4, 0}}, {{0, 0xfffa389f, 0x001dc0fe, 0}},
+ {{0, 0xfffa1f8c, 0x001e4218, 0}}, {{0, 0xfffa0679, 0x001ec332, 0}},
+ {{0, 0xfff9ed66, 0x001f444c, 0}}, {{0, 0xfff9d453, 0x001fc566, 0}},
+ {{0, 0xfff9bb40, 0x00204680, 0}}, {{0, 0xfff9a22d, 0x0020c79a, 0}},
+ {{0, 0xfff9891a, 0x002148b4, 0}}, {{0, 0xfff97007, 0x0021c9ce, 0}},
+ {{0, 0xfff956f4, 0x00224ae8, 0}}, {{0, 0xfff93de1, 0x0022cc02, 0}},
+ {{0, 0xfff924ce, 0x00234d1c, 0}}, {{0, 0xfff90bbb, 0x0023ce36, 0}},
+ {{0, 0xfff8f2a8, 0x00244f50, 0}}, {{0, 0xfff8d995, 0x0024d06a, 0}},
+ {{0, 0xfff8c082, 0x00255184, 0}}, {{0, 0xfff8a76f, 0x0025d29e, 0}},
+ {{0, 0xfff88e5c, 0x002653b8, 0}}, {{0, 0xfff87549, 0x0026d4d2, 0}},
+ {{0, 0xfff85c36, 0x002755ec, 0}}, {{0, 0xfff84323, 0x0027d706, 0}},
+ {{0, 0xfff82a10, 0x00285820, 0}}, {{0, 0xfff810fd, 0x0028d93a, 0}},
+ {{0, 0xfff7f7ea, 0x00295a54, 0}}, {{0, 0xfff7ded7, 0x0029db6e, 0}},
+ {{0, 0xfff7c5c4, 0x002a5c88, 0}}, {{0, 0xfff7acb1, 0x002adda2, 0}},
+ {{0, 0xfff7939e, 0x002b5ebc, 0}}, {{0, 0xfff77a8b, 0x002bdfd6, 0}},
+ {{0, 0xfff76178, 0x002c60f0, 0}}, {{0, 0xfff74865, 0x002ce20a, 0}},
+ {{0, 0xfff72f52, 0x002d6324, 0}}, {{0, 0xfff7163f, 0x002de43e, 0}},
+ {{0, 0xfff6fd2c, 0x002e6558, 0}}, {{0, 0xfff6e419, 0x002ee672, 0}},
+ {{0, 0xfff6cb06, 0x002f678c, 0}}, {{0, 0xfff6b1f3, 0x002fe8a6, 0}},
+ {{0, 0xfff698e0, 0x003069c0, 0}}, {{0, 0xfff67fcd, 0x0030eada, 0}},
+ {{0, 0xfff666ba, 0x00316bf4, 0}}, {{0, 0xfff64da7, 0x0031ed0e, 0}},
+ {{0, 0xfff63494, 0x00326e28, 0}}, {{0, 0xfff61b81, 0x0032ef42, 0}},
+ {{0, 0xfff6026e, 0x0033705c, 0}}, {{0, 0xfff5e95b, 0x0033f176, 0}},
+ {{0, 0xfff5d048, 0x00347290, 0}}, {{0, 0xfff5b735, 0x0034f3aa, 0}},
+ {{0, 0xfff59e22, 0x003574c4, 0}}, {{0, 0xfff5850f, 0x0035f5de, 0}},
+ {{0, 0xfff56bfc, 0x003676f8, 0}}, {{0, 0xfff552e9, 0x0036f812, 0}},
+ {{0, 0xfff539d6, 0x0037792c, 0}}, {{0, 0xfff520c3, 0x0037fa46, 0}},
+ {{0, 0xfff507b0, 0x00387b60, 0}}, {{0, 0xfff4ee9d, 0x0038fc7a, 0}},
+ {{0, 0xfff4d58a, 0x00397d94, 0}}, {{0, 0xfff4bc77, 0x0039feae, 0}},
+ {{0, 0xfff4a364, 0x003a7fc8, 0}}, {{0, 0xfff48a51, 0x003b00e2, 0}},
+ {{0, 0xfff4713e, 0x003b81fc, 0}}, {{0, 0xfff4582b, 0x003c0316, 0}},
+ {{0, 0xfff43f18, 0x003c8430, 0}}, {{0, 0xfff42605, 0x003d054a, 0}},
+ {{0, 0xfff40cf2, 0x003d8664, 0}}, {{0, 0xfff3f3df, 0x003e077e, 0}},
+ {{0, 0xfff3dacc, 0x003e8898, 0}}, {{0, 0xfff3c1b9, 0x003f09b2, 0}},
+ {{0, 0xfff3a8a6, 0x003f8acc, 0}}, {{0, 0xfff38f93, 0x00400be6, 0}}
+};
+
+static VP8kCstSSE2 VP8kVtoRGBA[256] = {
+ {{0xffcced80, 0x001a0400, 0, 0}}, {{0xffcd53a5, 0x0019cff8, 0, 0}},
+ {{0xffcdb9ca, 0x00199bf0, 0, 0}}, {{0xffce1fef, 0x001967e8, 0, 0}},
+ {{0xffce8614, 0x001933e0, 0, 0}}, {{0xffceec39, 0x0018ffd8, 0, 0}},
+ {{0xffcf525e, 0x0018cbd0, 0, 0}}, {{0xffcfb883, 0x001897c8, 0, 0}},
+ {{0xffd01ea8, 0x001863c0, 0, 0}}, {{0xffd084cd, 0x00182fb8, 0, 0}},
+ {{0xffd0eaf2, 0x0017fbb0, 0, 0}}, {{0xffd15117, 0x0017c7a8, 0, 0}},
+ {{0xffd1b73c, 0x001793a0, 0, 0}}, {{0xffd21d61, 0x00175f98, 0, 0}},
+ {{0xffd28386, 0x00172b90, 0, 0}}, {{0xffd2e9ab, 0x0016f788, 0, 0}},
+ {{0xffd34fd0, 0x0016c380, 0, 0}}, {{0xffd3b5f5, 0x00168f78, 0, 0}},
+ {{0xffd41c1a, 0x00165b70, 0, 0}}, {{0xffd4823f, 0x00162768, 0, 0}},
+ {{0xffd4e864, 0x0015f360, 0, 0}}, {{0xffd54e89, 0x0015bf58, 0, 0}},
+ {{0xffd5b4ae, 0x00158b50, 0, 0}}, {{0xffd61ad3, 0x00155748, 0, 0}},
+ {{0xffd680f8, 0x00152340, 0, 0}}, {{0xffd6e71d, 0x0014ef38, 0, 0}},
+ {{0xffd74d42, 0x0014bb30, 0, 0}}, {{0xffd7b367, 0x00148728, 0, 0}},
+ {{0xffd8198c, 0x00145320, 0, 0}}, {{0xffd87fb1, 0x00141f18, 0, 0}},
+ {{0xffd8e5d6, 0x0013eb10, 0, 0}}, {{0xffd94bfb, 0x0013b708, 0, 0}},
+ {{0xffd9b220, 0x00138300, 0, 0}}, {{0xffda1845, 0x00134ef8, 0, 0}},
+ {{0xffda7e6a, 0x00131af0, 0, 0}}, {{0xffdae48f, 0x0012e6e8, 0, 0}},
+ {{0xffdb4ab4, 0x0012b2e0, 0, 0}}, {{0xffdbb0d9, 0x00127ed8, 0, 0}},
+ {{0xffdc16fe, 0x00124ad0, 0, 0}}, {{0xffdc7d23, 0x001216c8, 0, 0}},
+ {{0xffdce348, 0x0011e2c0, 0, 0}}, {{0xffdd496d, 0x0011aeb8, 0, 0}},
+ {{0xffddaf92, 0x00117ab0, 0, 0}}, {{0xffde15b7, 0x001146a8, 0, 0}},
+ {{0xffde7bdc, 0x001112a0, 0, 0}}, {{0xffdee201, 0x0010de98, 0, 0}},
+ {{0xffdf4826, 0x0010aa90, 0, 0}}, {{0xffdfae4b, 0x00107688, 0, 0}},
+ {{0xffe01470, 0x00104280, 0, 0}}, {{0xffe07a95, 0x00100e78, 0, 0}},
+ {{0xffe0e0ba, 0x000fda70, 0, 0}}, {{0xffe146df, 0x000fa668, 0, 0}},
+ {{0xffe1ad04, 0x000f7260, 0, 0}}, {{0xffe21329, 0x000f3e58, 0, 0}},
+ {{0xffe2794e, 0x000f0a50, 0, 0}}, {{0xffe2df73, 0x000ed648, 0, 0}},
+ {{0xffe34598, 0x000ea240, 0, 0}}, {{0xffe3abbd, 0x000e6e38, 0, 0}},
+ {{0xffe411e2, 0x000e3a30, 0, 0}}, {{0xffe47807, 0x000e0628, 0, 0}},
+ {{0xffe4de2c, 0x000dd220, 0, 0}}, {{0xffe54451, 0x000d9e18, 0, 0}},
+ {{0xffe5aa76, 0x000d6a10, 0, 0}}, {{0xffe6109b, 0x000d3608, 0, 0}},
+ {{0xffe676c0, 0x000d0200, 0, 0}}, {{0xffe6dce5, 0x000ccdf8, 0, 0}},
+ {{0xffe7430a, 0x000c99f0, 0, 0}}, {{0xffe7a92f, 0x000c65e8, 0, 0}},
+ {{0xffe80f54, 0x000c31e0, 0, 0}}, {{0xffe87579, 0x000bfdd8, 0, 0}},
+ {{0xffe8db9e, 0x000bc9d0, 0, 0}}, {{0xffe941c3, 0x000b95c8, 0, 0}},
+ {{0xffe9a7e8, 0x000b61c0, 0, 0}}, {{0xffea0e0d, 0x000b2db8, 0, 0}},
+ {{0xffea7432, 0x000af9b0, 0, 0}}, {{0xffeada57, 0x000ac5a8, 0, 0}},
+ {{0xffeb407c, 0x000a91a0, 0, 0}}, {{0xffeba6a1, 0x000a5d98, 0, 0}},
+ {{0xffec0cc6, 0x000a2990, 0, 0}}, {{0xffec72eb, 0x0009f588, 0, 0}},
+ {{0xffecd910, 0x0009c180, 0, 0}}, {{0xffed3f35, 0x00098d78, 0, 0}},
+ {{0xffeda55a, 0x00095970, 0, 0}}, {{0xffee0b7f, 0x00092568, 0, 0}},
+ {{0xffee71a4, 0x0008f160, 0, 0}}, {{0xffeed7c9, 0x0008bd58, 0, 0}},
+ {{0xffef3dee, 0x00088950, 0, 0}}, {{0xffefa413, 0x00085548, 0, 0}},
+ {{0xfff00a38, 0x00082140, 0, 0}}, {{0xfff0705d, 0x0007ed38, 0, 0}},
+ {{0xfff0d682, 0x0007b930, 0, 0}}, {{0xfff13ca7, 0x00078528, 0, 0}},
+ {{0xfff1a2cc, 0x00075120, 0, 0}}, {{0xfff208f1, 0x00071d18, 0, 0}},
+ {{0xfff26f16, 0x0006e910, 0, 0}}, {{0xfff2d53b, 0x0006b508, 0, 0}},
+ {{0xfff33b60, 0x00068100, 0, 0}}, {{0xfff3a185, 0x00064cf8, 0, 0}},
+ {{0xfff407aa, 0x000618f0, 0, 0}}, {{0xfff46dcf, 0x0005e4e8, 0, 0}},
+ {{0xfff4d3f4, 0x0005b0e0, 0, 0}}, {{0xfff53a19, 0x00057cd8, 0, 0}},
+ {{0xfff5a03e, 0x000548d0, 0, 0}}, {{0xfff60663, 0x000514c8, 0, 0}},
+ {{0xfff66c88, 0x0004e0c0, 0, 0}}, {{0xfff6d2ad, 0x0004acb8, 0, 0}},
+ {{0xfff738d2, 0x000478b0, 0, 0}}, {{0xfff79ef7, 0x000444a8, 0, 0}},
+ {{0xfff8051c, 0x000410a0, 0, 0}}, {{0xfff86b41, 0x0003dc98, 0, 0}},
+ {{0xfff8d166, 0x0003a890, 0, 0}}, {{0xfff9378b, 0x00037488, 0, 0}},
+ {{0xfff99db0, 0x00034080, 0, 0}}, {{0xfffa03d5, 0x00030c78, 0, 0}},
+ {{0xfffa69fa, 0x0002d870, 0, 0}}, {{0xfffad01f, 0x0002a468, 0, 0}},
+ {{0xfffb3644, 0x00027060, 0, 0}}, {{0xfffb9c69, 0x00023c58, 0, 0}},
+ {{0xfffc028e, 0x00020850, 0, 0}}, {{0xfffc68b3, 0x0001d448, 0, 0}},
+ {{0xfffcced8, 0x0001a040, 0, 0}}, {{0xfffd34fd, 0x00016c38, 0, 0}},
+ {{0xfffd9b22, 0x00013830, 0, 0}}, {{0xfffe0147, 0x00010428, 0, 0}},
+ {{0xfffe676c, 0x0000d020, 0, 0}}, {{0xfffecd91, 0x00009c18, 0, 0}},
+ {{0xffff33b6, 0x00006810, 0, 0}}, {{0xffff99db, 0x00003408, 0, 0}},
+ {{0x00000000, 0x00000000, 0, 0}}, {{0x00006625, 0xffffcbf8, 0, 0}},
+ {{0x0000cc4a, 0xffff97f0, 0, 0}}, {{0x0001326f, 0xffff63e8, 0, 0}},
+ {{0x00019894, 0xffff2fe0, 0, 0}}, {{0x0001feb9, 0xfffefbd8, 0, 0}},
+ {{0x000264de, 0xfffec7d0, 0, 0}}, {{0x0002cb03, 0xfffe93c8, 0, 0}},
+ {{0x00033128, 0xfffe5fc0, 0, 0}}, {{0x0003974d, 0xfffe2bb8, 0, 0}},
+ {{0x0003fd72, 0xfffdf7b0, 0, 0}}, {{0x00046397, 0xfffdc3a8, 0, 0}},
+ {{0x0004c9bc, 0xfffd8fa0, 0, 0}}, {{0x00052fe1, 0xfffd5b98, 0, 0}},
+ {{0x00059606, 0xfffd2790, 0, 0}}, {{0x0005fc2b, 0xfffcf388, 0, 0}},
+ {{0x00066250, 0xfffcbf80, 0, 0}}, {{0x0006c875, 0xfffc8b78, 0, 0}},
+ {{0x00072e9a, 0xfffc5770, 0, 0}}, {{0x000794bf, 0xfffc2368, 0, 0}},
+ {{0x0007fae4, 0xfffbef60, 0, 0}}, {{0x00086109, 0xfffbbb58, 0, 0}},
+ {{0x0008c72e, 0xfffb8750, 0, 0}}, {{0x00092d53, 0xfffb5348, 0, 0}},
+ {{0x00099378, 0xfffb1f40, 0, 0}}, {{0x0009f99d, 0xfffaeb38, 0, 0}},
+ {{0x000a5fc2, 0xfffab730, 0, 0}}, {{0x000ac5e7, 0xfffa8328, 0, 0}},
+ {{0x000b2c0c, 0xfffa4f20, 0, 0}}, {{0x000b9231, 0xfffa1b18, 0, 0}},
+ {{0x000bf856, 0xfff9e710, 0, 0}}, {{0x000c5e7b, 0xfff9b308, 0, 0}},
+ {{0x000cc4a0, 0xfff97f00, 0, 0}}, {{0x000d2ac5, 0xfff94af8, 0, 0}},
+ {{0x000d90ea, 0xfff916f0, 0, 0}}, {{0x000df70f, 0xfff8e2e8, 0, 0}},
+ {{0x000e5d34, 0xfff8aee0, 0, 0}}, {{0x000ec359, 0xfff87ad8, 0, 0}},
+ {{0x000f297e, 0xfff846d0, 0, 0}}, {{0x000f8fa3, 0xfff812c8, 0, 0}},
+ {{0x000ff5c8, 0xfff7dec0, 0, 0}}, {{0x00105bed, 0xfff7aab8, 0, 0}},
+ {{0x0010c212, 0xfff776b0, 0, 0}}, {{0x00112837, 0xfff742a8, 0, 0}},
+ {{0x00118e5c, 0xfff70ea0, 0, 0}}, {{0x0011f481, 0xfff6da98, 0, 0}},
+ {{0x00125aa6, 0xfff6a690, 0, 0}}, {{0x0012c0cb, 0xfff67288, 0, 0}},
+ {{0x001326f0, 0xfff63e80, 0, 0}}, {{0x00138d15, 0xfff60a78, 0, 0}},
+ {{0x0013f33a, 0xfff5d670, 0, 0}}, {{0x0014595f, 0xfff5a268, 0, 0}},
+ {{0x0014bf84, 0xfff56e60, 0, 0}}, {{0x001525a9, 0xfff53a58, 0, 0}},
+ {{0x00158bce, 0xfff50650, 0, 0}}, {{0x0015f1f3, 0xfff4d248, 0, 0}},
+ {{0x00165818, 0xfff49e40, 0, 0}}, {{0x0016be3d, 0xfff46a38, 0, 0}},
+ {{0x00172462, 0xfff43630, 0, 0}}, {{0x00178a87, 0xfff40228, 0, 0}},
+ {{0x0017f0ac, 0xfff3ce20, 0, 0}}, {{0x001856d1, 0xfff39a18, 0, 0}},
+ {{0x0018bcf6, 0xfff36610, 0, 0}}, {{0x0019231b, 0xfff33208, 0, 0}},
+ {{0x00198940, 0xfff2fe00, 0, 0}}, {{0x0019ef65, 0xfff2c9f8, 0, 0}},
+ {{0x001a558a, 0xfff295f0, 0, 0}}, {{0x001abbaf, 0xfff261e8, 0, 0}},
+ {{0x001b21d4, 0xfff22de0, 0, 0}}, {{0x001b87f9, 0xfff1f9d8, 0, 0}},
+ {{0x001bee1e, 0xfff1c5d0, 0, 0}}, {{0x001c5443, 0xfff191c8, 0, 0}},
+ {{0x001cba68, 0xfff15dc0, 0, 0}}, {{0x001d208d, 0xfff129b8, 0, 0}},
+ {{0x001d86b2, 0xfff0f5b0, 0, 0}}, {{0x001decd7, 0xfff0c1a8, 0, 0}},
+ {{0x001e52fc, 0xfff08da0, 0, 0}}, {{0x001eb921, 0xfff05998, 0, 0}},
+ {{0x001f1f46, 0xfff02590, 0, 0}}, {{0x001f856b, 0xffeff188, 0, 0}},
+ {{0x001feb90, 0xffefbd80, 0, 0}}, {{0x002051b5, 0xffef8978, 0, 0}},
+ {{0x0020b7da, 0xffef5570, 0, 0}}, {{0x00211dff, 0xffef2168, 0, 0}},
+ {{0x00218424, 0xffeeed60, 0, 0}}, {{0x0021ea49, 0xffeeb958, 0, 0}},
+ {{0x0022506e, 0xffee8550, 0, 0}}, {{0x0022b693, 0xffee5148, 0, 0}},
+ {{0x00231cb8, 0xffee1d40, 0, 0}}, {{0x002382dd, 0xffede938, 0, 0}},
+ {{0x0023e902, 0xffedb530, 0, 0}}, {{0x00244f27, 0xffed8128, 0, 0}},
+ {{0x0024b54c, 0xffed4d20, 0, 0}}, {{0x00251b71, 0xffed1918, 0, 0}},
+ {{0x00258196, 0xffece510, 0, 0}}, {{0x0025e7bb, 0xffecb108, 0, 0}},
+ {{0x00264de0, 0xffec7d00, 0, 0}}, {{0x0026b405, 0xffec48f8, 0, 0}},
+ {{0x00271a2a, 0xffec14f0, 0, 0}}, {{0x0027804f, 0xffebe0e8, 0, 0}},
+ {{0x0027e674, 0xffebace0, 0, 0}}, {{0x00284c99, 0xffeb78d8, 0, 0}},
+ {{0x0028b2be, 0xffeb44d0, 0, 0}}, {{0x002918e3, 0xffeb10c8, 0, 0}},
+ {{0x00297f08, 0xffeadcc0, 0, 0}}, {{0x0029e52d, 0xffeaa8b8, 0, 0}},
+ {{0x002a4b52, 0xffea74b0, 0, 0}}, {{0x002ab177, 0xffea40a8, 0, 0}},
+ {{0x002b179c, 0xffea0ca0, 0, 0}}, {{0x002b7dc1, 0xffe9d898, 0, 0}},
+ {{0x002be3e6, 0xffe9a490, 0, 0}}, {{0x002c4a0b, 0xffe97088, 0, 0}},
+ {{0x002cb030, 0xffe93c80, 0, 0}}, {{0x002d1655, 0xffe90878, 0, 0}},
+ {{0x002d7c7a, 0xffe8d470, 0, 0}}, {{0x002de29f, 0xffe8a068, 0, 0}},
+ {{0x002e48c4, 0xffe86c60, 0, 0}}, {{0x002eaee9, 0xffe83858, 0, 0}},
+ {{0x002f150e, 0xffe80450, 0, 0}}, {{0x002f7b33, 0xffe7d048, 0, 0}},
+ {{0x002fe158, 0xffe79c40, 0, 0}}, {{0x0030477d, 0xffe76838, 0, 0}},
+ {{0x0030ada2, 0xffe73430, 0, 0}}, {{0x003113c7, 0xffe70028, 0, 0}},
+ {{0x003179ec, 0xffe6cc20, 0, 0}}, {{0x0031e011, 0xffe69818, 0, 0}},
+ {{0x00324636, 0xffe66410, 0, 0}}, {{0x0032ac5b, 0xffe63008, 0, 0}}
+};
diff --git a/drivers/webp/enc/alpha.c b/drivers/webp/enc/alpha.c
index e554eb7f30..1842b36401 100644
--- a/drivers/webp/enc/alpha.c
+++ b/drivers/webp/enc/alpha.c
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Alpha-plane compression.
@@ -13,13 +15,11 @@
#include <stdlib.h>
#include "./vp8enci.h"
+#include "../dsp/dsp.h"
#include "../utils/filters.h"
#include "../utils/quant_levels.h"
-#include "../format_constants.h"
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
+#include "../utils/utils.h"
+#include "webp/format_constants.h"
// -----------------------------------------------------------------------------
// Encodes the given alpha data via specified compression method 'method'.
@@ -36,7 +36,7 @@ extern "C" {
//
// 'output' corresponds to the buffer containing compressed alpha data.
// This buffer is allocated by this method and caller should call
-// free(*output) when done.
+// WebPSafeFree(*output) when done.
// 'output_size' corresponds to size of this compressed alpha buffer.
//
// Returns 1 on successfully encoding the alpha and
@@ -48,12 +48,11 @@ extern "C" {
static int EncodeLossless(const uint8_t* const data, int width, int height,
int effort_level, // in [0..6] range
- VP8BitWriter* const bw,
+ VP8LBitWriter* const bw,
WebPAuxStats* const stats) {
int ok = 0;
WebPConfig config;
WebPPicture picture;
- VP8LBitWriter tmp_bw;
WebPPictureInit(&picture);
picture.width = width;
@@ -63,53 +62,51 @@ static int EncodeLossless(const uint8_t* const data, int width, int height,
if (!WebPPictureAlloc(&picture)) return 0;
// Transfer the alpha values to the green channel.
- {
- int i, j;
- uint32_t* dst = picture.argb;
- const uint8_t* src = data;
- for (j = 0; j < picture.height; ++j) {
- for (i = 0; i < picture.width; ++i) {
- dst[i] = (src[i] << 8) | 0xff000000u;
- }
- src += width;
- dst += picture.argb_stride;
- }
- }
+ WebPDispatchAlphaToGreen(data, width, picture.width, picture.height,
+ picture.argb, picture.argb_stride);
WebPConfigInit(&config);
config.lossless = 1;
config.method = effort_level; // impact is very small
- // Set moderate default quality setting for alpha. Higher qualities (80 and
- // above) could be very slow.
- config.quality = 10.f + 15.f * effort_level;
- if (config.quality > 100.f) config.quality = 100.f;
+ // Set a low default quality for encoding alpha. Ensure that Alpha quality at
+ // lower methods (3 and below) is less than the threshold for triggering
+ // costly 'BackwardReferencesTraceBackwards'.
+ config.quality = 8.f * effort_level;
+ assert(config.quality >= 0 && config.quality <= 100.f);
- ok = VP8LBitWriterInit(&tmp_bw, (width * height) >> 3);
- ok = ok && (VP8LEncodeStream(&config, &picture, &tmp_bw) == VP8_ENC_OK);
+ ok = (VP8LEncodeStream(&config, &picture, bw) == VP8_ENC_OK);
WebPPictureFree(&picture);
- if (ok) {
- const uint8_t* const data = VP8LBitWriterFinish(&tmp_bw);
- const size_t data_size = VP8LBitWriterNumBytes(&tmp_bw);
- VP8BitWriterAppend(bw, data, data_size);
+ ok = ok && !bw->error_;
+ if (!ok) {
+ VP8LBitWriterWipeOut(bw);
+ return 0;
}
- VP8LBitWriterDestroy(&tmp_bw);
- return ok && !bw->error_;
+ return 1;
}
// -----------------------------------------------------------------------------
+// Small struct to hold the result of a filter mode compression attempt.
+typedef struct {
+ size_t score;
+ VP8BitWriter bw;
+ WebPAuxStats stats;
+} FilterTrial;
+
+// This function always returns an initialized 'bw' object, even upon error.
static int EncodeAlphaInternal(const uint8_t* const data, int width, int height,
int method, int filter, int reduce_levels,
int effort_level, // in [0..6] range
uint8_t* const tmp_alpha,
- VP8BitWriter* const bw,
- WebPAuxStats* const stats) {
+ FilterTrial* result) {
int ok = 0;
const uint8_t* alpha_src;
WebPFilterFunc filter_func;
uint8_t header;
- size_t expected_size;
const size_t data_size = width * height;
+ const uint8_t* output = NULL;
+ size_t output_size = 0;
+ VP8LBitWriter tmp_bw;
assert((uint64_t)data_size == (uint64_t)width * height); // as per spec
assert(filter >= 0 && filter < WEBP_FILTER_LAST);
@@ -118,43 +115,163 @@ static int EncodeAlphaInternal(const uint8_t* const data, int width, int height,
assert(sizeof(header) == ALPHA_HEADER_LEN);
// TODO(skal): have a common function and #define's to validate alpha params.
- expected_size =
- (method == ALPHA_NO_COMPRESSION) ? (ALPHA_HEADER_LEN + data_size)
- : (data_size >> 5);
- header = method | (filter << 2);
- if (reduce_levels) header |= ALPHA_PREPROCESSED_LEVELS << 4;
-
- VP8BitWriterInit(bw, expected_size);
- VP8BitWriterAppend(bw, &header, ALPHA_HEADER_LEN);
-
filter_func = WebPFilters[filter];
- if (filter_func) {
- filter_func(data, width, height, 1, width, tmp_alpha);
+ if (filter_func != NULL) {
+ filter_func(data, width, height, width, tmp_alpha);
alpha_src = tmp_alpha;
} else {
alpha_src = data;
}
+ if (method != ALPHA_NO_COMPRESSION) {
+ ok = VP8LBitWriterInit(&tmp_bw, data_size >> 3);
+ ok = ok && EncodeLossless(alpha_src, width, height, effort_level,
+ &tmp_bw, &result->stats);
+ if (ok) {
+ output = VP8LBitWriterFinish(&tmp_bw);
+ output_size = VP8LBitWriterNumBytes(&tmp_bw);
+ if (output_size > data_size) {
+ // compressed size is larger than source! Revert to uncompressed mode.
+ method = ALPHA_NO_COMPRESSION;
+ VP8LBitWriterWipeOut(&tmp_bw);
+ }
+ } else {
+ VP8LBitWriterWipeOut(&tmp_bw);
+ return 0;
+ }
+ }
+
if (method == ALPHA_NO_COMPRESSION) {
- ok = VP8BitWriterAppend(bw, alpha_src, width * height);
- ok = ok && !bw->error_;
- } else {
- ok = EncodeLossless(alpha_src, width, height, effort_level, bw, stats);
- VP8BitWriterFinish(bw);
+ output = alpha_src;
+ output_size = data_size;
+ ok = 1;
+ }
+
+ // Emit final result.
+ header = method | (filter << 2);
+ if (reduce_levels) header |= ALPHA_PREPROCESSED_LEVELS << 4;
+
+ VP8BitWriterInit(&result->bw, ALPHA_HEADER_LEN + output_size);
+ ok = ok && VP8BitWriterAppend(&result->bw, &header, ALPHA_HEADER_LEN);
+ ok = ok && VP8BitWriterAppend(&result->bw, output, output_size);
+
+ if (method != ALPHA_NO_COMPRESSION) {
+ VP8LBitWriterWipeOut(&tmp_bw);
}
+ ok = ok && !result->bw.error_;
+ result->score = VP8BitWriterSize(&result->bw);
return ok;
}
// -----------------------------------------------------------------------------
-// TODO(skal): move to dsp/ ?
-static void CopyPlane(const uint8_t* src, int src_stride,
- uint8_t* dst, int dst_stride, int width, int height) {
- while (height-- > 0) {
- memcpy(dst, src, width);
- src += src_stride;
- dst += dst_stride;
+static int GetNumColors(const uint8_t* data, int width, int height,
+ int stride) {
+ int j;
+ int colors = 0;
+ uint8_t color[256] = { 0 };
+
+ for (j = 0; j < height; ++j) {
+ int i;
+ const uint8_t* const p = data + j * stride;
+ for (i = 0; i < width; ++i) {
+ color[p[i]] = 1;
+ }
+ }
+ for (j = 0; j < 256; ++j) {
+ if (color[j] > 0) ++colors;
}
+ return colors;
+}
+
+#define FILTER_TRY_NONE (1 << WEBP_FILTER_NONE)
+#define FILTER_TRY_ALL ((1 << WEBP_FILTER_LAST) - 1)
+
+// Given the input 'filter' option, return an OR'd bit-set of filters to try.
+static uint32_t GetFilterMap(const uint8_t* alpha, int width, int height,
+ int filter, int effort_level) {
+ uint32_t bit_map = 0U;
+ if (filter == WEBP_FILTER_FAST) {
+ // Quick estimate of the best candidate.
+ int try_filter_none = (effort_level > 3);
+ const int kMinColorsForFilterNone = 16;
+ const int kMaxColorsForFilterNone = 192;
+ const int num_colors = GetNumColors(alpha, width, height, width);
+ // For low number of colors, NONE yields better compression.
+ filter = (num_colors <= kMinColorsForFilterNone)
+ ? WEBP_FILTER_NONE
+ : WebPEstimateBestFilter(alpha, width, height, width);
+ bit_map |= 1 << filter;
+ // For large number of colors, try FILTER_NONE in addition to the best
+ // filter as well.
+ if (try_filter_none || num_colors > kMaxColorsForFilterNone) {
+ bit_map |= FILTER_TRY_NONE;
+ }
+ } else if (filter == WEBP_FILTER_NONE) {
+ bit_map = FILTER_TRY_NONE;
+ } else { // WEBP_FILTER_BEST -> try all
+ bit_map = FILTER_TRY_ALL;
+ }
+ return bit_map;
+}
+
+static void InitFilterTrial(FilterTrial* const score) {
+ score->score = (size_t)~0U;
+ VP8BitWriterInit(&score->bw, 0);
+}
+
+static int ApplyFiltersAndEncode(const uint8_t* alpha, int width, int height,
+ size_t data_size, int method, int filter,
+ int reduce_levels, int effort_level,
+ uint8_t** const output,
+ size_t* const output_size,
+ WebPAuxStats* const stats) {
+ int ok = 1;
+ FilterTrial best;
+ uint32_t try_map =
+ GetFilterMap(alpha, width, height, filter, effort_level);
+ InitFilterTrial(&best);
+
+ if (try_map != FILTER_TRY_NONE) {
+ uint8_t* filtered_alpha = (uint8_t*)WebPSafeMalloc(1ULL, data_size);
+ if (filtered_alpha == NULL) return 0;
+
+ for (filter = WEBP_FILTER_NONE; ok && try_map; ++filter, try_map >>= 1) {
+ if (try_map & 1) {
+ FilterTrial trial;
+ ok = EncodeAlphaInternal(alpha, width, height, method, filter,
+ reduce_levels, effort_level, filtered_alpha,
+ &trial);
+ if (ok && trial.score < best.score) {
+ VP8BitWriterWipeOut(&best.bw);
+ best = trial;
+ } else {
+ VP8BitWriterWipeOut(&trial.bw);
+ }
+ }
+ }
+ WebPSafeFree(filtered_alpha);
+ } else {
+ ok = EncodeAlphaInternal(alpha, width, height, method, WEBP_FILTER_NONE,
+ reduce_levels, effort_level, NULL, &best);
+ }
+ if (ok) {
+ if (stats != NULL) {
+ stats->lossless_features = best.stats.lossless_features;
+ stats->histogram_bits = best.stats.histogram_bits;
+ stats->transform_bits = best.stats.transform_bits;
+ stats->cache_bits = best.stats.cache_bits;
+ stats->palette_size = best.stats.palette_size;
+ stats->lossless_size = best.stats.lossless_size;
+ stats->lossless_hdr_size = best.stats.lossless_hdr_size;
+ stats->lossless_data_size = best.stats.lossless_data_size;
+ }
+ *output_size = VP8BitWriterSize(&best.bw);
+ *output = VP8BitWriterBuf(&best.bw);
+ } else {
+ VP8BitWriterWipeOut(&best.bw);
+ }
+ return ok;
}
static int EncodeAlpha(VP8Encoder* const enc,
@@ -187,13 +304,18 @@ static int EncodeAlpha(VP8Encoder* const enc,
return 0;
}
- quant_alpha = (uint8_t*)malloc(data_size);
+ if (method == ALPHA_NO_COMPRESSION) {
+ // Don't filter, as filtering will make no impact on compressed size.
+ filter = WEBP_FILTER_NONE;
+ }
+
+ quant_alpha = (uint8_t*)WebPSafeMalloc(1ULL, data_size);
if (quant_alpha == NULL) {
return 0;
}
// Extract alpha data (width x height) from raw_data (stride x height).
- CopyPlane(pic->a, pic->a_stride, quant_alpha, width, width, height);
+ WebPCopyPlane(pic->a, pic->a_stride, quant_alpha, width, width, height);
if (reduce_levels) { // No Quantization required for 'quality = 100'.
// 16 alpha levels gives quite a low MSE w.r.t original alpha plane hence
@@ -205,126 +327,99 @@ static int EncodeAlpha(VP8Encoder* const enc,
}
if (ok) {
- VP8BitWriter bw;
- int test_filter;
- uint8_t* filtered_alpha = NULL;
-
- // We always test WEBP_FILTER_NONE first.
- ok = EncodeAlphaInternal(quant_alpha, width, height,
- method, WEBP_FILTER_NONE, reduce_levels,
- effort_level, NULL, &bw, pic->stats);
- if (!ok) {
- VP8BitWriterWipeOut(&bw);
- goto End;
- }
-
- if (filter == WEBP_FILTER_FAST) { // Quick estimate of a second candidate?
- filter = EstimateBestFilter(quant_alpha, width, height, width);
- }
- // Stop?
- if (filter == WEBP_FILTER_NONE) {
- goto Ok;
- }
-
- filtered_alpha = (uint8_t*)malloc(data_size);
- ok = (filtered_alpha != NULL);
- if (!ok) {
- goto End;
+ VP8FiltersInit();
+ ok = ApplyFiltersAndEncode(quant_alpha, width, height, data_size, method,
+ filter, reduce_levels, effort_level, output,
+ output_size, pic->stats);
+ if (pic->stats != NULL) { // need stats?
+ pic->stats->coded_size += (int)(*output_size);
+ enc->sse_[3] = sse;
}
-
- // Try the other mode(s).
- {
- WebPAuxStats best_stats;
- size_t best_score = VP8BitWriterSize(&bw);
-
- memset(&best_stats, 0, sizeof(best_stats)); // prevent spurious warning
- if (pic->stats != NULL) best_stats = *pic->stats;
- for (test_filter = WEBP_FILTER_HORIZONTAL;
- ok && (test_filter <= WEBP_FILTER_GRADIENT);
- ++test_filter) {
- VP8BitWriter tmp_bw;
- if (filter != WEBP_FILTER_BEST && test_filter != filter) {
- continue;
- }
- ok = EncodeAlphaInternal(quant_alpha, width, height,
- method, test_filter, reduce_levels,
- effort_level, filtered_alpha, &tmp_bw,
- pic->stats);
- if (ok) {
- const size_t score = VP8BitWriterSize(&tmp_bw);
- if (score < best_score) {
- // swap bitwriter objects.
- VP8BitWriter tmp = tmp_bw;
- tmp_bw = bw;
- bw = tmp;
- best_score = score;
- if (pic->stats != NULL) best_stats = *pic->stats;
- }
- } else {
- VP8BitWriterWipeOut(&bw);
- }
- VP8BitWriterWipeOut(&tmp_bw);
- }
- if (pic->stats != NULL) *pic->stats = best_stats;
- }
- Ok:
- if (ok) {
- *output_size = VP8BitWriterSize(&bw);
- *output = VP8BitWriterBuf(&bw);
- if (pic->stats != NULL) { // need stats?
- pic->stats->coded_size += (int)(*output_size);
- enc->sse_[3] = sse;
- }
- }
- free(filtered_alpha);
}
- End:
- free(quant_alpha);
+
+ WebPSafeFree(quant_alpha);
return ok;
}
-
//------------------------------------------------------------------------------
// Main calls
+static int CompressAlphaJob(VP8Encoder* const enc, void* dummy) {
+ const WebPConfig* config = enc->config_;
+ uint8_t* alpha_data = NULL;
+ size_t alpha_size = 0;
+ const int effort_level = config->method; // maps to [0..6]
+ const WEBP_FILTER_TYPE filter =
+ (config->alpha_filtering == 0) ? WEBP_FILTER_NONE :
+ (config->alpha_filtering == 1) ? WEBP_FILTER_FAST :
+ WEBP_FILTER_BEST;
+ if (!EncodeAlpha(enc, config->alpha_quality, config->alpha_compression,
+ filter, effort_level, &alpha_data, &alpha_size)) {
+ return 0;
+ }
+ if (alpha_size != (uint32_t)alpha_size) { // Sanity check.
+ WebPSafeFree(alpha_data);
+ return 0;
+ }
+ enc->alpha_data_size_ = (uint32_t)alpha_size;
+ enc->alpha_data_ = alpha_data;
+ (void)dummy;
+ return 1;
+}
+
void VP8EncInitAlpha(VP8Encoder* const enc) {
+ WebPInitAlphaProcessing();
enc->has_alpha_ = WebPPictureHasTransparency(enc->pic_);
enc->alpha_data_ = NULL;
enc->alpha_data_size_ = 0;
+ if (enc->thread_level_ > 0) {
+ WebPWorker* const worker = &enc->alpha_worker_;
+ WebPGetWorkerInterface()->Init(worker);
+ worker->data1 = enc;
+ worker->data2 = NULL;
+ worker->hook = (WebPWorkerHook)CompressAlphaJob;
+ }
}
-int VP8EncFinishAlpha(VP8Encoder* const enc) {
+int VP8EncStartAlpha(VP8Encoder* const enc) {
if (enc->has_alpha_) {
- const WebPConfig* config = enc->config_;
- uint8_t* tmp_data = NULL;
- size_t tmp_size = 0;
- const int effort_level = config->method; // maps to [0..6]
- const WEBP_FILTER_TYPE filter =
- (config->alpha_filtering == 0) ? WEBP_FILTER_NONE :
- (config->alpha_filtering == 1) ? WEBP_FILTER_FAST :
- WEBP_FILTER_BEST;
-
- if (!EncodeAlpha(enc, config->alpha_quality, config->alpha_compression,
- filter, effort_level, &tmp_data, &tmp_size)) {
- return 0;
+ if (enc->thread_level_ > 0) {
+ WebPWorker* const worker = &enc->alpha_worker_;
+ // Makes sure worker is good to go.
+ if (!WebPGetWorkerInterface()->Reset(worker)) {
+ return 0;
+ }
+ WebPGetWorkerInterface()->Launch(worker);
+ return 1;
+ } else {
+ return CompressAlphaJob(enc, NULL); // just do the job right away
}
- if (tmp_size != (uint32_t)tmp_size) { // Sanity check.
- free(tmp_data);
- return 0;
+ }
+ return 1;
+}
+
+int VP8EncFinishAlpha(VP8Encoder* const enc) {
+ if (enc->has_alpha_) {
+ if (enc->thread_level_ > 0) {
+ WebPWorker* const worker = &enc->alpha_worker_;
+ if (!WebPGetWorkerInterface()->Sync(worker)) return 0; // error
}
- enc->alpha_data_size_ = (uint32_t)tmp_size;
- enc->alpha_data_ = tmp_data;
}
return WebPReportProgress(enc->pic_, enc->percent_ + 20, &enc->percent_);
}
-void VP8EncDeleteAlpha(VP8Encoder* const enc) {
- free(enc->alpha_data_);
+int VP8EncDeleteAlpha(VP8Encoder* const enc) {
+ int ok = 1;
+ if (enc->thread_level_ > 0) {
+ WebPWorker* const worker = &enc->alpha_worker_;
+ // finish anything left in flight
+ ok = WebPGetWorkerInterface()->Sync(worker);
+ // still need to end the worker, even if !ok
+ WebPGetWorkerInterface()->End(worker);
+ }
+ WebPSafeFree(enc->alpha_data_);
enc->alpha_data_ = NULL;
enc->alpha_data_size_ = 0;
enc->has_alpha_ = 0;
+ return ok;
}
-
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/enc/analysis.c b/drivers/webp/enc/analysis.c
index 22cfb492e7..b55128fd48 100644
--- a/drivers/webp/enc/analysis.c
+++ b/drivers/webp/enc/analysis.c
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Macroblock analysis
@@ -17,16 +19,8 @@
#include "./cost.h"
#include "../utils/utils.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
#define MAX_ITERS_K_MEANS 6
-static int ClipAlpha(int alpha) {
- return alpha < 0 ? 0 : alpha > 255 ? 255 : alpha;
-}
-
//------------------------------------------------------------------------------
// Smooth the segment map by replacing isolated block by the majority of its
// neighbours.
@@ -36,7 +30,7 @@ static void SmoothSegmentMap(VP8Encoder* const enc) {
const int w = enc->mb_w_;
const int h = enc->mb_h_;
const int majority_cnt_3_x_3_grid = 5;
- uint8_t* const tmp = (uint8_t*)WebPSafeMalloc((uint64_t)w * h, sizeof(*tmp));
+ uint8_t* const tmp = (uint8_t*)WebPSafeMalloc(w * h, sizeof(*tmp));
assert((uint64_t)(w * h) == (uint64_t)w * h); // no overflow, as per spec
if (tmp == NULL) return;
@@ -57,6 +51,7 @@ static void SmoothSegmentMap(VP8Encoder* const enc) {
for (n = 0; n < NUM_MB_SEGMENTS; ++n) {
if (cnt[n] >= majority_cnt_3_x_3_grid) {
majority_seg = n;
+ break;
}
}
tmp[x + y * w] = majority_seg;
@@ -68,54 +63,14 @@ static void SmoothSegmentMap(VP8Encoder* const enc) {
mb->segment_ = tmp[x + y * w];
}
}
- free(tmp);
+ WebPSafeFree(tmp);
}
//------------------------------------------------------------------------------
-// Finalize Segment probability based on the coding tree
-
-static int GetProba(int a, int b) {
- int proba;
- const int total = a + b;
- if (total == 0) return 255; // that's the default probability.
- proba = (255 * a + total / 2) / total;
- return proba;
-}
-
-static void SetSegmentProbas(VP8Encoder* const enc) {
- int p[NUM_MB_SEGMENTS] = { 0 };
- int n;
-
- for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) {
- const VP8MBInfo* const mb = &enc->mb_info_[n];
- p[mb->segment_]++;
- }
- if (enc->pic_->stats) {
- for (n = 0; n < NUM_MB_SEGMENTS; ++n) {
- enc->pic_->stats->segment_size[n] = p[n];
- }
- }
- if (enc->segment_hdr_.num_segments_ > 1) {
- uint8_t* const probas = enc->proba_.segments_;
- probas[0] = GetProba(p[0] + p[1], p[2] + p[3]);
- probas[1] = GetProba(p[0], p[1]);
- probas[2] = GetProba(p[2], p[3]);
-
- enc->segment_hdr_.update_map_ =
- (probas[0] != 255) || (probas[1] != 255) || (probas[2] != 255);
- enc->segment_hdr_.size_ =
- p[0] * (VP8BitCost(0, probas[0]) + VP8BitCost(0, probas[1])) +
- p[1] * (VP8BitCost(0, probas[0]) + VP8BitCost(1, probas[1])) +
- p[2] * (VP8BitCost(1, probas[0]) + VP8BitCost(0, probas[2])) +
- p[3] * (VP8BitCost(1, probas[0]) + VP8BitCost(1, probas[2]));
- } else {
- enc->segment_hdr_.update_map_ = 0;
- enc->segment_hdr_.size_ = 0;
- }
-}
+// set segment susceptibility alpha_ / beta_
static WEBP_INLINE int clip(int v, int m, int M) {
- return v < m ? m : v > M ? M : v;
+ return (v < m) ? m : (v > M) ? M : v;
}
static void SetSegmentAlphas(VP8Encoder* const enc,
@@ -142,28 +97,77 @@ static void SetSegmentAlphas(VP8Encoder* const enc,
}
//------------------------------------------------------------------------------
+// Compute susceptibility based on DCT-coeff histograms:
+// the higher, the "easier" the macroblock is to compress.
+
+#define MAX_ALPHA 255 // 8b of precision for susceptibilities.
+#define ALPHA_SCALE (2 * MAX_ALPHA) // scaling factor for alpha.
+#define DEFAULT_ALPHA (-1)
+#define IS_BETTER_ALPHA(alpha, best_alpha) ((alpha) > (best_alpha))
+
+static int FinalAlphaValue(int alpha) {
+ alpha = MAX_ALPHA - alpha;
+ return clip(alpha, 0, MAX_ALPHA);
+}
+
+static int GetAlpha(const VP8Histogram* const histo) {
+ // 'alpha' will later be clipped to [0..MAX_ALPHA] range, clamping outer
+ // values which happen to be mostly noise. This leaves the maximum precision
+ // for handling the useful small values which contribute most.
+ const int max_value = histo->max_value;
+ const int last_non_zero = histo->last_non_zero;
+ const int alpha =
+ (max_value > 1) ? ALPHA_SCALE * last_non_zero / max_value : 0;
+ return alpha;
+}
+
+static void InitHistogram(VP8Histogram* const histo) {
+ histo->max_value = 0;
+ histo->last_non_zero = 1;
+}
+
+static void MergeHistograms(const VP8Histogram* const in,
+ VP8Histogram* const out) {
+ if (in->max_value > out->max_value) {
+ out->max_value = in->max_value;
+ }
+ if (in->last_non_zero > out->last_non_zero) {
+ out->last_non_zero = in->last_non_zero;
+ }
+}
+
+//------------------------------------------------------------------------------
// Simplified k-Means, to assign Nb segments based on alpha-histogram
-static void AssignSegments(VP8Encoder* const enc, const int alphas[256]) {
- const int nb = enc->segment_hdr_.num_segments_;
+static void AssignSegments(VP8Encoder* const enc,
+ const int alphas[MAX_ALPHA + 1]) {
+ // 'num_segments_' is previously validated and <= NUM_MB_SEGMENTS, but an
+ // explicit check is needed to avoid spurious warning about 'n + 1' exceeding
+ // array bounds of 'centers' with some compilers (noticed with gcc-4.9).
+ const int nb = (enc->segment_hdr_.num_segments_ < NUM_MB_SEGMENTS) ?
+ enc->segment_hdr_.num_segments_ : NUM_MB_SEGMENTS;
int centers[NUM_MB_SEGMENTS];
int weighted_average = 0;
- int map[256];
+ int map[MAX_ALPHA + 1];
int a, n, k;
- int min_a = 0, max_a = 255, range_a;
+ int min_a = 0, max_a = MAX_ALPHA, range_a;
// 'int' type is ok for histo, and won't overflow
int accum[NUM_MB_SEGMENTS], dist_accum[NUM_MB_SEGMENTS];
+ assert(nb >= 1);
+ assert(nb <= NUM_MB_SEGMENTS);
+
// bracket the input
- for (n = 0; n < 256 && alphas[n] == 0; ++n) {}
+ for (n = 0; n <= MAX_ALPHA && alphas[n] == 0; ++n) {}
min_a = n;
- for (n = 255; n > min_a && alphas[n] == 0; --n) {}
+ for (n = MAX_ALPHA; n > min_a && alphas[n] == 0; --n) {}
max_a = n;
range_a = max_a - min_a;
// Spread initial centers evenly
- for (n = 1, k = 0; n < 2 * nb; n += 2) {
- centers[k++] = min_a + (n * range_a) / (2 * nb);
+ for (k = 0, n = 1; k < nb; ++k, n += 2) {
+ assert(n < 2 * nb);
+ centers[k] = min_a + (n * range_a) / (2 * nb);
}
for (k = 0; k < MAX_ITERS_K_MEANS; ++k) { // few iters are enough
@@ -178,7 +182,7 @@ static void AssignSegments(VP8Encoder* const enc, const int alphas[256]) {
n = 0; // track the nearest center for current 'a'
for (a = min_a; a <= max_a; ++a) {
if (alphas[a]) {
- while (n < nb - 1 && abs(a - centers[n + 1]) < abs(a - centers[n])) {
+ while (n + 1 < nb && abs(a - centers[n + 1]) < abs(a - centers[n])) {
n++;
}
map[a] = n;
@@ -210,7 +214,7 @@ static void AssignSegments(VP8Encoder* const enc, const int alphas[256]) {
VP8MBInfo* const mb = &enc->mb_info_[n];
const int alpha = mb->alpha_;
mb->segment_ = map[alpha];
- mb->alpha_ = centers[map[alpha]]; // just for the record.
+ mb->alpha_ = centers[map[alpha]]; // for the record.
}
if (nb > 1) {
@@ -218,7 +222,6 @@ static void AssignSegments(VP8Encoder* const enc, const int alphas[256]) {
if (smooth) SmoothSegmentMap(enc);
}
- SetSegmentProbas(enc); // Assign final proba
SetSegmentAlphas(enc, centers, weighted_average); // pick some alphas.
}
@@ -227,24 +230,30 @@ static void AssignSegments(VP8Encoder* const enc, const int alphas[256]) {
// susceptibility and set best modes for this macroblock.
// Segment assignment is done later.
-// Number of modes to inspect for alpha_ evaluation. For high-quality settings,
-// we don't need to test all the possible modes during the analysis phase.
+// Number of modes to inspect for alpha_ evaluation. We don't need to test all
+// the possible modes during the analysis phase: we risk falling into a local
+// optimum, or be subject to boundary effect
#define MAX_INTRA16_MODE 2
#define MAX_INTRA4_MODE 2
#define MAX_UV_MODE 2
static int MBAnalyzeBestIntra16Mode(VP8EncIterator* const it) {
- const int max_mode = (it->enc_->method_ >= 3) ? MAX_INTRA16_MODE : 4;
+ const int max_mode = MAX_INTRA16_MODE;
int mode;
- int best_alpha = -1;
+ int best_alpha = DEFAULT_ALPHA;
int best_mode = 0;
VP8MakeLuma16Preds(it);
for (mode = 0; mode < max_mode; ++mode) {
- const int alpha = VP8CollectHistogram(it->yuv_in_ + Y_OFF,
- it->yuv_p_ + VP8I16ModeOffsets[mode],
- 0, 16);
- if (alpha > best_alpha) {
+ VP8Histogram histo;
+ int alpha;
+
+ InitHistogram(&histo);
+ VP8CollectHistogram(it->yuv_in_ + Y_OFF_ENC,
+ it->yuv_p_ + VP8I16ModeOffsets[mode],
+ 0, 16, &histo);
+ alpha = GetAlpha(&histo);
+ if (IS_BETTER_ALPHA(alpha, best_alpha)) {
best_alpha = alpha;
best_mode = mode;
}
@@ -256,46 +265,62 @@ static int MBAnalyzeBestIntra16Mode(VP8EncIterator* const it) {
static int MBAnalyzeBestIntra4Mode(VP8EncIterator* const it,
int best_alpha) {
uint8_t modes[16];
- const int max_mode = (it->enc_->method_ >= 3) ? MAX_INTRA4_MODE : NUM_BMODES;
- int i4_alpha = 0;
+ const int max_mode = MAX_INTRA4_MODE;
+ int i4_alpha;
+ VP8Histogram total_histo;
+ int cur_histo = 0;
+ InitHistogram(&total_histo);
+
VP8IteratorStartI4(it);
do {
int mode;
- int best_mode_alpha = -1;
- const uint8_t* const src = it->yuv_in_ + Y_OFF + VP8Scan[it->i4_];
+ int best_mode_alpha = DEFAULT_ALPHA;
+ VP8Histogram histos[2];
+ const uint8_t* const src = it->yuv_in_ + Y_OFF_ENC + VP8Scan[it->i4_];
VP8MakeIntra4Preds(it);
for (mode = 0; mode < max_mode; ++mode) {
- const int alpha = VP8CollectHistogram(src,
- it->yuv_p_ + VP8I4ModeOffsets[mode],
- 0, 1);
- if (alpha > best_mode_alpha) {
+ int alpha;
+
+ InitHistogram(&histos[cur_histo]);
+ VP8CollectHistogram(src, it->yuv_p_ + VP8I4ModeOffsets[mode],
+ 0, 1, &histos[cur_histo]);
+ alpha = GetAlpha(&histos[cur_histo]);
+ if (IS_BETTER_ALPHA(alpha, best_mode_alpha)) {
best_mode_alpha = alpha;
modes[it->i4_] = mode;
+ cur_histo ^= 1; // keep track of best histo so far.
}
}
- i4_alpha += best_mode_alpha;
+ // accumulate best histogram
+ MergeHistograms(&histos[cur_histo ^ 1], &total_histo);
// Note: we reuse the original samples for predictors
- } while (VP8IteratorRotateI4(it, it->yuv_in_ + Y_OFF));
+ } while (VP8IteratorRotateI4(it, it->yuv_in_ + Y_OFF_ENC));
- if (i4_alpha > best_alpha) {
+ i4_alpha = GetAlpha(&total_histo);
+ if (IS_BETTER_ALPHA(i4_alpha, best_alpha)) {
VP8SetIntra4Mode(it, modes);
- best_alpha = ClipAlpha(i4_alpha);
+ best_alpha = i4_alpha;
}
return best_alpha;
}
static int MBAnalyzeBestUVMode(VP8EncIterator* const it) {
- int best_alpha = -1;
+ int best_alpha = DEFAULT_ALPHA;
int best_mode = 0;
- const int max_mode = (it->enc_->method_ >= 3) ? MAX_UV_MODE : 4;
+ const int max_mode = MAX_UV_MODE;
int mode;
+
VP8MakeChroma8Preds(it);
for (mode = 0; mode < max_mode; ++mode) {
- const int alpha = VP8CollectHistogram(it->yuv_in_ + U_OFF,
- it->yuv_p_ + VP8UVModeOffsets[mode],
- 16, 16 + 4 + 4);
- if (alpha > best_alpha) {
+ VP8Histogram histo;
+ int alpha;
+ InitHistogram(&histo);
+ VP8CollectHistogram(it->yuv_in_ + U_OFF_ENC,
+ it->yuv_p_ + VP8UVModeOffsets[mode],
+ 16, 16 + 4 + 4, &histo);
+ alpha = GetAlpha(&histo);
+ if (IS_BETTER_ALPHA(alpha, best_alpha)) {
best_alpha = alpha;
best_mode = mode;
}
@@ -305,7 +330,8 @@ static int MBAnalyzeBestUVMode(VP8EncIterator* const it) {
}
static void MBAnalyze(VP8EncIterator* const it,
- int alphas[256], int* const uv_alpha) {
+ int alphas[MAX_ALPHA + 1],
+ int* const alpha, int* const uv_alpha) {
const VP8Encoder* const enc = it->enc_;
int best_alpha, best_uv_alpha;
@@ -314,7 +340,7 @@ static void MBAnalyze(VP8EncIterator* const it,
VP8SetSegment(it, 0); // default segment, spec-wise.
best_alpha = MBAnalyzeBestIntra16Mode(it);
- if (enc->method_ != 3) {
+ if (enc->method_ >= 5) {
// We go and make a fast decision for intra4/intra16.
// It's usually not a good and definitive pick, but helps seeding the stats
// about level bit-cost.
@@ -324,10 +350,22 @@ static void MBAnalyze(VP8EncIterator* const it,
best_uv_alpha = MBAnalyzeBestUVMode(it);
// Final susceptibility mix
- best_alpha = (best_alpha + best_uv_alpha + 1) / 2;
+ best_alpha = (3 * best_alpha + best_uv_alpha + 2) >> 2;
+ best_alpha = FinalAlphaValue(best_alpha);
alphas[best_alpha]++;
+ it->mb_->alpha_ = best_alpha; // for later remapping.
+
+ // Accumulate for later complexity analysis.
+ *alpha += best_alpha; // mixed susceptibility (not just luma)
*uv_alpha += best_uv_alpha;
- it->mb_->alpha_ = best_alpha; // Informative only.
+}
+
+static void DefaultMBInfo(VP8MBInfo* const mb) {
+ mb->type_ = 1; // I16x16
+ mb->uv_mode_ = 0;
+ mb->skip_ = 0; // not skipped
+ mb->segment_ = 0; // default segment
+ mb->alpha_ = 0;
}
//------------------------------------------------------------------------------
@@ -340,25 +378,124 @@ static void MBAnalyze(VP8EncIterator* const it,
// and decide intra4/intra16, but that's usually almost always a bad choice at
// this stage.
-int VP8EncAnalyze(VP8Encoder* const enc) {
- int ok = 1;
- int alphas[256] = { 0 };
- VP8EncIterator it;
-
- VP8IteratorInit(enc, &it);
+static void ResetAllMBInfo(VP8Encoder* const enc) {
+ int n;
+ for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) {
+ DefaultMBInfo(&enc->mb_info_[n]);
+ }
+ // Default susceptibilities.
+ enc->dqm_[0].alpha_ = 0;
+ enc->dqm_[0].beta_ = 0;
+ // Note: we can't compute this alpha_ / uv_alpha_ -> set to default value.
+ enc->alpha_ = 0;
enc->uv_alpha_ = 0;
- do {
- VP8IteratorImport(&it);
- MBAnalyze(&it, alphas, &enc->uv_alpha_);
- ok = VP8IteratorProgress(&it, 20);
- // Let's pretend we have perfect lossless reconstruction.
- } while (ok && VP8IteratorNext(&it, it.yuv_in_));
- enc->uv_alpha_ /= enc->mb_w_ * enc->mb_h_;
- if (ok) AssignSegments(enc, alphas);
+ WebPReportProgress(enc->pic_, enc->percent_ + 20, &enc->percent_);
+}
+
+// struct used to collect job result
+typedef struct {
+ WebPWorker worker;
+ int alphas[MAX_ALPHA + 1];
+ int alpha, uv_alpha;
+ VP8EncIterator it;
+ int delta_progress;
+} SegmentJob;
+// main work call
+static int DoSegmentsJob(SegmentJob* const job, VP8EncIterator* const it) {
+ int ok = 1;
+ if (!VP8IteratorIsDone(it)) {
+ uint8_t tmp[32 + WEBP_ALIGN_CST];
+ uint8_t* const scratch = (uint8_t*)WEBP_ALIGN(tmp);
+ do {
+ // Let's pretend we have perfect lossless reconstruction.
+ VP8IteratorImport(it, scratch);
+ MBAnalyze(it, job->alphas, &job->alpha, &job->uv_alpha);
+ ok = VP8IteratorProgress(it, job->delta_progress);
+ } while (ok && VP8IteratorNext(it));
+ }
return ok;
}
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
+static void MergeJobs(const SegmentJob* const src, SegmentJob* const dst) {
+ int i;
+ for (i = 0; i <= MAX_ALPHA; ++i) dst->alphas[i] += src->alphas[i];
+ dst->alpha += src->alpha;
+ dst->uv_alpha += src->uv_alpha;
+}
+
+// initialize the job struct with some TODOs
+static void InitSegmentJob(VP8Encoder* const enc, SegmentJob* const job,
+ int start_row, int end_row) {
+ WebPGetWorkerInterface()->Init(&job->worker);
+ job->worker.data1 = job;
+ job->worker.data2 = &job->it;
+ job->worker.hook = (WebPWorkerHook)DoSegmentsJob;
+ VP8IteratorInit(enc, &job->it);
+ VP8IteratorSetRow(&job->it, start_row);
+ VP8IteratorSetCountDown(&job->it, (end_row - start_row) * enc->mb_w_);
+ memset(job->alphas, 0, sizeof(job->alphas));
+ job->alpha = 0;
+ job->uv_alpha = 0;
+ // only one of both jobs can record the progress, since we don't
+ // expect the user's hook to be multi-thread safe
+ job->delta_progress = (start_row == 0) ? 20 : 0;
+}
+
+// main entry point
+int VP8EncAnalyze(VP8Encoder* const enc) {
+ int ok = 1;
+ const int do_segments =
+ enc->config_->emulate_jpeg_size || // We need the complexity evaluation.
+ (enc->segment_hdr_.num_segments_ > 1) ||
+ (enc->method_ == 0); // for method 0, we need preds_[] to be filled.
+ if (do_segments) {
+ const int last_row = enc->mb_h_;
+ // We give a little more than a half work to the main thread.
+ const int split_row = (9 * last_row + 15) >> 4;
+ const int total_mb = last_row * enc->mb_w_;
+#ifdef WEBP_USE_THREAD
+ const int kMinSplitRow = 2; // minimal rows needed for mt to be worth it
+ const int do_mt = (enc->thread_level_ > 0) && (split_row >= kMinSplitRow);
+#else
+ const int do_mt = 0;
#endif
+ const WebPWorkerInterface* const worker_interface =
+ WebPGetWorkerInterface();
+ SegmentJob main_job;
+ if (do_mt) {
+ SegmentJob side_job;
+ // Note the use of '&' instead of '&&' because we must call the functions
+ // no matter what.
+ InitSegmentJob(enc, &main_job, 0, split_row);
+ InitSegmentJob(enc, &side_job, split_row, last_row);
+ // we don't need to call Reset() on main_job.worker, since we're calling
+ // WebPWorkerExecute() on it
+ ok &= worker_interface->Reset(&side_job.worker);
+ // launch the two jobs in parallel
+ if (ok) {
+ worker_interface->Launch(&side_job.worker);
+ worker_interface->Execute(&main_job.worker);
+ ok &= worker_interface->Sync(&side_job.worker);
+ ok &= worker_interface->Sync(&main_job.worker);
+ }
+ worker_interface->End(&side_job.worker);
+ if (ok) MergeJobs(&side_job, &main_job); // merge results together
+ } else {
+ // Even for single-thread case, we use the generic Worker tools.
+ InitSegmentJob(enc, &main_job, 0, last_row);
+ worker_interface->Execute(&main_job.worker);
+ ok &= worker_interface->Sync(&main_job.worker);
+ }
+ worker_interface->End(&main_job.worker);
+ if (ok) {
+ enc->alpha_ = main_job.alpha / total_mb;
+ enc->uv_alpha_ = main_job.uv_alpha / total_mb;
+ AssignSegments(enc, main_job.alphas);
+ }
+ } else { // Use only one default segment.
+ ResetAllMBInfo(enc);
+ }
+ return ok;
+}
+
diff --git a/drivers/webp/enc/backward_references.c b/drivers/webp/enc/backward_references.c
index b8c8ece806..049125e521 100644
--- a/drivers/webp/enc/backward_references.c
+++ b/drivers/webp/enc/backward_references.c
@@ -1,8 +1,10 @@
// Copyright 2012 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Author: Jyrki Alakuijala (jyrki@google.com)
@@ -10,7 +12,6 @@
#include <assert.h>
#include <math.h>
-#include <stdio.h>
#include "./backward_references.h"
#include "./histogram.h"
@@ -20,9 +21,9 @@
#define VALUES_IN_BYTE 256
-#define HASH_BITS 18
-#define HASH_SIZE (1 << HASH_BITS)
-#define HASH_MULTIPLIER (0xc6a4a7935bd1e995ULL)
+#define MIN_BLOCK_SIZE 256 // minimum block size for backward references
+
+#define MAX_ENTROPY (1e30f)
// 1M window (4M bytes) minus 120 special codes for short distances.
#define WINDOW_SIZE ((1 << 20) - 120)
@@ -31,14 +32,6 @@
#define MIN_LENGTH 2
#define MAX_LENGTH 4096
-typedef struct {
- // Stores the most recently added position with the given hash value.
- int32_t hash_to_first_index_[HASH_SIZE];
- // chain_[pos] stores the previous position with the same hash value
- // for every pixel in the image.
- int32_t* chain_;
-} HashChain;
-
// -----------------------------------------------------------------------------
static const uint8_t plane_to_code_lut[128] = {
@@ -65,145 +58,275 @@ static int DistanceToPlaneCode(int xsize, int dist) {
static WEBP_INLINE int FindMatchLength(const uint32_t* const array1,
const uint32_t* const array2,
- const int max_limit) {
+ int best_len_match,
+ int max_limit) {
+#if !defined(__x86_64__)
+ // TODO(vrabaud): Compare on other architectures.
int match_len = 0;
+ // Before 'expensive' linear match, check if the two arrays match at the
+ // current best length index.
+ if (array1[best_len_match] != array2[best_len_match]) return 0;
while (match_len < max_limit && array1[match_len] == array2[match_len]) {
++match_len;
}
return match_len;
+#else
+ const uint32_t* array1_32 = array1;
+ const uint32_t* array2_32 = array2;
+ // max value is aligned to (uint64_t*) array1
+ const uint32_t* const array1_32_max = array1 + (max_limit & ~1);
+
+ // Before 'expensive' linear match, check if the two arrays match at the
+ // current best length index.
+ if (array1[best_len_match] != array2[best_len_match]) return 0;
+
+ // TODO(vrabaud): add __predict_true on bound checking?
+ while (array1_32 < array1_32_max) {
+ if (*(uint64_t*)array1_32 == *(uint64_t*)array2_32) {
+ array1_32 += 2;
+ array2_32 += 2;
+ } else {
+ // if the uint32_t pointed to are the same, then the following ones have
+ // to be different
+ return (array1_32 - array1) + (*array1_32 == *array2_32);
+ }
+ }
+
+ // Deal with the potential last uint32_t.
+ if ((max_limit & 1) && (*array1_32 != *array2_32)) return max_limit - 1;
+ return max_limit;
+#endif
}
// -----------------------------------------------------------------------------
// VP8LBackwardRefs
-void VP8LInitBackwardRefs(VP8LBackwardRefs* const refs) {
- if (refs != NULL) {
- refs->refs = NULL;
- refs->size = 0;
- refs->max_size = 0;
+struct PixOrCopyBlock {
+ PixOrCopyBlock* next_; // next block (or NULL)
+ PixOrCopy* start_; // data start
+ int size_; // currently used size
+};
+
+static void ClearBackwardRefs(VP8LBackwardRefs* const refs) {
+ assert(refs != NULL);
+ if (refs->tail_ != NULL) {
+ *refs->tail_ = refs->free_blocks_; // recycle all blocks at once
}
+ refs->free_blocks_ = refs->refs_;
+ refs->tail_ = &refs->refs_;
+ refs->last_block_ = NULL;
+ refs->refs_ = NULL;
}
-void VP8LClearBackwardRefs(VP8LBackwardRefs* const refs) {
- if (refs != NULL) {
- free(refs->refs);
- VP8LInitBackwardRefs(refs);
+void VP8LBackwardRefsClear(VP8LBackwardRefs* const refs) {
+ assert(refs != NULL);
+ ClearBackwardRefs(refs);
+ while (refs->free_blocks_ != NULL) {
+ PixOrCopyBlock* const next = refs->free_blocks_->next_;
+ WebPSafeFree(refs->free_blocks_);
+ refs->free_blocks_ = next;
}
}
-int VP8LBackwardRefsAlloc(VP8LBackwardRefs* const refs, int max_size) {
+void VP8LBackwardRefsInit(VP8LBackwardRefs* const refs, int block_size) {
assert(refs != NULL);
- refs->size = 0;
- refs->max_size = 0;
- refs->refs = (PixOrCopy*)WebPSafeMalloc((uint64_t)max_size,
- sizeof(*refs->refs));
- if (refs->refs == NULL) return 0;
- refs->max_size = max_size;
+ memset(refs, 0, sizeof(*refs));
+ refs->tail_ = &refs->refs_;
+ refs->block_size_ =
+ (block_size < MIN_BLOCK_SIZE) ? MIN_BLOCK_SIZE : block_size;
+}
+
+VP8LRefsCursor VP8LRefsCursorInit(const VP8LBackwardRefs* const refs) {
+ VP8LRefsCursor c;
+ c.cur_block_ = refs->refs_;
+ if (refs->refs_ != NULL) {
+ c.cur_pos = c.cur_block_->start_;
+ c.last_pos_ = c.cur_pos + c.cur_block_->size_;
+ } else {
+ c.cur_pos = NULL;
+ c.last_pos_ = NULL;
+ }
+ return c;
+}
+
+void VP8LRefsCursorNextBlock(VP8LRefsCursor* const c) {
+ PixOrCopyBlock* const b = c->cur_block_->next_;
+ c->cur_pos = (b == NULL) ? NULL : b->start_;
+ c->last_pos_ = (b == NULL) ? NULL : b->start_ + b->size_;
+ c->cur_block_ = b;
+}
+
+// Create a new block, either from the free list or allocated
+static PixOrCopyBlock* BackwardRefsNewBlock(VP8LBackwardRefs* const refs) {
+ PixOrCopyBlock* b = refs->free_blocks_;
+ if (b == NULL) { // allocate new memory chunk
+ const size_t total_size =
+ sizeof(*b) + refs->block_size_ * sizeof(*b->start_);
+ b = (PixOrCopyBlock*)WebPSafeMalloc(1ULL, total_size);
+ if (b == NULL) {
+ refs->error_ |= 1;
+ return NULL;
+ }
+ b->start_ = (PixOrCopy*)((uint8_t*)b + sizeof(*b)); // not always aligned
+ } else { // recycle from free-list
+ refs->free_blocks_ = b->next_;
+ }
+ *refs->tail_ = b;
+ refs->tail_ = &b->next_;
+ refs->last_block_ = b;
+ b->next_ = NULL;
+ b->size_ = 0;
+ return b;
+}
+
+static WEBP_INLINE void BackwardRefsCursorAdd(VP8LBackwardRefs* const refs,
+ const PixOrCopy v) {
+ PixOrCopyBlock* b = refs->last_block_;
+ if (b == NULL || b->size_ == refs->block_size_) {
+ b = BackwardRefsNewBlock(refs);
+ if (b == NULL) return; // refs->error_ is set
+ }
+ b->start_[b->size_++] = v;
+}
+
+int VP8LBackwardRefsCopy(const VP8LBackwardRefs* const src,
+ VP8LBackwardRefs* const dst) {
+ const PixOrCopyBlock* b = src->refs_;
+ ClearBackwardRefs(dst);
+ assert(src->block_size_ == dst->block_size_);
+ while (b != NULL) {
+ PixOrCopyBlock* const new_b = BackwardRefsNewBlock(dst);
+ if (new_b == NULL) return 0; // dst->error_ is set
+ memcpy(new_b->start_, b->start_, b->size_ * sizeof(*b->start_));
+ new_b->size_ = b->size_;
+ b = b->next_;
+ }
return 1;
}
// -----------------------------------------------------------------------------
// Hash chains
-static WEBP_INLINE uint64_t GetPixPairHash64(const uint32_t* const argb) {
- uint64_t key = ((uint64_t)(argb[1]) << 32) | argb[0];
- key = (key * HASH_MULTIPLIER) >> (64 - HASH_BITS);
- return key;
-}
-
-static int HashChainInit(HashChain* const p, int size) {
+// initialize as empty
+static void HashChainReset(VP8LHashChain* const p) {
int i;
- p->chain_ = (int*)WebPSafeMalloc((uint64_t)size, sizeof(*p->chain_));
- if (p->chain_ == NULL) {
- return 0;
- }
- for (i = 0; i < size; ++i) {
+ assert(p != NULL);
+ for (i = 0; i < p->size_; ++i) {
p->chain_[i] = -1;
}
for (i = 0; i < HASH_SIZE; ++i) {
p->hash_to_first_index_[i] = -1;
}
+}
+
+int VP8LHashChainInit(VP8LHashChain* const p, int size) {
+ assert(p->size_ == 0);
+ assert(p->chain_ == NULL);
+ assert(size > 0);
+ p->chain_ = (int*)WebPSafeMalloc(size, sizeof(*p->chain_));
+ if (p->chain_ == NULL) return 0;
+ p->size_ = size;
+ HashChainReset(p);
return 1;
}
-static void HashChainDelete(HashChain* const p) {
- if (p != NULL) {
- free(p->chain_);
- free(p);
- }
+void VP8LHashChainClear(VP8LHashChain* const p) {
+ assert(p != NULL);
+ WebPSafeFree(p->chain_);
+ p->size_ = 0;
+ p->chain_ = NULL;
+}
+
+// -----------------------------------------------------------------------------
+
+#define HASH_MULTIPLIER_HI (0xc6a4a793U)
+#define HASH_MULTIPLIER_LO (0x5bd1e996U)
+
+static WEBP_INLINE uint32_t GetPixPairHash64(const uint32_t* const argb) {
+ uint32_t key;
+ key = argb[1] * HASH_MULTIPLIER_HI;
+ key += argb[0] * HASH_MULTIPLIER_LO;
+ key = key >> (32 - HASH_BITS);
+ return key;
}
// Insertion of two pixels at a time.
-static void HashChainInsert(HashChain* const p,
+static void HashChainInsert(VP8LHashChain* const p,
const uint32_t* const argb, int pos) {
- const uint64_t hash_code = GetPixPairHash64(argb);
+ const uint32_t hash_code = GetPixPairHash64(argb);
p->chain_[pos] = p->hash_to_first_index_[hash_code];
p->hash_to_first_index_[hash_code] = pos;
}
-static int HashChainFindCopy(const HashChain* const p,
- int quality, int index, int xsize,
- const uint32_t* const argb, int maxlen,
+// Returns the maximum number of hash chain lookups to do for a
+// given compression quality. Return value in range [6, 86].
+static int GetMaxItersForQuality(int quality, int low_effort) {
+ return (low_effort ? 6 : 8) + (quality * quality) / 128;
+}
+
+static int GetWindowSizeForHashChain(int quality, int xsize) {
+ const int max_window_size = (quality > 75) ? WINDOW_SIZE
+ : (quality > 50) ? (xsize << 8)
+ : (quality > 25) ? (xsize << 6)
+ : (xsize << 4);
+ assert(xsize > 0);
+ return (max_window_size > WINDOW_SIZE) ? WINDOW_SIZE : max_window_size;
+}
+
+static WEBP_INLINE int MaxFindCopyLength(int len) {
+ return (len < MAX_LENGTH) ? len : MAX_LENGTH;
+}
+
+static void HashChainFindOffset(const VP8LHashChain* const p, int base_position,
+ const uint32_t* const argb, int len,
+ int window_size, int* const distance_ptr) {
+ const uint32_t* const argb_start = argb + base_position;
+ const int min_pos =
+ (base_position > window_size) ? base_position - window_size : 0;
+ int pos;
+ assert(len <= MAX_LENGTH);
+ for (pos = p->hash_to_first_index_[GetPixPairHash64(argb_start)];
+ pos >= min_pos;
+ pos = p->chain_[pos]) {
+ const int curr_length =
+ FindMatchLength(argb + pos, argb_start, len - 1, len);
+ if (curr_length == len) break;
+ }
+ *distance_ptr = base_position - pos;
+}
+
+static int HashChainFindCopy(const VP8LHashChain* const p,
+ int base_position,
+ const uint32_t* const argb, int max_len,
+ int window_size, int iter_max,
int* const distance_ptr,
int* const length_ptr) {
- const uint64_t hash_code = GetPixPairHash64(&argb[index]);
- int prev_length = 0;
- int64_t best_val = 0;
+ const uint32_t* const argb_start = argb + base_position;
+ int iter = iter_max;
int best_length = 0;
int best_distance = 0;
- const uint32_t* const argb_start = argb + index;
- const int iter_min_mult = (quality < 50) ? 2 : (quality < 75) ? 4 : 8;
- const int iter_min = -quality * iter_min_mult;
- int iter_cnt = 10 + (quality >> 1);
- const int min_pos = (index > WINDOW_SIZE) ? index - WINDOW_SIZE : 0;
+ const int min_pos =
+ (base_position > window_size) ? base_position - window_size : 0;
int pos;
-
- assert(xsize > 0);
- for (pos = p->hash_to_first_index_[hash_code];
+ int length_max = 256;
+ if (max_len < length_max) {
+ length_max = max_len;
+ }
+ for (pos = p->hash_to_first_index_[GetPixPairHash64(argb_start)];
pos >= min_pos;
pos = p->chain_[pos]) {
- int64_t val;
int curr_length;
- if (iter_cnt < 0) {
- if (iter_cnt < iter_min || best_val >= 0xff0000) {
- break;
- }
- }
- --iter_cnt;
- if (best_length != 0 &&
- argb[pos + best_length - 1] != argb_start[best_length - 1]) {
- continue;
- }
- curr_length = FindMatchLength(argb + pos, argb_start, maxlen);
- if (curr_length < prev_length) {
- continue;
+ int distance;
+ if (--iter < 0) {
+ break;
}
- val = 65536 * curr_length;
- // Favoring 2d locality here gives savings for certain images.
- if (index - pos < 9 * xsize) {
- const int y = (index - pos) / xsize;
- int x = (index - pos) % xsize;
- if (x > xsize / 2) {
- x = xsize - x;
- }
- if (x <= 7 && x >= -8) {
- val -= y * y + x * x;
- } else {
- val -= 9 * 9 + 9 * 9;
- }
- } else {
- val -= 9 * 9 + 9 * 9;
- }
- if (best_val < val) {
- prev_length = curr_length;
- best_val = val;
+
+ curr_length = FindMatchLength(argb + pos, argb_start, best_length, max_len);
+ if (best_length < curr_length) {
+ distance = base_position - pos;
best_length = curr_length;
- best_distance = index - pos;
- if (curr_length >= MAX_LENGTH) {
- break;
- }
- if ((best_distance == 1 || best_distance == xsize) &&
- best_length >= 128) {
+ best_distance = distance;
+ if (curr_length >= length_max) {
break;
}
}
@@ -213,140 +336,153 @@ static int HashChainFindCopy(const HashChain* const p,
return (best_length >= MIN_LENGTH);
}
-static WEBP_INLINE void PushBackCopy(VP8LBackwardRefs* const refs, int length) {
- int size = refs->size;
- while (length >= MAX_LENGTH) {
- refs->refs[size++] = PixOrCopyCreateCopy(1, MAX_LENGTH);
- length -= MAX_LENGTH;
- }
- if (length > 0) {
- refs->refs[size++] = PixOrCopyCreateCopy(1, length);
+static WEBP_INLINE void AddSingleLiteral(uint32_t pixel, int use_color_cache,
+ VP8LColorCache* const hashers,
+ VP8LBackwardRefs* const refs) {
+ PixOrCopy v;
+ if (use_color_cache) {
+ const uint32_t key = VP8LColorCacheGetIndex(hashers, pixel);
+ if (VP8LColorCacheLookup(hashers, key) == pixel) {
+ v = PixOrCopyCreateCacheIdx(key);
+ } else {
+ v = PixOrCopyCreateLiteral(pixel);
+ VP8LColorCacheSet(hashers, key, pixel);
+ }
+ } else {
+ v = PixOrCopyCreateLiteral(pixel);
}
- refs->size = size;
+ BackwardRefsCursorAdd(refs, v);
}
-static void BackwardReferencesRle(int xsize, int ysize,
- const uint32_t* const argb,
- VP8LBackwardRefs* const refs) {
+static int BackwardReferencesRle(int xsize, int ysize,
+ const uint32_t* const argb,
+ int cache_bits, VP8LBackwardRefs* const refs) {
const int pix_count = xsize * ysize;
- int match_len = 0;
- int i;
- refs->size = 0;
- PushBackCopy(refs, match_len); // i=0 case
- refs->refs[refs->size++] = PixOrCopyCreateLiteral(argb[0]);
- for (i = 1; i < pix_count; ++i) {
- if (argb[i] == argb[i - 1]) {
- ++match_len;
+ int i, k;
+ const int use_color_cache = (cache_bits > 0);
+ VP8LColorCache hashers;
+
+ if (use_color_cache && !VP8LColorCacheInit(&hashers, cache_bits)) {
+ return 0;
+ }
+ ClearBackwardRefs(refs);
+ // Add first pixel as literal.
+ AddSingleLiteral(argb[0], use_color_cache, &hashers, refs);
+ i = 1;
+ while (i < pix_count) {
+ const int max_len = MaxFindCopyLength(pix_count - i);
+ const int kMinLength = 4;
+ const int rle_len = FindMatchLength(argb + i, argb + i - 1, 0, max_len);
+ const int prev_row_len = (i < xsize) ? 0 :
+ FindMatchLength(argb + i, argb + i - xsize, 0, max_len);
+ if (rle_len >= prev_row_len && rle_len >= kMinLength) {
+ BackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(1, rle_len));
+ // We don't need to update the color cache here since it is always the
+ // same pixel being copied, and that does not change the color cache
+ // state.
+ i += rle_len;
+ } else if (prev_row_len >= kMinLength) {
+ BackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(xsize, prev_row_len));
+ if (use_color_cache) {
+ for (k = 0; k < prev_row_len; ++k) {
+ VP8LColorCacheInsert(&hashers, argb[i + k]);
+ }
+ }
+ i += prev_row_len;
} else {
- PushBackCopy(refs, match_len);
- match_len = 0;
- refs->refs[refs->size++] = PixOrCopyCreateLiteral(argb[i]);
+ AddSingleLiteral(argb[i], use_color_cache, &hashers, refs);
+ i++;
}
}
- PushBackCopy(refs, match_len);
+ if (use_color_cache) VP8LColorCacheClear(&hashers);
+ return !refs->error_;
}
-static int BackwardReferencesHashChain(int xsize, int ysize,
- const uint32_t* const argb,
- int cache_bits, int quality,
- VP8LBackwardRefs* const refs) {
+static int BackwardReferencesLz77(int xsize, int ysize,
+ const uint32_t* const argb, int cache_bits,
+ int quality, int low_effort,
+ VP8LHashChain* const hash_chain,
+ VP8LBackwardRefs* const refs) {
int i;
int ok = 0;
int cc_init = 0;
const int use_color_cache = (cache_bits > 0);
const int pix_count = xsize * ysize;
- HashChain* const hash_chain = (HashChain*)malloc(sizeof(*hash_chain));
VP8LColorCache hashers;
+ int iter_max = GetMaxItersForQuality(quality, low_effort);
+ const int window_size = GetWindowSizeForHashChain(quality, xsize);
+ int min_matches = 32;
- if (hash_chain == NULL) return 0;
if (use_color_cache) {
cc_init = VP8LColorCacheInit(&hashers, cache_bits);
if (!cc_init) goto Error;
}
-
- if (!HashChainInit(hash_chain, pix_count)) goto Error;
-
- refs->size = 0;
- for (i = 0; i < pix_count; ) {
+ ClearBackwardRefs(refs);
+ HashChainReset(hash_chain);
+ for (i = 0; i < pix_count - 2; ) {
// Alternative#1: Code the pixels starting at 'i' using backward reference.
int offset = 0;
int len = 0;
- if (i < pix_count - 1) { // FindCopy(i,..) reads pixels at [i] and [i + 1].
- int maxlen = pix_count - i;
- if (maxlen > MAX_LENGTH) {
- maxlen = MAX_LENGTH;
- }
- HashChainFindCopy(hash_chain, quality, i, xsize, argb, maxlen,
- &offset, &len);
- }
- if (len >= MIN_LENGTH) {
- // Alternative#2: Insert the pixel at 'i' as literal, and code the
- // pixels starting at 'i + 1' using backward reference.
+ const int max_len = MaxFindCopyLength(pix_count - i);
+ HashChainFindCopy(hash_chain, i, argb, max_len, window_size,
+ iter_max, &offset, &len);
+ if (len > MIN_LENGTH || (len == MIN_LENGTH && offset <= 512)) {
int offset2 = 0;
int len2 = 0;
int k;
+ min_matches = 8;
HashChainInsert(hash_chain, &argb[i], i);
- if (i < pix_count - 2) { // FindCopy(i+1,..) reads [i + 1] and [i + 2].
- int maxlen = pix_count - (i + 1);
- if (maxlen > MAX_LENGTH) {
- maxlen = MAX_LENGTH;
- }
- HashChainFindCopy(hash_chain, quality,
- i + 1, xsize, argb, maxlen, &offset2, &len2);
+ if ((len < (max_len >> 2)) && !low_effort) {
+ // Evaluate Alternative#2: Insert the pixel at 'i' as literal, and code
+ // the pixels starting at 'i + 1' using backward reference.
+ HashChainFindCopy(hash_chain, i + 1, argb, max_len - 1,
+ window_size, iter_max, &offset2,
+ &len2);
if (len2 > len + 1) {
- const uint32_t pixel = argb[i];
- // Alternative#2 is a better match. So push pixel at 'i' as literal.
- if (use_color_cache && VP8LColorCacheContains(&hashers, pixel)) {
- const int ix = VP8LColorCacheGetIndex(&hashers, pixel);
- refs->refs[refs->size] = PixOrCopyCreateCacheIdx(ix);
- } else {
- refs->refs[refs->size] = PixOrCopyCreateLiteral(pixel);
- }
- ++refs->size;
- if (use_color_cache) VP8LColorCacheInsert(&hashers, pixel);
+ AddSingleLiteral(argb[i], use_color_cache, &hashers, refs);
i++; // Backward reference to be done for next pixel.
len = len2;
offset = offset2;
}
}
- if (len >= MAX_LENGTH) {
- len = MAX_LENGTH - 1;
- }
- refs->refs[refs->size++] = PixOrCopyCreateCopy(offset, len);
+ BackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(offset, len));
if (use_color_cache) {
for (k = 0; k < len; ++k) {
VP8LColorCacheInsert(&hashers, argb[i + k]);
}
}
// Add to the hash_chain (but cannot add the last pixel).
- {
+ if (offset >= 3 && offset != xsize) {
const int last = (len < pix_count - 1 - i) ? len : pix_count - 1 - i;
- for (k = 1; k < last; ++k) {
+ for (k = 2; k < last - 8; k += 2) {
+ HashChainInsert(hash_chain, &argb[i + k], i + k);
+ }
+ for (; k < last; ++k) {
HashChainInsert(hash_chain, &argb[i + k], i + k);
}
}
i += len;
} else {
- const uint32_t pixel = argb[i];
- if (use_color_cache && VP8LColorCacheContains(&hashers, pixel)) {
- // push pixel as a PixOrCopyCreateCacheIdx pixel
- const int ix = VP8LColorCacheGetIndex(&hashers, pixel);
- refs->refs[refs->size] = PixOrCopyCreateCacheIdx(ix);
- } else {
- refs->refs[refs->size] = PixOrCopyCreateLiteral(pixel);
- }
- ++refs->size;
- if (use_color_cache) VP8LColorCacheInsert(&hashers, pixel);
- if (i + 1 < pix_count) {
+ AddSingleLiteral(argb[i], use_color_cache, &hashers, refs);
+ HashChainInsert(hash_chain, &argb[i], i);
+ ++i;
+ --min_matches;
+ if (min_matches <= 0) {
+ AddSingleLiteral(argb[i], use_color_cache, &hashers, refs);
HashChainInsert(hash_chain, &argb[i], i);
+ ++i;
}
- ++i;
}
}
- ok = 1;
-Error:
+ while (i < pix_count) {
+ // Handle the last pixel(s).
+ AddSingleLiteral(argb[i], use_color_cache, &hashers, refs);
+ ++i;
+ }
+
+ ok = !refs->error_;
+ Error:
if (cc_init) VP8LColorCacheClear(&hashers);
- HashChainDelete(hash_chain);
return ok;
}
@@ -355,18 +491,19 @@ Error:
typedef struct {
double alpha_[VALUES_IN_BYTE];
double red_[VALUES_IN_BYTE];
- double literal_[PIX_OR_COPY_CODES_MAX];
double blue_[VALUES_IN_BYTE];
double distance_[NUM_DISTANCE_CODES];
+ double* literal_;
} CostModel;
static int BackwardReferencesTraceBackwards(
- int xsize, int ysize, int recursive_cost_model,
- const uint32_t* const argb, int cache_bits, VP8LBackwardRefs* const refs);
+ int xsize, int ysize, const uint32_t* const argb, int quality,
+ int cache_bits, VP8LHashChain* const hash_chain,
+ VP8LBackwardRefs* const refs);
static void ConvertPopulationCountTableToBitEstimates(
- int num_symbols, const int population_counts[], double output[]) {
- int sum = 0;
+ int num_symbols, const uint32_t population_counts[], double output[]) {
+ uint32_t sum = 0;
int nonzeros = 0;
int i;
for (i = 0; i < num_symbols; ++i) {
@@ -385,42 +522,29 @@ static void ConvertPopulationCountTableToBitEstimates(
}
}
-static int CostModelBuild(CostModel* const m, int xsize, int ysize,
- int recursion_level, const uint32_t* const argb,
- int cache_bits) {
+static int CostModelBuild(CostModel* const m, int cache_bits,
+ VP8LBackwardRefs* const refs) {
int ok = 0;
- VP8LHistogram histo;
- VP8LBackwardRefs refs;
- const int quality = 100;
+ VP8LHistogram* const histo = VP8LAllocateHistogram(cache_bits);
+ if (histo == NULL) goto Error;
- if (!VP8LBackwardRefsAlloc(&refs, xsize * ysize)) goto Error;
+ VP8LHistogramCreate(histo, refs, cache_bits);
- if (recursion_level > 0) {
- if (!BackwardReferencesTraceBackwards(xsize, ysize, recursion_level - 1,
- argb, cache_bits, &refs)) {
- goto Error;
- }
- } else {
- if (!BackwardReferencesHashChain(xsize, ysize, argb, cache_bits, quality,
- &refs)) {
- goto Error;
- }
- }
- VP8LHistogramCreate(&histo, &refs, cache_bits);
ConvertPopulationCountTableToBitEstimates(
- VP8LHistogramNumCodes(&histo), histo.literal_, m->literal_);
+ VP8LHistogramNumCodes(histo->palette_code_bits_),
+ histo->literal_, m->literal_);
ConvertPopulationCountTableToBitEstimates(
- VALUES_IN_BYTE, histo.red_, m->red_);
+ VALUES_IN_BYTE, histo->red_, m->red_);
ConvertPopulationCountTableToBitEstimates(
- VALUES_IN_BYTE, histo.blue_, m->blue_);
+ VALUES_IN_BYTE, histo->blue_, m->blue_);
ConvertPopulationCountTableToBitEstimates(
- VALUES_IN_BYTE, histo.alpha_, m->alpha_);
+ VALUES_IN_BYTE, histo->alpha_, m->alpha_);
ConvertPopulationCountTableToBitEstimates(
- NUM_DISTANCE_CODES, histo.distance_, m->distance_);
+ NUM_DISTANCE_CODES, histo->distance_, m->distance_);
ok = 1;
Error:
- VP8LClearBackwardRefs(&refs);
+ VP8LFreeHistogram(histo);
return ok;
}
@@ -438,203 +562,211 @@ static WEBP_INLINE double GetCacheCost(const CostModel* const m, uint32_t idx) {
static WEBP_INLINE double GetLengthCost(const CostModel* const m,
uint32_t length) {
- int code, extra_bits_count, extra_bits_value;
- PrefixEncode(length, &code, &extra_bits_count, &extra_bits_value);
- return m->literal_[VALUES_IN_BYTE + code] + extra_bits_count;
+ int code, extra_bits;
+ VP8LPrefixEncodeBits(length, &code, &extra_bits);
+ return m->literal_[VALUES_IN_BYTE + code] + extra_bits;
}
static WEBP_INLINE double GetDistanceCost(const CostModel* const m,
uint32_t distance) {
- int code, extra_bits_count, extra_bits_value;
- PrefixEncode(distance, &code, &extra_bits_count, &extra_bits_value);
- return m->distance_[code] + extra_bits_count;
+ int code, extra_bits;
+ VP8LPrefixEncodeBits(distance, &code, &extra_bits);
+ return m->distance_[code] + extra_bits;
+}
+
+static void AddSingleLiteralWithCostModel(
+ const uint32_t* const argb, VP8LHashChain* const hash_chain,
+ VP8LColorCache* const hashers, const CostModel* const cost_model, int idx,
+ int is_last, int use_color_cache, double prev_cost, float* const cost,
+ uint16_t* const dist_array) {
+ double cost_val = prev_cost;
+ const uint32_t color = argb[0];
+ if (!is_last) {
+ HashChainInsert(hash_chain, argb, idx);
+ }
+ if (use_color_cache && VP8LColorCacheContains(hashers, color)) {
+ const double mul0 = 0.68;
+ const int ix = VP8LColorCacheGetIndex(hashers, color);
+ cost_val += GetCacheCost(cost_model, ix) * mul0;
+ } else {
+ const double mul1 = 0.82;
+ if (use_color_cache) VP8LColorCacheInsert(hashers, color);
+ cost_val += GetLiteralCost(cost_model, color) * mul1;
+ }
+ if (cost[idx] > cost_val) {
+ cost[idx] = (float)cost_val;
+ dist_array[idx] = 1; // only one is inserted.
+ }
}
static int BackwardReferencesHashChainDistanceOnly(
- int xsize, int ysize, int recursive_cost_model, const uint32_t* const argb,
- int cache_bits, uint32_t* const dist_array) {
+ int xsize, int ysize, const uint32_t* const argb,
+ int quality, int cache_bits, VP8LHashChain* const hash_chain,
+ VP8LBackwardRefs* const refs, uint16_t* const dist_array) {
int i;
int ok = 0;
int cc_init = 0;
- const int quality = 100;
const int pix_count = xsize * ysize;
const int use_color_cache = (cache_bits > 0);
- double* const cost =
- (double*)WebPSafeMalloc((uint64_t)pix_count, sizeof(*cost));
- CostModel* cost_model = (CostModel*)malloc(sizeof(*cost_model));
- HashChain* hash_chain = (HashChain*)malloc(sizeof(*hash_chain));
+ float* const cost =
+ (float*)WebPSafeMalloc(pix_count, sizeof(*cost));
+ const size_t literal_array_size = sizeof(double) *
+ (NUM_LITERAL_CODES + NUM_LENGTH_CODES +
+ ((cache_bits > 0) ? (1 << cache_bits) : 0));
+ const size_t cost_model_size = sizeof(CostModel) + literal_array_size;
+ CostModel* const cost_model =
+ (CostModel*)WebPSafeMalloc(1ULL, cost_model_size);
VP8LColorCache hashers;
- const double mul0 = (recursive_cost_model != 0) ? 1.0 : 0.68;
- const double mul1 = (recursive_cost_model != 0) ? 1.0 : 0.82;
-
- if (cost == NULL || cost_model == NULL || hash_chain == NULL) goto Error;
+ const int skip_length = 32 + quality;
+ const int skip_min_distance_code = 2;
+ int iter_max = GetMaxItersForQuality(quality, 0);
+ const int window_size = GetWindowSizeForHashChain(quality, xsize);
- if (!HashChainInit(hash_chain, pix_count)) goto Error;
+ if (cost == NULL || cost_model == NULL) goto Error;
+ cost_model->literal_ = (double*)(cost_model + 1);
if (use_color_cache) {
cc_init = VP8LColorCacheInit(&hashers, cache_bits);
if (!cc_init) goto Error;
}
- if (!CostModelBuild(cost_model, xsize, ysize, recursive_cost_model, argb,
- cache_bits)) {
+ if (!CostModelBuild(cost_model, cache_bits, refs)) {
goto Error;
}
- for (i = 0; i < pix_count; ++i) cost[i] = 1e100;
+ for (i = 0; i < pix_count; ++i) cost[i] = 1e38f;
// We loop one pixel at a time, but store all currently best points to
// non-processed locations from this point.
dist_array[0] = 0;
- for (i = 0; i < pix_count; ++i) {
- double prev_cost = 0.0;
- int shortmax;
- if (i > 0) {
- prev_cost = cost[i - 1];
- }
- for (shortmax = 0; shortmax < 2; ++shortmax) {
- int offset = 0;
- int len = 0;
- if (i < pix_count - 1) { // FindCopy reads pixels at [i] and [i + 1].
- int maxlen = shortmax ? 2 : MAX_LENGTH;
- if (maxlen > pix_count - i) {
- maxlen = pix_count - i;
+ HashChainReset(hash_chain);
+ // Add first pixel as literal.
+ AddSingleLiteralWithCostModel(argb + 0, hash_chain, &hashers, cost_model, 0,
+ 0, use_color_cache, 0.0, cost, dist_array);
+ for (i = 1; i < pix_count - 1; ++i) {
+ int offset = 0;
+ int len = 0;
+ double prev_cost = cost[i - 1];
+ const int max_len = MaxFindCopyLength(pix_count - i);
+ HashChainFindCopy(hash_chain, i, argb, max_len, window_size,
+ iter_max, &offset, &len);
+ if (len >= MIN_LENGTH) {
+ const int code = DistanceToPlaneCode(xsize, offset);
+ const double distance_cost =
+ prev_cost + GetDistanceCost(cost_model, code);
+ int k;
+ for (k = 1; k < len; ++k) {
+ const double cost_val = distance_cost + GetLengthCost(cost_model, k);
+ if (cost[i + k] > cost_val) {
+ cost[i + k] = (float)cost_val;
+ dist_array[i + k] = k + 1;
}
- HashChainFindCopy(hash_chain, quality, i, xsize, argb, maxlen,
- &offset, &len);
}
- if (len >= MIN_LENGTH) {
- const int code = DistanceToPlaneCode(xsize, offset);
- const double distance_cost =
- prev_cost + GetDistanceCost(cost_model, code);
- int k;
- for (k = 1; k < len; ++k) {
- const double cost_val =
- distance_cost + GetLengthCost(cost_model, k);
- if (cost[i + k] > cost_val) {
- cost[i + k] = cost_val;
- dist_array[i + k] = k + 1;
+ // This if is for speedup only. It roughly doubles the speed, and
+ // makes compression worse by .1 %.
+ if (len >= skip_length && code <= skip_min_distance_code) {
+ // Long copy for short distances, let's skip the middle
+ // lookups for better copies.
+ // 1) insert the hashes.
+ if (use_color_cache) {
+ for (k = 0; k < len; ++k) {
+ VP8LColorCacheInsert(&hashers, argb[i + k]);
}
}
- // This if is for speedup only. It roughly doubles the speed, and
- // makes compression worse by .1 %.
- if (len >= 128 && code < 2) {
- // Long copy for short distances, let's skip the middle
- // lookups for better copies.
- // 1) insert the hashes.
- if (use_color_cache) {
- for (k = 0; k < len; ++k) {
- VP8LColorCacheInsert(&hashers, argb[i + k]);
- }
- }
- // 2) Add to the hash_chain (but cannot add the last pixel)
- {
- const int last = (len < pix_count - 1 - i) ? len
- : pix_count - 1 - i;
- for (k = 0; k < last; ++k) {
- HashChainInsert(hash_chain, &argb[i + k], i + k);
- }
+ // 2) Add to the hash_chain (but cannot add the last pixel)
+ {
+ const int last = (len + i < pix_count - 1) ? len + i
+ : pix_count - 1;
+ for (k = i; k < last; ++k) {
+ HashChainInsert(hash_chain, &argb[k], k);
}
- // 3) jump.
- i += len - 1; // for loop does ++i, thus -1 here.
- goto next_symbol;
}
+ // 3) jump.
+ i += len - 1; // for loop does ++i, thus -1 here.
+ goto next_symbol;
}
- }
- if (i < pix_count - 1) {
- HashChainInsert(hash_chain, &argb[i], i);
- }
- {
- // inserting a literal pixel
- double cost_val = prev_cost;
- if (use_color_cache && VP8LColorCacheContains(&hashers, argb[i])) {
- const int ix = VP8LColorCacheGetIndex(&hashers, argb[i]);
- cost_val += GetCacheCost(cost_model, ix) * mul0;
- } else {
- cost_val += GetLiteralCost(cost_model, argb[i]) * mul1;
- }
- if (cost[i] > cost_val) {
- cost[i] = cost_val;
- dist_array[i] = 1; // only one is inserted.
+ if (len != MIN_LENGTH) {
+ int code_min_length;
+ double cost_total;
+ HashChainFindOffset(hash_chain, i, argb, MIN_LENGTH, window_size,
+ &offset);
+ code_min_length = DistanceToPlaneCode(xsize, offset);
+ cost_total = prev_cost +
+ GetDistanceCost(cost_model, code_min_length) +
+ GetLengthCost(cost_model, 1);
+ if (cost[i + 1] > cost_total) {
+ cost[i + 1] = (float)cost_total;
+ dist_array[i + 1] = 2;
+ }
}
- if (use_color_cache) VP8LColorCacheInsert(&hashers, argb[i]);
}
+ AddSingleLiteralWithCostModel(argb + i, hash_chain, &hashers, cost_model, i,
+ 0, use_color_cache, prev_cost, cost,
+ dist_array);
next_symbol: ;
}
- // Last pixel still to do, it can only be a single step if not reached
- // through cheaper means already.
- ok = 1;
-Error:
+ // Handle the last pixel.
+ if (i == (pix_count - 1)) {
+ AddSingleLiteralWithCostModel(argb + i, hash_chain, &hashers, cost_model, i,
+ 1, use_color_cache, cost[pix_count - 2], cost,
+ dist_array);
+ }
+ ok = !refs->error_;
+ Error:
if (cc_init) VP8LColorCacheClear(&hashers);
- HashChainDelete(hash_chain);
- free(cost_model);
- free(cost);
+ WebPSafeFree(cost_model);
+ WebPSafeFree(cost);
return ok;
}
-static int TraceBackwards(const uint32_t* const dist_array,
- int dist_array_size,
- uint32_t** const chosen_path,
- int* const chosen_path_size) {
- int i;
- // Count how many.
- int count = 0;
- for (i = dist_array_size - 1; i >= 0; ) {
- int k = dist_array[i];
- assert(k >= 1);
- ++count;
- i -= k;
- }
- // Allocate.
- *chosen_path_size = count;
- *chosen_path =
- (uint32_t*)WebPSafeMalloc((uint64_t)count, sizeof(**chosen_path));
- if (*chosen_path == NULL) return 0;
-
- // Write in reverse order.
- for (i = dist_array_size - 1; i >= 0; ) {
- int k = dist_array[i];
- assert(k >= 1);
- (*chosen_path)[--count] = k;
- i -= k;
+// We pack the path at the end of *dist_array and return
+// a pointer to this part of the array. Example:
+// dist_array = [1x2xx3x2] => packed [1x2x1232], chosen_path = [1232]
+static void TraceBackwards(uint16_t* const dist_array,
+ int dist_array_size,
+ uint16_t** const chosen_path,
+ int* const chosen_path_size) {
+ uint16_t* path = dist_array + dist_array_size;
+ uint16_t* cur = dist_array + dist_array_size - 1;
+ while (cur >= dist_array) {
+ const int k = *cur;
+ --path;
+ *path = k;
+ cur -= k;
}
- return 1;
+ *chosen_path = path;
+ *chosen_path_size = (int)(dist_array + dist_array_size - path);
}
static int BackwardReferencesHashChainFollowChosenPath(
- int xsize, int ysize, const uint32_t* const argb, int cache_bits,
- const uint32_t* const chosen_path, int chosen_path_size,
+ int xsize, int ysize, const uint32_t* const argb,
+ int quality, int cache_bits,
+ const uint16_t* const chosen_path, int chosen_path_size,
+ VP8LHashChain* const hash_chain,
VP8LBackwardRefs* const refs) {
- const int quality = 100;
const int pix_count = xsize * ysize;
const int use_color_cache = (cache_bits > 0);
- int size = 0;
- int i = 0;
- int k;
int ix;
+ int i = 0;
int ok = 0;
int cc_init = 0;
- HashChain* hash_chain = (HashChain*)malloc(sizeof(*hash_chain));
+ const int window_size = GetWindowSizeForHashChain(quality, xsize);
VP8LColorCache hashers;
- if (hash_chain == NULL || !HashChainInit(hash_chain, pix_count)) {
- goto Error;
- }
if (use_color_cache) {
cc_init = VP8LColorCacheInit(&hashers, cache_bits);
if (!cc_init) goto Error;
}
- refs->size = 0;
- for (ix = 0; ix < chosen_path_size; ++ix, ++size) {
+ ClearBackwardRefs(refs);
+ HashChainReset(hash_chain);
+ for (ix = 0; ix < chosen_path_size; ++ix) {
int offset = 0;
- int len = 0;
- int maxlen = chosen_path[ix];
- if (maxlen != 1) {
- HashChainFindCopy(hash_chain, quality,
- i, xsize, argb, maxlen, &offset, &len);
- assert(len == maxlen);
- refs->refs[size] = PixOrCopyCreateCopy(offset, len);
+ const int len = chosen_path[ix];
+ if (len != 1) {
+ int k;
+ HashChainFindOffset(hash_chain, i, argb, len, window_size, &offset);
+ BackwardRefsCursorAdd(refs, PixOrCopyCreateCopy(offset, len));
if (use_color_cache) {
for (k = 0; k < len; ++k) {
VP8LColorCacheInsert(&hashers, argb[i + k]);
@@ -648,227 +780,330 @@ static int BackwardReferencesHashChainFollowChosenPath(
}
i += len;
} else {
+ PixOrCopy v;
if (use_color_cache && VP8LColorCacheContains(&hashers, argb[i])) {
// push pixel as a color cache index
const int idx = VP8LColorCacheGetIndex(&hashers, argb[i]);
- refs->refs[size] = PixOrCopyCreateCacheIdx(idx);
+ v = PixOrCopyCreateCacheIdx(idx);
} else {
- refs->refs[size] = PixOrCopyCreateLiteral(argb[i]);
+ if (use_color_cache) VP8LColorCacheInsert(&hashers, argb[i]);
+ v = PixOrCopyCreateLiteral(argb[i]);
}
- if (use_color_cache) VP8LColorCacheInsert(&hashers, argb[i]);
+ BackwardRefsCursorAdd(refs, v);
if (i + 1 < pix_count) {
HashChainInsert(hash_chain, &argb[i], i);
}
++i;
}
}
- assert(size <= refs->max_size);
- refs->size = size;
- ok = 1;
-Error:
+ ok = !refs->error_;
+ Error:
if (cc_init) VP8LColorCacheClear(&hashers);
- HashChainDelete(hash_chain);
return ok;
}
// Returns 1 on success.
static int BackwardReferencesTraceBackwards(int xsize, int ysize,
- int recursive_cost_model,
const uint32_t* const argb,
- int cache_bits,
+ int quality, int cache_bits,
+ VP8LHashChain* const hash_chain,
VP8LBackwardRefs* const refs) {
int ok = 0;
const int dist_array_size = xsize * ysize;
- uint32_t* chosen_path = NULL;
+ uint16_t* chosen_path = NULL;
int chosen_path_size = 0;
- uint32_t* dist_array =
- (uint32_t*)WebPSafeMalloc((uint64_t)dist_array_size, sizeof(*dist_array));
+ uint16_t* dist_array =
+ (uint16_t*)WebPSafeMalloc(dist_array_size, sizeof(*dist_array));
if (dist_array == NULL) goto Error;
if (!BackwardReferencesHashChainDistanceOnly(
- xsize, ysize, recursive_cost_model, argb, cache_bits, dist_array)) {
- goto Error;
- }
- if (!TraceBackwards(dist_array, dist_array_size,
- &chosen_path, &chosen_path_size)) {
+ xsize, ysize, argb, quality, cache_bits, hash_chain,
+ refs, dist_array)) {
goto Error;
}
- free(dist_array); // no need to retain this memory any longer
- dist_array = NULL;
+ TraceBackwards(dist_array, dist_array_size, &chosen_path, &chosen_path_size);
if (!BackwardReferencesHashChainFollowChosenPath(
- xsize, ysize, argb, cache_bits, chosen_path, chosen_path_size, refs)) {
+ xsize, ysize, argb, quality, cache_bits, chosen_path, chosen_path_size,
+ hash_chain, refs)) {
goto Error;
}
ok = 1;
Error:
- free(chosen_path);
- free(dist_array);
+ WebPSafeFree(dist_array);
return ok;
}
static void BackwardReferences2DLocality(int xsize,
- VP8LBackwardRefs* const refs) {
- int i;
- for (i = 0; i < refs->size; ++i) {
- if (PixOrCopyIsCopy(&refs->refs[i])) {
- const int dist = refs->refs[i].argb_or_distance;
+ const VP8LBackwardRefs* const refs) {
+ VP8LRefsCursor c = VP8LRefsCursorInit(refs);
+ while (VP8LRefsCursorOk(&c)) {
+ if (PixOrCopyIsCopy(c.cur_pos)) {
+ const int dist = c.cur_pos->argb_or_distance;
const int transformed_dist = DistanceToPlaneCode(xsize, dist);
- refs->refs[i].argb_or_distance = transformed_dist;
+ c.cur_pos->argb_or_distance = transformed_dist;
}
+ VP8LRefsCursorNext(&c);
}
}
-int VP8LGetBackwardReferences(int width, int height,
- const uint32_t* const argb,
- int quality, int cache_bits, int use_2d_locality,
- VP8LBackwardRefs* const best) {
- int ok = 0;
- int lz77_is_useful;
- VP8LBackwardRefs refs_rle, refs_lz77;
- const int num_pix = width * height;
-
- VP8LBackwardRefsAlloc(&refs_rle, num_pix);
- VP8LBackwardRefsAlloc(&refs_lz77, num_pix);
- VP8LInitBackwardRefs(best);
- if (refs_rle.refs == NULL || refs_lz77.refs == NULL) {
- Error1:
- VP8LClearBackwardRefs(&refs_rle);
- VP8LClearBackwardRefs(&refs_lz77);
- goto End;
- }
-
- if (!BackwardReferencesHashChain(width, height, argb, cache_bits, quality,
- &refs_lz77)) {
- goto End;
- }
- // Backward Reference using RLE only.
- BackwardReferencesRle(width, height, argb, &refs_rle);
+// Returns entropy for the given cache bits.
+static double ComputeCacheEntropy(const uint32_t* argb,
+ const VP8LBackwardRefs* const refs,
+ int cache_bits) {
+ const int use_color_cache = (cache_bits > 0);
+ int cc_init = 0;
+ double entropy = MAX_ENTROPY;
+ const double kSmallPenaltyForLargeCache = 4.0;
+ VP8LColorCache hashers;
+ VP8LRefsCursor c = VP8LRefsCursorInit(refs);
+ VP8LHistogram* histo = VP8LAllocateHistogram(cache_bits);
+ if (histo == NULL) goto Error;
- {
- double bit_cost_lz77, bit_cost_rle;
- VP8LHistogram* const histo = (VP8LHistogram*)malloc(sizeof(*histo));
- if (histo == NULL) goto Error1;
- // Evaluate lz77 coding
- VP8LHistogramCreate(histo, &refs_lz77, cache_bits);
- bit_cost_lz77 = VP8LHistogramEstimateBits(histo);
- // Evaluate RLE coding
- VP8LHistogramCreate(histo, &refs_rle, cache_bits);
- bit_cost_rle = VP8LHistogramEstimateBits(histo);
- // Decide if LZ77 is useful.
- lz77_is_useful = (bit_cost_lz77 < bit_cost_rle);
- free(histo);
+ if (use_color_cache) {
+ cc_init = VP8LColorCacheInit(&hashers, cache_bits);
+ if (!cc_init) goto Error;
}
-
- // Choose appropriate backward reference.
- if (lz77_is_useful) {
- // TraceBackwards is costly. Run it for higher qualities.
- const int try_lz77_trace_backwards = (quality >= 75);
- *best = refs_lz77; // default guess: lz77 is better
- VP8LClearBackwardRefs(&refs_rle);
- if (try_lz77_trace_backwards) {
- const int recursion_level = (num_pix < 320 * 200) ? 1 : 0;
- VP8LBackwardRefs refs_trace;
- if (!VP8LBackwardRefsAlloc(&refs_trace, num_pix)) {
- goto End;
- }
- if (BackwardReferencesTraceBackwards(
- width, height, recursion_level, argb, cache_bits, &refs_trace)) {
- VP8LClearBackwardRefs(&refs_lz77);
- *best = refs_trace;
- }
+ if (!use_color_cache) {
+ while (VP8LRefsCursorOk(&c)) {
+ VP8LHistogramAddSinglePixOrCopy(histo, c.cur_pos);
+ VP8LRefsCursorNext(&c);
}
} else {
- VP8LClearBackwardRefs(&refs_lz77);
- *best = refs_rle;
+ while (VP8LRefsCursorOk(&c)) {
+ const PixOrCopy* const v = c.cur_pos;
+ if (PixOrCopyIsLiteral(v)) {
+ const uint32_t pix = *argb++;
+ const uint32_t key = VP8LColorCacheGetIndex(&hashers, pix);
+ if (VP8LColorCacheLookup(&hashers, key) == pix) {
+ ++histo->literal_[NUM_LITERAL_CODES + NUM_LENGTH_CODES + key];
+ } else {
+ VP8LColorCacheSet(&hashers, key, pix);
+ ++histo->blue_[pix & 0xff];
+ ++histo->literal_[(pix >> 8) & 0xff];
+ ++histo->red_[(pix >> 16) & 0xff];
+ ++histo->alpha_[pix >> 24];
+ }
+ } else {
+ int len = PixOrCopyLength(v);
+ int code, extra_bits;
+ VP8LPrefixEncodeBits(len, &code, &extra_bits);
+ ++histo->literal_[NUM_LITERAL_CODES + code];
+ VP8LPrefixEncodeBits(PixOrCopyDistance(v), &code, &extra_bits);
+ ++histo->distance_[code];
+ do {
+ VP8LColorCacheInsert(&hashers, *argb++);
+ } while(--len != 0);
+ }
+ VP8LRefsCursorNext(&c);
+ }
}
+ entropy = VP8LHistogramEstimateBits(histo) +
+ kSmallPenaltyForLargeCache * cache_bits;
+ Error:
+ if (cc_init) VP8LColorCacheClear(&hashers);
+ VP8LFreeHistogram(histo);
+ return entropy;
+}
- if (use_2d_locality) BackwardReferences2DLocality(width, best);
-
- ok = 1;
-
- End:
- if (!ok) {
- VP8LClearBackwardRefs(best);
+// Evaluate optimal cache bits for the local color cache.
+// The input *best_cache_bits sets the maximum cache bits to use (passing 0
+// implies disabling the local color cache). The local color cache is also
+// disabled for the lower (<= 25) quality.
+// Returns 0 in case of memory error.
+static int CalculateBestCacheSize(const uint32_t* const argb,
+ int xsize, int ysize, int quality,
+ VP8LHashChain* const hash_chain,
+ VP8LBackwardRefs* const refs,
+ int* const lz77_computed,
+ int* const best_cache_bits) {
+ int eval_low = 1;
+ int eval_high = 1;
+ double entropy_low = MAX_ENTROPY;
+ double entropy_high = MAX_ENTROPY;
+ const double cost_mul = 5e-4;
+ int cache_bits_low = 0;
+ int cache_bits_high = (quality <= 25) ? 0 : *best_cache_bits;
+
+ assert(cache_bits_high <= MAX_COLOR_CACHE_BITS);
+
+ *lz77_computed = 0;
+ if (cache_bits_high == 0) {
+ *best_cache_bits = 0;
+ // Local color cache is disabled.
+ return 1;
}
- return ok;
+ if (!BackwardReferencesLz77(xsize, ysize, argb, cache_bits_low, quality, 0,
+ hash_chain, refs)) {
+ return 0;
+ }
+ // Do a binary search to find the optimal entropy for cache_bits.
+ while (eval_low || eval_high) {
+ if (eval_low) {
+ entropy_low = ComputeCacheEntropy(argb, refs, cache_bits_low);
+ entropy_low += entropy_low * cache_bits_low * cost_mul;
+ eval_low = 0;
+ }
+ if (eval_high) {
+ entropy_high = ComputeCacheEntropy(argb, refs, cache_bits_high);
+ entropy_high += entropy_high * cache_bits_high * cost_mul;
+ eval_high = 0;
+ }
+ if (entropy_high < entropy_low) {
+ const int prev_cache_bits_low = cache_bits_low;
+ *best_cache_bits = cache_bits_high;
+ cache_bits_low = (cache_bits_low + cache_bits_high) / 2;
+ if (cache_bits_low != prev_cache_bits_low) eval_low = 1;
+ } else {
+ *best_cache_bits = cache_bits_low;
+ cache_bits_high = (cache_bits_low + cache_bits_high) / 2;
+ if (cache_bits_high != cache_bits_low) eval_high = 1;
+ }
+ }
+ *lz77_computed = 1;
+ return 1;
}
-// Returns 1 on success.
-static int ComputeCacheHistogram(const uint32_t* const argb,
- int xsize, int ysize,
- const VP8LBackwardRefs* const refs,
- int cache_bits,
- VP8LHistogram* const histo) {
+// Update (in-place) backward references for specified cache_bits.
+static int BackwardRefsWithLocalCache(const uint32_t* const argb,
+ int cache_bits,
+ VP8LBackwardRefs* const refs) {
int pixel_index = 0;
- int i;
- uint32_t k;
VP8LColorCache hashers;
- const int use_color_cache = (cache_bits > 0);
- int cc_init = 0;
+ VP8LRefsCursor c = VP8LRefsCursorInit(refs);
+ if (!VP8LColorCacheInit(&hashers, cache_bits)) return 0;
- if (use_color_cache) {
- cc_init = VP8LColorCacheInit(&hashers, cache_bits);
- if (!cc_init) return 0;
- }
-
- for (i = 0; i < refs->size; ++i) {
- const PixOrCopy* const v = &refs->refs[i];
+ while (VP8LRefsCursorOk(&c)) {
+ PixOrCopy* const v = c.cur_pos;
if (PixOrCopyIsLiteral(v)) {
- if (use_color_cache &&
- VP8LColorCacheContains(&hashers, argb[pixel_index])) {
- // push pixel as a cache index
- const int ix = VP8LColorCacheGetIndex(&hashers, argb[pixel_index]);
- const PixOrCopy token = PixOrCopyCreateCacheIdx(ix);
- VP8LHistogramAddSinglePixOrCopy(histo, &token);
+ const uint32_t argb_literal = v->argb_or_distance;
+ if (VP8LColorCacheContains(&hashers, argb_literal)) {
+ const int ix = VP8LColorCacheGetIndex(&hashers, argb_literal);
+ *v = PixOrCopyCreateCacheIdx(ix);
} else {
- VP8LHistogramAddSinglePixOrCopy(histo, v);
+ VP8LColorCacheInsert(&hashers, argb_literal);
}
+ ++pixel_index;
} else {
- VP8LHistogramAddSinglePixOrCopy(histo, v);
- }
- if (use_color_cache) {
- for (k = 0; k < PixOrCopyLength(v); ++k) {
- VP8LColorCacheInsert(&hashers, argb[pixel_index + k]);
+ // refs was created without local cache, so it can not have cache indexes.
+ int k;
+ assert(PixOrCopyIsCopy(v));
+ for (k = 0; k < v->len; ++k) {
+ VP8LColorCacheInsert(&hashers, argb[pixel_index++]);
}
}
- pixel_index += PixOrCopyLength(v);
+ VP8LRefsCursorNext(&c);
}
- assert(pixel_index == xsize * ysize);
- (void)xsize; // xsize is not used in non-debug compilations otherwise.
- (void)ysize; // ysize is not used in non-debug compilations otherwise.
- if (cc_init) VP8LColorCacheClear(&hashers);
+ VP8LColorCacheClear(&hashers);
return 1;
}
-// Returns how many bits are to be used for a color cache.
-int VP8LCalculateEstimateForCacheSize(const uint32_t* const argb,
- int xsize, int ysize,
- int* const best_cache_bits) {
- int ok = 0;
- int cache_bits;
- double lowest_entropy = 1e99;
- VP8LBackwardRefs refs;
- static const double kSmallPenaltyForLargeCache = 4.0;
- static const int quality = 30;
- if (!VP8LBackwardRefsAlloc(&refs, xsize * ysize) ||
- !BackwardReferencesHashChain(xsize, ysize, argb, 0, quality, &refs)) {
+static VP8LBackwardRefs* GetBackwardReferencesLowEffort(
+ int width, int height, const uint32_t* const argb, int quality,
+ int* const cache_bits, VP8LHashChain* const hash_chain,
+ VP8LBackwardRefs refs_array[2]) {
+ VP8LBackwardRefs* refs_lz77 = &refs_array[0];
+ *cache_bits = 0;
+ if (!BackwardReferencesLz77(width, height, argb, 0, quality,
+ 1 /* Low effort. */, hash_chain, refs_lz77)) {
+ return NULL;
+ }
+ BackwardReferences2DLocality(width, refs_lz77);
+ return refs_lz77;
+}
+
+static VP8LBackwardRefs* GetBackwardReferences(
+ int width, int height, const uint32_t* const argb, int quality,
+ int* const cache_bits, VP8LHashChain* const hash_chain,
+ VP8LBackwardRefs refs_array[2]) {
+ int lz77_is_useful;
+ int lz77_computed;
+ double bit_cost_lz77, bit_cost_rle;
+ VP8LBackwardRefs* best = NULL;
+ VP8LBackwardRefs* refs_lz77 = &refs_array[0];
+ VP8LBackwardRefs* refs_rle = &refs_array[1];
+ VP8LHistogram* histo = NULL;
+
+ if (!CalculateBestCacheSize(argb, width, height, quality, hash_chain,
+ refs_lz77, &lz77_computed, cache_bits)) {
goto Error;
}
- for (cache_bits = 0; cache_bits <= MAX_COLOR_CACHE_BITS; ++cache_bits) {
- double cur_entropy;
- VP8LHistogram histo;
- VP8LHistogramInit(&histo, cache_bits);
- ComputeCacheHistogram(argb, xsize, ysize, &refs, cache_bits, &histo);
- cur_entropy = VP8LHistogramEstimateBits(&histo) +
- kSmallPenaltyForLargeCache * cache_bits;
- if (cache_bits == 0 || cur_entropy < lowest_entropy) {
- *best_cache_bits = cache_bits;
- lowest_entropy = cur_entropy;
+
+ if (lz77_computed) {
+ // Transform refs_lz77 for the optimized cache_bits.
+ if (*cache_bits > 0) {
+ if (!BackwardRefsWithLocalCache(argb, *cache_bits, refs_lz77)) {
+ goto Error;
+ }
+ }
+ } else {
+ if (!BackwardReferencesLz77(width, height, argb, *cache_bits, quality,
+ 0 /* Low effort. */, hash_chain, refs_lz77)) {
+ goto Error;
}
}
- ok = 1;
+
+ if (!BackwardReferencesRle(width, height, argb, *cache_bits, refs_rle)) {
+ goto Error;
+ }
+
+ histo = VP8LAllocateHistogram(*cache_bits);
+ if (histo == NULL) goto Error;
+
+ {
+ // Evaluate LZ77 coding.
+ VP8LHistogramCreate(histo, refs_lz77, *cache_bits);
+ bit_cost_lz77 = VP8LHistogramEstimateBits(histo);
+ // Evaluate RLE coding.
+ VP8LHistogramCreate(histo, refs_rle, *cache_bits);
+ bit_cost_rle = VP8LHistogramEstimateBits(histo);
+ // Decide if LZ77 is useful.
+ lz77_is_useful = (bit_cost_lz77 < bit_cost_rle);
+ }
+
+ // Choose appropriate backward reference.
+ if (lz77_is_useful) {
+ // TraceBackwards is costly. Don't execute it at lower quality.
+ const int try_lz77_trace_backwards = (quality >= 25);
+ best = refs_lz77; // default guess: lz77 is better
+ if (try_lz77_trace_backwards) {
+ VP8LBackwardRefs* const refs_trace = refs_rle;
+ if (!VP8LBackwardRefsCopy(refs_lz77, refs_trace)) {
+ best = NULL;
+ goto Error;
+ }
+ if (BackwardReferencesTraceBackwards(width, height, argb, quality,
+ *cache_bits, hash_chain,
+ refs_trace)) {
+ double bit_cost_trace;
+ // Evaluate LZ77 coding.
+ VP8LHistogramCreate(histo, refs_trace, *cache_bits);
+ bit_cost_trace = VP8LHistogramEstimateBits(histo);
+ if (bit_cost_trace < bit_cost_lz77) {
+ best = refs_trace;
+ }
+ }
+ }
+ } else {
+ best = refs_rle;
+ }
+
+ BackwardReferences2DLocality(width, best);
+
Error:
- VP8LClearBackwardRefs(&refs);
- return ok;
+ VP8LFreeHistogram(histo);
+ return best;
+}
+
+VP8LBackwardRefs* VP8LGetBackwardReferences(
+ int width, int height, const uint32_t* const argb, int quality,
+ int low_effort, int* const cache_bits, VP8LHashChain* const hash_chain,
+ VP8LBackwardRefs refs_array[2]) {
+ if (low_effort) {
+ return GetBackwardReferencesLowEffort(width, height, argb, quality,
+ cache_bits, hash_chain, refs_array);
+ } else {
+ return GetBackwardReferences(width, height, argb, quality, cache_bits,
+ hash_chain, refs_array);
+ }
}
diff --git a/drivers/webp/enc/backward_references.h b/drivers/webp/enc/backward_references.h
index 8006a56ba1..e410b06f7d 100644
--- a/drivers/webp/enc/backward_references.h
+++ b/drivers/webp/enc/backward_references.h
@@ -1,8 +1,10 @@
// Copyright 2012 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Author: Jyrki Alakuijala (jyrki@google.com)
@@ -13,82 +15,15 @@
#include <assert.h>
#include <stdlib.h>
-#include "../types.h"
-#include "../format_constants.h"
+#include "webp/types.h"
+#include "webp/format_constants.h"
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
extern "C" {
#endif
-// The spec allows 11, we use 9 bits to reduce memory consumption in encoding.
-// Having 9 instead of 11 only removes about 0.25 % of compression density.
-#define MAX_COLOR_CACHE_BITS 9
-
-// Max ever number of codes we'll use:
-#define PIX_OR_COPY_CODES_MAX \
- (NUM_LITERAL_CODES + NUM_LENGTH_CODES + (1 << MAX_COLOR_CACHE_BITS))
-
-// -----------------------------------------------------------------------------
-// PrefixEncode()
-
-// use GNU builtins where available.
-#if defined(__GNUC__) && \
- ((__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || __GNUC__ >= 4)
-static WEBP_INLINE int BitsLog2Floor(uint32_t n) {
- return n == 0 ? -1 : 31 ^ __builtin_clz(n);
-}
-#elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))
-#include <intrin.h>
-#pragma intrinsic(_BitScanReverse)
-
-static WEBP_INLINE int BitsLog2Floor(uint32_t n) {
- unsigned long first_set_bit;
- return _BitScanReverse(&first_set_bit, n) ? first_set_bit : -1;
-}
-#else
-static WEBP_INLINE int BitsLog2Floor(uint32_t n) {
- int log = 0;
- uint32_t value = n;
- int i;
-
- if (value == 0) return -1;
- for (i = 4; i >= 0; --i) {
- const int shift = (1 << i);
- const uint32_t x = value >> shift;
- if (x != 0) {
- value = x;
- log += shift;
- }
- }
- return log;
-}
-#endif
-
-static WEBP_INLINE int VP8LBitsLog2Ceiling(uint32_t n) {
- const int floor = BitsLog2Floor(n);
- if (n == (n & ~(n - 1))) // zero or a power of two.
- return floor;
- else
- return floor + 1;
-}
-
-// Splitting of distance and length codes into prefixes and
-// extra bits. The prefixes are encoded with an entropy code
-// while the extra bits are stored just as normal bits.
-static WEBP_INLINE void PrefixEncode(int distance, int* const code,
- int* const extra_bits_count,
- int* const extra_bits_value) {
- // Collect the two most significant bits where the highest bit is 1.
- const int highest_bit = BitsLog2Floor(--distance);
- // & 0x3f is to make behavior well defined when highest_bit
- // does not exist or is the least significant bit.
- const int second_highest_bit =
- (distance >> ((highest_bit - 1) & 0x3f)) & 1;
- *extra_bits_count = (highest_bit > 0) ? (highest_bit - 1) : 0;
- *extra_bits_value = distance & ((1 << *extra_bits_count) - 1);
- *code = (highest_bit > 0) ? (2 * highest_bit + second_highest_bit)
- : (highest_bit == 0) ? 1 : 0;
-}
+// The maximum allowed limit is 11.
+#define MAX_COLOR_CACHE_BITS 10
// -----------------------------------------------------------------------------
// PixOrCopy
@@ -173,39 +108,94 @@ static WEBP_INLINE uint32_t PixOrCopyDistance(const PixOrCopy* const p) {
}
// -----------------------------------------------------------------------------
-// VP8LBackwardRefs
+// VP8LHashChain
+
+#define HASH_BITS 18
+#define HASH_SIZE (1 << HASH_BITS)
+
+typedef struct VP8LHashChain VP8LHashChain;
+struct VP8LHashChain {
+ // Stores the most recently added position with the given hash value.
+ int32_t hash_to_first_index_[HASH_SIZE];
+ // chain_[pos] stores the previous position with the same hash value
+ // for every pixel in the image.
+ int32_t* chain_;
+ // This is the maximum size of the hash_chain that can be constructed.
+ // Typically this is the pixel count (width x height) for a given image.
+ int size_;
+};
-typedef struct {
- PixOrCopy* refs;
- int size; // currently used
- int max_size; // maximum capacity
-} VP8LBackwardRefs;
+// Must be called first, to set size.
+int VP8LHashChainInit(VP8LHashChain* const p, int size);
+void VP8LHashChainClear(VP8LHashChain* const p); // release memory
-// Initialize the object. Must be called first. 'refs' can be NULL.
-void VP8LInitBackwardRefs(VP8LBackwardRefs* const refs);
+// -----------------------------------------------------------------------------
+// VP8LBackwardRefs (block-based backward-references storage)
+
+// maximum number of reference blocks the image will be segmented into
+#define MAX_REFS_BLOCK_PER_IMAGE 16
+
+typedef struct PixOrCopyBlock PixOrCopyBlock; // forward declaration
+typedef struct VP8LBackwardRefs VP8LBackwardRefs;
+
+// Container for blocks chain
+struct VP8LBackwardRefs {
+ int block_size_; // common block-size
+ int error_; // set to true if some memory error occurred
+ PixOrCopyBlock* refs_; // list of currently used blocks
+ PixOrCopyBlock** tail_; // for list recycling
+ PixOrCopyBlock* free_blocks_; // free-list
+ PixOrCopyBlock* last_block_; // used for adding new refs (internal)
+};
-// Release memory and re-initialize the object. 'refs' can be NULL.
-void VP8LClearBackwardRefs(VP8LBackwardRefs* const refs);
+// Initialize the object. 'block_size' is the common block size to store
+// references (typically, width * height / MAX_REFS_BLOCK_PER_IMAGE).
+void VP8LBackwardRefsInit(VP8LBackwardRefs* const refs, int block_size);
+// Release memory for backward references.
+void VP8LBackwardRefsClear(VP8LBackwardRefs* const refs);
+// Copies the 'src' backward refs to the 'dst'. Returns 0 in case of error.
+int VP8LBackwardRefsCopy(const VP8LBackwardRefs* const src,
+ VP8LBackwardRefs* const dst);
-// Allocate 'max_size' references. Returns false in case of memory error.
-int VP8LBackwardRefsAlloc(VP8LBackwardRefs* const refs, int max_size);
+// Cursor for iterating on references content
+typedef struct {
+ // public:
+ PixOrCopy* cur_pos; // current position
+ // private:
+ PixOrCopyBlock* cur_block_; // current block in the refs list
+ const PixOrCopy* last_pos_; // sentinel for switching to next block
+} VP8LRefsCursor;
+
+// Returns a cursor positioned at the beginning of the references list.
+VP8LRefsCursor VP8LRefsCursorInit(const VP8LBackwardRefs* const refs);
+// Returns true if cursor is pointing at a valid position.
+static WEBP_INLINE int VP8LRefsCursorOk(const VP8LRefsCursor* const c) {
+ return (c->cur_pos != NULL);
+}
+// Move to next block of references. Internal, not to be called directly.
+void VP8LRefsCursorNextBlock(VP8LRefsCursor* const c);
+// Move to next position, or NULL. Should not be called if !VP8LRefsCursorOk().
+static WEBP_INLINE void VP8LRefsCursorNext(VP8LRefsCursor* const c) {
+ assert(c != NULL);
+ assert(VP8LRefsCursorOk(c));
+ if (++c->cur_pos == c->last_pos_) VP8LRefsCursorNextBlock(c);
+}
// -----------------------------------------------------------------------------
// Main entry points
// Evaluates best possible backward references for specified quality.
-// Further optimize for 2D locality if use_2d_locality flag is set.
-int VP8LGetBackwardReferences(int width, int height,
- const uint32_t* const argb,
- int quality, int cache_bits, int use_2d_locality,
- VP8LBackwardRefs* const best);
-
-// Produce an estimate for a good color cache size for the image.
-int VP8LCalculateEstimateForCacheSize(const uint32_t* const argb,
- int xsize, int ysize,
- int* const best_cache_bits);
-
-#if defined(__cplusplus) || defined(c_plusplus)
+// The input cache_bits to 'VP8LGetBackwardReferences' sets the maximum cache
+// bits to use (passing 0 implies disabling the local color cache).
+// The optimal cache bits is evaluated and set for the *cache_bits parameter.
+// The return value is the pointer to the best of the two backward refs viz,
+// refs[0] or refs[1].
+VP8LBackwardRefs* VP8LGetBackwardReferences(
+ int width, int height, const uint32_t* const argb, int quality,
+ int low_effort, int* const cache_bits, VP8LHashChain* const hash_chain,
+ VP8LBackwardRefs refs[2]);
+
+#ifdef __cplusplus
}
#endif
diff --git a/drivers/webp/enc/config.c b/drivers/webp/enc/config.c
index 4136f6c227..8fd2276cb5 100644
--- a/drivers/webp/enc/config.c
+++ b/drivers/webp/enc/config.c
@@ -1,19 +1,17 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Coding tools configuration
//
// Author: Skal (pascal.massimino@gmail.com)
-#include "../encode.h"
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
+#include "webp/encode.h"
//------------------------------------------------------------------------------
// WebPConfig
@@ -31,9 +29,9 @@ int WebPConfigInitInternal(WebPConfig* config,
config->target_PSNR = 0.;
config->method = 4;
config->sns_strength = 50;
- config->filter_strength = 20; // default: light filtering
+ config->filter_strength = 60; // mid-filtering
config->filter_sharpness = 0;
- config->filter_type = 0; // default: simple
+ config->filter_type = 1; // default: strong (so U/V is filtered too)
config->partitions = 0;
config->segments = 4;
config->pass = 1;
@@ -45,7 +43,15 @@ int WebPConfigInitInternal(WebPConfig* config,
config->alpha_filtering = 1;
config->alpha_quality = 100;
config->lossless = 0;
+ config->exact = 0;
config->image_hint = WEBP_HINT_DEFAULT;
+ config->emulate_jpeg_size = 0;
+ config->thread_level = 0;
+ config->low_memory = 0;
+ config->near_lossless = 100;
+#ifdef WEBP_EXPERIMENTAL_FEATURES
+ config->delta_palettization = 0;
+#endif // WEBP_EXPERIMENTAL_FEATURES
// TODO(skal): tune.
switch (preset) {
@@ -53,11 +59,13 @@ int WebPConfigInitInternal(WebPConfig* config,
config->sns_strength = 80;
config->filter_sharpness = 4;
config->filter_strength = 35;
+ config->preprocessing &= ~2; // no dithering
break;
case WEBP_PRESET_PHOTO:
config->sns_strength = 80;
config->filter_sharpness = 3;
config->filter_strength = 30;
+ config->preprocessing |= 2;
break;
case WEBP_PRESET_DRAWING:
config->sns_strength = 25;
@@ -67,10 +75,12 @@ int WebPConfigInitInternal(WebPConfig* config,
case WEBP_PRESET_ICON:
config->sns_strength = 0;
config->filter_strength = 0; // disable filtering to retain sharpness
+ config->preprocessing &= ~2; // no dithering
break;
case WEBP_PRESET_TEXT:
config->sns_strength = 0;
config->filter_strength = 0; // disable filtering to retain sharpness
+ config->preprocessing &= ~2; // no dithering
config->segments = 2;
break;
case WEBP_PRESET_DEFAULT:
@@ -106,7 +116,7 @@ int WebPValidateConfig(const WebPConfig* config) {
return 0;
if (config->show_compressed < 0 || config->show_compressed > 1)
return 0;
- if (config->preprocessing < 0 || config->preprocessing > 1)
+ if (config->preprocessing < 0 || config->preprocessing > 7)
return 0;
if (config->partitions < 0 || config->partitions > 3)
return 0;
@@ -120,13 +130,44 @@ int WebPValidateConfig(const WebPConfig* config) {
return 0;
if (config->lossless < 0 || config->lossless > 1)
return 0;
+ if (config->near_lossless < 0 || config->near_lossless > 100)
+ return 0;
if (config->image_hint >= WEBP_HINT_LAST)
return 0;
+ if (config->emulate_jpeg_size < 0 || config->emulate_jpeg_size > 1)
+ return 0;
+ if (config->thread_level < 0 || config->thread_level > 1)
+ return 0;
+ if (config->low_memory < 0 || config->low_memory > 1)
+ return 0;
+ if (config->exact < 0 || config->exact > 1)
+ return 0;
+#ifdef WEBP_EXPERIMENTAL_FEATURES
+ if (config->delta_palettization < 0 || config->delta_palettization > 1)
+ return 0;
+#endif // WEBP_EXPERIMENTAL_FEATURES
return 1;
}
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
+#define MAX_LEVEL 9
+
+// Mapping between -z level and -m / -q parameter settings.
+static const struct {
+ uint8_t method_;
+ uint8_t quality_;
+} kLosslessPresets[MAX_LEVEL + 1] = {
+ { 0, 0 }, { 1, 20 }, { 2, 25 }, { 3, 30 }, { 3, 50 },
+ { 4, 50 }, { 4, 75 }, { 4, 90 }, { 5, 90 }, { 6, 100 }
+};
+
+int WebPConfigLosslessPreset(WebPConfig* config, int level) {
+ if (config == NULL || level < 0 || level > MAX_LEVEL) return 0;
+ config->lossless = 1;
+ config->method = kLosslessPresets[level].method_;
+ config->quality = kLosslessPresets[level].quality_;
+ return 1;
+}
+
+//------------------------------------------------------------------------------
diff --git a/drivers/webp/enc/cost.c b/drivers/webp/enc/cost.c
index 92e0cc713c..ae7fe01388 100644
--- a/drivers/webp/enc/cost.c
+++ b/drivers/webp/enc/cost.c
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Cost tables for level and modes
@@ -11,42 +13,6 @@
#include "./cost.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-//------------------------------------------------------------------------------
-// Boolean-cost cost table
-
-const uint16_t VP8EntropyCost[256] = {
- 1792, 1792, 1792, 1536, 1536, 1408, 1366, 1280, 1280, 1216,
- 1178, 1152, 1110, 1076, 1061, 1024, 1024, 992, 968, 951,
- 939, 911, 896, 878, 871, 854, 838, 820, 811, 794,
- 786, 768, 768, 752, 740, 732, 720, 709, 704, 690,
- 683, 672, 666, 655, 647, 640, 631, 622, 615, 607,
- 598, 592, 586, 576, 572, 564, 559, 555, 547, 541,
- 534, 528, 522, 512, 512, 504, 500, 494, 488, 483,
- 477, 473, 467, 461, 458, 452, 448, 443, 438, 434,
- 427, 424, 419, 415, 410, 406, 403, 399, 394, 390,
- 384, 384, 377, 374, 370, 366, 362, 359, 355, 351,
- 347, 342, 342, 336, 333, 330, 326, 323, 320, 316,
- 312, 308, 305, 302, 299, 296, 293, 288, 287, 283,
- 280, 277, 274, 272, 268, 266, 262, 256, 256, 256,
- 251, 248, 245, 242, 240, 237, 234, 232, 228, 226,
- 223, 221, 218, 216, 214, 211, 208, 205, 203, 201,
- 198, 196, 192, 191, 188, 187, 183, 181, 179, 176,
- 175, 171, 171, 168, 165, 163, 160, 159, 156, 154,
- 152, 150, 148, 146, 144, 142, 139, 138, 135, 133,
- 131, 128, 128, 125, 123, 121, 119, 117, 115, 113,
- 111, 110, 107, 105, 103, 102, 100, 98, 96, 94,
- 92, 91, 89, 86, 86, 83, 82, 80, 77, 76,
- 74, 73, 71, 69, 67, 66, 64, 63, 61, 59,
- 57, 55, 54, 52, 51, 49, 47, 46, 44, 43,
- 41, 40, 38, 36, 35, 33, 32, 30, 29, 27,
- 25, 24, 22, 21, 19, 18, 16, 15, 13, 12,
- 10, 9, 7, 6, 4, 3
-};
-
//------------------------------------------------------------------------------
// Level cost tables
@@ -73,267 +39,6 @@ const uint16_t VP8LevelCodes[MAX_VARIABLE_LEVEL][2] = {
{0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x153}
};
-// fixed costs for coding levels, deduce from the coding tree.
-// This is only the part that doesn't depend on the probability state.
-const uint16_t VP8LevelFixedCosts[2048] = {
- 0, 256, 256, 256, 256, 432, 618, 630,
- 731, 640, 640, 828, 901, 948, 1021, 1101,
- 1174, 1221, 1294, 1042, 1085, 1115, 1158, 1202,
- 1245, 1275, 1318, 1337, 1380, 1410, 1453, 1497,
- 1540, 1570, 1613, 1280, 1295, 1317, 1332, 1358,
- 1373, 1395, 1410, 1454, 1469, 1491, 1506, 1532,
- 1547, 1569, 1584, 1601, 1616, 1638, 1653, 1679,
- 1694, 1716, 1731, 1775, 1790, 1812, 1827, 1853,
- 1868, 1890, 1905, 1727, 1733, 1742, 1748, 1759,
- 1765, 1774, 1780, 1800, 1806, 1815, 1821, 1832,
- 1838, 1847, 1853, 1878, 1884, 1893, 1899, 1910,
- 1916, 1925, 1931, 1951, 1957, 1966, 1972, 1983,
- 1989, 1998, 2004, 2027, 2033, 2042, 2048, 2059,
- 2065, 2074, 2080, 2100, 2106, 2115, 2121, 2132,
- 2138, 2147, 2153, 2178, 2184, 2193, 2199, 2210,
- 2216, 2225, 2231, 2251, 2257, 2266, 2272, 2283,
- 2289, 2298, 2304, 2168, 2174, 2183, 2189, 2200,
- 2206, 2215, 2221, 2241, 2247, 2256, 2262, 2273,
- 2279, 2288, 2294, 2319, 2325, 2334, 2340, 2351,
- 2357, 2366, 2372, 2392, 2398, 2407, 2413, 2424,
- 2430, 2439, 2445, 2468, 2474, 2483, 2489, 2500,
- 2506, 2515, 2521, 2541, 2547, 2556, 2562, 2573,
- 2579, 2588, 2594, 2619, 2625, 2634, 2640, 2651,
- 2657, 2666, 2672, 2692, 2698, 2707, 2713, 2724,
- 2730, 2739, 2745, 2540, 2546, 2555, 2561, 2572,
- 2578, 2587, 2593, 2613, 2619, 2628, 2634, 2645,
- 2651, 2660, 2666, 2691, 2697, 2706, 2712, 2723,
- 2729, 2738, 2744, 2764, 2770, 2779, 2785, 2796,
- 2802, 2811, 2817, 2840, 2846, 2855, 2861, 2872,
- 2878, 2887, 2893, 2913, 2919, 2928, 2934, 2945,
- 2951, 2960, 2966, 2991, 2997, 3006, 3012, 3023,
- 3029, 3038, 3044, 3064, 3070, 3079, 3085, 3096,
- 3102, 3111, 3117, 2981, 2987, 2996, 3002, 3013,
- 3019, 3028, 3034, 3054, 3060, 3069, 3075, 3086,
- 3092, 3101, 3107, 3132, 3138, 3147, 3153, 3164,
- 3170, 3179, 3185, 3205, 3211, 3220, 3226, 3237,
- 3243, 3252, 3258, 3281, 3287, 3296, 3302, 3313,
- 3319, 3328, 3334, 3354, 3360, 3369, 3375, 3386,
- 3392, 3401, 3407, 3432, 3438, 3447, 3453, 3464,
- 3470, 3479, 3485, 3505, 3511, 3520, 3526, 3537,
- 3543, 3552, 3558, 2816, 2822, 2831, 2837, 2848,
- 2854, 2863, 2869, 2889, 2895, 2904, 2910, 2921,
- 2927, 2936, 2942, 2967, 2973, 2982, 2988, 2999,
- 3005, 3014, 3020, 3040, 3046, 3055, 3061, 3072,
- 3078, 3087, 3093, 3116, 3122, 3131, 3137, 3148,
- 3154, 3163, 3169, 3189, 3195, 3204, 3210, 3221,
- 3227, 3236, 3242, 3267, 3273, 3282, 3288, 3299,
- 3305, 3314, 3320, 3340, 3346, 3355, 3361, 3372,
- 3378, 3387, 3393, 3257, 3263, 3272, 3278, 3289,
- 3295, 3304, 3310, 3330, 3336, 3345, 3351, 3362,
- 3368, 3377, 3383, 3408, 3414, 3423, 3429, 3440,
- 3446, 3455, 3461, 3481, 3487, 3496, 3502, 3513,
- 3519, 3528, 3534, 3557, 3563, 3572, 3578, 3589,
- 3595, 3604, 3610, 3630, 3636, 3645, 3651, 3662,
- 3668, 3677, 3683, 3708, 3714, 3723, 3729, 3740,
- 3746, 3755, 3761, 3781, 3787, 3796, 3802, 3813,
- 3819, 3828, 3834, 3629, 3635, 3644, 3650, 3661,
- 3667, 3676, 3682, 3702, 3708, 3717, 3723, 3734,
- 3740, 3749, 3755, 3780, 3786, 3795, 3801, 3812,
- 3818, 3827, 3833, 3853, 3859, 3868, 3874, 3885,
- 3891, 3900, 3906, 3929, 3935, 3944, 3950, 3961,
- 3967, 3976, 3982, 4002, 4008, 4017, 4023, 4034,
- 4040, 4049, 4055, 4080, 4086, 4095, 4101, 4112,
- 4118, 4127, 4133, 4153, 4159, 4168, 4174, 4185,
- 4191, 4200, 4206, 4070, 4076, 4085, 4091, 4102,
- 4108, 4117, 4123, 4143, 4149, 4158, 4164, 4175,
- 4181, 4190, 4196, 4221, 4227, 4236, 4242, 4253,
- 4259, 4268, 4274, 4294, 4300, 4309, 4315, 4326,
- 4332, 4341, 4347, 4370, 4376, 4385, 4391, 4402,
- 4408, 4417, 4423, 4443, 4449, 4458, 4464, 4475,
- 4481, 4490, 4496, 4521, 4527, 4536, 4542, 4553,
- 4559, 4568, 4574, 4594, 4600, 4609, 4615, 4626,
- 4632, 4641, 4647, 3515, 3521, 3530, 3536, 3547,
- 3553, 3562, 3568, 3588, 3594, 3603, 3609, 3620,
- 3626, 3635, 3641, 3666, 3672, 3681, 3687, 3698,
- 3704, 3713, 3719, 3739, 3745, 3754, 3760, 3771,
- 3777, 3786, 3792, 3815, 3821, 3830, 3836, 3847,
- 3853, 3862, 3868, 3888, 3894, 3903, 3909, 3920,
- 3926, 3935, 3941, 3966, 3972, 3981, 3987, 3998,
- 4004, 4013, 4019, 4039, 4045, 4054, 4060, 4071,
- 4077, 4086, 4092, 3956, 3962, 3971, 3977, 3988,
- 3994, 4003, 4009, 4029, 4035, 4044, 4050, 4061,
- 4067, 4076, 4082, 4107, 4113, 4122, 4128, 4139,
- 4145, 4154, 4160, 4180, 4186, 4195, 4201, 4212,
- 4218, 4227, 4233, 4256, 4262, 4271, 4277, 4288,
- 4294, 4303, 4309, 4329, 4335, 4344, 4350, 4361,
- 4367, 4376, 4382, 4407, 4413, 4422, 4428, 4439,
- 4445, 4454, 4460, 4480, 4486, 4495, 4501, 4512,
- 4518, 4527, 4533, 4328, 4334, 4343, 4349, 4360,
- 4366, 4375, 4381, 4401, 4407, 4416, 4422, 4433,
- 4439, 4448, 4454, 4479, 4485, 4494, 4500, 4511,
- 4517, 4526, 4532, 4552, 4558, 4567, 4573, 4584,
- 4590, 4599, 4605, 4628, 4634, 4643, 4649, 4660,
- 4666, 4675, 4681, 4701, 4707, 4716, 4722, 4733,
- 4739, 4748, 4754, 4779, 4785, 4794, 4800, 4811,
- 4817, 4826, 4832, 4852, 4858, 4867, 4873, 4884,
- 4890, 4899, 4905, 4769, 4775, 4784, 4790, 4801,
- 4807, 4816, 4822, 4842, 4848, 4857, 4863, 4874,
- 4880, 4889, 4895, 4920, 4926, 4935, 4941, 4952,
- 4958, 4967, 4973, 4993, 4999, 5008, 5014, 5025,
- 5031, 5040, 5046, 5069, 5075, 5084, 5090, 5101,
- 5107, 5116, 5122, 5142, 5148, 5157, 5163, 5174,
- 5180, 5189, 5195, 5220, 5226, 5235, 5241, 5252,
- 5258, 5267, 5273, 5293, 5299, 5308, 5314, 5325,
- 5331, 5340, 5346, 4604, 4610, 4619, 4625, 4636,
- 4642, 4651, 4657, 4677, 4683, 4692, 4698, 4709,
- 4715, 4724, 4730, 4755, 4761, 4770, 4776, 4787,
- 4793, 4802, 4808, 4828, 4834, 4843, 4849, 4860,
- 4866, 4875, 4881, 4904, 4910, 4919, 4925, 4936,
- 4942, 4951, 4957, 4977, 4983, 4992, 4998, 5009,
- 5015, 5024, 5030, 5055, 5061, 5070, 5076, 5087,
- 5093, 5102, 5108, 5128, 5134, 5143, 5149, 5160,
- 5166, 5175, 5181, 5045, 5051, 5060, 5066, 5077,
- 5083, 5092, 5098, 5118, 5124, 5133, 5139, 5150,
- 5156, 5165, 5171, 5196, 5202, 5211, 5217, 5228,
- 5234, 5243, 5249, 5269, 5275, 5284, 5290, 5301,
- 5307, 5316, 5322, 5345, 5351, 5360, 5366, 5377,
- 5383, 5392, 5398, 5418, 5424, 5433, 5439, 5450,
- 5456, 5465, 5471, 5496, 5502, 5511, 5517, 5528,
- 5534, 5543, 5549, 5569, 5575, 5584, 5590, 5601,
- 5607, 5616, 5622, 5417, 5423, 5432, 5438, 5449,
- 5455, 5464, 5470, 5490, 5496, 5505, 5511, 5522,
- 5528, 5537, 5543, 5568, 5574, 5583, 5589, 5600,
- 5606, 5615, 5621, 5641, 5647, 5656, 5662, 5673,
- 5679, 5688, 5694, 5717, 5723, 5732, 5738, 5749,
- 5755, 5764, 5770, 5790, 5796, 5805, 5811, 5822,
- 5828, 5837, 5843, 5868, 5874, 5883, 5889, 5900,
- 5906, 5915, 5921, 5941, 5947, 5956, 5962, 5973,
- 5979, 5988, 5994, 5858, 5864, 5873, 5879, 5890,
- 5896, 5905, 5911, 5931, 5937, 5946, 5952, 5963,
- 5969, 5978, 5984, 6009, 6015, 6024, 6030, 6041,
- 6047, 6056, 6062, 6082, 6088, 6097, 6103, 6114,
- 6120, 6129, 6135, 6158, 6164, 6173, 6179, 6190,
- 6196, 6205, 6211, 6231, 6237, 6246, 6252, 6263,
- 6269, 6278, 6284, 6309, 6315, 6324, 6330, 6341,
- 6347, 6356, 6362, 6382, 6388, 6397, 6403, 6414,
- 6420, 6429, 6435, 3515, 3521, 3530, 3536, 3547,
- 3553, 3562, 3568, 3588, 3594, 3603, 3609, 3620,
- 3626, 3635, 3641, 3666, 3672, 3681, 3687, 3698,
- 3704, 3713, 3719, 3739, 3745, 3754, 3760, 3771,
- 3777, 3786, 3792, 3815, 3821, 3830, 3836, 3847,
- 3853, 3862, 3868, 3888, 3894, 3903, 3909, 3920,
- 3926, 3935, 3941, 3966, 3972, 3981, 3987, 3998,
- 4004, 4013, 4019, 4039, 4045, 4054, 4060, 4071,
- 4077, 4086, 4092, 3956, 3962, 3971, 3977, 3988,
- 3994, 4003, 4009, 4029, 4035, 4044, 4050, 4061,
- 4067, 4076, 4082, 4107, 4113, 4122, 4128, 4139,
- 4145, 4154, 4160, 4180, 4186, 4195, 4201, 4212,
- 4218, 4227, 4233, 4256, 4262, 4271, 4277, 4288,
- 4294, 4303, 4309, 4329, 4335, 4344, 4350, 4361,
- 4367, 4376, 4382, 4407, 4413, 4422, 4428, 4439,
- 4445, 4454, 4460, 4480, 4486, 4495, 4501, 4512,
- 4518, 4527, 4533, 4328, 4334, 4343, 4349, 4360,
- 4366, 4375, 4381, 4401, 4407, 4416, 4422, 4433,
- 4439, 4448, 4454, 4479, 4485, 4494, 4500, 4511,
- 4517, 4526, 4532, 4552, 4558, 4567, 4573, 4584,
- 4590, 4599, 4605, 4628, 4634, 4643, 4649, 4660,
- 4666, 4675, 4681, 4701, 4707, 4716, 4722, 4733,
- 4739, 4748, 4754, 4779, 4785, 4794, 4800, 4811,
- 4817, 4826, 4832, 4852, 4858, 4867, 4873, 4884,
- 4890, 4899, 4905, 4769, 4775, 4784, 4790, 4801,
- 4807, 4816, 4822, 4842, 4848, 4857, 4863, 4874,
- 4880, 4889, 4895, 4920, 4926, 4935, 4941, 4952,
- 4958, 4967, 4973, 4993, 4999, 5008, 5014, 5025,
- 5031, 5040, 5046, 5069, 5075, 5084, 5090, 5101,
- 5107, 5116, 5122, 5142, 5148, 5157, 5163, 5174,
- 5180, 5189, 5195, 5220, 5226, 5235, 5241, 5252,
- 5258, 5267, 5273, 5293, 5299, 5308, 5314, 5325,
- 5331, 5340, 5346, 4604, 4610, 4619, 4625, 4636,
- 4642, 4651, 4657, 4677, 4683, 4692, 4698, 4709,
- 4715, 4724, 4730, 4755, 4761, 4770, 4776, 4787,
- 4793, 4802, 4808, 4828, 4834, 4843, 4849, 4860,
- 4866, 4875, 4881, 4904, 4910, 4919, 4925, 4936,
- 4942, 4951, 4957, 4977, 4983, 4992, 4998, 5009,
- 5015, 5024, 5030, 5055, 5061, 5070, 5076, 5087,
- 5093, 5102, 5108, 5128, 5134, 5143, 5149, 5160,
- 5166, 5175, 5181, 5045, 5051, 5060, 5066, 5077,
- 5083, 5092, 5098, 5118, 5124, 5133, 5139, 5150,
- 5156, 5165, 5171, 5196, 5202, 5211, 5217, 5228,
- 5234, 5243, 5249, 5269, 5275, 5284, 5290, 5301,
- 5307, 5316, 5322, 5345, 5351, 5360, 5366, 5377,
- 5383, 5392, 5398, 5418, 5424, 5433, 5439, 5450,
- 5456, 5465, 5471, 5496, 5502, 5511, 5517, 5528,
- 5534, 5543, 5549, 5569, 5575, 5584, 5590, 5601,
- 5607, 5616, 5622, 5417, 5423, 5432, 5438, 5449,
- 5455, 5464, 5470, 5490, 5496, 5505, 5511, 5522,
- 5528, 5537, 5543, 5568, 5574, 5583, 5589, 5600,
- 5606, 5615, 5621, 5641, 5647, 5656, 5662, 5673,
- 5679, 5688, 5694, 5717, 5723, 5732, 5738, 5749,
- 5755, 5764, 5770, 5790, 5796, 5805, 5811, 5822,
- 5828, 5837, 5843, 5868, 5874, 5883, 5889, 5900,
- 5906, 5915, 5921, 5941, 5947, 5956, 5962, 5973,
- 5979, 5988, 5994, 5858, 5864, 5873, 5879, 5890,
- 5896, 5905, 5911, 5931, 5937, 5946, 5952, 5963,
- 5969, 5978, 5984, 6009, 6015, 6024, 6030, 6041,
- 6047, 6056, 6062, 6082, 6088, 6097, 6103, 6114,
- 6120, 6129, 6135, 6158, 6164, 6173, 6179, 6190,
- 6196, 6205, 6211, 6231, 6237, 6246, 6252, 6263,
- 6269, 6278, 6284, 6309, 6315, 6324, 6330, 6341,
- 6347, 6356, 6362, 6382, 6388, 6397, 6403, 6414,
- 6420, 6429, 6435, 5303, 5309, 5318, 5324, 5335,
- 5341, 5350, 5356, 5376, 5382, 5391, 5397, 5408,
- 5414, 5423, 5429, 5454, 5460, 5469, 5475, 5486,
- 5492, 5501, 5507, 5527, 5533, 5542, 5548, 5559,
- 5565, 5574, 5580, 5603, 5609, 5618, 5624, 5635,
- 5641, 5650, 5656, 5676, 5682, 5691, 5697, 5708,
- 5714, 5723, 5729, 5754, 5760, 5769, 5775, 5786,
- 5792, 5801, 5807, 5827, 5833, 5842, 5848, 5859,
- 5865, 5874, 5880, 5744, 5750, 5759, 5765, 5776,
- 5782, 5791, 5797, 5817, 5823, 5832, 5838, 5849,
- 5855, 5864, 5870, 5895, 5901, 5910, 5916, 5927,
- 5933, 5942, 5948, 5968, 5974, 5983, 5989, 6000,
- 6006, 6015, 6021, 6044, 6050, 6059, 6065, 6076,
- 6082, 6091, 6097, 6117, 6123, 6132, 6138, 6149,
- 6155, 6164, 6170, 6195, 6201, 6210, 6216, 6227,
- 6233, 6242, 6248, 6268, 6274, 6283, 6289, 6300,
- 6306, 6315, 6321, 6116, 6122, 6131, 6137, 6148,
- 6154, 6163, 6169, 6189, 6195, 6204, 6210, 6221,
- 6227, 6236, 6242, 6267, 6273, 6282, 6288, 6299,
- 6305, 6314, 6320, 6340, 6346, 6355, 6361, 6372,
- 6378, 6387, 6393, 6416, 6422, 6431, 6437, 6448,
- 6454, 6463, 6469, 6489, 6495, 6504, 6510, 6521,
- 6527, 6536, 6542, 6567, 6573, 6582, 6588, 6599,
- 6605, 6614, 6620, 6640, 6646, 6655, 6661, 6672,
- 6678, 6687, 6693, 6557, 6563, 6572, 6578, 6589,
- 6595, 6604, 6610, 6630, 6636, 6645, 6651, 6662,
- 6668, 6677, 6683, 6708, 6714, 6723, 6729, 6740,
- 6746, 6755, 6761, 6781, 6787, 6796, 6802, 6813,
- 6819, 6828, 6834, 6857, 6863, 6872, 6878, 6889,
- 6895, 6904, 6910, 6930, 6936, 6945, 6951, 6962,
- 6968, 6977, 6983, 7008, 7014, 7023, 7029, 7040,
- 7046, 7055, 7061, 7081, 7087, 7096, 7102, 7113,
- 7119, 7128, 7134, 6392, 6398, 6407, 6413, 6424,
- 6430, 6439, 6445, 6465, 6471, 6480, 6486, 6497,
- 6503, 6512, 6518, 6543, 6549, 6558, 6564, 6575,
- 6581, 6590, 6596, 6616, 6622, 6631, 6637, 6648,
- 6654, 6663, 6669, 6692, 6698, 6707, 6713, 6724,
- 6730, 6739, 6745, 6765, 6771, 6780, 6786, 6797,
- 6803, 6812, 6818, 6843, 6849, 6858, 6864, 6875,
- 6881, 6890, 6896, 6916, 6922, 6931, 6937, 6948,
- 6954, 6963, 6969, 6833, 6839, 6848, 6854, 6865,
- 6871, 6880, 6886, 6906, 6912, 6921, 6927, 6938,
- 6944, 6953, 6959, 6984, 6990, 6999, 7005, 7016,
- 7022, 7031, 7037, 7057, 7063, 7072, 7078, 7089,
- 7095, 7104, 7110, 7133, 7139, 7148, 7154, 7165,
- 7171, 7180, 7186, 7206, 7212, 7221, 7227, 7238,
- 7244, 7253, 7259, 7284, 7290, 7299, 7305, 7316,
- 7322, 7331, 7337, 7357, 7363, 7372, 7378, 7389,
- 7395, 7404, 7410, 7205, 7211, 7220, 7226, 7237,
- 7243, 7252, 7258, 7278, 7284, 7293, 7299, 7310,
- 7316, 7325, 7331, 7356, 7362, 7371, 7377, 7388,
- 7394, 7403, 7409, 7429, 7435, 7444, 7450, 7461,
- 7467, 7476, 7482, 7505, 7511, 7520, 7526, 7537,
- 7543, 7552, 7558, 7578, 7584, 7593, 7599, 7610,
- 7616, 7625, 7631, 7656, 7662, 7671, 7677, 7688,
- 7694, 7703, 7709, 7729, 7735, 7744, 7750, 7761
-};
-
static int VariableLevelCost(int level, const uint8_t probas[NUM_PROBAS]) {
int pattern = VP8LevelCodes[level - 1][0];
int bits = VP8LevelCodes[level - 1][1];
@@ -352,19 +57,21 @@ static int VariableLevelCost(int level, const uint8_t probas[NUM_PROBAS]) {
//------------------------------------------------------------------------------
// Pre-calc level costs once for all
-void VP8CalculateLevelCosts(VP8Proba* const proba) {
+void VP8CalculateLevelCosts(VP8EncProba* const proba) {
int ctype, band, ctx;
if (!proba->dirty_) return; // nothing to do.
for (ctype = 0; ctype < NUM_TYPES; ++ctype) {
+ int n;
for (band = 0; band < NUM_BANDS; ++band) {
- for(ctx = 0; ctx < NUM_CTX; ++ctx) {
+ for (ctx = 0; ctx < NUM_CTX; ++ctx) {
const uint8_t* const p = proba->coeffs_[ctype][band][ctx];
uint16_t* const table = proba->level_cost_[ctype][band][ctx];
- const int cost_base = VP8BitCost(1, p[1]);
+ const int cost0 = (ctx > 0) ? VP8BitCost(1, p[0]) : 0;
+ const int cost_base = VP8BitCost(1, p[1]) + cost0;
int v;
- table[0] = VP8BitCost(0, p[1]);
+ table[0] = VP8BitCost(0, p[1]) + cost0;
for (v = 1; v <= MAX_VARIABLE_LEVEL; ++v) {
table[v] = cost_base + VariableLevelCost(v, p);
}
@@ -372,6 +79,12 @@ void VP8CalculateLevelCosts(VP8Proba* const proba) {
// actually constant.
}
}
+ for (n = 0; n < 16; ++n) { // replicate bands. We don't need to sentinel.
+ for (ctx = 0; ctx < NUM_CTX; ++ctx) {
+ proba->remapped_costs_[ctype][n][ctx] =
+ proba->level_cost_[ctype][VP8EncBands[n]][ctx];
+ }
+ }
}
proba->dirty_ = 0;
}
@@ -385,110 +98,257 @@ const uint16_t VP8FixedCostsUV[4] = { 302, 984, 439, 642 };
// note: these values include the fixed VP8BitCost(1, 145) mode selection cost.
const uint16_t VP8FixedCostsI16[4] = { 663, 919, 872, 919 };
const uint16_t VP8FixedCostsI4[NUM_BMODES][NUM_BMODES][NUM_BMODES] = {
- { { 251, 1362, 1934, 2085, 2314, 2230, 1839, 1988, 2437, 2348 },
- { 403, 680, 1507, 1519, 2060, 2005, 1992, 1914, 1924, 1733 },
- { 353, 1121, 973, 1895, 2060, 1787, 1671, 1516, 2012, 1868 },
- { 770, 852, 1581, 632, 1393, 1780, 1823, 1936, 1074, 1218 },
- { 510, 1270, 1467, 1319, 847, 1279, 1792, 2094, 1080, 1353 },
- { 488, 1322, 918, 1573, 1300, 883, 1814, 1752, 1756, 1502 },
- { 425, 992, 1820, 1514, 1843, 2440, 937, 1771, 1924, 1129 },
- { 363, 1248, 1257, 1970, 2194, 2385, 1569, 953, 1951, 1601 },
- { 723, 1257, 1631, 964, 963, 1508, 1697, 1824, 671, 1418 },
- { 635, 1038, 1573, 930, 1673, 1413, 1410, 1687, 1410, 749 } },
- { { 451, 613, 1345, 1702, 1870, 1716, 1728, 1766, 2190, 2310 },
- { 678, 453, 1171, 1443, 1925, 1831, 2045, 1781, 1887, 1602 },
- { 711, 666, 674, 1718, 1910, 1493, 1775, 1193, 2325, 2325 },
- { 883, 854, 1583, 542, 1800, 1878, 1664, 2149, 1207, 1087 },
- { 669, 994, 1248, 1122, 949, 1179, 1376, 1729, 1070, 1244 },
- { 715, 1026, 715, 1350, 1430, 930, 1717, 1296, 1479, 1479 },
- { 544, 841, 1656, 1450, 2094, 3883, 1010, 1759, 2076, 809 },
- { 610, 855, 957, 1553, 2067, 1561, 1704, 824, 2066, 1226 },
- { 833, 960, 1416, 819, 1277, 1619, 1501, 1617, 757, 1182 },
- { 711, 964, 1252, 879, 1441, 1828, 1508, 1636, 1594, 734 } },
- { { 605, 764, 734, 1713, 1747, 1192, 1819, 1353, 1877, 2392 },
- { 866, 641, 586, 1622, 2072, 1431, 1888, 1346, 2189, 1764 },
- { 901, 851, 456, 2165, 2281, 1405, 1739, 1193, 2183, 2443 },
- { 770, 1045, 952, 1078, 1342, 1191, 1436, 1063, 1303, 995 },
- { 901, 1086, 727, 1170, 884, 1105, 1267, 1401, 1739, 1337 },
- { 951, 1162, 595, 1488, 1388, 703, 1790, 1366, 2057, 1724 },
- { 534, 986, 1273, 1987, 3273, 1485, 1024, 1399, 1583, 866 },
- { 699, 1182, 695, 1978, 1726, 1986, 1326, 714, 1750, 1672 },
- { 951, 1217, 1209, 920, 1062, 1441, 1548, 999, 952, 932 },
- { 733, 1284, 784, 1256, 1557, 1098, 1257, 1357, 1414, 908 } },
- { { 316, 1075, 1653, 1220, 2145, 2051, 1730, 2131, 1884, 1790 },
- { 745, 516, 1404, 894, 1599, 2375, 2013, 2105, 1475, 1381 },
- { 516, 729, 1088, 1319, 1637, 3426, 1636, 1275, 1531, 1453 },
- { 894, 943, 2138, 468, 1704, 2259, 2069, 1763, 1266, 1158 },
- { 605, 1025, 1235, 871, 1170, 1767, 1493, 1500, 1104, 1258 },
- { 739, 826, 1207, 1151, 1412, 846, 1305, 2726, 1014, 1569 },
- { 558, 825, 1820, 1398, 3344, 1556, 1218, 1550, 1228, 878 },
- { 429, 951, 1089, 1816, 3861, 3861, 1556, 969, 1568, 1828 },
- { 883, 961, 1752, 769, 1468, 1810, 2081, 2346, 613, 1298 },
- { 803, 895, 1372, 641, 1303, 1708, 1686, 1700, 1306, 1033 } },
- { { 439, 1267, 1270, 1579, 963, 1193, 1723, 1729, 1198, 1993 },
- { 705, 725, 1029, 1153, 1176, 1103, 1821, 1567, 1259, 1574 },
- { 723, 859, 802, 1253, 972, 1202, 1407, 1665, 1520, 1674 },
- { 894, 960, 1254, 887, 1052, 1607, 1344, 1349, 865, 1150 },
- { 833, 1312, 1337, 1205, 572, 1288, 1414, 1529, 1088, 1430 },
- { 842, 1279, 1068, 1861, 862, 688, 1861, 1630, 1039, 1381 },
- { 766, 938, 1279, 1546, 3338, 1550, 1031, 1542, 1288, 640 },
- { 715, 1090, 835, 1609, 1100, 1100, 1603, 1019, 1102, 1617 },
- { 894, 1813, 1500, 1188, 789, 1194, 1491, 1919, 617, 1333 },
- { 610, 1076, 1644, 1281, 1283, 975, 1179, 1688, 1434, 889 } },
- { { 544, 971, 1146, 1849, 1221, 740, 1857, 1621, 1683, 2430 },
- { 723, 705, 961, 1371, 1426, 821, 2081, 2079, 1839, 1380 },
- { 783, 857, 703, 2145, 1419, 814, 1791, 1310, 1609, 2206 },
- { 997, 1000, 1153, 792, 1229, 1162, 1810, 1418, 942, 979 },
- { 901, 1226, 883, 1289, 793, 715, 1904, 1649, 1319, 3108 },
- { 979, 1478, 782, 2216, 1454, 455, 3092, 1591, 1997, 1664 },
- { 663, 1110, 1504, 1114, 1522, 3311, 676, 1522, 1530, 1024 },
- { 605, 1138, 1153, 1314, 1569, 1315, 1157, 804, 1574, 1320 },
- { 770, 1216, 1218, 1227, 869, 1384, 1232, 1375, 834, 1239 },
- { 775, 1007, 843, 1216, 1225, 1074, 2527, 1479, 1149, 975 } },
- { { 477, 817, 1309, 1439, 1708, 1454, 1159, 1241, 1945, 1672 },
- { 577, 796, 1112, 1271, 1618, 1458, 1087, 1345, 1831, 1265 },
- { 663, 776, 753, 1940, 1690, 1690, 1227, 1097, 3149, 1361 },
- { 766, 1299, 1744, 1161, 1565, 1106, 1045, 1230, 1232, 707 },
- { 915, 1026, 1404, 1182, 1184, 851, 1428, 2425, 1043, 789 },
- { 883, 1456, 790, 1082, 1086, 985, 1083, 1484, 1238, 1160 },
- { 507, 1345, 2261, 1995, 1847, 3636, 653, 1761, 2287, 933 },
- { 553, 1193, 1470, 2057, 2059, 2059, 833, 779, 2058, 1263 },
- { 766, 1275, 1515, 1039, 957, 1554, 1286, 1540, 1289, 705 },
- { 499, 1378, 1496, 1385, 1850, 1850, 1044, 2465, 1515, 720 } },
- { { 553, 930, 978, 2077, 1968, 1481, 1457, 761, 1957, 2362 },
- { 694, 864, 905, 1720, 1670, 1621, 1429, 718, 2125, 1477 },
- { 699, 968, 658, 3190, 2024, 1479, 1865, 750, 2060, 2320 },
- { 733, 1308, 1296, 1062, 1576, 1322, 1062, 1112, 1172, 816 },
- { 920, 927, 1052, 939, 947, 1156, 1152, 1073, 3056, 1268 },
- { 723, 1534, 711, 1547, 1294, 892, 1553, 928, 1815, 1561 },
- { 663, 1366, 1583, 2111, 1712, 3501, 522, 1155, 2130, 1133 },
- { 614, 1731, 1188, 2343, 1944, 3733, 1287, 487, 3546, 1758 },
- { 770, 1585, 1312, 826, 884, 2673, 1185, 1006, 1195, 1195 },
- { 758, 1333, 1273, 1023, 1621, 1162, 1351, 833, 1479, 862 } },
- { { 376, 1193, 1446, 1149, 1545, 1577, 1870, 1789, 1175, 1823 },
- { 803, 633, 1136, 1058, 1350, 1323, 1598, 2247, 1072, 1252 },
- { 614, 1048, 943, 981, 1152, 1869, 1461, 1020, 1618, 1618 },
- { 1107, 1085, 1282, 592, 1779, 1933, 1648, 2403, 691, 1246 },
- { 851, 1309, 1223, 1243, 895, 1593, 1792, 2317, 627, 1076 },
- { 770, 1216, 1030, 1125, 921, 981, 1629, 1131, 1049, 1646 },
- { 626, 1469, 1456, 1081, 1489, 3278, 981, 1232, 1498, 733 },
- { 617, 1201, 812, 1220, 1476, 1476, 1478, 970, 1228, 1488 },
- { 1179, 1393, 1540, 999, 1243, 1503, 1916, 1925, 414, 1614 },
- { 943, 1088, 1490, 682, 1112, 1372, 1756, 1505, 966, 966 } },
- { { 322, 1142, 1589, 1396, 2144, 1859, 1359, 1925, 2084, 1518 },
- { 617, 625, 1241, 1234, 2121, 1615, 1524, 1858, 1720, 1004 },
- { 553, 851, 786, 1299, 1452, 1560, 1372, 1561, 1967, 1713 },
- { 770, 977, 1396, 568, 1893, 1639, 1540, 2108, 1430, 1013 },
- { 684, 1120, 1375, 982, 930, 2719, 1638, 1643, 933, 993 },
- { 553, 1103, 996, 1356, 1361, 1005, 1507, 1761, 1184, 1268 },
- { 419, 1247, 1537, 1554, 1817, 3606, 1026, 1666, 1829, 923 },
- { 439, 1139, 1101, 1257, 3710, 1922, 1205, 1040, 1931, 1529 },
- { 979, 935, 1269, 847, 1202, 1286, 1530, 1535, 827, 1036 },
- { 516, 1378, 1569, 1110, 1798, 1798, 1198, 2199, 1543, 712 } },
+ { { 40, 1151, 1723, 1874, 2103, 2019, 1628, 1777, 2226, 2137 },
+ { 192, 469, 1296, 1308, 1849, 1794, 1781, 1703, 1713, 1522 },
+ { 142, 910, 762, 1684, 1849, 1576, 1460, 1305, 1801, 1657 },
+ { 559, 641, 1370, 421, 1182, 1569, 1612, 1725, 863, 1007 },
+ { 299, 1059, 1256, 1108, 636, 1068, 1581, 1883, 869, 1142 },
+ { 277, 1111, 707, 1362, 1089, 672, 1603, 1541, 1545, 1291 },
+ { 214, 781, 1609, 1303, 1632, 2229, 726, 1560, 1713, 918 },
+ { 152, 1037, 1046, 1759, 1983, 2174, 1358, 742, 1740, 1390 },
+ { 512, 1046, 1420, 753, 752, 1297, 1486, 1613, 460, 1207 },
+ { 424, 827, 1362, 719, 1462, 1202, 1199, 1476, 1199, 538 } },
+ { { 240, 402, 1134, 1491, 1659, 1505, 1517, 1555, 1979, 2099 },
+ { 467, 242, 960, 1232, 1714, 1620, 1834, 1570, 1676, 1391 },
+ { 500, 455, 463, 1507, 1699, 1282, 1564, 982, 2114, 2114 },
+ { 672, 643, 1372, 331, 1589, 1667, 1453, 1938, 996, 876 },
+ { 458, 783, 1037, 911, 738, 968, 1165, 1518, 859, 1033 },
+ { 504, 815, 504, 1139, 1219, 719, 1506, 1085, 1268, 1268 },
+ { 333, 630, 1445, 1239, 1883, 3672, 799, 1548, 1865, 598 },
+ { 399, 644, 746, 1342, 1856, 1350, 1493, 613, 1855, 1015 },
+ { 622, 749, 1205, 608, 1066, 1408, 1290, 1406, 546, 971 },
+ { 500, 753, 1041, 668, 1230, 1617, 1297, 1425, 1383, 523 } },
+ { { 394, 553, 523, 1502, 1536, 981, 1608, 1142, 1666, 2181 },
+ { 655, 430, 375, 1411, 1861, 1220, 1677, 1135, 1978, 1553 },
+ { 690, 640, 245, 1954, 2070, 1194, 1528, 982, 1972, 2232 },
+ { 559, 834, 741, 867, 1131, 980, 1225, 852, 1092, 784 },
+ { 690, 875, 516, 959, 673, 894, 1056, 1190, 1528, 1126 },
+ { 740, 951, 384, 1277, 1177, 492, 1579, 1155, 1846, 1513 },
+ { 323, 775, 1062, 1776, 3062, 1274, 813, 1188, 1372, 655 },
+ { 488, 971, 484, 1767, 1515, 1775, 1115, 503, 1539, 1461 },
+ { 740, 1006, 998, 709, 851, 1230, 1337, 788, 741, 721 },
+ { 522, 1073, 573, 1045, 1346, 887, 1046, 1146, 1203, 697 } },
+ { { 105, 864, 1442, 1009, 1934, 1840, 1519, 1920, 1673, 1579 },
+ { 534, 305, 1193, 683, 1388, 2164, 1802, 1894, 1264, 1170 },
+ { 305, 518, 877, 1108, 1426, 3215, 1425, 1064, 1320, 1242 },
+ { 683, 732, 1927, 257, 1493, 2048, 1858, 1552, 1055, 947 },
+ { 394, 814, 1024, 660, 959, 1556, 1282, 1289, 893, 1047 },
+ { 528, 615, 996, 940, 1201, 635, 1094, 2515, 803, 1358 },
+ { 347, 614, 1609, 1187, 3133, 1345, 1007, 1339, 1017, 667 },
+ { 218, 740, 878, 1605, 3650, 3650, 1345, 758, 1357, 1617 },
+ { 672, 750, 1541, 558, 1257, 1599, 1870, 2135, 402, 1087 },
+ { 592, 684, 1161, 430, 1092, 1497, 1475, 1489, 1095, 822 } },
+ { { 228, 1056, 1059, 1368, 752, 982, 1512, 1518, 987, 1782 },
+ { 494, 514, 818, 942, 965, 892, 1610, 1356, 1048, 1363 },
+ { 512, 648, 591, 1042, 761, 991, 1196, 1454, 1309, 1463 },
+ { 683, 749, 1043, 676, 841, 1396, 1133, 1138, 654, 939 },
+ { 622, 1101, 1126, 994, 361, 1077, 1203, 1318, 877, 1219 },
+ { 631, 1068, 857, 1650, 651, 477, 1650, 1419, 828, 1170 },
+ { 555, 727, 1068, 1335, 3127, 1339, 820, 1331, 1077, 429 },
+ { 504, 879, 624, 1398, 889, 889, 1392, 808, 891, 1406 },
+ { 683, 1602, 1289, 977, 578, 983, 1280, 1708, 406, 1122 },
+ { 399, 865, 1433, 1070, 1072, 764, 968, 1477, 1223, 678 } },
+ { { 333, 760, 935, 1638, 1010, 529, 1646, 1410, 1472, 2219 },
+ { 512, 494, 750, 1160, 1215, 610, 1870, 1868, 1628, 1169 },
+ { 572, 646, 492, 1934, 1208, 603, 1580, 1099, 1398, 1995 },
+ { 786, 789, 942, 581, 1018, 951, 1599, 1207, 731, 768 },
+ { 690, 1015, 672, 1078, 582, 504, 1693, 1438, 1108, 2897 },
+ { 768, 1267, 571, 2005, 1243, 244, 2881, 1380, 1786, 1453 },
+ { 452, 899, 1293, 903, 1311, 3100, 465, 1311, 1319, 813 },
+ { 394, 927, 942, 1103, 1358, 1104, 946, 593, 1363, 1109 },
+ { 559, 1005, 1007, 1016, 658, 1173, 1021, 1164, 623, 1028 },
+ { 564, 796, 632, 1005, 1014, 863, 2316, 1268, 938, 764 } },
+ { { 266, 606, 1098, 1228, 1497, 1243, 948, 1030, 1734, 1461 },
+ { 366, 585, 901, 1060, 1407, 1247, 876, 1134, 1620, 1054 },
+ { 452, 565, 542, 1729, 1479, 1479, 1016, 886, 2938, 1150 },
+ { 555, 1088, 1533, 950, 1354, 895, 834, 1019, 1021, 496 },
+ { 704, 815, 1193, 971, 973, 640, 1217, 2214, 832, 578 },
+ { 672, 1245, 579, 871, 875, 774, 872, 1273, 1027, 949 },
+ { 296, 1134, 2050, 1784, 1636, 3425, 442, 1550, 2076, 722 },
+ { 342, 982, 1259, 1846, 1848, 1848, 622, 568, 1847, 1052 },
+ { 555, 1064, 1304, 828, 746, 1343, 1075, 1329, 1078, 494 },
+ { 288, 1167, 1285, 1174, 1639, 1639, 833, 2254, 1304, 509 } },
+ { { 342, 719, 767, 1866, 1757, 1270, 1246, 550, 1746, 2151 },
+ { 483, 653, 694, 1509, 1459, 1410, 1218, 507, 1914, 1266 },
+ { 488, 757, 447, 2979, 1813, 1268, 1654, 539, 1849, 2109 },
+ { 522, 1097, 1085, 851, 1365, 1111, 851, 901, 961, 605 },
+ { 709, 716, 841, 728, 736, 945, 941, 862, 2845, 1057 },
+ { 512, 1323, 500, 1336, 1083, 681, 1342, 717, 1604, 1350 },
+ { 452, 1155, 1372, 1900, 1501, 3290, 311, 944, 1919, 922 },
+ { 403, 1520, 977, 2132, 1733, 3522, 1076, 276, 3335, 1547 },
+ { 559, 1374, 1101, 615, 673, 2462, 974, 795, 984, 984 },
+ { 547, 1122, 1062, 812, 1410, 951, 1140, 622, 1268, 651 } },
+ { { 165, 982, 1235, 938, 1334, 1366, 1659, 1578, 964, 1612 },
+ { 592, 422, 925, 847, 1139, 1112, 1387, 2036, 861, 1041 },
+ { 403, 837, 732, 770, 941, 1658, 1250, 809, 1407, 1407 },
+ { 896, 874, 1071, 381, 1568, 1722, 1437, 2192, 480, 1035 },
+ { 640, 1098, 1012, 1032, 684, 1382, 1581, 2106, 416, 865 },
+ { 559, 1005, 819, 914, 710, 770, 1418, 920, 838, 1435 },
+ { 415, 1258, 1245, 870, 1278, 3067, 770, 1021, 1287, 522 },
+ { 406, 990, 601, 1009, 1265, 1265, 1267, 759, 1017, 1277 },
+ { 968, 1182, 1329, 788, 1032, 1292, 1705, 1714, 203, 1403 },
+ { 732, 877, 1279, 471, 901, 1161, 1545, 1294, 755, 755 } },
+ { { 111, 931, 1378, 1185, 1933, 1648, 1148, 1714, 1873, 1307 },
+ { 406, 414, 1030, 1023, 1910, 1404, 1313, 1647, 1509, 793 },
+ { 342, 640, 575, 1088, 1241, 1349, 1161, 1350, 1756, 1502 },
+ { 559, 766, 1185, 357, 1682, 1428, 1329, 1897, 1219, 802 },
+ { 473, 909, 1164, 771, 719, 2508, 1427, 1432, 722, 782 },
+ { 342, 892, 785, 1145, 1150, 794, 1296, 1550, 973, 1057 },
+ { 208, 1036, 1326, 1343, 1606, 3395, 815, 1455, 1618, 712 },
+ { 228, 928, 890, 1046, 3499, 1711, 994, 829, 1720, 1318 },
+ { 768, 724, 1058, 636, 991, 1075, 1319, 1324, 616, 825 },
+ { 305, 1167, 1358, 899, 1587, 1587, 987, 1988, 1332, 501 } }
};
//------------------------------------------------------------------------------
+// helper functions for residuals struct VP8Residual.
+
+void VP8InitResidual(int first, int coeff_type,
+ VP8Encoder* const enc, VP8Residual* const res) {
+ res->coeff_type = coeff_type;
+ res->prob = enc->proba_.coeffs_[coeff_type];
+ res->stats = enc->proba_.stats_[coeff_type];
+ res->costs = enc->proba_.remapped_costs_[coeff_type];
+ res->first = first;
+}
+
+//------------------------------------------------------------------------------
+// Mode costs
+
+int VP8GetCostLuma4(VP8EncIterator* const it, const int16_t levels[16]) {
+ const int x = (it->i4_ & 3), y = (it->i4_ >> 2);
+ VP8Residual res;
+ VP8Encoder* const enc = it->enc_;
+ int R = 0;
+ int ctx;
+
+ VP8InitResidual(0, 3, enc, &res);
+ ctx = it->top_nz_[x] + it->left_nz_[y];
+ VP8SetResidualCoeffs(levels, &res);
+ R += VP8GetResidualCost(ctx, &res);
+ return R;
+}
+
+int VP8GetCostLuma16(VP8EncIterator* const it, const VP8ModeScore* const rd) {
+ VP8Residual res;
+ VP8Encoder* const enc = it->enc_;
+ int x, y;
+ int R = 0;
+
+ VP8IteratorNzToBytes(it); // re-import the non-zero context
+
+ // DC
+ VP8InitResidual(0, 1, enc, &res);
+ VP8SetResidualCoeffs(rd->y_dc_levels, &res);
+ R += VP8GetResidualCost(it->top_nz_[8] + it->left_nz_[8], &res);
+
+ // AC
+ VP8InitResidual(1, 0, enc, &res);
+ for (y = 0; y < 4; ++y) {
+ for (x = 0; x < 4; ++x) {
+ const int ctx = it->top_nz_[x] + it->left_nz_[y];
+ VP8SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res);
+ R += VP8GetResidualCost(ctx, &res);
+ it->top_nz_[x] = it->left_nz_[y] = (res.last >= 0);
+ }
+ }
+ return R;
+}
+
+int VP8GetCostUV(VP8EncIterator* const it, const VP8ModeScore* const rd) {
+ VP8Residual res;
+ VP8Encoder* const enc = it->enc_;
+ int ch, x, y;
+ int R = 0;
+
+ VP8IteratorNzToBytes(it); // re-import the non-zero context
+
+ VP8InitResidual(0, 2, enc, &res);
+ for (ch = 0; ch <= 2; ch += 2) {
+ for (y = 0; y < 2; ++y) {
+ for (x = 0; x < 2; ++x) {
+ const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y];
+ VP8SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res);
+ R += VP8GetResidualCost(ctx, &res);
+ it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = (res.last >= 0);
+ }
+ }
+ }
+ return R;
+}
+
+
+//------------------------------------------------------------------------------
+// Recording of token probabilities.
+
+// Record proba context used
+static int Record(int bit, proba_t* const stats) {
+ proba_t p = *stats;
+ if (p >= 0xffff0000u) { // an overflow is inbound.
+ p = ((p + 1u) >> 1) & 0x7fff7fffu; // -> divide the stats by 2.
+ }
+ // record bit count (lower 16 bits) and increment total count (upper 16 bits).
+ p += 0x00010000u + bit;
+ *stats = p;
+ return bit;
+}
+
+// We keep the table-free variant around for reference, in case.
+#define USE_LEVEL_CODE_TABLE
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
+// Simulate block coding, but only record statistics.
+// Note: no need to record the fixed probas.
+int VP8RecordCoeffs(int ctx, const VP8Residual* const res) {
+ int n = res->first;
+ // should be stats[VP8EncBands[n]], but it's equivalent for n=0 or 1
+ proba_t* s = res->stats[n][ctx];
+ if (res->last < 0) {
+ Record(0, s + 0);
+ return 0;
+ }
+ while (n <= res->last) {
+ int v;
+ Record(1, s + 0); // order of record doesn't matter
+ while ((v = res->coeffs[n++]) == 0) {
+ Record(0, s + 1);
+ s = res->stats[VP8EncBands[n]][0];
+ }
+ Record(1, s + 1);
+ if (!Record(2u < (unsigned int)(v + 1), s + 2)) { // v = -1 or 1
+ s = res->stats[VP8EncBands[n]][1];
+ } else {
+ v = abs(v);
+#if !defined(USE_LEVEL_CODE_TABLE)
+ if (!Record(v > 4, s + 3)) {
+ if (Record(v != 2, s + 4))
+ Record(v == 4, s + 5);
+ } else if (!Record(v > 10, s + 6)) {
+ Record(v > 6, s + 7);
+ } else if (!Record((v >= 3 + (8 << 2)), s + 8)) {
+ Record((v >= 3 + (8 << 1)), s + 9);
+ } else {
+ Record((v >= 3 + (8 << 3)), s + 10);
+ }
+#else
+ if (v > MAX_VARIABLE_LEVEL) {
+ v = MAX_VARIABLE_LEVEL;
+ }
+
+ {
+ const int bits = VP8LevelCodes[v - 1][1];
+ int pattern = VP8LevelCodes[v - 1][0];
+ int i;
+ for (i = 0; (pattern >>= 1) != 0; ++i) {
+ const int mask = 2 << i;
+ if (pattern & 1) Record(!!(bits & mask), s + 3 + i);
+ }
+ }
#endif
+ s = res->stats[VP8EncBands[n]][2];
+ }
+ }
+ if (n < 16) Record(0, s + 0);
+ return 1;
+}
+
+//------------------------------------------------------------------------------
diff --git a/drivers/webp/enc/cost.h b/drivers/webp/enc/cost.h
index 09b75b699d..20960d6d74 100644
--- a/drivers/webp/enc/cost.h
+++ b/drivers/webp/enc/cost.h
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Cost tables for level and modes.
@@ -12,14 +14,32 @@
#ifndef WEBP_ENC_COST_H_
#define WEBP_ENC_COST_H_
+#include <assert.h>
+#include <stdlib.h>
#include "./vp8enci.h"
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
extern "C" {
#endif
-extern const uint16_t VP8LevelFixedCosts[2048]; // approximate cost per level
-extern const uint16_t VP8EntropyCost[256]; // 8bit fixed-point log(p)
+// On-the-fly info about the current set of residuals. Handy to avoid
+// passing zillions of params.
+typedef struct VP8Residual VP8Residual;
+struct VP8Residual {
+ int first;
+ int last;
+ const int16_t* coeffs;
+
+ int coeff_type;
+ ProbaArray* prob;
+ StatsArray* stats;
+ CostArrayPtr costs;
+};
+
+void VP8InitResidual(int first, int coeff_type,
+ VP8Encoder* const enc, VP8Residual* const res);
+
+int VP8RecordCoeffs(int ctx, const VP8Residual* const res);
// Cost of coding one event with probability 'proba'.
static WEBP_INLINE int VP8BitCost(int bit, uint8_t proba) {
@@ -28,7 +48,7 @@ static WEBP_INLINE int VP8BitCost(int bit, uint8_t proba) {
// Level cost calculations
extern const uint16_t VP8LevelCodes[MAX_VARIABLE_LEVEL][2];
-void VP8CalculateLevelCosts(VP8Proba* const proba);
+void VP8CalculateLevelCosts(VP8EncProba* const proba);
static WEBP_INLINE int VP8LevelCost(const uint16_t* const table, int level) {
return VP8LevelFixedCosts[level]
+ table[(level > MAX_VARIABLE_LEVEL) ? MAX_VARIABLE_LEVEL : level];
@@ -41,7 +61,7 @@ extern const uint16_t VP8FixedCostsI4[NUM_BMODES][NUM_BMODES][NUM_BMODES];
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/drivers/webp/enc/delta_palettization.c b/drivers/webp/enc/delta_palettization.c
new file mode 100644
index 0000000000..8bd3a3d233
--- /dev/null
+++ b/drivers/webp/enc/delta_palettization.c
@@ -0,0 +1,455 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Author: Mislav Bradac (mislavm@google.com)
+//
+
+#include "./delta_palettization.h"
+
+#ifdef WEBP_EXPERIMENTAL_FEATURES
+#include "webp/types.h"
+#include "../dsp/lossless.h"
+
+#define MK_COL(r, g, b) (((r) << 16) + ((g) << 8) + (b))
+
+// Format allows palette up to 256 entries, but more palette entries produce
+// bigger entropy. In the future it will probably be useful to add more entries
+// that are far from the origin of the palette or choose remaining entries
+// dynamically.
+#define DELTA_PALETTE_SIZE 226
+
+// Palette used for delta_palettization. Entries are roughly sorted by distance
+// of their signed equivalents from the origin.
+static const uint32_t kDeltaPalette[DELTA_PALETTE_SIZE] = {
+ MK_COL(0u, 0u, 0u),
+ MK_COL(255u, 255u, 255u),
+ MK_COL(1u, 1u, 1u),
+ MK_COL(254u, 254u, 254u),
+ MK_COL(2u, 2u, 2u),
+ MK_COL(4u, 4u, 4u),
+ MK_COL(252u, 252u, 252u),
+ MK_COL(250u, 0u, 0u),
+ MK_COL(0u, 250u, 0u),
+ MK_COL(0u, 0u, 250u),
+ MK_COL(6u, 0u, 0u),
+ MK_COL(0u, 6u, 0u),
+ MK_COL(0u, 0u, 6u),
+ MK_COL(0u, 0u, 248u),
+ MK_COL(0u, 0u, 8u),
+ MK_COL(0u, 248u, 0u),
+ MK_COL(0u, 248u, 248u),
+ MK_COL(0u, 248u, 8u),
+ MK_COL(0u, 8u, 0u),
+ MK_COL(0u, 8u, 248u),
+ MK_COL(0u, 8u, 8u),
+ MK_COL(8u, 8u, 8u),
+ MK_COL(248u, 0u, 0u),
+ MK_COL(248u, 0u, 248u),
+ MK_COL(248u, 0u, 8u),
+ MK_COL(248u, 248u, 0u),
+ MK_COL(248u, 8u, 0u),
+ MK_COL(8u, 0u, 0u),
+ MK_COL(8u, 0u, 248u),
+ MK_COL(8u, 0u, 8u),
+ MK_COL(8u, 248u, 0u),
+ MK_COL(8u, 8u, 0u),
+ MK_COL(23u, 23u, 23u),
+ MK_COL(13u, 13u, 13u),
+ MK_COL(232u, 232u, 232u),
+ MK_COL(244u, 244u, 244u),
+ MK_COL(245u, 245u, 250u),
+ MK_COL(50u, 50u, 50u),
+ MK_COL(204u, 204u, 204u),
+ MK_COL(236u, 236u, 236u),
+ MK_COL(16u, 16u, 16u),
+ MK_COL(240u, 16u, 16u),
+ MK_COL(16u, 240u, 16u),
+ MK_COL(240u, 240u, 16u),
+ MK_COL(16u, 16u, 240u),
+ MK_COL(240u, 16u, 240u),
+ MK_COL(16u, 240u, 240u),
+ MK_COL(240u, 240u, 240u),
+ MK_COL(0u, 0u, 232u),
+ MK_COL(0u, 232u, 0u),
+ MK_COL(232u, 0u, 0u),
+ MK_COL(0u, 0u, 24u),
+ MK_COL(0u, 24u, 0u),
+ MK_COL(24u, 0u, 0u),
+ MK_COL(32u, 32u, 32u),
+ MK_COL(224u, 32u, 32u),
+ MK_COL(32u, 224u, 32u),
+ MK_COL(224u, 224u, 32u),
+ MK_COL(32u, 32u, 224u),
+ MK_COL(224u, 32u, 224u),
+ MK_COL(32u, 224u, 224u),
+ MK_COL(224u, 224u, 224u),
+ MK_COL(0u, 0u, 176u),
+ MK_COL(0u, 0u, 80u),
+ MK_COL(0u, 176u, 0u),
+ MK_COL(0u, 176u, 176u),
+ MK_COL(0u, 176u, 80u),
+ MK_COL(0u, 80u, 0u),
+ MK_COL(0u, 80u, 176u),
+ MK_COL(0u, 80u, 80u),
+ MK_COL(176u, 0u, 0u),
+ MK_COL(176u, 0u, 176u),
+ MK_COL(176u, 0u, 80u),
+ MK_COL(176u, 176u, 0u),
+ MK_COL(176u, 80u, 0u),
+ MK_COL(80u, 0u, 0u),
+ MK_COL(80u, 0u, 176u),
+ MK_COL(80u, 0u, 80u),
+ MK_COL(80u, 176u, 0u),
+ MK_COL(80u, 80u, 0u),
+ MK_COL(0u, 0u, 152u),
+ MK_COL(0u, 0u, 104u),
+ MK_COL(0u, 152u, 0u),
+ MK_COL(0u, 152u, 152u),
+ MK_COL(0u, 152u, 104u),
+ MK_COL(0u, 104u, 0u),
+ MK_COL(0u, 104u, 152u),
+ MK_COL(0u, 104u, 104u),
+ MK_COL(152u, 0u, 0u),
+ MK_COL(152u, 0u, 152u),
+ MK_COL(152u, 0u, 104u),
+ MK_COL(152u, 152u, 0u),
+ MK_COL(152u, 104u, 0u),
+ MK_COL(104u, 0u, 0u),
+ MK_COL(104u, 0u, 152u),
+ MK_COL(104u, 0u, 104u),
+ MK_COL(104u, 152u, 0u),
+ MK_COL(104u, 104u, 0u),
+ MK_COL(216u, 216u, 216u),
+ MK_COL(216u, 216u, 40u),
+ MK_COL(216u, 216u, 176u),
+ MK_COL(216u, 216u, 80u),
+ MK_COL(216u, 40u, 216u),
+ MK_COL(216u, 40u, 40u),
+ MK_COL(216u, 40u, 176u),
+ MK_COL(216u, 40u, 80u),
+ MK_COL(216u, 176u, 216u),
+ MK_COL(216u, 176u, 40u),
+ MK_COL(216u, 176u, 176u),
+ MK_COL(216u, 176u, 80u),
+ MK_COL(216u, 80u, 216u),
+ MK_COL(216u, 80u, 40u),
+ MK_COL(216u, 80u, 176u),
+ MK_COL(216u, 80u, 80u),
+ MK_COL(40u, 216u, 216u),
+ MK_COL(40u, 216u, 40u),
+ MK_COL(40u, 216u, 176u),
+ MK_COL(40u, 216u, 80u),
+ MK_COL(40u, 40u, 216u),
+ MK_COL(40u, 40u, 40u),
+ MK_COL(40u, 40u, 176u),
+ MK_COL(40u, 40u, 80u),
+ MK_COL(40u, 176u, 216u),
+ MK_COL(40u, 176u, 40u),
+ MK_COL(40u, 176u, 176u),
+ MK_COL(40u, 176u, 80u),
+ MK_COL(40u, 80u, 216u),
+ MK_COL(40u, 80u, 40u),
+ MK_COL(40u, 80u, 176u),
+ MK_COL(40u, 80u, 80u),
+ MK_COL(80u, 216u, 216u),
+ MK_COL(80u, 216u, 40u),
+ MK_COL(80u, 216u, 176u),
+ MK_COL(80u, 216u, 80u),
+ MK_COL(80u, 40u, 216u),
+ MK_COL(80u, 40u, 40u),
+ MK_COL(80u, 40u, 176u),
+ MK_COL(80u, 40u, 80u),
+ MK_COL(80u, 176u, 216u),
+ MK_COL(80u, 176u, 40u),
+ MK_COL(80u, 176u, 176u),
+ MK_COL(80u, 176u, 80u),
+ MK_COL(80u, 80u, 216u),
+ MK_COL(80u, 80u, 40u),
+ MK_COL(80u, 80u, 176u),
+ MK_COL(80u, 80u, 80u),
+ MK_COL(0u, 0u, 192u),
+ MK_COL(0u, 0u, 64u),
+ MK_COL(0u, 0u, 128u),
+ MK_COL(0u, 192u, 0u),
+ MK_COL(0u, 192u, 192u),
+ MK_COL(0u, 192u, 64u),
+ MK_COL(0u, 192u, 128u),
+ MK_COL(0u, 64u, 0u),
+ MK_COL(0u, 64u, 192u),
+ MK_COL(0u, 64u, 64u),
+ MK_COL(0u, 64u, 128u),
+ MK_COL(0u, 128u, 0u),
+ MK_COL(0u, 128u, 192u),
+ MK_COL(0u, 128u, 64u),
+ MK_COL(0u, 128u, 128u),
+ MK_COL(176u, 216u, 216u),
+ MK_COL(176u, 216u, 40u),
+ MK_COL(176u, 216u, 176u),
+ MK_COL(176u, 216u, 80u),
+ MK_COL(176u, 40u, 216u),
+ MK_COL(176u, 40u, 40u),
+ MK_COL(176u, 40u, 176u),
+ MK_COL(176u, 40u, 80u),
+ MK_COL(176u, 176u, 216u),
+ MK_COL(176u, 176u, 40u),
+ MK_COL(176u, 176u, 176u),
+ MK_COL(176u, 176u, 80u),
+ MK_COL(176u, 80u, 216u),
+ MK_COL(176u, 80u, 40u),
+ MK_COL(176u, 80u, 176u),
+ MK_COL(176u, 80u, 80u),
+ MK_COL(192u, 0u, 0u),
+ MK_COL(192u, 0u, 192u),
+ MK_COL(192u, 0u, 64u),
+ MK_COL(192u, 0u, 128u),
+ MK_COL(192u, 192u, 0u),
+ MK_COL(192u, 192u, 192u),
+ MK_COL(192u, 192u, 64u),
+ MK_COL(192u, 192u, 128u),
+ MK_COL(192u, 64u, 0u),
+ MK_COL(192u, 64u, 192u),
+ MK_COL(192u, 64u, 64u),
+ MK_COL(192u, 64u, 128u),
+ MK_COL(192u, 128u, 0u),
+ MK_COL(192u, 128u, 192u),
+ MK_COL(192u, 128u, 64u),
+ MK_COL(192u, 128u, 128u),
+ MK_COL(64u, 0u, 0u),
+ MK_COL(64u, 0u, 192u),
+ MK_COL(64u, 0u, 64u),
+ MK_COL(64u, 0u, 128u),
+ MK_COL(64u, 192u, 0u),
+ MK_COL(64u, 192u, 192u),
+ MK_COL(64u, 192u, 64u),
+ MK_COL(64u, 192u, 128u),
+ MK_COL(64u, 64u, 0u),
+ MK_COL(64u, 64u, 192u),
+ MK_COL(64u, 64u, 64u),
+ MK_COL(64u, 64u, 128u),
+ MK_COL(64u, 128u, 0u),
+ MK_COL(64u, 128u, 192u),
+ MK_COL(64u, 128u, 64u),
+ MK_COL(64u, 128u, 128u),
+ MK_COL(128u, 0u, 0u),
+ MK_COL(128u, 0u, 192u),
+ MK_COL(128u, 0u, 64u),
+ MK_COL(128u, 0u, 128u),
+ MK_COL(128u, 192u, 0u),
+ MK_COL(128u, 192u, 192u),
+ MK_COL(128u, 192u, 64u),
+ MK_COL(128u, 192u, 128u),
+ MK_COL(128u, 64u, 0u),
+ MK_COL(128u, 64u, 192u),
+ MK_COL(128u, 64u, 64u),
+ MK_COL(128u, 64u, 128u),
+ MK_COL(128u, 128u, 0u),
+ MK_COL(128u, 128u, 192u),
+ MK_COL(128u, 128u, 64u),
+ MK_COL(128u, 128u, 128u),
+};
+
+#undef MK_COL
+
+//------------------------------------------------------------------------------
+// TODO(skal): move the functions to dsp/lossless.c when the correct
+// granularity is found. For now, we'll just copy-paste some useful bits
+// here instead.
+
+// In-place sum of each component with mod 256.
+static WEBP_INLINE void AddPixelsEq(uint32_t* a, uint32_t b) {
+ const uint32_t alpha_and_green = (*a & 0xff00ff00u) + (b & 0xff00ff00u);
+ const uint32_t red_and_blue = (*a & 0x00ff00ffu) + (b & 0x00ff00ffu);
+ *a = (alpha_and_green & 0xff00ff00u) | (red_and_blue & 0x00ff00ffu);
+}
+
+static WEBP_INLINE uint32_t Clip255(uint32_t a) {
+ if (a < 256) {
+ return a;
+ }
+ // return 0, when a is a negative integer.
+ // return 255, when a is positive.
+ return ~a >> 24;
+}
+
+// Delta palettization functions.
+static WEBP_INLINE int Square(int x) {
+ return x * x;
+}
+
+static WEBP_INLINE uint32_t Intensity(uint32_t a) {
+ return
+ 30 * ((a >> 16) & 0xff) +
+ 59 * ((a >> 8) & 0xff) +
+ 11 * ((a >> 0) & 0xff);
+}
+
+static uint32_t CalcDist(uint32_t predicted_value, uint32_t actual_value,
+ uint32_t palette_entry) {
+ int i;
+ uint32_t distance = 0;
+ AddPixelsEq(&predicted_value, palette_entry);
+ for (i = 0; i < 32; i += 8) {
+ const int32_t av = (actual_value >> i) & 0xff;
+ const int32_t pv = (predicted_value >> i) & 0xff;
+ distance += Square(pv - av);
+ }
+ // We sum square of intensity difference with factor 10, but because Intensity
+ // returns 100 times real intensity we need to multiply differences of colors
+ // by 1000.
+ distance *= 1000u;
+ distance += Square(Intensity(predicted_value)
+ - Intensity(actual_value));
+ return distance;
+}
+
+static uint32_t Predict(int x, int y, uint32_t* image) {
+ const uint32_t t = (y == 0) ? ARGB_BLACK : image[x];
+ const uint32_t l = (x == 0) ? ARGB_BLACK : image[x - 1];
+ const uint32_t p =
+ (((((t >> 24) & 0xff) + ((l >> 24) & 0xff)) / 2) << 24) +
+ (((((t >> 16) & 0xff) + ((l >> 16) & 0xff)) / 2) << 16) +
+ (((((t >> 8) & 0xff) + ((l >> 8) & 0xff)) / 2) << 8) +
+ (((((t >> 0) & 0xff) + ((l >> 0) & 0xff)) / 2) << 0);
+ if (x == 0 && y == 0) return ARGB_BLACK;
+ if (x == 0) return t;
+ if (y == 0) return l;
+ return p;
+}
+
+static WEBP_INLINE int AddSubtractComponentFullWithCoefficient(
+ int a, int b, int c) {
+ return Clip255(a + ((b - c) >> 2));
+}
+
+static WEBP_INLINE uint32_t ClampedAddSubtractFullWithCoefficient(
+ uint32_t c0, uint32_t c1, uint32_t c2) {
+ const int a = AddSubtractComponentFullWithCoefficient(
+ c0 >> 24, c1 >> 24, c2 >> 24);
+ const int r = AddSubtractComponentFullWithCoefficient((c0 >> 16) & 0xff,
+ (c1 >> 16) & 0xff,
+ (c2 >> 16) & 0xff);
+ const int g = AddSubtractComponentFullWithCoefficient((c0 >> 8) & 0xff,
+ (c1 >> 8) & 0xff,
+ (c2 >> 8) & 0xff);
+ const int b = AddSubtractComponentFullWithCoefficient(
+ c0 & 0xff, c1 & 0xff, c2 & 0xff);
+ return ((uint32_t)a << 24) | (r << 16) | (g << 8) | b;
+}
+
+//------------------------------------------------------------------------------
+
+// Find palette entry with minimum error from difference of actual pixel value
+// and predicted pixel value. Propagate error of pixel to its top and left pixel
+// in src array. Write predicted_value + palette_entry to new_image. Return
+// index of best palette entry.
+static int FindBestPaletteEntry(uint32_t src, uint32_t predicted_value,
+ const uint32_t palette[], int palette_size) {
+ int i;
+ int idx = 0;
+ uint32_t best_distance = CalcDist(predicted_value, src, palette[0]);
+ for (i = 1; i < palette_size; ++i) {
+ const uint32_t distance = CalcDist(predicted_value, src, palette[i]);
+ if (distance < best_distance) {
+ best_distance = distance;
+ idx = i;
+ }
+ }
+ return idx;
+}
+
+static void ApplyBestPaletteEntry(int x, int y,
+ uint32_t new_value, uint32_t palette_value,
+ uint32_t* src, int src_stride,
+ uint32_t* new_image) {
+ AddPixelsEq(&new_value, palette_value);
+ if (x > 0) {
+ src[x - 1] = ClampedAddSubtractFullWithCoefficient(src[x - 1],
+ new_value, src[x]);
+ }
+ if (y > 0) {
+ src[x - src_stride] =
+ ClampedAddSubtractFullWithCoefficient(src[x - src_stride],
+ new_value, src[x]);
+ }
+ new_image[x] = new_value;
+}
+
+//------------------------------------------------------------------------------
+// Main entry point
+
+static WebPEncodingError ApplyDeltaPalette(uint32_t* src, uint32_t* dst,
+ uint32_t src_stride,
+ uint32_t dst_stride,
+ const uint32_t* palette,
+ int palette_size,
+ int width, int height,
+ int num_passes) {
+ int x, y;
+ WebPEncodingError err = VP8_ENC_OK;
+ uint32_t* new_image = (uint32_t*)WebPSafeMalloc(width, sizeof(*new_image));
+ uint8_t* const tmp_row = (uint8_t*)WebPSafeMalloc(width, sizeof(*tmp_row));
+ if (new_image == NULL || tmp_row == NULL) {
+ err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ goto Error;
+ }
+
+ while (num_passes--) {
+ uint32_t* cur_src = src;
+ uint32_t* cur_dst = dst;
+ for (y = 0; y < height; ++y) {
+ for (x = 0; x < width; ++x) {
+ const uint32_t predicted_value = Predict(x, y, new_image);
+ tmp_row[x] = FindBestPaletteEntry(cur_src[x], predicted_value,
+ palette, palette_size);
+ ApplyBestPaletteEntry(x, y, predicted_value, palette[tmp_row[x]],
+ cur_src, src_stride, new_image);
+ }
+ for (x = 0; x < width; ++x) {
+ cur_dst[x] = palette[tmp_row[x]];
+ }
+ cur_src += src_stride;
+ cur_dst += dst_stride;
+ }
+ }
+ Error:
+ WebPSafeFree(new_image);
+ WebPSafeFree(tmp_row);
+ return err;
+}
+
+// replaces enc->argb_ by a palettizable approximation of it,
+// and generates optimal enc->palette_[]
+WebPEncodingError WebPSearchOptimalDeltaPalette(VP8LEncoder* const enc) {
+ const WebPPicture* const pic = enc->pic_;
+ uint32_t* src = pic->argb;
+ uint32_t* dst = enc->argb_;
+ const int width = pic->width;
+ const int height = pic->height;
+
+ WebPEncodingError err = VP8_ENC_OK;
+ memcpy(enc->palette_, kDeltaPalette, sizeof(kDeltaPalette));
+ enc->palette_[DELTA_PALETTE_SIZE - 1] = src[0] - 0xff000000u;
+ enc->palette_size_ = DELTA_PALETTE_SIZE;
+ err = ApplyDeltaPalette(src, dst, pic->argb_stride, enc->current_width_,
+ enc->palette_, enc->palette_size_,
+ width, height, 2);
+ if (err != VP8_ENC_OK) goto Error;
+
+ Error:
+ return err;
+}
+
+#else // !WEBP_EXPERIMENTAL_FEATURES
+
+WebPEncodingError WebPSearchOptimalDeltaPalette(VP8LEncoder* const enc) {
+ (void)enc;
+ return VP8_ENC_ERROR_INVALID_CONFIGURATION;
+}
+
+#endif // WEBP_EXPERIMENTAL_FEATURES
diff --git a/drivers/webp/enc/delta_palettization.h b/drivers/webp/enc/delta_palettization.h
new file mode 100644
index 0000000000..54195d452c
--- /dev/null
+++ b/drivers/webp/enc/delta_palettization.h
@@ -0,0 +1,25 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Author: Mislav Bradac (mislavm@google.com)
+//
+
+#ifndef WEBP_ENC_DELTA_PALETTIZATION_H_
+#define WEBP_ENC_DELTA_PALETTIZATION_H_
+
+#include "webp/encode.h"
+#include "../enc/vp8li.h"
+
+// Replaces enc->argb_[] input by a palettizable approximation of it,
+// and generates optimal enc->palette_[].
+// This function can revert enc->use_palette_ / enc->use_predict_ flag
+// if delta-palettization is not producing expected saving.
+WebPEncodingError WebPSearchOptimalDeltaPalette(VP8LEncoder* const enc);
+
+#endif // WEBP_ENC_DELTA_PALETTIZATION_H_
diff --git a/drivers/webp/enc/filter.c b/drivers/webp/enc/filter.c
index 7fb78a3949..1a4dd947fb 100644
--- a/drivers/webp/enc/filter.c
+++ b/drivers/webp/enc/filter.c
@@ -1,194 +1,68 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Selecting filter level
//
// Author: somnath@google.com (Somnath Banerjee)
+#include <assert.h>
#include "./vp8enci.h"
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-// NOTE: clip1, tables and InitTables are repeated entries of dsp.c
-static uint8_t abs0[255 + 255 + 1]; // abs(i)
-static uint8_t abs1[255 + 255 + 1]; // abs(i)>>1
-static int8_t sclip1[1020 + 1020 + 1]; // clips [-1020, 1020] to [-128, 127]
-static int8_t sclip2[112 + 112 + 1]; // clips [-112, 112] to [-16, 15]
-static uint8_t clip1[255 + 510 + 1]; // clips [-255,510] to [0,255]
-
-static int tables_ok = 0;
-
-static void InitTables(void) {
- if (!tables_ok) {
- int i;
- for (i = -255; i <= 255; ++i) {
- abs0[255 + i] = (i < 0) ? -i : i;
- abs1[255 + i] = abs0[255 + i] >> 1;
- }
- for (i = -1020; i <= 1020; ++i) {
- sclip1[1020 + i] = (i < -128) ? -128 : (i > 127) ? 127 : i;
- }
- for (i = -112; i <= 112; ++i) {
- sclip2[112 + i] = (i < -16) ? -16 : (i > 15) ? 15 : i;
- }
- for (i = -255; i <= 255 + 255; ++i) {
- clip1[255 + i] = (i < 0) ? 0 : (i > 255) ? 255 : i;
- }
- tables_ok = 1;
- }
-}
-
-//------------------------------------------------------------------------------
-// Edge filtering functions
-
-// 4 pixels in, 2 pixels out
-static WEBP_INLINE void do_filter2(uint8_t* p, int step) {
- const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
- const int a = 3 * (q0 - p0) + sclip1[1020 + p1 - q1];
- const int a1 = sclip2[112 + ((a + 4) >> 3)];
- const int a2 = sclip2[112 + ((a + 3) >> 3)];
- p[-step] = clip1[255 + p0 + a2];
- p[ 0] = clip1[255 + q0 - a1];
-}
-
-// 4 pixels in, 4 pixels out
-static WEBP_INLINE void do_filter4(uint8_t* p, int step) {
- const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
- const int a = 3 * (q0 - p0);
- const int a1 = sclip2[112 + ((a + 4) >> 3)];
- const int a2 = sclip2[112 + ((a + 3) >> 3)];
- const int a3 = (a1 + 1) >> 1;
- p[-2*step] = clip1[255 + p1 + a3];
- p[- step] = clip1[255 + p0 + a2];
- p[ 0] = clip1[255 + q0 - a1];
- p[ step] = clip1[255 + q1 - a3];
-}
-
-// high edge-variance
-static WEBP_INLINE int hev(const uint8_t* p, int step, int thresh) {
- const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
- return (abs0[255 + p1 - p0] > thresh) || (abs0[255 + q1 - q0] > thresh);
-}
-
-static WEBP_INLINE int needs_filter(const uint8_t* p, int step, int thresh) {
- const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
- return (2 * abs0[255 + p0 - q0] + abs1[255 + p1 - q1]) <= thresh;
-}
-
-static WEBP_INLINE int needs_filter2(const uint8_t* p,
- int step, int t, int it) {
- const int p3 = p[-4*step], p2 = p[-3*step], p1 = p[-2*step], p0 = p[-step];
- const int q0 = p[0], q1 = p[step], q2 = p[2*step], q3 = p[3*step];
- if ((2 * abs0[255 + p0 - q0] + abs1[255 + p1 - q1]) > t)
- return 0;
- return abs0[255 + p3 - p2] <= it && abs0[255 + p2 - p1] <= it &&
- abs0[255 + p1 - p0] <= it && abs0[255 + q3 - q2] <= it &&
- abs0[255 + q2 - q1] <= it && abs0[255 + q1 - q0] <= it;
+#include "../dsp/dsp.h"
+
+// This table gives, for a given sharpness, the filtering strength to be
+// used (at least) in order to filter a given edge step delta.
+// This is constructed by brute force inspection: for all delta, we iterate
+// over all possible filtering strength / thresh until needs_filter() returns
+// true.
+#define MAX_DELTA_SIZE 64
+static const uint8_t kLevelsFromDelta[8][MAX_DELTA_SIZE] = {
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63 },
+ { 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 17, 18,
+ 20, 21, 23, 24, 26, 27, 29, 30, 32, 33, 35, 36, 38, 39, 41, 42,
+ 44, 45, 47, 48, 50, 51, 53, 54, 56, 57, 59, 60, 62, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 },
+ { 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 19,
+ 20, 22, 23, 25, 26, 28, 29, 31, 32, 34, 35, 37, 38, 40, 41, 43,
+ 44, 46, 47, 49, 50, 52, 53, 55, 56, 58, 59, 61, 62, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 },
+ { 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 13, 15, 16, 18, 19,
+ 21, 22, 24, 25, 27, 28, 30, 31, 33, 34, 36, 37, 39, 40, 42, 43,
+ 45, 46, 48, 49, 51, 52, 54, 55, 57, 58, 60, 61, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 },
+ { 0, 1, 2, 3, 5, 6, 7, 8, 9, 11, 12, 14, 15, 17, 18, 20,
+ 21, 23, 24, 26, 27, 29, 30, 32, 33, 35, 36, 38, 39, 41, 42, 44,
+ 45, 47, 48, 50, 51, 53, 54, 56, 57, 59, 60, 62, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 },
+ { 0, 1, 2, 4, 5, 7, 8, 9, 11, 12, 13, 15, 16, 17, 19, 20,
+ 22, 23, 25, 26, 28, 29, 31, 32, 34, 35, 37, 38, 40, 41, 43, 44,
+ 46, 47, 49, 50, 52, 53, 55, 56, 58, 59, 61, 62, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 },
+ { 0, 1, 2, 4, 5, 7, 8, 9, 11, 12, 13, 15, 16, 18, 19, 21,
+ 22, 24, 25, 27, 28, 30, 31, 33, 34, 36, 37, 39, 40, 42, 43, 45,
+ 46, 48, 49, 51, 52, 54, 55, 57, 58, 60, 61, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 },
+ { 0, 1, 2, 4, 5, 7, 8, 9, 11, 12, 14, 15, 17, 18, 20, 21,
+ 23, 24, 26, 27, 29, 30, 32, 33, 35, 36, 38, 39, 41, 42, 44, 45,
+ 47, 48, 50, 51, 53, 54, 56, 57, 59, 60, 62, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63 }
+};
+
+int VP8FilterStrengthFromDelta(int sharpness, int delta) {
+ const int pos = (delta < MAX_DELTA_SIZE) ? delta : MAX_DELTA_SIZE - 1;
+ assert(sharpness >= 0 && sharpness <= 7);
+ return kLevelsFromDelta[sharpness][pos];
}
//------------------------------------------------------------------------------
-// Simple In-loop filtering (Paragraph 15.2)
-
-static void SimpleVFilter16(uint8_t* p, int stride, int thresh) {
- int i;
- for (i = 0; i < 16; ++i) {
- if (needs_filter(p + i, stride, thresh)) {
- do_filter2(p + i, stride);
- }
- }
-}
-
-static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
- int i;
- for (i = 0; i < 16; ++i) {
- if (needs_filter(p + i * stride, 1, thresh)) {
- do_filter2(p + i * stride, 1);
- }
- }
-}
-
-static void SimpleVFilter16i(uint8_t* p, int stride, int thresh) {
- int k;
- for (k = 3; k > 0; --k) {
- p += 4 * stride;
- SimpleVFilter16(p, stride, thresh);
- }
-}
-
-static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) {
- int k;
- for (k = 3; k > 0; --k) {
- p += 4;
- SimpleHFilter16(p, stride, thresh);
- }
-}
-
-//------------------------------------------------------------------------------
-// Complex In-loop filtering (Paragraph 15.3)
-
-static WEBP_INLINE void FilterLoop24(uint8_t* p,
- int hstride, int vstride, int size,
- int thresh, int ithresh, int hev_thresh) {
- while (size-- > 0) {
- if (needs_filter2(p, hstride, thresh, ithresh)) {
- if (hev(p, hstride, hev_thresh)) {
- do_filter2(p, hstride);
- } else {
- do_filter4(p, hstride);
- }
- }
- p += vstride;
- }
-}
-
-// on three inner edges
-static void VFilter16i(uint8_t* p, int stride,
- int thresh, int ithresh, int hev_thresh) {
- int k;
- for (k = 3; k > 0; --k) {
- p += 4 * stride;
- FilterLoop24(p, stride, 1, 16, thresh, ithresh, hev_thresh);
- }
-}
-
-static void HFilter16i(uint8_t* p, int stride,
- int thresh, int ithresh, int hev_thresh) {
- int k;
- for (k = 3; k > 0; --k) {
- p += 4;
- FilterLoop24(p, 1, stride, 16, thresh, ithresh, hev_thresh);
- }
-}
-
-static void VFilter8i(uint8_t* u, uint8_t* v, int stride,
- int thresh, int ithresh, int hev_thresh) {
- FilterLoop24(u + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh);
- FilterLoop24(v + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh);
-}
-
-static void HFilter8i(uint8_t* u, uint8_t* v, int stride,
- int thresh, int ithresh, int hev_thresh) {
- FilterLoop24(u + 4, 1, stride, 8, thresh, ithresh, hev_thresh);
- FilterLoop24(v + 4, 1, stride, 8, thresh, ithresh, hev_thresh);
-}
-
-//------------------------------------------------------------------------------
-
-void (*VP8EncVFilter16i)(uint8_t*, int, int, int, int) = VFilter16i;
-void (*VP8EncHFilter16i)(uint8_t*, int, int, int, int) = HFilter16i;
-void (*VP8EncVFilter8i)(uint8_t*, uint8_t*, int, int, int, int) = VFilter8i;
-void (*VP8EncHFilter8i)(uint8_t*, uint8_t*, int, int, int, int) = HFilter8i;
-
-void (*VP8EncSimpleVFilter16i)(uint8_t*, int, int) = SimpleVFilter16i;
-void (*VP8EncSimpleHFilter16i)(uint8_t*, int, int) = SimpleHFilter16i;
-
-//------------------------------------------------------------------------------
// Paragraph 15.4: compute the inner-edge filtering strength
static int GetILevel(int sharpness, int level) {
@@ -211,22 +85,22 @@ static void DoFilter(const VP8EncIterator* const it, int level) {
const int ilevel = GetILevel(enc->config_->filter_sharpness, level);
const int limit = 2 * level + ilevel;
- uint8_t* const y_dst = it->yuv_out2_ + Y_OFF;
- uint8_t* const u_dst = it->yuv_out2_ + U_OFF;
- uint8_t* const v_dst = it->yuv_out2_ + V_OFF;
+ uint8_t* const y_dst = it->yuv_out2_ + Y_OFF_ENC;
+ uint8_t* const u_dst = it->yuv_out2_ + U_OFF_ENC;
+ uint8_t* const v_dst = it->yuv_out2_ + V_OFF_ENC;
// copy current block to yuv_out2_
- memcpy(y_dst, it->yuv_out_, YUV_SIZE * sizeof(uint8_t));
+ memcpy(y_dst, it->yuv_out_, YUV_SIZE_ENC * sizeof(uint8_t));
if (enc->filter_hdr_.simple_ == 1) { // simple
- VP8EncSimpleHFilter16i(y_dst, BPS, limit);
- VP8EncSimpleVFilter16i(y_dst, BPS, limit);
+ VP8SimpleHFilter16i(y_dst, BPS, limit);
+ VP8SimpleVFilter16i(y_dst, BPS, limit);
} else { // complex
const int hev_thresh = (level >= 40) ? 2 : (level >= 15) ? 1 : 0;
- VP8EncHFilter16i(y_dst, BPS, limit, ilevel, hev_thresh);
- VP8EncHFilter8i(u_dst, v_dst, BPS, limit, ilevel, hev_thresh);
- VP8EncVFilter16i(y_dst, BPS, limit, ilevel, hev_thresh);
- VP8EncVFilter8i(u_dst, v_dst, BPS, limit, ilevel, hev_thresh);
+ VP8HFilter16i(y_dst, BPS, limit, ilevel, hev_thresh);
+ VP8HFilter8i(u_dst, v_dst, BPS, limit, ilevel, hev_thresh);
+ VP8VFilter16i(y_dst, BPS, limit, ilevel, hev_thresh);
+ VP8VFilter8i(u_dst, v_dst, BPS, limit, ilevel, hev_thresh);
}
}
@@ -321,13 +195,16 @@ static double GetMBSSIM(const uint8_t* yuv1, const uint8_t* yuv2) {
// compute SSIM in a 10 x 10 window
for (x = 3; x < 13; x++) {
for (y = 3; y < 13; y++) {
- VP8SSIMAccumulate(yuv1 + Y_OFF, BPS, yuv2 + Y_OFF, BPS, x, y, 16, 16, &s);
+ VP8SSIMAccumulate(yuv1 + Y_OFF_ENC, BPS, yuv2 + Y_OFF_ENC, BPS,
+ x, y, 16, 16, &s);
}
}
for (x = 1; x < 7; x++) {
for (y = 1; y < 7; y++) {
- VP8SSIMAccumulate(yuv1 + U_OFF, BPS, yuv2 + U_OFF, BPS, x, y, 8, 8, &s);
- VP8SSIMAccumulate(yuv1 + V_OFF, BPS, yuv2 + V_OFF, BPS, x, y, 8, 8, &s);
+ VP8SSIMAccumulate(yuv1 + U_OFF_ENC, BPS, yuv2 + U_OFF_ENC, BPS,
+ x, y, 8, 8, &s);
+ VP8SSIMAccumulate(yuv1 + V_OFF_ENC, BPS, yuv2 + V_OFF_ENC, BPS,
+ x, y, 8, 8, &s);
}
}
return VP8SSIMGet(&s);
@@ -338,28 +215,28 @@ static double GetMBSSIM(const uint8_t* yuv1, const uint8_t* yuv2) {
// loop filter strength
void VP8InitFilter(VP8EncIterator* const it) {
- int s, i;
- if (!it->lf_stats_) return;
-
- InitTables();
- for (s = 0; s < NUM_MB_SEGMENTS; s++) {
- for (i = 0; i < MAX_LF_LEVELS; i++) {
- (*it->lf_stats_)[s][i] = 0;
+ if (it->lf_stats_ != NULL) {
+ int s, i;
+ for (s = 0; s < NUM_MB_SEGMENTS; s++) {
+ for (i = 0; i < MAX_LF_LEVELS; i++) {
+ (*it->lf_stats_)[s][i] = 0;
+ }
}
}
}
void VP8StoreFilterStats(VP8EncIterator* const it) {
int d;
+ VP8Encoder* const enc = it->enc_;
const int s = it->mb_->segment_;
- const int level0 = it->enc_->dqm_[s].fstrength_; // TODO: ref_lf_delta[]
+ const int level0 = enc->dqm_[s].fstrength_; // TODO: ref_lf_delta[]
// explore +/-quant range of values around level0
- const int delta_min = -it->enc_->dqm_[s].quant_;
- const int delta_max = it->enc_->dqm_[s].quant_;
+ const int delta_min = -enc->dqm_[s].quant_;
+ const int delta_max = enc->dqm_[s].quant_;
const int step_size = (delta_max - delta_min >= 4) ? 4 : 1;
- if (!it->lf_stats_) return;
+ if (it->lf_stats_ == NULL) return;
// NOTE: Currently we are applying filter only across the sublock edges
// There are two reasons for that.
@@ -383,27 +260,40 @@ void VP8StoreFilterStats(VP8EncIterator* const it) {
}
void VP8AdjustFilterStrength(VP8EncIterator* const it) {
- int s;
VP8Encoder* const enc = it->enc_;
-
- if (!it->lf_stats_) {
- return;
- }
- for (s = 0; s < NUM_MB_SEGMENTS; s++) {
- int i, best_level = 0;
- // Improvement over filter level 0 should be at least 1e-5 (relatively)
- double best_v = 1.00001 * (*it->lf_stats_)[s][0];
- for (i = 1; i < MAX_LF_LEVELS; i++) {
- const double v = (*it->lf_stats_)[s][i];
- if (v > best_v) {
- best_v = v;
- best_level = i;
+ if (it->lf_stats_ != NULL) {
+ int s;
+ for (s = 0; s < NUM_MB_SEGMENTS; s++) {
+ int i, best_level = 0;
+ // Improvement over filter level 0 should be at least 1e-5 (relatively)
+ double best_v = 1.00001 * (*it->lf_stats_)[s][0];
+ for (i = 1; i < MAX_LF_LEVELS; i++) {
+ const double v = (*it->lf_stats_)[s][i];
+ if (v > best_v) {
+ best_v = v;
+ best_level = i;
+ }
}
+ enc->dqm_[s].fstrength_ = best_level;
}
- enc->dqm_[s].fstrength_ = best_level;
+ } else if (enc->config_->filter_strength > 0) {
+ int max_level = 0;
+ int s;
+ for (s = 0; s < NUM_MB_SEGMENTS; s++) {
+ VP8SegmentInfo* const dqm = &enc->dqm_[s];
+ // this '>> 3' accounts for some inverse WHT scaling
+ const int delta = (dqm->max_edge_ * dqm->y2_.q_[1]) >> 3;
+ const int level =
+ VP8FilterStrengthFromDelta(enc->filter_hdr_.sharpness_, delta);
+ if (level > dqm->fstrength_) {
+ dqm->fstrength_ = level;
+ }
+ if (max_level < dqm->fstrength_) {
+ max_level = dqm->fstrength_;
+ }
+ }
+ enc->filter_hdr_.level_ = max_level;
}
}
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
+// -----------------------------------------------------------------------------
diff --git a/drivers/webp/enc/frame.c b/drivers/webp/enc/frame.c
index bdd360069b..65a98ada4d 100644
--- a/drivers/webp/enc/frame.c
+++ b/drivers/webp/enc/frame.c
@@ -1,61 +1,98 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// frame coding and analysis
//
// Author: Skal (pascal.massimino@gmail.com)
-#include <assert.h>
-#include <stdlib.h>
#include <string.h>
#include <math.h>
-#include "./vp8enci.h"
#include "./cost.h"
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
+#include "./vp8enci.h"
+#include "../dsp/dsp.h"
+#include "webp/format_constants.h" // RIFF constants
#define SEGMENT_VISU 0
#define DEBUG_SEARCH 0 // useful to track search convergence
-// On-the-fly info about the current set of residuals. Handy to avoid
-// passing zillions of params.
-typedef struct {
- int first;
- int last;
- const int16_t* coeffs;
-
- int coeff_type;
- ProbaArray* prob;
- StatsArray* stats;
- CostArray* cost;
-} VP8Residual;
+//------------------------------------------------------------------------------
+// multi-pass convergence
+
+#define HEADER_SIZE_ESTIMATE (RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + \
+ VP8_FRAME_HEADER_SIZE)
+#define DQ_LIMIT 0.4 // convergence is considered reached if dq < DQ_LIMIT
+// we allow 2k of extra head-room in PARTITION0 limit.
+#define PARTITION0_SIZE_LIMIT ((VP8_MAX_PARTITION0_SIZE - 2048ULL) << 11)
+
+typedef struct { // struct for organizing convergence in either size or PSNR
+ int is_first;
+ float dq;
+ float q, last_q;
+ double value, last_value; // PSNR or size
+ double target;
+ int do_size_search;
+} PassStats;
+
+static int InitPassStats(const VP8Encoder* const enc, PassStats* const s) {
+ const uint64_t target_size = (uint64_t)enc->config_->target_size;
+ const int do_size_search = (target_size != 0);
+ const float target_PSNR = enc->config_->target_PSNR;
+
+ s->is_first = 1;
+ s->dq = 10.f;
+ s->q = s->last_q = enc->config_->quality;
+ s->target = do_size_search ? (double)target_size
+ : (target_PSNR > 0.) ? target_PSNR
+ : 40.; // default, just in case
+ s->value = s->last_value = 0.;
+ s->do_size_search = do_size_search;
+ return do_size_search;
+}
+
+static float Clamp(float v, float min, float max) {
+ return (v < min) ? min : (v > max) ? max : v;
+}
+
+static float ComputeNextQ(PassStats* const s) {
+ float dq;
+ if (s->is_first) {
+ dq = (s->value > s->target) ? -s->dq : s->dq;
+ s->is_first = 0;
+ } else if (s->value != s->last_value) {
+ const double slope = (s->target - s->value) / (s->last_value - s->value);
+ dq = (float)(slope * (s->last_q - s->q));
+ } else {
+ dq = 0.; // we're done?!
+ }
+ // Limit variable to avoid large swings.
+ s->dq = Clamp(dq, -30.f, 30.f);
+ s->last_q = s->q;
+ s->last_value = s->value;
+ s->q = Clamp(s->q + s->dq, 0.f, 100.f);
+ return s->q;
+}
//------------------------------------------------------------------------------
// Tables for level coding
-const uint8_t VP8EncBands[16 + 1] = {
- 0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7,
- 0 // sentinel
-};
-
-static const uint8_t kCat3[] = { 173, 148, 140 };
-static const uint8_t kCat4[] = { 176, 155, 140, 135 };
-static const uint8_t kCat5[] = { 180, 157, 141, 134, 130 };
-static const uint8_t kCat6[] =
+const uint8_t VP8Cat3[] = { 173, 148, 140 };
+const uint8_t VP8Cat4[] = { 176, 155, 140, 135 };
+const uint8_t VP8Cat5[] = { 180, 157, 141, 134, 130 };
+const uint8_t VP8Cat6[] =
{ 254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129 };
//------------------------------------------------------------------------------
// Reset the statistics about: number of skips, token proba, level cost,...
static void ResetStats(VP8Encoder* const enc) {
- VP8Proba* const proba = &enc->proba_;
+ VP8EncProba* const proba = &enc->proba_;
VP8CalculateLevelCosts(proba);
proba->nb_skip_ = 0;
}
@@ -71,7 +108,7 @@ static int CalcSkipProba(uint64_t nb, uint64_t total) {
// Returns the bit-cost for coding the skip probability.
static int FinalizeSkipProba(VP8Encoder* const enc) {
- VP8Proba* const proba = &enc->proba_;
+ VP8EncProba* const proba = &enc->proba_;
const int nb_mbs = enc->mb_w_ * enc->mb_h_;
const int nb_events = proba->nb_skip_;
int size;
@@ -86,82 +123,6 @@ static int FinalizeSkipProba(VP8Encoder* const enc) {
return size;
}
-//------------------------------------------------------------------------------
-// Recording of token probabilities.
-
-static void ResetTokenStats(VP8Encoder* const enc) {
- VP8Proba* const proba = &enc->proba_;
- memset(proba->stats_, 0, sizeof(proba->stats_));
-}
-
-// Record proba context used
-static int Record(int bit, proba_t* const stats) {
- proba_t p = *stats;
- if (p >= 0xffff0000u) { // an overflow is inbound.
- p = ((p + 1u) >> 1) & 0x7fff7fffu; // -> divide the stats by 2.
- }
- // record bit count (lower 16 bits) and increment total count (upper 16 bits).
- p += 0x00010000u + bit;
- *stats = p;
- return bit;
-}
-
-// We keep the table free variant around for reference, in case.
-#define USE_LEVEL_CODE_TABLE
-
-// Simulate block coding, but only record statistics.
-// Note: no need to record the fixed probas.
-static int RecordCoeffs(int ctx, const VP8Residual* const res) {
- int n = res->first;
- proba_t* s = res->stats[VP8EncBands[n]][ctx];
- if (res->last < 0) {
- Record(0, s + 0);
- return 0;
- }
- while (n <= res->last) {
- int v;
- Record(1, s + 0);
- while ((v = res->coeffs[n++]) == 0) {
- Record(0, s + 1);
- s = res->stats[VP8EncBands[n]][0];
- }
- Record(1, s + 1);
- if (!Record(2u < (unsigned int)(v + 1), s + 2)) { // v = -1 or 1
- s = res->stats[VP8EncBands[n]][1];
- } else {
- v = abs(v);
-#if !defined(USE_LEVEL_CODE_TABLE)
- if (!Record(v > 4, s + 3)) {
- if (Record(v != 2, s + 4))
- Record(v == 4, s + 5);
- } else if (!Record(v > 10, s + 6)) {
- Record(v > 6, s + 7);
- } else if (!Record((v >= 3 + (8 << 2)), s + 8)) {
- Record((v >= 3 + (8 << 1)), s + 9);
- } else {
- Record((v >= 3 + (8 << 3)), s + 10);
- }
-#else
- if (v > MAX_VARIABLE_LEVEL)
- v = MAX_VARIABLE_LEVEL;
-
- {
- const int bits = VP8LevelCodes[v - 1][1];
- int pattern = VP8LevelCodes[v - 1][0];
- int i;
- for (i = 0; (pattern >>= 1) != 0; ++i) {
- const int mask = 2 << i;
- if (pattern & 1) Record(!!(bits & mask), s + 3 + i);
- }
- }
-#endif
- s = res->stats[VP8EncBands[n]][2];
- }
- }
- if (n < 16) Record(0, s + 0);
- return 1;
-}
-
// Collect statistics and deduce probabilities for next coding pass.
// Return the total bit-cost for coding the probability updates.
static int CalcTokenProba(int nb, int total) {
@@ -174,8 +135,12 @@ static int BranchCost(int nb, int total, int proba) {
return nb * VP8BitCost(1, proba) + (total - nb) * VP8BitCost(0, proba);
}
-static int FinalizeTokenProbas(VP8Encoder* const enc) {
- VP8Proba* const proba = &enc->proba_;
+static void ResetTokenStats(VP8Encoder* const enc) {
+ VP8EncProba* const proba = &enc->proba_;
+ memset(proba->stats_, 0, sizeof(proba->stats_));
+}
+
+static int FinalizeTokenProbas(VP8EncProba* const proba) {
int has_changed = 0;
int size = 0;
int t, b, c, p;
@@ -212,129 +177,44 @@ static int FinalizeTokenProbas(VP8Encoder* const enc) {
}
//------------------------------------------------------------------------------
-// helper functions for residuals struct VP8Residual.
-
-static void InitResidual(int first, int coeff_type,
- VP8Encoder* const enc, VP8Residual* const res) {
- res->coeff_type = coeff_type;
- res->prob = enc->proba_.coeffs_[coeff_type];
- res->stats = enc->proba_.stats_[coeff_type];
- res->cost = enc->proba_.level_cost_[coeff_type];
- res->first = first;
-}
+// Finalize Segment probability based on the coding tree
-static void SetResidualCoeffs(const int16_t* const coeffs,
- VP8Residual* const res) {
- int n;
- res->last = -1;
- for (n = 15; n >= res->first; --n) {
- if (coeffs[n]) {
- res->last = n;
- break;
- }
- }
- res->coeffs = coeffs;
+static int GetProba(int a, int b) {
+ const int total = a + b;
+ return (total == 0) ? 255 // that's the default probability.
+ : (255 * a + total / 2) / total; // rounded proba
}
-//------------------------------------------------------------------------------
-// Mode costs
-
-static int GetResidualCost(int ctx, const VP8Residual* const res) {
- int n = res->first;
- int p0 = res->prob[VP8EncBands[n]][ctx][0];
- const uint16_t* t = res->cost[VP8EncBands[n]][ctx];
- int cost;
+static void SetSegmentProbas(VP8Encoder* const enc) {
+ int p[NUM_MB_SEGMENTS] = { 0 };
+ int n;
- if (res->last < 0) {
- return VP8BitCost(0, p0);
- }
- cost = 0;
- while (n <= res->last) {
- const int v = res->coeffs[n];
- const int b = VP8EncBands[n + 1];
- ++n;
- if (v == 0) {
- // short-case for VP8LevelCost(t, 0) (note: VP8LevelFixedCosts[0] == 0):
- cost += t[0];
- t = res->cost[b][0];
- continue;
- }
- cost += VP8BitCost(1, p0);
- if (2u >= (unsigned int)(v + 1)) { // v = -1 or 1
- // short-case for "VP8LevelCost(t, 1)" (256 is VP8LevelFixedCosts[1]):
- cost += 256 + t[1];
- p0 = res->prob[b][1][0];
- t = res->cost[b][1];
- } else {
- cost += VP8LevelCost(t, abs(v));
- p0 = res->prob[b][2][0];
- t = res->cost[b][2];
- }
+ for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) {
+ const VP8MBInfo* const mb = &enc->mb_info_[n];
+ p[mb->segment_]++;
}
- if (n < 16) cost += VP8BitCost(0, p0);
- return cost;
-}
-
-int VP8GetCostLuma4(VP8EncIterator* const it, const int16_t levels[16]) {
- const int x = (it->i4_ & 3), y = (it->i4_ >> 2);
- VP8Residual res;
- VP8Encoder* const enc = it->enc_;
- int R = 0;
- int ctx;
-
- InitResidual(0, 3, enc, &res);
- ctx = it->top_nz_[x] + it->left_nz_[y];
- SetResidualCoeffs(levels, &res);
- R += GetResidualCost(ctx, &res);
- return R;
-}
-
-int VP8GetCostLuma16(VP8EncIterator* const it, const VP8ModeScore* const rd) {
- VP8Residual res;
- VP8Encoder* const enc = it->enc_;
- int x, y;
- int R = 0;
-
- VP8IteratorNzToBytes(it); // re-import the non-zero context
-
- // DC
- InitResidual(0, 1, enc, &res);
- SetResidualCoeffs(rd->y_dc_levels, &res);
- R += GetResidualCost(it->top_nz_[8] + it->left_nz_[8], &res);
-
- // AC
- InitResidual(1, 0, enc, &res);
- for (y = 0; y < 4; ++y) {
- for (x = 0; x < 4; ++x) {
- const int ctx = it->top_nz_[x] + it->left_nz_[y];
- SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res);
- R += GetResidualCost(ctx, &res);
- it->top_nz_[x] = it->left_nz_[y] = (res.last >= 0);
+ if (enc->pic_->stats != NULL) {
+ for (n = 0; n < NUM_MB_SEGMENTS; ++n) {
+ enc->pic_->stats->segment_size[n] = p[n];
}
}
- return R;
-}
-
-int VP8GetCostUV(VP8EncIterator* const it, const VP8ModeScore* const rd) {
- VP8Residual res;
- VP8Encoder* const enc = it->enc_;
- int ch, x, y;
- int R = 0;
-
- VP8IteratorNzToBytes(it); // re-import the non-zero context
-
- InitResidual(0, 2, enc, &res);
- for (ch = 0; ch <= 2; ch += 2) {
- for (y = 0; y < 2; ++y) {
- for (x = 0; x < 2; ++x) {
- const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y];
- SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res);
- R += GetResidualCost(ctx, &res);
- it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = (res.last >= 0);
- }
- }
+ if (enc->segment_hdr_.num_segments_ > 1) {
+ uint8_t* const probas = enc->proba_.segments_;
+ probas[0] = GetProba(p[0] + p[1], p[2] + p[3]);
+ probas[1] = GetProba(p[0], p[1]);
+ probas[2] = GetProba(p[2], p[3]);
+
+ enc->segment_hdr_.update_map_ =
+ (probas[0] != 255) || (probas[1] != 255) || (probas[2] != 255);
+ enc->segment_hdr_.size_ =
+ p[0] * (VP8BitCost(0, probas[0]) + VP8BitCost(0, probas[1])) +
+ p[1] * (VP8BitCost(0, probas[0]) + VP8BitCost(1, probas[1])) +
+ p[2] * (VP8BitCost(1, probas[0]) + VP8BitCost(0, probas[2])) +
+ p[3] * (VP8BitCost(1, probas[0]) + VP8BitCost(1, probas[2]));
+ } else {
+ enc->segment_hdr_.update_map_ = 0;
+ enc->segment_hdr_.size_ = 0;
}
- return R;
}
//------------------------------------------------------------------------------
@@ -342,7 +222,8 @@ int VP8GetCostUV(VP8EncIterator* const it, const VP8ModeScore* const rd) {
static int PutCoeffs(VP8BitWriter* const bw, int ctx, const VP8Residual* res) {
int n = res->first;
- const uint8_t* p = res->prob[VP8EncBands[n]][ctx];
+ // should be prob[VP8EncBands[n]], but it's equivalent for n=0 or 1
+ const uint8_t* p = res->prob[n][ctx];
if (!VP8PutBit(bw, res->last >= 0, p[0])) {
return 0;
}
@@ -371,30 +252,30 @@ static int PutCoeffs(VP8BitWriter* const bw, int ctx, const VP8Residual* res) {
} else {
int mask;
const uint8_t* tab;
- if (v < 3 + (8 << 1)) { // kCat3 (3b)
+ if (v < 3 + (8 << 1)) { // VP8Cat3 (3b)
VP8PutBit(bw, 0, p[8]);
VP8PutBit(bw, 0, p[9]);
v -= 3 + (8 << 0);
mask = 1 << 2;
- tab = kCat3;
- } else if (v < 3 + (8 << 2)) { // kCat4 (4b)
+ tab = VP8Cat3;
+ } else if (v < 3 + (8 << 2)) { // VP8Cat4 (4b)
VP8PutBit(bw, 0, p[8]);
VP8PutBit(bw, 1, p[9]);
v -= 3 + (8 << 1);
mask = 1 << 3;
- tab = kCat4;
- } else if (v < 3 + (8 << 3)) { // kCat5 (5b)
+ tab = VP8Cat4;
+ } else if (v < 3 + (8 << 3)) { // VP8Cat5 (5b)
VP8PutBit(bw, 1, p[8]);
VP8PutBit(bw, 0, p[10]);
v -= 3 + (8 << 2);
mask = 1 << 4;
- tab = kCat5;
- } else { // kCat6 (11b)
+ tab = VP8Cat5;
+ } else { // VP8Cat6 (11b)
VP8PutBit(bw, 1, p[8]);
VP8PutBit(bw, 1, p[10]);
v -= 3 + (8 << 3);
mask = 1 << 10;
- tab = kCat6;
+ tab = VP8Cat6;
}
while (mask) {
VP8PutBit(bw, !!(v & mask), *tab++);
@@ -411,8 +292,7 @@ static int PutCoeffs(VP8BitWriter* const bw, int ctx, const VP8Residual* res) {
return 1;
}
-static void CodeResiduals(VP8BitWriter* const bw,
- VP8EncIterator* const it,
+static void CodeResiduals(VP8BitWriter* const bw, VP8EncIterator* const it,
const VP8ModeScore* const rd) {
int x, y, ch;
VP8Residual res;
@@ -425,32 +305,32 @@ static void CodeResiduals(VP8BitWriter* const bw,
pos1 = VP8BitWriterPos(bw);
if (i16) {
- InitResidual(0, 1, enc, &res);
- SetResidualCoeffs(rd->y_dc_levels, &res);
+ VP8InitResidual(0, 1, enc, &res);
+ VP8SetResidualCoeffs(rd->y_dc_levels, &res);
it->top_nz_[8] = it->left_nz_[8] =
PutCoeffs(bw, it->top_nz_[8] + it->left_nz_[8], &res);
- InitResidual(1, 0, enc, &res);
+ VP8InitResidual(1, 0, enc, &res);
} else {
- InitResidual(0, 3, enc, &res);
+ VP8InitResidual(0, 3, enc, &res);
}
// luma-AC
for (y = 0; y < 4; ++y) {
for (x = 0; x < 4; ++x) {
const int ctx = it->top_nz_[x] + it->left_nz_[y];
- SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res);
+ VP8SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res);
it->top_nz_[x] = it->left_nz_[y] = PutCoeffs(bw, ctx, &res);
}
}
pos2 = VP8BitWriterPos(bw);
// U/V
- InitResidual(0, 2, enc, &res);
+ VP8InitResidual(0, 2, enc, &res);
for (ch = 0; ch <= 2; ch += 2) {
for (y = 0; y < 2; ++y) {
for (x = 0; x < 2; ++x) {
const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y];
- SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res);
+ VP8SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res);
it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] =
PutCoeffs(bw, ctx, &res);
}
@@ -475,33 +355,33 @@ static void RecordResiduals(VP8EncIterator* const it,
VP8IteratorNzToBytes(it);
if (it->mb_->type_ == 1) { // i16x16
- InitResidual(0, 1, enc, &res);
- SetResidualCoeffs(rd->y_dc_levels, &res);
+ VP8InitResidual(0, 1, enc, &res);
+ VP8SetResidualCoeffs(rd->y_dc_levels, &res);
it->top_nz_[8] = it->left_nz_[8] =
- RecordCoeffs(it->top_nz_[8] + it->left_nz_[8], &res);
- InitResidual(1, 0, enc, &res);
+ VP8RecordCoeffs(it->top_nz_[8] + it->left_nz_[8], &res);
+ VP8InitResidual(1, 0, enc, &res);
} else {
- InitResidual(0, 3, enc, &res);
+ VP8InitResidual(0, 3, enc, &res);
}
// luma-AC
for (y = 0; y < 4; ++y) {
for (x = 0; x < 4; ++x) {
const int ctx = it->top_nz_[x] + it->left_nz_[y];
- SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res);
- it->top_nz_[x] = it->left_nz_[y] = RecordCoeffs(ctx, &res);
+ VP8SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res);
+ it->top_nz_[x] = it->left_nz_[y] = VP8RecordCoeffs(ctx, &res);
}
}
// U/V
- InitResidual(0, 2, enc, &res);
+ VP8InitResidual(0, 2, enc, &res);
for (ch = 0; ch <= 2; ch += 2) {
for (y = 0; y < 2; ++y) {
for (x = 0; x < 2; ++x) {
const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y];
- SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res);
+ VP8SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res);
it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] =
- RecordCoeffs(ctx, &res);
+ VP8RecordCoeffs(ctx, &res);
}
}
}
@@ -512,176 +392,59 @@ static void RecordResiduals(VP8EncIterator* const it,
//------------------------------------------------------------------------------
// Token buffer
-#ifdef USE_TOKEN_BUFFER
-
-void VP8TBufferInit(VP8TBuffer* const b) {
- b->rows_ = NULL;
- b->tokens_ = NULL;
- b->last_ = &b->rows_;
- b->left_ = 0;
- b->error_ = 0;
-}
-
-int VP8TBufferNewPage(VP8TBuffer* const b) {
- VP8Tokens* const page = b->error_ ? NULL : (VP8Tokens*)malloc(sizeof(*page));
- if (page == NULL) {
- b->error_ = 1;
- return 0;
- }
- *b->last_ = page;
- b->last_ = &page->next_;
- b->left_ = MAX_NUM_TOKEN;
- b->tokens_ = page->tokens_;
- return 1;
-}
-
-void VP8TBufferClear(VP8TBuffer* const b) {
- if (b != NULL) {
- const VP8Tokens* p = b->rows_;
- while (p != NULL) {
- const VP8Tokens* const next = p->next_;
- free((void*)p);
- p = next;
- }
- VP8TBufferInit(b);
- }
-}
-
-int VP8EmitTokens(const VP8TBuffer* const b, VP8BitWriter* const bw,
- const uint8_t* const probas) {
- VP8Tokens* p = b->rows_;
- if (b->error_) return 0;
- while (p != NULL) {
- const int N = (p->next_ == NULL) ? b->left_ : 0;
- int n = MAX_NUM_TOKEN;
- while (n-- > N) {
- VP8PutBit(bw, (p->tokens_[n] >> 15) & 1, probas[p->tokens_[n] & 0x7fff]);
- }
- p = p->next_;
- }
- return 1;
-}
-
-#define TOKEN_ID(b, ctx, p) ((p) + NUM_PROBAS * ((ctx) + (b) * NUM_CTX))
-
-static int RecordCoeffTokens(int ctx, const VP8Residual* const res,
- VP8TBuffer* tokens) {
- int n = res->first;
- int b = VP8EncBands[n];
- if (!VP8AddToken(tokens, res->last >= 0, TOKEN_ID(b, ctx, 0))) {
- return 0;
- }
-
- while (n < 16) {
- const int c = res->coeffs[n++];
- const int sign = c < 0;
- int v = sign ? -c : c;
- const int base_id = TOKEN_ID(b, ctx, 0);
- if (!VP8AddToken(tokens, v != 0, base_id + 1)) {
- b = VP8EncBands[n];
- ctx = 0;
- continue;
- }
- if (!VP8AddToken(tokens, v > 1, base_id + 2)) {
- b = VP8EncBands[n];
- ctx = 1;
- } else {
- if (!VP8AddToken(tokens, v > 4, base_id + 3)) {
- if (VP8AddToken(tokens, v != 2, base_id + 4))
- VP8AddToken(tokens, v == 4, base_id + 5);
- } else if (!VP8AddToken(tokens, v > 10, base_id + 6)) {
- if (!VP8AddToken(tokens, v > 6, base_id + 7)) {
-// VP8AddToken(tokens, v == 6, 159);
- } else {
-// VP8AddToken(tokens, v >= 9, 165);
-// VP8AddToken(tokens, !(v & 1), 145);
- }
- } else {
- int mask;
- const uint8_t* tab;
- if (v < 3 + (8 << 1)) { // kCat3 (3b)
- VP8AddToken(tokens, 0, base_id + 8);
- VP8AddToken(tokens, 0, base_id + 9);
- v -= 3 + (8 << 0);
- mask = 1 << 2;
- tab = kCat3;
- } else if (v < 3 + (8 << 2)) { // kCat4 (4b)
- VP8AddToken(tokens, 0, base_id + 8);
- VP8AddToken(tokens, 1, base_id + 9);
- v -= 3 + (8 << 1);
- mask = 1 << 3;
- tab = kCat4;
- } else if (v < 3 + (8 << 3)) { // kCat5 (5b)
- VP8AddToken(tokens, 1, base_id + 8);
- VP8AddToken(tokens, 0, base_id + 10);
- v -= 3 + (8 << 2);
- mask = 1 << 4;
- tab = kCat5;
- } else { // kCat6 (11b)
- VP8AddToken(tokens, 1, base_id + 8);
- VP8AddToken(tokens, 1, base_id + 10);
- v -= 3 + (8 << 3);
- mask = 1 << 10;
- tab = kCat6;
- }
- while (mask) {
- // VP8AddToken(tokens, !!(v & mask), *tab++);
- mask >>= 1;
- }
- }
- ctx = 2;
- }
- b = VP8EncBands[n];
- // VP8PutBitUniform(bw, sign);
- if (n == 16 || !VP8AddToken(tokens, n <= res->last, TOKEN_ID(b, ctx, 0))) {
- return 1; // EOB
- }
- }
- return 1;
-}
+#if !defined(DISABLE_TOKEN_BUFFER)
-static void RecordTokens(VP8EncIterator* const it,
- const VP8ModeScore* const rd, VP8TBuffer tokens[2]) {
+static int RecordTokens(VP8EncIterator* const it, const VP8ModeScore* const rd,
+ VP8TBuffer* const tokens) {
int x, y, ch;
VP8Residual res;
VP8Encoder* const enc = it->enc_;
VP8IteratorNzToBytes(it);
if (it->mb_->type_ == 1) { // i16x16
- InitResidual(0, 1, enc, &res);
- SetResidualCoeffs(rd->y_dc_levels, &res);
-// TODO(skal): FIX -> it->top_nz_[8] = it->left_nz_[8] =
- RecordCoeffTokens(it->top_nz_[8] + it->left_nz_[8], &res, &tokens[0]);
- InitResidual(1, 0, enc, &res);
+ const int ctx = it->top_nz_[8] + it->left_nz_[8];
+ VP8InitResidual(0, 1, enc, &res);
+ VP8SetResidualCoeffs(rd->y_dc_levels, &res);
+ it->top_nz_[8] = it->left_nz_[8] =
+ VP8RecordCoeffTokens(ctx, 1,
+ res.first, res.last, res.coeffs, tokens);
+ VP8RecordCoeffs(ctx, &res);
+ VP8InitResidual(1, 0, enc, &res);
} else {
- InitResidual(0, 3, enc, &res);
+ VP8InitResidual(0, 3, enc, &res);
}
// luma-AC
for (y = 0; y < 4; ++y) {
for (x = 0; x < 4; ++x) {
const int ctx = it->top_nz_[x] + it->left_nz_[y];
- SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res);
+ VP8SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res);
it->top_nz_[x] = it->left_nz_[y] =
- RecordCoeffTokens(ctx, &res, &tokens[0]);
+ VP8RecordCoeffTokens(ctx, res.coeff_type,
+ res.first, res.last, res.coeffs, tokens);
+ VP8RecordCoeffs(ctx, &res);
}
}
// U/V
- InitResidual(0, 2, enc, &res);
+ VP8InitResidual(0, 2, enc, &res);
for (ch = 0; ch <= 2; ch += 2) {
for (y = 0; y < 2; ++y) {
for (x = 0; x < 2; ++x) {
const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y];
- SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res);
+ VP8SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res);
it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] =
- RecordCoeffTokens(ctx, &res, &tokens[1]);
+ VP8RecordCoeffTokens(ctx, 2,
+ res.first, res.last, res.coeffs, tokens);
+ VP8RecordCoeffs(ctx, &res);
}
}
}
+ VP8IteratorBytesToNz(it);
+ return !tokens->error_;
}
-#endif // USE_TOKEN_BUFFER
+#endif // !DISABLE_TOKEN_BUFFER
//------------------------------------------------------------------------------
// ExtraInfo map / Debug function
@@ -697,7 +460,10 @@ static void SetBlock(uint8_t* p, int value, int size) {
#endif
static void ResetSSE(VP8Encoder* const enc) {
- memset(enc->sse_, 0, sizeof(enc->sse_));
+ enc->sse_[0] = 0;
+ enc->sse_[1] = 0;
+ enc->sse_[2] = 0;
+ // Note: enc->sse_[3] is managed by alpha.c
enc->sse_count_ = 0;
}
@@ -706,9 +472,9 @@ static void StoreSSE(const VP8EncIterator* const it) {
const uint8_t* const in = it->yuv_in_;
const uint8_t* const out = it->yuv_out_;
// Note: not totally accurate at boundary. And doesn't include in-loop filter.
- enc->sse_[0] += VP8SSE16x16(in + Y_OFF, out + Y_OFF);
- enc->sse_[1] += VP8SSE8x8(in + U_OFF, out + U_OFF);
- enc->sse_[2] += VP8SSE8x8(in + V_OFF, out + V_OFF);
+ enc->sse_[0] += VP8SSE16x16(in + Y_OFF_ENC, out + Y_OFF_ENC);
+ enc->sse_[1] += VP8SSE8x8(in + U_OFF_ENC, out + U_OFF_ENC);
+ enc->sse_[2] += VP8SSE8x8(in + V_OFF_ENC, out + V_OFF_ENC);
enc->sse_count_ += 16 * 16;
}
@@ -736,72 +502,163 @@ static void StoreSideInfo(const VP8EncIterator* const it) {
const int b = (int)((it->luma_bits_ + it->uv_bits_ + 7) >> 3);
*info = (b > 255) ? 255 : b; break;
}
+ case 7: *info = mb->alpha_; break;
default: *info = 0; break;
- };
+ }
}
#if SEGMENT_VISU // visualize segments and prediction modes
- SetBlock(it->yuv_out_ + Y_OFF, mb->segment_ * 64, 16);
- SetBlock(it->yuv_out_ + U_OFF, it->preds_[0] * 64, 8);
- SetBlock(it->yuv_out_ + V_OFF, mb->uv_mode_ * 64, 8);
+ SetBlock(it->yuv_out_ + Y_OFF_ENC, mb->segment_ * 64, 16);
+ SetBlock(it->yuv_out_ + U_OFF_ENC, it->preds_[0] * 64, 8);
+ SetBlock(it->yuv_out_ + V_OFF_ENC, mb->uv_mode_ * 64, 8);
#endif
}
-//------------------------------------------------------------------------------
-// Main loops
-//
-// VP8EncLoop(): does the final bitstream coding.
-
-static void ResetAfterSkip(VP8EncIterator* const it) {
- if (it->mb_->type_ == 1) {
- *it->nz_ = 0; // reset all predictors
- it->left_nz_[8] = 0;
- } else {
- *it->nz_ &= (1 << 24); // preserve the dc_nz bit
- }
+static double GetPSNR(uint64_t mse, uint64_t size) {
+ return (mse > 0 && size > 0) ? 10. * log10(255. * 255. * size / mse) : 99;
}
-int VP8EncLoop(VP8Encoder* const enc) {
- int i, s, p;
- int ok = 1;
- VP8EncIterator it;
- VP8ModeScore info;
- const int dont_use_skip = !enc->proba_.use_skip_proba_;
- const int rd_opt = enc->rd_opt_level_;
- const int kAverageBytesPerMB = 5; // TODO: have a kTable[quality/10]
- const int bytes_per_parts =
- enc->mb_w_ * enc->mb_h_ * kAverageBytesPerMB / enc->num_parts_;
+//------------------------------------------------------------------------------
+// StatLoop(): only collect statistics (number of skips, token usage, ...).
+// This is used for deciding optimal probabilities. It also modifies the
+// quantizer value if some target (size, PSNR) was specified.
- // Initialize the bit-writers
- for (p = 0; p < enc->num_parts_; ++p) {
- VP8BitWriterInit(enc->parts_ + p, bytes_per_parts);
- }
+static void SetLoopParams(VP8Encoder* const enc, float q) {
+ // Make sure the quality parameter is inside valid bounds
+ q = Clamp(q, 0.f, 100.f);
+
+ VP8SetSegmentParams(enc, q); // setup segment quantizations and filters
+ SetSegmentProbas(enc); // compute segment probabilities
ResetStats(enc);
ResetSSE(enc);
+}
+
+static uint64_t OneStatPass(VP8Encoder* const enc, VP8RDLevel rd_opt,
+ int nb_mbs, int percent_delta,
+ PassStats* const s) {
+ VP8EncIterator it;
+ uint64_t size = 0;
+ uint64_t size_p0 = 0;
+ uint64_t distortion = 0;
+ const uint64_t pixel_count = nb_mbs * 384;
VP8IteratorInit(enc, &it);
- VP8InitFilter(&it);
+ SetLoopParams(enc, s->q);
do {
- VP8IteratorImport(&it);
- // Warning! order is important: first call VP8Decimate() and
- // *then* decide how to code the skip decision if there's one.
- if (!VP8Decimate(&it, &info, rd_opt) || dont_use_skip) {
- CodeResiduals(it.bw_, &it, &info);
- } else { // reset predictors after a skip
- ResetAfterSkip(&it);
+ VP8ModeScore info;
+ VP8IteratorImport(&it, NULL);
+ if (VP8Decimate(&it, &info, rd_opt)) {
+ // Just record the number of skips and act like skip_proba is not used.
+ enc->proba_.nb_skip_++;
}
-#ifdef WEBP_EXPERIMENTAL_FEATURES
- if (enc->use_layer_) {
- VP8EncCodeLayerBlock(&it);
+ RecordResiduals(&it, &info);
+ size += info.R + info.H;
+ size_p0 += info.H;
+ distortion += info.D;
+ if (percent_delta && !VP8IteratorProgress(&it, percent_delta))
+ return 0;
+ VP8IteratorSaveBoundary(&it);
+ } while (VP8IteratorNext(&it) && --nb_mbs > 0);
+
+ size_p0 += enc->segment_hdr_.size_;
+ if (s->do_size_search) {
+ size += FinalizeSkipProba(enc);
+ size += FinalizeTokenProbas(&enc->proba_);
+ size = ((size + size_p0 + 1024) >> 11) + HEADER_SIZE_ESTIMATE;
+ s->value = (double)size;
+ } else {
+ s->value = GetPSNR(distortion, pixel_count);
+ }
+ return size_p0;
+}
+
+static int StatLoop(VP8Encoder* const enc) {
+ const int method = enc->method_;
+ const int do_search = enc->do_search_;
+ const int fast_probe = ((method == 0 || method == 3) && !do_search);
+ int num_pass_left = enc->config_->pass;
+ const int task_percent = 20;
+ const int percent_per_pass =
+ (task_percent + num_pass_left / 2) / num_pass_left;
+ const int final_percent = enc->percent_ + task_percent;
+ const VP8RDLevel rd_opt =
+ (method >= 3 || do_search) ? RD_OPT_BASIC : RD_OPT_NONE;
+ int nb_mbs = enc->mb_w_ * enc->mb_h_;
+ PassStats stats;
+
+ InitPassStats(enc, &stats);
+ ResetTokenStats(enc);
+
+ // Fast mode: quick analysis pass over few mbs. Better than nothing.
+ if (fast_probe) {
+ if (method == 3) { // we need more stats for method 3 to be reliable.
+ nb_mbs = (nb_mbs > 200) ? nb_mbs >> 1 : 100;
+ } else {
+ nb_mbs = (nb_mbs > 200) ? nb_mbs >> 2 : 50;
}
+ }
+
+ while (num_pass_left-- > 0) {
+ const int is_last_pass = (fabs(stats.dq) <= DQ_LIMIT) ||
+ (num_pass_left == 0) ||
+ (enc->max_i4_header_bits_ == 0);
+ const uint64_t size_p0 =
+ OneStatPass(enc, rd_opt, nb_mbs, percent_per_pass, &stats);
+ if (size_p0 == 0) return 0;
+#if (DEBUG_SEARCH > 0)
+ printf("#%d value:%.1lf -> %.1lf q:%.2f -> %.2f\n",
+ num_pass_left, stats.last_value, stats.value, stats.last_q, stats.q);
#endif
- StoreSideInfo(&it);
- VP8StoreFilterStats(&it);
- VP8IteratorExport(&it);
- ok = VP8IteratorProgress(&it, 20);
- } while (ok && VP8IteratorNext(&it, it.yuv_out_));
+ if (enc->max_i4_header_bits_ > 0 && size_p0 > PARTITION0_SIZE_LIMIT) {
+ ++num_pass_left;
+ enc->max_i4_header_bits_ >>= 1; // strengthen header bit limitation...
+ continue; // ...and start over
+ }
+ if (is_last_pass) {
+ break;
+ }
+ // If no target size: just do several pass without changing 'q'
+ if (do_search) {
+ ComputeNextQ(&stats);
+ if (fabs(stats.dq) <= DQ_LIMIT) break;
+ }
+ }
+ if (!do_search || !stats.do_size_search) {
+ // Need to finalize probas now, since it wasn't done during the search.
+ FinalizeSkipProba(enc);
+ FinalizeTokenProbas(&enc->proba_);
+ }
+ VP8CalculateLevelCosts(&enc->proba_); // finalize costs
+ return WebPReportProgress(enc->pic_, final_percent, &enc->percent_);
+}
+
+//------------------------------------------------------------------------------
+// Main loops
+//
+
+static const int kAverageBytesPerMB[8] = { 50, 24, 16, 9, 7, 5, 3, 2 };
+static int PreLoopInitialize(VP8Encoder* const enc) {
+ int p;
+ int ok = 1;
+ const int average_bytes_per_MB = kAverageBytesPerMB[enc->base_quant_ >> 4];
+ const int bytes_per_parts =
+ enc->mb_w_ * enc->mb_h_ * average_bytes_per_MB / enc->num_parts_;
+ // Initialize the bit-writers
+ for (p = 0; ok && p < enc->num_parts_; ++p) {
+ ok = VP8BitWriterInit(enc->parts_ + p, bytes_per_parts);
+ }
+ if (!ok) {
+ VP8EncFreeBitWriters(enc); // malloc error occurred
+ WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ }
+ return ok;
+}
+
+static int PostLoopFinalize(VP8EncIterator* const it, int ok) {
+ VP8Encoder* const enc = it->enc_;
if (ok) { // Finalize the partitions, check for extra errors.
+ int p;
for (p = 0; p < enc->num_parts_; ++p) {
VP8BitWriterFinish(enc->parts_ + p);
ok &= !enc->parts_[p].error_;
@@ -809,131 +666,185 @@ int VP8EncLoop(VP8Encoder* const enc) {
}
if (ok) { // All good. Finish up.
- if (enc->pic_->stats) { // finalize byte counters...
+ if (enc->pic_->stats != NULL) { // finalize byte counters...
+ int i, s;
for (i = 0; i <= 2; ++i) {
for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
- enc->residual_bytes_[i][s] = (int)((it.bit_count_[s][i] + 7) >> 3);
+ enc->residual_bytes_[i][s] = (int)((it->bit_count_[s][i] + 7) >> 3);
}
}
}
- VP8AdjustFilterStrength(&it); // ...and store filter stats.
+ VP8AdjustFilterStrength(it); // ...and store filter stats.
} else {
// Something bad happened -> need to do some memory cleanup.
VP8EncFreeBitWriters(enc);
}
-
return ok;
}
//------------------------------------------------------------------------------
-// VP8StatLoop(): only collect statistics (number of skips, token usage, ...)
-// This is used for deciding optimal probabilities. It also
-// modifies the quantizer value if some target (size, PNSR)
-// was specified.
-
-#define kHeaderSizeEstimate (15 + 20 + 10) // TODO: fix better
-
-static int OneStatPass(VP8Encoder* const enc, float q, int rd_opt, int nb_mbs,
- float* const PSNR, int percent_delta) {
- VP8EncIterator it;
- uint64_t size = 0;
- uint64_t distortion = 0;
- const uint64_t pixel_count = nb_mbs * 384;
+// VP8EncLoop(): does the final bitstream coding.
- // Make sure the quality parameter is inside valid bounds
- if (q < 0.) {
- q = 0;
- } else if (q > 100.) {
- q = 100;
+static void ResetAfterSkip(VP8EncIterator* const it) {
+ if (it->mb_->type_ == 1) {
+ *it->nz_ = 0; // reset all predictors
+ it->left_nz_[8] = 0;
+ } else {
+ *it->nz_ &= (1 << 24); // preserve the dc_nz bit
}
+}
- VP8SetSegmentParams(enc, q); // setup segment quantizations and filters
+int VP8EncLoop(VP8Encoder* const enc) {
+ VP8EncIterator it;
+ int ok = PreLoopInitialize(enc);
+ if (!ok) return 0;
- ResetStats(enc);
- ResetTokenStats(enc);
+ StatLoop(enc); // stats-collection loop
VP8IteratorInit(enc, &it);
+ VP8InitFilter(&it);
do {
VP8ModeScore info;
- VP8IteratorImport(&it);
- if (VP8Decimate(&it, &info, rd_opt)) {
- // Just record the number of skips and act like skip_proba is not used.
- enc->proba_.nb_skip_++;
+ const int dont_use_skip = !enc->proba_.use_skip_proba_;
+ const VP8RDLevel rd_opt = enc->rd_opt_level_;
+
+ VP8IteratorImport(&it, NULL);
+ // Warning! order is important: first call VP8Decimate() and
+ // *then* decide how to code the skip decision if there's one.
+ if (!VP8Decimate(&it, &info, rd_opt) || dont_use_skip) {
+ CodeResiduals(it.bw_, &it, &info);
+ } else { // reset predictors after a skip
+ ResetAfterSkip(&it);
}
- RecordResiduals(&it, &info);
- size += info.R;
- distortion += info.D;
- if (percent_delta && !VP8IteratorProgress(&it, percent_delta))
- return 0;
- } while (VP8IteratorNext(&it, it.yuv_out_) && --nb_mbs > 0);
- size += FinalizeSkipProba(enc);
- size += FinalizeTokenProbas(enc);
- size += enc->segment_hdr_.size_;
- size = ((size + 1024) >> 11) + kHeaderSizeEstimate;
-
- if (PSNR) {
- *PSNR = (float)(10.* log10(255. * 255. * pixel_count / distortion));
- }
- return (int)size;
+ StoreSideInfo(&it);
+ VP8StoreFilterStats(&it);
+ VP8IteratorExport(&it);
+ ok = VP8IteratorProgress(&it, 20);
+ VP8IteratorSaveBoundary(&it);
+ } while (ok && VP8IteratorNext(&it));
+
+ return PostLoopFinalize(&it, ok);
}
-// successive refinement increments.
-static const int dqs[] = { 20, 15, 10, 8, 6, 4, 2, 1, 0 };
+//------------------------------------------------------------------------------
+// Single pass using Token Buffer.
-int VP8StatLoop(VP8Encoder* const enc) {
- const int do_search =
- (enc->config_->target_size > 0 || enc->config_->target_PSNR > 0);
- const int fast_probe = (enc->method_ < 2 && !do_search);
- float q = enc->config_->quality;
- const int max_passes = enc->config_->pass;
- const int task_percent = 20;
- const int percent_per_pass = (task_percent + max_passes / 2) / max_passes;
- const int final_percent = enc->percent_ + task_percent;
- int pass;
- int nb_mbs;
+#if !defined(DISABLE_TOKEN_BUFFER)
- // Fast mode: quick analysis pass over few mbs. Better than nothing.
- nb_mbs = enc->mb_w_ * enc->mb_h_;
- if (fast_probe && nb_mbs > 100) nb_mbs = 100;
-
- // No target size: just do several pass without changing 'q'
- if (!do_search) {
- for (pass = 0; pass < max_passes; ++pass) {
- const int rd_opt = (enc->method_ > 2);
- if (!OneStatPass(enc, q, rd_opt, nb_mbs, NULL, percent_per_pass)) {
- return 0;
- }
+#define MIN_COUNT 96 // minimum number of macroblocks before updating stats
+
+int VP8EncTokenLoop(VP8Encoder* const enc) {
+ // Roughly refresh the proba eight times per pass
+ int max_count = (enc->mb_w_ * enc->mb_h_) >> 3;
+ int num_pass_left = enc->config_->pass;
+ const int do_search = enc->do_search_;
+ VP8EncIterator it;
+ VP8EncProba* const proba = &enc->proba_;
+ const VP8RDLevel rd_opt = enc->rd_opt_level_;
+ const uint64_t pixel_count = enc->mb_w_ * enc->mb_h_ * 384;
+ PassStats stats;
+ int ok;
+
+ InitPassStats(enc, &stats);
+ ok = PreLoopInitialize(enc);
+ if (!ok) return 0;
+
+ if (max_count < MIN_COUNT) max_count = MIN_COUNT;
+
+ assert(enc->num_parts_ == 1);
+ assert(enc->use_tokens_);
+ assert(proba->use_skip_proba_ == 0);
+ assert(rd_opt >= RD_OPT_BASIC); // otherwise, token-buffer won't be useful
+ assert(num_pass_left > 0);
+
+ while (ok && num_pass_left-- > 0) {
+ const int is_last_pass = (fabs(stats.dq) <= DQ_LIMIT) ||
+ (num_pass_left == 0) ||
+ (enc->max_i4_header_bits_ == 0);
+ uint64_t size_p0 = 0;
+ uint64_t distortion = 0;
+ int cnt = max_count;
+ VP8IteratorInit(enc, &it);
+ SetLoopParams(enc, stats.q);
+ if (is_last_pass) {
+ ResetTokenStats(enc);
+ VP8InitFilter(&it); // don't collect stats until last pass (too costly)
}
- } else {
- // binary search for a size close to target
- for (pass = 0; pass < max_passes && (dqs[pass] > 0); ++pass) {
- const int rd_opt = 1;
- float PSNR;
- int criterion;
- const int size = OneStatPass(enc, q, rd_opt, nb_mbs, &PSNR,
- percent_per_pass);
-#if DEBUG_SEARCH
- printf("#%d size=%d PSNR=%.2f q=%.2f\n", pass, size, PSNR, q);
-#endif
- if (!size) return 0;
- if (enc->config_->target_PSNR > 0) {
- criterion = (PSNR < enc->config_->target_PSNR);
- } else {
- criterion = (size < enc->config_->target_size);
+ VP8TBufferClear(&enc->tokens_);
+ do {
+ VP8ModeScore info;
+ VP8IteratorImport(&it, NULL);
+ if (--cnt < 0) {
+ FinalizeTokenProbas(proba);
+ VP8CalculateLevelCosts(proba); // refresh cost tables for rd-opt
+ cnt = max_count;
}
- // dichotomize
- if (criterion) {
- q += dqs[pass];
- } else {
- q -= dqs[pass];
+ VP8Decimate(&it, &info, rd_opt);
+ ok = RecordTokens(&it, &info, &enc->tokens_);
+ if (!ok) {
+ WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ break;
+ }
+ size_p0 += info.H;
+ distortion += info.D;
+ if (is_last_pass) {
+ StoreSideInfo(&it);
+ VP8StoreFilterStats(&it);
+ VP8IteratorExport(&it);
+ ok = VP8IteratorProgress(&it, 20);
}
+ VP8IteratorSaveBoundary(&it);
+ } while (ok && VP8IteratorNext(&it));
+ if (!ok) break;
+
+ size_p0 += enc->segment_hdr_.size_;
+ if (stats.do_size_search) {
+ uint64_t size = FinalizeTokenProbas(&enc->proba_);
+ size += VP8EstimateTokenSize(&enc->tokens_,
+ (const uint8_t*)proba->coeffs_);
+ size = (size + size_p0 + 1024) >> 11; // -> size in bytes
+ size += HEADER_SIZE_ESTIMATE;
+ stats.value = (double)size;
+ } else { // compute and store PSNR
+ stats.value = GetPSNR(distortion, pixel_count);
+ }
+
+#if (DEBUG_SEARCH > 0)
+ printf("#%2d metric:%.1lf -> %.1lf last_q=%.2lf q=%.2lf dq=%.2lf\n",
+ num_pass_left, stats.last_value, stats.value,
+ stats.last_q, stats.q, stats.dq);
+#endif
+ if (size_p0 > PARTITION0_SIZE_LIMIT) {
+ ++num_pass_left;
+ enc->max_i4_header_bits_ >>= 1; // strengthen header bit limitation...
+ continue; // ...and start over
+ }
+ if (is_last_pass) {
+ break; // done
+ }
+ if (do_search) {
+ ComputeNextQ(&stats); // Adjust q
}
}
- return WebPReportProgress(enc->pic_, final_percent, &enc->percent_);
+ if (ok) {
+ if (!stats.do_size_search) {
+ FinalizeTokenProbas(&enc->proba_);
+ }
+ ok = VP8EmitTokens(&enc->tokens_, enc->parts_ + 0,
+ (const uint8_t*)proba->coeffs_, 1);
+ }
+ ok = ok && WebPReportProgress(enc->pic_, enc->percent_ + 20, &enc->percent_);
+ return PostLoopFinalize(&it, ok);
+}
+
+#else
+
+int VP8EncTokenLoop(VP8Encoder* const enc) {
+ (void)enc;
+ return 0; // we shouldn't be here.
}
+#endif // DISABLE_TOKEN_BUFFER
+
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/enc/histogram.c b/drivers/webp/enc/histogram.c
index ca838e064d..68c27fb1db 100644
--- a/drivers/webp/enc/histogram.c
+++ b/drivers/webp/enc/histogram.c
@@ -1,38 +1,82 @@
// Copyright 2012 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Author: Jyrki Alakuijala (jyrki@google.com)
//
#ifdef HAVE_CONFIG_H
-#include "config.h"
+#include "webp/config.h"
#endif
#include <math.h>
-#include <stdio.h>
#include "./backward_references.h"
#include "./histogram.h"
#include "../dsp/lossless.h"
#include "../utils/utils.h"
+#define MAX_COST 1.e38
+
+// Number of partitions for the three dominant (literal, red and blue) symbol
+// costs.
+#define NUM_PARTITIONS 4
+// The size of the bin-hash corresponding to the three dominant costs.
+#define BIN_SIZE (NUM_PARTITIONS * NUM_PARTITIONS * NUM_PARTITIONS)
+// Maximum number of histograms allowed in greedy combining algorithm.
+#define MAX_HISTO_GREEDY 100
+
static void HistogramClear(VP8LHistogram* const p) {
- memset(p->literal_, 0, sizeof(p->literal_));
- memset(p->red_, 0, sizeof(p->red_));
- memset(p->blue_, 0, sizeof(p->blue_));
- memset(p->alpha_, 0, sizeof(p->alpha_));
- memset(p->distance_, 0, sizeof(p->distance_));
- p->bit_cost_ = 0;
+ uint32_t* const literal = p->literal_;
+ const int cache_bits = p->palette_code_bits_;
+ const int histo_size = VP8LGetHistogramSize(cache_bits);
+ memset(p, 0, histo_size);
+ p->palette_code_bits_ = cache_bits;
+ p->literal_ = literal;
+}
+
+// Swap two histogram pointers.
+static void HistogramSwap(VP8LHistogram** const A, VP8LHistogram** const B) {
+ VP8LHistogram* const tmp = *A;
+ *A = *B;
+ *B = tmp;
+}
+
+static void HistogramCopy(const VP8LHistogram* const src,
+ VP8LHistogram* const dst) {
+ uint32_t* const dst_literal = dst->literal_;
+ const int dst_cache_bits = dst->palette_code_bits_;
+ const int histo_size = VP8LGetHistogramSize(dst_cache_bits);
+ assert(src->palette_code_bits_ == dst_cache_bits);
+ memcpy(dst, src, histo_size);
+ dst->literal_ = dst_literal;
+}
+
+int VP8LGetHistogramSize(int cache_bits) {
+ const int literal_size = VP8LHistogramNumCodes(cache_bits);
+ const size_t total_size = sizeof(VP8LHistogram) + sizeof(int) * literal_size;
+ assert(total_size <= (size_t)0x7fffffff);
+ return (int)total_size;
+}
+
+void VP8LFreeHistogram(VP8LHistogram* const histo) {
+ WebPSafeFree(histo);
+}
+
+void VP8LFreeHistogramSet(VP8LHistogramSet* const histo) {
+ WebPSafeFree(histo);
}
void VP8LHistogramStoreRefs(const VP8LBackwardRefs* const refs,
VP8LHistogram* const histo) {
- int i;
- for (i = 0; i < refs->size; ++i) {
- VP8LHistogramAddSinglePixOrCopy(histo, &refs->refs[i]);
+ VP8LRefsCursor c = VP8LRefsCursorInit(refs);
+ while (VP8LRefsCursorOk(&c)) {
+ VP8LHistogramAddSinglePixOrCopy(histo, c.cur_pos);
+ VP8LRefsCursorNext(&c);
}
}
@@ -51,13 +95,25 @@ void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits) {
HistogramClear(p);
}
+VP8LHistogram* VP8LAllocateHistogram(int cache_bits) {
+ VP8LHistogram* histo = NULL;
+ const int total_size = VP8LGetHistogramSize(cache_bits);
+ uint8_t* const memory = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*memory));
+ if (memory == NULL) return NULL;
+ histo = (VP8LHistogram*)memory;
+ // literal_ won't necessary be aligned.
+ histo->literal_ = (uint32_t*)(memory + sizeof(VP8LHistogram));
+ VP8LHistogramInit(histo, cache_bits);
+ return histo;
+}
+
VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits) {
int i;
VP8LHistogramSet* set;
- VP8LHistogram* bulk;
- const uint64_t total_size = (uint64_t)sizeof(*set)
- + size * sizeof(*set->histograms)
- + size * sizeof(**set->histograms);
+ const int histo_size = VP8LGetHistogramSize(cache_bits);
+ const size_t total_size =
+ sizeof(*set) + size * (sizeof(*set->histograms) +
+ histo_size + WEBP_ALIGN_CST);
uint8_t* memory = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*memory));
if (memory == NULL) return NULL;
@@ -65,12 +121,15 @@ VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits) {
memory += sizeof(*set);
set->histograms = (VP8LHistogram**)memory;
memory += size * sizeof(*set->histograms);
- bulk = (VP8LHistogram*)memory;
set->max_size = size;
set->size = size;
for (i = 0; i < size; ++i) {
- set->histograms[i] = bulk + i;
+ memory = (uint8_t*)WEBP_ALIGN(memory);
+ set->histograms[i] = (VP8LHistogram*)memory;
+ // literal_ won't necessary be aligned.
+ set->histograms[i]->literal_ = (uint32_t*)(memory + sizeof(VP8LHistogram));
VP8LHistogramInit(set->histograms[i], cache_bits);
+ memory += histo_size;
}
return set;
}
@@ -85,151 +144,183 @@ void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo,
++histo->literal_[PixOrCopyLiteral(v, 1)];
++histo->blue_[PixOrCopyLiteral(v, 0)];
} else if (PixOrCopyIsCacheIdx(v)) {
- int literal_ix = 256 + NUM_LENGTH_CODES + PixOrCopyCacheIdx(v);
+ const int literal_ix =
+ NUM_LITERAL_CODES + NUM_LENGTH_CODES + PixOrCopyCacheIdx(v);
++histo->literal_[literal_ix];
} else {
- int code, extra_bits_count, extra_bits_value;
- PrefixEncode(PixOrCopyLength(v),
- &code, &extra_bits_count, &extra_bits_value);
- ++histo->literal_[256 + code];
- PrefixEncode(PixOrCopyDistance(v),
- &code, &extra_bits_count, &extra_bits_value);
+ int code, extra_bits;
+ VP8LPrefixEncodeBits(PixOrCopyLength(v), &code, &extra_bits);
+ ++histo->literal_[NUM_LITERAL_CODES + code];
+ VP8LPrefixEncodeBits(PixOrCopyDistance(v), &code, &extra_bits);
++histo->distance_[code];
}
}
+// -----------------------------------------------------------------------------
+// Various histogram combine/cost-eval functions
+
+static int GetCombinedHistogramEntropy(const VP8LHistogram* const a,
+ const VP8LHistogram* const b,
+ double cost_threshold,
+ double* cost) {
+ const int palette_code_bits = a->palette_code_bits_;
+ assert(a->palette_code_bits_ == b->palette_code_bits_);
+ *cost += VP8LGetCombinedEntropy(a->literal_, b->literal_,
+ VP8LHistogramNumCodes(palette_code_bits));
+ *cost += VP8LExtraCostCombined(a->literal_ + NUM_LITERAL_CODES,
+ b->literal_ + NUM_LITERAL_CODES,
+ NUM_LENGTH_CODES);
+ if (*cost > cost_threshold) return 0;
+
+ *cost += VP8LGetCombinedEntropy(a->red_, b->red_, NUM_LITERAL_CODES);
+ if (*cost > cost_threshold) return 0;
+
+ *cost += VP8LGetCombinedEntropy(a->blue_, b->blue_, NUM_LITERAL_CODES);
+ if (*cost > cost_threshold) return 0;
+
+ *cost += VP8LGetCombinedEntropy(a->alpha_, b->alpha_, NUM_LITERAL_CODES);
+ if (*cost > cost_threshold) return 0;
+
+ *cost += VP8LGetCombinedEntropy(a->distance_, b->distance_,
+ NUM_DISTANCE_CODES);
+ *cost += VP8LExtraCostCombined(a->distance_, b->distance_,
+ NUM_DISTANCE_CODES);
+ if (*cost > cost_threshold) return 0;
+
+ return 1;
+}
-
-static double BitsEntropy(const int* const array, int n) {
- double retval = 0.;
- int sum = 0;
- int nonzeros = 0;
- int max_val = 0;
- int i;
- double mix;
- for (i = 0; i < n; ++i) {
- if (array[i] != 0) {
- sum += array[i];
- ++nonzeros;
- retval -= VP8LFastSLog2(array[i]);
- if (max_val < array[i]) {
- max_val = array[i];
- }
- }
+// Performs out = a + b, computing the cost C(a+b) - C(a) - C(b) while comparing
+// to the threshold value 'cost_threshold'. The score returned is
+// Score = C(a+b) - C(a) - C(b), where C(a) + C(b) is known and fixed.
+// Since the previous score passed is 'cost_threshold', we only need to compare
+// the partial cost against 'cost_threshold + C(a) + C(b)' to possibly bail-out
+// early.
+static double HistogramAddEval(const VP8LHistogram* const a,
+ const VP8LHistogram* const b,
+ VP8LHistogram* const out,
+ double cost_threshold) {
+ double cost = 0;
+ const double sum_cost = a->bit_cost_ + b->bit_cost_;
+ cost_threshold += sum_cost;
+
+ if (GetCombinedHistogramEntropy(a, b, cost_threshold, &cost)) {
+ VP8LHistogramAdd(a, b, out);
+ out->bit_cost_ = cost;
+ out->palette_code_bits_ = a->palette_code_bits_;
+ out->trivial_symbol_ = (a->trivial_symbol_ == b->trivial_symbol_) ?
+ a->trivial_symbol_ : VP8L_NON_TRIVIAL_SYM;
}
- retval += VP8LFastSLog2(sum);
- if (nonzeros < 5) {
- if (nonzeros <= 1) {
- return 0;
- }
- // Two symbols, they will be 0 and 1 in a Huffman code.
- // Let's mix in a bit of entropy to favor good clustering when
- // distributions of these are combined.
- if (nonzeros == 2) {
- return 0.99 * sum + 0.01 * retval;
- }
- // No matter what the entropy says, we cannot be better than min_limit
- // with Huffman coding. I am mixing a bit of entropy into the
- // min_limit since it produces much better (~0.5 %) compression results
- // perhaps because of better entropy clustering.
- if (nonzeros == 3) {
- mix = 0.95;
- } else {
- mix = 0.7; // nonzeros == 4.
- }
- } else {
- mix = 0.627;
- }
+ return cost - sum_cost;
+}
- {
- double min_limit = 2 * sum - max_val;
- min_limit = mix * min_limit + (1.0 - mix) * retval;
- return (retval < min_limit) ? min_limit : retval;
- }
+// Same as HistogramAddEval(), except that the resulting histogram
+// is not stored. Only the cost C(a+b) - C(a) is evaluated. We omit
+// the term C(b) which is constant over all the evaluations.
+static double HistogramAddThresh(const VP8LHistogram* const a,
+ const VP8LHistogram* const b,
+ double cost_threshold) {
+ double cost = -a->bit_cost_;
+ GetCombinedHistogramEntropy(a, b, cost_threshold, &cost);
+ return cost;
}
-double VP8LHistogramEstimateBitsBulk(const VP8LHistogram* const p) {
- double retval = BitsEntropy(&p->literal_[0], VP8LHistogramNumCodes(p))
- + BitsEntropy(&p->red_[0], 256)
- + BitsEntropy(&p->blue_[0], 256)
- + BitsEntropy(&p->alpha_[0], 256)
- + BitsEntropy(&p->distance_[0], NUM_DISTANCE_CODES);
- // Compute the extra bits cost.
- int i;
- for (i = 2; i < NUM_LENGTH_CODES - 2; ++i) {
- retval +=
- (i >> 1) * p->literal_[256 + i + 2];
- }
- for (i = 2; i < NUM_DISTANCE_CODES - 2; ++i) {
- retval += (i >> 1) * p->distance_[i + 2];
- }
- return retval;
-}
-
-
-// Returns the cost encode the rle-encoded entropy code.
-// The constants in this function are experimental.
-static double HuffmanCost(const int* const population, int length) {
- // Small bias because Huffman code length is typically not stored in
- // full length.
- static const int kHuffmanCodeOfHuffmanCodeSize = CODE_LENGTH_CODES * 3;
- static const double kSmallBias = 9.1;
- double retval = kHuffmanCodeOfHuffmanCodeSize - kSmallBias;
- int streak = 0;
- int i = 0;
- for (; i < length - 1; ++i) {
- ++streak;
- if (population[i] == population[i + 1]) {
- continue;
- }
- last_streak_hack:
- // population[i] points now to the symbol in the streak of same values.
- if (streak > 3) {
- if (population[i] == 0) {
- retval += 1.5625 + 0.234375 * streak;
- } else {
- retval += 2.578125 + 0.703125 * streak;
- }
- } else {
- if (population[i] == 0) {
- retval += 1.796875 * streak;
- } else {
- retval += 3.28125 * streak;
- }
- }
- streak = 0;
- }
- if (i == length - 1) {
- ++streak;
- goto last_streak_hack;
+// -----------------------------------------------------------------------------
+
+// The structure to keep track of cost range for the three dominant entropy
+// symbols.
+// TODO(skal): Evaluate if float can be used here instead of double for
+// representing the entropy costs.
+typedef struct {
+ double literal_max_;
+ double literal_min_;
+ double red_max_;
+ double red_min_;
+ double blue_max_;
+ double blue_min_;
+} DominantCostRange;
+
+static void DominantCostRangeInit(DominantCostRange* const c) {
+ c->literal_max_ = 0.;
+ c->literal_min_ = MAX_COST;
+ c->red_max_ = 0.;
+ c->red_min_ = MAX_COST;
+ c->blue_max_ = 0.;
+ c->blue_min_ = MAX_COST;
+}
+
+static void UpdateDominantCostRange(
+ const VP8LHistogram* const h, DominantCostRange* const c) {
+ if (c->literal_max_ < h->literal_cost_) c->literal_max_ = h->literal_cost_;
+ if (c->literal_min_ > h->literal_cost_) c->literal_min_ = h->literal_cost_;
+ if (c->red_max_ < h->red_cost_) c->red_max_ = h->red_cost_;
+ if (c->red_min_ > h->red_cost_) c->red_min_ = h->red_cost_;
+ if (c->blue_max_ < h->blue_cost_) c->blue_max_ = h->blue_cost_;
+ if (c->blue_min_ > h->blue_cost_) c->blue_min_ = h->blue_cost_;
+}
+
+static void UpdateHistogramCost(VP8LHistogram* const h) {
+ uint32_t alpha_sym, red_sym, blue_sym;
+ const double alpha_cost = VP8LPopulationCost(h->alpha_, NUM_LITERAL_CODES,
+ &alpha_sym);
+ const double distance_cost =
+ VP8LPopulationCost(h->distance_, NUM_DISTANCE_CODES, NULL) +
+ VP8LExtraCost(h->distance_, NUM_DISTANCE_CODES);
+ const int num_codes = VP8LHistogramNumCodes(h->palette_code_bits_);
+ h->literal_cost_ = VP8LPopulationCost(h->literal_, num_codes, NULL) +
+ VP8LExtraCost(h->literal_ + NUM_LITERAL_CODES,
+ NUM_LENGTH_CODES);
+ h->red_cost_ = VP8LPopulationCost(h->red_, NUM_LITERAL_CODES, &red_sym);
+ h->blue_cost_ = VP8LPopulationCost(h->blue_, NUM_LITERAL_CODES, &blue_sym);
+ h->bit_cost_ = h->literal_cost_ + h->red_cost_ + h->blue_cost_ +
+ alpha_cost + distance_cost;
+ if ((alpha_sym | red_sym | blue_sym) == VP8L_NON_TRIVIAL_SYM) {
+ h->trivial_symbol_ = VP8L_NON_TRIVIAL_SYM;
+ } else {
+ h->trivial_symbol_ =
+ ((uint32_t)alpha_sym << 24) | (red_sym << 16) | (blue_sym << 0);
}
- return retval;
}
-// Estimates the Huffman dictionary + other block overhead size.
-static double HistogramEstimateBitsHeader(const VP8LHistogram* const p) {
- return HuffmanCost(&p->alpha_[0], 256) +
- HuffmanCost(&p->red_[0], 256) +
- HuffmanCost(&p->literal_[0], VP8LHistogramNumCodes(p)) +
- HuffmanCost(&p->blue_[0], 256) +
- HuffmanCost(&p->distance_[0], NUM_DISTANCE_CODES);
+static int GetBinIdForEntropy(double min, double max, double val) {
+ const double range = max - min + 1e-6;
+ const double delta = val - min;
+ return (int)(NUM_PARTITIONS * delta / range);
}
-double VP8LHistogramEstimateBits(const VP8LHistogram* const p) {
- return HistogramEstimateBitsHeader(p) + VP8LHistogramEstimateBitsBulk(p);
+static int GetHistoBinIndexLowEffort(
+ const VP8LHistogram* const h, const DominantCostRange* const c) {
+ const int bin_id = GetBinIdForEntropy(c->literal_min_, c->literal_max_,
+ h->literal_cost_);
+ assert(bin_id < NUM_PARTITIONS);
+ return bin_id;
}
-static void HistogramBuildImage(int xsize, int histo_bits,
- const VP8LBackwardRefs* const backward_refs,
- VP8LHistogramSet* const image) {
- int i;
+static int GetHistoBinIndex(
+ const VP8LHistogram* const h, const DominantCostRange* const c) {
+ const int bin_id =
+ GetBinIdForEntropy(c->blue_min_, c->blue_max_, h->blue_cost_) +
+ NUM_PARTITIONS * GetBinIdForEntropy(c->red_min_, c->red_max_,
+ h->red_cost_) +
+ NUM_PARTITIONS * NUM_PARTITIONS * GetBinIdForEntropy(c->literal_min_,
+ c->literal_max_,
+ h->literal_cost_);
+ assert(bin_id < BIN_SIZE);
+ return bin_id;
+}
+
+// Construct the histograms from backward references.
+static void HistogramBuild(
+ int xsize, int histo_bits, const VP8LBackwardRefs* const backward_refs,
+ VP8LHistogramSet* const image_histo) {
int x = 0, y = 0;
const int histo_xsize = VP8LSubSampleSize(xsize, histo_bits);
- VP8LHistogram** const histograms = image->histograms;
+ VP8LHistogram** const histograms = image_histo->histograms;
+ VP8LRefsCursor c = VP8LRefsCursorInit(backward_refs);
assert(histo_bits > 0);
- for (i = 0; i < backward_refs->size; ++i) {
- const PixOrCopy* const v = &backward_refs->refs[i];
+ while (VP8LRefsCursorOk(&c)) {
+ const PixOrCopy* const v = c.cur_pos;
const int ix = (y >> histo_bits) * histo_xsize + (x >> histo_bits);
VP8LHistogramAddSinglePixOrCopy(histograms[ix], v);
x += PixOrCopyLength(v);
@@ -237,7 +328,134 @@ static void HistogramBuildImage(int xsize, int histo_bits,
x -= xsize;
++y;
}
+ VP8LRefsCursorNext(&c);
+ }
+}
+
+// Copies the histograms and computes its bit_cost.
+static void HistogramCopyAndAnalyze(
+ VP8LHistogramSet* const orig_histo, VP8LHistogramSet* const image_histo) {
+ int i;
+ const int histo_size = orig_histo->size;
+ VP8LHistogram** const orig_histograms = orig_histo->histograms;
+ VP8LHistogram** const histograms = image_histo->histograms;
+ for (i = 0; i < histo_size; ++i) {
+ VP8LHistogram* const histo = orig_histograms[i];
+ UpdateHistogramCost(histo);
+ // Copy histograms from orig_histo[] to image_histo[].
+ HistogramCopy(histo, histograms[i]);
+ }
+}
+
+// Partition histograms to different entropy bins for three dominant (literal,
+// red and blue) symbol costs and compute the histogram aggregate bit_cost.
+static void HistogramAnalyzeEntropyBin(VP8LHistogramSet* const image_histo,
+ int16_t* const bin_map, int low_effort) {
+ int i;
+ VP8LHistogram** const histograms = image_histo->histograms;
+ const int histo_size = image_histo->size;
+ const int bin_depth = histo_size + 1;
+ DominantCostRange cost_range;
+ DominantCostRangeInit(&cost_range);
+
+ // Analyze the dominant (literal, red and blue) entropy costs.
+ for (i = 0; i < histo_size; ++i) {
+ VP8LHistogram* const histo = histograms[i];
+ UpdateDominantCostRange(histo, &cost_range);
+ }
+
+ // bin-hash histograms on three of the dominant (literal, red and blue)
+ // symbol costs.
+ for (i = 0; i < histo_size; ++i) {
+ int num_histos;
+ VP8LHistogram* const histo = histograms[i];
+ const int16_t bin_id = low_effort ?
+ (int16_t)GetHistoBinIndexLowEffort(histo, &cost_range) :
+ (int16_t)GetHistoBinIndex(histo, &cost_range);
+ const int bin_offset = bin_id * bin_depth;
+ // bin_map[n][0] for every bin 'n' maintains the counter for the number of
+ // histograms in that bin.
+ // Get and increment the num_histos in that bin.
+ num_histos = ++bin_map[bin_offset];
+ assert(bin_offset + num_histos < bin_depth * BIN_SIZE);
+ // Add histogram i'th index at num_histos (last) position in the bin_map.
+ bin_map[bin_offset + num_histos] = i;
+ }
+}
+
+// Compact the histogram set by removing unused entries.
+static void HistogramCompactBins(VP8LHistogramSet* const image_histo) {
+ VP8LHistogram** const histograms = image_histo->histograms;
+ int i, j;
+
+ for (i = 0, j = 0; i < image_histo->size; ++i) {
+ if (histograms[i] != NULL && histograms[i]->bit_cost_ != 0.) {
+ if (j < i) {
+ histograms[j] = histograms[i];
+ histograms[i] = NULL;
+ }
+ ++j;
+ }
}
+ image_histo->size = j;
+}
+
+static VP8LHistogram* HistogramCombineEntropyBin(
+ VP8LHistogramSet* const image_histo,
+ VP8LHistogram* cur_combo,
+ int16_t* const bin_map, int bin_depth, int num_bins,
+ double combine_cost_factor, int low_effort) {
+ int bin_id;
+ VP8LHistogram** const histograms = image_histo->histograms;
+
+ for (bin_id = 0; bin_id < num_bins; ++bin_id) {
+ const int bin_offset = bin_id * bin_depth;
+ const int num_histos = bin_map[bin_offset];
+ const int idx1 = bin_map[bin_offset + 1];
+ int num_combine_failures = 0;
+ int n;
+ for (n = 2; n <= num_histos; ++n) {
+ const int idx2 = bin_map[bin_offset + n];
+ if (low_effort) {
+ // Merge all histograms with the same bin index, irrespective of cost of
+ // the merged histograms.
+ VP8LHistogramAdd(histograms[idx1], histograms[idx2], histograms[idx1]);
+ histograms[idx2]->bit_cost_ = 0.;
+ } else {
+ const double bit_cost_idx2 = histograms[idx2]->bit_cost_;
+ if (bit_cost_idx2 > 0.) {
+ const double bit_cost_thresh = -bit_cost_idx2 * combine_cost_factor;
+ const double curr_cost_diff =
+ HistogramAddEval(histograms[idx1], histograms[idx2],
+ cur_combo, bit_cost_thresh);
+ if (curr_cost_diff < bit_cost_thresh) {
+ // Try to merge two histograms only if the combo is a trivial one or
+ // the two candidate histograms are already non-trivial.
+ // For some images, 'try_combine' turns out to be false for a lot of
+ // histogram pairs. In that case, we fallback to combining
+ // histograms as usual to avoid increasing the header size.
+ const int try_combine =
+ (cur_combo->trivial_symbol_ != VP8L_NON_TRIVIAL_SYM) ||
+ ((histograms[idx1]->trivial_symbol_ == VP8L_NON_TRIVIAL_SYM) &&
+ (histograms[idx2]->trivial_symbol_ == VP8L_NON_TRIVIAL_SYM));
+ const int max_combine_failures = 32;
+ if (try_combine || (num_combine_failures >= max_combine_failures)) {
+ HistogramSwap(&cur_combo, &histograms[idx1]);
+ histograms[idx2]->bit_cost_ = 0.;
+ } else {
+ ++num_combine_failures;
+ }
+ }
+ }
+ }
+ }
+ if (low_effort) {
+ // Update the bit_cost for the merged histograms (per bin index).
+ UpdateHistogramCost(histograms[idx1]);
+ }
+ }
+ HistogramCompactBins(image_histo);
+ return cur_combo;
}
static uint32_t MyRand(uint32_t *seed) {
@@ -248,159 +466,433 @@ static uint32_t MyRand(uint32_t *seed) {
return *seed;
}
-static int HistogramCombine(const VP8LHistogramSet* const in,
- VP8LHistogramSet* const out, int num_pairs) {
+// -----------------------------------------------------------------------------
+// Histogram pairs priority queue
+
+// Pair of histograms. Negative idx1 value means that pair is out-of-date.
+typedef struct {
+ int idx1;
+ int idx2;
+ double cost_diff;
+ double cost_combo;
+} HistogramPair;
+
+typedef struct {
+ HistogramPair* heap;
+ int* positions;
+ int size;
+ int max_index;
+} HistoHeap;
+
+static int HistoHeapInit(HistoHeap* const histo_heap, const int max_index) {
+ histo_heap->size = 0;
+ histo_heap->max_index = max_index;
+ histo_heap->heap = WebPSafeMalloc(max_index * max_index,
+ sizeof(*histo_heap->heap));
+ histo_heap->positions = WebPSafeMalloc(max_index * max_index,
+ sizeof(*histo_heap->positions));
+ return histo_heap->heap != NULL && histo_heap->positions != NULL;
+}
+
+static void HistoHeapClear(HistoHeap* const histo_heap) {
+ assert(histo_heap != NULL);
+ WebPSafeFree(histo_heap->heap);
+ WebPSafeFree(histo_heap->positions);
+}
+
+static void SwapHistogramPairs(HistogramPair *p1,
+ HistogramPair *p2) {
+ const HistogramPair tmp = *p1;
+ *p1 = *p2;
+ *p2 = tmp;
+}
+
+// Given a valid min-heap in range [0, heap_size-1) this function places value
+// heap[heap_size-1] into right location within heap and sets its position in
+// positions array.
+static void HeapPush(HistoHeap* const histo_heap) {
+ HistogramPair* const heap = histo_heap->heap - 1;
+ int* const positions = histo_heap->positions;
+ const int max_index = histo_heap->max_index;
+ int v;
+ ++histo_heap->size;
+ v = histo_heap->size;
+ while (v > 1 && heap[v].cost_diff < heap[v >> 1].cost_diff) {
+ SwapHistogramPairs(&heap[v], &heap[v >> 1]);
+ // Change position of moved pair in heap.
+ if (heap[v].idx1 >= 0) {
+ const int pos = heap[v].idx1 * max_index + heap[v].idx2;
+ assert(pos >= 0 && pos < max_index * max_index);
+ positions[pos] = v;
+ }
+ v >>= 1;
+ }
+ positions[heap[v].idx1 * max_index + heap[v].idx2] = v;
+}
+
+// Given a valid min-heap in range [0, heap_size) this function shortens heap
+// range by one and places element with the lowest value to (heap_size-1).
+static void HeapPop(HistoHeap* const histo_heap) {
+ HistogramPair* const heap = histo_heap->heap - 1;
+ int* const positions = histo_heap->positions;
+ const int heap_size = histo_heap->size;
+ const int max_index = histo_heap->max_index;
+ int v = 1;
+ if (heap[v].idx1 >= 0) {
+ positions[heap[v].idx1 * max_index + heap[v].idx2] = -1;
+ }
+ SwapHistogramPairs(&heap[v], &heap[heap_size]);
+ while ((v << 1) < heap_size) {
+ int son = (heap[v << 1].cost_diff < heap[v].cost_diff) ? (v << 1) : v;
+ if (((v << 1) + 1) < heap_size &&
+ heap[(v << 1) + 1].cost_diff < heap[son].cost_diff) {
+ son = (v << 1) + 1;
+ }
+ if (son == v) break;
+ SwapHistogramPairs(&heap[v], &heap[son]);
+ // Change position of moved pair in heap.
+ if (heap[v].idx1 >= 0) {
+ positions[heap[v].idx1 * max_index + heap[v].idx2] = v;
+ }
+ v = son;
+ }
+ if (heap[v].idx1 >= 0) {
+ positions[heap[v].idx1 * max_index + heap[v].idx2] = v;
+ }
+ --histo_heap->size;
+}
+
+// -----------------------------------------------------------------------------
+
+static void PreparePair(VP8LHistogram** histograms, int idx1, int idx2,
+ HistogramPair* const pair,
+ VP8LHistogram* const histos) {
+ if (idx1 > idx2) {
+ const int tmp = idx2;
+ idx2 = idx1;
+ idx1 = tmp;
+ }
+ pair->idx1 = idx1;
+ pair->idx2 = idx2;
+ pair->cost_diff =
+ HistogramAddEval(histograms[idx1], histograms[idx2], histos, 0);
+ pair->cost_combo = histos->bit_cost_;
+}
+
+#define POSITION_INVALID (-1)
+
+// Invalidates pairs intersecting (idx1, idx2) in heap.
+static void InvalidatePairs(int idx1, int idx2,
+ const HistoHeap* const histo_heap) {
+ HistogramPair* const heap = histo_heap->heap - 1;
+ int* const positions = histo_heap->positions;
+ const int max_index = histo_heap->max_index;
+ int i;
+ for (i = 0; i < idx1; ++i) {
+ const int pos = positions[i * max_index + idx1];
+ if (pos >= 0) {
+ heap[pos].idx1 = POSITION_INVALID;
+ }
+ }
+ for (i = idx1 + 1; i < max_index; ++i) {
+ const int pos = positions[idx1 * max_index + i];
+ if (pos >= 0) {
+ heap[pos].idx1 = POSITION_INVALID;
+ }
+ }
+ for (i = 0; i < idx2; ++i) {
+ const int pos = positions[i * max_index + idx2];
+ if (pos >= 0) {
+ heap[pos].idx1 = POSITION_INVALID;
+ }
+ }
+ for (i = idx2 + 1; i < max_index; ++i) {
+ const int pos = positions[idx2 * max_index + i];
+ if (pos >= 0) {
+ heap[pos].idx1 = POSITION_INVALID;
+ }
+ }
+}
+
+// Combines histograms by continuously choosing the one with the highest cost
+// reduction.
+static int HistogramCombineGreedy(VP8LHistogramSet* const image_histo,
+ VP8LHistogram* const histos) {
int ok = 0;
- int i, iter;
+ int image_histo_size = image_histo->size;
+ int i, j;
+ VP8LHistogram** const histograms = image_histo->histograms;
+ // Indexes of remaining histograms.
+ int* const clusters = WebPSafeMalloc(image_histo_size, sizeof(*clusters));
+ // Heap of histogram pairs.
+ HistoHeap histo_heap;
+
+ if (!HistoHeapInit(&histo_heap, image_histo_size) || clusters == NULL) {
+ goto End;
+ }
+
+ for (i = 0; i < image_histo_size; ++i) {
+ // Initialize clusters indexes.
+ clusters[i] = i;
+ for (j = i + 1; j < image_histo_size; ++j) {
+ // Initialize positions array.
+ histo_heap.positions[i * histo_heap.max_index + j] = POSITION_INVALID;
+ PreparePair(histograms, i, j, &histo_heap.heap[histo_heap.size], histos);
+ if (histo_heap.heap[histo_heap.size].cost_diff < 0) {
+ HeapPush(&histo_heap);
+ }
+ }
+ }
+
+ while (image_histo_size > 1 && histo_heap.size > 0) {
+ const int idx1 = histo_heap.heap[0].idx1;
+ const int idx2 = histo_heap.heap[0].idx2;
+ VP8LHistogramAdd(histograms[idx2], histograms[idx1], histograms[idx1]);
+ histograms[idx1]->bit_cost_ = histo_heap.heap[0].cost_combo;
+ // Remove merged histogram.
+ for (i = 0; i + 1 < image_histo_size; ++i) {
+ if (clusters[i] >= idx2) {
+ clusters[i] = clusters[i + 1];
+ }
+ }
+ --image_histo_size;
+
+ // Invalidate pairs intersecting the just combined best pair.
+ InvalidatePairs(idx1, idx2, &histo_heap);
+
+ // Pop invalid pairs from the top of the heap.
+ while (histo_heap.size > 0 && histo_heap.heap[0].idx1 < 0) {
+ HeapPop(&histo_heap);
+ }
+
+ // Push new pairs formed with combined histogram to the heap.
+ for (i = 0; i < image_histo_size; ++i) {
+ if (clusters[i] != idx1) {
+ PreparePair(histograms, idx1, clusters[i],
+ &histo_heap.heap[histo_heap.size], histos);
+ if (histo_heap.heap[histo_heap.size].cost_diff < 0) {
+ HeapPush(&histo_heap);
+ }
+ }
+ }
+ }
+ // Move remaining histograms to the beginning of the array.
+ for (i = 0; i < image_histo_size; ++i) {
+ if (i != clusters[i]) { // swap the two histograms
+ HistogramSwap(&histograms[i], &histograms[clusters[i]]);
+ }
+ }
+
+ image_histo->size = image_histo_size;
+ ok = 1;
+
+ End:
+ WebPSafeFree(clusters);
+ HistoHeapClear(&histo_heap);
+ return ok;
+}
+
+static VP8LHistogram* HistogramCombineStochastic(
+ VP8LHistogramSet* const image_histo,
+ VP8LHistogram* tmp_histo,
+ VP8LHistogram* best_combo,
+ int quality, int min_cluster_size) {
+ int iter;
uint32_t seed = 0;
int tries_with_no_success = 0;
- const int min_cluster_size = 2;
- int out_size = in->size;
- const int outer_iters = in->size * 3;
- VP8LHistogram* const histos = (VP8LHistogram*)malloc(2 * sizeof(*histos));
- VP8LHistogram* cur_combo = histos + 0; // trial merged histogram
- VP8LHistogram* best_combo = histos + 1; // best merged histogram so far
- if (histos == NULL) goto End;
-
- // Copy histograms from in[] to out[].
- assert(in->size <= out->size);
- for (i = 0; i < in->size; ++i) {
- in->histograms[i]->bit_cost_ = VP8LHistogramEstimateBits(in->histograms[i]);
- *out->histograms[i] = *in->histograms[i];
- }
-
- // Collapse similar histograms in 'out'.
- for (iter = 0; iter < outer_iters && out_size >= min_cluster_size; ++iter) {
- // We pick the best pair to be combined out of 'inner_iters' pairs.
+ int image_histo_size = image_histo->size;
+ const int iter_mult = (quality < 25) ? 2 : 2 + (quality - 25) / 8;
+ const int outer_iters = image_histo_size * iter_mult;
+ const int num_pairs = image_histo_size / 2;
+ const int num_tries_no_success = outer_iters / 2;
+ VP8LHistogram** const histograms = image_histo->histograms;
+
+ // Collapse similar histograms in 'image_histo'.
+ ++min_cluster_size;
+ for (iter = 0;
+ iter < outer_iters && image_histo_size >= min_cluster_size;
+ ++iter) {
double best_cost_diff = 0.;
- int best_idx1 = 0, best_idx2 = 1;
+ int best_idx1 = -1, best_idx2 = 1;
int j;
+ const int num_tries =
+ (num_pairs < image_histo_size) ? num_pairs : image_histo_size;
seed += iter;
- for (j = 0; j < num_pairs; ++j) {
+ for (j = 0; j < num_tries; ++j) {
double curr_cost_diff;
// Choose two histograms at random and try to combine them.
- const uint32_t idx1 = MyRand(&seed) % out_size;
- const uint32_t tmp = ((j & 7) + 1) % (out_size - 1);
- const uint32_t diff = (tmp < 3) ? tmp : MyRand(&seed) % (out_size - 1);
- const uint32_t idx2 = (idx1 + diff + 1) % out_size;
+ const uint32_t idx1 = MyRand(&seed) % image_histo_size;
+ const uint32_t tmp = (j & 7) + 1;
+ const uint32_t diff =
+ (tmp < 3) ? tmp : MyRand(&seed) % (image_histo_size - 1);
+ const uint32_t idx2 = (idx1 + diff + 1) % image_histo_size;
if (idx1 == idx2) {
continue;
}
- *cur_combo = *out->histograms[idx1];
- VP8LHistogramAdd(cur_combo, out->histograms[idx2]);
- cur_combo->bit_cost_ = VP8LHistogramEstimateBits(cur_combo);
+
// Calculate cost reduction on combining.
- curr_cost_diff = cur_combo->bit_cost_
- - out->histograms[idx1]->bit_cost_
- - out->histograms[idx2]->bit_cost_;
- if (best_cost_diff > curr_cost_diff) { // found a better pair?
- { // swap cur/best combo histograms
- VP8LHistogram* const tmp_histo = cur_combo;
- cur_combo = best_combo;
- best_combo = tmp_histo;
- }
+ curr_cost_diff = HistogramAddEval(histograms[idx1], histograms[idx2],
+ tmp_histo, best_cost_diff);
+ if (curr_cost_diff < best_cost_diff) { // found a better pair?
+ HistogramSwap(&best_combo, &tmp_histo);
best_cost_diff = curr_cost_diff;
best_idx1 = idx1;
best_idx2 = idx2;
}
}
- if (best_cost_diff < 0.0) {
- *out->histograms[best_idx1] = *best_combo;
+ if (best_idx1 >= 0) {
+ HistogramSwap(&best_combo, &histograms[best_idx1]);
// swap best_idx2 slot with last one (which is now unused)
- --out_size;
- if (best_idx2 != out_size) {
- out->histograms[best_idx2] = out->histograms[out_size];
- out->histograms[out_size] = NULL; // just for sanity check.
+ --image_histo_size;
+ if (best_idx2 != image_histo_size) {
+ HistogramSwap(&histograms[image_histo_size], &histograms[best_idx2]);
+ histograms[image_histo_size] = NULL;
}
tries_with_no_success = 0;
}
- if (++tries_with_no_success >= 50) {
+ if (++tries_with_no_success >= num_tries_no_success) {
break;
}
}
- out->size = out_size;
- ok = 1;
-
- End:
- free(histos);
- return ok;
+ image_histo->size = image_histo_size;
+ return best_combo;
}
// -----------------------------------------------------------------------------
// Histogram refinement
-// What is the bit cost of moving square_histogram from
-// cur_symbol to candidate_symbol.
-// TODO(skal): we don't really need to copy the histogram and Add(). Instead
-// we just need VP8LDualHistogramEstimateBits(A, B) estimation function.
-static double HistogramDistance(const VP8LHistogram* const square_histogram,
- const VP8LHistogram* const candidate) {
- const double previous_bit_cost = candidate->bit_cost_;
- double new_bit_cost;
- VP8LHistogram modified_histo;
- modified_histo = *candidate;
- VP8LHistogramAdd(&modified_histo, square_histogram);
- new_bit_cost = VP8LHistogramEstimateBits(&modified_histo);
-
- return new_bit_cost - previous_bit_cost;
-}
-
// Find the best 'out' histogram for each of the 'in' histograms.
// Note: we assume that out[]->bit_cost_ is already up-to-date.
-static void HistogramRemap(const VP8LHistogramSet* const in,
- const VP8LHistogramSet* const out,
+static void HistogramRemap(const VP8LHistogramSet* const orig_histo,
+ const VP8LHistogramSet* const image_histo,
uint16_t* const symbols) {
int i;
- for (i = 0; i < in->size; ++i) {
- int best_out = 0;
- double best_bits = HistogramDistance(in->histograms[i], out->histograms[0]);
- int k;
- for (k = 1; k < out->size; ++k) {
- const double cur_bits =
- HistogramDistance(in->histograms[i], out->histograms[k]);
- if (cur_bits < best_bits) {
- best_bits = cur_bits;
- best_out = k;
+ VP8LHistogram** const orig_histograms = orig_histo->histograms;
+ VP8LHistogram** const histograms = image_histo->histograms;
+ const int orig_histo_size = orig_histo->size;
+ const int image_histo_size = image_histo->size;
+ if (image_histo_size > 1) {
+ for (i = 0; i < orig_histo_size; ++i) {
+ int best_out = 0;
+ double best_bits =
+ HistogramAddThresh(histograms[0], orig_histograms[i], MAX_COST);
+ int k;
+ for (k = 1; k < image_histo_size; ++k) {
+ const double cur_bits =
+ HistogramAddThresh(histograms[k], orig_histograms[i], best_bits);
+ if (cur_bits < best_bits) {
+ best_bits = cur_bits;
+ best_out = k;
+ }
}
+ symbols[i] = best_out;
+ }
+ } else {
+ assert(image_histo_size == 1);
+ for (i = 0; i < orig_histo_size; ++i) {
+ symbols[i] = 0;
}
- symbols[i] = best_out;
}
// Recompute each out based on raw and symbols.
- for (i = 0; i < out->size; ++i) {
- HistogramClear(out->histograms[i]);
+ for (i = 0; i < image_histo_size; ++i) {
+ HistogramClear(histograms[i]);
}
- for (i = 0; i < in->size; ++i) {
- VP8LHistogramAdd(out->histograms[symbols[i]], in->histograms[i]);
+
+ for (i = 0; i < orig_histo_size; ++i) {
+ const int idx = symbols[i];
+ VP8LHistogramAdd(orig_histograms[i], histograms[idx], histograms[idx]);
}
}
+static double GetCombineCostFactor(int histo_size, int quality) {
+ double combine_cost_factor = 0.16;
+ if (quality < 90) {
+ if (histo_size > 256) combine_cost_factor /= 2.;
+ if (histo_size > 512) combine_cost_factor /= 2.;
+ if (histo_size > 1024) combine_cost_factor /= 2.;
+ if (quality <= 50) combine_cost_factor /= 2.;
+ }
+ return combine_cost_factor;
+}
+
int VP8LGetHistoImageSymbols(int xsize, int ysize,
const VP8LBackwardRefs* const refs,
- int quality, int histo_bits, int cache_bits,
- VP8LHistogramSet* const image_in,
+ int quality, int low_effort,
+ int histo_bits, int cache_bits,
+ VP8LHistogramSet* const image_histo,
+ VP8LHistogramSet* const tmp_histos,
uint16_t* const histogram_symbols) {
int ok = 0;
const int histo_xsize = histo_bits ? VP8LSubSampleSize(xsize, histo_bits) : 1;
const int histo_ysize = histo_bits ? VP8LSubSampleSize(ysize, histo_bits) : 1;
- const int num_histo_pairs = 10 + quality / 2; // For HistogramCombine().
- const int histo_image_raw_size = histo_xsize * histo_ysize;
- VP8LHistogramSet* const image_out =
- VP8LAllocateHistogramSet(histo_image_raw_size, cache_bits);
- if (image_out == NULL) return 0;
-
- // Build histogram image.
- HistogramBuildImage(xsize, histo_bits, refs, image_out);
- // Collapse similar histograms.
- if (!HistogramCombine(image_out, image_in, num_histo_pairs)) {
- goto Error;
+ const int image_histo_raw_size = histo_xsize * histo_ysize;
+ const int entropy_combine_num_bins = low_effort ? NUM_PARTITIONS : BIN_SIZE;
+
+ // The bin_map for every bin follows following semantics:
+ // bin_map[n][0] = num_histo; // The number of histograms in that bin.
+ // bin_map[n][1] = index of first histogram in that bin;
+ // bin_map[n][num_histo] = index of last histogram in that bin;
+ // bin_map[n][num_histo + 1] ... bin_map[n][bin_depth - 1] = unused indices.
+ const int bin_depth = image_histo_raw_size + 1;
+ int16_t* bin_map = NULL;
+ VP8LHistogramSet* const orig_histo =
+ VP8LAllocateHistogramSet(image_histo_raw_size, cache_bits);
+ VP8LHistogram* cur_combo;
+ const int entropy_combine =
+ (orig_histo->size > entropy_combine_num_bins * 2) && (quality < 100);
+
+ if (orig_histo == NULL) goto Error;
+
+ // Don't attempt linear bin-partition heuristic for:
+ // histograms of small sizes, as bin_map will be very sparse and;
+ // Maximum quality (q==100), to preserve the compression gains at that level.
+ if (entropy_combine) {
+ const int bin_map_size = bin_depth * entropy_combine_num_bins;
+ bin_map = (int16_t*)WebPSafeCalloc(bin_map_size, sizeof(*bin_map));
+ if (bin_map == NULL) goto Error;
}
+
+ // Construct the histograms from backward references.
+ HistogramBuild(xsize, histo_bits, refs, orig_histo);
+ // Copies the histograms and computes its bit_cost.
+ HistogramCopyAndAnalyze(orig_histo, image_histo);
+
+ cur_combo = tmp_histos->histograms[1]; // pick up working slot
+ if (entropy_combine) {
+ const double combine_cost_factor =
+ GetCombineCostFactor(image_histo_raw_size, quality);
+ HistogramAnalyzeEntropyBin(orig_histo, bin_map, low_effort);
+ // Collapse histograms with similar entropy.
+ cur_combo = HistogramCombineEntropyBin(image_histo, cur_combo, bin_map,
+ bin_depth, entropy_combine_num_bins,
+ combine_cost_factor, low_effort);
+ }
+
+ // Don't combine the histograms using stochastic and greedy heuristics for
+ // low-effort compression mode.
+ if (!low_effort || !entropy_combine) {
+ const float x = quality / 100.f;
+ // cubic ramp between 1 and MAX_HISTO_GREEDY:
+ const int threshold_size = (int)(1 + (x * x * x) * (MAX_HISTO_GREEDY - 1));
+ cur_combo = HistogramCombineStochastic(image_histo,
+ tmp_histos->histograms[0],
+ cur_combo, quality, threshold_size);
+ if ((image_histo->size <= threshold_size) &&
+ !HistogramCombineGreedy(image_histo, cur_combo)) {
+ goto Error;
+ }
+ }
+
+ // TODO(vikasa): Optimize HistogramRemap for low-effort compression mode also.
// Find the optimal map from original histograms to the final ones.
- HistogramRemap(image_out, image_in, histogram_symbols);
+ HistogramRemap(orig_histo, image_histo, histogram_symbols);
+
ok = 1;
-Error:
- free(image_out);
+ Error:
+ WebPSafeFree(bin_map);
+ VP8LFreeHistogramSet(orig_histo);
return ok;
}
diff --git a/drivers/webp/enc/histogram.h b/drivers/webp/enc/histogram.h
index 5b5de25539..72f045793a 100644
--- a/drivers/webp/enc/histogram.h
+++ b/drivers/webp/enc/histogram.h
@@ -1,8 +1,10 @@
// Copyright 2012 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Author: Jyrki Alakuijala (jyrki@google.com)
@@ -12,17 +14,13 @@
#ifndef WEBP_ENC_HISTOGRAM_H_
#define WEBP_ENC_HISTOGRAM_H_
-#include <assert.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
#include <string.h>
#include "./backward_references.h"
-#include "../format_constants.h"
-#include "../types.h"
+#include "webp/format_constants.h"
+#include "webp/types.h"
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
extern "C" {
#endif
@@ -30,18 +28,23 @@ extern "C" {
typedef struct {
// literal_ contains green literal, palette-code and
// copy-length-prefix histogram
- int literal_[PIX_OR_COPY_CODES_MAX];
- int red_[256];
- int blue_[256];
- int alpha_[256];
+ uint32_t* literal_; // Pointer to the allocated buffer for literal.
+ uint32_t red_[NUM_LITERAL_CODES];
+ uint32_t blue_[NUM_LITERAL_CODES];
+ uint32_t alpha_[NUM_LITERAL_CODES];
// Backward reference prefix-code histogram.
- int distance_[NUM_DISTANCE_CODES];
+ uint32_t distance_[NUM_DISTANCE_CODES];
int palette_code_bits_;
- double bit_cost_; // cached value of VP8LHistogramEstimateBits(this)
+ uint32_t trivial_symbol_; // True, if histograms for Red, Blue & Alpha
+ // literal symbols are single valued.
+ double bit_cost_; // cached value of bit cost.
+ double literal_cost_; // Cached values of dominant entropy costs:
+ double red_cost_; // literal, red & blue.
+ double blue_cost_;
} VP8LHistogram;
// Collection of histograms with fixed capacity, allocated as one
-// big memory chunk. Can be destroyed by simply calling 'free()'.
+// big memory chunk. Can be destroyed by calling WebPSafeFree().
typedef struct {
int size; // number of slots currently in use
int max_size; // maximum capacity
@@ -57,6 +60,9 @@ void VP8LHistogramCreate(VP8LHistogram* const p,
const VP8LBackwardRefs* const refs,
int palette_code_bits);
+// Return the size of the histogram for a given palette_code_bits.
+int VP8LGetHistogramSize(int palette_code_bits);
+
// Set the palette_code_bits and reset the stats.
void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits);
@@ -64,51 +70,40 @@ void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits);
void VP8LHistogramStoreRefs(const VP8LBackwardRefs* const refs,
VP8LHistogram* const histo);
+// Free the memory allocated for the histogram.
+void VP8LFreeHistogram(VP8LHistogram* const histo);
+
+// Free the memory allocated for the histogram set.
+void VP8LFreeHistogramSet(VP8LHistogramSet* const histo);
+
// Allocate an array of pointer to histograms, allocated and initialized
// using 'cache_bits'. Return NULL in case of memory error.
VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits);
+// Allocate and initialize histogram object with specified 'cache_bits'.
+// Returns NULL in case of memory error.
+// Special case of VP8LAllocateHistogramSet, with size equals 1.
+VP8LHistogram* VP8LAllocateHistogram(int cache_bits);
+
// Accumulate a token 'v' into a histogram.
void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo,
const PixOrCopy* const v);
-// Estimate how many bits the combined entropy of literals and distance
-// approximately maps to.
-double VP8LHistogramEstimateBits(const VP8LHistogram* const p);
-
-// This function estimates the cost in bits excluding the bits needed to
-// represent the entropy code itself.
-double VP8LHistogramEstimateBitsBulk(const VP8LHistogram* const p);
-
-static WEBP_INLINE void VP8LHistogramAdd(VP8LHistogram* const p,
- const VP8LHistogram* const a) {
- int i;
- for (i = 0; i < PIX_OR_COPY_CODES_MAX; ++i) {
- p->literal_[i] += a->literal_[i];
- }
- for (i = 0; i < NUM_DISTANCE_CODES; ++i) {
- p->distance_[i] += a->distance_[i];
- }
- for (i = 0; i < 256; ++i) {
- p->red_[i] += a->red_[i];
- p->blue_[i] += a->blue_[i];
- p->alpha_[i] += a->alpha_[i];
- }
-}
-
-static WEBP_INLINE int VP8LHistogramNumCodes(const VP8LHistogram* const p) {
- return 256 + NUM_LENGTH_CODES +
- ((p->palette_code_bits_ > 0) ? (1 << p->palette_code_bits_) : 0);
+static WEBP_INLINE int VP8LHistogramNumCodes(int palette_code_bits) {
+ return NUM_LITERAL_CODES + NUM_LENGTH_CODES +
+ ((palette_code_bits > 0) ? (1 << palette_code_bits) : 0);
}
// Builds the histogram image.
int VP8LGetHistoImageSymbols(int xsize, int ysize,
const VP8LBackwardRefs* const refs,
- int quality, int histogram_bits, int cache_bits,
+ int quality, int low_effort,
+ int histogram_bits, int cache_bits,
VP8LHistogramSet* const image_in,
+ VP8LHistogramSet* const tmp_histos,
uint16_t* const histogram_symbols);
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
}
#endif
diff --git a/drivers/webp/enc/iterator.c b/drivers/webp/enc/iterator.c
index 86e473bcf0..99d960a547 100644
--- a/drivers/webp/enc/iterator.c
+++ b/drivers/webp/enc/iterator.c
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// VP8Iterator: block iterator
@@ -13,21 +15,16 @@
#include "./vp8enci.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
//------------------------------------------------------------------------------
// VP8Iterator
//------------------------------------------------------------------------------
static void InitLeft(VP8EncIterator* const it) {
- const VP8Encoder* const enc = it->enc_;
- enc->y_left_[-1] = enc->u_left_[-1] = enc->v_left_[-1] =
+ it->y_left_[-1] = it->u_left_[-1] = it->v_left_[-1] =
(it->y_ > 0) ? 129 : 127;
- memset(enc->y_left_, 129, 16);
- memset(enc->u_left_, 129, 8);
- memset(enc->v_left_, 129, 8);
+ memset(it->y_left_, 129, 16);
+ memset(it->u_left_, 129, 8);
+ memset(it->v_left_, 129, 8);
it->left_nz_[8] = 0;
}
@@ -38,43 +35,60 @@ static void InitTop(VP8EncIterator* const it) {
memset(enc->nz_, 0, enc->mb_w_ * sizeof(*enc->nz_));
}
-void VP8IteratorReset(VP8EncIterator* const it) {
+void VP8IteratorSetRow(VP8EncIterator* const it, int y) {
VP8Encoder* const enc = it->enc_;
it->x_ = 0;
- it->y_ = 0;
- it->y_offset_ = 0;
- it->uv_offset_ = 0;
- it->mb_ = enc->mb_info_;
- it->preds_ = enc->preds_;
+ it->y_ = y;
+ it->bw_ = &enc->parts_[y & (enc->num_parts_ - 1)];
+ it->preds_ = enc->preds_ + y * 4 * enc->preds_w_;
it->nz_ = enc->nz_;
- it->bw_ = &enc->parts_[0];
- it->done_ = enc->mb_w_* enc->mb_h_;
+ it->mb_ = enc->mb_info_ + y * enc->mb_w_;
+ it->y_top_ = enc->y_top_;
+ it->uv_top_ = enc->uv_top_;
+ InitLeft(it);
+}
+
+void VP8IteratorReset(VP8EncIterator* const it) {
+ VP8Encoder* const enc = it->enc_;
+ VP8IteratorSetRow(it, 0);
+ VP8IteratorSetCountDown(it, enc->mb_w_ * enc->mb_h_); // default
InitTop(it);
InitLeft(it);
memset(it->bit_count_, 0, sizeof(it->bit_count_));
it->do_trellis_ = 0;
}
+void VP8IteratorSetCountDown(VP8EncIterator* const it, int count_down) {
+ it->count_down_ = it->count_down0_ = count_down;
+}
+
+int VP8IteratorIsDone(const VP8EncIterator* const it) {
+ return (it->count_down_ <= 0);
+}
+
void VP8IteratorInit(VP8Encoder* const enc, VP8EncIterator* const it) {
it->enc_ = enc;
it->y_stride_ = enc->pic_->y_stride;
it->uv_stride_ = enc->pic_->uv_stride;
- // TODO(later): for multithreading, these should be owned by 'it'.
- it->yuv_in_ = enc->yuv_in_;
- it->yuv_out_ = enc->yuv_out_;
- it->yuv_out2_ = enc->yuv_out2_;
- it->yuv_p_ = enc->yuv_p_;
+ it->yuv_in_ = (uint8_t*)WEBP_ALIGN(it->yuv_mem_);
+ it->yuv_out_ = it->yuv_in_ + YUV_SIZE_ENC;
+ it->yuv_out2_ = it->yuv_out_ + YUV_SIZE_ENC;
+ it->yuv_p_ = it->yuv_out2_ + YUV_SIZE_ENC;
it->lf_stats_ = enc->lf_stats_;
it->percent0_ = enc->percent_;
+ it->y_left_ = (uint8_t*)WEBP_ALIGN(it->yuv_left_mem_ + 1);
+ it->u_left_ = it->y_left_ + 16 + 16;
+ it->v_left_ = it->u_left_ + 16;
VP8IteratorReset(it);
}
int VP8IteratorProgress(const VP8EncIterator* const it, int delta) {
VP8Encoder* const enc = it->enc_;
- if (delta && enc->pic_->progress_hook) {
- const int percent = (enc->mb_h_ <= 1)
+ if (delta && enc->pic_->progress_hook != NULL) {
+ const int done = it->count_down0_ - it->count_down_;
+ const int percent = (it->count_down0_ <= 0)
? it->percent0_
- : it->percent0_ + delta * it->y_ / (enc->mb_h_ - 1);
+ : it->percent0_ + delta * done / it->count_down0_;
return WebPReportProgress(enc->pic_, percent, &enc->percent_);
}
return 1;
@@ -84,6 +98,8 @@ int VP8IteratorProgress(const VP8EncIterator* const it, int delta) {
// Import the source samples into the cache. Takes care of replicating
// boundary pixels if necessary.
+static WEBP_INLINE int MinSize(int a, int b) { return (a < b) ? a : b; }
+
static void ImportBlock(const uint8_t* src, int src_stride,
uint8_t* dst, int w, int h, int size) {
int i;
@@ -101,30 +117,55 @@ static void ImportBlock(const uint8_t* src, int src_stride,
}
}
-void VP8IteratorImport(const VP8EncIterator* const it) {
+static void ImportLine(const uint8_t* src, int src_stride,
+ uint8_t* dst, int len, int total_len) {
+ int i;
+ for (i = 0; i < len; ++i, src += src_stride) dst[i] = *src;
+ for (; i < total_len; ++i) dst[i] = dst[len - 1];
+}
+
+void VP8IteratorImport(VP8EncIterator* const it, uint8_t* tmp_32) {
const VP8Encoder* const enc = it->enc_;
const int x = it->x_, y = it->y_;
const WebPPicture* const pic = enc->pic_;
- const uint8_t* const ysrc = pic->y + (y * pic->y_stride + x) * 16;
+ const uint8_t* const ysrc = pic->y + (y * pic->y_stride + x) * 16;
const uint8_t* const usrc = pic->u + (y * pic->uv_stride + x) * 8;
const uint8_t* const vsrc = pic->v + (y * pic->uv_stride + x) * 8;
- uint8_t* const ydst = it->yuv_in_ + Y_OFF;
- uint8_t* const udst = it->yuv_in_ + U_OFF;
- uint8_t* const vdst = it->yuv_in_ + V_OFF;
- int w = (pic->width - x * 16);
- int h = (pic->height - y * 16);
-
- if (w > 16) w = 16;
- if (h > 16) h = 16;
-
- // Luma plane
- ImportBlock(ysrc, pic->y_stride, ydst, w, h, 16);
-
- { // U/V planes
- const int uv_w = (w + 1) >> 1;
- const int uv_h = (h + 1) >> 1;
- ImportBlock(usrc, pic->uv_stride, udst, uv_w, uv_h, 8);
- ImportBlock(vsrc, pic->uv_stride, vdst, uv_w, uv_h, 8);
+ const int w = MinSize(pic->width - x * 16, 16);
+ const int h = MinSize(pic->height - y * 16, 16);
+ const int uv_w = (w + 1) >> 1;
+ const int uv_h = (h + 1) >> 1;
+
+ ImportBlock(ysrc, pic->y_stride, it->yuv_in_ + Y_OFF_ENC, w, h, 16);
+ ImportBlock(usrc, pic->uv_stride, it->yuv_in_ + U_OFF_ENC, uv_w, uv_h, 8);
+ ImportBlock(vsrc, pic->uv_stride, it->yuv_in_ + V_OFF_ENC, uv_w, uv_h, 8);
+
+ if (tmp_32 == NULL) return;
+
+ // Import source (uncompressed) samples into boundary.
+ if (x == 0) {
+ InitLeft(it);
+ } else {
+ if (y == 0) {
+ it->y_left_[-1] = it->u_left_[-1] = it->v_left_[-1] = 127;
+ } else {
+ it->y_left_[-1] = ysrc[- 1 - pic->y_stride];
+ it->u_left_[-1] = usrc[- 1 - pic->uv_stride];
+ it->v_left_[-1] = vsrc[- 1 - pic->uv_stride];
+ }
+ ImportLine(ysrc - 1, pic->y_stride, it->y_left_, h, 16);
+ ImportLine(usrc - 1, pic->uv_stride, it->u_left_, uv_h, 8);
+ ImportLine(vsrc - 1, pic->uv_stride, it->v_left_, uv_h, 8);
+ }
+
+ it->y_top_ = tmp_32 + 0;
+ it->uv_top_ = tmp_32 + 16;
+ if (y == 0) {
+ memset(tmp_32, 127, 32 * sizeof(*tmp_32));
+ } else {
+ ImportLine(ysrc - pic->y_stride, 1, tmp_32, w, 16);
+ ImportLine(usrc - pic->uv_stride, 1, tmp_32 + 16, uv_w, 8);
+ ImportLine(vsrc - pic->uv_stride, 1, tmp_32 + 16 + 8, uv_w, 8);
}
}
@@ -144,9 +185,9 @@ void VP8IteratorExport(const VP8EncIterator* const it) {
const VP8Encoder* const enc = it->enc_;
if (enc->config_->show_compressed) {
const int x = it->x_, y = it->y_;
- const uint8_t* const ysrc = it->yuv_out_ + Y_OFF;
- const uint8_t* const usrc = it->yuv_out_ + U_OFF;
- const uint8_t* const vsrc = it->yuv_out_ + V_OFF;
+ const uint8_t* const ysrc = it->yuv_out_ + Y_OFF_ENC;
+ const uint8_t* const usrc = it->yuv_out_ + U_OFF_ENC;
+ const uint8_t* const vsrc = it->yuv_out_ + V_OFF_ENC;
const WebPPicture* const pic = enc->pic_;
uint8_t* const ydst = pic->y + (y * pic->y_stride + x) * 16;
uint8_t* const udst = pic->u + (y * pic->uv_stride + x) * 8;
@@ -240,48 +281,44 @@ void VP8IteratorBytesToNz(VP8EncIterator* const it) {
#undef BIT
//------------------------------------------------------------------------------
-// Advance to the next position, doing the bookeeping.
+// Advance to the next position, doing the bookkeeping.
-int VP8IteratorNext(VP8EncIterator* const it,
- const uint8_t* const block_to_save) {
+void VP8IteratorSaveBoundary(VP8EncIterator* const it) {
VP8Encoder* const enc = it->enc_;
- if (block_to_save) {
- const int x = it->x_, y = it->y_;
- const uint8_t* const ysrc = block_to_save + Y_OFF;
- const uint8_t* const usrc = block_to_save + U_OFF;
- if (x < enc->mb_w_ - 1) { // left
- int i;
- for (i = 0; i < 16; ++i) {
- enc->y_left_[i] = ysrc[15 + i * BPS];
- }
- for (i = 0; i < 8; ++i) {
- enc->u_left_[i] = usrc[7 + i * BPS];
- enc->v_left_[i] = usrc[15 + i * BPS];
- }
- // top-left (before 'top'!)
- enc->y_left_[-1] = enc->y_top_[x * 16 + 15];
- enc->u_left_[-1] = enc->uv_top_[x * 16 + 0 + 7];
- enc->v_left_[-1] = enc->uv_top_[x * 16 + 8 + 7];
+ const int x = it->x_, y = it->y_;
+ const uint8_t* const ysrc = it->yuv_out_ + Y_OFF_ENC;
+ const uint8_t* const uvsrc = it->yuv_out_ + U_OFF_ENC;
+ if (x < enc->mb_w_ - 1) { // left
+ int i;
+ for (i = 0; i < 16; ++i) {
+ it->y_left_[i] = ysrc[15 + i * BPS];
}
- if (y < enc->mb_h_ - 1) { // top
- memcpy(enc->y_top_ + x * 16, ysrc + 15 * BPS, 16);
- memcpy(enc->uv_top_ + x * 16, usrc + 7 * BPS, 8 + 8);
+ for (i = 0; i < 8; ++i) {
+ it->u_left_[i] = uvsrc[7 + i * BPS];
+ it->v_left_[i] = uvsrc[15 + i * BPS];
}
+ // top-left (before 'top'!)
+ it->y_left_[-1] = it->y_top_[15];
+ it->u_left_[-1] = it->uv_top_[0 + 7];
+ it->v_left_[-1] = it->uv_top_[8 + 7];
}
+ if (y < enc->mb_h_ - 1) { // top
+ memcpy(it->y_top_, ysrc + 15 * BPS, 16);
+ memcpy(it->uv_top_, uvsrc + 7 * BPS, 8 + 8);
+ }
+}
- it->mb_++;
+int VP8IteratorNext(VP8EncIterator* const it) {
it->preds_ += 4;
- it->nz_++;
- it->x_++;
- if (it->x_ == enc->mb_w_) {
- it->x_ = 0;
- it->y_++;
- it->bw_ = &enc->parts_[it->y_ & (enc->num_parts_ - 1)];
- it->preds_ = enc->preds_ + it->y_ * 4 * enc->preds_w_;
- it->nz_ = enc->nz_;
- InitLeft(it);
+ it->mb_ += 1;
+ it->nz_ += 1;
+ it->y_top_ += 16;
+ it->uv_top_ += 16;
+ it->x_ += 1;
+ if (it->x_ == it->enc_->mb_w_) {
+ VP8IteratorSetRow(it, ++it->y_);
}
- return (0 < --it->done_);
+ return (0 < --it->count_down_);
}
//------------------------------------------------------------------------------
@@ -368,15 +405,15 @@ void VP8IteratorStartI4(VP8EncIterator* const it) {
// Import the boundary samples
for (i = 0; i < 17; ++i) { // left
- it->i4_boundary_[i] = enc->y_left_[15 - i];
+ it->i4_boundary_[i] = it->y_left_[15 - i];
}
for (i = 0; i < 16; ++i) { // top
- it->i4_boundary_[17 + i] = enc->y_top_[it->x_ * 16 + i];
+ it->i4_boundary_[17 + i] = it->y_top_[i];
}
// top-right samples have a special case on the far right of the picture
if (it->x_ < enc->mb_w_ - 1) {
for (i = 16; i < 16 + 4; ++i) {
- it->i4_boundary_[17 + i] = enc->y_top_[it->x_ * 16 + i];
+ it->i4_boundary_[17 + i] = it->y_top_[i];
}
} else { // else, replicate the last valid pixel four times
for (i = 16; i < 16 + 4; ++i) {
@@ -417,6 +454,3 @@ int VP8IteratorRotateI4(VP8EncIterator* const it,
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/enc/near_lossless.c b/drivers/webp/enc/near_lossless.c
new file mode 100644
index 0000000000..9bc0f0e786
--- /dev/null
+++ b/drivers/webp/enc/near_lossless.c
@@ -0,0 +1,160 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Near-lossless image preprocessing adjusts pixel values to help
+// compressibility with a guarantee of maximum deviation between original and
+// resulting pixel values.
+//
+// Author: Jyrki Alakuijala (jyrki@google.com)
+// Converted to C by Aleksander Kramarz (akramarz@google.com)
+
+#include <stdlib.h>
+
+#include "../dsp/lossless.h"
+#include "../utils/utils.h"
+#include "./vp8enci.h"
+
+#define MIN_DIM_FOR_NEAR_LOSSLESS 64
+#define MAX_LIMIT_BITS 5
+
+// Computes quantized pixel value and distance from original value.
+static void GetValAndDistance(int a, int initial, int bits,
+ int* const val, int* const distance) {
+ const int mask = ~((1 << bits) - 1);
+ *val = (initial & mask) | (initial >> (8 - bits));
+ *distance = 2 * abs(a - *val);
+}
+
+// Clamps the value to range [0, 255].
+static int Clamp8b(int val) {
+ const int min_val = 0;
+ const int max_val = 0xff;
+ return (val < min_val) ? min_val : (val > max_val) ? max_val : val;
+}
+
+// Quantizes values {a, a+(1<<bits), a-(1<<bits)} and returns the nearest one.
+static int FindClosestDiscretized(int a, int bits) {
+ int best_val = a, i;
+ int min_distance = 256;
+
+ for (i = -1; i <= 1; ++i) {
+ int candidate, distance;
+ const int val = Clamp8b(a + i * (1 << bits));
+ GetValAndDistance(a, val, bits, &candidate, &distance);
+ if (i != 0) {
+ ++distance;
+ }
+ // Smallest distance but favor i == 0 over i == -1 and i == 1
+ // since that keeps the overall intensity more constant in the
+ // images.
+ if (distance < min_distance) {
+ min_distance = distance;
+ best_val = candidate;
+ }
+ }
+ return best_val;
+}
+
+// Applies FindClosestDiscretized to all channels of pixel.
+static uint32_t ClosestDiscretizedArgb(uint32_t a, int bits) {
+ return
+ (FindClosestDiscretized(a >> 24, bits) << 24) |
+ (FindClosestDiscretized((a >> 16) & 0xff, bits) << 16) |
+ (FindClosestDiscretized((a >> 8) & 0xff, bits) << 8) |
+ (FindClosestDiscretized(a & 0xff, bits));
+}
+
+// Checks if distance between corresponding channel values of pixels a and b
+// is within the given limit.
+static int IsNear(uint32_t a, uint32_t b, int limit) {
+ int k;
+ for (k = 0; k < 4; ++k) {
+ const int delta =
+ (int)((a >> (k * 8)) & 0xff) - (int)((b >> (k * 8)) & 0xff);
+ if (delta >= limit || delta <= -limit) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int IsSmooth(const uint32_t* const prev_row,
+ const uint32_t* const curr_row,
+ const uint32_t* const next_row,
+ int ix, int limit) {
+ // Check that all pixels in 4-connected neighborhood are smooth.
+ return (IsNear(curr_row[ix], curr_row[ix - 1], limit) &&
+ IsNear(curr_row[ix], curr_row[ix + 1], limit) &&
+ IsNear(curr_row[ix], prev_row[ix], limit) &&
+ IsNear(curr_row[ix], next_row[ix], limit));
+}
+
+// Adjusts pixel values of image with given maximum error.
+static void NearLossless(int xsize, int ysize, uint32_t* argb,
+ int limit_bits, uint32_t* copy_buffer) {
+ int x, y;
+ const int limit = 1 << limit_bits;
+ uint32_t* prev_row = copy_buffer;
+ uint32_t* curr_row = prev_row + xsize;
+ uint32_t* next_row = curr_row + xsize;
+ memcpy(copy_buffer, argb, xsize * 2 * sizeof(argb[0]));
+
+ for (y = 1; y < ysize - 1; ++y) {
+ uint32_t* const curr_argb_row = argb + y * xsize;
+ uint32_t* const next_argb_row = curr_argb_row + xsize;
+ memcpy(next_row, next_argb_row, xsize * sizeof(argb[0]));
+ for (x = 1; x < xsize - 1; ++x) {
+ if (!IsSmooth(prev_row, curr_row, next_row, x, limit)) {
+ curr_argb_row[x] = ClosestDiscretizedArgb(curr_row[x], limit_bits);
+ }
+ }
+ {
+ // Three-way swap.
+ uint32_t* const temp = prev_row;
+ prev_row = curr_row;
+ curr_row = next_row;
+ next_row = temp;
+ }
+ }
+}
+
+static int QualityToLimitBits(int quality) {
+ // quality mapping:
+ // 0..19 -> 5
+ // 0..39 -> 4
+ // 0..59 -> 3
+ // 0..79 -> 2
+ // 0..99 -> 1
+ // 100 -> 0
+ return MAX_LIMIT_BITS - quality / 20;
+}
+
+int VP8ApplyNearLossless(int xsize, int ysize, uint32_t* argb, int quality) {
+ int i;
+ uint32_t* const copy_buffer =
+ (uint32_t*)WebPSafeMalloc(xsize * 3, sizeof(*copy_buffer));
+ const int limit_bits = QualityToLimitBits(quality);
+ assert(argb != NULL);
+ assert(limit_bits >= 0);
+ assert(limit_bits <= MAX_LIMIT_BITS);
+ if (copy_buffer == NULL) {
+ return 0;
+ }
+ // For small icon images, don't attempt to apply near-lossless compression.
+ if (xsize < MIN_DIM_FOR_NEAR_LOSSLESS && ysize < MIN_DIM_FOR_NEAR_LOSSLESS) {
+ WebPSafeFree(copy_buffer);
+ return 1;
+ }
+
+ for (i = limit_bits; i != 0; --i) {
+ NearLossless(xsize, ysize, argb, i, copy_buffer);
+ }
+ WebPSafeFree(copy_buffer);
+ return 1;
+}
diff --git a/drivers/webp/enc/picture.c b/drivers/webp/enc/picture.c
index 44eed06083..26679a72e4 100644
--- a/drivers/webp/enc/picture.c
+++ b/drivers/webp/enc/picture.c
@@ -1,470 +1,179 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
-// WebPPicture utils: colorspace conversion, crop, ...
+// WebPPicture class basis
//
// Author: Skal (pascal.massimino@gmail.com)
#include <assert.h>
#include <stdlib.h>
-#include <math.h>
#include "./vp8enci.h"
-#include "../utils/rescaler.h"
-#include "../utils/utils.h"
#include "../dsp/dsp.h"
-#include "../dsp/yuv.h"
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-#define HALVE(x) (((x) + 1) >> 1)
-#define IS_YUV_CSP(csp, YUV_CSP) (((csp) & WEBP_CSP_UV_MASK) == (YUV_CSP))
-
-static const union {
- uint32_t argb;
- uint8_t bytes[4];
-} test_endian = { 0xff000000u };
-#define ALPHA_IS_LAST (test_endian.bytes[3] == 0xff)
+#include "../utils/utils.h"
//------------------------------------------------------------------------------
// WebPPicture
//------------------------------------------------------------------------------
-int WebPPictureAlloc(WebPPicture* picture) {
- if (picture != NULL) {
- const WebPEncCSP uv_csp = picture->colorspace & WEBP_CSP_UV_MASK;
- const int has_alpha = picture->colorspace & WEBP_CSP_ALPHA_BIT;
- const int width = picture->width;
- const int height = picture->height;
-
- if (!picture->use_argb) {
- const int y_stride = width;
- const int uv_width = HALVE(width);
- const int uv_height = HALVE(height);
- const int uv_stride = uv_width;
- int uv0_stride = 0;
- int a_width, a_stride;
- uint64_t y_size, uv_size, uv0_size, a_size, total_size;
- uint8_t* mem;
-
- // U/V
- switch (uv_csp) {
- case WEBP_YUV420:
- break;
-#ifdef WEBP_EXPERIMENTAL_FEATURES
- case WEBP_YUV400: // for now, we'll just reset the U/V samples
- break;
- case WEBP_YUV422:
- uv0_stride = uv_width;
- break;
- case WEBP_YUV444:
- uv0_stride = width;
- break;
-#endif
- default:
- return 0;
- }
- uv0_size = height * uv0_stride;
-
- // alpha
- a_width = has_alpha ? width : 0;
- a_stride = a_width;
- y_size = (uint64_t)y_stride * height;
- uv_size = (uint64_t)uv_stride * uv_height;
- a_size = (uint64_t)a_stride * height;
-
- total_size = y_size + a_size + 2 * uv_size + 2 * uv0_size;
-
- // Security and validation checks
- if (width <= 0 || height <= 0 || // luma/alpha param error
- uv_width < 0 || uv_height < 0) { // u/v param error
- return 0;
- }
- // Clear previous buffer and allocate a new one.
- WebPPictureFree(picture); // erase previous buffer
- mem = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*mem));
- if (mem == NULL) return 0;
-
- // From now on, we're in the clear, we can no longer fail...
- picture->memory_ = (void*)mem;
- picture->y_stride = y_stride;
- picture->uv_stride = uv_stride;
- picture->a_stride = a_stride;
- picture->uv0_stride = uv0_stride;
- // TODO(skal): we could align the y/u/v planes and adjust stride.
- picture->y = mem;
- mem += y_size;
-
- picture->u = mem;
- mem += uv_size;
- picture->v = mem;
- mem += uv_size;
-
- if (a_size) {
- picture->a = mem;
- mem += a_size;
- }
- if (uv0_size) {
- picture->u0 = mem;
- mem += uv0_size;
- picture->v0 = mem;
- mem += uv0_size;
- }
- } else {
- void* memory;
- const uint64_t argb_size = (uint64_t)width * height;
- if (width <= 0 || height <= 0) {
- return 0;
- }
- // Clear previous buffer and allocate a new one.
- WebPPictureFree(picture); // erase previous buffer
- memory = WebPSafeMalloc(argb_size, sizeof(*picture->argb));
- if (memory == NULL) return 0;
+static int DummyWriter(const uint8_t* data, size_t data_size,
+ const WebPPicture* const picture) {
+ // The following are to prevent 'unused variable' error message.
+ (void)data;
+ (void)data_size;
+ (void)picture;
+ return 1;
+}
- // TODO(skal): align plane to cache line?
- picture->memory_argb_ = memory;
- picture->argb = (uint32_t*)memory;
- picture->argb_stride = width;
- }
+int WebPPictureInitInternal(WebPPicture* picture, int version) {
+ if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_ENCODER_ABI_VERSION)) {
+ return 0; // caller/system version mismatch!
+ }
+ if (picture != NULL) {
+ memset(picture, 0, sizeof(*picture));
+ picture->writer = DummyWriter;
+ WebPEncodingSetError(picture, VP8_ENC_OK);
}
return 1;
}
-// Remove reference to the ARGB buffer (doesn't free anything).
-static void PictureResetARGB(WebPPicture* const picture) {
+//------------------------------------------------------------------------------
+
+static void WebPPictureResetBufferARGB(WebPPicture* const picture) {
picture->memory_argb_ = NULL;
picture->argb = NULL;
picture->argb_stride = 0;
}
-// Remove reference to the YUVA buffer (doesn't free anything).
-static void PictureResetYUVA(WebPPicture* const picture) {
+static void WebPPictureResetBufferYUVA(WebPPicture* const picture) {
picture->memory_ = NULL;
picture->y = picture->u = picture->v = picture->a = NULL;
- picture->u0 = picture->v0 = NULL;
picture->y_stride = picture->uv_stride = 0;
picture->a_stride = 0;
- picture->uv0_stride = 0;
}
-// Grab the 'specs' (writer, *opaque, width, height...) from 'src' and copy them
-// into 'dst'. Mark 'dst' as not owning any memory.
-static void WebPPictureGrabSpecs(const WebPPicture* const src,
- WebPPicture* const dst) {
- assert(src != NULL && dst != NULL);
- *dst = *src;
- PictureResetYUVA(dst);
- PictureResetARGB(dst);
+void WebPPictureResetBuffers(WebPPicture* const picture) {
+ WebPPictureResetBufferARGB(picture);
+ WebPPictureResetBufferYUVA(picture);
}
-// Allocate a new argb buffer, discarding any existing one and preserving
-// the other YUV(A) buffer.
-static int PictureAllocARGB(WebPPicture* const picture) {
- WebPPicture tmp;
- free(picture->memory_argb_);
- PictureResetARGB(picture);
- picture->use_argb = 1;
- WebPPictureGrabSpecs(picture, &tmp);
- if (!WebPPictureAlloc(&tmp)) {
- return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
- }
- picture->memory_argb_ = tmp.memory_argb_;
- picture->argb = tmp.argb;
- picture->argb_stride = tmp.argb_stride;
- return 1;
-}
+int WebPPictureAllocARGB(WebPPicture* const picture, int width, int height) {
+ void* memory;
+ const uint64_t argb_size = (uint64_t)width * height;
-// Release memory owned by 'picture' (both YUV and ARGB buffers).
-void WebPPictureFree(WebPPicture* picture) {
- if (picture != NULL) {
- free(picture->memory_);
- free(picture->memory_argb_);
- PictureResetYUVA(picture);
- PictureResetARGB(picture);
- }
-}
+ assert(picture != NULL);
-//------------------------------------------------------------------------------
-// Picture copying
+ WebPSafeFree(picture->memory_argb_);
+ WebPPictureResetBufferARGB(picture);
-// Not worth moving to dsp/enc.c (only used here).
-static void CopyPlane(const uint8_t* src, int src_stride,
- uint8_t* dst, int dst_stride, int width, int height) {
- while (height-- > 0) {
- memcpy(dst, src, width);
- src += src_stride;
- dst += dst_stride;
+ if (width <= 0 || height <= 0) {
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
}
-}
-
-// Adjust top-left corner to chroma sample position.
-static void SnapTopLeftPosition(const WebPPicture* const pic,
- int* const left, int* const top) {
- if (!pic->use_argb) {
- const int is_yuv422 = IS_YUV_CSP(pic->colorspace, WEBP_YUV422);
- if (IS_YUV_CSP(pic->colorspace, WEBP_YUV420) || is_yuv422) {
- *left &= ~1;
- if (!is_yuv422) *top &= ~1;
- }
+ // allocate a new buffer.
+ memory = WebPSafeMalloc(argb_size, sizeof(*picture->argb));
+ if (memory == NULL) {
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
}
-}
-
-// Adjust top-left corner and verify that the sub-rectangle is valid.
-static int AdjustAndCheckRectangle(const WebPPicture* const pic,
- int* const left, int* const top,
- int width, int height) {
- SnapTopLeftPosition(pic, left, top);
- if ((*left) < 0 || (*top) < 0) return 0;
- if (width <= 0 || height <= 0) return 0;
- if ((*left) + width > pic->width) return 0;
- if ((*top) + height > pic->height) return 0;
+ // TODO(skal): align plane to cache line?
+ picture->memory_argb_ = memory;
+ picture->argb = (uint32_t*)memory;
+ picture->argb_stride = width;
return 1;
}
-int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst) {
- if (src == NULL || dst == NULL) return 0;
- if (src == dst) return 1;
+int WebPPictureAllocYUVA(WebPPicture* const picture, int width, int height) {
+ const WebPEncCSP uv_csp = picture->colorspace & WEBP_CSP_UV_MASK;
+ const int has_alpha = picture->colorspace & WEBP_CSP_ALPHA_BIT;
+ const int y_stride = width;
+ const int uv_width = (width + 1) >> 1;
+ const int uv_height = (height + 1) >> 1;
+ const int uv_stride = uv_width;
+ int a_width, a_stride;
+ uint64_t y_size, uv_size, a_size, total_size;
+ uint8_t* mem;
- WebPPictureGrabSpecs(src, dst);
- if (!WebPPictureAlloc(dst)) return 0;
+ assert(picture != NULL);
- if (!src->use_argb) {
- CopyPlane(src->y, src->y_stride,
- dst->y, dst->y_stride, dst->width, dst->height);
- CopyPlane(src->u, src->uv_stride,
- dst->u, dst->uv_stride, HALVE(dst->width), HALVE(dst->height));
- CopyPlane(src->v, src->uv_stride,
- dst->v, dst->uv_stride, HALVE(dst->width), HALVE(dst->height));
- if (dst->a != NULL) {
- CopyPlane(src->a, src->a_stride,
- dst->a, dst->a_stride, dst->width, dst->height);
- }
-#ifdef WEBP_EXPERIMENTAL_FEATURES
- if (dst->u0 != NULL) {
- int uv0_width = src->width;
- if (IS_YUV_CSP(dst->colorspace, WEBP_YUV422)) {
- uv0_width = HALVE(uv0_width);
- }
- CopyPlane(src->u0, src->uv0_stride,
- dst->u0, dst->uv0_stride, uv0_width, dst->height);
- CopyPlane(src->v0, src->uv0_stride,
- dst->v0, dst->uv0_stride, uv0_width, dst->height);
- }
-#endif
- } else {
- CopyPlane((const uint8_t*)src->argb, 4 * src->argb_stride,
- (uint8_t*)dst->argb, 4 * dst->argb_stride,
- 4 * dst->width, dst->height);
- }
- return 1;
-}
+ WebPSafeFree(picture->memory_);
+ WebPPictureResetBufferYUVA(picture);
-int WebPPictureIsView(const WebPPicture* picture) {
- if (picture == NULL) return 0;
- if (picture->use_argb) {
- return (picture->memory_argb_ == NULL);
+ if (uv_csp != WEBP_YUV420) {
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);
}
- return (picture->memory_ == NULL);
-}
-int WebPPictureView(const WebPPicture* src,
- int left, int top, int width, int height,
- WebPPicture* dst) {
- if (src == NULL || dst == NULL) return 0;
+ // alpha
+ a_width = has_alpha ? width : 0;
+ a_stride = a_width;
+ y_size = (uint64_t)y_stride * height;
+ uv_size = (uint64_t)uv_stride * uv_height;
+ a_size = (uint64_t)a_stride * height;
- // verify rectangle position.
- if (!AdjustAndCheckRectangle(src, &left, &top, width, height)) return 0;
+ total_size = y_size + a_size + 2 * uv_size;
- if (src != dst) { // beware of aliasing! We don't want to leak 'memory_'.
- WebPPictureGrabSpecs(src, dst);
+ // Security and validation checks
+ if (width <= 0 || height <= 0 || // luma/alpha param error
+ uv_width < 0 || uv_height < 0) { // u/v param error
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_BAD_DIMENSION);
}
- dst->width = width;
- dst->height = height;
- if (!src->use_argb) {
- dst->y = src->y + top * src->y_stride + left;
- dst->u = src->u + (top >> 1) * src->uv_stride + (left >> 1);
- dst->v = src->v + (top >> 1) * src->uv_stride + (left >> 1);
- if (src->a != NULL) {
- dst->a = src->a + top * src->a_stride + left;
- }
-#ifdef WEBP_EXPERIMENTAL_FEATURES
- if (src->u0 != NULL) {
- const int left_pos =
- IS_YUV_CSP(dst->colorspace, WEBP_YUV422) ? (left >> 1) : left;
- dst->u0 = src->u0 + top * src->uv0_stride + left_pos;
- dst->v0 = src->v0 + top * src->uv0_stride + left_pos;
- }
-#endif
- } else {
- dst->argb = src->argb + top * src->argb_stride + left;
+ // allocate a new buffer.
+ mem = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*mem));
+ if (mem == NULL) {
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
}
- return 1;
-}
-//------------------------------------------------------------------------------
-// Picture cropping
+ // From now on, we're in the clear, we can no longer fail...
+ picture->memory_ = (void*)mem;
+ picture->y_stride = y_stride;
+ picture->uv_stride = uv_stride;
+ picture->a_stride = a_stride;
-int WebPPictureCrop(WebPPicture* pic,
- int left, int top, int width, int height) {
- WebPPicture tmp;
+ // TODO(skal): we could align the y/u/v planes and adjust stride.
+ picture->y = mem;
+ mem += y_size;
- if (pic == NULL) return 0;
- if (!AdjustAndCheckRectangle(pic, &left, &top, width, height)) return 0;
+ picture->u = mem;
+ mem += uv_size;
+ picture->v = mem;
+ mem += uv_size;
- WebPPictureGrabSpecs(pic, &tmp);
- tmp.width = width;
- tmp.height = height;
- if (!WebPPictureAlloc(&tmp)) return 0;
-
- if (!pic->use_argb) {
- const int y_offset = top * pic->y_stride + left;
- const int uv_offset = (top / 2) * pic->uv_stride + left / 2;
- CopyPlane(pic->y + y_offset, pic->y_stride,
- tmp.y, tmp.y_stride, width, height);
- CopyPlane(pic->u + uv_offset, pic->uv_stride,
- tmp.u, tmp.uv_stride, HALVE(width), HALVE(height));
- CopyPlane(pic->v + uv_offset, pic->uv_stride,
- tmp.v, tmp.uv_stride, HALVE(width), HALVE(height));
-
- if (tmp.a != NULL) {
- const int a_offset = top * pic->a_stride + left;
- CopyPlane(pic->a + a_offset, pic->a_stride,
- tmp.a, tmp.a_stride, width, height);
- }
-#ifdef WEBP_EXPERIMENTAL_FEATURES
- if (tmp.u0 != NULL) {
- int w = width;
- int left_pos = left;
- if (IS_YUV_CSP(tmp.colorspace, WEBP_YUV422)) {
- w = HALVE(w);
- left_pos = HALVE(left_pos);
- }
- CopyPlane(pic->u0 + top * pic->uv0_stride + left_pos, pic->uv0_stride,
- tmp.u0, tmp.uv0_stride, w, height);
- CopyPlane(pic->v0 + top * pic->uv0_stride + left_pos, pic->uv0_stride,
- tmp.v0, tmp.uv0_stride, w, height);
- }
-#endif
- } else {
- const uint8_t* const src =
- (const uint8_t*)(pic->argb + top * pic->argb_stride + left);
- CopyPlane(src, pic->argb_stride * 4,
- (uint8_t*)tmp.argb, tmp.argb_stride * 4,
- width * 4, height);
+ if (a_size > 0) {
+ picture->a = mem;
+ mem += a_size;
}
- WebPPictureFree(pic);
- *pic = tmp;
+ (void)mem; // makes the static analyzer happy
return 1;
}
-//------------------------------------------------------------------------------
-// Simple picture rescaler
-
-static void RescalePlane(const uint8_t* src,
- int src_width, int src_height, int src_stride,
- uint8_t* dst,
- int dst_width, int dst_height, int dst_stride,
- int32_t* const work,
- int num_channels) {
- WebPRescaler rescaler;
- int y = 0;
- WebPRescalerInit(&rescaler, src_width, src_height,
- dst, dst_width, dst_height, dst_stride,
- num_channels,
- src_width, dst_width,
- src_height, dst_height,
- work);
- memset(work, 0, 2 * dst_width * num_channels * sizeof(*work));
- while (y < src_height) {
- y += WebPRescalerImport(&rescaler, src_height - y,
- src + y * src_stride, src_stride);
- WebPRescalerExport(&rescaler);
- }
-}
-
-int WebPPictureRescale(WebPPicture* pic, int width, int height) {
- WebPPicture tmp;
- int prev_width, prev_height;
- int32_t* work;
-
- if (pic == NULL) return 0;
- prev_width = pic->width;
- prev_height = pic->height;
- // if width is unspecified, scale original proportionally to height ratio.
- if (width == 0) {
- width = (prev_width * height + prev_height / 2) / prev_height;
- }
- // if height is unspecified, scale original proportionally to width ratio.
- if (height == 0) {
- height = (prev_height * width + prev_width / 2) / prev_width;
- }
- // Check if the overall dimensions still make sense.
- if (width <= 0 || height <= 0) return 0;
-
- WebPPictureGrabSpecs(pic, &tmp);
- tmp.width = width;
- tmp.height = height;
- if (!WebPPictureAlloc(&tmp)) return 0;
-
- if (!pic->use_argb) {
- work = (int32_t*)WebPSafeMalloc(2ULL * width, sizeof(*work));
- if (work == NULL) {
- WebPPictureFree(&tmp);
- return 0;
- }
+int WebPPictureAlloc(WebPPicture* picture) {
+ if (picture != NULL) {
+ const int width = picture->width;
+ const int height = picture->height;
- RescalePlane(pic->y, prev_width, prev_height, pic->y_stride,
- tmp.y, width, height, tmp.y_stride, work, 1);
- RescalePlane(pic->u,
- HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
- tmp.u,
- HALVE(width), HALVE(height), tmp.uv_stride, work, 1);
- RescalePlane(pic->v,
- HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
- tmp.v,
- HALVE(width), HALVE(height), tmp.uv_stride, work, 1);
+ WebPPictureFree(picture); // erase previous buffer
- if (tmp.a != NULL) {
- RescalePlane(pic->a, prev_width, prev_height, pic->a_stride,
- tmp.a, width, height, tmp.a_stride, work, 1);
- }
-#ifdef WEBP_EXPERIMENTAL_FEATURES
- if (tmp.u0 != NULL) {
- const int s = IS_YUV_CSP(tmp.colorspace, WEBP_YUV422) ? 2 : 1;
- RescalePlane(
- pic->u0, (prev_width + s / 2) / s, prev_height, pic->uv0_stride,
- tmp.u0, (width + s / 2) / s, height, tmp.uv0_stride, work, 1);
- RescalePlane(
- pic->v0, (prev_width + s / 2) / s, prev_height, pic->uv0_stride,
- tmp.v0, (width + s / 2) / s, height, tmp.uv0_stride, work, 1);
- }
-#endif
- } else {
- work = (int32_t*)WebPSafeMalloc(2ULL * width * 4, sizeof(*work));
- if (work == NULL) {
- WebPPictureFree(&tmp);
- return 0;
+ if (!picture->use_argb) {
+ return WebPPictureAllocYUVA(picture, width, height);
+ } else {
+ return WebPPictureAllocARGB(picture, width, height);
}
-
- RescalePlane((const uint8_t*)pic->argb, prev_width, prev_height,
- pic->argb_stride * 4,
- (uint8_t*)tmp.argb, width, height,
- tmp.argb_stride * 4,
- work, 4);
-
}
- WebPPictureFree(pic);
- free(work);
- *pic = tmp;
return 1;
}
+void WebPPictureFree(WebPPicture* picture) {
+ if (picture != NULL) {
+ WebPSafeFree(picture->memory_);
+ WebPSafeFree(picture->memory_argb_);
+ WebPPictureResetBuffers(picture);
+ }
+}
+
//------------------------------------------------------------------------------
// WebPMemoryWriter: Write-to-memory
@@ -494,7 +203,7 @@ int WebPMemoryWrite(const uint8_t* data, size_t data_size,
if (w->size > 0) {
memcpy(new_mem, w->mem, w->size);
}
- free(w->mem);
+ WebPSafeFree(w->mem);
w->mem = new_mem;
// down-cast is ok, thanks to WebPSafeMalloc
w->max_size = (size_t)next_max_size;
@@ -506,469 +215,13 @@ int WebPMemoryWrite(const uint8_t* data, size_t data_size,
return 1;
}
-//------------------------------------------------------------------------------
-// Detection of non-trivial transparency
-
-// Returns true if alpha[] has non-0xff values.
-static int CheckNonOpaque(const uint8_t* alpha, int width, int height,
- int x_step, int y_step) {
- if (alpha == NULL) return 0;
- while (height-- > 0) {
- int x;
- for (x = 0; x < width * x_step; x += x_step) {
- if (alpha[x] != 0xff) return 1; // TODO(skal): check 4/8 bytes at a time.
- }
- alpha += y_step;
- }
- return 0;
-}
-
-// Checking for the presence of non-opaque alpha.
-int WebPPictureHasTransparency(const WebPPicture* picture) {
- if (picture == NULL) return 0;
- if (!picture->use_argb) {
- return CheckNonOpaque(picture->a, picture->width, picture->height,
- 1, picture->a_stride);
- } else {
- int x, y;
- const uint32_t* argb = picture->argb;
- if (argb == NULL) return 0;
- for (y = 0; y < picture->height; ++y) {
- for (x = 0; x < picture->width; ++x) {
- if (argb[x] < 0xff000000u) return 1; // test any alpha values != 0xff
- }
- argb += picture->argb_stride;
- }
- }
- return 0;
-}
-
-//------------------------------------------------------------------------------
-// RGB -> YUV conversion
-
-// TODO: we can do better than simply 2x2 averaging on U/V samples.
-#define SUM4(ptr) ((ptr)[0] + (ptr)[step] + \
- (ptr)[rgb_stride] + (ptr)[rgb_stride + step])
-#define SUM2H(ptr) (2 * (ptr)[0] + 2 * (ptr)[step])
-#define SUM2V(ptr) (2 * (ptr)[0] + 2 * (ptr)[rgb_stride])
-#define SUM1(ptr) (4 * (ptr)[0])
-#define RGB_TO_UV(x, y, SUM) { \
- const int src = (2 * (step * (x) + (y) * rgb_stride)); \
- const int dst = (x) + (y) * picture->uv_stride; \
- const int r = SUM(r_ptr + src); \
- const int g = SUM(g_ptr + src); \
- const int b = SUM(b_ptr + src); \
- picture->u[dst] = VP8RGBToU(r, g, b); \
- picture->v[dst] = VP8RGBToV(r, g, b); \
-}
-
-#define RGB_TO_UV0(x_in, x_out, y, SUM) { \
- const int src = (step * (x_in) + (y) * rgb_stride); \
- const int dst = (x_out) + (y) * picture->uv0_stride; \
- const int r = SUM(r_ptr + src); \
- const int g = SUM(g_ptr + src); \
- const int b = SUM(b_ptr + src); \
- picture->u0[dst] = VP8RGBToU(r, g, b); \
- picture->v0[dst] = VP8RGBToV(r, g, b); \
-}
-
-static void MakeGray(WebPPicture* const picture) {
- int y;
- const int uv_width = HALVE(picture->width);
- const int uv_height = HALVE(picture->height);
- for (y = 0; y < uv_height; ++y) {
- memset(picture->u + y * picture->uv_stride, 128, uv_width);
- memset(picture->v + y * picture->uv_stride, 128, uv_width);
- }
-}
-
-static int ImportYUVAFromRGBA(const uint8_t* const r_ptr,
- const uint8_t* const g_ptr,
- const uint8_t* const b_ptr,
- const uint8_t* const a_ptr,
- int step, // bytes per pixel
- int rgb_stride, // bytes per scanline
- WebPPicture* const picture) {
- const WebPEncCSP uv_csp = picture->colorspace & WEBP_CSP_UV_MASK;
- int x, y;
- const int width = picture->width;
- const int height = picture->height;
- const int has_alpha = CheckNonOpaque(a_ptr, width, height, step, rgb_stride);
-
- picture->colorspace = uv_csp;
- picture->use_argb = 0;
- if (has_alpha) {
- picture->colorspace |= WEBP_CSP_ALPHA_BIT;
- }
- if (!WebPPictureAlloc(picture)) return 0;
-
- // Import luma plane
- for (y = 0; y < height; ++y) {
- for (x = 0; x < width; ++x) {
- const int offset = step * x + y * rgb_stride;
- picture->y[x + y * picture->y_stride] =
- VP8RGBToY(r_ptr[offset], g_ptr[offset], b_ptr[offset]);
- }
- }
-
- // Downsample U/V plane
- if (uv_csp != WEBP_YUV400) {
- for (y = 0; y < (height >> 1); ++y) {
- for (x = 0; x < (width >> 1); ++x) {
- RGB_TO_UV(x, y, SUM4);
- }
- if (width & 1) {
- RGB_TO_UV(x, y, SUM2V);
- }
- }
- if (height & 1) {
- for (x = 0; x < (width >> 1); ++x) {
- RGB_TO_UV(x, y, SUM2H);
- }
- if (width & 1) {
- RGB_TO_UV(x, y, SUM1);
- }
- }
-
-#ifdef WEBP_EXPERIMENTAL_FEATURES
- // Store original U/V samples too
- if (uv_csp == WEBP_YUV422) {
- for (y = 0; y < height; ++y) {
- for (x = 0; x < (width >> 1); ++x) {
- RGB_TO_UV0(2 * x, x, y, SUM2H);
- }
- if (width & 1) {
- RGB_TO_UV0(2 * x, x, y, SUM1);
- }
- }
- } else if (uv_csp == WEBP_YUV444) {
- for (y = 0; y < height; ++y) {
- for (x = 0; x < width; ++x) {
- RGB_TO_UV0(x, x, y, SUM1);
- }
- }
- }
-#endif
- } else {
- MakeGray(picture);
- }
-
- if (has_alpha) {
- assert(step >= 4);
- for (y = 0; y < height; ++y) {
- for (x = 0; x < width; ++x) {
- picture->a[x + y * picture->a_stride] =
- a_ptr[step * x + y * rgb_stride];
- }
- }
- }
- return 1;
-}
-
-static int Import(WebPPicture* const picture,
- const uint8_t* const rgb, int rgb_stride,
- int step, int swap_rb, int import_alpha) {
- const uint8_t* const r_ptr = rgb + (swap_rb ? 2 : 0);
- const uint8_t* const g_ptr = rgb + 1;
- const uint8_t* const b_ptr = rgb + (swap_rb ? 0 : 2);
- const uint8_t* const a_ptr = import_alpha ? rgb + 3 : NULL;
- const int width = picture->width;
- const int height = picture->height;
-
- if (!picture->use_argb) {
- return ImportYUVAFromRGBA(r_ptr, g_ptr, b_ptr, a_ptr, step, rgb_stride,
- picture);
- }
- if (import_alpha) {
- picture->colorspace |= WEBP_CSP_ALPHA_BIT;
- } else {
- picture->colorspace &= ~WEBP_CSP_ALPHA_BIT;
- }
- if (!WebPPictureAlloc(picture)) return 0;
-
- if (!import_alpha) {
- int x, y;
- for (y = 0; y < height; ++y) {
- for (x = 0; x < width; ++x) {
- const int offset = step * x + y * rgb_stride;
- const uint32_t argb =
- 0xff000000u |
- (r_ptr[offset] << 16) |
- (g_ptr[offset] << 8) |
- (b_ptr[offset]);
- picture->argb[x + y * picture->argb_stride] = argb;
- }
- }
- } else {
- int x, y;
- assert(step >= 4);
- for (y = 0; y < height; ++y) {
- for (x = 0; x < width; ++x) {
- const int offset = step * x + y * rgb_stride;
- const uint32_t argb = (a_ptr[offset] << 24) |
- (r_ptr[offset] << 16) |
- (g_ptr[offset] << 8) |
- (b_ptr[offset]);
- picture->argb[x + y * picture->argb_stride] = argb;
- }
- }
- }
- return 1;
-}
-#undef SUM4
-#undef SUM2V
-#undef SUM2H
-#undef SUM1
-#undef RGB_TO_UV
-
-int WebPPictureImportRGB(WebPPicture* picture,
- const uint8_t* rgb, int rgb_stride) {
- return Import(picture, rgb, rgb_stride, 3, 0, 0);
-}
-
-int WebPPictureImportBGR(WebPPicture* picture,
- const uint8_t* rgb, int rgb_stride) {
- return Import(picture, rgb, rgb_stride, 3, 1, 0);
-}
-
-int WebPPictureImportRGBA(WebPPicture* picture,
- const uint8_t* rgba, int rgba_stride) {
- return Import(picture, rgba, rgba_stride, 4, 0, 1);
-}
-
-int WebPPictureImportBGRA(WebPPicture* picture,
- const uint8_t* rgba, int rgba_stride) {
- return Import(picture, rgba, rgba_stride, 4, 1, 1);
-}
-
-int WebPPictureImportRGBX(WebPPicture* picture,
- const uint8_t* rgba, int rgba_stride) {
- return Import(picture, rgba, rgba_stride, 4, 0, 0);
-}
-
-int WebPPictureImportBGRX(WebPPicture* picture,
- const uint8_t* rgba, int rgba_stride) {
- return Import(picture, rgba, rgba_stride, 4, 1, 0);
-}
-
-//------------------------------------------------------------------------------
-// Automatic YUV <-> ARGB conversions.
-
-int WebPPictureYUVAToARGB(WebPPicture* picture) {
- if (picture == NULL) return 0;
- if (picture->memory_ == NULL || picture->y == NULL ||
- picture->u == NULL || picture->v == NULL) {
- return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
- }
- if ((picture->colorspace & WEBP_CSP_ALPHA_BIT) && picture->a == NULL) {
- return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
- }
- if ((picture->colorspace & WEBP_CSP_UV_MASK) != WEBP_YUV420) {
- return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);
- }
- // Allocate a new argb buffer (discarding the previous one).
- if (!PictureAllocARGB(picture)) return 0;
-
- // Convert
- {
- int y;
- const int width = picture->width;
- const int height = picture->height;
- const int argb_stride = 4 * picture->argb_stride;
- uint8_t* dst = (uint8_t*)picture->argb;
- const uint8_t *cur_u = picture->u, *cur_v = picture->v, *cur_y = picture->y;
- WebPUpsampleLinePairFunc upsample = WebPGetLinePairConverter(ALPHA_IS_LAST);
-
- // First row, with replicated top samples.
- upsample(NULL, cur_y, cur_u, cur_v, cur_u, cur_v, NULL, dst, width);
- cur_y += picture->y_stride;
- dst += argb_stride;
- // Center rows.
- for (y = 1; y + 1 < height; y += 2) {
- const uint8_t* const top_u = cur_u;
- const uint8_t* const top_v = cur_v;
- cur_u += picture->uv_stride;
- cur_v += picture->uv_stride;
- upsample(cur_y, cur_y + picture->y_stride, top_u, top_v, cur_u, cur_v,
- dst, dst + argb_stride, width);
- cur_y += 2 * picture->y_stride;
- dst += 2 * argb_stride;
- }
- // Last row (if needed), with replicated bottom samples.
- if (height > 1 && !(height & 1)) {
- upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, dst, NULL, width);
- }
- // Insert alpha values if needed, in replacement for the default 0xff ones.
- if (picture->colorspace & WEBP_CSP_ALPHA_BIT) {
- for (y = 0; y < height; ++y) {
- uint32_t* const dst = picture->argb + y * picture->argb_stride;
- const uint8_t* const src = picture->a + y * picture->a_stride;
- int x;
- for (x = 0; x < width; ++x) {
- dst[x] = (dst[x] & 0x00ffffffu) | (src[x] << 24);
- }
- }
- }
- }
- return 1;
-}
-
-int WebPPictureARGBToYUVA(WebPPicture* picture, WebPEncCSP colorspace) {
- if (picture == NULL) return 0;
- if (picture->argb == NULL) {
- return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
- } else {
- const uint8_t* const argb = (const uint8_t*)picture->argb;
- const uint8_t* const r = ALPHA_IS_LAST ? argb + 2 : argb + 1;
- const uint8_t* const g = ALPHA_IS_LAST ? argb + 1 : argb + 2;
- const uint8_t* const b = ALPHA_IS_LAST ? argb + 0 : argb + 3;
- const uint8_t* const a = ALPHA_IS_LAST ? argb + 3 : argb + 0;
- // We work on a tmp copy of 'picture', because ImportYUVAFromRGBA()
- // would be calling WebPPictureFree(picture) otherwise.
- WebPPicture tmp = *picture;
- PictureResetARGB(&tmp); // reset ARGB buffer so that it's not free()'d.
- tmp.use_argb = 0;
- tmp.colorspace = colorspace & WEBP_CSP_UV_MASK;
- if (!ImportYUVAFromRGBA(r, g, b, a, 4, 4 * picture->argb_stride, &tmp)) {
- return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
- }
- // Copy back the YUV specs into 'picture'.
- tmp.argb = picture->argb;
- tmp.argb_stride = picture->argb_stride;
- tmp.memory_argb_ = picture->memory_argb_;
- *picture = tmp;
+void WebPMemoryWriterClear(WebPMemoryWriter* writer) {
+ if (writer != NULL) {
+ WebPSafeFree(writer->mem);
+ writer->mem = NULL;
+ writer->size = 0;
+ writer->max_size = 0;
}
- return 1;
-}
-
-//------------------------------------------------------------------------------
-// Helper: clean up fully transparent area to help compressibility.
-
-#define SIZE 8
-#define SIZE2 (SIZE / 2)
-static int is_transparent_area(const uint8_t* ptr, int stride, int size) {
- int y, x;
- for (y = 0; y < size; ++y) {
- for (x = 0; x < size; ++x) {
- if (ptr[x]) {
- return 0;
- }
- }
- ptr += stride;
- }
- return 1;
-}
-
-static WEBP_INLINE void flatten(uint8_t* ptr, int v, int stride, int size) {
- int y;
- for (y = 0; y < size; ++y) {
- memset(ptr, v, size);
- ptr += stride;
- }
-}
-
-void WebPCleanupTransparentArea(WebPPicture* pic) {
- int x, y, w, h;
- const uint8_t* a_ptr;
- int values[3] = { 0 };
-
- if (pic == NULL) return;
-
- a_ptr = pic->a;
- if (a_ptr == NULL) return; // nothing to do
-
- w = pic->width / SIZE;
- h = pic->height / SIZE;
- for (y = 0; y < h; ++y) {
- int need_reset = 1;
- for (x = 0; x < w; ++x) {
- const int off_a = (y * pic->a_stride + x) * SIZE;
- const int off_y = (y * pic->y_stride + x) * SIZE;
- const int off_uv = (y * pic->uv_stride + x) * SIZE2;
- if (is_transparent_area(a_ptr + off_a, pic->a_stride, SIZE)) {
- if (need_reset) {
- values[0] = pic->y[off_y];
- values[1] = pic->u[off_uv];
- values[2] = pic->v[off_uv];
- need_reset = 0;
- }
- flatten(pic->y + off_y, values[0], pic->y_stride, SIZE);
- flatten(pic->u + off_uv, values[1], pic->uv_stride, SIZE2);
- flatten(pic->v + off_uv, values[2], pic->uv_stride, SIZE2);
- } else {
- need_reset = 1;
- }
- }
- // ignore the left-overs on right/bottom
- }
-}
-
-#undef SIZE
-#undef SIZE2
-
-
-//------------------------------------------------------------------------------
-// Distortion
-
-// Max value returned in case of exact similarity.
-static const double kMinDistortion_dB = 99.;
-
-int WebPPictureDistortion(const WebPPicture* pic1, const WebPPicture* pic2,
- int type, float result[5]) {
- int c;
- DistoStats stats[5];
- int has_alpha;
-
- if (pic1 == NULL || pic2 == NULL ||
- pic1->width != pic2->width || pic1->height != pic2->height ||
- pic1->y == NULL || pic2->y == NULL ||
- pic1->u == NULL || pic2->u == NULL ||
- pic1->v == NULL || pic2->v == NULL ||
- result == NULL) {
- return 0;
- }
- // TODO(skal): provide distortion for ARGB too.
- if (pic1->use_argb == 1 || pic1->use_argb != pic2->use_argb) {
- return 0;
- }
-
- has_alpha = !!(pic1->colorspace & WEBP_CSP_ALPHA_BIT);
- if (has_alpha != !!(pic2->colorspace & WEBP_CSP_ALPHA_BIT) ||
- (has_alpha && (pic1->a == NULL || pic2->a == NULL))) {
- return 0;
- }
-
- memset(stats, 0, sizeof(stats));
- VP8SSIMAccumulatePlane(pic1->y, pic1->y_stride,
- pic2->y, pic2->y_stride,
- pic1->width, pic1->height, &stats[0]);
- VP8SSIMAccumulatePlane(pic1->u, pic1->uv_stride,
- pic2->u, pic2->uv_stride,
- (pic1->width + 1) >> 1, (pic1->height + 1) >> 1,
- &stats[1]);
- VP8SSIMAccumulatePlane(pic1->v, pic1->uv_stride,
- pic2->v, pic2->uv_stride,
- (pic1->width + 1) >> 1, (pic1->height + 1) >> 1,
- &stats[2]);
- if (has_alpha) {
- VP8SSIMAccumulatePlane(pic1->a, pic1->a_stride,
- pic2->a, pic2->a_stride,
- pic1->width, pic1->height, &stats[3]);
- }
- for (c = 0; c <= 4; ++c) {
- if (type == 1) {
- const double v = VP8SSIMGet(&stats[c]);
- result[c] = (float)((v < 1.) ? -10.0 * log10(1. - v)
- : kMinDistortion_dB);
- } else {
- const double v = VP8SSIMGetSquaredError(&stats[c]);
- result[c] = (float)((v > 0.) ? -4.3429448 * log(v / (255 * 255.))
- : kMinDistortion_dB);
- }
- // Accumulate forward
- if (c < 4) VP8SSIMAddStats(&stats[c], &stats[4]);
- }
- return 1;
}
//------------------------------------------------------------------------------
@@ -1000,7 +253,7 @@ static size_t Encode(const uint8_t* rgba, int width, int height, int stride,
ok = import(&pic, rgba, stride) && WebPEncode(&config, &pic);
WebPPictureFree(&pic);
if (!ok) {
- free(wrt.mem);
+ WebPMemoryWriterClear(&wrt);
*output = NULL;
return 0;
}
@@ -1014,10 +267,10 @@ size_t NAME(const uint8_t* in, int w, int h, int bps, float q, \
return Encode(in, w, h, bps, IMPORTER, q, 0, out); \
}
-ENCODE_FUNC(WebPEncodeRGB, WebPPictureImportRGB);
-ENCODE_FUNC(WebPEncodeBGR, WebPPictureImportBGR);
-ENCODE_FUNC(WebPEncodeRGBA, WebPPictureImportRGBA);
-ENCODE_FUNC(WebPEncodeBGRA, WebPPictureImportBGRA);
+ENCODE_FUNC(WebPEncodeRGB, WebPPictureImportRGB)
+ENCODE_FUNC(WebPEncodeBGR, WebPPictureImportBGR)
+ENCODE_FUNC(WebPEncodeRGBA, WebPPictureImportRGBA)
+ENCODE_FUNC(WebPEncodeBGRA, WebPPictureImportBGRA)
#undef ENCODE_FUNC
@@ -1027,15 +280,11 @@ size_t NAME(const uint8_t* in, int w, int h, int bps, uint8_t** out) { \
return Encode(in, w, h, bps, IMPORTER, LOSSLESS_DEFAULT_QUALITY, 1, out); \
}
-LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessRGB, WebPPictureImportRGB);
-LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGR, WebPPictureImportBGR);
-LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessRGBA, WebPPictureImportRGBA);
-LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGRA, WebPPictureImportBGRA);
+LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessRGB, WebPPictureImportRGB)
+LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGR, WebPPictureImportBGR)
+LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessRGBA, WebPPictureImportRGBA)
+LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGRA, WebPPictureImportBGRA)
#undef LOSSLESS_ENCODE_FUNC
//------------------------------------------------------------------------------
-
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/enc/picture_csp.c b/drivers/webp/enc/picture_csp.c
new file mode 100644
index 0000000000..0ef5f9eee2
--- /dev/null
+++ b/drivers/webp/enc/picture_csp.c
@@ -0,0 +1,1156 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// WebPPicture utils for colorspace conversion
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <assert.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "./vp8enci.h"
+#include "../utils/random.h"
+#include "../utils/utils.h"
+#include "../dsp/yuv.h"
+
+// Uncomment to disable gamma-compression during RGB->U/V averaging
+#define USE_GAMMA_COMPRESSION
+
+// If defined, use table to compute x / alpha.
+#define USE_INVERSE_ALPHA_TABLE
+
+static const union {
+ uint32_t argb;
+ uint8_t bytes[4];
+} test_endian = { 0xff000000u };
+#define ALPHA_IS_LAST (test_endian.bytes[3] == 0xff)
+
+//------------------------------------------------------------------------------
+// Detection of non-trivial transparency
+
+// Returns true if alpha[] has non-0xff values.
+static int CheckNonOpaque(const uint8_t* alpha, int width, int height,
+ int x_step, int y_step) {
+ if (alpha == NULL) return 0;
+ while (height-- > 0) {
+ int x;
+ for (x = 0; x < width * x_step; x += x_step) {
+ if (alpha[x] != 0xff) return 1; // TODO(skal): check 4/8 bytes at a time.
+ }
+ alpha += y_step;
+ }
+ return 0;
+}
+
+// Checking for the presence of non-opaque alpha.
+int WebPPictureHasTransparency(const WebPPicture* picture) {
+ if (picture == NULL) return 0;
+ if (!picture->use_argb) {
+ return CheckNonOpaque(picture->a, picture->width, picture->height,
+ 1, picture->a_stride);
+ } else {
+ int x, y;
+ const uint32_t* argb = picture->argb;
+ if (argb == NULL) return 0;
+ for (y = 0; y < picture->height; ++y) {
+ for (x = 0; x < picture->width; ++x) {
+ if (argb[x] < 0xff000000u) return 1; // test any alpha values != 0xff
+ }
+ argb += picture->argb_stride;
+ }
+ }
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+// Code for gamma correction
+
+#if defined(USE_GAMMA_COMPRESSION)
+
+// gamma-compensates loss of resolution during chroma subsampling
+#define kGamma 0.80 // for now we use a different gamma value than kGammaF
+#define kGammaFix 12 // fixed-point precision for linear values
+#define kGammaScale ((1 << kGammaFix) - 1)
+#define kGammaTabFix 7 // fixed-point fractional bits precision
+#define kGammaTabScale (1 << kGammaTabFix)
+#define kGammaTabRounder (kGammaTabScale >> 1)
+#define kGammaTabSize (1 << (kGammaFix - kGammaTabFix))
+
+static int kLinearToGammaTab[kGammaTabSize + 1];
+static uint16_t kGammaToLinearTab[256];
+static volatile int kGammaTablesOk = 0;
+
+static WEBP_TSAN_IGNORE_FUNCTION void InitGammaTables(void) {
+ if (!kGammaTablesOk) {
+ int v;
+ const double scale = (double)(1 << kGammaTabFix) / kGammaScale;
+ const double norm = 1. / 255.;
+ for (v = 0; v <= 255; ++v) {
+ kGammaToLinearTab[v] =
+ (uint16_t)(pow(norm * v, kGamma) * kGammaScale + .5);
+ }
+ for (v = 0; v <= kGammaTabSize; ++v) {
+ kLinearToGammaTab[v] = (int)(255. * pow(scale * v, 1. / kGamma) + .5);
+ }
+ kGammaTablesOk = 1;
+ }
+}
+
+static WEBP_INLINE uint32_t GammaToLinear(uint8_t v) {
+ return kGammaToLinearTab[v];
+}
+
+static WEBP_INLINE int Interpolate(int v) {
+ const int tab_pos = v >> (kGammaTabFix + 2); // integer part
+ const int x = v & ((kGammaTabScale << 2) - 1); // fractional part
+ const int v0 = kLinearToGammaTab[tab_pos];
+ const int v1 = kLinearToGammaTab[tab_pos + 1];
+ const int y = v1 * x + v0 * ((kGammaTabScale << 2) - x); // interpolate
+ assert(tab_pos + 1 < kGammaTabSize + 1);
+ return y;
+}
+
+// Convert a linear value 'v' to YUV_FIX+2 fixed-point precision
+// U/V value, suitable for RGBToU/V calls.
+static WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) {
+ const int y = Interpolate(base_value << shift); // final uplifted value
+ return (y + kGammaTabRounder) >> kGammaTabFix; // descale
+}
+
+#else
+
+static WEBP_TSAN_IGNORE_FUNCTION void InitGammaTables(void) {}
+static WEBP_INLINE uint32_t GammaToLinear(uint8_t v) { return v; }
+static WEBP_INLINE int LinearToGamma(uint32_t base_value, int shift) {
+ return (int)(base_value << shift);
+}
+
+#endif // USE_GAMMA_COMPRESSION
+
+//------------------------------------------------------------------------------
+// RGB -> YUV conversion
+
+static int RGBToY(int r, int g, int b, VP8Random* const rg) {
+ return (rg == NULL) ? VP8RGBToY(r, g, b, YUV_HALF)
+ : VP8RGBToY(r, g, b, VP8RandomBits(rg, YUV_FIX));
+}
+
+static int RGBToU(int r, int g, int b, VP8Random* const rg) {
+ return (rg == NULL) ? VP8RGBToU(r, g, b, YUV_HALF << 2)
+ : VP8RGBToU(r, g, b, VP8RandomBits(rg, YUV_FIX + 2));
+}
+
+static int RGBToV(int r, int g, int b, VP8Random* const rg) {
+ return (rg == NULL) ? VP8RGBToV(r, g, b, YUV_HALF << 2)
+ : VP8RGBToV(r, g, b, VP8RandomBits(rg, YUV_FIX + 2));
+}
+
+//------------------------------------------------------------------------------
+// Smart RGB->YUV conversion
+
+static const int kNumIterations = 6;
+static const int kMinDimensionIterativeConversion = 4;
+
+// We could use SFIX=0 and only uint8_t for fixed_y_t, but it produces some
+// banding sometimes. Better use extra precision.
+#define SFIX 2 // fixed-point precision of RGB and Y/W
+typedef int16_t fixed_t; // signed type with extra SFIX precision for UV
+typedef uint16_t fixed_y_t; // unsigned type with extra SFIX precision for W
+
+#define SHALF (1 << SFIX >> 1)
+#define MAX_Y_T ((256 << SFIX) - 1)
+#define SROUNDER (1 << (YUV_FIX + SFIX - 1))
+
+#if defined(USE_GAMMA_COMPRESSION)
+
+// float variant of gamma-correction
+// We use tables of different size and precision, along with a 'real-world'
+// Gamma value close to ~2.
+#define kGammaF 2.2
+static float kGammaToLinearTabF[MAX_Y_T + 1]; // size scales with Y_FIX
+static float kLinearToGammaTabF[kGammaTabSize + 2];
+static volatile int kGammaTablesFOk = 0;
+
+static WEBP_TSAN_IGNORE_FUNCTION void InitGammaTablesF(void) {
+ if (!kGammaTablesFOk) {
+ int v;
+ const double norm = 1. / MAX_Y_T;
+ const double scale = 1. / kGammaTabSize;
+ for (v = 0; v <= MAX_Y_T; ++v) {
+ kGammaToLinearTabF[v] = (float)pow(norm * v, kGammaF);
+ }
+ for (v = 0; v <= kGammaTabSize; ++v) {
+ kLinearToGammaTabF[v] = (float)(MAX_Y_T * pow(scale * v, 1. / kGammaF));
+ }
+ // to prevent small rounding errors to cause read-overflow:
+ kLinearToGammaTabF[kGammaTabSize + 1] = kLinearToGammaTabF[kGammaTabSize];
+ kGammaTablesFOk = 1;
+ }
+}
+
+static WEBP_INLINE float GammaToLinearF(int v) {
+ return kGammaToLinearTabF[v];
+}
+
+static WEBP_INLINE int LinearToGammaF(float value) {
+ const float v = value * kGammaTabSize;
+ const int tab_pos = (int)v;
+ const float x = v - (float)tab_pos; // fractional part
+ const float v0 = kLinearToGammaTabF[tab_pos + 0];
+ const float v1 = kLinearToGammaTabF[tab_pos + 1];
+ const float y = v1 * x + v0 * (1.f - x); // interpolate
+ return (int)(y + .5);
+}
+
+#else
+
+static WEBP_TSAN_IGNORE_FUNCTION void InitGammaTablesF(void) {}
+static WEBP_INLINE float GammaToLinearF(int v) {
+ const float norm = 1.f / MAX_Y_T;
+ return norm * v;
+}
+static WEBP_INLINE int LinearToGammaF(float value) {
+ return (int)(MAX_Y_T * value + .5);
+}
+
+#endif // USE_GAMMA_COMPRESSION
+
+//------------------------------------------------------------------------------
+
+static uint8_t clip_8b(fixed_t v) {
+ return (!(v & ~0xff)) ? (uint8_t)v : (v < 0) ? 0u : 255u;
+}
+
+static fixed_y_t clip_y(int y) {
+ return (!(y & ~MAX_Y_T)) ? (fixed_y_t)y : (y < 0) ? 0 : MAX_Y_T;
+}
+
+//------------------------------------------------------------------------------
+
+static int RGBToGray(int r, int g, int b) {
+ const int luma = 19595 * r + 38470 * g + 7471 * b + YUV_HALF;
+ return (luma >> YUV_FIX);
+}
+
+static float RGBToGrayF(float r, float g, float b) {
+ return 0.299f * r + 0.587f * g + 0.114f * b;
+}
+
+static int ScaleDown(int a, int b, int c, int d) {
+ const float A = GammaToLinearF(a);
+ const float B = GammaToLinearF(b);
+ const float C = GammaToLinearF(c);
+ const float D = GammaToLinearF(d);
+ return LinearToGammaF(0.25f * (A + B + C + D));
+}
+
+static WEBP_INLINE void UpdateW(const fixed_y_t* src, fixed_y_t* dst, int len) {
+ while (len-- > 0) {
+ const float R = GammaToLinearF(src[0]);
+ const float G = GammaToLinearF(src[1]);
+ const float B = GammaToLinearF(src[2]);
+ const float Y = RGBToGrayF(R, G, B);
+ *dst++ = (fixed_y_t)LinearToGammaF(Y);
+ src += 3;
+ }
+}
+
+static int UpdateChroma(const fixed_y_t* src1,
+ const fixed_y_t* src2,
+ fixed_t* dst, fixed_y_t* tmp, int len) {
+ int diff = 0;
+ while (len--> 0) {
+ const int r = ScaleDown(src1[0], src1[3], src2[0], src2[3]);
+ const int g = ScaleDown(src1[1], src1[4], src2[1], src2[4]);
+ const int b = ScaleDown(src1[2], src1[5], src2[2], src2[5]);
+ const int W = RGBToGray(r, g, b);
+ const int r_avg = (src1[0] + src1[3] + src2[0] + src2[3] + 2) >> 2;
+ const int g_avg = (src1[1] + src1[4] + src2[1] + src2[4] + 2) >> 2;
+ const int b_avg = (src1[2] + src1[5] + src2[2] + src2[5] + 2) >> 2;
+ dst[0] = (fixed_t)(r - W);
+ dst[1] = (fixed_t)(g - W);
+ dst[2] = (fixed_t)(b - W);
+ dst += 3;
+ src1 += 6;
+ src2 += 6;
+ if (tmp != NULL) {
+ tmp[0] = tmp[1] = clip_y(W);
+ tmp += 2;
+ }
+ diff += abs(RGBToGray(r_avg, g_avg, b_avg) - W);
+ }
+ return diff;
+}
+
+//------------------------------------------------------------------------------
+
+static WEBP_INLINE int Filter(const fixed_t* const A, const fixed_t* const B,
+ int rightwise) {
+ int v;
+ if (!rightwise) {
+ v = (A[0] * 9 + A[-3] * 3 + B[0] * 3 + B[-3]);
+ } else {
+ v = (A[0] * 9 + A[+3] * 3 + B[0] * 3 + B[+3]);
+ }
+ return (v + 8) >> 4;
+}
+
+static WEBP_INLINE int Filter2(int A, int B) { return (A * 3 + B + 2) >> 2; }
+
+//------------------------------------------------------------------------------
+
+static WEBP_INLINE fixed_y_t UpLift(uint8_t a) { // 8bit -> SFIX
+ return ((fixed_y_t)a << SFIX) | SHALF;
+}
+
+static void ImportOneRow(const uint8_t* const r_ptr,
+ const uint8_t* const g_ptr,
+ const uint8_t* const b_ptr,
+ int step,
+ int pic_width,
+ fixed_y_t* const dst) {
+ int i;
+ for (i = 0; i < pic_width; ++i) {
+ const int off = i * step;
+ dst[3 * i + 0] = UpLift(r_ptr[off]);
+ dst[3 * i + 1] = UpLift(g_ptr[off]);
+ dst[3 * i + 2] = UpLift(b_ptr[off]);
+ }
+ if (pic_width & 1) { // replicate rightmost pixel
+ memcpy(dst + 3 * pic_width, dst + 3 * (pic_width - 1), 3 * sizeof(*dst));
+ }
+}
+
+static void InterpolateTwoRows(const fixed_y_t* const best_y,
+ const fixed_t* const prev_uv,
+ const fixed_t* const cur_uv,
+ const fixed_t* const next_uv,
+ int w,
+ fixed_y_t* const out1,
+ fixed_y_t* const out2) {
+ int i, k;
+ { // special boundary case for i==0
+ const int W0 = best_y[0];
+ const int W1 = best_y[w];
+ for (k = 0; k <= 2; ++k) {
+ out1[k] = clip_y(Filter2(cur_uv[k], prev_uv[k]) + W0);
+ out2[k] = clip_y(Filter2(cur_uv[k], next_uv[k]) + W1);
+ }
+ }
+ for (i = 1; i < w - 1; ++i) {
+ const int W0 = best_y[i + 0];
+ const int W1 = best_y[i + w];
+ const int off = 3 * (i >> 1);
+ for (k = 0; k <= 2; ++k) {
+ const int tmp0 = Filter(cur_uv + off + k, prev_uv + off + k, i & 1);
+ const int tmp1 = Filter(cur_uv + off + k, next_uv + off + k, i & 1);
+ out1[3 * i + k] = clip_y(tmp0 + W0);
+ out2[3 * i + k] = clip_y(tmp1 + W1);
+ }
+ }
+ { // special boundary case for i == w - 1
+ const int W0 = best_y[i + 0];
+ const int W1 = best_y[i + w];
+ const int off = 3 * (i >> 1);
+ for (k = 0; k <= 2; ++k) {
+ out1[3 * i + k] = clip_y(Filter2(cur_uv[off + k], prev_uv[off + k]) + W0);
+ out2[3 * i + k] = clip_y(Filter2(cur_uv[off + k], next_uv[off + k]) + W1);
+ }
+ }
+}
+
+static WEBP_INLINE uint8_t ConvertRGBToY(int r, int g, int b) {
+ const int luma = 16839 * r + 33059 * g + 6420 * b + SROUNDER;
+ return clip_8b(16 + (luma >> (YUV_FIX + SFIX)));
+}
+
+static WEBP_INLINE uint8_t ConvertRGBToU(int r, int g, int b) {
+ const int u = -9719 * r - 19081 * g + 28800 * b + SROUNDER;
+ return clip_8b(128 + (u >> (YUV_FIX + SFIX)));
+}
+
+static WEBP_INLINE uint8_t ConvertRGBToV(int r, int g, int b) {
+ const int v = +28800 * r - 24116 * g - 4684 * b + SROUNDER;
+ return clip_8b(128 + (v >> (YUV_FIX + SFIX)));
+}
+
+static int ConvertWRGBToYUV(const fixed_y_t* const best_y,
+ const fixed_t* const best_uv,
+ WebPPicture* const picture) {
+ int i, j;
+ const int w = (picture->width + 1) & ~1;
+ const int h = (picture->height + 1) & ~1;
+ const int uv_w = w >> 1;
+ const int uv_h = h >> 1;
+ for (j = 0; j < picture->height; ++j) {
+ for (i = 0; i < picture->width; ++i) {
+ const int off = 3 * ((i >> 1) + (j >> 1) * uv_w);
+ const int off2 = i + j * picture->y_stride;
+ const int W = best_y[i + j * w];
+ const int r = best_uv[off + 0] + W;
+ const int g = best_uv[off + 1] + W;
+ const int b = best_uv[off + 2] + W;
+ picture->y[off2] = ConvertRGBToY(r, g, b);
+ }
+ }
+ for (j = 0; j < uv_h; ++j) {
+ uint8_t* const dst_u = picture->u + j * picture->uv_stride;
+ uint8_t* const dst_v = picture->v + j * picture->uv_stride;
+ for (i = 0; i < uv_w; ++i) {
+ const int off = 3 * (i + j * uv_w);
+ const int r = best_uv[off + 0];
+ const int g = best_uv[off + 1];
+ const int b = best_uv[off + 2];
+ dst_u[i] = ConvertRGBToU(r, g, b);
+ dst_v[i] = ConvertRGBToV(r, g, b);
+ }
+ }
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+// Main function
+
+#define SAFE_ALLOC(W, H, T) ((T*)WebPSafeMalloc((W) * (H), sizeof(T)))
+
+static int PreprocessARGB(const uint8_t* const r_ptr,
+ const uint8_t* const g_ptr,
+ const uint8_t* const b_ptr,
+ int step, int rgb_stride,
+ WebPPicture* const picture) {
+ // we expand the right/bottom border if needed
+ const int w = (picture->width + 1) & ~1;
+ const int h = (picture->height + 1) & ~1;
+ const int uv_w = w >> 1;
+ const int uv_h = h >> 1;
+ int i, j, iter;
+
+ // TODO(skal): allocate one big memory chunk. But for now, it's easier
+ // for valgrind debugging to have several chunks.
+ fixed_y_t* const tmp_buffer = SAFE_ALLOC(w * 3, 2, fixed_y_t); // scratch
+ fixed_y_t* const best_y = SAFE_ALLOC(w, h, fixed_y_t);
+ fixed_y_t* const target_y = SAFE_ALLOC(w, h, fixed_y_t);
+ fixed_y_t* const best_rgb_y = SAFE_ALLOC(w, 2, fixed_y_t);
+ fixed_t* const best_uv = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
+ fixed_t* const target_uv = SAFE_ALLOC(uv_w * 3, uv_h, fixed_t);
+ fixed_t* const best_rgb_uv = SAFE_ALLOC(uv_w * 3, 1, fixed_t);
+ int ok;
+ int diff_sum = 0;
+ const int first_diff_threshold = (int)(2.5 * w * h);
+ const int min_improvement = 5; // stop if improvement is below this %
+ const int min_first_improvement = 80;
+
+ if (best_y == NULL || best_uv == NULL ||
+ target_y == NULL || target_uv == NULL ||
+ best_rgb_y == NULL || best_rgb_uv == NULL ||
+ tmp_buffer == NULL) {
+ ok = WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ goto End;
+ }
+ assert(picture->width >= kMinDimensionIterativeConversion);
+ assert(picture->height >= kMinDimensionIterativeConversion);
+
+ // Import RGB samples to W/RGB representation.
+ for (j = 0; j < picture->height; j += 2) {
+ const int is_last_row = (j == picture->height - 1);
+ fixed_y_t* const src1 = tmp_buffer;
+ fixed_y_t* const src2 = tmp_buffer + 3 * w;
+ const int off1 = j * rgb_stride;
+ const int off2 = off1 + rgb_stride;
+ const int uv_off = (j >> 1) * 3 * uv_w;
+ fixed_y_t* const dst_y = best_y + j * w;
+
+ // prepare two rows of input
+ ImportOneRow(r_ptr + off1, g_ptr + off1, b_ptr + off1,
+ step, picture->width, src1);
+ if (!is_last_row) {
+ ImportOneRow(r_ptr + off2, g_ptr + off2, b_ptr + off2,
+ step, picture->width, src2);
+ } else {
+ memcpy(src2, src1, 3 * w * sizeof(*src2));
+ }
+ UpdateW(src1, target_y + (j + 0) * w, w);
+ UpdateW(src2, target_y + (j + 1) * w, w);
+ diff_sum += UpdateChroma(src1, src2, target_uv + uv_off, dst_y, uv_w);
+ memcpy(best_uv + uv_off, target_uv + uv_off, 3 * uv_w * sizeof(*best_uv));
+ memcpy(dst_y + w, dst_y, w * sizeof(*dst_y));
+ }
+
+ // Iterate and resolve clipping conflicts.
+ for (iter = 0; iter < kNumIterations; ++iter) {
+ int k;
+ const fixed_t* cur_uv = best_uv;
+ const fixed_t* prev_uv = best_uv;
+ const int old_diff_sum = diff_sum;
+ diff_sum = 0;
+ for (j = 0; j < h; j += 2) {
+ fixed_y_t* const src1 = tmp_buffer;
+ fixed_y_t* const src2 = tmp_buffer + 3 * w;
+ {
+ const fixed_t* const next_uv = cur_uv + ((j < h - 2) ? 3 * uv_w : 0);
+ InterpolateTwoRows(best_y + j * w, prev_uv, cur_uv, next_uv,
+ w, src1, src2);
+ prev_uv = cur_uv;
+ cur_uv = next_uv;
+ }
+
+ UpdateW(src1, best_rgb_y + 0 * w, w);
+ UpdateW(src2, best_rgb_y + 1 * w, w);
+ diff_sum += UpdateChroma(src1, src2, best_rgb_uv, NULL, uv_w);
+
+ // update two rows of Y and one row of RGB
+ for (i = 0; i < 2 * w; ++i) {
+ const int off = i + j * w;
+ const int diff_y = target_y[off] - best_rgb_y[i];
+ const int new_y = (int)best_y[off] + diff_y;
+ best_y[off] = clip_y(new_y);
+ }
+ for (i = 0; i < uv_w; ++i) {
+ const int off = 3 * (i + (j >> 1) * uv_w);
+ int W;
+ for (k = 0; k <= 2; ++k) {
+ const int diff_uv = (int)target_uv[off + k] - best_rgb_uv[3 * i + k];
+ best_uv[off + k] += diff_uv;
+ }
+ W = RGBToGray(best_uv[off + 0], best_uv[off + 1], best_uv[off + 2]);
+ for (k = 0; k <= 2; ++k) {
+ best_uv[off + k] -= W;
+ }
+ }
+ }
+ // test exit condition
+ if (diff_sum > 0) {
+ const int improvement = 100 * abs(diff_sum - old_diff_sum) / diff_sum;
+ // Check if first iteration gave good result already, without a large
+ // jump of improvement (otherwise it means we need to try few extra
+ // iterations, just to be sure).
+ if (iter == 0 && diff_sum < first_diff_threshold &&
+ improvement < min_first_improvement) {
+ break;
+ }
+ // then, check if improvement is stalling.
+ if (improvement < min_improvement) {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+ // final reconstruction
+ ok = ConvertWRGBToYUV(best_y, best_uv, picture);
+
+ End:
+ WebPSafeFree(best_y);
+ WebPSafeFree(best_uv);
+ WebPSafeFree(target_y);
+ WebPSafeFree(target_uv);
+ WebPSafeFree(best_rgb_y);
+ WebPSafeFree(best_rgb_uv);
+ WebPSafeFree(tmp_buffer);
+ return ok;
+}
+#undef SAFE_ALLOC
+
+//------------------------------------------------------------------------------
+// "Fast" regular RGB->YUV
+
+#define SUM4(ptr, step) LinearToGamma( \
+ GammaToLinear((ptr)[0]) + \
+ GammaToLinear((ptr)[(step)]) + \
+ GammaToLinear((ptr)[rgb_stride]) + \
+ GammaToLinear((ptr)[rgb_stride + (step)]), 0) \
+
+#define SUM2(ptr) \
+ LinearToGamma(GammaToLinear((ptr)[0]) + GammaToLinear((ptr)[rgb_stride]), 1)
+
+#define SUM2ALPHA(ptr) ((ptr)[0] + (ptr)[rgb_stride])
+#define SUM4ALPHA(ptr) (SUM2ALPHA(ptr) + SUM2ALPHA((ptr) + 4))
+
+#if defined(USE_INVERSE_ALPHA_TABLE)
+
+static const int kAlphaFix = 19;
+// Following table is (1 << kAlphaFix) / a. The (v * kInvAlpha[a]) >> kAlphaFix
+// formula is then equal to v / a in most (99.6%) cases. Note that this table
+// and constant are adjusted very tightly to fit 32b arithmetic.
+// In particular, they use the fact that the operands for 'v / a' are actually
+// derived as v = (a0.p0 + a1.p1 + a2.p2 + a3.p3) and a = a0 + a1 + a2 + a3
+// with ai in [0..255] and pi in [0..1<<kGammaFix). The constraint to avoid
+// overflow is: kGammaFix + kAlphaFix <= 31.
+static const uint32_t kInvAlpha[4 * 0xff + 1] = {
+ 0, /* alpha = 0 */
+ 524288, 262144, 174762, 131072, 104857, 87381, 74898, 65536,
+ 58254, 52428, 47662, 43690, 40329, 37449, 34952, 32768,
+ 30840, 29127, 27594, 26214, 24966, 23831, 22795, 21845,
+ 20971, 20164, 19418, 18724, 18078, 17476, 16912, 16384,
+ 15887, 15420, 14979, 14563, 14169, 13797, 13443, 13107,
+ 12787, 12483, 12192, 11915, 11650, 11397, 11155, 10922,
+ 10699, 10485, 10280, 10082, 9892, 9709, 9532, 9362,
+ 9198, 9039, 8886, 8738, 8594, 8456, 8322, 8192,
+ 8065, 7943, 7825, 7710, 7598, 7489, 7384, 7281,
+ 7182, 7084, 6990, 6898, 6808, 6721, 6636, 6553,
+ 6472, 6393, 6316, 6241, 6168, 6096, 6026, 5957,
+ 5890, 5825, 5761, 5698, 5637, 5577, 5518, 5461,
+ 5405, 5349, 5295, 5242, 5190, 5140, 5090, 5041,
+ 4993, 4946, 4899, 4854, 4809, 4766, 4723, 4681,
+ 4639, 4599, 4559, 4519, 4481, 4443, 4405, 4369,
+ 4332, 4297, 4262, 4228, 4194, 4161, 4128, 4096,
+ 4064, 4032, 4002, 3971, 3942, 3912, 3883, 3855,
+ 3826, 3799, 3771, 3744, 3718, 3692, 3666, 3640,
+ 3615, 3591, 3566, 3542, 3518, 3495, 3472, 3449,
+ 3426, 3404, 3382, 3360, 3339, 3318, 3297, 3276,
+ 3256, 3236, 3216, 3196, 3177, 3158, 3139, 3120,
+ 3102, 3084, 3066, 3048, 3030, 3013, 2995, 2978,
+ 2962, 2945, 2928, 2912, 2896, 2880, 2864, 2849,
+ 2833, 2818, 2803, 2788, 2774, 2759, 2744, 2730,
+ 2716, 2702, 2688, 2674, 2661, 2647, 2634, 2621,
+ 2608, 2595, 2582, 2570, 2557, 2545, 2532, 2520,
+ 2508, 2496, 2484, 2473, 2461, 2449, 2438, 2427,
+ 2416, 2404, 2394, 2383, 2372, 2361, 2351, 2340,
+ 2330, 2319, 2309, 2299, 2289, 2279, 2269, 2259,
+ 2250, 2240, 2231, 2221, 2212, 2202, 2193, 2184,
+ 2175, 2166, 2157, 2148, 2139, 2131, 2122, 2114,
+ 2105, 2097, 2088, 2080, 2072, 2064, 2056, 2048,
+ 2040, 2032, 2024, 2016, 2008, 2001, 1993, 1985,
+ 1978, 1971, 1963, 1956, 1949, 1941, 1934, 1927,
+ 1920, 1913, 1906, 1899, 1892, 1885, 1879, 1872,
+ 1865, 1859, 1852, 1846, 1839, 1833, 1826, 1820,
+ 1814, 1807, 1801, 1795, 1789, 1783, 1777, 1771,
+ 1765, 1759, 1753, 1747, 1741, 1736, 1730, 1724,
+ 1718, 1713, 1707, 1702, 1696, 1691, 1685, 1680,
+ 1675, 1669, 1664, 1659, 1653, 1648, 1643, 1638,
+ 1633, 1628, 1623, 1618, 1613, 1608, 1603, 1598,
+ 1593, 1588, 1583, 1579, 1574, 1569, 1565, 1560,
+ 1555, 1551, 1546, 1542, 1537, 1533, 1528, 1524,
+ 1519, 1515, 1510, 1506, 1502, 1497, 1493, 1489,
+ 1485, 1481, 1476, 1472, 1468, 1464, 1460, 1456,
+ 1452, 1448, 1444, 1440, 1436, 1432, 1428, 1424,
+ 1420, 1416, 1413, 1409, 1405, 1401, 1398, 1394,
+ 1390, 1387, 1383, 1379, 1376, 1372, 1368, 1365,
+ 1361, 1358, 1354, 1351, 1347, 1344, 1340, 1337,
+ 1334, 1330, 1327, 1323, 1320, 1317, 1314, 1310,
+ 1307, 1304, 1300, 1297, 1294, 1291, 1288, 1285,
+ 1281, 1278, 1275, 1272, 1269, 1266, 1263, 1260,
+ 1257, 1254, 1251, 1248, 1245, 1242, 1239, 1236,
+ 1233, 1230, 1227, 1224, 1222, 1219, 1216, 1213,
+ 1210, 1208, 1205, 1202, 1199, 1197, 1194, 1191,
+ 1188, 1186, 1183, 1180, 1178, 1175, 1172, 1170,
+ 1167, 1165, 1162, 1159, 1157, 1154, 1152, 1149,
+ 1147, 1144, 1142, 1139, 1137, 1134, 1132, 1129,
+ 1127, 1125, 1122, 1120, 1117, 1115, 1113, 1110,
+ 1108, 1106, 1103, 1101, 1099, 1096, 1094, 1092,
+ 1089, 1087, 1085, 1083, 1081, 1078, 1076, 1074,
+ 1072, 1069, 1067, 1065, 1063, 1061, 1059, 1057,
+ 1054, 1052, 1050, 1048, 1046, 1044, 1042, 1040,
+ 1038, 1036, 1034, 1032, 1030, 1028, 1026, 1024,
+ 1022, 1020, 1018, 1016, 1014, 1012, 1010, 1008,
+ 1006, 1004, 1002, 1000, 998, 996, 994, 992,
+ 991, 989, 987, 985, 983, 981, 979, 978,
+ 976, 974, 972, 970, 969, 967, 965, 963,
+ 961, 960, 958, 956, 954, 953, 951, 949,
+ 948, 946, 944, 942, 941, 939, 937, 936,
+ 934, 932, 931, 929, 927, 926, 924, 923,
+ 921, 919, 918, 916, 914, 913, 911, 910,
+ 908, 907, 905, 903, 902, 900, 899, 897,
+ 896, 894, 893, 891, 890, 888, 887, 885,
+ 884, 882, 881, 879, 878, 876, 875, 873,
+ 872, 870, 869, 868, 866, 865, 863, 862,
+ 860, 859, 858, 856, 855, 853, 852, 851,
+ 849, 848, 846, 845, 844, 842, 841, 840,
+ 838, 837, 836, 834, 833, 832, 830, 829,
+ 828, 826, 825, 824, 823, 821, 820, 819,
+ 817, 816, 815, 814, 812, 811, 810, 809,
+ 807, 806, 805, 804, 802, 801, 800, 799,
+ 798, 796, 795, 794, 793, 791, 790, 789,
+ 788, 787, 786, 784, 783, 782, 781, 780,
+ 779, 777, 776, 775, 774, 773, 772, 771,
+ 769, 768, 767, 766, 765, 764, 763, 762,
+ 760, 759, 758, 757, 756, 755, 754, 753,
+ 752, 751, 750, 748, 747, 746, 745, 744,
+ 743, 742, 741, 740, 739, 738, 737, 736,
+ 735, 734, 733, 732, 731, 730, 729, 728,
+ 727, 726, 725, 724, 723, 722, 721, 720,
+ 719, 718, 717, 716, 715, 714, 713, 712,
+ 711, 710, 709, 708, 707, 706, 705, 704,
+ 703, 702, 701, 700, 699, 699, 698, 697,
+ 696, 695, 694, 693, 692, 691, 690, 689,
+ 688, 688, 687, 686, 685, 684, 683, 682,
+ 681, 680, 680, 679, 678, 677, 676, 675,
+ 674, 673, 673, 672, 671, 670, 669, 668,
+ 667, 667, 666, 665, 664, 663, 662, 661,
+ 661, 660, 659, 658, 657, 657, 656, 655,
+ 654, 653, 652, 652, 651, 650, 649, 648,
+ 648, 647, 646, 645, 644, 644, 643, 642,
+ 641, 640, 640, 639, 638, 637, 637, 636,
+ 635, 634, 633, 633, 632, 631, 630, 630,
+ 629, 628, 627, 627, 626, 625, 624, 624,
+ 623, 622, 621, 621, 620, 619, 618, 618,
+ 617, 616, 616, 615, 614, 613, 613, 612,
+ 611, 611, 610, 609, 608, 608, 607, 606,
+ 606, 605, 604, 604, 603, 602, 601, 601,
+ 600, 599, 599, 598, 597, 597, 596, 595,
+ 595, 594, 593, 593, 592, 591, 591, 590,
+ 589, 589, 588, 587, 587, 586, 585, 585,
+ 584, 583, 583, 582, 581, 581, 580, 579,
+ 579, 578, 578, 577, 576, 576, 575, 574,
+ 574, 573, 572, 572, 571, 571, 570, 569,
+ 569, 568, 568, 567, 566, 566, 565, 564,
+ 564, 563, 563, 562, 561, 561, 560, 560,
+ 559, 558, 558, 557, 557, 556, 555, 555,
+ 554, 554, 553, 553, 552, 551, 551, 550,
+ 550, 549, 548, 548, 547, 547, 546, 546,
+ 545, 544, 544, 543, 543, 542, 542, 541,
+ 541, 540, 539, 539, 538, 538, 537, 537,
+ 536, 536, 535, 534, 534, 533, 533, 532,
+ 532, 531, 531, 530, 530, 529, 529, 528,
+ 527, 527, 526, 526, 525, 525, 524, 524,
+ 523, 523, 522, 522, 521, 521, 520, 520,
+ 519, 519, 518, 518, 517, 517, 516, 516,
+ 515, 515, 514, 514
+};
+
+// Note that LinearToGamma() expects the values to be premultiplied by 4,
+// so we incorporate this factor 4 inside the DIVIDE_BY_ALPHA macro directly.
+#define DIVIDE_BY_ALPHA(sum, a) (((sum) * kInvAlpha[(a)]) >> (kAlphaFix - 2))
+
+#else
+
+#define DIVIDE_BY_ALPHA(sum, a) (4 * (sum) / (a))
+
+#endif // USE_INVERSE_ALPHA_TABLE
+
+static WEBP_INLINE int LinearToGammaWeighted(const uint8_t* src,
+ const uint8_t* a_ptr,
+ uint32_t total_a, int step,
+ int rgb_stride) {
+ const uint32_t sum =
+ a_ptr[0] * GammaToLinear(src[0]) +
+ a_ptr[step] * GammaToLinear(src[step]) +
+ a_ptr[rgb_stride] * GammaToLinear(src[rgb_stride]) +
+ a_ptr[rgb_stride + step] * GammaToLinear(src[rgb_stride + step]);
+ assert(total_a > 0 && total_a <= 4 * 0xff);
+#if defined(USE_INVERSE_ALPHA_TABLE)
+ assert((uint64_t)sum * kInvAlpha[total_a] < ((uint64_t)1 << 32));
+#endif
+ return LinearToGamma(DIVIDE_BY_ALPHA(sum, total_a), 0);
+}
+
+static WEBP_INLINE void ConvertRowToY(const uint8_t* const r_ptr,
+ const uint8_t* const g_ptr,
+ const uint8_t* const b_ptr,
+ int step,
+ uint8_t* const dst_y,
+ int width,
+ VP8Random* const rg) {
+ int i, j;
+ for (i = 0, j = 0; i < width; i += 1, j += step) {
+ dst_y[i] = RGBToY(r_ptr[j], g_ptr[j], b_ptr[j], rg);
+ }
+}
+
+static WEBP_INLINE void AccumulateRGBA(const uint8_t* const r_ptr,
+ const uint8_t* const g_ptr,
+ const uint8_t* const b_ptr,
+ const uint8_t* const a_ptr,
+ int rgb_stride,
+ uint16_t* dst, int width) {
+ int i, j;
+ // we loop over 2x2 blocks and produce one R/G/B/A value for each.
+ for (i = 0, j = 0; i < (width >> 1); i += 1, j += 2 * 4, dst += 4) {
+ const uint32_t a = SUM4ALPHA(a_ptr + j);
+ int r, g, b;
+ if (a == 4 * 0xff || a == 0) {
+ r = SUM4(r_ptr + j, 4);
+ g = SUM4(g_ptr + j, 4);
+ b = SUM4(b_ptr + j, 4);
+ } else {
+ r = LinearToGammaWeighted(r_ptr + j, a_ptr + j, a, 4, rgb_stride);
+ g = LinearToGammaWeighted(g_ptr + j, a_ptr + j, a, 4, rgb_stride);
+ b = LinearToGammaWeighted(b_ptr + j, a_ptr + j, a, 4, rgb_stride);
+ }
+ dst[0] = r;
+ dst[1] = g;
+ dst[2] = b;
+ dst[3] = a;
+ }
+ if (width & 1) {
+ const uint32_t a = 2u * SUM2ALPHA(a_ptr + j);
+ int r, g, b;
+ if (a == 4 * 0xff || a == 0) {
+ r = SUM2(r_ptr + j);
+ g = SUM2(g_ptr + j);
+ b = SUM2(b_ptr + j);
+ } else {
+ r = LinearToGammaWeighted(r_ptr + j, a_ptr + j, a, 0, rgb_stride);
+ g = LinearToGammaWeighted(g_ptr + j, a_ptr + j, a, 0, rgb_stride);
+ b = LinearToGammaWeighted(b_ptr + j, a_ptr + j, a, 0, rgb_stride);
+ }
+ dst[0] = r;
+ dst[1] = g;
+ dst[2] = b;
+ dst[3] = a;
+ }
+}
+
+static WEBP_INLINE void AccumulateRGB(const uint8_t* const r_ptr,
+ const uint8_t* const g_ptr,
+ const uint8_t* const b_ptr,
+ int step, int rgb_stride,
+ uint16_t* dst, int width) {
+ int i, j;
+ for (i = 0, j = 0; i < (width >> 1); i += 1, j += 2 * step, dst += 4) {
+ dst[0] = SUM4(r_ptr + j, step);
+ dst[1] = SUM4(g_ptr + j, step);
+ dst[2] = SUM4(b_ptr + j, step);
+ }
+ if (width & 1) {
+ dst[0] = SUM2(r_ptr + j);
+ dst[1] = SUM2(g_ptr + j);
+ dst[2] = SUM2(b_ptr + j);
+ }
+}
+
+static WEBP_INLINE void ConvertRowsToUV(const uint16_t* rgb,
+ uint8_t* const dst_u,
+ uint8_t* const dst_v,
+ int width,
+ VP8Random* const rg) {
+ int i;
+ for (i = 0; i < width; i += 1, rgb += 4) {
+ const int r = rgb[0], g = rgb[1], b = rgb[2];
+ dst_u[i] = RGBToU(r, g, b, rg);
+ dst_v[i] = RGBToV(r, g, b, rg);
+ }
+}
+
+static int ImportYUVAFromRGBA(const uint8_t* const r_ptr,
+ const uint8_t* const g_ptr,
+ const uint8_t* const b_ptr,
+ const uint8_t* const a_ptr,
+ int step, // bytes per pixel
+ int rgb_stride, // bytes per scanline
+ float dithering,
+ int use_iterative_conversion,
+ WebPPicture* const picture) {
+ int y;
+ const int width = picture->width;
+ const int height = picture->height;
+ const int has_alpha = CheckNonOpaque(a_ptr, width, height, step, rgb_stride);
+ const int is_rgb = (r_ptr < b_ptr); // otherwise it's bgr
+
+ picture->colorspace = has_alpha ? WEBP_YUV420A : WEBP_YUV420;
+ picture->use_argb = 0;
+
+ // disable smart conversion if source is too small (overkill).
+ if (width < kMinDimensionIterativeConversion ||
+ height < kMinDimensionIterativeConversion) {
+ use_iterative_conversion = 0;
+ }
+
+ if (!WebPPictureAllocYUVA(picture, width, height)) {
+ return 0;
+ }
+ if (has_alpha) {
+ WebPInitAlphaProcessing();
+ assert(step == 4);
+#if defined(USE_GAMMA_COMPRESSION) && defined(USE_INVERSE_ALPHA_TABLE)
+ assert(kAlphaFix + kGammaFix <= 31);
+#endif
+ }
+
+ if (use_iterative_conversion) {
+ InitGammaTablesF();
+ if (!PreprocessARGB(r_ptr, g_ptr, b_ptr, step, rgb_stride, picture)) {
+ return 0;
+ }
+ if (has_alpha) {
+ WebPExtractAlpha(a_ptr, rgb_stride, width, height,
+ picture->a, picture->a_stride);
+ }
+ } else {
+ const int uv_width = (width + 1) >> 1;
+ int use_dsp = (step == 3); // use special function in this case
+ // temporary storage for accumulated R/G/B values during conversion to U/V
+ uint16_t* const tmp_rgb =
+ (uint16_t*)WebPSafeMalloc(4 * uv_width, sizeof(*tmp_rgb));
+ uint8_t* dst_y = picture->y;
+ uint8_t* dst_u = picture->u;
+ uint8_t* dst_v = picture->v;
+ uint8_t* dst_a = picture->a;
+
+ VP8Random base_rg;
+ VP8Random* rg = NULL;
+ if (dithering > 0.) {
+ VP8InitRandom(&base_rg, dithering);
+ rg = &base_rg;
+ use_dsp = 0; // can't use dsp in this case
+ }
+ WebPInitConvertARGBToYUV();
+ InitGammaTables();
+
+ if (tmp_rgb == NULL) return 0; // malloc error
+
+ // Downsample Y/U/V planes, two rows at a time
+ for (y = 0; y < (height >> 1); ++y) {
+ int rows_have_alpha = has_alpha;
+ const int off1 = (2 * y + 0) * rgb_stride;
+ const int off2 = (2 * y + 1) * rgb_stride;
+ if (use_dsp) {
+ if (is_rgb) {
+ WebPConvertRGB24ToY(r_ptr + off1, dst_y, width);
+ WebPConvertRGB24ToY(r_ptr + off2, dst_y + picture->y_stride, width);
+ } else {
+ WebPConvertBGR24ToY(b_ptr + off1, dst_y, width);
+ WebPConvertBGR24ToY(b_ptr + off2, dst_y + picture->y_stride, width);
+ }
+ } else {
+ ConvertRowToY(r_ptr + off1, g_ptr + off1, b_ptr + off1, step,
+ dst_y, width, rg);
+ ConvertRowToY(r_ptr + off2, g_ptr + off2, b_ptr + off2, step,
+ dst_y + picture->y_stride, width, rg);
+ }
+ dst_y += 2 * picture->y_stride;
+ if (has_alpha) {
+ rows_have_alpha &= !WebPExtractAlpha(a_ptr + off1, rgb_stride,
+ width, 2,
+ dst_a, picture->a_stride);
+ dst_a += 2 * picture->a_stride;
+ }
+ // Collect averaged R/G/B(/A)
+ if (!rows_have_alpha) {
+ AccumulateRGB(r_ptr + off1, g_ptr + off1, b_ptr + off1,
+ step, rgb_stride, tmp_rgb, width);
+ } else {
+ AccumulateRGBA(r_ptr + off1, g_ptr + off1, b_ptr + off1, a_ptr + off1,
+ rgb_stride, tmp_rgb, width);
+ }
+ // Convert to U/V
+ if (rg == NULL) {
+ WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width);
+ } else {
+ ConvertRowsToUV(tmp_rgb, dst_u, dst_v, uv_width, rg);
+ }
+ dst_u += picture->uv_stride;
+ dst_v += picture->uv_stride;
+ }
+ if (height & 1) { // extra last row
+ const int off = 2 * y * rgb_stride;
+ int row_has_alpha = has_alpha;
+ if (use_dsp) {
+ if (r_ptr < b_ptr) {
+ WebPConvertRGB24ToY(r_ptr + off, dst_y, width);
+ } else {
+ WebPConvertBGR24ToY(b_ptr + off, dst_y, width);
+ }
+ } else {
+ ConvertRowToY(r_ptr + off, g_ptr + off, b_ptr + off, step,
+ dst_y, width, rg);
+ }
+ if (row_has_alpha) {
+ row_has_alpha &= !WebPExtractAlpha(a_ptr + off, 0, width, 1, dst_a, 0);
+ }
+ // Collect averaged R/G/B(/A)
+ if (!row_has_alpha) {
+ // Collect averaged R/G/B
+ AccumulateRGB(r_ptr + off, g_ptr + off, b_ptr + off,
+ step, /* rgb_stride = */ 0, tmp_rgb, width);
+ } else {
+ AccumulateRGBA(r_ptr + off, g_ptr + off, b_ptr + off, a_ptr + off,
+ /* rgb_stride = */ 0, tmp_rgb, width);
+ }
+ if (rg == NULL) {
+ WebPConvertRGBA32ToUV(tmp_rgb, dst_u, dst_v, uv_width);
+ } else {
+ ConvertRowsToUV(tmp_rgb, dst_u, dst_v, uv_width, rg);
+ }
+ }
+ WebPSafeFree(tmp_rgb);
+ }
+ return 1;
+}
+
+#undef SUM4
+#undef SUM2
+#undef SUM4ALPHA
+#undef SUM2ALPHA
+
+//------------------------------------------------------------------------------
+// call for ARGB->YUVA conversion
+
+static int PictureARGBToYUVA(WebPPicture* picture, WebPEncCSP colorspace,
+ float dithering, int use_iterative_conversion) {
+ if (picture == NULL) return 0;
+ if (picture->argb == NULL) {
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
+ } else if ((colorspace & WEBP_CSP_UV_MASK) != WEBP_YUV420) {
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);
+ } else {
+ const uint8_t* const argb = (const uint8_t*)picture->argb;
+ const uint8_t* const r = ALPHA_IS_LAST ? argb + 2 : argb + 1;
+ const uint8_t* const g = ALPHA_IS_LAST ? argb + 1 : argb + 2;
+ const uint8_t* const b = ALPHA_IS_LAST ? argb + 0 : argb + 3;
+ const uint8_t* const a = ALPHA_IS_LAST ? argb + 3 : argb + 0;
+
+ picture->colorspace = WEBP_YUV420;
+ return ImportYUVAFromRGBA(r, g, b, a, 4, 4 * picture->argb_stride,
+ dithering, use_iterative_conversion, picture);
+ }
+}
+
+int WebPPictureARGBToYUVADithered(WebPPicture* picture, WebPEncCSP colorspace,
+ float dithering) {
+ return PictureARGBToYUVA(picture, colorspace, dithering, 0);
+}
+
+int WebPPictureARGBToYUVA(WebPPicture* picture, WebPEncCSP colorspace) {
+ return PictureARGBToYUVA(picture, colorspace, 0.f, 0);
+}
+
+int WebPPictureSmartARGBToYUVA(WebPPicture* picture) {
+ return PictureARGBToYUVA(picture, WEBP_YUV420, 0.f, 1);
+}
+
+//------------------------------------------------------------------------------
+// call for YUVA -> ARGB conversion
+
+int WebPPictureYUVAToARGB(WebPPicture* picture) {
+ if (picture == NULL) return 0;
+ if (picture->y == NULL || picture->u == NULL || picture->v == NULL) {
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
+ }
+ if ((picture->colorspace & WEBP_CSP_ALPHA_BIT) && picture->a == NULL) {
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
+ }
+ if ((picture->colorspace & WEBP_CSP_UV_MASK) != WEBP_YUV420) {
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);
+ }
+ // Allocate a new argb buffer (discarding the previous one).
+ if (!WebPPictureAllocARGB(picture, picture->width, picture->height)) return 0;
+ picture->use_argb = 1;
+
+ // Convert
+ {
+ int y;
+ const int width = picture->width;
+ const int height = picture->height;
+ const int argb_stride = 4 * picture->argb_stride;
+ uint8_t* dst = (uint8_t*)picture->argb;
+ const uint8_t *cur_u = picture->u, *cur_v = picture->v, *cur_y = picture->y;
+ WebPUpsampleLinePairFunc upsample = WebPGetLinePairConverter(ALPHA_IS_LAST);
+
+ // First row, with replicated top samples.
+ upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, dst, NULL, width);
+ cur_y += picture->y_stride;
+ dst += argb_stride;
+ // Center rows.
+ for (y = 1; y + 1 < height; y += 2) {
+ const uint8_t* const top_u = cur_u;
+ const uint8_t* const top_v = cur_v;
+ cur_u += picture->uv_stride;
+ cur_v += picture->uv_stride;
+ upsample(cur_y, cur_y + picture->y_stride, top_u, top_v, cur_u, cur_v,
+ dst, dst + argb_stride, width);
+ cur_y += 2 * picture->y_stride;
+ dst += 2 * argb_stride;
+ }
+ // Last row (if needed), with replicated bottom samples.
+ if (height > 1 && !(height & 1)) {
+ upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, dst, NULL, width);
+ }
+ // Insert alpha values if needed, in replacement for the default 0xff ones.
+ if (picture->colorspace & WEBP_CSP_ALPHA_BIT) {
+ for (y = 0; y < height; ++y) {
+ uint32_t* const argb_dst = picture->argb + y * picture->argb_stride;
+ const uint8_t* const src = picture->a + y * picture->a_stride;
+ int x;
+ for (x = 0; x < width; ++x) {
+ argb_dst[x] = (argb_dst[x] & 0x00ffffffu) | ((uint32_t)src[x] << 24);
+ }
+ }
+ }
+ }
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+// automatic import / conversion
+
+static int Import(WebPPicture* const picture,
+ const uint8_t* const rgb, int rgb_stride,
+ int step, int swap_rb, int import_alpha) {
+ int y;
+ const uint8_t* const r_ptr = rgb + (swap_rb ? 2 : 0);
+ const uint8_t* const g_ptr = rgb + 1;
+ const uint8_t* const b_ptr = rgb + (swap_rb ? 0 : 2);
+ const uint8_t* const a_ptr = import_alpha ? rgb + 3 : NULL;
+ const int width = picture->width;
+ const int height = picture->height;
+
+ if (!picture->use_argb) {
+ return ImportYUVAFromRGBA(r_ptr, g_ptr, b_ptr, a_ptr, step, rgb_stride,
+ 0.f /* no dithering */, 0, picture);
+ }
+ if (!WebPPictureAlloc(picture)) return 0;
+
+ VP8EncDspARGBInit();
+
+ if (import_alpha) {
+ assert(step == 4);
+ for (y = 0; y < height; ++y) {
+ uint32_t* const dst = &picture->argb[y * picture->argb_stride];
+ const int offset = y * rgb_stride;
+ VP8PackARGB(a_ptr + offset, r_ptr + offset, g_ptr + offset,
+ b_ptr + offset, width, dst);
+ }
+ } else {
+ assert(step >= 3);
+ for (y = 0; y < height; ++y) {
+ uint32_t* const dst = &picture->argb[y * picture->argb_stride];
+ const int offset = y * rgb_stride;
+ VP8PackRGB(r_ptr + offset, g_ptr + offset, b_ptr + offset,
+ width, step, dst);
+ }
+ }
+ return 1;
+}
+
+// Public API
+
+int WebPPictureImportRGB(WebPPicture* picture,
+ const uint8_t* rgb, int rgb_stride) {
+ return (picture != NULL) ? Import(picture, rgb, rgb_stride, 3, 0, 0) : 0;
+}
+
+int WebPPictureImportBGR(WebPPicture* picture,
+ const uint8_t* rgb, int rgb_stride) {
+ return (picture != NULL) ? Import(picture, rgb, rgb_stride, 3, 1, 0) : 0;
+}
+
+int WebPPictureImportRGBA(WebPPicture* picture,
+ const uint8_t* rgba, int rgba_stride) {
+ return (picture != NULL) ? Import(picture, rgba, rgba_stride, 4, 0, 1) : 0;
+}
+
+int WebPPictureImportBGRA(WebPPicture* picture,
+ const uint8_t* rgba, int rgba_stride) {
+ return (picture != NULL) ? Import(picture, rgba, rgba_stride, 4, 1, 1) : 0;
+}
+
+int WebPPictureImportRGBX(WebPPicture* picture,
+ const uint8_t* rgba, int rgba_stride) {
+ return (picture != NULL) ? Import(picture, rgba, rgba_stride, 4, 0, 0) : 0;
+}
+
+int WebPPictureImportBGRX(WebPPicture* picture,
+ const uint8_t* rgba, int rgba_stride) {
+ return (picture != NULL) ? Import(picture, rgba, rgba_stride, 4, 1, 0) : 0;
+}
+
+//------------------------------------------------------------------------------
diff --git a/drivers/webp/enc/picture_psnr.c b/drivers/webp/enc/picture_psnr.c
new file mode 100644
index 0000000000..40214efc95
--- /dev/null
+++ b/drivers/webp/enc/picture_psnr.c
@@ -0,0 +1,175 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// WebPPicture tools for measuring distortion
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "./vp8enci.h"
+#include "../utils/utils.h"
+
+//------------------------------------------------------------------------------
+// local-min distortion
+//
+// For every pixel in the *reference* picture, we search for the local best
+// match in the compressed image. This is not a symmetrical measure.
+
+#define RADIUS 2 // search radius. Shouldn't be too large.
+
+static void AccumulateLSIM(const uint8_t* src, int src_stride,
+ const uint8_t* ref, int ref_stride,
+ int w, int h, DistoStats* stats) {
+ int x, y;
+ double total_sse = 0.;
+ for (y = 0; y < h; ++y) {
+ const int y_0 = (y - RADIUS < 0) ? 0 : y - RADIUS;
+ const int y_1 = (y + RADIUS + 1 >= h) ? h : y + RADIUS + 1;
+ for (x = 0; x < w; ++x) {
+ const int x_0 = (x - RADIUS < 0) ? 0 : x - RADIUS;
+ const int x_1 = (x + RADIUS + 1 >= w) ? w : x + RADIUS + 1;
+ double best_sse = 255. * 255.;
+ const double value = (double)ref[y * ref_stride + x];
+ int i, j;
+ for (j = y_0; j < y_1; ++j) {
+ const uint8_t* const s = src + j * src_stride;
+ for (i = x_0; i < x_1; ++i) {
+ const double diff = s[i] - value;
+ const double sse = diff * diff;
+ if (sse < best_sse) best_sse = sse;
+ }
+ }
+ total_sse += best_sse;
+ }
+ }
+ stats->w = w * h;
+ stats->xm = 0;
+ stats->ym = 0;
+ stats->xxm = total_sse;
+ stats->yym = 0;
+ stats->xxm = 0;
+}
+#undef RADIUS
+
+//------------------------------------------------------------------------------
+// Distortion
+
+// Max value returned in case of exact similarity.
+static const double kMinDistortion_dB = 99.;
+static float GetPSNR(const double v) {
+ return (float)((v > 0.) ? -4.3429448 * log(v / (255 * 255.))
+ : kMinDistortion_dB);
+}
+
+int WebPPictureDistortion(const WebPPicture* src, const WebPPicture* ref,
+ int type, float result[5]) {
+ DistoStats stats[5];
+ int w, h;
+
+ memset(stats, 0, sizeof(stats));
+
+ if (src == NULL || ref == NULL ||
+ src->width != ref->width || src->height != ref->height ||
+ src->use_argb != ref->use_argb || result == NULL) {
+ return 0;
+ }
+ w = src->width;
+ h = src->height;
+
+ if (src->use_argb == 1) {
+ if (src->argb == NULL || ref->argb == NULL) {
+ return 0;
+ } else {
+ int i, j, c;
+ uint8_t* tmp1, *tmp2;
+ uint8_t* const tmp_plane =
+ (uint8_t*)WebPSafeMalloc(2ULL * w * h, sizeof(*tmp_plane));
+ if (tmp_plane == NULL) return 0;
+ tmp1 = tmp_plane;
+ tmp2 = tmp_plane + w * h;
+ for (c = 0; c < 4; ++c) {
+ for (j = 0; j < h; ++j) {
+ for (i = 0; i < w; ++i) {
+ tmp1[j * w + i] = src->argb[i + j * src->argb_stride] >> (c * 8);
+ tmp2[j * w + i] = ref->argb[i + j * ref->argb_stride] >> (c * 8);
+ }
+ }
+ if (type >= 2) {
+ AccumulateLSIM(tmp1, w, tmp2, w, w, h, &stats[c]);
+ } else {
+ VP8SSIMAccumulatePlane(tmp1, w, tmp2, w, w, h, &stats[c]);
+ }
+ }
+ free(tmp_plane);
+ }
+ } else {
+ int has_alpha, uv_w, uv_h;
+ if (src->y == NULL || ref->y == NULL ||
+ src->u == NULL || ref->u == NULL ||
+ src->v == NULL || ref->v == NULL) {
+ return 0;
+ }
+ has_alpha = !!(src->colorspace & WEBP_CSP_ALPHA_BIT);
+ if (has_alpha != !!(ref->colorspace & WEBP_CSP_ALPHA_BIT) ||
+ (has_alpha && (src->a == NULL || ref->a == NULL))) {
+ return 0;
+ }
+
+ uv_w = (src->width + 1) >> 1;
+ uv_h = (src->height + 1) >> 1;
+ if (type >= 2) {
+ AccumulateLSIM(src->y, src->y_stride, ref->y, ref->y_stride,
+ w, h, &stats[0]);
+ AccumulateLSIM(src->u, src->uv_stride, ref->u, ref->uv_stride,
+ uv_w, uv_h, &stats[1]);
+ AccumulateLSIM(src->v, src->uv_stride, ref->v, ref->uv_stride,
+ uv_w, uv_h, &stats[2]);
+ if (has_alpha) {
+ AccumulateLSIM(src->a, src->a_stride, ref->a, ref->a_stride,
+ w, h, &stats[3]);
+ }
+ } else {
+ VP8SSIMAccumulatePlane(src->y, src->y_stride,
+ ref->y, ref->y_stride,
+ w, h, &stats[0]);
+ VP8SSIMAccumulatePlane(src->u, src->uv_stride,
+ ref->u, ref->uv_stride,
+ uv_w, uv_h, &stats[1]);
+ VP8SSIMAccumulatePlane(src->v, src->uv_stride,
+ ref->v, ref->uv_stride,
+ uv_w, uv_h, &stats[2]);
+ if (has_alpha) {
+ VP8SSIMAccumulatePlane(src->a, src->a_stride,
+ ref->a, ref->a_stride,
+ w, h, &stats[3]);
+ }
+ }
+ }
+ // Final stat calculations.
+ {
+ int c;
+ for (c = 0; c <= 4; ++c) {
+ if (type == 1) {
+ const double v = VP8SSIMGet(&stats[c]);
+ result[c] = (float)((v < 1.) ? -10.0 * log10(1. - v)
+ : kMinDistortion_dB);
+ } else {
+ const double v = VP8SSIMGetSquaredError(&stats[c]);
+ result[c] = GetPSNR(v);
+ }
+ // Accumulate forward
+ if (c < 4) VP8SSIMAddStats(&stats[c], &stats[4]);
+ }
+ }
+ return 1;
+}
+
+//------------------------------------------------------------------------------
diff --git a/drivers/webp/enc/picture_rescale.c b/drivers/webp/enc/picture_rescale.c
new file mode 100644
index 0000000000..9f19e8e80f
--- /dev/null
+++ b/drivers/webp/enc/picture_rescale.c
@@ -0,0 +1,264 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// WebPPicture tools: copy, crop, rescaling and view.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "./vp8enci.h"
+#include "../utils/rescaler.h"
+#include "../utils/utils.h"
+
+#define HALVE(x) (((x) + 1) >> 1)
+
+// Grab the 'specs' (writer, *opaque, width, height...) from 'src' and copy them
+// into 'dst'. Mark 'dst' as not owning any memory.
+static void PictureGrabSpecs(const WebPPicture* const src,
+ WebPPicture* const dst) {
+ assert(src != NULL && dst != NULL);
+ *dst = *src;
+ WebPPictureResetBuffers(dst);
+}
+
+//------------------------------------------------------------------------------
+
+// Adjust top-left corner to chroma sample position.
+static void SnapTopLeftPosition(const WebPPicture* const pic,
+ int* const left, int* const top) {
+ if (!pic->use_argb) {
+ *left &= ~1;
+ *top &= ~1;
+ }
+}
+
+// Adjust top-left corner and verify that the sub-rectangle is valid.
+static int AdjustAndCheckRectangle(const WebPPicture* const pic,
+ int* const left, int* const top,
+ int width, int height) {
+ SnapTopLeftPosition(pic, left, top);
+ if ((*left) < 0 || (*top) < 0) return 0;
+ if (width <= 0 || height <= 0) return 0;
+ if ((*left) + width > pic->width) return 0;
+ if ((*top) + height > pic->height) return 0;
+ return 1;
+}
+
+int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst) {
+ if (src == NULL || dst == NULL) return 0;
+ if (src == dst) return 1;
+
+ PictureGrabSpecs(src, dst);
+ if (!WebPPictureAlloc(dst)) return 0;
+
+ if (!src->use_argb) {
+ WebPCopyPlane(src->y, src->y_stride,
+ dst->y, dst->y_stride, dst->width, dst->height);
+ WebPCopyPlane(src->u, src->uv_stride, dst->u, dst->uv_stride,
+ HALVE(dst->width), HALVE(dst->height));
+ WebPCopyPlane(src->v, src->uv_stride, dst->v, dst->uv_stride,
+ HALVE(dst->width), HALVE(dst->height));
+ if (dst->a != NULL) {
+ WebPCopyPlane(src->a, src->a_stride,
+ dst->a, dst->a_stride, dst->width, dst->height);
+ }
+ } else {
+ WebPCopyPlane((const uint8_t*)src->argb, 4 * src->argb_stride,
+ (uint8_t*)dst->argb, 4 * dst->argb_stride,
+ 4 * dst->width, dst->height);
+ }
+ return 1;
+}
+
+int WebPPictureIsView(const WebPPicture* picture) {
+ if (picture == NULL) return 0;
+ if (picture->use_argb) {
+ return (picture->memory_argb_ == NULL);
+ }
+ return (picture->memory_ == NULL);
+}
+
+int WebPPictureView(const WebPPicture* src,
+ int left, int top, int width, int height,
+ WebPPicture* dst) {
+ if (src == NULL || dst == NULL) return 0;
+
+ // verify rectangle position.
+ if (!AdjustAndCheckRectangle(src, &left, &top, width, height)) return 0;
+
+ if (src != dst) { // beware of aliasing! We don't want to leak 'memory_'.
+ PictureGrabSpecs(src, dst);
+ }
+ dst->width = width;
+ dst->height = height;
+ if (!src->use_argb) {
+ dst->y = src->y + top * src->y_stride + left;
+ dst->u = src->u + (top >> 1) * src->uv_stride + (left >> 1);
+ dst->v = src->v + (top >> 1) * src->uv_stride + (left >> 1);
+ dst->y_stride = src->y_stride;
+ dst->uv_stride = src->uv_stride;
+ if (src->a != NULL) {
+ dst->a = src->a + top * src->a_stride + left;
+ dst->a_stride = src->a_stride;
+ }
+ } else {
+ dst->argb = src->argb + top * src->argb_stride + left;
+ dst->argb_stride = src->argb_stride;
+ }
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+// Picture cropping
+
+int WebPPictureCrop(WebPPicture* pic,
+ int left, int top, int width, int height) {
+ WebPPicture tmp;
+
+ if (pic == NULL) return 0;
+ if (!AdjustAndCheckRectangle(pic, &left, &top, width, height)) return 0;
+
+ PictureGrabSpecs(pic, &tmp);
+ tmp.width = width;
+ tmp.height = height;
+ if (!WebPPictureAlloc(&tmp)) return 0;
+
+ if (!pic->use_argb) {
+ const int y_offset = top * pic->y_stride + left;
+ const int uv_offset = (top / 2) * pic->uv_stride + left / 2;
+ WebPCopyPlane(pic->y + y_offset, pic->y_stride,
+ tmp.y, tmp.y_stride, width, height);
+ WebPCopyPlane(pic->u + uv_offset, pic->uv_stride,
+ tmp.u, tmp.uv_stride, HALVE(width), HALVE(height));
+ WebPCopyPlane(pic->v + uv_offset, pic->uv_stride,
+ tmp.v, tmp.uv_stride, HALVE(width), HALVE(height));
+
+ if (tmp.a != NULL) {
+ const int a_offset = top * pic->a_stride + left;
+ WebPCopyPlane(pic->a + a_offset, pic->a_stride,
+ tmp.a, tmp.a_stride, width, height);
+ }
+ } else {
+ const uint8_t* const src =
+ (const uint8_t*)(pic->argb + top * pic->argb_stride + left);
+ WebPCopyPlane(src, pic->argb_stride * 4, (uint8_t*)tmp.argb,
+ tmp.argb_stride * 4, width * 4, height);
+ }
+ WebPPictureFree(pic);
+ *pic = tmp;
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+// Simple picture rescaler
+
+static void RescalePlane(const uint8_t* src,
+ int src_width, int src_height, int src_stride,
+ uint8_t* dst,
+ int dst_width, int dst_height, int dst_stride,
+ rescaler_t* const work,
+ int num_channels) {
+ WebPRescaler rescaler;
+ int y = 0;
+ WebPRescalerInit(&rescaler, src_width, src_height,
+ dst, dst_width, dst_height, dst_stride,
+ num_channels, work);
+ while (y < src_height) {
+ y += WebPRescalerImport(&rescaler, src_height - y,
+ src + y * src_stride, src_stride);
+ WebPRescalerExport(&rescaler);
+ }
+}
+
+static void AlphaMultiplyARGB(WebPPicture* const pic, int inverse) {
+ assert(pic->argb != NULL);
+ WebPMultARGBRows((uint8_t*)pic->argb, pic->argb_stride * sizeof(*pic->argb),
+ pic->width, pic->height, inverse);
+}
+
+static void AlphaMultiplyY(WebPPicture* const pic, int inverse) {
+ if (pic->a != NULL) {
+ WebPMultRows(pic->y, pic->y_stride, pic->a, pic->a_stride,
+ pic->width, pic->height, inverse);
+ }
+}
+
+int WebPPictureRescale(WebPPicture* pic, int width, int height) {
+ WebPPicture tmp;
+ int prev_width, prev_height;
+ rescaler_t* work;
+
+ if (pic == NULL) return 0;
+ prev_width = pic->width;
+ prev_height = pic->height;
+ if (!WebPRescalerGetScaledDimensions(
+ prev_width, prev_height, &width, &height)) {
+ return 0;
+ }
+
+ PictureGrabSpecs(pic, &tmp);
+ tmp.width = width;
+ tmp.height = height;
+ if (!WebPPictureAlloc(&tmp)) return 0;
+
+ if (!pic->use_argb) {
+ work = (rescaler_t*)WebPSafeMalloc(2ULL * width, sizeof(*work));
+ if (work == NULL) {
+ WebPPictureFree(&tmp);
+ return 0;
+ }
+ // If present, we need to rescale alpha first (for AlphaMultiplyY).
+ if (pic->a != NULL) {
+ WebPInitAlphaProcessing();
+ RescalePlane(pic->a, prev_width, prev_height, pic->a_stride,
+ tmp.a, width, height, tmp.a_stride, work, 1);
+ }
+
+ // We take transparency into account on the luma plane only. That's not
+ // totally exact blending, but still is a good approximation.
+ AlphaMultiplyY(pic, 0);
+ RescalePlane(pic->y, prev_width, prev_height, pic->y_stride,
+ tmp.y, width, height, tmp.y_stride, work, 1);
+ AlphaMultiplyY(&tmp, 1);
+
+ RescalePlane(pic->u,
+ HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
+ tmp.u,
+ HALVE(width), HALVE(height), tmp.uv_stride, work, 1);
+ RescalePlane(pic->v,
+ HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
+ tmp.v,
+ HALVE(width), HALVE(height), tmp.uv_stride, work, 1);
+ } else {
+ work = (rescaler_t*)WebPSafeMalloc(2ULL * width * 4, sizeof(*work));
+ if (work == NULL) {
+ WebPPictureFree(&tmp);
+ return 0;
+ }
+ // In order to correctly interpolate colors, we need to apply the alpha
+ // weighting first (black-matting), scale the RGB values, and remove
+ // the premultiplication afterward (while preserving the alpha channel).
+ WebPInitAlphaProcessing();
+ AlphaMultiplyARGB(pic, 0);
+ RescalePlane((const uint8_t*)pic->argb, prev_width, prev_height,
+ pic->argb_stride * 4,
+ (uint8_t*)tmp.argb, width, height,
+ tmp.argb_stride * 4,
+ work, 4);
+ AlphaMultiplyARGB(&tmp, 1);
+ }
+ WebPPictureFree(pic);
+ WebPSafeFree(work);
+ *pic = tmp;
+ return 1;
+}
+
+//------------------------------------------------------------------------------
diff --git a/drivers/webp/enc/picture_tools.c b/drivers/webp/enc/picture_tools.c
new file mode 100644
index 0000000000..7c73646397
--- /dev/null
+++ b/drivers/webp/enc/picture_tools.c
@@ -0,0 +1,206 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// WebPPicture tools: alpha handling, etc.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./vp8enci.h"
+#include "../dsp/yuv.h"
+
+static WEBP_INLINE uint32_t MakeARGB32(int r, int g, int b) {
+ return (0xff000000u | (r << 16) | (g << 8) | b);
+}
+
+//------------------------------------------------------------------------------
+// Helper: clean up fully transparent area to help compressibility.
+
+#define SIZE 8
+#define SIZE2 (SIZE / 2)
+static int is_transparent_area(const uint8_t* ptr, int stride, int size) {
+ int y, x;
+ for (y = 0; y < size; ++y) {
+ for (x = 0; x < size; ++x) {
+ if (ptr[x]) {
+ return 0;
+ }
+ }
+ ptr += stride;
+ }
+ return 1;
+}
+
+static int is_transparent_argb_area(const uint32_t* ptr, int stride, int size) {
+ int y, x;
+ for (y = 0; y < size; ++y) {
+ for (x = 0; x < size; ++x) {
+ if (ptr[x] & 0xff000000u) {
+ return 0;
+ }
+ }
+ ptr += stride;
+ }
+ return 1;
+}
+
+static void flatten(uint8_t* ptr, int v, int stride, int size) {
+ int y;
+ for (y = 0; y < size; ++y) {
+ memset(ptr, v, size);
+ ptr += stride;
+ }
+}
+
+static void flatten_argb(uint32_t* ptr, uint32_t v, int stride, int size) {
+ int x, y;
+ for (y = 0; y < size; ++y) {
+ for (x = 0; x < size; ++x) ptr[x] = v;
+ ptr += stride;
+ }
+}
+
+void WebPCleanupTransparentArea(WebPPicture* pic) {
+ int x, y, w, h;
+ if (pic == NULL) return;
+ w = pic->width / SIZE;
+ h = pic->height / SIZE;
+
+ // note: we ignore the left-overs on right/bottom
+ if (pic->use_argb) {
+ uint32_t argb_value = 0;
+ for (y = 0; y < h; ++y) {
+ int need_reset = 1;
+ for (x = 0; x < w; ++x) {
+ const int off = (y * pic->argb_stride + x) * SIZE;
+ if (is_transparent_argb_area(pic->argb + off, pic->argb_stride, SIZE)) {
+ if (need_reset) {
+ argb_value = pic->argb[off];
+ need_reset = 0;
+ }
+ flatten_argb(pic->argb + off, argb_value, pic->argb_stride, SIZE);
+ } else {
+ need_reset = 1;
+ }
+ }
+ }
+ } else {
+ const uint8_t* const a_ptr = pic->a;
+ int values[3] = { 0 };
+ if (a_ptr == NULL) return; // nothing to do
+ for (y = 0; y < h; ++y) {
+ int need_reset = 1;
+ for (x = 0; x < w; ++x) {
+ const int off_a = (y * pic->a_stride + x) * SIZE;
+ const int off_y = (y * pic->y_stride + x) * SIZE;
+ const int off_uv = (y * pic->uv_stride + x) * SIZE2;
+ if (is_transparent_area(a_ptr + off_a, pic->a_stride, SIZE)) {
+ if (need_reset) {
+ values[0] = pic->y[off_y];
+ values[1] = pic->u[off_uv];
+ values[2] = pic->v[off_uv];
+ need_reset = 0;
+ }
+ flatten(pic->y + off_y, values[0], pic->y_stride, SIZE);
+ flatten(pic->u + off_uv, values[1], pic->uv_stride, SIZE2);
+ flatten(pic->v + off_uv, values[2], pic->uv_stride, SIZE2);
+ } else {
+ need_reset = 1;
+ }
+ }
+ }
+ }
+}
+
+#undef SIZE
+#undef SIZE2
+
+//------------------------------------------------------------------------------
+// Blend color and remove transparency info
+
+#define BLEND(V0, V1, ALPHA) \
+ ((((V0) * (255 - (ALPHA)) + (V1) * (ALPHA)) * 0x101) >> 16)
+#define BLEND_10BIT(V0, V1, ALPHA) \
+ ((((V0) * (1020 - (ALPHA)) + (V1) * (ALPHA)) * 0x101) >> 18)
+
+void WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb) {
+ const int red = (background_rgb >> 16) & 0xff;
+ const int green = (background_rgb >> 8) & 0xff;
+ const int blue = (background_rgb >> 0) & 0xff;
+ int x, y;
+ if (pic == NULL) return;
+ if (!pic->use_argb) {
+ const int uv_width = (pic->width >> 1); // omit last pixel during u/v loop
+ const int Y0 = VP8RGBToY(red, green, blue, YUV_HALF);
+ // VP8RGBToU/V expects the u/v values summed over four pixels
+ const int U0 = VP8RGBToU(4 * red, 4 * green, 4 * blue, 4 * YUV_HALF);
+ const int V0 = VP8RGBToV(4 * red, 4 * green, 4 * blue, 4 * YUV_HALF);
+ const int has_alpha = pic->colorspace & WEBP_CSP_ALPHA_BIT;
+ if (!has_alpha || pic->a == NULL) return; // nothing to do
+ for (y = 0; y < pic->height; ++y) {
+ // Luma blending
+ uint8_t* const y_ptr = pic->y + y * pic->y_stride;
+ uint8_t* const a_ptr = pic->a + y * pic->a_stride;
+ for (x = 0; x < pic->width; ++x) {
+ const int alpha = a_ptr[x];
+ if (alpha < 0xff) {
+ y_ptr[x] = BLEND(Y0, y_ptr[x], a_ptr[x]);
+ }
+ }
+ // Chroma blending every even line
+ if ((y & 1) == 0) {
+ uint8_t* const u = pic->u + (y >> 1) * pic->uv_stride;
+ uint8_t* const v = pic->v + (y >> 1) * pic->uv_stride;
+ uint8_t* const a_ptr2 =
+ (y + 1 == pic->height) ? a_ptr : a_ptr + pic->a_stride;
+ for (x = 0; x < uv_width; ++x) {
+ // Average four alpha values into a single blending weight.
+ // TODO(skal): might lead to visible contouring. Can we do better?
+ const int alpha =
+ a_ptr[2 * x + 0] + a_ptr[2 * x + 1] +
+ a_ptr2[2 * x + 0] + a_ptr2[2 * x + 1];
+ u[x] = BLEND_10BIT(U0, u[x], alpha);
+ v[x] = BLEND_10BIT(V0, v[x], alpha);
+ }
+ if (pic->width & 1) { // rightmost pixel
+ const int alpha = 2 * (a_ptr[2 * x + 0] + a_ptr2[2 * x + 0]);
+ u[x] = BLEND_10BIT(U0, u[x], alpha);
+ v[x] = BLEND_10BIT(V0, v[x], alpha);
+ }
+ }
+ memset(a_ptr, 0xff, pic->width);
+ }
+ } else {
+ uint32_t* argb = pic->argb;
+ const uint32_t background = MakeARGB32(red, green, blue);
+ for (y = 0; y < pic->height; ++y) {
+ for (x = 0; x < pic->width; ++x) {
+ const int alpha = (argb[x] >> 24) & 0xff;
+ if (alpha != 0xff) {
+ if (alpha > 0) {
+ int r = (argb[x] >> 16) & 0xff;
+ int g = (argb[x] >> 8) & 0xff;
+ int b = (argb[x] >> 0) & 0xff;
+ r = BLEND(red, r, alpha);
+ g = BLEND(green, g, alpha);
+ b = BLEND(blue, b, alpha);
+ argb[x] = MakeARGB32(r, g, b);
+ } else {
+ argb[x] = background;
+ }
+ }
+ }
+ argb += pic->argb_stride;
+ }
+ }
+}
+
+#undef BLEND
+#undef BLEND_10BIT
+
+//------------------------------------------------------------------------------
diff --git a/drivers/webp/enc/quant.c b/drivers/webp/enc/quant.c
index ea153849c8..002c326b82 100644
--- a/drivers/webp/enc/quant.c
+++ b/drivers/webp/enc/quant.c
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Quantization
@@ -11,6 +13,7 @@
#include <assert.h>
#include <math.h>
+#include <stdlib.h> // for abs()
#include "./vp8enci.h"
#include "./cost.h"
@@ -22,16 +25,78 @@
#define MID_ALPHA 64 // neutral value for susceptibility
#define MIN_ALPHA 30 // lowest usable value for susceptibility
-#define MAX_ALPHA 100 // higher meaninful value for susceptibility
+#define MAX_ALPHA 100 // higher meaningful value for susceptibility
#define SNS_TO_DQ 0.9 // Scaling constant between the sns value and the QP
// power-law modulation. Must be strictly less than 1.
+#define I4_PENALTY 4000 // Rate-penalty for quick i4/i16 decision
+
+// number of non-zero coeffs below which we consider the block very flat
+// (and apply a penalty to complex predictions)
+#define FLATNESS_LIMIT_I16 10 // I16 mode
+#define FLATNESS_LIMIT_I4 3 // I4 mode
+#define FLATNESS_LIMIT_UV 2 // UV mode
+#define FLATNESS_PENALTY 140 // roughly ~1bit per block
+
#define MULT_8B(a, b) (((a) * (b) + 128) >> 8)
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
+// #define DEBUG_BLOCK
+
+//------------------------------------------------------------------------------
+
+#if defined(DEBUG_BLOCK)
+
+#include <stdio.h>
+#include <stdlib.h>
+
+static void PrintBlockInfo(const VP8EncIterator* const it,
+ const VP8ModeScore* const rd) {
+ int i, j;
+ const int is_i16 = (it->mb_->type_ == 1);
+ printf("SOURCE / OUTPUT / ABS DELTA\n");
+ for (j = 0; j < 24; ++j) {
+ if (j == 16) printf("\n"); // newline before the U/V block
+ for (i = 0; i < 16; ++i) printf("%3d ", it->yuv_in_[i + j * BPS]);
+ printf(" ");
+ for (i = 0; i < 16; ++i) printf("%3d ", it->yuv_out_[i + j * BPS]);
+ printf(" ");
+ for (i = 0; i < 16; ++i) {
+ printf("%1d ", abs(it->yuv_out_[i + j * BPS] - it->yuv_in_[i + j * BPS]));
+ }
+ printf("\n");
+ }
+ printf("\nD:%d SD:%d R:%d H:%d nz:0x%x score:%d\n",
+ (int)rd->D, (int)rd->SD, (int)rd->R, (int)rd->H, (int)rd->nz,
+ (int)rd->score);
+ if (is_i16) {
+ printf("Mode: %d\n", rd->mode_i16);
+ printf("y_dc_levels:");
+ for (i = 0; i < 16; ++i) printf("%3d ", rd->y_dc_levels[i]);
+ printf("\n");
+ } else {
+ printf("Modes[16]: ");
+ for (i = 0; i < 16; ++i) printf("%d ", rd->modes_i4[i]);
+ printf("\n");
+ }
+ printf("y_ac_levels:\n");
+ for (j = 0; j < 16; ++j) {
+ for (i = is_i16 ? 1 : 0; i < 16; ++i) {
+ printf("%4d ", rd->y_ac_levels[j][i]);
+ }
+ printf("\n");
+ }
+ printf("\n");
+ printf("uv_levels (mode=%d):\n", rd->mode_uv);
+ for (j = 0; j < 8; ++j) {
+ for (i = 0; i < 16; ++i) {
+ printf("%4d ", rd->uv_levels[j][i]);
+ }
+ printf("\n");
+ }
+}
+
+#endif // DEBUG_BLOCK
//------------------------------------------------------------------------------
@@ -100,31 +165,13 @@ static const uint16_t kAcTable2[128] = {
385, 393, 401, 409, 416, 424, 432, 440
};
-static const uint16_t kCoeffThresh[16] = {
- 0, 10, 20, 30,
- 10, 20, 30, 30,
- 20, 30, 30, 30,
- 30, 30, 30, 30
-};
-
-// TODO(skal): tune more. Coeff thresholding?
-static const uint8_t kBiasMatrices[3][16] = { // [3] = [luma-ac,luma-dc,chroma]
- { 96, 96, 96, 96,
- 96, 96, 96, 96,
- 96, 96, 96, 96,
- 96, 96, 96, 96 },
- { 96, 96, 96, 96,
- 96, 96, 96, 96,
- 96, 96, 96, 96,
- 96, 96, 96, 96 },
- { 96, 96, 96, 96,
- 96, 96, 96, 96,
- 96, 96, 96, 96,
- 96, 96, 96, 96 }
+static const uint8_t kBiasMatrices[3][2] = { // [luma-ac,luma-dc,chroma][dc,ac]
+ { 96, 110 }, { 96, 108 }, { 110, 115 }
};
-// Sharpening by (slightly) raising the hi-frequency coeffs (only for trellis).
+// Sharpening by (slightly) raising the hi-frequency coeffs.
// Hack-ish but helpful for mid-bitrate range. Use with care.
+#define SHARPEN_BITS 11 // number of descaling bits for sharpening bias
static const uint8_t kFreqSharpening[16] = {
0, 30, 60, 90,
30, 60, 90, 90,
@@ -137,20 +184,30 @@ static const uint8_t kFreqSharpening[16] = {
// Returns the average quantizer
static int ExpandMatrix(VP8Matrix* const m, int type) {
- int i;
- int sum = 0;
+ int i, sum;
+ for (i = 0; i < 2; ++i) {
+ const int is_ac_coeff = (i > 0);
+ const int bias = kBiasMatrices[type][is_ac_coeff];
+ m->iq_[i] = (1 << QFIX) / m->q_[i];
+ m->bias_[i] = BIAS(bias);
+ // zthresh_ is the exact value such that QUANTDIV(coeff, iQ, B) is:
+ // * zero if coeff <= zthresh
+ // * non-zero if coeff > zthresh
+ m->zthresh_[i] = ((1 << QFIX) - 1 - m->bias_[i]) / m->iq_[i];
+ }
for (i = 2; i < 16; ++i) {
m->q_[i] = m->q_[1];
+ m->iq_[i] = m->iq_[1];
+ m->bias_[i] = m->bias_[1];
+ m->zthresh_[i] = m->zthresh_[1];
}
- for (i = 0; i < 16; ++i) {
- const int j = kZigzag[i];
- const int bias = kBiasMatrices[type][j];
- m->iq_[j] = (1 << QFIX) / m->q_[j];
- m->bias_[j] = BIAS(bias);
- // TODO(skal): tune kCoeffThresh[]
- m->zthresh_[j] = ((256 /*+ kCoeffThresh[j]*/ - bias) * m->q_[j] + 127) >> 8;
- m->sharpen_[j] = (kFreqSharpening[j] * m->q_[j]) >> 11;
- sum += m->q_[j];
+ for (sum = 0, i = 0; i < 16; ++i) {
+ if (type == 0) { // we only use sharpening for AC luma coeffs
+ m->sharpen_[i] = (kFreqSharpening[i] * m->q_[i]) >> SHARPEN_BITS;
+ } else {
+ m->sharpen_[i] = 0;
+ }
+ sum += m->q_[i];
}
return (sum + 8) >> 4;
}
@@ -178,17 +235,17 @@ static void SetupMatrices(VP8Encoder* enc) {
q16 = ExpandMatrix(&m->y2_, 1);
quv = ExpandMatrix(&m->uv_, 2);
- // TODO: Switch to kLambda*[] tables?
- {
- m->lambda_i4_ = (3 * q4 * q4) >> 7;
- m->lambda_i16_ = (3 * q16 * q16);
- m->lambda_uv_ = (3 * quv * quv) >> 6;
- m->lambda_mode_ = (1 * q4 * q4) >> 7;
- m->lambda_trellis_i4_ = (7 * q4 * q4) >> 3;
- m->lambda_trellis_i16_ = (q16 * q16) >> 2;
- m->lambda_trellis_uv_ = (quv *quv) << 1;
- m->tlambda_ = (tlambda_scale * q4) >> 5;
- }
+ m->lambda_i4_ = (3 * q4 * q4) >> 7;
+ m->lambda_i16_ = (3 * q16 * q16);
+ m->lambda_uv_ = (3 * quv * quv) >> 6;
+ m->lambda_mode_ = (1 * q4 * q4) >> 7;
+ m->lambda_trellis_i4_ = (7 * q4 * q4) >> 3;
+ m->lambda_trellis_i16_ = (q16 * q16) >> 2;
+ m->lambda_trellis_uv_ = (quv *quv) << 1;
+ m->tlambda_ = (tlambda_scale * q4) >> 5;
+
+ m->min_disto_ = 10 * m->y1_.q_[0]; // quantization-aware min disto
+ m->max_edge_ = 0;
}
}
@@ -197,16 +254,21 @@ static void SetupMatrices(VP8Encoder* enc) {
// Very small filter-strength values have close to no visual effect. So we can
// save a little decoding-CPU by turning filtering off for these.
-#define FSTRENGTH_CUTOFF 3
+#define FSTRENGTH_CUTOFF 2
static void SetupFilterStrength(VP8Encoder* const enc) {
int i;
- const int level0 = enc->config_->filter_strength;
+ // level0 is in [0..500]. Using '-f 50' as filter_strength is mid-filtering.
+ const int level0 = 5 * enc->config_->filter_strength;
for (i = 0; i < NUM_MB_SEGMENTS; ++i) {
- // Segments with lower quantizer will be less filtered. TODO: tune (wrt SNS)
- const int level = level0 * 256 * enc->dqm_[i].quant_ / 128;
- const int f = level / (256 + enc->dqm_[i].beta_);
- enc->dqm_[i].fstrength_ = (f < FSTRENGTH_CUTOFF) ? 0 : (f > 63) ? 63 : f;
+ VP8SegmentInfo* const m = &enc->dqm_[i];
+ // We focus on the quantization of AC coeffs.
+ const int qstep = kAcTable[clip(m->quant_, 0, 127)] >> 2;
+ const int base_strength =
+ VP8FilterStrengthFromDelta(enc->filter_hdr_.sharpness_, qstep);
+ // Segments with lower complexity ('beta') will be less filtered.
+ const int f = base_strength * level0 / (256 + m->beta_);
+ m->fstrength_ = (f < FSTRENGTH_CUTOFF) ? 0 : (f > 63) ? 63 : f;
}
// We record the initial strength (mainly for the case of 1-segment only).
enc->filter_hdr_.level_ = enc->dqm_[0].fstrength_;
@@ -224,28 +286,90 @@ static void SetupFilterStrength(VP8Encoder* const enc) {
// We want to emulate jpeg-like behaviour where the expected "good" quality
// is around q=75. Internally, our "good" middle is around c=50. So we
// map accordingly using linear piece-wise function
-static double QualityToCompression(double q) {
- const double c = q / 100.;
- return (c < 0.75) ? c * (2. / 3.) : 2. * c - 1.;
+static double QualityToCompression(double c) {
+ const double linear_c = (c < 0.75) ? c * (2. / 3.) : 2. * c - 1.;
+ // The file size roughly scales as pow(quantizer, 3.). Actually, the
+ // exponent is somewhere between 2.8 and 3.2, but we're mostly interested
+ // in the mid-quant range. So we scale the compressibility inversely to
+ // this power-law: quant ~= compression ^ 1/3. This law holds well for
+ // low quant. Finer modeling for high-quant would make use of kAcTable[]
+ // more explicitly.
+ const double v = pow(linear_c, 1 / 3.);
+ return v;
+}
+
+static double QualityToJPEGCompression(double c, double alpha) {
+ // We map the complexity 'alpha' and quality setting 'c' to a compression
+ // exponent empirically matched to the compression curve of libjpeg6b.
+ // On average, the WebP output size will be roughly similar to that of a
+ // JPEG file compressed with same quality factor.
+ const double amin = 0.30;
+ const double amax = 0.85;
+ const double exp_min = 0.4;
+ const double exp_max = 0.9;
+ const double slope = (exp_min - exp_max) / (amax - amin);
+ // Linearly interpolate 'expn' from exp_min to exp_max
+ // in the [amin, amax] range.
+ const double expn = (alpha > amax) ? exp_min
+ : (alpha < amin) ? exp_max
+ : exp_max + slope * (alpha - amin);
+ const double v = pow(c, expn);
+ return v;
+}
+
+static int SegmentsAreEquivalent(const VP8SegmentInfo* const S1,
+ const VP8SegmentInfo* const S2) {
+ return (S1->quant_ == S2->quant_) && (S1->fstrength_ == S2->fstrength_);
+}
+
+static void SimplifySegments(VP8Encoder* const enc) {
+ int map[NUM_MB_SEGMENTS] = { 0, 1, 2, 3 };
+ const int num_segments = enc->segment_hdr_.num_segments_;
+ int num_final_segments = 1;
+ int s1, s2;
+ for (s1 = 1; s1 < num_segments; ++s1) { // find similar segments
+ const VP8SegmentInfo* const S1 = &enc->dqm_[s1];
+ int found = 0;
+ // check if we already have similar segment
+ for (s2 = 0; s2 < num_final_segments; ++s2) {
+ const VP8SegmentInfo* const S2 = &enc->dqm_[s2];
+ if (SegmentsAreEquivalent(S1, S2)) {
+ found = 1;
+ break;
+ }
+ }
+ map[s1] = s2;
+ if (!found) {
+ if (num_final_segments != s1) {
+ enc->dqm_[num_final_segments] = enc->dqm_[s1];
+ }
+ ++num_final_segments;
+ }
+ }
+ if (num_final_segments < num_segments) { // Remap
+ int i = enc->mb_w_ * enc->mb_h_;
+ while (i-- > 0) enc->mb_info_[i].segment_ = map[enc->mb_info_[i].segment_];
+ enc->segment_hdr_.num_segments_ = num_final_segments;
+ // Replicate the trailing segment infos (it's mostly cosmetics)
+ for (i = num_final_segments; i < num_segments; ++i) {
+ enc->dqm_[i] = enc->dqm_[num_final_segments - 1];
+ }
+ }
}
void VP8SetSegmentParams(VP8Encoder* const enc, float quality) {
int i;
int dq_uv_ac, dq_uv_dc;
- const int num_segments = enc->config_->segments;
+ const int num_segments = enc->segment_hdr_.num_segments_;
const double amp = SNS_TO_DQ * enc->config_->sns_strength / 100. / 128.;
- const double c_base = QualityToCompression(quality);
+ const double Q = quality / 100.;
+ const double c_base = enc->config_->emulate_jpeg_size ?
+ QualityToJPEGCompression(Q, enc->alpha_ / 255.) :
+ QualityToCompression(Q);
for (i = 0; i < num_segments; ++i) {
- // The file size roughly scales as pow(quantizer, 3.). Actually, the
- // exponent is somewhere between 2.8 and 3.2, but we're mostly interested
- // in the mid-quant range. So we scale the compressibility inversely to
- // this power-law: quant ~= compression ^ 1/3. This law holds well for
- // low quant. Finer modelling for high-quant would make use of kAcTable[]
- // more explicitely.
- // Additionally, we modulate the base exponent 1/3 to accommodate for the
- // quantization susceptibility and allow denser segments to be quantized
- // more.
- const double expn = (1. - amp * enc->dqm_[i].alpha_) / 3.;
+ // We modulate the base coefficient to accommodate for the quantization
+ // susceptibility and allow denser segments to be quantized more.
+ const double expn = 1. - amp * enc->dqm_[i].alpha_;
const double c = pow(c_base, expn);
const int q = (int)(127. * (1. - c));
assert(expn > 0.);
@@ -271,7 +395,7 @@ void VP8SetSegmentParams(VP8Encoder* const enc, float quality) {
dq_uv_ac = clip(dq_uv_ac, MIN_DQ_UV, MAX_DQ_UV);
// We also boost the dc-uv-quant a little, based on sns-strength, since
// U/V channels are quite more reactive to high quants (flat DC-blocks
- // tend to appear, and are displeasant).
+ // tend to appear, and are unpleasant).
dq_uv_dc = -4 * enc->config_->sns_strength / 100;
dq_uv_dc = clip(dq_uv_dc, -15, 15); // 4bit-signed max allowed
@@ -281,9 +405,11 @@ void VP8SetSegmentParams(VP8Encoder* const enc, float quality) {
enc->dq_uv_dc_ = dq_uv_dc;
enc->dq_uv_ac_ = dq_uv_ac;
- SetupMatrices(enc);
-
SetupFilterStrength(enc); // initialize segments' filtering, eventually
+
+ if (num_segments > 1) SimplifySegments(enc);
+
+ SetupMatrices(enc); // finalize quantization matrices
}
//------------------------------------------------------------------------------
@@ -299,16 +425,14 @@ const int VP8I4ModeOffsets[NUM_BMODES] = {
};
void VP8MakeLuma16Preds(const VP8EncIterator* const it) {
- const VP8Encoder* const enc = it->enc_;
- const uint8_t* const left = it->x_ ? enc->y_left_ : NULL;
- const uint8_t* const top = it->y_ ? enc->y_top_ + it->x_ * 16 : NULL;
+ const uint8_t* const left = it->x_ ? it->y_left_ : NULL;
+ const uint8_t* const top = it->y_ ? it->y_top_ : NULL;
VP8EncPredLuma16(it->yuv_p_, left, top);
}
void VP8MakeChroma8Preds(const VP8EncIterator* const it) {
- const VP8Encoder* const enc = it->enc_;
- const uint8_t* const left = it->x_ ? enc->u_left_ : NULL;
- const uint8_t* const top = it->y_ ? enc->uv_top_ + it->x_ * 16 : NULL;
+ const uint8_t* const left = it->x_ ? it->u_left_ : NULL;
+ const uint8_t* const top = it->y_ ? it->uv_top_ : NULL;
VP8EncPredChroma8(it->yuv_p_, left, top);
}
@@ -320,23 +444,21 @@ void VP8MakeIntra4Preds(const VP8EncIterator* const it) {
// Quantize
// Layout:
-// +----+
-// |YYYY| 0
-// |YYYY| 4
-// |YYYY| 8
-// |YYYY| 12
-// +----+
-// |UUVV| 16
-// |UUVV| 20
-// +----+
-
-const int VP8Scan[16 + 4 + 4] = {
- // Luma
+// +----+----+
+// |YYYY|UUVV| 0
+// |YYYY|UUVV| 4
+// |YYYY|....| 8
+// |YYYY|....| 12
+// +----+----+
+
+const int VP8Scan[16] = { // Luma
0 + 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS,
0 + 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS,
0 + 8 * BPS, 4 + 8 * BPS, 8 + 8 * BPS, 12 + 8 * BPS,
0 + 12 * BPS, 4 + 12 * BPS, 8 + 12 * BPS, 12 + 12 * BPS,
+};
+static const int VP8ScanUV[4 + 4] = {
0 + 0 * BPS, 4 + 0 * BPS, 0 + 4 * BPS, 4 + 4 * BPS, // U
8 + 0 * BPS, 12 + 0 * BPS, 8 + 4 * BPS, 12 + 4 * BPS // V
};
@@ -364,6 +486,7 @@ static void InitScore(VP8ModeScore* const rd) {
rd->D = 0;
rd->SD = 0;
rd->R = 0;
+ rd->H = 0;
rd->nz = 0;
rd->score = MAX_COST;
}
@@ -372,6 +495,7 @@ static void CopyScore(VP8ModeScore* const dst, const VP8ModeScore* const src) {
dst->D = src->D;
dst->SD = src->SD;
dst->R = src->R;
+ dst->H = src->H;
dst->nz = src->nz; // note that nz is not accumulated, but just copied.
dst->score = src->score;
}
@@ -380,6 +504,7 @@ static void AddScore(VP8ModeScore* const dst, const VP8ModeScore* const src) {
dst->D += src->D;
dst->SD += src->SD;
dst->R += src->R;
+ dst->H += src->H;
dst->nz |= src->nz; // here, new nz bits are accumulated.
dst->score += src->score;
}
@@ -387,28 +512,31 @@ static void AddScore(VP8ModeScore* const dst, const VP8ModeScore* const src) {
//------------------------------------------------------------------------------
// Performs trellis-optimized quantization.
-// Trellis
-
+// Trellis node
typedef struct {
- int prev; // best previous
- int level; // level
- int sign; // sign of coeff_i
- score_t cost; // bit cost
- score_t error; // distortion = sum of (|coeff_i| - level_i * Q_i)^2
- int ctx; // context (only depends on 'level'. Could be spared.)
+ int8_t prev; // best previous node
+ int8_t sign; // sign of coeff_i
+ int16_t level; // level
} Node;
+// Score state
+typedef struct {
+ score_t score; // partial RD score
+ const uint16_t* costs; // shortcut to cost tables
+} ScoreState;
+
// If a coefficient was quantized to a value Q (using a neutral bias),
// we test all alternate possibilities between [Q-MIN_DELTA, Q+MAX_DELTA]
// We don't test negative values though.
#define MIN_DELTA 0 // how much lower level to try
#define MAX_DELTA 1 // how much higher
#define NUM_NODES (MIN_DELTA + 1 + MAX_DELTA)
-#define NODE(n, l) (nodes[(n) + 1][(l) + MIN_DELTA])
+#define NODE(n, l) (nodes[(n)][(l) + MIN_DELTA])
+#define SCORE_STATE(n, l) (score_states[n][(l) + MIN_DELTA])
static WEBP_INLINE void SetRDScore(int lambda, VP8ModeScore* const rd) {
// TODO: incorporate the "* 256" in the tables?
- rd->score = rd->R * lambda + 256 * (rd->D + rd->SD);
+ rd->score = (rd->R + rd->H) * lambda + 256 * (rd->D + rd->SD);
}
static WEBP_INLINE score_t RDScoreTrellis(int lambda, score_t rate,
@@ -416,34 +544,37 @@ static WEBP_INLINE score_t RDScoreTrellis(int lambda, score_t rate,
return rate * lambda + 256 * distortion;
}
-static int TrellisQuantizeBlock(const VP8EncIterator* const it,
+static int TrellisQuantizeBlock(const VP8Encoder* const enc,
int16_t in[16], int16_t out[16],
int ctx0, int coeff_type,
const VP8Matrix* const mtx,
int lambda) {
- ProbaArray* const last_costs = it->enc_->proba_.coeffs_[coeff_type];
- CostArray* const costs = it->enc_->proba_.level_cost_[coeff_type];
+ const ProbaArray* const probas = enc->proba_.coeffs_[coeff_type];
+ CostArrayPtr const costs =
+ (CostArrayPtr)enc->proba_.remapped_costs_[coeff_type];
const int first = (coeff_type == 0) ? 1 : 0;
- Node nodes[17][NUM_NODES];
+ Node nodes[16][NUM_NODES];
+ ScoreState score_states[2][NUM_NODES];
+ ScoreState* ss_cur = &SCORE_STATE(0, MIN_DELTA);
+ ScoreState* ss_prev = &SCORE_STATE(1, MIN_DELTA);
int best_path[3] = {-1, -1, -1}; // store best-last/best-level/best-previous
score_t best_score;
- int best_node;
- int last = first - 1;
- int n, m, p, nz;
+ int n, m, p, last;
{
score_t cost;
- score_t max_error;
const int thresh = mtx->q_[1] * mtx->q_[1] / 4;
- const int last_proba = last_costs[VP8EncBands[first]][ctx0][0];
+ const int last_proba = probas[VP8EncBands[first]][ctx0][0];
- // compute maximal distortion.
- max_error = 0;
- for (n = first; n < 16; ++n) {
- const int j = kZigzag[n];
+ // compute the position of the last interesting coefficient
+ last = first - 1;
+ for (n = 15; n >= first; --n) {
+ const int j = kZigzag[n];
const int err = in[j] * in[j];
- max_error += kWeightTrellis[j] * err;
- if (err > thresh) last = n;
+ if (err > thresh) {
+ last = n;
+ break;
+ }
}
// we don't need to go inspect up to n = 16 coeffs. We can just go up
// to last + 1 (inclusive) without losing much.
@@ -451,93 +582,95 @@ static int TrellisQuantizeBlock(const VP8EncIterator* const it,
// compute 'skip' score. This is the max score one can do.
cost = VP8BitCost(0, last_proba);
- best_score = RDScoreTrellis(lambda, cost, max_error);
+ best_score = RDScoreTrellis(lambda, cost, 0);
// initialize source node.
- n = first - 1;
for (m = -MIN_DELTA; m <= MAX_DELTA; ++m) {
- NODE(n, m).cost = 0;
- NODE(n, m).error = max_error;
- NODE(n, m).ctx = ctx0;
+ const score_t rate = (ctx0 == 0) ? VP8BitCost(1, last_proba) : 0;
+ ss_cur[m].score = RDScoreTrellis(lambda, rate, 0);
+ ss_cur[m].costs = costs[first][ctx0];
}
}
// traverse trellis.
for (n = first; n <= last; ++n) {
- const int j = kZigzag[n];
- const int Q = mtx->q_[j];
- const int iQ = mtx->iq_[j];
- const int B = BIAS(0x00); // neutral bias
+ const int j = kZigzag[n];
+ const uint32_t Q = mtx->q_[j];
+ const uint32_t iQ = mtx->iq_[j];
+ const uint32_t B = BIAS(0x00); // neutral bias
// note: it's important to take sign of the _original_ coeff,
// so we don't have to consider level < 0 afterward.
const int sign = (in[j] < 0);
- int coeff0 = (sign ? -in[j] : in[j]) + mtx->sharpen_[j];
- int level0;
- if (coeff0 > 2047) coeff0 = 2047;
+ const uint32_t coeff0 = (sign ? -in[j] : in[j]) + mtx->sharpen_[j];
+ int level0 = QUANTDIV(coeff0, iQ, B);
+ if (level0 > MAX_LEVEL) level0 = MAX_LEVEL;
+
+ { // Swap current and previous score states
+ ScoreState* const tmp = ss_cur;
+ ss_cur = ss_prev;
+ ss_prev = tmp;
+ }
- level0 = QUANTDIV(coeff0, iQ, B);
// test all alternate level values around level0.
for (m = -MIN_DELTA; m <= MAX_DELTA; ++m) {
Node* const cur = &NODE(n, m);
- int delta_error, new_error;
- score_t cur_score = MAX_COST;
int level = level0 + m;
- int last_proba;
-
- cur->sign = sign;
- cur->level = level;
- cur->ctx = (level == 0) ? 0 : (level == 1) ? 1 : 2;
- if (level >= 2048 || level < 0) { // node is dead?
- cur->cost = MAX_COST;
+ const int ctx = (level > 2) ? 2 : level;
+ const int band = VP8EncBands[n + 1];
+ score_t base_score, last_pos_score;
+ score_t best_cur_score = MAX_COST;
+ int best_prev = 0; // default, in case
+
+ ss_cur[m].score = MAX_COST;
+ ss_cur[m].costs = costs[n + 1][ctx];
+ if (level > MAX_LEVEL || level < 0) { // node is dead?
continue;
}
- last_proba = last_costs[VP8EncBands[n + 1]][cur->ctx][0];
- // Compute delta_error = how much coding this level will
- // subtract as distortion to max_error
- new_error = coeff0 - level * Q;
- delta_error =
- kWeightTrellis[j] * (coeff0 * coeff0 - new_error * new_error);
+ // Compute extra rate cost if last coeff's position is < 15
+ {
+ const score_t last_pos_cost =
+ (n < 15) ? VP8BitCost(0, probas[band][ctx][0]) : 0;
+ last_pos_score = RDScoreTrellis(lambda, last_pos_cost, 0);
+ }
+
+ {
+ // Compute delta_error = how much coding this level will
+ // subtract to max_error as distortion.
+ // Here, distortion = sum of (|coeff_i| - level_i * Q_i)^2
+ const int new_error = coeff0 - level * Q;
+ const int delta_error =
+ kWeightTrellis[j] * (new_error * new_error - coeff0 * coeff0);
+ base_score = RDScoreTrellis(lambda, 0, delta_error);
+ }
// Inspect all possible non-dead predecessors. Retain only the best one.
for (p = -MIN_DELTA; p <= MAX_DELTA; ++p) {
- const Node* const prev = &NODE(n - 1, p);
- const int prev_ctx = prev->ctx;
- const uint16_t* const tcost = costs[VP8EncBands[n]][prev_ctx];
- const score_t total_error = prev->error - delta_error;
- score_t cost, base_cost, score;
-
- if (prev->cost >= MAX_COST) { // dead node?
- continue;
- }
-
- // Base cost of both terminal/non-terminal
- base_cost = prev->cost + VP8LevelCost(tcost, level);
-
+ // Dead nodes (with ss_prev[p].score >= MAX_COST) are automatically
+ // eliminated since their score can't be better than the current best.
+ const score_t cost = VP8LevelCost(ss_prev[p].costs, level);
// Examine node assuming it's a non-terminal one.
- cost = base_cost;
- if (level && n < 15) {
- cost += VP8BitCost(1, last_proba);
+ const score_t score =
+ base_score + ss_prev[p].score + RDScoreTrellis(lambda, cost, 0);
+ if (score < best_cur_score) {
+ best_cur_score = score;
+ best_prev = p;
}
- score = RDScoreTrellis(lambda, cost, total_error);
- if (score < cur_score) {
- cur_score = score;
- cur->cost = cost;
- cur->error = total_error;
- cur->prev = p;
- }
-
- // Now, record best terminal node (and thus best entry in the graph).
- if (level) {
- cost = base_cost;
- if (n < 15) cost += VP8BitCost(0, last_proba);
- score = RDScoreTrellis(lambda, cost, total_error);
- if (score < best_score) {
- best_score = score;
- best_path[0] = n; // best eob position
- best_path[1] = m; // best level
- best_path[2] = p; // best predecessor
- }
+ }
+ // Store best finding in current node.
+ cur->sign = sign;
+ cur->level = level;
+ cur->prev = best_prev;
+ ss_cur[m].score = best_cur_score;
+
+ // Now, record best terminal node (and thus best entry in the graph).
+ if (level != 0) {
+ const score_t score = best_cur_score + last_pos_score;
+ if (score < best_score) {
+ best_score = score;
+ best_path[0] = n; // best eob position
+ best_path[1] = m; // best node index
+ best_path[2] = best_prev; // best predecessor
}
}
}
@@ -550,23 +683,25 @@ static int TrellisQuantizeBlock(const VP8EncIterator* const it,
return 0; // skip!
}
- // Unwind the best path.
- // Note: best-prev on terminal node is not necessarily equal to the
- // best_prev for non-terminal. So we patch best_path[2] in.
- n = best_path[0];
- best_node = best_path[1];
- NODE(n, best_node).prev = best_path[2]; // force best-prev for terminal
- nz = 0;
-
- for (; n >= first; --n) {
- const Node* const node = &NODE(n, best_node);
- const int j = kZigzag[n];
- out[n] = node->sign ? -node->level : node->level;
- nz |= (node->level != 0);
- in[j] = out[n] * mtx->q_[j];
- best_node = node->prev;
+ {
+ // Unwind the best path.
+ // Note: best-prev on terminal node is not necessarily equal to the
+ // best_prev for non-terminal. So we patch best_path[2] in.
+ int nz = 0;
+ int best_node = best_path[1];
+ n = best_path[0];
+ NODE(n, best_node).prev = best_path[2]; // force best-prev for terminal
+
+ for (; n >= first; --n) {
+ const Node* const node = &NODE(n, best_node);
+ const int j = kZigzag[n];
+ out[n] = node->sign ? -node->level : node->level;
+ nz |= node->level;
+ in[j] = out[n] * mtx->q_[j];
+ best_node = node->prev;
+ }
+ return (nz != 0);
}
- return nz;
}
#undef NODE
@@ -582,17 +717,17 @@ static int ReconstructIntra16(VP8EncIterator* const it,
int mode) {
const VP8Encoder* const enc = it->enc_;
const uint8_t* const ref = it->yuv_p_ + VP8I16ModeOffsets[mode];
- const uint8_t* const src = it->yuv_in_ + Y_OFF;
+ const uint8_t* const src = it->yuv_in_ + Y_OFF_ENC;
const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_];
int nz = 0;
int n;
int16_t tmp[16][16], dc_tmp[16];
- for (n = 0; n < 16; ++n) {
- VP8FTransform(src + VP8Scan[n], ref + VP8Scan[n], tmp[n]);
+ for (n = 0; n < 16; n += 2) {
+ VP8FTransform2(src + VP8Scan[n], ref + VP8Scan[n], tmp[n]);
}
VP8FTransformWHT(tmp[0], dc_tmp);
- nz |= VP8EncQuantizeBlock(dc_tmp, rd->y_dc_levels, 0, &dqm->y2_) << 24;
+ nz |= VP8EncQuantizeBlockWHT(dc_tmp, rd->y_dc_levels, &dqm->y2_) << 24;
if (DO_TRELLIS_I16 && it->do_trellis_) {
int x, y;
@@ -601,20 +736,26 @@ static int ReconstructIntra16(VP8EncIterator* const it,
for (x = 0; x < 4; ++x, ++n) {
const int ctx = it->top_nz_[x] + it->left_nz_[y];
const int non_zero =
- TrellisQuantizeBlock(it, tmp[n], rd->y_ac_levels[n], ctx, 0,
- &dqm->y1_, dqm->lambda_trellis_i16_);
+ TrellisQuantizeBlock(enc, tmp[n], rd->y_ac_levels[n], ctx, 0,
+ &dqm->y1_, dqm->lambda_trellis_i16_);
it->top_nz_[x] = it->left_nz_[y] = non_zero;
+ rd->y_ac_levels[n][0] = 0;
nz |= non_zero << n;
}
}
} else {
- for (n = 0; n < 16; ++n) {
- nz |= VP8EncQuantizeBlock(tmp[n], rd->y_ac_levels[n], 1, &dqm->y1_) << n;
+ for (n = 0; n < 16; n += 2) {
+ // Zero-out the first coeff, so that: a) nz is correct below, and
+ // b) finding 'last' non-zero coeffs in SetResidualCoeffs() is simplified.
+ tmp[n][0] = tmp[n + 1][0] = 0;
+ nz |= VP8EncQuantize2Blocks(tmp[n], rd->y_ac_levels[n], &dqm->y1_) << n;
+ assert(rd->y_ac_levels[n + 0][0] == 0);
+ assert(rd->y_ac_levels[n + 1][0] == 0);
}
}
// Transform back
- VP8ITransformWHT(dc_tmp, tmp[0]);
+ VP8TransformWHT(dc_tmp, tmp[0]);
for (n = 0; n < 16; n += 2) {
VP8ITransform(ref + VP8Scan[n], tmp[n], yuv_out + VP8Scan[n], 1);
}
@@ -637,10 +778,10 @@ static int ReconstructIntra4(VP8EncIterator* const it,
if (DO_TRELLIS_I4 && it->do_trellis_) {
const int x = it->i4_ & 3, y = it->i4_ >> 2;
const int ctx = it->top_nz_[x] + it->left_nz_[y];
- nz = TrellisQuantizeBlock(it, tmp, levels, ctx, 3, &dqm->y1_,
+ nz = TrellisQuantizeBlock(enc, tmp, levels, ctx, 3, &dqm->y1_,
dqm->lambda_trellis_i4_);
} else {
- nz = VP8EncQuantizeBlock(tmp, levels, 0, &dqm->y1_);
+ nz = VP8EncQuantizeBlock(tmp, levels, &dqm->y1_);
}
VP8ITransform(ref, tmp, yuv_out, 0);
return nz;
@@ -650,14 +791,14 @@ static int ReconstructUV(VP8EncIterator* const it, VP8ModeScore* const rd,
uint8_t* const yuv_out, int mode) {
const VP8Encoder* const enc = it->enc_;
const uint8_t* const ref = it->yuv_p_ + VP8UVModeOffsets[mode];
- const uint8_t* const src = it->yuv_in_ + U_OFF;
+ const uint8_t* const src = it->yuv_in_ + U_OFF_ENC;
const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_];
int nz = 0;
int n;
int16_t tmp[8][16];
- for (n = 0; n < 8; ++n) {
- VP8FTransform(src + VP8Scan[16 + n], ref + VP8Scan[16 + n], tmp[n]);
+ for (n = 0; n < 8; n += 2) {
+ VP8FTransform2(src + VP8ScanUV[n], ref + VP8ScanUV[n], tmp[n]);
}
if (DO_TRELLIS_UV && it->do_trellis_) {
int ch, x, y;
@@ -666,28 +807,45 @@ static int ReconstructUV(VP8EncIterator* const it, VP8ModeScore* const rd,
for (x = 0; x < 2; ++x, ++n) {
const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y];
const int non_zero =
- TrellisQuantizeBlock(it, tmp[n], rd->uv_levels[n], ctx, 2,
- &dqm->uv_, dqm->lambda_trellis_uv_);
+ TrellisQuantizeBlock(enc, tmp[n], rd->uv_levels[n], ctx, 2,
+ &dqm->uv_, dqm->lambda_trellis_uv_);
it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = non_zero;
nz |= non_zero << n;
}
}
}
} else {
- for (n = 0; n < 8; ++n) {
- nz |= VP8EncQuantizeBlock(tmp[n], rd->uv_levels[n], 0, &dqm->uv_) << n;
+ for (n = 0; n < 8; n += 2) {
+ nz |= VP8EncQuantize2Blocks(tmp[n], rd->uv_levels[n], &dqm->uv_) << n;
}
}
for (n = 0; n < 8; n += 2) {
- VP8ITransform(ref + VP8Scan[16 + n], tmp[n], yuv_out + VP8Scan[16 + n], 1);
+ VP8ITransform(ref + VP8ScanUV[n], tmp[n], yuv_out + VP8ScanUV[n], 1);
}
return (nz << 16);
}
//------------------------------------------------------------------------------
// RD-opt decision. Reconstruct each modes, evalue distortion and bit-cost.
-// Pick the mode is lower RD-cost = Rate + lamba * Distortion.
+// Pick the mode is lower RD-cost = Rate + lambda * Distortion.
+
+static void StoreMaxDelta(VP8SegmentInfo* const dqm, const int16_t DCs[16]) {
+ // We look at the first three AC coefficients to determine what is the average
+ // delta between each sub-4x4 block.
+ const int v0 = abs(DCs[1]);
+ const int v1 = abs(DCs[4]);
+ const int v2 = abs(DCs[5]);
+ int max_v = (v0 > v1) ? v1 : v0;
+ max_v = (v2 > max_v) ? v2 : max_v;
+ if (max_v > dqm->max_edge_) dqm->max_edge_ = max_v;
+}
+
+static void SwapModeScore(VP8ModeScore** a, VP8ModeScore** b) {
+ VP8ModeScore* const tmp = *a;
+ *a = *b;
+ *b = tmp;
+}
static void SwapPtr(uint8_t** a, uint8_t** b) {
uint8_t* const tmp = *a;
@@ -699,43 +857,69 @@ static void SwapOut(VP8EncIterator* const it) {
SwapPtr(&it->yuv_out_, &it->yuv_out2_);
}
-static void PickBestIntra16(VP8EncIterator* const it, VP8ModeScore* const rd) {
- const VP8Encoder* const enc = it->enc_;
- const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_];
+static score_t IsFlat(const int16_t* levels, int num_blocks, score_t thresh) {
+ score_t score = 0;
+ while (num_blocks-- > 0) { // TODO(skal): refine positional scoring?
+ int i;
+ for (i = 1; i < 16; ++i) { // omit DC, we're only interested in AC
+ score += (levels[i] != 0);
+ if (score > thresh) return 0;
+ }
+ levels += 16;
+ }
+ return 1;
+}
+
+static void PickBestIntra16(VP8EncIterator* const it, VP8ModeScore* rd) {
+ const int kNumBlocks = 16;
+ VP8SegmentInfo* const dqm = &it->enc_->dqm_[it->mb_->segment_];
const int lambda = dqm->lambda_i16_;
const int tlambda = dqm->tlambda_;
- const uint8_t* const src = it->yuv_in_ + Y_OFF;
- VP8ModeScore rd16;
+ const uint8_t* const src = it->yuv_in_ + Y_OFF_ENC;
+ VP8ModeScore rd_tmp;
+ VP8ModeScore* rd_cur = &rd_tmp;
+ VP8ModeScore* rd_best = rd;
int mode;
rd->mode_i16 = -1;
- for (mode = 0; mode < 4; ++mode) {
- uint8_t* const tmp_dst = it->yuv_out2_ + Y_OFF; // scratch buffer
- int nz;
+ for (mode = 0; mode < NUM_PRED_MODES; ++mode) {
+ uint8_t* const tmp_dst = it->yuv_out2_ + Y_OFF_ENC; // scratch buffer
+ rd_cur->mode_i16 = mode;
// Reconstruct
- nz = ReconstructIntra16(it, &rd16, tmp_dst, mode);
+ rd_cur->nz = ReconstructIntra16(it, rd_cur, tmp_dst, mode);
// Measure RD-score
- rd16.D = VP8SSE16x16(src, tmp_dst);
- rd16.SD = tlambda ? MULT_8B(tlambda, VP8TDisto16x16(src, tmp_dst, kWeightY))
- : 0;
- rd16.R = VP8GetCostLuma16(it, &rd16);
- rd16.R += VP8FixedCostsI16[mode];
+ rd_cur->D = VP8SSE16x16(src, tmp_dst);
+ rd_cur->SD =
+ tlambda ? MULT_8B(tlambda, VP8TDisto16x16(src, tmp_dst, kWeightY)) : 0;
+ rd_cur->H = VP8FixedCostsI16[mode];
+ rd_cur->R = VP8GetCostLuma16(it, rd_cur);
+ if (mode > 0 &&
+ IsFlat(rd_cur->y_ac_levels[0], kNumBlocks, FLATNESS_LIMIT_I16)) {
+ // penalty to avoid flat area to be mispredicted by complex mode
+ rd_cur->R += FLATNESS_PENALTY * kNumBlocks;
+ }
// Since we always examine Intra16 first, we can overwrite *rd directly.
- SetRDScore(lambda, &rd16);
- if (mode == 0 || rd16.score < rd->score) {
- CopyScore(rd, &rd16);
- rd->mode_i16 = mode;
- rd->nz = nz;
- memcpy(rd->y_ac_levels, rd16.y_ac_levels, sizeof(rd16.y_ac_levels));
- memcpy(rd->y_dc_levels, rd16.y_dc_levels, sizeof(rd16.y_dc_levels));
+ SetRDScore(lambda, rd_cur);
+ if (mode == 0 || rd_cur->score < rd_best->score) {
+ SwapModeScore(&rd_cur, &rd_best);
SwapOut(it);
}
}
+ if (rd_best != rd) {
+ memcpy(rd, rd_best, sizeof(*rd));
+ }
SetRDScore(dqm->lambda_mode_, rd); // finalize score for mode decision.
VP8SetIntra16Mode(it, rd->mode_i16);
+
+ // we have a blocky macroblock (only DCs are non-zero) with fairly high
+ // distortion, record max delta so we can later adjust the minimal filtering
+ // strength needed to smooth these blocks out.
+ if ((rd->nz & 0xffff) == 0 && rd->D > dqm->min_disto_) {
+ StoreMaxDelta(dqm, rd->y_dc_levels);
+ }
}
//------------------------------------------------------------------------------
@@ -755,8 +939,8 @@ static int PickBestIntra4(VP8EncIterator* const it, VP8ModeScore* const rd) {
const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_];
const int lambda = dqm->lambda_i4_;
const int tlambda = dqm->tlambda_;
- const uint8_t* const src0 = it->yuv_in_ + Y_OFF;
- uint8_t* const best_blocks = it->yuv_out2_ + Y_OFF;
+ const uint8_t* const src0 = it->yuv_in_ + Y_OFF_ENC;
+ uint8_t* const best_blocks = it->yuv_out2_ + Y_OFF_ENC;
int total_header_bits = 0;
VP8ModeScore rd_best;
@@ -765,9 +949,11 @@ static int PickBestIntra4(VP8EncIterator* const it, VP8ModeScore* const rd) {
}
InitScore(&rd_best);
- rd_best.score = 211; // '211' is the value of VP8BitCost(0, 145)
+ rd_best.H = 211; // '211' is the value of VP8BitCost(0, 145)
+ SetRDScore(dqm->lambda_mode_, &rd_best);
VP8IteratorStartI4(it);
do {
+ const int kNumBlocks = 1;
VP8ModeScore rd_i4;
int mode;
int best_mode = -1;
@@ -791,27 +977,44 @@ static int PickBestIntra4(VP8EncIterator* const it, VP8ModeScore* const rd) {
rd_tmp.SD =
tlambda ? MULT_8B(tlambda, VP8TDisto4x4(src, tmp_dst, kWeightY))
: 0;
- rd_tmp.R = VP8GetCostLuma4(it, tmp_levels);
- rd_tmp.R += mode_costs[mode];
+ rd_tmp.H = mode_costs[mode];
+
+ // Add flatness penalty
+ if (mode > 0 && IsFlat(tmp_levels, kNumBlocks, FLATNESS_LIMIT_I4)) {
+ rd_tmp.R = FLATNESS_PENALTY * kNumBlocks;
+ } else {
+ rd_tmp.R = 0;
+ }
+ // early-out check
SetRDScore(lambda, &rd_tmp);
+ if (best_mode >= 0 && rd_tmp.score >= rd_i4.score) continue;
+
+ // finish computing score
+ rd_tmp.R += VP8GetCostLuma4(it, tmp_levels);
+ SetRDScore(lambda, &rd_tmp);
+
if (best_mode < 0 || rd_tmp.score < rd_i4.score) {
CopyScore(&rd_i4, &rd_tmp);
best_mode = mode;
SwapPtr(&tmp_dst, &best_block);
- memcpy(rd_best.y_ac_levels[it->i4_], tmp_levels, sizeof(tmp_levels));
+ memcpy(rd_best.y_ac_levels[it->i4_], tmp_levels,
+ sizeof(rd_best.y_ac_levels[it->i4_]));
}
}
SetRDScore(dqm->lambda_mode_, &rd_i4);
AddScore(&rd_best, &rd_i4);
- total_header_bits += mode_costs[best_mode];
- if (rd_best.score >= rd->score ||
- total_header_bits > enc->max_i4_header_bits_) {
+ if (rd_best.score >= rd->score) {
+ return 0;
+ }
+ total_header_bits += (int)rd_i4.H; // <- equal to mode_costs[best_mode];
+ if (total_header_bits > enc->max_i4_header_bits_) {
return 0;
}
// Copy selected samples if not in the right place already.
- if (best_block != best_blocks + VP8Scan[it->i4_])
+ if (best_block != best_blocks + VP8Scan[it->i4_]) {
VP8Copy4x4(best_block, best_blocks + VP8Scan[it->i4_]);
+ }
rd->modes_i4[it->i4_] = best_mode;
it->top_nz_[it->i4_ & 3] = it->left_nz_[it->i4_ >> 2] = (rd_i4.nz ? 1 : 0);
} while (VP8IteratorRotateI4(it, best_blocks));
@@ -827,18 +1030,19 @@ static int PickBestIntra4(VP8EncIterator* const it, VP8ModeScore* const rd) {
//------------------------------------------------------------------------------
static void PickBestUV(VP8EncIterator* const it, VP8ModeScore* const rd) {
- const VP8Encoder* const enc = it->enc_;
- const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_];
+ const int kNumBlocks = 8;
+ const VP8SegmentInfo* const dqm = &it->enc_->dqm_[it->mb_->segment_];
const int lambda = dqm->lambda_uv_;
- const uint8_t* const src = it->yuv_in_ + U_OFF;
- uint8_t* const tmp_dst = it->yuv_out2_ + U_OFF; // scratch buffer
- uint8_t* const dst0 = it->yuv_out_ + U_OFF;
+ const uint8_t* const src = it->yuv_in_ + U_OFF_ENC;
+ uint8_t* tmp_dst = it->yuv_out2_ + U_OFF_ENC; // scratch buffer
+ uint8_t* dst0 = it->yuv_out_ + U_OFF_ENC;
+ uint8_t* dst = dst0;
VP8ModeScore rd_best;
int mode;
rd->mode_uv = -1;
InitScore(&rd_best);
- for (mode = 0; mode < 4; ++mode) {
+ for (mode = 0; mode < NUM_PRED_MODES; ++mode) {
VP8ModeScore rd_uv;
// Reconstruct
@@ -847,19 +1051,25 @@ static void PickBestUV(VP8EncIterator* const it, VP8ModeScore* const rd) {
// Compute RD-score
rd_uv.D = VP8SSE16x8(src, tmp_dst);
rd_uv.SD = 0; // TODO: should we call TDisto? it tends to flatten areas.
+ rd_uv.H = VP8FixedCostsUV[mode];
rd_uv.R = VP8GetCostUV(it, &rd_uv);
- rd_uv.R += VP8FixedCostsUV[mode];
+ if (mode > 0 && IsFlat(rd_uv.uv_levels[0], kNumBlocks, FLATNESS_LIMIT_UV)) {
+ rd_uv.R += FLATNESS_PENALTY * kNumBlocks;
+ }
SetRDScore(lambda, &rd_uv);
if (mode == 0 || rd_uv.score < rd_best.score) {
CopyScore(&rd_best, &rd_uv);
rd->mode_uv = mode;
memcpy(rd->uv_levels, rd_uv.uv_levels, sizeof(rd->uv_levels));
- memcpy(dst0, tmp_dst, UV_SIZE); // TODO: SwapUVOut() ?
+ SwapPtr(&dst, &tmp_dst);
}
}
VP8SetIntraUVMode(it, rd->mode_uv);
AddScore(rd, &rd_best);
+ if (dst != dst0) { // copy 16x8 block if needed
+ VP8Copy16x8(dst, dst0);
+ }
}
//------------------------------------------------------------------------------
@@ -867,33 +1077,88 @@ static void PickBestUV(VP8EncIterator* const it, VP8ModeScore* const rd) {
static void SimpleQuantize(VP8EncIterator* const it, VP8ModeScore* const rd) {
const VP8Encoder* const enc = it->enc_;
- const int i16 = (it->mb_->type_ == 1);
+ const int is_i16 = (it->mb_->type_ == 1);
int nz = 0;
- if (i16) {
- nz = ReconstructIntra16(it, rd, it->yuv_out_ + Y_OFF, it->preds_[0]);
+ if (is_i16) {
+ nz = ReconstructIntra16(it, rd, it->yuv_out_ + Y_OFF_ENC, it->preds_[0]);
} else {
VP8IteratorStartI4(it);
do {
const int mode =
it->preds_[(it->i4_ & 3) + (it->i4_ >> 2) * enc->preds_w_];
- const uint8_t* const src = it->yuv_in_ + Y_OFF + VP8Scan[it->i4_];
- uint8_t* const dst = it->yuv_out_ + Y_OFF + VP8Scan[it->i4_];
+ const uint8_t* const src = it->yuv_in_ + Y_OFF_ENC + VP8Scan[it->i4_];
+ uint8_t* const dst = it->yuv_out_ + Y_OFF_ENC + VP8Scan[it->i4_];
VP8MakeIntra4Preds(it);
nz |= ReconstructIntra4(it, rd->y_ac_levels[it->i4_],
src, dst, mode) << it->i4_;
- } while (VP8IteratorRotateI4(it, it->yuv_out_ + Y_OFF));
+ } while (VP8IteratorRotateI4(it, it->yuv_out_ + Y_OFF_ENC));
}
- nz |= ReconstructUV(it, rd, it->yuv_out_ + U_OFF, it->mb_->uv_mode_);
+ nz |= ReconstructUV(it, rd, it->yuv_out_ + U_OFF_ENC, it->mb_->uv_mode_);
rd->nz = nz;
}
+// Refine intra16/intra4 sub-modes based on distortion only (not rate).
+static void DistoRefine(VP8EncIterator* const it, int try_both_i4_i16) {
+ const int is_i16 = (it->mb_->type_ == 1);
+ score_t best_score = MAX_COST;
+
+ if (try_both_i4_i16 || is_i16) {
+ int mode;
+ int best_mode = -1;
+ for (mode = 0; mode < NUM_PRED_MODES; ++mode) {
+ const uint8_t* const ref = it->yuv_p_ + VP8I16ModeOffsets[mode];
+ const uint8_t* const src = it->yuv_in_ + Y_OFF_ENC;
+ const score_t score = VP8SSE16x16(src, ref);
+ if (score < best_score) {
+ best_mode = mode;
+ best_score = score;
+ }
+ }
+ VP8SetIntra16Mode(it, best_mode);
+ }
+ if (try_both_i4_i16 || !is_i16) {
+ uint8_t modes_i4[16];
+ // We don't evaluate the rate here, but just account for it through a
+ // constant penalty (i4 mode usually needs more bits compared to i16).
+ score_t score_i4 = (score_t)I4_PENALTY;
+
+ VP8IteratorStartI4(it);
+ do {
+ int mode;
+ int best_sub_mode = -1;
+ score_t best_sub_score = MAX_COST;
+ const uint8_t* const src = it->yuv_in_ + Y_OFF_ENC + VP8Scan[it->i4_];
+
+ // TODO(skal): we don't really need the prediction pixels here,
+ // but just the distortion against 'src'.
+ VP8MakeIntra4Preds(it);
+ for (mode = 0; mode < NUM_BMODES; ++mode) {
+ const uint8_t* const ref = it->yuv_p_ + VP8I4ModeOffsets[mode];
+ const score_t score = VP8SSE4x4(src, ref);
+ if (score < best_sub_score) {
+ best_sub_mode = mode;
+ best_sub_score = score;
+ }
+ }
+ modes_i4[it->i4_] = best_sub_mode;
+ score_i4 += best_sub_score;
+ if (score_i4 >= best_score) break;
+ } while (VP8IteratorRotateI4(it, it->yuv_in_ + Y_OFF_ENC));
+ if (score_i4 < best_score) {
+ VP8SetIntra4Mode(it, modes_i4);
+ }
+ }
+}
+
//------------------------------------------------------------------------------
// Entry point
-int VP8Decimate(VP8EncIterator* const it, VP8ModeScore* const rd, int rd_opt) {
+int VP8Decimate(VP8EncIterator* const it, VP8ModeScore* const rd,
+ VP8RDLevel rd_opt) {
int is_skipped;
+ const int method = it->enc_->method_;
InitScore(rd);
@@ -902,22 +1167,21 @@ int VP8Decimate(VP8EncIterator* const it, VP8ModeScore* const rd, int rd_opt) {
VP8MakeLuma16Preds(it);
VP8MakeChroma8Preds(it);
- // for rd_opt = 2, we perform trellis-quant on the final decision only.
- // for rd_opt > 2, we use it for every scoring (=much slower).
- if (rd_opt > 0) {
- it->do_trellis_ = (rd_opt > 2);
+ if (rd_opt > RD_OPT_NONE) {
+ it->do_trellis_ = (rd_opt >= RD_OPT_TRELLIS_ALL);
PickBestIntra16(it, rd);
- if (it->enc_->method_ >= 2) {
+ if (method >= 2) {
PickBestIntra4(it, rd);
}
PickBestUV(it, rd);
- if (rd_opt == 2) {
+ if (rd_opt == RD_OPT_TRELLIS) { // finish off with trellis-optim now
it->do_trellis_ = 1;
SimpleQuantize(it, rd);
}
} else {
- // TODO: for method_ == 2, pick the best intra4/intra16 based on SSE
- it->do_trellis_ = (it->enc_->method_ == 2);
+ // For method == 2, pick the best intra4/intra16 based on SSE (~tad slower).
+ // For method <= 1, we refine intra4 or intra16 (but don't re-examine mode).
+ DistoRefine(it, (method >= 2));
SimpleQuantize(it, rd);
}
is_skipped = (rd->nz == 0);
@@ -925,6 +1189,3 @@ int VP8Decimate(VP8EncIterator* const it, VP8ModeScore* const rd, int rd_opt) {
return is_skipped;
}
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/enc/syntax.c b/drivers/webp/enc/syntax.c
index 4221436ff9..2b65f15ca1 100644
--- a/drivers/webp/enc/syntax.c
+++ b/drivers/webp/enc/syntax.c
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Header syntax writing
@@ -11,35 +13,20 @@
#include <assert.h>
-#include "../format_constants.h"
+#include "../utils/utils.h"
+#include "webp/format_constants.h" // RIFF constants
+#include "webp/mux_types.h" // ALPHA_FLAG
#include "./vp8enci.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
//------------------------------------------------------------------------------
// Helper functions
-// TODO(later): Move to webp/format_constants.h?
-static void PutLE24(uint8_t* const data, uint32_t val) {
- data[0] = (val >> 0) & 0xff;
- data[1] = (val >> 8) & 0xff;
- data[2] = (val >> 16) & 0xff;
-}
-
-static void PutLE32(uint8_t* const data, uint32_t val) {
- PutLE24(data, val);
- data[3] = (val >> 24) & 0xff;
-}
-
static int IsVP8XNeeded(const VP8Encoder* const enc) {
return !!enc->has_alpha_; // Currently the only case when VP8X is needed.
// This could change in the future.
}
static int PutPaddingByte(const WebPPicture* const pic) {
-
const uint8_t pad_byte[1] = { 0 };
return !!pic->writer(pad_byte, 1, pic);
}
@@ -73,14 +60,14 @@ static WebPEncodingError PutVP8XHeader(const VP8Encoder* const enc) {
assert(pic->width <= MAX_CANVAS_SIZE && pic->height <= MAX_CANVAS_SIZE);
if (enc->has_alpha_) {
- flags |= ALPHA_FLAG_BIT;
+ flags |= ALPHA_FLAG;
}
PutLE32(vp8x + TAG_SIZE, VP8X_CHUNK_SIZE);
PutLE32(vp8x + CHUNK_HEADER_SIZE, flags);
PutLE24(vp8x + CHUNK_HEADER_SIZE + 4, pic->width - 1);
PutLE24(vp8x + CHUNK_HEADER_SIZE + 7, pic->height - 1);
- if(!pic->writer(vp8x, sizeof(vp8x), pic)) {
+ if (!pic->writer(vp8x, sizeof(vp8x), pic)) {
return VP8_ENC_ERROR_BAD_WRITE;
}
return VP8_ENC_OK;
@@ -199,8 +186,8 @@ static int PutWebPHeaders(const VP8Encoder* const enc, size_t size0,
// Segmentation header
static void PutSegmentHeader(VP8BitWriter* const bw,
const VP8Encoder* const enc) {
- const VP8SegmentHeader* const hdr = &enc->segment_hdr_;
- const VP8Proba* const proba = &enc->proba_;
+ const VP8EncSegmentHeader* const hdr = &enc->segment_hdr_;
+ const VP8EncProba* const proba = &enc->proba_;
if (VP8PutBitUniform(bw, (hdr->num_segments_ > 1))) {
// We always 'update' the quant and filter strength values
const int update_data = 1;
@@ -210,16 +197,16 @@ static void PutSegmentHeader(VP8BitWriter* const bw,
// we always use absolute values, not relative ones
VP8PutBitUniform(bw, 1); // (segment_feature_mode = 1. Paragraph 9.3.)
for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
- VP8PutSignedValue(bw, enc->dqm_[s].quant_, 7);
+ VP8PutSignedBits(bw, enc->dqm_[s].quant_, 7);
}
for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
- VP8PutSignedValue(bw, enc->dqm_[s].fstrength_, 6);
+ VP8PutSignedBits(bw, enc->dqm_[s].fstrength_, 6);
}
}
if (hdr->update_map_) {
for (s = 0; s < 3; ++s) {
if (VP8PutBitUniform(bw, (proba->segments_[s] != 255u))) {
- VP8PutValue(bw, proba->segments_[s], 8);
+ VP8PutBits(bw, proba->segments_[s], 8);
}
}
}
@@ -228,20 +215,20 @@ static void PutSegmentHeader(VP8BitWriter* const bw,
// Filtering parameters header
static void PutFilterHeader(VP8BitWriter* const bw,
- const VP8FilterHeader* const hdr) {
+ const VP8EncFilterHeader* const hdr) {
const int use_lf_delta = (hdr->i4x4_lf_delta_ != 0);
VP8PutBitUniform(bw, hdr->simple_);
- VP8PutValue(bw, hdr->level_, 6);
- VP8PutValue(bw, hdr->sharpness_, 3);
+ VP8PutBits(bw, hdr->level_, 6);
+ VP8PutBits(bw, hdr->sharpness_, 3);
if (VP8PutBitUniform(bw, use_lf_delta)) {
// '0' is the default value for i4x4_lf_delta_ at frame #0.
const int need_update = (hdr->i4x4_lf_delta_ != 0);
if (VP8PutBitUniform(bw, need_update)) {
// we don't use ref_lf_delta => emit four 0 bits
- VP8PutValue(bw, 0, 4);
+ VP8PutBits(bw, 0, 4);
// we use mode_lf_delta for i4x4
- VP8PutSignedValue(bw, hdr->i4x4_lf_delta_, 6);
- VP8PutValue(bw, 0, 3); // all others unused
+ VP8PutSignedBits(bw, hdr->i4x4_lf_delta_, 6);
+ VP8PutBits(bw, 0, 3); // all others unused
}
}
}
@@ -249,12 +236,12 @@ static void PutFilterHeader(VP8BitWriter* const bw,
// Nominal quantization parameters
static void PutQuant(VP8BitWriter* const bw,
const VP8Encoder* const enc) {
- VP8PutValue(bw, enc->base_quant_, 7);
- VP8PutSignedValue(bw, enc->dq_y1_dc_, 4);
- VP8PutSignedValue(bw, enc->dq_y2_dc_, 4);
- VP8PutSignedValue(bw, enc->dq_y2_ac_, 4);
- VP8PutSignedValue(bw, enc->dq_uv_dc_, 4);
- VP8PutSignedValue(bw, enc->dq_uv_ac_, 4);
+ VP8PutBits(bw, enc->base_quant_, 7);
+ VP8PutSignedBits(bw, enc->dq_y1_dc_, 4);
+ VP8PutSignedBits(bw, enc->dq_y2_dc_, 4);
+ VP8PutSignedBits(bw, enc->dq_y2_ac_, 4);
+ VP8PutSignedBits(bw, enc->dq_uv_dc_, 4);
+ VP8PutSignedBits(bw, enc->dq_uv_ac_, 4);
}
// Partition sizes
@@ -276,58 +263,23 @@ static int EmitPartitionsSize(const VP8Encoder* const enc,
//------------------------------------------------------------------------------
-#ifdef WEBP_EXPERIMENTAL_FEATURES
-
-#define KTRAILER_SIZE 8
-
-static int WriteExtensions(VP8Encoder* const enc) {
- uint8_t buffer[KTRAILER_SIZE];
- VP8BitWriter* const bw = &enc->bw_;
- WebPPicture* const pic = enc->pic_;
-
- // Layer (bytes 0..3)
- PutLE24(buffer + 0, enc->layer_data_size_);
- buffer[3] = enc->pic_->colorspace & WEBP_CSP_UV_MASK;
- if (enc->layer_data_size_ > 0) {
- assert(enc->use_layer_);
- // append layer data to last partition
- if (!VP8BitWriterAppend(&enc->parts_[enc->num_parts_ - 1],
- enc->layer_data_, enc->layer_data_size_)) {
- return WebPEncodingSetError(pic, VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY);
- }
- }
-
- buffer[KTRAILER_SIZE - 1] = 0x01; // marker
- if (!VP8BitWriterAppend(bw, buffer, KTRAILER_SIZE)) {
- return WebPEncodingSetError(pic, VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY);
- }
- return 1;
-}
-
-#endif /* WEBP_EXPERIMENTAL_FEATURES */
-
-//------------------------------------------------------------------------------
-
-static size_t GeneratePartition0(VP8Encoder* const enc) {
+static int GeneratePartition0(VP8Encoder* const enc) {
VP8BitWriter* const bw = &enc->bw_;
const int mb_size = enc->mb_w_ * enc->mb_h_;
uint64_t pos1, pos2, pos3;
-#ifdef WEBP_EXPERIMENTAL_FEATURES
- const int need_extensions = enc->use_layer_;
-#endif
pos1 = VP8BitWriterPos(bw);
- VP8BitWriterInit(bw, mb_size * 7 / 8); // ~7 bits per macroblock
-#ifdef WEBP_EXPERIMENTAL_FEATURES
- VP8PutBitUniform(bw, need_extensions); // extensions
-#else
+ if (!VP8BitWriterInit(bw, mb_size * 7 / 8)) { // ~7 bits per macroblock
+ return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ }
VP8PutBitUniform(bw, 0); // colorspace
-#endif
VP8PutBitUniform(bw, 0); // clamp type
PutSegmentHeader(bw, enc);
PutFilterHeader(bw, &enc->filter_hdr_);
- VP8PutValue(bw, enc->config_->partitions, 2);
+ VP8PutBits(bw, enc->num_parts_ == 8 ? 3 :
+ enc->num_parts_ == 4 ? 2 :
+ enc->num_parts_ == 2 ? 1 : 0, 2);
PutQuant(bw, enc);
VP8PutBitUniform(bw, 0); // no proba update
VP8WriteProbas(bw, &enc->proba_);
@@ -335,21 +287,17 @@ static size_t GeneratePartition0(VP8Encoder* const enc) {
VP8CodeIntraModes(enc);
VP8BitWriterFinish(bw);
-#ifdef WEBP_EXPERIMENTAL_FEATURES
- if (need_extensions && !WriteExtensions(enc)) {
- return 0;
- }
-#endif
-
pos3 = VP8BitWriterPos(bw);
if (enc->pic_->stats) {
enc->pic_->stats->header_bytes[0] = (int)((pos2 - pos1 + 7) >> 3);
enc->pic_->stats->header_bytes[1] = (int)((pos3 - pos2 + 7) >> 3);
enc->pic_->stats->alpha_data_size = (int)enc->alpha_data_size_;
- enc->pic_->stats->layer_data_size = (int)enc->layer_data_size_;
}
- return !bw->error_;
+ if (bw->error_) {
+ return WebPEncodingSetError(enc->pic_, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ }
+ return 1;
}
void VP8EncFreeBitWriters(VP8Encoder* const enc) {
@@ -371,7 +319,8 @@ int VP8EncWrite(VP8Encoder* const enc) {
int p;
// Partition #0 with header and partition sizes
- ok = !!GeneratePartition0(enc);
+ ok = GeneratePartition0(enc);
+ if (!ok) return 0;
// Compute VP8 size
vp8_size = VP8_FRAME_HEADER_SIZE +
@@ -432,6 +381,3 @@ int VP8EncWrite(VP8Encoder* const enc) {
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/enc/token.c b/drivers/webp/enc/token.c
new file mode 100644
index 0000000000..e73256b37e
--- /dev/null
+++ b/drivers/webp/enc/token.c
@@ -0,0 +1,285 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Paginated token buffer
+//
+// A 'token' is a bit value associated with a probability, either fixed
+// or a later-to-be-determined after statistics have been collected.
+// For dynamic probability, we just record the slot id (idx) for the probability
+// value in the final probability array (uint8_t* probas in VP8EmitTokens).
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "./cost.h"
+#include "./vp8enci.h"
+#include "../utils/utils.h"
+
+#if !defined(DISABLE_TOKEN_BUFFER)
+
+// we use pages to reduce the number of memcpy()
+#define MIN_PAGE_SIZE 8192 // minimum number of token per page
+#define FIXED_PROBA_BIT (1u << 14)
+
+typedef uint16_t token_t; // bit #15: bit value
+ // bit #14: flags for constant proba or idx
+ // bits #0..13: slot or constant proba
+struct VP8Tokens {
+ VP8Tokens* next_; // pointer to next page
+};
+// Token data is located in memory just after the next_ field.
+// This macro is used to return their address and hide the trick.
+#define TOKEN_DATA(p) ((const token_t*)&(p)[1])
+
+//------------------------------------------------------------------------------
+
+void VP8TBufferInit(VP8TBuffer* const b, int page_size) {
+ b->tokens_ = NULL;
+ b->pages_ = NULL;
+ b->last_page_ = &b->pages_;
+ b->left_ = 0;
+ b->page_size_ = (page_size < MIN_PAGE_SIZE) ? MIN_PAGE_SIZE : page_size;
+ b->error_ = 0;
+}
+
+void VP8TBufferClear(VP8TBuffer* const b) {
+ if (b != NULL) {
+ VP8Tokens* p = b->pages_;
+ while (p != NULL) {
+ VP8Tokens* const next = p->next_;
+ WebPSafeFree(p);
+ p = next;
+ }
+ VP8TBufferInit(b, b->page_size_);
+ }
+}
+
+static int TBufferNewPage(VP8TBuffer* const b) {
+ VP8Tokens* page = NULL;
+ if (!b->error_) {
+ const size_t size = sizeof(*page) + b->page_size_ * sizeof(token_t);
+ page = (VP8Tokens*)WebPSafeMalloc(1ULL, size);
+ }
+ if (page == NULL) {
+ b->error_ = 1;
+ return 0;
+ }
+ page->next_ = NULL;
+
+ *b->last_page_ = page;
+ b->last_page_ = &page->next_;
+ b->left_ = b->page_size_;
+ b->tokens_ = (token_t*)TOKEN_DATA(page);
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+
+#define TOKEN_ID(t, b, ctx) \
+ (NUM_PROBAS * ((ctx) + NUM_CTX * ((b) + NUM_BANDS * (t))))
+
+static WEBP_INLINE uint32_t AddToken(VP8TBuffer* const b,
+ uint32_t bit, uint32_t proba_idx) {
+ assert(proba_idx < FIXED_PROBA_BIT);
+ assert(bit <= 1);
+ if (b->left_ > 0 || TBufferNewPage(b)) {
+ const int slot = --b->left_;
+ b->tokens_[slot] = (bit << 15) | proba_idx;
+ }
+ return bit;
+}
+
+static WEBP_INLINE void AddConstantToken(VP8TBuffer* const b,
+ uint32_t bit, uint32_t proba) {
+ assert(proba < 256);
+ assert(bit <= 1);
+ if (b->left_ > 0 || TBufferNewPage(b)) {
+ const int slot = --b->left_;
+ b->tokens_[slot] = (bit << 15) | FIXED_PROBA_BIT | proba;
+ }
+}
+
+int VP8RecordCoeffTokens(const int ctx, const int coeff_type,
+ int first, int last,
+ const int16_t* const coeffs,
+ VP8TBuffer* const tokens) {
+ int n = first;
+ uint32_t base_id = TOKEN_ID(coeff_type, n, ctx);
+ if (!AddToken(tokens, last >= 0, base_id + 0)) {
+ return 0;
+ }
+
+ while (n < 16) {
+ const int c = coeffs[n++];
+ const int sign = c < 0;
+ const uint32_t v = sign ? -c : c;
+ if (!AddToken(tokens, v != 0, base_id + 1)) {
+ base_id = TOKEN_ID(coeff_type, VP8EncBands[n], 0); // ctx=0
+ continue;
+ }
+ if (!AddToken(tokens, v > 1, base_id + 2)) {
+ base_id = TOKEN_ID(coeff_type, VP8EncBands[n], 1); // ctx=1
+ } else {
+ if (!AddToken(tokens, v > 4, base_id + 3)) {
+ if (AddToken(tokens, v != 2, base_id + 4))
+ AddToken(tokens, v == 4, base_id + 5);
+ } else if (!AddToken(tokens, v > 10, base_id + 6)) {
+ if (!AddToken(tokens, v > 6, base_id + 7)) {
+ AddConstantToken(tokens, v == 6, 159);
+ } else {
+ AddConstantToken(tokens, v >= 9, 165);
+ AddConstantToken(tokens, !(v & 1), 145);
+ }
+ } else {
+ int mask;
+ const uint8_t* tab;
+ uint32_t residue = v - 3;
+ if (residue < (8 << 1)) { // VP8Cat3 (3b)
+ AddToken(tokens, 0, base_id + 8);
+ AddToken(tokens, 0, base_id + 9);
+ residue -= (8 << 0);
+ mask = 1 << 2;
+ tab = VP8Cat3;
+ } else if (residue < (8 << 2)) { // VP8Cat4 (4b)
+ AddToken(tokens, 0, base_id + 8);
+ AddToken(tokens, 1, base_id + 9);
+ residue -= (8 << 1);
+ mask = 1 << 3;
+ tab = VP8Cat4;
+ } else if (residue < (8 << 3)) { // VP8Cat5 (5b)
+ AddToken(tokens, 1, base_id + 8);
+ AddToken(tokens, 0, base_id + 10);
+ residue -= (8 << 2);
+ mask = 1 << 4;
+ tab = VP8Cat5;
+ } else { // VP8Cat6 (11b)
+ AddToken(tokens, 1, base_id + 8);
+ AddToken(tokens, 1, base_id + 10);
+ residue -= (8 << 3);
+ mask = 1 << 10;
+ tab = VP8Cat6;
+ }
+ while (mask) {
+ AddConstantToken(tokens, !!(residue & mask), *tab++);
+ mask >>= 1;
+ }
+ }
+ base_id = TOKEN_ID(coeff_type, VP8EncBands[n], 2); // ctx=2
+ }
+ AddConstantToken(tokens, sign, 128);
+ if (n == 16 || !AddToken(tokens, n <= last, base_id + 0)) {
+ return 1; // EOB
+ }
+ }
+ return 1;
+}
+
+#undef TOKEN_ID
+
+//------------------------------------------------------------------------------
+// This function works, but isn't currently used. Saved for later.
+
+#if 0
+
+static void Record(int bit, proba_t* const stats) {
+ proba_t p = *stats;
+ if (p >= 0xffff0000u) { // an overflow is inbound.
+ p = ((p + 1u) >> 1) & 0x7fff7fffu; // -> divide the stats by 2.
+ }
+ // record bit count (lower 16 bits) and increment total count (upper 16 bits).
+ p += 0x00010000u + bit;
+ *stats = p;
+}
+
+void VP8TokenToStats(const VP8TBuffer* const b, proba_t* const stats) {
+ const VP8Tokens* p = b->pages_;
+ while (p != NULL) {
+ const int N = (p->next_ == NULL) ? b->left_ : 0;
+ int n = MAX_NUM_TOKEN;
+ const token_t* const tokens = TOKEN_DATA(p);
+ while (n-- > N) {
+ const token_t token = tokens[n];
+ if (!(token & FIXED_PROBA_BIT)) {
+ Record((token >> 15) & 1, stats + (token & 0x3fffu));
+ }
+ }
+ p = p->next_;
+ }
+}
+
+#endif // 0
+
+//------------------------------------------------------------------------------
+// Final coding pass, with known probabilities
+
+int VP8EmitTokens(VP8TBuffer* const b, VP8BitWriter* const bw,
+ const uint8_t* const probas, int final_pass) {
+ const VP8Tokens* p = b->pages_;
+ assert(!b->error_);
+ while (p != NULL) {
+ const VP8Tokens* const next = p->next_;
+ const int N = (next == NULL) ? b->left_ : 0;
+ int n = b->page_size_;
+ const token_t* const tokens = TOKEN_DATA(p);
+ while (n-- > N) {
+ const token_t token = tokens[n];
+ const int bit = (token >> 15) & 1;
+ if (token & FIXED_PROBA_BIT) {
+ VP8PutBit(bw, bit, token & 0xffu); // constant proba
+ } else {
+ VP8PutBit(bw, bit, probas[token & 0x3fffu]);
+ }
+ }
+ if (final_pass) WebPSafeFree((void*)p);
+ p = next;
+ }
+ if (final_pass) b->pages_ = NULL;
+ return 1;
+}
+
+// Size estimation
+size_t VP8EstimateTokenSize(VP8TBuffer* const b, const uint8_t* const probas) {
+ size_t size = 0;
+ const VP8Tokens* p = b->pages_;
+ assert(!b->error_);
+ while (p != NULL) {
+ const VP8Tokens* const next = p->next_;
+ const int N = (next == NULL) ? b->left_ : 0;
+ int n = b->page_size_;
+ const token_t* const tokens = TOKEN_DATA(p);
+ while (n-- > N) {
+ const token_t token = tokens[n];
+ const int bit = token & (1 << 15);
+ if (token & FIXED_PROBA_BIT) {
+ size += VP8BitCost(bit, token & 0xffu);
+ } else {
+ size += VP8BitCost(bit, probas[token & 0x3fffu]);
+ }
+ }
+ p = next;
+ }
+ return size;
+}
+
+//------------------------------------------------------------------------------
+
+#else // DISABLE_TOKEN_BUFFER
+
+void VP8TBufferInit(VP8TBuffer* const b) {
+ (void)b;
+}
+void VP8TBufferClear(VP8TBuffer* const b) {
+ (void)b;
+}
+
+#endif // !DISABLE_TOKEN_BUFFER
+
diff --git a/drivers/webp/enc/tree.c b/drivers/webp/enc/tree.c
index 8b25e5e488..f141006d19 100644
--- a/drivers/webp/enc/tree.c
+++ b/drivers/webp/enc/tree.c
@@ -1,27 +1,24 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
-// Token probabilities
+// Coding of token probabilities, intra modes and segments.
//
// Author: Skal (pascal.massimino@gmail.com)
#include "./vp8enci.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
//------------------------------------------------------------------------------
// Default probabilities
// Paragraph 13.5
const uint8_t
VP8CoeffsProba0[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS] = {
- // genereated using vp8_default_coef_probs() in entropy.c:129
{ { { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
{ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
{ 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }
@@ -157,7 +154,7 @@ const uint8_t
};
void VP8DefaultProbas(VP8Encoder* const enc) {
- VP8Proba* const probas = &enc->proba_;
+ VP8EncProba* const probas = &enc->proba_;
probas->use_skip_proba_ = 0;
memset(probas->segments_, 255u, sizeof(probas->segments_));
memcpy(probas->coeffs_, VP8CoeffsProba0, sizeof(VP8CoeffsProba0));
@@ -318,7 +315,7 @@ void VP8CodeIntraModes(VP8Encoder* const enc) {
VP8EncIterator it;
VP8IteratorInit(enc, &it);
do {
- const VP8MBInfo* mb = it.mb_;
+ const VP8MBInfo* const mb = it.mb_;
const uint8_t* preds = it.preds_;
if (enc->segment_hdr_.update_map_) {
PutSegment(bw, mb->segment_, enc->proba_.segments_);
@@ -343,7 +340,7 @@ void VP8CodeIntraModes(VP8Encoder* const enc) {
}
}
PutUVMode(bw, mb->uv_mode_);
- } while (VP8IteratorNext(&it, 0));
+ } while (VP8IteratorNext(&it));
}
//------------------------------------------------------------------------------
@@ -485,7 +482,7 @@ const uint8_t
}
};
-void VP8WriteProbas(VP8BitWriter* const bw, const VP8Proba* const probas) {
+void VP8WriteProbas(VP8BitWriter* const bw, const VP8EncProba* const probas) {
int t, b, c, p;
for (t = 0; t < NUM_TYPES; ++t) {
for (b = 0; b < NUM_BANDS; ++b) {
@@ -494,17 +491,14 @@ void VP8WriteProbas(VP8BitWriter* const bw, const VP8Proba* const probas) {
const uint8_t p0 = probas->coeffs_[t][b][c][p];
const int update = (p0 != VP8CoeffsProba0[t][b][c][p]);
if (VP8PutBit(bw, update, VP8CoeffsUpdateProba[t][b][c][p])) {
- VP8PutValue(bw, p0, 8);
+ VP8PutBits(bw, p0, 8);
}
}
}
}
}
if (VP8PutBitUniform(bw, probas->use_skip_proba_)) {
- VP8PutValue(bw, probas->skip_proba_, 8);
+ VP8PutBits(bw, probas->skip_proba_, 8);
}
}
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/enc/vp8enci.h b/drivers/webp/enc/vp8enci.h
index 936e1c18ce..0cb2ccc353 100644
--- a/drivers/webp/enc/vp8enci.h
+++ b/drivers/webp/enc/vp8enci.h
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// WebP encoder: internal header.
@@ -13,11 +15,18 @@
#define WEBP_ENC_VP8ENCI_H_
#include <string.h> // for memcpy()
-#include "../encode.h"
+#include "../dec/common.h"
#include "../dsp/dsp.h"
#include "../utils/bit_writer.h"
+#include "../utils/thread.h"
+#include "../utils/utils.h"
+#include "webp/encode.h"
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef WEBP_EXPERIMENTAL_FEATURES
+#include "./vp8li.h"
+#endif // WEBP_EXPERIMENTAL_FEATURES
+
+#ifdef __cplusplus
extern "C" {
#endif
@@ -26,141 +35,94 @@ extern "C" {
// version numbers
#define ENC_MAJ_VERSION 0
-#define ENC_MIN_VERSION 2
-#define ENC_REV_VERSION 0
-
-// size of histogram used by CollectHistogram.
-#define MAX_COEFF_THRESH 64
-
-// intra prediction modes
-enum { B_DC_PRED = 0, // 4x4 modes
- B_TM_PRED = 1,
- B_VE_PRED = 2,
- B_HE_PRED = 3,
- B_RD_PRED = 4,
- B_VR_PRED = 5,
- B_LD_PRED = 6,
- B_VL_PRED = 7,
- B_HD_PRED = 8,
- B_HU_PRED = 9,
- NUM_BMODES = B_HU_PRED + 1 - B_DC_PRED, // = 10
-
- // Luma16 or UV modes
- DC_PRED = B_DC_PRED, V_PRED = B_VE_PRED,
- H_PRED = B_HE_PRED, TM_PRED = B_TM_PRED
- };
+#define ENC_MIN_VERSION 4
+#define ENC_REV_VERSION 4
-enum { NUM_MB_SEGMENTS = 4,
- MAX_NUM_PARTITIONS = 8,
- NUM_TYPES = 4, // 0: i16-AC, 1: i16-DC, 2:chroma-AC, 3:i4-AC
- NUM_BANDS = 8,
- NUM_CTX = 3,
- NUM_PROBAS = 11,
- MAX_LF_LEVELS = 64, // Maximum loop filter level
- MAX_VARIABLE_LEVEL = 67 // last (inclusive) level with variable cost
+enum { MAX_LF_LEVELS = 64, // Maximum loop filter level
+ MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost
+ MAX_LEVEL = 2047 // max level (note: max codable is 2047 + 67)
};
-// YUV-cache parameters. Cache is 16-pixels wide.
-// The original or reconstructed samples can be accessed using VP8Scan[]
+typedef enum { // Rate-distortion optimization levels
+ RD_OPT_NONE = 0, // no rd-opt
+ RD_OPT_BASIC = 1, // basic scoring (no trellis)
+ RD_OPT_TRELLIS = 2, // perform trellis-quant on the final decision only
+ RD_OPT_TRELLIS_ALL = 3 // trellis-quant for every scoring (much slower)
+} VP8RDLevel;
+
+// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
+// The original or reconstructed samples can be accessed using VP8Scan[].
// The predicted blocks can be accessed using offsets to yuv_p_ and
-// the arrays VP8*ModeOffsets[];
-// +----+ YUV Samples area. See VP8Scan[] for accessing the blocks.
-// Y_OFF |YYYY| <- original samples (enc->yuv_in_)
-// |YYYY|
-// |YYYY|
-// |YYYY|
-// U_OFF |UUVV| V_OFF (=U_OFF + 8)
-// |UUVV|
-// +----+
-// Y_OFF |YYYY| <- compressed/decoded samples ('yuv_out_')
-// |YYYY| There are two buffers like this ('yuv_out_'/'yuv_out2_')
-// |YYYY|
-// |YYYY|
-// U_OFF |UUVV| V_OFF
-// |UUVV|
-// x2 (for yuv_out2_)
-// +----+ Prediction area ('yuv_p_', size = PRED_SIZE)
-// I16DC16 |YYYY| Intra16 predictions (16x16 block each)
-// |YYYY|
-// |YYYY|
-// |YYYY|
-// I16TM16 |YYYY|
-// |YYYY|
-// |YYYY|
-// |YYYY|
-// I16VE16 |YYYY|
-// |YYYY|
-// |YYYY|
-// |YYYY|
-// I16HE16 |YYYY|
-// |YYYY|
-// |YYYY|
-// |YYYY|
-// +----+ Chroma U/V predictions (16x8 block each)
-// C8DC8 |UUVV|
-// |UUVV|
-// C8TM8 |UUVV|
-// |UUVV|
-// C8VE8 |UUVV|
-// |UUVV|
-// C8HE8 |UUVV|
-// |UUVV|
-// +----+ Intra 4x4 predictions (4x4 block each)
-// |YYYY| I4DC4 I4TM4 I4VE4 I4HE4
-// |YYYY| I4RD4 I4VR4 I4LD4 I4VL4
-// |YY..| I4HD4 I4HU4 I4TMP
-// +----+
-#define BPS 16 // this is the common stride
-#define Y_SIZE (BPS * 16)
-#define UV_SIZE (BPS * 8)
-#define YUV_SIZE (Y_SIZE + UV_SIZE)
-#define PRED_SIZE (6 * 16 * BPS + 12 * BPS)
-#define Y_OFF (0)
-#define U_OFF (Y_SIZE)
-#define V_OFF (U_OFF + 8)
-#define ALIGN_CST 15
-#define DO_ALIGN(PTR) ((uintptr_t)((PTR) + ALIGN_CST) & ~ALIGN_CST)
-
-extern const int VP8Scan[16 + 4 + 4]; // in quant.c
-extern const int VP8UVModeOffsets[4]; // in analyze.c
+// the arrays VP8*ModeOffsets[].
+// * YUV Samples area (yuv_in_/yuv_out_/yuv_out2_)
+// (see VP8Scan[] for accessing the blocks, along with
+// Y_OFF_ENC/U_OFF_ENC/V_OFF_ENC):
+// +----+----+
+// Y_OFF_ENC |YYYY|UUVV|
+// U_OFF_ENC |YYYY|UUVV|
+// V_OFF_ENC |YYYY|....| <- 25% wasted U/V area
+// |YYYY|....|
+// +----+----+
+// * Prediction area ('yuv_p_', size = PRED_SIZE_ENC)
+// Intra16 predictions (16x16 block each, two per row):
+// |I16DC16|I16TM16|
+// |I16VE16|I16HE16|
+// Chroma U/V predictions (16x8 block each, two per row):
+// |C8DC8|C8TM8|
+// |C8VE8|C8HE8|
+// Intra 4x4 predictions (4x4 block each)
+// |I4DC4 I4TM4 I4VE4 I4HE4|I4RD4 I4VR4 I4LD4 I4VL4|
+// |I4HD4 I4HU4 I4TMP .....|.......................| <- ~31% wasted
+#define YUV_SIZE_ENC (BPS * 16)
+#define PRED_SIZE_ENC (32 * BPS + 16 * BPS + 8 * BPS) // I16+Chroma+I4 preds
+#define Y_OFF_ENC (0)
+#define U_OFF_ENC (16)
+#define V_OFF_ENC (16 + 8)
+
+extern const int VP8Scan[16]; // in quant.c
+extern const int VP8UVModeOffsets[4]; // in analyze.c
extern const int VP8I16ModeOffsets[4];
extern const int VP8I4ModeOffsets[NUM_BMODES];
// Layout of prediction blocks
// intra 16x16
#define I16DC16 (0 * 16 * BPS)
-#define I16TM16 (1 * 16 * BPS)
-#define I16VE16 (2 * 16 * BPS)
-#define I16HE16 (3 * 16 * BPS)
+#define I16TM16 (I16DC16 + 16)
+#define I16VE16 (1 * 16 * BPS)
+#define I16HE16 (I16VE16 + 16)
// chroma 8x8, two U/V blocks side by side (hence: 16x8 each)
-#define C8DC8 (4 * 16 * BPS)
-#define C8TM8 (4 * 16 * BPS + 8 * BPS)
-#define C8VE8 (5 * 16 * BPS)
-#define C8HE8 (5 * 16 * BPS + 8 * BPS)
+#define C8DC8 (2 * 16 * BPS)
+#define C8TM8 (C8DC8 + 1 * 16)
+#define C8VE8 (2 * 16 * BPS + 8 * BPS)
+#define C8HE8 (C8VE8 + 1 * 16)
// intra 4x4
-#define I4DC4 (6 * 16 * BPS + 0)
-#define I4TM4 (6 * 16 * BPS + 4)
-#define I4VE4 (6 * 16 * BPS + 8)
-#define I4HE4 (6 * 16 * BPS + 12)
-#define I4RD4 (6 * 16 * BPS + 4 * BPS + 0)
-#define I4VR4 (6 * 16 * BPS + 4 * BPS + 4)
-#define I4LD4 (6 * 16 * BPS + 4 * BPS + 8)
-#define I4VL4 (6 * 16 * BPS + 4 * BPS + 12)
-#define I4HD4 (6 * 16 * BPS + 8 * BPS + 0)
-#define I4HU4 (6 * 16 * BPS + 8 * BPS + 4)
-#define I4TMP (6 * 16 * BPS + 8 * BPS + 8)
+#define I4DC4 (3 * 16 * BPS + 0)
+#define I4TM4 (I4DC4 + 4)
+#define I4VE4 (I4DC4 + 8)
+#define I4HE4 (I4DC4 + 12)
+#define I4RD4 (I4DC4 + 16)
+#define I4VR4 (I4DC4 + 20)
+#define I4LD4 (I4DC4 + 24)
+#define I4VL4 (I4DC4 + 28)
+#define I4HD4 (3 * 16 * BPS + 4 * BPS)
+#define I4HU4 (I4HD4 + 4)
+#define I4TMP (I4HD4 + 8)
typedef int64_t score_t; // type used for scores, rate, distortion
+// Note that MAX_COST is not the maximum allowed by sizeof(score_t),
+// in order to allow overflowing computations.
#define MAX_COST ((score_t)0x7fffffffffffffLL)
#define QFIX 17
#define BIAS(b) ((b) << (QFIX - 8))
// Fun fact: this is the _only_ line where we're actually being lossy and
// discarding bits.
-static WEBP_INLINE int QUANTDIV(int n, int iQ, int B) {
- return (n * iQ + B) >> QFIX;
+static WEBP_INLINE int QUANTDIV(uint32_t n, uint32_t iQ, uint32_t B) {
+ return (int)((n * iQ + B) >> QFIX);
}
-extern const uint8_t VP8Zigzag[16];
+
+// Uncomment the following to remove token-buffer code:
+// #define DISABLE_TOKEN_BUFFER
//------------------------------------------------------------------------------
// Headers
@@ -169,6 +131,8 @@ typedef uint32_t proba_t; // 16b + 16b
typedef uint8_t ProbaArray[NUM_CTX][NUM_PROBAS];
typedef proba_t StatsArray[NUM_CTX][NUM_PROBAS];
typedef uint16_t CostArray[NUM_CTX][MAX_VARIABLE_LEVEL + 1];
+typedef const uint16_t* (*CostArrayPtr)[NUM_CTX]; // for easy casting
+typedef const uint16_t* CostArrayMap[16][NUM_CTX];
typedef double LFStats[NUM_MB_SEGMENTS][MAX_LF_LEVELS]; // filter stats
typedef struct VP8Encoder VP8Encoder;
@@ -179,19 +143,20 @@ typedef struct {
int update_map_; // whether to update the segment map or not.
// must be 0 if there's only 1 segment.
int size_; // bit-cost for transmitting the segment map
-} VP8SegmentHeader;
+} VP8EncSegmentHeader;
// Struct collecting all frame-persistent probabilities.
typedef struct {
uint8_t segments_[3]; // probabilities for segment tree
uint8_t skip_proba_; // final probability of being skipped.
- ProbaArray coeffs_[NUM_TYPES][NUM_BANDS]; // 924 bytes
+ ProbaArray coeffs_[NUM_TYPES][NUM_BANDS]; // 1056 bytes
StatsArray stats_[NUM_TYPES][NUM_BANDS]; // 4224 bytes
- CostArray level_cost_[NUM_TYPES][NUM_BANDS]; // 11.4k
+ CostArray level_cost_[NUM_TYPES][NUM_BANDS]; // 13056 bytes
+ CostArrayMap remapped_costs_[NUM_TYPES]; // 1536 bytes
int dirty_; // if true, need to call VP8CalculateLevelCosts()
int use_skip_proba_; // Note: we always use skip_proba for now.
int nb_skip_; // number of skipped blocks
-} VP8Proba;
+} VP8EncProba;
// Filter parameters. Not actually used in the code (we don't perform
// the in-loop filtering), but filled from user's config
@@ -200,7 +165,7 @@ typedef struct {
int level_; // base filter level [0..63]
int sharpness_; // [0..7]
int i4x4_lf_delta_; // delta filter level for i4x4 relative to i16x16
-} VP8FilterHeader;
+} VP8EncFilterHeader;
//------------------------------------------------------------------------------
// Informations about the macroblocks.
@@ -217,8 +182,8 @@ typedef struct {
typedef struct VP8Matrix {
uint16_t q_[16]; // quantizer steps
uint16_t iq_[16]; // reciprocals, fixed point.
- uint16_t bias_[16]; // rounding bias
- uint16_t zthresh_[16]; // value under which a coefficient is zeroed
+ uint32_t bias_[16]; // rounding bias
+ uint32_t zthresh_[16]; // value below which a coefficient is zeroed
uint16_t sharpen_[16]; // frequency boosters for slight sharpening
} VP8Matrix;
@@ -229,16 +194,19 @@ typedef struct {
int beta_; // filter-susceptibility, range [0,255].
int quant_; // final segment quantizer.
int fstrength_; // final in-loop filtering strength
+ int max_edge_; // max edge delta (for filtering strength)
+ int min_disto_; // minimum distortion required to trigger filtering record
// reactivities
int lambda_i16_, lambda_i4_, lambda_uv_;
int lambda_mode_, lambda_trellis_, tlambda_;
int lambda_trellis_i16_, lambda_trellis_i4_, lambda_trellis_uv_;
} VP8SegmentInfo;
-// Handy transcient struct to accumulate score and info during RD-optimization
+// Handy transient struct to accumulate score and info during RD-optimization
// and mode evaluation.
typedef struct {
- score_t D, SD, R, score; // Distortion, spectral distortion, rate, score.
+ score_t D, SD; // Distortion, spectral distortion
+ score_t H, R, score; // header bits, rate, score.
int16_t y_dc_levels[16]; // Quantized levels for luma-DC, luma-AC, chroma.
int16_t y_ac_levels[16][16];
int16_t uv_levels[4 + 4][16];
@@ -252,12 +220,11 @@ typedef struct {
// right neighbouring data (samples, predictions, contexts, ...)
typedef struct {
int x_, y_; // current macroblock
- int y_offset_, uv_offset_; // offset to the luma / chroma planes
int y_stride_, uv_stride_; // respective strides
- uint8_t* yuv_in_; // borrowed from enc_ (for now)
- uint8_t* yuv_out_; // ''
- uint8_t* yuv_out2_; // ''
- uint8_t* yuv_p_; // ''
+ uint8_t* yuv_in_; // input samples
+ uint8_t* yuv_out_; // output samples
+ uint8_t* yuv_out2_; // secondary buffer swapped with yuv_out_.
+ uint8_t* yuv_p_; // scratch buffer for prediction
VP8Encoder* enc_; // back-pointer
VP8MBInfo* mb_; // current macroblock
VP8BitWriter* bw_; // current bit-writer
@@ -273,24 +240,44 @@ typedef struct {
uint64_t uv_bits_; // macroblock bit-cost for chroma
LFStats* lf_stats_; // filter stats (borrowed from enc_)
int do_trellis_; // if true, perform extra level optimisation
- int done_; // true when scan is finished
+ int count_down_; // number of mb still to be processed
+ int count_down0_; // starting counter value (for progress)
int percent0_; // saved initial progress percent
+
+ uint8_t* y_left_; // left luma samples (addressable from index -1 to 15).
+ uint8_t* u_left_; // left u samples (addressable from index -1 to 7)
+ uint8_t* v_left_; // left v samples (addressable from index -1 to 7)
+
+ uint8_t* y_top_; // top luma samples at position 'x_'
+ uint8_t* uv_top_; // top u/v samples at position 'x_', packed as 16 bytes
+
+ // memory for storing y/u/v_left_
+ uint8_t yuv_left_mem_[17 + 16 + 16 + 8 + WEBP_ALIGN_CST];
+ // memory for yuv_*
+ uint8_t yuv_mem_[3 * YUV_SIZE_ENC + PRED_SIZE_ENC + WEBP_ALIGN_CST];
} VP8EncIterator;
// in iterator.c
-// must be called first.
+// must be called first
void VP8IteratorInit(VP8Encoder* const enc, VP8EncIterator* const it);
-// restart a scan.
+// restart a scan
void VP8IteratorReset(VP8EncIterator* const it);
-// import samples from source
-void VP8IteratorImport(const VP8EncIterator* const it);
+// reset iterator position to row 'y'
+void VP8IteratorSetRow(VP8EncIterator* const it, int y);
+// set count down (=number of iterations to go)
+void VP8IteratorSetCountDown(VP8EncIterator* const it, int count_down);
+// return true if iteration is finished
+int VP8IteratorIsDone(const VP8EncIterator* const it);
+// Import uncompressed samples from source.
+// If tmp_32 is not NULL, import boundary samples too.
+// tmp_32 is a 32-bytes scratch buffer that must be aligned in memory.
+void VP8IteratorImport(VP8EncIterator* const it, uint8_t* tmp_32);
// export decimated samples
void VP8IteratorExport(const VP8EncIterator* const it);
-// go to next macroblock. Returns !done_. If *block_to_save is non-null, will
-// save the boundary values to top_/left_ arrays. block_to_save can be
-// it->yuv_out_ or it->yuv_in_.
-int VP8IteratorNext(VP8EncIterator* const it,
- const uint8_t* const block_to_save);
+// go to next macroblock. Returns false if not finished.
+int VP8IteratorNext(VP8EncIterator* const it);
+// save the yuv_out_ boundary values to top_/left_ arrays for next iterations.
+void VP8IteratorSaveBoundary(VP8EncIterator* const it);
// Report progression based on macroblock rows. Return 0 for user-abort request.
int VP8IteratorProgress(const VP8EncIterator* const it,
int final_delta_percent);
@@ -314,44 +301,43 @@ void VP8SetSegment(const VP8EncIterator* const it, int segment);
//------------------------------------------------------------------------------
// Paginated token buffer
-// WIP: #define USE_TOKEN_BUFFER
+typedef struct VP8Tokens VP8Tokens; // struct details in token.c
-#ifdef USE_TOKEN_BUFFER
+typedef struct {
+#if !defined(DISABLE_TOKEN_BUFFER)
+ VP8Tokens* pages_; // first page
+ VP8Tokens** last_page_; // last page
+ uint16_t* tokens_; // set to (*last_page_)->tokens_
+ int left_; // how many free tokens left before the page is full
+ int page_size_; // number of tokens per page
+#endif
+ int error_; // true in case of malloc error
+} VP8TBuffer;
-#define MAX_NUM_TOKEN 2048
+// initialize an empty buffer
+void VP8TBufferInit(VP8TBuffer* const b, int page_size);
+void VP8TBufferClear(VP8TBuffer* const b); // de-allocate pages memory
-typedef struct VP8Tokens VP8Tokens;
-struct VP8Tokens {
- uint16_t tokens_[MAX_NUM_TOKEN]; // bit#15: bit, bits 0..14: slot
- int left_;
- VP8Tokens* next_;
-};
+#if !defined(DISABLE_TOKEN_BUFFER)
-typedef struct {
- VP8Tokens* rows_;
- uint16_t* tokens_; // set to (*last_)->tokens_
- VP8Tokens** last_;
- int left_;
- int error_; // true in case of malloc error
-} VP8TBuffer;
+// Finalizes bitstream when probabilities are known.
+// Deletes the allocated token memory if final_pass is true.
+int VP8EmitTokens(VP8TBuffer* const b, VP8BitWriter* const bw,
+ const uint8_t* const probas, int final_pass);
-void VP8TBufferInit(VP8TBuffer* const b); // initialize an empty buffer
-int VP8TBufferNewPage(VP8TBuffer* const b); // allocate a new page
-void VP8TBufferClear(VP8TBuffer* const b); // de-allocate memory
+// record the coding of coefficients without knowing the probabilities yet
+int VP8RecordCoeffTokens(const int ctx, const int coeff_type,
+ int first, int last,
+ const int16_t* const coeffs,
+ VP8TBuffer* const tokens);
-int VP8EmitTokens(const VP8TBuffer* const b, VP8BitWriter* const bw,
- const uint8_t* const probas);
+// Estimate the final coded size given a set of 'probas'.
+size_t VP8EstimateTokenSize(VP8TBuffer* const b, const uint8_t* const probas);
-static WEBP_INLINE int VP8AddToken(VP8TBuffer* const b,
- int bit, int proba_idx) {
- if (b->left_ > 0 || VP8TBufferNewPage(b)) {
- const int slot = --b->left_;
- b->tokens_[slot] = (bit << 15) | proba_idx;
- }
- return bit;
-}
+// unused for now
+void VP8TokenToStats(const VP8TBuffer* const b, proba_t* const stats);
-#endif // USE_TOKEN_BUFFER
+#endif // !DISABLE_TOKEN_BUFFER
//------------------------------------------------------------------------------
// VP8Encoder
@@ -361,8 +347,8 @@ struct VP8Encoder {
WebPPicture* pic_; // input / output picture
// headers
- VP8FilterHeader filter_hdr_; // filtering information
- VP8SegmentHeader segment_hdr_; // segment information
+ VP8EncFilterHeader filter_hdr_; // filtering information
+ VP8EncSegmentHeader segment_hdr_; // segment information
int profile_; // VP8's profile, deduced from Config.
@@ -376,6 +362,7 @@ struct VP8Encoder {
// per-partition boolean decoders.
VP8BitWriter bw_; // part0
VP8BitWriter parts_[MAX_NUM_PARTITIONS]; // token partitions
+ VP8TBuffer tokens_; // token buffer
int percent_; // for progress
@@ -383,17 +370,13 @@ struct VP8Encoder {
int has_alpha_;
uint8_t* alpha_data_; // non-NULL if transparency is present
uint32_t alpha_data_size_;
-
- // enhancement layer
- int use_layer_;
- VP8BitWriter layer_bw_;
- uint8_t* layer_data_;
- size_t layer_data_size_;
+ WebPWorker alpha_worker_;
// quantization info (one set of DC/AC dequant factor per segment)
VP8SegmentInfo dqm_[NUM_MB_SEGMENTS];
int base_quant_; // nominal quantizer value. Only used
// for relative coding of segments' quant.
+ int alpha_; // global susceptibility (<=> complexity)
int uv_alpha_; // U/V quantization susceptibility
// global offset of quantizers, shared by all segments
int dq_y1_dc_;
@@ -401,34 +384,29 @@ struct VP8Encoder {
int dq_uv_dc_, dq_uv_ac_;
// probabilities and statistics
- VP8Proba proba_;
- uint64_t sse_[4]; // sum of Y/U/V/A squared errors for all macroblocks
- uint64_t sse_count_; // pixel count for the sse_[] stats
- int coded_size_;
- int residual_bytes_[3][4];
- int block_count_[3];
+ VP8EncProba proba_;
+ uint64_t sse_[4]; // sum of Y/U/V/A squared errors for all macroblocks
+ uint64_t sse_count_; // pixel count for the sse_[] stats
+ int coded_size_;
+ int residual_bytes_[3][4];
+ int block_count_[3];
// quality/speed settings
- int method_; // 0=fastest, 6=best/slowest.
- int rd_opt_level_; // Deduced from method_.
- int max_i4_header_bits_; // partition #0 safeness factor
+ int method_; // 0=fastest, 6=best/slowest.
+ VP8RDLevel rd_opt_level_; // Deduced from method_.
+ int max_i4_header_bits_; // partition #0 safeness factor
+ int thread_level_; // derived from config->thread_level
+ int do_search_; // derived from config->target_XXX
+ int use_tokens_; // if true, use token buffer
// Memory
VP8MBInfo* mb_info_; // contextual macroblock infos (mb_w_ + 1)
uint8_t* preds_; // predictions modes: (4*mb_w+1) * (4*mb_h+1)
uint32_t* nz_; // non-zero bit context: mb_w+1
- uint8_t* yuv_in_; // input samples
- uint8_t* yuv_out_; // output samples
- uint8_t* yuv_out2_; // secondary scratch out-buffer. swapped with yuv_out_.
- uint8_t* yuv_p_; // scratch buffer for prediction
- uint8_t *y_top_; // top luma samples.
- uint8_t *uv_top_; // top u/v samples.
- // U and V are packed into 16 pixels (8 U + 8 V)
- uint8_t *y_left_; // left luma samples (adressable from index -1 to 15).
- uint8_t *u_left_; // left u samples (adressable from index -1 to 7)
- uint8_t *v_left_; // left v samples (adressable from index -1 to 7)
-
- LFStats *lf_stats_; // autofilter stats (if NULL, autofilter is off)
+ uint8_t* y_top_; // top luma samples.
+ uint8_t* uv_top_; // top u/v samples.
+ // U and V are packed into 16 bytes (8 U + 8 V)
+ LFStats* lf_stats_; // autofilter stats (if NULL, autofilter is off)
};
//------------------------------------------------------------------------------
@@ -441,7 +419,7 @@ extern const uint8_t
// Reset the token probabilities to their initial (default) values
void VP8DefaultProbas(VP8Encoder* const enc);
// Write the token probabilities
-void VP8WriteProbas(VP8BitWriter* const bw, const VP8Proba* const probas);
+void VP8WriteProbas(VP8BitWriter* const bw, const VP8EncProba* const probas);
// Writes the partition #0 modes (that is: all intra modes)
void VP8CodeIntraModes(VP8Encoder* const enc);
@@ -454,7 +432,11 @@ int VP8EncWrite(VP8Encoder* const enc);
void VP8EncFreeBitWriters(VP8Encoder* const enc);
// in frame.c
-extern const uint8_t VP8EncBands[16 + 1];
+extern const uint8_t VP8Cat3[];
+extern const uint8_t VP8Cat4[];
+extern const uint8_t VP8Cat5[];
+extern const uint8_t VP8Cat6[];
+
// Form all the four Intra16x16 predictions in the yuv_p_ cache
void VP8MakeLuma16Preds(const VP8EncIterator* const it);
// Form all the four Chroma8x8 predictions in the yuv_p_ cache
@@ -466,9 +448,9 @@ void VP8MakeIntra4Preds(const VP8EncIterator* const it);
int VP8GetCostLuma16(VP8EncIterator* const it, const VP8ModeScore* const rd);
int VP8GetCostLuma4(VP8EncIterator* const it, const int16_t levels[16]);
int VP8GetCostUV(VP8EncIterator* const it, const VP8ModeScore* const rd);
-// Main stat / coding passes
+// Main coding calls
int VP8EncLoop(VP8Encoder* const enc);
-int VP8StatLoop(VP8Encoder* const enc);
+int VP8EncTokenLoop(VP8Encoder* const enc);
// in webpenc.c
// Assign an error code to a picture. Return false for convenience.
@@ -485,18 +467,14 @@ int VP8EncAnalyze(VP8Encoder* const enc);
// Sets up segment's quantization values, base_quant_ and filter strengths.
void VP8SetSegmentParams(VP8Encoder* const enc, float quality);
// Pick best modes and fills the levels. Returns true if skipped.
-int VP8Decimate(VP8EncIterator* const it, VP8ModeScore* const rd, int rd_opt);
+int VP8Decimate(VP8EncIterator* const it, VP8ModeScore* const rd,
+ VP8RDLevel rd_opt);
// in alpha.c
void VP8EncInitAlpha(VP8Encoder* const enc); // initialize alpha compression
+int VP8EncStartAlpha(VP8Encoder* const enc); // start alpha coding process
int VP8EncFinishAlpha(VP8Encoder* const enc); // finalize compressed data
-void VP8EncDeleteAlpha(VP8Encoder* const enc); // delete compressed data
-
- // in layer.c
-void VP8EncInitLayer(VP8Encoder* const enc); // init everything
-void VP8EncCodeLayerBlock(VP8EncIterator* it); // code one more macroblock
-int VP8EncFinishLayer(VP8Encoder* const enc); // finalize coding
-void VP8EncDeleteLayer(VP8Encoder* enc); // reclaim memory
+int VP8EncDeleteAlpha(VP8Encoder* const enc); // delete compressed data
// in filter.c
@@ -516,9 +494,38 @@ void VP8InitFilter(VP8EncIterator* const it);
void VP8StoreFilterStats(VP8EncIterator* const it);
void VP8AdjustFilterStrength(VP8EncIterator* const it);
+// returns the approximate filtering strength needed to smooth a edge
+// step of 'delta', given a sharpness parameter 'sharpness'.
+int VP8FilterStrengthFromDelta(int sharpness, int delta);
+
+ // misc utils for picture_*.c:
+
+// Remove reference to the ARGB/YUVA buffer (doesn't free anything).
+void WebPPictureResetBuffers(WebPPicture* const picture);
+
+// Allocates ARGB buffer of given dimension (previous one is always free'd).
+// Preserves the YUV(A) buffer. Returns false in case of error (invalid param,
+// out-of-memory).
+int WebPPictureAllocARGB(WebPPicture* const picture, int width, int height);
+
+// Allocates YUVA buffer of given dimension (previous one is always free'd).
+// Uses picture->csp to determine whether an alpha buffer is needed.
+// Preserves the ARGB buffer.
+// Returns false in case of error (invalid param, out-of-memory).
+int WebPPictureAllocYUVA(WebPPicture* const picture, int width, int height);
+
+ // in near_lossless.c
+// Near lossless preprocessing in RGB color-space.
+int VP8ApplyNearLossless(int xsize, int ysize, uint32_t* argb, int quality);
+// Near lossless adjustment for predictors.
+void VP8ApplyNearLosslessPredict(int xsize, int ysize, int pred_bits,
+ const uint32_t* argb_orig,
+ uint32_t* argb, uint32_t* argb_scratch,
+ const uint32_t* const transform_data,
+ int quality, int subtract_green);
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/drivers/webp/enc/vp8l.c b/drivers/webp/enc/vp8l.c
index f4eb6e783f..284995e830 100644
--- a/drivers/webp/enc/vp8l.c
+++ b/drivers/webp/enc/vp8l.c
@@ -1,8 +1,10 @@
// Copyright 2012 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// main entry for the lossless encoder.
@@ -11,7 +13,6 @@
//
#include <assert.h>
-#include <stdio.h>
#include <stdlib.h>
#include "./backward_references.h"
@@ -21,28 +22,107 @@
#include "../utils/bit_writer.h"
#include "../utils/huffman_encode.h"
#include "../utils/utils.h"
-#include "../format_constants.h"
+#include "webp/format_constants.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
+#include "./delta_palettization.h"
#define PALETTE_KEY_RIGHT_SHIFT 22 // Key for 1K buffer.
-#define MAX_HUFF_IMAGE_SIZE (16 * 1024 * 1024)
-#define MAX_COLORS_FOR_GRAPH 64
+// Maximum number of histogram images (sub-blocks).
+#define MAX_HUFF_IMAGE_SIZE 2600
-// -----------------------------------------------------------------------------
-// Palette
+// Palette reordering for smaller sum of deltas (and for smaller storage).
-static int CompareColors(const void* p1, const void* p2) {
+static int PaletteCompareColorsForQsort(const void* p1, const void* p2) {
const uint32_t a = *(const uint32_t*)p1;
const uint32_t b = *(const uint32_t*)p2;
- return (a < b) ? -1 : (a > b) ? 1 : 0;
+ assert(a != b);
+ return (a < b) ? -1 : 1;
+}
+
+static WEBP_INLINE uint32_t PaletteComponentDistance(uint32_t v) {
+ return (v <= 128) ? v : (256 - v);
+}
+
+// Computes a value that is related to the entropy created by the
+// palette entry diff.
+//
+// Note that the last & 0xff is a no-operation in the next statement, but
+// removed by most compilers and is here only for regularity of the code.
+static WEBP_INLINE uint32_t PaletteColorDistance(uint32_t col1, uint32_t col2) {
+ const uint32_t diff = VP8LSubPixels(col1, col2);
+ const int kMoreWeightForRGBThanForAlpha = 9;
+ uint32_t score;
+ score = PaletteComponentDistance((diff >> 0) & 0xff);
+ score += PaletteComponentDistance((diff >> 8) & 0xff);
+ score += PaletteComponentDistance((diff >> 16) & 0xff);
+ score *= kMoreWeightForRGBThanForAlpha;
+ score += PaletteComponentDistance((diff >> 24) & 0xff);
+ return score;
+}
+
+static WEBP_INLINE void SwapColor(uint32_t* const col1, uint32_t* const col2) {
+ const uint32_t tmp = *col1;
+ *col1 = *col2;
+ *col2 = tmp;
+}
+
+static void GreedyMinimizeDeltas(uint32_t palette[], int num_colors) {
+ // Find greedily always the closest color of the predicted color to minimize
+ // deltas in the palette. This reduces storage needs since the
+ // palette is stored with delta encoding.
+ uint32_t predict = 0x00000000;
+ int i, k;
+ for (i = 0; i < num_colors; ++i) {
+ int best_ix = i;
+ uint32_t best_score = ~0U;
+ for (k = i; k < num_colors; ++k) {
+ const uint32_t cur_score = PaletteColorDistance(palette[k], predict);
+ if (best_score > cur_score) {
+ best_score = cur_score;
+ best_ix = k;
+ }
+ }
+ SwapColor(&palette[best_ix], &palette[i]);
+ predict = palette[i];
+ }
+}
+
+// The palette has been sorted by alpha. This function checks if the other
+// components of the palette have a monotonic development with regards to
+// position in the palette. If all have monotonic development, there is
+// no benefit to re-organize them greedily. A monotonic development
+// would be spotted in green-only situations (like lossy alpha) or gray-scale
+// images.
+static int PaletteHasNonMonotonousDeltas(uint32_t palette[], int num_colors) {
+ uint32_t predict = 0x000000;
+ int i;
+ uint8_t sign_found = 0x00;
+ for (i = 0; i < num_colors; ++i) {
+ const uint32_t diff = VP8LSubPixels(palette[i], predict);
+ const uint8_t rd = (diff >> 16) & 0xff;
+ const uint8_t gd = (diff >> 8) & 0xff;
+ const uint8_t bd = (diff >> 0) & 0xff;
+ if (rd != 0x00) {
+ sign_found |= (rd < 0x80) ? 1 : 2;
+ }
+ if (gd != 0x00) {
+ sign_found |= (gd < 0x80) ? 8 : 16;
+ }
+ if (bd != 0x00) {
+ sign_found |= (bd < 0x80) ? 64 : 128;
+ }
+ predict = palette[i];
+ }
+ return (sign_found & (sign_found << 1)) != 0; // two consequent signs.
}
+// -----------------------------------------------------------------------------
+// Palette
+
// If number of colors in the image is less than or equal to MAX_PALETTE_SIZE,
// creates a palette and returns true, else returns false.
static int AnalyzeAndCreatePalette(const WebPPicture* const pic,
+ int low_effort,
uint32_t palette[MAX_PALETTE_SIZE],
int* const palette_size) {
int i, x, y, key;
@@ -85,7 +165,7 @@ static int AnalyzeAndCreatePalette(const WebPPicture* const pic,
argb += pic->argb_stride;
}
- // TODO(skal): could we reuse in_use[] to speed up ApplyPalette()?
+ // TODO(skal): could we reuse in_use[] to speed up EncodePalette()?
num_colors = 0;
for (i = 0; i < (int)(sizeof(in_use) / sizeof(in_use[0])); ++i) {
if (in_use[i]) {
@@ -93,106 +173,272 @@ static int AnalyzeAndCreatePalette(const WebPPicture* const pic,
++num_colors;
}
}
-
- qsort(palette, num_colors, sizeof(*palette), CompareColors);
*palette_size = num_colors;
+ qsort(palette, num_colors, sizeof(*palette), PaletteCompareColorsForQsort);
+ if (!low_effort && PaletteHasNonMonotonousDeltas(palette, num_colors)) {
+ GreedyMinimizeDeltas(palette, num_colors);
+ }
return 1;
}
+// These five modes are evaluated and their respective entropy is computed.
+typedef enum {
+ kDirect = 0,
+ kSpatial = 1,
+ kSubGreen = 2,
+ kSpatialSubGreen = 3,
+ kPalette = 4,
+ kNumEntropyIx = 5
+} EntropyIx;
+
+typedef enum {
+ kHistoAlpha = 0,
+ kHistoAlphaPred,
+ kHistoGreen,
+ kHistoGreenPred,
+ kHistoRed,
+ kHistoRedPred,
+ kHistoBlue,
+ kHistoBluePred,
+ kHistoRedSubGreen,
+ kHistoRedPredSubGreen,
+ kHistoBlueSubGreen,
+ kHistoBluePredSubGreen,
+ kHistoPalette,
+ kHistoTotal // Must be last.
+} HistoIx;
+
+static void AddSingleSubGreen(uint32_t p, uint32_t* r, uint32_t* b) {
+ const uint32_t green = p >> 8; // The upper bits are masked away later.
+ ++r[((p >> 16) - green) & 0xff];
+ ++b[(p - green) & 0xff];
+}
+
+static void AddSingle(uint32_t p,
+ uint32_t* a, uint32_t* r, uint32_t* g, uint32_t* b) {
+ ++a[p >> 24];
+ ++r[(p >> 16) & 0xff];
+ ++g[(p >> 8) & 0xff];
+ ++b[(p & 0xff)];
+}
+
static int AnalyzeEntropy(const uint32_t* argb,
int width, int height, int argb_stride,
- double* const nonpredicted_bits,
- double* const predicted_bits) {
- int x, y;
- const uint32_t* last_line = NULL;
- uint32_t last_pix = argb[0]; // so we're sure that pix_diff == 0
-
- VP8LHistogram* nonpredicted = NULL;
- VP8LHistogram* predicted =
- (VP8LHistogram*)malloc(2 * sizeof(*predicted));
- if (predicted == NULL) return 0;
- nonpredicted = predicted + 1;
-
- VP8LHistogramInit(predicted, 0);
- VP8LHistogramInit(nonpredicted, 0);
- for (y = 0; y < height; ++y) {
- for (x = 0; x < width; ++x) {
- const uint32_t pix = argb[x];
- const uint32_t pix_diff = VP8LSubPixels(pix, last_pix);
- if (pix_diff == 0) continue;
- if (last_line != NULL && pix == last_line[x]) {
- continue;
+ int use_palette,
+ EntropyIx* const min_entropy_ix,
+ int* const red_and_blue_always_zero) {
+ // Allocate histogram set with cache_bits = 0.
+ uint32_t* const histo =
+ (uint32_t*)WebPSafeCalloc(kHistoTotal, sizeof(*histo) * 256);
+ if (histo != NULL) {
+ int i, x, y;
+ const uint32_t* prev_row = argb;
+ const uint32_t* curr_row = argb + argb_stride;
+ for (y = 1; y < height; ++y) {
+ uint32_t prev_pix = curr_row[0];
+ for (x = 1; x < width; ++x) {
+ const uint32_t pix = curr_row[x];
+ const uint32_t pix_diff = VP8LSubPixels(pix, prev_pix);
+ if ((pix_diff == 0) || (pix == prev_row[x])) continue;
+ prev_pix = pix;
+ AddSingle(pix,
+ &histo[kHistoAlpha * 256],
+ &histo[kHistoRed * 256],
+ &histo[kHistoGreen * 256],
+ &histo[kHistoBlue * 256]);
+ AddSingle(pix_diff,
+ &histo[kHistoAlphaPred * 256],
+ &histo[kHistoRedPred * 256],
+ &histo[kHistoGreenPred * 256],
+ &histo[kHistoBluePred * 256]);
+ AddSingleSubGreen(pix,
+ &histo[kHistoRedSubGreen * 256],
+ &histo[kHistoBlueSubGreen * 256]);
+ AddSingleSubGreen(pix_diff,
+ &histo[kHistoRedPredSubGreen * 256],
+ &histo[kHistoBluePredSubGreen * 256]);
+ {
+ // Approximate the palette by the entropy of the multiplicative hash.
+ const int hash = ((pix + (pix >> 19)) * 0x39c5fba7) >> 24;
+ ++histo[kHistoPalette * 256 + (hash & 0xff)];
+ }
+ }
+ prev_row = curr_row;
+ curr_row += argb_stride;
+ }
+ {
+ double entropy_comp[kHistoTotal];
+ double entropy[kNumEntropyIx];
+ EntropyIx k;
+ EntropyIx last_mode_to_analyze =
+ use_palette ? kPalette : kSpatialSubGreen;
+ int j;
+ // Let's add one zero to the predicted histograms. The zeros are removed
+ // too efficiently by the pix_diff == 0 comparison, at least one of the
+ // zeros is likely to exist.
+ ++histo[kHistoRedPredSubGreen * 256];
+ ++histo[kHistoBluePredSubGreen * 256];
+ ++histo[kHistoRedPred * 256];
+ ++histo[kHistoGreenPred * 256];
+ ++histo[kHistoBluePred * 256];
+ ++histo[kHistoAlphaPred * 256];
+
+ for (j = 0; j < kHistoTotal; ++j) {
+ entropy_comp[j] = VP8LBitsEntropy(&histo[j * 256], 256, NULL);
+ }
+ entropy[kDirect] = entropy_comp[kHistoAlpha] +
+ entropy_comp[kHistoRed] +
+ entropy_comp[kHistoGreen] +
+ entropy_comp[kHistoBlue];
+ entropy[kSpatial] = entropy_comp[kHistoAlphaPred] +
+ entropy_comp[kHistoRedPred] +
+ entropy_comp[kHistoGreenPred] +
+ entropy_comp[kHistoBluePred];
+ entropy[kSubGreen] = entropy_comp[kHistoAlpha] +
+ entropy_comp[kHistoRedSubGreen] +
+ entropy_comp[kHistoGreen] +
+ entropy_comp[kHistoBlueSubGreen];
+ entropy[kSpatialSubGreen] = entropy_comp[kHistoAlphaPred] +
+ entropy_comp[kHistoRedPredSubGreen] +
+ entropy_comp[kHistoGreenPred] +
+ entropy_comp[kHistoBluePredSubGreen];
+ // Palette mode seems more efficient in a breakeven case. Bias with 1.0.
+ entropy[kPalette] = entropy_comp[kHistoPalette] - 1.0;
+
+ *min_entropy_ix = kDirect;
+ for (k = kDirect + 1; k <= last_mode_to_analyze; ++k) {
+ if (entropy[*min_entropy_ix] > entropy[k]) {
+ *min_entropy_ix = k;
+ }
}
- last_pix = pix;
+ *red_and_blue_always_zero = 1;
+ // Let's check if the histogram of the chosen entropy mode has
+ // non-zero red and blue values. If all are zero, we can later skip
+ // the cross color optimization.
{
- const PixOrCopy pix_token = PixOrCopyCreateLiteral(pix);
- const PixOrCopy pix_diff_token = PixOrCopyCreateLiteral(pix_diff);
- VP8LHistogramAddSinglePixOrCopy(nonpredicted, &pix_token);
- VP8LHistogramAddSinglePixOrCopy(predicted, &pix_diff_token);
+ static const uint8_t kHistoPairs[5][2] = {
+ { kHistoRed, kHistoBlue },
+ { kHistoRedPred, kHistoBluePred },
+ { kHistoRedSubGreen, kHistoBlueSubGreen },
+ { kHistoRedPredSubGreen, kHistoBluePredSubGreen },
+ { kHistoRed, kHistoBlue }
+ };
+ const uint32_t* const red_histo =
+ &histo[256 * kHistoPairs[*min_entropy_ix][0]];
+ const uint32_t* const blue_histo =
+ &histo[256 * kHistoPairs[*min_entropy_ix][1]];
+ for (i = 1; i < 256; ++i) {
+ if ((red_histo[i] | blue_histo[i]) != 0) {
+ *red_and_blue_always_zero = 0;
+ break;
+ }
+ }
}
}
- last_line = argb;
- argb += argb_stride;
+ free(histo);
+ return 1;
+ } else {
+ return 0;
}
- *nonpredicted_bits = VP8LHistogramEstimateBitsBulk(nonpredicted);
- *predicted_bits = VP8LHistogramEstimateBitsBulk(predicted);
- free(predicted);
- return 1;
}
-static int VP8LEncAnalyze(VP8LEncoder* const enc, WebPImageHint image_hint) {
+static int GetHistoBits(int method, int use_palette, int width, int height) {
+ // Make tile size a function of encoding method (Range: 0 to 6).
+ int histo_bits = (use_palette ? 9 : 7) - method;
+ while (1) {
+ const int huff_image_size = VP8LSubSampleSize(width, histo_bits) *
+ VP8LSubSampleSize(height, histo_bits);
+ if (huff_image_size <= MAX_HUFF_IMAGE_SIZE) break;
+ ++histo_bits;
+ }
+ return (histo_bits < MIN_HUFFMAN_BITS) ? MIN_HUFFMAN_BITS :
+ (histo_bits > MAX_HUFFMAN_BITS) ? MAX_HUFFMAN_BITS : histo_bits;
+}
+
+static int GetTransformBits(int method, int histo_bits) {
+ const int max_transform_bits = (method < 4) ? 6 : (method > 4) ? 4 : 5;
+ return (histo_bits > max_transform_bits) ? max_transform_bits : histo_bits;
+}
+
+static int AnalyzeAndInit(VP8LEncoder* const enc) {
const WebPPicture* const pic = enc->pic_;
+ const int width = pic->width;
+ const int height = pic->height;
+ const int pix_cnt = width * height;
+ const WebPConfig* const config = enc->config_;
+ const int method = config->method;
+ const int low_effort = (config->method == 0);
+ // we round the block size up, so we're guaranteed to have
+ // at max MAX_REFS_BLOCK_PER_IMAGE blocks used:
+ int refs_block_size = (pix_cnt - 1) / MAX_REFS_BLOCK_PER_IMAGE + 1;
assert(pic != NULL && pic->argb != NULL);
+ enc->use_cross_color_ = 0;
+ enc->use_predict_ = 0;
+ enc->use_subtract_green_ = 0;
enc->use_palette_ =
- AnalyzeAndCreatePalette(pic, enc->palette_, &enc->palette_size_);
-
- if (image_hint == WEBP_HINT_GRAPH) {
- if (enc->use_palette_ && enc->palette_size_ < MAX_COLORS_FOR_GRAPH) {
- enc->use_palette_ = 0;
+ AnalyzeAndCreatePalette(pic, low_effort,
+ enc->palette_, &enc->palette_size_);
+
+ // TODO(jyrki): replace the decision to be based on an actual estimate
+ // of entropy, or even spatial variance of entropy.
+ enc->histo_bits_ = GetHistoBits(method, enc->use_palette_,
+ pic->width, pic->height);
+ enc->transform_bits_ = GetTransformBits(method, enc->histo_bits_);
+
+ if (low_effort) {
+ // AnalyzeEntropy is somewhat slow.
+ enc->use_predict_ = !enc->use_palette_;
+ enc->use_subtract_green_ = !enc->use_palette_;
+ enc->use_cross_color_ = 0;
+ } else {
+ int red_and_blue_always_zero;
+ EntropyIx min_entropy_ix;
+ if (!AnalyzeEntropy(pic->argb, width, height, pic->argb_stride,
+ enc->use_palette_, &min_entropy_ix,
+ &red_and_blue_always_zero)) {
+ return 0;
}
+ enc->use_palette_ = (min_entropy_ix == kPalette);
+ enc->use_subtract_green_ =
+ (min_entropy_ix == kSubGreen) || (min_entropy_ix == kSpatialSubGreen);
+ enc->use_predict_ =
+ (min_entropy_ix == kSpatial) || (min_entropy_ix == kSpatialSubGreen);
+ enc->use_cross_color_ = red_and_blue_always_zero ? 0 : enc->use_predict_;
}
- if (!enc->use_palette_) {
- if (image_hint == WEBP_HINT_PHOTO) {
- enc->use_predict_ = 1;
- enc->use_cross_color_ = 1;
- } else {
- double non_pred_entropy, pred_entropy;
- if (!AnalyzeEntropy(pic->argb, pic->width, pic->height, pic->argb_stride,
- &non_pred_entropy, &pred_entropy)) {
- return 0;
- }
- if (pred_entropy < 0.95 * non_pred_entropy) {
- enc->use_predict_ = 1;
- // TODO(vikasa): Observed some correlation of cross_color transform with
- // predict. Need to investigate this further and add separate heuristic
- // for setting use_cross_color flag.
- enc->use_cross_color_ = 1;
- }
- }
- }
+ if (!VP8LHashChainInit(&enc->hash_chain_, pix_cnt)) return 0;
+
+ // palette-friendly input typically uses less literals
+ // -> reduce block size a bit
+ if (enc->use_palette_) refs_block_size /= 2;
+ VP8LBackwardRefsInit(&enc->refs_[0], refs_block_size);
+ VP8LBackwardRefsInit(&enc->refs_[1], refs_block_size);
return 1;
}
+// Returns false in case of memory error.
static int GetHuffBitLengthsAndCodes(
const VP8LHistogramSet* const histogram_image,
HuffmanTreeCode* const huffman_codes) {
int i, k;
- int ok = 1;
+ int ok = 0;
uint64_t total_length_size = 0;
uint8_t* mem_buf = NULL;
const int histogram_image_size = histogram_image->size;
+ int max_num_symbols = 0;
+ uint8_t* buf_rle = NULL;
+ HuffmanTree* huff_tree = NULL;
// Iterate over all histograms and get the aggregate number of codes used.
for (i = 0; i < histogram_image_size; ++i) {
const VP8LHistogram* const histo = histogram_image->histograms[i];
HuffmanTreeCode* const codes = &huffman_codes[5 * i];
for (k = 0; k < 5; ++k) {
- const int num_symbols = (k == 0) ? VP8LHistogramNumCodes(histo)
- : (k == 4) ? NUM_DISTANCE_CODES
- : 256;
+ const int num_symbols =
+ (k == 0) ? VP8LHistogramNumCodes(histo->palette_code_bits_) :
+ (k == 4) ? NUM_DISTANCE_CODES : 256;
codes[k].num_symbols = num_symbols;
total_length_size += num_symbols;
}
@@ -204,10 +450,8 @@ static int GetHuffBitLengthsAndCodes(
uint8_t* lengths;
mem_buf = (uint8_t*)WebPSafeCalloc(total_length_size,
sizeof(*lengths) + sizeof(*codes));
- if (mem_buf == NULL) {
- ok = 0;
- goto End;
- }
+ if (mem_buf == NULL) goto End;
+
codes = (uint16_t*)mem_buf;
lengths = (uint8_t*)&codes[total_length_size];
for (i = 0; i < 5 * histogram_image_size; ++i) {
@@ -216,22 +460,35 @@ static int GetHuffBitLengthsAndCodes(
huffman_codes[i].code_lengths = lengths;
codes += bit_length;
lengths += bit_length;
+ if (max_num_symbols < bit_length) {
+ max_num_symbols = bit_length;
+ }
}
}
+ buf_rle = (uint8_t*)WebPSafeMalloc(1ULL, max_num_symbols);
+ huff_tree = (HuffmanTree*)WebPSafeMalloc(3ULL * max_num_symbols,
+ sizeof(*huff_tree));
+ if (buf_rle == NULL || huff_tree == NULL) goto End;
+
// Create Huffman trees.
for (i = 0; i < histogram_image_size; ++i) {
HuffmanTreeCode* const codes = &huffman_codes[5 * i];
VP8LHistogram* const histo = histogram_image->histograms[i];
- ok = ok && VP8LCreateHuffmanTree(histo->literal_, 15, codes + 0);
- ok = ok && VP8LCreateHuffmanTree(histo->red_, 15, codes + 1);
- ok = ok && VP8LCreateHuffmanTree(histo->blue_, 15, codes + 2);
- ok = ok && VP8LCreateHuffmanTree(histo->alpha_, 15, codes + 3);
- ok = ok && VP8LCreateHuffmanTree(histo->distance_, 15, codes + 4);
+ VP8LCreateHuffmanTree(histo->literal_, 15, buf_rle, huff_tree, codes + 0);
+ VP8LCreateHuffmanTree(histo->red_, 15, buf_rle, huff_tree, codes + 1);
+ VP8LCreateHuffmanTree(histo->blue_, 15, buf_rle, huff_tree, codes + 2);
+ VP8LCreateHuffmanTree(histo->alpha_, 15, buf_rle, huff_tree, codes + 3);
+ VP8LCreateHuffmanTree(histo->distance_, 15, buf_rle, huff_tree, codes + 4);
}
-
+ ok = 1;
End:
- if (!ok) free(mem_buf);
+ WebPSafeFree(huff_tree);
+ WebPSafeFree(buf_rle);
+ if (!ok) {
+ WebPSafeFree(mem_buf);
+ memset(huffman_codes, 0, 5 * histogram_image_size * sizeof(*huffman_codes));
+ }
return ok;
}
@@ -251,9 +508,9 @@ static void StoreHuffmanTreeOfHuffmanTreeToBitMask(
break;
}
}
- VP8LWriteBits(bw, 4, codes_to_store - 4);
+ VP8LPutBits(bw, codes_to_store - 4, 4);
for (i = 0; i < codes_to_store; ++i) {
- VP8LWriteBits(bw, 3, code_length_bitdepth[kStorageOrder[i]]);
+ VP8LPutBits(bw, code_length_bitdepth[kStorageOrder[i]], 3);
}
}
@@ -281,49 +538,46 @@ static void StoreHuffmanTreeToBitMask(
for (i = 0; i < num_tokens; ++i) {
const int ix = tokens[i].code;
const int extra_bits = tokens[i].extra_bits;
- VP8LWriteBits(bw, huffman_code->code_lengths[ix], huffman_code->codes[ix]);
+ VP8LPutBits(bw, huffman_code->codes[ix], huffman_code->code_lengths[ix]);
switch (ix) {
case 16:
- VP8LWriteBits(bw, 2, extra_bits);
+ VP8LPutBits(bw, extra_bits, 2);
break;
case 17:
- VP8LWriteBits(bw, 3, extra_bits);
+ VP8LPutBits(bw, extra_bits, 3);
break;
case 18:
- VP8LWriteBits(bw, 7, extra_bits);
+ VP8LPutBits(bw, extra_bits, 7);
break;
}
}
}
-static int StoreFullHuffmanCode(VP8LBitWriter* const bw,
- const HuffmanTreeCode* const tree) {
- int ok = 0;
+// 'huff_tree' and 'tokens' are pre-alloacted buffers.
+static void StoreFullHuffmanCode(VP8LBitWriter* const bw,
+ HuffmanTree* const huff_tree,
+ HuffmanTreeToken* const tokens,
+ const HuffmanTreeCode* const tree) {
uint8_t code_length_bitdepth[CODE_LENGTH_CODES] = { 0 };
uint16_t code_length_bitdepth_symbols[CODE_LENGTH_CODES] = { 0 };
const int max_tokens = tree->num_symbols;
int num_tokens;
HuffmanTreeCode huffman_code;
- HuffmanTreeToken* const tokens =
- (HuffmanTreeToken*)WebPSafeMalloc((uint64_t)max_tokens, sizeof(*tokens));
- if (tokens == NULL) return 0;
-
huffman_code.num_symbols = CODE_LENGTH_CODES;
huffman_code.code_lengths = code_length_bitdepth;
huffman_code.codes = code_length_bitdepth_symbols;
- VP8LWriteBits(bw, 1, 0);
+ VP8LPutBits(bw, 0, 1);
num_tokens = VP8LCreateCompressedHuffmanTree(tree, tokens, max_tokens);
{
- int histogram[CODE_LENGTH_CODES] = { 0 };
+ uint32_t histogram[CODE_LENGTH_CODES] = { 0 };
+ uint8_t buf_rle[CODE_LENGTH_CODES] = { 0 };
int i;
for (i = 0; i < num_tokens; ++i) {
++histogram[tokens[i].code];
}
- if (!VP8LCreateHuffmanTree(histogram, 7, &huffman_code)) {
- goto End;
- }
+ VP8LCreateHuffmanTree(histogram, 7, buf_rle, huff_tree, &huffman_code);
}
StoreHuffmanTreeOfHuffmanTreeToBitMask(bw, code_length_bitdepth);
@@ -350,24 +604,23 @@ static int StoreFullHuffmanCode(VP8LBitWriter* const bw,
}
write_trimmed_length = (trimmed_length > 1 && trailing_zero_bits > 12);
length = write_trimmed_length ? trimmed_length : num_tokens;
- VP8LWriteBits(bw, 1, write_trimmed_length);
+ VP8LPutBits(bw, write_trimmed_length, 1);
if (write_trimmed_length) {
const int nbits = VP8LBitsLog2Ceiling(trimmed_length - 1);
const int nbitpairs = (nbits == 0) ? 1 : (nbits + 1) / 2;
- VP8LWriteBits(bw, 3, nbitpairs - 1);
+ VP8LPutBits(bw, nbitpairs - 1, 3);
assert(trimmed_length >= 2);
- VP8LWriteBits(bw, nbitpairs * 2, trimmed_length - 2);
+ VP8LPutBits(bw, trimmed_length - 2, nbitpairs * 2);
}
StoreHuffmanTreeToBitMask(bw, tokens, length, &huffman_code);
}
- ok = 1;
- End:
- free(tokens);
- return ok;
}
-static int StoreHuffmanCode(VP8LBitWriter* const bw,
- const HuffmanTreeCode* const huffman_code) {
+// 'huff_tree' and 'tokens' are pre-alloacted buffers.
+static void StoreHuffmanCode(VP8LBitWriter* const bw,
+ HuffmanTree* const huff_tree,
+ HuffmanTreeToken* const tokens,
+ const HuffmanTreeCode* const huffman_code) {
int i;
int count = 0;
int symbols[2] = { 0, 0 };
@@ -384,163 +637,248 @@ static int StoreHuffmanCode(VP8LBitWriter* const bw,
if (count == 0) { // emit minimal tree for empty cases
// bits: small tree marker: 1, count-1: 0, large 8-bit code: 0, code: 0
- VP8LWriteBits(bw, 4, 0x01);
- return 1;
+ VP8LPutBits(bw, 0x01, 4);
} else if (count <= 2 && symbols[0] < kMaxSymbol && symbols[1] < kMaxSymbol) {
- VP8LWriteBits(bw, 1, 1); // Small tree marker to encode 1 or 2 symbols.
- VP8LWriteBits(bw, 1, count - 1);
+ VP8LPutBits(bw, 1, 1); // Small tree marker to encode 1 or 2 symbols.
+ VP8LPutBits(bw, count - 1, 1);
if (symbols[0] <= 1) {
- VP8LWriteBits(bw, 1, 0); // Code bit for small (1 bit) symbol value.
- VP8LWriteBits(bw, 1, symbols[0]);
+ VP8LPutBits(bw, 0, 1); // Code bit for small (1 bit) symbol value.
+ VP8LPutBits(bw, symbols[0], 1);
} else {
- VP8LWriteBits(bw, 1, 1);
- VP8LWriteBits(bw, 8, symbols[0]);
+ VP8LPutBits(bw, 1, 1);
+ VP8LPutBits(bw, symbols[0], 8);
}
if (count == 2) {
- VP8LWriteBits(bw, 8, symbols[1]);
+ VP8LPutBits(bw, symbols[1], 8);
}
- return 1;
} else {
- return StoreFullHuffmanCode(bw, huffman_code);
+ StoreFullHuffmanCode(bw, huff_tree, tokens, huffman_code);
}
}
-static void WriteHuffmanCode(VP8LBitWriter* const bw,
- const HuffmanTreeCode* const code, int index) {
- const int depth = code->code_lengths[index];
- const int symbol = code->codes[index];
- VP8LWriteBits(bw, depth, symbol);
+static WEBP_INLINE void WriteHuffmanCode(VP8LBitWriter* const bw,
+ const HuffmanTreeCode* const code,
+ int code_index) {
+ const int depth = code->code_lengths[code_index];
+ const int symbol = code->codes[code_index];
+ VP8LPutBits(bw, symbol, depth);
}
-static void StoreImageToBitMask(
+static WEBP_INLINE void WriteHuffmanCodeWithExtraBits(
+ VP8LBitWriter* const bw,
+ const HuffmanTreeCode* const code,
+ int code_index,
+ int bits,
+ int n_bits) {
+ const int depth = code->code_lengths[code_index];
+ const int symbol = code->codes[code_index];
+ VP8LPutBits(bw, (bits << depth) | symbol, depth + n_bits);
+}
+
+static WebPEncodingError StoreImageToBitMask(
VP8LBitWriter* const bw, int width, int histo_bits,
- const VP8LBackwardRefs* const refs,
+ VP8LBackwardRefs* const refs,
const uint16_t* histogram_symbols,
const HuffmanTreeCode* const huffman_codes) {
+ const int histo_xsize = histo_bits ? VP8LSubSampleSize(width, histo_bits) : 1;
+ const int tile_mask = (histo_bits == 0) ? 0 : -(1 << histo_bits);
// x and y trace the position in the image.
int x = 0;
int y = 0;
- const int histo_xsize = histo_bits ? VP8LSubSampleSize(width, histo_bits) : 1;
- int i;
- for (i = 0; i < refs->size; ++i) {
- const PixOrCopy* const v = &refs->refs[i];
- const int histogram_ix = histogram_symbols[histo_bits ?
- (y >> histo_bits) * histo_xsize +
- (x >> histo_bits) : 0];
- const HuffmanTreeCode* const codes = huffman_codes + 5 * histogram_ix;
- if (PixOrCopyIsCacheIdx(v)) {
- const int code = PixOrCopyCacheIdx(v);
- const int literal_ix = 256 + NUM_LENGTH_CODES + code;
- WriteHuffmanCode(bw, codes, literal_ix);
- } else if (PixOrCopyIsLiteral(v)) {
+ int tile_x = x & tile_mask;
+ int tile_y = y & tile_mask;
+ int histogram_ix = histogram_symbols[0];
+ const HuffmanTreeCode* codes = huffman_codes + 5 * histogram_ix;
+ VP8LRefsCursor c = VP8LRefsCursorInit(refs);
+ while (VP8LRefsCursorOk(&c)) {
+ const PixOrCopy* const v = c.cur_pos;
+ if ((tile_x != (x & tile_mask)) || (tile_y != (y & tile_mask))) {
+ tile_x = x & tile_mask;
+ tile_y = y & tile_mask;
+ histogram_ix = histogram_symbols[(y >> histo_bits) * histo_xsize +
+ (x >> histo_bits)];
+ codes = huffman_codes + 5 * histogram_ix;
+ }
+ if (PixOrCopyIsLiteral(v)) {
static const int order[] = { 1, 2, 0, 3 };
int k;
for (k = 0; k < 4; ++k) {
const int code = PixOrCopyLiteral(v, order[k]);
WriteHuffmanCode(bw, codes + k, code);
}
+ } else if (PixOrCopyIsCacheIdx(v)) {
+ const int code = PixOrCopyCacheIdx(v);
+ const int literal_ix = 256 + NUM_LENGTH_CODES + code;
+ WriteHuffmanCode(bw, codes, literal_ix);
} else {
int bits, n_bits;
- int code, distance;
+ int code;
- PrefixEncode(v->len, &code, &n_bits, &bits);
- WriteHuffmanCode(bw, codes, 256 + code);
- VP8LWriteBits(bw, n_bits, bits);
+ const int distance = PixOrCopyDistance(v);
+ VP8LPrefixEncode(v->len, &code, &n_bits, &bits);
+ WriteHuffmanCodeWithExtraBits(bw, codes, 256 + code, bits, n_bits);
- distance = PixOrCopyDistance(v);
- PrefixEncode(distance, &code, &n_bits, &bits);
+ // Don't write the distance with the extra bits code since
+ // the distance can be up to 18 bits of extra bits, and the prefix
+ // 15 bits, totaling to 33, and our PutBits only supports up to 32 bits.
+ // TODO(jyrki): optimize this further.
+ VP8LPrefixEncode(distance, &code, &n_bits, &bits);
WriteHuffmanCode(bw, codes + 4, code);
- VP8LWriteBits(bw, n_bits, bits);
+ VP8LPutBits(bw, bits, n_bits);
}
x += PixOrCopyLength(v);
while (x >= width) {
x -= width;
++y;
}
+ VP8LRefsCursorNext(&c);
}
+ return bw->error_ ? VP8_ENC_ERROR_OUT_OF_MEMORY : VP8_ENC_OK;
}
// Special case of EncodeImageInternal() for cache-bits=0, histo_bits=31
-static int EncodeImageNoHuffman(VP8LBitWriter* const bw,
- const uint32_t* const argb,
- int width, int height, int quality) {
+static WebPEncodingError EncodeImageNoHuffman(VP8LBitWriter* const bw,
+ const uint32_t* const argb,
+ VP8LHashChain* const hash_chain,
+ VP8LBackwardRefs refs_array[2],
+ int width, int height,
+ int quality) {
int i;
- int ok = 0;
- VP8LBackwardRefs refs;
+ int max_tokens = 0;
+ WebPEncodingError err = VP8_ENC_OK;
+ VP8LBackwardRefs* refs;
+ HuffmanTreeToken* tokens = NULL;
HuffmanTreeCode huffman_codes[5] = { { 0, NULL, NULL } };
const uint16_t histogram_symbols[1] = { 0 }; // only one tree, one symbol
- VP8LHistogramSet* const histogram_image = VP8LAllocateHistogramSet(1, 0);
- if (histogram_image == NULL) return 0;
+ int cache_bits = 0;
+ VP8LHistogramSet* histogram_image = NULL;
+ HuffmanTree* const huff_tree = (HuffmanTree*)WebPSafeMalloc(
+ 3ULL * CODE_LENGTH_CODES, sizeof(*huff_tree));
+ if (huff_tree == NULL) {
+ err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ goto Error;
+ }
// Calculate backward references from ARGB image.
- if (!VP8LGetBackwardReferences(width, height, argb, quality, 0, 1, &refs)) {
+ refs = VP8LGetBackwardReferences(width, height, argb, quality, 0, &cache_bits,
+ hash_chain, refs_array);
+ if (refs == NULL) {
+ err = VP8_ENC_ERROR_OUT_OF_MEMORY;
goto Error;
}
+ histogram_image = VP8LAllocateHistogramSet(1, cache_bits);
+ if (histogram_image == NULL) {
+ err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ goto Error;
+ }
+
// Build histogram image and symbols from backward references.
- VP8LHistogramStoreRefs(&refs, histogram_image->histograms[0]);
+ VP8LHistogramStoreRefs(refs, histogram_image->histograms[0]);
// Create Huffman bit lengths and codes for each histogram image.
assert(histogram_image->size == 1);
if (!GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
+ err = VP8_ENC_ERROR_OUT_OF_MEMORY;
goto Error;
}
// No color cache, no Huffman image.
- VP8LWriteBits(bw, 1, 0);
+ VP8LPutBits(bw, 0, 1);
- // Store Huffman codes.
+ // Find maximum number of symbols for the huffman tree-set.
for (i = 0; i < 5; ++i) {
HuffmanTreeCode* const codes = &huffman_codes[i];
- if (!StoreHuffmanCode(bw, codes)) {
- goto Error;
+ if (max_tokens < codes->num_symbols) {
+ max_tokens = codes->num_symbols;
}
+ }
+
+ tokens = (HuffmanTreeToken*)WebPSafeMalloc(max_tokens, sizeof(*tokens));
+ if (tokens == NULL) {
+ err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ goto Error;
+ }
+
+ // Store Huffman codes.
+ for (i = 0; i < 5; ++i) {
+ HuffmanTreeCode* const codes = &huffman_codes[i];
+ StoreHuffmanCode(bw, huff_tree, tokens, codes);
ClearHuffmanTreeIfOnlyOneSymbol(codes);
}
// Store actual literals.
- StoreImageToBitMask(bw, width, 0, &refs, histogram_symbols, huffman_codes);
- ok = 1;
+ err = StoreImageToBitMask(bw, width, 0, refs, histogram_symbols,
+ huffman_codes);
Error:
- free(histogram_image);
- VP8LClearBackwardRefs(&refs);
- free(huffman_codes[0].codes);
- return ok;
+ WebPSafeFree(tokens);
+ WebPSafeFree(huff_tree);
+ VP8LFreeHistogramSet(histogram_image);
+ WebPSafeFree(huffman_codes[0].codes);
+ return err;
}
-static int EncodeImageInternal(VP8LBitWriter* const bw,
- const uint32_t* const argb,
- int width, int height, int quality,
- int cache_bits, int histogram_bits) {
- int ok = 0;
- const int use_2d_locality = 1;
- const int use_color_cache = (cache_bits > 0);
+static WebPEncodingError EncodeImageInternal(VP8LBitWriter* const bw,
+ const uint32_t* const argb,
+ VP8LHashChain* const hash_chain,
+ VP8LBackwardRefs refs_array[2],
+ int width, int height, int quality,
+ int low_effort, int* cache_bits,
+ int histogram_bits,
+ size_t init_byte_position,
+ int* const hdr_size,
+ int* const data_size) {
+ WebPEncodingError err = VP8_ENC_OK;
const uint32_t histogram_image_xysize =
VP8LSubSampleSize(width, histogram_bits) *
VP8LSubSampleSize(height, histogram_bits);
- VP8LHistogramSet* histogram_image =
- VP8LAllocateHistogramSet(histogram_image_xysize, 0);
+ VP8LHistogramSet* histogram_image = NULL;
+ VP8LHistogramSet* tmp_histos = NULL;
int histogram_image_size = 0;
size_t bit_array_size = 0;
+ HuffmanTree* huff_tree = NULL;
+ HuffmanTreeToken* tokens = NULL;
HuffmanTreeCode* huffman_codes = NULL;
VP8LBackwardRefs refs;
+ VP8LBackwardRefs* best_refs;
uint16_t* const histogram_symbols =
- (uint16_t*)WebPSafeMalloc((uint64_t)histogram_image_xysize,
+ (uint16_t*)WebPSafeMalloc(histogram_image_xysize,
sizeof(*histogram_symbols));
assert(histogram_bits >= MIN_HUFFMAN_BITS);
assert(histogram_bits <= MAX_HUFFMAN_BITS);
- if (histogram_image == NULL || histogram_symbols == NULL) goto Error;
+ assert(hdr_size != NULL);
+ assert(data_size != NULL);
+ VP8LBackwardRefsInit(&refs, refs_array[0].block_size_);
+ if (histogram_symbols == NULL) {
+ err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ goto Error;
+ }
+
+ *cache_bits = MAX_COLOR_CACHE_BITS;
+ // 'best_refs' is the reference to the best backward refs and points to one
+ // of refs_array[0] or refs_array[1].
// Calculate backward references from ARGB image.
- if (!VP8LGetBackwardReferences(width, height, argb, quality, cache_bits,
- use_2d_locality, &refs)) {
+ best_refs = VP8LGetBackwardReferences(width, height, argb, quality,
+ low_effort, cache_bits, hash_chain,
+ refs_array);
+ if (best_refs == NULL || !VP8LBackwardRefsCopy(best_refs, &refs)) {
+ err = VP8_ENC_ERROR_OUT_OF_MEMORY;
goto Error;
}
+ histogram_image =
+ VP8LAllocateHistogramSet(histogram_image_xysize, *cache_bits);
+ tmp_histos = VP8LAllocateHistogramSet(2, *cache_bits);
+ if (histogram_image == NULL || tmp_histos == NULL) {
+ err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ goto Error;
+ }
+
// Build histogram image and symbols from backward references.
- if (!VP8LGetHistoImageSymbols(width, height, &refs,
- quality, histogram_bits, cache_bits,
- histogram_image,
- histogram_symbols)) {
+ if (!VP8LGetHistoImageSymbols(width, height, &refs, quality, low_effort,
+ histogram_bits, *cache_bits, histogram_image,
+ tmp_histos, histogram_symbols)) {
+ err = VP8_ENC_ERROR_OUT_OF_MEMORY;
goto Error;
}
// Create Huffman bit lengths and codes for each histogram image.
@@ -548,171 +886,167 @@ static int EncodeImageInternal(VP8LBitWriter* const bw,
bit_array_size = 5 * histogram_image_size;
huffman_codes = (HuffmanTreeCode*)WebPSafeCalloc(bit_array_size,
sizeof(*huffman_codes));
+ // Note: some histogram_image entries may point to tmp_histos[], so the latter
+ // need to outlive the following call to GetHuffBitLengthsAndCodes().
if (huffman_codes == NULL ||
!GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
+ err = VP8_ENC_ERROR_OUT_OF_MEMORY;
goto Error;
}
+ // Free combined histograms.
+ VP8LFreeHistogramSet(histogram_image);
+ histogram_image = NULL;
+
+ // Free scratch histograms.
+ VP8LFreeHistogramSet(tmp_histos);
+ tmp_histos = NULL;
// Color Cache parameters.
- VP8LWriteBits(bw, 1, use_color_cache);
- if (use_color_cache) {
- VP8LWriteBits(bw, 4, cache_bits);
+ if (*cache_bits > 0) {
+ VP8LPutBits(bw, 1, 1);
+ VP8LPutBits(bw, *cache_bits, 4);
+ } else {
+ VP8LPutBits(bw, 0, 1);
}
// Huffman image + meta huffman.
{
const int write_histogram_image = (histogram_image_size > 1);
- VP8LWriteBits(bw, 1, write_histogram_image);
+ VP8LPutBits(bw, write_histogram_image, 1);
if (write_histogram_image) {
uint32_t* const histogram_argb =
- (uint32_t*)WebPSafeMalloc((uint64_t)histogram_image_xysize,
+ (uint32_t*)WebPSafeMalloc(histogram_image_xysize,
sizeof(*histogram_argb));
int max_index = 0;
uint32_t i;
- if (histogram_argb == NULL) goto Error;
+ if (histogram_argb == NULL) {
+ err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ goto Error;
+ }
for (i = 0; i < histogram_image_xysize; ++i) {
- const int index = histogram_symbols[i] & 0xffff;
- histogram_argb[i] = 0xff000000 | (index << 8);
- if (index >= max_index) {
- max_index = index + 1;
+ const int symbol_index = histogram_symbols[i] & 0xffff;
+ histogram_argb[i] = (symbol_index << 8);
+ if (symbol_index >= max_index) {
+ max_index = symbol_index + 1;
}
}
histogram_image_size = max_index;
- VP8LWriteBits(bw, 3, histogram_bits - 2);
- ok = EncodeImageNoHuffman(bw, histogram_argb,
- VP8LSubSampleSize(width, histogram_bits),
- VP8LSubSampleSize(height, histogram_bits),
- quality);
- free(histogram_argb);
- if (!ok) goto Error;
+ VP8LPutBits(bw, histogram_bits - 2, 3);
+ err = EncodeImageNoHuffman(bw, histogram_argb, hash_chain, refs_array,
+ VP8LSubSampleSize(width, histogram_bits),
+ VP8LSubSampleSize(height, histogram_bits),
+ quality);
+ WebPSafeFree(histogram_argb);
+ if (err != VP8_ENC_OK) goto Error;
}
}
// Store Huffman codes.
{
int i;
+ int max_tokens = 0;
+ huff_tree = (HuffmanTree*)WebPSafeMalloc(3ULL * CODE_LENGTH_CODES,
+ sizeof(*huff_tree));
+ if (huff_tree == NULL) {
+ err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ goto Error;
+ }
+ // Find maximum number of symbols for the huffman tree-set.
for (i = 0; i < 5 * histogram_image_size; ++i) {
HuffmanTreeCode* const codes = &huffman_codes[i];
- if (!StoreHuffmanCode(bw, codes)) goto Error;
+ if (max_tokens < codes->num_symbols) {
+ max_tokens = codes->num_symbols;
+ }
+ }
+ tokens = (HuffmanTreeToken*)WebPSafeMalloc(max_tokens,
+ sizeof(*tokens));
+ if (tokens == NULL) {
+ err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ goto Error;
+ }
+ for (i = 0; i < 5 * histogram_image_size; ++i) {
+ HuffmanTreeCode* const codes = &huffman_codes[i];
+ StoreHuffmanCode(bw, huff_tree, tokens, codes);
ClearHuffmanTreeIfOnlyOneSymbol(codes);
}
}
- // Free combined histograms.
- free(histogram_image);
- histogram_image = NULL;
+ *hdr_size = (int)(VP8LBitWriterNumBytes(bw) - init_byte_position);
// Store actual literals.
- StoreImageToBitMask(bw, width, histogram_bits, &refs,
- histogram_symbols, huffman_codes);
- ok = 1;
+ err = StoreImageToBitMask(bw, width, histogram_bits, &refs,
+ histogram_symbols, huffman_codes);
+ *data_size =
+ (int)(VP8LBitWriterNumBytes(bw) - init_byte_position - *hdr_size);
Error:
- if (!ok) free(histogram_image);
-
- VP8LClearBackwardRefs(&refs);
+ WebPSafeFree(tokens);
+ WebPSafeFree(huff_tree);
+ VP8LFreeHistogramSet(histogram_image);
+ VP8LFreeHistogramSet(tmp_histos);
+ VP8LBackwardRefsClear(&refs);
if (huffman_codes != NULL) {
- free(huffman_codes->codes);
- free(huffman_codes);
+ WebPSafeFree(huffman_codes->codes);
+ WebPSafeFree(huffman_codes);
}
- free(histogram_symbols);
- return ok;
+ WebPSafeFree(histogram_symbols);
+ return err;
}
// -----------------------------------------------------------------------------
// Transforms
-// Check if it would be a good idea to subtract green from red and blue. We
-// only impact entropy in red/blue components, don't bother to look at others.
-static int EvalAndApplySubtractGreen(VP8LEncoder* const enc,
- int width, int height,
- VP8LBitWriter* const bw) {
- if (!enc->use_palette_) {
- int i;
- const uint32_t* const argb = enc->argb_;
- double bit_cost_before, bit_cost_after;
- VP8LHistogram* const histo = (VP8LHistogram*)malloc(sizeof(*histo));
- if (histo == NULL) return 0;
-
- VP8LHistogramInit(histo, 1);
- for (i = 0; i < width * height; ++i) {
- const uint32_t c = argb[i];
- ++histo->red_[(c >> 16) & 0xff];
- ++histo->blue_[(c >> 0) & 0xff];
- }
- bit_cost_before = VP8LHistogramEstimateBits(histo);
-
- VP8LHistogramInit(histo, 1);
- for (i = 0; i < width * height; ++i) {
- const uint32_t c = argb[i];
- const int green = (c >> 8) & 0xff;
- ++histo->red_[((c >> 16) - green) & 0xff];
- ++histo->blue_[((c >> 0) - green) & 0xff];
- }
- bit_cost_after = VP8LHistogramEstimateBits(histo);
- free(histo);
-
- // Check if subtracting green yields low entropy.
- enc->use_subtract_green_ = (bit_cost_after < bit_cost_before);
- if (enc->use_subtract_green_) {
- VP8LWriteBits(bw, 1, TRANSFORM_PRESENT);
- VP8LWriteBits(bw, 2, SUBTRACT_GREEN);
- VP8LSubtractGreenFromBlueAndRed(enc->argb_, width * height);
- }
- }
- return 1;
+static void ApplySubtractGreen(VP8LEncoder* const enc, int width, int height,
+ VP8LBitWriter* const bw) {
+ VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
+ VP8LPutBits(bw, SUBTRACT_GREEN, 2);
+ VP8LSubtractGreenFromBlueAndRed(enc->argb_, width * height);
}
-static int ApplyPredictFilter(const VP8LEncoder* const enc,
- int width, int height, int quality,
- VP8LBitWriter* const bw) {
+static WebPEncodingError ApplyPredictFilter(const VP8LEncoder* const enc,
+ int width, int height,
+ int quality, int low_effort,
+ VP8LBitWriter* const bw) {
const int pred_bits = enc->transform_bits_;
const int transform_width = VP8LSubSampleSize(width, pred_bits);
const int transform_height = VP8LSubSampleSize(height, pred_bits);
- VP8LResidualImage(width, height, pred_bits, enc->argb_, enc->argb_scratch_,
- enc->transform_data_);
- VP8LWriteBits(bw, 1, TRANSFORM_PRESENT);
- VP8LWriteBits(bw, 2, PREDICTOR_TRANSFORM);
+ VP8LResidualImage(width, height, pred_bits, low_effort, enc->argb_,
+ enc->argb_scratch_, enc->transform_data_);
+ VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
+ VP8LPutBits(bw, PREDICTOR_TRANSFORM, 2);
assert(pred_bits >= 2);
- VP8LWriteBits(bw, 3, pred_bits - 2);
- if (!EncodeImageNoHuffman(bw, enc->transform_data_,
- transform_width, transform_height, quality)) {
- return 0;
- }
- return 1;
+ VP8LPutBits(bw, pred_bits - 2, 3);
+ return EncodeImageNoHuffman(bw, enc->transform_data_,
+ (VP8LHashChain*)&enc->hash_chain_,
+ (VP8LBackwardRefs*)enc->refs_, // cast const away
+ transform_width, transform_height,
+ quality);
}
-static int ApplyCrossColorFilter(const VP8LEncoder* const enc,
- int width, int height, int quality,
- VP8LBitWriter* const bw) {
+static WebPEncodingError ApplyCrossColorFilter(const VP8LEncoder* const enc,
+ int width, int height,
+ int quality,
+ VP8LBitWriter* const bw) {
const int ccolor_transform_bits = enc->transform_bits_;
const int transform_width = VP8LSubSampleSize(width, ccolor_transform_bits);
const int transform_height = VP8LSubSampleSize(height, ccolor_transform_bits);
- const int step = (quality == 0) ? 32 : 8;
- VP8LColorSpaceTransform(width, height, ccolor_transform_bits, step,
+ VP8LColorSpaceTransform(width, height, ccolor_transform_bits, quality,
enc->argb_, enc->transform_data_);
- VP8LWriteBits(bw, 1, TRANSFORM_PRESENT);
- VP8LWriteBits(bw, 2, CROSS_COLOR_TRANSFORM);
+ VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
+ VP8LPutBits(bw, CROSS_COLOR_TRANSFORM, 2);
assert(ccolor_transform_bits >= 2);
- VP8LWriteBits(bw, 3, ccolor_transform_bits - 2);
- if (!EncodeImageNoHuffman(bw, enc->transform_data_,
- transform_width, transform_height, quality)) {
- return 0;
- }
- return 1;
+ VP8LPutBits(bw, ccolor_transform_bits - 2, 3);
+ return EncodeImageNoHuffman(bw, enc->transform_data_,
+ (VP8LHashChain*)&enc->hash_chain_,
+ (VP8LBackwardRefs*)enc->refs_, // cast const away
+ transform_width, transform_height,
+ quality);
}
// -----------------------------------------------------------------------------
-static void PutLE32(uint8_t* const data, uint32_t val) {
- data[0] = (val >> 0) & 0xff;
- data[1] = (val >> 8) & 0xff;
- data[2] = (val >> 16) & 0xff;
- data[3] = (val >> 24) & 0xff;
-}
-
static WebPEncodingError WriteRiffHeader(const WebPPicture* const pic,
size_t riff_size, size_t vp8l_size) {
uint8_t riff[RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + VP8L_SIGNATURE_SIZE] = {
@@ -733,14 +1067,14 @@ static int WriteImageSize(const WebPPicture* const pic,
const int height = pic->height - 1;
assert(width < WEBP_MAX_DIMENSION && height < WEBP_MAX_DIMENSION);
- VP8LWriteBits(bw, VP8L_IMAGE_SIZE_BITS, width);
- VP8LWriteBits(bw, VP8L_IMAGE_SIZE_BITS, height);
+ VP8LPutBits(bw, width, VP8L_IMAGE_SIZE_BITS);
+ VP8LPutBits(bw, height, VP8L_IMAGE_SIZE_BITS);
return !bw->error_;
}
static int WriteRealAlphaAndVersion(VP8LBitWriter* const bw, int has_alpha) {
- VP8LWriteBits(bw, 1, has_alpha);
- VP8LWriteBits(bw, VP8L_VERSION_BITS, VP8L_VERSION);
+ VP8LPutBits(bw, has_alpha, 1);
+ VP8LPutBits(bw, VP8L_VERSION, VP8L_VERSION_BITS);
return !bw->error_;
}
@@ -780,166 +1114,261 @@ static WebPEncodingError WriteImage(const WebPPicture* const pic,
// Allocates the memory for argb (W x H) buffer, 2 rows of context for
// prediction and transform data.
+// Flags influencing the memory allocated:
+// enc->transform_bits_
+// enc->use_predict_, enc->use_cross_color_
static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc,
int width, int height) {
WebPEncodingError err = VP8_ENC_OK;
- const int tile_size = 1 << enc->transform_bits_;
- const uint64_t image_size = width * height;
- const uint64_t argb_scratch_size = tile_size * width + width;
- const uint64_t transform_data_size =
- (uint64_t)VP8LSubSampleSize(width, enc->transform_bits_) *
- (uint64_t)VP8LSubSampleSize(height, enc->transform_bits_);
- const uint64_t total_size =
- image_size + argb_scratch_size + transform_data_size;
- uint32_t* mem = (uint32_t*)WebPSafeMalloc(total_size, sizeof(*mem));
- if (mem == NULL) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
- goto Error;
+ if (enc->argb_ == NULL) {
+ const int tile_size = 1 << enc->transform_bits_;
+ const uint64_t image_size = width * height;
+ // Ensure enough size for tiles, as well as for two scanlines and two
+ // extra pixels for CopyImageWithPrediction.
+ const uint64_t argb_scratch_size =
+ enc->use_predict_ ? tile_size * width + width + 2 : 0;
+ const int transform_data_size =
+ (enc->use_predict_ || enc->use_cross_color_)
+ ? VP8LSubSampleSize(width, enc->transform_bits_) *
+ VP8LSubSampleSize(height, enc->transform_bits_)
+ : 0;
+ const uint64_t total_size =
+ image_size + WEBP_ALIGN_CST +
+ argb_scratch_size + WEBP_ALIGN_CST +
+ (uint64_t)transform_data_size;
+ uint32_t* mem = (uint32_t*)WebPSafeMalloc(total_size, sizeof(*mem));
+ if (mem == NULL) {
+ err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ goto Error;
+ }
+ enc->argb_ = mem;
+ mem = (uint32_t*)WEBP_ALIGN(mem + image_size);
+ enc->argb_scratch_ = mem;
+ mem = (uint32_t*)WEBP_ALIGN(mem + argb_scratch_size);
+ enc->transform_data_ = mem;
+ enc->current_width_ = width;
}
- enc->argb_ = mem;
- mem += image_size;
- enc->argb_scratch_ = mem;
- mem += argb_scratch_size;
- enc->transform_data_ = mem;
- enc->current_width_ = width;
-
Error:
return err;
}
-// Bundles multiple (2, 4 or 8) pixels into a single pixel.
-// Returns the new xsize.
-static void BundleColorMap(const WebPPicture* const pic,
- int xbits, uint32_t* bundled_argb, int xs) {
- int y;
- const int bit_depth = 1 << (3 - xbits);
- uint32_t code = 0;
- const uint32_t* argb = pic->argb;
- const int width = pic->width;
- const int height = pic->height;
+static void ClearTransformBuffer(VP8LEncoder* const enc) {
+ WebPSafeFree(enc->argb_);
+ enc->argb_ = NULL;
+}
+static WebPEncodingError MakeInputImageCopy(VP8LEncoder* const enc) {
+ WebPEncodingError err = VP8_ENC_OK;
+ const WebPPicture* const picture = enc->pic_;
+ const int width = picture->width;
+ const int height = picture->height;
+ int y;
+ err = AllocateTransformBuffer(enc, width, height);
+ if (err != VP8_ENC_OK) return err;
for (y = 0; y < height; ++y) {
- int x;
- for (x = 0; x < width; ++x) {
- const int mask = (1 << xbits) - 1;
- const int xsub = x & mask;
- if (xsub == 0) {
- code = 0;
- }
- // TODO(vikasa): simplify the bundling logic.
- code |= (argb[x] & 0xff00) << (bit_depth * xsub);
- bundled_argb[y * xs + (x >> xbits)] = 0xff000000 | code;
- }
- argb += pic->argb_stride;
+ memcpy(enc->argb_ + y * width,
+ picture->argb + y * picture->argb_stride,
+ width * sizeof(*enc->argb_));
}
+ assert(enc->current_width_ == width);
+ return VP8_ENC_OK;
}
-// Note: Expects "enc->palette_" to be set properly.
-// Also, "enc->palette_" will be modified after this call and should not be used
-// later.
-static WebPEncodingError ApplyPalette(VP8LBitWriter* const bw,
- VP8LEncoder* const enc, int quality) {
- WebPEncodingError err = VP8_ENC_OK;
- int i, x, y;
- const WebPPicture* const pic = enc->pic_;
- uint32_t* argb = pic->argb;
- const int width = pic->width;
- const int height = pic->height;
- uint32_t* const palette = enc->palette_;
- const int palette_size = enc->palette_size_;
+// -----------------------------------------------------------------------------
- // Replace each input pixel by corresponding palette index.
- for (y = 0; y < height; ++y) {
- for (x = 0; x < width; ++x) {
- const uint32_t pix = argb[x];
- for (i = 0; i < palette_size; ++i) {
+static void MapToPalette(const uint32_t palette[], int num_colors,
+ uint32_t* const last_pix, int* const last_idx,
+ const uint32_t* src, uint8_t* dst, int width) {
+ int x;
+ int prev_idx = *last_idx;
+ uint32_t prev_pix = *last_pix;
+ for (x = 0; x < width; ++x) {
+ const uint32_t pix = src[x];
+ if (pix != prev_pix) {
+ int i;
+ for (i = 0; i < num_colors; ++i) {
if (pix == palette[i]) {
- argb[x] = 0xff000000u | (i << 8);
+ prev_idx = i;
+ prev_pix = pix;
break;
}
}
}
- argb += pic->argb_stride;
+ dst[x] = prev_idx;
}
+ *last_idx = prev_idx;
+ *last_pix = prev_pix;
+}
- // Save palette to bitstream.
- VP8LWriteBits(bw, 1, TRANSFORM_PRESENT);
- VP8LWriteBits(bw, 2, COLOR_INDEXING_TRANSFORM);
- assert(palette_size >= 1);
- VP8LWriteBits(bw, 8, palette_size - 1);
- for (i = palette_size - 1; i >= 1; --i) {
- palette[i] = VP8LSubPixels(palette[i], palette[i - 1]);
- }
- if (!EncodeImageNoHuffman(bw, palette, palette_size, 1, quality)) {
- err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
- goto Error;
+// Remap argb values in src[] to packed palettes entries in dst[]
+// using 'row' as a temporary buffer of size 'width'.
+// We assume that all src[] values have a corresponding entry in the palette.
+// Note: src[] can be the same as dst[]
+static WebPEncodingError ApplyPalette(const uint32_t* src, uint32_t src_stride,
+ uint32_t* dst, uint32_t dst_stride,
+ const uint32_t* palette, int palette_size,
+ int width, int height, int xbits) {
+ // TODO(skal): this tmp buffer is not needed if VP8LBundleColorMap() can be
+ // made to work in-place.
+ uint8_t* const tmp_row = (uint8_t*)WebPSafeMalloc(width, sizeof(*tmp_row));
+ int i, x, y;
+ int use_LUT = 1;
+
+ if (tmp_row == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
+ for (i = 0; i < palette_size; ++i) {
+ if ((palette[i] & 0xffff00ffu) != 0) {
+ use_LUT = 0;
+ break;
+ }
}
- if (palette_size <= 16) {
- // Image can be packed (multiple pixels per uint32_t).
- int xbits = 1;
- if (palette_size <= 2) {
- xbits = 3;
- } else if (palette_size <= 4) {
- xbits = 2;
+ if (use_LUT) {
+ uint8_t inv_palette[MAX_PALETTE_SIZE] = { 0 };
+ for (i = 0; i < palette_size; ++i) {
+ const int color = (palette[i] >> 8) & 0xff;
+ inv_palette[color] = i;
+ }
+ for (y = 0; y < height; ++y) {
+ for (x = 0; x < width; ++x) {
+ const int color = (src[x] >> 8) & 0xff;
+ tmp_row[x] = inv_palette[color];
+ }
+ VP8LBundleColorMap(tmp_row, width, xbits, dst);
+ src += src_stride;
+ dst += dst_stride;
+ }
+ } else {
+ // Use 1 pixel cache for ARGB pixels.
+ uint32_t last_pix = palette[0];
+ int last_idx = 0;
+ for (y = 0; y < height; ++y) {
+ MapToPalette(palette, palette_size, &last_pix, &last_idx,
+ src, tmp_row, width);
+ VP8LBundleColorMap(tmp_row, width, xbits, dst);
+ src += src_stride;
+ dst += dst_stride;
}
- err = AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height);
- if (err != VP8_ENC_OK) goto Error;
- BundleColorMap(pic, xbits, enc->argb_, enc->current_width_);
}
+ WebPSafeFree(tmp_row);
+ return VP8_ENC_OK;
+}
- Error:
+// Note: Expects "enc->palette_" to be set properly.
+static WebPEncodingError MapImageFromPalette(VP8LEncoder* const enc,
+ int in_place) {
+ WebPEncodingError err = VP8_ENC_OK;
+ const WebPPicture* const pic = enc->pic_;
+ const int width = pic->width;
+ const int height = pic->height;
+ const uint32_t* const palette = enc->palette_;
+ const uint32_t* src = in_place ? enc->argb_ : pic->argb;
+ const int src_stride = in_place ? enc->current_width_ : pic->argb_stride;
+ const int palette_size = enc->palette_size_;
+ int xbits;
+
+ // Replace each input pixel by corresponding palette index.
+ // This is done line by line.
+ if (palette_size <= 4) {
+ xbits = (palette_size <= 2) ? 3 : 2;
+ } else {
+ xbits = (palette_size <= 16) ? 1 : 0;
+ }
+
+ err = AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height);
+ if (err != VP8_ENC_OK) return err;
+
+ err = ApplyPalette(src, src_stride,
+ enc->argb_, enc->current_width_,
+ palette, palette_size, width, height, xbits);
return err;
}
-// -----------------------------------------------------------------------------
+// Save palette_[] to bitstream.
+static WebPEncodingError EncodePalette(VP8LBitWriter* const bw,
+ VP8LEncoder* const enc) {
+ int i;
+ uint32_t tmp_palette[MAX_PALETTE_SIZE];
+ const int palette_size = enc->palette_size_;
+ const uint32_t* const palette = enc->palette_;
+ VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
+ VP8LPutBits(bw, COLOR_INDEXING_TRANSFORM, 2);
+ assert(palette_size >= 1 && palette_size <= MAX_PALETTE_SIZE);
+ VP8LPutBits(bw, palette_size - 1, 8);
+ for (i = palette_size - 1; i >= 1; --i) {
+ tmp_palette[i] = VP8LSubPixels(palette[i], palette[i - 1]);
+ }
+ tmp_palette[0] = palette[0];
+ return EncodeImageNoHuffman(bw, tmp_palette, &enc->hash_chain_, enc->refs_,
+ palette_size, 1, 20 /* quality */);
+}
-static int GetHistoBits(const WebPConfig* const config,
- const WebPPicture* const pic) {
+#ifdef WEBP_EXPERIMENTAL_FEATURES
+
+static WebPEncodingError EncodeDeltaPalettePredictorImage(
+ VP8LBitWriter* const bw, VP8LEncoder* const enc, int quality) {
+ const WebPPicture* const pic = enc->pic_;
const int width = pic->width;
const int height = pic->height;
- const size_t hist_size = sizeof(VP8LHistogram);
- // Make tile size a function of encoding method (Range: 0 to 6).
- int histo_bits = 7 - config->method;
- while (1) {
- const size_t huff_image_size = VP8LSubSampleSize(width, histo_bits) *
- VP8LSubSampleSize(height, histo_bits) *
- hist_size;
- if (huff_image_size <= MAX_HUFF_IMAGE_SIZE) break;
- ++histo_bits;
+
+ const int pred_bits = 5;
+ const int transform_width = VP8LSubSampleSize(width, pred_bits);
+ const int transform_height = VP8LSubSampleSize(height, pred_bits);
+ const int pred = 7; // default is Predictor7 (Top/Left Average)
+ const int tiles_per_row = VP8LSubSampleSize(width, pred_bits);
+ const int tiles_per_col = VP8LSubSampleSize(height, pred_bits);
+ uint32_t* predictors;
+ int tile_x, tile_y;
+ WebPEncodingError err = VP8_ENC_OK;
+
+ predictors = (uint32_t*)WebPSafeMalloc(tiles_per_col * tiles_per_row,
+ sizeof(*predictors));
+ if (predictors == NULL) return VP8_ENC_ERROR_OUT_OF_MEMORY;
+
+ for (tile_y = 0; tile_y < tiles_per_col; ++tile_y) {
+ for (tile_x = 0; tile_x < tiles_per_row; ++tile_x) {
+ predictors[tile_y * tiles_per_row + tile_x] = 0xff000000u | (pred << 8);
+ }
}
- return (histo_bits < MIN_HUFFMAN_BITS) ? MIN_HUFFMAN_BITS :
- (histo_bits > MAX_HUFFMAN_BITS) ? MAX_HUFFMAN_BITS : histo_bits;
-}
-static void InitEncParams(VP8LEncoder* const enc) {
- const WebPConfig* const config = enc->config_;
- const WebPPicture* const picture = enc->pic_;
- const int method = config->method;
- const float quality = config->quality;
- enc->transform_bits_ = (method < 4) ? 5 : (method > 4) ? 3 : 4;
- enc->histo_bits_ = GetHistoBits(config, picture);
- enc->cache_bits_ = (quality <= 25.f) ? 0 : 7;
+ VP8LPutBits(bw, TRANSFORM_PRESENT, 1);
+ VP8LPutBits(bw, PREDICTOR_TRANSFORM, 2);
+ VP8LPutBits(bw, pred_bits - 2, 3);
+ err = EncodeImageNoHuffman(bw, predictors, &enc->hash_chain_,
+ (VP8LBackwardRefs*)enc->refs_, // cast const away
+ transform_width, transform_height,
+ quality);
+ WebPSafeFree(predictors);
+ return err;
}
+#endif // WEBP_EXPERIMENTAL_FEATURES
+
// -----------------------------------------------------------------------------
// VP8LEncoder
static VP8LEncoder* VP8LEncoderNew(const WebPConfig* const config,
const WebPPicture* const picture) {
- VP8LEncoder* const enc = (VP8LEncoder*)calloc(1, sizeof(*enc));
+ VP8LEncoder* const enc = (VP8LEncoder*)WebPSafeCalloc(1ULL, sizeof(*enc));
if (enc == NULL) {
WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
return NULL;
}
enc->config_ = config;
enc->pic_ = picture;
+
+ VP8LEncDspInit();
+
return enc;
}
static void VP8LEncoderDelete(VP8LEncoder* enc) {
- free(enc->argb_);
- free(enc);
+ if (enc != NULL) {
+ VP8LHashChainClear(&enc->hash_chain_);
+ VP8LBackwardRefsClear(&enc->refs_[0]);
+ VP8LBackwardRefsClear(&enc->refs_[1]);
+ ClearTransformBuffer(enc);
+ WebPSafeFree(enc);
+ }
}
// -----------------------------------------------------------------------------
@@ -950,89 +1379,102 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
VP8LBitWriter* const bw) {
WebPEncodingError err = VP8_ENC_OK;
const int quality = (int)config->quality;
+ const int low_effort = (config->method == 0);
const int width = picture->width;
const int height = picture->height;
VP8LEncoder* const enc = VP8LEncoderNew(config, picture);
const size_t byte_position = VP8LBitWriterNumBytes(bw);
+ int use_near_lossless = 0;
+ int hdr_size = 0;
+ int data_size = 0;
+ int use_delta_palettization = 0;
if (enc == NULL) {
err = VP8_ENC_ERROR_OUT_OF_MEMORY;
goto Error;
}
- InitEncParams(enc);
-
// ---------------------------------------------------------------------------
// Analyze image (entropy, num_palettes etc)
- if (!VP8LEncAnalyze(enc, config->image_hint)) {
+ if (!AnalyzeAndInit(enc)) {
err = VP8_ENC_ERROR_OUT_OF_MEMORY;
goto Error;
}
- if (enc->use_palette_) {
- err = ApplyPalette(bw, enc, quality);
- if (err != VP8_ENC_OK) goto Error;
- // Color cache is disabled for palette.
- enc->cache_bits_ = 0;
+ // Apply near-lossless preprocessing.
+ use_near_lossless = !enc->use_palette_ && (config->near_lossless < 100);
+ if (use_near_lossless) {
+ if (!VP8ApplyNearLossless(width, height, picture->argb,
+ config->near_lossless)) {
+ err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ goto Error;
+ }
}
- // In case image is not packed.
- if (enc->argb_ == NULL) {
- int y;
- err = AllocateTransformBuffer(enc, width, height);
+#ifdef WEBP_EXPERIMENTAL_FEATURES
+ if (config->delta_palettization) {
+ enc->use_predict_ = 1;
+ enc->use_cross_color_ = 0;
+ enc->use_subtract_green_ = 0;
+ enc->use_palette_ = 1;
+ err = MakeInputImageCopy(enc);
if (err != VP8_ENC_OK) goto Error;
- for (y = 0; y < height; ++y) {
- memcpy(enc->argb_ + y * width,
- picture->argb + y * picture->argb_stride,
- width * sizeof(*enc->argb_));
+ err = WebPSearchOptimalDeltaPalette(enc);
+ if (err != VP8_ENC_OK) goto Error;
+ if (enc->use_palette_) {
+ err = AllocateTransformBuffer(enc, width, height);
+ if (err != VP8_ENC_OK) goto Error;
+ err = EncodeDeltaPalettePredictorImage(bw, enc, quality);
+ if (err != VP8_ENC_OK) goto Error;
+ use_delta_palettization = 1;
}
- enc->current_width_ = width;
}
+#endif // WEBP_EXPERIMENTAL_FEATURES
- // ---------------------------------------------------------------------------
- // Apply transforms and write transform data.
-
- if (!EvalAndApplySubtractGreen(enc, enc->current_width_, height, bw)) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
- goto Error;
+ // Encode palette
+ if (enc->use_palette_) {
+ err = EncodePalette(bw, enc);
+ if (err != VP8_ENC_OK) goto Error;
+ err = MapImageFromPalette(enc, use_delta_palettization);
+ if (err != VP8_ENC_OK) goto Error;
}
-
- if (enc->use_predict_) {
- if (!ApplyPredictFilter(enc, enc->current_width_, height, quality, bw)) {
- err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
- goto Error;
+ if (!use_delta_palettization) {
+ // In case image is not packed.
+ if (enc->argb_ == NULL) {
+ err = MakeInputImageCopy(enc);
+ if (err != VP8_ENC_OK) goto Error;
}
- }
- if (enc->use_cross_color_) {
- if (!ApplyCrossColorFilter(enc, enc->current_width_, height, quality, bw)) {
- err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
- goto Error;
- }
- }
+ // -------------------------------------------------------------------------
+ // Apply transforms and write transform data.
- VP8LWriteBits(bw, 1, !TRANSFORM_PRESENT); // No more transforms.
+ if (enc->use_subtract_green_) {
+ ApplySubtractGreen(enc, enc->current_width_, height, bw);
+ }
- // ---------------------------------------------------------------------------
- // Estimate the color cache size.
+ if (enc->use_predict_) {
+ err = ApplyPredictFilter(enc, enc->current_width_, height, quality,
+ low_effort, bw);
+ if (err != VP8_ENC_OK) goto Error;
+ }
- if (enc->cache_bits_ > 0) {
- if (!VP8LCalculateEstimateForCacheSize(enc->argb_, enc->current_width_,
- height, &enc->cache_bits_)) {
- err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
- goto Error;
+ if (enc->use_cross_color_) {
+ err = ApplyCrossColorFilter(enc, enc->current_width_,
+ height, quality, bw);
+ if (err != VP8_ENC_OK) goto Error;
}
}
+ VP8LPutBits(bw, !TRANSFORM_PRESENT, 1); // No more transforms.
+
// ---------------------------------------------------------------------------
// Encode and write the transformed image.
-
- if (!EncodeImageInternal(bw, enc->argb_, enc->current_width_, height,
- quality, enc->cache_bits_, enc->histo_bits_)) {
- err = VP8_ENC_ERROR_OUT_OF_MEMORY;
- goto Error;
- }
+ err = EncodeImageInternal(bw, enc->argb_, &enc->hash_chain_, enc->refs_,
+ enc->current_width_, height, quality, low_effort,
+ &enc->cache_bits_, enc->histo_bits_, byte_position,
+ &hdr_size, &data_size);
+ if (err != VP8_ENC_OK) goto Error;
if (picture->stats != NULL) {
WebPAuxStats* const stats = picture->stats;
@@ -1046,6 +1488,8 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
stats->cache_bits = enc->cache_bits_;
stats->palette_size = enc->palette_size_;
stats->lossless_size = (int)(VP8LBitWriterNumBytes(bw) - byte_position);
+ stats->lossless_hdr_size = hdr_size;
+ stats->lossless_data_size = data_size;
}
Error:
@@ -1059,6 +1503,7 @@ int VP8LEncodeImage(const WebPConfig* const config,
int has_alpha;
size_t coded_size;
int percent = 0;
+ int initial_size;
WebPEncodingError err = VP8_ENC_OK;
VP8LBitWriter bw;
@@ -1072,7 +1517,11 @@ int VP8LEncodeImage(const WebPConfig* const config,
width = picture->width;
height = picture->height;
- if (!VP8LBitWriterInit(&bw, (width * height) >> 1)) {
+ // Initialize BitWriter with size corresponding to 16 bpp to photo images and
+ // 8 bpp for graphical images.
+ initial_size = (config->image_hint == WEBP_HINT_GRAPH) ?
+ width * height : width * height * 2;
+ if (!VP8LBitWriterInit(&bw, initial_size)) {
err = VP8_ENC_ERROR_OUT_OF_MEMORY;
goto Error;
}
@@ -1135,7 +1584,7 @@ int VP8LEncodeImage(const WebPConfig* const config,
Error:
if (bw.error_) err = VP8_ENC_ERROR_OUT_OF_MEMORY;
- VP8LBitWriterDestroy(&bw);
+ VP8LBitWriterWipeOut(&bw);
if (err != VP8_ENC_OK) {
WebPEncodingSetError(picture, err);
return 0;
@@ -1144,7 +1593,3 @@ int VP8LEncodeImage(const WebPConfig* const config,
}
//------------------------------------------------------------------------------
-
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/enc/vp8li.h b/drivers/webp/enc/vp8li.h
index bb111aec33..4543c3b260 100644
--- a/drivers/webp/enc/vp8li.h
+++ b/drivers/webp/enc/vp8li.h
@@ -1,8 +1,10 @@
// Copyright 2012 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Lossless encoder: internal header.
@@ -12,12 +14,13 @@
#ifndef WEBP_ENC_VP8LI_H_
#define WEBP_ENC_VP8LI_H_
+#include "./backward_references.h"
#include "./histogram.h"
#include "../utils/bit_writer.h"
-#include "../encode.h"
-#include "../format_constants.h"
+#include "webp/encode.h"
+#include "webp/format_constants.h"
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
extern "C" {
#endif
@@ -43,6 +46,12 @@ typedef struct {
int use_palette_;
int palette_size_;
uint32_t palette_[MAX_PALETTE_SIZE];
+
+ // Some 'scratch' (potentially large) objects.
+ struct VP8LBackwardRefs refs_[2]; // Backward Refs array corresponding to
+ // LZ77 & RLE coding.
+ VP8LHashChain hash_chain_; // HashChain data for constructing
+ // backward references.
} VP8LEncoder;
//------------------------------------------------------------------------------
@@ -61,7 +70,7 @@ WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/drivers/webp/enc/webpenc.c b/drivers/webp/enc/webpenc.c
index 3c275589fc..8ced07a2a3 100644
--- a/drivers/webp/enc/webpenc.c
+++ b/drivers/webp/enc/webpenc.c
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// WebP encoder: main entry point
@@ -14,16 +16,13 @@
#include <string.h>
#include <math.h>
+#include "./cost.h"
#include "./vp8enci.h"
#include "./vp8li.h"
#include "../utils/utils.h"
// #define PRINT_MEMORY_INFO
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
#ifdef PRINT_MEMORY_INFO
#include <stdio.h>
#endif
@@ -35,43 +34,18 @@ int WebPGetEncoderVersion(void) {
}
//------------------------------------------------------------------------------
-// WebPPicture
-//------------------------------------------------------------------------------
-
-static int DummyWriter(const uint8_t* data, size_t data_size,
- const WebPPicture* const picture) {
- // The following are to prevent 'unused variable' error message.
- (void)data;
- (void)data_size;
- (void)picture;
- return 1;
-}
-
-int WebPPictureInitInternal(WebPPicture* picture, int version) {
- if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_ENCODER_ABI_VERSION)) {
- return 0; // caller/system version mismatch!
- }
- if (picture != NULL) {
- memset(picture, 0, sizeof(*picture));
- picture->writer = DummyWriter;
- WebPEncodingSetError(picture, VP8_ENC_OK);
- }
- return 1;
-}
-
-//------------------------------------------------------------------------------
// VP8Encoder
//------------------------------------------------------------------------------
static void ResetSegmentHeader(VP8Encoder* const enc) {
- VP8SegmentHeader* const hdr = &enc->segment_hdr_;
+ VP8EncSegmentHeader* const hdr = &enc->segment_hdr_;
hdr->num_segments_ = enc->config_->segments;
hdr->update_map_ = (hdr->num_segments_ > 1);
hdr->size_ = 0;
}
static void ResetFilterHeader(VP8Encoder* const enc) {
- VP8FilterHeader* const hdr = &enc->filter_hdr_;
+ VP8EncFilterHeader* const hdr = &enc->filter_hdr_;
hdr->simple_ = 1;
hdr->level_ = 0;
hdr->sharpness_ = 0;
@@ -93,56 +67,73 @@ static void ResetBoundaryPredictions(VP8Encoder* const enc) {
enc->nz_[-1] = 0; // constant
}
-// Map configured quality level to coding tools used.
-//-------------+---+---+---+---+---+---+
-// Quality | 0 | 1 | 2 | 3 | 4 | 5 +
-//-------------+---+---+---+---+---+---+
-// dynamic prob| ~ | x | x | x | x | x |
-//-------------+---+---+---+---+---+---+
-// rd-opt modes| | | x | x | x | x |
-//-------------+---+---+---+---+---+---+
-// fast i4/i16 | x | x | | | | |
-//-------------+---+---+---+---+---+---+
-// rd-opt i4/16| | | x | x | x | x |
-//-------------+---+---+---+---+---+---+
-// Trellis | | x | | | x | x |
-//-------------+---+---+---+---+---+---+
-// full-SNS | | | | | | x |
-//-------------+---+---+---+---+---+---+
+// Mapping from config->method_ to coding tools used.
+//-------------------+---+---+---+---+---+---+---+
+// Method | 0 | 1 | 2 | 3 |(4)| 5 | 6 |
+//-------------------+---+---+---+---+---+---+---+
+// fast probe | x | | | x | | | |
+//-------------------+---+---+---+---+---+---+---+
+// dynamic proba | ~ | x | x | x | x | x | x |
+//-------------------+---+---+---+---+---+---+---+
+// fast mode analysis| | | | | x | x | x |
+//-------------------+---+---+---+---+---+---+---+
+// basic rd-opt | | | | x | x | x | x |
+//-------------------+---+---+---+---+---+---+---+
+// disto-score i4/16 | | | x | | | | |
+//-------------------+---+---+---+---+---+---+---+
+// rd-opt i4/16 | | | ~ | x | x | x | x |
+//-------------------+---+---+---+---+---+---+---+
+// token buffer (opt)| | | | x | x | x | x |
+//-------------------+---+---+---+---+---+---+---+
+// Trellis | | | | | | x |Ful|
+//-------------------+---+---+---+---+---+---+---+
+// full-SNS | | | | | x | x | x |
+//-------------------+---+---+---+---+---+---+---+
static void MapConfigToTools(VP8Encoder* const enc) {
- const int method = enc->config_->method;
- const int limit = 100 - enc->config_->partition_limit;
+ const WebPConfig* const config = enc->config_;
+ const int method = config->method;
+ const int limit = 100 - config->partition_limit;
enc->method_ = method;
- enc->rd_opt_level_ = (method >= 6) ? 3
- : (method >= 5) ? 2
- : (method >= 3) ? 1
- : 0;
+ enc->rd_opt_level_ = (method >= 6) ? RD_OPT_TRELLIS_ALL
+ : (method >= 5) ? RD_OPT_TRELLIS
+ : (method >= 3) ? RD_OPT_BASIC
+ : RD_OPT_NONE;
enc->max_i4_header_bits_ =
256 * 16 * 16 * // upper bound: up to 16bit per 4x4 block
(limit * limit) / (100 * 100); // ... modulated with a quadratic curve.
+
+ enc->thread_level_ = config->thread_level;
+
+ enc->do_search_ = (config->target_size > 0 || config->target_PSNR > 0);
+ if (!config->low_memory) {
+#if !defined(DISABLE_TOKEN_BUFFER)
+ enc->use_tokens_ = (enc->rd_opt_level_ >= RD_OPT_BASIC); // need rd stats
+#endif
+ if (enc->use_tokens_) {
+ enc->num_parts_ = 1; // doesn't work with multi-partition
+ }
+ }
}
// Memory scaling with dimensions:
// memory (bytes) ~= 2.25 * w + 0.0625 * w * h
//
-// Typical memory footprint (768x510 picture)
-// Memory used:
-// encoder: 33919
-// block cache: 2880
-// info: 3072
-// preds: 24897
-// top samples: 1623
-// non-zero: 196
-// lf-stats: 2048
-// total: 68635
-// Transcient object sizes:
-// VP8EncIterator: 352
-// VP8ModeScore: 912
-// VP8SegmentInfo: 532
-// VP8Proba: 31032
+// Typical memory footprint (614x440 picture)
+// encoder: 22111
+// info: 4368
+// preds: 17741
+// top samples: 1263
+// non-zero: 175
+// lf-stats: 0
+// total: 45658
+// Transient object sizes:
+// VP8EncIterator: 3360
+// VP8ModeScore: 872
+// VP8SegmentInfo: 732
+// VP8EncProba: 18352
// LFStats: 2048
-// Picture size (yuv): 589824
+// Picture size (yuv): 419328
static VP8Encoder* InitVP8Encoder(const WebPConfig* const config,
WebPPicture* const picture) {
@@ -154,20 +145,16 @@ static VP8Encoder* InitVP8Encoder(const WebPConfig* const config,
const int preds_h = 4 * mb_h + 1;
const size_t preds_size = preds_w * preds_h * sizeof(uint8_t);
const int top_stride = mb_w * 16;
- const size_t nz_size = (mb_w + 1) * sizeof(uint32_t);
- const size_t cache_size = (3 * YUV_SIZE + PRED_SIZE) * sizeof(uint8_t);
+ const size_t nz_size = (mb_w + 1) * sizeof(uint32_t) + WEBP_ALIGN_CST;
const size_t info_size = mb_w * mb_h * sizeof(VP8MBInfo);
- const size_t samples_size = (2 * top_stride + // top-luma/u/v
- 16 + 16 + 16 + 8 + 1 + // left y/u/v
- 2 * ALIGN_CST) // align all
- * sizeof(uint8_t);
+ const size_t samples_size = 2 * top_stride * sizeof(uint8_t) // top-luma/u/v
+ + WEBP_ALIGN_CST; // align all
const size_t lf_stats_size =
- config->autofilter ? sizeof(LFStats) + ALIGN_CST : 0;
+ config->autofilter ? sizeof(LFStats) + WEBP_ALIGN_CST : 0;
VP8Encoder* enc;
uint8_t* mem;
const uint64_t size = (uint64_t)sizeof(VP8Encoder) // main struct
- + ALIGN_CST // cache alignment
- + cache_size // working caches
+ + WEBP_ALIGN_CST // cache alignment
+ info_size // modes info
+ preds_size // prediction modes
+ samples_size // top/left samples
@@ -178,23 +165,22 @@ static VP8Encoder* InitVP8Encoder(const WebPConfig* const config,
printf("===================================\n");
printf("Memory used:\n"
" encoder: %ld\n"
- " block cache: %ld\n"
" info: %ld\n"
" preds: %ld\n"
" top samples: %ld\n"
" non-zero: %ld\n"
" lf-stats: %ld\n"
" total: %ld\n",
- sizeof(VP8Encoder) + ALIGN_CST, cache_size, info_size,
+ sizeof(VP8Encoder) + WEBP_ALIGN_CST, info_size,
preds_size, samples_size, nz_size, lf_stats_size, size);
- printf("Transcient object sizes:\n"
+ printf("Transient object sizes:\n"
" VP8EncIterator: %ld\n"
" VP8ModeScore: %ld\n"
" VP8SegmentInfo: %ld\n"
- " VP8Proba: %ld\n"
+ " VP8EncProba: %ld\n"
" LFStats: %ld\n",
sizeof(VP8EncIterator), sizeof(VP8ModeScore),
- sizeof(VP8SegmentInfo), sizeof(VP8Proba),
+ sizeof(VP8SegmentInfo), sizeof(VP8EncProba),
sizeof(LFStats));
printf("Picture size (yuv): %ld\n",
mb_w * mb_h * 384 * sizeof(uint8_t));
@@ -206,41 +192,27 @@ static VP8Encoder* InitVP8Encoder(const WebPConfig* const config,
return NULL;
}
enc = (VP8Encoder*)mem;
- mem = (uint8_t*)DO_ALIGN(mem + sizeof(*enc));
+ mem = (uint8_t*)WEBP_ALIGN(mem + sizeof(*enc));
memset(enc, 0, sizeof(*enc));
enc->num_parts_ = 1 << config->partitions;
enc->mb_w_ = mb_w;
enc->mb_h_ = mb_h;
enc->preds_w_ = preds_w;
- enc->yuv_in_ = (uint8_t*)mem;
- mem += YUV_SIZE;
- enc->yuv_out_ = (uint8_t*)mem;
- mem += YUV_SIZE;
- enc->yuv_out2_ = (uint8_t*)mem;
- mem += YUV_SIZE;
- enc->yuv_p_ = (uint8_t*)mem;
- mem += PRED_SIZE;
enc->mb_info_ = (VP8MBInfo*)mem;
mem += info_size;
enc->preds_ = ((uint8_t*)mem) + 1 + enc->preds_w_;
mem += preds_w * preds_h * sizeof(uint8_t);
- enc->nz_ = 1 + (uint32_t*)mem;
+ enc->nz_ = 1 + (uint32_t*)WEBP_ALIGN(mem);
mem += nz_size;
- enc->lf_stats_ = lf_stats_size ? (LFStats*)DO_ALIGN(mem) : NULL;
+ enc->lf_stats_ = lf_stats_size ? (LFStats*)WEBP_ALIGN(mem) : NULL;
mem += lf_stats_size;
// top samples (all 16-aligned)
- mem = (uint8_t*)DO_ALIGN(mem);
+ mem = (uint8_t*)WEBP_ALIGN(mem);
enc->y_top_ = (uint8_t*)mem;
enc->uv_top_ = enc->y_top_ + top_stride;
mem += 2 * top_stride;
- mem = (uint8_t*)DO_ALIGN(mem + 1);
- enc->y_left_ = (uint8_t*)mem;
- mem += 16 + 16;
- enc->u_left_ = (uint8_t*)mem;
- mem += 16;
- enc->v_left_ = (uint8_t*)mem;
- mem += 8;
+ assert(mem <= (uint8_t*)enc + size);
enc->config_ = config;
enc->profile_ = use_filter ? ((config->filter_type == 1) ? 0 : 1) : 2;
@@ -253,29 +225,32 @@ static VP8Encoder* InitVP8Encoder(const WebPConfig* const config,
ResetSegmentHeader(enc);
ResetFilterHeader(enc);
ResetBoundaryPredictions(enc);
-
+ VP8EncDspCostInit();
VP8EncInitAlpha(enc);
-#ifdef WEBP_EXPERIMENTAL_FEATURES
- VP8EncInitLayer(enc);
-#endif
+ // lower quality means smaller output -> we modulate a little the page
+ // size based on quality. This is just a crude 1rst-order prediction.
+ {
+ const float scale = 1.f + config->quality * 5.f / 100.f; // in [1,6]
+ VP8TBufferInit(&enc->tokens_, (int)(mb_w * mb_h * 4 * scale));
+ }
return enc;
}
-static void DeleteVP8Encoder(VP8Encoder* enc) {
+static int DeleteVP8Encoder(VP8Encoder* enc) {
+ int ok = 1;
if (enc != NULL) {
- VP8EncDeleteAlpha(enc);
-#ifdef WEBP_EXPERIMENTAL_FEATURES
- VP8EncDeleteLayer(enc);
-#endif
- free(enc);
+ ok = VP8EncDeleteAlpha(enc);
+ VP8TBufferClear(&enc->tokens_);
+ WebPSafeFree(enc);
}
+ return ok;
}
//------------------------------------------------------------------------------
static double GetPSNR(uint64_t err, uint64_t size) {
- return err ? 10. * log10(255. * 255. * size / err) : 99.;
+ return (err > 0 && size > 0) ? 10. * log10(255. * 255. * size / err) : 99.;
}
static void FinalizePSNR(const VP8Encoder* const enc) {
@@ -332,7 +307,7 @@ int WebPReportProgress(const WebPPicture* const pic,
//------------------------------------------------------------------------------
int WebPEncode(const WebPConfig* config, WebPPicture* pic) {
- int ok;
+ int ok = 0;
if (pic == NULL)
return 0;
@@ -346,44 +321,63 @@ int WebPEncode(const WebPConfig* config, WebPPicture* pic) {
if (pic->width > WEBP_MAX_DIMENSION || pic->height > WEBP_MAX_DIMENSION)
return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION);
+ if (!config->exact) {
+ WebPCleanupTransparentArea(pic);
+ }
+
if (pic->stats != NULL) memset(pic->stats, 0, sizeof(*pic->stats));
if (!config->lossless) {
VP8Encoder* enc = NULL;
- if (pic->y == NULL || pic->u == NULL || pic->v == NULL) {
- if (pic->argb != NULL) {
- if (!WebPPictureARGBToYUVA(pic, WEBP_YUV420)) return 0;
+ if (pic->use_argb || pic->y == NULL || pic->u == NULL || pic->v == NULL) {
+ // Make sure we have YUVA samples.
+ if (config->preprocessing & 4) {
+ if (!WebPPictureSmartARGBToYUVA(pic)) {
+ return 0;
+ }
} else {
- return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER);
+ float dithering = 0.f;
+ if (config->preprocessing & 2) {
+ const float x = config->quality / 100.f;
+ const float x2 = x * x;
+ // slowly decreasing from max dithering at low quality (q->0)
+ // to 0.5 dithering amplitude at high quality (q->100)
+ dithering = 1.0f + (0.5f - 1.0f) * x2 * x2;
+ }
+ if (!WebPPictureARGBToYUVADithered(pic, WEBP_YUV420, dithering)) {
+ return 0;
+ }
}
}
enc = InitVP8Encoder(config, pic);
if (enc == NULL) return 0; // pic->error is already set.
// Note: each of the tasks below account for 20% in the progress report.
- ok = VP8EncAnalyze(enc)
- && VP8StatLoop(enc)
- && VP8EncLoop(enc)
- && VP8EncFinishAlpha(enc)
-#ifdef WEBP_EXPERIMENTAL_FEATURES
- && VP8EncFinishLayer(enc)
-#endif
- && VP8EncWrite(enc);
+ ok = VP8EncAnalyze(enc);
+
+ // Analysis is done, proceed to actual coding.
+ ok = ok && VP8EncStartAlpha(enc); // possibly done in parallel
+ if (!enc->use_tokens_) {
+ ok = ok && VP8EncLoop(enc);
+ } else {
+ ok = ok && VP8EncTokenLoop(enc);
+ }
+ ok = ok && VP8EncFinishAlpha(enc);
+
+ ok = ok && VP8EncWrite(enc);
StoreStats(enc);
if (!ok) {
VP8EncFreeBitWriters(enc);
}
- DeleteVP8Encoder(enc);
+ ok &= DeleteVP8Encoder(enc); // must always be called, even if !ok
} else {
- if (pic->argb == NULL)
- return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER);
+ // Make sure we have ARGB samples.
+ if (pic->argb == NULL && !WebPPictureYUVAToARGB(pic)) {
+ return 0;
+ }
ok = VP8LEncodeImage(config, pic); // Sets pic->error in case of problem.
}
return ok;
}
-
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/encode.h b/drivers/webp/encode.h
index 2e37cfabe7..c382ea7608 100644
--- a/drivers/webp/encode.h
+++ b/drivers/webp/encode.h
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// WebP encoder: main interface
@@ -14,11 +16,22 @@
#include "./types.h"
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
extern "C" {
#endif
-#define WEBP_ENCODER_ABI_VERSION 0x0200 // MAJOR(8b) + MINOR(8b)
+#define WEBP_ENCODER_ABI_VERSION 0x0209 // MAJOR(8b) + MINOR(8b)
+
+// Note: forward declaring enumerations is not allowed in (strict) C and C++,
+// the types are left here for reference.
+// typedef enum WebPImageHint WebPImageHint;
+// typedef enum WebPEncCSP WebPEncCSP;
+// typedef enum WebPPreset WebPPreset;
+// typedef enum WebPEncodingError WebPEncodingError;
+typedef struct WebPConfig WebPConfig;
+typedef struct WebPPicture WebPPicture; // main structure for I/O
+typedef struct WebPAuxStats WebPAuxStats;
+typedef struct WebPMemoryWriter WebPMemoryWriter;
// Return the encoder's version number, packed in hexadecimal using 8bits for
// each of major/minor/revision. E.g: v2.5.7 is 0x020507.
@@ -29,7 +42,7 @@ WEBP_EXTERN(int) WebPGetEncoderVersion(void);
// Returns the size of the compressed data (pointed to by *output), or 0 if
// an error occurred. The compressed data must be released by the caller
-// using the call 'free(*output)'.
+// using the call 'WebPFree(*output)'.
// These functions compress using the lossy format, and the quality_factor
// can go from 0 (smaller output, lower quality) to 100 (best quality,
// larger output).
@@ -62,11 +75,14 @@ WEBP_EXTERN(size_t) WebPEncodeLosslessBGRA(const uint8_t* bgra,
int width, int height, int stride,
uint8_t** output);
+// Releases memory returned by the WebPEncode*() functions above.
+WEBP_EXTERN(void) WebPFree(void* ptr);
+
//------------------------------------------------------------------------------
// Coding parameters
// Image characteristics hint for the underlying encoder.
-typedef enum {
+typedef enum WebPImageHint {
WEBP_HINT_DEFAULT = 0, // default preset.
WEBP_HINT_PICTURE, // digital picture, like portrait, inner shot
WEBP_HINT_PHOTO, // outdoor photograph, with natural lighting
@@ -74,7 +90,8 @@ typedef enum {
WEBP_HINT_LAST
} WebPImageHint;
-typedef struct {
+// Compression parameters.
+struct WebPConfig {
int lossless; // Lossless encoding (0=lossy(default), 1=lossless).
float quality; // between 0 (smallest file) and 100 (biggest)
int method; // quality/speed trade-off (0=fast, 6=slower-better)
@@ -103,19 +120,38 @@ typedef struct {
int show_compressed; // if true, export the compressed picture back.
// In-loop filtering is not applied.
- int preprocessing; // preprocessing filter (0=none, 1=segment-smooth)
+ int preprocessing; // preprocessing filter:
+ // 0=none, 1=segment-smooth, 2=pseudo-random dithering
int partitions; // log2(number of token partitions) in [0..3]. Default
// is set to 0 for easier progressive decoding.
int partition_limit; // quality degradation allowed to fit the 512k limit
// on prediction modes coding (0: no degradation,
// 100: maximum possible degradation).
-
- uint32_t pad[8]; // padding for later use
-} WebPConfig;
+ int emulate_jpeg_size; // If true, compression parameters will be remapped
+ // to better match the expected output size from
+ // JPEG compression. Generally, the output size will
+ // be similar but the degradation will be lower.
+ int thread_level; // If non-zero, try and use multi-threaded encoding.
+ int low_memory; // If set, reduce memory usage (but increase CPU use).
+
+ int near_lossless; // Near lossless encoding [0 = off(default) .. 100].
+ // This feature is experimental.
+ int exact; // if non-zero, preserve the exact RGB values under
+ // transparent area. Otherwise, discard this invisible
+ // RGB information for better compression. The default
+ // value is 0.
+
+#ifdef WEBP_EXPERIMENTAL_FEATURES
+ int delta_palettization;
+ uint32_t pad[2]; // padding for later use
+#else
+ uint32_t pad[3]; // padding for later use
+#endif // WEBP_EXPERIMENTAL_FEATURES
+};
// Enumerate some predefined settings for WebPConfig, depending on the type
// of source picture. These presets are used when calling WebPConfigPreset().
-typedef enum {
+typedef enum WebPPreset {
WEBP_PRESET_DEFAULT = 0, // default preset.
WEBP_PRESET_PICTURE, // digital picture, like portrait, inner shot
WEBP_PRESET_PHOTO, // outdoor photograph, with natural lighting
@@ -146,17 +182,23 @@ static WEBP_INLINE int WebPConfigPreset(WebPConfig* config,
WEBP_ENCODER_ABI_VERSION);
}
+// Activate the lossless compression mode with the desired efficiency level
+// between 0 (fastest, lowest compression) and 9 (slower, best compression).
+// A good default level is '6', providing a fair tradeoff between compression
+// speed and final compressed size.
+// This function will overwrite several fields from config: 'method', 'quality'
+// and 'lossless'. Returns false in case of parameter error.
+WEBP_EXTERN(int) WebPConfigLosslessPreset(WebPConfig* config, int level);
+
// Returns true if 'config' is non-NULL and all configuration parameters are
// within their valid ranges.
WEBP_EXTERN(int) WebPValidateConfig(const WebPConfig* config);
//------------------------------------------------------------------------------
// Input / Output
-
-typedef struct WebPPicture WebPPicture; // main structure for I/O
-
// Structure for storing auxiliary statistics (mostly for lossy encoding).
-typedef struct {
+
+struct WebPAuxStats {
int coded_size; // final size
float PSNR[5]; // peak-signal-to-noise ratio for Y/U/V/All/Alpha
@@ -180,9 +222,11 @@ typedef struct {
int cache_bits; // number of bits for color cache lookup
int palette_size; // number of color in palette, if used
int lossless_size; // final lossless size
+ int lossless_hdr_size; // lossless header (transform, huffman etc) size
+ int lossless_data_size; // lossless image data size
- uint32_t pad[4]; // padding for later use
-} WebPAuxStats;
+ uint32_t pad[2]; // padding for later use
+};
// Signature for output function. Should return true if writing was successful.
// data/data_size is the segment of data to write, and 'picture' is for
@@ -192,18 +236,22 @@ typedef int (*WebPWriterFunction)(const uint8_t* data, size_t data_size,
// WebPMemoryWrite: a special WebPWriterFunction that writes to memory using
// the following WebPMemoryWriter object (to be set as a custom_ptr).
-typedef struct {
+struct WebPMemoryWriter {
uint8_t* mem; // final buffer (of size 'max_size', larger than 'size').
size_t size; // final size
size_t max_size; // total capacity
uint32_t pad[1]; // padding for later use
-} WebPMemoryWriter;
+};
// The following must be called first before any use.
WEBP_EXTERN(void) WebPMemoryWriterInit(WebPMemoryWriter* writer);
+// The following must be called to deallocate writer->mem memory. The 'writer'
+// object itself is not deallocated.
+WEBP_EXTERN(void) WebPMemoryWriterClear(WebPMemoryWriter* writer);
// The custom writer to be used with WebPMemoryWriter as custom_ptr. Upon
// completion, writer.mem and writer.size will hold the coded data.
+// writer.mem must be freed by calling WebPMemoryWriterClear.
WEBP_EXTERN(int) WebPMemoryWrite(const uint8_t* data, size_t data_size,
const WebPPicture* picture);
@@ -212,23 +260,17 @@ WEBP_EXTERN(int) WebPMemoryWrite(const uint8_t* data, size_t data_size,
// everything is OK.
typedef int (*WebPProgressHook)(int percent, const WebPPicture* picture);
-typedef enum {
+// Color spaces.
+typedef enum WebPEncCSP {
// chroma sampling
- WEBP_YUV420 = 0, // 4:2:0
- WEBP_YUV422 = 1, // 4:2:2
- WEBP_YUV444 = 2, // 4:4:4
- WEBP_YUV400 = 3, // grayscale
- WEBP_CSP_UV_MASK = 3, // bit-mask to get the UV sampling factors
- // alpha channel variants
- WEBP_YUV420A = 4,
- WEBP_YUV422A = 5,
- WEBP_YUV444A = 6,
- WEBP_YUV400A = 7, // grayscale + alpha
+ WEBP_YUV420 = 0, // 4:2:0
+ WEBP_YUV420A = 4, // alpha channel variant
+ WEBP_CSP_UV_MASK = 3, // bit-mask to get the UV sampling factors
WEBP_CSP_ALPHA_BIT = 4 // bit that is set if alpha is present
} WebPEncCSP;
// Encoding error conditions.
-typedef enum {
+typedef enum WebPEncodingError {
VP8_ENC_OK = 0,
VP8_ENC_ERROR_OUT_OF_MEMORY, // memory error allocating objects
VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY, // memory error while flushing bits
@@ -248,7 +290,6 @@ typedef enum {
// Main exchange structure (input samples, output bytes, statistics)
struct WebPPicture {
-
// INPUT
//////////////
// Main flag for encoder selecting between ARGB or YUV input.
@@ -303,17 +344,15 @@ struct WebPPicture {
uint32_t pad3[3]; // padding for later use
- // Unused for now: original samples (for non-YUV420 modes)
- uint8_t *u0, *v0;
- int uv0_stride;
-
- uint32_t pad4[7]; // padding for later use
+ // Unused for now
+ uint8_t *pad4, *pad5;
+ uint32_t pad6[8]; // padding for later use
// PRIVATE FIELDS
////////////////////
void* memory_; // row chunk of memory for yuva planes
void* memory_argb_; // and for argb too.
- void* pad5[2]; // padding for later use
+ void* pad7[2]; // padding for later use
};
// Internal, version-checked, entry point
@@ -343,18 +382,19 @@ WEBP_EXTERN(int) WebPPictureAlloc(WebPPicture* picture);
// preserved.
WEBP_EXTERN(void) WebPPictureFree(WebPPicture* picture);
-// Copy the pixels of *src into *dst, using WebPPictureAlloc. Upon return,
-// *dst will fully own the copied pixels (this is not a view).
+// Copy the pixels of *src into *dst, using WebPPictureAlloc. Upon return, *dst
+// will fully own the copied pixels (this is not a view). The 'dst' picture need
+// not be initialized as its content is overwritten.
// Returns false in case of memory allocation error.
WEBP_EXTERN(int) WebPPictureCopy(const WebPPicture* src, WebPPicture* dst);
-// Compute PSNR or SSIM distortion between two pictures.
-// Result is in dB, stores in result[] in the Y/U/V/Alpha/All order.
-// Returns false in case of error (pic1 and pic2 don't have same dimension, ...)
+// Compute PSNR, SSIM or LSIM distortion metric between two pictures. Results
+// are in dB, stored in result[] in the Y/U/V/Alpha/All or B/G/R/A/All order.
+// Returns false in case of error (src and ref don't have same dimension, ...)
// Warning: this function is rather CPU-intensive.
WEBP_EXTERN(int) WebPPictureDistortion(
- const WebPPicture* pic1, const WebPPicture* pic2,
- int metric_type, // 0 = PSNR, 1 = SSIM
+ const WebPPicture* src, const WebPPicture* ref,
+ int metric_type, // 0 = PSNR, 1 = SSIM, 2 = LSIM
float result[5]);
// self-crops a picture to the rectangle defined by top/left/width/height.
@@ -375,7 +415,9 @@ WEBP_EXTERN(int) WebPPictureCrop(WebPPicture* picture,
// the top and left coordinates will be snapped to even values.
// Picture 'src' must out-live 'dst' picture. Self-extraction of view is allowed
// ('src' equal to 'dst') as a mean of fast-cropping (but note that doing so,
-// the original dimension will be lost).
+// the original dimension will be lost). Picture 'dst' need not be initialized
+// with WebPPictureInit() if it is different from 'src', since its content will
+// be overwritten.
// Returns false in case of memory allocation error or invalid parameters.
WEBP_EXTERN(int) WebPPictureView(const WebPPicture* src,
int left, int top, int width, int height,
@@ -386,7 +428,9 @@ WEBP_EXTERN(int) WebPPictureView(const WebPPicture* src,
WEBP_EXTERN(int) WebPPictureIsView(const WebPPicture* picture);
// Rescale a picture to new dimension width x height.
-// Now gamma correction is applied.
+// If either 'width' or 'height' (but not both) is 0 the corresponding
+// dimension will be calculated preserving the aspect ratio.
+// No gamma correction is applied.
// Returns false in case of error (invalid parameter or insufficient memory).
WEBP_EXTERN(int) WebPPictureRescale(WebPPicture* pic, int width, int height);
@@ -413,13 +457,28 @@ WEBP_EXTERN(int) WebPPictureImportBGRA(
WEBP_EXTERN(int) WebPPictureImportBGRX(
WebPPicture* picture, const uint8_t* bgrx, int bgrx_stride);
-// Converts picture->argb data to the YUVA format specified by 'colorspace'.
+// Converts picture->argb data to the YUV420A format. The 'colorspace'
+// parameter is deprecated and should be equal to WEBP_YUV420.
// Upon return, picture->use_argb is set to false. The presence of real
// non-opaque transparent values is detected, and 'colorspace' will be
// adjusted accordingly. Note that this method is lossy.
// Returns false in case of error.
WEBP_EXTERN(int) WebPPictureARGBToYUVA(WebPPicture* picture,
- WebPEncCSP colorspace);
+ WebPEncCSP /*colorspace = WEBP_YUV420*/);
+
+// Same as WebPPictureARGBToYUVA(), but the conversion is done using
+// pseudo-random dithering with a strength 'dithering' between
+// 0.0 (no dithering) and 1.0 (maximum dithering). This is useful
+// for photographic picture.
+WEBP_EXTERN(int) WebPPictureARGBToYUVADithered(
+ WebPPicture* picture, WebPEncCSP colorspace, float dithering);
+
+// Performs 'smart' RGBA->YUVA420 downsampling and colorspace conversion.
+// Downsampling is handled with extra care in case of color clipping. This
+// method is roughly 2x slower than WebPPictureARGBToYUVA() but produces better
+// YUV representation.
+// Returns false in case of error.
+WEBP_EXTERN(int) WebPPictureSmartARGBToYUVA(WebPPicture* picture);
// Converts picture->yuv to picture->argb and sets picture->use_argb to true.
// The input format must be YUV_420 or YUV_420A.
@@ -429,9 +488,9 @@ WEBP_EXTERN(int) WebPPictureARGBToYUVA(WebPPicture* picture,
// Returns false in case of error.
WEBP_EXTERN(int) WebPPictureYUVAToARGB(WebPPicture* picture);
-// Helper function: given a width x height plane of YUV(A) samples
-// (with stride 'stride'), clean-up the YUV samples under fully transparent
-// area, to help compressibility (no guarantee, though).
+// Helper function: given a width x height plane of RGBA or YUV(A) samples
+// clean-up the YUV or RGB samples under fully transparent area, to help
+// compressibility (no guarantee, though).
WEBP_EXTERN(void) WebPCleanupTransparentArea(WebPPicture* picture);
// Scan the picture 'picture' for the presence of non fully opaque alpha values.
@@ -439,6 +498,11 @@ WEBP_EXTERN(void) WebPCleanupTransparentArea(WebPPicture* picture);
// alpha plane can be ignored altogether e.g.).
WEBP_EXTERN(int) WebPPictureHasTransparency(const WebPPicture* picture);
+// Remove the transparency information (if present) by blending the color with
+// the background color 'background_rgb' (specified as 24bit RGB triplet).
+// After this call, all alpha values are reset to 0xff.
+WEBP_EXTERN(void) WebPBlendAlpha(WebPPicture* pic, uint32_t background_rgb);
+
//------------------------------------------------------------------------------
// Main call
@@ -456,7 +520,7 @@ WEBP_EXTERN(int) WebPEncode(const WebPConfig* config, WebPPicture* picture);
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/drivers/webp/extras.h b/drivers/webp/extras.h
new file mode 100644
index 0000000000..1c24be2e0c
--- /dev/null
+++ b/drivers/webp/extras.h
@@ -0,0 +1,51 @@
+// Copyright 2015 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+
+#ifndef WEBP_WEBP_EXTRAS_H_
+#define WEBP_WEBP_EXTRAS_H_
+
+#include "./types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "./encode.h"
+
+#define WEBP_EXTRAS_ABI_VERSION 0x0000 // MAJOR(8b) + MINOR(8b)
+
+//------------------------------------------------------------------------------
+
+// Returns the version number of the extras library, packed in hexadecimal using
+// 8bits for each of major/minor/revision. E.g: v2.5.7 is 0x020507.
+WEBP_EXTERN(int) WebPGetExtrasVersion(void);
+
+//------------------------------------------------------------------------------
+// Ad-hoc colorspace importers.
+
+// Import luma sample (gray scale image) into 'picture'. The 'picture'
+// width and height must be set prior to calling this function.
+WEBP_EXTERN(int) WebPImportGray(const uint8_t* gray, WebPPicture* picture);
+
+// Import rgb sample in RGB565 packed format into 'picture'. The 'picture'
+// width and height must be set prior to calling this function.
+WEBP_EXTERN(int) WebPImportRGB565(const uint8_t* rgb565, WebPPicture* pic);
+
+// Import rgb sample in RGB4444 packed format into 'picture'. The 'picture'
+// width and height must be set prior to calling this function.
+WEBP_EXTERN(int) WebPImportRGB4444(const uint8_t* rgb4444, WebPPicture* pic);
+
+//------------------------------------------------------------------------------
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* WEBP_WEBP_EXTRAS_H_ */
diff --git a/drivers/webp/format_constants.h b/drivers/webp/format_constants.h
index 7ce498f672..b6e78a643e 100644
--- a/drivers/webp/format_constants.h
+++ b/drivers/webp/format_constants.h
@@ -1,8 +1,10 @@
// Copyright 2012 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Internal header for constants related to WebP file format.
@@ -12,6 +14,9 @@
#ifndef WEBP_WEBP_FORMAT_CONSTANTS_H_
#define WEBP_WEBP_FORMAT_CONSTANTS_H_
+// Create fourcc of the chunk from the chunk tag characters.
+#define MKFOURCC(a, b, c, d) ((a) | (b) << 8 | (c) << 16 | (uint32_t)(d) << 24)
+
// VP8 related constants.
#define VP8_SIGNATURE 0x9d012a // Signature in VP8 data.
#define VP8_MAX_PARTITION0_SIZE (1 << 19) // max size of mode partition
@@ -65,23 +70,16 @@ typedef enum {
#define CHUNK_SIZE_BYTES 4 // Size needed to store chunk's size.
#define CHUNK_HEADER_SIZE 8 // Size of a chunk header.
#define RIFF_HEADER_SIZE 12 // Size of the RIFF header ("RIFFnnnnWEBP").
-#define FRAME_CHUNK_SIZE 15 // Size of a FRM chunk.
-#define LOOP_CHUNK_SIZE 2 // Size of a LOOP chunk.
-#define TILE_CHUNK_SIZE 6 // Size of a TILE chunk.
+#define ANMF_CHUNK_SIZE 16 // Size of an ANMF chunk.
+#define ANIM_CHUNK_SIZE 6 // Size of an ANIM chunk.
+#define FRGM_CHUNK_SIZE 6 // Size of a FRGM chunk.
#define VP8X_CHUNK_SIZE 10 // Size of a VP8X chunk.
-#define TILING_FLAG_BIT 0x01 // Set if tiles are possibly used.
-#define ANIMATION_FLAG_BIT 0x02 // Set if some animation is expected
-#define ICC_FLAG_BIT 0x04 // Whether ICC is present or not.
-#define METADATA_FLAG_BIT 0x08 // Set if some META chunk is possibly present.
-#define ALPHA_FLAG_BIT 0x10 // Should be same as the ALPHA_FLAG in mux.h
-#define ROTATION_FLAG_BITS 0xe0 // all 3 bits for rotation + symmetry
-
-#define MAX_CANVAS_SIZE (1 << 24) // 24-bit max for VP8X width/height.
-#define MAX_IMAGE_AREA (1ULL << 32) // 32-bit max for width x height.
-#define MAX_LOOP_COUNT (1 << 16) // maximum value for loop-count
-#define MAX_DURATION (1 << 24) // maximum duration
-#define MAX_POSITION_OFFSET (1 << 24) // maximum frame/tile x/y offset
+#define MAX_CANVAS_SIZE (1 << 24) // 24-bit max for VP8X width/height.
+#define MAX_IMAGE_AREA (1ULL << 32) // 32-bit max for width x height.
+#define MAX_LOOP_COUNT (1 << 16) // maximum value for loop-count
+#define MAX_DURATION (1 << 24) // maximum duration
+#define MAX_POSITION_OFFSET (1 << 24) // maximum frame/fragment x/y offset
// Maximum chunk payload is such that adding the header and padding won't
// overflow a uint32_t.
diff --git a/drivers/webp/image_loader_webp.cpp b/drivers/webp/image_loader_webp.cpp
index 9d8a616556..5fb14eaf7a 100644
--- a/drivers/webp/image_loader_webp.cpp
+++ b/drivers/webp/image_loader_webp.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/*************************************************/
/* Source code within this file is: */
-/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
/* All Rights Reserved. */
/*************************************************/
diff --git a/drivers/webp/image_loader_webp.h b/drivers/webp/image_loader_webp.h
index 8fc188cc9c..ea99a60676 100644
--- a/drivers/webp/image_loader_webp.h
+++ b/drivers/webp/image_loader_webp.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/*************************************************/
/* Source code within this file is: */
-/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
/* All Rights Reserved. */
/*************************************************/
diff --git a/drivers/webp/mux.h b/drivers/webp/mux.h
index 5139af80fa..1fddfb76d4 100644
--- a/drivers/webp/mux.h
+++ b/drivers/webp/mux.h
@@ -1,60 +1,76 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
-// RIFF container manipulation for WEBP images.
+// RIFF container manipulation and encoding for WebP images.
//
// Authors: Urvang (urvang@google.com)
// Vikas (vikasa@google.com)
-// This API allows manipulation of WebP container images containing features
-// like Color profile, XMP metadata, Animation and Tiling.
-//
-// Code Example#1: Creating a MUX with image data, color profile and XMP
-// metadata.
-//
-// int copy_data = 0;
-// WebPMux* mux = WebPMuxNew();
-// // ... (Prepare image data).
-// WebPMuxSetImage(mux, &image, copy_data);
-// // ... (Prepare ICCP color profile data).
-// WebPMuxSetColorProfile(mux, &icc_profile, copy_data);
-// // ... (Prepare XMP metadata).
-// WebPMuxSetMetadata(mux, &xmp, copy_data);
-// // Get data from mux in WebP RIFF format.
-// WebPMuxAssemble(mux, &output_data);
-// WebPMuxDelete(mux);
-// // ... (Consume output_data; e.g. write output_data.bytes_ to file).
-// WebPDataClear(&output_data);
-//
-// Code Example#2: Get image and color profile data from a WebP file.
-//
-// int copy_data = 0;
-// // ... (Read data from file).
-// WebPMux* mux = WebPMuxCreate(&data, copy_data);
-// WebPMuxGetImage(mux, &image);
-// // ... (Consume image; e.g. call WebPDecode() to decode the data).
-// WebPMuxGetColorProfile(mux, &icc_profile);
-// // ... (Consume icc_data).
-// WebPMuxDelete(mux);
-// free(data);
-
#ifndef WEBP_WEBP_MUX_H_
#define WEBP_WEBP_MUX_H_
-#include "./types.h"
+#include "./mux_types.h"
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
extern "C" {
#endif
-#define WEBP_MUX_ABI_VERSION 0x0100 // MAJOR(8b) + MINOR(8b)
+#define WEBP_MUX_ABI_VERSION 0x0106 // MAJOR(8b) + MINOR(8b)
+
+//------------------------------------------------------------------------------
+// Mux API
+//
+// This API allows manipulation of WebP container images containing features
+// like color profile, metadata, animation and fragmented images.
+//
+// Code Example#1: Create a WebPMux object with image data, color profile and
+// XMP metadata.
+/*
+ int copy_data = 0;
+ WebPMux* mux = WebPMuxNew();
+ // ... (Prepare image data).
+ WebPMuxSetImage(mux, &image, copy_data);
+ // ... (Prepare ICCP color profile data).
+ WebPMuxSetChunk(mux, "ICCP", &icc_profile, copy_data);
+ // ... (Prepare XMP metadata).
+ WebPMuxSetChunk(mux, "XMP ", &xmp, copy_data);
+ // Get data from mux in WebP RIFF format.
+ WebPMuxAssemble(mux, &output_data);
+ WebPMuxDelete(mux);
+ // ... (Consume output_data; e.g. write output_data.bytes to file).
+ WebPDataClear(&output_data);
+*/
+
+// Code Example#2: Get image and color profile data from a WebP file.
+/*
+ int copy_data = 0;
+ // ... (Read data from file).
+ WebPMux* mux = WebPMuxCreate(&data, copy_data);
+ WebPMuxGetFrame(mux, 1, &image);
+ // ... (Consume image; e.g. call WebPDecode() to decode the data).
+ WebPMuxGetChunk(mux, "ICCP", &icc_profile);
+ // ... (Consume icc_data).
+ WebPMuxDelete(mux);
+ free(data);
+*/
+
+// Note: forward declaring enumerations is not allowed in (strict) C and C++,
+// the types are left here for reference.
+// typedef enum WebPMuxError WebPMuxError;
+// typedef enum WebPChunkId WebPChunkId;
+typedef struct WebPMux WebPMux; // main opaque object.
+typedef struct WebPMuxFrameInfo WebPMuxFrameInfo;
+typedef struct WebPMuxAnimParams WebPMuxAnimParams;
+typedef struct WebPAnimEncoderOptions WebPAnimEncoderOptions;
// Error codes
-typedef enum {
+typedef enum WebPMuxError {
WEBP_MUX_OK = 1,
WEBP_MUX_NOT_FOUND = 0,
WEBP_MUX_INVALID_ARGUMENT = -1,
@@ -63,51 +79,26 @@ typedef enum {
WEBP_MUX_NOT_ENOUGH_DATA = -4
} WebPMuxError;
-// Flag values for different features used in VP8X chunk.
-typedef enum {
- TILE_FLAG = 0x00000001,
- ANIMATION_FLAG = 0x00000002,
- ICCP_FLAG = 0x00000004,
- META_FLAG = 0x00000008,
- ALPHA_FLAG = 0x00000010
-} WebPFeatureFlags;
-
// IDs for different types of chunks.
-typedef enum {
+typedef enum WebPChunkId {
WEBP_CHUNK_VP8X, // VP8X
WEBP_CHUNK_ICCP, // ICCP
- WEBP_CHUNK_LOOP, // LOOP
- WEBP_CHUNK_FRAME, // FRM
- WEBP_CHUNK_TILE, // TILE
+ WEBP_CHUNK_ANIM, // ANIM
+ WEBP_CHUNK_ANMF, // ANMF
+ WEBP_CHUNK_FRGM, // FRGM
WEBP_CHUNK_ALPHA, // ALPH
WEBP_CHUNK_IMAGE, // VP8/VP8L
- WEBP_CHUNK_META, // META
+ WEBP_CHUNK_EXIF, // EXIF
+ WEBP_CHUNK_XMP, // XMP
WEBP_CHUNK_UNKNOWN, // Other chunks.
WEBP_CHUNK_NIL
} WebPChunkId;
-typedef struct WebPMux WebPMux; // main opaque object.
-
-// Data type used to describe 'raw' data, e.g., chunk data
-// (ICC profile, metadata) and WebP compressed image data.
-typedef struct {
- const uint8_t* bytes_;
- size_t size_;
-} WebPData;
-
//------------------------------------------------------------------------------
-// Manipulation of a WebPData object.
-
-// Initializes the contents of the 'webp_data' object with default values.
-WEBP_EXTERN(void) WebPDataInit(WebPData* webp_data);
-// Clears the contents of the 'webp_data' object by calling free(). Does not
-// deallocate the object itself.
-WEBP_EXTERN(void) WebPDataClear(WebPData* webp_data);
-
-// Allocates necessary storage for 'dst' and copies the contents of 'src'.
-// Returns true on success.
-WEBP_EXTERN(int) WebPDataCopy(const WebPData* src, WebPData* dst);
+// Returns the version number of the mux library, packed in hexadecimal using
+// 8bits for each of major/minor/revision. E.g: v2.5.7 is 0x020507.
+WEBP_EXTERN(int) WebPGetMuxVersion(void);
//------------------------------------------------------------------------------
// Life of a Mux object
@@ -118,6 +109,7 @@ WEBP_EXTERN(WebPMux*) WebPNewInternal(int);
// Creates an empty mux object.
// Returns:
// A pointer to the newly created empty mux object.
+// Or NULL in case of memory error.
static WEBP_INLINE WebPMux* WebPMuxNew(void) {
return WebPNewInternal(WEBP_MUX_ABI_VERSION);
}
@@ -136,8 +128,8 @@ WEBP_EXTERN(WebPMux*) WebPMuxCreateInternal(const WebPData*, int, int);
// Creates a mux object from raw data given in WebP RIFF format.
// Parameters:
// bitstream - (in) the bitstream data in WebP RIFF format
-// copy_data - (in) value 1 indicates given data WILL copied to the mux, and
-// value 0 indicates data will NOT be copied.
+// copy_data - (in) value 1 indicates given data WILL be copied to the mux
+// object and value 0 indicates data will NOT be copied.
// Returns:
// A pointer to the mux object created from given data - on success.
// NULL - In case of invalid data or memory error.
@@ -147,295 +139,237 @@ static WEBP_INLINE WebPMux* WebPMuxCreate(const WebPData* bitstream,
}
//------------------------------------------------------------------------------
-// Single Image.
-
-// Sets the image in the mux object. Any existing images (including frame/tile)
-// will be removed.
-// Parameters:
-// mux - (in/out) object in which the image is to be set
-// bitstream - (in) can either be a raw VP8/VP8L bitstream or a single-image
-// WebP file (non-animated and non-tiled)
-// copy_data - (in) value 1 indicates given data WILL copied to the mux, and
-// value 0 indicates data will NOT be copied.
-// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or bitstream is NULL.
-// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
-// WEBP_MUX_OK - on success.
-WEBP_EXTERN(WebPMuxError) WebPMuxSetImage(WebPMux* mux,
- const WebPData* bitstream,
- int copy_data);
-
-// Gets image data from the mux object.
-// The content of 'bitstream' is allocated using malloc(), and NOT
-// owned by the 'mux' object. It MUST be deallocated by the caller by calling
-// WebPDataClear().
-// Parameters:
-// mux - (in) object from which the image is to be fetched
-// bitstream - (out) the image data
-// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if either mux or bitstream is NULL
-// OR mux contains animation/tiling.
-// WEBP_MUX_NOT_FOUND - if image is not present in mux object.
-// WEBP_MUX_OK - on success.
-WEBP_EXTERN(WebPMuxError) WebPMuxGetImage(const WebPMux* mux,
- WebPData* bitstream);
-
-// Deletes the image in the mux object.
-// Parameters:
-// mux - (in/out) object from which the image is to be deleted
-// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL
-// OR if mux contains animation/tiling.
-// WEBP_MUX_NOT_FOUND - if image is not present in mux object.
-// WEBP_MUX_OK - on success.
-WEBP_EXTERN(WebPMuxError) WebPMuxDeleteImage(WebPMux* mux);
+// Non-image chunks.
-//------------------------------------------------------------------------------
-// XMP Metadata.
+// Note: Only non-image related chunks should be managed through chunk APIs.
+// (Image related chunks are: "ANMF", "FRGM", "VP8 ", "VP8L" and "ALPH").
+// To add, get and delete images, use WebPMuxSetImage(), WebPMuxPushFrame(),
+// WebPMuxGetFrame() and WebPMuxDeleteFrame().
-// Sets the XMP metadata in the mux object. Any existing metadata chunk(s) will
-// be removed.
+// Adds a chunk with id 'fourcc' and data 'chunk_data' in the mux object.
+// Any existing chunk(s) with the same id will be removed.
// Parameters:
-// mux - (in/out) object to which the XMP metadata is to be added
-// metadata - (in) the XMP metadata data to be added
-// copy_data - (in) value 1 indicates given data WILL copied to the mux, and
-// value 0 indicates data will NOT be copied.
+// mux - (in/out) object to which the chunk is to be added
+// fourcc - (in) a character array containing the fourcc of the given chunk;
+// e.g., "ICCP", "XMP ", "EXIF" etc.
+// chunk_data - (in) the chunk data to be added
+// copy_data - (in) value 1 indicates given data WILL be copied to the mux
+// object and value 0 indicates data will NOT be copied.
// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if mux or metadata is NULL.
+// WEBP_MUX_INVALID_ARGUMENT - if mux, fourcc or chunk_data is NULL
+// or if fourcc corresponds to an image chunk.
// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
// WEBP_MUX_OK - on success.
-WEBP_EXTERN(WebPMuxError) WebPMuxSetMetadata(WebPMux* mux,
- const WebPData* metadata,
- int copy_data);
+WEBP_EXTERN(WebPMuxError) WebPMuxSetChunk(
+ WebPMux* mux, const char fourcc[4], const WebPData* chunk_data,
+ int copy_data);
-// Gets a reference to the XMP metadata in the mux object.
+// Gets a reference to the data of the chunk with id 'fourcc' in the mux object.
// The caller should NOT free the returned data.
// Parameters:
-// mux - (in) object from which the XMP metadata is to be fetched
-// metadata - (out) XMP metadata
+// mux - (in) object from which the chunk data is to be fetched
+// fourcc - (in) a character array containing the fourcc of the chunk;
+// e.g., "ICCP", "XMP ", "EXIF" etc.
+// chunk_data - (out) returned chunk data
// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if either mux or metadata is NULL.
-// WEBP_MUX_NOT_FOUND - if metadata is not present in mux object.
+// WEBP_MUX_INVALID_ARGUMENT - if mux, fourcc or chunk_data is NULL
+// or if fourcc corresponds to an image chunk.
+// WEBP_MUX_NOT_FOUND - If mux does not contain a chunk with the given id.
// WEBP_MUX_OK - on success.
-WEBP_EXTERN(WebPMuxError) WebPMuxGetMetadata(const WebPMux* mux,
- WebPData* metadata);
+WEBP_EXTERN(WebPMuxError) WebPMuxGetChunk(
+ const WebPMux* mux, const char fourcc[4], WebPData* chunk_data);
-// Deletes the XMP metadata in the mux object.
+// Deletes the chunk with the given 'fourcc' from the mux object.
// Parameters:
-// mux - (in/out) object from which XMP metadata is to be deleted
+// mux - (in/out) object from which the chunk is to be deleted
+// fourcc - (in) a character array containing the fourcc of the chunk;
+// e.g., "ICCP", "XMP ", "EXIF" etc.
// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL
-// WEBP_MUX_NOT_FOUND - If mux does not contain metadata.
+// WEBP_MUX_INVALID_ARGUMENT - if mux or fourcc is NULL
+// or if fourcc corresponds to an image chunk.
+// WEBP_MUX_NOT_FOUND - If mux does not contain a chunk with the given fourcc.
// WEBP_MUX_OK - on success.
-WEBP_EXTERN(WebPMuxError) WebPMuxDeleteMetadata(WebPMux* mux);
+WEBP_EXTERN(WebPMuxError) WebPMuxDeleteChunk(
+ WebPMux* mux, const char fourcc[4]);
//------------------------------------------------------------------------------
-// ICC Color Profile.
-
-// Sets the color profile in the mux object. Any existing color profile chunk(s)
-// will be removed.
+// Images.
+
+// Encapsulates data about a single frame/fragment.
+struct WebPMuxFrameInfo {
+ WebPData bitstream; // image data: can be a raw VP8/VP8L bitstream
+ // or a single-image WebP file.
+ int x_offset; // x-offset of the frame.
+ int y_offset; // y-offset of the frame.
+ int duration; // duration of the frame (in milliseconds).
+
+ WebPChunkId id; // frame type: should be one of WEBP_CHUNK_ANMF,
+ // WEBP_CHUNK_FRGM or WEBP_CHUNK_IMAGE
+ WebPMuxAnimDispose dispose_method; // Disposal method for the frame.
+ WebPMuxAnimBlend blend_method; // Blend operation for the frame.
+ uint32_t pad[1]; // padding for later use
+};
+
+// Sets the (non-animated and non-fragmented) image in the mux object.
+// Note: Any existing images (including frames/fragments) will be removed.
// Parameters:
-// mux - (in/out) object to which the color profile is to be added
-// color_profile - (in) the color profile data to be added
-// copy_data - (in) value 1 indicates given data WILL copied to the mux, and
-// value 0 indicates data will NOT be copied.
-// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if mux or color_profile is NULL
-// WEBP_MUX_MEMORY_ERROR - on memory allocation error
-// WEBP_MUX_OK - on success
-WEBP_EXTERN(WebPMuxError) WebPMuxSetColorProfile(WebPMux* mux,
- const WebPData* color_profile,
- int copy_data);
-
-// Gets a reference to the color profile in the mux object.
-// The caller should NOT free the returned data.
-// Parameters:
-// mux - (in) object from which the color profile data is to be fetched
-// color_profile - (out) color profile data
+// mux - (in/out) object in which the image is to be set
+// bitstream - (in) can be a raw VP8/VP8L bitstream or a single-image
+// WebP file (non-animated and non-fragmented)
+// copy_data - (in) value 1 indicates given data WILL be copied to the mux
+// object and value 0 indicates data will NOT be copied.
// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if either mux or color_profile is NULL.
-// WEBP_MUX_NOT_FOUND - if color profile is not present in mux object.
+// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or bitstream is NULL.
+// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
// WEBP_MUX_OK - on success.
-WEBP_EXTERN(WebPMuxError) WebPMuxGetColorProfile(const WebPMux* mux,
- WebPData* color_profile);
-
-// Deletes the color profile in the mux object.
+WEBP_EXTERN(WebPMuxError) WebPMuxSetImage(
+ WebPMux* mux, const WebPData* bitstream, int copy_data);
+
+// Adds a frame at the end of the mux object.
+// Notes: (1) frame.id should be one of WEBP_CHUNK_ANMF or WEBP_CHUNK_FRGM
+// (2) For setting a non-animated non-fragmented image, use
+// WebPMuxSetImage() instead.
+// (3) Type of frame being pushed must be same as the frames in mux.
+// (4) As WebP only supports even offsets, any odd offset will be snapped
+// to an even location using: offset &= ~1
// Parameters:
-// mux - (in/out) object from which color profile is to be deleted
+// mux - (in/out) object to which the frame is to be added
+// frame - (in) frame data.
+// copy_data - (in) value 1 indicates given data WILL be copied to the mux
+// object and value 0 indicates data will NOT be copied.
// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL
-// WEBP_MUX_NOT_FOUND - If mux does not contain color profile.
-// WEBP_MUX_OK - on success.
-WEBP_EXTERN(WebPMuxError) WebPMuxDeleteColorProfile(WebPMux* mux);
-
-//------------------------------------------------------------------------------
-// Animation.
-
-// Adds an animation frame at the end of the mux object.
-// Note: as WebP only supports even offsets, any odd offset will be snapped to
-// an even location using: offset &= ~1
-// Parameters:
-// mux - (in/out) object to which an animation frame is to be added
-// bitstream - (in) the image data corresponding to the frame. It can either
-// be a raw VP8/VP8L bitstream or a single-image WebP file
-// (non-animated and non-tiled)
-// x_offset - (in) x-offset of the frame to be added
-// y_offset - (in) y-offset of the frame to be added
-// duration - (in) duration of the frame to be added (in milliseconds)
-// copy_data - (in) value 1 indicates given data WILL copied to the mux, and
-// value 0 indicates data will NOT be copied.
-// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or bitstream is NULL
+// WEBP_MUX_INVALID_ARGUMENT - if mux or frame is NULL
+// or if content of 'frame' is invalid.
// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
// WEBP_MUX_OK - on success.
WEBP_EXTERN(WebPMuxError) WebPMuxPushFrame(
- WebPMux* mux, const WebPData* bitstream,
- int x_offset, int y_offset, int duration, int copy_data);
-
-// TODO(urvang): Create a struct as follows to reduce argument list size:
-// typedef struct {
-// WebPData bitstream;
-// int x_offset, y_offset;
-// int duration;
-// } FrameInfo;
-
-// Gets the nth animation frame from the mux object.
-// The content of 'bitstream' is allocated using malloc(), and NOT
+ WebPMux* mux, const WebPMuxFrameInfo* frame, int copy_data);
+
+// Gets the nth frame from the mux object.
+// The content of 'frame->bitstream' is allocated using malloc(), and NOT
// owned by the 'mux' object. It MUST be deallocated by the caller by calling
// WebPDataClear().
// nth=0 has a special meaning - last position.
// Parameters:
// mux - (in) object from which the info is to be fetched
// nth - (in) index of the frame in the mux object
-// bitstream - (out) the image data
-// x_offset - (out) x-offset of the returned frame
-// y_offset - (out) y-offset of the returned frame
-// duration - (out) duration of the returned frame (in milliseconds)
+// frame - (out) data of the returned frame
// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if either mux, bitstream, x_offset,
-// y_offset, or duration is NULL
+// WEBP_MUX_INVALID_ARGUMENT - if mux or frame is NULL.
// WEBP_MUX_NOT_FOUND - if there are less than nth frames in the mux object.
// WEBP_MUX_BAD_DATA - if nth frame chunk in mux is invalid.
+// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
// WEBP_MUX_OK - on success.
WEBP_EXTERN(WebPMuxError) WebPMuxGetFrame(
- const WebPMux* mux, uint32_t nth, WebPData* bitstream,
- int* x_offset, int* y_offset, int* duration);
+ const WebPMux* mux, uint32_t nth, WebPMuxFrameInfo* frame);
-// Deletes an animation frame from the mux object.
+// Deletes a frame from the mux object.
// nth=0 has a special meaning - last position.
// Parameters:
// mux - (in/out) object from which a frame is to be deleted
// nth - (in) The position from which the frame is to be deleted
// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL
+// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL.
// WEBP_MUX_NOT_FOUND - If there are less than nth frames in the mux object
// before deletion.
// WEBP_MUX_OK - on success.
WEBP_EXTERN(WebPMuxError) WebPMuxDeleteFrame(WebPMux* mux, uint32_t nth);
-// Sets the animation loop count in the mux object. Any existing loop count
-// value(s) will be removed.
+//------------------------------------------------------------------------------
+// Animation.
+
+// Animation parameters.
+struct WebPMuxAnimParams {
+ uint32_t bgcolor; // Background color of the canvas stored (in MSB order) as:
+ // Bits 00 to 07: Alpha.
+ // Bits 08 to 15: Red.
+ // Bits 16 to 23: Green.
+ // Bits 24 to 31: Blue.
+ int loop_count; // Number of times to repeat the animation [0 = infinite].
+};
+
+// Sets the animation parameters in the mux object. Any existing ANIM chunks
+// will be removed.
// Parameters:
-// mux - (in/out) object in which loop chunk is to be set/added
-// loop_count - (in) animation loop count value.
-// Note that loop_count of zero denotes infinite loop.
+// mux - (in/out) object in which ANIM chunk is to be set/added
+// params - (in) animation parameters.
// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL
+// WEBP_MUX_INVALID_ARGUMENT - if mux or params is NULL.
// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
// WEBP_MUX_OK - on success.
-WEBP_EXTERN(WebPMuxError) WebPMuxSetLoopCount(WebPMux* mux, int loop_count);
+WEBP_EXTERN(WebPMuxError) WebPMuxSetAnimationParams(
+ WebPMux* mux, const WebPMuxAnimParams* params);
-// Gets the animation loop count from the mux object.
+// Gets the animation parameters from the mux object.
// Parameters:
-// mux - (in) object from which the loop count is to be fetched
-// loop_count - (out) the loop_count value present in the LOOP chunk
+// mux - (in) object from which the animation parameters to be fetched
+// params - (out) animation parameters extracted from the ANIM chunk
// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if either of mux or loop_count is NULL
-// WEBP_MUX_NOT_FOUND - if loop chunk is not present in mux object.
+// WEBP_MUX_INVALID_ARGUMENT - if mux or params is NULL.
+// WEBP_MUX_NOT_FOUND - if ANIM chunk is not present in mux object.
// WEBP_MUX_OK - on success.
-WEBP_EXTERN(WebPMuxError) WebPMuxGetLoopCount(const WebPMux* mux,
- int* loop_count);
+WEBP_EXTERN(WebPMuxError) WebPMuxGetAnimationParams(
+ const WebPMux* mux, WebPMuxAnimParams* params);
//------------------------------------------------------------------------------
-// Tiling.
-
-// Adds a tile at the end of the mux object.
-// Note: as WebP only supports even offsets, any odd offset will be snapped to
-// an even location using: offset &= ~1
-// Parameters:
-// mux - (in/out) object to which a tile is to be added.
-// bitstream - (in) the image data corresponding to the frame. It can either
-// be a raw VP8/VP8L bitstream or a single-image WebP file
-// (non-animated and non-tiled)
-// x_offset - (in) x-offset of the tile to be added
-// y_offset - (in) y-offset of the tile to be added
-// copy_data - (in) value 1 indicates given data WILL copied to the mux, and
-// value 0 indicates data will NOT be copied.
-// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or bitstream is NULL
-// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
-// WEBP_MUX_OK - on success.
-WEBP_EXTERN(WebPMuxError) WebPMuxPushTile(
- WebPMux* mux, const WebPData* bitstream,
- int x_offset, int y_offset, int copy_data);
+// Misc Utilities.
-// Gets the nth tile from the mux object.
-// The content of 'bitstream' is allocated using malloc(), and NOT
-// owned by the 'mux' object. It MUST be deallocated by the caller by calling
-// WebPDataClear().
-// nth=0 has a special meaning - last position.
+// Sets the canvas size for the mux object. The width and height can be
+// specified explicitly or left as zero (0, 0).
+// * When width and height are specified explicitly, then this frame bound is
+// enforced during subsequent calls to WebPMuxAssemble() and an error is
+// reported if any animated frame does not completely fit within the canvas.
+// * When unspecified (0, 0), the constructed canvas will get the frame bounds
+// from the bounding-box over all frames after calling WebPMuxAssemble().
// Parameters:
-// mux - (in) object from which the info is to be fetched
-// nth - (in) index of the tile in the mux object
-// bitstream - (out) the image data
-// x_offset - (out) x-offset of the returned tile
-// y_offset - (out) y-offset of the returned tile
+// mux - (in) object to which the canvas size is to be set
+// width - (in) canvas width
+// height - (in) canvas height
// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if either mux, bitstream, x_offset or
-// y_offset is NULL
-// WEBP_MUX_NOT_FOUND - if there are less than nth tiles in the mux object.
-// WEBP_MUX_BAD_DATA - if nth tile chunk in mux is invalid.
+// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL; or
+// width or height are invalid or out of bounds
// WEBP_MUX_OK - on success.
-WEBP_EXTERN(WebPMuxError) WebPMuxGetTile(
- const WebPMux* mux, uint32_t nth, WebPData* bitstream,
- int* x_offset, int* y_offset);
+WEBP_EXTERN(WebPMuxError) WebPMuxSetCanvasSize(WebPMux* mux,
+ int width, int height);
-// Deletes a tile from the mux object.
-// nth=0 has a special meaning - last position
+// Gets the canvas size from the mux object.
+// Note: This method assumes that the VP8X chunk, if present, is up-to-date.
+// That is, the mux object hasn't been modified since the last call to
+// WebPMuxAssemble() or WebPMuxCreate().
// Parameters:
-// mux - (in/out) object from which a tile is to be deleted
-// nth - (in) The position from which the tile is to be deleted
+// mux - (in) object from which the canvas size is to be fetched
+// width - (out) canvas width
+// height - (out) canvas height
// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL
-// WEBP_MUX_NOT_FOUND - If there are less than nth tiles in the mux object
-// before deletion.
+// WEBP_MUX_INVALID_ARGUMENT - if mux, width or height is NULL.
+// WEBP_MUX_BAD_DATA - if VP8X/VP8/VP8L chunk or canvas size is invalid.
// WEBP_MUX_OK - on success.
-WEBP_EXTERN(WebPMuxError) WebPMuxDeleteTile(WebPMux* mux, uint32_t nth);
-
-//------------------------------------------------------------------------------
-// Misc Utilities.
+WEBP_EXTERN(WebPMuxError) WebPMuxGetCanvasSize(const WebPMux* mux,
+ int* width, int* height);
// Gets the feature flags from the mux object.
+// Note: This method assumes that the VP8X chunk, if present, is up-to-date.
+// That is, the mux object hasn't been modified since the last call to
+// WebPMuxAssemble() or WebPMuxCreate().
// Parameters:
// mux - (in) object from which the features are to be fetched
// flags - (out) the flags specifying which features are present in the
// mux object. This will be an OR of various flag values.
// Enum 'WebPFeatureFlags' can be used to test individual flag values.
// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if mux or flags is NULL
-// WEBP_MUX_NOT_FOUND - if VP8X chunk is not present in mux object.
-// WEBP_MUX_BAD_DATA - if VP8X chunk in mux is invalid.
+// WEBP_MUX_INVALID_ARGUMENT - if mux or flags is NULL.
+// WEBP_MUX_BAD_DATA - if VP8X/VP8/VP8L chunk or canvas size is invalid.
// WEBP_MUX_OK - on success.
WEBP_EXTERN(WebPMuxError) WebPMuxGetFeatures(const WebPMux* mux,
uint32_t* flags);
-// Gets number of chunks having tag value tag in the mux object.
+// Gets number of chunks with the given 'id' in the mux object.
// Parameters:
// mux - (in) object from which the info is to be fetched
// id - (in) chunk id specifying the type of chunk
// num_elements - (out) number of chunks with the given chunk id
// Returns:
-// WEBP_MUX_INVALID_ARGUMENT - if either mux, or num_elements is NULL
+// WEBP_MUX_INVALID_ARGUMENT - if mux, or num_elements is NULL.
// WEBP_MUX_OK - on success.
WEBP_EXTERN(WebPMuxError) WebPMuxNumChunks(const WebPMux* mux,
WebPChunkId id, int* num_elements);
@@ -445,159 +379,151 @@ WEBP_EXTERN(WebPMuxError) WebPMuxNumChunks(const WebPMux* mux,
// Note: The content of 'assembled_data' will be ignored and overwritten.
// Also, the content of 'assembled_data' is allocated using malloc(), and NOT
// owned by the 'mux' object. It MUST be deallocated by the caller by calling
-// WebPDataClear().
+// WebPDataClear(). It's always safe to call WebPDataClear() upon return,
+// even in case of error.
// Parameters:
// mux - (in/out) object whose chunks are to be assembled
// assembled_data - (out) assembled WebP data
// Returns:
// WEBP_MUX_BAD_DATA - if mux object is invalid.
-// WEBP_MUX_INVALID_ARGUMENT - if either mux, output_data or output_size is
-// NULL.
+// WEBP_MUX_INVALID_ARGUMENT - if mux or assembled_data is NULL.
// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
-// WEBP_MUX_OK - on success
+// WEBP_MUX_OK - on success.
WEBP_EXTERN(WebPMuxError) WebPMuxAssemble(WebPMux* mux,
WebPData* assembled_data);
//------------------------------------------------------------------------------
-// Demux API.
-// Enables extraction of image and extended format data from WebP files.
-
-#define WEBP_DEMUX_ABI_VERSION 0x0100 // MAJOR(8b) + MINOR(8b)
-
-typedef struct WebPDemuxer WebPDemuxer;
-
-typedef enum {
- WEBP_DEMUX_PARSING_HEADER, // Not enough data to parse full header.
- WEBP_DEMUX_PARSED_HEADER, // Header parsing complete, data may be available.
- WEBP_DEMUX_DONE // Entire file has been parsed.
-} WebPDemuxState;
-
-//------------------------------------------------------------------------------
-// Life of a Demux object
-
-// Internal, version-checked, entry point
-WEBP_EXTERN(WebPDemuxer*) WebPDemuxInternal(
- const WebPData*, int, WebPDemuxState*, int);
-
-// Parses the WebP file given by 'data'.
-// A complete WebP file must be present in 'data' for the function to succeed.
-// Returns a WebPDemuxer object on successful parse, NULL otherwise.
-static WEBP_INLINE WebPDemuxer* WebPDemux(const WebPData* data) {
- return WebPDemuxInternal(data, 0, NULL, WEBP_DEMUX_ABI_VERSION);
-}
-
-// Parses the WebP file given by 'data'.
-// If 'state' is non-NULL it will be set to indicate the status of the demuxer.
-// Returns a WebPDemuxer object on successful parse, NULL otherwise.
-static WEBP_INLINE WebPDemuxer* WebPDemuxPartial(
- const WebPData* data, WebPDemuxState* state) {
- return WebPDemuxInternal(data, 1, state, WEBP_DEMUX_ABI_VERSION);
+// WebPAnimEncoder API
+//
+// This API allows encoding (possibly) animated WebP images.
+//
+// Code Example:
+/*
+ WebPAnimEncoderOptions enc_options;
+ WebPAnimEncoderOptionsInit(&enc_options);
+ // Tune 'enc_options' as needed.
+ WebPAnimEncoder* enc = WebPAnimEncoderNew(width, height, &enc_options);
+ while(<there are more frames>) {
+ WebPConfig config;
+ WebPConfigInit(&config);
+ // Tune 'config' as needed.
+ WebPAnimEncoderAdd(enc, frame, timestamp_ms, &config);
+ }
+ WebPAnimEncoderAdd(enc, NULL, timestamp_ms, NULL);
+ WebPAnimEncoderAssemble(enc, webp_data);
+ WebPAnimEncoderDelete(enc);
+ // Write the 'webp_data' to a file, or re-mux it further.
+*/
+
+typedef struct WebPAnimEncoder WebPAnimEncoder; // Main opaque object.
+
+// Forward declarations. Defined in encode.h.
+struct WebPPicture;
+struct WebPConfig;
+
+// Global options.
+struct WebPAnimEncoderOptions {
+ WebPMuxAnimParams anim_params; // Animation parameters.
+ int minimize_size; // If true, minimize the output size (slow). Implicitly
+ // disables key-frame insertion.
+ int kmin;
+ int kmax; // Minimum and maximum distance between consecutive key
+ // frames in the output. The library may insert some key
+ // frames as needed to satisfy this criteria.
+ // Note that these conditions should hold: kmax > kmin
+ // and kmin >= kmax / 2 + 1. Also, if kmin == 0, then
+ // key-frame insertion is disabled; and if kmax == 0,
+ // then all frames will be key-frames.
+ int allow_mixed; // If true, use mixed compression mode; may choose
+ // either lossy and lossless for each frame.
+ int verbose; // If true, print info and warning messages to stderr.
+
+ uint32_t padding[4]; // Padding for later use.
+};
+
+// Internal, version-checked, entry point.
+WEBP_EXTERN(int) WebPAnimEncoderOptionsInitInternal(
+ WebPAnimEncoderOptions*, int);
+
+// Should always be called, to initialize a fresh WebPAnimEncoderOptions
+// structure before modification. Returns false in case of version mismatch.
+// WebPAnimEncoderOptionsInit() must have succeeded before using the
+// 'enc_options' object.
+static WEBP_INLINE int WebPAnimEncoderOptionsInit(
+ WebPAnimEncoderOptions* enc_options) {
+ return WebPAnimEncoderOptionsInitInternal(enc_options, WEBP_MUX_ABI_VERSION);
}
-// Frees memory associated with 'dmux'.
-WEBP_EXTERN(void) WebPDemuxDelete(WebPDemuxer* dmux);
-
-//------------------------------------------------------------------------------
-// Data/information extraction.
+// Internal, version-checked, entry point.
+WEBP_EXTERN(WebPAnimEncoder*) WebPAnimEncoderNewInternal(
+ int, int, const WebPAnimEncoderOptions*, int);
-typedef enum {
- WEBP_FF_FORMAT_FLAGS, // Extended format flags present in the 'VP8X' chunk.
- WEBP_FF_CANVAS_WIDTH,
- WEBP_FF_CANVAS_HEIGHT,
- WEBP_FF_LOOP_COUNT
-} WebPFormatFeature;
+// Creates and initializes a WebPAnimEncoder object.
+// Parameters:
+// width/height - (in) canvas width and height of the animation.
+// enc_options - (in) encoding options; can be passed NULL to pick
+// reasonable defaults.
+// Returns:
+// A pointer to the newly created WebPAnimEncoder object.
+// Or NULL in case of memory error.
+static WEBP_INLINE WebPAnimEncoder* WebPAnimEncoderNew(
+ int width, int height, const WebPAnimEncoderOptions* enc_options) {
+ return WebPAnimEncoderNewInternal(width, height, enc_options,
+ WEBP_MUX_ABI_VERSION);
+}
-// Get the 'feature' value from the 'dmux'.
-// NOTE: values are only valid if WebPDemux() was used or WebPDemuxPartial()
-// returned a state > WEBP_DEMUX_PARSING_HEADER.
-WEBP_EXTERN(uint32_t) WebPDemuxGetI(
- const WebPDemuxer* dmux, WebPFormatFeature feature);
+// Optimize the given frame for WebP, encode it and add it to the
+// WebPAnimEncoder object.
+// The last call to 'WebPAnimEncoderAdd' should be with frame = NULL, which
+// indicates that no more frames are to be added. This call is also used to
+// determine the duration of the last frame.
+// Parameters:
+// enc - (in/out) object to which the frame is to be added.
+// frame - (in/out) frame data in ARGB or YUV(A) format. If it is in YUV(A)
+// format, it will be converted to ARGB, which incurs a small loss.
+// timestamp_ms - (in) timestamp of this frame in milliseconds.
+// Duration of a frame would be calculated as
+// "timestamp of next frame - timestamp of this frame".
+// Hence, timestamps should be in non-decreasing order.
+// config - (in) encoding options; can be passed NULL to pick
+// reasonable defaults.
+// Returns:
+// On error, returns false and frame->error_code is set appropriately.
+// Otherwise, returns true.
+WEBP_EXTERN(int) WebPAnimEncoderAdd(
+ WebPAnimEncoder* enc, struct WebPPicture* frame, int timestamp_ms,
+ const struct WebPConfig* config);
+
+// Assemble all frames added so far into a WebP bitstream.
+// This call should be preceded by a call to 'WebPAnimEncoderAdd' with
+// frame = NULL; if not, the duration of the last frame will be internally
+// estimated.
+// Parameters:
+// enc - (in/out) object from which the frames are to be assembled.
+// webp_data - (out) generated WebP bitstream.
+// Returns:
+// True on success.
+WEBP_EXTERN(int) WebPAnimEncoderAssemble(WebPAnimEncoder* enc,
+ WebPData* webp_data);
-//------------------------------------------------------------------------------
-// Frame iteration.
-
-typedef struct {
- int frame_num_;
- int num_frames_;
- int tile_num_;
- int num_tiles_;
- int x_offset_, y_offset_; // offset relative to the canvas.
- int width_, height_; // dimensions of this frame or tile.
- int duration_; // display duration in milliseconds.
- int complete_; // true if 'tile_' contains a full frame. partial images may
- // still be decoded with the WebP incremental decoder.
- WebPData tile_; // The frame or tile given by 'frame_num_' and 'tile_num_'.
-
- uint32_t pad[4]; // padding for later use
- void* private_;
-} WebPIterator;
-
-// Retrieves frame 'frame_number' from 'dmux'.
-// 'iter->tile_' points to the first tile on return from this function.
-// Individual tiles may be extracted using WebPDemuxSetTile().
-// Setting 'frame_number' equal to 0 will return the last frame of the image.
-// Returns false if 'dmux' is NULL or frame 'frame_number' is not present.
-// Call WebPDemuxReleaseIterator() when use of the iterator is complete.
-// NOTE: 'dmux' must persist for the lifetime of 'iter'.
-WEBP_EXTERN(int) WebPDemuxGetFrame(
- const WebPDemuxer* dmux, int frame_number, WebPIterator* iter);
-
-// Sets 'iter->tile_' to point to the next ('iter->frame_num_' + 1) or previous
-// ('iter->frame_num_' - 1) frame. These functions do not loop.
-// Returns true on success, false otherwise.
-WEBP_EXTERN(int) WebPDemuxNextFrame(WebPIterator* iter);
-WEBP_EXTERN(int) WebPDemuxPrevFrame(WebPIterator* iter);
-
-// Sets 'iter->tile_' to reflect tile number 'tile_number'.
-// Returns true if tile 'tile_number' is present, false otherwise.
-WEBP_EXTERN(int) WebPDemuxSelectTile(WebPIterator* iter, int tile_number);
-
-// Releases any memory associated with 'iter'.
-// Must be called before destroying the associated WebPDemuxer with
-// WebPDemuxDelete().
-WEBP_EXTERN(void) WebPDemuxReleaseIterator(WebPIterator* iter);
+// Get error string corresponding to the most recent call using 'enc'. The
+// returned string is owned by 'enc' and is valid only until the next call to
+// WebPAnimEncoderAdd() or WebPAnimEncoderAssemble() or WebPAnimEncoderDelete().
+// Parameters:
+// enc - (in/out) object from which the error string is to be fetched.
+// Returns:
+// NULL if 'enc' is NULL. Otherwise, returns the error string if the last call
+// to 'enc' had an error, or an empty string if the last call was a success.
+WEBP_EXTERN(const char*) WebPAnimEncoderGetError(WebPAnimEncoder* enc);
-//------------------------------------------------------------------------------
-// Chunk iteration.
-
-typedef struct {
- // The current and total number of chunks with the fourcc given to
- // WebPDemuxGetChunk().
- int chunk_num_;
- int num_chunks_;
- WebPData chunk_; // The payload of the chunk.
-
- uint32_t pad[6]; // padding for later use
- void* private_;
-} WebPChunkIterator;
-
-// Retrieves the 'chunk_number' instance of the chunk with id 'fourcc' from
-// 'dmux'.
-// 'fourcc' is a character array containing the fourcc of the chunk to return,
-// e.g., "ICCP", "META", "EXIF", etc.
-// Setting 'chunk_number' equal to 0 will return the last chunk in a set.
-// Returns true if the chunk is found, false otherwise. Image related chunk
-// payloads are accessed through WebPDemuxGetFrame() and related functions.
-// Call WebPDemuxReleaseChunkIterator() when use of the iterator is complete.
-// NOTE: 'dmux' must persist for the lifetime of the iterator.
-WEBP_EXTERN(int) WebPDemuxGetChunk(const WebPDemuxer* dmux,
- const char fourcc[4], int chunk_number,
- WebPChunkIterator* iter);
-
-// Sets 'iter->chunk_' to point to the next ('iter->chunk_num_' + 1) or previous
-// ('iter->chunk_num_' - 1) chunk. These functions do not loop.
-// Returns true on success, false otherwise.
-WEBP_EXTERN(int) WebPDemuxNextChunk(WebPChunkIterator* iter);
-WEBP_EXTERN(int) WebPDemuxPrevChunk(WebPChunkIterator* iter);
-
-// Releases any memory associated with 'iter'.
-// Must be called before destroying the associated WebPDemuxer with
-// WebPDemuxDelete().
-WEBP_EXTERN(void) WebPDemuxReleaseChunkIterator(WebPChunkIterator* iter);
+// Deletes the WebPAnimEncoder object.
+// Parameters:
+// enc - (in/out) object to be deleted
+WEBP_EXTERN(void) WebPAnimEncoderDelete(WebPAnimEncoder* enc);
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/drivers/webp/mux/anim_encode.c b/drivers/webp/mux/anim_encode.c
new file mode 100644
index 0000000000..bb7c0f50b9
--- /dev/null
+++ b/drivers/webp/mux/anim_encode.c
@@ -0,0 +1,1404 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// AnimEncoder implementation.
+//
+
+#include <assert.h>
+#include <limits.h>
+#include <stdio.h>
+
+#include "../utils/utils.h"
+#include "webp/decode.h"
+#include "webp/encode.h"
+#include "webp/format_constants.h"
+#include "webp/mux.h"
+
+#if defined(_MSC_VER) && _MSC_VER < 1900
+#define snprintf _snprintf
+#endif
+
+#define ERROR_STR_MAX_LENGTH 100
+
+//------------------------------------------------------------------------------
+// Internal structs.
+
+// Stores frame rectangle dimensions.
+typedef struct {
+ int x_offset_, y_offset_, width_, height_;
+} FrameRect;
+
+// Used to store two candidates of encoded data for an animation frame. One of
+// the two will be chosen later.
+typedef struct {
+ WebPMuxFrameInfo sub_frame_; // Encoded frame rectangle.
+ WebPMuxFrameInfo key_frame_; // Encoded frame if it is a key-frame.
+ int is_key_frame_; // True if 'key_frame' has been chosen.
+} EncodedFrame;
+
+struct WebPAnimEncoder {
+ const int canvas_width_; // Canvas width.
+ const int canvas_height_; // Canvas height.
+ const WebPAnimEncoderOptions options_; // Global encoding options.
+
+ FrameRect prev_rect_; // Previous WebP frame rectangle.
+ WebPConfig last_config_; // Cached in case a re-encode is needed.
+ WebPConfig last_config2_; // 2nd cached config; only valid if
+ // 'options_.allow_mixed' is true.
+
+ WebPPicture* curr_canvas_; // Only pointer; we don't own memory.
+
+ // Canvas buffers.
+ WebPPicture curr_canvas_copy_; // Possibly modified current canvas.
+ int curr_canvas_copy_modified_; // True if pixels in 'curr_canvas_copy_'
+ // differ from those in 'curr_canvas_'.
+
+ WebPPicture prev_canvas_; // Previous canvas.
+ WebPPicture prev_canvas_disposed_; // Previous canvas disposed to background.
+
+ // Encoded data.
+ EncodedFrame* encoded_frames_; // Array of encoded frames.
+ size_t size_; // Number of allocated frames.
+ size_t start_; // Frame start index.
+ size_t count_; // Number of valid frames.
+ size_t flush_count_; // If >0, 'flush_count' frames starting from
+ // 'start' are ready to be added to mux.
+
+ // key-frame related.
+ int64_t best_delta_; // min(canvas size - frame size) over the frames.
+ // Can be negative in certain cases due to
+ // transparent pixels in a frame.
+ int keyframe_; // Index of selected key-frame relative to 'start_'.
+ int count_since_key_frame_; // Frames seen since the last key-frame.
+
+ int first_timestamp_; // Timestamp of the first frame.
+ int prev_timestamp_; // Timestamp of the last added frame.
+ int prev_candidate_undecided_; // True if it's not yet decided if previous
+ // frame would be a sub-frame or a key-frame.
+
+ // Misc.
+ int is_first_frame_; // True if first frame is yet to be added/being added.
+ int got_null_frame_; // True if WebPAnimEncoderAdd() has already been called
+ // with a NULL frame.
+
+ size_t in_frame_count_; // Number of input frames processed so far.
+ size_t out_frame_count_; // Number of frames added to mux so far. This may be
+ // different from 'in_frame_count_' due to merging.
+
+ WebPMux* mux_; // Muxer to assemble the WebP bitstream.
+ char error_str_[ERROR_STR_MAX_LENGTH]; // Error string. Empty if no error.
+};
+
+// -----------------------------------------------------------------------------
+// Life of WebPAnimEncoder object.
+
+#define DELTA_INFINITY (1ULL << 32)
+#define KEYFRAME_NONE (-1)
+
+// Reset the counters in the WebPAnimEncoder.
+static void ResetCounters(WebPAnimEncoder* const enc) {
+ enc->start_ = 0;
+ enc->count_ = 0;
+ enc->flush_count_ = 0;
+ enc->best_delta_ = DELTA_INFINITY;
+ enc->keyframe_ = KEYFRAME_NONE;
+}
+
+static void DisableKeyframes(WebPAnimEncoderOptions* const enc_options) {
+ enc_options->kmax = INT_MAX;
+ enc_options->kmin = enc_options->kmax - 1;
+}
+
+#define MAX_CACHED_FRAMES 30
+
+static void SanitizeEncoderOptions(WebPAnimEncoderOptions* const enc_options) {
+ int print_warning = enc_options->verbose;
+
+ if (enc_options->minimize_size) {
+ DisableKeyframes(enc_options);
+ }
+
+ if (enc_options->kmin <= 0) {
+ DisableKeyframes(enc_options);
+ print_warning = 0;
+ }
+ if (enc_options->kmax <= 0) { // All frames will be key-frames.
+ enc_options->kmin = 0;
+ enc_options->kmax = 0;
+ return;
+ }
+
+ if (enc_options->kmin >= enc_options->kmax) {
+ enc_options->kmin = enc_options->kmax - 1;
+ if (print_warning) {
+ fprintf(stderr, "WARNING: Setting kmin = %d, so that kmin < kmax.\n",
+ enc_options->kmin);
+ }
+ } else {
+ const int kmin_limit = enc_options->kmax / 2 + 1;
+ if (enc_options->kmin < kmin_limit && kmin_limit < enc_options->kmax) {
+ // This ensures that enc.keyframe + kmin >= kmax is always true. So, we
+ // can flush all the frames in the 'count_since_key_frame == kmax' case.
+ enc_options->kmin = kmin_limit;
+ if (print_warning) {
+ fprintf(stderr,
+ "WARNING: Setting kmin = %d, so that kmin >= kmax / 2 + 1.\n",
+ enc_options->kmin);
+ }
+ }
+ }
+ // Limit the max number of frames that are allocated.
+ if (enc_options->kmax - enc_options->kmin > MAX_CACHED_FRAMES) {
+ enc_options->kmin = enc_options->kmax - MAX_CACHED_FRAMES;
+ if (print_warning) {
+ fprintf(stderr,
+ "WARNING: Setting kmin = %d, so that kmax - kmin <= %d.\n",
+ enc_options->kmin, MAX_CACHED_FRAMES);
+ }
+ }
+ assert(enc_options->kmin < enc_options->kmax);
+}
+
+#undef MAX_CACHED_FRAMES
+
+static void DefaultEncoderOptions(WebPAnimEncoderOptions* const enc_options) {
+ enc_options->anim_params.loop_count = 0;
+ enc_options->anim_params.bgcolor = 0xffffffff; // White.
+ enc_options->minimize_size = 0;
+ DisableKeyframes(enc_options);
+ enc_options->allow_mixed = 0;
+}
+
+int WebPAnimEncoderOptionsInitInternal(WebPAnimEncoderOptions* enc_options,
+ int abi_version) {
+ if (enc_options == NULL ||
+ WEBP_ABI_IS_INCOMPATIBLE(abi_version, WEBP_MUX_ABI_VERSION)) {
+ return 0;
+ }
+ DefaultEncoderOptions(enc_options);
+ return 1;
+}
+
+#define TRANSPARENT_COLOR 0x00ffffff
+
+static void ClearRectangle(WebPPicture* const picture,
+ int left, int top, int width, int height) {
+ int j;
+ for (j = top; j < top + height; ++j) {
+ uint32_t* const dst = picture->argb + j * picture->argb_stride;
+ int i;
+ for (i = left; i < left + width; ++i) {
+ dst[i] = TRANSPARENT_COLOR;
+ }
+ }
+}
+
+static void WebPUtilClearPic(WebPPicture* const picture,
+ const FrameRect* const rect) {
+ if (rect != NULL) {
+ ClearRectangle(picture, rect->x_offset_, rect->y_offset_,
+ rect->width_, rect->height_);
+ } else {
+ ClearRectangle(picture, 0, 0, picture->width, picture->height);
+ }
+}
+
+static void MarkNoError(WebPAnimEncoder* const enc) {
+ enc->error_str_[0] = '\0'; // Empty string.
+}
+
+static void MarkError(WebPAnimEncoder* const enc, const char* str) {
+ if (snprintf(enc->error_str_, ERROR_STR_MAX_LENGTH, "%s.", str) < 0) {
+ assert(0); // FIX ME!
+ }
+}
+
+static void MarkError2(WebPAnimEncoder* const enc,
+ const char* str, int error_code) {
+ if (snprintf(enc->error_str_, ERROR_STR_MAX_LENGTH, "%s: %d.", str,
+ error_code) < 0) {
+ assert(0); // FIX ME!
+ }
+}
+
+WebPAnimEncoder* WebPAnimEncoderNewInternal(
+ int width, int height, const WebPAnimEncoderOptions* enc_options,
+ int abi_version) {
+ WebPAnimEncoder* enc;
+
+ if (WEBP_ABI_IS_INCOMPATIBLE(abi_version, WEBP_MUX_ABI_VERSION)) {
+ return NULL;
+ }
+ if (width <= 0 || height <= 0 ||
+ (width * (uint64_t)height) >= MAX_IMAGE_AREA) {
+ return NULL;
+ }
+
+ enc = (WebPAnimEncoder*)WebPSafeCalloc(1, sizeof(*enc));
+ if (enc == NULL) return NULL;
+ // sanity inits, so we can call WebPAnimEncoderDelete():
+ enc->encoded_frames_ = NULL;
+ enc->mux_ = NULL;
+ MarkNoError(enc);
+
+ // Dimensions and options.
+ *(int*)&enc->canvas_width_ = width;
+ *(int*)&enc->canvas_height_ = height;
+ if (enc_options != NULL) {
+ *(WebPAnimEncoderOptions*)&enc->options_ = *enc_options;
+ SanitizeEncoderOptions((WebPAnimEncoderOptions*)&enc->options_);
+ } else {
+ DefaultEncoderOptions((WebPAnimEncoderOptions*)&enc->options_);
+ }
+
+ // Canvas buffers.
+ if (!WebPPictureInit(&enc->curr_canvas_copy_) ||
+ !WebPPictureInit(&enc->prev_canvas_) ||
+ !WebPPictureInit(&enc->prev_canvas_disposed_)) {
+ goto Err;
+ }
+ enc->curr_canvas_copy_.width = width;
+ enc->curr_canvas_copy_.height = height;
+ enc->curr_canvas_copy_.use_argb = 1;
+ if (!WebPPictureAlloc(&enc->curr_canvas_copy_) ||
+ !WebPPictureCopy(&enc->curr_canvas_copy_, &enc->prev_canvas_) ||
+ !WebPPictureCopy(&enc->curr_canvas_copy_, &enc->prev_canvas_disposed_)) {
+ goto Err;
+ }
+ WebPUtilClearPic(&enc->prev_canvas_, NULL);
+ enc->curr_canvas_copy_modified_ = 1;
+
+ // Encoded frames.
+ ResetCounters(enc);
+ // Note: one extra storage is for the previous frame.
+ enc->size_ = enc->options_.kmax - enc->options_.kmin + 1;
+ // We need space for at least 2 frames. But when kmin, kmax are both zero,
+ // enc->size_ will be 1. So we handle that special case below.
+ if (enc->size_ < 2) enc->size_ = 2;
+ enc->encoded_frames_ =
+ (EncodedFrame*)WebPSafeCalloc(enc->size_, sizeof(*enc->encoded_frames_));
+ if (enc->encoded_frames_ == NULL) goto Err;
+
+ enc->mux_ = WebPMuxNew();
+ if (enc->mux_ == NULL) goto Err;
+
+ enc->count_since_key_frame_ = 0;
+ enc->first_timestamp_ = 0;
+ enc->prev_timestamp_ = 0;
+ enc->prev_candidate_undecided_ = 0;
+ enc->is_first_frame_ = 1;
+ enc->got_null_frame_ = 0;
+
+ return enc; // All OK.
+
+ Err:
+ WebPAnimEncoderDelete(enc);
+ return NULL;
+}
+
+// Release the data contained by 'encoded_frame'.
+static void FrameRelease(EncodedFrame* const encoded_frame) {
+ if (encoded_frame != NULL) {
+ WebPDataClear(&encoded_frame->sub_frame_.bitstream);
+ WebPDataClear(&encoded_frame->key_frame_.bitstream);
+ memset(encoded_frame, 0, sizeof(*encoded_frame));
+ }
+}
+
+void WebPAnimEncoderDelete(WebPAnimEncoder* enc) {
+ if (enc != NULL) {
+ WebPPictureFree(&enc->curr_canvas_copy_);
+ WebPPictureFree(&enc->prev_canvas_);
+ WebPPictureFree(&enc->prev_canvas_disposed_);
+ if (enc->encoded_frames_ != NULL) {
+ size_t i;
+ for (i = 0; i < enc->size_; ++i) {
+ FrameRelease(&enc->encoded_frames_[i]);
+ }
+ WebPSafeFree(enc->encoded_frames_);
+ }
+ WebPMuxDelete(enc->mux_);
+ WebPSafeFree(enc);
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Frame addition.
+
+// Returns cached frame at the given 'position'.
+static EncodedFrame* GetFrame(const WebPAnimEncoder* const enc,
+ size_t position) {
+ assert(enc->start_ + position < enc->size_);
+ return &enc->encoded_frames_[enc->start_ + position];
+}
+
+// Returns true if 'length' number of pixels in 'src' and 'dst' are identical,
+// assuming the given step sizes between pixels.
+static WEBP_INLINE int ComparePixels(const uint32_t* src, int src_step,
+ const uint32_t* dst, int dst_step,
+ int length) {
+ assert(length > 0);
+ while (length-- > 0) {
+ if (*src != *dst) {
+ return 0;
+ }
+ src += src_step;
+ dst += dst_step;
+ }
+ return 1;
+}
+
+static int IsEmptyRect(const FrameRect* const rect) {
+ return (rect->width_ == 0) || (rect->height_ == 0);
+}
+
+// Assumes that an initial valid guess of change rectangle 'rect' is passed.
+static void MinimizeChangeRectangle(const WebPPicture* const src,
+ const WebPPicture* const dst,
+ FrameRect* const rect) {
+ int i, j;
+ // Sanity checks.
+ assert(src->width == dst->width && src->height == dst->height);
+ assert(rect->x_offset_ + rect->width_ <= dst->width);
+ assert(rect->y_offset_ + rect->height_ <= dst->height);
+
+ // Left boundary.
+ for (i = rect->x_offset_; i < rect->x_offset_ + rect->width_; ++i) {
+ const uint32_t* const src_argb =
+ &src->argb[rect->y_offset_ * src->argb_stride + i];
+ const uint32_t* const dst_argb =
+ &dst->argb[rect->y_offset_ * dst->argb_stride + i];
+ if (ComparePixels(src_argb, src->argb_stride, dst_argb, dst->argb_stride,
+ rect->height_)) {
+ --rect->width_; // Redundant column.
+ ++rect->x_offset_;
+ } else {
+ break;
+ }
+ }
+ if (rect->width_ == 0) goto NoChange;
+
+ // Right boundary.
+ for (i = rect->x_offset_ + rect->width_ - 1; i >= rect->x_offset_; --i) {
+ const uint32_t* const src_argb =
+ &src->argb[rect->y_offset_ * src->argb_stride + i];
+ const uint32_t* const dst_argb =
+ &dst->argb[rect->y_offset_ * dst->argb_stride + i];
+ if (ComparePixels(src_argb, src->argb_stride, dst_argb, dst->argb_stride,
+ rect->height_)) {
+ --rect->width_; // Redundant column.
+ } else {
+ break;
+ }
+ }
+ if (rect->width_ == 0) goto NoChange;
+
+ // Top boundary.
+ for (j = rect->y_offset_; j < rect->y_offset_ + rect->height_; ++j) {
+ const uint32_t* const src_argb =
+ &src->argb[j * src->argb_stride + rect->x_offset_];
+ const uint32_t* const dst_argb =
+ &dst->argb[j * dst->argb_stride + rect->x_offset_];
+ if (ComparePixels(src_argb, 1, dst_argb, 1, rect->width_)) {
+ --rect->height_; // Redundant row.
+ ++rect->y_offset_;
+ } else {
+ break;
+ }
+ }
+ if (rect->height_ == 0) goto NoChange;
+
+ // Bottom boundary.
+ for (j = rect->y_offset_ + rect->height_ - 1; j >= rect->y_offset_; --j) {
+ const uint32_t* const src_argb =
+ &src->argb[j * src->argb_stride + rect->x_offset_];
+ const uint32_t* const dst_argb =
+ &dst->argb[j * dst->argb_stride + rect->x_offset_];
+ if (ComparePixels(src_argb, 1, dst_argb, 1, rect->width_)) {
+ --rect->height_; // Redundant row.
+ } else {
+ break;
+ }
+ }
+ if (rect->height_ == 0) goto NoChange;
+
+ if (IsEmptyRect(rect)) {
+ NoChange:
+ rect->x_offset_ = 0;
+ rect->y_offset_ = 0;
+ rect->width_ = 0;
+ rect->height_ = 0;
+ }
+}
+
+// Snap rectangle to even offsets (and adjust dimensions if needed).
+static WEBP_INLINE void SnapToEvenOffsets(FrameRect* const rect) {
+ rect->width_ += (rect->x_offset_ & 1);
+ rect->height_ += (rect->y_offset_ & 1);
+ rect->x_offset_ &= ~1;
+ rect->y_offset_ &= ~1;
+}
+
+// Given previous and current canvas, picks the optimal rectangle for the
+// current frame. The initial guess for 'rect' will be the full canvas.
+static int GetSubRect(const WebPPicture* const prev_canvas,
+ const WebPPicture* const curr_canvas, int is_key_frame,
+ int is_first_frame, int empty_rect_allowed,
+ FrameRect* const rect, WebPPicture* const sub_frame) {
+ rect->x_offset_ = 0;
+ rect->y_offset_ = 0;
+ rect->width_ = curr_canvas->width;
+ rect->height_ = curr_canvas->height;
+ if (!is_key_frame || is_first_frame) { // Optimize frame rectangle.
+ // Note: This behaves as expected for first frame, as 'prev_canvas' is
+ // initialized to a fully transparent canvas in the beginning.
+ MinimizeChangeRectangle(prev_canvas, curr_canvas, rect);
+ }
+
+ if (IsEmptyRect(rect)) {
+ if (empty_rect_allowed) { // No need to get 'sub_frame'.
+ return 1;
+ } else { // Force a 1x1 rectangle.
+ rect->width_ = 1;
+ rect->height_ = 1;
+ assert(rect->x_offset_ == 0);
+ assert(rect->y_offset_ == 0);
+ }
+ }
+
+ SnapToEvenOffsets(rect);
+ return WebPPictureView(curr_canvas, rect->x_offset_, rect->y_offset_,
+ rect->width_, rect->height_, sub_frame);
+}
+
+static void DisposeFrameRectangle(int dispose_method,
+ const FrameRect* const rect,
+ WebPPicture* const curr_canvas) {
+ assert(rect != NULL);
+ if (dispose_method == WEBP_MUX_DISPOSE_BACKGROUND) {
+ WebPUtilClearPic(curr_canvas, rect);
+ }
+}
+
+static uint32_t RectArea(const FrameRect* const rect) {
+ return (uint32_t)rect->width_ * rect->height_;
+}
+
+static int IsBlendingPossible(const WebPPicture* const src,
+ const WebPPicture* const dst,
+ const FrameRect* const rect) {
+ int i, j;
+ assert(src->width == dst->width && src->height == dst->height);
+ assert(rect->x_offset_ + rect->width_ <= dst->width);
+ assert(rect->y_offset_ + rect->height_ <= dst->height);
+ for (j = rect->y_offset_; j < rect->y_offset_ + rect->height_; ++j) {
+ for (i = rect->x_offset_; i < rect->x_offset_ + rect->width_; ++i) {
+ const uint32_t src_pixel = src->argb[j * src->argb_stride + i];
+ const uint32_t dst_pixel = dst->argb[j * dst->argb_stride + i];
+ const uint32_t dst_alpha = dst_pixel >> 24;
+ if (dst_alpha != 0xff && src_pixel != dst_pixel) {
+ // In this case, if we use blending, we can't attain the desired
+ // 'dst_pixel' value for this pixel. So, blending is not possible.
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+#define MIN_COLORS_LOSSY 31 // Don't try lossy below this threshold.
+#define MAX_COLORS_LOSSLESS 194 // Don't try lossless above this threshold.
+#define MAX_COLOR_COUNT 256 // Power of 2 greater than MAX_COLORS_LOSSLESS.
+#define HASH_SIZE (MAX_COLOR_COUNT * 4)
+#define HASH_RIGHT_SHIFT 22 // 32 - log2(HASH_SIZE).
+
+// TODO(urvang): Also used in enc/vp8l.c. Move to utils.
+// If the number of colors in the 'pic' is at least MAX_COLOR_COUNT, return
+// MAX_COLOR_COUNT. Otherwise, return the exact number of colors in the 'pic'.
+static int GetColorCount(const WebPPicture* const pic) {
+ int x, y;
+ int num_colors = 0;
+ uint8_t in_use[HASH_SIZE] = { 0 };
+ uint32_t colors[HASH_SIZE];
+ static const uint32_t kHashMul = 0x1e35a7bd;
+ const uint32_t* argb = pic->argb;
+ const int width = pic->width;
+ const int height = pic->height;
+ uint32_t last_pix = ~argb[0]; // so we're sure that last_pix != argb[0]
+
+ for (y = 0; y < height; ++y) {
+ for (x = 0; x < width; ++x) {
+ int key;
+ if (argb[x] == last_pix) {
+ continue;
+ }
+ last_pix = argb[x];
+ key = (kHashMul * last_pix) >> HASH_RIGHT_SHIFT;
+ while (1) {
+ if (!in_use[key]) {
+ colors[key] = last_pix;
+ in_use[key] = 1;
+ ++num_colors;
+ if (num_colors >= MAX_COLOR_COUNT) {
+ return MAX_COLOR_COUNT; // Exact count not needed.
+ }
+ break;
+ } else if (colors[key] == last_pix) {
+ break; // The color is already there.
+ } else {
+ // Some other color sits here, so do linear conflict resolution.
+ ++key;
+ key &= (HASH_SIZE - 1); // Key mask.
+ }
+ }
+ }
+ argb += pic->argb_stride;
+ }
+ return num_colors;
+}
+
+#undef MAX_COLOR_COUNT
+#undef HASH_SIZE
+#undef HASH_RIGHT_SHIFT
+
+// For pixels in 'rect', replace those pixels in 'dst' that are same as 'src' by
+// transparent pixels.
+static void IncreaseTransparency(const WebPPicture* const src,
+ const FrameRect* const rect,
+ WebPPicture* const dst) {
+ int i, j;
+ assert(src != NULL && dst != NULL && rect != NULL);
+ assert(src->width == dst->width && src->height == dst->height);
+ for (j = rect->y_offset_; j < rect->y_offset_ + rect->height_; ++j) {
+ const uint32_t* const psrc = src->argb + j * src->argb_stride;
+ uint32_t* const pdst = dst->argb + j * dst->argb_stride;
+ for (i = rect->x_offset_; i < rect->x_offset_ + rect->width_; ++i) {
+ if (psrc[i] == pdst[i]) {
+ pdst[i] = TRANSPARENT_COLOR;
+ }
+ }
+ }
+}
+
+#undef TRANSPARENT_COLOR
+
+// Replace similar blocks of pixels by a 'see-through' transparent block
+// with uniform average color.
+static void FlattenSimilarBlocks(const WebPPicture* const src,
+ const FrameRect* const rect,
+ WebPPicture* const dst) {
+ int i, j;
+ const int block_size = 8;
+ const int y_start = (rect->y_offset_ + block_size) & ~(block_size - 1);
+ const int y_end = (rect->y_offset_ + rect->height_) & ~(block_size - 1);
+ const int x_start = (rect->x_offset_ + block_size) & ~(block_size - 1);
+ const int x_end = (rect->x_offset_ + rect->width_) & ~(block_size - 1);
+ assert(src != NULL && dst != NULL && rect != NULL);
+ assert(src->width == dst->width && src->height == dst->height);
+ assert((block_size & (block_size - 1)) == 0); // must be a power of 2
+ // Iterate over each block and count similar pixels.
+ for (j = y_start; j < y_end; j += block_size) {
+ for (i = x_start; i < x_end; i += block_size) {
+ int cnt = 0;
+ int avg_r = 0, avg_g = 0, avg_b = 0;
+ int x, y;
+ const uint32_t* const psrc = src->argb + j * src->argb_stride + i;
+ uint32_t* const pdst = dst->argb + j * dst->argb_stride + i;
+ for (y = 0; y < block_size; ++y) {
+ for (x = 0; x < block_size; ++x) {
+ const uint32_t src_pixel = psrc[x + y * src->argb_stride];
+ const int alpha = src_pixel >> 24;
+ if (alpha == 0xff &&
+ src_pixel == pdst[x + y * dst->argb_stride]) {
+ ++cnt;
+ avg_r += (src_pixel >> 16) & 0xff;
+ avg_g += (src_pixel >> 8) & 0xff;
+ avg_b += (src_pixel >> 0) & 0xff;
+ }
+ }
+ }
+ // If we have a fully similar block, we replace it with an
+ // average transparent block. This compresses better in lossy mode.
+ if (cnt == block_size * block_size) {
+ const uint32_t color = (0x00 << 24) |
+ ((avg_r / cnt) << 16) |
+ ((avg_g / cnt) << 8) |
+ ((avg_b / cnt) << 0);
+ for (y = 0; y < block_size; ++y) {
+ for (x = 0; x < block_size; ++x) {
+ pdst[x + y * dst->argb_stride] = color;
+ }
+ }
+ }
+ }
+ }
+}
+
+static int EncodeFrame(const WebPConfig* const config, WebPPicture* const pic,
+ WebPMemoryWriter* const memory) {
+ pic->use_argb = 1;
+ pic->writer = WebPMemoryWrite;
+ pic->custom_ptr = memory;
+ if (!WebPEncode(config, pic)) {
+ return 0;
+ }
+ return 1;
+}
+
+// Struct representing a candidate encoded frame including its metadata.
+typedef struct {
+ WebPMemoryWriter mem_;
+ WebPMuxFrameInfo info_;
+ FrameRect rect_;
+ int evaluate_; // True if this candidate should be evaluated.
+} Candidate;
+
+// Generates a candidate encoded frame given a picture and metadata.
+static WebPEncodingError EncodeCandidate(WebPPicture* const sub_frame,
+ const FrameRect* const rect,
+ const WebPConfig* const config,
+ int use_blending,
+ Candidate* const candidate) {
+ WebPEncodingError error_code = VP8_ENC_OK;
+ assert(candidate != NULL);
+ memset(candidate, 0, sizeof(*candidate));
+
+ // Set frame rect and info.
+ candidate->rect_ = *rect;
+ candidate->info_.id = WEBP_CHUNK_ANMF;
+ candidate->info_.x_offset = rect->x_offset_;
+ candidate->info_.y_offset = rect->y_offset_;
+ candidate->info_.dispose_method = WEBP_MUX_DISPOSE_NONE; // Set later.
+ candidate->info_.blend_method =
+ use_blending ? WEBP_MUX_BLEND : WEBP_MUX_NO_BLEND;
+ candidate->info_.duration = 0; // Set in next call to WebPAnimEncoderAdd().
+
+ // Encode picture.
+ WebPMemoryWriterInit(&candidate->mem_);
+
+ if (!EncodeFrame(config, sub_frame, &candidate->mem_)) {
+ error_code = sub_frame->error_code;
+ goto Err;
+ }
+
+ candidate->evaluate_ = 1;
+ return error_code;
+
+ Err:
+ WebPMemoryWriterClear(&candidate->mem_);
+ return error_code;
+}
+
+static void CopyCurrentCanvas(WebPAnimEncoder* const enc) {
+ if (enc->curr_canvas_copy_modified_) {
+ WebPCopyPixels(enc->curr_canvas_, &enc->curr_canvas_copy_);
+ enc->curr_canvas_copy_modified_ = 0;
+ }
+}
+
+enum {
+ LL_DISP_NONE = 0,
+ LL_DISP_BG,
+ LOSSY_DISP_NONE,
+ LOSSY_DISP_BG,
+ CANDIDATE_COUNT
+};
+
+// Generates candidates for a given dispose method given pre-filled 'rect'
+// and 'sub_frame'.
+static WebPEncodingError GenerateCandidates(
+ WebPAnimEncoder* const enc, Candidate candidates[CANDIDATE_COUNT],
+ WebPMuxAnimDispose dispose_method, int is_lossless, int is_key_frame,
+ const FrameRect* const rect, WebPPicture* sub_frame,
+ const WebPConfig* const config_ll, const WebPConfig* const config_lossy) {
+ WebPEncodingError error_code = VP8_ENC_OK;
+ const int is_dispose_none = (dispose_method == WEBP_MUX_DISPOSE_NONE);
+ Candidate* const candidate_ll =
+ is_dispose_none ? &candidates[LL_DISP_NONE] : &candidates[LL_DISP_BG];
+ Candidate* const candidate_lossy = is_dispose_none
+ ? &candidates[LOSSY_DISP_NONE]
+ : &candidates[LOSSY_DISP_BG];
+ WebPPicture* const curr_canvas = &enc->curr_canvas_copy_;
+ const WebPPicture* const prev_canvas =
+ is_dispose_none ? &enc->prev_canvas_ : &enc->prev_canvas_disposed_;
+ const int use_blending =
+ !is_key_frame &&
+ IsBlendingPossible(prev_canvas, curr_canvas, rect);
+
+ // Pick candidates to be tried.
+ if (!enc->options_.allow_mixed) {
+ candidate_ll->evaluate_ = is_lossless;
+ candidate_lossy->evaluate_ = !is_lossless;
+ } else { // Use a heuristic for trying lossless and/or lossy compression.
+ const int num_colors = GetColorCount(sub_frame);
+ candidate_ll->evaluate_ = (num_colors < MAX_COLORS_LOSSLESS);
+ candidate_lossy->evaluate_ = (num_colors >= MIN_COLORS_LOSSY);
+ }
+
+ // Generate candidates.
+ if (candidate_ll->evaluate_) {
+ CopyCurrentCanvas(enc);
+ if (use_blending) {
+ IncreaseTransparency(prev_canvas, rect, curr_canvas);
+ enc->curr_canvas_copy_modified_ = 1;
+ }
+ error_code = EncodeCandidate(sub_frame, rect, config_ll, use_blending,
+ candidate_ll);
+ if (error_code != VP8_ENC_OK) return error_code;
+ }
+ if (candidate_lossy->evaluate_) {
+ CopyCurrentCanvas(enc);
+ if (use_blending) {
+ FlattenSimilarBlocks(prev_canvas, rect, curr_canvas);
+ enc->curr_canvas_copy_modified_ = 1;
+ }
+ error_code = EncodeCandidate(sub_frame, rect, config_lossy, use_blending,
+ candidate_lossy);
+ if (error_code != VP8_ENC_OK) return error_code;
+ }
+ return error_code;
+}
+
+#undef MIN_COLORS_LOSSY
+#undef MAX_COLORS_LOSSLESS
+
+static void GetEncodedData(const WebPMemoryWriter* const memory,
+ WebPData* const encoded_data) {
+ encoded_data->bytes = memory->mem;
+ encoded_data->size = memory->size;
+}
+
+// Sets dispose method of the previous frame to be 'dispose_method'.
+static void SetPreviousDisposeMethod(WebPAnimEncoder* const enc,
+ WebPMuxAnimDispose dispose_method) {
+ const size_t position = enc->count_ - 2;
+ EncodedFrame* const prev_enc_frame = GetFrame(enc, position);
+ assert(enc->count_ >= 2); // As current and previous frames are in enc.
+
+ if (enc->prev_candidate_undecided_) {
+ assert(dispose_method == WEBP_MUX_DISPOSE_NONE);
+ prev_enc_frame->sub_frame_.dispose_method = dispose_method;
+ prev_enc_frame->key_frame_.dispose_method = dispose_method;
+ } else {
+ WebPMuxFrameInfo* const prev_info = prev_enc_frame->is_key_frame_
+ ? &prev_enc_frame->key_frame_
+ : &prev_enc_frame->sub_frame_;
+ prev_info->dispose_method = dispose_method;
+ }
+}
+
+static int IncreasePreviousDuration(WebPAnimEncoder* const enc, int duration) {
+ const size_t position = enc->count_ - 1;
+ EncodedFrame* const prev_enc_frame = GetFrame(enc, position);
+ int new_duration;
+
+ assert(enc->count_ >= 1);
+ assert(prev_enc_frame->sub_frame_.duration ==
+ prev_enc_frame->key_frame_.duration);
+ assert(prev_enc_frame->sub_frame_.duration ==
+ (prev_enc_frame->sub_frame_.duration & (MAX_DURATION - 1)));
+ assert(duration == (duration & (MAX_DURATION - 1)));
+
+ new_duration = prev_enc_frame->sub_frame_.duration + duration;
+ if (new_duration >= MAX_DURATION) { // Special case.
+ // Separate out previous frame from earlier merged frames to avoid overflow.
+ // We add a 1x1 transparent frame for the previous frame, with blending on.
+ const FrameRect rect = { 0, 0, 1, 1 };
+ const uint8_t lossless_1x1_bytes[] = {
+ 0x52, 0x49, 0x46, 0x46, 0x14, 0x00, 0x00, 0x00, 0x57, 0x45, 0x42, 0x50,
+ 0x56, 0x50, 0x38, 0x4c, 0x08, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00,
+ 0x10, 0x88, 0x88, 0x08
+ };
+ const WebPData lossless_1x1 = {
+ lossless_1x1_bytes, sizeof(lossless_1x1_bytes)
+ };
+ const uint8_t lossy_1x1_bytes[] = {
+ 0x52, 0x49, 0x46, 0x46, 0x40, 0x00, 0x00, 0x00, 0x57, 0x45, 0x42, 0x50,
+ 0x56, 0x50, 0x38, 0x58, 0x0a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x4c, 0x50, 0x48, 0x02, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x56, 0x50, 0x38, 0x20, 0x18, 0x00, 0x00, 0x00,
+ 0x30, 0x01, 0x00, 0x9d, 0x01, 0x2a, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00,
+ 0x34, 0x25, 0xa4, 0x00, 0x03, 0x70, 0x00, 0xfe, 0xfb, 0xfd, 0x50, 0x00
+ };
+ const WebPData lossy_1x1 = { lossy_1x1_bytes, sizeof(lossy_1x1_bytes) };
+ const int can_use_lossless =
+ (enc->last_config_.lossless || enc->options_.allow_mixed);
+ EncodedFrame* const curr_enc_frame = GetFrame(enc, enc->count_);
+ curr_enc_frame->is_key_frame_ = 0;
+ curr_enc_frame->sub_frame_.id = WEBP_CHUNK_ANMF;
+ curr_enc_frame->sub_frame_.x_offset = 0;
+ curr_enc_frame->sub_frame_.y_offset = 0;
+ curr_enc_frame->sub_frame_.dispose_method = WEBP_MUX_DISPOSE_NONE;
+ curr_enc_frame->sub_frame_.blend_method = WEBP_MUX_BLEND;
+ curr_enc_frame->sub_frame_.duration = duration;
+ if (!WebPDataCopy(can_use_lossless ? &lossless_1x1 : &lossy_1x1,
+ &curr_enc_frame->sub_frame_.bitstream)) {
+ return 0;
+ }
+ ++enc->count_;
+ ++enc->count_since_key_frame_;
+ enc->flush_count_ = enc->count_ - 1;
+ enc->prev_candidate_undecided_ = 0;
+ enc->prev_rect_ = rect;
+ } else { // Regular case.
+ // Increase duration of the previous frame by 'duration'.
+ prev_enc_frame->sub_frame_.duration = new_duration;
+ prev_enc_frame->key_frame_.duration = new_duration;
+ }
+ return 1;
+}
+
+// Pick the candidate encoded frame with smallest size and release other
+// candidates.
+// TODO(later): Perhaps a rough SSIM/PSNR produced by the encoder should
+// also be a criteria, in addition to sizes.
+static void PickBestCandidate(WebPAnimEncoder* const enc,
+ Candidate* const candidates, int is_key_frame,
+ EncodedFrame* const encoded_frame) {
+ int i;
+ int best_idx = -1;
+ size_t best_size = ~0;
+ for (i = 0; i < CANDIDATE_COUNT; ++i) {
+ if (candidates[i].evaluate_) {
+ const size_t candidate_size = candidates[i].mem_.size;
+ if (candidate_size < best_size) {
+ best_idx = i;
+ best_size = candidate_size;
+ }
+ }
+ }
+ assert(best_idx != -1);
+ for (i = 0; i < CANDIDATE_COUNT; ++i) {
+ if (candidates[i].evaluate_) {
+ if (i == best_idx) {
+ WebPMuxFrameInfo* const dst = is_key_frame
+ ? &encoded_frame->key_frame_
+ : &encoded_frame->sub_frame_;
+ *dst = candidates[i].info_;
+ GetEncodedData(&candidates[i].mem_, &dst->bitstream);
+ if (!is_key_frame) {
+ // Note: Previous dispose method only matters for non-keyframes.
+ // Also, we don't want to modify previous dispose method that was
+ // selected when a non key-frame was assumed.
+ const WebPMuxAnimDispose prev_dispose_method =
+ (best_idx == LL_DISP_NONE || best_idx == LOSSY_DISP_NONE)
+ ? WEBP_MUX_DISPOSE_NONE
+ : WEBP_MUX_DISPOSE_BACKGROUND;
+ SetPreviousDisposeMethod(enc, prev_dispose_method);
+ }
+ enc->prev_rect_ = candidates[i].rect_; // save for next frame.
+ } else {
+ WebPMemoryWriterClear(&candidates[i].mem_);
+ candidates[i].evaluate_ = 0;
+ }
+ }
+ }
+}
+
+// Depending on the configuration, tries different compressions
+// (lossy/lossless), dispose methods, blending methods etc to encode the current
+// frame and outputs the best one in 'encoded_frame'.
+// 'frame_skipped' will be set to true if this frame should actually be skipped.
+static WebPEncodingError SetFrame(WebPAnimEncoder* const enc,
+ const WebPConfig* const config,
+ int is_key_frame,
+ EncodedFrame* const encoded_frame,
+ int* const frame_skipped) {
+ int i;
+ WebPEncodingError error_code = VP8_ENC_OK;
+ const WebPPicture* const curr_canvas = &enc->curr_canvas_copy_;
+ const WebPPicture* const prev_canvas = &enc->prev_canvas_;
+ Candidate candidates[CANDIDATE_COUNT];
+ const int is_lossless = config->lossless;
+ const int is_first_frame = enc->is_first_frame_;
+
+ int try_dispose_none = 1; // Default.
+ FrameRect rect_none;
+ WebPPicture sub_frame_none;
+ // First frame cannot be skipped as there is no 'previous frame' to merge it
+ // to. So, empty rectangle is not allowed for the first frame.
+ const int empty_rect_allowed_none = !is_first_frame;
+
+ // If current frame is a key-frame, dispose method of previous frame doesn't
+ // matter, so we don't try dispose to background.
+ // Also, if key-frame insertion is on, and previous frame could be picked as
+ // either a sub-frame or a key-frame, then we can't be sure about what frame
+ // rectangle would be disposed. In that case too, we don't try dispose to
+ // background.
+ const int dispose_bg_possible =
+ !is_key_frame && !enc->prev_candidate_undecided_;
+ int try_dispose_bg = 0; // Default.
+ FrameRect rect_bg;
+ WebPPicture sub_frame_bg;
+
+ WebPConfig config_ll = *config;
+ WebPConfig config_lossy = *config;
+ config_ll.lossless = 1;
+ config_lossy.lossless = 0;
+ enc->last_config_ = *config;
+ enc->last_config2_ = config->lossless ? config_lossy : config_ll;
+ *frame_skipped = 0;
+
+ if (!WebPPictureInit(&sub_frame_none) || !WebPPictureInit(&sub_frame_bg)) {
+ return VP8_ENC_ERROR_INVALID_CONFIGURATION;
+ }
+
+ for (i = 0; i < CANDIDATE_COUNT; ++i) {
+ candidates[i].evaluate_ = 0;
+ }
+
+ // Change-rectangle assuming previous frame was DISPOSE_NONE.
+ GetSubRect(prev_canvas, curr_canvas, is_key_frame, is_first_frame,
+ empty_rect_allowed_none, &rect_none, &sub_frame_none);
+
+ if (IsEmptyRect(&rect_none)) {
+ // Don't encode the frame at all. Instead, the duration of the previous
+ // frame will be increased later.
+ assert(empty_rect_allowed_none);
+ *frame_skipped = 1;
+ goto End;
+ }
+
+ if (dispose_bg_possible) {
+ // Change-rectangle assuming previous frame was DISPOSE_BACKGROUND.
+ WebPPicture* const prev_canvas_disposed = &enc->prev_canvas_disposed_;
+ WebPCopyPixels(prev_canvas, prev_canvas_disposed);
+ DisposeFrameRectangle(WEBP_MUX_DISPOSE_BACKGROUND, &enc->prev_rect_,
+ prev_canvas_disposed);
+ // Even if there is exact pixel match between 'disposed previous canvas' and
+ // 'current canvas', we can't skip current frame, as there may not be exact
+ // pixel match between 'previous canvas' and 'current canvas'. So, we don't
+ // allow empty rectangle in this case.
+ GetSubRect(prev_canvas_disposed, curr_canvas, is_key_frame, is_first_frame,
+ 0 /* empty_rect_allowed */, &rect_bg, &sub_frame_bg);
+ assert(!IsEmptyRect(&rect_bg));
+
+ if (enc->options_.minimize_size) { // Try both dispose methods.
+ try_dispose_bg = 1;
+ try_dispose_none = 1;
+ } else if (RectArea(&rect_bg) < RectArea(&rect_none)) {
+ try_dispose_bg = 1; // Pick DISPOSE_BACKGROUND.
+ try_dispose_none = 0;
+ }
+ }
+
+ if (try_dispose_none) {
+ error_code = GenerateCandidates(
+ enc, candidates, WEBP_MUX_DISPOSE_NONE, is_lossless, is_key_frame,
+ &rect_none, &sub_frame_none, &config_ll, &config_lossy);
+ if (error_code != VP8_ENC_OK) goto Err;
+ }
+
+ if (try_dispose_bg) {
+ assert(!enc->is_first_frame_);
+ assert(dispose_bg_possible);
+ error_code = GenerateCandidates(
+ enc, candidates, WEBP_MUX_DISPOSE_BACKGROUND, is_lossless, is_key_frame,
+ &rect_bg, &sub_frame_bg, &config_ll, &config_lossy);
+ if (error_code != VP8_ENC_OK) goto Err;
+ }
+
+ PickBestCandidate(enc, candidates, is_key_frame, encoded_frame);
+
+ goto End;
+
+ Err:
+ for (i = 0; i < CANDIDATE_COUNT; ++i) {
+ if (candidates[i].evaluate_) {
+ WebPMemoryWriterClear(&candidates[i].mem_);
+ }
+ }
+
+ End:
+ WebPPictureFree(&sub_frame_none);
+ WebPPictureFree(&sub_frame_bg);
+ return error_code;
+}
+
+// Calculate the penalty incurred if we encode given frame as a key frame
+// instead of a sub-frame.
+static int64_t KeyFramePenalty(const EncodedFrame* const encoded_frame) {
+ return ((int64_t)encoded_frame->key_frame_.bitstream.size -
+ encoded_frame->sub_frame_.bitstream.size);
+}
+
+static int CacheFrame(WebPAnimEncoder* const enc,
+ const WebPConfig* const config) {
+ int ok = 0;
+ int frame_skipped = 0;
+ WebPEncodingError error_code = VP8_ENC_OK;
+ const size_t position = enc->count_;
+ EncodedFrame* const encoded_frame = GetFrame(enc, position);
+
+ ++enc->count_;
+
+ if (enc->is_first_frame_) { // Add this as a key-frame.
+ error_code = SetFrame(enc, config, 1, encoded_frame, &frame_skipped);
+ if (error_code != VP8_ENC_OK) goto End;
+ assert(frame_skipped == 0); // First frame can't be skipped, even if empty.
+ assert(position == 0 && enc->count_ == 1);
+ encoded_frame->is_key_frame_ = 1;
+ enc->flush_count_ = 0;
+ enc->count_since_key_frame_ = 0;
+ enc->prev_candidate_undecided_ = 0;
+ } else {
+ ++enc->count_since_key_frame_;
+ if (enc->count_since_key_frame_ <= enc->options_.kmin) {
+ // Add this as a frame rectangle.
+ error_code = SetFrame(enc, config, 0, encoded_frame, &frame_skipped);
+ if (error_code != VP8_ENC_OK) goto End;
+ if (frame_skipped) goto Skip;
+ encoded_frame->is_key_frame_ = 0;
+ enc->flush_count_ = enc->count_ - 1;
+ enc->prev_candidate_undecided_ = 0;
+ } else {
+ int64_t curr_delta;
+
+ // Add this as a frame rectangle to enc.
+ error_code = SetFrame(enc, config, 0, encoded_frame, &frame_skipped);
+ if (error_code != VP8_ENC_OK) goto End;
+ if (frame_skipped) goto Skip;
+
+ // Add this as a key-frame to enc, too.
+ error_code = SetFrame(enc, config, 1, encoded_frame, &frame_skipped);
+ if (error_code != VP8_ENC_OK) goto End;
+ assert(frame_skipped == 0); // Key-frame cannot be an empty rectangle.
+
+ // Analyze size difference of the two variants.
+ curr_delta = KeyFramePenalty(encoded_frame);
+ if (curr_delta <= enc->best_delta_) { // Pick this as the key-frame.
+ if (enc->keyframe_ != KEYFRAME_NONE) {
+ EncodedFrame* const old_keyframe = GetFrame(enc, enc->keyframe_);
+ assert(old_keyframe->is_key_frame_);
+ old_keyframe->is_key_frame_ = 0;
+ }
+ encoded_frame->is_key_frame_ = 1;
+ enc->keyframe_ = (int)position;
+ enc->best_delta_ = curr_delta;
+ enc->flush_count_ = enc->count_ - 1; // We can flush previous frames.
+ } else {
+ encoded_frame->is_key_frame_ = 0;
+ }
+ // Note: We need '>=' below because when kmin and kmax are both zero,
+ // count_since_key_frame will always be > kmax.
+ if (enc->count_since_key_frame_ >= enc->options_.kmax) {
+ enc->flush_count_ = enc->count_ - 1;
+ enc->count_since_key_frame_ = 0;
+ enc->keyframe_ = KEYFRAME_NONE;
+ enc->best_delta_ = DELTA_INFINITY;
+ }
+ enc->prev_candidate_undecided_ = 1;
+ }
+ }
+
+ // Update previous to previous and previous canvases for next call.
+ WebPCopyPixels(enc->curr_canvas_, &enc->prev_canvas_);
+ enc->is_first_frame_ = 0;
+
+ Skip:
+ ok = 1;
+ ++enc->in_frame_count_;
+
+ End:
+ if (!ok || frame_skipped) {
+ FrameRelease(encoded_frame);
+ // We reset some counters, as the frame addition failed/was skipped.
+ --enc->count_;
+ if (!enc->is_first_frame_) --enc->count_since_key_frame_;
+ if (!ok) {
+ MarkError2(enc, "ERROR adding frame. WebPEncodingError", error_code);
+ }
+ }
+ enc->curr_canvas_->error_code = error_code; // report error_code
+ assert(ok || error_code != VP8_ENC_OK);
+ return ok;
+}
+
+static int FlushFrames(WebPAnimEncoder* const enc) {
+ while (enc->flush_count_ > 0) {
+ WebPMuxError err;
+ EncodedFrame* const curr = GetFrame(enc, 0);
+ const WebPMuxFrameInfo* const info =
+ curr->is_key_frame_ ? &curr->key_frame_ : &curr->sub_frame_;
+ assert(enc->mux_ != NULL);
+ err = WebPMuxPushFrame(enc->mux_, info, 1);
+ if (err != WEBP_MUX_OK) {
+ MarkError2(enc, "ERROR adding frame. WebPMuxError", err);
+ return 0;
+ }
+ if (enc->options_.verbose) {
+ fprintf(stderr, "INFO: Added frame. offset:%d,%d dispose:%d blend:%d\n",
+ info->x_offset, info->y_offset, info->dispose_method,
+ info->blend_method);
+ }
+ ++enc->out_frame_count_;
+ FrameRelease(curr);
+ ++enc->start_;
+ --enc->flush_count_;
+ --enc->count_;
+ if (enc->keyframe_ != KEYFRAME_NONE) --enc->keyframe_;
+ }
+
+ if (enc->count_ == 1 && enc->start_ != 0) {
+ // Move enc->start to index 0.
+ const int enc_start_tmp = (int)enc->start_;
+ EncodedFrame temp = enc->encoded_frames_[0];
+ enc->encoded_frames_[0] = enc->encoded_frames_[enc_start_tmp];
+ enc->encoded_frames_[enc_start_tmp] = temp;
+ FrameRelease(&enc->encoded_frames_[enc_start_tmp]);
+ enc->start_ = 0;
+ }
+ return 1;
+}
+
+#undef DELTA_INFINITY
+#undef KEYFRAME_NONE
+
+int WebPAnimEncoderAdd(WebPAnimEncoder* enc, WebPPicture* frame, int timestamp,
+ const WebPConfig* encoder_config) {
+ WebPConfig config;
+
+ if (enc == NULL) {
+ return 0;
+ }
+ MarkNoError(enc);
+
+ if (!enc->is_first_frame_) {
+ // Make sure timestamps are non-decreasing (integer wrap-around is OK).
+ const uint32_t prev_frame_duration =
+ (uint32_t)timestamp - enc->prev_timestamp_;
+ if (prev_frame_duration >= MAX_DURATION) {
+ if (frame != NULL) {
+ frame->error_code = VP8_ENC_ERROR_INVALID_CONFIGURATION;
+ }
+ MarkError(enc, "ERROR adding frame: timestamps must be non-decreasing");
+ return 0;
+ }
+ if (!IncreasePreviousDuration(enc, (int)prev_frame_duration)) {
+ return 0;
+ }
+ } else {
+ enc->first_timestamp_ = timestamp;
+ }
+
+ if (frame == NULL) { // Special: last call.
+ enc->got_null_frame_ = 1;
+ enc->prev_timestamp_ = timestamp;
+ return 1;
+ }
+
+ if (frame->width != enc->canvas_width_ ||
+ frame->height != enc->canvas_height_) {
+ frame->error_code = VP8_ENC_ERROR_INVALID_CONFIGURATION;
+ MarkError(enc, "ERROR adding frame: Invalid frame dimensions");
+ return 0;
+ }
+
+ if (!frame->use_argb) { // Convert frame from YUV(A) to ARGB.
+ if (enc->options_.verbose) {
+ fprintf(stderr, "WARNING: Converting frame from YUV(A) to ARGB format; "
+ "this incurs a small loss.\n");
+ }
+ if (!WebPPictureYUVAToARGB(frame)) {
+ MarkError(enc, "ERROR converting frame from YUV(A) to ARGB");
+ return 0;
+ }
+ }
+
+ if (encoder_config != NULL) {
+ config = *encoder_config;
+ } else {
+ WebPConfigInit(&config);
+ config.lossless = 1;
+ }
+ assert(enc->curr_canvas_ == NULL);
+ enc->curr_canvas_ = frame; // Store reference.
+ assert(enc->curr_canvas_copy_modified_ == 1);
+ CopyCurrentCanvas(enc);
+
+ if (!CacheFrame(enc, &config)) {
+ return 0;
+ }
+
+ if (!FlushFrames(enc)) {
+ return 0;
+ }
+ enc->curr_canvas_ = NULL;
+ enc->curr_canvas_copy_modified_ = 1;
+ enc->prev_timestamp_ = timestamp;
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+// Bitstream assembly.
+
+static int DecodeFrameOntoCanvas(const WebPMuxFrameInfo* const frame,
+ WebPPicture* const canvas) {
+ const WebPData* const image = &frame->bitstream;
+ WebPPicture sub_image;
+ WebPDecoderConfig config;
+ WebPInitDecoderConfig(&config);
+ WebPUtilClearPic(canvas, NULL);
+ if (WebPGetFeatures(image->bytes, image->size, &config.input) !=
+ VP8_STATUS_OK) {
+ return 0;
+ }
+ if (!WebPPictureView(canvas, frame->x_offset, frame->y_offset,
+ config.input.width, config.input.height, &sub_image)) {
+ return 0;
+ }
+ config.output.is_external_memory = 1;
+ config.output.colorspace = MODE_BGRA;
+ config.output.u.RGBA.rgba = (uint8_t*)sub_image.argb;
+ config.output.u.RGBA.stride = sub_image.argb_stride * 4;
+ config.output.u.RGBA.size = config.output.u.RGBA.stride * sub_image.height;
+
+ if (WebPDecode(image->bytes, image->size, &config) != VP8_STATUS_OK) {
+ return 0;
+ }
+ return 1;
+}
+
+static int FrameToFullCanvas(WebPAnimEncoder* const enc,
+ const WebPMuxFrameInfo* const frame,
+ WebPData* const full_image) {
+ WebPPicture* const canvas_buf = &enc->curr_canvas_copy_;
+ WebPMemoryWriter mem1, mem2;
+ WebPMemoryWriterInit(&mem1);
+ WebPMemoryWriterInit(&mem2);
+
+ if (!DecodeFrameOntoCanvas(frame, canvas_buf)) goto Err;
+ if (!EncodeFrame(&enc->last_config_, canvas_buf, &mem1)) goto Err;
+ GetEncodedData(&mem1, full_image);
+
+ if (enc->options_.allow_mixed) {
+ if (!EncodeFrame(&enc->last_config_, canvas_buf, &mem2)) goto Err;
+ if (mem2.size < mem1.size) {
+ GetEncodedData(&mem2, full_image);
+ WebPMemoryWriterClear(&mem1);
+ } else {
+ WebPMemoryWriterClear(&mem2);
+ }
+ }
+ return 1;
+
+ Err:
+ WebPMemoryWriterClear(&mem1);
+ WebPMemoryWriterClear(&mem2);
+ return 0;
+}
+
+// Convert a single-frame animation to a non-animated image if appropriate.
+// TODO(urvang): Can we pick one of the two heuristically (based on frame
+// rectangle and/or presence of alpha)?
+static WebPMuxError OptimizeSingleFrame(WebPAnimEncoder* const enc,
+ WebPData* const webp_data) {
+ WebPMuxError err = WEBP_MUX_OK;
+ int canvas_width, canvas_height;
+ WebPMuxFrameInfo frame;
+ WebPData full_image;
+ WebPData webp_data2;
+ WebPMux* const mux = WebPMuxCreate(webp_data, 0);
+ if (mux == NULL) return WEBP_MUX_BAD_DATA;
+ assert(enc->out_frame_count_ == 1);
+ WebPDataInit(&frame.bitstream);
+ WebPDataInit(&full_image);
+ WebPDataInit(&webp_data2);
+
+ err = WebPMuxGetFrame(mux, 1, &frame);
+ if (err != WEBP_MUX_OK) goto End;
+ if (frame.id != WEBP_CHUNK_ANMF) goto End; // Non-animation: nothing to do.
+ err = WebPMuxGetCanvasSize(mux, &canvas_width, &canvas_height);
+ if (err != WEBP_MUX_OK) goto End;
+ if (!FrameToFullCanvas(enc, &frame, &full_image)) {
+ err = WEBP_MUX_BAD_DATA;
+ goto End;
+ }
+ err = WebPMuxSetImage(mux, &full_image, 1);
+ if (err != WEBP_MUX_OK) goto End;
+ err = WebPMuxAssemble(mux, &webp_data2);
+ if (err != WEBP_MUX_OK) goto End;
+
+ if (webp_data2.size < webp_data->size) { // Pick 'webp_data2' if smaller.
+ WebPDataClear(webp_data);
+ *webp_data = webp_data2;
+ WebPDataInit(&webp_data2);
+ }
+
+ End:
+ WebPDataClear(&frame.bitstream);
+ WebPDataClear(&full_image);
+ WebPMuxDelete(mux);
+ WebPDataClear(&webp_data2);
+ return err;
+}
+
+int WebPAnimEncoderAssemble(WebPAnimEncoder* enc, WebPData* webp_data) {
+ WebPMux* mux;
+ WebPMuxError err;
+
+ if (enc == NULL) {
+ return 0;
+ }
+ MarkNoError(enc);
+
+ if (webp_data == NULL) {
+ MarkError(enc, "ERROR assembling: NULL input");
+ return 0;
+ }
+
+ if (enc->in_frame_count_ == 0) {
+ MarkError(enc, "ERROR: No frames to assemble");
+ return 0;
+ }
+
+ if (!enc->got_null_frame_ && enc->in_frame_count_ > 1 && enc->count_ > 0) {
+ // set duration of the last frame to be avg of durations of previous frames.
+ const double delta_time = enc->prev_timestamp_ - enc->first_timestamp_;
+ const int average_duration = (int)(delta_time / (enc->in_frame_count_ - 1));
+ if (!IncreasePreviousDuration(enc, average_duration)) {
+ return 0;
+ }
+ }
+
+ // Flush any remaining frames.
+ enc->flush_count_ = enc->count_;
+ if (!FlushFrames(enc)) {
+ return 0;
+ }
+
+ // Set definitive canvas size.
+ mux = enc->mux_;
+ err = WebPMuxSetCanvasSize(mux, enc->canvas_width_, enc->canvas_height_);
+ if (err != WEBP_MUX_OK) goto Err;
+
+ err = WebPMuxSetAnimationParams(mux, &enc->options_.anim_params);
+ if (err != WEBP_MUX_OK) goto Err;
+
+ // Assemble into a WebP bitstream.
+ err = WebPMuxAssemble(mux, webp_data);
+ if (err != WEBP_MUX_OK) goto Err;
+
+ if (enc->out_frame_count_ == 1) {
+ err = OptimizeSingleFrame(enc, webp_data);
+ if (err != WEBP_MUX_OK) goto Err;
+ }
+ return 1;
+
+ Err:
+ MarkError2(enc, "ERROR assembling WebP", err);
+ return 0;
+}
+
+const char* WebPAnimEncoderGetError(WebPAnimEncoder* enc) {
+ if (enc == NULL) return NULL;
+ return enc->error_str_;
+}
+
+// -----------------------------------------------------------------------------
diff --git a/drivers/webp/mux/muxedit.c b/drivers/webp/mux/muxedit.c
index 08629d4ae2..b27663f87a 100644
--- a/drivers/webp/mux/muxedit.c
+++ b/drivers/webp/mux/muxedit.c
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Set and delete APIs for mux.
@@ -12,50 +14,51 @@
#include <assert.h>
#include "./muxi.h"
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
+#include "../utils/utils.h"
//------------------------------------------------------------------------------
// Life of a mux object.
static void MuxInit(WebPMux* const mux) {
- if (mux == NULL) return;
+ assert(mux != NULL);
memset(mux, 0, sizeof(*mux));
+ mux->canvas_width_ = 0; // just to be explicit
+ mux->canvas_height_ = 0;
}
WebPMux* WebPNewInternal(int version) {
if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_MUX_ABI_VERSION)) {
return NULL;
} else {
- WebPMux* const mux = (WebPMux*)malloc(sizeof(WebPMux));
- // If mux is NULL MuxInit is a noop.
- MuxInit(mux);
+ WebPMux* const mux = (WebPMux*)WebPSafeMalloc(1ULL, sizeof(WebPMux));
+ if (mux != NULL) MuxInit(mux);
return mux;
}
}
-static void DeleteAllChunks(WebPChunk** const chunk_list) {
- while (*chunk_list) {
- *chunk_list = ChunkDelete(*chunk_list);
+// Delete all images in 'wpi_list'.
+static void DeleteAllImages(WebPMuxImage** const wpi_list) {
+ while (*wpi_list != NULL) {
+ *wpi_list = MuxImageDelete(*wpi_list);
}
}
static void MuxRelease(WebPMux* const mux) {
- if (mux == NULL) return;
- MuxImageDeleteAll(&mux->images_);
- DeleteAllChunks(&mux->vp8x_);
- DeleteAllChunks(&mux->iccp_);
- DeleteAllChunks(&mux->loop_);
- DeleteAllChunks(&mux->meta_);
- DeleteAllChunks(&mux->unknown_);
+ assert(mux != NULL);
+ DeleteAllImages(&mux->images_);
+ ChunkListDelete(&mux->vp8x_);
+ ChunkListDelete(&mux->iccp_);
+ ChunkListDelete(&mux->anim_);
+ ChunkListDelete(&mux->exif_);
+ ChunkListDelete(&mux->xmp_);
+ ChunkListDelete(&mux->unknown_);
}
void WebPMuxDelete(WebPMux* mux) {
- // If mux is NULL MuxRelease is a noop.
- MuxRelease(mux);
- free(mux);
+ if (mux != NULL) {
+ MuxRelease(mux);
+ WebPSafeFree(mux);
+ }
}
//------------------------------------------------------------------------------
@@ -64,81 +67,60 @@ void WebPMuxDelete(WebPMux* mux) {
// Handy MACRO, makes MuxSet() very symmetric to MuxGet().
#define SWITCH_ID_LIST(INDEX, LIST) \
if (idx == (INDEX)) { \
- err = ChunkAssignData(&chunk, data, copy_data, kChunks[(INDEX)].tag); \
+ err = ChunkAssignData(&chunk, data, copy_data, tag); \
if (err == WEBP_MUX_OK) { \
err = ChunkSetNth(&chunk, (LIST), nth); \
} \
return err; \
}
-static WebPMuxError MuxSet(WebPMux* const mux, CHUNK_INDEX idx, uint32_t nth,
+static WebPMuxError MuxSet(WebPMux* const mux, uint32_t tag, uint32_t nth,
const WebPData* const data, int copy_data) {
WebPChunk chunk;
WebPMuxError err = WEBP_MUX_NOT_FOUND;
+ const CHUNK_INDEX idx = ChunkGetIndexFromTag(tag);
assert(mux != NULL);
assert(!IsWPI(kChunks[idx].id));
ChunkInit(&chunk);
- SWITCH_ID_LIST(IDX_VP8X, &mux->vp8x_);
- SWITCH_ID_LIST(IDX_ICCP, &mux->iccp_);
- SWITCH_ID_LIST(IDX_LOOP, &mux->loop_);
- SWITCH_ID_LIST(IDX_META, &mux->meta_);
- if (idx == IDX_UNKNOWN && data->size_ > TAG_SIZE) {
- // For raw-data unknown chunk, the first four bytes should be the tag to be
- // used for the chunk.
- const WebPData tmp = { data->bytes_ + TAG_SIZE, data->size_ - TAG_SIZE };
- err = ChunkAssignData(&chunk, &tmp, copy_data, GetLE32(data->bytes_ + 0));
- if (err == WEBP_MUX_OK)
- err = ChunkSetNth(&chunk, &mux->unknown_, nth);
- }
+ SWITCH_ID_LIST(IDX_VP8X, &mux->vp8x_);
+ SWITCH_ID_LIST(IDX_ICCP, &mux->iccp_);
+ SWITCH_ID_LIST(IDX_ANIM, &mux->anim_);
+ SWITCH_ID_LIST(IDX_EXIF, &mux->exif_);
+ SWITCH_ID_LIST(IDX_XMP, &mux->xmp_);
+ SWITCH_ID_LIST(IDX_UNKNOWN, &mux->unknown_);
return err;
}
#undef SWITCH_ID_LIST
-static WebPMuxError MuxAddChunk(WebPMux* const mux, uint32_t nth, uint32_t tag,
- const uint8_t* data, size_t size,
- int copy_data) {
- const CHUNK_INDEX idx = ChunkGetIndexFromTag(tag);
- const WebPData chunk_data = { data, size };
- assert(mux != NULL);
- assert(size <= MAX_CHUNK_PAYLOAD);
- assert(idx != IDX_NIL);
- return MuxSet(mux, idx, nth, &chunk_data, copy_data);
-}
+// Create data for frame/fragment given image data, offsets and duration.
+static WebPMuxError CreateFrameFragmentData(
+ int width, int height, const WebPMuxFrameInfo* const info, int is_frame,
+ WebPData* const frame_frgm) {
+ uint8_t* frame_frgm_bytes;
+ const size_t frame_frgm_size = kChunks[is_frame ? IDX_ANMF : IDX_FRGM].size;
-// Create data for frame/tile given image data, offsets and duration.
-static WebPMuxError CreateFrameTileData(const WebPData* const image,
- int x_offset, int y_offset,
- int duration, int is_lossless,
- int is_frame,
- WebPData* const frame_tile) {
- int width;
- int height;
- uint8_t* frame_tile_bytes;
- const size_t frame_tile_size = kChunks[is_frame ? IDX_FRAME : IDX_TILE].size;
-
- const int ok = is_lossless ?
- VP8LGetInfo(image->bytes_, image->size_, &width, &height, NULL) :
- VP8GetInfo(image->bytes_, image->size_, image->size_, &width, &height);
- if (!ok) return WEBP_MUX_INVALID_ARGUMENT;
-
- assert(width > 0 && height > 0 && duration > 0);
+ assert(width > 0 && height > 0 && info->duration >= 0);
+ assert(info->dispose_method == (info->dispose_method & 1));
// Note: assertion on upper bounds is done in PutLE24().
- frame_tile_bytes = (uint8_t*)malloc(frame_tile_size);
- if (frame_tile_bytes == NULL) return WEBP_MUX_MEMORY_ERROR;
+ frame_frgm_bytes = (uint8_t*)WebPSafeMalloc(1ULL, frame_frgm_size);
+ if (frame_frgm_bytes == NULL) return WEBP_MUX_MEMORY_ERROR;
- PutLE24(frame_tile_bytes + 0, x_offset / 2);
- PutLE24(frame_tile_bytes + 3, y_offset / 2);
+ PutLE24(frame_frgm_bytes + 0, info->x_offset / 2);
+ PutLE24(frame_frgm_bytes + 3, info->y_offset / 2);
if (is_frame) {
- PutLE24(frame_tile_bytes + 6, width - 1);
- PutLE24(frame_tile_bytes + 9, height - 1);
- PutLE24(frame_tile_bytes + 12, duration - 1);
+ PutLE24(frame_frgm_bytes + 6, width - 1);
+ PutLE24(frame_frgm_bytes + 9, height - 1);
+ PutLE24(frame_frgm_bytes + 12, info->duration);
+ frame_frgm_bytes[15] =
+ (info->blend_method == WEBP_MUX_NO_BLEND ? 2 : 0) |
+ (info->dispose_method == WEBP_MUX_DISPOSE_BACKGROUND ? 1 : 0);
}
- frame_tile->bytes_ = frame_tile_bytes;
- frame_tile->size_ = frame_tile_size;
+ frame_frgm->bytes = frame_frgm_bytes;
+ frame_frgm->size = frame_frgm_size;
return WEBP_MUX_OK;
}
@@ -149,8 +131,8 @@ static WebPMuxError GetImageData(const WebPData* const bitstream,
WebPData* const image, WebPData* const alpha,
int* const is_lossless) {
WebPDataInit(alpha); // Default: no alpha.
- if (bitstream->size_ < TAG_SIZE ||
- memcmp(bitstream->bytes_, "RIFF", TAG_SIZE)) {
+ if (bitstream->size < TAG_SIZE ||
+ memcmp(bitstream->bytes, "RIFF", TAG_SIZE)) {
// It is NOT webp file data. Return input data as is.
*image = *bitstream;
} else {
@@ -166,7 +148,7 @@ static WebPMuxError GetImageData(const WebPData* const bitstream,
}
WebPMuxDelete(mux);
}
- *is_lossless = VP8LCheckSignature(image->bytes_, image->size_);
+ *is_lossless = VP8LCheckSignature(image->bytes, image->size);
return WEBP_MUX_OK;
}
@@ -185,204 +167,166 @@ static WebPMuxError DeleteChunks(WebPChunk** chunk_list, uint32_t tag) {
return err;
}
-static WebPMuxError MuxDeleteAllNamedData(WebPMux* const mux, CHUNK_INDEX idx) {
- const WebPChunkId id = kChunks[idx].id;
- WebPChunk** chunk_list;
-
- if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT;
+static WebPMuxError MuxDeleteAllNamedData(WebPMux* const mux, uint32_t tag) {
+ const WebPChunkId id = ChunkGetIdFromTag(tag);
+ assert(mux != NULL);
if (IsWPI(id)) return WEBP_MUX_INVALID_ARGUMENT;
-
- chunk_list = MuxGetChunkListFromId(mux, id);
- if (chunk_list == NULL) return WEBP_MUX_INVALID_ARGUMENT;
-
- return DeleteChunks(chunk_list, kChunks[idx].tag);
-}
-
-static WebPMuxError DeleteLoopCount(WebPMux* const mux) {
- return MuxDeleteAllNamedData(mux, IDX_LOOP);
+ return DeleteChunks(MuxGetChunkListFromId(mux, id), tag);
}
//------------------------------------------------------------------------------
// Set API(s).
-WebPMuxError WebPMuxSetImage(WebPMux* mux,
- const WebPData* bitstream, int copy_data) {
+WebPMuxError WebPMuxSetChunk(WebPMux* mux, const char fourcc[4],
+ const WebPData* chunk_data, int copy_data) {
+ uint32_t tag;
WebPMuxError err;
- WebPChunk chunk;
- WebPMuxImage wpi;
- WebPData image;
- WebPData alpha;
- int is_lossless;
- int image_tag;
-
- if (mux == NULL || bitstream == NULL || bitstream->bytes_ == NULL ||
- bitstream->size_ > MAX_CHUNK_PAYLOAD) {
+ if (mux == NULL || fourcc == NULL || chunk_data == NULL ||
+ chunk_data->bytes == NULL || chunk_data->size > MAX_CHUNK_PAYLOAD) {
return WEBP_MUX_INVALID_ARGUMENT;
}
+ tag = ChunkGetTagFromFourCC(fourcc);
- // If given data is for a whole webp file,
- // extract only the VP8/VP8L data from it.
- err = GetImageData(bitstream, &image, &alpha, &is_lossless);
- if (err != WEBP_MUX_OK) return err;
- image_tag = is_lossless ? kChunks[IDX_VP8L].tag : kChunks[IDX_VP8].tag;
-
- // Delete the existing images.
- MuxImageDeleteAll(&mux->images_);
-
- MuxImageInit(&wpi);
+ // Delete existing chunk(s) with the same 'fourcc'.
+ err = MuxDeleteAllNamedData(mux, tag);
+ if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err;
- if (alpha.bytes_ != NULL) { // Add alpha chunk.
- ChunkInit(&chunk);
- err = ChunkAssignData(&chunk, &alpha, copy_data, kChunks[IDX_ALPHA].tag);
- if (err != WEBP_MUX_OK) goto Err;
- err = ChunkSetNth(&chunk, &wpi.alpha_, 1);
- if (err != WEBP_MUX_OK) goto Err;
- }
+ // Add the given chunk.
+ return MuxSet(mux, tag, 1, chunk_data, copy_data);
+}
- // Add image chunk.
+// Creates a chunk from given 'data' and sets it as 1st chunk in 'chunk_list'.
+static WebPMuxError AddDataToChunkList(
+ const WebPData* const data, int copy_data, uint32_t tag,
+ WebPChunk** chunk_list) {
+ WebPChunk chunk;
+ WebPMuxError err;
ChunkInit(&chunk);
- err = ChunkAssignData(&chunk, &image, copy_data, image_tag);
+ err = ChunkAssignData(&chunk, data, copy_data, tag);
if (err != WEBP_MUX_OK) goto Err;
- err = ChunkSetNth(&chunk, &wpi.img_, 1);
- if (err != WEBP_MUX_OK) goto Err;
-
- // Add this image to mux.
- err = MuxImagePush(&wpi, &mux->images_);
+ err = ChunkSetNth(&chunk, chunk_list, 1);
if (err != WEBP_MUX_OK) goto Err;
-
- // All OK.
return WEBP_MUX_OK;
-
Err:
- // Something bad happened.
ChunkRelease(&chunk);
- MuxImageRelease(&wpi);
return err;
}
-WebPMuxError WebPMuxSetMetadata(WebPMux* mux, const WebPData* metadata,
- int copy_data) {
- WebPMuxError err;
-
- if (mux == NULL || metadata == NULL || metadata->bytes_ == NULL ||
- metadata->size_ > MAX_CHUNK_PAYLOAD) {
- return WEBP_MUX_INVALID_ARGUMENT;
+// Extracts image & alpha data from the given bitstream and then sets wpi.alpha_
+// and wpi.img_ appropriately.
+static WebPMuxError SetAlphaAndImageChunks(
+ const WebPData* const bitstream, int copy_data, WebPMuxImage* const wpi) {
+ int is_lossless = 0;
+ WebPData image, alpha;
+ WebPMuxError err = GetImageData(bitstream, &image, &alpha, &is_lossless);
+ const int image_tag =
+ is_lossless ? kChunks[IDX_VP8L].tag : kChunks[IDX_VP8].tag;
+ if (err != WEBP_MUX_OK) return err;
+ if (alpha.bytes != NULL) {
+ err = AddDataToChunkList(&alpha, copy_data, kChunks[IDX_ALPHA].tag,
+ &wpi->alpha_);
+ if (err != WEBP_MUX_OK) return err;
}
-
- // Delete the existing metadata chunk(s).
- err = WebPMuxDeleteMetadata(mux);
- if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err;
-
- // Add the given metadata chunk.
- return MuxSet(mux, IDX_META, 1, metadata, copy_data);
+ err = AddDataToChunkList(&image, copy_data, image_tag, &wpi->img_);
+ if (err != WEBP_MUX_OK) return err;
+ return MuxImageFinalize(wpi) ? WEBP_MUX_OK : WEBP_MUX_INVALID_ARGUMENT;
}
-WebPMuxError WebPMuxSetColorProfile(WebPMux* mux, const WebPData* color_profile,
- int copy_data) {
+WebPMuxError WebPMuxSetImage(WebPMux* mux, const WebPData* bitstream,
+ int copy_data) {
+ WebPMuxImage wpi;
WebPMuxError err;
- if (mux == NULL || color_profile == NULL || color_profile->bytes_ == NULL ||
- color_profile->size_ > MAX_CHUNK_PAYLOAD) {
+ // Sanity checks.
+ if (mux == NULL || bitstream == NULL || bitstream->bytes == NULL ||
+ bitstream->size > MAX_CHUNK_PAYLOAD) {
return WEBP_MUX_INVALID_ARGUMENT;
}
- // Delete the existing ICCP chunk(s).
- err = WebPMuxDeleteColorProfile(mux);
- if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err;
-
- // Add the given ICCP chunk.
- return MuxSet(mux, IDX_ICCP, 1, color_profile, copy_data);
-}
-
-WebPMuxError WebPMuxSetLoopCount(WebPMux* mux, int loop_count) {
- WebPMuxError err;
- uint8_t* data = NULL;
+ if (mux->images_ != NULL) {
+ // Only one 'simple image' can be added in mux. So, remove present images.
+ DeleteAllImages(&mux->images_);
+ }
- if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT;
- if (loop_count >= MAX_LOOP_COUNT) return WEBP_MUX_INVALID_ARGUMENT;
+ MuxImageInit(&wpi);
+ err = SetAlphaAndImageChunks(bitstream, copy_data, &wpi);
+ if (err != WEBP_MUX_OK) goto Err;
- // Delete the existing LOOP chunk(s).
- err = DeleteLoopCount(mux);
- if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err;
+ // Add this WebPMuxImage to mux.
+ err = MuxImagePush(&wpi, &mux->images_);
+ if (err != WEBP_MUX_OK) goto Err;
- // Add the given loop count.
- data = (uint8_t*)malloc(kChunks[IDX_LOOP].size);
- if (data == NULL) return WEBP_MUX_MEMORY_ERROR;
+ // All is well.
+ return WEBP_MUX_OK;
- PutLE16(data, loop_count);
- err = MuxAddChunk(mux, 1, kChunks[IDX_LOOP].tag, data,
- kChunks[IDX_LOOP].size, 1);
- free(data);
+ Err: // Something bad happened.
+ MuxImageRelease(&wpi);
return err;
}
-static WebPMuxError MuxPushFrameTileInternal(
- WebPMux* const mux, const WebPData* const bitstream, int x_offset,
- int y_offset, int duration, int copy_data, uint32_t tag) {
- WebPChunk chunk;
- WebPData image;
- WebPData alpha;
+WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPMuxFrameInfo* frame,
+ int copy_data) {
WebPMuxImage wpi;
WebPMuxError err;
- WebPData frame_tile;
- const int is_frame = (tag == kChunks[IDX_FRAME].tag) ? 1 : 0;
- int is_lossless;
- int image_tag;
+ int is_frame;
+ const WebPData* const bitstream = &frame->bitstream;
// Sanity checks.
- if (mux == NULL || bitstream == NULL || bitstream->bytes_ == NULL ||
- bitstream->size_ > MAX_CHUNK_PAYLOAD) {
+ if (mux == NULL || frame == NULL) return WEBP_MUX_INVALID_ARGUMENT;
+
+ is_frame = (frame->id == WEBP_CHUNK_ANMF);
+ if (!(is_frame || (frame->id == WEBP_CHUNK_FRGM))) {
return WEBP_MUX_INVALID_ARGUMENT;
}
- if (x_offset < 0 || x_offset >= MAX_POSITION_OFFSET ||
- y_offset < 0 || y_offset >= MAX_POSITION_OFFSET ||
- duration <= 0 || duration > MAX_DURATION) {
+ if (frame->id == WEBP_CHUNK_FRGM) { // Dead experiment.
return WEBP_MUX_INVALID_ARGUMENT;
}
- // Snap offsets to even positions.
- x_offset &= ~1;
- y_offset &= ~1;
+ if (bitstream->bytes == NULL || bitstream->size > MAX_CHUNK_PAYLOAD) {
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
- // If given data is for a whole webp file,
- // extract only the VP8/VP8L data from it.
- err = GetImageData(bitstream, &image, &alpha, &is_lossless);
- if (err != WEBP_MUX_OK) return err;
- image_tag = is_lossless ? kChunks[IDX_VP8L].tag : kChunks[IDX_VP8].tag;
+ if (mux->images_ != NULL) {
+ const WebPMuxImage* const image = mux->images_;
+ const uint32_t image_id = (image->header_ != NULL) ?
+ ChunkGetIdFromTag(image->header_->tag_) : WEBP_CHUNK_IMAGE;
+ if (image_id != frame->id) {
+ return WEBP_MUX_INVALID_ARGUMENT; // Conflicting frame types.
+ }
+ }
- WebPDataInit(&frame_tile);
- ChunkInit(&chunk);
MuxImageInit(&wpi);
-
- if (alpha.bytes_ != NULL) {
- // Add alpha chunk.
- err = ChunkAssignData(&chunk, &alpha, copy_data, kChunks[IDX_ALPHA].tag);
+ err = SetAlphaAndImageChunks(bitstream, copy_data, &wpi);
+ if (err != WEBP_MUX_OK) goto Err;
+ assert(wpi.img_ != NULL); // As SetAlphaAndImageChunks() was successful.
+
+ {
+ WebPData frame_frgm;
+ const uint32_t tag = kChunks[is_frame ? IDX_ANMF : IDX_FRGM].tag;
+ WebPMuxFrameInfo tmp = *frame;
+ tmp.x_offset &= ~1; // Snap offsets to even.
+ tmp.y_offset &= ~1;
+ if (!is_frame) { // Reset unused values.
+ tmp.duration = 1;
+ tmp.dispose_method = WEBP_MUX_DISPOSE_NONE;
+ tmp.blend_method = WEBP_MUX_BLEND;
+ }
+ if (tmp.x_offset < 0 || tmp.x_offset >= MAX_POSITION_OFFSET ||
+ tmp.y_offset < 0 || tmp.y_offset >= MAX_POSITION_OFFSET ||
+ (tmp.duration < 0 || tmp.duration >= MAX_DURATION) ||
+ tmp.dispose_method != (tmp.dispose_method & 1)) {
+ err = WEBP_MUX_INVALID_ARGUMENT;
+ goto Err;
+ }
+ err = CreateFrameFragmentData(wpi.width_, wpi.height_, &tmp, is_frame,
+ &frame_frgm);
if (err != WEBP_MUX_OK) goto Err;
- err = ChunkSetNth(&chunk, &wpi.alpha_, 1);
+ // Add frame/fragment chunk (with copy_data = 1).
+ err = AddDataToChunkList(&frame_frgm, 1, tag, &wpi.header_);
+ WebPDataClear(&frame_frgm); // frame_frgm owned by wpi.header_ now.
if (err != WEBP_MUX_OK) goto Err;
- ChunkInit(&chunk); // chunk owned by wpi.alpha_ now.
}
- // Add image chunk.
- err = ChunkAssignData(&chunk, &image, copy_data, image_tag);
- if (err != WEBP_MUX_OK) goto Err;
- err = ChunkSetNth(&chunk, &wpi.img_, 1);
- if (err != WEBP_MUX_OK) goto Err;
- ChunkInit(&chunk); // chunk owned by wpi.img_ now.
-
- // Create frame/tile data.
- err = CreateFrameTileData(&image, x_offset, y_offset, duration, is_lossless,
- is_frame, &frame_tile);
- if (err != WEBP_MUX_OK) goto Err;
-
- // Add frame/tile chunk (with copy_data = 1).
- err = ChunkAssignData(&chunk, &frame_tile, 1, tag);
- if (err != WEBP_MUX_OK) goto Err;
- WebPDataClear(&frame_tile);
- err = ChunkSetNth(&chunk, &wpi.header_, 1);
- if (err != WEBP_MUX_OK) goto Err;
- ChunkInit(&chunk); // chunk owned by wpi.header_ now.
-
// Add this WebPMuxImage to mux.
err = MuxImagePush(&wpi, &mux->images_);
if (err != WEBP_MUX_OK) goto Err;
@@ -391,128 +335,114 @@ static WebPMuxError MuxPushFrameTileInternal(
return WEBP_MUX_OK;
Err: // Something bad happened.
- WebPDataClear(&frame_tile);
- ChunkRelease(&chunk);
MuxImageRelease(&wpi);
return err;
}
-WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPData* bitstream,
- int x_offset, int y_offset,
- int duration, int copy_data) {
- return MuxPushFrameTileInternal(mux, bitstream, x_offset, y_offset,
- duration, copy_data, kChunks[IDX_FRAME].tag);
-}
-
-WebPMuxError WebPMuxPushTile(WebPMux* mux, const WebPData* bitstream,
- int x_offset, int y_offset,
- int copy_data) {
- return MuxPushFrameTileInternal(mux, bitstream, x_offset, y_offset,
- 1 /* unused duration */, copy_data,
- kChunks[IDX_TILE].tag);
-}
-
-//------------------------------------------------------------------------------
-// Delete API(s).
-
-WebPMuxError WebPMuxDeleteImage(WebPMux* mux) {
+WebPMuxError WebPMuxSetAnimationParams(WebPMux* mux,
+ const WebPMuxAnimParams* params) {
WebPMuxError err;
+ uint8_t data[ANIM_CHUNK_SIZE];
+ const WebPData anim = { data, ANIM_CHUNK_SIZE };
- if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT;
+ if (mux == NULL || params == NULL) return WEBP_MUX_INVALID_ARGUMENT;
+ if (params->loop_count < 0 || params->loop_count >= MAX_LOOP_COUNT) {
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
- err = MuxValidateForImage(mux);
- if (err != WEBP_MUX_OK) return err;
+ // Delete any existing ANIM chunk(s).
+ err = MuxDeleteAllNamedData(mux, kChunks[IDX_ANIM].tag);
+ if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err;
- // All well, delete image.
- MuxImageDeleteAll(&mux->images_);
- return WEBP_MUX_OK;
+ // Set the animation parameters.
+ PutLE32(data, params->bgcolor);
+ PutLE16(data + 4, params->loop_count);
+ return MuxSet(mux, kChunks[IDX_ANIM].tag, 1, &anim, 1);
}
-WebPMuxError WebPMuxDeleteMetadata(WebPMux* mux) {
- return MuxDeleteAllNamedData(mux, IDX_META);
-}
+WebPMuxError WebPMuxSetCanvasSize(WebPMux* mux,
+ int width, int height) {
+ WebPMuxError err;
+ if (mux == NULL) {
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+ if (width < 0 || height < 0 ||
+ width > MAX_CANVAS_SIZE || height > MAX_CANVAS_SIZE) {
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+ if (width * (uint64_t)height >= MAX_IMAGE_AREA) {
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+ if ((width * height) == 0 && (width | height) != 0) {
+ // one of width / height is zero, but not both -> invalid!
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+ // If we already assembled a VP8X chunk, invalidate it.
+ err = MuxDeleteAllNamedData(mux, kChunks[IDX_VP8X].tag);
+ if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err;
-WebPMuxError WebPMuxDeleteColorProfile(WebPMux* mux) {
- return MuxDeleteAllNamedData(mux, IDX_ICCP);
+ mux->canvas_width_ = width;
+ mux->canvas_height_ = height;
+ return WEBP_MUX_OK;
}
-static WebPMuxError DeleteFrameTileInternal(WebPMux* const mux, uint32_t nth,
- CHUNK_INDEX idx) {
- const WebPChunkId id = kChunks[idx].id;
- if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT;
+//------------------------------------------------------------------------------
+// Delete API(s).
- assert(idx == IDX_FRAME || idx == IDX_TILE);
- return MuxImageDeleteNth(&mux->images_, nth, id);
+WebPMuxError WebPMuxDeleteChunk(WebPMux* mux, const char fourcc[4]) {
+ if (mux == NULL || fourcc == NULL) return WEBP_MUX_INVALID_ARGUMENT;
+ return MuxDeleteAllNamedData(mux, ChunkGetTagFromFourCC(fourcc));
}
WebPMuxError WebPMuxDeleteFrame(WebPMux* mux, uint32_t nth) {
- return DeleteFrameTileInternal(mux, nth, IDX_FRAME);
-}
-
-WebPMuxError WebPMuxDeleteTile(WebPMux* mux, uint32_t nth) {
- return DeleteFrameTileInternal(mux, nth, IDX_TILE);
+ if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT;
+ return MuxImageDeleteNth(&mux->images_, nth);
}
//------------------------------------------------------------------------------
// Assembly of the WebP RIFF file.
-static WebPMuxError GetFrameTileInfo(const WebPChunk* const frame_tile_chunk,
- int* const x_offset, int* const y_offset,
- int* const duration) {
- const uint32_t tag = frame_tile_chunk->tag_;
- const int is_frame = (tag == kChunks[IDX_FRAME].tag);
- const WebPData* const data = &frame_tile_chunk->data_;
+static WebPMuxError GetFrameFragmentInfo(
+ const WebPChunk* const frame_frgm_chunk,
+ int* const x_offset, int* const y_offset, int* const duration) {
+ const uint32_t tag = frame_frgm_chunk->tag_;
+ const int is_frame = (tag == kChunks[IDX_ANMF].tag);
+ const WebPData* const data = &frame_frgm_chunk->data_;
const size_t expected_data_size =
- is_frame ? FRAME_CHUNK_SIZE : TILE_CHUNK_SIZE;
- assert(frame_tile_chunk != NULL);
- assert(tag == kChunks[IDX_FRAME].tag || tag == kChunks[IDX_TILE].tag);
- if (data->size_ != expected_data_size) return WEBP_MUX_INVALID_ARGUMENT;
-
- *x_offset = 2 * GetLE24(data->bytes_ + 0);
- *y_offset = 2 * GetLE24(data->bytes_ + 3);
- if (is_frame) *duration = 1 + GetLE24(data->bytes_ + 12);
+ is_frame ? ANMF_CHUNK_SIZE : FRGM_CHUNK_SIZE;
+ assert(frame_frgm_chunk != NULL);
+ assert(tag == kChunks[IDX_ANMF].tag || tag == kChunks[IDX_FRGM].tag);
+ if (data->size != expected_data_size) return WEBP_MUX_INVALID_ARGUMENT;
+
+ *x_offset = 2 * GetLE24(data->bytes + 0);
+ *y_offset = 2 * GetLE24(data->bytes + 3);
+ if (is_frame) *duration = GetLE24(data->bytes + 12);
return WEBP_MUX_OK;
}
-WebPMuxError MuxGetImageWidthHeight(const WebPChunk* const image_chunk,
- int* const width, int* const height) {
- const uint32_t tag = image_chunk->tag_;
- const WebPData* const data = &image_chunk->data_;
- int w, h;
- int ok;
- assert(image_chunk != NULL);
- assert(tag == kChunks[IDX_VP8].tag || tag == kChunks[IDX_VP8L].tag);
- ok = (tag == kChunks[IDX_VP8].tag) ?
- VP8GetInfo(data->bytes_, data->size_, data->size_, &w, &h) :
- VP8LGetInfo(data->bytes_, data->size_, &w, &h, NULL);
- if (ok) {
- *width = w;
- *height = h;
- return WEBP_MUX_OK;
- } else {
- return WEBP_MUX_BAD_DATA;
- }
-}
-
static WebPMuxError GetImageInfo(const WebPMuxImage* const wpi,
int* const x_offset, int* const y_offset,
int* const duration,
int* const width, int* const height) {
- const WebPChunk* const image_chunk = wpi->img_;
- const WebPChunk* const frame_tile_chunk = wpi->header_;
+ const WebPChunk* const frame_frgm_chunk = wpi->header_;
+ WebPMuxError err;
+ assert(wpi != NULL);
+ assert(frame_frgm_chunk != NULL);
- // Get offsets and duration from FRM/TILE chunk.
- const WebPMuxError err =
- GetFrameTileInfo(frame_tile_chunk, x_offset, y_offset, duration);
+ // Get offsets and duration from ANMF/FRGM chunk.
+ err = GetFrameFragmentInfo(frame_frgm_chunk, x_offset, y_offset, duration);
if (err != WEBP_MUX_OK) return err;
// Get width and height from VP8/VP8L chunk.
- return MuxGetImageWidthHeight(image_chunk, width, height);
+ if (width != NULL) *width = wpi->width_;
+ if (height != NULL) *height = wpi->height_;
+ return WEBP_MUX_OK;
}
-static WebPMuxError GetImageCanvasWidthHeight(
- const WebPMux* const mux, uint32_t flags,
- int* const width, int* const height) {
+// Returns the tightest dimension for the canvas considering the image list.
+static WebPMuxError GetAdjustedCanvasSize(const WebPMux* const mux,
+ uint32_t flags,
+ int* const width, int* const height) {
WebPMuxImage* wpi = NULL;
assert(mux != NULL);
assert(width != NULL && height != NULL);
@@ -521,13 +451,15 @@ static WebPMuxError GetImageCanvasWidthHeight(
assert(wpi != NULL);
assert(wpi->img_ != NULL);
- if (wpi->next_) {
+ if (wpi->next_ != NULL) {
int max_x = 0;
int max_y = 0;
int64_t image_area = 0;
- // Aggregate the bounding box for animation frames & tiled images.
+ // if we have a chain of wpi's, header_ is necessarily set
+ assert(wpi->header_ != NULL);
+ // Aggregate the bounding box for animation frames & fragmented images.
for (; wpi != NULL; wpi = wpi->next_) {
- int x_offset, y_offset, duration, w, h;
+ int x_offset = 0, y_offset = 0, duration = 0, w = 0, h = 0;
const WebPMuxError err = GetImageInfo(wpi, &x_offset, &y_offset,
&duration, &w, &h);
const int max_x_pos = x_offset + w;
@@ -542,23 +474,19 @@ static WebPMuxError GetImageCanvasWidthHeight(
}
*width = max_x;
*height = max_y;
- // Crude check to validate that there are no image overlaps/holes for tile
- // images. Check that the aggregated image area for individual tiles exactly
- // matches the image area of the constructed canvas. However, the area-match
- // is necessary but not sufficient condition.
- if ((flags & TILE_FLAG) && (image_area != (max_x * max_y))) {
+ // Crude check to validate that there are no image overlaps/holes for
+ // fragmented images. Check that the aggregated image area for individual
+ // fragments exactly matches the image area of the constructed canvas.
+ // However, the area-match is necessary but not sufficient condition.
+ if ((flags & FRAGMENTS_FLAG) && (image_area != (max_x * max_y))) {
*width = 0;
*height = 0;
return WEBP_MUX_INVALID_ARGUMENT;
}
} else {
- // For a single image, extract the width & height from VP8/VP8L image-data.
- int w, h;
- const WebPChunk* const image_chunk = wpi->img_;
- const WebPMuxError err = MuxGetImageWidthHeight(image_chunk, &w, &h);
- if (err != WEBP_MUX_OK) return err;
- *width = w;
- *height = h;
+ // For a single image, canvas dimensions are same as image dimensions.
+ *width = wpi->width_;
+ *height = wpi->height_;
}
return WEBP_MUX_OK;
}
@@ -574,50 +502,45 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) {
int width = 0;
int height = 0;
uint8_t data[VP8X_CHUNK_SIZE];
- const size_t data_size = VP8X_CHUNK_SIZE;
+ const WebPData vp8x = { data, VP8X_CHUNK_SIZE };
const WebPMuxImage* images = NULL;
assert(mux != NULL);
images = mux->images_; // First image.
if (images == NULL || images->img_ == NULL ||
- images->img_->data_.bytes_ == NULL) {
+ images->img_->data_.bytes == NULL) {
return WEBP_MUX_INVALID_ARGUMENT;
}
// If VP8X chunk(s) is(are) already present, remove them (and later add new
// VP8X chunk with updated flags).
- err = MuxDeleteAllNamedData(mux, IDX_VP8X);
+ err = MuxDeleteAllNamedData(mux, kChunks[IDX_VP8X].tag);
if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err;
// Set flags.
- if (mux->iccp_ != NULL && mux->iccp_->data_.bytes_ != NULL) {
+ if (mux->iccp_ != NULL && mux->iccp_->data_.bytes != NULL) {
flags |= ICCP_FLAG;
}
-
- if (mux->meta_ != NULL && mux->meta_->data_.bytes_ != NULL) {
- flags |= META_FLAG;
+ if (mux->exif_ != NULL && mux->exif_->data_.bytes != NULL) {
+ flags |= EXIF_FLAG;
+ }
+ if (mux->xmp_ != NULL && mux->xmp_->data_.bytes != NULL) {
+ flags |= XMP_FLAG;
}
-
if (images->header_ != NULL) {
- if (images->header_->tag_ == kChunks[IDX_TILE].tag) {
- // This is a tiled image.
- flags |= TILE_FLAG;
- } else if (images->header_->tag_ == kChunks[IDX_FRAME].tag) {
+ if (images->header_->tag_ == kChunks[IDX_FRGM].tag) {
+ // This is a fragmented image.
+ flags |= FRAGMENTS_FLAG;
+ } else if (images->header_->tag_ == kChunks[IDX_ANMF].tag) {
// This is an image with animation.
flags |= ANIMATION_FLAG;
}
}
-
if (MuxImageCount(images, WEBP_CHUNK_ALPHA) > 0) {
flags |= ALPHA_FLAG; // Some images have an alpha channel.
}
- if (flags == 0) {
- // For Simple Image, VP8X chunk should not be added.
- return WEBP_MUX_OK;
- }
-
- err = GetImageCanvasWidthHeight(mux, flags, &width, &height);
+ err = GetAdjustedCanvasSize(mux, flags, &width, &height);
if (err != WEBP_MUX_OK) return err;
if (width <= 0 || height <= 0) {
@@ -627,9 +550,21 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) {
return WEBP_MUX_INVALID_ARGUMENT;
}
- if (MuxHasLosslessImages(images)) {
- // We have a file with a VP8X chunk having some lossless images.
- // As lossless images implicitly contain alpha, force ALPHA_FLAG to be true.
+ if (mux->canvas_width_ != 0 || mux->canvas_height_ != 0) {
+ if (width > mux->canvas_width_ || height > mux->canvas_height_) {
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+ width = mux->canvas_width_;
+ height = mux->canvas_height_;
+ }
+
+ if (flags == 0) {
+ // For Simple Image, VP8X chunk should not be added.
+ return WEBP_MUX_OK;
+ }
+
+ if (MuxHasAlpha(images)) {
+ // This means some frames explicitly/implicitly contain alpha.
// Note: This 'flags' update must NOT be done for a lossless image
// without a VP8X chunk!
flags |= ALPHA_FLAG;
@@ -639,74 +574,123 @@ static WebPMuxError CreateVP8XChunk(WebPMux* const mux) {
PutLE24(data + 4, width - 1); // canvas width.
PutLE24(data + 7, height - 1); // canvas height.
- err = MuxAddChunk(mux, 1, kChunks[IDX_VP8X].tag, data, data_size, 1);
- return err;
+ return MuxSet(mux, kChunks[IDX_VP8X].tag, 1, &vp8x, 1);
+}
+
+// Cleans up 'mux' by removing any unnecessary chunks.
+static WebPMuxError MuxCleanup(WebPMux* const mux) {
+ int num_frames;
+ int num_fragments;
+ int num_anim_chunks;
+
+ // If we have an image with a single fragment or frame, and its rectangle
+ // covers the whole canvas, convert it to a non-animated non-fragmented image
+ // (to avoid writing FRGM/ANMF chunk unnecessarily).
+ WebPMuxError err = WebPMuxNumChunks(mux, kChunks[IDX_ANMF].id, &num_frames);
+ if (err != WEBP_MUX_OK) return err;
+ err = WebPMuxNumChunks(mux, kChunks[IDX_FRGM].id, &num_fragments);
+ if (err != WEBP_MUX_OK) return err;
+ if (num_frames == 1 || num_fragments == 1) {
+ WebPMuxImage* frame_frag;
+ err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, 1, &frame_frag);
+ assert(err == WEBP_MUX_OK); // We know that one frame/fragment does exist.
+ assert(frame_frag != NULL);
+ if (frame_frag->header_ != NULL &&
+ ((mux->canvas_width_ == 0 && mux->canvas_height_ == 0) ||
+ (frame_frag->width_ == mux->canvas_width_ &&
+ frame_frag->height_ == mux->canvas_height_))) {
+ assert(frame_frag->header_->tag_ == kChunks[IDX_ANMF].tag ||
+ frame_frag->header_->tag_ == kChunks[IDX_FRGM].tag);
+ ChunkDelete(frame_frag->header_); // Removes ANMF/FRGM chunk.
+ frame_frag->header_ = NULL;
+ num_frames = 0;
+ num_fragments = 0;
+ }
+ }
+ // Remove ANIM chunk if this is a non-animated image.
+ err = WebPMuxNumChunks(mux, kChunks[IDX_ANIM].id, &num_anim_chunks);
+ if (err != WEBP_MUX_OK) return err;
+ if (num_anim_chunks >= 1 && num_frames == 0) {
+ err = MuxDeleteAllNamedData(mux, kChunks[IDX_ANIM].tag);
+ if (err != WEBP_MUX_OK) return err;
+ }
+ return WEBP_MUX_OK;
+}
+
+// Total size of a list of images.
+static size_t ImageListDiskSize(const WebPMuxImage* wpi_list) {
+ size_t size = 0;
+ while (wpi_list != NULL) {
+ size += MuxImageDiskSize(wpi_list);
+ wpi_list = wpi_list->next_;
+ }
+ return size;
+}
+
+// Write out the given list of images into 'dst'.
+static uint8_t* ImageListEmit(const WebPMuxImage* wpi_list, uint8_t* dst) {
+ while (wpi_list != NULL) {
+ dst = MuxImageEmit(wpi_list, dst);
+ wpi_list = wpi_list->next_;
+ }
+ return dst;
}
WebPMuxError WebPMuxAssemble(WebPMux* mux, WebPData* assembled_data) {
size_t size = 0;
uint8_t* data = NULL;
uint8_t* dst = NULL;
- int num_frames;
- int num_loop_chunks;
WebPMuxError err;
- if (mux == NULL || assembled_data == NULL) {
+ if (assembled_data == NULL) {
return WEBP_MUX_INVALID_ARGUMENT;
}
+ // Clean up returned data, in case something goes wrong.
+ memset(assembled_data, 0, sizeof(*assembled_data));
- // Remove LOOP chunk if unnecessary.
- err = WebPMuxNumChunks(mux, kChunks[IDX_LOOP].id, &num_loop_chunks);
- if (err != WEBP_MUX_OK) return err;
- if (num_loop_chunks >= 1) {
- err = WebPMuxNumChunks(mux, kChunks[IDX_FRAME].id, &num_frames);
- if (err != WEBP_MUX_OK) return err;
- if (num_frames == 0) {
- err = DeleteLoopCount(mux);
- if (err != WEBP_MUX_OK) return err;
- }
+ if (mux == NULL) {
+ return WEBP_MUX_INVALID_ARGUMENT;
}
- // Create VP8X chunk.
+ // Finalize mux.
+ err = MuxCleanup(mux);
+ if (err != WEBP_MUX_OK) return err;
err = CreateVP8XChunk(mux);
if (err != WEBP_MUX_OK) return err;
// Allocate data.
- size = ChunksListDiskSize(mux->vp8x_) + ChunksListDiskSize(mux->iccp_)
- + ChunksListDiskSize(mux->loop_) + MuxImageListDiskSize(mux->images_)
- + ChunksListDiskSize(mux->meta_) + ChunksListDiskSize(mux->unknown_)
- + RIFF_HEADER_SIZE;
+ size = ChunkListDiskSize(mux->vp8x_) + ChunkListDiskSize(mux->iccp_)
+ + ChunkListDiskSize(mux->anim_) + ImageListDiskSize(mux->images_)
+ + ChunkListDiskSize(mux->exif_) + ChunkListDiskSize(mux->xmp_)
+ + ChunkListDiskSize(mux->unknown_) + RIFF_HEADER_SIZE;
- data = (uint8_t*)malloc(size);
+ data = (uint8_t*)WebPSafeMalloc(1ULL, size);
if (data == NULL) return WEBP_MUX_MEMORY_ERROR;
// Emit header & chunks.
dst = MuxEmitRiffHeader(data, size);
dst = ChunkListEmit(mux->vp8x_, dst);
dst = ChunkListEmit(mux->iccp_, dst);
- dst = ChunkListEmit(mux->loop_, dst);
- dst = MuxImageListEmit(mux->images_, dst);
- dst = ChunkListEmit(mux->meta_, dst);
+ dst = ChunkListEmit(mux->anim_, dst);
+ dst = ImageListEmit(mux->images_, dst);
+ dst = ChunkListEmit(mux->exif_, dst);
+ dst = ChunkListEmit(mux->xmp_, dst);
dst = ChunkListEmit(mux->unknown_, dst);
assert(dst == data + size);
// Validate mux.
err = MuxValidate(mux);
if (err != WEBP_MUX_OK) {
- free(data);
+ WebPSafeFree(data);
data = NULL;
size = 0;
}
- // Finalize.
- assembled_data->bytes_ = data;
- assembled_data->size_ = size;
+ // Finalize data.
+ assembled_data->bytes = data;
+ assembled_data->size = size;
return err;
}
//------------------------------------------------------------------------------
-
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/mux/muxi.h b/drivers/webp/mux/muxi.h
index 2f06f3ed03..8bd5291661 100644
--- a/drivers/webp/mux/muxi.h
+++ b/drivers/webp/mux/muxi.h
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Internal header for mux library.
@@ -15,34 +17,41 @@
#include <stdlib.h>
#include "../dec/vp8i.h"
#include "../dec/vp8li.h"
-#include "../format_constants.h"
-#include "../mux.h"
+#include "webp/mux.h"
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
extern "C" {
#endif
//------------------------------------------------------------------------------
// Defines and constants.
+#define MUX_MAJ_VERSION 0
+#define MUX_MIN_VERSION 2
+#define MUX_REV_VERSION 2
+
// Chunk object.
typedef struct WebPChunk WebPChunk;
struct WebPChunk {
uint32_t tag_;
int owner_; // True if *data_ memory is owned internally.
- // VP8X, Loop, and other internally created chunks
- // like frame/tile are always owned.
+ // VP8X, ANIM, and other internally created chunks
+ // like ANMF/FRGM are always owned.
WebPData data_;
WebPChunk* next_;
};
-// MuxImage object. Store a full webp image (including frame/tile chunk, alpha
+// MuxImage object. Store a full WebP image (including ANMF/FRGM chunk, ALPH
// chunk and VP8/VP8L chunk),
typedef struct WebPMuxImage WebPMuxImage;
struct WebPMuxImage {
- WebPChunk* header_; // Corresponds to WEBP_CHUNK_FRAME/WEBP_CHUNK_TILE.
+ WebPChunk* header_; // Corresponds to WEBP_CHUNK_ANMF/WEBP_CHUNK_FRGM.
WebPChunk* alpha_; // Corresponds to WEBP_CHUNK_ALPHA.
WebPChunk* img_; // Corresponds to WEBP_CHUNK_IMAGE.
+ WebPChunk* unknown_; // Corresponds to WEBP_CHUNK_UNKNOWN.
+ int width_;
+ int height_;
+ int has_alpha_; // Through ALPH chunk or as part of VP8L.
int is_partial_; // True if only some of the chunks are filled.
WebPMuxImage* next_;
};
@@ -51,11 +60,14 @@ struct WebPMuxImage {
struct WebPMux {
WebPMuxImage* images_;
WebPChunk* iccp_;
- WebPChunk* meta_;
- WebPChunk* loop_;
+ WebPChunk* exif_;
+ WebPChunk* xmp_;
+ WebPChunk* anim_;
WebPChunk* vp8x_;
- WebPChunk* unknown_;
+ WebPChunk* unknown_;
+ int canvas_width_;
+ int canvas_height_;
};
// CHUNK_INDEX enum: used for indexing within 'kChunks' (defined below) only.
@@ -65,13 +77,14 @@ struct WebPMux {
typedef enum {
IDX_VP8X = 0,
IDX_ICCP,
- IDX_LOOP,
- IDX_FRAME,
- IDX_TILE,
+ IDX_ANIM,
+ IDX_ANMF,
+ IDX_FRGM,
IDX_ALPHA,
IDX_VP8,
IDX_VP8L,
- IDX_META,
+ IDX_EXIF,
+ IDX_XMP,
IDX_UNKNOWN,
IDX_NIL,
@@ -80,8 +93,6 @@ typedef enum {
#define NIL_TAG 0x00000000u // To signal void chunk.
-#define MKFOURCC(a, b, c, d) ((uint32_t)(a) | (b) << 8 | (c) << 16 | (d) << 24)
-
typedef struct {
uint32_t tag;
WebPChunkId id;
@@ -91,55 +102,23 @@ typedef struct {
extern const ChunkInfo kChunks[IDX_LAST_CHUNK];
//------------------------------------------------------------------------------
-// Helper functions.
-
-// Read 16, 24 or 32 bits stored in little-endian order.
-static WEBP_INLINE int GetLE16(const uint8_t* const data) {
- return (int)(data[0] << 0) | (data[1] << 8);
-}
-
-static WEBP_INLINE int GetLE24(const uint8_t* const data) {
- return GetLE16(data) | (data[2] << 16);
-}
-
-static WEBP_INLINE uint32_t GetLE32(const uint8_t* const data) {
- return (uint32_t)GetLE16(data) | (GetLE16(data + 2) << 16);
-}
-
-// Store 16, 24 or 32 bits in little-endian order.
-static WEBP_INLINE void PutLE16(uint8_t* const data, int val) {
- assert(val < (1 << 16));
- data[0] = (val >> 0);
- data[1] = (val >> 8);
-}
-
-static WEBP_INLINE void PutLE24(uint8_t* const data, int val) {
- assert(val < (1 << 24));
- PutLE16(data, val & 0xffff);
- data[2] = (val >> 16);
-}
-
-static WEBP_INLINE void PutLE32(uint8_t* const data, uint32_t val) {
- PutLE16(data, (int)(val & 0xffff));
- PutLE16(data + 2, (int)(val >> 16));
-}
-
-static WEBP_INLINE size_t SizeWithPadding(size_t chunk_size) {
- return CHUNK_HEADER_SIZE + ((chunk_size + 1) & ~1U);
-}
-
-//------------------------------------------------------------------------------
// Chunk object management.
// Initialize.
void ChunkInit(WebPChunk* const chunk);
-// Get chunk index from chunk tag. Returns IDX_NIL if not found.
+// Get chunk index from chunk tag. Returns IDX_UNKNOWN if not found.
CHUNK_INDEX ChunkGetIndexFromTag(uint32_t tag);
-// Get chunk id from chunk tag. Returns WEBP_CHUNK_NIL if not found.
+// Get chunk id from chunk tag. Returns WEBP_CHUNK_UNKNOWN if not found.
WebPChunkId ChunkGetIdFromTag(uint32_t tag);
+// Convert a fourcc string to a tag.
+uint32_t ChunkGetTagFromFourCC(const char fourcc[4]);
+
+// Get chunk index from fourcc. Returns IDX_UNKNOWN if given fourcc is unknown.
+CHUNK_INDEX ChunkGetIndexFromFourCC(const char fourcc[4]);
+
// Search for nth chunk with given 'tag' in the chunk list.
// nth = 0 means "last of the list".
WebPChunk* ChunkSearchList(WebPChunk* first, uint32_t nth, uint32_t tag);
@@ -150,7 +129,8 @@ WebPMuxError ChunkAssignData(WebPChunk* chunk, const WebPData* const data,
// Sets 'chunk' at nth position in the 'chunk_list'.
// nth = 0 has the special meaning "last of the list".
-WebPMuxError ChunkSetNth(const WebPChunk* chunk, WebPChunk** chunk_list,
+// On success ownership is transferred from 'chunk' to the 'chunk_list'.
+WebPMuxError ChunkSetNth(WebPChunk* chunk, WebPChunk** chunk_list,
uint32_t nth);
// Releases chunk and returns chunk->next_.
@@ -159,23 +139,27 @@ WebPChunk* ChunkRelease(WebPChunk* const chunk);
// Deletes given chunk & returns chunk->next_.
WebPChunk* ChunkDelete(WebPChunk* const chunk);
+// Deletes all chunks in the given chunk list.
+void ChunkListDelete(WebPChunk** const chunk_list);
+
+// Returns size of the chunk including chunk header and padding byte (if any).
+static WEBP_INLINE size_t SizeWithPadding(size_t chunk_size) {
+ return CHUNK_HEADER_SIZE + ((chunk_size + 1) & ~1U);
+}
+
// Size of a chunk including header and padding.
static WEBP_INLINE size_t ChunkDiskSize(const WebPChunk* chunk) {
- const size_t data_size = chunk->data_.size_;
+ const size_t data_size = chunk->data_.size;
assert(data_size < MAX_CHUNK_PAYLOAD);
return SizeWithPadding(data_size);
}
// Total size of a list of chunks.
-size_t ChunksListDiskSize(const WebPChunk* chunk_list);
+size_t ChunkListDiskSize(const WebPChunk* chunk_list);
// Write out the given list of chunks into 'dst'.
uint8_t* ChunkListEmit(const WebPChunk* chunk_list, uint8_t* dst);
-// Get the width & height of image stored in 'image_chunk'.
-WebPMuxError MuxGetImageWidthHeight(const WebPChunk* const image_chunk,
- int* const width, int* const height);
-
//------------------------------------------------------------------------------
// MuxImage object management.
@@ -189,82 +173,59 @@ WebPMuxImage* MuxImageRelease(WebPMuxImage* const wpi);
// 'wpi' can be NULL.
WebPMuxImage* MuxImageDelete(WebPMuxImage* const wpi);
-// Delete all images in 'wpi_list'.
-void MuxImageDeleteAll(WebPMuxImage** const wpi_list);
-
// Count number of images matching the given tag id in the 'wpi_list'.
+// If id == WEBP_CHUNK_NIL, all images will be matched.
int MuxImageCount(const WebPMuxImage* wpi_list, WebPChunkId id);
+// Update width/height/has_alpha info from chunks within wpi.
+// Also remove ALPH chunk if not needed.
+int MuxImageFinalize(WebPMuxImage* const wpi);
+
// Check if given ID corresponds to an image related chunk.
static WEBP_INLINE int IsWPI(WebPChunkId id) {
switch (id) {
- case WEBP_CHUNK_FRAME:
- case WEBP_CHUNK_TILE:
+ case WEBP_CHUNK_ANMF:
+ case WEBP_CHUNK_FRGM:
case WEBP_CHUNK_ALPHA:
case WEBP_CHUNK_IMAGE: return 1;
default: return 0;
}
}
-// Get a reference to appropriate chunk list within an image given chunk tag.
-static WEBP_INLINE WebPChunk** MuxImageGetListFromId(
- const WebPMuxImage* const wpi, WebPChunkId id) {
- assert(wpi != NULL);
- switch (id) {
- case WEBP_CHUNK_FRAME:
- case WEBP_CHUNK_TILE: return (WebPChunk**)&wpi->header_;
- case WEBP_CHUNK_ALPHA: return (WebPChunk**)&wpi->alpha_;
- case WEBP_CHUNK_IMAGE: return (WebPChunk**)&wpi->img_;
- default: return NULL;
- }
-}
-
// Pushes 'wpi' at the end of 'wpi_list'.
WebPMuxError MuxImagePush(const WebPMuxImage* wpi, WebPMuxImage** wpi_list);
-// Delete nth image in the image list with given tag id.
-WebPMuxError MuxImageDeleteNth(WebPMuxImage** wpi_list, uint32_t nth,
- WebPChunkId id);
+// Delete nth image in the image list.
+WebPMuxError MuxImageDeleteNth(WebPMuxImage** wpi_list, uint32_t nth);
-// Get nth image in the image list with given tag id.
+// Get nth image in the image list.
WebPMuxError MuxImageGetNth(const WebPMuxImage** wpi_list, uint32_t nth,
- WebPChunkId id, WebPMuxImage** wpi);
+ WebPMuxImage** wpi);
// Total size of the given image.
size_t MuxImageDiskSize(const WebPMuxImage* const wpi);
-// Total size of a list of images.
-size_t MuxImageListDiskSize(const WebPMuxImage* wpi_list);
-
// Write out the given image into 'dst'.
uint8_t* MuxImageEmit(const WebPMuxImage* const wpi, uint8_t* dst);
-// Write out the given list of images into 'dst'.
-uint8_t* MuxImageListEmit(const WebPMuxImage* wpi_list, uint8_t* dst);
-
//------------------------------------------------------------------------------
// Helper methods for mux.
-// Checks if the given image list contains at least one lossless image.
-int MuxHasLosslessImages(const WebPMuxImage* images);
+// Checks if the given image list contains at least one image with alpha.
+int MuxHasAlpha(const WebPMuxImage* images);
// Write out RIFF header into 'data', given total data size 'size'.
uint8_t* MuxEmitRiffHeader(uint8_t* const data, size_t size);
// Returns the list where chunk with given ID is to be inserted in mux.
-// Return value is NULL if this chunk should be inserted in mux->images_ list
-// or if 'id' is not known.
WebPChunk** MuxGetChunkListFromId(const WebPMux* mux, WebPChunkId id);
-// Validates that the given mux has a single image.
-WebPMuxError MuxValidateForImage(const WebPMux* const mux);
-
// Validates the given mux object.
WebPMuxError MuxValidate(const WebPMux* const mux);
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/drivers/webp/mux/muxinternal.c b/drivers/webp/mux/muxinternal.c
index 6c3c4fe60a..4babbe82fc 100644
--- a/drivers/webp/mux/muxinternal.c
+++ b/drivers/webp/mux/muxinternal.c
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Internal objects and utils for mux.
@@ -12,29 +14,33 @@
#include <assert.h>
#include "./muxi.h"
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
+#include "../utils/utils.h"
#define UNDEFINED_CHUNK_SIZE (-1)
const ChunkInfo kChunks[] = {
{ MKFOURCC('V', 'P', '8', 'X'), WEBP_CHUNK_VP8X, VP8X_CHUNK_SIZE },
{ MKFOURCC('I', 'C', 'C', 'P'), WEBP_CHUNK_ICCP, UNDEFINED_CHUNK_SIZE },
- { MKFOURCC('L', 'O', 'O', 'P'), WEBP_CHUNK_LOOP, LOOP_CHUNK_SIZE },
- { MKFOURCC('F', 'R', 'M', ' '), WEBP_CHUNK_FRAME, FRAME_CHUNK_SIZE },
- { MKFOURCC('T', 'I', 'L', 'E'), WEBP_CHUNK_TILE, TILE_CHUNK_SIZE },
+ { MKFOURCC('A', 'N', 'I', 'M'), WEBP_CHUNK_ANIM, ANIM_CHUNK_SIZE },
+ { MKFOURCC('A', 'N', 'M', 'F'), WEBP_CHUNK_ANMF, ANMF_CHUNK_SIZE },
+ { MKFOURCC('F', 'R', 'G', 'M'), WEBP_CHUNK_FRGM, FRGM_CHUNK_SIZE },
{ MKFOURCC('A', 'L', 'P', 'H'), WEBP_CHUNK_ALPHA, UNDEFINED_CHUNK_SIZE },
{ MKFOURCC('V', 'P', '8', ' '), WEBP_CHUNK_IMAGE, UNDEFINED_CHUNK_SIZE },
{ MKFOURCC('V', 'P', '8', 'L'), WEBP_CHUNK_IMAGE, UNDEFINED_CHUNK_SIZE },
- { MKFOURCC('M', 'E', 'T', 'A'), WEBP_CHUNK_META, UNDEFINED_CHUNK_SIZE },
- { MKFOURCC('U', 'N', 'K', 'N'), WEBP_CHUNK_UNKNOWN, UNDEFINED_CHUNK_SIZE },
+ { MKFOURCC('E', 'X', 'I', 'F'), WEBP_CHUNK_EXIF, UNDEFINED_CHUNK_SIZE },
+ { MKFOURCC('X', 'M', 'P', ' '), WEBP_CHUNK_XMP, UNDEFINED_CHUNK_SIZE },
+ { NIL_TAG, WEBP_CHUNK_UNKNOWN, UNDEFINED_CHUNK_SIZE },
- { NIL_TAG, WEBP_CHUNK_NIL, UNDEFINED_CHUNK_SIZE }
+ { NIL_TAG, WEBP_CHUNK_NIL, UNDEFINED_CHUNK_SIZE }
};
//------------------------------------------------------------------------------
+
+int WebPGetMuxVersion(void) {
+ return (MUX_MAJ_VERSION << 16) | (MUX_MIN_VERSION << 8) | MUX_REV_VERSION;
+}
+
+//------------------------------------------------------------------------------
// Life of a chunk object.
void ChunkInit(WebPChunk* const chunk) {
@@ -60,9 +66,9 @@ WebPChunk* ChunkRelease(WebPChunk* const chunk) {
CHUNK_INDEX ChunkGetIndexFromTag(uint32_t tag) {
int i;
for (i = 0; kChunks[i].tag != NIL_TAG; ++i) {
- if (tag == kChunks[i].tag) return i;
+ if (tag == kChunks[i].tag) return (CHUNK_INDEX)i;
}
- return IDX_NIL;
+ return IDX_UNKNOWN;
}
WebPChunkId ChunkGetIdFromTag(uint32_t tag) {
@@ -70,7 +76,16 @@ WebPChunkId ChunkGetIdFromTag(uint32_t tag) {
for (i = 0; kChunks[i].tag != NIL_TAG; ++i) {
if (tag == kChunks[i].tag) return kChunks[i].id;
}
- return WEBP_CHUNK_NIL;
+ return WEBP_CHUNK_UNKNOWN;
+}
+
+uint32_t ChunkGetTagFromFourCC(const char fourcc[4]) {
+ return MKFOURCC(fourcc[0], fourcc[1], fourcc[2], fourcc[3]);
+}
+
+CHUNK_INDEX ChunkGetIndexFromFourCC(const char fourcc[4]) {
+ const uint32_t tag = ChunkGetTagFromFourCC(fourcc);
+ return ChunkGetIndexFromTag(tag);
}
//------------------------------------------------------------------------------
@@ -78,7 +93,7 @@ WebPChunkId ChunkGetIdFromTag(uint32_t tag) {
// Returns next chunk in the chunk list with the given tag.
static WebPChunk* ChunkSearchNextInList(WebPChunk* chunk, uint32_t tag) {
- while (chunk && chunk->tag_ != tag) {
+ while (chunk != NULL && chunk->tag_ != tag) {
chunk = chunk->next_;
}
return chunk;
@@ -87,7 +102,7 @@ static WebPChunk* ChunkSearchNextInList(WebPChunk* chunk, uint32_t tag) {
WebPChunk* ChunkSearchList(WebPChunk* first, uint32_t nth, uint32_t tag) {
uint32_t iter = nth;
first = ChunkSearchNextInList(first, tag);
- if (!first) return NULL;
+ if (first == NULL) return NULL;
while (--iter != 0) {
WebPChunk* next_chunk = ChunkSearchNextInList(first->next_, tag);
@@ -99,14 +114,14 @@ WebPChunk* ChunkSearchList(WebPChunk* first, uint32_t nth, uint32_t tag) {
// Outputs a pointer to 'prev_chunk->next_',
// where 'prev_chunk' is the pointer to the chunk at position (nth - 1).
-// Returns 1 if nth chunk was found, 0 otherwise.
+// Returns true if nth chunk was found.
static int ChunkSearchListToSet(WebPChunk** chunk_list, uint32_t nth,
WebPChunk*** const location) {
uint32_t count = 0;
- assert(chunk_list);
+ assert(chunk_list != NULL);
*location = chunk_list;
- while (*chunk_list) {
+ while (*chunk_list != NULL) {
WebPChunk* const cur_chunk = *chunk_list;
++count;
if (count == nth) return 1; // Found.
@@ -124,34 +139,25 @@ static int ChunkSearchListToSet(WebPChunk** chunk_list, uint32_t nth,
WebPMuxError ChunkAssignData(WebPChunk* chunk, const WebPData* const data,
int copy_data, uint32_t tag) {
// For internally allocated chunks, always copy data & make it owner of data.
- if (tag == kChunks[IDX_VP8X].tag || tag == kChunks[IDX_LOOP].tag) {
+ if (tag == kChunks[IDX_VP8X].tag || tag == kChunks[IDX_ANIM].tag) {
copy_data = 1;
}
ChunkRelease(chunk);
if (data != NULL) {
- if (copy_data) {
- // Copy data.
- chunk->data_.bytes_ = (uint8_t*)malloc(data->size_);
- if (chunk->data_.bytes_ == NULL) return WEBP_MUX_MEMORY_ERROR;
- memcpy((uint8_t*)chunk->data_.bytes_, data->bytes_, data->size_);
- chunk->data_.size_ = data->size_;
-
- // Chunk is owner of data.
- chunk->owner_ = 1;
- } else {
- // Don't copy data.
+ if (copy_data) { // Copy data.
+ if (!WebPDataCopy(data, &chunk->data_)) return WEBP_MUX_MEMORY_ERROR;
+ chunk->owner_ = 1; // Chunk is owner of data.
+ } else { // Don't copy data.
chunk->data_ = *data;
}
}
-
chunk->tag_ = tag;
-
return WEBP_MUX_OK;
}
-WebPMuxError ChunkSetNth(const WebPChunk* chunk, WebPChunk** chunk_list,
+WebPMuxError ChunkSetNth(WebPChunk* chunk, WebPChunk** chunk_list,
uint32_t nth) {
WebPChunk* new_chunk;
@@ -159,9 +165,10 @@ WebPMuxError ChunkSetNth(const WebPChunk* chunk, WebPChunk** chunk_list,
return WEBP_MUX_NOT_FOUND;
}
- new_chunk = (WebPChunk*)malloc(sizeof(*new_chunk));
+ new_chunk = (WebPChunk*)WebPSafeMalloc(1ULL, sizeof(*new_chunk));
if (new_chunk == NULL) return WEBP_MUX_MEMORY_ERROR;
*new_chunk = *chunk;
+ chunk->owner_ = 0;
new_chunk->next_ = *chunk_list;
*chunk_list = new_chunk;
return WEBP_MUX_OK;
@@ -172,70 +179,47 @@ WebPMuxError ChunkSetNth(const WebPChunk* chunk, WebPChunk** chunk_list,
WebPChunk* ChunkDelete(WebPChunk* const chunk) {
WebPChunk* const next = ChunkRelease(chunk);
- free(chunk);
+ WebPSafeFree(chunk);
return next;
}
-//------------------------------------------------------------------------------
-// Chunk serialization methods.
-
-size_t ChunksListDiskSize(const WebPChunk* chunk_list) {
- size_t size = 0;
- while (chunk_list) {
- size += ChunkDiskSize(chunk_list);
- chunk_list = chunk_list->next_;
+void ChunkListDelete(WebPChunk** const chunk_list) {
+ while (*chunk_list != NULL) {
+ *chunk_list = ChunkDelete(*chunk_list);
}
- return size;
}
+//------------------------------------------------------------------------------
+// Chunk serialization methods.
+
static uint8_t* ChunkEmit(const WebPChunk* const chunk, uint8_t* dst) {
- const size_t chunk_size = chunk->data_.size_;
+ const size_t chunk_size = chunk->data_.size;
assert(chunk);
assert(chunk->tag_ != NIL_TAG);
PutLE32(dst + 0, chunk->tag_);
PutLE32(dst + TAG_SIZE, (uint32_t)chunk_size);
assert(chunk_size == (uint32_t)chunk_size);
- memcpy(dst + CHUNK_HEADER_SIZE, chunk->data_.bytes_, chunk_size);
+ memcpy(dst + CHUNK_HEADER_SIZE, chunk->data_.bytes, chunk_size);
if (chunk_size & 1)
dst[CHUNK_HEADER_SIZE + chunk_size] = 0; // Add padding.
return dst + ChunkDiskSize(chunk);
}
uint8_t* ChunkListEmit(const WebPChunk* chunk_list, uint8_t* dst) {
- while (chunk_list) {
+ while (chunk_list != NULL) {
dst = ChunkEmit(chunk_list, dst);
chunk_list = chunk_list->next_;
}
return dst;
}
-//------------------------------------------------------------------------------
-// Manipulation of a WebPData object.
-
-void WebPDataInit(WebPData* webp_data) {
- if (webp_data != NULL) {
- memset(webp_data, 0, sizeof(*webp_data));
- }
-}
-
-void WebPDataClear(WebPData* webp_data) {
- if (webp_data != NULL) {
- free((void*)webp_data->bytes_);
- WebPDataInit(webp_data);
- }
-}
-
-int WebPDataCopy(const WebPData* src, WebPData* dst) {
- if (src == NULL || dst == NULL) return 0;
-
- WebPDataInit(dst);
- if (src->bytes_ != NULL && src->size_ != 0) {
- dst->bytes_ = (uint8_t*)malloc(src->size_);
- if (dst->bytes_ == NULL) return 0;
- memcpy((void*)dst->bytes_, src->bytes_, src->size_);
- dst->size_ = src->size_;
+size_t ChunkListDiskSize(const WebPChunk* chunk_list) {
+ size_t size = 0;
+ while (chunk_list != NULL) {
+ size += ChunkDiskSize(chunk_list);
+ chunk_list = chunk_list->next_;
}
- return 1;
+ return size;
}
//------------------------------------------------------------------------------
@@ -252,6 +236,7 @@ WebPMuxImage* MuxImageRelease(WebPMuxImage* const wpi) {
ChunkDelete(wpi->header_);
ChunkDelete(wpi->alpha_);
ChunkDelete(wpi->img_);
+ ChunkListDelete(&wpi->unknown_);
next = wpi->next_;
MuxImageInit(wpi);
@@ -261,14 +246,31 @@ WebPMuxImage* MuxImageRelease(WebPMuxImage* const wpi) {
//------------------------------------------------------------------------------
// MuxImage search methods.
+// Get a reference to appropriate chunk list within an image given chunk tag.
+static WebPChunk** GetChunkListFromId(const WebPMuxImage* const wpi,
+ WebPChunkId id) {
+ assert(wpi != NULL);
+ switch (id) {
+ case WEBP_CHUNK_ANMF:
+ case WEBP_CHUNK_FRGM: return (WebPChunk**)&wpi->header_;
+ case WEBP_CHUNK_ALPHA: return (WebPChunk**)&wpi->alpha_;
+ case WEBP_CHUNK_IMAGE: return (WebPChunk**)&wpi->img_;
+ default: return NULL;
+ }
+}
+
int MuxImageCount(const WebPMuxImage* wpi_list, WebPChunkId id) {
int count = 0;
const WebPMuxImage* current;
for (current = wpi_list; current != NULL; current = current->next_) {
- const WebPChunk* const wpi_chunk = *MuxImageGetListFromId(current, id);
- if (wpi_chunk != NULL) {
- const WebPChunkId wpi_chunk_id = ChunkGetIdFromTag(wpi_chunk->tag_);
- if (wpi_chunk_id == id) ++count;
+ if (id == WEBP_CHUNK_NIL) {
+ ++count; // Special case: count all images.
+ } else {
+ const WebPChunk* const wpi_chunk = *GetChunkListFromId(current, id);
+ if (wpi_chunk != NULL) {
+ const WebPChunkId wpi_chunk_id = ChunkGetIdFromTag(wpi_chunk->tag_);
+ if (wpi_chunk_id == id) ++count; // Count images with a matching 'id'.
+ }
}
}
return count;
@@ -276,34 +278,22 @@ int MuxImageCount(const WebPMuxImage* wpi_list, WebPChunkId id) {
// Outputs a pointer to 'prev_wpi->next_',
// where 'prev_wpi' is the pointer to the image at position (nth - 1).
-// Returns 1 if nth image with given id was found, 0 otherwise.
+// Returns true if nth image was found.
static int SearchImageToGetOrDelete(WebPMuxImage** wpi_list, uint32_t nth,
- WebPChunkId id,
WebPMuxImage*** const location) {
uint32_t count = 0;
assert(wpi_list);
*location = wpi_list;
- // Search makes sense only for the following.
- assert(id == WEBP_CHUNK_FRAME || id == WEBP_CHUNK_TILE ||
- id == WEBP_CHUNK_IMAGE);
- assert(id != WEBP_CHUNK_IMAGE || nth == 1);
-
if (nth == 0) {
- nth = MuxImageCount(*wpi_list, id);
+ nth = MuxImageCount(*wpi_list, WEBP_CHUNK_NIL);
if (nth == 0) return 0; // Not found.
}
- while (*wpi_list) {
+ while (*wpi_list != NULL) {
WebPMuxImage* const cur_wpi = *wpi_list;
- const WebPChunk* const wpi_chunk = *MuxImageGetListFromId(cur_wpi, id);
- if (wpi_chunk != NULL) {
- const WebPChunkId wpi_chunk_id = ChunkGetIdFromTag(wpi_chunk->tag_);
- if (wpi_chunk_id == id) {
- ++count;
- if (count == nth) return 1; // Found.
- }
- }
+ ++count;
+ if (count == nth) return 1; // Found.
wpi_list = &cur_wpi->next_;
*location = wpi_list;
}
@@ -322,7 +312,7 @@ WebPMuxError MuxImagePush(const WebPMuxImage* wpi, WebPMuxImage** wpi_list) {
wpi_list = &cur_wpi->next_;
}
- new_wpi = (WebPMuxImage*)malloc(sizeof(*new_wpi));
+ new_wpi = (WebPMuxImage*)WebPSafeMalloc(1ULL, sizeof(*new_wpi));
if (new_wpi == NULL) return WEBP_MUX_MEMORY_ERROR;
*new_wpi = *wpi;
new_wpi->next_ = NULL;
@@ -341,20 +331,13 @@ WebPMuxError MuxImagePush(const WebPMuxImage* wpi, WebPMuxImage** wpi_list) {
WebPMuxImage* MuxImageDelete(WebPMuxImage* const wpi) {
// Delete the components of wpi. If wpi is NULL this is a noop.
WebPMuxImage* const next = MuxImageRelease(wpi);
- free(wpi);
+ WebPSafeFree(wpi);
return next;
}
-void MuxImageDeleteAll(WebPMuxImage** const wpi_list) {
- while (*wpi_list) {
- *wpi_list = MuxImageDelete(*wpi_list);
- }
-}
-
-WebPMuxError MuxImageDeleteNth(WebPMuxImage** wpi_list, uint32_t nth,
- WebPChunkId id) {
+WebPMuxError MuxImageDeleteNth(WebPMuxImage** wpi_list, uint32_t nth) {
assert(wpi_list);
- if (!SearchImageToGetOrDelete(wpi_list, nth, id, &wpi_list)) {
+ if (!SearchImageToGetOrDelete(wpi_list, nth, &wpi_list)) {
return WEBP_MUX_NOT_FOUND;
}
*wpi_list = MuxImageDelete(*wpi_list);
@@ -365,10 +348,10 @@ WebPMuxError MuxImageDeleteNth(WebPMuxImage** wpi_list, uint32_t nth,
// MuxImage reader methods.
WebPMuxError MuxImageGetNth(const WebPMuxImage** wpi_list, uint32_t nth,
- WebPChunkId id, WebPMuxImage** wpi) {
+ WebPMuxImage** wpi) {
assert(wpi_list);
assert(wpi);
- if (!SearchImageToGetOrDelete((WebPMuxImage**)wpi_list, nth, id,
+ if (!SearchImageToGetOrDelete((WebPMuxImage**)wpi_list, nth,
(WebPMuxImage***)&wpi_list)) {
return WEBP_MUX_NOT_FOUND;
}
@@ -385,47 +368,48 @@ size_t MuxImageDiskSize(const WebPMuxImage* const wpi) {
if (wpi->header_ != NULL) size += ChunkDiskSize(wpi->header_);
if (wpi->alpha_ != NULL) size += ChunkDiskSize(wpi->alpha_);
if (wpi->img_ != NULL) size += ChunkDiskSize(wpi->img_);
+ if (wpi->unknown_ != NULL) size += ChunkListDiskSize(wpi->unknown_);
return size;
}
-size_t MuxImageListDiskSize(const WebPMuxImage* wpi_list) {
- size_t size = 0;
- while (wpi_list) {
- size += MuxImageDiskSize(wpi_list);
- wpi_list = wpi_list->next_;
+// Special case as ANMF/FRGM chunk encapsulates other image chunks.
+static uint8_t* ChunkEmitSpecial(const WebPChunk* const header,
+ size_t total_size, uint8_t* dst) {
+ const size_t header_size = header->data_.size;
+ const size_t offset_to_next = total_size - CHUNK_HEADER_SIZE;
+ assert(header->tag_ == kChunks[IDX_ANMF].tag ||
+ header->tag_ == kChunks[IDX_FRGM].tag);
+ PutLE32(dst + 0, header->tag_);
+ PutLE32(dst + TAG_SIZE, (uint32_t)offset_to_next);
+ assert(header_size == (uint32_t)header_size);
+ memcpy(dst + CHUNK_HEADER_SIZE, header->data_.bytes, header_size);
+ if (header_size & 1) {
+ dst[CHUNK_HEADER_SIZE + header_size] = 0; // Add padding.
}
- return size;
+ return dst + ChunkDiskSize(header);
}
uint8_t* MuxImageEmit(const WebPMuxImage* const wpi, uint8_t* dst) {
// Ordering of chunks to be emitted is strictly as follows:
- // 1. Frame/Tile chunk (if present).
- // 2. Alpha chunk (if present).
+ // 1. ANMF/FRGM chunk (if present).
+ // 2. ALPH chunk (if present).
// 3. VP8/VP8L chunk.
assert(wpi);
- if (wpi->header_ != NULL) dst = ChunkEmit(wpi->header_, dst);
+ if (wpi->header_ != NULL) {
+ dst = ChunkEmitSpecial(wpi->header_, MuxImageDiskSize(wpi), dst);
+ }
if (wpi->alpha_ != NULL) dst = ChunkEmit(wpi->alpha_, dst);
if (wpi->img_ != NULL) dst = ChunkEmit(wpi->img_, dst);
- return dst;
-}
-
-uint8_t* MuxImageListEmit(const WebPMuxImage* wpi_list, uint8_t* dst) {
- while (wpi_list) {
- dst = MuxImageEmit(wpi_list, dst);
- wpi_list = wpi_list->next_;
- }
+ if (wpi->unknown_ != NULL) dst = ChunkListEmit(wpi->unknown_, dst);
return dst;
}
//------------------------------------------------------------------------------
// Helper methods for mux.
-int MuxHasLosslessImages(const WebPMuxImage* images) {
+int MuxHasAlpha(const WebPMuxImage* images) {
while (images != NULL) {
- assert(images->img_ != NULL);
- if (images->img_->tag_ == kChunks[IDX_VP8L].tag) {
- return 1;
- }
+ if (images->has_alpha_) return 1;
images = images->next_;
}
return 0;
@@ -441,30 +425,13 @@ uint8_t* MuxEmitRiffHeader(uint8_t* const data, size_t size) {
WebPChunk** MuxGetChunkListFromId(const WebPMux* mux, WebPChunkId id) {
assert(mux != NULL);
- switch(id) {
+ switch (id) {
case WEBP_CHUNK_VP8X: return (WebPChunk**)&mux->vp8x_;
case WEBP_CHUNK_ICCP: return (WebPChunk**)&mux->iccp_;
- case WEBP_CHUNK_LOOP: return (WebPChunk**)&mux->loop_;
- case WEBP_CHUNK_META: return (WebPChunk**)&mux->meta_;
- case WEBP_CHUNK_UNKNOWN: return (WebPChunk**)&mux->unknown_;
- default: return NULL;
- }
-}
-
-WebPMuxError MuxValidateForImage(const WebPMux* const mux) {
- const int num_images = MuxImageCount(mux->images_, WEBP_CHUNK_IMAGE);
- const int num_frames = MuxImageCount(mux->images_, WEBP_CHUNK_FRAME);
- const int num_tiles = MuxImageCount(mux->images_, WEBP_CHUNK_TILE);
-
- if (num_images == 0) {
- // No images in mux.
- return WEBP_MUX_NOT_FOUND;
- } else if (num_images == 1 && num_frames == 0 && num_tiles == 0) {
- // Valid case (single image).
- return WEBP_MUX_OK;
- } else {
- // Frame/Tile case OR an invalid mux.
- return WEBP_MUX_INVALID_ARGUMENT;
+ case WEBP_CHUNK_ANIM: return (WebPChunk**)&mux->anim_;
+ case WEBP_CHUNK_EXIF: return (WebPChunk**)&mux->exif_;
+ case WEBP_CHUNK_XMP: return (WebPChunk**)&mux->xmp_;
+ default: return (WebPChunk**)&mux->unknown_;
}
}
@@ -480,7 +447,7 @@ static int IsNotCompatible(int feature, int num_items) {
// On success returns WEBP_MUX_OK and stores the chunk count in *num.
static WebPMuxError ValidateChunk(const WebPMux* const mux, CHUNK_INDEX idx,
WebPFeatureFlags feature,
- WebPFeatureFlags vp8x_flags,
+ uint32_t vp8x_flags,
int max, int* num) {
const WebPMuxError err =
WebPMuxNumChunks(mux, kChunks[idx].id, num);
@@ -494,10 +461,11 @@ static WebPMuxError ValidateChunk(const WebPMux* const mux, CHUNK_INDEX idx,
WebPMuxError MuxValidate(const WebPMux* const mux) {
int num_iccp;
- int num_meta;
- int num_loop_chunks;
+ int num_exif;
+ int num_xmp;
+ int num_anim;
int num_frames;
- int num_tiles;
+ int num_fragments;
int num_vp8x;
int num_images;
int num_alpha;
@@ -517,29 +485,33 @@ WebPMuxError MuxValidate(const WebPMux* const mux) {
err = ValidateChunk(mux, IDX_ICCP, ICCP_FLAG, flags, 1, &num_iccp);
if (err != WEBP_MUX_OK) return err;
+ // At most one EXIF metadata.
+ err = ValidateChunk(mux, IDX_EXIF, EXIF_FLAG, flags, 1, &num_exif);
+ if (err != WEBP_MUX_OK) return err;
+
// At most one XMP metadata.
- err = ValidateChunk(mux, IDX_META, META_FLAG, flags, 1, &num_meta);
+ err = ValidateChunk(mux, IDX_XMP, XMP_FLAG, flags, 1, &num_xmp);
if (err != WEBP_MUX_OK) return err;
- // Animation: ANIMATION_FLAG, loop chunk and frame chunk(s) are consistent.
- // At most one loop chunk.
- err = ValidateChunk(mux, IDX_LOOP, NO_FLAG, flags, 1, &num_loop_chunks);
+ // Animation: ANIMATION_FLAG, ANIM chunk and ANMF chunk(s) are consistent.
+ // At most one ANIM chunk.
+ err = ValidateChunk(mux, IDX_ANIM, NO_FLAG, flags, 1, &num_anim);
if (err != WEBP_MUX_OK) return err;
- err = ValidateChunk(mux, IDX_FRAME, NO_FLAG, flags, -1, &num_frames);
+ err = ValidateChunk(mux, IDX_ANMF, NO_FLAG, flags, -1, &num_frames);
if (err != WEBP_MUX_OK) return err;
{
const int has_animation = !!(flags & ANIMATION_FLAG);
- if (has_animation && (num_loop_chunks == 0 || num_frames == 0)) {
+ if (has_animation && (num_anim == 0 || num_frames == 0)) {
return WEBP_MUX_INVALID_ARGUMENT;
}
- if (!has_animation && (num_loop_chunks == 1 || num_frames > 0)) {
+ if (!has_animation && (num_anim == 1 || num_frames > 0)) {
return WEBP_MUX_INVALID_ARGUMENT;
}
}
- // Tiling: TILE_FLAG and tile chunk(s) are consistent.
- err = ValidateChunk(mux, IDX_TILE, TILE_FLAG, flags, -1, &num_tiles);
+ // Fragmentation: FRAGMENTS_FLAG and FRGM chunk(s) are consistent.
+ err = ValidateChunk(mux, IDX_FRGM, FRAGMENTS_FLAG, flags, -1, &num_fragments);
if (err != WEBP_MUX_OK) return err;
// Verify either VP8X chunk is present OR there is only one elem in
@@ -551,16 +523,22 @@ WebPMuxError MuxValidate(const WebPMux* const mux) {
if (num_vp8x == 0 && num_images != 1) return WEBP_MUX_INVALID_ARGUMENT;
// ALPHA_FLAG & alpha chunk(s) are consistent.
- if (num_vp8x > 0 && MuxHasLosslessImages(mux->images_)) {
- // Special case: we have a VP8X chunk as well as some lossless images.
- if (!(flags & ALPHA_FLAG)) return WEBP_MUX_INVALID_ARGUMENT;
- } else {
- err = ValidateChunk(mux, IDX_ALPHA, ALPHA_FLAG, flags, -1, &num_alpha);
- if (err != WEBP_MUX_OK) return err;
+ if (MuxHasAlpha(mux->images_)) {
+ if (num_vp8x > 0) {
+ // VP8X chunk is present, so it should contain ALPHA_FLAG.
+ if (!(flags & ALPHA_FLAG)) return WEBP_MUX_INVALID_ARGUMENT;
+ } else {
+ // VP8X chunk is not present, so ALPH chunks should NOT be present either.
+ err = WebPMuxNumChunks(mux, WEBP_CHUNK_ALPHA, &num_alpha);
+ if (err != WEBP_MUX_OK) return err;
+ if (num_alpha > 0) return WEBP_MUX_INVALID_ARGUMENT;
+ }
+ } else { // Mux doesn't need alpha. So, ALPHA_FLAG should NOT be present.
+ if (flags & ALPHA_FLAG) return WEBP_MUX_INVALID_ARGUMENT;
}
- // num_tiles & num_images are consistent.
- if (num_tiles > 0 && num_images != num_tiles) {
+ // num_fragments & num_images are consistent.
+ if (num_fragments > 0 && num_images != num_fragments) {
return WEBP_MUX_INVALID_ARGUMENT;
}
@@ -571,6 +549,3 @@ WebPMuxError MuxValidate(const WebPMux* const mux) {
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/mux/muxread.c b/drivers/webp/mux/muxread.c
index 21c3cfbaeb..8957a1e46e 100644
--- a/drivers/webp/mux/muxread.c
+++ b/drivers/webp/mux/muxread.c
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Read APIs for mux.
@@ -12,10 +14,7 @@
#include <assert.h>
#include "./muxi.h"
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
+#include "../utils/utils.h"
//------------------------------------------------------------------------------
// Helper method(s).
@@ -41,8 +40,9 @@ static WebPMuxError MuxGet(const WebPMux* const mux, CHUNK_INDEX idx,
SWITCH_ID_LIST(IDX_VP8X, mux->vp8x_);
SWITCH_ID_LIST(IDX_ICCP, mux->iccp_);
- SWITCH_ID_LIST(IDX_LOOP, mux->loop_);
- SWITCH_ID_LIST(IDX_META, mux->meta_);
+ SWITCH_ID_LIST(IDX_ANIM, mux->anim_);
+ SWITCH_ID_LIST(IDX_EXIF, mux->exif_);
+ SWITCH_ID_LIST(IDX_XMP, mux->xmp_);
SWITCH_ID_LIST(IDX_UNKNOWN, mux->unknown_);
return WEBP_MUX_NOT_FOUND;
}
@@ -50,15 +50,14 @@ static WebPMuxError MuxGet(const WebPMux* const mux, CHUNK_INDEX idx,
// Fill the chunk with the given data (includes chunk header bytes), after some
// verifications.
-static WebPMuxError ChunkVerifyAndAssignData(WebPChunk* chunk,
- const uint8_t* data,
- size_t data_size, size_t riff_size,
- int copy_data) {
+static WebPMuxError ChunkVerifyAndAssign(WebPChunk* chunk,
+ const uint8_t* data, size_t data_size,
+ size_t riff_size, int copy_data) {
uint32_t chunk_size;
WebPData chunk_data;
// Sanity checks.
- if (data_size < TAG_SIZE) return WEBP_MUX_NOT_ENOUGH_DATA;
+ if (data_size < CHUNK_HEADER_SIZE) return WEBP_MUX_NOT_ENOUGH_DATA;
chunk_size = GetLE32(data + TAG_SIZE);
{
@@ -68,11 +67,103 @@ static WebPMuxError ChunkVerifyAndAssignData(WebPChunk* chunk,
}
// Data assignment.
- chunk_data.bytes_ = data + CHUNK_HEADER_SIZE;
- chunk_data.size_ = chunk_size;
+ chunk_data.bytes = data + CHUNK_HEADER_SIZE;
+ chunk_data.size = chunk_size;
return ChunkAssignData(chunk, &chunk_data, copy_data, GetLE32(data + 0));
}
+int MuxImageFinalize(WebPMuxImage* const wpi) {
+ const WebPChunk* const img = wpi->img_;
+ const WebPData* const image = &img->data_;
+ const int is_lossless = (img->tag_ == kChunks[IDX_VP8L].tag);
+ int w, h;
+ int vp8l_has_alpha = 0;
+ const int ok = is_lossless ?
+ VP8LGetInfo(image->bytes, image->size, &w, &h, &vp8l_has_alpha) :
+ VP8GetInfo(image->bytes, image->size, image->size, &w, &h);
+ assert(img != NULL);
+ if (ok) {
+ // Ignore ALPH chunk accompanying VP8L.
+ if (is_lossless && (wpi->alpha_ != NULL)) {
+ ChunkDelete(wpi->alpha_);
+ wpi->alpha_ = NULL;
+ }
+ wpi->width_ = w;
+ wpi->height_ = h;
+ wpi->has_alpha_ = vp8l_has_alpha || (wpi->alpha_ != NULL);
+ }
+ return ok;
+}
+
+static int MuxImageParse(const WebPChunk* const chunk, int copy_data,
+ WebPMuxImage* const wpi) {
+ const uint8_t* bytes = chunk->data_.bytes;
+ size_t size = chunk->data_.size;
+ const uint8_t* const last = bytes + size;
+ WebPChunk subchunk;
+ size_t subchunk_size;
+ ChunkInit(&subchunk);
+
+ assert(chunk->tag_ == kChunks[IDX_ANMF].tag ||
+ chunk->tag_ == kChunks[IDX_FRGM].tag);
+ assert(!wpi->is_partial_);
+
+ // ANMF/FRGM.
+ {
+ const size_t hdr_size = (chunk->tag_ == kChunks[IDX_ANMF].tag) ?
+ ANMF_CHUNK_SIZE : FRGM_CHUNK_SIZE;
+ const WebPData temp = { bytes, hdr_size };
+ // Each of ANMF and FRGM chunk contain a header at the beginning. So, its
+ // size should at least be 'hdr_size'.
+ if (size < hdr_size) goto Fail;
+ ChunkAssignData(&subchunk, &temp, copy_data, chunk->tag_);
+ }
+ ChunkSetNth(&subchunk, &wpi->header_, 1);
+ wpi->is_partial_ = 1; // Waiting for ALPH and/or VP8/VP8L chunks.
+
+ // Rest of the chunks.
+ subchunk_size = ChunkDiskSize(&subchunk) - CHUNK_HEADER_SIZE;
+ bytes += subchunk_size;
+ size -= subchunk_size;
+
+ while (bytes != last) {
+ ChunkInit(&subchunk);
+ if (ChunkVerifyAndAssign(&subchunk, bytes, size, size,
+ copy_data) != WEBP_MUX_OK) {
+ goto Fail;
+ }
+ switch (ChunkGetIdFromTag(subchunk.tag_)) {
+ case WEBP_CHUNK_ALPHA:
+ if (wpi->alpha_ != NULL) goto Fail; // Consecutive ALPH chunks.
+ if (ChunkSetNth(&subchunk, &wpi->alpha_, 1) != WEBP_MUX_OK) goto Fail;
+ wpi->is_partial_ = 1; // Waiting for a VP8 chunk.
+ break;
+ case WEBP_CHUNK_IMAGE:
+ if (ChunkSetNth(&subchunk, &wpi->img_, 1) != WEBP_MUX_OK) goto Fail;
+ if (!MuxImageFinalize(wpi)) goto Fail;
+ wpi->is_partial_ = 0; // wpi is completely filled.
+ break;
+ case WEBP_CHUNK_UNKNOWN:
+ if (wpi->is_partial_) goto Fail; // Encountered an unknown chunk
+ // before some image chunks.
+ if (ChunkSetNth(&subchunk, &wpi->unknown_, 0) != WEBP_MUX_OK) goto Fail;
+ break;
+ default:
+ goto Fail;
+ break;
+ }
+ subchunk_size = ChunkDiskSize(&subchunk);
+ bytes += subchunk_size;
+ size -= subchunk_size;
+ }
+ if (wpi->is_partial_) goto Fail;
+ return 1;
+
+ Fail:
+ ChunkRelease(&subchunk);
+ return 0;
+}
+
//------------------------------------------------------------------------------
// Create a mux object from WebP-RIFF data.
@@ -94,8 +185,8 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
}
if (bitstream == NULL) return NULL;
- data = bitstream->bytes_;
- size = bitstream->size_;
+ data = bitstream->bytes;
+ size = bitstream->size;
if (data == NULL) return NULL;
if (size < RIFF_HEADER_SIZE) return NULL;
@@ -129,48 +220,55 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
data += RIFF_HEADER_SIZE;
size -= RIFF_HEADER_SIZE;
- wpi = (WebPMuxImage*)malloc(sizeof(*wpi));
+ wpi = (WebPMuxImage*)WebPSafeMalloc(1ULL, sizeof(*wpi));
if (wpi == NULL) goto Err;
MuxImageInit(wpi);
// Loop over chunks.
while (data != end) {
+ size_t data_size;
WebPChunkId id;
- WebPMuxError err;
-
- err = ChunkVerifyAndAssignData(&chunk, data, size, riff_size, copy_data);
- if (err != WEBP_MUX_OK) goto Err;
-
+ WebPChunk** chunk_list;
+ if (ChunkVerifyAndAssign(&chunk, data, size, riff_size,
+ copy_data) != WEBP_MUX_OK) {
+ goto Err;
+ }
+ data_size = ChunkDiskSize(&chunk);
id = ChunkGetIdFromTag(chunk.tag_);
-
- if (IsWPI(id)) { // An image chunk (frame/tile/alpha/vp8).
- WebPChunk** wpi_chunk_ptr =
- MuxImageGetListFromId(wpi, id); // Image chunk to set.
- assert(wpi_chunk_ptr != NULL);
- if (*wpi_chunk_ptr != NULL) goto Err; // Consecutive alpha chunks or
- // consecutive frame/tile chunks.
- if (ChunkSetNth(&chunk, wpi_chunk_ptr, 1) != WEBP_MUX_OK) goto Err;
- if (id == WEBP_CHUNK_IMAGE) {
+ switch (id) {
+ case WEBP_CHUNK_ALPHA:
+ if (wpi->alpha_ != NULL) goto Err; // Consecutive ALPH chunks.
+ if (ChunkSetNth(&chunk, &wpi->alpha_, 1) != WEBP_MUX_OK) goto Err;
+ wpi->is_partial_ = 1; // Waiting for a VP8 chunk.
+ break;
+ case WEBP_CHUNK_IMAGE:
+ if (ChunkSetNth(&chunk, &wpi->img_, 1) != WEBP_MUX_OK) goto Err;
+ if (!MuxImageFinalize(wpi)) goto Err;
wpi->is_partial_ = 0; // wpi is completely filled.
+ PushImage:
// Add this to mux->images_ list.
if (MuxImagePush(wpi, &mux->images_) != WEBP_MUX_OK) goto Err;
MuxImageInit(wpi); // Reset for reading next image.
- } else {
- wpi->is_partial_ = 1; // wpi is only partially filled.
- }
- } else { // A non-image chunk.
- WebPChunk** chunk_list;
- if (wpi->is_partial_) goto Err; // Encountered a non-image chunk before
- // getting all chunks of an image.
- chunk_list = MuxGetChunkListFromId(mux, id); // List to add this chunk.
- if (chunk_list == NULL) chunk_list = &mux->unknown_;
- if (ChunkSetNth(&chunk, chunk_list, 0) != WEBP_MUX_OK) goto Err;
- }
- {
- const size_t data_size = ChunkDiskSize(&chunk);
- data += data_size;
- size -= data_size;
+ break;
+ case WEBP_CHUNK_ANMF:
+ if (wpi->is_partial_) goto Err; // Previous wpi is still incomplete.
+ if (!MuxImageParse(&chunk, copy_data, wpi)) goto Err;
+ ChunkRelease(&chunk);
+ goto PushImage;
+ break;
+ default: // A non-image chunk.
+ if (wpi->is_partial_) goto Err; // Encountered a non-image chunk before
+ // getting all chunks of an image.
+ chunk_list = MuxGetChunkListFromId(mux, id); // List to add this chunk.
+ if (ChunkSetNth(&chunk, chunk_list, 0) != WEBP_MUX_OK) goto Err;
+ if (id == WEBP_CHUNK_VP8X) { // grab global specs
+ mux->canvas_width_ = GetLE24(data + 12) + 1;
+ mux->canvas_height_ = GetLE24(data + 15) + 1;
+ }
+ break;
}
+ data += data_size;
+ size -= data_size;
ChunkInit(&chunk);
}
@@ -190,31 +288,74 @@ WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
//------------------------------------------------------------------------------
// Get API(s).
-WebPMuxError WebPMuxGetFeatures(const WebPMux* mux, uint32_t* flags) {
- WebPData data;
- WebPMuxError err;
+// Validates that the given mux has a single image.
+static WebPMuxError ValidateForSingleImage(const WebPMux* const mux) {
+ const int num_images = MuxImageCount(mux->images_, WEBP_CHUNK_IMAGE);
+ const int num_frames = MuxImageCount(mux->images_, WEBP_CHUNK_ANMF);
+ const int num_fragments = MuxImageCount(mux->images_, WEBP_CHUNK_FRGM);
+
+ if (num_images == 0) {
+ // No images in mux.
+ return WEBP_MUX_NOT_FOUND;
+ } else if (num_images == 1 && num_frames == 0 && num_fragments == 0) {
+ // Valid case (single image).
+ return WEBP_MUX_OK;
+ } else {
+ // Frame/Fragment case OR an invalid mux.
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+}
- if (mux == NULL || flags == NULL) return WEBP_MUX_INVALID_ARGUMENT;
- *flags = 0;
+// Get the canvas width, height and flags after validating that VP8X/VP8/VP8L
+// chunk and canvas size are valid.
+static WebPMuxError MuxGetCanvasInfo(const WebPMux* const mux,
+ int* width, int* height, uint32_t* flags) {
+ int w, h;
+ uint32_t f = 0;
+ WebPData data;
+ assert(mux != NULL);
// Check if VP8X chunk is present.
- err = MuxGet(mux, IDX_VP8X, 1, &data);
- if (err == WEBP_MUX_NOT_FOUND) {
- // Check if VP8/VP8L chunk is present.
- err = WebPMuxGetImage(mux, &data);
- WebPDataClear(&data);
- return err;
- } else if (err != WEBP_MUX_OK) {
- return err;
+ if (MuxGet(mux, IDX_VP8X, 1, &data) == WEBP_MUX_OK) {
+ if (data.size < VP8X_CHUNK_SIZE) return WEBP_MUX_BAD_DATA;
+ f = GetLE32(data.bytes + 0);
+ w = GetLE24(data.bytes + 4) + 1;
+ h = GetLE24(data.bytes + 7) + 1;
+ } else {
+ const WebPMuxImage* const wpi = mux->images_;
+ // Grab user-forced canvas size as default.
+ w = mux->canvas_width_;
+ h = mux->canvas_height_;
+ if (w == 0 && h == 0 && ValidateForSingleImage(mux) == WEBP_MUX_OK) {
+ // single image and not forced canvas size => use dimension of first frame
+ assert(wpi != NULL);
+ w = wpi->width_;
+ h = wpi->height_;
+ }
+ if (wpi != NULL) {
+ if (wpi->has_alpha_) f |= ALPHA_FLAG;
+ }
}
+ if (w * (uint64_t)h >= MAX_IMAGE_AREA) return WEBP_MUX_BAD_DATA;
- if (data.size_ < CHUNK_SIZE_BYTES) return WEBP_MUX_BAD_DATA;
-
- // All OK. Fill up flags.
- *flags = GetLE32(data.bytes_);
+ if (width != NULL) *width = w;
+ if (height != NULL) *height = h;
+ if (flags != NULL) *flags = f;
return WEBP_MUX_OK;
}
+WebPMuxError WebPMuxGetCanvasSize(const WebPMux* mux, int* width, int* height) {
+ if (mux == NULL || width == NULL || height == NULL) {
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+ return MuxGetCanvasInfo(mux, width, height, NULL);
+}
+
+WebPMuxError WebPMuxGetFeatures(const WebPMux* mux, uint32_t* flags) {
+ if (mux == NULL || flags == NULL) return WEBP_MUX_INVALID_ARGUMENT;
+ return MuxGetCanvasInfo(mux, NULL, NULL, flags);
+}
+
static uint8_t* EmitVP8XChunk(uint8_t* const dst, int width,
int height, uint32_t flags) {
const size_t vp8x_size = CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE;
@@ -230,7 +371,7 @@ static uint8_t* EmitVP8XChunk(uint8_t* const dst, int width,
}
// Assemble a single image WebP bitstream from 'wpi'.
-static WebPMuxError SynthesizeBitstream(WebPMuxImage* const wpi,
+static WebPMuxError SynthesizeBitstream(const WebPMuxImage* const wpi,
WebPData* const bitstream) {
uint8_t* dst;
@@ -238,25 +379,17 @@ static WebPMuxError SynthesizeBitstream(WebPMuxImage* const wpi,
const int need_vp8x = (wpi->alpha_ != NULL);
const size_t vp8x_size = need_vp8x ? CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE : 0;
const size_t alpha_size = need_vp8x ? ChunkDiskSize(wpi->alpha_) : 0;
- // Note: No need to output FRM/TILE chunk for a single image.
+ // Note: No need to output ANMF/FRGM chunk for a single image.
const size_t size = RIFF_HEADER_SIZE + vp8x_size + alpha_size +
ChunkDiskSize(wpi->img_);
- uint8_t* const data = (uint8_t*)malloc(size);
+ uint8_t* const data = (uint8_t*)WebPSafeMalloc(1ULL, size);
if (data == NULL) return WEBP_MUX_MEMORY_ERROR;
// Main RIFF header.
dst = MuxEmitRiffHeader(data, size);
if (need_vp8x) {
- int w, h;
- WebPMuxError err;
- assert(wpi->img_ != NULL);
- err = MuxGetImageWidthHeight(wpi->img_, &w, &h);
- if (err != WEBP_MUX_OK) {
- free(data);
- return err;
- }
- dst = EmitVP8XChunk(dst, w, h, ALPHA_FLAG); // VP8X.
+ dst = EmitVP8XChunk(dst, wpi->width_, wpi->height_, ALPHA_FLAG); // VP8X.
dst = ChunkListEmit(wpi->alpha_, dst); // ALPH.
}
@@ -265,107 +398,115 @@ static WebPMuxError SynthesizeBitstream(WebPMuxImage* const wpi,
assert(dst == data + size);
// Output.
- bitstream->bytes_ = data;
- bitstream->size_ = size;
+ bitstream->bytes = data;
+ bitstream->size = size;
return WEBP_MUX_OK;
}
-WebPMuxError WebPMuxGetImage(const WebPMux* mux, WebPData* bitstream) {
- WebPMuxError err;
- WebPMuxImage* wpi = NULL;
-
- if (mux == NULL || bitstream == NULL) {
+WebPMuxError WebPMuxGetChunk(const WebPMux* mux, const char fourcc[4],
+ WebPData* chunk_data) {
+ CHUNK_INDEX idx;
+ if (mux == NULL || fourcc == NULL || chunk_data == NULL) {
return WEBP_MUX_INVALID_ARGUMENT;
}
-
- err = MuxValidateForImage(mux);
- if (err != WEBP_MUX_OK) return err;
-
- // All well. Get the image.
- err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, 1, WEBP_CHUNK_IMAGE,
- &wpi);
- assert(err == WEBP_MUX_OK); // Already tested above.
-
- return SynthesizeBitstream(wpi, bitstream);
-}
-
-WebPMuxError WebPMuxGetMetadata(const WebPMux* mux, WebPData* metadata) {
- if (mux == NULL || metadata == NULL) return WEBP_MUX_INVALID_ARGUMENT;
- return MuxGet(mux, IDX_META, 1, metadata);
+ idx = ChunkGetIndexFromFourCC(fourcc);
+ if (IsWPI(kChunks[idx].id)) { // An image chunk.
+ return WEBP_MUX_INVALID_ARGUMENT;
+ } else if (idx != IDX_UNKNOWN) { // A known chunk type.
+ return MuxGet(mux, idx, 1, chunk_data);
+ } else { // An unknown chunk type.
+ const WebPChunk* const chunk =
+ ChunkSearchList(mux->unknown_, 1, ChunkGetTagFromFourCC(fourcc));
+ if (chunk == NULL) return WEBP_MUX_NOT_FOUND;
+ *chunk_data = chunk->data_;
+ return WEBP_MUX_OK;
+ }
}
-WebPMuxError WebPMuxGetColorProfile(const WebPMux* mux,
- WebPData* color_profile) {
- if (mux == NULL || color_profile == NULL) return WEBP_MUX_INVALID_ARGUMENT;
- return MuxGet(mux, IDX_ICCP, 1, color_profile);
+static WebPMuxError MuxGetImageInternal(const WebPMuxImage* const wpi,
+ WebPMuxFrameInfo* const info) {
+ // Set some defaults for unrelated fields.
+ info->x_offset = 0;
+ info->y_offset = 0;
+ info->duration = 1;
+ info->dispose_method = WEBP_MUX_DISPOSE_NONE;
+ info->blend_method = WEBP_MUX_BLEND;
+ // Extract data for related fields.
+ info->id = ChunkGetIdFromTag(wpi->img_->tag_);
+ return SynthesizeBitstream(wpi, &info->bitstream);
}
-WebPMuxError WebPMuxGetLoopCount(const WebPMux* mux, int* loop_count) {
- WebPData image;
- WebPMuxError err;
-
- if (mux == NULL || loop_count == NULL) return WEBP_MUX_INVALID_ARGUMENT;
-
- err = MuxGet(mux, IDX_LOOP, 1, &image);
- if (err != WEBP_MUX_OK) return err;
- if (image.size_ < kChunks[WEBP_CHUNK_LOOP].size) return WEBP_MUX_BAD_DATA;
- *loop_count = GetLE16(image.bytes_);
-
- return WEBP_MUX_OK;
+static WebPMuxError MuxGetFrameFragmentInternal(const WebPMuxImage* const wpi,
+ WebPMuxFrameInfo* const frame) {
+ const int is_frame = (wpi->header_->tag_ == kChunks[IDX_ANMF].tag);
+ const CHUNK_INDEX idx = is_frame ? IDX_ANMF : IDX_FRGM;
+ const WebPData* frame_frgm_data;
+ if (!is_frame) return WEBP_MUX_INVALID_ARGUMENT;
+ assert(wpi->header_ != NULL); // Already checked by WebPMuxGetFrame().
+ // Get frame/fragment chunk.
+ frame_frgm_data = &wpi->header_->data_;
+ if (frame_frgm_data->size < kChunks[idx].size) return WEBP_MUX_BAD_DATA;
+ // Extract info.
+ frame->x_offset = 2 * GetLE24(frame_frgm_data->bytes + 0);
+ frame->y_offset = 2 * GetLE24(frame_frgm_data->bytes + 3);
+ if (is_frame) {
+ const uint8_t bits = frame_frgm_data->bytes[15];
+ frame->duration = GetLE24(frame_frgm_data->bytes + 12);
+ frame->dispose_method =
+ (bits & 1) ? WEBP_MUX_DISPOSE_BACKGROUND : WEBP_MUX_DISPOSE_NONE;
+ frame->blend_method = (bits & 2) ? WEBP_MUX_NO_BLEND : WEBP_MUX_BLEND;
+ } else { // Defaults for unused values.
+ frame->duration = 1;
+ frame->dispose_method = WEBP_MUX_DISPOSE_NONE;
+ frame->blend_method = WEBP_MUX_BLEND;
+ }
+ frame->id = ChunkGetIdFromTag(wpi->header_->tag_);
+ return SynthesizeBitstream(wpi, &frame->bitstream);
}
-static WebPMuxError MuxGetFrameTileInternal(
- const WebPMux* const mux, uint32_t nth, WebPData* const bitstream,
- int* const x_offset, int* const y_offset, int* const duration,
- uint32_t tag) {
- const WebPData* frame_tile_data;
+WebPMuxError WebPMuxGetFrame(
+ const WebPMux* mux, uint32_t nth, WebPMuxFrameInfo* frame) {
WebPMuxError err;
WebPMuxImage* wpi;
- const int is_frame = (tag == kChunks[WEBP_CHUNK_FRAME].tag) ? 1 : 0;
- const CHUNK_INDEX idx = is_frame ? IDX_FRAME : IDX_TILE;
- const WebPChunkId id = kChunks[idx].id;
-
- if (mux == NULL || bitstream == NULL ||
- x_offset == NULL || y_offset == NULL || (is_frame && duration == NULL)) {
+ // Sanity checks.
+ if (mux == NULL || frame == NULL) {
return WEBP_MUX_INVALID_ARGUMENT;
}
// Get the nth WebPMuxImage.
- err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, nth, id, &wpi);
+ err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, nth, &wpi);
if (err != WEBP_MUX_OK) return err;
- // Get frame chunk.
- assert(wpi->header_ != NULL); // As MuxImageGetNth() already checked header_.
- frame_tile_data = &wpi->header_->data_;
+ // Get frame info.
+ if (wpi->header_ == NULL) {
+ return MuxGetImageInternal(wpi, frame);
+ } else {
+ return MuxGetFrameFragmentInternal(wpi, frame);
+ }
+}
- if (frame_tile_data->size_ < kChunks[idx].size) return WEBP_MUX_BAD_DATA;
- *x_offset = 2 * GetLE24(frame_tile_data->bytes_ + 0);
- *y_offset = 2 * GetLE24(frame_tile_data->bytes_ + 3);
- if (is_frame) *duration = 1 + GetLE24(frame_tile_data->bytes_ + 12);
+WebPMuxError WebPMuxGetAnimationParams(const WebPMux* mux,
+ WebPMuxAnimParams* params) {
+ WebPData anim;
+ WebPMuxError err;
- return SynthesizeBitstream(wpi, bitstream);
-}
+ if (mux == NULL || params == NULL) return WEBP_MUX_INVALID_ARGUMENT;
-WebPMuxError WebPMuxGetFrame(const WebPMux* mux, uint32_t nth,
- WebPData* bitstream,
- int* x_offset, int* y_offset, int* duration) {
- return MuxGetFrameTileInternal(mux, nth, bitstream, x_offset, y_offset,
- duration, kChunks[IDX_FRAME].tag);
-}
+ err = MuxGet(mux, IDX_ANIM, 1, &anim);
+ if (err != WEBP_MUX_OK) return err;
+ if (anim.size < kChunks[WEBP_CHUNK_ANIM].size) return WEBP_MUX_BAD_DATA;
+ params->bgcolor = GetLE32(anim.bytes);
+ params->loop_count = GetLE16(anim.bytes + 4);
-WebPMuxError WebPMuxGetTile(const WebPMux* mux, uint32_t nth,
- WebPData* bitstream,
- int* x_offset, int* y_offset) {
- return MuxGetFrameTileInternal(mux, nth, bitstream, x_offset, y_offset, NULL,
- kChunks[IDX_TILE].tag);
+ return WEBP_MUX_OK;
}
// Get chunk index from chunk id. Returns IDX_NIL if not found.
static CHUNK_INDEX ChunkGetIndexFromId(WebPChunkId id) {
int i;
for (i = 0; kChunks[i].id != WEBP_CHUNK_NIL; ++i) {
- if (id == kChunks[i].id) return i;
+ if (id == kChunks[i].id) return (CHUNK_INDEX)i;
}
return IDX_NIL;
}
@@ -393,19 +534,11 @@ WebPMuxError WebPMuxNumChunks(const WebPMux* mux,
*num_elements = MuxImageCount(mux->images_, id);
} else {
WebPChunk* const* chunk_list = MuxGetChunkListFromId(mux, id);
- if (chunk_list == NULL) {
- *num_elements = 0;
- } else {
- const CHUNK_INDEX idx = ChunkGetIndexFromId(id);
- *num_elements = CountChunks(*chunk_list, kChunks[idx].tag);
- }
+ const CHUNK_INDEX idx = ChunkGetIndexFromId(id);
+ *num_elements = CountChunks(*chunk_list, kChunks[idx].tag);
}
return WEBP_MUX_OK;
}
//------------------------------------------------------------------------------
-
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/mux_types.h b/drivers/webp/mux_types.h
new file mode 100644
index 0000000000..c94043a3c0
--- /dev/null
+++ b/drivers/webp/mux_types.h
@@ -0,0 +1,97 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Data-types common to the mux and demux libraries.
+//
+// Author: Urvang (urvang@google.com)
+
+#ifndef WEBP_WEBP_MUX_TYPES_H_
+#define WEBP_WEBP_MUX_TYPES_H_
+
+#include <stdlib.h> // free()
+#include <string.h> // memset()
+#include "./types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Note: forward declaring enumerations is not allowed in (strict) C and C++,
+// the types are left here for reference.
+// typedef enum WebPFeatureFlags WebPFeatureFlags;
+// typedef enum WebPMuxAnimDispose WebPMuxAnimDispose;
+// typedef enum WebPMuxAnimBlend WebPMuxAnimBlend;
+typedef struct WebPData WebPData;
+
+// VP8X Feature Flags.
+typedef enum WebPFeatureFlags {
+ FRAGMENTS_FLAG = 0x00000001,
+ ANIMATION_FLAG = 0x00000002,
+ XMP_FLAG = 0x00000004,
+ EXIF_FLAG = 0x00000008,
+ ALPHA_FLAG = 0x00000010,
+ ICCP_FLAG = 0x00000020
+} WebPFeatureFlags;
+
+// Dispose method (animation only). Indicates how the area used by the current
+// frame is to be treated before rendering the next frame on the canvas.
+typedef enum WebPMuxAnimDispose {
+ WEBP_MUX_DISPOSE_NONE, // Do not dispose.
+ WEBP_MUX_DISPOSE_BACKGROUND // Dispose to background color.
+} WebPMuxAnimDispose;
+
+// Blend operation (animation only). Indicates how transparent pixels of the
+// current frame are blended with those of the previous canvas.
+typedef enum WebPMuxAnimBlend {
+ WEBP_MUX_BLEND, // Blend.
+ WEBP_MUX_NO_BLEND // Do not blend.
+} WebPMuxAnimBlend;
+
+// Data type used to describe 'raw' data, e.g., chunk data
+// (ICC profile, metadata) and WebP compressed image data.
+struct WebPData {
+ const uint8_t* bytes;
+ size_t size;
+};
+
+// Initializes the contents of the 'webp_data' object with default values.
+static WEBP_INLINE void WebPDataInit(WebPData* webp_data) {
+ if (webp_data != NULL) {
+ memset(webp_data, 0, sizeof(*webp_data));
+ }
+}
+
+// Clears the contents of the 'webp_data' object by calling free(). Does not
+// deallocate the object itself.
+static WEBP_INLINE void WebPDataClear(WebPData* webp_data) {
+ if (webp_data != NULL) {
+ free((void*)webp_data->bytes);
+ WebPDataInit(webp_data);
+ }
+}
+
+// Allocates necessary storage for 'dst' and copies the contents of 'src'.
+// Returns true on success.
+static WEBP_INLINE int WebPDataCopy(const WebPData* src, WebPData* dst) {
+ if (src == NULL || dst == NULL) return 0;
+ WebPDataInit(dst);
+ if (src->bytes != NULL && src->size != 0) {
+ dst->bytes = (uint8_t*)malloc(src->size);
+ if (dst->bytes == NULL) return 0;
+ memcpy((void*)dst->bytes, src->bytes, src->size);
+ dst->size = src->size;
+ }
+ return 1;
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* WEBP_WEBP_MUX_TYPES_H_ */
diff --git a/drivers/webp/types.h b/drivers/webp/types.h
index 3e27190bef..98fff35a11 100644
--- a/drivers/webp/types.h
+++ b/drivers/webp/types.h
@@ -1,8 +1,10 @@
// Copyright 2010 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Common types
@@ -16,10 +18,11 @@
#ifndef _MSC_VER
#include <inttypes.h>
-#ifdef __STRICT_ANSI__
-#define WEBP_INLINE
-#else /* __STRICT_ANSI__ */
+#if defined(__cplusplus) || !defined(__STRICT_ANSI__) || \
+ (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L)
#define WEBP_INLINE inline
+#else
+#define WEBP_INLINE
#endif
#else
typedef signed char int8_t;
@@ -36,7 +39,11 @@ typedef long long int int64_t;
#ifndef WEBP_EXTERN
// This explicitly marks library functions and allows for changing the
// signature for e.g., Windows DLL builds.
-#define WEBP_EXTERN(type) extern type
+# if defined(__GNUC__) && __GNUC__ >= 4
+# define WEBP_EXTERN(type) extern __attribute__ ((visibility ("default"))) type
+# else
+# define WEBP_EXTERN(type) extern type
+# endif /* __GNUC__ >= 4 */
#endif /* WEBP_EXTERN */
// Macro to check ABI compatibility (same major revision number)
diff --git a/drivers/webp/utils/bit_reader.c b/drivers/webp/utils/bit_reader.c
index 1afb1db890..4d6b4f0164 100644
--- a/drivers/webp/utils/bit_reader.c
+++ b/drivers/webp/utils/bit_reader.c
@@ -1,36 +1,62 @@
// Copyright 2010 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
-// Boolean decoder
+// Boolean decoder non-inlined methods
//
// Author: Skal (pascal.massimino@gmail.com)
-#include "./bit_reader.h"
-
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
+#ifdef HAVE_CONFIG_H
+#include "webp/config.h"
#endif
-#define MK(X) (((bit_t)(X) << (BITS)) | (MASK))
+#include "./bit_reader_inl.h"
+
+#define JAVASCRIPT_ENABLED // testing
//------------------------------------------------------------------------------
// VP8BitReader
+void VP8BitReaderSetBuffer(VP8BitReader* const br,
+ const uint8_t* const start,
+ size_t size) {
+ br->buf_ = start;
+ br->buf_end_ = start + size;
+ br->buf_max_ =
+ (size >= sizeof(lbit_t)) ? start + size - sizeof(lbit_t) + 1
+ : start;
+}
+
void VP8InitBitReader(VP8BitReader* const br,
- const uint8_t* const start, const uint8_t* const end) {
+ const uint8_t* const start, size_t size) {
assert(br != NULL);
assert(start != NULL);
- assert(start <= end);
- br->range_ = MK(255 - 1);
- br->buf_ = start;
- br->buf_end_ = end;
+ assert(size < (1u << 31)); // limit ensured by format and upstream checks
+ br->range_ = 255 - 1;
br->value_ = 0;
- br->missing_ = 8; // to load the very first 8bits
+ br->bits_ = -8; // to load the very first 8bits
br->eof_ = 0;
+ VP8BitReaderSetBuffer(br, start, size);
+
+#ifdef JAVASCRIPT_ENABLED // html5 required aligned reads
+ while(((uintptr_t)br->buf_ & 1) != 0 && !br->eof_)
+ VP8LoadFinalBytes(br);
+#else
+ VP8LoadNewBytes(br);
+#endif
+}
+
+void VP8RemapBitReader(VP8BitReader* const br, ptrdiff_t offset) {
+ if (br->buf_ != NULL) {
+ br->buf_ += offset;
+ br->buf_end_ += offset;
+ br->buf_max_ += offset;
+ }
}
const uint8_t kVP8Log2Range[128] = {
@@ -45,36 +71,38 @@ const uint8_t kVP8Log2Range[128] = {
0
};
-// range = (range << kVP8Log2Range[range]) + trailing 1's
-const bit_t kVP8NewRange[128] = {
- MK(127), MK(127), MK(191), MK(127), MK(159), MK(191), MK(223), MK(127),
- MK(143), MK(159), MK(175), MK(191), MK(207), MK(223), MK(239), MK(127),
- MK(135), MK(143), MK(151), MK(159), MK(167), MK(175), MK(183), MK(191),
- MK(199), MK(207), MK(215), MK(223), MK(231), MK(239), MK(247), MK(127),
- MK(131), MK(135), MK(139), MK(143), MK(147), MK(151), MK(155), MK(159),
- MK(163), MK(167), MK(171), MK(175), MK(179), MK(183), MK(187), MK(191),
- MK(195), MK(199), MK(203), MK(207), MK(211), MK(215), MK(219), MK(223),
- MK(227), MK(231), MK(235), MK(239), MK(243), MK(247), MK(251), MK(127),
- MK(129), MK(131), MK(133), MK(135), MK(137), MK(139), MK(141), MK(143),
- MK(145), MK(147), MK(149), MK(151), MK(153), MK(155), MK(157), MK(159),
- MK(161), MK(163), MK(165), MK(167), MK(169), MK(171), MK(173), MK(175),
- MK(177), MK(179), MK(181), MK(183), MK(185), MK(187), MK(189), MK(191),
- MK(193), MK(195), MK(197), MK(199), MK(201), MK(203), MK(205), MK(207),
- MK(209), MK(211), MK(213), MK(215), MK(217), MK(219), MK(221), MK(223),
- MK(225), MK(227), MK(229), MK(231), MK(233), MK(235), MK(237), MK(239),
- MK(241), MK(243), MK(245), MK(247), MK(249), MK(251), MK(253), MK(127)
+// range = ((range - 1) << kVP8Log2Range[range]) + 1
+const uint8_t kVP8NewRange[128] = {
+ 127, 127, 191, 127, 159, 191, 223, 127,
+ 143, 159, 175, 191, 207, 223, 239, 127,
+ 135, 143, 151, 159, 167, 175, 183, 191,
+ 199, 207, 215, 223, 231, 239, 247, 127,
+ 131, 135, 139, 143, 147, 151, 155, 159,
+ 163, 167, 171, 175, 179, 183, 187, 191,
+ 195, 199, 203, 207, 211, 215, 219, 223,
+ 227, 231, 235, 239, 243, 247, 251, 127,
+ 129, 131, 133, 135, 137, 139, 141, 143,
+ 145, 147, 149, 151, 153, 155, 157, 159,
+ 161, 163, 165, 167, 169, 171, 173, 175,
+ 177, 179, 181, 183, 185, 187, 189, 191,
+ 193, 195, 197, 199, 201, 203, 205, 207,
+ 209, 211, 213, 215, 217, 219, 221, 223,
+ 225, 227, 229, 231, 233, 235, 237, 239,
+ 241, 243, 245, 247, 249, 251, 253, 127
};
-#undef MK
-
void VP8LoadFinalBytes(VP8BitReader* const br) {
assert(br != NULL && br->buf_ != NULL);
// Only read 8bits at a time
if (br->buf_ < br->buf_end_) {
- br->value_ |= (bit_t)(*br->buf_++) << ((BITS) - 8 + br->missing_);
- br->missing_ -= 8;
- } else {
+ br->bits_ += 8;
+ br->value_ = (bit_t)(*br->buf_++) | (br->value_ << 8);
+ } else if (!br->eof_) {
+ br->value_ <<= 8;
+ br->bits_ += 8;
br->eof_ = 1;
+ } else {
+ br->bits_ = 0; // This is to avoid undefined behaviour with shifts.
}
}
@@ -97,32 +125,47 @@ int32_t VP8GetSignedValue(VP8BitReader* const br, int bits) {
//------------------------------------------------------------------------------
// VP8LBitReader
-#define MAX_NUM_BIT_READ 25
+#define VP8L_LOG8_WBITS 4 // Number of bytes needed to store VP8L_WBITS bits.
+
+#if !defined(WEBP_FORCE_ALIGNED) && \
+ (defined(__arm__) || defined(_M_ARM) || defined(__aarch64__) || \
+ defined(__i386__) || defined(_M_IX86) || \
+ defined(__x86_64__) || defined(_M_X64))
+#define VP8L_USE_UNALIGNED_LOAD
+#endif
-static const uint32_t kBitMask[MAX_NUM_BIT_READ] = {
- 0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767,
- 65535, 131071, 262143, 524287, 1048575, 2097151, 4194303, 8388607, 16777215
+static const uint32_t kBitMask[VP8L_MAX_NUM_BIT_READ + 1] = {
+ 0,
+ 0x000001, 0x000003, 0x000007, 0x00000f,
+ 0x00001f, 0x00003f, 0x00007f, 0x0000ff,
+ 0x0001ff, 0x0003ff, 0x0007ff, 0x000fff,
+ 0x001fff, 0x003fff, 0x007fff, 0x00ffff,
+ 0x01ffff, 0x03ffff, 0x07ffff, 0x0fffff,
+ 0x1fffff, 0x3fffff, 0x7fffff, 0xffffff
};
-void VP8LInitBitReader(VP8LBitReader* const br,
- const uint8_t* const start,
+void VP8LInitBitReader(VP8LBitReader* const br, const uint8_t* const start,
size_t length) {
size_t i;
+ vp8l_val_t value = 0;
assert(br != NULL);
assert(start != NULL);
assert(length < 0xfffffff8u); // can't happen with a RIFF chunk.
- br->buf_ = start;
br->len_ = length;
br->val_ = 0;
- br->pos_ = 0;
br->bit_pos_ = 0;
br->eos_ = 0;
- br->error_ = 0;
- for (i = 0; i < sizeof(br->val_) && i < br->len_; ++i) {
- br->val_ |= ((uint64_t)br->buf_[br->pos_]) << (8 * i);
- ++br->pos_;
+
+ if (length > sizeof(br->val_)) {
+ length = sizeof(br->val_);
+ }
+ for (i = 0; i < length; ++i) {
+ value |= (vp8l_val_t)start[i] << (8 * i);
}
+ br->val_ = value;
+ br->pos_ = length;
+ br->buf_ = start;
}
void VP8LBitReaderSetBuffer(VP8LBitReader* const br,
@@ -130,100 +173,62 @@ void VP8LBitReaderSetBuffer(VP8LBitReader* const br,
assert(br != NULL);
assert(buf != NULL);
assert(len < 0xfffffff8u); // can't happen with a RIFF chunk.
- br->eos_ = (br->pos_ >= len);
br->buf_ = buf;
br->len_ = len;
+ // pos_ > len_ should be considered a param error.
+ br->eos_ = (br->pos_ > br->len_) || VP8LIsEndOfStream(br);
}
+static void VP8LSetEndOfStream(VP8LBitReader* const br) {
+ br->eos_ = 1;
+ br->bit_pos_ = 0; // To avoid undefined behaviour with shifts.
+}
+
+// If not at EOS, reload up to VP8L_LBITS byte-by-byte
static void ShiftBytes(VP8LBitReader* const br) {
while (br->bit_pos_ >= 8 && br->pos_ < br->len_) {
br->val_ >>= 8;
- br->val_ |= ((uint64_t)br->buf_[br->pos_]) << 56;
+ br->val_ |= ((vp8l_val_t)br->buf_[br->pos_]) << (VP8L_LBITS - 8);
++br->pos_;
br->bit_pos_ -= 8;
}
-}
-
-void VP8LFillBitWindow(VP8LBitReader* const br) {
- if (br->bit_pos_ >= 32) {
-#if defined(__x86_64__) || defined(_M_X64)
- if (br->pos_ + 8 < br->len_) {
- br->val_ >>= 32;
- // The expression below needs a little-endian arch to work correctly.
- // This gives a large speedup for decoding speed.
- br->val_ |= *(const uint64_t *)(br->buf_ + br->pos_) << 32;
- br->pos_ += 4;
- br->bit_pos_ -= 32;
- } else {
- // Slow path.
- ShiftBytes(br);
- }
-#else
- // Always the slow path.
- ShiftBytes(br);
-#endif
- }
- if (br->pos_ == br->len_ && br->bit_pos_ == 64) {
- br->eos_ = 1;
+ if (VP8LIsEndOfStream(br)) {
+ VP8LSetEndOfStream(br);
}
}
-uint32_t VP8LReadOneBit(VP8LBitReader* const br) {
- const uint32_t val = (br->val_ >> br->bit_pos_) & 1;
- // Flag an error at end_of_stream.
- if (!br->eos_) {
- ++br->bit_pos_;
- if (br->bit_pos_ >= 32) {
- ShiftBytes(br);
- }
- // After this last bit is read, check if eos needs to be flagged.
- if (br->pos_ == br->len_ && br->bit_pos_ == 64) {
- br->eos_ = 1;
- }
- } else {
- br->error_ = 1;
+void VP8LDoFillBitWindow(VP8LBitReader* const br) {
+ assert(br->bit_pos_ >= VP8L_WBITS);
+ // TODO(jzern): given the fixed read size it may be possible to force
+ // alignment in this block.
+#if defined(VP8L_USE_UNALIGNED_LOAD)
+ if (br->pos_ + sizeof(br->val_) < br->len_) {
+ br->val_ >>= VP8L_WBITS;
+ br->bit_pos_ -= VP8L_WBITS;
+ // The expression below needs a little-endian arch to work correctly.
+ // This gives a large speedup for decoding speed.
+ br->val_ |= (vp8l_val_t)*(const uint32_t*)(br->buf_ + br->pos_) <<
+ (VP8L_LBITS - VP8L_WBITS);
+ br->pos_ += VP8L_LOG8_WBITS;
+ return;
}
- return val;
+#endif
+ ShiftBytes(br); // Slow path.
}
uint32_t VP8LReadBits(VP8LBitReader* const br, int n_bits) {
- uint32_t val = 0;
assert(n_bits >= 0);
// Flag an error if end_of_stream or n_bits is more than allowed limit.
- if (!br->eos_ && n_bits < MAX_NUM_BIT_READ) {
- // If this read is going to cross the read buffer, set the eos flag.
- if (br->pos_ == br->len_) {
- if ((br->bit_pos_ + n_bits) >= 64) {
- br->eos_ = 1;
- if ((br->bit_pos_ + n_bits) > 64) return val;
- }
- }
- val = (br->val_ >> br->bit_pos_) & kBitMask[n_bits];
- br->bit_pos_ += n_bits;
- if (br->bit_pos_ >= 40) {
- if (br->pos_ + 5 < br->len_) {
- br->val_ >>= 40;
- br->val_ |=
- (((uint64_t)br->buf_[br->pos_ + 0]) << 24) |
- (((uint64_t)br->buf_[br->pos_ + 1]) << 32) |
- (((uint64_t)br->buf_[br->pos_ + 2]) << 40) |
- (((uint64_t)br->buf_[br->pos_ + 3]) << 48) |
- (((uint64_t)br->buf_[br->pos_ + 4]) << 56);
- br->pos_ += 5;
- br->bit_pos_ -= 40;
- }
- if (br->bit_pos_ >= 8) {
- ShiftBytes(br);
- }
- }
+ if (!br->eos_ && n_bits <= VP8L_MAX_NUM_BIT_READ) {
+ const uint32_t val = VP8LPrefetchBits(br) & kBitMask[n_bits];
+ const int new_bits = br->bit_pos_ + n_bits;
+ br->bit_pos_ = new_bits;
+ ShiftBytes(br);
+ return val;
} else {
- br->error_ = 1;
+ VP8LSetEndOfStream(br);
+ return 0;
}
- return val;
}
//------------------------------------------------------------------------------
-
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/utils/bit_reader.h b/drivers/webp/utils/bit_reader.h
index 43cd948fd4..f0f450231d 100644
--- a/drivers/webp/utils/bit_reader.h
+++ b/drivers/webp/utils/bit_reader.h
@@ -1,9 +1,10 @@
-//
// Copyright 2010 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Boolean decoder
@@ -18,44 +19,83 @@
#ifdef _MSC_VER
#include <stdlib.h> // _byteswap_ulong
#endif
-#include <string.h> // For memcpy
-#include "../types.h"
+#include "webp/types.h"
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
extern "C" {
#endif
-#define BITS 32 // can be 32, 16 or 8
-#define MASK ((((bit_t)1) << (BITS)) - 1)
-#if (BITS == 32)
-typedef uint64_t bit_t; // natural register type
-typedef uint32_t lbit_t; // natural type for memory I/O
-#elif (BITS == 16)
-typedef uint32_t bit_t;
-typedef uint16_t lbit_t;
+// The Boolean decoder needs to maintain infinite precision on the value_ field.
+// However, since range_ is only 8bit, we only need an active window of 8 bits
+// for value_. Left bits (MSB) gets zeroed and shifted away when value_ falls
+// below 128, range_ is updated, and fresh bits read from the bitstream are
+// brought in as LSB. To avoid reading the fresh bits one by one (slow), we
+// cache BITS of them ahead. The total of (BITS + 8) bits must fit into a
+// natural register (with type bit_t). To fetch BITS bits from bitstream we
+// use a type lbit_t.
+//
+// BITS can be any multiple of 8 from 8 to 56 (inclusive).
+// Pick values that fit natural register size.
+
+#ifdef JAVASCRIPT_ENABLED
+
+#define BITS 16
+
+#else
+
+#if defined(__i386__) || defined(_M_IX86) // x86 32bit
+#define BITS 24
+#elif defined(__x86_64__) || defined(_M_X64) // x86 64bit
+#define BITS 56
+#elif defined(__arm__) || defined(_M_ARM) // ARM
+#define BITS 24
+#elif defined(__mips__) // MIPS
+#define BITS 24
+#else // reasonable default
+#define BITS 24 // TODO(skal): test aarch64 and find the proper BITS value.
+#endif
+
+#endif
+
+//------------------------------------------------------------------------------
+// Derived types and constants:
+// bit_t = natural register type for storing 'value_' (which is BITS+8 bits)
+// range_t = register for 'range_' (which is 8bits only)
+
+#if (BITS > 24)
+typedef uint64_t bit_t;
#else
typedef uint32_t bit_t;
-typedef uint8_t lbit_t;
#endif
+typedef uint32_t range_t;
+
//------------------------------------------------------------------------------
-// Bitreader and code-tree reader
+// Bitreader
typedef struct VP8BitReader VP8BitReader;
struct VP8BitReader {
+ // boolean decoder (keep the field ordering as is!)
+ bit_t value_; // current value
+ range_t range_; // current range minus 1. In [127, 254] interval.
+ int bits_; // number of valid bits left
+ // read buffer
const uint8_t* buf_; // next byte to be read
const uint8_t* buf_end_; // end of read buffer
+ const uint8_t* buf_max_; // max packed-read position on buffer
int eof_; // true if input is exhausted
-
- // boolean decoder
- bit_t range_; // current range minus 1. In [127, 254] interval.
- bit_t value_; // current value
- int missing_; // number of missing bits in value_ (8bit)
};
// Initialize the bit reader and the boolean decoder.
void VP8InitBitReader(VP8BitReader* const br,
- const uint8_t* const start, const uint8_t* const end);
+ const uint8_t* const start, size_t size);
+// Sets the working read buffer.
+void VP8BitReaderSetBuffer(VP8BitReader* const br,
+ const uint8_t* const start, size_t size);
+
+// Update internal pointers to displace the byte buffer by the
+// relative offset 'offset'.
+void VP8RemapBitReader(VP8BitReader* const br, ptrdiff_t offset);
// return the next value made of 'num_bits' bits
uint32_t VP8GetValue(VP8BitReader* const br, int num_bits);
@@ -66,100 +106,31 @@ static WEBP_INLINE uint32_t VP8Get(VP8BitReader* const br) {
// return the next value with sign-extension.
int32_t VP8GetSignedValue(VP8BitReader* const br, int num_bits);
-// Read a bit with proba 'prob'. Speed-critical function!
-extern const uint8_t kVP8Log2Range[128];
-extern const bit_t kVP8NewRange[128];
-
-void VP8LoadFinalBytes(VP8BitReader* const br); // special case for the tail
-
-static WEBP_INLINE void VP8LoadNewBytes(VP8BitReader* const br) {
- assert(br && br->buf_);
- // Read 'BITS' bits at a time if possible.
- if (br->buf_ + sizeof(lbit_t) <= br->buf_end_) {
- // convert memory type to register type (with some zero'ing!)
- bit_t bits;
- lbit_t in_bits = *(lbit_t*)br->buf_;
- br->buf_ += (BITS) >> 3;
-#if !defined(__BIG_ENDIAN__)
-#if (BITS == 32)
-#if defined(__i386__) || defined(__x86_64__)
- __asm__ volatile("bswap %k0" : "=r"(in_bits) : "0"(in_bits));
- bits = (bit_t)in_bits; // 32b -> 64b zero-extension
-#elif defined(_MSC_VER)
- bits = _byteswap_ulong(in_bits);
-#else
- bits = (bit_t)(in_bits >> 24) | ((in_bits >> 8) & 0xff00)
- | ((in_bits << 8) & 0xff0000) | (in_bits << 24);
-#endif // x86
-#elif (BITS == 16)
- // gcc will recognize a 'rorw $8, ...' here:
- bits = (bit_t)(in_bits >> 8) | ((in_bits & 0xff) << 8);
-#endif
-#else // LITTLE_ENDIAN
- bits = (bit_t)in_bits;
-#endif
- br->value_ |= bits << br->missing_;
- br->missing_ -= (BITS);
- } else {
- VP8LoadFinalBytes(br); // no need to be inlined
- }
-}
+// bit_reader_inl.h will implement the following methods:
+// static WEBP_INLINE int VP8GetBit(VP8BitReader* const br, int prob)
+// static WEBP_INLINE int VP8GetSigned(VP8BitReader* const br, int v)
+// and should be included by the .c files that actually need them.
+// This is to avoid recompiling the whole library whenever this file is touched,
+// and also allowing platform-specific ad-hoc hacks.
-static WEBP_INLINE int VP8BitUpdate(VP8BitReader* const br, bit_t split) {
- const bit_t value_split = split | (MASK);
- if (br->missing_ > 0) { // Make sure we have a least BITS bits in 'value_'
- VP8LoadNewBytes(br);
- }
- if (br->value_ > value_split) {
- br->range_ -= value_split + 1;
- br->value_ -= value_split + 1;
- return 1;
- } else {
- br->range_ = value_split;
- return 0;
- }
-}
-
-static WEBP_INLINE void VP8Shift(VP8BitReader* const br) {
- // range_ is in [0..127] interval here.
- const int idx = br->range_ >> (BITS);
- const int shift = kVP8Log2Range[idx];
- br->range_ = kVP8NewRange[idx];
- br->value_ <<= shift;
- br->missing_ += shift;
-}
-
-static WEBP_INLINE int VP8GetBit(VP8BitReader* const br, int prob) {
- // It's important to avoid generating a 64bit x 64bit multiply here.
- // We just need an 8b x 8b after all.
- const bit_t split =
- (bit_t)((uint32_t)(br->range_ >> (BITS)) * prob) << ((BITS) - 8);
- const int bit = VP8BitUpdate(br, split);
- if (br->range_ <= (((bit_t)0x7e << (BITS)) | (MASK))) {
- VP8Shift(br);
- }
- return bit;
-}
+// -----------------------------------------------------------------------------
+// Bitreader for lossless format
-static WEBP_INLINE int VP8GetSigned(VP8BitReader* const br, int v) {
- const bit_t split = (br->range_ >> 1);
- const int bit = VP8BitUpdate(br, split);
- VP8Shift(br);
- return bit ? -v : v;
-}
+// maximum number of bits (inclusive) the bit-reader can handle:
+#define VP8L_MAX_NUM_BIT_READ 24
+#define VP8L_LBITS 64 // Number of bits prefetched (= bit-size of vp8l_val_t).
+#define VP8L_WBITS 32 // Minimum number of bytes ready after VP8LFillBitWindow.
-// -----------------------------------------------------------------------------
-// Bitreader
+typedef uint64_t vp8l_val_t; // right now, this bit-reader can only use 64bit.
typedef struct {
- uint64_t val_;
- const uint8_t* buf_;
- size_t len_;
- size_t pos_;
- int bit_pos_;
- int eos_;
- int error_;
+ vp8l_val_t val_; // pre-fetched bits
+ const uint8_t* buf_; // input byte buffer
+ size_t len_; // buffer length
+ size_t pos_; // byte position in buf_
+ int bit_pos_; // current bit-reading position in val_
+ int eos_; // true if a bit was read past the end of buffer
} VP8LBitReader;
void VP8LInitBitReader(VP8LBitReader* const br,
@@ -170,28 +141,39 @@ void VP8LInitBitReader(VP8LBitReader* const br,
void VP8LBitReaderSetBuffer(VP8LBitReader* const br,
const uint8_t* const buffer, size_t length);
-// Reads the specified number of bits from Read Buffer.
-// Flags an error in case end_of_stream or n_bits is more than allowed limit.
-// Flags eos if this read attempt is going to cross the read buffer.
+// Reads the specified number of bits from read buffer.
+// Flags an error in case end_of_stream or n_bits is more than the allowed limit
+// of VP8L_MAX_NUM_BIT_READ (inclusive).
+// Flags eos_ if this read attempt is going to cross the read buffer.
uint32_t VP8LReadBits(VP8LBitReader* const br, int n_bits);
-// Reads one bit from Read Buffer. Flags an error in case end_of_stream.
-// Flags eos after reading last bit from the buffer.
-uint32_t VP8LReadOneBit(VP8LBitReader* const br);
-
-// VP8LReadOneBitUnsafe is faster than VP8LReadOneBit, but it can be called only
-// 32 times after the last VP8LFillBitWindow. Any subsequent calls
-// (without VP8LFillBitWindow) will return invalid data.
-static WEBP_INLINE uint32_t VP8LReadOneBitUnsafe(VP8LBitReader* const br) {
- const uint32_t val = (br->val_ >> br->bit_pos_) & 1;
- ++br->bit_pos_;
- return val;
+// Return the prefetched bits, so they can be looked up.
+static WEBP_INLINE uint32_t VP8LPrefetchBits(VP8LBitReader* const br) {
+ return (uint32_t)(br->val_ >> (br->bit_pos_ & (VP8L_LBITS - 1)));
}
-// Advances the Read buffer by 4 bytes to make room for reading next 32 bits.
-void VP8LFillBitWindow(VP8LBitReader* const br);
+// Returns true if there was an attempt at reading bit past the end of
+// the buffer. Doesn't set br->eos_ flag.
+static WEBP_INLINE int VP8LIsEndOfStream(const VP8LBitReader* const br) {
+ assert(br->pos_ <= br->len_);
+ return br->eos_ || ((br->pos_ == br->len_) && (br->bit_pos_ > VP8L_LBITS));
+}
+
+// For jumping over a number of bits in the bit stream when accessed with
+// VP8LPrefetchBits and VP8LFillBitWindow.
+static WEBP_INLINE void VP8LSetBitPos(VP8LBitReader* const br, int val) {
+ br->bit_pos_ = val;
+ br->eos_ = VP8LIsEndOfStream(br);
+}
+
+// Advances the read buffer by 4 bytes to make room for reading next 32 bits.
+// Speed critical, but infrequent part of the code can be non-inlined.
+extern void VP8LDoFillBitWindow(VP8LBitReader* const br);
+static WEBP_INLINE void VP8LFillBitWindow(VP8LBitReader* const br) {
+ if (br->bit_pos_ >= VP8L_WBITS) VP8LDoFillBitWindow(br);
+}
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/drivers/webp/utils/bit_reader_inl.h b/drivers/webp/utils/bit_reader_inl.h
new file mode 100644
index 0000000000..20ce5f3cc7
--- /dev/null
+++ b/drivers/webp/utils/bit_reader_inl.h
@@ -0,0 +1,172 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Specific inlined methods for boolean decoder [VP8GetBit() ...]
+// This file should be included by the .c sources that actually need to call
+// these methods.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#ifndef WEBP_UTILS_BIT_READER_INL_H_
+#define WEBP_UTILS_BIT_READER_INL_H_
+
+#ifdef HAVE_CONFIG_H
+#include "webp/config.h"
+#endif
+
+#ifdef WEBP_FORCE_ALIGNED
+#include <string.h> // memcpy
+#endif
+
+#include "../dsp/dsp.h"
+#include "./bit_reader.h"
+#include "./endian_inl.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// Derived type lbit_t = natural type for memory I/O
+
+#if (BITS > 32)
+typedef uint64_t lbit_t;
+#elif (BITS > 16)
+typedef uint32_t lbit_t;
+#elif (BITS > 8)
+typedef uint16_t lbit_t;
+#else
+typedef uint8_t lbit_t;
+#endif
+
+extern const uint8_t kVP8Log2Range[128];
+extern const uint8_t kVP8NewRange[128];
+
+// special case for the tail byte-reading
+void VP8LoadFinalBytes(VP8BitReader* const br);
+
+//------------------------------------------------------------------------------
+// Inlined critical functions
+
+// makes sure br->value_ has at least BITS bits worth of data
+static WEBP_INLINE void VP8LoadNewBytes(VP8BitReader* const br) {
+ assert(br != NULL && br->buf_ != NULL);
+ // Read 'BITS' bits at a time if possible.
+ if (br->buf_ < br->buf_max_) {
+ // convert memory type to register type (with some zero'ing!)
+ bit_t bits;
+#if defined(WEBP_FORCE_ALIGNED)
+ lbit_t in_bits;
+ memcpy(&in_bits, br->buf_, sizeof(in_bits));
+#elif defined(WEBP_USE_MIPS32)
+ // This is needed because of un-aligned read.
+ lbit_t in_bits;
+ lbit_t* p_buf_ = (lbit_t*)br->buf_;
+ __asm__ volatile(
+ ".set push \n\t"
+ ".set at \n\t"
+ ".set macro \n\t"
+ "ulw %[in_bits], 0(%[p_buf_]) \n\t"
+ ".set pop \n\t"
+ : [in_bits]"=r"(in_bits)
+ : [p_buf_]"r"(p_buf_)
+ : "memory", "at"
+ );
+#else
+ const lbit_t in_bits = *(const lbit_t*)br->buf_;
+#endif
+ br->buf_ += BITS >> 3;
+#if !defined(WORDS_BIGENDIAN)
+#if (BITS > 32)
+ bits = BSwap64(in_bits);
+ bits >>= 64 - BITS;
+#elif (BITS >= 24)
+ bits = BSwap32(in_bits);
+ bits >>= (32 - BITS);
+#elif (BITS == 16)
+ bits = BSwap16(in_bits);
+#else // BITS == 8
+ bits = (bit_t)in_bits;
+#endif // BITS > 32
+#else // WORDS_BIGENDIAN
+ bits = (bit_t)in_bits;
+ if (BITS != 8 * sizeof(bit_t)) bits >>= (8 * sizeof(bit_t) - BITS);
+#endif
+ br->value_ = bits | (br->value_ << BITS);
+ br->bits_ += BITS;
+ } else {
+ VP8LoadFinalBytes(br); // no need to be inlined
+ }
+}
+
+// Read a bit with proba 'prob'. Speed-critical function!
+static WEBP_INLINE int VP8GetBit(VP8BitReader* const br, int prob) {
+ // Don't move this declaration! It makes a big speed difference to store
+ // 'range' *before* calling VP8LoadNewBytes(), even if this function doesn't
+ // alter br->range_ value.
+ range_t range = br->range_;
+ if (br->bits_ < 0) {
+ VP8LoadNewBytes(br);
+ }
+ {
+ const int pos = br->bits_;
+ const range_t split = (range * prob) >> 8;
+ const range_t value = (range_t)(br->value_ >> pos);
+#if defined(__arm__) || defined(_M_ARM) // ARM-specific
+ const int bit = ((int)(split - value) >> 31) & 1;
+ if (value > split) {
+ range -= split + 1;
+ br->value_ -= (bit_t)(split + 1) << pos;
+ } else {
+ range = split;
+ }
+#else // faster version on x86
+ int bit; // Don't use 'const int bit = (value > split);", it's slower.
+ if (value > split) {
+ range -= split + 1;
+ br->value_ -= (bit_t)(split + 1) << pos;
+ bit = 1;
+ } else {
+ range = split;
+ bit = 0;
+ }
+#endif
+ if (range <= (range_t)0x7e) {
+ const int shift = kVP8Log2Range[range];
+ range = kVP8NewRange[range];
+ br->bits_ -= shift;
+ }
+ br->range_ = range;
+ return bit;
+ }
+}
+
+// simplified version of VP8GetBit() for prob=0x80 (note shift is always 1 here)
+static WEBP_INLINE int VP8GetSigned(VP8BitReader* const br, int v) {
+ if (br->bits_ < 0) {
+ VP8LoadNewBytes(br);
+ }
+ {
+ const int pos = br->bits_;
+ const range_t split = br->range_ >> 1;
+ const range_t value = (range_t)(br->value_ >> pos);
+ const int32_t mask = (int32_t)(split - value) >> 31; // -1 or 0
+ br->bits_ -= 1;
+ br->range_ += mask;
+ br->range_ |= 1;
+ br->value_ -= (bit_t)((split + 1) & mask) << pos;
+ return (v ^ mask) - mask;
+ }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // WEBP_UTILS_BIT_READER_INL_H_
diff --git a/drivers/webp/utils/bit_writer.c b/drivers/webp/utils/bit_writer.c
index 671159cacd..064428691b 100644
--- a/drivers/webp/utils/bit_writer.c
+++ b/drivers/webp/utils/bit_writer.c
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Bit writing and boolean coder
@@ -13,11 +15,10 @@
#include <assert.h>
#include <string.h> // for memcpy()
#include <stdlib.h>
-#include "./bit_writer.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
+#include "./bit_writer.h"
+#include "./endian_inl.h"
+#include "./utils.h"
//------------------------------------------------------------------------------
// VP8BitWriter
@@ -36,19 +37,22 @@ static int BitWriterResize(VP8BitWriter* const bw, size_t extra_size) {
new_size = 2 * bw->max_pos_;
if (new_size < needed_size) new_size = needed_size;
if (new_size < 1024) new_size = 1024;
- new_buf = (uint8_t*)malloc(new_size);
+ new_buf = (uint8_t*)WebPSafeMalloc(1ULL, new_size);
if (new_buf == NULL) {
bw->error_ = 1;
return 0;
}
- memcpy(new_buf, bw->buf_, bw->pos_);
- free(bw->buf_);
+ if (bw->pos_ > 0) {
+ assert(bw->buf_ != NULL);
+ memcpy(new_buf, bw->buf_, bw->pos_);
+ }
+ WebPSafeFree(bw->buf_);
bw->buf_ = new_buf;
bw->max_pos_ = new_size;
return 1;
}
-static void kFlush(VP8BitWriter* const bw) {
+static void Flush(VP8BitWriter* const bw) {
const int s = 8 + bw->nb_bits_;
const int32_t bits = bw->value_ >> s;
assert(bw->nb_bits_ >= 0);
@@ -114,7 +118,7 @@ int VP8PutBit(VP8BitWriter* const bw, int bit, int prob) {
bw->range_ = kNewRange[bw->range_];
bw->value_ <<= shift;
bw->nb_bits_ += shift;
- if (bw->nb_bits_ > 0) kFlush(bw);
+ if (bw->nb_bits_ > 0) Flush(bw);
}
return bit;
}
@@ -131,24 +135,25 @@ int VP8PutBitUniform(VP8BitWriter* const bw, int bit) {
bw->range_ = kNewRange[bw->range_];
bw->value_ <<= 1;
bw->nb_bits_ += 1;
- if (bw->nb_bits_ > 0) kFlush(bw);
+ if (bw->nb_bits_ > 0) Flush(bw);
}
return bit;
}
-void VP8PutValue(VP8BitWriter* const bw, int value, int nb_bits) {
- int mask;
- for (mask = 1 << (nb_bits - 1); mask; mask >>= 1)
+void VP8PutBits(VP8BitWriter* const bw, uint32_t value, int nb_bits) {
+ uint32_t mask;
+ assert(nb_bits > 0 && nb_bits < 32);
+ for (mask = 1u << (nb_bits - 1); mask; mask >>= 1)
VP8PutBitUniform(bw, value & mask);
}
-void VP8PutSignedValue(VP8BitWriter* const bw, int value, int nb_bits) {
+void VP8PutSignedBits(VP8BitWriter* const bw, int value, int nb_bits) {
if (!VP8PutBitUniform(bw, value != 0))
return;
if (value < 0) {
- VP8PutValue(bw, ((-value) << 1) | 1, nb_bits + 1);
+ VP8PutBits(bw, ((-value) << 1) | 1, nb_bits + 1);
} else {
- VP8PutValue(bw, value << 1, nb_bits + 1);
+ VP8PutBits(bw, value << 1, nb_bits + 1);
}
}
@@ -167,16 +172,16 @@ int VP8BitWriterInit(VP8BitWriter* const bw, size_t expected_size) {
}
uint8_t* VP8BitWriterFinish(VP8BitWriter* const bw) {
- VP8PutValue(bw, 0, 9 - bw->nb_bits_);
+ VP8PutBits(bw, 0, 9 - bw->nb_bits_);
bw->nb_bits_ = 0; // pad with zeroes
- kFlush(bw);
+ Flush(bw);
return bw->buf_;
}
int VP8BitWriterAppend(VP8BitWriter* const bw,
const uint8_t* data, size_t size) {
- assert(data);
- if (bw->nb_bits_ != -8) return 0; // kFlush() must have been called
+ assert(data != NULL);
+ if (bw->nb_bits_ != -8) return 0; // Flush() must have been called
if (!BitWriterResize(bw, size)) return 0;
memcpy(bw->buf_ + bw->pos_, data, size);
bw->pos_ += size;
@@ -184,8 +189,8 @@ int VP8BitWriterAppend(VP8BitWriter* const bw,
}
void VP8BitWriterWipeOut(VP8BitWriter* const bw) {
- if (bw) {
- free(bw->buf_);
+ if (bw != NULL) {
+ WebPSafeFree(bw->buf_);
memset(bw, 0, sizeof(*bw));
}
}
@@ -193,32 +198,39 @@ void VP8BitWriterWipeOut(VP8BitWriter* const bw) {
//------------------------------------------------------------------------------
// VP8LBitWriter
+// This is the minimum amount of size the memory buffer is guaranteed to grow
+// when extra space is needed.
+#define MIN_EXTRA_SIZE (32768ULL)
+
// Returns 1 on success.
static int VP8LBitWriterResize(VP8LBitWriter* const bw, size_t extra_size) {
uint8_t* allocated_buf;
size_t allocated_size;
- const size_t current_size = VP8LBitWriterNumBytes(bw);
+ const size_t max_bytes = bw->end_ - bw->buf_;
+ const size_t current_size = bw->cur_ - bw->buf_;
const uint64_t size_required_64b = (uint64_t)current_size + extra_size;
const size_t size_required = (size_t)size_required_64b;
if (size_required != size_required_64b) {
bw->error_ = 1;
return 0;
}
- if (bw->max_bytes_ > 0 && size_required <= bw->max_bytes_) return 1;
- allocated_size = (3 * bw->max_bytes_) >> 1;
+ if (max_bytes > 0 && size_required <= max_bytes) return 1;
+ allocated_size = (3 * max_bytes) >> 1;
if (allocated_size < size_required) allocated_size = size_required;
// make allocated size multiple of 1k
allocated_size = (((allocated_size >> 10) + 1) << 10);
- allocated_buf = (uint8_t*)malloc(allocated_size);
+ allocated_buf = (uint8_t*)WebPSafeMalloc(1ULL, allocated_size);
if (allocated_buf == NULL) {
bw->error_ = 1;
return 0;
}
- memcpy(allocated_buf, bw->buf_, current_size);
- free(bw->buf_);
+ if (current_size > 0) {
+ memcpy(allocated_buf, bw->buf_, current_size);
+ }
+ WebPSafeFree(bw->buf_);
bw->buf_ = allocated_buf;
- bw->max_bytes_ = allocated_size;
- memset(allocated_buf + current_size, 0, allocated_size - current_size);
+ bw->cur_ = bw->buf_ + current_size;
+ bw->end_ = bw->buf_ + allocated_size;
return 1;
}
@@ -227,58 +239,81 @@ int VP8LBitWriterInit(VP8LBitWriter* const bw, size_t expected_size) {
return VP8LBitWriterResize(bw, expected_size);
}
-void VP8LBitWriterDestroy(VP8LBitWriter* const bw) {
+void VP8LBitWriterWipeOut(VP8LBitWriter* const bw) {
if (bw != NULL) {
- free(bw->buf_);
+ WebPSafeFree(bw->buf_);
memset(bw, 0, sizeof(*bw));
}
}
-void VP8LWriteBits(VP8LBitWriter* const bw, int n_bits, uint32_t bits) {
- if (n_bits < 1) return;
-#if !defined(__BIG_ENDIAN__)
- // Technically, this branch of the code can write up to 25 bits at a time,
- // but in prefix encoding, the maximum number of bits written is 18 at a time.
- {
- uint8_t* const p = &bw->buf_[bw->bit_pos_ >> 3];
- uint32_t v = *(const uint32_t*)p;
- v |= bits << (bw->bit_pos_ & 7);
- *(uint32_t*)p = v;
- bw->bit_pos_ += n_bits;
+void VP8LPutBitsFlushBits(VP8LBitWriter* const bw) {
+ // If needed, make some room by flushing some bits out.
+ if (bw->cur_ + VP8L_WRITER_BYTES > bw->end_) {
+ const uint64_t extra_size = (bw->end_ - bw->buf_) + MIN_EXTRA_SIZE;
+ if (extra_size != (size_t)extra_size ||
+ !VP8LBitWriterResize(bw, (size_t)extra_size)) {
+ bw->cur_ = bw->buf_;
+ bw->error_ = 1;
+ return;
+ }
}
-#else // BIG_ENDIAN
- {
- uint8_t* p = &bw->buf_[bw->bit_pos_ >> 3];
- const int bits_reserved_in_first_byte = bw->bit_pos_ & 7;
- const int bits_left_to_write = n_bits - 8 + bits_reserved_in_first_byte;
- // implicit & 0xff is assumed for uint8_t arithmetics
- *p++ |= bits << bits_reserved_in_first_byte;
- bits >>= 8 - bits_reserved_in_first_byte;
- if (bits_left_to_write >= 1) {
- *p++ = bits;
- bits >>= 8;
- if (bits_left_to_write >= 9) {
- *p++ = bits;
- bits >>= 8;
+ *(vp8l_wtype_t*)bw->cur_ = (vp8l_wtype_t)WSWAP((vp8l_wtype_t)bw->bits_);
+ bw->cur_ += VP8L_WRITER_BYTES;
+ bw->bits_ >>= VP8L_WRITER_BITS;
+ bw->used_ -= VP8L_WRITER_BITS;
+}
+
+void VP8LPutBitsInternal(VP8LBitWriter* const bw, uint32_t bits, int n_bits) {
+ assert(n_bits <= 32);
+ // That's the max we can handle:
+ assert(sizeof(vp8l_wtype_t) == 2);
+ if (n_bits > 0) {
+ vp8l_atype_t lbits = bw->bits_;
+ int used = bw->used_;
+ // Special case of overflow handling for 32bit accumulator (2-steps flush).
+#if VP8L_WRITER_BITS == 16
+ if (used + n_bits >= VP8L_WRITER_MAX_BITS) {
+ // Fill up all the VP8L_WRITER_MAX_BITS so it can be flushed out below.
+ const int shift = VP8L_WRITER_MAX_BITS - used;
+ lbits |= (vp8l_atype_t)bits << used;
+ used = VP8L_WRITER_MAX_BITS;
+ n_bits -= shift;
+ bits >>= shift;
+ assert(n_bits <= VP8L_WRITER_MAX_BITS);
+ }
+#endif
+ // If needed, make some room by flushing some bits out.
+ while (used >= VP8L_WRITER_BITS) {
+ if (bw->cur_ + VP8L_WRITER_BYTES > bw->end_) {
+ const uint64_t extra_size = (bw->end_ - bw->buf_) + MIN_EXTRA_SIZE;
+ if (extra_size != (size_t)extra_size ||
+ !VP8LBitWriterResize(bw, (size_t)extra_size)) {
+ bw->cur_ = bw->buf_;
+ bw->error_ = 1;
+ return;
+ }
}
+ *(vp8l_wtype_t*)bw->cur_ = (vp8l_wtype_t)WSWAP((vp8l_wtype_t)lbits);
+ bw->cur_ += VP8L_WRITER_BYTES;
+ lbits >>= VP8L_WRITER_BITS;
+ used -= VP8L_WRITER_BITS;
}
- assert(n_bits <= 25);
- *p = bits;
- bw->bit_pos_ += n_bits;
+ bw->bits_ = lbits | ((vp8l_atype_t)bits << used);
+ bw->used_ = used + n_bits;
}
-#endif
- if ((bw->bit_pos_ >> 3) > (bw->max_bytes_ - 8)) {
- const uint64_t extra_size = 32768ULL + bw->max_bytes_;
- if (extra_size != (size_t)extra_size ||
- !VP8LBitWriterResize(bw, (size_t)extra_size)) {
- bw->bit_pos_ = 0;
- bw->error_ = 1;
+}
+
+uint8_t* VP8LBitWriterFinish(VP8LBitWriter* const bw) {
+ // flush leftover bits
+ if (VP8LBitWriterResize(bw, (bw->used_ + 7) >> 3)) {
+ while (bw->used_ > 0) {
+ *bw->cur_++ = (uint8_t)bw->bits_;
+ bw->bits_ >>= 8;
+ bw->used_ -= 8;
}
+ bw->used_ = 0;
}
+ return bw->buf_;
}
//------------------------------------------------------------------------------
-
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/utils/bit_writer.h b/drivers/webp/utils/bit_writer.h
index 57f39b11b1..867a5ee055 100644
--- a/drivers/webp/utils/bit_writer.h
+++ b/drivers/webp/utils/bit_writer.h
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Bit writing and boolean coder
@@ -12,9 +14,9 @@
#ifndef WEBP_UTILS_BIT_WRITER_H_
#define WEBP_UTILS_BIT_WRITER_H_
-#include "../types.h"
+#include "webp/types.h"
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
extern "C" {
#endif
@@ -43,8 +45,8 @@ void VP8BitWriterWipeOut(VP8BitWriter* const bw);
int VP8PutBit(VP8BitWriter* const bw, int bit, int prob);
int VP8PutBitUniform(VP8BitWriter* const bw, int bit);
-void VP8PutValue(VP8BitWriter* const bw, int value, int nb_bits);
-void VP8PutSignedValue(VP8BitWriter* const bw, int value, int nb_bits);
+void VP8PutBits(VP8BitWriter* const bw, uint32_t value, int nb_bits);
+void VP8PutSignedBits(VP8BitWriter* const bw, int value, int nb_bits);
// Appends some bytes to the internal buffer. Data is copied.
int VP8BitWriterAppend(VP8BitWriter* const bw,
@@ -66,57 +68,77 @@ static WEBP_INLINE size_t VP8BitWriterSize(const VP8BitWriter* const bw) {
//------------------------------------------------------------------------------
// VP8LBitWriter
-// TODO(vikasa): VP8LBitWriter is copied as-is from lossless code. There's scope
-// of re-using VP8BitWriter. Will evaluate once basic lossless encoder is
-// implemented.
-typedef struct {
- uint8_t* buf_;
- size_t bit_pos_;
- size_t max_bytes_;
+#if defined(__x86_64__) || defined(_M_X64) // 64bit
+typedef uint64_t vp8l_atype_t; // accumulator type
+typedef uint32_t vp8l_wtype_t; // writing type
+#define WSWAP HToLE32
+#define VP8L_WRITER_BYTES 4 // sizeof(vp8l_wtype_t)
+#define VP8L_WRITER_BITS 32 // 8 * sizeof(vp8l_wtype_t)
+#define VP8L_WRITER_MAX_BITS 64 // 8 * sizeof(vp8l_atype_t)
+#else
+typedef uint32_t vp8l_atype_t;
+typedef uint16_t vp8l_wtype_t;
+#define WSWAP HToLE16
+#define VP8L_WRITER_BYTES 2
+#define VP8L_WRITER_BITS 16
+#define VP8L_WRITER_MAX_BITS 32
+#endif
- // After all bits are written, the caller must observe the state of
- // error_. A value of 1 indicates that a memory allocation failure
- // has happened during bit writing. A value of 0 indicates successful
+typedef struct {
+ vp8l_atype_t bits_; // bit accumulator
+ int used_; // number of bits used in accumulator
+ uint8_t* buf_; // start of buffer
+ uint8_t* cur_; // current write position
+ uint8_t* end_; // end of buffer
+
+ // After all bits are written (VP8LBitWriterFinish()), the caller must observe
+ // the state of error_. A value of 1 indicates that a memory allocation
+ // failure has happened during bit writing. A value of 0 indicates successful
// writing of bits.
int error_;
} VP8LBitWriter;
static WEBP_INLINE size_t VP8LBitWriterNumBytes(VP8LBitWriter* const bw) {
- return (bw->bit_pos_ + 7) >> 3;
-}
-
-static WEBP_INLINE uint8_t* VP8LBitWriterFinish(VP8LBitWriter* const bw) {
- return bw->buf_;
+ return (bw->cur_ - bw->buf_) + ((bw->used_ + 7) >> 3);
}
-// Returns 0 in case of memory allocation error.
+// Returns false in case of memory allocation error.
int VP8LBitWriterInit(VP8LBitWriter* const bw, size_t expected_size);
+// Finalize the bitstream coding. Returns a pointer to the internal buffer.
+uint8_t* VP8LBitWriterFinish(VP8LBitWriter* const bw);
+// Release any pending memory and zeroes the object.
+void VP8LBitWriterWipeOut(VP8LBitWriter* const bw);
-void VP8LBitWriterDestroy(VP8LBitWriter* const bw);
+// Internal function for VP8LPutBits flushing 32 bits from the written state.
+void VP8LPutBitsFlushBits(VP8LBitWriter* const bw);
-// This function writes bits into bytes in increasing addresses, and within
-// a byte least-significant-bit first.
-//
-// The function can write up to 16 bits in one go with WriteBits
-// Example: let's assume that 3 bits (Rs below) have been written already:
-//
-// BYTE-0 BYTE+1 BYTE+2
-//
-// 0000 0RRR 0000 0000 0000 0000
-//
-// Now, we could write 5 or less bits in MSB by just sifting by 3
-// and OR'ing to BYTE-0.
-//
-// For n bits, we take the last 5 bytes, OR that with high bits in BYTE-0,
-// and locate the rest in BYTE+1 and BYTE+2.
-//
+// PutBits internal function used in the 16 bit vp8l_wtype_t case.
+void VP8LPutBitsInternal(VP8LBitWriter* const bw, uint32_t bits, int n_bits);
+
+// This function writes bits into bytes in increasing addresses (little endian),
+// and within a byte least-significant-bit first.
+// This function can write up to 32 bits in one go, but VP8LBitReader can only
+// read 24 bits max (VP8L_MAX_NUM_BIT_READ).
// VP8LBitWriter's error_ flag is set in case of memory allocation error.
-void VP8LWriteBits(VP8LBitWriter* const bw, int n_bits, uint32_t bits);
+static WEBP_INLINE void VP8LPutBits(VP8LBitWriter* const bw,
+ uint32_t bits, int n_bits) {
+ if (sizeof(vp8l_wtype_t) == 4) {
+ if (n_bits > 0) {
+ if (bw->used_ >= 32) {
+ VP8LPutBitsFlushBits(bw);
+ }
+ bw->bits_ |= (vp8l_atype_t)bits << bw->used_;
+ bw->used_ += n_bits;
+ }
+ } else {
+ VP8LPutBitsInternal(bw, bits, n_bits);
+ }
+}
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/drivers/webp/utils/color_cache.c b/drivers/webp/utils/color_cache.c
index 560f81db10..f9ff4b5451 100644
--- a/drivers/webp/utils/color_cache.c
+++ b/drivers/webp/utils/color_cache.c
@@ -1,8 +1,10 @@
// Copyright 2012 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Color Cache for WebP Lossless
@@ -11,13 +13,10 @@
#include <assert.h>
#include <stdlib.h>
+#include <string.h>
#include "./color_cache.h"
#include "../utils/utils.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
//------------------------------------------------------------------------------
// VP8LColorCache.
@@ -29,16 +28,22 @@ int VP8LColorCacheInit(VP8LColorCache* const cc, int hash_bits) {
sizeof(*cc->colors_));
if (cc->colors_ == NULL) return 0;
cc->hash_shift_ = 32 - hash_bits;
+ cc->hash_bits_ = hash_bits;
return 1;
}
void VP8LColorCacheClear(VP8LColorCache* const cc) {
if (cc != NULL) {
- free(cc->colors_);
+ WebPSafeFree(cc->colors_);
cc->colors_ = NULL;
}
}
-#if defined(__cplusplus) || defined(c_plusplus)
+void VP8LColorCacheCopy(const VP8LColorCache* const src,
+ VP8LColorCache* const dst) {
+ assert(src != NULL);
+ assert(dst != NULL);
+ assert(src->hash_bits_ == dst->hash_bits_);
+ memcpy(dst->colors_, src->colors_,
+ ((size_t)1u << dst->hash_bits_) * sizeof(*dst->colors_));
}
-#endif
diff --git a/drivers/webp/utils/color_cache.h b/drivers/webp/utils/color_cache.h
index da5e260195..34299e4c4e 100644
--- a/drivers/webp/utils/color_cache.h
+++ b/drivers/webp/utils/color_cache.h
@@ -1,8 +1,10 @@
// Copyright 2012 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Color Cache for WebP Lossless
@@ -13,26 +15,33 @@
#ifndef WEBP_UTILS_COLOR_CACHE_H_
#define WEBP_UTILS_COLOR_CACHE_H_
-#include "../types.h"
+#include "webp/types.h"
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
extern "C" {
#endif
// Main color cache struct.
typedef struct {
uint32_t *colors_; // color entries
- int hash_shift_; // Hash shift: 32 - hash_bits.
+ int hash_shift_; // Hash shift: 32 - hash_bits_.
+ int hash_bits_;
} VP8LColorCache;
static const uint32_t kHashMul = 0x1e35a7bd;
static WEBP_INLINE uint32_t VP8LColorCacheLookup(
const VP8LColorCache* const cc, uint32_t key) {
- assert(key <= (~0U >> cc->hash_shift_));
+ assert((key >> cc->hash_bits_) == 0u);
return cc->colors_[key];
}
+static WEBP_INLINE void VP8LColorCacheSet(const VP8LColorCache* const cc,
+ uint32_t key, uint32_t argb) {
+ assert((key >> cc->hash_bits_) == 0u);
+ cc->colors_[key] = argb;
+}
+
static WEBP_INLINE void VP8LColorCacheInsert(const VP8LColorCache* const cc,
uint32_t argb) {
const uint32_t key = (kHashMul * argb) >> cc->hash_shift_;
@@ -47,7 +56,7 @@ static WEBP_INLINE int VP8LColorCacheGetIndex(const VP8LColorCache* const cc,
static WEBP_INLINE int VP8LColorCacheContains(const VP8LColorCache* const cc,
uint32_t argb) {
const uint32_t key = (kHashMul * argb) >> cc->hash_shift_;
- return cc->colors_[key] == argb;
+ return (cc->colors_[key] == argb);
}
//------------------------------------------------------------------------------
@@ -56,12 +65,15 @@ static WEBP_INLINE int VP8LColorCacheContains(const VP8LColorCache* const cc,
// Returns false in case of memory error.
int VP8LColorCacheInit(VP8LColorCache* const color_cache, int hash_bits);
+void VP8LColorCacheCopy(const VP8LColorCache* const src,
+ VP8LColorCache* const dst);
+
// Delete the memory associated to color cache.
void VP8LColorCacheClear(VP8LColorCache* const color_cache);
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
}
#endif
diff --git a/drivers/webp/utils/endian_inl.h b/drivers/webp/utils/endian_inl.h
new file mode 100644
index 0000000000..253b7be8ee
--- /dev/null
+++ b/drivers/webp/utils/endian_inl.h
@@ -0,0 +1,100 @@
+// Copyright 2014 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Endian related functions.
+
+#ifndef WEBP_UTILS_ENDIAN_INL_H_
+#define WEBP_UTILS_ENDIAN_INL_H_
+
+#ifdef HAVE_CONFIG_H
+#include "webp/config.h"
+#endif
+
+#include "../dsp/dsp.h"
+#include "webp/types.h"
+
+// some endian fix (e.g.: mips-gcc doesn't define __BIG_ENDIAN__)
+#if !defined(WORDS_BIGENDIAN) && \
+ (defined(__BIG_ENDIAN__) || defined(_M_PPC) || \
+ (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)))
+#define WORDS_BIGENDIAN
+#endif
+
+#if defined(WORDS_BIGENDIAN)
+#define HToLE32 BSwap32
+#define HToLE16 BSwap16
+#else
+#define HToLE32(x) (x)
+#define HToLE16(x) (x)
+#endif
+
+#if !defined(HAVE_CONFIG_H)
+#if LOCAL_GCC_PREREQ(4,8) || __has_builtin(__builtin_bswap16)
+#define HAVE_BUILTIN_BSWAP16
+#endif
+#if LOCAL_GCC_PREREQ(4,3) || __has_builtin(__builtin_bswap32)
+#define HAVE_BUILTIN_BSWAP32
+#endif
+#if LOCAL_GCC_PREREQ(4,3) || __has_builtin(__builtin_bswap64)
+#define HAVE_BUILTIN_BSWAP64
+#endif
+#endif // !HAVE_CONFIG_H
+
+static WEBP_INLINE uint16_t BSwap16(uint16_t x) {
+#if defined(HAVE_BUILTIN_BSWAP16)
+ return __builtin_bswap16(x);
+#elif defined(_MSC_VER)
+ return _byteswap_ushort(x);
+#else
+ // gcc will recognize a 'rorw $8, ...' here:
+ return (x >> 8) | ((x & 0xff) << 8);
+#endif // HAVE_BUILTIN_BSWAP16
+}
+
+static WEBP_INLINE uint32_t BSwap32(uint32_t x) {
+#if defined(WEBP_USE_MIPS32_R2)
+ uint32_t ret;
+ __asm__ volatile (
+ "wsbh %[ret], %[x] \n\t"
+ "rotr %[ret], %[ret], 16 \n\t"
+ : [ret]"=r"(ret)
+ : [x]"r"(x)
+ );
+ return ret;
+#elif defined(HAVE_BUILTIN_BSWAP32)
+ return __builtin_bswap32(x);
+#elif defined(__i386__) || defined(__x86_64__)
+ uint32_t swapped_bytes;
+ __asm__ volatile("bswap %0" : "=r"(swapped_bytes) : "0"(x));
+ return swapped_bytes;
+#elif defined(_MSC_VER)
+ return (uint32_t)_byteswap_ulong(x);
+#else
+ return (x >> 24) | ((x >> 8) & 0xff00) | ((x << 8) & 0xff0000) | (x << 24);
+#endif // HAVE_BUILTIN_BSWAP32
+}
+
+static WEBP_INLINE uint64_t BSwap64(uint64_t x) {
+#if defined(HAVE_BUILTIN_BSWAP64)
+ return __builtin_bswap64(x);
+#elif defined(__x86_64__)
+ uint64_t swapped_bytes;
+ __asm__ volatile("bswapq %0" : "=r"(swapped_bytes) : "0"(x));
+ return swapped_bytes;
+#elif defined(_MSC_VER)
+ return (uint64_t)_byteswap_uint64(x);
+#else // generic code for swapping 64-bit values (suggested by bdb@)
+ x = ((x & 0xffffffff00000000ull) >> 32) | ((x & 0x00000000ffffffffull) << 32);
+ x = ((x & 0xffff0000ffff0000ull) >> 16) | ((x & 0x0000ffff0000ffffull) << 16);
+ x = ((x & 0xff00ff00ff00ff00ull) >> 8) | ((x & 0x00ff00ff00ff00ffull) << 8);
+ return x;
+#endif // HAVE_BUILTIN_BSWAP64
+}
+
+#endif // WEBP_UTILS_ENDIAN_INL_H_
diff --git a/drivers/webp/utils/filters.c b/drivers/webp/utils/filters.c
index 08f52a3d20..15543b1271 100644
--- a/drivers/webp/utils/filters.c
+++ b/drivers/webp/utils/filters.c
@@ -1,171 +1,37 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
-// Spatial prediction using various filters
+// filter estimation
//
// Author: Urvang (urvang@google.com)
#include "./filters.h"
-#include <assert.h>
#include <stdlib.h>
#include <string.h>
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-//------------------------------------------------------------------------------
-// Helpful macro.
-
-# define SANITY_CHECK(in, out) \
- assert(in != NULL); \
- assert(out != NULL); \
- assert(width > 0); \
- assert(height > 0); \
- assert(bpp > 0); \
- assert(stride >= width * bpp);
-
-static WEBP_INLINE void PredictLine(const uint8_t* src, const uint8_t* pred,
- uint8_t* dst, int length, int inverse) {
- int i;
- if (inverse) {
- for (i = 0; i < length; ++i) dst[i] = src[i] + pred[i];
- } else {
- for (i = 0; i < length; ++i) dst[i] = src[i] - pred[i];
- }
-}
-
-//------------------------------------------------------------------------------
-// Horizontal filter.
-
-static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in,
- int width, int height, int bpp, int stride, int inverse, uint8_t* out) {
- int h;
- const uint8_t* preds = (inverse ? out : in);
- SANITY_CHECK(in, out);
-
- // Filter line-by-line.
- for (h = 0; h < height; ++h) {
- // Leftmost pixel is predicted from above (except for topmost scanline).
- if (h == 0) {
- memcpy((void*)out, (const void*)in, bpp);
- } else {
- PredictLine(in, preds - stride, out, bpp, inverse);
- }
- PredictLine(in + bpp, preds, out + bpp, bpp * (width - 1), inverse);
- preds += stride;
- in += stride;
- out += stride;
- }
-}
-
-static void HorizontalFilter(const uint8_t* data, int width, int height,
- int bpp, int stride, uint8_t* filtered_data) {
- DoHorizontalFilter(data, width, height, bpp, stride, 0, filtered_data);
-}
-
-static void HorizontalUnfilter(const uint8_t* data, int width, int height,
- int bpp, int stride, uint8_t* recon_data) {
- DoHorizontalFilter(data, width, height, bpp, stride, 1, recon_data);
-}
-
-//------------------------------------------------------------------------------
-// Vertical filter.
-
-static WEBP_INLINE void DoVerticalFilter(const uint8_t* in,
- int width, int height, int bpp, int stride, int inverse, uint8_t* out) {
- int h;
- const uint8_t* preds = (inverse ? out : in);
- SANITY_CHECK(in, out);
-
- // Very first top-left pixel is copied.
- memcpy((void*)out, (const void*)in, bpp);
- // Rest of top scan-line is left-predicted.
- PredictLine(in + bpp, preds, out + bpp, bpp * (width - 1), inverse);
-
- // Filter line-by-line.
- for (h = 1; h < height; ++h) {
- in += stride;
- out += stride;
- PredictLine(in, preds, out, bpp * width, inverse);
- preds += stride;
- }
-}
-
-static void VerticalFilter(const uint8_t* data, int width, int height,
- int bpp, int stride, uint8_t* filtered_data) {
- DoVerticalFilter(data, width, height, bpp, stride, 0, filtered_data);
-}
-
-static void VerticalUnfilter(const uint8_t* data, int width, int height,
- int bpp, int stride, uint8_t* recon_data) {
- DoVerticalFilter(data, width, height, bpp, stride, 1, recon_data);
-}
+// -----------------------------------------------------------------------------
+// Quick estimate of a potentially interesting filter mode to try.
-//------------------------------------------------------------------------------
-// Gradient filter.
+#define SMAX 16
+#define SDIFF(a, b) (abs((a) - (b)) >> 4) // Scoring diff, in [0..SMAX)
static WEBP_INLINE int GradientPredictor(uint8_t a, uint8_t b, uint8_t c) {
const int g = a + b - c;
- return (g < 0) ? 0 : (g > 255) ? 255 : g;
-}
-
-static WEBP_INLINE
-void DoGradientFilter(const uint8_t* in, int width, int height,
- int bpp, int stride, int inverse, uint8_t* out) {
- const uint8_t* preds = (inverse ? out : in);
- int h;
- SANITY_CHECK(in, out);
-
- // left prediction for top scan-line
- memcpy((void*)out, (const void*)in, bpp);
- PredictLine(in + bpp, preds, out + bpp, bpp * (width - 1), inverse);
-
- // Filter line-by-line.
- for (h = 1; h < height; ++h) {
- int w;
- preds += stride;
- in += stride;
- out += stride;
- // leftmost pixel: predict from above.
- PredictLine(in, preds - stride, out, bpp, inverse);
- for (w = bpp; w < width * bpp; ++w) {
- const int pred = GradientPredictor(preds[w - bpp],
- preds[w - stride],
- preds[w - stride - bpp]);
- out[w] = in[w] + (inverse ? pred : -pred);
- }
- }
+ return ((g & ~0xff) == 0) ? g : (g < 0) ? 0 : 255; // clip to 8bit
}
-static void GradientFilter(const uint8_t* data, int width, int height,
- int bpp, int stride, uint8_t* filtered_data) {
- DoGradientFilter(data, width, height, bpp, stride, 0, filtered_data);
-}
-
-static void GradientUnfilter(const uint8_t* data, int width, int height,
- int bpp, int stride, uint8_t* recon_data) {
- DoGradientFilter(data, width, height, bpp, stride, 1, recon_data);
-}
-
-#undef SANITY_CHECK
-
-// -----------------------------------------------------------------------------
-// Quick estimate of a potentially interesting filter mode to try, in addition
-// to the default NONE.
-
-#define SMAX 16
-#define SDIFF(a, b) (abs((a) - (b)) >> 4) // Scoring diff, in [0..SMAX)
-
-WEBP_FILTER_TYPE EstimateBestFilter(const uint8_t* data,
- int width, int height, int stride) {
+WEBP_FILTER_TYPE WebPEstimateBestFilter(const uint8_t* data,
+ int width, int height, int stride) {
int i, j;
int bins[WEBP_FILTER_LAST][SMAX];
memset(bins, 0, sizeof(bins));
+
// We only sample every other pixels. That's enough.
for (j = 2; j < height - 1; j += 2) {
const uint8_t* const p = data + j * stride;
@@ -185,7 +51,8 @@ WEBP_FILTER_TYPE EstimateBestFilter(const uint8_t* data,
}
}
{
- WEBP_FILTER_TYPE filter, best_filter = WEBP_FILTER_NONE;
+ int filter;
+ WEBP_FILTER_TYPE best_filter = WEBP_FILTER_NONE;
int best_score = 0x7fffffff;
for (filter = WEBP_FILTER_NONE; filter < WEBP_FILTER_LAST; ++filter) {
int score = 0;
@@ -196,7 +63,7 @@ WEBP_FILTER_TYPE EstimateBestFilter(const uint8_t* data,
}
if (score < best_score) {
best_score = score;
- best_filter = filter;
+ best_filter = (WEBP_FILTER_TYPE)filter;
}
}
return best_filter;
@@ -207,23 +74,3 @@ WEBP_FILTER_TYPE EstimateBestFilter(const uint8_t* data,
#undef SDIFF
//------------------------------------------------------------------------------
-
-const WebPFilterFunc WebPFilters[WEBP_FILTER_LAST] = {
- NULL, // WEBP_FILTER_NONE
- HorizontalFilter, // WEBP_FILTER_HORIZONTAL
- VerticalFilter, // WEBP_FILTER_VERTICAL
- GradientFilter // WEBP_FILTER_GRADIENT
-};
-
-const WebPFilterFunc WebPUnfilters[WEBP_FILTER_LAST] = {
- NULL, // WEBP_FILTER_NONE
- HorizontalUnfilter, // WEBP_FILTER_HORIZONTAL
- VerticalUnfilter, // WEBP_FILTER_VERTICAL
- GradientUnfilter // WEBP_FILTER_GRADIENT
-};
-
-//------------------------------------------------------------------------------
-
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/utils/filters.h b/drivers/webp/utils/filters.h
index db886be29a..4aba3fd3b7 100644
--- a/drivers/webp/utils/filters.h
+++ b/drivers/webp/utils/filters.h
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Spatial prediction using various filters
@@ -12,42 +14,18 @@
#ifndef WEBP_UTILS_FILTERS_H_
#define WEBP_UTILS_FILTERS_H_
-#include "../types.h"
+#include "webp/types.h"
+#include "../dsp/dsp.h"
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
extern "C" {
#endif
-// Filters.
-typedef enum {
- WEBP_FILTER_NONE = 0,
- WEBP_FILTER_HORIZONTAL,
- WEBP_FILTER_VERTICAL,
- WEBP_FILTER_GRADIENT,
- WEBP_FILTER_LAST = WEBP_FILTER_GRADIENT + 1, // end marker
- WEBP_FILTER_BEST,
- WEBP_FILTER_FAST
-} WEBP_FILTER_TYPE;
-
-typedef void (*WebPFilterFunc)(const uint8_t* in, int width, int height,
- int bpp, int stride, uint8_t* out);
-
-// Filter the given data using the given predictor.
-// 'in' corresponds to a 2-dimensional pixel array of size (stride * height)
-// in raster order.
-// 'bpp' is number of bytes per pixel, and
-// 'stride' is number of bytes per scan line (with possible padding).
-// 'out' should be pre-allocated.
-extern const WebPFilterFunc WebPFilters[WEBP_FILTER_LAST];
-
-// Reconstruct the original data from the given filtered data.
-extern const WebPFilterFunc WebPUnfilters[WEBP_FILTER_LAST];
-
// Fast estimate of a potentially good filter.
-extern WEBP_FILTER_TYPE EstimateBestFilter(const uint8_t* data,
- int width, int height, int stride);
+WEBP_FILTER_TYPE WebPEstimateBestFilter(const uint8_t* data,
+ int width, int height, int stride);
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/drivers/webp/utils/huffman.c b/drivers/webp/utils/huffman.c
index 1cc1cfd355..e6f482a6a8 100644
--- a/drivers/webp/utils/huffman.c
+++ b/drivers/webp/utils/huffman.c
@@ -1,8 +1,10 @@
// Copyright 2012 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Utilities for building and looking up Huffman trees.
@@ -11,228 +13,193 @@
#include <assert.h>
#include <stdlib.h>
+#include <string.h>
#include "./huffman.h"
#include "../utils/utils.h"
-#include "../format_constants.h"
+#include "webp/format_constants.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
+// Huffman data read via DecodeImageStream is represented in two (red and green)
+// bytes.
+#define MAX_HTREE_GROUPS 0x10000
-#define NON_EXISTENT_SYMBOL (-1)
-
-static void TreeNodeInit(HuffmanTreeNode* const node) {
- node->children_ = -1; // means: 'unassigned so far'
-}
-
-static int NodeIsEmpty(const HuffmanTreeNode* const node) {
- return (node->children_ < 0);
+HTreeGroup* VP8LHtreeGroupsNew(int num_htree_groups) {
+ HTreeGroup* const htree_groups =
+ (HTreeGroup*)WebPSafeMalloc(num_htree_groups, sizeof(*htree_groups));
+ if (htree_groups == NULL) {
+ return NULL;
+ }
+ assert(num_htree_groups <= MAX_HTREE_GROUPS);
+ return htree_groups;
}
-static int IsFull(const HuffmanTree* const tree) {
- return (tree->num_nodes_ == tree->max_nodes_);
+void VP8LHtreeGroupsFree(HTreeGroup* const htree_groups) {
+ if (htree_groups != NULL) {
+ WebPSafeFree(htree_groups);
+ }
}
-static void AssignChildren(HuffmanTree* const tree,
- HuffmanTreeNode* const node) {
- HuffmanTreeNode* const children = tree->root_ + tree->num_nodes_;
- node->children_ = (int)(children - node);
- assert(children - node == (int)(children - node));
- tree->num_nodes_ += 2;
- TreeNodeInit(children + 0);
- TreeNodeInit(children + 1);
+// Returns reverse(reverse(key, len) + 1, len), where reverse(key, len) is the
+// bit-wise reversal of the len least significant bits of key.
+static WEBP_INLINE uint32_t GetNextKey(uint32_t key, int len) {
+ uint32_t step = 1 << (len - 1);
+ while (key & step) {
+ step >>= 1;
+ }
+ return (key & (step - 1)) + step;
}
-static int TreeInit(HuffmanTree* const tree, int num_leaves) {
- assert(tree != NULL);
- if (num_leaves == 0) return 0;
- // We allocate maximum possible nodes in the tree at once.
- // Note that a Huffman tree is a full binary tree; and in a full binary tree
- // with L leaves, the total number of nodes N = 2 * L - 1.
- tree->max_nodes_ = 2 * num_leaves - 1;
- tree->root_ = (HuffmanTreeNode*)WebPSafeMalloc((uint64_t)tree->max_nodes_,
- sizeof(*tree->root_));
- if (tree->root_ == NULL) return 0;
- TreeNodeInit(tree->root_); // Initialize root.
- tree->num_nodes_ = 1;
- return 1;
+// Stores code in table[0], table[step], table[2*step], ..., table[end].
+// Assumes that end is an integer multiple of step.
+static WEBP_INLINE void ReplicateValue(HuffmanCode* table,
+ int step, int end,
+ HuffmanCode code) {
+ assert(end % step == 0);
+ do {
+ end -= step;
+ table[end] = code;
+ } while (end > 0);
}
-void HuffmanTreeRelease(HuffmanTree* const tree) {
- if (tree != NULL) {
- free(tree->root_);
- tree->root_ = NULL;
- tree->max_nodes_ = 0;
- tree->num_nodes_ = 0;
+// Returns the table width of the next 2nd level table. count is the histogram
+// of bit lengths for the remaining symbols, len is the code length of the next
+// processed symbol
+static WEBP_INLINE int NextTableBitSize(const int* const count,
+ int len, int root_bits) {
+ int left = 1 << (len - root_bits);
+ while (len < MAX_ALLOWED_CODE_LENGTH) {
+ left -= count[len];
+ if (left <= 0) break;
+ ++len;
+ left <<= 1;
}
+ return len - root_bits;
}
-int HuffmanCodeLengthsToCodes(const int* const code_lengths,
- int code_lengths_size, int* const huff_codes) {
- int symbol;
- int code_len;
- int code_length_hist[MAX_ALLOWED_CODE_LENGTH + 1] = { 0 };
- int curr_code;
- int next_codes[MAX_ALLOWED_CODE_LENGTH + 1] = { 0 };
- int max_code_length = 0;
-
+int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
+ const int code_lengths[], int code_lengths_size) {
+ HuffmanCode* table = root_table; // next available space in table
+ int total_size = 1 << root_bits; // total size root table + 2nd level table
+ int* sorted = NULL; // symbols sorted by code length
+ int len; // current code length
+ int symbol; // symbol index in original or sorted table
+ // number of codes of each length:
+ int count[MAX_ALLOWED_CODE_LENGTH + 1] = { 0 };
+ // offsets in sorted table for each length:
+ int offset[MAX_ALLOWED_CODE_LENGTH + 1];
+
+ assert(code_lengths_size != 0);
assert(code_lengths != NULL);
- assert(code_lengths_size > 0);
- assert(huff_codes != NULL);
+ assert(root_table != NULL);
+ assert(root_bits > 0);
- // Calculate max code length.
+ // Build histogram of code lengths.
for (symbol = 0; symbol < code_lengths_size; ++symbol) {
- if (code_lengths[symbol] > max_code_length) {
- max_code_length = code_lengths[symbol];
+ if (code_lengths[symbol] > MAX_ALLOWED_CODE_LENGTH) {
+ return 0;
}
+ ++count[code_lengths[symbol]];
}
- if (max_code_length > MAX_ALLOWED_CODE_LENGTH) return 0;
- // Calculate code length histogram.
- for (symbol = 0; symbol < code_lengths_size; ++symbol) {
- ++code_length_hist[code_lengths[symbol]];
- }
- code_length_hist[0] = 0;
-
- // Calculate the initial values of 'next_codes' for each code length.
- // next_codes[code_len] denotes the code to be assigned to the next symbol
- // of code length 'code_len'.
- curr_code = 0;
- next_codes[0] = -1; // Unused, as code length = 0 implies code doesn't exist.
- for (code_len = 1; code_len <= max_code_length; ++code_len) {
- curr_code = (curr_code + code_length_hist[code_len - 1]) << 1;
- next_codes[code_len] = curr_code;
+ // Error, all code lengths are zeros.
+ if (count[0] == code_lengths_size) {
+ return 0;
}
- // Get symbols.
- for (symbol = 0; symbol < code_lengths_size; ++symbol) {
- if (code_lengths[symbol] > 0) {
- huff_codes[symbol] = next_codes[code_lengths[symbol]]++;
- } else {
- huff_codes[symbol] = NON_EXISTENT_SYMBOL;
- }
- }
- return 1;
-}
-
-static int TreeAddSymbol(HuffmanTree* const tree,
- int symbol, int code, int code_length) {
- HuffmanTreeNode* node = tree->root_;
- const HuffmanTreeNode* const max_node = tree->root_ + tree->max_nodes_;
- while (code_length-- > 0) {
- if (node >= max_node) {
+ // Generate offsets into sorted symbol table by code length.
+ offset[1] = 0;
+ for (len = 1; len < MAX_ALLOWED_CODE_LENGTH; ++len) {
+ if (count[len] > (1 << len)) {
return 0;
}
- if (NodeIsEmpty(node)) {
- if (IsFull(tree)) return 0; // error: too many symbols.
- AssignChildren(tree, node);
- } else if (HuffmanTreeNodeIsLeaf(node)) {
- return 0; // leaf is already occupied.
- }
- node += node->children_ + ((code >> code_length) & 1);
- }
- if (NodeIsEmpty(node)) {
- node->children_ = 0; // turn newly created node into a leaf.
- } else if (!HuffmanTreeNodeIsLeaf(node)) {
- return 0; // trying to assign a symbol to already used code.
+ offset[len + 1] = offset[len] + count[len];
}
- node->symbol_ = symbol; // Add symbol in this node.
- return 1;
-}
-int HuffmanTreeBuildImplicit(HuffmanTree* const tree,
- const int* const code_lengths,
- int code_lengths_size) {
- int symbol;
- int num_symbols = 0;
- int root_symbol = 0;
-
- assert(tree != NULL);
- assert(code_lengths != NULL);
+ sorted = (int*)WebPSafeMalloc(code_lengths_size, sizeof(*sorted));
+ if (sorted == NULL) {
+ return 0;
+ }
- // Find out number of symbols and the root symbol.
+ // Sort symbols by length, by symbol order within each length.
for (symbol = 0; symbol < code_lengths_size; ++symbol) {
+ const int symbol_code_length = code_lengths[symbol];
if (code_lengths[symbol] > 0) {
- // Note: code length = 0 indicates non-existent symbol.
- ++num_symbols;
- root_symbol = symbol;
+ sorted[offset[symbol_code_length]++] = symbol;
}
}
- // Initialize the tree. Will fail for num_symbols = 0
- if (!TreeInit(tree, num_symbols)) return 0;
-
- // Build tree.
- if (num_symbols == 1) { // Trivial case.
- const int max_symbol = code_lengths_size;
- if (root_symbol < 0 || root_symbol >= max_symbol) {
- HuffmanTreeRelease(tree);
- return 0;
- }
- return TreeAddSymbol(tree, root_symbol, 0, 0);
- } else { // Normal case.
- int ok = 0;
-
- // Get Huffman codes from the code lengths.
- int* const codes =
- (int*)WebPSafeMalloc((uint64_t)code_lengths_size, sizeof(*codes));
- if (codes == NULL) goto End;
+ // Special case code with only one value.
+ if (offset[MAX_ALLOWED_CODE_LENGTH] == 1) {
+ HuffmanCode code;
+ code.bits = 0;
+ code.value = (uint16_t)sorted[0];
+ ReplicateValue(table, 1, total_size, code);
+ WebPSafeFree(sorted);
+ return total_size;
+ }
- if (!HuffmanCodeLengthsToCodes(code_lengths, code_lengths_size, codes)) {
- goto End;
+ {
+ int step; // step size to replicate values in current table
+ uint32_t low = -1; // low bits for current root entry
+ uint32_t mask = total_size - 1; // mask for low bits
+ uint32_t key = 0; // reversed prefix code
+ int num_nodes = 1; // number of Huffman tree nodes
+ int num_open = 1; // number of open branches in current tree level
+ int table_bits = root_bits; // key length of current table
+ int table_size = 1 << table_bits; // size of current table
+ symbol = 0;
+ // Fill in root table.
+ for (len = 1, step = 2; len <= root_bits; ++len, step <<= 1) {
+ num_open <<= 1;
+ num_nodes += num_open;
+ num_open -= count[len];
+ if (num_open < 0) {
+ WebPSafeFree(sorted);
+ return 0;
+ }
+ for (; count[len] > 0; --count[len]) {
+ HuffmanCode code;
+ code.bits = (uint8_t)len;
+ code.value = (uint16_t)sorted[symbol++];
+ ReplicateValue(&table[key], step, table_size, code);
+ key = GetNextKey(key, len);
+ }
}
- // Add symbols one-by-one.
- for (symbol = 0; symbol < code_lengths_size; ++symbol) {
- if (code_lengths[symbol] > 0) {
- if (!TreeAddSymbol(tree, symbol, codes[symbol], code_lengths[symbol])) {
- goto End;
+ // Fill in 2nd level tables and add pointers to root table.
+ for (len = root_bits + 1, step = 2; len <= MAX_ALLOWED_CODE_LENGTH;
+ ++len, step <<= 1) {
+ num_open <<= 1;
+ num_nodes += num_open;
+ num_open -= count[len];
+ if (num_open < 0) {
+ WebPSafeFree(sorted);
+ return 0;
+ }
+ for (; count[len] > 0; --count[len]) {
+ HuffmanCode code;
+ if ((key & mask) != low) {
+ table += table_size;
+ table_bits = NextTableBitSize(count, len, root_bits);
+ table_size = 1 << table_bits;
+ total_size += table_size;
+ low = key & mask;
+ root_table[low].bits = (uint8_t)(table_bits + root_bits);
+ root_table[low].value = (uint16_t)((table - root_table) - low);
}
+ code.bits = (uint8_t)(len - root_bits);
+ code.value = (uint16_t)sorted[symbol++];
+ ReplicateValue(&table[key >> root_bits], step, table_size, code);
+ key = GetNextKey(key, len);
}
}
- ok = 1;
- End:
- free(codes);
- ok = ok && IsFull(tree);
- if (!ok) HuffmanTreeRelease(tree);
- return ok;
- }
-}
-
-int HuffmanTreeBuildExplicit(HuffmanTree* const tree,
- const int* const code_lengths,
- const int* const codes,
- const int* const symbols, int max_symbol,
- int num_symbols) {
- int ok = 0;
- int i;
-
- assert(tree != NULL);
- assert(code_lengths != NULL);
- assert(codes != NULL);
- assert(symbols != NULL);
-
- // Initialize the tree. Will fail if num_symbols = 0.
- if (!TreeInit(tree, num_symbols)) return 0;
- // Add symbols one-by-one.
- for (i = 0; i < num_symbols; ++i) {
- if (codes[i] != NON_EXISTENT_SYMBOL) {
- if (symbols[i] < 0 || symbols[i] >= max_symbol) {
- goto End;
- }
- if (!TreeAddSymbol(tree, symbols[i], codes[i], code_lengths[i])) {
- goto End;
- }
+ // Check if tree is full.
+ if (num_nodes != 2 * offset[MAX_ALLOWED_CODE_LENGTH] - 1) {
+ WebPSafeFree(sorted);
+ return 0;
}
}
- ok = 1;
- End:
- ok = ok && IsFull(tree);
- if (!ok) HuffmanTreeRelease(tree);
- return ok;
-}
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
+ WebPSafeFree(sorted);
+ return total_size;
+}
diff --git a/drivers/webp/utils/huffman.h b/drivers/webp/utils/huffman.h
index f16447e649..a8cc0da1c3 100644
--- a/drivers/webp/utils/huffman.h
+++ b/drivers/webp/utils/huffman.h
@@ -1,8 +1,10 @@
// Copyright 2012 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Utilities for building and looking up Huffman trees.
@@ -13,65 +15,73 @@
#define WEBP_UTILS_HUFFMAN_H_
#include <assert.h>
-#include "../types.h"
+#include "webp/format_constants.h"
+#include "webp/types.h"
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
extern "C" {
#endif
-// A node of a Huffman tree.
-typedef struct {
- int symbol_;
- int children_; // delta offset to both children (contiguous) or 0 if leaf.
-} HuffmanTreeNode;
+#define HUFFMAN_TABLE_BITS 8
+#define HUFFMAN_TABLE_MASK ((1 << HUFFMAN_TABLE_BITS) - 1)
+
+#define LENGTHS_TABLE_BITS 7
+#define LENGTHS_TABLE_MASK ((1 << LENGTHS_TABLE_BITS) - 1)
-// Huffman Tree.
-typedef struct HuffmanTree HuffmanTree;
-struct HuffmanTree {
- HuffmanTreeNode* root_; // all the nodes, starting at root.
- int max_nodes_; // max number of nodes
- int num_nodes_; // number of currently occupied nodes
-};
-// Returns true if the given node is a leaf of the Huffman tree.
-static WEBP_INLINE int HuffmanTreeNodeIsLeaf(
- const HuffmanTreeNode* const node) {
- return (node->children_ == 0);
-}
+// Huffman lookup table entry
+typedef struct {
+ uint8_t bits; // number of bits used for this symbol
+ uint16_t value; // symbol value or table offset
+} HuffmanCode;
-// Go down one level. Most critical function. 'right_child' must be 0 or 1.
-static WEBP_INLINE const HuffmanTreeNode* HuffmanTreeNextNode(
- const HuffmanTreeNode* node, int right_child) {
- return node + node->children_ + right_child;
-}
+// long version for holding 32b values
+typedef struct {
+ int bits; // number of bits used for this symbol,
+ // or an impossible value if not a literal code.
+ uint32_t value; // 32b packed ARGB value if literal,
+ // or non-literal symbol otherwise
+} HuffmanCode32;
-// Releases the nodes of the Huffman tree.
-// Note: It does NOT free 'tree' itself.
-void HuffmanTreeRelease(HuffmanTree* const tree);
+#define HUFFMAN_PACKED_BITS 6
+#define HUFFMAN_PACKED_TABLE_SIZE (1u << HUFFMAN_PACKED_BITS)
-// Builds Huffman tree assuming code lengths are implicitly in symbol order.
-// Returns false in case of error (invalid tree or memory error).
-int HuffmanTreeBuildImplicit(HuffmanTree* const tree,
- const int* const code_lengths,
- int code_lengths_size);
+// Huffman table group.
+// Includes special handling for the following cases:
+// - is_trivial_literal: one common literal base for RED/BLUE/ALPHA (not GREEN)
+// - is_trivial_code: only 1 code (no bit is read from bitstream)
+// - use_packed_table: few enough literal symbols, so all the bit codes
+// can fit into a small look-up table packed_table[]
+// The common literal base, if applicable, is stored in 'literal_arb'.
+typedef struct HTreeGroup HTreeGroup;
+struct HTreeGroup {
+ HuffmanCode* htrees[HUFFMAN_CODES_PER_META_CODE];
+ int is_trivial_literal; // True, if huffman trees for Red, Blue & Alpha
+ // Symbols are trivial (have a single code).
+ uint32_t literal_arb; // If is_trivial_literal is true, this is the
+ // ARGB value of the pixel, with Green channel
+ // being set to zero.
+ int is_trivial_code; // true if is_trivial_literal with only one code
+ int use_packed_table; // use packed table below for short literal code
+ // table mapping input bits to a packed values, or escape case to literal code
+ HuffmanCode32 packed_table[HUFFMAN_PACKED_TABLE_SIZE];
+};
-// Build a Huffman tree with explicitly given lists of code lengths, codes
-// and symbols. Verifies that all symbols added are smaller than max_symbol.
-// Returns false in case of an invalid symbol, invalid tree or memory error.
-int HuffmanTreeBuildExplicit(HuffmanTree* const tree,
- const int* const code_lengths,
- const int* const codes,
- const int* const symbols, int max_symbol,
- int num_symbols);
+// Creates the instance of HTreeGroup with specified number of tree-groups.
+HTreeGroup* VP8LHtreeGroupsNew(int num_htree_groups);
-// Utility: converts Huffman code lengths to corresponding Huffman codes.
-// 'huff_codes' should be pre-allocated.
-// Returns false in case of error (memory allocation, invalid codes).
-int HuffmanCodeLengthsToCodes(const int* const code_lengths,
- int code_lengths_size, int* const huff_codes);
+// Releases the memory allocated for HTreeGroup.
+void VP8LHtreeGroupsFree(HTreeGroup* const htree_groups);
+// Builds Huffman lookup table assuming code lengths are in symbol order.
+// The 'code_lengths' is pre-allocated temporary memory buffer used for creating
+// the huffman table.
+// Returns built table size or 0 in case of error (invalid tree or
+// memory error).
+int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
+ const int code_lengths[], int code_lengths_size);
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/drivers/webp/utils/huffman_encode.c b/drivers/webp/utils/huffman_encode.c
index e172b10a85..d7aad6f56d 100644
--- a/drivers/webp/utils/huffman_encode.c
+++ b/drivers/webp/utils/huffman_encode.c
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Author: Jyrki Alakuijala (jyrki@google.com)
@@ -14,7 +16,7 @@
#include <string.h>
#include "./huffman_encode.h"
#include "../utils/utils.h"
-#include "../format_constants.h"
+#include "webp/format_constants.h"
// -----------------------------------------------------------------------------
// Util function to optimize the symbol map for RLE coding
@@ -25,14 +27,14 @@ static int ValuesShouldBeCollapsedToStrideAverage(int a, int b) {
}
// Change the population counts in a way that the consequent
-// Hufmann tree compression, especially its RLE-part, give smaller output.
-static int OptimizeHuffmanForRle(int length, int* const counts) {
- uint8_t* good_for_rle;
+// Huffman tree compression, especially its RLE-part, give smaller output.
+static void OptimizeHuffmanForRle(int length, uint8_t* const good_for_rle,
+ uint32_t* const counts) {
// 1) Let's make the Huffman code more compatible with rle encoding.
int i;
for (; length >= 0; --length) {
if (length == 0) {
- return 1; // All zeros.
+ return; // All zeros.
}
if (counts[length - 1] != 0) {
// Now counts[0..length - 1] does not have trailing zeros.
@@ -41,15 +43,11 @@ static int OptimizeHuffmanForRle(int length, int* const counts) {
}
// 2) Let's mark all population counts that already can be encoded
// with an rle code.
- good_for_rle = (uint8_t*)calloc(length, 1);
- if (good_for_rle == NULL) {
- return 0;
- }
{
// Let's not spoil any of the existing good rle codes.
// Mark any seq of 0's that is longer as 5 as a good_for_rle.
// Mark any seq of non-0's that is longer as 7 as a good_for_rle.
- int symbol = counts[0];
+ uint32_t symbol = counts[0];
int stride = 0;
for (i = 0; i < length + 1; ++i) {
if (i == length || counts[i] != symbol) {
@@ -71,17 +69,17 @@ static int OptimizeHuffmanForRle(int length, int* const counts) {
}
// 3) Let's replace those population counts that lead to more rle codes.
{
- int stride = 0;
- int limit = counts[0];
- int sum = 0;
+ uint32_t stride = 0;
+ uint32_t limit = counts[0];
+ uint32_t sum = 0;
for (i = 0; i < length + 1; ++i) {
if (i == length || good_for_rle[i] ||
(i != 0 && good_for_rle[i - 1]) ||
!ValuesShouldBeCollapsedToStrideAverage(counts[i], limit)) {
if (stride >= 4 || (stride >= 3 && sum == 0)) {
- int k;
+ uint32_t k;
// The stride must end, collapse what we have, if we have enough (4).
- int count = (sum + stride / 2) / stride;
+ uint32_t count = (sum + stride / 2) / stride;
if (count < 1) {
count = 1;
}
@@ -117,17 +115,8 @@ static int OptimizeHuffmanForRle(int length, int* const counts) {
}
}
}
- free(good_for_rle);
- return 1;
}
-typedef struct {
- int total_count_;
- int value_;
- int pool_index_left_;
- int pool_index_right_;
-} HuffmanTree;
-
// A comparer function for two Huffman trees: sorts first by 'total count'
// (more comes first), and then by 'value' (more comes first).
static int CompareHuffmanTrees(const void* ptr1, const void* ptr2) {
@@ -138,13 +127,8 @@ static int CompareHuffmanTrees(const void* ptr1, const void* ptr2) {
} else if (t1->total_count_ < t2->total_count_) {
return 1;
} else {
- if (t1->value_ < t2->value_) {
- return -1;
- }
- if (t1->value_ > t2->value_) {
- return 1;
- }
- return 0;
+ assert(t1->value_ != t2->value_);
+ return (t1->value_ < t2->value_) ? -1 : 1;
}
}
@@ -178,12 +162,12 @@ static void SetBitDepths(const HuffmanTree* const tree,
// we are not planning to use this with extremely long blocks.
//
// See http://en.wikipedia.org/wiki/Huffman_coding
-static int GenerateOptimalTree(const int* const histogram, int histogram_size,
- int tree_depth_limit,
- uint8_t* const bit_depths) {
- int count_min;
+static void GenerateOptimalTree(const uint32_t* const histogram,
+ int histogram_size,
+ HuffmanTree* tree, int tree_depth_limit,
+ uint8_t* const bit_depths) {
+ uint32_t count_min;
HuffmanTree* tree_pool;
- HuffmanTree* tree;
int tree_size_orig = 0;
int i;
@@ -193,12 +177,10 @@ static int GenerateOptimalTree(const int* const histogram, int histogram_size,
}
}
- // 3 * tree_size is enough to cover all the nodes representing a
- // population and all the inserted nodes combining two existing nodes.
- // The tree pool needs 2 * (tree_size_orig - 1) entities, and the
- // tree needs exactly tree_size_orig entities.
- tree = (HuffmanTree*)WebPSafeMalloc(3ULL * tree_size_orig, sizeof(*tree));
- if (tree == NULL) return 0;
+ if (tree_size_orig == 0) { // pretty optimal already!
+ return;
+ }
+
tree_pool = tree + tree_size_orig;
// For block sizes with less than 64k symbols we never need to do a
@@ -214,7 +196,7 @@ static int GenerateOptimalTree(const int* const histogram, int histogram_size,
int j;
for (j = 0; j < histogram_size; ++j) {
if (histogram[j] != 0) {
- const int count =
+ const uint32_t count =
(histogram[j] < count_min) ? count_min : histogram[j];
tree[idx].total_count_ = count;
tree[idx].value_ = j;
@@ -230,11 +212,11 @@ static int GenerateOptimalTree(const int* const histogram, int histogram_size,
if (tree_size > 1) { // Normal case.
int tree_pool_size = 0;
while (tree_size > 1) { // Finish when we have only one root.
- int count;
+ uint32_t count;
tree_pool[tree_pool_size++] = tree[tree_size - 1];
tree_pool[tree_pool_size++] = tree[tree_size - 2];
count = tree_pool[tree_pool_size - 1].total_count_ +
- tree_pool[tree_pool_size - 2].total_count_;
+ tree_pool[tree_pool_size - 2].total_count_;
tree_size -= 2;
{
// Search for the insertion point.
@@ -271,8 +253,6 @@ static int GenerateOptimalTree(const int* const histogram, int histogram_size,
}
}
}
- free(tree);
- return 1;
}
// -----------------------------------------------------------------------------
@@ -423,17 +403,15 @@ static void ConvertBitDepthsToSymbols(HuffmanTreeCode* const tree) {
// -----------------------------------------------------------------------------
// Main entry point
-int VP8LCreateHuffmanTree(int* const histogram, int tree_depth_limit,
- HuffmanTreeCode* const tree) {
- const int num_symbols = tree->num_symbols;
- if (!OptimizeHuffmanForRle(num_symbols, histogram)) {
- return 0;
- }
- if (!GenerateOptimalTree(histogram, num_symbols,
- tree_depth_limit, tree->code_lengths)) {
- return 0;
- }
+void VP8LCreateHuffmanTree(uint32_t* const histogram, int tree_depth_limit,
+ uint8_t* const buf_rle,
+ HuffmanTree* const huff_tree,
+ HuffmanTreeCode* const huff_code) {
+ const int num_symbols = huff_code->num_symbols;
+ memset(buf_rle, 0, num_symbols * sizeof(*buf_rle));
+ OptimizeHuffmanForRle(num_symbols, buf_rle, histogram);
+ GenerateOptimalTree(histogram, num_symbols, huff_tree, tree_depth_limit,
+ huff_code->code_lengths);
// Create the actual bit codes for the bit lengths.
- ConvertBitDepthsToSymbols(tree);
- return 1;
+ ConvertBitDepthsToSymbols(huff_code);
}
diff --git a/drivers/webp/utils/huffman_encode.h b/drivers/webp/utils/huffman_encode.h
index 7f4aedc102..93610066f3 100644
--- a/drivers/webp/utils/huffman_encode.h
+++ b/drivers/webp/utils/huffman_encode.h
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Author: Jyrki Alakuijala (jyrki@google.com)
@@ -12,9 +14,9 @@
#ifndef WEBP_UTILS_HUFFMAN_ENCODE_H_
#define WEBP_UTILS_HUFFMAN_ENCODE_H_
-#include "../types.h"
+#include "webp/types.h"
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
extern "C" {
#endif
@@ -31,16 +33,27 @@ typedef struct {
uint16_t* codes; // Symbol Codes.
} HuffmanTreeCode;
+// Struct to represent the Huffman tree.
+typedef struct {
+ uint32_t total_count_; // Symbol frequency.
+ int value_; // Symbol value.
+ int pool_index_left_; // Index for the left sub-tree.
+ int pool_index_right_; // Index for the right sub-tree.
+} HuffmanTree;
+
// Turn the Huffman tree into a token sequence.
// Returns the number of tokens used.
int VP8LCreateCompressedHuffmanTree(const HuffmanTreeCode* const tree,
HuffmanTreeToken* tokens, int max_tokens);
// Create an optimized tree, and tokenize it.
-int VP8LCreateHuffmanTree(int* const histogram, int tree_depth_limit,
- HuffmanTreeCode* const tree);
+// 'buf_rle' and 'huff_tree' are pre-allocated and the 'tree' is the constructed
+// huffman code tree.
+void VP8LCreateHuffmanTree(uint32_t* const histogram, int tree_depth_limit,
+ uint8_t* const buf_rle, HuffmanTree* const huff_tree,
+ HuffmanTreeCode* const tree);
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
}
#endif
diff --git a/drivers/webp/utils/quant_levels.c b/drivers/webp/utils/quant_levels.c
index f6884392aa..d7c8aab922 100644
--- a/drivers/webp/utils/quant_levels.c
+++ b/drivers/webp/utils/quant_levels.c
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Quantize levels for specified number of quantization-levels ([2, 256]).
@@ -14,10 +16,6 @@
#include "./quant_levels.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
#define NUM_SYMBOLS 256
#define MAX_ITER 6 // Maximum number of convergence steps.
@@ -140,15 +138,3 @@ int QuantizeLevels(uint8_t* const data, int width, int height,
return 1;
}
-int DequantizeLevels(uint8_t* const data, int width, int height) {
- if (data == NULL || width <= 0 || height <= 0) return 0;
- // TODO(skal): implement gradient smoothing.
- (void)data;
- (void)width;
- (void)height;
- return 1;
-}
-
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/utils/quant_levels.h b/drivers/webp/utils/quant_levels.h
index 4f165fd230..3916b977ab 100644
--- a/drivers/webp/utils/quant_levels.h
+++ b/drivers/webp/utils/quant_levels.h
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Alpha plane quantization utility
@@ -14,9 +16,9 @@
#include <stdlib.h>
-#include "../types.h"
+#include "webp/types.h"
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
extern "C" {
#endif
@@ -27,12 +29,7 @@ extern "C" {
int QuantizeLevels(uint8_t* const data, int width, int height, int num_levels,
uint64_t* const sse);
-// Apply post-processing to input 'data' of size 'width'x'height' assuming
-// that the source was quantized to a reduced number of levels.
-// Returns false in case of error (data is NULL, invalid parameters, ...).
-int DequantizeLevels(uint8_t* const data, int width, int height);
-
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/drivers/webp/utils/quant_levels_dec.c b/drivers/webp/utils/quant_levels_dec.c
new file mode 100644
index 0000000000..5b8b8b49e6
--- /dev/null
+++ b/drivers/webp/utils/quant_levels_dec.c
@@ -0,0 +1,279 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Implement gradient smoothing: we replace a current alpha value by its
+// surrounding average if it's close enough (that is: the change will be less
+// than the minimum distance between two quantized level).
+// We use sliding window for computing the 2d moving average.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./quant_levels_dec.h"
+
+#include <string.h> // for memset
+
+#include "./utils.h"
+
+// #define USE_DITHERING // uncomment to enable ordered dithering (not vital)
+
+#define FIX 16 // fix-point precision for averaging
+#define LFIX 2 // extra precision for look-up table
+#define LUT_SIZE ((1 << (8 + LFIX)) - 1) // look-up table size
+
+#if defined(USE_DITHERING)
+
+#define DFIX 4 // extra precision for ordered dithering
+#define DSIZE 4 // dithering size (must be a power of two)
+// cf. http://en.wikipedia.org/wiki/Ordered_dithering
+static const uint8_t kOrderedDither[DSIZE][DSIZE] = {
+ { 0, 8, 2, 10 }, // coefficients are in DFIX fixed-point precision
+ { 12, 4, 14, 6 },
+ { 3, 11, 1, 9 },
+ { 15, 7, 13, 5 }
+};
+
+#else
+#define DFIX 0
+#endif
+
+typedef struct {
+ int width_, height_; // dimension
+ int row_; // current input row being processed
+ uint8_t* src_; // input pointer
+ uint8_t* dst_; // output pointer
+
+ int radius_; // filter radius (=delay)
+ int scale_; // normalization factor, in FIX bits precision
+
+ void* mem_; // all memory
+
+ // various scratch buffers
+ uint16_t* start_;
+ uint16_t* cur_;
+ uint16_t* end_;
+ uint16_t* top_;
+ uint16_t* average_;
+
+ // input levels distribution
+ int num_levels_; // number of quantized levels
+ int min_, max_; // min and max level values
+ int min_level_dist_; // smallest distance between two consecutive levels
+
+ int16_t* correction_; // size = 1 + 2*LUT_SIZE -> ~4k memory
+} SmoothParams;
+
+//------------------------------------------------------------------------------
+
+#define CLIP_MASK (int)(~0U << (8 + DFIX))
+static WEBP_INLINE uint8_t clip_8b(int v) {
+ return (!(v & CLIP_MASK)) ? (uint8_t)(v >> DFIX) : (v < 0) ? 0u : 255u;
+}
+
+// vertical accumulation
+static void VFilter(SmoothParams* const p) {
+ const uint8_t* src = p->src_;
+ const int w = p->width_;
+ uint16_t* const cur = p->cur_;
+ const uint16_t* const top = p->top_;
+ uint16_t* const out = p->end_;
+ uint16_t sum = 0; // all arithmetic is modulo 16bit
+ int x;
+
+ for (x = 0; x < w; ++x) {
+ uint16_t new_value;
+ sum += src[x];
+ new_value = top[x] + sum;
+ out[x] = new_value - cur[x]; // vertical sum of 'r' pixels.
+ cur[x] = new_value;
+ }
+ // move input pointers one row down
+ p->top_ = p->cur_;
+ p->cur_ += w;
+ if (p->cur_ == p->end_) p->cur_ = p->start_; // roll-over
+ // We replicate edges, as it's somewhat easier as a boundary condition.
+ // That's why we don't update the 'src' pointer on top/bottom area:
+ if (p->row_ >= 0 && p->row_ < p->height_ - 1) {
+ p->src_ += p->width_;
+ }
+}
+
+// horizontal accumulation. We use mirror replication of missing pixels, as it's
+// a little easier to implement (surprisingly).
+static void HFilter(SmoothParams* const p) {
+ const uint16_t* const in = p->end_;
+ uint16_t* const out = p->average_;
+ const uint32_t scale = p->scale_;
+ const int w = p->width_;
+ const int r = p->radius_;
+
+ int x;
+ for (x = 0; x <= r; ++x) { // left mirroring
+ const uint16_t delta = in[x + r - 1] + in[r - x];
+ out[x] = (delta * scale) >> FIX;
+ }
+ for (; x < w - r; ++x) { // bulk middle run
+ const uint16_t delta = in[x + r] - in[x - r - 1];
+ out[x] = (delta * scale) >> FIX;
+ }
+ for (; x < w; ++x) { // right mirroring
+ const uint16_t delta =
+ 2 * in[w - 1] - in[2 * w - 2 - r - x] - in[x - r - 1];
+ out[x] = (delta * scale) >> FIX;
+ }
+}
+
+// emit one filtered output row
+static void ApplyFilter(SmoothParams* const p) {
+ const uint16_t* const average = p->average_;
+ const int w = p->width_;
+ const int16_t* const correction = p->correction_;
+#if defined(USE_DITHERING)
+ const uint8_t* const dither = kOrderedDither[p->row_ % DSIZE];
+#endif
+ uint8_t* const dst = p->dst_;
+ int x;
+ for (x = 0; x < w; ++x) {
+ const int v = dst[x];
+ if (v < p->max_ && v > p->min_) {
+ const int c = (v << DFIX) + correction[average[x] - (v << LFIX)];
+#if defined(USE_DITHERING)
+ dst[x] = clip_8b(c + dither[x % DSIZE]);
+#else
+ dst[x] = clip_8b(c);
+#endif
+ }
+ }
+ p->dst_ += w; // advance output pointer
+}
+
+//------------------------------------------------------------------------------
+// Initialize correction table
+
+static void InitCorrectionLUT(int16_t* const lut, int min_dist) {
+ // The correction curve is:
+ // f(x) = x for x <= threshold2
+ // f(x) = 0 for x >= threshold1
+ // and a linear interpolation for range x=[threshold2, threshold1]
+ // (along with f(-x) = -f(x) symmetry).
+ // Note that: threshold2 = 3/4 * threshold1
+ const int threshold1 = min_dist << LFIX;
+ const int threshold2 = (3 * threshold1) >> 2;
+ const int max_threshold = threshold2 << DFIX;
+ const int delta = threshold1 - threshold2;
+ int i;
+ for (i = 1; i <= LUT_SIZE; ++i) {
+ int c = (i <= threshold2) ? (i << DFIX)
+ : (i < threshold1) ? max_threshold * (threshold1 - i) / delta
+ : 0;
+ c >>= LFIX;
+ lut[+i] = +c;
+ lut[-i] = -c;
+ }
+ lut[0] = 0;
+}
+
+static void CountLevels(const uint8_t* const data, int size,
+ SmoothParams* const p) {
+ int i, last_level;
+ uint8_t used_levels[256] = { 0 };
+ p->min_ = 255;
+ p->max_ = 0;
+ for (i = 0; i < size; ++i) {
+ const int v = data[i];
+ if (v < p->min_) p->min_ = v;
+ if (v > p->max_) p->max_ = v;
+ used_levels[v] = 1;
+ }
+ // Compute the mininum distance between two non-zero levels.
+ p->min_level_dist_ = p->max_ - p->min_;
+ last_level = -1;
+ for (i = 0; i < 256; ++i) {
+ if (used_levels[i]) {
+ ++p->num_levels_;
+ if (last_level >= 0) {
+ const int level_dist = i - last_level;
+ if (level_dist < p->min_level_dist_) {
+ p->min_level_dist_ = level_dist;
+ }
+ }
+ last_level = i;
+ }
+ }
+}
+
+// Initialize all params.
+static int InitParams(uint8_t* const data, int width, int height,
+ int radius, SmoothParams* const p) {
+ const int R = 2 * radius + 1; // total size of the kernel
+
+ const size_t size_scratch_m = (R + 1) * width * sizeof(*p->start_);
+ const size_t size_m = width * sizeof(*p->average_);
+ const size_t size_lut = (1 + 2 * LUT_SIZE) * sizeof(*p->correction_);
+ const size_t total_size = size_scratch_m + size_m + size_lut;
+ uint8_t* mem = (uint8_t*)WebPSafeMalloc(1U, total_size);
+
+ if (mem == NULL) return 0;
+ p->mem_ = (void*)mem;
+
+ p->start_ = (uint16_t*)mem;
+ p->cur_ = p->start_;
+ p->end_ = p->start_ + R * width;
+ p->top_ = p->end_ - width;
+ memset(p->top_, 0, width * sizeof(*p->top_));
+ mem += size_scratch_m;
+
+ p->average_ = (uint16_t*)mem;
+ mem += size_m;
+
+ p->width_ = width;
+ p->height_ = height;
+ p->src_ = data;
+ p->dst_ = data;
+ p->radius_ = radius;
+ p->scale_ = (1 << (FIX + LFIX)) / (R * R); // normalization constant
+ p->row_ = -radius;
+
+ // analyze the input distribution so we can best-fit the threshold
+ CountLevels(data, width * height, p);
+
+ // correction table
+ p->correction_ = ((int16_t*)mem) + LUT_SIZE;
+ InitCorrectionLUT(p->correction_, p->min_level_dist_);
+
+ return 1;
+}
+
+static void CleanupParams(SmoothParams* const p) {
+ WebPSafeFree(p->mem_);
+}
+
+int WebPDequantizeLevels(uint8_t* const data, int width, int height,
+ int strength) {
+ const int radius = 4 * strength / 100;
+ if (strength < 0 || strength > 100) return 0;
+ if (data == NULL || width <= 0 || height <= 0) return 0; // bad params
+ if (radius > 0) {
+ SmoothParams p;
+ memset(&p, 0, sizeof(p));
+ if (!InitParams(data, width, height, radius, &p)) return 0;
+ if (p.num_levels_ > 2) {
+ for (; p.row_ < p.height_; ++p.row_) {
+ VFilter(&p); // accumulate average of input
+ // Need to wait few rows in order to prime the filter,
+ // before emitting some output.
+ if (p.row_ >= p.radius_) {
+ HFilter(&p);
+ ApplyFilter(&p);
+ }
+ }
+ }
+ CleanupParams(&p);
+ }
+ return 1;
+}
diff --git a/drivers/webp/utils/quant_levels_dec.h b/drivers/webp/utils/quant_levels_dec.h
new file mode 100644
index 0000000000..29c7e6e205
--- /dev/null
+++ b/drivers/webp/utils/quant_levels_dec.h
@@ -0,0 +1,35 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Alpha plane de-quantization utility
+//
+// Author: Vikas Arora (vikasa@google.com)
+
+#ifndef WEBP_UTILS_QUANT_LEVELS_DEC_H_
+#define WEBP_UTILS_QUANT_LEVELS_DEC_H_
+
+#include "webp/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Apply post-processing to input 'data' of size 'width'x'height' assuming that
+// the source was quantized to a reduced number of levels.
+// Strength is in [0..100] and controls the amount of dithering applied.
+// Returns false in case of error (data is NULL, invalid parameters,
+// malloc failure, ...).
+int WebPDequantizeLevels(uint8_t* const data, int width, int height,
+ int strength);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* WEBP_UTILS_QUANT_LEVELS_DEC_H_ */
diff --git a/drivers/webp/utils/random.c b/drivers/webp/utils/random.c
new file mode 100644
index 0000000000..24e96ad648
--- /dev/null
+++ b/drivers/webp/utils/random.c
@@ -0,0 +1,43 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Pseudo-random utilities
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <string.h>
+#include "./random.h"
+
+//------------------------------------------------------------------------------
+
+// 31b-range values
+static const uint32_t kRandomTable[VP8_RANDOM_TABLE_SIZE] = {
+ 0x0de15230, 0x03b31886, 0x775faccb, 0x1c88626a, 0x68385c55, 0x14b3b828,
+ 0x4a85fef8, 0x49ddb84b, 0x64fcf397, 0x5c550289, 0x4a290000, 0x0d7ec1da,
+ 0x5940b7ab, 0x5492577d, 0x4e19ca72, 0x38d38c69, 0x0c01ee65, 0x32a1755f,
+ 0x5437f652, 0x5abb2c32, 0x0faa57b1, 0x73f533e7, 0x685feeda, 0x7563cce2,
+ 0x6e990e83, 0x4730a7ed, 0x4fc0d9c6, 0x496b153c, 0x4f1403fa, 0x541afb0c,
+ 0x73990b32, 0x26d7cb1c, 0x6fcc3706, 0x2cbb77d8, 0x75762f2a, 0x6425ccdd,
+ 0x24b35461, 0x0a7d8715, 0x220414a8, 0x141ebf67, 0x56b41583, 0x73e502e3,
+ 0x44cab16f, 0x28264d42, 0x73baaefb, 0x0a50ebed, 0x1d6ab6fb, 0x0d3ad40b,
+ 0x35db3b68, 0x2b081e83, 0x77ce6b95, 0x5181e5f0, 0x78853bbc, 0x009f9494,
+ 0x27e5ed3c
+};
+
+void VP8InitRandom(VP8Random* const rg, float dithering) {
+ memcpy(rg->tab_, kRandomTable, sizeof(rg->tab_));
+ rg->index1_ = 0;
+ rg->index2_ = 31;
+ rg->amp_ = (dithering < 0.0) ? 0
+ : (dithering > 1.0) ? (1 << VP8_RANDOM_DITHER_FIX)
+ : (uint32_t)((1 << VP8_RANDOM_DITHER_FIX) * dithering);
+}
+
+//------------------------------------------------------------------------------
+
diff --git a/drivers/webp/utils/random.h b/drivers/webp/utils/random.h
new file mode 100644
index 0000000000..745f3e2e87
--- /dev/null
+++ b/drivers/webp/utils/random.h
@@ -0,0 +1,63 @@
+// Copyright 2013 Google Inc. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+// -----------------------------------------------------------------------------
+//
+// Pseudo-random utilities
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#ifndef WEBP_UTILS_RANDOM_H_
+#define WEBP_UTILS_RANDOM_H_
+
+#include <assert.h>
+#include "webp/types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define VP8_RANDOM_DITHER_FIX 8 // fixed-point precision for dithering
+#define VP8_RANDOM_TABLE_SIZE 55
+
+typedef struct {
+ int index1_, index2_;
+ uint32_t tab_[VP8_RANDOM_TABLE_SIZE];
+ int amp_;
+} VP8Random;
+
+// Initializes random generator with an amplitude 'dithering' in range [0..1].
+void VP8InitRandom(VP8Random* const rg, float dithering);
+
+// Returns a centered pseudo-random number with 'num_bits' amplitude.
+// (uses D.Knuth's Difference-based random generator).
+// 'amp' is in VP8_RANDOM_DITHER_FIX fixed-point precision.
+static WEBP_INLINE int VP8RandomBits2(VP8Random* const rg, int num_bits,
+ int amp) {
+ int diff;
+ assert(num_bits + VP8_RANDOM_DITHER_FIX <= 31);
+ diff = rg->tab_[rg->index1_] - rg->tab_[rg->index2_];
+ if (diff < 0) diff += (1u << 31);
+ rg->tab_[rg->index1_] = diff;
+ if (++rg->index1_ == VP8_RANDOM_TABLE_SIZE) rg->index1_ = 0;
+ if (++rg->index2_ == VP8_RANDOM_TABLE_SIZE) rg->index2_ = 0;
+ // sign-extend, 0-center
+ diff = (int)((uint32_t)diff << 1) >> (32 - num_bits);
+ diff = (diff * amp) >> VP8_RANDOM_DITHER_FIX; // restrict range
+ diff += 1 << (num_bits - 1); // shift back to 0.5-center
+ return diff;
+}
+
+static WEBP_INLINE int VP8RandomBits(VP8Random* const rg, int num_bits) {
+ return VP8RandomBits2(rg, num_bits, rg->amp_);
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif /* WEBP_UTILS_RANDOM_H_ */
diff --git a/drivers/webp/utils/rescaler.c b/drivers/webp/utils/rescaler.c
index 9825dcbc5f..00c9300bfb 100644
--- a/drivers/webp/utils/rescaler.c
+++ b/drivers/webp/utils/rescaler.c
@@ -1,8 +1,10 @@
// Copyright 2012 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Rescaling functions
@@ -11,124 +13,116 @@
#include <assert.h>
#include <stdlib.h>
+#include <string.h>
+#include "../dsp/dsp.h"
#include "./rescaler.h"
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
-
-#define RFIX 30
-#define MULT_FIX(x,y) (((int64_t)(x) * (y) + (1 << (RFIX - 1))) >> RFIX)
-
void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height,
- uint8_t* const dst, int dst_width, int dst_height,
- int dst_stride, int num_channels, int x_add, int x_sub,
- int y_add, int y_sub, int32_t* const work) {
+ uint8_t* const dst,
+ int dst_width, int dst_height, int dst_stride,
+ int num_channels, rescaler_t* const work) {
+ const int x_add = src_width, x_sub = dst_width;
+ const int y_add = src_height, y_sub = dst_height;
wrk->x_expand = (src_width < dst_width);
+ wrk->y_expand = (src_height < dst_height);
wrk->src_width = src_width;
wrk->src_height = src_height;
wrk->dst_width = dst_width;
wrk->dst_height = dst_height;
+ wrk->src_y = 0;
+ wrk->dst_y = 0;
wrk->dst = dst;
wrk->dst_stride = dst_stride;
wrk->num_channels = num_channels;
+
// for 'x_expand', we use bilinear interpolation
- wrk->x_add = wrk->x_expand ? (x_sub - 1) : x_add - x_sub;
+ wrk->x_add = wrk->x_expand ? (x_sub - 1) : x_add;
wrk->x_sub = wrk->x_expand ? (x_add - 1) : x_sub;
- wrk->y_accum = y_add;
- wrk->y_add = y_add;
- wrk->y_sub = y_sub;
- wrk->fx_scale = (1 << RFIX) / x_sub;
- wrk->fy_scale = (1 << RFIX) / y_sub;
- wrk->fxy_scale = wrk->x_expand ?
- ((int64_t)dst_height << RFIX) / (x_sub * src_height) :
- ((int64_t)dst_height << RFIX) / (x_add * src_height);
+ if (!wrk->x_expand) { // fx_scale is not used otherwise
+ wrk->fx_scale = WEBP_RESCALER_FRAC(1, wrk->x_sub);
+ }
+ // vertical scaling parameters
+ wrk->y_add = wrk->y_expand ? y_add - 1 : y_add;
+ wrk->y_sub = wrk->y_expand ? y_sub - 1 : y_sub;
+ wrk->y_accum = wrk->y_expand ? wrk->y_sub : wrk->y_add;
+ if (!wrk->y_expand) {
+ // this is WEBP_RESCALER_FRAC(dst_height, x_add * y_add) without the cast.
+ const uint64_t ratio =
+ (uint64_t)dst_height * WEBP_RESCALER_ONE / (wrk->x_add * wrk->y_add);
+ if (ratio != (uint32_t)ratio) {
+ // We can't represent the ratio with the current fixed-point precision.
+ // => We special-case fxy_scale = 0, in WebPRescalerExportRow().
+ wrk->fxy_scale = 0;
+ } else {
+ wrk->fxy_scale = (uint32_t)ratio;
+ }
+ wrk->fy_scale = WEBP_RESCALER_FRAC(1, wrk->y_sub);
+ } else {
+ wrk->fy_scale = WEBP_RESCALER_FRAC(1, wrk->x_add);
+ // wrk->fxy_scale is unused here.
+ }
wrk->irow = work;
wrk->frow = work + num_channels * dst_width;
-}
+ memset(work, 0, 2 * dst_width * num_channels * sizeof(*work));
-void WebPRescalerImportRow(WebPRescaler* const wrk,
- const uint8_t* const src, int channel) {
- const int x_stride = wrk->num_channels;
- const int x_out_max = wrk->dst_width * wrk->num_channels;
- int x_in = channel;
- int x_out;
- int accum = 0;
- if (!wrk->x_expand) {
- int sum = 0;
- for (x_out = channel; x_out < x_out_max; x_out += x_stride) {
- accum += wrk->x_add;
- for (; accum > 0; accum -= wrk->x_sub) {
- sum += src[x_in];
- x_in += x_stride;
- }
- { // Emit next horizontal pixel.
- const int32_t base = src[x_in];
- const int32_t frac = base * (-accum);
- x_in += x_stride;
- wrk->frow[x_out] = (sum + base) * wrk->x_sub - frac;
- // fresh fractional start for next pixel
- sum = (int)MULT_FIX(frac, wrk->fx_scale);
- }
- }
- } else { // simple bilinear interpolation
- int left = src[channel], right = src[channel];
- for (x_out = channel; x_out < x_out_max; x_out += x_stride) {
- if (accum < 0) {
- left = right;
- x_in += x_stride;
- right = src[x_in];
- accum += wrk->x_add;
- }
- wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum;
- accum -= wrk->x_sub;
- }
- }
- // Accumulate the new row's contribution
- for (x_out = channel; x_out < x_out_max; x_out += x_stride) {
- wrk->irow[x_out] += wrk->frow[x_out];
- }
+ WebPRescalerDspInit();
}
-uint8_t* WebPRescalerExportRow(WebPRescaler* const wrk) {
- if (wrk->y_accum <= 0) {
- int x_out;
- uint8_t* const dst = wrk->dst;
- int32_t* const irow = wrk->irow;
- const int32_t* const frow = wrk->frow;
- const int yscale = wrk->fy_scale * (-wrk->y_accum);
- const int x_out_max = wrk->dst_width * wrk->num_channels;
+int WebPRescalerGetScaledDimensions(int src_width, int src_height,
+ int* const scaled_width,
+ int* const scaled_height) {
+ assert(scaled_width != NULL);
+ assert(scaled_height != NULL);
+ {
+ int width = *scaled_width;
+ int height = *scaled_height;
- for (x_out = 0; x_out < x_out_max; ++x_out) {
- const int frac = (int)MULT_FIX(frow[x_out], yscale);
- const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
- dst[x_out] = (!(v & ~0xff)) ? v : (v < 0) ? 0 : 255;
- irow[x_out] = frac; // new fractional start
+ // if width is unspecified, scale original proportionally to height ratio.
+ if (width == 0) {
+ width = (src_width * height + src_height / 2) / src_height;
}
- wrk->y_accum += wrk->y_add;
- wrk->dst += wrk->dst_stride;
- return dst;
- } else {
- return NULL;
+ // if height is unspecified, scale original proportionally to width ratio.
+ if (height == 0) {
+ height = (src_height * width + src_width / 2) / src_width;
+ }
+ // Check if the overall dimensions still make sense.
+ if (width <= 0 || height <= 0) {
+ return 0;
+ }
+
+ *scaled_width = width;
+ *scaled_height = height;
+ return 1;
}
}
-#undef MULT_FIX
-#undef RFIX
-
//------------------------------------------------------------------------------
// all-in-one calls
+int WebPRescaleNeededLines(const WebPRescaler* const wrk, int max_num_lines) {
+ const int num_lines = (wrk->y_accum + wrk->y_sub - 1) / wrk->y_sub;
+ return (num_lines > max_num_lines) ? max_num_lines : num_lines;
+}
+
int WebPRescalerImport(WebPRescaler* const wrk, int num_lines,
const uint8_t* src, int src_stride) {
int total_imported = 0;
- while (total_imported < num_lines && wrk->y_accum > 0) {
- int channel;
- for (channel = 0; channel < wrk->num_channels; ++channel) {
- WebPRescalerImportRow(wrk, src, channel);
+ while (total_imported < num_lines && !WebPRescalerHasPendingOutput(wrk)) {
+ if (wrk->y_expand) {
+ rescaler_t* const tmp = wrk->irow;
+ wrk->irow = wrk->frow;
+ wrk->frow = tmp;
}
+ WebPRescalerImportRow(wrk, src);
+ if (!wrk->y_expand) { // Accumulate the contribution of the new row.
+ int x;
+ for (x = 0; x < wrk->num_channels * wrk->dst_width; ++x) {
+ wrk->irow[x] += wrk->frow[x];
+ }
+ }
+ ++wrk->src_y;
src += src_stride;
++total_imported;
wrk->y_accum -= wrk->y_sub;
@@ -146,7 +140,3 @@ int WebPRescalerExport(WebPRescaler* const rescaler) {
}
//------------------------------------------------------------------------------
-
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
diff --git a/drivers/webp/utils/rescaler.h b/drivers/webp/utils/rescaler.h
index 9c9133d19b..868467b4d7 100644
--- a/drivers/webp/utils/rescaler.h
+++ b/drivers/webp/utils/rescaler.h
@@ -1,8 +1,10 @@
// Copyright 2012 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Rescaling functions
@@ -12,64 +14,87 @@
#ifndef WEBP_UTILS_RESCALER_H_
#define WEBP_UTILS_RESCALER_H_
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
extern "C" {
#endif
-#include "../types.h"
+#include "webp/types.h"
+
+#define WEBP_RESCALER_RFIX 32 // fixed-point precision for multiplies
+#define WEBP_RESCALER_ONE (1ull << WEBP_RESCALER_RFIX)
+#define WEBP_RESCALER_FRAC(x, y) \
+ ((uint32_t)(((uint64_t)(x) << WEBP_RESCALER_RFIX) / (y)))
// Structure used for on-the-fly rescaling
-typedef struct {
+typedef uint32_t rescaler_t; // type for side-buffer
+typedef struct WebPRescaler WebPRescaler;
+struct WebPRescaler {
int x_expand; // true if we're expanding in the x direction
+ int y_expand; // true if we're expanding in the y direction
int num_channels; // bytes to jump between pixels
- int fy_scale, fx_scale; // fixed-point scaling factor
- int64_t fxy_scale; // ''
- // we need hpel-precise add/sub increments, for the downsampled U/V planes.
+ uint32_t fx_scale; // fixed-point scaling factors
+ uint32_t fy_scale; // ''
+ uint32_t fxy_scale; // ''
int y_accum; // vertical accumulator
- int y_add, y_sub; // vertical increments (add ~= src, sub ~= dst)
- int x_add, x_sub; // horizontal increments (add ~= src, sub ~= dst)
+ int y_add, y_sub; // vertical increments
+ int x_add, x_sub; // horizontal increments
int src_width, src_height; // source dimensions
int dst_width, dst_height; // destination dimensions
+ int src_y, dst_y; // row counters for input and output
uint8_t* dst;
int dst_stride;
- int32_t* irow, *frow; // work buffer
-} WebPRescaler;
+ rescaler_t* irow, *frow; // work buffer
+};
// Initialize a rescaler given scratch area 'work' and dimensions of src & dst.
-void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height,
+void WebPRescalerInit(WebPRescaler* const rescaler,
+ int src_width, int src_height,
uint8_t* const dst,
int dst_width, int dst_height, int dst_stride,
int num_channels,
- int x_add, int x_sub,
- int y_add, int y_sub,
- int32_t* const work);
+ rescaler_t* const work);
+
+// If either 'scaled_width' or 'scaled_height' (but not both) is 0 the value
+// will be calculated preserving the aspect ratio, otherwise the values are
+// left unmodified. Returns true on success, false if either value is 0 after
+// performing the scaling calculation.
+int WebPRescalerGetScaledDimensions(int src_width, int src_height,
+ int* const scaled_width,
+ int* const scaled_height);
-// Import a row of data and save its contribution in the rescaler.
-// 'channel' denotes the channel number to be imported.
-void WebPRescalerImportRow(WebPRescaler* const rescaler,
- const uint8_t* const src, int channel);
+// Returns the number of input lines needed next to produce one output line,
+// considering that the maximum available input lines are 'max_num_lines'.
+int WebPRescaleNeededLines(const WebPRescaler* const rescaler,
+ int max_num_lines);
// Import multiple rows over all channels, until at least one row is ready to
// be exported. Returns the actual number of lines that were imported.
int WebPRescalerImport(WebPRescaler* const rescaler, int num_rows,
const uint8_t* src, int src_stride);
-// Return true if there is pending output rows ready.
+// Export as many rows as possible. Return the numbers of rows written.
+int WebPRescalerExport(WebPRescaler* const rescaler);
+
+// Return true if input is finished
static WEBP_INLINE
-int WebPRescalerHasPendingOutput(const WebPRescaler* const rescaler) {
- return (rescaler->y_accum <= 0);
+int WebPRescalerInputDone(const WebPRescaler* const rescaler) {
+ return (rescaler->src_y >= rescaler->src_height);
+}
+// Return true if output is finished
+static WEBP_INLINE
+int WebPRescalerOutputDone(const WebPRescaler* const rescaler) {
+ return (rescaler->dst_y >= rescaler->dst_height);
}
-// Export one row from rescaler. Returns the pointer where output was written,
-// or NULL if no row was pending.
-uint8_t* WebPRescalerExportRow(WebPRescaler* const wrk);
-
-// Export as many rows as possible. Return the numbers of rows written.
-int WebPRescalerExport(WebPRescaler* const wrk);
+// Return true if there are pending output rows ready.
+static WEBP_INLINE
+int WebPRescalerHasPendingOutput(const WebPRescaler* const rescaler) {
+ return !WebPRescalerOutputDone(rescaler) && (rescaler->y_accum <= 0);
+}
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/drivers/webp/utils/thread.c b/drivers/webp/utils/thread.c
index ce89cf9dc7..93f7622797 100644
--- a/drivers/webp/utils/thread.c
+++ b/drivers/webp/utils/thread.c
@@ -1,27 +1,60 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Multi-threaded worker
//
// Author: Skal (pascal.massimino@gmail.com)
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
#include <assert.h>
#include <string.h> // for memset()
#include "./thread.h"
+#include "./utils.h"
+
+#ifdef WEBP_USE_THREAD
+
+#if defined(_WIN32)
+
+#include <windows.h>
+typedef HANDLE pthread_t;
+typedef CRITICAL_SECTION pthread_mutex_t;
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
+#if _WIN32_WINNT >= 0x0600 // Windows Vista / Server 2008 or greater
+#define USE_WINDOWS_CONDITION_VARIABLE
+typedef CONDITION_VARIABLE pthread_cond_t;
+#else
+typedef struct {
+ HANDLE waiting_sem_;
+ HANDLE received_sem_;
+ HANDLE signal_event_;
+} pthread_cond_t;
+#endif // _WIN32_WINNT >= 0x600
+
+#ifndef WINAPI_FAMILY_PARTITION
+#define WINAPI_PARTITION_DESKTOP 1
+#define WINAPI_FAMILY_PARTITION(x) x
#endif
-#ifdef WEBP_USE_THREAD
+#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+#define USE_CREATE_THREAD
+#endif
+
+#else // !_WIN32
+
+#include <pthread.h>
+
+#endif // _WIN32
+
+struct WebPWorkerImpl {
+ pthread_mutex_t mutex_;
+ pthread_cond_t condition_;
+ pthread_t thread_;
+};
#if defined(_WIN32)
@@ -34,15 +67,29 @@ extern "C" {
#define THREADFN unsigned int __stdcall
#define THREAD_RETURN(val) (unsigned int)((DWORD_PTR)val)
+#if _WIN32_WINNT >= 0x0501 // Windows XP or greater
+#define WaitForSingleObject(obj, timeout) \
+ WaitForSingleObjectEx(obj, timeout, FALSE /*bAlertable*/)
+#endif
+
static int pthread_create(pthread_t* const thread, const void* attr,
unsigned int (__stdcall *start)(void*), void* arg) {
(void)attr;
+#ifdef USE_CREATE_THREAD
+ *thread = CreateThread(NULL, /* lpThreadAttributes */
+ 0, /* dwStackSize */
+ start,
+ arg,
+ 0, /* dwStackSize */
+ NULL); /* lpThreadId */
+#else
*thread = (pthread_t)_beginthreadex(NULL, /* void *security */
0, /* unsigned stack_size */
start,
arg,
0, /* unsigned initflag */
NULL); /* unsigned *thrdaddr */
+#endif
if (*thread == NULL) return 1;
SetThreadPriority(*thread, THREAD_PRIORITY_ABOVE_NORMAL);
return 0;
@@ -57,7 +104,11 @@ static int pthread_join(pthread_t thread, void** value_ptr) {
// Mutex
static int pthread_mutex_init(pthread_mutex_t* const mutex, void* mutexattr) {
(void)mutexattr;
+#if _WIN32_WINNT >= 0x0600 // Windows Vista / Server 2008 or greater
+ InitializeCriticalSectionEx(mutex, 0 /*dwSpinCount*/, 0 /*Flags*/);
+#else
InitializeCriticalSection(mutex);
+#endif
return 0;
}
@@ -79,14 +130,21 @@ static int pthread_mutex_destroy(pthread_mutex_t* const mutex) {
// Condition
static int pthread_cond_destroy(pthread_cond_t* const condition) {
int ok = 1;
+#ifdef USE_WINDOWS_CONDITION_VARIABLE
+ (void)condition;
+#else
ok &= (CloseHandle(condition->waiting_sem_) != 0);
ok &= (CloseHandle(condition->received_sem_) != 0);
ok &= (CloseHandle(condition->signal_event_) != 0);
+#endif
return !ok;
}
static int pthread_cond_init(pthread_cond_t* const condition, void* cond_attr) {
(void)cond_attr;
+#ifdef USE_WINDOWS_CONDITION_VARIABLE
+ InitializeConditionVariable(condition);
+#else
condition->waiting_sem_ = CreateSemaphore(NULL, 0, 1, NULL);
condition->received_sem_ = CreateSemaphore(NULL, 0, 1, NULL);
condition->signal_event_ = CreateEvent(NULL, FALSE, FALSE, NULL);
@@ -96,11 +154,15 @@ static int pthread_cond_init(pthread_cond_t* const condition, void* cond_attr) {
pthread_cond_destroy(condition);
return 1;
}
+#endif
return 0;
}
static int pthread_cond_signal(pthread_cond_t* const condition) {
int ok = 1;
+#ifdef USE_WINDOWS_CONDITION_VARIABLE
+ WakeConditionVariable(condition);
+#else
if (WaitForSingleObject(condition->waiting_sem_, 0) == WAIT_OBJECT_0) {
// a thread is waiting in pthread_cond_wait: allow it to be notified
ok = SetEvent(condition->signal_event_);
@@ -109,12 +171,16 @@ static int pthread_cond_signal(pthread_cond_t* const condition) {
ok &= (WaitForSingleObject(condition->received_sem_, INFINITE) !=
WAIT_OBJECT_0);
}
+#endif
return !ok;
}
static int pthread_cond_wait(pthread_cond_t* const condition,
pthread_mutex_t* const mutex) {
int ok;
+#ifdef USE_WINDOWS_CONDITION_VARIABLE
+ ok = SleepConditionVariableCS(condition, mutex, INFINITE);
+#else
// note that there is a consumer available so the signal isn't dropped in
// pthread_cond_signal
if (!ReleaseSemaphore(condition->waiting_sem_, 1, NULL))
@@ -125,123 +191,168 @@ static int pthread_cond_wait(pthread_cond_t* const condition,
WAIT_OBJECT_0);
ok &= ReleaseSemaphore(condition->received_sem_, 1, NULL);
pthread_mutex_lock(mutex);
+#endif
return !ok;
}
-#else // _WIN32
+#else // !_WIN32
# define THREADFN void*
# define THREAD_RETURN(val) val
-#endif
+#endif // _WIN32
//------------------------------------------------------------------------------
-static THREADFN WebPWorkerThreadLoop(void *ptr) { // thread loop
+static void Execute(WebPWorker* const worker); // Forward declaration.
+
+static THREADFN ThreadLoop(void* ptr) {
WebPWorker* const worker = (WebPWorker*)ptr;
int done = 0;
while (!done) {
- pthread_mutex_lock(&worker->mutex_);
+ pthread_mutex_lock(&worker->impl_->mutex_);
while (worker->status_ == OK) { // wait in idling mode
- pthread_cond_wait(&worker->condition_, &worker->mutex_);
+ pthread_cond_wait(&worker->impl_->condition_, &worker->impl_->mutex_);
}
if (worker->status_ == WORK) {
- if (worker->hook) {
- worker->had_error |= !worker->hook(worker->data1, worker->data2);
- }
+ Execute(worker);
worker->status_ = OK;
} else if (worker->status_ == NOT_OK) { // finish the worker
done = 1;
}
// signal to the main thread that we're done (for Sync())
- pthread_cond_signal(&worker->condition_);
- pthread_mutex_unlock(&worker->mutex_);
+ pthread_cond_signal(&worker->impl_->condition_);
+ pthread_mutex_unlock(&worker->impl_->mutex_);
}
return THREAD_RETURN(NULL); // Thread is finished
}
// main thread state control
-static void WebPWorkerChangeState(WebPWorker* const worker,
- WebPWorkerStatus new_status) {
- // no-op when attempting to change state on a thread that didn't come up
- if (worker->status_ < OK) return;
-
- pthread_mutex_lock(&worker->mutex_);
- // wait for the worker to finish
- while (worker->status_ != OK) {
- pthread_cond_wait(&worker->condition_, &worker->mutex_);
- }
- // assign new status and release the working thread if needed
- if (new_status != OK) {
- worker->status_ = new_status;
- pthread_cond_signal(&worker->condition_);
+static void ChangeState(WebPWorker* const worker,
+ WebPWorkerStatus new_status) {
+ // No-op when attempting to change state on a thread that didn't come up.
+ // Checking status_ without acquiring the lock first would result in a data
+ // race.
+ if (worker->impl_ == NULL) return;
+
+ pthread_mutex_lock(&worker->impl_->mutex_);
+ if (worker->status_ >= OK) {
+ // wait for the worker to finish
+ while (worker->status_ != OK) {
+ pthread_cond_wait(&worker->impl_->condition_, &worker->impl_->mutex_);
+ }
+ // assign new status and release the working thread if needed
+ if (new_status != OK) {
+ worker->status_ = new_status;
+ pthread_cond_signal(&worker->impl_->condition_);
+ }
}
- pthread_mutex_unlock(&worker->mutex_);
+ pthread_mutex_unlock(&worker->impl_->mutex_);
}
-#endif
+#endif // WEBP_USE_THREAD
//------------------------------------------------------------------------------
-void WebPWorkerInit(WebPWorker* const worker) {
+static void Init(WebPWorker* const worker) {
memset(worker, 0, sizeof(*worker));
worker->status_ = NOT_OK;
}
-int WebPWorkerSync(WebPWorker* const worker) {
+static int Sync(WebPWorker* const worker) {
#ifdef WEBP_USE_THREAD
- WebPWorkerChangeState(worker, OK);
+ ChangeState(worker, OK);
#endif
assert(worker->status_ <= OK);
return !worker->had_error;
}
-int WebPWorkerReset(WebPWorker* const worker) {
+static int Reset(WebPWorker* const worker) {
int ok = 1;
worker->had_error = 0;
if (worker->status_ < OK) {
#ifdef WEBP_USE_THREAD
- if (pthread_mutex_init(&worker->mutex_, NULL) ||
- pthread_cond_init(&worker->condition_, NULL)) {
+ worker->impl_ = (WebPWorkerImpl*)WebPSafeCalloc(1, sizeof(*worker->impl_));
+ if (worker->impl_ == NULL) {
return 0;
}
- pthread_mutex_lock(&worker->mutex_);
- ok = !pthread_create(&worker->thread_, NULL, WebPWorkerThreadLoop, worker);
+ if (pthread_mutex_init(&worker->impl_->mutex_, NULL)) {
+ goto Error;
+ }
+ if (pthread_cond_init(&worker->impl_->condition_, NULL)) {
+ pthread_mutex_destroy(&worker->impl_->mutex_);
+ goto Error;
+ }
+ pthread_mutex_lock(&worker->impl_->mutex_);
+ ok = !pthread_create(&worker->impl_->thread_, NULL, ThreadLoop, worker);
if (ok) worker->status_ = OK;
- pthread_mutex_unlock(&worker->mutex_);
+ pthread_mutex_unlock(&worker->impl_->mutex_);
+ if (!ok) {
+ pthread_mutex_destroy(&worker->impl_->mutex_);
+ pthread_cond_destroy(&worker->impl_->condition_);
+ Error:
+ WebPSafeFree(worker->impl_);
+ worker->impl_ = NULL;
+ return 0;
+ }
#else
worker->status_ = OK;
#endif
} else if (worker->status_ > OK) {
- ok = WebPWorkerSync(worker);
+ ok = Sync(worker);
}
assert(!ok || (worker->status_ == OK));
return ok;
}
-void WebPWorkerLaunch(WebPWorker* const worker) {
+static void Execute(WebPWorker* const worker) {
+ if (worker->hook != NULL) {
+ worker->had_error |= !worker->hook(worker->data1, worker->data2);
+ }
+}
+
+static void Launch(WebPWorker* const worker) {
#ifdef WEBP_USE_THREAD
- WebPWorkerChangeState(worker, WORK);
+ ChangeState(worker, WORK);
#else
- if (worker->hook)
- worker->had_error |= !worker->hook(worker->data1, worker->data2);
+ Execute(worker);
#endif
}
-void WebPWorkerEnd(WebPWorker* const worker) {
- if (worker->status_ >= OK) {
+static void End(WebPWorker* const worker) {
#ifdef WEBP_USE_THREAD
- WebPWorkerChangeState(worker, NOT_OK);
- pthread_join(worker->thread_, NULL);
- pthread_mutex_destroy(&worker->mutex_);
- pthread_cond_destroy(&worker->condition_);
+ if (worker->impl_ != NULL) {
+ ChangeState(worker, NOT_OK);
+ pthread_join(worker->impl_->thread_, NULL);
+ pthread_mutex_destroy(&worker->impl_->mutex_);
+ pthread_cond_destroy(&worker->impl_->condition_);
+ WebPSafeFree(worker->impl_);
+ worker->impl_ = NULL;
+ }
#else
- worker->status_ = NOT_OK;
+ worker->status_ = NOT_OK;
+ assert(worker->impl_ == NULL);
#endif
- }
assert(worker->status_ == NOT_OK);
}
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
+static WebPWorkerInterface g_worker_interface = {
+ Init, Reset, Sync, Launch, Execute, End
+};
+
+int WebPSetWorkerInterface(const WebPWorkerInterface* const winterface) {
+ if (winterface == NULL ||
+ winterface->Init == NULL || winterface->Reset == NULL ||
+ winterface->Sync == NULL || winterface->Launch == NULL ||
+ winterface->Execute == NULL || winterface->End == NULL) {
+ return 0;
+ }
+ g_worker_interface = *winterface;
+ return 1;
+}
+
+const WebPWorkerInterface* WebPGetWorkerInterface(void) {
+ return &g_worker_interface;
+}
+
+//------------------------------------------------------------------------------
diff --git a/drivers/webp/utils/thread.h b/drivers/webp/utils/thread.h
index 3191890b76..6008bb7c01 100644
--- a/drivers/webp/utils/thread.h
+++ b/drivers/webp/utils/thread.h
@@ -1,8 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Multi-threaded worker
@@ -12,29 +14,15 @@
#ifndef WEBP_UTILS_THREAD_H_
#define WEBP_UTILS_THREAD_H_
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
+#ifdef HAVE_CONFIG_H
+#include "webp/config.h"
#endif
-#if WEBP_USE_THREAD
-
-#if defined(_WIN32)
-
-#include <windows.h>
-typedef HANDLE pthread_t;
-typedef CRITICAL_SECTION pthread_mutex_t;
-typedef struct {
- HANDLE waiting_sem_;
- HANDLE received_sem_;
- HANDLE signal_event_;
-} pthread_cond_t;
+#include "webp/types.h"
-#else
-
-#include <pthread.h>
-
-#endif /* _WIN32 */
-#endif /* WEBP_USE_THREAD */
+#ifdef __cplusplus
+extern "C" {
+#endif
// State of the worker thread object
typedef enum {
@@ -47,13 +35,12 @@ typedef enum {
// arguments (data1 and data2), and should return false in case of error.
typedef int (*WebPWorkerHook)(void*, void*);
-// Synchronize object used to launch job in the worker thread
+// Platform-dependent implementation details for the worker.
+typedef struct WebPWorkerImpl WebPWorkerImpl;
+
+// Synchronization object used to launch job in the worker thread
typedef struct {
-#if WEBP_USE_THREAD
- pthread_mutex_t mutex_;
- pthread_cond_t condition_;
- pthread_t thread_;
-#endif
+ WebPWorkerImpl* impl_;
WebPWorkerStatus status_;
WebPWorkerHook hook; // hook to call
void* data1; // first argument passed to 'hook'
@@ -61,25 +48,45 @@ typedef struct {
int had_error; // return value of the last call to 'hook'
} WebPWorker;
-// Must be called first, before any other method.
-void WebPWorkerInit(WebPWorker* const worker);
-// Must be called initialize the object and spawn the thread. Re-entrant.
-// Will potentially launch the thread. Returns false in case of error.
-int WebPWorkerReset(WebPWorker* const worker);
-// Make sure the previous work is finished. Returns true if worker->had_error
-// was not set and not error condition was triggered by the working thread.
-int WebPWorkerSync(WebPWorker* const worker);
-// Trigger the thread to call hook() with data1 and data2 argument. These
-// hook/data1/data2 can be changed at any time before calling this function,
-// but not be changed afterward until the next call to WebPWorkerSync().
-void WebPWorkerLaunch(WebPWorker* const worker);
-// Kill the thread and terminate the object. To use the object again, one
-// must call WebPWorkerReset() again.
-void WebPWorkerEnd(WebPWorker* const worker);
+// The interface for all thread-worker related functions. All these functions
+// must be implemented.
+typedef struct {
+ // Must be called first, before any other method.
+ void (*Init)(WebPWorker* const worker);
+ // Must be called to initialize the object and spawn the thread. Re-entrant.
+ // Will potentially launch the thread. Returns false in case of error.
+ int (*Reset)(WebPWorker* const worker);
+ // Makes sure the previous work is finished. Returns true if worker->had_error
+ // was not set and no error condition was triggered by the working thread.
+ int (*Sync)(WebPWorker* const worker);
+ // Triggers the thread to call hook() with data1 and data2 arguments. These
+ // hook/data1/data2 values can be changed at any time before calling this
+ // function, but not be changed afterward until the next call to Sync().
+ void (*Launch)(WebPWorker* const worker);
+ // This function is similar to Launch() except that it calls the
+ // hook directly instead of using a thread. Convenient to bypass the thread
+ // mechanism while still using the WebPWorker structs. Sync() must
+ // still be called afterward (for error reporting).
+ void (*Execute)(WebPWorker* const worker);
+ // Kill the thread and terminate the object. To use the object again, one
+ // must call Reset() again.
+ void (*End)(WebPWorker* const worker);
+} WebPWorkerInterface;
+
+// Install a new set of threading functions, overriding the defaults. This
+// should be done before any workers are started, i.e., before any encoding or
+// decoding takes place. The contents of the interface struct are copied, it
+// is safe to free the corresponding memory after this call. This function is
+// not thread-safe. Return false in case of invalid pointer or methods.
+WEBP_EXTERN(int) WebPSetWorkerInterface(
+ const WebPWorkerInterface* const winterface);
+
+// Retrieve the currently set thread worker interface.
+WEBP_EXTERN(const WebPWorkerInterface*) WebPGetWorkerInterface(void);
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/drivers/webp/utils/utils.c b/drivers/webp/utils/utils.c
index 673b7e284c..35aeae6ab8 100644
--- a/drivers/webp/utils/utils.c
+++ b/drivers/webp/utils/utils.c
@@ -1,8 +1,10 @@
// Copyright 2012 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Misc. common utility functions
@@ -10,35 +12,228 @@
// Author: Skal (pascal.massimino@gmail.com)
#include <stdlib.h>
+#include <string.h> // for memcpy()
+#include "webp/decode.h"
+#include "webp/encode.h"
#include "./utils.h"
-#if defined(__cplusplus) || defined(c_plusplus)
-extern "C" {
-#endif
+// If PRINT_MEM_INFO is defined, extra info (like total memory used, number of
+// alloc/free etc) is printed. For debugging/tuning purpose only (it's slow,
+// and not multi-thread safe!).
+// An interesting alternative is valgrind's 'massif' tool:
+// http://valgrind.org/docs/manual/ms-manual.html
+// Here is an example command line:
+/* valgrind --tool=massif --massif-out-file=massif.out \
+ --stacks=yes --alloc-fn=WebPSafeAlloc --alloc-fn=WebPSafeCalloc
+ ms_print massif.out
+*/
+// In addition:
+// * if PRINT_MEM_TRAFFIC is defined, all the details of the malloc/free cycles
+// are printed.
+// * if MALLOC_FAIL_AT is defined, the global environment variable
+// $MALLOC_FAIL_AT is used to simulate a memory error when calloc or malloc
+// is called for the nth time. Example usage:
+// export MALLOC_FAIL_AT=50 && ./examples/cwebp input.png
+// * if MALLOC_LIMIT is defined, the global environment variable $MALLOC_LIMIT
+// sets the maximum amount of memory (in bytes) made available to libwebp.
+// This can be used to emulate environment with very limited memory.
+// Example: export MALLOC_LIMIT=64000000 && ./examples/dwebp picture.webp
+
+// #define PRINT_MEM_INFO
+// #define PRINT_MEM_TRAFFIC
+// #define MALLOC_FAIL_AT
+// #define MALLOC_LIMIT
//------------------------------------------------------------------------------
// Checked memory allocation
-static int CheckSizeArguments(uint64_t nmemb, size_t size) {
+#if defined(PRINT_MEM_INFO)
+
+#include <stdio.h>
+
+static int num_malloc_calls = 0;
+static int num_calloc_calls = 0;
+static int num_free_calls = 0;
+static int countdown_to_fail = 0; // 0 = off
+
+typedef struct MemBlock MemBlock;
+struct MemBlock {
+ void* ptr_;
+ size_t size_;
+ MemBlock* next_;
+};
+
+static MemBlock* all_blocks = NULL;
+static size_t total_mem = 0;
+static size_t total_mem_allocated = 0;
+static size_t high_water_mark = 0;
+static size_t mem_limit = 0;
+
+static int exit_registered = 0;
+
+static void PrintMemInfo(void) {
+ fprintf(stderr, "\nMEMORY INFO:\n");
+ fprintf(stderr, "num calls to: malloc = %4d\n", num_malloc_calls);
+ fprintf(stderr, " calloc = %4d\n", num_calloc_calls);
+ fprintf(stderr, " free = %4d\n", num_free_calls);
+ fprintf(stderr, "total_mem: %u\n", (uint32_t)total_mem);
+ fprintf(stderr, "total_mem allocated: %u\n", (uint32_t)total_mem_allocated);
+ fprintf(stderr, "high-water mark: %u\n", (uint32_t)high_water_mark);
+ while (all_blocks != NULL) {
+ MemBlock* b = all_blocks;
+ all_blocks = b->next_;
+ free(b);
+ }
+}
+
+static void Increment(int* const v) {
+ if (!exit_registered) {
+#if defined(MALLOC_FAIL_AT)
+ {
+ const char* const malloc_fail_at_str = getenv("MALLOC_FAIL_AT");
+ if (malloc_fail_at_str != NULL) {
+ countdown_to_fail = atoi(malloc_fail_at_str);
+ }
+ }
+#endif
+#if defined(MALLOC_LIMIT)
+ {
+ const char* const malloc_limit_str = getenv("MALLOC_LIMIT");
+ if (malloc_limit_str != NULL) {
+ mem_limit = atoi(malloc_limit_str);
+ }
+ }
+#endif
+ (void)countdown_to_fail;
+ (void)mem_limit;
+ atexit(PrintMemInfo);
+ exit_registered = 1;
+ }
+ ++*v;
+}
+
+static void AddMem(void* ptr, size_t size) {
+ if (ptr != NULL) {
+ MemBlock* const b = (MemBlock*)malloc(sizeof(*b));
+ if (b == NULL) abort();
+ b->next_ = all_blocks;
+ all_blocks = b;
+ b->ptr_ = ptr;
+ b->size_ = size;
+ total_mem += size;
+ total_mem_allocated += size;
+#if defined(PRINT_MEM_TRAFFIC)
+#if defined(MALLOC_FAIL_AT)
+ fprintf(stderr, "fail-count: %5d [mem=%u]\n",
+ num_malloc_calls + num_calloc_calls, (uint32_t)total_mem);
+#else
+ fprintf(stderr, "Mem: %u (+%u)\n", (uint32_t)total_mem, (uint32_t)size);
+#endif
+#endif
+ if (total_mem > high_water_mark) high_water_mark = total_mem;
+ }
+}
+
+static void SubMem(void* ptr) {
+ if (ptr != NULL) {
+ MemBlock** b = &all_blocks;
+ // Inefficient search, but that's just for debugging.
+ while (*b != NULL && (*b)->ptr_ != ptr) b = &(*b)->next_;
+ if (*b == NULL) {
+ fprintf(stderr, "Invalid pointer free! (%p)\n", ptr);
+ abort();
+ }
+ {
+ MemBlock* const block = *b;
+ *b = block->next_;
+ total_mem -= block->size_;
+#if defined(PRINT_MEM_TRAFFIC)
+ fprintf(stderr, "Mem: %u (-%u)\n",
+ (uint32_t)total_mem, (uint32_t)block->size_);
+#endif
+ free(block);
+ }
+ }
+}
+
+#else
+#define Increment(v) do {} while (0)
+#define AddMem(p, s) do {} while (0)
+#define SubMem(p) do {} while (0)
+#endif
+
+// Returns 0 in case of overflow of nmemb * size.
+static int CheckSizeArgumentsOverflow(uint64_t nmemb, size_t size) {
const uint64_t total_size = nmemb * size;
if (nmemb == 0) return 1;
if ((uint64_t)size > WEBP_MAX_ALLOCABLE_MEMORY / nmemb) return 0;
if (total_size != (size_t)total_size) return 0;
+#if defined(PRINT_MEM_INFO) && defined(MALLOC_FAIL_AT)
+ if (countdown_to_fail > 0 && --countdown_to_fail == 0) {
+ return 0; // fake fail!
+ }
+#endif
+#if defined(MALLOC_LIMIT)
+ if (mem_limit > 0 && total_mem + total_size >= mem_limit) {
+ return 0; // fake fail!
+ }
+#endif
+
return 1;
}
void* WebPSafeMalloc(uint64_t nmemb, size_t size) {
- if (!CheckSizeArguments(nmemb, size)) return NULL;
- return malloc((size_t)(nmemb * size));
+ void* ptr;
+ Increment(&num_malloc_calls);
+ if (!CheckSizeArgumentsOverflow(nmemb, size)) return NULL;
+ assert(nmemb * size > 0);
+ ptr = malloc((size_t)(nmemb * size));
+ AddMem(ptr, (size_t)(nmemb * size));
+ return ptr;
}
void* WebPSafeCalloc(uint64_t nmemb, size_t size) {
- if (!CheckSizeArguments(nmemb, size)) return NULL;
- return calloc((size_t)nmemb, size);
+ void* ptr;
+ Increment(&num_calloc_calls);
+ if (!CheckSizeArgumentsOverflow(nmemb, size)) return NULL;
+ assert(nmemb * size > 0);
+ ptr = calloc((size_t)nmemb, size);
+ AddMem(ptr, (size_t)(nmemb * size));
+ return ptr;
+}
+
+void WebPSafeFree(void* const ptr) {
+ if (ptr != NULL) {
+ Increment(&num_free_calls);
+ SubMem(ptr);
+ }
+ free(ptr);
+}
+
+// Public API function.
+void WebPFree(void* ptr) {
+ free(ptr);
}
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
-} // extern "C"
-#endif
+void WebPCopyPlane(const uint8_t* src, int src_stride,
+ uint8_t* dst, int dst_stride, int width, int height) {
+ assert(src != NULL && dst != NULL);
+ assert(src_stride >= width && dst_stride >= width);
+ while (height-- > 0) {
+ memcpy(dst, src, width);
+ src += src_stride;
+ dst += dst_stride;
+ }
+}
+
+void WebPCopyPixels(const WebPPicture* const src, WebPPicture* const dst) {
+ assert(src != NULL && dst != NULL);
+ assert(src->width == dst->width && src->height == dst->height);
+ assert(src->use_argb && dst->use_argb);
+ WebPCopyPlane((uint8_t*)src->argb, 4 * src->argb_stride, (uint8_t*)dst->argb,
+ 4 * dst->argb_stride, 4 * src->width, src->height);
+}
+
+//------------------------------------------------------------------------------
diff --git a/drivers/webp/utils/utils.h b/drivers/webp/utils/utils.h
index 316ac90612..d0e1cb250a 100644
--- a/drivers/webp/utils/utils.h
+++ b/drivers/webp/utils/utils.h
@@ -1,20 +1,25 @@
// Copyright 2012 Google Inc. All Rights Reserved.
//
-// This code is licensed under the same terms as WebM:
-// Software License Agreement: http://www.webmproject.org/license/software/
-// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// Use of this source code is governed by a BSD-style license
+// that can be found in the COPYING file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS. All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
// -----------------------------------------------------------------------------
//
// Misc. common utility functions
//
-// Author: Skal (pascal.massimino@gmail.com)
+// Authors: Skal (pascal.massimino@gmail.com)
+// Urvang (urvang@google.com)
#ifndef WEBP_UTILS_UTILS_H_
#define WEBP_UTILS_UTILS_H_
-#include "../types.h"
+#include <assert.h>
-#if defined(__cplusplus) || defined(c_plusplus)
+#include "webp/types.h"
+
+#ifdef __cplusplus
extern "C" {
#endif
@@ -30,14 +35,107 @@ extern "C" {
// somewhere (like: malloc(num_pixels * sizeof(*something))). That's why this
// safe malloc() borrows the signature from calloc(), pointing at the dangerous
// underlying multiply involved.
-void* WebPSafeMalloc(uint64_t nmemb, size_t size);
+WEBP_EXTERN(void*) WebPSafeMalloc(uint64_t nmemb, size_t size);
// Note that WebPSafeCalloc() expects the second argument type to be 'size_t'
// in order to favor the "calloc(num_foo, sizeof(foo))" pattern.
-void* WebPSafeCalloc(uint64_t nmemb, size_t size);
+WEBP_EXTERN(void*) WebPSafeCalloc(uint64_t nmemb, size_t size);
+
+// Companion deallocation function to the above allocations.
+WEBP_EXTERN(void) WebPSafeFree(void* const ptr);
+
+//------------------------------------------------------------------------------
+// Alignment
+
+#define WEBP_ALIGN_CST 31
+#define WEBP_ALIGN(PTR) ((uintptr_t)((PTR) + WEBP_ALIGN_CST) & ~WEBP_ALIGN_CST)
+
+//------------------------------------------------------------------------------
+// Reading/writing data.
+
+// Read 16, 24 or 32 bits stored in little-endian order.
+static WEBP_INLINE int GetLE16(const uint8_t* const data) {
+ return (int)(data[0] << 0) | (data[1] << 8);
+}
+
+static WEBP_INLINE int GetLE24(const uint8_t* const data) {
+ return GetLE16(data) | (data[2] << 16);
+}
+
+static WEBP_INLINE uint32_t GetLE32(const uint8_t* const data) {
+ return GetLE16(data) | ((uint32_t)GetLE16(data + 2) << 16);
+}
+
+// Store 16, 24 or 32 bits in little-endian order.
+static WEBP_INLINE void PutLE16(uint8_t* const data, int val) {
+ assert(val < (1 << 16));
+ data[0] = (val >> 0);
+ data[1] = (val >> 8);
+}
+
+static WEBP_INLINE void PutLE24(uint8_t* const data, int val) {
+ assert(val < (1 << 24));
+ PutLE16(data, val & 0xffff);
+ data[2] = (val >> 16);
+}
+
+static WEBP_INLINE void PutLE32(uint8_t* const data, uint32_t val) {
+ PutLE16(data, (int)(val & 0xffff));
+ PutLE16(data + 2, (int)(val >> 16));
+}
+
+// Returns (int)floor(log2(n)). n must be > 0.
+// use GNU builtins where available.
+#if defined(__GNUC__) && \
+ ((__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || __GNUC__ >= 4)
+static WEBP_INLINE int BitsLog2Floor(uint32_t n) {
+ return 31 ^ __builtin_clz(n);
+}
+#elif defined(_MSC_VER) && _MSC_VER > 1310 && \
+ (defined(_M_X64) || defined(_M_IX86))
+#include <intrin.h>
+#pragma intrinsic(_BitScanReverse)
+
+static WEBP_INLINE int BitsLog2Floor(uint32_t n) {
+ unsigned long first_set_bit;
+ _BitScanReverse(&first_set_bit, n);
+ return first_set_bit;
+}
+#else
+static WEBP_INLINE int BitsLog2Floor(uint32_t n) {
+ int log = 0;
+ uint32_t value = n;
+ int i;
+
+ for (i = 4; i >= 0; --i) {
+ const int shift = (1 << i);
+ const uint32_t x = value >> shift;
+ if (x != 0) {
+ value = x;
+ log += shift;
+ }
+ }
+ return log;
+}
+#endif
+
+//------------------------------------------------------------------------------
+// Pixel copying.
+
+struct WebPPicture;
+
+// Copy width x height pixels from 'src' to 'dst' honoring the strides.
+WEBP_EXTERN(void) WebPCopyPlane(const uint8_t* src, int src_stride,
+ uint8_t* dst, int dst_stride,
+ int width, int height);
+
+// Copy ARGB pixels from 'src' to 'dst' honoring strides. 'src' and 'dst' are
+// assumed to be already allocated and using ARGB data.
+WEBP_EXTERN(void) WebPCopyPixels(const struct WebPPicture* const src,
+ struct WebPPicture* const dst);
//------------------------------------------------------------------------------
-#if defined(__cplusplus) || defined(c_plusplus)
+#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/drivers/webpold/SCsub b/drivers/webpold/SCsub
new file mode 100644
index 0000000000..5596edbe09
--- /dev/null
+++ b/drivers/webpold/SCsub
@@ -0,0 +1,63 @@
+Import('env')
+
+
+webp_sources = [
+ "webp/mux/muxedit.c",
+ "webp/mux/muxread.c",
+ "webp/mux/muxinternal.c",
+ "webp/mux/demux.c",
+ "webp/enc/tree.c",
+ "webp/enc/analysis.c",
+ "webp/enc/backward_references.c",
+ "webp/enc/alpha.c",
+ "webp/enc/picture.c",
+ "webp/enc/frame.c",
+ "webp/enc/webpenc.c",
+ "webp/enc/cost.c",
+ "webp/enc/filter.c",
+ "webp/enc/vp8l.c",
+ "webp/enc/quant.c",
+ "webp/enc/histogram.c",
+ "webp/enc/syntax.c",
+ "webp/enc/config.c",
+ "webp/enc/layer.c",
+ "webp/enc/iterator.c",
+ "webp/dsp/dec_sse2.c",
+ "webp/dsp/upsampling_sse2.c",
+ "webp/dsp/dec_neon.c",
+ "webp/dsp/enc.c",
+ "webp/dsp/enc_sse2.c",
+ "webp/dsp/upsampling.c",
+ "webp/dsp/lossless.c",
+ "webp/dsp/cpu.c",
+ "webp/dsp/dec.c",
+ "webp/dsp/yuv.c",
+ "webp/utils/bit_reader.c",
+ "webp/utils/filters.c",
+ "webp/utils/bit_writer.c",
+ "webp/utils/thread.c",
+ "webp/utils/quant_levels.c",
+ "webp/utils/color_cache.c",
+ "webp/utils/rescaler.c",
+ "webp/utils/utils.c",
+ "webp/utils/huffman.c",
+ "webp/utils/huffman_encode.c",
+ "webp/dec/tree.c",
+ "webp/dec/alpha.c",
+ "webp/dec/frame.c",
+ "webp/dec/vp8l.c",
+ "webp/dec/vp8.c",
+ "webp/dec/quant.c",
+ "webp/dec/webp.c",
+ "webp/dec/buffer.c",
+ "webp/dec/io.c",
+ "webp/dec/layer.c",
+ "webp/dec/idec.c",
+ "webp/image_loader_webp.cpp"
+]
+
+env.drivers_sources+=webp_sources
+
+#env.add_source_files(env.drivers_sources, webp_sources)
+
+Export('env')
diff --git a/drivers/webpold/dec/alpha.c b/drivers/webpold/dec/alpha.c
new file mode 100644
index 0000000000..d1095fa555
--- /dev/null
+++ b/drivers/webpold/dec/alpha.c
@@ -0,0 +1,140 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Alpha-plane decompression.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <stdlib.h>
+#include "./vp8i.h"
+#include "./vp8li.h"
+#include "../utils/filters.h"
+#include "../utils/quant_levels.h"
+#include "../format_constants.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+// TODO(skal): move to dsp/ ?
+static void CopyPlane(const uint8_t* src, int src_stride,
+ uint8_t* dst, int dst_stride, int width, int height) {
+ while (height-- > 0) {
+ memcpy(dst, src, width);
+ src += src_stride;
+ dst += dst_stride;
+ }
+}
+
+//------------------------------------------------------------------------------
+// Decodes the compressed data 'data' of size 'data_size' into the 'output'.
+// The 'output' buffer should be pre-allocated and must be of the same
+// dimension 'height'x'stride', as that of the image.
+//
+// Returns 1 on successfully decoding the compressed alpha and
+// 0 if either:
+// error in bit-stream header (invalid compression mode or filter), or
+// error returned by appropriate compression method.
+
+static int DecodeAlpha(const uint8_t* data, size_t data_size,
+ int width, int height, int stride, uint8_t* output) {
+ uint8_t* decoded_data = NULL;
+ const size_t decoded_size = height * width;
+ uint8_t* unfiltered_data = NULL;
+ WEBP_FILTER_TYPE filter;
+ int pre_processing;
+ int rsrv;
+ int ok = 0;
+ int method;
+
+ assert(width > 0 && height > 0 && stride >= width);
+ assert(data != NULL && output != NULL);
+
+ if (data_size <= ALPHA_HEADER_LEN) {
+ return 0;
+ }
+
+ method = (data[0] >> 0) & 0x03;
+ filter = (data[0] >> 2) & 0x03;
+ pre_processing = (data[0] >> 4) & 0x03;
+ rsrv = (data[0] >> 6) & 0x03;
+ if (method < ALPHA_NO_COMPRESSION ||
+ method > ALPHA_LOSSLESS_COMPRESSION ||
+ filter >= WEBP_FILTER_LAST ||
+ pre_processing > ALPHA_PREPROCESSED_LEVELS ||
+ rsrv != 0) {
+ return 0;
+ }
+
+ if (method == ALPHA_NO_COMPRESSION) {
+ ok = (data_size >= decoded_size);
+ decoded_data = (uint8_t*)data + ALPHA_HEADER_LEN;
+ } else {
+ decoded_data = (uint8_t*)malloc(decoded_size);
+ if (decoded_data == NULL) return 0;
+ ok = VP8LDecodeAlphaImageStream(width, height,
+ data + ALPHA_HEADER_LEN,
+ data_size - ALPHA_HEADER_LEN,
+ decoded_data);
+ }
+
+ if (ok) {
+ WebPFilterFunc unfilter_func = WebPUnfilters[filter];
+ if (unfilter_func != NULL) {
+ unfiltered_data = (uint8_t*)malloc(decoded_size);
+ if (unfiltered_data == NULL) {
+ ok = 0;
+ goto Error;
+ }
+ // TODO(vikas): Implement on-the-fly decoding & filter mechanism to decode
+ // and apply filter per image-row.
+ unfilter_func(decoded_data, width, height, 1, width, unfiltered_data);
+ // Construct raw_data (height x stride) from alpha data (height x width).
+ CopyPlane(unfiltered_data, width, output, stride, width, height);
+ free(unfiltered_data);
+ } else {
+ // Construct raw_data (height x stride) from alpha data (height x width).
+ CopyPlane(decoded_data, width, output, stride, width, height);
+ }
+ if (pre_processing == ALPHA_PREPROCESSED_LEVELS) {
+ ok = DequantizeLevels(decoded_data, width, height);
+ }
+ }
+
+ Error:
+ if (method != ALPHA_NO_COMPRESSION) {
+ free(decoded_data);
+ }
+ return ok;
+}
+
+//------------------------------------------------------------------------------
+
+const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
+ int row, int num_rows) {
+ const int stride = dec->pic_hdr_.width_;
+
+ if (row < 0 || num_rows < 0 || row + num_rows > dec->pic_hdr_.height_) {
+ return NULL; // sanity check.
+ }
+
+ if (row == 0) {
+ // Decode everything during the first call.
+ if (!DecodeAlpha(dec->alpha_data_, (size_t)dec->alpha_data_size_,
+ dec->pic_hdr_.width_, dec->pic_hdr_.height_, stride,
+ dec->alpha_plane_)) {
+ return NULL; // Error.
+ }
+ }
+
+ // Return a pointer to the current decoded row.
+ return dec->alpha_plane_ + row * stride;
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/dec/buffer.c b/drivers/webpold/dec/buffer.c
new file mode 100644
index 0000000000..c159f6f248
--- /dev/null
+++ b/drivers/webpold/dec/buffer.c
@@ -0,0 +1,215 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Everything about WebPDecBuffer
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <stdlib.h>
+
+#include "./vp8i.h"
+#include "./webpi.h"
+#include "../utils/utils.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// WebPDecBuffer
+
+// Number of bytes per pixel for the different color-spaces.
+static const int kModeBpp[MODE_LAST] = {
+ 3, 4, 3, 4, 4, 2, 2,
+ 4, 4, 4, 2, // pre-multiplied modes
+ 1, 1 };
+
+// Check that webp_csp_mode is within the bounds of WEBP_CSP_MODE.
+// Convert to an integer to handle both the unsigned/signed enum cases
+// without the need for casting to remove type limit warnings.
+static int IsValidColorspace(int webp_csp_mode) {
+ return (webp_csp_mode >= MODE_RGB && webp_csp_mode < MODE_LAST);
+}
+
+static VP8StatusCode CheckDecBuffer(const WebPDecBuffer* const buffer) {
+ int ok = 1;
+ const WEBP_CSP_MODE mode = buffer->colorspace;
+ const int width = buffer->width;
+ const int height = buffer->height;
+ if (!IsValidColorspace(mode)) {
+ ok = 0;
+ } else if (!WebPIsRGBMode(mode)) { // YUV checks
+ const WebPYUVABuffer* const buf = &buffer->u.YUVA;
+ const uint64_t y_size = (uint64_t)buf->y_stride * height;
+ const uint64_t u_size = (uint64_t)buf->u_stride * ((height + 1) / 2);
+ const uint64_t v_size = (uint64_t)buf->v_stride * ((height + 1) / 2);
+ const uint64_t a_size = (uint64_t)buf->a_stride * height;
+ ok &= (y_size <= buf->y_size);
+ ok &= (u_size <= buf->u_size);
+ ok &= (v_size <= buf->v_size);
+ ok &= (buf->y_stride >= width);
+ ok &= (buf->u_stride >= (width + 1) / 2);
+ ok &= (buf->v_stride >= (width + 1) / 2);
+ ok &= (buf->y != NULL);
+ ok &= (buf->u != NULL);
+ ok &= (buf->v != NULL);
+ if (mode == MODE_YUVA) {
+ ok &= (buf->a_stride >= width);
+ ok &= (a_size <= buf->a_size);
+ ok &= (buf->a != NULL);
+ }
+ } else { // RGB checks
+ const WebPRGBABuffer* const buf = &buffer->u.RGBA;
+ const uint64_t size = (uint64_t)buf->stride * height;
+ ok &= (size <= buf->size);
+ ok &= (buf->stride >= width * kModeBpp[mode]);
+ ok &= (buf->rgba != NULL);
+ }
+ return ok ? VP8_STATUS_OK : VP8_STATUS_INVALID_PARAM;
+}
+
+static VP8StatusCode AllocateBuffer(WebPDecBuffer* const buffer) {
+ const int w = buffer->width;
+ const int h = buffer->height;
+ const WEBP_CSP_MODE mode = buffer->colorspace;
+
+ if (w <= 0 || h <= 0 || !IsValidColorspace(mode)) {
+ return VP8_STATUS_INVALID_PARAM;
+ }
+
+ if (!buffer->is_external_memory && buffer->private_memory == NULL) {
+ uint8_t* output;
+ int uv_stride = 0, a_stride = 0;
+ uint64_t uv_size = 0, a_size = 0, total_size;
+ // We need memory and it hasn't been allocated yet.
+ // => initialize output buffer, now that dimensions are known.
+ const int stride = w * kModeBpp[mode];
+ const uint64_t size = (uint64_t)stride * h;
+
+ if (!WebPIsRGBMode(mode)) {
+ uv_stride = (w + 1) / 2;
+ uv_size = (uint64_t)uv_stride * ((h + 1) / 2);
+ if (mode == MODE_YUVA) {
+ a_stride = w;
+ a_size = (uint64_t)a_stride * h;
+ }
+ }
+ total_size = size + 2 * uv_size + a_size;
+
+ // Security/sanity checks
+ output = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*output));
+ if (output == NULL) {
+ return VP8_STATUS_OUT_OF_MEMORY;
+ }
+ buffer->private_memory = output;
+
+ if (!WebPIsRGBMode(mode)) { // YUVA initialization
+ WebPYUVABuffer* const buf = &buffer->u.YUVA;
+ buf->y = output;
+ buf->y_stride = stride;
+ buf->y_size = (size_t)size;
+ buf->u = output + size;
+ buf->u_stride = uv_stride;
+ buf->u_size = (size_t)uv_size;
+ buf->v = output + size + uv_size;
+ buf->v_stride = uv_stride;
+ buf->v_size = (size_t)uv_size;
+ if (mode == MODE_YUVA) {
+ buf->a = output + size + 2 * uv_size;
+ }
+ buf->a_size = (size_t)a_size;
+ buf->a_stride = a_stride;
+ } else { // RGBA initialization
+ WebPRGBABuffer* const buf = &buffer->u.RGBA;
+ buf->rgba = output;
+ buf->stride = stride;
+ buf->size = (size_t)size;
+ }
+ }
+ return CheckDecBuffer(buffer);
+}
+
+VP8StatusCode WebPAllocateDecBuffer(int w, int h,
+ const WebPDecoderOptions* const options,
+ WebPDecBuffer* const out) {
+ if (out == NULL || w <= 0 || h <= 0) {
+ return VP8_STATUS_INVALID_PARAM;
+ }
+ if (options != NULL) { // First, apply options if there is any.
+ if (options->use_cropping) {
+ const int cw = options->crop_width;
+ const int ch = options->crop_height;
+ const int x = options->crop_left & ~1;
+ const int y = options->crop_top & ~1;
+ if (x < 0 || y < 0 || cw <= 0 || ch <= 0 || x + cw > w || y + ch > h) {
+ return VP8_STATUS_INVALID_PARAM; // out of frame boundary.
+ }
+ w = cw;
+ h = ch;
+ }
+ if (options->use_scaling) {
+ if (options->scaled_width <= 0 || options->scaled_height <= 0) {
+ return VP8_STATUS_INVALID_PARAM;
+ }
+ w = options->scaled_width;
+ h = options->scaled_height;
+ }
+ }
+ out->width = w;
+ out->height = h;
+
+ // Then, allocate buffer for real
+ return AllocateBuffer(out);
+}
+
+//------------------------------------------------------------------------------
+// constructors / destructors
+
+int WebPInitDecBufferInternal(WebPDecBuffer* buffer, int version) {
+ if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) {
+ return 0; // version mismatch
+ }
+ if (buffer == NULL) return 0;
+ memset(buffer, 0, sizeof(*buffer));
+ return 1;
+}
+
+void WebPFreeDecBuffer(WebPDecBuffer* buffer) {
+ if (buffer != NULL) {
+ if (!buffer->is_external_memory)
+ free(buffer->private_memory);
+ buffer->private_memory = NULL;
+ }
+}
+
+void WebPCopyDecBuffer(const WebPDecBuffer* const src,
+ WebPDecBuffer* const dst) {
+ if (src != NULL && dst != NULL) {
+ *dst = *src;
+ if (src->private_memory != NULL) {
+ dst->is_external_memory = 1; // dst buffer doesn't own the memory.
+ dst->private_memory = NULL;
+ }
+ }
+}
+
+// Copy and transfer ownership from src to dst (beware of parameter order!)
+void WebPGrabDecBuffer(WebPDecBuffer* const src, WebPDecBuffer* const dst) {
+ if (src != NULL && dst != NULL) {
+ *dst = *src;
+ if (src->private_memory != NULL) {
+ src->is_external_memory = 1; // src relinquishes ownership
+ src->private_memory = NULL;
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/dec/decode_vp8.h b/drivers/webpold/dec/decode_vp8.h
new file mode 100644
index 0000000000..c26a9fc891
--- /dev/null
+++ b/drivers/webpold/dec/decode_vp8.h
@@ -0,0 +1,182 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Low-level API for VP8 decoder
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#ifndef WEBP_WEBP_DECODE_VP8_H_
+#define WEBP_WEBP_DECODE_VP8_H_
+
+#include "../decode.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// Lower-level API
+//
+// These functions provide fine-grained control of the decoding process.
+// The call flow should resemble:
+//
+// VP8Io io;
+// VP8InitIo(&io);
+// io.data = data;
+// io.data_size = size;
+// /* customize io's functions (setup()/put()/teardown()) if needed. */
+//
+// VP8Decoder* dec = VP8New();
+// bool ok = VP8Decode(dec);
+// if (!ok) printf("Error: %s\n", VP8StatusMessage(dec));
+// VP8Delete(dec);
+// return ok;
+
+// Input / Output
+typedef struct VP8Io VP8Io;
+typedef int (*VP8IoPutHook)(const VP8Io* io);
+typedef int (*VP8IoSetupHook)(VP8Io* io);
+typedef void (*VP8IoTeardownHook)(const VP8Io* io);
+
+struct VP8Io {
+ // set by VP8GetHeaders()
+ int width, height; // picture dimensions, in pixels (invariable).
+ // These are the original, uncropped dimensions.
+ // The actual area passed to put() is stored
+ // in mb_w / mb_h fields.
+
+ // set before calling put()
+ int mb_y; // position of the current rows (in pixels)
+ int mb_w; // number of columns in the sample
+ int mb_h; // number of rows in the sample
+ const uint8_t* y, *u, *v; // rows to copy (in yuv420 format)
+ int y_stride; // row stride for luma
+ int uv_stride; // row stride for chroma
+
+ void* opaque; // user data
+
+ // called when fresh samples are available. Currently, samples are in
+ // YUV420 format, and can be up to width x 24 in size (depending on the
+ // in-loop filtering level, e.g.). Should return false in case of error
+ // or abort request. The actual size of the area to update is mb_w x mb_h
+ // in size, taking cropping into account.
+ VP8IoPutHook put;
+
+ // called just before starting to decode the blocks.
+ // Must return false in case of setup error, true otherwise. If false is
+ // returned, teardown() will NOT be called. But if the setup succeeded
+ // and true is returned, then teardown() will always be called afterward.
+ VP8IoSetupHook setup;
+
+ // Called just after block decoding is finished (or when an error occurred
+ // during put()). Is NOT called if setup() failed.
+ VP8IoTeardownHook teardown;
+
+ // this is a recommendation for the user-side yuv->rgb converter. This flag
+ // is set when calling setup() hook and can be overwritten by it. It then
+ // can be taken into consideration during the put() method.
+ int fancy_upsampling;
+
+ // Input buffer.
+ size_t data_size;
+ const uint8_t* data;
+
+ // If true, in-loop filtering will not be performed even if present in the
+ // bitstream. Switching off filtering may speed up decoding at the expense
+ // of more visible blocking. Note that output will also be non-compliant
+ // with the VP8 specifications.
+ int bypass_filtering;
+
+ // Cropping parameters.
+ int use_cropping;
+ int crop_left, crop_right, crop_top, crop_bottom;
+
+ // Scaling parameters.
+ int use_scaling;
+ int scaled_width, scaled_height;
+
+ // If non NULL, pointer to the alpha data (if present) corresponding to the
+ // start of the current row (That is: it is pre-offset by mb_y and takes
+ // cropping into account).
+ const uint8_t* a;
+};
+
+// Internal, version-checked, entry point
+int VP8InitIoInternal(VP8Io* const, int);
+
+// Set the custom IO function pointers and user-data. The setter for IO hooks
+// should be called before initiating incremental decoding. Returns true if
+// WebPIDecoder object is successfully modified, false otherwise.
+int WebPISetIOHooks(WebPIDecoder* const idec,
+ VP8IoPutHook put,
+ VP8IoSetupHook setup,
+ VP8IoTeardownHook teardown,
+ void* user_data);
+
+// Main decoding object. This is an opaque structure.
+typedef struct VP8Decoder VP8Decoder;
+
+// Create a new decoder object.
+VP8Decoder* VP8New(void);
+
+// Must be called to make sure 'io' is initialized properly.
+// Returns false in case of version mismatch. Upon such failure, no other
+// decoding function should be called (VP8Decode, VP8GetHeaders, ...)
+static WEBP_INLINE int VP8InitIo(VP8Io* const io) {
+ return VP8InitIoInternal(io, WEBP_DECODER_ABI_VERSION);
+}
+
+// Start decoding a new picture. Returns true if ok.
+int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io);
+
+// Decode a picture. Will call VP8GetHeaders() if it wasn't done already.
+// Returns false in case of error.
+int VP8Decode(VP8Decoder* const dec, VP8Io* const io);
+
+// Return current status of the decoder:
+VP8StatusCode VP8Status(VP8Decoder* const dec);
+
+// return readable string corresponding to the last status.
+const char* VP8StatusMessage(VP8Decoder* const dec);
+
+// Resets the decoder in its initial state, reclaiming memory.
+// Not a mandatory call between calls to VP8Decode().
+void VP8Clear(VP8Decoder* const dec);
+
+// Destroy the decoder object.
+void VP8Delete(VP8Decoder* const dec);
+
+//------------------------------------------------------------------------------
+// Miscellaneous VP8/VP8L bitstream probing functions.
+
+// Returns true if the next 3 bytes in data contain the VP8 signature.
+WEBP_EXTERN(int) VP8CheckSignature(const uint8_t* const data, size_t data_size);
+
+// Validates the VP8 data-header and retrieves basic header information viz
+// width and height. Returns 0 in case of formatting error. *width/*height
+// can be passed NULL.
+WEBP_EXTERN(int) VP8GetInfo(
+ const uint8_t* data,
+ size_t data_size, // data available so far
+ size_t chunk_size, // total data size expected in the chunk
+ int* const width, int* const height);
+
+// Returns true if the next byte(s) in data is a VP8L signature.
+WEBP_EXTERN(int) VP8LCheckSignature(const uint8_t* const data, size_t size);
+
+// Validates the VP8L data-header and retrieves basic header information viz
+// width, height and alpha. Returns 0 in case of formatting error.
+// width/height/has_alpha can be passed NULL.
+WEBP_EXTERN(int) VP8LGetInfo(
+ const uint8_t* data, size_t data_size, // data available so far
+ int* const width, int* const height, int* const has_alpha);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif /* WEBP_WEBP_DECODE_VP8_H_ */
diff --git a/drivers/webpold/dec/frame.c b/drivers/webpold/dec/frame.c
new file mode 100644
index 0000000000..9c91a48e17
--- /dev/null
+++ b/drivers/webpold/dec/frame.c
@@ -0,0 +1,679 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Frame-reconstruction function. Memory allocation.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <stdlib.h>
+#include "./vp8i.h"
+#include "../utils/utils.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define ALIGN_MASK (32 - 1)
+
+//------------------------------------------------------------------------------
+// Filtering
+
+// kFilterExtraRows[] = How many extra lines are needed on the MB boundary
+// for caching, given a filtering level.
+// Simple filter: up to 2 luma samples are read and 1 is written.
+// Complex filter: up to 4 luma samples are read and 3 are written. Same for
+// U/V, so it's 8 samples total (because of the 2x upsampling).
+static const uint8_t kFilterExtraRows[3] = { 0, 2, 8 };
+
+static WEBP_INLINE int hev_thresh_from_level(int level, int keyframe) {
+ if (keyframe) {
+ return (level >= 40) ? 2 : (level >= 15) ? 1 : 0;
+ } else {
+ return (level >= 40) ? 3 : (level >= 20) ? 2 : (level >= 15) ? 1 : 0;
+ }
+}
+
+static void DoFilter(const VP8Decoder* const dec, int mb_x, int mb_y) {
+ const VP8ThreadContext* const ctx = &dec->thread_ctx_;
+ const int y_bps = dec->cache_y_stride_;
+ VP8FInfo* const f_info = ctx->f_info_ + mb_x;
+ uint8_t* const y_dst = dec->cache_y_ + ctx->id_ * 16 * y_bps + mb_x * 16;
+ const int level = f_info->f_level_;
+ const int ilevel = f_info->f_ilevel_;
+ const int limit = 2 * level + ilevel;
+ if (level == 0) {
+ return;
+ }
+ if (dec->filter_type_ == 1) { // simple
+ if (mb_x > 0) {
+ VP8SimpleHFilter16(y_dst, y_bps, limit + 4);
+ }
+ if (f_info->f_inner_) {
+ VP8SimpleHFilter16i(y_dst, y_bps, limit);
+ }
+ if (mb_y > 0) {
+ VP8SimpleVFilter16(y_dst, y_bps, limit + 4);
+ }
+ if (f_info->f_inner_) {
+ VP8SimpleVFilter16i(y_dst, y_bps, limit);
+ }
+ } else { // complex
+ const int uv_bps = dec->cache_uv_stride_;
+ uint8_t* const u_dst = dec->cache_u_ + ctx->id_ * 8 * uv_bps + mb_x * 8;
+ uint8_t* const v_dst = dec->cache_v_ + ctx->id_ * 8 * uv_bps + mb_x * 8;
+ const int hev_thresh =
+ hev_thresh_from_level(level, dec->frm_hdr_.key_frame_);
+ if (mb_x > 0) {
+ VP8HFilter16(y_dst, y_bps, limit + 4, ilevel, hev_thresh);
+ VP8HFilter8(u_dst, v_dst, uv_bps, limit + 4, ilevel, hev_thresh);
+ }
+ if (f_info->f_inner_) {
+ VP8HFilter16i(y_dst, y_bps, limit, ilevel, hev_thresh);
+ VP8HFilter8i(u_dst, v_dst, uv_bps, limit, ilevel, hev_thresh);
+ }
+ if (mb_y > 0) {
+ VP8VFilter16(y_dst, y_bps, limit + 4, ilevel, hev_thresh);
+ VP8VFilter8(u_dst, v_dst, uv_bps, limit + 4, ilevel, hev_thresh);
+ }
+ if (f_info->f_inner_) {
+ VP8VFilter16i(y_dst, y_bps, limit, ilevel, hev_thresh);
+ VP8VFilter8i(u_dst, v_dst, uv_bps, limit, ilevel, hev_thresh);
+ }
+ }
+}
+
+// Filter the decoded macroblock row (if needed)
+static void FilterRow(const VP8Decoder* const dec) {
+ int mb_x;
+ const int mb_y = dec->thread_ctx_.mb_y_;
+ assert(dec->thread_ctx_.filter_row_);
+ for (mb_x = dec->tl_mb_x_; mb_x < dec->br_mb_x_; ++mb_x) {
+ DoFilter(dec, mb_x, mb_y);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+void VP8StoreBlock(VP8Decoder* const dec) {
+ if (dec->filter_type_ > 0) {
+ VP8FInfo* const info = dec->f_info_ + dec->mb_x_;
+ const int skip = dec->mb_info_[dec->mb_x_].skip_;
+ int level = dec->filter_levels_[dec->segment_];
+ if (dec->filter_hdr_.use_lf_delta_) {
+ // TODO(skal): only CURRENT is handled for now.
+ level += dec->filter_hdr_.ref_lf_delta_[0];
+ if (dec->is_i4x4_) {
+ level += dec->filter_hdr_.mode_lf_delta_[0];
+ }
+ }
+ level = (level < 0) ? 0 : (level > 63) ? 63 : level;
+ info->f_level_ = level;
+
+ if (dec->filter_hdr_.sharpness_ > 0) {
+ if (dec->filter_hdr_.sharpness_ > 4) {
+ level >>= 2;
+ } else {
+ level >>= 1;
+ }
+ if (level > 9 - dec->filter_hdr_.sharpness_) {
+ level = 9 - dec->filter_hdr_.sharpness_;
+ }
+ }
+
+ info->f_ilevel_ = (level < 1) ? 1 : level;
+ info->f_inner_ = (!skip || dec->is_i4x4_);
+ }
+ {
+ // Transfer samples to row cache
+ int y;
+ const int y_offset = dec->cache_id_ * 16 * dec->cache_y_stride_;
+ const int uv_offset = dec->cache_id_ * 8 * dec->cache_uv_stride_;
+ uint8_t* const ydst = dec->cache_y_ + dec->mb_x_ * 16 + y_offset;
+ uint8_t* const udst = dec->cache_u_ + dec->mb_x_ * 8 + uv_offset;
+ uint8_t* const vdst = dec->cache_v_ + dec->mb_x_ * 8 + uv_offset;
+ for (y = 0; y < 16; ++y) {
+ memcpy(ydst + y * dec->cache_y_stride_,
+ dec->yuv_b_ + Y_OFF + y * BPS, 16);
+ }
+ for (y = 0; y < 8; ++y) {
+ memcpy(udst + y * dec->cache_uv_stride_,
+ dec->yuv_b_ + U_OFF + y * BPS, 8);
+ memcpy(vdst + y * dec->cache_uv_stride_,
+ dec->yuv_b_ + V_OFF + y * BPS, 8);
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+// This function is called after a row of macroblocks is finished decoding.
+// It also takes into account the following restrictions:
+// * In case of in-loop filtering, we must hold off sending some of the bottom
+// pixels as they are yet unfiltered. They will be when the next macroblock
+// row is decoded. Meanwhile, we must preserve them by rotating them in the
+// cache area. This doesn't hold for the very bottom row of the uncropped
+// picture of course.
+// * we must clip the remaining pixels against the cropping area. The VP8Io
+// struct must have the following fields set correctly before calling put():
+
+#define MACROBLOCK_VPOS(mb_y) ((mb_y) * 16) // vertical position of a MB
+
+// Finalize and transmit a complete row. Return false in case of user-abort.
+static int FinishRow(VP8Decoder* const dec, VP8Io* const io) {
+ int ok = 1;
+ const VP8ThreadContext* const ctx = &dec->thread_ctx_;
+ const int extra_y_rows = kFilterExtraRows[dec->filter_type_];
+ const int ysize = extra_y_rows * dec->cache_y_stride_;
+ const int uvsize = (extra_y_rows / 2) * dec->cache_uv_stride_;
+ const int y_offset = ctx->id_ * 16 * dec->cache_y_stride_;
+ const int uv_offset = ctx->id_ * 8 * dec->cache_uv_stride_;
+ uint8_t* const ydst = dec->cache_y_ - ysize + y_offset;
+ uint8_t* const udst = dec->cache_u_ - uvsize + uv_offset;
+ uint8_t* const vdst = dec->cache_v_ - uvsize + uv_offset;
+ const int first_row = (ctx->mb_y_ == 0);
+ const int last_row = (ctx->mb_y_ >= dec->br_mb_y_ - 1);
+ int y_start = MACROBLOCK_VPOS(ctx->mb_y_);
+ int y_end = MACROBLOCK_VPOS(ctx->mb_y_ + 1);
+
+ if (ctx->filter_row_) {
+ FilterRow(dec);
+ }
+
+ if (io->put) {
+ if (!first_row) {
+ y_start -= extra_y_rows;
+ io->y = ydst;
+ io->u = udst;
+ io->v = vdst;
+ } else {
+ io->y = dec->cache_y_ + y_offset;
+ io->u = dec->cache_u_ + uv_offset;
+ io->v = dec->cache_v_ + uv_offset;
+ }
+
+ if (!last_row) {
+ y_end -= extra_y_rows;
+ }
+ if (y_end > io->crop_bottom) {
+ y_end = io->crop_bottom; // make sure we don't overflow on last row.
+ }
+ io->a = NULL;
+ if (dec->alpha_data_ != NULL && y_start < y_end) {
+ // TODO(skal): several things to correct here:
+ // * testing presence of alpha with dec->alpha_data_ is not a good idea
+ // * we're actually decompressing the full plane only once. It should be
+ // more obvious from signature.
+ // * we could free alpha_data_ right after this call, but we don't own.
+ io->a = VP8DecompressAlphaRows(dec, y_start, y_end - y_start);
+ if (io->a == NULL) {
+ return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
+ "Could not decode alpha data.");
+ }
+ }
+ if (y_start < io->crop_top) {
+ const int delta_y = io->crop_top - y_start;
+ y_start = io->crop_top;
+ assert(!(delta_y & 1));
+ io->y += dec->cache_y_stride_ * delta_y;
+ io->u += dec->cache_uv_stride_ * (delta_y >> 1);
+ io->v += dec->cache_uv_stride_ * (delta_y >> 1);
+ if (io->a != NULL) {
+ io->a += io->width * delta_y;
+ }
+ }
+ if (y_start < y_end) {
+ io->y += io->crop_left;
+ io->u += io->crop_left >> 1;
+ io->v += io->crop_left >> 1;
+ if (io->a != NULL) {
+ io->a += io->crop_left;
+ }
+ io->mb_y = y_start - io->crop_top;
+ io->mb_w = io->crop_right - io->crop_left;
+ io->mb_h = y_end - y_start;
+ ok = io->put(io);
+ }
+ }
+ // rotate top samples if needed
+ if (ctx->id_ + 1 == dec->num_caches_) {
+ if (!last_row) {
+ memcpy(dec->cache_y_ - ysize, ydst + 16 * dec->cache_y_stride_, ysize);
+ memcpy(dec->cache_u_ - uvsize, udst + 8 * dec->cache_uv_stride_, uvsize);
+ memcpy(dec->cache_v_ - uvsize, vdst + 8 * dec->cache_uv_stride_, uvsize);
+ }
+ }
+
+ return ok;
+}
+
+#undef MACROBLOCK_VPOS
+
+//------------------------------------------------------------------------------
+
+int VP8ProcessRow(VP8Decoder* const dec, VP8Io* const io) {
+ int ok = 1;
+ VP8ThreadContext* const ctx = &dec->thread_ctx_;
+ if (!dec->use_threads_) {
+ // ctx->id_ and ctx->f_info_ are already set
+ ctx->mb_y_ = dec->mb_y_;
+ ctx->filter_row_ = dec->filter_row_;
+ ok = FinishRow(dec, io);
+ } else {
+ WebPWorker* const worker = &dec->worker_;
+ // Finish previous job *before* updating context
+ ok &= WebPWorkerSync(worker);
+ assert(worker->status_ == OK);
+ if (ok) { // spawn a new deblocking/output job
+ ctx->io_ = *io;
+ ctx->id_ = dec->cache_id_;
+ ctx->mb_y_ = dec->mb_y_;
+ ctx->filter_row_ = dec->filter_row_;
+ if (ctx->filter_row_) { // just swap filter info
+ VP8FInfo* const tmp = ctx->f_info_;
+ ctx->f_info_ = dec->f_info_;
+ dec->f_info_ = tmp;
+ }
+ WebPWorkerLaunch(worker);
+ if (++dec->cache_id_ == dec->num_caches_) {
+ dec->cache_id_ = 0;
+ }
+ }
+ }
+ return ok;
+}
+
+//------------------------------------------------------------------------------
+// Finish setting up the decoding parameter once user's setup() is called.
+
+VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io) {
+ // Call setup() first. This may trigger additional decoding features on 'io'.
+ // Note: Afterward, we must call teardown() not matter what.
+ if (io->setup && !io->setup(io)) {
+ VP8SetError(dec, VP8_STATUS_USER_ABORT, "Frame setup failed");
+ return dec->status_;
+ }
+
+ // Disable filtering per user request
+ if (io->bypass_filtering) {
+ dec->filter_type_ = 0;
+ }
+ // TODO(skal): filter type / strength / sharpness forcing
+
+ // Define the area where we can skip in-loop filtering, in case of cropping.
+ //
+ // 'Simple' filter reads two luma samples outside of the macroblock and
+ // and filters one. It doesn't filter the chroma samples. Hence, we can
+ // avoid doing the in-loop filtering before crop_top/crop_left position.
+ // For the 'Complex' filter, 3 samples are read and up to 3 are filtered.
+ // Means: there's a dependency chain that goes all the way up to the
+ // top-left corner of the picture (MB #0). We must filter all the previous
+ // macroblocks.
+ // TODO(skal): add an 'approximate_decoding' option, that won't produce
+ // a 1:1 bit-exactness for complex filtering?
+ {
+ const int extra_pixels = kFilterExtraRows[dec->filter_type_];
+ if (dec->filter_type_ == 2) {
+ // For complex filter, we need to preserve the dependency chain.
+ dec->tl_mb_x_ = 0;
+ dec->tl_mb_y_ = 0;
+ } else {
+ // For simple filter, we can filter only the cropped region.
+ // We include 'extra_pixels' on the other side of the boundary, since
+ // vertical or horizontal filtering of the previous macroblock can
+ // modify some abutting pixels.
+ dec->tl_mb_x_ = (io->crop_left - extra_pixels) >> 4;
+ dec->tl_mb_y_ = (io->crop_top - extra_pixels) >> 4;
+ if (dec->tl_mb_x_ < 0) dec->tl_mb_x_ = 0;
+ if (dec->tl_mb_y_ < 0) dec->tl_mb_y_ = 0;
+ }
+ // We need some 'extra' pixels on the right/bottom.
+ dec->br_mb_y_ = (io->crop_bottom + 15 + extra_pixels) >> 4;
+ dec->br_mb_x_ = (io->crop_right + 15 + extra_pixels) >> 4;
+ if (dec->br_mb_x_ > dec->mb_w_) {
+ dec->br_mb_x_ = dec->mb_w_;
+ }
+ if (dec->br_mb_y_ > dec->mb_h_) {
+ dec->br_mb_y_ = dec->mb_h_;
+ }
+ }
+ return VP8_STATUS_OK;
+}
+
+int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io) {
+ int ok = 1;
+ if (dec->use_threads_) {
+ ok = WebPWorkerSync(&dec->worker_);
+ }
+
+ if (io->teardown) {
+ io->teardown(io);
+ }
+ return ok;
+}
+
+//------------------------------------------------------------------------------
+// For multi-threaded decoding we need to use 3 rows of 16 pixels as delay line.
+//
+// Reason is: the deblocking filter cannot deblock the bottom horizontal edges
+// immediately, and needs to wait for first few rows of the next macroblock to
+// be decoded. Hence, deblocking is lagging behind by 4 or 8 pixels (depending
+// on strength).
+// With two threads, the vertical positions of the rows being decoded are:
+// Decode: [ 0..15][16..31][32..47][48..63][64..79][...
+// Deblock: [ 0..11][12..27][28..43][44..59][...
+// If we use two threads and two caches of 16 pixels, the sequence would be:
+// Decode: [ 0..15][16..31][ 0..15!!][16..31][ 0..15][...
+// Deblock: [ 0..11][12..27!!][-4..11][12..27][...
+// The problem occurs during row [12..15!!] that both the decoding and
+// deblocking threads are writing simultaneously.
+// With 3 cache lines, one get a safe write pattern:
+// Decode: [ 0..15][16..31][32..47][ 0..15][16..31][32..47][0..
+// Deblock: [ 0..11][12..27][28..43][-4..11][12..27][28...
+// Note that multi-threaded output _without_ deblocking can make use of two
+// cache lines of 16 pixels only, since there's no lagging behind. The decoding
+// and output process have non-concurrent writing:
+// Decode: [ 0..15][16..31][ 0..15][16..31][...
+// io->put: [ 0..15][16..31][ 0..15][...
+
+#define MT_CACHE_LINES 3
+#define ST_CACHE_LINES 1 // 1 cache row only for single-threaded case
+
+// Initialize multi/single-thread worker
+static int InitThreadContext(VP8Decoder* const dec) {
+ dec->cache_id_ = 0;
+ if (dec->use_threads_) {
+ WebPWorker* const worker = &dec->worker_;
+ if (!WebPWorkerReset(worker)) {
+ return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,
+ "thread initialization failed.");
+ }
+ worker->data1 = dec;
+ worker->data2 = (void*)&dec->thread_ctx_.io_;
+ worker->hook = (WebPWorkerHook)FinishRow;
+ dec->num_caches_ =
+ (dec->filter_type_ > 0) ? MT_CACHE_LINES : MT_CACHE_LINES - 1;
+ } else {
+ dec->num_caches_ = ST_CACHE_LINES;
+ }
+ return 1;
+}
+
+#undef MT_CACHE_LINES
+#undef ST_CACHE_LINES
+
+//------------------------------------------------------------------------------
+// Memory setup
+
+static int AllocateMemory(VP8Decoder* const dec) {
+ const int num_caches = dec->num_caches_;
+ const int mb_w = dec->mb_w_;
+ // Note: we use 'size_t' when there's no overflow risk, uint64_t otherwise.
+ const size_t intra_pred_mode_size = 4 * mb_w * sizeof(uint8_t);
+ const size_t top_size = (16 + 8 + 8) * mb_w;
+ const size_t mb_info_size = (mb_w + 1) * sizeof(VP8MB);
+ const size_t f_info_size =
+ (dec->filter_type_ > 0) ?
+ mb_w * (dec->use_threads_ ? 2 : 1) * sizeof(VP8FInfo)
+ : 0;
+ const size_t yuv_size = YUV_SIZE * sizeof(*dec->yuv_b_);
+ const size_t coeffs_size = 384 * sizeof(*dec->coeffs_);
+ const size_t cache_height = (16 * num_caches
+ + kFilterExtraRows[dec->filter_type_]) * 3 / 2;
+ const size_t cache_size = top_size * cache_height;
+ // alpha_size is the only one that scales as width x height.
+ const uint64_t alpha_size = (dec->alpha_data_ != NULL) ?
+ (uint64_t)dec->pic_hdr_.width_ * dec->pic_hdr_.height_ : 0ULL;
+ const uint64_t needed = (uint64_t)intra_pred_mode_size
+ + top_size + mb_info_size + f_info_size
+ + yuv_size + coeffs_size
+ + cache_size + alpha_size + ALIGN_MASK;
+ uint8_t* mem;
+
+ if (needed != (size_t)needed) return 0; // check for overflow
+ if (needed > dec->mem_size_) {
+ free(dec->mem_);
+ dec->mem_size_ = 0;
+ dec->mem_ = WebPSafeMalloc(needed, sizeof(uint8_t));
+ if (dec->mem_ == NULL) {
+ return VP8SetError(dec, VP8_STATUS_OUT_OF_MEMORY,
+ "no memory during frame initialization.");
+ }
+ // down-cast is ok, thanks to WebPSafeAlloc() above.
+ dec->mem_size_ = (size_t)needed;
+ }
+
+ mem = (uint8_t*)dec->mem_;
+ dec->intra_t_ = (uint8_t*)mem;
+ mem += intra_pred_mode_size;
+
+ dec->y_t_ = (uint8_t*)mem;
+ mem += 16 * mb_w;
+ dec->u_t_ = (uint8_t*)mem;
+ mem += 8 * mb_w;
+ dec->v_t_ = (uint8_t*)mem;
+ mem += 8 * mb_w;
+
+ dec->mb_info_ = ((VP8MB*)mem) + 1;
+ mem += mb_info_size;
+
+ dec->f_info_ = f_info_size ? (VP8FInfo*)mem : NULL;
+ mem += f_info_size;
+ dec->thread_ctx_.id_ = 0;
+ dec->thread_ctx_.f_info_ = dec->f_info_;
+ if (dec->use_threads_) {
+ // secondary cache line. The deblocking process need to make use of the
+ // filtering strength from previous macroblock row, while the new ones
+ // are being decoded in parallel. We'll just swap the pointers.
+ dec->thread_ctx_.f_info_ += mb_w;
+ }
+
+ mem = (uint8_t*)((uintptr_t)(mem + ALIGN_MASK) & ~ALIGN_MASK);
+ assert((yuv_size & ALIGN_MASK) == 0);
+ dec->yuv_b_ = (uint8_t*)mem;
+ mem += yuv_size;
+
+ dec->coeffs_ = (int16_t*)mem;
+ mem += coeffs_size;
+
+ dec->cache_y_stride_ = 16 * mb_w;
+ dec->cache_uv_stride_ = 8 * mb_w;
+ {
+ const int extra_rows = kFilterExtraRows[dec->filter_type_];
+ const int extra_y = extra_rows * dec->cache_y_stride_;
+ const int extra_uv = (extra_rows / 2) * dec->cache_uv_stride_;
+ dec->cache_y_ = ((uint8_t*)mem) + extra_y;
+ dec->cache_u_ = dec->cache_y_
+ + 16 * num_caches * dec->cache_y_stride_ + extra_uv;
+ dec->cache_v_ = dec->cache_u_
+ + 8 * num_caches * dec->cache_uv_stride_ + extra_uv;
+ dec->cache_id_ = 0;
+ }
+ mem += cache_size;
+
+ // alpha plane
+ dec->alpha_plane_ = alpha_size ? (uint8_t*)mem : NULL;
+ mem += alpha_size;
+
+ // note: left-info is initialized once for all.
+ memset(dec->mb_info_ - 1, 0, mb_info_size);
+
+ // initialize top
+ memset(dec->intra_t_, B_DC_PRED, intra_pred_mode_size);
+
+ return 1;
+}
+
+static void InitIo(VP8Decoder* const dec, VP8Io* io) {
+ // prepare 'io'
+ io->mb_y = 0;
+ io->y = dec->cache_y_;
+ io->u = dec->cache_u_;
+ io->v = dec->cache_v_;
+ io->y_stride = dec->cache_y_stride_;
+ io->uv_stride = dec->cache_uv_stride_;
+ io->a = NULL;
+}
+
+int VP8InitFrame(VP8Decoder* const dec, VP8Io* io) {
+ if (!InitThreadContext(dec)) return 0; // call first. Sets dec->num_caches_.
+ if (!AllocateMemory(dec)) return 0;
+ InitIo(dec, io);
+ VP8DspInit(); // Init critical function pointers and look-up tables.
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+// Main reconstruction function.
+
+static const int kScan[16] = {
+ 0 + 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS,
+ 0 + 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS,
+ 0 + 8 * BPS, 4 + 8 * BPS, 8 + 8 * BPS, 12 + 8 * BPS,
+ 0 + 12 * BPS, 4 + 12 * BPS, 8 + 12 * BPS, 12 + 12 * BPS
+};
+
+static WEBP_INLINE int CheckMode(VP8Decoder* const dec, int mode) {
+ if (mode == B_DC_PRED) {
+ if (dec->mb_x_ == 0) {
+ return (dec->mb_y_ == 0) ? B_DC_PRED_NOTOPLEFT : B_DC_PRED_NOLEFT;
+ } else {
+ return (dec->mb_y_ == 0) ? B_DC_PRED_NOTOP : B_DC_PRED;
+ }
+ }
+ return mode;
+}
+
+static WEBP_INLINE void Copy32b(uint8_t* dst, uint8_t* src) {
+ *(uint32_t*)dst = *(uint32_t*)src;
+}
+
+void VP8ReconstructBlock(VP8Decoder* const dec) {
+ uint8_t* const y_dst = dec->yuv_b_ + Y_OFF;
+ uint8_t* const u_dst = dec->yuv_b_ + U_OFF;
+ uint8_t* const v_dst = dec->yuv_b_ + V_OFF;
+
+ // Rotate in the left samples from previously decoded block. We move four
+ // pixels at a time for alignment reason, and because of in-loop filter.
+ if (dec->mb_x_ > 0) {
+ int j;
+ for (j = -1; j < 16; ++j) {
+ Copy32b(&y_dst[j * BPS - 4], &y_dst[j * BPS + 12]);
+ }
+ for (j = -1; j < 8; ++j) {
+ Copy32b(&u_dst[j * BPS - 4], &u_dst[j * BPS + 4]);
+ Copy32b(&v_dst[j * BPS - 4], &v_dst[j * BPS + 4]);
+ }
+ } else {
+ int j;
+ for (j = 0; j < 16; ++j) {
+ y_dst[j * BPS - 1] = 129;
+ }
+ for (j = 0; j < 8; ++j) {
+ u_dst[j * BPS - 1] = 129;
+ v_dst[j * BPS - 1] = 129;
+ }
+ // Init top-left sample on left column too
+ if (dec->mb_y_ > 0) {
+ y_dst[-1 - BPS] = u_dst[-1 - BPS] = v_dst[-1 - BPS] = 129;
+ }
+ }
+ {
+ // bring top samples into the cache
+ uint8_t* const top_y = dec->y_t_ + dec->mb_x_ * 16;
+ uint8_t* const top_u = dec->u_t_ + dec->mb_x_ * 8;
+ uint8_t* const top_v = dec->v_t_ + dec->mb_x_ * 8;
+ const int16_t* coeffs = dec->coeffs_;
+ int n;
+
+ if (dec->mb_y_ > 0) {
+ memcpy(y_dst - BPS, top_y, 16);
+ memcpy(u_dst - BPS, top_u, 8);
+ memcpy(v_dst - BPS, top_v, 8);
+ } else if (dec->mb_x_ == 0) {
+ // we only need to do this init once at block (0,0).
+ // Afterward, it remains valid for the whole topmost row.
+ memset(y_dst - BPS - 1, 127, 16 + 4 + 1);
+ memset(u_dst - BPS - 1, 127, 8 + 1);
+ memset(v_dst - BPS - 1, 127, 8 + 1);
+ }
+
+ // predict and add residuals
+
+ if (dec->is_i4x4_) { // 4x4
+ uint32_t* const top_right = (uint32_t*)(y_dst - BPS + 16);
+
+ if (dec->mb_y_ > 0) {
+ if (dec->mb_x_ >= dec->mb_w_ - 1) { // on rightmost border
+ top_right[0] = top_y[15] * 0x01010101u;
+ } else {
+ memcpy(top_right, top_y + 16, sizeof(*top_right));
+ }
+ }
+ // replicate the top-right pixels below
+ top_right[BPS] = top_right[2 * BPS] = top_right[3 * BPS] = top_right[0];
+
+ // predict and add residues for all 4x4 blocks in turn.
+ for (n = 0; n < 16; n++) {
+ uint8_t* const dst = y_dst + kScan[n];
+ VP8PredLuma4[dec->imodes_[n]](dst);
+ if (dec->non_zero_ac_ & (1 << n)) {
+ VP8Transform(coeffs + n * 16, dst, 0);
+ } else if (dec->non_zero_ & (1 << n)) { // only DC is present
+ VP8TransformDC(coeffs + n * 16, dst);
+ }
+ }
+ } else { // 16x16
+ const int pred_func = CheckMode(dec, dec->imodes_[0]);
+ VP8PredLuma16[pred_func](y_dst);
+ if (dec->non_zero_) {
+ for (n = 0; n < 16; n++) {
+ uint8_t* const dst = y_dst + kScan[n];
+ if (dec->non_zero_ac_ & (1 << n)) {
+ VP8Transform(coeffs + n * 16, dst, 0);
+ } else if (dec->non_zero_ & (1 << n)) { // only DC is present
+ VP8TransformDC(coeffs + n * 16, dst);
+ }
+ }
+ }
+ }
+ {
+ // Chroma
+ const int pred_func = CheckMode(dec, dec->uvmode_);
+ VP8PredChroma8[pred_func](u_dst);
+ VP8PredChroma8[pred_func](v_dst);
+
+ if (dec->non_zero_ & 0x0f0000) { // chroma-U
+ const int16_t* const u_coeffs = dec->coeffs_ + 16 * 16;
+ if (dec->non_zero_ac_ & 0x0f0000) {
+ VP8TransformUV(u_coeffs, u_dst);
+ } else {
+ VP8TransformDCUV(u_coeffs, u_dst);
+ }
+ }
+ if (dec->non_zero_ & 0xf00000) { // chroma-V
+ const int16_t* const v_coeffs = dec->coeffs_ + 20 * 16;
+ if (dec->non_zero_ac_ & 0xf00000) {
+ VP8TransformUV(v_coeffs, v_dst);
+ } else {
+ VP8TransformDCUV(v_coeffs, v_dst);
+ }
+ }
+
+ // stash away top samples for next block
+ if (dec->mb_y_ < dec->mb_h_ - 1) {
+ memcpy(top_y, y_dst + 15 * BPS, 16);
+ memcpy(top_u, u_dst + 7 * BPS, 8);
+ memcpy(top_v, v_dst + 7 * BPS, 8);
+ }
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/dec/idec.c b/drivers/webpold/dec/idec.c
new file mode 100644
index 0000000000..7df790ced8
--- /dev/null
+++ b/drivers/webpold/dec/idec.c
@@ -0,0 +1,785 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Incremental decoding
+//
+// Author: somnath@google.com (Somnath Banerjee)
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "./webpi.h"
+#include "./vp8i.h"
+#include "../utils/utils.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+// In append mode, buffer allocations increase as multiples of this value.
+// Needs to be a power of 2.
+#define CHUNK_SIZE 4096
+#define MAX_MB_SIZE 4096
+
+//------------------------------------------------------------------------------
+// Data structures for memory and states
+
+// Decoding states. State normally flows like HEADER->PARTS0->DATA->DONE.
+// If there is any error the decoder goes into state ERROR.
+typedef enum {
+ STATE_PRE_VP8, // All data before that of the first VP8 chunk.
+ STATE_VP8_FRAME_HEADER, // For VP8 Frame header (within VP8 chunk).
+ STATE_VP8_PARTS0,
+ STATE_VP8_DATA,
+ STATE_VP8L_HEADER,
+ STATE_VP8L_DATA,
+ STATE_DONE,
+ STATE_ERROR
+} DecState;
+
+// Operating state for the MemBuffer
+typedef enum {
+ MEM_MODE_NONE = 0,
+ MEM_MODE_APPEND,
+ MEM_MODE_MAP
+} MemBufferMode;
+
+// storage for partition #0 and partial data (in a rolling fashion)
+typedef struct {
+ MemBufferMode mode_; // Operation mode
+ size_t start_; // start location of the data to be decoded
+ size_t end_; // end location
+ size_t buf_size_; // size of the allocated buffer
+ uint8_t* buf_; // We don't own this buffer in case WebPIUpdate()
+
+ size_t part0_size_; // size of partition #0
+ const uint8_t* part0_buf_; // buffer to store partition #0
+} MemBuffer;
+
+struct WebPIDecoder {
+ DecState state_; // current decoding state
+ WebPDecParams params_; // Params to store output info
+ int is_lossless_; // for down-casting 'dec_'.
+ void* dec_; // either a VP8Decoder or a VP8LDecoder instance
+ VP8Io io_;
+
+ MemBuffer mem_; // input memory buffer.
+ WebPDecBuffer output_; // output buffer (when no external one is supplied)
+ size_t chunk_size_; // Compressed VP8/VP8L size extracted from Header.
+};
+
+// MB context to restore in case VP8DecodeMB() fails
+typedef struct {
+ VP8MB left_;
+ VP8MB info_;
+ uint8_t intra_t_[4];
+ uint8_t intra_l_[4];
+ VP8BitReader br_;
+ VP8BitReader token_br_;
+} MBContext;
+
+//------------------------------------------------------------------------------
+// MemBuffer: incoming data handling
+
+static void RemapBitReader(VP8BitReader* const br, ptrdiff_t offset) {
+ if (br->buf_ != NULL) {
+ br->buf_ += offset;
+ br->buf_end_ += offset;
+ }
+}
+
+static WEBP_INLINE size_t MemDataSize(const MemBuffer* mem) {
+ return (mem->end_ - mem->start_);
+}
+
+static void DoRemap(WebPIDecoder* const idec, ptrdiff_t offset) {
+ MemBuffer* const mem = &idec->mem_;
+ const uint8_t* const new_base = mem->buf_ + mem->start_;
+ // note: for VP8, setting up idec->io_ is only really needed at the beginning
+ // of the decoding, till partition #0 is complete.
+ idec->io_.data = new_base;
+ idec->io_.data_size = MemDataSize(mem);
+
+ if (idec->dec_ != NULL) {
+ if (!idec->is_lossless_) {
+ VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
+ const int last_part = dec->num_parts_ - 1;
+ if (offset != 0) {
+ int p;
+ for (p = 0; p <= last_part; ++p) {
+ RemapBitReader(dec->parts_ + p, offset);
+ }
+ // Remap partition #0 data pointer to new offset, but only in MAP
+ // mode (in APPEND mode, partition #0 is copied into a fixed memory).
+ if (mem->mode_ == MEM_MODE_MAP) {
+ RemapBitReader(&dec->br_, offset);
+ }
+ }
+ assert(last_part >= 0);
+ dec->parts_[last_part].buf_end_ = mem->buf_ + mem->end_;
+ } else { // Resize lossless bitreader
+ VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_;
+ VP8LBitReaderSetBuffer(&dec->br_, new_base, MemDataSize(mem));
+ }
+ }
+}
+
+// Appends data to the end of MemBuffer->buf_. It expands the allocated memory
+// size if required and also updates VP8BitReader's if new memory is allocated.
+static int AppendToMemBuffer(WebPIDecoder* const idec,
+ const uint8_t* const data, size_t data_size) {
+ MemBuffer* const mem = &idec->mem_;
+ const uint8_t* const old_base = mem->buf_ + mem->start_;
+ assert(mem->mode_ == MEM_MODE_APPEND);
+ if (data_size > MAX_CHUNK_PAYLOAD) {
+ // security safeguard: trying to allocate more than what the format
+ // allows for a chunk should be considered a smoke smell.
+ return 0;
+ }
+
+ if (mem->end_ + data_size > mem->buf_size_) { // Need some free memory
+ const size_t current_size = MemDataSize(mem);
+ const uint64_t new_size = (uint64_t)current_size + data_size;
+ const uint64_t extra_size = (new_size + CHUNK_SIZE - 1) & ~(CHUNK_SIZE - 1);
+ uint8_t* const new_buf =
+ (uint8_t*)WebPSafeMalloc(extra_size, sizeof(*new_buf));
+ if (new_buf == NULL) return 0;
+ memcpy(new_buf, old_base, current_size);
+ free(mem->buf_);
+ mem->buf_ = new_buf;
+ mem->buf_size_ = (size_t)extra_size;
+ mem->start_ = 0;
+ mem->end_ = current_size;
+ }
+
+ memcpy(mem->buf_ + mem->end_, data, data_size);
+ mem->end_ += data_size;
+ assert(mem->end_ <= mem->buf_size_);
+
+ DoRemap(idec, mem->buf_ + mem->start_ - old_base);
+ return 1;
+}
+
+static int RemapMemBuffer(WebPIDecoder* const idec,
+ const uint8_t* const data, size_t data_size) {
+ MemBuffer* const mem = &idec->mem_;
+ const uint8_t* const old_base = mem->buf_ + mem->start_;
+ assert(mem->mode_ == MEM_MODE_MAP);
+
+ if (data_size < mem->buf_size_) return 0; // can't remap to a shorter buffer!
+
+ mem->buf_ = (uint8_t*)data;
+ mem->end_ = mem->buf_size_ = data_size;
+
+ DoRemap(idec, mem->buf_ + mem->start_ - old_base);
+ return 1;
+}
+
+static void InitMemBuffer(MemBuffer* const mem) {
+ mem->mode_ = MEM_MODE_NONE;
+ mem->buf_ = NULL;
+ mem->buf_size_ = 0;
+ mem->part0_buf_ = NULL;
+ mem->part0_size_ = 0;
+}
+
+static void ClearMemBuffer(MemBuffer* const mem) {
+ assert(mem);
+ if (mem->mode_ == MEM_MODE_APPEND) {
+ free(mem->buf_);
+ free((void*)mem->part0_buf_);
+ }
+}
+
+static int CheckMemBufferMode(MemBuffer* const mem, MemBufferMode expected) {
+ if (mem->mode_ == MEM_MODE_NONE) {
+ mem->mode_ = expected; // switch to the expected mode
+ } else if (mem->mode_ != expected) {
+ return 0; // we mixed the modes => error
+ }
+ assert(mem->mode_ == expected); // mode is ok
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+// Macroblock-decoding contexts
+
+static void SaveContext(const VP8Decoder* dec, const VP8BitReader* token_br,
+ MBContext* const context) {
+ const VP8BitReader* const br = &dec->br_;
+ const VP8MB* const left = dec->mb_info_ - 1;
+ const VP8MB* const info = dec->mb_info_ + dec->mb_x_;
+
+ context->left_ = *left;
+ context->info_ = *info;
+ context->br_ = *br;
+ context->token_br_ = *token_br;
+ memcpy(context->intra_t_, dec->intra_t_ + 4 * dec->mb_x_, 4);
+ memcpy(context->intra_l_, dec->intra_l_, 4);
+}
+
+static void RestoreContext(const MBContext* context, VP8Decoder* const dec,
+ VP8BitReader* const token_br) {
+ VP8BitReader* const br = &dec->br_;
+ VP8MB* const left = dec->mb_info_ - 1;
+ VP8MB* const info = dec->mb_info_ + dec->mb_x_;
+
+ *left = context->left_;
+ *info = context->info_;
+ *br = context->br_;
+ *token_br = context->token_br_;
+ memcpy(dec->intra_t_ + 4 * dec->mb_x_, context->intra_t_, 4);
+ memcpy(dec->intra_l_, context->intra_l_, 4);
+}
+
+//------------------------------------------------------------------------------
+
+static VP8StatusCode IDecError(WebPIDecoder* const idec, VP8StatusCode error) {
+ if (idec->state_ == STATE_VP8_DATA) {
+ VP8Io* const io = &idec->io_;
+ if (io->teardown) {
+ io->teardown(io);
+ }
+ }
+ idec->state_ = STATE_ERROR;
+ return error;
+}
+
+static void ChangeState(WebPIDecoder* const idec, DecState new_state,
+ size_t consumed_bytes) {
+ MemBuffer* const mem = &idec->mem_;
+ idec->state_ = new_state;
+ mem->start_ += consumed_bytes;
+ assert(mem->start_ <= mem->end_);
+ idec->io_.data = mem->buf_ + mem->start_;
+ idec->io_.data_size = MemDataSize(mem);
+}
+
+// Headers
+static VP8StatusCode DecodeWebPHeaders(WebPIDecoder* const idec) {
+ MemBuffer* const mem = &idec->mem_;
+ const uint8_t* data = mem->buf_ + mem->start_;
+ size_t curr_size = MemDataSize(mem);
+ VP8StatusCode status;
+ WebPHeaderStructure headers;
+
+ headers.data = data;
+ headers.data_size = curr_size;
+ status = WebPParseHeaders(&headers);
+ if (status == VP8_STATUS_NOT_ENOUGH_DATA) {
+ return VP8_STATUS_SUSPENDED; // We haven't found a VP8 chunk yet.
+ } else if (status != VP8_STATUS_OK) {
+ return IDecError(idec, status);
+ }
+
+ idec->chunk_size_ = headers.compressed_size;
+ idec->is_lossless_ = headers.is_lossless;
+ if (!idec->is_lossless_) {
+ VP8Decoder* const dec = VP8New();
+ if (dec == NULL) {
+ return VP8_STATUS_OUT_OF_MEMORY;
+ }
+ idec->dec_ = dec;
+#ifdef WEBP_USE_THREAD
+ dec->use_threads_ = (idec->params_.options != NULL) &&
+ (idec->params_.options->use_threads > 0);
+#else
+ dec->use_threads_ = 0;
+#endif
+ dec->alpha_data_ = headers.alpha_data;
+ dec->alpha_data_size_ = headers.alpha_data_size;
+ ChangeState(idec, STATE_VP8_FRAME_HEADER, headers.offset);
+ } else {
+ VP8LDecoder* const dec = VP8LNew();
+ if (dec == NULL) {
+ return VP8_STATUS_OUT_OF_MEMORY;
+ }
+ idec->dec_ = dec;
+ ChangeState(idec, STATE_VP8L_HEADER, headers.offset);
+ }
+ return VP8_STATUS_OK;
+}
+
+static VP8StatusCode DecodeVP8FrameHeader(WebPIDecoder* const idec) {
+ const uint8_t* data = idec->mem_.buf_ + idec->mem_.start_;
+ const size_t curr_size = MemDataSize(&idec->mem_);
+ uint32_t bits;
+
+ if (curr_size < VP8_FRAME_HEADER_SIZE) {
+ // Not enough data bytes to extract VP8 Frame Header.
+ return VP8_STATUS_SUSPENDED;
+ }
+ if (!VP8GetInfo(data, curr_size, idec->chunk_size_, NULL, NULL)) {
+ return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
+ }
+
+ bits = data[0] | (data[1] << 8) | (data[2] << 16);
+ idec->mem_.part0_size_ = (bits >> 5) + VP8_FRAME_HEADER_SIZE;
+
+ idec->io_.data = data;
+ idec->io_.data_size = curr_size;
+ idec->state_ = STATE_VP8_PARTS0;
+ return VP8_STATUS_OK;
+}
+
+// Partition #0
+static int CopyParts0Data(WebPIDecoder* const idec) {
+ VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
+ VP8BitReader* const br = &dec->br_;
+ const size_t psize = br->buf_end_ - br->buf_;
+ MemBuffer* const mem = &idec->mem_;
+ assert(!idec->is_lossless_);
+ assert(mem->part0_buf_ == NULL);
+ assert(psize > 0);
+ assert(psize <= mem->part0_size_); // Format limit: no need for runtime check
+ if (mem->mode_ == MEM_MODE_APPEND) {
+ // We copy and grab ownership of the partition #0 data.
+ uint8_t* const part0_buf = (uint8_t*)malloc(psize);
+ if (part0_buf == NULL) {
+ return 0;
+ }
+ memcpy(part0_buf, br->buf_, psize);
+ mem->part0_buf_ = part0_buf;
+ br->buf_ = part0_buf;
+ br->buf_end_ = part0_buf + psize;
+ } else {
+ // Else: just keep pointers to the partition #0's data in dec_->br_.
+ }
+ mem->start_ += psize;
+ return 1;
+}
+
+static VP8StatusCode DecodePartition0(WebPIDecoder* const idec) {
+ VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
+ VP8Io* const io = &idec->io_;
+ const WebPDecParams* const params = &idec->params_;
+ WebPDecBuffer* const output = params->output;
+
+ // Wait till we have enough data for the whole partition #0
+ if (MemDataSize(&idec->mem_) < idec->mem_.part0_size_) {
+ return VP8_STATUS_SUSPENDED;
+ }
+
+ if (!VP8GetHeaders(dec, io)) {
+ const VP8StatusCode status = dec->status_;
+ if (status == VP8_STATUS_SUSPENDED ||
+ status == VP8_STATUS_NOT_ENOUGH_DATA) {
+ // treating NOT_ENOUGH_DATA as SUSPENDED state
+ return VP8_STATUS_SUSPENDED;
+ }
+ return IDecError(idec, status);
+ }
+
+ // Allocate/Verify output buffer now
+ dec->status_ = WebPAllocateDecBuffer(io->width, io->height, params->options,
+ output);
+ if (dec->status_ != VP8_STATUS_OK) {
+ return IDecError(idec, dec->status_);
+ }
+
+ if (!CopyParts0Data(idec)) {
+ return IDecError(idec, VP8_STATUS_OUT_OF_MEMORY);
+ }
+
+ // Finish setting up the decoding parameters. Will call io->setup().
+ if (VP8EnterCritical(dec, io) != VP8_STATUS_OK) {
+ return IDecError(idec, dec->status_);
+ }
+
+ // Note: past this point, teardown() must always be called
+ // in case of error.
+ idec->state_ = STATE_VP8_DATA;
+ // Allocate memory and prepare everything.
+ if (!VP8InitFrame(dec, io)) {
+ return IDecError(idec, dec->status_);
+ }
+ return VP8_STATUS_OK;
+}
+
+// Remaining partitions
+static VP8StatusCode DecodeRemaining(WebPIDecoder* const idec) {
+ VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
+ VP8Io* const io = &idec->io_;
+
+ assert(dec->ready_);
+
+ for (; dec->mb_y_ < dec->mb_h_; ++dec->mb_y_) {
+ VP8BitReader* token_br = &dec->parts_[dec->mb_y_ & (dec->num_parts_ - 1)];
+ if (dec->mb_x_ == 0) {
+ VP8InitScanline(dec);
+ }
+ for (; dec->mb_x_ < dec->mb_w_; dec->mb_x_++) {
+ MBContext context;
+ SaveContext(dec, token_br, &context);
+
+ if (!VP8DecodeMB(dec, token_br)) {
+ RestoreContext(&context, dec, token_br);
+ // We shouldn't fail when MAX_MB data was available
+ if (dec->num_parts_ == 1 && MemDataSize(&idec->mem_) > MAX_MB_SIZE) {
+ return IDecError(idec, VP8_STATUS_BITSTREAM_ERROR);
+ }
+ return VP8_STATUS_SUSPENDED;
+ }
+ VP8ReconstructBlock(dec);
+ // Store data and save block's filtering params
+ VP8StoreBlock(dec);
+
+ // Release buffer only if there is only one partition
+ if (dec->num_parts_ == 1) {
+ idec->mem_.start_ = token_br->buf_ - idec->mem_.buf_;
+ assert(idec->mem_.start_ <= idec->mem_.end_);
+ }
+ }
+ if (!VP8ProcessRow(dec, io)) {
+ return IDecError(idec, VP8_STATUS_USER_ABORT);
+ }
+ dec->mb_x_ = 0;
+ }
+ // Synchronize the thread and check for errors.
+ if (!VP8ExitCritical(dec, io)) {
+ return IDecError(idec, VP8_STATUS_USER_ABORT);
+ }
+ dec->ready_ = 0;
+ idec->state_ = STATE_DONE;
+
+ return VP8_STATUS_OK;
+}
+
+static int ErrorStatusLossless(WebPIDecoder* const idec, VP8StatusCode status) {
+ if (status == VP8_STATUS_SUSPENDED || status == VP8_STATUS_NOT_ENOUGH_DATA) {
+ return VP8_STATUS_SUSPENDED;
+ }
+ return IDecError(idec, status);
+}
+
+static VP8StatusCode DecodeVP8LHeader(WebPIDecoder* const idec) {
+ VP8Io* const io = &idec->io_;
+ VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_;
+ const WebPDecParams* const params = &idec->params_;
+ WebPDecBuffer* const output = params->output;
+ size_t curr_size = MemDataSize(&idec->mem_);
+ assert(idec->is_lossless_);
+
+ // Wait until there's enough data for decoding header.
+ if (curr_size < (idec->chunk_size_ >> 3)) {
+ return VP8_STATUS_SUSPENDED;
+ }
+ if (!VP8LDecodeHeader(dec, io)) {
+ return ErrorStatusLossless(idec, dec->status_);
+ }
+ // Allocate/verify output buffer now.
+ dec->status_ = WebPAllocateDecBuffer(io->width, io->height, params->options,
+ output);
+ if (dec->status_ != VP8_STATUS_OK) {
+ return IDecError(idec, dec->status_);
+ }
+
+ idec->state_ = STATE_VP8L_DATA;
+ return VP8_STATUS_OK;
+}
+
+static VP8StatusCode DecodeVP8LData(WebPIDecoder* const idec) {
+ VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_;
+ const size_t curr_size = MemDataSize(&idec->mem_);
+ assert(idec->is_lossless_);
+
+ // At present Lossless decoder can't decode image incrementally. So wait till
+ // all the image data is aggregated before image can be decoded.
+ if (curr_size < idec->chunk_size_) {
+ return VP8_STATUS_SUSPENDED;
+ }
+
+ if (!VP8LDecodeImage(dec)) {
+ return ErrorStatusLossless(idec, dec->status_);
+ }
+
+ idec->state_ = STATE_DONE;
+
+ return VP8_STATUS_OK;
+}
+
+ // Main decoding loop
+static VP8StatusCode IDecode(WebPIDecoder* idec) {
+ VP8StatusCode status = VP8_STATUS_SUSPENDED;
+
+ if (idec->state_ == STATE_PRE_VP8) {
+ status = DecodeWebPHeaders(idec);
+ } else {
+ if (idec->dec_ == NULL) {
+ return VP8_STATUS_SUSPENDED; // can't continue if we have no decoder.
+ }
+ }
+ if (idec->state_ == STATE_VP8_FRAME_HEADER) {
+ status = DecodeVP8FrameHeader(idec);
+ }
+ if (idec->state_ == STATE_VP8_PARTS0) {
+ status = DecodePartition0(idec);
+ }
+ if (idec->state_ == STATE_VP8_DATA) {
+ status = DecodeRemaining(idec);
+ }
+ if (idec->state_ == STATE_VP8L_HEADER) {
+ status = DecodeVP8LHeader(idec);
+ }
+ if (idec->state_ == STATE_VP8L_DATA) {
+ status = DecodeVP8LData(idec);
+ }
+ return status;
+}
+
+//------------------------------------------------------------------------------
+// Public functions
+
+WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) {
+ WebPIDecoder* idec = (WebPIDecoder*)calloc(1, sizeof(*idec));
+ if (idec == NULL) {
+ return NULL;
+ }
+
+ idec->state_ = STATE_PRE_VP8;
+ idec->chunk_size_ = 0;
+
+ InitMemBuffer(&idec->mem_);
+ WebPInitDecBuffer(&idec->output_);
+ VP8InitIo(&idec->io_);
+
+ WebPResetDecParams(&idec->params_);
+ idec->params_.output = output_buffer ? output_buffer : &idec->output_;
+ WebPInitCustomIo(&idec->params_, &idec->io_); // Plug the I/O functions.
+
+ return idec;
+}
+
+WebPIDecoder* WebPIDecode(const uint8_t* data, size_t data_size,
+ WebPDecoderConfig* config) {
+ WebPIDecoder* idec;
+
+ // Parse the bitstream's features, if requested:
+ if (data != NULL && data_size > 0 && config != NULL) {
+ if (WebPGetFeatures(data, data_size, &config->input) != VP8_STATUS_OK) {
+ return NULL;
+ }
+ }
+ // Create an instance of the incremental decoder
+ idec = WebPINewDecoder(config ? &config->output : NULL);
+ if (idec == NULL) {
+ return NULL;
+ }
+ // Finish initialization
+ if (config != NULL) {
+ idec->params_.options = &config->options;
+ }
+ return idec;
+}
+
+void WebPIDelete(WebPIDecoder* idec) {
+ if (idec == NULL) return;
+ if (idec->dec_ != NULL) {
+ if (!idec->is_lossless_) {
+ VP8Delete(idec->dec_);
+ } else {
+ VP8LDelete(idec->dec_);
+ }
+ }
+ ClearMemBuffer(&idec->mem_);
+ WebPFreeDecBuffer(&idec->output_);
+ free(idec);
+}
+
+//------------------------------------------------------------------------------
+// Wrapper toward WebPINewDecoder
+
+WebPIDecoder* WebPINewRGB(WEBP_CSP_MODE mode, uint8_t* output_buffer,
+ size_t output_buffer_size, int output_stride) {
+ WebPIDecoder* idec;
+ if (mode >= MODE_YUV) return NULL;
+ idec = WebPINewDecoder(NULL);
+ if (idec == NULL) return NULL;
+ idec->output_.colorspace = mode;
+ idec->output_.is_external_memory = 1;
+ idec->output_.u.RGBA.rgba = output_buffer;
+ idec->output_.u.RGBA.stride = output_stride;
+ idec->output_.u.RGBA.size = output_buffer_size;
+ return idec;
+}
+
+WebPIDecoder* WebPINewYUVA(uint8_t* luma, size_t luma_size, int luma_stride,
+ uint8_t* u, size_t u_size, int u_stride,
+ uint8_t* v, size_t v_size, int v_stride,
+ uint8_t* a, size_t a_size, int a_stride) {
+ WebPIDecoder* const idec = WebPINewDecoder(NULL);
+ if (idec == NULL) return NULL;
+ idec->output_.colorspace = (a == NULL) ? MODE_YUV : MODE_YUVA;
+ idec->output_.is_external_memory = 1;
+ idec->output_.u.YUVA.y = luma;
+ idec->output_.u.YUVA.y_stride = luma_stride;
+ idec->output_.u.YUVA.y_size = luma_size;
+ idec->output_.u.YUVA.u = u;
+ idec->output_.u.YUVA.u_stride = u_stride;
+ idec->output_.u.YUVA.u_size = u_size;
+ idec->output_.u.YUVA.v = v;
+ idec->output_.u.YUVA.v_stride = v_stride;
+ idec->output_.u.YUVA.v_size = v_size;
+ idec->output_.u.YUVA.a = a;
+ idec->output_.u.YUVA.a_stride = a_stride;
+ idec->output_.u.YUVA.a_size = a_size;
+ return idec;
+}
+
+WebPIDecoder* WebPINewYUV(uint8_t* luma, size_t luma_size, int luma_stride,
+ uint8_t* u, size_t u_size, int u_stride,
+ uint8_t* v, size_t v_size, int v_stride) {
+ return WebPINewYUVA(luma, luma_size, luma_stride,
+ u, u_size, u_stride,
+ v, v_size, v_stride,
+ NULL, 0, 0);
+}
+
+//------------------------------------------------------------------------------
+
+static VP8StatusCode IDecCheckStatus(const WebPIDecoder* const idec) {
+ assert(idec);
+ if (idec->state_ == STATE_ERROR) {
+ return VP8_STATUS_BITSTREAM_ERROR;
+ }
+ if (idec->state_ == STATE_DONE) {
+ return VP8_STATUS_OK;
+ }
+ return VP8_STATUS_SUSPENDED;
+}
+
+VP8StatusCode WebPIAppend(WebPIDecoder* idec,
+ const uint8_t* data, size_t data_size) {
+ VP8StatusCode status;
+ if (idec == NULL || data == NULL) {
+ return VP8_STATUS_INVALID_PARAM;
+ }
+ status = IDecCheckStatus(idec);
+ if (status != VP8_STATUS_SUSPENDED) {
+ return status;
+ }
+ // Check mixed calls between RemapMemBuffer and AppendToMemBuffer.
+ if (!CheckMemBufferMode(&idec->mem_, MEM_MODE_APPEND)) {
+ return VP8_STATUS_INVALID_PARAM;
+ }
+ // Append data to memory buffer
+ if (!AppendToMemBuffer(idec, data, data_size)) {
+ return VP8_STATUS_OUT_OF_MEMORY;
+ }
+ return IDecode(idec);
+}
+
+VP8StatusCode WebPIUpdate(WebPIDecoder* idec,
+ const uint8_t* data, size_t data_size) {
+ VP8StatusCode status;
+ if (idec == NULL || data == NULL) {
+ return VP8_STATUS_INVALID_PARAM;
+ }
+ status = IDecCheckStatus(idec);
+ if (status != VP8_STATUS_SUSPENDED) {
+ return status;
+ }
+ // Check mixed calls between RemapMemBuffer and AppendToMemBuffer.
+ if (!CheckMemBufferMode(&idec->mem_, MEM_MODE_MAP)) {
+ return VP8_STATUS_INVALID_PARAM;
+ }
+ // Make the memory buffer point to the new buffer
+ if (!RemapMemBuffer(idec, data, data_size)) {
+ return VP8_STATUS_INVALID_PARAM;
+ }
+ return IDecode(idec);
+}
+
+//------------------------------------------------------------------------------
+
+static const WebPDecBuffer* GetOutputBuffer(const WebPIDecoder* const idec) {
+ if (idec == NULL || idec->dec_ == NULL) {
+ return NULL;
+ }
+ if (idec->state_ <= STATE_VP8_PARTS0) {
+ return NULL;
+ }
+ return idec->params_.output;
+}
+
+const WebPDecBuffer* WebPIDecodedArea(const WebPIDecoder* idec,
+ int* left, int* top,
+ int* width, int* height) {
+ const WebPDecBuffer* const src = GetOutputBuffer(idec);
+ if (left != NULL) *left = 0;
+ if (top != NULL) *top = 0;
+ // TODO(skal): later include handling of rotations.
+ if (src) {
+ if (width != NULL) *width = src->width;
+ if (height != NULL) *height = idec->params_.last_y;
+ } else {
+ if (width != NULL) *width = 0;
+ if (height != NULL) *height = 0;
+ }
+ return src;
+}
+
+uint8_t* WebPIDecGetRGB(const WebPIDecoder* idec, int* last_y,
+ int* width, int* height, int* stride) {
+ const WebPDecBuffer* const src = GetOutputBuffer(idec);
+ if (src == NULL) return NULL;
+ if (src->colorspace >= MODE_YUV) {
+ return NULL;
+ }
+
+ if (last_y != NULL) *last_y = idec->params_.last_y;
+ if (width != NULL) *width = src->width;
+ if (height != NULL) *height = src->height;
+ if (stride != NULL) *stride = src->u.RGBA.stride;
+
+ return src->u.RGBA.rgba;
+}
+
+uint8_t* WebPIDecGetYUVA(const WebPIDecoder* idec, int* last_y,
+ uint8_t** u, uint8_t** v, uint8_t** a,
+ int* width, int* height,
+ int* stride, int* uv_stride, int* a_stride) {
+ const WebPDecBuffer* const src = GetOutputBuffer(idec);
+ if (src == NULL) return NULL;
+ if (src->colorspace < MODE_YUV) {
+ return NULL;
+ }
+
+ if (last_y != NULL) *last_y = idec->params_.last_y;
+ if (u != NULL) *u = src->u.YUVA.u;
+ if (v != NULL) *v = src->u.YUVA.v;
+ if (a != NULL) *a = src->u.YUVA.a;
+ if (width != NULL) *width = src->width;
+ if (height != NULL) *height = src->height;
+ if (stride != NULL) *stride = src->u.YUVA.y_stride;
+ if (uv_stride != NULL) *uv_stride = src->u.YUVA.u_stride;
+ if (a_stride != NULL) *a_stride = src->u.YUVA.a_stride;
+
+ return src->u.YUVA.y;
+}
+
+int WebPISetIOHooks(WebPIDecoder* const idec,
+ VP8IoPutHook put,
+ VP8IoSetupHook setup,
+ VP8IoTeardownHook teardown,
+ void* user_data) {
+ if (idec == NULL || idec->state_ > STATE_PRE_VP8) {
+ return 0;
+ }
+
+ idec->io_.put = put;
+ idec->io_.setup = setup;
+ idec->io_.teardown = teardown;
+ idec->io_.opaque = user_data;
+
+ return 1;
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/dec/io.c b/drivers/webpold/dec/io.c
new file mode 100644
index 0000000000..594804c2e6
--- /dev/null
+++ b/drivers/webpold/dec/io.c
@@ -0,0 +1,633 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// functions for sample output.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <assert.h>
+#include <stdlib.h>
+#include "../dec/vp8i.h"
+#include "./webpi.h"
+#include "../dsp/dsp.h"
+#include "../dsp/yuv.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// Main YUV<->RGB conversion functions
+
+static int EmitYUV(const VP8Io* const io, WebPDecParams* const p) {
+ WebPDecBuffer* output = p->output;
+ const WebPYUVABuffer* const buf = &output->u.YUVA;
+ uint8_t* const y_dst = buf->y + io->mb_y * buf->y_stride;
+ uint8_t* const u_dst = buf->u + (io->mb_y >> 1) * buf->u_stride;
+ uint8_t* const v_dst = buf->v + (io->mb_y >> 1) * buf->v_stride;
+ const int mb_w = io->mb_w;
+ const int mb_h = io->mb_h;
+ const int uv_w = (mb_w + 1) / 2;
+ const int uv_h = (mb_h + 1) / 2;
+ int j;
+ for (j = 0; j < mb_h; ++j) {
+ memcpy(y_dst + j * buf->y_stride, io->y + j * io->y_stride, mb_w);
+ }
+ for (j = 0; j < uv_h; ++j) {
+ memcpy(u_dst + j * buf->u_stride, io->u + j * io->uv_stride, uv_w);
+ memcpy(v_dst + j * buf->v_stride, io->v + j * io->uv_stride, uv_w);
+ }
+ return io->mb_h;
+}
+
+// Point-sampling U/V sampler.
+static int EmitSampledRGB(const VP8Io* const io, WebPDecParams* const p) {
+ WebPDecBuffer* output = p->output;
+ const WebPRGBABuffer* const buf = &output->u.RGBA;
+ uint8_t* dst = buf->rgba + io->mb_y * buf->stride;
+ const uint8_t* y_src = io->y;
+ const uint8_t* u_src = io->u;
+ const uint8_t* v_src = io->v;
+ const WebPSampleLinePairFunc sample = WebPSamplers[output->colorspace];
+ const int mb_w = io->mb_w;
+ const int last = io->mb_h - 1;
+ int j;
+ for (j = 0; j < last; j += 2) {
+ sample(y_src, y_src + io->y_stride, u_src, v_src,
+ dst, dst + buf->stride, mb_w);
+ y_src += 2 * io->y_stride;
+ u_src += io->uv_stride;
+ v_src += io->uv_stride;
+ dst += 2 * buf->stride;
+ }
+ if (j == last) { // Just do the last line twice
+ sample(y_src, y_src, u_src, v_src, dst, dst, mb_w);
+ }
+ return io->mb_h;
+}
+
+//------------------------------------------------------------------------------
+// YUV444 -> RGB conversion
+
+#if 0 // TODO(skal): this is for future rescaling.
+static int EmitRGB(const VP8Io* const io, WebPDecParams* const p) {
+ WebPDecBuffer* output = p->output;
+ const WebPRGBABuffer* const buf = &output->u.RGBA;
+ uint8_t* dst = buf->rgba + io->mb_y * buf->stride;
+ const uint8_t* y_src = io->y;
+ const uint8_t* u_src = io->u;
+ const uint8_t* v_src = io->v;
+ const WebPYUV444Converter convert = WebPYUV444Converters[output->colorspace];
+ const int mb_w = io->mb_w;
+ const int last = io->mb_h;
+ int j;
+ for (j = 0; j < last; ++j) {
+ convert(y_src, u_src, v_src, dst, mb_w);
+ y_src += io->y_stride;
+ u_src += io->uv_stride;
+ v_src += io->uv_stride;
+ dst += buf->stride;
+ }
+ return io->mb_h;
+}
+#endif
+
+//------------------------------------------------------------------------------
+// Fancy upsampling
+
+#ifdef FANCY_UPSAMPLING
+static int EmitFancyRGB(const VP8Io* const io, WebPDecParams* const p) {
+ int num_lines_out = io->mb_h; // a priori guess
+ const WebPRGBABuffer* const buf = &p->output->u.RGBA;
+ uint8_t* dst = buf->rgba + io->mb_y * buf->stride;
+ WebPUpsampleLinePairFunc upsample = WebPUpsamplers[p->output->colorspace];
+ const uint8_t* cur_y = io->y;
+ const uint8_t* cur_u = io->u;
+ const uint8_t* cur_v = io->v;
+ const uint8_t* top_u = p->tmp_u;
+ const uint8_t* top_v = p->tmp_v;
+ int y = io->mb_y;
+ const int y_end = io->mb_y + io->mb_h;
+ const int mb_w = io->mb_w;
+ const int uv_w = (mb_w + 1) / 2;
+
+ if (y == 0) {
+ // First line is special cased. We mirror the u/v samples at boundary.
+ upsample(NULL, cur_y, cur_u, cur_v, cur_u, cur_v, NULL, dst, mb_w);
+ } else {
+ // We can finish the left-over line from previous call.
+ upsample(p->tmp_y, cur_y, top_u, top_v, cur_u, cur_v,
+ dst - buf->stride, dst, mb_w);
+ ++num_lines_out;
+ }
+ // Loop over each output pairs of row.
+ for (; y + 2 < y_end; y += 2) {
+ top_u = cur_u;
+ top_v = cur_v;
+ cur_u += io->uv_stride;
+ cur_v += io->uv_stride;
+ dst += 2 * buf->stride;
+ cur_y += 2 * io->y_stride;
+ upsample(cur_y - io->y_stride, cur_y,
+ top_u, top_v, cur_u, cur_v,
+ dst - buf->stride, dst, mb_w);
+ }
+ // move to last row
+ cur_y += io->y_stride;
+ if (io->crop_top + y_end < io->crop_bottom) {
+ // Save the unfinished samples for next call (as we're not done yet).
+ memcpy(p->tmp_y, cur_y, mb_w * sizeof(*p->tmp_y));
+ memcpy(p->tmp_u, cur_u, uv_w * sizeof(*p->tmp_u));
+ memcpy(p->tmp_v, cur_v, uv_w * sizeof(*p->tmp_v));
+ // The fancy upsampler leaves a row unfinished behind
+ // (except for the very last row)
+ num_lines_out--;
+ } else {
+ // Process the very last row of even-sized picture
+ if (!(y_end & 1)) {
+ upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v,
+ dst + buf->stride, NULL, mb_w);
+ }
+ }
+ return num_lines_out;
+}
+
+#endif /* FANCY_UPSAMPLING */
+
+//------------------------------------------------------------------------------
+
+static int EmitAlphaYUV(const VP8Io* const io, WebPDecParams* const p) {
+ const uint8_t* alpha = io->a;
+ const WebPYUVABuffer* const buf = &p->output->u.YUVA;
+ const int mb_w = io->mb_w;
+ const int mb_h = io->mb_h;
+ uint8_t* dst = buf->a + io->mb_y * buf->a_stride;
+ int j;
+
+ if (alpha != NULL) {
+ for (j = 0; j < mb_h; ++j) {
+ memcpy(dst, alpha, mb_w * sizeof(*dst));
+ alpha += io->width;
+ dst += buf->a_stride;
+ }
+ } else if (buf->a != NULL) {
+ // the user requested alpha, but there is none, set it to opaque.
+ for (j = 0; j < mb_h; ++j) {
+ memset(dst, 0xff, mb_w * sizeof(*dst));
+ dst += buf->a_stride;
+ }
+ }
+ return 0;
+}
+
+static int GetAlphaSourceRow(const VP8Io* const io,
+ const uint8_t** alpha, int* const num_rows) {
+ int start_y = io->mb_y;
+ *num_rows = io->mb_h;
+
+ // Compensate for the 1-line delay of the fancy upscaler.
+ // This is similar to EmitFancyRGB().
+ if (io->fancy_upsampling) {
+ if (start_y == 0) {
+ // We don't process the last row yet. It'll be done during the next call.
+ --*num_rows;
+ } else {
+ --start_y;
+ // Fortunately, *alpha data is persistent, so we can go back
+ // one row and finish alpha blending, now that the fancy upscaler
+ // completed the YUV->RGB interpolation.
+ *alpha -= io->width;
+ }
+ if (io->crop_top + io->mb_y + io->mb_h == io->crop_bottom) {
+ // If it's the very last call, we process all the remaining rows!
+ *num_rows = io->crop_bottom - io->crop_top - start_y;
+ }
+ }
+ return start_y;
+}
+
+static int EmitAlphaRGB(const VP8Io* const io, WebPDecParams* const p) {
+ const uint8_t* alpha = io->a;
+ if (alpha != NULL) {
+ const int mb_w = io->mb_w;
+ const WEBP_CSP_MODE colorspace = p->output->colorspace;
+ const int alpha_first =
+ (colorspace == MODE_ARGB || colorspace == MODE_Argb);
+ const WebPRGBABuffer* const buf = &p->output->u.RGBA;
+ int num_rows;
+ const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
+ uint8_t* const base_rgba = buf->rgba + start_y * buf->stride;
+ uint8_t* dst = base_rgba + (alpha_first ? 0 : 3);
+ uint32_t alpha_mask = 0xff;
+ int i, j;
+
+ for (j = 0; j < num_rows; ++j) {
+ for (i = 0; i < mb_w; ++i) {
+ const uint32_t alpha_value = alpha[i];
+ dst[4 * i] = alpha_value;
+ alpha_mask &= alpha_value;
+ }
+ alpha += io->width;
+ dst += buf->stride;
+ }
+ // alpha_mask is < 0xff if there's non-trivial alpha to premultiply with.
+ if (alpha_mask != 0xff && WebPIsPremultipliedMode(colorspace)) {
+ WebPApplyAlphaMultiply(base_rgba, alpha_first,
+ mb_w, num_rows, buf->stride);
+ }
+ }
+ return 0;
+}
+
+static int EmitAlphaRGBA4444(const VP8Io* const io, WebPDecParams* const p) {
+ const uint8_t* alpha = io->a;
+ if (alpha != NULL) {
+ const int mb_w = io->mb_w;
+ const WEBP_CSP_MODE colorspace = p->output->colorspace;
+ const WebPRGBABuffer* const buf = &p->output->u.RGBA;
+ int num_rows;
+ const int start_y = GetAlphaSourceRow(io, &alpha, &num_rows);
+ uint8_t* const base_rgba = buf->rgba + start_y * buf->stride;
+ uint8_t* alpha_dst = base_rgba + 1;
+ uint32_t alpha_mask = 0x0f;
+ int i, j;
+
+ for (j = 0; j < num_rows; ++j) {
+ for (i = 0; i < mb_w; ++i) {
+ // Fill in the alpha value (converted to 4 bits).
+ const uint32_t alpha_value = alpha[i] >> 4;
+ alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value;
+ alpha_mask &= alpha_value;
+ }
+ alpha += io->width;
+ alpha_dst += buf->stride;
+ }
+ if (alpha_mask != 0x0f && WebPIsPremultipliedMode(colorspace)) {
+ WebPApplyAlphaMultiply4444(base_rgba, mb_w, num_rows, buf->stride);
+ }
+ }
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+// YUV rescaling (no final RGB conversion needed)
+
+static int Rescale(const uint8_t* src, int src_stride,
+ int new_lines, WebPRescaler* const wrk) {
+ int num_lines_out = 0;
+ while (new_lines > 0) { // import new contributions of source rows.
+ const int lines_in = WebPRescalerImport(wrk, new_lines, src, src_stride);
+ src += lines_in * src_stride;
+ new_lines -= lines_in;
+ num_lines_out += WebPRescalerExport(wrk); // emit output row(s)
+ }
+ return num_lines_out;
+}
+
+static int EmitRescaledYUV(const VP8Io* const io, WebPDecParams* const p) {
+ const int mb_h = io->mb_h;
+ const int uv_mb_h = (mb_h + 1) >> 1;
+ const int num_lines_out = Rescale(io->y, io->y_stride, mb_h, &p->scaler_y);
+ Rescale(io->u, io->uv_stride, uv_mb_h, &p->scaler_u);
+ Rescale(io->v, io->uv_stride, uv_mb_h, &p->scaler_v);
+ return num_lines_out;
+}
+
+static int EmitRescaledAlphaYUV(const VP8Io* const io, WebPDecParams* const p) {
+ if (io->a != NULL) {
+ Rescale(io->a, io->width, io->mb_h, &p->scaler_a);
+ }
+ return 0;
+}
+
+static int InitYUVRescaler(const VP8Io* const io, WebPDecParams* const p) {
+ const int has_alpha = WebPIsAlphaMode(p->output->colorspace);
+ const WebPYUVABuffer* const buf = &p->output->u.YUVA;
+ const int out_width = io->scaled_width;
+ const int out_height = io->scaled_height;
+ const int uv_out_width = (out_width + 1) >> 1;
+ const int uv_out_height = (out_height + 1) >> 1;
+ const int uv_in_width = (io->mb_w + 1) >> 1;
+ const int uv_in_height = (io->mb_h + 1) >> 1;
+ const size_t work_size = 2 * out_width; // scratch memory for luma rescaler
+ const size_t uv_work_size = 2 * uv_out_width; // and for each u/v ones
+ size_t tmp_size;
+ int32_t* work;
+
+ tmp_size = work_size + 2 * uv_work_size;
+ if (has_alpha) {
+ tmp_size += work_size;
+ }
+ p->memory = calloc(1, tmp_size * sizeof(*work));
+ if (p->memory == NULL) {
+ return 0; // memory error
+ }
+ work = (int32_t*)p->memory;
+ WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h,
+ buf->y, out_width, out_height, buf->y_stride, 1,
+ io->mb_w, out_width, io->mb_h, out_height,
+ work);
+ WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height,
+ buf->u, uv_out_width, uv_out_height, buf->u_stride, 1,
+ uv_in_width, uv_out_width,
+ uv_in_height, uv_out_height,
+ work + work_size);
+ WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height,
+ buf->v, uv_out_width, uv_out_height, buf->v_stride, 1,
+ uv_in_width, uv_out_width,
+ uv_in_height, uv_out_height,
+ work + work_size + uv_work_size);
+ p->emit = EmitRescaledYUV;
+
+ if (has_alpha) {
+ WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h,
+ buf->a, out_width, out_height, buf->a_stride, 1,
+ io->mb_w, out_width, io->mb_h, out_height,
+ work + work_size + 2 * uv_work_size);
+ p->emit_alpha = EmitRescaledAlphaYUV;
+ }
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+// RGBA rescaling
+
+static int ExportRGB(WebPDecParams* const p, int y_pos) {
+ const WebPYUV444Converter convert =
+ WebPYUV444Converters[p->output->colorspace];
+ const WebPRGBABuffer* const buf = &p->output->u.RGBA;
+ uint8_t* dst = buf->rgba + (p->last_y + y_pos) * buf->stride;
+ int num_lines_out = 0;
+ // For RGB rescaling, because of the YUV420, current scan position
+ // U/V can be +1/-1 line from the Y one. Hence the double test.
+ while (WebPRescalerHasPendingOutput(&p->scaler_y) &&
+ WebPRescalerHasPendingOutput(&p->scaler_u)) {
+ assert(p->last_y + y_pos + num_lines_out < p->output->height);
+ assert(p->scaler_u.y_accum == p->scaler_v.y_accum);
+ WebPRescalerExportRow(&p->scaler_y);
+ WebPRescalerExportRow(&p->scaler_u);
+ WebPRescalerExportRow(&p->scaler_v);
+ convert(p->scaler_y.dst, p->scaler_u.dst, p->scaler_v.dst,
+ dst, p->scaler_y.dst_width);
+ dst += buf->stride;
+ ++num_lines_out;
+ }
+ return num_lines_out;
+}
+
+static int EmitRescaledRGB(const VP8Io* const io, WebPDecParams* const p) {
+ const int mb_h = io->mb_h;
+ const int uv_mb_h = (mb_h + 1) >> 1;
+ int j = 0, uv_j = 0;
+ int num_lines_out = 0;
+ while (j < mb_h) {
+ const int y_lines_in =
+ WebPRescalerImport(&p->scaler_y, mb_h - j,
+ io->y + j * io->y_stride, io->y_stride);
+ const int u_lines_in =
+ WebPRescalerImport(&p->scaler_u, uv_mb_h - uv_j,
+ io->u + uv_j * io->uv_stride, io->uv_stride);
+ const int v_lines_in =
+ WebPRescalerImport(&p->scaler_v, uv_mb_h - uv_j,
+ io->v + uv_j * io->uv_stride, io->uv_stride);
+ (void)v_lines_in; // remove a gcc warning
+ assert(u_lines_in == v_lines_in);
+ j += y_lines_in;
+ uv_j += u_lines_in;
+ num_lines_out += ExportRGB(p, num_lines_out);
+ }
+ return num_lines_out;
+}
+
+static int ExportAlpha(WebPDecParams* const p, int y_pos) {
+ const WebPRGBABuffer* const buf = &p->output->u.RGBA;
+ uint8_t* const base_rgba = buf->rgba + (p->last_y + y_pos) * buf->stride;
+ const WEBP_CSP_MODE colorspace = p->output->colorspace;
+ const int alpha_first =
+ (colorspace == MODE_ARGB || colorspace == MODE_Argb);
+ uint8_t* dst = base_rgba + (alpha_first ? 0 : 3);
+ int num_lines_out = 0;
+ const int is_premult_alpha = WebPIsPremultipliedMode(colorspace);
+ uint32_t alpha_mask = 0xff;
+ const int width = p->scaler_a.dst_width;
+
+ while (WebPRescalerHasPendingOutput(&p->scaler_a)) {
+ int i;
+ assert(p->last_y + y_pos + num_lines_out < p->output->height);
+ WebPRescalerExportRow(&p->scaler_a);
+ for (i = 0; i < width; ++i) {
+ const uint32_t alpha_value = p->scaler_a.dst[i];
+ dst[4 * i] = alpha_value;
+ alpha_mask &= alpha_value;
+ }
+ dst += buf->stride;
+ ++num_lines_out;
+ }
+ if (is_premult_alpha && alpha_mask != 0xff) {
+ WebPApplyAlphaMultiply(base_rgba, alpha_first,
+ width, num_lines_out, buf->stride);
+ }
+ return num_lines_out;
+}
+
+static int ExportAlphaRGBA4444(WebPDecParams* const p, int y_pos) {
+ const WebPRGBABuffer* const buf = &p->output->u.RGBA;
+ uint8_t* const base_rgba = buf->rgba + (p->last_y + y_pos) * buf->stride;
+ uint8_t* alpha_dst = base_rgba + 1;
+ int num_lines_out = 0;
+ const WEBP_CSP_MODE colorspace = p->output->colorspace;
+ const int width = p->scaler_a.dst_width;
+ const int is_premult_alpha = WebPIsPremultipliedMode(colorspace);
+ uint32_t alpha_mask = 0x0f;
+
+ while (WebPRescalerHasPendingOutput(&p->scaler_a)) {
+ int i;
+ assert(p->last_y + y_pos + num_lines_out < p->output->height);
+ WebPRescalerExportRow(&p->scaler_a);
+ for (i = 0; i < width; ++i) {
+ // Fill in the alpha value (converted to 4 bits).
+ const uint32_t alpha_value = p->scaler_a.dst[i] >> 4;
+ alpha_dst[2 * i] = (alpha_dst[2 * i] & 0xf0) | alpha_value;
+ alpha_mask &= alpha_value;
+ }
+ alpha_dst += buf->stride;
+ ++num_lines_out;
+ }
+ if (is_premult_alpha && alpha_mask != 0x0f) {
+ WebPApplyAlphaMultiply4444(base_rgba, width, num_lines_out, buf->stride);
+ }
+ return num_lines_out;
+}
+
+static int EmitRescaledAlphaRGB(const VP8Io* const io, WebPDecParams* const p) {
+ if (io->a != NULL) {
+ WebPRescaler* const scaler = &p->scaler_a;
+ int j = 0;
+ int pos = 0;
+ while (j < io->mb_h) {
+ j += WebPRescalerImport(scaler, io->mb_h - j,
+ io->a + j * io->width, io->width);
+ pos += p->emit_alpha_row(p, pos);
+ }
+ }
+ return 0;
+}
+
+static int InitRGBRescaler(const VP8Io* const io, WebPDecParams* const p) {
+ const int has_alpha = WebPIsAlphaMode(p->output->colorspace);
+ const int out_width = io->scaled_width;
+ const int out_height = io->scaled_height;
+ const int uv_in_width = (io->mb_w + 1) >> 1;
+ const int uv_in_height = (io->mb_h + 1) >> 1;
+ const size_t work_size = 2 * out_width; // scratch memory for one rescaler
+ int32_t* work; // rescalers work area
+ uint8_t* tmp; // tmp storage for scaled YUV444 samples before RGB conversion
+ size_t tmp_size1, tmp_size2;
+
+ tmp_size1 = 3 * work_size;
+ tmp_size2 = 3 * out_width;
+ if (has_alpha) {
+ tmp_size1 += work_size;
+ tmp_size2 += out_width;
+ }
+ p->memory = calloc(1, tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp));
+ if (p->memory == NULL) {
+ return 0; // memory error
+ }
+ work = (int32_t*)p->memory;
+ tmp = (uint8_t*)(work + tmp_size1);
+ WebPRescalerInit(&p->scaler_y, io->mb_w, io->mb_h,
+ tmp + 0 * out_width, out_width, out_height, 0, 1,
+ io->mb_w, out_width, io->mb_h, out_height,
+ work + 0 * work_size);
+ WebPRescalerInit(&p->scaler_u, uv_in_width, uv_in_height,
+ tmp + 1 * out_width, out_width, out_height, 0, 1,
+ io->mb_w, 2 * out_width, io->mb_h, 2 * out_height,
+ work + 1 * work_size);
+ WebPRescalerInit(&p->scaler_v, uv_in_width, uv_in_height,
+ tmp + 2 * out_width, out_width, out_height, 0, 1,
+ io->mb_w, 2 * out_width, io->mb_h, 2 * out_height,
+ work + 2 * work_size);
+ p->emit = EmitRescaledRGB;
+
+ if (has_alpha) {
+ WebPRescalerInit(&p->scaler_a, io->mb_w, io->mb_h,
+ tmp + 3 * out_width, out_width, out_height, 0, 1,
+ io->mb_w, out_width, io->mb_h, out_height,
+ work + 3 * work_size);
+ p->emit_alpha = EmitRescaledAlphaRGB;
+ if (p->output->colorspace == MODE_RGBA_4444 ||
+ p->output->colorspace == MODE_rgbA_4444) {
+ p->emit_alpha_row = ExportAlphaRGBA4444;
+ } else {
+ p->emit_alpha_row = ExportAlpha;
+ }
+ }
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+// Default custom functions
+
+static int CustomSetup(VP8Io* io) {
+ WebPDecParams* const p = (WebPDecParams*)io->opaque;
+ const WEBP_CSP_MODE colorspace = p->output->colorspace;
+ const int is_rgb = WebPIsRGBMode(colorspace);
+ const int is_alpha = WebPIsAlphaMode(colorspace);
+
+ p->memory = NULL;
+ p->emit = NULL;
+ p->emit_alpha = NULL;
+ p->emit_alpha_row = NULL;
+ if (!WebPIoInitFromOptions(p->options, io, is_alpha ? MODE_YUV : MODE_YUVA)) {
+ return 0;
+ }
+
+ if (io->use_scaling) {
+ const int ok = is_rgb ? InitRGBRescaler(io, p) : InitYUVRescaler(io, p);
+ if (!ok) {
+ return 0; // memory error
+ }
+ } else {
+ if (is_rgb) {
+ p->emit = EmitSampledRGB; // default
+#ifdef FANCY_UPSAMPLING
+ if (io->fancy_upsampling) {
+ const int uv_width = (io->mb_w + 1) >> 1;
+ p->memory = malloc(io->mb_w + 2 * uv_width);
+ if (p->memory == NULL) {
+ return 0; // memory error.
+ }
+ p->tmp_y = (uint8_t*)p->memory;
+ p->tmp_u = p->tmp_y + io->mb_w;
+ p->tmp_v = p->tmp_u + uv_width;
+ p->emit = EmitFancyRGB;
+ WebPInitUpsamplers();
+ }
+#endif
+ } else {
+ p->emit = EmitYUV;
+ }
+ if (is_alpha) { // need transparency output
+ if (WebPIsPremultipliedMode(colorspace)) WebPInitPremultiply();
+ p->emit_alpha =
+ (colorspace == MODE_RGBA_4444 || colorspace == MODE_rgbA_4444) ?
+ EmitAlphaRGBA4444
+ : is_rgb ? EmitAlphaRGB
+ : EmitAlphaYUV;
+ }
+ }
+
+ if (is_rgb) {
+ VP8YUVInit();
+ }
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+
+static int CustomPut(const VP8Io* io) {
+ WebPDecParams* const p = (WebPDecParams*)io->opaque;
+ const int mb_w = io->mb_w;
+ const int mb_h = io->mb_h;
+ int num_lines_out;
+ assert(!(io->mb_y & 1));
+
+ if (mb_w <= 0 || mb_h <= 0) {
+ return 0;
+ }
+ num_lines_out = p->emit(io, p);
+ if (p->emit_alpha) {
+ p->emit_alpha(io, p);
+ }
+ p->last_y += num_lines_out;
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+
+static void CustomTeardown(const VP8Io* io) {
+ WebPDecParams* const p = (WebPDecParams*)io->opaque;
+ free(p->memory);
+ p->memory = NULL;
+}
+
+//------------------------------------------------------------------------------
+// Main entry point
+
+void WebPInitCustomIo(WebPDecParams* const params, VP8Io* const io) {
+ io->put = CustomPut;
+ io->setup = CustomSetup;
+ io->teardown = CustomTeardown;
+ io->opaque = params;
+}
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webp/dec/layer.c b/drivers/webpold/dec/layer.c
index a3a5bdcfe8..a3a5bdcfe8 100644
--- a/drivers/webp/dec/layer.c
+++ b/drivers/webpold/dec/layer.c
diff --git a/drivers/webpold/dec/quant.c b/drivers/webpold/dec/quant.c
new file mode 100644
index 0000000000..d54097af0d
--- /dev/null
+++ b/drivers/webpold/dec/quant.c
@@ -0,0 +1,113 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Quantizer initialization
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./vp8i.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+static WEBP_INLINE int clip(int v, int M) {
+ return v < 0 ? 0 : v > M ? M : v;
+}
+
+// Paragraph 14.1
+static const uint8_t kDcTable[128] = {
+ 4, 5, 6, 7, 8, 9, 10, 10,
+ 11, 12, 13, 14, 15, 16, 17, 17,
+ 18, 19, 20, 20, 21, 21, 22, 22,
+ 23, 23, 24, 25, 25, 26, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 46, 47, 48, 49, 50,
+ 51, 52, 53, 54, 55, 56, 57, 58,
+ 59, 60, 61, 62, 63, 64, 65, 66,
+ 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 87, 88, 89,
+ 91, 93, 95, 96, 98, 100, 101, 102,
+ 104, 106, 108, 110, 112, 114, 116, 118,
+ 122, 124, 126, 128, 130, 132, 134, 136,
+ 138, 140, 143, 145, 148, 151, 154, 157
+};
+
+static const uint16_t kAcTable[128] = {
+ 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 57, 58, 60,
+ 62, 64, 66, 68, 70, 72, 74, 76,
+ 78, 80, 82, 84, 86, 88, 90, 92,
+ 94, 96, 98, 100, 102, 104, 106, 108,
+ 110, 112, 114, 116, 119, 122, 125, 128,
+ 131, 134, 137, 140, 143, 146, 149, 152,
+ 155, 158, 161, 164, 167, 170, 173, 177,
+ 181, 185, 189, 193, 197, 201, 205, 209,
+ 213, 217, 221, 225, 229, 234, 239, 245,
+ 249, 254, 259, 264, 269, 274, 279, 284
+};
+
+//------------------------------------------------------------------------------
+// Paragraph 9.6
+
+void VP8ParseQuant(VP8Decoder* const dec) {
+ VP8BitReader* const br = &dec->br_;
+ const int base_q0 = VP8GetValue(br, 7);
+ const int dqy1_dc = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0;
+ const int dqy2_dc = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0;
+ const int dqy2_ac = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0;
+ const int dquv_dc = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0;
+ const int dquv_ac = VP8Get(br) ? VP8GetSignedValue(br, 4) : 0;
+
+ const VP8SegmentHeader* const hdr = &dec->segment_hdr_;
+ int i;
+
+ for (i = 0; i < NUM_MB_SEGMENTS; ++i) {
+ int q;
+ if (hdr->use_segment_) {
+ q = hdr->quantizer_[i];
+ if (!hdr->absolute_delta_) {
+ q += base_q0;
+ }
+ } else {
+ if (i > 0) {
+ dec->dqm_[i] = dec->dqm_[0];
+ continue;
+ } else {
+ q = base_q0;
+ }
+ }
+ {
+ VP8QuantMatrix* const m = &dec->dqm_[i];
+ m->y1_mat_[0] = kDcTable[clip(q + dqy1_dc, 127)];
+ m->y1_mat_[1] = kAcTable[clip(q + 0, 127)];
+
+ m->y2_mat_[0] = kDcTable[clip(q + dqy2_dc, 127)] * 2;
+ // For all x in [0..284], x*155/100 is bitwise equal to (x*101581) >> 16.
+ // The smallest precision for that is '(x*6349) >> 12' but 16 is a good
+ // word size.
+ m->y2_mat_[1] = (kAcTable[clip(q + dqy2_ac, 127)] * 101581) >> 16;
+ if (m->y2_mat_[1] < 8) m->y2_mat_[1] = 8;
+
+ m->uv_mat_[0] = kDcTable[clip(q + dquv_dc, 117)];
+ m->uv_mat_[1] = kAcTable[clip(q + dquv_ac, 127)];
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/dec/tree.c b/drivers/webpold/dec/tree.c
new file mode 100644
index 0000000000..82484e4c55
--- /dev/null
+++ b/drivers/webpold/dec/tree.c
@@ -0,0 +1,589 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Coding trees and probas
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "vp8i.h"
+
+#define USE_GENERIC_TREE
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#ifdef USE_GENERIC_TREE
+static const int8_t kYModesIntra4[18] = {
+ -B_DC_PRED, 1,
+ -B_TM_PRED, 2,
+ -B_VE_PRED, 3,
+ 4, 6,
+ -B_HE_PRED, 5,
+ -B_RD_PRED, -B_VR_PRED,
+ -B_LD_PRED, 7,
+ -B_VL_PRED, 8,
+ -B_HD_PRED, -B_HU_PRED
+};
+#endif
+
+#ifndef ONLY_KEYFRAME_CODE
+
+// inter prediction modes
+enum {
+ LEFT4 = 0, ABOVE4 = 1, ZERO4 = 2, NEW4 = 3,
+ NEARESTMV, NEARMV, ZEROMV, NEWMV, SPLITMV };
+
+static const int8_t kYModesInter[8] = {
+ -DC_PRED, 1,
+ 2, 3,
+ -V_PRED, -H_PRED,
+ -TM_PRED, -B_PRED
+};
+
+static const int8_t kMBSplit[6] = {
+ -3, 1,
+ -2, 2,
+ -0, -1
+};
+
+static const int8_t kMVRef[8] = {
+ -ZEROMV, 1,
+ -NEARESTMV, 2,
+ -NEARMV, 3,
+ -NEWMV, -SPLITMV
+};
+
+static const int8_t kMVRef4[6] = {
+ -LEFT4, 1,
+ -ABOVE4, 2,
+ -ZERO4, -NEW4
+};
+#endif
+
+//------------------------------------------------------------------------------
+// Default probabilities
+
+// Inter
+#ifndef ONLY_KEYFRAME_CODE
+static const uint8_t kYModeProbaInter0[4] = { 112, 86, 140, 37 };
+static const uint8_t kUVModeProbaInter0[3] = { 162, 101, 204 };
+static const uint8_t kMVProba0[2][NUM_MV_PROBAS] = {
+ { 162, 128, 225, 146, 172, 147, 214, 39,
+ 156, 128, 129, 132, 75, 145, 178, 206,
+ 239, 254, 254 },
+ { 164, 128, 204, 170, 119, 235, 140, 230,
+ 228, 128, 130, 130, 74, 148, 180, 203,
+ 236, 254, 254 }
+};
+#endif
+
+// Paragraph 13.5
+static const uint8_t
+ CoeffsProba0[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS] = {
+ // genereated using vp8_default_coef_probs() in entropy.c:129
+ { { { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }
+ },
+ { { 253, 136, 254, 255, 228, 219, 128, 128, 128, 128, 128 },
+ { 189, 129, 242, 255, 227, 213, 255, 219, 128, 128, 128 },
+ { 106, 126, 227, 252, 214, 209, 255, 255, 128, 128, 128 }
+ },
+ { { 1, 98, 248, 255, 236, 226, 255, 255, 128, 128, 128 },
+ { 181, 133, 238, 254, 221, 234, 255, 154, 128, 128, 128 },
+ { 78, 134, 202, 247, 198, 180, 255, 219, 128, 128, 128 },
+ },
+ { { 1, 185, 249, 255, 243, 255, 128, 128, 128, 128, 128 },
+ { 184, 150, 247, 255, 236, 224, 128, 128, 128, 128, 128 },
+ { 77, 110, 216, 255, 236, 230, 128, 128, 128, 128, 128 },
+ },
+ { { 1, 101, 251, 255, 241, 255, 128, 128, 128, 128, 128 },
+ { 170, 139, 241, 252, 236, 209, 255, 255, 128, 128, 128 },
+ { 37, 116, 196, 243, 228, 255, 255, 255, 128, 128, 128 }
+ },
+ { { 1, 204, 254, 255, 245, 255, 128, 128, 128, 128, 128 },
+ { 207, 160, 250, 255, 238, 128, 128, 128, 128, 128, 128 },
+ { 102, 103, 231, 255, 211, 171, 128, 128, 128, 128, 128 }
+ },
+ { { 1, 152, 252, 255, 240, 255, 128, 128, 128, 128, 128 },
+ { 177, 135, 243, 255, 234, 225, 128, 128, 128, 128, 128 },
+ { 80, 129, 211, 255, 194, 224, 128, 128, 128, 128, 128 }
+ },
+ { { 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 246, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }
+ }
+ },
+ { { { 198, 35, 237, 223, 193, 187, 162, 160, 145, 155, 62 },
+ { 131, 45, 198, 221, 172, 176, 220, 157, 252, 221, 1 },
+ { 68, 47, 146, 208, 149, 167, 221, 162, 255, 223, 128 }
+ },
+ { { 1, 149, 241, 255, 221, 224, 255, 255, 128, 128, 128 },
+ { 184, 141, 234, 253, 222, 220, 255, 199, 128, 128, 128 },
+ { 81, 99, 181, 242, 176, 190, 249, 202, 255, 255, 128 }
+ },
+ { { 1, 129, 232, 253, 214, 197, 242, 196, 255, 255, 128 },
+ { 99, 121, 210, 250, 201, 198, 255, 202, 128, 128, 128 },
+ { 23, 91, 163, 242, 170, 187, 247, 210, 255, 255, 128 }
+ },
+ { { 1, 200, 246, 255, 234, 255, 128, 128, 128, 128, 128 },
+ { 109, 178, 241, 255, 231, 245, 255, 255, 128, 128, 128 },
+ { 44, 130, 201, 253, 205, 192, 255, 255, 128, 128, 128 }
+ },
+ { { 1, 132, 239, 251, 219, 209, 255, 165, 128, 128, 128 },
+ { 94, 136, 225, 251, 218, 190, 255, 255, 128, 128, 128 },
+ { 22, 100, 174, 245, 186, 161, 255, 199, 128, 128, 128 }
+ },
+ { { 1, 182, 249, 255, 232, 235, 128, 128, 128, 128, 128 },
+ { 124, 143, 241, 255, 227, 234, 128, 128, 128, 128, 128 },
+ { 35, 77, 181, 251, 193, 211, 255, 205, 128, 128, 128 }
+ },
+ { { 1, 157, 247, 255, 236, 231, 255, 255, 128, 128, 128 },
+ { 121, 141, 235, 255, 225, 227, 255, 255, 128, 128, 128 },
+ { 45, 99, 188, 251, 195, 217, 255, 224, 128, 128, 128 }
+ },
+ { { 1, 1, 251, 255, 213, 255, 128, 128, 128, 128, 128 },
+ { 203, 1, 248, 255, 255, 128, 128, 128, 128, 128, 128 },
+ { 137, 1, 177, 255, 224, 255, 128, 128, 128, 128, 128 }
+ }
+ },
+ { { { 253, 9, 248, 251, 207, 208, 255, 192, 128, 128, 128 },
+ { 175, 13, 224, 243, 193, 185, 249, 198, 255, 255, 128 },
+ { 73, 17, 171, 221, 161, 179, 236, 167, 255, 234, 128 }
+ },
+ { { 1, 95, 247, 253, 212, 183, 255, 255, 128, 128, 128 },
+ { 239, 90, 244, 250, 211, 209, 255, 255, 128, 128, 128 },
+ { 155, 77, 195, 248, 188, 195, 255, 255, 128, 128, 128 }
+ },
+ { { 1, 24, 239, 251, 218, 219, 255, 205, 128, 128, 128 },
+ { 201, 51, 219, 255, 196, 186, 128, 128, 128, 128, 128 },
+ { 69, 46, 190, 239, 201, 218, 255, 228, 128, 128, 128 }
+ },
+ { { 1, 191, 251, 255, 255, 128, 128, 128, 128, 128, 128 },
+ { 223, 165, 249, 255, 213, 255, 128, 128, 128, 128, 128 },
+ { 141, 124, 248, 255, 255, 128, 128, 128, 128, 128, 128 }
+ },
+ { { 1, 16, 248, 255, 255, 128, 128, 128, 128, 128, 128 },
+ { 190, 36, 230, 255, 236, 255, 128, 128, 128, 128, 128 },
+ { 149, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }
+ },
+ { { 1, 226, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 247, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 240, 128, 255, 128, 128, 128, 128, 128, 128, 128, 128 }
+ },
+ { { 1, 134, 252, 255, 255, 128, 128, 128, 128, 128, 128 },
+ { 213, 62, 250, 255, 255, 128, 128, 128, 128, 128, 128 },
+ { 55, 93, 255, 128, 128, 128, 128, 128, 128, 128, 128 }
+ },
+ { { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }
+ }
+ },
+ { { { 202, 24, 213, 235, 186, 191, 220, 160, 240, 175, 255 },
+ { 126, 38, 182, 232, 169, 184, 228, 174, 255, 187, 128 },
+ { 61, 46, 138, 219, 151, 178, 240, 170, 255, 216, 128 }
+ },
+ { { 1, 112, 230, 250, 199, 191, 247, 159, 255, 255, 128 },
+ { 166, 109, 228, 252, 211, 215, 255, 174, 128, 128, 128 },
+ { 39, 77, 162, 232, 172, 180, 245, 178, 255, 255, 128 }
+ },
+ { { 1, 52, 220, 246, 198, 199, 249, 220, 255, 255, 128 },
+ { 124, 74, 191, 243, 183, 193, 250, 221, 255, 255, 128 },
+ { 24, 71, 130, 219, 154, 170, 243, 182, 255, 255, 128 }
+ },
+ { { 1, 182, 225, 249, 219, 240, 255, 224, 128, 128, 128 },
+ { 149, 150, 226, 252, 216, 205, 255, 171, 128, 128, 128 },
+ { 28, 108, 170, 242, 183, 194, 254, 223, 255, 255, 128 }
+ },
+ { { 1, 81, 230, 252, 204, 203, 255, 192, 128, 128, 128 },
+ { 123, 102, 209, 247, 188, 196, 255, 233, 128, 128, 128 },
+ { 20, 95, 153, 243, 164, 173, 255, 203, 128, 128, 128 }
+ },
+ { { 1, 222, 248, 255, 216, 213, 128, 128, 128, 128, 128 },
+ { 168, 175, 246, 252, 235, 205, 255, 255, 128, 128, 128 },
+ { 47, 116, 215, 255, 211, 212, 255, 255, 128, 128, 128 }
+ },
+ { { 1, 121, 236, 253, 212, 214, 255, 255, 128, 128, 128 },
+ { 141, 84, 213, 252, 201, 202, 255, 219, 128, 128, 128 },
+ { 42, 80, 160, 240, 162, 185, 255, 205, 128, 128, 128 }
+ },
+ { { 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 244, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 238, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }
+ }
+ }
+};
+
+// Paragraph 11.5
+static const uint8_t kBModesProba[NUM_BMODES][NUM_BMODES][NUM_BMODES - 1] = {
+ { { 231, 120, 48, 89, 115, 113, 120, 152, 112 },
+ { 152, 179, 64, 126, 170, 118, 46, 70, 95 },
+ { 175, 69, 143, 80, 85, 82, 72, 155, 103 },
+ { 56, 58, 10, 171, 218, 189, 17, 13, 152 },
+ { 114, 26, 17, 163, 44, 195, 21, 10, 173 },
+ { 121, 24, 80, 195, 26, 62, 44, 64, 85 },
+ { 144, 71, 10, 38, 171, 213, 144, 34, 26 },
+ { 170, 46, 55, 19, 136, 160, 33, 206, 71 },
+ { 63, 20, 8, 114, 114, 208, 12, 9, 226 },
+ { 81, 40, 11, 96, 182, 84, 29, 16, 36 } },
+ { { 134, 183, 89, 137, 98, 101, 106, 165, 148 },
+ { 72, 187, 100, 130, 157, 111, 32, 75, 80 },
+ { 66, 102, 167, 99, 74, 62, 40, 234, 128 },
+ { 41, 53, 9, 178, 241, 141, 26, 8, 107 },
+ { 74, 43, 26, 146, 73, 166, 49, 23, 157 },
+ { 65, 38, 105, 160, 51, 52, 31, 115, 128 },
+ { 104, 79, 12, 27, 217, 255, 87, 17, 7 },
+ { 87, 68, 71, 44, 114, 51, 15, 186, 23 },
+ { 47, 41, 14, 110, 182, 183, 21, 17, 194 },
+ { 66, 45, 25, 102, 197, 189, 23, 18, 22 } },
+ { { 88, 88, 147, 150, 42, 46, 45, 196, 205 },
+ { 43, 97, 183, 117, 85, 38, 35, 179, 61 },
+ { 39, 53, 200, 87, 26, 21, 43, 232, 171 },
+ { 56, 34, 51, 104, 114, 102, 29, 93, 77 },
+ { 39, 28, 85, 171, 58, 165, 90, 98, 64 },
+ { 34, 22, 116, 206, 23, 34, 43, 166, 73 },
+ { 107, 54, 32, 26, 51, 1, 81, 43, 31 },
+ { 68, 25, 106, 22, 64, 171, 36, 225, 114 },
+ { 34, 19, 21, 102, 132, 188, 16, 76, 124 },
+ { 62, 18, 78, 95, 85, 57, 50, 48, 51 } },
+ { { 193, 101, 35, 159, 215, 111, 89, 46, 111 },
+ { 60, 148, 31, 172, 219, 228, 21, 18, 111 },
+ { 112, 113, 77, 85, 179, 255, 38, 120, 114 },
+ { 40, 42, 1, 196, 245, 209, 10, 25, 109 },
+ { 88, 43, 29, 140, 166, 213, 37, 43, 154 },
+ { 61, 63, 30, 155, 67, 45, 68, 1, 209 },
+ { 100, 80, 8, 43, 154, 1, 51, 26, 71 },
+ { 142, 78, 78, 16, 255, 128, 34, 197, 171 },
+ { 41, 40, 5, 102, 211, 183, 4, 1, 221 },
+ { 51, 50, 17, 168, 209, 192, 23, 25, 82 } },
+ { { 138, 31, 36, 171, 27, 166, 38, 44, 229 },
+ { 67, 87, 58, 169, 82, 115, 26, 59, 179 },
+ { 63, 59, 90, 180, 59, 166, 93, 73, 154 },
+ { 40, 40, 21, 116, 143, 209, 34, 39, 175 },
+ { 47, 15, 16, 183, 34, 223, 49, 45, 183 },
+ { 46, 17, 33, 183, 6, 98, 15, 32, 183 },
+ { 57, 46, 22, 24, 128, 1, 54, 17, 37 },
+ { 65, 32, 73, 115, 28, 128, 23, 128, 205 },
+ { 40, 3, 9, 115, 51, 192, 18, 6, 223 },
+ { 87, 37, 9, 115, 59, 77, 64, 21, 47 } },
+ { { 104, 55, 44, 218, 9, 54, 53, 130, 226 },
+ { 64, 90, 70, 205, 40, 41, 23, 26, 57 },
+ { 54, 57, 112, 184, 5, 41, 38, 166, 213 },
+ { 30, 34, 26, 133, 152, 116, 10, 32, 134 },
+ { 39, 19, 53, 221, 26, 114, 32, 73, 255 },
+ { 31, 9, 65, 234, 2, 15, 1, 118, 73 },
+ { 75, 32, 12, 51, 192, 255, 160, 43, 51 },
+ { 88, 31, 35, 67, 102, 85, 55, 186, 85 },
+ { 56, 21, 23, 111, 59, 205, 45, 37, 192 },
+ { 55, 38, 70, 124, 73, 102, 1, 34, 98 } },
+ { { 125, 98, 42, 88, 104, 85, 117, 175, 82 },
+ { 95, 84, 53, 89, 128, 100, 113, 101, 45 },
+ { 75, 79, 123, 47, 51, 128, 81, 171, 1 },
+ { 57, 17, 5, 71, 102, 57, 53, 41, 49 },
+ { 38, 33, 13, 121, 57, 73, 26, 1, 85 },
+ { 41, 10, 67, 138, 77, 110, 90, 47, 114 },
+ { 115, 21, 2, 10, 102, 255, 166, 23, 6 },
+ { 101, 29, 16, 10, 85, 128, 101, 196, 26 },
+ { 57, 18, 10, 102, 102, 213, 34, 20, 43 },
+ { 117, 20, 15, 36, 163, 128, 68, 1, 26 } },
+ { { 102, 61, 71, 37, 34, 53, 31, 243, 192 },
+ { 69, 60, 71, 38, 73, 119, 28, 222, 37 },
+ { 68, 45, 128, 34, 1, 47, 11, 245, 171 },
+ { 62, 17, 19, 70, 146, 85, 55, 62, 70 },
+ { 37, 43, 37, 154, 100, 163, 85, 160, 1 },
+ { 63, 9, 92, 136, 28, 64, 32, 201, 85 },
+ { 75, 15, 9, 9, 64, 255, 184, 119, 16 },
+ { 86, 6, 28, 5, 64, 255, 25, 248, 1 },
+ { 56, 8, 17, 132, 137, 255, 55, 116, 128 },
+ { 58, 15, 20, 82, 135, 57, 26, 121, 40 } },
+ { { 164, 50, 31, 137, 154, 133, 25, 35, 218 },
+ { 51, 103, 44, 131, 131, 123, 31, 6, 158 },
+ { 86, 40, 64, 135, 148, 224, 45, 183, 128 },
+ { 22, 26, 17, 131, 240, 154, 14, 1, 209 },
+ { 45, 16, 21, 91, 64, 222, 7, 1, 197 },
+ { 56, 21, 39, 155, 60, 138, 23, 102, 213 },
+ { 83, 12, 13, 54, 192, 255, 68, 47, 28 },
+ { 85, 26, 85, 85, 128, 128, 32, 146, 171 },
+ { 18, 11, 7, 63, 144, 171, 4, 4, 246 },
+ { 35, 27, 10, 146, 174, 171, 12, 26, 128 } },
+ { { 190, 80, 35, 99, 180, 80, 126, 54, 45 },
+ { 85, 126, 47, 87, 176, 51, 41, 20, 32 },
+ { 101, 75, 128, 139, 118, 146, 116, 128, 85 },
+ { 56, 41, 15, 176, 236, 85, 37, 9, 62 },
+ { 71, 30, 17, 119, 118, 255, 17, 18, 138 },
+ { 101, 38, 60, 138, 55, 70, 43, 26, 142 },
+ { 146, 36, 19, 30, 171, 255, 97, 27, 20 },
+ { 138, 45, 61, 62, 219, 1, 81, 188, 64 },
+ { 32, 41, 20, 117, 151, 142, 20, 21, 163 },
+ { 112, 19, 12, 61, 195, 128, 48, 4, 24 } }
+};
+
+void VP8ResetProba(VP8Proba* const proba) {
+ memset(proba->segments_, 255u, sizeof(proba->segments_));
+ memcpy(proba->coeffs_, CoeffsProba0, sizeof(CoeffsProba0));
+#ifndef ONLY_KEYFRAME_CODE
+ memcpy(proba->mv_, kMVProba0, sizeof(kMVProba0));
+ memcpy(proba->ymode_, kYModeProbaInter0, sizeof(kYModeProbaInter0));
+ memcpy(proba->uvmode_, kUVModeProbaInter0, sizeof(kUVModeProbaInter0));
+#endif
+}
+
+void VP8ParseIntraMode(VP8BitReader* const br, VP8Decoder* const dec) {
+ uint8_t* const top = dec->intra_t_ + 4 * dec->mb_x_;
+ uint8_t* const left = dec->intra_l_;
+ // Hardcoded 16x16 intra-mode decision tree.
+ dec->is_i4x4_ = !VP8GetBit(br, 145); // decide for B_PRED first
+ if (!dec->is_i4x4_) {
+ const int ymode =
+ VP8GetBit(br, 156) ? (VP8GetBit(br, 128) ? TM_PRED : H_PRED)
+ : (VP8GetBit(br, 163) ? V_PRED : DC_PRED);
+ dec->imodes_[0] = ymode;
+ memset(top, ymode, 4 * sizeof(top[0]));
+ memset(left, ymode, 4 * sizeof(left[0]));
+ } else {
+ uint8_t* modes = dec->imodes_;
+ int y;
+ for (y = 0; y < 4; ++y) {
+ int ymode = left[y];
+ int x;
+ for (x = 0; x < 4; ++x) {
+ const uint8_t* const prob = kBModesProba[top[x]][ymode];
+#ifdef USE_GENERIC_TREE
+ // Generic tree-parsing
+ int i = 0;
+ do {
+ i = kYModesIntra4[2 * i + VP8GetBit(br, prob[i])];
+ } while (i > 0);
+ ymode = -i;
+#else
+ // Hardcoded tree parsing
+ ymode = !VP8GetBit(br, prob[0]) ? B_DC_PRED :
+ !VP8GetBit(br, prob[1]) ? B_TM_PRED :
+ !VP8GetBit(br, prob[2]) ? B_VE_PRED :
+ !VP8GetBit(br, prob[3]) ?
+ (!VP8GetBit(br, prob[4]) ? B_HE_PRED :
+ (!VP8GetBit(br, prob[5]) ? B_RD_PRED : B_VR_PRED)) :
+ (!VP8GetBit(br, prob[6]) ? B_LD_PRED :
+ (!VP8GetBit(br, prob[7]) ? B_VL_PRED :
+ (!VP8GetBit(br, prob[8]) ? B_HD_PRED : B_HU_PRED)));
+#endif // USE_GENERIC_TREE
+ top[x] = ymode;
+ *modes++ = ymode;
+ }
+ left[y] = ymode;
+ }
+ }
+ // Hardcoded UVMode decision tree
+ dec->uvmode_ = !VP8GetBit(br, 142) ? DC_PRED
+ : !VP8GetBit(br, 114) ? V_PRED
+ : VP8GetBit(br, 183) ? TM_PRED : H_PRED;
+}
+
+//------------------------------------------------------------------------------
+// Paragraph 13
+
+static const uint8_t
+ CoeffsUpdateProba[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS] = {
+ { { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 176, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 223, 241, 252, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 249, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 244, 252, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 234, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 246, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 239, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 251, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 251, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 254, 253, 255, 254, 255, 255, 255, 255, 255, 255 },
+ { 250, 255, 254, 255, 254, 255, 255, 255, 255, 255, 255 },
+ { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ }
+ },
+ { { { 217, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 225, 252, 241, 253, 255, 255, 254, 255, 255, 255, 255 },
+ { 234, 250, 241, 250, 253, 255, 253, 254, 255, 255, 255 }
+ },
+ { { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 223, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 238, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 249, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 247, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ }
+ },
+ { { { 186, 251, 250, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 234, 251, 244, 254, 255, 255, 255, 255, 255, 255, 255 },
+ { 251, 251, 243, 253, 254, 255, 254, 255, 255, 255, 255 }
+ },
+ { { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 236, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 251, 253, 253, 254, 254, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ }
+ },
+ { { { 248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 250, 254, 252, 254, 255, 255, 255, 255, 255, 255, 255 },
+ { 248, 254, 249, 253, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 246, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 252, 254, 251, 254, 254, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 254, 252, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 248, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 253, 255, 254, 254, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 245, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 253, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 251, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 249, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 255, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ }
+ }
+};
+
+#ifndef ONLY_KEYFRAME_CODE
+static const uint8_t MVUpdateProba[2][NUM_MV_PROBAS] = {
+ { 237, 246, 253, 253, 254, 254, 254, 254,
+ 254, 254, 254, 254, 254, 254, 250, 250,
+ 252, 254, 254 },
+ { 231, 243, 245, 253, 254, 254, 254, 254,
+ 254, 254, 254, 254, 254, 254, 251, 251,
+ 254, 254, 254 }
+};
+#endif
+
+// Paragraph 9.9
+void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec) {
+ VP8Proba* const proba = &dec->proba_;
+ int t, b, c, p;
+ for (t = 0; t < NUM_TYPES; ++t) {
+ for (b = 0; b < NUM_BANDS; ++b) {
+ for (c = 0; c < NUM_CTX; ++c) {
+ for (p = 0; p < NUM_PROBAS; ++p) {
+ if (VP8GetBit(br, CoeffsUpdateProba[t][b][c][p])) {
+ proba->coeffs_[t][b][c][p] = VP8GetValue(br, 8);
+ }
+ }
+ }
+ }
+ }
+ dec->use_skip_proba_ = VP8Get(br);
+ if (dec->use_skip_proba_) {
+ dec->skip_p_ = VP8GetValue(br, 8);
+ }
+#ifndef ONLY_KEYFRAME_CODE
+ if (!dec->frm_hdr_.key_frame_) {
+ int i;
+ dec->intra_p_ = VP8GetValue(br, 8);
+ dec->last_p_ = VP8GetValue(br, 8);
+ dec->golden_p_ = VP8GetValue(br, 8);
+ if (VP8Get(br)) { // update y-mode
+ for (i = 0; i < 4; ++i) {
+ proba->ymode_[i] = VP8GetValue(br, 8);
+ }
+ }
+ if (VP8Get(br)) { // update uv-mode
+ for (i = 0; i < 3; ++i) {
+ proba->uvmode_[i] = VP8GetValue(br, 8);
+ }
+ }
+ // update MV
+ for (i = 0; i < 2; ++i) {
+ int k;
+ for (k = 0; k < NUM_MV_PROBAS; ++k) {
+ if (VP8GetBit(br, MVUpdateProba[i][k])) {
+ const int v = VP8GetValue(br, 7);
+ proba->mv_[i][k] = v ? v << 1 : 1;
+ }
+ }
+ }
+ }
+#endif
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/dec/vp8.c b/drivers/webpold/dec/vp8.c
new file mode 100644
index 0000000000..b0ccfa2a06
--- /dev/null
+++ b/drivers/webpold/dec/vp8.c
@@ -0,0 +1,787 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// main entry for the decoder
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <stdlib.h>
+
+#include "./vp8i.h"
+#include "./vp8li.h"
+#include "./webpi.h"
+#include "../utils/bit_reader.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+
+int WebPGetDecoderVersion(void) {
+ return (DEC_MAJ_VERSION << 16) | (DEC_MIN_VERSION << 8) | DEC_REV_VERSION;
+}
+
+//------------------------------------------------------------------------------
+// VP8Decoder
+
+static void SetOk(VP8Decoder* const dec) {
+ dec->status_ = VP8_STATUS_OK;
+ dec->error_msg_ = "OK";
+}
+
+int VP8InitIoInternal(VP8Io* const io, int version) {
+ if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) {
+ return 0; // mismatch error
+ }
+ if (io != NULL) {
+ memset(io, 0, sizeof(*io));
+ }
+ return 1;
+}
+
+VP8Decoder* VP8New(void) {
+ VP8Decoder* const dec = (VP8Decoder*)calloc(1, sizeof(*dec));
+ if (dec != NULL) {
+ SetOk(dec);
+ WebPWorkerInit(&dec->worker_);
+ dec->ready_ = 0;
+ dec->num_parts_ = 1;
+ }
+ return dec;
+}
+
+VP8StatusCode VP8Status(VP8Decoder* const dec) {
+ if (!dec) return VP8_STATUS_INVALID_PARAM;
+ return dec->status_;
+}
+
+const char* VP8StatusMessage(VP8Decoder* const dec) {
+ if (dec == NULL) return "no object";
+ if (!dec->error_msg_) return "OK";
+ return dec->error_msg_;
+}
+
+void VP8Delete(VP8Decoder* const dec) {
+ if (dec != NULL) {
+ VP8Clear(dec);
+ free(dec);
+ }
+}
+
+int VP8SetError(VP8Decoder* const dec,
+ VP8StatusCode error, const char* const msg) {
+ // TODO This check would be unnecessary if alpha decompression was separated
+ // from VP8ProcessRow/FinishRow. This avoids setting 'dec->status_' to
+ // something other than VP8_STATUS_BITSTREAM_ERROR on alpha decompression
+ // failure.
+ if (dec->status_ == VP8_STATUS_OK) {
+ dec->status_ = error;
+ dec->error_msg_ = msg;
+ dec->ready_ = 0;
+ }
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+
+int VP8CheckSignature(const uint8_t* const data, size_t data_size) {
+ return (data_size >= 3 &&
+ data[0] == 0x9d && data[1] == 0x01 && data[2] == 0x2a);
+}
+
+int VP8GetInfo(const uint8_t* data, size_t data_size, size_t chunk_size,
+ int* const width, int* const height) {
+ if (data == NULL || data_size < VP8_FRAME_HEADER_SIZE) {
+ return 0; // not enough data
+ }
+ // check signature
+ if (!VP8CheckSignature(data + 3, data_size - 3)) {
+ return 0; // Wrong signature.
+ } else {
+ const uint32_t bits = data[0] | (data[1] << 8) | (data[2] << 16);
+ const int key_frame = !(bits & 1);
+ const int w = ((data[7] << 8) | data[6]) & 0x3fff;
+ const int h = ((data[9] << 8) | data[8]) & 0x3fff;
+
+ if (!key_frame) { // Not a keyframe.
+ return 0;
+ }
+
+ if (((bits >> 1) & 7) > 3) {
+ return 0; // unknown profile
+ }
+ if (!((bits >> 4) & 1)) {
+ return 0; // first frame is invisible!
+ }
+ if (((bits >> 5)) >= chunk_size) { // partition_length
+ return 0; // inconsistent size information.
+ }
+
+ if (width) {
+ *width = w;
+ }
+ if (height) {
+ *height = h;
+ }
+
+ return 1;
+ }
+}
+
+//------------------------------------------------------------------------------
+// Header parsing
+
+static void ResetSegmentHeader(VP8SegmentHeader* const hdr) {
+ assert(hdr != NULL);
+ hdr->use_segment_ = 0;
+ hdr->update_map_ = 0;
+ hdr->absolute_delta_ = 1;
+ memset(hdr->quantizer_, 0, sizeof(hdr->quantizer_));
+ memset(hdr->filter_strength_, 0, sizeof(hdr->filter_strength_));
+}
+
+// Paragraph 9.3
+static int ParseSegmentHeader(VP8BitReader* br,
+ VP8SegmentHeader* hdr, VP8Proba* proba) {
+ assert(br != NULL);
+ assert(hdr != NULL);
+ hdr->use_segment_ = VP8Get(br);
+ if (hdr->use_segment_) {
+ hdr->update_map_ = VP8Get(br);
+ if (VP8Get(br)) { // update data
+ int s;
+ hdr->absolute_delta_ = VP8Get(br);
+ for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
+ hdr->quantizer_[s] = VP8Get(br) ? VP8GetSignedValue(br, 7) : 0;
+ }
+ for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
+ hdr->filter_strength_[s] = VP8Get(br) ? VP8GetSignedValue(br, 6) : 0;
+ }
+ }
+ if (hdr->update_map_) {
+ int s;
+ for (s = 0; s < MB_FEATURE_TREE_PROBS; ++s) {
+ proba->segments_[s] = VP8Get(br) ? VP8GetValue(br, 8) : 255u;
+ }
+ }
+ } else {
+ hdr->update_map_ = 0;
+ }
+ return !br->eof_;
+}
+
+// Paragraph 9.5
+// This function returns VP8_STATUS_SUSPENDED if we don't have all the
+// necessary data in 'buf'.
+// This case is not necessarily an error (for incremental decoding).
+// Still, no bitreader is ever initialized to make it possible to read
+// unavailable memory.
+// If we don't even have the partitions' sizes, than VP8_STATUS_NOT_ENOUGH_DATA
+// is returned, and this is an unrecoverable error.
+// If the partitions were positioned ok, VP8_STATUS_OK is returned.
+static VP8StatusCode ParsePartitions(VP8Decoder* const dec,
+ const uint8_t* buf, size_t size) {
+ VP8BitReader* const br = &dec->br_;
+ const uint8_t* sz = buf;
+ const uint8_t* buf_end = buf + size;
+ const uint8_t* part_start;
+ int last_part;
+ int p;
+
+ dec->num_parts_ = 1 << VP8GetValue(br, 2);
+ last_part = dec->num_parts_ - 1;
+ part_start = buf + last_part * 3;
+ if (buf_end < part_start) {
+ // we can't even read the sizes with sz[]! That's a failure.
+ return VP8_STATUS_NOT_ENOUGH_DATA;
+ }
+ for (p = 0; p < last_part; ++p) {
+ const uint32_t psize = sz[0] | (sz[1] << 8) | (sz[2] << 16);
+ const uint8_t* part_end = part_start + psize;
+ if (part_end > buf_end) part_end = buf_end;
+ VP8InitBitReader(dec->parts_ + p, part_start, part_end);
+ part_start = part_end;
+ sz += 3;
+ }
+ VP8InitBitReader(dec->parts_ + last_part, part_start, buf_end);
+ return (part_start < buf_end) ? VP8_STATUS_OK :
+ VP8_STATUS_SUSPENDED; // Init is ok, but there's not enough data
+}
+
+// Paragraph 9.4
+static int ParseFilterHeader(VP8BitReader* br, VP8Decoder* const dec) {
+ VP8FilterHeader* const hdr = &dec->filter_hdr_;
+ hdr->simple_ = VP8Get(br);
+ hdr->level_ = VP8GetValue(br, 6);
+ hdr->sharpness_ = VP8GetValue(br, 3);
+ hdr->use_lf_delta_ = VP8Get(br);
+ if (hdr->use_lf_delta_) {
+ if (VP8Get(br)) { // update lf-delta?
+ int i;
+ for (i = 0; i < NUM_REF_LF_DELTAS; ++i) {
+ if (VP8Get(br)) {
+ hdr->ref_lf_delta_[i] = VP8GetSignedValue(br, 6);
+ }
+ }
+ for (i = 0; i < NUM_MODE_LF_DELTAS; ++i) {
+ if (VP8Get(br)) {
+ hdr->mode_lf_delta_[i] = VP8GetSignedValue(br, 6);
+ }
+ }
+ }
+ }
+ dec->filter_type_ = (hdr->level_ == 0) ? 0 : hdr->simple_ ? 1 : 2;
+ if (dec->filter_type_ > 0) { // precompute filter levels per segment
+ if (dec->segment_hdr_.use_segment_) {
+ int s;
+ for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
+ int strength = dec->segment_hdr_.filter_strength_[s];
+ if (!dec->segment_hdr_.absolute_delta_) {
+ strength += hdr->level_;
+ }
+ dec->filter_levels_[s] = strength;
+ }
+ } else {
+ dec->filter_levels_[0] = hdr->level_;
+ }
+ }
+ return !br->eof_;
+}
+
+// Topmost call
+int VP8GetHeaders(VP8Decoder* const dec, VP8Io* const io) {
+ const uint8_t* buf;
+ size_t buf_size;
+ VP8FrameHeader* frm_hdr;
+ VP8PictureHeader* pic_hdr;
+ VP8BitReader* br;
+ VP8StatusCode status;
+ WebPHeaderStructure headers;
+
+ if (dec == NULL) {
+ return 0;
+ }
+ SetOk(dec);
+ if (io == NULL) {
+ return VP8SetError(dec, VP8_STATUS_INVALID_PARAM,
+ "null VP8Io passed to VP8GetHeaders()");
+ }
+
+ // Process Pre-VP8 chunks.
+ headers.data = io->data;
+ headers.data_size = io->data_size;
+ status = WebPParseHeaders(&headers);
+ if (status != VP8_STATUS_OK) {
+ return VP8SetError(dec, status, "Incorrect/incomplete header.");
+ }
+ if (headers.is_lossless) {
+ return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
+ "Unexpected lossless format encountered.");
+ }
+
+ if (dec->alpha_data_ == NULL) {
+ assert(dec->alpha_data_size_ == 0);
+ // We have NOT set alpha data yet. Set it now.
+ // (This is to ensure that dec->alpha_data_ is NOT reset to NULL if
+ // WebPParseHeaders() is called more than once, as in incremental decoding
+ // case.)
+ dec->alpha_data_ = headers.alpha_data;
+ dec->alpha_data_size_ = headers.alpha_data_size;
+ }
+
+ // Process the VP8 frame header.
+ buf = headers.data + headers.offset;
+ buf_size = headers.data_size - headers.offset;
+ assert(headers.data_size >= headers.offset); // WebPParseHeaders' guarantee
+ if (buf_size < 4) {
+ return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
+ "Truncated header.");
+ }
+
+ // Paragraph 9.1
+ {
+ const uint32_t bits = buf[0] | (buf[1] << 8) | (buf[2] << 16);
+ frm_hdr = &dec->frm_hdr_;
+ frm_hdr->key_frame_ = !(bits & 1);
+ frm_hdr->profile_ = (bits >> 1) & 7;
+ frm_hdr->show_ = (bits >> 4) & 1;
+ frm_hdr->partition_length_ = (bits >> 5);
+ if (frm_hdr->profile_ > 3)
+ return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
+ "Incorrect keyframe parameters.");
+ if (!frm_hdr->show_)
+ return VP8SetError(dec, VP8_STATUS_UNSUPPORTED_FEATURE,
+ "Frame not displayable.");
+ buf += 3;
+ buf_size -= 3;
+ }
+
+ pic_hdr = &dec->pic_hdr_;
+ if (frm_hdr->key_frame_) {
+ // Paragraph 9.2
+ if (buf_size < 7) {
+ return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
+ "cannot parse picture header");
+ }
+ if (!VP8CheckSignature(buf, buf_size)) {
+ return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
+ "Bad code word");
+ }
+ pic_hdr->width_ = ((buf[4] << 8) | buf[3]) & 0x3fff;
+ pic_hdr->xscale_ = buf[4] >> 6; // ratio: 1, 5/4 5/3 or 2
+ pic_hdr->height_ = ((buf[6] << 8) | buf[5]) & 0x3fff;
+ pic_hdr->yscale_ = buf[6] >> 6;
+ buf += 7;
+ buf_size -= 7;
+
+ dec->mb_w_ = (pic_hdr->width_ + 15) >> 4;
+ dec->mb_h_ = (pic_hdr->height_ + 15) >> 4;
+ // Setup default output area (can be later modified during io->setup())
+ io->width = pic_hdr->width_;
+ io->height = pic_hdr->height_;
+ io->use_scaling = 0;
+ io->use_cropping = 0;
+ io->crop_top = 0;
+ io->crop_left = 0;
+ io->crop_right = io->width;
+ io->crop_bottom = io->height;
+ io->mb_w = io->width; // sanity check
+ io->mb_h = io->height; // ditto
+
+ VP8ResetProba(&dec->proba_);
+ ResetSegmentHeader(&dec->segment_hdr_);
+ dec->segment_ = 0; // default for intra
+ }
+
+ // Check if we have all the partition #0 available, and initialize dec->br_
+ // to read this partition (and this partition only).
+ if (frm_hdr->partition_length_ > buf_size) {
+ return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
+ "bad partition length");
+ }
+
+ br = &dec->br_;
+ VP8InitBitReader(br, buf, buf + frm_hdr->partition_length_);
+ buf += frm_hdr->partition_length_;
+ buf_size -= frm_hdr->partition_length_;
+
+ if (frm_hdr->key_frame_) {
+ pic_hdr->colorspace_ = VP8Get(br);
+ pic_hdr->clamp_type_ = VP8Get(br);
+ }
+ if (!ParseSegmentHeader(br, &dec->segment_hdr_, &dec->proba_)) {
+ return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
+ "cannot parse segment header");
+ }
+ // Filter specs
+ if (!ParseFilterHeader(br, dec)) {
+ return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
+ "cannot parse filter header");
+ }
+ status = ParsePartitions(dec, buf, buf_size);
+ if (status != VP8_STATUS_OK) {
+ return VP8SetError(dec, status, "cannot parse partitions");
+ }
+
+ // quantizer change
+ VP8ParseQuant(dec);
+
+ // Frame buffer marking
+ if (!frm_hdr->key_frame_) {
+ // Paragraph 9.7
+#ifndef ONLY_KEYFRAME_CODE
+ dec->buffer_flags_ = VP8Get(br) << 0; // update golden
+ dec->buffer_flags_ |= VP8Get(br) << 1; // update alt ref
+ if (!(dec->buffer_flags_ & 1)) {
+ dec->buffer_flags_ |= VP8GetValue(br, 2) << 2;
+ }
+ if (!(dec->buffer_flags_ & 2)) {
+ dec->buffer_flags_ |= VP8GetValue(br, 2) << 4;
+ }
+ dec->buffer_flags_ |= VP8Get(br) << 6; // sign bias golden
+ dec->buffer_flags_ |= VP8Get(br) << 7; // sign bias alt ref
+#else
+ return VP8SetError(dec, VP8_STATUS_UNSUPPORTED_FEATURE,
+ "Not a key frame.");
+#endif
+ } else {
+ dec->buffer_flags_ = 0x003 | 0x100;
+ }
+
+ // Paragraph 9.8
+#ifndef ONLY_KEYFRAME_CODE
+ dec->update_proba_ = VP8Get(br);
+ if (!dec->update_proba_) { // save for later restore
+ dec->proba_saved_ = dec->proba_;
+ }
+ dec->buffer_flags_ &= 1 << 8;
+ dec->buffer_flags_ |=
+ (frm_hdr->key_frame_ || VP8Get(br)) << 8; // refresh last frame
+#else
+ VP8Get(br); // just ignore the value of update_proba_
+#endif
+
+ VP8ParseProba(br, dec);
+
+#ifdef WEBP_EXPERIMENTAL_FEATURES
+ // Extensions
+ if (dec->pic_hdr_.colorspace_) {
+ const size_t kTrailerSize = 8;
+ const uint8_t kTrailerMarker = 0x01;
+ const uint8_t* ext_buf = buf - kTrailerSize;
+ size_t size;
+
+ if (frm_hdr->partition_length_ < kTrailerSize ||
+ ext_buf[kTrailerSize - 1] != kTrailerMarker) {
+ return VP8SetError(dec, VP8_STATUS_BITSTREAM_ERROR,
+ "RIFF: Inconsistent extra information.");
+ }
+
+ // Layer
+ size = (ext_buf[0] << 0) | (ext_buf[1] << 8) | (ext_buf[2] << 16);
+ dec->layer_data_size_ = size;
+ dec->layer_data_ = NULL; // will be set later
+ dec->layer_colorspace_ = ext_buf[3];
+ }
+#endif
+
+ // sanitized state
+ dec->ready_ = 1;
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+// Residual decoding (Paragraph 13.2 / 13.3)
+
+static const uint8_t kBands[16 + 1] = {
+ 0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7,
+ 0 // extra entry as sentinel
+};
+
+static const uint8_t kCat3[] = { 173, 148, 140, 0 };
+static const uint8_t kCat4[] = { 176, 155, 140, 135, 0 };
+static const uint8_t kCat5[] = { 180, 157, 141, 134, 130, 0 };
+static const uint8_t kCat6[] =
+ { 254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129, 0 };
+static const uint8_t* const kCat3456[] = { kCat3, kCat4, kCat5, kCat6 };
+static const uint8_t kZigzag[16] = {
+ 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15
+};
+
+typedef const uint8_t (*ProbaArray)[NUM_CTX][NUM_PROBAS]; // for const-casting
+
+// Returns the position of the last non-zero coeff plus one
+// (and 0 if there's no coeff at all)
+static int GetCoeffs(VP8BitReader* const br, ProbaArray prob,
+ int ctx, const quant_t dq, int n, int16_t* out) {
+ // n is either 0 or 1 here. kBands[n] is not necessary for extracting '*p'.
+ const uint8_t* p = prob[n][ctx];
+ if (!VP8GetBit(br, p[0])) { // first EOB is more a 'CBP' bit.
+ return 0;
+ }
+ while (1) {
+ ++n;
+ if (!VP8GetBit(br, p[1])) {
+ p = prob[kBands[n]][0];
+ } else { // non zero coeff
+ int v, j;
+ if (!VP8GetBit(br, p[2])) {
+ p = prob[kBands[n]][1];
+ v = 1;
+ } else {
+ if (!VP8GetBit(br, p[3])) {
+ if (!VP8GetBit(br, p[4])) {
+ v = 2;
+ } else {
+ v = 3 + VP8GetBit(br, p[5]);
+ }
+ } else {
+ if (!VP8GetBit(br, p[6])) {
+ if (!VP8GetBit(br, p[7])) {
+ v = 5 + VP8GetBit(br, 159);
+ } else {
+ v = 7 + 2 * VP8GetBit(br, 165);
+ v += VP8GetBit(br, 145);
+ }
+ } else {
+ const uint8_t* tab;
+ const int bit1 = VP8GetBit(br, p[8]);
+ const int bit0 = VP8GetBit(br, p[9 + bit1]);
+ const int cat = 2 * bit1 + bit0;
+ v = 0;
+ for (tab = kCat3456[cat]; *tab; ++tab) {
+ v += v + VP8GetBit(br, *tab);
+ }
+ v += 3 + (8 << cat);
+ }
+ }
+ p = prob[kBands[n]][2];
+ }
+ j = kZigzag[n - 1];
+ out[j] = VP8GetSigned(br, v) * dq[j > 0];
+ if (n == 16 || !VP8GetBit(br, p[0])) { // EOB
+ return n;
+ }
+ }
+ if (n == 16) {
+ return 16;
+ }
+ }
+}
+
+// Alias-safe way of converting 4bytes to 32bits.
+typedef union {
+ uint8_t i8[4];
+ uint32_t i32;
+} PackedNz;
+
+// Table to unpack four bits into four bytes
+static const PackedNz kUnpackTab[16] = {
+ {{0, 0, 0, 0}}, {{1, 0, 0, 0}}, {{0, 1, 0, 0}}, {{1, 1, 0, 0}},
+ {{0, 0, 1, 0}}, {{1, 0, 1, 0}}, {{0, 1, 1, 0}}, {{1, 1, 1, 0}},
+ {{0, 0, 0, 1}}, {{1, 0, 0, 1}}, {{0, 1, 0, 1}}, {{1, 1, 0, 1}},
+ {{0, 0, 1, 1}}, {{1, 0, 1, 1}}, {{0, 1, 1, 1}}, {{1, 1, 1, 1}} };
+
+// Macro to pack four LSB of four bytes into four bits.
+#if defined(__PPC__) || defined(_M_PPC) || defined(_ARCH_PPC) || \
+ defined(__BIG_ENDIAN__)
+#define PACK_CST 0x08040201U
+#else
+#define PACK_CST 0x01020408U
+#endif
+#define PACK(X, S) ((((X).i32 * PACK_CST) & 0xff000000) >> (S))
+
+static void ParseResiduals(VP8Decoder* const dec,
+ VP8MB* const mb, VP8BitReader* const token_br) {
+ int out_t_nz, out_l_nz, first;
+ ProbaArray ac_prob;
+ const VP8QuantMatrix* q = &dec->dqm_[dec->segment_];
+ int16_t* dst = dec->coeffs_;
+ VP8MB* const left_mb = dec->mb_info_ - 1;
+ PackedNz nz_ac, nz_dc;
+ PackedNz tnz, lnz;
+ uint32_t non_zero_ac = 0;
+ uint32_t non_zero_dc = 0;
+ int x, y, ch;
+
+ nz_dc.i32 = nz_ac.i32 = 0;
+ memset(dst, 0, 384 * sizeof(*dst));
+ if (!dec->is_i4x4_) { // parse DC
+ int16_t dc[16] = { 0 };
+ const int ctx = mb->dc_nz_ + left_mb->dc_nz_;
+ mb->dc_nz_ = left_mb->dc_nz_ =
+ (GetCoeffs(token_br, (ProbaArray)dec->proba_.coeffs_[1],
+ ctx, q->y2_mat_, 0, dc) > 0);
+ first = 1;
+ ac_prob = (ProbaArray)dec->proba_.coeffs_[0];
+ VP8TransformWHT(dc, dst);
+ } else {
+ first = 0;
+ ac_prob = (ProbaArray)dec->proba_.coeffs_[3];
+ }
+
+ tnz = kUnpackTab[mb->nz_ & 0xf];
+ lnz = kUnpackTab[left_mb->nz_ & 0xf];
+ for (y = 0; y < 4; ++y) {
+ int l = lnz.i8[y];
+ for (x = 0; x < 4; ++x) {
+ const int ctx = l + tnz.i8[x];
+ const int nz = GetCoeffs(token_br, ac_prob, ctx,
+ q->y1_mat_, first, dst);
+ tnz.i8[x] = l = (nz > 0);
+ nz_dc.i8[x] = (dst[0] != 0);
+ nz_ac.i8[x] = (nz > 1);
+ dst += 16;
+ }
+ lnz.i8[y] = l;
+ non_zero_dc |= PACK(nz_dc, 24 - y * 4);
+ non_zero_ac |= PACK(nz_ac, 24 - y * 4);
+ }
+ out_t_nz = PACK(tnz, 24);
+ out_l_nz = PACK(lnz, 24);
+
+ tnz = kUnpackTab[mb->nz_ >> 4];
+ lnz = kUnpackTab[left_mb->nz_ >> 4];
+ for (ch = 0; ch < 4; ch += 2) {
+ for (y = 0; y < 2; ++y) {
+ int l = lnz.i8[ch + y];
+ for (x = 0; x < 2; ++x) {
+ const int ctx = l + tnz.i8[ch + x];
+ const int nz =
+ GetCoeffs(token_br, (ProbaArray)dec->proba_.coeffs_[2],
+ ctx, q->uv_mat_, 0, dst);
+ tnz.i8[ch + x] = l = (nz > 0);
+ nz_dc.i8[y * 2 + x] = (dst[0] != 0);
+ nz_ac.i8[y * 2 + x] = (nz > 1);
+ dst += 16;
+ }
+ lnz.i8[ch + y] = l;
+ }
+ non_zero_dc |= PACK(nz_dc, 8 - ch * 2);
+ non_zero_ac |= PACK(nz_ac, 8 - ch * 2);
+ }
+ out_t_nz |= PACK(tnz, 20);
+ out_l_nz |= PACK(lnz, 20);
+ mb->nz_ = out_t_nz;
+ left_mb->nz_ = out_l_nz;
+
+ dec->non_zero_ac_ = non_zero_ac;
+ dec->non_zero_ = non_zero_ac | non_zero_dc;
+ mb->skip_ = !dec->non_zero_;
+}
+#undef PACK
+
+//------------------------------------------------------------------------------
+// Main loop
+
+int VP8DecodeMB(VP8Decoder* const dec, VP8BitReader* const token_br) {
+ VP8BitReader* const br = &dec->br_;
+ VP8MB* const left = dec->mb_info_ - 1;
+ VP8MB* const info = dec->mb_info_ + dec->mb_x_;
+
+ // Note: we don't save segment map (yet), as we don't expect
+ // to decode more than 1 keyframe.
+ if (dec->segment_hdr_.update_map_) {
+ // Hardcoded tree parsing
+ dec->segment_ = !VP8GetBit(br, dec->proba_.segments_[0]) ?
+ VP8GetBit(br, dec->proba_.segments_[1]) :
+ 2 + VP8GetBit(br, dec->proba_.segments_[2]);
+ }
+ info->skip_ = dec->use_skip_proba_ ? VP8GetBit(br, dec->skip_p_) : 0;
+
+ VP8ParseIntraMode(br, dec);
+ if (br->eof_) {
+ return 0;
+ }
+
+ if (!info->skip_) {
+ ParseResiduals(dec, info, token_br);
+ } else {
+ left->nz_ = info->nz_ = 0;
+ if (!dec->is_i4x4_) {
+ left->dc_nz_ = info->dc_nz_ = 0;
+ }
+ dec->non_zero_ = 0;
+ dec->non_zero_ac_ = 0;
+ }
+
+ return (!token_br->eof_);
+}
+
+void VP8InitScanline(VP8Decoder* const dec) {
+ VP8MB* const left = dec->mb_info_ - 1;
+ left->nz_ = 0;
+ left->dc_nz_ = 0;
+ memset(dec->intra_l_, B_DC_PRED, sizeof(dec->intra_l_));
+ dec->filter_row_ =
+ (dec->filter_type_ > 0) &&
+ (dec->mb_y_ >= dec->tl_mb_y_) && (dec->mb_y_ <= dec->br_mb_y_);
+}
+
+static int ParseFrame(VP8Decoder* const dec, VP8Io* io) {
+ for (dec->mb_y_ = 0; dec->mb_y_ < dec->br_mb_y_; ++dec->mb_y_) {
+ VP8BitReader* const token_br =
+ &dec->parts_[dec->mb_y_ & (dec->num_parts_ - 1)];
+ VP8InitScanline(dec);
+ for (dec->mb_x_ = 0; dec->mb_x_ < dec->mb_w_; dec->mb_x_++) {
+ if (!VP8DecodeMB(dec, token_br)) {
+ return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
+ "Premature end-of-file encountered.");
+ }
+ VP8ReconstructBlock(dec);
+
+ // Store data and save block's filtering params
+ VP8StoreBlock(dec);
+ }
+ if (!VP8ProcessRow(dec, io)) {
+ return VP8SetError(dec, VP8_STATUS_USER_ABORT, "Output aborted.");
+ }
+ }
+ if (dec->use_threads_ && !WebPWorkerSync(&dec->worker_)) {
+ return 0;
+ }
+
+ // Finish
+#ifndef ONLY_KEYFRAME_CODE
+ if (!dec->update_proba_) {
+ dec->proba_ = dec->proba_saved_;
+ }
+#endif
+
+#ifdef WEBP_EXPERIMENTAL_FEATURES
+ if (dec->layer_data_size_ > 0) {
+ if (!VP8DecodeLayer(dec)) {
+ return 0;
+ }
+ }
+#endif
+
+ return 1;
+}
+
+// Main entry point
+int VP8Decode(VP8Decoder* const dec, VP8Io* const io) {
+ int ok = 0;
+ if (dec == NULL) {
+ return 0;
+ }
+ if (io == NULL) {
+ return VP8SetError(dec, VP8_STATUS_INVALID_PARAM,
+ "NULL VP8Io parameter in VP8Decode().");
+ }
+
+ if (!dec->ready_) {
+ if (!VP8GetHeaders(dec, io)) {
+ return 0;
+ }
+ }
+ assert(dec->ready_);
+
+ // Finish setting up the decoding parameter. Will call io->setup().
+ ok = (VP8EnterCritical(dec, io) == VP8_STATUS_OK);
+ if (ok) { // good to go.
+ // Will allocate memory and prepare everything.
+ if (ok) ok = VP8InitFrame(dec, io);
+
+ // Main decoding loop
+ if (ok) ok = ParseFrame(dec, io);
+
+ // Exit.
+ ok &= VP8ExitCritical(dec, io);
+ }
+
+ if (!ok) {
+ VP8Clear(dec);
+ return 0;
+ }
+
+ dec->ready_ = 0;
+ return ok;
+}
+
+void VP8Clear(VP8Decoder* const dec) {
+ if (dec == NULL) {
+ return;
+ }
+ if (dec->use_threads_) {
+ WebPWorkerEnd(&dec->worker_);
+ }
+ if (dec->mem_) {
+ free(dec->mem_);
+ }
+ dec->mem_ = NULL;
+ dec->mem_size_ = 0;
+ memset(&dec->br_, 0, sizeof(dec->br_));
+ dec->ready_ = 0;
+}
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/dec/vp8i.h b/drivers/webpold/dec/vp8i.h
new file mode 100644
index 0000000000..4382edfd8e
--- /dev/null
+++ b/drivers/webpold/dec/vp8i.h
@@ -0,0 +1,335 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// VP8 decoder: internal header.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#ifndef WEBP_DEC_VP8I_H_
+#define WEBP_DEC_VP8I_H_
+
+#include <string.h> // for memcpy()
+#include "./vp8li.h"
+#include "../utils/bit_reader.h"
+#include "../utils/thread.h"
+#include "../dsp/dsp.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// Various defines and enums
+
+// version numbers
+#define DEC_MAJ_VERSION 0
+#define DEC_MIN_VERSION 2
+#define DEC_REV_VERSION 0
+
+#define ONLY_KEYFRAME_CODE // to remove any code related to P-Frames
+
+// intra prediction modes
+enum { B_DC_PRED = 0, // 4x4 modes
+ B_TM_PRED,
+ B_VE_PRED,
+ B_HE_PRED,
+ B_RD_PRED,
+ B_VR_PRED,
+ B_LD_PRED,
+ B_VL_PRED,
+ B_HD_PRED,
+ B_HU_PRED,
+ NUM_BMODES = B_HU_PRED + 1 - B_DC_PRED, // = 10
+
+ // Luma16 or UV modes
+ DC_PRED = B_DC_PRED, V_PRED = B_VE_PRED,
+ H_PRED = B_HE_PRED, TM_PRED = B_TM_PRED,
+ B_PRED = NUM_BMODES, // refined I4x4 mode
+
+ // special modes
+ B_DC_PRED_NOTOP = 4,
+ B_DC_PRED_NOLEFT = 5,
+ B_DC_PRED_NOTOPLEFT = 6,
+ NUM_B_DC_MODES = 7 };
+
+enum { MB_FEATURE_TREE_PROBS = 3,
+ NUM_MB_SEGMENTS = 4,
+ NUM_REF_LF_DELTAS = 4,
+ NUM_MODE_LF_DELTAS = 4, // I4x4, ZERO, *, SPLIT
+ MAX_NUM_PARTITIONS = 8,
+ // Probabilities
+ NUM_TYPES = 4,
+ NUM_BANDS = 8,
+ NUM_CTX = 3,
+ NUM_PROBAS = 11,
+ NUM_MV_PROBAS = 19 };
+
+// YUV-cache parameters.
+// Constraints are: We need to store one 16x16 block of luma samples (y),
+// and two 8x8 chroma blocks (u/v). These are better be 16-bytes aligned,
+// in order to be SIMD-friendly. We also need to store the top, left and
+// top-left samples (from previously decoded blocks), along with four
+// extra top-right samples for luma (intra4x4 prediction only).
+// One possible layout is, using 32 * (17 + 9) bytes:
+//
+// .+------ <- only 1 pixel high
+// .|yyyyt.
+// .|yyyyt.
+// .|yyyyt.
+// .|yyyy..
+// .+--.+-- <- only 1 pixel high
+// .|uu.|vv
+// .|uu.|vv
+//
+// Every character is a 4x4 block, with legend:
+// '.' = unused
+// 'y' = y-samples 'u' = u-samples 'v' = u-samples
+// '|' = left sample, '-' = top sample, '+' = top-left sample
+// 't' = extra top-right sample for 4x4 modes
+// With this layout, BPS (=Bytes Per Scan-line) is one cacheline size.
+#define BPS 32 // this is the common stride used by yuv[]
+#define YUV_SIZE (BPS * 17 + BPS * 9)
+#define Y_SIZE (BPS * 17)
+#define Y_OFF (BPS * 1 + 8)
+#define U_OFF (Y_OFF + BPS * 16 + BPS)
+#define V_OFF (U_OFF + 16)
+
+//------------------------------------------------------------------------------
+// Headers
+
+typedef struct {
+ uint8_t key_frame_;
+ uint8_t profile_;
+ uint8_t show_;
+ uint32_t partition_length_;
+} VP8FrameHeader;
+
+typedef struct {
+ uint16_t width_;
+ uint16_t height_;
+ uint8_t xscale_;
+ uint8_t yscale_;
+ uint8_t colorspace_; // 0 = YCbCr
+ uint8_t clamp_type_;
+} VP8PictureHeader;
+
+// segment features
+typedef struct {
+ int use_segment_;
+ int update_map_; // whether to update the segment map or not
+ int absolute_delta_; // absolute or delta values for quantizer and filter
+ int8_t quantizer_[NUM_MB_SEGMENTS]; // quantization changes
+ int8_t filter_strength_[NUM_MB_SEGMENTS]; // filter strength for segments
+} VP8SegmentHeader;
+
+// Struct collecting all frame-persistent probabilities.
+typedef struct {
+ uint8_t segments_[MB_FEATURE_TREE_PROBS];
+ // Type: 0:Intra16-AC 1:Intra16-DC 2:Chroma 3:Intra4
+ uint8_t coeffs_[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS];
+#ifndef ONLY_KEYFRAME_CODE
+ uint8_t ymode_[4], uvmode_[3];
+ uint8_t mv_[2][NUM_MV_PROBAS];
+#endif
+} VP8Proba;
+
+// Filter parameters
+typedef struct {
+ int simple_; // 0=complex, 1=simple
+ int level_; // [0..63]
+ int sharpness_; // [0..7]
+ int use_lf_delta_;
+ int ref_lf_delta_[NUM_REF_LF_DELTAS];
+ int mode_lf_delta_[NUM_MODE_LF_DELTAS];
+} VP8FilterHeader;
+
+//------------------------------------------------------------------------------
+// Informations about the macroblocks.
+
+typedef struct { // filter specs
+ unsigned int f_level_:6; // filter strength: 0..63
+ unsigned int f_ilevel_:6; // inner limit: 1..63
+ unsigned int f_inner_:1; // do inner filtering?
+} VP8FInfo;
+
+typedef struct { // used for syntax-parsing
+ unsigned int nz_; // non-zero AC/DC coeffs
+ unsigned int dc_nz_:1; // non-zero DC coeffs
+ unsigned int skip_:1; // block type
+} VP8MB;
+
+// Dequantization matrices
+typedef int quant_t[2]; // [DC / AC]. Can be 'uint16_t[2]' too (~slower).
+typedef struct {
+ quant_t y1_mat_, y2_mat_, uv_mat_;
+} VP8QuantMatrix;
+
+// Persistent information needed by the parallel processing
+typedef struct {
+ int id_; // cache row to process (in [0..2])
+ int mb_y_; // macroblock position of the row
+ int filter_row_; // true if row-filtering is needed
+ VP8FInfo* f_info_; // filter strengths
+ VP8Io io_; // copy of the VP8Io to pass to put()
+} VP8ThreadContext;
+
+//------------------------------------------------------------------------------
+// VP8Decoder: the main opaque structure handed over to user
+
+struct VP8Decoder {
+ VP8StatusCode status_;
+ int ready_; // true if ready to decode a picture with VP8Decode()
+ const char* error_msg_; // set when status_ is not OK.
+
+ // Main data source
+ VP8BitReader br_;
+
+ // headers
+ VP8FrameHeader frm_hdr_;
+ VP8PictureHeader pic_hdr_;
+ VP8FilterHeader filter_hdr_;
+ VP8SegmentHeader segment_hdr_;
+
+ // Worker
+ WebPWorker worker_;
+ int use_threads_; // use multi-thread
+ int cache_id_; // current cache row
+ int num_caches_; // number of cached rows of 16 pixels (1, 2 or 3)
+ VP8ThreadContext thread_ctx_; // Thread context
+
+ // dimension, in macroblock units.
+ int mb_w_, mb_h_;
+
+ // Macroblock to process/filter, depending on cropping and filter_type.
+ int tl_mb_x_, tl_mb_y_; // top-left MB that must be in-loop filtered
+ int br_mb_x_, br_mb_y_; // last bottom-right MB that must be decoded
+
+ // number of partitions.
+ int num_parts_;
+ // per-partition boolean decoders.
+ VP8BitReader parts_[MAX_NUM_PARTITIONS];
+
+ // buffer refresh flags
+ // bit 0: refresh Gold, bit 1: refresh Alt
+ // bit 2-3: copy to Gold, bit 4-5: copy to Alt
+ // bit 6: Gold sign bias, bit 7: Alt sign bias
+ // bit 8: refresh last frame
+ uint32_t buffer_flags_;
+
+ // dequantization (one set of DC/AC dequant factor per segment)
+ VP8QuantMatrix dqm_[NUM_MB_SEGMENTS];
+
+ // probabilities
+ VP8Proba proba_;
+ int use_skip_proba_;
+ uint8_t skip_p_;
+#ifndef ONLY_KEYFRAME_CODE
+ uint8_t intra_p_, last_p_, golden_p_;
+ VP8Proba proba_saved_;
+ int update_proba_;
+#endif
+
+ // Boundary data cache and persistent buffers.
+ uint8_t* intra_t_; // top intra modes values: 4 * mb_w_
+ uint8_t intra_l_[4]; // left intra modes values
+ uint8_t* y_t_; // top luma samples: 16 * mb_w_
+ uint8_t* u_t_, *v_t_; // top u/v samples: 8 * mb_w_ each
+
+ VP8MB* mb_info_; // contextual macroblock info (mb_w_ + 1)
+ VP8FInfo* f_info_; // filter strength info
+ uint8_t* yuv_b_; // main block for Y/U/V (size = YUV_SIZE)
+ int16_t* coeffs_; // 384 coeffs = (16+8+8) * 4*4
+
+ uint8_t* cache_y_; // macroblock row for storing unfiltered samples
+ uint8_t* cache_u_;
+ uint8_t* cache_v_;
+ int cache_y_stride_;
+ int cache_uv_stride_;
+
+ // main memory chunk for the above data. Persistent.
+ void* mem_;
+ size_t mem_size_;
+
+ // Per macroblock non-persistent infos.
+ int mb_x_, mb_y_; // current position, in macroblock units
+ uint8_t is_i4x4_; // true if intra4x4
+ uint8_t imodes_[16]; // one 16x16 mode (#0) or sixteen 4x4 modes
+ uint8_t uvmode_; // chroma prediction mode
+ uint8_t segment_; // block's segment
+
+ // bit-wise info about the content of each sub-4x4 blocks: there are 16 bits
+ // for luma (bits #0->#15), then 4 bits for chroma-u (#16->#19) and 4 bits for
+ // chroma-v (#20->#23), each corresponding to one 4x4 block in decoding order.
+ // If the bit is set, the 4x4 block contains some non-zero coefficients.
+ uint32_t non_zero_;
+ uint32_t non_zero_ac_;
+
+ // Filtering side-info
+ int filter_type_; // 0=off, 1=simple, 2=complex
+ int filter_row_; // per-row flag
+ uint8_t filter_levels_[NUM_MB_SEGMENTS]; // precalculated per-segment
+
+ // extensions
+ const uint8_t* alpha_data_; // compressed alpha data (if present)
+ size_t alpha_data_size_;
+ uint8_t* alpha_plane_; // output. Persistent, contains the whole data.
+
+ int layer_colorspace_;
+ const uint8_t* layer_data_; // compressed layer data (if present)
+ size_t layer_data_size_;
+};
+
+//------------------------------------------------------------------------------
+// internal functions. Not public.
+
+// in vp8.c
+int VP8SetError(VP8Decoder* const dec,
+ VP8StatusCode error, const char* const msg);
+
+// in tree.c
+void VP8ResetProba(VP8Proba* const proba);
+void VP8ParseProba(VP8BitReader* const br, VP8Decoder* const dec);
+void VP8ParseIntraMode(VP8BitReader* const br, VP8Decoder* const dec);
+
+// in quant.c
+void VP8ParseQuant(VP8Decoder* const dec);
+
+// in frame.c
+int VP8InitFrame(VP8Decoder* const dec, VP8Io* io);
+// Predict a block and add residual
+void VP8ReconstructBlock(VP8Decoder* const dec);
+// Call io->setup() and finish setting up scan parameters.
+// After this call returns, one must always call VP8ExitCritical() with the
+// same parameters. Both functions should be used in pair. Returns VP8_STATUS_OK
+// if ok, otherwise sets and returns the error status on *dec.
+VP8StatusCode VP8EnterCritical(VP8Decoder* const dec, VP8Io* const io);
+// Must always be called in pair with VP8EnterCritical().
+// Returns false in case of error.
+int VP8ExitCritical(VP8Decoder* const dec, VP8Io* const io);
+// Process the last decoded row (filtering + output)
+int VP8ProcessRow(VP8Decoder* const dec, VP8Io* const io);
+// Store a block, along with filtering params
+void VP8StoreBlock(VP8Decoder* const dec);
+// To be called at the start of a new scanline, to initialize predictors.
+void VP8InitScanline(VP8Decoder* const dec);
+// Decode one macroblock. Returns false if there is not enough data.
+int VP8DecodeMB(VP8Decoder* const dec, VP8BitReader* const token_br);
+
+// in alpha.c
+const uint8_t* VP8DecompressAlphaRows(VP8Decoder* const dec,
+ int row, int num_rows);
+
+// in layer.c
+int VP8DecodeLayer(VP8Decoder* const dec);
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif /* WEBP_DEC_VP8I_H_ */
diff --git a/drivers/webpold/dec/vp8l.c b/drivers/webpold/dec/vp8l.c
new file mode 100644
index 0000000000..897e4395c7
--- /dev/null
+++ b/drivers/webpold/dec/vp8l.c
@@ -0,0 +1,1200 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// main entry for the decoder
+//
+// Authors: Vikas Arora (vikaas.arora@gmail.com)
+// Jyrki Alakuijala (jyrki@google.com)
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "./vp8li.h"
+#include "../dsp/lossless.h"
+#include "../dsp/yuv.h"
+#include "../utils/huffman.h"
+#include "../utils/utils.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define NUM_ARGB_CACHE_ROWS 16
+
+static const int kCodeLengthLiterals = 16;
+static const int kCodeLengthRepeatCode = 16;
+static const int kCodeLengthExtraBits[3] = { 2, 3, 7 };
+static const int kCodeLengthRepeatOffsets[3] = { 3, 3, 11 };
+
+// -----------------------------------------------------------------------------
+// Five Huffman codes are used at each meta code:
+// 1. green + length prefix codes + color cache codes,
+// 2. alpha,
+// 3. red,
+// 4. blue, and,
+// 5. distance prefix codes.
+typedef enum {
+ GREEN = 0,
+ RED = 1,
+ BLUE = 2,
+ ALPHA = 3,
+ DIST = 4
+} HuffIndex;
+
+static const uint16_t kAlphabetSize[HUFFMAN_CODES_PER_META_CODE] = {
+ NUM_LITERAL_CODES + NUM_LENGTH_CODES,
+ NUM_LITERAL_CODES, NUM_LITERAL_CODES, NUM_LITERAL_CODES,
+ NUM_DISTANCE_CODES
+};
+
+
+#define NUM_CODE_LENGTH_CODES 19
+static const uint8_t kCodeLengthCodeOrder[NUM_CODE_LENGTH_CODES] = {
+ 17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+};
+
+#define CODE_TO_PLANE_CODES 120
+static const uint8_t code_to_plane_lut[CODE_TO_PLANE_CODES] = {
+ 0x18, 0x07, 0x17, 0x19, 0x28, 0x06, 0x27, 0x29, 0x16, 0x1a,
+ 0x26, 0x2a, 0x38, 0x05, 0x37, 0x39, 0x15, 0x1b, 0x36, 0x3a,
+ 0x25, 0x2b, 0x48, 0x04, 0x47, 0x49, 0x14, 0x1c, 0x35, 0x3b,
+ 0x46, 0x4a, 0x24, 0x2c, 0x58, 0x45, 0x4b, 0x34, 0x3c, 0x03,
+ 0x57, 0x59, 0x13, 0x1d, 0x56, 0x5a, 0x23, 0x2d, 0x44, 0x4c,
+ 0x55, 0x5b, 0x33, 0x3d, 0x68, 0x02, 0x67, 0x69, 0x12, 0x1e,
+ 0x66, 0x6a, 0x22, 0x2e, 0x54, 0x5c, 0x43, 0x4d, 0x65, 0x6b,
+ 0x32, 0x3e, 0x78, 0x01, 0x77, 0x79, 0x53, 0x5d, 0x11, 0x1f,
+ 0x64, 0x6c, 0x42, 0x4e, 0x76, 0x7a, 0x21, 0x2f, 0x75, 0x7b,
+ 0x31, 0x3f, 0x63, 0x6d, 0x52, 0x5e, 0x00, 0x74, 0x7c, 0x41,
+ 0x4f, 0x10, 0x20, 0x62, 0x6e, 0x30, 0x73, 0x7d, 0x51, 0x5f,
+ 0x40, 0x72, 0x7e, 0x61, 0x6f, 0x50, 0x71, 0x7f, 0x60, 0x70
+};
+
+static int DecodeImageStream(int xsize, int ysize,
+ int is_level0,
+ VP8LDecoder* const dec,
+ uint32_t** const decoded_data);
+
+//------------------------------------------------------------------------------
+
+int VP8LCheckSignature(const uint8_t* const data, size_t size) {
+ return (size >= 1) && (data[0] == VP8L_MAGIC_BYTE);
+}
+
+static int ReadImageInfo(VP8LBitReader* const br,
+ int* const width, int* const height,
+ int* const has_alpha) {
+ const uint8_t signature = VP8LReadBits(br, 8);
+ if (!VP8LCheckSignature(&signature, 1)) {
+ return 0;
+ }
+ *width = VP8LReadBits(br, VP8L_IMAGE_SIZE_BITS) + 1;
+ *height = VP8LReadBits(br, VP8L_IMAGE_SIZE_BITS) + 1;
+ *has_alpha = VP8LReadBits(br, 1);
+ VP8LReadBits(br, VP8L_VERSION_BITS); // Read/ignore the version number.
+ return 1;
+}
+
+int VP8LGetInfo(const uint8_t* data, size_t data_size,
+ int* const width, int* const height, int* const has_alpha) {
+ if (data == NULL || data_size < VP8L_FRAME_HEADER_SIZE) {
+ return 0; // not enough data
+ } else {
+ int w, h, a;
+ VP8LBitReader br;
+ VP8LInitBitReader(&br, data, data_size);
+ if (!ReadImageInfo(&br, &w, &h, &a)) {
+ return 0;
+ }
+ if (width != NULL) *width = w;
+ if (height != NULL) *height = h;
+ if (has_alpha != NULL) *has_alpha = a;
+ return 1;
+ }
+}
+
+//------------------------------------------------------------------------------
+
+static WEBP_INLINE int GetCopyDistance(int distance_symbol,
+ VP8LBitReader* const br) {
+ int extra_bits, offset;
+ if (distance_symbol < 4) {
+ return distance_symbol + 1;
+ }
+ extra_bits = (distance_symbol - 2) >> 1;
+ offset = (2 + (distance_symbol & 1)) << extra_bits;
+ return offset + VP8LReadBits(br, extra_bits) + 1;
+}
+
+static WEBP_INLINE int GetCopyLength(int length_symbol,
+ VP8LBitReader* const br) {
+ // Length and distance prefixes are encoded the same way.
+ return GetCopyDistance(length_symbol, br);
+}
+
+static WEBP_INLINE int PlaneCodeToDistance(int xsize, int plane_code) {
+ if (plane_code > CODE_TO_PLANE_CODES) {
+ return plane_code - CODE_TO_PLANE_CODES;
+ } else {
+ const int dist_code = code_to_plane_lut[plane_code - 1];
+ const int yoffset = dist_code >> 4;
+ const int xoffset = 8 - (dist_code & 0xf);
+ const int dist = yoffset * xsize + xoffset;
+ return (dist >= 1) ? dist : 1;
+ }
+}
+
+//------------------------------------------------------------------------------
+// Decodes the next Huffman code from bit-stream.
+// FillBitWindow(br) needs to be called at minimum every second call
+// to ReadSymbolUnsafe.
+static int ReadSymbolUnsafe(const HuffmanTree* tree, VP8LBitReader* const br) {
+ const HuffmanTreeNode* node = tree->root_;
+ assert(node != NULL);
+ while (!HuffmanTreeNodeIsLeaf(node)) {
+ node = HuffmanTreeNextNode(node, VP8LReadOneBitUnsafe(br));
+ }
+ return node->symbol_;
+}
+
+static WEBP_INLINE int ReadSymbol(const HuffmanTree* tree,
+ VP8LBitReader* const br) {
+ const int read_safe = (br->pos_ + 8 > br->len_);
+ if (!read_safe) {
+ return ReadSymbolUnsafe(tree, br);
+ } else {
+ const HuffmanTreeNode* node = tree->root_;
+ assert(node != NULL);
+ while (!HuffmanTreeNodeIsLeaf(node)) {
+ node = HuffmanTreeNextNode(node, VP8LReadOneBit(br));
+ }
+ return node->symbol_;
+ }
+}
+
+static int ReadHuffmanCodeLengths(
+ VP8LDecoder* const dec, const int* const code_length_code_lengths,
+ int num_symbols, int* const code_lengths) {
+ int ok = 0;
+ VP8LBitReader* const br = &dec->br_;
+ int symbol;
+ int max_symbol;
+ int prev_code_len = DEFAULT_CODE_LENGTH;
+ HuffmanTree tree;
+
+ if (!HuffmanTreeBuildImplicit(&tree, code_length_code_lengths,
+ NUM_CODE_LENGTH_CODES)) {
+ dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
+ return 0;
+ }
+
+ if (VP8LReadBits(br, 1)) { // use length
+ const int length_nbits = 2 + 2 * VP8LReadBits(br, 3);
+ max_symbol = 2 + VP8LReadBits(br, length_nbits);
+ if (max_symbol > num_symbols) {
+ dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
+ goto End;
+ }
+ } else {
+ max_symbol = num_symbols;
+ }
+
+ symbol = 0;
+ while (symbol < num_symbols) {
+ int code_len;
+ if (max_symbol-- == 0) break;
+ VP8LFillBitWindow(br);
+ code_len = ReadSymbol(&tree, br);
+ if (code_len < kCodeLengthLiterals) {
+ code_lengths[symbol++] = code_len;
+ if (code_len != 0) prev_code_len = code_len;
+ } else {
+ const int use_prev = (code_len == kCodeLengthRepeatCode);
+ const int slot = code_len - kCodeLengthLiterals;
+ const int extra_bits = kCodeLengthExtraBits[slot];
+ const int repeat_offset = kCodeLengthRepeatOffsets[slot];
+ int repeat = VP8LReadBits(br, extra_bits) + repeat_offset;
+ if (symbol + repeat > num_symbols) {
+ dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
+ goto End;
+ } else {
+ const int length = use_prev ? prev_code_len : 0;
+ while (repeat-- > 0) code_lengths[symbol++] = length;
+ }
+ }
+ }
+ ok = 1;
+
+ End:
+ HuffmanTreeRelease(&tree);
+ return ok;
+}
+
+static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
+ HuffmanTree* const tree) {
+ int ok = 0;
+ VP8LBitReader* const br = &dec->br_;
+ const int simple_code = VP8LReadBits(br, 1);
+
+ if (simple_code) { // Read symbols, codes & code lengths directly.
+ int symbols[2];
+ int codes[2];
+ int code_lengths[2];
+ const int num_symbols = VP8LReadBits(br, 1) + 1;
+ const int first_symbol_len_code = VP8LReadBits(br, 1);
+ // The first code is either 1 bit or 8 bit code.
+ symbols[0] = VP8LReadBits(br, (first_symbol_len_code == 0) ? 1 : 8);
+ codes[0] = 0;
+ code_lengths[0] = num_symbols - 1;
+ // The second code (if present), is always 8 bit long.
+ if (num_symbols == 2) {
+ symbols[1] = VP8LReadBits(br, 8);
+ codes[1] = 1;
+ code_lengths[1] = num_symbols - 1;
+ }
+ ok = HuffmanTreeBuildExplicit(tree, code_lengths, codes, symbols,
+ alphabet_size, num_symbols);
+ } else { // Decode Huffman-coded code lengths.
+ int* code_lengths = NULL;
+ int i;
+ int code_length_code_lengths[NUM_CODE_LENGTH_CODES] = { 0 };
+ const int num_codes = VP8LReadBits(br, 4) + 4;
+ if (num_codes > NUM_CODE_LENGTH_CODES) {
+ dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
+ return 0;
+ }
+
+ code_lengths =
+ (int*)WebPSafeCalloc((uint64_t)alphabet_size, sizeof(*code_lengths));
+ if (code_lengths == NULL) {
+ dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
+ return 0;
+ }
+
+ for (i = 0; i < num_codes; ++i) {
+ code_length_code_lengths[kCodeLengthCodeOrder[i]] = VP8LReadBits(br, 3);
+ }
+ ok = ReadHuffmanCodeLengths(dec, code_length_code_lengths, alphabet_size,
+ code_lengths);
+ if (ok) {
+ ok = HuffmanTreeBuildImplicit(tree, code_lengths, alphabet_size);
+ }
+ free(code_lengths);
+ }
+ ok = ok && !br->error_;
+ if (!ok) {
+ dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
+ return 0;
+ }
+ return 1;
+}
+
+static void DeleteHtreeGroups(HTreeGroup* htree_groups, int num_htree_groups) {
+ if (htree_groups != NULL) {
+ int i, j;
+ for (i = 0; i < num_htree_groups; ++i) {
+ HuffmanTree* const htrees = htree_groups[i].htrees_;
+ for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
+ HuffmanTreeRelease(&htrees[j]);
+ }
+ }
+ free(htree_groups);
+ }
+}
+
+static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
+ int color_cache_bits, int allow_recursion) {
+ int i, j;
+ VP8LBitReader* const br = &dec->br_;
+ VP8LMetadata* const hdr = &dec->hdr_;
+ uint32_t* huffman_image = NULL;
+ HTreeGroup* htree_groups = NULL;
+ int num_htree_groups = 1;
+
+ if (allow_recursion && VP8LReadBits(br, 1)) {
+ // use meta Huffman codes.
+ const int huffman_precision = VP8LReadBits(br, 3) + 2;
+ const int huffman_xsize = VP8LSubSampleSize(xsize, huffman_precision);
+ const int huffman_ysize = VP8LSubSampleSize(ysize, huffman_precision);
+ const int huffman_pixs = huffman_xsize * huffman_ysize;
+ if (!DecodeImageStream(huffman_xsize, huffman_ysize, 0, dec,
+ &huffman_image)) {
+ dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
+ goto Error;
+ }
+ hdr->huffman_subsample_bits_ = huffman_precision;
+ for (i = 0; i < huffman_pixs; ++i) {
+ // The huffman data is stored in red and green bytes.
+ const int index = (huffman_image[i] >> 8) & 0xffff;
+ huffman_image[i] = index;
+ if (index >= num_htree_groups) {
+ num_htree_groups = index + 1;
+ }
+ }
+ }
+
+ if (br->error_) goto Error;
+
+ assert(num_htree_groups <= 0x10000);
+ htree_groups =
+ (HTreeGroup*)WebPSafeCalloc((uint64_t)num_htree_groups,
+ sizeof(*htree_groups));
+ if (htree_groups == NULL) {
+ dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
+ goto Error;
+ }
+
+ for (i = 0; i < num_htree_groups; ++i) {
+ HuffmanTree* const htrees = htree_groups[i].htrees_;
+ for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
+ int alphabet_size = kAlphabetSize[j];
+ if (j == 0 && color_cache_bits > 0) {
+ alphabet_size += 1 << color_cache_bits;
+ }
+ if (!ReadHuffmanCode(alphabet_size, dec, htrees + j)) goto Error;
+ }
+ }
+
+ // All OK. Finalize pointers and return.
+ hdr->huffman_image_ = huffman_image;
+ hdr->num_htree_groups_ = num_htree_groups;
+ hdr->htree_groups_ = htree_groups;
+ return 1;
+
+ Error:
+ free(huffman_image);
+ DeleteHtreeGroups(htree_groups, num_htree_groups);
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+// Scaling.
+
+static int AllocateAndInitRescaler(VP8LDecoder* const dec, VP8Io* const io) {
+ const int num_channels = 4;
+ const int in_width = io->mb_w;
+ const int out_width = io->scaled_width;
+ const int in_height = io->mb_h;
+ const int out_height = io->scaled_height;
+ const uint64_t work_size = 2 * num_channels * (uint64_t)out_width;
+ int32_t* work; // Rescaler work area.
+ const uint64_t scaled_data_size = num_channels * (uint64_t)out_width;
+ uint32_t* scaled_data; // Temporary storage for scaled BGRA data.
+ const uint64_t memory_size = sizeof(*dec->rescaler) +
+ work_size * sizeof(*work) +
+ scaled_data_size * sizeof(*scaled_data);
+ uint8_t* memory = (uint8_t*)WebPSafeCalloc(memory_size, sizeof(*memory));
+ if (memory == NULL) {
+ dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
+ return 0;
+ }
+ assert(dec->rescaler_memory == NULL);
+ dec->rescaler_memory = memory;
+
+ dec->rescaler = (WebPRescaler*)memory;
+ memory += sizeof(*dec->rescaler);
+ work = (int32_t*)memory;
+ memory += work_size * sizeof(*work);
+ scaled_data = (uint32_t*)memory;
+
+ WebPRescalerInit(dec->rescaler, in_width, in_height, (uint8_t*)scaled_data,
+ out_width, out_height, 0, num_channels,
+ in_width, out_width, in_height, out_height, work);
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+// Export to ARGB
+
+// We have special "export" function since we need to convert from BGRA
+static int Export(WebPRescaler* const rescaler, WEBP_CSP_MODE colorspace,
+ int rgba_stride, uint8_t* const rgba) {
+ const uint32_t* const src = (const uint32_t*)rescaler->dst;
+ const int dst_width = rescaler->dst_width;
+ int num_lines_out = 0;
+ while (WebPRescalerHasPendingOutput(rescaler)) {
+ uint8_t* const dst = rgba + num_lines_out * rgba_stride;
+ WebPRescalerExportRow(rescaler);
+ VP8LConvertFromBGRA(src, dst_width, colorspace, dst);
+ ++num_lines_out;
+ }
+ return num_lines_out;
+}
+
+// Emit scaled rows.
+static int EmitRescaledRows(const VP8LDecoder* const dec,
+ const uint32_t* const data, int in_stride, int mb_h,
+ uint8_t* const out, int out_stride) {
+ const WEBP_CSP_MODE colorspace = dec->output_->colorspace;
+ const uint8_t* const in = (const uint8_t*)data;
+ int num_lines_in = 0;
+ int num_lines_out = 0;
+ while (num_lines_in < mb_h) {
+ const uint8_t* const row_in = in + num_lines_in * in_stride;
+ uint8_t* const row_out = out + num_lines_out * out_stride;
+ num_lines_in += WebPRescalerImport(dec->rescaler, mb_h - num_lines_in,
+ row_in, in_stride);
+ num_lines_out += Export(dec->rescaler, colorspace, out_stride, row_out);
+ }
+ return num_lines_out;
+}
+
+// Emit rows without any scaling.
+static int EmitRows(WEBP_CSP_MODE colorspace,
+ const uint32_t* const data, int in_stride,
+ int mb_w, int mb_h,
+ uint8_t* const out, int out_stride) {
+ int lines = mb_h;
+ const uint8_t* row_in = (const uint8_t*)data;
+ uint8_t* row_out = out;
+ while (lines-- > 0) {
+ VP8LConvertFromBGRA((const uint32_t*)row_in, mb_w, colorspace, row_out);
+ row_in += in_stride;
+ row_out += out_stride;
+ }
+ return mb_h; // Num rows out == num rows in.
+}
+
+//------------------------------------------------------------------------------
+// Export to YUVA
+
+static void ConvertToYUVA(const uint32_t* const src, int width, int y_pos,
+ const WebPDecBuffer* const output) {
+ const WebPYUVABuffer* const buf = &output->u.YUVA;
+ // first, the luma plane
+ {
+ int i;
+ uint8_t* const y = buf->y + y_pos * buf->y_stride;
+ for (i = 0; i < width; ++i) {
+ const uint32_t p = src[i];
+ y[i] = VP8RGBToY((p >> 16) & 0xff, (p >> 8) & 0xff, (p >> 0) & 0xff);
+ }
+ }
+
+ // then U/V planes
+ {
+ uint8_t* const u = buf->u + (y_pos >> 1) * buf->u_stride;
+ uint8_t* const v = buf->v + (y_pos >> 1) * buf->v_stride;
+ const int uv_width = width >> 1;
+ int i;
+ for (i = 0; i < uv_width; ++i) {
+ const uint32_t v0 = src[2 * i + 0];
+ const uint32_t v1 = src[2 * i + 1];
+ // VP8RGBToU/V expects four accumulated pixels. Hence we need to
+ // scale r/g/b value by a factor 2. We just shift v0/v1 one bit less.
+ const int r = ((v0 >> 15) & 0x1fe) + ((v1 >> 15) & 0x1fe);
+ const int g = ((v0 >> 7) & 0x1fe) + ((v1 >> 7) & 0x1fe);
+ const int b = ((v0 << 1) & 0x1fe) + ((v1 << 1) & 0x1fe);
+ if (!(y_pos & 1)) { // even lines: store values
+ u[i] = VP8RGBToU(r, g, b);
+ v[i] = VP8RGBToV(r, g, b);
+ } else { // odd lines: average with previous values
+ const int tmp_u = VP8RGBToU(r, g, b);
+ const int tmp_v = VP8RGBToV(r, g, b);
+ // Approximated average-of-four. But it's an acceptable diff.
+ u[i] = (u[i] + tmp_u + 1) >> 1;
+ v[i] = (v[i] + tmp_v + 1) >> 1;
+ }
+ }
+ if (width & 1) { // last pixel
+ const uint32_t v0 = src[2 * i + 0];
+ const int r = (v0 >> 14) & 0x3fc;
+ const int g = (v0 >> 6) & 0x3fc;
+ const int b = (v0 << 2) & 0x3fc;
+ if (!(y_pos & 1)) { // even lines
+ u[i] = VP8RGBToU(r, g, b);
+ v[i] = VP8RGBToV(r, g, b);
+ } else { // odd lines (note: we could just skip this)
+ const int tmp_u = VP8RGBToU(r, g, b);
+ const int tmp_v = VP8RGBToV(r, g, b);
+ u[i] = (u[i] + tmp_u + 1) >> 1;
+ v[i] = (v[i] + tmp_v + 1) >> 1;
+ }
+ }
+ }
+ // Lastly, store alpha if needed.
+ if (buf->a != NULL) {
+ int i;
+ uint8_t* const a = buf->a + y_pos * buf->a_stride;
+ for (i = 0; i < width; ++i) a[i] = (src[i] >> 24);
+ }
+}
+
+static int ExportYUVA(const VP8LDecoder* const dec, int y_pos) {
+ WebPRescaler* const rescaler = dec->rescaler;
+ const uint32_t* const src = (const uint32_t*)rescaler->dst;
+ const int dst_width = rescaler->dst_width;
+ int num_lines_out = 0;
+ while (WebPRescalerHasPendingOutput(rescaler)) {
+ WebPRescalerExportRow(rescaler);
+ ConvertToYUVA(src, dst_width, y_pos, dec->output_);
+ ++y_pos;
+ ++num_lines_out;
+ }
+ return num_lines_out;
+}
+
+static int EmitRescaledRowsYUVA(const VP8LDecoder* const dec,
+ const uint32_t* const data,
+ int in_stride, int mb_h) {
+ const uint8_t* const in = (const uint8_t*)data;
+ int num_lines_in = 0;
+ int y_pos = dec->last_out_row_;
+ while (num_lines_in < mb_h) {
+ const uint8_t* const row_in = in + num_lines_in * in_stride;
+ num_lines_in += WebPRescalerImport(dec->rescaler, mb_h - num_lines_in,
+ row_in, in_stride);
+ y_pos += ExportYUVA(dec, y_pos);
+ }
+ return y_pos;
+}
+
+static int EmitRowsYUVA(const VP8LDecoder* const dec,
+ const uint32_t* const data, int in_stride,
+ int mb_w, int num_rows) {
+ int y_pos = dec->last_out_row_;
+ const uint8_t* row_in = (const uint8_t*)data;
+ while (num_rows-- > 0) {
+ ConvertToYUVA((const uint32_t*)row_in, mb_w, y_pos, dec->output_);
+ row_in += in_stride;
+ ++y_pos;
+ }
+ return y_pos;
+}
+
+//------------------------------------------------------------------------------
+// Cropping.
+
+// Sets io->mb_y, io->mb_h & io->mb_w according to start row, end row and
+// crop options. Also updates the input data pointer, so that it points to the
+// start of the cropped window.
+// Note that 'pixel_stride' is in units of 'uint32_t' (and not 'bytes).
+// Returns true if the crop window is not empty.
+static int SetCropWindow(VP8Io* const io, int y_start, int y_end,
+ const uint32_t** const in_data, int pixel_stride) {
+ assert(y_start < y_end);
+ assert(io->crop_left < io->crop_right);
+ if (y_end > io->crop_bottom) {
+ y_end = io->crop_bottom; // make sure we don't overflow on last row.
+ }
+ if (y_start < io->crop_top) {
+ const int delta = io->crop_top - y_start;
+ y_start = io->crop_top;
+ *in_data += pixel_stride * delta;
+ }
+ if (y_start >= y_end) return 0; // Crop window is empty.
+
+ *in_data += io->crop_left;
+
+ io->mb_y = y_start - io->crop_top;
+ io->mb_w = io->crop_right - io->crop_left;
+ io->mb_h = y_end - y_start;
+ return 1; // Non-empty crop window.
+}
+
+//------------------------------------------------------------------------------
+
+static WEBP_INLINE int GetMetaIndex(
+ const uint32_t* const image, int xsize, int bits, int x, int y) {
+ if (bits == 0) return 0;
+ return image[xsize * (y >> bits) + (x >> bits)];
+}
+
+static WEBP_INLINE HTreeGroup* GetHtreeGroupForPos(VP8LMetadata* const hdr,
+ int x, int y) {
+ const int meta_index = GetMetaIndex(hdr->huffman_image_, hdr->huffman_xsize_,
+ hdr->huffman_subsample_bits_, x, y);
+ assert(meta_index < hdr->num_htree_groups_);
+ return hdr->htree_groups_ + meta_index;
+}
+
+//------------------------------------------------------------------------------
+// Main loop, with custom row-processing function
+
+typedef void (*ProcessRowsFunc)(VP8LDecoder* const dec, int row);
+
+static void ApplyInverseTransforms(VP8LDecoder* const dec, int num_rows,
+ const uint32_t* const rows) {
+ int n = dec->next_transform_;
+ const int cache_pixs = dec->width_ * num_rows;
+ const int start_row = dec->last_row_;
+ const int end_row = start_row + num_rows;
+ const uint32_t* rows_in = rows;
+ uint32_t* const rows_out = dec->argb_cache_;
+
+ // Inverse transforms.
+ // TODO: most transforms only need to operate on the cropped region only.
+ memcpy(rows_out, rows_in, cache_pixs * sizeof(*rows_out));
+ while (n-- > 0) {
+ VP8LTransform* const transform = &dec->transforms_[n];
+ VP8LInverseTransform(transform, start_row, end_row, rows_in, rows_out);
+ rows_in = rows_out;
+ }
+}
+
+// Processes (transforms, scales & color-converts) the rows decoded after the
+// last call.
+static void ProcessRows(VP8LDecoder* const dec, int row) {
+ const uint32_t* const rows = dec->argb_ + dec->width_ * dec->last_row_;
+ const int num_rows = row - dec->last_row_;
+
+ if (num_rows <= 0) return; // Nothing to be done.
+ ApplyInverseTransforms(dec, num_rows, rows);
+
+ // Emit output.
+ {
+ VP8Io* const io = dec->io_;
+ const uint32_t* rows_data = dec->argb_cache_;
+ if (!SetCropWindow(io, dec->last_row_, row, &rows_data, io->width)) {
+ // Nothing to output (this time).
+ } else {
+ const WebPDecBuffer* const output = dec->output_;
+ const int in_stride = io->width * sizeof(*rows_data);
+ if (output->colorspace < MODE_YUV) { // convert to RGBA
+ const WebPRGBABuffer* const buf = &output->u.RGBA;
+ uint8_t* const rgba = buf->rgba + dec->last_out_row_ * buf->stride;
+ const int num_rows_out = io->use_scaling ?
+ EmitRescaledRows(dec, rows_data, in_stride, io->mb_h,
+ rgba, buf->stride) :
+ EmitRows(output->colorspace, rows_data, in_stride,
+ io->mb_w, io->mb_h, rgba, buf->stride);
+ // Update 'last_out_row_'.
+ dec->last_out_row_ += num_rows_out;
+ } else { // convert to YUVA
+ dec->last_out_row_ = io->use_scaling ?
+ EmitRescaledRowsYUVA(dec, rows_data, in_stride, io->mb_h) :
+ EmitRowsYUVA(dec, rows_data, in_stride, io->mb_w, io->mb_h);
+ }
+ assert(dec->last_out_row_ <= output->height);
+ }
+ }
+
+ // Update 'last_row_'.
+ dec->last_row_ = row;
+ assert(dec->last_row_ <= dec->height_);
+}
+
+static int DecodeImageData(VP8LDecoder* const dec,
+ uint32_t* const data, int width, int height,
+ ProcessRowsFunc process_func) {
+ int ok = 1;
+ int col = 0, row = 0;
+ VP8LBitReader* const br = &dec->br_;
+ VP8LMetadata* const hdr = &dec->hdr_;
+ HTreeGroup* htree_group = hdr->htree_groups_;
+ uint32_t* src = data;
+ uint32_t* last_cached = data;
+ uint32_t* const src_end = data + width * height;
+ const int len_code_limit = NUM_LITERAL_CODES + NUM_LENGTH_CODES;
+ const int color_cache_limit = len_code_limit + hdr->color_cache_size_;
+ VP8LColorCache* const color_cache =
+ (hdr->color_cache_size_ > 0) ? &hdr->color_cache_ : NULL;
+ const int mask = hdr->huffman_mask_;
+
+ assert(htree_group != NULL);
+
+ while (!br->eos_ && src < src_end) {
+ int code;
+ // Only update when changing tile. Note we could use the following test:
+ // if "((((prev_col ^ col) | prev_row ^ row)) > mask)" -> tile changed
+ // but that's actually slower and requires storing the previous col/row
+ if ((col & mask) == 0) {
+ htree_group = GetHtreeGroupForPos(hdr, col, row);
+ }
+ VP8LFillBitWindow(br);
+ code = ReadSymbol(&htree_group->htrees_[GREEN], br);
+ if (code < NUM_LITERAL_CODES) { // Literal.
+ int red, green, blue, alpha;
+ red = ReadSymbol(&htree_group->htrees_[RED], br);
+ green = code;
+ VP8LFillBitWindow(br);
+ blue = ReadSymbol(&htree_group->htrees_[BLUE], br);
+ alpha = ReadSymbol(&htree_group->htrees_[ALPHA], br);
+ *src = (alpha << 24) + (red << 16) + (green << 8) + blue;
+ AdvanceByOne:
+ ++src;
+ ++col;
+ if (col >= width) {
+ col = 0;
+ ++row;
+ if ((process_func != NULL) && (row % NUM_ARGB_CACHE_ROWS == 0)) {
+ process_func(dec, row);
+ }
+ if (color_cache != NULL) {
+ while (last_cached < src) {
+ VP8LColorCacheInsert(color_cache, *last_cached++);
+ }
+ }
+ }
+ } else if (code < len_code_limit) { // Backward reference
+ int dist_code, dist;
+ const int length_sym = code - NUM_LITERAL_CODES;
+ const int length = GetCopyLength(length_sym, br);
+ const int dist_symbol = ReadSymbol(&htree_group->htrees_[DIST], br);
+ VP8LFillBitWindow(br);
+ dist_code = GetCopyDistance(dist_symbol, br);
+ dist = PlaneCodeToDistance(width, dist_code);
+ if (src - data < dist || src_end - src < length) {
+ ok = 0;
+ goto End;
+ }
+ {
+ int i;
+ for (i = 0; i < length; ++i) src[i] = src[i - dist];
+ src += length;
+ }
+ col += length;
+ while (col >= width) {
+ col -= width;
+ ++row;
+ if ((process_func != NULL) && (row % NUM_ARGB_CACHE_ROWS == 0)) {
+ process_func(dec, row);
+ }
+ }
+ if (src < src_end) {
+ htree_group = GetHtreeGroupForPos(hdr, col, row);
+ if (color_cache != NULL) {
+ while (last_cached < src) {
+ VP8LColorCacheInsert(color_cache, *last_cached++);
+ }
+ }
+ }
+ } else if (code < color_cache_limit) { // Color cache.
+ const int key = code - len_code_limit;
+ assert(color_cache != NULL);
+ while (last_cached < src) {
+ VP8LColorCacheInsert(color_cache, *last_cached++);
+ }
+ *src = VP8LColorCacheLookup(color_cache, key);
+ goto AdvanceByOne;
+ } else { // Not reached.
+ ok = 0;
+ goto End;
+ }
+ ok = !br->error_;
+ if (!ok) goto End;
+ }
+ // Process the remaining rows corresponding to last row-block.
+ if (process_func != NULL) process_func(dec, row);
+
+ End:
+ if (br->error_ || !ok || (br->eos_ && src < src_end)) {
+ ok = 0;
+ dec->status_ = (!br->eos_) ?
+ VP8_STATUS_BITSTREAM_ERROR : VP8_STATUS_SUSPENDED;
+ } else if (src == src_end) {
+ dec->state_ = READ_DATA;
+ }
+
+ return ok;
+}
+
+// -----------------------------------------------------------------------------
+// VP8LTransform
+
+static void ClearTransform(VP8LTransform* const transform) {
+ free(transform->data_);
+ transform->data_ = NULL;
+}
+
+// For security reason, we need to remap the color map to span
+// the total possible bundled values, and not just the num_colors.
+static int ExpandColorMap(int num_colors, VP8LTransform* const transform) {
+ int i;
+ const int final_num_colors = 1 << (8 >> transform->bits_);
+ uint32_t* const new_color_map =
+ (uint32_t*)WebPSafeMalloc((uint64_t)final_num_colors,
+ sizeof(*new_color_map));
+ if (new_color_map == NULL) {
+ return 0;
+ } else {
+ uint8_t* const data = (uint8_t*)transform->data_;
+ uint8_t* const new_data = (uint8_t*)new_color_map;
+ new_color_map[0] = transform->data_[0];
+ for (i = 4; i < 4 * num_colors; ++i) {
+ // Equivalent to AddPixelEq(), on a byte-basis.
+ new_data[i] = (data[i] + new_data[i - 4]) & 0xff;
+ }
+ for (; i < 4 * final_num_colors; ++i)
+ new_data[i] = 0; // black tail.
+ free(transform->data_);
+ transform->data_ = new_color_map;
+ }
+ return 1;
+}
+
+static int ReadTransform(int* const xsize, int const* ysize,
+ VP8LDecoder* const dec) {
+ int ok = 1;
+ VP8LBitReader* const br = &dec->br_;
+ VP8LTransform* transform = &dec->transforms_[dec->next_transform_];
+ const VP8LImageTransformType type =
+ (VP8LImageTransformType)VP8LReadBits(br, 2);
+
+ // Each transform type can only be present once in the stream.
+ if (dec->transforms_seen_ & (1U << type)) {
+ return 0; // Already there, let's not accept the second same transform.
+ }
+ dec->transforms_seen_ |= (1U << type);
+
+ transform->type_ = type;
+ transform->xsize_ = *xsize;
+ transform->ysize_ = *ysize;
+ transform->data_ = NULL;
+ ++dec->next_transform_;
+ assert(dec->next_transform_ <= NUM_TRANSFORMS);
+
+ switch (type) {
+ case PREDICTOR_TRANSFORM:
+ case CROSS_COLOR_TRANSFORM:
+ transform->bits_ = VP8LReadBits(br, 3) + 2;
+ ok = DecodeImageStream(VP8LSubSampleSize(transform->xsize_,
+ transform->bits_),
+ VP8LSubSampleSize(transform->ysize_,
+ transform->bits_),
+ 0, dec, &transform->data_);
+ break;
+ case COLOR_INDEXING_TRANSFORM: {
+ const int num_colors = VP8LReadBits(br, 8) + 1;
+ const int bits = (num_colors > 16) ? 0
+ : (num_colors > 4) ? 1
+ : (num_colors > 2) ? 2
+ : 3;
+ *xsize = VP8LSubSampleSize(transform->xsize_, bits);
+ transform->bits_ = bits;
+ ok = DecodeImageStream(num_colors, 1, 0, dec, &transform->data_);
+ ok = ok && ExpandColorMap(num_colors, transform);
+ break;
+ }
+ case SUBTRACT_GREEN:
+ break;
+ default:
+ assert(0); // can't happen
+ break;
+ }
+
+ return ok;
+}
+
+// -----------------------------------------------------------------------------
+// VP8LMetadata
+
+static void InitMetadata(VP8LMetadata* const hdr) {
+ assert(hdr);
+ memset(hdr, 0, sizeof(*hdr));
+}
+
+static void ClearMetadata(VP8LMetadata* const hdr) {
+ assert(hdr);
+
+ free(hdr->huffman_image_);
+ DeleteHtreeGroups(hdr->htree_groups_, hdr->num_htree_groups_);
+ VP8LColorCacheClear(&hdr->color_cache_);
+ InitMetadata(hdr);
+}
+
+// -----------------------------------------------------------------------------
+// VP8LDecoder
+
+VP8LDecoder* VP8LNew(void) {
+ VP8LDecoder* const dec = (VP8LDecoder*)calloc(1, sizeof(*dec));
+ if (dec == NULL) return NULL;
+ dec->status_ = VP8_STATUS_OK;
+ dec->action_ = READ_DIM;
+ dec->state_ = READ_DIM;
+ return dec;
+}
+
+void VP8LClear(VP8LDecoder* const dec) {
+ int i;
+ if (dec == NULL) return;
+ ClearMetadata(&dec->hdr_);
+
+ free(dec->argb_);
+ dec->argb_ = NULL;
+ for (i = 0; i < dec->next_transform_; ++i) {
+ ClearTransform(&dec->transforms_[i]);
+ }
+ dec->next_transform_ = 0;
+ dec->transforms_seen_ = 0;
+
+ free(dec->rescaler_memory);
+ dec->rescaler_memory = NULL;
+
+ dec->output_ = NULL; // leave no trace behind
+}
+
+void VP8LDelete(VP8LDecoder* const dec) {
+ if (dec != NULL) {
+ VP8LClear(dec);
+ free(dec);
+ }
+}
+
+static void UpdateDecoder(VP8LDecoder* const dec, int width, int height) {
+ VP8LMetadata* const hdr = &dec->hdr_;
+ const int num_bits = hdr->huffman_subsample_bits_;
+ dec->width_ = width;
+ dec->height_ = height;
+
+ hdr->huffman_xsize_ = VP8LSubSampleSize(width, num_bits);
+ hdr->huffman_mask_ = (num_bits == 0) ? ~0 : (1 << num_bits) - 1;
+}
+
+static int DecodeImageStream(int xsize, int ysize,
+ int is_level0,
+ VP8LDecoder* const dec,
+ uint32_t** const decoded_data) {
+ int ok = 1;
+ int transform_xsize = xsize;
+ int transform_ysize = ysize;
+ VP8LBitReader* const br = &dec->br_;
+ VP8LMetadata* const hdr = &dec->hdr_;
+ uint32_t* data = NULL;
+ int color_cache_bits = 0;
+
+ // Read the transforms (may recurse).
+ if (is_level0) {
+ while (ok && VP8LReadBits(br, 1)) {
+ ok = ReadTransform(&transform_xsize, &transform_ysize, dec);
+ }
+ }
+
+ // Color cache
+ if (ok && VP8LReadBits(br, 1)) {
+ color_cache_bits = VP8LReadBits(br, 4);
+ ok = (color_cache_bits >= 1 && color_cache_bits <= MAX_CACHE_BITS);
+ if (!ok) {
+ dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
+ goto End;
+ }
+ }
+
+ // Read the Huffman codes (may recurse).
+ ok = ok && ReadHuffmanCodes(dec, transform_xsize, transform_ysize,
+ color_cache_bits, is_level0);
+ if (!ok) {
+ dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
+ goto End;
+ }
+
+ // Finish setting up the color-cache
+ if (color_cache_bits > 0) {
+ hdr->color_cache_size_ = 1 << color_cache_bits;
+ if (!VP8LColorCacheInit(&hdr->color_cache_, color_cache_bits)) {
+ dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
+ ok = 0;
+ goto End;
+ }
+ } else {
+ hdr->color_cache_size_ = 0;
+ }
+ UpdateDecoder(dec, transform_xsize, transform_ysize);
+
+ if (is_level0) { // level 0 complete
+ dec->state_ = READ_HDR;
+ goto End;
+ }
+
+ {
+ const uint64_t total_size = (uint64_t)transform_xsize * transform_ysize;
+ data = (uint32_t*)WebPSafeMalloc(total_size, sizeof(*data));
+ if (data == NULL) {
+ dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
+ ok = 0;
+ goto End;
+ }
+ }
+
+ // Use the Huffman trees to decode the LZ77 encoded data.
+ ok = DecodeImageData(dec, data, transform_xsize, transform_ysize, NULL);
+ ok = ok && !br->error_;
+
+ End:
+
+ if (!ok) {
+ free(data);
+ ClearMetadata(hdr);
+ // If not enough data (br.eos_) resulted in BIT_STREAM_ERROR, update the
+ // status appropriately.
+ if (dec->status_ == VP8_STATUS_BITSTREAM_ERROR && dec->br_.eos_) {
+ dec->status_ = VP8_STATUS_SUSPENDED;
+ }
+ } else {
+ if (decoded_data != NULL) {
+ *decoded_data = data;
+ } else {
+ // We allocate image data in this function only for transforms. At level 0
+ // (that is: not the transforms), we shouldn't have allocated anything.
+ assert(data == NULL);
+ assert(is_level0);
+ }
+ if (!is_level0) ClearMetadata(hdr); // Clean up temporary data behind.
+ }
+ return ok;
+}
+
+//------------------------------------------------------------------------------
+// Allocate dec->argb_ and dec->argb_cache_ using dec->width_ and dec->height_
+
+static int AllocateARGBBuffers(VP8LDecoder* const dec, int final_width) {
+ const uint64_t num_pixels = (uint64_t)dec->width_ * dec->height_;
+ // Scratch buffer corresponding to top-prediction row for transforming the
+ // first row in the row-blocks.
+ const uint64_t cache_top_pixels = final_width;
+ // Scratch buffer for temporary BGRA storage.
+ const uint64_t cache_pixels = (uint64_t)final_width * NUM_ARGB_CACHE_ROWS;
+ const uint64_t total_num_pixels =
+ num_pixels + cache_top_pixels + cache_pixels;
+
+ assert(dec->width_ <= final_width);
+ dec->argb_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, sizeof(*dec->argb_));
+ if (dec->argb_ == NULL) {
+ dec->argb_cache_ = NULL; // for sanity check
+ dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
+ return 0;
+ }
+ dec->argb_cache_ = dec->argb_ + num_pixels + cache_top_pixels;
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+// Special row-processing that only stores the alpha data.
+
+static void ExtractAlphaRows(VP8LDecoder* const dec, int row) {
+ const int num_rows = row - dec->last_row_;
+ const uint32_t* const in = dec->argb_ + dec->width_ * dec->last_row_;
+
+ if (num_rows <= 0) return; // Nothing to be done.
+ ApplyInverseTransforms(dec, num_rows, in);
+
+ // Extract alpha (which is stored in the green plane).
+ {
+ const int width = dec->io_->width; // the final width (!= dec->width_)
+ const int cache_pixs = width * num_rows;
+ uint8_t* const dst = (uint8_t*)dec->io_->opaque + width * dec->last_row_;
+ const uint32_t* const src = dec->argb_cache_;
+ int i;
+ for (i = 0; i < cache_pixs; ++i) dst[i] = (src[i] >> 8) & 0xff;
+ }
+
+ dec->last_row_ = dec->last_out_row_ = row;
+}
+
+int VP8LDecodeAlphaImageStream(int width, int height, const uint8_t* const data,
+ size_t data_size, uint8_t* const output) {
+ VP8Io io;
+ int ok = 0;
+ VP8LDecoder* const dec = VP8LNew();
+ if (dec == NULL) return 0;
+
+ dec->width_ = width;
+ dec->height_ = height;
+ dec->io_ = &io;
+
+ VP8InitIo(&io);
+ WebPInitCustomIo(NULL, &io); // Just a sanity Init. io won't be used.
+ io.opaque = output;
+ io.width = width;
+ io.height = height;
+
+ dec->status_ = VP8_STATUS_OK;
+ VP8LInitBitReader(&dec->br_, data, data_size);
+
+ dec->action_ = READ_HDR;
+ if (!DecodeImageStream(width, height, 1, dec, NULL)) goto Err;
+
+ // Allocate output (note that dec->width_ may have changed here).
+ if (!AllocateARGBBuffers(dec, width)) goto Err;
+
+ // Decode (with special row processing).
+ dec->action_ = READ_DATA;
+ ok = DecodeImageData(dec, dec->argb_, dec->width_, dec->height_,
+ ExtractAlphaRows);
+
+ Err:
+ VP8LDelete(dec);
+ return ok;
+}
+
+//------------------------------------------------------------------------------
+
+int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io) {
+ int width, height, has_alpha;
+
+ if (dec == NULL) return 0;
+ if (io == NULL) {
+ dec->status_ = VP8_STATUS_INVALID_PARAM;
+ return 0;
+ }
+
+ dec->io_ = io;
+ dec->status_ = VP8_STATUS_OK;
+ VP8LInitBitReader(&dec->br_, io->data, io->data_size);
+ if (!ReadImageInfo(&dec->br_, &width, &height, &has_alpha)) {
+ dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
+ goto Error;
+ }
+ dec->state_ = READ_DIM;
+ io->width = width;
+ io->height = height;
+
+ dec->action_ = READ_HDR;
+ if (!DecodeImageStream(width, height, 1, dec, NULL)) goto Error;
+ return 1;
+
+ Error:
+ VP8LClear(dec);
+ assert(dec->status_ != VP8_STATUS_OK);
+ return 0;
+}
+
+int VP8LDecodeImage(VP8LDecoder* const dec) {
+ VP8Io* io = NULL;
+ WebPDecParams* params = NULL;
+
+ // Sanity checks.
+ if (dec == NULL) return 0;
+
+ io = dec->io_;
+ assert(io != NULL);
+ params = (WebPDecParams*)io->opaque;
+ assert(params != NULL);
+ dec->output_ = params->output;
+ assert(dec->output_ != NULL);
+
+ // Initialization.
+ if (!WebPIoInitFromOptions(params->options, io, MODE_BGRA)) {
+ dec->status_ = VP8_STATUS_INVALID_PARAM;
+ goto Err;
+ }
+
+ if (!AllocateARGBBuffers(dec, io->width)) goto Err;
+
+ if (io->use_scaling && !AllocateAndInitRescaler(dec, io)) goto Err;
+
+ // Decode.
+ dec->action_ = READ_DATA;
+ if (!DecodeImageData(dec, dec->argb_, dec->width_, dec->height_,
+ ProcessRows)) {
+ goto Err;
+ }
+
+ // Cleanup.
+ params->last_y = dec->last_out_row_;
+ VP8LClear(dec);
+ return 1;
+
+ Err:
+ VP8LClear(dec);
+ assert(dec->status_ != VP8_STATUS_OK);
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/dec/vp8li.h b/drivers/webpold/dec/vp8li.h
new file mode 100644
index 0000000000..5f6cd6a01c
--- /dev/null
+++ b/drivers/webpold/dec/vp8li.h
@@ -0,0 +1,121 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Lossless decoder: internal header.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+// Vikas Arora(vikaas.arora@gmail.com)
+
+#ifndef WEBP_DEC_VP8LI_H_
+#define WEBP_DEC_VP8LI_H_
+
+#include <string.h> // for memcpy()
+#include "./webpi.h"
+#include "../utils/bit_reader.h"
+#include "../utils/color_cache.h"
+#include "../utils/huffman.h"
+#include "../format_constants.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef enum {
+ READ_DATA = 0,
+ READ_HDR = 1,
+ READ_DIM = 2
+} VP8LDecodeState;
+
+typedef struct VP8LTransform VP8LTransform;
+struct VP8LTransform {
+ VP8LImageTransformType type_; // transform type.
+ int bits_; // subsampling bits defining transform window.
+ int xsize_; // transform window X index.
+ int ysize_; // transform window Y index.
+ uint32_t *data_; // transform data.
+};
+
+typedef struct {
+ HuffmanTree htrees_[HUFFMAN_CODES_PER_META_CODE];
+} HTreeGroup;
+
+typedef struct {
+ int color_cache_size_;
+ VP8LColorCache color_cache_;
+
+ int huffman_mask_;
+ int huffman_subsample_bits_;
+ int huffman_xsize_;
+ uint32_t *huffman_image_;
+ int num_htree_groups_;
+ HTreeGroup *htree_groups_;
+} VP8LMetadata;
+
+typedef struct {
+ VP8StatusCode status_;
+ VP8LDecodeState action_;
+ VP8LDecodeState state_;
+ VP8Io *io_;
+
+ const WebPDecBuffer *output_; // shortcut to io->opaque->output
+
+ uint32_t *argb_; // Internal data: always in BGRA color mode.
+ uint32_t *argb_cache_; // Scratch buffer for temporary BGRA storage.
+
+ VP8LBitReader br_;
+
+ int width_;
+ int height_;
+ int last_row_; // last input row decoded so far.
+ int last_out_row_; // last row output so far.
+
+ VP8LMetadata hdr_;
+
+ int next_transform_;
+ VP8LTransform transforms_[NUM_TRANSFORMS];
+ // or'd bitset storing the transforms types.
+ uint32_t transforms_seen_;
+
+ uint8_t *rescaler_memory; // Working memory for rescaling work.
+ WebPRescaler *rescaler; // Common rescaler for all channels.
+} VP8LDecoder;
+
+//------------------------------------------------------------------------------
+// internal functions. Not public.
+
+// in vp8l.c
+
+// Decodes a raw image stream (without header) and store the alpha data
+// into *output, which must be of size width x height. Returns false in case
+// of error.
+int VP8LDecodeAlphaImageStream(int width, int height, const uint8_t* const data,
+ size_t data_size, uint8_t* const output);
+
+// Allocates and initialize a new lossless decoder instance.
+VP8LDecoder* VP8LNew(void);
+
+// Decodes the image header. Returns false in case of error.
+int VP8LDecodeHeader(VP8LDecoder* const dec, VP8Io* const io);
+
+// Decodes an image. It's required to decode the lossless header before calling
+// this function. Returns false in case of error, with updated dec->status_.
+int VP8LDecodeImage(VP8LDecoder* const dec);
+
+// Resets the decoder in its initial state, reclaiming memory.
+// Preserves the dec->status_ value.
+void VP8LClear(VP8LDecoder* const dec);
+
+// Clears and deallocate a lossless decoder instance.
+void VP8LDelete(VP8LDecoder* const dec);
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif /* WEBP_DEC_VP8LI_H_ */
diff --git a/drivers/webpold/dec/webp.c b/drivers/webpold/dec/webp.c
new file mode 100644
index 0000000000..f44bc2b8ae
--- /dev/null
+++ b/drivers/webpold/dec/webp.c
@@ -0,0 +1,771 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Main decoding functions for WEBP images.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <stdlib.h>
+
+#include "./vp8i.h"
+#include "./vp8li.h"
+#include "./webpi.h"
+#include "../format_constants.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// RIFF layout is:
+// Offset tag
+// 0...3 "RIFF" 4-byte tag
+// 4...7 size of image data (including metadata) starting at offset 8
+// 8...11 "WEBP" our form-type signature
+// The RIFF container (12 bytes) is followed by appropriate chunks:
+// 12..15 "VP8 ": 4-bytes tags, signaling the use of VP8 video format
+// 16..19 size of the raw VP8 image data, starting at offset 20
+// 20.... the VP8 bytes
+// Or,
+// 12..15 "VP8L": 4-bytes tags, signaling the use of VP8L lossless format
+// 16..19 size of the raw VP8L image data, starting at offset 20
+// 20.... the VP8L bytes
+// Or,
+// 12..15 "VP8X": 4-bytes tags, describing the extended-VP8 chunk.
+// 16..19 size of the VP8X chunk starting at offset 20.
+// 20..23 VP8X flags bit-map corresponding to the chunk-types present.
+// 24..26 Width of the Canvas Image.
+// 27..29 Height of the Canvas Image.
+// There can be extra chunks after the "VP8X" chunk (ICCP, TILE, FRM, VP8,
+// META ...)
+// All sizes are in little-endian order.
+// Note: chunk data size must be padded to multiple of 2 when written.
+
+static WEBP_INLINE uint32_t get_le24(const uint8_t* const data) {
+ return data[0] | (data[1] << 8) | (data[2] << 16);
+}
+
+static WEBP_INLINE uint32_t get_le32(const uint8_t* const data) {
+ return (uint32_t)get_le24(data) | (data[3] << 24);
+}
+
+// Validates the RIFF container (if detected) and skips over it.
+// If a RIFF container is detected,
+// Returns VP8_STATUS_BITSTREAM_ERROR for invalid header, and
+// VP8_STATUS_OK otherwise.
+// In case there are not enough bytes (partial RIFF container), return 0 for
+// *riff_size. Else return the RIFF size extracted from the header.
+static VP8StatusCode ParseRIFF(const uint8_t** const data,
+ size_t* const data_size,
+ size_t* const riff_size) {
+ assert(data != NULL);
+ assert(data_size != NULL);
+ assert(riff_size != NULL);
+
+ *riff_size = 0; // Default: no RIFF present.
+ if (*data_size >= RIFF_HEADER_SIZE && !memcmp(*data, "RIFF", TAG_SIZE)) {
+ if (memcmp(*data + 8, "WEBP", TAG_SIZE)) {
+ return VP8_STATUS_BITSTREAM_ERROR; // Wrong image file signature.
+ } else {
+ const uint32_t size = get_le32(*data + TAG_SIZE);
+ // Check that we have at least one chunk (i.e "WEBP" + "VP8?nnnn").
+ if (size < TAG_SIZE + CHUNK_HEADER_SIZE) {
+ return VP8_STATUS_BITSTREAM_ERROR;
+ }
+ // We have a RIFF container. Skip it.
+ *riff_size = size;
+ *data += RIFF_HEADER_SIZE;
+ *data_size -= RIFF_HEADER_SIZE;
+ }
+ }
+ return VP8_STATUS_OK;
+}
+
+// Validates the VP8X header and skips over it.
+// Returns VP8_STATUS_BITSTREAM_ERROR for invalid VP8X header,
+// VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and
+// VP8_STATUS_OK otherwise.
+// If a VP8X chunk is found, found_vp8x is set to true and *width_ptr,
+// *height_ptr and *flags_ptr are set to the corresponding values extracted
+// from the VP8X chunk.
+static VP8StatusCode ParseVP8X(const uint8_t** const data,
+ size_t* const data_size,
+ int* const found_vp8x,
+ int* const width_ptr, int* const height_ptr,
+ uint32_t* const flags_ptr) {
+ const uint32_t vp8x_size = CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE;
+ assert(data != NULL);
+ assert(data_size != NULL);
+ assert(found_vp8x != NULL);
+
+ *found_vp8x = 0;
+
+ if (*data_size < CHUNK_HEADER_SIZE) {
+ return VP8_STATUS_NOT_ENOUGH_DATA; // Insufficient data.
+ }
+
+ if (!memcmp(*data, "VP8X", TAG_SIZE)) {
+ int width, height;
+ uint32_t flags;
+ const uint32_t chunk_size = get_le32(*data + TAG_SIZE);
+ if (chunk_size != VP8X_CHUNK_SIZE) {
+ return VP8_STATUS_BITSTREAM_ERROR; // Wrong chunk size.
+ }
+
+ // Verify if enough data is available to validate the VP8X chunk.
+ if (*data_size < vp8x_size) {
+ return VP8_STATUS_NOT_ENOUGH_DATA; // Insufficient data.
+ }
+ flags = get_le32(*data + 8);
+ width = 1 + get_le24(*data + 12);
+ height = 1 + get_le24(*data + 15);
+ if (width * (uint64_t)height >= MAX_IMAGE_AREA) {
+ return VP8_STATUS_BITSTREAM_ERROR; // image is too large
+ }
+
+ if (flags_ptr != NULL) *flags_ptr = flags;
+ if (width_ptr != NULL) *width_ptr = width;
+ if (height_ptr != NULL) *height_ptr = height;
+ // Skip over VP8X header bytes.
+ *data += vp8x_size;
+ *data_size -= vp8x_size;
+ *found_vp8x = 1;
+ }
+ return VP8_STATUS_OK;
+}
+
+// Skips to the next VP8/VP8L chunk header in the data given the size of the
+// RIFF chunk 'riff_size'.
+// Returns VP8_STATUS_BITSTREAM_ERROR if any invalid chunk size is encountered,
+// VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and
+// VP8_STATUS_OK otherwise.
+// If an alpha chunk is found, *alpha_data and *alpha_size are set
+// appropriately.
+static VP8StatusCode ParseOptionalChunks(const uint8_t** const data,
+ size_t* const data_size,
+ size_t const riff_size,
+ const uint8_t** const alpha_data,
+ size_t* const alpha_size) {
+ const uint8_t* buf;
+ size_t buf_size;
+ uint32_t total_size = TAG_SIZE + // "WEBP".
+ CHUNK_HEADER_SIZE + // "VP8Xnnnn".
+ VP8X_CHUNK_SIZE; // data.
+ assert(data != NULL);
+ assert(data_size != NULL);
+ buf = *data;
+ buf_size = *data_size;
+
+ assert(alpha_data != NULL);
+ assert(alpha_size != NULL);
+ *alpha_data = NULL;
+ *alpha_size = 0;
+
+ while (1) {
+ uint32_t chunk_size;
+ uint32_t disk_chunk_size; // chunk_size with padding
+
+ *data = buf;
+ *data_size = buf_size;
+
+ if (buf_size < CHUNK_HEADER_SIZE) { // Insufficient data.
+ return VP8_STATUS_NOT_ENOUGH_DATA;
+ }
+
+ chunk_size = get_le32(buf + TAG_SIZE);
+ // For odd-sized chunk-payload, there's one byte padding at the end.
+ disk_chunk_size = (CHUNK_HEADER_SIZE + chunk_size + 1) & ~1;
+ total_size += disk_chunk_size;
+
+ // Check that total bytes skipped so far does not exceed riff_size.
+ if (riff_size > 0 && (total_size > riff_size)) {
+ return VP8_STATUS_BITSTREAM_ERROR; // Not a valid chunk size.
+ }
+
+ if (buf_size < disk_chunk_size) { // Insufficient data.
+ return VP8_STATUS_NOT_ENOUGH_DATA;
+ }
+
+ if (!memcmp(buf, "ALPH", TAG_SIZE)) { // A valid ALPH header.
+ *alpha_data = buf + CHUNK_HEADER_SIZE;
+ *alpha_size = chunk_size;
+ } else if (!memcmp(buf, "VP8 ", TAG_SIZE) ||
+ !memcmp(buf, "VP8L", TAG_SIZE)) { // A valid VP8/VP8L header.
+ return VP8_STATUS_OK; // Found.
+ }
+
+ // We have a full and valid chunk; skip it.
+ buf += disk_chunk_size;
+ buf_size -= disk_chunk_size;
+ }
+}
+
+// Validates the VP8/VP8L Header ("VP8 nnnn" or "VP8L nnnn") and skips over it.
+// Returns VP8_STATUS_BITSTREAM_ERROR for invalid (chunk larger than
+// riff_size) VP8/VP8L header,
+// VP8_STATUS_NOT_ENOUGH_DATA in case of insufficient data, and
+// VP8_STATUS_OK otherwise.
+// If a VP8/VP8L chunk is found, *chunk_size is set to the total number of bytes
+// extracted from the VP8/VP8L chunk header.
+// The flag '*is_lossless' is set to 1 in case of VP8L chunk / raw VP8L data.
+static VP8StatusCode ParseVP8Header(const uint8_t** const data_ptr,
+ size_t* const data_size,
+ size_t riff_size,
+ size_t* const chunk_size,
+ int* const is_lossless) {
+ const uint8_t* const data = *data_ptr;
+ const int is_vp8 = !memcmp(data, "VP8 ", TAG_SIZE);
+ const int is_vp8l = !memcmp(data, "VP8L", TAG_SIZE);
+ const uint32_t minimal_size =
+ TAG_SIZE + CHUNK_HEADER_SIZE; // "WEBP" + "VP8 nnnn" OR
+ // "WEBP" + "VP8Lnnnn"
+ assert(data != NULL);
+ assert(data_size != NULL);
+ assert(chunk_size != NULL);
+ assert(is_lossless != NULL);
+
+ if (*data_size < CHUNK_HEADER_SIZE) {
+ return VP8_STATUS_NOT_ENOUGH_DATA; // Insufficient data.
+ }
+
+ if (is_vp8 || is_vp8l) {
+ // Bitstream contains VP8/VP8L header.
+ const uint32_t size = get_le32(data + TAG_SIZE);
+ if ((riff_size >= minimal_size) && (size > riff_size - minimal_size)) {
+ return VP8_STATUS_BITSTREAM_ERROR; // Inconsistent size information.
+ }
+ // Skip over CHUNK_HEADER_SIZE bytes from VP8/VP8L Header.
+ *chunk_size = size;
+ *data_ptr += CHUNK_HEADER_SIZE;
+ *data_size -= CHUNK_HEADER_SIZE;
+ *is_lossless = is_vp8l;
+ } else {
+ // Raw VP8/VP8L bitstream (no header).
+ *is_lossless = VP8LCheckSignature(data, *data_size);
+ *chunk_size = *data_size;
+ }
+
+ return VP8_STATUS_OK;
+}
+
+//------------------------------------------------------------------------------
+
+// Fetch '*width', '*height', '*has_alpha' and fill out 'headers' based on
+// 'data'. All the output parameters may be NULL. If 'headers' is NULL only the
+// minimal amount will be read to fetch the remaining parameters.
+// If 'headers' is non-NULL this function will attempt to locate both alpha
+// data (with or without a VP8X chunk) and the bitstream chunk (VP8/VP8L).
+// Note: The following chunk sequences (before the raw VP8/VP8L data) are
+// considered valid by this function:
+// RIFF + VP8(L)
+// RIFF + VP8X + (optional chunks) + VP8(L)
+// ALPH + VP8 <-- Not a valid WebP format: only allowed for internal purpose.
+// VP8(L) <-- Not a valid WebP format: only allowed for internal purpose.
+static VP8StatusCode ParseHeadersInternal(const uint8_t* data,
+ size_t data_size,
+ int* const width,
+ int* const height,
+ int* const has_alpha,
+ WebPHeaderStructure* const headers) {
+ int found_riff = 0;
+ int found_vp8x = 0;
+ VP8StatusCode status;
+ WebPHeaderStructure hdrs;
+
+ if (data == NULL || data_size < RIFF_HEADER_SIZE) {
+ return VP8_STATUS_NOT_ENOUGH_DATA;
+ }
+ memset(&hdrs, 0, sizeof(hdrs));
+ hdrs.data = data;
+ hdrs.data_size = data_size;
+
+ // Skip over RIFF header.
+ status = ParseRIFF(&data, &data_size, &hdrs.riff_size);
+ if (status != VP8_STATUS_OK) {
+ return status; // Wrong RIFF header / insufficient data.
+ }
+ found_riff = (hdrs.riff_size > 0);
+
+ // Skip over VP8X.
+ {
+ uint32_t flags = 0;
+ status = ParseVP8X(&data, &data_size, &found_vp8x, width, height, &flags);
+ if (status != VP8_STATUS_OK) {
+ return status; // Wrong VP8X / insufficient data.
+ }
+ if (!found_riff && found_vp8x) {
+ // Note: This restriction may be removed in the future, if it becomes
+ // necessary to send VP8X chunk to the decoder.
+ return VP8_STATUS_BITSTREAM_ERROR;
+ }
+ if (has_alpha != NULL) *has_alpha = !!(flags & ALPHA_FLAG_BIT);
+ if (found_vp8x && headers == NULL) {
+ return VP8_STATUS_OK; // Return features from VP8X header.
+ }
+ }
+
+ if (data_size < TAG_SIZE) return VP8_STATUS_NOT_ENOUGH_DATA;
+
+ // Skip over optional chunks if data started with "RIFF + VP8X" or "ALPH".
+ if ((found_riff && found_vp8x) ||
+ (!found_riff && !found_vp8x && !memcmp(data, "ALPH", TAG_SIZE))) {
+ status = ParseOptionalChunks(&data, &data_size, hdrs.riff_size,
+ &hdrs.alpha_data, &hdrs.alpha_data_size);
+ if (status != VP8_STATUS_OK) {
+ return status; // Found an invalid chunk size / insufficient data.
+ }
+ }
+
+ // Skip over VP8/VP8L header.
+ status = ParseVP8Header(&data, &data_size, hdrs.riff_size,
+ &hdrs.compressed_size, &hdrs.is_lossless);
+ if (status != VP8_STATUS_OK) {
+ return status; // Wrong VP8/VP8L chunk-header / insufficient data.
+ }
+ if (hdrs.compressed_size > MAX_CHUNK_PAYLOAD) {
+ return VP8_STATUS_BITSTREAM_ERROR;
+ }
+
+ if (!hdrs.is_lossless) {
+ if (data_size < VP8_FRAME_HEADER_SIZE) {
+ return VP8_STATUS_NOT_ENOUGH_DATA;
+ }
+ // Validates raw VP8 data.
+ if (!VP8GetInfo(data, data_size,
+ (uint32_t)hdrs.compressed_size, width, height)) {
+ return VP8_STATUS_BITSTREAM_ERROR;
+ }
+ } else {
+ if (data_size < VP8L_FRAME_HEADER_SIZE) {
+ return VP8_STATUS_NOT_ENOUGH_DATA;
+ }
+ // Validates raw VP8L data.
+ if (!VP8LGetInfo(data, data_size, width, height, has_alpha)) {
+ return VP8_STATUS_BITSTREAM_ERROR;
+ }
+ }
+
+ if (has_alpha != NULL) {
+ // If the data did not contain a VP8X/VP8L chunk the only definitive way
+ // to set this is by looking for alpha data (from an ALPH chunk).
+ *has_alpha |= (hdrs.alpha_data != NULL);
+ }
+ if (headers != NULL) {
+ *headers = hdrs;
+ headers->offset = data - headers->data;
+ assert((uint64_t)(data - headers->data) < MAX_CHUNK_PAYLOAD);
+ assert(headers->offset == headers->data_size - data_size);
+ }
+ return VP8_STATUS_OK; // Return features from VP8 header.
+}
+
+VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers) {
+ assert(headers != NULL);
+ // fill out headers, ignore width/height/has_alpha.
+ return ParseHeadersInternal(headers->data, headers->data_size,
+ NULL, NULL, NULL, headers);
+}
+
+//------------------------------------------------------------------------------
+// WebPDecParams
+
+void WebPResetDecParams(WebPDecParams* const params) {
+ if (params) {
+ memset(params, 0, sizeof(*params));
+ }
+}
+
+//------------------------------------------------------------------------------
+// "Into" decoding variants
+
+// Main flow
+static VP8StatusCode DecodeInto(const uint8_t* const data, size_t data_size,
+ WebPDecParams* const params) {
+ VP8StatusCode status;
+ VP8Io io;
+ WebPHeaderStructure headers;
+
+ headers.data = data;
+ headers.data_size = data_size;
+ status = WebPParseHeaders(&headers); // Process Pre-VP8 chunks.
+ if (status != VP8_STATUS_OK) {
+ return status;
+ }
+
+ assert(params != NULL);
+ VP8InitIo(&io);
+ io.data = headers.data + headers.offset;
+ io.data_size = headers.data_size - headers.offset;
+ WebPInitCustomIo(params, &io); // Plug the I/O functions.
+
+ if (!headers.is_lossless) {
+ VP8Decoder* const dec = VP8New();
+ if (dec == NULL) {
+ return VP8_STATUS_OUT_OF_MEMORY;
+ }
+#ifdef WEBP_USE_THREAD
+ dec->use_threads_ = params->options && (params->options->use_threads > 0);
+#else
+ dec->use_threads_ = 0;
+#endif
+ dec->alpha_data_ = headers.alpha_data;
+ dec->alpha_data_size_ = headers.alpha_data_size;
+
+ // Decode bitstream header, update io->width/io->height.
+ if (!VP8GetHeaders(dec, &io)) {
+ status = dec->status_; // An error occurred. Grab error status.
+ } else {
+ // Allocate/check output buffers.
+ status = WebPAllocateDecBuffer(io.width, io.height, params->options,
+ params->output);
+ if (status == VP8_STATUS_OK) { // Decode
+ if (!VP8Decode(dec, &io)) {
+ status = dec->status_;
+ }
+ }
+ }
+ VP8Delete(dec);
+ } else {
+ VP8LDecoder* const dec = VP8LNew();
+ if (dec == NULL) {
+ return VP8_STATUS_OUT_OF_MEMORY;
+ }
+ if (!VP8LDecodeHeader(dec, &io)) {
+ status = dec->status_; // An error occurred. Grab error status.
+ } else {
+ // Allocate/check output buffers.
+ status = WebPAllocateDecBuffer(io.width, io.height, params->options,
+ params->output);
+ if (status == VP8_STATUS_OK) { // Decode
+ if (!VP8LDecodeImage(dec)) {
+ status = dec->status_;
+ }
+ }
+ }
+ VP8LDelete(dec);
+ }
+
+ if (status != VP8_STATUS_OK) {
+ WebPFreeDecBuffer(params->output);
+ }
+ return status;
+}
+
+// Helpers
+static uint8_t* DecodeIntoRGBABuffer(WEBP_CSP_MODE colorspace,
+ const uint8_t* const data,
+ size_t data_size,
+ uint8_t* const rgba,
+ int stride, size_t size) {
+ WebPDecParams params;
+ WebPDecBuffer buf;
+ if (rgba == NULL) {
+ return NULL;
+ }
+ WebPInitDecBuffer(&buf);
+ WebPResetDecParams(&params);
+ params.output = &buf;
+ buf.colorspace = colorspace;
+ buf.u.RGBA.rgba = rgba;
+ buf.u.RGBA.stride = stride;
+ buf.u.RGBA.size = size;
+ buf.is_external_memory = 1;
+ if (DecodeInto(data, data_size, &params) != VP8_STATUS_OK) {
+ return NULL;
+ }
+ return rgba;
+}
+
+uint8_t* WebPDecodeRGBInto(const uint8_t* data, size_t data_size,
+ uint8_t* output, size_t size, int stride) {
+ return DecodeIntoRGBABuffer(MODE_RGB, data, data_size, output, stride, size);
+}
+
+uint8_t* WebPDecodeRGBAInto(const uint8_t* data, size_t data_size,
+ uint8_t* output, size_t size, int stride) {
+ return DecodeIntoRGBABuffer(MODE_RGBA, data, data_size, output, stride, size);
+}
+
+uint8_t* WebPDecodeARGBInto(const uint8_t* data, size_t data_size,
+ uint8_t* output, size_t size, int stride) {
+ return DecodeIntoRGBABuffer(MODE_ARGB, data, data_size, output, stride, size);
+}
+
+uint8_t* WebPDecodeBGRInto(const uint8_t* data, size_t data_size,
+ uint8_t* output, size_t size, int stride) {
+ return DecodeIntoRGBABuffer(MODE_BGR, data, data_size, output, stride, size);
+}
+
+uint8_t* WebPDecodeBGRAInto(const uint8_t* data, size_t data_size,
+ uint8_t* output, size_t size, int stride) {
+ return DecodeIntoRGBABuffer(MODE_BGRA, data, data_size, output, stride, size);
+}
+
+uint8_t* WebPDecodeYUVInto(const uint8_t* data, size_t data_size,
+ uint8_t* luma, size_t luma_size, int luma_stride,
+ uint8_t* u, size_t u_size, int u_stride,
+ uint8_t* v, size_t v_size, int v_stride) {
+ WebPDecParams params;
+ WebPDecBuffer output;
+ if (luma == NULL) return NULL;
+ WebPInitDecBuffer(&output);
+ WebPResetDecParams(&params);
+ params.output = &output;
+ output.colorspace = MODE_YUV;
+ output.u.YUVA.y = luma;
+ output.u.YUVA.y_stride = luma_stride;
+ output.u.YUVA.y_size = luma_size;
+ output.u.YUVA.u = u;
+ output.u.YUVA.u_stride = u_stride;
+ output.u.YUVA.u_size = u_size;
+ output.u.YUVA.v = v;
+ output.u.YUVA.v_stride = v_stride;
+ output.u.YUVA.v_size = v_size;
+ output.is_external_memory = 1;
+ if (DecodeInto(data, data_size, &params) != VP8_STATUS_OK) {
+ return NULL;
+ }
+ return luma;
+}
+
+//------------------------------------------------------------------------------
+
+static uint8_t* Decode(WEBP_CSP_MODE mode, const uint8_t* const data,
+ size_t data_size, int* const width, int* const height,
+ WebPDecBuffer* const keep_info) {
+ WebPDecParams params;
+ WebPDecBuffer output;
+
+ WebPInitDecBuffer(&output);
+ WebPResetDecParams(&params);
+ params.output = &output;
+ output.colorspace = mode;
+
+ // Retrieve (and report back) the required dimensions from bitstream.
+ if (!WebPGetInfo(data, data_size, &output.width, &output.height)) {
+ return NULL;
+ }
+ if (width != NULL) *width = output.width;
+ if (height != NULL) *height = output.height;
+
+ // Decode
+ if (DecodeInto(data, data_size, &params) != VP8_STATUS_OK) {
+ return NULL;
+ }
+ if (keep_info != NULL) { // keep track of the side-info
+ WebPCopyDecBuffer(&output, keep_info);
+ }
+ // return decoded samples (don't clear 'output'!)
+ return WebPIsRGBMode(mode) ? output.u.RGBA.rgba : output.u.YUVA.y;
+}
+
+uint8_t* WebPDecodeRGB(const uint8_t* data, size_t data_size,
+ int* width, int* height) {
+ return Decode(MODE_RGB, data, data_size, width, height, NULL);
+}
+
+uint8_t* WebPDecodeRGBA(const uint8_t* data, size_t data_size,
+ int* width, int* height) {
+ return Decode(MODE_RGBA, data, data_size, width, height, NULL);
+}
+
+uint8_t* WebPDecodeARGB(const uint8_t* data, size_t data_size,
+ int* width, int* height) {
+ return Decode(MODE_ARGB, data, data_size, width, height, NULL);
+}
+
+uint8_t* WebPDecodeBGR(const uint8_t* data, size_t data_size,
+ int* width, int* height) {
+ return Decode(MODE_BGR, data, data_size, width, height, NULL);
+}
+
+uint8_t* WebPDecodeBGRA(const uint8_t* data, size_t data_size,
+ int* width, int* height) {
+ return Decode(MODE_BGRA, data, data_size, width, height, NULL);
+}
+
+uint8_t* WebPDecodeYUV(const uint8_t* data, size_t data_size,
+ int* width, int* height, uint8_t** u, uint8_t** v,
+ int* stride, int* uv_stride) {
+ WebPDecBuffer output; // only to preserve the side-infos
+ uint8_t* const out = Decode(MODE_YUV, data, data_size,
+ width, height, &output);
+
+ if (out != NULL) {
+ const WebPYUVABuffer* const buf = &output.u.YUVA;
+ *u = buf->u;
+ *v = buf->v;
+ *stride = buf->y_stride;
+ *uv_stride = buf->u_stride;
+ assert(buf->u_stride == buf->v_stride);
+ }
+ return out;
+}
+
+static void DefaultFeatures(WebPBitstreamFeatures* const features) {
+ assert(features != NULL);
+ memset(features, 0, sizeof(*features));
+ features->bitstream_version = 0;
+}
+
+static VP8StatusCode GetFeatures(const uint8_t* const data, size_t data_size,
+ WebPBitstreamFeatures* const features) {
+ if (features == NULL || data == NULL) {
+ return VP8_STATUS_INVALID_PARAM;
+ }
+ DefaultFeatures(features);
+
+ // Only parse enough of the data to retrieve width/height/has_alpha.
+ return ParseHeadersInternal(data, data_size,
+ &features->width, &features->height,
+ &features->has_alpha, NULL);
+}
+
+//------------------------------------------------------------------------------
+// WebPGetInfo()
+
+int WebPGetInfo(const uint8_t* data, size_t data_size,
+ int* width, int* height) {
+ WebPBitstreamFeatures features;
+
+ if (GetFeatures(data, data_size, &features) != VP8_STATUS_OK) {
+ return 0;
+ }
+
+ if (width != NULL) {
+ *width = features.width;
+ }
+ if (height != NULL) {
+ *height = features.height;
+ }
+
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+// Advance decoding API
+
+int WebPInitDecoderConfigInternal(WebPDecoderConfig* config,
+ int version) {
+ if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) {
+ return 0; // version mismatch
+ }
+ if (config == NULL) {
+ return 0;
+ }
+ memset(config, 0, sizeof(*config));
+ DefaultFeatures(&config->input);
+ WebPInitDecBuffer(&config->output);
+ return 1;
+}
+
+VP8StatusCode WebPGetFeaturesInternal(const uint8_t* data, size_t data_size,
+ WebPBitstreamFeatures* features,
+ int version) {
+ VP8StatusCode status;
+ if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_DECODER_ABI_VERSION)) {
+ return VP8_STATUS_INVALID_PARAM; // version mismatch
+ }
+ if (features == NULL) {
+ return VP8_STATUS_INVALID_PARAM;
+ }
+
+ status = GetFeatures(data, data_size, features);
+ if (status == VP8_STATUS_NOT_ENOUGH_DATA) {
+ return VP8_STATUS_BITSTREAM_ERROR; // Not-enough-data treated as error.
+ }
+ return status;
+}
+
+VP8StatusCode WebPDecode(const uint8_t* data, size_t data_size,
+ WebPDecoderConfig* config) {
+ WebPDecParams params;
+ VP8StatusCode status;
+
+ if (config == NULL) {
+ return VP8_STATUS_INVALID_PARAM;
+ }
+
+ status = GetFeatures(data, data_size, &config->input);
+ if (status != VP8_STATUS_OK) {
+ if (status == VP8_STATUS_NOT_ENOUGH_DATA) {
+ return VP8_STATUS_BITSTREAM_ERROR; // Not-enough-data treated as error.
+ }
+ return status;
+ }
+
+ WebPResetDecParams(&params);
+ params.output = &config->output;
+ params.options = &config->options;
+ status = DecodeInto(data, data_size, &params);
+
+ return status;
+}
+
+//------------------------------------------------------------------------------
+// Cropping and rescaling.
+
+int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
+ VP8Io* const io, WEBP_CSP_MODE src_colorspace) {
+ const int W = io->width;
+ const int H = io->height;
+ int x = 0, y = 0, w = W, h = H;
+
+ // Cropping
+ io->use_cropping = (options != NULL) && (options->use_cropping > 0);
+ if (io->use_cropping) {
+ w = options->crop_width;
+ h = options->crop_height;
+ x = options->crop_left;
+ y = options->crop_top;
+ if (!WebPIsRGBMode(src_colorspace)) { // only snap for YUV420 or YUV422
+ x &= ~1;
+ y &= ~1; // TODO(later): only for YUV420, not YUV422.
+ }
+ if (x < 0 || y < 0 || w <= 0 || h <= 0 || x + w > W || y + h > H) {
+ return 0; // out of frame boundary error
+ }
+ }
+ io->crop_left = x;
+ io->crop_top = y;
+ io->crop_right = x + w;
+ io->crop_bottom = y + h;
+ io->mb_w = w;
+ io->mb_h = h;
+
+ // Scaling
+ io->use_scaling = (options != NULL) && (options->use_scaling > 0);
+ if (io->use_scaling) {
+ if (options->scaled_width <= 0 || options->scaled_height <= 0) {
+ return 0;
+ }
+ io->scaled_width = options->scaled_width;
+ io->scaled_height = options->scaled_height;
+ }
+
+ // Filter
+ io->bypass_filtering = options && options->bypass_filtering;
+
+ // Fancy upsampler
+#ifdef FANCY_UPSAMPLING
+ io->fancy_upsampling = (options == NULL) || (!options->no_fancy_upsampling);
+#endif
+
+ if (io->use_scaling) {
+ // disable filter (only for large downscaling ratio).
+ io->bypass_filtering = (io->scaled_width < W * 3 / 4) &&
+ (io->scaled_height < H * 3 / 4);
+ io->fancy_upsampling = 0;
+ }
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/dec/webpi.h b/drivers/webpold/dec/webpi.h
new file mode 100644
index 0000000000..44e5744411
--- /dev/null
+++ b/drivers/webpold/dec/webpi.h
@@ -0,0 +1,114 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Internal header: WebP decoding parameters and custom IO on buffer
+//
+// Author: somnath@google.com (Somnath Banerjee)
+
+#ifndef WEBP_DEC_WEBPI_H_
+#define WEBP_DEC_WEBPI_H_
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "../utils/rescaler.h"
+#include "./decode_vp8.h"
+
+//------------------------------------------------------------------------------
+// WebPDecParams: Decoding output parameters. Transient internal object.
+
+typedef struct WebPDecParams WebPDecParams;
+typedef int (*OutputFunc)(const VP8Io* const io, WebPDecParams* const p);
+typedef int (*OutputRowFunc)(WebPDecParams* const p, int y_pos);
+
+struct WebPDecParams {
+ WebPDecBuffer* output; // output buffer.
+ uint8_t* tmp_y, *tmp_u, *tmp_v; // cache for the fancy upsampler
+ // or used for tmp rescaling
+
+ int last_y; // coordinate of the line that was last output
+ const WebPDecoderOptions* options; // if not NULL, use alt decoding features
+ // rescalers
+ WebPRescaler scaler_y, scaler_u, scaler_v, scaler_a;
+ void* memory; // overall scratch memory for the output work.
+
+ OutputFunc emit; // output RGB or YUV samples
+ OutputFunc emit_alpha; // output alpha channel
+ OutputRowFunc emit_alpha_row; // output one line of rescaled alpha values
+};
+
+// Should be called first, before any use of the WebPDecParams object.
+void WebPResetDecParams(WebPDecParams* const params);
+
+//------------------------------------------------------------------------------
+// Header parsing helpers
+
+// Structure storing a description of the RIFF headers.
+typedef struct {
+ const uint8_t* data; // input buffer
+ size_t data_size; // input buffer size
+ size_t offset; // offset to main data chunk (VP8 or VP8L)
+ const uint8_t* alpha_data; // points to alpha chunk (if present)
+ size_t alpha_data_size; // alpha chunk size
+ size_t compressed_size; // VP8/VP8L compressed data size
+ size_t riff_size; // size of the riff payload (or 0 if absent)
+ int is_lossless; // true if a VP8L chunk is present
+} WebPHeaderStructure;
+
+// Skips over all valid chunks prior to the first VP8/VP8L frame header.
+// Returns VP8_STATUS_OK on success,
+// VP8_STATUS_BITSTREAM_ERROR if an invalid header/chunk is found, and
+// VP8_STATUS_NOT_ENOUGH_DATA if case of insufficient data.
+// In 'headers', compressed_size, offset, alpha_data, alpha_size and lossless
+// fields are updated appropriately upon success.
+VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers);
+
+//------------------------------------------------------------------------------
+// Misc utils
+
+// Initializes VP8Io with custom setup, io and teardown functions. The default
+// hooks will use the supplied 'params' as io->opaque handle.
+void WebPInitCustomIo(WebPDecParams* const params, VP8Io* const io);
+
+// Setup crop_xxx fields, mb_w and mb_h in io. 'src_colorspace' refers
+// to the *compressed* format, not the output one.
+int WebPIoInitFromOptions(const WebPDecoderOptions* const options,
+ VP8Io* const io, WEBP_CSP_MODE src_colorspace);
+
+//------------------------------------------------------------------------------
+// Internal functions regarding WebPDecBuffer memory (in buffer.c).
+// Don't really need to be externally visible for now.
+
+// Prepare 'buffer' with the requested initial dimensions width/height.
+// If no external storage is supplied, initializes buffer by allocating output
+// memory and setting up the stride information. Validate the parameters. Return
+// an error code in case of problem (no memory, or invalid stride / size /
+// dimension / etc.). If *options is not NULL, also verify that the options'
+// parameters are valid and apply them to the width/height dimensions of the
+// output buffer. This takes cropping / scaling / rotation into account.
+VP8StatusCode WebPAllocateDecBuffer(int width, int height,
+ const WebPDecoderOptions* const options,
+ WebPDecBuffer* const buffer);
+
+// Copy 'src' into 'dst' buffer, making sure 'dst' is not marked as owner of the
+// memory (still held by 'src').
+void WebPCopyDecBuffer(const WebPDecBuffer* const src,
+ WebPDecBuffer* const dst);
+
+// Copy and transfer ownership from src to dst (beware of parameter order!)
+void WebPGrabDecBuffer(WebPDecBuffer* const src, WebPDecBuffer* const dst);
+
+
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif /* WEBP_DEC_WEBPI_H_ */
diff --git a/drivers/webpold/decode.h b/drivers/webpold/decode.h
new file mode 100644
index 0000000000..43b6c58f4f
--- /dev/null
+++ b/drivers/webpold/decode.h
@@ -0,0 +1,454 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Main decoding functions for WebP images.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#ifndef WEBP_WEBP_DECODE_H_
+#define WEBP_WEBP_DECODE_H_
+
+#include "./types.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define WEBP_DECODER_ABI_VERSION 0x0200 // MAJOR(8b) + MINOR(8b)
+
+// Return the decoder's version number, packed in hexadecimal using 8bits for
+// each of major/minor/revision. E.g: v2.5.7 is 0x020507.
+WEBP_EXTERN(int) WebPGetDecoderVersion(void);
+
+// Retrieve basic header information: width, height.
+// This function will also validate the header and return 0 in
+// case of formatting error.
+// Pointers 'width' and 'height' can be passed NULL if deemed irrelevant.
+WEBP_EXTERN(int) WebPGetInfo(const uint8_t* data, size_t data_size,
+ int* width, int* height);
+
+// Decodes WebP images pointed to by 'data' and returns RGBA samples, along
+// with the dimensions in *width and *height. The ordering of samples in
+// memory is R, G, B, A, R, G, B, A... in scan order (endian-independent).
+// The returned pointer should be deleted calling free().
+// Returns NULL in case of error.
+WEBP_EXTERN(uint8_t*) WebPDecodeRGBA(const uint8_t* data, size_t data_size,
+ int* width, int* height);
+
+// Same as WebPDecodeRGBA, but returning A, R, G, B, A, R, G, B... ordered data.
+WEBP_EXTERN(uint8_t*) WebPDecodeARGB(const uint8_t* data, size_t data_size,
+ int* width, int* height);
+
+// Same as WebPDecodeRGBA, but returning B, G, R, A, B, G, R, A... ordered data.
+WEBP_EXTERN(uint8_t*) WebPDecodeBGRA(const uint8_t* data, size_t data_size,
+ int* width, int* height);
+
+// Same as WebPDecodeRGBA, but returning R, G, B, R, G, B... ordered data.
+// If the bitstream contains transparency, it is ignored.
+WEBP_EXTERN(uint8_t*) WebPDecodeRGB(const uint8_t* data, size_t data_size,
+ int* width, int* height);
+
+// Same as WebPDecodeRGB, but returning B, G, R, B, G, R... ordered data.
+WEBP_EXTERN(uint8_t*) WebPDecodeBGR(const uint8_t* data, size_t data_size,
+ int* width, int* height);
+
+
+// Decode WebP images pointed to by 'data' to Y'UV format(*). The pointer
+// returned is the Y samples buffer. Upon return, *u and *v will point to
+// the U and V chroma data. These U and V buffers need NOT be free()'d,
+// unlike the returned Y luma one. The dimension of the U and V planes
+// are both (*width + 1) / 2 and (*height + 1)/ 2.
+// Upon return, the Y buffer has a stride returned as '*stride', while U and V
+// have a common stride returned as '*uv_stride'.
+// Return NULL in case of error.
+// (*) Also named Y'CbCr. See: http://en.wikipedia.org/wiki/YCbCr
+WEBP_EXTERN(uint8_t*) WebPDecodeYUV(const uint8_t* data, size_t data_size,
+ int* width, int* height,
+ uint8_t** u, uint8_t** v,
+ int* stride, int* uv_stride);
+
+// These five functions are variants of the above ones, that decode the image
+// directly into a pre-allocated buffer 'output_buffer'. The maximum storage
+// available in this buffer is indicated by 'output_buffer_size'. If this
+// storage is not sufficient (or an error occurred), NULL is returned.
+// Otherwise, output_buffer is returned, for convenience.
+// The parameter 'output_stride' specifies the distance (in bytes)
+// between scanlines. Hence, output_buffer_size is expected to be at least
+// output_stride x picture-height.
+WEBP_EXTERN(uint8_t*) WebPDecodeRGBAInto(
+ const uint8_t* data, size_t data_size,
+ uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
+WEBP_EXTERN(uint8_t*) WebPDecodeARGBInto(
+ const uint8_t* data, size_t data_size,
+ uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
+WEBP_EXTERN(uint8_t*) WebPDecodeBGRAInto(
+ const uint8_t* data, size_t data_size,
+ uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
+
+// RGB and BGR variants. Here too the transparency information, if present,
+// will be dropped and ignored.
+WEBP_EXTERN(uint8_t*) WebPDecodeRGBInto(
+ const uint8_t* data, size_t data_size,
+ uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
+WEBP_EXTERN(uint8_t*) WebPDecodeBGRInto(
+ const uint8_t* data, size_t data_size,
+ uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
+
+// WebPDecodeYUVInto() is a variant of WebPDecodeYUV() that operates directly
+// into pre-allocated luma/chroma plane buffers. This function requires the
+// strides to be passed: one for the luma plane and one for each of the
+// chroma ones. The size of each plane buffer is passed as 'luma_size',
+// 'u_size' and 'v_size' respectively.
+// Pointer to the luma plane ('*luma') is returned or NULL if an error occurred
+// during decoding (or because some buffers were found to be too small).
+WEBP_EXTERN(uint8_t*) WebPDecodeYUVInto(
+ const uint8_t* data, size_t data_size,
+ uint8_t* luma, size_t luma_size, int luma_stride,
+ uint8_t* u, size_t u_size, int u_stride,
+ uint8_t* v, size_t v_size, int v_stride);
+
+//------------------------------------------------------------------------------
+// Output colorspaces and buffer
+
+// Colorspaces
+// Note: the naming describes the byte-ordering of packed samples in memory.
+// For instance, MODE_BGRA relates to samples ordered as B,G,R,A,B,G,R,A,...
+// Non-capital names (e.g.:MODE_Argb) relates to pre-multiplied RGB channels.
+// RGB-565 and RGBA-4444 are also endian-agnostic and byte-oriented.
+typedef enum { MODE_RGB = 0, MODE_RGBA = 1,
+ MODE_BGR = 2, MODE_BGRA = 3,
+ MODE_ARGB = 4, MODE_RGBA_4444 = 5,
+ MODE_RGB_565 = 6,
+ // RGB-premultiplied transparent modes (alpha value is preserved)
+ MODE_rgbA = 7,
+ MODE_bgrA = 8,
+ MODE_Argb = 9,
+ MODE_rgbA_4444 = 10,
+ // YUV modes must come after RGB ones.
+ MODE_YUV = 11, MODE_YUVA = 12, // yuv 4:2:0
+ MODE_LAST = 13
+ } WEBP_CSP_MODE;
+
+// Some useful macros:
+static WEBP_INLINE int WebPIsPremultipliedMode(WEBP_CSP_MODE mode) {
+ return (mode == MODE_rgbA || mode == MODE_bgrA || mode == MODE_Argb ||
+ mode == MODE_rgbA_4444);
+}
+
+static WEBP_INLINE int WebPIsAlphaMode(WEBP_CSP_MODE mode) {
+ return (mode == MODE_RGBA || mode == MODE_BGRA || mode == MODE_ARGB ||
+ mode == MODE_RGBA_4444 || mode == MODE_YUVA ||
+ WebPIsPremultipliedMode(mode));
+}
+
+static WEBP_INLINE int WebPIsRGBMode(WEBP_CSP_MODE mode) {
+ return (mode < MODE_YUV);
+}
+
+//------------------------------------------------------------------------------
+// WebPDecBuffer: Generic structure for describing the output sample buffer.
+
+typedef struct { // view as RGBA
+ uint8_t* rgba; // pointer to RGBA samples
+ int stride; // stride in bytes from one scanline to the next.
+ size_t size; // total size of the *rgba buffer.
+} WebPRGBABuffer;
+
+typedef struct { // view as YUVA
+ uint8_t* y, *u, *v, *a; // pointer to luma, chroma U/V, alpha samples
+ int y_stride; // luma stride
+ int u_stride, v_stride; // chroma strides
+ int a_stride; // alpha stride
+ size_t y_size; // luma plane size
+ size_t u_size, v_size; // chroma planes size
+ size_t a_size; // alpha-plane size
+} WebPYUVABuffer;
+
+// Output buffer
+typedef struct {
+ WEBP_CSP_MODE colorspace; // Colorspace.
+ int width, height; // Dimensions.
+ int is_external_memory; // If true, 'internal_memory' pointer is not used.
+ union {
+ WebPRGBABuffer RGBA;
+ WebPYUVABuffer YUVA;
+ } u; // Nameless union of buffer parameters.
+ uint32_t pad[4]; // padding for later use
+
+ uint8_t* private_memory; // Internally allocated memory (only when
+ // is_external_memory is false). Should not be used
+ // externally, but accessed via the buffer union.
+} WebPDecBuffer;
+
+// Internal, version-checked, entry point
+WEBP_EXTERN(int) WebPInitDecBufferInternal(WebPDecBuffer*, int);
+
+// Initialize the structure as empty. Must be called before any other use.
+// Returns false in case of version mismatch
+static WEBP_INLINE int WebPInitDecBuffer(WebPDecBuffer* buffer) {
+ return WebPInitDecBufferInternal(buffer, WEBP_DECODER_ABI_VERSION);
+}
+
+// Free any memory associated with the buffer. Must always be called last.
+// Note: doesn't free the 'buffer' structure itself.
+WEBP_EXTERN(void) WebPFreeDecBuffer(WebPDecBuffer* buffer);
+
+//------------------------------------------------------------------------------
+// Enumeration of the status codes
+
+typedef enum {
+ VP8_STATUS_OK = 0,
+ VP8_STATUS_OUT_OF_MEMORY,
+ VP8_STATUS_INVALID_PARAM,
+ VP8_STATUS_BITSTREAM_ERROR,
+ VP8_STATUS_UNSUPPORTED_FEATURE,
+ VP8_STATUS_SUSPENDED,
+ VP8_STATUS_USER_ABORT,
+ VP8_STATUS_NOT_ENOUGH_DATA
+} VP8StatusCode;
+
+//------------------------------------------------------------------------------
+// Incremental decoding
+//
+// This API allows streamlined decoding of partial data.
+// Picture can be incrementally decoded as data become available thanks to the
+// WebPIDecoder object. This object can be left in a SUSPENDED state if the
+// picture is only partially decoded, pending additional input.
+// Code example:
+//
+// WebPInitDecBuffer(&buffer);
+// buffer.colorspace = mode;
+// ...
+// WebPIDecoder* idec = WebPINewDecoder(&buffer);
+// while (has_more_data) {
+// // ... (get additional data)
+// status = WebPIAppend(idec, new_data, new_data_size);
+// if (status != VP8_STATUS_SUSPENDED ||
+// break;
+// }
+//
+// // The above call decodes the current available buffer.
+// // Part of the image can now be refreshed by calling to
+// // WebPIDecGetRGB()/WebPIDecGetYUVA() etc.
+// }
+// WebPIDelete(idec);
+
+typedef struct WebPIDecoder WebPIDecoder;
+
+// Creates a new incremental decoder with the supplied buffer parameter.
+// This output_buffer can be passed NULL, in which case a default output buffer
+// is used (with MODE_RGB). Otherwise, an internal reference to 'output_buffer'
+// is kept, which means that the lifespan of 'output_buffer' must be larger than
+// that of the returned WebPIDecoder object.
+// Returns NULL if the allocation failed.
+WEBP_EXTERN(WebPIDecoder*) WebPINewDecoder(WebPDecBuffer* output_buffer);
+
+// This function allocates and initializes an incremental-decoder object, which
+// will output the RGB/A samples specified by 'csp' into a preallocated
+// buffer 'output_buffer'. The size of this buffer is at least
+// 'output_buffer_size' and the stride (distance in bytes between two scanlines)
+// is specified by 'output_stride'. Returns NULL if the allocation failed.
+WEBP_EXTERN(WebPIDecoder*) WebPINewRGB(
+ WEBP_CSP_MODE csp,
+ uint8_t* output_buffer, size_t output_buffer_size, int output_stride);
+
+// This function allocates and initializes an incremental-decoder object, which
+// will output the raw luma/chroma samples into a preallocated planes. The luma
+// plane is specified by its pointer 'luma', its size 'luma_size' and its stride
+// 'luma_stride'. Similarly, the chroma-u plane is specified by the 'u',
+// 'u_size' and 'u_stride' parameters, and the chroma-v plane by 'v'
+// and 'v_size'. And same for the alpha-plane. The 'a' pointer can be pass
+// NULL in case one is not interested in the transparency plane.
+// Returns NULL if the allocation failed.
+WEBP_EXTERN(WebPIDecoder*) WebPINewYUVA(
+ uint8_t* luma, size_t luma_size, int luma_stride,
+ uint8_t* u, size_t u_size, int u_stride,
+ uint8_t* v, size_t v_size, int v_stride,
+ uint8_t* a, size_t a_size, int a_stride);
+
+// Deprecated version of the above, without the alpha plane.
+// Kept for backward compatibility.
+WEBP_EXTERN(WebPIDecoder*) WebPINewYUV(
+ uint8_t* luma, size_t luma_size, int luma_stride,
+ uint8_t* u, size_t u_size, int u_stride,
+ uint8_t* v, size_t v_size, int v_stride);
+
+// Deletes the WebPIDecoder object and associated memory. Must always be called
+// if WebPINewDecoder, WebPINewRGB or WebPINewYUV succeeded.
+WEBP_EXTERN(void) WebPIDelete(WebPIDecoder* idec);
+
+// Copies and decodes the next available data. Returns VP8_STATUS_OK when
+// the image is successfully decoded. Returns VP8_STATUS_SUSPENDED when more
+// data is expected. Returns error in other cases.
+WEBP_EXTERN(VP8StatusCode) WebPIAppend(
+ WebPIDecoder* idec, const uint8_t* data, size_t data_size);
+
+// A variant of the above function to be used when data buffer contains
+// partial data from the beginning. In this case data buffer is not copied
+// to the internal memory.
+// Note that the value of the 'data' pointer can change between calls to
+// WebPIUpdate, for instance when the data buffer is resized to fit larger data.
+WEBP_EXTERN(VP8StatusCode) WebPIUpdate(
+ WebPIDecoder* idec, const uint8_t* data, size_t data_size);
+
+// Returns the RGB/A image decoded so far. Returns NULL if output params
+// are not initialized yet. The RGB/A output type corresponds to the colorspace
+// specified during call to WebPINewDecoder() or WebPINewRGB().
+// *last_y is the index of last decoded row in raster scan order. Some pointers
+// (*last_y, *width etc.) can be NULL if corresponding information is not
+// needed.
+WEBP_EXTERN(uint8_t*) WebPIDecGetRGB(
+ const WebPIDecoder* idec, int* last_y,
+ int* width, int* height, int* stride);
+
+// Same as above function to get a YUVA image. Returns pointer to the luma
+// plane or NULL in case of error. If there is no alpha information
+// the alpha pointer '*a' will be returned NULL.
+WEBP_EXTERN(uint8_t*) WebPIDecGetYUVA(
+ const WebPIDecoder* idec, int* last_y,
+ uint8_t** u, uint8_t** v, uint8_t** a,
+ int* width, int* height, int* stride, int* uv_stride, int* a_stride);
+
+// Deprecated alpha-less version of WebPIDecGetYUVA(): it will ignore the
+// alpha information (if present). Kept for backward compatibility.
+static WEBP_INLINE uint8_t* WebPIDecGetYUV(
+ const WebPIDecoder* idec, int* last_y, uint8_t** u, uint8_t** v,
+ int* width, int* height, int* stride, int* uv_stride) {
+ return WebPIDecGetYUVA(idec, last_y, u, v, NULL, width, height,
+ stride, uv_stride, NULL);
+}
+
+// Generic call to retrieve information about the displayable area.
+// If non NULL, the left/right/width/height pointers are filled with the visible
+// rectangular area so far.
+// Returns NULL in case the incremental decoder object is in an invalid state.
+// Otherwise returns the pointer to the internal representation. This structure
+// is read-only, tied to WebPIDecoder's lifespan and should not be modified.
+WEBP_EXTERN(const WebPDecBuffer*) WebPIDecodedArea(
+ const WebPIDecoder* idec, int* left, int* top, int* width, int* height);
+
+//------------------------------------------------------------------------------
+// Advanced decoding parametrization
+//
+// Code sample for using the advanced decoding API
+/*
+ // A) Init a configuration object
+ WebPDecoderConfig config;
+ CHECK(WebPInitDecoderConfig(&config));
+
+ // B) optional: retrieve the bitstream's features.
+ CHECK(WebPGetFeatures(data, data_size, &config.input) == VP8_STATUS_OK);
+
+ // C) Adjust 'config', if needed
+ config.no_fancy = 1;
+ config.output.colorspace = MODE_BGRA;
+ // etc.
+
+ // Note that you can also make config.output point to an externally
+ // supplied memory buffer, provided it's big enough to store the decoded
+ // picture. Otherwise, config.output will just be used to allocate memory
+ // and store the decoded picture.
+
+ // D) Decode!
+ CHECK(WebPDecode(data, data_size, &config) == VP8_STATUS_OK);
+
+ // E) Decoded image is now in config.output (and config.output.u.RGBA)
+
+ // F) Reclaim memory allocated in config's object. It's safe to call
+ // this function even if the memory is external and wasn't allocated
+ // by WebPDecode().
+ WebPFreeDecBuffer(&config.output);
+*/
+
+// Features gathered from the bitstream
+typedef struct {
+ int width; // Width in pixels, as read from the bitstream.
+ int height; // Height in pixels, as read from the bitstream.
+ int has_alpha; // True if the bitstream contains an alpha channel.
+
+ // Unused for now:
+ int bitstream_version; // should be 0 for now. TODO(later)
+ int no_incremental_decoding; // if true, using incremental decoding is not
+ // recommended.
+ int rotate; // TODO(later)
+ int uv_sampling; // should be 0 for now. TODO(later)
+ uint32_t pad[3]; // padding for later use
+} WebPBitstreamFeatures;
+
+// Internal, version-checked, entry point
+WEBP_EXTERN(VP8StatusCode) WebPGetFeaturesInternal(
+ const uint8_t*, size_t, WebPBitstreamFeatures*, int);
+
+// Retrieve features from the bitstream. The *features structure is filled
+// with information gathered from the bitstream.
+// Returns false in case of error or version mismatch.
+// In case of error, features->bitstream_status will reflect the error code.
+static WEBP_INLINE VP8StatusCode WebPGetFeatures(
+ const uint8_t* data, size_t data_size,
+ WebPBitstreamFeatures* features) {
+ return WebPGetFeaturesInternal(data, data_size, features,
+ WEBP_DECODER_ABI_VERSION);
+}
+
+// Decoding options
+typedef struct {
+ int bypass_filtering; // if true, skip the in-loop filtering
+ int no_fancy_upsampling; // if true, use faster pointwise upsampler
+ int use_cropping; // if true, cropping is applied _first_
+ int crop_left, crop_top; // top-left position for cropping.
+ // Will be snapped to even values.
+ int crop_width, crop_height; // dimension of the cropping area
+ int use_scaling; // if true, scaling is applied _afterward_
+ int scaled_width, scaled_height; // final resolution
+ int use_threads; // if true, use multi-threaded decoding
+
+ // Unused for now:
+ int force_rotation; // forced rotation (to be applied _last_)
+ int no_enhancement; // if true, discard enhancement layer
+ uint32_t pad[6]; // padding for later use
+} WebPDecoderOptions;
+
+// Main object storing the configuration for advanced decoding.
+typedef struct {
+ WebPBitstreamFeatures input; // Immutable bitstream features (optional)
+ WebPDecBuffer output; // Output buffer (can point to external mem)
+ WebPDecoderOptions options; // Decoding options
+} WebPDecoderConfig;
+
+// Internal, version-checked, entry point
+WEBP_EXTERN(int) WebPInitDecoderConfigInternal(WebPDecoderConfig*, int);
+
+// Initialize the configuration as empty. This function must always be
+// called first, unless WebPGetFeatures() is to be called.
+// Returns false in case of mismatched version.
+static WEBP_INLINE int WebPInitDecoderConfig(WebPDecoderConfig* config) {
+ return WebPInitDecoderConfigInternal(config, WEBP_DECODER_ABI_VERSION);
+}
+
+// Instantiate a new incremental decoder object with the requested
+// configuration. The bitstream can be passed using 'data' and 'data_size'
+// parameter, in which case the features will be parsed and stored into
+// config->input. Otherwise, 'data' can be NULL and no parsing will occur.
+// Note that 'config' can be NULL too, in which case a default configuration
+// is used.
+// The return WebPIDecoder object must always be deleted calling WebPIDelete().
+// Returns NULL in case of error (and config->status will then reflect
+// the error condition).
+WEBP_EXTERN(WebPIDecoder*) WebPIDecode(const uint8_t* data, size_t data_size,
+ WebPDecoderConfig* config);
+
+// Non-incremental version. This version decodes the full data at once, taking
+// 'config' into account. Returns decoding status (which should be VP8_STATUS_OK
+// if the decoding was successful).
+WEBP_EXTERN(VP8StatusCode) WebPDecode(const uint8_t* data, size_t data_size,
+ WebPDecoderConfig* config);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif /* WEBP_WEBP_DECODE_H_ */
diff --git a/drivers/webpold/dsp/cpu.c b/drivers/webpold/dsp/cpu.c
new file mode 100644
index 0000000000..0228734457
--- /dev/null
+++ b/drivers/webpold/dsp/cpu.c
@@ -0,0 +1,85 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// CPU detection
+//
+// Author: Christian Duvivier (cduvivier@google.com)
+
+#include "./dsp.h"
+
+#if defined(__ANDROID__)
+#include <cpu-features.h>
+#endif
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// SSE2 detection.
+//
+
+// apple/darwin gcc-4.0.1 defines __PIC__, but not __pic__ with -fPIC.
+#if (defined(__pic__) || defined(__PIC__)) && defined(__i386__)
+static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) {
+ __asm__ volatile (
+ "mov %%ebx, %%edi\n"
+ "cpuid\n"
+ "xchg %%edi, %%ebx\n"
+ : "=a"(cpu_info[0]), "=D"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
+ : "a"(info_type));
+}
+#elif defined(__i386__) || defined(__x86_64__)
+static WEBP_INLINE void GetCPUInfo(int cpu_info[4], int info_type) {
+ __asm__ volatile (
+ "cpuid\n"
+ : "=a"(cpu_info[0]), "=b"(cpu_info[1]), "=c"(cpu_info[2]), "=d"(cpu_info[3])
+ : "a"(info_type));
+}
+#elif defined(WEBP_MSC_SSE2)
+#define GetCPUInfo __cpuid
+#endif
+
+#if defined(__i386__) || defined(__x86_64__) || defined(WEBP_MSC_SSE2)
+static int x86CPUInfo(CPUFeature feature) {
+ int cpu_info[4];
+ GetCPUInfo(cpu_info, 1);
+ if (feature == kSSE2) {
+ return 0 != (cpu_info[3] & 0x04000000);
+ }
+ if (feature == kSSE3) {
+ return 0 != (cpu_info[2] & 0x00000001);
+ }
+ return 0;
+}
+VP8CPUInfo VP8GetCPUInfo = x86CPUInfo;
+#elif defined(WEBP_ANDROID_NEON)
+static int AndroidCPUInfo(CPUFeature feature) {
+ const AndroidCpuFamily cpu_family = android_getCpuFamily();
+ const uint64_t cpu_features = android_getCpuFeatures();
+ if (feature == kNEON) {
+ return (cpu_family == ANDROID_CPU_FAMILY_ARM &&
+ 0 != (cpu_features & ANDROID_CPU_ARM_FEATURE_NEON));
+ }
+ return 0;
+}
+VP8CPUInfo VP8GetCPUInfo = AndroidCPUInfo;
+#elif defined(__ARM_NEON__)
+// define a dummy function to enable turning off NEON at runtime by setting
+// VP8DecGetCPUInfo = NULL
+static int armCPUInfo(CPUFeature feature) {
+ (void)feature;
+ return 1;
+}
+VP8CPUInfo VP8GetCPUInfo = armCPUInfo;
+#else
+VP8CPUInfo VP8GetCPUInfo = NULL;
+#endif
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/dsp/dec.c b/drivers/webpold/dsp/dec.c
new file mode 100644
index 0000000000..9ae7b6fa76
--- /dev/null
+++ b/drivers/webpold/dsp/dec.c
@@ -0,0 +1,732 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Speed-critical decoding functions.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./dsp.h"
+#include "../dec/vp8i.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// run-time tables (~4k)
+
+static uint8_t abs0[255 + 255 + 1]; // abs(i)
+static uint8_t abs1[255 + 255 + 1]; // abs(i)>>1
+static int8_t sclip1[1020 + 1020 + 1]; // clips [-1020, 1020] to [-128, 127]
+static int8_t sclip2[112 + 112 + 1]; // clips [-112, 112] to [-16, 15]
+static uint8_t clip1[255 + 510 + 1]; // clips [-255,510] to [0,255]
+
+// We declare this variable 'volatile' to prevent instruction reordering
+// and make sure it's set to true _last_ (so as to be thread-safe)
+static volatile int tables_ok = 0;
+
+static void DspInitTables(void) {
+ if (!tables_ok) {
+ int i;
+ for (i = -255; i <= 255; ++i) {
+ abs0[255 + i] = (i < 0) ? -i : i;
+ abs1[255 + i] = abs0[255 + i] >> 1;
+ }
+ for (i = -1020; i <= 1020; ++i) {
+ sclip1[1020 + i] = (i < -128) ? -128 : (i > 127) ? 127 : i;
+ }
+ for (i = -112; i <= 112; ++i) {
+ sclip2[112 + i] = (i < -16) ? -16 : (i > 15) ? 15 : i;
+ }
+ for (i = -255; i <= 255 + 255; ++i) {
+ clip1[255 + i] = (i < 0) ? 0 : (i > 255) ? 255 : i;
+ }
+ tables_ok = 1;
+ }
+}
+
+static WEBP_INLINE uint8_t clip_8b(int v) {
+ return (!(v & ~0xff)) ? v : (v < 0) ? 0 : 255;
+}
+
+//------------------------------------------------------------------------------
+// Transforms (Paragraph 14.4)
+
+#define STORE(x, y, v) \
+ dst[x + y * BPS] = clip_8b(dst[x + y * BPS] + ((v) >> 3))
+
+static const int kC1 = 20091 + (1 << 16);
+static const int kC2 = 35468;
+#define MUL(a, b) (((a) * (b)) >> 16)
+
+static void TransformOne(const int16_t* in, uint8_t* dst) {
+ int C[4 * 4], *tmp;
+ int i;
+ tmp = C;
+ for (i = 0; i < 4; ++i) { // vertical pass
+ const int a = in[0] + in[8]; // [-4096, 4094]
+ const int b = in[0] - in[8]; // [-4095, 4095]
+ const int c = MUL(in[4], kC2) - MUL(in[12], kC1); // [-3783, 3783]
+ const int d = MUL(in[4], kC1) + MUL(in[12], kC2); // [-3785, 3781]
+ tmp[0] = a + d; // [-7881, 7875]
+ tmp[1] = b + c; // [-7878, 7878]
+ tmp[2] = b - c; // [-7878, 7878]
+ tmp[3] = a - d; // [-7877, 7879]
+ tmp += 4;
+ in++;
+ }
+ // Each pass is expanding the dynamic range by ~3.85 (upper bound).
+ // The exact value is (2. + (kC1 + kC2) / 65536).
+ // After the second pass, maximum interval is [-3794, 3794], assuming
+ // an input in [-2048, 2047] interval. We then need to add a dst value
+ // in the [0, 255] range.
+ // In the worst case scenario, the input to clip_8b() can be as large as
+ // [-60713, 60968].
+ tmp = C;
+ for (i = 0; i < 4; ++i) { // horizontal pass
+ const int dc = tmp[0] + 4;
+ const int a = dc + tmp[8];
+ const int b = dc - tmp[8];
+ const int c = MUL(tmp[4], kC2) - MUL(tmp[12], kC1);
+ const int d = MUL(tmp[4], kC1) + MUL(tmp[12], kC2);
+ STORE(0, 0, a + d);
+ STORE(1, 0, b + c);
+ STORE(2, 0, b - c);
+ STORE(3, 0, a - d);
+ tmp++;
+ dst += BPS;
+ }
+}
+#undef MUL
+
+static void TransformTwo(const int16_t* in, uint8_t* dst, int do_two) {
+ TransformOne(in, dst);
+ if (do_two) {
+ TransformOne(in + 16, dst + 4);
+ }
+}
+
+static void TransformUV(const int16_t* in, uint8_t* dst) {
+ VP8Transform(in + 0 * 16, dst, 1);
+ VP8Transform(in + 2 * 16, dst + 4 * BPS, 1);
+}
+
+static void TransformDC(const int16_t *in, uint8_t* dst) {
+ const int DC = in[0] + 4;
+ int i, j;
+ for (j = 0; j < 4; ++j) {
+ for (i = 0; i < 4; ++i) {
+ STORE(i, j, DC);
+ }
+ }
+}
+
+static void TransformDCUV(const int16_t* in, uint8_t* dst) {
+ if (in[0 * 16]) TransformDC(in + 0 * 16, dst);
+ if (in[1 * 16]) TransformDC(in + 1 * 16, dst + 4);
+ if (in[2 * 16]) TransformDC(in + 2 * 16, dst + 4 * BPS);
+ if (in[3 * 16]) TransformDC(in + 3 * 16, dst + 4 * BPS + 4);
+}
+
+#undef STORE
+
+//------------------------------------------------------------------------------
+// Paragraph 14.3
+
+static void TransformWHT(const int16_t* in, int16_t* out) {
+ int tmp[16];
+ int i;
+ for (i = 0; i < 4; ++i) {
+ const int a0 = in[0 + i] + in[12 + i];
+ const int a1 = in[4 + i] + in[ 8 + i];
+ const int a2 = in[4 + i] - in[ 8 + i];
+ const int a3 = in[0 + i] - in[12 + i];
+ tmp[0 + i] = a0 + a1;
+ tmp[8 + i] = a0 - a1;
+ tmp[4 + i] = a3 + a2;
+ tmp[12 + i] = a3 - a2;
+ }
+ for (i = 0; i < 4; ++i) {
+ const int dc = tmp[0 + i * 4] + 3; // w/ rounder
+ const int a0 = dc + tmp[3 + i * 4];
+ const int a1 = tmp[1 + i * 4] + tmp[2 + i * 4];
+ const int a2 = tmp[1 + i * 4] - tmp[2 + i * 4];
+ const int a3 = dc - tmp[3 + i * 4];
+ out[ 0] = (a0 + a1) >> 3;
+ out[16] = (a3 + a2) >> 3;
+ out[32] = (a0 - a1) >> 3;
+ out[48] = (a3 - a2) >> 3;
+ out += 64;
+ }
+}
+
+void (*VP8TransformWHT)(const int16_t* in, int16_t* out) = TransformWHT;
+
+//------------------------------------------------------------------------------
+// Intra predictions
+
+#define DST(x, y) dst[(x) + (y) * BPS]
+
+static WEBP_INLINE void TrueMotion(uint8_t *dst, int size) {
+ const uint8_t* top = dst - BPS;
+ const uint8_t* const clip0 = clip1 + 255 - top[-1];
+ int y;
+ for (y = 0; y < size; ++y) {
+ const uint8_t* const clip = clip0 + dst[-1];
+ int x;
+ for (x = 0; x < size; ++x) {
+ dst[x] = clip[top[x]];
+ }
+ dst += BPS;
+ }
+}
+static void TM4(uint8_t *dst) { TrueMotion(dst, 4); }
+static void TM8uv(uint8_t *dst) { TrueMotion(dst, 8); }
+static void TM16(uint8_t *dst) { TrueMotion(dst, 16); }
+
+//------------------------------------------------------------------------------
+// 16x16
+
+static void VE16(uint8_t *dst) { // vertical
+ int j;
+ for (j = 0; j < 16; ++j) {
+ memcpy(dst + j * BPS, dst - BPS, 16);
+ }
+}
+
+static void HE16(uint8_t *dst) { // horizontal
+ int j;
+ for (j = 16; j > 0; --j) {
+ memset(dst, dst[-1], 16);
+ dst += BPS;
+ }
+}
+
+static WEBP_INLINE void Put16(int v, uint8_t* dst) {
+ int j;
+ for (j = 0; j < 16; ++j) {
+ memset(dst + j * BPS, v, 16);
+ }
+}
+
+static void DC16(uint8_t *dst) { // DC
+ int DC = 16;
+ int j;
+ for (j = 0; j < 16; ++j) {
+ DC += dst[-1 + j * BPS] + dst[j - BPS];
+ }
+ Put16(DC >> 5, dst);
+}
+
+static void DC16NoTop(uint8_t *dst) { // DC with top samples not available
+ int DC = 8;
+ int j;
+ for (j = 0; j < 16; ++j) {
+ DC += dst[-1 + j * BPS];
+ }
+ Put16(DC >> 4, dst);
+}
+
+static void DC16NoLeft(uint8_t *dst) { // DC with left samples not available
+ int DC = 8;
+ int i;
+ for (i = 0; i < 16; ++i) {
+ DC += dst[i - BPS];
+ }
+ Put16(DC >> 4, dst);
+}
+
+static void DC16NoTopLeft(uint8_t *dst) { // DC with no top and left samples
+ Put16(0x80, dst);
+}
+
+//------------------------------------------------------------------------------
+// 4x4
+
+#define AVG3(a, b, c) (((a) + 2 * (b) + (c) + 2) >> 2)
+#define AVG2(a, b) (((a) + (b) + 1) >> 1)
+
+static void VE4(uint8_t *dst) { // vertical
+ const uint8_t* top = dst - BPS;
+ const uint8_t vals[4] = {
+ AVG3(top[-1], top[0], top[1]),
+ AVG3(top[ 0], top[1], top[2]),
+ AVG3(top[ 1], top[2], top[3]),
+ AVG3(top[ 2], top[3], top[4])
+ };
+ int i;
+ for (i = 0; i < 4; ++i) {
+ memcpy(dst + i * BPS, vals, sizeof(vals));
+ }
+}
+
+static void HE4(uint8_t *dst) { // horizontal
+ const int A = dst[-1 - BPS];
+ const int B = dst[-1];
+ const int C = dst[-1 + BPS];
+ const int D = dst[-1 + 2 * BPS];
+ const int E = dst[-1 + 3 * BPS];
+ *(uint32_t*)(dst + 0 * BPS) = 0x01010101U * AVG3(A, B, C);
+ *(uint32_t*)(dst + 1 * BPS) = 0x01010101U * AVG3(B, C, D);
+ *(uint32_t*)(dst + 2 * BPS) = 0x01010101U * AVG3(C, D, E);
+ *(uint32_t*)(dst + 3 * BPS) = 0x01010101U * AVG3(D, E, E);
+}
+
+static void DC4(uint8_t *dst) { // DC
+ uint32_t dc = 4;
+ int i;
+ for (i = 0; i < 4; ++i) dc += dst[i - BPS] + dst[-1 + i * BPS];
+ dc >>= 3;
+ for (i = 0; i < 4; ++i) memset(dst + i * BPS, dc, 4);
+}
+
+static void RD4(uint8_t *dst) { // Down-right
+ const int I = dst[-1 + 0 * BPS];
+ const int J = dst[-1 + 1 * BPS];
+ const int K = dst[-1 + 2 * BPS];
+ const int L = dst[-1 + 3 * BPS];
+ const int X = dst[-1 - BPS];
+ const int A = dst[0 - BPS];
+ const int B = dst[1 - BPS];
+ const int C = dst[2 - BPS];
+ const int D = dst[3 - BPS];
+ DST(0, 3) = AVG3(J, K, L);
+ DST(0, 2) = DST(1, 3) = AVG3(I, J, K);
+ DST(0, 1) = DST(1, 2) = DST(2, 3) = AVG3(X, I, J);
+ DST(0, 0) = DST(1, 1) = DST(2, 2) = DST(3, 3) = AVG3(A, X, I);
+ DST(1, 0) = DST(2, 1) = DST(3, 2) = AVG3(B, A, X);
+ DST(2, 0) = DST(3, 1) = AVG3(C, B, A);
+ DST(3, 0) = AVG3(D, C, B);
+}
+
+static void LD4(uint8_t *dst) { // Down-Left
+ const int A = dst[0 - BPS];
+ const int B = dst[1 - BPS];
+ const int C = dst[2 - BPS];
+ const int D = dst[3 - BPS];
+ const int E = dst[4 - BPS];
+ const int F = dst[5 - BPS];
+ const int G = dst[6 - BPS];
+ const int H = dst[7 - BPS];
+ DST(0, 0) = AVG3(A, B, C);
+ DST(1, 0) = DST(0, 1) = AVG3(B, C, D);
+ DST(2, 0) = DST(1, 1) = DST(0, 2) = AVG3(C, D, E);
+ DST(3, 0) = DST(2, 1) = DST(1, 2) = DST(0, 3) = AVG3(D, E, F);
+ DST(3, 1) = DST(2, 2) = DST(1, 3) = AVG3(E, F, G);
+ DST(3, 2) = DST(2, 3) = AVG3(F, G, H);
+ DST(3, 3) = AVG3(G, H, H);
+}
+
+static void VR4(uint8_t *dst) { // Vertical-Right
+ const int I = dst[-1 + 0 * BPS];
+ const int J = dst[-1 + 1 * BPS];
+ const int K = dst[-1 + 2 * BPS];
+ const int X = dst[-1 - BPS];
+ const int A = dst[0 - BPS];
+ const int B = dst[1 - BPS];
+ const int C = dst[2 - BPS];
+ const int D = dst[3 - BPS];
+ DST(0, 0) = DST(1, 2) = AVG2(X, A);
+ DST(1, 0) = DST(2, 2) = AVG2(A, B);
+ DST(2, 0) = DST(3, 2) = AVG2(B, C);
+ DST(3, 0) = AVG2(C, D);
+
+ DST(0, 3) = AVG3(K, J, I);
+ DST(0, 2) = AVG3(J, I, X);
+ DST(0, 1) = DST(1, 3) = AVG3(I, X, A);
+ DST(1, 1) = DST(2, 3) = AVG3(X, A, B);
+ DST(2, 1) = DST(3, 3) = AVG3(A, B, C);
+ DST(3, 1) = AVG3(B, C, D);
+}
+
+static void VL4(uint8_t *dst) { // Vertical-Left
+ const int A = dst[0 - BPS];
+ const int B = dst[1 - BPS];
+ const int C = dst[2 - BPS];
+ const int D = dst[3 - BPS];
+ const int E = dst[4 - BPS];
+ const int F = dst[5 - BPS];
+ const int G = dst[6 - BPS];
+ const int H = dst[7 - BPS];
+ DST(0, 0) = AVG2(A, B);
+ DST(1, 0) = DST(0, 2) = AVG2(B, C);
+ DST(2, 0) = DST(1, 2) = AVG2(C, D);
+ DST(3, 0) = DST(2, 2) = AVG2(D, E);
+
+ DST(0, 1) = AVG3(A, B, C);
+ DST(1, 1) = DST(0, 3) = AVG3(B, C, D);
+ DST(2, 1) = DST(1, 3) = AVG3(C, D, E);
+ DST(3, 1) = DST(2, 3) = AVG3(D, E, F);
+ DST(3, 2) = AVG3(E, F, G);
+ DST(3, 3) = AVG3(F, G, H);
+}
+
+static void HU4(uint8_t *dst) { // Horizontal-Up
+ const int I = dst[-1 + 0 * BPS];
+ const int J = dst[-1 + 1 * BPS];
+ const int K = dst[-1 + 2 * BPS];
+ const int L = dst[-1 + 3 * BPS];
+ DST(0, 0) = AVG2(I, J);
+ DST(2, 0) = DST(0, 1) = AVG2(J, K);
+ DST(2, 1) = DST(0, 2) = AVG2(K, L);
+ DST(1, 0) = AVG3(I, J, K);
+ DST(3, 0) = DST(1, 1) = AVG3(J, K, L);
+ DST(3, 1) = DST(1, 2) = AVG3(K, L, L);
+ DST(3, 2) = DST(2, 2) =
+ DST(0, 3) = DST(1, 3) = DST(2, 3) = DST(3, 3) = L;
+}
+
+static void HD4(uint8_t *dst) { // Horizontal-Down
+ const int I = dst[-1 + 0 * BPS];
+ const int J = dst[-1 + 1 * BPS];
+ const int K = dst[-1 + 2 * BPS];
+ const int L = dst[-1 + 3 * BPS];
+ const int X = dst[-1 - BPS];
+ const int A = dst[0 - BPS];
+ const int B = dst[1 - BPS];
+ const int C = dst[2 - BPS];
+
+ DST(0, 0) = DST(2, 1) = AVG2(I, X);
+ DST(0, 1) = DST(2, 2) = AVG2(J, I);
+ DST(0, 2) = DST(2, 3) = AVG2(K, J);
+ DST(0, 3) = AVG2(L, K);
+
+ DST(3, 0) = AVG3(A, B, C);
+ DST(2, 0) = AVG3(X, A, B);
+ DST(1, 0) = DST(3, 1) = AVG3(I, X, A);
+ DST(1, 1) = DST(3, 2) = AVG3(J, I, X);
+ DST(1, 2) = DST(3, 3) = AVG3(K, J, I);
+ DST(1, 3) = AVG3(L, K, J);
+}
+
+#undef DST
+#undef AVG3
+#undef AVG2
+
+//------------------------------------------------------------------------------
+// Chroma
+
+static void VE8uv(uint8_t *dst) { // vertical
+ int j;
+ for (j = 0; j < 8; ++j) {
+ memcpy(dst + j * BPS, dst - BPS, 8);
+ }
+}
+
+static void HE8uv(uint8_t *dst) { // horizontal
+ int j;
+ for (j = 0; j < 8; ++j) {
+ memset(dst, dst[-1], 8);
+ dst += BPS;
+ }
+}
+
+// helper for chroma-DC predictions
+static WEBP_INLINE void Put8x8uv(uint64_t v, uint8_t* dst) {
+ int j;
+ for (j = 0; j < 8; ++j) {
+ *(uint64_t*)(dst + j * BPS) = v;
+ }
+}
+
+static void DC8uv(uint8_t *dst) { // DC
+ int dc0 = 8;
+ int i;
+ for (i = 0; i < 8; ++i) {
+ dc0 += dst[i - BPS] + dst[-1 + i * BPS];
+ }
+ Put8x8uv((uint64_t)((dc0 >> 4) * 0x0101010101010101ULL), dst);
+}
+
+static void DC8uvNoLeft(uint8_t *dst) { // DC with no left samples
+ int dc0 = 4;
+ int i;
+ for (i = 0; i < 8; ++i) {
+ dc0 += dst[i - BPS];
+ }
+ Put8x8uv((uint64_t)((dc0 >> 3) * 0x0101010101010101ULL), dst);
+}
+
+static void DC8uvNoTop(uint8_t *dst) { // DC with no top samples
+ int dc0 = 4;
+ int i;
+ for (i = 0; i < 8; ++i) {
+ dc0 += dst[-1 + i * BPS];
+ }
+ Put8x8uv((uint64_t)((dc0 >> 3) * 0x0101010101010101ULL), dst);
+}
+
+static void DC8uvNoTopLeft(uint8_t *dst) { // DC with nothing
+ Put8x8uv(0x8080808080808080ULL, dst);
+}
+
+//------------------------------------------------------------------------------
+// default C implementations
+
+const VP8PredFunc VP8PredLuma4[NUM_BMODES] = {
+ DC4, TM4, VE4, HE4, RD4, VR4, LD4, VL4, HD4, HU4
+};
+
+const VP8PredFunc VP8PredLuma16[NUM_B_DC_MODES] = {
+ DC16, TM16, VE16, HE16,
+ DC16NoTop, DC16NoLeft, DC16NoTopLeft
+};
+
+const VP8PredFunc VP8PredChroma8[NUM_B_DC_MODES] = {
+ DC8uv, TM8uv, VE8uv, HE8uv,
+ DC8uvNoTop, DC8uvNoLeft, DC8uvNoTopLeft
+};
+
+//------------------------------------------------------------------------------
+// Edge filtering functions
+
+// 4 pixels in, 2 pixels out
+static WEBP_INLINE void do_filter2(uint8_t* p, int step) {
+ const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
+ const int a = 3 * (q0 - p0) + sclip1[1020 + p1 - q1];
+ const int a1 = sclip2[112 + ((a + 4) >> 3)];
+ const int a2 = sclip2[112 + ((a + 3) >> 3)];
+ p[-step] = clip1[255 + p0 + a2];
+ p[ 0] = clip1[255 + q0 - a1];
+}
+
+// 4 pixels in, 4 pixels out
+static WEBP_INLINE void do_filter4(uint8_t* p, int step) {
+ const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
+ const int a = 3 * (q0 - p0);
+ const int a1 = sclip2[112 + ((a + 4) >> 3)];
+ const int a2 = sclip2[112 + ((a + 3) >> 3)];
+ const int a3 = (a1 + 1) >> 1;
+ p[-2*step] = clip1[255 + p1 + a3];
+ p[- step] = clip1[255 + p0 + a2];
+ p[ 0] = clip1[255 + q0 - a1];
+ p[ step] = clip1[255 + q1 - a3];
+}
+
+// 6 pixels in, 6 pixels out
+static WEBP_INLINE void do_filter6(uint8_t* p, int step) {
+ const int p2 = p[-3*step], p1 = p[-2*step], p0 = p[-step];
+ const int q0 = p[0], q1 = p[step], q2 = p[2*step];
+ const int a = sclip1[1020 + 3 * (q0 - p0) + sclip1[1020 + p1 - q1]];
+ const int a1 = (27 * a + 63) >> 7; // eq. to ((3 * a + 7) * 9) >> 7
+ const int a2 = (18 * a + 63) >> 7; // eq. to ((2 * a + 7) * 9) >> 7
+ const int a3 = (9 * a + 63) >> 7; // eq. to ((1 * a + 7) * 9) >> 7
+ p[-3*step] = clip1[255 + p2 + a3];
+ p[-2*step] = clip1[255 + p1 + a2];
+ p[- step] = clip1[255 + p0 + a1];
+ p[ 0] = clip1[255 + q0 - a1];
+ p[ step] = clip1[255 + q1 - a2];
+ p[ 2*step] = clip1[255 + q2 - a3];
+}
+
+static WEBP_INLINE int hev(const uint8_t* p, int step, int thresh) {
+ const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
+ return (abs0[255 + p1 - p0] > thresh) || (abs0[255 + q1 - q0] > thresh);
+}
+
+static WEBP_INLINE int needs_filter(const uint8_t* p, int step, int thresh) {
+ const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
+ return (2 * abs0[255 + p0 - q0] + abs1[255 + p1 - q1]) <= thresh;
+}
+
+static WEBP_INLINE int needs_filter2(const uint8_t* p,
+ int step, int t, int it) {
+ const int p3 = p[-4*step], p2 = p[-3*step], p1 = p[-2*step], p0 = p[-step];
+ const int q0 = p[0], q1 = p[step], q2 = p[2*step], q3 = p[3*step];
+ if ((2 * abs0[255 + p0 - q0] + abs1[255 + p1 - q1]) > t)
+ return 0;
+ return abs0[255 + p3 - p2] <= it && abs0[255 + p2 - p1] <= it &&
+ abs0[255 + p1 - p0] <= it && abs0[255 + q3 - q2] <= it &&
+ abs0[255 + q2 - q1] <= it && abs0[255 + q1 - q0] <= it;
+}
+
+//------------------------------------------------------------------------------
+// Simple In-loop filtering (Paragraph 15.2)
+
+static void SimpleVFilter16(uint8_t* p, int stride, int thresh) {
+ int i;
+ for (i = 0; i < 16; ++i) {
+ if (needs_filter(p + i, stride, thresh)) {
+ do_filter2(p + i, stride);
+ }
+ }
+}
+
+static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
+ int i;
+ for (i = 0; i < 16; ++i) {
+ if (needs_filter(p + i * stride, 1, thresh)) {
+ do_filter2(p + i * stride, 1);
+ }
+ }
+}
+
+static void SimpleVFilter16i(uint8_t* p, int stride, int thresh) {
+ int k;
+ for (k = 3; k > 0; --k) {
+ p += 4 * stride;
+ SimpleVFilter16(p, stride, thresh);
+ }
+}
+
+static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) {
+ int k;
+ for (k = 3; k > 0; --k) {
+ p += 4;
+ SimpleHFilter16(p, stride, thresh);
+ }
+}
+
+//------------------------------------------------------------------------------
+// Complex In-loop filtering (Paragraph 15.3)
+
+static WEBP_INLINE void FilterLoop26(uint8_t* p,
+ int hstride, int vstride, int size,
+ int thresh, int ithresh, int hev_thresh) {
+ while (size-- > 0) {
+ if (needs_filter2(p, hstride, thresh, ithresh)) {
+ if (hev(p, hstride, hev_thresh)) {
+ do_filter2(p, hstride);
+ } else {
+ do_filter6(p, hstride);
+ }
+ }
+ p += vstride;
+ }
+}
+
+static WEBP_INLINE void FilterLoop24(uint8_t* p,
+ int hstride, int vstride, int size,
+ int thresh, int ithresh, int hev_thresh) {
+ while (size-- > 0) {
+ if (needs_filter2(p, hstride, thresh, ithresh)) {
+ if (hev(p, hstride, hev_thresh)) {
+ do_filter2(p, hstride);
+ } else {
+ do_filter4(p, hstride);
+ }
+ }
+ p += vstride;
+ }
+}
+
+// on macroblock edges
+static void VFilter16(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop26(p, stride, 1, 16, thresh, ithresh, hev_thresh);
+}
+
+static void HFilter16(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop26(p, 1, stride, 16, thresh, ithresh, hev_thresh);
+}
+
+// on three inner edges
+static void VFilter16i(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ int k;
+ for (k = 3; k > 0; --k) {
+ p += 4 * stride;
+ FilterLoop24(p, stride, 1, 16, thresh, ithresh, hev_thresh);
+ }
+}
+
+static void HFilter16i(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ int k;
+ for (k = 3; k > 0; --k) {
+ p += 4;
+ FilterLoop24(p, 1, stride, 16, thresh, ithresh, hev_thresh);
+ }
+}
+
+// 8-pixels wide variant, for chroma filtering
+static void VFilter8(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop26(u, stride, 1, 8, thresh, ithresh, hev_thresh);
+ FilterLoop26(v, stride, 1, 8, thresh, ithresh, hev_thresh);
+}
+
+static void HFilter8(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop26(u, 1, stride, 8, thresh, ithresh, hev_thresh);
+ FilterLoop26(v, 1, stride, 8, thresh, ithresh, hev_thresh);
+}
+
+static void VFilter8i(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop24(u + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh);
+ FilterLoop24(v + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh);
+}
+
+static void HFilter8i(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop24(u + 4, 1, stride, 8, thresh, ithresh, hev_thresh);
+ FilterLoop24(v + 4, 1, stride, 8, thresh, ithresh, hev_thresh);
+}
+
+//------------------------------------------------------------------------------
+
+VP8DecIdct2 VP8Transform;
+VP8DecIdct VP8TransformUV;
+VP8DecIdct VP8TransformDC;
+VP8DecIdct VP8TransformDCUV;
+
+VP8LumaFilterFunc VP8VFilter16;
+VP8LumaFilterFunc VP8HFilter16;
+VP8ChromaFilterFunc VP8VFilter8;
+VP8ChromaFilterFunc VP8HFilter8;
+VP8LumaFilterFunc VP8VFilter16i;
+VP8LumaFilterFunc VP8HFilter16i;
+VP8ChromaFilterFunc VP8VFilter8i;
+VP8ChromaFilterFunc VP8HFilter8i;
+VP8SimpleFilterFunc VP8SimpleVFilter16;
+VP8SimpleFilterFunc VP8SimpleHFilter16;
+VP8SimpleFilterFunc VP8SimpleVFilter16i;
+VP8SimpleFilterFunc VP8SimpleHFilter16i;
+
+extern void VP8DspInitSSE2(void);
+extern void VP8DspInitNEON(void);
+
+void VP8DspInit(void) {
+ DspInitTables();
+
+ VP8Transform = TransformTwo;
+ VP8TransformUV = TransformUV;
+ VP8TransformDC = TransformDC;
+ VP8TransformDCUV = TransformDCUV;
+
+ VP8VFilter16 = VFilter16;
+ VP8HFilter16 = HFilter16;
+ VP8VFilter8 = VFilter8;
+ VP8HFilter8 = HFilter8;
+ VP8VFilter16i = VFilter16i;
+ VP8HFilter16i = HFilter16i;
+ VP8VFilter8i = VFilter8i;
+ VP8HFilter8i = HFilter8i;
+ VP8SimpleVFilter16 = SimpleVFilter16;
+ VP8SimpleHFilter16 = SimpleHFilter16;
+ VP8SimpleVFilter16i = SimpleVFilter16i;
+ VP8SimpleHFilter16i = SimpleHFilter16i;
+
+ // If defined, use CPUInfo() to overwrite some pointers with faster versions.
+ if (VP8GetCPUInfo) {
+#if defined(WEBP_USE_SSE2)
+ if (VP8GetCPUInfo(kSSE2)) {
+ VP8DspInitSSE2();
+ }
+#elif defined(WEBP_USE_NEON)
+ if (VP8GetCPUInfo(kNEON)) {
+ VP8DspInitNEON();
+ }
+#endif
+ }
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/dsp/dec_neon.c b/drivers/webpold/dsp/dec_neon.c
new file mode 100644
index 0000000000..ec824b790b
--- /dev/null
+++ b/drivers/webpold/dsp/dec_neon.c
@@ -0,0 +1,329 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// ARM NEON version of dsp functions and loop filtering.
+//
+// Authors: Somnath Banerjee (somnath@google.com)
+// Johann Koenig (johannkoenig@google.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_NEON)
+
+#include "../dec/vp8i.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define QRegs "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7", \
+ "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15"
+
+#define FLIP_SIGN_BIT2(a, b, s) \
+ "veor " #a "," #a "," #s " \n" \
+ "veor " #b "," #b "," #s " \n" \
+
+#define FLIP_SIGN_BIT4(a, b, c, d, s) \
+ FLIP_SIGN_BIT2(a, b, s) \
+ FLIP_SIGN_BIT2(c, d, s) \
+
+#define NEEDS_FILTER(p1, p0, q0, q1, thresh, mask) \
+ "vabd.u8 q15," #p0 "," #q0 " \n" /* abs(p0 - q0) */ \
+ "vabd.u8 q14," #p1 "," #q1 " \n" /* abs(p1 - q1) */ \
+ "vqadd.u8 q15, q15, q15 \n" /* abs(p0 - q0) * 2 */ \
+ "vshr.u8 q14, q14, #1 \n" /* abs(p1 - q1) / 2 */ \
+ "vqadd.u8 q15, q15, q14 \n" /* abs(p0 - q0) * 2 + abs(p1 - q1) / 2 */ \
+ "vdup.8 q14, " #thresh " \n" \
+ "vcge.u8 " #mask ", q14, q15 \n" /* mask <= thresh */
+
+#define GET_BASE_DELTA(p1, p0, q0, q1, o) \
+ "vqsub.s8 q15," #q0 "," #p0 " \n" /* (q0 - p0) */ \
+ "vqsub.s8 " #o "," #p1 "," #q1 " \n" /* (p1 - q1) */ \
+ "vqadd.s8 " #o "," #o ", q15 \n" /* (p1 - q1) + 1 * (p0 - q0) */ \
+ "vqadd.s8 " #o "," #o ", q15 \n" /* (p1 - q1) + 2 * (p0 - q0) */ \
+ "vqadd.s8 " #o "," #o ", q15 \n" /* (p1 - q1) + 3 * (p0 - q0) */
+
+#define DO_SIMPLE_FILTER(p0, q0, fl) \
+ "vmov.i8 q15, #0x03 \n" \
+ "vqadd.s8 q15, q15, " #fl " \n" /* filter1 = filter + 3 */ \
+ "vshr.s8 q15, q15, #3 \n" /* filter1 >> 3 */ \
+ "vqadd.s8 " #p0 "," #p0 ", q15 \n" /* p0 += filter1 */ \
+ \
+ "vmov.i8 q15, #0x04 \n" \
+ "vqadd.s8 q15, q15, " #fl " \n" /* filter1 = filter + 4 */ \
+ "vshr.s8 q15, q15, #3 \n" /* filter2 >> 3 */ \
+ "vqsub.s8 " #q0 "," #q0 ", q15 \n" /* q0 -= filter2 */
+
+// Applies filter on 2 pixels (p0 and q0)
+#define DO_FILTER2(p1, p0, q0, q1, thresh) \
+ NEEDS_FILTER(p1, p0, q0, q1, thresh, q9) /* filter mask in q9 */ \
+ "vmov.i8 q10, #0x80 \n" /* sign bit */ \
+ FLIP_SIGN_BIT4(p1, p0, q0, q1, q10) /* convert to signed value */ \
+ GET_BASE_DELTA(p1, p0, q0, q1, q11) /* get filter level */ \
+ "vand q9, q9, q11 \n" /* apply filter mask */ \
+ DO_SIMPLE_FILTER(p0, q0, q9) /* apply filter */ \
+ FLIP_SIGN_BIT2(p0, q0, q10)
+
+// Load/Store vertical edge
+#define LOAD8x4(c1, c2, c3, c4, b1, b2, stride) \
+ "vld4.8 {" #c1"[0], " #c2"[0], " #c3"[0], " #c4"[0]}," #b1 "," #stride"\n" \
+ "vld4.8 {" #c1"[1], " #c2"[1], " #c3"[1], " #c4"[1]}," #b2 "," #stride"\n" \
+ "vld4.8 {" #c1"[2], " #c2"[2], " #c3"[2], " #c4"[2]}," #b1 "," #stride"\n" \
+ "vld4.8 {" #c1"[3], " #c2"[3], " #c3"[3], " #c4"[3]}," #b2 "," #stride"\n" \
+ "vld4.8 {" #c1"[4], " #c2"[4], " #c3"[4], " #c4"[4]}," #b1 "," #stride"\n" \
+ "vld4.8 {" #c1"[5], " #c2"[5], " #c3"[5], " #c4"[5]}," #b2 "," #stride"\n" \
+ "vld4.8 {" #c1"[6], " #c2"[6], " #c3"[6], " #c4"[6]}," #b1 "," #stride"\n" \
+ "vld4.8 {" #c1"[7], " #c2"[7], " #c3"[7], " #c4"[7]}," #b2 "," #stride"\n"
+
+#define STORE8x2(c1, c2, p,stride) \
+ "vst2.8 {" #c1"[0], " #c2"[0]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1"[1], " #c2"[1]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1"[2], " #c2"[2]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1"[3], " #c2"[3]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1"[4], " #c2"[4]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1"[5], " #c2"[5]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1"[6], " #c2"[6]}," #p "," #stride " \n" \
+ "vst2.8 {" #c1"[7], " #c2"[7]}," #p "," #stride " \n"
+
+//-----------------------------------------------------------------------------
+// Simple In-loop filtering (Paragraph 15.2)
+
+static void SimpleVFilter16NEON(uint8_t* p, int stride, int thresh) {
+ __asm__ volatile (
+ "sub %[p], %[p], %[stride], lsl #1 \n" // p -= 2 * stride
+
+ "vld1.u8 {q1}, [%[p]], %[stride] \n" // p1
+ "vld1.u8 {q2}, [%[p]], %[stride] \n" // p0
+ "vld1.u8 {q3}, [%[p]], %[stride] \n" // q0
+ "vld1.u8 {q4}, [%[p]] \n" // q1
+
+ DO_FILTER2(q1, q2, q3, q4, %[thresh])
+
+ "sub %[p], %[p], %[stride], lsl #1 \n" // p -= 2 * stride
+
+ "vst1.u8 {q2}, [%[p]], %[stride] \n" // store op0
+ "vst1.u8 {q3}, [%[p]] \n" // store oq0
+ : [p] "+r"(p)
+ : [stride] "r"(stride), [thresh] "r"(thresh)
+ : "memory", QRegs
+ );
+}
+
+static void SimpleHFilter16NEON(uint8_t* p, int stride, int thresh) {
+ __asm__ volatile (
+ "sub r4, %[p], #2 \n" // base1 = p - 2
+ "lsl r6, %[stride], #1 \n" // r6 = 2 * stride
+ "add r5, r4, %[stride] \n" // base2 = base1 + stride
+
+ LOAD8x4(d2, d3, d4, d5, [r4], [r5], r6)
+ LOAD8x4(d6, d7, d8, d9, [r4], [r5], r6)
+ "vswp d3, d6 \n" // p1:q1 p0:q3
+ "vswp d5, d8 \n" // q0:q2 q1:q4
+ "vswp q2, q3 \n" // p1:q1 p0:q2 q0:q3 q1:q4
+
+ DO_FILTER2(q1, q2, q3, q4, %[thresh])
+
+ "sub %[p], %[p], #1 \n" // p - 1
+
+ "vswp d5, d6 \n"
+ STORE8x2(d4, d5, [%[p]], %[stride])
+ STORE8x2(d6, d7, [%[p]], %[stride])
+
+ : [p] "+r"(p)
+ : [stride] "r"(stride), [thresh] "r"(thresh)
+ : "memory", "r4", "r5", "r6", QRegs
+ );
+}
+
+static void SimpleVFilter16iNEON(uint8_t* p, int stride, int thresh) {
+ int k;
+ for (k = 3; k > 0; --k) {
+ p += 4 * stride;
+ SimpleVFilter16NEON(p, stride, thresh);
+ }
+}
+
+static void SimpleHFilter16iNEON(uint8_t* p, int stride, int thresh) {
+ int k;
+ for (k = 3; k > 0; --k) {
+ p += 4;
+ SimpleHFilter16NEON(p, stride, thresh);
+ }
+}
+
+static void TransformOneNEON(const int16_t *in, uint8_t *dst) {
+ const int kBPS = BPS;
+ const int16_t constants[] = {20091, 17734, 0, 0};
+ /* kC1, kC2. Padded because vld1.16 loads 8 bytes
+ * Technically these are unsigned but vqdmulh is only available in signed.
+ * vqdmulh returns high half (effectively >> 16) but also doubles the value,
+ * changing the >> 16 to >> 15 and requiring an additional >> 1.
+ * We use this to our advantage with kC2. The canonical value is 35468.
+ * However, the high bit is set so treating it as signed will give incorrect
+ * results. We avoid this by down shifting by 1 here to clear the highest bit.
+ * Combined with the doubling effect of vqdmulh we get >> 16.
+ * This can not be applied to kC1 because the lowest bit is set. Down shifting
+ * the constant would reduce precision.
+ */
+
+ /* libwebp uses a trick to avoid some extra addition that libvpx does.
+ * Instead of:
+ * temp2 = ip[12] + ((ip[12] * cospi8sqrt2minus1) >> 16);
+ * libwebp adds 1 << 16 to cospi8sqrt2minus1 (kC1). However, this causes the
+ * same issue with kC1 and vqdmulh that we work around by down shifting kC2
+ */
+
+ /* Adapted from libvpx: vp8/common/arm/neon/shortidct4x4llm_neon.asm */
+ __asm__ volatile (
+ "vld1.16 {q1, q2}, [%[in]] \n"
+ "vld1.16 {d0}, [%[constants]] \n"
+
+ /* d2: in[0]
+ * d3: in[8]
+ * d4: in[4]
+ * d5: in[12]
+ */
+ "vswp d3, d4 \n"
+
+ /* q8 = {in[4], in[12]} * kC1 * 2 >> 16
+ * q9 = {in[4], in[12]} * kC2 >> 16
+ */
+ "vqdmulh.s16 q8, q2, d0[0] \n"
+ "vqdmulh.s16 q9, q2, d0[1] \n"
+
+ /* d22 = a = in[0] + in[8]
+ * d23 = b = in[0] - in[8]
+ */
+ "vqadd.s16 d22, d2, d3 \n"
+ "vqsub.s16 d23, d2, d3 \n"
+
+ /* The multiplication should be x * kC1 >> 16
+ * However, with vqdmulh we get x * kC1 * 2 >> 16
+ * (multiply, double, return high half)
+ * We avoided this in kC2 by pre-shifting the constant.
+ * q8 = in[4]/[12] * kC1 >> 16
+ */
+ "vshr.s16 q8, q8, #1 \n"
+
+ /* Add {in[4], in[12]} back after the multiplication. This is handled by
+ * adding 1 << 16 to kC1 in the libwebp C code.
+ */
+ "vqadd.s16 q8, q2, q8 \n"
+
+ /* d20 = c = in[4]*kC2 - in[12]*kC1
+ * d21 = d = in[4]*kC1 + in[12]*kC2
+ */
+ "vqsub.s16 d20, d18, d17 \n"
+ "vqadd.s16 d21, d19, d16 \n"
+
+ /* d2 = tmp[0] = a + d
+ * d3 = tmp[1] = b + c
+ * d4 = tmp[2] = b - c
+ * d5 = tmp[3] = a - d
+ */
+ "vqadd.s16 d2, d22, d21 \n"
+ "vqadd.s16 d3, d23, d20 \n"
+ "vqsub.s16 d4, d23, d20 \n"
+ "vqsub.s16 d5, d22, d21 \n"
+
+ "vzip.16 q1, q2 \n"
+ "vzip.16 q1, q2 \n"
+
+ "vswp d3, d4 \n"
+
+ /* q8 = {tmp[4], tmp[12]} * kC1 * 2 >> 16
+ * q9 = {tmp[4], tmp[12]} * kC2 >> 16
+ */
+ "vqdmulh.s16 q8, q2, d0[0] \n"
+ "vqdmulh.s16 q9, q2, d0[1] \n"
+
+ /* d22 = a = tmp[0] + tmp[8]
+ * d23 = b = tmp[0] - tmp[8]
+ */
+ "vqadd.s16 d22, d2, d3 \n"
+ "vqsub.s16 d23, d2, d3 \n"
+
+ /* See long winded explanations prior */
+ "vshr.s16 q8, q8, #1 \n"
+ "vqadd.s16 q8, q2, q8 \n"
+
+ /* d20 = c = in[4]*kC2 - in[12]*kC1
+ * d21 = d = in[4]*kC1 + in[12]*kC2
+ */
+ "vqsub.s16 d20, d18, d17 \n"
+ "vqadd.s16 d21, d19, d16 \n"
+
+ /* d2 = tmp[0] = a + d
+ * d3 = tmp[1] = b + c
+ * d4 = tmp[2] = b - c
+ * d5 = tmp[3] = a - d
+ */
+ "vqadd.s16 d2, d22, d21 \n"
+ "vqadd.s16 d3, d23, d20 \n"
+ "vqsub.s16 d4, d23, d20 \n"
+ "vqsub.s16 d5, d22, d21 \n"
+
+ "vld1.32 d6[0], [%[dst]], %[kBPS] \n"
+ "vld1.32 d6[1], [%[dst]], %[kBPS] \n"
+ "vld1.32 d7[0], [%[dst]], %[kBPS] \n"
+ "vld1.32 d7[1], [%[dst]], %[kBPS] \n"
+
+ "sub %[dst], %[dst], %[kBPS], lsl #2 \n"
+
+ /* (val) + 4 >> 3 */
+ "vrshr.s16 d2, d2, #3 \n"
+ "vrshr.s16 d3, d3, #3 \n"
+ "vrshr.s16 d4, d4, #3 \n"
+ "vrshr.s16 d5, d5, #3 \n"
+
+ "vzip.16 q1, q2 \n"
+ "vzip.16 q1, q2 \n"
+
+ /* Must accumulate before saturating */
+ "vmovl.u8 q8, d6 \n"
+ "vmovl.u8 q9, d7 \n"
+
+ "vqadd.s16 q1, q1, q8 \n"
+ "vqadd.s16 q2, q2, q9 \n"
+
+ "vqmovun.s16 d0, q1 \n"
+ "vqmovun.s16 d1, q2 \n"
+
+ "vst1.32 d0[0], [%[dst]], %[kBPS] \n"
+ "vst1.32 d0[1], [%[dst]], %[kBPS] \n"
+ "vst1.32 d1[0], [%[dst]], %[kBPS] \n"
+ "vst1.32 d1[1], [%[dst]] \n"
+
+ : [in] "+r"(in), [dst] "+r"(dst) /* modified registers */
+ : [kBPS] "r"(kBPS), [constants] "r"(constants) /* constants */
+ : "memory", "q0", "q1", "q2", "q8", "q9", "q10", "q11" /* clobbered */
+ );
+}
+
+static void TransformTwoNEON(const int16_t* in, uint8_t* dst, int do_two) {
+ TransformOneNEON(in, dst);
+ if (do_two) {
+ TransformOneNEON(in + 16, dst + 4);
+ }
+}
+
+extern void VP8DspInitNEON(void);
+
+void VP8DspInitNEON(void) {
+ VP8Transform = TransformTwoNEON;
+
+ VP8SimpleVFilter16 = SimpleVFilter16NEON;
+ VP8SimpleHFilter16 = SimpleHFilter16NEON;
+ VP8SimpleVFilter16i = SimpleVFilter16iNEON;
+ VP8SimpleHFilter16i = SimpleHFilter16iNEON;
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif // WEBP_USE_NEON
diff --git a/drivers/webpold/dsp/dec_sse2.c b/drivers/webpold/dsp/dec_sse2.c
new file mode 100644
index 0000000000..472b68ecb8
--- /dev/null
+++ b/drivers/webpold/dsp/dec_sse2.c
@@ -0,0 +1,903 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// SSE2 version of some decoding functions (idct, loop filtering).
+//
+// Author: somnath@google.com (Somnath Banerjee)
+// cduvivier@google.com (Christian Duvivier)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_SSE2)
+
+#include <emmintrin.h>
+#include "../dec/vp8i.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// Transforms (Paragraph 14.4)
+
+static void TransformSSE2(const int16_t* in, uint8_t* dst, int do_two) {
+ // This implementation makes use of 16-bit fixed point versions of two
+ // multiply constants:
+ // K1 = sqrt(2) * cos (pi/8) ~= 85627 / 2^16
+ // K2 = sqrt(2) * sin (pi/8) ~= 35468 / 2^16
+ //
+ // To be able to use signed 16-bit integers, we use the following trick to
+ // have constants within range:
+ // - Associated constants are obtained by subtracting the 16-bit fixed point
+ // version of one:
+ // k = K - (1 << 16) => K = k + (1 << 16)
+ // K1 = 85267 => k1 = 20091
+ // K2 = 35468 => k2 = -30068
+ // - The multiplication of a variable by a constant become the sum of the
+ // variable and the multiplication of that variable by the associated
+ // constant:
+ // (x * K) >> 16 = (x * (k + (1 << 16))) >> 16 = ((x * k ) >> 16) + x
+ const __m128i k1 = _mm_set1_epi16(20091);
+ const __m128i k2 = _mm_set1_epi16(-30068);
+ __m128i T0, T1, T2, T3;
+
+ // Load and concatenate the transform coefficients (we'll do two transforms
+ // in parallel). In the case of only one transform, the second half of the
+ // vectors will just contain random value we'll never use nor store.
+ __m128i in0, in1, in2, in3;
+ {
+ in0 = _mm_loadl_epi64((__m128i*)&in[0]);
+ in1 = _mm_loadl_epi64((__m128i*)&in[4]);
+ in2 = _mm_loadl_epi64((__m128i*)&in[8]);
+ in3 = _mm_loadl_epi64((__m128i*)&in[12]);
+ // a00 a10 a20 a30 x x x x
+ // a01 a11 a21 a31 x x x x
+ // a02 a12 a22 a32 x x x x
+ // a03 a13 a23 a33 x x x x
+ if (do_two) {
+ const __m128i inB0 = _mm_loadl_epi64((__m128i*)&in[16]);
+ const __m128i inB1 = _mm_loadl_epi64((__m128i*)&in[20]);
+ const __m128i inB2 = _mm_loadl_epi64((__m128i*)&in[24]);
+ const __m128i inB3 = _mm_loadl_epi64((__m128i*)&in[28]);
+ in0 = _mm_unpacklo_epi64(in0, inB0);
+ in1 = _mm_unpacklo_epi64(in1, inB1);
+ in2 = _mm_unpacklo_epi64(in2, inB2);
+ in3 = _mm_unpacklo_epi64(in3, inB3);
+ // a00 a10 a20 a30 b00 b10 b20 b30
+ // a01 a11 a21 a31 b01 b11 b21 b31
+ // a02 a12 a22 a32 b02 b12 b22 b32
+ // a03 a13 a23 a33 b03 b13 b23 b33
+ }
+ }
+
+ // Vertical pass and subsequent transpose.
+ {
+ // First pass, c and d calculations are longer because of the "trick"
+ // multiplications.
+ const __m128i a = _mm_add_epi16(in0, in2);
+ const __m128i b = _mm_sub_epi16(in0, in2);
+ // c = MUL(in1, K2) - MUL(in3, K1) = MUL(in1, k2) - MUL(in3, k1) + in1 - in3
+ const __m128i c1 = _mm_mulhi_epi16(in1, k2);
+ const __m128i c2 = _mm_mulhi_epi16(in3, k1);
+ const __m128i c3 = _mm_sub_epi16(in1, in3);
+ const __m128i c4 = _mm_sub_epi16(c1, c2);
+ const __m128i c = _mm_add_epi16(c3, c4);
+ // d = MUL(in1, K1) + MUL(in3, K2) = MUL(in1, k1) + MUL(in3, k2) + in1 + in3
+ const __m128i d1 = _mm_mulhi_epi16(in1, k1);
+ const __m128i d2 = _mm_mulhi_epi16(in3, k2);
+ const __m128i d3 = _mm_add_epi16(in1, in3);
+ const __m128i d4 = _mm_add_epi16(d1, d2);
+ const __m128i d = _mm_add_epi16(d3, d4);
+
+ // Second pass.
+ const __m128i tmp0 = _mm_add_epi16(a, d);
+ const __m128i tmp1 = _mm_add_epi16(b, c);
+ const __m128i tmp2 = _mm_sub_epi16(b, c);
+ const __m128i tmp3 = _mm_sub_epi16(a, d);
+
+ // Transpose the two 4x4.
+ // a00 a01 a02 a03 b00 b01 b02 b03
+ // a10 a11 a12 a13 b10 b11 b12 b13
+ // a20 a21 a22 a23 b20 b21 b22 b23
+ // a30 a31 a32 a33 b30 b31 b32 b33
+ const __m128i transpose0_0 = _mm_unpacklo_epi16(tmp0, tmp1);
+ const __m128i transpose0_1 = _mm_unpacklo_epi16(tmp2, tmp3);
+ const __m128i transpose0_2 = _mm_unpackhi_epi16(tmp0, tmp1);
+ const __m128i transpose0_3 = _mm_unpackhi_epi16(tmp2, tmp3);
+ // a00 a10 a01 a11 a02 a12 a03 a13
+ // a20 a30 a21 a31 a22 a32 a23 a33
+ // b00 b10 b01 b11 b02 b12 b03 b13
+ // b20 b30 b21 b31 b22 b32 b23 b33
+ const __m128i transpose1_0 = _mm_unpacklo_epi32(transpose0_0, transpose0_1);
+ const __m128i transpose1_1 = _mm_unpacklo_epi32(transpose0_2, transpose0_3);
+ const __m128i transpose1_2 = _mm_unpackhi_epi32(transpose0_0, transpose0_1);
+ const __m128i transpose1_3 = _mm_unpackhi_epi32(transpose0_2, transpose0_3);
+ // a00 a10 a20 a30 a01 a11 a21 a31
+ // b00 b10 b20 b30 b01 b11 b21 b31
+ // a02 a12 a22 a32 a03 a13 a23 a33
+ // b02 b12 a22 b32 b03 b13 b23 b33
+ T0 = _mm_unpacklo_epi64(transpose1_0, transpose1_1);
+ T1 = _mm_unpackhi_epi64(transpose1_0, transpose1_1);
+ T2 = _mm_unpacklo_epi64(transpose1_2, transpose1_3);
+ T3 = _mm_unpackhi_epi64(transpose1_2, transpose1_3);
+ // a00 a10 a20 a30 b00 b10 b20 b30
+ // a01 a11 a21 a31 b01 b11 b21 b31
+ // a02 a12 a22 a32 b02 b12 b22 b32
+ // a03 a13 a23 a33 b03 b13 b23 b33
+ }
+
+ // Horizontal pass and subsequent transpose.
+ {
+ // First pass, c and d calculations are longer because of the "trick"
+ // multiplications.
+ const __m128i four = _mm_set1_epi16(4);
+ const __m128i dc = _mm_add_epi16(T0, four);
+ const __m128i a = _mm_add_epi16(dc, T2);
+ const __m128i b = _mm_sub_epi16(dc, T2);
+ // c = MUL(T1, K2) - MUL(T3, K1) = MUL(T1, k2) - MUL(T3, k1) + T1 - T3
+ const __m128i c1 = _mm_mulhi_epi16(T1, k2);
+ const __m128i c2 = _mm_mulhi_epi16(T3, k1);
+ const __m128i c3 = _mm_sub_epi16(T1, T3);
+ const __m128i c4 = _mm_sub_epi16(c1, c2);
+ const __m128i c = _mm_add_epi16(c3, c4);
+ // d = MUL(T1, K1) + MUL(T3, K2) = MUL(T1, k1) + MUL(T3, k2) + T1 + T3
+ const __m128i d1 = _mm_mulhi_epi16(T1, k1);
+ const __m128i d2 = _mm_mulhi_epi16(T3, k2);
+ const __m128i d3 = _mm_add_epi16(T1, T3);
+ const __m128i d4 = _mm_add_epi16(d1, d2);
+ const __m128i d = _mm_add_epi16(d3, d4);
+
+ // Second pass.
+ const __m128i tmp0 = _mm_add_epi16(a, d);
+ const __m128i tmp1 = _mm_add_epi16(b, c);
+ const __m128i tmp2 = _mm_sub_epi16(b, c);
+ const __m128i tmp3 = _mm_sub_epi16(a, d);
+ const __m128i shifted0 = _mm_srai_epi16(tmp0, 3);
+ const __m128i shifted1 = _mm_srai_epi16(tmp1, 3);
+ const __m128i shifted2 = _mm_srai_epi16(tmp2, 3);
+ const __m128i shifted3 = _mm_srai_epi16(tmp3, 3);
+
+ // Transpose the two 4x4.
+ // a00 a01 a02 a03 b00 b01 b02 b03
+ // a10 a11 a12 a13 b10 b11 b12 b13
+ // a20 a21 a22 a23 b20 b21 b22 b23
+ // a30 a31 a32 a33 b30 b31 b32 b33
+ const __m128i transpose0_0 = _mm_unpacklo_epi16(shifted0, shifted1);
+ const __m128i transpose0_1 = _mm_unpacklo_epi16(shifted2, shifted3);
+ const __m128i transpose0_2 = _mm_unpackhi_epi16(shifted0, shifted1);
+ const __m128i transpose0_3 = _mm_unpackhi_epi16(shifted2, shifted3);
+ // a00 a10 a01 a11 a02 a12 a03 a13
+ // a20 a30 a21 a31 a22 a32 a23 a33
+ // b00 b10 b01 b11 b02 b12 b03 b13
+ // b20 b30 b21 b31 b22 b32 b23 b33
+ const __m128i transpose1_0 = _mm_unpacklo_epi32(transpose0_0, transpose0_1);
+ const __m128i transpose1_1 = _mm_unpacklo_epi32(transpose0_2, transpose0_3);
+ const __m128i transpose1_2 = _mm_unpackhi_epi32(transpose0_0, transpose0_1);
+ const __m128i transpose1_3 = _mm_unpackhi_epi32(transpose0_2, transpose0_3);
+ // a00 a10 a20 a30 a01 a11 a21 a31
+ // b00 b10 b20 b30 b01 b11 b21 b31
+ // a02 a12 a22 a32 a03 a13 a23 a33
+ // b02 b12 a22 b32 b03 b13 b23 b33
+ T0 = _mm_unpacklo_epi64(transpose1_0, transpose1_1);
+ T1 = _mm_unpackhi_epi64(transpose1_0, transpose1_1);
+ T2 = _mm_unpacklo_epi64(transpose1_2, transpose1_3);
+ T3 = _mm_unpackhi_epi64(transpose1_2, transpose1_3);
+ // a00 a10 a20 a30 b00 b10 b20 b30
+ // a01 a11 a21 a31 b01 b11 b21 b31
+ // a02 a12 a22 a32 b02 b12 b22 b32
+ // a03 a13 a23 a33 b03 b13 b23 b33
+ }
+
+ // Add inverse transform to 'dst' and store.
+ {
+ const __m128i zero = _mm_set1_epi16(0);
+ // Load the reference(s).
+ __m128i dst0, dst1, dst2, dst3;
+ if (do_two) {
+ // Load eight bytes/pixels per line.
+ dst0 = _mm_loadl_epi64((__m128i*)&dst[0 * BPS]);
+ dst1 = _mm_loadl_epi64((__m128i*)&dst[1 * BPS]);
+ dst2 = _mm_loadl_epi64((__m128i*)&dst[2 * BPS]);
+ dst3 = _mm_loadl_epi64((__m128i*)&dst[3 * BPS]);
+ } else {
+ // Load four bytes/pixels per line.
+ dst0 = _mm_cvtsi32_si128(*(int*)&dst[0 * BPS]);
+ dst1 = _mm_cvtsi32_si128(*(int*)&dst[1 * BPS]);
+ dst2 = _mm_cvtsi32_si128(*(int*)&dst[2 * BPS]);
+ dst3 = _mm_cvtsi32_si128(*(int*)&dst[3 * BPS]);
+ }
+ // Convert to 16b.
+ dst0 = _mm_unpacklo_epi8(dst0, zero);
+ dst1 = _mm_unpacklo_epi8(dst1, zero);
+ dst2 = _mm_unpacklo_epi8(dst2, zero);
+ dst3 = _mm_unpacklo_epi8(dst3, zero);
+ // Add the inverse transform(s).
+ dst0 = _mm_add_epi16(dst0, T0);
+ dst1 = _mm_add_epi16(dst1, T1);
+ dst2 = _mm_add_epi16(dst2, T2);
+ dst3 = _mm_add_epi16(dst3, T3);
+ // Unsigned saturate to 8b.
+ dst0 = _mm_packus_epi16(dst0, dst0);
+ dst1 = _mm_packus_epi16(dst1, dst1);
+ dst2 = _mm_packus_epi16(dst2, dst2);
+ dst3 = _mm_packus_epi16(dst3, dst3);
+ // Store the results.
+ if (do_two) {
+ // Store eight bytes/pixels per line.
+ _mm_storel_epi64((__m128i*)&dst[0 * BPS], dst0);
+ _mm_storel_epi64((__m128i*)&dst[1 * BPS], dst1);
+ _mm_storel_epi64((__m128i*)&dst[2 * BPS], dst2);
+ _mm_storel_epi64((__m128i*)&dst[3 * BPS], dst3);
+ } else {
+ // Store four bytes/pixels per line.
+ *((int32_t *)&dst[0 * BPS]) = _mm_cvtsi128_si32(dst0);
+ *((int32_t *)&dst[1 * BPS]) = _mm_cvtsi128_si32(dst1);
+ *((int32_t *)&dst[2 * BPS]) = _mm_cvtsi128_si32(dst2);
+ *((int32_t *)&dst[3 * BPS]) = _mm_cvtsi128_si32(dst3);
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+// Loop Filter (Paragraph 15)
+
+// Compute abs(p - q) = subs(p - q) OR subs(q - p)
+#define MM_ABS(p, q) _mm_or_si128( \
+ _mm_subs_epu8((q), (p)), \
+ _mm_subs_epu8((p), (q)))
+
+// Shift each byte of "a" by N bits while preserving by the sign bit.
+//
+// It first shifts the lower bytes of the words and then the upper bytes and
+// then merges the results together.
+#define SIGNED_SHIFT_N(a, N) { \
+ __m128i t = a; \
+ t = _mm_slli_epi16(t, 8); \
+ t = _mm_srai_epi16(t, N); \
+ t = _mm_srli_epi16(t, 8); \
+ \
+ a = _mm_srai_epi16(a, N + 8); \
+ a = _mm_slli_epi16(a, 8); \
+ \
+ a = _mm_or_si128(t, a); \
+}
+
+#define FLIP_SIGN_BIT2(a, b) { \
+ a = _mm_xor_si128(a, sign_bit); \
+ b = _mm_xor_si128(b, sign_bit); \
+}
+
+#define FLIP_SIGN_BIT4(a, b, c, d) { \
+ FLIP_SIGN_BIT2(a, b); \
+ FLIP_SIGN_BIT2(c, d); \
+}
+
+#define GET_NOTHEV(p1, p0, q0, q1, hev_thresh, not_hev) { \
+ const __m128i zero = _mm_setzero_si128(); \
+ const __m128i t1 = MM_ABS(p1, p0); \
+ const __m128i t2 = MM_ABS(q1, q0); \
+ \
+ const __m128i h = _mm_set1_epi8(hev_thresh); \
+ const __m128i t3 = _mm_subs_epu8(t1, h); /* abs(p1 - p0) - hev_tresh */ \
+ const __m128i t4 = _mm_subs_epu8(t2, h); /* abs(q1 - q0) - hev_tresh */ \
+ \
+ not_hev = _mm_or_si128(t3, t4); \
+ not_hev = _mm_cmpeq_epi8(not_hev, zero); /* not_hev <= t1 && not_hev <= t2 */\
+}
+
+#define GET_BASE_DELTA(p1, p0, q0, q1, o) { \
+ const __m128i qp0 = _mm_subs_epi8(q0, p0); /* q0 - p0 */ \
+ o = _mm_subs_epi8(p1, q1); /* p1 - q1 */ \
+ o = _mm_adds_epi8(o, qp0); /* p1 - q1 + 1 * (q0 - p0) */ \
+ o = _mm_adds_epi8(o, qp0); /* p1 - q1 + 2 * (q0 - p0) */ \
+ o = _mm_adds_epi8(o, qp0); /* p1 - q1 + 3 * (q0 - p0) */ \
+}
+
+#define DO_SIMPLE_FILTER(p0, q0, fl) { \
+ const __m128i three = _mm_set1_epi8(3); \
+ const __m128i four = _mm_set1_epi8(4); \
+ __m128i v3 = _mm_adds_epi8(fl, three); \
+ __m128i v4 = _mm_adds_epi8(fl, four); \
+ \
+ /* Do +4 side */ \
+ SIGNED_SHIFT_N(v4, 3); /* v4 >> 3 */ \
+ q0 = _mm_subs_epi8(q0, v4); /* q0 -= v4 */ \
+ \
+ /* Now do +3 side */ \
+ SIGNED_SHIFT_N(v3, 3); /* v3 >> 3 */ \
+ p0 = _mm_adds_epi8(p0, v3); /* p0 += v3 */ \
+}
+
+// Updates values of 2 pixels at MB edge during complex filtering.
+// Update operations:
+// q = q - a and p = p + a; where a = [(a_hi >> 7), (a_lo >> 7)]
+#define UPDATE_2PIXELS(pi, qi, a_lo, a_hi) { \
+ const __m128i a_lo7 = _mm_srai_epi16(a_lo, 7); \
+ const __m128i a_hi7 = _mm_srai_epi16(a_hi, 7); \
+ const __m128i a = _mm_packs_epi16(a_lo7, a_hi7); \
+ pi = _mm_adds_epi8(pi, a); \
+ qi = _mm_subs_epi8(qi, a); \
+}
+
+static void NeedsFilter(const __m128i* p1, const __m128i* p0, const __m128i* q0,
+ const __m128i* q1, int thresh, __m128i *mask) {
+ __m128i t1 = MM_ABS(*p1, *q1); // abs(p1 - q1)
+ *mask = _mm_set1_epi8(0xFE);
+ t1 = _mm_and_si128(t1, *mask); // set lsb of each byte to zero
+ t1 = _mm_srli_epi16(t1, 1); // abs(p1 - q1) / 2
+
+ *mask = MM_ABS(*p0, *q0); // abs(p0 - q0)
+ *mask = _mm_adds_epu8(*mask, *mask); // abs(p0 - q0) * 2
+ *mask = _mm_adds_epu8(*mask, t1); // abs(p0 - q0) * 2 + abs(p1 - q1) / 2
+
+ t1 = _mm_set1_epi8(thresh);
+ *mask = _mm_subs_epu8(*mask, t1); // mask <= thresh
+ *mask = _mm_cmpeq_epi8(*mask, _mm_setzero_si128());
+}
+
+//------------------------------------------------------------------------------
+// Edge filtering functions
+
+// Applies filter on 2 pixels (p0 and q0)
+static WEBP_INLINE void DoFilter2(const __m128i* p1, __m128i* p0, __m128i* q0,
+ const __m128i* q1, int thresh) {
+ __m128i a, mask;
+ const __m128i sign_bit = _mm_set1_epi8(0x80);
+ const __m128i p1s = _mm_xor_si128(*p1, sign_bit);
+ const __m128i q1s = _mm_xor_si128(*q1, sign_bit);
+
+ NeedsFilter(p1, p0, q0, q1, thresh, &mask);
+
+ // convert to signed values
+ FLIP_SIGN_BIT2(*p0, *q0);
+
+ GET_BASE_DELTA(p1s, *p0, *q0, q1s, a);
+ a = _mm_and_si128(a, mask); // mask filter values we don't care about
+ DO_SIMPLE_FILTER(*p0, *q0, a);
+
+ // unoffset
+ FLIP_SIGN_BIT2(*p0, *q0);
+}
+
+// Applies filter on 4 pixels (p1, p0, q0 and q1)
+static WEBP_INLINE void DoFilter4(__m128i* p1, __m128i *p0,
+ __m128i* q0, __m128i* q1,
+ const __m128i* mask, int hev_thresh) {
+ __m128i not_hev;
+ __m128i t1, t2, t3;
+ const __m128i sign_bit = _mm_set1_epi8(0x80);
+
+ // compute hev mask
+ GET_NOTHEV(*p1, *p0, *q0, *q1, hev_thresh, not_hev);
+
+ // convert to signed values
+ FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1);
+
+ t1 = _mm_subs_epi8(*p1, *q1); // p1 - q1
+ t1 = _mm_andnot_si128(not_hev, t1); // hev(p1 - q1)
+ t2 = _mm_subs_epi8(*q0, *p0); // q0 - p0
+ t1 = _mm_adds_epi8(t1, t2); // hev(p1 - q1) + 1 * (q0 - p0)
+ t1 = _mm_adds_epi8(t1, t2); // hev(p1 - q1) + 2 * (q0 - p0)
+ t1 = _mm_adds_epi8(t1, t2); // hev(p1 - q1) + 3 * (q0 - p0)
+ t1 = _mm_and_si128(t1, *mask); // mask filter values we don't care about
+
+ // Do +4 side
+ t2 = _mm_set1_epi8(4);
+ t2 = _mm_adds_epi8(t1, t2); // 3 * (q0 - p0) + (p1 - q1) + 4
+ SIGNED_SHIFT_N(t2, 3); // (3 * (q0 - p0) + hev(p1 - q1) + 4) >> 3
+ t3 = t2; // save t2
+ *q0 = _mm_subs_epi8(*q0, t2); // q0 -= t2
+
+ // Now do +3 side
+ t2 = _mm_set1_epi8(3);
+ t2 = _mm_adds_epi8(t1, t2); // +3 instead of +4
+ SIGNED_SHIFT_N(t2, 3); // (3 * (q0 - p0) + hev(p1 - q1) + 3) >> 3
+ *p0 = _mm_adds_epi8(*p0, t2); // p0 += t2
+
+ t2 = _mm_set1_epi8(1);
+ t3 = _mm_adds_epi8(t3, t2);
+ SIGNED_SHIFT_N(t3, 1); // (3 * (q0 - p0) + hev(p1 - q1) + 4) >> 4
+
+ t3 = _mm_and_si128(not_hev, t3); // if !hev
+ *q1 = _mm_subs_epi8(*q1, t3); // q1 -= t3
+ *p1 = _mm_adds_epi8(*p1, t3); // p1 += t3
+
+ // unoffset
+ FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1);
+}
+
+// Applies filter on 6 pixels (p2, p1, p0, q0, q1 and q2)
+static WEBP_INLINE void DoFilter6(__m128i *p2, __m128i* p1, __m128i *p0,
+ __m128i* q0, __m128i* q1, __m128i *q2,
+ const __m128i* mask, int hev_thresh) {
+ __m128i a, not_hev;
+ const __m128i sign_bit = _mm_set1_epi8(0x80);
+
+ // compute hev mask
+ GET_NOTHEV(*p1, *p0, *q0, *q1, hev_thresh, not_hev);
+
+ // convert to signed values
+ FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1);
+ FLIP_SIGN_BIT2(*p2, *q2);
+
+ GET_BASE_DELTA(*p1, *p0, *q0, *q1, a);
+
+ { // do simple filter on pixels with hev
+ const __m128i m = _mm_andnot_si128(not_hev, *mask);
+ const __m128i f = _mm_and_si128(a, m);
+ DO_SIMPLE_FILTER(*p0, *q0, f);
+ }
+ { // do strong filter on pixels with not hev
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i nine = _mm_set1_epi16(0x0900);
+ const __m128i sixty_three = _mm_set1_epi16(63);
+
+ const __m128i m = _mm_and_si128(not_hev, *mask);
+ const __m128i f = _mm_and_si128(a, m);
+ const __m128i f_lo = _mm_unpacklo_epi8(zero, f);
+ const __m128i f_hi = _mm_unpackhi_epi8(zero, f);
+
+ const __m128i f9_lo = _mm_mulhi_epi16(f_lo, nine); // Filter (lo) * 9
+ const __m128i f9_hi = _mm_mulhi_epi16(f_hi, nine); // Filter (hi) * 9
+ const __m128i f18_lo = _mm_add_epi16(f9_lo, f9_lo); // Filter (lo) * 18
+ const __m128i f18_hi = _mm_add_epi16(f9_hi, f9_hi); // Filter (hi) * 18
+
+ const __m128i a2_lo = _mm_add_epi16(f9_lo, sixty_three); // Filter * 9 + 63
+ const __m128i a2_hi = _mm_add_epi16(f9_hi, sixty_three); // Filter * 9 + 63
+
+ const __m128i a1_lo = _mm_add_epi16(f18_lo, sixty_three); // F... * 18 + 63
+ const __m128i a1_hi = _mm_add_epi16(f18_hi, sixty_three); // F... * 18 + 63
+
+ const __m128i a0_lo = _mm_add_epi16(f18_lo, a2_lo); // Filter * 27 + 63
+ const __m128i a0_hi = _mm_add_epi16(f18_hi, a2_hi); // Filter * 27 + 63
+
+ UPDATE_2PIXELS(*p2, *q2, a2_lo, a2_hi);
+ UPDATE_2PIXELS(*p1, *q1, a1_lo, a1_hi);
+ UPDATE_2PIXELS(*p0, *q0, a0_lo, a0_hi);
+ }
+
+ // unoffset
+ FLIP_SIGN_BIT4(*p1, *p0, *q0, *q1);
+ FLIP_SIGN_BIT2(*p2, *q2);
+}
+
+// reads 8 rows across a vertical edge.
+//
+// TODO(somnath): Investigate _mm_shuffle* also see if it can be broken into
+// two Load4x4() to avoid code duplication.
+static WEBP_INLINE void Load8x4(const uint8_t* b, int stride,
+ __m128i* p, __m128i* q) {
+ __m128i t1, t2;
+
+ // Load 0th, 1st, 4th and 5th rows
+ __m128i r0 = _mm_cvtsi32_si128(*((int*)&b[0 * stride])); // 03 02 01 00
+ __m128i r1 = _mm_cvtsi32_si128(*((int*)&b[1 * stride])); // 13 12 11 10
+ __m128i r4 = _mm_cvtsi32_si128(*((int*)&b[4 * stride])); // 43 42 41 40
+ __m128i r5 = _mm_cvtsi32_si128(*((int*)&b[5 * stride])); // 53 52 51 50
+
+ r0 = _mm_unpacklo_epi32(r0, r4); // 43 42 41 40 03 02 01 00
+ r1 = _mm_unpacklo_epi32(r1, r5); // 53 52 51 50 13 12 11 10
+
+ // t1 = 53 43 52 42 51 41 50 40 13 03 12 02 11 01 10 00
+ t1 = _mm_unpacklo_epi8(r0, r1);
+
+ // Load 2nd, 3rd, 6th and 7th rows
+ r0 = _mm_cvtsi32_si128(*((int*)&b[2 * stride])); // 23 22 21 22
+ r1 = _mm_cvtsi32_si128(*((int*)&b[3 * stride])); // 33 32 31 30
+ r4 = _mm_cvtsi32_si128(*((int*)&b[6 * stride])); // 63 62 61 60
+ r5 = _mm_cvtsi32_si128(*((int*)&b[7 * stride])); // 73 72 71 70
+
+ r0 = _mm_unpacklo_epi32(r0, r4); // 63 62 61 60 23 22 21 20
+ r1 = _mm_unpacklo_epi32(r1, r5); // 73 72 71 70 33 32 31 30
+
+ // t2 = 73 63 72 62 71 61 70 60 33 23 32 22 31 21 30 20
+ t2 = _mm_unpacklo_epi8(r0, r1);
+
+ // t1 = 33 23 13 03 32 22 12 02 31 21 11 01 30 20 10 00
+ // t2 = 73 63 53 43 72 62 52 42 71 61 51 41 70 60 50 40
+ r0 = t1;
+ t1 = _mm_unpacklo_epi16(t1, t2);
+ t2 = _mm_unpackhi_epi16(r0, t2);
+
+ // *p = 71 61 51 41 31 21 11 01 70 60 50 40 30 20 10 00
+ // *q = 73 63 53 43 33 23 13 03 72 62 52 42 32 22 12 02
+ *p = _mm_unpacklo_epi32(t1, t2);
+ *q = _mm_unpackhi_epi32(t1, t2);
+}
+
+static WEBP_INLINE void Load16x4(const uint8_t* r0, const uint8_t* r8,
+ int stride,
+ __m128i* p1, __m128i* p0,
+ __m128i* q0, __m128i* q1) {
+ __m128i t1, t2;
+ // Assume the pixels around the edge (|) are numbered as follows
+ // 00 01 | 02 03
+ // 10 11 | 12 13
+ // ... | ...
+ // e0 e1 | e2 e3
+ // f0 f1 | f2 f3
+ //
+ // r0 is pointing to the 0th row (00)
+ // r8 is pointing to the 8th row (80)
+
+ // Load
+ // p1 = 71 61 51 41 31 21 11 01 70 60 50 40 30 20 10 00
+ // q0 = 73 63 53 43 33 23 13 03 72 62 52 42 32 22 12 02
+ // p0 = f1 e1 d1 c1 b1 a1 91 81 f0 e0 d0 c0 b0 a0 90 80
+ // q1 = f3 e3 d3 c3 b3 a3 93 83 f2 e2 d2 c2 b2 a2 92 82
+ Load8x4(r0, stride, p1, q0);
+ Load8x4(r8, stride, p0, q1);
+
+ t1 = *p1;
+ t2 = *q0;
+ // p1 = f0 e0 d0 c0 b0 a0 90 80 70 60 50 40 30 20 10 00
+ // p0 = f1 e1 d1 c1 b1 a1 91 81 71 61 51 41 31 21 11 01
+ // q0 = f2 e2 d2 c2 b2 a2 92 82 72 62 52 42 32 22 12 02
+ // q1 = f3 e3 d3 c3 b3 a3 93 83 73 63 53 43 33 23 13 03
+ *p1 = _mm_unpacklo_epi64(t1, *p0);
+ *p0 = _mm_unpackhi_epi64(t1, *p0);
+ *q0 = _mm_unpacklo_epi64(t2, *q1);
+ *q1 = _mm_unpackhi_epi64(t2, *q1);
+}
+
+static WEBP_INLINE void Store4x4(__m128i* x, uint8_t* dst, int stride) {
+ int i;
+ for (i = 0; i < 4; ++i, dst += stride) {
+ *((int32_t*)dst) = _mm_cvtsi128_si32(*x);
+ *x = _mm_srli_si128(*x, 4);
+ }
+}
+
+// Transpose back and store
+static WEBP_INLINE void Store16x4(uint8_t* r0, uint8_t* r8, int stride,
+ __m128i* p1, __m128i* p0,
+ __m128i* q0, __m128i* q1) {
+ __m128i t1;
+
+ // p0 = 71 70 61 60 51 50 41 40 31 30 21 20 11 10 01 00
+ // p1 = f1 f0 e1 e0 d1 d0 c1 c0 b1 b0 a1 a0 91 90 81 80
+ t1 = *p0;
+ *p0 = _mm_unpacklo_epi8(*p1, t1);
+ *p1 = _mm_unpackhi_epi8(*p1, t1);
+
+ // q0 = 73 72 63 62 53 52 43 42 33 32 23 22 13 12 03 02
+ // q1 = f3 f2 e3 e2 d3 d2 c3 c2 b3 b2 a3 a2 93 92 83 82
+ t1 = *q0;
+ *q0 = _mm_unpacklo_epi8(t1, *q1);
+ *q1 = _mm_unpackhi_epi8(t1, *q1);
+
+ // p0 = 33 32 31 30 23 22 21 20 13 12 11 10 03 02 01 00
+ // q0 = 73 72 71 70 63 62 61 60 53 52 51 50 43 42 41 40
+ t1 = *p0;
+ *p0 = _mm_unpacklo_epi16(t1, *q0);
+ *q0 = _mm_unpackhi_epi16(t1, *q0);
+
+ // p1 = b3 b2 b1 b0 a3 a2 a1 a0 93 92 91 90 83 82 81 80
+ // q1 = f3 f2 f1 f0 e3 e2 e1 e0 d3 d2 d1 d0 c3 c2 c1 c0
+ t1 = *p1;
+ *p1 = _mm_unpacklo_epi16(t1, *q1);
+ *q1 = _mm_unpackhi_epi16(t1, *q1);
+
+ Store4x4(p0, r0, stride);
+ r0 += 4 * stride;
+ Store4x4(q0, r0, stride);
+
+ Store4x4(p1, r8, stride);
+ r8 += 4 * stride;
+ Store4x4(q1, r8, stride);
+}
+
+//------------------------------------------------------------------------------
+// Simple In-loop filtering (Paragraph 15.2)
+
+static void SimpleVFilter16SSE2(uint8_t* p, int stride, int thresh) {
+ // Load
+ __m128i p1 = _mm_loadu_si128((__m128i*)&p[-2 * stride]);
+ __m128i p0 = _mm_loadu_si128((__m128i*)&p[-stride]);
+ __m128i q0 = _mm_loadu_si128((__m128i*)&p[0]);
+ __m128i q1 = _mm_loadu_si128((__m128i*)&p[stride]);
+
+ DoFilter2(&p1, &p0, &q0, &q1, thresh);
+
+ // Store
+ _mm_storeu_si128((__m128i*)&p[-stride], p0);
+ _mm_storeu_si128((__m128i*)p, q0);
+}
+
+static void SimpleHFilter16SSE2(uint8_t* p, int stride, int thresh) {
+ __m128i p1, p0, q0, q1;
+
+ p -= 2; // beginning of p1
+
+ Load16x4(p, p + 8 * stride, stride, &p1, &p0, &q0, &q1);
+ DoFilter2(&p1, &p0, &q0, &q1, thresh);
+ Store16x4(p, p + 8 * stride, stride, &p1, &p0, &q0, &q1);
+}
+
+static void SimpleVFilter16iSSE2(uint8_t* p, int stride, int thresh) {
+ int k;
+ for (k = 3; k > 0; --k) {
+ p += 4 * stride;
+ SimpleVFilter16SSE2(p, stride, thresh);
+ }
+}
+
+static void SimpleHFilter16iSSE2(uint8_t* p, int stride, int thresh) {
+ int k;
+ for (k = 3; k > 0; --k) {
+ p += 4;
+ SimpleHFilter16SSE2(p, stride, thresh);
+ }
+}
+
+//------------------------------------------------------------------------------
+// Complex In-loop filtering (Paragraph 15.3)
+
+#define MAX_DIFF1(p3, p2, p1, p0, m) { \
+ m = MM_ABS(p3, p2); \
+ m = _mm_max_epu8(m, MM_ABS(p2, p1)); \
+ m = _mm_max_epu8(m, MM_ABS(p1, p0)); \
+}
+
+#define MAX_DIFF2(p3, p2, p1, p0, m) { \
+ m = _mm_max_epu8(m, MM_ABS(p3, p2)); \
+ m = _mm_max_epu8(m, MM_ABS(p2, p1)); \
+ m = _mm_max_epu8(m, MM_ABS(p1, p0)); \
+}
+
+#define LOAD_H_EDGES4(p, stride, e1, e2, e3, e4) { \
+ e1 = _mm_loadu_si128((__m128i*)&(p)[0 * stride]); \
+ e2 = _mm_loadu_si128((__m128i*)&(p)[1 * stride]); \
+ e3 = _mm_loadu_si128((__m128i*)&(p)[2 * stride]); \
+ e4 = _mm_loadu_si128((__m128i*)&(p)[3 * stride]); \
+}
+
+#define LOADUV_H_EDGE(p, u, v, stride) { \
+ p = _mm_loadl_epi64((__m128i*)&(u)[(stride)]); \
+ p = _mm_unpacklo_epi64(p, _mm_loadl_epi64((__m128i*)&(v)[(stride)])); \
+}
+
+#define LOADUV_H_EDGES4(u, v, stride, e1, e2, e3, e4) { \
+ LOADUV_H_EDGE(e1, u, v, 0 * stride); \
+ LOADUV_H_EDGE(e2, u, v, 1 * stride); \
+ LOADUV_H_EDGE(e3, u, v, 2 * stride); \
+ LOADUV_H_EDGE(e4, u, v, 3 * stride); \
+}
+
+#define STOREUV(p, u, v, stride) { \
+ _mm_storel_epi64((__m128i*)&u[(stride)], p); \
+ p = _mm_srli_si128(p, 8); \
+ _mm_storel_epi64((__m128i*)&v[(stride)], p); \
+}
+
+#define COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask) { \
+ __m128i fl_yes; \
+ const __m128i it = _mm_set1_epi8(ithresh); \
+ mask = _mm_subs_epu8(mask, it); \
+ mask = _mm_cmpeq_epi8(mask, _mm_setzero_si128()); \
+ NeedsFilter(&p1, &p0, &q0, &q1, thresh, &fl_yes); \
+ mask = _mm_and_si128(mask, fl_yes); \
+}
+
+// on macroblock edges
+static void VFilter16SSE2(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ __m128i t1;
+ __m128i mask;
+ __m128i p2, p1, p0, q0, q1, q2;
+
+ // Load p3, p2, p1, p0
+ LOAD_H_EDGES4(p - 4 * stride, stride, t1, p2, p1, p0);
+ MAX_DIFF1(t1, p2, p1, p0, mask);
+
+ // Load q0, q1, q2, q3
+ LOAD_H_EDGES4(p, stride, q0, q1, q2, t1);
+ MAX_DIFF2(t1, q2, q1, q0, mask);
+
+ COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
+ DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
+
+ // Store
+ _mm_storeu_si128((__m128i*)&p[-3 * stride], p2);
+ _mm_storeu_si128((__m128i*)&p[-2 * stride], p1);
+ _mm_storeu_si128((__m128i*)&p[-1 * stride], p0);
+ _mm_storeu_si128((__m128i*)&p[0 * stride], q0);
+ _mm_storeu_si128((__m128i*)&p[1 * stride], q1);
+ _mm_storeu_si128((__m128i*)&p[2 * stride], q2);
+}
+
+static void HFilter16SSE2(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ __m128i mask;
+ __m128i p3, p2, p1, p0, q0, q1, q2, q3;
+
+ uint8_t* const b = p - 4;
+ Load16x4(b, b + 8 * stride, stride, &p3, &p2, &p1, &p0); // p3, p2, p1, p0
+ MAX_DIFF1(p3, p2, p1, p0, mask);
+
+ Load16x4(p, p + 8 * stride, stride, &q0, &q1, &q2, &q3); // q0, q1, q2, q3
+ MAX_DIFF2(q3, q2, q1, q0, mask);
+
+ COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
+ DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
+
+ Store16x4(b, b + 8 * stride, stride, &p3, &p2, &p1, &p0);
+ Store16x4(p, p + 8 * stride, stride, &q0, &q1, &q2, &q3);
+}
+
+// on three inner edges
+static void VFilter16iSSE2(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ int k;
+ __m128i mask;
+ __m128i t1, t2, p1, p0, q0, q1;
+
+ for (k = 3; k > 0; --k) {
+ // Load p3, p2, p1, p0
+ LOAD_H_EDGES4(p, stride, t2, t1, p1, p0);
+ MAX_DIFF1(t2, t1, p1, p0, mask);
+
+ p += 4 * stride;
+
+ // Load q0, q1, q2, q3
+ LOAD_H_EDGES4(p, stride, q0, q1, t1, t2);
+ MAX_DIFF2(t2, t1, q1, q0, mask);
+
+ COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
+ DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh);
+
+ // Store
+ _mm_storeu_si128((__m128i*)&p[-2 * stride], p1);
+ _mm_storeu_si128((__m128i*)&p[-1 * stride], p0);
+ _mm_storeu_si128((__m128i*)&p[0 * stride], q0);
+ _mm_storeu_si128((__m128i*)&p[1 * stride], q1);
+ }
+}
+
+static void HFilter16iSSE2(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ int k;
+ uint8_t* b;
+ __m128i mask;
+ __m128i t1, t2, p1, p0, q0, q1;
+
+ for (k = 3; k > 0; --k) {
+ b = p;
+ Load16x4(b, b + 8 * stride, stride, &t2, &t1, &p1, &p0); // p3, p2, p1, p0
+ MAX_DIFF1(t2, t1, p1, p0, mask);
+
+ b += 4; // beginning of q0
+ Load16x4(b, b + 8 * stride, stride, &q0, &q1, &t1, &t2); // q0, q1, q2, q3
+ MAX_DIFF2(t2, t1, q1, q0, mask);
+
+ COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
+ DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh);
+
+ b -= 2; // beginning of p1
+ Store16x4(b, b + 8 * stride, stride, &p1, &p0, &q0, &q1);
+
+ p += 4;
+ }
+}
+
+// 8-pixels wide variant, for chroma filtering
+static void VFilter8SSE2(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ __m128i mask;
+ __m128i t1, p2, p1, p0, q0, q1, q2;
+
+ // Load p3, p2, p1, p0
+ LOADUV_H_EDGES4(u - 4 * stride, v - 4 * stride, stride, t1, p2, p1, p0);
+ MAX_DIFF1(t1, p2, p1, p0, mask);
+
+ // Load q0, q1, q2, q3
+ LOADUV_H_EDGES4(u, v, stride, q0, q1, q2, t1);
+ MAX_DIFF2(t1, q2, q1, q0, mask);
+
+ COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
+ DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
+
+ // Store
+ STOREUV(p2, u, v, -3 * stride);
+ STOREUV(p1, u, v, -2 * stride);
+ STOREUV(p0, u, v, -1 * stride);
+ STOREUV(q0, u, v, 0 * stride);
+ STOREUV(q1, u, v, 1 * stride);
+ STOREUV(q2, u, v, 2 * stride);
+}
+
+static void HFilter8SSE2(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ __m128i mask;
+ __m128i p3, p2, p1, p0, q0, q1, q2, q3;
+
+ uint8_t* const tu = u - 4;
+ uint8_t* const tv = v - 4;
+ Load16x4(tu, tv, stride, &p3, &p2, &p1, &p0); // p3, p2, p1, p0
+ MAX_DIFF1(p3, p2, p1, p0, mask);
+
+ Load16x4(u, v, stride, &q0, &q1, &q2, &q3); // q0, q1, q2, q3
+ MAX_DIFF2(q3, q2, q1, q0, mask);
+
+ COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
+ DoFilter6(&p2, &p1, &p0, &q0, &q1, &q2, &mask, hev_thresh);
+
+ Store16x4(tu, tv, stride, &p3, &p2, &p1, &p0);
+ Store16x4(u, v, stride, &q0, &q1, &q2, &q3);
+}
+
+static void VFilter8iSSE2(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ __m128i mask;
+ __m128i t1, t2, p1, p0, q0, q1;
+
+ // Load p3, p2, p1, p0
+ LOADUV_H_EDGES4(u, v, stride, t2, t1, p1, p0);
+ MAX_DIFF1(t2, t1, p1, p0, mask);
+
+ u += 4 * stride;
+ v += 4 * stride;
+
+ // Load q0, q1, q2, q3
+ LOADUV_H_EDGES4(u, v, stride, q0, q1, t1, t2);
+ MAX_DIFF2(t2, t1, q1, q0, mask);
+
+ COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
+ DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh);
+
+ // Store
+ STOREUV(p1, u, v, -2 * stride);
+ STOREUV(p0, u, v, -1 * stride);
+ STOREUV(q0, u, v, 0 * stride);
+ STOREUV(q1, u, v, 1 * stride);
+}
+
+static void HFilter8iSSE2(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ __m128i mask;
+ __m128i t1, t2, p1, p0, q0, q1;
+ Load16x4(u, v, stride, &t2, &t1, &p1, &p0); // p3, p2, p1, p0
+ MAX_DIFF1(t2, t1, p1, p0, mask);
+
+ u += 4; // beginning of q0
+ v += 4;
+ Load16x4(u, v, stride, &q0, &q1, &t1, &t2); // q0, q1, q2, q3
+ MAX_DIFF2(t2, t1, q1, q0, mask);
+
+ COMPLEX_FL_MASK(p1, p0, q0, q1, thresh, ithresh, mask);
+ DoFilter4(&p1, &p0, &q0, &q1, &mask, hev_thresh);
+
+ u -= 2; // beginning of p1
+ v -= 2;
+ Store16x4(u, v, stride, &p1, &p0, &q0, &q1);
+}
+
+extern void VP8DspInitSSE2(void);
+
+void VP8DspInitSSE2(void) {
+ VP8Transform = TransformSSE2;
+
+ VP8VFilter16 = VFilter16SSE2;
+ VP8HFilter16 = HFilter16SSE2;
+ VP8VFilter8 = VFilter8SSE2;
+ VP8HFilter8 = HFilter8SSE2;
+ VP8VFilter16i = VFilter16iSSE2;
+ VP8HFilter16i = HFilter16iSSE2;
+ VP8VFilter8i = VFilter8iSSE2;
+ VP8HFilter8i = HFilter8iSSE2;
+
+ VP8SimpleVFilter16 = SimpleVFilter16SSE2;
+ VP8SimpleHFilter16 = SimpleHFilter16SSE2;
+ VP8SimpleVFilter16i = SimpleVFilter16iSSE2;
+ VP8SimpleHFilter16i = SimpleHFilter16iSSE2;
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif // WEBP_USE_SSE2
diff --git a/drivers/webpold/dsp/dsp.h b/drivers/webpold/dsp/dsp.h
new file mode 100644
index 0000000000..fd686a8532
--- /dev/null
+++ b/drivers/webpold/dsp/dsp.h
@@ -0,0 +1,210 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Speed-critical functions.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#ifndef WEBP_DSP_DSP_H_
+#define WEBP_DSP_DSP_H_
+
+#include "../types.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// CPU detection
+
+#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))
+#define WEBP_MSC_SSE2 // Visual C++ SSE2 targets
+#endif
+
+#if defined(__SSE2__) || defined(WEBP_MSC_SSE2)
+#define WEBP_USE_SSE2
+#endif
+
+#if defined(__ANDROID__) && defined(__ARM_ARCH_7A__) && defined(__ARM_NEON__)
+#define WEBP_ANDROID_NEON // Android targets that might support NEON
+#endif
+
+#if ( (defined(__ARM_NEON__) && !defined(__aarch64__)) || defined(WEBP_ANDROID_NEON)) && !defined(PSP2_ENABLED)
+#define WEBP_USE_NEON
+#endif
+
+typedef enum {
+ kSSE2,
+ kSSE3,
+ kNEON
+} CPUFeature;
+// returns true if the CPU supports the feature.
+typedef int (*VP8CPUInfo)(CPUFeature feature);
+extern VP8CPUInfo VP8GetCPUInfo;
+
+//------------------------------------------------------------------------------
+// Encoding
+
+int VP8GetAlpha(const int histo[]);
+
+// Transforms
+// VP8Idct: Does one of two inverse transforms. If do_two is set, the transforms
+// will be done for (ref, in, dst) and (ref + 4, in + 16, dst + 4).
+typedef void (*VP8Idct)(const uint8_t* ref, const int16_t* in, uint8_t* dst,
+ int do_two);
+typedef void (*VP8Fdct)(const uint8_t* src, const uint8_t* ref, int16_t* out);
+typedef void (*VP8WHT)(const int16_t* in, int16_t* out);
+extern VP8Idct VP8ITransform;
+extern VP8Fdct VP8FTransform;
+extern VP8WHT VP8ITransformWHT;
+extern VP8WHT VP8FTransformWHT;
+// Predictions
+// *dst is the destination block. *top and *left can be NULL.
+typedef void (*VP8IntraPreds)(uint8_t *dst, const uint8_t* left,
+ const uint8_t* top);
+typedef void (*VP8Intra4Preds)(uint8_t *dst, const uint8_t* top);
+extern VP8Intra4Preds VP8EncPredLuma4;
+extern VP8IntraPreds VP8EncPredLuma16;
+extern VP8IntraPreds VP8EncPredChroma8;
+
+typedef int (*VP8Metric)(const uint8_t* pix, const uint8_t* ref);
+extern VP8Metric VP8SSE16x16, VP8SSE16x8, VP8SSE8x8, VP8SSE4x4;
+typedef int (*VP8WMetric)(const uint8_t* pix, const uint8_t* ref,
+ const uint16_t* const weights);
+extern VP8WMetric VP8TDisto4x4, VP8TDisto16x16;
+
+typedef void (*VP8BlockCopy)(const uint8_t* src, uint8_t* dst);
+extern VP8BlockCopy VP8Copy4x4;
+// Quantization
+struct VP8Matrix; // forward declaration
+typedef int (*VP8QuantizeBlock)(int16_t in[16], int16_t out[16],
+ int n, const struct VP8Matrix* const mtx);
+extern VP8QuantizeBlock VP8EncQuantizeBlock;
+
+// Compute susceptibility based on DCT-coeff histograms:
+// the higher, the "easier" the macroblock is to compress.
+typedef int (*VP8CHisto)(const uint8_t* ref, const uint8_t* pred,
+ int start_block, int end_block);
+extern const int VP8DspScan[16 + 4 + 4];
+extern VP8CHisto VP8CollectHistogram;
+
+void VP8EncDspInit(void); // must be called before using any of the above
+
+//------------------------------------------------------------------------------
+// Decoding
+
+typedef void (*VP8DecIdct)(const int16_t* coeffs, uint8_t* dst);
+// when doing two transforms, coeffs is actually int16_t[2][16].
+typedef void (*VP8DecIdct2)(const int16_t* coeffs, uint8_t* dst, int do_two);
+extern VP8DecIdct2 VP8Transform;
+extern VP8DecIdct VP8TransformUV;
+extern VP8DecIdct VP8TransformDC;
+extern VP8DecIdct VP8TransformDCUV;
+extern void (*VP8TransformWHT)(const int16_t* in, int16_t* out);
+
+// *dst is the destination block, with stride BPS. Boundary samples are
+// assumed accessible when needed.
+typedef void (*VP8PredFunc)(uint8_t* dst);
+extern const VP8PredFunc VP8PredLuma16[/* NUM_B_DC_MODES */];
+extern const VP8PredFunc VP8PredChroma8[/* NUM_B_DC_MODES */];
+extern const VP8PredFunc VP8PredLuma4[/* NUM_BMODES */];
+
+// simple filter (only for luma)
+typedef void (*VP8SimpleFilterFunc)(uint8_t* p, int stride, int thresh);
+extern VP8SimpleFilterFunc VP8SimpleVFilter16;
+extern VP8SimpleFilterFunc VP8SimpleHFilter16;
+extern VP8SimpleFilterFunc VP8SimpleVFilter16i; // filter 3 inner edges
+extern VP8SimpleFilterFunc VP8SimpleHFilter16i;
+
+// regular filter (on both macroblock edges and inner edges)
+typedef void (*VP8LumaFilterFunc)(uint8_t* luma, int stride,
+ int thresh, int ithresh, int hev_t);
+typedef void (*VP8ChromaFilterFunc)(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_t);
+// on outer edge
+extern VP8LumaFilterFunc VP8VFilter16;
+extern VP8LumaFilterFunc VP8HFilter16;
+extern VP8ChromaFilterFunc VP8VFilter8;
+extern VP8ChromaFilterFunc VP8HFilter8;
+
+// on inner edge
+extern VP8LumaFilterFunc VP8VFilter16i; // filtering 3 inner edges altogether
+extern VP8LumaFilterFunc VP8HFilter16i;
+extern VP8ChromaFilterFunc VP8VFilter8i; // filtering u and v altogether
+extern VP8ChromaFilterFunc VP8HFilter8i;
+
+// must be called before anything using the above
+void VP8DspInit(void);
+
+//------------------------------------------------------------------------------
+// WebP I/O
+
+#define FANCY_UPSAMPLING // undefined to remove fancy upsampling support
+
+typedef void (*WebPUpsampleLinePairFunc)(
+ const uint8_t* top_y, const uint8_t* bottom_y,
+ const uint8_t* top_u, const uint8_t* top_v,
+ const uint8_t* cur_u, const uint8_t* cur_v,
+ uint8_t* top_dst, uint8_t* bottom_dst, int len);
+
+#ifdef FANCY_UPSAMPLING
+
+// Fancy upsampling functions to convert YUV to RGB(A) modes
+extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */];
+
+// Initializes SSE2 version of the fancy upsamplers.
+void WebPInitUpsamplersSSE2(void);
+
+#endif // FANCY_UPSAMPLING
+
+// Point-sampling methods.
+typedef void (*WebPSampleLinePairFunc)(
+ const uint8_t* top_y, const uint8_t* bottom_y,
+ const uint8_t* u, const uint8_t* v,
+ uint8_t* top_dst, uint8_t* bottom_dst, int len);
+
+extern const WebPSampleLinePairFunc WebPSamplers[/* MODE_LAST */];
+
+// General function for converting two lines of ARGB or RGBA.
+// 'alpha_is_last' should be true if 0xff000000 is stored in memory as
+// as 0x00, 0x00, 0x00, 0xff (little endian).
+WebPUpsampleLinePairFunc WebPGetLinePairConverter(int alpha_is_last);
+
+// YUV444->RGB converters
+typedef void (*WebPYUV444Converter)(const uint8_t* y,
+ const uint8_t* u, const uint8_t* v,
+ uint8_t* dst, int len);
+
+extern const WebPYUV444Converter WebPYUV444Converters[/* MODE_LAST */];
+
+// Main function to be called
+void WebPInitUpsamplers(void);
+
+//------------------------------------------------------------------------------
+// Pre-multiply planes with alpha values
+
+// Apply alpha pre-multiply on an rgba, bgra or argb plane of size w * h.
+// alpha_first should be 0 for argb, 1 for rgba or bgra (where alpha is last).
+extern void (*WebPApplyAlphaMultiply)(
+ uint8_t* rgba, int alpha_first, int w, int h, int stride);
+
+// Same, buf specifically for RGBA4444 format
+extern void (*WebPApplyAlphaMultiply4444)(
+ uint8_t* rgba4444, int w, int h, int stride);
+
+// To be called first before using the above.
+void WebPInitPremultiply(void);
+
+void WebPInitPremultiplySSE2(void); // should not be called directly.
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif /* WEBP_DSP_DSP_H_ */
diff --git a/drivers/webpold/dsp/enc.c b/drivers/webpold/dsp/enc.c
new file mode 100644
index 0000000000..02234564be
--- /dev/null
+++ b/drivers/webpold/dsp/enc.c
@@ -0,0 +1,743 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Speed-critical encoding functions.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <stdlib.h> // for abs()
+#include "./dsp.h"
+#include "../enc/vp8enci.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// Compute susceptibility based on DCT-coeff histograms:
+// the higher, the "easier" the macroblock is to compress.
+
+static int ClipAlpha(int alpha) {
+ return alpha < 0 ? 0 : alpha > 255 ? 255 : alpha;
+}
+
+int VP8GetAlpha(const int histo[MAX_COEFF_THRESH + 1]) {
+ int num = 0, den = 0, val = 0;
+ int k;
+ int alpha;
+ // note: changing this loop to avoid the numerous "k + 1" slows things down.
+ for (k = 0; k < MAX_COEFF_THRESH; ++k) {
+ if (histo[k + 1]) {
+ val += histo[k + 1];
+ num += val * (k + 1);
+ den += (k + 1) * (k + 1);
+ }
+ }
+ // we scale the value to a usable [0..255] range
+ alpha = den ? 10 * num / den - 5 : 0;
+ return ClipAlpha(alpha);
+}
+
+const int VP8DspScan[16 + 4 + 4] = {
+ // Luma
+ 0 + 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS,
+ 0 + 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS,
+ 0 + 8 * BPS, 4 + 8 * BPS, 8 + 8 * BPS, 12 + 8 * BPS,
+ 0 + 12 * BPS, 4 + 12 * BPS, 8 + 12 * BPS, 12 + 12 * BPS,
+
+ 0 + 0 * BPS, 4 + 0 * BPS, 0 + 4 * BPS, 4 + 4 * BPS, // U
+ 8 + 0 * BPS, 12 + 0 * BPS, 8 + 4 * BPS, 12 + 4 * BPS // V
+};
+
+static int CollectHistogram(const uint8_t* ref, const uint8_t* pred,
+ int start_block, int end_block) {
+ int histo[MAX_COEFF_THRESH + 1] = { 0 };
+ int16_t out[16];
+ int j, k;
+ for (j = start_block; j < end_block; ++j) {
+ VP8FTransform(ref + VP8DspScan[j], pred + VP8DspScan[j], out);
+
+ // Convert coefficients to bin (within out[]).
+ for (k = 0; k < 16; ++k) {
+ const int v = abs(out[k]) >> 2;
+ out[k] = (v > MAX_COEFF_THRESH) ? MAX_COEFF_THRESH : v;
+ }
+
+ // Use bin to update histogram.
+ for (k = 0; k < 16; ++k) {
+ histo[out[k]]++;
+ }
+ }
+
+ return VP8GetAlpha(histo);
+}
+
+//------------------------------------------------------------------------------
+// run-time tables (~4k)
+
+static uint8_t clip1[255 + 510 + 1]; // clips [-255,510] to [0,255]
+
+// We declare this variable 'volatile' to prevent instruction reordering
+// and make sure it's set to true _last_ (so as to be thread-safe)
+static volatile int tables_ok = 0;
+
+static void InitTables(void) {
+ if (!tables_ok) {
+ int i;
+ for (i = -255; i <= 255 + 255; ++i) {
+ clip1[255 + i] = (i < 0) ? 0 : (i > 255) ? 255 : i;
+ }
+ tables_ok = 1;
+ }
+}
+
+static WEBP_INLINE uint8_t clip_8b(int v) {
+ return (!(v & ~0xff)) ? v : v < 0 ? 0 : 255;
+}
+
+//------------------------------------------------------------------------------
+// Transforms (Paragraph 14.4)
+
+#define STORE(x, y, v) \
+ dst[(x) + (y) * BPS] = clip_8b(ref[(x) + (y) * BPS] + ((v) >> 3))
+
+static const int kC1 = 20091 + (1 << 16);
+static const int kC2 = 35468;
+#define MUL(a, b) (((a) * (b)) >> 16)
+
+static WEBP_INLINE void ITransformOne(const uint8_t* ref, const int16_t* in,
+ uint8_t* dst) {
+ int C[4 * 4], *tmp;
+ int i;
+ tmp = C;
+ for (i = 0; i < 4; ++i) { // vertical pass
+ const int a = in[0] + in[8];
+ const int b = in[0] - in[8];
+ const int c = MUL(in[4], kC2) - MUL(in[12], kC1);
+ const int d = MUL(in[4], kC1) + MUL(in[12], kC2);
+ tmp[0] = a + d;
+ tmp[1] = b + c;
+ tmp[2] = b - c;
+ tmp[3] = a - d;
+ tmp += 4;
+ in++;
+ }
+
+ tmp = C;
+ for (i = 0; i < 4; ++i) { // horizontal pass
+ const int dc = tmp[0] + 4;
+ const int a = dc + tmp[8];
+ const int b = dc - tmp[8];
+ const int c = MUL(tmp[4], kC2) - MUL(tmp[12], kC1);
+ const int d = MUL(tmp[4], kC1) + MUL(tmp[12], kC2);
+ STORE(0, i, a + d);
+ STORE(1, i, b + c);
+ STORE(2, i, b - c);
+ STORE(3, i, a - d);
+ tmp++;
+ }
+}
+
+static void ITransform(const uint8_t* ref, const int16_t* in, uint8_t* dst,
+ int do_two) {
+ ITransformOne(ref, in, dst);
+ if (do_two) {
+ ITransformOne(ref + 4, in + 16, dst + 4);
+ }
+}
+
+static void FTransform(const uint8_t* src, const uint8_t* ref, int16_t* out) {
+ int i;
+ int tmp[16];
+ for (i = 0; i < 4; ++i, src += BPS, ref += BPS) {
+ const int d0 = src[0] - ref[0];
+ const int d1 = src[1] - ref[1];
+ const int d2 = src[2] - ref[2];
+ const int d3 = src[3] - ref[3];
+ const int a0 = (d0 + d3) << 3;
+ const int a1 = (d1 + d2) << 3;
+ const int a2 = (d1 - d2) << 3;
+ const int a3 = (d0 - d3) << 3;
+ tmp[0 + i * 4] = (a0 + a1);
+ tmp[1 + i * 4] = (a2 * 2217 + a3 * 5352 + 14500) >> 12;
+ tmp[2 + i * 4] = (a0 - a1);
+ tmp[3 + i * 4] = (a3 * 2217 - a2 * 5352 + 7500) >> 12;
+ }
+ for (i = 0; i < 4; ++i) {
+ const int a0 = (tmp[0 + i] + tmp[12 + i]);
+ const int a1 = (tmp[4 + i] + tmp[ 8 + i]);
+ const int a2 = (tmp[4 + i] - tmp[ 8 + i]);
+ const int a3 = (tmp[0 + i] - tmp[12 + i]);
+ out[0 + i] = (a0 + a1 + 7) >> 4;
+ out[4 + i] = ((a2 * 2217 + a3 * 5352 + 12000) >> 16) + (a3 != 0);
+ out[8 + i] = (a0 - a1 + 7) >> 4;
+ out[12+ i] = ((a3 * 2217 - a2 * 5352 + 51000) >> 16);
+ }
+}
+
+static void ITransformWHT(const int16_t* in, int16_t* out) {
+ int tmp[16];
+ int i;
+ for (i = 0; i < 4; ++i) {
+ const int a0 = in[0 + i] + in[12 + i];
+ const int a1 = in[4 + i] + in[ 8 + i];
+ const int a2 = in[4 + i] - in[ 8 + i];
+ const int a3 = in[0 + i] - in[12 + i];
+ tmp[0 + i] = a0 + a1;
+ tmp[8 + i] = a0 - a1;
+ tmp[4 + i] = a3 + a2;
+ tmp[12 + i] = a3 - a2;
+ }
+ for (i = 0; i < 4; ++i) {
+ const int dc = tmp[0 + i * 4] + 3; // w/ rounder
+ const int a0 = dc + tmp[3 + i * 4];
+ const int a1 = tmp[1 + i * 4] + tmp[2 + i * 4];
+ const int a2 = tmp[1 + i * 4] - tmp[2 + i * 4];
+ const int a3 = dc - tmp[3 + i * 4];
+ out[ 0] = (a0 + a1) >> 3;
+ out[16] = (a3 + a2) >> 3;
+ out[32] = (a0 - a1) >> 3;
+ out[48] = (a3 - a2) >> 3;
+ out += 64;
+ }
+}
+
+static void FTransformWHT(const int16_t* in, int16_t* out) {
+ int tmp[16];
+ int i;
+ for (i = 0; i < 4; ++i, in += 64) {
+ const int a0 = (in[0 * 16] + in[2 * 16]) << 2;
+ const int a1 = (in[1 * 16] + in[3 * 16]) << 2;
+ const int a2 = (in[1 * 16] - in[3 * 16]) << 2;
+ const int a3 = (in[0 * 16] - in[2 * 16]) << 2;
+ tmp[0 + i * 4] = (a0 + a1) + (a0 != 0);
+ tmp[1 + i * 4] = a3 + a2;
+ tmp[2 + i * 4] = a3 - a2;
+ tmp[3 + i * 4] = a0 - a1;
+ }
+ for (i = 0; i < 4; ++i) {
+ const int a0 = (tmp[0 + i] + tmp[8 + i]);
+ const int a1 = (tmp[4 + i] + tmp[12+ i]);
+ const int a2 = (tmp[4 + i] - tmp[12+ i]);
+ const int a3 = (tmp[0 + i] - tmp[8 + i]);
+ const int b0 = a0 + a1;
+ const int b1 = a3 + a2;
+ const int b2 = a3 - a2;
+ const int b3 = a0 - a1;
+ out[ 0 + i] = (b0 + (b0 > 0) + 3) >> 3;
+ out[ 4 + i] = (b1 + (b1 > 0) + 3) >> 3;
+ out[ 8 + i] = (b2 + (b2 > 0) + 3) >> 3;
+ out[12 + i] = (b3 + (b3 > 0) + 3) >> 3;
+ }
+}
+
+#undef MUL
+#undef STORE
+
+//------------------------------------------------------------------------------
+// Intra predictions
+
+#define DST(x, y) dst[(x) + (y) * BPS]
+
+static WEBP_INLINE void Fill(uint8_t* dst, int value, int size) {
+ int j;
+ for (j = 0; j < size; ++j) {
+ memset(dst + j * BPS, value, size);
+ }
+}
+
+static WEBP_INLINE void VerticalPred(uint8_t* dst,
+ const uint8_t* top, int size) {
+ int j;
+ if (top) {
+ for (j = 0; j < size; ++j) memcpy(dst + j * BPS, top, size);
+ } else {
+ Fill(dst, 127, size);
+ }
+}
+
+static WEBP_INLINE void HorizontalPred(uint8_t* dst,
+ const uint8_t* left, int size) {
+ if (left) {
+ int j;
+ for (j = 0; j < size; ++j) {
+ memset(dst + j * BPS, left[j], size);
+ }
+ } else {
+ Fill(dst, 129, size);
+ }
+}
+
+static WEBP_INLINE void TrueMotion(uint8_t* dst, const uint8_t* left,
+ const uint8_t* top, int size) {
+ int y;
+ if (left) {
+ if (top) {
+ const uint8_t* const clip = clip1 + 255 - left[-1];
+ for (y = 0; y < size; ++y) {
+ const uint8_t* const clip_table = clip + left[y];
+ int x;
+ for (x = 0; x < size; ++x) {
+ dst[x] = clip_table[top[x]];
+ }
+ dst += BPS;
+ }
+ } else {
+ HorizontalPred(dst, left, size);
+ }
+ } else {
+ // true motion without left samples (hence: with default 129 value)
+ // is equivalent to VE prediction where you just copy the top samples.
+ // Note that if top samples are not available, the default value is
+ // then 129, and not 127 as in the VerticalPred case.
+ if (top) {
+ VerticalPred(dst, top, size);
+ } else {
+ Fill(dst, 129, size);
+ }
+ }
+}
+
+static WEBP_INLINE void DCMode(uint8_t* dst, const uint8_t* left,
+ const uint8_t* top,
+ int size, int round, int shift) {
+ int DC = 0;
+ int j;
+ if (top) {
+ for (j = 0; j < size; ++j) DC += top[j];
+ if (left) { // top and left present
+ for (j = 0; j < size; ++j) DC += left[j];
+ } else { // top, but no left
+ DC += DC;
+ }
+ DC = (DC + round) >> shift;
+ } else if (left) { // left but no top
+ for (j = 0; j < size; ++j) DC += left[j];
+ DC += DC;
+ DC = (DC + round) >> shift;
+ } else { // no top, no left, nothing.
+ DC = 0x80;
+ }
+ Fill(dst, DC, size);
+}
+
+//------------------------------------------------------------------------------
+// Chroma 8x8 prediction (paragraph 12.2)
+
+static void IntraChromaPreds(uint8_t* dst, const uint8_t* left,
+ const uint8_t* top) {
+ // U block
+ DCMode(C8DC8 + dst, left, top, 8, 8, 4);
+ VerticalPred(C8VE8 + dst, top, 8);
+ HorizontalPred(C8HE8 + dst, left, 8);
+ TrueMotion(C8TM8 + dst, left, top, 8);
+ // V block
+ dst += 8;
+ if (top) top += 8;
+ if (left) left += 16;
+ DCMode(C8DC8 + dst, left, top, 8, 8, 4);
+ VerticalPred(C8VE8 + dst, top, 8);
+ HorizontalPred(C8HE8 + dst, left, 8);
+ TrueMotion(C8TM8 + dst, left, top, 8);
+}
+
+//------------------------------------------------------------------------------
+// luma 16x16 prediction (paragraph 12.3)
+
+static void Intra16Preds(uint8_t* dst,
+ const uint8_t* left, const uint8_t* top) {
+ DCMode(I16DC16 + dst, left, top, 16, 16, 5);
+ VerticalPred(I16VE16 + dst, top, 16);
+ HorizontalPred(I16HE16 + dst, left, 16);
+ TrueMotion(I16TM16 + dst, left, top, 16);
+}
+
+//------------------------------------------------------------------------------
+// luma 4x4 prediction
+
+#define AVG3(a, b, c) (((a) + 2 * (b) + (c) + 2) >> 2)
+#define AVG2(a, b) (((a) + (b) + 1) >> 1)
+
+static void VE4(uint8_t* dst, const uint8_t* top) { // vertical
+ const uint8_t vals[4] = {
+ AVG3(top[-1], top[0], top[1]),
+ AVG3(top[ 0], top[1], top[2]),
+ AVG3(top[ 1], top[2], top[3]),
+ AVG3(top[ 2], top[3], top[4])
+ };
+ int i;
+ for (i = 0; i < 4; ++i) {
+ memcpy(dst + i * BPS, vals, 4);
+ }
+}
+
+static void HE4(uint8_t* dst, const uint8_t* top) { // horizontal
+ const int X = top[-1];
+ const int I = top[-2];
+ const int J = top[-3];
+ const int K = top[-4];
+ const int L = top[-5];
+ *(uint32_t*)(dst + 0 * BPS) = 0x01010101U * AVG3(X, I, J);
+ *(uint32_t*)(dst + 1 * BPS) = 0x01010101U * AVG3(I, J, K);
+ *(uint32_t*)(dst + 2 * BPS) = 0x01010101U * AVG3(J, K, L);
+ *(uint32_t*)(dst + 3 * BPS) = 0x01010101U * AVG3(K, L, L);
+}
+
+static void DC4(uint8_t* dst, const uint8_t* top) {
+ uint32_t dc = 4;
+ int i;
+ for (i = 0; i < 4; ++i) dc += top[i] + top[-5 + i];
+ Fill(dst, dc >> 3, 4);
+}
+
+static void RD4(uint8_t* dst, const uint8_t* top) {
+ const int X = top[-1];
+ const int I = top[-2];
+ const int J = top[-3];
+ const int K = top[-4];
+ const int L = top[-5];
+ const int A = top[0];
+ const int B = top[1];
+ const int C = top[2];
+ const int D = top[3];
+ DST(0, 3) = AVG3(J, K, L);
+ DST(0, 2) = DST(1, 3) = AVG3(I, J, K);
+ DST(0, 1) = DST(1, 2) = DST(2, 3) = AVG3(X, I, J);
+ DST(0, 0) = DST(1, 1) = DST(2, 2) = DST(3, 3) = AVG3(A, X, I);
+ DST(1, 0) = DST(2, 1) = DST(3, 2) = AVG3(B, A, X);
+ DST(2, 0) = DST(3, 1) = AVG3(C, B, A);
+ DST(3, 0) = AVG3(D, C, B);
+}
+
+static void LD4(uint8_t* dst, const uint8_t* top) {
+ const int A = top[0];
+ const int B = top[1];
+ const int C = top[2];
+ const int D = top[3];
+ const int E = top[4];
+ const int F = top[5];
+ const int G = top[6];
+ const int H = top[7];
+ DST(0, 0) = AVG3(A, B, C);
+ DST(1, 0) = DST(0, 1) = AVG3(B, C, D);
+ DST(2, 0) = DST(1, 1) = DST(0, 2) = AVG3(C, D, E);
+ DST(3, 0) = DST(2, 1) = DST(1, 2) = DST(0, 3) = AVG3(D, E, F);
+ DST(3, 1) = DST(2, 2) = DST(1, 3) = AVG3(E, F, G);
+ DST(3, 2) = DST(2, 3) = AVG3(F, G, H);
+ DST(3, 3) = AVG3(G, H, H);
+}
+
+static void VR4(uint8_t* dst, const uint8_t* top) {
+ const int X = top[-1];
+ const int I = top[-2];
+ const int J = top[-3];
+ const int K = top[-4];
+ const int A = top[0];
+ const int B = top[1];
+ const int C = top[2];
+ const int D = top[3];
+ DST(0, 0) = DST(1, 2) = AVG2(X, A);
+ DST(1, 0) = DST(2, 2) = AVG2(A, B);
+ DST(2, 0) = DST(3, 2) = AVG2(B, C);
+ DST(3, 0) = AVG2(C, D);
+
+ DST(0, 3) = AVG3(K, J, I);
+ DST(0, 2) = AVG3(J, I, X);
+ DST(0, 1) = DST(1, 3) = AVG3(I, X, A);
+ DST(1, 1) = DST(2, 3) = AVG3(X, A, B);
+ DST(2, 1) = DST(3, 3) = AVG3(A, B, C);
+ DST(3, 1) = AVG3(B, C, D);
+}
+
+static void VL4(uint8_t* dst, const uint8_t* top) {
+ const int A = top[0];
+ const int B = top[1];
+ const int C = top[2];
+ const int D = top[3];
+ const int E = top[4];
+ const int F = top[5];
+ const int G = top[6];
+ const int H = top[7];
+ DST(0, 0) = AVG2(A, B);
+ DST(1, 0) = DST(0, 2) = AVG2(B, C);
+ DST(2, 0) = DST(1, 2) = AVG2(C, D);
+ DST(3, 0) = DST(2, 2) = AVG2(D, E);
+
+ DST(0, 1) = AVG3(A, B, C);
+ DST(1, 1) = DST(0, 3) = AVG3(B, C, D);
+ DST(2, 1) = DST(1, 3) = AVG3(C, D, E);
+ DST(3, 1) = DST(2, 3) = AVG3(D, E, F);
+ DST(3, 2) = AVG3(E, F, G);
+ DST(3, 3) = AVG3(F, G, H);
+}
+
+static void HU4(uint8_t* dst, const uint8_t* top) {
+ const int I = top[-2];
+ const int J = top[-3];
+ const int K = top[-4];
+ const int L = top[-5];
+ DST(0, 0) = AVG2(I, J);
+ DST(2, 0) = DST(0, 1) = AVG2(J, K);
+ DST(2, 1) = DST(0, 2) = AVG2(K, L);
+ DST(1, 0) = AVG3(I, J, K);
+ DST(3, 0) = DST(1, 1) = AVG3(J, K, L);
+ DST(3, 1) = DST(1, 2) = AVG3(K, L, L);
+ DST(3, 2) = DST(2, 2) =
+ DST(0, 3) = DST(1, 3) = DST(2, 3) = DST(3, 3) = L;
+}
+
+static void HD4(uint8_t* dst, const uint8_t* top) {
+ const int X = top[-1];
+ const int I = top[-2];
+ const int J = top[-3];
+ const int K = top[-4];
+ const int L = top[-5];
+ const int A = top[0];
+ const int B = top[1];
+ const int C = top[2];
+
+ DST(0, 0) = DST(2, 1) = AVG2(I, X);
+ DST(0, 1) = DST(2, 2) = AVG2(J, I);
+ DST(0, 2) = DST(2, 3) = AVG2(K, J);
+ DST(0, 3) = AVG2(L, K);
+
+ DST(3, 0) = AVG3(A, B, C);
+ DST(2, 0) = AVG3(X, A, B);
+ DST(1, 0) = DST(3, 1) = AVG3(I, X, A);
+ DST(1, 1) = DST(3, 2) = AVG3(J, I, X);
+ DST(1, 2) = DST(3, 3) = AVG3(K, J, I);
+ DST(1, 3) = AVG3(L, K, J);
+}
+
+static void TM4(uint8_t* dst, const uint8_t* top) {
+ int x, y;
+ const uint8_t* const clip = clip1 + 255 - top[-1];
+ for (y = 0; y < 4; ++y) {
+ const uint8_t* const clip_table = clip + top[-2 - y];
+ for (x = 0; x < 4; ++x) {
+ dst[x] = clip_table[top[x]];
+ }
+ dst += BPS;
+ }
+}
+
+#undef DST
+#undef AVG3
+#undef AVG2
+
+// Left samples are top[-5 .. -2], top_left is top[-1], top are
+// located at top[0..3], and top right is top[4..7]
+static void Intra4Preds(uint8_t* dst, const uint8_t* top) {
+ DC4(I4DC4 + dst, top);
+ TM4(I4TM4 + dst, top);
+ VE4(I4VE4 + dst, top);
+ HE4(I4HE4 + dst, top);
+ RD4(I4RD4 + dst, top);
+ VR4(I4VR4 + dst, top);
+ LD4(I4LD4 + dst, top);
+ VL4(I4VL4 + dst, top);
+ HD4(I4HD4 + dst, top);
+ HU4(I4HU4 + dst, top);
+}
+
+//------------------------------------------------------------------------------
+// Metric
+
+static WEBP_INLINE int GetSSE(const uint8_t* a, const uint8_t* b,
+ int w, int h) {
+ int count = 0;
+ int y, x;
+ for (y = 0; y < h; ++y) {
+ for (x = 0; x < w; ++x) {
+ const int diff = (int)a[x] - b[x];
+ count += diff * diff;
+ }
+ a += BPS;
+ b += BPS;
+ }
+ return count;
+}
+
+static int SSE16x16(const uint8_t* a, const uint8_t* b) {
+ return GetSSE(a, b, 16, 16);
+}
+static int SSE16x8(const uint8_t* a, const uint8_t* b) {
+ return GetSSE(a, b, 16, 8);
+}
+static int SSE8x8(const uint8_t* a, const uint8_t* b) {
+ return GetSSE(a, b, 8, 8);
+}
+static int SSE4x4(const uint8_t* a, const uint8_t* b) {
+ return GetSSE(a, b, 4, 4);
+}
+
+//------------------------------------------------------------------------------
+// Texture distortion
+//
+// We try to match the spectral content (weighted) between source and
+// reconstructed samples.
+
+// Hadamard transform
+// Returns the weighted sum of the absolute value of transformed coefficients.
+static int TTransform(const uint8_t* in, const uint16_t* w) {
+ int sum = 0;
+ int tmp[16];
+ int i;
+ // horizontal pass
+ for (i = 0; i < 4; ++i, in += BPS) {
+ const int a0 = (in[0] + in[2]) << 2;
+ const int a1 = (in[1] + in[3]) << 2;
+ const int a2 = (in[1] - in[3]) << 2;
+ const int a3 = (in[0] - in[2]) << 2;
+ tmp[0 + i * 4] = a0 + a1 + (a0 != 0);
+ tmp[1 + i * 4] = a3 + a2;
+ tmp[2 + i * 4] = a3 - a2;
+ tmp[3 + i * 4] = a0 - a1;
+ }
+ // vertical pass
+ for (i = 0; i < 4; ++i, ++w) {
+ const int a0 = (tmp[0 + i] + tmp[8 + i]);
+ const int a1 = (tmp[4 + i] + tmp[12+ i]);
+ const int a2 = (tmp[4 + i] - tmp[12+ i]);
+ const int a3 = (tmp[0 + i] - tmp[8 + i]);
+ const int b0 = a0 + a1;
+ const int b1 = a3 + a2;
+ const int b2 = a3 - a2;
+ const int b3 = a0 - a1;
+ // abs((b + (b<0) + 3) >> 3) = (abs(b) + 3) >> 3
+ sum += w[ 0] * ((abs(b0) + 3) >> 3);
+ sum += w[ 4] * ((abs(b1) + 3) >> 3);
+ sum += w[ 8] * ((abs(b2) + 3) >> 3);
+ sum += w[12] * ((abs(b3) + 3) >> 3);
+ }
+ return sum;
+}
+
+static int Disto4x4(const uint8_t* const a, const uint8_t* const b,
+ const uint16_t* const w) {
+ const int sum1 = TTransform(a, w);
+ const int sum2 = TTransform(b, w);
+ return (abs(sum2 - sum1) + 8) >> 4;
+}
+
+static int Disto16x16(const uint8_t* const a, const uint8_t* const b,
+ const uint16_t* const w) {
+ int D = 0;
+ int x, y;
+ for (y = 0; y < 16 * BPS; y += 4 * BPS) {
+ for (x = 0; x < 16; x += 4) {
+ D += Disto4x4(a + x + y, b + x + y, w);
+ }
+ }
+ return D;
+}
+
+//------------------------------------------------------------------------------
+// Quantization
+//
+
+static const uint8_t kZigzag[16] = {
+ 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15
+};
+
+// Simple quantization
+static int QuantizeBlock(int16_t in[16], int16_t out[16],
+ int n, const VP8Matrix* const mtx) {
+ int last = -1;
+ for (; n < 16; ++n) {
+ const int j = kZigzag[n];
+ const int sign = (in[j] < 0);
+ int coeff = (sign ? -in[j] : in[j]) + mtx->sharpen_[j];
+ if (coeff > 2047) coeff = 2047;
+ if (coeff > mtx->zthresh_[j]) {
+ const int Q = mtx->q_[j];
+ const int iQ = mtx->iq_[j];
+ const int B = mtx->bias_[j];
+ out[n] = QUANTDIV(coeff, iQ, B);
+ if (sign) out[n] = -out[n];
+ in[j] = out[n] * Q;
+ if (out[n]) last = n;
+ } else {
+ out[n] = 0;
+ in[j] = 0;
+ }
+ }
+ return (last >= 0);
+}
+
+//------------------------------------------------------------------------------
+// Block copy
+
+static WEBP_INLINE void Copy(const uint8_t* src, uint8_t* dst, int size) {
+ int y;
+ for (y = 0; y < size; ++y) {
+ memcpy(dst, src, size);
+ src += BPS;
+ dst += BPS;
+ }
+}
+
+static void Copy4x4(const uint8_t* src, uint8_t* dst) { Copy(src, dst, 4); }
+
+//------------------------------------------------------------------------------
+// Initialization
+
+// Speed-critical function pointers. We have to initialize them to the default
+// implementations within VP8EncDspInit().
+VP8CHisto VP8CollectHistogram;
+VP8Idct VP8ITransform;
+VP8Fdct VP8FTransform;
+VP8WHT VP8ITransformWHT;
+VP8WHT VP8FTransformWHT;
+VP8Intra4Preds VP8EncPredLuma4;
+VP8IntraPreds VP8EncPredLuma16;
+VP8IntraPreds VP8EncPredChroma8;
+VP8Metric VP8SSE16x16;
+VP8Metric VP8SSE8x8;
+VP8Metric VP8SSE16x8;
+VP8Metric VP8SSE4x4;
+VP8WMetric VP8TDisto4x4;
+VP8WMetric VP8TDisto16x16;
+VP8QuantizeBlock VP8EncQuantizeBlock;
+VP8BlockCopy VP8Copy4x4;
+
+extern void VP8EncDspInitSSE2(void);
+
+void VP8EncDspInit(void) {
+ InitTables();
+
+ // default C implementations
+ VP8CollectHistogram = CollectHistogram;
+ VP8ITransform = ITransform;
+ VP8FTransform = FTransform;
+ VP8ITransformWHT = ITransformWHT;
+ VP8FTransformWHT = FTransformWHT;
+ VP8EncPredLuma4 = Intra4Preds;
+ VP8EncPredLuma16 = Intra16Preds;
+ VP8EncPredChroma8 = IntraChromaPreds;
+ VP8SSE16x16 = SSE16x16;
+ VP8SSE8x8 = SSE8x8;
+ VP8SSE16x8 = SSE16x8;
+ VP8SSE4x4 = SSE4x4;
+ VP8TDisto4x4 = Disto4x4;
+ VP8TDisto16x16 = Disto16x16;
+ VP8EncQuantizeBlock = QuantizeBlock;
+ VP8Copy4x4 = Copy4x4;
+
+ // If defined, use CPUInfo() to overwrite some pointers with faster versions.
+ if (VP8GetCPUInfo) {
+#if defined(WEBP_USE_SSE2)
+ if (VP8GetCPUInfo(kSSE2)) {
+ VP8EncDspInitSSE2();
+ }
+#endif
+ }
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/dsp/enc_sse2.c b/drivers/webpold/dsp/enc_sse2.c
new file mode 100644
index 0000000000..b046761dc1
--- /dev/null
+++ b/drivers/webpold/dsp/enc_sse2.c
@@ -0,0 +1,837 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// SSE2 version of speed-critical encoding functions.
+//
+// Author: Christian Duvivier (cduvivier@google.com)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_SSE2)
+#include <stdlib.h> // for abs()
+#include <emmintrin.h>
+
+#include "../enc/vp8enci.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// Compute susceptibility based on DCT-coeff histograms:
+// the higher, the "easier" the macroblock is to compress.
+
+static int CollectHistogramSSE2(const uint8_t* ref, const uint8_t* pred,
+ int start_block, int end_block) {
+ int histo[MAX_COEFF_THRESH + 1] = { 0 };
+ int16_t out[16];
+ int j, k;
+ const __m128i max_coeff_thresh = _mm_set1_epi16(MAX_COEFF_THRESH);
+ for (j = start_block; j < end_block; ++j) {
+ VP8FTransform(ref + VP8DspScan[j], pred + VP8DspScan[j], out);
+
+ // Convert coefficients to bin (within out[]).
+ {
+ // Load.
+ const __m128i out0 = _mm_loadu_si128((__m128i*)&out[0]);
+ const __m128i out1 = _mm_loadu_si128((__m128i*)&out[8]);
+ // sign(out) = out >> 15 (0x0000 if positive, 0xffff if negative)
+ const __m128i sign0 = _mm_srai_epi16(out0, 15);
+ const __m128i sign1 = _mm_srai_epi16(out1, 15);
+ // abs(out) = (out ^ sign) - sign
+ const __m128i xor0 = _mm_xor_si128(out0, sign0);
+ const __m128i xor1 = _mm_xor_si128(out1, sign1);
+ const __m128i abs0 = _mm_sub_epi16(xor0, sign0);
+ const __m128i abs1 = _mm_sub_epi16(xor1, sign1);
+ // v = abs(out) >> 2
+ const __m128i v0 = _mm_srai_epi16(abs0, 2);
+ const __m128i v1 = _mm_srai_epi16(abs1, 2);
+ // bin = min(v, MAX_COEFF_THRESH)
+ const __m128i bin0 = _mm_min_epi16(v0, max_coeff_thresh);
+ const __m128i bin1 = _mm_min_epi16(v1, max_coeff_thresh);
+ // Store.
+ _mm_storeu_si128((__m128i*)&out[0], bin0);
+ _mm_storeu_si128((__m128i*)&out[8], bin1);
+ }
+
+ // Use bin to update histogram.
+ for (k = 0; k < 16; ++k) {
+ histo[out[k]]++;
+ }
+ }
+
+ return VP8GetAlpha(histo);
+}
+
+//------------------------------------------------------------------------------
+// Transforms (Paragraph 14.4)
+
+// Does one or two inverse transforms.
+static void ITransformSSE2(const uint8_t* ref, const int16_t* in, uint8_t* dst,
+ int do_two) {
+ // This implementation makes use of 16-bit fixed point versions of two
+ // multiply constants:
+ // K1 = sqrt(2) * cos (pi/8) ~= 85627 / 2^16
+ // K2 = sqrt(2) * sin (pi/8) ~= 35468 / 2^16
+ //
+ // To be able to use signed 16-bit integers, we use the following trick to
+ // have constants within range:
+ // - Associated constants are obtained by subtracting the 16-bit fixed point
+ // version of one:
+ // k = K - (1 << 16) => K = k + (1 << 16)
+ // K1 = 85267 => k1 = 20091
+ // K2 = 35468 => k2 = -30068
+ // - The multiplication of a variable by a constant become the sum of the
+ // variable and the multiplication of that variable by the associated
+ // constant:
+ // (x * K) >> 16 = (x * (k + (1 << 16))) >> 16 = ((x * k ) >> 16) + x
+ const __m128i k1 = _mm_set1_epi16(20091);
+ const __m128i k2 = _mm_set1_epi16(-30068);
+ __m128i T0, T1, T2, T3;
+
+ // Load and concatenate the transform coefficients (we'll do two inverse
+ // transforms in parallel). In the case of only one inverse transform, the
+ // second half of the vectors will just contain random value we'll never
+ // use nor store.
+ __m128i in0, in1, in2, in3;
+ {
+ in0 = _mm_loadl_epi64((__m128i*)&in[0]);
+ in1 = _mm_loadl_epi64((__m128i*)&in[4]);
+ in2 = _mm_loadl_epi64((__m128i*)&in[8]);
+ in3 = _mm_loadl_epi64((__m128i*)&in[12]);
+ // a00 a10 a20 a30 x x x x
+ // a01 a11 a21 a31 x x x x
+ // a02 a12 a22 a32 x x x x
+ // a03 a13 a23 a33 x x x x
+ if (do_two) {
+ const __m128i inB0 = _mm_loadl_epi64((__m128i*)&in[16]);
+ const __m128i inB1 = _mm_loadl_epi64((__m128i*)&in[20]);
+ const __m128i inB2 = _mm_loadl_epi64((__m128i*)&in[24]);
+ const __m128i inB3 = _mm_loadl_epi64((__m128i*)&in[28]);
+ in0 = _mm_unpacklo_epi64(in0, inB0);
+ in1 = _mm_unpacklo_epi64(in1, inB1);
+ in2 = _mm_unpacklo_epi64(in2, inB2);
+ in3 = _mm_unpacklo_epi64(in3, inB3);
+ // a00 a10 a20 a30 b00 b10 b20 b30
+ // a01 a11 a21 a31 b01 b11 b21 b31
+ // a02 a12 a22 a32 b02 b12 b22 b32
+ // a03 a13 a23 a33 b03 b13 b23 b33
+ }
+ }
+
+ // Vertical pass and subsequent transpose.
+ {
+ // First pass, c and d calculations are longer because of the "trick"
+ // multiplications.
+ const __m128i a = _mm_add_epi16(in0, in2);
+ const __m128i b = _mm_sub_epi16(in0, in2);
+ // c = MUL(in1, K2) - MUL(in3, K1) = MUL(in1, k2) - MUL(in3, k1) + in1 - in3
+ const __m128i c1 = _mm_mulhi_epi16(in1, k2);
+ const __m128i c2 = _mm_mulhi_epi16(in3, k1);
+ const __m128i c3 = _mm_sub_epi16(in1, in3);
+ const __m128i c4 = _mm_sub_epi16(c1, c2);
+ const __m128i c = _mm_add_epi16(c3, c4);
+ // d = MUL(in1, K1) + MUL(in3, K2) = MUL(in1, k1) + MUL(in3, k2) + in1 + in3
+ const __m128i d1 = _mm_mulhi_epi16(in1, k1);
+ const __m128i d2 = _mm_mulhi_epi16(in3, k2);
+ const __m128i d3 = _mm_add_epi16(in1, in3);
+ const __m128i d4 = _mm_add_epi16(d1, d2);
+ const __m128i d = _mm_add_epi16(d3, d4);
+
+ // Second pass.
+ const __m128i tmp0 = _mm_add_epi16(a, d);
+ const __m128i tmp1 = _mm_add_epi16(b, c);
+ const __m128i tmp2 = _mm_sub_epi16(b, c);
+ const __m128i tmp3 = _mm_sub_epi16(a, d);
+
+ // Transpose the two 4x4.
+ // a00 a01 a02 a03 b00 b01 b02 b03
+ // a10 a11 a12 a13 b10 b11 b12 b13
+ // a20 a21 a22 a23 b20 b21 b22 b23
+ // a30 a31 a32 a33 b30 b31 b32 b33
+ const __m128i transpose0_0 = _mm_unpacklo_epi16(tmp0, tmp1);
+ const __m128i transpose0_1 = _mm_unpacklo_epi16(tmp2, tmp3);
+ const __m128i transpose0_2 = _mm_unpackhi_epi16(tmp0, tmp1);
+ const __m128i transpose0_3 = _mm_unpackhi_epi16(tmp2, tmp3);
+ // a00 a10 a01 a11 a02 a12 a03 a13
+ // a20 a30 a21 a31 a22 a32 a23 a33
+ // b00 b10 b01 b11 b02 b12 b03 b13
+ // b20 b30 b21 b31 b22 b32 b23 b33
+ const __m128i transpose1_0 = _mm_unpacklo_epi32(transpose0_0, transpose0_1);
+ const __m128i transpose1_1 = _mm_unpacklo_epi32(transpose0_2, transpose0_3);
+ const __m128i transpose1_2 = _mm_unpackhi_epi32(transpose0_0, transpose0_1);
+ const __m128i transpose1_3 = _mm_unpackhi_epi32(transpose0_2, transpose0_3);
+ // a00 a10 a20 a30 a01 a11 a21 a31
+ // b00 b10 b20 b30 b01 b11 b21 b31
+ // a02 a12 a22 a32 a03 a13 a23 a33
+ // b02 b12 a22 b32 b03 b13 b23 b33
+ T0 = _mm_unpacklo_epi64(transpose1_0, transpose1_1);
+ T1 = _mm_unpackhi_epi64(transpose1_0, transpose1_1);
+ T2 = _mm_unpacklo_epi64(transpose1_2, transpose1_3);
+ T3 = _mm_unpackhi_epi64(transpose1_2, transpose1_3);
+ // a00 a10 a20 a30 b00 b10 b20 b30
+ // a01 a11 a21 a31 b01 b11 b21 b31
+ // a02 a12 a22 a32 b02 b12 b22 b32
+ // a03 a13 a23 a33 b03 b13 b23 b33
+ }
+
+ // Horizontal pass and subsequent transpose.
+ {
+ // First pass, c and d calculations are longer because of the "trick"
+ // multiplications.
+ const __m128i four = _mm_set1_epi16(4);
+ const __m128i dc = _mm_add_epi16(T0, four);
+ const __m128i a = _mm_add_epi16(dc, T2);
+ const __m128i b = _mm_sub_epi16(dc, T2);
+ // c = MUL(T1, K2) - MUL(T3, K1) = MUL(T1, k2) - MUL(T3, k1) + T1 - T3
+ const __m128i c1 = _mm_mulhi_epi16(T1, k2);
+ const __m128i c2 = _mm_mulhi_epi16(T3, k1);
+ const __m128i c3 = _mm_sub_epi16(T1, T3);
+ const __m128i c4 = _mm_sub_epi16(c1, c2);
+ const __m128i c = _mm_add_epi16(c3, c4);
+ // d = MUL(T1, K1) + MUL(T3, K2) = MUL(T1, k1) + MUL(T3, k2) + T1 + T3
+ const __m128i d1 = _mm_mulhi_epi16(T1, k1);
+ const __m128i d2 = _mm_mulhi_epi16(T3, k2);
+ const __m128i d3 = _mm_add_epi16(T1, T3);
+ const __m128i d4 = _mm_add_epi16(d1, d2);
+ const __m128i d = _mm_add_epi16(d3, d4);
+
+ // Second pass.
+ const __m128i tmp0 = _mm_add_epi16(a, d);
+ const __m128i tmp1 = _mm_add_epi16(b, c);
+ const __m128i tmp2 = _mm_sub_epi16(b, c);
+ const __m128i tmp3 = _mm_sub_epi16(a, d);
+ const __m128i shifted0 = _mm_srai_epi16(tmp0, 3);
+ const __m128i shifted1 = _mm_srai_epi16(tmp1, 3);
+ const __m128i shifted2 = _mm_srai_epi16(tmp2, 3);
+ const __m128i shifted3 = _mm_srai_epi16(tmp3, 3);
+
+ // Transpose the two 4x4.
+ // a00 a01 a02 a03 b00 b01 b02 b03
+ // a10 a11 a12 a13 b10 b11 b12 b13
+ // a20 a21 a22 a23 b20 b21 b22 b23
+ // a30 a31 a32 a33 b30 b31 b32 b33
+ const __m128i transpose0_0 = _mm_unpacklo_epi16(shifted0, shifted1);
+ const __m128i transpose0_1 = _mm_unpacklo_epi16(shifted2, shifted3);
+ const __m128i transpose0_2 = _mm_unpackhi_epi16(shifted0, shifted1);
+ const __m128i transpose0_3 = _mm_unpackhi_epi16(shifted2, shifted3);
+ // a00 a10 a01 a11 a02 a12 a03 a13
+ // a20 a30 a21 a31 a22 a32 a23 a33
+ // b00 b10 b01 b11 b02 b12 b03 b13
+ // b20 b30 b21 b31 b22 b32 b23 b33
+ const __m128i transpose1_0 = _mm_unpacklo_epi32(transpose0_0, transpose0_1);
+ const __m128i transpose1_1 = _mm_unpacklo_epi32(transpose0_2, transpose0_3);
+ const __m128i transpose1_2 = _mm_unpackhi_epi32(transpose0_0, transpose0_1);
+ const __m128i transpose1_3 = _mm_unpackhi_epi32(transpose0_2, transpose0_3);
+ // a00 a10 a20 a30 a01 a11 a21 a31
+ // b00 b10 b20 b30 b01 b11 b21 b31
+ // a02 a12 a22 a32 a03 a13 a23 a33
+ // b02 b12 a22 b32 b03 b13 b23 b33
+ T0 = _mm_unpacklo_epi64(transpose1_0, transpose1_1);
+ T1 = _mm_unpackhi_epi64(transpose1_0, transpose1_1);
+ T2 = _mm_unpacklo_epi64(transpose1_2, transpose1_3);
+ T3 = _mm_unpackhi_epi64(transpose1_2, transpose1_3);
+ // a00 a10 a20 a30 b00 b10 b20 b30
+ // a01 a11 a21 a31 b01 b11 b21 b31
+ // a02 a12 a22 a32 b02 b12 b22 b32
+ // a03 a13 a23 a33 b03 b13 b23 b33
+ }
+
+ // Add inverse transform to 'ref' and store.
+ {
+ const __m128i zero = _mm_set1_epi16(0);
+ // Load the reference(s).
+ __m128i ref0, ref1, ref2, ref3;
+ if (do_two) {
+ // Load eight bytes/pixels per line.
+ ref0 = _mm_loadl_epi64((__m128i*)&ref[0 * BPS]);
+ ref1 = _mm_loadl_epi64((__m128i*)&ref[1 * BPS]);
+ ref2 = _mm_loadl_epi64((__m128i*)&ref[2 * BPS]);
+ ref3 = _mm_loadl_epi64((__m128i*)&ref[3 * BPS]);
+ } else {
+ // Load four bytes/pixels per line.
+ ref0 = _mm_cvtsi32_si128(*(int*)&ref[0 * BPS]);
+ ref1 = _mm_cvtsi32_si128(*(int*)&ref[1 * BPS]);
+ ref2 = _mm_cvtsi32_si128(*(int*)&ref[2 * BPS]);
+ ref3 = _mm_cvtsi32_si128(*(int*)&ref[3 * BPS]);
+ }
+ // Convert to 16b.
+ ref0 = _mm_unpacklo_epi8(ref0, zero);
+ ref1 = _mm_unpacklo_epi8(ref1, zero);
+ ref2 = _mm_unpacklo_epi8(ref2, zero);
+ ref3 = _mm_unpacklo_epi8(ref3, zero);
+ // Add the inverse transform(s).
+ ref0 = _mm_add_epi16(ref0, T0);
+ ref1 = _mm_add_epi16(ref1, T1);
+ ref2 = _mm_add_epi16(ref2, T2);
+ ref3 = _mm_add_epi16(ref3, T3);
+ // Unsigned saturate to 8b.
+ ref0 = _mm_packus_epi16(ref0, ref0);
+ ref1 = _mm_packus_epi16(ref1, ref1);
+ ref2 = _mm_packus_epi16(ref2, ref2);
+ ref3 = _mm_packus_epi16(ref3, ref3);
+ // Store the results.
+ if (do_two) {
+ // Store eight bytes/pixels per line.
+ _mm_storel_epi64((__m128i*)&dst[0 * BPS], ref0);
+ _mm_storel_epi64((__m128i*)&dst[1 * BPS], ref1);
+ _mm_storel_epi64((__m128i*)&dst[2 * BPS], ref2);
+ _mm_storel_epi64((__m128i*)&dst[3 * BPS], ref3);
+ } else {
+ // Store four bytes/pixels per line.
+ *((int32_t *)&dst[0 * BPS]) = _mm_cvtsi128_si32(ref0);
+ *((int32_t *)&dst[1 * BPS]) = _mm_cvtsi128_si32(ref1);
+ *((int32_t *)&dst[2 * BPS]) = _mm_cvtsi128_si32(ref2);
+ *((int32_t *)&dst[3 * BPS]) = _mm_cvtsi128_si32(ref3);
+ }
+ }
+}
+
+static void FTransformSSE2(const uint8_t* src, const uint8_t* ref,
+ int16_t* out) {
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i seven = _mm_set1_epi16(7);
+ const __m128i k7500 = _mm_set1_epi32(7500);
+ const __m128i k14500 = _mm_set1_epi32(14500);
+ const __m128i k51000 = _mm_set1_epi32(51000);
+ const __m128i k12000_plus_one = _mm_set1_epi32(12000 + (1 << 16));
+ const __m128i k5352_2217 = _mm_set_epi16(5352, 2217, 5352, 2217,
+ 5352, 2217, 5352, 2217);
+ const __m128i k2217_5352 = _mm_set_epi16(2217, -5352, 2217, -5352,
+ 2217, -5352, 2217, -5352);
+
+ __m128i v01, v32;
+
+ // Difference between src and ref and initial transpose.
+ {
+ // Load src and convert to 16b.
+ const __m128i src0 = _mm_loadl_epi64((__m128i*)&src[0 * BPS]);
+ const __m128i src1 = _mm_loadl_epi64((__m128i*)&src[1 * BPS]);
+ const __m128i src2 = _mm_loadl_epi64((__m128i*)&src[2 * BPS]);
+ const __m128i src3 = _mm_loadl_epi64((__m128i*)&src[3 * BPS]);
+ const __m128i src_0 = _mm_unpacklo_epi8(src0, zero);
+ const __m128i src_1 = _mm_unpacklo_epi8(src1, zero);
+ const __m128i src_2 = _mm_unpacklo_epi8(src2, zero);
+ const __m128i src_3 = _mm_unpacklo_epi8(src3, zero);
+ // Load ref and convert to 16b.
+ const __m128i ref0 = _mm_loadl_epi64((__m128i*)&ref[0 * BPS]);
+ const __m128i ref1 = _mm_loadl_epi64((__m128i*)&ref[1 * BPS]);
+ const __m128i ref2 = _mm_loadl_epi64((__m128i*)&ref[2 * BPS]);
+ const __m128i ref3 = _mm_loadl_epi64((__m128i*)&ref[3 * BPS]);
+ const __m128i ref_0 = _mm_unpacklo_epi8(ref0, zero);
+ const __m128i ref_1 = _mm_unpacklo_epi8(ref1, zero);
+ const __m128i ref_2 = _mm_unpacklo_epi8(ref2, zero);
+ const __m128i ref_3 = _mm_unpacklo_epi8(ref3, zero);
+ // Compute difference.
+ const __m128i diff0 = _mm_sub_epi16(src_0, ref_0);
+ const __m128i diff1 = _mm_sub_epi16(src_1, ref_1);
+ const __m128i diff2 = _mm_sub_epi16(src_2, ref_2);
+ const __m128i diff3 = _mm_sub_epi16(src_3, ref_3);
+
+ // Transpose.
+ // 00 01 02 03 0 0 0 0
+ // 10 11 12 13 0 0 0 0
+ // 20 21 22 23 0 0 0 0
+ // 30 31 32 33 0 0 0 0
+ const __m128i transpose0_0 = _mm_unpacklo_epi16(diff0, diff1);
+ const __m128i transpose0_1 = _mm_unpacklo_epi16(diff2, diff3);
+ // 00 10 01 11 02 12 03 13
+ // 20 30 21 31 22 32 23 33
+ const __m128i v23 = _mm_unpackhi_epi32(transpose0_0, transpose0_1);
+ v01 = _mm_unpacklo_epi32(transpose0_0, transpose0_1);
+ v32 = _mm_shuffle_epi32(v23, _MM_SHUFFLE(1, 0, 3, 2));
+ // a02 a12 a22 a32 a03 a13 a23 a33
+ // a00 a10 a20 a30 a01 a11 a21 a31
+ // a03 a13 a23 a33 a02 a12 a22 a32
+ }
+
+ // First pass and subsequent transpose.
+ {
+ // Same operations are done on the (0,3) and (1,2) pairs.
+ // b0 = (a0 + a3) << 3
+ // b1 = (a1 + a2) << 3
+ // b3 = (a0 - a3) << 3
+ // b2 = (a1 - a2) << 3
+ const __m128i a01 = _mm_add_epi16(v01, v32);
+ const __m128i a32 = _mm_sub_epi16(v01, v32);
+ const __m128i b01 = _mm_slli_epi16(a01, 3);
+ const __m128i b32 = _mm_slli_epi16(a32, 3);
+ const __m128i b11 = _mm_unpackhi_epi64(b01, b01);
+ const __m128i b22 = _mm_unpackhi_epi64(b32, b32);
+
+ // e0 = b0 + b1
+ // e2 = b0 - b1
+ const __m128i e0 = _mm_add_epi16(b01, b11);
+ const __m128i e2 = _mm_sub_epi16(b01, b11);
+ const __m128i e02 = _mm_unpacklo_epi64(e0, e2);
+
+ // e1 = (b3 * 5352 + b2 * 2217 + 14500) >> 12
+ // e3 = (b3 * 2217 - b2 * 5352 + 7500) >> 12
+ const __m128i b23 = _mm_unpacklo_epi16(b22, b32);
+ const __m128i c1 = _mm_madd_epi16(b23, k5352_2217);
+ const __m128i c3 = _mm_madd_epi16(b23, k2217_5352);
+ const __m128i d1 = _mm_add_epi32(c1, k14500);
+ const __m128i d3 = _mm_add_epi32(c3, k7500);
+ const __m128i e1 = _mm_srai_epi32(d1, 12);
+ const __m128i e3 = _mm_srai_epi32(d3, 12);
+ const __m128i e13 = _mm_packs_epi32(e1, e3);
+
+ // Transpose.
+ // 00 01 02 03 20 21 22 23
+ // 10 11 12 13 30 31 32 33
+ const __m128i transpose0_0 = _mm_unpacklo_epi16(e02, e13);
+ const __m128i transpose0_1 = _mm_unpackhi_epi16(e02, e13);
+ // 00 10 01 11 02 12 03 13
+ // 20 30 21 31 22 32 23 33
+ const __m128i v23 = _mm_unpackhi_epi32(transpose0_0, transpose0_1);
+ v01 = _mm_unpacklo_epi32(transpose0_0, transpose0_1);
+ v32 = _mm_shuffle_epi32(v23, _MM_SHUFFLE(1, 0, 3, 2));
+ // 02 12 22 32 03 13 23 33
+ // 00 10 20 30 01 11 21 31
+ // 03 13 23 33 02 12 22 32
+ }
+
+ // Second pass
+ {
+ // Same operations are done on the (0,3) and (1,2) pairs.
+ // a0 = v0 + v3
+ // a1 = v1 + v2
+ // a3 = v0 - v3
+ // a2 = v1 - v2
+ const __m128i a01 = _mm_add_epi16(v01, v32);
+ const __m128i a32 = _mm_sub_epi16(v01, v32);
+ const __m128i a11 = _mm_unpackhi_epi64(a01, a01);
+ const __m128i a22 = _mm_unpackhi_epi64(a32, a32);
+
+ // d0 = (a0 + a1 + 7) >> 4;
+ // d2 = (a0 - a1 + 7) >> 4;
+ const __m128i b0 = _mm_add_epi16(a01, a11);
+ const __m128i b2 = _mm_sub_epi16(a01, a11);
+ const __m128i c0 = _mm_add_epi16(b0, seven);
+ const __m128i c2 = _mm_add_epi16(b2, seven);
+ const __m128i d0 = _mm_srai_epi16(c0, 4);
+ const __m128i d2 = _mm_srai_epi16(c2, 4);
+
+ // f1 = ((b3 * 5352 + b2 * 2217 + 12000) >> 16)
+ // f3 = ((b3 * 2217 - b2 * 5352 + 51000) >> 16)
+ const __m128i b23 = _mm_unpacklo_epi16(a22, a32);
+ const __m128i c1 = _mm_madd_epi16(b23, k5352_2217);
+ const __m128i c3 = _mm_madd_epi16(b23, k2217_5352);
+ const __m128i d1 = _mm_add_epi32(c1, k12000_plus_one);
+ const __m128i d3 = _mm_add_epi32(c3, k51000);
+ const __m128i e1 = _mm_srai_epi32(d1, 16);
+ const __m128i e3 = _mm_srai_epi32(d3, 16);
+ const __m128i f1 = _mm_packs_epi32(e1, e1);
+ const __m128i f3 = _mm_packs_epi32(e3, e3);
+ // f1 = f1 + (a3 != 0);
+ // The compare will return (0xffff, 0) for (==0, !=0). To turn that into the
+ // desired (0, 1), we add one earlier through k12000_plus_one.
+ const __m128i g1 = _mm_add_epi16(f1, _mm_cmpeq_epi16(a32, zero));
+
+ _mm_storel_epi64((__m128i*)&out[ 0], d0);
+ _mm_storel_epi64((__m128i*)&out[ 4], g1);
+ _mm_storel_epi64((__m128i*)&out[ 8], d2);
+ _mm_storel_epi64((__m128i*)&out[12], f3);
+ }
+}
+
+//------------------------------------------------------------------------------
+// Metric
+
+static int SSE4x4SSE2(const uint8_t* a, const uint8_t* b) {
+ const __m128i zero = _mm_set1_epi16(0);
+
+ // Load values.
+ const __m128i a0 = _mm_loadl_epi64((__m128i*)&a[BPS * 0]);
+ const __m128i a1 = _mm_loadl_epi64((__m128i*)&a[BPS * 1]);
+ const __m128i a2 = _mm_loadl_epi64((__m128i*)&a[BPS * 2]);
+ const __m128i a3 = _mm_loadl_epi64((__m128i*)&a[BPS * 3]);
+ const __m128i b0 = _mm_loadl_epi64((__m128i*)&b[BPS * 0]);
+ const __m128i b1 = _mm_loadl_epi64((__m128i*)&b[BPS * 1]);
+ const __m128i b2 = _mm_loadl_epi64((__m128i*)&b[BPS * 2]);
+ const __m128i b3 = _mm_loadl_epi64((__m128i*)&b[BPS * 3]);
+
+ // Combine pair of lines and convert to 16b.
+ const __m128i a01 = _mm_unpacklo_epi32(a0, a1);
+ const __m128i a23 = _mm_unpacklo_epi32(a2, a3);
+ const __m128i b01 = _mm_unpacklo_epi32(b0, b1);
+ const __m128i b23 = _mm_unpacklo_epi32(b2, b3);
+ const __m128i a01s = _mm_unpacklo_epi8(a01, zero);
+ const __m128i a23s = _mm_unpacklo_epi8(a23, zero);
+ const __m128i b01s = _mm_unpacklo_epi8(b01, zero);
+ const __m128i b23s = _mm_unpacklo_epi8(b23, zero);
+
+ // Compute differences; (a-b)^2 = (abs(a-b))^2 = (sat8(a-b) + sat8(b-a))^2
+ // TODO(cduvivier): Dissassemble and figure out why this is fastest. We don't
+ // need absolute values, there is no need to do calculation
+ // in 8bit as we are already in 16bit, ... Yet this is what
+ // benchmarks the fastest!
+ const __m128i d0 = _mm_subs_epu8(a01s, b01s);
+ const __m128i d1 = _mm_subs_epu8(b01s, a01s);
+ const __m128i d2 = _mm_subs_epu8(a23s, b23s);
+ const __m128i d3 = _mm_subs_epu8(b23s, a23s);
+
+ // Square and add them all together.
+ const __m128i madd0 = _mm_madd_epi16(d0, d0);
+ const __m128i madd1 = _mm_madd_epi16(d1, d1);
+ const __m128i madd2 = _mm_madd_epi16(d2, d2);
+ const __m128i madd3 = _mm_madd_epi16(d3, d3);
+ const __m128i sum0 = _mm_add_epi32(madd0, madd1);
+ const __m128i sum1 = _mm_add_epi32(madd2, madd3);
+ const __m128i sum2 = _mm_add_epi32(sum0, sum1);
+ int32_t tmp[4];
+ _mm_storeu_si128((__m128i*)tmp, sum2);
+ return (tmp[3] + tmp[2] + tmp[1] + tmp[0]);
+}
+
+//------------------------------------------------------------------------------
+// Texture distortion
+//
+// We try to match the spectral content (weighted) between source and
+// reconstructed samples.
+
+// Hadamard transform
+// Returns the difference between the weighted sum of the absolute value of
+// transformed coefficients.
+static int TTransformSSE2(const uint8_t* inA, const uint8_t* inB,
+ const uint16_t* const w) {
+ int32_t sum[4];
+ __m128i tmp_0, tmp_1, tmp_2, tmp_3;
+ const __m128i zero = _mm_setzero_si128();
+ const __m128i one = _mm_set1_epi16(1);
+ const __m128i three = _mm_set1_epi16(3);
+
+ // Load, combine and tranpose inputs.
+ {
+ const __m128i inA_0 = _mm_loadl_epi64((__m128i*)&inA[BPS * 0]);
+ const __m128i inA_1 = _mm_loadl_epi64((__m128i*)&inA[BPS * 1]);
+ const __m128i inA_2 = _mm_loadl_epi64((__m128i*)&inA[BPS * 2]);
+ const __m128i inA_3 = _mm_loadl_epi64((__m128i*)&inA[BPS * 3]);
+ const __m128i inB_0 = _mm_loadl_epi64((__m128i*)&inB[BPS * 0]);
+ const __m128i inB_1 = _mm_loadl_epi64((__m128i*)&inB[BPS * 1]);
+ const __m128i inB_2 = _mm_loadl_epi64((__m128i*)&inB[BPS * 2]);
+ const __m128i inB_3 = _mm_loadl_epi64((__m128i*)&inB[BPS * 3]);
+
+ // Combine inA and inB (we'll do two transforms in parallel).
+ const __m128i inAB_0 = _mm_unpacklo_epi8(inA_0, inB_0);
+ const __m128i inAB_1 = _mm_unpacklo_epi8(inA_1, inB_1);
+ const __m128i inAB_2 = _mm_unpacklo_epi8(inA_2, inB_2);
+ const __m128i inAB_3 = _mm_unpacklo_epi8(inA_3, inB_3);
+ // a00 b00 a01 b01 a02 b03 a03 b03 0 0 0 0 0 0 0 0
+ // a10 b10 a11 b11 a12 b12 a13 b13 0 0 0 0 0 0 0 0
+ // a20 b20 a21 b21 a22 b22 a23 b23 0 0 0 0 0 0 0 0
+ // a30 b30 a31 b31 a32 b32 a33 b33 0 0 0 0 0 0 0 0
+
+ // Transpose the two 4x4, discarding the filling zeroes.
+ const __m128i transpose0_0 = _mm_unpacklo_epi8(inAB_0, inAB_2);
+ const __m128i transpose0_1 = _mm_unpacklo_epi8(inAB_1, inAB_3);
+ // a00 a20 b00 b20 a01 a21 b01 b21 a02 a22 b02 b22 a03 a23 b03 b23
+ // a10 a30 b10 b30 a11 a31 b11 b31 a12 a32 b12 b32 a13 a33 b13 b33
+ const __m128i transpose1_0 = _mm_unpacklo_epi8(transpose0_0, transpose0_1);
+ const __m128i transpose1_1 = _mm_unpackhi_epi8(transpose0_0, transpose0_1);
+ // a00 a10 a20 a30 b00 b10 b20 b30 a01 a11 a21 a31 b01 b11 b21 b31
+ // a02 a12 a22 a32 b02 b12 b22 b32 a03 a13 a23 a33 b03 b13 b23 b33
+
+ // Convert to 16b.
+ tmp_0 = _mm_unpacklo_epi8(transpose1_0, zero);
+ tmp_1 = _mm_unpackhi_epi8(transpose1_0, zero);
+ tmp_2 = _mm_unpacklo_epi8(transpose1_1, zero);
+ tmp_3 = _mm_unpackhi_epi8(transpose1_1, zero);
+ // a00 a10 a20 a30 b00 b10 b20 b30
+ // a01 a11 a21 a31 b01 b11 b21 b31
+ // a02 a12 a22 a32 b02 b12 b22 b32
+ // a03 a13 a23 a33 b03 b13 b23 b33
+ }
+
+ // Horizontal pass and subsequent transpose.
+ {
+ // Calculate a and b (two 4x4 at once).
+ const __m128i a0 = _mm_slli_epi16(_mm_add_epi16(tmp_0, tmp_2), 2);
+ const __m128i a1 = _mm_slli_epi16(_mm_add_epi16(tmp_1, tmp_3), 2);
+ const __m128i a2 = _mm_slli_epi16(_mm_sub_epi16(tmp_1, tmp_3), 2);
+ const __m128i a3 = _mm_slli_epi16(_mm_sub_epi16(tmp_0, tmp_2), 2);
+ // b0_extra = (a0 != 0);
+ const __m128i b0_extra = _mm_andnot_si128(_mm_cmpeq_epi16 (a0, zero), one);
+ const __m128i b0_base = _mm_add_epi16(a0, a1);
+ const __m128i b1 = _mm_add_epi16(a3, a2);
+ const __m128i b2 = _mm_sub_epi16(a3, a2);
+ const __m128i b3 = _mm_sub_epi16(a0, a1);
+ const __m128i b0 = _mm_add_epi16(b0_base, b0_extra);
+ // a00 a01 a02 a03 b00 b01 b02 b03
+ // a10 a11 a12 a13 b10 b11 b12 b13
+ // a20 a21 a22 a23 b20 b21 b22 b23
+ // a30 a31 a32 a33 b30 b31 b32 b33
+
+ // Transpose the two 4x4.
+ const __m128i transpose0_0 = _mm_unpacklo_epi16(b0, b1);
+ const __m128i transpose0_1 = _mm_unpacklo_epi16(b2, b3);
+ const __m128i transpose0_2 = _mm_unpackhi_epi16(b0, b1);
+ const __m128i transpose0_3 = _mm_unpackhi_epi16(b2, b3);
+ // a00 a10 a01 a11 a02 a12 a03 a13
+ // a20 a30 a21 a31 a22 a32 a23 a33
+ // b00 b10 b01 b11 b02 b12 b03 b13
+ // b20 b30 b21 b31 b22 b32 b23 b33
+ const __m128i transpose1_0 = _mm_unpacklo_epi32(transpose0_0, transpose0_1);
+ const __m128i transpose1_1 = _mm_unpacklo_epi32(transpose0_2, transpose0_3);
+ const __m128i transpose1_2 = _mm_unpackhi_epi32(transpose0_0, transpose0_1);
+ const __m128i transpose1_3 = _mm_unpackhi_epi32(transpose0_2, transpose0_3);
+ // a00 a10 a20 a30 a01 a11 a21 a31
+ // b00 b10 b20 b30 b01 b11 b21 b31
+ // a02 a12 a22 a32 a03 a13 a23 a33
+ // b02 b12 a22 b32 b03 b13 b23 b33
+ tmp_0 = _mm_unpacklo_epi64(transpose1_0, transpose1_1);
+ tmp_1 = _mm_unpackhi_epi64(transpose1_0, transpose1_1);
+ tmp_2 = _mm_unpacklo_epi64(transpose1_2, transpose1_3);
+ tmp_3 = _mm_unpackhi_epi64(transpose1_2, transpose1_3);
+ // a00 a10 a20 a30 b00 b10 b20 b30
+ // a01 a11 a21 a31 b01 b11 b21 b31
+ // a02 a12 a22 a32 b02 b12 b22 b32
+ // a03 a13 a23 a33 b03 b13 b23 b33
+ }
+
+ // Vertical pass and difference of weighted sums.
+ {
+ // Load all inputs.
+ // TODO(cduvivier): Make variable declarations and allocations aligned so
+ // we can use _mm_load_si128 instead of _mm_loadu_si128.
+ const __m128i w_0 = _mm_loadu_si128((__m128i*)&w[0]);
+ const __m128i w_8 = _mm_loadu_si128((__m128i*)&w[8]);
+
+ // Calculate a and b (two 4x4 at once).
+ const __m128i a0 = _mm_add_epi16(tmp_0, tmp_2);
+ const __m128i a1 = _mm_add_epi16(tmp_1, tmp_3);
+ const __m128i a2 = _mm_sub_epi16(tmp_1, tmp_3);
+ const __m128i a3 = _mm_sub_epi16(tmp_0, tmp_2);
+ const __m128i b0 = _mm_add_epi16(a0, a1);
+ const __m128i b1 = _mm_add_epi16(a3, a2);
+ const __m128i b2 = _mm_sub_epi16(a3, a2);
+ const __m128i b3 = _mm_sub_epi16(a0, a1);
+
+ // Separate the transforms of inA and inB.
+ __m128i A_b0 = _mm_unpacklo_epi64(b0, b1);
+ __m128i A_b2 = _mm_unpacklo_epi64(b2, b3);
+ __m128i B_b0 = _mm_unpackhi_epi64(b0, b1);
+ __m128i B_b2 = _mm_unpackhi_epi64(b2, b3);
+
+ {
+ // sign(b) = b >> 15 (0x0000 if positive, 0xffff if negative)
+ const __m128i sign_A_b0 = _mm_srai_epi16(A_b0, 15);
+ const __m128i sign_A_b2 = _mm_srai_epi16(A_b2, 15);
+ const __m128i sign_B_b0 = _mm_srai_epi16(B_b0, 15);
+ const __m128i sign_B_b2 = _mm_srai_epi16(B_b2, 15);
+
+ // b = abs(b) = (b ^ sign) - sign
+ A_b0 = _mm_xor_si128(A_b0, sign_A_b0);
+ A_b2 = _mm_xor_si128(A_b2, sign_A_b2);
+ B_b0 = _mm_xor_si128(B_b0, sign_B_b0);
+ B_b2 = _mm_xor_si128(B_b2, sign_B_b2);
+ A_b0 = _mm_sub_epi16(A_b0, sign_A_b0);
+ A_b2 = _mm_sub_epi16(A_b2, sign_A_b2);
+ B_b0 = _mm_sub_epi16(B_b0, sign_B_b0);
+ B_b2 = _mm_sub_epi16(B_b2, sign_B_b2);
+ }
+
+ // b = abs(b) + 3
+ A_b0 = _mm_add_epi16(A_b0, three);
+ A_b2 = _mm_add_epi16(A_b2, three);
+ B_b0 = _mm_add_epi16(B_b0, three);
+ B_b2 = _mm_add_epi16(B_b2, three);
+
+ // abs((b + (b<0) + 3) >> 3) = (abs(b) + 3) >> 3
+ // b = (abs(b) + 3) >> 3
+ A_b0 = _mm_srai_epi16(A_b0, 3);
+ A_b2 = _mm_srai_epi16(A_b2, 3);
+ B_b0 = _mm_srai_epi16(B_b0, 3);
+ B_b2 = _mm_srai_epi16(B_b2, 3);
+
+ // weighted sums
+ A_b0 = _mm_madd_epi16(A_b0, w_0);
+ A_b2 = _mm_madd_epi16(A_b2, w_8);
+ B_b0 = _mm_madd_epi16(B_b0, w_0);
+ B_b2 = _mm_madd_epi16(B_b2, w_8);
+ A_b0 = _mm_add_epi32(A_b0, A_b2);
+ B_b0 = _mm_add_epi32(B_b0, B_b2);
+
+ // difference of weighted sums
+ A_b0 = _mm_sub_epi32(A_b0, B_b0);
+ _mm_storeu_si128((__m128i*)&sum[0], A_b0);
+ }
+ return sum[0] + sum[1] + sum[2] + sum[3];
+}
+
+static int Disto4x4SSE2(const uint8_t* const a, const uint8_t* const b,
+ const uint16_t* const w) {
+ const int diff_sum = TTransformSSE2(a, b, w);
+ return (abs(diff_sum) + 8) >> 4;
+}
+
+static int Disto16x16SSE2(const uint8_t* const a, const uint8_t* const b,
+ const uint16_t* const w) {
+ int D = 0;
+ int x, y;
+ for (y = 0; y < 16 * BPS; y += 4 * BPS) {
+ for (x = 0; x < 16; x += 4) {
+ D += Disto4x4SSE2(a + x + y, b + x + y, w);
+ }
+ }
+ return D;
+}
+
+
+//------------------------------------------------------------------------------
+// Quantization
+//
+
+// Simple quantization
+static int QuantizeBlockSSE2(int16_t in[16], int16_t out[16],
+ int n, const VP8Matrix* const mtx) {
+ const __m128i max_coeff_2047 = _mm_set1_epi16(2047);
+ const __m128i zero = _mm_set1_epi16(0);
+ __m128i sign0, sign8;
+ __m128i coeff0, coeff8;
+ __m128i out0, out8;
+ __m128i packed_out;
+
+ // Load all inputs.
+ // TODO(cduvivier): Make variable declarations and allocations aligned so that
+ // we can use _mm_load_si128 instead of _mm_loadu_si128.
+ __m128i in0 = _mm_loadu_si128((__m128i*)&in[0]);
+ __m128i in8 = _mm_loadu_si128((__m128i*)&in[8]);
+ const __m128i sharpen0 = _mm_loadu_si128((__m128i*)&mtx->sharpen_[0]);
+ const __m128i sharpen8 = _mm_loadu_si128((__m128i*)&mtx->sharpen_[8]);
+ const __m128i iq0 = _mm_loadu_si128((__m128i*)&mtx->iq_[0]);
+ const __m128i iq8 = _mm_loadu_si128((__m128i*)&mtx->iq_[8]);
+ const __m128i bias0 = _mm_loadu_si128((__m128i*)&mtx->bias_[0]);
+ const __m128i bias8 = _mm_loadu_si128((__m128i*)&mtx->bias_[8]);
+ const __m128i q0 = _mm_loadu_si128((__m128i*)&mtx->q_[0]);
+ const __m128i q8 = _mm_loadu_si128((__m128i*)&mtx->q_[8]);
+ const __m128i zthresh0 = _mm_loadu_si128((__m128i*)&mtx->zthresh_[0]);
+ const __m128i zthresh8 = _mm_loadu_si128((__m128i*)&mtx->zthresh_[8]);
+
+ // sign(in) = in >> 15 (0x0000 if positive, 0xffff if negative)
+ sign0 = _mm_srai_epi16(in0, 15);
+ sign8 = _mm_srai_epi16(in8, 15);
+
+ // coeff = abs(in) = (in ^ sign) - sign
+ coeff0 = _mm_xor_si128(in0, sign0);
+ coeff8 = _mm_xor_si128(in8, sign8);
+ coeff0 = _mm_sub_epi16(coeff0, sign0);
+ coeff8 = _mm_sub_epi16(coeff8, sign8);
+
+ // coeff = abs(in) + sharpen
+ coeff0 = _mm_add_epi16(coeff0, sharpen0);
+ coeff8 = _mm_add_epi16(coeff8, sharpen8);
+
+ // if (coeff > 2047) coeff = 2047
+ coeff0 = _mm_min_epi16(coeff0, max_coeff_2047);
+ coeff8 = _mm_min_epi16(coeff8, max_coeff_2047);
+
+ // out = (coeff * iQ + B) >> QFIX;
+ {
+ // doing calculations with 32b precision (QFIX=17)
+ // out = (coeff * iQ)
+ __m128i coeff_iQ0H = _mm_mulhi_epu16(coeff0, iq0);
+ __m128i coeff_iQ0L = _mm_mullo_epi16(coeff0, iq0);
+ __m128i coeff_iQ8H = _mm_mulhi_epu16(coeff8, iq8);
+ __m128i coeff_iQ8L = _mm_mullo_epi16(coeff8, iq8);
+ __m128i out_00 = _mm_unpacklo_epi16(coeff_iQ0L, coeff_iQ0H);
+ __m128i out_04 = _mm_unpackhi_epi16(coeff_iQ0L, coeff_iQ0H);
+ __m128i out_08 = _mm_unpacklo_epi16(coeff_iQ8L, coeff_iQ8H);
+ __m128i out_12 = _mm_unpackhi_epi16(coeff_iQ8L, coeff_iQ8H);
+ // expand bias from 16b to 32b
+ __m128i bias_00 = _mm_unpacklo_epi16(bias0, zero);
+ __m128i bias_04 = _mm_unpackhi_epi16(bias0, zero);
+ __m128i bias_08 = _mm_unpacklo_epi16(bias8, zero);
+ __m128i bias_12 = _mm_unpackhi_epi16(bias8, zero);
+ // out = (coeff * iQ + B)
+ out_00 = _mm_add_epi32(out_00, bias_00);
+ out_04 = _mm_add_epi32(out_04, bias_04);
+ out_08 = _mm_add_epi32(out_08, bias_08);
+ out_12 = _mm_add_epi32(out_12, bias_12);
+ // out = (coeff * iQ + B) >> QFIX;
+ out_00 = _mm_srai_epi32(out_00, QFIX);
+ out_04 = _mm_srai_epi32(out_04, QFIX);
+ out_08 = _mm_srai_epi32(out_08, QFIX);
+ out_12 = _mm_srai_epi32(out_12, QFIX);
+ // pack result as 16b
+ out0 = _mm_packs_epi32(out_00, out_04);
+ out8 = _mm_packs_epi32(out_08, out_12);
+ }
+
+ // get sign back (if (sign[j]) out_n = -out_n)
+ out0 = _mm_xor_si128(out0, sign0);
+ out8 = _mm_xor_si128(out8, sign8);
+ out0 = _mm_sub_epi16(out0, sign0);
+ out8 = _mm_sub_epi16(out8, sign8);
+
+ // in = out * Q
+ in0 = _mm_mullo_epi16(out0, q0);
+ in8 = _mm_mullo_epi16(out8, q8);
+
+ // if (coeff <= mtx->zthresh_) {in=0; out=0;}
+ {
+ __m128i cmp0 = _mm_cmpgt_epi16(coeff0, zthresh0);
+ __m128i cmp8 = _mm_cmpgt_epi16(coeff8, zthresh8);
+ in0 = _mm_and_si128(in0, cmp0);
+ in8 = _mm_and_si128(in8, cmp8);
+ _mm_storeu_si128((__m128i*)&in[0], in0);
+ _mm_storeu_si128((__m128i*)&in[8], in8);
+ out0 = _mm_and_si128(out0, cmp0);
+ out8 = _mm_and_si128(out8, cmp8);
+ }
+
+ // zigzag the output before storing it.
+ //
+ // The zigzag pattern can almost be reproduced with a small sequence of
+ // shuffles. After it, we only need to swap the 7th (ending up in third
+ // position instead of twelfth) and 8th values.
+ {
+ __m128i outZ0, outZ8;
+ outZ0 = _mm_shufflehi_epi16(out0, _MM_SHUFFLE(2, 1, 3, 0));
+ outZ0 = _mm_shuffle_epi32 (outZ0, _MM_SHUFFLE(3, 1, 2, 0));
+ outZ0 = _mm_shufflehi_epi16(outZ0, _MM_SHUFFLE(3, 1, 0, 2));
+ outZ8 = _mm_shufflelo_epi16(out8, _MM_SHUFFLE(3, 0, 2, 1));
+ outZ8 = _mm_shuffle_epi32 (outZ8, _MM_SHUFFLE(3, 1, 2, 0));
+ outZ8 = _mm_shufflelo_epi16(outZ8, _MM_SHUFFLE(1, 3, 2, 0));
+ _mm_storeu_si128((__m128i*)&out[0], outZ0);
+ _mm_storeu_si128((__m128i*)&out[8], outZ8);
+ packed_out = _mm_packs_epi16(outZ0, outZ8);
+ }
+ {
+ const int16_t outZ_12 = out[12];
+ const int16_t outZ_3 = out[3];
+ out[3] = outZ_12;
+ out[12] = outZ_3;
+ }
+
+ // detect if all 'out' values are zeroes or not
+ {
+ int32_t tmp[4];
+ _mm_storeu_si128((__m128i*)tmp, packed_out);
+ if (n) {
+ tmp[0] &= ~0xff;
+ }
+ return (tmp[3] || tmp[2] || tmp[1] || tmp[0]);
+ }
+}
+
+extern void VP8EncDspInitSSE2(void);
+void VP8EncDspInitSSE2(void) {
+ VP8CollectHistogram = CollectHistogramSSE2;
+ VP8EncQuantizeBlock = QuantizeBlockSSE2;
+ VP8ITransform = ITransformSSE2;
+ VP8FTransform = FTransformSSE2;
+ VP8SSE4x4 = SSE4x4SSE2;
+ VP8TDisto4x4 = Disto4x4SSE2;
+ VP8TDisto16x16 = Disto16x16SSE2;
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif // WEBP_USE_SSE2
diff --git a/drivers/webpold/dsp/lossless.c b/drivers/webpold/dsp/lossless.c
new file mode 100644
index 0000000000..62a6b7b15a
--- /dev/null
+++ b/drivers/webpold/dsp/lossless.c
@@ -0,0 +1,1138 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Image transforms and color space conversion methods for lossless decoder.
+//
+// Authors: Vikas Arora (vikaas.arora@gmail.com)
+// Jyrki Alakuijala (jyrki@google.com)
+// Urvang Joshi (urvang@google.com)
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include <math.h>
+#include <stdlib.h>
+#include "./lossless.h"
+#include "../dec/vp8li.h"
+#include "../dsp/yuv.h"
+#include "../dsp/dsp.h"
+#include "../enc/histogram.h"
+
+#define MAX_DIFF_COST (1e30f)
+
+// lookup table for small values of log2(int)
+#define APPROX_LOG_MAX 4096
+#define LOG_2_RECIPROCAL 1.44269504088896338700465094007086
+#define LOG_LOOKUP_IDX_MAX 256
+static const float kLog2Table[LOG_LOOKUP_IDX_MAX] = {
+ 0.0000000000000000f, 0.0000000000000000f,
+ 1.0000000000000000f, 1.5849625007211560f,
+ 2.0000000000000000f, 2.3219280948873621f,
+ 2.5849625007211560f, 2.8073549220576041f,
+ 3.0000000000000000f, 3.1699250014423121f,
+ 3.3219280948873621f, 3.4594316186372973f,
+ 3.5849625007211560f, 3.7004397181410921f,
+ 3.8073549220576041f, 3.9068905956085187f,
+ 4.0000000000000000f, 4.0874628412503390f,
+ 4.1699250014423121f, 4.2479275134435852f,
+ 4.3219280948873626f, 4.3923174227787606f,
+ 4.4594316186372973f, 4.5235619560570130f,
+ 4.5849625007211560f, 4.6438561897747243f,
+ 4.7004397181410917f, 4.7548875021634682f,
+ 4.8073549220576037f, 4.8579809951275718f,
+ 4.9068905956085187f, 4.9541963103868749f,
+ 5.0000000000000000f, 5.0443941193584533f,
+ 5.0874628412503390f, 5.1292830169449663f,
+ 5.1699250014423121f, 5.2094533656289501f,
+ 5.2479275134435852f, 5.2854022188622487f,
+ 5.3219280948873626f, 5.3575520046180837f,
+ 5.3923174227787606f, 5.4262647547020979f,
+ 5.4594316186372973f, 5.4918530963296747f,
+ 5.5235619560570130f, 5.5545888516776376f,
+ 5.5849625007211560f, 5.6147098441152083f,
+ 5.6438561897747243f, 5.6724253419714951f,
+ 5.7004397181410917f, 5.7279204545631987f,
+ 5.7548875021634682f, 5.7813597135246599f,
+ 5.8073549220576037f, 5.8328900141647412f,
+ 5.8579809951275718f, 5.8826430493618415f,
+ 5.9068905956085187f, 5.9307373375628866f,
+ 5.9541963103868749f, 5.9772799234999167f,
+ 6.0000000000000000f, 6.0223678130284543f,
+ 6.0443941193584533f, 6.0660891904577720f,
+ 6.0874628412503390f, 6.1085244567781691f,
+ 6.1292830169449663f, 6.1497471195046822f,
+ 6.1699250014423121f, 6.1898245588800175f,
+ 6.2094533656289501f, 6.2288186904958804f,
+ 6.2479275134435852f, 6.2667865406949010f,
+ 6.2854022188622487f, 6.3037807481771030f,
+ 6.3219280948873626f, 6.3398500028846243f,
+ 6.3575520046180837f, 6.3750394313469245f,
+ 6.3923174227787606f, 6.4093909361377017f,
+ 6.4262647547020979f, 6.4429434958487279f,
+ 6.4594316186372973f, 6.4757334309663976f,
+ 6.4918530963296747f, 6.5077946401986963f,
+ 6.5235619560570130f, 6.5391588111080309f,
+ 6.5545888516776376f, 6.5698556083309478f,
+ 6.5849625007211560f, 6.5999128421871278f,
+ 6.6147098441152083f, 6.6293566200796094f,
+ 6.6438561897747243f, 6.6582114827517946f,
+ 6.6724253419714951f, 6.6865005271832185f,
+ 6.7004397181410917f, 6.7142455176661224f,
+ 6.7279204545631987f, 6.7414669864011464f,
+ 6.7548875021634682f, 6.7681843247769259f,
+ 6.7813597135246599f, 6.7944158663501061f,
+ 6.8073549220576037f, 6.8201789624151878f,
+ 6.8328900141647412f, 6.8454900509443747f,
+ 6.8579809951275718f, 6.8703647195834047f,
+ 6.8826430493618415f, 6.8948177633079437f,
+ 6.9068905956085187f, 6.9188632372745946f,
+ 6.9307373375628866f, 6.9425145053392398f,
+ 6.9541963103868749f, 6.9657842846620869f,
+ 6.9772799234999167f, 6.9886846867721654f,
+ 7.0000000000000000f, 7.0112272554232539f,
+ 7.0223678130284543f, 7.0334230015374501f,
+ 7.0443941193584533f, 7.0552824355011898f,
+ 7.0660891904577720f, 7.0768155970508308f,
+ 7.0874628412503390f, 7.0980320829605263f,
+ 7.1085244567781691f, 7.1189410727235076f,
+ 7.1292830169449663f, 7.1395513523987936f,
+ 7.1497471195046822f, 7.1598713367783890f,
+ 7.1699250014423121f, 7.1799090900149344f,
+ 7.1898245588800175f, 7.1996723448363644f,
+ 7.2094533656289501f, 7.2191685204621611f,
+ 7.2288186904958804f, 7.2384047393250785f,
+ 7.2479275134435852f, 7.2573878426926521f,
+ 7.2667865406949010f, 7.2761244052742375f,
+ 7.2854022188622487f, 7.2946207488916270f,
+ 7.3037807481771030f, 7.3128829552843557f,
+ 7.3219280948873626f, 7.3309168781146167f,
+ 7.3398500028846243f, 7.3487281542310771f,
+ 7.3575520046180837f, 7.3663222142458160f,
+ 7.3750394313469245f, 7.3837042924740519f,
+ 7.3923174227787606f, 7.4008794362821843f,
+ 7.4093909361377017f, 7.4178525148858982f,
+ 7.4262647547020979f, 7.4346282276367245f,
+ 7.4429434958487279f, 7.4512111118323289f,
+ 7.4594316186372973f, 7.4676055500829976f,
+ 7.4757334309663976f, 7.4838157772642563f,
+ 7.4918530963296747f, 7.4998458870832056f,
+ 7.5077946401986963f, 7.5156998382840427f,
+ 7.5235619560570130f, 7.5313814605163118f,
+ 7.5391588111080309f, 7.5468944598876364f,
+ 7.5545888516776376f, 7.5622424242210728f,
+ 7.5698556083309478f, 7.5774288280357486f,
+ 7.5849625007211560f, 7.5924570372680806f,
+ 7.5999128421871278f, 7.6073303137496104f,
+ 7.6147098441152083f, 7.6220518194563764f,
+ 7.6293566200796094f, 7.6366246205436487f,
+ 7.6438561897747243f, 7.6510516911789281f,
+ 7.6582114827517946f, 7.6653359171851764f,
+ 7.6724253419714951f, 7.6794800995054464f,
+ 7.6865005271832185f, 7.6934869574993252f,
+ 7.7004397181410917f, 7.7073591320808825f,
+ 7.7142455176661224f, 7.7210991887071855f,
+ 7.7279204545631987f, 7.7347096202258383f,
+ 7.7414669864011464f, 7.7481928495894605f,
+ 7.7548875021634682f, 7.7615512324444795f,
+ 7.7681843247769259f, 7.7747870596011736f,
+ 7.7813597135246599f, 7.7879025593914317f,
+ 7.7944158663501061f, 7.8008998999203047f,
+ 7.8073549220576037f, 7.8137811912170374f,
+ 7.8201789624151878f, 7.8265484872909150f,
+ 7.8328900141647412f, 7.8392037880969436f,
+ 7.8454900509443747f, 7.8517490414160571f,
+ 7.8579809951275718f, 7.8641861446542797f,
+ 7.8703647195834047f, 7.8765169465649993f,
+ 7.8826430493618415f, 7.8887432488982591f,
+ 7.8948177633079437f, 7.9008668079807486f,
+ 7.9068905956085187f, 7.9128893362299619f,
+ 7.9188632372745946f, 7.9248125036057812f,
+ 7.9307373375628866f, 7.9366379390025709f,
+ 7.9425145053392398f, 7.9483672315846778f,
+ 7.9541963103868749f, 7.9600019320680805f,
+ 7.9657842846620869f, 7.9715435539507719f,
+ 7.9772799234999167f, 7.9829935746943103f,
+ 7.9886846867721654f, 7.9943534368588577f
+};
+
+float VP8LFastLog2(int v) {
+ if (v < LOG_LOOKUP_IDX_MAX) {
+ return kLog2Table[v];
+ } else if (v < APPROX_LOG_MAX) {
+ int log_cnt = 0;
+ while (v >= LOG_LOOKUP_IDX_MAX) {
+ ++log_cnt;
+ v = v >> 1;
+ }
+ return kLog2Table[v] + (float)log_cnt;
+ } else {
+ return (float)(LOG_2_RECIPROCAL * log((double)v));
+ }
+}
+
+//------------------------------------------------------------------------------
+// Image transforms.
+
+// In-place sum of each component with mod 256.
+static WEBP_INLINE void AddPixelsEq(uint32_t* a, uint32_t b) {
+ const uint32_t alpha_and_green = (*a & 0xff00ff00u) + (b & 0xff00ff00u);
+ const uint32_t red_and_blue = (*a & 0x00ff00ffu) + (b & 0x00ff00ffu);
+ *a = (alpha_and_green & 0xff00ff00u) | (red_and_blue & 0x00ff00ffu);
+}
+
+static WEBP_INLINE uint32_t Average2(uint32_t a0, uint32_t a1) {
+ return (((a0 ^ a1) & 0xfefefefeL) >> 1) + (a0 & a1);
+}
+
+static WEBP_INLINE uint32_t Average3(uint32_t a0, uint32_t a1, uint32_t a2) {
+ return Average2(Average2(a0, a2), a1);
+}
+
+static WEBP_INLINE uint32_t Average4(uint32_t a0, uint32_t a1,
+ uint32_t a2, uint32_t a3) {
+ return Average2(Average2(a0, a1), Average2(a2, a3));
+}
+
+static WEBP_INLINE uint32_t Clip255(uint32_t a) {
+ if (a < 256) {
+ return a;
+ }
+ // return 0, when a is a negative integer.
+ // return 255, when a is positive.
+ return ~a >> 24;
+}
+
+static WEBP_INLINE int AddSubtractComponentFull(int a, int b, int c) {
+ return Clip255(a + b - c);
+}
+
+static WEBP_INLINE uint32_t ClampedAddSubtractFull(uint32_t c0, uint32_t c1,
+ uint32_t c2) {
+ const int a = AddSubtractComponentFull(c0 >> 24, c1 >> 24, c2 >> 24);
+ const int r = AddSubtractComponentFull((c0 >> 16) & 0xff,
+ (c1 >> 16) & 0xff,
+ (c2 >> 16) & 0xff);
+ const int g = AddSubtractComponentFull((c0 >> 8) & 0xff,
+ (c1 >> 8) & 0xff,
+ (c2 >> 8) & 0xff);
+ const int b = AddSubtractComponentFull(c0 & 0xff, c1 & 0xff, c2 & 0xff);
+ return (a << 24) | (r << 16) | (g << 8) | b;
+}
+
+static WEBP_INLINE int AddSubtractComponentHalf(int a, int b) {
+ return Clip255(a + (a - b) / 2);
+}
+
+static WEBP_INLINE uint32_t ClampedAddSubtractHalf(uint32_t c0, uint32_t c1,
+ uint32_t c2) {
+ const uint32_t ave = Average2(c0, c1);
+ const int a = AddSubtractComponentHalf(ave >> 24, c2 >> 24);
+ const int r = AddSubtractComponentHalf((ave >> 16) & 0xff, (c2 >> 16) & 0xff);
+ const int g = AddSubtractComponentHalf((ave >> 8) & 0xff, (c2 >> 8) & 0xff);
+ const int b = AddSubtractComponentHalf((ave >> 0) & 0xff, (c2 >> 0) & 0xff);
+ return (a << 24) | (r << 16) | (g << 8) | b;
+}
+
+static WEBP_INLINE int Sub3(int a, int b, int c) {
+ const int pa = b - c;
+ const int pb = a - c;
+ return abs(pa) - abs(pb);
+}
+
+static WEBP_INLINE uint32_t Select(uint32_t a, uint32_t b, uint32_t c) {
+ const int pa_minus_pb =
+ Sub3((a >> 24) , (b >> 24) , (c >> 24) ) +
+ Sub3((a >> 16) & 0xff, (b >> 16) & 0xff, (c >> 16) & 0xff) +
+ Sub3((a >> 8) & 0xff, (b >> 8) & 0xff, (c >> 8) & 0xff) +
+ Sub3((a ) & 0xff, (b ) & 0xff, (c ) & 0xff);
+
+ return (pa_minus_pb <= 0) ? a : b;
+}
+
+//------------------------------------------------------------------------------
+// Predictors
+
+static uint32_t Predictor0(uint32_t left, const uint32_t* const top) {
+ (void)top;
+ (void)left;
+ return ARGB_BLACK;
+}
+static uint32_t Predictor1(uint32_t left, const uint32_t* const top) {
+ (void)top;
+ return left;
+}
+static uint32_t Predictor2(uint32_t left, const uint32_t* const top) {
+ (void)left;
+ return top[0];
+}
+static uint32_t Predictor3(uint32_t left, const uint32_t* const top) {
+ (void)left;
+ return top[1];
+}
+static uint32_t Predictor4(uint32_t left, const uint32_t* const top) {
+ (void)left;
+ return top[-1];
+}
+static uint32_t Predictor5(uint32_t left, const uint32_t* const top) {
+ const uint32_t pred = Average3(left, top[0], top[1]);
+ return pred;
+}
+static uint32_t Predictor6(uint32_t left, const uint32_t* const top) {
+ const uint32_t pred = Average2(left, top[-1]);
+ return pred;
+}
+static uint32_t Predictor7(uint32_t left, const uint32_t* const top) {
+ const uint32_t pred = Average2(left, top[0]);
+ return pred;
+}
+static uint32_t Predictor8(uint32_t left, const uint32_t* const top) {
+ const uint32_t pred = Average2(top[-1], top[0]);
+ (void)left;
+ return pred;
+}
+static uint32_t Predictor9(uint32_t left, const uint32_t* const top) {
+ const uint32_t pred = Average2(top[0], top[1]);
+ (void)left;
+ return pred;
+}
+static uint32_t Predictor10(uint32_t left, const uint32_t* const top) {
+ const uint32_t pred = Average4(left, top[-1], top[0], top[1]);
+ return pred;
+}
+static uint32_t Predictor11(uint32_t left, const uint32_t* const top) {
+ const uint32_t pred = Select(top[0], left, top[-1]);
+ return pred;
+}
+static uint32_t Predictor12(uint32_t left, const uint32_t* const top) {
+ const uint32_t pred = ClampedAddSubtractFull(left, top[0], top[-1]);
+ return pred;
+}
+static uint32_t Predictor13(uint32_t left, const uint32_t* const top) {
+ const uint32_t pred = ClampedAddSubtractHalf(left, top[0], top[-1]);
+ return pred;
+}
+
+typedef uint32_t (*PredictorFunc)(uint32_t left, const uint32_t* const top);
+static const PredictorFunc kPredictors[16] = {
+ Predictor0, Predictor1, Predictor2, Predictor3,
+ Predictor4, Predictor5, Predictor6, Predictor7,
+ Predictor8, Predictor9, Predictor10, Predictor11,
+ Predictor12, Predictor13,
+ Predictor0, Predictor0 // <- padding security sentinels
+};
+
+// TODO(vikasa): Replace 256 etc with defines.
+static float PredictionCostSpatial(const int* counts,
+ int weight_0, double exp_val) {
+ const int significant_symbols = 16;
+ const double exp_decay_factor = 0.6;
+ double bits = weight_0 * counts[0];
+ int i;
+ for (i = 1; i < significant_symbols; ++i) {
+ bits += exp_val * (counts[i] + counts[256 - i]);
+ exp_val *= exp_decay_factor;
+ }
+ return (float)(-0.1 * bits);
+}
+
+// Compute the Shanon's entropy: Sum(p*log2(p))
+static float ShannonEntropy(const int* const array, int n) {
+ int i;
+ float retval = 0.f;
+ int sum = 0;
+ for (i = 0; i < n; ++i) {
+ if (array[i] != 0) {
+ sum += array[i];
+ retval -= VP8LFastSLog2(array[i]);
+ }
+ }
+ retval += VP8LFastSLog2(sum);
+ return retval;
+}
+
+static float PredictionCostSpatialHistogram(int accumulated[4][256],
+ int tile[4][256]) {
+ int i;
+ int k;
+ int combo[256];
+ double retval = 0;
+ for (i = 0; i < 4; ++i) {
+ const double exp_val = 0.94;
+ retval += PredictionCostSpatial(&tile[i][0], 1, exp_val);
+ retval += ShannonEntropy(&tile[i][0], 256);
+ for (k = 0; k < 256; ++k) {
+ combo[k] = accumulated[i][k] + tile[i][k];
+ }
+ retval += ShannonEntropy(&combo[0], 256);
+ }
+ return (float)retval;
+}
+
+static int GetBestPredictorForTile(int width, int height,
+ int tile_x, int tile_y, int bits,
+ int accumulated[4][256],
+ const uint32_t* const argb_scratch) {
+ const int kNumPredModes = 14;
+ const int col_start = tile_x << bits;
+ const int row_start = tile_y << bits;
+ const int tile_size = 1 << bits;
+ const int ymax = (tile_size <= height - row_start) ?
+ tile_size : height - row_start;
+ const int xmax = (tile_size <= width - col_start) ?
+ tile_size : width - col_start;
+ int histo[4][256];
+ float best_diff = MAX_DIFF_COST;
+ int best_mode = 0;
+
+ int mode;
+ for (mode = 0; mode < kNumPredModes; ++mode) {
+ const uint32_t* current_row = argb_scratch;
+ const PredictorFunc pred_func = kPredictors[mode];
+ float cur_diff;
+ int y;
+ memset(&histo[0][0], 0, sizeof(histo));
+ for (y = 0; y < ymax; ++y) {
+ int x;
+ const int row = row_start + y;
+ const uint32_t* const upper_row = current_row;
+ current_row = upper_row + width;
+ for (x = 0; x < xmax; ++x) {
+ const int col = col_start + x;
+ uint32_t predict;
+ uint32_t predict_diff;
+ if (row == 0) {
+ predict = (col == 0) ? ARGB_BLACK : current_row[col - 1]; // Left.
+ } else if (col == 0) {
+ predict = upper_row[col]; // Top.
+ } else {
+ predict = pred_func(current_row[col - 1], upper_row + col);
+ }
+ predict_diff = VP8LSubPixels(current_row[col], predict);
+ ++histo[0][predict_diff >> 24];
+ ++histo[1][((predict_diff >> 16) & 0xff)];
+ ++histo[2][((predict_diff >> 8) & 0xff)];
+ ++histo[3][(predict_diff & 0xff)];
+ }
+ }
+ cur_diff = PredictionCostSpatialHistogram(accumulated, histo);
+ if (cur_diff < best_diff) {
+ best_diff = cur_diff;
+ best_mode = mode;
+ }
+ }
+
+ return best_mode;
+}
+
+static void CopyTileWithPrediction(int width, int height,
+ int tile_x, int tile_y, int bits, int mode,
+ const uint32_t* const argb_scratch,
+ uint32_t* const argb) {
+ const int col_start = tile_x << bits;
+ const int row_start = tile_y << bits;
+ const int tile_size = 1 << bits;
+ const int ymax = (tile_size <= height - row_start) ?
+ tile_size : height - row_start;
+ const int xmax = (tile_size <= width - col_start) ?
+ tile_size : width - col_start;
+ const PredictorFunc pred_func = kPredictors[mode];
+ const uint32_t* current_row = argb_scratch;
+
+ int y;
+ for (y = 0; y < ymax; ++y) {
+ int x;
+ const int row = row_start + y;
+ const uint32_t* const upper_row = current_row;
+ current_row = upper_row + width;
+ for (x = 0; x < xmax; ++x) {
+ const int col = col_start + x;
+ const int pix = row * width + col;
+ uint32_t predict;
+ if (row == 0) {
+ predict = (col == 0) ? ARGB_BLACK : current_row[col - 1]; // Left.
+ } else if (col == 0) {
+ predict = upper_row[col]; // Top.
+ } else {
+ predict = pred_func(current_row[col - 1], upper_row + col);
+ }
+ argb[pix] = VP8LSubPixels(current_row[col], predict);
+ }
+ }
+}
+
+void VP8LResidualImage(int width, int height, int bits,
+ uint32_t* const argb, uint32_t* const argb_scratch,
+ uint32_t* const image) {
+ const int max_tile_size = 1 << bits;
+ const int tiles_per_row = VP8LSubSampleSize(width, bits);
+ const int tiles_per_col = VP8LSubSampleSize(height, bits);
+ uint32_t* const upper_row = argb_scratch;
+ uint32_t* const current_tile_rows = argb_scratch + width;
+ int tile_y;
+ int histo[4][256];
+ memset(histo, 0, sizeof(histo));
+ for (tile_y = 0; tile_y < tiles_per_col; ++tile_y) {
+ const int tile_y_offset = tile_y * max_tile_size;
+ const int this_tile_height =
+ (tile_y < tiles_per_col - 1) ? max_tile_size : height - tile_y_offset;
+ int tile_x;
+ if (tile_y > 0) {
+ memcpy(upper_row, current_tile_rows + (max_tile_size - 1) * width,
+ width * sizeof(*upper_row));
+ }
+ memcpy(current_tile_rows, &argb[tile_y_offset * width],
+ this_tile_height * width * sizeof(*current_tile_rows));
+ for (tile_x = 0; tile_x < tiles_per_row; ++tile_x) {
+ int pred;
+ int y;
+ const int tile_x_offset = tile_x * max_tile_size;
+ int all_x_max = tile_x_offset + max_tile_size;
+ if (all_x_max > width) {
+ all_x_max = width;
+ }
+ pred = GetBestPredictorForTile(width, height, tile_x, tile_y, bits, histo,
+ argb_scratch);
+ image[tile_y * tiles_per_row + tile_x] = 0xff000000u | (pred << 8);
+ CopyTileWithPrediction(width, height, tile_x, tile_y, bits, pred,
+ argb_scratch, argb);
+ for (y = 0; y < max_tile_size; ++y) {
+ int ix;
+ int all_x;
+ int all_y = tile_y_offset + y;
+ if (all_y >= height) {
+ break;
+ }
+ ix = all_y * width + tile_x_offset;
+ for (all_x = tile_x_offset; all_x < all_x_max; ++all_x, ++ix) {
+ const uint32_t a = argb[ix];
+ ++histo[0][a >> 24];
+ ++histo[1][((a >> 16) & 0xff)];
+ ++histo[2][((a >> 8) & 0xff)];
+ ++histo[3][(a & 0xff)];
+ }
+ }
+ }
+ }
+}
+
+// Inverse prediction.
+static void PredictorInverseTransform(const VP8LTransform* const transform,
+ int y_start, int y_end, uint32_t* data) {
+ const int width = transform->xsize_;
+ if (y_start == 0) { // First Row follows the L (mode=1) mode.
+ int x;
+ const uint32_t pred0 = Predictor0(data[-1], NULL);
+ AddPixelsEq(data, pred0);
+ for (x = 1; x < width; ++x) {
+ const uint32_t pred1 = Predictor1(data[x - 1], NULL);
+ AddPixelsEq(data + x, pred1);
+ }
+ data += width;
+ ++y_start;
+ }
+
+ {
+ int y = y_start;
+ const int mask = (1 << transform->bits_) - 1;
+ const int tiles_per_row = VP8LSubSampleSize(width, transform->bits_);
+ const uint32_t* pred_mode_base =
+ transform->data_ + (y >> transform->bits_) * tiles_per_row;
+
+ while (y < y_end) {
+ int x;
+ const uint32_t pred2 = Predictor2(data[-1], data - width);
+ const uint32_t* pred_mode_src = pred_mode_base;
+ PredictorFunc pred_func;
+
+ // First pixel follows the T (mode=2) mode.
+ AddPixelsEq(data, pred2);
+
+ // .. the rest:
+ pred_func = kPredictors[((*pred_mode_src++) >> 8) & 0xf];
+ for (x = 1; x < width; ++x) {
+ uint32_t pred;
+ if ((x & mask) == 0) { // start of tile. Read predictor function.
+ pred_func = kPredictors[((*pred_mode_src++) >> 8) & 0xf];
+ }
+ pred = pred_func(data[x - 1], data + x - width);
+ AddPixelsEq(data + x, pred);
+ }
+ data += width;
+ ++y;
+ if ((y & mask) == 0) { // Use the same mask, since tiles are squares.
+ pred_mode_base += tiles_per_row;
+ }
+ }
+ }
+}
+
+void VP8LSubtractGreenFromBlueAndRed(uint32_t* argb_data, int num_pixs) {
+ int i;
+ for (i = 0; i < num_pixs; ++i) {
+ const uint32_t argb = argb_data[i];
+ const uint32_t green = (argb >> 8) & 0xff;
+ const uint32_t new_r = (((argb >> 16) & 0xff) - green) & 0xff;
+ const uint32_t new_b = ((argb & 0xff) - green) & 0xff;
+ argb_data[i] = (argb & 0xff00ff00) | (new_r << 16) | new_b;
+ }
+}
+
+// Add green to blue and red channels (i.e. perform the inverse transform of
+// 'subtract green').
+static void AddGreenToBlueAndRed(const VP8LTransform* const transform,
+ int y_start, int y_end, uint32_t* data) {
+ const int width = transform->xsize_;
+ const uint32_t* const data_end = data + (y_end - y_start) * width;
+ while (data < data_end) {
+ const uint32_t argb = *data;
+ // "* 0001001u" is equivalent to "(green << 16) + green)"
+ const uint32_t green = ((argb >> 8) & 0xff);
+ uint32_t red_blue = (argb & 0x00ff00ffu);
+ red_blue += (green << 16) | green;
+ red_blue &= 0x00ff00ffu;
+ *data++ = (argb & 0xff00ff00u) | red_blue;
+ }
+}
+
+typedef struct {
+ // Note: the members are uint8_t, so that any negative values are
+ // automatically converted to "mod 256" values.
+ uint8_t green_to_red_;
+ uint8_t green_to_blue_;
+ uint8_t red_to_blue_;
+} Multipliers;
+
+static WEBP_INLINE void MultipliersClear(Multipliers* m) {
+ m->green_to_red_ = 0;
+ m->green_to_blue_ = 0;
+ m->red_to_blue_ = 0;
+}
+
+static WEBP_INLINE uint32_t ColorTransformDelta(int8_t color_pred,
+ int8_t color) {
+ return (uint32_t)((int)(color_pred) * color) >> 5;
+}
+
+static WEBP_INLINE void ColorCodeToMultipliers(uint32_t color_code,
+ Multipliers* const m) {
+ m->green_to_red_ = (color_code >> 0) & 0xff;
+ m->green_to_blue_ = (color_code >> 8) & 0xff;
+ m->red_to_blue_ = (color_code >> 16) & 0xff;
+}
+
+static WEBP_INLINE uint32_t MultipliersToColorCode(Multipliers* const m) {
+ return 0xff000000u |
+ ((uint32_t)(m->red_to_blue_) << 16) |
+ ((uint32_t)(m->green_to_blue_) << 8) |
+ m->green_to_red_;
+}
+
+static WEBP_INLINE uint32_t TransformColor(const Multipliers* const m,
+ uint32_t argb, int inverse) {
+ const uint32_t green = argb >> 8;
+ const uint32_t red = argb >> 16;
+ uint32_t new_red = red;
+ uint32_t new_blue = argb;
+
+ if (inverse) {
+ new_red += ColorTransformDelta(m->green_to_red_, green);
+ new_red &= 0xff;
+ new_blue += ColorTransformDelta(m->green_to_blue_, green);
+ new_blue += ColorTransformDelta(m->red_to_blue_, new_red);
+ new_blue &= 0xff;
+ } else {
+ new_red -= ColorTransformDelta(m->green_to_red_, green);
+ new_red &= 0xff;
+ new_blue -= ColorTransformDelta(m->green_to_blue_, green);
+ new_blue -= ColorTransformDelta(m->red_to_blue_, red);
+ new_blue &= 0xff;
+ }
+ return (argb & 0xff00ff00u) | (new_red << 16) | (new_blue);
+}
+
+static WEBP_INLINE int SkipRepeatedPixels(const uint32_t* const argb,
+ int ix, int xsize) {
+ const uint32_t v = argb[ix];
+ if (ix >= xsize + 3) {
+ if (v == argb[ix - xsize] &&
+ argb[ix - 1] == argb[ix - xsize - 1] &&
+ argb[ix - 2] == argb[ix - xsize - 2] &&
+ argb[ix - 3] == argb[ix - xsize - 3]) {
+ return 1;
+ }
+ return v == argb[ix - 3] && v == argb[ix - 2] && v == argb[ix - 1];
+ } else if (ix >= 3) {
+ return v == argb[ix - 3] && v == argb[ix - 2] && v == argb[ix - 1];
+ }
+ return 0;
+}
+
+static float PredictionCostCrossColor(const int accumulated[256],
+ const int counts[256]) {
+ // Favor low entropy, locally and globally.
+ int i;
+ int combo[256];
+ for (i = 0; i < 256; ++i) {
+ combo[i] = accumulated[i] + counts[i];
+ }
+ return ShannonEntropy(combo, 256) +
+ ShannonEntropy(counts, 256) +
+ PredictionCostSpatial(counts, 3, 2.4); // Favor small absolute values.
+}
+
+static Multipliers GetBestColorTransformForTile(
+ int tile_x, int tile_y, int bits,
+ Multipliers prevX,
+ Multipliers prevY,
+ int step, int xsize, int ysize,
+ int* accumulated_red_histo,
+ int* accumulated_blue_histo,
+ const uint32_t* const argb) {
+ float best_diff = MAX_DIFF_COST;
+ float cur_diff;
+ const int halfstep = step / 2;
+ const int max_tile_size = 1 << bits;
+ const int tile_y_offset = tile_y * max_tile_size;
+ const int tile_x_offset = tile_x * max_tile_size;
+ int green_to_red;
+ int green_to_blue;
+ int red_to_blue;
+ int all_x_max = tile_x_offset + max_tile_size;
+ int all_y_max = tile_y_offset + max_tile_size;
+ Multipliers best_tx;
+ MultipliersClear(&best_tx);
+ if (all_x_max > xsize) {
+ all_x_max = xsize;
+ }
+ if (all_y_max > ysize) {
+ all_y_max = ysize;
+ }
+ for (green_to_red = -64; green_to_red <= 64; green_to_red += halfstep) {
+ int histo[256] = { 0 };
+ int all_y;
+ Multipliers tx;
+ MultipliersClear(&tx);
+ tx.green_to_red_ = green_to_red & 0xff;
+
+ for (all_y = tile_y_offset; all_y < all_y_max; ++all_y) {
+ uint32_t predict;
+ int ix = all_y * xsize + tile_x_offset;
+ int all_x;
+ for (all_x = tile_x_offset; all_x < all_x_max; ++all_x, ++ix) {
+ if (SkipRepeatedPixels(argb, ix, xsize)) {
+ continue;
+ }
+ predict = TransformColor(&tx, argb[ix], 0);
+ ++histo[(predict >> 16) & 0xff]; // red.
+ }
+ }
+ cur_diff = PredictionCostCrossColor(&accumulated_red_histo[0], &histo[0]);
+ if (tx.green_to_red_ == prevX.green_to_red_) {
+ cur_diff -= 3; // favor keeping the areas locally similar
+ }
+ if (tx.green_to_red_ == prevY.green_to_red_) {
+ cur_diff -= 3; // favor keeping the areas locally similar
+ }
+ if (tx.green_to_red_ == 0) {
+ cur_diff -= 3;
+ }
+ if (cur_diff < best_diff) {
+ best_diff = cur_diff;
+ best_tx = tx;
+ }
+ }
+ best_diff = MAX_DIFF_COST;
+ green_to_red = best_tx.green_to_red_;
+ for (green_to_blue = -32; green_to_blue <= 32; green_to_blue += step) {
+ for (red_to_blue = -32; red_to_blue <= 32; red_to_blue += step) {
+ int all_y;
+ int histo[256] = { 0 };
+ Multipliers tx;
+ tx.green_to_red_ = green_to_red;
+ tx.green_to_blue_ = green_to_blue;
+ tx.red_to_blue_ = red_to_blue;
+ for (all_y = tile_y_offset; all_y < all_y_max; ++all_y) {
+ uint32_t predict;
+ int all_x;
+ int ix = all_y * xsize + tile_x_offset;
+ for (all_x = tile_x_offset; all_x < all_x_max; ++all_x, ++ix) {
+ if (SkipRepeatedPixels(argb, ix, xsize)) {
+ continue;
+ }
+ predict = TransformColor(&tx, argb[ix], 0);
+ ++histo[predict & 0xff]; // blue.
+ }
+ }
+ cur_diff =
+ PredictionCostCrossColor(&accumulated_blue_histo[0], &histo[0]);
+ if (tx.green_to_blue_ == prevX.green_to_blue_) {
+ cur_diff -= 3; // favor keeping the areas locally similar
+ }
+ if (tx.green_to_blue_ == prevY.green_to_blue_) {
+ cur_diff -= 3; // favor keeping the areas locally similar
+ }
+ if (tx.red_to_blue_ == prevX.red_to_blue_) {
+ cur_diff -= 3; // favor keeping the areas locally similar
+ }
+ if (tx.red_to_blue_ == prevY.red_to_blue_) {
+ cur_diff -= 3; // favor keeping the areas locally similar
+ }
+ if (tx.green_to_blue_ == 0) {
+ cur_diff -= 3;
+ }
+ if (tx.red_to_blue_ == 0) {
+ cur_diff -= 3;
+ }
+ if (cur_diff < best_diff) {
+ best_diff = cur_diff;
+ best_tx = tx;
+ }
+ }
+ }
+ return best_tx;
+}
+
+static void CopyTileWithColorTransform(int xsize, int ysize,
+ int tile_x, int tile_y, int bits,
+ Multipliers color_transform,
+ uint32_t* const argb) {
+ int y;
+ int xscan = 1 << bits;
+ int yscan = 1 << bits;
+ tile_x <<= bits;
+ tile_y <<= bits;
+ if (xscan > xsize - tile_x) {
+ xscan = xsize - tile_x;
+ }
+ if (yscan > ysize - tile_y) {
+ yscan = ysize - tile_y;
+ }
+ yscan += tile_y;
+ for (y = tile_y; y < yscan; ++y) {
+ int ix = y * xsize + tile_x;
+ const int end_ix = ix + xscan;
+ for (; ix < end_ix; ++ix) {
+ argb[ix] = TransformColor(&color_transform, argb[ix], 0);
+ }
+ }
+}
+
+void VP8LColorSpaceTransform(int width, int height, int bits, int step,
+ uint32_t* const argb, uint32_t* image) {
+ const int max_tile_size = 1 << bits;
+ int tile_xsize = VP8LSubSampleSize(width, bits);
+ int tile_ysize = VP8LSubSampleSize(height, bits);
+ int accumulated_red_histo[256] = { 0 };
+ int accumulated_blue_histo[256] = { 0 };
+ int tile_y;
+ int tile_x;
+ Multipliers prevX;
+ Multipliers prevY;
+ MultipliersClear(&prevY);
+ MultipliersClear(&prevX);
+ for (tile_y = 0; tile_y < tile_ysize; ++tile_y) {
+ for (tile_x = 0; tile_x < tile_xsize; ++tile_x) {
+ Multipliers color_transform;
+ int all_x_max;
+ int y;
+ const int tile_y_offset = tile_y * max_tile_size;
+ const int tile_x_offset = tile_x * max_tile_size;
+ if (tile_y != 0) {
+ ColorCodeToMultipliers(image[tile_y * tile_xsize + tile_x - 1], &prevX);
+ ColorCodeToMultipliers(image[(tile_y - 1) * tile_xsize + tile_x],
+ &prevY);
+ } else if (tile_x != 0) {
+ ColorCodeToMultipliers(image[tile_y * tile_xsize + tile_x - 1], &prevX);
+ }
+ color_transform =
+ GetBestColorTransformForTile(tile_x, tile_y, bits,
+ prevX, prevY,
+ step, width, height,
+ &accumulated_red_histo[0],
+ &accumulated_blue_histo[0],
+ argb);
+ image[tile_y * tile_xsize + tile_x] =
+ MultipliersToColorCode(&color_transform);
+ CopyTileWithColorTransform(width, height, tile_x, tile_y, bits,
+ color_transform, argb);
+
+ // Gather accumulated histogram data.
+ all_x_max = tile_x_offset + max_tile_size;
+ if (all_x_max > width) {
+ all_x_max = width;
+ }
+ for (y = 0; y < max_tile_size; ++y) {
+ int ix;
+ int all_x;
+ int all_y = tile_y_offset + y;
+ if (all_y >= height) {
+ break;
+ }
+ ix = all_y * width + tile_x_offset;
+ for (all_x = tile_x_offset; all_x < all_x_max; ++all_x, ++ix) {
+ if (ix >= 2 &&
+ argb[ix] == argb[ix - 2] &&
+ argb[ix] == argb[ix - 1]) {
+ continue; // repeated pixels are handled by backward references
+ }
+ if (ix >= width + 2 &&
+ argb[ix - 2] == argb[ix - width - 2] &&
+ argb[ix - 1] == argb[ix - width - 1] &&
+ argb[ix] == argb[ix - width]) {
+ continue; // repeated pixels are handled by backward references
+ }
+ ++accumulated_red_histo[(argb[ix] >> 16) & 0xff];
+ ++accumulated_blue_histo[argb[ix] & 0xff];
+ }
+ }
+ }
+ }
+}
+
+// Color space inverse transform.
+static void ColorSpaceInverseTransform(const VP8LTransform* const transform,
+ int y_start, int y_end, uint32_t* data) {
+ const int width = transform->xsize_;
+ const int mask = (1 << transform->bits_) - 1;
+ const int tiles_per_row = VP8LSubSampleSize(width, transform->bits_);
+ int y = y_start;
+ const uint32_t* pred_row =
+ transform->data_ + (y >> transform->bits_) * tiles_per_row;
+
+ while (y < y_end) {
+ const uint32_t* pred = pred_row;
+ Multipliers m = { 0, 0, 0 };
+ int x;
+
+ for (x = 0; x < width; ++x) {
+ if ((x & mask) == 0) ColorCodeToMultipliers(*pred++, &m);
+ data[x] = TransformColor(&m, data[x], 1);
+ }
+ data += width;
+ ++y;
+ if ((y & mask) == 0) pred_row += tiles_per_row;;
+ }
+}
+
+// Separate out pixels packed together using pixel-bundling.
+static void ColorIndexInverseTransform(
+ const VP8LTransform* const transform,
+ int y_start, int y_end, const uint32_t* src, uint32_t* dst) {
+ int y;
+ const int bits_per_pixel = 8 >> transform->bits_;
+ const int width = transform->xsize_;
+ const uint32_t* const color_map = transform->data_;
+ if (bits_per_pixel < 8) {
+ const int pixels_per_byte = 1 << transform->bits_;
+ const int count_mask = pixels_per_byte - 1;
+ const uint32_t bit_mask = (1 << bits_per_pixel) - 1;
+ for (y = y_start; y < y_end; ++y) {
+ uint32_t packed_pixels = 0;
+ int x;
+ for (x = 0; x < width; ++x) {
+ // We need to load fresh 'packed_pixels' once every 'pixels_per_byte'
+ // increments of x. Fortunately, pixels_per_byte is a power of 2, so
+ // can just use a mask for that, instead of decrementing a counter.
+ if ((x & count_mask) == 0) packed_pixels = ((*src++) >> 8) & 0xff;
+ *dst++ = color_map[packed_pixels & bit_mask];
+ packed_pixels >>= bits_per_pixel;
+ }
+ }
+ } else {
+ for (y = y_start; y < y_end; ++y) {
+ int x;
+ for (x = 0; x < width; ++x) {
+ *dst++ = color_map[((*src++) >> 8) & 0xff];
+ }
+ }
+ }
+}
+
+void VP8LInverseTransform(const VP8LTransform* const transform,
+ int row_start, int row_end,
+ const uint32_t* const in, uint32_t* const out) {
+ assert(row_start < row_end);
+ assert(row_end <= transform->ysize_);
+ switch (transform->type_) {
+ case SUBTRACT_GREEN:
+ AddGreenToBlueAndRed(transform, row_start, row_end, out);
+ break;
+ case PREDICTOR_TRANSFORM:
+ PredictorInverseTransform(transform, row_start, row_end, out);
+ if (row_end != transform->ysize_) {
+ // The last predicted row in this iteration will be the top-pred row
+ // for the first row in next iteration.
+ const int width = transform->xsize_;
+ memcpy(out - width, out + (row_end - row_start - 1) * width,
+ width * sizeof(*out));
+ }
+ break;
+ case CROSS_COLOR_TRANSFORM:
+ ColorSpaceInverseTransform(transform, row_start, row_end, out);
+ break;
+ case COLOR_INDEXING_TRANSFORM:
+ if (in == out && transform->bits_ > 0) {
+ // Move packed pixels to the end of unpacked region, so that unpacking
+ // can occur seamlessly.
+ // Also, note that this is the only transform that applies on
+ // the effective width of VP8LSubSampleSize(xsize_, bits_). All other
+ // transforms work on effective width of xsize_.
+ const int out_stride = (row_end - row_start) * transform->xsize_;
+ const int in_stride = (row_end - row_start) *
+ VP8LSubSampleSize(transform->xsize_, transform->bits_);
+ uint32_t* const src = out + out_stride - in_stride;
+ memmove(src, out, in_stride * sizeof(*src));
+ ColorIndexInverseTransform(transform, row_start, row_end, src, out);
+ } else {
+ ColorIndexInverseTransform(transform, row_start, row_end, in, out);
+ }
+ break;
+ }
+}
+
+//------------------------------------------------------------------------------
+// Color space conversion.
+
+static int is_big_endian(void) {
+ static const union {
+ uint16_t w;
+ uint8_t b[2];
+ } tmp = { 1 };
+ return (tmp.b[0] != 1);
+}
+
+static void ConvertBGRAToRGB(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ const uint32_t* const src_end = src + num_pixels;
+ while (src < src_end) {
+ const uint32_t argb = *src++;
+ *dst++ = (argb >> 16) & 0xff;
+ *dst++ = (argb >> 8) & 0xff;
+ *dst++ = (argb >> 0) & 0xff;
+ }
+}
+
+static void ConvertBGRAToRGBA(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ const uint32_t* const src_end = src + num_pixels;
+ while (src < src_end) {
+ const uint32_t argb = *src++;
+ *dst++ = (argb >> 16) & 0xff;
+ *dst++ = (argb >> 8) & 0xff;
+ *dst++ = (argb >> 0) & 0xff;
+ *dst++ = (argb >> 24) & 0xff;
+ }
+}
+
+static void ConvertBGRAToRGBA4444(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ const uint32_t* const src_end = src + num_pixels;
+ while (src < src_end) {
+ const uint32_t argb = *src++;
+ *dst++ = ((argb >> 16) & 0xf0) | ((argb >> 12) & 0xf);
+ *dst++ = ((argb >> 0) & 0xf0) | ((argb >> 28) & 0xf);
+ }
+}
+
+static void ConvertBGRAToRGB565(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ const uint32_t* const src_end = src + num_pixels;
+ while (src < src_end) {
+ const uint32_t argb = *src++;
+ *dst++ = ((argb >> 16) & 0xf8) | ((argb >> 13) & 0x7);
+ *dst++ = ((argb >> 5) & 0xe0) | ((argb >> 3) & 0x1f);
+ }
+}
+
+static void ConvertBGRAToBGR(const uint32_t* src,
+ int num_pixels, uint8_t* dst) {
+ const uint32_t* const src_end = src + num_pixels;
+ while (src < src_end) {
+ const uint32_t argb = *src++;
+ *dst++ = (argb >> 0) & 0xff;
+ *dst++ = (argb >> 8) & 0xff;
+ *dst++ = (argb >> 16) & 0xff;
+ }
+}
+
+static void CopyOrSwap(const uint32_t* src, int num_pixels, uint8_t* dst,
+ int swap_on_big_endian) {
+ if (is_big_endian() == swap_on_big_endian) {
+ const uint32_t* const src_end = src + num_pixels;
+ while (src < src_end) {
+ uint32_t argb = *src++;
+#if !defined(__BIG_ENDIAN__) && (defined(__i386__) || defined(__x86_64__))
+ __asm__ volatile("bswap %0" : "=r"(argb) : "0"(argb));
+ *(uint32_t*)dst = argb;
+ dst += sizeof(argb);
+#elif !defined(__BIG_ENDIAN__) && defined(_MSC_VER)
+ argb = _byteswap_ulong(argb);
+ *(uint32_t*)dst = argb;
+ dst += sizeof(argb);
+#else
+ *dst++ = (argb >> 24) & 0xff;
+ *dst++ = (argb >> 16) & 0xff;
+ *dst++ = (argb >> 8) & 0xff;
+ *dst++ = (argb >> 0) & 0xff;
+#endif
+ }
+ } else {
+ memcpy(dst, src, num_pixels * sizeof(*src));
+ }
+}
+
+void VP8LConvertFromBGRA(const uint32_t* const in_data, int num_pixels,
+ WEBP_CSP_MODE out_colorspace, uint8_t* const rgba) {
+ switch (out_colorspace) {
+ case MODE_RGB:
+ ConvertBGRAToRGB(in_data, num_pixels, rgba);
+ break;
+ case MODE_RGBA:
+ ConvertBGRAToRGBA(in_data, num_pixels, rgba);
+ break;
+ case MODE_rgbA:
+ ConvertBGRAToRGBA(in_data, num_pixels, rgba);
+ WebPApplyAlphaMultiply(rgba, 0, num_pixels, 1, 0);
+ break;
+ case MODE_BGR:
+ ConvertBGRAToBGR(in_data, num_pixels, rgba);
+ break;
+ case MODE_BGRA:
+ CopyOrSwap(in_data, num_pixels, rgba, 1);
+ break;
+ case MODE_bgrA:
+ CopyOrSwap(in_data, num_pixels, rgba, 1);
+ WebPApplyAlphaMultiply(rgba, 0, num_pixels, 1, 0);
+ break;
+ case MODE_ARGB:
+ CopyOrSwap(in_data, num_pixels, rgba, 0);
+ break;
+ case MODE_Argb:
+ CopyOrSwap(in_data, num_pixels, rgba, 0);
+ WebPApplyAlphaMultiply(rgba, 1, num_pixels, 1, 0);
+ break;
+ case MODE_RGBA_4444:
+ ConvertBGRAToRGBA4444(in_data, num_pixels, rgba);
+ break;
+ case MODE_rgbA_4444:
+ ConvertBGRAToRGBA4444(in_data, num_pixels, rgba);
+ WebPApplyAlphaMultiply4444(rgba, num_pixels, 1, 0);
+ break;
+ case MODE_RGB_565:
+ ConvertBGRAToRGB565(in_data, num_pixels, rgba);
+ break;
+ default:
+ assert(0); // Code flow should not reach here.
+ }
+}
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/dsp/lossless.h b/drivers/webpold/dsp/lossless.h
new file mode 100644
index 0000000000..7c7d5555ed
--- /dev/null
+++ b/drivers/webpold/dsp/lossless.h
@@ -0,0 +1,82 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Image transforms and color space conversion methods for lossless decoder.
+//
+// Authors: Vikas Arora (vikaas.arora@gmail.com)
+// Jyrki Alakuijala (jyrki@google.com)
+
+#ifndef WEBP_DSP_LOSSLESS_H_
+#define WEBP_DSP_LOSSLESS_H_
+
+#include "../types.h"
+#include "../decode.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// Image transforms.
+
+struct VP8LTransform; // Defined in dec/vp8li.h.
+
+// Performs inverse transform of data given transform information, start and end
+// rows. Transform will be applied to rows [row_start, row_end[.
+// The *in and *out pointers refer to source and destination data respectively
+// corresponding to the intermediate row (row_start).
+void VP8LInverseTransform(const struct VP8LTransform* const transform,
+ int row_start, int row_end,
+ const uint32_t* const in, uint32_t* const out);
+
+// Subtracts green from blue and red channels.
+void VP8LSubtractGreenFromBlueAndRed(uint32_t* argb_data, int num_pixs);
+
+void VP8LResidualImage(int width, int height, int bits,
+ uint32_t* const argb, uint32_t* const argb_scratch,
+ uint32_t* const image);
+
+void VP8LColorSpaceTransform(int width, int height, int bits, int step,
+ uint32_t* const argb, uint32_t* image);
+
+//------------------------------------------------------------------------------
+// Color space conversion.
+
+// Converts from BGRA to other color spaces.
+void VP8LConvertFromBGRA(const uint32_t* const in_data, int num_pixels,
+ WEBP_CSP_MODE out_colorspace, uint8_t* const rgba);
+
+//------------------------------------------------------------------------------
+// Misc methods.
+
+// Computes sampled size of 'size' when sampling using 'sampling bits'.
+static WEBP_INLINE uint32_t VP8LSubSampleSize(uint32_t size,
+ uint32_t sampling_bits) {
+ return (size + (1 << sampling_bits) - 1) >> sampling_bits;
+}
+
+// Faster logarithm for integers, with the property of log2(0) == 0.
+float VP8LFastLog2(int v);
+// Fast calculation of v * log2(v) for integer input.
+static WEBP_INLINE float VP8LFastSLog2(int v) { return VP8LFastLog2(v) * v; }
+
+// In-place difference of each component with mod 256.
+static WEBP_INLINE uint32_t VP8LSubPixels(uint32_t a, uint32_t b) {
+ const uint32_t alpha_and_green =
+ 0x00ff00ffu + (a & 0xff00ff00u) - (b & 0xff00ff00u);
+ const uint32_t red_and_blue =
+ 0xff00ff00u + (a & 0x00ff00ffu) - (b & 0x00ff00ffu);
+ return (alpha_and_green & 0xff00ff00u) | (red_and_blue & 0x00ff00ffu);
+}
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif // WEBP_DSP_LOSSLESS_H_
diff --git a/drivers/webpold/dsp/upsampling.c b/drivers/webpold/dsp/upsampling.c
new file mode 100644
index 0000000000..4855eb1432
--- /dev/null
+++ b/drivers/webpold/dsp/upsampling.c
@@ -0,0 +1,357 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// YUV to RGB upsampling functions.
+//
+// Author: somnath@google.com (Somnath Banerjee)
+
+#include "./dsp.h"
+#include "./yuv.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// Fancy upsampler
+
+#ifdef FANCY_UPSAMPLING
+
+// Fancy upsampling functions to convert YUV to RGB
+WebPUpsampleLinePairFunc WebPUpsamplers[MODE_LAST];
+
+// Given samples laid out in a square as:
+// [a b]
+// [c d]
+// we interpolate u/v as:
+// ([9*a + 3*b + 3*c + d 3*a + 9*b + 3*c + d] + [8 8]) / 16
+// ([3*a + b + 9*c + 3*d a + 3*b + 3*c + 9*d] [8 8]) / 16
+
+// We process u and v together stashed into 32bit (16bit each).
+#define LOAD_UV(u,v) ((u) | ((v) << 16))
+
+#define UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \
+static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
+ const uint8_t* top_u, const uint8_t* top_v, \
+ const uint8_t* cur_u, const uint8_t* cur_v, \
+ uint8_t* top_dst, uint8_t* bottom_dst, int len) { \
+ int x; \
+ const int last_pixel_pair = (len - 1) >> 1; \
+ uint32_t tl_uv = LOAD_UV(top_u[0], top_v[0]); /* top-left sample */ \
+ uint32_t l_uv = LOAD_UV(cur_u[0], cur_v[0]); /* left-sample */ \
+ if (top_y) { \
+ const uint32_t uv0 = (3 * tl_uv + l_uv + 0x00020002u) >> 2; \
+ FUNC(top_y[0], uv0 & 0xff, (uv0 >> 16), top_dst); \
+ } \
+ if (bottom_y) { \
+ const uint32_t uv0 = (3 * l_uv + tl_uv + 0x00020002u) >> 2; \
+ FUNC(bottom_y[0], uv0 & 0xff, (uv0 >> 16), bottom_dst); \
+ } \
+ for (x = 1; x <= last_pixel_pair; ++x) { \
+ const uint32_t t_uv = LOAD_UV(top_u[x], top_v[x]); /* top sample */ \
+ const uint32_t uv = LOAD_UV(cur_u[x], cur_v[x]); /* sample */ \
+ /* precompute invariant values associated with first and second diagonals*/\
+ const uint32_t avg = tl_uv + t_uv + l_uv + uv + 0x00080008u; \
+ const uint32_t diag_12 = (avg + 2 * (t_uv + l_uv)) >> 3; \
+ const uint32_t diag_03 = (avg + 2 * (tl_uv + uv)) >> 3; \
+ if (top_y) { \
+ const uint32_t uv0 = (diag_12 + tl_uv) >> 1; \
+ const uint32_t uv1 = (diag_03 + t_uv) >> 1; \
+ FUNC(top_y[2 * x - 1], uv0 & 0xff, (uv0 >> 16), \
+ top_dst + (2 * x - 1) * XSTEP); \
+ FUNC(top_y[2 * x - 0], uv1 & 0xff, (uv1 >> 16), \
+ top_dst + (2 * x - 0) * XSTEP); \
+ } \
+ if (bottom_y) { \
+ const uint32_t uv0 = (diag_03 + l_uv) >> 1; \
+ const uint32_t uv1 = (diag_12 + uv) >> 1; \
+ FUNC(bottom_y[2 * x - 1], uv0 & 0xff, (uv0 >> 16), \
+ bottom_dst + (2 * x - 1) * XSTEP); \
+ FUNC(bottom_y[2 * x + 0], uv1 & 0xff, (uv1 >> 16), \
+ bottom_dst + (2 * x + 0) * XSTEP); \
+ } \
+ tl_uv = t_uv; \
+ l_uv = uv; \
+ } \
+ if (!(len & 1)) { \
+ if (top_y) { \
+ const uint32_t uv0 = (3 * tl_uv + l_uv + 0x00020002u) >> 2; \
+ FUNC(top_y[len - 1], uv0 & 0xff, (uv0 >> 16), \
+ top_dst + (len - 1) * XSTEP); \
+ } \
+ if (bottom_y) { \
+ const uint32_t uv0 = (3 * l_uv + tl_uv + 0x00020002u) >> 2; \
+ FUNC(bottom_y[len - 1], uv0 & 0xff, (uv0 >> 16), \
+ bottom_dst + (len - 1) * XSTEP); \
+ } \
+ } \
+}
+
+// All variants implemented.
+UPSAMPLE_FUNC(UpsampleRgbLinePair, VP8YuvToRgb, 3)
+UPSAMPLE_FUNC(UpsampleBgrLinePair, VP8YuvToBgr, 3)
+UPSAMPLE_FUNC(UpsampleRgbaLinePair, VP8YuvToRgba, 4)
+UPSAMPLE_FUNC(UpsampleBgraLinePair, VP8YuvToBgra, 4)
+UPSAMPLE_FUNC(UpsampleArgbLinePair, VP8YuvToArgb, 4)
+UPSAMPLE_FUNC(UpsampleRgba4444LinePair, VP8YuvToRgba4444, 2)
+UPSAMPLE_FUNC(UpsampleRgb565LinePair, VP8YuvToRgb565, 2)
+
+#undef LOAD_UV
+#undef UPSAMPLE_FUNC
+
+#endif // FANCY_UPSAMPLING
+
+//------------------------------------------------------------------------------
+// simple point-sampling
+
+#define SAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \
+static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
+ const uint8_t* u, const uint8_t* v, \
+ uint8_t* top_dst, uint8_t* bottom_dst, int len) { \
+ int i; \
+ for (i = 0; i < len - 1; i += 2) { \
+ FUNC(top_y[0], u[0], v[0], top_dst); \
+ FUNC(top_y[1], u[0], v[0], top_dst + XSTEP); \
+ FUNC(bottom_y[0], u[0], v[0], bottom_dst); \
+ FUNC(bottom_y[1], u[0], v[0], bottom_dst + XSTEP); \
+ top_y += 2; \
+ bottom_y += 2; \
+ u++; \
+ v++; \
+ top_dst += 2 * XSTEP; \
+ bottom_dst += 2 * XSTEP; \
+ } \
+ if (i == len - 1) { /* last one */ \
+ FUNC(top_y[0], u[0], v[0], top_dst); \
+ FUNC(bottom_y[0], u[0], v[0], bottom_dst); \
+ } \
+}
+
+// All variants implemented.
+SAMPLE_FUNC(SampleRgbLinePair, VP8YuvToRgb, 3)
+SAMPLE_FUNC(SampleBgrLinePair, VP8YuvToBgr, 3)
+SAMPLE_FUNC(SampleRgbaLinePair, VP8YuvToRgba, 4)
+SAMPLE_FUNC(SampleBgraLinePair, VP8YuvToBgra, 4)
+SAMPLE_FUNC(SampleArgbLinePair, VP8YuvToArgb, 4)
+SAMPLE_FUNC(SampleRgba4444LinePair, VP8YuvToRgba4444, 2)
+SAMPLE_FUNC(SampleRgb565LinePair, VP8YuvToRgb565, 2)
+
+#undef SAMPLE_FUNC
+
+const WebPSampleLinePairFunc WebPSamplers[MODE_LAST] = {
+ SampleRgbLinePair, // MODE_RGB
+ SampleRgbaLinePair, // MODE_RGBA
+ SampleBgrLinePair, // MODE_BGR
+ SampleBgraLinePair, // MODE_BGRA
+ SampleArgbLinePair, // MODE_ARGB
+ SampleRgba4444LinePair, // MODE_RGBA_4444
+ SampleRgb565LinePair, // MODE_RGB_565
+ SampleRgbaLinePair, // MODE_rgbA
+ SampleBgraLinePair, // MODE_bgrA
+ SampleArgbLinePair, // MODE_Argb
+ SampleRgba4444LinePair // MODE_rgbA_4444
+};
+
+//------------------------------------------------------------------------------
+
+#if !defined(FANCY_UPSAMPLING)
+#define DUAL_SAMPLE_FUNC(FUNC_NAME, FUNC) \
+static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bot_y, \
+ const uint8_t* top_u, const uint8_t* top_v, \
+ const uint8_t* bot_u, const uint8_t* bot_v, \
+ uint8_t* top_dst, uint8_t* bot_dst, int len) { \
+ const int half_len = len >> 1; \
+ int x; \
+ if (top_dst != NULL) { \
+ for (x = 0; x < half_len; ++x) { \
+ FUNC(top_y[2 * x + 0], top_u[x], top_v[x], top_dst + 8 * x + 0); \
+ FUNC(top_y[2 * x + 1], top_u[x], top_v[x], top_dst + 8 * x + 4); \
+ } \
+ if (len & 1) FUNC(top_y[2 * x + 0], top_u[x], top_v[x], top_dst + 8 * x); \
+ } \
+ if (bot_dst != NULL) { \
+ for (x = 0; x < half_len; ++x) { \
+ FUNC(bot_y[2 * x + 0], bot_u[x], bot_v[x], bot_dst + 8 * x + 0); \
+ FUNC(bot_y[2 * x + 1], bot_u[x], bot_v[x], bot_dst + 8 * x + 4); \
+ } \
+ if (len & 1) FUNC(bot_y[2 * x + 0], bot_u[x], bot_v[x], bot_dst + 8 * x); \
+ } \
+}
+
+DUAL_SAMPLE_FUNC(DualLineSamplerBGRA, VP8YuvToBgra)
+DUAL_SAMPLE_FUNC(DualLineSamplerARGB, VP8YuvToArgb)
+#undef DUAL_SAMPLE_FUNC
+
+#endif // !FANCY_UPSAMPLING
+
+WebPUpsampleLinePairFunc WebPGetLinePairConverter(int alpha_is_last) {
+ WebPInitUpsamplers();
+ VP8YUVInit();
+#ifdef FANCY_UPSAMPLING
+ return WebPUpsamplers[alpha_is_last ? MODE_BGRA : MODE_ARGB];
+#else
+ return (alpha_is_last ? DualLineSamplerBGRA : DualLineSamplerARGB);
+#endif
+}
+
+//------------------------------------------------------------------------------
+// YUV444 converter
+
+#define YUV444_FUNC(FUNC_NAME, FUNC, XSTEP) \
+static void FUNC_NAME(const uint8_t* y, const uint8_t* u, const uint8_t* v, \
+ uint8_t* dst, int len) { \
+ int i; \
+ for (i = 0; i < len; ++i) FUNC(y[i], u[i], v[i], &dst[i * XSTEP]); \
+}
+
+YUV444_FUNC(Yuv444ToRgb, VP8YuvToRgb, 3)
+YUV444_FUNC(Yuv444ToBgr, VP8YuvToBgr, 3)
+YUV444_FUNC(Yuv444ToRgba, VP8YuvToRgba, 4)
+YUV444_FUNC(Yuv444ToBgra, VP8YuvToBgra, 4)
+YUV444_FUNC(Yuv444ToArgb, VP8YuvToArgb, 4)
+YUV444_FUNC(Yuv444ToRgba4444, VP8YuvToRgba4444, 2)
+YUV444_FUNC(Yuv444ToRgb565, VP8YuvToRgb565, 2)
+
+#undef YUV444_FUNC
+
+const WebPYUV444Converter WebPYUV444Converters[MODE_LAST] = {
+ Yuv444ToRgb, // MODE_RGB
+ Yuv444ToRgba, // MODE_RGBA
+ Yuv444ToBgr, // MODE_BGR
+ Yuv444ToBgra, // MODE_BGRA
+ Yuv444ToArgb, // MODE_ARGB
+ Yuv444ToRgba4444, // MODE_RGBA_4444
+ Yuv444ToRgb565, // MODE_RGB_565
+ Yuv444ToRgba, // MODE_rgbA
+ Yuv444ToBgra, // MODE_bgrA
+ Yuv444ToArgb, // MODE_Argb
+ Yuv444ToRgba4444 // MODE_rgbA_4444
+};
+
+//------------------------------------------------------------------------------
+// Premultiplied modes
+
+// non dithered-modes
+
+// (x * a * 32897) >> 23 is bit-wise equivalent to (int)(x * a / 255.)
+// for all 8bit x or a. For bit-wise equivalence to (int)(x * a / 255. + .5),
+// one can use instead: (x * a * 65793 + (1 << 23)) >> 24
+#if 1 // (int)(x * a / 255.)
+#define MULTIPLIER(a) ((a) * 32897UL)
+#define PREMULTIPLY(x, m) (((x) * (m)) >> 23)
+#else // (int)(x * a / 255. + .5)
+#define MULTIPLIER(a) ((a) * 65793UL)
+#define PREMULTIPLY(x, m) (((x) * (m) + (1UL << 23)) >> 24)
+#endif
+
+static void ApplyAlphaMultiply(uint8_t* rgba, int alpha_first,
+ int w, int h, int stride) {
+ while (h-- > 0) {
+ uint8_t* const rgb = rgba + (alpha_first ? 1 : 0);
+ const uint8_t* const alpha = rgba + (alpha_first ? 0 : 3);
+ int i;
+ for (i = 0; i < w; ++i) {
+ const uint32_t a = alpha[4 * i];
+ if (a != 0xff) {
+ const uint32_t mult = MULTIPLIER(a);
+ rgb[4 * i + 0] = PREMULTIPLY(rgb[4 * i + 0], mult);
+ rgb[4 * i + 1] = PREMULTIPLY(rgb[4 * i + 1], mult);
+ rgb[4 * i + 2] = PREMULTIPLY(rgb[4 * i + 2], mult);
+ }
+ }
+ rgba += stride;
+ }
+}
+#undef MULTIPLIER
+#undef PREMULTIPLY
+
+// rgbA4444
+
+#define MULTIPLIER(a) ((a) * 0x1111) // 0x1111 ~= (1 << 16) / 15
+
+static WEBP_INLINE uint8_t dither_hi(uint8_t x) {
+ return (x & 0xf0) | (x >> 4);
+}
+
+static WEBP_INLINE uint8_t dither_lo(uint8_t x) {
+ return (x & 0x0f) | (x << 4);
+}
+
+static WEBP_INLINE uint8_t multiply(uint8_t x, uint32_t m) {
+ return (x * m) >> 16;
+}
+
+static void ApplyAlphaMultiply4444(uint8_t* rgba4444,
+ int w, int h, int stride) {
+ while (h-- > 0) {
+ int i;
+ for (i = 0; i < w; ++i) {
+ const uint8_t a = (rgba4444[2 * i + 1] & 0x0f);
+ const uint32_t mult = MULTIPLIER(a);
+ const uint8_t r = multiply(dither_hi(rgba4444[2 * i + 0]), mult);
+ const uint8_t g = multiply(dither_lo(rgba4444[2 * i + 0]), mult);
+ const uint8_t b = multiply(dither_hi(rgba4444[2 * i + 1]), mult);
+ rgba4444[2 * i + 0] = (r & 0xf0) | ((g >> 4) & 0x0f);
+ rgba4444[2 * i + 1] = (b & 0xf0) | a;
+ }
+ rgba4444 += stride;
+ }
+}
+#undef MULTIPLIER
+
+void (*WebPApplyAlphaMultiply)(uint8_t*, int, int, int, int)
+ = ApplyAlphaMultiply;
+void (*WebPApplyAlphaMultiply4444)(uint8_t*, int, int, int)
+ = ApplyAlphaMultiply4444;
+
+//------------------------------------------------------------------------------
+// Main call
+
+void WebPInitUpsamplers(void) {
+#ifdef FANCY_UPSAMPLING
+ WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePair;
+ WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePair;
+ WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePair;
+ WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePair;
+ WebPUpsamplers[MODE_ARGB] = UpsampleArgbLinePair;
+ WebPUpsamplers[MODE_RGBA_4444] = UpsampleRgba4444LinePair;
+ WebPUpsamplers[MODE_RGB_565] = UpsampleRgb565LinePair;
+
+ // If defined, use CPUInfo() to overwrite some pointers with faster versions.
+ if (VP8GetCPUInfo != NULL) {
+#if defined(WEBP_USE_SSE2)
+ if (VP8GetCPUInfo(kSSE2)) {
+ WebPInitUpsamplersSSE2();
+ }
+#endif
+ }
+#endif // FANCY_UPSAMPLING
+}
+
+void WebPInitPremultiply(void) {
+ WebPApplyAlphaMultiply = ApplyAlphaMultiply;
+ WebPApplyAlphaMultiply4444 = ApplyAlphaMultiply4444;
+
+#ifdef FANCY_UPSAMPLING
+ WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePair;
+ WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePair;
+ WebPUpsamplers[MODE_Argb] = UpsampleArgbLinePair;
+ WebPUpsamplers[MODE_rgbA_4444] = UpsampleRgba4444LinePair;
+
+ if (VP8GetCPUInfo != NULL) {
+#if defined(WEBP_USE_SSE2)
+ if (VP8GetCPUInfo(kSSE2)) {
+ WebPInitPremultiplySSE2();
+ }
+#endif
+ }
+#endif // FANCY_UPSAMPLING
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/dsp/upsampling_sse2.c b/drivers/webpold/dsp/upsampling_sse2.c
new file mode 100644
index 0000000000..8cb275a02b
--- /dev/null
+++ b/drivers/webpold/dsp/upsampling_sse2.c
@@ -0,0 +1,209 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// SSE2 version of YUV to RGB upsampling functions.
+//
+// Author: somnath@google.com (Somnath Banerjee)
+
+#include "./dsp.h"
+
+#if defined(WEBP_USE_SSE2)
+
+#include <assert.h>
+#include <emmintrin.h>
+#include <string.h>
+#include "./yuv.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#ifdef FANCY_UPSAMPLING
+
+// We compute (9*a + 3*b + 3*c + d + 8) / 16 as follows
+// u = (9*a + 3*b + 3*c + d + 8) / 16
+// = (a + (a + 3*b + 3*c + d) / 8 + 1) / 2
+// = (a + m + 1) / 2
+// where m = (a + 3*b + 3*c + d) / 8
+// = ((a + b + c + d) / 2 + b + c) / 4
+//
+// Let's say k = (a + b + c + d) / 4.
+// We can compute k as
+// k = (s + t + 1) / 2 - ((a^d) | (b^c) | (s^t)) & 1
+// where s = (a + d + 1) / 2 and t = (b + c + 1) / 2
+//
+// Then m can be written as
+// m = (k + t + 1) / 2 - (((b^c) & (s^t)) | (k^t)) & 1
+
+// Computes out = (k + in + 1) / 2 - ((ij & (s^t)) | (k^in)) & 1
+#define GET_M(ij, in, out) do { \
+ const __m128i tmp0 = _mm_avg_epu8(k, (in)); /* (k + in + 1) / 2 */ \
+ const __m128i tmp1 = _mm_and_si128((ij), st); /* (ij) & (s^t) */ \
+ const __m128i tmp2 = _mm_xor_si128(k, (in)); /* (k^in) */ \
+ const __m128i tmp3 = _mm_or_si128(tmp1, tmp2); /* ((ij) & (s^t)) | (k^in) */\
+ const __m128i tmp4 = _mm_and_si128(tmp3, one); /* & 1 -> lsb_correction */ \
+ (out) = _mm_sub_epi8(tmp0, tmp4); /* (k + in + 1) / 2 - lsb_correction */ \
+} while (0)
+
+// pack and store two alterning pixel rows
+#define PACK_AND_STORE(a, b, da, db, out) do { \
+ const __m128i ta = _mm_avg_epu8(a, da); /* (9a + 3b + 3c + d + 8) / 16 */ \
+ const __m128i tb = _mm_avg_epu8(b, db); /* (3a + 9b + c + 3d + 8) / 16 */ \
+ const __m128i t1 = _mm_unpacklo_epi8(ta, tb); \
+ const __m128i t2 = _mm_unpackhi_epi8(ta, tb); \
+ _mm_store_si128(((__m128i*)(out)) + 0, t1); \
+ _mm_store_si128(((__m128i*)(out)) + 1, t2); \
+} while (0)
+
+// Loads 17 pixels each from rows r1 and r2 and generates 32 pixels.
+#define UPSAMPLE_32PIXELS(r1, r2, out) { \
+ const __m128i one = _mm_set1_epi8(1); \
+ const __m128i a = _mm_loadu_si128((__m128i*)&(r1)[0]); \
+ const __m128i b = _mm_loadu_si128((__m128i*)&(r1)[1]); \
+ const __m128i c = _mm_loadu_si128((__m128i*)&(r2)[0]); \
+ const __m128i d = _mm_loadu_si128((__m128i*)&(r2)[1]); \
+ \
+ const __m128i s = _mm_avg_epu8(a, d); /* s = (a + d + 1) / 2 */ \
+ const __m128i t = _mm_avg_epu8(b, c); /* t = (b + c + 1) / 2 */ \
+ const __m128i st = _mm_xor_si128(s, t); /* st = s^t */ \
+ \
+ const __m128i ad = _mm_xor_si128(a, d); /* ad = a^d */ \
+ const __m128i bc = _mm_xor_si128(b, c); /* bc = b^c */ \
+ \
+ const __m128i t1 = _mm_or_si128(ad, bc); /* (a^d) | (b^c) */ \
+ const __m128i t2 = _mm_or_si128(t1, st); /* (a^d) | (b^c) | (s^t) */ \
+ const __m128i t3 = _mm_and_si128(t2, one); /* (a^d) | (b^c) | (s^t) & 1 */ \
+ const __m128i t4 = _mm_avg_epu8(s, t); \
+ const __m128i k = _mm_sub_epi8(t4, t3); /* k = (a + b + c + d) / 4 */ \
+ __m128i diag1, diag2; \
+ \
+ GET_M(bc, t, diag1); /* diag1 = (a + 3b + 3c + d) / 8 */ \
+ GET_M(ad, s, diag2); /* diag2 = (3a + b + c + 3d) / 8 */ \
+ \
+ /* pack the alternate pixels */ \
+ PACK_AND_STORE(a, b, diag1, diag2, &(out)[0 * 32]); \
+ PACK_AND_STORE(c, d, diag2, diag1, &(out)[2 * 32]); \
+}
+
+// Turn the macro into a function for reducing code-size when non-critical
+static void Upsample32Pixels(const uint8_t r1[], const uint8_t r2[],
+ uint8_t* const out) {
+ UPSAMPLE_32PIXELS(r1, r2, out);
+}
+
+#define UPSAMPLE_LAST_BLOCK(tb, bb, num_pixels, out) { \
+ uint8_t r1[17], r2[17]; \
+ memcpy(r1, (tb), (num_pixels)); \
+ memcpy(r2, (bb), (num_pixels)); \
+ /* replicate last byte */ \
+ memset(r1 + (num_pixels), r1[(num_pixels) - 1], 17 - (num_pixels)); \
+ memset(r2 + (num_pixels), r2[(num_pixels) - 1], 17 - (num_pixels)); \
+ /* using the shared function instead of the macro saves ~3k code size */ \
+ Upsample32Pixels(r1, r2, out); \
+}
+
+#define CONVERT2RGB(FUNC, XSTEP, top_y, bottom_y, uv, \
+ top_dst, bottom_dst, cur_x, num_pixels) { \
+ int n; \
+ if (top_y) { \
+ for (n = 0; n < (num_pixels); ++n) { \
+ FUNC(top_y[(cur_x) + n], (uv)[n], (uv)[32 + n], \
+ top_dst + ((cur_x) + n) * XSTEP); \
+ } \
+ } \
+ if (bottom_y) { \
+ for (n = 0; n < (num_pixels); ++n) { \
+ FUNC(bottom_y[(cur_x) + n], (uv)[64 + n], (uv)[64 + 32 + n], \
+ bottom_dst + ((cur_x) + n) * XSTEP); \
+ } \
+ } \
+}
+
+#define SSE2_UPSAMPLE_FUNC(FUNC_NAME, FUNC, XSTEP) \
+static void FUNC_NAME(const uint8_t* top_y, const uint8_t* bottom_y, \
+ const uint8_t* top_u, const uint8_t* top_v, \
+ const uint8_t* cur_u, const uint8_t* cur_v, \
+ uint8_t* top_dst, uint8_t* bottom_dst, int len) { \
+ int b; \
+ /* 16 byte aligned array to cache reconstructed u and v */ \
+ uint8_t uv_buf[4 * 32 + 15]; \
+ uint8_t* const r_uv = (uint8_t*)((uintptr_t)(uv_buf + 15) & ~15); \
+ const int uv_len = (len + 1) >> 1; \
+ /* 17 pixels must be read-able for each block */ \
+ const int num_blocks = (uv_len - 1) >> 4; \
+ const int leftover = uv_len - num_blocks * 16; \
+ const int last_pos = 1 + 32 * num_blocks; \
+ \
+ const int u_diag = ((top_u[0] + cur_u[0]) >> 1) + 1; \
+ const int v_diag = ((top_v[0] + cur_v[0]) >> 1) + 1; \
+ \
+ assert(len > 0); \
+ /* Treat the first pixel in regular way */ \
+ if (top_y) { \
+ const int u0 = (top_u[0] + u_diag) >> 1; \
+ const int v0 = (top_v[0] + v_diag) >> 1; \
+ FUNC(top_y[0], u0, v0, top_dst); \
+ } \
+ if (bottom_y) { \
+ const int u0 = (cur_u[0] + u_diag) >> 1; \
+ const int v0 = (cur_v[0] + v_diag) >> 1; \
+ FUNC(bottom_y[0], u0, v0, bottom_dst); \
+ } \
+ \
+ for (b = 0; b < num_blocks; ++b) { \
+ UPSAMPLE_32PIXELS(top_u, cur_u, r_uv + 0 * 32); \
+ UPSAMPLE_32PIXELS(top_v, cur_v, r_uv + 1 * 32); \
+ CONVERT2RGB(FUNC, XSTEP, top_y, bottom_y, r_uv, top_dst, bottom_dst, \
+ 32 * b + 1, 32) \
+ top_u += 16; \
+ cur_u += 16; \
+ top_v += 16; \
+ cur_v += 16; \
+ } \
+ \
+ UPSAMPLE_LAST_BLOCK(top_u, cur_u, leftover, r_uv + 0 * 32); \
+ UPSAMPLE_LAST_BLOCK(top_v, cur_v, leftover, r_uv + 1 * 32); \
+ CONVERT2RGB(FUNC, XSTEP, top_y, bottom_y, r_uv, top_dst, bottom_dst, \
+ last_pos, len - last_pos); \
+}
+
+// SSE2 variants of the fancy upsampler.
+SSE2_UPSAMPLE_FUNC(UpsampleRgbLinePairSSE2, VP8YuvToRgb, 3)
+SSE2_UPSAMPLE_FUNC(UpsampleBgrLinePairSSE2, VP8YuvToBgr, 3)
+SSE2_UPSAMPLE_FUNC(UpsampleRgbaLinePairSSE2, VP8YuvToRgba, 4)
+SSE2_UPSAMPLE_FUNC(UpsampleBgraLinePairSSE2, VP8YuvToBgra, 4)
+
+#undef GET_M
+#undef PACK_AND_STORE
+#undef UPSAMPLE_32PIXELS
+#undef UPSAMPLE_LAST_BLOCK
+#undef CONVERT2RGB
+#undef SSE2_UPSAMPLE_FUNC
+
+//------------------------------------------------------------------------------
+
+extern WebPUpsampleLinePairFunc WebPUpsamplers[/* MODE_LAST */];
+
+void WebPInitUpsamplersSSE2(void) {
+ WebPUpsamplers[MODE_RGB] = UpsampleRgbLinePairSSE2;
+ WebPUpsamplers[MODE_RGBA] = UpsampleRgbaLinePairSSE2;
+ WebPUpsamplers[MODE_BGR] = UpsampleBgrLinePairSSE2;
+ WebPUpsamplers[MODE_BGRA] = UpsampleBgraLinePairSSE2;
+}
+
+void WebPInitPremultiplySSE2(void) {
+ WebPUpsamplers[MODE_rgbA] = UpsampleRgbaLinePairSSE2;
+ WebPUpsamplers[MODE_bgrA] = UpsampleBgraLinePairSSE2;
+}
+
+#endif // FANCY_UPSAMPLING
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif // WEBP_USE_SSE2
diff --git a/drivers/webpold/dsp/yuv.c b/drivers/webpold/dsp/yuv.c
new file mode 100644
index 0000000000..7f05f9a3aa
--- /dev/null
+++ b/drivers/webpold/dsp/yuv.c
@@ -0,0 +1,52 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// YUV->RGB conversion function
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./yuv.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+enum { YUV_HALF = 1 << (YUV_FIX - 1) };
+
+int16_t VP8kVToR[256], VP8kUToB[256];
+int32_t VP8kVToG[256], VP8kUToG[256];
+uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN];
+uint8_t VP8kClip4Bits[YUV_RANGE_MAX - YUV_RANGE_MIN];
+
+static int done = 0;
+
+static WEBP_INLINE uint8_t clip(int v, int max_value) {
+ return v < 0 ? 0 : v > max_value ? max_value : v;
+}
+
+void VP8YUVInit(void) {
+ int i;
+ if (done) {
+ return;
+ }
+ for (i = 0; i < 256; ++i) {
+ VP8kVToR[i] = (89858 * (i - 128) + YUV_HALF) >> YUV_FIX;
+ VP8kUToG[i] = -22014 * (i - 128) + YUV_HALF;
+ VP8kVToG[i] = -45773 * (i - 128);
+ VP8kUToB[i] = (113618 * (i - 128) + YUV_HALF) >> YUV_FIX;
+ }
+ for (i = YUV_RANGE_MIN; i < YUV_RANGE_MAX; ++i) {
+ const int k = ((i - 16) * 76283 + YUV_HALF) >> YUV_FIX;
+ VP8kClip[i - YUV_RANGE_MIN] = clip(k, 255);
+ VP8kClip4Bits[i - YUV_RANGE_MIN] = clip((k + 8) >> 4, 15);
+ }
+ done = 1;
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/dsp/yuv.h b/drivers/webpold/dsp/yuv.h
new file mode 100644
index 0000000000..a569109c54
--- /dev/null
+++ b/drivers/webpold/dsp/yuv.h
@@ -0,0 +1,128 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// inline YUV<->RGB conversion function
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#ifndef WEBP_DSP_YUV_H_
+#define WEBP_DSP_YUV_H_
+
+#include "../dec/decode_vp8.h"
+
+//------------------------------------------------------------------------------
+// YUV -> RGB conversion
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+enum { YUV_FIX = 16, // fixed-point precision
+ YUV_RANGE_MIN = -227, // min value of r/g/b output
+ YUV_RANGE_MAX = 256 + 226 // max value of r/g/b output
+};
+extern int16_t VP8kVToR[256], VP8kUToB[256];
+extern int32_t VP8kVToG[256], VP8kUToG[256];
+extern uint8_t VP8kClip[YUV_RANGE_MAX - YUV_RANGE_MIN];
+extern uint8_t VP8kClip4Bits[YUV_RANGE_MAX - YUV_RANGE_MIN];
+
+static WEBP_INLINE void VP8YuvToRgb(uint8_t y, uint8_t u, uint8_t v,
+ uint8_t* const rgb) {
+ const int r_off = VP8kVToR[v];
+ const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
+ const int b_off = VP8kUToB[u];
+ rgb[0] = VP8kClip[y + r_off - YUV_RANGE_MIN];
+ rgb[1] = VP8kClip[y + g_off - YUV_RANGE_MIN];
+ rgb[2] = VP8kClip[y + b_off - YUV_RANGE_MIN];
+}
+
+static WEBP_INLINE void VP8YuvToRgb565(uint8_t y, uint8_t u, uint8_t v,
+ uint8_t* const rgb) {
+ const int r_off = VP8kVToR[v];
+ const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
+ const int b_off = VP8kUToB[u];
+ rgb[0] = ((VP8kClip[y + r_off - YUV_RANGE_MIN] & 0xf8) |
+ (VP8kClip[y + g_off - YUV_RANGE_MIN] >> 5));
+ rgb[1] = (((VP8kClip[y + g_off - YUV_RANGE_MIN] << 3) & 0xe0) |
+ (VP8kClip[y + b_off - YUV_RANGE_MIN] >> 3));
+}
+
+static WEBP_INLINE void VP8YuvToArgb(uint8_t y, uint8_t u, uint8_t v,
+ uint8_t* const argb) {
+ argb[0] = 0xff;
+ VP8YuvToRgb(y, u, v, argb + 1);
+}
+
+static WEBP_INLINE void VP8YuvToRgba4444(uint8_t y, uint8_t u, uint8_t v,
+ uint8_t* const argb) {
+ const int r_off = VP8kVToR[v];
+ const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
+ const int b_off = VP8kUToB[u];
+ // Don't update alpha (last 4 bits of argb[1])
+ argb[0] = ((VP8kClip4Bits[y + r_off - YUV_RANGE_MIN] << 4) |
+ VP8kClip4Bits[y + g_off - YUV_RANGE_MIN]);
+ argb[1] = 0x0f | (VP8kClip4Bits[y + b_off - YUV_RANGE_MIN] << 4);
+}
+
+static WEBP_INLINE void VP8YuvToBgr(uint8_t y, uint8_t u, uint8_t v,
+ uint8_t* const bgr) {
+ const int r_off = VP8kVToR[v];
+ const int g_off = (VP8kVToG[v] + VP8kUToG[u]) >> YUV_FIX;
+ const int b_off = VP8kUToB[u];
+ bgr[0] = VP8kClip[y + b_off - YUV_RANGE_MIN];
+ bgr[1] = VP8kClip[y + g_off - YUV_RANGE_MIN];
+ bgr[2] = VP8kClip[y + r_off - YUV_RANGE_MIN];
+}
+
+static WEBP_INLINE void VP8YuvToBgra(uint8_t y, uint8_t u, uint8_t v,
+ uint8_t* const bgra) {
+ VP8YuvToBgr(y, u, v, bgra);
+ bgra[3] = 0xff;
+}
+
+static WEBP_INLINE void VP8YuvToRgba(uint8_t y, uint8_t u, uint8_t v,
+ uint8_t* const rgba) {
+ VP8YuvToRgb(y, u, v, rgba);
+ rgba[3] = 0xff;
+}
+
+// Must be called before everything, to initialize the tables.
+void VP8YUVInit(void);
+
+//------------------------------------------------------------------------------
+// RGB -> YUV conversion
+// The exact naming is Y'CbCr, following the ITU-R BT.601 standard.
+// More information at: http://en.wikipedia.org/wiki/YCbCr
+// Y = 0.2569 * R + 0.5044 * G + 0.0979 * B + 16
+// U = -0.1483 * R - 0.2911 * G + 0.4394 * B + 128
+// V = 0.4394 * R - 0.3679 * G - 0.0715 * B + 128
+// We use 16bit fixed point operations.
+
+static WEBP_INLINE int VP8ClipUV(int v) {
+ v = (v + (257 << (YUV_FIX + 2 - 1))) >> (YUV_FIX + 2);
+ return ((v & ~0xff) == 0) ? v : (v < 0) ? 0 : 255;
+}
+
+static WEBP_INLINE int VP8RGBToY(int r, int g, int b) {
+ const int kRound = (1 << (YUV_FIX - 1)) + (16 << YUV_FIX);
+ const int luma = 16839 * r + 33059 * g + 6420 * b;
+ return (luma + kRound) >> YUV_FIX; // no need to clip
+}
+
+static WEBP_INLINE int VP8RGBToU(int r, int g, int b) {
+ return VP8ClipUV(-9719 * r - 19081 * g + 28800 * b);
+}
+
+static WEBP_INLINE int VP8RGBToV(int r, int g, int b) {
+ return VP8ClipUV(+28800 * r - 24116 * g - 4684 * b);
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif /* WEBP_DSP_YUV_H_ */
diff --git a/drivers/webpold/enc/alpha.c b/drivers/webpold/enc/alpha.c
new file mode 100644
index 0000000000..e554eb7f30
--- /dev/null
+++ b/drivers/webpold/enc/alpha.c
@@ -0,0 +1,330 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Alpha-plane compression.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "./vp8enci.h"
+#include "../utils/filters.h"
+#include "../utils/quant_levels.h"
+#include "../format_constants.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+// -----------------------------------------------------------------------------
+// Encodes the given alpha data via specified compression method 'method'.
+// The pre-processing (quantization) is performed if 'quality' is less than 100.
+// For such cases, the encoding is lossy. The valid range is [0, 100] for
+// 'quality' and [0, 1] for 'method':
+// 'method = 0' - No compression;
+// 'method = 1' - Use lossless coder on the alpha plane only
+// 'filter' values [0, 4] correspond to prediction modes none, horizontal,
+// vertical & gradient filters. The prediction mode 4 will try all the
+// prediction modes 0 to 3 and pick the best one.
+// 'effort_level': specifies how much effort must be spent to try and reduce
+// the compressed output size. In range 0 (quick) to 6 (slow).
+//
+// 'output' corresponds to the buffer containing compressed alpha data.
+// This buffer is allocated by this method and caller should call
+// free(*output) when done.
+// 'output_size' corresponds to size of this compressed alpha buffer.
+//
+// Returns 1 on successfully encoding the alpha and
+// 0 if either:
+// invalid quality or method, or
+// memory allocation for the compressed data fails.
+
+#include "../enc/vp8li.h"
+
+static int EncodeLossless(const uint8_t* const data, int width, int height,
+ int effort_level, // in [0..6] range
+ VP8BitWriter* const bw,
+ WebPAuxStats* const stats) {
+ int ok = 0;
+ WebPConfig config;
+ WebPPicture picture;
+ VP8LBitWriter tmp_bw;
+
+ WebPPictureInit(&picture);
+ picture.width = width;
+ picture.height = height;
+ picture.use_argb = 1;
+ picture.stats = stats;
+ if (!WebPPictureAlloc(&picture)) return 0;
+
+ // Transfer the alpha values to the green channel.
+ {
+ int i, j;
+ uint32_t* dst = picture.argb;
+ const uint8_t* src = data;
+ for (j = 0; j < picture.height; ++j) {
+ for (i = 0; i < picture.width; ++i) {
+ dst[i] = (src[i] << 8) | 0xff000000u;
+ }
+ src += width;
+ dst += picture.argb_stride;
+ }
+ }
+
+ WebPConfigInit(&config);
+ config.lossless = 1;
+ config.method = effort_level; // impact is very small
+ // Set moderate default quality setting for alpha. Higher qualities (80 and
+ // above) could be very slow.
+ config.quality = 10.f + 15.f * effort_level;
+ if (config.quality > 100.f) config.quality = 100.f;
+
+ ok = VP8LBitWriterInit(&tmp_bw, (width * height) >> 3);
+ ok = ok && (VP8LEncodeStream(&config, &picture, &tmp_bw) == VP8_ENC_OK);
+ WebPPictureFree(&picture);
+ if (ok) {
+ const uint8_t* const data = VP8LBitWriterFinish(&tmp_bw);
+ const size_t data_size = VP8LBitWriterNumBytes(&tmp_bw);
+ VP8BitWriterAppend(bw, data, data_size);
+ }
+ VP8LBitWriterDestroy(&tmp_bw);
+ return ok && !bw->error_;
+}
+
+// -----------------------------------------------------------------------------
+
+static int EncodeAlphaInternal(const uint8_t* const data, int width, int height,
+ int method, int filter, int reduce_levels,
+ int effort_level, // in [0..6] range
+ uint8_t* const tmp_alpha,
+ VP8BitWriter* const bw,
+ WebPAuxStats* const stats) {
+ int ok = 0;
+ const uint8_t* alpha_src;
+ WebPFilterFunc filter_func;
+ uint8_t header;
+ size_t expected_size;
+ const size_t data_size = width * height;
+
+ assert((uint64_t)data_size == (uint64_t)width * height); // as per spec
+ assert(filter >= 0 && filter < WEBP_FILTER_LAST);
+ assert(method >= ALPHA_NO_COMPRESSION);
+ assert(method <= ALPHA_LOSSLESS_COMPRESSION);
+ assert(sizeof(header) == ALPHA_HEADER_LEN);
+ // TODO(skal): have a common function and #define's to validate alpha params.
+
+ expected_size =
+ (method == ALPHA_NO_COMPRESSION) ? (ALPHA_HEADER_LEN + data_size)
+ : (data_size >> 5);
+ header = method | (filter << 2);
+ if (reduce_levels) header |= ALPHA_PREPROCESSED_LEVELS << 4;
+
+ VP8BitWriterInit(bw, expected_size);
+ VP8BitWriterAppend(bw, &header, ALPHA_HEADER_LEN);
+
+ filter_func = WebPFilters[filter];
+ if (filter_func) {
+ filter_func(data, width, height, 1, width, tmp_alpha);
+ alpha_src = tmp_alpha;
+ } else {
+ alpha_src = data;
+ }
+
+ if (method == ALPHA_NO_COMPRESSION) {
+ ok = VP8BitWriterAppend(bw, alpha_src, width * height);
+ ok = ok && !bw->error_;
+ } else {
+ ok = EncodeLossless(alpha_src, width, height, effort_level, bw, stats);
+ VP8BitWriterFinish(bw);
+ }
+ return ok;
+}
+
+// -----------------------------------------------------------------------------
+
+// TODO(skal): move to dsp/ ?
+static void CopyPlane(const uint8_t* src, int src_stride,
+ uint8_t* dst, int dst_stride, int width, int height) {
+ while (height-- > 0) {
+ memcpy(dst, src, width);
+ src += src_stride;
+ dst += dst_stride;
+ }
+}
+
+static int EncodeAlpha(VP8Encoder* const enc,
+ int quality, int method, int filter,
+ int effort_level,
+ uint8_t** const output, size_t* const output_size) {
+ const WebPPicture* const pic = enc->pic_;
+ const int width = pic->width;
+ const int height = pic->height;
+
+ uint8_t* quant_alpha = NULL;
+ const size_t data_size = width * height;
+ uint64_t sse = 0;
+ int ok = 1;
+ const int reduce_levels = (quality < 100);
+
+ // quick sanity checks
+ assert((uint64_t)data_size == (uint64_t)width * height); // as per spec
+ assert(enc != NULL && pic != NULL && pic->a != NULL);
+ assert(output != NULL && output_size != NULL);
+ assert(width > 0 && height > 0);
+ assert(pic->a_stride >= width);
+ assert(filter >= WEBP_FILTER_NONE && filter <= WEBP_FILTER_FAST);
+
+ if (quality < 0 || quality > 100) {
+ return 0;
+ }
+
+ if (method < ALPHA_NO_COMPRESSION || method > ALPHA_LOSSLESS_COMPRESSION) {
+ return 0;
+ }
+
+ quant_alpha = (uint8_t*)malloc(data_size);
+ if (quant_alpha == NULL) {
+ return 0;
+ }
+
+ // Extract alpha data (width x height) from raw_data (stride x height).
+ CopyPlane(pic->a, pic->a_stride, quant_alpha, width, width, height);
+
+ if (reduce_levels) { // No Quantization required for 'quality = 100'.
+ // 16 alpha levels gives quite a low MSE w.r.t original alpha plane hence
+ // mapped to moderate quality 70. Hence Quality:[0, 70] -> Levels:[2, 16]
+ // and Quality:]70, 100] -> Levels:]16, 256].
+ const int alpha_levels = (quality <= 70) ? (2 + quality / 5)
+ : (16 + (quality - 70) * 8);
+ ok = QuantizeLevels(quant_alpha, width, height, alpha_levels, &sse);
+ }
+
+ if (ok) {
+ VP8BitWriter bw;
+ int test_filter;
+ uint8_t* filtered_alpha = NULL;
+
+ // We always test WEBP_FILTER_NONE first.
+ ok = EncodeAlphaInternal(quant_alpha, width, height,
+ method, WEBP_FILTER_NONE, reduce_levels,
+ effort_level, NULL, &bw, pic->stats);
+ if (!ok) {
+ VP8BitWriterWipeOut(&bw);
+ goto End;
+ }
+
+ if (filter == WEBP_FILTER_FAST) { // Quick estimate of a second candidate?
+ filter = EstimateBestFilter(quant_alpha, width, height, width);
+ }
+ // Stop?
+ if (filter == WEBP_FILTER_NONE) {
+ goto Ok;
+ }
+
+ filtered_alpha = (uint8_t*)malloc(data_size);
+ ok = (filtered_alpha != NULL);
+ if (!ok) {
+ goto End;
+ }
+
+ // Try the other mode(s).
+ {
+ WebPAuxStats best_stats;
+ size_t best_score = VP8BitWriterSize(&bw);
+
+ memset(&best_stats, 0, sizeof(best_stats)); // prevent spurious warning
+ if (pic->stats != NULL) best_stats = *pic->stats;
+ for (test_filter = WEBP_FILTER_HORIZONTAL;
+ ok && (test_filter <= WEBP_FILTER_GRADIENT);
+ ++test_filter) {
+ VP8BitWriter tmp_bw;
+ if (filter != WEBP_FILTER_BEST && test_filter != filter) {
+ continue;
+ }
+ ok = EncodeAlphaInternal(quant_alpha, width, height,
+ method, test_filter, reduce_levels,
+ effort_level, filtered_alpha, &tmp_bw,
+ pic->stats);
+ if (ok) {
+ const size_t score = VP8BitWriterSize(&tmp_bw);
+ if (score < best_score) {
+ // swap bitwriter objects.
+ VP8BitWriter tmp = tmp_bw;
+ tmp_bw = bw;
+ bw = tmp;
+ best_score = score;
+ if (pic->stats != NULL) best_stats = *pic->stats;
+ }
+ } else {
+ VP8BitWriterWipeOut(&bw);
+ }
+ VP8BitWriterWipeOut(&tmp_bw);
+ }
+ if (pic->stats != NULL) *pic->stats = best_stats;
+ }
+ Ok:
+ if (ok) {
+ *output_size = VP8BitWriterSize(&bw);
+ *output = VP8BitWriterBuf(&bw);
+ if (pic->stats != NULL) { // need stats?
+ pic->stats->coded_size += (int)(*output_size);
+ enc->sse_[3] = sse;
+ }
+ }
+ free(filtered_alpha);
+ }
+ End:
+ free(quant_alpha);
+ return ok;
+}
+
+
+//------------------------------------------------------------------------------
+// Main calls
+
+void VP8EncInitAlpha(VP8Encoder* const enc) {
+ enc->has_alpha_ = WebPPictureHasTransparency(enc->pic_);
+ enc->alpha_data_ = NULL;
+ enc->alpha_data_size_ = 0;
+}
+
+int VP8EncFinishAlpha(VP8Encoder* const enc) {
+ if (enc->has_alpha_) {
+ const WebPConfig* config = enc->config_;
+ uint8_t* tmp_data = NULL;
+ size_t tmp_size = 0;
+ const int effort_level = config->method; // maps to [0..6]
+ const WEBP_FILTER_TYPE filter =
+ (config->alpha_filtering == 0) ? WEBP_FILTER_NONE :
+ (config->alpha_filtering == 1) ? WEBP_FILTER_FAST :
+ WEBP_FILTER_BEST;
+
+ if (!EncodeAlpha(enc, config->alpha_quality, config->alpha_compression,
+ filter, effort_level, &tmp_data, &tmp_size)) {
+ return 0;
+ }
+ if (tmp_size != (uint32_t)tmp_size) { // Sanity check.
+ free(tmp_data);
+ return 0;
+ }
+ enc->alpha_data_size_ = (uint32_t)tmp_size;
+ enc->alpha_data_ = tmp_data;
+ }
+ return WebPReportProgress(enc->pic_, enc->percent_ + 20, &enc->percent_);
+}
+
+void VP8EncDeleteAlpha(VP8Encoder* const enc) {
+ free(enc->alpha_data_);
+ enc->alpha_data_ = NULL;
+ enc->alpha_data_size_ = 0;
+ enc->has_alpha_ = 0;
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/enc/analysis.c b/drivers/webpold/enc/analysis.c
new file mode 100644
index 0000000000..22cfb492e7
--- /dev/null
+++ b/drivers/webpold/enc/analysis.c
@@ -0,0 +1,364 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Macroblock analysis
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "./vp8enci.h"
+#include "./cost.h"
+#include "../utils/utils.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define MAX_ITERS_K_MEANS 6
+
+static int ClipAlpha(int alpha) {
+ return alpha < 0 ? 0 : alpha > 255 ? 255 : alpha;
+}
+
+//------------------------------------------------------------------------------
+// Smooth the segment map by replacing isolated block by the majority of its
+// neighbours.
+
+static void SmoothSegmentMap(VP8Encoder* const enc) {
+ int n, x, y;
+ const int w = enc->mb_w_;
+ const int h = enc->mb_h_;
+ const int majority_cnt_3_x_3_grid = 5;
+ uint8_t* const tmp = (uint8_t*)WebPSafeMalloc((uint64_t)w * h, sizeof(*tmp));
+ assert((uint64_t)(w * h) == (uint64_t)w * h); // no overflow, as per spec
+
+ if (tmp == NULL) return;
+ for (y = 1; y < h - 1; ++y) {
+ for (x = 1; x < w - 1; ++x) {
+ int cnt[NUM_MB_SEGMENTS] = { 0 };
+ const VP8MBInfo* const mb = &enc->mb_info_[x + w * y];
+ int majority_seg = mb->segment_;
+ // Check the 8 neighbouring segment values.
+ cnt[mb[-w - 1].segment_]++; // top-left
+ cnt[mb[-w + 0].segment_]++; // top
+ cnt[mb[-w + 1].segment_]++; // top-right
+ cnt[mb[ - 1].segment_]++; // left
+ cnt[mb[ + 1].segment_]++; // right
+ cnt[mb[ w - 1].segment_]++; // bottom-left
+ cnt[mb[ w + 0].segment_]++; // bottom
+ cnt[mb[ w + 1].segment_]++; // bottom-right
+ for (n = 0; n < NUM_MB_SEGMENTS; ++n) {
+ if (cnt[n] >= majority_cnt_3_x_3_grid) {
+ majority_seg = n;
+ }
+ }
+ tmp[x + y * w] = majority_seg;
+ }
+ }
+ for (y = 1; y < h - 1; ++y) {
+ for (x = 1; x < w - 1; ++x) {
+ VP8MBInfo* const mb = &enc->mb_info_[x + w * y];
+ mb->segment_ = tmp[x + y * w];
+ }
+ }
+ free(tmp);
+}
+
+//------------------------------------------------------------------------------
+// Finalize Segment probability based on the coding tree
+
+static int GetProba(int a, int b) {
+ int proba;
+ const int total = a + b;
+ if (total == 0) return 255; // that's the default probability.
+ proba = (255 * a + total / 2) / total;
+ return proba;
+}
+
+static void SetSegmentProbas(VP8Encoder* const enc) {
+ int p[NUM_MB_SEGMENTS] = { 0 };
+ int n;
+
+ for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) {
+ const VP8MBInfo* const mb = &enc->mb_info_[n];
+ p[mb->segment_]++;
+ }
+ if (enc->pic_->stats) {
+ for (n = 0; n < NUM_MB_SEGMENTS; ++n) {
+ enc->pic_->stats->segment_size[n] = p[n];
+ }
+ }
+ if (enc->segment_hdr_.num_segments_ > 1) {
+ uint8_t* const probas = enc->proba_.segments_;
+ probas[0] = GetProba(p[0] + p[1], p[2] + p[3]);
+ probas[1] = GetProba(p[0], p[1]);
+ probas[2] = GetProba(p[2], p[3]);
+
+ enc->segment_hdr_.update_map_ =
+ (probas[0] != 255) || (probas[1] != 255) || (probas[2] != 255);
+ enc->segment_hdr_.size_ =
+ p[0] * (VP8BitCost(0, probas[0]) + VP8BitCost(0, probas[1])) +
+ p[1] * (VP8BitCost(0, probas[0]) + VP8BitCost(1, probas[1])) +
+ p[2] * (VP8BitCost(1, probas[0]) + VP8BitCost(0, probas[2])) +
+ p[3] * (VP8BitCost(1, probas[0]) + VP8BitCost(1, probas[2]));
+ } else {
+ enc->segment_hdr_.update_map_ = 0;
+ enc->segment_hdr_.size_ = 0;
+ }
+}
+
+static WEBP_INLINE int clip(int v, int m, int M) {
+ return v < m ? m : v > M ? M : v;
+}
+
+static void SetSegmentAlphas(VP8Encoder* const enc,
+ const int centers[NUM_MB_SEGMENTS],
+ int mid) {
+ const int nb = enc->segment_hdr_.num_segments_;
+ int min = centers[0], max = centers[0];
+ int n;
+
+ if (nb > 1) {
+ for (n = 0; n < nb; ++n) {
+ if (min > centers[n]) min = centers[n];
+ if (max < centers[n]) max = centers[n];
+ }
+ }
+ if (max == min) max = min + 1;
+ assert(mid <= max && mid >= min);
+ for (n = 0; n < nb; ++n) {
+ const int alpha = 255 * (centers[n] - mid) / (max - min);
+ const int beta = 255 * (centers[n] - min) / (max - min);
+ enc->dqm_[n].alpha_ = clip(alpha, -127, 127);
+ enc->dqm_[n].beta_ = clip(beta, 0, 255);
+ }
+}
+
+//------------------------------------------------------------------------------
+// Simplified k-Means, to assign Nb segments based on alpha-histogram
+
+static void AssignSegments(VP8Encoder* const enc, const int alphas[256]) {
+ const int nb = enc->segment_hdr_.num_segments_;
+ int centers[NUM_MB_SEGMENTS];
+ int weighted_average = 0;
+ int map[256];
+ int a, n, k;
+ int min_a = 0, max_a = 255, range_a;
+ // 'int' type is ok for histo, and won't overflow
+ int accum[NUM_MB_SEGMENTS], dist_accum[NUM_MB_SEGMENTS];
+
+ // bracket the input
+ for (n = 0; n < 256 && alphas[n] == 0; ++n) {}
+ min_a = n;
+ for (n = 255; n > min_a && alphas[n] == 0; --n) {}
+ max_a = n;
+ range_a = max_a - min_a;
+
+ // Spread initial centers evenly
+ for (n = 1, k = 0; n < 2 * nb; n += 2) {
+ centers[k++] = min_a + (n * range_a) / (2 * nb);
+ }
+
+ for (k = 0; k < MAX_ITERS_K_MEANS; ++k) { // few iters are enough
+ int total_weight;
+ int displaced;
+ // Reset stats
+ for (n = 0; n < nb; ++n) {
+ accum[n] = 0;
+ dist_accum[n] = 0;
+ }
+ // Assign nearest center for each 'a'
+ n = 0; // track the nearest center for current 'a'
+ for (a = min_a; a <= max_a; ++a) {
+ if (alphas[a]) {
+ while (n < nb - 1 && abs(a - centers[n + 1]) < abs(a - centers[n])) {
+ n++;
+ }
+ map[a] = n;
+ // accumulate contribution into best centroid
+ dist_accum[n] += a * alphas[a];
+ accum[n] += alphas[a];
+ }
+ }
+ // All point are classified. Move the centroids to the
+ // center of their respective cloud.
+ displaced = 0;
+ weighted_average = 0;
+ total_weight = 0;
+ for (n = 0; n < nb; ++n) {
+ if (accum[n]) {
+ const int new_center = (dist_accum[n] + accum[n] / 2) / accum[n];
+ displaced += abs(centers[n] - new_center);
+ centers[n] = new_center;
+ weighted_average += new_center * accum[n];
+ total_weight += accum[n];
+ }
+ }
+ weighted_average = (weighted_average + total_weight / 2) / total_weight;
+ if (displaced < 5) break; // no need to keep on looping...
+ }
+
+ // Map each original value to the closest centroid
+ for (n = 0; n < enc->mb_w_ * enc->mb_h_; ++n) {
+ VP8MBInfo* const mb = &enc->mb_info_[n];
+ const int alpha = mb->alpha_;
+ mb->segment_ = map[alpha];
+ mb->alpha_ = centers[map[alpha]]; // just for the record.
+ }
+
+ if (nb > 1) {
+ const int smooth = (enc->config_->preprocessing & 1);
+ if (smooth) SmoothSegmentMap(enc);
+ }
+
+ SetSegmentProbas(enc); // Assign final proba
+ SetSegmentAlphas(enc, centers, weighted_average); // pick some alphas.
+}
+
+//------------------------------------------------------------------------------
+// Macroblock analysis: collect histogram for each mode, deduce the maximal
+// susceptibility and set best modes for this macroblock.
+// Segment assignment is done later.
+
+// Number of modes to inspect for alpha_ evaluation. For high-quality settings,
+// we don't need to test all the possible modes during the analysis phase.
+#define MAX_INTRA16_MODE 2
+#define MAX_INTRA4_MODE 2
+#define MAX_UV_MODE 2
+
+static int MBAnalyzeBestIntra16Mode(VP8EncIterator* const it) {
+ const int max_mode = (it->enc_->method_ >= 3) ? MAX_INTRA16_MODE : 4;
+ int mode;
+ int best_alpha = -1;
+ int best_mode = 0;
+
+ VP8MakeLuma16Preds(it);
+ for (mode = 0; mode < max_mode; ++mode) {
+ const int alpha = VP8CollectHistogram(it->yuv_in_ + Y_OFF,
+ it->yuv_p_ + VP8I16ModeOffsets[mode],
+ 0, 16);
+ if (alpha > best_alpha) {
+ best_alpha = alpha;
+ best_mode = mode;
+ }
+ }
+ VP8SetIntra16Mode(it, best_mode);
+ return best_alpha;
+}
+
+static int MBAnalyzeBestIntra4Mode(VP8EncIterator* const it,
+ int best_alpha) {
+ uint8_t modes[16];
+ const int max_mode = (it->enc_->method_ >= 3) ? MAX_INTRA4_MODE : NUM_BMODES;
+ int i4_alpha = 0;
+ VP8IteratorStartI4(it);
+ do {
+ int mode;
+ int best_mode_alpha = -1;
+ const uint8_t* const src = it->yuv_in_ + Y_OFF + VP8Scan[it->i4_];
+
+ VP8MakeIntra4Preds(it);
+ for (mode = 0; mode < max_mode; ++mode) {
+ const int alpha = VP8CollectHistogram(src,
+ it->yuv_p_ + VP8I4ModeOffsets[mode],
+ 0, 1);
+ if (alpha > best_mode_alpha) {
+ best_mode_alpha = alpha;
+ modes[it->i4_] = mode;
+ }
+ }
+ i4_alpha += best_mode_alpha;
+ // Note: we reuse the original samples for predictors
+ } while (VP8IteratorRotateI4(it, it->yuv_in_ + Y_OFF));
+
+ if (i4_alpha > best_alpha) {
+ VP8SetIntra4Mode(it, modes);
+ best_alpha = ClipAlpha(i4_alpha);
+ }
+ return best_alpha;
+}
+
+static int MBAnalyzeBestUVMode(VP8EncIterator* const it) {
+ int best_alpha = -1;
+ int best_mode = 0;
+ const int max_mode = (it->enc_->method_ >= 3) ? MAX_UV_MODE : 4;
+ int mode;
+ VP8MakeChroma8Preds(it);
+ for (mode = 0; mode < max_mode; ++mode) {
+ const int alpha = VP8CollectHistogram(it->yuv_in_ + U_OFF,
+ it->yuv_p_ + VP8UVModeOffsets[mode],
+ 16, 16 + 4 + 4);
+ if (alpha > best_alpha) {
+ best_alpha = alpha;
+ best_mode = mode;
+ }
+ }
+ VP8SetIntraUVMode(it, best_mode);
+ return best_alpha;
+}
+
+static void MBAnalyze(VP8EncIterator* const it,
+ int alphas[256], int* const uv_alpha) {
+ const VP8Encoder* const enc = it->enc_;
+ int best_alpha, best_uv_alpha;
+
+ VP8SetIntra16Mode(it, 0); // default: Intra16, DC_PRED
+ VP8SetSkip(it, 0); // not skipped
+ VP8SetSegment(it, 0); // default segment, spec-wise.
+
+ best_alpha = MBAnalyzeBestIntra16Mode(it);
+ if (enc->method_ != 3) {
+ // We go and make a fast decision for intra4/intra16.
+ // It's usually not a good and definitive pick, but helps seeding the stats
+ // about level bit-cost.
+ // TODO(skal): improve criterion.
+ best_alpha = MBAnalyzeBestIntra4Mode(it, best_alpha);
+ }
+ best_uv_alpha = MBAnalyzeBestUVMode(it);
+
+ // Final susceptibility mix
+ best_alpha = (best_alpha + best_uv_alpha + 1) / 2;
+ alphas[best_alpha]++;
+ *uv_alpha += best_uv_alpha;
+ it->mb_->alpha_ = best_alpha; // Informative only.
+}
+
+//------------------------------------------------------------------------------
+// Main analysis loop:
+// Collect all susceptibilities for each macroblock and record their
+// distribution in alphas[]. Segments is assigned a-posteriori, based on
+// this histogram.
+// We also pick an intra16 prediction mode, which shouldn't be considered
+// final except for fast-encode settings. We can also pick some intra4 modes
+// and decide intra4/intra16, but that's usually almost always a bad choice at
+// this stage.
+
+int VP8EncAnalyze(VP8Encoder* const enc) {
+ int ok = 1;
+ int alphas[256] = { 0 };
+ VP8EncIterator it;
+
+ VP8IteratorInit(enc, &it);
+ enc->uv_alpha_ = 0;
+ do {
+ VP8IteratorImport(&it);
+ MBAnalyze(&it, alphas, &enc->uv_alpha_);
+ ok = VP8IteratorProgress(&it, 20);
+ // Let's pretend we have perfect lossless reconstruction.
+ } while (ok && VP8IteratorNext(&it, it.yuv_in_));
+ enc->uv_alpha_ /= enc->mb_w_ * enc->mb_h_;
+ if (ok) AssignSegments(enc, alphas);
+
+ return ok;
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/enc/backward_references.c b/drivers/webpold/enc/backward_references.c
new file mode 100644
index 0000000000..b8c8ece806
--- /dev/null
+++ b/drivers/webpold/enc/backward_references.c
@@ -0,0 +1,874 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Author: Jyrki Alakuijala (jyrki@google.com)
+//
+
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+
+#include "./backward_references.h"
+#include "./histogram.h"
+#include "../dsp/lossless.h"
+#include "../utils/color_cache.h"
+#include "../utils/utils.h"
+
+#define VALUES_IN_BYTE 256
+
+#define HASH_BITS 18
+#define HASH_SIZE (1 << HASH_BITS)
+#define HASH_MULTIPLIER (0xc6a4a7935bd1e995ULL)
+
+// 1M window (4M bytes) minus 120 special codes for short distances.
+#define WINDOW_SIZE ((1 << 20) - 120)
+
+// Bounds for the match length.
+#define MIN_LENGTH 2
+#define MAX_LENGTH 4096
+
+typedef struct {
+ // Stores the most recently added position with the given hash value.
+ int32_t hash_to_first_index_[HASH_SIZE];
+ // chain_[pos] stores the previous position with the same hash value
+ // for every pixel in the image.
+ int32_t* chain_;
+} HashChain;
+
+// -----------------------------------------------------------------------------
+
+static const uint8_t plane_to_code_lut[128] = {
+ 96, 73, 55, 39, 23, 13, 5, 1, 255, 255, 255, 255, 255, 255, 255, 255,
+ 101, 78, 58, 42, 26, 16, 8, 2, 0, 3, 9, 17, 27, 43, 59, 79,
+ 102, 86, 62, 46, 32, 20, 10, 6, 4, 7, 11, 21, 33, 47, 63, 87,
+ 105, 90, 70, 52, 37, 28, 18, 14, 12, 15, 19, 29, 38, 53, 71, 91,
+ 110, 99, 82, 66, 48, 35, 30, 24, 22, 25, 31, 36, 49, 67, 83, 100,
+ 115, 108, 94, 76, 64, 50, 44, 40, 34, 41, 45, 51, 65, 77, 95, 109,
+ 118, 113, 103, 92, 80, 68, 60, 56, 54, 57, 61, 69, 81, 93, 104, 114,
+ 119, 116, 111, 106, 97, 88, 84, 74, 72, 75, 85, 89, 98, 107, 112, 117
+};
+
+static int DistanceToPlaneCode(int xsize, int dist) {
+ const int yoffset = dist / xsize;
+ const int xoffset = dist - yoffset * xsize;
+ if (xoffset <= 8 && yoffset < 8) {
+ return plane_to_code_lut[yoffset * 16 + 8 - xoffset] + 1;
+ } else if (xoffset > xsize - 8 && yoffset < 7) {
+ return plane_to_code_lut[(yoffset + 1) * 16 + 8 + (xsize - xoffset)] + 1;
+ }
+ return dist + 120;
+}
+
+static WEBP_INLINE int FindMatchLength(const uint32_t* const array1,
+ const uint32_t* const array2,
+ const int max_limit) {
+ int match_len = 0;
+ while (match_len < max_limit && array1[match_len] == array2[match_len]) {
+ ++match_len;
+ }
+ return match_len;
+}
+
+// -----------------------------------------------------------------------------
+// VP8LBackwardRefs
+
+void VP8LInitBackwardRefs(VP8LBackwardRefs* const refs) {
+ if (refs != NULL) {
+ refs->refs = NULL;
+ refs->size = 0;
+ refs->max_size = 0;
+ }
+}
+
+void VP8LClearBackwardRefs(VP8LBackwardRefs* const refs) {
+ if (refs != NULL) {
+ free(refs->refs);
+ VP8LInitBackwardRefs(refs);
+ }
+}
+
+int VP8LBackwardRefsAlloc(VP8LBackwardRefs* const refs, int max_size) {
+ assert(refs != NULL);
+ refs->size = 0;
+ refs->max_size = 0;
+ refs->refs = (PixOrCopy*)WebPSafeMalloc((uint64_t)max_size,
+ sizeof(*refs->refs));
+ if (refs->refs == NULL) return 0;
+ refs->max_size = max_size;
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+// Hash chains
+
+static WEBP_INLINE uint64_t GetPixPairHash64(const uint32_t* const argb) {
+ uint64_t key = ((uint64_t)(argb[1]) << 32) | argb[0];
+ key = (key * HASH_MULTIPLIER) >> (64 - HASH_BITS);
+ return key;
+}
+
+static int HashChainInit(HashChain* const p, int size) {
+ int i;
+ p->chain_ = (int*)WebPSafeMalloc((uint64_t)size, sizeof(*p->chain_));
+ if (p->chain_ == NULL) {
+ return 0;
+ }
+ for (i = 0; i < size; ++i) {
+ p->chain_[i] = -1;
+ }
+ for (i = 0; i < HASH_SIZE; ++i) {
+ p->hash_to_first_index_[i] = -1;
+ }
+ return 1;
+}
+
+static void HashChainDelete(HashChain* const p) {
+ if (p != NULL) {
+ free(p->chain_);
+ free(p);
+ }
+}
+
+// Insertion of two pixels at a time.
+static void HashChainInsert(HashChain* const p,
+ const uint32_t* const argb, int pos) {
+ const uint64_t hash_code = GetPixPairHash64(argb);
+ p->chain_[pos] = p->hash_to_first_index_[hash_code];
+ p->hash_to_first_index_[hash_code] = pos;
+}
+
+static int HashChainFindCopy(const HashChain* const p,
+ int quality, int index, int xsize,
+ const uint32_t* const argb, int maxlen,
+ int* const distance_ptr,
+ int* const length_ptr) {
+ const uint64_t hash_code = GetPixPairHash64(&argb[index]);
+ int prev_length = 0;
+ int64_t best_val = 0;
+ int best_length = 0;
+ int best_distance = 0;
+ const uint32_t* const argb_start = argb + index;
+ const int iter_min_mult = (quality < 50) ? 2 : (quality < 75) ? 4 : 8;
+ const int iter_min = -quality * iter_min_mult;
+ int iter_cnt = 10 + (quality >> 1);
+ const int min_pos = (index > WINDOW_SIZE) ? index - WINDOW_SIZE : 0;
+ int pos;
+
+ assert(xsize > 0);
+ for (pos = p->hash_to_first_index_[hash_code];
+ pos >= min_pos;
+ pos = p->chain_[pos]) {
+ int64_t val;
+ int curr_length;
+ if (iter_cnt < 0) {
+ if (iter_cnt < iter_min || best_val >= 0xff0000) {
+ break;
+ }
+ }
+ --iter_cnt;
+ if (best_length != 0 &&
+ argb[pos + best_length - 1] != argb_start[best_length - 1]) {
+ continue;
+ }
+ curr_length = FindMatchLength(argb + pos, argb_start, maxlen);
+ if (curr_length < prev_length) {
+ continue;
+ }
+ val = 65536 * curr_length;
+ // Favoring 2d locality here gives savings for certain images.
+ if (index - pos < 9 * xsize) {
+ const int y = (index - pos) / xsize;
+ int x = (index - pos) % xsize;
+ if (x > xsize / 2) {
+ x = xsize - x;
+ }
+ if (x <= 7 && x >= -8) {
+ val -= y * y + x * x;
+ } else {
+ val -= 9 * 9 + 9 * 9;
+ }
+ } else {
+ val -= 9 * 9 + 9 * 9;
+ }
+ if (best_val < val) {
+ prev_length = curr_length;
+ best_val = val;
+ best_length = curr_length;
+ best_distance = index - pos;
+ if (curr_length >= MAX_LENGTH) {
+ break;
+ }
+ if ((best_distance == 1 || best_distance == xsize) &&
+ best_length >= 128) {
+ break;
+ }
+ }
+ }
+ *distance_ptr = best_distance;
+ *length_ptr = best_length;
+ return (best_length >= MIN_LENGTH);
+}
+
+static WEBP_INLINE void PushBackCopy(VP8LBackwardRefs* const refs, int length) {
+ int size = refs->size;
+ while (length >= MAX_LENGTH) {
+ refs->refs[size++] = PixOrCopyCreateCopy(1, MAX_LENGTH);
+ length -= MAX_LENGTH;
+ }
+ if (length > 0) {
+ refs->refs[size++] = PixOrCopyCreateCopy(1, length);
+ }
+ refs->size = size;
+}
+
+static void BackwardReferencesRle(int xsize, int ysize,
+ const uint32_t* const argb,
+ VP8LBackwardRefs* const refs) {
+ const int pix_count = xsize * ysize;
+ int match_len = 0;
+ int i;
+ refs->size = 0;
+ PushBackCopy(refs, match_len); // i=0 case
+ refs->refs[refs->size++] = PixOrCopyCreateLiteral(argb[0]);
+ for (i = 1; i < pix_count; ++i) {
+ if (argb[i] == argb[i - 1]) {
+ ++match_len;
+ } else {
+ PushBackCopy(refs, match_len);
+ match_len = 0;
+ refs->refs[refs->size++] = PixOrCopyCreateLiteral(argb[i]);
+ }
+ }
+ PushBackCopy(refs, match_len);
+}
+
+static int BackwardReferencesHashChain(int xsize, int ysize,
+ const uint32_t* const argb,
+ int cache_bits, int quality,
+ VP8LBackwardRefs* const refs) {
+ int i;
+ int ok = 0;
+ int cc_init = 0;
+ const int use_color_cache = (cache_bits > 0);
+ const int pix_count = xsize * ysize;
+ HashChain* const hash_chain = (HashChain*)malloc(sizeof(*hash_chain));
+ VP8LColorCache hashers;
+
+ if (hash_chain == NULL) return 0;
+ if (use_color_cache) {
+ cc_init = VP8LColorCacheInit(&hashers, cache_bits);
+ if (!cc_init) goto Error;
+ }
+
+ if (!HashChainInit(hash_chain, pix_count)) goto Error;
+
+ refs->size = 0;
+ for (i = 0; i < pix_count; ) {
+ // Alternative#1: Code the pixels starting at 'i' using backward reference.
+ int offset = 0;
+ int len = 0;
+ if (i < pix_count - 1) { // FindCopy(i,..) reads pixels at [i] and [i + 1].
+ int maxlen = pix_count - i;
+ if (maxlen > MAX_LENGTH) {
+ maxlen = MAX_LENGTH;
+ }
+ HashChainFindCopy(hash_chain, quality, i, xsize, argb, maxlen,
+ &offset, &len);
+ }
+ if (len >= MIN_LENGTH) {
+ // Alternative#2: Insert the pixel at 'i' as literal, and code the
+ // pixels starting at 'i + 1' using backward reference.
+ int offset2 = 0;
+ int len2 = 0;
+ int k;
+ HashChainInsert(hash_chain, &argb[i], i);
+ if (i < pix_count - 2) { // FindCopy(i+1,..) reads [i + 1] and [i + 2].
+ int maxlen = pix_count - (i + 1);
+ if (maxlen > MAX_LENGTH) {
+ maxlen = MAX_LENGTH;
+ }
+ HashChainFindCopy(hash_chain, quality,
+ i + 1, xsize, argb, maxlen, &offset2, &len2);
+ if (len2 > len + 1) {
+ const uint32_t pixel = argb[i];
+ // Alternative#2 is a better match. So push pixel at 'i' as literal.
+ if (use_color_cache && VP8LColorCacheContains(&hashers, pixel)) {
+ const int ix = VP8LColorCacheGetIndex(&hashers, pixel);
+ refs->refs[refs->size] = PixOrCopyCreateCacheIdx(ix);
+ } else {
+ refs->refs[refs->size] = PixOrCopyCreateLiteral(pixel);
+ }
+ ++refs->size;
+ if (use_color_cache) VP8LColorCacheInsert(&hashers, pixel);
+ i++; // Backward reference to be done for next pixel.
+ len = len2;
+ offset = offset2;
+ }
+ }
+ if (len >= MAX_LENGTH) {
+ len = MAX_LENGTH - 1;
+ }
+ refs->refs[refs->size++] = PixOrCopyCreateCopy(offset, len);
+ if (use_color_cache) {
+ for (k = 0; k < len; ++k) {
+ VP8LColorCacheInsert(&hashers, argb[i + k]);
+ }
+ }
+ // Add to the hash_chain (but cannot add the last pixel).
+ {
+ const int last = (len < pix_count - 1 - i) ? len : pix_count - 1 - i;
+ for (k = 1; k < last; ++k) {
+ HashChainInsert(hash_chain, &argb[i + k], i + k);
+ }
+ }
+ i += len;
+ } else {
+ const uint32_t pixel = argb[i];
+ if (use_color_cache && VP8LColorCacheContains(&hashers, pixel)) {
+ // push pixel as a PixOrCopyCreateCacheIdx pixel
+ const int ix = VP8LColorCacheGetIndex(&hashers, pixel);
+ refs->refs[refs->size] = PixOrCopyCreateCacheIdx(ix);
+ } else {
+ refs->refs[refs->size] = PixOrCopyCreateLiteral(pixel);
+ }
+ ++refs->size;
+ if (use_color_cache) VP8LColorCacheInsert(&hashers, pixel);
+ if (i + 1 < pix_count) {
+ HashChainInsert(hash_chain, &argb[i], i);
+ }
+ ++i;
+ }
+ }
+ ok = 1;
+Error:
+ if (cc_init) VP8LColorCacheClear(&hashers);
+ HashChainDelete(hash_chain);
+ return ok;
+}
+
+// -----------------------------------------------------------------------------
+
+typedef struct {
+ double alpha_[VALUES_IN_BYTE];
+ double red_[VALUES_IN_BYTE];
+ double literal_[PIX_OR_COPY_CODES_MAX];
+ double blue_[VALUES_IN_BYTE];
+ double distance_[NUM_DISTANCE_CODES];
+} CostModel;
+
+static int BackwardReferencesTraceBackwards(
+ int xsize, int ysize, int recursive_cost_model,
+ const uint32_t* const argb, int cache_bits, VP8LBackwardRefs* const refs);
+
+static void ConvertPopulationCountTableToBitEstimates(
+ int num_symbols, const int population_counts[], double output[]) {
+ int sum = 0;
+ int nonzeros = 0;
+ int i;
+ for (i = 0; i < num_symbols; ++i) {
+ sum += population_counts[i];
+ if (population_counts[i] > 0) {
+ ++nonzeros;
+ }
+ }
+ if (nonzeros <= 1) {
+ memset(output, 0, num_symbols * sizeof(*output));
+ } else {
+ const double logsum = VP8LFastLog2(sum);
+ for (i = 0; i < num_symbols; ++i) {
+ output[i] = logsum - VP8LFastLog2(population_counts[i]);
+ }
+ }
+}
+
+static int CostModelBuild(CostModel* const m, int xsize, int ysize,
+ int recursion_level, const uint32_t* const argb,
+ int cache_bits) {
+ int ok = 0;
+ VP8LHistogram histo;
+ VP8LBackwardRefs refs;
+ const int quality = 100;
+
+ if (!VP8LBackwardRefsAlloc(&refs, xsize * ysize)) goto Error;
+
+ if (recursion_level > 0) {
+ if (!BackwardReferencesTraceBackwards(xsize, ysize, recursion_level - 1,
+ argb, cache_bits, &refs)) {
+ goto Error;
+ }
+ } else {
+ if (!BackwardReferencesHashChain(xsize, ysize, argb, cache_bits, quality,
+ &refs)) {
+ goto Error;
+ }
+ }
+ VP8LHistogramCreate(&histo, &refs, cache_bits);
+ ConvertPopulationCountTableToBitEstimates(
+ VP8LHistogramNumCodes(&histo), histo.literal_, m->literal_);
+ ConvertPopulationCountTableToBitEstimates(
+ VALUES_IN_BYTE, histo.red_, m->red_);
+ ConvertPopulationCountTableToBitEstimates(
+ VALUES_IN_BYTE, histo.blue_, m->blue_);
+ ConvertPopulationCountTableToBitEstimates(
+ VALUES_IN_BYTE, histo.alpha_, m->alpha_);
+ ConvertPopulationCountTableToBitEstimates(
+ NUM_DISTANCE_CODES, histo.distance_, m->distance_);
+ ok = 1;
+
+ Error:
+ VP8LClearBackwardRefs(&refs);
+ return ok;
+}
+
+static WEBP_INLINE double GetLiteralCost(const CostModel* const m, uint32_t v) {
+ return m->alpha_[v >> 24] +
+ m->red_[(v >> 16) & 0xff] +
+ m->literal_[(v >> 8) & 0xff] +
+ m->blue_[v & 0xff];
+}
+
+static WEBP_INLINE double GetCacheCost(const CostModel* const m, uint32_t idx) {
+ const int literal_idx = VALUES_IN_BYTE + NUM_LENGTH_CODES + idx;
+ return m->literal_[literal_idx];
+}
+
+static WEBP_INLINE double GetLengthCost(const CostModel* const m,
+ uint32_t length) {
+ int code, extra_bits_count, extra_bits_value;
+ PrefixEncode(length, &code, &extra_bits_count, &extra_bits_value);
+ return m->literal_[VALUES_IN_BYTE + code] + extra_bits_count;
+}
+
+static WEBP_INLINE double GetDistanceCost(const CostModel* const m,
+ uint32_t distance) {
+ int code, extra_bits_count, extra_bits_value;
+ PrefixEncode(distance, &code, &extra_bits_count, &extra_bits_value);
+ return m->distance_[code] + extra_bits_count;
+}
+
+static int BackwardReferencesHashChainDistanceOnly(
+ int xsize, int ysize, int recursive_cost_model, const uint32_t* const argb,
+ int cache_bits, uint32_t* const dist_array) {
+ int i;
+ int ok = 0;
+ int cc_init = 0;
+ const int quality = 100;
+ const int pix_count = xsize * ysize;
+ const int use_color_cache = (cache_bits > 0);
+ double* const cost =
+ (double*)WebPSafeMalloc((uint64_t)pix_count, sizeof(*cost));
+ CostModel* cost_model = (CostModel*)malloc(sizeof(*cost_model));
+ HashChain* hash_chain = (HashChain*)malloc(sizeof(*hash_chain));
+ VP8LColorCache hashers;
+ const double mul0 = (recursive_cost_model != 0) ? 1.0 : 0.68;
+ const double mul1 = (recursive_cost_model != 0) ? 1.0 : 0.82;
+
+ if (cost == NULL || cost_model == NULL || hash_chain == NULL) goto Error;
+
+ if (!HashChainInit(hash_chain, pix_count)) goto Error;
+
+ if (use_color_cache) {
+ cc_init = VP8LColorCacheInit(&hashers, cache_bits);
+ if (!cc_init) goto Error;
+ }
+
+ if (!CostModelBuild(cost_model, xsize, ysize, recursive_cost_model, argb,
+ cache_bits)) {
+ goto Error;
+ }
+
+ for (i = 0; i < pix_count; ++i) cost[i] = 1e100;
+
+ // We loop one pixel at a time, but store all currently best points to
+ // non-processed locations from this point.
+ dist_array[0] = 0;
+ for (i = 0; i < pix_count; ++i) {
+ double prev_cost = 0.0;
+ int shortmax;
+ if (i > 0) {
+ prev_cost = cost[i - 1];
+ }
+ for (shortmax = 0; shortmax < 2; ++shortmax) {
+ int offset = 0;
+ int len = 0;
+ if (i < pix_count - 1) { // FindCopy reads pixels at [i] and [i + 1].
+ int maxlen = shortmax ? 2 : MAX_LENGTH;
+ if (maxlen > pix_count - i) {
+ maxlen = pix_count - i;
+ }
+ HashChainFindCopy(hash_chain, quality, i, xsize, argb, maxlen,
+ &offset, &len);
+ }
+ if (len >= MIN_LENGTH) {
+ const int code = DistanceToPlaneCode(xsize, offset);
+ const double distance_cost =
+ prev_cost + GetDistanceCost(cost_model, code);
+ int k;
+ for (k = 1; k < len; ++k) {
+ const double cost_val =
+ distance_cost + GetLengthCost(cost_model, k);
+ if (cost[i + k] > cost_val) {
+ cost[i + k] = cost_val;
+ dist_array[i + k] = k + 1;
+ }
+ }
+ // This if is for speedup only. It roughly doubles the speed, and
+ // makes compression worse by .1 %.
+ if (len >= 128 && code < 2) {
+ // Long copy for short distances, let's skip the middle
+ // lookups for better copies.
+ // 1) insert the hashes.
+ if (use_color_cache) {
+ for (k = 0; k < len; ++k) {
+ VP8LColorCacheInsert(&hashers, argb[i + k]);
+ }
+ }
+ // 2) Add to the hash_chain (but cannot add the last pixel)
+ {
+ const int last = (len < pix_count - 1 - i) ? len
+ : pix_count - 1 - i;
+ for (k = 0; k < last; ++k) {
+ HashChainInsert(hash_chain, &argb[i + k], i + k);
+ }
+ }
+ // 3) jump.
+ i += len - 1; // for loop does ++i, thus -1 here.
+ goto next_symbol;
+ }
+ }
+ }
+ if (i < pix_count - 1) {
+ HashChainInsert(hash_chain, &argb[i], i);
+ }
+ {
+ // inserting a literal pixel
+ double cost_val = prev_cost;
+ if (use_color_cache && VP8LColorCacheContains(&hashers, argb[i])) {
+ const int ix = VP8LColorCacheGetIndex(&hashers, argb[i]);
+ cost_val += GetCacheCost(cost_model, ix) * mul0;
+ } else {
+ cost_val += GetLiteralCost(cost_model, argb[i]) * mul1;
+ }
+ if (cost[i] > cost_val) {
+ cost[i] = cost_val;
+ dist_array[i] = 1; // only one is inserted.
+ }
+ if (use_color_cache) VP8LColorCacheInsert(&hashers, argb[i]);
+ }
+ next_symbol: ;
+ }
+ // Last pixel still to do, it can only be a single step if not reached
+ // through cheaper means already.
+ ok = 1;
+Error:
+ if (cc_init) VP8LColorCacheClear(&hashers);
+ HashChainDelete(hash_chain);
+ free(cost_model);
+ free(cost);
+ return ok;
+}
+
+static int TraceBackwards(const uint32_t* const dist_array,
+ int dist_array_size,
+ uint32_t** const chosen_path,
+ int* const chosen_path_size) {
+ int i;
+ // Count how many.
+ int count = 0;
+ for (i = dist_array_size - 1; i >= 0; ) {
+ int k = dist_array[i];
+ assert(k >= 1);
+ ++count;
+ i -= k;
+ }
+ // Allocate.
+ *chosen_path_size = count;
+ *chosen_path =
+ (uint32_t*)WebPSafeMalloc((uint64_t)count, sizeof(**chosen_path));
+ if (*chosen_path == NULL) return 0;
+
+ // Write in reverse order.
+ for (i = dist_array_size - 1; i >= 0; ) {
+ int k = dist_array[i];
+ assert(k >= 1);
+ (*chosen_path)[--count] = k;
+ i -= k;
+ }
+ return 1;
+}
+
+static int BackwardReferencesHashChainFollowChosenPath(
+ int xsize, int ysize, const uint32_t* const argb, int cache_bits,
+ const uint32_t* const chosen_path, int chosen_path_size,
+ VP8LBackwardRefs* const refs) {
+ const int quality = 100;
+ const int pix_count = xsize * ysize;
+ const int use_color_cache = (cache_bits > 0);
+ int size = 0;
+ int i = 0;
+ int k;
+ int ix;
+ int ok = 0;
+ int cc_init = 0;
+ HashChain* hash_chain = (HashChain*)malloc(sizeof(*hash_chain));
+ VP8LColorCache hashers;
+
+ if (hash_chain == NULL || !HashChainInit(hash_chain, pix_count)) {
+ goto Error;
+ }
+ if (use_color_cache) {
+ cc_init = VP8LColorCacheInit(&hashers, cache_bits);
+ if (!cc_init) goto Error;
+ }
+
+ refs->size = 0;
+ for (ix = 0; ix < chosen_path_size; ++ix, ++size) {
+ int offset = 0;
+ int len = 0;
+ int maxlen = chosen_path[ix];
+ if (maxlen != 1) {
+ HashChainFindCopy(hash_chain, quality,
+ i, xsize, argb, maxlen, &offset, &len);
+ assert(len == maxlen);
+ refs->refs[size] = PixOrCopyCreateCopy(offset, len);
+ if (use_color_cache) {
+ for (k = 0; k < len; ++k) {
+ VP8LColorCacheInsert(&hashers, argb[i + k]);
+ }
+ }
+ {
+ const int last = (len < pix_count - 1 - i) ? len : pix_count - 1 - i;
+ for (k = 0; k < last; ++k) {
+ HashChainInsert(hash_chain, &argb[i + k], i + k);
+ }
+ }
+ i += len;
+ } else {
+ if (use_color_cache && VP8LColorCacheContains(&hashers, argb[i])) {
+ // push pixel as a color cache index
+ const int idx = VP8LColorCacheGetIndex(&hashers, argb[i]);
+ refs->refs[size] = PixOrCopyCreateCacheIdx(idx);
+ } else {
+ refs->refs[size] = PixOrCopyCreateLiteral(argb[i]);
+ }
+ if (use_color_cache) VP8LColorCacheInsert(&hashers, argb[i]);
+ if (i + 1 < pix_count) {
+ HashChainInsert(hash_chain, &argb[i], i);
+ }
+ ++i;
+ }
+ }
+ assert(size <= refs->max_size);
+ refs->size = size;
+ ok = 1;
+Error:
+ if (cc_init) VP8LColorCacheClear(&hashers);
+ HashChainDelete(hash_chain);
+ return ok;
+}
+
+// Returns 1 on success.
+static int BackwardReferencesTraceBackwards(int xsize, int ysize,
+ int recursive_cost_model,
+ const uint32_t* const argb,
+ int cache_bits,
+ VP8LBackwardRefs* const refs) {
+ int ok = 0;
+ const int dist_array_size = xsize * ysize;
+ uint32_t* chosen_path = NULL;
+ int chosen_path_size = 0;
+ uint32_t* dist_array =
+ (uint32_t*)WebPSafeMalloc((uint64_t)dist_array_size, sizeof(*dist_array));
+
+ if (dist_array == NULL) goto Error;
+
+ if (!BackwardReferencesHashChainDistanceOnly(
+ xsize, ysize, recursive_cost_model, argb, cache_bits, dist_array)) {
+ goto Error;
+ }
+ if (!TraceBackwards(dist_array, dist_array_size,
+ &chosen_path, &chosen_path_size)) {
+ goto Error;
+ }
+ free(dist_array); // no need to retain this memory any longer
+ dist_array = NULL;
+ if (!BackwardReferencesHashChainFollowChosenPath(
+ xsize, ysize, argb, cache_bits, chosen_path, chosen_path_size, refs)) {
+ goto Error;
+ }
+ ok = 1;
+ Error:
+ free(chosen_path);
+ free(dist_array);
+ return ok;
+}
+
+static void BackwardReferences2DLocality(int xsize,
+ VP8LBackwardRefs* const refs) {
+ int i;
+ for (i = 0; i < refs->size; ++i) {
+ if (PixOrCopyIsCopy(&refs->refs[i])) {
+ const int dist = refs->refs[i].argb_or_distance;
+ const int transformed_dist = DistanceToPlaneCode(xsize, dist);
+ refs->refs[i].argb_or_distance = transformed_dist;
+ }
+ }
+}
+
+int VP8LGetBackwardReferences(int width, int height,
+ const uint32_t* const argb,
+ int quality, int cache_bits, int use_2d_locality,
+ VP8LBackwardRefs* const best) {
+ int ok = 0;
+ int lz77_is_useful;
+ VP8LBackwardRefs refs_rle, refs_lz77;
+ const int num_pix = width * height;
+
+ VP8LBackwardRefsAlloc(&refs_rle, num_pix);
+ VP8LBackwardRefsAlloc(&refs_lz77, num_pix);
+ VP8LInitBackwardRefs(best);
+ if (refs_rle.refs == NULL || refs_lz77.refs == NULL) {
+ Error1:
+ VP8LClearBackwardRefs(&refs_rle);
+ VP8LClearBackwardRefs(&refs_lz77);
+ goto End;
+ }
+
+ if (!BackwardReferencesHashChain(width, height, argb, cache_bits, quality,
+ &refs_lz77)) {
+ goto End;
+ }
+ // Backward Reference using RLE only.
+ BackwardReferencesRle(width, height, argb, &refs_rle);
+
+ {
+ double bit_cost_lz77, bit_cost_rle;
+ VP8LHistogram* const histo = (VP8LHistogram*)malloc(sizeof(*histo));
+ if (histo == NULL) goto Error1;
+ // Evaluate lz77 coding
+ VP8LHistogramCreate(histo, &refs_lz77, cache_bits);
+ bit_cost_lz77 = VP8LHistogramEstimateBits(histo);
+ // Evaluate RLE coding
+ VP8LHistogramCreate(histo, &refs_rle, cache_bits);
+ bit_cost_rle = VP8LHistogramEstimateBits(histo);
+ // Decide if LZ77 is useful.
+ lz77_is_useful = (bit_cost_lz77 < bit_cost_rle);
+ free(histo);
+ }
+
+ // Choose appropriate backward reference.
+ if (lz77_is_useful) {
+ // TraceBackwards is costly. Run it for higher qualities.
+ const int try_lz77_trace_backwards = (quality >= 75);
+ *best = refs_lz77; // default guess: lz77 is better
+ VP8LClearBackwardRefs(&refs_rle);
+ if (try_lz77_trace_backwards) {
+ const int recursion_level = (num_pix < 320 * 200) ? 1 : 0;
+ VP8LBackwardRefs refs_trace;
+ if (!VP8LBackwardRefsAlloc(&refs_trace, num_pix)) {
+ goto End;
+ }
+ if (BackwardReferencesTraceBackwards(
+ width, height, recursion_level, argb, cache_bits, &refs_trace)) {
+ VP8LClearBackwardRefs(&refs_lz77);
+ *best = refs_trace;
+ }
+ }
+ } else {
+ VP8LClearBackwardRefs(&refs_lz77);
+ *best = refs_rle;
+ }
+
+ if (use_2d_locality) BackwardReferences2DLocality(width, best);
+
+ ok = 1;
+
+ End:
+ if (!ok) {
+ VP8LClearBackwardRefs(best);
+ }
+ return ok;
+}
+
+// Returns 1 on success.
+static int ComputeCacheHistogram(const uint32_t* const argb,
+ int xsize, int ysize,
+ const VP8LBackwardRefs* const refs,
+ int cache_bits,
+ VP8LHistogram* const histo) {
+ int pixel_index = 0;
+ int i;
+ uint32_t k;
+ VP8LColorCache hashers;
+ const int use_color_cache = (cache_bits > 0);
+ int cc_init = 0;
+
+ if (use_color_cache) {
+ cc_init = VP8LColorCacheInit(&hashers, cache_bits);
+ if (!cc_init) return 0;
+ }
+
+ for (i = 0; i < refs->size; ++i) {
+ const PixOrCopy* const v = &refs->refs[i];
+ if (PixOrCopyIsLiteral(v)) {
+ if (use_color_cache &&
+ VP8LColorCacheContains(&hashers, argb[pixel_index])) {
+ // push pixel as a cache index
+ const int ix = VP8LColorCacheGetIndex(&hashers, argb[pixel_index]);
+ const PixOrCopy token = PixOrCopyCreateCacheIdx(ix);
+ VP8LHistogramAddSinglePixOrCopy(histo, &token);
+ } else {
+ VP8LHistogramAddSinglePixOrCopy(histo, v);
+ }
+ } else {
+ VP8LHistogramAddSinglePixOrCopy(histo, v);
+ }
+ if (use_color_cache) {
+ for (k = 0; k < PixOrCopyLength(v); ++k) {
+ VP8LColorCacheInsert(&hashers, argb[pixel_index + k]);
+ }
+ }
+ pixel_index += PixOrCopyLength(v);
+ }
+ assert(pixel_index == xsize * ysize);
+ (void)xsize; // xsize is not used in non-debug compilations otherwise.
+ (void)ysize; // ysize is not used in non-debug compilations otherwise.
+ if (cc_init) VP8LColorCacheClear(&hashers);
+ return 1;
+}
+
+// Returns how many bits are to be used for a color cache.
+int VP8LCalculateEstimateForCacheSize(const uint32_t* const argb,
+ int xsize, int ysize,
+ int* const best_cache_bits) {
+ int ok = 0;
+ int cache_bits;
+ double lowest_entropy = 1e99;
+ VP8LBackwardRefs refs;
+ static const double kSmallPenaltyForLargeCache = 4.0;
+ static const int quality = 30;
+ if (!VP8LBackwardRefsAlloc(&refs, xsize * ysize) ||
+ !BackwardReferencesHashChain(xsize, ysize, argb, 0, quality, &refs)) {
+ goto Error;
+ }
+ for (cache_bits = 0; cache_bits <= MAX_COLOR_CACHE_BITS; ++cache_bits) {
+ double cur_entropy;
+ VP8LHistogram histo;
+ VP8LHistogramInit(&histo, cache_bits);
+ ComputeCacheHistogram(argb, xsize, ysize, &refs, cache_bits, &histo);
+ cur_entropy = VP8LHistogramEstimateBits(&histo) +
+ kSmallPenaltyForLargeCache * cache_bits;
+ if (cache_bits == 0 || cur_entropy < lowest_entropy) {
+ *best_cache_bits = cache_bits;
+ lowest_entropy = cur_entropy;
+ }
+ }
+ ok = 1;
+ Error:
+ VP8LClearBackwardRefs(&refs);
+ return ok;
+}
diff --git a/drivers/webpold/enc/backward_references.h b/drivers/webpold/enc/backward_references.h
new file mode 100644
index 0000000000..8006a56ba1
--- /dev/null
+++ b/drivers/webpold/enc/backward_references.h
@@ -0,0 +1,212 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Author: Jyrki Alakuijala (jyrki@google.com)
+//
+
+#ifndef WEBP_ENC_BACKWARD_REFERENCES_H_
+#define WEBP_ENC_BACKWARD_REFERENCES_H_
+
+#include <assert.h>
+#include <stdlib.h>
+#include "../types.h"
+#include "../format_constants.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+// The spec allows 11, we use 9 bits to reduce memory consumption in encoding.
+// Having 9 instead of 11 only removes about 0.25 % of compression density.
+#define MAX_COLOR_CACHE_BITS 9
+
+// Max ever number of codes we'll use:
+#define PIX_OR_COPY_CODES_MAX \
+ (NUM_LITERAL_CODES + NUM_LENGTH_CODES + (1 << MAX_COLOR_CACHE_BITS))
+
+// -----------------------------------------------------------------------------
+// PrefixEncode()
+
+// use GNU builtins where available.
+#if defined(__GNUC__) && \
+ ((__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || __GNUC__ >= 4)
+static WEBP_INLINE int BitsLog2Floor(uint32_t n) {
+ return n == 0 ? -1 : 31 ^ __builtin_clz(n);
+}
+#elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))
+#include <intrin.h>
+#pragma intrinsic(_BitScanReverse)
+
+static WEBP_INLINE int BitsLog2Floor(uint32_t n) {
+ unsigned long first_set_bit;
+ return _BitScanReverse(&first_set_bit, n) ? first_set_bit : -1;
+}
+#else
+static WEBP_INLINE int BitsLog2Floor(uint32_t n) {
+ int log = 0;
+ uint32_t value = n;
+ int i;
+
+ if (value == 0) return -1;
+ for (i = 4; i >= 0; --i) {
+ const int shift = (1 << i);
+ const uint32_t x = value >> shift;
+ if (x != 0) {
+ value = x;
+ log += shift;
+ }
+ }
+ return log;
+}
+#endif
+
+static WEBP_INLINE int VP8LBitsLog2Ceiling(uint32_t n) {
+ const int floor = BitsLog2Floor(n);
+ if (n == (n & ~(n - 1))) // zero or a power of two.
+ return floor;
+ else
+ return floor + 1;
+}
+
+// Splitting of distance and length codes into prefixes and
+// extra bits. The prefixes are encoded with an entropy code
+// while the extra bits are stored just as normal bits.
+static WEBP_INLINE void PrefixEncode(int distance, int* const code,
+ int* const extra_bits_count,
+ int* const extra_bits_value) {
+ // Collect the two most significant bits where the highest bit is 1.
+ const int highest_bit = BitsLog2Floor(--distance);
+ // & 0x3f is to make behavior well defined when highest_bit
+ // does not exist or is the least significant bit.
+ const int second_highest_bit =
+ (distance >> ((highest_bit - 1) & 0x3f)) & 1;
+ *extra_bits_count = (highest_bit > 0) ? (highest_bit - 1) : 0;
+ *extra_bits_value = distance & ((1 << *extra_bits_count) - 1);
+ *code = (highest_bit > 0) ? (2 * highest_bit + second_highest_bit)
+ : (highest_bit == 0) ? 1 : 0;
+}
+
+// -----------------------------------------------------------------------------
+// PixOrCopy
+
+enum Mode {
+ kLiteral,
+ kCacheIdx,
+ kCopy,
+ kNone
+};
+
+typedef struct {
+ // mode as uint8_t to make the memory layout to be exactly 8 bytes.
+ uint8_t mode;
+ uint16_t len;
+ uint32_t argb_or_distance;
+} PixOrCopy;
+
+static WEBP_INLINE PixOrCopy PixOrCopyCreateCopy(uint32_t distance,
+ uint16_t len) {
+ PixOrCopy retval;
+ retval.mode = kCopy;
+ retval.argb_or_distance = distance;
+ retval.len = len;
+ return retval;
+}
+
+static WEBP_INLINE PixOrCopy PixOrCopyCreateCacheIdx(int idx) {
+ PixOrCopy retval;
+ assert(idx >= 0);
+ assert(idx < (1 << MAX_COLOR_CACHE_BITS));
+ retval.mode = kCacheIdx;
+ retval.argb_or_distance = idx;
+ retval.len = 1;
+ return retval;
+}
+
+static WEBP_INLINE PixOrCopy PixOrCopyCreateLiteral(uint32_t argb) {
+ PixOrCopy retval;
+ retval.mode = kLiteral;
+ retval.argb_or_distance = argb;
+ retval.len = 1;
+ return retval;
+}
+
+static WEBP_INLINE int PixOrCopyIsLiteral(const PixOrCopy* const p) {
+ return (p->mode == kLiteral);
+}
+
+static WEBP_INLINE int PixOrCopyIsCacheIdx(const PixOrCopy* const p) {
+ return (p->mode == kCacheIdx);
+}
+
+static WEBP_INLINE int PixOrCopyIsCopy(const PixOrCopy* const p) {
+ return (p->mode == kCopy);
+}
+
+static WEBP_INLINE uint32_t PixOrCopyLiteral(const PixOrCopy* const p,
+ int component) {
+ assert(p->mode == kLiteral);
+ return (p->argb_or_distance >> (component * 8)) & 0xff;
+}
+
+static WEBP_INLINE uint32_t PixOrCopyLength(const PixOrCopy* const p) {
+ return p->len;
+}
+
+static WEBP_INLINE uint32_t PixOrCopyArgb(const PixOrCopy* const p) {
+ assert(p->mode == kLiteral);
+ return p->argb_or_distance;
+}
+
+static WEBP_INLINE uint32_t PixOrCopyCacheIdx(const PixOrCopy* const p) {
+ assert(p->mode == kCacheIdx);
+ assert(p->argb_or_distance < (1U << MAX_COLOR_CACHE_BITS));
+ return p->argb_or_distance;
+}
+
+static WEBP_INLINE uint32_t PixOrCopyDistance(const PixOrCopy* const p) {
+ assert(p->mode == kCopy);
+ return p->argb_or_distance;
+}
+
+// -----------------------------------------------------------------------------
+// VP8LBackwardRefs
+
+typedef struct {
+ PixOrCopy* refs;
+ int size; // currently used
+ int max_size; // maximum capacity
+} VP8LBackwardRefs;
+
+// Initialize the object. Must be called first. 'refs' can be NULL.
+void VP8LInitBackwardRefs(VP8LBackwardRefs* const refs);
+
+// Release memory and re-initialize the object. 'refs' can be NULL.
+void VP8LClearBackwardRefs(VP8LBackwardRefs* const refs);
+
+// Allocate 'max_size' references. Returns false in case of memory error.
+int VP8LBackwardRefsAlloc(VP8LBackwardRefs* const refs, int max_size);
+
+// -----------------------------------------------------------------------------
+// Main entry points
+
+// Evaluates best possible backward references for specified quality.
+// Further optimize for 2D locality if use_2d_locality flag is set.
+int VP8LGetBackwardReferences(int width, int height,
+ const uint32_t* const argb,
+ int quality, int cache_bits, int use_2d_locality,
+ VP8LBackwardRefs* const best);
+
+// Produce an estimate for a good color cache size for the image.
+int VP8LCalculateEstimateForCacheSize(const uint32_t* const argb,
+ int xsize, int ysize,
+ int* const best_cache_bits);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif // WEBP_ENC_BACKWARD_REFERENCES_H_
diff --git a/drivers/webpold/enc/config.c b/drivers/webpold/enc/config.c
new file mode 100644
index 0000000000..4136f6c227
--- /dev/null
+++ b/drivers/webpold/enc/config.c
@@ -0,0 +1,132 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Coding tools configuration
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "../encode.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// WebPConfig
+//------------------------------------------------------------------------------
+
+int WebPConfigInitInternal(WebPConfig* config,
+ WebPPreset preset, float quality, int version) {
+ if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_ENCODER_ABI_VERSION)) {
+ return 0; // caller/system version mismatch!
+ }
+ if (config == NULL) return 0;
+
+ config->quality = quality;
+ config->target_size = 0;
+ config->target_PSNR = 0.;
+ config->method = 4;
+ config->sns_strength = 50;
+ config->filter_strength = 20; // default: light filtering
+ config->filter_sharpness = 0;
+ config->filter_type = 0; // default: simple
+ config->partitions = 0;
+ config->segments = 4;
+ config->pass = 1;
+ config->show_compressed = 0;
+ config->preprocessing = 0;
+ config->autofilter = 0;
+ config->partition_limit = 0;
+ config->alpha_compression = 1;
+ config->alpha_filtering = 1;
+ config->alpha_quality = 100;
+ config->lossless = 0;
+ config->image_hint = WEBP_HINT_DEFAULT;
+
+ // TODO(skal): tune.
+ switch (preset) {
+ case WEBP_PRESET_PICTURE:
+ config->sns_strength = 80;
+ config->filter_sharpness = 4;
+ config->filter_strength = 35;
+ break;
+ case WEBP_PRESET_PHOTO:
+ config->sns_strength = 80;
+ config->filter_sharpness = 3;
+ config->filter_strength = 30;
+ break;
+ case WEBP_PRESET_DRAWING:
+ config->sns_strength = 25;
+ config->filter_sharpness = 6;
+ config->filter_strength = 10;
+ break;
+ case WEBP_PRESET_ICON:
+ config->sns_strength = 0;
+ config->filter_strength = 0; // disable filtering to retain sharpness
+ break;
+ case WEBP_PRESET_TEXT:
+ config->sns_strength = 0;
+ config->filter_strength = 0; // disable filtering to retain sharpness
+ config->segments = 2;
+ break;
+ case WEBP_PRESET_DEFAULT:
+ default:
+ break;
+ }
+ return WebPValidateConfig(config);
+}
+
+int WebPValidateConfig(const WebPConfig* config) {
+ if (config == NULL) return 0;
+ if (config->quality < 0 || config->quality > 100)
+ return 0;
+ if (config->target_size < 0)
+ return 0;
+ if (config->target_PSNR < 0)
+ return 0;
+ if (config->method < 0 || config->method > 6)
+ return 0;
+ if (config->segments < 1 || config->segments > 4)
+ return 0;
+ if (config->sns_strength < 0 || config->sns_strength > 100)
+ return 0;
+ if (config->filter_strength < 0 || config->filter_strength > 100)
+ return 0;
+ if (config->filter_sharpness < 0 || config->filter_sharpness > 7)
+ return 0;
+ if (config->filter_type < 0 || config->filter_type > 1)
+ return 0;
+ if (config->autofilter < 0 || config->autofilter > 1)
+ return 0;
+ if (config->pass < 1 || config->pass > 10)
+ return 0;
+ if (config->show_compressed < 0 || config->show_compressed > 1)
+ return 0;
+ if (config->preprocessing < 0 || config->preprocessing > 1)
+ return 0;
+ if (config->partitions < 0 || config->partitions > 3)
+ return 0;
+ if (config->partition_limit < 0 || config->partition_limit > 100)
+ return 0;
+ if (config->alpha_compression < 0)
+ return 0;
+ if (config->alpha_filtering < 0)
+ return 0;
+ if (config->alpha_quality < 0 || config->alpha_quality > 100)
+ return 0;
+ if (config->lossless < 0 || config->lossless > 1)
+ return 0;
+ if (config->image_hint >= WEBP_HINT_LAST)
+ return 0;
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/enc/cost.c b/drivers/webpold/enc/cost.c
new file mode 100644
index 0000000000..92e0cc713c
--- /dev/null
+++ b/drivers/webpold/enc/cost.c
@@ -0,0 +1,494 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Cost tables for level and modes
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./cost.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// Boolean-cost cost table
+
+const uint16_t VP8EntropyCost[256] = {
+ 1792, 1792, 1792, 1536, 1536, 1408, 1366, 1280, 1280, 1216,
+ 1178, 1152, 1110, 1076, 1061, 1024, 1024, 992, 968, 951,
+ 939, 911, 896, 878, 871, 854, 838, 820, 811, 794,
+ 786, 768, 768, 752, 740, 732, 720, 709, 704, 690,
+ 683, 672, 666, 655, 647, 640, 631, 622, 615, 607,
+ 598, 592, 586, 576, 572, 564, 559, 555, 547, 541,
+ 534, 528, 522, 512, 512, 504, 500, 494, 488, 483,
+ 477, 473, 467, 461, 458, 452, 448, 443, 438, 434,
+ 427, 424, 419, 415, 410, 406, 403, 399, 394, 390,
+ 384, 384, 377, 374, 370, 366, 362, 359, 355, 351,
+ 347, 342, 342, 336, 333, 330, 326, 323, 320, 316,
+ 312, 308, 305, 302, 299, 296, 293, 288, 287, 283,
+ 280, 277, 274, 272, 268, 266, 262, 256, 256, 256,
+ 251, 248, 245, 242, 240, 237, 234, 232, 228, 226,
+ 223, 221, 218, 216, 214, 211, 208, 205, 203, 201,
+ 198, 196, 192, 191, 188, 187, 183, 181, 179, 176,
+ 175, 171, 171, 168, 165, 163, 160, 159, 156, 154,
+ 152, 150, 148, 146, 144, 142, 139, 138, 135, 133,
+ 131, 128, 128, 125, 123, 121, 119, 117, 115, 113,
+ 111, 110, 107, 105, 103, 102, 100, 98, 96, 94,
+ 92, 91, 89, 86, 86, 83, 82, 80, 77, 76,
+ 74, 73, 71, 69, 67, 66, 64, 63, 61, 59,
+ 57, 55, 54, 52, 51, 49, 47, 46, 44, 43,
+ 41, 40, 38, 36, 35, 33, 32, 30, 29, 27,
+ 25, 24, 22, 21, 19, 18, 16, 15, 13, 12,
+ 10, 9, 7, 6, 4, 3
+};
+
+//------------------------------------------------------------------------------
+// Level cost tables
+
+// For each given level, the following table gives the pattern of contexts to
+// use for coding it (in [][0]) as well as the bit value to use for each
+// context (in [][1]).
+const uint16_t VP8LevelCodes[MAX_VARIABLE_LEVEL][2] = {
+ {0x001, 0x000}, {0x007, 0x001}, {0x00f, 0x005},
+ {0x00f, 0x00d}, {0x033, 0x003}, {0x033, 0x003}, {0x033, 0x023},
+ {0x033, 0x023}, {0x033, 0x023}, {0x033, 0x023}, {0x0d3, 0x013},
+ {0x0d3, 0x013}, {0x0d3, 0x013}, {0x0d3, 0x013}, {0x0d3, 0x013},
+ {0x0d3, 0x013}, {0x0d3, 0x013}, {0x0d3, 0x013}, {0x0d3, 0x093},
+ {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093},
+ {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093},
+ {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093},
+ {0x0d3, 0x093}, {0x0d3, 0x093}, {0x0d3, 0x093}, {0x153, 0x053},
+ {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053},
+ {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053},
+ {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053},
+ {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053},
+ {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053},
+ {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053},
+ {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053},
+ {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x053}, {0x153, 0x153}
+};
+
+// fixed costs for coding levels, deduce from the coding tree.
+// This is only the part that doesn't depend on the probability state.
+const uint16_t VP8LevelFixedCosts[2048] = {
+ 0, 256, 256, 256, 256, 432, 618, 630,
+ 731, 640, 640, 828, 901, 948, 1021, 1101,
+ 1174, 1221, 1294, 1042, 1085, 1115, 1158, 1202,
+ 1245, 1275, 1318, 1337, 1380, 1410, 1453, 1497,
+ 1540, 1570, 1613, 1280, 1295, 1317, 1332, 1358,
+ 1373, 1395, 1410, 1454, 1469, 1491, 1506, 1532,
+ 1547, 1569, 1584, 1601, 1616, 1638, 1653, 1679,
+ 1694, 1716, 1731, 1775, 1790, 1812, 1827, 1853,
+ 1868, 1890, 1905, 1727, 1733, 1742, 1748, 1759,
+ 1765, 1774, 1780, 1800, 1806, 1815, 1821, 1832,
+ 1838, 1847, 1853, 1878, 1884, 1893, 1899, 1910,
+ 1916, 1925, 1931, 1951, 1957, 1966, 1972, 1983,
+ 1989, 1998, 2004, 2027, 2033, 2042, 2048, 2059,
+ 2065, 2074, 2080, 2100, 2106, 2115, 2121, 2132,
+ 2138, 2147, 2153, 2178, 2184, 2193, 2199, 2210,
+ 2216, 2225, 2231, 2251, 2257, 2266, 2272, 2283,
+ 2289, 2298, 2304, 2168, 2174, 2183, 2189, 2200,
+ 2206, 2215, 2221, 2241, 2247, 2256, 2262, 2273,
+ 2279, 2288, 2294, 2319, 2325, 2334, 2340, 2351,
+ 2357, 2366, 2372, 2392, 2398, 2407, 2413, 2424,
+ 2430, 2439, 2445, 2468, 2474, 2483, 2489, 2500,
+ 2506, 2515, 2521, 2541, 2547, 2556, 2562, 2573,
+ 2579, 2588, 2594, 2619, 2625, 2634, 2640, 2651,
+ 2657, 2666, 2672, 2692, 2698, 2707, 2713, 2724,
+ 2730, 2739, 2745, 2540, 2546, 2555, 2561, 2572,
+ 2578, 2587, 2593, 2613, 2619, 2628, 2634, 2645,
+ 2651, 2660, 2666, 2691, 2697, 2706, 2712, 2723,
+ 2729, 2738, 2744, 2764, 2770, 2779, 2785, 2796,
+ 2802, 2811, 2817, 2840, 2846, 2855, 2861, 2872,
+ 2878, 2887, 2893, 2913, 2919, 2928, 2934, 2945,
+ 2951, 2960, 2966, 2991, 2997, 3006, 3012, 3023,
+ 3029, 3038, 3044, 3064, 3070, 3079, 3085, 3096,
+ 3102, 3111, 3117, 2981, 2987, 2996, 3002, 3013,
+ 3019, 3028, 3034, 3054, 3060, 3069, 3075, 3086,
+ 3092, 3101, 3107, 3132, 3138, 3147, 3153, 3164,
+ 3170, 3179, 3185, 3205, 3211, 3220, 3226, 3237,
+ 3243, 3252, 3258, 3281, 3287, 3296, 3302, 3313,
+ 3319, 3328, 3334, 3354, 3360, 3369, 3375, 3386,
+ 3392, 3401, 3407, 3432, 3438, 3447, 3453, 3464,
+ 3470, 3479, 3485, 3505, 3511, 3520, 3526, 3537,
+ 3543, 3552, 3558, 2816, 2822, 2831, 2837, 2848,
+ 2854, 2863, 2869, 2889, 2895, 2904, 2910, 2921,
+ 2927, 2936, 2942, 2967, 2973, 2982, 2988, 2999,
+ 3005, 3014, 3020, 3040, 3046, 3055, 3061, 3072,
+ 3078, 3087, 3093, 3116, 3122, 3131, 3137, 3148,
+ 3154, 3163, 3169, 3189, 3195, 3204, 3210, 3221,
+ 3227, 3236, 3242, 3267, 3273, 3282, 3288, 3299,
+ 3305, 3314, 3320, 3340, 3346, 3355, 3361, 3372,
+ 3378, 3387, 3393, 3257, 3263, 3272, 3278, 3289,
+ 3295, 3304, 3310, 3330, 3336, 3345, 3351, 3362,
+ 3368, 3377, 3383, 3408, 3414, 3423, 3429, 3440,
+ 3446, 3455, 3461, 3481, 3487, 3496, 3502, 3513,
+ 3519, 3528, 3534, 3557, 3563, 3572, 3578, 3589,
+ 3595, 3604, 3610, 3630, 3636, 3645, 3651, 3662,
+ 3668, 3677, 3683, 3708, 3714, 3723, 3729, 3740,
+ 3746, 3755, 3761, 3781, 3787, 3796, 3802, 3813,
+ 3819, 3828, 3834, 3629, 3635, 3644, 3650, 3661,
+ 3667, 3676, 3682, 3702, 3708, 3717, 3723, 3734,
+ 3740, 3749, 3755, 3780, 3786, 3795, 3801, 3812,
+ 3818, 3827, 3833, 3853, 3859, 3868, 3874, 3885,
+ 3891, 3900, 3906, 3929, 3935, 3944, 3950, 3961,
+ 3967, 3976, 3982, 4002, 4008, 4017, 4023, 4034,
+ 4040, 4049, 4055, 4080, 4086, 4095, 4101, 4112,
+ 4118, 4127, 4133, 4153, 4159, 4168, 4174, 4185,
+ 4191, 4200, 4206, 4070, 4076, 4085, 4091, 4102,
+ 4108, 4117, 4123, 4143, 4149, 4158, 4164, 4175,
+ 4181, 4190, 4196, 4221, 4227, 4236, 4242, 4253,
+ 4259, 4268, 4274, 4294, 4300, 4309, 4315, 4326,
+ 4332, 4341, 4347, 4370, 4376, 4385, 4391, 4402,
+ 4408, 4417, 4423, 4443, 4449, 4458, 4464, 4475,
+ 4481, 4490, 4496, 4521, 4527, 4536, 4542, 4553,
+ 4559, 4568, 4574, 4594, 4600, 4609, 4615, 4626,
+ 4632, 4641, 4647, 3515, 3521, 3530, 3536, 3547,
+ 3553, 3562, 3568, 3588, 3594, 3603, 3609, 3620,
+ 3626, 3635, 3641, 3666, 3672, 3681, 3687, 3698,
+ 3704, 3713, 3719, 3739, 3745, 3754, 3760, 3771,
+ 3777, 3786, 3792, 3815, 3821, 3830, 3836, 3847,
+ 3853, 3862, 3868, 3888, 3894, 3903, 3909, 3920,
+ 3926, 3935, 3941, 3966, 3972, 3981, 3987, 3998,
+ 4004, 4013, 4019, 4039, 4045, 4054, 4060, 4071,
+ 4077, 4086, 4092, 3956, 3962, 3971, 3977, 3988,
+ 3994, 4003, 4009, 4029, 4035, 4044, 4050, 4061,
+ 4067, 4076, 4082, 4107, 4113, 4122, 4128, 4139,
+ 4145, 4154, 4160, 4180, 4186, 4195, 4201, 4212,
+ 4218, 4227, 4233, 4256, 4262, 4271, 4277, 4288,
+ 4294, 4303, 4309, 4329, 4335, 4344, 4350, 4361,
+ 4367, 4376, 4382, 4407, 4413, 4422, 4428, 4439,
+ 4445, 4454, 4460, 4480, 4486, 4495, 4501, 4512,
+ 4518, 4527, 4533, 4328, 4334, 4343, 4349, 4360,
+ 4366, 4375, 4381, 4401, 4407, 4416, 4422, 4433,
+ 4439, 4448, 4454, 4479, 4485, 4494, 4500, 4511,
+ 4517, 4526, 4532, 4552, 4558, 4567, 4573, 4584,
+ 4590, 4599, 4605, 4628, 4634, 4643, 4649, 4660,
+ 4666, 4675, 4681, 4701, 4707, 4716, 4722, 4733,
+ 4739, 4748, 4754, 4779, 4785, 4794, 4800, 4811,
+ 4817, 4826, 4832, 4852, 4858, 4867, 4873, 4884,
+ 4890, 4899, 4905, 4769, 4775, 4784, 4790, 4801,
+ 4807, 4816, 4822, 4842, 4848, 4857, 4863, 4874,
+ 4880, 4889, 4895, 4920, 4926, 4935, 4941, 4952,
+ 4958, 4967, 4973, 4993, 4999, 5008, 5014, 5025,
+ 5031, 5040, 5046, 5069, 5075, 5084, 5090, 5101,
+ 5107, 5116, 5122, 5142, 5148, 5157, 5163, 5174,
+ 5180, 5189, 5195, 5220, 5226, 5235, 5241, 5252,
+ 5258, 5267, 5273, 5293, 5299, 5308, 5314, 5325,
+ 5331, 5340, 5346, 4604, 4610, 4619, 4625, 4636,
+ 4642, 4651, 4657, 4677, 4683, 4692, 4698, 4709,
+ 4715, 4724, 4730, 4755, 4761, 4770, 4776, 4787,
+ 4793, 4802, 4808, 4828, 4834, 4843, 4849, 4860,
+ 4866, 4875, 4881, 4904, 4910, 4919, 4925, 4936,
+ 4942, 4951, 4957, 4977, 4983, 4992, 4998, 5009,
+ 5015, 5024, 5030, 5055, 5061, 5070, 5076, 5087,
+ 5093, 5102, 5108, 5128, 5134, 5143, 5149, 5160,
+ 5166, 5175, 5181, 5045, 5051, 5060, 5066, 5077,
+ 5083, 5092, 5098, 5118, 5124, 5133, 5139, 5150,
+ 5156, 5165, 5171, 5196, 5202, 5211, 5217, 5228,
+ 5234, 5243, 5249, 5269, 5275, 5284, 5290, 5301,
+ 5307, 5316, 5322, 5345, 5351, 5360, 5366, 5377,
+ 5383, 5392, 5398, 5418, 5424, 5433, 5439, 5450,
+ 5456, 5465, 5471, 5496, 5502, 5511, 5517, 5528,
+ 5534, 5543, 5549, 5569, 5575, 5584, 5590, 5601,
+ 5607, 5616, 5622, 5417, 5423, 5432, 5438, 5449,
+ 5455, 5464, 5470, 5490, 5496, 5505, 5511, 5522,
+ 5528, 5537, 5543, 5568, 5574, 5583, 5589, 5600,
+ 5606, 5615, 5621, 5641, 5647, 5656, 5662, 5673,
+ 5679, 5688, 5694, 5717, 5723, 5732, 5738, 5749,
+ 5755, 5764, 5770, 5790, 5796, 5805, 5811, 5822,
+ 5828, 5837, 5843, 5868, 5874, 5883, 5889, 5900,
+ 5906, 5915, 5921, 5941, 5947, 5956, 5962, 5973,
+ 5979, 5988, 5994, 5858, 5864, 5873, 5879, 5890,
+ 5896, 5905, 5911, 5931, 5937, 5946, 5952, 5963,
+ 5969, 5978, 5984, 6009, 6015, 6024, 6030, 6041,
+ 6047, 6056, 6062, 6082, 6088, 6097, 6103, 6114,
+ 6120, 6129, 6135, 6158, 6164, 6173, 6179, 6190,
+ 6196, 6205, 6211, 6231, 6237, 6246, 6252, 6263,
+ 6269, 6278, 6284, 6309, 6315, 6324, 6330, 6341,
+ 6347, 6356, 6362, 6382, 6388, 6397, 6403, 6414,
+ 6420, 6429, 6435, 3515, 3521, 3530, 3536, 3547,
+ 3553, 3562, 3568, 3588, 3594, 3603, 3609, 3620,
+ 3626, 3635, 3641, 3666, 3672, 3681, 3687, 3698,
+ 3704, 3713, 3719, 3739, 3745, 3754, 3760, 3771,
+ 3777, 3786, 3792, 3815, 3821, 3830, 3836, 3847,
+ 3853, 3862, 3868, 3888, 3894, 3903, 3909, 3920,
+ 3926, 3935, 3941, 3966, 3972, 3981, 3987, 3998,
+ 4004, 4013, 4019, 4039, 4045, 4054, 4060, 4071,
+ 4077, 4086, 4092, 3956, 3962, 3971, 3977, 3988,
+ 3994, 4003, 4009, 4029, 4035, 4044, 4050, 4061,
+ 4067, 4076, 4082, 4107, 4113, 4122, 4128, 4139,
+ 4145, 4154, 4160, 4180, 4186, 4195, 4201, 4212,
+ 4218, 4227, 4233, 4256, 4262, 4271, 4277, 4288,
+ 4294, 4303, 4309, 4329, 4335, 4344, 4350, 4361,
+ 4367, 4376, 4382, 4407, 4413, 4422, 4428, 4439,
+ 4445, 4454, 4460, 4480, 4486, 4495, 4501, 4512,
+ 4518, 4527, 4533, 4328, 4334, 4343, 4349, 4360,
+ 4366, 4375, 4381, 4401, 4407, 4416, 4422, 4433,
+ 4439, 4448, 4454, 4479, 4485, 4494, 4500, 4511,
+ 4517, 4526, 4532, 4552, 4558, 4567, 4573, 4584,
+ 4590, 4599, 4605, 4628, 4634, 4643, 4649, 4660,
+ 4666, 4675, 4681, 4701, 4707, 4716, 4722, 4733,
+ 4739, 4748, 4754, 4779, 4785, 4794, 4800, 4811,
+ 4817, 4826, 4832, 4852, 4858, 4867, 4873, 4884,
+ 4890, 4899, 4905, 4769, 4775, 4784, 4790, 4801,
+ 4807, 4816, 4822, 4842, 4848, 4857, 4863, 4874,
+ 4880, 4889, 4895, 4920, 4926, 4935, 4941, 4952,
+ 4958, 4967, 4973, 4993, 4999, 5008, 5014, 5025,
+ 5031, 5040, 5046, 5069, 5075, 5084, 5090, 5101,
+ 5107, 5116, 5122, 5142, 5148, 5157, 5163, 5174,
+ 5180, 5189, 5195, 5220, 5226, 5235, 5241, 5252,
+ 5258, 5267, 5273, 5293, 5299, 5308, 5314, 5325,
+ 5331, 5340, 5346, 4604, 4610, 4619, 4625, 4636,
+ 4642, 4651, 4657, 4677, 4683, 4692, 4698, 4709,
+ 4715, 4724, 4730, 4755, 4761, 4770, 4776, 4787,
+ 4793, 4802, 4808, 4828, 4834, 4843, 4849, 4860,
+ 4866, 4875, 4881, 4904, 4910, 4919, 4925, 4936,
+ 4942, 4951, 4957, 4977, 4983, 4992, 4998, 5009,
+ 5015, 5024, 5030, 5055, 5061, 5070, 5076, 5087,
+ 5093, 5102, 5108, 5128, 5134, 5143, 5149, 5160,
+ 5166, 5175, 5181, 5045, 5051, 5060, 5066, 5077,
+ 5083, 5092, 5098, 5118, 5124, 5133, 5139, 5150,
+ 5156, 5165, 5171, 5196, 5202, 5211, 5217, 5228,
+ 5234, 5243, 5249, 5269, 5275, 5284, 5290, 5301,
+ 5307, 5316, 5322, 5345, 5351, 5360, 5366, 5377,
+ 5383, 5392, 5398, 5418, 5424, 5433, 5439, 5450,
+ 5456, 5465, 5471, 5496, 5502, 5511, 5517, 5528,
+ 5534, 5543, 5549, 5569, 5575, 5584, 5590, 5601,
+ 5607, 5616, 5622, 5417, 5423, 5432, 5438, 5449,
+ 5455, 5464, 5470, 5490, 5496, 5505, 5511, 5522,
+ 5528, 5537, 5543, 5568, 5574, 5583, 5589, 5600,
+ 5606, 5615, 5621, 5641, 5647, 5656, 5662, 5673,
+ 5679, 5688, 5694, 5717, 5723, 5732, 5738, 5749,
+ 5755, 5764, 5770, 5790, 5796, 5805, 5811, 5822,
+ 5828, 5837, 5843, 5868, 5874, 5883, 5889, 5900,
+ 5906, 5915, 5921, 5941, 5947, 5956, 5962, 5973,
+ 5979, 5988, 5994, 5858, 5864, 5873, 5879, 5890,
+ 5896, 5905, 5911, 5931, 5937, 5946, 5952, 5963,
+ 5969, 5978, 5984, 6009, 6015, 6024, 6030, 6041,
+ 6047, 6056, 6062, 6082, 6088, 6097, 6103, 6114,
+ 6120, 6129, 6135, 6158, 6164, 6173, 6179, 6190,
+ 6196, 6205, 6211, 6231, 6237, 6246, 6252, 6263,
+ 6269, 6278, 6284, 6309, 6315, 6324, 6330, 6341,
+ 6347, 6356, 6362, 6382, 6388, 6397, 6403, 6414,
+ 6420, 6429, 6435, 5303, 5309, 5318, 5324, 5335,
+ 5341, 5350, 5356, 5376, 5382, 5391, 5397, 5408,
+ 5414, 5423, 5429, 5454, 5460, 5469, 5475, 5486,
+ 5492, 5501, 5507, 5527, 5533, 5542, 5548, 5559,
+ 5565, 5574, 5580, 5603, 5609, 5618, 5624, 5635,
+ 5641, 5650, 5656, 5676, 5682, 5691, 5697, 5708,
+ 5714, 5723, 5729, 5754, 5760, 5769, 5775, 5786,
+ 5792, 5801, 5807, 5827, 5833, 5842, 5848, 5859,
+ 5865, 5874, 5880, 5744, 5750, 5759, 5765, 5776,
+ 5782, 5791, 5797, 5817, 5823, 5832, 5838, 5849,
+ 5855, 5864, 5870, 5895, 5901, 5910, 5916, 5927,
+ 5933, 5942, 5948, 5968, 5974, 5983, 5989, 6000,
+ 6006, 6015, 6021, 6044, 6050, 6059, 6065, 6076,
+ 6082, 6091, 6097, 6117, 6123, 6132, 6138, 6149,
+ 6155, 6164, 6170, 6195, 6201, 6210, 6216, 6227,
+ 6233, 6242, 6248, 6268, 6274, 6283, 6289, 6300,
+ 6306, 6315, 6321, 6116, 6122, 6131, 6137, 6148,
+ 6154, 6163, 6169, 6189, 6195, 6204, 6210, 6221,
+ 6227, 6236, 6242, 6267, 6273, 6282, 6288, 6299,
+ 6305, 6314, 6320, 6340, 6346, 6355, 6361, 6372,
+ 6378, 6387, 6393, 6416, 6422, 6431, 6437, 6448,
+ 6454, 6463, 6469, 6489, 6495, 6504, 6510, 6521,
+ 6527, 6536, 6542, 6567, 6573, 6582, 6588, 6599,
+ 6605, 6614, 6620, 6640, 6646, 6655, 6661, 6672,
+ 6678, 6687, 6693, 6557, 6563, 6572, 6578, 6589,
+ 6595, 6604, 6610, 6630, 6636, 6645, 6651, 6662,
+ 6668, 6677, 6683, 6708, 6714, 6723, 6729, 6740,
+ 6746, 6755, 6761, 6781, 6787, 6796, 6802, 6813,
+ 6819, 6828, 6834, 6857, 6863, 6872, 6878, 6889,
+ 6895, 6904, 6910, 6930, 6936, 6945, 6951, 6962,
+ 6968, 6977, 6983, 7008, 7014, 7023, 7029, 7040,
+ 7046, 7055, 7061, 7081, 7087, 7096, 7102, 7113,
+ 7119, 7128, 7134, 6392, 6398, 6407, 6413, 6424,
+ 6430, 6439, 6445, 6465, 6471, 6480, 6486, 6497,
+ 6503, 6512, 6518, 6543, 6549, 6558, 6564, 6575,
+ 6581, 6590, 6596, 6616, 6622, 6631, 6637, 6648,
+ 6654, 6663, 6669, 6692, 6698, 6707, 6713, 6724,
+ 6730, 6739, 6745, 6765, 6771, 6780, 6786, 6797,
+ 6803, 6812, 6818, 6843, 6849, 6858, 6864, 6875,
+ 6881, 6890, 6896, 6916, 6922, 6931, 6937, 6948,
+ 6954, 6963, 6969, 6833, 6839, 6848, 6854, 6865,
+ 6871, 6880, 6886, 6906, 6912, 6921, 6927, 6938,
+ 6944, 6953, 6959, 6984, 6990, 6999, 7005, 7016,
+ 7022, 7031, 7037, 7057, 7063, 7072, 7078, 7089,
+ 7095, 7104, 7110, 7133, 7139, 7148, 7154, 7165,
+ 7171, 7180, 7186, 7206, 7212, 7221, 7227, 7238,
+ 7244, 7253, 7259, 7284, 7290, 7299, 7305, 7316,
+ 7322, 7331, 7337, 7357, 7363, 7372, 7378, 7389,
+ 7395, 7404, 7410, 7205, 7211, 7220, 7226, 7237,
+ 7243, 7252, 7258, 7278, 7284, 7293, 7299, 7310,
+ 7316, 7325, 7331, 7356, 7362, 7371, 7377, 7388,
+ 7394, 7403, 7409, 7429, 7435, 7444, 7450, 7461,
+ 7467, 7476, 7482, 7505, 7511, 7520, 7526, 7537,
+ 7543, 7552, 7558, 7578, 7584, 7593, 7599, 7610,
+ 7616, 7625, 7631, 7656, 7662, 7671, 7677, 7688,
+ 7694, 7703, 7709, 7729, 7735, 7744, 7750, 7761
+};
+
+static int VariableLevelCost(int level, const uint8_t probas[NUM_PROBAS]) {
+ int pattern = VP8LevelCodes[level - 1][0];
+ int bits = VP8LevelCodes[level - 1][1];
+ int cost = 0;
+ int i;
+ for (i = 2; pattern; ++i) {
+ if (pattern & 1) {
+ cost += VP8BitCost(bits & 1, probas[i]);
+ }
+ bits >>= 1;
+ pattern >>= 1;
+ }
+ return cost;
+}
+
+//------------------------------------------------------------------------------
+// Pre-calc level costs once for all
+
+void VP8CalculateLevelCosts(VP8Proba* const proba) {
+ int ctype, band, ctx;
+
+ if (!proba->dirty_) return; // nothing to do.
+
+ for (ctype = 0; ctype < NUM_TYPES; ++ctype) {
+ for (band = 0; band < NUM_BANDS; ++band) {
+ for(ctx = 0; ctx < NUM_CTX; ++ctx) {
+ const uint8_t* const p = proba->coeffs_[ctype][band][ctx];
+ uint16_t* const table = proba->level_cost_[ctype][band][ctx];
+ const int cost_base = VP8BitCost(1, p[1]);
+ int v;
+ table[0] = VP8BitCost(0, p[1]);
+ for (v = 1; v <= MAX_VARIABLE_LEVEL; ++v) {
+ table[v] = cost_base + VariableLevelCost(v, p);
+ }
+ // Starting at level 67 and up, the variable part of the cost is
+ // actually constant.
+ }
+ }
+ }
+ proba->dirty_ = 0;
+}
+
+//------------------------------------------------------------------------------
+// Mode cost tables.
+
+// These are the fixed probabilities (in the coding trees) turned into bit-cost
+// by calling VP8BitCost().
+const uint16_t VP8FixedCostsUV[4] = { 302, 984, 439, 642 };
+// note: these values include the fixed VP8BitCost(1, 145) mode selection cost.
+const uint16_t VP8FixedCostsI16[4] = { 663, 919, 872, 919 };
+const uint16_t VP8FixedCostsI4[NUM_BMODES][NUM_BMODES][NUM_BMODES] = {
+ { { 251, 1362, 1934, 2085, 2314, 2230, 1839, 1988, 2437, 2348 },
+ { 403, 680, 1507, 1519, 2060, 2005, 1992, 1914, 1924, 1733 },
+ { 353, 1121, 973, 1895, 2060, 1787, 1671, 1516, 2012, 1868 },
+ { 770, 852, 1581, 632, 1393, 1780, 1823, 1936, 1074, 1218 },
+ { 510, 1270, 1467, 1319, 847, 1279, 1792, 2094, 1080, 1353 },
+ { 488, 1322, 918, 1573, 1300, 883, 1814, 1752, 1756, 1502 },
+ { 425, 992, 1820, 1514, 1843, 2440, 937, 1771, 1924, 1129 },
+ { 363, 1248, 1257, 1970, 2194, 2385, 1569, 953, 1951, 1601 },
+ { 723, 1257, 1631, 964, 963, 1508, 1697, 1824, 671, 1418 },
+ { 635, 1038, 1573, 930, 1673, 1413, 1410, 1687, 1410, 749 } },
+ { { 451, 613, 1345, 1702, 1870, 1716, 1728, 1766, 2190, 2310 },
+ { 678, 453, 1171, 1443, 1925, 1831, 2045, 1781, 1887, 1602 },
+ { 711, 666, 674, 1718, 1910, 1493, 1775, 1193, 2325, 2325 },
+ { 883, 854, 1583, 542, 1800, 1878, 1664, 2149, 1207, 1087 },
+ { 669, 994, 1248, 1122, 949, 1179, 1376, 1729, 1070, 1244 },
+ { 715, 1026, 715, 1350, 1430, 930, 1717, 1296, 1479, 1479 },
+ { 544, 841, 1656, 1450, 2094, 3883, 1010, 1759, 2076, 809 },
+ { 610, 855, 957, 1553, 2067, 1561, 1704, 824, 2066, 1226 },
+ { 833, 960, 1416, 819, 1277, 1619, 1501, 1617, 757, 1182 },
+ { 711, 964, 1252, 879, 1441, 1828, 1508, 1636, 1594, 734 } },
+ { { 605, 764, 734, 1713, 1747, 1192, 1819, 1353, 1877, 2392 },
+ { 866, 641, 586, 1622, 2072, 1431, 1888, 1346, 2189, 1764 },
+ { 901, 851, 456, 2165, 2281, 1405, 1739, 1193, 2183, 2443 },
+ { 770, 1045, 952, 1078, 1342, 1191, 1436, 1063, 1303, 995 },
+ { 901, 1086, 727, 1170, 884, 1105, 1267, 1401, 1739, 1337 },
+ { 951, 1162, 595, 1488, 1388, 703, 1790, 1366, 2057, 1724 },
+ { 534, 986, 1273, 1987, 3273, 1485, 1024, 1399, 1583, 866 },
+ { 699, 1182, 695, 1978, 1726, 1986, 1326, 714, 1750, 1672 },
+ { 951, 1217, 1209, 920, 1062, 1441, 1548, 999, 952, 932 },
+ { 733, 1284, 784, 1256, 1557, 1098, 1257, 1357, 1414, 908 } },
+ { { 316, 1075, 1653, 1220, 2145, 2051, 1730, 2131, 1884, 1790 },
+ { 745, 516, 1404, 894, 1599, 2375, 2013, 2105, 1475, 1381 },
+ { 516, 729, 1088, 1319, 1637, 3426, 1636, 1275, 1531, 1453 },
+ { 894, 943, 2138, 468, 1704, 2259, 2069, 1763, 1266, 1158 },
+ { 605, 1025, 1235, 871, 1170, 1767, 1493, 1500, 1104, 1258 },
+ { 739, 826, 1207, 1151, 1412, 846, 1305, 2726, 1014, 1569 },
+ { 558, 825, 1820, 1398, 3344, 1556, 1218, 1550, 1228, 878 },
+ { 429, 951, 1089, 1816, 3861, 3861, 1556, 969, 1568, 1828 },
+ { 883, 961, 1752, 769, 1468, 1810, 2081, 2346, 613, 1298 },
+ { 803, 895, 1372, 641, 1303, 1708, 1686, 1700, 1306, 1033 } },
+ { { 439, 1267, 1270, 1579, 963, 1193, 1723, 1729, 1198, 1993 },
+ { 705, 725, 1029, 1153, 1176, 1103, 1821, 1567, 1259, 1574 },
+ { 723, 859, 802, 1253, 972, 1202, 1407, 1665, 1520, 1674 },
+ { 894, 960, 1254, 887, 1052, 1607, 1344, 1349, 865, 1150 },
+ { 833, 1312, 1337, 1205, 572, 1288, 1414, 1529, 1088, 1430 },
+ { 842, 1279, 1068, 1861, 862, 688, 1861, 1630, 1039, 1381 },
+ { 766, 938, 1279, 1546, 3338, 1550, 1031, 1542, 1288, 640 },
+ { 715, 1090, 835, 1609, 1100, 1100, 1603, 1019, 1102, 1617 },
+ { 894, 1813, 1500, 1188, 789, 1194, 1491, 1919, 617, 1333 },
+ { 610, 1076, 1644, 1281, 1283, 975, 1179, 1688, 1434, 889 } },
+ { { 544, 971, 1146, 1849, 1221, 740, 1857, 1621, 1683, 2430 },
+ { 723, 705, 961, 1371, 1426, 821, 2081, 2079, 1839, 1380 },
+ { 783, 857, 703, 2145, 1419, 814, 1791, 1310, 1609, 2206 },
+ { 997, 1000, 1153, 792, 1229, 1162, 1810, 1418, 942, 979 },
+ { 901, 1226, 883, 1289, 793, 715, 1904, 1649, 1319, 3108 },
+ { 979, 1478, 782, 2216, 1454, 455, 3092, 1591, 1997, 1664 },
+ { 663, 1110, 1504, 1114, 1522, 3311, 676, 1522, 1530, 1024 },
+ { 605, 1138, 1153, 1314, 1569, 1315, 1157, 804, 1574, 1320 },
+ { 770, 1216, 1218, 1227, 869, 1384, 1232, 1375, 834, 1239 },
+ { 775, 1007, 843, 1216, 1225, 1074, 2527, 1479, 1149, 975 } },
+ { { 477, 817, 1309, 1439, 1708, 1454, 1159, 1241, 1945, 1672 },
+ { 577, 796, 1112, 1271, 1618, 1458, 1087, 1345, 1831, 1265 },
+ { 663, 776, 753, 1940, 1690, 1690, 1227, 1097, 3149, 1361 },
+ { 766, 1299, 1744, 1161, 1565, 1106, 1045, 1230, 1232, 707 },
+ { 915, 1026, 1404, 1182, 1184, 851, 1428, 2425, 1043, 789 },
+ { 883, 1456, 790, 1082, 1086, 985, 1083, 1484, 1238, 1160 },
+ { 507, 1345, 2261, 1995, 1847, 3636, 653, 1761, 2287, 933 },
+ { 553, 1193, 1470, 2057, 2059, 2059, 833, 779, 2058, 1263 },
+ { 766, 1275, 1515, 1039, 957, 1554, 1286, 1540, 1289, 705 },
+ { 499, 1378, 1496, 1385, 1850, 1850, 1044, 2465, 1515, 720 } },
+ { { 553, 930, 978, 2077, 1968, 1481, 1457, 761, 1957, 2362 },
+ { 694, 864, 905, 1720, 1670, 1621, 1429, 718, 2125, 1477 },
+ { 699, 968, 658, 3190, 2024, 1479, 1865, 750, 2060, 2320 },
+ { 733, 1308, 1296, 1062, 1576, 1322, 1062, 1112, 1172, 816 },
+ { 920, 927, 1052, 939, 947, 1156, 1152, 1073, 3056, 1268 },
+ { 723, 1534, 711, 1547, 1294, 892, 1553, 928, 1815, 1561 },
+ { 663, 1366, 1583, 2111, 1712, 3501, 522, 1155, 2130, 1133 },
+ { 614, 1731, 1188, 2343, 1944, 3733, 1287, 487, 3546, 1758 },
+ { 770, 1585, 1312, 826, 884, 2673, 1185, 1006, 1195, 1195 },
+ { 758, 1333, 1273, 1023, 1621, 1162, 1351, 833, 1479, 862 } },
+ { { 376, 1193, 1446, 1149, 1545, 1577, 1870, 1789, 1175, 1823 },
+ { 803, 633, 1136, 1058, 1350, 1323, 1598, 2247, 1072, 1252 },
+ { 614, 1048, 943, 981, 1152, 1869, 1461, 1020, 1618, 1618 },
+ { 1107, 1085, 1282, 592, 1779, 1933, 1648, 2403, 691, 1246 },
+ { 851, 1309, 1223, 1243, 895, 1593, 1792, 2317, 627, 1076 },
+ { 770, 1216, 1030, 1125, 921, 981, 1629, 1131, 1049, 1646 },
+ { 626, 1469, 1456, 1081, 1489, 3278, 981, 1232, 1498, 733 },
+ { 617, 1201, 812, 1220, 1476, 1476, 1478, 970, 1228, 1488 },
+ { 1179, 1393, 1540, 999, 1243, 1503, 1916, 1925, 414, 1614 },
+ { 943, 1088, 1490, 682, 1112, 1372, 1756, 1505, 966, 966 } },
+ { { 322, 1142, 1589, 1396, 2144, 1859, 1359, 1925, 2084, 1518 },
+ { 617, 625, 1241, 1234, 2121, 1615, 1524, 1858, 1720, 1004 },
+ { 553, 851, 786, 1299, 1452, 1560, 1372, 1561, 1967, 1713 },
+ { 770, 977, 1396, 568, 1893, 1639, 1540, 2108, 1430, 1013 },
+ { 684, 1120, 1375, 982, 930, 2719, 1638, 1643, 933, 993 },
+ { 553, 1103, 996, 1356, 1361, 1005, 1507, 1761, 1184, 1268 },
+ { 419, 1247, 1537, 1554, 1817, 3606, 1026, 1666, 1829, 923 },
+ { 439, 1139, 1101, 1257, 3710, 1922, 1205, 1040, 1931, 1529 },
+ { 979, 935, 1269, 847, 1202, 1286, 1530, 1535, 827, 1036 },
+ { 516, 1378, 1569, 1110, 1798, 1798, 1198, 2199, 1543, 712 } },
+};
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/enc/cost.h b/drivers/webpold/enc/cost.h
new file mode 100644
index 0000000000..09b75b699d
--- /dev/null
+++ b/drivers/webpold/enc/cost.h
@@ -0,0 +1,48 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Cost tables for level and modes.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#ifndef WEBP_ENC_COST_H_
+#define WEBP_ENC_COST_H_
+
+#include "./vp8enci.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+extern const uint16_t VP8LevelFixedCosts[2048]; // approximate cost per level
+extern const uint16_t VP8EntropyCost[256]; // 8bit fixed-point log(p)
+
+// Cost of coding one event with probability 'proba'.
+static WEBP_INLINE int VP8BitCost(int bit, uint8_t proba) {
+ return !bit ? VP8EntropyCost[proba] : VP8EntropyCost[255 - proba];
+}
+
+// Level cost calculations
+extern const uint16_t VP8LevelCodes[MAX_VARIABLE_LEVEL][2];
+void VP8CalculateLevelCosts(VP8Proba* const proba);
+static WEBP_INLINE int VP8LevelCost(const uint16_t* const table, int level) {
+ return VP8LevelFixedCosts[level]
+ + table[(level > MAX_VARIABLE_LEVEL) ? MAX_VARIABLE_LEVEL : level];
+}
+
+// Mode costs
+extern const uint16_t VP8FixedCostsUV[4];
+extern const uint16_t VP8FixedCostsI16[4];
+extern const uint16_t VP8FixedCostsI4[NUM_BMODES][NUM_BMODES][NUM_BMODES];
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif /* WEBP_ENC_COST_H_ */
diff --git a/drivers/webpold/enc/filter.c b/drivers/webpold/enc/filter.c
new file mode 100644
index 0000000000..7fb78a3949
--- /dev/null
+++ b/drivers/webpold/enc/filter.c
@@ -0,0 +1,409 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Selecting filter level
+//
+// Author: somnath@google.com (Somnath Banerjee)
+
+#include "./vp8enci.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+// NOTE: clip1, tables and InitTables are repeated entries of dsp.c
+static uint8_t abs0[255 + 255 + 1]; // abs(i)
+static uint8_t abs1[255 + 255 + 1]; // abs(i)>>1
+static int8_t sclip1[1020 + 1020 + 1]; // clips [-1020, 1020] to [-128, 127]
+static int8_t sclip2[112 + 112 + 1]; // clips [-112, 112] to [-16, 15]
+static uint8_t clip1[255 + 510 + 1]; // clips [-255,510] to [0,255]
+
+static int tables_ok = 0;
+
+static void InitTables(void) {
+ if (!tables_ok) {
+ int i;
+ for (i = -255; i <= 255; ++i) {
+ abs0[255 + i] = (i < 0) ? -i : i;
+ abs1[255 + i] = abs0[255 + i] >> 1;
+ }
+ for (i = -1020; i <= 1020; ++i) {
+ sclip1[1020 + i] = (i < -128) ? -128 : (i > 127) ? 127 : i;
+ }
+ for (i = -112; i <= 112; ++i) {
+ sclip2[112 + i] = (i < -16) ? -16 : (i > 15) ? 15 : i;
+ }
+ for (i = -255; i <= 255 + 255; ++i) {
+ clip1[255 + i] = (i < 0) ? 0 : (i > 255) ? 255 : i;
+ }
+ tables_ok = 1;
+ }
+}
+
+//------------------------------------------------------------------------------
+// Edge filtering functions
+
+// 4 pixels in, 2 pixels out
+static WEBP_INLINE void do_filter2(uint8_t* p, int step) {
+ const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
+ const int a = 3 * (q0 - p0) + sclip1[1020 + p1 - q1];
+ const int a1 = sclip2[112 + ((a + 4) >> 3)];
+ const int a2 = sclip2[112 + ((a + 3) >> 3)];
+ p[-step] = clip1[255 + p0 + a2];
+ p[ 0] = clip1[255 + q0 - a1];
+}
+
+// 4 pixels in, 4 pixels out
+static WEBP_INLINE void do_filter4(uint8_t* p, int step) {
+ const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
+ const int a = 3 * (q0 - p0);
+ const int a1 = sclip2[112 + ((a + 4) >> 3)];
+ const int a2 = sclip2[112 + ((a + 3) >> 3)];
+ const int a3 = (a1 + 1) >> 1;
+ p[-2*step] = clip1[255 + p1 + a3];
+ p[- step] = clip1[255 + p0 + a2];
+ p[ 0] = clip1[255 + q0 - a1];
+ p[ step] = clip1[255 + q1 - a3];
+}
+
+// high edge-variance
+static WEBP_INLINE int hev(const uint8_t* p, int step, int thresh) {
+ const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
+ return (abs0[255 + p1 - p0] > thresh) || (abs0[255 + q1 - q0] > thresh);
+}
+
+static WEBP_INLINE int needs_filter(const uint8_t* p, int step, int thresh) {
+ const int p1 = p[-2*step], p0 = p[-step], q0 = p[0], q1 = p[step];
+ return (2 * abs0[255 + p0 - q0] + abs1[255 + p1 - q1]) <= thresh;
+}
+
+static WEBP_INLINE int needs_filter2(const uint8_t* p,
+ int step, int t, int it) {
+ const int p3 = p[-4*step], p2 = p[-3*step], p1 = p[-2*step], p0 = p[-step];
+ const int q0 = p[0], q1 = p[step], q2 = p[2*step], q3 = p[3*step];
+ if ((2 * abs0[255 + p0 - q0] + abs1[255 + p1 - q1]) > t)
+ return 0;
+ return abs0[255 + p3 - p2] <= it && abs0[255 + p2 - p1] <= it &&
+ abs0[255 + p1 - p0] <= it && abs0[255 + q3 - q2] <= it &&
+ abs0[255 + q2 - q1] <= it && abs0[255 + q1 - q0] <= it;
+}
+
+//------------------------------------------------------------------------------
+// Simple In-loop filtering (Paragraph 15.2)
+
+static void SimpleVFilter16(uint8_t* p, int stride, int thresh) {
+ int i;
+ for (i = 0; i < 16; ++i) {
+ if (needs_filter(p + i, stride, thresh)) {
+ do_filter2(p + i, stride);
+ }
+ }
+}
+
+static void SimpleHFilter16(uint8_t* p, int stride, int thresh) {
+ int i;
+ for (i = 0; i < 16; ++i) {
+ if (needs_filter(p + i * stride, 1, thresh)) {
+ do_filter2(p + i * stride, 1);
+ }
+ }
+}
+
+static void SimpleVFilter16i(uint8_t* p, int stride, int thresh) {
+ int k;
+ for (k = 3; k > 0; --k) {
+ p += 4 * stride;
+ SimpleVFilter16(p, stride, thresh);
+ }
+}
+
+static void SimpleHFilter16i(uint8_t* p, int stride, int thresh) {
+ int k;
+ for (k = 3; k > 0; --k) {
+ p += 4;
+ SimpleHFilter16(p, stride, thresh);
+ }
+}
+
+//------------------------------------------------------------------------------
+// Complex In-loop filtering (Paragraph 15.3)
+
+static WEBP_INLINE void FilterLoop24(uint8_t* p,
+ int hstride, int vstride, int size,
+ int thresh, int ithresh, int hev_thresh) {
+ while (size-- > 0) {
+ if (needs_filter2(p, hstride, thresh, ithresh)) {
+ if (hev(p, hstride, hev_thresh)) {
+ do_filter2(p, hstride);
+ } else {
+ do_filter4(p, hstride);
+ }
+ }
+ p += vstride;
+ }
+}
+
+// on three inner edges
+static void VFilter16i(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ int k;
+ for (k = 3; k > 0; --k) {
+ p += 4 * stride;
+ FilterLoop24(p, stride, 1, 16, thresh, ithresh, hev_thresh);
+ }
+}
+
+static void HFilter16i(uint8_t* p, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ int k;
+ for (k = 3; k > 0; --k) {
+ p += 4;
+ FilterLoop24(p, 1, stride, 16, thresh, ithresh, hev_thresh);
+ }
+}
+
+static void VFilter8i(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop24(u + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh);
+ FilterLoop24(v + 4 * stride, stride, 1, 8, thresh, ithresh, hev_thresh);
+}
+
+static void HFilter8i(uint8_t* u, uint8_t* v, int stride,
+ int thresh, int ithresh, int hev_thresh) {
+ FilterLoop24(u + 4, 1, stride, 8, thresh, ithresh, hev_thresh);
+ FilterLoop24(v + 4, 1, stride, 8, thresh, ithresh, hev_thresh);
+}
+
+//------------------------------------------------------------------------------
+
+void (*VP8EncVFilter16i)(uint8_t*, int, int, int, int) = VFilter16i;
+void (*VP8EncHFilter16i)(uint8_t*, int, int, int, int) = HFilter16i;
+void (*VP8EncVFilter8i)(uint8_t*, uint8_t*, int, int, int, int) = VFilter8i;
+void (*VP8EncHFilter8i)(uint8_t*, uint8_t*, int, int, int, int) = HFilter8i;
+
+void (*VP8EncSimpleVFilter16i)(uint8_t*, int, int) = SimpleVFilter16i;
+void (*VP8EncSimpleHFilter16i)(uint8_t*, int, int) = SimpleHFilter16i;
+
+//------------------------------------------------------------------------------
+// Paragraph 15.4: compute the inner-edge filtering strength
+
+static int GetILevel(int sharpness, int level) {
+ if (sharpness > 0) {
+ if (sharpness > 4) {
+ level >>= 2;
+ } else {
+ level >>= 1;
+ }
+ if (level > 9 - sharpness) {
+ level = 9 - sharpness;
+ }
+ }
+ if (level < 1) level = 1;
+ return level;
+}
+
+static void DoFilter(const VP8EncIterator* const it, int level) {
+ const VP8Encoder* const enc = it->enc_;
+ const int ilevel = GetILevel(enc->config_->filter_sharpness, level);
+ const int limit = 2 * level + ilevel;
+
+ uint8_t* const y_dst = it->yuv_out2_ + Y_OFF;
+ uint8_t* const u_dst = it->yuv_out2_ + U_OFF;
+ uint8_t* const v_dst = it->yuv_out2_ + V_OFF;
+
+ // copy current block to yuv_out2_
+ memcpy(y_dst, it->yuv_out_, YUV_SIZE * sizeof(uint8_t));
+
+ if (enc->filter_hdr_.simple_ == 1) { // simple
+ VP8EncSimpleHFilter16i(y_dst, BPS, limit);
+ VP8EncSimpleVFilter16i(y_dst, BPS, limit);
+ } else { // complex
+ const int hev_thresh = (level >= 40) ? 2 : (level >= 15) ? 1 : 0;
+ VP8EncHFilter16i(y_dst, BPS, limit, ilevel, hev_thresh);
+ VP8EncHFilter8i(u_dst, v_dst, BPS, limit, ilevel, hev_thresh);
+ VP8EncVFilter16i(y_dst, BPS, limit, ilevel, hev_thresh);
+ VP8EncVFilter8i(u_dst, v_dst, BPS, limit, ilevel, hev_thresh);
+ }
+}
+
+//------------------------------------------------------------------------------
+// SSIM metric
+
+enum { KERNEL = 3 };
+static const double kMinValue = 1.e-10; // minimal threshold
+
+void VP8SSIMAddStats(const DistoStats* const src, DistoStats* const dst) {
+ dst->w += src->w;
+ dst->xm += src->xm;
+ dst->ym += src->ym;
+ dst->xxm += src->xxm;
+ dst->xym += src->xym;
+ dst->yym += src->yym;
+}
+
+static void VP8SSIMAccumulate(const uint8_t* src1, int stride1,
+ const uint8_t* src2, int stride2,
+ int xo, int yo, int W, int H,
+ DistoStats* const stats) {
+ const int ymin = (yo - KERNEL < 0) ? 0 : yo - KERNEL;
+ const int ymax = (yo + KERNEL > H - 1) ? H - 1 : yo + KERNEL;
+ const int xmin = (xo - KERNEL < 0) ? 0 : xo - KERNEL;
+ const int xmax = (xo + KERNEL > W - 1) ? W - 1 : xo + KERNEL;
+ int x, y;
+ src1 += ymin * stride1;
+ src2 += ymin * stride2;
+ for (y = ymin; y <= ymax; ++y, src1 += stride1, src2 += stride2) {
+ for (x = xmin; x <= xmax; ++x) {
+ const int s1 = src1[x];
+ const int s2 = src2[x];
+ stats->w += 1;
+ stats->xm += s1;
+ stats->ym += s2;
+ stats->xxm += s1 * s1;
+ stats->xym += s1 * s2;
+ stats->yym += s2 * s2;
+ }
+ }
+}
+
+double VP8SSIMGet(const DistoStats* const stats) {
+ const double xmxm = stats->xm * stats->xm;
+ const double ymym = stats->ym * stats->ym;
+ const double xmym = stats->xm * stats->ym;
+ const double w2 = stats->w * stats->w;
+ double sxx = stats->xxm * stats->w - xmxm;
+ double syy = stats->yym * stats->w - ymym;
+ double sxy = stats->xym * stats->w - xmym;
+ double C1, C2;
+ double fnum;
+ double fden;
+ // small errors are possible, due to rounding. Clamp to zero.
+ if (sxx < 0.) sxx = 0.;
+ if (syy < 0.) syy = 0.;
+ C1 = 6.5025 * w2;
+ C2 = 58.5225 * w2;
+ fnum = (2 * xmym + C1) * (2 * sxy + C2);
+ fden = (xmxm + ymym + C1) * (sxx + syy + C2);
+ return (fden != 0.) ? fnum / fden : kMinValue;
+}
+
+double VP8SSIMGetSquaredError(const DistoStats* const s) {
+ if (s->w > 0.) {
+ const double iw2 = 1. / (s->w * s->w);
+ const double sxx = s->xxm * s->w - s->xm * s->xm;
+ const double syy = s->yym * s->w - s->ym * s->ym;
+ const double sxy = s->xym * s->w - s->xm * s->ym;
+ const double SSE = iw2 * (sxx + syy - 2. * sxy);
+ if (SSE > kMinValue) return SSE;
+ }
+ return kMinValue;
+}
+
+void VP8SSIMAccumulatePlane(const uint8_t* src1, int stride1,
+ const uint8_t* src2, int stride2,
+ int W, int H, DistoStats* const stats) {
+ int x, y;
+ for (y = 0; y < H; ++y) {
+ for (x = 0; x < W; ++x) {
+ VP8SSIMAccumulate(src1, stride1, src2, stride2, x, y, W, H, stats);
+ }
+ }
+}
+
+static double GetMBSSIM(const uint8_t* yuv1, const uint8_t* yuv2) {
+ int x, y;
+ DistoStats s = { .0, .0, .0, .0, .0, .0 };
+
+ // compute SSIM in a 10 x 10 window
+ for (x = 3; x < 13; x++) {
+ for (y = 3; y < 13; y++) {
+ VP8SSIMAccumulate(yuv1 + Y_OFF, BPS, yuv2 + Y_OFF, BPS, x, y, 16, 16, &s);
+ }
+ }
+ for (x = 1; x < 7; x++) {
+ for (y = 1; y < 7; y++) {
+ VP8SSIMAccumulate(yuv1 + U_OFF, BPS, yuv2 + U_OFF, BPS, x, y, 8, 8, &s);
+ VP8SSIMAccumulate(yuv1 + V_OFF, BPS, yuv2 + V_OFF, BPS, x, y, 8, 8, &s);
+ }
+ }
+ return VP8SSIMGet(&s);
+}
+
+//------------------------------------------------------------------------------
+// Exposed APIs: Encoder should call the following 3 functions to adjust
+// loop filter strength
+
+void VP8InitFilter(VP8EncIterator* const it) {
+ int s, i;
+ if (!it->lf_stats_) return;
+
+ InitTables();
+ for (s = 0; s < NUM_MB_SEGMENTS; s++) {
+ for (i = 0; i < MAX_LF_LEVELS; i++) {
+ (*it->lf_stats_)[s][i] = 0;
+ }
+ }
+}
+
+void VP8StoreFilterStats(VP8EncIterator* const it) {
+ int d;
+ const int s = it->mb_->segment_;
+ const int level0 = it->enc_->dqm_[s].fstrength_; // TODO: ref_lf_delta[]
+
+ // explore +/-quant range of values around level0
+ const int delta_min = -it->enc_->dqm_[s].quant_;
+ const int delta_max = it->enc_->dqm_[s].quant_;
+ const int step_size = (delta_max - delta_min >= 4) ? 4 : 1;
+
+ if (!it->lf_stats_) return;
+
+ // NOTE: Currently we are applying filter only across the sublock edges
+ // There are two reasons for that.
+ // 1. Applying filter on macro block edges will change the pixels in
+ // the left and top macro blocks. That will be hard to restore
+ // 2. Macro Blocks on the bottom and right are not yet compressed. So we
+ // cannot apply filter on the right and bottom macro block edges.
+ if (it->mb_->type_ == 1 && it->mb_->skip_) return;
+
+ // Always try filter level zero
+ (*it->lf_stats_)[s][0] += GetMBSSIM(it->yuv_in_, it->yuv_out_);
+
+ for (d = delta_min; d <= delta_max; d += step_size) {
+ const int level = level0 + d;
+ if (level <= 0 || level >= MAX_LF_LEVELS) {
+ continue;
+ }
+ DoFilter(it, level);
+ (*it->lf_stats_)[s][level] += GetMBSSIM(it->yuv_in_, it->yuv_out2_);
+ }
+}
+
+void VP8AdjustFilterStrength(VP8EncIterator* const it) {
+ int s;
+ VP8Encoder* const enc = it->enc_;
+
+ if (!it->lf_stats_) {
+ return;
+ }
+ for (s = 0; s < NUM_MB_SEGMENTS; s++) {
+ int i, best_level = 0;
+ // Improvement over filter level 0 should be at least 1e-5 (relatively)
+ double best_v = 1.00001 * (*it->lf_stats_)[s][0];
+ for (i = 1; i < MAX_LF_LEVELS; i++) {
+ const double v = (*it->lf_stats_)[s][i];
+ if (v > best_v) {
+ best_v = v;
+ best_level = i;
+ }
+ }
+ enc->dqm_[s].fstrength_ = best_level;
+ }
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/enc/frame.c b/drivers/webpold/enc/frame.c
new file mode 100644
index 0000000000..bdd360069b
--- /dev/null
+++ b/drivers/webpold/enc/frame.c
@@ -0,0 +1,939 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// frame coding and analysis
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "./vp8enci.h"
+#include "./cost.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define SEGMENT_VISU 0
+#define DEBUG_SEARCH 0 // useful to track search convergence
+
+// On-the-fly info about the current set of residuals. Handy to avoid
+// passing zillions of params.
+typedef struct {
+ int first;
+ int last;
+ const int16_t* coeffs;
+
+ int coeff_type;
+ ProbaArray* prob;
+ StatsArray* stats;
+ CostArray* cost;
+} VP8Residual;
+
+//------------------------------------------------------------------------------
+// Tables for level coding
+
+const uint8_t VP8EncBands[16 + 1] = {
+ 0, 1, 2, 3, 6, 4, 5, 6, 6, 6, 6, 6, 6, 6, 6, 7,
+ 0 // sentinel
+};
+
+static const uint8_t kCat3[] = { 173, 148, 140 };
+static const uint8_t kCat4[] = { 176, 155, 140, 135 };
+static const uint8_t kCat5[] = { 180, 157, 141, 134, 130 };
+static const uint8_t kCat6[] =
+ { 254, 254, 243, 230, 196, 177, 153, 140, 133, 130, 129 };
+
+//------------------------------------------------------------------------------
+// Reset the statistics about: number of skips, token proba, level cost,...
+
+static void ResetStats(VP8Encoder* const enc) {
+ VP8Proba* const proba = &enc->proba_;
+ VP8CalculateLevelCosts(proba);
+ proba->nb_skip_ = 0;
+}
+
+//------------------------------------------------------------------------------
+// Skip decision probability
+
+#define SKIP_PROBA_THRESHOLD 250 // value below which using skip_proba is OK.
+
+static int CalcSkipProba(uint64_t nb, uint64_t total) {
+ return (int)(total ? (total - nb) * 255 / total : 255);
+}
+
+// Returns the bit-cost for coding the skip probability.
+static int FinalizeSkipProba(VP8Encoder* const enc) {
+ VP8Proba* const proba = &enc->proba_;
+ const int nb_mbs = enc->mb_w_ * enc->mb_h_;
+ const int nb_events = proba->nb_skip_;
+ int size;
+ proba->skip_proba_ = CalcSkipProba(nb_events, nb_mbs);
+ proba->use_skip_proba_ = (proba->skip_proba_ < SKIP_PROBA_THRESHOLD);
+ size = 256; // 'use_skip_proba' bit
+ if (proba->use_skip_proba_) {
+ size += nb_events * VP8BitCost(1, proba->skip_proba_)
+ + (nb_mbs - nb_events) * VP8BitCost(0, proba->skip_proba_);
+ size += 8 * 256; // cost of signaling the skip_proba_ itself.
+ }
+ return size;
+}
+
+//------------------------------------------------------------------------------
+// Recording of token probabilities.
+
+static void ResetTokenStats(VP8Encoder* const enc) {
+ VP8Proba* const proba = &enc->proba_;
+ memset(proba->stats_, 0, sizeof(proba->stats_));
+}
+
+// Record proba context used
+static int Record(int bit, proba_t* const stats) {
+ proba_t p = *stats;
+ if (p >= 0xffff0000u) { // an overflow is inbound.
+ p = ((p + 1u) >> 1) & 0x7fff7fffu; // -> divide the stats by 2.
+ }
+ // record bit count (lower 16 bits) and increment total count (upper 16 bits).
+ p += 0x00010000u + bit;
+ *stats = p;
+ return bit;
+}
+
+// We keep the table free variant around for reference, in case.
+#define USE_LEVEL_CODE_TABLE
+
+// Simulate block coding, but only record statistics.
+// Note: no need to record the fixed probas.
+static int RecordCoeffs(int ctx, const VP8Residual* const res) {
+ int n = res->first;
+ proba_t* s = res->stats[VP8EncBands[n]][ctx];
+ if (res->last < 0) {
+ Record(0, s + 0);
+ return 0;
+ }
+ while (n <= res->last) {
+ int v;
+ Record(1, s + 0);
+ while ((v = res->coeffs[n++]) == 0) {
+ Record(0, s + 1);
+ s = res->stats[VP8EncBands[n]][0];
+ }
+ Record(1, s + 1);
+ if (!Record(2u < (unsigned int)(v + 1), s + 2)) { // v = -1 or 1
+ s = res->stats[VP8EncBands[n]][1];
+ } else {
+ v = abs(v);
+#if !defined(USE_LEVEL_CODE_TABLE)
+ if (!Record(v > 4, s + 3)) {
+ if (Record(v != 2, s + 4))
+ Record(v == 4, s + 5);
+ } else if (!Record(v > 10, s + 6)) {
+ Record(v > 6, s + 7);
+ } else if (!Record((v >= 3 + (8 << 2)), s + 8)) {
+ Record((v >= 3 + (8 << 1)), s + 9);
+ } else {
+ Record((v >= 3 + (8 << 3)), s + 10);
+ }
+#else
+ if (v > MAX_VARIABLE_LEVEL)
+ v = MAX_VARIABLE_LEVEL;
+
+ {
+ const int bits = VP8LevelCodes[v - 1][1];
+ int pattern = VP8LevelCodes[v - 1][0];
+ int i;
+ for (i = 0; (pattern >>= 1) != 0; ++i) {
+ const int mask = 2 << i;
+ if (pattern & 1) Record(!!(bits & mask), s + 3 + i);
+ }
+ }
+#endif
+ s = res->stats[VP8EncBands[n]][2];
+ }
+ }
+ if (n < 16) Record(0, s + 0);
+ return 1;
+}
+
+// Collect statistics and deduce probabilities for next coding pass.
+// Return the total bit-cost for coding the probability updates.
+static int CalcTokenProba(int nb, int total) {
+ assert(nb <= total);
+ return nb ? (255 - nb * 255 / total) : 255;
+}
+
+// Cost of coding 'nb' 1's and 'total-nb' 0's using 'proba' probability.
+static int BranchCost(int nb, int total, int proba) {
+ return nb * VP8BitCost(1, proba) + (total - nb) * VP8BitCost(0, proba);
+}
+
+static int FinalizeTokenProbas(VP8Encoder* const enc) {
+ VP8Proba* const proba = &enc->proba_;
+ int has_changed = 0;
+ int size = 0;
+ int t, b, c, p;
+ for (t = 0; t < NUM_TYPES; ++t) {
+ for (b = 0; b < NUM_BANDS; ++b) {
+ for (c = 0; c < NUM_CTX; ++c) {
+ for (p = 0; p < NUM_PROBAS; ++p) {
+ const proba_t stats = proba->stats_[t][b][c][p];
+ const int nb = (stats >> 0) & 0xffff;
+ const int total = (stats >> 16) & 0xffff;
+ const int update_proba = VP8CoeffsUpdateProba[t][b][c][p];
+ const int old_p = VP8CoeffsProba0[t][b][c][p];
+ const int new_p = CalcTokenProba(nb, total);
+ const int old_cost = BranchCost(nb, total, old_p)
+ + VP8BitCost(0, update_proba);
+ const int new_cost = BranchCost(nb, total, new_p)
+ + VP8BitCost(1, update_proba)
+ + 8 * 256;
+ const int use_new_p = (old_cost > new_cost);
+ size += VP8BitCost(use_new_p, update_proba);
+ if (use_new_p) { // only use proba that seem meaningful enough.
+ proba->coeffs_[t][b][c][p] = new_p;
+ has_changed |= (new_p != old_p);
+ size += 8 * 256;
+ } else {
+ proba->coeffs_[t][b][c][p] = old_p;
+ }
+ }
+ }
+ }
+ }
+ proba->dirty_ = has_changed;
+ return size;
+}
+
+//------------------------------------------------------------------------------
+// helper functions for residuals struct VP8Residual.
+
+static void InitResidual(int first, int coeff_type,
+ VP8Encoder* const enc, VP8Residual* const res) {
+ res->coeff_type = coeff_type;
+ res->prob = enc->proba_.coeffs_[coeff_type];
+ res->stats = enc->proba_.stats_[coeff_type];
+ res->cost = enc->proba_.level_cost_[coeff_type];
+ res->first = first;
+}
+
+static void SetResidualCoeffs(const int16_t* const coeffs,
+ VP8Residual* const res) {
+ int n;
+ res->last = -1;
+ for (n = 15; n >= res->first; --n) {
+ if (coeffs[n]) {
+ res->last = n;
+ break;
+ }
+ }
+ res->coeffs = coeffs;
+}
+
+//------------------------------------------------------------------------------
+// Mode costs
+
+static int GetResidualCost(int ctx, const VP8Residual* const res) {
+ int n = res->first;
+ int p0 = res->prob[VP8EncBands[n]][ctx][0];
+ const uint16_t* t = res->cost[VP8EncBands[n]][ctx];
+ int cost;
+
+ if (res->last < 0) {
+ return VP8BitCost(0, p0);
+ }
+ cost = 0;
+ while (n <= res->last) {
+ const int v = res->coeffs[n];
+ const int b = VP8EncBands[n + 1];
+ ++n;
+ if (v == 0) {
+ // short-case for VP8LevelCost(t, 0) (note: VP8LevelFixedCosts[0] == 0):
+ cost += t[0];
+ t = res->cost[b][0];
+ continue;
+ }
+ cost += VP8BitCost(1, p0);
+ if (2u >= (unsigned int)(v + 1)) { // v = -1 or 1
+ // short-case for "VP8LevelCost(t, 1)" (256 is VP8LevelFixedCosts[1]):
+ cost += 256 + t[1];
+ p0 = res->prob[b][1][0];
+ t = res->cost[b][1];
+ } else {
+ cost += VP8LevelCost(t, abs(v));
+ p0 = res->prob[b][2][0];
+ t = res->cost[b][2];
+ }
+ }
+ if (n < 16) cost += VP8BitCost(0, p0);
+ return cost;
+}
+
+int VP8GetCostLuma4(VP8EncIterator* const it, const int16_t levels[16]) {
+ const int x = (it->i4_ & 3), y = (it->i4_ >> 2);
+ VP8Residual res;
+ VP8Encoder* const enc = it->enc_;
+ int R = 0;
+ int ctx;
+
+ InitResidual(0, 3, enc, &res);
+ ctx = it->top_nz_[x] + it->left_nz_[y];
+ SetResidualCoeffs(levels, &res);
+ R += GetResidualCost(ctx, &res);
+ return R;
+}
+
+int VP8GetCostLuma16(VP8EncIterator* const it, const VP8ModeScore* const rd) {
+ VP8Residual res;
+ VP8Encoder* const enc = it->enc_;
+ int x, y;
+ int R = 0;
+
+ VP8IteratorNzToBytes(it); // re-import the non-zero context
+
+ // DC
+ InitResidual(0, 1, enc, &res);
+ SetResidualCoeffs(rd->y_dc_levels, &res);
+ R += GetResidualCost(it->top_nz_[8] + it->left_nz_[8], &res);
+
+ // AC
+ InitResidual(1, 0, enc, &res);
+ for (y = 0; y < 4; ++y) {
+ for (x = 0; x < 4; ++x) {
+ const int ctx = it->top_nz_[x] + it->left_nz_[y];
+ SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res);
+ R += GetResidualCost(ctx, &res);
+ it->top_nz_[x] = it->left_nz_[y] = (res.last >= 0);
+ }
+ }
+ return R;
+}
+
+int VP8GetCostUV(VP8EncIterator* const it, const VP8ModeScore* const rd) {
+ VP8Residual res;
+ VP8Encoder* const enc = it->enc_;
+ int ch, x, y;
+ int R = 0;
+
+ VP8IteratorNzToBytes(it); // re-import the non-zero context
+
+ InitResidual(0, 2, enc, &res);
+ for (ch = 0; ch <= 2; ch += 2) {
+ for (y = 0; y < 2; ++y) {
+ for (x = 0; x < 2; ++x) {
+ const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y];
+ SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res);
+ R += GetResidualCost(ctx, &res);
+ it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = (res.last >= 0);
+ }
+ }
+ }
+ return R;
+}
+
+//------------------------------------------------------------------------------
+// Coefficient coding
+
+static int PutCoeffs(VP8BitWriter* const bw, int ctx, const VP8Residual* res) {
+ int n = res->first;
+ const uint8_t* p = res->prob[VP8EncBands[n]][ctx];
+ if (!VP8PutBit(bw, res->last >= 0, p[0])) {
+ return 0;
+ }
+
+ while (n < 16) {
+ const int c = res->coeffs[n++];
+ const int sign = c < 0;
+ int v = sign ? -c : c;
+ if (!VP8PutBit(bw, v != 0, p[1])) {
+ p = res->prob[VP8EncBands[n]][0];
+ continue;
+ }
+ if (!VP8PutBit(bw, v > 1, p[2])) {
+ p = res->prob[VP8EncBands[n]][1];
+ } else {
+ if (!VP8PutBit(bw, v > 4, p[3])) {
+ if (VP8PutBit(bw, v != 2, p[4]))
+ VP8PutBit(bw, v == 4, p[5]);
+ } else if (!VP8PutBit(bw, v > 10, p[6])) {
+ if (!VP8PutBit(bw, v > 6, p[7])) {
+ VP8PutBit(bw, v == 6, 159);
+ } else {
+ VP8PutBit(bw, v >= 9, 165);
+ VP8PutBit(bw, !(v & 1), 145);
+ }
+ } else {
+ int mask;
+ const uint8_t* tab;
+ if (v < 3 + (8 << 1)) { // kCat3 (3b)
+ VP8PutBit(bw, 0, p[8]);
+ VP8PutBit(bw, 0, p[9]);
+ v -= 3 + (8 << 0);
+ mask = 1 << 2;
+ tab = kCat3;
+ } else if (v < 3 + (8 << 2)) { // kCat4 (4b)
+ VP8PutBit(bw, 0, p[8]);
+ VP8PutBit(bw, 1, p[9]);
+ v -= 3 + (8 << 1);
+ mask = 1 << 3;
+ tab = kCat4;
+ } else if (v < 3 + (8 << 3)) { // kCat5 (5b)
+ VP8PutBit(bw, 1, p[8]);
+ VP8PutBit(bw, 0, p[10]);
+ v -= 3 + (8 << 2);
+ mask = 1 << 4;
+ tab = kCat5;
+ } else { // kCat6 (11b)
+ VP8PutBit(bw, 1, p[8]);
+ VP8PutBit(bw, 1, p[10]);
+ v -= 3 + (8 << 3);
+ mask = 1 << 10;
+ tab = kCat6;
+ }
+ while (mask) {
+ VP8PutBit(bw, !!(v & mask), *tab++);
+ mask >>= 1;
+ }
+ }
+ p = res->prob[VP8EncBands[n]][2];
+ }
+ VP8PutBitUniform(bw, sign);
+ if (n == 16 || !VP8PutBit(bw, n <= res->last, p[0])) {
+ return 1; // EOB
+ }
+ }
+ return 1;
+}
+
+static void CodeResiduals(VP8BitWriter* const bw,
+ VP8EncIterator* const it,
+ const VP8ModeScore* const rd) {
+ int x, y, ch;
+ VP8Residual res;
+ uint64_t pos1, pos2, pos3;
+ const int i16 = (it->mb_->type_ == 1);
+ const int segment = it->mb_->segment_;
+ VP8Encoder* const enc = it->enc_;
+
+ VP8IteratorNzToBytes(it);
+
+ pos1 = VP8BitWriterPos(bw);
+ if (i16) {
+ InitResidual(0, 1, enc, &res);
+ SetResidualCoeffs(rd->y_dc_levels, &res);
+ it->top_nz_[8] = it->left_nz_[8] =
+ PutCoeffs(bw, it->top_nz_[8] + it->left_nz_[8], &res);
+ InitResidual(1, 0, enc, &res);
+ } else {
+ InitResidual(0, 3, enc, &res);
+ }
+
+ // luma-AC
+ for (y = 0; y < 4; ++y) {
+ for (x = 0; x < 4; ++x) {
+ const int ctx = it->top_nz_[x] + it->left_nz_[y];
+ SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res);
+ it->top_nz_[x] = it->left_nz_[y] = PutCoeffs(bw, ctx, &res);
+ }
+ }
+ pos2 = VP8BitWriterPos(bw);
+
+ // U/V
+ InitResidual(0, 2, enc, &res);
+ for (ch = 0; ch <= 2; ch += 2) {
+ for (y = 0; y < 2; ++y) {
+ for (x = 0; x < 2; ++x) {
+ const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y];
+ SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res);
+ it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] =
+ PutCoeffs(bw, ctx, &res);
+ }
+ }
+ }
+ pos3 = VP8BitWriterPos(bw);
+ it->luma_bits_ = pos2 - pos1;
+ it->uv_bits_ = pos3 - pos2;
+ it->bit_count_[segment][i16] += it->luma_bits_;
+ it->bit_count_[segment][2] += it->uv_bits_;
+ VP8IteratorBytesToNz(it);
+}
+
+// Same as CodeResiduals, but doesn't actually write anything.
+// Instead, it just records the event distribution.
+static void RecordResiduals(VP8EncIterator* const it,
+ const VP8ModeScore* const rd) {
+ int x, y, ch;
+ VP8Residual res;
+ VP8Encoder* const enc = it->enc_;
+
+ VP8IteratorNzToBytes(it);
+
+ if (it->mb_->type_ == 1) { // i16x16
+ InitResidual(0, 1, enc, &res);
+ SetResidualCoeffs(rd->y_dc_levels, &res);
+ it->top_nz_[8] = it->left_nz_[8] =
+ RecordCoeffs(it->top_nz_[8] + it->left_nz_[8], &res);
+ InitResidual(1, 0, enc, &res);
+ } else {
+ InitResidual(0, 3, enc, &res);
+ }
+
+ // luma-AC
+ for (y = 0; y < 4; ++y) {
+ for (x = 0; x < 4; ++x) {
+ const int ctx = it->top_nz_[x] + it->left_nz_[y];
+ SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res);
+ it->top_nz_[x] = it->left_nz_[y] = RecordCoeffs(ctx, &res);
+ }
+ }
+
+ // U/V
+ InitResidual(0, 2, enc, &res);
+ for (ch = 0; ch <= 2; ch += 2) {
+ for (y = 0; y < 2; ++y) {
+ for (x = 0; x < 2; ++x) {
+ const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y];
+ SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res);
+ it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] =
+ RecordCoeffs(ctx, &res);
+ }
+ }
+ }
+
+ VP8IteratorBytesToNz(it);
+}
+
+//------------------------------------------------------------------------------
+// Token buffer
+
+#ifdef USE_TOKEN_BUFFER
+
+void VP8TBufferInit(VP8TBuffer* const b) {
+ b->rows_ = NULL;
+ b->tokens_ = NULL;
+ b->last_ = &b->rows_;
+ b->left_ = 0;
+ b->error_ = 0;
+}
+
+int VP8TBufferNewPage(VP8TBuffer* const b) {
+ VP8Tokens* const page = b->error_ ? NULL : (VP8Tokens*)malloc(sizeof(*page));
+ if (page == NULL) {
+ b->error_ = 1;
+ return 0;
+ }
+ *b->last_ = page;
+ b->last_ = &page->next_;
+ b->left_ = MAX_NUM_TOKEN;
+ b->tokens_ = page->tokens_;
+ return 1;
+}
+
+void VP8TBufferClear(VP8TBuffer* const b) {
+ if (b != NULL) {
+ const VP8Tokens* p = b->rows_;
+ while (p != NULL) {
+ const VP8Tokens* const next = p->next_;
+ free((void*)p);
+ p = next;
+ }
+ VP8TBufferInit(b);
+ }
+}
+
+int VP8EmitTokens(const VP8TBuffer* const b, VP8BitWriter* const bw,
+ const uint8_t* const probas) {
+ VP8Tokens* p = b->rows_;
+ if (b->error_) return 0;
+ while (p != NULL) {
+ const int N = (p->next_ == NULL) ? b->left_ : 0;
+ int n = MAX_NUM_TOKEN;
+ while (n-- > N) {
+ VP8PutBit(bw, (p->tokens_[n] >> 15) & 1, probas[p->tokens_[n] & 0x7fff]);
+ }
+ p = p->next_;
+ }
+ return 1;
+}
+
+#define TOKEN_ID(b, ctx, p) ((p) + NUM_PROBAS * ((ctx) + (b) * NUM_CTX))
+
+static int RecordCoeffTokens(int ctx, const VP8Residual* const res,
+ VP8TBuffer* tokens) {
+ int n = res->first;
+ int b = VP8EncBands[n];
+ if (!VP8AddToken(tokens, res->last >= 0, TOKEN_ID(b, ctx, 0))) {
+ return 0;
+ }
+
+ while (n < 16) {
+ const int c = res->coeffs[n++];
+ const int sign = c < 0;
+ int v = sign ? -c : c;
+ const int base_id = TOKEN_ID(b, ctx, 0);
+ if (!VP8AddToken(tokens, v != 0, base_id + 1)) {
+ b = VP8EncBands[n];
+ ctx = 0;
+ continue;
+ }
+ if (!VP8AddToken(tokens, v > 1, base_id + 2)) {
+ b = VP8EncBands[n];
+ ctx = 1;
+ } else {
+ if (!VP8AddToken(tokens, v > 4, base_id + 3)) {
+ if (VP8AddToken(tokens, v != 2, base_id + 4))
+ VP8AddToken(tokens, v == 4, base_id + 5);
+ } else if (!VP8AddToken(tokens, v > 10, base_id + 6)) {
+ if (!VP8AddToken(tokens, v > 6, base_id + 7)) {
+// VP8AddToken(tokens, v == 6, 159);
+ } else {
+// VP8AddToken(tokens, v >= 9, 165);
+// VP8AddToken(tokens, !(v & 1), 145);
+ }
+ } else {
+ int mask;
+ const uint8_t* tab;
+ if (v < 3 + (8 << 1)) { // kCat3 (3b)
+ VP8AddToken(tokens, 0, base_id + 8);
+ VP8AddToken(tokens, 0, base_id + 9);
+ v -= 3 + (8 << 0);
+ mask = 1 << 2;
+ tab = kCat3;
+ } else if (v < 3 + (8 << 2)) { // kCat4 (4b)
+ VP8AddToken(tokens, 0, base_id + 8);
+ VP8AddToken(tokens, 1, base_id + 9);
+ v -= 3 + (8 << 1);
+ mask = 1 << 3;
+ tab = kCat4;
+ } else if (v < 3 + (8 << 3)) { // kCat5 (5b)
+ VP8AddToken(tokens, 1, base_id + 8);
+ VP8AddToken(tokens, 0, base_id + 10);
+ v -= 3 + (8 << 2);
+ mask = 1 << 4;
+ tab = kCat5;
+ } else { // kCat6 (11b)
+ VP8AddToken(tokens, 1, base_id + 8);
+ VP8AddToken(tokens, 1, base_id + 10);
+ v -= 3 + (8 << 3);
+ mask = 1 << 10;
+ tab = kCat6;
+ }
+ while (mask) {
+ // VP8AddToken(tokens, !!(v & mask), *tab++);
+ mask >>= 1;
+ }
+ }
+ ctx = 2;
+ }
+ b = VP8EncBands[n];
+ // VP8PutBitUniform(bw, sign);
+ if (n == 16 || !VP8AddToken(tokens, n <= res->last, TOKEN_ID(b, ctx, 0))) {
+ return 1; // EOB
+ }
+ }
+ return 1;
+}
+
+static void RecordTokens(VP8EncIterator* const it,
+ const VP8ModeScore* const rd, VP8TBuffer tokens[2]) {
+ int x, y, ch;
+ VP8Residual res;
+ VP8Encoder* const enc = it->enc_;
+
+ VP8IteratorNzToBytes(it);
+ if (it->mb_->type_ == 1) { // i16x16
+ InitResidual(0, 1, enc, &res);
+ SetResidualCoeffs(rd->y_dc_levels, &res);
+// TODO(skal): FIX -> it->top_nz_[8] = it->left_nz_[8] =
+ RecordCoeffTokens(it->top_nz_[8] + it->left_nz_[8], &res, &tokens[0]);
+ InitResidual(1, 0, enc, &res);
+ } else {
+ InitResidual(0, 3, enc, &res);
+ }
+
+ // luma-AC
+ for (y = 0; y < 4; ++y) {
+ for (x = 0; x < 4; ++x) {
+ const int ctx = it->top_nz_[x] + it->left_nz_[y];
+ SetResidualCoeffs(rd->y_ac_levels[x + y * 4], &res);
+ it->top_nz_[x] = it->left_nz_[y] =
+ RecordCoeffTokens(ctx, &res, &tokens[0]);
+ }
+ }
+
+ // U/V
+ InitResidual(0, 2, enc, &res);
+ for (ch = 0; ch <= 2; ch += 2) {
+ for (y = 0; y < 2; ++y) {
+ for (x = 0; x < 2; ++x) {
+ const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y];
+ SetResidualCoeffs(rd->uv_levels[ch * 2 + x + y * 2], &res);
+ it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] =
+ RecordCoeffTokens(ctx, &res, &tokens[1]);
+ }
+ }
+ }
+}
+
+#endif // USE_TOKEN_BUFFER
+
+//------------------------------------------------------------------------------
+// ExtraInfo map / Debug function
+
+#if SEGMENT_VISU
+static void SetBlock(uint8_t* p, int value, int size) {
+ int y;
+ for (y = 0; y < size; ++y) {
+ memset(p, value, size);
+ p += BPS;
+ }
+}
+#endif
+
+static void ResetSSE(VP8Encoder* const enc) {
+ memset(enc->sse_, 0, sizeof(enc->sse_));
+ enc->sse_count_ = 0;
+}
+
+static void StoreSSE(const VP8EncIterator* const it) {
+ VP8Encoder* const enc = it->enc_;
+ const uint8_t* const in = it->yuv_in_;
+ const uint8_t* const out = it->yuv_out_;
+ // Note: not totally accurate at boundary. And doesn't include in-loop filter.
+ enc->sse_[0] += VP8SSE16x16(in + Y_OFF, out + Y_OFF);
+ enc->sse_[1] += VP8SSE8x8(in + U_OFF, out + U_OFF);
+ enc->sse_[2] += VP8SSE8x8(in + V_OFF, out + V_OFF);
+ enc->sse_count_ += 16 * 16;
+}
+
+static void StoreSideInfo(const VP8EncIterator* const it) {
+ VP8Encoder* const enc = it->enc_;
+ const VP8MBInfo* const mb = it->mb_;
+ WebPPicture* const pic = enc->pic_;
+
+ if (pic->stats != NULL) {
+ StoreSSE(it);
+ enc->block_count_[0] += (mb->type_ == 0);
+ enc->block_count_[1] += (mb->type_ == 1);
+ enc->block_count_[2] += (mb->skip_ != 0);
+ }
+
+ if (pic->extra_info != NULL) {
+ uint8_t* const info = &pic->extra_info[it->x_ + it->y_ * enc->mb_w_];
+ switch (pic->extra_info_type) {
+ case 1: *info = mb->type_; break;
+ case 2: *info = mb->segment_; break;
+ case 3: *info = enc->dqm_[mb->segment_].quant_; break;
+ case 4: *info = (mb->type_ == 1) ? it->preds_[0] : 0xff; break;
+ case 5: *info = mb->uv_mode_; break;
+ case 6: {
+ const int b = (int)((it->luma_bits_ + it->uv_bits_ + 7) >> 3);
+ *info = (b > 255) ? 255 : b; break;
+ }
+ default: *info = 0; break;
+ };
+ }
+#if SEGMENT_VISU // visualize segments and prediction modes
+ SetBlock(it->yuv_out_ + Y_OFF, mb->segment_ * 64, 16);
+ SetBlock(it->yuv_out_ + U_OFF, it->preds_[0] * 64, 8);
+ SetBlock(it->yuv_out_ + V_OFF, mb->uv_mode_ * 64, 8);
+#endif
+}
+
+//------------------------------------------------------------------------------
+// Main loops
+//
+// VP8EncLoop(): does the final bitstream coding.
+
+static void ResetAfterSkip(VP8EncIterator* const it) {
+ if (it->mb_->type_ == 1) {
+ *it->nz_ = 0; // reset all predictors
+ it->left_nz_[8] = 0;
+ } else {
+ *it->nz_ &= (1 << 24); // preserve the dc_nz bit
+ }
+}
+
+int VP8EncLoop(VP8Encoder* const enc) {
+ int i, s, p;
+ int ok = 1;
+ VP8EncIterator it;
+ VP8ModeScore info;
+ const int dont_use_skip = !enc->proba_.use_skip_proba_;
+ const int rd_opt = enc->rd_opt_level_;
+ const int kAverageBytesPerMB = 5; // TODO: have a kTable[quality/10]
+ const int bytes_per_parts =
+ enc->mb_w_ * enc->mb_h_ * kAverageBytesPerMB / enc->num_parts_;
+
+ // Initialize the bit-writers
+ for (p = 0; p < enc->num_parts_; ++p) {
+ VP8BitWriterInit(enc->parts_ + p, bytes_per_parts);
+ }
+
+ ResetStats(enc);
+ ResetSSE(enc);
+
+ VP8IteratorInit(enc, &it);
+ VP8InitFilter(&it);
+ do {
+ VP8IteratorImport(&it);
+ // Warning! order is important: first call VP8Decimate() and
+ // *then* decide how to code the skip decision if there's one.
+ if (!VP8Decimate(&it, &info, rd_opt) || dont_use_skip) {
+ CodeResiduals(it.bw_, &it, &info);
+ } else { // reset predictors after a skip
+ ResetAfterSkip(&it);
+ }
+#ifdef WEBP_EXPERIMENTAL_FEATURES
+ if (enc->use_layer_) {
+ VP8EncCodeLayerBlock(&it);
+ }
+#endif
+ StoreSideInfo(&it);
+ VP8StoreFilterStats(&it);
+ VP8IteratorExport(&it);
+ ok = VP8IteratorProgress(&it, 20);
+ } while (ok && VP8IteratorNext(&it, it.yuv_out_));
+
+ if (ok) { // Finalize the partitions, check for extra errors.
+ for (p = 0; p < enc->num_parts_; ++p) {
+ VP8BitWriterFinish(enc->parts_ + p);
+ ok &= !enc->parts_[p].error_;
+ }
+ }
+
+ if (ok) { // All good. Finish up.
+ if (enc->pic_->stats) { // finalize byte counters...
+ for (i = 0; i <= 2; ++i) {
+ for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
+ enc->residual_bytes_[i][s] = (int)((it.bit_count_[s][i] + 7) >> 3);
+ }
+ }
+ }
+ VP8AdjustFilterStrength(&it); // ...and store filter stats.
+ } else {
+ // Something bad happened -> need to do some memory cleanup.
+ VP8EncFreeBitWriters(enc);
+ }
+
+ return ok;
+}
+
+//------------------------------------------------------------------------------
+// VP8StatLoop(): only collect statistics (number of skips, token usage, ...)
+// This is used for deciding optimal probabilities. It also
+// modifies the quantizer value if some target (size, PNSR)
+// was specified.
+
+#define kHeaderSizeEstimate (15 + 20 + 10) // TODO: fix better
+
+static int OneStatPass(VP8Encoder* const enc, float q, int rd_opt, int nb_mbs,
+ float* const PSNR, int percent_delta) {
+ VP8EncIterator it;
+ uint64_t size = 0;
+ uint64_t distortion = 0;
+ const uint64_t pixel_count = nb_mbs * 384;
+
+ // Make sure the quality parameter is inside valid bounds
+ if (q < 0.) {
+ q = 0;
+ } else if (q > 100.) {
+ q = 100;
+ }
+
+ VP8SetSegmentParams(enc, q); // setup segment quantizations and filters
+
+ ResetStats(enc);
+ ResetTokenStats(enc);
+
+ VP8IteratorInit(enc, &it);
+ do {
+ VP8ModeScore info;
+ VP8IteratorImport(&it);
+ if (VP8Decimate(&it, &info, rd_opt)) {
+ // Just record the number of skips and act like skip_proba is not used.
+ enc->proba_.nb_skip_++;
+ }
+ RecordResiduals(&it, &info);
+ size += info.R;
+ distortion += info.D;
+ if (percent_delta && !VP8IteratorProgress(&it, percent_delta))
+ return 0;
+ } while (VP8IteratorNext(&it, it.yuv_out_) && --nb_mbs > 0);
+ size += FinalizeSkipProba(enc);
+ size += FinalizeTokenProbas(enc);
+ size += enc->segment_hdr_.size_;
+ size = ((size + 1024) >> 11) + kHeaderSizeEstimate;
+
+ if (PSNR) {
+ *PSNR = (float)(10.* log10(255. * 255. * pixel_count / distortion));
+ }
+ return (int)size;
+}
+
+// successive refinement increments.
+static const int dqs[] = { 20, 15, 10, 8, 6, 4, 2, 1, 0 };
+
+int VP8StatLoop(VP8Encoder* const enc) {
+ const int do_search =
+ (enc->config_->target_size > 0 || enc->config_->target_PSNR > 0);
+ const int fast_probe = (enc->method_ < 2 && !do_search);
+ float q = enc->config_->quality;
+ const int max_passes = enc->config_->pass;
+ const int task_percent = 20;
+ const int percent_per_pass = (task_percent + max_passes / 2) / max_passes;
+ const int final_percent = enc->percent_ + task_percent;
+ int pass;
+ int nb_mbs;
+
+ // Fast mode: quick analysis pass over few mbs. Better than nothing.
+ nb_mbs = enc->mb_w_ * enc->mb_h_;
+ if (fast_probe && nb_mbs > 100) nb_mbs = 100;
+
+ // No target size: just do several pass without changing 'q'
+ if (!do_search) {
+ for (pass = 0; pass < max_passes; ++pass) {
+ const int rd_opt = (enc->method_ > 2);
+ if (!OneStatPass(enc, q, rd_opt, nb_mbs, NULL, percent_per_pass)) {
+ return 0;
+ }
+ }
+ } else {
+ // binary search for a size close to target
+ for (pass = 0; pass < max_passes && (dqs[pass] > 0); ++pass) {
+ const int rd_opt = 1;
+ float PSNR;
+ int criterion;
+ const int size = OneStatPass(enc, q, rd_opt, nb_mbs, &PSNR,
+ percent_per_pass);
+#if DEBUG_SEARCH
+ printf("#%d size=%d PSNR=%.2f q=%.2f\n", pass, size, PSNR, q);
+#endif
+ if (!size) return 0;
+ if (enc->config_->target_PSNR > 0) {
+ criterion = (PSNR < enc->config_->target_PSNR);
+ } else {
+ criterion = (size < enc->config_->target_size);
+ }
+ // dichotomize
+ if (criterion) {
+ q += dqs[pass];
+ } else {
+ q -= dqs[pass];
+ }
+ }
+ }
+ return WebPReportProgress(enc->pic_, final_percent, &enc->percent_);
+}
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/enc/histogram.c b/drivers/webpold/enc/histogram.c
new file mode 100644
index 0000000000..ca838e064d
--- /dev/null
+++ b/drivers/webpold/enc/histogram.c
@@ -0,0 +1,406 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Author: Jyrki Alakuijala (jyrki@google.com)
+//
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <math.h>
+#include <stdio.h>
+
+#include "./backward_references.h"
+#include "./histogram.h"
+#include "../dsp/lossless.h"
+#include "../utils/utils.h"
+
+static void HistogramClear(VP8LHistogram* const p) {
+ memset(p->literal_, 0, sizeof(p->literal_));
+ memset(p->red_, 0, sizeof(p->red_));
+ memset(p->blue_, 0, sizeof(p->blue_));
+ memset(p->alpha_, 0, sizeof(p->alpha_));
+ memset(p->distance_, 0, sizeof(p->distance_));
+ p->bit_cost_ = 0;
+}
+
+void VP8LHistogramStoreRefs(const VP8LBackwardRefs* const refs,
+ VP8LHistogram* const histo) {
+ int i;
+ for (i = 0; i < refs->size; ++i) {
+ VP8LHistogramAddSinglePixOrCopy(histo, &refs->refs[i]);
+ }
+}
+
+void VP8LHistogramCreate(VP8LHistogram* const p,
+ const VP8LBackwardRefs* const refs,
+ int palette_code_bits) {
+ if (palette_code_bits >= 0) {
+ p->palette_code_bits_ = palette_code_bits;
+ }
+ HistogramClear(p);
+ VP8LHistogramStoreRefs(refs, p);
+}
+
+void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits) {
+ p->palette_code_bits_ = palette_code_bits;
+ HistogramClear(p);
+}
+
+VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits) {
+ int i;
+ VP8LHistogramSet* set;
+ VP8LHistogram* bulk;
+ const uint64_t total_size = (uint64_t)sizeof(*set)
+ + size * sizeof(*set->histograms)
+ + size * sizeof(**set->histograms);
+ uint8_t* memory = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*memory));
+ if (memory == NULL) return NULL;
+
+ set = (VP8LHistogramSet*)memory;
+ memory += sizeof(*set);
+ set->histograms = (VP8LHistogram**)memory;
+ memory += size * sizeof(*set->histograms);
+ bulk = (VP8LHistogram*)memory;
+ set->max_size = size;
+ set->size = size;
+ for (i = 0; i < size; ++i) {
+ set->histograms[i] = bulk + i;
+ VP8LHistogramInit(set->histograms[i], cache_bits);
+ }
+ return set;
+}
+
+// -----------------------------------------------------------------------------
+
+void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo,
+ const PixOrCopy* const v) {
+ if (PixOrCopyIsLiteral(v)) {
+ ++histo->alpha_[PixOrCopyLiteral(v, 3)];
+ ++histo->red_[PixOrCopyLiteral(v, 2)];
+ ++histo->literal_[PixOrCopyLiteral(v, 1)];
+ ++histo->blue_[PixOrCopyLiteral(v, 0)];
+ } else if (PixOrCopyIsCacheIdx(v)) {
+ int literal_ix = 256 + NUM_LENGTH_CODES + PixOrCopyCacheIdx(v);
+ ++histo->literal_[literal_ix];
+ } else {
+ int code, extra_bits_count, extra_bits_value;
+ PrefixEncode(PixOrCopyLength(v),
+ &code, &extra_bits_count, &extra_bits_value);
+ ++histo->literal_[256 + code];
+ PrefixEncode(PixOrCopyDistance(v),
+ &code, &extra_bits_count, &extra_bits_value);
+ ++histo->distance_[code];
+ }
+}
+
+
+
+static double BitsEntropy(const int* const array, int n) {
+ double retval = 0.;
+ int sum = 0;
+ int nonzeros = 0;
+ int max_val = 0;
+ int i;
+ double mix;
+ for (i = 0; i < n; ++i) {
+ if (array[i] != 0) {
+ sum += array[i];
+ ++nonzeros;
+ retval -= VP8LFastSLog2(array[i]);
+ if (max_val < array[i]) {
+ max_val = array[i];
+ }
+ }
+ }
+ retval += VP8LFastSLog2(sum);
+
+ if (nonzeros < 5) {
+ if (nonzeros <= 1) {
+ return 0;
+ }
+ // Two symbols, they will be 0 and 1 in a Huffman code.
+ // Let's mix in a bit of entropy to favor good clustering when
+ // distributions of these are combined.
+ if (nonzeros == 2) {
+ return 0.99 * sum + 0.01 * retval;
+ }
+ // No matter what the entropy says, we cannot be better than min_limit
+ // with Huffman coding. I am mixing a bit of entropy into the
+ // min_limit since it produces much better (~0.5 %) compression results
+ // perhaps because of better entropy clustering.
+ if (nonzeros == 3) {
+ mix = 0.95;
+ } else {
+ mix = 0.7; // nonzeros == 4.
+ }
+ } else {
+ mix = 0.627;
+ }
+
+ {
+ double min_limit = 2 * sum - max_val;
+ min_limit = mix * min_limit + (1.0 - mix) * retval;
+ return (retval < min_limit) ? min_limit : retval;
+ }
+}
+
+double VP8LHistogramEstimateBitsBulk(const VP8LHistogram* const p) {
+ double retval = BitsEntropy(&p->literal_[0], VP8LHistogramNumCodes(p))
+ + BitsEntropy(&p->red_[0], 256)
+ + BitsEntropy(&p->blue_[0], 256)
+ + BitsEntropy(&p->alpha_[0], 256)
+ + BitsEntropy(&p->distance_[0], NUM_DISTANCE_CODES);
+ // Compute the extra bits cost.
+ int i;
+ for (i = 2; i < NUM_LENGTH_CODES - 2; ++i) {
+ retval +=
+ (i >> 1) * p->literal_[256 + i + 2];
+ }
+ for (i = 2; i < NUM_DISTANCE_CODES - 2; ++i) {
+ retval += (i >> 1) * p->distance_[i + 2];
+ }
+ return retval;
+}
+
+
+// Returns the cost encode the rle-encoded entropy code.
+// The constants in this function are experimental.
+static double HuffmanCost(const int* const population, int length) {
+ // Small bias because Huffman code length is typically not stored in
+ // full length.
+ static const int kHuffmanCodeOfHuffmanCodeSize = CODE_LENGTH_CODES * 3;
+ static const double kSmallBias = 9.1;
+ double retval = kHuffmanCodeOfHuffmanCodeSize - kSmallBias;
+ int streak = 0;
+ int i = 0;
+ for (; i < length - 1; ++i) {
+ ++streak;
+ if (population[i] == population[i + 1]) {
+ continue;
+ }
+ last_streak_hack:
+ // population[i] points now to the symbol in the streak of same values.
+ if (streak > 3) {
+ if (population[i] == 0) {
+ retval += 1.5625 + 0.234375 * streak;
+ } else {
+ retval += 2.578125 + 0.703125 * streak;
+ }
+ } else {
+ if (population[i] == 0) {
+ retval += 1.796875 * streak;
+ } else {
+ retval += 3.28125 * streak;
+ }
+ }
+ streak = 0;
+ }
+ if (i == length - 1) {
+ ++streak;
+ goto last_streak_hack;
+ }
+ return retval;
+}
+
+// Estimates the Huffman dictionary + other block overhead size.
+static double HistogramEstimateBitsHeader(const VP8LHistogram* const p) {
+ return HuffmanCost(&p->alpha_[0], 256) +
+ HuffmanCost(&p->red_[0], 256) +
+ HuffmanCost(&p->literal_[0], VP8LHistogramNumCodes(p)) +
+ HuffmanCost(&p->blue_[0], 256) +
+ HuffmanCost(&p->distance_[0], NUM_DISTANCE_CODES);
+}
+
+double VP8LHistogramEstimateBits(const VP8LHistogram* const p) {
+ return HistogramEstimateBitsHeader(p) + VP8LHistogramEstimateBitsBulk(p);
+}
+
+static void HistogramBuildImage(int xsize, int histo_bits,
+ const VP8LBackwardRefs* const backward_refs,
+ VP8LHistogramSet* const image) {
+ int i;
+ int x = 0, y = 0;
+ const int histo_xsize = VP8LSubSampleSize(xsize, histo_bits);
+ VP8LHistogram** const histograms = image->histograms;
+ assert(histo_bits > 0);
+ for (i = 0; i < backward_refs->size; ++i) {
+ const PixOrCopy* const v = &backward_refs->refs[i];
+ const int ix = (y >> histo_bits) * histo_xsize + (x >> histo_bits);
+ VP8LHistogramAddSinglePixOrCopy(histograms[ix], v);
+ x += PixOrCopyLength(v);
+ while (x >= xsize) {
+ x -= xsize;
+ ++y;
+ }
+ }
+}
+
+static uint32_t MyRand(uint32_t *seed) {
+ *seed *= 16807U;
+ if (*seed == 0) {
+ *seed = 1;
+ }
+ return *seed;
+}
+
+static int HistogramCombine(const VP8LHistogramSet* const in,
+ VP8LHistogramSet* const out, int num_pairs) {
+ int ok = 0;
+ int i, iter;
+ uint32_t seed = 0;
+ int tries_with_no_success = 0;
+ const int min_cluster_size = 2;
+ int out_size = in->size;
+ const int outer_iters = in->size * 3;
+ VP8LHistogram* const histos = (VP8LHistogram*)malloc(2 * sizeof(*histos));
+ VP8LHistogram* cur_combo = histos + 0; // trial merged histogram
+ VP8LHistogram* best_combo = histos + 1; // best merged histogram so far
+ if (histos == NULL) goto End;
+
+ // Copy histograms from in[] to out[].
+ assert(in->size <= out->size);
+ for (i = 0; i < in->size; ++i) {
+ in->histograms[i]->bit_cost_ = VP8LHistogramEstimateBits(in->histograms[i]);
+ *out->histograms[i] = *in->histograms[i];
+ }
+
+ // Collapse similar histograms in 'out'.
+ for (iter = 0; iter < outer_iters && out_size >= min_cluster_size; ++iter) {
+ // We pick the best pair to be combined out of 'inner_iters' pairs.
+ double best_cost_diff = 0.;
+ int best_idx1 = 0, best_idx2 = 1;
+ int j;
+ seed += iter;
+ for (j = 0; j < num_pairs; ++j) {
+ double curr_cost_diff;
+ // Choose two histograms at random and try to combine them.
+ const uint32_t idx1 = MyRand(&seed) % out_size;
+ const uint32_t tmp = ((j & 7) + 1) % (out_size - 1);
+ const uint32_t diff = (tmp < 3) ? tmp : MyRand(&seed) % (out_size - 1);
+ const uint32_t idx2 = (idx1 + diff + 1) % out_size;
+ if (idx1 == idx2) {
+ continue;
+ }
+ *cur_combo = *out->histograms[idx1];
+ VP8LHistogramAdd(cur_combo, out->histograms[idx2]);
+ cur_combo->bit_cost_ = VP8LHistogramEstimateBits(cur_combo);
+ // Calculate cost reduction on combining.
+ curr_cost_diff = cur_combo->bit_cost_
+ - out->histograms[idx1]->bit_cost_
+ - out->histograms[idx2]->bit_cost_;
+ if (best_cost_diff > curr_cost_diff) { // found a better pair?
+ { // swap cur/best combo histograms
+ VP8LHistogram* const tmp_histo = cur_combo;
+ cur_combo = best_combo;
+ best_combo = tmp_histo;
+ }
+ best_cost_diff = curr_cost_diff;
+ best_idx1 = idx1;
+ best_idx2 = idx2;
+ }
+ }
+
+ if (best_cost_diff < 0.0) {
+ *out->histograms[best_idx1] = *best_combo;
+ // swap best_idx2 slot with last one (which is now unused)
+ --out_size;
+ if (best_idx2 != out_size) {
+ out->histograms[best_idx2] = out->histograms[out_size];
+ out->histograms[out_size] = NULL; // just for sanity check.
+ }
+ tries_with_no_success = 0;
+ }
+ if (++tries_with_no_success >= 50) {
+ break;
+ }
+ }
+ out->size = out_size;
+ ok = 1;
+
+ End:
+ free(histos);
+ return ok;
+}
+
+// -----------------------------------------------------------------------------
+// Histogram refinement
+
+// What is the bit cost of moving square_histogram from
+// cur_symbol to candidate_symbol.
+// TODO(skal): we don't really need to copy the histogram and Add(). Instead
+// we just need VP8LDualHistogramEstimateBits(A, B) estimation function.
+static double HistogramDistance(const VP8LHistogram* const square_histogram,
+ const VP8LHistogram* const candidate) {
+ const double previous_bit_cost = candidate->bit_cost_;
+ double new_bit_cost;
+ VP8LHistogram modified_histo;
+ modified_histo = *candidate;
+ VP8LHistogramAdd(&modified_histo, square_histogram);
+ new_bit_cost = VP8LHistogramEstimateBits(&modified_histo);
+
+ return new_bit_cost - previous_bit_cost;
+}
+
+// Find the best 'out' histogram for each of the 'in' histograms.
+// Note: we assume that out[]->bit_cost_ is already up-to-date.
+static void HistogramRemap(const VP8LHistogramSet* const in,
+ const VP8LHistogramSet* const out,
+ uint16_t* const symbols) {
+ int i;
+ for (i = 0; i < in->size; ++i) {
+ int best_out = 0;
+ double best_bits = HistogramDistance(in->histograms[i], out->histograms[0]);
+ int k;
+ for (k = 1; k < out->size; ++k) {
+ const double cur_bits =
+ HistogramDistance(in->histograms[i], out->histograms[k]);
+ if (cur_bits < best_bits) {
+ best_bits = cur_bits;
+ best_out = k;
+ }
+ }
+ symbols[i] = best_out;
+ }
+
+ // Recompute each out based on raw and symbols.
+ for (i = 0; i < out->size; ++i) {
+ HistogramClear(out->histograms[i]);
+ }
+ for (i = 0; i < in->size; ++i) {
+ VP8LHistogramAdd(out->histograms[symbols[i]], in->histograms[i]);
+ }
+}
+
+int VP8LGetHistoImageSymbols(int xsize, int ysize,
+ const VP8LBackwardRefs* const refs,
+ int quality, int histo_bits, int cache_bits,
+ VP8LHistogramSet* const image_in,
+ uint16_t* const histogram_symbols) {
+ int ok = 0;
+ const int histo_xsize = histo_bits ? VP8LSubSampleSize(xsize, histo_bits) : 1;
+ const int histo_ysize = histo_bits ? VP8LSubSampleSize(ysize, histo_bits) : 1;
+ const int num_histo_pairs = 10 + quality / 2; // For HistogramCombine().
+ const int histo_image_raw_size = histo_xsize * histo_ysize;
+ VP8LHistogramSet* const image_out =
+ VP8LAllocateHistogramSet(histo_image_raw_size, cache_bits);
+ if (image_out == NULL) return 0;
+
+ // Build histogram image.
+ HistogramBuildImage(xsize, histo_bits, refs, image_out);
+ // Collapse similar histograms.
+ if (!HistogramCombine(image_out, image_in, num_histo_pairs)) {
+ goto Error;
+ }
+ // Find the optimal map from original histograms to the final ones.
+ HistogramRemap(image_out, image_in, histogram_symbols);
+ ok = 1;
+
+Error:
+ free(image_out);
+ return ok;
+}
diff --git a/drivers/webpold/enc/histogram.h b/drivers/webpold/enc/histogram.h
new file mode 100644
index 0000000000..5b5de25539
--- /dev/null
+++ b/drivers/webpold/enc/histogram.h
@@ -0,0 +1,115 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Author: Jyrki Alakuijala (jyrki@google.com)
+//
+// Models the histograms of literal and distance codes.
+
+#ifndef WEBP_ENC_HISTOGRAM_H_
+#define WEBP_ENC_HISTOGRAM_H_
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "./backward_references.h"
+#include "../format_constants.h"
+#include "../types.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+// A simple container for histograms of data.
+typedef struct {
+ // literal_ contains green literal, palette-code and
+ // copy-length-prefix histogram
+ int literal_[PIX_OR_COPY_CODES_MAX];
+ int red_[256];
+ int blue_[256];
+ int alpha_[256];
+ // Backward reference prefix-code histogram.
+ int distance_[NUM_DISTANCE_CODES];
+ int palette_code_bits_;
+ double bit_cost_; // cached value of VP8LHistogramEstimateBits(this)
+} VP8LHistogram;
+
+// Collection of histograms with fixed capacity, allocated as one
+// big memory chunk. Can be destroyed by simply calling 'free()'.
+typedef struct {
+ int size; // number of slots currently in use
+ int max_size; // maximum capacity
+ VP8LHistogram** histograms;
+} VP8LHistogramSet;
+
+// Create the histogram.
+//
+// The input data is the PixOrCopy data, which models the literals, stop
+// codes and backward references (both distances and lengths). Also: if
+// palette_code_bits is >= 0, initialize the histogram with this value.
+void VP8LHistogramCreate(VP8LHistogram* const p,
+ const VP8LBackwardRefs* const refs,
+ int palette_code_bits);
+
+// Set the palette_code_bits and reset the stats.
+void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits);
+
+// Collect all the references into a histogram (without reset)
+void VP8LHistogramStoreRefs(const VP8LBackwardRefs* const refs,
+ VP8LHistogram* const histo);
+
+// Allocate an array of pointer to histograms, allocated and initialized
+// using 'cache_bits'. Return NULL in case of memory error.
+VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits);
+
+// Accumulate a token 'v' into a histogram.
+void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo,
+ const PixOrCopy* const v);
+
+// Estimate how many bits the combined entropy of literals and distance
+// approximately maps to.
+double VP8LHistogramEstimateBits(const VP8LHistogram* const p);
+
+// This function estimates the cost in bits excluding the bits needed to
+// represent the entropy code itself.
+double VP8LHistogramEstimateBitsBulk(const VP8LHistogram* const p);
+
+static WEBP_INLINE void VP8LHistogramAdd(VP8LHistogram* const p,
+ const VP8LHistogram* const a) {
+ int i;
+ for (i = 0; i < PIX_OR_COPY_CODES_MAX; ++i) {
+ p->literal_[i] += a->literal_[i];
+ }
+ for (i = 0; i < NUM_DISTANCE_CODES; ++i) {
+ p->distance_[i] += a->distance_[i];
+ }
+ for (i = 0; i < 256; ++i) {
+ p->red_[i] += a->red_[i];
+ p->blue_[i] += a->blue_[i];
+ p->alpha_[i] += a->alpha_[i];
+ }
+}
+
+static WEBP_INLINE int VP8LHistogramNumCodes(const VP8LHistogram* const p) {
+ return 256 + NUM_LENGTH_CODES +
+ ((p->palette_code_bits_ > 0) ? (1 << p->palette_code_bits_) : 0);
+}
+
+// Builds the histogram image.
+int VP8LGetHistoImageSymbols(int xsize, int ysize,
+ const VP8LBackwardRefs* const refs,
+ int quality, int histogram_bits, int cache_bits,
+ VP8LHistogramSet* const image_in,
+ uint16_t* const histogram_symbols);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif // WEBP_ENC_HISTOGRAM_H_
diff --git a/drivers/webpold/enc/iterator.c b/drivers/webpold/enc/iterator.c
new file mode 100644
index 0000000000..86e473bcf0
--- /dev/null
+++ b/drivers/webpold/enc/iterator.c
@@ -0,0 +1,422 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// VP8Iterator: block iterator
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <string.h>
+
+#include "./vp8enci.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// VP8Iterator
+//------------------------------------------------------------------------------
+
+static void InitLeft(VP8EncIterator* const it) {
+ const VP8Encoder* const enc = it->enc_;
+ enc->y_left_[-1] = enc->u_left_[-1] = enc->v_left_[-1] =
+ (it->y_ > 0) ? 129 : 127;
+ memset(enc->y_left_, 129, 16);
+ memset(enc->u_left_, 129, 8);
+ memset(enc->v_left_, 129, 8);
+ it->left_nz_[8] = 0;
+}
+
+static void InitTop(VP8EncIterator* const it) {
+ const VP8Encoder* const enc = it->enc_;
+ const size_t top_size = enc->mb_w_ * 16;
+ memset(enc->y_top_, 127, 2 * top_size);
+ memset(enc->nz_, 0, enc->mb_w_ * sizeof(*enc->nz_));
+}
+
+void VP8IteratorReset(VP8EncIterator* const it) {
+ VP8Encoder* const enc = it->enc_;
+ it->x_ = 0;
+ it->y_ = 0;
+ it->y_offset_ = 0;
+ it->uv_offset_ = 0;
+ it->mb_ = enc->mb_info_;
+ it->preds_ = enc->preds_;
+ it->nz_ = enc->nz_;
+ it->bw_ = &enc->parts_[0];
+ it->done_ = enc->mb_w_* enc->mb_h_;
+ InitTop(it);
+ InitLeft(it);
+ memset(it->bit_count_, 0, sizeof(it->bit_count_));
+ it->do_trellis_ = 0;
+}
+
+void VP8IteratorInit(VP8Encoder* const enc, VP8EncIterator* const it) {
+ it->enc_ = enc;
+ it->y_stride_ = enc->pic_->y_stride;
+ it->uv_stride_ = enc->pic_->uv_stride;
+ // TODO(later): for multithreading, these should be owned by 'it'.
+ it->yuv_in_ = enc->yuv_in_;
+ it->yuv_out_ = enc->yuv_out_;
+ it->yuv_out2_ = enc->yuv_out2_;
+ it->yuv_p_ = enc->yuv_p_;
+ it->lf_stats_ = enc->lf_stats_;
+ it->percent0_ = enc->percent_;
+ VP8IteratorReset(it);
+}
+
+int VP8IteratorProgress(const VP8EncIterator* const it, int delta) {
+ VP8Encoder* const enc = it->enc_;
+ if (delta && enc->pic_->progress_hook) {
+ const int percent = (enc->mb_h_ <= 1)
+ ? it->percent0_
+ : it->percent0_ + delta * it->y_ / (enc->mb_h_ - 1);
+ return WebPReportProgress(enc->pic_, percent, &enc->percent_);
+ }
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+// Import the source samples into the cache. Takes care of replicating
+// boundary pixels if necessary.
+
+static void ImportBlock(const uint8_t* src, int src_stride,
+ uint8_t* dst, int w, int h, int size) {
+ int i;
+ for (i = 0; i < h; ++i) {
+ memcpy(dst, src, w);
+ if (w < size) {
+ memset(dst + w, dst[w - 1], size - w);
+ }
+ dst += BPS;
+ src += src_stride;
+ }
+ for (i = h; i < size; ++i) {
+ memcpy(dst, dst - BPS, size);
+ dst += BPS;
+ }
+}
+
+void VP8IteratorImport(const VP8EncIterator* const it) {
+ const VP8Encoder* const enc = it->enc_;
+ const int x = it->x_, y = it->y_;
+ const WebPPicture* const pic = enc->pic_;
+ const uint8_t* const ysrc = pic->y + (y * pic->y_stride + x) * 16;
+ const uint8_t* const usrc = pic->u + (y * pic->uv_stride + x) * 8;
+ const uint8_t* const vsrc = pic->v + (y * pic->uv_stride + x) * 8;
+ uint8_t* const ydst = it->yuv_in_ + Y_OFF;
+ uint8_t* const udst = it->yuv_in_ + U_OFF;
+ uint8_t* const vdst = it->yuv_in_ + V_OFF;
+ int w = (pic->width - x * 16);
+ int h = (pic->height - y * 16);
+
+ if (w > 16) w = 16;
+ if (h > 16) h = 16;
+
+ // Luma plane
+ ImportBlock(ysrc, pic->y_stride, ydst, w, h, 16);
+
+ { // U/V planes
+ const int uv_w = (w + 1) >> 1;
+ const int uv_h = (h + 1) >> 1;
+ ImportBlock(usrc, pic->uv_stride, udst, uv_w, uv_h, 8);
+ ImportBlock(vsrc, pic->uv_stride, vdst, uv_w, uv_h, 8);
+ }
+}
+
+//------------------------------------------------------------------------------
+// Copy back the compressed samples into user space if requested.
+
+static void ExportBlock(const uint8_t* src, uint8_t* dst, int dst_stride,
+ int w, int h) {
+ while (h-- > 0) {
+ memcpy(dst, src, w);
+ dst += dst_stride;
+ src += BPS;
+ }
+}
+
+void VP8IteratorExport(const VP8EncIterator* const it) {
+ const VP8Encoder* const enc = it->enc_;
+ if (enc->config_->show_compressed) {
+ const int x = it->x_, y = it->y_;
+ const uint8_t* const ysrc = it->yuv_out_ + Y_OFF;
+ const uint8_t* const usrc = it->yuv_out_ + U_OFF;
+ const uint8_t* const vsrc = it->yuv_out_ + V_OFF;
+ const WebPPicture* const pic = enc->pic_;
+ uint8_t* const ydst = pic->y + (y * pic->y_stride + x) * 16;
+ uint8_t* const udst = pic->u + (y * pic->uv_stride + x) * 8;
+ uint8_t* const vdst = pic->v + (y * pic->uv_stride + x) * 8;
+ int w = (pic->width - x * 16);
+ int h = (pic->height - y * 16);
+
+ if (w > 16) w = 16;
+ if (h > 16) h = 16;
+
+ // Luma plane
+ ExportBlock(ysrc, ydst, pic->y_stride, w, h);
+
+ { // U/V planes
+ const int uv_w = (w + 1) >> 1;
+ const int uv_h = (h + 1) >> 1;
+ ExportBlock(usrc, udst, pic->uv_stride, uv_w, uv_h);
+ ExportBlock(vsrc, vdst, pic->uv_stride, uv_w, uv_h);
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+// Non-zero contexts setup/teardown
+
+// Nz bits:
+// 0 1 2 3 Y
+// 4 5 6 7
+// 8 9 10 11
+// 12 13 14 15
+// 16 17 U
+// 18 19
+// 20 21 V
+// 22 23
+// 24 DC-intra16
+
+// Convert packed context to byte array
+#define BIT(nz, n) (!!((nz) & (1 << (n))))
+
+void VP8IteratorNzToBytes(VP8EncIterator* const it) {
+ const int tnz = it->nz_[0], lnz = it->nz_[-1];
+ int* const top_nz = it->top_nz_;
+ int* const left_nz = it->left_nz_;
+
+ // Top-Y
+ top_nz[0] = BIT(tnz, 12);
+ top_nz[1] = BIT(tnz, 13);
+ top_nz[2] = BIT(tnz, 14);
+ top_nz[3] = BIT(tnz, 15);
+ // Top-U
+ top_nz[4] = BIT(tnz, 18);
+ top_nz[5] = BIT(tnz, 19);
+ // Top-V
+ top_nz[6] = BIT(tnz, 22);
+ top_nz[7] = BIT(tnz, 23);
+ // DC
+ top_nz[8] = BIT(tnz, 24);
+
+ // left-Y
+ left_nz[0] = BIT(lnz, 3);
+ left_nz[1] = BIT(lnz, 7);
+ left_nz[2] = BIT(lnz, 11);
+ left_nz[3] = BIT(lnz, 15);
+ // left-U
+ left_nz[4] = BIT(lnz, 17);
+ left_nz[5] = BIT(lnz, 19);
+ // left-V
+ left_nz[6] = BIT(lnz, 21);
+ left_nz[7] = BIT(lnz, 23);
+ // left-DC is special, iterated separately
+}
+
+void VP8IteratorBytesToNz(VP8EncIterator* const it) {
+ uint32_t nz = 0;
+ const int* const top_nz = it->top_nz_;
+ const int* const left_nz = it->left_nz_;
+ // top
+ nz |= (top_nz[0] << 12) | (top_nz[1] << 13);
+ nz |= (top_nz[2] << 14) | (top_nz[3] << 15);
+ nz |= (top_nz[4] << 18) | (top_nz[5] << 19);
+ nz |= (top_nz[6] << 22) | (top_nz[7] << 23);
+ nz |= (top_nz[8] << 24); // we propagate the _top_ bit, esp. for intra4
+ // left
+ nz |= (left_nz[0] << 3) | (left_nz[1] << 7);
+ nz |= (left_nz[2] << 11);
+ nz |= (left_nz[4] << 17) | (left_nz[6] << 21);
+
+ *it->nz_ = nz;
+}
+
+#undef BIT
+
+//------------------------------------------------------------------------------
+// Advance to the next position, doing the bookeeping.
+
+int VP8IteratorNext(VP8EncIterator* const it,
+ const uint8_t* const block_to_save) {
+ VP8Encoder* const enc = it->enc_;
+ if (block_to_save) {
+ const int x = it->x_, y = it->y_;
+ const uint8_t* const ysrc = block_to_save + Y_OFF;
+ const uint8_t* const usrc = block_to_save + U_OFF;
+ if (x < enc->mb_w_ - 1) { // left
+ int i;
+ for (i = 0; i < 16; ++i) {
+ enc->y_left_[i] = ysrc[15 + i * BPS];
+ }
+ for (i = 0; i < 8; ++i) {
+ enc->u_left_[i] = usrc[7 + i * BPS];
+ enc->v_left_[i] = usrc[15 + i * BPS];
+ }
+ // top-left (before 'top'!)
+ enc->y_left_[-1] = enc->y_top_[x * 16 + 15];
+ enc->u_left_[-1] = enc->uv_top_[x * 16 + 0 + 7];
+ enc->v_left_[-1] = enc->uv_top_[x * 16 + 8 + 7];
+ }
+ if (y < enc->mb_h_ - 1) { // top
+ memcpy(enc->y_top_ + x * 16, ysrc + 15 * BPS, 16);
+ memcpy(enc->uv_top_ + x * 16, usrc + 7 * BPS, 8 + 8);
+ }
+ }
+
+ it->mb_++;
+ it->preds_ += 4;
+ it->nz_++;
+ it->x_++;
+ if (it->x_ == enc->mb_w_) {
+ it->x_ = 0;
+ it->y_++;
+ it->bw_ = &enc->parts_[it->y_ & (enc->num_parts_ - 1)];
+ it->preds_ = enc->preds_ + it->y_ * 4 * enc->preds_w_;
+ it->nz_ = enc->nz_;
+ InitLeft(it);
+ }
+ return (0 < --it->done_);
+}
+
+//------------------------------------------------------------------------------
+// Helper function to set mode properties
+
+void VP8SetIntra16Mode(const VP8EncIterator* const it, int mode) {
+ uint8_t* preds = it->preds_;
+ int y;
+ for (y = 0; y < 4; ++y) {
+ memset(preds, mode, 4);
+ preds += it->enc_->preds_w_;
+ }
+ it->mb_->type_ = 1;
+}
+
+void VP8SetIntra4Mode(const VP8EncIterator* const it, const uint8_t* modes) {
+ uint8_t* preds = it->preds_;
+ int y;
+ for (y = 4; y > 0; --y) {
+ memcpy(preds, modes, 4 * sizeof(*modes));
+ preds += it->enc_->preds_w_;
+ modes += 4;
+ }
+ it->mb_->type_ = 0;
+}
+
+void VP8SetIntraUVMode(const VP8EncIterator* const it, int mode) {
+ it->mb_->uv_mode_ = mode;
+}
+
+void VP8SetSkip(const VP8EncIterator* const it, int skip) {
+ it->mb_->skip_ = skip;
+}
+
+void VP8SetSegment(const VP8EncIterator* const it, int segment) {
+ it->mb_->segment_ = segment;
+}
+
+//------------------------------------------------------------------------------
+// Intra4x4 sub-blocks iteration
+//
+// We store and update the boundary samples into an array of 37 pixels. They
+// are updated as we iterate and reconstructs each intra4x4 blocks in turn.
+// The position of the samples has the following snake pattern:
+//
+// 16|17 18 19 20|21 22 23 24|25 26 27 28|29 30 31 32|33 34 35 36 <- Top-right
+// --+-----------+-----------+-----------+-----------+
+// 15| 19| 23| 27| 31|
+// 14| 18| 22| 26| 30|
+// 13| 17| 21| 25| 29|
+// 12|13 14 15 16|17 18 19 20|21 22 23 24|25 26 27 28|
+// --+-----------+-----------+-----------+-----------+
+// 11| 15| 19| 23| 27|
+// 10| 14| 18| 22| 26|
+// 9| 13| 17| 21| 25|
+// 8| 9 10 11 12|13 14 15 16|17 18 19 20|21 22 23 24|
+// --+-----------+-----------+-----------+-----------+
+// 7| 11| 15| 19| 23|
+// 6| 10| 14| 18| 22|
+// 5| 9| 13| 17| 21|
+// 4| 5 6 7 8| 9 10 11 12|13 14 15 16|17 18 19 20|
+// --+-----------+-----------+-----------+-----------+
+// 3| 7| 11| 15| 19|
+// 2| 6| 10| 14| 18|
+// 1| 5| 9| 13| 17|
+// 0| 1 2 3 4| 5 6 7 8| 9 10 11 12|13 14 15 16|
+// --+-----------+-----------+-----------+-----------+
+
+// Array to record the position of the top sample to pass to the prediction
+// functions in dsp.c.
+static const uint8_t VP8TopLeftI4[16] = {
+ 17, 21, 25, 29,
+ 13, 17, 21, 25,
+ 9, 13, 17, 21,
+ 5, 9, 13, 17
+};
+
+void VP8IteratorStartI4(VP8EncIterator* const it) {
+ const VP8Encoder* const enc = it->enc_;
+ int i;
+
+ it->i4_ = 0; // first 4x4 sub-block
+ it->i4_top_ = it->i4_boundary_ + VP8TopLeftI4[0];
+
+ // Import the boundary samples
+ for (i = 0; i < 17; ++i) { // left
+ it->i4_boundary_[i] = enc->y_left_[15 - i];
+ }
+ for (i = 0; i < 16; ++i) { // top
+ it->i4_boundary_[17 + i] = enc->y_top_[it->x_ * 16 + i];
+ }
+ // top-right samples have a special case on the far right of the picture
+ if (it->x_ < enc->mb_w_ - 1) {
+ for (i = 16; i < 16 + 4; ++i) {
+ it->i4_boundary_[17 + i] = enc->y_top_[it->x_ * 16 + i];
+ }
+ } else { // else, replicate the last valid pixel four times
+ for (i = 16; i < 16 + 4; ++i) {
+ it->i4_boundary_[17 + i] = it->i4_boundary_[17 + 15];
+ }
+ }
+ VP8IteratorNzToBytes(it); // import the non-zero context
+}
+
+int VP8IteratorRotateI4(VP8EncIterator* const it,
+ const uint8_t* const yuv_out) {
+ const uint8_t* const blk = yuv_out + VP8Scan[it->i4_];
+ uint8_t* const top = it->i4_top_;
+ int i;
+
+ // Update the cache with 7 fresh samples
+ for (i = 0; i <= 3; ++i) {
+ top[-4 + i] = blk[i + 3 * BPS]; // store future top samples
+ }
+ if ((it->i4_ & 3) != 3) { // if not on the right sub-blocks #3, #7, #11, #15
+ for (i = 0; i <= 2; ++i) { // store future left samples
+ top[i] = blk[3 + (2 - i) * BPS];
+ }
+ } else { // else replicate top-right samples, as says the specs.
+ for (i = 0; i <= 3; ++i) {
+ top[i] = top[i + 4];
+ }
+ }
+ // move pointers to next sub-block
+ ++it->i4_;
+ if (it->i4_ == 16) { // we're done
+ return 0;
+ }
+
+ it->i4_top_ = it->i4_boundary_ + VP8TopLeftI4[it->i4_];
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webp/enc/layer.c b/drivers/webpold/enc/layer.c
index 423127df63..423127df63 100644
--- a/drivers/webp/enc/layer.c
+++ b/drivers/webpold/enc/layer.c
diff --git a/drivers/webpold/enc/picture.c b/drivers/webpold/enc/picture.c
new file mode 100644
index 0000000000..44eed06083
--- /dev/null
+++ b/drivers/webpold/enc/picture.c
@@ -0,0 +1,1041 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// WebPPicture utils: colorspace conversion, crop, ...
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <assert.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include "./vp8enci.h"
+#include "../utils/rescaler.h"
+#include "../utils/utils.h"
+#include "../dsp/dsp.h"
+#include "../dsp/yuv.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define HALVE(x) (((x) + 1) >> 1)
+#define IS_YUV_CSP(csp, YUV_CSP) (((csp) & WEBP_CSP_UV_MASK) == (YUV_CSP))
+
+static const union {
+ uint32_t argb;
+ uint8_t bytes[4];
+} test_endian = { 0xff000000u };
+#define ALPHA_IS_LAST (test_endian.bytes[3] == 0xff)
+
+//------------------------------------------------------------------------------
+// WebPPicture
+//------------------------------------------------------------------------------
+
+int WebPPictureAlloc(WebPPicture* picture) {
+ if (picture != NULL) {
+ const WebPEncCSP uv_csp = picture->colorspace & WEBP_CSP_UV_MASK;
+ const int has_alpha = picture->colorspace & WEBP_CSP_ALPHA_BIT;
+ const int width = picture->width;
+ const int height = picture->height;
+
+ if (!picture->use_argb) {
+ const int y_stride = width;
+ const int uv_width = HALVE(width);
+ const int uv_height = HALVE(height);
+ const int uv_stride = uv_width;
+ int uv0_stride = 0;
+ int a_width, a_stride;
+ uint64_t y_size, uv_size, uv0_size, a_size, total_size;
+ uint8_t* mem;
+
+ // U/V
+ switch (uv_csp) {
+ case WEBP_YUV420:
+ break;
+#ifdef WEBP_EXPERIMENTAL_FEATURES
+ case WEBP_YUV400: // for now, we'll just reset the U/V samples
+ break;
+ case WEBP_YUV422:
+ uv0_stride = uv_width;
+ break;
+ case WEBP_YUV444:
+ uv0_stride = width;
+ break;
+#endif
+ default:
+ return 0;
+ }
+ uv0_size = height * uv0_stride;
+
+ // alpha
+ a_width = has_alpha ? width : 0;
+ a_stride = a_width;
+ y_size = (uint64_t)y_stride * height;
+ uv_size = (uint64_t)uv_stride * uv_height;
+ a_size = (uint64_t)a_stride * height;
+
+ total_size = y_size + a_size + 2 * uv_size + 2 * uv0_size;
+
+ // Security and validation checks
+ if (width <= 0 || height <= 0 || // luma/alpha param error
+ uv_width < 0 || uv_height < 0) { // u/v param error
+ return 0;
+ }
+ // Clear previous buffer and allocate a new one.
+ WebPPictureFree(picture); // erase previous buffer
+ mem = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*mem));
+ if (mem == NULL) return 0;
+
+ // From now on, we're in the clear, we can no longer fail...
+ picture->memory_ = (void*)mem;
+ picture->y_stride = y_stride;
+ picture->uv_stride = uv_stride;
+ picture->a_stride = a_stride;
+ picture->uv0_stride = uv0_stride;
+ // TODO(skal): we could align the y/u/v planes and adjust stride.
+ picture->y = mem;
+ mem += y_size;
+
+ picture->u = mem;
+ mem += uv_size;
+ picture->v = mem;
+ mem += uv_size;
+
+ if (a_size) {
+ picture->a = mem;
+ mem += a_size;
+ }
+ if (uv0_size) {
+ picture->u0 = mem;
+ mem += uv0_size;
+ picture->v0 = mem;
+ mem += uv0_size;
+ }
+ } else {
+ void* memory;
+ const uint64_t argb_size = (uint64_t)width * height;
+ if (width <= 0 || height <= 0) {
+ return 0;
+ }
+ // Clear previous buffer and allocate a new one.
+ WebPPictureFree(picture); // erase previous buffer
+ memory = WebPSafeMalloc(argb_size, sizeof(*picture->argb));
+ if (memory == NULL) return 0;
+
+ // TODO(skal): align plane to cache line?
+ picture->memory_argb_ = memory;
+ picture->argb = (uint32_t*)memory;
+ picture->argb_stride = width;
+ }
+ }
+ return 1;
+}
+
+// Remove reference to the ARGB buffer (doesn't free anything).
+static void PictureResetARGB(WebPPicture* const picture) {
+ picture->memory_argb_ = NULL;
+ picture->argb = NULL;
+ picture->argb_stride = 0;
+}
+
+// Remove reference to the YUVA buffer (doesn't free anything).
+static void PictureResetYUVA(WebPPicture* const picture) {
+ picture->memory_ = NULL;
+ picture->y = picture->u = picture->v = picture->a = NULL;
+ picture->u0 = picture->v0 = NULL;
+ picture->y_stride = picture->uv_stride = 0;
+ picture->a_stride = 0;
+ picture->uv0_stride = 0;
+}
+
+// Grab the 'specs' (writer, *opaque, width, height...) from 'src' and copy them
+// into 'dst'. Mark 'dst' as not owning any memory.
+static void WebPPictureGrabSpecs(const WebPPicture* const src,
+ WebPPicture* const dst) {
+ assert(src != NULL && dst != NULL);
+ *dst = *src;
+ PictureResetYUVA(dst);
+ PictureResetARGB(dst);
+}
+
+// Allocate a new argb buffer, discarding any existing one and preserving
+// the other YUV(A) buffer.
+static int PictureAllocARGB(WebPPicture* const picture) {
+ WebPPicture tmp;
+ free(picture->memory_argb_);
+ PictureResetARGB(picture);
+ picture->use_argb = 1;
+ WebPPictureGrabSpecs(picture, &tmp);
+ if (!WebPPictureAlloc(&tmp)) {
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ }
+ picture->memory_argb_ = tmp.memory_argb_;
+ picture->argb = tmp.argb;
+ picture->argb_stride = tmp.argb_stride;
+ return 1;
+}
+
+// Release memory owned by 'picture' (both YUV and ARGB buffers).
+void WebPPictureFree(WebPPicture* picture) {
+ if (picture != NULL) {
+ free(picture->memory_);
+ free(picture->memory_argb_);
+ PictureResetYUVA(picture);
+ PictureResetARGB(picture);
+ }
+}
+
+//------------------------------------------------------------------------------
+// Picture copying
+
+// Not worth moving to dsp/enc.c (only used here).
+static void CopyPlane(const uint8_t* src, int src_stride,
+ uint8_t* dst, int dst_stride, int width, int height) {
+ while (height-- > 0) {
+ memcpy(dst, src, width);
+ src += src_stride;
+ dst += dst_stride;
+ }
+}
+
+// Adjust top-left corner to chroma sample position.
+static void SnapTopLeftPosition(const WebPPicture* const pic,
+ int* const left, int* const top) {
+ if (!pic->use_argb) {
+ const int is_yuv422 = IS_YUV_CSP(pic->colorspace, WEBP_YUV422);
+ if (IS_YUV_CSP(pic->colorspace, WEBP_YUV420) || is_yuv422) {
+ *left &= ~1;
+ if (!is_yuv422) *top &= ~1;
+ }
+ }
+}
+
+// Adjust top-left corner and verify that the sub-rectangle is valid.
+static int AdjustAndCheckRectangle(const WebPPicture* const pic,
+ int* const left, int* const top,
+ int width, int height) {
+ SnapTopLeftPosition(pic, left, top);
+ if ((*left) < 0 || (*top) < 0) return 0;
+ if (width <= 0 || height <= 0) return 0;
+ if ((*left) + width > pic->width) return 0;
+ if ((*top) + height > pic->height) return 0;
+ return 1;
+}
+
+int WebPPictureCopy(const WebPPicture* src, WebPPicture* dst) {
+ if (src == NULL || dst == NULL) return 0;
+ if (src == dst) return 1;
+
+ WebPPictureGrabSpecs(src, dst);
+ if (!WebPPictureAlloc(dst)) return 0;
+
+ if (!src->use_argb) {
+ CopyPlane(src->y, src->y_stride,
+ dst->y, dst->y_stride, dst->width, dst->height);
+ CopyPlane(src->u, src->uv_stride,
+ dst->u, dst->uv_stride, HALVE(dst->width), HALVE(dst->height));
+ CopyPlane(src->v, src->uv_stride,
+ dst->v, dst->uv_stride, HALVE(dst->width), HALVE(dst->height));
+ if (dst->a != NULL) {
+ CopyPlane(src->a, src->a_stride,
+ dst->a, dst->a_stride, dst->width, dst->height);
+ }
+#ifdef WEBP_EXPERIMENTAL_FEATURES
+ if (dst->u0 != NULL) {
+ int uv0_width = src->width;
+ if (IS_YUV_CSP(dst->colorspace, WEBP_YUV422)) {
+ uv0_width = HALVE(uv0_width);
+ }
+ CopyPlane(src->u0, src->uv0_stride,
+ dst->u0, dst->uv0_stride, uv0_width, dst->height);
+ CopyPlane(src->v0, src->uv0_stride,
+ dst->v0, dst->uv0_stride, uv0_width, dst->height);
+ }
+#endif
+ } else {
+ CopyPlane((const uint8_t*)src->argb, 4 * src->argb_stride,
+ (uint8_t*)dst->argb, 4 * dst->argb_stride,
+ 4 * dst->width, dst->height);
+ }
+ return 1;
+}
+
+int WebPPictureIsView(const WebPPicture* picture) {
+ if (picture == NULL) return 0;
+ if (picture->use_argb) {
+ return (picture->memory_argb_ == NULL);
+ }
+ return (picture->memory_ == NULL);
+}
+
+int WebPPictureView(const WebPPicture* src,
+ int left, int top, int width, int height,
+ WebPPicture* dst) {
+ if (src == NULL || dst == NULL) return 0;
+
+ // verify rectangle position.
+ if (!AdjustAndCheckRectangle(src, &left, &top, width, height)) return 0;
+
+ if (src != dst) { // beware of aliasing! We don't want to leak 'memory_'.
+ WebPPictureGrabSpecs(src, dst);
+ }
+ dst->width = width;
+ dst->height = height;
+ if (!src->use_argb) {
+ dst->y = src->y + top * src->y_stride + left;
+ dst->u = src->u + (top >> 1) * src->uv_stride + (left >> 1);
+ dst->v = src->v + (top >> 1) * src->uv_stride + (left >> 1);
+ if (src->a != NULL) {
+ dst->a = src->a + top * src->a_stride + left;
+ }
+#ifdef WEBP_EXPERIMENTAL_FEATURES
+ if (src->u0 != NULL) {
+ const int left_pos =
+ IS_YUV_CSP(dst->colorspace, WEBP_YUV422) ? (left >> 1) : left;
+ dst->u0 = src->u0 + top * src->uv0_stride + left_pos;
+ dst->v0 = src->v0 + top * src->uv0_stride + left_pos;
+ }
+#endif
+ } else {
+ dst->argb = src->argb + top * src->argb_stride + left;
+ }
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+// Picture cropping
+
+int WebPPictureCrop(WebPPicture* pic,
+ int left, int top, int width, int height) {
+ WebPPicture tmp;
+
+ if (pic == NULL) return 0;
+ if (!AdjustAndCheckRectangle(pic, &left, &top, width, height)) return 0;
+
+ WebPPictureGrabSpecs(pic, &tmp);
+ tmp.width = width;
+ tmp.height = height;
+ if (!WebPPictureAlloc(&tmp)) return 0;
+
+ if (!pic->use_argb) {
+ const int y_offset = top * pic->y_stride + left;
+ const int uv_offset = (top / 2) * pic->uv_stride + left / 2;
+ CopyPlane(pic->y + y_offset, pic->y_stride,
+ tmp.y, tmp.y_stride, width, height);
+ CopyPlane(pic->u + uv_offset, pic->uv_stride,
+ tmp.u, tmp.uv_stride, HALVE(width), HALVE(height));
+ CopyPlane(pic->v + uv_offset, pic->uv_stride,
+ tmp.v, tmp.uv_stride, HALVE(width), HALVE(height));
+
+ if (tmp.a != NULL) {
+ const int a_offset = top * pic->a_stride + left;
+ CopyPlane(pic->a + a_offset, pic->a_stride,
+ tmp.a, tmp.a_stride, width, height);
+ }
+#ifdef WEBP_EXPERIMENTAL_FEATURES
+ if (tmp.u0 != NULL) {
+ int w = width;
+ int left_pos = left;
+ if (IS_YUV_CSP(tmp.colorspace, WEBP_YUV422)) {
+ w = HALVE(w);
+ left_pos = HALVE(left_pos);
+ }
+ CopyPlane(pic->u0 + top * pic->uv0_stride + left_pos, pic->uv0_stride,
+ tmp.u0, tmp.uv0_stride, w, height);
+ CopyPlane(pic->v0 + top * pic->uv0_stride + left_pos, pic->uv0_stride,
+ tmp.v0, tmp.uv0_stride, w, height);
+ }
+#endif
+ } else {
+ const uint8_t* const src =
+ (const uint8_t*)(pic->argb + top * pic->argb_stride + left);
+ CopyPlane(src, pic->argb_stride * 4,
+ (uint8_t*)tmp.argb, tmp.argb_stride * 4,
+ width * 4, height);
+ }
+ WebPPictureFree(pic);
+ *pic = tmp;
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+// Simple picture rescaler
+
+static void RescalePlane(const uint8_t* src,
+ int src_width, int src_height, int src_stride,
+ uint8_t* dst,
+ int dst_width, int dst_height, int dst_stride,
+ int32_t* const work,
+ int num_channels) {
+ WebPRescaler rescaler;
+ int y = 0;
+ WebPRescalerInit(&rescaler, src_width, src_height,
+ dst, dst_width, dst_height, dst_stride,
+ num_channels,
+ src_width, dst_width,
+ src_height, dst_height,
+ work);
+ memset(work, 0, 2 * dst_width * num_channels * sizeof(*work));
+ while (y < src_height) {
+ y += WebPRescalerImport(&rescaler, src_height - y,
+ src + y * src_stride, src_stride);
+ WebPRescalerExport(&rescaler);
+ }
+}
+
+int WebPPictureRescale(WebPPicture* pic, int width, int height) {
+ WebPPicture tmp;
+ int prev_width, prev_height;
+ int32_t* work;
+
+ if (pic == NULL) return 0;
+ prev_width = pic->width;
+ prev_height = pic->height;
+ // if width is unspecified, scale original proportionally to height ratio.
+ if (width == 0) {
+ width = (prev_width * height + prev_height / 2) / prev_height;
+ }
+ // if height is unspecified, scale original proportionally to width ratio.
+ if (height == 0) {
+ height = (prev_height * width + prev_width / 2) / prev_width;
+ }
+ // Check if the overall dimensions still make sense.
+ if (width <= 0 || height <= 0) return 0;
+
+ WebPPictureGrabSpecs(pic, &tmp);
+ tmp.width = width;
+ tmp.height = height;
+ if (!WebPPictureAlloc(&tmp)) return 0;
+
+ if (!pic->use_argb) {
+ work = (int32_t*)WebPSafeMalloc(2ULL * width, sizeof(*work));
+ if (work == NULL) {
+ WebPPictureFree(&tmp);
+ return 0;
+ }
+
+ RescalePlane(pic->y, prev_width, prev_height, pic->y_stride,
+ tmp.y, width, height, tmp.y_stride, work, 1);
+ RescalePlane(pic->u,
+ HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
+ tmp.u,
+ HALVE(width), HALVE(height), tmp.uv_stride, work, 1);
+ RescalePlane(pic->v,
+ HALVE(prev_width), HALVE(prev_height), pic->uv_stride,
+ tmp.v,
+ HALVE(width), HALVE(height), tmp.uv_stride, work, 1);
+
+ if (tmp.a != NULL) {
+ RescalePlane(pic->a, prev_width, prev_height, pic->a_stride,
+ tmp.a, width, height, tmp.a_stride, work, 1);
+ }
+#ifdef WEBP_EXPERIMENTAL_FEATURES
+ if (tmp.u0 != NULL) {
+ const int s = IS_YUV_CSP(tmp.colorspace, WEBP_YUV422) ? 2 : 1;
+ RescalePlane(
+ pic->u0, (prev_width + s / 2) / s, prev_height, pic->uv0_stride,
+ tmp.u0, (width + s / 2) / s, height, tmp.uv0_stride, work, 1);
+ RescalePlane(
+ pic->v0, (prev_width + s / 2) / s, prev_height, pic->uv0_stride,
+ tmp.v0, (width + s / 2) / s, height, tmp.uv0_stride, work, 1);
+ }
+#endif
+ } else {
+ work = (int32_t*)WebPSafeMalloc(2ULL * width * 4, sizeof(*work));
+ if (work == NULL) {
+ WebPPictureFree(&tmp);
+ return 0;
+ }
+
+ RescalePlane((const uint8_t*)pic->argb, prev_width, prev_height,
+ pic->argb_stride * 4,
+ (uint8_t*)tmp.argb, width, height,
+ tmp.argb_stride * 4,
+ work, 4);
+
+ }
+ WebPPictureFree(pic);
+ free(work);
+ *pic = tmp;
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+// WebPMemoryWriter: Write-to-memory
+
+void WebPMemoryWriterInit(WebPMemoryWriter* writer) {
+ writer->mem = NULL;
+ writer->size = 0;
+ writer->max_size = 0;
+}
+
+int WebPMemoryWrite(const uint8_t* data, size_t data_size,
+ const WebPPicture* picture) {
+ WebPMemoryWriter* const w = (WebPMemoryWriter*)picture->custom_ptr;
+ uint64_t next_size;
+ if (w == NULL) {
+ return 1;
+ }
+ next_size = (uint64_t)w->size + data_size;
+ if (next_size > w->max_size) {
+ uint8_t* new_mem;
+ uint64_t next_max_size = 2ULL * w->max_size;
+ if (next_max_size < next_size) next_max_size = next_size;
+ if (next_max_size < 8192ULL) next_max_size = 8192ULL;
+ new_mem = (uint8_t*)WebPSafeMalloc(next_max_size, 1);
+ if (new_mem == NULL) {
+ return 0;
+ }
+ if (w->size > 0) {
+ memcpy(new_mem, w->mem, w->size);
+ }
+ free(w->mem);
+ w->mem = new_mem;
+ // down-cast is ok, thanks to WebPSafeMalloc
+ w->max_size = (size_t)next_max_size;
+ }
+ if (data_size > 0) {
+ memcpy(w->mem + w->size, data, data_size);
+ w->size += data_size;
+ }
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+// Detection of non-trivial transparency
+
+// Returns true if alpha[] has non-0xff values.
+static int CheckNonOpaque(const uint8_t* alpha, int width, int height,
+ int x_step, int y_step) {
+ if (alpha == NULL) return 0;
+ while (height-- > 0) {
+ int x;
+ for (x = 0; x < width * x_step; x += x_step) {
+ if (alpha[x] != 0xff) return 1; // TODO(skal): check 4/8 bytes at a time.
+ }
+ alpha += y_step;
+ }
+ return 0;
+}
+
+// Checking for the presence of non-opaque alpha.
+int WebPPictureHasTransparency(const WebPPicture* picture) {
+ if (picture == NULL) return 0;
+ if (!picture->use_argb) {
+ return CheckNonOpaque(picture->a, picture->width, picture->height,
+ 1, picture->a_stride);
+ } else {
+ int x, y;
+ const uint32_t* argb = picture->argb;
+ if (argb == NULL) return 0;
+ for (y = 0; y < picture->height; ++y) {
+ for (x = 0; x < picture->width; ++x) {
+ if (argb[x] < 0xff000000u) return 1; // test any alpha values != 0xff
+ }
+ argb += picture->argb_stride;
+ }
+ }
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+// RGB -> YUV conversion
+
+// TODO: we can do better than simply 2x2 averaging on U/V samples.
+#define SUM4(ptr) ((ptr)[0] + (ptr)[step] + \
+ (ptr)[rgb_stride] + (ptr)[rgb_stride + step])
+#define SUM2H(ptr) (2 * (ptr)[0] + 2 * (ptr)[step])
+#define SUM2V(ptr) (2 * (ptr)[0] + 2 * (ptr)[rgb_stride])
+#define SUM1(ptr) (4 * (ptr)[0])
+#define RGB_TO_UV(x, y, SUM) { \
+ const int src = (2 * (step * (x) + (y) * rgb_stride)); \
+ const int dst = (x) + (y) * picture->uv_stride; \
+ const int r = SUM(r_ptr + src); \
+ const int g = SUM(g_ptr + src); \
+ const int b = SUM(b_ptr + src); \
+ picture->u[dst] = VP8RGBToU(r, g, b); \
+ picture->v[dst] = VP8RGBToV(r, g, b); \
+}
+
+#define RGB_TO_UV0(x_in, x_out, y, SUM) { \
+ const int src = (step * (x_in) + (y) * rgb_stride); \
+ const int dst = (x_out) + (y) * picture->uv0_stride; \
+ const int r = SUM(r_ptr + src); \
+ const int g = SUM(g_ptr + src); \
+ const int b = SUM(b_ptr + src); \
+ picture->u0[dst] = VP8RGBToU(r, g, b); \
+ picture->v0[dst] = VP8RGBToV(r, g, b); \
+}
+
+static void MakeGray(WebPPicture* const picture) {
+ int y;
+ const int uv_width = HALVE(picture->width);
+ const int uv_height = HALVE(picture->height);
+ for (y = 0; y < uv_height; ++y) {
+ memset(picture->u + y * picture->uv_stride, 128, uv_width);
+ memset(picture->v + y * picture->uv_stride, 128, uv_width);
+ }
+}
+
+static int ImportYUVAFromRGBA(const uint8_t* const r_ptr,
+ const uint8_t* const g_ptr,
+ const uint8_t* const b_ptr,
+ const uint8_t* const a_ptr,
+ int step, // bytes per pixel
+ int rgb_stride, // bytes per scanline
+ WebPPicture* const picture) {
+ const WebPEncCSP uv_csp = picture->colorspace & WEBP_CSP_UV_MASK;
+ int x, y;
+ const int width = picture->width;
+ const int height = picture->height;
+ const int has_alpha = CheckNonOpaque(a_ptr, width, height, step, rgb_stride);
+
+ picture->colorspace = uv_csp;
+ picture->use_argb = 0;
+ if (has_alpha) {
+ picture->colorspace |= WEBP_CSP_ALPHA_BIT;
+ }
+ if (!WebPPictureAlloc(picture)) return 0;
+
+ // Import luma plane
+ for (y = 0; y < height; ++y) {
+ for (x = 0; x < width; ++x) {
+ const int offset = step * x + y * rgb_stride;
+ picture->y[x + y * picture->y_stride] =
+ VP8RGBToY(r_ptr[offset], g_ptr[offset], b_ptr[offset]);
+ }
+ }
+
+ // Downsample U/V plane
+ if (uv_csp != WEBP_YUV400) {
+ for (y = 0; y < (height >> 1); ++y) {
+ for (x = 0; x < (width >> 1); ++x) {
+ RGB_TO_UV(x, y, SUM4);
+ }
+ if (width & 1) {
+ RGB_TO_UV(x, y, SUM2V);
+ }
+ }
+ if (height & 1) {
+ for (x = 0; x < (width >> 1); ++x) {
+ RGB_TO_UV(x, y, SUM2H);
+ }
+ if (width & 1) {
+ RGB_TO_UV(x, y, SUM1);
+ }
+ }
+
+#ifdef WEBP_EXPERIMENTAL_FEATURES
+ // Store original U/V samples too
+ if (uv_csp == WEBP_YUV422) {
+ for (y = 0; y < height; ++y) {
+ for (x = 0; x < (width >> 1); ++x) {
+ RGB_TO_UV0(2 * x, x, y, SUM2H);
+ }
+ if (width & 1) {
+ RGB_TO_UV0(2 * x, x, y, SUM1);
+ }
+ }
+ } else if (uv_csp == WEBP_YUV444) {
+ for (y = 0; y < height; ++y) {
+ for (x = 0; x < width; ++x) {
+ RGB_TO_UV0(x, x, y, SUM1);
+ }
+ }
+ }
+#endif
+ } else {
+ MakeGray(picture);
+ }
+
+ if (has_alpha) {
+ assert(step >= 4);
+ for (y = 0; y < height; ++y) {
+ for (x = 0; x < width; ++x) {
+ picture->a[x + y * picture->a_stride] =
+ a_ptr[step * x + y * rgb_stride];
+ }
+ }
+ }
+ return 1;
+}
+
+static int Import(WebPPicture* const picture,
+ const uint8_t* const rgb, int rgb_stride,
+ int step, int swap_rb, int import_alpha) {
+ const uint8_t* const r_ptr = rgb + (swap_rb ? 2 : 0);
+ const uint8_t* const g_ptr = rgb + 1;
+ const uint8_t* const b_ptr = rgb + (swap_rb ? 0 : 2);
+ const uint8_t* const a_ptr = import_alpha ? rgb + 3 : NULL;
+ const int width = picture->width;
+ const int height = picture->height;
+
+ if (!picture->use_argb) {
+ return ImportYUVAFromRGBA(r_ptr, g_ptr, b_ptr, a_ptr, step, rgb_stride,
+ picture);
+ }
+ if (import_alpha) {
+ picture->colorspace |= WEBP_CSP_ALPHA_BIT;
+ } else {
+ picture->colorspace &= ~WEBP_CSP_ALPHA_BIT;
+ }
+ if (!WebPPictureAlloc(picture)) return 0;
+
+ if (!import_alpha) {
+ int x, y;
+ for (y = 0; y < height; ++y) {
+ for (x = 0; x < width; ++x) {
+ const int offset = step * x + y * rgb_stride;
+ const uint32_t argb =
+ 0xff000000u |
+ (r_ptr[offset] << 16) |
+ (g_ptr[offset] << 8) |
+ (b_ptr[offset]);
+ picture->argb[x + y * picture->argb_stride] = argb;
+ }
+ }
+ } else {
+ int x, y;
+ assert(step >= 4);
+ for (y = 0; y < height; ++y) {
+ for (x = 0; x < width; ++x) {
+ const int offset = step * x + y * rgb_stride;
+ const uint32_t argb = (a_ptr[offset] << 24) |
+ (r_ptr[offset] << 16) |
+ (g_ptr[offset] << 8) |
+ (b_ptr[offset]);
+ picture->argb[x + y * picture->argb_stride] = argb;
+ }
+ }
+ }
+ return 1;
+}
+#undef SUM4
+#undef SUM2V
+#undef SUM2H
+#undef SUM1
+#undef RGB_TO_UV
+
+int WebPPictureImportRGB(WebPPicture* picture,
+ const uint8_t* rgb, int rgb_stride) {
+ return Import(picture, rgb, rgb_stride, 3, 0, 0);
+}
+
+int WebPPictureImportBGR(WebPPicture* picture,
+ const uint8_t* rgb, int rgb_stride) {
+ return Import(picture, rgb, rgb_stride, 3, 1, 0);
+}
+
+int WebPPictureImportRGBA(WebPPicture* picture,
+ const uint8_t* rgba, int rgba_stride) {
+ return Import(picture, rgba, rgba_stride, 4, 0, 1);
+}
+
+int WebPPictureImportBGRA(WebPPicture* picture,
+ const uint8_t* rgba, int rgba_stride) {
+ return Import(picture, rgba, rgba_stride, 4, 1, 1);
+}
+
+int WebPPictureImportRGBX(WebPPicture* picture,
+ const uint8_t* rgba, int rgba_stride) {
+ return Import(picture, rgba, rgba_stride, 4, 0, 0);
+}
+
+int WebPPictureImportBGRX(WebPPicture* picture,
+ const uint8_t* rgba, int rgba_stride) {
+ return Import(picture, rgba, rgba_stride, 4, 1, 0);
+}
+
+//------------------------------------------------------------------------------
+// Automatic YUV <-> ARGB conversions.
+
+int WebPPictureYUVAToARGB(WebPPicture* picture) {
+ if (picture == NULL) return 0;
+ if (picture->memory_ == NULL || picture->y == NULL ||
+ picture->u == NULL || picture->v == NULL) {
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
+ }
+ if ((picture->colorspace & WEBP_CSP_ALPHA_BIT) && picture->a == NULL) {
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
+ }
+ if ((picture->colorspace & WEBP_CSP_UV_MASK) != WEBP_YUV420) {
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_INVALID_CONFIGURATION);
+ }
+ // Allocate a new argb buffer (discarding the previous one).
+ if (!PictureAllocARGB(picture)) return 0;
+
+ // Convert
+ {
+ int y;
+ const int width = picture->width;
+ const int height = picture->height;
+ const int argb_stride = 4 * picture->argb_stride;
+ uint8_t* dst = (uint8_t*)picture->argb;
+ const uint8_t *cur_u = picture->u, *cur_v = picture->v, *cur_y = picture->y;
+ WebPUpsampleLinePairFunc upsample = WebPGetLinePairConverter(ALPHA_IS_LAST);
+
+ // First row, with replicated top samples.
+ upsample(NULL, cur_y, cur_u, cur_v, cur_u, cur_v, NULL, dst, width);
+ cur_y += picture->y_stride;
+ dst += argb_stride;
+ // Center rows.
+ for (y = 1; y + 1 < height; y += 2) {
+ const uint8_t* const top_u = cur_u;
+ const uint8_t* const top_v = cur_v;
+ cur_u += picture->uv_stride;
+ cur_v += picture->uv_stride;
+ upsample(cur_y, cur_y + picture->y_stride, top_u, top_v, cur_u, cur_v,
+ dst, dst + argb_stride, width);
+ cur_y += 2 * picture->y_stride;
+ dst += 2 * argb_stride;
+ }
+ // Last row (if needed), with replicated bottom samples.
+ if (height > 1 && !(height & 1)) {
+ upsample(cur_y, NULL, cur_u, cur_v, cur_u, cur_v, dst, NULL, width);
+ }
+ // Insert alpha values if needed, in replacement for the default 0xff ones.
+ if (picture->colorspace & WEBP_CSP_ALPHA_BIT) {
+ for (y = 0; y < height; ++y) {
+ uint32_t* const dst = picture->argb + y * picture->argb_stride;
+ const uint8_t* const src = picture->a + y * picture->a_stride;
+ int x;
+ for (x = 0; x < width; ++x) {
+ dst[x] = (dst[x] & 0x00ffffffu) | (src[x] << 24);
+ }
+ }
+ }
+ }
+ return 1;
+}
+
+int WebPPictureARGBToYUVA(WebPPicture* picture, WebPEncCSP colorspace) {
+ if (picture == NULL) return 0;
+ if (picture->argb == NULL) {
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_NULL_PARAMETER);
+ } else {
+ const uint8_t* const argb = (const uint8_t*)picture->argb;
+ const uint8_t* const r = ALPHA_IS_LAST ? argb + 2 : argb + 1;
+ const uint8_t* const g = ALPHA_IS_LAST ? argb + 1 : argb + 2;
+ const uint8_t* const b = ALPHA_IS_LAST ? argb + 0 : argb + 3;
+ const uint8_t* const a = ALPHA_IS_LAST ? argb + 3 : argb + 0;
+ // We work on a tmp copy of 'picture', because ImportYUVAFromRGBA()
+ // would be calling WebPPictureFree(picture) otherwise.
+ WebPPicture tmp = *picture;
+ PictureResetARGB(&tmp); // reset ARGB buffer so that it's not free()'d.
+ tmp.use_argb = 0;
+ tmp.colorspace = colorspace & WEBP_CSP_UV_MASK;
+ if (!ImportYUVAFromRGBA(r, g, b, a, 4, 4 * picture->argb_stride, &tmp)) {
+ return WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ }
+ // Copy back the YUV specs into 'picture'.
+ tmp.argb = picture->argb;
+ tmp.argb_stride = picture->argb_stride;
+ tmp.memory_argb_ = picture->memory_argb_;
+ *picture = tmp;
+ }
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+// Helper: clean up fully transparent area to help compressibility.
+
+#define SIZE 8
+#define SIZE2 (SIZE / 2)
+static int is_transparent_area(const uint8_t* ptr, int stride, int size) {
+ int y, x;
+ for (y = 0; y < size; ++y) {
+ for (x = 0; x < size; ++x) {
+ if (ptr[x]) {
+ return 0;
+ }
+ }
+ ptr += stride;
+ }
+ return 1;
+}
+
+static WEBP_INLINE void flatten(uint8_t* ptr, int v, int stride, int size) {
+ int y;
+ for (y = 0; y < size; ++y) {
+ memset(ptr, v, size);
+ ptr += stride;
+ }
+}
+
+void WebPCleanupTransparentArea(WebPPicture* pic) {
+ int x, y, w, h;
+ const uint8_t* a_ptr;
+ int values[3] = { 0 };
+
+ if (pic == NULL) return;
+
+ a_ptr = pic->a;
+ if (a_ptr == NULL) return; // nothing to do
+
+ w = pic->width / SIZE;
+ h = pic->height / SIZE;
+ for (y = 0; y < h; ++y) {
+ int need_reset = 1;
+ for (x = 0; x < w; ++x) {
+ const int off_a = (y * pic->a_stride + x) * SIZE;
+ const int off_y = (y * pic->y_stride + x) * SIZE;
+ const int off_uv = (y * pic->uv_stride + x) * SIZE2;
+ if (is_transparent_area(a_ptr + off_a, pic->a_stride, SIZE)) {
+ if (need_reset) {
+ values[0] = pic->y[off_y];
+ values[1] = pic->u[off_uv];
+ values[2] = pic->v[off_uv];
+ need_reset = 0;
+ }
+ flatten(pic->y + off_y, values[0], pic->y_stride, SIZE);
+ flatten(pic->u + off_uv, values[1], pic->uv_stride, SIZE2);
+ flatten(pic->v + off_uv, values[2], pic->uv_stride, SIZE2);
+ } else {
+ need_reset = 1;
+ }
+ }
+ // ignore the left-overs on right/bottom
+ }
+}
+
+#undef SIZE
+#undef SIZE2
+
+
+//------------------------------------------------------------------------------
+// Distortion
+
+// Max value returned in case of exact similarity.
+static const double kMinDistortion_dB = 99.;
+
+int WebPPictureDistortion(const WebPPicture* pic1, const WebPPicture* pic2,
+ int type, float result[5]) {
+ int c;
+ DistoStats stats[5];
+ int has_alpha;
+
+ if (pic1 == NULL || pic2 == NULL ||
+ pic1->width != pic2->width || pic1->height != pic2->height ||
+ pic1->y == NULL || pic2->y == NULL ||
+ pic1->u == NULL || pic2->u == NULL ||
+ pic1->v == NULL || pic2->v == NULL ||
+ result == NULL) {
+ return 0;
+ }
+ // TODO(skal): provide distortion for ARGB too.
+ if (pic1->use_argb == 1 || pic1->use_argb != pic2->use_argb) {
+ return 0;
+ }
+
+ has_alpha = !!(pic1->colorspace & WEBP_CSP_ALPHA_BIT);
+ if (has_alpha != !!(pic2->colorspace & WEBP_CSP_ALPHA_BIT) ||
+ (has_alpha && (pic1->a == NULL || pic2->a == NULL))) {
+ return 0;
+ }
+
+ memset(stats, 0, sizeof(stats));
+ VP8SSIMAccumulatePlane(pic1->y, pic1->y_stride,
+ pic2->y, pic2->y_stride,
+ pic1->width, pic1->height, &stats[0]);
+ VP8SSIMAccumulatePlane(pic1->u, pic1->uv_stride,
+ pic2->u, pic2->uv_stride,
+ (pic1->width + 1) >> 1, (pic1->height + 1) >> 1,
+ &stats[1]);
+ VP8SSIMAccumulatePlane(pic1->v, pic1->uv_stride,
+ pic2->v, pic2->uv_stride,
+ (pic1->width + 1) >> 1, (pic1->height + 1) >> 1,
+ &stats[2]);
+ if (has_alpha) {
+ VP8SSIMAccumulatePlane(pic1->a, pic1->a_stride,
+ pic2->a, pic2->a_stride,
+ pic1->width, pic1->height, &stats[3]);
+ }
+ for (c = 0; c <= 4; ++c) {
+ if (type == 1) {
+ const double v = VP8SSIMGet(&stats[c]);
+ result[c] = (float)((v < 1.) ? -10.0 * log10(1. - v)
+ : kMinDistortion_dB);
+ } else {
+ const double v = VP8SSIMGetSquaredError(&stats[c]);
+ result[c] = (float)((v > 0.) ? -4.3429448 * log(v / (255 * 255.))
+ : kMinDistortion_dB);
+ }
+ // Accumulate forward
+ if (c < 4) VP8SSIMAddStats(&stats[c], &stats[4]);
+ }
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+// Simplest high-level calls:
+
+typedef int (*Importer)(WebPPicture* const, const uint8_t* const, int);
+
+static size_t Encode(const uint8_t* rgba, int width, int height, int stride,
+ Importer import, float quality_factor, int lossless,
+ uint8_t** output) {
+ WebPPicture pic;
+ WebPConfig config;
+ WebPMemoryWriter wrt;
+ int ok;
+
+ if (!WebPConfigPreset(&config, WEBP_PRESET_DEFAULT, quality_factor) ||
+ !WebPPictureInit(&pic)) {
+ return 0; // shouldn't happen, except if system installation is broken
+ }
+
+ config.lossless = !!lossless;
+ pic.use_argb = !!lossless;
+ pic.width = width;
+ pic.height = height;
+ pic.writer = WebPMemoryWrite;
+ pic.custom_ptr = &wrt;
+ WebPMemoryWriterInit(&wrt);
+
+ ok = import(&pic, rgba, stride) && WebPEncode(&config, &pic);
+ WebPPictureFree(&pic);
+ if (!ok) {
+ free(wrt.mem);
+ *output = NULL;
+ return 0;
+ }
+ *output = wrt.mem;
+ return wrt.size;
+}
+
+#define ENCODE_FUNC(NAME, IMPORTER) \
+size_t NAME(const uint8_t* in, int w, int h, int bps, float q, \
+ uint8_t** out) { \
+ return Encode(in, w, h, bps, IMPORTER, q, 0, out); \
+}
+
+ENCODE_FUNC(WebPEncodeRGB, WebPPictureImportRGB);
+ENCODE_FUNC(WebPEncodeBGR, WebPPictureImportBGR);
+ENCODE_FUNC(WebPEncodeRGBA, WebPPictureImportRGBA);
+ENCODE_FUNC(WebPEncodeBGRA, WebPPictureImportBGRA);
+
+#undef ENCODE_FUNC
+
+#define LOSSLESS_DEFAULT_QUALITY 70.
+#define LOSSLESS_ENCODE_FUNC(NAME, IMPORTER) \
+size_t NAME(const uint8_t* in, int w, int h, int bps, uint8_t** out) { \
+ return Encode(in, w, h, bps, IMPORTER, LOSSLESS_DEFAULT_QUALITY, 1, out); \
+}
+
+LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessRGB, WebPPictureImportRGB);
+LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGR, WebPPictureImportBGR);
+LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessRGBA, WebPPictureImportRGBA);
+LOSSLESS_ENCODE_FUNC(WebPEncodeLosslessBGRA, WebPPictureImportBGRA);
+
+#undef LOSSLESS_ENCODE_FUNC
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/enc/quant.c b/drivers/webpold/enc/quant.c
new file mode 100644
index 0000000000..ea153849c8
--- /dev/null
+++ b/drivers/webpold/enc/quant.c
@@ -0,0 +1,930 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Quantization
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <assert.h>
+#include <math.h>
+
+#include "./vp8enci.h"
+#include "./cost.h"
+
+#define DO_TRELLIS_I4 1
+#define DO_TRELLIS_I16 1 // not a huge gain, but ok at low bitrate.
+#define DO_TRELLIS_UV 0 // disable trellis for UV. Risky. Not worth.
+#define USE_TDISTO 1
+
+#define MID_ALPHA 64 // neutral value for susceptibility
+#define MIN_ALPHA 30 // lowest usable value for susceptibility
+#define MAX_ALPHA 100 // higher meaninful value for susceptibility
+
+#define SNS_TO_DQ 0.9 // Scaling constant between the sns value and the QP
+ // power-law modulation. Must be strictly less than 1.
+
+#define MULT_8B(a, b) (((a) * (b) + 128) >> 8)
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+
+static WEBP_INLINE int clip(int v, int m, int M) {
+ return v < m ? m : v > M ? M : v;
+}
+
+static const uint8_t kZigzag[16] = {
+ 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15
+};
+
+static const uint8_t kDcTable[128] = {
+ 4, 5, 6, 7, 8, 9, 10, 10,
+ 11, 12, 13, 14, 15, 16, 17, 17,
+ 18, 19, 20, 20, 21, 21, 22, 22,
+ 23, 23, 24, 25, 25, 26, 27, 28,
+ 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 46, 47, 48, 49, 50,
+ 51, 52, 53, 54, 55, 56, 57, 58,
+ 59, 60, 61, 62, 63, 64, 65, 66,
+ 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 76, 77, 78, 79, 80, 81,
+ 82, 83, 84, 85, 86, 87, 88, 89,
+ 91, 93, 95, 96, 98, 100, 101, 102,
+ 104, 106, 108, 110, 112, 114, 116, 118,
+ 122, 124, 126, 128, 130, 132, 134, 136,
+ 138, 140, 143, 145, 148, 151, 154, 157
+};
+
+static const uint16_t kAcTable[128] = {
+ 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39, 40, 41, 42, 43,
+ 44, 45, 46, 47, 48, 49, 50, 51,
+ 52, 53, 54, 55, 56, 57, 58, 60,
+ 62, 64, 66, 68, 70, 72, 74, 76,
+ 78, 80, 82, 84, 86, 88, 90, 92,
+ 94, 96, 98, 100, 102, 104, 106, 108,
+ 110, 112, 114, 116, 119, 122, 125, 128,
+ 131, 134, 137, 140, 143, 146, 149, 152,
+ 155, 158, 161, 164, 167, 170, 173, 177,
+ 181, 185, 189, 193, 197, 201, 205, 209,
+ 213, 217, 221, 225, 229, 234, 239, 245,
+ 249, 254, 259, 264, 269, 274, 279, 284
+};
+
+static const uint16_t kAcTable2[128] = {
+ 8, 8, 9, 10, 12, 13, 15, 17,
+ 18, 20, 21, 23, 24, 26, 27, 29,
+ 31, 32, 34, 35, 37, 38, 40, 41,
+ 43, 44, 46, 48, 49, 51, 52, 54,
+ 55, 57, 58, 60, 62, 63, 65, 66,
+ 68, 69, 71, 72, 74, 75, 77, 79,
+ 80, 82, 83, 85, 86, 88, 89, 93,
+ 96, 99, 102, 105, 108, 111, 114, 117,
+ 120, 124, 127, 130, 133, 136, 139, 142,
+ 145, 148, 151, 155, 158, 161, 164, 167,
+ 170, 173, 176, 179, 184, 189, 193, 198,
+ 203, 207, 212, 217, 221, 226, 230, 235,
+ 240, 244, 249, 254, 258, 263, 268, 274,
+ 280, 286, 292, 299, 305, 311, 317, 323,
+ 330, 336, 342, 348, 354, 362, 370, 379,
+ 385, 393, 401, 409, 416, 424, 432, 440
+};
+
+static const uint16_t kCoeffThresh[16] = {
+ 0, 10, 20, 30,
+ 10, 20, 30, 30,
+ 20, 30, 30, 30,
+ 30, 30, 30, 30
+};
+
+// TODO(skal): tune more. Coeff thresholding?
+static const uint8_t kBiasMatrices[3][16] = { // [3] = [luma-ac,luma-dc,chroma]
+ { 96, 96, 96, 96,
+ 96, 96, 96, 96,
+ 96, 96, 96, 96,
+ 96, 96, 96, 96 },
+ { 96, 96, 96, 96,
+ 96, 96, 96, 96,
+ 96, 96, 96, 96,
+ 96, 96, 96, 96 },
+ { 96, 96, 96, 96,
+ 96, 96, 96, 96,
+ 96, 96, 96, 96,
+ 96, 96, 96, 96 }
+};
+
+// Sharpening by (slightly) raising the hi-frequency coeffs (only for trellis).
+// Hack-ish but helpful for mid-bitrate range. Use with care.
+static const uint8_t kFreqSharpening[16] = {
+ 0, 30, 60, 90,
+ 30, 60, 90, 90,
+ 60, 90, 90, 90,
+ 90, 90, 90, 90
+};
+
+//------------------------------------------------------------------------------
+// Initialize quantization parameters in VP8Matrix
+
+// Returns the average quantizer
+static int ExpandMatrix(VP8Matrix* const m, int type) {
+ int i;
+ int sum = 0;
+ for (i = 2; i < 16; ++i) {
+ m->q_[i] = m->q_[1];
+ }
+ for (i = 0; i < 16; ++i) {
+ const int j = kZigzag[i];
+ const int bias = kBiasMatrices[type][j];
+ m->iq_[j] = (1 << QFIX) / m->q_[j];
+ m->bias_[j] = BIAS(bias);
+ // TODO(skal): tune kCoeffThresh[]
+ m->zthresh_[j] = ((256 /*+ kCoeffThresh[j]*/ - bias) * m->q_[j] + 127) >> 8;
+ m->sharpen_[j] = (kFreqSharpening[j] * m->q_[j]) >> 11;
+ sum += m->q_[j];
+ }
+ return (sum + 8) >> 4;
+}
+
+static void SetupMatrices(VP8Encoder* enc) {
+ int i;
+ const int tlambda_scale =
+ (enc->method_ >= 4) ? enc->config_->sns_strength
+ : 0;
+ const int num_segments = enc->segment_hdr_.num_segments_;
+ for (i = 0; i < num_segments; ++i) {
+ VP8SegmentInfo* const m = &enc->dqm_[i];
+ const int q = m->quant_;
+ int q4, q16, quv;
+ m->y1_.q_[0] = kDcTable[clip(q + enc->dq_y1_dc_, 0, 127)];
+ m->y1_.q_[1] = kAcTable[clip(q, 0, 127)];
+
+ m->y2_.q_[0] = kDcTable[ clip(q + enc->dq_y2_dc_, 0, 127)] * 2;
+ m->y2_.q_[1] = kAcTable2[clip(q + enc->dq_y2_ac_, 0, 127)];
+
+ m->uv_.q_[0] = kDcTable[clip(q + enc->dq_uv_dc_, 0, 117)];
+ m->uv_.q_[1] = kAcTable[clip(q + enc->dq_uv_ac_, 0, 127)];
+
+ q4 = ExpandMatrix(&m->y1_, 0);
+ q16 = ExpandMatrix(&m->y2_, 1);
+ quv = ExpandMatrix(&m->uv_, 2);
+
+ // TODO: Switch to kLambda*[] tables?
+ {
+ m->lambda_i4_ = (3 * q4 * q4) >> 7;
+ m->lambda_i16_ = (3 * q16 * q16);
+ m->lambda_uv_ = (3 * quv * quv) >> 6;
+ m->lambda_mode_ = (1 * q4 * q4) >> 7;
+ m->lambda_trellis_i4_ = (7 * q4 * q4) >> 3;
+ m->lambda_trellis_i16_ = (q16 * q16) >> 2;
+ m->lambda_trellis_uv_ = (quv *quv) << 1;
+ m->tlambda_ = (tlambda_scale * q4) >> 5;
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+// Initialize filtering parameters
+
+// Very small filter-strength values have close to no visual effect. So we can
+// save a little decoding-CPU by turning filtering off for these.
+#define FSTRENGTH_CUTOFF 3
+
+static void SetupFilterStrength(VP8Encoder* const enc) {
+ int i;
+ const int level0 = enc->config_->filter_strength;
+ for (i = 0; i < NUM_MB_SEGMENTS; ++i) {
+ // Segments with lower quantizer will be less filtered. TODO: tune (wrt SNS)
+ const int level = level0 * 256 * enc->dqm_[i].quant_ / 128;
+ const int f = level / (256 + enc->dqm_[i].beta_);
+ enc->dqm_[i].fstrength_ = (f < FSTRENGTH_CUTOFF) ? 0 : (f > 63) ? 63 : f;
+ }
+ // We record the initial strength (mainly for the case of 1-segment only).
+ enc->filter_hdr_.level_ = enc->dqm_[0].fstrength_;
+ enc->filter_hdr_.simple_ = (enc->config_->filter_type == 0);
+ enc->filter_hdr_.sharpness_ = enc->config_->filter_sharpness;
+}
+
+//------------------------------------------------------------------------------
+
+// Note: if you change the values below, remember that the max range
+// allowed by the syntax for DQ_UV is [-16,16].
+#define MAX_DQ_UV (6)
+#define MIN_DQ_UV (-4)
+
+// We want to emulate jpeg-like behaviour where the expected "good" quality
+// is around q=75. Internally, our "good" middle is around c=50. So we
+// map accordingly using linear piece-wise function
+static double QualityToCompression(double q) {
+ const double c = q / 100.;
+ return (c < 0.75) ? c * (2. / 3.) : 2. * c - 1.;
+}
+
+void VP8SetSegmentParams(VP8Encoder* const enc, float quality) {
+ int i;
+ int dq_uv_ac, dq_uv_dc;
+ const int num_segments = enc->config_->segments;
+ const double amp = SNS_TO_DQ * enc->config_->sns_strength / 100. / 128.;
+ const double c_base = QualityToCompression(quality);
+ for (i = 0; i < num_segments; ++i) {
+ // The file size roughly scales as pow(quantizer, 3.). Actually, the
+ // exponent is somewhere between 2.8 and 3.2, but we're mostly interested
+ // in the mid-quant range. So we scale the compressibility inversely to
+ // this power-law: quant ~= compression ^ 1/3. This law holds well for
+ // low quant. Finer modelling for high-quant would make use of kAcTable[]
+ // more explicitely.
+ // Additionally, we modulate the base exponent 1/3 to accommodate for the
+ // quantization susceptibility and allow denser segments to be quantized
+ // more.
+ const double expn = (1. - amp * enc->dqm_[i].alpha_) / 3.;
+ const double c = pow(c_base, expn);
+ const int q = (int)(127. * (1. - c));
+ assert(expn > 0.);
+ enc->dqm_[i].quant_ = clip(q, 0, 127);
+ }
+
+ // purely indicative in the bitstream (except for the 1-segment case)
+ enc->base_quant_ = enc->dqm_[0].quant_;
+
+ // fill-in values for the unused segments (required by the syntax)
+ for (i = num_segments; i < NUM_MB_SEGMENTS; ++i) {
+ enc->dqm_[i].quant_ = enc->base_quant_;
+ }
+
+ // uv_alpha_ is normally spread around ~60. The useful range is
+ // typically ~30 (quite bad) to ~100 (ok to decimate UV more).
+ // We map it to the safe maximal range of MAX/MIN_DQ_UV for dq_uv.
+ dq_uv_ac = (enc->uv_alpha_ - MID_ALPHA) * (MAX_DQ_UV - MIN_DQ_UV)
+ / (MAX_ALPHA - MIN_ALPHA);
+ // we rescale by the user-defined strength of adaptation
+ dq_uv_ac = dq_uv_ac * enc->config_->sns_strength / 100;
+ // and make it safe.
+ dq_uv_ac = clip(dq_uv_ac, MIN_DQ_UV, MAX_DQ_UV);
+ // We also boost the dc-uv-quant a little, based on sns-strength, since
+ // U/V channels are quite more reactive to high quants (flat DC-blocks
+ // tend to appear, and are displeasant).
+ dq_uv_dc = -4 * enc->config_->sns_strength / 100;
+ dq_uv_dc = clip(dq_uv_dc, -15, 15); // 4bit-signed max allowed
+
+ enc->dq_y1_dc_ = 0; // TODO(skal): dq-lum
+ enc->dq_y2_dc_ = 0;
+ enc->dq_y2_ac_ = 0;
+ enc->dq_uv_dc_ = dq_uv_dc;
+ enc->dq_uv_ac_ = dq_uv_ac;
+
+ SetupMatrices(enc);
+
+ SetupFilterStrength(enc); // initialize segments' filtering, eventually
+}
+
+//------------------------------------------------------------------------------
+// Form the predictions in cache
+
+// Must be ordered using {DC_PRED, TM_PRED, V_PRED, H_PRED} as index
+const int VP8I16ModeOffsets[4] = { I16DC16, I16TM16, I16VE16, I16HE16 };
+const int VP8UVModeOffsets[4] = { C8DC8, C8TM8, C8VE8, C8HE8 };
+
+// Must be indexed using {B_DC_PRED -> B_HU_PRED} as index
+const int VP8I4ModeOffsets[NUM_BMODES] = {
+ I4DC4, I4TM4, I4VE4, I4HE4, I4RD4, I4VR4, I4LD4, I4VL4, I4HD4, I4HU4
+};
+
+void VP8MakeLuma16Preds(const VP8EncIterator* const it) {
+ const VP8Encoder* const enc = it->enc_;
+ const uint8_t* const left = it->x_ ? enc->y_left_ : NULL;
+ const uint8_t* const top = it->y_ ? enc->y_top_ + it->x_ * 16 : NULL;
+ VP8EncPredLuma16(it->yuv_p_, left, top);
+}
+
+void VP8MakeChroma8Preds(const VP8EncIterator* const it) {
+ const VP8Encoder* const enc = it->enc_;
+ const uint8_t* const left = it->x_ ? enc->u_left_ : NULL;
+ const uint8_t* const top = it->y_ ? enc->uv_top_ + it->x_ * 16 : NULL;
+ VP8EncPredChroma8(it->yuv_p_, left, top);
+}
+
+void VP8MakeIntra4Preds(const VP8EncIterator* const it) {
+ VP8EncPredLuma4(it->yuv_p_, it->i4_top_);
+}
+
+//------------------------------------------------------------------------------
+// Quantize
+
+// Layout:
+// +----+
+// |YYYY| 0
+// |YYYY| 4
+// |YYYY| 8
+// |YYYY| 12
+// +----+
+// |UUVV| 16
+// |UUVV| 20
+// +----+
+
+const int VP8Scan[16 + 4 + 4] = {
+ // Luma
+ 0 + 0 * BPS, 4 + 0 * BPS, 8 + 0 * BPS, 12 + 0 * BPS,
+ 0 + 4 * BPS, 4 + 4 * BPS, 8 + 4 * BPS, 12 + 4 * BPS,
+ 0 + 8 * BPS, 4 + 8 * BPS, 8 + 8 * BPS, 12 + 8 * BPS,
+ 0 + 12 * BPS, 4 + 12 * BPS, 8 + 12 * BPS, 12 + 12 * BPS,
+
+ 0 + 0 * BPS, 4 + 0 * BPS, 0 + 4 * BPS, 4 + 4 * BPS, // U
+ 8 + 0 * BPS, 12 + 0 * BPS, 8 + 4 * BPS, 12 + 4 * BPS // V
+};
+
+//------------------------------------------------------------------------------
+// Distortion measurement
+
+static const uint16_t kWeightY[16] = {
+ 38, 32, 20, 9, 32, 28, 17, 7, 20, 17, 10, 4, 9, 7, 4, 2
+};
+
+static const uint16_t kWeightTrellis[16] = {
+#if USE_TDISTO == 0
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16
+#else
+ 30, 27, 19, 11,
+ 27, 24, 17, 10,
+ 19, 17, 12, 8,
+ 11, 10, 8, 6
+#endif
+};
+
+// Init/Copy the common fields in score.
+static void InitScore(VP8ModeScore* const rd) {
+ rd->D = 0;
+ rd->SD = 0;
+ rd->R = 0;
+ rd->nz = 0;
+ rd->score = MAX_COST;
+}
+
+static void CopyScore(VP8ModeScore* const dst, const VP8ModeScore* const src) {
+ dst->D = src->D;
+ dst->SD = src->SD;
+ dst->R = src->R;
+ dst->nz = src->nz; // note that nz is not accumulated, but just copied.
+ dst->score = src->score;
+}
+
+static void AddScore(VP8ModeScore* const dst, const VP8ModeScore* const src) {
+ dst->D += src->D;
+ dst->SD += src->SD;
+ dst->R += src->R;
+ dst->nz |= src->nz; // here, new nz bits are accumulated.
+ dst->score += src->score;
+}
+
+//------------------------------------------------------------------------------
+// Performs trellis-optimized quantization.
+
+// Trellis
+
+typedef struct {
+ int prev; // best previous
+ int level; // level
+ int sign; // sign of coeff_i
+ score_t cost; // bit cost
+ score_t error; // distortion = sum of (|coeff_i| - level_i * Q_i)^2
+ int ctx; // context (only depends on 'level'. Could be spared.)
+} Node;
+
+// If a coefficient was quantized to a value Q (using a neutral bias),
+// we test all alternate possibilities between [Q-MIN_DELTA, Q+MAX_DELTA]
+// We don't test negative values though.
+#define MIN_DELTA 0 // how much lower level to try
+#define MAX_DELTA 1 // how much higher
+#define NUM_NODES (MIN_DELTA + 1 + MAX_DELTA)
+#define NODE(n, l) (nodes[(n) + 1][(l) + MIN_DELTA])
+
+static WEBP_INLINE void SetRDScore(int lambda, VP8ModeScore* const rd) {
+ // TODO: incorporate the "* 256" in the tables?
+ rd->score = rd->R * lambda + 256 * (rd->D + rd->SD);
+}
+
+static WEBP_INLINE score_t RDScoreTrellis(int lambda, score_t rate,
+ score_t distortion) {
+ return rate * lambda + 256 * distortion;
+}
+
+static int TrellisQuantizeBlock(const VP8EncIterator* const it,
+ int16_t in[16], int16_t out[16],
+ int ctx0, int coeff_type,
+ const VP8Matrix* const mtx,
+ int lambda) {
+ ProbaArray* const last_costs = it->enc_->proba_.coeffs_[coeff_type];
+ CostArray* const costs = it->enc_->proba_.level_cost_[coeff_type];
+ const int first = (coeff_type == 0) ? 1 : 0;
+ Node nodes[17][NUM_NODES];
+ int best_path[3] = {-1, -1, -1}; // store best-last/best-level/best-previous
+ score_t best_score;
+ int best_node;
+ int last = first - 1;
+ int n, m, p, nz;
+
+ {
+ score_t cost;
+ score_t max_error;
+ const int thresh = mtx->q_[1] * mtx->q_[1] / 4;
+ const int last_proba = last_costs[VP8EncBands[first]][ctx0][0];
+
+ // compute maximal distortion.
+ max_error = 0;
+ for (n = first; n < 16; ++n) {
+ const int j = kZigzag[n];
+ const int err = in[j] * in[j];
+ max_error += kWeightTrellis[j] * err;
+ if (err > thresh) last = n;
+ }
+ // we don't need to go inspect up to n = 16 coeffs. We can just go up
+ // to last + 1 (inclusive) without losing much.
+ if (last < 15) ++last;
+
+ // compute 'skip' score. This is the max score one can do.
+ cost = VP8BitCost(0, last_proba);
+ best_score = RDScoreTrellis(lambda, cost, max_error);
+
+ // initialize source node.
+ n = first - 1;
+ for (m = -MIN_DELTA; m <= MAX_DELTA; ++m) {
+ NODE(n, m).cost = 0;
+ NODE(n, m).error = max_error;
+ NODE(n, m).ctx = ctx0;
+ }
+ }
+
+ // traverse trellis.
+ for (n = first; n <= last; ++n) {
+ const int j = kZigzag[n];
+ const int Q = mtx->q_[j];
+ const int iQ = mtx->iq_[j];
+ const int B = BIAS(0x00); // neutral bias
+ // note: it's important to take sign of the _original_ coeff,
+ // so we don't have to consider level < 0 afterward.
+ const int sign = (in[j] < 0);
+ int coeff0 = (sign ? -in[j] : in[j]) + mtx->sharpen_[j];
+ int level0;
+ if (coeff0 > 2047) coeff0 = 2047;
+
+ level0 = QUANTDIV(coeff0, iQ, B);
+ // test all alternate level values around level0.
+ for (m = -MIN_DELTA; m <= MAX_DELTA; ++m) {
+ Node* const cur = &NODE(n, m);
+ int delta_error, new_error;
+ score_t cur_score = MAX_COST;
+ int level = level0 + m;
+ int last_proba;
+
+ cur->sign = sign;
+ cur->level = level;
+ cur->ctx = (level == 0) ? 0 : (level == 1) ? 1 : 2;
+ if (level >= 2048 || level < 0) { // node is dead?
+ cur->cost = MAX_COST;
+ continue;
+ }
+ last_proba = last_costs[VP8EncBands[n + 1]][cur->ctx][0];
+
+ // Compute delta_error = how much coding this level will
+ // subtract as distortion to max_error
+ new_error = coeff0 - level * Q;
+ delta_error =
+ kWeightTrellis[j] * (coeff0 * coeff0 - new_error * new_error);
+
+ // Inspect all possible non-dead predecessors. Retain only the best one.
+ for (p = -MIN_DELTA; p <= MAX_DELTA; ++p) {
+ const Node* const prev = &NODE(n - 1, p);
+ const int prev_ctx = prev->ctx;
+ const uint16_t* const tcost = costs[VP8EncBands[n]][prev_ctx];
+ const score_t total_error = prev->error - delta_error;
+ score_t cost, base_cost, score;
+
+ if (prev->cost >= MAX_COST) { // dead node?
+ continue;
+ }
+
+ // Base cost of both terminal/non-terminal
+ base_cost = prev->cost + VP8LevelCost(tcost, level);
+
+ // Examine node assuming it's a non-terminal one.
+ cost = base_cost;
+ if (level && n < 15) {
+ cost += VP8BitCost(1, last_proba);
+ }
+ score = RDScoreTrellis(lambda, cost, total_error);
+ if (score < cur_score) {
+ cur_score = score;
+ cur->cost = cost;
+ cur->error = total_error;
+ cur->prev = p;
+ }
+
+ // Now, record best terminal node (and thus best entry in the graph).
+ if (level) {
+ cost = base_cost;
+ if (n < 15) cost += VP8BitCost(0, last_proba);
+ score = RDScoreTrellis(lambda, cost, total_error);
+ if (score < best_score) {
+ best_score = score;
+ best_path[0] = n; // best eob position
+ best_path[1] = m; // best level
+ best_path[2] = p; // best predecessor
+ }
+ }
+ }
+ }
+ }
+
+ // Fresh start
+ memset(in + first, 0, (16 - first) * sizeof(*in));
+ memset(out + first, 0, (16 - first) * sizeof(*out));
+ if (best_path[0] == -1) {
+ return 0; // skip!
+ }
+
+ // Unwind the best path.
+ // Note: best-prev on terminal node is not necessarily equal to the
+ // best_prev for non-terminal. So we patch best_path[2] in.
+ n = best_path[0];
+ best_node = best_path[1];
+ NODE(n, best_node).prev = best_path[2]; // force best-prev for terminal
+ nz = 0;
+
+ for (; n >= first; --n) {
+ const Node* const node = &NODE(n, best_node);
+ const int j = kZigzag[n];
+ out[n] = node->sign ? -node->level : node->level;
+ nz |= (node->level != 0);
+ in[j] = out[n] * mtx->q_[j];
+ best_node = node->prev;
+ }
+ return nz;
+}
+
+#undef NODE
+
+//------------------------------------------------------------------------------
+// Performs: difference, transform, quantize, back-transform, add
+// all at once. Output is the reconstructed block in *yuv_out, and the
+// quantized levels in *levels.
+
+static int ReconstructIntra16(VP8EncIterator* const it,
+ VP8ModeScore* const rd,
+ uint8_t* const yuv_out,
+ int mode) {
+ const VP8Encoder* const enc = it->enc_;
+ const uint8_t* const ref = it->yuv_p_ + VP8I16ModeOffsets[mode];
+ const uint8_t* const src = it->yuv_in_ + Y_OFF;
+ const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_];
+ int nz = 0;
+ int n;
+ int16_t tmp[16][16], dc_tmp[16];
+
+ for (n = 0; n < 16; ++n) {
+ VP8FTransform(src + VP8Scan[n], ref + VP8Scan[n], tmp[n]);
+ }
+ VP8FTransformWHT(tmp[0], dc_tmp);
+ nz |= VP8EncQuantizeBlock(dc_tmp, rd->y_dc_levels, 0, &dqm->y2_) << 24;
+
+ if (DO_TRELLIS_I16 && it->do_trellis_) {
+ int x, y;
+ VP8IteratorNzToBytes(it);
+ for (y = 0, n = 0; y < 4; ++y) {
+ for (x = 0; x < 4; ++x, ++n) {
+ const int ctx = it->top_nz_[x] + it->left_nz_[y];
+ const int non_zero =
+ TrellisQuantizeBlock(it, tmp[n], rd->y_ac_levels[n], ctx, 0,
+ &dqm->y1_, dqm->lambda_trellis_i16_);
+ it->top_nz_[x] = it->left_nz_[y] = non_zero;
+ nz |= non_zero << n;
+ }
+ }
+ } else {
+ for (n = 0; n < 16; ++n) {
+ nz |= VP8EncQuantizeBlock(tmp[n], rd->y_ac_levels[n], 1, &dqm->y1_) << n;
+ }
+ }
+
+ // Transform back
+ VP8ITransformWHT(dc_tmp, tmp[0]);
+ for (n = 0; n < 16; n += 2) {
+ VP8ITransform(ref + VP8Scan[n], tmp[n], yuv_out + VP8Scan[n], 1);
+ }
+
+ return nz;
+}
+
+static int ReconstructIntra4(VP8EncIterator* const it,
+ int16_t levels[16],
+ const uint8_t* const src,
+ uint8_t* const yuv_out,
+ int mode) {
+ const VP8Encoder* const enc = it->enc_;
+ const uint8_t* const ref = it->yuv_p_ + VP8I4ModeOffsets[mode];
+ const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_];
+ int nz = 0;
+ int16_t tmp[16];
+
+ VP8FTransform(src, ref, tmp);
+ if (DO_TRELLIS_I4 && it->do_trellis_) {
+ const int x = it->i4_ & 3, y = it->i4_ >> 2;
+ const int ctx = it->top_nz_[x] + it->left_nz_[y];
+ nz = TrellisQuantizeBlock(it, tmp, levels, ctx, 3, &dqm->y1_,
+ dqm->lambda_trellis_i4_);
+ } else {
+ nz = VP8EncQuantizeBlock(tmp, levels, 0, &dqm->y1_);
+ }
+ VP8ITransform(ref, tmp, yuv_out, 0);
+ return nz;
+}
+
+static int ReconstructUV(VP8EncIterator* const it, VP8ModeScore* const rd,
+ uint8_t* const yuv_out, int mode) {
+ const VP8Encoder* const enc = it->enc_;
+ const uint8_t* const ref = it->yuv_p_ + VP8UVModeOffsets[mode];
+ const uint8_t* const src = it->yuv_in_ + U_OFF;
+ const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_];
+ int nz = 0;
+ int n;
+ int16_t tmp[8][16];
+
+ for (n = 0; n < 8; ++n) {
+ VP8FTransform(src + VP8Scan[16 + n], ref + VP8Scan[16 + n], tmp[n]);
+ }
+ if (DO_TRELLIS_UV && it->do_trellis_) {
+ int ch, x, y;
+ for (ch = 0, n = 0; ch <= 2; ch += 2) {
+ for (y = 0; y < 2; ++y) {
+ for (x = 0; x < 2; ++x, ++n) {
+ const int ctx = it->top_nz_[4 + ch + x] + it->left_nz_[4 + ch + y];
+ const int non_zero =
+ TrellisQuantizeBlock(it, tmp[n], rd->uv_levels[n], ctx, 2,
+ &dqm->uv_, dqm->lambda_trellis_uv_);
+ it->top_nz_[4 + ch + x] = it->left_nz_[4 + ch + y] = non_zero;
+ nz |= non_zero << n;
+ }
+ }
+ }
+ } else {
+ for (n = 0; n < 8; ++n) {
+ nz |= VP8EncQuantizeBlock(tmp[n], rd->uv_levels[n], 0, &dqm->uv_) << n;
+ }
+ }
+
+ for (n = 0; n < 8; n += 2) {
+ VP8ITransform(ref + VP8Scan[16 + n], tmp[n], yuv_out + VP8Scan[16 + n], 1);
+ }
+ return (nz << 16);
+}
+
+//------------------------------------------------------------------------------
+// RD-opt decision. Reconstruct each modes, evalue distortion and bit-cost.
+// Pick the mode is lower RD-cost = Rate + lamba * Distortion.
+
+static void SwapPtr(uint8_t** a, uint8_t** b) {
+ uint8_t* const tmp = *a;
+ *a = *b;
+ *b = tmp;
+}
+
+static void SwapOut(VP8EncIterator* const it) {
+ SwapPtr(&it->yuv_out_, &it->yuv_out2_);
+}
+
+static void PickBestIntra16(VP8EncIterator* const it, VP8ModeScore* const rd) {
+ const VP8Encoder* const enc = it->enc_;
+ const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_];
+ const int lambda = dqm->lambda_i16_;
+ const int tlambda = dqm->tlambda_;
+ const uint8_t* const src = it->yuv_in_ + Y_OFF;
+ VP8ModeScore rd16;
+ int mode;
+
+ rd->mode_i16 = -1;
+ for (mode = 0; mode < 4; ++mode) {
+ uint8_t* const tmp_dst = it->yuv_out2_ + Y_OFF; // scratch buffer
+ int nz;
+
+ // Reconstruct
+ nz = ReconstructIntra16(it, &rd16, tmp_dst, mode);
+
+ // Measure RD-score
+ rd16.D = VP8SSE16x16(src, tmp_dst);
+ rd16.SD = tlambda ? MULT_8B(tlambda, VP8TDisto16x16(src, tmp_dst, kWeightY))
+ : 0;
+ rd16.R = VP8GetCostLuma16(it, &rd16);
+ rd16.R += VP8FixedCostsI16[mode];
+
+ // Since we always examine Intra16 first, we can overwrite *rd directly.
+ SetRDScore(lambda, &rd16);
+ if (mode == 0 || rd16.score < rd->score) {
+ CopyScore(rd, &rd16);
+ rd->mode_i16 = mode;
+ rd->nz = nz;
+ memcpy(rd->y_ac_levels, rd16.y_ac_levels, sizeof(rd16.y_ac_levels));
+ memcpy(rd->y_dc_levels, rd16.y_dc_levels, sizeof(rd16.y_dc_levels));
+ SwapOut(it);
+ }
+ }
+ SetRDScore(dqm->lambda_mode_, rd); // finalize score for mode decision.
+ VP8SetIntra16Mode(it, rd->mode_i16);
+}
+
+//------------------------------------------------------------------------------
+
+// return the cost array corresponding to the surrounding prediction modes.
+static const uint16_t* GetCostModeI4(VP8EncIterator* const it,
+ const uint8_t modes[16]) {
+ const int preds_w = it->enc_->preds_w_;
+ const int x = (it->i4_ & 3), y = it->i4_ >> 2;
+ const int left = (x == 0) ? it->preds_[y * preds_w - 1] : modes[it->i4_ - 1];
+ const int top = (y == 0) ? it->preds_[-preds_w + x] : modes[it->i4_ - 4];
+ return VP8FixedCostsI4[top][left];
+}
+
+static int PickBestIntra4(VP8EncIterator* const it, VP8ModeScore* const rd) {
+ const VP8Encoder* const enc = it->enc_;
+ const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_];
+ const int lambda = dqm->lambda_i4_;
+ const int tlambda = dqm->tlambda_;
+ const uint8_t* const src0 = it->yuv_in_ + Y_OFF;
+ uint8_t* const best_blocks = it->yuv_out2_ + Y_OFF;
+ int total_header_bits = 0;
+ VP8ModeScore rd_best;
+
+ if (enc->max_i4_header_bits_ == 0) {
+ return 0;
+ }
+
+ InitScore(&rd_best);
+ rd_best.score = 211; // '211' is the value of VP8BitCost(0, 145)
+ VP8IteratorStartI4(it);
+ do {
+ VP8ModeScore rd_i4;
+ int mode;
+ int best_mode = -1;
+ const uint8_t* const src = src0 + VP8Scan[it->i4_];
+ const uint16_t* const mode_costs = GetCostModeI4(it, rd->modes_i4);
+ uint8_t* best_block = best_blocks + VP8Scan[it->i4_];
+ uint8_t* tmp_dst = it->yuv_p_ + I4TMP; // scratch buffer.
+
+ InitScore(&rd_i4);
+ VP8MakeIntra4Preds(it);
+ for (mode = 0; mode < NUM_BMODES; ++mode) {
+ VP8ModeScore rd_tmp;
+ int16_t tmp_levels[16];
+
+ // Reconstruct
+ rd_tmp.nz =
+ ReconstructIntra4(it, tmp_levels, src, tmp_dst, mode) << it->i4_;
+
+ // Compute RD-score
+ rd_tmp.D = VP8SSE4x4(src, tmp_dst);
+ rd_tmp.SD =
+ tlambda ? MULT_8B(tlambda, VP8TDisto4x4(src, tmp_dst, kWeightY))
+ : 0;
+ rd_tmp.R = VP8GetCostLuma4(it, tmp_levels);
+ rd_tmp.R += mode_costs[mode];
+
+ SetRDScore(lambda, &rd_tmp);
+ if (best_mode < 0 || rd_tmp.score < rd_i4.score) {
+ CopyScore(&rd_i4, &rd_tmp);
+ best_mode = mode;
+ SwapPtr(&tmp_dst, &best_block);
+ memcpy(rd_best.y_ac_levels[it->i4_], tmp_levels, sizeof(tmp_levels));
+ }
+ }
+ SetRDScore(dqm->lambda_mode_, &rd_i4);
+ AddScore(&rd_best, &rd_i4);
+ total_header_bits += mode_costs[best_mode];
+ if (rd_best.score >= rd->score ||
+ total_header_bits > enc->max_i4_header_bits_) {
+ return 0;
+ }
+ // Copy selected samples if not in the right place already.
+ if (best_block != best_blocks + VP8Scan[it->i4_])
+ VP8Copy4x4(best_block, best_blocks + VP8Scan[it->i4_]);
+ rd->modes_i4[it->i4_] = best_mode;
+ it->top_nz_[it->i4_ & 3] = it->left_nz_[it->i4_ >> 2] = (rd_i4.nz ? 1 : 0);
+ } while (VP8IteratorRotateI4(it, best_blocks));
+
+ // finalize state
+ CopyScore(rd, &rd_best);
+ VP8SetIntra4Mode(it, rd->modes_i4);
+ SwapOut(it);
+ memcpy(rd->y_ac_levels, rd_best.y_ac_levels, sizeof(rd->y_ac_levels));
+ return 1; // select intra4x4 over intra16x16
+}
+
+//------------------------------------------------------------------------------
+
+static void PickBestUV(VP8EncIterator* const it, VP8ModeScore* const rd) {
+ const VP8Encoder* const enc = it->enc_;
+ const VP8SegmentInfo* const dqm = &enc->dqm_[it->mb_->segment_];
+ const int lambda = dqm->lambda_uv_;
+ const uint8_t* const src = it->yuv_in_ + U_OFF;
+ uint8_t* const tmp_dst = it->yuv_out2_ + U_OFF; // scratch buffer
+ uint8_t* const dst0 = it->yuv_out_ + U_OFF;
+ VP8ModeScore rd_best;
+ int mode;
+
+ rd->mode_uv = -1;
+ InitScore(&rd_best);
+ for (mode = 0; mode < 4; ++mode) {
+ VP8ModeScore rd_uv;
+
+ // Reconstruct
+ rd_uv.nz = ReconstructUV(it, &rd_uv, tmp_dst, mode);
+
+ // Compute RD-score
+ rd_uv.D = VP8SSE16x8(src, tmp_dst);
+ rd_uv.SD = 0; // TODO: should we call TDisto? it tends to flatten areas.
+ rd_uv.R = VP8GetCostUV(it, &rd_uv);
+ rd_uv.R += VP8FixedCostsUV[mode];
+
+ SetRDScore(lambda, &rd_uv);
+ if (mode == 0 || rd_uv.score < rd_best.score) {
+ CopyScore(&rd_best, &rd_uv);
+ rd->mode_uv = mode;
+ memcpy(rd->uv_levels, rd_uv.uv_levels, sizeof(rd->uv_levels));
+ memcpy(dst0, tmp_dst, UV_SIZE); // TODO: SwapUVOut() ?
+ }
+ }
+ VP8SetIntraUVMode(it, rd->mode_uv);
+ AddScore(rd, &rd_best);
+}
+
+//------------------------------------------------------------------------------
+// Final reconstruction and quantization.
+
+static void SimpleQuantize(VP8EncIterator* const it, VP8ModeScore* const rd) {
+ const VP8Encoder* const enc = it->enc_;
+ const int i16 = (it->mb_->type_ == 1);
+ int nz = 0;
+
+ if (i16) {
+ nz = ReconstructIntra16(it, rd, it->yuv_out_ + Y_OFF, it->preds_[0]);
+ } else {
+ VP8IteratorStartI4(it);
+ do {
+ const int mode =
+ it->preds_[(it->i4_ & 3) + (it->i4_ >> 2) * enc->preds_w_];
+ const uint8_t* const src = it->yuv_in_ + Y_OFF + VP8Scan[it->i4_];
+ uint8_t* const dst = it->yuv_out_ + Y_OFF + VP8Scan[it->i4_];
+ VP8MakeIntra4Preds(it);
+ nz |= ReconstructIntra4(it, rd->y_ac_levels[it->i4_],
+ src, dst, mode) << it->i4_;
+ } while (VP8IteratorRotateI4(it, it->yuv_out_ + Y_OFF));
+ }
+
+ nz |= ReconstructUV(it, rd, it->yuv_out_ + U_OFF, it->mb_->uv_mode_);
+ rd->nz = nz;
+}
+
+//------------------------------------------------------------------------------
+// Entry point
+
+int VP8Decimate(VP8EncIterator* const it, VP8ModeScore* const rd, int rd_opt) {
+ int is_skipped;
+
+ InitScore(rd);
+
+ // We can perform predictions for Luma16x16 and Chroma8x8 already.
+ // Luma4x4 predictions needs to be done as-we-go.
+ VP8MakeLuma16Preds(it);
+ VP8MakeChroma8Preds(it);
+
+ // for rd_opt = 2, we perform trellis-quant on the final decision only.
+ // for rd_opt > 2, we use it for every scoring (=much slower).
+ if (rd_opt > 0) {
+ it->do_trellis_ = (rd_opt > 2);
+ PickBestIntra16(it, rd);
+ if (it->enc_->method_ >= 2) {
+ PickBestIntra4(it, rd);
+ }
+ PickBestUV(it, rd);
+ if (rd_opt == 2) {
+ it->do_trellis_ = 1;
+ SimpleQuantize(it, rd);
+ }
+ } else {
+ // TODO: for method_ == 2, pick the best intra4/intra16 based on SSE
+ it->do_trellis_ = (it->enc_->method_ == 2);
+ SimpleQuantize(it, rd);
+ }
+ is_skipped = (rd->nz == 0);
+ VP8SetSkip(it, is_skipped);
+ return is_skipped;
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/enc/syntax.c b/drivers/webpold/enc/syntax.c
new file mode 100644
index 0000000000..4221436ff9
--- /dev/null
+++ b/drivers/webpold/enc/syntax.c
@@ -0,0 +1,437 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Header syntax writing
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <assert.h>
+
+#include "../format_constants.h"
+#include "./vp8enci.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// Helper functions
+
+// TODO(later): Move to webp/format_constants.h?
+static void PutLE24(uint8_t* const data, uint32_t val) {
+ data[0] = (val >> 0) & 0xff;
+ data[1] = (val >> 8) & 0xff;
+ data[2] = (val >> 16) & 0xff;
+}
+
+static void PutLE32(uint8_t* const data, uint32_t val) {
+ PutLE24(data, val);
+ data[3] = (val >> 24) & 0xff;
+}
+
+static int IsVP8XNeeded(const VP8Encoder* const enc) {
+ return !!enc->has_alpha_; // Currently the only case when VP8X is needed.
+ // This could change in the future.
+}
+
+static int PutPaddingByte(const WebPPicture* const pic) {
+
+ const uint8_t pad_byte[1] = { 0 };
+ return !!pic->writer(pad_byte, 1, pic);
+}
+
+//------------------------------------------------------------------------------
+// Writers for header's various pieces (in order of appearance)
+
+static WebPEncodingError PutRIFFHeader(const VP8Encoder* const enc,
+ size_t riff_size) {
+ const WebPPicture* const pic = enc->pic_;
+ uint8_t riff[RIFF_HEADER_SIZE] = {
+ 'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P'
+ };
+ assert(riff_size == (uint32_t)riff_size);
+ PutLE32(riff + TAG_SIZE, (uint32_t)riff_size);
+ if (!pic->writer(riff, sizeof(riff), pic)) {
+ return VP8_ENC_ERROR_BAD_WRITE;
+ }
+ return VP8_ENC_OK;
+}
+
+static WebPEncodingError PutVP8XHeader(const VP8Encoder* const enc) {
+ const WebPPicture* const pic = enc->pic_;
+ uint8_t vp8x[CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE] = {
+ 'V', 'P', '8', 'X'
+ };
+ uint32_t flags = 0;
+
+ assert(IsVP8XNeeded(enc));
+ assert(pic->width >= 1 && pic->height >= 1);
+ assert(pic->width <= MAX_CANVAS_SIZE && pic->height <= MAX_CANVAS_SIZE);
+
+ if (enc->has_alpha_) {
+ flags |= ALPHA_FLAG_BIT;
+ }
+
+ PutLE32(vp8x + TAG_SIZE, VP8X_CHUNK_SIZE);
+ PutLE32(vp8x + CHUNK_HEADER_SIZE, flags);
+ PutLE24(vp8x + CHUNK_HEADER_SIZE + 4, pic->width - 1);
+ PutLE24(vp8x + CHUNK_HEADER_SIZE + 7, pic->height - 1);
+ if(!pic->writer(vp8x, sizeof(vp8x), pic)) {
+ return VP8_ENC_ERROR_BAD_WRITE;
+ }
+ return VP8_ENC_OK;
+}
+
+static WebPEncodingError PutAlphaChunk(const VP8Encoder* const enc) {
+ const WebPPicture* const pic = enc->pic_;
+ uint8_t alpha_chunk_hdr[CHUNK_HEADER_SIZE] = {
+ 'A', 'L', 'P', 'H'
+ };
+
+ assert(enc->has_alpha_);
+
+ // Alpha chunk header.
+ PutLE32(alpha_chunk_hdr + TAG_SIZE, enc->alpha_data_size_);
+ if (!pic->writer(alpha_chunk_hdr, sizeof(alpha_chunk_hdr), pic)) {
+ return VP8_ENC_ERROR_BAD_WRITE;
+ }
+
+ // Alpha chunk data.
+ if (!pic->writer(enc->alpha_data_, enc->alpha_data_size_, pic)) {
+ return VP8_ENC_ERROR_BAD_WRITE;
+ }
+
+ // Padding.
+ if ((enc->alpha_data_size_ & 1) && !PutPaddingByte(pic)) {
+ return VP8_ENC_ERROR_BAD_WRITE;
+ }
+ return VP8_ENC_OK;
+}
+
+static WebPEncodingError PutVP8Header(const WebPPicture* const pic,
+ size_t vp8_size) {
+ uint8_t vp8_chunk_hdr[CHUNK_HEADER_SIZE] = {
+ 'V', 'P', '8', ' '
+ };
+ assert(vp8_size == (uint32_t)vp8_size);
+ PutLE32(vp8_chunk_hdr + TAG_SIZE, (uint32_t)vp8_size);
+ if (!pic->writer(vp8_chunk_hdr, sizeof(vp8_chunk_hdr), pic)) {
+ return VP8_ENC_ERROR_BAD_WRITE;
+ }
+ return VP8_ENC_OK;
+}
+
+static WebPEncodingError PutVP8FrameHeader(const WebPPicture* const pic,
+ int profile, size_t size0) {
+ uint8_t vp8_frm_hdr[VP8_FRAME_HEADER_SIZE];
+ uint32_t bits;
+
+ if (size0 >= VP8_MAX_PARTITION0_SIZE) { // partition #0 is too big to fit
+ return VP8_ENC_ERROR_PARTITION0_OVERFLOW;
+ }
+
+ // Paragraph 9.1.
+ bits = 0 // keyframe (1b)
+ | (profile << 1) // profile (3b)
+ | (1 << 4) // visible (1b)
+ | ((uint32_t)size0 << 5); // partition length (19b)
+ vp8_frm_hdr[0] = (bits >> 0) & 0xff;
+ vp8_frm_hdr[1] = (bits >> 8) & 0xff;
+ vp8_frm_hdr[2] = (bits >> 16) & 0xff;
+ // signature
+ vp8_frm_hdr[3] = (VP8_SIGNATURE >> 16) & 0xff;
+ vp8_frm_hdr[4] = (VP8_SIGNATURE >> 8) & 0xff;
+ vp8_frm_hdr[5] = (VP8_SIGNATURE >> 0) & 0xff;
+ // dimensions
+ vp8_frm_hdr[6] = pic->width & 0xff;
+ vp8_frm_hdr[7] = pic->width >> 8;
+ vp8_frm_hdr[8] = pic->height & 0xff;
+ vp8_frm_hdr[9] = pic->height >> 8;
+
+ if (!pic->writer(vp8_frm_hdr, sizeof(vp8_frm_hdr), pic)) {
+ return VP8_ENC_ERROR_BAD_WRITE;
+ }
+ return VP8_ENC_OK;
+}
+
+// WebP Headers.
+static int PutWebPHeaders(const VP8Encoder* const enc, size_t size0,
+ size_t vp8_size, size_t riff_size) {
+ WebPPicture* const pic = enc->pic_;
+ WebPEncodingError err = VP8_ENC_OK;
+
+ // RIFF header.
+ err = PutRIFFHeader(enc, riff_size);
+ if (err != VP8_ENC_OK) goto Error;
+
+ // VP8X.
+ if (IsVP8XNeeded(enc)) {
+ err = PutVP8XHeader(enc);
+ if (err != VP8_ENC_OK) goto Error;
+ }
+
+ // Alpha.
+ if (enc->has_alpha_) {
+ err = PutAlphaChunk(enc);
+ if (err != VP8_ENC_OK) goto Error;
+ }
+
+ // VP8 header.
+ err = PutVP8Header(pic, vp8_size);
+ if (err != VP8_ENC_OK) goto Error;
+
+ // VP8 frame header.
+ err = PutVP8FrameHeader(pic, enc->profile_, size0);
+ if (err != VP8_ENC_OK) goto Error;
+
+ // All OK.
+ return 1;
+
+ // Error.
+ Error:
+ return WebPEncodingSetError(pic, err);
+}
+
+// Segmentation header
+static void PutSegmentHeader(VP8BitWriter* const bw,
+ const VP8Encoder* const enc) {
+ const VP8SegmentHeader* const hdr = &enc->segment_hdr_;
+ const VP8Proba* const proba = &enc->proba_;
+ if (VP8PutBitUniform(bw, (hdr->num_segments_ > 1))) {
+ // We always 'update' the quant and filter strength values
+ const int update_data = 1;
+ int s;
+ VP8PutBitUniform(bw, hdr->update_map_);
+ if (VP8PutBitUniform(bw, update_data)) {
+ // we always use absolute values, not relative ones
+ VP8PutBitUniform(bw, 1); // (segment_feature_mode = 1. Paragraph 9.3.)
+ for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
+ VP8PutSignedValue(bw, enc->dqm_[s].quant_, 7);
+ }
+ for (s = 0; s < NUM_MB_SEGMENTS; ++s) {
+ VP8PutSignedValue(bw, enc->dqm_[s].fstrength_, 6);
+ }
+ }
+ if (hdr->update_map_) {
+ for (s = 0; s < 3; ++s) {
+ if (VP8PutBitUniform(bw, (proba->segments_[s] != 255u))) {
+ VP8PutValue(bw, proba->segments_[s], 8);
+ }
+ }
+ }
+ }
+}
+
+// Filtering parameters header
+static void PutFilterHeader(VP8BitWriter* const bw,
+ const VP8FilterHeader* const hdr) {
+ const int use_lf_delta = (hdr->i4x4_lf_delta_ != 0);
+ VP8PutBitUniform(bw, hdr->simple_);
+ VP8PutValue(bw, hdr->level_, 6);
+ VP8PutValue(bw, hdr->sharpness_, 3);
+ if (VP8PutBitUniform(bw, use_lf_delta)) {
+ // '0' is the default value for i4x4_lf_delta_ at frame #0.
+ const int need_update = (hdr->i4x4_lf_delta_ != 0);
+ if (VP8PutBitUniform(bw, need_update)) {
+ // we don't use ref_lf_delta => emit four 0 bits
+ VP8PutValue(bw, 0, 4);
+ // we use mode_lf_delta for i4x4
+ VP8PutSignedValue(bw, hdr->i4x4_lf_delta_, 6);
+ VP8PutValue(bw, 0, 3); // all others unused
+ }
+ }
+}
+
+// Nominal quantization parameters
+static void PutQuant(VP8BitWriter* const bw,
+ const VP8Encoder* const enc) {
+ VP8PutValue(bw, enc->base_quant_, 7);
+ VP8PutSignedValue(bw, enc->dq_y1_dc_, 4);
+ VP8PutSignedValue(bw, enc->dq_y2_dc_, 4);
+ VP8PutSignedValue(bw, enc->dq_y2_ac_, 4);
+ VP8PutSignedValue(bw, enc->dq_uv_dc_, 4);
+ VP8PutSignedValue(bw, enc->dq_uv_ac_, 4);
+}
+
+// Partition sizes
+static int EmitPartitionsSize(const VP8Encoder* const enc,
+ WebPPicture* const pic) {
+ uint8_t buf[3 * (MAX_NUM_PARTITIONS - 1)];
+ int p;
+ for (p = 0; p < enc->num_parts_ - 1; ++p) {
+ const size_t part_size = VP8BitWriterSize(enc->parts_ + p);
+ if (part_size >= VP8_MAX_PARTITION_SIZE) {
+ return WebPEncodingSetError(pic, VP8_ENC_ERROR_PARTITION_OVERFLOW);
+ }
+ buf[3 * p + 0] = (part_size >> 0) & 0xff;
+ buf[3 * p + 1] = (part_size >> 8) & 0xff;
+ buf[3 * p + 2] = (part_size >> 16) & 0xff;
+ }
+ return p ? pic->writer(buf, 3 * p, pic) : 1;
+}
+
+//------------------------------------------------------------------------------
+
+#ifdef WEBP_EXPERIMENTAL_FEATURES
+
+#define KTRAILER_SIZE 8
+
+static int WriteExtensions(VP8Encoder* const enc) {
+ uint8_t buffer[KTRAILER_SIZE];
+ VP8BitWriter* const bw = &enc->bw_;
+ WebPPicture* const pic = enc->pic_;
+
+ // Layer (bytes 0..3)
+ PutLE24(buffer + 0, enc->layer_data_size_);
+ buffer[3] = enc->pic_->colorspace & WEBP_CSP_UV_MASK;
+ if (enc->layer_data_size_ > 0) {
+ assert(enc->use_layer_);
+ // append layer data to last partition
+ if (!VP8BitWriterAppend(&enc->parts_[enc->num_parts_ - 1],
+ enc->layer_data_, enc->layer_data_size_)) {
+ return WebPEncodingSetError(pic, VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY);
+ }
+ }
+
+ buffer[KTRAILER_SIZE - 1] = 0x01; // marker
+ if (!VP8BitWriterAppend(bw, buffer, KTRAILER_SIZE)) {
+ return WebPEncodingSetError(pic, VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY);
+ }
+ return 1;
+}
+
+#endif /* WEBP_EXPERIMENTAL_FEATURES */
+
+//------------------------------------------------------------------------------
+
+static size_t GeneratePartition0(VP8Encoder* const enc) {
+ VP8BitWriter* const bw = &enc->bw_;
+ const int mb_size = enc->mb_w_ * enc->mb_h_;
+ uint64_t pos1, pos2, pos3;
+#ifdef WEBP_EXPERIMENTAL_FEATURES
+ const int need_extensions = enc->use_layer_;
+#endif
+
+ pos1 = VP8BitWriterPos(bw);
+ VP8BitWriterInit(bw, mb_size * 7 / 8); // ~7 bits per macroblock
+#ifdef WEBP_EXPERIMENTAL_FEATURES
+ VP8PutBitUniform(bw, need_extensions); // extensions
+#else
+ VP8PutBitUniform(bw, 0); // colorspace
+#endif
+ VP8PutBitUniform(bw, 0); // clamp type
+
+ PutSegmentHeader(bw, enc);
+ PutFilterHeader(bw, &enc->filter_hdr_);
+ VP8PutValue(bw, enc->config_->partitions, 2);
+ PutQuant(bw, enc);
+ VP8PutBitUniform(bw, 0); // no proba update
+ VP8WriteProbas(bw, &enc->proba_);
+ pos2 = VP8BitWriterPos(bw);
+ VP8CodeIntraModes(enc);
+ VP8BitWriterFinish(bw);
+
+#ifdef WEBP_EXPERIMENTAL_FEATURES
+ if (need_extensions && !WriteExtensions(enc)) {
+ return 0;
+ }
+#endif
+
+ pos3 = VP8BitWriterPos(bw);
+
+ if (enc->pic_->stats) {
+ enc->pic_->stats->header_bytes[0] = (int)((pos2 - pos1 + 7) >> 3);
+ enc->pic_->stats->header_bytes[1] = (int)((pos3 - pos2 + 7) >> 3);
+ enc->pic_->stats->alpha_data_size = (int)enc->alpha_data_size_;
+ enc->pic_->stats->layer_data_size = (int)enc->layer_data_size_;
+ }
+ return !bw->error_;
+}
+
+void VP8EncFreeBitWriters(VP8Encoder* const enc) {
+ int p;
+ VP8BitWriterWipeOut(&enc->bw_);
+ for (p = 0; p < enc->num_parts_; ++p) {
+ VP8BitWriterWipeOut(enc->parts_ + p);
+ }
+}
+
+int VP8EncWrite(VP8Encoder* const enc) {
+ WebPPicture* const pic = enc->pic_;
+ VP8BitWriter* const bw = &enc->bw_;
+ const int task_percent = 19;
+ const int percent_per_part = task_percent / enc->num_parts_;
+ const int final_percent = enc->percent_ + task_percent;
+ int ok = 0;
+ size_t vp8_size, pad, riff_size;
+ int p;
+
+ // Partition #0 with header and partition sizes
+ ok = !!GeneratePartition0(enc);
+
+ // Compute VP8 size
+ vp8_size = VP8_FRAME_HEADER_SIZE +
+ VP8BitWriterSize(bw) +
+ 3 * (enc->num_parts_ - 1);
+ for (p = 0; p < enc->num_parts_; ++p) {
+ vp8_size += VP8BitWriterSize(enc->parts_ + p);
+ }
+ pad = vp8_size & 1;
+ vp8_size += pad;
+
+ // Compute RIFF size
+ // At the minimum it is: "WEBPVP8 nnnn" + VP8 data size.
+ riff_size = TAG_SIZE + CHUNK_HEADER_SIZE + vp8_size;
+ if (IsVP8XNeeded(enc)) { // Add size for: VP8X header + data.
+ riff_size += CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE;
+ }
+ if (enc->has_alpha_) { // Add size for: ALPH header + data.
+ const uint32_t padded_alpha_size = enc->alpha_data_size_ +
+ (enc->alpha_data_size_ & 1);
+ riff_size += CHUNK_HEADER_SIZE + padded_alpha_size;
+ }
+ // Sanity check.
+ if (riff_size > 0xfffffffeU) {
+ return WebPEncodingSetError(pic, VP8_ENC_ERROR_FILE_TOO_BIG);
+ }
+
+ // Emit headers and partition #0
+ {
+ const uint8_t* const part0 = VP8BitWriterBuf(bw);
+ const size_t size0 = VP8BitWriterSize(bw);
+ ok = ok && PutWebPHeaders(enc, size0, vp8_size, riff_size)
+ && pic->writer(part0, size0, pic)
+ && EmitPartitionsSize(enc, pic);
+ VP8BitWriterWipeOut(bw); // will free the internal buffer.
+ }
+
+ // Token partitions
+ for (p = 0; p < enc->num_parts_; ++p) {
+ const uint8_t* const buf = VP8BitWriterBuf(enc->parts_ + p);
+ const size_t size = VP8BitWriterSize(enc->parts_ + p);
+ if (size)
+ ok = ok && pic->writer(buf, size, pic);
+ VP8BitWriterWipeOut(enc->parts_ + p); // will free the internal buffer.
+ ok = ok && WebPReportProgress(pic, enc->percent_ + percent_per_part,
+ &enc->percent_);
+ }
+
+ // Padding byte
+ if (ok && pad) {
+ ok = PutPaddingByte(pic);
+ }
+
+ enc->coded_size_ = (int)(CHUNK_HEADER_SIZE + riff_size);
+ ok = ok && WebPReportProgress(pic, final_percent, &enc->percent_);
+ return ok;
+}
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/enc/tree.c b/drivers/webpold/enc/tree.c
new file mode 100644
index 0000000000..8b25e5e488
--- /dev/null
+++ b/drivers/webpold/enc/tree.c
@@ -0,0 +1,510 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Token probabilities
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./vp8enci.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// Default probabilities
+
+// Paragraph 13.5
+const uint8_t
+ VP8CoeffsProba0[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS] = {
+ // genereated using vp8_default_coef_probs() in entropy.c:129
+ { { { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }
+ },
+ { { 253, 136, 254, 255, 228, 219, 128, 128, 128, 128, 128 },
+ { 189, 129, 242, 255, 227, 213, 255, 219, 128, 128, 128 },
+ { 106, 126, 227, 252, 214, 209, 255, 255, 128, 128, 128 }
+ },
+ { { 1, 98, 248, 255, 236, 226, 255, 255, 128, 128, 128 },
+ { 181, 133, 238, 254, 221, 234, 255, 154, 128, 128, 128 },
+ { 78, 134, 202, 247, 198, 180, 255, 219, 128, 128, 128 },
+ },
+ { { 1, 185, 249, 255, 243, 255, 128, 128, 128, 128, 128 },
+ { 184, 150, 247, 255, 236, 224, 128, 128, 128, 128, 128 },
+ { 77, 110, 216, 255, 236, 230, 128, 128, 128, 128, 128 },
+ },
+ { { 1, 101, 251, 255, 241, 255, 128, 128, 128, 128, 128 },
+ { 170, 139, 241, 252, 236, 209, 255, 255, 128, 128, 128 },
+ { 37, 116, 196, 243, 228, 255, 255, 255, 128, 128, 128 }
+ },
+ { { 1, 204, 254, 255, 245, 255, 128, 128, 128, 128, 128 },
+ { 207, 160, 250, 255, 238, 128, 128, 128, 128, 128, 128 },
+ { 102, 103, 231, 255, 211, 171, 128, 128, 128, 128, 128 }
+ },
+ { { 1, 152, 252, 255, 240, 255, 128, 128, 128, 128, 128 },
+ { 177, 135, 243, 255, 234, 225, 128, 128, 128, 128, 128 },
+ { 80, 129, 211, 255, 194, 224, 128, 128, 128, 128, 128 }
+ },
+ { { 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 246, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 255, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }
+ }
+ },
+ { { { 198, 35, 237, 223, 193, 187, 162, 160, 145, 155, 62 },
+ { 131, 45, 198, 221, 172, 176, 220, 157, 252, 221, 1 },
+ { 68, 47, 146, 208, 149, 167, 221, 162, 255, 223, 128 }
+ },
+ { { 1, 149, 241, 255, 221, 224, 255, 255, 128, 128, 128 },
+ { 184, 141, 234, 253, 222, 220, 255, 199, 128, 128, 128 },
+ { 81, 99, 181, 242, 176, 190, 249, 202, 255, 255, 128 }
+ },
+ { { 1, 129, 232, 253, 214, 197, 242, 196, 255, 255, 128 },
+ { 99, 121, 210, 250, 201, 198, 255, 202, 128, 128, 128 },
+ { 23, 91, 163, 242, 170, 187, 247, 210, 255, 255, 128 }
+ },
+ { { 1, 200, 246, 255, 234, 255, 128, 128, 128, 128, 128 },
+ { 109, 178, 241, 255, 231, 245, 255, 255, 128, 128, 128 },
+ { 44, 130, 201, 253, 205, 192, 255, 255, 128, 128, 128 }
+ },
+ { { 1, 132, 239, 251, 219, 209, 255, 165, 128, 128, 128 },
+ { 94, 136, 225, 251, 218, 190, 255, 255, 128, 128, 128 },
+ { 22, 100, 174, 245, 186, 161, 255, 199, 128, 128, 128 }
+ },
+ { { 1, 182, 249, 255, 232, 235, 128, 128, 128, 128, 128 },
+ { 124, 143, 241, 255, 227, 234, 128, 128, 128, 128, 128 },
+ { 35, 77, 181, 251, 193, 211, 255, 205, 128, 128, 128 }
+ },
+ { { 1, 157, 247, 255, 236, 231, 255, 255, 128, 128, 128 },
+ { 121, 141, 235, 255, 225, 227, 255, 255, 128, 128, 128 },
+ { 45, 99, 188, 251, 195, 217, 255, 224, 128, 128, 128 }
+ },
+ { { 1, 1, 251, 255, 213, 255, 128, 128, 128, 128, 128 },
+ { 203, 1, 248, 255, 255, 128, 128, 128, 128, 128, 128 },
+ { 137, 1, 177, 255, 224, 255, 128, 128, 128, 128, 128 }
+ }
+ },
+ { { { 253, 9, 248, 251, 207, 208, 255, 192, 128, 128, 128 },
+ { 175, 13, 224, 243, 193, 185, 249, 198, 255, 255, 128 },
+ { 73, 17, 171, 221, 161, 179, 236, 167, 255, 234, 128 }
+ },
+ { { 1, 95, 247, 253, 212, 183, 255, 255, 128, 128, 128 },
+ { 239, 90, 244, 250, 211, 209, 255, 255, 128, 128, 128 },
+ { 155, 77, 195, 248, 188, 195, 255, 255, 128, 128, 128 }
+ },
+ { { 1, 24, 239, 251, 218, 219, 255, 205, 128, 128, 128 },
+ { 201, 51, 219, 255, 196, 186, 128, 128, 128, 128, 128 },
+ { 69, 46, 190, 239, 201, 218, 255, 228, 128, 128, 128 }
+ },
+ { { 1, 191, 251, 255, 255, 128, 128, 128, 128, 128, 128 },
+ { 223, 165, 249, 255, 213, 255, 128, 128, 128, 128, 128 },
+ { 141, 124, 248, 255, 255, 128, 128, 128, 128, 128, 128 }
+ },
+ { { 1, 16, 248, 255, 255, 128, 128, 128, 128, 128, 128 },
+ { 190, 36, 230, 255, 236, 255, 128, 128, 128, 128, 128 },
+ { 149, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }
+ },
+ { { 1, 226, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 247, 192, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 240, 128, 255, 128, 128, 128, 128, 128, 128, 128, 128 }
+ },
+ { { 1, 134, 252, 255, 255, 128, 128, 128, 128, 128, 128 },
+ { 213, 62, 250, 255, 255, 128, 128, 128, 128, 128, 128 },
+ { 55, 93, 255, 128, 128, 128, 128, 128, 128, 128, 128 }
+ },
+ { { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128 }
+ }
+ },
+ { { { 202, 24, 213, 235, 186, 191, 220, 160, 240, 175, 255 },
+ { 126, 38, 182, 232, 169, 184, 228, 174, 255, 187, 128 },
+ { 61, 46, 138, 219, 151, 178, 240, 170, 255, 216, 128 }
+ },
+ { { 1, 112, 230, 250, 199, 191, 247, 159, 255, 255, 128 },
+ { 166, 109, 228, 252, 211, 215, 255, 174, 128, 128, 128 },
+ { 39, 77, 162, 232, 172, 180, 245, 178, 255, 255, 128 }
+ },
+ { { 1, 52, 220, 246, 198, 199, 249, 220, 255, 255, 128 },
+ { 124, 74, 191, 243, 183, 193, 250, 221, 255, 255, 128 },
+ { 24, 71, 130, 219, 154, 170, 243, 182, 255, 255, 128 }
+ },
+ { { 1, 182, 225, 249, 219, 240, 255, 224, 128, 128, 128 },
+ { 149, 150, 226, 252, 216, 205, 255, 171, 128, 128, 128 },
+ { 28, 108, 170, 242, 183, 194, 254, 223, 255, 255, 128 }
+ },
+ { { 1, 81, 230, 252, 204, 203, 255, 192, 128, 128, 128 },
+ { 123, 102, 209, 247, 188, 196, 255, 233, 128, 128, 128 },
+ { 20, 95, 153, 243, 164, 173, 255, 203, 128, 128, 128 }
+ },
+ { { 1, 222, 248, 255, 216, 213, 128, 128, 128, 128, 128 },
+ { 168, 175, 246, 252, 235, 205, 255, 255, 128, 128, 128 },
+ { 47, 116, 215, 255, 211, 212, 255, 255, 128, 128, 128 }
+ },
+ { { 1, 121, 236, 253, 212, 214, 255, 255, 128, 128, 128 },
+ { 141, 84, 213, 252, 201, 202, 255, 219, 128, 128, 128 },
+ { 42, 80, 160, 240, 162, 185, 255, 205, 128, 128, 128 }
+ },
+ { { 1, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 244, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 },
+ { 238, 1, 255, 128, 128, 128, 128, 128, 128, 128, 128 }
+ }
+ }
+};
+
+void VP8DefaultProbas(VP8Encoder* const enc) {
+ VP8Proba* const probas = &enc->proba_;
+ probas->use_skip_proba_ = 0;
+ memset(probas->segments_, 255u, sizeof(probas->segments_));
+ memcpy(probas->coeffs_, VP8CoeffsProba0, sizeof(VP8CoeffsProba0));
+ // Note: we could hard-code the level_costs_ corresponding to VP8CoeffsProba0,
+ // but that's ~11k of static data. Better call VP8CalculateLevelCosts() later.
+ probas->dirty_ = 1;
+}
+
+// Paragraph 11.5. 900bytes.
+static const uint8_t kBModesProba[NUM_BMODES][NUM_BMODES][NUM_BMODES - 1] = {
+ { { 231, 120, 48, 89, 115, 113, 120, 152, 112 },
+ { 152, 179, 64, 126, 170, 118, 46, 70, 95 },
+ { 175, 69, 143, 80, 85, 82, 72, 155, 103 },
+ { 56, 58, 10, 171, 218, 189, 17, 13, 152 },
+ { 114, 26, 17, 163, 44, 195, 21, 10, 173 },
+ { 121, 24, 80, 195, 26, 62, 44, 64, 85 },
+ { 144, 71, 10, 38, 171, 213, 144, 34, 26 },
+ { 170, 46, 55, 19, 136, 160, 33, 206, 71 },
+ { 63, 20, 8, 114, 114, 208, 12, 9, 226 },
+ { 81, 40, 11, 96, 182, 84, 29, 16, 36 } },
+ { { 134, 183, 89, 137, 98, 101, 106, 165, 148 },
+ { 72, 187, 100, 130, 157, 111, 32, 75, 80 },
+ { 66, 102, 167, 99, 74, 62, 40, 234, 128 },
+ { 41, 53, 9, 178, 241, 141, 26, 8, 107 },
+ { 74, 43, 26, 146, 73, 166, 49, 23, 157 },
+ { 65, 38, 105, 160, 51, 52, 31, 115, 128 },
+ { 104, 79, 12, 27, 217, 255, 87, 17, 7 },
+ { 87, 68, 71, 44, 114, 51, 15, 186, 23 },
+ { 47, 41, 14, 110, 182, 183, 21, 17, 194 },
+ { 66, 45, 25, 102, 197, 189, 23, 18, 22 } },
+ { { 88, 88, 147, 150, 42, 46, 45, 196, 205 },
+ { 43, 97, 183, 117, 85, 38, 35, 179, 61 },
+ { 39, 53, 200, 87, 26, 21, 43, 232, 171 },
+ { 56, 34, 51, 104, 114, 102, 29, 93, 77 },
+ { 39, 28, 85, 171, 58, 165, 90, 98, 64 },
+ { 34, 22, 116, 206, 23, 34, 43, 166, 73 },
+ { 107, 54, 32, 26, 51, 1, 81, 43, 31 },
+ { 68, 25, 106, 22, 64, 171, 36, 225, 114 },
+ { 34, 19, 21, 102, 132, 188, 16, 76, 124 },
+ { 62, 18, 78, 95, 85, 57, 50, 48, 51 } },
+ { { 193, 101, 35, 159, 215, 111, 89, 46, 111 },
+ { 60, 148, 31, 172, 219, 228, 21, 18, 111 },
+ { 112, 113, 77, 85, 179, 255, 38, 120, 114 },
+ { 40, 42, 1, 196, 245, 209, 10, 25, 109 },
+ { 88, 43, 29, 140, 166, 213, 37, 43, 154 },
+ { 61, 63, 30, 155, 67, 45, 68, 1, 209 },
+ { 100, 80, 8, 43, 154, 1, 51, 26, 71 },
+ { 142, 78, 78, 16, 255, 128, 34, 197, 171 },
+ { 41, 40, 5, 102, 211, 183, 4, 1, 221 },
+ { 51, 50, 17, 168, 209, 192, 23, 25, 82 } },
+ { { 138, 31, 36, 171, 27, 166, 38, 44, 229 },
+ { 67, 87, 58, 169, 82, 115, 26, 59, 179 },
+ { 63, 59, 90, 180, 59, 166, 93, 73, 154 },
+ { 40, 40, 21, 116, 143, 209, 34, 39, 175 },
+ { 47, 15, 16, 183, 34, 223, 49, 45, 183 },
+ { 46, 17, 33, 183, 6, 98, 15, 32, 183 },
+ { 57, 46, 22, 24, 128, 1, 54, 17, 37 },
+ { 65, 32, 73, 115, 28, 128, 23, 128, 205 },
+ { 40, 3, 9, 115, 51, 192, 18, 6, 223 },
+ { 87, 37, 9, 115, 59, 77, 64, 21, 47 } },
+ { { 104, 55, 44, 218, 9, 54, 53, 130, 226 },
+ { 64, 90, 70, 205, 40, 41, 23, 26, 57 },
+ { 54, 57, 112, 184, 5, 41, 38, 166, 213 },
+ { 30, 34, 26, 133, 152, 116, 10, 32, 134 },
+ { 39, 19, 53, 221, 26, 114, 32, 73, 255 },
+ { 31, 9, 65, 234, 2, 15, 1, 118, 73 },
+ { 75, 32, 12, 51, 192, 255, 160, 43, 51 },
+ { 88, 31, 35, 67, 102, 85, 55, 186, 85 },
+ { 56, 21, 23, 111, 59, 205, 45, 37, 192 },
+ { 55, 38, 70, 124, 73, 102, 1, 34, 98 } },
+ { { 125, 98, 42, 88, 104, 85, 117, 175, 82 },
+ { 95, 84, 53, 89, 128, 100, 113, 101, 45 },
+ { 75, 79, 123, 47, 51, 128, 81, 171, 1 },
+ { 57, 17, 5, 71, 102, 57, 53, 41, 49 },
+ { 38, 33, 13, 121, 57, 73, 26, 1, 85 },
+ { 41, 10, 67, 138, 77, 110, 90, 47, 114 },
+ { 115, 21, 2, 10, 102, 255, 166, 23, 6 },
+ { 101, 29, 16, 10, 85, 128, 101, 196, 26 },
+ { 57, 18, 10, 102, 102, 213, 34, 20, 43 },
+ { 117, 20, 15, 36, 163, 128, 68, 1, 26 } },
+ { { 102, 61, 71, 37, 34, 53, 31, 243, 192 },
+ { 69, 60, 71, 38, 73, 119, 28, 222, 37 },
+ { 68, 45, 128, 34, 1, 47, 11, 245, 171 },
+ { 62, 17, 19, 70, 146, 85, 55, 62, 70 },
+ { 37, 43, 37, 154, 100, 163, 85, 160, 1 },
+ { 63, 9, 92, 136, 28, 64, 32, 201, 85 },
+ { 75, 15, 9, 9, 64, 255, 184, 119, 16 },
+ { 86, 6, 28, 5, 64, 255, 25, 248, 1 },
+ { 56, 8, 17, 132, 137, 255, 55, 116, 128 },
+ { 58, 15, 20, 82, 135, 57, 26, 121, 40 } },
+ { { 164, 50, 31, 137, 154, 133, 25, 35, 218 },
+ { 51, 103, 44, 131, 131, 123, 31, 6, 158 },
+ { 86, 40, 64, 135, 148, 224, 45, 183, 128 },
+ { 22, 26, 17, 131, 240, 154, 14, 1, 209 },
+ { 45, 16, 21, 91, 64, 222, 7, 1, 197 },
+ { 56, 21, 39, 155, 60, 138, 23, 102, 213 },
+ { 83, 12, 13, 54, 192, 255, 68, 47, 28 },
+ { 85, 26, 85, 85, 128, 128, 32, 146, 171 },
+ { 18, 11, 7, 63, 144, 171, 4, 4, 246 },
+ { 35, 27, 10, 146, 174, 171, 12, 26, 128 } },
+ { { 190, 80, 35, 99, 180, 80, 126, 54, 45 },
+ { 85, 126, 47, 87, 176, 51, 41, 20, 32 },
+ { 101, 75, 128, 139, 118, 146, 116, 128, 85 },
+ { 56, 41, 15, 176, 236, 85, 37, 9, 62 },
+ { 71, 30, 17, 119, 118, 255, 17, 18, 138 },
+ { 101, 38, 60, 138, 55, 70, 43, 26, 142 },
+ { 146, 36, 19, 30, 171, 255, 97, 27, 20 },
+ { 138, 45, 61, 62, 219, 1, 81, 188, 64 },
+ { 32, 41, 20, 117, 151, 142, 20, 21, 163 },
+ { 112, 19, 12, 61, 195, 128, 48, 4, 24 } }
+};
+
+static int PutI4Mode(VP8BitWriter* const bw, int mode,
+ const uint8_t* const prob) {
+ if (VP8PutBit(bw, mode != B_DC_PRED, prob[0])) {
+ if (VP8PutBit(bw, mode != B_TM_PRED, prob[1])) {
+ if (VP8PutBit(bw, mode != B_VE_PRED, prob[2])) {
+ if (!VP8PutBit(bw, mode >= B_LD_PRED, prob[3])) {
+ if (VP8PutBit(bw, mode != B_HE_PRED, prob[4])) {
+ VP8PutBit(bw, mode != B_RD_PRED, prob[5]);
+ }
+ } else {
+ if (VP8PutBit(bw, mode != B_LD_PRED, prob[6])) {
+ if (VP8PutBit(bw, mode != B_VL_PRED, prob[7])) {
+ VP8PutBit(bw, mode != B_HD_PRED, prob[8]);
+ }
+ }
+ }
+ }
+ }
+ }
+ return mode;
+}
+
+static void PutI16Mode(VP8BitWriter* const bw, int mode) {
+ if (VP8PutBit(bw, (mode == TM_PRED || mode == H_PRED), 156)) {
+ VP8PutBit(bw, mode == TM_PRED, 128); // TM or HE
+ } else {
+ VP8PutBit(bw, mode == V_PRED, 163); // VE or DC
+ }
+}
+
+static void PutUVMode(VP8BitWriter* const bw, int uv_mode) {
+ if (VP8PutBit(bw, uv_mode != DC_PRED, 142)) {
+ if (VP8PutBit(bw, uv_mode != V_PRED, 114)) {
+ VP8PutBit(bw, uv_mode != H_PRED, 183); // else: TM_PRED
+ }
+ }
+}
+
+static void PutSegment(VP8BitWriter* const bw, int s, const uint8_t* p) {
+ if (VP8PutBit(bw, s >= 2, p[0])) p += 1;
+ VP8PutBit(bw, s & 1, p[1]);
+}
+
+void VP8CodeIntraModes(VP8Encoder* const enc) {
+ VP8BitWriter* const bw = &enc->bw_;
+ VP8EncIterator it;
+ VP8IteratorInit(enc, &it);
+ do {
+ const VP8MBInfo* mb = it.mb_;
+ const uint8_t* preds = it.preds_;
+ if (enc->segment_hdr_.update_map_) {
+ PutSegment(bw, mb->segment_, enc->proba_.segments_);
+ }
+ if (enc->proba_.use_skip_proba_) {
+ VP8PutBit(bw, mb->skip_, enc->proba_.skip_proba_);
+ }
+ if (VP8PutBit(bw, (mb->type_ != 0), 145)) { // i16x16
+ PutI16Mode(bw, preds[0]);
+ } else {
+ const int preds_w = enc->preds_w_;
+ const uint8_t* top_pred = preds - preds_w;
+ int x, y;
+ for (y = 0; y < 4; ++y) {
+ int left = preds[-1];
+ for (x = 0; x < 4; ++x) {
+ const uint8_t* const probas = kBModesProba[top_pred[x]][left];
+ left = PutI4Mode(bw, preds[x], probas);
+ }
+ top_pred = preds;
+ preds += preds_w;
+ }
+ }
+ PutUVMode(bw, mb->uv_mode_);
+ } while (VP8IteratorNext(&it, 0));
+}
+
+//------------------------------------------------------------------------------
+// Paragraph 13
+
+const uint8_t
+ VP8CoeffsUpdateProba[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS] = {
+ { { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 176, 246, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 223, 241, 252, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 249, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 244, 252, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 234, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 246, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 239, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 251, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 251, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 254, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 254, 253, 255, 254, 255, 255, 255, 255, 255, 255 },
+ { 250, 255, 254, 255, 254, 255, 255, 255, 255, 255, 255 },
+ { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ }
+ },
+ { { { 217, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 225, 252, 241, 253, 255, 255, 254, 255, 255, 255, 255 },
+ { 234, 250, 241, 250, 253, 255, 253, 254, 255, 255, 255 }
+ },
+ { { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 223, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 238, 253, 254, 254, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 248, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 249, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 253, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 247, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 252, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 253, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ }
+ },
+ { { { 186, 251, 250, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 234, 251, 244, 254, 255, 255, 255, 255, 255, 255, 255 },
+ { 251, 251, 243, 253, 254, 255, 254, 255, 255, 255, 255 }
+ },
+ { { 255, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 236, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 251, 253, 253, 254, 254, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ }
+ },
+ { { { 248, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 250, 254, 252, 254, 255, 255, 255, 255, 255, 255, 255 },
+ { 248, 254, 249, 253, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 246, 253, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 252, 254, 251, 254, 254, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 254, 252, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 248, 254, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 253, 255, 254, 254, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 245, 251, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 253, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 251, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 252, 253, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 252, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 249, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 254, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 255, 253, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 250, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ },
+ { { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 },
+ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 }
+ }
+ }
+};
+
+void VP8WriteProbas(VP8BitWriter* const bw, const VP8Proba* const probas) {
+ int t, b, c, p;
+ for (t = 0; t < NUM_TYPES; ++t) {
+ for (b = 0; b < NUM_BANDS; ++b) {
+ for (c = 0; c < NUM_CTX; ++c) {
+ for (p = 0; p < NUM_PROBAS; ++p) {
+ const uint8_t p0 = probas->coeffs_[t][b][c][p];
+ const int update = (p0 != VP8CoeffsProba0[t][b][c][p]);
+ if (VP8PutBit(bw, update, VP8CoeffsUpdateProba[t][b][c][p])) {
+ VP8PutValue(bw, p0, 8);
+ }
+ }
+ }
+ }
+ }
+ if (VP8PutBitUniform(bw, probas->use_skip_proba_)) {
+ VP8PutValue(bw, probas->skip_proba_, 8);
+ }
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/enc/vp8enci.h b/drivers/webpold/enc/vp8enci.h
new file mode 100644
index 0000000000..936e1c18ce
--- /dev/null
+++ b/drivers/webpold/enc/vp8enci.h
@@ -0,0 +1,525 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// WebP encoder: internal header.
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#ifndef WEBP_ENC_VP8ENCI_H_
+#define WEBP_ENC_VP8ENCI_H_
+
+#include <string.h> // for memcpy()
+#include "../encode.h"
+#include "../dsp/dsp.h"
+#include "../utils/bit_writer.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// Various defines and enums
+
+// version numbers
+#define ENC_MAJ_VERSION 0
+#define ENC_MIN_VERSION 2
+#define ENC_REV_VERSION 0
+
+// size of histogram used by CollectHistogram.
+#define MAX_COEFF_THRESH 64
+
+// intra prediction modes
+enum { B_DC_PRED = 0, // 4x4 modes
+ B_TM_PRED = 1,
+ B_VE_PRED = 2,
+ B_HE_PRED = 3,
+ B_RD_PRED = 4,
+ B_VR_PRED = 5,
+ B_LD_PRED = 6,
+ B_VL_PRED = 7,
+ B_HD_PRED = 8,
+ B_HU_PRED = 9,
+ NUM_BMODES = B_HU_PRED + 1 - B_DC_PRED, // = 10
+
+ // Luma16 or UV modes
+ DC_PRED = B_DC_PRED, V_PRED = B_VE_PRED,
+ H_PRED = B_HE_PRED, TM_PRED = B_TM_PRED
+ };
+
+enum { NUM_MB_SEGMENTS = 4,
+ MAX_NUM_PARTITIONS = 8,
+ NUM_TYPES = 4, // 0: i16-AC, 1: i16-DC, 2:chroma-AC, 3:i4-AC
+ NUM_BANDS = 8,
+ NUM_CTX = 3,
+ NUM_PROBAS = 11,
+ MAX_LF_LEVELS = 64, // Maximum loop filter level
+ MAX_VARIABLE_LEVEL = 67 // last (inclusive) level with variable cost
+ };
+
+// YUV-cache parameters. Cache is 16-pixels wide.
+// The original or reconstructed samples can be accessed using VP8Scan[]
+// The predicted blocks can be accessed using offsets to yuv_p_ and
+// the arrays VP8*ModeOffsets[];
+// +----+ YUV Samples area. See VP8Scan[] for accessing the blocks.
+// Y_OFF |YYYY| <- original samples (enc->yuv_in_)
+// |YYYY|
+// |YYYY|
+// |YYYY|
+// U_OFF |UUVV| V_OFF (=U_OFF + 8)
+// |UUVV|
+// +----+
+// Y_OFF |YYYY| <- compressed/decoded samples ('yuv_out_')
+// |YYYY| There are two buffers like this ('yuv_out_'/'yuv_out2_')
+// |YYYY|
+// |YYYY|
+// U_OFF |UUVV| V_OFF
+// |UUVV|
+// x2 (for yuv_out2_)
+// +----+ Prediction area ('yuv_p_', size = PRED_SIZE)
+// I16DC16 |YYYY| Intra16 predictions (16x16 block each)
+// |YYYY|
+// |YYYY|
+// |YYYY|
+// I16TM16 |YYYY|
+// |YYYY|
+// |YYYY|
+// |YYYY|
+// I16VE16 |YYYY|
+// |YYYY|
+// |YYYY|
+// |YYYY|
+// I16HE16 |YYYY|
+// |YYYY|
+// |YYYY|
+// |YYYY|
+// +----+ Chroma U/V predictions (16x8 block each)
+// C8DC8 |UUVV|
+// |UUVV|
+// C8TM8 |UUVV|
+// |UUVV|
+// C8VE8 |UUVV|
+// |UUVV|
+// C8HE8 |UUVV|
+// |UUVV|
+// +----+ Intra 4x4 predictions (4x4 block each)
+// |YYYY| I4DC4 I4TM4 I4VE4 I4HE4
+// |YYYY| I4RD4 I4VR4 I4LD4 I4VL4
+// |YY..| I4HD4 I4HU4 I4TMP
+// +----+
+#define BPS 16 // this is the common stride
+#define Y_SIZE (BPS * 16)
+#define UV_SIZE (BPS * 8)
+#define YUV_SIZE (Y_SIZE + UV_SIZE)
+#define PRED_SIZE (6 * 16 * BPS + 12 * BPS)
+#define Y_OFF (0)
+#define U_OFF (Y_SIZE)
+#define V_OFF (U_OFF + 8)
+#define ALIGN_CST 15
+#define DO_ALIGN(PTR) ((uintptr_t)((PTR) + ALIGN_CST) & ~ALIGN_CST)
+
+extern const int VP8Scan[16 + 4 + 4]; // in quant.c
+extern const int VP8UVModeOffsets[4]; // in analyze.c
+extern const int VP8I16ModeOffsets[4];
+extern const int VP8I4ModeOffsets[NUM_BMODES];
+
+// Layout of prediction blocks
+// intra 16x16
+#define I16DC16 (0 * 16 * BPS)
+#define I16TM16 (1 * 16 * BPS)
+#define I16VE16 (2 * 16 * BPS)
+#define I16HE16 (3 * 16 * BPS)
+// chroma 8x8, two U/V blocks side by side (hence: 16x8 each)
+#define C8DC8 (4 * 16 * BPS)
+#define C8TM8 (4 * 16 * BPS + 8 * BPS)
+#define C8VE8 (5 * 16 * BPS)
+#define C8HE8 (5 * 16 * BPS + 8 * BPS)
+// intra 4x4
+#define I4DC4 (6 * 16 * BPS + 0)
+#define I4TM4 (6 * 16 * BPS + 4)
+#define I4VE4 (6 * 16 * BPS + 8)
+#define I4HE4 (6 * 16 * BPS + 12)
+#define I4RD4 (6 * 16 * BPS + 4 * BPS + 0)
+#define I4VR4 (6 * 16 * BPS + 4 * BPS + 4)
+#define I4LD4 (6 * 16 * BPS + 4 * BPS + 8)
+#define I4VL4 (6 * 16 * BPS + 4 * BPS + 12)
+#define I4HD4 (6 * 16 * BPS + 8 * BPS + 0)
+#define I4HU4 (6 * 16 * BPS + 8 * BPS + 4)
+#define I4TMP (6 * 16 * BPS + 8 * BPS + 8)
+
+typedef int64_t score_t; // type used for scores, rate, distortion
+#define MAX_COST ((score_t)0x7fffffffffffffLL)
+
+#define QFIX 17
+#define BIAS(b) ((b) << (QFIX - 8))
+// Fun fact: this is the _only_ line where we're actually being lossy and
+// discarding bits.
+static WEBP_INLINE int QUANTDIV(int n, int iQ, int B) {
+ return (n * iQ + B) >> QFIX;
+}
+extern const uint8_t VP8Zigzag[16];
+
+//------------------------------------------------------------------------------
+// Headers
+
+typedef uint32_t proba_t; // 16b + 16b
+typedef uint8_t ProbaArray[NUM_CTX][NUM_PROBAS];
+typedef proba_t StatsArray[NUM_CTX][NUM_PROBAS];
+typedef uint16_t CostArray[NUM_CTX][MAX_VARIABLE_LEVEL + 1];
+typedef double LFStats[NUM_MB_SEGMENTS][MAX_LF_LEVELS]; // filter stats
+
+typedef struct VP8Encoder VP8Encoder;
+
+// segment features
+typedef struct {
+ int num_segments_; // Actual number of segments. 1 segment only = unused.
+ int update_map_; // whether to update the segment map or not.
+ // must be 0 if there's only 1 segment.
+ int size_; // bit-cost for transmitting the segment map
+} VP8SegmentHeader;
+
+// Struct collecting all frame-persistent probabilities.
+typedef struct {
+ uint8_t segments_[3]; // probabilities for segment tree
+ uint8_t skip_proba_; // final probability of being skipped.
+ ProbaArray coeffs_[NUM_TYPES][NUM_BANDS]; // 924 bytes
+ StatsArray stats_[NUM_TYPES][NUM_BANDS]; // 4224 bytes
+ CostArray level_cost_[NUM_TYPES][NUM_BANDS]; // 11.4k
+ int dirty_; // if true, need to call VP8CalculateLevelCosts()
+ int use_skip_proba_; // Note: we always use skip_proba for now.
+ int nb_skip_; // number of skipped blocks
+} VP8Proba;
+
+// Filter parameters. Not actually used in the code (we don't perform
+// the in-loop filtering), but filled from user's config
+typedef struct {
+ int simple_; // filtering type: 0=complex, 1=simple
+ int level_; // base filter level [0..63]
+ int sharpness_; // [0..7]
+ int i4x4_lf_delta_; // delta filter level for i4x4 relative to i16x16
+} VP8FilterHeader;
+
+//------------------------------------------------------------------------------
+// Informations about the macroblocks.
+
+typedef struct {
+ // block type
+ unsigned int type_:2; // 0=i4x4, 1=i16x16
+ unsigned int uv_mode_:2;
+ unsigned int skip_:1;
+ unsigned int segment_:2;
+ uint8_t alpha_; // quantization-susceptibility
+} VP8MBInfo;
+
+typedef struct VP8Matrix {
+ uint16_t q_[16]; // quantizer steps
+ uint16_t iq_[16]; // reciprocals, fixed point.
+ uint16_t bias_[16]; // rounding bias
+ uint16_t zthresh_[16]; // value under which a coefficient is zeroed
+ uint16_t sharpen_[16]; // frequency boosters for slight sharpening
+} VP8Matrix;
+
+typedef struct {
+ VP8Matrix y1_, y2_, uv_; // quantization matrices
+ int alpha_; // quant-susceptibility, range [-127,127]. Zero is neutral.
+ // Lower values indicate a lower risk of blurriness.
+ int beta_; // filter-susceptibility, range [0,255].
+ int quant_; // final segment quantizer.
+ int fstrength_; // final in-loop filtering strength
+ // reactivities
+ int lambda_i16_, lambda_i4_, lambda_uv_;
+ int lambda_mode_, lambda_trellis_, tlambda_;
+ int lambda_trellis_i16_, lambda_trellis_i4_, lambda_trellis_uv_;
+} VP8SegmentInfo;
+
+// Handy transcient struct to accumulate score and info during RD-optimization
+// and mode evaluation.
+typedef struct {
+ score_t D, SD, R, score; // Distortion, spectral distortion, rate, score.
+ int16_t y_dc_levels[16]; // Quantized levels for luma-DC, luma-AC, chroma.
+ int16_t y_ac_levels[16][16];
+ int16_t uv_levels[4 + 4][16];
+ int mode_i16; // mode number for intra16 prediction
+ uint8_t modes_i4[16]; // mode numbers for intra4 predictions
+ int mode_uv; // mode number of chroma prediction
+ uint32_t nz; // non-zero blocks
+} VP8ModeScore;
+
+// Iterator structure to iterate through macroblocks, pointing to the
+// right neighbouring data (samples, predictions, contexts, ...)
+typedef struct {
+ int x_, y_; // current macroblock
+ int y_offset_, uv_offset_; // offset to the luma / chroma planes
+ int y_stride_, uv_stride_; // respective strides
+ uint8_t* yuv_in_; // borrowed from enc_ (for now)
+ uint8_t* yuv_out_; // ''
+ uint8_t* yuv_out2_; // ''
+ uint8_t* yuv_p_; // ''
+ VP8Encoder* enc_; // back-pointer
+ VP8MBInfo* mb_; // current macroblock
+ VP8BitWriter* bw_; // current bit-writer
+ uint8_t* preds_; // intra mode predictors (4x4 blocks)
+ uint32_t* nz_; // non-zero pattern
+ uint8_t i4_boundary_[37]; // 32+5 boundary samples needed by intra4x4
+ uint8_t* i4_top_; // pointer to the current top boundary sample
+ int i4_; // current intra4x4 mode being tested
+ int top_nz_[9]; // top-non-zero context.
+ int left_nz_[9]; // left-non-zero. left_nz[8] is independent.
+ uint64_t bit_count_[4][3]; // bit counters for coded levels.
+ uint64_t luma_bits_; // macroblock bit-cost for luma
+ uint64_t uv_bits_; // macroblock bit-cost for chroma
+ LFStats* lf_stats_; // filter stats (borrowed from enc_)
+ int do_trellis_; // if true, perform extra level optimisation
+ int done_; // true when scan is finished
+ int percent0_; // saved initial progress percent
+} VP8EncIterator;
+
+ // in iterator.c
+// must be called first.
+void VP8IteratorInit(VP8Encoder* const enc, VP8EncIterator* const it);
+// restart a scan.
+void VP8IteratorReset(VP8EncIterator* const it);
+// import samples from source
+void VP8IteratorImport(const VP8EncIterator* const it);
+// export decimated samples
+void VP8IteratorExport(const VP8EncIterator* const it);
+// go to next macroblock. Returns !done_. If *block_to_save is non-null, will
+// save the boundary values to top_/left_ arrays. block_to_save can be
+// it->yuv_out_ or it->yuv_in_.
+int VP8IteratorNext(VP8EncIterator* const it,
+ const uint8_t* const block_to_save);
+// Report progression based on macroblock rows. Return 0 for user-abort request.
+int VP8IteratorProgress(const VP8EncIterator* const it,
+ int final_delta_percent);
+// Intra4x4 iterations
+void VP8IteratorStartI4(VP8EncIterator* const it);
+// returns true if not done.
+int VP8IteratorRotateI4(VP8EncIterator* const it,
+ const uint8_t* const yuv_out);
+
+// Non-zero context setup/teardown
+void VP8IteratorNzToBytes(VP8EncIterator* const it);
+void VP8IteratorBytesToNz(VP8EncIterator* const it);
+
+// Helper functions to set mode properties
+void VP8SetIntra16Mode(const VP8EncIterator* const it, int mode);
+void VP8SetIntra4Mode(const VP8EncIterator* const it, const uint8_t* modes);
+void VP8SetIntraUVMode(const VP8EncIterator* const it, int mode);
+void VP8SetSkip(const VP8EncIterator* const it, int skip);
+void VP8SetSegment(const VP8EncIterator* const it, int segment);
+
+//------------------------------------------------------------------------------
+// Paginated token buffer
+
+// WIP: #define USE_TOKEN_BUFFER
+
+#ifdef USE_TOKEN_BUFFER
+
+#define MAX_NUM_TOKEN 2048
+
+typedef struct VP8Tokens VP8Tokens;
+struct VP8Tokens {
+ uint16_t tokens_[MAX_NUM_TOKEN]; // bit#15: bit, bits 0..14: slot
+ int left_;
+ VP8Tokens* next_;
+};
+
+typedef struct {
+ VP8Tokens* rows_;
+ uint16_t* tokens_; // set to (*last_)->tokens_
+ VP8Tokens** last_;
+ int left_;
+ int error_; // true in case of malloc error
+} VP8TBuffer;
+
+void VP8TBufferInit(VP8TBuffer* const b); // initialize an empty buffer
+int VP8TBufferNewPage(VP8TBuffer* const b); // allocate a new page
+void VP8TBufferClear(VP8TBuffer* const b); // de-allocate memory
+
+int VP8EmitTokens(const VP8TBuffer* const b, VP8BitWriter* const bw,
+ const uint8_t* const probas);
+
+static WEBP_INLINE int VP8AddToken(VP8TBuffer* const b,
+ int bit, int proba_idx) {
+ if (b->left_ > 0 || VP8TBufferNewPage(b)) {
+ const int slot = --b->left_;
+ b->tokens_[slot] = (bit << 15) | proba_idx;
+ }
+ return bit;
+}
+
+#endif // USE_TOKEN_BUFFER
+
+//------------------------------------------------------------------------------
+// VP8Encoder
+
+struct VP8Encoder {
+ const WebPConfig* config_; // user configuration and parameters
+ WebPPicture* pic_; // input / output picture
+
+ // headers
+ VP8FilterHeader filter_hdr_; // filtering information
+ VP8SegmentHeader segment_hdr_; // segment information
+
+ int profile_; // VP8's profile, deduced from Config.
+
+ // dimension, in macroblock units.
+ int mb_w_, mb_h_;
+ int preds_w_; // stride of the *preds_ prediction plane (=4*mb_w + 1)
+
+ // number of partitions (1, 2, 4 or 8 = MAX_NUM_PARTITIONS)
+ int num_parts_;
+
+ // per-partition boolean decoders.
+ VP8BitWriter bw_; // part0
+ VP8BitWriter parts_[MAX_NUM_PARTITIONS]; // token partitions
+
+ int percent_; // for progress
+
+ // transparency blob
+ int has_alpha_;
+ uint8_t* alpha_data_; // non-NULL if transparency is present
+ uint32_t alpha_data_size_;
+
+ // enhancement layer
+ int use_layer_;
+ VP8BitWriter layer_bw_;
+ uint8_t* layer_data_;
+ size_t layer_data_size_;
+
+ // quantization info (one set of DC/AC dequant factor per segment)
+ VP8SegmentInfo dqm_[NUM_MB_SEGMENTS];
+ int base_quant_; // nominal quantizer value. Only used
+ // for relative coding of segments' quant.
+ int uv_alpha_; // U/V quantization susceptibility
+ // global offset of quantizers, shared by all segments
+ int dq_y1_dc_;
+ int dq_y2_dc_, dq_y2_ac_;
+ int dq_uv_dc_, dq_uv_ac_;
+
+ // probabilities and statistics
+ VP8Proba proba_;
+ uint64_t sse_[4]; // sum of Y/U/V/A squared errors for all macroblocks
+ uint64_t sse_count_; // pixel count for the sse_[] stats
+ int coded_size_;
+ int residual_bytes_[3][4];
+ int block_count_[3];
+
+ // quality/speed settings
+ int method_; // 0=fastest, 6=best/slowest.
+ int rd_opt_level_; // Deduced from method_.
+ int max_i4_header_bits_; // partition #0 safeness factor
+
+ // Memory
+ VP8MBInfo* mb_info_; // contextual macroblock infos (mb_w_ + 1)
+ uint8_t* preds_; // predictions modes: (4*mb_w+1) * (4*mb_h+1)
+ uint32_t* nz_; // non-zero bit context: mb_w+1
+ uint8_t* yuv_in_; // input samples
+ uint8_t* yuv_out_; // output samples
+ uint8_t* yuv_out2_; // secondary scratch out-buffer. swapped with yuv_out_.
+ uint8_t* yuv_p_; // scratch buffer for prediction
+ uint8_t *y_top_; // top luma samples.
+ uint8_t *uv_top_; // top u/v samples.
+ // U and V are packed into 16 pixels (8 U + 8 V)
+ uint8_t *y_left_; // left luma samples (adressable from index -1 to 15).
+ uint8_t *u_left_; // left u samples (adressable from index -1 to 7)
+ uint8_t *v_left_; // left v samples (adressable from index -1 to 7)
+
+ LFStats *lf_stats_; // autofilter stats (if NULL, autofilter is off)
+};
+
+//------------------------------------------------------------------------------
+// internal functions. Not public.
+
+ // in tree.c
+extern const uint8_t VP8CoeffsProba0[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS];
+extern const uint8_t
+ VP8CoeffsUpdateProba[NUM_TYPES][NUM_BANDS][NUM_CTX][NUM_PROBAS];
+// Reset the token probabilities to their initial (default) values
+void VP8DefaultProbas(VP8Encoder* const enc);
+// Write the token probabilities
+void VP8WriteProbas(VP8BitWriter* const bw, const VP8Proba* const probas);
+// Writes the partition #0 modes (that is: all intra modes)
+void VP8CodeIntraModes(VP8Encoder* const enc);
+
+ // in syntax.c
+// Generates the final bitstream by coding the partition0 and headers,
+// and appending an assembly of all the pre-coded token partitions.
+// Return true if everything is ok.
+int VP8EncWrite(VP8Encoder* const enc);
+// Release memory allocated for bit-writing in VP8EncLoop & seq.
+void VP8EncFreeBitWriters(VP8Encoder* const enc);
+
+ // in frame.c
+extern const uint8_t VP8EncBands[16 + 1];
+// Form all the four Intra16x16 predictions in the yuv_p_ cache
+void VP8MakeLuma16Preds(const VP8EncIterator* const it);
+// Form all the four Chroma8x8 predictions in the yuv_p_ cache
+void VP8MakeChroma8Preds(const VP8EncIterator* const it);
+// Form all the ten Intra4x4 predictions in the yuv_p_ cache
+// for the 4x4 block it->i4_
+void VP8MakeIntra4Preds(const VP8EncIterator* const it);
+// Rate calculation
+int VP8GetCostLuma16(VP8EncIterator* const it, const VP8ModeScore* const rd);
+int VP8GetCostLuma4(VP8EncIterator* const it, const int16_t levels[16]);
+int VP8GetCostUV(VP8EncIterator* const it, const VP8ModeScore* const rd);
+// Main stat / coding passes
+int VP8EncLoop(VP8Encoder* const enc);
+int VP8StatLoop(VP8Encoder* const enc);
+
+ // in webpenc.c
+// Assign an error code to a picture. Return false for convenience.
+int WebPEncodingSetError(const WebPPicture* const pic, WebPEncodingError error);
+int WebPReportProgress(const WebPPicture* const pic,
+ int percent, int* const percent_store);
+
+ // in analysis.c
+// Main analysis loop. Decides the segmentations and complexity.
+// Assigns a first guess for Intra16 and uvmode_ prediction modes.
+int VP8EncAnalyze(VP8Encoder* const enc);
+
+ // in quant.c
+// Sets up segment's quantization values, base_quant_ and filter strengths.
+void VP8SetSegmentParams(VP8Encoder* const enc, float quality);
+// Pick best modes and fills the levels. Returns true if skipped.
+int VP8Decimate(VP8EncIterator* const it, VP8ModeScore* const rd, int rd_opt);
+
+ // in alpha.c
+void VP8EncInitAlpha(VP8Encoder* const enc); // initialize alpha compression
+int VP8EncFinishAlpha(VP8Encoder* const enc); // finalize compressed data
+void VP8EncDeleteAlpha(VP8Encoder* const enc); // delete compressed data
+
+ // in layer.c
+void VP8EncInitLayer(VP8Encoder* const enc); // init everything
+void VP8EncCodeLayerBlock(VP8EncIterator* it); // code one more macroblock
+int VP8EncFinishLayer(VP8Encoder* const enc); // finalize coding
+void VP8EncDeleteLayer(VP8Encoder* enc); // reclaim memory
+
+ // in filter.c
+
+// SSIM utils
+typedef struct {
+ double w, xm, ym, xxm, xym, yym;
+} DistoStats;
+void VP8SSIMAddStats(const DistoStats* const src, DistoStats* const dst);
+void VP8SSIMAccumulatePlane(const uint8_t* src1, int stride1,
+ const uint8_t* src2, int stride2,
+ int W, int H, DistoStats* const stats);
+double VP8SSIMGet(const DistoStats* const stats);
+double VP8SSIMGetSquaredError(const DistoStats* const stats);
+
+// autofilter
+void VP8InitFilter(VP8EncIterator* const it);
+void VP8StoreFilterStats(VP8EncIterator* const it);
+void VP8AdjustFilterStrength(VP8EncIterator* const it);
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif /* WEBP_ENC_VP8ENCI_H_ */
diff --git a/drivers/webpold/enc/vp8l.c b/drivers/webpold/enc/vp8l.c
new file mode 100644
index 0000000000..f4eb6e783f
--- /dev/null
+++ b/drivers/webpold/enc/vp8l.c
@@ -0,0 +1,1150 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// main entry for the lossless encoder.
+//
+// Author: Vikas Arora (vikaas.arora@gmail.com)
+//
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "./backward_references.h"
+#include "./vp8enci.h"
+#include "./vp8li.h"
+#include "../dsp/lossless.h"
+#include "../utils/bit_writer.h"
+#include "../utils/huffman_encode.h"
+#include "../utils/utils.h"
+#include "../format_constants.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define PALETTE_KEY_RIGHT_SHIFT 22 // Key for 1K buffer.
+#define MAX_HUFF_IMAGE_SIZE (16 * 1024 * 1024)
+#define MAX_COLORS_FOR_GRAPH 64
+
+// -----------------------------------------------------------------------------
+// Palette
+
+static int CompareColors(const void* p1, const void* p2) {
+ const uint32_t a = *(const uint32_t*)p1;
+ const uint32_t b = *(const uint32_t*)p2;
+ return (a < b) ? -1 : (a > b) ? 1 : 0;
+}
+
+// If number of colors in the image is less than or equal to MAX_PALETTE_SIZE,
+// creates a palette and returns true, else returns false.
+static int AnalyzeAndCreatePalette(const WebPPicture* const pic,
+ uint32_t palette[MAX_PALETTE_SIZE],
+ int* const palette_size) {
+ int i, x, y, key;
+ int num_colors = 0;
+ uint8_t in_use[MAX_PALETTE_SIZE * 4] = { 0 };
+ uint32_t colors[MAX_PALETTE_SIZE * 4];
+ static const uint32_t kHashMul = 0x1e35a7bd;
+ const uint32_t* argb = pic->argb;
+ const int width = pic->width;
+ const int height = pic->height;
+ uint32_t last_pix = ~argb[0]; // so we're sure that last_pix != argb[0]
+
+ for (y = 0; y < height; ++y) {
+ for (x = 0; x < width; ++x) {
+ if (argb[x] == last_pix) {
+ continue;
+ }
+ last_pix = argb[x];
+ key = (kHashMul * last_pix) >> PALETTE_KEY_RIGHT_SHIFT;
+ while (1) {
+ if (!in_use[key]) {
+ colors[key] = last_pix;
+ in_use[key] = 1;
+ ++num_colors;
+ if (num_colors > MAX_PALETTE_SIZE) {
+ return 0;
+ }
+ break;
+ } else if (colors[key] == last_pix) {
+ // The color is already there.
+ break;
+ } else {
+ // Some other color sits there.
+ // Do linear conflict resolution.
+ ++key;
+ key &= (MAX_PALETTE_SIZE * 4 - 1); // key mask for 1K buffer.
+ }
+ }
+ }
+ argb += pic->argb_stride;
+ }
+
+ // TODO(skal): could we reuse in_use[] to speed up ApplyPalette()?
+ num_colors = 0;
+ for (i = 0; i < (int)(sizeof(in_use) / sizeof(in_use[0])); ++i) {
+ if (in_use[i]) {
+ palette[num_colors] = colors[i];
+ ++num_colors;
+ }
+ }
+
+ qsort(palette, num_colors, sizeof(*palette), CompareColors);
+ *palette_size = num_colors;
+ return 1;
+}
+
+static int AnalyzeEntropy(const uint32_t* argb,
+ int width, int height, int argb_stride,
+ double* const nonpredicted_bits,
+ double* const predicted_bits) {
+ int x, y;
+ const uint32_t* last_line = NULL;
+ uint32_t last_pix = argb[0]; // so we're sure that pix_diff == 0
+
+ VP8LHistogram* nonpredicted = NULL;
+ VP8LHistogram* predicted =
+ (VP8LHistogram*)malloc(2 * sizeof(*predicted));
+ if (predicted == NULL) return 0;
+ nonpredicted = predicted + 1;
+
+ VP8LHistogramInit(predicted, 0);
+ VP8LHistogramInit(nonpredicted, 0);
+ for (y = 0; y < height; ++y) {
+ for (x = 0; x < width; ++x) {
+ const uint32_t pix = argb[x];
+ const uint32_t pix_diff = VP8LSubPixels(pix, last_pix);
+ if (pix_diff == 0) continue;
+ if (last_line != NULL && pix == last_line[x]) {
+ continue;
+ }
+ last_pix = pix;
+ {
+ const PixOrCopy pix_token = PixOrCopyCreateLiteral(pix);
+ const PixOrCopy pix_diff_token = PixOrCopyCreateLiteral(pix_diff);
+ VP8LHistogramAddSinglePixOrCopy(nonpredicted, &pix_token);
+ VP8LHistogramAddSinglePixOrCopy(predicted, &pix_diff_token);
+ }
+ }
+ last_line = argb;
+ argb += argb_stride;
+ }
+ *nonpredicted_bits = VP8LHistogramEstimateBitsBulk(nonpredicted);
+ *predicted_bits = VP8LHistogramEstimateBitsBulk(predicted);
+ free(predicted);
+ return 1;
+}
+
+static int VP8LEncAnalyze(VP8LEncoder* const enc, WebPImageHint image_hint) {
+ const WebPPicture* const pic = enc->pic_;
+ assert(pic != NULL && pic->argb != NULL);
+
+ enc->use_palette_ =
+ AnalyzeAndCreatePalette(pic, enc->palette_, &enc->palette_size_);
+
+ if (image_hint == WEBP_HINT_GRAPH) {
+ if (enc->use_palette_ && enc->palette_size_ < MAX_COLORS_FOR_GRAPH) {
+ enc->use_palette_ = 0;
+ }
+ }
+
+ if (!enc->use_palette_) {
+ if (image_hint == WEBP_HINT_PHOTO) {
+ enc->use_predict_ = 1;
+ enc->use_cross_color_ = 1;
+ } else {
+ double non_pred_entropy, pred_entropy;
+ if (!AnalyzeEntropy(pic->argb, pic->width, pic->height, pic->argb_stride,
+ &non_pred_entropy, &pred_entropy)) {
+ return 0;
+ }
+ if (pred_entropy < 0.95 * non_pred_entropy) {
+ enc->use_predict_ = 1;
+ // TODO(vikasa): Observed some correlation of cross_color transform with
+ // predict. Need to investigate this further and add separate heuristic
+ // for setting use_cross_color flag.
+ enc->use_cross_color_ = 1;
+ }
+ }
+ }
+
+ return 1;
+}
+
+static int GetHuffBitLengthsAndCodes(
+ const VP8LHistogramSet* const histogram_image,
+ HuffmanTreeCode* const huffman_codes) {
+ int i, k;
+ int ok = 1;
+ uint64_t total_length_size = 0;
+ uint8_t* mem_buf = NULL;
+ const int histogram_image_size = histogram_image->size;
+
+ // Iterate over all histograms and get the aggregate number of codes used.
+ for (i = 0; i < histogram_image_size; ++i) {
+ const VP8LHistogram* const histo = histogram_image->histograms[i];
+ HuffmanTreeCode* const codes = &huffman_codes[5 * i];
+ for (k = 0; k < 5; ++k) {
+ const int num_symbols = (k == 0) ? VP8LHistogramNumCodes(histo)
+ : (k == 4) ? NUM_DISTANCE_CODES
+ : 256;
+ codes[k].num_symbols = num_symbols;
+ total_length_size += num_symbols;
+ }
+ }
+
+ // Allocate and Set Huffman codes.
+ {
+ uint16_t* codes;
+ uint8_t* lengths;
+ mem_buf = (uint8_t*)WebPSafeCalloc(total_length_size,
+ sizeof(*lengths) + sizeof(*codes));
+ if (mem_buf == NULL) {
+ ok = 0;
+ goto End;
+ }
+ codes = (uint16_t*)mem_buf;
+ lengths = (uint8_t*)&codes[total_length_size];
+ for (i = 0; i < 5 * histogram_image_size; ++i) {
+ const int bit_length = huffman_codes[i].num_symbols;
+ huffman_codes[i].codes = codes;
+ huffman_codes[i].code_lengths = lengths;
+ codes += bit_length;
+ lengths += bit_length;
+ }
+ }
+
+ // Create Huffman trees.
+ for (i = 0; i < histogram_image_size; ++i) {
+ HuffmanTreeCode* const codes = &huffman_codes[5 * i];
+ VP8LHistogram* const histo = histogram_image->histograms[i];
+ ok = ok && VP8LCreateHuffmanTree(histo->literal_, 15, codes + 0);
+ ok = ok && VP8LCreateHuffmanTree(histo->red_, 15, codes + 1);
+ ok = ok && VP8LCreateHuffmanTree(histo->blue_, 15, codes + 2);
+ ok = ok && VP8LCreateHuffmanTree(histo->alpha_, 15, codes + 3);
+ ok = ok && VP8LCreateHuffmanTree(histo->distance_, 15, codes + 4);
+ }
+
+ End:
+ if (!ok) free(mem_buf);
+ return ok;
+}
+
+static void StoreHuffmanTreeOfHuffmanTreeToBitMask(
+ VP8LBitWriter* const bw, const uint8_t* code_length_bitdepth) {
+ // RFC 1951 will calm you down if you are worried about this funny sequence.
+ // This sequence is tuned from that, but more weighted for lower symbol count,
+ // and more spiking histograms.
+ static const uint8_t kStorageOrder[CODE_LENGTH_CODES] = {
+ 17, 18, 0, 1, 2, 3, 4, 5, 16, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
+ };
+ int i;
+ // Throw away trailing zeros:
+ int codes_to_store = CODE_LENGTH_CODES;
+ for (; codes_to_store > 4; --codes_to_store) {
+ if (code_length_bitdepth[kStorageOrder[codes_to_store - 1]] != 0) {
+ break;
+ }
+ }
+ VP8LWriteBits(bw, 4, codes_to_store - 4);
+ for (i = 0; i < codes_to_store; ++i) {
+ VP8LWriteBits(bw, 3, code_length_bitdepth[kStorageOrder[i]]);
+ }
+}
+
+static void ClearHuffmanTreeIfOnlyOneSymbol(
+ HuffmanTreeCode* const huffman_code) {
+ int k;
+ int count = 0;
+ for (k = 0; k < huffman_code->num_symbols; ++k) {
+ if (huffman_code->code_lengths[k] != 0) {
+ ++count;
+ if (count > 1) return;
+ }
+ }
+ for (k = 0; k < huffman_code->num_symbols; ++k) {
+ huffman_code->code_lengths[k] = 0;
+ huffman_code->codes[k] = 0;
+ }
+}
+
+static void StoreHuffmanTreeToBitMask(
+ VP8LBitWriter* const bw,
+ const HuffmanTreeToken* const tokens, const int num_tokens,
+ const HuffmanTreeCode* const huffman_code) {
+ int i;
+ for (i = 0; i < num_tokens; ++i) {
+ const int ix = tokens[i].code;
+ const int extra_bits = tokens[i].extra_bits;
+ VP8LWriteBits(bw, huffman_code->code_lengths[ix], huffman_code->codes[ix]);
+ switch (ix) {
+ case 16:
+ VP8LWriteBits(bw, 2, extra_bits);
+ break;
+ case 17:
+ VP8LWriteBits(bw, 3, extra_bits);
+ break;
+ case 18:
+ VP8LWriteBits(bw, 7, extra_bits);
+ break;
+ }
+ }
+}
+
+static int StoreFullHuffmanCode(VP8LBitWriter* const bw,
+ const HuffmanTreeCode* const tree) {
+ int ok = 0;
+ uint8_t code_length_bitdepth[CODE_LENGTH_CODES] = { 0 };
+ uint16_t code_length_bitdepth_symbols[CODE_LENGTH_CODES] = { 0 };
+ const int max_tokens = tree->num_symbols;
+ int num_tokens;
+ HuffmanTreeCode huffman_code;
+ HuffmanTreeToken* const tokens =
+ (HuffmanTreeToken*)WebPSafeMalloc((uint64_t)max_tokens, sizeof(*tokens));
+ if (tokens == NULL) return 0;
+
+ huffman_code.num_symbols = CODE_LENGTH_CODES;
+ huffman_code.code_lengths = code_length_bitdepth;
+ huffman_code.codes = code_length_bitdepth_symbols;
+
+ VP8LWriteBits(bw, 1, 0);
+ num_tokens = VP8LCreateCompressedHuffmanTree(tree, tokens, max_tokens);
+ {
+ int histogram[CODE_LENGTH_CODES] = { 0 };
+ int i;
+ for (i = 0; i < num_tokens; ++i) {
+ ++histogram[tokens[i].code];
+ }
+
+ if (!VP8LCreateHuffmanTree(histogram, 7, &huffman_code)) {
+ goto End;
+ }
+ }
+
+ StoreHuffmanTreeOfHuffmanTreeToBitMask(bw, code_length_bitdepth);
+ ClearHuffmanTreeIfOnlyOneSymbol(&huffman_code);
+ {
+ int trailing_zero_bits = 0;
+ int trimmed_length = num_tokens;
+ int write_trimmed_length;
+ int length;
+ int i = num_tokens;
+ while (i-- > 0) {
+ const int ix = tokens[i].code;
+ if (ix == 0 || ix == 17 || ix == 18) {
+ --trimmed_length; // discount trailing zeros
+ trailing_zero_bits += code_length_bitdepth[ix];
+ if (ix == 17) {
+ trailing_zero_bits += 3;
+ } else if (ix == 18) {
+ trailing_zero_bits += 7;
+ }
+ } else {
+ break;
+ }
+ }
+ write_trimmed_length = (trimmed_length > 1 && trailing_zero_bits > 12);
+ length = write_trimmed_length ? trimmed_length : num_tokens;
+ VP8LWriteBits(bw, 1, write_trimmed_length);
+ if (write_trimmed_length) {
+ const int nbits = VP8LBitsLog2Ceiling(trimmed_length - 1);
+ const int nbitpairs = (nbits == 0) ? 1 : (nbits + 1) / 2;
+ VP8LWriteBits(bw, 3, nbitpairs - 1);
+ assert(trimmed_length >= 2);
+ VP8LWriteBits(bw, nbitpairs * 2, trimmed_length - 2);
+ }
+ StoreHuffmanTreeToBitMask(bw, tokens, length, &huffman_code);
+ }
+ ok = 1;
+ End:
+ free(tokens);
+ return ok;
+}
+
+static int StoreHuffmanCode(VP8LBitWriter* const bw,
+ const HuffmanTreeCode* const huffman_code) {
+ int i;
+ int count = 0;
+ int symbols[2] = { 0, 0 };
+ const int kMaxBits = 8;
+ const int kMaxSymbol = 1 << kMaxBits;
+
+ // Check whether it's a small tree.
+ for (i = 0; i < huffman_code->num_symbols && count < 3; ++i) {
+ if (huffman_code->code_lengths[i] != 0) {
+ if (count < 2) symbols[count] = i;
+ ++count;
+ }
+ }
+
+ if (count == 0) { // emit minimal tree for empty cases
+ // bits: small tree marker: 1, count-1: 0, large 8-bit code: 0, code: 0
+ VP8LWriteBits(bw, 4, 0x01);
+ return 1;
+ } else if (count <= 2 && symbols[0] < kMaxSymbol && symbols[1] < kMaxSymbol) {
+ VP8LWriteBits(bw, 1, 1); // Small tree marker to encode 1 or 2 symbols.
+ VP8LWriteBits(bw, 1, count - 1);
+ if (symbols[0] <= 1) {
+ VP8LWriteBits(bw, 1, 0); // Code bit for small (1 bit) symbol value.
+ VP8LWriteBits(bw, 1, symbols[0]);
+ } else {
+ VP8LWriteBits(bw, 1, 1);
+ VP8LWriteBits(bw, 8, symbols[0]);
+ }
+ if (count == 2) {
+ VP8LWriteBits(bw, 8, symbols[1]);
+ }
+ return 1;
+ } else {
+ return StoreFullHuffmanCode(bw, huffman_code);
+ }
+}
+
+static void WriteHuffmanCode(VP8LBitWriter* const bw,
+ const HuffmanTreeCode* const code, int index) {
+ const int depth = code->code_lengths[index];
+ const int symbol = code->codes[index];
+ VP8LWriteBits(bw, depth, symbol);
+}
+
+static void StoreImageToBitMask(
+ VP8LBitWriter* const bw, int width, int histo_bits,
+ const VP8LBackwardRefs* const refs,
+ const uint16_t* histogram_symbols,
+ const HuffmanTreeCode* const huffman_codes) {
+ // x and y trace the position in the image.
+ int x = 0;
+ int y = 0;
+ const int histo_xsize = histo_bits ? VP8LSubSampleSize(width, histo_bits) : 1;
+ int i;
+ for (i = 0; i < refs->size; ++i) {
+ const PixOrCopy* const v = &refs->refs[i];
+ const int histogram_ix = histogram_symbols[histo_bits ?
+ (y >> histo_bits) * histo_xsize +
+ (x >> histo_bits) : 0];
+ const HuffmanTreeCode* const codes = huffman_codes + 5 * histogram_ix;
+ if (PixOrCopyIsCacheIdx(v)) {
+ const int code = PixOrCopyCacheIdx(v);
+ const int literal_ix = 256 + NUM_LENGTH_CODES + code;
+ WriteHuffmanCode(bw, codes, literal_ix);
+ } else if (PixOrCopyIsLiteral(v)) {
+ static const int order[] = { 1, 2, 0, 3 };
+ int k;
+ for (k = 0; k < 4; ++k) {
+ const int code = PixOrCopyLiteral(v, order[k]);
+ WriteHuffmanCode(bw, codes + k, code);
+ }
+ } else {
+ int bits, n_bits;
+ int code, distance;
+
+ PrefixEncode(v->len, &code, &n_bits, &bits);
+ WriteHuffmanCode(bw, codes, 256 + code);
+ VP8LWriteBits(bw, n_bits, bits);
+
+ distance = PixOrCopyDistance(v);
+ PrefixEncode(distance, &code, &n_bits, &bits);
+ WriteHuffmanCode(bw, codes + 4, code);
+ VP8LWriteBits(bw, n_bits, bits);
+ }
+ x += PixOrCopyLength(v);
+ while (x >= width) {
+ x -= width;
+ ++y;
+ }
+ }
+}
+
+// Special case of EncodeImageInternal() for cache-bits=0, histo_bits=31
+static int EncodeImageNoHuffman(VP8LBitWriter* const bw,
+ const uint32_t* const argb,
+ int width, int height, int quality) {
+ int i;
+ int ok = 0;
+ VP8LBackwardRefs refs;
+ HuffmanTreeCode huffman_codes[5] = { { 0, NULL, NULL } };
+ const uint16_t histogram_symbols[1] = { 0 }; // only one tree, one symbol
+ VP8LHistogramSet* const histogram_image = VP8LAllocateHistogramSet(1, 0);
+ if (histogram_image == NULL) return 0;
+
+ // Calculate backward references from ARGB image.
+ if (!VP8LGetBackwardReferences(width, height, argb, quality, 0, 1, &refs)) {
+ goto Error;
+ }
+ // Build histogram image and symbols from backward references.
+ VP8LHistogramStoreRefs(&refs, histogram_image->histograms[0]);
+
+ // Create Huffman bit lengths and codes for each histogram image.
+ assert(histogram_image->size == 1);
+ if (!GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
+ goto Error;
+ }
+
+ // No color cache, no Huffman image.
+ VP8LWriteBits(bw, 1, 0);
+
+ // Store Huffman codes.
+ for (i = 0; i < 5; ++i) {
+ HuffmanTreeCode* const codes = &huffman_codes[i];
+ if (!StoreHuffmanCode(bw, codes)) {
+ goto Error;
+ }
+ ClearHuffmanTreeIfOnlyOneSymbol(codes);
+ }
+
+ // Store actual literals.
+ StoreImageToBitMask(bw, width, 0, &refs, histogram_symbols, huffman_codes);
+ ok = 1;
+
+ Error:
+ free(histogram_image);
+ VP8LClearBackwardRefs(&refs);
+ free(huffman_codes[0].codes);
+ return ok;
+}
+
+static int EncodeImageInternal(VP8LBitWriter* const bw,
+ const uint32_t* const argb,
+ int width, int height, int quality,
+ int cache_bits, int histogram_bits) {
+ int ok = 0;
+ const int use_2d_locality = 1;
+ const int use_color_cache = (cache_bits > 0);
+ const uint32_t histogram_image_xysize =
+ VP8LSubSampleSize(width, histogram_bits) *
+ VP8LSubSampleSize(height, histogram_bits);
+ VP8LHistogramSet* histogram_image =
+ VP8LAllocateHistogramSet(histogram_image_xysize, 0);
+ int histogram_image_size = 0;
+ size_t bit_array_size = 0;
+ HuffmanTreeCode* huffman_codes = NULL;
+ VP8LBackwardRefs refs;
+ uint16_t* const histogram_symbols =
+ (uint16_t*)WebPSafeMalloc((uint64_t)histogram_image_xysize,
+ sizeof(*histogram_symbols));
+ assert(histogram_bits >= MIN_HUFFMAN_BITS);
+ assert(histogram_bits <= MAX_HUFFMAN_BITS);
+ if (histogram_image == NULL || histogram_symbols == NULL) goto Error;
+
+ // Calculate backward references from ARGB image.
+ if (!VP8LGetBackwardReferences(width, height, argb, quality, cache_bits,
+ use_2d_locality, &refs)) {
+ goto Error;
+ }
+ // Build histogram image and symbols from backward references.
+ if (!VP8LGetHistoImageSymbols(width, height, &refs,
+ quality, histogram_bits, cache_bits,
+ histogram_image,
+ histogram_symbols)) {
+ goto Error;
+ }
+ // Create Huffman bit lengths and codes for each histogram image.
+ histogram_image_size = histogram_image->size;
+ bit_array_size = 5 * histogram_image_size;
+ huffman_codes = (HuffmanTreeCode*)WebPSafeCalloc(bit_array_size,
+ sizeof(*huffman_codes));
+ if (huffman_codes == NULL ||
+ !GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
+ goto Error;
+ }
+
+ // Color Cache parameters.
+ VP8LWriteBits(bw, 1, use_color_cache);
+ if (use_color_cache) {
+ VP8LWriteBits(bw, 4, cache_bits);
+ }
+
+ // Huffman image + meta huffman.
+ {
+ const int write_histogram_image = (histogram_image_size > 1);
+ VP8LWriteBits(bw, 1, write_histogram_image);
+ if (write_histogram_image) {
+ uint32_t* const histogram_argb =
+ (uint32_t*)WebPSafeMalloc((uint64_t)histogram_image_xysize,
+ sizeof(*histogram_argb));
+ int max_index = 0;
+ uint32_t i;
+ if (histogram_argb == NULL) goto Error;
+ for (i = 0; i < histogram_image_xysize; ++i) {
+ const int index = histogram_symbols[i] & 0xffff;
+ histogram_argb[i] = 0xff000000 | (index << 8);
+ if (index >= max_index) {
+ max_index = index + 1;
+ }
+ }
+ histogram_image_size = max_index;
+
+ VP8LWriteBits(bw, 3, histogram_bits - 2);
+ ok = EncodeImageNoHuffman(bw, histogram_argb,
+ VP8LSubSampleSize(width, histogram_bits),
+ VP8LSubSampleSize(height, histogram_bits),
+ quality);
+ free(histogram_argb);
+ if (!ok) goto Error;
+ }
+ }
+
+ // Store Huffman codes.
+ {
+ int i;
+ for (i = 0; i < 5 * histogram_image_size; ++i) {
+ HuffmanTreeCode* const codes = &huffman_codes[i];
+ if (!StoreHuffmanCode(bw, codes)) goto Error;
+ ClearHuffmanTreeIfOnlyOneSymbol(codes);
+ }
+ }
+ // Free combined histograms.
+ free(histogram_image);
+ histogram_image = NULL;
+
+ // Store actual literals.
+ StoreImageToBitMask(bw, width, histogram_bits, &refs,
+ histogram_symbols, huffman_codes);
+ ok = 1;
+
+ Error:
+ if (!ok) free(histogram_image);
+
+ VP8LClearBackwardRefs(&refs);
+ if (huffman_codes != NULL) {
+ free(huffman_codes->codes);
+ free(huffman_codes);
+ }
+ free(histogram_symbols);
+ return ok;
+}
+
+// -----------------------------------------------------------------------------
+// Transforms
+
+// Check if it would be a good idea to subtract green from red and blue. We
+// only impact entropy in red/blue components, don't bother to look at others.
+static int EvalAndApplySubtractGreen(VP8LEncoder* const enc,
+ int width, int height,
+ VP8LBitWriter* const bw) {
+ if (!enc->use_palette_) {
+ int i;
+ const uint32_t* const argb = enc->argb_;
+ double bit_cost_before, bit_cost_after;
+ VP8LHistogram* const histo = (VP8LHistogram*)malloc(sizeof(*histo));
+ if (histo == NULL) return 0;
+
+ VP8LHistogramInit(histo, 1);
+ for (i = 0; i < width * height; ++i) {
+ const uint32_t c = argb[i];
+ ++histo->red_[(c >> 16) & 0xff];
+ ++histo->blue_[(c >> 0) & 0xff];
+ }
+ bit_cost_before = VP8LHistogramEstimateBits(histo);
+
+ VP8LHistogramInit(histo, 1);
+ for (i = 0; i < width * height; ++i) {
+ const uint32_t c = argb[i];
+ const int green = (c >> 8) & 0xff;
+ ++histo->red_[((c >> 16) - green) & 0xff];
+ ++histo->blue_[((c >> 0) - green) & 0xff];
+ }
+ bit_cost_after = VP8LHistogramEstimateBits(histo);
+ free(histo);
+
+ // Check if subtracting green yields low entropy.
+ enc->use_subtract_green_ = (bit_cost_after < bit_cost_before);
+ if (enc->use_subtract_green_) {
+ VP8LWriteBits(bw, 1, TRANSFORM_PRESENT);
+ VP8LWriteBits(bw, 2, SUBTRACT_GREEN);
+ VP8LSubtractGreenFromBlueAndRed(enc->argb_, width * height);
+ }
+ }
+ return 1;
+}
+
+static int ApplyPredictFilter(const VP8LEncoder* const enc,
+ int width, int height, int quality,
+ VP8LBitWriter* const bw) {
+ const int pred_bits = enc->transform_bits_;
+ const int transform_width = VP8LSubSampleSize(width, pred_bits);
+ const int transform_height = VP8LSubSampleSize(height, pred_bits);
+
+ VP8LResidualImage(width, height, pred_bits, enc->argb_, enc->argb_scratch_,
+ enc->transform_data_);
+ VP8LWriteBits(bw, 1, TRANSFORM_PRESENT);
+ VP8LWriteBits(bw, 2, PREDICTOR_TRANSFORM);
+ assert(pred_bits >= 2);
+ VP8LWriteBits(bw, 3, pred_bits - 2);
+ if (!EncodeImageNoHuffman(bw, enc->transform_data_,
+ transform_width, transform_height, quality)) {
+ return 0;
+ }
+ return 1;
+}
+
+static int ApplyCrossColorFilter(const VP8LEncoder* const enc,
+ int width, int height, int quality,
+ VP8LBitWriter* const bw) {
+ const int ccolor_transform_bits = enc->transform_bits_;
+ const int transform_width = VP8LSubSampleSize(width, ccolor_transform_bits);
+ const int transform_height = VP8LSubSampleSize(height, ccolor_transform_bits);
+ const int step = (quality == 0) ? 32 : 8;
+
+ VP8LColorSpaceTransform(width, height, ccolor_transform_bits, step,
+ enc->argb_, enc->transform_data_);
+ VP8LWriteBits(bw, 1, TRANSFORM_PRESENT);
+ VP8LWriteBits(bw, 2, CROSS_COLOR_TRANSFORM);
+ assert(ccolor_transform_bits >= 2);
+ VP8LWriteBits(bw, 3, ccolor_transform_bits - 2);
+ if (!EncodeImageNoHuffman(bw, enc->transform_data_,
+ transform_width, transform_height, quality)) {
+ return 0;
+ }
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+
+static void PutLE32(uint8_t* const data, uint32_t val) {
+ data[0] = (val >> 0) & 0xff;
+ data[1] = (val >> 8) & 0xff;
+ data[2] = (val >> 16) & 0xff;
+ data[3] = (val >> 24) & 0xff;
+}
+
+static WebPEncodingError WriteRiffHeader(const WebPPicture* const pic,
+ size_t riff_size, size_t vp8l_size) {
+ uint8_t riff[RIFF_HEADER_SIZE + CHUNK_HEADER_SIZE + VP8L_SIGNATURE_SIZE] = {
+ 'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P',
+ 'V', 'P', '8', 'L', 0, 0, 0, 0, VP8L_MAGIC_BYTE,
+ };
+ PutLE32(riff + TAG_SIZE, (uint32_t)riff_size);
+ PutLE32(riff + RIFF_HEADER_SIZE + TAG_SIZE, (uint32_t)vp8l_size);
+ if (!pic->writer(riff, sizeof(riff), pic)) {
+ return VP8_ENC_ERROR_BAD_WRITE;
+ }
+ return VP8_ENC_OK;
+}
+
+static int WriteImageSize(const WebPPicture* const pic,
+ VP8LBitWriter* const bw) {
+ const int width = pic->width - 1;
+ const int height = pic->height - 1;
+ assert(width < WEBP_MAX_DIMENSION && height < WEBP_MAX_DIMENSION);
+
+ VP8LWriteBits(bw, VP8L_IMAGE_SIZE_BITS, width);
+ VP8LWriteBits(bw, VP8L_IMAGE_SIZE_BITS, height);
+ return !bw->error_;
+}
+
+static int WriteRealAlphaAndVersion(VP8LBitWriter* const bw, int has_alpha) {
+ VP8LWriteBits(bw, 1, has_alpha);
+ VP8LWriteBits(bw, VP8L_VERSION_BITS, VP8L_VERSION);
+ return !bw->error_;
+}
+
+static WebPEncodingError WriteImage(const WebPPicture* const pic,
+ VP8LBitWriter* const bw,
+ size_t* const coded_size) {
+ WebPEncodingError err = VP8_ENC_OK;
+ const uint8_t* const webpll_data = VP8LBitWriterFinish(bw);
+ const size_t webpll_size = VP8LBitWriterNumBytes(bw);
+ const size_t vp8l_size = VP8L_SIGNATURE_SIZE + webpll_size;
+ const size_t pad = vp8l_size & 1;
+ const size_t riff_size = TAG_SIZE + CHUNK_HEADER_SIZE + vp8l_size + pad;
+
+ err = WriteRiffHeader(pic, riff_size, vp8l_size);
+ if (err != VP8_ENC_OK) goto Error;
+
+ if (!pic->writer(webpll_data, webpll_size, pic)) {
+ err = VP8_ENC_ERROR_BAD_WRITE;
+ goto Error;
+ }
+
+ if (pad) {
+ const uint8_t pad_byte[1] = { 0 };
+ if (!pic->writer(pad_byte, 1, pic)) {
+ err = VP8_ENC_ERROR_BAD_WRITE;
+ goto Error;
+ }
+ }
+ *coded_size = CHUNK_HEADER_SIZE + riff_size;
+ return VP8_ENC_OK;
+
+ Error:
+ return err;
+}
+
+// -----------------------------------------------------------------------------
+
+// Allocates the memory for argb (W x H) buffer, 2 rows of context for
+// prediction and transform data.
+static WebPEncodingError AllocateTransformBuffer(VP8LEncoder* const enc,
+ int width, int height) {
+ WebPEncodingError err = VP8_ENC_OK;
+ const int tile_size = 1 << enc->transform_bits_;
+ const uint64_t image_size = width * height;
+ const uint64_t argb_scratch_size = tile_size * width + width;
+ const uint64_t transform_data_size =
+ (uint64_t)VP8LSubSampleSize(width, enc->transform_bits_) *
+ (uint64_t)VP8LSubSampleSize(height, enc->transform_bits_);
+ const uint64_t total_size =
+ image_size + argb_scratch_size + transform_data_size;
+ uint32_t* mem = (uint32_t*)WebPSafeMalloc(total_size, sizeof(*mem));
+ if (mem == NULL) {
+ err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ goto Error;
+ }
+ enc->argb_ = mem;
+ mem += image_size;
+ enc->argb_scratch_ = mem;
+ mem += argb_scratch_size;
+ enc->transform_data_ = mem;
+ enc->current_width_ = width;
+
+ Error:
+ return err;
+}
+
+// Bundles multiple (2, 4 or 8) pixels into a single pixel.
+// Returns the new xsize.
+static void BundleColorMap(const WebPPicture* const pic,
+ int xbits, uint32_t* bundled_argb, int xs) {
+ int y;
+ const int bit_depth = 1 << (3 - xbits);
+ uint32_t code = 0;
+ const uint32_t* argb = pic->argb;
+ const int width = pic->width;
+ const int height = pic->height;
+
+ for (y = 0; y < height; ++y) {
+ int x;
+ for (x = 0; x < width; ++x) {
+ const int mask = (1 << xbits) - 1;
+ const int xsub = x & mask;
+ if (xsub == 0) {
+ code = 0;
+ }
+ // TODO(vikasa): simplify the bundling logic.
+ code |= (argb[x] & 0xff00) << (bit_depth * xsub);
+ bundled_argb[y * xs + (x >> xbits)] = 0xff000000 | code;
+ }
+ argb += pic->argb_stride;
+ }
+}
+
+// Note: Expects "enc->palette_" to be set properly.
+// Also, "enc->palette_" will be modified after this call and should not be used
+// later.
+static WebPEncodingError ApplyPalette(VP8LBitWriter* const bw,
+ VP8LEncoder* const enc, int quality) {
+ WebPEncodingError err = VP8_ENC_OK;
+ int i, x, y;
+ const WebPPicture* const pic = enc->pic_;
+ uint32_t* argb = pic->argb;
+ const int width = pic->width;
+ const int height = pic->height;
+ uint32_t* const palette = enc->palette_;
+ const int palette_size = enc->palette_size_;
+
+ // Replace each input pixel by corresponding palette index.
+ for (y = 0; y < height; ++y) {
+ for (x = 0; x < width; ++x) {
+ const uint32_t pix = argb[x];
+ for (i = 0; i < palette_size; ++i) {
+ if (pix == palette[i]) {
+ argb[x] = 0xff000000u | (i << 8);
+ break;
+ }
+ }
+ }
+ argb += pic->argb_stride;
+ }
+
+ // Save palette to bitstream.
+ VP8LWriteBits(bw, 1, TRANSFORM_PRESENT);
+ VP8LWriteBits(bw, 2, COLOR_INDEXING_TRANSFORM);
+ assert(palette_size >= 1);
+ VP8LWriteBits(bw, 8, palette_size - 1);
+ for (i = palette_size - 1; i >= 1; --i) {
+ palette[i] = VP8LSubPixels(palette[i], palette[i - 1]);
+ }
+ if (!EncodeImageNoHuffman(bw, palette, palette_size, 1, quality)) {
+ err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
+ goto Error;
+ }
+
+ if (palette_size <= 16) {
+ // Image can be packed (multiple pixels per uint32_t).
+ int xbits = 1;
+ if (palette_size <= 2) {
+ xbits = 3;
+ } else if (palette_size <= 4) {
+ xbits = 2;
+ }
+ err = AllocateTransformBuffer(enc, VP8LSubSampleSize(width, xbits), height);
+ if (err != VP8_ENC_OK) goto Error;
+ BundleColorMap(pic, xbits, enc->argb_, enc->current_width_);
+ }
+
+ Error:
+ return err;
+}
+
+// -----------------------------------------------------------------------------
+
+static int GetHistoBits(const WebPConfig* const config,
+ const WebPPicture* const pic) {
+ const int width = pic->width;
+ const int height = pic->height;
+ const size_t hist_size = sizeof(VP8LHistogram);
+ // Make tile size a function of encoding method (Range: 0 to 6).
+ int histo_bits = 7 - config->method;
+ while (1) {
+ const size_t huff_image_size = VP8LSubSampleSize(width, histo_bits) *
+ VP8LSubSampleSize(height, histo_bits) *
+ hist_size;
+ if (huff_image_size <= MAX_HUFF_IMAGE_SIZE) break;
+ ++histo_bits;
+ }
+ return (histo_bits < MIN_HUFFMAN_BITS) ? MIN_HUFFMAN_BITS :
+ (histo_bits > MAX_HUFFMAN_BITS) ? MAX_HUFFMAN_BITS : histo_bits;
+}
+
+static void InitEncParams(VP8LEncoder* const enc) {
+ const WebPConfig* const config = enc->config_;
+ const WebPPicture* const picture = enc->pic_;
+ const int method = config->method;
+ const float quality = config->quality;
+ enc->transform_bits_ = (method < 4) ? 5 : (method > 4) ? 3 : 4;
+ enc->histo_bits_ = GetHistoBits(config, picture);
+ enc->cache_bits_ = (quality <= 25.f) ? 0 : 7;
+}
+
+// -----------------------------------------------------------------------------
+// VP8LEncoder
+
+static VP8LEncoder* VP8LEncoderNew(const WebPConfig* const config,
+ const WebPPicture* const picture) {
+ VP8LEncoder* const enc = (VP8LEncoder*)calloc(1, sizeof(*enc));
+ if (enc == NULL) {
+ WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ return NULL;
+ }
+ enc->config_ = config;
+ enc->pic_ = picture;
+ return enc;
+}
+
+static void VP8LEncoderDelete(VP8LEncoder* enc) {
+ free(enc->argb_);
+ free(enc);
+}
+
+// -----------------------------------------------------------------------------
+// Main call
+
+WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
+ const WebPPicture* const picture,
+ VP8LBitWriter* const bw) {
+ WebPEncodingError err = VP8_ENC_OK;
+ const int quality = (int)config->quality;
+ const int width = picture->width;
+ const int height = picture->height;
+ VP8LEncoder* const enc = VP8LEncoderNew(config, picture);
+ const size_t byte_position = VP8LBitWriterNumBytes(bw);
+
+ if (enc == NULL) {
+ err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ goto Error;
+ }
+
+ InitEncParams(enc);
+
+ // ---------------------------------------------------------------------------
+ // Analyze image (entropy, num_palettes etc)
+
+ if (!VP8LEncAnalyze(enc, config->image_hint)) {
+ err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ goto Error;
+ }
+
+ if (enc->use_palette_) {
+ err = ApplyPalette(bw, enc, quality);
+ if (err != VP8_ENC_OK) goto Error;
+ // Color cache is disabled for palette.
+ enc->cache_bits_ = 0;
+ }
+
+ // In case image is not packed.
+ if (enc->argb_ == NULL) {
+ int y;
+ err = AllocateTransformBuffer(enc, width, height);
+ if (err != VP8_ENC_OK) goto Error;
+ for (y = 0; y < height; ++y) {
+ memcpy(enc->argb_ + y * width,
+ picture->argb + y * picture->argb_stride,
+ width * sizeof(*enc->argb_));
+ }
+ enc->current_width_ = width;
+ }
+
+ // ---------------------------------------------------------------------------
+ // Apply transforms and write transform data.
+
+ if (!EvalAndApplySubtractGreen(enc, enc->current_width_, height, bw)) {
+ err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ goto Error;
+ }
+
+ if (enc->use_predict_) {
+ if (!ApplyPredictFilter(enc, enc->current_width_, height, quality, bw)) {
+ err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
+ goto Error;
+ }
+ }
+
+ if (enc->use_cross_color_) {
+ if (!ApplyCrossColorFilter(enc, enc->current_width_, height, quality, bw)) {
+ err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
+ goto Error;
+ }
+ }
+
+ VP8LWriteBits(bw, 1, !TRANSFORM_PRESENT); // No more transforms.
+
+ // ---------------------------------------------------------------------------
+ // Estimate the color cache size.
+
+ if (enc->cache_bits_ > 0) {
+ if (!VP8LCalculateEstimateForCacheSize(enc->argb_, enc->current_width_,
+ height, &enc->cache_bits_)) {
+ err = VP8_ENC_ERROR_INVALID_CONFIGURATION;
+ goto Error;
+ }
+ }
+
+ // ---------------------------------------------------------------------------
+ // Encode and write the transformed image.
+
+ if (!EncodeImageInternal(bw, enc->argb_, enc->current_width_, height,
+ quality, enc->cache_bits_, enc->histo_bits_)) {
+ err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ goto Error;
+ }
+
+ if (picture->stats != NULL) {
+ WebPAuxStats* const stats = picture->stats;
+ stats->lossless_features = 0;
+ if (enc->use_predict_) stats->lossless_features |= 1;
+ if (enc->use_cross_color_) stats->lossless_features |= 2;
+ if (enc->use_subtract_green_) stats->lossless_features |= 4;
+ if (enc->use_palette_) stats->lossless_features |= 8;
+ stats->histogram_bits = enc->histo_bits_;
+ stats->transform_bits = enc->transform_bits_;
+ stats->cache_bits = enc->cache_bits_;
+ stats->palette_size = enc->palette_size_;
+ stats->lossless_size = (int)(VP8LBitWriterNumBytes(bw) - byte_position);
+ }
+
+ Error:
+ VP8LEncoderDelete(enc);
+ return err;
+}
+
+int VP8LEncodeImage(const WebPConfig* const config,
+ const WebPPicture* const picture) {
+ int width, height;
+ int has_alpha;
+ size_t coded_size;
+ int percent = 0;
+ WebPEncodingError err = VP8_ENC_OK;
+ VP8LBitWriter bw;
+
+ if (picture == NULL) return 0;
+
+ if (config == NULL || picture->argb == NULL) {
+ err = VP8_ENC_ERROR_NULL_PARAMETER;
+ WebPEncodingSetError(picture, err);
+ return 0;
+ }
+
+ width = picture->width;
+ height = picture->height;
+ if (!VP8LBitWriterInit(&bw, (width * height) >> 1)) {
+ err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ goto Error;
+ }
+
+ if (!WebPReportProgress(picture, 1, &percent)) {
+ UserAbort:
+ err = VP8_ENC_ERROR_USER_ABORT;
+ goto Error;
+ }
+ // Reset stats (for pure lossless coding)
+ if (picture->stats != NULL) {
+ WebPAuxStats* const stats = picture->stats;
+ memset(stats, 0, sizeof(*stats));
+ stats->PSNR[0] = 99.f;
+ stats->PSNR[1] = 99.f;
+ stats->PSNR[2] = 99.f;
+ stats->PSNR[3] = 99.f;
+ stats->PSNR[4] = 99.f;
+ }
+
+ // Write image size.
+ if (!WriteImageSize(picture, &bw)) {
+ err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ goto Error;
+ }
+
+ has_alpha = WebPPictureHasTransparency(picture);
+ // Write the non-trivial Alpha flag and lossless version.
+ if (!WriteRealAlphaAndVersion(&bw, has_alpha)) {
+ err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ goto Error;
+ }
+
+ if (!WebPReportProgress(picture, 5, &percent)) goto UserAbort;
+
+ // Encode main image stream.
+ err = VP8LEncodeStream(config, picture, &bw);
+ if (err != VP8_ENC_OK) goto Error;
+
+ // TODO(skal): have a fine-grained progress report in VP8LEncodeStream().
+ if (!WebPReportProgress(picture, 90, &percent)) goto UserAbort;
+
+ // Finish the RIFF chunk.
+ err = WriteImage(picture, &bw, &coded_size);
+ if (err != VP8_ENC_OK) goto Error;
+
+ if (!WebPReportProgress(picture, 100, &percent)) goto UserAbort;
+
+ // Save size.
+ if (picture->stats != NULL) {
+ picture->stats->coded_size += (int)coded_size;
+ picture->stats->lossless_size = (int)coded_size;
+ }
+
+ if (picture->extra_info != NULL) {
+ const int mb_w = (width + 15) >> 4;
+ const int mb_h = (height + 15) >> 4;
+ memset(picture->extra_info, 0, mb_w * mb_h * sizeof(*picture->extra_info));
+ }
+
+ Error:
+ if (bw.error_) err = VP8_ENC_ERROR_OUT_OF_MEMORY;
+ VP8LBitWriterDestroy(&bw);
+ if (err != VP8_ENC_OK) {
+ WebPEncodingSetError(picture, err);
+ return 0;
+ }
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/enc/vp8li.h b/drivers/webpold/enc/vp8li.h
new file mode 100644
index 0000000000..bb111aec33
--- /dev/null
+++ b/drivers/webpold/enc/vp8li.h
@@ -0,0 +1,68 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Lossless encoder: internal header.
+//
+// Author: Vikas Arora (vikaas.arora@gmail.com)
+
+#ifndef WEBP_ENC_VP8LI_H_
+#define WEBP_ENC_VP8LI_H_
+
+#include "./histogram.h"
+#include "../utils/bit_writer.h"
+#include "../encode.h"
+#include "../format_constants.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+typedef struct {
+ const WebPConfig* config_; // user configuration and parameters
+ const WebPPicture* pic_; // input picture.
+
+ uint32_t* argb_; // Transformed argb image data.
+ uint32_t* argb_scratch_; // Scratch memory for argb rows
+ // (used for prediction).
+ uint32_t* transform_data_; // Scratch memory for transform data.
+ int current_width_; // Corresponds to packed image width.
+
+ // Encoding parameters derived from quality parameter.
+ int histo_bits_;
+ int transform_bits_;
+ int cache_bits_; // If equal to 0, don't use color cache.
+
+ // Encoding parameters derived from image characteristics.
+ int use_cross_color_;
+ int use_subtract_green_;
+ int use_predict_;
+ int use_palette_;
+ int palette_size_;
+ uint32_t palette_[MAX_PALETTE_SIZE];
+} VP8LEncoder;
+
+//------------------------------------------------------------------------------
+// internal functions. Not public.
+
+// Encodes the picture.
+// Returns 0 if config or picture is NULL or picture doesn't have valid argb
+// input.
+int VP8LEncodeImage(const WebPConfig* const config,
+ const WebPPicture* const picture);
+
+// Encodes the main image stream using the supplied bit writer.
+WebPEncodingError VP8LEncodeStream(const WebPConfig* const config,
+ const WebPPicture* const picture,
+ VP8LBitWriter* const bw);
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif /* WEBP_ENC_VP8LI_H_ */
diff --git a/drivers/webpold/enc/webpenc.c b/drivers/webpold/enc/webpenc.c
new file mode 100644
index 0000000000..3c275589fc
--- /dev/null
+++ b/drivers/webpold/enc/webpenc.c
@@ -0,0 +1,389 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// WebP encoder: main entry point
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "./vp8enci.h"
+#include "./vp8li.h"
+#include "../utils/utils.h"
+
+// #define PRINT_MEMORY_INFO
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#ifdef PRINT_MEMORY_INFO
+#include <stdio.h>
+#endif
+
+//------------------------------------------------------------------------------
+
+int WebPGetEncoderVersion(void) {
+ return (ENC_MAJ_VERSION << 16) | (ENC_MIN_VERSION << 8) | ENC_REV_VERSION;
+}
+
+//------------------------------------------------------------------------------
+// WebPPicture
+//------------------------------------------------------------------------------
+
+static int DummyWriter(const uint8_t* data, size_t data_size,
+ const WebPPicture* const picture) {
+ // The following are to prevent 'unused variable' error message.
+ (void)data;
+ (void)data_size;
+ (void)picture;
+ return 1;
+}
+
+int WebPPictureInitInternal(WebPPicture* picture, int version) {
+ if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_ENCODER_ABI_VERSION)) {
+ return 0; // caller/system version mismatch!
+ }
+ if (picture != NULL) {
+ memset(picture, 0, sizeof(*picture));
+ picture->writer = DummyWriter;
+ WebPEncodingSetError(picture, VP8_ENC_OK);
+ }
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+// VP8Encoder
+//------------------------------------------------------------------------------
+
+static void ResetSegmentHeader(VP8Encoder* const enc) {
+ VP8SegmentHeader* const hdr = &enc->segment_hdr_;
+ hdr->num_segments_ = enc->config_->segments;
+ hdr->update_map_ = (hdr->num_segments_ > 1);
+ hdr->size_ = 0;
+}
+
+static void ResetFilterHeader(VP8Encoder* const enc) {
+ VP8FilterHeader* const hdr = &enc->filter_hdr_;
+ hdr->simple_ = 1;
+ hdr->level_ = 0;
+ hdr->sharpness_ = 0;
+ hdr->i4x4_lf_delta_ = 0;
+}
+
+static void ResetBoundaryPredictions(VP8Encoder* const enc) {
+ // init boundary values once for all
+ // Note: actually, initializing the preds_[] is only needed for intra4.
+ int i;
+ uint8_t* const top = enc->preds_ - enc->preds_w_;
+ uint8_t* const left = enc->preds_ - 1;
+ for (i = -1; i < 4 * enc->mb_w_; ++i) {
+ top[i] = B_DC_PRED;
+ }
+ for (i = 0; i < 4 * enc->mb_h_; ++i) {
+ left[i * enc->preds_w_] = B_DC_PRED;
+ }
+ enc->nz_[-1] = 0; // constant
+}
+
+// Map configured quality level to coding tools used.
+//-------------+---+---+---+---+---+---+
+// Quality | 0 | 1 | 2 | 3 | 4 | 5 +
+//-------------+---+---+---+---+---+---+
+// dynamic prob| ~ | x | x | x | x | x |
+//-------------+---+---+---+---+---+---+
+// rd-opt modes| | | x | x | x | x |
+//-------------+---+---+---+---+---+---+
+// fast i4/i16 | x | x | | | | |
+//-------------+---+---+---+---+---+---+
+// rd-opt i4/16| | | x | x | x | x |
+//-------------+---+---+---+---+---+---+
+// Trellis | | x | | | x | x |
+//-------------+---+---+---+---+---+---+
+// full-SNS | | | | | | x |
+//-------------+---+---+---+---+---+---+
+
+static void MapConfigToTools(VP8Encoder* const enc) {
+ const int method = enc->config_->method;
+ const int limit = 100 - enc->config_->partition_limit;
+ enc->method_ = method;
+ enc->rd_opt_level_ = (method >= 6) ? 3
+ : (method >= 5) ? 2
+ : (method >= 3) ? 1
+ : 0;
+ enc->max_i4_header_bits_ =
+ 256 * 16 * 16 * // upper bound: up to 16bit per 4x4 block
+ (limit * limit) / (100 * 100); // ... modulated with a quadratic curve.
+}
+
+// Memory scaling with dimensions:
+// memory (bytes) ~= 2.25 * w + 0.0625 * w * h
+//
+// Typical memory footprint (768x510 picture)
+// Memory used:
+// encoder: 33919
+// block cache: 2880
+// info: 3072
+// preds: 24897
+// top samples: 1623
+// non-zero: 196
+// lf-stats: 2048
+// total: 68635
+// Transcient object sizes:
+// VP8EncIterator: 352
+// VP8ModeScore: 912
+// VP8SegmentInfo: 532
+// VP8Proba: 31032
+// LFStats: 2048
+// Picture size (yuv): 589824
+
+static VP8Encoder* InitVP8Encoder(const WebPConfig* const config,
+ WebPPicture* const picture) {
+ const int use_filter =
+ (config->filter_strength > 0) || (config->autofilter > 0);
+ const int mb_w = (picture->width + 15) >> 4;
+ const int mb_h = (picture->height + 15) >> 4;
+ const int preds_w = 4 * mb_w + 1;
+ const int preds_h = 4 * mb_h + 1;
+ const size_t preds_size = preds_w * preds_h * sizeof(uint8_t);
+ const int top_stride = mb_w * 16;
+ const size_t nz_size = (mb_w + 1) * sizeof(uint32_t);
+ const size_t cache_size = (3 * YUV_SIZE + PRED_SIZE) * sizeof(uint8_t);
+ const size_t info_size = mb_w * mb_h * sizeof(VP8MBInfo);
+ const size_t samples_size = (2 * top_stride + // top-luma/u/v
+ 16 + 16 + 16 + 8 + 1 + // left y/u/v
+ 2 * ALIGN_CST) // align all
+ * sizeof(uint8_t);
+ const size_t lf_stats_size =
+ config->autofilter ? sizeof(LFStats) + ALIGN_CST : 0;
+ VP8Encoder* enc;
+ uint8_t* mem;
+ const uint64_t size = (uint64_t)sizeof(VP8Encoder) // main struct
+ + ALIGN_CST // cache alignment
+ + cache_size // working caches
+ + info_size // modes info
+ + preds_size // prediction modes
+ + samples_size // top/left samples
+ + nz_size // coeff context bits
+ + lf_stats_size; // autofilter stats
+
+#ifdef PRINT_MEMORY_INFO
+ printf("===================================\n");
+ printf("Memory used:\n"
+ " encoder: %ld\n"
+ " block cache: %ld\n"
+ " info: %ld\n"
+ " preds: %ld\n"
+ " top samples: %ld\n"
+ " non-zero: %ld\n"
+ " lf-stats: %ld\n"
+ " total: %ld\n",
+ sizeof(VP8Encoder) + ALIGN_CST, cache_size, info_size,
+ preds_size, samples_size, nz_size, lf_stats_size, size);
+ printf("Transcient object sizes:\n"
+ " VP8EncIterator: %ld\n"
+ " VP8ModeScore: %ld\n"
+ " VP8SegmentInfo: %ld\n"
+ " VP8Proba: %ld\n"
+ " LFStats: %ld\n",
+ sizeof(VP8EncIterator), sizeof(VP8ModeScore),
+ sizeof(VP8SegmentInfo), sizeof(VP8Proba),
+ sizeof(LFStats));
+ printf("Picture size (yuv): %ld\n",
+ mb_w * mb_h * 384 * sizeof(uint8_t));
+ printf("===================================\n");
+#endif
+ mem = (uint8_t*)WebPSafeMalloc(size, sizeof(*mem));
+ if (mem == NULL) {
+ WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
+ return NULL;
+ }
+ enc = (VP8Encoder*)mem;
+ mem = (uint8_t*)DO_ALIGN(mem + sizeof(*enc));
+ memset(enc, 0, sizeof(*enc));
+ enc->num_parts_ = 1 << config->partitions;
+ enc->mb_w_ = mb_w;
+ enc->mb_h_ = mb_h;
+ enc->preds_w_ = preds_w;
+ enc->yuv_in_ = (uint8_t*)mem;
+ mem += YUV_SIZE;
+ enc->yuv_out_ = (uint8_t*)mem;
+ mem += YUV_SIZE;
+ enc->yuv_out2_ = (uint8_t*)mem;
+ mem += YUV_SIZE;
+ enc->yuv_p_ = (uint8_t*)mem;
+ mem += PRED_SIZE;
+ enc->mb_info_ = (VP8MBInfo*)mem;
+ mem += info_size;
+ enc->preds_ = ((uint8_t*)mem) + 1 + enc->preds_w_;
+ mem += preds_w * preds_h * sizeof(uint8_t);
+ enc->nz_ = 1 + (uint32_t*)mem;
+ mem += nz_size;
+ enc->lf_stats_ = lf_stats_size ? (LFStats*)DO_ALIGN(mem) : NULL;
+ mem += lf_stats_size;
+
+ // top samples (all 16-aligned)
+ mem = (uint8_t*)DO_ALIGN(mem);
+ enc->y_top_ = (uint8_t*)mem;
+ enc->uv_top_ = enc->y_top_ + top_stride;
+ mem += 2 * top_stride;
+ mem = (uint8_t*)DO_ALIGN(mem + 1);
+ enc->y_left_ = (uint8_t*)mem;
+ mem += 16 + 16;
+ enc->u_left_ = (uint8_t*)mem;
+ mem += 16;
+ enc->v_left_ = (uint8_t*)mem;
+ mem += 8;
+
+ enc->config_ = config;
+ enc->profile_ = use_filter ? ((config->filter_type == 1) ? 0 : 1) : 2;
+ enc->pic_ = picture;
+ enc->percent_ = 0;
+
+ MapConfigToTools(enc);
+ VP8EncDspInit();
+ VP8DefaultProbas(enc);
+ ResetSegmentHeader(enc);
+ ResetFilterHeader(enc);
+ ResetBoundaryPredictions(enc);
+
+ VP8EncInitAlpha(enc);
+#ifdef WEBP_EXPERIMENTAL_FEATURES
+ VP8EncInitLayer(enc);
+#endif
+
+ return enc;
+}
+
+static void DeleteVP8Encoder(VP8Encoder* enc) {
+ if (enc != NULL) {
+ VP8EncDeleteAlpha(enc);
+#ifdef WEBP_EXPERIMENTAL_FEATURES
+ VP8EncDeleteLayer(enc);
+#endif
+ free(enc);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+static double GetPSNR(uint64_t err, uint64_t size) {
+ return err ? 10. * log10(255. * 255. * size / err) : 99.;
+}
+
+static void FinalizePSNR(const VP8Encoder* const enc) {
+ WebPAuxStats* stats = enc->pic_->stats;
+ const uint64_t size = enc->sse_count_;
+ const uint64_t* const sse = enc->sse_;
+ stats->PSNR[0] = (float)GetPSNR(sse[0], size);
+ stats->PSNR[1] = (float)GetPSNR(sse[1], size / 4);
+ stats->PSNR[2] = (float)GetPSNR(sse[2], size / 4);
+ stats->PSNR[3] = (float)GetPSNR(sse[0] + sse[1] + sse[2], size * 3 / 2);
+ stats->PSNR[4] = (float)GetPSNR(sse[3], size);
+}
+
+static void StoreStats(VP8Encoder* const enc) {
+ WebPAuxStats* const stats = enc->pic_->stats;
+ if (stats != NULL) {
+ int i, s;
+ for (i = 0; i < NUM_MB_SEGMENTS; ++i) {
+ stats->segment_level[i] = enc->dqm_[i].fstrength_;
+ stats->segment_quant[i] = enc->dqm_[i].quant_;
+ for (s = 0; s <= 2; ++s) {
+ stats->residual_bytes[s][i] = enc->residual_bytes_[s][i];
+ }
+ }
+ FinalizePSNR(enc);
+ stats->coded_size = enc->coded_size_;
+ for (i = 0; i < 3; ++i) {
+ stats->block_count[i] = enc->block_count_[i];
+ }
+ }
+ WebPReportProgress(enc->pic_, 100, &enc->percent_); // done!
+}
+
+int WebPEncodingSetError(const WebPPicture* const pic,
+ WebPEncodingError error) {
+ assert((int)error < VP8_ENC_ERROR_LAST);
+ assert((int)error >= VP8_ENC_OK);
+ ((WebPPicture*)pic)->error_code = error;
+ return 0;
+}
+
+int WebPReportProgress(const WebPPicture* const pic,
+ int percent, int* const percent_store) {
+ if (percent_store != NULL && percent != *percent_store) {
+ *percent_store = percent;
+ if (pic->progress_hook && !pic->progress_hook(percent, pic)) {
+ // user abort requested
+ WebPEncodingSetError(pic, VP8_ENC_ERROR_USER_ABORT);
+ return 0;
+ }
+ }
+ return 1; // ok
+}
+//------------------------------------------------------------------------------
+
+int WebPEncode(const WebPConfig* config, WebPPicture* pic) {
+ int ok;
+
+ if (pic == NULL)
+ return 0;
+ WebPEncodingSetError(pic, VP8_ENC_OK); // all ok so far
+ if (config == NULL) // bad params
+ return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER);
+ if (!WebPValidateConfig(config))
+ return WebPEncodingSetError(pic, VP8_ENC_ERROR_INVALID_CONFIGURATION);
+ if (pic->width <= 0 || pic->height <= 0)
+ return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION);
+ if (pic->width > WEBP_MAX_DIMENSION || pic->height > WEBP_MAX_DIMENSION)
+ return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION);
+
+ if (pic->stats != NULL) memset(pic->stats, 0, sizeof(*pic->stats));
+
+ if (!config->lossless) {
+ VP8Encoder* enc = NULL;
+ if (pic->y == NULL || pic->u == NULL || pic->v == NULL) {
+ if (pic->argb != NULL) {
+ if (!WebPPictureARGBToYUVA(pic, WEBP_YUV420)) return 0;
+ } else {
+ return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER);
+ }
+ }
+
+ enc = InitVP8Encoder(config, pic);
+ if (enc == NULL) return 0; // pic->error is already set.
+ // Note: each of the tasks below account for 20% in the progress report.
+ ok = VP8EncAnalyze(enc)
+ && VP8StatLoop(enc)
+ && VP8EncLoop(enc)
+ && VP8EncFinishAlpha(enc)
+#ifdef WEBP_EXPERIMENTAL_FEATURES
+ && VP8EncFinishLayer(enc)
+#endif
+ && VP8EncWrite(enc);
+ StoreStats(enc);
+ if (!ok) {
+ VP8EncFreeBitWriters(enc);
+ }
+ DeleteVP8Encoder(enc);
+ } else {
+ if (pic->argb == NULL)
+ return WebPEncodingSetError(pic, VP8_ENC_ERROR_NULL_PARAMETER);
+
+ ok = VP8LEncodeImage(config, pic); // Sets pic->error in case of problem.
+ }
+
+ return ok;
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/encode.h b/drivers/webpold/encode.h
new file mode 100644
index 0000000000..2e37cfabe7
--- /dev/null
+++ b/drivers/webpold/encode.h
@@ -0,0 +1,463 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// WebP encoder: main interface
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#ifndef WEBP_WEBP_ENCODE_H_
+#define WEBP_WEBP_ENCODE_H_
+
+#include "./types.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define WEBP_ENCODER_ABI_VERSION 0x0200 // MAJOR(8b) + MINOR(8b)
+
+// Return the encoder's version number, packed in hexadecimal using 8bits for
+// each of major/minor/revision. E.g: v2.5.7 is 0x020507.
+WEBP_EXTERN(int) WebPGetEncoderVersion(void);
+
+//------------------------------------------------------------------------------
+// One-stop-shop call! No questions asked:
+
+// Returns the size of the compressed data (pointed to by *output), or 0 if
+// an error occurred. The compressed data must be released by the caller
+// using the call 'free(*output)'.
+// These functions compress using the lossy format, and the quality_factor
+// can go from 0 (smaller output, lower quality) to 100 (best quality,
+// larger output).
+WEBP_EXTERN(size_t) WebPEncodeRGB(const uint8_t* rgb,
+ int width, int height, int stride,
+ float quality_factor, uint8_t** output);
+WEBP_EXTERN(size_t) WebPEncodeBGR(const uint8_t* bgr,
+ int width, int height, int stride,
+ float quality_factor, uint8_t** output);
+WEBP_EXTERN(size_t) WebPEncodeRGBA(const uint8_t* rgba,
+ int width, int height, int stride,
+ float quality_factor, uint8_t** output);
+WEBP_EXTERN(size_t) WebPEncodeBGRA(const uint8_t* bgra,
+ int width, int height, int stride,
+ float quality_factor, uint8_t** output);
+
+// These functions are the equivalent of the above, but compressing in a
+// lossless manner. Files are usually larger than lossy format, but will
+// not suffer any compression loss.
+WEBP_EXTERN(size_t) WebPEncodeLosslessRGB(const uint8_t* rgb,
+ int width, int height, int stride,
+ uint8_t** output);
+WEBP_EXTERN(size_t) WebPEncodeLosslessBGR(const uint8_t* bgr,
+ int width, int height, int stride,
+ uint8_t** output);
+WEBP_EXTERN(size_t) WebPEncodeLosslessRGBA(const uint8_t* rgba,
+ int width, int height, int stride,
+ uint8_t** output);
+WEBP_EXTERN(size_t) WebPEncodeLosslessBGRA(const uint8_t* bgra,
+ int width, int height, int stride,
+ uint8_t** output);
+
+//------------------------------------------------------------------------------
+// Coding parameters
+
+// Image characteristics hint for the underlying encoder.
+typedef enum {
+ WEBP_HINT_DEFAULT = 0, // default preset.
+ WEBP_HINT_PICTURE, // digital picture, like portrait, inner shot
+ WEBP_HINT_PHOTO, // outdoor photograph, with natural lighting
+ WEBP_HINT_GRAPH, // Discrete tone image (graph, map-tile etc).
+ WEBP_HINT_LAST
+} WebPImageHint;
+
+typedef struct {
+ int lossless; // Lossless encoding (0=lossy(default), 1=lossless).
+ float quality; // between 0 (smallest file) and 100 (biggest)
+ int method; // quality/speed trade-off (0=fast, 6=slower-better)
+
+ WebPImageHint image_hint; // Hint for image type (lossless only for now).
+
+ // Parameters related to lossy compression only:
+ int target_size; // if non-zero, set the desired target size in bytes.
+ // Takes precedence over the 'compression' parameter.
+ float target_PSNR; // if non-zero, specifies the minimal distortion to
+ // try to achieve. Takes precedence over target_size.
+ int segments; // maximum number of segments to use, in [1..4]
+ int sns_strength; // Spatial Noise Shaping. 0=off, 100=maximum.
+ int filter_strength; // range: [0 = off .. 100 = strongest]
+ int filter_sharpness; // range: [0 = off .. 7 = least sharp]
+ int filter_type; // filtering type: 0 = simple, 1 = strong (only used
+ // if filter_strength > 0 or autofilter > 0)
+ int autofilter; // Auto adjust filter's strength [0 = off, 1 = on]
+ int alpha_compression; // Algorithm for encoding the alpha plane (0 = none,
+ // 1 = compressed with WebP lossless). Default is 1.
+ int alpha_filtering; // Predictive filtering method for alpha plane.
+ // 0: none, 1: fast, 2: best. Default if 1.
+ int alpha_quality; // Between 0 (smallest size) and 100 (lossless).
+ // Default is 100.
+ int pass; // number of entropy-analysis passes (in [1..10]).
+
+ int show_compressed; // if true, export the compressed picture back.
+ // In-loop filtering is not applied.
+ int preprocessing; // preprocessing filter (0=none, 1=segment-smooth)
+ int partitions; // log2(number of token partitions) in [0..3]. Default
+ // is set to 0 for easier progressive decoding.
+ int partition_limit; // quality degradation allowed to fit the 512k limit
+ // on prediction modes coding (0: no degradation,
+ // 100: maximum possible degradation).
+
+ uint32_t pad[8]; // padding for later use
+} WebPConfig;
+
+// Enumerate some predefined settings for WebPConfig, depending on the type
+// of source picture. These presets are used when calling WebPConfigPreset().
+typedef enum {
+ WEBP_PRESET_DEFAULT = 0, // default preset.
+ WEBP_PRESET_PICTURE, // digital picture, like portrait, inner shot
+ WEBP_PRESET_PHOTO, // outdoor photograph, with natural lighting
+ WEBP_PRESET_DRAWING, // hand or line drawing, with high-contrast details
+ WEBP_PRESET_ICON, // small-sized colorful images
+ WEBP_PRESET_TEXT // text-like
+} WebPPreset;
+
+// Internal, version-checked, entry point
+WEBP_EXTERN(int) WebPConfigInitInternal(WebPConfig*, WebPPreset, float, int);
+
+// Should always be called, to initialize a fresh WebPConfig structure before
+// modification. Returns false in case of version mismatch. WebPConfigInit()
+// must have succeeded before using the 'config' object.
+// Note that the default values are lossless=0 and quality=75.
+static WEBP_INLINE int WebPConfigInit(WebPConfig* config) {
+ return WebPConfigInitInternal(config, WEBP_PRESET_DEFAULT, 75.f,
+ WEBP_ENCODER_ABI_VERSION);
+}
+
+// This function will initialize the configuration according to a predefined
+// set of parameters (referred to by 'preset') and a given quality factor.
+// This function can be called as a replacement to WebPConfigInit(). Will
+// return false in case of error.
+static WEBP_INLINE int WebPConfigPreset(WebPConfig* config,
+ WebPPreset preset, float quality) {
+ return WebPConfigInitInternal(config, preset, quality,
+ WEBP_ENCODER_ABI_VERSION);
+}
+
+// Returns true if 'config' is non-NULL and all configuration parameters are
+// within their valid ranges.
+WEBP_EXTERN(int) WebPValidateConfig(const WebPConfig* config);
+
+//------------------------------------------------------------------------------
+// Input / Output
+
+typedef struct WebPPicture WebPPicture; // main structure for I/O
+
+// Structure for storing auxiliary statistics (mostly for lossy encoding).
+typedef struct {
+ int coded_size; // final size
+
+ float PSNR[5]; // peak-signal-to-noise ratio for Y/U/V/All/Alpha
+ int block_count[3]; // number of intra4/intra16/skipped macroblocks
+ int header_bytes[2]; // approximate number of bytes spent for header
+ // and mode-partition #0
+ int residual_bytes[3][4]; // approximate number of bytes spent for
+ // DC/AC/uv coefficients for each (0..3) segments.
+ int segment_size[4]; // number of macroblocks in each segments
+ int segment_quant[4]; // quantizer values for each segments
+ int segment_level[4]; // filtering strength for each segments [0..63]
+
+ int alpha_data_size; // size of the transparency data
+ int layer_data_size; // size of the enhancement layer data
+
+ // lossless encoder statistics
+ uint32_t lossless_features; // bit0:predictor bit1:cross-color transform
+ // bit2:subtract-green bit3:color indexing
+ int histogram_bits; // number of precision bits of histogram
+ int transform_bits; // precision bits for transform
+ int cache_bits; // number of bits for color cache lookup
+ int palette_size; // number of color in palette, if used
+ int lossless_size; // final lossless size
+
+ uint32_t pad[4]; // padding for later use
+} WebPAuxStats;
+
+// Signature for output function. Should return true if writing was successful.
+// data/data_size is the segment of data to write, and 'picture' is for
+// reference (and so one can make use of picture->custom_ptr).
+typedef int (*WebPWriterFunction)(const uint8_t* data, size_t data_size,
+ const WebPPicture* picture);
+
+// WebPMemoryWrite: a special WebPWriterFunction that writes to memory using
+// the following WebPMemoryWriter object (to be set as a custom_ptr).
+typedef struct {
+ uint8_t* mem; // final buffer (of size 'max_size', larger than 'size').
+ size_t size; // final size
+ size_t max_size; // total capacity
+ uint32_t pad[1]; // padding for later use
+} WebPMemoryWriter;
+
+// The following must be called first before any use.
+WEBP_EXTERN(void) WebPMemoryWriterInit(WebPMemoryWriter* writer);
+
+// The custom writer to be used with WebPMemoryWriter as custom_ptr. Upon
+// completion, writer.mem and writer.size will hold the coded data.
+WEBP_EXTERN(int) WebPMemoryWrite(const uint8_t* data, size_t data_size,
+ const WebPPicture* picture);
+
+// Progress hook, called from time to time to report progress. It can return
+// false to request an abort of the encoding process, or true otherwise if
+// everything is OK.
+typedef int (*WebPProgressHook)(int percent, const WebPPicture* picture);
+
+typedef enum {
+ // chroma sampling
+ WEBP_YUV420 = 0, // 4:2:0
+ WEBP_YUV422 = 1, // 4:2:2
+ WEBP_YUV444 = 2, // 4:4:4
+ WEBP_YUV400 = 3, // grayscale
+ WEBP_CSP_UV_MASK = 3, // bit-mask to get the UV sampling factors
+ // alpha channel variants
+ WEBP_YUV420A = 4,
+ WEBP_YUV422A = 5,
+ WEBP_YUV444A = 6,
+ WEBP_YUV400A = 7, // grayscale + alpha
+ WEBP_CSP_ALPHA_BIT = 4 // bit that is set if alpha is present
+} WebPEncCSP;
+
+// Encoding error conditions.
+typedef enum {
+ VP8_ENC_OK = 0,
+ VP8_ENC_ERROR_OUT_OF_MEMORY, // memory error allocating objects
+ VP8_ENC_ERROR_BITSTREAM_OUT_OF_MEMORY, // memory error while flushing bits
+ VP8_ENC_ERROR_NULL_PARAMETER, // a pointer parameter is NULL
+ VP8_ENC_ERROR_INVALID_CONFIGURATION, // configuration is invalid
+ VP8_ENC_ERROR_BAD_DIMENSION, // picture has invalid width/height
+ VP8_ENC_ERROR_PARTITION0_OVERFLOW, // partition is bigger than 512k
+ VP8_ENC_ERROR_PARTITION_OVERFLOW, // partition is bigger than 16M
+ VP8_ENC_ERROR_BAD_WRITE, // error while flushing bytes
+ VP8_ENC_ERROR_FILE_TOO_BIG, // file is bigger than 4G
+ VP8_ENC_ERROR_USER_ABORT, // abort request by user
+ VP8_ENC_ERROR_LAST // list terminator. always last.
+} WebPEncodingError;
+
+// maximum width/height allowed (inclusive), in pixels
+#define WEBP_MAX_DIMENSION 16383
+
+// Main exchange structure (input samples, output bytes, statistics)
+struct WebPPicture {
+
+ // INPUT
+ //////////////
+ // Main flag for encoder selecting between ARGB or YUV input.
+ // It is recommended to use ARGB input (*argb, argb_stride) for lossless
+ // compression, and YUV input (*y, *u, *v, etc.) for lossy compression
+ // since these are the respective native colorspace for these formats.
+ int use_argb;
+
+ // YUV input (mostly used for input to lossy compression)
+ WebPEncCSP colorspace; // colorspace: should be YUV420 for now (=Y'CbCr).
+ int width, height; // dimensions (less or equal to WEBP_MAX_DIMENSION)
+ uint8_t *y, *u, *v; // pointers to luma/chroma planes.
+ int y_stride, uv_stride; // luma/chroma strides.
+ uint8_t* a; // pointer to the alpha plane
+ int a_stride; // stride of the alpha plane
+ uint32_t pad1[2]; // padding for later use
+
+ // ARGB input (mostly used for input to lossless compression)
+ uint32_t* argb; // Pointer to argb (32 bit) plane.
+ int argb_stride; // This is stride in pixels units, not bytes.
+ uint32_t pad2[3]; // padding for later use
+
+ // OUTPUT
+ ///////////////
+ // Byte-emission hook, to store compressed bytes as they are ready.
+ WebPWriterFunction writer; // can be NULL
+ void* custom_ptr; // can be used by the writer.
+
+ // map for extra information (only for lossy compression mode)
+ int extra_info_type; // 1: intra type, 2: segment, 3: quant
+ // 4: intra-16 prediction mode,
+ // 5: chroma prediction mode,
+ // 6: bit cost, 7: distortion
+ uint8_t* extra_info; // if not NULL, points to an array of size
+ // ((width + 15) / 16) * ((height + 15) / 16) that
+ // will be filled with a macroblock map, depending
+ // on extra_info_type.
+
+ // STATS AND REPORTS
+ ///////////////////////////
+ // Pointer to side statistics (updated only if not NULL)
+ WebPAuxStats* stats;
+
+ // Error code for the latest error encountered during encoding
+ WebPEncodingError error_code;
+
+ // If not NULL, report progress during encoding.
+ WebPProgressHook progress_hook;
+
+ void* user_data; // this field is free to be set to any value and
+ // used during callbacks (like progress-report e.g.).
+
+ uint32_t pad3[3]; // padding for later use
+
+ // Unused for now: original samples (for non-YUV420 modes)
+ uint8_t *u0, *v0;
+ int uv0_stride;
+
+ uint32_t pad4[7]; // padding for later use
+
+ // PRIVATE FIELDS
+ ////////////////////
+ void* memory_; // row chunk of memory for yuva planes
+ void* memory_argb_; // and for argb too.
+ void* pad5[2]; // padding for later use
+};
+
+// Internal, version-checked, entry point
+WEBP_EXTERN(int) WebPPictureInitInternal(WebPPicture*, int);
+
+// Should always be called, to initialize the structure. Returns false in case
+// of version mismatch. WebPPictureInit() must have succeeded before using the
+// 'picture' object.
+// Note that, by default, use_argb is false and colorspace is WEBP_YUV420.
+static WEBP_INLINE int WebPPictureInit(WebPPicture* picture) {
+ return WebPPictureInitInternal(picture, WEBP_ENCODER_ABI_VERSION);
+}
+
+//------------------------------------------------------------------------------
+// WebPPicture utils
+
+// Convenience allocation / deallocation based on picture->width/height:
+// Allocate y/u/v buffers as per colorspace/width/height specification.
+// Note! This function will free the previous buffer if needed.
+// Returns false in case of memory error.
+WEBP_EXTERN(int) WebPPictureAlloc(WebPPicture* picture);
+
+// Release the memory allocated by WebPPictureAlloc() or WebPPictureImport*().
+// Note that this function does _not_ free the memory used by the 'picture'
+// object itself.
+// Besides memory (which is reclaimed) all other fields of 'picture' are
+// preserved.
+WEBP_EXTERN(void) WebPPictureFree(WebPPicture* picture);
+
+// Copy the pixels of *src into *dst, using WebPPictureAlloc. Upon return,
+// *dst will fully own the copied pixels (this is not a view).
+// Returns false in case of memory allocation error.
+WEBP_EXTERN(int) WebPPictureCopy(const WebPPicture* src, WebPPicture* dst);
+
+// Compute PSNR or SSIM distortion between two pictures.
+// Result is in dB, stores in result[] in the Y/U/V/Alpha/All order.
+// Returns false in case of error (pic1 and pic2 don't have same dimension, ...)
+// Warning: this function is rather CPU-intensive.
+WEBP_EXTERN(int) WebPPictureDistortion(
+ const WebPPicture* pic1, const WebPPicture* pic2,
+ int metric_type, // 0 = PSNR, 1 = SSIM
+ float result[5]);
+
+// self-crops a picture to the rectangle defined by top/left/width/height.
+// Returns false in case of memory allocation error, or if the rectangle is
+// outside of the source picture.
+// The rectangle for the view is defined by the top-left corner pixel
+// coordinates (left, top) as well as its width and height. This rectangle
+// must be fully be comprised inside the 'src' source picture. If the source
+// picture uses the YUV420 colorspace, the top and left coordinates will be
+// snapped to even values.
+WEBP_EXTERN(int) WebPPictureCrop(WebPPicture* picture,
+ int left, int top, int width, int height);
+
+// Extracts a view from 'src' picture into 'dst'. The rectangle for the view
+// is defined by the top-left corner pixel coordinates (left, top) as well
+// as its width and height. This rectangle must be fully be comprised inside
+// the 'src' source picture. If the source picture uses the YUV420 colorspace,
+// the top and left coordinates will be snapped to even values.
+// Picture 'src' must out-live 'dst' picture. Self-extraction of view is allowed
+// ('src' equal to 'dst') as a mean of fast-cropping (but note that doing so,
+// the original dimension will be lost).
+// Returns false in case of memory allocation error or invalid parameters.
+WEBP_EXTERN(int) WebPPictureView(const WebPPicture* src,
+ int left, int top, int width, int height,
+ WebPPicture* dst);
+
+// Returns true if the 'picture' is actually a view and therefore does
+// not own the memory for pixels.
+WEBP_EXTERN(int) WebPPictureIsView(const WebPPicture* picture);
+
+// Rescale a picture to new dimension width x height.
+// Now gamma correction is applied.
+// Returns false in case of error (invalid parameter or insufficient memory).
+WEBP_EXTERN(int) WebPPictureRescale(WebPPicture* pic, int width, int height);
+
+// Colorspace conversion function to import RGB samples.
+// Previous buffer will be free'd, if any.
+// *rgb buffer should have a size of at least height * rgb_stride.
+// Returns false in case of memory error.
+WEBP_EXTERN(int) WebPPictureImportRGB(
+ WebPPicture* picture, const uint8_t* rgb, int rgb_stride);
+// Same, but for RGBA buffer.
+WEBP_EXTERN(int) WebPPictureImportRGBA(
+ WebPPicture* picture, const uint8_t* rgba, int rgba_stride);
+// Same, but for RGBA buffer. Imports the RGB direct from the 32-bit format
+// input buffer ignoring the alpha channel. Avoids needing to copy the data
+// to a temporary 24-bit RGB buffer to import the RGB only.
+WEBP_EXTERN(int) WebPPictureImportRGBX(
+ WebPPicture* picture, const uint8_t* rgbx, int rgbx_stride);
+
+// Variants of the above, but taking BGR(A|X) input.
+WEBP_EXTERN(int) WebPPictureImportBGR(
+ WebPPicture* picture, const uint8_t* bgr, int bgr_stride);
+WEBP_EXTERN(int) WebPPictureImportBGRA(
+ WebPPicture* picture, const uint8_t* bgra, int bgra_stride);
+WEBP_EXTERN(int) WebPPictureImportBGRX(
+ WebPPicture* picture, const uint8_t* bgrx, int bgrx_stride);
+
+// Converts picture->argb data to the YUVA format specified by 'colorspace'.
+// Upon return, picture->use_argb is set to false. The presence of real
+// non-opaque transparent values is detected, and 'colorspace' will be
+// adjusted accordingly. Note that this method is lossy.
+// Returns false in case of error.
+WEBP_EXTERN(int) WebPPictureARGBToYUVA(WebPPicture* picture,
+ WebPEncCSP colorspace);
+
+// Converts picture->yuv to picture->argb and sets picture->use_argb to true.
+// The input format must be YUV_420 or YUV_420A.
+// Note that the use of this method is discouraged if one has access to the
+// raw ARGB samples, since using YUV420 is comparatively lossy. Also, the
+// conversion from YUV420 to ARGB incurs a small loss too.
+// Returns false in case of error.
+WEBP_EXTERN(int) WebPPictureYUVAToARGB(WebPPicture* picture);
+
+// Helper function: given a width x height plane of YUV(A) samples
+// (with stride 'stride'), clean-up the YUV samples under fully transparent
+// area, to help compressibility (no guarantee, though).
+WEBP_EXTERN(void) WebPCleanupTransparentArea(WebPPicture* picture);
+
+// Scan the picture 'picture' for the presence of non fully opaque alpha values.
+// Returns true in such case. Otherwise returns false (indicating that the
+// alpha plane can be ignored altogether e.g.).
+WEBP_EXTERN(int) WebPPictureHasTransparency(const WebPPicture* picture);
+
+//------------------------------------------------------------------------------
+// Main call
+
+// Main encoding call, after config and picture have been initialized.
+// 'picture' must be less than 16384x16384 in dimension (cf WEBP_MAX_DIMENSION),
+// and the 'config' object must be a valid one.
+// Returns false in case of error, true otherwise.
+// In case of error, picture->error_code is updated accordingly.
+// 'picture' can hold the source samples in both YUV(A) or ARGB input, depending
+// on the value of 'picture->use_argb'. It is highly recommended to use
+// the former for lossy encoding, and the latter for lossless encoding
+// (when config.lossless is true). Automatic conversion from one format to
+// another is provided but they both incur some loss.
+WEBP_EXTERN(int) WebPEncode(const WebPConfig* config, WebPPicture* picture);
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif /* WEBP_WEBP_ENCODE_H_ */
diff --git a/drivers/webpold/format_constants.h b/drivers/webpold/format_constants.h
new file mode 100644
index 0000000000..7ce498f672
--- /dev/null
+++ b/drivers/webpold/format_constants.h
@@ -0,0 +1,90 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Internal header for constants related to WebP file format.
+//
+// Author: Urvang (urvang@google.com)
+
+#ifndef WEBP_WEBP_FORMAT_CONSTANTS_H_
+#define WEBP_WEBP_FORMAT_CONSTANTS_H_
+
+// VP8 related constants.
+#define VP8_SIGNATURE 0x9d012a // Signature in VP8 data.
+#define VP8_MAX_PARTITION0_SIZE (1 << 19) // max size of mode partition
+#define VP8_MAX_PARTITION_SIZE (1 << 24) // max size for token partition
+#define VP8_FRAME_HEADER_SIZE 10 // Size of the frame header within VP8 data.
+
+// VP8L related constants.
+#define VP8L_SIGNATURE_SIZE 1 // VP8L signature size.
+#define VP8L_MAGIC_BYTE 0x2f // VP8L signature byte.
+#define VP8L_IMAGE_SIZE_BITS 14 // Number of bits used to store
+ // width and height.
+#define VP8L_VERSION_BITS 3 // 3 bits reserved for version.
+#define VP8L_VERSION 0 // version 0
+#define VP8L_FRAME_HEADER_SIZE 5 // Size of the VP8L frame header.
+
+#define MAX_PALETTE_SIZE 256
+#define MAX_CACHE_BITS 11
+#define HUFFMAN_CODES_PER_META_CODE 5
+#define ARGB_BLACK 0xff000000
+
+#define DEFAULT_CODE_LENGTH 8
+#define MAX_ALLOWED_CODE_LENGTH 15
+
+#define NUM_LITERAL_CODES 256
+#define NUM_LENGTH_CODES 24
+#define NUM_DISTANCE_CODES 40
+#define CODE_LENGTH_CODES 19
+
+#define MIN_HUFFMAN_BITS 2 // min number of Huffman bits
+#define MAX_HUFFMAN_BITS 9 // max number of Huffman bits
+
+#define TRANSFORM_PRESENT 1 // The bit to be written when next data
+ // to be read is a transform.
+#define NUM_TRANSFORMS 4 // Maximum number of allowed transform
+ // in a bitstream.
+typedef enum {
+ PREDICTOR_TRANSFORM = 0,
+ CROSS_COLOR_TRANSFORM = 1,
+ SUBTRACT_GREEN = 2,
+ COLOR_INDEXING_TRANSFORM = 3
+} VP8LImageTransformType;
+
+// Alpha related constants.
+#define ALPHA_HEADER_LEN 1
+#define ALPHA_NO_COMPRESSION 0
+#define ALPHA_LOSSLESS_COMPRESSION 1
+#define ALPHA_PREPROCESSED_LEVELS 1
+
+// Mux related constants.
+#define TAG_SIZE 4 // Size of a chunk tag (e.g. "VP8L").
+#define CHUNK_SIZE_BYTES 4 // Size needed to store chunk's size.
+#define CHUNK_HEADER_SIZE 8 // Size of a chunk header.
+#define RIFF_HEADER_SIZE 12 // Size of the RIFF header ("RIFFnnnnWEBP").
+#define FRAME_CHUNK_SIZE 15 // Size of a FRM chunk.
+#define LOOP_CHUNK_SIZE 2 // Size of a LOOP chunk.
+#define TILE_CHUNK_SIZE 6 // Size of a TILE chunk.
+#define VP8X_CHUNK_SIZE 10 // Size of a VP8X chunk.
+
+#define TILING_FLAG_BIT 0x01 // Set if tiles are possibly used.
+#define ANIMATION_FLAG_BIT 0x02 // Set if some animation is expected
+#define ICC_FLAG_BIT 0x04 // Whether ICC is present or not.
+#define METADATA_FLAG_BIT 0x08 // Set if some META chunk is possibly present.
+#define ALPHA_FLAG_BIT 0x10 // Should be same as the ALPHA_FLAG in mux.h
+#define ROTATION_FLAG_BITS 0xe0 // all 3 bits for rotation + symmetry
+
+#define MAX_CANVAS_SIZE (1 << 24) // 24-bit max for VP8X width/height.
+#define MAX_IMAGE_AREA (1ULL << 32) // 32-bit max for width x height.
+#define MAX_LOOP_COUNT (1 << 16) // maximum value for loop-count
+#define MAX_DURATION (1 << 24) // maximum duration
+#define MAX_POSITION_OFFSET (1 << 24) // maximum frame/tile x/y offset
+
+// Maximum chunk payload is such that adding the header and padding won't
+// overflow a uint32_t.
+#define MAX_CHUNK_PAYLOAD (~0U - CHUNK_HEADER_SIZE - 1)
+
+#endif /* WEBP_WEBP_FORMAT_CONSTANTS_H_ */
diff --git a/drivers/webpold/image_loader_webp.cpp b/drivers/webpold/image_loader_webp.cpp
new file mode 100644
index 0000000000..5fb14eaf7a
--- /dev/null
+++ b/drivers/webpold/image_loader_webp.cpp
@@ -0,0 +1,165 @@
+/*************************************************/
+/* image_loader_webp.cpp */
+/*************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/*************************************************/
+/* Source code within this file is: */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
+/* All Rights Reserved. */
+/*************************************************/
+
+#include "image_loader_webp.h"
+
+#include "print_string.h"
+#include "os/os.h"
+#include "drivers/webp/decode.h"
+#include "drivers/webp/encode.h"
+#include "io/marshalls.h"
+#include <stdlib.h>
+
+static DVector<uint8_t> _webp_lossy_pack(const Image& p_image,float p_quality) {
+
+ ERR_FAIL_COND_V(p_image.empty(),DVector<uint8_t>());
+
+ Image img=p_image;
+ if (img.detect_alpha())
+ img.convert(Image::FORMAT_RGBA);
+ else
+ img.convert(Image::FORMAT_RGB);
+
+ Size2 s(img.get_width(),img.get_height());
+ DVector<uint8_t> data = img.get_data();
+ DVector<uint8_t>::Read r = data.read();
+
+ uint8_t *dst_buff=NULL;
+ size_t dst_size=0;
+ if (img.get_format()==Image::FORMAT_RGB) {
+
+ dst_size = WebPEncodeRGB(r.ptr(),s.width,s.height,3*s.width,CLAMP(p_quality*100.0,0,100.0),&dst_buff);
+ } else {
+ dst_size = WebPEncodeRGBA(r.ptr(),s.width,s.height,4*s.width,CLAMP(p_quality*100.0,0,100.0),&dst_buff);
+ }
+
+ ERR_FAIL_COND_V(dst_size==0,DVector<uint8_t>());
+ DVector<uint8_t> dst;
+ dst.resize(4+dst_size);
+ DVector<uint8_t>::Write w = dst.write();
+ w[0]='W';
+ w[1]='E';
+ w[2]='B';
+ w[3]='P';
+ copymem(&w[4],dst_buff,dst_size);
+ free(dst_buff);
+ w=DVector<uint8_t>::Write();
+ return dst;
+}
+
+static Image _webp_lossy_unpack(const DVector<uint8_t>& p_buffer) {
+
+ int size = p_buffer.size()-4;
+ ERR_FAIL_COND_V(size<=0,Image());
+ DVector<uint8_t>::Read r = p_buffer.read();
+
+ ERR_FAIL_COND_V(r[0]!='W' || r[1]!='E' || r[2]!='B' || r[3]!='P',Image());
+ WebPBitstreamFeatures features;
+ if (WebPGetFeatures(&r[4],size,&features)!=VP8_STATUS_OK) {
+ ERR_EXPLAIN("Error unpacking WEBP image:");
+ ERR_FAIL_V(Image());
+ }
+
+ //print_line("width: "+itos(features.width));
+ //print_line("height: "+itos(features.height));
+ //print_line("alpha: "+itos(features.has_alpha));
+
+ DVector<uint8_t> dst_image;
+ int datasize = features.width*features.height*(features.has_alpha?4:3);
+ dst_image.resize(datasize);
+
+ DVector<uint8_t>::Write dst_w = dst_image.write();
+
+ bool errdec=false;
+ if (features.has_alpha) {
+ errdec = WebPDecodeRGBAInto(&r[4],size,dst_w.ptr(),datasize,4*features.width)==NULL;
+ } else {
+ errdec = WebPDecodeRGBInto(&r[4],size,dst_w.ptr(),datasize,3*features.width)==NULL;
+
+ }
+
+ //ERR_EXPLAIN("Error decoding webp! - "+p_file);
+ ERR_FAIL_COND_V(errdec,Image());
+
+ dst_w = DVector<uint8_t>::Write();
+
+ return Image(features.width,features.height,0,features.has_alpha?Image::FORMAT_RGBA:Image::FORMAT_RGB,dst_image);
+
+}
+
+
+Error ImageLoaderWEBP::load_image(Image *p_image,FileAccess *f) {
+
+
+ uint32_t size = f->get_len();
+ DVector<uint8_t> src_image;
+ src_image.resize(size);
+
+ WebPBitstreamFeatures features;
+
+ DVector<uint8_t>::Write src_w = src_image.write();
+ f->get_buffer(src_w.ptr(),size);
+ ERR_FAIL_COND_V(f->eof_reached(), ERR_FILE_EOF);
+
+ if (WebPGetFeatures(src_w.ptr(),size,&features)!=VP8_STATUS_OK) {
+ f->close();
+ //ERR_EXPLAIN("Error decoding WEBP image: "+p_file);
+ ERR_FAIL_V(ERR_FILE_CORRUPT);
+ }
+
+ print_line("width: "+itos(features.width));
+ print_line("height: "+itos(features.height));
+ print_line("alpha: "+itos(features.has_alpha));
+
+ src_w = DVector<uint8_t>::Write();
+
+ DVector<uint8_t> dst_image;
+ int datasize = features.width*features.height*(features.has_alpha?4:3);
+ dst_image.resize(datasize);
+
+ DVector<uint8_t>::Read src_r = src_image.read();
+ DVector<uint8_t>::Write dst_w = dst_image.write();
+
+
+ bool errdec=false;
+ if (features.has_alpha) {
+ errdec = WebPDecodeRGBAInto(src_r.ptr(),size,dst_w.ptr(),datasize,4*features.width)==NULL;
+ } else {
+ errdec = WebPDecodeRGBInto(src_r.ptr(),size,dst_w.ptr(),datasize,3*features.width)==NULL;
+
+ }
+
+ //ERR_EXPLAIN("Error decoding webp! - "+p_file);
+ ERR_FAIL_COND_V(errdec,ERR_FILE_CORRUPT);
+
+ src_r = DVector<uint8_t>::Read();
+ dst_w = DVector<uint8_t>::Write();
+
+ *p_image = Image(features.width,features.height,0,features.has_alpha?Image::FORMAT_RGBA:Image::FORMAT_RGB,dst_image);
+
+
+ return OK;
+
+}
+
+void ImageLoaderWEBP::get_recognized_extensions(List<String> *p_extensions) const {
+
+ p_extensions->push_back("webp");
+}
+
+
+ImageLoaderWEBP::ImageLoaderWEBP() {
+
+ Image::lossy_packer=_webp_lossy_pack;
+ Image::lossy_unpacker=_webp_lossy_unpack;
+}
+
+
diff --git a/drivers/webpold/image_loader_webp.h b/drivers/webpold/image_loader_webp.h
new file mode 100644
index 0000000000..ea99a60676
--- /dev/null
+++ b/drivers/webpold/image_loader_webp.h
@@ -0,0 +1,32 @@
+/*************************************************/
+/* image_loader_webp.h */
+/*************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/*************************************************/
+/* Source code within this file is: */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
+/* All Rights Reserved. */
+/*************************************************/
+
+#ifndef IMAGE_LOADER_WEBP_H
+#define IMAGE_LOADER_WEBP_H
+
+#include "io/image_loader.h"
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+class ImageLoaderWEBP : public ImageFormatLoader {
+
+
+public:
+
+ virtual Error load_image(Image *p_image,FileAccess *f);
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ ImageLoaderWEBP();
+};
+
+
+
+#endif
diff --git a/drivers/webpold/mux.h b/drivers/webpold/mux.h
new file mode 100644
index 0000000000..5139af80fa
--- /dev/null
+++ b/drivers/webpold/mux.h
@@ -0,0 +1,604 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// RIFF container manipulation for WEBP images.
+//
+// Authors: Urvang (urvang@google.com)
+// Vikas (vikasa@google.com)
+
+// This API allows manipulation of WebP container images containing features
+// like Color profile, XMP metadata, Animation and Tiling.
+//
+// Code Example#1: Creating a MUX with image data, color profile and XMP
+// metadata.
+//
+// int copy_data = 0;
+// WebPMux* mux = WebPMuxNew();
+// // ... (Prepare image data).
+// WebPMuxSetImage(mux, &image, copy_data);
+// // ... (Prepare ICCP color profile data).
+// WebPMuxSetColorProfile(mux, &icc_profile, copy_data);
+// // ... (Prepare XMP metadata).
+// WebPMuxSetMetadata(mux, &xmp, copy_data);
+// // Get data from mux in WebP RIFF format.
+// WebPMuxAssemble(mux, &output_data);
+// WebPMuxDelete(mux);
+// // ... (Consume output_data; e.g. write output_data.bytes_ to file).
+// WebPDataClear(&output_data);
+//
+// Code Example#2: Get image and color profile data from a WebP file.
+//
+// int copy_data = 0;
+// // ... (Read data from file).
+// WebPMux* mux = WebPMuxCreate(&data, copy_data);
+// WebPMuxGetImage(mux, &image);
+// // ... (Consume image; e.g. call WebPDecode() to decode the data).
+// WebPMuxGetColorProfile(mux, &icc_profile);
+// // ... (Consume icc_data).
+// WebPMuxDelete(mux);
+// free(data);
+
+#ifndef WEBP_WEBP_MUX_H_
+#define WEBP_WEBP_MUX_H_
+
+#include "./types.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define WEBP_MUX_ABI_VERSION 0x0100 // MAJOR(8b) + MINOR(8b)
+
+// Error codes
+typedef enum {
+ WEBP_MUX_OK = 1,
+ WEBP_MUX_NOT_FOUND = 0,
+ WEBP_MUX_INVALID_ARGUMENT = -1,
+ WEBP_MUX_BAD_DATA = -2,
+ WEBP_MUX_MEMORY_ERROR = -3,
+ WEBP_MUX_NOT_ENOUGH_DATA = -4
+} WebPMuxError;
+
+// Flag values for different features used in VP8X chunk.
+typedef enum {
+ TILE_FLAG = 0x00000001,
+ ANIMATION_FLAG = 0x00000002,
+ ICCP_FLAG = 0x00000004,
+ META_FLAG = 0x00000008,
+ ALPHA_FLAG = 0x00000010
+} WebPFeatureFlags;
+
+// IDs for different types of chunks.
+typedef enum {
+ WEBP_CHUNK_VP8X, // VP8X
+ WEBP_CHUNK_ICCP, // ICCP
+ WEBP_CHUNK_LOOP, // LOOP
+ WEBP_CHUNK_FRAME, // FRM
+ WEBP_CHUNK_TILE, // TILE
+ WEBP_CHUNK_ALPHA, // ALPH
+ WEBP_CHUNK_IMAGE, // VP8/VP8L
+ WEBP_CHUNK_META, // META
+ WEBP_CHUNK_UNKNOWN, // Other chunks.
+ WEBP_CHUNK_NIL
+} WebPChunkId;
+
+typedef struct WebPMux WebPMux; // main opaque object.
+
+// Data type used to describe 'raw' data, e.g., chunk data
+// (ICC profile, metadata) and WebP compressed image data.
+typedef struct {
+ const uint8_t* bytes_;
+ size_t size_;
+} WebPData;
+
+//------------------------------------------------------------------------------
+// Manipulation of a WebPData object.
+
+// Initializes the contents of the 'webp_data' object with default values.
+WEBP_EXTERN(void) WebPDataInit(WebPData* webp_data);
+
+// Clears the contents of the 'webp_data' object by calling free(). Does not
+// deallocate the object itself.
+WEBP_EXTERN(void) WebPDataClear(WebPData* webp_data);
+
+// Allocates necessary storage for 'dst' and copies the contents of 'src'.
+// Returns true on success.
+WEBP_EXTERN(int) WebPDataCopy(const WebPData* src, WebPData* dst);
+
+//------------------------------------------------------------------------------
+// Life of a Mux object
+
+// Internal, version-checked, entry point
+WEBP_EXTERN(WebPMux*) WebPNewInternal(int);
+
+// Creates an empty mux object.
+// Returns:
+// A pointer to the newly created empty mux object.
+static WEBP_INLINE WebPMux* WebPMuxNew(void) {
+ return WebPNewInternal(WEBP_MUX_ABI_VERSION);
+}
+
+// Deletes the mux object.
+// Parameters:
+// mux - (in/out) object to be deleted
+WEBP_EXTERN(void) WebPMuxDelete(WebPMux* mux);
+
+//------------------------------------------------------------------------------
+// Mux creation.
+
+// Internal, version-checked, entry point
+WEBP_EXTERN(WebPMux*) WebPMuxCreateInternal(const WebPData*, int, int);
+
+// Creates a mux object from raw data given in WebP RIFF format.
+// Parameters:
+// bitstream - (in) the bitstream data in WebP RIFF format
+// copy_data - (in) value 1 indicates given data WILL copied to the mux, and
+// value 0 indicates data will NOT be copied.
+// Returns:
+// A pointer to the mux object created from given data - on success.
+// NULL - In case of invalid data or memory error.
+static WEBP_INLINE WebPMux* WebPMuxCreate(const WebPData* bitstream,
+ int copy_data) {
+ return WebPMuxCreateInternal(bitstream, copy_data, WEBP_MUX_ABI_VERSION);
+}
+
+//------------------------------------------------------------------------------
+// Single Image.
+
+// Sets the image in the mux object. Any existing images (including frame/tile)
+// will be removed.
+// Parameters:
+// mux - (in/out) object in which the image is to be set
+// bitstream - (in) can either be a raw VP8/VP8L bitstream or a single-image
+// WebP file (non-animated and non-tiled)
+// copy_data - (in) value 1 indicates given data WILL copied to the mux, and
+// value 0 indicates data will NOT be copied.
+// Returns:
+// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or bitstream is NULL.
+// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
+// WEBP_MUX_OK - on success.
+WEBP_EXTERN(WebPMuxError) WebPMuxSetImage(WebPMux* mux,
+ const WebPData* bitstream,
+ int copy_data);
+
+// Gets image data from the mux object.
+// The content of 'bitstream' is allocated using malloc(), and NOT
+// owned by the 'mux' object. It MUST be deallocated by the caller by calling
+// WebPDataClear().
+// Parameters:
+// mux - (in) object from which the image is to be fetched
+// bitstream - (out) the image data
+// Returns:
+// WEBP_MUX_INVALID_ARGUMENT - if either mux or bitstream is NULL
+// OR mux contains animation/tiling.
+// WEBP_MUX_NOT_FOUND - if image is not present in mux object.
+// WEBP_MUX_OK - on success.
+WEBP_EXTERN(WebPMuxError) WebPMuxGetImage(const WebPMux* mux,
+ WebPData* bitstream);
+
+// Deletes the image in the mux object.
+// Parameters:
+// mux - (in/out) object from which the image is to be deleted
+// Returns:
+// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL
+// OR if mux contains animation/tiling.
+// WEBP_MUX_NOT_FOUND - if image is not present in mux object.
+// WEBP_MUX_OK - on success.
+WEBP_EXTERN(WebPMuxError) WebPMuxDeleteImage(WebPMux* mux);
+
+//------------------------------------------------------------------------------
+// XMP Metadata.
+
+// Sets the XMP metadata in the mux object. Any existing metadata chunk(s) will
+// be removed.
+// Parameters:
+// mux - (in/out) object to which the XMP metadata is to be added
+// metadata - (in) the XMP metadata data to be added
+// copy_data - (in) value 1 indicates given data WILL copied to the mux, and
+// value 0 indicates data will NOT be copied.
+// Returns:
+// WEBP_MUX_INVALID_ARGUMENT - if mux or metadata is NULL.
+// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
+// WEBP_MUX_OK - on success.
+WEBP_EXTERN(WebPMuxError) WebPMuxSetMetadata(WebPMux* mux,
+ const WebPData* metadata,
+ int copy_data);
+
+// Gets a reference to the XMP metadata in the mux object.
+// The caller should NOT free the returned data.
+// Parameters:
+// mux - (in) object from which the XMP metadata is to be fetched
+// metadata - (out) XMP metadata
+// Returns:
+// WEBP_MUX_INVALID_ARGUMENT - if either mux or metadata is NULL.
+// WEBP_MUX_NOT_FOUND - if metadata is not present in mux object.
+// WEBP_MUX_OK - on success.
+WEBP_EXTERN(WebPMuxError) WebPMuxGetMetadata(const WebPMux* mux,
+ WebPData* metadata);
+
+// Deletes the XMP metadata in the mux object.
+// Parameters:
+// mux - (in/out) object from which XMP metadata is to be deleted
+// Returns:
+// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL
+// WEBP_MUX_NOT_FOUND - If mux does not contain metadata.
+// WEBP_MUX_OK - on success.
+WEBP_EXTERN(WebPMuxError) WebPMuxDeleteMetadata(WebPMux* mux);
+
+//------------------------------------------------------------------------------
+// ICC Color Profile.
+
+// Sets the color profile in the mux object. Any existing color profile chunk(s)
+// will be removed.
+// Parameters:
+// mux - (in/out) object to which the color profile is to be added
+// color_profile - (in) the color profile data to be added
+// copy_data - (in) value 1 indicates given data WILL copied to the mux, and
+// value 0 indicates data will NOT be copied.
+// Returns:
+// WEBP_MUX_INVALID_ARGUMENT - if mux or color_profile is NULL
+// WEBP_MUX_MEMORY_ERROR - on memory allocation error
+// WEBP_MUX_OK - on success
+WEBP_EXTERN(WebPMuxError) WebPMuxSetColorProfile(WebPMux* mux,
+ const WebPData* color_profile,
+ int copy_data);
+
+// Gets a reference to the color profile in the mux object.
+// The caller should NOT free the returned data.
+// Parameters:
+// mux - (in) object from which the color profile data is to be fetched
+// color_profile - (out) color profile data
+// Returns:
+// WEBP_MUX_INVALID_ARGUMENT - if either mux or color_profile is NULL.
+// WEBP_MUX_NOT_FOUND - if color profile is not present in mux object.
+// WEBP_MUX_OK - on success.
+WEBP_EXTERN(WebPMuxError) WebPMuxGetColorProfile(const WebPMux* mux,
+ WebPData* color_profile);
+
+// Deletes the color profile in the mux object.
+// Parameters:
+// mux - (in/out) object from which color profile is to be deleted
+// Returns:
+// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL
+// WEBP_MUX_NOT_FOUND - If mux does not contain color profile.
+// WEBP_MUX_OK - on success.
+WEBP_EXTERN(WebPMuxError) WebPMuxDeleteColorProfile(WebPMux* mux);
+
+//------------------------------------------------------------------------------
+// Animation.
+
+// Adds an animation frame at the end of the mux object.
+// Note: as WebP only supports even offsets, any odd offset will be snapped to
+// an even location using: offset &= ~1
+// Parameters:
+// mux - (in/out) object to which an animation frame is to be added
+// bitstream - (in) the image data corresponding to the frame. It can either
+// be a raw VP8/VP8L bitstream or a single-image WebP file
+// (non-animated and non-tiled)
+// x_offset - (in) x-offset of the frame to be added
+// y_offset - (in) y-offset of the frame to be added
+// duration - (in) duration of the frame to be added (in milliseconds)
+// copy_data - (in) value 1 indicates given data WILL copied to the mux, and
+// value 0 indicates data will NOT be copied.
+// Returns:
+// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or bitstream is NULL
+// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
+// WEBP_MUX_OK - on success.
+WEBP_EXTERN(WebPMuxError) WebPMuxPushFrame(
+ WebPMux* mux, const WebPData* bitstream,
+ int x_offset, int y_offset, int duration, int copy_data);
+
+// TODO(urvang): Create a struct as follows to reduce argument list size:
+// typedef struct {
+// WebPData bitstream;
+// int x_offset, y_offset;
+// int duration;
+// } FrameInfo;
+
+// Gets the nth animation frame from the mux object.
+// The content of 'bitstream' is allocated using malloc(), and NOT
+// owned by the 'mux' object. It MUST be deallocated by the caller by calling
+// WebPDataClear().
+// nth=0 has a special meaning - last position.
+// Parameters:
+// mux - (in) object from which the info is to be fetched
+// nth - (in) index of the frame in the mux object
+// bitstream - (out) the image data
+// x_offset - (out) x-offset of the returned frame
+// y_offset - (out) y-offset of the returned frame
+// duration - (out) duration of the returned frame (in milliseconds)
+// Returns:
+// WEBP_MUX_INVALID_ARGUMENT - if either mux, bitstream, x_offset,
+// y_offset, or duration is NULL
+// WEBP_MUX_NOT_FOUND - if there are less than nth frames in the mux object.
+// WEBP_MUX_BAD_DATA - if nth frame chunk in mux is invalid.
+// WEBP_MUX_OK - on success.
+WEBP_EXTERN(WebPMuxError) WebPMuxGetFrame(
+ const WebPMux* mux, uint32_t nth, WebPData* bitstream,
+ int* x_offset, int* y_offset, int* duration);
+
+// Deletes an animation frame from the mux object.
+// nth=0 has a special meaning - last position.
+// Parameters:
+// mux - (in/out) object from which a frame is to be deleted
+// nth - (in) The position from which the frame is to be deleted
+// Returns:
+// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL
+// WEBP_MUX_NOT_FOUND - If there are less than nth frames in the mux object
+// before deletion.
+// WEBP_MUX_OK - on success.
+WEBP_EXTERN(WebPMuxError) WebPMuxDeleteFrame(WebPMux* mux, uint32_t nth);
+
+// Sets the animation loop count in the mux object. Any existing loop count
+// value(s) will be removed.
+// Parameters:
+// mux - (in/out) object in which loop chunk is to be set/added
+// loop_count - (in) animation loop count value.
+// Note that loop_count of zero denotes infinite loop.
+// Returns:
+// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL
+// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
+// WEBP_MUX_OK - on success.
+WEBP_EXTERN(WebPMuxError) WebPMuxSetLoopCount(WebPMux* mux, int loop_count);
+
+// Gets the animation loop count from the mux object.
+// Parameters:
+// mux - (in) object from which the loop count is to be fetched
+// loop_count - (out) the loop_count value present in the LOOP chunk
+// Returns:
+// WEBP_MUX_INVALID_ARGUMENT - if either of mux or loop_count is NULL
+// WEBP_MUX_NOT_FOUND - if loop chunk is not present in mux object.
+// WEBP_MUX_OK - on success.
+WEBP_EXTERN(WebPMuxError) WebPMuxGetLoopCount(const WebPMux* mux,
+ int* loop_count);
+
+//------------------------------------------------------------------------------
+// Tiling.
+
+// Adds a tile at the end of the mux object.
+// Note: as WebP only supports even offsets, any odd offset will be snapped to
+// an even location using: offset &= ~1
+// Parameters:
+// mux - (in/out) object to which a tile is to be added.
+// bitstream - (in) the image data corresponding to the frame. It can either
+// be a raw VP8/VP8L bitstream or a single-image WebP file
+// (non-animated and non-tiled)
+// x_offset - (in) x-offset of the tile to be added
+// y_offset - (in) y-offset of the tile to be added
+// copy_data - (in) value 1 indicates given data WILL copied to the mux, and
+// value 0 indicates data will NOT be copied.
+// Returns:
+// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL or bitstream is NULL
+// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
+// WEBP_MUX_OK - on success.
+WEBP_EXTERN(WebPMuxError) WebPMuxPushTile(
+ WebPMux* mux, const WebPData* bitstream,
+ int x_offset, int y_offset, int copy_data);
+
+// Gets the nth tile from the mux object.
+// The content of 'bitstream' is allocated using malloc(), and NOT
+// owned by the 'mux' object. It MUST be deallocated by the caller by calling
+// WebPDataClear().
+// nth=0 has a special meaning - last position.
+// Parameters:
+// mux - (in) object from which the info is to be fetched
+// nth - (in) index of the tile in the mux object
+// bitstream - (out) the image data
+// x_offset - (out) x-offset of the returned tile
+// y_offset - (out) y-offset of the returned tile
+// Returns:
+// WEBP_MUX_INVALID_ARGUMENT - if either mux, bitstream, x_offset or
+// y_offset is NULL
+// WEBP_MUX_NOT_FOUND - if there are less than nth tiles in the mux object.
+// WEBP_MUX_BAD_DATA - if nth tile chunk in mux is invalid.
+// WEBP_MUX_OK - on success.
+WEBP_EXTERN(WebPMuxError) WebPMuxGetTile(
+ const WebPMux* mux, uint32_t nth, WebPData* bitstream,
+ int* x_offset, int* y_offset);
+
+// Deletes a tile from the mux object.
+// nth=0 has a special meaning - last position
+// Parameters:
+// mux - (in/out) object from which a tile is to be deleted
+// nth - (in) The position from which the tile is to be deleted
+// Returns:
+// WEBP_MUX_INVALID_ARGUMENT - if mux is NULL
+// WEBP_MUX_NOT_FOUND - If there are less than nth tiles in the mux object
+// before deletion.
+// WEBP_MUX_OK - on success.
+WEBP_EXTERN(WebPMuxError) WebPMuxDeleteTile(WebPMux* mux, uint32_t nth);
+
+//------------------------------------------------------------------------------
+// Misc Utilities.
+
+// Gets the feature flags from the mux object.
+// Parameters:
+// mux - (in) object from which the features are to be fetched
+// flags - (out) the flags specifying which features are present in the
+// mux object. This will be an OR of various flag values.
+// Enum 'WebPFeatureFlags' can be used to test individual flag values.
+// Returns:
+// WEBP_MUX_INVALID_ARGUMENT - if mux or flags is NULL
+// WEBP_MUX_NOT_FOUND - if VP8X chunk is not present in mux object.
+// WEBP_MUX_BAD_DATA - if VP8X chunk in mux is invalid.
+// WEBP_MUX_OK - on success.
+WEBP_EXTERN(WebPMuxError) WebPMuxGetFeatures(const WebPMux* mux,
+ uint32_t* flags);
+
+// Gets number of chunks having tag value tag in the mux object.
+// Parameters:
+// mux - (in) object from which the info is to be fetched
+// id - (in) chunk id specifying the type of chunk
+// num_elements - (out) number of chunks with the given chunk id
+// Returns:
+// WEBP_MUX_INVALID_ARGUMENT - if either mux, or num_elements is NULL
+// WEBP_MUX_OK - on success.
+WEBP_EXTERN(WebPMuxError) WebPMuxNumChunks(const WebPMux* mux,
+ WebPChunkId id, int* num_elements);
+
+// Assembles all chunks in WebP RIFF format and returns in 'assembled_data'.
+// This function also validates the mux object.
+// Note: The content of 'assembled_data' will be ignored and overwritten.
+// Also, the content of 'assembled_data' is allocated using malloc(), and NOT
+// owned by the 'mux' object. It MUST be deallocated by the caller by calling
+// WebPDataClear().
+// Parameters:
+// mux - (in/out) object whose chunks are to be assembled
+// assembled_data - (out) assembled WebP data
+// Returns:
+// WEBP_MUX_BAD_DATA - if mux object is invalid.
+// WEBP_MUX_INVALID_ARGUMENT - if either mux, output_data or output_size is
+// NULL.
+// WEBP_MUX_MEMORY_ERROR - on memory allocation error.
+// WEBP_MUX_OK - on success
+WEBP_EXTERN(WebPMuxError) WebPMuxAssemble(WebPMux* mux,
+ WebPData* assembled_data);
+
+//------------------------------------------------------------------------------
+// Demux API.
+// Enables extraction of image and extended format data from WebP files.
+
+#define WEBP_DEMUX_ABI_VERSION 0x0100 // MAJOR(8b) + MINOR(8b)
+
+typedef struct WebPDemuxer WebPDemuxer;
+
+typedef enum {
+ WEBP_DEMUX_PARSING_HEADER, // Not enough data to parse full header.
+ WEBP_DEMUX_PARSED_HEADER, // Header parsing complete, data may be available.
+ WEBP_DEMUX_DONE // Entire file has been parsed.
+} WebPDemuxState;
+
+//------------------------------------------------------------------------------
+// Life of a Demux object
+
+// Internal, version-checked, entry point
+WEBP_EXTERN(WebPDemuxer*) WebPDemuxInternal(
+ const WebPData*, int, WebPDemuxState*, int);
+
+// Parses the WebP file given by 'data'.
+// A complete WebP file must be present in 'data' for the function to succeed.
+// Returns a WebPDemuxer object on successful parse, NULL otherwise.
+static WEBP_INLINE WebPDemuxer* WebPDemux(const WebPData* data) {
+ return WebPDemuxInternal(data, 0, NULL, WEBP_DEMUX_ABI_VERSION);
+}
+
+// Parses the WebP file given by 'data'.
+// If 'state' is non-NULL it will be set to indicate the status of the demuxer.
+// Returns a WebPDemuxer object on successful parse, NULL otherwise.
+static WEBP_INLINE WebPDemuxer* WebPDemuxPartial(
+ const WebPData* data, WebPDemuxState* state) {
+ return WebPDemuxInternal(data, 1, state, WEBP_DEMUX_ABI_VERSION);
+}
+
+// Frees memory associated with 'dmux'.
+WEBP_EXTERN(void) WebPDemuxDelete(WebPDemuxer* dmux);
+
+//------------------------------------------------------------------------------
+// Data/information extraction.
+
+typedef enum {
+ WEBP_FF_FORMAT_FLAGS, // Extended format flags present in the 'VP8X' chunk.
+ WEBP_FF_CANVAS_WIDTH,
+ WEBP_FF_CANVAS_HEIGHT,
+ WEBP_FF_LOOP_COUNT
+} WebPFormatFeature;
+
+// Get the 'feature' value from the 'dmux'.
+// NOTE: values are only valid if WebPDemux() was used or WebPDemuxPartial()
+// returned a state > WEBP_DEMUX_PARSING_HEADER.
+WEBP_EXTERN(uint32_t) WebPDemuxGetI(
+ const WebPDemuxer* dmux, WebPFormatFeature feature);
+
+//------------------------------------------------------------------------------
+// Frame iteration.
+
+typedef struct {
+ int frame_num_;
+ int num_frames_;
+ int tile_num_;
+ int num_tiles_;
+ int x_offset_, y_offset_; // offset relative to the canvas.
+ int width_, height_; // dimensions of this frame or tile.
+ int duration_; // display duration in milliseconds.
+ int complete_; // true if 'tile_' contains a full frame. partial images may
+ // still be decoded with the WebP incremental decoder.
+ WebPData tile_; // The frame or tile given by 'frame_num_' and 'tile_num_'.
+
+ uint32_t pad[4]; // padding for later use
+ void* private_;
+} WebPIterator;
+
+// Retrieves frame 'frame_number' from 'dmux'.
+// 'iter->tile_' points to the first tile on return from this function.
+// Individual tiles may be extracted using WebPDemuxSetTile().
+// Setting 'frame_number' equal to 0 will return the last frame of the image.
+// Returns false if 'dmux' is NULL or frame 'frame_number' is not present.
+// Call WebPDemuxReleaseIterator() when use of the iterator is complete.
+// NOTE: 'dmux' must persist for the lifetime of 'iter'.
+WEBP_EXTERN(int) WebPDemuxGetFrame(
+ const WebPDemuxer* dmux, int frame_number, WebPIterator* iter);
+
+// Sets 'iter->tile_' to point to the next ('iter->frame_num_' + 1) or previous
+// ('iter->frame_num_' - 1) frame. These functions do not loop.
+// Returns true on success, false otherwise.
+WEBP_EXTERN(int) WebPDemuxNextFrame(WebPIterator* iter);
+WEBP_EXTERN(int) WebPDemuxPrevFrame(WebPIterator* iter);
+
+// Sets 'iter->tile_' to reflect tile number 'tile_number'.
+// Returns true if tile 'tile_number' is present, false otherwise.
+WEBP_EXTERN(int) WebPDemuxSelectTile(WebPIterator* iter, int tile_number);
+
+// Releases any memory associated with 'iter'.
+// Must be called before destroying the associated WebPDemuxer with
+// WebPDemuxDelete().
+WEBP_EXTERN(void) WebPDemuxReleaseIterator(WebPIterator* iter);
+
+//------------------------------------------------------------------------------
+// Chunk iteration.
+
+typedef struct {
+ // The current and total number of chunks with the fourcc given to
+ // WebPDemuxGetChunk().
+ int chunk_num_;
+ int num_chunks_;
+ WebPData chunk_; // The payload of the chunk.
+
+ uint32_t pad[6]; // padding for later use
+ void* private_;
+} WebPChunkIterator;
+
+// Retrieves the 'chunk_number' instance of the chunk with id 'fourcc' from
+// 'dmux'.
+// 'fourcc' is a character array containing the fourcc of the chunk to return,
+// e.g., "ICCP", "META", "EXIF", etc.
+// Setting 'chunk_number' equal to 0 will return the last chunk in a set.
+// Returns true if the chunk is found, false otherwise. Image related chunk
+// payloads are accessed through WebPDemuxGetFrame() and related functions.
+// Call WebPDemuxReleaseChunkIterator() when use of the iterator is complete.
+// NOTE: 'dmux' must persist for the lifetime of the iterator.
+WEBP_EXTERN(int) WebPDemuxGetChunk(const WebPDemuxer* dmux,
+ const char fourcc[4], int chunk_number,
+ WebPChunkIterator* iter);
+
+// Sets 'iter->chunk_' to point to the next ('iter->chunk_num_' + 1) or previous
+// ('iter->chunk_num_' - 1) chunk. These functions do not loop.
+// Returns true on success, false otherwise.
+WEBP_EXTERN(int) WebPDemuxNextChunk(WebPChunkIterator* iter);
+WEBP_EXTERN(int) WebPDemuxPrevChunk(WebPChunkIterator* iter);
+
+// Releases any memory associated with 'iter'.
+// Must be called before destroying the associated WebPDemuxer with
+// WebPDemuxDelete().
+WEBP_EXTERN(void) WebPDemuxReleaseChunkIterator(WebPChunkIterator* iter);
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif /* WEBP_WEBP_MUX_H_ */
diff --git a/drivers/webp/mux/demux.c b/drivers/webpold/mux/demux.c
index 501d08f41d..501d08f41d 100644
--- a/drivers/webp/mux/demux.c
+++ b/drivers/webpold/mux/demux.c
diff --git a/drivers/webpold/mux/muxedit.c b/drivers/webpold/mux/muxedit.c
new file mode 100644
index 0000000000..08629d4ae2
--- /dev/null
+++ b/drivers/webpold/mux/muxedit.c
@@ -0,0 +1,712 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Set and delete APIs for mux.
+//
+// Authors: Urvang (urvang@google.com)
+// Vikas (vikasa@google.com)
+
+#include <assert.h>
+#include "./muxi.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// Life of a mux object.
+
+static void MuxInit(WebPMux* const mux) {
+ if (mux == NULL) return;
+ memset(mux, 0, sizeof(*mux));
+}
+
+WebPMux* WebPNewInternal(int version) {
+ if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_MUX_ABI_VERSION)) {
+ return NULL;
+ } else {
+ WebPMux* const mux = (WebPMux*)malloc(sizeof(WebPMux));
+ // If mux is NULL MuxInit is a noop.
+ MuxInit(mux);
+ return mux;
+ }
+}
+
+static void DeleteAllChunks(WebPChunk** const chunk_list) {
+ while (*chunk_list) {
+ *chunk_list = ChunkDelete(*chunk_list);
+ }
+}
+
+static void MuxRelease(WebPMux* const mux) {
+ if (mux == NULL) return;
+ MuxImageDeleteAll(&mux->images_);
+ DeleteAllChunks(&mux->vp8x_);
+ DeleteAllChunks(&mux->iccp_);
+ DeleteAllChunks(&mux->loop_);
+ DeleteAllChunks(&mux->meta_);
+ DeleteAllChunks(&mux->unknown_);
+}
+
+void WebPMuxDelete(WebPMux* mux) {
+ // If mux is NULL MuxRelease is a noop.
+ MuxRelease(mux);
+ free(mux);
+}
+
+//------------------------------------------------------------------------------
+// Helper method(s).
+
+// Handy MACRO, makes MuxSet() very symmetric to MuxGet().
+#define SWITCH_ID_LIST(INDEX, LIST) \
+ if (idx == (INDEX)) { \
+ err = ChunkAssignData(&chunk, data, copy_data, kChunks[(INDEX)].tag); \
+ if (err == WEBP_MUX_OK) { \
+ err = ChunkSetNth(&chunk, (LIST), nth); \
+ } \
+ return err; \
+ }
+
+static WebPMuxError MuxSet(WebPMux* const mux, CHUNK_INDEX idx, uint32_t nth,
+ const WebPData* const data, int copy_data) {
+ WebPChunk chunk;
+ WebPMuxError err = WEBP_MUX_NOT_FOUND;
+ assert(mux != NULL);
+ assert(!IsWPI(kChunks[idx].id));
+
+ ChunkInit(&chunk);
+ SWITCH_ID_LIST(IDX_VP8X, &mux->vp8x_);
+ SWITCH_ID_LIST(IDX_ICCP, &mux->iccp_);
+ SWITCH_ID_LIST(IDX_LOOP, &mux->loop_);
+ SWITCH_ID_LIST(IDX_META, &mux->meta_);
+ if (idx == IDX_UNKNOWN && data->size_ > TAG_SIZE) {
+ // For raw-data unknown chunk, the first four bytes should be the tag to be
+ // used for the chunk.
+ const WebPData tmp = { data->bytes_ + TAG_SIZE, data->size_ - TAG_SIZE };
+ err = ChunkAssignData(&chunk, &tmp, copy_data, GetLE32(data->bytes_ + 0));
+ if (err == WEBP_MUX_OK)
+ err = ChunkSetNth(&chunk, &mux->unknown_, nth);
+ }
+ return err;
+}
+#undef SWITCH_ID_LIST
+
+static WebPMuxError MuxAddChunk(WebPMux* const mux, uint32_t nth, uint32_t tag,
+ const uint8_t* data, size_t size,
+ int copy_data) {
+ const CHUNK_INDEX idx = ChunkGetIndexFromTag(tag);
+ const WebPData chunk_data = { data, size };
+ assert(mux != NULL);
+ assert(size <= MAX_CHUNK_PAYLOAD);
+ assert(idx != IDX_NIL);
+ return MuxSet(mux, idx, nth, &chunk_data, copy_data);
+}
+
+// Create data for frame/tile given image data, offsets and duration.
+static WebPMuxError CreateFrameTileData(const WebPData* const image,
+ int x_offset, int y_offset,
+ int duration, int is_lossless,
+ int is_frame,
+ WebPData* const frame_tile) {
+ int width;
+ int height;
+ uint8_t* frame_tile_bytes;
+ const size_t frame_tile_size = kChunks[is_frame ? IDX_FRAME : IDX_TILE].size;
+
+ const int ok = is_lossless ?
+ VP8LGetInfo(image->bytes_, image->size_, &width, &height, NULL) :
+ VP8GetInfo(image->bytes_, image->size_, image->size_, &width, &height);
+ if (!ok) return WEBP_MUX_INVALID_ARGUMENT;
+
+ assert(width > 0 && height > 0 && duration > 0);
+ // Note: assertion on upper bounds is done in PutLE24().
+
+ frame_tile_bytes = (uint8_t*)malloc(frame_tile_size);
+ if (frame_tile_bytes == NULL) return WEBP_MUX_MEMORY_ERROR;
+
+ PutLE24(frame_tile_bytes + 0, x_offset / 2);
+ PutLE24(frame_tile_bytes + 3, y_offset / 2);
+
+ if (is_frame) {
+ PutLE24(frame_tile_bytes + 6, width - 1);
+ PutLE24(frame_tile_bytes + 9, height - 1);
+ PutLE24(frame_tile_bytes + 12, duration - 1);
+ }
+
+ frame_tile->bytes_ = frame_tile_bytes;
+ frame_tile->size_ = frame_tile_size;
+ return WEBP_MUX_OK;
+}
+
+// Outputs image data given a bitstream. The bitstream can either be a
+// single-image WebP file or raw VP8/VP8L data.
+// Also outputs 'is_lossless' to be true if the given bitstream is lossless.
+static WebPMuxError GetImageData(const WebPData* const bitstream,
+ WebPData* const image, WebPData* const alpha,
+ int* const is_lossless) {
+ WebPDataInit(alpha); // Default: no alpha.
+ if (bitstream->size_ < TAG_SIZE ||
+ memcmp(bitstream->bytes_, "RIFF", TAG_SIZE)) {
+ // It is NOT webp file data. Return input data as is.
+ *image = *bitstream;
+ } else {
+ // It is webp file data. Extract image data from it.
+ const WebPMuxImage* wpi;
+ WebPMux* const mux = WebPMuxCreate(bitstream, 0);
+ if (mux == NULL) return WEBP_MUX_BAD_DATA;
+ wpi = mux->images_;
+ assert(wpi != NULL && wpi->img_ != NULL);
+ *image = wpi->img_->data_;
+ if (wpi->alpha_ != NULL) {
+ *alpha = wpi->alpha_->data_;
+ }
+ WebPMuxDelete(mux);
+ }
+ *is_lossless = VP8LCheckSignature(image->bytes_, image->size_);
+ return WEBP_MUX_OK;
+}
+
+static WebPMuxError DeleteChunks(WebPChunk** chunk_list, uint32_t tag) {
+ WebPMuxError err = WEBP_MUX_NOT_FOUND;
+ assert(chunk_list);
+ while (*chunk_list) {
+ WebPChunk* const chunk = *chunk_list;
+ if (chunk->tag_ == tag) {
+ *chunk_list = ChunkDelete(chunk);
+ err = WEBP_MUX_OK;
+ } else {
+ chunk_list = &chunk->next_;
+ }
+ }
+ return err;
+}
+
+static WebPMuxError MuxDeleteAllNamedData(WebPMux* const mux, CHUNK_INDEX idx) {
+ const WebPChunkId id = kChunks[idx].id;
+ WebPChunk** chunk_list;
+
+ if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT;
+ if (IsWPI(id)) return WEBP_MUX_INVALID_ARGUMENT;
+
+ chunk_list = MuxGetChunkListFromId(mux, id);
+ if (chunk_list == NULL) return WEBP_MUX_INVALID_ARGUMENT;
+
+ return DeleteChunks(chunk_list, kChunks[idx].tag);
+}
+
+static WebPMuxError DeleteLoopCount(WebPMux* const mux) {
+ return MuxDeleteAllNamedData(mux, IDX_LOOP);
+}
+
+//------------------------------------------------------------------------------
+// Set API(s).
+
+WebPMuxError WebPMuxSetImage(WebPMux* mux,
+ const WebPData* bitstream, int copy_data) {
+ WebPMuxError err;
+ WebPChunk chunk;
+ WebPMuxImage wpi;
+ WebPData image;
+ WebPData alpha;
+ int is_lossless;
+ int image_tag;
+
+ if (mux == NULL || bitstream == NULL || bitstream->bytes_ == NULL ||
+ bitstream->size_ > MAX_CHUNK_PAYLOAD) {
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+
+ // If given data is for a whole webp file,
+ // extract only the VP8/VP8L data from it.
+ err = GetImageData(bitstream, &image, &alpha, &is_lossless);
+ if (err != WEBP_MUX_OK) return err;
+ image_tag = is_lossless ? kChunks[IDX_VP8L].tag : kChunks[IDX_VP8].tag;
+
+ // Delete the existing images.
+ MuxImageDeleteAll(&mux->images_);
+
+ MuxImageInit(&wpi);
+
+ if (alpha.bytes_ != NULL) { // Add alpha chunk.
+ ChunkInit(&chunk);
+ err = ChunkAssignData(&chunk, &alpha, copy_data, kChunks[IDX_ALPHA].tag);
+ if (err != WEBP_MUX_OK) goto Err;
+ err = ChunkSetNth(&chunk, &wpi.alpha_, 1);
+ if (err != WEBP_MUX_OK) goto Err;
+ }
+
+ // Add image chunk.
+ ChunkInit(&chunk);
+ err = ChunkAssignData(&chunk, &image, copy_data, image_tag);
+ if (err != WEBP_MUX_OK) goto Err;
+ err = ChunkSetNth(&chunk, &wpi.img_, 1);
+ if (err != WEBP_MUX_OK) goto Err;
+
+ // Add this image to mux.
+ err = MuxImagePush(&wpi, &mux->images_);
+ if (err != WEBP_MUX_OK) goto Err;
+
+ // All OK.
+ return WEBP_MUX_OK;
+
+ Err:
+ // Something bad happened.
+ ChunkRelease(&chunk);
+ MuxImageRelease(&wpi);
+ return err;
+}
+
+WebPMuxError WebPMuxSetMetadata(WebPMux* mux, const WebPData* metadata,
+ int copy_data) {
+ WebPMuxError err;
+
+ if (mux == NULL || metadata == NULL || metadata->bytes_ == NULL ||
+ metadata->size_ > MAX_CHUNK_PAYLOAD) {
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+
+ // Delete the existing metadata chunk(s).
+ err = WebPMuxDeleteMetadata(mux);
+ if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err;
+
+ // Add the given metadata chunk.
+ return MuxSet(mux, IDX_META, 1, metadata, copy_data);
+}
+
+WebPMuxError WebPMuxSetColorProfile(WebPMux* mux, const WebPData* color_profile,
+ int copy_data) {
+ WebPMuxError err;
+
+ if (mux == NULL || color_profile == NULL || color_profile->bytes_ == NULL ||
+ color_profile->size_ > MAX_CHUNK_PAYLOAD) {
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+
+ // Delete the existing ICCP chunk(s).
+ err = WebPMuxDeleteColorProfile(mux);
+ if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err;
+
+ // Add the given ICCP chunk.
+ return MuxSet(mux, IDX_ICCP, 1, color_profile, copy_data);
+}
+
+WebPMuxError WebPMuxSetLoopCount(WebPMux* mux, int loop_count) {
+ WebPMuxError err;
+ uint8_t* data = NULL;
+
+ if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT;
+ if (loop_count >= MAX_LOOP_COUNT) return WEBP_MUX_INVALID_ARGUMENT;
+
+ // Delete the existing LOOP chunk(s).
+ err = DeleteLoopCount(mux);
+ if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err;
+
+ // Add the given loop count.
+ data = (uint8_t*)malloc(kChunks[IDX_LOOP].size);
+ if (data == NULL) return WEBP_MUX_MEMORY_ERROR;
+
+ PutLE16(data, loop_count);
+ err = MuxAddChunk(mux, 1, kChunks[IDX_LOOP].tag, data,
+ kChunks[IDX_LOOP].size, 1);
+ free(data);
+ return err;
+}
+
+static WebPMuxError MuxPushFrameTileInternal(
+ WebPMux* const mux, const WebPData* const bitstream, int x_offset,
+ int y_offset, int duration, int copy_data, uint32_t tag) {
+ WebPChunk chunk;
+ WebPData image;
+ WebPData alpha;
+ WebPMuxImage wpi;
+ WebPMuxError err;
+ WebPData frame_tile;
+ const int is_frame = (tag == kChunks[IDX_FRAME].tag) ? 1 : 0;
+ int is_lossless;
+ int image_tag;
+
+ // Sanity checks.
+ if (mux == NULL || bitstream == NULL || bitstream->bytes_ == NULL ||
+ bitstream->size_ > MAX_CHUNK_PAYLOAD) {
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+ if (x_offset < 0 || x_offset >= MAX_POSITION_OFFSET ||
+ y_offset < 0 || y_offset >= MAX_POSITION_OFFSET ||
+ duration <= 0 || duration > MAX_DURATION) {
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+
+ // Snap offsets to even positions.
+ x_offset &= ~1;
+ y_offset &= ~1;
+
+ // If given data is for a whole webp file,
+ // extract only the VP8/VP8L data from it.
+ err = GetImageData(bitstream, &image, &alpha, &is_lossless);
+ if (err != WEBP_MUX_OK) return err;
+ image_tag = is_lossless ? kChunks[IDX_VP8L].tag : kChunks[IDX_VP8].tag;
+
+ WebPDataInit(&frame_tile);
+ ChunkInit(&chunk);
+ MuxImageInit(&wpi);
+
+ if (alpha.bytes_ != NULL) {
+ // Add alpha chunk.
+ err = ChunkAssignData(&chunk, &alpha, copy_data, kChunks[IDX_ALPHA].tag);
+ if (err != WEBP_MUX_OK) goto Err;
+ err = ChunkSetNth(&chunk, &wpi.alpha_, 1);
+ if (err != WEBP_MUX_OK) goto Err;
+ ChunkInit(&chunk); // chunk owned by wpi.alpha_ now.
+ }
+
+ // Add image chunk.
+ err = ChunkAssignData(&chunk, &image, copy_data, image_tag);
+ if (err != WEBP_MUX_OK) goto Err;
+ err = ChunkSetNth(&chunk, &wpi.img_, 1);
+ if (err != WEBP_MUX_OK) goto Err;
+ ChunkInit(&chunk); // chunk owned by wpi.img_ now.
+
+ // Create frame/tile data.
+ err = CreateFrameTileData(&image, x_offset, y_offset, duration, is_lossless,
+ is_frame, &frame_tile);
+ if (err != WEBP_MUX_OK) goto Err;
+
+ // Add frame/tile chunk (with copy_data = 1).
+ err = ChunkAssignData(&chunk, &frame_tile, 1, tag);
+ if (err != WEBP_MUX_OK) goto Err;
+ WebPDataClear(&frame_tile);
+ err = ChunkSetNth(&chunk, &wpi.header_, 1);
+ if (err != WEBP_MUX_OK) goto Err;
+ ChunkInit(&chunk); // chunk owned by wpi.header_ now.
+
+ // Add this WebPMuxImage to mux.
+ err = MuxImagePush(&wpi, &mux->images_);
+ if (err != WEBP_MUX_OK) goto Err;
+
+ // All is well.
+ return WEBP_MUX_OK;
+
+ Err: // Something bad happened.
+ WebPDataClear(&frame_tile);
+ ChunkRelease(&chunk);
+ MuxImageRelease(&wpi);
+ return err;
+}
+
+WebPMuxError WebPMuxPushFrame(WebPMux* mux, const WebPData* bitstream,
+ int x_offset, int y_offset,
+ int duration, int copy_data) {
+ return MuxPushFrameTileInternal(mux, bitstream, x_offset, y_offset,
+ duration, copy_data, kChunks[IDX_FRAME].tag);
+}
+
+WebPMuxError WebPMuxPushTile(WebPMux* mux, const WebPData* bitstream,
+ int x_offset, int y_offset,
+ int copy_data) {
+ return MuxPushFrameTileInternal(mux, bitstream, x_offset, y_offset,
+ 1 /* unused duration */, copy_data,
+ kChunks[IDX_TILE].tag);
+}
+
+//------------------------------------------------------------------------------
+// Delete API(s).
+
+WebPMuxError WebPMuxDeleteImage(WebPMux* mux) {
+ WebPMuxError err;
+
+ if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT;
+
+ err = MuxValidateForImage(mux);
+ if (err != WEBP_MUX_OK) return err;
+
+ // All well, delete image.
+ MuxImageDeleteAll(&mux->images_);
+ return WEBP_MUX_OK;
+}
+
+WebPMuxError WebPMuxDeleteMetadata(WebPMux* mux) {
+ return MuxDeleteAllNamedData(mux, IDX_META);
+}
+
+WebPMuxError WebPMuxDeleteColorProfile(WebPMux* mux) {
+ return MuxDeleteAllNamedData(mux, IDX_ICCP);
+}
+
+static WebPMuxError DeleteFrameTileInternal(WebPMux* const mux, uint32_t nth,
+ CHUNK_INDEX idx) {
+ const WebPChunkId id = kChunks[idx].id;
+ if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT;
+
+ assert(idx == IDX_FRAME || idx == IDX_TILE);
+ return MuxImageDeleteNth(&mux->images_, nth, id);
+}
+
+WebPMuxError WebPMuxDeleteFrame(WebPMux* mux, uint32_t nth) {
+ return DeleteFrameTileInternal(mux, nth, IDX_FRAME);
+}
+
+WebPMuxError WebPMuxDeleteTile(WebPMux* mux, uint32_t nth) {
+ return DeleteFrameTileInternal(mux, nth, IDX_TILE);
+}
+
+//------------------------------------------------------------------------------
+// Assembly of the WebP RIFF file.
+
+static WebPMuxError GetFrameTileInfo(const WebPChunk* const frame_tile_chunk,
+ int* const x_offset, int* const y_offset,
+ int* const duration) {
+ const uint32_t tag = frame_tile_chunk->tag_;
+ const int is_frame = (tag == kChunks[IDX_FRAME].tag);
+ const WebPData* const data = &frame_tile_chunk->data_;
+ const size_t expected_data_size =
+ is_frame ? FRAME_CHUNK_SIZE : TILE_CHUNK_SIZE;
+ assert(frame_tile_chunk != NULL);
+ assert(tag == kChunks[IDX_FRAME].tag || tag == kChunks[IDX_TILE].tag);
+ if (data->size_ != expected_data_size) return WEBP_MUX_INVALID_ARGUMENT;
+
+ *x_offset = 2 * GetLE24(data->bytes_ + 0);
+ *y_offset = 2 * GetLE24(data->bytes_ + 3);
+ if (is_frame) *duration = 1 + GetLE24(data->bytes_ + 12);
+ return WEBP_MUX_OK;
+}
+
+WebPMuxError MuxGetImageWidthHeight(const WebPChunk* const image_chunk,
+ int* const width, int* const height) {
+ const uint32_t tag = image_chunk->tag_;
+ const WebPData* const data = &image_chunk->data_;
+ int w, h;
+ int ok;
+ assert(image_chunk != NULL);
+ assert(tag == kChunks[IDX_VP8].tag || tag == kChunks[IDX_VP8L].tag);
+ ok = (tag == kChunks[IDX_VP8].tag) ?
+ VP8GetInfo(data->bytes_, data->size_, data->size_, &w, &h) :
+ VP8LGetInfo(data->bytes_, data->size_, &w, &h, NULL);
+ if (ok) {
+ *width = w;
+ *height = h;
+ return WEBP_MUX_OK;
+ } else {
+ return WEBP_MUX_BAD_DATA;
+ }
+}
+
+static WebPMuxError GetImageInfo(const WebPMuxImage* const wpi,
+ int* const x_offset, int* const y_offset,
+ int* const duration,
+ int* const width, int* const height) {
+ const WebPChunk* const image_chunk = wpi->img_;
+ const WebPChunk* const frame_tile_chunk = wpi->header_;
+
+ // Get offsets and duration from FRM/TILE chunk.
+ const WebPMuxError err =
+ GetFrameTileInfo(frame_tile_chunk, x_offset, y_offset, duration);
+ if (err != WEBP_MUX_OK) return err;
+
+ // Get width and height from VP8/VP8L chunk.
+ return MuxGetImageWidthHeight(image_chunk, width, height);
+}
+
+static WebPMuxError GetImageCanvasWidthHeight(
+ const WebPMux* const mux, uint32_t flags,
+ int* const width, int* const height) {
+ WebPMuxImage* wpi = NULL;
+ assert(mux != NULL);
+ assert(width != NULL && height != NULL);
+
+ wpi = mux->images_;
+ assert(wpi != NULL);
+ assert(wpi->img_ != NULL);
+
+ if (wpi->next_) {
+ int max_x = 0;
+ int max_y = 0;
+ int64_t image_area = 0;
+ // Aggregate the bounding box for animation frames & tiled images.
+ for (; wpi != NULL; wpi = wpi->next_) {
+ int x_offset, y_offset, duration, w, h;
+ const WebPMuxError err = GetImageInfo(wpi, &x_offset, &y_offset,
+ &duration, &w, &h);
+ const int max_x_pos = x_offset + w;
+ const int max_y_pos = y_offset + h;
+ if (err != WEBP_MUX_OK) return err;
+ assert(x_offset < MAX_POSITION_OFFSET);
+ assert(y_offset < MAX_POSITION_OFFSET);
+
+ if (max_x_pos > max_x) max_x = max_x_pos;
+ if (max_y_pos > max_y) max_y = max_y_pos;
+ image_area += w * h;
+ }
+ *width = max_x;
+ *height = max_y;
+ // Crude check to validate that there are no image overlaps/holes for tile
+ // images. Check that the aggregated image area for individual tiles exactly
+ // matches the image area of the constructed canvas. However, the area-match
+ // is necessary but not sufficient condition.
+ if ((flags & TILE_FLAG) && (image_area != (max_x * max_y))) {
+ *width = 0;
+ *height = 0;
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+ } else {
+ // For a single image, extract the width & height from VP8/VP8L image-data.
+ int w, h;
+ const WebPChunk* const image_chunk = wpi->img_;
+ const WebPMuxError err = MuxGetImageWidthHeight(image_chunk, &w, &h);
+ if (err != WEBP_MUX_OK) return err;
+ *width = w;
+ *height = h;
+ }
+ return WEBP_MUX_OK;
+}
+
+// VP8X format:
+// Total Size : 10,
+// Flags : 4 bytes,
+// Width : 3 bytes,
+// Height : 3 bytes.
+static WebPMuxError CreateVP8XChunk(WebPMux* const mux) {
+ WebPMuxError err = WEBP_MUX_OK;
+ uint32_t flags = 0;
+ int width = 0;
+ int height = 0;
+ uint8_t data[VP8X_CHUNK_SIZE];
+ const size_t data_size = VP8X_CHUNK_SIZE;
+ const WebPMuxImage* images = NULL;
+
+ assert(mux != NULL);
+ images = mux->images_; // First image.
+ if (images == NULL || images->img_ == NULL ||
+ images->img_->data_.bytes_ == NULL) {
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+
+ // If VP8X chunk(s) is(are) already present, remove them (and later add new
+ // VP8X chunk with updated flags).
+ err = MuxDeleteAllNamedData(mux, IDX_VP8X);
+ if (err != WEBP_MUX_OK && err != WEBP_MUX_NOT_FOUND) return err;
+
+ // Set flags.
+ if (mux->iccp_ != NULL && mux->iccp_->data_.bytes_ != NULL) {
+ flags |= ICCP_FLAG;
+ }
+
+ if (mux->meta_ != NULL && mux->meta_->data_.bytes_ != NULL) {
+ flags |= META_FLAG;
+ }
+
+ if (images->header_ != NULL) {
+ if (images->header_->tag_ == kChunks[IDX_TILE].tag) {
+ // This is a tiled image.
+ flags |= TILE_FLAG;
+ } else if (images->header_->tag_ == kChunks[IDX_FRAME].tag) {
+ // This is an image with animation.
+ flags |= ANIMATION_FLAG;
+ }
+ }
+
+ if (MuxImageCount(images, WEBP_CHUNK_ALPHA) > 0) {
+ flags |= ALPHA_FLAG; // Some images have an alpha channel.
+ }
+
+ if (flags == 0) {
+ // For Simple Image, VP8X chunk should not be added.
+ return WEBP_MUX_OK;
+ }
+
+ err = GetImageCanvasWidthHeight(mux, flags, &width, &height);
+ if (err != WEBP_MUX_OK) return err;
+
+ if (width <= 0 || height <= 0) {
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+ if (width > MAX_CANVAS_SIZE || height > MAX_CANVAS_SIZE) {
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+
+ if (MuxHasLosslessImages(images)) {
+ // We have a file with a VP8X chunk having some lossless images.
+ // As lossless images implicitly contain alpha, force ALPHA_FLAG to be true.
+ // Note: This 'flags' update must NOT be done for a lossless image
+ // without a VP8X chunk!
+ flags |= ALPHA_FLAG;
+ }
+
+ PutLE32(data + 0, flags); // VP8X chunk flags.
+ PutLE24(data + 4, width - 1); // canvas width.
+ PutLE24(data + 7, height - 1); // canvas height.
+
+ err = MuxAddChunk(mux, 1, kChunks[IDX_VP8X].tag, data, data_size, 1);
+ return err;
+}
+
+WebPMuxError WebPMuxAssemble(WebPMux* mux, WebPData* assembled_data) {
+ size_t size = 0;
+ uint8_t* data = NULL;
+ uint8_t* dst = NULL;
+ int num_frames;
+ int num_loop_chunks;
+ WebPMuxError err;
+
+ if (mux == NULL || assembled_data == NULL) {
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+
+ // Remove LOOP chunk if unnecessary.
+ err = WebPMuxNumChunks(mux, kChunks[IDX_LOOP].id, &num_loop_chunks);
+ if (err != WEBP_MUX_OK) return err;
+ if (num_loop_chunks >= 1) {
+ err = WebPMuxNumChunks(mux, kChunks[IDX_FRAME].id, &num_frames);
+ if (err != WEBP_MUX_OK) return err;
+ if (num_frames == 0) {
+ err = DeleteLoopCount(mux);
+ if (err != WEBP_MUX_OK) return err;
+ }
+ }
+
+ // Create VP8X chunk.
+ err = CreateVP8XChunk(mux);
+ if (err != WEBP_MUX_OK) return err;
+
+ // Allocate data.
+ size = ChunksListDiskSize(mux->vp8x_) + ChunksListDiskSize(mux->iccp_)
+ + ChunksListDiskSize(mux->loop_) + MuxImageListDiskSize(mux->images_)
+ + ChunksListDiskSize(mux->meta_) + ChunksListDiskSize(mux->unknown_)
+ + RIFF_HEADER_SIZE;
+
+ data = (uint8_t*)malloc(size);
+ if (data == NULL) return WEBP_MUX_MEMORY_ERROR;
+
+ // Emit header & chunks.
+ dst = MuxEmitRiffHeader(data, size);
+ dst = ChunkListEmit(mux->vp8x_, dst);
+ dst = ChunkListEmit(mux->iccp_, dst);
+ dst = ChunkListEmit(mux->loop_, dst);
+ dst = MuxImageListEmit(mux->images_, dst);
+ dst = ChunkListEmit(mux->meta_, dst);
+ dst = ChunkListEmit(mux->unknown_, dst);
+ assert(dst == data + size);
+
+ // Validate mux.
+ err = MuxValidate(mux);
+ if (err != WEBP_MUX_OK) {
+ free(data);
+ data = NULL;
+ size = 0;
+ }
+
+ // Finalize.
+ assembled_data->bytes_ = data;
+ assembled_data->size_ = size;
+
+ return err;
+}
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/mux/muxi.h b/drivers/webpold/mux/muxi.h
new file mode 100644
index 0000000000..2f06f3ed03
--- /dev/null
+++ b/drivers/webpold/mux/muxi.h
@@ -0,0 +1,271 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Internal header for mux library.
+//
+// Author: Urvang (urvang@google.com)
+
+#ifndef WEBP_MUX_MUXI_H_
+#define WEBP_MUX_MUXI_H_
+
+#include <stdlib.h>
+#include "../dec/vp8i.h"
+#include "../dec/vp8li.h"
+#include "../format_constants.h"
+#include "../mux.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// Defines and constants.
+
+// Chunk object.
+typedef struct WebPChunk WebPChunk;
+struct WebPChunk {
+ uint32_t tag_;
+ int owner_; // True if *data_ memory is owned internally.
+ // VP8X, Loop, and other internally created chunks
+ // like frame/tile are always owned.
+ WebPData data_;
+ WebPChunk* next_;
+};
+
+// MuxImage object. Store a full webp image (including frame/tile chunk, alpha
+// chunk and VP8/VP8L chunk),
+typedef struct WebPMuxImage WebPMuxImage;
+struct WebPMuxImage {
+ WebPChunk* header_; // Corresponds to WEBP_CHUNK_FRAME/WEBP_CHUNK_TILE.
+ WebPChunk* alpha_; // Corresponds to WEBP_CHUNK_ALPHA.
+ WebPChunk* img_; // Corresponds to WEBP_CHUNK_IMAGE.
+ int is_partial_; // True if only some of the chunks are filled.
+ WebPMuxImage* next_;
+};
+
+// Main mux object. Stores data chunks.
+struct WebPMux {
+ WebPMuxImage* images_;
+ WebPChunk* iccp_;
+ WebPChunk* meta_;
+ WebPChunk* loop_;
+ WebPChunk* vp8x_;
+
+ WebPChunk* unknown_;
+};
+
+// CHUNK_INDEX enum: used for indexing within 'kChunks' (defined below) only.
+// Note: the reason for having two enums ('WebPChunkId' and 'CHUNK_INDEX') is to
+// allow two different chunks to have the same id (e.g. WebPChunkId
+// 'WEBP_CHUNK_IMAGE' can correspond to CHUNK_INDEX 'IDX_VP8' or 'IDX_VP8L').
+typedef enum {
+ IDX_VP8X = 0,
+ IDX_ICCP,
+ IDX_LOOP,
+ IDX_FRAME,
+ IDX_TILE,
+ IDX_ALPHA,
+ IDX_VP8,
+ IDX_VP8L,
+ IDX_META,
+ IDX_UNKNOWN,
+
+ IDX_NIL,
+ IDX_LAST_CHUNK
+} CHUNK_INDEX;
+
+#define NIL_TAG 0x00000000u // To signal void chunk.
+
+#define MKFOURCC(a, b, c, d) ((uint32_t)(a) | (b) << 8 | (c) << 16 | (d) << 24)
+
+typedef struct {
+ uint32_t tag;
+ WebPChunkId id;
+ uint32_t size;
+} ChunkInfo;
+
+extern const ChunkInfo kChunks[IDX_LAST_CHUNK];
+
+//------------------------------------------------------------------------------
+// Helper functions.
+
+// Read 16, 24 or 32 bits stored in little-endian order.
+static WEBP_INLINE int GetLE16(const uint8_t* const data) {
+ return (int)(data[0] << 0) | (data[1] << 8);
+}
+
+static WEBP_INLINE int GetLE24(const uint8_t* const data) {
+ return GetLE16(data) | (data[2] << 16);
+}
+
+static WEBP_INLINE uint32_t GetLE32(const uint8_t* const data) {
+ return (uint32_t)GetLE16(data) | (GetLE16(data + 2) << 16);
+}
+
+// Store 16, 24 or 32 bits in little-endian order.
+static WEBP_INLINE void PutLE16(uint8_t* const data, int val) {
+ assert(val < (1 << 16));
+ data[0] = (val >> 0);
+ data[1] = (val >> 8);
+}
+
+static WEBP_INLINE void PutLE24(uint8_t* const data, int val) {
+ assert(val < (1 << 24));
+ PutLE16(data, val & 0xffff);
+ data[2] = (val >> 16);
+}
+
+static WEBP_INLINE void PutLE32(uint8_t* const data, uint32_t val) {
+ PutLE16(data, (int)(val & 0xffff));
+ PutLE16(data + 2, (int)(val >> 16));
+}
+
+static WEBP_INLINE size_t SizeWithPadding(size_t chunk_size) {
+ return CHUNK_HEADER_SIZE + ((chunk_size + 1) & ~1U);
+}
+
+//------------------------------------------------------------------------------
+// Chunk object management.
+
+// Initialize.
+void ChunkInit(WebPChunk* const chunk);
+
+// Get chunk index from chunk tag. Returns IDX_NIL if not found.
+CHUNK_INDEX ChunkGetIndexFromTag(uint32_t tag);
+
+// Get chunk id from chunk tag. Returns WEBP_CHUNK_NIL if not found.
+WebPChunkId ChunkGetIdFromTag(uint32_t tag);
+
+// Search for nth chunk with given 'tag' in the chunk list.
+// nth = 0 means "last of the list".
+WebPChunk* ChunkSearchList(WebPChunk* first, uint32_t nth, uint32_t tag);
+
+// Fill the chunk with the given data.
+WebPMuxError ChunkAssignData(WebPChunk* chunk, const WebPData* const data,
+ int copy_data, uint32_t tag);
+
+// Sets 'chunk' at nth position in the 'chunk_list'.
+// nth = 0 has the special meaning "last of the list".
+WebPMuxError ChunkSetNth(const WebPChunk* chunk, WebPChunk** chunk_list,
+ uint32_t nth);
+
+// Releases chunk and returns chunk->next_.
+WebPChunk* ChunkRelease(WebPChunk* const chunk);
+
+// Deletes given chunk & returns chunk->next_.
+WebPChunk* ChunkDelete(WebPChunk* const chunk);
+
+// Size of a chunk including header and padding.
+static WEBP_INLINE size_t ChunkDiskSize(const WebPChunk* chunk) {
+ const size_t data_size = chunk->data_.size_;
+ assert(data_size < MAX_CHUNK_PAYLOAD);
+ return SizeWithPadding(data_size);
+}
+
+// Total size of a list of chunks.
+size_t ChunksListDiskSize(const WebPChunk* chunk_list);
+
+// Write out the given list of chunks into 'dst'.
+uint8_t* ChunkListEmit(const WebPChunk* chunk_list, uint8_t* dst);
+
+// Get the width & height of image stored in 'image_chunk'.
+WebPMuxError MuxGetImageWidthHeight(const WebPChunk* const image_chunk,
+ int* const width, int* const height);
+
+//------------------------------------------------------------------------------
+// MuxImage object management.
+
+// Initialize.
+void MuxImageInit(WebPMuxImage* const wpi);
+
+// Releases image 'wpi' and returns wpi->next.
+WebPMuxImage* MuxImageRelease(WebPMuxImage* const wpi);
+
+// Delete image 'wpi' and return the next image in the list or NULL.
+// 'wpi' can be NULL.
+WebPMuxImage* MuxImageDelete(WebPMuxImage* const wpi);
+
+// Delete all images in 'wpi_list'.
+void MuxImageDeleteAll(WebPMuxImage** const wpi_list);
+
+// Count number of images matching the given tag id in the 'wpi_list'.
+int MuxImageCount(const WebPMuxImage* wpi_list, WebPChunkId id);
+
+// Check if given ID corresponds to an image related chunk.
+static WEBP_INLINE int IsWPI(WebPChunkId id) {
+ switch (id) {
+ case WEBP_CHUNK_FRAME:
+ case WEBP_CHUNK_TILE:
+ case WEBP_CHUNK_ALPHA:
+ case WEBP_CHUNK_IMAGE: return 1;
+ default: return 0;
+ }
+}
+
+// Get a reference to appropriate chunk list within an image given chunk tag.
+static WEBP_INLINE WebPChunk** MuxImageGetListFromId(
+ const WebPMuxImage* const wpi, WebPChunkId id) {
+ assert(wpi != NULL);
+ switch (id) {
+ case WEBP_CHUNK_FRAME:
+ case WEBP_CHUNK_TILE: return (WebPChunk**)&wpi->header_;
+ case WEBP_CHUNK_ALPHA: return (WebPChunk**)&wpi->alpha_;
+ case WEBP_CHUNK_IMAGE: return (WebPChunk**)&wpi->img_;
+ default: return NULL;
+ }
+}
+
+// Pushes 'wpi' at the end of 'wpi_list'.
+WebPMuxError MuxImagePush(const WebPMuxImage* wpi, WebPMuxImage** wpi_list);
+
+// Delete nth image in the image list with given tag id.
+WebPMuxError MuxImageDeleteNth(WebPMuxImage** wpi_list, uint32_t nth,
+ WebPChunkId id);
+
+// Get nth image in the image list with given tag id.
+WebPMuxError MuxImageGetNth(const WebPMuxImage** wpi_list, uint32_t nth,
+ WebPChunkId id, WebPMuxImage** wpi);
+
+// Total size of the given image.
+size_t MuxImageDiskSize(const WebPMuxImage* const wpi);
+
+// Total size of a list of images.
+size_t MuxImageListDiskSize(const WebPMuxImage* wpi_list);
+
+// Write out the given image into 'dst'.
+uint8_t* MuxImageEmit(const WebPMuxImage* const wpi, uint8_t* dst);
+
+// Write out the given list of images into 'dst'.
+uint8_t* MuxImageListEmit(const WebPMuxImage* wpi_list, uint8_t* dst);
+
+//------------------------------------------------------------------------------
+// Helper methods for mux.
+
+// Checks if the given image list contains at least one lossless image.
+int MuxHasLosslessImages(const WebPMuxImage* images);
+
+// Write out RIFF header into 'data', given total data size 'size'.
+uint8_t* MuxEmitRiffHeader(uint8_t* const data, size_t size);
+
+// Returns the list where chunk with given ID is to be inserted in mux.
+// Return value is NULL if this chunk should be inserted in mux->images_ list
+// or if 'id' is not known.
+WebPChunk** MuxGetChunkListFromId(const WebPMux* mux, WebPChunkId id);
+
+// Validates that the given mux has a single image.
+WebPMuxError MuxValidateForImage(const WebPMux* const mux);
+
+// Validates the given mux object.
+WebPMuxError MuxValidate(const WebPMux* const mux);
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif /* WEBP_MUX_MUXI_H_ */
diff --git a/drivers/webpold/mux/muxinternal.c b/drivers/webpold/mux/muxinternal.c
new file mode 100644
index 0000000000..6c3c4fe60a
--- /dev/null
+++ b/drivers/webpold/mux/muxinternal.c
@@ -0,0 +1,576 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Internal objects and utils for mux.
+//
+// Authors: Urvang (urvang@google.com)
+// Vikas (vikasa@google.com)
+
+#include <assert.h>
+#include "./muxi.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define UNDEFINED_CHUNK_SIZE (-1)
+
+const ChunkInfo kChunks[] = {
+ { MKFOURCC('V', 'P', '8', 'X'), WEBP_CHUNK_VP8X, VP8X_CHUNK_SIZE },
+ { MKFOURCC('I', 'C', 'C', 'P'), WEBP_CHUNK_ICCP, UNDEFINED_CHUNK_SIZE },
+ { MKFOURCC('L', 'O', 'O', 'P'), WEBP_CHUNK_LOOP, LOOP_CHUNK_SIZE },
+ { MKFOURCC('F', 'R', 'M', ' '), WEBP_CHUNK_FRAME, FRAME_CHUNK_SIZE },
+ { MKFOURCC('T', 'I', 'L', 'E'), WEBP_CHUNK_TILE, TILE_CHUNK_SIZE },
+ { MKFOURCC('A', 'L', 'P', 'H'), WEBP_CHUNK_ALPHA, UNDEFINED_CHUNK_SIZE },
+ { MKFOURCC('V', 'P', '8', ' '), WEBP_CHUNK_IMAGE, UNDEFINED_CHUNK_SIZE },
+ { MKFOURCC('V', 'P', '8', 'L'), WEBP_CHUNK_IMAGE, UNDEFINED_CHUNK_SIZE },
+ { MKFOURCC('M', 'E', 'T', 'A'), WEBP_CHUNK_META, UNDEFINED_CHUNK_SIZE },
+ { MKFOURCC('U', 'N', 'K', 'N'), WEBP_CHUNK_UNKNOWN, UNDEFINED_CHUNK_SIZE },
+
+ { NIL_TAG, WEBP_CHUNK_NIL, UNDEFINED_CHUNK_SIZE }
+};
+
+//------------------------------------------------------------------------------
+// Life of a chunk object.
+
+void ChunkInit(WebPChunk* const chunk) {
+ assert(chunk);
+ memset(chunk, 0, sizeof(*chunk));
+ chunk->tag_ = NIL_TAG;
+}
+
+WebPChunk* ChunkRelease(WebPChunk* const chunk) {
+ WebPChunk* next;
+ if (chunk == NULL) return NULL;
+ if (chunk->owner_) {
+ WebPDataClear(&chunk->data_);
+ }
+ next = chunk->next_;
+ ChunkInit(chunk);
+ return next;
+}
+
+//------------------------------------------------------------------------------
+// Chunk misc methods.
+
+CHUNK_INDEX ChunkGetIndexFromTag(uint32_t tag) {
+ int i;
+ for (i = 0; kChunks[i].tag != NIL_TAG; ++i) {
+ if (tag == kChunks[i].tag) return i;
+ }
+ return IDX_NIL;
+}
+
+WebPChunkId ChunkGetIdFromTag(uint32_t tag) {
+ int i;
+ for (i = 0; kChunks[i].tag != NIL_TAG; ++i) {
+ if (tag == kChunks[i].tag) return kChunks[i].id;
+ }
+ return WEBP_CHUNK_NIL;
+}
+
+//------------------------------------------------------------------------------
+// Chunk search methods.
+
+// Returns next chunk in the chunk list with the given tag.
+static WebPChunk* ChunkSearchNextInList(WebPChunk* chunk, uint32_t tag) {
+ while (chunk && chunk->tag_ != tag) {
+ chunk = chunk->next_;
+ }
+ return chunk;
+}
+
+WebPChunk* ChunkSearchList(WebPChunk* first, uint32_t nth, uint32_t tag) {
+ uint32_t iter = nth;
+ first = ChunkSearchNextInList(first, tag);
+ if (!first) return NULL;
+
+ while (--iter != 0) {
+ WebPChunk* next_chunk = ChunkSearchNextInList(first->next_, tag);
+ if (next_chunk == NULL) break;
+ first = next_chunk;
+ }
+ return ((nth > 0) && (iter > 0)) ? NULL : first;
+}
+
+// Outputs a pointer to 'prev_chunk->next_',
+// where 'prev_chunk' is the pointer to the chunk at position (nth - 1).
+// Returns 1 if nth chunk was found, 0 otherwise.
+static int ChunkSearchListToSet(WebPChunk** chunk_list, uint32_t nth,
+ WebPChunk*** const location) {
+ uint32_t count = 0;
+ assert(chunk_list);
+ *location = chunk_list;
+
+ while (*chunk_list) {
+ WebPChunk* const cur_chunk = *chunk_list;
+ ++count;
+ if (count == nth) return 1; // Found.
+ chunk_list = &cur_chunk->next_;
+ *location = chunk_list;
+ }
+
+ // *chunk_list is ok to be NULL if adding at last location.
+ return (nth == 0 || (count == nth - 1)) ? 1 : 0;
+}
+
+//------------------------------------------------------------------------------
+// Chunk writer methods.
+
+WebPMuxError ChunkAssignData(WebPChunk* chunk, const WebPData* const data,
+ int copy_data, uint32_t tag) {
+ // For internally allocated chunks, always copy data & make it owner of data.
+ if (tag == kChunks[IDX_VP8X].tag || tag == kChunks[IDX_LOOP].tag) {
+ copy_data = 1;
+ }
+
+ ChunkRelease(chunk);
+
+ if (data != NULL) {
+ if (copy_data) {
+ // Copy data.
+ chunk->data_.bytes_ = (uint8_t*)malloc(data->size_);
+ if (chunk->data_.bytes_ == NULL) return WEBP_MUX_MEMORY_ERROR;
+ memcpy((uint8_t*)chunk->data_.bytes_, data->bytes_, data->size_);
+ chunk->data_.size_ = data->size_;
+
+ // Chunk is owner of data.
+ chunk->owner_ = 1;
+ } else {
+ // Don't copy data.
+ chunk->data_ = *data;
+ }
+ }
+
+ chunk->tag_ = tag;
+
+ return WEBP_MUX_OK;
+}
+
+WebPMuxError ChunkSetNth(const WebPChunk* chunk, WebPChunk** chunk_list,
+ uint32_t nth) {
+ WebPChunk* new_chunk;
+
+ if (!ChunkSearchListToSet(chunk_list, nth, &chunk_list)) {
+ return WEBP_MUX_NOT_FOUND;
+ }
+
+ new_chunk = (WebPChunk*)malloc(sizeof(*new_chunk));
+ if (new_chunk == NULL) return WEBP_MUX_MEMORY_ERROR;
+ *new_chunk = *chunk;
+ new_chunk->next_ = *chunk_list;
+ *chunk_list = new_chunk;
+ return WEBP_MUX_OK;
+}
+
+//------------------------------------------------------------------------------
+// Chunk deletion method(s).
+
+WebPChunk* ChunkDelete(WebPChunk* const chunk) {
+ WebPChunk* const next = ChunkRelease(chunk);
+ free(chunk);
+ return next;
+}
+
+//------------------------------------------------------------------------------
+// Chunk serialization methods.
+
+size_t ChunksListDiskSize(const WebPChunk* chunk_list) {
+ size_t size = 0;
+ while (chunk_list) {
+ size += ChunkDiskSize(chunk_list);
+ chunk_list = chunk_list->next_;
+ }
+ return size;
+}
+
+static uint8_t* ChunkEmit(const WebPChunk* const chunk, uint8_t* dst) {
+ const size_t chunk_size = chunk->data_.size_;
+ assert(chunk);
+ assert(chunk->tag_ != NIL_TAG);
+ PutLE32(dst + 0, chunk->tag_);
+ PutLE32(dst + TAG_SIZE, (uint32_t)chunk_size);
+ assert(chunk_size == (uint32_t)chunk_size);
+ memcpy(dst + CHUNK_HEADER_SIZE, chunk->data_.bytes_, chunk_size);
+ if (chunk_size & 1)
+ dst[CHUNK_HEADER_SIZE + chunk_size] = 0; // Add padding.
+ return dst + ChunkDiskSize(chunk);
+}
+
+uint8_t* ChunkListEmit(const WebPChunk* chunk_list, uint8_t* dst) {
+ while (chunk_list) {
+ dst = ChunkEmit(chunk_list, dst);
+ chunk_list = chunk_list->next_;
+ }
+ return dst;
+}
+
+//------------------------------------------------------------------------------
+// Manipulation of a WebPData object.
+
+void WebPDataInit(WebPData* webp_data) {
+ if (webp_data != NULL) {
+ memset(webp_data, 0, sizeof(*webp_data));
+ }
+}
+
+void WebPDataClear(WebPData* webp_data) {
+ if (webp_data != NULL) {
+ free((void*)webp_data->bytes_);
+ WebPDataInit(webp_data);
+ }
+}
+
+int WebPDataCopy(const WebPData* src, WebPData* dst) {
+ if (src == NULL || dst == NULL) return 0;
+
+ WebPDataInit(dst);
+ if (src->bytes_ != NULL && src->size_ != 0) {
+ dst->bytes_ = (uint8_t*)malloc(src->size_);
+ if (dst->bytes_ == NULL) return 0;
+ memcpy((void*)dst->bytes_, src->bytes_, src->size_);
+ dst->size_ = src->size_;
+ }
+ return 1;
+}
+
+//------------------------------------------------------------------------------
+// Life of a MuxImage object.
+
+void MuxImageInit(WebPMuxImage* const wpi) {
+ assert(wpi);
+ memset(wpi, 0, sizeof(*wpi));
+}
+
+WebPMuxImage* MuxImageRelease(WebPMuxImage* const wpi) {
+ WebPMuxImage* next;
+ if (wpi == NULL) return NULL;
+ ChunkDelete(wpi->header_);
+ ChunkDelete(wpi->alpha_);
+ ChunkDelete(wpi->img_);
+
+ next = wpi->next_;
+ MuxImageInit(wpi);
+ return next;
+}
+
+//------------------------------------------------------------------------------
+// MuxImage search methods.
+
+int MuxImageCount(const WebPMuxImage* wpi_list, WebPChunkId id) {
+ int count = 0;
+ const WebPMuxImage* current;
+ for (current = wpi_list; current != NULL; current = current->next_) {
+ const WebPChunk* const wpi_chunk = *MuxImageGetListFromId(current, id);
+ if (wpi_chunk != NULL) {
+ const WebPChunkId wpi_chunk_id = ChunkGetIdFromTag(wpi_chunk->tag_);
+ if (wpi_chunk_id == id) ++count;
+ }
+ }
+ return count;
+}
+
+// Outputs a pointer to 'prev_wpi->next_',
+// where 'prev_wpi' is the pointer to the image at position (nth - 1).
+// Returns 1 if nth image with given id was found, 0 otherwise.
+static int SearchImageToGetOrDelete(WebPMuxImage** wpi_list, uint32_t nth,
+ WebPChunkId id,
+ WebPMuxImage*** const location) {
+ uint32_t count = 0;
+ assert(wpi_list);
+ *location = wpi_list;
+
+ // Search makes sense only for the following.
+ assert(id == WEBP_CHUNK_FRAME || id == WEBP_CHUNK_TILE ||
+ id == WEBP_CHUNK_IMAGE);
+ assert(id != WEBP_CHUNK_IMAGE || nth == 1);
+
+ if (nth == 0) {
+ nth = MuxImageCount(*wpi_list, id);
+ if (nth == 0) return 0; // Not found.
+ }
+
+ while (*wpi_list) {
+ WebPMuxImage* const cur_wpi = *wpi_list;
+ const WebPChunk* const wpi_chunk = *MuxImageGetListFromId(cur_wpi, id);
+ if (wpi_chunk != NULL) {
+ const WebPChunkId wpi_chunk_id = ChunkGetIdFromTag(wpi_chunk->tag_);
+ if (wpi_chunk_id == id) {
+ ++count;
+ if (count == nth) return 1; // Found.
+ }
+ }
+ wpi_list = &cur_wpi->next_;
+ *location = wpi_list;
+ }
+ return 0; // Not found.
+}
+
+//------------------------------------------------------------------------------
+// MuxImage writer methods.
+
+WebPMuxError MuxImagePush(const WebPMuxImage* wpi, WebPMuxImage** wpi_list) {
+ WebPMuxImage* new_wpi;
+
+ while (*wpi_list != NULL) {
+ WebPMuxImage* const cur_wpi = *wpi_list;
+ if (cur_wpi->next_ == NULL) break;
+ wpi_list = &cur_wpi->next_;
+ }
+
+ new_wpi = (WebPMuxImage*)malloc(sizeof(*new_wpi));
+ if (new_wpi == NULL) return WEBP_MUX_MEMORY_ERROR;
+ *new_wpi = *wpi;
+ new_wpi->next_ = NULL;
+
+ if (*wpi_list != NULL) {
+ (*wpi_list)->next_ = new_wpi;
+ } else {
+ *wpi_list = new_wpi;
+ }
+ return WEBP_MUX_OK;
+}
+
+//------------------------------------------------------------------------------
+// MuxImage deletion methods.
+
+WebPMuxImage* MuxImageDelete(WebPMuxImage* const wpi) {
+ // Delete the components of wpi. If wpi is NULL this is a noop.
+ WebPMuxImage* const next = MuxImageRelease(wpi);
+ free(wpi);
+ return next;
+}
+
+void MuxImageDeleteAll(WebPMuxImage** const wpi_list) {
+ while (*wpi_list) {
+ *wpi_list = MuxImageDelete(*wpi_list);
+ }
+}
+
+WebPMuxError MuxImageDeleteNth(WebPMuxImage** wpi_list, uint32_t nth,
+ WebPChunkId id) {
+ assert(wpi_list);
+ if (!SearchImageToGetOrDelete(wpi_list, nth, id, &wpi_list)) {
+ return WEBP_MUX_NOT_FOUND;
+ }
+ *wpi_list = MuxImageDelete(*wpi_list);
+ return WEBP_MUX_OK;
+}
+
+//------------------------------------------------------------------------------
+// MuxImage reader methods.
+
+WebPMuxError MuxImageGetNth(const WebPMuxImage** wpi_list, uint32_t nth,
+ WebPChunkId id, WebPMuxImage** wpi) {
+ assert(wpi_list);
+ assert(wpi);
+ if (!SearchImageToGetOrDelete((WebPMuxImage**)wpi_list, nth, id,
+ (WebPMuxImage***)&wpi_list)) {
+ return WEBP_MUX_NOT_FOUND;
+ }
+ *wpi = (WebPMuxImage*)*wpi_list;
+ return WEBP_MUX_OK;
+}
+
+//------------------------------------------------------------------------------
+// MuxImage serialization methods.
+
+// Size of an image.
+size_t MuxImageDiskSize(const WebPMuxImage* const wpi) {
+ size_t size = 0;
+ if (wpi->header_ != NULL) size += ChunkDiskSize(wpi->header_);
+ if (wpi->alpha_ != NULL) size += ChunkDiskSize(wpi->alpha_);
+ if (wpi->img_ != NULL) size += ChunkDiskSize(wpi->img_);
+ return size;
+}
+
+size_t MuxImageListDiskSize(const WebPMuxImage* wpi_list) {
+ size_t size = 0;
+ while (wpi_list) {
+ size += MuxImageDiskSize(wpi_list);
+ wpi_list = wpi_list->next_;
+ }
+ return size;
+}
+
+uint8_t* MuxImageEmit(const WebPMuxImage* const wpi, uint8_t* dst) {
+ // Ordering of chunks to be emitted is strictly as follows:
+ // 1. Frame/Tile chunk (if present).
+ // 2. Alpha chunk (if present).
+ // 3. VP8/VP8L chunk.
+ assert(wpi);
+ if (wpi->header_ != NULL) dst = ChunkEmit(wpi->header_, dst);
+ if (wpi->alpha_ != NULL) dst = ChunkEmit(wpi->alpha_, dst);
+ if (wpi->img_ != NULL) dst = ChunkEmit(wpi->img_, dst);
+ return dst;
+}
+
+uint8_t* MuxImageListEmit(const WebPMuxImage* wpi_list, uint8_t* dst) {
+ while (wpi_list) {
+ dst = MuxImageEmit(wpi_list, dst);
+ wpi_list = wpi_list->next_;
+ }
+ return dst;
+}
+
+//------------------------------------------------------------------------------
+// Helper methods for mux.
+
+int MuxHasLosslessImages(const WebPMuxImage* images) {
+ while (images != NULL) {
+ assert(images->img_ != NULL);
+ if (images->img_->tag_ == kChunks[IDX_VP8L].tag) {
+ return 1;
+ }
+ images = images->next_;
+ }
+ return 0;
+}
+
+uint8_t* MuxEmitRiffHeader(uint8_t* const data, size_t size) {
+ PutLE32(data + 0, MKFOURCC('R', 'I', 'F', 'F'));
+ PutLE32(data + TAG_SIZE, (uint32_t)size - CHUNK_HEADER_SIZE);
+ assert(size == (uint32_t)size);
+ PutLE32(data + TAG_SIZE + CHUNK_SIZE_BYTES, MKFOURCC('W', 'E', 'B', 'P'));
+ return data + RIFF_HEADER_SIZE;
+}
+
+WebPChunk** MuxGetChunkListFromId(const WebPMux* mux, WebPChunkId id) {
+ assert(mux != NULL);
+ switch(id) {
+ case WEBP_CHUNK_VP8X: return (WebPChunk**)&mux->vp8x_;
+ case WEBP_CHUNK_ICCP: return (WebPChunk**)&mux->iccp_;
+ case WEBP_CHUNK_LOOP: return (WebPChunk**)&mux->loop_;
+ case WEBP_CHUNK_META: return (WebPChunk**)&mux->meta_;
+ case WEBP_CHUNK_UNKNOWN: return (WebPChunk**)&mux->unknown_;
+ default: return NULL;
+ }
+}
+
+WebPMuxError MuxValidateForImage(const WebPMux* const mux) {
+ const int num_images = MuxImageCount(mux->images_, WEBP_CHUNK_IMAGE);
+ const int num_frames = MuxImageCount(mux->images_, WEBP_CHUNK_FRAME);
+ const int num_tiles = MuxImageCount(mux->images_, WEBP_CHUNK_TILE);
+
+ if (num_images == 0) {
+ // No images in mux.
+ return WEBP_MUX_NOT_FOUND;
+ } else if (num_images == 1 && num_frames == 0 && num_tiles == 0) {
+ // Valid case (single image).
+ return WEBP_MUX_OK;
+ } else {
+ // Frame/Tile case OR an invalid mux.
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+}
+
+static int IsNotCompatible(int feature, int num_items) {
+ return (feature != 0) != (num_items > 0);
+}
+
+#define NO_FLAG 0
+
+// Test basic constraints:
+// retrieval, maximum number of chunks by index (use -1 to skip)
+// and feature incompatibility (use NO_FLAG to skip).
+// On success returns WEBP_MUX_OK and stores the chunk count in *num.
+static WebPMuxError ValidateChunk(const WebPMux* const mux, CHUNK_INDEX idx,
+ WebPFeatureFlags feature,
+ WebPFeatureFlags vp8x_flags,
+ int max, int* num) {
+ const WebPMuxError err =
+ WebPMuxNumChunks(mux, kChunks[idx].id, num);
+ if (err != WEBP_MUX_OK) return err;
+ if (max > -1 && *num > max) return WEBP_MUX_INVALID_ARGUMENT;
+ if (feature != NO_FLAG && IsNotCompatible(vp8x_flags & feature, *num)) {
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+ return WEBP_MUX_OK;
+}
+
+WebPMuxError MuxValidate(const WebPMux* const mux) {
+ int num_iccp;
+ int num_meta;
+ int num_loop_chunks;
+ int num_frames;
+ int num_tiles;
+ int num_vp8x;
+ int num_images;
+ int num_alpha;
+ uint32_t flags;
+ WebPMuxError err;
+
+ // Verify mux is not NULL.
+ if (mux == NULL) return WEBP_MUX_INVALID_ARGUMENT;
+
+ // Verify mux has at least one image.
+ if (mux->images_ == NULL) return WEBP_MUX_INVALID_ARGUMENT;
+
+ err = WebPMuxGetFeatures(mux, &flags);
+ if (err != WEBP_MUX_OK) return err;
+
+ // At most one color profile chunk.
+ err = ValidateChunk(mux, IDX_ICCP, ICCP_FLAG, flags, 1, &num_iccp);
+ if (err != WEBP_MUX_OK) return err;
+
+ // At most one XMP metadata.
+ err = ValidateChunk(mux, IDX_META, META_FLAG, flags, 1, &num_meta);
+ if (err != WEBP_MUX_OK) return err;
+
+ // Animation: ANIMATION_FLAG, loop chunk and frame chunk(s) are consistent.
+ // At most one loop chunk.
+ err = ValidateChunk(mux, IDX_LOOP, NO_FLAG, flags, 1, &num_loop_chunks);
+ if (err != WEBP_MUX_OK) return err;
+ err = ValidateChunk(mux, IDX_FRAME, NO_FLAG, flags, -1, &num_frames);
+ if (err != WEBP_MUX_OK) return err;
+
+ {
+ const int has_animation = !!(flags & ANIMATION_FLAG);
+ if (has_animation && (num_loop_chunks == 0 || num_frames == 0)) {
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+ if (!has_animation && (num_loop_chunks == 1 || num_frames > 0)) {
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+ }
+
+ // Tiling: TILE_FLAG and tile chunk(s) are consistent.
+ err = ValidateChunk(mux, IDX_TILE, TILE_FLAG, flags, -1, &num_tiles);
+ if (err != WEBP_MUX_OK) return err;
+
+ // Verify either VP8X chunk is present OR there is only one elem in
+ // mux->images_.
+ err = ValidateChunk(mux, IDX_VP8X, NO_FLAG, flags, 1, &num_vp8x);
+ if (err != WEBP_MUX_OK) return err;
+ err = ValidateChunk(mux, IDX_VP8, NO_FLAG, flags, -1, &num_images);
+ if (err != WEBP_MUX_OK) return err;
+ if (num_vp8x == 0 && num_images != 1) return WEBP_MUX_INVALID_ARGUMENT;
+
+ // ALPHA_FLAG & alpha chunk(s) are consistent.
+ if (num_vp8x > 0 && MuxHasLosslessImages(mux->images_)) {
+ // Special case: we have a VP8X chunk as well as some lossless images.
+ if (!(flags & ALPHA_FLAG)) return WEBP_MUX_INVALID_ARGUMENT;
+ } else {
+ err = ValidateChunk(mux, IDX_ALPHA, ALPHA_FLAG, flags, -1, &num_alpha);
+ if (err != WEBP_MUX_OK) return err;
+ }
+
+ // num_tiles & num_images are consistent.
+ if (num_tiles > 0 && num_images != num_tiles) {
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+
+ return WEBP_MUX_OK;
+}
+
+#undef NO_FLAG
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/mux/muxread.c b/drivers/webpold/mux/muxread.c
new file mode 100644
index 0000000000..21c3cfbaeb
--- /dev/null
+++ b/drivers/webpold/mux/muxread.c
@@ -0,0 +1,411 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Read APIs for mux.
+//
+// Authors: Urvang (urvang@google.com)
+// Vikas (vikasa@google.com)
+
+#include <assert.h>
+#include "./muxi.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// Helper method(s).
+
+// Handy MACRO.
+#define SWITCH_ID_LIST(INDEX, LIST) \
+ if (idx == (INDEX)) { \
+ const WebPChunk* const chunk = ChunkSearchList((LIST), nth, \
+ kChunks[(INDEX)].tag); \
+ if (chunk) { \
+ *data = chunk->data_; \
+ return WEBP_MUX_OK; \
+ } else { \
+ return WEBP_MUX_NOT_FOUND; \
+ } \
+ }
+
+static WebPMuxError MuxGet(const WebPMux* const mux, CHUNK_INDEX idx,
+ uint32_t nth, WebPData* const data) {
+ assert(mux != NULL);
+ assert(!IsWPI(kChunks[idx].id));
+ WebPDataInit(data);
+
+ SWITCH_ID_LIST(IDX_VP8X, mux->vp8x_);
+ SWITCH_ID_LIST(IDX_ICCP, mux->iccp_);
+ SWITCH_ID_LIST(IDX_LOOP, mux->loop_);
+ SWITCH_ID_LIST(IDX_META, mux->meta_);
+ SWITCH_ID_LIST(IDX_UNKNOWN, mux->unknown_);
+ return WEBP_MUX_NOT_FOUND;
+}
+#undef SWITCH_ID_LIST
+
+// Fill the chunk with the given data (includes chunk header bytes), after some
+// verifications.
+static WebPMuxError ChunkVerifyAndAssignData(WebPChunk* chunk,
+ const uint8_t* data,
+ size_t data_size, size_t riff_size,
+ int copy_data) {
+ uint32_t chunk_size;
+ WebPData chunk_data;
+
+ // Sanity checks.
+ if (data_size < TAG_SIZE) return WEBP_MUX_NOT_ENOUGH_DATA;
+ chunk_size = GetLE32(data + TAG_SIZE);
+
+ {
+ const size_t chunk_disk_size = SizeWithPadding(chunk_size);
+ if (chunk_disk_size > riff_size) return WEBP_MUX_BAD_DATA;
+ if (chunk_disk_size > data_size) return WEBP_MUX_NOT_ENOUGH_DATA;
+ }
+
+ // Data assignment.
+ chunk_data.bytes_ = data + CHUNK_HEADER_SIZE;
+ chunk_data.size_ = chunk_size;
+ return ChunkAssignData(chunk, &chunk_data, copy_data, GetLE32(data + 0));
+}
+
+//------------------------------------------------------------------------------
+// Create a mux object from WebP-RIFF data.
+
+WebPMux* WebPMuxCreateInternal(const WebPData* bitstream, int copy_data,
+ int version) {
+ size_t riff_size;
+ uint32_t tag;
+ const uint8_t* end;
+ WebPMux* mux = NULL;
+ WebPMuxImage* wpi = NULL;
+ const uint8_t* data;
+ size_t size;
+ WebPChunk chunk;
+ ChunkInit(&chunk);
+
+ // Sanity checks.
+ if (WEBP_ABI_IS_INCOMPATIBLE(version, WEBP_MUX_ABI_VERSION)) {
+ return NULL; // version mismatch
+ }
+ if (bitstream == NULL) return NULL;
+
+ data = bitstream->bytes_;
+ size = bitstream->size_;
+
+ if (data == NULL) return NULL;
+ if (size < RIFF_HEADER_SIZE) return NULL;
+ if (GetLE32(data + 0) != MKFOURCC('R', 'I', 'F', 'F') ||
+ GetLE32(data + CHUNK_HEADER_SIZE) != MKFOURCC('W', 'E', 'B', 'P')) {
+ return NULL;
+ }
+
+ mux = WebPMuxNew();
+ if (mux == NULL) return NULL;
+
+ if (size < RIFF_HEADER_SIZE + TAG_SIZE) goto Err;
+
+ tag = GetLE32(data + RIFF_HEADER_SIZE);
+ if (tag != kChunks[IDX_VP8].tag &&
+ tag != kChunks[IDX_VP8L].tag &&
+ tag != kChunks[IDX_VP8X].tag) {
+ goto Err; // First chunk should be VP8, VP8L or VP8X.
+ }
+
+ riff_size = SizeWithPadding(GetLE32(data + TAG_SIZE));
+ if (riff_size > MAX_CHUNK_PAYLOAD || riff_size > size) {
+ goto Err;
+ } else {
+ if (riff_size < size) { // Redundant data after last chunk.
+ size = riff_size; // To make sure we don't read any data beyond mux_size.
+ }
+ }
+
+ end = data + size;
+ data += RIFF_HEADER_SIZE;
+ size -= RIFF_HEADER_SIZE;
+
+ wpi = (WebPMuxImage*)malloc(sizeof(*wpi));
+ if (wpi == NULL) goto Err;
+ MuxImageInit(wpi);
+
+ // Loop over chunks.
+ while (data != end) {
+ WebPChunkId id;
+ WebPMuxError err;
+
+ err = ChunkVerifyAndAssignData(&chunk, data, size, riff_size, copy_data);
+ if (err != WEBP_MUX_OK) goto Err;
+
+ id = ChunkGetIdFromTag(chunk.tag_);
+
+ if (IsWPI(id)) { // An image chunk (frame/tile/alpha/vp8).
+ WebPChunk** wpi_chunk_ptr =
+ MuxImageGetListFromId(wpi, id); // Image chunk to set.
+ assert(wpi_chunk_ptr != NULL);
+ if (*wpi_chunk_ptr != NULL) goto Err; // Consecutive alpha chunks or
+ // consecutive frame/tile chunks.
+ if (ChunkSetNth(&chunk, wpi_chunk_ptr, 1) != WEBP_MUX_OK) goto Err;
+ if (id == WEBP_CHUNK_IMAGE) {
+ wpi->is_partial_ = 0; // wpi is completely filled.
+ // Add this to mux->images_ list.
+ if (MuxImagePush(wpi, &mux->images_) != WEBP_MUX_OK) goto Err;
+ MuxImageInit(wpi); // Reset for reading next image.
+ } else {
+ wpi->is_partial_ = 1; // wpi is only partially filled.
+ }
+ } else { // A non-image chunk.
+ WebPChunk** chunk_list;
+ if (wpi->is_partial_) goto Err; // Encountered a non-image chunk before
+ // getting all chunks of an image.
+ chunk_list = MuxGetChunkListFromId(mux, id); // List to add this chunk.
+ if (chunk_list == NULL) chunk_list = &mux->unknown_;
+ if (ChunkSetNth(&chunk, chunk_list, 0) != WEBP_MUX_OK) goto Err;
+ }
+ {
+ const size_t data_size = ChunkDiskSize(&chunk);
+ data += data_size;
+ size -= data_size;
+ }
+ ChunkInit(&chunk);
+ }
+
+ // Validate mux if complete.
+ if (MuxValidate(mux) != WEBP_MUX_OK) goto Err;
+
+ MuxImageDelete(wpi);
+ return mux; // All OK;
+
+ Err: // Something bad happened.
+ ChunkRelease(&chunk);
+ MuxImageDelete(wpi);
+ WebPMuxDelete(mux);
+ return NULL;
+}
+
+//------------------------------------------------------------------------------
+// Get API(s).
+
+WebPMuxError WebPMuxGetFeatures(const WebPMux* mux, uint32_t* flags) {
+ WebPData data;
+ WebPMuxError err;
+
+ if (mux == NULL || flags == NULL) return WEBP_MUX_INVALID_ARGUMENT;
+ *flags = 0;
+
+ // Check if VP8X chunk is present.
+ err = MuxGet(mux, IDX_VP8X, 1, &data);
+ if (err == WEBP_MUX_NOT_FOUND) {
+ // Check if VP8/VP8L chunk is present.
+ err = WebPMuxGetImage(mux, &data);
+ WebPDataClear(&data);
+ return err;
+ } else if (err != WEBP_MUX_OK) {
+ return err;
+ }
+
+ if (data.size_ < CHUNK_SIZE_BYTES) return WEBP_MUX_BAD_DATA;
+
+ // All OK. Fill up flags.
+ *flags = GetLE32(data.bytes_);
+ return WEBP_MUX_OK;
+}
+
+static uint8_t* EmitVP8XChunk(uint8_t* const dst, int width,
+ int height, uint32_t flags) {
+ const size_t vp8x_size = CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE;
+ assert(width >= 1 && height >= 1);
+ assert(width <= MAX_CANVAS_SIZE && height <= MAX_CANVAS_SIZE);
+ assert(width * (uint64_t)height < MAX_IMAGE_AREA);
+ PutLE32(dst, MKFOURCC('V', 'P', '8', 'X'));
+ PutLE32(dst + TAG_SIZE, VP8X_CHUNK_SIZE);
+ PutLE32(dst + CHUNK_HEADER_SIZE, flags);
+ PutLE24(dst + CHUNK_HEADER_SIZE + 4, width - 1);
+ PutLE24(dst + CHUNK_HEADER_SIZE + 7, height - 1);
+ return dst + vp8x_size;
+}
+
+// Assemble a single image WebP bitstream from 'wpi'.
+static WebPMuxError SynthesizeBitstream(WebPMuxImage* const wpi,
+ WebPData* const bitstream) {
+ uint8_t* dst;
+
+ // Allocate data.
+ const int need_vp8x = (wpi->alpha_ != NULL);
+ const size_t vp8x_size = need_vp8x ? CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE : 0;
+ const size_t alpha_size = need_vp8x ? ChunkDiskSize(wpi->alpha_) : 0;
+ // Note: No need to output FRM/TILE chunk for a single image.
+ const size_t size = RIFF_HEADER_SIZE + vp8x_size + alpha_size +
+ ChunkDiskSize(wpi->img_);
+ uint8_t* const data = (uint8_t*)malloc(size);
+ if (data == NULL) return WEBP_MUX_MEMORY_ERROR;
+
+ // Main RIFF header.
+ dst = MuxEmitRiffHeader(data, size);
+
+ if (need_vp8x) {
+ int w, h;
+ WebPMuxError err;
+ assert(wpi->img_ != NULL);
+ err = MuxGetImageWidthHeight(wpi->img_, &w, &h);
+ if (err != WEBP_MUX_OK) {
+ free(data);
+ return err;
+ }
+ dst = EmitVP8XChunk(dst, w, h, ALPHA_FLAG); // VP8X.
+ dst = ChunkListEmit(wpi->alpha_, dst); // ALPH.
+ }
+
+ // Bitstream.
+ dst = ChunkListEmit(wpi->img_, dst);
+ assert(dst == data + size);
+
+ // Output.
+ bitstream->bytes_ = data;
+ bitstream->size_ = size;
+ return WEBP_MUX_OK;
+}
+
+WebPMuxError WebPMuxGetImage(const WebPMux* mux, WebPData* bitstream) {
+ WebPMuxError err;
+ WebPMuxImage* wpi = NULL;
+
+ if (mux == NULL || bitstream == NULL) {
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+
+ err = MuxValidateForImage(mux);
+ if (err != WEBP_MUX_OK) return err;
+
+ // All well. Get the image.
+ err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, 1, WEBP_CHUNK_IMAGE,
+ &wpi);
+ assert(err == WEBP_MUX_OK); // Already tested above.
+
+ return SynthesizeBitstream(wpi, bitstream);
+}
+
+WebPMuxError WebPMuxGetMetadata(const WebPMux* mux, WebPData* metadata) {
+ if (mux == NULL || metadata == NULL) return WEBP_MUX_INVALID_ARGUMENT;
+ return MuxGet(mux, IDX_META, 1, metadata);
+}
+
+WebPMuxError WebPMuxGetColorProfile(const WebPMux* mux,
+ WebPData* color_profile) {
+ if (mux == NULL || color_profile == NULL) return WEBP_MUX_INVALID_ARGUMENT;
+ return MuxGet(mux, IDX_ICCP, 1, color_profile);
+}
+
+WebPMuxError WebPMuxGetLoopCount(const WebPMux* mux, int* loop_count) {
+ WebPData image;
+ WebPMuxError err;
+
+ if (mux == NULL || loop_count == NULL) return WEBP_MUX_INVALID_ARGUMENT;
+
+ err = MuxGet(mux, IDX_LOOP, 1, &image);
+ if (err != WEBP_MUX_OK) return err;
+ if (image.size_ < kChunks[WEBP_CHUNK_LOOP].size) return WEBP_MUX_BAD_DATA;
+ *loop_count = GetLE16(image.bytes_);
+
+ return WEBP_MUX_OK;
+}
+
+static WebPMuxError MuxGetFrameTileInternal(
+ const WebPMux* const mux, uint32_t nth, WebPData* const bitstream,
+ int* const x_offset, int* const y_offset, int* const duration,
+ uint32_t tag) {
+ const WebPData* frame_tile_data;
+ WebPMuxError err;
+ WebPMuxImage* wpi;
+
+ const int is_frame = (tag == kChunks[WEBP_CHUNK_FRAME].tag) ? 1 : 0;
+ const CHUNK_INDEX idx = is_frame ? IDX_FRAME : IDX_TILE;
+ const WebPChunkId id = kChunks[idx].id;
+
+ if (mux == NULL || bitstream == NULL ||
+ x_offset == NULL || y_offset == NULL || (is_frame && duration == NULL)) {
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+
+ // Get the nth WebPMuxImage.
+ err = MuxImageGetNth((const WebPMuxImage**)&mux->images_, nth, id, &wpi);
+ if (err != WEBP_MUX_OK) return err;
+
+ // Get frame chunk.
+ assert(wpi->header_ != NULL); // As MuxImageGetNth() already checked header_.
+ frame_tile_data = &wpi->header_->data_;
+
+ if (frame_tile_data->size_ < kChunks[idx].size) return WEBP_MUX_BAD_DATA;
+ *x_offset = 2 * GetLE24(frame_tile_data->bytes_ + 0);
+ *y_offset = 2 * GetLE24(frame_tile_data->bytes_ + 3);
+ if (is_frame) *duration = 1 + GetLE24(frame_tile_data->bytes_ + 12);
+
+ return SynthesizeBitstream(wpi, bitstream);
+}
+
+WebPMuxError WebPMuxGetFrame(const WebPMux* mux, uint32_t nth,
+ WebPData* bitstream,
+ int* x_offset, int* y_offset, int* duration) {
+ return MuxGetFrameTileInternal(mux, nth, bitstream, x_offset, y_offset,
+ duration, kChunks[IDX_FRAME].tag);
+}
+
+WebPMuxError WebPMuxGetTile(const WebPMux* mux, uint32_t nth,
+ WebPData* bitstream,
+ int* x_offset, int* y_offset) {
+ return MuxGetFrameTileInternal(mux, nth, bitstream, x_offset, y_offset, NULL,
+ kChunks[IDX_TILE].tag);
+}
+
+// Get chunk index from chunk id. Returns IDX_NIL if not found.
+static CHUNK_INDEX ChunkGetIndexFromId(WebPChunkId id) {
+ int i;
+ for (i = 0; kChunks[i].id != WEBP_CHUNK_NIL; ++i) {
+ if (id == kChunks[i].id) return i;
+ }
+ return IDX_NIL;
+}
+
+// Count number of chunks matching 'tag' in the 'chunk_list'.
+// If tag == NIL_TAG, any tag will be matched.
+static int CountChunks(const WebPChunk* const chunk_list, uint32_t tag) {
+ int count = 0;
+ const WebPChunk* current;
+ for (current = chunk_list; current != NULL; current = current->next_) {
+ if (tag == NIL_TAG || current->tag_ == tag) {
+ count++; // Count chunks whose tags match.
+ }
+ }
+ return count;
+}
+
+WebPMuxError WebPMuxNumChunks(const WebPMux* mux,
+ WebPChunkId id, int* num_elements) {
+ if (mux == NULL || num_elements == NULL) {
+ return WEBP_MUX_INVALID_ARGUMENT;
+ }
+
+ if (IsWPI(id)) {
+ *num_elements = MuxImageCount(mux->images_, id);
+ } else {
+ WebPChunk* const* chunk_list = MuxGetChunkListFromId(mux, id);
+ if (chunk_list == NULL) {
+ *num_elements = 0;
+ } else {
+ const CHUNK_INDEX idx = ChunkGetIndexFromId(id);
+ *num_elements = CountChunks(*chunk_list, kChunks[idx].tag);
+ }
+ }
+
+ return WEBP_MUX_OK;
+}
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/types.h b/drivers/webpold/types.h
new file mode 100644
index 0000000000..3e27190bef
--- /dev/null
+++ b/drivers/webpold/types.h
@@ -0,0 +1,45 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Common types
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#ifndef WEBP_WEBP_TYPES_H_
+#define WEBP_WEBP_TYPES_H_
+
+#include <stddef.h> // for size_t
+
+#ifndef _MSC_VER
+#include <inttypes.h>
+#ifdef __STRICT_ANSI__
+#define WEBP_INLINE
+#else /* __STRICT_ANSI__ */
+#define WEBP_INLINE inline
+#endif
+#else
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef signed short int16_t;
+typedef unsigned short uint16_t;
+typedef signed int int32_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long int uint64_t;
+typedef long long int int64_t;
+#define WEBP_INLINE __forceinline
+#endif /* _MSC_VER */
+
+#ifndef WEBP_EXTERN
+// This explicitly marks library functions and allows for changing the
+// signature for e.g., Windows DLL builds.
+#define WEBP_EXTERN(type) extern type
+#endif /* WEBP_EXTERN */
+
+// Macro to check ABI compatibility (same major revision number)
+#define WEBP_ABI_IS_INCOMPATIBLE(a, b) (((a) >> 8) != ((b) >> 8))
+
+#endif /* WEBP_WEBP_TYPES_H_ */
diff --git a/drivers/webpold/utils/bit_reader.c b/drivers/webpold/utils/bit_reader.c
new file mode 100644
index 0000000000..1afb1db890
--- /dev/null
+++ b/drivers/webpold/utils/bit_reader.c
@@ -0,0 +1,229 @@
+// Copyright 2010 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Boolean decoder
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include "./bit_reader.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define MK(X) (((bit_t)(X) << (BITS)) | (MASK))
+
+//------------------------------------------------------------------------------
+// VP8BitReader
+
+void VP8InitBitReader(VP8BitReader* const br,
+ const uint8_t* const start, const uint8_t* const end) {
+ assert(br != NULL);
+ assert(start != NULL);
+ assert(start <= end);
+ br->range_ = MK(255 - 1);
+ br->buf_ = start;
+ br->buf_end_ = end;
+ br->value_ = 0;
+ br->missing_ = 8; // to load the very first 8bits
+ br->eof_ = 0;
+}
+
+const uint8_t kVP8Log2Range[128] = {
+ 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 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, 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,
+ 0
+};
+
+// range = (range << kVP8Log2Range[range]) + trailing 1's
+const bit_t kVP8NewRange[128] = {
+ MK(127), MK(127), MK(191), MK(127), MK(159), MK(191), MK(223), MK(127),
+ MK(143), MK(159), MK(175), MK(191), MK(207), MK(223), MK(239), MK(127),
+ MK(135), MK(143), MK(151), MK(159), MK(167), MK(175), MK(183), MK(191),
+ MK(199), MK(207), MK(215), MK(223), MK(231), MK(239), MK(247), MK(127),
+ MK(131), MK(135), MK(139), MK(143), MK(147), MK(151), MK(155), MK(159),
+ MK(163), MK(167), MK(171), MK(175), MK(179), MK(183), MK(187), MK(191),
+ MK(195), MK(199), MK(203), MK(207), MK(211), MK(215), MK(219), MK(223),
+ MK(227), MK(231), MK(235), MK(239), MK(243), MK(247), MK(251), MK(127),
+ MK(129), MK(131), MK(133), MK(135), MK(137), MK(139), MK(141), MK(143),
+ MK(145), MK(147), MK(149), MK(151), MK(153), MK(155), MK(157), MK(159),
+ MK(161), MK(163), MK(165), MK(167), MK(169), MK(171), MK(173), MK(175),
+ MK(177), MK(179), MK(181), MK(183), MK(185), MK(187), MK(189), MK(191),
+ MK(193), MK(195), MK(197), MK(199), MK(201), MK(203), MK(205), MK(207),
+ MK(209), MK(211), MK(213), MK(215), MK(217), MK(219), MK(221), MK(223),
+ MK(225), MK(227), MK(229), MK(231), MK(233), MK(235), MK(237), MK(239),
+ MK(241), MK(243), MK(245), MK(247), MK(249), MK(251), MK(253), MK(127)
+};
+
+#undef MK
+
+void VP8LoadFinalBytes(VP8BitReader* const br) {
+ assert(br != NULL && br->buf_ != NULL);
+ // Only read 8bits at a time
+ if (br->buf_ < br->buf_end_) {
+ br->value_ |= (bit_t)(*br->buf_++) << ((BITS) - 8 + br->missing_);
+ br->missing_ -= 8;
+ } else {
+ br->eof_ = 1;
+ }
+}
+
+//------------------------------------------------------------------------------
+// Higher-level calls
+
+uint32_t VP8GetValue(VP8BitReader* const br, int bits) {
+ uint32_t v = 0;
+ while (bits-- > 0) {
+ v |= VP8GetBit(br, 0x80) << bits;
+ }
+ return v;
+}
+
+int32_t VP8GetSignedValue(VP8BitReader* const br, int bits) {
+ const int value = VP8GetValue(br, bits);
+ return VP8Get(br) ? -value : value;
+}
+
+//------------------------------------------------------------------------------
+// VP8LBitReader
+
+#define MAX_NUM_BIT_READ 25
+
+static const uint32_t kBitMask[MAX_NUM_BIT_READ] = {
+ 0, 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, 16383, 32767,
+ 65535, 131071, 262143, 524287, 1048575, 2097151, 4194303, 8388607, 16777215
+};
+
+void VP8LInitBitReader(VP8LBitReader* const br,
+ const uint8_t* const start,
+ size_t length) {
+ size_t i;
+ assert(br != NULL);
+ assert(start != NULL);
+ assert(length < 0xfffffff8u); // can't happen with a RIFF chunk.
+
+ br->buf_ = start;
+ br->len_ = length;
+ br->val_ = 0;
+ br->pos_ = 0;
+ br->bit_pos_ = 0;
+ br->eos_ = 0;
+ br->error_ = 0;
+ for (i = 0; i < sizeof(br->val_) && i < br->len_; ++i) {
+ br->val_ |= ((uint64_t)br->buf_[br->pos_]) << (8 * i);
+ ++br->pos_;
+ }
+}
+
+void VP8LBitReaderSetBuffer(VP8LBitReader* const br,
+ const uint8_t* const buf, size_t len) {
+ assert(br != NULL);
+ assert(buf != NULL);
+ assert(len < 0xfffffff8u); // can't happen with a RIFF chunk.
+ br->eos_ = (br->pos_ >= len);
+ br->buf_ = buf;
+ br->len_ = len;
+}
+
+static void ShiftBytes(VP8LBitReader* const br) {
+ while (br->bit_pos_ >= 8 && br->pos_ < br->len_) {
+ br->val_ >>= 8;
+ br->val_ |= ((uint64_t)br->buf_[br->pos_]) << 56;
+ ++br->pos_;
+ br->bit_pos_ -= 8;
+ }
+}
+
+void VP8LFillBitWindow(VP8LBitReader* const br) {
+ if (br->bit_pos_ >= 32) {
+#if defined(__x86_64__) || defined(_M_X64)
+ if (br->pos_ + 8 < br->len_) {
+ br->val_ >>= 32;
+ // The expression below needs a little-endian arch to work correctly.
+ // This gives a large speedup for decoding speed.
+ br->val_ |= *(const uint64_t *)(br->buf_ + br->pos_) << 32;
+ br->pos_ += 4;
+ br->bit_pos_ -= 32;
+ } else {
+ // Slow path.
+ ShiftBytes(br);
+ }
+#else
+ // Always the slow path.
+ ShiftBytes(br);
+#endif
+ }
+ if (br->pos_ == br->len_ && br->bit_pos_ == 64) {
+ br->eos_ = 1;
+ }
+}
+
+uint32_t VP8LReadOneBit(VP8LBitReader* const br) {
+ const uint32_t val = (br->val_ >> br->bit_pos_) & 1;
+ // Flag an error at end_of_stream.
+ if (!br->eos_) {
+ ++br->bit_pos_;
+ if (br->bit_pos_ >= 32) {
+ ShiftBytes(br);
+ }
+ // After this last bit is read, check if eos needs to be flagged.
+ if (br->pos_ == br->len_ && br->bit_pos_ == 64) {
+ br->eos_ = 1;
+ }
+ } else {
+ br->error_ = 1;
+ }
+ return val;
+}
+
+uint32_t VP8LReadBits(VP8LBitReader* const br, int n_bits) {
+ uint32_t val = 0;
+ assert(n_bits >= 0);
+ // Flag an error if end_of_stream or n_bits is more than allowed limit.
+ if (!br->eos_ && n_bits < MAX_NUM_BIT_READ) {
+ // If this read is going to cross the read buffer, set the eos flag.
+ if (br->pos_ == br->len_) {
+ if ((br->bit_pos_ + n_bits) >= 64) {
+ br->eos_ = 1;
+ if ((br->bit_pos_ + n_bits) > 64) return val;
+ }
+ }
+ val = (br->val_ >> br->bit_pos_) & kBitMask[n_bits];
+ br->bit_pos_ += n_bits;
+ if (br->bit_pos_ >= 40) {
+ if (br->pos_ + 5 < br->len_) {
+ br->val_ >>= 40;
+ br->val_ |=
+ (((uint64_t)br->buf_[br->pos_ + 0]) << 24) |
+ (((uint64_t)br->buf_[br->pos_ + 1]) << 32) |
+ (((uint64_t)br->buf_[br->pos_ + 2]) << 40) |
+ (((uint64_t)br->buf_[br->pos_ + 3]) << 48) |
+ (((uint64_t)br->buf_[br->pos_ + 4]) << 56);
+ br->pos_ += 5;
+ br->bit_pos_ -= 40;
+ }
+ if (br->bit_pos_ >= 8) {
+ ShiftBytes(br);
+ }
+ }
+ } else {
+ br->error_ = 1;
+ }
+ return val;
+}
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/utils/bit_reader.h b/drivers/webpold/utils/bit_reader.h
new file mode 100644
index 0000000000..43cd948fd4
--- /dev/null
+++ b/drivers/webpold/utils/bit_reader.h
@@ -0,0 +1,198 @@
+//
+// Copyright 2010 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Boolean decoder
+//
+// Author: Skal (pascal.massimino@gmail.com)
+// Vikas Arora (vikaas.arora@gmail.com)
+
+#ifndef WEBP_UTILS_BIT_READER_H_
+#define WEBP_UTILS_BIT_READER_H_
+
+#include <assert.h>
+#ifdef _MSC_VER
+#include <stdlib.h> // _byteswap_ulong
+#endif
+#include <string.h> // For memcpy
+#include "../types.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define BITS 32 // can be 32, 16 or 8
+#define MASK ((((bit_t)1) << (BITS)) - 1)
+#if (BITS == 32)
+typedef uint64_t bit_t; // natural register type
+typedef uint32_t lbit_t; // natural type for memory I/O
+#elif (BITS == 16)
+typedef uint32_t bit_t;
+typedef uint16_t lbit_t;
+#else
+typedef uint32_t bit_t;
+typedef uint8_t lbit_t;
+#endif
+
+//------------------------------------------------------------------------------
+// Bitreader and code-tree reader
+
+typedef struct VP8BitReader VP8BitReader;
+struct VP8BitReader {
+ const uint8_t* buf_; // next byte to be read
+ const uint8_t* buf_end_; // end of read buffer
+ int eof_; // true if input is exhausted
+
+ // boolean decoder
+ bit_t range_; // current range minus 1. In [127, 254] interval.
+ bit_t value_; // current value
+ int missing_; // number of missing bits in value_ (8bit)
+};
+
+// Initialize the bit reader and the boolean decoder.
+void VP8InitBitReader(VP8BitReader* const br,
+ const uint8_t* const start, const uint8_t* const end);
+
+// return the next value made of 'num_bits' bits
+uint32_t VP8GetValue(VP8BitReader* const br, int num_bits);
+static WEBP_INLINE uint32_t VP8Get(VP8BitReader* const br) {
+ return VP8GetValue(br, 1);
+}
+
+// return the next value with sign-extension.
+int32_t VP8GetSignedValue(VP8BitReader* const br, int num_bits);
+
+// Read a bit with proba 'prob'. Speed-critical function!
+extern const uint8_t kVP8Log2Range[128];
+extern const bit_t kVP8NewRange[128];
+
+void VP8LoadFinalBytes(VP8BitReader* const br); // special case for the tail
+
+static WEBP_INLINE void VP8LoadNewBytes(VP8BitReader* const br) {
+ assert(br && br->buf_);
+ // Read 'BITS' bits at a time if possible.
+ if (br->buf_ + sizeof(lbit_t) <= br->buf_end_) {
+ // convert memory type to register type (with some zero'ing!)
+ bit_t bits;
+ lbit_t in_bits = *(lbit_t*)br->buf_;
+ br->buf_ += (BITS) >> 3;
+#if !defined(__BIG_ENDIAN__)
+#if (BITS == 32)
+#if defined(__i386__) || defined(__x86_64__)
+ __asm__ volatile("bswap %k0" : "=r"(in_bits) : "0"(in_bits));
+ bits = (bit_t)in_bits; // 32b -> 64b zero-extension
+#elif defined(_MSC_VER)
+ bits = _byteswap_ulong(in_bits);
+#else
+ bits = (bit_t)(in_bits >> 24) | ((in_bits >> 8) & 0xff00)
+ | ((in_bits << 8) & 0xff0000) | (in_bits << 24);
+#endif // x86
+#elif (BITS == 16)
+ // gcc will recognize a 'rorw $8, ...' here:
+ bits = (bit_t)(in_bits >> 8) | ((in_bits & 0xff) << 8);
+#endif
+#else // LITTLE_ENDIAN
+ bits = (bit_t)in_bits;
+#endif
+ br->value_ |= bits << br->missing_;
+ br->missing_ -= (BITS);
+ } else {
+ VP8LoadFinalBytes(br); // no need to be inlined
+ }
+}
+
+static WEBP_INLINE int VP8BitUpdate(VP8BitReader* const br, bit_t split) {
+ const bit_t value_split = split | (MASK);
+ if (br->missing_ > 0) { // Make sure we have a least BITS bits in 'value_'
+ VP8LoadNewBytes(br);
+ }
+ if (br->value_ > value_split) {
+ br->range_ -= value_split + 1;
+ br->value_ -= value_split + 1;
+ return 1;
+ } else {
+ br->range_ = value_split;
+ return 0;
+ }
+}
+
+static WEBP_INLINE void VP8Shift(VP8BitReader* const br) {
+ // range_ is in [0..127] interval here.
+ const int idx = br->range_ >> (BITS);
+ const int shift = kVP8Log2Range[idx];
+ br->range_ = kVP8NewRange[idx];
+ br->value_ <<= shift;
+ br->missing_ += shift;
+}
+
+static WEBP_INLINE int VP8GetBit(VP8BitReader* const br, int prob) {
+ // It's important to avoid generating a 64bit x 64bit multiply here.
+ // We just need an 8b x 8b after all.
+ const bit_t split =
+ (bit_t)((uint32_t)(br->range_ >> (BITS)) * prob) << ((BITS) - 8);
+ const int bit = VP8BitUpdate(br, split);
+ if (br->range_ <= (((bit_t)0x7e << (BITS)) | (MASK))) {
+ VP8Shift(br);
+ }
+ return bit;
+}
+
+static WEBP_INLINE int VP8GetSigned(VP8BitReader* const br, int v) {
+ const bit_t split = (br->range_ >> 1);
+ const int bit = VP8BitUpdate(br, split);
+ VP8Shift(br);
+ return bit ? -v : v;
+}
+
+
+// -----------------------------------------------------------------------------
+// Bitreader
+
+typedef struct {
+ uint64_t val_;
+ const uint8_t* buf_;
+ size_t len_;
+ size_t pos_;
+ int bit_pos_;
+ int eos_;
+ int error_;
+} VP8LBitReader;
+
+void VP8LInitBitReader(VP8LBitReader* const br,
+ const uint8_t* const start,
+ size_t length);
+
+// Sets a new data buffer.
+void VP8LBitReaderSetBuffer(VP8LBitReader* const br,
+ const uint8_t* const buffer, size_t length);
+
+// Reads the specified number of bits from Read Buffer.
+// Flags an error in case end_of_stream or n_bits is more than allowed limit.
+// Flags eos if this read attempt is going to cross the read buffer.
+uint32_t VP8LReadBits(VP8LBitReader* const br, int n_bits);
+
+// Reads one bit from Read Buffer. Flags an error in case end_of_stream.
+// Flags eos after reading last bit from the buffer.
+uint32_t VP8LReadOneBit(VP8LBitReader* const br);
+
+// VP8LReadOneBitUnsafe is faster than VP8LReadOneBit, but it can be called only
+// 32 times after the last VP8LFillBitWindow. Any subsequent calls
+// (without VP8LFillBitWindow) will return invalid data.
+static WEBP_INLINE uint32_t VP8LReadOneBitUnsafe(VP8LBitReader* const br) {
+ const uint32_t val = (br->val_ >> br->bit_pos_) & 1;
+ ++br->bit_pos_;
+ return val;
+}
+
+// Advances the Read buffer by 4 bytes to make room for reading next 32 bits.
+void VP8LFillBitWindow(VP8LBitReader* const br);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif /* WEBP_UTILS_BIT_READER_H_ */
diff --git a/drivers/webpold/utils/bit_writer.c b/drivers/webpold/utils/bit_writer.c
new file mode 100644
index 0000000000..671159cacd
--- /dev/null
+++ b/drivers/webpold/utils/bit_writer.c
@@ -0,0 +1,284 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Bit writing and boolean coder
+//
+// Author: Skal (pascal.massimino@gmail.com)
+// Vikas Arora (vikaas.arora@gmail.com)
+
+#include <assert.h>
+#include <string.h> // for memcpy()
+#include <stdlib.h>
+#include "./bit_writer.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// VP8BitWriter
+
+static int BitWriterResize(VP8BitWriter* const bw, size_t extra_size) {
+ uint8_t* new_buf;
+ size_t new_size;
+ const uint64_t needed_size_64b = (uint64_t)bw->pos_ + extra_size;
+ const size_t needed_size = (size_t)needed_size_64b;
+ if (needed_size_64b != needed_size) {
+ bw->error_ = 1;
+ return 0;
+ }
+ if (needed_size <= bw->max_pos_) return 1;
+ // If the following line wraps over 32bit, the test just after will catch it.
+ new_size = 2 * bw->max_pos_;
+ if (new_size < needed_size) new_size = needed_size;
+ if (new_size < 1024) new_size = 1024;
+ new_buf = (uint8_t*)malloc(new_size);
+ if (new_buf == NULL) {
+ bw->error_ = 1;
+ return 0;
+ }
+ memcpy(new_buf, bw->buf_, bw->pos_);
+ free(bw->buf_);
+ bw->buf_ = new_buf;
+ bw->max_pos_ = new_size;
+ return 1;
+}
+
+static void kFlush(VP8BitWriter* const bw) {
+ const int s = 8 + bw->nb_bits_;
+ const int32_t bits = bw->value_ >> s;
+ assert(bw->nb_bits_ >= 0);
+ bw->value_ -= bits << s;
+ bw->nb_bits_ -= 8;
+ if ((bits & 0xff) != 0xff) {
+ size_t pos = bw->pos_;
+ if (!BitWriterResize(bw, bw->run_ + 1)) {
+ return;
+ }
+ if (bits & 0x100) { // overflow -> propagate carry over pending 0xff's
+ if (pos > 0) bw->buf_[pos - 1]++;
+ }
+ if (bw->run_ > 0) {
+ const int value = (bits & 0x100) ? 0x00 : 0xff;
+ for (; bw->run_ > 0; --bw->run_) bw->buf_[pos++] = value;
+ }
+ bw->buf_[pos++] = bits;
+ bw->pos_ = pos;
+ } else {
+ bw->run_++; // delay writing of bytes 0xff, pending eventual carry.
+ }
+}
+
+//------------------------------------------------------------------------------
+// renormalization
+
+static const uint8_t kNorm[128] = { // renorm_sizes[i] = 8 - log2(i)
+ 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 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, 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,
+ 0
+};
+
+// range = ((range + 1) << kVP8Log2Range[range]) - 1
+static const uint8_t kNewRange[128] = {
+ 127, 127, 191, 127, 159, 191, 223, 127, 143, 159, 175, 191, 207, 223, 239,
+ 127, 135, 143, 151, 159, 167, 175, 183, 191, 199, 207, 215, 223, 231, 239,
+ 247, 127, 131, 135, 139, 143, 147, 151, 155, 159, 163, 167, 171, 175, 179,
+ 183, 187, 191, 195, 199, 203, 207, 211, 215, 219, 223, 227, 231, 235, 239,
+ 243, 247, 251, 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149,
+ 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179,
+ 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 201, 203, 205, 207, 209,
+ 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 237, 239,
+ 241, 243, 245, 247, 249, 251, 253, 127
+};
+
+int VP8PutBit(VP8BitWriter* const bw, int bit, int prob) {
+ const int split = (bw->range_ * prob) >> 8;
+ if (bit) {
+ bw->value_ += split + 1;
+ bw->range_ -= split + 1;
+ } else {
+ bw->range_ = split;
+ }
+ if (bw->range_ < 127) { // emit 'shift' bits out and renormalize
+ const int shift = kNorm[bw->range_];
+ bw->range_ = kNewRange[bw->range_];
+ bw->value_ <<= shift;
+ bw->nb_bits_ += shift;
+ if (bw->nb_bits_ > 0) kFlush(bw);
+ }
+ return bit;
+}
+
+int VP8PutBitUniform(VP8BitWriter* const bw, int bit) {
+ const int split = bw->range_ >> 1;
+ if (bit) {
+ bw->value_ += split + 1;
+ bw->range_ -= split + 1;
+ } else {
+ bw->range_ = split;
+ }
+ if (bw->range_ < 127) {
+ bw->range_ = kNewRange[bw->range_];
+ bw->value_ <<= 1;
+ bw->nb_bits_ += 1;
+ if (bw->nb_bits_ > 0) kFlush(bw);
+ }
+ return bit;
+}
+
+void VP8PutValue(VP8BitWriter* const bw, int value, int nb_bits) {
+ int mask;
+ for (mask = 1 << (nb_bits - 1); mask; mask >>= 1)
+ VP8PutBitUniform(bw, value & mask);
+}
+
+void VP8PutSignedValue(VP8BitWriter* const bw, int value, int nb_bits) {
+ if (!VP8PutBitUniform(bw, value != 0))
+ return;
+ if (value < 0) {
+ VP8PutValue(bw, ((-value) << 1) | 1, nb_bits + 1);
+ } else {
+ VP8PutValue(bw, value << 1, nb_bits + 1);
+ }
+}
+
+//------------------------------------------------------------------------------
+
+int VP8BitWriterInit(VP8BitWriter* const bw, size_t expected_size) {
+ bw->range_ = 255 - 1;
+ bw->value_ = 0;
+ bw->run_ = 0;
+ bw->nb_bits_ = -8;
+ bw->pos_ = 0;
+ bw->max_pos_ = 0;
+ bw->error_ = 0;
+ bw->buf_ = NULL;
+ return (expected_size > 0) ? BitWriterResize(bw, expected_size) : 1;
+}
+
+uint8_t* VP8BitWriterFinish(VP8BitWriter* const bw) {
+ VP8PutValue(bw, 0, 9 - bw->nb_bits_);
+ bw->nb_bits_ = 0; // pad with zeroes
+ kFlush(bw);
+ return bw->buf_;
+}
+
+int VP8BitWriterAppend(VP8BitWriter* const bw,
+ const uint8_t* data, size_t size) {
+ assert(data);
+ if (bw->nb_bits_ != -8) return 0; // kFlush() must have been called
+ if (!BitWriterResize(bw, size)) return 0;
+ memcpy(bw->buf_ + bw->pos_, data, size);
+ bw->pos_ += size;
+ return 1;
+}
+
+void VP8BitWriterWipeOut(VP8BitWriter* const bw) {
+ if (bw) {
+ free(bw->buf_);
+ memset(bw, 0, sizeof(*bw));
+ }
+}
+
+//------------------------------------------------------------------------------
+// VP8LBitWriter
+
+// Returns 1 on success.
+static int VP8LBitWriterResize(VP8LBitWriter* const bw, size_t extra_size) {
+ uint8_t* allocated_buf;
+ size_t allocated_size;
+ const size_t current_size = VP8LBitWriterNumBytes(bw);
+ const uint64_t size_required_64b = (uint64_t)current_size + extra_size;
+ const size_t size_required = (size_t)size_required_64b;
+ if (size_required != size_required_64b) {
+ bw->error_ = 1;
+ return 0;
+ }
+ if (bw->max_bytes_ > 0 && size_required <= bw->max_bytes_) return 1;
+ allocated_size = (3 * bw->max_bytes_) >> 1;
+ if (allocated_size < size_required) allocated_size = size_required;
+ // make allocated size multiple of 1k
+ allocated_size = (((allocated_size >> 10) + 1) << 10);
+ allocated_buf = (uint8_t*)malloc(allocated_size);
+ if (allocated_buf == NULL) {
+ bw->error_ = 1;
+ return 0;
+ }
+ memcpy(allocated_buf, bw->buf_, current_size);
+ free(bw->buf_);
+ bw->buf_ = allocated_buf;
+ bw->max_bytes_ = allocated_size;
+ memset(allocated_buf + current_size, 0, allocated_size - current_size);
+ return 1;
+}
+
+int VP8LBitWriterInit(VP8LBitWriter* const bw, size_t expected_size) {
+ memset(bw, 0, sizeof(*bw));
+ return VP8LBitWriterResize(bw, expected_size);
+}
+
+void VP8LBitWriterDestroy(VP8LBitWriter* const bw) {
+ if (bw != NULL) {
+ free(bw->buf_);
+ memset(bw, 0, sizeof(*bw));
+ }
+}
+
+void VP8LWriteBits(VP8LBitWriter* const bw, int n_bits, uint32_t bits) {
+ if (n_bits < 1) return;
+#if !defined(__BIG_ENDIAN__)
+ // Technically, this branch of the code can write up to 25 bits at a time,
+ // but in prefix encoding, the maximum number of bits written is 18 at a time.
+ {
+ uint8_t* const p = &bw->buf_[bw->bit_pos_ >> 3];
+ uint32_t v = *(const uint32_t*)p;
+ v |= bits << (bw->bit_pos_ & 7);
+ *(uint32_t*)p = v;
+ bw->bit_pos_ += n_bits;
+ }
+#else // BIG_ENDIAN
+ {
+ uint8_t* p = &bw->buf_[bw->bit_pos_ >> 3];
+ const int bits_reserved_in_first_byte = bw->bit_pos_ & 7;
+ const int bits_left_to_write = n_bits - 8 + bits_reserved_in_first_byte;
+ // implicit & 0xff is assumed for uint8_t arithmetics
+ *p++ |= bits << bits_reserved_in_first_byte;
+ bits >>= 8 - bits_reserved_in_first_byte;
+ if (bits_left_to_write >= 1) {
+ *p++ = bits;
+ bits >>= 8;
+ if (bits_left_to_write >= 9) {
+ *p++ = bits;
+ bits >>= 8;
+ }
+ }
+ assert(n_bits <= 25);
+ *p = bits;
+ bw->bit_pos_ += n_bits;
+ }
+#endif
+ if ((bw->bit_pos_ >> 3) > (bw->max_bytes_ - 8)) {
+ const uint64_t extra_size = 32768ULL + bw->max_bytes_;
+ if (extra_size != (size_t)extra_size ||
+ !VP8LBitWriterResize(bw, (size_t)extra_size)) {
+ bw->bit_pos_ = 0;
+ bw->error_ = 1;
+ }
+ }
+}
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/utils/bit_writer.h b/drivers/webpold/utils/bit_writer.h
new file mode 100644
index 0000000000..57f39b11b1
--- /dev/null
+++ b/drivers/webpold/utils/bit_writer.h
@@ -0,0 +1,123 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Bit writing and boolean coder
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#ifndef WEBP_UTILS_BIT_WRITER_H_
+#define WEBP_UTILS_BIT_WRITER_H_
+
+#include "../types.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// Bit-writing
+
+typedef struct VP8BitWriter VP8BitWriter;
+struct VP8BitWriter {
+ int32_t range_; // range-1
+ int32_t value_;
+ int run_; // number of outstanding bits
+ int nb_bits_; // number of pending bits
+ uint8_t* buf_; // internal buffer. Re-allocated regularly. Not owned.
+ size_t pos_;
+ size_t max_pos_;
+ int error_; // true in case of error
+};
+
+// Initialize the object. Allocates some initial memory based on expected_size.
+int VP8BitWriterInit(VP8BitWriter* const bw, size_t expected_size);
+// Finalize the bitstream coding. Returns a pointer to the internal buffer.
+uint8_t* VP8BitWriterFinish(VP8BitWriter* const bw);
+// Release any pending memory and zeroes the object. Not a mandatory call.
+// Only useful in case of error, when the internal buffer hasn't been grabbed!
+void VP8BitWriterWipeOut(VP8BitWriter* const bw);
+
+int VP8PutBit(VP8BitWriter* const bw, int bit, int prob);
+int VP8PutBitUniform(VP8BitWriter* const bw, int bit);
+void VP8PutValue(VP8BitWriter* const bw, int value, int nb_bits);
+void VP8PutSignedValue(VP8BitWriter* const bw, int value, int nb_bits);
+
+// Appends some bytes to the internal buffer. Data is copied.
+int VP8BitWriterAppend(VP8BitWriter* const bw,
+ const uint8_t* data, size_t size);
+
+// return approximate write position (in bits)
+static WEBP_INLINE uint64_t VP8BitWriterPos(const VP8BitWriter* const bw) {
+ return (uint64_t)(bw->pos_ + bw->run_) * 8 + 8 + bw->nb_bits_;
+}
+
+// Returns a pointer to the internal buffer.
+static WEBP_INLINE uint8_t* VP8BitWriterBuf(const VP8BitWriter* const bw) {
+ return bw->buf_;
+}
+// Returns the size of the internal buffer.
+static WEBP_INLINE size_t VP8BitWriterSize(const VP8BitWriter* const bw) {
+ return bw->pos_;
+}
+
+//------------------------------------------------------------------------------
+// VP8LBitWriter
+// TODO(vikasa): VP8LBitWriter is copied as-is from lossless code. There's scope
+// of re-using VP8BitWriter. Will evaluate once basic lossless encoder is
+// implemented.
+
+typedef struct {
+ uint8_t* buf_;
+ size_t bit_pos_;
+ size_t max_bytes_;
+
+ // After all bits are written, the caller must observe the state of
+ // error_. A value of 1 indicates that a memory allocation failure
+ // has happened during bit writing. A value of 0 indicates successful
+ // writing of bits.
+ int error_;
+} VP8LBitWriter;
+
+static WEBP_INLINE size_t VP8LBitWriterNumBytes(VP8LBitWriter* const bw) {
+ return (bw->bit_pos_ + 7) >> 3;
+}
+
+static WEBP_INLINE uint8_t* VP8LBitWriterFinish(VP8LBitWriter* const bw) {
+ return bw->buf_;
+}
+
+// Returns 0 in case of memory allocation error.
+int VP8LBitWriterInit(VP8LBitWriter* const bw, size_t expected_size);
+
+void VP8LBitWriterDestroy(VP8LBitWriter* const bw);
+
+// This function writes bits into bytes in increasing addresses, and within
+// a byte least-significant-bit first.
+//
+// The function can write up to 16 bits in one go with WriteBits
+// Example: let's assume that 3 bits (Rs below) have been written already:
+//
+// BYTE-0 BYTE+1 BYTE+2
+//
+// 0000 0RRR 0000 0000 0000 0000
+//
+// Now, we could write 5 or less bits in MSB by just sifting by 3
+// and OR'ing to BYTE-0.
+//
+// For n bits, we take the last 5 bytes, OR that with high bits in BYTE-0,
+// and locate the rest in BYTE+1 and BYTE+2.
+//
+// VP8LBitWriter's error_ flag is set in case of memory allocation error.
+void VP8LWriteBits(VP8LBitWriter* const bw, int n_bits, uint32_t bits);
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif /* WEBP_UTILS_BIT_WRITER_H_ */
diff --git a/drivers/webpold/utils/color_cache.c b/drivers/webpold/utils/color_cache.c
new file mode 100644
index 0000000000..560f81db10
--- /dev/null
+++ b/drivers/webpold/utils/color_cache.c
@@ -0,0 +1,44 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Color Cache for WebP Lossless
+//
+// Author: Jyrki Alakuijala (jyrki@google.com)
+
+#include <assert.h>
+#include <stdlib.h>
+#include "./color_cache.h"
+#include "../utils/utils.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// VP8LColorCache.
+
+int VP8LColorCacheInit(VP8LColorCache* const cc, int hash_bits) {
+ const int hash_size = 1 << hash_bits;
+ assert(cc != NULL);
+ assert(hash_bits > 0);
+ cc->colors_ = (uint32_t*)WebPSafeCalloc((uint64_t)hash_size,
+ sizeof(*cc->colors_));
+ if (cc->colors_ == NULL) return 0;
+ cc->hash_shift_ = 32 - hash_bits;
+ return 1;
+}
+
+void VP8LColorCacheClear(VP8LColorCache* const cc) {
+ if (cc != NULL) {
+ free(cc->colors_);
+ cc->colors_ = NULL;
+ }
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
diff --git a/drivers/webpold/utils/color_cache.h b/drivers/webpold/utils/color_cache.h
new file mode 100644
index 0000000000..da5e260195
--- /dev/null
+++ b/drivers/webpold/utils/color_cache.h
@@ -0,0 +1,68 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Color Cache for WebP Lossless
+//
+// Authors: Jyrki Alakuijala (jyrki@google.com)
+// Urvang Joshi (urvang@google.com)
+
+#ifndef WEBP_UTILS_COLOR_CACHE_H_
+#define WEBP_UTILS_COLOR_CACHE_H_
+
+#include "../types.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+// Main color cache struct.
+typedef struct {
+ uint32_t *colors_; // color entries
+ int hash_shift_; // Hash shift: 32 - hash_bits.
+} VP8LColorCache;
+
+static const uint32_t kHashMul = 0x1e35a7bd;
+
+static WEBP_INLINE uint32_t VP8LColorCacheLookup(
+ const VP8LColorCache* const cc, uint32_t key) {
+ assert(key <= (~0U >> cc->hash_shift_));
+ return cc->colors_[key];
+}
+
+static WEBP_INLINE void VP8LColorCacheInsert(const VP8LColorCache* const cc,
+ uint32_t argb) {
+ const uint32_t key = (kHashMul * argb) >> cc->hash_shift_;
+ cc->colors_[key] = argb;
+}
+
+static WEBP_INLINE int VP8LColorCacheGetIndex(const VP8LColorCache* const cc,
+ uint32_t argb) {
+ return (kHashMul * argb) >> cc->hash_shift_;
+}
+
+static WEBP_INLINE int VP8LColorCacheContains(const VP8LColorCache* const cc,
+ uint32_t argb) {
+ const uint32_t key = (kHashMul * argb) >> cc->hash_shift_;
+ return cc->colors_[key] == argb;
+}
+
+//------------------------------------------------------------------------------
+
+// Initializes the color cache with 'hash_bits' bits for the keys.
+// Returns false in case of memory error.
+int VP8LColorCacheInit(VP8LColorCache* const color_cache, int hash_bits);
+
+// Delete the memory associated to color cache.
+void VP8LColorCacheClear(VP8LColorCache* const color_cache);
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif // WEBP_UTILS_COLOR_CACHE_H_
diff --git a/drivers/webpold/utils/filters.c b/drivers/webpold/utils/filters.c
new file mode 100644
index 0000000000..08f52a3d20
--- /dev/null
+++ b/drivers/webpold/utils/filters.c
@@ -0,0 +1,229 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Spatial prediction using various filters
+//
+// Author: Urvang (urvang@google.com)
+
+#include "./filters.h"
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// Helpful macro.
+
+# define SANITY_CHECK(in, out) \
+ assert(in != NULL); \
+ assert(out != NULL); \
+ assert(width > 0); \
+ assert(height > 0); \
+ assert(bpp > 0); \
+ assert(stride >= width * bpp);
+
+static WEBP_INLINE void PredictLine(const uint8_t* src, const uint8_t* pred,
+ uint8_t* dst, int length, int inverse) {
+ int i;
+ if (inverse) {
+ for (i = 0; i < length; ++i) dst[i] = src[i] + pred[i];
+ } else {
+ for (i = 0; i < length; ++i) dst[i] = src[i] - pred[i];
+ }
+}
+
+//------------------------------------------------------------------------------
+// Horizontal filter.
+
+static WEBP_INLINE void DoHorizontalFilter(const uint8_t* in,
+ int width, int height, int bpp, int stride, int inverse, uint8_t* out) {
+ int h;
+ const uint8_t* preds = (inverse ? out : in);
+ SANITY_CHECK(in, out);
+
+ // Filter line-by-line.
+ for (h = 0; h < height; ++h) {
+ // Leftmost pixel is predicted from above (except for topmost scanline).
+ if (h == 0) {
+ memcpy((void*)out, (const void*)in, bpp);
+ } else {
+ PredictLine(in, preds - stride, out, bpp, inverse);
+ }
+ PredictLine(in + bpp, preds, out + bpp, bpp * (width - 1), inverse);
+ preds += stride;
+ in += stride;
+ out += stride;
+ }
+}
+
+static void HorizontalFilter(const uint8_t* data, int width, int height,
+ int bpp, int stride, uint8_t* filtered_data) {
+ DoHorizontalFilter(data, width, height, bpp, stride, 0, filtered_data);
+}
+
+static void HorizontalUnfilter(const uint8_t* data, int width, int height,
+ int bpp, int stride, uint8_t* recon_data) {
+ DoHorizontalFilter(data, width, height, bpp, stride, 1, recon_data);
+}
+
+//------------------------------------------------------------------------------
+// Vertical filter.
+
+static WEBP_INLINE void DoVerticalFilter(const uint8_t* in,
+ int width, int height, int bpp, int stride, int inverse, uint8_t* out) {
+ int h;
+ const uint8_t* preds = (inverse ? out : in);
+ SANITY_CHECK(in, out);
+
+ // Very first top-left pixel is copied.
+ memcpy((void*)out, (const void*)in, bpp);
+ // Rest of top scan-line is left-predicted.
+ PredictLine(in + bpp, preds, out + bpp, bpp * (width - 1), inverse);
+
+ // Filter line-by-line.
+ for (h = 1; h < height; ++h) {
+ in += stride;
+ out += stride;
+ PredictLine(in, preds, out, bpp * width, inverse);
+ preds += stride;
+ }
+}
+
+static void VerticalFilter(const uint8_t* data, int width, int height,
+ int bpp, int stride, uint8_t* filtered_data) {
+ DoVerticalFilter(data, width, height, bpp, stride, 0, filtered_data);
+}
+
+static void VerticalUnfilter(const uint8_t* data, int width, int height,
+ int bpp, int stride, uint8_t* recon_data) {
+ DoVerticalFilter(data, width, height, bpp, stride, 1, recon_data);
+}
+
+//------------------------------------------------------------------------------
+// Gradient filter.
+
+static WEBP_INLINE int GradientPredictor(uint8_t a, uint8_t b, uint8_t c) {
+ const int g = a + b - c;
+ return (g < 0) ? 0 : (g > 255) ? 255 : g;
+}
+
+static WEBP_INLINE
+void DoGradientFilter(const uint8_t* in, int width, int height,
+ int bpp, int stride, int inverse, uint8_t* out) {
+ const uint8_t* preds = (inverse ? out : in);
+ int h;
+ SANITY_CHECK(in, out);
+
+ // left prediction for top scan-line
+ memcpy((void*)out, (const void*)in, bpp);
+ PredictLine(in + bpp, preds, out + bpp, bpp * (width - 1), inverse);
+
+ // Filter line-by-line.
+ for (h = 1; h < height; ++h) {
+ int w;
+ preds += stride;
+ in += stride;
+ out += stride;
+ // leftmost pixel: predict from above.
+ PredictLine(in, preds - stride, out, bpp, inverse);
+ for (w = bpp; w < width * bpp; ++w) {
+ const int pred = GradientPredictor(preds[w - bpp],
+ preds[w - stride],
+ preds[w - stride - bpp]);
+ out[w] = in[w] + (inverse ? pred : -pred);
+ }
+ }
+}
+
+static void GradientFilter(const uint8_t* data, int width, int height,
+ int bpp, int stride, uint8_t* filtered_data) {
+ DoGradientFilter(data, width, height, bpp, stride, 0, filtered_data);
+}
+
+static void GradientUnfilter(const uint8_t* data, int width, int height,
+ int bpp, int stride, uint8_t* recon_data) {
+ DoGradientFilter(data, width, height, bpp, stride, 1, recon_data);
+}
+
+#undef SANITY_CHECK
+
+// -----------------------------------------------------------------------------
+// Quick estimate of a potentially interesting filter mode to try, in addition
+// to the default NONE.
+
+#define SMAX 16
+#define SDIFF(a, b) (abs((a) - (b)) >> 4) // Scoring diff, in [0..SMAX)
+
+WEBP_FILTER_TYPE EstimateBestFilter(const uint8_t* data,
+ int width, int height, int stride) {
+ int i, j;
+ int bins[WEBP_FILTER_LAST][SMAX];
+ memset(bins, 0, sizeof(bins));
+ // We only sample every other pixels. That's enough.
+ for (j = 2; j < height - 1; j += 2) {
+ const uint8_t* const p = data + j * stride;
+ int mean = p[0];
+ for (i = 2; i < width - 1; i += 2) {
+ const int diff0 = SDIFF(p[i], mean);
+ const int diff1 = SDIFF(p[i], p[i - 1]);
+ const int diff2 = SDIFF(p[i], p[i - width]);
+ const int grad_pred =
+ GradientPredictor(p[i - 1], p[i - width], p[i - width - 1]);
+ const int diff3 = SDIFF(p[i], grad_pred);
+ bins[WEBP_FILTER_NONE][diff0] = 1;
+ bins[WEBP_FILTER_HORIZONTAL][diff1] = 1;
+ bins[WEBP_FILTER_VERTICAL][diff2] = 1;
+ bins[WEBP_FILTER_GRADIENT][diff3] = 1;
+ mean = (3 * mean + p[i] + 2) >> 2;
+ }
+ }
+ {
+ WEBP_FILTER_TYPE filter, best_filter = WEBP_FILTER_NONE;
+ int best_score = 0x7fffffff;
+ for (filter = WEBP_FILTER_NONE; filter < WEBP_FILTER_LAST; ++filter) {
+ int score = 0;
+ for (i = 0; i < SMAX; ++i) {
+ if (bins[filter][i] > 0) {
+ score += i;
+ }
+ }
+ if (score < best_score) {
+ best_score = score;
+ best_filter = filter;
+ }
+ }
+ return best_filter;
+ }
+}
+
+#undef SMAX
+#undef SDIFF
+
+//------------------------------------------------------------------------------
+
+const WebPFilterFunc WebPFilters[WEBP_FILTER_LAST] = {
+ NULL, // WEBP_FILTER_NONE
+ HorizontalFilter, // WEBP_FILTER_HORIZONTAL
+ VerticalFilter, // WEBP_FILTER_VERTICAL
+ GradientFilter // WEBP_FILTER_GRADIENT
+};
+
+const WebPFilterFunc WebPUnfilters[WEBP_FILTER_LAST] = {
+ NULL, // WEBP_FILTER_NONE
+ HorizontalUnfilter, // WEBP_FILTER_HORIZONTAL
+ VerticalUnfilter, // WEBP_FILTER_VERTICAL
+ GradientUnfilter // WEBP_FILTER_GRADIENT
+};
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/utils/filters.h b/drivers/webpold/utils/filters.h
new file mode 100644
index 0000000000..db886be29a
--- /dev/null
+++ b/drivers/webpold/utils/filters.h
@@ -0,0 +1,54 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Spatial prediction using various filters
+//
+// Author: Urvang (urvang@google.com)
+
+#ifndef WEBP_UTILS_FILTERS_H_
+#define WEBP_UTILS_FILTERS_H_
+
+#include "../types.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+// Filters.
+typedef enum {
+ WEBP_FILTER_NONE = 0,
+ WEBP_FILTER_HORIZONTAL,
+ WEBP_FILTER_VERTICAL,
+ WEBP_FILTER_GRADIENT,
+ WEBP_FILTER_LAST = WEBP_FILTER_GRADIENT + 1, // end marker
+ WEBP_FILTER_BEST,
+ WEBP_FILTER_FAST
+} WEBP_FILTER_TYPE;
+
+typedef void (*WebPFilterFunc)(const uint8_t* in, int width, int height,
+ int bpp, int stride, uint8_t* out);
+
+// Filter the given data using the given predictor.
+// 'in' corresponds to a 2-dimensional pixel array of size (stride * height)
+// in raster order.
+// 'bpp' is number of bytes per pixel, and
+// 'stride' is number of bytes per scan line (with possible padding).
+// 'out' should be pre-allocated.
+extern const WebPFilterFunc WebPFilters[WEBP_FILTER_LAST];
+
+// Reconstruct the original data from the given filtered data.
+extern const WebPFilterFunc WebPUnfilters[WEBP_FILTER_LAST];
+
+// Fast estimate of a potentially good filter.
+extern WEBP_FILTER_TYPE EstimateBestFilter(const uint8_t* data,
+ int width, int height, int stride);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif /* WEBP_UTILS_FILTERS_H_ */
diff --git a/drivers/webpold/utils/huffman.c b/drivers/webpold/utils/huffman.c
new file mode 100644
index 0000000000..1cc1cfd355
--- /dev/null
+++ b/drivers/webpold/utils/huffman.c
@@ -0,0 +1,238 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Utilities for building and looking up Huffman trees.
+//
+// Author: Urvang Joshi (urvang@google.com)
+
+#include <assert.h>
+#include <stdlib.h>
+#include "./huffman.h"
+#include "../utils/utils.h"
+#include "../format_constants.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define NON_EXISTENT_SYMBOL (-1)
+
+static void TreeNodeInit(HuffmanTreeNode* const node) {
+ node->children_ = -1; // means: 'unassigned so far'
+}
+
+static int NodeIsEmpty(const HuffmanTreeNode* const node) {
+ return (node->children_ < 0);
+}
+
+static int IsFull(const HuffmanTree* const tree) {
+ return (tree->num_nodes_ == tree->max_nodes_);
+}
+
+static void AssignChildren(HuffmanTree* const tree,
+ HuffmanTreeNode* const node) {
+ HuffmanTreeNode* const children = tree->root_ + tree->num_nodes_;
+ node->children_ = (int)(children - node);
+ assert(children - node == (int)(children - node));
+ tree->num_nodes_ += 2;
+ TreeNodeInit(children + 0);
+ TreeNodeInit(children + 1);
+}
+
+static int TreeInit(HuffmanTree* const tree, int num_leaves) {
+ assert(tree != NULL);
+ if (num_leaves == 0) return 0;
+ // We allocate maximum possible nodes in the tree at once.
+ // Note that a Huffman tree is a full binary tree; and in a full binary tree
+ // with L leaves, the total number of nodes N = 2 * L - 1.
+ tree->max_nodes_ = 2 * num_leaves - 1;
+ tree->root_ = (HuffmanTreeNode*)WebPSafeMalloc((uint64_t)tree->max_nodes_,
+ sizeof(*tree->root_));
+ if (tree->root_ == NULL) return 0;
+ TreeNodeInit(tree->root_); // Initialize root.
+ tree->num_nodes_ = 1;
+ return 1;
+}
+
+void HuffmanTreeRelease(HuffmanTree* const tree) {
+ if (tree != NULL) {
+ free(tree->root_);
+ tree->root_ = NULL;
+ tree->max_nodes_ = 0;
+ tree->num_nodes_ = 0;
+ }
+}
+
+int HuffmanCodeLengthsToCodes(const int* const code_lengths,
+ int code_lengths_size, int* const huff_codes) {
+ int symbol;
+ int code_len;
+ int code_length_hist[MAX_ALLOWED_CODE_LENGTH + 1] = { 0 };
+ int curr_code;
+ int next_codes[MAX_ALLOWED_CODE_LENGTH + 1] = { 0 };
+ int max_code_length = 0;
+
+ assert(code_lengths != NULL);
+ assert(code_lengths_size > 0);
+ assert(huff_codes != NULL);
+
+ // Calculate max code length.
+ for (symbol = 0; symbol < code_lengths_size; ++symbol) {
+ if (code_lengths[symbol] > max_code_length) {
+ max_code_length = code_lengths[symbol];
+ }
+ }
+ if (max_code_length > MAX_ALLOWED_CODE_LENGTH) return 0;
+
+ // Calculate code length histogram.
+ for (symbol = 0; symbol < code_lengths_size; ++symbol) {
+ ++code_length_hist[code_lengths[symbol]];
+ }
+ code_length_hist[0] = 0;
+
+ // Calculate the initial values of 'next_codes' for each code length.
+ // next_codes[code_len] denotes the code to be assigned to the next symbol
+ // of code length 'code_len'.
+ curr_code = 0;
+ next_codes[0] = -1; // Unused, as code length = 0 implies code doesn't exist.
+ for (code_len = 1; code_len <= max_code_length; ++code_len) {
+ curr_code = (curr_code + code_length_hist[code_len - 1]) << 1;
+ next_codes[code_len] = curr_code;
+ }
+
+ // Get symbols.
+ for (symbol = 0; symbol < code_lengths_size; ++symbol) {
+ if (code_lengths[symbol] > 0) {
+ huff_codes[symbol] = next_codes[code_lengths[symbol]]++;
+ } else {
+ huff_codes[symbol] = NON_EXISTENT_SYMBOL;
+ }
+ }
+ return 1;
+}
+
+static int TreeAddSymbol(HuffmanTree* const tree,
+ int symbol, int code, int code_length) {
+ HuffmanTreeNode* node = tree->root_;
+ const HuffmanTreeNode* const max_node = tree->root_ + tree->max_nodes_;
+ while (code_length-- > 0) {
+ if (node >= max_node) {
+ return 0;
+ }
+ if (NodeIsEmpty(node)) {
+ if (IsFull(tree)) return 0; // error: too many symbols.
+ AssignChildren(tree, node);
+ } else if (HuffmanTreeNodeIsLeaf(node)) {
+ return 0; // leaf is already occupied.
+ }
+ node += node->children_ + ((code >> code_length) & 1);
+ }
+ if (NodeIsEmpty(node)) {
+ node->children_ = 0; // turn newly created node into a leaf.
+ } else if (!HuffmanTreeNodeIsLeaf(node)) {
+ return 0; // trying to assign a symbol to already used code.
+ }
+ node->symbol_ = symbol; // Add symbol in this node.
+ return 1;
+}
+
+int HuffmanTreeBuildImplicit(HuffmanTree* const tree,
+ const int* const code_lengths,
+ int code_lengths_size) {
+ int symbol;
+ int num_symbols = 0;
+ int root_symbol = 0;
+
+ assert(tree != NULL);
+ assert(code_lengths != NULL);
+
+ // Find out number of symbols and the root symbol.
+ for (symbol = 0; symbol < code_lengths_size; ++symbol) {
+ if (code_lengths[symbol] > 0) {
+ // Note: code length = 0 indicates non-existent symbol.
+ ++num_symbols;
+ root_symbol = symbol;
+ }
+ }
+
+ // Initialize the tree. Will fail for num_symbols = 0
+ if (!TreeInit(tree, num_symbols)) return 0;
+
+ // Build tree.
+ if (num_symbols == 1) { // Trivial case.
+ const int max_symbol = code_lengths_size;
+ if (root_symbol < 0 || root_symbol >= max_symbol) {
+ HuffmanTreeRelease(tree);
+ return 0;
+ }
+ return TreeAddSymbol(tree, root_symbol, 0, 0);
+ } else { // Normal case.
+ int ok = 0;
+
+ // Get Huffman codes from the code lengths.
+ int* const codes =
+ (int*)WebPSafeMalloc((uint64_t)code_lengths_size, sizeof(*codes));
+ if (codes == NULL) goto End;
+
+ if (!HuffmanCodeLengthsToCodes(code_lengths, code_lengths_size, codes)) {
+ goto End;
+ }
+
+ // Add symbols one-by-one.
+ for (symbol = 0; symbol < code_lengths_size; ++symbol) {
+ if (code_lengths[symbol] > 0) {
+ if (!TreeAddSymbol(tree, symbol, codes[symbol], code_lengths[symbol])) {
+ goto End;
+ }
+ }
+ }
+ ok = 1;
+ End:
+ free(codes);
+ ok = ok && IsFull(tree);
+ if (!ok) HuffmanTreeRelease(tree);
+ return ok;
+ }
+}
+
+int HuffmanTreeBuildExplicit(HuffmanTree* const tree,
+ const int* const code_lengths,
+ const int* const codes,
+ const int* const symbols, int max_symbol,
+ int num_symbols) {
+ int ok = 0;
+ int i;
+
+ assert(tree != NULL);
+ assert(code_lengths != NULL);
+ assert(codes != NULL);
+ assert(symbols != NULL);
+
+ // Initialize the tree. Will fail if num_symbols = 0.
+ if (!TreeInit(tree, num_symbols)) return 0;
+
+ // Add symbols one-by-one.
+ for (i = 0; i < num_symbols; ++i) {
+ if (codes[i] != NON_EXISTENT_SYMBOL) {
+ if (symbols[i] < 0 || symbols[i] >= max_symbol) {
+ goto End;
+ }
+ if (!TreeAddSymbol(tree, symbols[i], codes[i], code_lengths[i])) {
+ goto End;
+ }
+ }
+ }
+ ok = 1;
+ End:
+ ok = ok && IsFull(tree);
+ if (!ok) HuffmanTreeRelease(tree);
+ return ok;
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/utils/huffman.h b/drivers/webpold/utils/huffman.h
new file mode 100644
index 0000000000..f16447e649
--- /dev/null
+++ b/drivers/webpold/utils/huffman.h
@@ -0,0 +1,78 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Utilities for building and looking up Huffman trees.
+//
+// Author: Urvang Joshi (urvang@google.com)
+
+#ifndef WEBP_UTILS_HUFFMAN_H_
+#define WEBP_UTILS_HUFFMAN_H_
+
+#include <assert.h>
+#include "../types.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+// A node of a Huffman tree.
+typedef struct {
+ int symbol_;
+ int children_; // delta offset to both children (contiguous) or 0 if leaf.
+} HuffmanTreeNode;
+
+// Huffman Tree.
+typedef struct HuffmanTree HuffmanTree;
+struct HuffmanTree {
+ HuffmanTreeNode* root_; // all the nodes, starting at root.
+ int max_nodes_; // max number of nodes
+ int num_nodes_; // number of currently occupied nodes
+};
+
+// Returns true if the given node is a leaf of the Huffman tree.
+static WEBP_INLINE int HuffmanTreeNodeIsLeaf(
+ const HuffmanTreeNode* const node) {
+ return (node->children_ == 0);
+}
+
+// Go down one level. Most critical function. 'right_child' must be 0 or 1.
+static WEBP_INLINE const HuffmanTreeNode* HuffmanTreeNextNode(
+ const HuffmanTreeNode* node, int right_child) {
+ return node + node->children_ + right_child;
+}
+
+// Releases the nodes of the Huffman tree.
+// Note: It does NOT free 'tree' itself.
+void HuffmanTreeRelease(HuffmanTree* const tree);
+
+// Builds Huffman tree assuming code lengths are implicitly in symbol order.
+// Returns false in case of error (invalid tree or memory error).
+int HuffmanTreeBuildImplicit(HuffmanTree* const tree,
+ const int* const code_lengths,
+ int code_lengths_size);
+
+// Build a Huffman tree with explicitly given lists of code lengths, codes
+// and symbols. Verifies that all symbols added are smaller than max_symbol.
+// Returns false in case of an invalid symbol, invalid tree or memory error.
+int HuffmanTreeBuildExplicit(HuffmanTree* const tree,
+ const int* const code_lengths,
+ const int* const codes,
+ const int* const symbols, int max_symbol,
+ int num_symbols);
+
+// Utility: converts Huffman code lengths to corresponding Huffman codes.
+// 'huff_codes' should be pre-allocated.
+// Returns false in case of error (memory allocation, invalid codes).
+int HuffmanCodeLengthsToCodes(const int* const code_lengths,
+ int code_lengths_size, int* const huff_codes);
+
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif // WEBP_UTILS_HUFFMAN_H_
diff --git a/drivers/webpold/utils/huffman_encode.c b/drivers/webpold/utils/huffman_encode.c
new file mode 100644
index 0000000000..e172b10a85
--- /dev/null
+++ b/drivers/webpold/utils/huffman_encode.c
@@ -0,0 +1,439 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Author: Jyrki Alakuijala (jyrki@google.com)
+//
+// Entropy encoding (Huffman) for webp lossless.
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include "./huffman_encode.h"
+#include "../utils/utils.h"
+#include "../format_constants.h"
+
+// -----------------------------------------------------------------------------
+// Util function to optimize the symbol map for RLE coding
+
+// Heuristics for selecting the stride ranges to collapse.
+static int ValuesShouldBeCollapsedToStrideAverage(int a, int b) {
+ return abs(a - b) < 4;
+}
+
+// Change the population counts in a way that the consequent
+// Hufmann tree compression, especially its RLE-part, give smaller output.
+static int OptimizeHuffmanForRle(int length, int* const counts) {
+ uint8_t* good_for_rle;
+ // 1) Let's make the Huffman code more compatible with rle encoding.
+ int i;
+ for (; length >= 0; --length) {
+ if (length == 0) {
+ return 1; // All zeros.
+ }
+ if (counts[length - 1] != 0) {
+ // Now counts[0..length - 1] does not have trailing zeros.
+ break;
+ }
+ }
+ // 2) Let's mark all population counts that already can be encoded
+ // with an rle code.
+ good_for_rle = (uint8_t*)calloc(length, 1);
+ if (good_for_rle == NULL) {
+ return 0;
+ }
+ {
+ // Let's not spoil any of the existing good rle codes.
+ // Mark any seq of 0's that is longer as 5 as a good_for_rle.
+ // Mark any seq of non-0's that is longer as 7 as a good_for_rle.
+ int symbol = counts[0];
+ int stride = 0;
+ for (i = 0; i < length + 1; ++i) {
+ if (i == length || counts[i] != symbol) {
+ if ((symbol == 0 && stride >= 5) ||
+ (symbol != 0 && stride >= 7)) {
+ int k;
+ for (k = 0; k < stride; ++k) {
+ good_for_rle[i - k - 1] = 1;
+ }
+ }
+ stride = 1;
+ if (i != length) {
+ symbol = counts[i];
+ }
+ } else {
+ ++stride;
+ }
+ }
+ }
+ // 3) Let's replace those population counts that lead to more rle codes.
+ {
+ int stride = 0;
+ int limit = counts[0];
+ int sum = 0;
+ for (i = 0; i < length + 1; ++i) {
+ if (i == length || good_for_rle[i] ||
+ (i != 0 && good_for_rle[i - 1]) ||
+ !ValuesShouldBeCollapsedToStrideAverage(counts[i], limit)) {
+ if (stride >= 4 || (stride >= 3 && sum == 0)) {
+ int k;
+ // The stride must end, collapse what we have, if we have enough (4).
+ int count = (sum + stride / 2) / stride;
+ if (count < 1) {
+ count = 1;
+ }
+ if (sum == 0) {
+ // Don't make an all zeros stride to be upgraded to ones.
+ count = 0;
+ }
+ for (k = 0; k < stride; ++k) {
+ // We don't want to change value at counts[i],
+ // that is already belonging to the next stride. Thus - 1.
+ counts[i - k - 1] = count;
+ }
+ }
+ stride = 0;
+ sum = 0;
+ if (i < length - 3) {
+ // All interesting strides have a count of at least 4,
+ // at least when non-zeros.
+ limit = (counts[i] + counts[i + 1] +
+ counts[i + 2] + counts[i + 3] + 2) / 4;
+ } else if (i < length) {
+ limit = counts[i];
+ } else {
+ limit = 0;
+ }
+ }
+ ++stride;
+ if (i != length) {
+ sum += counts[i];
+ if (stride >= 4) {
+ limit = (sum + stride / 2) / stride;
+ }
+ }
+ }
+ }
+ free(good_for_rle);
+ return 1;
+}
+
+typedef struct {
+ int total_count_;
+ int value_;
+ int pool_index_left_;
+ int pool_index_right_;
+} HuffmanTree;
+
+// A comparer function for two Huffman trees: sorts first by 'total count'
+// (more comes first), and then by 'value' (more comes first).
+static int CompareHuffmanTrees(const void* ptr1, const void* ptr2) {
+ const HuffmanTree* const t1 = (const HuffmanTree*)ptr1;
+ const HuffmanTree* const t2 = (const HuffmanTree*)ptr2;
+ if (t1->total_count_ > t2->total_count_) {
+ return -1;
+ } else if (t1->total_count_ < t2->total_count_) {
+ return 1;
+ } else {
+ if (t1->value_ < t2->value_) {
+ return -1;
+ }
+ if (t1->value_ > t2->value_) {
+ return 1;
+ }
+ return 0;
+ }
+}
+
+static void SetBitDepths(const HuffmanTree* const tree,
+ const HuffmanTree* const pool,
+ uint8_t* const bit_depths, int level) {
+ if (tree->pool_index_left_ >= 0) {
+ SetBitDepths(&pool[tree->pool_index_left_], pool, bit_depths, level + 1);
+ SetBitDepths(&pool[tree->pool_index_right_], pool, bit_depths, level + 1);
+ } else {
+ bit_depths[tree->value_] = level;
+ }
+}
+
+// Create an optimal Huffman tree.
+//
+// (data,length): population counts.
+// tree_limit: maximum bit depth (inclusive) of the codes.
+// bit_depths[]: how many bits are used for the symbol.
+//
+// Returns 0 when an error has occurred.
+//
+// The catch here is that the tree cannot be arbitrarily deep
+//
+// count_limit is the value that is to be faked as the minimum value
+// and this minimum value is raised until the tree matches the
+// maximum length requirement.
+//
+// This algorithm is not of excellent performance for very long data blocks,
+// especially when population counts are longer than 2**tree_limit, but
+// we are not planning to use this with extremely long blocks.
+//
+// See http://en.wikipedia.org/wiki/Huffman_coding
+static int GenerateOptimalTree(const int* const histogram, int histogram_size,
+ int tree_depth_limit,
+ uint8_t* const bit_depths) {
+ int count_min;
+ HuffmanTree* tree_pool;
+ HuffmanTree* tree;
+ int tree_size_orig = 0;
+ int i;
+
+ for (i = 0; i < histogram_size; ++i) {
+ if (histogram[i] != 0) {
+ ++tree_size_orig;
+ }
+ }
+
+ // 3 * tree_size is enough to cover all the nodes representing a
+ // population and all the inserted nodes combining two existing nodes.
+ // The tree pool needs 2 * (tree_size_orig - 1) entities, and the
+ // tree needs exactly tree_size_orig entities.
+ tree = (HuffmanTree*)WebPSafeMalloc(3ULL * tree_size_orig, sizeof(*tree));
+ if (tree == NULL) return 0;
+ tree_pool = tree + tree_size_orig;
+
+ // For block sizes with less than 64k symbols we never need to do a
+ // second iteration of this loop.
+ // If we actually start running inside this loop a lot, we would perhaps
+ // be better off with the Katajainen algorithm.
+ assert(tree_size_orig <= (1 << (tree_depth_limit - 1)));
+ for (count_min = 1; ; count_min *= 2) {
+ int tree_size = tree_size_orig;
+ // We need to pack the Huffman tree in tree_depth_limit bits.
+ // So, we try by faking histogram entries to be at least 'count_min'.
+ int idx = 0;
+ int j;
+ for (j = 0; j < histogram_size; ++j) {
+ if (histogram[j] != 0) {
+ const int count =
+ (histogram[j] < count_min) ? count_min : histogram[j];
+ tree[idx].total_count_ = count;
+ tree[idx].value_ = j;
+ tree[idx].pool_index_left_ = -1;
+ tree[idx].pool_index_right_ = -1;
+ ++idx;
+ }
+ }
+
+ // Build the Huffman tree.
+ qsort(tree, tree_size, sizeof(*tree), CompareHuffmanTrees);
+
+ if (tree_size > 1) { // Normal case.
+ int tree_pool_size = 0;
+ while (tree_size > 1) { // Finish when we have only one root.
+ int count;
+ tree_pool[tree_pool_size++] = tree[tree_size - 1];
+ tree_pool[tree_pool_size++] = tree[tree_size - 2];
+ count = tree_pool[tree_pool_size - 1].total_count_ +
+ tree_pool[tree_pool_size - 2].total_count_;
+ tree_size -= 2;
+ {
+ // Search for the insertion point.
+ int k;
+ for (k = 0; k < tree_size; ++k) {
+ if (tree[k].total_count_ <= count) {
+ break;
+ }
+ }
+ memmove(tree + (k + 1), tree + k, (tree_size - k) * sizeof(*tree));
+ tree[k].total_count_ = count;
+ tree[k].value_ = -1;
+
+ tree[k].pool_index_left_ = tree_pool_size - 1;
+ tree[k].pool_index_right_ = tree_pool_size - 2;
+ tree_size = tree_size + 1;
+ }
+ }
+ SetBitDepths(&tree[0], tree_pool, bit_depths, 0);
+ } else if (tree_size == 1) { // Trivial case: only one element.
+ bit_depths[tree[0].value_] = 1;
+ }
+
+ {
+ // Test if this Huffman tree satisfies our 'tree_depth_limit' criteria.
+ int max_depth = bit_depths[0];
+ for (j = 1; j < histogram_size; ++j) {
+ if (max_depth < bit_depths[j]) {
+ max_depth = bit_depths[j];
+ }
+ }
+ if (max_depth <= tree_depth_limit) {
+ break;
+ }
+ }
+ }
+ free(tree);
+ return 1;
+}
+
+// -----------------------------------------------------------------------------
+// Coding of the Huffman tree values
+
+static HuffmanTreeToken* CodeRepeatedValues(int repetitions,
+ HuffmanTreeToken* tokens,
+ int value, int prev_value) {
+ assert(value <= MAX_ALLOWED_CODE_LENGTH);
+ if (value != prev_value) {
+ tokens->code = value;
+ tokens->extra_bits = 0;
+ ++tokens;
+ --repetitions;
+ }
+ while (repetitions >= 1) {
+ if (repetitions < 3) {
+ int i;
+ for (i = 0; i < repetitions; ++i) {
+ tokens->code = value;
+ tokens->extra_bits = 0;
+ ++tokens;
+ }
+ break;
+ } else if (repetitions < 7) {
+ tokens->code = 16;
+ tokens->extra_bits = repetitions - 3;
+ ++tokens;
+ break;
+ } else {
+ tokens->code = 16;
+ tokens->extra_bits = 3;
+ ++tokens;
+ repetitions -= 6;
+ }
+ }
+ return tokens;
+}
+
+static HuffmanTreeToken* CodeRepeatedZeros(int repetitions,
+ HuffmanTreeToken* tokens) {
+ while (repetitions >= 1) {
+ if (repetitions < 3) {
+ int i;
+ for (i = 0; i < repetitions; ++i) {
+ tokens->code = 0; // 0-value
+ tokens->extra_bits = 0;
+ ++tokens;
+ }
+ break;
+ } else if (repetitions < 11) {
+ tokens->code = 17;
+ tokens->extra_bits = repetitions - 3;
+ ++tokens;
+ break;
+ } else if (repetitions < 139) {
+ tokens->code = 18;
+ tokens->extra_bits = repetitions - 11;
+ ++tokens;
+ break;
+ } else {
+ tokens->code = 18;
+ tokens->extra_bits = 0x7f; // 138 repeated 0s
+ ++tokens;
+ repetitions -= 138;
+ }
+ }
+ return tokens;
+}
+
+int VP8LCreateCompressedHuffmanTree(const HuffmanTreeCode* const tree,
+ HuffmanTreeToken* tokens, int max_tokens) {
+ HuffmanTreeToken* const starting_token = tokens;
+ HuffmanTreeToken* const ending_token = tokens + max_tokens;
+ const int depth_size = tree->num_symbols;
+ int prev_value = 8; // 8 is the initial value for rle.
+ int i = 0;
+ assert(tokens != NULL);
+ while (i < depth_size) {
+ const int value = tree->code_lengths[i];
+ int k = i + 1;
+ int runs;
+ while (k < depth_size && tree->code_lengths[k] == value) ++k;
+ runs = k - i;
+ if (value == 0) {
+ tokens = CodeRepeatedZeros(runs, tokens);
+ } else {
+ tokens = CodeRepeatedValues(runs, tokens, value, prev_value);
+ prev_value = value;
+ }
+ i += runs;
+ assert(tokens <= ending_token);
+ }
+ (void)ending_token; // suppress 'unused variable' warning
+ return (int)(tokens - starting_token);
+}
+
+// -----------------------------------------------------------------------------
+
+// Pre-reversed 4-bit values.
+static const uint8_t kReversedBits[16] = {
+ 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe,
+ 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf
+};
+
+static uint32_t ReverseBits(int num_bits, uint32_t bits) {
+ uint32_t retval = 0;
+ int i = 0;
+ while (i < num_bits) {
+ i += 4;
+ retval |= kReversedBits[bits & 0xf] << (MAX_ALLOWED_CODE_LENGTH + 1 - i);
+ bits >>= 4;
+ }
+ retval >>= (MAX_ALLOWED_CODE_LENGTH + 1 - num_bits);
+ return retval;
+}
+
+// Get the actual bit values for a tree of bit depths.
+static void ConvertBitDepthsToSymbols(HuffmanTreeCode* const tree) {
+ // 0 bit-depth means that the symbol does not exist.
+ int i;
+ int len;
+ uint32_t next_code[MAX_ALLOWED_CODE_LENGTH + 1];
+ int depth_count[MAX_ALLOWED_CODE_LENGTH + 1] = { 0 };
+
+ assert(tree != NULL);
+ len = tree->num_symbols;
+ for (i = 0; i < len; ++i) {
+ const int code_length = tree->code_lengths[i];
+ assert(code_length <= MAX_ALLOWED_CODE_LENGTH);
+ ++depth_count[code_length];
+ }
+ depth_count[0] = 0; // ignore unused symbol
+ next_code[0] = 0;
+ {
+ uint32_t code = 0;
+ for (i = 1; i <= MAX_ALLOWED_CODE_LENGTH; ++i) {
+ code = (code + depth_count[i - 1]) << 1;
+ next_code[i] = code;
+ }
+ }
+ for (i = 0; i < len; ++i) {
+ const int code_length = tree->code_lengths[i];
+ tree->codes[i] = ReverseBits(code_length, next_code[code_length]++);
+ }
+}
+
+// -----------------------------------------------------------------------------
+// Main entry point
+
+int VP8LCreateHuffmanTree(int* const histogram, int tree_depth_limit,
+ HuffmanTreeCode* const tree) {
+ const int num_symbols = tree->num_symbols;
+ if (!OptimizeHuffmanForRle(num_symbols, histogram)) {
+ return 0;
+ }
+ if (!GenerateOptimalTree(histogram, num_symbols,
+ tree_depth_limit, tree->code_lengths)) {
+ return 0;
+ }
+ // Create the actual bit codes for the bit lengths.
+ ConvertBitDepthsToSymbols(tree);
+ return 1;
+}
diff --git a/drivers/webpold/utils/huffman_encode.h b/drivers/webpold/utils/huffman_encode.h
new file mode 100644
index 0000000000..7f4aedc102
--- /dev/null
+++ b/drivers/webpold/utils/huffman_encode.h
@@ -0,0 +1,47 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Author: Jyrki Alakuijala (jyrki@google.com)
+//
+// Entropy encoding (Huffman) for webp lossless
+
+#ifndef WEBP_UTILS_HUFFMAN_ENCODE_H_
+#define WEBP_UTILS_HUFFMAN_ENCODE_H_
+
+#include "../types.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+// Struct for holding the tree header in coded form.
+typedef struct {
+ uint8_t code; // value (0..15) or escape code (16,17,18)
+ uint8_t extra_bits; // extra bits for escape codes
+} HuffmanTreeToken;
+
+// Struct to represent the tree codes (depth and bits array).
+typedef struct {
+ int num_symbols; // Number of symbols.
+ uint8_t* code_lengths; // Code lengths of the symbols.
+ uint16_t* codes; // Symbol Codes.
+} HuffmanTreeCode;
+
+// Turn the Huffman tree into a token sequence.
+// Returns the number of tokens used.
+int VP8LCreateCompressedHuffmanTree(const HuffmanTreeCode* const tree,
+ HuffmanTreeToken* tokens, int max_tokens);
+
+// Create an optimized tree, and tokenize it.
+int VP8LCreateHuffmanTree(int* const histogram, int tree_depth_limit,
+ HuffmanTreeCode* const tree);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+}
+#endif
+
+#endif // WEBP_UTILS_HUFFMAN_ENCODE_H_
diff --git a/drivers/webpold/utils/quant_levels.c b/drivers/webpold/utils/quant_levels.c
new file mode 100644
index 0000000000..f6884392aa
--- /dev/null
+++ b/drivers/webpold/utils/quant_levels.c
@@ -0,0 +1,154 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Quantize levels for specified number of quantization-levels ([2, 256]).
+// Min and max values are preserved (usual 0 and 255 for alpha plane).
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <assert.h>
+
+#include "./quant_levels.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define NUM_SYMBOLS 256
+
+#define MAX_ITER 6 // Maximum number of convergence steps.
+#define ERROR_THRESHOLD 1e-4 // MSE stopping criterion.
+
+// -----------------------------------------------------------------------------
+// Quantize levels.
+
+int QuantizeLevels(uint8_t* const data, int width, int height,
+ int num_levels, uint64_t* const sse) {
+ int freq[NUM_SYMBOLS] = { 0 };
+ int q_level[NUM_SYMBOLS] = { 0 };
+ double inv_q_level[NUM_SYMBOLS] = { 0 };
+ int min_s = 255, max_s = 0;
+ const size_t data_size = height * width;
+ int i, num_levels_in, iter;
+ double last_err = 1.e38, err = 0.;
+ const double err_threshold = ERROR_THRESHOLD * data_size;
+
+ if (data == NULL) {
+ return 0;
+ }
+
+ if (width <= 0 || height <= 0) {
+ return 0;
+ }
+
+ if (num_levels < 2 || num_levels > 256) {
+ return 0;
+ }
+
+ {
+ size_t n;
+ num_levels_in = 0;
+ for (n = 0; n < data_size; ++n) {
+ num_levels_in += (freq[data[n]] == 0);
+ if (min_s > data[n]) min_s = data[n];
+ if (max_s < data[n]) max_s = data[n];
+ ++freq[data[n]];
+ }
+ }
+
+ if (num_levels_in <= num_levels) goto End; // nothing to do!
+
+ // Start with uniformly spread centroids.
+ for (i = 0; i < num_levels; ++i) {
+ inv_q_level[i] = min_s + (double)(max_s - min_s) * i / (num_levels - 1);
+ }
+
+ // Fixed values. Won't be changed.
+ q_level[min_s] = 0;
+ q_level[max_s] = num_levels - 1;
+ assert(inv_q_level[0] == min_s);
+ assert(inv_q_level[num_levels - 1] == max_s);
+
+ // k-Means iterations.
+ for (iter = 0; iter < MAX_ITER; ++iter) {
+ double q_sum[NUM_SYMBOLS] = { 0 };
+ double q_count[NUM_SYMBOLS] = { 0 };
+ int s, slot = 0;
+
+ // Assign classes to representatives.
+ for (s = min_s; s <= max_s; ++s) {
+ // Keep track of the nearest neighbour 'slot'
+ while (slot < num_levels - 1 &&
+ 2 * s > inv_q_level[slot] + inv_q_level[slot + 1]) {
+ ++slot;
+ }
+ if (freq[s] > 0) {
+ q_sum[slot] += s * freq[s];
+ q_count[slot] += freq[s];
+ }
+ q_level[s] = slot;
+ }
+
+ // Assign new representatives to classes.
+ if (num_levels > 2) {
+ for (slot = 1; slot < num_levels - 1; ++slot) {
+ const double count = q_count[slot];
+ if (count > 0.) {
+ inv_q_level[slot] = q_sum[slot] / count;
+ }
+ }
+ }
+
+ // Compute convergence error.
+ err = 0.;
+ for (s = min_s; s <= max_s; ++s) {
+ const double error = s - inv_q_level[q_level[s]];
+ err += freq[s] * error * error;
+ }
+
+ // Check for convergence: we stop as soon as the error is no
+ // longer improving.
+ if (last_err - err < err_threshold) break;
+ last_err = err;
+ }
+
+ // Remap the alpha plane to quantized values.
+ {
+ // double->int rounding operation can be costly, so we do it
+ // once for all before remapping. We also perform the data[] -> slot
+ // mapping, while at it (avoid one indirection in the final loop).
+ uint8_t map[NUM_SYMBOLS];
+ int s;
+ size_t n;
+ for (s = min_s; s <= max_s; ++s) {
+ const int slot = q_level[s];
+ map[s] = (uint8_t)(inv_q_level[slot] + .5);
+ }
+ // Final pass.
+ for (n = 0; n < data_size; ++n) {
+ data[n] = map[data[n]];
+ }
+ }
+ End:
+ // Store sum of squared error if needed.
+ if (sse != NULL) *sse = (uint64_t)err;
+
+ return 1;
+}
+
+int DequantizeLevels(uint8_t* const data, int width, int height) {
+ if (data == NULL || width <= 0 || height <= 0) return 0;
+ // TODO(skal): implement gradient smoothing.
+ (void)data;
+ (void)width;
+ (void)height;
+ return 1;
+}
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/utils/quant_levels.h b/drivers/webpold/utils/quant_levels.h
new file mode 100644
index 0000000000..4f165fd230
--- /dev/null
+++ b/drivers/webpold/utils/quant_levels.h
@@ -0,0 +1,39 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Alpha plane quantization utility
+//
+// Author: Vikas Arora (vikasa@google.com)
+
+#ifndef WEBP_UTILS_QUANT_LEVELS_H_
+#define WEBP_UTILS_QUANT_LEVELS_H_
+
+#include <stdlib.h>
+
+#include "../types.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+// Replace the input 'data' of size 'width'x'height' with 'num-levels'
+// quantized values. If not NULL, 'sse' will contain the sum of squared error.
+// Valid range for 'num_levels' is [2, 256].
+// Returns false in case of error (data is NULL, or parameters are invalid).
+int QuantizeLevels(uint8_t* const data, int width, int height, int num_levels,
+ uint64_t* const sse);
+
+// Apply post-processing to input 'data' of size 'width'x'height' assuming
+// that the source was quantized to a reduced number of levels.
+// Returns false in case of error (data is NULL, invalid parameters, ...).
+int DequantizeLevels(uint8_t* const data, int width, int height);
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif /* WEBP_UTILS_QUANT_LEVELS_H_ */
diff --git a/drivers/webpold/utils/rescaler.c b/drivers/webpold/utils/rescaler.c
new file mode 100644
index 0000000000..9825dcbc5f
--- /dev/null
+++ b/drivers/webpold/utils/rescaler.c
@@ -0,0 +1,152 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Rescaling functions
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <assert.h>
+#include <stdlib.h>
+#include "./rescaler.h"
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#define RFIX 30
+#define MULT_FIX(x,y) (((int64_t)(x) * (y) + (1 << (RFIX - 1))) >> RFIX)
+
+void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height,
+ uint8_t* const dst, int dst_width, int dst_height,
+ int dst_stride, int num_channels, int x_add, int x_sub,
+ int y_add, int y_sub, int32_t* const work) {
+ wrk->x_expand = (src_width < dst_width);
+ wrk->src_width = src_width;
+ wrk->src_height = src_height;
+ wrk->dst_width = dst_width;
+ wrk->dst_height = dst_height;
+ wrk->dst = dst;
+ wrk->dst_stride = dst_stride;
+ wrk->num_channels = num_channels;
+ // for 'x_expand', we use bilinear interpolation
+ wrk->x_add = wrk->x_expand ? (x_sub - 1) : x_add - x_sub;
+ wrk->x_sub = wrk->x_expand ? (x_add - 1) : x_sub;
+ wrk->y_accum = y_add;
+ wrk->y_add = y_add;
+ wrk->y_sub = y_sub;
+ wrk->fx_scale = (1 << RFIX) / x_sub;
+ wrk->fy_scale = (1 << RFIX) / y_sub;
+ wrk->fxy_scale = wrk->x_expand ?
+ ((int64_t)dst_height << RFIX) / (x_sub * src_height) :
+ ((int64_t)dst_height << RFIX) / (x_add * src_height);
+ wrk->irow = work;
+ wrk->frow = work + num_channels * dst_width;
+}
+
+void WebPRescalerImportRow(WebPRescaler* const wrk,
+ const uint8_t* const src, int channel) {
+ const int x_stride = wrk->num_channels;
+ const int x_out_max = wrk->dst_width * wrk->num_channels;
+ int x_in = channel;
+ int x_out;
+ int accum = 0;
+ if (!wrk->x_expand) {
+ int sum = 0;
+ for (x_out = channel; x_out < x_out_max; x_out += x_stride) {
+ accum += wrk->x_add;
+ for (; accum > 0; accum -= wrk->x_sub) {
+ sum += src[x_in];
+ x_in += x_stride;
+ }
+ { // Emit next horizontal pixel.
+ const int32_t base = src[x_in];
+ const int32_t frac = base * (-accum);
+ x_in += x_stride;
+ wrk->frow[x_out] = (sum + base) * wrk->x_sub - frac;
+ // fresh fractional start for next pixel
+ sum = (int)MULT_FIX(frac, wrk->fx_scale);
+ }
+ }
+ } else { // simple bilinear interpolation
+ int left = src[channel], right = src[channel];
+ for (x_out = channel; x_out < x_out_max; x_out += x_stride) {
+ if (accum < 0) {
+ left = right;
+ x_in += x_stride;
+ right = src[x_in];
+ accum += wrk->x_add;
+ }
+ wrk->frow[x_out] = right * wrk->x_add + (left - right) * accum;
+ accum -= wrk->x_sub;
+ }
+ }
+ // Accumulate the new row's contribution
+ for (x_out = channel; x_out < x_out_max; x_out += x_stride) {
+ wrk->irow[x_out] += wrk->frow[x_out];
+ }
+}
+
+uint8_t* WebPRescalerExportRow(WebPRescaler* const wrk) {
+ if (wrk->y_accum <= 0) {
+ int x_out;
+ uint8_t* const dst = wrk->dst;
+ int32_t* const irow = wrk->irow;
+ const int32_t* const frow = wrk->frow;
+ const int yscale = wrk->fy_scale * (-wrk->y_accum);
+ const int x_out_max = wrk->dst_width * wrk->num_channels;
+
+ for (x_out = 0; x_out < x_out_max; ++x_out) {
+ const int frac = (int)MULT_FIX(frow[x_out], yscale);
+ const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
+ dst[x_out] = (!(v & ~0xff)) ? v : (v < 0) ? 0 : 255;
+ irow[x_out] = frac; // new fractional start
+ }
+ wrk->y_accum += wrk->y_add;
+ wrk->dst += wrk->dst_stride;
+ return dst;
+ } else {
+ return NULL;
+ }
+}
+
+#undef MULT_FIX
+#undef RFIX
+
+//------------------------------------------------------------------------------
+// all-in-one calls
+
+int WebPRescalerImport(WebPRescaler* const wrk, int num_lines,
+ const uint8_t* src, int src_stride) {
+ int total_imported = 0;
+ while (total_imported < num_lines && wrk->y_accum > 0) {
+ int channel;
+ for (channel = 0; channel < wrk->num_channels; ++channel) {
+ WebPRescalerImportRow(wrk, src, channel);
+ }
+ src += src_stride;
+ ++total_imported;
+ wrk->y_accum -= wrk->y_sub;
+ }
+ return total_imported;
+}
+
+int WebPRescalerExport(WebPRescaler* const rescaler) {
+ int total_exported = 0;
+ while (WebPRescalerHasPendingOutput(rescaler)) {
+ WebPRescalerExportRow(rescaler);
+ ++total_exported;
+ }
+ return total_exported;
+}
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/utils/rescaler.h b/drivers/webpold/utils/rescaler.h
new file mode 100644
index 0000000000..9c9133d19b
--- /dev/null
+++ b/drivers/webpold/utils/rescaler.h
@@ -0,0 +1,76 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Rescaling functions
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#ifndef WEBP_UTILS_RESCALER_H_
+#define WEBP_UTILS_RESCALER_H_
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#include "../types.h"
+
+// Structure used for on-the-fly rescaling
+typedef struct {
+ int x_expand; // true if we're expanding in the x direction
+ int num_channels; // bytes to jump between pixels
+ int fy_scale, fx_scale; // fixed-point scaling factor
+ int64_t fxy_scale; // ''
+ // we need hpel-precise add/sub increments, for the downsampled U/V planes.
+ int y_accum; // vertical accumulator
+ int y_add, y_sub; // vertical increments (add ~= src, sub ~= dst)
+ int x_add, x_sub; // horizontal increments (add ~= src, sub ~= dst)
+ int src_width, src_height; // source dimensions
+ int dst_width, dst_height; // destination dimensions
+ uint8_t* dst;
+ int dst_stride;
+ int32_t* irow, *frow; // work buffer
+} WebPRescaler;
+
+// Initialize a rescaler given scratch area 'work' and dimensions of src & dst.
+void WebPRescalerInit(WebPRescaler* const wrk, int src_width, int src_height,
+ uint8_t* const dst,
+ int dst_width, int dst_height, int dst_stride,
+ int num_channels,
+ int x_add, int x_sub,
+ int y_add, int y_sub,
+ int32_t* const work);
+
+// Import a row of data and save its contribution in the rescaler.
+// 'channel' denotes the channel number to be imported.
+void WebPRescalerImportRow(WebPRescaler* const rescaler,
+ const uint8_t* const src, int channel);
+
+// Import multiple rows over all channels, until at least one row is ready to
+// be exported. Returns the actual number of lines that were imported.
+int WebPRescalerImport(WebPRescaler* const rescaler, int num_rows,
+ const uint8_t* src, int src_stride);
+
+// Return true if there is pending output rows ready.
+static WEBP_INLINE
+int WebPRescalerHasPendingOutput(const WebPRescaler* const rescaler) {
+ return (rescaler->y_accum <= 0);
+}
+
+// Export one row from rescaler. Returns the pointer where output was written,
+// or NULL if no row was pending.
+uint8_t* WebPRescalerExportRow(WebPRescaler* const wrk);
+
+// Export as many rows as possible. Return the numbers of rows written.
+int WebPRescalerExport(WebPRescaler* const wrk);
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif /* WEBP_UTILS_RESCALER_H_ */
diff --git a/drivers/webpold/utils/thread.c b/drivers/webpold/utils/thread.c
new file mode 100644
index 0000000000..ce89cf9dc7
--- /dev/null
+++ b/drivers/webpold/utils/thread.c
@@ -0,0 +1,247 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Multi-threaded worker
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <assert.h>
+#include <string.h> // for memset()
+#include "./thread.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#ifdef WEBP_USE_THREAD
+
+#if defined(_WIN32)
+
+//------------------------------------------------------------------------------
+// simplistic pthread emulation layer
+
+#include <process.h>
+
+// _beginthreadex requires __stdcall
+#define THREADFN unsigned int __stdcall
+#define THREAD_RETURN(val) (unsigned int)((DWORD_PTR)val)
+
+static int pthread_create(pthread_t* const thread, const void* attr,
+ unsigned int (__stdcall *start)(void*), void* arg) {
+ (void)attr;
+ *thread = (pthread_t)_beginthreadex(NULL, /* void *security */
+ 0, /* unsigned stack_size */
+ start,
+ arg,
+ 0, /* unsigned initflag */
+ NULL); /* unsigned *thrdaddr */
+ if (*thread == NULL) return 1;
+ SetThreadPriority(*thread, THREAD_PRIORITY_ABOVE_NORMAL);
+ return 0;
+}
+
+static int pthread_join(pthread_t thread, void** value_ptr) {
+ (void)value_ptr;
+ return (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0 ||
+ CloseHandle(thread) == 0);
+}
+
+// Mutex
+static int pthread_mutex_init(pthread_mutex_t* const mutex, void* mutexattr) {
+ (void)mutexattr;
+ InitializeCriticalSection(mutex);
+ return 0;
+}
+
+static int pthread_mutex_lock(pthread_mutex_t* const mutex) {
+ EnterCriticalSection(mutex);
+ return 0;
+}
+
+static int pthread_mutex_unlock(pthread_mutex_t* const mutex) {
+ LeaveCriticalSection(mutex);
+ return 0;
+}
+
+static int pthread_mutex_destroy(pthread_mutex_t* const mutex) {
+ DeleteCriticalSection(mutex);
+ return 0;
+}
+
+// Condition
+static int pthread_cond_destroy(pthread_cond_t* const condition) {
+ int ok = 1;
+ ok &= (CloseHandle(condition->waiting_sem_) != 0);
+ ok &= (CloseHandle(condition->received_sem_) != 0);
+ ok &= (CloseHandle(condition->signal_event_) != 0);
+ return !ok;
+}
+
+static int pthread_cond_init(pthread_cond_t* const condition, void* cond_attr) {
+ (void)cond_attr;
+ condition->waiting_sem_ = CreateSemaphore(NULL, 0, 1, NULL);
+ condition->received_sem_ = CreateSemaphore(NULL, 0, 1, NULL);
+ condition->signal_event_ = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (condition->waiting_sem_ == NULL ||
+ condition->received_sem_ == NULL ||
+ condition->signal_event_ == NULL) {
+ pthread_cond_destroy(condition);
+ return 1;
+ }
+ return 0;
+}
+
+static int pthread_cond_signal(pthread_cond_t* const condition) {
+ int ok = 1;
+ if (WaitForSingleObject(condition->waiting_sem_, 0) == WAIT_OBJECT_0) {
+ // a thread is waiting in pthread_cond_wait: allow it to be notified
+ ok = SetEvent(condition->signal_event_);
+ // wait until the event is consumed so the signaler cannot consume
+ // the event via its own pthread_cond_wait.
+ ok &= (WaitForSingleObject(condition->received_sem_, INFINITE) !=
+ WAIT_OBJECT_0);
+ }
+ return !ok;
+}
+
+static int pthread_cond_wait(pthread_cond_t* const condition,
+ pthread_mutex_t* const mutex) {
+ int ok;
+ // note that there is a consumer available so the signal isn't dropped in
+ // pthread_cond_signal
+ if (!ReleaseSemaphore(condition->waiting_sem_, 1, NULL))
+ return 1;
+ // now unlock the mutex so pthread_cond_signal may be issued
+ pthread_mutex_unlock(mutex);
+ ok = (WaitForSingleObject(condition->signal_event_, INFINITE) ==
+ WAIT_OBJECT_0);
+ ok &= ReleaseSemaphore(condition->received_sem_, 1, NULL);
+ pthread_mutex_lock(mutex);
+ return !ok;
+}
+
+#else // _WIN32
+# define THREADFN void*
+# define THREAD_RETURN(val) val
+#endif
+
+//------------------------------------------------------------------------------
+
+static THREADFN WebPWorkerThreadLoop(void *ptr) { // thread loop
+ WebPWorker* const worker = (WebPWorker*)ptr;
+ int done = 0;
+ while (!done) {
+ pthread_mutex_lock(&worker->mutex_);
+ while (worker->status_ == OK) { // wait in idling mode
+ pthread_cond_wait(&worker->condition_, &worker->mutex_);
+ }
+ if (worker->status_ == WORK) {
+ if (worker->hook) {
+ worker->had_error |= !worker->hook(worker->data1, worker->data2);
+ }
+ worker->status_ = OK;
+ } else if (worker->status_ == NOT_OK) { // finish the worker
+ done = 1;
+ }
+ // signal to the main thread that we're done (for Sync())
+ pthread_cond_signal(&worker->condition_);
+ pthread_mutex_unlock(&worker->mutex_);
+ }
+ return THREAD_RETURN(NULL); // Thread is finished
+}
+
+// main thread state control
+static void WebPWorkerChangeState(WebPWorker* const worker,
+ WebPWorkerStatus new_status) {
+ // no-op when attempting to change state on a thread that didn't come up
+ if (worker->status_ < OK) return;
+
+ pthread_mutex_lock(&worker->mutex_);
+ // wait for the worker to finish
+ while (worker->status_ != OK) {
+ pthread_cond_wait(&worker->condition_, &worker->mutex_);
+ }
+ // assign new status and release the working thread if needed
+ if (new_status != OK) {
+ worker->status_ = new_status;
+ pthread_cond_signal(&worker->condition_);
+ }
+ pthread_mutex_unlock(&worker->mutex_);
+}
+
+#endif
+
+//------------------------------------------------------------------------------
+
+void WebPWorkerInit(WebPWorker* const worker) {
+ memset(worker, 0, sizeof(*worker));
+ worker->status_ = NOT_OK;
+}
+
+int WebPWorkerSync(WebPWorker* const worker) {
+#ifdef WEBP_USE_THREAD
+ WebPWorkerChangeState(worker, OK);
+#endif
+ assert(worker->status_ <= OK);
+ return !worker->had_error;
+}
+
+int WebPWorkerReset(WebPWorker* const worker) {
+ int ok = 1;
+ worker->had_error = 0;
+ if (worker->status_ < OK) {
+#ifdef WEBP_USE_THREAD
+ if (pthread_mutex_init(&worker->mutex_, NULL) ||
+ pthread_cond_init(&worker->condition_, NULL)) {
+ return 0;
+ }
+ pthread_mutex_lock(&worker->mutex_);
+ ok = !pthread_create(&worker->thread_, NULL, WebPWorkerThreadLoop, worker);
+ if (ok) worker->status_ = OK;
+ pthread_mutex_unlock(&worker->mutex_);
+#else
+ worker->status_ = OK;
+#endif
+ } else if (worker->status_ > OK) {
+ ok = WebPWorkerSync(worker);
+ }
+ assert(!ok || (worker->status_ == OK));
+ return ok;
+}
+
+void WebPWorkerLaunch(WebPWorker* const worker) {
+#ifdef WEBP_USE_THREAD
+ WebPWorkerChangeState(worker, WORK);
+#else
+ if (worker->hook)
+ worker->had_error |= !worker->hook(worker->data1, worker->data2);
+#endif
+}
+
+void WebPWorkerEnd(WebPWorker* const worker) {
+ if (worker->status_ >= OK) {
+#ifdef WEBP_USE_THREAD
+ WebPWorkerChangeState(worker, NOT_OK);
+ pthread_join(worker->thread_, NULL);
+ pthread_mutex_destroy(&worker->mutex_);
+ pthread_cond_destroy(&worker->condition_);
+#else
+ worker->status_ = NOT_OK;
+#endif
+ }
+ assert(worker->status_ == NOT_OK);
+}
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/utils/thread.h b/drivers/webpold/utils/thread.h
new file mode 100644
index 0000000000..3191890b76
--- /dev/null
+++ b/drivers/webpold/utils/thread.h
@@ -0,0 +1,86 @@
+// Copyright 2011 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Multi-threaded worker
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#ifndef WEBP_UTILS_THREAD_H_
+#define WEBP_UTILS_THREAD_H_
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+#if WEBP_USE_THREAD
+
+#if defined(_WIN32)
+
+#include <windows.h>
+typedef HANDLE pthread_t;
+typedef CRITICAL_SECTION pthread_mutex_t;
+typedef struct {
+ HANDLE waiting_sem_;
+ HANDLE received_sem_;
+ HANDLE signal_event_;
+} pthread_cond_t;
+
+#else
+
+#include <pthread.h>
+
+#endif /* _WIN32 */
+#endif /* WEBP_USE_THREAD */
+
+// State of the worker thread object
+typedef enum {
+ NOT_OK = 0, // object is unusable
+ OK, // ready to work
+ WORK // busy finishing the current task
+} WebPWorkerStatus;
+
+// Function to be called by the worker thread. Takes two opaque pointers as
+// arguments (data1 and data2), and should return false in case of error.
+typedef int (*WebPWorkerHook)(void*, void*);
+
+// Synchronize object used to launch job in the worker thread
+typedef struct {
+#if WEBP_USE_THREAD
+ pthread_mutex_t mutex_;
+ pthread_cond_t condition_;
+ pthread_t thread_;
+#endif
+ WebPWorkerStatus status_;
+ WebPWorkerHook hook; // hook to call
+ void* data1; // first argument passed to 'hook'
+ void* data2; // second argument passed to 'hook'
+ int had_error; // return value of the last call to 'hook'
+} WebPWorker;
+
+// Must be called first, before any other method.
+void WebPWorkerInit(WebPWorker* const worker);
+// Must be called initialize the object and spawn the thread. Re-entrant.
+// Will potentially launch the thread. Returns false in case of error.
+int WebPWorkerReset(WebPWorker* const worker);
+// Make sure the previous work is finished. Returns true if worker->had_error
+// was not set and not error condition was triggered by the working thread.
+int WebPWorkerSync(WebPWorker* const worker);
+// Trigger the thread to call hook() with data1 and data2 argument. These
+// hook/data1/data2 can be changed at any time before calling this function,
+// but not be changed afterward until the next call to WebPWorkerSync().
+void WebPWorkerLaunch(WebPWorker* const worker);
+// Kill the thread and terminate the object. To use the object again, one
+// must call WebPWorkerReset() again.
+void WebPWorkerEnd(WebPWorker* const worker);
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif /* WEBP_UTILS_THREAD_H_ */
diff --git a/drivers/webpold/utils/utils.c b/drivers/webpold/utils/utils.c
new file mode 100644
index 0000000000..673b7e284c
--- /dev/null
+++ b/drivers/webpold/utils/utils.c
@@ -0,0 +1,44 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Misc. common utility functions
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#include <stdlib.h>
+#include "./utils.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// Checked memory allocation
+
+static int CheckSizeArguments(uint64_t nmemb, size_t size) {
+ const uint64_t total_size = nmemb * size;
+ if (nmemb == 0) return 1;
+ if ((uint64_t)size > WEBP_MAX_ALLOCABLE_MEMORY / nmemb) return 0;
+ if (total_size != (size_t)total_size) return 0;
+ return 1;
+}
+
+void* WebPSafeMalloc(uint64_t nmemb, size_t size) {
+ if (!CheckSizeArguments(nmemb, size)) return NULL;
+ return malloc((size_t)(nmemb * size));
+}
+
+void* WebPSafeCalloc(uint64_t nmemb, size_t size) {
+ if (!CheckSizeArguments(nmemb, size)) return NULL;
+ return calloc((size_t)nmemb, size);
+}
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
diff --git a/drivers/webpold/utils/utils.h b/drivers/webpold/utils/utils.h
new file mode 100644
index 0000000000..316ac90612
--- /dev/null
+++ b/drivers/webpold/utils/utils.h
@@ -0,0 +1,44 @@
+// Copyright 2012 Google Inc. All Rights Reserved.
+//
+// This code is licensed under the same terms as WebM:
+// Software License Agreement: http://www.webmproject.org/license/software/
+// Additional IP Rights Grant: http://www.webmproject.org/license/additional/
+// -----------------------------------------------------------------------------
+//
+// Misc. common utility functions
+//
+// Author: Skal (pascal.massimino@gmail.com)
+
+#ifndef WEBP_UTILS_UTILS_H_
+#define WEBP_UTILS_UTILS_H_
+
+#include "../types.h"
+
+#if defined(__cplusplus) || defined(c_plusplus)
+extern "C" {
+#endif
+
+//------------------------------------------------------------------------------
+// Memory allocation
+
+// This is the maximum memory amount that libwebp will ever try to allocate.
+#define WEBP_MAX_ALLOCABLE_MEMORY (1ULL << 40)
+
+// size-checking safe malloc/calloc: verify that the requested size is not too
+// large, or return NULL. You don't need to call these for constructs like
+// malloc(sizeof(foo)), but only if there's picture-dependent size involved
+// somewhere (like: malloc(num_pixels * sizeof(*something))). That's why this
+// safe malloc() borrows the signature from calloc(), pointing at the dangerous
+// underlying multiply involved.
+void* WebPSafeMalloc(uint64_t nmemb, size_t size);
+// Note that WebPSafeCalloc() expects the second argument type to be 'size_t'
+// in order to favor the "calloc(num_foo, sizeof(foo))" pattern.
+void* WebPSafeCalloc(uint64_t nmemb, size_t size);
+
+//------------------------------------------------------------------------------
+
+#if defined(__cplusplus) || defined(c_plusplus)
+} // extern "C"
+#endif
+
+#endif /* WEBP_UTILS_UTILS_H_ */
diff --git a/drivers/windows/SCsub b/drivers/windows/SCsub
index bcd231579c..9fbb467baa 100644
--- a/drivers/windows/SCsub
+++ b/drivers/windows/SCsub
@@ -3,5 +3,3 @@ Import('env')
env.add_source_files(env.drivers_sources,"*.cpp")
Export('env')
-
-
diff --git a/drivers/windows/dir_access_windows.cpp b/drivers/windows/dir_access_windows.cpp
index 7c81e8e051..0a413979fc 100644
--- a/drivers/windows/dir_access_windows.cpp
+++ b/drivers/windows/dir_access_windows.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/windows/dir_access_windows.h b/drivers/windows/dir_access_windows.h
index 384bc8327d..6861291fd9 100644
--- a/drivers/windows/dir_access_windows.h
+++ b/drivers/windows/dir_access_windows.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp
index 90903f2cbd..66181a6f44 100644
--- a/drivers/windows/file_access_windows.cpp
+++ b/drivers/windows/file_access_windows.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -72,6 +72,8 @@ Error FileAccessWindows::_open(const String& p_filename, int p_mode_flags) {
mode_string=L"wb";
else if (p_mode_flags==READ_WRITE)
mode_string=L"rb+";
+ else if (p_mode_flags==WRITE_READ)
+ mode_string=L"wb+";
else
return ERR_INVALID_PARAMETER;
diff --git a/drivers/windows/file_access_windows.h b/drivers/windows/file_access_windows.h
index a2598bfeec..b02b6f66a7 100644
--- a/drivers/windows/file_access_windows.h
+++ b/drivers/windows/file_access_windows.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/windows/mutex_windows.cpp b/drivers/windows/mutex_windows.cpp
index 09f8590510..f63415d0f8 100644
--- a/drivers/windows/mutex_windows.cpp
+++ b/drivers/windows/mutex_windows.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/windows/mutex_windows.h b/drivers/windows/mutex_windows.h
index 9447f17a1c..4cff027906 100644
--- a/drivers/windows/mutex_windows.h
+++ b/drivers/windows/mutex_windows.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/windows/semaphore_windows.cpp b/drivers/windows/semaphore_windows.cpp
index 50cdf7cce5..74094f482a 100644
--- a/drivers/windows/semaphore_windows.cpp
+++ b/drivers/windows/semaphore_windows.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/windows/semaphore_windows.h b/drivers/windows/semaphore_windows.h
index 43f6c0b560..e8836e49dc 100644
--- a/drivers/windows/semaphore_windows.h
+++ b/drivers/windows/semaphore_windows.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/windows/shell_windows.cpp b/drivers/windows/shell_windows.cpp
index 670f4e483d..c69d371a65 100644
--- a/drivers/windows/shell_windows.cpp
+++ b/drivers/windows/shell_windows.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/windows/shell_windows.h b/drivers/windows/shell_windows.h
index 98eae81175..6f97964a09 100644
--- a/drivers/windows/shell_windows.h
+++ b/drivers/windows/shell_windows.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/windows/thread_windows.cpp b/drivers/windows/thread_windows.cpp
index 6a9e97ba01..d5e489aab4 100644
--- a/drivers/windows/thread_windows.cpp
+++ b/drivers/windows/thread_windows.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/drivers/windows/thread_windows.h b/drivers/windows/thread_windows.h
index 3c8f92ce57..b051bfe370 100644
--- a/drivers/windows/thread_windows.h
+++ b/drivers/windows/thread_windows.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/godot_icon.png b/godot_icon.png
new file mode 100644
index 0000000000..013632ddf1
--- /dev/null
+++ b/godot_icon.png
Binary files differ
diff --git a/godot_icon.svg b/godot_icon.svg
new file mode 100644
index 0000000000..6e32074d89
--- /dev/null
+++ b/godot_icon.svg
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="1024"
+ height="1024"
+ id="svg3030"
+ version="1.1"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="godot_icon.svg">
+ <defs
+ id="defs3032" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.24748737"
+ inkscape:cx="340.91041"
+ inkscape:cy="224.06536"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="1366"
+ inkscape:window-height="748"
+ inkscape:window-x="-2"
+ inkscape:window-y="-3"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata3035">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-28.362183)">
+ <rect
+ style="fill:#a39f9f;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="rect4009"
+ width="990"
+ height="990"
+ x="20"
+ y="47.362183"
+ ry="187.81349" />
+ <path
+ style="fill:#ffffff;fill-opacity:1;stroke:none"
+ d="m 116.99388,715.36604 43.13957,-74.51381 75.99672,-171.42666 271.088,-13.63746 282.06373,14.1696 138.45065,255.56931 -25.0756,66.96734 -376.12685,53.39482 -367.70391,-40.32222 z"
+ id="path3239"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cccccccccc" />
+ <g
+ id="g3412"
+ transform="matrix(12.995388,0,0,-12.995388,898.37246,704.73082)">
+ <path
+ inkscape:connector-curvature="0"
+ d="m 0,0 0,-3.942 c 0,-0.39 -0.25,-0.734 -0.621,-0.852 L -6.835,-6.8 c -0.273,-0.091 -0.57,-0.042 -0.8,0.128 -0.232,0.168 -0.37,0.437 -0.37,0.721 l 0,4.305 -5.818,-1.108 0,-4.381 c 0,-0.447 -0.332,-0.824 -0.775,-0.885 l -8.41,-1.152 c -0.039,-0.003 -0.081,-0.008 -0.121,-0.008 -0.214,0 -0.424,0.078 -0.588,0.22 -0.195,0.172 -0.306,0.416 -0.306,0.676 l 0,4.638 -4.341,-0.018 0,-10e-4 -0.318,10e-4 -0.319,-10e-4 0,10e-4 -4.34,0.018 0,-4.638 c 0,-0.26 -0.112,-0.504 -0.307,-0.676 -0.164,-0.142 -0.374,-0.22 -0.587,-0.22 -0.041,0 -0.082,0.005 -0.123,0.008 l -8.41,1.152 c -0.442,0.061 -0.774,0.438 -0.774,0.885 l 0,4.381 -5.819,1.108 0,-4.305 c 0,-0.284 -0.137,-0.553 -0.368,-0.721 -0.232,-0.17 -0.529,-0.219 -0.802,-0.128 l -6.215,2.006 c -0.369,0.118 -0.619,0.462 -0.619,0.852 l 0,3.942 -3.837,1.29 c -0.19,-0.811 -0.295,-1.642 -0.295,-2.481 0,-10.301 14.512,-18.252 32.448,-18.309 l 0.022,0 0.023,0 c 17.936,0.057 32.448,8.008 32.448,18.309 0,0.766 -0.088,1.521 -0.247,2.266 L 0,0 z"
+ style="fill:#478cbf;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path3414" />
+ </g>
+ <g
+ id="g3416"
+ transform="matrix(12.995388,0,0,-12.995388,140.10982,467.34929)">
+ <path
+ inkscape:connector-curvature="0"
+ d="m 0,0 0,-16.047 2.163,-0.729 c 0.364,-0.122 0.61,-0.462 0.61,-0.847 l 0,-3.936 4.426,-1.428 0,4.154 c 0,0.27 0.118,0.52 0.323,0.689 0.206,0.172 0.474,0.241 0.739,0.192 l 7.608,-1.452 c 0.422,-0.079 0.728,-0.448 0.728,-0.877 l 0,-4.338 6.62,-0.904 0,4.509 c 0,0.241 0.096,0.467 0.264,0.635 0.167,0.166 0.394,0.259 0.633,0.259 l 0.002,0 5.551,-0.022 5.549,0.022 c 0.245,-10e-4 0.468,-0.093 0.635,-0.259 0.169,-0.168 0.264,-0.394 0.264,-0.635 l 0,-4.509 6.621,0.904 0,4.338 c 0,0.429 0.304,0.798 0.726,0.877 l 7.609,1.452 c 0.262,0.049 0.533,-0.02 0.738,-0.192 0.205,-0.169 0.325,-0.419 0.325,-0.689 l 0,-4.154 4.425,1.428 0,3.936 c 0,0.385 0.245,0.725 0.609,0.847 l 1.475,0.497 0,16.279 0.04,0 c 1.437,1.834 2.767,3.767 4.042,5.828 -1.694,2.883 -3.768,5.459 -5.986,7.846 -2.057,-1.035 -4.055,-2.208 -5.942,-3.456 -0.944,0.938 -2.008,1.706 -3.052,2.509 -1.027,0.824 -2.183,1.428 -3.281,2.132 0.327,2.433 0.489,4.828 0.554,7.327 -2.831,1.424 -5.85,2.369 -8.903,3.047 -1.219,-2.048 -2.334,-4.267 -3.304,-6.436 -1.152,0.192 -2.309,0.264 -3.467,0.277 l 0,0.002 c -0.008,0 -0.015,-0.002 -0.022,-0.002 -0.008,0 -0.015,0.002 -0.022,0.002 l 0,-0.002 c -1.16,-0.013 -2.316,-0.085 -3.468,-0.277 -0.97,2.169 -2.084,4.388 -3.305,6.436 C 19.475,24.555 16.456,23.61 13.626,22.186 13.69,19.687 13.852,17.292 14.18,14.859 13.081,14.155 11.925,13.551 10.898,12.727 9.855,11.924 8.79,11.156 7.846,10.218 5.958,11.466 3.961,12.639 1.904,13.674 -0.314,11.287 -2.388,8.711 -4.082,5.828 -2.807,3.767 -1.477,1.834 -0.04,0 L 0,0 z"
+ style="fill:#478cbf;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path3418" />
+ </g>
+ <g
+ id="g3420"
+ transform="matrix(12.995388,0,0,-12.995388,411.4457,567.42812)">
+ <path
+ inkscape:connector-curvature="0"
+ d="m 0,0 c 0,-3.611 -2.926,-6.537 -6.537,-6.537 -3.608,0 -6.535,2.926 -6.535,6.537 0,3.609 2.927,6.533 6.535,6.533 C -2.926,6.533 0,3.609 0,0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path3422" />
+ </g>
+ <g
+ id="g3424"
+ transform="matrix(12.995388,0,0,-12.995388,391.00655,572.46636)">
+ <path
+ inkscape:connector-curvature="0"
+ d="m 0,0 c 0,-2.396 -1.941,-4.337 -4.339,-4.337 -2.396,0 -4.339,1.941 -4.339,4.337 0,2.396 1.943,4.339 4.339,4.339 C -1.941,4.339 0,2.396 0,0"
+ style="fill:#414042;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path3426" />
+ </g>
+ <g
+ id="g3428"
+ transform="matrix(12.995388,0,0,-12.995388,526.30933,660.10985)">
+ <path
+ inkscape:connector-curvature="0"
+ d="m 0,0 c -1.162,0 -2.104,0.856 -2.104,1.912 l 0,6.018 c 0,1.054 0.942,1.912 2.104,1.912 1.162,0 2.106,-0.858 2.106,-1.912 l 0,-6.018 C 2.106,0.856 1.162,0 0,0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path3430" />
+ </g>
+ <g
+ id="g3432"
+ transform="matrix(12.995388,0,0,-12.995388,641.18731,567.42812)">
+ <path
+ inkscape:connector-curvature="0"
+ d="m 0,0 c 0,-3.611 2.926,-6.537 6.537,-6.537 3.609,0 6.535,2.926 6.535,6.537 0,3.609 -2.926,6.533 -6.535,6.533 C 2.926,6.533 0,3.609 0,0"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path3434" />
+ </g>
+ <g
+ id="g3436"
+ transform="matrix(12.995388,0,0,-12.995388,661.63165,572.46636)">
+ <path
+ inkscape:connector-curvature="0"
+ d="m 0,0 c 0,-2.396 1.941,-4.337 4.336,-4.337 2.398,0 4.339,1.941 4.339,4.337 0,2.396 -1.941,4.339 -4.339,4.339 C 1.941,4.339 0,2.396 0,0"
+ style="fill:#414042;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path3438" />
+ </g>
+ </g>
+</svg>
diff --git a/logo_small.png b/logo_small.png
deleted file mode 100644
index 61e4cc95d6..0000000000
--- a/logo_small.png
+++ /dev/null
Binary files differ
diff --git a/main/SCsub b/main/SCsub
index 795c427c8d..fa60ffc3e8 100644
--- a/main/SCsub
+++ b/main/SCsub
@@ -8,5 +8,3 @@ Export('env')
lib = env.Library("main",env.main_sources)
env.Prepend(LIBS=[lib])
-
-
diff --git a/main/input_default.cpp b/main/input_default.cpp
new file mode 100644
index 0000000000..a79199580b
--- /dev/null
+++ b/main/input_default.cpp
@@ -0,0 +1,829 @@
+#include "input_default.h"
+#include "servers/visual_server.h"
+#include "os/os.h"
+#include "input_map.h"
+
+void InputDefault::SpeedTrack::update(const Vector2& p_delta_p) {
+
+ uint64_t tick = OS::get_singleton()->get_ticks_usec();
+ uint32_t tdiff = tick-last_tick;
+ float delta_t = tdiff / 1000000.0;
+ last_tick=tick;
+
+
+ accum+=p_delta_p;
+ accum_t+=delta_t;
+
+ if (accum_t>max_ref_frame*10)
+ accum_t=max_ref_frame*10;
+
+ while( accum_t>=min_ref_frame ) {
+
+ float slice_t = min_ref_frame / accum_t;
+ Vector2 slice = accum*slice_t;
+ accum=accum-slice;
+ accum_t-=min_ref_frame;
+
+ speed=(slice/min_ref_frame).linear_interpolate(speed,min_ref_frame/max_ref_frame);
+ }
+
+}
+
+void InputDefault::SpeedTrack::reset() {
+ last_tick = OS::get_singleton()->get_ticks_usec();
+ speed=Vector2();
+ accum_t=0;
+}
+
+InputDefault::SpeedTrack::SpeedTrack() {
+
+ min_ref_frame=0.1;
+ max_ref_frame=0.3;
+ reset();
+}
+
+bool InputDefault::is_key_pressed(int p_scancode) {
+
+ _THREAD_SAFE_METHOD_
+ return keys_pressed.has(p_scancode);
+}
+
+bool InputDefault::is_mouse_button_pressed(int p_button) {
+
+ _THREAD_SAFE_METHOD_
+ return (mouse_button_mask&(1<<p_button))!=0;
+}
+
+
+static int _combine_device(int p_value,int p_device) {
+
+ return p_value|(p_device<<20);
+}
+
+bool InputDefault::is_joy_button_pressed(int p_device, int p_button) {
+
+ _THREAD_SAFE_METHOD_
+ return joy_buttons_pressed.has(_combine_device(p_button,p_device));
+}
+
+bool InputDefault::is_action_pressed(const StringName& p_action) {
+
+ if (custom_action_press.has(p_action))
+ return true; //simpler
+
+ const List<InputEvent> *alist = InputMap::get_singleton()->get_action_list(p_action);
+ if (!alist)
+ return NULL;
+
+
+ for (const List<InputEvent>::Element *E=alist->front();E;E=E->next()) {
+
+
+ int device=E->get().device;
+
+ switch(E->get().type) {
+
+ case InputEvent::KEY: {
+
+ const InputEventKey &iek=E->get().key;
+ if ((keys_pressed.has(iek.scancode)))
+ return true;
+ } break;
+ case InputEvent::MOUSE_BUTTON: {
+
+ const InputEventMouseButton &iemb=E->get().mouse_button;
+ if(mouse_button_mask&(1<<iemb.button_index))
+ return true;
+ } break;
+ case InputEvent::JOYSTICK_BUTTON: {
+
+ const InputEventJoystickButton &iejb=E->get().joy_button;
+ int c = _combine_device(iejb.button_index,device);
+ if (joy_buttons_pressed.has(c))
+ return true;
+ } break;
+ }
+ }
+
+ return false;
+}
+
+float InputDefault::get_joy_axis(int p_device,int p_axis) {
+
+ _THREAD_SAFE_METHOD_
+ int c = _combine_device(p_axis,p_device);
+ if (_joy_axis.has(c)) {
+ return _joy_axis[c];
+ } else {
+ return 0;
+ }
+}
+
+String InputDefault::get_joy_name(int p_idx) {
+
+ _THREAD_SAFE_METHOD_
+ return joy_names[p_idx].name;
+};
+
+static String _hex_str(uint8_t p_byte) {
+
+ static const char* dict = "0123456789abcdef";
+ char ret[3];
+ ret[2] = 0;
+
+ ret[0] = dict[p_byte>>4];
+ ret[1] = dict[p_byte & 0xf];
+
+ return ret;
+};
+
+void InputDefault::joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid) {
+
+ _THREAD_SAFE_METHOD_
+ Joystick js;
+ js.name = p_connected ? p_name : "";
+ js.uid = p_connected ? p_guid : "";
+ js.mapping = -1;
+ js.hat_current = 0;
+
+ if (p_connected) {
+
+ String uidname = p_guid;
+ if (p_guid == "") {
+ int uidlen = MIN(p_name.length(), 16);
+ for (int i=0; i<uidlen; i++) {
+ uidname = uidname + _hex_str(p_name[i]);
+ };
+ };
+ js.uid = uidname;
+ //printf("looking for mappings for guid %ls\n", uidname.c_str());
+ int mapping = -1;
+ for (int i=0; i < map_db.size(); i++) {
+ if (js.uid == map_db[i].uid) {
+ mapping = i;
+ //printf("found mapping\n");
+ };
+ };
+ js.mapping = mapping;
+ };
+ joy_names[p_idx] = js;
+
+ emit_signal("joy_connection_changed", p_idx, p_connected);
+};
+
+Vector3 InputDefault::get_accelerometer() {
+
+ _THREAD_SAFE_METHOD_
+ return accelerometer;
+}
+
+void InputDefault::parse_input_event(const InputEvent& p_event) {
+
+ _THREAD_SAFE_METHOD_
+ switch(p_event.type) {
+
+ case InputEvent::KEY: {
+
+ if (p_event.key.echo)
+ break;
+ if (p_event.key.scancode==0)
+ break;
+
+ // print_line(p_event);
+
+ if (p_event.key.pressed)
+ keys_pressed.insert(p_event.key.scancode);
+ else
+ keys_pressed.erase(p_event.key.scancode);
+ } break;
+ case InputEvent::MOUSE_BUTTON: {
+
+ if (p_event.mouse_button.doubleclick)
+ break;
+
+ if (p_event.mouse_button.pressed)
+ mouse_button_mask|=(1<<p_event.mouse_button.button_index);
+ else
+ mouse_button_mask&=~(1<<p_event.mouse_button.button_index);
+
+ if (main_loop && emulate_touch && p_event.mouse_button.button_index==1) {
+ InputEventScreenTouch touch_event;
+ touch_event.index=0;
+ touch_event.pressed=p_event.mouse_button.pressed;
+ touch_event.x=p_event.mouse_button.x;
+ touch_event.y=p_event.mouse_button.y;
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_TOUCH;
+ ev.screen_touch=touch_event;
+ main_loop->input_event(ev);
+ }
+ } break;
+ case InputEvent::MOUSE_MOTION: {
+
+ if (main_loop && emulate_touch && p_event.mouse_motion.button_mask&1) {
+ InputEventScreenDrag drag_event;
+ drag_event.index=0;
+ drag_event.x=p_event.mouse_motion.x;
+ drag_event.y=p_event.mouse_motion.y;
+ drag_event.relative_x=p_event.mouse_motion.relative_x;
+ drag_event.relative_y=p_event.mouse_motion.relative_y;
+ drag_event.speed_x=p_event.mouse_motion.speed_x;
+ drag_event.speed_y=p_event.mouse_motion.speed_y;
+
+ InputEvent ev;
+ ev.type=InputEvent::SCREEN_DRAG;
+ ev.screen_drag=drag_event;
+
+ main_loop->input_event(ev);
+ }
+
+ } break;
+ case InputEvent::JOYSTICK_BUTTON: {
+
+ int c = _combine_device(p_event.joy_button.button_index,p_event.device);
+
+ if (p_event.joy_button.pressed)
+ joy_buttons_pressed.insert(c);
+ else
+ joy_buttons_pressed.erase(c);
+ } break;
+ case InputEvent::JOYSTICK_MOTION: {
+ set_joy_axis(p_event.device, p_event.joy_motion.axis, p_event.joy_motion.axis_value);
+ } break;
+
+ }
+
+ if (main_loop)
+ main_loop->input_event(p_event);
+
+}
+
+void InputDefault::set_joy_axis(int p_device,int p_axis,float p_value) {
+
+ _THREAD_SAFE_METHOD_
+ int c = _combine_device(p_axis,p_device);
+ _joy_axis[c]=p_value;
+}
+
+void InputDefault::set_accelerometer(const Vector3& p_accel) {
+
+ _THREAD_SAFE_METHOD_
+
+ accelerometer=p_accel;
+
+}
+
+void InputDefault::set_main_loop(MainLoop *p_main_loop) {
+ main_loop=p_main_loop;
+
+}
+
+void InputDefault::set_mouse_pos(const Point2& p_posf) {
+
+ mouse_speed_track.update(p_posf-mouse_pos);
+ mouse_pos=p_posf;
+ if (custom_cursor.is_valid()) {
+ VisualServer::get_singleton()->cursor_set_pos(get_mouse_pos());
+ }
+}
+
+Point2 InputDefault::get_mouse_pos() const {
+
+ return mouse_pos;
+}
+Point2 InputDefault::get_mouse_speed() const {
+
+ return mouse_speed_track.speed;
+}
+
+int InputDefault::get_mouse_button_mask() const {
+
+ return OS::get_singleton()->get_mouse_button_state();
+}
+
+void InputDefault::warp_mouse_pos(const Vector2& p_to) {
+
+ OS::get_singleton()->warp_mouse_pos(p_to);
+}
+
+
+void InputDefault::iteration(float p_step) {
+
+
+}
+
+void InputDefault::action_press(const StringName& p_action) {
+
+ if (custom_action_press.has(p_action)) {
+
+ custom_action_press[p_action]++;
+ } else {
+ custom_action_press[p_action]=1;
+ }
+}
+
+void InputDefault::action_release(const StringName& p_action){
+
+ ERR_FAIL_COND(!custom_action_press.has(p_action));
+ custom_action_press[p_action]--;
+ if (custom_action_press[p_action]==0) {
+ custom_action_press.erase(p_action);
+ }
+}
+
+void InputDefault::set_emulate_touch(bool p_emulate) {
+
+ emulate_touch=p_emulate;
+}
+
+bool InputDefault::is_emulating_touchscreen() const {
+
+ return emulate_touch;
+}
+
+void InputDefault::set_custom_mouse_cursor(const RES& p_cursor,const Vector2& p_hotspot) {
+ if (custom_cursor==p_cursor)
+ return;
+
+ custom_cursor=p_cursor;
+
+ if (p_cursor.is_null()) {
+ set_mouse_mode(MOUSE_MODE_VISIBLE);
+ VisualServer::get_singleton()->cursor_set_visible(false);
+ } else {
+ set_mouse_mode(MOUSE_MODE_HIDDEN);
+ VisualServer::get_singleton()->cursor_set_visible(true);
+ VisualServer::get_singleton()->cursor_set_texture(custom_cursor->get_rid(),p_hotspot);
+ VisualServer::get_singleton()->cursor_set_pos(get_mouse_pos());
+ }
+}
+
+void InputDefault::set_mouse_in_window(bool p_in_window) {
+
+ if (custom_cursor.is_valid()) {
+
+ if (p_in_window) {
+ set_mouse_mode(MOUSE_MODE_HIDDEN);
+ VisualServer::get_singleton()->cursor_set_visible(true);
+ } else {
+ set_mouse_mode(MOUSE_MODE_VISIBLE);
+ VisualServer::get_singleton()->cursor_set_visible(false);
+ }
+
+ }
+}
+
+// from github.com/gabomdq/SDL_GameControllerDB
+static const char *s_ControllerMappings [] =
+{
+ #ifdef WINDOWS_ENABLED
+ "8f0e1200000000000000504944564944,Acme,platform:Windows,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,",
+ "341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+ "ffff0000000000000000504944564944,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,",
+ "6d0416c2000000000000504944564944,Generic DirectInput Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+ "6d0419c2000000000000504944564944,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,",
+ "88880803000000000000504944564944,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows,",
+ "4c056802000000000000504944564944,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows,",
+ "25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows,",
+ "4c05c405000000000000504944564944,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows,",
+ "6d0418c2000000000000504944564944,Logitech RumblePad 2 USB,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,",
+ "36280100000000000000504944564944,OUYA Controller,platform:Windows,a:b0,b:b3,y:b2,x:b1,start:b14,guide:b15,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b8,dpleft:b10,dpdown:b9,dpright:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b12,righttrigger:b13,",
+ "4f0400b3000000000000504944564944,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Windows,",
+ "00f00300000000000000504944564944,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows,",
+ "00f0f100000000000000504944564944,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows,",
+ "28040140000000000000504944564944,GamePad Pro USB,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7,",
+ "ff113133000000000000504944564944,SVEN X-PAD,platform:Windows,a:b2,b:b3,y:b1,x:b0,start:b5,back:b4,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b8,righttrigger:b9,",
+ "8f0e0300000000000000504944564944,Piranha xtreme,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,",
+ "8f0e0d31000000000000504944564944,Multilaser JS071 USB,platform:Windows,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,",
+ "10080300000000000000504944564944,PS2 USB,platform:Windows,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a4,righty:a2,lefttrigger:b4,righttrigger:b5,",
+ "79000600000000000000504944564944,G-Shark GS-GP702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Windows,",
+ "4b12014d000000000000504944564944,NYKO AIRFLO,a:b0,b:b1,x:b2,y:b3,back:b8,guide:b10,start:b9,leftstick:a0,rightstick:a2,leftshoulder:a3,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:h0.6,lefty:h0.12,rightx:h0.9,righty:h0.4,lefttrigger:b6,righttrigger:b7,platform:Windows,",
+ "d6206dca000000000000504944564944,PowerA Pro Ex,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,",
+ "a3060cff000000000000504944564944,Saitek P2500,a:b2,b:b3,y:b1,x:b0,start:b4,guide:b10,back:b5,leftstick:b8,rightstick:b9,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows,",
+ "8f0e0300000000000000504944564944,Trust GTX 28,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows,",
+ "4f0415b3000000000000504944564944,Thrustmaster Dual Analog 3.2,platform:Windows,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,",
+ "6f0e1e01000000000000504944564944,Rock Candy Gamepad for PS3,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,",
+ "83056020000000000000504944564944,iBuffalo USB 2-axis 8-button Gamepad,a:b1,b:b0,y:b2,x:b3,start:b7,back:b6,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,platform:Windows,",
+ "c911f055000000000000504944564944,GAMEPAD,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+ "79000600000000000000504944564944,Generic Speedlink,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,",
+ "__XINPUT_DEVICE__,XInput Gamepad,a:b12,b:b13,x:b14,y:b15,start:b4,back:b5,leftstick:b6,rightstick:b7,leftshoulder:b8,rightshoulder:b9,dpup:b0,dpdown:b1,dpleft:b2,dpright:b3,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,",
+
+ #endif
+ #ifdef OSX_ENABLED
+ "0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+ "6d0400000000000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", /* Guide button doesn't seem to be sent in DInput mode. */
+ "6d0400000000000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+ "6d040000000000001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
+ "6d0400000000000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", /* This includes F710 in DInput mode and the "Logitech Cordless RumblePad 2", at the very least. */
+ "4c050000000000006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
+ "4c05000000000000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+ "5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,",
+ #endif
+ #if X11_ENABLED
+ "0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
+ "03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,",
+ "030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+ "030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+ "030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+ "030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,",
+ "030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+ "030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
+ "030000004c050000c405000011010000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,",
+ "03000000de280000ff11000001000000,Valve Streaming Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+ "030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+ "030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+ "030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+ "03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,y:b0,x:b3,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,",
+ "03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,",
+ "030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,y:b3,x:b1,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,",
+ "030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5,",
+ "030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,",
+ "030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2,",
+ "030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,",
+ "030000006d04000016c2000010010000,Logitech Logitech Dual Action,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,",
+ "03000000260900008888000000010000,GameCube {WiseGroup USB box},a:b0,b:b2,y:b3,x:b1,start:b7,leftshoulder:,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,rightstick:,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,",
+ "030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,y:b4,x:b3,start:b8,guide:b5,back:b2,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b9,righttrigger:b10,",
+ "030000006d04000018c2000010010000,Logitech Logitech RumblePad 2 USB,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,",
+ "05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,y:b3,x:b2,start:b6,leftstick:b7,rightstick:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4,",
+ "030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,a:b1,b:b2,x:b0,y:b3,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,",
+ "030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,a:b1,b:b2,x:b0,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,",
+ "0300000000f000000300000000010000,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,",
+ "0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,",
+ "030000006f0e00001f01000000010000,Generic X-Box pad,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,",
+ "03000000280400000140000000010000,Gravis GamePad Pro USB ,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1,",
+ "030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4,",
+ "030000006f0e00001e01000011010000,Rock Candy Gamepad for PS3,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,",
+ "03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,a:b2,b:b1,y:b0,x:b3,start:b8,back:b9,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,",
+ "030000008916000000fd000024010000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,",
+ "030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,",
+ "03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,",
+ "050000004c050000c405000000010000,PS4 Controller (Bluetooth),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,",
+ "060000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,",
+ "03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,",
+ "03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,dpup:b12,dpleft:b15,dpdown:b14,dpright:b13,",
+ "05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,",
+ "05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,",
+ "030000008916000001fd000024010000,Razer Onza Classic Edition,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:b11,dpdown:b14,dpright:b12,dpup:b13,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,",
+ "030000005e040000d102000001010000,Microsoft X-Box One pad,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,",
+ "03000000790000001100000010010000,RetroLink Saturn Classic Controller,platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b5,guide:b2,start:b8,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,",
+ "050000007e0500003003000001000000,Nintendo Wii U Pro Controller,platform:Linux,a:b0,b:b1,x:b3,y:b2,back:b8,start:b9,guide:b10,leftshoulder:b4,rightshoulder:b5,leftstick:b11,rightstick:b12,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:b13,dpleft:b15,dpdown:b14,dpright:b16,",
+ "030000005e0400008e02000004010000,Microsoft X-Box 360 pad,platform:Linux,a:b0,b:b1,x:b2,y:b3,back:b6,start:b7,guide:b8,leftshoulder:b4,rightshoulder:b5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,",
+ "030000000d0f00002200000011010000,HORI CO.,LTD. REAL ARCADE Pro.V3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,",
+ "030000000d0f00001000000011010000,HORI CO.,LTD. FIGHTING STICK 3,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7",
+ "03000000f0250000c183000010010000,Goodbetterbest Ltd USB Controller,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,guide:b12,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,",
+ "0000000058626f782047616d65706100,Xbox Gamepad (userspace driver),platform:Linux,a:b0,b:b1,x:b2,y:b3,start:b7,back:b6,guide:b8,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftshoulder:b4,rightshoulder:b5,lefttrigger:a5,righttrigger:a4,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a2,righty:a3,",
+ "03000000ff1100003133000010010000,PC Game Controller,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Linux,",
+ #endif
+
+ #if defined(__ANDROID__)
+ "4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+ #endif
+ NULL
+};
+
+InputDefault::InputDefault() {
+
+ mouse_button_mask=0;
+ emulate_touch=false;
+ main_loop=NULL;
+
+ hat_map_default[HAT_UP].type = TYPE_BUTTON;
+ hat_map_default[HAT_UP].index = JOY_DPAD_UP;
+ hat_map_default[HAT_UP].value = 0;
+
+ hat_map_default[HAT_RIGHT].type = TYPE_BUTTON;
+ hat_map_default[HAT_RIGHT].index = JOY_DPAD_RIGHT;
+ hat_map_default[HAT_RIGHT].value = 0;
+
+ hat_map_default[HAT_DOWN].type = TYPE_BUTTON;
+ hat_map_default[HAT_DOWN].index = JOY_DPAD_DOWN;
+ hat_map_default[HAT_DOWN].value = 0;
+
+ hat_map_default[HAT_LEFT].type = TYPE_BUTTON;
+ hat_map_default[HAT_LEFT].index = JOY_DPAD_LEFT;
+ hat_map_default[HAT_LEFT].value = 0;
+
+ String env_mapping = OS::get_singleton()->get_environment("SDL_GAMECONTROLLERCONFIG");
+ if (env_mapping != "") {
+
+ Vector<String> entries = env_mapping.split("\n");
+ for (int i=0; i < entries.size(); i++) {
+ if (entries[i] == "")
+ continue;
+ parse_mapping(entries[i]);
+ };
+ };
+
+ int i = 0;
+ while (s_ControllerMappings[i]) {
+
+ parse_mapping(s_ControllerMappings[i++]);
+ };
+}
+
+
+uint32_t InputDefault::joy_button(uint32_t p_last_id, int p_device, int p_button, bool p_pressed) {
+
+ _THREAD_SAFE_METHOD_;
+ Joystick& joy = joy_names[p_device];
+ //printf("got button %i, mapping is %i\n", p_button, joy.mapping);
+ if (joy.last_buttons[p_button] == p_pressed) {
+ return p_last_id;
+ //printf("same button value\n");
+ }
+ joy.last_buttons[p_button] = p_pressed;
+ if (joy.mapping == -1) {
+ return _button_event(p_last_id, p_device, p_button, p_pressed);
+ };
+
+ Map<int,JoyEvent>::Element* el = map_db[joy.mapping].buttons.find(p_button);
+ if (!el) {
+ //don't process un-mapped events for now, it could mess things up badly for devices with additional buttons/axis
+ //return _button_event(p_last_id, p_device, p_button, p_pressed);
+ return p_last_id;
+ };
+
+ JoyEvent map = el->get();
+ if (map.type == TYPE_BUTTON) {
+ //fake additional axis event for triggers
+ if (map.index == JOY_L2 || map.index == JOY_R2) {
+ float value = p_pressed ? 1.0f : 0.0f;
+ int axis = map.index == JOY_L2 ? JOY_ANALOG_L2 : JOY_ANALOG_R2;
+ p_last_id = _axis_event(p_last_id, p_device, axis, value);
+ }
+ return _button_event(p_last_id, p_device, map.index, p_pressed);
+ };
+
+ if (map.type == TYPE_AXIS) {
+ return _axis_event(p_last_id, p_device, map.index, p_pressed ? 1.0 : 0.0);
+ };
+
+ return p_last_id; // no event?
+};
+
+uint32_t InputDefault::joy_axis(uint32_t p_last_id, int p_device, int p_axis, const JoyAxis& p_value) {
+
+ _THREAD_SAFE_METHOD_;
+
+ Joystick& joy = joy_names[p_device];
+
+ if (joy.last_axis[p_axis] == p_value.value) {
+ return p_last_id;
+ }
+
+ if (p_value.value > joy.last_axis[p_axis]) {
+
+ if (p_value.value < joy.last_axis[p_axis] + joy.filter ) {
+
+ return p_last_id;
+ }
+ }
+ else if (p_value.value > joy.last_axis[p_axis] - joy.filter) {
+
+ return p_last_id;
+ }
+
+
+ joy.last_axis[p_axis] = p_value.value;
+ float val = p_value.min == 0 ? -1.0f + 2.0f * p_value.value : p_value.value;
+
+ if (joy.mapping == -1) {
+ return _axis_event(p_last_id, p_device, p_axis, val);
+ };
+
+ Map<int,JoyEvent>::Element* el = map_db[joy.mapping].axis.find(p_axis);
+ if (!el) {
+ //return _axis_event(p_last_id, p_device, p_axis, p_value);
+ return p_last_id;
+ };
+
+
+ JoyEvent map = el->get();
+
+ if (map.type == TYPE_BUTTON) {
+ //send axis event for triggers
+ if (map.index == JOY_L2 || map.index == JOY_R2) {
+ float value = p_value.min == 0 ? p_value.value : 0.5f + p_value.value / 2.0f;
+ int axis = map.index == JOY_L2 ? JOY_ANALOG_L2 : JOY_ANALOG_R2;
+ p_last_id = _axis_event(p_last_id, p_device, axis, value);
+ }
+ float deadzone = p_value.min == 0 ? 0.5f : 0.0f;
+ bool pressed = p_value.value > deadzone ? true : false;
+ if (pressed == joy_buttons_pressed.has(_combine_device(map.index,p_device))) {
+ // button already pressed or released, this is an axis bounce value
+ return p_last_id;
+ };
+ return _button_event(p_last_id, p_device, map.index, pressed);
+ };
+
+ if (map.type == TYPE_AXIS) {
+
+ return _axis_event(p_last_id, p_device, map.index, val );
+ };
+ //printf("invalid mapping\n");
+ return p_last_id;
+};
+
+uint32_t InputDefault::joy_hat(uint32_t p_last_id, int p_device, int p_val) {
+
+ _THREAD_SAFE_METHOD_;
+ const Joystick& joy = joy_names[p_device];
+
+ JoyEvent* map;
+
+ if (joy.mapping == -1) {
+ map = hat_map_default;
+ } else {
+ map = map_db[joy.mapping].hat;
+ };
+
+ int cur_val = joy_names[p_device].hat_current;
+
+ if ( (p_val & HAT_MASK_UP) != (cur_val & HAT_MASK_UP) ) {
+ p_last_id = _button_event(p_last_id, p_device, map[HAT_UP].index, p_val & HAT_MASK_UP);
+ };
+
+ if ( (p_val & HAT_MASK_RIGHT) != (cur_val & HAT_MASK_RIGHT) ) {
+ p_last_id = _button_event(p_last_id, p_device, map[HAT_RIGHT].index, p_val & HAT_MASK_RIGHT);
+ };
+ if ( (p_val & HAT_MASK_DOWN) != (cur_val & HAT_MASK_DOWN) ) {
+ p_last_id = _button_event(p_last_id, p_device, map[HAT_DOWN].index, p_val & HAT_MASK_DOWN);
+ };
+ if ( (p_val & HAT_MASK_LEFT) != (cur_val & HAT_MASK_LEFT) ) {
+ p_last_id = _button_event(p_last_id, p_device, map[HAT_LEFT].index, p_val & HAT_MASK_LEFT);
+ };
+
+ joy_names[p_device].hat_current = p_val;
+
+ return p_last_id;
+};
+
+uint32_t InputDefault::_button_event(uint32_t p_last_id, int p_device, int p_index, bool p_pressed) {
+
+ InputEvent ievent;
+ ievent.type = InputEvent::JOYSTICK_BUTTON;
+ ievent.device = p_device;
+ ievent.ID = ++p_last_id;
+ ievent.joy_button.button_index = p_index;
+ ievent.joy_button.pressed = p_pressed;
+
+ parse_input_event(ievent);
+
+ return p_last_id;
+};
+
+uint32_t InputDefault::_axis_event(uint32_t p_last_id, int p_device, int p_axis, float p_value) {
+
+ InputEvent ievent;
+ ievent.type = InputEvent::JOYSTICK_MOTION;
+ ievent.device = p_device;
+ ievent.ID = ++p_last_id;
+ ievent.joy_motion.axis = p_axis;
+ ievent.joy_motion.axis_value = p_value;
+
+ parse_input_event( ievent );
+
+ return p_last_id;
+};
+
+InputDefault::JoyEvent InputDefault::_find_to_event(String p_to) {
+
+ // string names of the SDL buttons in the same order as input_event.h godot buttons
+ static const char* buttons[] = {"a", "b", "x", "y", "leftshoulder", "rightshoulder", "lefttrigger", "righttrigger", "leftstick", "rightstick", "back", "start", "dpup", "dpdown", "dpleft", "dpright", "guide", NULL };
+
+ static const char* axis[] = {"leftx", "lefty", "rightx", "righty", NULL };
+
+ JoyEvent ret;
+ ret.type = -1;
+
+ int i=0;
+ while (buttons[i]) {
+
+ if (p_to == buttons[i]) {
+ //printf("mapping button %s\n", buttons[i]);
+ ret.type = TYPE_BUTTON;
+ ret.index = i;
+ ret.value = 0;
+ return ret;
+ };
+ ++i;
+ };
+
+ i = 0;
+ while (axis[i]) {
+
+ if (p_to == axis[i]) {
+ ret.type = TYPE_AXIS;
+ ret.index = i;
+ ret.value = 0;
+ return ret;
+ };
+ ++i;
+ };
+
+ return ret;
+};
+
+void InputDefault::parse_mapping(String p_mapping) {
+
+ _THREAD_SAFE_METHOD_;
+ JoyDeviceMapping mapping;
+
+ Vector<String> entry = p_mapping.split(",");
+ CharString uid;
+ uid.resize(17);
+
+ mapping.uid = entry[0];
+
+ int idx = 1;
+ while (++idx < entry.size()) {
+
+ if (entry[idx] == "")
+ continue;
+
+ String from = entry[idx].get_slice(":", 1);
+ String to = entry[idx].get_slice(":", 0);
+
+ JoyEvent to_event = _find_to_event(to);
+ if (to_event.type == -1)
+ continue;
+
+ String etype = from.substr(0, 1);
+ if (etype == "a") {
+
+ int aid = from.substr(1, from.length()-1).to_int();
+ mapping.axis[aid] = to_event;
+
+ } else if (etype == "b") {
+
+ int bid = from.substr(1, from.length()-1).to_int();
+ mapping.buttons[bid] = to_event;
+
+ } else if (etype == "h") {
+
+ int hat_value = from.get_slice(".", 1).to_int();
+ switch (hat_value) {
+ case 1:
+ mapping.hat[HAT_UP] = to_event;
+ break;
+ case 2:
+ mapping.hat[HAT_RIGHT] = to_event;
+ break;
+ case 4:
+ mapping.hat[HAT_DOWN] = to_event;
+ break;
+ case 8:
+ mapping.hat[HAT_LEFT] = to_event;
+ break;
+ };
+ };
+ };
+ map_db.push_back(mapping);
+ //printf("added mapping with uuid %ls\n", mapping.uid.c_str());
+};
+
+void InputDefault::add_joy_mapping(String p_mapping, bool p_update_existing) {
+ parse_mapping(p_mapping);
+ if (p_update_existing) {
+ Vector<String> entry = p_mapping.split(",");
+ String uid = entry[0];
+ for (int i=0; i<joy_names.size(); i++) {
+ if (uid == joy_names[i].uid) {
+ joy_names[i].mapping = map_db.size() -1;
+ }
+ }
+ }
+}
+
+void InputDefault::remove_joy_mapping(String p_guid) {
+ for (int i=map_db.size()-1; i >= 0;i--) {
+ if (p_guid == map_db[i].uid) {
+ map_db.remove(i);
+ }
+ }
+ for (int i=0; i<joy_names.size(); i++) {
+ if (joy_names[i].uid == p_guid) {
+ joy_names[i].mapping = -1;
+ }
+ }
+}
+
+//Defaults to simple implementation for platforms with a fixed gamepad layout, like consoles.
+bool InputDefault::is_joy_known(int p_device) {
+
+ return OS::get_singleton()->is_joy_known(p_device);
+}
+
+String InputDefault::get_joy_guid(int p_device) const {
+ return OS::get_singleton()->get_joy_guid(p_device);
+}
+
+//platforms that use the remapping system can override and call to these ones
+bool InputDefault::is_joy_mapped(int p_device) {
+ return joy_names[p_device].mapping != -1 ? true : false;
+}
+
+String InputDefault::get_joy_guid_remapped(int p_device) const {
+ return joy_names[p_device].uid;
+}
+
diff --git a/main/input_default.h b/main/input_default.h
new file mode 100644
index 0000000000..bbfd9ced2c
--- /dev/null
+++ b/main/input_default.h
@@ -0,0 +1,176 @@
+#ifndef INPUT_DEFAULT_H
+#define INPUT_DEFAULT_H
+
+#include "os/input.h"
+
+class InputDefault : public Input {
+
+ OBJ_TYPE( InputDefault, Input );
+ _THREAD_SAFE_CLASS_
+
+ int mouse_button_mask;
+ Set<int> keys_pressed;
+ Set<int> joy_buttons_pressed;
+ Map<int,float> _joy_axis;
+ Map<StringName,int> custom_action_press;
+ Vector3 accelerometer;
+ Vector2 mouse_pos;
+ MainLoop *main_loop;
+
+ bool emulate_touch;
+
+ struct SpeedTrack {
+
+ uint64_t last_tick;
+ Vector2 speed;
+ Vector2 accum;
+ float accum_t;
+ float min_ref_frame;
+ float max_ref_frame;
+
+ void update(const Vector2& p_delta_p);
+ void reset();
+ SpeedTrack();
+ };
+
+ struct Joystick {
+ StringName name;
+ StringName uid;
+ bool last_buttons[JOY_BUTTON_MAX];
+ float last_axis[JOY_AXIS_MAX];
+ float filter;
+ int last_hat;
+ int mapping;
+ int hat_current;
+
+ Joystick() {
+
+ for (int i = 0; i < JOY_AXIS_MAX; i++) {
+
+ last_axis[i] = 0.0f;
+
+ }
+ for (int i = 0; i < JOY_BUTTON_MAX; i++) {
+
+ last_buttons[i] = false;
+ }
+ last_hat = HAT_MASK_CENTER;
+ filter = 0.01f;
+ mapping = -1;
+ }
+ };
+
+ SpeedTrack mouse_speed_track;
+ Map<int, Joystick> joy_names;
+ RES custom_cursor;
+public:
+ enum HatMask {
+ HAT_MASK_CENTER = 0,
+ HAT_MASK_UP = 1,
+ HAT_MASK_RIGHT = 2,
+ HAT_MASK_DOWN = 4,
+ HAT_MASK_LEFT = 8,
+ };
+
+ enum HatDir {
+ HAT_UP,
+ HAT_RIGHT,
+ HAT_DOWN,
+ HAT_LEFT,
+ HAT_MAX,
+ };
+ struct JoyAxis {
+ int min;
+ float value;
+ };
+
+private:
+
+ enum JoyType {
+ TYPE_BUTTON,
+ TYPE_AXIS,
+ TYPE_HAT,
+ TYPE_MAX,
+ };
+
+ struct JoyEvent {
+ int type;
+ int index;
+ int value;
+ };
+
+ struct JoyDeviceMapping {
+
+ String uid;
+ Map<int,JoyEvent> buttons;
+ Map<int,JoyEvent> axis;
+ JoyEvent hat[HAT_MAX];
+ };
+
+ JoyEvent hat_map_default[HAT_MAX];
+
+ Vector<JoyDeviceMapping> map_db;
+
+ JoyEvent _find_to_event(String p_to);
+ uint32_t _button_event(uint32_t p_last_id, int p_device, int p_index, bool p_pressed);
+ uint32_t _axis_event(uint32_t p_last_id, int p_device, int p_axis, float p_value);
+ float _handle_deadzone(int p_device, int p_axis, float p_value);
+
+public:
+
+
+
+ virtual bool is_key_pressed(int p_scancode);
+ virtual bool is_mouse_button_pressed(int p_button);
+ virtual bool is_joy_button_pressed(int p_device, int p_button);
+ virtual bool is_action_pressed(const StringName& p_action);
+
+ virtual float get_joy_axis(int p_device,int p_axis);
+ String get_joy_name(int p_idx);
+ void joy_connection_changed(int p_idx, bool p_connected, String p_name, String p_guid = "");
+ void parse_joystick_mapping(String p_mapping, bool p_update_existing);
+
+ virtual Vector3 get_accelerometer();
+
+ virtual Point2 get_mouse_pos() const;
+ virtual Point2 get_mouse_speed() const;
+ virtual int get_mouse_button_mask() const;
+
+ virtual void warp_mouse_pos(const Vector2& p_to);
+
+
+ void parse_input_event(const InputEvent& p_event);
+ void set_accelerometer(const Vector3& p_accel);
+ void set_joy_axis(int p_device,int p_axis,float p_value);
+
+ void set_main_loop(MainLoop *main_loop);
+ void set_mouse_pos(const Point2& p_posf);
+
+ void action_press(const StringName& p_action);
+ void action_release(const StringName& p_action);
+
+ void iteration(float p_step);
+
+ void set_emulate_touch(bool p_emulate);
+ virtual bool is_emulating_touchscreen() const;
+
+ virtual void set_custom_mouse_cursor(const RES& p_cursor,const Vector2& p_hotspot=Vector2());
+ virtual void set_mouse_in_window(bool p_in_window);
+
+ void parse_mapping(String p_mapping);
+ uint32_t joy_button(uint32_t p_last_id, int p_device, int p_button, bool p_pressed);
+ uint32_t joy_axis(uint32_t p_last_id, int p_device, int p_axis, const JoyAxis& p_value);
+ uint32_t joy_hat(uint32_t p_last_id, int p_device, int p_val);
+
+ virtual void add_joy_mapping(String p_mapping, bool p_update_existing=false);
+ virtual void remove_joy_mapping(String p_guid);
+ virtual bool is_joy_known(int p_device);
+ virtual String get_joy_guid(int p_device) const;
+
+ bool is_joy_mapped(int p_device);
+ String get_joy_guid_remapped(int p_device) const;
+
+ InputDefault();
+};
+
+#endif // INPUT_DEFAULT_H
diff --git a/main/main.cpp b/main/main.cpp
index 15f969f466..19fe037613 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -56,7 +56,7 @@
#ifdef TOOLS_ENABLED
#include "tools/editor/editor_node.h"
#include "tools/editor/project_manager.h"
-#include "tools/editor/console.h"
+
#include "tools/pck/pck_packer.h"
#endif
@@ -75,7 +75,7 @@
#include "core/io/file_access_zip.h"
#include "translation.h"
#include "version.h"
-
+#include "main/input_default.h"
#include "performance.h"
static Globals *globals=NULL;
@@ -94,11 +94,18 @@ static FileAccessNetworkClient *file_access_network_client=NULL;
static TranslationServer *translation_server = NULL;
static OS::VideoMode video_mode;
+static bool init_maximized=false;
+static bool init_windowed=false;
+static bool init_fullscreen=false;
+static bool init_use_custom_pos=false;
+static bool debug_collisions=false;
+static bool debug_navigation=false;
+static Vector2 init_custom_pos;
static int video_driver_idx=-1;
static int audio_driver_idx=-1;
static String locale;
-static bool init_maximized=false;
+
static int init_screen=-1;
static String unescape_cmdline(const String& p_str) {
@@ -117,7 +124,7 @@ static String unescape_cmdline(const String& p_str) {
void Main::print_help(const char* p_binary) {
- OS::get_singleton()->print(VERSION_FULL_NAME" (c) 2008-2015 Juan Linietsky, Ariel Manzur.\n");
+ OS::get_singleton()->print(VERSION_FULL_NAME" (c) 2008-2016 Juan Linietsky, Ariel Manzur.\n");
OS::get_singleton()->print("Usage: %s [options] [scene]\n",p_binary);
OS::get_singleton()->print("Options:\n");
OS::get_singleton()->print("\t-path [dir] : Path to a game, containing engine.cfg\n");
@@ -136,8 +143,11 @@ void Main::print_help(const char* p_binary) {
}
OS::get_singleton()->print(")\n");
- OS::get_singleton()->print("\t-r WIDTHxHEIGHT\t : Request Screen Resolution\n");
+ OS::get_singleton()->print("\t-r WIDTHxHEIGHT\t : Request Window Resolution\n");
+ OS::get_singleton()->print("\t-p XxY\t : Request Window Position\n");
OS::get_singleton()->print("\t-f\t\t : Request Fullscreen\n");
+ OS::get_singleton()->print("\t-mx\t\t Request Maximized\n");
+ OS::get_singleton()->print("\t-w\t\t Request Windowed\n");
OS::get_singleton()->print("\t-vd DRIVER\t : Video Driver (");
for (int i=0;i<OS::get_singleton()->get_video_driver_count();i++) {
@@ -287,6 +297,7 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
if (vm.find("x")==-1) { // invalid parameter format
+ OS::get_singleton()->print("Invalid -r argument: %s\n",vm.utf8().get_data());
goto error;
@@ -297,6 +308,7 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
if (w==0 || h==0) {
+ OS::get_singleton()->print("Invalid -r resolution, x and y must be >0\n");
goto error;
}
@@ -307,11 +319,46 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
N=I->next()->next();
} else {
+ OS::get_singleton()->print("Invalid -p argument, needs resolution\n");
goto error;
}
-
+ } else if (I->get()=="-p") { // position
+
+ if (I->next()) {
+
+ String vm=I->next()->get();
+
+ if (vm.find("x")==-1) { // invalid parameter format
+
+ OS::get_singleton()->print("Invalid -p argument: %s\n",vm.utf8().get_data());
+ goto error;
+
+
+ }
+
+ int x=vm.get_slice("x",0).to_int();
+ int y=vm.get_slice("x",1).to_int();
+
+ init_custom_pos=Point2(x,y);
+ init_use_custom_pos=true;
+
+ N=I->next()->next();
+ } else {
+ OS::get_singleton()->print("Invalid -r argument, needs position\n");
+ goto error;
+
+
+ }
+
+
+ } else if (I->get()=="-mx") { // video driver
+
+ init_maximized=true;
+ } else if (I->get()=="-w") { // video driver
+
+ init_windowed=true;
} else if (I->get()=="-vd") { // video driver
if (I->next()) {
@@ -319,6 +366,7 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
video_driver=I->next()->get();
N=I->next()->next();
} else {
+ OS::get_singleton()->print("Invalid -cd argument, needs driver name\n");
goto error;
}
@@ -329,6 +377,7 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
locale=I->next()->get();
N=I->next()->next();
} else {
+ OS::get_singleton()->print("Invalid -lang argument, needs language code\n");
goto error;
}
@@ -383,11 +432,11 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
} else if (I->get()=="-f") { // fullscreen
- video_mode.fullscreen=true;
+ //video_mode.fullscreen=false;
+ init_fullscreen=true;
} else if (I->get()=="-e" || I->get()=="-editor") { // fonud editor
editor=true;
- init_maximized=true;
} else if (I->get()=="-nowindow") { // fullscreen
OS::get_singleton()->set_no_window_mode(true);
@@ -406,7 +455,6 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
} else {
game_path=I->next()->get(); //use game_path instead
}
-
N=I->next()->next();
} else {
goto error;
@@ -472,6 +520,10 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
} else if (I->get()=="-debug" || I->get()=="-d") {
debug_mode="local";
+ } else if (I->get()=="-debugcol" || I->get()=="-dc") {
+ debug_collisions=true;
+ } else if (I->get()=="-debugnav" || I->get()=="-dn") {
+ debug_navigation=true;
} else if (I->get()=="-editor_scene") {
if (I->next()) {
@@ -487,8 +539,10 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
debug_mode="remote";
debug_host=I->next()->get();
- if (debug_host.find(":")==-1) //wrong host
+ if (debug_host.find(":")==-1) { //wrong host
+ OS::get_singleton()->print("Invalid debug host string\n");
goto error;
+ }
N=I->next()->next();
} else {
goto error;
@@ -518,14 +572,14 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
}
-
+ GLOBAL_DEF("debug/max_remote_stdout_chars_per_second",2048);
if (debug_mode == "remote") {
ScriptDebuggerRemote *sdr = memnew( ScriptDebuggerRemote );
uint16_t debug_port = GLOBAL_DEF("debug/remote_port",6007);
if (debug_host.find(":")!=-1) {
- debug_port=debug_host.get_slice(":",1).to_int();
- debug_host=debug_host.get_slice(":",0);
+ debug_port=debug_host.get_slicec(':',1).to_int();
+ debug_host=debug_host.get_slicec(':',0);
}
Error derr = sdr->connect_to_host(debug_host,debug_port);
@@ -546,8 +600,8 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
file_access_network_client=memnew(FileAccessNetworkClient);
int port;
if (remotefs.find(":")!=-1) {
- port=remotefs.get_slice(":",1).to_int();
- remotefs=remotefs.get_slice(":",0);
+ port=remotefs.get_slicec(':',1).to_int();
+ remotefs=remotefs.get_slicec(':',0);
} else {
port=6010;
}
@@ -599,12 +653,16 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
if (editor) {
main_args.push_back("-editor");
+ init_maximized=true;
use_custom_res=false;
}
if (bool(Globals::get_singleton()->get("application/disable_stdout"))) {
quiet_stdout=true;
}
+ if (bool(Globals::get_singleton()->get("application/disable_stderr"))) {
+ _print_error_enabled = false;
+ };
if (quiet_stdout)
_print_line_enabled=false;
@@ -648,6 +706,8 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
GLOBAL_DEF("display/resizable",video_mode.resizable);
GLOBAL_DEF("display/test_width",0);
GLOBAL_DEF("display/test_height",0);
+ OS::get_singleton()->_pixel_snap=GLOBAL_DEF("display/use_2d_pixel_snap",false);
+ OS::get_singleton()->_keep_screen_on=GLOBAL_DEF("display/keep_screen_on",true);
if (rtm==-1) {
rtm=GLOBAL_DEF("render/thread_model",OS::RENDER_THREAD_SAFE);
if (rtm>=1) //hack for now
@@ -655,8 +715,12 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
}
- if (rtm>=0 && rtm<3)
+ if (rtm>=0 && rtm<3) {
+ if (editor) {
+ rtm=OS::RENDER_THREAD_SAFE;
+ }
OS::get_singleton()->_render_thread_mode=OS::RenderThreadMode(rtm);
+ }
@@ -729,6 +793,7 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
if (p_second_phase)
return setup2();
+
return OK;
error:
@@ -741,7 +806,6 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
main_args.clear();
print_help(execpath);
-
if (performance)
memdelete(performance);
@@ -757,6 +821,8 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
memdelete(packed_data);
if (file_access_network_client)
memdelete(file_access_network_client);
+ if(path_remap)
+ memdelete(path_remap);
// Note 1: *zip_packed_data live into *packed_data
// Note 2: PackedData::~PackedData destroy this.
@@ -765,7 +831,7 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
// memdelete( zip_packed_data );
//#endif
-
+ unregister_core_driver_types();
unregister_core_types();
OS::get_singleton()->_cmdline.clear();
@@ -782,6 +848,10 @@ Error Main::setup2() {
OS::get_singleton()->initialize(video_mode,video_driver_idx,audio_driver_idx);
+ if (init_use_custom_pos) {
+ OS::get_singleton()->set_window_position(init_custom_pos);
+ }
+
register_core_singletons();
@@ -795,20 +865,29 @@ Error Main::setup2() {
if (init_screen!=-1) {
OS::get_singleton()->set_current_screen(init_screen);
}
- if (init_maximized) {
+ if (init_windowed) {
+ //do none..
+ } else if (init_maximized) {
OS::get_singleton()->set_window_maximized(true);
+ } else if (init_fullscreen) {
+ OS::get_singleton()->set_window_fullscreen(true);
}
+ MAIN_PRINT("Main: Load Remaps");
+
+ path_remap->load_remaps();
if (show_logo) { //boot logo!
String boot_logo_path=GLOBAL_DEF("application/boot_splash",String());
bool boot_logo_scale=GLOBAL_DEF("application/boot_splash_fullsize",true);
Globals::get_singleton()->set_custom_property_info("application/boot_splash",PropertyInfo(Variant::STRING,"application/boot_splash",PROPERTY_HINT_FILE,"*.png"));
-
Image boot_logo;
- if (boot_logo_path.strip_edges()!="" && FileAccess::exists(boot_logo_path)) {
- boot_logo.load(boot_logo_path);
+ boot_logo_path = boot_logo_path.strip_edges();
+
+ if (boot_logo_path!=String() /*&& FileAccess::exists(boot_logo_path)*/) {
+ print_line("Boot splash path: "+boot_logo_path);
+ Error err = boot_logo.load(boot_logo_path);
}
if (!boot_logo.empty()) {
@@ -819,13 +898,13 @@ Error Main::setup2() {
VisualServer::get_singleton()->set_boot_image(boot_logo, boot_bg,boot_logo_scale);
#ifndef TOOLS_ENABLED
//no tools, so free the boot logo (no longer needed)
- Globals::get_singleton()->set("application/boot_logo",Image());
+ // Globals::get_singleton()->set("application/boot_logo",Image());
#endif
} else {
#ifndef NO_DEFAULT_BOOT_LOGO
- MAIN_PRINT("Main: Create botsplash");
+ MAIN_PRINT("Main: Create bootsplash");
Image splash(boot_splash_png);
MAIN_PRINT("Main: ClearColor");
@@ -844,15 +923,38 @@ Error Main::setup2() {
GLOBAL_DEF("application/icon",String());
Globals::get_singleton()->set_custom_property_info("application/icon",PropertyInfo(Variant::STRING,"application/icon",PROPERTY_HINT_FILE,"*.png,*.webp"));
- MAIN_PRINT("Main: Load Remaps");
+ if (bool(GLOBAL_DEF("display/emulate_touchscreen",false))) {
+ if (!OS::get_singleton()->has_touchscreen_ui_hint() && Input::get_singleton()) {
+ //only if no touchscreen ui hint, set emulation
+ InputDefault *id = Input::get_singleton()->cast_to<InputDefault>();
+ if (id)
+ id->set_emulate_touch(true);
+ }
+ }
- path_remap->load_remaps();
+
+
+ MAIN_PRINT("Main: Load Remaps");
MAIN_PRINT("Main: Load Scene Types");
register_scene_types();
register_server_types();
+ GLOBAL_DEF("display/custom_mouse_cursor",String());
+ GLOBAL_DEF("display/custom_mouse_cursor_hotspot",Vector2());
+ Globals::get_singleton()->set_custom_property_info("display/custom_mouse_cursor",PropertyInfo(Variant::STRING,"display/custom_mouse_cursor",PROPERTY_HINT_FILE,"*.png,*.webp"));
+
+ if (String(Globals::get_singleton()->get("display/custom_mouse_cursor"))!=String()) {
+
+ //print_line("use custom cursor");
+ Ref<Texture> cursor=ResourceLoader::load(Globals::get_singleton()->get("display/custom_mouse_cursor"));
+ if (cursor.is_valid()) {
+ // print_line("loaded ok");
+ Vector2 hotspot = Globals::get_singleton()->get("display/custom_mouse_cursor_hotspot");
+ Input::get_singleton()->set_custom_mouse_cursor(cursor,hotspot);
+ }
+ }
#ifdef TOOLS_ENABLED
EditorNode::register_editor_types();
ObjectTypeDB::register_type<PCKPacker>(); // todo: move somewhere else
@@ -909,63 +1011,57 @@ bool Main::start() {
bool export_debug=false;
List<String> args = OS::get_singleton()->get_cmdline_args();
for (int i=0;i<args.size();i++) {
-
-
- if (args[i]=="-doctool" && i <(args.size()-1)) {
-
- doc_tool=args[i+1];
- i++;
- }else if (args[i]=="-nodocbase") {
-
+ //parameters that do not have an argument to the right
+ if (args[i]=="-nodocbase") {
doc_base=false;
- } else if ((args[i]=="-script" || args[i]=="-s") && i <(args.size()-1)) {
-
- script=args[i+1];
- i++;
- } else if ((args[i]=="-level" || args[i]=="-l") && i <(args.size()-1)) {
-
- OS::get_singleton()->_custom_level=args[i+1];
- i++;
- } else if (args[i]=="-test" && i <(args.size()-1)) {
- test=args[i+1];
- i++;
- } else if (args[i]=="-optimize" && i <(args.size()-1)) {
- optimize=args[i+1];
- i++;
- } else if (args[i]=="-optimize_preset" && i <(args.size()-1)) {
- optimize_preset=args[i+1];
- i++;
- } else if (args[i]=="-export" && i <(args.size()-1)) {
- editor=true; //needs editor
- _export_platform=args[i+1];
- i++;
- } else if (args[i]=="-export_debug" && i <(args.size()-1)) {
- editor=true; //needs editor
- _export_platform=args[i+1];
- export_debug=true;
- i++;
- } else if (args[i]=="-import" && i <(args.size()-1)) {
- editor=true; //needs editor
- _import=args[i+1];
- i++;
- } else if (args[i]=="-import_script" && i <(args.size()-1)) {
- editor=true; //needs editor
- _import_script=args[i+1];
- i++;
- } else if (args[i]=="-noquit" ) {
+ } else if (args[i]=="-noquit") {
noquit=true;
- } else if (args[i]=="-dumpstrings" && i <(args.size()-1)) {
- editor=true; //needs editor
- dumpstrings=args[i+1];
- i++;
- } else if (args[i]=="-editor" || args[i]=="-e") {
- editor=true;
} else if (args[i]=="-convert_old") {
convert_old=true;
+ } else if (args[i]=="-editor" || args[i]=="-e") {
+ editor=true;
} else if (args[i].length() && args[i][0] != '-' && game_path == "") {
-
game_path=args[i];
}
+ //parameters that have an argument to the right
+ else if (i < (args.size()-1)) {
+ bool parsed_pair=true;
+ if (args[i]=="-doctool") {
+ doc_tool=args[i+1];
+ } else if (args[i]=="-script" || args[i]=="-s") {
+ script=args[i+1];
+ } else if (args[i]=="-level" || args[i]=="-l") {
+ OS::get_singleton()->_custom_level=args[i+1];
+ } else if (args[i]=="-test") {
+ test=args[i+1];
+ } else if (args[i]=="-optimize") {
+ optimize=args[i+1];
+ } else if (args[i]=="-optimize_preset") {
+ optimize_preset=args[i+1];
+ } else if (args[i]=="-export") {
+ editor=true; //needs editor
+ _export_platform=args[i+1];
+ } else if (args[i]=="-export_debug") {
+ editor=true; //needs editor
+ _export_platform=args[i+1];
+ export_debug=true;
+ } else if (args[i]=="-import") {
+ editor=true; //needs editor
+ _import=args[i+1];
+ } else if (args[i]=="-import_script") {
+ editor=true; //needs editor
+ _import_script=args[i+1];
+ } else if (args[i]=="-dumpstrings") {
+ editor=true; //needs editor
+ dumpstrings=args[i+1];
+ } else {
+ // The parameter does not match anything known, don't skip the next argument
+ parsed_pair=false;
+ }
+ if (parsed_pair) {
+ i++;
+ }
+ }
}
if (editor)
@@ -1000,7 +1096,18 @@ bool Main::start() {
#endif
- if(script=="" && game_path=="" && !editor && String(GLOBAL_DEF("application/main_scene",""))!="") {
+ if (_export_platform!="") {
+ if (game_path=="") {
+ String err="Command line param ";
+ err+=export_debug?"-export_debug":"-export";
+ err+=" passed but no destination path given.\n";
+ err+="Please specify the binary's file path to export to. Aborting export.";
+ ERR_PRINT(err.utf8().get_data());
+ return false;
+ }
+ }
+
+ if(script=="" && game_path=="" && String(GLOBAL_DEF("application/main_scene",""))!="") {
game_path=GLOBAL_DEF("application/main_scene","");
}
@@ -1080,8 +1187,15 @@ bool Main::start() {
SceneTree *sml = main_loop->cast_to<SceneTree>();
+ if (debug_collisions) {
+ sml->set_debug_collisions_hint(true);
+ }
+ if (debug_navigation) {
+ sml->set_debug_navigation_hint(true);
+ }
#ifdef TOOLS_ENABLED
+
EditorNode *editor_node=NULL;
if (editor) {
@@ -1214,13 +1328,43 @@ bool Main::start() {
//autoload
List<PropertyInfo> props;
Globals::get_singleton()->get_property_list(&props);
+
+ //first pass, add the constants so they exist before any script is loaded
for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) {
String s = E->get().name;
if (!s.begins_with("autoload/"))
continue;
- String name = s.get_slice("/",1);
+ String name = s.get_slicec('/',1);
String path = Globals::get_singleton()->get(s);
+ bool global_var=false;
+ if (path.begins_with("*")) {
+ global_var=true;
+ }
+
+ if (global_var) {
+ for(int i=0;i<ScriptServer::get_language_count();i++) {
+ ScriptServer::get_language(i)->add_global_constant(name,Variant());
+ }
+ }
+
+ }
+
+ //second pass, load into global constants
+ List<Node*> to_add;
+ for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) {
+
+ String s = E->get().name;
+ if (!s.begins_with("autoload/"))
+ continue;
+ String name = s.get_slicec('/',1);
+ String path = Globals::get_singleton()->get(s);
+ bool global_var=false;
+ if (path.begins_with("*")) {
+ global_var=true;
+ path=path.substr(1,path.length()-1);
+ }
+
RES res = ResourceLoader::load(path);
ERR_EXPLAIN("Can't autoload: "+path);
ERR_CONTINUE(res.is_null());
@@ -1231,12 +1375,13 @@ bool Main::start() {
} else if (res->is_type("Script")) {
Ref<Script> s = res;
StringName ibt = s->get_instance_base_type();
+ bool valid_type = ObjectTypeDB::is_type(ibt,"Node");
ERR_EXPLAIN("Script does not inherit a Node: "+path);
- ERR_CONTINUE( !ObjectTypeDB::is_type(ibt,"Node") );
+ ERR_CONTINUE( !valid_type );
Object *obj = ObjectTypeDB::instance(ibt);
- ERR_EXPLAIN("Cannot instance node for autoload type: "+String(ibt));
+ ERR_EXPLAIN("Cannot instance script for autoload, expected 'Node' inheritance, got: "+String(ibt));
ERR_CONTINUE( obj==NULL );
n = obj->cast_to<Node>();
@@ -1246,9 +1391,26 @@ bool Main::start() {
ERR_EXPLAIN("Path in autoload not a node or script: "+path);
ERR_CONTINUE(!n);
n->set_name(name);
- sml->get_root()->add_child(n);
+
+ //defer so references are all valid on _ready()
+ //sml->get_root()->add_child(n);
+ to_add.push_back(n);
+
+ if (global_var) {
+ for(int i=0;i<ScriptServer::get_language_count();i++) {
+ ScriptServer::get_language(i)->add_global_constant(name,n);
+ }
+ }
+
+ }
+
+ for(List<Node*>::Element *E=to_add.front();E;E=E->next()) {
+
+ sml->get_root()->add_child(E->get());
}
+
+
}
Node *scene=NULL;
@@ -1451,9 +1613,9 @@ bool Main::iteration() {
OS::get_singleton()->delay_usec( OS::get_singleton()->get_frame_delay()*1000 );
}
- int taret_fps = OS::get_singleton()->get_target_fps();
- if (taret_fps>0) {
- uint64_t time_step = 1000000L/taret_fps;
+ int target_fps = OS::get_singleton()->get_target_fps();
+ if (target_fps>0) {
+ uint64_t time_step = 1000000L/target_fps;
target_ticks += time_step;
uint64_t current_ticks = OS::get_singleton()->get_ticks_usec();
if (current_ticks<target_ticks) OS::get_singleton()->delay_usec(target_ticks-current_ticks);
diff --git a/main/main.h b/main/main.h
index 12b4411d56..bc8b18776e 100644
--- a/main/main.h
+++ b/main/main.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/main/performance.cpp b/main/performance.cpp
index f8c5df42d1..13ae0504f6 100644
--- a/main/performance.cpp
+++ b/main/performance.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/main/performance.h b/main/performance.h
index f0cd217b2b..81e42710ca 100644
--- a/main/performance.h
+++ b/main/performance.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/main/splash.h b/main/splash.h
index 6ad0062e24..832f504288 100644
--- a/main/splash.h
+++ b/main/splash.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,7 +34,7 @@ static const unsigned char boot_splash_png[]={
};
static const unsigned char app_icon_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x80,0x0,0x0,0x0,0x80,0x8,0x6,0x0,0x0,0x0,0xc3,0x3e,0x61,0xcb,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0x32,0xb8,0x0,0x0,0x32,0xb8,0x1,0x28,0xf3,0x26,0x89,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x1,0x19,0x15,0x3b,0x3a,0x14,0xc2,0xb1,0x4b,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x20,0x0,0x49,0x44,0x41,0x54,0x78,0xda,0xed,0xbd,0x77,0x9c,0x64,0x55,0x99,0x3e,0xfe,0xbc,0xe7,0xdc,0x50,0xb1,0xf3,0x4c,0x4f,0x64,0x98,0x61,0x40,0xc2,0x24,0x92,0xc0,0x22,0x12,0x5c,0x1,0x15,0x50,0x82,0xee,0x2a,0x6,0x14,0x14,0x17,0xdd,0x9f,0x12,0x6,0x56,0x24,0x8c,0xc3,0xa,0xae,0x20,0xa8,0xdf,0x75,0xd7,0x35,0xb0,0xe6,0x48,0x46,0x10,0x90,0xc,0x4a,0x1e,0xc2,0xc,0x99,0xc9,0xb9,0xa7,0x63,0xc5,0x1b,0xce,0x39,0xef,0xef,0x8f,0x5b,0x55,0x5d,0x55,0x5d,0xdd,0x53,0x3d,0x33,0xc0,0xe0,0xce,0xfd,0x30,0x1f,0xaa,0xaa,0x6f,0xdd,0xba,0xf7,0xbc,0xcf,0x79,0xc3,0xf3,0xbe,0xe7,0x3d,0xc0,0xae,0x63,0xd7,0xb1,0xeb,0xd8,0x75,0xec,0x3a,0x76,0x1d,0xef,0xcc,0xe3,0xc0,0xcb,0x1f,0xa1,0x3,0x16,0x3d,0x22,0xde,0xf2,0xdf,0xfd,0xc6,0xa3,0xe2,0xc0,0xcb,0x1f,0xa5,0x77,0xfa,0xf8,0x59,0xef,0xc4,0x9b,0x3e,0xe0,0xf2,0x7,0x25,0x20,0xa4,0xed,0xc4,0xf5,0x13,0x5f,0x3f,0x58,0x3,0xe0,0x93,0x2e,0xfc,0x9d,0x58,0xeb,0x4e,0xec,0x78,0xf6,0x8a,0x63,0x7a,0xdf,0xcc,0xdf,0xde,0xff,0xd2,0x7,0x5b,0x1c,0xe9,0xa9,0x27,0x2e,0x7f,0x4f,0x1,0x0,0xe,0x59,0xfc,0x92,0x8,0x4d,0x9f,0xcd,0x86,0xd5,0xb3,0x8b,0xdf,0xab,0x77,0x1,0xe0,0x2d,0x38,0x58,0x17,0xc,0x5b,0x49,0x14,0xbd,0xdc,0x1e,0x7,0x5c,0xfe,0xc8,0x47,0x41,0xf8,0xe7,0xf5,0x24,0xe6,0x8,0x60,0x25,0x80,0x59,0x6f,0xa,0xe8,0x16,0x3d,0x2a,0x96,0x2c,0x7a,0x8f,0x11,0x96,0x7d,0x95,0x82,0x7d,0xce,0x81,0xdf,0x78,0x74,0x2d,0x1b,0xfc,0x2e,0xd4,0x3d,0xbf,0xd3,0xda,0x7d,0x5e,0x88,0x22,0xbf,0x13,0xc7,0x72,0xa7,0x56,0x61,0xfb,0x5f,0x7a,0xbf,0x90,0xd2,0xa2,0xa7,0x17,0x45,0x33,0xeb,0xe0,0x45,0xf,0xed,0x19,0x6a,0x3a,0x88,0x61,0x8e,0x13,0x24,0x4e,0xb0,0x6d,0xd9,0xe9,0x38,0x36,0x2c,0x5b,0x20,0x11,0x77,0xbc,0xcd,0x3d,0x59,0x9b,0xc0,0x9f,0x7b,0xfa,0xf2,0xf7,0xfc,0x62,0x47,0xdf,0xcb,0x41,0x8b,0x9e,0xb0,0x35,0x79,0xdd,0x82,0xad,0xb5,0xed,0xed,0x71,0x5f,0x8,0x69,0x17,0x8b,0xbe,0x8,0x2,0x85,0x30,0xd4,0x5a,0x69,0x73,0x33,0x11,0xee,0x76,0x2c,0x7a,0xea,0xa9,0xcb,0xdf,0xfb,0x3c,0x0,0x1c,0x76,0xe5,0x33,0xe4,0x7b,0x19,0xb1,0x64,0xf1,0xd1,0x7a,0x17,0x0,0xc6,0x33,0xdb,0x2e,0xbd,0x5f,0x40,0xa,0xb9,0x64,0xd1,0x51,0x21,0x0,0x1c,0x74,0xf9,0x43,0x5f,0x30,0x10,0xff,0x62,0xb4,0x99,0x11,0x8f,0x5b,0xed,0xb1,0x98,0x8d,0x58,0xcc,0x81,0x94,0x92,0xa1,0x3d,0xb0,0x56,0x44,0x96,0x8d,0x82,0x4f,0x18,0x18,0x2c,0xbe,0x24,0x89,0xe,0x66,0xe6,0xe0,0x99,0x6f,0xbc,0x47,0xed,0x10,0x7b,0x7f,0xc5,0x5f,0xc5,0x33,0x97,0x1e,0x6e,0xe,0xfc,0xc6,0x5f,0x97,0xa4,0x92,0xee,0xfe,0x2d,0x29,0x1,0x55,0xcc,0xc3,0x8a,0x25,0x98,0x85,0xd,0xa3,0xd,0x5,0x81,0x86,0xe7,0x85,0xc8,0xe4,0xfc,0x9c,0x14,0xb4,0x5e,0x4a,0xfa,0xb9,0x9,0x6,0xae,0x59,0xf2,0xcd,0x93,0xc2,0x3,0x17,0x3f,0x62,0x99,0x20,0xe4,0x67,0xff,0xfd,0x18,0xbd,0xb,0x0,0xcd,0xcc,0xb6,0xcb,0xef,0xb3,0x95,0x11,0x33,0xc1,0xbc,0x50,0x5a,0xf2,0x2c,0x22,0x20,0x91,0x70,0xc3,0x8e,0xd6,0x98,0xd0,0xc6,0x8,0xa3,0x42,0xd2,0x61,0x0,0x1d,0x78,0x10,0xc2,0x2a,0x3d,0x5,0xc1,0x4e,0xb7,0xa3,0xa7,0x27,0xb,0x15,0xea,0x4f,0x2f,0x59,0x7c,0xe4,0x2f,0xf,0xbc,0xec,0x61,0x7a,0x66,0xf1,0x7b,0x77,0x88,0x6a,0x3e,0xe8,0x8a,0x47,0x4f,0x86,0xc1,0x4d,0x53,0xa6,0xb4,0xea,0x20,0x3b,0x28,0x99,0x35,0xc0,0xc,0x66,0x3,0x21,0x6d,0x8,0xcb,0x81,0xb4,0x1d,0x80,0x84,0xf6,0xfc,0xd0,0xc,0xc,0x16,0x6d,0x36,0xc,0x63,0xcc,0xad,0x6c,0xf8,0x4a,0x5b,0xe2,0xb9,0xa7,0x16,0x1f,0x13,0xec,0x2,0xc0,0xd6,0x66,0xdb,0x65,0xf7,0x7f,0x42,0x69,0x3e,0x83,0x4,0xbd,0x3f,0x9d,0x8c,0x21,0x95,0x8a,0x29,0x4b,0x30,0x19,0x1d,0xca,0xd0,0xf7,0x0,0x36,0x60,0x36,0x20,0x8a,0x1c,0x7f,0xa2,0xf2,0x23,0x30,0xa4,0x1d,0x87,0x22,0x57,0xf5,0xf5,0x17,0xe4,0x33,0x8b,0xde,0x23,0xde,0xfd,0xef,0x7f,0x13,0x4f,0x5e,0xf2,0xf,0x66,0xfb,0x6c,0xff,0xc3,0x94,0x10,0x6c,0xe5,0xb5,0x78,0xa2,0xad,0x25,0xbe,0x20,0x19,0x7,0x85,0x85,0x1c,0x80,0x5a,0x5c,0xb1,0x31,0x60,0x66,0x48,0xdb,0x1,0x9,0x9,0x27,0x16,0x33,0x45,0x9f,0x74,0x18,0x86,0x76,0x2e,0xe7,0xc1,0xf,0xd4,0x93,0x8e,0x25,0x7f,0x96,0x63,0xff,0xc7,0xaf,0x5c,0x71,0x9c,0xda,0x5,0x80,0xba,0x63,0xc1,0x45,0x77,0x4d,0x11,0x8e,0xfb,0x32,0x11,0x25,0xdb,0x5a,0x62,0x32,0x16,0xb7,0x1,0xd6,0x50,0xc5,0x2c,0x18,0x4,0x30,0x57,0xdd,0x31,0x55,0x5e,0x12,0x8,0x24,0xa2,0x3f,0x33,0x80,0x58,0xaa,0x8d,0x37,0xf4,0x14,0x88,0x8d,0xb9,0xfe,0xe9,0x45,0x47,0x9c,0xb9,0x3d,0xf7,0x34,0xff,0x8a,0x47,0xc8,0xd1,0x24,0x14,0xf1,0x89,0x92,0xc4,0xcd,0x53,0xba,0xd3,0xf0,0x73,0x83,0x20,0x36,0x15,0x0,0x94,0x61,0xc0,0x5c,0xd,0x88,0xe8,0xb5,0x20,0x9,0x61,0x3b,0x10,0x4e,0x1c,0xc5,0x62,0x80,0xfe,0x81,0x2,0x8,0xf0,0xc0,0xe6,0x48,0x8,0xf1,0xf4,0x92,0xc5,0x47,0x9b,0xb7,0x7b,0xdc,0xc5,0xce,0x2,0x0,0x19,0xb3,0x93,0x52,0x8a,0x96,0x69,0x93,0x5b,0xb4,0x63,0x19,0xa8,0x42,0x6,0x41,0x7e,0x30,0x92,0x7b,0x69,0x70,0x2b,0x2,0x7,0x20,0x8,0x20,0x2a,0x6b,0x0,0x82,0x10,0x11,0x28,0x42,0xdf,0xa3,0xce,0x8e,0x84,0x56,0x6,0x1f,0x39,0x78,0xf1,0x23,0xd3,0xb7,0x2b,0x44,0x32,0xc2,0x7a,0x6a,0xd1,0x7b,0x34,0x18,0xd7,0xb5,0xa4,0x63,0xd0,0x61,0x0,0x18,0x5d,0xf9,0x5d,0xa2,0xd2,0x7d,0x60,0xf8,0x5f,0xf5,0x61,0x8c,0x86,0xf2,0x8b,0xf0,0x33,0xbd,0x70,0xa4,0xc1,0x6e,0xd3,0xda,0x8c,0x25,0x45,0xcc,0x80,0x12,0x11,0xaa,0xdf,0xfe,0x63,0xe7,0x1,0x80,0x41,0x3f,0xc0,0x60,0xa3,0x84,0xf2,0xf2,0x60,0xa3,0x21,0x48,0x80,0x4a,0x23,0x55,0x2d,0xf0,0xb2,0xd0,0x89,0xa2,0xd9,0x5f,0x16,0x82,0x14,0x4,0x15,0x78,0x88,0x39,0x42,0xba,0x8e,0xe8,0xd0,0x9a,0x3f,0xb9,0xe0,0x92,0xfb,0x68,0xff,0xcb,0x1f,0xd8,0xa6,0xc1,0x7e,0xe6,0xf2,0xc3,0xc3,0x3,0x16,0x3d,0x7c,0xb2,0x25,0xc5,0xee,0x89,0xb8,0xa5,0x95,0x9f,0x87,0x65,0x9,0x88,0x92,0xf0,0x6b,0xee,0xa3,0x1,0x20,0x2a,0x6a,0x96,0x8,0x61,0x61,0x8,0x5a,0x69,0x61,0x59,0x4,0xa3,0x4d,0x8,0xde,0x39,0xa2,0xc6,0x9d,0x2,0x0,0x87,0x5d,0xf9,0x98,0x98,0xd0,0x6a,0x86,0x2a,0xfa,0x93,0xa8,0x4a,0xe0,0xf5,0x3,0x1d,0xd,0xb2,0x24,0x82,0xa8,0x39,0xaf,0xf4,0x5e,0x0,0x41,0xb1,0x80,0x8e,0xf6,0x4,0xc,0xe3,0x6b,0x52,0xda,0x52,0x90,0x65,0x6f,0xb3,0x8d,0x24,0xf1,0x83,0x64,0xc2,0xd,0xa0,0x3,0x29,0x45,0xe9,0xb7,0x4,0x22,0x10,0xd4,0x0,0xb3,0xf1,0x7d,0x56,0x0,0x41,0xd1,0x97,0x99,0x19,0x60,0xe,0xeb,0x7d,0x88,0xff,0xd3,0x44,0x90,0xe7,0x7,0xe2,0x8e,0x8b,0xdf,0xaf,0xe,0xbc,0xec,0x7e,0x4,0x5a,0x44,0x3,0x59,0x1a,0xd4,0x61,0x41,0xa0,0x34,0xb8,0xb5,0xef,0x6b,0xfe,0x6,0x40,0xa,0x81,0x30,0xf4,0x10,0x73,0x13,0x1c,0x8f,0xd9,0x69,0x3f,0x8,0xbf,0xbc,0x64,0xd1,0x11,0xdf,0x3d,0x60,0xd1,0xc3,0x82,0x19,0xc,0x88,0x8a,0xdf,0x48,0x4c,0xc4,0x15,0xd0,0x45,0x57,0x63,0xd6,0x6c,0x10,0xe2,0xb9,0x6f,0xbc,0x8f,0xf,0xfa,0xc6,0xa3,0xff,0xcc,0xc0,0xc4,0x96,0xb4,0x43,0x41,0x6e,0x8,0x8e,0x14,0x15,0xcb,0xcf,0xe0,0xd2,0x2f,0x96,0x74,0x39,0x51,0xc9,0xf,0xe1,0x1a,0xed,0xce,0x5c,0xf3,0x1c,0x1c,0x9d,0xc6,0x1,0x68,0xe7,0x40,0xc0,0xce,0xc1,0x4,0x6a,0x4d,0xd1,0x60,0x51,0xc5,0xc7,0xa3,0xd2,0xc,0xab,0xc,0x1e,0x51,0x8d,0xc0,0xcb,0x52,0xac,0xd7,0xed,0x96,0x24,0x28,0x23,0xa0,0xfc,0x3c,0xa5,0x92,0xf1,0x20,0x8,0xf5,0x35,0x0,0xbe,0x2b,0x44,0x4c,0x3c,0x7d,0xd9,0xbb,0x15,0x9a,0x98,0x7a,0x7,0x7e,0xe3,0x9,0xfb,0x80,0x45,0x8f,0xda,0xca,0xf0,0xe7,0x3b,0x5a,0xe3,0xd2,0xa8,0x0,0x16,0x19,0x0,0x2,0x54,0xa5,0xd6,0x6b,0xdc,0xbe,0x92,0xa0,0xa9,0xc,0xf,0x2e,0x81,0xb8,0xa,0x10,0xd1,0xe4,0x47,0xc0,0x8c,0x80,0xd,0x76,0x69,0x80,0x3a,0xa7,0x19,0x60,0x86,0x89,0xb4,0x66,0x5d,0x88,0x37,0xfc,0x5a,0x94,0xa7,0x6a,0x55,0x20,0x53,0x85,0xd,0x10,0x4,0x6c,0x69,0x10,0x6a,0x85,0x64,0x4a,0x58,0x3,0x3,0x44,0x7,0x2e,0x7a,0xe4,0x8a,0x40,0x15,0x7f,0x33,0xff,0xd2,0x87,0xe,0x20,0x12,0x7b,0x13,0x51,0x37,0x11,0xd2,0x82,0xa8,0x8d,0x99,0x8,0xe0,0x21,0x63,0x38,0x3,0x42,0x3f,0x1b,0xf3,0x9a,0xd6,0xde,0x72,0x66,0xd2,0xb6,0x65,0x1d,0x93,0x48,0x38,0xd0,0x85,0x41,0x38,0x56,0xad,0xb5,0x64,0xae,0xb7,0xf3,0xe5,0xc7,0xa0,0xaa,0x59,0x5f,0x3a,0xc9,0xc,0x23,0x99,0x19,0x1,0x18,0x3b,0xd,0x1f,0xb0,0x93,0xe4,0x2,0x2a,0x1e,0x51,0x3f,0x80,0x8e,0x8a,0x83,0x42,0x75,0x61,0x1f,0x35,0x0,0x6,0xaa,0xcd,0x45,0xf4,0xb9,0x2d,0x5,0x42,0xa5,0x10,0xf8,0x45,0x31,0x61,0x42,0x12,0xbd,0x7d,0xf9,0x4b,0x92,0xae,0x7d,0x89,0x63,0xcb,0xca,0x39,0x8e,0x2d,0x61,0xd9,0x2,0x0,0xc1,0x68,0x86,0xef,0x87,0xe0,0x92,0xc0,0x7c,0x5f,0x83,0xd9,0x20,0x9d,0x4e,0x68,0x56,0xbe,0xb4,0x25,0x41,0xa,0xaa,0xdc,0x25,0x33,0x81,0x88,0xc1,0xc4,0xd1,0xf5,0x38,0xa,0x3,0xcb,0xb7,0x20,0x41,0x30,0xe0,0x61,0x30,0x80,0x21,0x2c,0x7,0x44,0x40,0xae,0x10,0x7a,0xb1,0xb8,0xed,0x6b,0xbd,0xcb,0x7,0x18,0xa1,0x2,0x88,0x78,0x39,0x8,0x1d,0xcc,0x25,0x69,0xb,0x54,0x5,0x7e,0xc3,0x66,0xa1,0x6,0x4,0x54,0x4b,0x69,0x44,0x5f,0x23,0xc4,0x5d,0x9,0x2f,0xf4,0x61,0xb9,0x12,0xdd,0xdd,0x2d,0x0,0x6b,0x86,0x51,0x95,0x2f,0x19,0xe5,0x83,0x3,0x5,0x10,0x41,0x92,0x40,0x3a,0xe9,0x44,0x6a,0x9b,0x19,0xe9,0x64,0x1c,0x44,0x4,0xa3,0x7c,0x69,0xfc,0x22,0xe2,0xae,0x15,0x81,0x3,0x25,0xb2,0xa1,0xca,0xe7,0xa8,0xd0,0x13,0x54,0xa5,0xc8,0xc0,0x10,0x15,0xe5,0x4f,0x30,0x64,0x4a,0x7f,0x64,0x8,0x20,0x4b,0x8c,0x5c,0x1d,0x71,0xf0,0x7f,0x1d,0x0,0x91,0x2f,0xa6,0x14,0xaf,0x28,0x16,0x82,0x83,0x53,0xf1,0x4,0xd8,0x2f,0x40,0x40,0x56,0x9,0x96,0xaa,0x9c,0xa9,0x61,0xe1,0x47,0x76,0x37,0x52,0xcf,0x86,0x19,0x6c,0x0,0x9f,0x35,0x42,0x1d,0x9d,0xa0,0xfc,0x2,0xb8,0x98,0x7,0x88,0x22,0xcc,0x70,0xc5,0x2d,0x2f,0xcd,0x5e,0x3,0x86,0x81,0xd1,0x61,0x5,0x8b,0x91,0x68,0x86,0xd9,0xc6,0x9c,0xaf,0x60,0x4b,0x82,0x25,0x4,0x88,0x86,0x85,0x5b,0xb6,0xf8,0x28,0x5d,0x97,0xc0,0x25,0xf5,0x3f,0xac,0x2d,0x22,0x5,0x21,0x0,0x62,0x10,0x11,0x33,0x90,0x85,0xad,0xf2,0x46,0xd3,0x2e,0xd,0xd0,0xc0,0x4,0xac,0x28,0x49,0x29,0x9a,0x3b,0x44,0x23,0x54,0x3e,0x4a,0xcc,0x5f,0xf9,0x33,0x63,0x80,0xd0,0x18,0x68,0xc3,0x30,0xcc,0xd,0xdc,0x42,0x2,0x89,0xba,0x70,0x82,0xea,0x9d,0x8f,0x3a,0x50,0x45,0xcc,0x44,0xcd,0xdf,0x43,0xcd,0x8,0xb5,0x8e,0x42,0x3f,0x1,0x58,0x44,0x90,0x92,0x20,0x84,0x28,0xf9,0x2e,0x1c,0x81,0x80,0x2a,0x91,0x2c,0xc0,0x54,0x72,0x8,0x19,0xc2,0x76,0xe0,0x79,0xa,0x24,0x28,0xf3,0xd4,0xa5,0xff,0xb8,0xcb,0x7,0xa8,0x61,0xcc,0xa2,0xe9,0x4,0xc3,0xbc,0xbc,0xc2,0xe9,0x46,0x33,0xa6,0x62,0xe3,0xab,0xed,0xbd,0x61,0x46,0xa8,0xd,0x42,0xc5,0x15,0x11,0x55,0xfb,0x0,0x6f,0x26,0xeb,0xcd,0x0,0xb4,0x1,0x34,0xc,0x58,0x45,0x7e,0x8a,0x2d,0x5,0x6c,0x19,0xdd,0x1b,0x57,0x81,0x90,0xc1,0x20,0x8e,0x62,0x7f,0x49,0x2,0x61,0xa8,0x41,0x8c,0x21,0xec,0x44,0xc7,0x4e,0x1,0x0,0x22,0x83,0x3,0x2f,0x7b,0x44,0x86,0xa1,0xb7,0x32,0x8,0x14,0xd2,0xc9,0x38,0x74,0x50,0x80,0xa0,0xf2,0xa0,0x46,0x33,0x5d,0x19,0xd,0x55,0x46,0xb,0x46,0x46,0x8,0x4d,0x9,0xbf,0x19,0x1c,0x50,0x79,0xf2,0xd3,0x18,0x51,0x63,0xe4,0x8,0x1a,0x6,0x7c,0x65,0xe0,0x2b,0x40,0xa,0xc0,0x12,0x54,0x22,0xa9,0x50,0xd1,0x3c,0x86,0x1,0x9,0x2a,0xa9,0x8,0x6c,0xd8,0x99,0x0,0xb0,0x53,0x30,0x81,0xcf,0x7d,0xf3,0x58,0x36,0x26,0x4c,0x68,0xc6,0x4b,0xc6,0x70,0x44,0xb5,0x31,0x21,0xd4,0x6,0x5,0x5f,0xa3,0xe0,0x6b,0x14,0x95,0x46,0x58,0x27,0x7c,0xda,0xaa,0xf0,0x6b,0xe2,0xc3,0xf1,0x29,0x81,0xba,0x8,0x64,0x74,0x10,0xc,0x9f,0xa1,0x4d,0x4,0x86,0x42,0xa8,0x51,0x8,0x34,0xfc,0xd0,0x54,0x7c,0x82,0xa,0x53,0x60,0xf0,0xa,0x0,0xcc,0xbb,0xf8,0x2f,0xbb,0x72,0x1,0x35,0x37,0xc2,0xa1,0xb1,0x85,0xf8,0x7f,0x65,0x16,0x90,0x29,0x1a,0x4c,0xc3,0x5c,0x37,0x7,0xab,0x8,0xa0,0x51,0x85,0x3f,0x5e,0x69,0xa3,0x79,0xd,0xd2,0xe8,0x6f,0x34,0xf2,0x5c,0x53,0xf2,0x1b,0xf2,0xbe,0xaa,0x70,0xca,0x44,0x60,0x8,0x7c,0x6a,0xff,0x8b,0xef,0x9d,0xf6,0xc2,0x95,0xef,0xe7,0x77,0x1c,0x0,0xf6,0x3b,0xff,0x8e,0xca,0xf9,0xf3,0x2e,0xfc,0x93,0xbd,0x3d,0x3f,0x3c,0xff,0xe2,0x7b,0x2a,0xd7,0xda,0xff,0x92,0xfb,0xbe,0x1c,0x18,0xd1,0x9f,0x4c,0x3a,0xa7,0x75,0x74,0x24,0x58,0xfb,0x85,0x8a,0x7,0x5e,0x33,0xc0,0x15,0x76,0x90,0x1a,0x8,0x9f,0x1a,0xcf,0xf8,0x1d,0x86,0x85,0xb1,0x2e,0x46,0x75,0xb7,0x43,0x75,0x0,0x21,0x28,0xbf,0x88,0x74,0xca,0xa6,0x96,0x74,0xec,0x0,0x26,0x5a,0xbb,0xff,0x25,0xf7,0x2e,0x3e,0xe8,0xe2,0x7b,0xe3,0x0,0xb0,0xe0,0x6b,0x77,0x6d,0xd7,0x44,0x9c,0x77,0xe1,0x9d,0xb2,0xf2,0xfa,0x82,0xdb,0xc5,0x8e,0x82,0x76,0x63,0xc1,0x5d,0xf0,0xa7,0xf,0x42,0x40,0x3e,0xff,0xed,0x13,0x6e,0x9f,0x77,0xe1,0x9d,0x36,0xb4,0x51,0x2f,0x7c,0xe7,0x84,0x71,0xa1,0x79,0xc1,0xd7,0xee,0xa2,0xe7,0xae,0x3a,0x9e,0x17,0x7c,0xfd,0x9e,0x29,0x80,0xbc,0x4f,0x4a,0xda,0xbb,0xab,0x23,0x9,0xdb,0x96,0x50,0x7e,0x1e,0x6c,0x4c,0x43,0xfa,0x77,0xf4,0xdb,0xa5,0xed,0x78,0xa2,0xed,0x60,0x2e,0x47,0xf3,0xf,0x2a,0x5a,0x8b,0x6b,0xcf,0x25,0x82,0xed,0xc6,0x11,0x28,0xa0,0x7f,0xa0,0x0,0x15,0xea,0x8d,0x82,0xcd,0x7,0x97,0x5c,0x75,0xec,0x73,0xb,0x2e,0xbe,0xc7,0x7a,0xee,0xca,0x63,0xc7,0x55,0x28,0x32,0xef,0x82,0x5b,0x8,0xc2,0xb1,0x5f,0xf8,0xf6,0x7,0x83,0x5,0x17,0xdd,0xf1,0x1e,0x66,0x6e,0x7f,0xfe,0xdb,0x27,0xdc,0x3e,0x7f,0xe1,0xed,0xe2,0xf9,0xab,0x4f,0x34,0x3b,0x4c,0x3,0xcc,0x5b,0x78,0x2b,0x1,0xc0,0xdc,0x85,0xb7,0xed,0xcd,0x82,0x7e,0xb,0x12,0xb7,0xcd,0xb9,0xe0,0xf6,0x27,0x40,0x66,0xaf,0xb2,0xf0,0xe7,0x2d,0xbc,0x73,0xab,0x43,0xbf,0xe0,0xdf,0xee,0x26,0x0,0x90,0xaa,0x40,0xf3,0xbf,0x76,0xcf,0xa7,0x1,0xb1,0x3e,0x95,0x72,0x67,0x75,0x77,0xa7,0x99,0x38,0x44,0x90,0x1f,0x2,0x1b,0x1e,0xe,0xf0,0x41,0x4d,0xc8,0xf4,0x2d,0x16,0x7e,0x33,0xf3,0x87,0xaa,0xee,0xbc,0x5a,0x35,0x30,0x23,0x28,0x16,0x20,0xa0,0x30,0xa9,0x3b,0x85,0xd6,0xb6,0x44,0x87,0x11,0xe2,0xd9,0xf9,0x5f,0xbb,0xe7,0xf2,0x89,0x7b,0x17,0x75,0x34,0x39,0xb6,0x3e,0x8e,0xf3,0x17,0xde,0x41,0x0,0xf0,0xc2,0x35,0x1f,0x61,0x66,0x33,0x69,0xee,0xc2,0x3b,0x7e,0xf,0xa2,0x47,0x40,0xe2,0xb6,0x79,0xb,0x6f,0x3f,0xa6,0x59,0xe1,0x37,0x3d,0x64,0xef,0xfe,0xda,0xc3,0x94,0xd7,0xbd,0x6d,0xc2,0xd8,0xaf,0xa5,0xd3,0xf1,0xae,0x64,0xd2,0xd5,0xf9,0xbc,0x27,0x33,0x59,0x1f,0x44,0x74,0xa3,0x6d,0xe3,0xd2,0x25,0x57,0x7e,0xe8,0xe5,0xf9,0x17,0xfe,0xd9,0x79,0xfe,0xdb,0x1f,0x68,0x18,0xe3,0xce,0xb9,0xe0,0xe,0x5a,0x76,0xcd,0x87,0xf8,0xa0,0xb,0xef,0x68,0x51,0x96,0xfd,0x6b,0x40,0x9c,0xd0,0xd5,0x99,0x32,0xf1,0x98,0x14,0x7e,0x31,0x7,0x30,0xf,0xab,0x7d,0xaa,0x21,0x7a,0x47,0x51,0xf7,0x78,0x1b,0x5,0xdf,0x9c,0x26,0x18,0x51,0x25,0x54,0x62,0x3,0xd9,0x18,0x80,0x8,0x4e,0x3c,0x89,0x20,0x44,0xd8,0x3f,0x90,0xb7,0xc3,0x40,0x3f,0x2f,0x85,0x39,0x71,0xc9,0x95,0xc7,0xad,0x5d,0xf0,0xb5,0xbb,0xac,0xe7,0xae,0x3a,0xbe,0xa1,0x36,0x98,0x7f,0xe1,0x9d,0xf6,0xf3,0xdf,0xfe,0x60,0x78,0xd0,0xbf,0xfd,0x79,0x52,0x60,0x78,0x31,0x80,0xcf,0xa7,0x92,0x2e,0xd2,0x29,0x57,0xf9,0x7e,0x68,0xb6,0xf4,0xe6,0x1d,0xd7,0x11,0xb,0x42,0xdf,0x5a,0xba,0xf4,0xba,0x63,0xcd,0xe,0x1,0xc0,0x81,0xe7,0xdf,0xe6,0x84,0x42,0x2c,0x4f,0x24,0x9c,0xc9,0x6d,0x6d,0x71,0x19,0xe6,0xb3,0xb0,0xe2,0x9,0x10,0x59,0x18,0x1c,0x2a,0x22,0x57,0x8,0x20,0x80,0x9f,0xbf,0x70,0xf5,0x87,0xce,0x58,0xf0,0xb5,0xbf,0x88,0xe7,0xae,0x7a,0x7f,0xcd,0xf,0xcf,0xbd,0xe0,0x2e,0xb2,0x62,0x52,0xb0,0xe2,0x59,0x20,0x3c,0x66,0xdb,0x56,0x67,0x77,0x77,0xb,0x54,0xe8,0xc3,0x84,0x7e,0xad,0x27,0x3f,0x9c,0xfe,0x1b,0xc3,0xd1,0xa3,0xb7,0x57,0xf0,0xcd,0x82,0xa0,0xc6,0x81,0xad,0x35,0x7,0xa5,0xba,0x0,0x8,0xcb,0x81,0xb0,0x5d,0xf4,0xf5,0x17,0xd8,0xf7,0x43,0x3,0x56,0x1f,0x79,0xee,0xaa,0xf,0xfc,0x69,0x14,0xe1,0xcb,0xe7,0xbf,0xfd,0x41,0xbd,0xe0,0xc2,0x3b,0x16,0x19,0x88,0x8b,0x85,0x84,0x3d,0xa1,0x2b,0x5,0x61,0xc,0x54,0x58,0x84,0x1d,0x4b,0x20,0x97,0xb,0x30,0x38,0xe4,0x5,0x42,0x6,0x93,0xc1,0xf1,0xec,0xb,0x57,0x7f,0x20,0xdc,0x66,0x13,0x30,0xe7,0xbc,0xdb,0x6d,0x0,0xf0,0x81,0xdb,0xa5,0xa4,0x69,0x1d,0xed,0x71,0x19,0xe4,0x33,0x0,0x31,0xc2,0x62,0x16,0xa1,0x97,0x45,0x7b,0xab,0x83,0xc9,0xdd,0xe9,0xc0,0x71,0xe5,0x67,0xe6,0x2d,0xbc,0x33,0x6f,0x54,0x70,0xd2,0xb0,0xaa,0xba,0x93,0x16,0x5c,0xf8,0x67,0x5a,0x7a,0xcd,0xf1,0x6c,0xb4,0x3e,0x8d,0xc1,0xaf,0xa5,0xd3,0x6e,0xcb,0xc4,0x89,0x49,0x84,0xc5,0x1c,0x4c,0xe0,0x8d,0x82,0xc7,0x77,0x88,0xf0,0xeb,0xb4,0x55,0x3,0x82,0x63,0xd4,0x68,0x21,0xaa,0x66,0x22,0x18,0x15,0x40,0x79,0x79,0x4c,0x9c,0x90,0xa0,0xd6,0x96,0x98,0x26,0x92,0xb7,0xcf,0xbf,0xe8,0xae,0xcb,0x0,0xe0,0x80,0xcb,0x1e,0x10,0xf3,0x16,0xfe,0xa9,0xf2,0x2d,0x41,0x38,0x74,0xee,0xc2,0x3b,0x5e,0x96,0xb6,0xbc,0xbc,0xb3,0x33,0xc1,0x53,0x27,0xa5,0x0,0xe5,0x21,0xf4,0x73,0x0,0x1b,0x84,0xc5,0x2c,0x52,0x29,0x1b,0xad,0xad,0xae,0x80,0xb1,0x5f,0x4c,0x4e,0x8b,0xeb,0x6d,0xd6,0x0,0xfb,0x9d,0x77,0x9b,0xf5,0xe2,0xb5,0x27,0xa9,0x39,0xe7,0xdf,0xf6,0x1d,0xd7,0xb5,0xce,0xeb,0xea,0x4c,0x41,0xfb,0x51,0xa9,0xd6,0xf0,0xc3,0x94,0x58,0x2e,0xdb,0x86,0xb4,0x5d,0xf6,0x3,0xa6,0xfe,0x81,0x2,0x0,0x7a,0x48,0x12,0xce,0x58,0xf2,0xad,0xf,0xac,0x2,0x80,0xf9,0x17,0xdd,0xb5,0x58,0x48,0x71,0x69,0x5b,0x6b,0x42,0x27,0xe2,0x32,0xaa,0xee,0x8d,0x72,0xa4,0xc3,0x82,0xae,0x9a,0xf9,0xa3,0x3b,0x7d,0xb4,0x73,0x2f,0x65,0xe1,0xd1,0xcc,0x1,0x97,0xc8,0x6e,0x1e,0x71,0x4e,0x59,0x13,0x80,0x19,0x56,0x2c,0xe,0x65,0x4,0x6f,0xd9,0x92,0x25,0x86,0xb9,0xf1,0xb9,0x2b,0x8f,0x3f,0xd,0x0,0x8e,0xb8,0xe8,0x6,0x3b,0x83,0xe4,0x6f,0x94,0x32,0xa7,0x75,0x75,0x26,0x10,0x4f,0x38,0x86,0x43,0x5f,0xa8,0xc0,0x3,0x95,0xe8,0x85,0xb2,0xd3,0x49,0x24,0xe0,0x24,0x52,0xbc,0x71,0x53,0x86,0xb4,0x36,0x7f,0x7e,0xe1,0xea,0x13,0x3f,0x38,0xf7,0xdc,0x9b,0xc5,0xd2,0xeb,0x4e,0x36,0xe3,0x36,0x1,0xf3,0xce,0xbf,0xf5,0xb3,0x20,0x71,0x7d,0x47,0x67,0x52,0x5b,0x8,0x24,0x6b,0x55,0x11,0x42,0x39,0x1c,0x33,0x55,0x6a,0xcd,0x72,0x13,0x80,0xb4,0x30,0x38,0xe0,0x1b,0xcf,0xf,0x5,0x1b,0xfe,0x22,0x8,0x87,0x4a,0x4b,0x9e,0x31,0xa9,0xbb,0x85,0xd9,0x68,0x32,0xa1,0x5f,0xf5,0xcb,0xc3,0xf5,0x7d,0xa0,0x77,0xb8,0xf0,0xb7,0x2,0x82,0x1a,0x7f,0x80,0xb9,0x72,0xce,0xf0,0xe7,0x11,0x8,0x48,0x5a,0x20,0xcb,0xc5,0xc6,0x4d,0x19,0x80,0x71,0xaf,0xd1,0xea,0x67,0x42,0xca,0x5f,0x39,0x8e,0xd4,0x5d,0x1d,0x71,0x61,0xb4,0x26,0xed,0x17,0xa2,0x6c,0x85,0x88,0x18,0x52,0x80,0x4b,0x72,0x28,0x5f,0xc3,0x81,0xe5,0xba,0xd8,0xb4,0x39,0x7,0xa3,0xf4,0xd7,0x5f,0xf8,0xce,0x49,0x57,0xce,0x3f,0xef,0x36,0xf1,0xfc,0xb5,0x27,0x99,0xa6,0x0,0x30,0xef,0x5f,0xfe,0x48,0x94,0x70,0xf6,0x63,0xc6,0xd2,0x8e,0xce,0x54,0x10,0x73,0xc9,0x9,0xbd,0x42,0x2d,0xfb,0x45,0x91,0x5,0x11,0xa5,0x34,0xa8,0x66,0x6,0x31,0x40,0xd2,0x82,0xe5,0xc6,0x10,0x86,0x8,0xf3,0x85,0xd0,0x26,0x22,0xa4,0xd3,0xae,0x22,0x68,0xcb,0x84,0x7e,0xc4,0xf2,0x95,0x63,0xfa,0xea,0x59,0x4f,0x4d,0x38,0x7d,0xef,0x18,0x0,0x34,0x2,0x1,0x57,0xd5,0x81,0x56,0x52,0x8e,0xc3,0x0,0xa8,0xbc,0x37,0x51,0xed,0x80,0xb0,0x38,0x97,0xf,0x48,0x6b,0x83,0x98,0x6b,0x85,0xf1,0x98,0xb4,0x2,0xaf,0x48,0xd0,0x1,0xa4,0x94,0x11,0x4d,0xe,0x86,0x36,0x5c,0x52,0x20,0x8c,0x8a,0xc7,0x61,0x18,0x64,0xd9,0x20,0xcb,0x55,0x9b,0x36,0x65,0x2c,0x0,0x27,0x2f,0xfd,0xce,0x49,0xb7,0xcc,0x39,0xef,0x16,0x5a,0x76,0xed,0x47,0x78,0x4c,0x0,0xcc,0x3d,0xf7,0x16,0x77,0xe9,0x75,0x1f,0xf1,0xf7,0xfb,0xea,0x2d,0xcb,0x5b,0x5b,0x63,0xb3,0xd2,0x29,0x1b,0xa1,0x57,0xa8,0x2a,0xc1,0xa2,0x92,0xc,0xa9,0x54,0x1d,0x5b,0xfa,0xbc,0x84,0x46,0x6d,0x22,0x95,0x24,0xa4,0x5,0x69,0xd9,0xc,0x12,0x64,0x54,0x8,0x63,0x74,0x55,0xe,0x5f,0x54,0x9,0xba,0xc9,0xd9,0xff,0x4e,0x1,0xc0,0xa8,0x20,0xe0,0x2a,0x3f,0xb0,0x4a,0xe8,0xa5,0x3a,0x42,0x54,0x69,0x82,0xe1,0x22,0x12,0x1b,0x24,0x88,0xb5,0x52,0x64,0x54,0x8,0x1,0x86,0x63,0xc9,0x92,0x8c,0xb9,0x94,0xfe,0x2e,0x55,0x2a,0x70,0x4,0x1e,0xae,0xd2,0x42,0x96,0x13,0x43,0xc1,0x63,0x35,0x34,0x54,0xc,0x60,0xf4,0xbc,0x17,0xae,0x3b,0x79,0xf9,0x98,0x1a,0x60,0xee,0x79,0xb7,0xd0,0xd2,0x6b,0x3f,0xc2,0x73,0xcf,0xbd,0xf9,0x7f,0x1d,0xc7,0x3e,0xa3,0x6b,0x42,0x92,0x43,0xaf,0x50,0xb1,0x30,0xd5,0x2c,0x5c,0x54,0xd,0x2b,0x50,0x6d,0xc2,0x5,0x9,0x30,0x3,0x81,0x2e,0xd7,0xc3,0x50,0x94,0x3b,0xad,0x66,0xcb,0xca,0xdf,0xa9,0x16,0x3c,0x8d,0x45,0xef,0xbe,0xc3,0x84,0xdf,0x94,0x16,0xe0,0x11,0xe6,0xa2,0x42,0x7e,0x55,0x9f,0x63,0x4c,0xe5,0xa,0x8e,0x45,0xb0,0x5,0x45,0x42,0xaf,0x9a,0xf1,0xc6,0x94,0x5f,0x97,0x0,0x50,0xc1,0x52,0x24,0x1,0x3b,0x9e,0x44,0x7f,0x5f,0x11,0x85,0x82,0xff,0xb0,0xe3,0xf6,0x1c,0x15,0x86,0x13,0xc4,0xd2,0x6b,0x4f,0xd6,0xd,0xa3,0x80,0xa5,0xd7,0x7e,0x84,0xe7,0x5d,0x70,0xcb,0x67,0xc,0xe3,0x8c,0xce,0xce,0x64,0xa8,0x43,0x8f,0x50,0xaa,0x5e,0xa4,0xaa,0xd9,0x29,0xaa,0x8b,0x32,0xa9,0x36,0x29,0x63,0x49,0x1,0x5b,0x8a,0x6,0x74,0x2d,0x37,0x20,0x6d,0x68,0x64,0x61,0xdd,0x9b,0x4d,0xeb,0xbf,0x8d,0xfc,0x50,0x75,0x94,0x33,0x56,0xc4,0x50,0x99,0xe,0x42,0x54,0xde,0x97,0x6b,0x12,0x9,0xb5,0x45,0xb1,0x95,0x88,0xa2,0x21,0x25,0xcd,0x8,0x8b,0x79,0x74,0x76,0x25,0x61,0xd9,0xe2,0xbd,0x41,0x30,0xe1,0xf2,0xa5,0xd7,0x9e,0xac,0xe7,0x9e,0x77,0x93,0x1c,0x71,0xab,0x73,0xce,0xbb,0x49,0x90,0xa0,0xa9,0x46,0x99,0x25,0x5d,0x5d,0xe9,0x4e,0xc7,0x26,0xd2,0x41,0xb1,0x62,0xe7,0x87,0x85,0x3f,0x5c,0x60,0x41,0x55,0xdc,0x3c,0x89,0xa8,0x14,0xcb,0x30,0xc1,0x53,0x7a,0x84,0x73,0x57,0x4d,0xf2,0x10,0x44,0x1d,0x0,0xe8,0xef,0x43,0xf5,0x37,0xe5,0x10,0xd6,0x6b,0x81,0x6a,0x5f,0x80,0x4b,0xb,0x4e,0x47,0x6a,0x6,0x4b,0x0,0x6e,0x9,0x4,0xcc,0xc3,0x4e,0x9f,0x31,0x5c,0x71,0xc4,0x4d,0x49,0x3,0x80,0xcb,0xc5,0x31,0xa5,0xe1,0x93,0x36,0xc,0x49,0xdd,0xbb,0x25,0x2b,0x99,0xcd,0x81,0x4b,0xaf,0x3d,0x75,0x49,0x8d,0x6,0x98,0x73,0xee,0x4d,0xd6,0xb2,0x6b,0x4f,0x31,0x3a,0x34,0x57,0xba,0xae,0xd5,0xe5,0xba,0x16,0x69,0xdf,0xab,0x72,0xca,0xc6,0x9e,0xf9,0xd1,0xeb,0xe8,0x73,0x3f,0x54,0xa0,0x6a,0x89,0x31,0x46,0x26,0x4a,0x68,0x1c,0x34,0xd4,0x3b,0xb9,0x9,0xb,0x8d,0xf7,0x81,0x46,0xaa,0xbb,0xf2,0x78,0xab,0x92,0x7f,0x55,0xbd,0x2c,0x8d,0x51,0x5b,0x2a,0x57,0xad,0xa5,0xab,0xaf,0x62,0x74,0x8,0x4b,0xb0,0x4c,0xa5,0x62,0x3e,0x1b,0xba,0xa1,0x86,0x8,0xda,0xef,0xab,0x37,0xd0,0xb2,0xeb,0x4e,0x51,0x73,0xbf,0x7a,0xd3,0x7,0x2c,0x4b,0x7c,0xb2,0xb3,0xb3,0x45,0x6b,0xbf,0x58,0x15,0xea,0x45,0x97,0xdb,0x9a,0xf0,0x89,0x0,0x2f,0x34,0xc3,0x2b,0x2c,0xaa,0x9e,0x89,0x6b,0x66,0x32,0x35,0xa9,0x16,0xe9,0x9d,0x2d,0xfc,0xca,0x24,0xa6,0xf1,0x9b,0x83,0xfa,0x4,0x38,0x45,0x55,0x31,0x5e,0xa8,0x2b,0xbe,0xa2,0x68,0x20,0xf8,0xea,0xb5,0x14,0x54,0x37,0x7c,0xca,0xf7,0x91,0x4e,0xbb,0x2e,0x1,0x33,0xe7,0x9d,0x7b,0xd3,0x5,0x0,0x30,0xe7,0x2b,0x37,0x46,0x97,0x58,0x70,0xfe,0x8d,0xb6,0x32,0xdc,0xdf,0x92,0x4e,0x38,0xc9,0x84,0x74,0x74,0x18,0x94,0x99,0x27,0x0,0x2,0x52,0xa0,0xa6,0x3e,0x2f,0xf2,0xe5,0xa8,0x52,0xb2,0x45,0x14,0x39,0x7e,0x4a,0x73,0xc5,0xb3,0xa7,0x1a,0x7,0x8f,0xaa,0x56,0xfb,0x88,0x11,0xa1,0x5f,0x35,0xd2,0xff,0xae,0x0,0x30,0x8a,0x19,0xa8,0x8d,0xfd,0xab,0xa8,0xe1,0x4a,0x64,0x50,0x15,0xd2,0x95,0x4c,0x43,0x94,0x24,0x63,0x8,0x2,0x12,0xae,0x55,0x71,0x4,0xeb,0x9d,0x42,0x66,0x94,0x22,0x83,0xe8,0x9a,0xcc,0x11,0xe5,0x6,0x63,0x20,0x2c,0x17,0x6,0x12,0x9b,0x36,0xf,0x42,0xa,0x74,0x32,0x28,0x27,0x22,0x3b,0x43,0x9d,0x0,0x14,0x9,0xaa,0xc3,0x25,0x41,0x94,0x6a,0xf3,0x6a,0x66,0xbe,0xa8,0x9d,0xf9,0xda,0x44,0x35,0x7a,0xcd,0xd,0x8,0x37,0xaf,0x3b,0xf9,0xef,0x41,0xf8,0xe3,0xb1,0x75,0x3c,0x86,0x8f,0x38,0x5c,0x5e,0xe6,0x87,0xa6,0x2a,0x82,0xa6,0x9a,0xd9,0x3f,0x96,0x53,0xc8,0x6c,0x0,0x18,0x8,0x41,0x60,0x70,0xa7,0x61,0xa9,0xc5,0x9c,0xaf,0xde,0x40,0xcf,0x5f,0x77,0xca,0x26,0x30,0x4e,0xcd,0x64,0x8a,0x8e,0x66,0xa9,0xcb,0xd4,0x62,0xf9,0xc2,0x3c,0x86,0xda,0x7,0x0,0x2f,0xd4,0x8d,0xe5,0xdc,0x50,0xcb,0x11,0xc6,0x25,0x5d,0x7e,0x7,0x2,0x61,0x9b,0xee,0xb9,0x7e,0xc0,0xa8,0x66,0xb2,0x54,0x5f,0x2e,0xd4,0x51,0x15,0x74,0x65,0x61,0x6a,0x95,0x16,0x15,0x55,0x8b,0x67,0x6a,0x1c,0x6b,0x21,0xe1,0xc4,0x63,0xd8,0xb2,0x25,0xb,0x62,0x5c,0xb0,0xec,0xba,0x8f,0xbe,0x2e,0x28,0x34,0x14,0xd9,0x82,0x1b,0xe4,0xb2,0xef,0x9d,0xa6,0xf7,0xfd,0xca,0x1f,0xaf,0x4f,0x27,0x63,0x9f,0x6d,0x6b,0x4f,0x22,0x28,0xe6,0x40,0x44,0xb0,0xa5,0x84,0x10,0xd5,0xc2,0xa7,0xa,0x19,0x44,0x44,0x28,0xf8,0x3a,0xf2,0x38,0xcb,0x37,0x52,0x9d,0xc7,0x17,0xc3,0x55,0x34,0xe5,0xb0,0xb0,0x11,0xfb,0x37,0xaa,0x9,0x78,0xa7,0x3a,0x82,0x3c,0xf6,0x7,0x8d,0x68,0xe1,0x46,0x8c,0x60,0x3d,0x39,0x84,0xba,0x5,0x85,0x49,0x57,0x56,0x4e,0x89,0x4c,0x41,0xf4,0xc6,0x98,0xe1,0xd7,0xda,0x18,0x68,0x6,0x6c,0xd7,0x45,0x5f,0x5f,0x51,0x5,0x41,0xf8,0xfa,0xb,0xd7,0x9e,0xba,0x6f,0x4d,0x14,0xb0,0xec,0x7b,0xa7,0xe9,0x39,0x5f,0xf9,0xa3,0x74,0x6c,0x79,0x41,0x26,0x5b,0xec,0x2b,0x16,0x7c,0x63,0x39,0x6e,0xe4,0x3c,0x68,0x53,0x61,0xfc,0x2a,0x33,0xbf,0xb4,0x4c,0xda,0xf,0x4d,0x4d,0xb8,0x31,0x52,0x50,0xcd,0x55,0xeb,0x52,0x73,0xa3,0xf8,0xe,0xf5,0xfe,0x79,0xac,0x90,0x7f,0x94,0x91,0x6a,0xb0,0xbe,0xa1,0xc1,0x77,0x8a,0x81,0xae,0x72,0x4,0x47,0x3a,0x85,0xe5,0x70,0x51,0x48,0xb,0x61,0x88,0xd0,0xf7,0x42,0x8b,0x98,0x3f,0x5c,0x13,0x5,0x94,0x5f,0x2c,0xfb,0xde,0x47,0xf5,0x73,0xd7,0x9c,0xd2,0xef,0xd8,0xf2,0xa2,0xc1,0xc1,0xbc,0x20,0x61,0xe9,0x48,0xfd,0xf3,0x70,0xf8,0x51,0xfe,0x11,0x1e,0xa7,0xdd,0xaf,0x8b,0x79,0x77,0x1d,0x5b,0xf1,0x1,0x9a,0x3c,0xc,0x33,0x42,0x65,0xaa,0xbc,0xfe,0x5a,0x7f,0x40,0x95,0x8,0x2,0x12,0x36,0xfa,0x7a,0xb3,0x36,0xb3,0x39,0xff,0xf9,0xeb,0x4e,0x7b,0x7d,0xce,0x57,0xff,0x28,0x1a,0x32,0x81,0x73,0xcf,0xbd,0x41,0x3e,0x7f,0xed,0xa9,0x3f,0x35,0x8c,0xfb,0x7b,0xfb,0xb2,0x52,0xba,0x9,0x6,0xa2,0xf2,0xec,0x9a,0x75,0xee,0x14,0xa1,0x6f,0x5b,0xf4,0x62,0x8d,0x7,0x5c,0xc3,0x8c,0xff,0x3d,0x82,0xa3,0x41,0x56,0xb0,0x3a,0x29,0x54,0x9d,0x15,0xac,0x29,0x18,0x69,0x4e,0x21,0x32,0xa2,0xca,0xe9,0xca,0xd2,0xf4,0x2a,0x10,0x84,0x3a,0x8a,0x26,0xa4,0x1b,0x47,0x2e,0xef,0x21,0xd4,0xfa,0x59,0x41,0xe2,0x7,0x73,0xbe,0xfa,0x47,0x6b,0xd9,0x77,0x3f,0x6a,0x46,0x55,0x2c,0x73,0xce,0xbd,0xd1,0xb1,0x94,0x92,0x21,0x89,0x37,0xda,0xda,0x93,0x53,0x12,0x71,0x1b,0x5a,0xf9,0x20,0x0,0x49,0xd7,0x82,0x20,0x81,0x7c,0x10,0x96,0xd8,0x27,0xaa,0x8b,0xda,0xea,0x7c,0x0,0xa2,0x51,0xc2,0x42,0x34,0x99,0x6,0x7e,0x87,0x32,0x81,0x4d,0x67,0x4,0xeb,0x26,0x46,0x7d,0x9a,0x78,0x2b,0x3e,0x40,0x19,0x34,0x4,0x20,0x19,0xb3,0x2a,0x93,0x2b,0x54,0x6,0x81,0xd2,0x10,0x96,0x8d,0x20,0x84,0xb7,0x65,0x4b,0x26,0x66,0xbb,0xd6,0x3e,0xcf,0x5f,0x7d,0xf2,0x2b,0x4d,0x1b,0xe9,0xb9,0xe7,0xdd,0x78,0xb4,0x56,0xe6,0x2f,0xdd,0xdd,0xad,0x24,0x85,0x11,0xac,0x15,0x2c,0x11,0x51,0xba,0x61,0x25,0x71,0xb1,0x15,0x0,0x88,0x3a,0x30,0x34,0x2,0x40,0x15,0x41,0xf4,0x77,0x9f,0xc,0xaa,0xae,0x16,0xae,0xe2,0x8,0x86,0x69,0xe0,0x3a,0xaa,0xb8,0x49,0x0,0x44,0x54,0x31,0x21,0xe6,0x8,0x18,0x3,0x14,0x7c,0x5,0x12,0x4,0x16,0x8e,0xd9,0xd2,0x33,0x24,0x58,0xe3,0xcc,0xa5,0xdf,0x3b,0xf5,0xfa,0x46,0xb7,0x3a,0x6a,0x49,0xd8,0xd2,0x6b,0x4f,0x7d,0xc0,0xb2,0xc4,0x35,0x5b,0xb6,0x64,0x84,0x90,0xb6,0x26,0x12,0x50,0x65,0xbb,0xdf,0xac,0xb6,0x66,0xde,0x8a,0x2e,0xe3,0xbf,0x17,0xb7,0xaf,0x9,0x9d,0x5d,0xb7,0xc0,0x85,0xc7,0x78,0x62,0x6a,0x30,0x76,0xd,0xc6,0xb2,0x86,0xe9,0x33,0xc,0xa5,0x19,0x5e,0xa8,0xc0,0xc,0x58,0x4e,0x1c,0xfd,0x7d,0x39,0xa1,0x35,0xff,0x6e,0xe9,0xf7,0x4e,0xbd,0x7e,0xce,0x57,0x6e,0xb4,0xc7,0x45,0x4c,0xef,0xf7,0x95,0x1b,0xe5,0x8b,0xdf,0x3b,0x55,0xef,0xf7,0x95,0x1b,0x1e,0x8e,0xc7,0xed,0x23,0xda,0xdb,0x93,0xd0,0x41,0xb1,0xae,0x72,0x77,0x6b,0x26,0xa0,0x81,0xda,0xaf,0x37,0x11,0x95,0x13,0xff,0x4e,0x52,0xc2,0x5b,0x2d,0xb,0x43,0xdd,0xcc,0xe6,0x91,0xfe,0x80,0xe1,0x11,0x13,0x65,0xe4,0x67,0xf5,0x26,0x65,0xf8,0x77,0x6d,0x27,0x86,0xc1,0xa1,0x22,0x67,0x32,0xde,0xaa,0x98,0x23,0xe6,0x4,0x1,0xfb,0xcb,0xbe,0x7f,0xaa,0x1e,0x6f,0x66,0x2,0x73,0xfe,0xbf,0x1b,0x1c,0x69,0xe9,0x64,0x10,0x60,0xe5,0x94,0xa9,0x1d,0xad,0x30,0x61,0x49,0xd,0xd1,0xe8,0x0,0x88,0x74,0x7f,0x6d,0xb8,0x43,0xd5,0x35,0x1,0xf5,0x66,0xa0,0x19,0x4e,0xe0,0x1d,0x2,0x82,0x31,0x2a,0x84,0x1b,0xd1,0xbf,0x35,0x9f,0xd7,0xd8,0xff,0x5a,0x2d,0xcb,0x65,0xd5,0xcf,0x5b,0x7,0x0,0x9,0x1,0xa5,0x84,0xea,0xeb,0xcf,0x59,0x0,0x1f,0xbe,0xf4,0xba,0xd3,0xfe,0x36,0xd6,0x2d,0x8f,0x59,0x15,0xcc,0x42,0x85,0xcf,0x5f,0xfb,0x4f,0x3,0x6c,0x70,0xe3,0xf8,0x38,0xfa,0xb1,0xd4,0xd7,0xc8,0x72,0x28,0x29,0xa2,0xe6,0xb,0xb6,0x45,0xb0,0x2d,0x1,0x4b,0x10,0x2c,0x49,0xa3,0x84,0x92,0xef,0x40,0xd5,0xcf,0x6,0x44,0xd1,0x33,0x59,0x32,0x7a,0x4e,0x4b,0x46,0xcf,0x29,0x88,0x86,0x5,0x5c,0x4f,0x12,0x6d,0x8b,0x7d,0x8c,0x16,0xa3,0x32,0x18,0x43,0x4b,0xaf,0x3b,0xed,0x6f,0x73,0xbe,0x7a,0xa3,0x1c,0xeb,0xf4,0x31,0x97,0x87,0x13,0x8b,0xf2,0x35,0x9d,0x5a,0x1,0x6e,0x5,0x4,0xcc,0x63,0x2c,0xdc,0x1c,0x3e,0x47,0x48,0x1,0x5b,0x48,0xf4,0x67,0xb,0x8,0x2,0xd,0x5d,0x6e,0xa3,0x22,0x24,0x6c,0x49,0xe8,0x68,0x4b,0x82,0x88,0xa0,0xb4,0xa9,0x25,0x48,0x78,0x27,0xd3,0x4,0x3c,0x3a,0xe3,0x27,0x4,0xc1,0xb6,0x24,0x72,0x79,0xf,0xf9,0x42,0x0,0x63,0x18,0x9a,0x4d,0xa5,0xcf,0x60,0x2a,0x6e,0x23,0x95,0x74,0xa1,0x94,0x8e,0xca,0xe9,0xea,0x2e,0xc3,0xdb,0xd9,0x4e,0x8c,0xb6,0x2,0x1d,0xab,0xf9,0x27,0xe4,0x6,0x56,0x63,0xc,0x49,0xd4,0x83,0xa0,0x42,0x17,0xb,0x18,0x30,0x72,0x85,0x0,0xad,0x31,0x9,0x57,0x12,0xce,0x3c,0x7c,0x6,0xde,0x35,0xa5,0x15,0x93,0xda,0x13,0x88,0x39,0x16,0x36,0xf6,0x17,0xb1,0xae,0x3f,0x8f,0x3b,0x96,0xac,0xc5,0xda,0xfe,0x22,0xf2,0x6,0x70,0x5d,0x1b,0xb6,0x25,0xab,0x54,0x26,0xed,0xd4,0xb,0x43,0x4,0x11,0x72,0x5e,0x0,0x28,0x8d,0x16,0x57,0xe0,0xa8,0xd9,0x9d,0xf8,0x87,0x3d,0xbb,0xd0,0xdd,0x1e,0xc7,0xc4,0x74,0xc,0x5b,0x32,0x1e,0x36,0xf,0x16,0xf0,0xd8,0xeb,0x5b,0xf0,0xd8,0x2b,0x9b,0x51,0xd0,0x80,0x26,0x42,0x2a,0xe1,0xc0,0x68,0x1e,0x5b,0x1b,0x6c,0xe5,0x86,0x18,0x6,0xd5,0x1d,0x8b,0x76,0x0,0x0,0x46,0x13,0x35,0x8d,0x7d,0x23,0x6,0x35,0xed,0x59,0x4,0x0,0x3f,0x8,0x90,0xc9,0x14,0x71,0xd6,0x51,0xb3,0x71,0xfc,0x82,0xa9,0x98,0x39,0xb9,0xad,0xe2,0xe4,0x98,0x92,0x7b,0x31,0xa5,0x3d,0x8e,0x3,0xf7,0xe8,0xc2,0x87,0xf,0x9e,0x81,0x4c,0x31,0xc0,0x3,0xcb,0x36,0xe1,0xbf,0xee,0x7d,0xd,0x83,0x79,0x1f,0x13,0x3a,0x52,0x8,0x94,0x1e,0xd6,0x44,0x6f,0x97,0x5f,0x30,0x86,0xbd,0xb7,0xa5,0xc0,0xaa,0x8d,0x3,0x78,0xcf,0xec,0x2e,0x9c,0x79,0xd4,0x1e,0x38,0x60,0x56,0x67,0xc9,0x79,0x36,0x30,0xa5,0x44,0x4e,0x57,0xca,0xc1,0x7e,0xd3,0x5a,0xf1,0xbe,0xf9,0x53,0x61,0x94,0xc2,0xd3,0x6f,0xf4,0xe2,0x37,0x7f,0x5b,0x89,0xfb,0x5e,0xd9,0x82,0x19,0x93,0x5a,0xe1,0x7,0xaa,0xf9,0x5b,0x68,0xf4,0x79,0x6d,0x47,0xcd,0x6d,0x3,0x0,0x57,0xdb,0x5d,0x6e,0xd6,0x75,0x1c,0xe9,0xfc,0x50,0xa9,0x45,0xaa,0x1f,0x6a,0xa4,0x49,0xe1,0xf,0x17,0x1d,0x83,0xb8,0x6b,0xc1,0x92,0x12,0xbe,0x1f,0x56,0xf5,0xff,0x8d,0x1c,0x49,0xa5,0xa2,0xb4,0x25,0x11,0x21,0xe9,0x48,0x9c,0x70,0xe0,0x34,0x7c,0xf8,0xe0,0xe9,0xf8,0xb7,0xdf,0x2c,0xc1,0x43,0xaf,0xf7,0xa1,0xbd,0x35,0x31,0x1c,0x3b,0x97,0xb5,0xc1,0x5b,0x9,0x4,0x1e,0x9b,0xe7,0x5f,0xbe,0x7a,0xb,0x7e,0xf0,0xb9,0x43,0x70,0xd4,0xbe,0xdd,0x30,0xcc,0xd0,0x3a,0x7a,0x1e,0xae,0xf2,0x7d,0x34,0x0,0xad,0x19,0x26,0x8c,0x56,0x6e,0xcd,0x9d,0xd1,0x81,0x2b,0xa6,0xb5,0xe2,0xc3,0xcb,0xfb,0x70,0xde,0xcf,0x1e,0xc7,0xc4,0x49,0x1d,0xd0,0xc6,0x6c,0xd5,0x92,0x36,0x52,0xfa,0xc4,0x80,0xa0,0x72,0xc7,0xf2,0xb1,0x35,0x80,0x18,0xbf,0x9,0x18,0xbf,0x23,0x26,0x4,0xe0,0xf9,0xa,0x7b,0x75,0x38,0xf8,0xdd,0xb9,0x47,0xc3,0xb1,0x4,0xa4,0x10,0x35,0xde,0xbe,0xd6,0x1a,0x5a,0xeb,0xa,0x60,0x8c,0x31,0x95,0xf7,0x60,0x46,0xc1,0x57,0xf8,0xd6,0x27,0xe,0xc4,0xa7,0xe,0x99,0x8e,0x2d,0x7d,0xd9,0x92,0x39,0x68,0xe0,0x20,0xf2,0xdb,0x23,0xfc,0x72,0x9f,0xc0,0xcc,0x60,0xe,0x37,0x9e,0x77,0x14,0x8e,0xdc,0xa7,0x3b,0x4a,0x96,0x95,0x32,0x73,0x5a,0xeb,0xd2,0x58,0x88,0xca,0x7b,0x63,0x4c,0x15,0x70,0xa2,0x2c,0xeb,0x3f,0xec,0xd5,0x85,0xff,0xfd,0xd2,0x11,0xc8,0xf,0x66,0xb6,0x9a,0x3b,0x19,0x35,0x89,0x46,0xdc,0x74,0xd9,0xdd,0xd8,0x0,0x60,0xb3,0x43,0x28,0x9a,0x6c,0xae,0x88,0xc9,0x9,0xc2,0x77,0x3f,0x73,0x8,0x98,0x1,0xc7,0xb6,0x2a,0x83,0x66,0x8c,0x41,0x10,0x4,0x88,0xc5,0x62,0x88,0xc5,0x62,0xf0,0x7c,0xf,0x9b,0x36,0x6d,0x82,0xe3,0x38,0x70,0x1c,0x7,0x42,0x8,0x84,0xa1,0x82,0x6b,0x9,0x68,0xad,0x71,0xce,0xf1,0xfb,0xe0,0xd4,0x83,0xa6,0xa1,0xa7,0x2f,0xb,0xab,0xa6,0x7b,0x27,0xf,0xff,0x7b,0xb3,0x80,0xc0,0x3c,0x2a,0xca,0x12,0x31,0x1b,0xab,0xd7,0xf7,0xe1,0x3f,0xcf,0x78,0x37,0xf6,0x9e,0xda,0x6,0xcd,0xc,0x41,0x8c,0x20,0x8,0x60,0xdb,0x36,0x5c,0xd7,0x45,0x18,0x2a,0x6c,0xd8,0xb0,0x1e,0x96,0x6d,0x23,0x1e,0x8f,0x97,0x9e,0x2d,0xac,0x71,0x18,0x43,0xd,0xec,0x35,0x39,0x8d,0xff,0x3e,0xeb,0x30,0xc,0xe,0xe6,0x9a,0xe8,0x7f,0xd4,0x50,0x7,0x80,0x4a,0x5a,0xb1,0xfc,0xff,0x6d,0xf4,0x1,0x78,0x14,0x4d,0x40,0xe3,0x1a,0xb3,0x18,0x1,0xd7,0x7e,0xfa,0x60,0x14,0xfc,0x10,0xf1,0x98,0x33,0xc2,0x3c,0xf4,0xf6,0xf6,0xe2,0xda,0xef,0x5c,0x87,0xdb,0x6e,0xbb,0xd,0x5a,0x6b,0x24,0x12,0x9,0x64,0x32,0x59,0xcc,0x9e,0x3d,0x1b,0x9f,0xfa,0xd4,0xe9,0x38,0xe1,0xa4,0x13,0x87,0xcd,0x48,0x10,0xe2,0xdf,0x3e,0x3c,0x17,0xaf,0x6c,0x18,0xc2,0xca,0x41,0xf,0x89,0xaa,0xeb,0x8d,0xc,0x19,0xb7,0xee,0x28,0x96,0xb3,0x9b,0xbc,0xd5,0xc7,0x1f,0xdd,0xe2,0xa,0x22,0xbc,0xb1,0xa6,0xf,0xdf,0xf8,0xe8,0x2,0x2c,0xd8,0xbd,0x3,0x4a,0x97,0xb7,0x93,0x61,0x14,0xa,0x5,0x7c,0xff,0x7b,0xff,0xf,0x37,0xdf,0x7c,0x33,0x7c,0xdf,0x47,0x32,0x99,0xc2,0xc0,0x40,0x3f,0x76,0xdb,0x6d,0x6,0xce,0xf8,0xec,0xa7,0x71,0xec,0xb1,0xc7,0x42,0x4a,0x51,0xe9,0x25,0x24,0x4,0xc1,0x18,0xc2,0x6e,0x5d,0x49,0x5c,0x78,0xc2,0x3e,0xb8,0xe6,0xcf,0xaf,0xa2,0xad,0x2d,0x39,0xee,0x44,0x2a,0x37,0x39,0x75,0x45,0xd3,0x52,0x2c,0x13,0x40,0xe3,0xac,0xd5,0xb,0x82,0x10,0x27,0xcd,0x9f,0x8c,0xb6,0x84,0x83,0x98,0x6b,0x97,0xea,0xd4,0x22,0x15,0x68,0x59,0x16,0x7e,0xf8,0xc3,0xff,0xc1,0xc7,0x3e,0xfa,0x4f,0xb8,0xfb,0xae,0xbb,0xb1,0xd7,0x5e,0x7b,0x61,0xc1,0x82,0xfd,0xb1,0xcf,0x3e,0xfb,0xe0,0xdd,0xef,0x3e,0x18,0x96,0x25,0x71,0xd5,0x55,0xdf,0xc2,0x69,0xa7,0x9e,0x86,0xa5,0x4b,0x97,0x95,0x96,0x44,0x1,0x45,0x3f,0xc4,0x45,0x27,0xee,0x8b,0xc0,0xb,0xb7,0xe2,0x29,0x73,0x8d,0x62,0xa8,0xfe,0x67,0x9,0x81,0x2d,0x3,0x5,0xac,0xda,0x30,0x84,0x35,0x3d,0x19,0x64,0xf3,0x1,0x6c,0x29,0x23,0xc6,0x8d,0x9b,0x14,0x7e,0xa9,0x31,0x65,0x31,0x50,0xd8,0xab,0x3b,0x89,0xd3,0xe,0xd9,0xd,0x5,0x2f,0x44,0x18,0x4,0xb0,0x2c,0xb,0xbf,0xfd,0xcd,0x6f,0x71,0xec,0xfb,0x8f,0xc3,0xdd,0x77,0xdf,0x83,0x59,0xb3,0x66,0xe1,0x80,0x3,0xe,0xc0,0x3e,0xfb,0xec,0x8d,0x43,0xe,0x39,0x4,0xa9,0x54,0x12,0x57,0x7d,0xf3,0x2a,0x9c,0x7e,0xfa,0x27,0xf1,0xf8,0xe3,0x4f,0xc0,0xb6,0xed,0x8a,0x49,0x10,0x42,0x40,0x8,0x81,0xf,0xec,0x3f,0x1d,0x93,0x92,0x56,0x69,0x19,0xd8,0x38,0x84,0x6f,0xaa,0xf2,0x8,0xbc,0x43,0x7c,0x80,0xba,0x72,0xe5,0x26,0xd1,0x18,0x73,0x2d,0x78,0x43,0x39,0x7c,0xee,0x1f,0xf7,0xae,0x61,0xff,0x8c,0x31,0x90,0x52,0xe2,0xc2,0xb,0x2f,0xc2,0x1f,0x7e,0xff,0x7b,0x74,0x76,0x76,0xa2,0x6b,0x42,0x17,0x98,0x19,0xb6,0x6d,0x21,0x16,0x8b,0x41,0x4a,0x9,0xcb,0xb2,0x30,0x6d,0xea,0x34,0x4,0x7e,0x80,0x2f,0x9c,0xf5,0x5,0x2c,0x59,0xb2,0x4,0x96,0x65,0xc1,0x96,0x84,0x7d,0xa6,0xb5,0x63,0xc1,0xb4,0x34,0x0,0x44,0x3,0xc7,0x3c,0x2a,0x5,0x3b,0x32,0x44,0x3,0xd6,0x6f,0xe8,0xc3,0x79,0xc7,0xee,0x89,0x5b,0xcf,0x3d,0x2,0xbf,0x3a,0xfb,0x50,0xbc,0xef,0x5d,0x9d,0x58,0xb5,0xbe,0x1f,0x31,0xd7,0x1e,0xf3,0xbb,0x15,0xc1,0x97,0x12,0x3b,0x44,0x80,0x57,0xf4,0xf1,0xf9,0xa3,0xf7,0x40,0x10,0x28,0x48,0x62,0xc4,0xe3,0x71,0x5c,0x71,0xc5,0xbf,0xe3,0x7,0x3f,0xf8,0x2f,0x4c,0x9a,0x34,0x9,0x6d,0xad,0xad,0x10,0x42,0xc0,0x71,0x1c,0xb8,0x6e,0xac,0x22,0xe0,0xdd,0x66,0xcc,0x40,0x18,0x84,0xb8,0xf4,0x92,0x4b,0x71,0xef,0xbd,0xf7,0x56,0x26,0x47,0x19,0x4,0x8e,0x94,0x38,0xe7,0xf8,0x7d,0x30,0x30,0x58,0x80,0x94,0x62,0x1c,0xdc,0xd0,0xf0,0xba,0x0,0xb3,0x23,0x0,0xc0,0x64,0x6a,0x7,0xa3,0x9,0x40,0x12,0x11,0xb2,0x59,0xf,0x87,0xec,0xdd,0x8d,0x74,0xcc,0xaa,0xfc,0x94,0x31,0x6,0xc6,0x18,0xdc,0x74,0xd3,0xcd,0x78,0xf4,0x91,0x47,0x90,0x4a,0xa5,0xa1,0xb5,0x86,0xef,0xfb,0x28,0x14,0xa,0x18,0x18,0x18,0x40,0x6f,0x6f,0x1f,0x6,0x6,0x7,0x51,0x2c,0x16,0xe1,0x7,0x1,0x8,0xc0,0x6e,0x33,0x76,0xc3,0x39,0xff,0xf2,0x25,0xf4,0xf6,0xf6,0x55,0xba,0x71,0x1e,0xb9,0x4f,0x37,0x3c,0x2f,0x88,0x54,0x68,0xc5,0x44,0xf3,0x98,0x8e,0xac,0xd2,0x1a,0x41,0xae,0x80,0x25,0xdf,0x3a,0x11,0x9f,0x38,0x7c,0x77,0xcc,0xe8,0x4a,0x62,0xce,0xb4,0x36,0x7c,0xe3,0xb4,0xf9,0xf8,0xc5,0xbf,0xfc,0x3,0xd6,0x6e,0x1c,0x40,0xb4,0x8b,0x0,0x6f,0x2d,0x36,0x8a,0xd4,0xbf,0x4,0x5a,0x5d,0xb,0x73,0xa6,0xb7,0x43,0x10,0xc1,0x75,0x5d,0xfc,0xf1,0x8f,0x37,0xe0,0xf6,0xdb,0x6e,0xc7,0xd4,0xa9,0x53,0xa3,0xa5,0x72,0x61,0x88,0x5c,0x2e,0x8f,0xfe,0xbe,0x7e,0x6c,0xe9,0xdd,0x82,0xc1,0xd2,0xb3,0x85,0x61,0x8,0x21,0x8,0xa9,0x54,0x1a,0x57,0x2c,0xbe,0x2,0x99,0x4c,0x6,0xbe,0xef,0x57,0xae,0xee,0x29,0x8d,0xe3,0xe6,0x4f,0x43,0x3e,0x9b,0xaf,0x6c,0x89,0xd3,0x4c,0x10,0x6e,0x18,0x30,0xac,0x4a,0xaf,0xd5,0xf6,0x38,0x81,0x55,0xdc,0xf4,0xd6,0xa,0x16,0xea,0x2f,0x4c,0x84,0xa1,0xbc,0x8f,0xd3,0xe,0xdd,0x1d,0x79,0x7f,0xb8,0x74,0x49,0x29,0x5,0x66,0xc6,0x77,0xaf,0xbb,0xe,0xed,0xed,0x9d,0xc3,0x37,0x6d,0x18,0x9e,0xe7,0x21,0x93,0xc9,0x62,0x70,0x70,0x0,0xb9,0x4c,0x16,0xbe,0xef,0x47,0x7e,0x82,0x10,0xc8,0xe5,0x72,0x48,0xa5,0x52,0xf8,0xd1,0x8f,0x7e,0x4,0x63,0x18,0x61,0xa8,0x70,0xec,0xfc,0x29,0xc8,0xe,0x15,0x60,0x5b,0x54,0x97,0x8b,0x19,0xfd,0x46,0x7,0x32,0x1e,0xfe,0xfb,0xac,0x43,0x11,0x94,0x98,0x37,0x5b,0xa,0x58,0x52,0x20,0x54,0x1a,0xb,0x66,0xb4,0xe3,0xe3,0x87,0x4c,0x47,0xb6,0x10,0x34,0x6d,0x73,0x9,0x84,0x9,0x49,0x1b,0x53,0x3b,0x53,0x0,0x11,0x6,0xfa,0x7,0xf0,0xd3,0x9f,0x5c,0x8f,0xa9,0x53,0xa6,0xa2,0x58,0x28,0x2,0xcc,0xd0,0x5a,0xc1,0xf7,0x3d,0x64,0xb3,0x59,0xc,0xd,0xe,0x22,0x9f,0xcf,0x23,0x8,0x82,0x92,0xca,0x2f,0x6b,0x46,0x81,0xab,0xae,0xbc,0xa,0x1d,0x1d,0x1d,0x95,0x88,0x81,0x88,0xe0,0x87,0x1a,0x27,0x1e,0x3c,0x3,0x83,0x99,0xe2,0x38,0x9c,0x40,0x6e,0xba,0x8,0xab,0x29,0xd,0x40,0x4c,0x63,0x65,0x71,0x47,0x9,0xfd,0x8,0x7d,0x3,0x39,0x2c,0xd8,0xbd,0xa3,0x44,0xdc,0x44,0x4e,0x5f,0x2c,0x1e,0xc3,0x5d,0x7f,0xbe,0xb,0x4a,0xe9,0x1a,0x54,0x53,0xd,0x77,0xce,0x95,0x22,0x47,0x66,0x3,0x63,0xa2,0x81,0xb6,0x2c,0xb,0x4f,0x3c,0xf6,0x4,0xf2,0xf9,0x3c,0xc2,0x50,0xa3,0x23,0x9d,0x80,0x36,0x66,0x14,0x1b,0xc9,0xd,0x66,0x6,0x63,0x6a,0x8b,0x83,0x89,0x2d,0xb1,0xd2,0x76,0x33,0xc3,0xdf,0xb3,0x4a,0x2a,0x76,0xee,0x6e,0xed,0xb0,0xa4,0xa8,0x8a,0xbf,0x87,0x8b,0x36,0x99,0x79,0xc4,0x80,0x1a,0x66,0xcc,0x9c,0x90,0x4,0x40,0xd0,0x5a,0x63,0xc9,0xb3,0xcf,0x22,0x97,0xcd,0xc2,0xf3,0xbd,0x28,0x27,0x5f,0xdf,0xc,0xa2,0xea,0xff,0x54,0xd9,0x43,0x80,0xd1,0xd9,0xd9,0x89,0x7,0x1f,0x7c,0x8,0xbd,0xbd,0x7d,0x90,0xa5,0x35,0x81,0x42,0x8,0x28,0xcd,0xd8,0x67,0x5a,0x1b,0xfc,0xb0,0xf9,0xa,0x2c,0xae,0x4d,0x38,0xbe,0x9,0x3c,0x40,0x13,0x26,0xc0,0x30,0x23,0x1d,0x77,0x10,0xb3,0x64,0xd,0x1b,0x15,0x73,0x63,0xb8,0xf3,0xce,0x3b,0xd1,0xd9,0xd9,0x5,0x63,0xb8,0xc9,0x18,0xd7,0x44,0x2d,0xd8,0x85,0xc0,0x6b,0xaf,0xbf,0x86,0x4c,0x26,0x3,0xa5,0x23,0xd5,0x36,0xb9,0x3d,0x1e,0x2d,0x48,0x81,0x19,0x31,0x0,0xc3,0x42,0x2b,0x35,0x66,0xe2,0x68,0x51,0x85,0x14,0xa3,0x3f,0x40,0xdc,0x96,0x51,0xe1,0xb,0x50,0x11,0x78,0x2d,0xdf,0x30,0xdc,0xd1,0x43,0x12,0x90,0xcb,0x79,0x98,0xd6,0x95,0x0,0x4a,0xaa,0xf6,0xf9,0xe7,0x9f,0xdf,0x26,0x42,0x4a,0x29,0x85,0x96,0xd6,0x16,0x3c,0xf4,0xe0,0x83,0xb0,0x6c,0xbb,0x32,0x6,0xca,0x18,0x4c,0x6d,0x4f,0x20,0x8,0xf5,0x8,0x52,0x88,0xb7,0x1a,0xae,0x6e,0x1d,0x1,0x62,0x6b,0x2c,0xde,0xf0,0x25,0xc6,0xe9,0x89,0x32,0x90,0x88,0xc9,0xa8,0x61,0x72,0xdd,0x9d,0xaf,0x5c,0xb9,0xa,0xf1,0x78,0xac,0xe6,0xe6,0x9a,0xb5,0x2e,0xf1,0x78,0x1c,0xab,0x56,0xad,0x86,0x6d,0x45,0x11,0x6c,0xc2,0xb5,0x2a,0xc2,0x45,0xb9,0x94,0xba,0x61,0xbc,0x3e,0xfe,0xc5,0x26,0x34,0x66,0x36,0x32,0x7a,0xae,0x20,0x50,0x68,0x89,0xd9,0x51,0xc7,0x6b,0x66,0x6c,0xda,0xb4,0x9,0x96,0x35,0xfe,0x16,0xcc,0xc6,0x18,0x24,0xe2,0x9,0xac,0x59,0xbb,0xa6,0xe6,0xfb,0xc6,0x30,0xd2,0x31,0xb,0x41,0xa8,0x46,0xdc,0x11,0x35,0x77,0xe3,0x3b,0x48,0x3,0x54,0x6d,0x96,0xd8,0xb4,0x9,0x18,0xf2,0x20,0x88,0x60,0xea,0xaa,0x87,0xcb,0x6c,0xd8,0xb6,0xdc,0x73,0x39,0x56,0x2e,0x7f,0x7b,0xf3,0x40,0xb1,0xa1,0x87,0xfc,0xa6,0x71,0xc3,0x55,0x97,0xd4,0xda,0xa0,0xbd,0x2d,0x89,0xb5,0xfd,0x5,0x40,0x8e,0x55,0xcb,0xd0,0xfc,0xb3,0xd5,0x7f,0xdf,0x92,0x2,0x1b,0x87,0x3c,0x24,0xe2,0x4e,0xf3,0xc9,0xa1,0x1d,0x17,0x6,0x6e,0x7,0x9d,0xc6,0xc,0x37,0xe6,0x60,0xe3,0x60,0x11,0xb2,0x2e,0xb7,0x3f,0x63,0xf7,0xdd,0x10,0x4,0xe1,0x36,0x5d,0x36,0x9f,0xcf,0x63,0xda,0xb4,0xe9,0xd0,0x2a,0xda,0xff,0x29,0xeb,0x5,0x10,0x6f,0x53,0x56,0x90,0x4b,0xce,0xee,0xba,0xde,0x3c,0xa2,0xfd,0x5,0x80,0x49,0xdd,0x93,0x10,0x86,0xe3,0xdf,0x19,0x56,0x4a,0x89,0x5c,0x2e,0x83,0xe9,0xd3,0xa7,0x57,0x9c,0x40,0xe6,0xa8,0x56,0x62,0x7d,0x5f,0xbe,0xa1,0xd9,0xda,0x11,0x64,0xa7,0x68,0xfe,0x61,0x69,0x5c,0x4b,0xdd,0xc,0x3,0xc9,0x98,0x83,0xfb,0x96,0x6e,0x40,0xcc,0x1e,0xae,0x49,0xf0,0x7d,0x1f,0xc7,0x1f,0x7f,0x3c,0x6,0x7,0xfa,0xab,0x16,0x8a,0x36,0x37,0xda,0x4a,0x29,0xcc,0x9e,0x3d,0x1b,0xad,0xad,0x2d,0x70,0x2c,0x89,0x25,0xcb,0x7b,0x90,0x4c,0xb8,0x55,0xf5,0x2,0x6f,0x65,0x22,0x28,0x7a,0x2d,0x8,0x58,0xd5,0x9b,0xaf,0x0,0x7a,0xee,0xdc,0x39,0x30,0x46,0x37,0xe5,0x81,0xd7,0xcc,0x74,0xcb,0x42,0x7f,0xff,0x20,0x8e,0x79,0xdf,0x31,0x95,0x50,0xd0,0x18,0x83,0x98,0x2d,0xf1,0xc0,0x8b,0x9b,0x90,0x8a,0x3b,0x4d,0xeb,0xb7,0xd2,0xd2,0xd0,0x11,0x41,0xeb,0x36,0x84,0x81,0xd5,0x2a,0xc5,0x8c,0xb,0x72,0xc6,0x18,0x4c,0x9a,0xd8,0x82,0x9b,0x9e,0x58,0x5,0xd7,0x95,0x15,0xda,0xb7,0x50,0x28,0xe0,0x84,0x13,0x4e,0x80,0x32,0x7a,0x7c,0xf9,0x6e,0x2,0xc2,0x30,0xc4,0xe1,0x87,0x1f,0x8e,0x64,0x32,0x9,0xd7,0xb5,0xf1,0x97,0x17,0x36,0x20,0x16,0x7b,0x8b,0x1,0x50,0x57,0xb5,0xae,0xd,0x23,0x13,0x18,0xbc,0xbe,0x21,0xda,0x7,0x62,0xfe,0x82,0xf9,0x68,0x6d,0x6d,0x85,0x94,0xb2,0xe9,0x39,0x4a,0x44,0xe8,0xef,0xeb,0xc3,0x71,0xc7,0x1f,0x87,0xd6,0x96,0xd6,0x1a,0x1,0xc,0x79,0x21,0x9e,0x5d,0xb1,0x5,0xa9,0x84,0x3b,0x3e,0x7f,0x7d,0xc7,0x44,0x1,0x65,0xe2,0x87,0x9b,0xca,0x88,0xd5,0x1f,0x5a,0x1b,0xc,0x78,0x6,0x4f,0xbe,0xda,0x13,0x6d,0x1,0x4b,0x54,0xa1,0x3c,0x2f,0x38,0xff,0x7c,0xc,0xd,0xd,0x80,0x48,0x6c,0x15,0x8,0xcc,0x88,0x12,0x45,0x9e,0x87,0xcf,0x9d,0xf9,0x59,0x18,0x66,0xc,0xe4,0x2,0x3c,0xfa,0x6a,0xf,0x5c,0xc7,0x1a,0x23,0x9a,0x78,0xf3,0xeb,0xc7,0xb4,0x61,0x4,0x4c,0xb8,0xef,0xc5,0x8d,0x30,0xcc,0x98,0x30,0x61,0x2,0xce,0x3a,0xeb,0x4c,0xac,0x5f,0xbf,0x1e,0xf1,0x78,0x62,0xab,0x5a,0xa0,0x3c,0x31,0x3c,0xdf,0xc3,0x85,0x17,0x2e,0xc4,0xd0,0xd0,0x50,0xc5,0xf,0x48,0xc7,0x6c,0x7c,0xef,0xf6,0x65,0x98,0x31,0x7d,0x42,0xc9,0x9,0xdc,0x96,0xa7,0xe3,0x1d,0x63,0x2,0x1a,0x5f,0x68,0x6c,0x5b,0x10,0x2a,0x3,0x27,0x11,0xc3,0xaf,0x1e,0x59,0x8e,0x50,0x69,0x28,0xa5,0x20,0x84,0x80,0x94,0x12,0xa7,0x9e,0x76,0xa,0xe,0x3a,0xe8,0x60,0x28,0x15,0x34,0xf4,0x9a,0xab,0x7f,0xcd,0xb6,0x6d,0xbc,0xf4,0xd2,0x4b,0xf8,0x9f,0x1f,0xfd,0x10,0x1d,0x9d,0x9d,0xd0,0xda,0xe0,0xfe,0x17,0x37,0x61,0x43,0x4e,0x45,0xf9,0x9e,0x11,0xbd,0x88,0xde,0x42,0x85,0x40,0x40,0x3a,0xe9,0xe2,0x27,0xf,0xad,0x40,0xa8,0xc,0x86,0xb2,0x79,0x9c,0x72,0xea,0x29,0x38,0xfd,0xf4,0x4f,0x60,0xd5,0xaa,0x95,0xa5,0x44,0xcf,0xe8,0xbd,0x84,0x5d,0xd7,0xc5,0xe6,0xcd,0x9b,0xb0,0xf8,0x8a,0xc5,0x68,0x6b,0x6b,0x83,0xe3,0x38,0x20,0x8a,0x38,0x85,0x57,0x36,0xc,0xe2,0x91,0xd7,0x7a,0xe1,0x38,0x56,0x43,0x20,0x51,0x53,0x2a,0x60,0x7,0xf9,0x0,0xdb,0x52,0x10,0x42,0x14,0x79,0xb1,0x8f,0x2e,0xef,0xc7,0x23,0xaf,0xf4,0x44,0xbb,0x7a,0x6a,0x3,0x21,0x4,0x8a,0x45,0xf,0x3f,0xf8,0xaf,0xff,0xc4,0x91,0x47,0x1e,0x89,0xc1,0xc1,0x1,0x64,0x72,0xd9,0x12,0x35,0x2a,0x2a,0x7d,0xf0,0x7c,0xdf,0xc7,0xe0,0xc0,0x20,0x98,0xd,0x6e,0xb9,0xf5,0x66,0xcc,0x9e,0x3d,0x1b,0x64,0x34,0xfa,0xf3,0x1,0xbe,0x75,0xdb,0x32,0x4c,0x68,0x4f,0x34,0x78,0xce,0xb7,0xc1,0x23,0x64,0xc6,0x9b,0xa6,0xb3,0x95,0x0,0x0,0x1e,0xa3,0x49,0x44,0x41,0x54,0x84,0x8e,0x14,0xbe,0xfc,0xb3,0x27,0xd1,0x9a,0x74,0x50,0x28,0x14,0x71,0xde,0xf9,0xe7,0xe1,0x8b,0x5f,0x3c,0x3b,0x62,0xff,0x86,0x86,0x22,0xf0,0x53,0xf4,0x6c,0x44,0x54,0x62,0x3d,0x33,0x8,0x2,0x1f,0xd7,0x7c,0xe7,0x1a,0x1c,0x7b,0xec,0xb1,0x95,0x28,0x20,0x8,0x15,0xa4,0x20,0xfc,0xf0,0xee,0x57,0x10,0x48,0xb,0xa1,0x32,0xd,0x1f,0x8b,0xb7,0xc2,0xe0,0x36,0xe5,0x7b,0x34,0x27,0xf5,0xba,0x1d,0x71,0xc7,0x59,0x94,0xd9,0xdd,0xd5,0x82,0x4b,0x7e,0xff,0x2c,0xba,0x5a,0x62,0x38,0x68,0x56,0x27,0xbc,0xd0,0xc0,0x75,0x5d,0xc,0xe,0xe,0xe2,0x92,0x4b,0x2f,0xc1,0x49,0x1f,0x3e,0x9,0x7f,0xb9,0xe7,0x5e,0x3c,0xfc,0xc8,0xc3,0x58,0xbb,0x66,0x2d,0x8a,0xc5,0x2,0x3a,0xbb,0xba,0x30,0x6f,0xde,0x7c,0x1c,0x75,0xd4,0x91,0x38,0xee,0xb8,0x63,0x91,0x4e,0xa7,0x10,0x86,0xa,0xf9,0xc0,0xe0,0x8c,0xff,0x7a,0x14,0x9d,0x5d,0x2d,0x4d,0xd4,0x9e,0x8e,0x1f,0xc,0xbc,0xd,0x27,0x30,0x0,0xd7,0xb1,0xb0,0x72,0xd0,0xc7,0xa2,0x1b,0x9e,0xc7,0xa2,0x8f,0x2e,0x40,0x36,0x5f,0xc4,0xd9,0x5f,0x3c,0x1b,0x47,0x1e,0x75,0x24,0xee,0xbe,0xeb,0x6e,0x3c,0xf8,0xd0,0x43,0x58,0xb3,0x7a,0x2d,0xb2,0xb9,0xc,0x3a,0xda,0x3b,0xb0,0xef,0xbe,0xfb,0xe0,0xa8,0xa3,0x8f,0xc2,0x71,0xc7,0x1e,0x87,0xf6,0xce,0x76,0x14,0x8b,0x45,0x58,0x96,0x5,0x2f,0x8,0xd1,0x9e,0x76,0x71,0xc5,0xef,0x97,0xe0,0x6f,0xab,0x87,0x86,0xab,0x9f,0x78,0xfc,0xa0,0x6c,0x6,0xc,0x56,0x53,0xd7,0xd8,0xce,0x71,0x55,0xca,0x60,0xf2,0x94,0x4e,0xfc,0xeb,0xf5,0x8f,0xe3,0x5b,0xa7,0x1f,0x84,0x43,0x66,0x4f,0x80,0xd6,0x1a,0x8e,0xe3,0xc0,0xf7,0x7d,0xcc,0x9e,0x3d,0x1b,0xb3,0x67,0xcf,0xc6,0x97,0xbe,0x7c,0x4e,0xb4,0xd,0x5b,0x3,0x32,0xca,0xf7,0x43,0x64,0x3c,0x85,0xcf,0xfc,0xd7,0xa3,0xa0,0x78,0xc,0xc6,0x94,0x8,0xa6,0x1d,0x5c,0x21,0x4c,0xcd,0x9c,0xc0,0x8d,0x7d,0x81,0x64,0xdc,0xc1,0xad,0x4b,0x36,0x40,0x6b,0xc6,0xa5,0xa7,0xcc,0x43,0xa1,0x58,0xc4,0xee,0xbb,0xef,0x8e,0x2f,0x9c,0xfd,0x5,0x9c,0xfd,0xc5,0xb3,0x47,0x38,0xc9,0x5a,0x6b,0x8,0x21,0xa0,0x95,0x86,0x94,0x12,0x61,0x18,0xc2,0x91,0x2,0x17,0xff,0xf2,0x29,0xfc,0x6d,0x75,0xa6,0xaa,0xf4,0x6d,0x7c,0x0,0x1e,0x87,0xf,0xd8,0xa4,0x9,0xa8,0xe4,0xc8,0xb7,0xb1,0x36,0x9f,0x0,0xa5,0x34,0xba,0xba,0x3b,0x70,0xc1,0xaf,0x9f,0xc5,0xcf,0x1e,0x7c,0x1d,0x7d,0x59,0xf,0x71,0x3b,0xda,0x6c,0x11,0x14,0x65,0xf3,0x42,0xa5,0xe0,0xfb,0x1,0x8a,0x9e,0x8f,0xa2,0xe7,0x43,0x29,0x85,0xb8,0x1b,0x61,0xf4,0x9e,0x17,0xd6,0xe3,0xd4,0x6b,0x1f,0x82,0xb6,0x9d,0xda,0x72,0x32,0x6a,0xfe,0x1e,0x88,0x80,0x21,0x3f,0x84,0x32,0x66,0x94,0x81,0x65,0xe4,0xbc,0x10,0x81,0x32,0xdb,0xec,0x49,0x4c,0x9b,0xdc,0x86,0xbb,0x5f,0xee,0xc1,0xe7,0x7e,0xf8,0x57,0xbc,0xb2,0x7e,0x8,0x31,0xd7,0x82,0x2d,0x5,0x82,0x20,0x84,0xe7,0xf9,0xf0,0x3c,0x1f,0x7e,0x10,0x20,0x54,0xaa,0xe4,0x0,0x47,0x2d,0xe0,0x62,0x36,0xe1,0x95,0xd,0x43,0x38,0xff,0x97,0x4f,0xe2,0xde,0xd7,0xfa,0xe0,0x94,0x6a,0x27,0xb6,0xd5,0x24,0xed,0x58,0x13,0x50,0xbd,0x11,0xf2,0x36,0x9a,0xd9,0xc8,0xb1,0x31,0xe8,0x9e,0xd8,0x82,0xdf,0x3c,0xb5,0x1e,0xb7,0x3d,0xb3,0x16,0xef,0xdb,0x6f,0x32,0x4e,0x3e,0x74,0x26,0xde,0x35,0xbd,0x1d,0xac,0x34,0xb4,0x36,0x20,0x21,0x22,0xd2,0x43,0x4a,0xf4,0x67,0xa,0xf8,0xf9,0x83,0xaf,0xe3,0x86,0xc7,0xd7,0xa0,0x37,0x30,0x48,0xb7,0x25,0x23,0x16,0xb0,0x3e,0x31,0x35,0xa2,0x21,0x43,0xe3,0xd4,0x29,0x9,0xc2,0xba,0x2d,0x45,0xbc,0xbe,0x29,0x8b,0xb9,0xd3,0xdb,0x61,0x98,0x2b,0x9,0xa1,0x40,0x19,0x38,0x96,0xc0,0x63,0xcb,0xfb,0xb6,0x8b,0xcd,0xb,0x42,0x8d,0xce,0xb6,0x4,0xd6,0x64,0x3,0x9c,0xf3,0xbf,0x4f,0x61,0xee,0xd4,0x34,0x4e,0x7f,0xcf,0x2c,0x1c,0x35,0x67,0x72,0x54,0xa4,0xaf,0x39,0x2a,0x17,0x43,0x54,0x2,0x6,0x22,0x3c,0xb0,0x74,0x3,0x7e,0xfb,0xc8,0x1b,0x58,0xb6,0x21,0xb,0x2b,0xee,0xa2,0xbd,0x25,0x51,0xb5,0x9,0xe6,0x36,0x80,0x80,0x78,0xc7,0x98,0x0,0xf0,0x28,0x88,0xda,0xe,0xb5,0xcb,0xcc,0x48,0x27,0x5c,0xd8,0xb6,0xc4,0x9f,0x5f,0xee,0xc5,0xaf,0xfe,0xb6,0xa,0x9d,0x49,0x1b,0xfb,0xce,0xe8,0xc4,0xb4,0xb6,0x38,0x5c,0x4b,0x62,0x4d,0x7f,0x1,0x2b,0x7b,0xf2,0x58,0xde,0x93,0x41,0x6b,0x3a,0x81,0xae,0x8e,0x14,0x5a,0xec,0x66,0xc9,0x15,0x1a,0x73,0x62,0x4c,0xef,0x6e,0xc5,0xd9,0x3f,0x79,0x1c,0x7f,0xba,0xf0,0x7d,0xe8,0x6e,0x89,0xd,0xef,0x4a,0x4e,0x84,0x5b,0x9f,0x59,0x8b,0x9b,0x9f,0x5e,0x8b,0x19,0x53,0xda,0xc7,0x4c,0x54,0x6d,0x9d,0x3,0x61,0xc4,0x5d,0x1b,0xa9,0xb8,0x83,0x55,0x19,0x85,0xb,0x7e,0xf7,0x1c,0x54,0xf8,0x34,0xe6,0x4e,0x6f,0xc7,0xb4,0xf6,0x38,0x26,0xb6,0xba,0xd8,0x92,0xf5,0xb1,0xbe,0xbf,0x80,0xa7,0x5f,0xef,0x41,0x2a,0x9d,0x40,0x7b,0x6b,0x1c,0x2d,0xed,0xe9,0xa8,0x5e,0xa2,0xc9,0x19,0x3c,0x2a,0x3c,0x18,0xd8,0x41,0xeb,0x2,0xaa,0x92,0x35,0xd1,0xee,0x87,0x3b,0xc6,0xd1,0x26,0x20,0x8,0xd,0xe2,0x31,0x7,0xbb,0x4f,0xef,0x82,0x61,0xe0,0x95,0x5e,0xf,0xcf,0xae,0xcb,0x46,0x31,0xbf,0x6b,0x21,0x11,0x73,0xb0,0xc7,0x8c,0x9,0xd0,0x9a,0xe1,0x7,0x7a,0xec,0x1d,0xe2,0xc6,0x23,0x1c,0x66,0x4c,0xee,0x6e,0xc3,0x87,0xae,0x7e,0x0,0xc7,0xcf,0x9b,0x82,0x19,0x1d,0x71,0x78,0x4a,0xe3,0xb9,0x35,0x43,0x78,0x7e,0xed,0x20,0x66,0x4e,0x6d,0x2f,0x65,0x17,0xb7,0x93,0x5a,0xa0,0xa8,0xec,0x5b,0x5a,0x2,0xdd,0x5d,0x69,0x10,0x11,0x7a,0x7c,0x83,0xd7,0xdf,0xe8,0xaf,0x14,0x80,0x26,0x62,0x36,0x66,0xce,0xec,0x86,0xd1,0x26,0x22,0xb3,0xb6,0xc1,0xde,0x8f,0x8a,0xf4,0x26,0x9d,0x0,0xab,0xb9,0x18,0x0,0x86,0x44,0xa9,0x6d,0xa9,0xa0,0xed,0x52,0x91,0xd5,0x21,0xa2,0x61,0x46,0x50,0xca,0x73,0xdb,0x52,0xc0,0x49,0xb9,0xa5,0xfb,0x8f,0x12,0x48,0x81,0xc1,0x76,0x27,0x58,0x46,0x23,0x6f,0xba,0xbb,0xd2,0x78,0x62,0xcd,0x10,0x1e,0x5f,0x3d,0x4,0x6,0xc3,0x12,0x2,0x93,0xba,0x52,0x63,0xb,0x1f,0xe3,0xd4,0xca,0xa5,0x46,0x5f,0x15,0xa6,0x92,0x81,0x96,0x94,0x1b,0x6d,0xf2,0x50,0xba,0x4c,0x10,0xa8,0x1d,0xf4,0x54,0x5c,0x43,0x5,0xef,0x18,0xd,0x50,0xba,0x51,0x5b,0x60,0xa8,0x67,0xf3,0x20,0x12,0x31,0x7,0xf1,0x54,0x1c,0x42,0x10,0x5b,0x8e,0xbd,0xc3,0xd7,0x66,0x31,0xef,0x10,0x2b,0xd3,0xb4,0xad,0xb2,0x2d,0x59,0x91,0x27,0xa1,0xc9,0xa5,0x58,0xbc,0xfd,0xb7,0xb4,0xa3,0xa8,0xaa,0x7a,0x2c,0xb2,0xd6,0xac,0x95,0x26,0x15,0x2a,0x1b,0x86,0x13,0x25,0x7b,0x34,0x3e,0x0,0xec,0xf3,0xb9,0xef,0x4b,0x96,0x31,0x1,0x66,0xfd,0xca,0xf,0x3f,0x57,0x6a,0x15,0xce,0x97,0xf4,0x2d,0xbb,0xff,0xf5,0x4c,0xdb,0xd4,0xa3,0xe2,0x5d,0xd3,0x8f,0x71,0xe2,0xc9,0xb6,0x64,0xd2,0xd5,0xa9,0x74,0x52,0x92,0xb4,0xc7,0x37,0x2a,0x4d,0x4a,0x96,0x76,0xf0,0xf5,0x1a,0x9d,0x5c,0x13,0x48,0xec,0xec,0xab,0x8e,0xc7,0xd2,0x3c,0xcc,0x8,0x7c,0x8f,0x33,0x43,0x79,0x52,0x81,0x46,0xbe,0x6f,0xe3,0x93,0x30,0xc1,0xcf,0xeb,0xa7,0xd5,0xde,0x9f,0xff,0x91,0x5,0xc0,0xbc,0xf2,0xe3,0x2f,0x8c,0xec,0x11,0xb4,0xf7,0x59,0x3f,0x22,0x80,0x93,0x20,0xab,0xe3,0x95,0x1f,0x9f,0xb9,0xe6,0x5d,0x5f,0xb8,0x9e,0x88,0x15,0x5e,0xf9,0xf1,0x17,0xca,0x17,0x38,0xc,0xc0,0x24,0x0,0x98,0x70,0xf0,0x29,0xf3,0x3a,0xe6,0x7f,0xe0,0xf2,0x9,0xdd,0xed,0xe4,0xc4,0x5c,0x90,0x90,0xb5,0xfd,0x1,0x4a,0xbf,0xcb,0xcc,0xb5,0xeb,0xfe,0x85,0x1c,0x7d,0x87,0x4d,0x1a,0xd9,0x1b,0x88,0x68,0x6b,0xe7,0x8d,0xdc,0x5a,0xbe,0xf6,0xf4,0xba,0x92,0xb3,0x7a,0x53,0x42,0x34,0x8a,0xe3,0x54,0xf5,0xc,0x8d,0xa6,0xfe,0x98,0xed,0x5f,0xab,0xfe,0xd6,0x60,0xe5,0xd2,0x88,0x86,0x58,0xa3,0xad,0xf9,0x2f,0x95,0xc3,0xd,0x7f,0x5f,0x34,0xa8,0x8,0x8a,0x2e,0xa8,0xc3,0x0,0xfd,0xbd,0x43,0xc8,0xf5,0xae,0xff,0xdb,0x8a,0xdf,0x5d,0x7c,0xd,0x9,0x49,0x6c,0xf4,0x93,0x0,0xd6,0x95,0xcf,0x7d,0xd7,0x59,0x3f,0xa2,0x57,0x7f,0xf2,0x85,0x11,0x10,0xaa,0xe4,0x69,0xbb,0xe,0x38,0x41,0x30,0x63,0xf,0x21,0xf8,0xf5,0x8e,0xf9,0x1f,0x3a,0x13,0x46,0x77,0xa,0x49,0xc1,0xe4,0x43,0x4e,0xed,0xef,0x79,0xea,0x96,0x0,0xc0,0x54,0x8,0xd9,0x22,0x63,0x69,0x3b,0xb7,0xfa,0xb9,0x8d,0xf1,0x49,0x7b,0xcb,0xd6,0x49,0x53,0xf7,0xb3,0x6c,0x2b,0x4a,0xeb,0x56,0x1,0x80,0x8d,0x41,0x18,0x4,0xec,0x17,0x7d,0xa,0x83,0x0,0x61,0xa0,0x10,0x6,0x1,0x88,0xc,0x54,0x10,0x1a,0x29,0x65,0x49,0x20,0xd1,0xb2,0x95,0x61,0x46,0x8f,0x9a,0x6,0x0,0x81,0x9a,0x16,0xfe,0xf0,0xd7,0xc6,0x0,0xc0,0x56,0xd5,0xd0,0xd8,0x8d,0x2b,0xb7,0xc5,0x5c,0x31,0x73,0x69,0xd3,0xa7,0xd2,0x1b,0xd6,0x8,0x83,0x90,0x75,0x18,0x40,0x5,0x21,0xf9,0xbe,0x8f,0xd0,0xf,0xa3,0x54,0x33,0x6b,0x48,0x29,0x6a,0x52,0xe8,0x95,0x9e,0xab,0x5a,0xa1,0x90,0x2f,0x78,0xaf,0xfe,0xfc,0xbc,0x85,0x4e,0xcb,0xc4,0xb8,0x9,0x3d,0xd,0x36,0xeb,0x0,0x64,0x1,0x60,0xdf,0xb3,0x7f,0xba,0x17,0x1b,0x73,0x5c,0xd7,0x81,0x27,0x7d,0x7f,0xc2,0x81,0x27,0x66,0x7a,0x97,0xdc,0xfe,0x4a,0x3,0x13,0xc0,0x64,0x8c,0x99,0xe8,0xc6,0x5c,0xb4,0x75,0xa4,0xa7,0xfb,0xc5,0xf0,0xeb,0xf9,0x5c,0xf1,0xeb,0xbe,0xf6,0x56,0xec,0xfd,0xf9,0x1f,0xfd,0x6d,0xe0,0xe5,0x7,0x1f,0xde,0xfc,0xe8,0x6f,0x7a,0xb5,0x97,0x55,0x0,0xa0,0xbd,0xdc,0x50,0xa3,0xd6,0x66,0xc,0x86,0xd1,0x1a,0x3,0xfd,0x43,0x94,0xeb,0xd9,0xf4,0x54,0x7e,0xe3,0xcb,0xf,0x3b,0xad,0x13,0xa7,0xd9,0x2d,0x13,0xf7,0x4e,0xb6,0x76,0xbd,0x8b,0x89,0x62,0x96,0x95,0x3,0x91,0x40,0x2c,0xe1,0x68,0x41,0x64,0x52,0x2d,0x9,0x61,0x34,0xaa,0x5a,0x89,0x96,0x5f,0x5a,0x55,0x5c,0x4,0x6d,0xb3,0xe6,0xc4,0x36,0x3b,0x91,0x54,0x29,0x41,0xe7,0x9a,0xae,0x68,0x8c,0x11,0x2d,0x6f,0xcb,0xfd,0x79,0xb9,0x4c,0x9a,0xf3,0xc8,0xd9,0x6a,0xca,0x79,0x7a,0x3,0x66,0x66,0x21,0x60,0xc2,0x40,0xb1,0xef,0x7,0x1c,0x6,0xca,0xe,0x43,0x5,0xa3,0x34,0x31,0x3,0x61,0x31,0xb7,0xc6,0xcb,0xf4,0xbe,0xea,0xf7,0xaf,0x7f,0x4d,0xb8,0xc9,0x54,0x7a,0xfa,0x7e,0x9f,0xec,0xea,0x6e,0x93,0xb1,0x58,0x1c,0x24,0xc4,0x48,0xa2,0x5e,0x5,0xfd,0x56,0xb2,0xdd,0xd,0xf3,0x3,0x3e,0xeb,0xd0,0xb4,0xed,0x7b,0x54,0xcb,0xe4,0xf7,0x7c,0xe2,0x93,0x86,0x71,0x5a,0x18,0x86,0xb3,0xe3,0x71,0xa7,0x8d,0xd,0x23,0xc,0xc3,0x67,0x0,0xdc,0x5c,0x3,0x80,0x77,0x9d,0xf9,0x43,0x22,0x6,0xb3,0xe1,0xc9,0xb6,0x6d,0xc1,0x75,0x5d,0xb8,0xae,0x8b,0xd6,0xf6,0x34,0x7,0x7e,0x30,0x23,0x97,0x2d,0x4c,0x6b,0xdf,0xfb,0xa8,0x4f,0x6,0x3,0x9b,0xce,0x1f,0x78,0xf1,0xfe,0x95,0x95,0xa1,0x6d,0xd4,0xb7,0x26,0xaa,0x1d,0xe0,0xe2,0xe0,0xd0,0xa6,0xf5,0xf7,0x7c,0xf7,0x7b,0x61,0x6e,0xc0,0x67,0xe5,0x57,0x4a,0x5a,0xad,0x64,0xbb,0xd3,0xb5,0xff,0x7,0xe6,0xc6,0x27,0xce,0xde,0xaf,0xd8,0xd2,0x3d,0x5f,0x58,0x6e,0x77,0x5f,0xcf,0xa0,0x65,0xbb,0x8e,0x1d,0x8b,0xbb,0x24,0xa5,0x44,0x22,0x11,0x8b,0x2e,0x4f,0x1,0xa4,0x6d,0x83,0x84,0xb5,0x9d,0x6,0xf4,0xad,0xeb,0x28,0xc1,0x35,0xd4,0x23,0xc0,0x46,0xc3,0xa8,0x10,0x5c,0x62,0x1f,0xb5,0xd2,0xc8,0xe7,0x7d,0x10,0x31,0x65,0x6,0xf3,0x2c,0x88,0x43,0x36,0xc6,0xd7,0x85,0x81,0x17,0xfd,0xfe,0x75,0x4b,0x33,0x2b,0x9e,0x5a,0x3a,0xf4,0xfa,0xe3,0x1b,0x2b,0x57,0x89,0xd4,0x39,0x4f,0xff,0xe0,0x5,0x8e,0x97,0xde,0xff,0xe3,0x31,0xd7,0xe5,0x72,0x1f,0x77,0xaa,0xb6,0x46,0x1c,0xed,0xe1,0x47,0x52,0x12,0x2b,0xa0,0xfb,0xb0,0x7f,0xba,0x53,0x90,0x98,0x91,0x48,0x38,0xba,0xb5,0x2d,0x2d,0x18,0xcc,0x85,0x6c,0x81,0x7,0x7,0xc2,0x3d,0x47,0x3a,0x81,0x44,0x10,0xca,0x63,0x40,0x76,0x5a,0x56,0x94,0xad,0x22,0xcb,0x6,0x1b,0x43,0x6e,0xcc,0x95,0xc9,0x54,0xcc,0xac,0x5b,0xbd,0x19,0xc4,0xd5,0x95,0x17,0xa3,0xe7,0xe0,0x9,0x80,0x31,0x6a,0x28,0xcc,0xf5,0x7b,0x6c,0x34,0x93,0x90,0x24,0xdc,0xa4,0x45,0x24,0xc8,0x84,0x9e,0xde,0xf4,0xe8,0x6f,0x9e,0x1,0xf0,0x4c,0xf9,0x1b,0x6d,0x7b,0x1d,0x36,0x39,0xd6,0xbd,0xe7,0x6e,0x76,0xeb,0xa4,0xe9,0x56,0xb2,0x6d,0xaa,0x70,0x92,0x53,0x9d,0x44,0x7a,0x8a,0x1b,0x8b,0x25,0x52,0xe9,0x38,0x27,0xd2,0x49,0x2,0x59,0xa3,0x84,0x84,0x75,0xaa,0xbf,0x54,0x1c,0xca,0xe3,0xea,0xd1,0x4a,0x5b,0xed,0x68,0xc6,0x5c,0xf5,0x4b,0x35,0xf9,0xa,0xaa,0x17,0x7b,0x15,0x7f,0x66,0x60,0x54,0x88,0x81,0xbe,0xc,0x54,0xa8,0x51,0xc8,0xe,0x6d,0x34,0x41,0x61,0xa3,0xf6,0x32,0xeb,0xc2,0x4c,0xef,0xba,0xb0,0x7f,0xcd,0x9a,0xcc,0xca,0xa7,0xd7,0xfa,0x3,0x9b,0x6a,0x8a,0xfe,0x65,0xbc,0xc5,0x8e,0x54,0x7b,0x68,0x4c,0xe8,0x19,0x0,0x8,0xb,0x83,0x5b,0xa2,0xee,0xaf,0x3c,0xb2,0x34,0x94,0x1a,0xae,0x5e,0xca,0xb5,0x75,0xa4,0x75,0x2c,0x1e,0xb3,0xc,0x8,0x14,0x55,0x4d,0x6b,0x30,0x77,0x8c,0x0,0x0,0x81,0xe9,0xc5,0x9f,0x7d,0xc5,0xcc,0xfe,0xcc,0x7f,0xda,0x95,0x25,0x4f,0xa5,0x42,0x5,0x90,0x5,0xad,0x55,0x14,0xba,0x52,0x5d,0x61,0x5a,0xf9,0xdc,0x11,0xc9,0x8,0x6,0x1b,0x26,0x18,0xc5,0x25,0x67,0x90,0x75,0x31,0x53,0x29,0x2,0x14,0x6e,0xd2,0x2,0x1b,0x66,0x63,0xc0,0x3a,0x30,0x83,0xaf,0x3d,0xb6,0x11,0xaf,0x3d,0xb6,0x11,0xc0,0x13,0x91,0x96,0x68,0x73,0x84,0xe5,0xca,0xae,0x3,0x3e,0x74,0x40,0xb0,0xf7,0x51,0xe7,0x93,0x10,0x3a,0x9e,0x4a,0x49,0x8c,0x48,0xfe,0xd4,0xdd,0x8e,0x61,0xe8,0xc0,0x43,0xb1,0xe8,0x6b,0x22,0x92,0xcc,0xd4,0x58,0x3,0xd4,0xcc,0x9f,0x6,0x3d,0x79,0xb9,0xba,0x91,0x53,0xad,0xaa,0xb7,0x2c,0x61,0x62,0x71,0x57,0x90,0xed,0x56,0x9d,0x47,0xb5,0xa6,0xaa,0x42,0xc3,0x6a,0xde,0xb2,0xa9,0x1f,0x5e,0xa6,0xef,0xa5,0xd5,0x7f,0xba,0xe6,0x3f,0x58,0x5,0x3a,0xcc,0xf7,0xfb,0xac,0xc2,0x9a,0xd8,0x8c,0xa4,0x2d,0x40,0x82,0x48,0x5a,0xc4,0x2a,0x30,0xd5,0x63,0x55,0x46,0x7c,0xa9,0xbc,0x9d,0xb8,0xe2,0x59,0xf3,0x48,0x87,0xbb,0x16,0xf3,0xb6,0x56,0x5a,0x80,0x4a,0x79,0x13,0x6d,0xca,0xbb,0x9,0xc8,0x11,0x0,0x60,0x6,0xbf,0xeb,0x73,0xff,0x29,0xb4,0xe6,0xd,0x41,0x10,0x20,0x6e,0x14,0x50,0x9,0xef,0xca,0xff,0xcc,0x88,0xf6,0xe5,0x5c,0xd3,0x36,0x66,0xf8,0x35,0x57,0xff,0x95,0x99,0x21,0x2c,0xda,0xf3,0x93,0x57,0x7f,0x2b,0xcc,0x67,0xd6,0x5,0x43,0x9b,0x5f,0xcb,0xaf,0x7f,0xe9,0xd5,0x30,0xdb,0x9b,0x53,0xd9,0x2d,0xf9,0x60,0x68,0xf3,0x88,0x25,0x2f,0xda,0xcb,0x2b,0x76,0x98,0x37,0x3c,0x70,0xfd,0x5f,0x53,0xbb,0x1f,0x78,0x32,0x23,0x3d,0xb,0x34,0xa,0x21,0x54,0x5,0x6,0x1d,0x16,0xd0,0xdf,0x97,0x45,0x6e,0xa0,0x77,0x55,0x30,0xb8,0xf9,0xd9,0xf2,0xa6,0x2a,0xa0,0x52,0xab,0x6b,0xaa,0xec,0x58,0x51,0x69,0x57,0x46,0x84,0xd2,0xa0,0x56,0x56,0x80,0xa0,0x62,0xa4,0xcb,0xbd,0xd9,0x4a,0x5d,0x1a,0x2d,0x37,0xd5,0xe9,0x74,0x4c,0x3a,0x62,0xc2,0xc4,0x76,0xe1,0x82,0x20,0x2c,0x7b,0xd4,0xbc,0x47,0x69,0xa6,0x1a,0x66,0x96,0x5b,0x9e,0xf8,0xc3,0xf,0xfd,0x81,0xd,0x79,0x21,0x2d,0xd1,0x88,0x63,0x16,0x76,0x4c,0x3a,0xad,0x13,0x13,0x32,0xd9,0x99,0x48,0x74,0xcf,0x9c,0x1c,0x9b,0x30,0x73,0x3f,0xa7,0x65,0xe2,0xbe,0x85,0x75,0x2f,0xfe,0x79,0xc3,0x83,0x3f,0x7d,0xb8,0x9a,0xde,0xc1,0x68,0xd,0x1f,0xa8,0x81,0xcf,0x51,0x69,0x15,0x53,0x71,0x64,0x24,0x3,0xeb,0x47,0x0,0xe0,0xd5,0x9f,0x7e,0x91,0xdf,0xf5,0xd9,0xff,0x16,0x80,0xde,0xac,0x43,0x3,0xd6,0x26,0x6a,0xb,0x55,0xd7,0xd6,0xb7,0x7a,0xa9,0x39,0x1b,0xcd,0x82,0x8,0x30,0x1a,0x4c,0x2,0x24,0xe5,0xb0,0x2a,0xad,0xf,0x93,0x8c,0x62,0x92,0xee,0xc4,0xc9,0xb3,0xf7,0xde,0xd3,0xf3,0x67,0x1d,0xad,0xf7,0x3e,0x14,0x46,0xa9,0xa0,0x90,0xc9,0x6e,0x66,0xe3,0xf5,0x18,0x2f,0xb7,0x51,0xe5,0x7a,0x56,0x14,0x37,0x2f,0x5f,0xdd,0xbf,0xf4,0xde,0x95,0xac,0x43,0xa3,0xbd,0x4c,0x74,0x15,0xe5,0xf,0x46,0x79,0xa8,0xb1,0x3d,0x7e,0xd6,0x21,0x8c,0x6,0xb2,0x7d,0x7d,0x6b,0xde,0xf8,0xf9,0x97,0x16,0xbe,0x59,0x36,0x7e,0xea,0xfb,0xff,0xf5,0x95,0x44,0xe2,0x88,0x73,0xdc,0x98,0x3b,0xac,0x7e,0x79,0x94,0x40,0xbd,0x54,0x47,0x19,0x64,0xfb,0xf2,0x30,0x9a,0x8d,0x89,0xca,0x7d,0x93,0x53,0xf6,0x6e,0x4b,0xcd,0xdc,0x7f,0x96,0xd3,0x36,0x6d,0xa6,0x95,0x6c,0xdb,0xd,0x32,0x3e,0xc1,0x8e,0xc7,0x27,0xc5,0x13,0xc9,0x36,0x10,0x23,0x16,0x73,0xe0,0x7b,0x21,0xf2,0xeb,0xe8,0x9e,0x2a,0x1f,0x7d,0x78,0x6c,0x29,0x7a,0xcf,0x6c,0xc0,0x5a,0x95,0x9a,0x4b,0x94,0x62,0xc6,0x1a,0xcf,0xb0,0x36,0x4b,0x46,0x44,0x82,0x99,0xd7,0x8c,0x42,0x4,0x19,0xb0,0x31,0x5,0x1a,0x61,0xdf,0xa9,0x21,0x85,0x25,0x6d,0x4b,0x64,0x6,0x73,0x88,0xc5,0x43,0x4e,0xb7,0x26,0xa1,0x43,0x43,0xc2,0x76,0x4a,0x28,0x69,0xd0,0x27,0xcf,0x68,0x93,0x48,0xba,0x2a,0x16,0x77,0xad,0x12,0x3e,0x1d,0x9a,0xd4,0x31,0x3d,0x8,0xc2,0xe9,0x61,0xa0,0x91,0xcb,0xcd,0xe2,0xd6,0x3d,0xe,0xc1,0xc4,0x77,0x7f,0x74,0xe8,0x8d,0xdf,0x5e,0xf4,0x45,0x36,0x8a,0xb5,0x97,0xb,0x2b,0xb9,0xe2,0x31,0x66,0x7e,0x65,0x80,0xc0,0xd0,0x7e,0x6e,0x6d,0xe4,0x3c,0x59,0xc4,0x46,0x31,0x9,0x49,0x8d,0xbd,0xf7,0x66,0x1d,0xc7,0xf2,0x4e,0xdf,0xd1,0xcc,0xf5,0x6,0xd6,0x6f,0x1a,0x9e,0x6e,0xe5,0x98,0x74,0x24,0x8,0x22,0x2d,0x50,0xf2,0x89,0xaa,0x42,0xb7,0xdd,0x3e,0x74,0xc1,0xc9,0xc9,0x69,0xfb,0x7e,0x8a,0x99,0x39,0x91,0x88,0x91,0x10,0x84,0x74,0x6b,0x12,0x5c,0x69,0x7,0x43,0x20,0x82,0x31,0xda,0xd0,0x88,0x26,0x90,0xe5,0x56,0xb2,0x5a,0xc3,0xa8,0x0,0x30,0x6,0xa1,0x52,0x5c,0xcc,0x7b,0xe4,0x7b,0x81,0x35,0xb2,0x34,0x6e,0x18,0x30,0xc4,0x1a,0xd9,0x4c,0x1e,0x52,0xd2,0xfa,0x86,0x0,0x60,0x66,0x76,0x1c,0x6b,0x63,0x2e,0x5b,0xe8,0x69,0xeb,0x6a,0x99,0x60,0x94,0x22,0x21,0xe5,0xb0,0x36,0xac,0x1a,0x4,0x0,0x18,0x7c,0xe9,0x81,0xc7,0xac,0x58,0xaa,0x23,0x9f,0xec,0x9a,0x33,0xd8,0x9f,0x98,0x1e,0x4b,0xc4,0x63,0xc9,0x74,0xc,0x44,0x82,0xdd,0xb8,0xc3,0xcc,0x5c,0x3,0x85,0xf2,0x1e,0x36,0xd2,0x8d,0x83,0x28,0x22,0x8e,0x8c,0x56,0x88,0xd9,0x36,0x62,0x9,0x46,0xba,0x3d,0xc5,0xc6,0x18,0xda,0xb2,0x61,0x4b,0xd,0xa9,0x32,0xbc,0x25,0x6a,0x59,0x20,0xd4,0xd8,0x7,0x20,0xd4,0x2c,0xaf,0x2e,0x1f,0xed,0x73,0xde,0x37,0x53,0x2b,0x66,0x22,0x22,0x46,0xa9,0xef,0xbd,0x31,0xa3,0x70,0xbf,0x14,0x39,0x78,0x95,0xfd,0x2f,0xa2,0xff,0xfc,0xbe,0x35,0x7d,0x85,0xd,0xaf,0xc,0x96,0x5,0x4b,0xe5,0xce,0x9d,0x95,0x7,0x1c,0x4d,0x13,0x70,0x1d,0x2f,0xf,0x28,0xa5,0xb8,0x73,0x62,0x2b,0x5c,0xc7,0x31,0x24,0x84,0x60,0x66,0x82,0xb0,0xa2,0xa2,0x59,0x61,0x45,0x49,0x24,0xbf,0x8,0xc3,0x6,0x54,0x4f,0x2e,0x11,0xb3,0x56,0xca,0x78,0x5,0x4f,0xfa,0x7e,0x0,0xaf,0x18,0xc0,0xcb,0x66,0x36,0x71,0x90,0x5f,0x5d,0x58,0xbb,0xec,0xde,0x30,0xd7,0xe7,0x57,0x9a,0x72,0x72,0x69,0x4f,0xd1,0xd2,0x10,0x69,0x6d,0xc,0xb3,0x11,0x4,0x79,0x77,0x43,0x0,0x90,0x20,0x7e,0xf9,0xa7,0xe7,0xac,0x9d,0xfd,0xa9,0xef,0xbf,0xe1,0x15,0xbc,0xae,0x64,0xda,0xa2,0x88,0x27,0x22,0x80,0x99,0x98,0x1,0x99,0x68,0x8b,0x16,0xe4,0xb,0x49,0x85,0xf5,0x2f,0xf7,0xaf,0x59,0xff,0xf2,0x2f,0x1,0x20,0xbd,0xc7,0xc1,0x53,0x92,0x53,0xe7,0xec,0x99,0xeb,0xde,0xf3,0x68,0xb7,0xa5,0x63,0x9e,0xed,0xd8,0x24,0x88,0x46,0xf6,0x58,0x28,0x2f,0xdb,0x12,0x91,0x30,0x85,0xb4,0xaa,0xda,0xcb,0x42,0xa8,0x7c,0x6,0xcc,0x64,0x8d,0x9c,0xa5,0xf5,0xc2,0x1f,0xc9,0xf0,0x8d,0x20,0xdd,0x58,0x43,0x48,0x8b,0xba,0xf,0x3f,0xfd,0xaa,0x44,0xdc,0x35,0x6,0x64,0x45,0xb3,0xb1,0x26,0x54,0xe7,0x3a,0xf,0x36,0xe2,0x97,0xb8,0xf4,0x92,0x98,0xc3,0xd0,0xc8,0xcc,0xaa,0x17,0x7e,0xb3,0xfa,0xb6,0x6f,0xdd,0x58,0x26,0xb9,0x2a,0x33,0xbb,0x5e,0xd7,0x8d,0x20,0xe7,0x47,0x2a,0x43,0x22,0x21,0xb5,0xd2,0x80,0x2b,0xa5,0xb0,0xdd,0xba,0x66,0x57,0x5c,0xd1,0x64,0x84,0xda,0x9a,0x7e,0x2,0xd8,0x2b,0x78,0xe4,0x17,0x7c,0xe9,0x7b,0x85,0x41,0xaf,0x77,0xed,0x7d,0xf9,0x75,0x4b,0x9f,0x2a,0x6e,0x78,0x79,0x83,0xd7,0xbb,0x26,0x57,0x56,0x3b,0xc2,0x72,0xa5,0x9,0xa,0x8a,0x41,0x5d,0x60,0xd6,0x0,0x4,0x6b,0x8d,0x62,0x3e,0x2f,0xb4,0x32,0xea,0xb5,0x9f,0x9d,0xf3,0xe2,0x5e,0x67,0xfc,0xa7,0xf5,0xda,0xcf,0xbe,0xac,0x6a,0x0,0xf0,0xea,0xf5,0x5f,0x62,0x0,0x10,0x82,0x9e,0x2a,0x64,0x8b,0x87,0x25,0xd3,0xc9,0x61,0xef,0x81,0x48,0xba,0x8e,0x6d,0x5a,0x66,0x1d,0x72,0xda,0xc0,0xd2,0x7b,0x5f,0xd1,0x61,0x51,0x57,0x7b,0x3c,0xd9,0x95,0x4b,0x36,0x66,0x57,0x2e,0xd9,0x8,0xa3,0x1f,0x22,0xcb,0x11,0x93,0x8f,0x3c,0xe3,0x18,0xa7,0xa5,0x7b,0x4f,0x92,0xb6,0x60,0xe3,0xeb,0x91,0x29,0x32,0xd4,0x9,0x32,0xa2,0x3a,0xcb,0x2e,0xe4,0xf0,0x6c,0xaa,0xa3,0x4b,0x1b,0xa,0x1f,0xd,0xe2,0x90,0x2a,0x7,0x9a,0x21,0x3a,0x27,0xb4,0x41,0x73,0xed,0x2,0x22,0x6a,0x2a,0xd7,0xc3,0x9c,0xcf,0x16,0x68,0x90,0x9b,0xc9,0x8,0x95,0xa4,0x4f,0x18,0x69,0x6,0x1b,0x74,0xda,0x21,0x1a,0x85,0x12,0x1e,0x65,0x4b,0x25,0x36,0x61,0x90,0xdf,0xb2,0xe6,0xae,0xfe,0x17,0xee,0xb9,0x3d,0xbb,0xfc,0xc9,0x8d,0xe5,0xe8,0x81,0x8d,0xaa,0x51,0x97,0x26,0x28,0xa8,0x49,0x87,0x7f,0xe2,0x30,0x1,0x9a,0xe0,0x38,0xb6,0x1,0x8,0x6c,0x42,0x84,0xa1,0x16,0x6c,0xcc,0xef,0xeb,0xf9,0xe7,0x11,0xc,0x8b,0x65,0xdb,0xd7,0x7,0xbe,0xff,0x15,0x1d,0x86,0xa1,0x25,0x1d,0x1b,0x44,0x20,0x21,0xa9,0xa5,0x2d,0x41,0x5a,0x77,0xce,0x9b,0xf5,0xcf,0x57,0xfe,0xc2,0x1f,0xea,0x79,0xdc,0xef,0x5b,0xfb,0x6c,0x7e,0xf5,0xb3,0x2f,0xe7,0xd6,0x2e,0xeb,0x5,0x6b,0x90,0xb4,0x85,0x70,0xe3,0x16,0xb3,0xe1,0xd,0xf7,0xfd,0xe8,0x5e,0x0,0xf7,0x8e,0x70,0x88,0x1a,0xc5,0xe3,0x55,0x3b,0x88,0x52,0xc3,0x92,0xb3,0xf2,0xa,0x5d,0x1d,0x99,0x8e,0x32,0x4d,0x5c,0x53,0x11,0xca,0x95,0xdf,0xa8,0xd5,0xea,0xc3,0x6d,0x58,0xed,0x58,0x92,0xc6,0xb7,0x86,0x8c,0xa0,0xfd,0x62,0xd9,0xfe,0x37,0x4e,0x5b,0x46,0x21,0x44,0xf5,0xce,0xca,0xc3,0xee,0x81,0x89,0x1a,0x60,0x31,0xd7,0x55,0xf4,0x96,0x16,0xb0,0x72,0x23,0x8e,0x82,0x47,0xa4,0x74,0x2b,0xb,0xe,0x37,0x3f,0xfa,0xab,0xc7,0x0,0x3c,0x16,0xf1,0x4,0x69,0x1b,0x86,0xa1,0xfd,0x5c,0x58,0x26,0x8b,0x3a,0xe7,0x1d,0xb7,0x8f,0xdb,0x3d,0x7b,0xae,0xd3,0x36,0xe9,0xdd,0xb1,0x54,0xeb,0xcc,0x64,0x2a,0xe,0xcb,0xb6,0x25,0x48,0x40,0x7b,0x1e,0x8a,0x79,0xf,0x0,0x7e,0xbc,0xe7,0xa7,0xaf,0x93,0x4,0x32,0xd,0x1,0xb0,0xe7,0xa7,0xaf,0x15,0x2f,0xfd,0xe4,0x8b,0x2f,0xec,0xf9,0xe9,0xeb,0x9e,0x1c,0x1a,0x18,0x7a,0x77,0xc7,0x44,0x7,0x64,0x45,0xc9,0x1e,0x27,0x96,0x44,0xc7,0x4,0x82,0xe,0x93,0x31,0xbf,0xbd,0xe5,0x28,0x6f,0xc2,0xb4,0xa3,0x52,0xd3,0xe7,0x65,0x27,0xb2,0xda,0xe2,0x6f,0x59,0xf1,0x97,0xf5,0xf7,0xfd,0xf8,0x6e,0xad,0x43,0x3,0x21,0x49,0x38,0x9,0x8b,0x75,0x68,0x58,0xf,0xc7,0xbb,0xa5,0x18,0x76,0xcc,0xfc,0x4f,0xa4,0xc,0xeb,0x6,0xdb,0x68,0x23,0x25,0x31,0x87,0x3e,0xeb,0x20,0x88,0x2a,0xbb,0x84,0x4,0x64,0x44,0x13,0x4b,0x27,0x56,0x65,0x61,0x18,0x80,0xae,0xbb,0x66,0x79,0xc0,0x4d,0xa5,0xf5,0xed,0x78,0x38,0xbd,0xda,0x8d,0x1b,0x50,0x9,0xad,0x98,0x23,0x7a,0x85,0x85,0x0,0x54,0x8,0xa3,0x75,0xe4,0xd7,0x84,0x1,0x88,0xc0,0xc6,0x18,0x58,0x92,0xc,0x8,0xb2,0xca,0x75,0xaa,0x7d,0xc6,0x1a,0x0,0x95,0x41,0x80,0x4a,0x24,0x5a,0x65,0x1a,0x18,0x44,0x44,0xd2,0x11,0x44,0x4,0x5d,0xcc,0x86,0x0,0xd0,0x31,0xf7,0x1f,0xf7,0x68,0xd9,0xeb,0xd0,0x13,0x65,0xac,0x75,0x8e,0xb0,0xec,0x96,0x78,0x3c,0x6e,0xa5,0x5a,0x92,0x0,0xc,0x9c,0x78,0x2,0xc2,0x8e,0x41,0x7,0x1e,0x82,0x30,0x44,0x10,0xf8,0xcb,0xa4,0x2b,0x1e,0x67,0x4d,0xf4,0xea,0xcf,0xbe,0xdc,0x58,0x3,0xbc,0xfe,0x8b,0xf3,0xcc,0x3e,0x9f,0xba,0x5a,0x86,0x24,0xbe,0xe8,0x79,0xfe,0x92,0xa0,0x90,0x63,0x27,0xed,0x44,0xc1,0xb2,0x65,0xc1,0xb1,0xdb,0x60,0x94,0x82,0xa3,0x2,0xa4,0xd2,0x49,0x56,0x61,0x6b,0xc2,0x2b,0x14,0x66,0xe4,0x13,0xa9,0xb3,0xdf,0xf5,0xd9,0xef,0x9f,0x1d,0xe4,0x32,0x2f,0xe6,0xd6,0xbc,0xf0,0xa7,0xdc,0x9a,0x67,0x5f,0xf3,0xb6,0xac,0xc9,0x94,0xaf,0x1b,0x6b,0x9f,0x9a,0x20,0xc0,0x2,0x78,0xf4,0x40,0x9e,0x69,0x78,0x79,0x77,0x4d,0x8e,0x5b,0xe5,0x7b,0xd6,0xf7,0x14,0xd,0xc3,0x6a,0x6d,0x6f,0x75,0x8c,0x31,0xb0,0x1d,0x1b,0x6e,0xa9,0x3b,0x98,0x28,0xe6,0x2b,0x3b,0x24,0x9,0x21,0x1b,0xf8,0x4d,0x63,0x6f,0x4d,0x35,0x66,0x1e,0xa0,0xc1,0x22,0x8b,0xca,0x36,0xed,0x5a,0xa3,0x38,0xd4,0xcb,0x20,0x22,0xd6,0x51,0x19,0x17,0x1,0xc8,0x65,0xb,0x10,0x82,0xa8,0x58,0xf4,0x74,0x50,0xf4,0x7c,0x61,0x59,0xc6,0xa8,0xd0,0x54,0xc8,0x81,0xb2,0xdb,0x51,0xad,0xf2,0xeb,0x83,0x2e,0x36,0xc4,0x86,0x49,0xb8,0xc9,0xd6,0x6a,0xf5,0x6e,0xa7,0x3b,0x63,0xf1,0xae,0xdd,0x3b,0x5b,0xf6,0x3c,0xec,0x98,0xd8,0x84,0xdd,0x3e,0x20,0x85,0xb0,0x1d,0xc7,0x66,0x37,0xee,0x98,0x54,0x3a,0x25,0xc,0x1b,0x8,0x2b,0x56,0xe2,0x27,0x4a,0x48,0x32,0x21,0xf,0xd,0xc,0x91,0x10,0xe2,0xd7,0xaf,0xfd,0xf4,0xab,0xc5,0xad,0xd6,0x3,0x28,0x92,0xf4,0xc6,0xcf,0xbf,0xf2,0xec,0x1e,0xa7,0x5f,0xf3,0x48,0x2e,0x57,0x3c,0xa2,0xd5,0xca,0x42,0xa4,0x5a,0x2b,0x9d,0xc2,0x84,0x94,0x80,0x95,0x0,0xc0,0x24,0x1c,0x25,0xdd,0x44,0x12,0xa9,0x16,0x8f,0x3,0xcf,0x33,0x5e,0x32,0xbe,0x5f,0xaa,0xf3,0x98,0xfd,0xf2,0x7b,0x1d,0x1a,0x9a,0x62,0xee,0xe5,0x60,0x68,0xf3,0xb,0x41,0xa6,0x67,0x5d,0x72,0xea,0x3e,0x47,0x39,0xf1,0x58,0x8a,0x41,0x4c,0x42,0x56,0x86,0xb7,0xe6,0xa1,0xa9,0x8a,0x59,0x14,0x52,0x18,0x15,0xad,0x85,0x5a,0x71,0xe3,0xa2,0xef,0x25,0x27,0xef,0xd5,0x1e,0xeb,0x9c,0xd6,0x31,0x18,0xef,0x68,0xb7,0x13,0xad,0x1d,0x32,0xd1,0x36,0x41,0xc4,0x92,0x13,0xa5,0x1d,0xef,0x4e,0xb4,0xb6,0x4e,0x24,0x69,0xb5,0xb0,0x61,0x72,0x5c,0x7,0x96,0x65,0x39,0xb5,0x1a,0xa0,0xbc,0xa6,0x61,0x1b,0xf2,0x1,0xd,0x7a,0xe,0x9,0x29,0x44,0x18,0x84,0xd4,0xd7,0x3b,0x18,0x15,0xb1,0x82,0x95,0x9f,0xcf,0xf5,0x4,0xc5,0x7c,0x8f,0xf1,0xf3,0x3d,0xc6,0xcf,0x6d,0x56,0x85,0xc1,0x3e,0x95,0x1f,0xec,0x57,0xd9,0x9e,0x81,0xfc,0xa6,0x37,0xfa,0xc3,0xa1,0xcd,0x45,0x8,0x49,0x60,0x5d,0xcb,0x2b,0x73,0x35,0xd4,0xb8,0x2a,0x1,0x25,0xc9,0x8d,0xd9,0x70,0x27,0xec,0x7e,0x62,0xf7,0x91,0x9f,0xcd,0xb2,0x56,0x61,0xac,0x73,0xda,0x5c,0x11,0x6f,0xdd,0x37,0x96,0x4c,0x4d,0x8a,0xb9,0xe,0x1c,0xd7,0x66,0xdb,0xb1,0xb5,0x1b,0x4f,0x8,0x90,0x90,0x10,0x12,0x96,0x94,0x35,0xe5,0x60,0x46,0x5,0xc8,0x67,0x73,0xbe,0xa,0x95,0x69,0x4b,0xb6,0x7e,0xbf,0xa9,0x82,0x90,0xd7,0x7f,0x71,0x9e,0x2,0x0,0x29,0xad,0xb,0xb3,0x43,0xb9,0xfb,0x13,0x9,0xd7,0x15,0xbe,0x27,0xa4,0xe3,0xa2,0x9e,0x18,0x17,0xd2,0x2,0x40,0xb0,0xa4,0x4d,0x56,0xb2,0x45,0xc6,0xfc,0x2,0x54,0x10,0xa2,0xb5,0xb5,0xc5,0xf6,0x3c,0x6f,0x9e,0x9e,0x34,0x65,0x1e,0x97,0xd4,0x57,0x2a,0x95,0x80,0xb0,0x9c,0xe1,0x5d,0x8f,0x1b,0x51,0xb9,0xd1,0xe3,0x5b,0xcc,0x86,0x49,0x58,0x4,0x22,0x62,0x15,0x98,0xdc,0xda,0x65,0x7d,0xb9,0xb5,0xcb,0xfa,0x6a,0xe6,0xa7,0x90,0x44,0x96,0x23,0x48,0xd8,0x82,0x2c,0x4b,0xc6,0x27,0xce,0x6e,0x4f,0x4e,0xdb,0x67,0x16,0x98,0xd5,0xf0,0x6c,0x8b,0x5c,0x85,0x7a,0x67,0xbf,0x69,0xf9,0xd3,0xc8,0xb0,0xd2,0xef,0x5b,0xb3,0xb9,0xff,0xf5,0xa7,0xfe,0xa7,0xd8,0xb3,0x72,0x55,0x7e,0xcd,0xb,0xeb,0x95,0x97,0xd,0x60,0x34,0x9b,0xd0,0xd7,0xd5,0x26,0xaf,0x9e,0x1a,0x24,0x12,0x4,0x29,0x8,0x42,0x3a,0x5c,0x36,0xef,0x65,0xbb,0x4f,0xb5,0xb5,0x3,0x32,0x16,0x87,0xed,0x17,0xd0,0x39,0xa1,0xab,0xad,0xad,0xe3,0xf0,0x73,0x4a,0x34,0xa,0xa5,0xd2,0x49,0x80,0x18,0x96,0xe3,0x42,0x3a,0x2e,0x91,0xb4,0x64,0x43,0x67,0x19,0x80,0x31,0x1a,0x7e,0x3e,0x6b,0x32,0x83,0xb9,0x98,0x90,0xf2,0x94,0xa7,0xff,0xe7,0xac,0xc2,0xb8,0x4a,0xc2,0x5e,0xfb,0xc5,0x57,0x1f,0xdf,0xeb,0xd3,0xd7,0xfd,0xef,0x96,0xcd,0x7d,0xe7,0x4c,0x9e,0x2a,0xb5,0xb4,0x1d,0x9,0x1a,0x25,0xe7,0x5e,0x7a,0x10,0x19,0x4b,0xc1,0x8a,0xb,0xe8,0xc0,0x83,0x1d,0x77,0x23,0x22,0x34,0x62,0xa0,0x88,0x2c,0x27,0xb2,0xd7,0xe5,0x72,0xe7,0x6,0x12,0x11,0x42,0x30,0x49,0x8a,0x4d,0x3a,0xe2,0xd3,0x27,0xc,0x2d,0xbb,0xf7,0x1,0x3f,0xb3,0xb9,0x10,0x66,0xfb,0xbc,0x86,0x37,0x28,0x2c,0x11,0xe5,0x26,0xc,0x60,0x8c,0xc9,0xaf,0x5b,0xda,0x93,0x5d,0xf1,0xe4,0xc6,0x7a,0xe3,0x42,0x6c,0x40,0xd8,0x9e,0xfa,0xfa,0x5a,0x27,0x30,0xbb,0xe2,0x99,0xcd,0xd9,0x15,0xcf,0xdc,0xd,0x21,0x49,0xba,0xc9,0xe1,0x30,0xda,0xb2,0x45,0x94,0xdf,0x18,0x59,0x54,0x28,0x2c,0x57,0xb8,0x1d,0x53,0x53,0x4e,0xc7,0xb4,0x8e,0xc4,0xc4,0xdd,0x3f,0x28,0x28,0x6a,0x7c,0x5,0xe6,0xc6,0x31,0x24,0x33,0x9c,0x74,0x2b,0xa4,0xed,0x80,0xcb,0xe,0x4,0x33,0xc8,0x72,0x20,0x2c,0x7b,0xf8,0xbb,0x6c,0x1a,0x42,0x9b,0x99,0x61,0xbc,0x3c,0x32,0x99,0x9c,0xd0,0x2a,0xbc,0xe5,0x8d,0x5f,0x2f,0xbc,0x79,0xaf,0x4f,0x5d,0x6b,0xbd,0xf6,0xcb,0xf3,0x54,0xd3,0x0,0x98,0x7d,0xfa,0xd5,0xf2,0xb5,0x5f,0x9c,0xfb,0xa5,0x3d,0x3e,0x71,0xf5,0x87,0x32,0x43,0xd9,0x19,0x2d,0x42,0xc0,0x49,0xb4,0xd5,0xe5,0x50,0x78,0x4,0x8,0x98,0x35,0x84,0xe5,0x2,0xc2,0x2d,0xbb,0x79,0x11,0x27,0xc0,0x63,0xd5,0x59,0x44,0xdf,0x75,0x92,0x2d,0x94,0x2c,0x14,0x58,0xcc,0x5e,0x70,0xba,0x33,0x61,0xe6,0x87,0x60,0x54,0x16,0xac,0xb3,0x8,0xc3,0xa1,0xb0,0x98,0xd9,0x60,0xbc,0xa1,0x8d,0x7e,0xff,0xba,0x75,0xc5,0x75,0x2f,0x6e,0x28,0x6c,0x59,0x9d,0x63,0xe5,0x8f,0xe0,0xd4,0xc9,0x72,0x4,0x1b,0xc5,0xac,0x35,0xb,0x37,0x21,0xca,0x89,0xa9,0x6d,0xe8,0xb9,0x3c,0x9c,0x68,0x29,0xe5,0xa3,0x85,0x1d,0x97,0x24,0xa5,0x0,0x9,0xe8,0x62,0x56,0xd5,0x24,0x6d,0x2a,0x99,0xcd,0x43,0xa7,0xc4,0x26,0xcc,0x9c,0x6a,0xa5,0x27,0x4c,0x16,0xb1,0xd6,0x69,0xd2,0x8d,0x4f,0x60,0xc8,0x14,0x49,0x99,0x74,0x93,0xa9,0x49,0x89,0x84,0xb,0x37,0x1e,0x83,0x70,0xdc,0x31,0xeb,0xf5,0x88,0x4,0xac,0x78,0x6a,0x98,0xca,0xa9,0x6e,0x7d,0x53,0x2e,0x2a,0x25,0x6a,0x50,0xc4,0xc4,0x50,0xc5,0xc,0xb2,0x3,0x43,0xca,0xcb,0x17,0xf3,0x42,0x5a,0x5f,0xdc,0xf3,0x93,0xdf,0x91,0x8d,0x84,0x3f,0x26,0x0,0xde,0xf8,0xf5,0x42,0x3d,0xfb,0xf4,0x6f,0xdb,0x82,0x70,0x48,0x76,0x28,0xbb,0xdc,0xb2,0xad,0x24,0x1b,0x86,0x9b,0x6a,0xc7,0x70,0x38,0x45,0xa3,0xc7,0xc3,0x3c,0x4a,0x8e,0x7c,0xac,0xf1,0x96,0x16,0x52,0x6d,0x1d,0x14,0x4b,0x16,0xd1,0xd9,0xd5,0xda,0xa,0xa0,0xd5,0x2b,0xfa,0x8,0x82,0x10,0x52,0xa,0x1a,0x1a,0xca,0xa3,0x65,0xd6,0x81,0xc0,0x41,0x27,0x45,0xfe,0x8d,0xa,0x7a,0x74,0x31,0xb7,0x32,0xc8,0xf5,0xaf,0xa,0x6,0x37,0xac,0x2a,0xac,0x7f,0x79,0x55,0x7e,0xdd,0x4b,0xbd,0xa5,0x1c,0x82,0x9e,0x78,0xf8,0xe7,0x8f,0x23,0x40,0x6e,0x47,0x1d,0x26,0x31,0x1b,0xe3,0xb6,0x4d,0x39,0x54,0xba,0xc9,0x1b,0x8d,0xa,0xc,0xb3,0x31,0x76,0xb2,0xcd,0x6d,0xdb,0xfb,0x88,0x3d,0xdc,0xae,0x19,0xbb,0x3b,0xa9,0xce,0x99,0x32,0xd5,0xb6,0xbb,0x74,0x12,0x33,0x89,0xc8,0x2a,0x13,0x8c,0x6e,0xcc,0x81,0x1b,0x73,0xd8,0x28,0x8d,0xd6,0xf6,0x34,0xb4,0xe6,0x88,0x61,0x22,0x1,0x3b,0xd9,0x5a,0xa5,0xfa,0x9,0xa3,0xaf,0xe6,0xe5,0xba,0xb5,0x19,0x3c,0x46,0x99,0x60,0xa9,0x31,0x64,0xe8,0x23,0x33,0x30,0xa0,0x73,0x99,0x82,0x45,0x82,0x3e,0xf6,0xda,0x2f,0xce,0xdd,0xbc,0xdd,0xb5,0x97,0x7b,0x9d,0x71,0xdd,0x11,0xca,0xf3,0x1f,0x6e,0xeb,0x68,0xf5,0x93,0xad,0x2d,0xae,0x93,0x6a,0x6b,0x48,0xc5,0xd6,0xec,0x3d,0xde,0x68,0xf,0xa0,0x31,0xf6,0xa,0xa2,0xea,0xd7,0x24,0xa0,0xc2,0x68,0x83,0x2a,0x36,0x3a,0x4a,0x38,0x1,0xc,0xa3,0x18,0x20,0x16,0x44,0x3c,0x34,0x38,0xc8,0x42,0x4a,0x4b,0x85,0x9a,0xc2,0x20,0xda,0x26,0x2d,0xf0,0xc3,0x88,0x15,0xd4,0x3a,0xc3,0xac,0xa,0x24,0x9c,0x49,0x6d,0x1d,0x29,0x24,0x5b,0xdb,0x61,0xc5,0x53,0xe3,0xaf,0xbb,0x37,0xc,0x95,0xef,0xc7,0xc6,0xf5,0xbd,0x0,0x9b,0xa2,0xd1,0xc1,0xa0,0xb0,0x63,0x93,0x98,0x99,0x2c,0x29,0x2a,0xbd,0x89,0xe2,0x89,0x18,0x8c,0xd1,0xca,0x71,0x1d,0xb8,0xae,0x5b,0x6e,0xd4,0x2e,0x28,0xea,0x85,0x44,0xc2,0x72,0xc1,0x6c,0x22,0xe6,0x53,0x5a,0xd1,0x33,0xd5,0xf3,0xfb,0xc,0x8c,0x6c,0xee,0xd7,0x78,0x93,0xc9,0x11,0xf5,0x83,0xa5,0xa1,0x54,0xc5,0x3c,0xfc,0xdc,0x10,0xf7,0xf5,0xe,0x11,0x1b,0xf3,0xf9,0x37,0x7e,0xbd,0xf0,0x27,0xb3,0x3f,0x79,0xb5,0x7c,0xe3,0x57,0xb,0xf5,0x76,0x1,0x0,0x0,0xf6,0xf8,0xc4,0xb7,0x4f,0x63,0x63,0xfe,0xd8,0xd6,0xd1,0x12,0x26,0x52,0x29,0xdb,0x6d,0xed,0x40,0xcd,0xd2,0xc2,0x6d,0x6,0xc0,0x70,0x8d,0x5f,0x8d,0x6f,0x21,0x86,0x1d,0xa5,0xf2,0x5e,0xb8,0xa6,0x7a,0xbf,0x42,0xd6,0xc3,0x59,0x40,0x15,0x32,0x9,0x9,0x2f,0x3b,0x8,0x22,0xaa,0x9,0x5,0x9d,0x64,0xa,0x76,0xa2,0x65,0x1b,0xe7,0x3f,0x41,0xfb,0x1e,0xc2,0xfc,0x10,0xb4,0xa,0x87,0x93,0x3c,0x60,0xb6,0x9d,0x58,0xc9,0x46,0x33,0xa4,0x9b,0x8c,0x7c,0x91,0x52,0xe1,0x66,0xc4,0x77,0x88,0xe1,0x4e,0xd4,0x86,0x47,0x72,0xb,0x3b,0xa,0x0,0x86,0x1,0x21,0xa0,0xa,0x59,0x4,0x85,0xac,0xd9,0xb2,0xa9,0x4f,0x18,0xe6,0xc5,0x2b,0x7e,0x7b,0xd1,0xe5,0x7b,0x9c,0x7e,0xb5,0x5c,0xfe,0xeb,0x85,0x7a,0xbb,0x35,0xc0,0xac,0x8f,0x5f,0x2d,0x6c,0x77,0x3,0xab,0x60,0xf2,0x49,0x2a,0xc,0x6f,0xe9,0x9a,0xd0,0x8e,0x78,0x3a,0x9,0x37,0xdd,0x9,0x90,0x44,0x55,0xf6,0x4,0xf5,0x9b,0x41,0x8e,0x5f,0x3,0xa0,0x31,0xe7,0xdf,0x90,0xf2,0x2d,0xbf,0x17,0xa5,0x7b,0x10,0xa3,0x74,0x33,0xd9,0xce,0x9a,0xef,0xca,0xb6,0x76,0xf5,0x14,0x75,0xb9,0xd3,0xa7,0xa9,0xe2,0x33,0x78,0xe4,0x6e,0x88,0x5c,0x5f,0x5d,0xc4,0x3b,0x54,0x3,0x84,0xf9,0x21,0x78,0xf9,0x2c,0x7a,0x7b,0xfa,0x20,0x84,0xf8,0xf6,0x1b,0xbf,0xbe,0xe8,0xa2,0x66,0x1f,0xad,0x29,0x6a,0x6c,0xc5,0x6f,0x17,0x1a,0x15,0x4c,0xa1,0xe5,0xbf,0xb9,0xf0,0x56,0x37,0xe6,0x1c,0xd7,0xd7,0xdb,0x8f,0xcc,0xc0,0xa0,0xa,0x32,0xbd,0xac,0x82,0x22,0xca,0xb1,0xfd,0x36,0x14,0xce,0xd5,0x51,0x9f,0x63,0x8,0x6e,0xcc,0x35,0xea,0xe5,0x95,0x37,0x3a,0x72,0xac,0xb8,0xea,0xdf,0x8e,0x28,0xf8,0x67,0x1e,0xe5,0xda,0x8d,0xaa,0x8d,0x68,0xdc,0xcf,0x3e,0xfe,0x13,0x4b,0xf6,0x5e,0x6b,0x84,0xb9,0x7e,0x64,0xfa,0x7a,0x75,0x6f,0x4f,0x2f,0x0,0xfa,0xd7,0x37,0x7e,0x7d,0xd1,0x45,0x7b,0xfc,0xf3,0x55,0x4d,0x17,0x51,0x6e,0x53,0xa5,0xe4,0xac,0x8f,0x5f,0xb5,0xf,0x1b,0xbd,0xc4,0xb2,0xad,0xd8,0xc4,0x49,0x13,0x21,0xec,0x18,0x9c,0x74,0x7b,0x15,0xd9,0x32,0xca,0x9e,0xc0,0x34,0xcc,0xfa,0x8c,0xfc,0xac,0x4e,0x33,0xd4,0x6b,0x91,0xad,0xe,0x2e,0x6d,0xe7,0x53,0x8d,0x57,0x1e,0x63,0xb4,0x90,0xaf,0x3f,0x87,0x6b,0x5f,0x33,0x1a,0xed,0x15,0x58,0xaf,0x1,0xb8,0x4e,0x19,0x70,0x4d,0xd9,0x99,0xe,0x7d,0x14,0x7,0x36,0x23,0x97,0xcd,0xfb,0xf9,0x6c,0xc1,0x15,0x24,0x4e,0x5e,0xfe,0xbb,0xaf,0xdd,0x32,0xeb,0x9f,0xae,0xa4,0x15,0xbf,0xbf,0x98,0x77,0xa8,0x6,0x18,0x71,0xe8,0xe0,0x35,0x99,0x6a,0xed,0xd4,0x61,0xf8,0xf0,0xfa,0xd5,0xeb,0x50,0xcc,0xf4,0x73,0x30,0xb4,0xa5,0x94,0x23,0xdf,0x6,0xb6,0x6d,0xb4,0x85,0x14,0xdb,0x3e,0x7d,0xde,0xe4,0x83,0xb7,0xf9,0x54,0x1e,0x75,0xcd,0x5e,0x13,0xd7,0x2c,0x85,0xda,0x61,0xb6,0x1f,0xb9,0x2d,0xeb,0xcd,0x60,0xff,0x10,0x72,0x83,0xd9,0x75,0x64,0xc5,0x66,0x2e,0xff,0xdd,0xd7,0x6e,0x99,0xf5,0xf1,0xab,0xc6,0x25,0xfc,0x1d,0x32,0x57,0x66,0x7e,0xec,0xdf,0x17,0x82,0xcd,0xb7,0x93,0x2d,0x49,0x9d,0x6a,0x49,0xb,0x37,0xd9,0x4a,0x4e,0xaa,0x3,0xcc,0x6a,0xe4,0x6c,0xaf,0xf6,0x3,0xaa,0x1c,0xc0,0x51,0xb5,0x40,0x1d,0xe1,0xd4,0x38,0xfd,0xfb,0x16,0x69,0x2,0xde,0x11,0xb3,0xbf,0xee,0xef,0x35,0x3b,0x88,0x8e,0xa5,0x1,0x22,0xcd,0x1a,0x16,0x32,0x30,0x41,0x9e,0x33,0x7d,0x3,0x7e,0x36,0x9b,0x8b,0x69,0xc3,0x3f,0x9c,0x3d,0x67,0xfe,0x97,0xee,0xbb,0xfc,0xc3,0x66,0xd6,0xc7,0xff,0x43,0xac,0xf8,0xed,0x45,0xe3,0xee,0x97,0x27,0xb7,0x77,0x5c,0x6,0x5f,0xbc,0xff,0x6f,0xed,0x73,0x8f,0xf9,0x7d,0xe8,0xf9,0xa7,0x16,0x73,0x85,0x94,0x2d,0x41,0xaa,0x30,0x4,0x3b,0x91,0xae,0xaa,0xbf,0x1c,0x9,0x80,0x51,0x81,0x51,0x9f,0x22,0xac,0x7,0xc1,0x78,0x0,0xb0,0xa3,0x80,0x30,0x6e,0xe1,0x6f,0xed,0x32,0xdc,0xa0,0xfb,0x3a,0x8f,0xe9,0x83,0x78,0xfd,0x1b,0x51,0xcc,0xc,0xa0,0x7f,0x73,0xf,0x79,0x5,0xcf,0x83,0x94,0xc7,0xae,0xfa,0xc3,0xa5,0x3f,0xa0,0x49,0x73,0x31,0xb0,0xec,0x7e,0xc,0x2c,0xbb,0x77,0x9b,0xd4,0xa3,0xdc,0x7e,0xd,0xf0,0x4d,0xc1,0x83,0x43,0x7d,0xab,0x6e,0xff,0xe6,0x77,0xda,0xf7,0x3b,0x9a,0x87,0x6,0x6,0xdf,0xd,0x22,0x47,0x17,0x32,0x5a,0x8,0x10,0x9,0x49,0xc2,0xb2,0x87,0x43,0x22,0xa2,0xda,0x82,0xd,0x8c,0xdc,0xdf,0x6e,0x2c,0x2d,0x30,0x12,0x24,0x4d,0x80,0xe0,0x4d,0x5f,0x13,0xc2,0x8d,0xf7,0x41,0x6f,0x68,0xde,0xb6,0xf2,0x6d,0x2e,0x85,0x93,0x42,0x40,0xfb,0x1e,0x54,0x31,0x83,0xcc,0xa6,0xd5,0x3a,0x9f,0xc9,0x89,0xc1,0xfe,0xa1,0x90,0x99,0x7f,0xb8,0xe2,0x86,0xcb,0x8f,0x18,0x58,0x76,0xff,0xea,0x99,0xff,0x7c,0xa5,0x5c,0xf9,0xbb,0xaf,0x6f,0x57,0x97,0xcc,0x1d,0x36,0x34,0x33,0x3f,0xfc,0x75,0x5a,0x79,0xeb,0x37,0x79,0xcf,0x8f,0x7f,0x73,0x4a,0xe0,0xfb,0x8b,0xa5,0x14,0x67,0x3a,0xae,0x63,0x5a,0xda,0xdb,0xd8,0x89,0x27,0xa5,0x93,0xee,0x80,0xe5,0x26,0x86,0x49,0x10,0xaa,0x25,0x7f,0x6a,0x1d,0xbe,0x46,0x21,0x61,0x1d,0x8,0xde,0xa,0xa7,0xb0,0x29,0xc7,0x8f,0x1b,0x2c,0xf9,0xe6,0x6,0xb,0x43,0xab,0xc4,0x3c,0x22,0xcc,0x1b,0x2e,0xe0,0x24,0x21,0xa1,0x82,0x2,0xc2,0x4c,0x1f,0x42,0xdf,0xd3,0x3,0xbd,0xbd,0x26,0xc,0xb4,0xad,0xb5,0xb9,0x47,0x5a,0xf2,0xab,0x2b,0xfe,0x70,0xd9,0xcb,0x3b,0x12,0xba,0x62,0x47,0x5d,0x68,0xe5,0xad,0xdf,0x64,0x0,0x50,0xa1,0xea,0x59,0x7d,0xd3,0xe2,0xb3,0xa4,0x1d,0x9b,0xe4,0x7b,0xc1,0x5f,0x37,0xaf,0xdb,0xa4,0xfa,0x36,0x6d,0x42,0x6e,0xd3,0x6a,0xc,0xad,0x7d,0x15,0x26,0xf0,0xaa,0xfa,0xd8,0x8e,0x62,0xf,0xeb,0x7,0x90,0x1b,0x2a,0xd1,0xa6,0x42,0xa5,0x1d,0xe7,0x3b,0x8e,0xbe,0xa9,0xf3,0x56,0x85,0x8f,0xad,0x34,0xc6,0x2f,0x71,0xfa,0xda,0xcf,0xa3,0xd0,0xbb,0x1e,0xb9,0x8d,0xab,0xd0,0xb7,0xb9,0x7,0x1b,0x56,0xaf,0x17,0xbe,0xa7,0x5e,0x86,0x14,0x7,0xae,0xbe,0xe9,0x1b,0xc7,0x31,0xf3,0xeb,0x3b,0x5a,0x77,0xbd,0x29,0xca,0x71,0xe6,0x69,0x8b,0x64,0x31,0xbb,0xd9,0x6c,0xba,0xfb,0xbf,0x79,0xd6,0xc7,0x16,0x1f,0xa6,0x42,0xff,0x4b,0x42,0x58,0xa7,0xdb,0x8e,0x85,0x64,0x22,0xae,0xdd,0x64,0x12,0xb1,0x74,0xbb,0x24,0x27,0x8e,0x58,0xb2,0x15,0x1c,0x95,0xa4,0x97,0xee,0x48,0x8c,0xa2,0xea,0x47,0x33,0x7,0xcd,0xf8,0x4,0xa3,0x67,0x20,0xb7,0x2e,0xef,0xb1,0x6d,0x73,0x53,0xc2,0x67,0x1e,0x41,0x1e,0x95,0x9f,0x2d,0xc,0x3c,0x68,0x2f,0xb,0x55,0xcc,0x9b,0xdc,0x60,0xbf,0x9,0x83,0xd0,0xca,0xe7,0xa,0x60,0xf0,0x1d,0xb6,0x65,0xff,0xf7,0xf2,0x3f,0x5c,0x7e,0x47,0x64,0x6a,0x17,0x5b,0x2b,0xff,0x70,0x99,0x7a,0x47,0x0,0xa0,0xfe,0x38,0xfc,0xb2,0x3f,0xd1,0x9a,0xe7,0x1f,0xef,0x20,0x41,0x67,0xa,0xe2,0x7f,0x27,0x41,0x76,0x2c,0x1e,0xb,0x5b,0xda,0xda,0x84,0xb0,0x6c,0x69,0xc7,0x53,0x88,0xb5,0x4d,0x2c,0x9,0xbf,0xaa,0x96,0x1d,0x62,0x64,0xea,0x70,0x9b,0xcc,0x41,0x3d,0xb7,0xb0,0xbd,0xc2,0x1f,0x45,0xed,0x37,0x70,0xe8,0xea,0x59,0x3f,0x22,0x1,0xa3,0x2,0x4,0x85,0xc,0x82,0x6c,0x1f,0x88,0x84,0xc9,0xc,0xf4,0x6b,0xaf,0xe8,0xd9,0x2a,0x54,0x60,0xd0,0x77,0x48,0x88,0xef,0xb2,0xed,0x6e,0x5c,0xfd,0xdb,0x8b,0xf5,0x9b,0x2d,0x1b,0xf9,0x56,0x0,0xc0,0x9a,0xb0,0x27,0x41,0x90,0x5a,0x73,0xd3,0x15,0xf,0xf,0xbe,0xfc,0xf0,0x15,0xed,0xfb,0x1d,0xbd,0x22,0xf4,0xfd,0x99,0x99,0xc1,0xa1,0xa4,0xd6,0x2a,0xa6,0xbc,0x2,0xfc,0x4c,0x2f,0x4c,0x50,0x64,0x68,0x4d,0x24,0x44,0x85,0x4b,0x17,0xa5,0x35,0x4,0x8d,0x67,0xf2,0xd6,0x2a,0x84,0xb7,0x3,0x4,0xe3,0x12,0x7e,0x3,0x6f,0x9e,0xa8,0xd2,0x8,0x9b,0xb5,0x6,0xeb,0x10,0xaa,0x98,0x43,0x71,0x60,0x33,0x67,0x7a,0x56,0xc3,0xcf,0x65,0x68,0xb0,0x7f,0x0,0x3,0x5b,0xfa,0xf2,0x81,0x1f,0xae,0x4,0xd3,0x77,0x56,0xdd,0x74,0xc5,0xfb,0x87,0x5e,0x7e,0xf8,0x9e,0xd6,0xbd,0xdf,0xeb,0x81,0x8d,0x19,0x7a,0xe9,0xa1,0x37,0x9d,0xf8,0x78,0x4b,0x1b,0xeb,0xce,0x38,0xf5,0x72,0xc1,0xca,0xa3,0x35,0xb7,0xfe,0x87,0x6,0x80,0x3d,0x3e,0x76,0xf9,0x5e,0xa1,0xe7,0x1f,0xc6,0xe0,0xd3,0x2c,0xc7,0x39,0xc1,0x92,0x2,0xb6,0x63,0xc3,0x76,0x6c,0xbf,0xa5,0xab,0x5b,0x82,0x2c,0x9,0x21,0xc8,0x89,0xb7,0x80,0x2c,0x7,0x76,0x3c,0x51,0xd9,0x1e,0xc6,0x18,0x55,0x95,0x63,0x10,0x15,0x70,0xd0,0x8e,0x0,0x1,0x8f,0xd,0x80,0x8a,0xe3,0x56,0x75,0x1e,0x95,0x72,0x22,0x24,0x25,0x74,0x18,0x40,0x79,0x79,0x68,0xbf,0x0,0x1d,0xfa,0xcc,0x3a,0xd4,0xc5,0xec,0x90,0xe,0x3c,0xdf,0xf5,0x7d,0x1f,0x2a,0x54,0x50,0xa1,0x7a,0x54,0x8,0xfa,0x83,0xb4,0xac,0x87,0x56,0xdc,0x70,0xc5,0xb,0x0,0xb0,0xdb,0x49,0x17,0xa,0xe1,0x24,0xb0,0xea,0x86,0x45,0x6f,0x59,0xff,0xfb,0xb7,0x69,0xaf,0x8d,0xda,0x63,0xf7,0x8f,0x5e,0x2a,0x74,0x28,0x2d,0x21,0xd4,0xc7,0xc0,0xe6,0x33,0x60,0xfe,0x47,0x30,0x23,0x9e,0x4c,0x42,0xda,0x16,0xb7,0xb4,0xb6,0xc2,0x30,0x13,0x98,0x61,0xc7,0x53,0x90,0xb1,0x4,0xe2,0xed,0x93,0x4b,0xeb,0x1e,0x46,0x3e,0x46,0x53,0x11,0x2,0x6d,0x85,0xfb,0x6f,0x6a,0xf6,0xf,0x97,0x80,0xfb,0xd9,0x7e,0xb0,0x31,0x28,0xe,0x6c,0x8c,0x56,0xf8,0xb0,0xe1,0x62,0xa1,0x0,0xbf,0xe0,0xc1,0xf7,0x3c,0x8a,0x56,0xe9,0x88,0x27,0x89,0xf9,0x97,0xc6,0x8e,0xfd,0x52,0x72,0x98,0x5d,0x79,0xc3,0x15,0xe6,0xed,0x1e,0xfb,0x9d,0x2,0x0,0x33,0x4e,0xbd,0x54,0xc2,0x28,0x6b,0xf5,0xcd,0x57,0x55,0x4a,0x7c,0x66,0x7d,0x6c,0xd1,0x11,0xca,0xf7,0x4f,0x4,0xf8,0x60,0xa3,0xcd,0x74,0xcb,0xb1,0xa7,0x3b,0xae,0xeb,0x38,0x4e,0x54,0x12,0x65,0xdb,0x12,0xcc,0xac,0x9d,0x44,0x1a,0x6e,0x22,0x45,0x6c,0xc,0x39,0xe9,0xce,0xa8,0xc7,0x1c,0x31,0xa4,0x13,0xaf,0x3c,0x22,0x33,0xc3,0x72,0x62,0x18,0x5e,0xd7,0x4f,0x35,0x8b,0x8d,0x6a,0x34,0x7e,0x89,0xaa,0x50,0x7e,0x1e,0xc3,0xc5,0x38,0xc,0x56,0x7e,0xd4,0xe1,0x43,0x8,0x56,0x85,0x21,0xb0,0xd1,0xac,0x55,0xc8,0xc5,0x4c,0x3f,0x98,0x59,0x6a,0x1d,0x39,0xb2,0x5e,0xd1,0x87,0xd1,0x86,0x7d,0xdf,0x5b,0x4b,0x44,0xeb,0x88,0x68,0x89,0xb0,0xed,0x3f,0xaf,0xfa,0xe3,0xe2,0x3b,0x2b,0xcf,0xfb,0xe1,0x8b,0x1c,0x92,0x96,0x11,0x96,0xad,0x57,0xfc,0x61,0x11,0xff,0x9f,0x7,0x40,0x45,0x13,0x9c,0x72,0x9,0x31,0x83,0x8a,0x83,0x2b,0xb9,0xe7,0x81,0x5f,0x57,0x6,0x66,0xf6,0x47,0x2f,0xeb,0xc,0xc2,0xb0,0xdb,0x68,0x3d,0x85,0x48,0x1c,0xce,0xc6,0xbc,0xd7,0x71,0x9d,0x83,0x8d,0xe1,0xb4,0x10,0x14,0xed,0xcf,0x67,0x80,0x54,0x4b,0x82,0x1,0x84,0xcc,0xe0,0xd6,0xae,0x89,0x54,0x8a,0x2c,0x88,0xc1,0x44,0xd2,0xa6,0xd2,0x22,0x4d,0xe2,0x91,0xca,0xa2,0x7a,0xc9,0x42,0xa4,0xd8,0x75,0xc0,0xc3,0xe9,0x7b,0xe6,0x42,0x66,0x88,0x4b,0x5b,0xc1,0xd8,0xc5,0x82,0x27,0x8c,0xd1,0x51,0x55,0x92,0x31,0x20,0xa2,0x50,0x85,0xea,0x19,0x30,0x3f,0xc,0xa2,0xbf,0x2,0x58,0x61,0x5b,0x72,0xcb,0x8a,0x9b,0xbe,0x59,0x53,0x8d,0x33,0xe3,0xe4,0xaf,0xb,0x62,0xf0,0xaa,0x5b,0xbe,0xb9,0xd3,0xf4,0x24,0xdb,0xa9,0x0,0xd0,0xd8,0x3c,0x2c,0x22,0x84,0x1,0x31,0x81,0xd8,0x18,0xac,0xb9,0xf5,0x5b,0x35,0x9e,0xf1,0xac,0x8f,0x5f,0xb1,0xb7,0xf1,0xfc,0x5,0x0,0x1f,0x68,0x8c,0x59,0xc0,0xcc,0x7b,0x11,0xd0,0xc6,0xc4,0x82,0x98,0x44,0x69,0x61,0x86,0x48,0x24,0x13,0x42,0x5a,0x56,0x84,0x16,0xf0,0x58,0x2b,0xc3,0x98,0x48,0x70,0x66,0x70,0x90,0x9,0xa4,0x41,0x6c,0xc0,0xd0,0x44,0x30,0x4c,0xc8,0x3,0xb4,0x5c,0x10,0x3d,0xb,0xa6,0xe7,0xa4,0xe3,0x3e,0xbb,0xfc,0xf,0x97,0x3d,0x5b,0x7d,0x81,0xdd,0x4e,0x58,0x28,0xc9,0x76,0x0,0x36,0x4c,0xd2,0xe6,0x55,0x37,0x2e,0xde,0xa9,0x1b,0xd0,0xed,0xf4,0x0,0x18,0x1,0x88,0x53,0x2f,0x11,0x46,0x29,0x41,0x44,0x82,0x8d,0xc1,0x9a,0xdb,0xfe,0x23,0x68,0x6c,0xc6,0x99,0xf6,0xfa,0xf4,0xd5,0x5d,0xc6,0xcb,0x77,0xb1,0x52,0x5d,0x4a,0xeb,0x34,0x33,0xbb,0x20,0x72,0x19,0x70,0x5,0x10,0x63,0x90,0x5b,0xea,0x55,0xee,0x33,0xe0,0x3,0xf0,0xc0,0xec,0x1b,0x63,0x7c,0x37,0x16,0x2b,0x80,0xd1,0x6b,0xa7,0x5a,0xb6,0xcc,0x3e,0xe2,0xa0,0xbe,0x3b,0x3e,0x7f,0x74,0xc3,0x6d,0xce,0xa6,0x9d,0x78,0xa1,0x2d,0xa5,0x24,0x66,0x18,0x21,0x85,0x11,0xb6,0xcb,0x2b,0x7e,0x7f,0x19,0xbf,0x53,0xc6,0xf3,0x1d,0x7,0x80,0x51,0xfd,0x88,0x8f,0x5c,0x5c,0x6e,0x83,0x81,0x35,0xb7,0x5c,0xf5,0xa6,0x8,0x60,0xb7,0x8f,0xfc,0x5b,0xb4,0x5e,0x9c,0x81,0xd5,0x6f,0xd2,0x6f,0xec,0x3a,0x76,0x1d,0xbb,0x8e,0x5d,0xc7,0xae,0x63,0xd7,0xb1,0xeb,0xd8,0x75,0xbc,0x15,0xc7,0xff,0xf,0xd8,0x38,0x69,0x89,0x29,0xb2,0xb8,0x39,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x0,0x0,0x0,0x0d,0x49,0x48,0x44,0x52,0x0,0x0,0x01,0x0,0x0,0x0,0x01,0x0,0x08,0x06,0x0,0x0,0x0,0x5c,0x72,0xa8,0x66,0x0,0x0,0x0,0x06,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x09,0x70,0x48,0x59,0x73,0x0,0x0,0x0d,0xd7,0x0,0x0,0x0d,0xd7,0x01,0x42,0x28,0x9b,0x78,0x0,0x0,0x20,0x0,0x49,0x44,0x41,0x54,0x78,0xda,0xed,0x9d,0x79,0x9c,0x54,0xd5,0x99,0xf7,0x7f,0xe7,0xde,0x5b,0x7b,0x55,0x57,0xf5,0xbe,0x77,0x43,0x37,0x6b,0xb3,0x8b,0x20,0x8b,0x22,0x2e,0xd1,0x98,0x31,0xd1,0xc4,0x84,0x44,0x07,0xd0,0x06,0x9d,0x64,0x26,0xaf,0x8e,0x89,0x79,0x67,0x46,0xf3,0x26,0xa2,0x93,0x65,0x7c,0xe7,0xcd,0x32,0x8e,0x66,0x24,0x09,0x69,0x40,0x8d,0x19,0x26,0x89,0x21,0x2e,0xb8,0x6f,0x80,0x88,0x82,0xa0,0xec,0x74,0x43,0xd3,0xd0,0x6b,0xf5,0x56,0xfb,0x7a,0xef,0x3d,0xef,0x1f,0x8d,0xad,0xd0,0x5b,0x55,0x77,0xed,0xf5,0x7c,0x3f,0x1f,0x3e,0x68,0x51,0x55,0xe7,0xd6,0x59,0x7e,0xe7,0x39,0xcf,0x79,0xce,0x73,0x0,0x82,0x20,0x08,0x82,0x20,0x08,0x82,0x20,0x08,0x82,0x20,0xb2,0x01,0x96,0xce,0x0f,0xbf,0x6d,0xe3,0x46,0xab,0x47,0xa3,0xd1,0xea,0x0,0x0b,0x67,0xcc,0xa4,0xaa,0xaa,0x8e,0x33,0x66,0xa3,0x66,0x25,0xe2,0x3a,0x68,0x38,0x0f,0x88,0xa2,0xe8,0x57,0x65,0xd9,0xc9,0xb5,0xda,0x90,0x28,0x8a,0x6e,0x8d,0x46,0xe3,0x5d,0xb5,0x6a,0x55,0x88,0x04,0x20,0x0e,0x34,0x34,0x34,0xd8,0x24,0xc6,0x96,0x73,0x60,0x16,0x38,0x9f,0x2e,0x70,0x3e,0x93,0x33,0x36,0x03,0x40,0x2e,0x75,0x47,0x22,0x35,0x46,0x12,0x93,0xc1,0x79,0x33,0x07,0x8e,0x0a,0x9c,0x9f,0xe0,0xc0,0x71,0xae,0xaa,0x1f,0xac,0x59,0xbf,0xfe,0x08,0x63,0x8c,0x93,0x0,0x44,0xc1,0xc6,0x8d,0x1b,0x8d,0x26,0x8d,0xe6,0x6a,0x15,0x58,0xc9,0x18,0x5b,0x09,0x60,0x3e,0x0,0x91,0x7a,0x19,0x91,0x86,0x74,0x83,0xb1,0xb7,0x39,0xf0,0x16,0x53,0x94,0xd7,0xd6,0xac,0x5f,0x7f,0x82,0x04,0x60,0x18,0xde,0xdc,0xb0,0x41,0x3a,0x57,0x5d,0x7d,0x83,0x0,0xac,0xe1,0xc0,0x17,0x01,0xe8,0xa9,0xef,0x10,0x19,0x07,0xe7,0xc7,0xc0,0xd8,0x36,0x41,0x51,0x1a,0xfe,0xf6,0xce,0x3b,0x5b,0xb2,0x5e,0x0,0xb6,0x6d,0xdc,0x68,0x0d,0x6a,0xb5,0xdf,0x06,0x70,0x27,0x80,0xc9,0xd4,0x43,0x88,0x2c,0x21,0x04,0xce,0x5f,0xe0,0x9c,0xff,0x7c,0xed,0xfa,0xf5,0xbb,0xb2,0x4e,0x0,0x9e,0xd9,0xb4,0xa9,0x4c,0x61,0xec,0x9f,0x39,0x63,0xeb,0x01,0x98,0xa8,0x3f,0x10,0x59,0x6c,0x15,0x1c,0xe0,0x8c,0xfd,0x74,0xcd,0x1d,0x77,0xfc,0x31,0xd1,0xfe,0x82,0x84,0x0b,0xc0,0xd6,0xad,0x5b,0x4d,0x90,0xe5,0xfb,0x19,0x63,0xf7,0x0,0xb0,0x50,0xeb,0x13,0xc4,0x20,0xbb,0x19,0xf0,0xbd,0xd5,0xf5,0xf5,0xef,0x65,0x9c,0x0,0x70,0xce,0xd9,0x53,0x5b,0xb6,0xac,0x01,0xe7,0x8f,0x0,0x28,0xa1,0xb6,0x26,0x88,0x11,0xc6,0x0a,0x63,0xcf,0x6b,0x54,0xf5,0x1f,0x6e,0x5d,0xb7,0xee,0x5c,0x46,0x08,0xc0,0xe6,0xcd,0x9b,0x6b,0x45,0xce,0x1f,0x03,0xf0,0x79,0x6a,0x5e,0x82,0x88,0x40,0x04,0x80,0x3e,0xc6,0xf9,0x03,0xab,0xeb,0xeb,0x7f,0x1d,0xcf,0x65,0x41,0xdc,0x05,0xe0,0xc9,0xdf,0xfd,0xee,0x4e,0x30,0xf6,0x28,0x0,0x03,0x35,0x2b,0x41,0x44,0x6d,0x39,0xbf,0xa9,0x30,0x76,0x5b,0x7d,0x7d,0x7d,0x67,0x5a,0x09,0xc0,0xc6,0x8d,0x1b,0x8d,0x26,0xad,0xf6,0x09,0x0e,0xac,0xa1,0x66,0x24,0x88,0x09,0xd1,0xc6,0x55,0xf5,0x1b,0xf1,0xd8,0x2d,0x88,0x8b,0x0,0x3c,0xb3,0x69,0x53,0x99,0x2c,0x8a,0xdb,0xc1,0xf9,0xa5,0xd4,0x76,0x04,0x11,0x13,0x42,0xe0,0xfc,0x9e,0x35,0xeb,0xd6,0x6d,0x4c,0x69,0x01,0x78,0xba,0xa1,0x61,0xbe,0x0a,0xbc,0x08,0xa0,0x94,0xda,0x8c,0x20,0x62,0x3c,0x63,0x73,0xfe,0x68,0xd3,0xd9,0xb3,0xdf,0xd9,0xb0,0x61,0x83,0x9a,0x72,0x02,0xf0,0xf4,0xe6,0xcd,0x2b,0x54,0xce,0xb7,0x03,0xa0,0x03,0x39,0x04,0x11,0x3f,0xfe,0x24,0x03,0xab,0xeb,0xeb,0xeb,0x03,0x13,0xfd,0x22,0x21,0x56,0x4f,0xf4,0x64,0x43,0xc3,0xe7,0x54,0xce,0x77,0xd0,0xe0,0x27,0x88,0xb8,0x73,0x8b,0x04,0x6c,0xdb,0xb6,0x6d,0x9b,0x36,0x25,0x2c,0x80,0xad,0x9b,0x36,0x5d,0xce,0x04,0xe1,0x15,0x90,0xa7,0x9f,0x20,0x12,0x07,0xe7,0x7f,0xd5,0x99,0xcd,0x5f,0x59,0xb5,0x6a,0x95,0x92,0x34,0x0b,0xe0,0xc9,0x4d,0x9b,0xe6,0x31,0x41,0x78,0x9e,0x06,0x3f,0x41,0x24,0xda,0x21,0xc0,0xbe,0x14,0xf4,0x7a,0x1f,0x4f,0xda,0x12,0xe0,0x99,0x4d,0x9b,0xca,0x98,0x20,0xfc,0x05,0x80,0x95,0x5a,0x83,0x20,0x92,0xc2,0x37,0x9f,0x6c,0x68,0xf8,0xe7,0x84,0x2f,0x01,0xb6,0x6d,0xdb,0xa6,0x0d,0x7a,0xbd,0xbb,0x0,0x2c,0xa2,0x36,0x20,0x88,0xe4,0x2e,0x06,0x0,0x7c,0x65,0x4d,0x7d,0xfd,0x5f,0x12,0x66,0x01,0x04,0x7d,0xbe,0x7f,0xa3,0xc1,0x4f,0x10,0xa9,0xb1,0x18,0x0,0xf0,0xbb,0x86,0x86,0x86,0x49,0x09,0x11,0x80,0xad,0x0d,0x0d,0x5f,0x01,0xe7,0xf7,0x52,0xbd,0x13,0x44,0xca,0x90,0x2b,0x02,0xff,0x1d,0xed,0xce,0x40,0xd4,0x02,0xf0,0xfb,0xdf,0xfc,0xa6,0x98,0x31,0xb6,0x11,0x69,0x9e,0x50,0x94,0x20,0x32,0xd0,0x0c,0x58,0x1c,0xf4,0x7a,0x1f,0x88,0xab,0x0,0x28,0x92,0xf4,0x4b,0x70,0x5e,0x40,0xd5,0x4d,0x10,0xa9,0xa8,0x02,0xec,0xfb,0x5b,0xb6,0x6c,0x99,0x1b,0x17,0x01,0x78,0xb2,0xa1,0xe1,0xf3,0x0,0xbe,0x41,0xb5,0x9c,0x1c,0x42,0xaa,0x80,0x10,0x17,0xd2,0xea,0x99,0xbd,0xaa,0x04,0x4e,0x4d,0x97,0x38,0x38,0x97,0x04,0x55,0x7d,0x8c,0x73,0x1e,0x91,0x85,0x1e,0xb1,0x19,0xff,0xe8,0xa3,0x8f,0xea,0x72,0x2d,0x96,0x43,0x0,0xa6,0x52,0x2d,0x27,0x06,0xa7,0xa2,0x81,0x3d,0xac,0x83,0x5d,0xd6,0xa3,0x27,0xac,0x87,0x5b,0x95,0x30,0x49,0xeb,0xc1,0xe5,0x96,0x9e,0xb4,0x19,0xfc,0x7f,0x75,0x94,0x83,0x73,0x20,0x57,0x0a,0xa3,0x44,0xe3,0x47,0xa1,0x14,0x44,0x91,0x26,0x0,0x2d,0x53,0xa9,0x81,0xe3,0x69,0x08,0x70,0xbe,0x66,0xf5,0xba,0x75,0x4f,0xc5,0x4c,0x0,0x9e,0x6a,0x68,0xb8,0x9b,0x03,0x8f,0x52,0xd5,0xc6,0x8f,0x30,0x67,0x68,0x0b,0x1b,0xd1,0x15,0xd6,0xc3,0x1e,0xd6,0xc3,0xa9,0x68,0x86,0x6d,0xb0,0xeb,0xad,0xed,0x28,0x90,0x52,0xff,0x0e,0x8a,0xdd,0xee,0x02,0x34,0x87,0xcc,0x43,0x5e,0x17,0x19,0x1f,0x14,0x82,0x72,0xad,0x1f,0x79,0x62,0x90,0x1c,0x4a,0xb1,0x5f,0x0a,0xb4,0xf6,0xbb,0x5c,0x53,0xee,0xb9,0xe7,0x9e,0xe0,0x68,0x6f,0x93,0x22,0xf9,0xae,0x6d,0xdb,0xb6,0x19,0xa2,0x75,0x2e,0x10,0x91,0xcf,0xf2,0xad,0x21,0x23,0xda,0xc2,0x46,0xd8,0xc3,0xda,0x31,0x35,0x99,0x03,0x78,0xdf,0x5b,0x80,0x2f,0x58,0xdb,0x53,0xfa,0x77,0x75,0x85,0x75,0xc3,0x0e,0x7e,0x0,0x50,0x38,0x43,0x67,0x58,0x8f,0xce,0xb0,0x1e,0x1f,0xfb,0x6c,0xd0,0x09,0x2a,0xca,0x34,0x3e,0x54,0x6a,0xfd,0x28,0xd3,0xf8,0x21,0x91,0x75,0x10,0x8b,0xa5,0x40,0x45,0x9e,0xc5,0xb2,0x1e,0xc0,0xaf,0x26,0x6c,0x01,0x6c,0x6d,0x68,0xf8,0x16,0x03,0xfe,0x8b,0x6a,0x35,0x76,0x83,0xfe,0x6c,0xc8,0x88,0xd6,0x90,0x11,0x7d,0xb2,0x6e,0x5c,0x6b,0xe4,0xe5,0xe6,0x6e,0x4c,0xd6,0x79,0x53,0xb3,0xef,0x01,0x78,0xd9,0x59,0x8a,0x1e,0x59,0x17,0xf5,0x67,0xb5,0x4c,0x45,0x99,0xc6,0x8f,0x0a,0xad,0x0f,0xe5,0x5a,0x1f,0x34,0x8c,0x3c,0x08,0x13,0x68,0x87,0x73,0x7a,0x93,0x69,0xca,0x68,0x57,0x96,0x8d,0x69,0x01,0xbc,0xb9,0x61,0x83,0xd4,0x0a,0xfc,0x13,0x55,0xe7,0xc4,0x08,0x72,0x11,0x67,0x02,0x46,0x9c,0x0e,0x59,0xd0,0x2b,0x4f,0xf8,0x10,0x17,0x0e,0xfa,0x72,0x51,0xa5,0xf5,0x41,0x4c,0xc1,0x01,0x72,0x26,0x64,0x1e,0xd7,0xe0,0x07,0x80,0x10,0x17,0x70,0x26,0x64,0xc2,0x99,0x90,0x09,0x22,0xe3,0xa8,0xd2,0x78,0x51,0xa3,0xf7,0xa2,0x54,0xe3,0xa7,0x4e,0x14,0xed,0x2a,0x0,0xa8,0x0c,0x79,0x3c,0xb7,0x02,0xd8,0x32,0x6e,0x01,0x68,0xab,0xaa,0xba,0x19,0x74,0x61,0xc7,0xb8,0x90,0x39,0x43,0x73,0xd0,0x84,0xe6,0x90,0x25,0x22,0xf3,0x3e,0x1a,0xbc,0xaa,0x84,0xa3,0x81,0x1c,0xcc,0x31,0x38,0x53,0xea,0x37,0x2b,0x9c,0xe1,0x80,0x37,0x37,0x66,0xdf,0xd5,0x1c,0x32,0xa3,0x39,0x64,0x86,0x56,0x50,0x51,0xad,0xf5,0xa1,0x46,0xe7,0x41,0xa1,0x14,0xa0,0xce,0x15,0xa9,0x15,0xc0,0xd8,0x77,0x46,0x13,0x80,0x31,0xf7,0x94,0x38,0xb0,0x8e,0xaa,0x31,0x3a,0x5c,0x8a,0x06,0xfb,0xbc,0x79,0x78,0xd6,0x51,0x89,0xbd,0xde,0x02,0xd8,0xc3,0x3a,0xc4,0x23,0x6e,0xea,0xb8,0xdf,0x9a,0x72,0xdb,0x82,0x8d,0x41,0x0b,0x7c,0x6a,0xec,0xaf,0x71,0x0c,0xa9,0x02,0x1a,0x03,0x66,0xbc,0xec,0x2c,0xc1,0x4b,0xce,0x52,0x34,0x06,0x2c,0x50,0x38,0xb9,0x0e,0x23,0x60,0xde,0xd6,0x4d,0x9b,0x2e,0x1d,0x97,0x05,0xd0,0xd0,0xd0,0x50,0x02,0xe0,0x3a,0xaa,0xc3,0xc8,0x68,0x0d,0x19,0x71,0x34,0x60,0x3d,0x3f,0xe0,0x13,0xb1,0xac,0x10,0x70,0xc4,0x6f,0xc5,0x02,0x63,0x7f,0x4a,0xfc,0xfe,0x30,0x67,0x38,0xe4,0x8b,0xff,0xc1,0xd0,0x1e,0x59,0x87,0x1e,0x59,0x87,0x0f,0x7d,0x79,0xa8,0xd1,0x7b,0x30,0x5b,0xef,0x80,0x41,0x50,0xa8,0x03,0x8e,0x34,0xcb,0x33,0xb6,0x06,0xc0,0xbe,0xa8,0x2d,0x0,0x91,0xf3,0x5b,0x41,0xb7,0xf2,0x8e,0x8a,0x0a,0x86,0xd3,0x41,0x13,0x5e,0x74,0x96,0xe1,0x2d,0x77,0x51,0xc2,0x06,0xff,0xa0,0x15,0x10,0xc8,0x81,0x5f,0x4d,0x8d,0x26,0x3a,0x16,0xb0,0x22,0xc8,0x13,0xf7,0x2c,0x61,0xce,0x70,0xc2,0x6f,0xc1,0xb3,0x8e,0x4a,0xec,0xf6,0x14,0x0c,0xbb,0x6d,0x4a,0x0,0x9c,0xb1,0x5b,0x37,0x6e,0xdc,0xa8,0x89,0xda,0x02,0x60,0x8c,0xdd,0x4a,0xd5,0x37,0x32,0xe7,0x42,0x46,0x1c,0xf4,0xe5,0x26,0xb5,0xe3,0x29,0x9c,0xe1,0x88,0xdf,0x8a,0x4b,0x4d,0x7d,0x49,0xad,0x8b,0x90,0x2a,0xe0,0xb8,0x3f,0x27,0x39,0x22,0xcc,0x81,0xe6,0xa0,0x19,0x2d,0x41,0x13,0xaa,0xb4,0x3e,0x5c,0x62,0xea,0x83,0x91,0x2c,0x82,0xcf,0x52,0x68,0xd4,0x6a,0xaf,0x01,0xf0,0x52,0xc4,0x16,0xc0,0x79,0xf3,0x9f,0xd2,0x7a,0x8f,0x42,0x73,0xd0,0x94,0x12,0xb3,0xce,0xc9,0x80,0x05,0x3e,0x55,0x4a,0xea,0x33,0x1c,0x0b,0x24,0xdf,0x1f,0xa1,0x82,0xe1,0x4c,0xc8,0x04,0xb7,0x22,0x51,0xe7,0x1c,0x3a,0x9b,0xff,0x4d,0x54,0x4b,0x0,0x89,0xf3,0xab,0x40,0x27,0xfe,0x46,0x45,0x9b,0x22,0x5b,0x70,0x2a,0x18,0x0e,0xf9,0x93,0x97,0x94,0x29,0xc8,0x45,0x1c,0x0b,0xe4,0x50,0xbb,0xa4,0xf4,0x5a,0x55,0xbd,0x26,0x3a,0x1f,0x80,0x20,0x5c,0x4d,0xb5,0x36,0x3a,0xa2,0x90,0x3a,0x1d,0xed,0x54,0xc0,0x0c,0x6f,0x92,0xac,0x80,0xa3,0x7e,0x0b,0xe4,0x14,0xf2,0xc8,0x8b,0x24,0x0,0xc3,0x59,0x0,0x33,0xb7,0x6c,0xd9,0x52,0x1e,0xb9,0x0,0x70,0x4e,0x02,0x30,0xd6,0x4c,0x83,0xd4,0x09,0x59,0x55,0x31,0xe0,0x0b,0x48,0xc6,0xec,0x7f,0xd2,0x9f,0x93,0x5a,0xed,0x42,0xa1,0xc4,0xc3,0xcf,0xe9,0x9c,0xaf,0x8c,0x48,0x0,0xb6,0x6e,0xdd,0x5a,0x04,0xa0,0x86,0xaa,0x6c,0x74,0xa4,0x14,0x9b,0x69,0x9a,0x02,0xe6,0x84,0xfb,0x02,0x8e,0xfb,0x73,0x10,0x86,0x90,0x62,0xed,0x42,0x02,0x30,0x02,0x4b,0x22,0xb3,0x0,0x64,0x79,0x26,0xd5,0x55,0x24,0xa6,0x66,0x6a,0x75,0x34,0x15,0x0c,0xc7,0x12,0x38,0x1b,0x87,0x39,0xc3,0x89,0x80,0x25,0xc5,0x5a,0x85,0xd3,0x12,0x60,0x64,0xab,0x7e,0x66,0x44,0x02,0xc0,0x04,0x61,0x3a,0xd5,0x56,0x7a,0x9a,0x9a,0x27,0x83,0x96,0x84,0xed,0xc5,0x9f,0x0c,0xe4,0xa4,0x5c,0x24,0xa2,0xc4,0x38,0x79,0xae,0x47,0xf6,0x03,0x4c,0x8f,0xcc,0x02,0xe0,0x9c,0x04,0x20,0x22,0x0b,0x20,0xf5,0x66,0x1a,0x85,0x33,0x9c,0xf0,0x9b,0xe3,0x6f,0x6d,0x70,0xe0,0x44,0x20,0x27,0xe5,0x7e,0x3f,0xed,0x0,0x8c,0x6a,0x01,0x94,0x6f,0x7b,0xfc,0x71,0xf3,0xd8,0x02,0x40,0x59,0x7f,0x22,0x42,0x93,0xa2,0x6b,0xcd,0x13,0x81,0x9c,0xb8,0xc7,0xc9,0x9f,0x0e,0x99,0xe3,0x12,0xf3,0x9f,0x89,0xa2,0x9c,0x4a,0x36,0x40,0xd8,0x68,0x9c,0x72,0x81,0xc5,0x34,0xc2,0x1b,0x4b,0xa8,0xae,0x22,0x11,0x80,0xd4,0xec,0x6c,0x41,0x2e,0xe2,0x74,0xd0,0x84,0xa9,0x7a,0xcf,0x88,0xef,0x09,0xa9,0x02,0x14,0x30,0x84,0xb9,0x80,0x30,0x67,0x0,0x18,0x04,0xc6,0x21,0x31,0x15,0x5a,0xc6,0x21,0x41,0x1d,0x71,0x30,0x71,0x20,0x69,0x51,0x7f,0xe9,0xb8,0x2c,0x4b,0x25,0xd4,0x8b,0xc6,0xb6,0x34,0x42,0x03,0x5b,0x68,0x1d,0x15,0xc9,0x7a,0x33,0x75,0x3b,0xdb,0xb1,0x80,0x15,0x12,0x1b,0x38,0x36,0xec,0x55,0x45,0x78,0x14,0x09,0x3e,0x55,0x82,0x47,0x95,0xa2,0xb2,0x0e,0xf4,0x82,0x02,0xb3,0xa0,0xc0,0x24,0x84,0x61,0x14,0x14,0x98,0x44,0x19,0x32,0x67,0x70,0x28,0xda,0x94,0xfc,0xdd,0x22,0x48,0x0,0x46,0x5d,0x05,0x0,0x96,0x31,0x05,0x80,0x5d,0xf4,0x26,0x22,0xfd,0x04,0xc0,0xa5,0x68,0xb0,0xdb,0x33,0xf1,0xec,0xed,0x01,0x55,0x44,0x40,0x15,0xd1,0x03,0x6d,0x5a,0xb4,0x09,0x59,0x0,0xa3,0x23,0x5c,0x34,0xb6,0x47,0xf2,0x01,0x90,0x0,0x44,0x80,0x81,0x3a,0x5b,0xca,0xa1,0xa3,0x43,0x40,0x63,0x91,0x13,0x89,0x0,0x98,0xa8,0x9e,0x22,0xb3,0x0,0xc8,0xe9,0x94,0x62,0xa2,0x2c,0x90,0x28,0x8f,0xea,0x03,0xe0,0x3c,0xa2,0x5d,0x0,0xca,0x01,0x10,0xe9,0x1a,0x99,0xd1,0x8c,0x93,0x5a,0x16,0x0,0x09,0xc0,0x68,0x30,0xc6,0xa4,0x48,0x04,0x80,0xa0,0x19,0x27,0x4d,0x05,0x59,0xa6,0x4a,0x88,0xce,0x27,0x40,0x50,0x87,0x23,0x41,0x26,0x01,0x20,0xc6,0x67,0x72,0x8a,0xd4,0xe1,0x48,0x90,0x49,0x0,0xb2,0x16,0x93,0x40,0x1d,0x2e,0x95,0xa0,0x54,0x60,0x24,0x0,0x09,0xc5,0x4c,0x02,0x90,0x32,0x48,0x4c,0x85,0x96,0x96,0x0,0x24,0x0,0x89,0x9d,0x71,0x48,0x0,0x52,0xc7,0x1a,0xa3,0xd9,0x9f,0x04,0x80,0x2c,0x80,0xec,0x6d,0x0b,0x91,0xda,0x82,0x04,0x20,0xd1,0x16,0x80,0xa8,0x0,0xa0,0x60,0xa0,0x94,0x68,0x0b,0x72,0x0,0x92,0x0,0x24,0x1a,0xb7,0x22,0x41,0xa4,0x93,0x53,0x29,0x41,0x90,0x8b,0x50,0x29,0x1d,0x48,0x54,0x50,0x02,0xf5,0xf1,0x76,0x36,0x55,0xc0,0x3e,0x5f,0x1e,0x9a,0x83,0x26,0x50,0xf6,0xf4,0xd4,0xe0,0x6c,0xc8,0x88,0x67,0xfb,0x2b,0xb0,0xc0,0xd8,0x87,0x9a,0x14,0xbd,0x3a,0x9d,0x04,0x20,0xcd,0xe1,0x18,0x48,0xbe,0x79,0xd0,0x9f,0x87,0xa0,0x4a,0x06,0x54,0xaa,0xe1,0x57,0x45,0xbc,0xeb,0x29,0xc4,0xe9,0xa0,0x05,0x8b,0x4c,0xbd,0xb0,0x8a,0x61,0xaa,0x14,0x12,0x80,0xd8,0x99,0xfb,0xef,0x7b,0xf3,0xd1,0x11,0x36,0x50,0x65,0xa4,0x38,0x9d,0x61,0x3d,0x76,0x38,0xcb,0x30,0xc7,0xe0,0xc4,0x4c,0x83,0x13,0x02,0xf9,0x69,0xd2,0xd3,0x07,0x10,0x50,0x45,0x7c,0xe4,0xb3,0x25,0xf4,0xd2,0xc9,0x8b,0x19,0xc8,0xb9,0x6f,0xc3,0xf3,0xce,0x72,0x1a,0xfc,0x69,0x84,0xcc,0x19,0x0e,0xf8,0x6c,0x78,0xd1,0x59,0x86,0x5e,0x59,0x97,0xd4,0x67,0xe9,0x0a,0xeb,0x71,0x3c,0x05,0x73,0x28,0xa6,0xb4,0x05,0x10,0xe6,0x0c,0xaf,0xbb,0x8b,0xd1,0x2f,0x6b,0x71,0x2c,0x90,0x83,0x3a,0xbd,0x0b,0x33,0x0d,0xce,0x84,0xa6,0xe2,0x72,0x28,0x5a,0xec,0xf6,0x14,0xa0,0x5f,0xd6,0xd2,0x88,0x4a,0x53,0x1c,0xb2,0x06,0x2f,0x39,0x4b,0x31,0xd3,0xe0,0xc2,0x7c,0x43,0x1f,0x84,0x04,0xba,0x6c,0x7a,0x65,0x1d,0x3e,0xf2,0xe7,0xa2,0x3d,0xa4,0x07,0x0,0x30,0xce,0x31,0xdd,0xe0,0x26,0x01,0x18,0x73,0xd6,0xe5,0xc0,0xdb,0xee,0xa2,0xc1,0x81,0x27,0x73,0x01,0x1f,0xfb,0x6d,0x38,0x11,0xcc,0xc1,0x2c,0x83,0x13,0xd3,0x75,0xae,0xb8,0x9f,0xc5,0x3f,0x19,0xcc,0xc1,0x7e,0x6f,0x6e,0xdc,0x13,0x6c,0x12,0xf1,0x87,0x03,0x38,0xea,0xcf,0x41,0x57,0x58,0x8f,0xcb,0xcd,0x76,0x58,0xe2,0x1c,0x33,0xe0,0x54,0x34,0x38,0xe8,0xcf,0x45,0x6b,0xd0,0x78,0xc1,0xe2,0xe3,0x03,0x5f,0x1e,0x0c,0xa2,0x8a,0x2a,0x6d,0x6a,0x38,0x29,0x85,0x54,0x6d,0xac,0x3d,0xde,0x42,0x74,0x0e,0x63,0x6e,0x07,0x55,0x01,0x1f,0x7a,0x73,0xf1,0x57,0x67,0x05,0xce,0x84,0x4c,0x71,0x59,0xd9,0x85,0xb8,0x80,0xb7,0xdd,0x45,0x78,0xdf,0x93,0x47,0x83,0x3f,0xc3,0xe8,0x95,0xb5,0x78,0xd1,0x51,0x76,0x7e,0xf7,0x26,0xf6,0x04,0xb9,0x88,0xbd,0xde,0x7c,0x3c,0xef,0x28,0xc7,0xb9,0x8b,0x06,0xff,0x0,0x0c,0xbb,0xdc,0x05,0xb0,0xcb,0x7a,0x12,0x80,0x91,0x78,0xdf,0x9b,0x3f,0x66,0x03,0x79,0x15,0x11,0xbb,0xdc,0x85,0xd8,0xe1,0x2c,0x83,0x3d,0x1c,0xbb,0xca,0xec,0x91,0x75,0x78,0xc1,0x51,0x86,0x73,0x21,0x23,0x8d,0x96,0x0c,0x25,0x0c,0x01,0xbb,0x3d,0x85,0xd8,0xed,0x29,0x88,0x99,0xc0,0x2b,0x9c,0xe1,0x63,0x9f,0x0d,0x7f,0xee,0xaf,0x40,0x63,0xc0,0x32,0xea,0xc4,0xa4,0x82,0xe1,0x0d,0x57,0x11,0xfa,0x52,0x60,0x59,0x99,0x72,0x02,0x70,0x2c,0x60,0x45,0x63,0x14,0xd7,0x4d,0xf5,0xc9,0x5a,0xbc,0xe2,0x2a,0xc6,0xbb,0x9e,0x02,0x04,0x26,0x98,0xa7,0xbe,0x39,0x68,0xc6,0xab,0xae,0x92,0xa4,0xdd,0xb2,0x4b,0x24,0x96,0x58,0xb5,0x77,0x6b,0xd8,0x88,0xe7,0x9d,0xe5,0xf8,0xd8,0x6f,0x8b,0x58,0x50,0x64,0x2e,0xe0,0x4d,0x77,0x71,0xd2,0xfb,0x5a,0x4a,0x09,0xc0,0xb9,0x90,0x11,0xfb,0xbd,0xb6,0x71,0x7c,0x92,0xe1,0x74,0xd0,0x8c,0xed,0x8e,0x0a,0x1c,0xf3,0xe7,0x44,0x1d,0x0d,0xa6,0x82,0x61,0xaf,0x37,0x3f,0xa6,0x33,0x02,0x91,0x1e,0xf4,0xc8,0x3a,0xbc,0xe8,0x28,0x1d,0x76,0xb9,0x39,0x16,0x6e,0x55,0xc2,0x5b,0xae,0x22,0xbc,0xe5,0x2a,0x82,0x5b,0x89,0x7e,0x20,0xfb,0x55,0x11,0x6f,0xba,0x8a,0x20,0x27,0xf1,0x7a,0xb5,0x94,0x11,0x0,0x87,0xac,0xc1,0xbb,0xee,0x02,0x4c,0x24,0xaa,0x2e,0xcc,0x19,0xf6,0xfb,0xf2,0xf0,0xa2,0xa3,0x14,0x5d,0x61,0x5d,0xc4,0x8d,0xf0,0x8a,0xb3,0x24,0x2a,0xab,0x83,0xc8,0x2c,0x82,0x5c,0xc4,0xeb,0xae,0x62,0x1c,0x8d,0xf0,0xb2,0x93,0x4f,0xcc,0xfd,0xe7,0x1d,0xe5,0x68,0x0d,0x4f,0x6c,0xa9,0xe8,0x50,0xb4,0xd8,0x15,0x83,0xf4,0xed,0x69,0x2d,0x0,0x41,0x2e,0xe2,0x2d,0x4f,0x71,0xcc,0xae,0x99,0x76,0x28,0x5a,0xbc,0xe6,0x2a,0xc5,0x6e,0x77,0x01,0x02,0xa3,0x44,0xeb,0xf5,0xc9,0x5a,0xec,0x70,0x96,0xa2,0x27,0xc9,0x7b,0xc4,0x44,0xf2,0xe1,0x0,0x3e,0xf4,0xe5,0xe1,0x5d,0x4f,0xc1,0xa8,0x16,0x64,0x5b,0xc8,0x80,0xe7,0xa2,0x34,0xf7,0xc7,0x5c,0x42,0x84,0x8c,0xf8,0xc8,0x67,0x4b,0xca,0xef,0x4e,0xfa,0x62,0x57,0x05,0xc3,0x4e,0x77,0x21,0x3c,0x8a,0x14,0xf3,0x06,0x6d,0x0e,0x99,0xd1,0x2e,0x1b,0xb1,0xd0,0xd8,0x3b,0x24,0x36,0xbc,0x35,0x6c,0xc4,0x2e,0x77,0x21,0x64,0x32,0xf9,0x89,0xcf,0x70,0x3a,0x68,0x86,0x47,0x95,0xb0,0xd2,0x62,0xbf,0xe0,0x92,0x91,0x20,0x17,0xf1,0x81,0x27,0x17,0x67,0x42,0xf1,0xb9,0x78,0xf5,0xb0,0xdf,0x06,0x9b,0x14,0x46,0x75,0x82,0xb7,0x07,0x93,0x6e,0x01,0xec,0xf5,0xe4,0xa3,0x33,0x1c,0xbf,0x2d,0x91,0xa0,0x2a,0xe0,0x5d,0x4f,0x21,0x5e,0x71,0x95,0xc2,0xa9,0x68,0x0,0x0,0x8d,0x01,0x0b,0xde,0x76,0x15,0xd1,0xe0,0x27,0x86,0xc5,0x1e,0xd6,0xe3,0x65,0x67,0xe9,0xa0,0x83,0xee,0x78,0x20,0x07,0xdb,0xfb,0xcb,0xe3,0x36,0xf8,0x3f,0x99,0xb0,0xde,0xf5,0x14,0xa0,0x27,0xc1,0x3b,0x03,0x49,0xb5,0x0,0x9a,0x82,0x16,0x9c,0x0a,0x9a,0x13,0xd4,0xa8,0x3a,0xec,0x70,0x96,0xa1,0x5a,0xeb,0xc5,0xa9,0x20,0xdd,0x7b,0x42,0x8c,0x8e,0x53,0xd1,0xe0,0x35,0x67,0x31,0xcc,0xa2,0x9c,0xb0,0xf0,0x6f,0x85,0x33,0xec,0x74,0x17,0xe1,0x0b,0xb6,0x0e,0xe8,0x12,0x74,0xdf,0x44,0xd2,0x2c,0x80,0x1e,0x59,0x87,0xf7,0xbd,0xf9,0x09,0x2d,0x53,0xe6,0xec,0xbc,0xe0,0xd0,0xcc,0x4f,0x8c,0x8d,0x5b,0xd5,0x24,0xfc,0xec,0x87,0x57,0x95,0xf0,0x8e,0xbb,0x30,0x61,0x47,0x97,0x92,0x22,0x0,0x41,0x55,0xc0,0x3b,0xee,0x42,0xa8,0x74,0x40,0x8b,0x20,0x86,0xd0,0x15,0xd6,0xe3,0x63,0x5f,0x6e,0xe6,0x0a,0xc0,0x7b,0xbe,0x02,0xf8,0x28,0xd8,0x86,0x20,0x46,0xe4,0x90,0x3f,0x27,0xae,0xbe,0xb1,0xa4,0x09,0x40,0x63,0xd0,0x82,0x73,0x41,0x0a,0xb3,0x25,0x88,0xd1,0x61,0xd8,0xed,0x29,0x8c,0xfb,0x31,0xf8,0x84,0x0a,0x80,0x43,0xd6,0x60,0x9f,0x37,0x8f,0xda,0x96,0x20,0x22,0xc0,0xaf,0x8a,0xd8,0xed,0x2e,0x88,0xab,0x3f,0x20,0x61,0x02,0xa0,0x70,0x86,0x9d,0x9e,0x22,0x0a,0xb5,0x25,0x88,0x28,0x68,0x0f,0x1b,0xe2,0x1a,0xa5,0x9a,0x30,0x01,0x38,0xe8,0xb3,0x0d,0xee,0xc3,0x13,0x04,0x11,0x39,0xfb,0x7d,0x79,0x71,0x1b,0x3b,0x09,0x11,0x80,0xce,0xb0,0x01,0xc7,0x03,0x56,0x6a,0x49,0x82,0x18,0xa7,0xf5,0xbc,0xcb,0x5d,0x18,0x97,0x94,0xe7,0x42,0x22,0x1e,0xfe,0x7d,0x6f,0x1e,0xa5,0x64,0x24,0x88,0x09,0xd0,0xaf,0x68,0xe3,0x92,0x53,0x30,0xee,0x02,0x70,0xd8,0x6f,0x83,0x8b,0x4c,0x7f,0x82,0x98,0x30,0x1f,0xf9,0x6c,0x70,0xc7,0x78,0xfb,0x3c,0xae,0x02,0xd0,0xaf,0x68,0x71,0xc4,0x9f,0x43,0x2d,0x47,0x10,0xb1,0xb2,0xa6,0x3d,0xf9,0xe9,0x23,0x0,0x7b,0x3d,0xf9,0x74,0x55,0x13,0x41,0xc4,0x90,0x8e,0xb0,0x21,0xa6,0xf9,0x0c,0xe3,0x26,0x0,0x27,0x03,0x16,0x3a,0x67,0x4f,0x10,0x71,0x60,0x9f,0x37,0x2f,0x66,0x01,0x42,0x71,0x11,0x80,0xa0,0x2a,0xe0,0xa0,0x3f,0x97,0x5a,0x8a,0x20,0xe2,0x31,0xbe,0xb8,0x18,0xb3,0x04,0x22,0x71,0x11,0x0,0x9d,0xa0,0xc2,0x2a,0xd0,0x9d,0x6c,0x04,0x11,0x2f,0x0a,0xa5,0x60,0x6a,0x2f,0x01,0x2e,0x33,0xf7,0x26,0xf4,0x06,0x16,0x82,0xc8,0x16,0x4a,0x35,0x7e,0x4c,0xd6,0x79,0x52,0x5b,0x0,0x6c,0x62,0x08,0xb3,0xf4,0x4e,0x6a,0x2d,0x82,0x88,0x21,0x1a,0xa8,0x58,0x62,0xee,0x8d,0xd9,0xf7,0xc5,0x75,0x17,0x60,0x8e,0xd1,0x41,0xd7,0x33,0x13,0x44,0x8c,0xc7,0x94,0x49,0x90,0xd3,0x43,0x0,0x04,0x70,0x5c,0x6a,0xea,0xa3,0x8d,0x40,0x82,0x88,0x01,0xb9,0x62,0x08,0x33,0x62,0x7c,0xb1,0x68,0xdc,0x23,0x01,0x4b,0x35,0x7e,0x4c,0xd5,0xbb,0xa9,0xf5,0x08,0x62,0x02,0x88,0x8c,0xe3,0x72,0x4b,0x37,0x84,0x18,0x07,0xd5,0x27,0xe4,0x30,0xd0,0x25,0xc6,0x3e,0x58,0x68,0x57,0x80,0x20,0xc6,0xcd,0x5c,0x83,0x33,0x2e,0xcb,0xe9,0x84,0x08,0x80,0xc4,0x38,0x96,0x9a,0x7b,0x0,0x3a,0x12,0x44,0x10,0x51,0x53,0x20,0x05,0x51,0x67,0x70,0xc4,0x69,0x99,0x9e,0x20,0x8a,0x34,0x41,0xcc,0xa0,0xa5,0x0,0x41,0x44,0x6d,0xfa,0x2f,0x35,0xf7,0xc4,0xcd,0x8f,0x96,0xd0,0x94,0x60,0xf3,0x4c,0x0e,0x58,0x62,0xe8,0xc1,0x24,0x88,0x4c,0x67,0x8e,0x21,0xbe,0x3b,0x69,0x09,0x15,0x0,0x0d,0x54,0x5c,0x61,0xb1,0x53,0x80,0x10,0x41,0x44,0x40,0x89,0x26,0x80,0xd9,0x86,0xf8,0xc6,0xd2,0x24,0x3c,0x2b,0x70,0x9e,0x14,0xc2,0xbc,0x38,0xad,0x67,0x08,0x22,0x53,0xd0,0x09,0x2a,0x96,0x9b,0xbb,0xe3,0x5e,0x4e,0x52,0xee,0x05,0x98,0x65,0x70,0xa0,0x44,0x13,0xa0,0x56,0x26,0x88,0x11,0x58,0x62,0xec,0x81,0x41,0x50,0x32,0x53,0x0,0x0,0x60,0xb9,0xb9,0x1b,0xba,0xcf,0xdc,0xbe,0x4a,0x10,0xc4,0x0,0x53,0x74,0x6e,0x54,0xea,0x7c,0x09,0x29,0x2b,0x69,0x02,0x60,0x10,0x14,0x2c,0x32,0xf5,0x52,0x6b,0x13,0xc4,0x67,0xc8,0x11,0xc3,0x58,0x68,0xea,0x4b,0x58,0x79,0x49,0xbd,0x1e,0x7c,0x92,0xce,0x8b,0x99,0x06,0x17,0xb5,0x3a,0x41,0x0,0x90,0x98,0x8a,0x95,0x16,0x3b,0x34,0x8c,0x67,0x87,0x0,0x0,0xc0,0x02,0x63,0x3f,0x8a,0x34,0x41,0x6a,0x7d,0x82,0xd6,0xfd,0xe6,0x3e,0xe4,0x24,0xf8,0xf0,0x5c,0xd2,0x05,0x40,0x0,0x3f,0xef,0x0f,0x50,0xa8,0x07,0x10,0x59,0x4b,0xad,0xde,0x83,0x49,0x5a,0x4f,0x12,0xc6,0x5f,0x0a,0x60,0x12,0x64,0x2c,0xb5,0xf4,0x82,0x42,0x85,0x89,0x6c,0xc4,0x26,0x86,0xb0,0xc8,0x98,0x1c,0x7f,0x98,0x90,0x2a,0x95,0x50,0xa1,0xf1,0xa5,0xce,0xc3,0x10,0x44,0x02,0x29,0xd3,0x06,0x20,0x31,0x9e,0xdd,0x02,0x40,0x10,0x04,0x09,0x0,0x41,0x10,0x09,0x44,0xa2,0x2a,0x88,0x1e,0x93,0x4e,0x42,0x65,0x9e,0x11,0x15,0xb9,0x46,0x68,0xa5,0x4f,0x35,0x54,0x51,0x39,0x3a,0x9d,0x7e,0x9c,0xed,0xf3,0xa1,0xdf,0x1b,0xa2,0x8a,0x4a,0x10,0x16,0xbd,0x06,0x55,0xf9,0x46,0x94,0xd9,0x0c,0xd0,0x88,0x9f,0xb6,0x87,0xac,0xaa,0xe8,0x70,0x04,0xd0,0xd2,0xeb,0x85,0xcb,0x4f,0xf9,0x28,0x48,0x0,0x26,0xc0,0xd4,0x62,0x0b,0x56,0xce,0x28,0xc2,0x82,0xea,0x5c,0x4c,0x2e,0x34,0x8f,0x79,0x3c,0xb3,0xcb,0x15,0xc0,0xc1,0x96,0x7e,0xec,0x6a,0xec,0xc6,0xfe,0x33,0xfd,0x50,0x39,0x39,0x38,0x63,0x05,0x03,0x50,0x57,0x6e,0xc5,0x8a,0xe9,0x45,0x58,0x50,0x65,0x43,0x55,0xfe,0xd8,0x37,0xe5,0xb4,0xf5,0xfb,0x70,0xe0,0xac,0x03,0xef,0x9c,0xb0,0xe3,0xd0,0x39,0x07,0xb9,0x9b,0x49,0x0,0x22,0xa8,0x1c,0x81,0x61,0xe5,0x8c,0x62,0x7c,0xe5,0xd2,0x0a,0xd4,0x14,0x9a,0xa3,0xfa,0x6c,0x71,0x8e,0x1e,0xd7,0xcf,0x29,0xc5,0xf5,0x73,0x4a,0xd1,0xeb,0x09,0xe2,0xb9,0x83,0xed,0x78,0xfe,0x60,0x1b,0x3c,0x41,0x3a,0x0e,0x3d,0x5e,0xb4,0x92,0x80,0xeb,0x66,0x95,0xe0,0xcb,0x0b,0x2b,0x50,0x9e,0x6b,0x8c,0xea,0xb3,0xe5,0xb9,0x46,0x94,0xe7,0x1a,0x71,0xe3,0xbc,0x32,0x74,0x3a,0x03,0xf8,0xcb,0x87,0xad,0x78,0xe9,0x50,0x07,0x02,0x61,0x85,0x04,0x80,0x18,0xca,0xe2,0x9a,0x7c,0xfc,0xfd,0xd5,0x53,0x50,0x6a,0x35,0x4c,0xf8,0xbb,0xf2,0xcd,0x3a,0xdc,0x71,0xf9,0x64,0x7c,0x6d,0x51,0x25,0x9e,0x7c,0xf7,0x0c,0x9e,0x3b,0xd8,0x06,0x45,0xa5,0x39,0x28,0x1a,0x56,0xce,0x28,0xc2,0xdf,0xad,0x9c,0x82,0x3c,0x93,0x76,0xc2,0xdf,0x55,0x62,0xd5,0xe3,0x5b,0x57,0x4d,0xc1,0x37,0x2e,0xab,0xc2,0xa6,0x77,0x4e,0xe3,0xb5,0x23,0x9d,0x59,0x6b,0x11,0x90,0x0,0x5c,0x84,0x51,0x2b,0xe1,0xee,0x6b,0xa7,0xe2,0xaa,0x99,0xc5,0x71,0xf1,0x1d,0x7c,0xeb,0xaa,0x29,0xb8,0xba,0xae,0x18,0x8f,0xbc,0x70,0x14,0x6d,0xfd,0x7e,0xaa,0xf0,0x31,0xb0,0x19,0xb5,0xb8,0xef,0xf3,0xd3,0xb1,0x68,0x72,0x7e,0x9c,0xbe,0x7b,0x06,0xae,0xa9,0x2b,0xc6,0xbf,0xef,0x38,0x8e,0x5e,0x4f,0xf6,0x45,0xa4,0xd2,0x2e,0xc0,0x45,0x66,0xe2,0xe3,0x6b,0x16,0xc6,0x65,0xf0,0x7f,0x96,0x69,0xc5,0x16,0x3c,0xb6,0xfa,0x52,0x2c,0xa9,0xcd,0xa7,0x4a,0x1f,0xa3,0x9e,0x7e,0xb5,0xf6,0xd2,0xb8,0x0c,0xfe,0xcf,0x32,0xbf,0x2a,0x17,0xbf,0x5a,0x7b,0x29,0x66,0x95,0x5b,0x49,0x0,0xb2,0x95,0xda,0x22,0x33,0x7e,0xf6,0x8d,0xf9,0x28,0xb5,0x19,0x12,0x52,0x9e,0x41,0x2b,0xe2,0x07,0x5f,0x9a,0x8d,0x6b,0xea,0x8a,0xa9,0xf2,0x87,0x61,0x4e,0x85,0x0d,0x8f,0xac,0x9a,0x1f,0x13,0x93,0x3f,0x12,0xac,0x06,0x0d,0x7e,0x72,0xcb,0x5c,0x2c,0x9a,0x9c,0x47,0x02,0x90,0x8d,0x83,0xff,0xff,0xae,0x9a,0x0f,0x9b,0x51,0x9b,0xd0,0x72,0x45,0x81,0xe1,0x7b,0x37,0xcc,0xc4,0xf5,0xb3,0x4b,0xa9,0x11,0x2e,0x1a,0xfc,0x3f,0xbe,0x65,0x2e,0x0c,0x5a,0x31,0xa1,0xe5,0xea,0x34,0x22,0x1e,0xbc,0x79,0x4e,0xdc,0x2d,0x0e,0x12,0x80,0x14,0x22,0xc7,0xa0,0xc1,0x83,0x37,0xcd,0x86,0x49,0x37,0x71,0x77,0x88,0xc7,0xe3,0x81,0xa2,0x44,0xe7,0x55,0x66,0x0,0xee,0xbe,0x76,0x2a,0x66,0x94,0xe6,0xd0,0xc8,0x07,0x50,0x94,0xa3,0xc7,0x0f,0x6f,0x9a,0x75,0x41,0x7c,0x45,0x24,0x70,0xce,0xe1,0x76,0xbb,0xc1,0x27,0xb8,0xdd,0x2a,0x09,0x0c,0x0f,0xdc,0x58,0x87,0x8a,0x3c,0x63,0x56,0xd4,0x77,0x56,0x3b,0x01,0x19,0x80,0xef,0x5e,0x3f,0x1d,0x45,0x39,0xfa,0xa8,0x3f,0xeb,0x74,0x3a,0xf1,0xde,0x7b,0x7b,0xb1,0xe7,0xdd,0x3d,0x68,0x6e,0x6e,0x86,0xdd,0x6e,0x47,0x30,0x18,0x84,0x28,0x8a,0xc8,0xcf,0xcf,0x43,0x79,0x79,0x05,0x16,0x2d,0x5e,0x84,0xa5,0x4b,0x97,0xa2,0xba,0xba,0x6a,0xf4,0x46,0x10,0x05,0xdc,0x7f,0x63,0x1d,0xbe,0xbd,0x75,0x5f,0x56,0x6f,0x13,0x8a,0x02,0xc3,0xbf,0xfc,0xcd,0x4c,0x58,0xf4,0x9a,0x31,0xdf,0x6b,0xb7,0xdb,0xb1,0x67,0xcf,0x1e,0xec,0xd9,0xf3,0x1e,0xce,0x9d,0x3d,0x87,0xee,0xee,0x6e,0xc8,0xb2,0x0c,0x49,0x92,0x50,0x54,0x54,0x84,0xca,0xca,0x4a,0x2c,0x5d,0xba,0x04,0x4b,0x96,0x2e,0x45,0x51,0x51,0x61,0xd4,0xcb,0xb3,0xfb,0xff,0xa6,0x0e,0xf7,0xfe,0xfe,0x43,0x84,0x15,0x95,0x04,0x20,0x53,0xf9,0xdc,0xec,0x12,0x2c,0xa9,0x2d,0x88,0xea,0x33,0x76,0xbb,0x1d,0x5b,0x36,0x6f,0xc5,0xcb,0x2f,0xbf,0x0c,0x55,0x1d,0xda,0x39,0x14,0x45,0x81,0xdd,0xde,0x0d,0xbb,0xbd,0x1b,0x07,0x0e,0x1c,0xc0,0xaf,0x37,0xfe,0x1a,0x75,0xb3,0xea,0x70,0xd7,0x5d,0x77,0x62,0xde,0xbc,0x79,0x23,0x7e,0x6f,0x71,0x8e,0x1e,0x77,0xad,0xac,0xc5,0x2f,0x5e,0x3e,0x91,0xb5,0xed,0xf1,0xd5,0x45,0x95,0xa8,0x2b,0x1b,0xdd,0x11,0x77,0xfa,0x74,0x33,0x36,0x6d,0xda,0x84,0x3d,0xef,0xee,0x19,0xf6,0xdf,0x65,0x59,0x46,0x7b,0x7b,0x3b,0xda,0xdb,0xdb,0xb1,0x77,0xef,0x5e,0xe0,0x97,0xff,0x81,0xe5,0xcb,0x97,0x63,0xdd,0xfa,0x7a,0x4c,0x9e,0x3c,0x39,0xaa,0x65,0xe1,0x6d,0x4b,0xab,0xb1,0x65,0x57,0x33,0x2d,0x01,0x32,0x11,0xa3,0x56,0x42,0xfd,0x15,0x35,0x51,0x99,0x98,0xcf,0x3c,0xf3,0x07,0xac,0x59,0xbd,0x16,0x3b,0x76,0xec,0x18,0x76,0xf0,0x8f,0xc4,0xd1,0x23,0x47,0xf1,0x9d,0x7b,0xbf,0x8b,0x1f,0xfe,0xe0,0x87,0xf0,0x7a,0xbd,0x23,0xbe,0xef,0xba,0x59,0x25,0x98,0x56,0x62,0xc9,0xca,0xf6,0xc8,0x37,0xeb,0xf0,0x8d,0xcb,0xaa,0x47,0xfc,0x77,0x59,0x96,0xf1,0x1f,0xbf,0x7c,0x14,0x77,0xdd,0x79,0xd7,0x88,0x83,0x7f,0x24,0x76,0xef,0xde,0x8d,0x3b,0xd7,0xdf,0x85,0xff,0xfc,0xcf,0xc7,0x20,0xcb,0x91,0x5b,0x58,0xb7,0x2c,0xac,0x8c,0x49,0x1c,0x08,0x09,0x40,0x0a,0x72,0xd3,0x25,0xe5,0xc8,0x8d,0xd0,0xe9,0x17,0x08,0x04,0xf0,0xd0,0x86,0x87,0xf1,0x9b,0x5f,0xff,0x06,0xe1,0xf0,0xf8,0x63,0xca,0x77,0xed,0xda,0x8d,0x6f,0xfe,0xdd,0xb7,0xd0,0xd2,0xd2,0x32,0xfc,0x92,0x84,0x31,0xdc,0xbe,0x7c,0x72,0x56,0xb6,0xc7,0xd7,0x17,0x57,0xc1,0xa0,0x19,0xde,0xe9,0xd7,0xd7,0xd7,0x87,0x7b,0xff,0xf1,0x3b,0xd8,0xbe,0x7d,0xfb,0xb8,0xd7,0xf8,0x9c,0x73,0x3c,0xfb,0xe7,0x67,0x71,0xef,0xbd,0xdf,0x41,0x5f,0x5f,0x64,0x39,0xf7,0xb4,0x92,0x80,0xdb,0x96,0x56,0x93,0x0,0x64,0xdc,0xba,0x47,0x14,0xf0,0xa5,0xf9,0xe5,0x11,0x77,0x9c,0x9f,0xfc,0xf8,0x27,0x78,0xe7,0x9d,0x77,0x62,0x52,0x76,0x7b,0x7b,0x3b,0xbe,0x77,0xdf,0xff,0x46,0x6f,0xef,0xf0,0x09,0x20,0x2e,0x99,0x94,0x87,0x49,0x05,0xa6,0x84,0xd4,0x03,0x63,0xc0,0xd5,0x33,0x8b,0xf1,0xe3,0x5b,0xe6,0xe2,0x7f,0xbe,0xbd,0x1c,0x2f,0xdd,0xb7,0x12,0xcf,0xde,0x7d,0x05,0xfe,0xfd,0xeb,0xf3,0xf1,0xc5,0xf9,0xe5,0x17,0x1c,0xac,0x89,0x27,0x66,0xbd,0x84,0xeb,0x66,0x97,0x0c,0xfb,0x6f,0xc1,0x60,0x10,0xf7,0xff,0xcb,0xfd,0x38,0x7a,0xf4,0x68,0x4c,0xca,0x3a,0x7a,0xe4,0x28,0x1e,0xb8,0xff,0xfb,0x08,0x06,0x23,0x0b,0xfa,0xb9,0x6a,0x46,0x11,0xf2,0xcd,0x3a,0x12,0x80,0x4c,0x62,0x49,0x4d,0x3e,0x72,0x23,0xdc,0x5f,0xfe,0xed,0x6f,0x37,0x61,0xd7,0xae,0xdd,0x31,0x2d,0xbf,0xb7,0xb7,0x17,0x0f,0xdc,0xff,0xc0,0xb0,0x9d,0x90,0x01,0xb8,0x61,0x4e,0xfc,0xb7,0x05,0x0b,0x2c,0x3a,0xfc,0xec,0x1b,0x0b,0xf0,0x4f,0x5f,0x98,0x89,0x85,0x93,0xf2,0x06,0x1d,0x6f,0x06,0xad,0x88,0x39,0x15,0x36,0x7c,0xfb,0x9a,0xa9,0xf8,0xd5,0xda,0x4b,0x31,0x39,0xca,0x33,0x10,0xe3,0xe1,0xaa,0x19,0xc5,0xd0,0x0f,0x33,0xfb,0x73,0x95,0xe3,0x47,0xff,0xfa,0x63,0x34,0x36,0x36,0xc5,0xb4,0xbc,0x93,0x27,0x4f,0xe2,0x27,0x3f,0xfe,0x69,0x44,0xd6,0x84,0x24,0x0a,0xb8,0x76,0x56,0x31,0x09,0x40,0x26,0x71,0xe5,0x8c,0xa2,0x88,0x67,0x8b,0x3f,0x3c,0xf3,0x87,0xb8,0x3c,0x43,0x63,0x63,0x13,0x9e,0x7e,0xfa,0xf7,0xc3,0xfe,0xdb,0x15,0xd3,0x8b,0x10,0xcf,0xdb,0xd3,0xcc,0x3a,0x09,0x3f,0xfd,0xea,0xbc,0x31,0x1d,0x6e,0x95,0x79,0x46,0xfc,0xdb,0xd7,0xe6,0xa1,0xc4,0xaa,0x8f,0x6f,0x7b,0x4c,0x1f,0xbe,0x3d,0x5e,0x79,0xf5,0x55,0xec,0xde,0xbd,0x3b,0x2e,0x65,0xee,0xdc,0xb9,0x13,0x6f,0xbc,0xf1,0x46,0x44,0xef,0x5d,0x31,0xad,0x88,0x04,0x20,0x53,0x60,0x0c,0x98,0x5f,0x65,0x8b,0xc8,0xf4,0x7f,0xec,0xb1,0xc7,0x27,0xbc,0xaf,0x3c,0x1a,0xdb,0xfe,0x7b,0x1b,0xec,0x76,0xfb,0x90,0xd7,0xf3,0x4c,0x5a,0x54,0xc7,0x71,0x19,0xb0,0x7a,0xd9,0x24,0x54,0x46,0xb8,0xcf,0x6d,0x35,0x68,0xf0,0xed,0x6b,0xa6,0xc6,0xed,0x59,0x0c,0x5a,0x11,0x33,0xcb,0x72,0x86,0xf5,0xbb,0xfc,0xf6,0x37,0xbf,0x8d,0x6b,0x5f,0xd8,0xf8,0xc4,0xaf,0x23,0x5a,0x0a,0xd4,0x14,0x99,0x23,0xf6,0x17,0x91,0x0,0xa4,0x38,0x55,0x79,0xa6,0x88,0xf6,0x99,0x3f,0xf8,0x60,0x1f,0x8e,0x1f,0x3f,0x1e,0xd7,0x67,0x09,0x85,0x42,0x23,0x5a,0x18,0xb3,0xe3,0x14,0x97,0xae,0x95,0x84,0xa8,0x23,0x0f,0x2f,0x9d,0x9c,0x1f,0x37,0x6f,0xf8,0xf4,0x92,0x1c,0x88,0xc3,0xdc,0x16,0xfb,0xc2,0x0b,0x2f,0x8e,0xe8,0x27,0x89,0x15,0x3d,0x3d,0x3d,0xd8,0xb1,0xe3,0xa5,0xb1,0x27,0x0d,0x60,0x58,0x91,0x22,0x01,0x48,0x43,0x26,0x15,0x46,0x36,0xb3,0xbe,0xf6,0xea,0xab,0x09,0x79,0x9e,0xd7,0x5f,0x7f,0x63,0xd8,0xe8,0xc1,0x78,0x39,0x02,0x2b,0xf3,0x8c,0x51,0x87,0xd8,0x32,0x0,0xd3,0x4a,0xe3,0xb3,0x3d,0x39,0x79,0x84,0xf6,0x78,0xf5,0x95,0xc4,0xd4,0x7f,0xa4,0xe5,0x24,0xca,0x31,0x4b,0x02,0x10,0x67,0xca,0x22,0x38,0xec,0x23,0xcb,0x32,0xf6,0xec,0x79,0x2f,0x21,0xcf,0xe3,0x76,0xbb,0xf1,0xf1,0xc7,0x1f,0x0f,0x7d,0xce,0xdc,0xf8,0x84,0xa2,0x9a,0xc7,0x19,0xf2,0x1c,0x89,0xd5,0x14,0xab,0xf6,0xb0,0xdb,0xed,0x68,0x6c,0x6c,0x4c,0x48,0xfd,0x1f,0x3f,0x7e,0x1c,0xdd,0xdd,0x63,0xdf,0xc2,0x5b,0x96,0x6b,0x20,0x01,0xc8,0x04,0x22,0x19,0x0,0x67,0xce,0x9c,0x19,0x35,0x60,0x27,0xd6,0x1c,0x3e,0x74,0x78,0x98,0x01,0x17,0x9f,0x20,0x4d,0xc6,0xc6,0xe7,0x5e,0x8c,0x97,0x53,0x72,0xb8,0x33,0x18,0x87,0x0f,0x1f,0x89,0xab,0xef,0xe5,0xb3,0x70,0xce,0x71,0xf4,0xe8,0xb1,0xa4,0x09,0x20,0x09,0x40,0x82,0x89,0xc4,0xfc,0xed,0xe9,0xe9,0x49,0xe8,0x33,0x0d,0x57,0xde,0x48,0x41,0x31,0x19,0xd7,0x1e,0xc3,0xfc,0xce,0x78,0xaf,0xfd,0x87,0xd4,0x7f,0x04,0x16,0x40,0xa6,0xb6,0x47,0xd6,0x09,0x40,0x58,0x19,0x7b,0x66,0xe9,0xed,0xed,0x4b,0x6c,0x07,0x1c,0xa6,0xc3,0xcb,0x59,0x92,0x32,0x6c,0xb8,0xdf,0x99,0x68,0x01,0x88,0xa4,0xbc,0x4c,0x3d,0x14,0x94,0x75,0x02,0x10,0x51,0x12,0xc8,0x44,0x67,0xf0,0x1d,0xa6,0x3c,0x5f,0x48,0xce,0xde,0xf6,0x48,0x70,0xfd,0x47,0x52,0x9a,0x3f,0x43,0x93,0x87,0x66,0x9d,0x0,0xf4,0xb8,0xc7,0xde,0xf7,0x2d,0x28,0x2c,0x48,0xe8,0x33,0x15,0x14,0x0e,0x3d,0xae,0xda,0xed,0xce,0x8e,0xfc,0x74,0xc3,0xfd,0xce,0xfc,0x82,0x04,0xd7,0x7f,0x04,0xe5,0x75,0xbb,0x82,0x24,0x0,0x99,0xc0,0xb9,0x3e,0xdf,0x98,0xef,0xc9,0xcf,0x4f,0x6c,0x46,0x98,0x82,0x61,0xca,0x8b,0xe4,0x39,0x33,0xb5,0x3d,0x12,0x5e,0xff,0x11,0x08,0x40,0x6b,0xbf,0x8f,0x04,0x20,0x13,0x38,0x65,0xf7,0x8c,0xe9,0x61,0xae,0xa9,0xa9,0x81,0xd5,0x9a,0xb8,0x04,0x91,0xf3,0xe6,0x0f,0xcd,0x13,0xd0,0xd4,0xe5,0xc9,0x8a,0xf6,0x68,0xea,0x72,0x0f,0xad,0x8f,0x79,0x73,0xc7,0xbd,0x5b,0x11,0x2d,0x8c,0x31,0xcc,0x9b,0x37,0x77,0xcc,0xf7,0x35,0x0e,0xf3,0x9c,0x24,0x0,0x69,0x88,0x3b,0x10,0xc6,0x29,0xfb,0xe8,0x83,0x4b,0x10,0x04,0x2c,0xbe,0x6c,0x71,0x42,0x9e,0xc7,0x6a,0xb5,0x62,0xf6,0xec,0xd9,0x17,0xbc,0xa6,0x72,0x8e,0x43,0xad,0x8e,0xac,0xb1,0x0,0x2e,0x4e,0xc7,0x9d,0x9f,0x9f,0x8f,0x69,0xd3,0xa7,0x25,0xa4,0xfc,0x99,0x75,0x33,0x61,0xb3,0x8d,0x1e,0x1a,0xee,0x09,0xc8,0x19,0x2b,0xc8,0x59,0x79,0x18,0xe8,0x83,0xe6,0xb1,0xbd,0xfc,0x2b,0x56,0x5c,0x91,0x90,0x67,0xb9,0xfc,0xf2,0xe5,0x10,0x84,0x0b,0x9b,0xe1,0x48,0x9b,0x13,0xde,0x2c,0x4a,0x0d,0x36,0x5c,0x7b,0xac,0x58,0xb1,0x22,0x21,0x65,0x47,0x52,0xce,0xbe,0x33,0x7d,0x19,0x7b,0xb5,0x5b,0x56,0x0a,0xc0,0x4b,0x87,0x3a,0xc6,0xf4,0xfc,0x2e,0x5f,0xbe,0x7c,0xc8,0xcc,0x1c,0x6b,0x74,0x3a,0x1d,0x6e,0xbf,0xe3,0xf6,0x21,0xaf,0xbf,0x72,0xb8,0x33,0xab,0xda,0xe3,0xe5,0xc3,0x1d,0x43,0x5e,0xfb,0xca,0x57,0xbe,0x1c,0x75,0x2e,0xbf,0x68,0x29,0x2a,0x2a,0xc2,0xcd,0x37,0xdf,0x34,0xe6,0xfb,0x5e,0x3d,0x92,0xb9,0xed,0x91,0x95,0x02,0xd0,0xe5,0x0a,0xe0,0xc3,0x33,0x63,0x5b,0x01,0xeb,0xd6,0xd5,0xc7,0xf5,0x39,0x6e,0xba,0xe9,0x4b,0x43,0x1c,0x50,0x2e,0x7f,0x18,0x3b,0x4f,0x76,0x67,0x55,0x7b,0x1c,0x6f,0x77,0x0d,0x59,0x96,0xe9,0x74,0x3a,0xdc,0x76,0xdb,0x6d,0x71,0x2d,0x77,0xed,0xed,0x6b,0xa1,0xd5,0x8e,0x7e,0xca,0xaf,0xad,0xdf,0x8f,0x03,0x2d,0xfd,0x24,0x0,0x99,0xc6,0x1f,0xf6,0x9e,0x1d,0xf3,0x3d,0xf3,0x17,0xcc,0xc7,0x9a,0xb5,0x6b,0xe2,0x52,0x7e,0xdd,0xac,0x3a,0xac,0x5b,0xbf,0x6e,0xc8,0xeb,0xcf,0xee,0x6f,0xcd,0xba,0x0b,0x2b,0x39,0x80,0x6d,0xef,0x0f,0x6d,0x8f,0x2f,0x7e,0xe9,0x8b,0xb8,0xfa,0x9a,0xab,0xe3,0x52,0xe6,0xb5,0xd7,0x5e,0x83,0x1b,0x6e,0xf8,0xfc,0x98,0xef,0xdb,0xf6,0xfe,0xd9,0x8c,0xbe,0xd9,0x39,0x6b,0x05,0xe0,0x50,0xab,0x23,0xa2,0x99,0xf6,0x8e,0xdb,0x6f,0xc7,0xb2,0x65,0xcb,0x62,0x5a,0x76,0x7e,0x7e,0x3e,0x36,0x6c,0x78,0x70,0xc8,0xec,0xd3,0xe1,0xf4,0xe3,0x4f,0xfb,0xcf,0x65,0x65,0x7b,0xbc,0x73,0xc2,0x8e,0x8f,0xce,0x5d,0xe8,0xf8,0x64,0x8c,0xe1,0xbe,0xfb,0xbe,0x8b,0xda,0xda,0xda,0x98,0x96,0x35,0x75,0xea,0x54,0xdc,0xf7,0xbd,0xfb,0xc6,0xdc,0x69,0x38,0xde,0xe1,0xc2,0x2b,0x47,0x3a,0x32,0xba,0xde,0xb3,0xfa,0x62,0x90,0xdf,0xbc,0x7d,0x6a,0xcc,0x88,0x3b,0x26,0x30,0x3c,0xf4,0xf0,0x86,0x88,0xd6,0x8a,0x91,0x30,0x6d,0xda,0x34,0xfc,0xd7,0x13,0xbf,0x1a,0x76,0xef,0x79,0xe3,0x9b,0x4d,0x08,0xc9,0x6a,0x56,0xb6,0x05,0x07,0xf0,0xc4,0x9b,0x4d,0x90,0x2f,0x0a,0xb9,0x35,0x18,0x0c,0xf8,0x8f,0x47,0x7f,0x89,0xa5,0x4b,0x97,0xc4,0xa4,0x9c,0xa5,0xcb,0x96,0xe2,0x17,0xbf,0xfc,0x39,0x74,0xba,0xd1,0xf3,0xfc,0xa9,0x9c,0xe3,0x89,0x37,0x9b,0xc0,0x33,0x3c,0x22,0x3b,0xab,0x05,0xc0,0xee,0x0a,0xe0,0xe7,0x2f,0x8d,0x9d,0x87,0x5f,0x14,0x45,0xdc,0x7d,0xcf,0xdd,0xb8,0xeb,0xae,0x3b,0x21,0x49,0xe3,0x3f,0xa5,0xb7,0x7c,0xf9,0x72,0xfc,0xec,0xe7,0xff,0x6f,0xd8,0xc1,0xbf,0xfd,0xc3,0x56,0xbc,0x77,0xaa,0x37,0x9b,0x9b,0x03,0xcd,0xdd,0x1e,0xfc,0xfa,0xed,0x53,0x43,0x5e,0x37,0x1a,0x8d,0x78,0xe8,0xe1,0x87,0x70,0xd3,0x4d,0x37,0x8d,0xff,0x34,0x23,0x63,0xb8,0xf9,0xcb,0x37,0xe3,0xa1,0x87,0x36,0xc0,0x68,0x1c,0xfb,0xa8,0xf5,0x96,0x5d,0xcd,0x38,0xde,0xe1,0xca,0xf8,0x3a,0xcf,0xfa,0xab,0xc1,0x76,0x35,0x76,0x63,0xfb,0x87,0xad,0x11,0x75,0xa0,0x5b,0x6f,0xbb,0x15,0xbf,0x7f,0xe6,0x69,0xdc,0x78,0xe3,0x8d,0x43,0xb6,0xee,0x46,0x63,0xd6,0xac,0x59,0x78,0xec,0xf1,0xff,0xc4,0xbf,0xfe,0xe8,0x61,0x98,0x4c,0x43,0x13,0x4b,0x1c,0x6b,0x77,0x61,0xd3,0xce,0xd3,0x20,0x80,0xe7,0x0e,0xb4,0xe1,0xed,0x13,0x43,0xd3,0xa4,0x49,0x92,0x84,0x7f,0xbc,0xf7,0x1e,0x34,0x6c,0xfe,0x1d,0xae,0x5c,0x79,0x65,0x54,0xdf,0x79,0xe5,0xca,0x2b,0xb1,0x79,0x4b,0x03,0xee,0xb9,0xe7,0xee,0x88,0x04,0x7c,0xef,0xe9,0x5e,0xfc,0xcf,0x07,0xd9,0xb1,0x14,0x93,0xa8,0xcb,0x01,0x4f,0xbc,0xd5,0x04,0x93,0x5e,0xc2,0xb5,0x75,0x25,0x63,0xbe,0xb7,0xa0,0xa0,0x0,0xdf,0xbd,0xef,0x3b,0xb8,0xf5,0xb6,0x6f,0xe0,0xdd,0xdd,0xef,0xe2,0xdd,0x77,0xf7,0xe0,0xec,0xd9,0xb3,0x70,0x38,0x1c,0x83,0x99,0x7d,0x72,0x72,0x72,0x50,0x5c,0x5c,0x84,0x4b,0x17,0x2d,0xc2,0xb2,0x65,0x4b,0x51,0x37,0xb3,0x0e,0x4c,0x18,0x7e,0xe6,0x3a,0xdd,0xed,0xc1,0x0f,0x9e,0xfd,0x38,0x6b,0x4d,0xff,0xe1,0x96,0x02,0xff,0xbe,0xe3,0x38,0x8c,0x5a,0x71,0xd8,0x4b,0x3a,0xab,0xaa,0xaa,0xf0,0xe0,0x83,0x3f,0xc4,0xa9,0xd5,0xa7,0xb0,0x67,0xcf,0x7b,0x78,0x6f,0xcf,0x7b,0xe8,0xe8,0xe8,0x80,0xc3,0xe1,0x0,0xe7,0x1c,0x8c,0x31,0xd8,0x6c,0x36,0x94,0x96,0x95,0x62,0xe9,0xd2,0xa5,0x58,0xba,0x74,0x09,0x6a,0x6a,0x22,0xbf,0x0,0xe6,0xe3,0x73,0x0e,0xfc,0xf8,0xb9,0x23,0x19,0xed,0xf8,0x23,0x01,0xb8,0xb8,0xd3,0x71,0xe0,0x67,0x3b,0x8e,0xc3,0xe9,0x0b,0xe3,0x96,0x4b,0x2b,0x23,0xfa,0x4c,0x69,0x69,0x29,0x6e,0xf9,0xea,0x2d,0xb8,0xe5,0xab,0xb7,0x9c,0xff,0x0e,0x0e,0x8f,0xc7,0x03,0x83,0xc1,0x10,0xf1,0x32,0xe1,0x40,0x4b,0x3f,0x1e,0xde,0x7e,0x38,0x63,0x4f,0x9a,0x8d,0x17,0x59,0x51,0xf1,0xe0,0xb3,0x87,0x71,0xef,0x75,0xd3,0x47,0xbc,0x2f,0xa0,0xb6,0xb6,0x16,0xb5,0xb5,0xb5,0x58,0xbd,0xfa,0x6f,0x01,0x0c,0x5c,0xc9,0xe6,0xf3,0xf9,0x60,0x32,0x99,0xa2,0xb2,0xce,0x3e,0xcb,0xce,0x93,0xdd,0x78,0xe4,0xc5,0x63,0x43,0xfc,0x10,0x24,0x0,0x59,0x32,0xf3,0xfc,0xf6,0xed,0x53,0xe8,0xf3,0x86,0x50,0x7f,0xf9,0x64,0x48,0x51,0x5e,0x8a,0xc1,0x18,0x83,0xc5,0x12,0x79,0xde,0xbc,0x57,0x8f,0x74,0xe2,0xf1,0xd7,0x1b,0x13,0xbe,0xe5,0x37,0x91,0x9b,0x75,0x12,0x89,0xca,0x39,0x7e,0xf9,0xca,0x09,0xf4,0x79,0x83,0xf8,0xfa,0xe2,0xaa,0x31,0xd7,0xfe,0xa2,0x28,0x46,0x55,0xff,0x17,0xb7,0xfd,0xb3,0xfb,0x5b,0xf1,0xbb,0x77,0x4e,0x65,0x4d,0x1e,0x06,0x12,0x80,0x11,0x3a,0xc2,0x9f,0xf6,0x9d,0xc3,0xa1,0x73,0x0e,0xfc,0xe3,0x75,0xd3,0x51,0x5b,0x14,0xfb,0x4b,0x31,0xfa,0xbd,0x21,0x3c,0xf1,0x56,0x13,0xde,0x3e,0x6e,0x4f,0xca,0x6f,0x74,0xfa,0xc7,0x77,0xb5,0x99,0xc3,0x17,0x4e,0xf8,0xb3,0xaa,0x9c,0x63,0xf3,0xae,0x66,0x1c,0x68,0xe9,0xc7,0x3d,0x9f,0x9b,0x8e,0xf2,0x38,0xe4,0xe5,0xeb,0x72,0x05,0xf0,0xd8,0x6b,0x27,0x23,0x0a,0x0f,0x27,0x01,0xc8,0x12,0x4e,0x76,0xb9,0x71,0xcf,0xd3,0xfb,0xf1,0x85,0xb9,0x65,0xf8,0xda,0xa2,0xca,0x71,0x5d,0x1f,0x7e,0x31,0xfe,0x90,0x82,0x17,0x3e,0x6a,0xc7,0x1f,0xf6,0xb6,0x24,0xf5,0x0a,0xf0,0xb3,0xbd,0x3e,0x38,0xfd,0x61,0x58,0x0d,0x9a,0xa8,0x06,0xe2,0x91,0x36,0x67,0xd2,0x9e,0xf9,0xa3,0x73,0x0e,0x7c,0x6b,0xcb,0x07,0xf8,0xf2,0xc2,0x0a,0x7c,0x65,0x61,0x05,0x6c,0x31,0xc8,0xd1,0xef,0xf2,0x87,0xb1,0xfd,0x40,0x1b,0xfe,0xb8,0xef,0x1c,0x82,0x59,0xbc,0x04,0x23,0x01,0x18,0x01,0x45,0xe5,0x78,0xee,0x60,0x1b,0x76,0x7c,0xdc,0x8e,0xcb,0xa7,0x15,0xe2,0xfa,0xd9,0xa5,0x98,0x5f,0x65,0x8b,0x7a,0x1b,0xaa,0xb9,0xdb,0x83,0x57,0x8f,0x74,0xe2,0x95,0xc3,0x9d,0x49,0x1d,0xf8,0x9f,0x1d,0xcc,0x2f,0x7e,0xd4,0x8e,0x5b,0x97,0x44,0x7e,0xe9,0xe5,0xce,0x93,0xdd,0xe8,0xf7,0x85,0x92,0xfa,0xdc,0x61,0x45,0xc5,0xb6,0xf7,0xcf,0xe2,0x2f,0x1f,0xb6,0xe2,0xaa,0x99,0xc5,0xb8,0x6e,0x56,0x09,0xea,0xca,0xad,0x51,0x27,0x2b,0x3d,0xde,0xe1,0xc2,0xab,0x47,0x3a,0xf1,0xfa,0xd1,0xae,0xac,0x8b,0xb8,0x24,0x01,0x18,0x07,0xb2,0xca,0xf1,0xd6,0x71,0x3b,0xde,0x3a,0x6e,0x47,0xae,0x51,0x8b,0x79,0x55,0x36,0xcc,0xae,0xb0,0xa1,0x2a,0xcf,0x88,0x8a,0x3c,0x23,0xcc,0x3a,0x09,0x5a,0x49,0x80,0xac,0x72,0x78,0x83,0x32,0x3a,0x9d,0x7e,0x9c,0xed,0xf5,0xe1,0x78,0x87,0x0b,0x07,0xcf,0xf6,0xa3,0xad,0xdf,0x9f,0x72,0xbf,0xe9,0x99,0xbd,0x2d,0x98,0x5b,0x69,0xc3,0xac,0x08,0x2e,0x1f,0x69,0x77,0xf8,0xf1,0xab,0xd7,0x1b,0x53,0xe6,0xd9,0x43,0xb2,0x8a,0x97,0x0f,0x75,0xe0,0xe5,0x43,0x1d,0x28,0xb0,0xe8,0x30,0xbf,0x32,0x17,0xb3,0xca,0xad,0xa8,0xca,0x37,0xa2,0x2c,0xd7,0x0,0x93,0x76,0xa0,0x3d,0xc2,0x8a,0x0a,0x6f,0x50,0x46,0x87,0x23,0x80,0xb3,0xbd,0x5e,0x1c,0x6d,0x77,0xe1,0xc0,0xd9,0x7e,0xd8,0x5d,0x01,0xea,0xd4,0x24,0x0,0xe3,0x5c,0xbf,0xfb,0x42,0x83,0x62,0x90,0xce,0x84,0x64,0x15,0x3f,0x7c,0xf6,0x10,0xfe,0xf7,0x0d,0x33,0xb0,0xa4,0xb6,0x60,0xd4,0xd9,0xf2,0x47,0xcf,0x1d,0x19,0xb7,0xdf,0x20,0xde,0xf4,0xb8,0x83,0x78,0xed,0x68,0x27,0x5e,0x3b,0xda,0x49,0x9d,0x93,0x04,0x80,0x88,0x06,0x6f,0x50,0xc6,0x86,0xbf,0x1c,0xc6,0x9c,0x0a,0x1b,0xae,0x9d,0x55,0x8c,0xb9,0x15,0x36,0x58,0xf4,0x1a,0xf8,0x42,0x32,0x8e,0x77,0xb8,0xf0,0xc6,0x31,0x3b,0xf6,0x9e,0xee,0x01,0xe7,0x54,0x57,0x24,0x0,0x44,0xc6,0x72,0xa8,0xd5,0x91,0x35,0xd9,0x87,0x88,0xa1,0x08,0x54,0x05,0x04,0x41,0x02,0x90,0x12,0x24,0x2a,0x11,0x24,0x41,0x10,0x29,0x26,0x0,0x4c,0x10,0x20,0x8a,0x64,0x90,0x10,0xd9,0x87,0x28,0x26,0xef,0xda,0xb1,0x94,0xf1,0x01,0x4c,0x9b,0x36,0x0d,0x4f,0xcd,0x5b,0x88,0x3d,0x4d,0x3d,0x78,0xe7,0x64,0x37,0x3e,0x3a,0xdb,0x9f,0x75,0x61,0x99,0x44,0xf6,0x61,0xd0,0x8a,0x98,0x39,0xa9,0x04,0xe8,0xe8,0xce,0x5e,0x01,0xd0,0xe9,0x74,0x98,0x77,0xc9,0x25,0xd0,0x6a,0x35,0xb8,0x7e,0x4e,0x29,0xae,0x9f,0x53,0x8a,0x60,0x58,0xc1,0x81,0xb3,0x0e,0xec,0x3c,0x69,0xc7,0xee,0xc6,0x1e,0x0a,0xda,0x20,0x32,0x06,0x9b,0x51,0x8b,0x2b,0x67,0x14,0x61,0xc5,0xb4,0x42,0xcc,0x2c,0xcb,0x01,0x38,0xc7,0x73,0xcf,0x9e,0x81,0xdb,0xed,0xce,0x4c,0x01,0x50,0xc1,0x20,0x8c,0x92,0x87,0x77,0xee,0xfc,0xf9,0x43,0xd2,0x63,0xe9,0x34,0x22,0x96,0xd4,0xe6,0x63,0x49,0x6d,0x3e,0xbe,0x75,0x55,0x18,0x2f,0x1f,0xea,0xc4,0xe6,0xdd,0xcd,0x59,0x75,0x52,0x8b,0xc8,0xbc,0x81,0x7f,0xd7,0x95,0xb5,0xb8,0x62,0x5a,0x21,0xb4,0xd2,0x67,0x96,0xbb,0x8c,0x61,0xee,0x82,0x05,0xd8,0xfd,0xce,0x3b,0x99,0xe9,0x03,0x68,0x09,0x1a,0xf1,0x57,0x47,0x39,0x0e,0xfa,0x6c,0x70,0x28,0x17,0x0e,0x74,0x5b,0x6e,0x2e,0xa6,0xcd,0x98,0x31,0xea,0xe7,0x2d,0x7a,0x0d,0xbe,0xba,0xa8,0x12,0x77,0xad,0xa8,0xa1,0x5e,0x44,0xa4,0x2d,0xff,0xe7,0x8b,0xb3,0x70,0x4d,0x5d,0xf1,0x85,0x83,0xff,0x3c,0x93,0x6b,0x6a,0x90,0x37,0xca,0x95,0x68,0xbd,0x8a,0x0e,0x3c,0x5d,0x05,0xc0,0xa1,0x68,0xe1,0x52,0x34,0x38,0xec,0xb7,0xe1,0x79,0x47,0x19,0x9e,0x75,0x54,0xe2,0x03,0x5f,0x3e,0xba,0x65,0x3d,0x16,0x2e,0x5e,0x1c,0xb1,0xf7,0xff,0x73,0xb3,0x4b,0x40,0xfb,0x04,0x44,0x3a,0x52,0x66,0x33,0x60,0x76,0xc5,0xe8,0xa1,0xd7,0x0b,0x16,0x2e,0xbc,0xc0,0x6a,0x6e,0x0d,0x19,0xb1,0xdb,0x53,0x80,0xff,0xe9,0xab,0xc4,0x0e,0x47,0x29,0x7c,0x6a,0xec,0x0d,0x76,0x29,0x51,0x02,0xf0,0x59,0xbc,0x8a,0x88,0x13,0x7e,0x0b,0x4e,0xf8,0x2d,0x38,0xf0,0x7c,0x0b,0x96,0x4e,0xf1,0x62,0xc5,0xb4,0xc2,0x31,0x63,0xd3,0x8d,0x5a,0x09,0x1a,0x49,0xa0,0xec,0x39,0x44,0xda,0x61,0x35,0x8e,0x7d,0xfa,0xb2,0xa8,0xa4,0x14,0x5e,0x73,0x05,0x0e,0x76,0x06,0xd0,0x1e,0x32,0x20,0xc8,0x2f,0xdc,0x1d,0x70,0x2a,0x1a,0x98,0x04,0x39,0x0d,0x05,0x40,0x1e,0xf9,0xc7,0xdb,0x5d,0x01,0x6c,0xff,0xb0,0x15,0xdb,0x3f,0x6c,0x45,0x4d,0xa1,0x19,0x2b,0xa6,0x17,0xe2,0x8a,0x69,0x45,0x71,0x39,0xfb,0xbd,0x70,0x52,0x1e,0xee,0x5c,0x51,0x83,0x7c,0xb3,0x0e,0xed,0x0e,0x3f,0x4e,0xd9,0x3d,0x83,0x7f,0x9a,0x7b,0x3c,0x24,0x2c,0x04,0xcc,0x3a,0x09,0x35,0x45,0x66,0xd4,0x16,0x99,0x51,0x53,0x38,0xf0,0x77,0x91,0x45,0x8f,0x26,0xbb,0x1b,0xff,0xf5,0x46,0x13,0x5a,0x7a,0xbd,0x31,0x2f,0xf3,0x64,0x97,0x1b,0x3b,0x4f,0x74,0x63,0xe7,0x49,0x3b,0x3a,0x9d,0x12,0x80,0xe1,0xf3,0x50,0x38,0x15,0x0d,0xca,0x34,0xfe,0xf4,0x12,0x0,0x0e,0xc0,0xab,0x46,0xb6,0xcf,0x79,0xba,0xdb,0x83,0xd3,0xdd,0x1e,0x6c,0xde,0xd5,0x8c,0x47,0xff,0x76,0x21,0xa6,0x95,0x58,0x62,0xf6,0x1c,0xd5,0xf9,0x26,0x3c,0x78,0xd3,0xec,0xc1,0xf5,0x57,0x8e,0x41,0x83,0x19,0xa5,0x39,0x9f,0x9a,0x5c,0x9c,0xa3,0xb5,0xcf,0x37,0x20,0x08,0xdd,0x1e,0x9c,0xb6,0x7b,0xd0,0x64,0xf7,0xc0,0x95,0xa2,0x07,0x61,0x88,0x89,0x53,0x94,0xa3,0x1f,0x1c,0xe4,0xb5,0x85,0x66,0xd4,0x14,0x99,0x51,0x62,0x1d,0x3e,0xf7,0xc3,0xfc,0xaa,0x5c,0xfc,0xe8,0x96,0xb9,0xf8,0xe6,0xe6,0x0f,0xc6,0x4c,0x25,0x1f,0x0d,0x2f,0x1d,0xea,0xc0,0x2f,0x5f,0x39,0x11,0xd1,0x7b,0xdd,0x8a,0x26,0xe6,0x75,0x10,0x77,0x01,0x08,0x73,0x01,0x18,0xc7,0xca,0x5d,0x89,0x71,0x0c,0xc0,0xb2,0xa9,0x05,0xc3,0x3a,0x5f,0x06,0x9d,0x21,0x8c,0xa1,0x2a,0xdf,0x84,0xaa,0x7c,0x13,0xae,0x9a,0x59,0x3c,0xf8,0x7a,0x8f,0x3b,0x38,0x28,0x08,0x9f,0x88,0x43,0xa7,0xc3,0x0f,0x8a,0x50,0x48,0x1f,0x44,0x81,0xa1,0x32,0xcf,0xf8,0xe9,0x60,0x3f,0xff,0xc7,0xa2,0x8f,0x6e,0x40,0x15,0x5a,0x74,0x98,0x53,0x61,0xc5,0xde,0xd3,0xb1,0x4b,0xdf,0x1e,0x4d,0x3f,0x1f,0x18,0x4b,0xe9,0x26,0x0,0x6a,0x6a,0xb8,0xed,0xf2,0x4d,0xe3,0xcb,0x22,0x53,0x60,0xd1,0xa1,0xc0,0xa2,0xc3,0x65,0x35,0x9f,0x7a,0x68,0x65,0x95,0xa3,0xad,0xdf,0x87,0xc6,0x2e,0x37,0x1a,0xbb,0x3c,0x68,0xea,0x72,0xe3,0xb4,0xdd,0x43,0xc9,0x3d,0x53,0x80,0x5c,0xa3,0x16,0xd3,0x4a,0x2c,0x98,0x5a,0x6c,0xc1,0x94,0x62,0x0b,0xaa,0x0b,0x8c,0x28,0xce,0xd1,0x43,0x88,0x51,0x98,0x79,0xbe,0x59,0x97,0xb4,0xdf,0x16,0xe6,0x2c,0x0d,0x05,0x0,0x62,0xc6,0x75,0x32,0x49,0x60,0xa8,0xce,0x37,0xa1,0x3a,0xdf,0x84,0x6b,0xeb,0x3e,0x15,0x85,0xb3,0xbd,0x5e,0x9c,0xb2,0x0f,0x2c,0x63,0x4e,0x76,0xba,0x71,0xb4,0xcd,0x49,0x96,0x42,0x3c,0xdb,0x41,0x14,0x30,0xaf,0xd2,0x86,0x29,0x9f,0x99,0xd5,0xcb,0x6c,0x33,0x6b,0x97,0xff,0x0,0x0,0x10,0xb2,0x49,0x44,0x41,0x54,0x86,0x8c,0x3d,0x53,0x12,0x52,0xd3,0xd0,0x02,0xc8,0x96,0x03,0xe5,0x92,0xc0,0x50,0x53,0x38,0xe0,0x38,0xfa,0xac,0x73,0xe7,0xe1,0xed,0x87,0xd1,0xe3,0x0e,0xd2,0x68,0x8d,0x31,0xd3,0x4b,0x72,0xf0,0x83,0x2f,0xcd,0x42,0x81,0x45,0x47,0x95,0x31,0x01,0xe2,0x1e,0x07,0x90,0xea,0xe7,0x7b,0x5e,0x39,0xdc,0x89,0x5d,0x8d,0xdd,0xe8,0x70,0xc6,0x3e,0x75,0xd7,0xb4,0x62,0x0b,0xbe,0xb9,0x72,0x0a,0xf5,0xb2,0x38,0xf0,0x4f,0x5f,0x98,0x19,0xf3,0xc1,0xaf,0xa8,0x1c,0x2d,0xbd,0x5e,0xbc,0x71,0xac,0x2b,0xa6,0xeb,0xfc,0x98,0x4d,0x32,0x2c,0xf6,0x93,0x69,0xdc,0x2d,0x0,0x0d,0x52,0x7b,0x6b,0xed,0xa5,0x43,0x1d,0x38,0xda,0xee,0x1c,0x9c,0xc5,0xcb,0x72,0x8d,0x98,0x5a,0x6c,0xc6,0xd4,0xe2,0x81,0x75,0x64,0x6d,0x91,0x19,0x7a,0xcd,0xf8,0x97,0x31,0x63,0x05,0x7f,0x4c,0x84,0xda,0x22,0x33,0xd6,0xaf,0xa8,0x45,0xa9,0x4d,0x9f,0x52,0x75,0xaa,0xaa,0xc0,0x29,0xbb,0x1b,0x1b,0xdf,0x3a,0x85,0x5e,0x4f,0xec,0xad,0x9f,0x3c,0x93,0x76,0xc2,0xdb,0xc4,0x4e,0x7f,0x18,0xc7,0xda,0x5d,0x68,0xea,0x72,0xa3,0xa5,0xd7,0x8b,0x96,0x5e,0x1f,0xda,0xfa,0x7d,0x83,0x4e,0xb9,0x1b,0xe7,0x97,0x5f,0xe0,0xf7,0x49,0x05,0x34,0x42,0x1a,0x0a,0x80,0x56,0x50,0x31,0xb0,0x19,0x98,0xfa,0xeb,0xb2,0x4f,0xd6,0xf1,0x67,0x7b,0xbd,0x78,0xfd,0x68,0xd7,0x40,0xa5,0x8b,0x02,0x26,0x15,0x98,0x2e,0xf0,0x1e,0x4f,0x2e,0x34,0xc3,0x10,0xa1,0x28,0xe8,0xa5,0xf8,0xf8,0x40,0x0a,0x2c,0x3a,0x3c,0xb2,0x6a,0x3e,0xcc,0xba,0xd4,0x4c,0xea,0x54,0x9e,0x6b,0x40,0x75,0x81,0x09,0xff,0xeb,0xc9,0xfd,0x08,0xc7,0xf8,0xfc,0xc6,0x68,0xbb,0x39,0xc3,0xe1,0xf2,0x87,0x07,0x77,0x70,0x3e,0x89,0xfb,0x68,0xed,0xf3,0xa5,0xdd,0xf5,0x5f,0x3a,0xa6,0xa4,0x9f,0x0,0x08,0xe0,0x30,0x89,0x2a,0xbc,0x4a,0x7a,0x3a,0x03,0xc3,0x8a,0x7a,0xde,0xdb,0xef,0x1e,0x32,0x0b,0x4d,0x2d,0xb6,0xa0,0xba,0xc0,0x84,0xaa,0x7c,0x23,0xa6,0x16,0x5b,0x50,0x95,0x6f,0x4a,0x98,0xcc,0xad,0x98,0x56,0x94,0xb2,0x83,0xff,0x13,0xaa,0xf3,0x4d,0x98,0x55,0x6e,0xc5,0xc1,0xb3,0xfd,0x89,0xb1,0x3c,0x38,0xc7,0xb9,0xbe,0x0b,0x77,0x67,0x5a,0x7a,0xbc,0x29,0x91,0x8e,0x3d,0x16,0x98,0x85,0x70,0xfa,0x09,0x0,0x0,0x98,0x58,0x18,0xde,0x0c,0xdb,0x0d,0xe8,0xf3,0x86,0xb0,0xf7,0x74,0xef,0x05,0x6b,0xc5,0x86,0x3b,0x2f,0x43,0xa9,0xd5,0x90,0x90,0xf2,0xf3,0x4c,0xda,0xb4,0xa8,0xa7,0x44,0x3e,0xe7,0x7b,0x4d,0xbd,0x78,0xf8,0xaf,0x87,0x33,0xd6,0xef,0x61,0x11,0x63,0x2f,0x64,0x09,0x71,0xd1,0x59,0xa5,0xd8,0x29,0x57,0x2c,0x6e,0x85,0x21,0x88,0x44,0x63,0x35,0x4c,0xbc,0xdf,0xe6,0x88,0x69,0x6a,0x01,0x14,0x4a,0x01,0x34,0x22,0x36,0x61,0xbd,0x5b,0xef,0x5a,0x82,0x96,0x5e,0x2f,0x76,0x9e,0xe8,0xc6,0xdb,0x27,0xec,0x38,0xd7,0xe7,0xa3,0xde,0xf5,0x19,0xfc,0x61,0x05,0x8a,0x12,0xfd,0xda,0x56,0xaf,0x11,0x20,0x89,0x03,0x07,0xad,0xc6,0x73,0x26,0x42,0x2b,0x09,0x51,0xaf,0xcd,0x33,0x19,0x06,0xa0,0xae,0xdc,0x8a,0x2b,0xa6,0x15,0x62,0xe9,0x94,0x02,0x14,0x4f,0xf0,0x7a,0x39,0x1d,0x53,0xd3,0x57,0x0,0x0a,0xa4,0xd8,0x5e,0x2b,0x55,0x9d,0x6f,0x42,0xf5,0x32,0x13,0x56,0x2f,0x9b,0x34,0x28,0x06,0x7b,0x4f,0xf7,0x0e,0x59,0xa7,0x67,0x23,0x3f,0xfa,0xeb,0x11,0xec,0x3f,0x93,0xf8,0x8b,0x2e,0xbf,0x7a,0x69,0x25,0xee,0xbc,0xb2,0x36,0xab,0xeb,0x5e,0x14,0x18,0xe6,0x56,0xda,0x70,0x59,0x4d,0x3e,0x96,0x4d,0x29,0x88,0xc9,0x9d,0x92,0x9f,0x90,0x2f,0x05,0xe3,0xe2,0x5f,0x4a,0x88,0x0,0x58,0xc4,0x30,0x8c,0x82,0x1c,0xd5,0x79,0xe6,0x7e,0x6f,0x28,0x6a,0x31,0xe8,0x74,0x06,0xf0,0xde,0xa9,0x1e,0xec,0x3c,0xd9,0x4d,0x51,0x78,0x44,0x42,0x90,0x04,0x86,0x85,0x93,0xf2,0x70,0xc5,0xf4,0x42,0x2c,0x9e,0x9c,0x8f,0x1c,0x43,0x74,0xe7,0x0b,0x22,0xdd,0x26,0x2d,0xd1,0xc6,0xe7,0x4a,0xb3,0x84,0x08,0x0,0x03,0x50,0xa9,0xf5,0xe1,0x44,0x20,0x27,0xe2,0xcf,0x3c,0xf7,0x51,0x1b,0x96,0x4c,0xc9,0x8f,0x2a,0x86,0xbb,0xc4,0xaa,0xc7,0xcd,0x97,0x54,0xe0,0xe6,0x4b,0x2a,0x60,0x77,0x05,0xf0,0x6e,0xd3,0x79,0x31,0x68,0x77,0x52,0x4f,0x25,0x62,0x37,0x68,0x44,0x01,0x0b,0xab,0x73,0x71,0xc5,0xf4,0x42,0x5c,0x56,0x93,0x1f,0xf5,0xa1,0xa2,0x4f,0xf0,0x06,0xe5,0xc1,0xed,0xe6,0xb1,0xa8,0xd4,0xfa,0xd2,0x57,0x0,0x30,0x0e,0x01,0x38,0xd0,0xd2,0x8f,0xef,0xff,0xe9,0x63,0xdc,0xbe,0x7c,0x32,0xa6,0x97,0xe6,0x44,0x6d,0xfe,0x14,0xe5,0x7c,0x2a,0x06,0x1d,0x0e,0x7f,0xcc,0x4f,0x17,0x12,0xd9,0xc9,0x0d,0x73,0x4b,0xb1,0x76,0xf9,0xa4,0x09,0x39,0xa3,0x65,0x95,0x63,0xff,0x99,0x3e,0x6c,0x7a,0xe7,0x34,0xba,0x22,0xb8,0xac,0xd4,0x26,0x86,0x60,0x11,0xc2,0xe9,0x2d,0x0,0x45,0x9a,0x20,0x0c,0x82,0x02,0xbf,0x2a,0x46,0x25,0x02,0x07,0x5a,0xfa,0x51,0x60,0xd1,0x61,0xf9,0x94,0x02,0x2c,0x9b,0x5a,0x88,0x39,0x15,0xd6,0xa8,0x4f,0x76,0x95,0xda,0x0c,0xd4,0x73,0x89,0x98,0x30,0xb5,0x78,0x7c,0xce,0xec,0x90,0xac,0x62,0x5f,0x73,0x1f,0x76,0x37,0x0d,0xf8,0xab,0x3c,0x81,0xc8,0xb7,0xf4,0x26,0xeb,0xe2,0xe7,0xe8,0x4e,0x98,0x0,0x08,0xe0,0x98,0xaa,0x77,0xe3,0x63,0x9f,0x2d,0xea,0xcf,0xf6,0xb8,0x83,0xd8,0x7e,0xa0,0x0d,0xdb,0x0f,0xb4,0x41,0xa7,0x11,0x31,0xbf,0xd2,0x86,0x2b,0xa6,0x17,0x62,0xf9,0x94,0x42,0x18,0xb4,0x22,0xf5,0x4a,0x22,0x25,0xe9,0xf7,0x86,0xf0,0xf6,0x09,0x3b,0x76,0x9e,0xec,0xc6,0xb1,0x76,0xd7,0xb8,0x22,0x0f,0x05,0x70,0x4c,0xd1,0xbb,0xd3,0x5f,0x0,0x0,0x60,0x8a,0xce,0x83,0xc3,0x3e,0x2b,0xd4,0x09,0xf8,0x33,0x83,0x61,0x65,0x30,0x0,0xe7,0x51,0xe9,0x24,0x16,0x54,0xe5,0xe2,0xb2,0xda,0x01,0xaf,0x2b,0xc5,0x08,0x10,0xc9,0xa6,0xc7,0x1d,0xc4,0xae,0xc6,0xee,0x41,0xdf,0xd3,0x44,0xa3,0x8d,0x2b,0x75,0xbe,0xb8,0x84,0x0,0x27,0x45,0x0,0x8c,0x82,0x8c,0x2a,0xad,0x0f,0x67,0x42,0xa6,0x98,0x7c,0x5f,0x48,0x56,0x07,0xc5,0xe0,0x89,0x37,0x9b,0xb0,0x70,0x52,0x1e,0x96,0x4d,0x29,0xc0,0x92,0xda,0xc8,0x1d,0x33,0x74,0xcf,0x0,0x31,0x1c,0x8a,0x1a,0x79,0xbf,0xb0,0xbb,0x02,0xd8,0xd3,0xd4,0x83,0x5d,0x8d,0x3d,0x38,0xd2,0xe6,0x8c,0xe9,0x19,0x83,0x99,0x7a,0x57,0x5c,0x7f,0x67,0xc2,0x83,0xc9,0xe7,0x18,0x1d,0x68,0x09,0x99,0x62,0xbe,0x45,0x17,0x92,0x55,0xec,0x69,0xea,0xc1,0x9e,0xa6,0x1e,0x48,0xe7,0xf7,0x63,0x97,0x4f,0x1d,0x08,0xc2,0x18,0x29,0x1c,0xd5,0x17,0x92,0x71,0x36,0xce,0x81,0x44,0xa2,0xc0,0x30,0xb3,0x2c,0x07,0xed,0xfd,0x7e,0x38,0x29,0xbf,0xe0,0x84,0x60,0x0,0xf2,0x2d,0xba,0x71,0xaf,0xc3,0xa3,0xe1,0x64,0xa7,0x7b,0xd4,0x23,0x6c,0x6d,0xfd,0x3e,0xec,0x6a,0xec,0xc1,0xee,0xc6,0x6e,0x34,0x9e,0x7f,0x6f,0xac,0x29,0xd7,0xfa,0x51,0x20,0x05,0x33,0x4b,0x0,0xac,0x62,0x18,0x93,0x74,0x5e,0x34,0x07,0x4d,0x71,0x2b,0x43,0x56,0x39,0x3e,0x6c,0xe9,0xc7,0x87,0x2d,0xfd,0x78,0xec,0xf5,0x93,0xa8,0x2b,0xb3,0x62,0xd9,0x94,0x02,0x2c,0x9f,0x5a,0x38,0x98,0xf4,0x31,0x10,0x56,0xf0,0xb3,0x97,0x4e,0xc4,0xfd,0xca,0x31,0xad,0x24,0xe0,0x17,0xb7,0x5e,0x32,0x68,0x6d,0x74,0x7b,0x82,0xe8,0x74,0x04,0xd0,0xe1,0xf4,0xa3,0xd3,0x19,0x40,0x87,0x63,0xe0,0xef,0x96,0x5e,0x2f,0x65,0x25,0x06,0x60,0xd0,0x88,0xa8,0xc8,0x33,0xa2,0xc4,0xaa,0x47,0xa9,0xcd,0x30,0xf0,0xb7,0xd5,0x80,0x12,0x9b,0x1e,0x45,0x16,0x3d,0x44,0x21,0x31,0xc7,0xad,0x4e,0xd9,0x3d,0xd8,0xb2,0xab,0x19,0x6b,0x97,0x4f,0x1a,0x74,0x3a,0x9f,0xb2,0x7b,0xb0,0xbb,0xb1,0x1b,0xbb,0x1b,0x7b,0xe2,0x92,0x1d,0xf8,0x62,0xb1,0x9b,0x6b,0x70,0xc4,0xfd,0x77,0x26,0xe5,0x38,0xd9,0x7c,0x63,0x3f,0xce,0x86,0x8c,0x50,0x78,0xfc,0x1b,0x93,0x73,0xe0,0x48,0x9b,0x13,0x47,0xda,0x9c,0xf8,0xcd,0xdb,0xa7,0x30,0xa9,0xc0,0x84,0x5c,0x93,0x16,0xa7,0x92,0x90,0xf1,0x57,0x12,0x05,0x94,0x5a,0x0d,0x28,0xb5,0x1a,0xb0,0x0,0xb9,0x17,0x99,0x9c,0x1c,0x76,0x77,0x60,0x58,0x71,0x38,0xd7,0xe7,0xcb,0xa8,0xbb,0x11,0x4d,0x3a,0x09,0x65,0xe7,0x07,0x77,0x75,0xbe,0x09,0xd5,0x05,0xa6,0xc1,0x81,0x6e,0xd6,0xa7,0xce,0x09,0xc7,0x3f,0xec,0x6d,0xc1,0x5b,0xc7,0xbb,0x50,0x6a,0x33,0xa0,0xad,0xdf,0x0f,0xbb,0x2b,0x90,0xb0,0xb2,0x27,0xe9,0xbc,0xc8,0x97,0x82,0x99,0x29,0x0,0x26,0x41,0xc6,0x6c,0x83,0x13,0x1f,0x8d,0x63,0x47,0x60,0xa2,0x9c,0xe9,0xf1,0xe2,0x4c,0x4f,0x7c,0xd4,0x3b,0x18,0x1e,0xff,0x0c,0x2e,0x0a,0x6c,0x44,0x71,0x90,0x15,0x15,0x5d,0xae,0x0,0xda,0x1d,0x01,0xb4,0x3b,0xfc,0x68,0x77,0xf8,0x51,0x91,0x97,0x1e,0x5b,0x9b,0x75,0x65,0x39,0xc8,0x33,0x6b,0x51,0x66,0x33,0x0c,0xfe,0x29,0xb4,0xe8,0xe2,0x92,0xb7,0x2f,0x1e,0x49,0x59,0x3b,0x9d,0x01,0x74,0x3a,0x03,0x09,0xad,0x33,0x89,0xa9,0x58,0x60,0x4c,0x4c,0x38,0x77,0xd2,0xe4,0xb6,0x4e,0xef,0xc4,0xa9,0xa0,0x19,0x1e,0x45,0x42,0xa6,0xb0,0xaf,0xb9,0x0f,0x93,0x0a,0x62,0xbf,0xb4,0x91,0x44,0x01,0xe5,0xb9,0x46,0x94,0xe7,0x1a,0xd3,0xae,0x4e,0x6e,0x9c,0x5f,0x9e,0xb0,0xb2,0x3e,0x68,0xee,0xcd,0x88,0x7e,0x34,0xd7,0xe8,0x84,0x51,0x48,0x8c,0xc5,0x97,0xb4,0xe3,0x5b,0x22,0xe3,0x58,0x6e,0xee,0xc9,0xa8,0xbb,0xfe,0x9e,0xda,0x73,0x06,0xef,0x36,0xf5,0xd0,0x19,0x84,0x04,0x23,0xab,0x1c,0x7f,0xdc,0x77,0x0e,0x6f,0x1f,0xb7,0xa7,0xfd,0x6f,0x29,0x94,0x82,0x98,0xa9,0x4f,0x5c,0xe8,0xba,0x94,0xdc,0x1f,0x1b,0xc0,0x2c,0x83,0x13,0x87,0xfd,0xd6,0x8c,0xe8,0x88,0x81,0xb0,0x82,0x87,0xb7,0x1f,0x46,0x81,0x45,0x87,0x49,0xf9,0x26,0x94,0xda,0x0c,0x28,0xb5,0x19,0x50,0x66,0x1b,0x70,0x68,0x95,0x5a,0x0d,0x74,0x64,0x76,0x02,0x78,0x83,0x32,0x3a,0x1c,0x7e,0x74,0x38,0x07,0x96,0x42,0x9d,0x4e,0x3f,0x3a,0x1c,0x01,0x9c,0xee,0xce,0x8c,0x1b,0x9c,0x24,0xc6,0xb1,0xcc,0x92,0xd8,0x49,0x31,0xe9,0xf6,0xf7,0x5c,0x43,0x3f,0x3a,0xc2,0x7a,0xf4,0xca,0x99,0x93,0xde,0xb9,0xc7,0x1d,0x1c,0x31,0x15,0x78,0xbe,0x59,0x87,0x52,0xdb,0x80,0xc3,0xab,0xec,0xbc,0x40,0x7c,0xf2,0xff,0xd1,0x9e,0x24,0x1b,0xa9,0xec,0x64,0xd0,0xeb,0x8d,0xcd,0x91,0xef,0x5e,0x4f,0x10,0x1d,0xe7,0x1d,0xa1,0xed,0x0e,0xff,0xa0,0x23,0xb4,0xdd,0xe1,0xcf,0xf8,0x6b,0xda,0x16,0x99,0xfa,0xe2,0x16,0xf3,0x9f,0xb2,0x02,0x20,0x30,0xe0,0x4a,0x4b,0x37,0x5e,0x74,0x96,0x22,0xa0,0x66,0x7e,0x58,0x6f,0xaf,0x27,0x88,0x5e,0x4f,0x10,0x87,0x5b,0x87,0x9a,0x79,0x26,0x9d,0x74,0xde,0x52,0xd0,0x0f,0x8a,0x43,0xc9,0xf9,0xff,0x8e,0xc4,0x71,0x76,0xa2,0xd3,0x85,0xb3,0x7d,0xde,0xa4,0xfc,0xae,0xfd,0x67,0xfa,0xd0,0xef,0x0b,0x21,0x77,0x8c,0x68,0xcc,0x01,0x87,0x66,0x10,0x1d,0xce,0x81,0xc1,0xdd,0xe1,0xf0,0xa3,0xdd,0x11,0x40,0xe7,0xf9,0x01,0x9f,0xad,0x5b,0xa1,0xd3,0xf5,0x2e,0xd4,0xea,0x12,0x9f,0xcf,0x22,0x25,0x3c,0x70,0x46,0x41,0xc6,0x95,0x16,0x3b,0x5e,0x75,0x95,0x22,0x9b,0x0f,0xed,0x79,0x83,0x32,0x9a,0xba,0xdc,0x68,0x1a,0x26,0xb1,0x89,0x24,0x0a,0x83,0x5b,0x65,0x65,0x36,0x3d,0x4a,0xac,0x9f,0x2e,0x2f,0x04,0xc6,0x70,0xa4,0xdd,0x89,0xad,0xbb,0xcf,0x24,0xed,0x1e,0x16,0x97,0x3f,0x8c,0xef,0xff,0xf1,0x63,0xac,0x5e,0x36,0x09,0x93,0x0a,0x4c,0xf0,0x87,0x94,0xcf,0x0c,0xf2,0xc0,0xe0,0x6c,0xde,0xed,0x0e,0xa6,0x5d,0x36,0xde,0x78,0x53,0xa2,0x09,0x60,0xa1,0xa9,0x3f,0x29,0x65,0xa7,0x8c,0x0b,0xbe,0x50,0x0a,0x62,0x85,0xb9,0x0b,0x6f,0xbb,0x8b,0xc9,0x89,0x36,0xc2,0xcc,0xd9,0xda,0xe7,0x43,0x6b,0x0a,0xa7,0x40,0x3b,0xdd,0xed,0xc1,0xc3,0xdb,0x0f,0x53,0x63,0x45,0x41,0x9e,0x14,0xc2,0x95,0x96,0x2e,0x08,0x49,0xea,0xf5,0x29,0xe5,0x91,0xaa,0xd0,0xfa,0xb1,0xd8,0xd4,0x4b,0xbd,0x82,0xc8,0x0a,0x4c,0x82,0x8c,0x95,0x96,0x2e,0x68,0x58,0xf2,0xa6,0xbc,0x94,0x73,0x49,0x4f,0xd5,0xbb,0x51,0xa7,0xa7,0x0c,0x3e,0x44,0x66,0xa3,0x63,0x2a,0xae,0xb2,0x74,0x25,0x6c,0xbf,0x3f,0x6d,0x04,0x0,0x0,0x2e,0x31,0xf5,0x63,0x81,0xb1,0x9f,0x7a,0x09,0x91,0x91,0x18,0x04,0x05,0xd7,0x59,0x3b,0x60,0x93,0x92,0xbf,0xab,0x91,0xb2,0x61,0x78,0xb3,0x0c,0x4e,0x30,0x70,0x7c,0xe8,0xcb,0xa3,0x1e,0x43,0x64,0x0c,0x46,0x41,0xc6,0xb5,0x39,0x5d,0x71,0x49,0xf1,0x9d,0x51,0x02,0x0,0x0,0x75,0x06,0x17,0x18,0x80,0xfd,0xbe,0x5c,0x0,0x8c,0x7a,0x0f,0x91,0xd6,0x58,0x44,0x19,0xd7,0x58,0x3a,0x61,0x16,0x53,0xe7,0xaa,0xb2,0x91,0x04,0x40,0x01,0x52,0xe3,0x2e,0xaf,0x99,0x06,0x17,0xac,0x62,0x08,0x3b,0x3d,0xc5,0x08,0x73,0x12,0x01,0x22,0x3d,0x29,0xd5,0xf8,0x71,0xa5,0xa5,0x1b,0x12,0x4b,0x6e,0x9c,0x03,0xe7,0x5c,0x8e,0xc4,0x07,0xe0,0x49,0xa5,0xca,0x2b,0xd3,0x06,0x70,0x8d,0xa5,0x13,0x06,0x41,0xa1,0x9e,0x44,0xa4,0x1d,0xd5,0x3a,0x2f,0x56,0x5a,0xec,0x49,0x1f,0xfc,0x0,0xc0,0x18,0x73,0x8f,0x2d,0x0,0x17,0xbd,0x29,0x15,0x28,0xd0,0x04,0x71,0xa3,0xad,0x1d,0x25,0x9a,0x0,0xf5,0x28,0x22,0x2d,0x10,0x18,0x70,0x99,0xa9,0x07,0x57,0x98,0xbb,0x21,0xb2,0x14,0x89,0x6e,0xe1,0xdc,0x35,0xb6,0x0,0xa8,0x6a,0x4a,0xde,0xb1,0xa5,0x63,0x0a,0xae,0xb6,0x74,0x62,0x9a,0xce,0x45,0xbd,0x8b,0x48,0x69,0xf4,0x82,0x8a,0xab,0x2d,0x9d,0x98,0xaa,0x4f,0x29,0x63,0x1a,0x0c,0x70,0x8f,0xe9,0x03,0xe0,0x8c,0xb9,0x53,0x75,0xb5,0x2d,0x30,0x60,0xb1,0xb9,0x0f,0x95,0x3a,0x3f,0xf6,0x78,0x0a,0xe0,0x53,0x29,0x2d,0x38,0x91,0x5a,0x4c,0xd2,0x7a,0xb0,0xd8,0xdc,0x07,0x2d,0x4b,0xbd,0x73,0x0d,0xea,0x45,0x02,0x20,0x8c,0xa0,0x12,0x5d,0xa9,0x5e,0xc9,0xa5,0x1a,0x3f,0x6e,0xb0,0xb6,0xa3,0x54,0xe3,0xa7,0x1e,0x47,0xa4,0x04,0x22,0xe3,0x58,0x6c,0xea,0xc5,0x72,0x4b,0x4f,0x4a,0x0e,0xfe,0x81,0x67,0x64,0x5d,0x63,0x2f,0x01,0x80,0xe3,0xe9,0x50,0xe1,0x06,0x41,0xc1,0x35,0x39,0x5d,0x58,0x61,0xe9,0x8e,0x6b,0xee,0x74,0x82,0x18,0x8b,0x4a,0xad,0x0f,0x37,0xd9,0x5a,0x31,0x4d,0xef,0x4e,0xe5,0x0d,0x6b,0x55,0x63,0x32,0x9d,0x88,0x64,0x09,0x70,0x82,0xa5,0xd1,0x89,0xad,0x2a,0xad,0x17,0x25,0x36,0x3f,0x0e,0xf8,0xf3,0xd0,0x18,0x30,0x53,0x6f,0x24,0x12,0x86,0x8e,0x29,0xb8,0xcc,0xdc,0x87,0x2a,0xad,0x37,0x1d,0x1e,0xf7,0xdc,0xaa,0x55,0xab,0xfc,0x63,0x0a,0x0,0x14,0xe5,0x04,0x84,0xf4,0xca,0x5c,0xa3,0x15,0x54,0x5c,0x66,0xea,0x41,0xb9,0xc6,0x87,0xfd,0xde,0x3c,0xb8,0x55,0x89,0x7a,0x27,0x11,0x37,0x18,0x80,0x49,0x3a,0x0f,0x2e,0x31,0xf6,0xa7,0xd3,0xf6,0xf4,0x89,0x8b,0x5f,0x18,0x7e,0x94,0x68,0x34,0x27,0xa1,0xa4,0xa7,0x49,0x5d,0xa1,0xf5,0xa1,0x4c,0xeb,0xc7,0xc9,0x80,0x05,0x1f,0xf9,0x72,0x29,0x78,0x88,0x88,0x39,0x85,0x52,0x10,0x8b,0x4c,0xbd,0xc8,0x93,0x42,0xe9,0xf5,0xe0,0x8c,0x9d,0xbc,0xf8,0xa5,0x61,0xa7,0xf9,0xb5,0x6b,0xd7,0xda,0x01,0x9c,0x4c,0xd7,0x06,0x12,0xc0,0x31,0x43,0xef,0xc2,0x8d,0xb6,0x36,0x4c,0xd1,0x79,0x28,0x88,0x98,0x88,0x09,0x26,0x41,0xc6,0x52,0x53,0x0f,0xae,0xb3,0x76,0xa4,0xdf,0xe0,0x07,0xc0,0x54,0x75,0x57,0x64,0x16,0xc0,0x80,0x89,0xf3,0x06,0x07,0xa6,0xa5,0x7b,0x83,0x2d,0x31,0xf7,0x60,0x8e,0xa1,0x1f,0x87,0x03,0xb9,0x68,0x0a,0x98,0x29,0xd9,0x08,0x11,0x35,0x46,0x41,0xc1,0x1c,0x43,0x3f,0x6a,0xf5,0xde,0xa4,0x25,0xee,0x88,0x01,0x5c,0x95,0xa4,0x37,0x23,0x16,0x0,0x15,0x78,0x83,0x01,0xdf,0xca,0x08,0xe5,0x16,0x15,0x5c,0x66,0xea,0xc1,0x54,0x9d,0x0b,0x87,0x02,0x36,0xb4,0x06,0x8d,0x24,0x04,0xc4,0x98,0xe8,0x05,0x15,0x33,0xf5,0x4e,0x4c,0xd7,0xbb,0x53,0x22,0x8c,0x77,0x82,0x1c,0x3a,0x6f,0xd9,0x47,0x26,0x0,0x5c,0x10,0xde,0x60,0xaa,0xaa,0x22,0x45,0x73,0x06,0x8c,0x87,0x3c,0x29,0x84,0x2b,0xcd,0x76,0x38,0x0c,0x5a,0x1c,0xf6,0x59,0x71,0x26,0x64,0x04,0x9d,0x32,0x24,0x2e,0xc6,0x20,0x28,0xa8,0x33,0xb8,0x30,0x55,0xe7,0x82,0xc4,0x32,0x63,0xaa,0xe0,0xc0,0x1b,0xc3,0x2f,0x97,0x47,0xe0,0xf6,0xdb,0x6f,0xef,0x05,0xb0,0x3f,0x13,0x1b,0xd8,0x26,0x86,0x70,0xb9,0xa5,0x1b,0x5f,0xcd,0x6d,0xc5,0x5c,0x83,0x83,0x62,0x08,0x08,0x0,0x40,0x89,0xc6,0x8f,0x95,0x16,0x3b,0x6e,0xc9,0x3d,0x87,0x99,0x7a,0x67,0xc6,0x0c,0xfe,0xf3,0x4b,0xfa,0x97,0x87,0x7b,0x7d,0xd4,0xbd,0x32,0xce,0xd8,0x16,0xc6,0xf9,0xa2,0xcc,0x35,0xf1,0x14,0xcc,0x35,0x3a,0x30,0xd3,0xe0,0xc4,0xa9,0xa0,0x05,0x27,0x03,0x16,0xb8,0x14,0x0d,0x8d,0x84,0x2c,0x42,0x0,0x47,0x85,0xd6,0x8f,0xe9,0x7a,0x27,0x8a,0x35,0xc1,0xcc,0xfc,0x91,0x8c,0xb5,0x9e,0x3a,0x73,0xe6,0x95,0xa8,0x05,0x40,0x2f,0xcb,0xcf,0x04,0x45,0xf1,0x67,0x0,0x74,0x99,0xdc,0x09,0x34,0x6c,0x60,0xd7,0x60,0x86,0xde,0x85,0x5e,0x59,0x8b,0xa6,0x60,0x0e,0x9a,0x83,0x26,0xc8,0xb4,0x85,0x98,0xb1,0xd8,0xc4,0x10,0xa6,0xeb,0x5d,0xa8,0xd6,0xf9,0x52,0x36,0x6c,0x37,0x76,0xf6,0x3f,0x7f,0x66,0xc3,0x86,0x0d,0xea,0x08,0x96,0xc1,0xe8,0x6c,0x6d,0x68,0xf8,0x0b,0x03,0x6e,0xca,0xb6,0x0e,0xe2,0xe7,0x22,0x9a,0x83,0x66,0x9c,0x0e,0x9a,0xe1,0x90,0xc9,0x2a,0xc8,0x04,0x44,0xc6,0x51,0xa9,0xf1,0xa1,0x46,0xef,0x41,0x59,0x16,0x9d,0x21,0x51,0x18,0x9b,0x7d,0xc7,0x1d,0x77,0x1c,0x89,0xda,0x02,0x0,0x0,0x81,0xf3,0xa7,0x38,0x63,0x59,0x27,0x0,0x06,0xa6,0xa0,0x4e,0xef,0x44,0x9d,0xde,0x09,0x87,0xa2,0x45,0x73,0xd0,0x84,0x33,0x41,0x13,0xbc,0x14,0x61,0x98,0x6e,0x6b,0x5f,0x14,0x6b,0x02,0xa8,0xd1,0x79,0x50,0xa9,0xf5,0x26,0x35,0x05,0x77,0x92,0xf8,0x68,0xa4,0xc1,0x1f,0x91,0x0,0x34,0x9d,0x3d,0xfb,0xe7,0x29,0xd5,0xd5,0x47,0x38,0x30,0x2b,0x9b,0xcd,0xc5,0x05,0xc6,0x10,0x16,0x18,0xfb,0xe1,0x54,0x34,0x68,0x0d,0x19,0xd1,0x16,0x36,0xa2,0x3b,0xac,0xa3,0xed,0xc4,0x14,0x5d,0xd2,0x55,0x68,0xbd,0xa8,0xd6,0xfa,0x50,0xa2,0xf1,0x67,0x94,0x33,0x2f,0x6a,0x01,0xe4,0xfc,0xa7,0x63,0x09,0xe4,0x98,0x6c,0x6d,0x68,0xb8,0x83,0x01,0x0d,0xd4,0xb5,0x2e,0xc4,0xa9,0x68,0xd0,0x16,0x32,0xa2,0x3d,0x6c,0x80,0x3d,0xac,0x83,0x4a,0x5b,0x8a,0x49,0xc3,0x28,0xc8,0x28,0xd5,0x06,0x50,0xae,0xf1,0xa3,0x4c,0xe3,0xcf,0x84,0x7d,0xfb,0x58,0x70,0x52,0x67,0x32,0xd5,0xad,0x5a,0xb5,0x4a,0x19,0xb7,0x05,0x0,0x0,0xfe,0x50,0xe8,0x69,0x93,0x56,0xfb,0x20,0x07,0x26,0x51,0x9d,0x7e,0x8a,0x55,0x0c,0xc3,0x6a,0x70,0xa2,0xce,0xe0,0x84,0xcc,0x19,0xba,0xc2,0x7a,0xb4,0xcb,0x46,0x74,0x86,0xf4,0x70,0x29,0x1a,0xb2,0x0e,0xe2,0x39,0xcb,0x43,0x45,0x91,0x36,0x88,0x62,0xc9,0x8f,0x32,0x6d,0x0,0x36,0x31,0x44,0x95,0x32,0x74,0x76,0x7f,0x64,0xb4,0xc1,0x1f,0xb1,0x05,0x0,0x0,0x4f,0x35,0x34,0xdc,0xcd,0x81,0x47,0xa9,0x5a,0x23,0xc3,0xcf,0x45,0x74,0x85,0xf5,0xe8,0x3a,0x6f,0x1d,0x90,0x20,0x4c,0x0c,0x89,0xa9,0x28,0x90,0x42,0x28,0xd1,0x04,0x50,0x24,0xf9,0x51,0xa0,0x09,0xa5,0x73,0x58,0x6e,0x02,0x46,0x3f,0x6b,0xed,0x77,0xb9,0xa6,0xdc,0x73,0xcf,0x3d,0xc1,0x98,0x08,0xc0,0xb6,0x6d,0xdb,0xc4,0xa0,0xd7,0xbb,0x0f,0xc0,0x7c,0xaa,0xdd,0xe8,0x09,0x72,0x01,0xbd,0xb2,0x0e,0xdd,0x61,0x1d,0xba,0x65,0x3d,0xfa,0x64,0x2d,0x42,0x5c,0xa0,0x8a,0x19,0x06,0x91,0x71,0xe4,0x8a,0x21,0x14,0x48,0x41,0xe4,0x49,0x41,0xe4,0x4b,0x21,0x58,0x53,0xe4,0x22,0x8d,0x74,0x81,0x03,0xb7,0xac,0xad,0xaf,0xff,0x73,0x04,0x56,0x42,0xe4,0x3c,0xbd,0x65,0xcb,0x62,0x55,0x55,0xf7,0x20,0x83,0xc2,0x83,0x93,0x89,0x5b,0x95,0xe0,0x90,0xb5,0xe8,0x95,0xb5,0x70,0xc8,0x5a,0x38,0x54,0x2d,0x7c,0x8a,0x98,0x55,0xbe,0x04,0x2d,0x53,0x61,0x11,0x65,0xe4,0x8a,0x41,0xe4,0x4b,0x41,0x14,0x48,0x21,0x58,0xa5,0x30,0xcd,0xee,0x13,0x19,0xfc,0x8c,0x3d,0xbf,0xf6,0x8e,0x3b,0xbe,0x18,0xe1,0x32,0x21,0x3a,0xb6,0x36,0x34,0x6c,0x62,0xc0,0x3a,0xaa,0xe6,0xf8,0x11,0x52,0x05,0x38,0x55,0x2d,0x1c,0xb2,0x04,0x8f,0xaa,0x81,0x5b,0x91,0xe0,0x55,0x35,0x70,0x28,0x1a,0x28,0x69,0x18,0x9c,0x64,0x11,0x64,0x98,0xc4,0x30,0x2c,0xa2,0x02,0xb3,0x10,0x86,0x45,0x94,0x61,0x15,0x43,0x30,0x0b,0x72,0xea,0xa4,0xcb,0xce,0x1c,0x02,0xe7,0xf7,0xfd,0x4f,0x45,0xb4,0xb4,0x8a,0x7a,0x2d,0x26,0xcb,0x0f,0x28,0x1a,0xcd,0x97,0xc0,0x79,0x01,0xd5,0x75,0x9c,0x66,0x45,0x41,0x45,0xa1,0x10,0x40,0xe1,0x45,0xad,0xa3,0x82,0x9d,0x17,0x03,0x09,0x41,0x2e,0x22,0xa0,0x8a,0x08,0xaa,0x02,0x02,0xaa,0x88,0x0,0x1f,0xf8,0xef,0x20,0x17,0xe0,0x57,0xa5,0xb8,0x27,0x42,0x11,0xc0,0xa1,0x13,0x54,0xe8,0x98,0x02,0xbd,0xa0,0x42,0xcf,0x64,0xe8,0x05,0x15,0x5a,0xa6,0x40,0x2f,0x72,0x18,0x98,0x0c,0x1d,0x53,0x61,0x11,0xc3,0x74,0xa1,0x4b,0x62,0x79,0x24,0xd2,0xc1,0x3f,0x2e,0x0b,0xe0,0xfc,0x52,0xe0,0x2a,0x55,0x55,0x5f,0x45,0x8a,0x5c,0x1f,0x46,0x0c,0x45,0x05,0x43,0x50,0x15,0x20,0x73,0x86,0x10,0x17,0x10,0xe6,0x02,0x64,0x2e,0x40,0x86,0x80,0x70,0x84,0x3b,0x64,0x8c,0x01,0x5a,0xc6,0x21,0x41,0x81,0xc4,0x38,0x24,0xc6,0xa1,0x11,0x54,0x68,0xa1,0x42,0x27,0xd0,0x36,0x5b,0x0a,0xf2,0xea,0xa9,0x96,0x96,0xcf,0x8f,0x14,0xf6,0x1b,0x33,0x01,0x0,0x80,0x27,0x1b,0x1a,0x1e,0x06,0xf0,0x03,0xaa,0x73,0x82,0x48,0x09,0xda,0xb9,0x28,0x2e,0x18,0xee,0xcc,0xff,0xe8,0x96,0xdc,0x38,0x39,0xd5,0xd2,0xb2,0x81,0x31,0xf6,0x1a,0xd5,0x3b,0x41,0x24,0x1d,0x85,0x73,0x7e,0x5b,0xb4,0x83,0x7f,0x42,0x16,0x0,0x0,0x3c,0xb3,0x69,0x53,0x99,0x22,0x08,0xbb,0x29,0x40,0x88,0x20,0x92,0xca,0xbf,0xac,0xa9,0xaf,0x7f,0x64,0x3c,0x1f,0x9c,0xd0,0x76,0xde,0xad,0xeb,0xd7,0xb7,0x33,0xce,0xaf,0x01,0xd0,0x41,0x6d,0x40,0x10,0x89,0x87,0x03,0xff,0x36,0xde,0xc1,0x3f,0x61,0x0b,0xe0,0x13,0x9e,0x6a,0x68,0x98,0xc3,0x81,0xb7,0x01,0xe4,0x52,0x93,0x10,0x44,0xc2,0xd8,0xb4,0xfa,0x8e,0x3b,0xee,0x62,0x6c,0xfc,0x7b,0xa9,0x31,0x09,0xe8,0x59,0x5d,0x5f,0x7f,0x08,0xc0,0xd7,0x01,0xf8,0xa8,0x4d,0x08,0x22,0x21,0x3c,0xa7,0x33,0x99,0xfe,0x61,0x22,0x83,0x3f,0x66,0x02,0x0,0x0,0x6b,0xea,0xeb,0x5f,0x65,0xc0,0x12,0x0,0x6d,0xd4,0x36,0x04,0x11,0x57,0x7e,0xa5,0x33,0x99,0xbe,0xbc,0x6a,0xd5,0xaa,0x09,0x9f,0x80,0x8a,0x79,0xb4,0xc8,0xd6,0xad,0x5b,0x27,0x33,0x45,0x79,0x09,0x69,0x7e,0xa7,0x0,0x41,0xa4,0xe6,0x92,0x1f,0xf7,0x4f,0x64,0xcd,0x1f,0x37,0x0b,0xe0,0x13,0xd6,0xae,0x5d,0xdb,0x2c,0xa9,0xea,0x55,0x60,0x6c,0x1f,0xb5,0x17,0x41,0xc4,0x8c,0x10,0x38,0xff,0xfb,0x58,0x0e,0xfe,0xb8,0x08,0x0,0x30,0xb0,0x3b,0x50,0x71,0xe6,0xcc,0x52,0x0,0x0f,0x01,0xa0,0x90,0x31,0x82,0x98,0x18,0x47,0x19,0xe7,0x0b,0xd6,0xac,0x5b,0xb7,0x31,0xd6,0x5f,0x1c,0xf7,0x93,0x25,0x4f,0xfd,0xee,0x77,0x37,0xaa,0x8c,0x6d,0x61,0x40,0x1e,0xb5,0x23,0x41,0x44,0xcd,0x1f,0x42,0xaa,0xfa,0x77,0xeb,0xd7,0xaf,0x77,0xc7,0xe3,0xcb,0x13,0x72,0xb4,0x6c,0xf3,0xe6,0xcd,0xb5,0x22,0xe7,0x8f,0x01,0xf8,0x3c,0xb5,0x27,0x41,0x44,0xb4,0xd8,0xef,0x63,0x9c,0x3f,0xb0,0xba,0xbe,0xfe,0xd7,0x13,0xf5,0xf4,0x27,0x5d,0x0,0x06,0xad,0x81,0xcd,0x9b,0xaf,0x51,0x39,0x7f,0x8c,0x01,0x33,0xa8,0x89,0x09,0x62,0x58,0x14,0xc6,0xf9,0xe3,0x61,0xc6,0x1e,0xac,0xaf,0xaf,0x77,0xc4,0xbb,0xb0,0x84,0x1f,0x2e,0xdf,0xba,0x75,0xab,0x09,0xb2,0x7c,0x3f,0x63,0xec,0x1e,0x0,0x16,0x6a,0x6f,0x82,0x18,0x64,0x37,0x03,0xbe,0xb7,0xba,0xbe,0xfe,0xbd,0x44,0x15,0x98,0xb4,0xec,0x12,0xdb,0x1e,0x7f,0xdc,0x1c,0x34,0x1a,0xd7,0x03,0xf8,0x67,0x0,0xa5,0xd4,0xf6,0x44,0xb6,0x5a,0xfb,0x9c,0xb1,0x17,0x38,0x63,0x3f,0xb9,0xfd,0xf6,0xdb,0xf7,0x24,0xba,0xf0,0xa4,0xa7,0x97,0xd9,0xb6,0x71,0xa3,0x35,0xa0,0xd1,0xfc,0x03,0x13,0x84,0x75,0xe0,0x7c,0x0a,0xf5,0x07,0x22,0x4b,0x08,0x32,0xe0,0x05,0x55,0x55,0x7f,0xb1,0x76,0xfd,0xfa,0x5d,0xc9,0x7a,0x88,0x94,0xca,0x2f,0xb5,0x79,0xf3,0xe6,0x59,0x22,0xe7,0x5f,0x03,0xb0,0x06,0x40,0x0d,0xf5,0x11,0x22,0xc3,0x08,0x73,0xc6,0x5e,0x06,0xe7,0x5b,0xf5,0x26,0xd3,0xf3,0xab,0x56,0xad,0x4a,0xfa,0xfd,0x64,0x29,0x99,0x60,0xee,0xcd,0x0d,0x1b,0xa4,0xd6,0xea,0xea,0xa5,0x9c,0xf3,0x6b,0x19,0x63,0xd7,0x82,0xb1,0xc5,0xe0,0x9c,0xee,0xe4,0x22,0xd2,0x91,0x0e,0x06,0xbc,0xc6,0x19,0x7b,0x4d,0xe6,0xfc,0x95,0xfa,0xfa,0xfa,0xce,0x54,0x7a,0xb8,0xb4,0xc8,0x30,0xf9,0xd4,0x53,0x4f,0xe5,0xa8,0xe1,0xf0,0xe5,0x60,0x6c,0x36,0x38,0x9f,0x2e,0x70,0x3e,0x93,0x33,0x36,0x03,0x74,0xfa,0x90,0x48,0x99,0x91,0xc4,0x64,0x70,0xde,0xcc,0x81,0xa3,0x02,0xe7,0x27,0x38,0x70,0x5c,0x11,0x84,0xf7,0x47,0xbb,0x97,0x8f,0x04,0x20,0x06,0xfe,0x03,0x8f,0x46,0xa3,0xd5,0x01,0x16,0xce,0x98,0x89,0x31,0xa6,0xa5,0x9e,0x48,0x24,0x0a,0x55,0x96,0x9d,0x5c,0xab,0x0d,0x89,0xa2,0xe8,0xd6,0x68,0x34,0xde,0x58,0x1c,0xce,0x21,0x08,0x82,0x20,0x08,0x82,0x20,0x08,0x82,0x88,0x23,0xff,0x1f,0x03,0x13,0x3a,0x12,0x64,0x41,0x40,0x31,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const Color boot_splash_bg_color = Color(224/255.0,224/255.0,224/255.0);
diff --git a/makerel.bat b/makerel.bat
deleted file mode 100644
index 7db76e1dd7..0000000000
--- a/makerel.bat
+++ /dev/null
@@ -1 +0,0 @@
-"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" && c:\python27\scons p=windows target=debug_release tools=no
diff --git a/methods.py b/methods.py
index 9608b1b61d..a894973e69 100755
--- a/methods.py
+++ b/methods.py
@@ -1098,6 +1098,8 @@ def update_version():
f.write("#define VERSION_MINOR "+str(version.minor)+"\n")
f.write("#define VERSION_REVISION "+str(rev)+"\n")
f.write("#define VERSION_STATUS "+str(version.status)+"\n")
+ import datetime
+ f.write("#define VERSION_YEAR "+str(datetime.datetime.now().year)+"\n")
def parse_cg_file(fname, uniforms, sizes, conditionals):
@@ -1272,30 +1274,35 @@ def win32_spawn(sh, escape, cmd, args, spawnenv):
return exit_code
"""
-def android_module_source(self,subpath,manifest=""):
- base_path = "../../../modules/"+self.current_module+"/"+subpath
- self.android_source_modules.append(base_path)
+def android_add_maven_repository(self,url):
+ self.android_maven_repos.append(url)
-def android_module_library(self,subpath,manifest=""):
- base_path = ""
- if (os.path.isabs(subpath)):
- base_path=subpath
- else:
- base_path = self.Dir(".").abspath+"/modules/"+self.current_module+"/"+subpath
- self.android_module_libraries.append(base_path)
+def android_add_dependency(self,depline):
+ self.android_dependencies.append(depline)
-def android_module_file(self,file):
- base_path = self.Dir(".").abspath+"/modules/"+self.current_module+"/"+file
- self.android_source_files.append(base_path)
-def android_module_manifest(self,file):
+def android_add_java_dir(self,subpath):
+ base_path = self.Dir(".").abspath+"/modules/"+self.current_module+"/"+subpath
+ self.android_java_dirs.append(base_path)
+
+def android_add_res_dir(self,subpath):
+ base_path = self.Dir(".").abspath+"/modules/"+self.current_module+"/"+subpath
+ self.android_res_dirs.append(base_path)
+def android_add_aidl_dir(self,file):
+ base_path = self.Dir(".").abspath+"/modules/"+self.current_module+"/"+subpath
+ self.android_aidl_dirs.append(base_path)
+def android_add_jni_dir(self,file):
+ base_path = self.Dir(".").abspath+"/modules/"+self.current_module+"/"+subpath
+ self.android_jni_dirs.append(base_path)
+
+def android_add_to_manifest(self,file):
base_path = self.Dir(".").abspath+"/modules/"+self.current_module+"/"+file
f = open(base_path,"rb")
self.android_manifest_chunk+=f.read()
-def android_module_permission(self,file):
+def android_add_to_permissions(self,file):
base_path = self.Dir(".").abspath+"/modules/"+self.current_module+"/"+file
f = open(base_path,"rb")
self.android_permission_chunk+=f.read()
-def android_module_attribute(self,file):
+def android_add_to_attributes(self,file):
base_path = self.Dir(".").abspath+"/modules/"+self.current_module+"/"+file
f = open(base_path,"rb")
self.android_appattributes_chunk+=f.read()
diff --git a/modules/SCsub b/modules/SCsub
index d215f72c08..9215bfd48f 100644
--- a/modules/SCsub
+++ b/modules/SCsub
@@ -19,5 +19,3 @@ for x in env.module_list:
lib = env_modules.Library("modules",env.modules_sources)
env.Prepend(LIBS=[lib])
-
-
diff --git a/modules/gdscript/SCsub b/modules/gdscript/SCsub
index d20da72b72..403fe68f66 100644
--- a/modules/gdscript/SCsub
+++ b/modules/gdscript/SCsub
@@ -3,5 +3,3 @@ Import('env')
env.add_source_files(env.modules_sources,"*.cpp")
Export('env')
-
-
diff --git a/modules/gdscript/gd_compiler.cpp b/modules/gdscript/gd_compiler.cpp
index a62225f663..53519030fc 100644
--- a/modules/gdscript/gd_compiler.cpp
+++ b/modules/gdscript/gd_compiler.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -1156,6 +1156,10 @@ Error GDCompiler::_parse_block(CodeGen& codegen,const GDParser::BlockNode *p_blo
codegen.opcodes.push_back(GDFunction::OPCODE_ASSERT);
codegen.opcodes.push_back(ret);
} break;
+ case GDParser::Node::TYPE_BREAKPOINT: {
+ // try subblocks
+ codegen.opcodes.push_back(GDFunction::OPCODE_BREAKPOINT);
+ } break;
case GDParser::Node::TYPE_LOCAL_VAR: {
@@ -1181,7 +1185,7 @@ Error GDCompiler::_parse_block(CodeGen& codegen,const GDParser::BlockNode *p_blo
}
-Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *p_class,const GDParser::FunctionNode *p_func) {
+Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *p_class,const GDParser::FunctionNode *p_func,bool p_for_ready) {
Vector<int> bytecode;
CodeGen codegen;
@@ -1212,9 +1216,9 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *
/* Parse initializer -if applies- */
- bool is_initializer=false || !p_func;
+ bool is_initializer=!p_for_ready && !p_func;
- if (!p_func || String(p_func->name)=="_init") {
+ if (is_initializer || (p_func && String(p_func->name)=="_init")) {
//parse initializer for class members
if (!p_func && p_class->extends_used && p_script->native.is_null()){
@@ -1232,12 +1236,24 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *
}
+ if (p_for_ready || (p_func && String(p_func->name)=="_ready")) {
+ //parse initializer for class members
+ if (p_class->ready->statements.size()) {
+ Error err = _parse_block(codegen,p_class->ready,stack_level);
+ if (err)
+ return err;
+ }
+
+ }
+
+
/* Parse default argument code -if applies- */
Vector<int> defarg_addr;
StringName func_name;
if (p_func) {
+
if (p_func->default_values.size()) {
codegen.opcodes.push_back(GDFunction::OPCODE_JUMP_TO_DEF_ARGUMENT);
@@ -1260,7 +1276,10 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *
func_name=p_func->name;
} else {
- func_name="_init";
+ if (p_for_ready)
+ func_name="_ready";
+ else
+ func_name="_init";
}
codegen.opcodes.push_back(GDFunction::OPCODE_END);
@@ -1328,7 +1347,7 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *
if (defarg_addr.size()) {
gdfunc->default_arguments=defarg_addr;
- gdfunc->_default_arg_count=defarg_addr.size();
+ gdfunc->_default_arg_count=defarg_addr.size()-1;
gdfunc->_default_arg_ptr=&gdfunc->default_arguments[0];
} else {
gdfunc->_default_arg_count=0;
@@ -1614,10 +1633,14 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars
//parse methods
bool has_initializer=false;
+ bool has_ready=false;
+
for(int i=0;i<p_class->functions.size();i++) {
if (!has_initializer && p_class->functions[i]->name=="_init")
has_initializer=true;
+ if (!has_ready && p_class->functions[i]->name=="_ready")
+ has_ready=true;
Error err = _parse_function(p_script,p_class,p_class->functions[i]);
if (err)
return err;
@@ -1640,6 +1663,13 @@ Error GDCompiler::_parse_class(GDScript *p_script,GDScript *p_owner,const GDPars
return err;
}
+ if (!has_ready && p_class->ready->statements.size()) {
+ //create a constructor
+ Error err = _parse_function(p_script,p_class,NULL,true);
+ if (err)
+ return err;
+ }
+
#ifdef DEBUG_ENABLED
//validate setters/getters if debug is enabled
for(int i=0;i<p_class->variables.size();i++) {
diff --git a/modules/gdscript/gd_compiler.h b/modules/gdscript/gd_compiler.h
index bdf4e9816a..5bf7ec980d 100644
--- a/modules/gdscript/gd_compiler.h
+++ b/modules/gdscript/gd_compiler.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -143,7 +143,7 @@ class GDCompiler {
int _parse_assign_right_expression(CodeGen& codegen,const GDParser::OperatorNode *p_expression, int p_stack_level);
int _parse_expression(CodeGen& codegen,const GDParser::Node *p_expression, int p_stack_level,bool p_root=false,bool p_initializer=false);
Error _parse_block(CodeGen& codegen,const GDParser::BlockNode *p_block,int p_stack_level=0,int p_break_addr=-1,int p_continue_addr=-1);
- Error _parse_function(GDScript *p_script,const GDParser::ClassNode *p_class,const GDParser::FunctionNode *p_func);
+ Error _parse_function(GDScript *p_script,const GDParser::ClassNode *p_class,const GDParser::FunctionNode *p_func,bool p_for_ready=false);
Error _parse_class(GDScript *p_script,GDScript *p_owner,const GDParser::ClassNode *p_class);
int err_line;
int err_column;
diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp
index 0edfd6b9a4..126a8cd1eb 100644
--- a/modules/gdscript/gd_editor.cpp
+++ b/modules/gdscript/gd_editor.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,6 +29,7 @@
#include "gd_script.h"
#include "gd_compiler.h"
#include "globals.h"
+#include "os/file_access.h"
void GDScriptLanguage::get_comment_delimiters(List<String> *p_delimiters) const {
@@ -238,26 +239,26 @@ void GDScriptLanguage::debug_get_stack_level_members(int p_level,List<String> *p
if (_debug_parse_err_line>=0)
return;
- ERR_FAIL_INDEX(p_level,_debug_call_stack_pos);
- int l = _debug_call_stack_pos - p_level -1;
+ ERR_FAIL_INDEX(p_level,_debug_call_stack_pos);
+ int l = _debug_call_stack_pos - p_level -1;
- GDInstance *instance = _call_stack[l].instance;
+ GDInstance *instance = _call_stack[l].instance;
- if (!instance)
- return;
+ if (!instance)
+ return;
- Ref<GDScript> script = instance->get_script();
- ERR_FAIL_COND( script.is_null() );
+ Ref<GDScript> script = instance->get_script();
+ ERR_FAIL_COND( script.is_null() );
- const Map<StringName,GDScript::MemberInfo>& mi = script->debug_get_member_indices();
+ const Map<StringName,GDScript::MemberInfo>& mi = script->debug_get_member_indices();
- for(const Map<StringName,GDScript::MemberInfo>::Element *E=mi.front();E;E=E->next()) {
+ for(const Map<StringName,GDScript::MemberInfo>::Element *E=mi.front();E;E=E->next()) {
- p_members->push_back(E->key());
- p_values->push_back( instance->debug_get_member_by_index(E->get().index));
- }
+ p_members->push_back(E->key());
+ p_values->push_back( instance->debug_get_member_by_index(E->get().index));
+ }
}
void GDScriptLanguage::debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems,int p_max_depth) {
@@ -317,6 +318,7 @@ String GDScriptLanguage::make_function(const String& p_class,const String& p_nam
struct GDCompletionIdentifier {
StringName obj_type;
+ Ref<GDScript> script;
Variant::Type type;
Variant value; //im case there is a value, also return it
};
@@ -381,7 +383,12 @@ static Ref<Reference> _get_parent_class(GDCompletionContext& context) {
path=context.base_path.plus_file(path);
}
- script = ResourceLoader::load(path);
+
+ if (ScriptCodeCompletionCache::get_sigleton())
+ script = ScriptCodeCompletionCache::get_sigleton()->get_cached_resource(path);
+ else
+ script = ResourceLoader::load(path);
+
if (script.is_null()) {
return REF();
}
@@ -441,7 +448,7 @@ static Ref<Reference> _get_parent_class(GDCompletionContext& context) {
base_class=base_class->subclasses[subclass];
} else {
- print_line("Could not find subclass: "+subclass);
+ //print_line("Could not find subclass: "+subclass);
return _get_type_from_class(context); //fail please
}
}
@@ -626,7 +633,9 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser::
//try calling the function if constant and all args are constant, should not crash..
Object *baseptr = base.value;
- if (baseptr && mb->is_const() && pi.type==Variant::OBJECT) {
+
+ if (mb->is_const() && pi.type==Variant::OBJECT) {
+
bool all_valid=true;
Vector<Variant> args;
for(int i=2;i<op->arguments.size();i++) {
@@ -643,25 +652,88 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser::
all_valid=false;
}
}
- if (all_valid) {
- Vector<const Variant*> argptr;
- for(int i=0;i<args.size();i++) {
- argptr.push_back(&args[i]);
- }
- Variant::CallError ce;
- Variant ret=mb->call(baseptr,argptr.ptr(),argptr.size(),ce);
+ if (all_valid && String(id)=="get_node" && ObjectTypeDB::is_type(base.obj_type,"Node") && args.size()) {
+
+ String arg1=args[0];
+ if (arg1.begins_with("/root/")) {
+ String which = arg1.get_slice("/",2);
+ if (which!="") {
+ List<PropertyInfo> props;
+ Globals::get_singleton()->get_property_list(&props);
+ //print_line("find singleton");
+
+ for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) {
+
+ String s = E->get().name;
+ if (!s.begins_with("autoload/"))
+ continue;
+ //print_line("found "+s);
+ String name = s.get_slice("/",1);
+ //print_line("name: "+name+", which: "+which);
+ if (name==which) {
+ String script = Globals::get_singleton()->get(s);
+
+ if (!script.begins_with("res://")) {
+ script="res://"+script;
+ }
+
+ if (!script.ends_with(".gd")) {
+ //not a script, try find the script anyway,
+ //may have some success
+ script=script.basename()+".gd";
+ }
+ if (FileAccess::exists(script)) {
- if (ce.error==Variant::CallError::CALL_OK && ret.get_type()!=Variant::NIL) {
+ //print_line("is a script");
- if (ret.get_type()!=Variant::OBJECT || ret.operator Object*()!=NULL) {
- r_type=_get_type_from_variant(ret);
- return true;
+ Ref<Script> scr;
+ if (ScriptCodeCompletionCache::get_sigleton())
+ scr = ScriptCodeCompletionCache::get_sigleton()->get_cached_resource(script);
+ else
+ scr = ResourceLoader::load(script);
+
+
+ r_type.obj_type="Node";
+ r_type.type=Variant::OBJECT;
+ r_type.script=scr;
+ r_type.value=Variant();
+
+ return true;
+
+ }
+ }
+ }
}
}
+ }
+
+
+
+ if (baseptr) {
+
+ if (all_valid) {
+ Vector<const Variant*> argptr;
+ for(int i=0;i<args.size();i++) {
+ argptr.push_back(&args[i]);
+ }
+
+ Variant::CallError ce;
+ Variant ret=mb->call(baseptr,argptr.ptr(),argptr.size(),ce);
+
+
+ if (ce.error==Variant::CallError::CALL_OK && ret.get_type()!=Variant::NIL) {
+
+ if (ret.get_type()!=Variant::OBJECT || ret.operator Object*()!=NULL) {
+
+ r_type=_get_type_from_variant(ret);
+ return true;
+ }
+ }
+ }
}
}
@@ -926,6 +998,44 @@ static bool _guess_identifier_type_in_block(GDCompletionContext& context,int p_l
return false;
}
+
+static bool _guess_identifier_from_assignment_in_function(GDCompletionContext& context,const StringName& p_identifier, const StringName& p_function,GDCompletionIdentifier &r_type) {
+
+ const GDParser::FunctionNode* func=NULL;
+ for(int i=0;i<context._class->functions.size();i++) {
+ if (context._class->functions[i]->name==p_function) {
+ func=context._class->functions[i];
+ break;
+ }
+ }
+
+ if (!func)
+ return false;
+
+ for(int i=0;i<func->body->statements.size();i++) {
+
+
+
+ if (func->body->statements[i]->type==GDParser::BlockNode::TYPE_OPERATOR) {
+ const GDParser::OperatorNode *op = static_cast<const GDParser::OperatorNode *>(func->body->statements[i]);
+ if (op->op==GDParser::OperatorNode::OP_ASSIGN) {
+
+ if (op->arguments.size() && op->arguments[0]->type==GDParser::Node::TYPE_IDENTIFIER) {
+
+ const GDParser::IdentifierNode *id = static_cast<const GDParser::IdentifierNode *>(op->arguments[0]);
+
+ if (id->name==p_identifier) {
+
+ return _guess_expression_type(context,op->arguments[1],func->body->statements[i]->line,r_type);
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
static bool _guess_identifier_type(GDCompletionContext& context,int p_line,const StringName& p_identifier,GDCompletionIdentifier &r_type) {
//go to block first
@@ -1017,14 +1127,74 @@ static bool _guess_identifier_type(GDCompletionContext& context,int p_line,const
r_type=_get_type_from_pinfo(context._class->variables[i]._export);
return true;
} else if (context._class->variables[i].expression) {
- return _guess_expression_type(context,context._class->variables[i].expression,context._class->variables[i].line,r_type);
+
+ bool rtype = _guess_expression_type(context,context._class->variables[i].expression,context._class->variables[i].line,r_type);
+ if (rtype && r_type.type!=Variant::NIL)
+ return true;
+ //return _guess_expression_type(context,context._class->variables[i].expression,context._class->variables[i].line,r_type);
}
+
+ //try to guess from assignment in construtor or _ready
+ if (_guess_identifier_from_assignment_in_function(context,p_identifier,"_ready",r_type))
+ return true;
+ if (_guess_identifier_from_assignment_in_function(context,p_identifier,"_enter_tree",r_type))
+ return true;
+ if (_guess_identifier_from_assignment_in_function(context,p_identifier,"_init",r_type))
+ return true;
+
+ return false;
}
}
}
+ //autoloads as singletons
+ List<PropertyInfo> props;
+ Globals::get_singleton()->get_property_list(&props);
+
+ for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) {
+ String s = E->get().name;
+ if (!s.begins_with("autoload/"))
+ continue;
+ String name = s.get_slice("/",1);
+ if (name==String(p_identifier)) {
+
+ String path = Globals::get_singleton()->get(s);
+ if (path.begins_with("*")) {
+ String script =path.substr(1,path.length());
+
+ if (!script.ends_with(".gd")) {
+ //not a script, try find the script anyway,
+ //may have some success
+ script=script.basename()+".gd";
+ }
+ if (FileAccess::exists(script)) {
+
+ //print_line("is a script");
+
+
+ Ref<Script> scr;
+ if (ScriptCodeCompletionCache::get_sigleton())
+ scr = ScriptCodeCompletionCache::get_sigleton()->get_cached_resource(script);
+ else
+ scr = ResourceLoader::load(script);
+
+
+ r_type.obj_type="Node";
+ r_type.type=Variant::OBJECT;
+ r_type.script=scr;
+ r_type.value=Variant();
+
+ return true;
+
+ }
+ }
+ }
+
+ }
+
+ //global
for(Map<StringName,int>::Element *E=GDScriptLanguage::get_singleton()->get_global_map().front();E;E=E->next()) {
if (E->key()==p_identifier) {
@@ -1167,6 +1337,15 @@ static void _find_identifiers(GDCompletionContext& context,int p_line,bool p_onl
const GDParser::BlockNode *block=context.block;
+ if (context.function) {
+
+ const GDParser::FunctionNode* f = context.function;
+
+ for (int i=0;i<f->arguments.size();i++) {
+ result.insert(f->arguments[i].operator String());
+ }
+ }
+
while(block) {
GDCompletionContext c = context;
@@ -1203,6 +1382,24 @@ static void _find_identifiers(GDCompletionContext& context,int p_line,bool p_onl
result.insert(_type_names[i]);
}
+ //autoload singletons
+ List<PropertyInfo> props;
+ Globals::get_singleton()->get_property_list(&props);
+
+ for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) {
+
+ String s = E->get().name;
+ if (!s.begins_with("autoload/"))
+ continue;
+ String name = s.get_slice("/",1);
+ String path = Globals::get_singleton()->get(s);
+ if (path.begins_with("*")) {
+ result.insert(name);
+ }
+
+ }
+
+
for(const Map<StringName,int>::Element *E=GDScriptLanguage::get_singleton()->get_global_map().front();E;E=E->next()) {
result.insert(E->key().operator String());
}
@@ -1276,6 +1473,7 @@ static void _make_function_hint(const GDParser::FunctionNode* p_func,int p_argid
static void _find_type_arguments(const GDParser::Node*p_node,int p_line,const StringName& p_method,const GDCompletionIdentifier& id, int p_argidx, Set<String>& result, String& arghint) {
+ //print_line("find type arguments?");
if (id.type==Variant::INPUT_EVENT && String(p_method)=="is_action" && p_argidx==0) {
List<PropertyInfo> pinfo;
@@ -1296,78 +1494,300 @@ static void _find_type_arguments(const GDParser::Node*p_node,int p_line,const St
MethodBind *m = ObjectTypeDB::get_method(id.obj_type,p_method);
- if (!m)
- return;
+ if (!m) {
+ //not in static method, see script
+
+ //print_line("not in static: "+String(p_method));
+ Ref<GDScript> on_script;
+
+ if (id.value.get_type()) {
+ Object *obj=id.value;
+
+
+ if (obj) {
+
+
+ GDScript *scr = obj->cast_to<GDScript>();
+ if (scr) {
+ while (scr) {
+
+ for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) {
+ if (E->get().is_static() && p_method==E->get().get_name()) {
+ arghint="static func "+String(p_method)+"(";
+ for(int i=0;i<E->get().get_argument_count();i++) {
+ if (i>0)
+ arghint+=", ";
+ else
+ arghint+=" ";
+ if (i==p_argidx) {
+ arghint+=String::chr(0xFFFF);
+ }
+ arghint+="var "+E->get().get_argument_name(i);
+ int deffrom = E->get().get_argument_count()-E->get().get_default_argument_count();
+ if (i>=deffrom) {
+ int defidx = deffrom-i;
+ if (defidx>=0 && defidx<E->get().get_default_argument_count()) {
+ arghint+="="+E->get().get_default_argument(defidx).get_construct_string();
+ }
+ }
+ if (i==p_argidx) {
+ arghint+=String::chr(0xFFFF);
+ }
+ }
+ arghint+=")";
+ return; //found
+ }
+ }
- if (p_method.operator String()=="connect") {
+ if (scr->get_base().is_valid())
+ scr=scr->get_base().ptr();
+ else
+ scr=NULL;
+ }
+ } else {
+ on_script=obj->get_script();
+ }
+ }
+ }
+
+ //print_line("but it has a script?");
+ if (!on_script.is_valid() && id.script.is_valid()) {
+ //print_line("yes");
+ on_script=id.script;
+ }
+
+ if (on_script.is_valid()) {
+
+ GDScript *scr = on_script.ptr();
+ if (scr) {
+ while (scr) {
+
+ String code = scr->get_source_code();
+ //print_line("has source code!");
+
+ if (code!="") {
+ //if there is code, parse it. This way is slower but updates in real-time
+ GDParser p;
+ //Error parse(const String& p_code, const String& p_base_path="", bool p_just_validate=false,const String& p_self_path="",bool p_for_completion=false);
+
+ Error err = p.parse(scr->get_source_code(),scr->get_path().get_base_dir(),true,"",false);
+
+ if (err==OK) {
+ //print_line("checking the functions...");
+ //only if ok, otherwise use what is cached on the script
+ //GDParser::ClassNode *base = p.
+ const GDParser::Node *root = p.get_parse_tree();
+ ERR_FAIL_COND(root->type!=GDParser::Node::TYPE_CLASS);
+
+ const GDParser::ClassNode *cl = static_cast<const GDParser::ClassNode*>(root);
+
+ const GDParser::FunctionNode* func=NULL;
+ bool st=false;
+
+ for(int i=0;i<cl->functions.size();i++) {
+ //print_line(String(cl->functions[i]->name)+" vs "+String(p_method));
+ if (cl->functions[i]->name==p_method) {
+ func=cl->functions[i];
+ }
+ }
+ for(int i=0;i<cl->static_functions.size();i++) {
- if (p_argidx==0) {
- List<MethodInfo> sigs;
- ObjectTypeDB::get_signal_list(id.obj_type,&sigs);
- for (List<MethodInfo>::Element *E=sigs.front();E;E=E->next()) {
- result.insert("\""+E->get().name+"\"");
+ //print_line(String(cl->static_functions[i]->name)+" vs "+String(p_method));
+ if (cl->static_functions[i]->name==p_method) {
+ func=cl->static_functions[i];
+ st=true;
+ }
+
+ }
+
+ if (func) {
+
+ arghint="func "+String(p_method)+"(";
+ if (st)
+ arghint="static "+arghint;
+ for(int i=0;i<func->arguments.size();i++) {
+ if (i>0)
+ arghint+=", ";
+ else
+ arghint+=" ";
+ if (i==p_argidx) {
+ arghint+=String::chr(0xFFFF);
+ }
+ arghint+="var "+String(func->arguments[i]);
+ int deffrom = func->arguments.size()-func->default_values.size();
+ if (i>=deffrom) {
+
+ int defidx = deffrom-i;
+
+ if (defidx>=0 && defidx<func->default_values.size() && func->default_values[defidx]->type==GDParser::Node::TYPE_OPERATOR) {
+ const GDParser::OperatorNode *op=static_cast<const GDParser::OperatorNode *>(func->default_values[defidx]);
+ if (op->op==GDParser::OperatorNode::OP_ASSIGN) {
+ const GDParser::ConstantNode *cn=static_cast<const GDParser::ConstantNode *>(op->arguments[1]);
+ arghint+="="+cn->value.get_construct_string();
+ }
+ }
+ }
+ if (i==p_argidx) {
+ arghint+=String::chr(0xFFFF);
+ }
+ }
+
+ arghint+=" )";
+ return;
+ }
+ } else {
+ //print_line("failed parsing?");
+ code="";
+ }
+
+ }
+
+ if (code=="") {
+
+ for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) {
+ if (p_method==E->get().get_name()) {
+ arghint="func "+String(p_method)+"(";
+ for(int i=0;i<E->get().get_argument_count();i++) {
+ if (i>0)
+ arghint+=", ";
+ else
+ arghint+=" ";
+ if (i==p_argidx) {
+ arghint+=String::chr(0xFFFF);
+ }
+ arghint+="var "+E->get().get_argument_name(i);
+ int deffrom = E->get().get_argument_count()-E->get().get_default_argument_count();
+ if (i>=deffrom) {
+ int defidx = deffrom-i;
+ if (defidx>=0 && defidx<E->get().get_default_argument_count()) {
+ arghint+="="+E->get().get_default_argument(defidx).get_construct_string();
+ }
+ }
+ if (i==p_argidx) {
+ arghint+=String::chr(0xFFFF);
+ }
+ }
+ arghint+=")";
+ return; //found
+ }
+ }
+#if 0
+ //use class directly, no code was found
+ if (!isfunction) {
+ for (const Map<StringName,Variant>::Element *E=scr->get_constants().front();E;E=E->next()) {
+ options.insert(E->key());
+ }
+ }
+ for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) {
+ options.insert(String(E->key())+"(");
+ }
+
+ for (const Set<StringName>::Element *E=scr->get_members().front();E;E=E->next()) {
+ options.insert(E->get());
+ }
+#endif
+ }
+
+ if (scr->get_base().is_valid())
+ scr=scr->get_base().ptr();
+ else
+ scr=NULL;
+ }
}
}
- /*if (p_argidx==2) {
- ERR_FAIL_COND(p_node->type!=GDParser::Node::TYPE_OPERATOR);
- const GDParser::OperatorNode *op=static_cast<const GDParser::OperatorNode *>(p_node);
- if (op->arguments.size()>)
- }*/
} else {
+ //regular method
- Object *obj=id.value;
- if (obj) {
- List<String> options;
- obj->get_argument_options(p_method,p_argidx,&options);
- for(List<String>::Element *E=options.front();E;E=E->next()) {
+ if (p_method.operator String()=="connect") {
- result.insert(E->get());
+
+ if (p_argidx==0) {
+ List<MethodInfo> sigs;
+ ObjectTypeDB::get_signal_list(id.obj_type,&sigs);
+ for (List<MethodInfo>::Element *E=sigs.front();E;E=E->next()) {
+ result.insert("\""+E->get().name+"\"");
+ }
}
- }
+ /*if (p_argidx==2) {
- }
+ ERR_FAIL_COND(p_node->type!=GDParser::Node::TYPE_OPERATOR);
+ const GDParser::OperatorNode *op=static_cast<const GDParser::OperatorNode *>(p_node);
+ if (op->arguments.size()>)
- arghint = _get_visual_datatype(m->get_argument_info(-1),false)+" "+p_method.operator String()+String("(");
+ }*/
+ } else {
- for(int i=0;i<m->get_argument_count();i++) {
- if (i>0)
- arghint+=", ";
- else
- arghint+=" ";
+ if (p_argidx==0 && (String(p_method)=="get_node" || String(p_method)=="has_node") && ObjectTypeDB::is_type(id.obj_type,"Node")) {
- if (i==p_argidx) {
- arghint+=String::chr(0xFFFF);
- }
- String n = m->get_argument_info(i).name;
- int dp = n.find(":");
- if (dp!=-1)
- n=n.substr(0,dp);
- arghint+=_get_visual_datatype(m->get_argument_info(i))+" "+n;
- int deffrom = m->get_argument_count()-m->get_default_argument_count();
+ List<PropertyInfo> props;
+ Globals::get_singleton()->get_property_list(&props);
+ for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) {
- if (i>=deffrom) {
- int defidx = i-deffrom;
+ String s = E->get().name;
+ if (!s.begins_with("autoload/"))
+ continue;
+ // print_line("found "+s);
+ String name = s.get_slice("/",1);
+ result.insert("\"/root/"+name+"\"");
+ }
+ }
+
+ Object *obj=id.value;
+ if (obj) {
+ List<String> options;
+ obj->get_argument_options(p_method,p_argidx,&options);
- if (defidx>=0 && defidx<m->get_default_argument_count()) {
- Variant v= m->get_default_argument(i);
- arghint+="="+v.get_construct_string();
+ for(List<String>::Element *E=options.front();E;E=E->next()) {
+
+ result.insert(E->get());
+ }
}
- }
- if (i==p_argidx) {
- arghint+=String::chr(0xFFFF);
}
- }
- if (m->get_argument_count()>0)
- arghint+=" ";
+ arghint = _get_visual_datatype(m->get_argument_info(-1),false)+" "+p_method.operator String()+String("(");
+ for(int i=0;i<m->get_argument_count();i++) {
+ if (i>0)
+ arghint+=", ";
+ else
+ arghint+=" ";
+
+ if (i==p_argidx) {
+ arghint+=String::chr(0xFFFF);
+ }
+ String n = m->get_argument_info(i).name;
+ int dp = n.find(":");
+ if (dp!=-1)
+ n=n.substr(0,dp);
+ arghint+=_get_visual_datatype(m->get_argument_info(i))+" "+n;
+ int deffrom = m->get_argument_count()-m->get_default_argument_count();
- arghint+=")";
+
+ if (i>=deffrom) {
+ int defidx = i-deffrom;
+
+ if (defidx>=0 && defidx<m->get_default_argument_count()) {
+ Variant v= m->get_default_argument(i);
+ arghint+="="+v.get_construct_string();
+ }
+ }
+
+ if (i==p_argidx) {
+ arghint+=String::chr(0xFFFF);
+ }
+
+ }
+ if (m->get_argument_count()>0)
+ arghint+=" ";
+
+
+ arghint+=")";
+ }
}
}
@@ -1414,7 +1834,7 @@ static void _find_call_arguments(GDCompletionContext& context,const GDParser::No
arghint+=")";
} else if (op->arguments[0]->type==GDParser::Node::TYPE_TYPE) {
- //complete built-in function
+ //complete constructor
const GDParser::TypeNode *tn = static_cast<const GDParser::TypeNode*>(op->arguments[0]);
List<MethodInfo> mil;
@@ -1549,7 +1969,7 @@ static void _find_call_arguments(GDCompletionContext& context,const GDParser::No
}
} else {
-
+ //indexed lookup
GDCompletionIdentifier ci;
if (_guess_expression_type(context,op->arguments[0],p_line,ci)) {
@@ -1661,7 +2081,9 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base
//print_line( p_code.replace(String::chr(0xFFFF),"<cursor>"));
GDParser p;
- Error err = p.parse(p_code,p_base_path,true);
+ //Error parse(const String& p_code, const String& p_base_path="", bool p_just_validate=false,const String& p_self_path="",bool p_for_completion=false);
+
+ Error err = p.parse(p_code,p_base_path,false,"",true);
bool isfunction=false;
Set<String> options;
@@ -1713,20 +2135,123 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base
if (t.type==Variant::OBJECT && t.obj_type!=StringName()) {
+ Ref<GDScript> on_script;
if (t.value.get_type()) {
Object *obj=t.value;
+
+
if (obj) {
+
+
GDScript *scr = obj->cast_to<GDScript>();
+ if (scr) {
+ while (scr) {
+
+ if (!isfunction) {
+ for (const Map<StringName,Variant>::Element *E=scr->get_constants().front();E;E=E->next()) {
+ options.insert(E->key());
+ }
+ }
+ for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) {
+ if (E->get().is_static())
+ options.insert(E->key());
+ }
+
+ if (scr->get_base().is_valid())
+ scr=scr->get_base().ptr();
+ else
+ scr=NULL;
+ }
+ } else {
+ on_script=obj->get_script();
+ }
+ }
+ }
+
+
+ if (!on_script.is_valid() && t.script.is_valid()) {
+ on_script=t.script;
+ }
+
+ if (on_script.is_valid()) {
+
+ GDScript *scr = on_script.ptr();
+ if (scr) {
while (scr) {
- if (!isfunction) {
- for (const Map<StringName,Variant>::Element *E=scr->get_constants().front();E;E=E->next()) {
- options.insert(E->key());
+ String code = scr->get_source_code();
+
+ if (code!="") {
+ //if there is code, parse it. This way is slower but updates in real-time
+ GDParser p;
+ //Error parse(const String& p_code, const String& p_base_path="", bool p_just_validate=false,const String& p_self_path="",bool p_for_completion=false);
+
+ Error err = p.parse(scr->get_source_code(),scr->get_path().get_base_dir(),true,"",false);
+
+ if (err==OK) {
+ //only if ok, otherwise use what is cached on the script
+ //GDParser::ClassNode *base = p.
+ const GDParser::Node *root = p.get_parse_tree();
+ ERR_FAIL_COND_V(root->type!=GDParser::Node::TYPE_CLASS,ERR_PARSE_ERROR);
+
+ const GDParser::ClassNode *cl = static_cast<const GDParser::ClassNode*>(root);
+
+ for(int i=0;i<cl->functions.size();i++) {
+
+ if (cl->functions[i]->arguments.size())
+ options.insert(String(cl->functions[i]->name)+"(");
+ else
+ options.insert(String(cl->functions[i]->name)+"()");
+ }
+
+ for(int i=0;i<cl->static_functions.size();i++) {
+
+ if (cl->static_functions[i]->arguments.size())
+ options.insert(String(cl->static_functions[i]->name)+"(");
+ else
+ options.insert(String(cl->static_functions[i]->name)+"()");
+
+ }
+
+ if (!isfunction) {
+ for(int i=0;i<cl->variables.size();i++) {
+
+ options.insert(String(cl->variables[i].identifier));
+ }
+
+ for(int i=0;i<cl->constant_expressions.size();i++) {
+
+ options.insert(String(cl->constant_expressions[i].identifier));
+ }
+
+ }
+
+
+ } else {
+ code=""; //well, then no code
}
+
}
- for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) {
- options.insert(E->key());
+
+ if (code=="") {
+ //use class directly, no code was found
+ if (!isfunction) {
+ for (const Map<StringName,Variant>::Element *E=scr->get_constants().front();E;E=E->next()) {
+ options.insert(E->key());
+ }
+ }
+ for (const Map<StringName,GDFunction>::Element *E=scr->get_member_functions().front();E;E=E->next()) {
+ if (E->get().get_argument_count())
+ options.insert(String(E->key())+"()");
+ else
+ options.insert(String(E->key())+"(");
+
+ }
+
+ for (const Set<StringName>::Element *E=scr->get_members().front();E;E=E->next()) {
+ options.insert(E->get());
+ }
}
if (scr->get_base().is_valid())
@@ -1738,6 +2263,10 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base
}
+
+
+
+
if (!isfunction) {
ObjectTypeDB::get_integer_constant_list(t.obj_type,r_options);
}
diff --git a/modules/gdscript/gd_functions.cpp b/modules/gdscript/gd_functions.cpp
index 37ddb2bc41..e015ddb65e 100644
--- a/modules/gdscript/gd_functions.cpp
+++ b/modules/gdscript/gd_functions.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,6 +33,8 @@
#include "gd_script.h"
#include "func_ref.h"
#include "os/os.h"
+#include "variant_parser.h"
+#include "io/marshalls.h"
const char *GDFunctions::get_func_name(Function p_func) {
@@ -93,11 +95,14 @@ const char *GDFunctions::get_func_name(Function p_func) {
"printraw",
"var2str",
"str2var",
+ "var2bytes",
+ "bytes2var",
"range",
"load",
"inst2dict",
"dict2inst",
"hash",
+ "Color8",
"print_stack",
"instance_from_id",
};
@@ -524,6 +529,7 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
for(int i=0;i<p_arg_count;i++) {
String os = p_args[i]->operator String();;
+
if (i==0)
str=os;
else
@@ -607,7 +613,9 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
} break;
case VAR_TO_STR: {
VALIDATE_ARG_COUNT(1);
- r_ret=p_args[0]->get_construct_string();
+ String vars;
+ VariantWriter::write_to_string(*p_args[0],vars);
+ r_ret=vars;
} break;
case STR_TO_VAR: {
VALIDATE_ARG_COUNT(1);
@@ -618,7 +626,72 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
r_ret=Variant();
return;
}
- Variant::construct_from_string(*p_args[0],r_ret);
+
+ VariantParser::StreamString ss;
+ ss.s=*p_args[0];
+
+ String errs;
+ int line;
+ Error err = VariantParser::parse(&ss,r_ret,errs,line);
+
+ if (err!=OK) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=0;
+ r_error.expected=Variant::STRING;
+ r_ret=Variant();
+ }
+
+ } break;
+ case VAR_TO_BYTES: {
+ VALIDATE_ARG_COUNT(1);
+
+ ByteArray barr;
+ int len;
+ Error err = encode_variant(*p_args[0],NULL,len);
+ if (err) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=0;
+ r_error.expected=Variant::NIL;
+ r_ret=Variant();
+ return;
+ }
+
+ barr.resize(len);
+ {
+ ByteArray::Write w = barr.write();
+ encode_variant(*p_args[0],w.ptr(),len);
+
+ }
+ r_ret=barr;
+ } break;
+ case BYTES_TO_VAR: {
+ VALIDATE_ARG_COUNT(1);
+ if (p_args[0]->get_type()!=Variant::RAW_ARRAY) {
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=0;
+ r_error.expected=Variant::RAW_ARRAY;
+ r_ret=Variant();
+ return;
+ }
+
+ ByteArray varr=*p_args[0];
+ Variant ret;
+ {
+ ByteArray::Read r=varr.read();
+ Error err = decode_variant(ret,r.ptr(),varr.size(),NULL);
+ if (err!=OK) {
+ ERR_PRINT("Not enough bytes for decoding..");
+ r_error.error=Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
+ r_error.argument=0;
+ r_error.expected=Variant::RAW_ARRAY;
+ r_ret=Variant();
+ return;
+ }
+
+ }
+
+ r_ret=ret;
+
} break;
case GEN_RANGE: {
@@ -904,6 +977,15 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
r_ret = gdscr->_new(NULL,0,r_error);
+ GDInstance *ins = static_cast<GDInstance*>(static_cast<Object*>(r_ret)->get_script_instance());
+ Ref<GDScript> gd_ref = ins->get_script();
+
+ for(Map<StringName,GDScript::MemberInfo>::Element *E = gd_ref->member_indices.front(); E; E = E->next()) {
+ if(d.has(E->key())) {
+ ins->members[E->get().index] = d[E->key()];
+ }
+ }
+
} break;
case HASH: {
@@ -911,6 +993,33 @@ void GDFunctions::call(Function p_func,const Variant **p_args,int p_arg_count,Va
r_ret=p_args[0]->hash();
} break;
+ case COLOR8: {
+
+ if (p_arg_count<3) {
+ r_error.error=Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
+ r_error.argument=3;
+ return;
+ }
+ if (p_arg_count>4) {
+ r_error.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
+ r_error.argument=4;
+ return;
+ }
+
+ VALIDATE_ARG_NUM(0);
+ VALIDATE_ARG_NUM(1);
+ VALIDATE_ARG_NUM(2);
+
+ Color color(*p_args[0],*p_args[1],*p_args[2]);
+
+ if (p_arg_count==4) {
+ VALIDATE_ARG_NUM(3);
+ color.a=*p_args[3];
+ }
+
+ r_ret=color;
+
+ } break;
case PRINT_STACK: {
@@ -990,6 +1099,7 @@ bool GDFunctions::is_deterministic(Function p_func) {
case TYPE_CONVERT:
case TYPE_OF:
case TEXT_STR:
+ case COLOR8:
// enable for debug only, otherwise not desirable - case GEN_RANGE:
return true;
default:
@@ -1298,7 +1408,19 @@ MethodInfo GDFunctions::get_info(Function p_func) {
} break;
case STR_TO_VAR: {
- MethodInfo mi("str2var:var",PropertyInfo(Variant::STRING,"string"));
+ MethodInfo mi("str2var:Variant",PropertyInfo(Variant::STRING,"string"));
+ mi.return_val.type=Variant::NIL;
+ return mi;
+ } break;
+ case VAR_TO_BYTES: {
+ MethodInfo mi("var2bytes",PropertyInfo(Variant::NIL,"var"));
+ mi.return_val.type=Variant::RAW_ARRAY;
+ return mi;
+
+ } break;
+ case BYTES_TO_VAR: {
+
+ MethodInfo mi("bytes2var:Variant",PropertyInfo(Variant::RAW_ARRAY,"bytes"));
mi.return_val.type=Variant::NIL;
return mi;
} break;
@@ -1329,10 +1451,16 @@ MethodInfo GDFunctions::get_info(Function p_func) {
} break;
case HASH: {
- MethodInfo mi("hash",PropertyInfo(Variant::NIL,"var:var"));
+ MethodInfo mi("hash",PropertyInfo(Variant::NIL,"var:Variant"));
mi.return_val.type=Variant::INT;
return mi;
} break;
+ case COLOR8: {
+
+ MethodInfo mi("Color8",PropertyInfo(Variant::INT,"r8"),PropertyInfo(Variant::INT,"g8"),PropertyInfo(Variant::INT,"b8"),PropertyInfo(Variant::INT,"a8"));
+ mi.return_val.type=Variant::COLOR;
+ return mi;
+ } break;
case PRINT_STACK: {
MethodInfo mi("print_stack");
diff --git a/modules/gdscript/gd_functions.h b/modules/gdscript/gd_functions.h
index ad35a628d5..8c88472567 100644
--- a/modules/gdscript/gd_functions.h
+++ b/modules/gdscript/gd_functions.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -89,11 +89,14 @@ public:
TEXT_PRINTRAW,
VAR_TO_STR,
STR_TO_VAR,
+ VAR_TO_BYTES,
+ BYTES_TO_VAR,
GEN_RANGE,
RESOURCE_LOAD,
INST2DICT,
DICT2INST,
HASH,
+ COLOR8,
PRINT_STACK,
INSTANCE_FROM_ID,
FUNC_MAX
diff --git a/modules/gdscript/gd_parser.cpp b/modules/gdscript/gd_parser.cpp
index 71af9ab10d..c4175e048d 100644
--- a/modules/gdscript/gd_parser.cpp
+++ b/modules/gdscript/gd_parser.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,6 +30,7 @@
#include "print_string.h"
#include "io/resource_loader.h"
#include "os/file_access.h"
+#include "script_language.h"
template<class T>
T* GDParser::alloc_node() {
@@ -64,28 +65,38 @@ bool GDParser::_enter_indent_block(BlockNode* p_block) {
if (tokenizer->get_token()!=GDTokenizer::TK_COLON) {
-
- _set_error("':' expected at end of line.");
+ // report location at the previous token (on the previous line)
+ int error_line = tokenizer->get_token_line(-1);
+ int error_column = tokenizer->get_token_column(-1);
+ _set_error("':' expected at end of line.",error_line,error_column);
return false;
}
tokenizer->advance();
if (tokenizer->get_token()!=GDTokenizer::TK_NEWLINE) {
- _set_error("newline expected after ':'.");
- return false;
+ // be more python-like
+ int current = tab_level.back()->get();
+ tab_level.push_back(current+1);
+ return true;
+ //_set_error("newline expected after ':'.");
+ //return false;
}
while(true) {
if (tokenizer->get_token()!=GDTokenizer::TK_NEWLINE) {
+ print_line("no newline");
return false; //wtf
} else if (tokenizer->get_token(1)!=GDTokenizer::TK_NEWLINE) {
int indent = tokenizer->get_token_line_indent();
int current = tab_level.back()->get();
- if (indent<=current)
+ if (indent<=current) {
+ print_line("current: "+itos(current)+" indent: "+itos(indent));
+ print_line("less than current");
return false;
+ }
tab_level.push_back(indent);
tokenizer->advance();
@@ -116,6 +127,14 @@ bool GDParser::_parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_stat
if (tokenizer->get_token()==GDTokenizer::TK_CURSOR) {
_make_completable_call(argidx);
completion_node=p_parent;
+ } else if (tokenizer->get_token()==GDTokenizer::TK_CONSTANT && tokenizer->get_token_constant().get_type()==Variant::STRING && tokenizer->get_token(1)==GDTokenizer::TK_CURSOR) {
+ //completing a string argument..
+ completion_cursor=tokenizer->get_token_constant();
+
+ _make_completable_call(argidx);
+ completion_node=p_parent;
+ tokenizer->advance(1);
+ return false;
}
Node*arg = _parse_expression(p_parent,p_static);
@@ -161,6 +180,7 @@ void GDParser::_make_completable_call(int p_arg) {
completion_line=tokenizer->get_token_line();
completion_argument=p_arg;
completion_block=current_block;
+ completion_found=true;
tokenizer->advance();
}
@@ -181,6 +201,7 @@ bool GDParser::_get_completable_identifier(CompletionType p_type,StringName& ide
completion_function=current_function;
completion_line=tokenizer->get_token_line();
completion_block=current_block;
+ completion_found=true;
tokenizer->advance();
if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER) {
@@ -246,6 +267,13 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
constant->value=tokenizer->get_token_constant();
tokenizer->advance();
expr=constant;
+ } else if (tokenizer->get_token()==GDTokenizer::TK_CONST_PI) {
+
+ //constant defined by tokenizer
+ ConstantNode *constant = alloc_node<ConstantNode>();
+ constant->value=Math_PI;
+ tokenizer->advance();
+ expr=constant;
} else if (tokenizer->get_token()==GDTokenizer::TK_PR_PRELOAD) {
//constant defined by tokenizer
@@ -277,7 +305,11 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
if (!validating) {
//this can be too slow for just validating code
- res = ResourceLoader::load(path);
+ if (for_completion && ScriptCodeCompletionCache::get_sigleton()) {
+ res = ScriptCodeCompletionCache::get_sigleton()->get_cached_resource(path);
+ } else {
+ res = ResourceLoader::load(path);
+ }
if (!res.is_valid()) {
_set_error("Can't preload resource at path: "+path);
return NULL;
@@ -1401,6 +1433,24 @@ GDParser::Node* GDParser::_parse_and_reduce_expression(Node *p_parent,bool p_sta
return expr;
}
+bool GDParser::_recover_from_completion() {
+
+ if (!completion_found) {
+ return false; //can't recover if no completion
+ }
+ //skip stuff until newline
+ while(tokenizer->get_token()!=GDTokenizer::TK_NEWLINE && tokenizer->get_token()!=GDTokenizer::TK_EOF && tokenizer->get_token()!=GDTokenizer::TK_ERROR) {
+ tokenizer->advance();
+ }
+ completion_found=false;
+ error_set=false;
+ if(tokenizer->get_token() == GDTokenizer::TK_ERROR){
+ error_set = true;
+ }
+
+ return true;
+}
+
void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
int indent_level = tab_level.back()->get();
@@ -1498,8 +1548,14 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
Node *subexpr=NULL;
subexpr = _parse_and_reduce_expression(p_block,p_static);
- if (!subexpr)
+ if (!subexpr) {
+ if (_recover_from_completion()) {
+ break;
+ }
return;
+ }
+
+
lv->assign=subexpr;
assigned=subexpr;
@@ -1530,8 +1586,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
tokenizer->advance();
Node *condition = _parse_and_reduce_expression(p_block,p_static);
- if (!condition)
+ if (!condition) {
+ if (_recover_from_completion()) {
+ break;
+ }
return;
+ }
ControlFlowNode *cf_if = alloc_node<ControlFlowNode>();
@@ -1543,6 +1603,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
p_block->sub_blocks.push_back(cf_if->body);
if (!_enter_indent_block(cf_if->body)) {
+ _set_error("Expected intended block after 'if'");
p_block->end_line=tokenizer->get_token_line();
return;
}
@@ -1585,8 +1646,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
//condition
Node *condition = _parse_and_reduce_expression(p_block,p_static);
- if (!condition)
+ if (!condition) {
+ if (_recover_from_completion()) {
+ break;
+ }
return;
+ }
cf_else->arguments.push_back(condition);
cf_else->cf_type=ControlFlowNode::CF_IF;
@@ -1598,6 +1663,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
if (!_enter_indent_block(cf_if->body)) {
+ _set_error("Expected indented block after 'elif'");
p_block->end_line=tokenizer->get_token_line();
return;
}
@@ -1612,7 +1678,6 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
} else if (tokenizer->get_token()==GDTokenizer::TK_CF_ELSE) {
if (tab_level.back()->get() > indent_level) {
-
_set_error("Invalid indent");
return;
}
@@ -1624,6 +1689,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
p_block->sub_blocks.push_back(cf_if->body_else);
if (!_enter_indent_block(cf_if->body_else)) {
+ _set_error("Expected indented block after 'else'");
p_block->end_line=tokenizer->get_token_line();
return;
}
@@ -1647,8 +1713,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
tokenizer->advance();
Node *condition = _parse_and_reduce_expression(p_block,p_static);
- if (!condition)
+ if (!condition) {
+ if (_recover_from_completion()) {
+ break;
+ }
return;
+ }
ControlFlowNode *cf_while = alloc_node<ControlFlowNode>();
@@ -1660,6 +1730,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
p_block->sub_blocks.push_back(cf_while->body);
if (!_enter_indent_block(cf_while->body)) {
+ _set_error("Expected indented block after 'while'");
p_block->end_line=tokenizer->get_token_line();
return;
}
@@ -1693,8 +1764,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
tokenizer->advance();
Node *container = _parse_and_reduce_expression(p_block,p_static);
- if (!container)
+ if (!container) {
+ if (_recover_from_completion()) {
+ break;
+ }
return;
+ }
ControlFlowNode *cf_for = alloc_node<ControlFlowNode>();
@@ -1707,6 +1782,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
p_block->sub_blocks.push_back(cf_for->body);
if (!_enter_indent_block(cf_for->body)) {
+ _set_error("Expected indented block after 'while'");
p_block->end_line=tokenizer->get_token_line();
return;
}
@@ -1758,8 +1834,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
} else {
//expect expression
Node *retexpr = _parse_and_reduce_expression(p_block,p_static);
- if (!retexpr)
+ if (!retexpr) {
+ if (_recover_from_completion()) {
+ break;
+ }
return;
+ }
cf_return->arguments.push_back(retexpr);
p_block->statements.push_back(cf_return);
if (!_end_statement()) {
@@ -1774,8 +1854,12 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
tokenizer->advance();
Node *condition = _parse_and_reduce_expression(p_block,p_static);
- if (!condition)
+ if (!condition) {
+ if (_recover_from_completion()) {
+ break;
+ }
return;
+ }
AssertNode *an = alloc_node<AssertNode>();
an->condition=condition;
p_block->statements.push_back(an);
@@ -1785,11 +1869,26 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
return;
}
} break;
+ case GDTokenizer::TK_PR_BREAKPOINT: {
+
+ tokenizer->advance();
+ BreakpointNode *bn = alloc_node<BreakpointNode>();
+ p_block->statements.push_back(bn);
+
+ if (!_end_statement()) {
+ _set_error("Expected end of statement after breakpoint.");
+ return;
+ }
+ } break;
default: {
Node *expression = _parse_and_reduce_expression(p_block,p_static,false,true);
- if (!expression)
+ if (!expression) {
+ if (_recover_from_completion()) {
+ break;
+ }
return;
+ }
p_block->statements.push_back(expression);
if (!_end_statement()) {
_set_error("Expected end of statement after expression.");
@@ -1873,9 +1972,15 @@ void GDParser::_parse_extends(ClassNode *p_class) {
p_class->extends_used=true;
- //see if inheritance happens from a file
tokenizer->advance();
+ if (tokenizer->get_token()==GDTokenizer::TK_BUILT_IN_TYPE && tokenizer->get_token_type()==Variant::OBJECT) {
+ p_class->extends_class.push_back(Variant::get_type_name(Variant::OBJECT));
+ tokenizer->advance();
+ return;
+ }
+
+ // see if inheritance happens from a file
if (tokenizer->get_token()==GDTokenizer::TK_CONSTANT) {
Variant constant = tokenizer->get_token_constant();
@@ -1983,6 +2088,8 @@ void GDParser::_parse_class(ClassNode *p_class) {
ClassNode *newclass = alloc_node<ClassNode>();
newclass->initializer = alloc_node<BlockNode>();
newclass->initializer->parent_class=newclass;
+ newclass->ready = alloc_node<BlockNode>();
+ newclass->ready->parent_class=newclass;
newclass->name=name;
newclass->owner=p_class;
@@ -2302,6 +2409,55 @@ void GDParser::_parse_class(ClassNode *p_class) {
case Variant::INT: {
+ if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier()=="FLAGS") {
+
+ current_export.hint=PROPERTY_HINT_ALL_FLAGS;
+ tokenizer->advance();
+
+ if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) {
+ break;
+ }
+ if (tokenizer->get_token()!=GDTokenizer::TK_COMMA)
+ {
+ _set_error("Expected ')' or ',' in bit flags hint.");
+ return;
+ }
+
+ current_export.hint=PROPERTY_HINT_FLAGS;
+ tokenizer->advance();
+
+ bool first = true;
+ while(true) {
+
+ if (tokenizer->get_token()!=GDTokenizer::TK_CONSTANT || tokenizer->get_token_constant().get_type()!=Variant::STRING) {
+ current_export=PropertyInfo();
+ _set_error("Expected a string constant in named bit flags hint.");
+ return;
+ }
+
+ String c = tokenizer->get_token_constant();
+ if (!first)
+ current_export.hint_string+=",";
+ else
+ first=false;
+
+ current_export.hint_string+=c.xml_escape();
+
+ tokenizer->advance();
+ if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE)
+ break;
+
+ if (tokenizer->get_token()!=GDTokenizer::TK_COMMA) {
+ current_export=PropertyInfo();
+ _set_error("Expected ')' or ',' in named bit flags hint.");
+ return;
+ }
+ tokenizer->advance();
+ }
+
+ break;
+ }
+
if (tokenizer->get_token()==GDTokenizer::TK_CONSTANT && tokenizer->get_token_constant().get_type()==Variant::STRING) {
//enumeration
current_export.hint=PROPERTY_HINT_ENUM;
@@ -2343,6 +2499,33 @@ void GDParser::_parse_class(ClassNode *p_class) {
}; //fallthrough to use the same
case Variant::REAL: {
+ if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier()=="EASE") {
+ current_export.hint=PROPERTY_HINT_EXP_EASING;
+ tokenizer->advance();
+ if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) {
+ _set_error("Expected ')' in hint.");
+ return;
+ }
+ break;
+ }
+
+ // range
+ if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier()=="EXP") {
+
+ current_export.hint=PROPERTY_HINT_EXP_RANGE;
+ tokenizer->advance();
+
+ if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE)
+ break;
+ else if (tokenizer->get_token()!=GDTokenizer::TK_COMMA) {
+ _set_error("Expected ')' or ',' in exponential range hint.");
+ return;
+ }
+ tokenizer->advance();
+ }
+ else
+ current_export.hint=PROPERTY_HINT_RANGE;
+
float sign=1.0;
if (tokenizer->get_token()==GDTokenizer::TK_OP_SUB) {
@@ -2356,8 +2539,6 @@ void GDParser::_parse_class(ClassNode *p_class) {
return;
}
- //enumeration
- current_export.hint=PROPERTY_HINT_RANGE;
current_export.hint_string=rtos(sign*double(tokenizer->get_token_constant()));
tokenizer->advance();
@@ -2460,10 +2641,32 @@ void GDParser::_parse_class(ClassNode *p_class) {
if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier()=="DIR") {
- current_export.hint=PROPERTY_HINT_DIR;
tokenizer->advance();
- if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) {
- _set_error("Expected ')' in hint.");
+
+ if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE)
+ current_export.hint=PROPERTY_HINT_DIR;
+ else if (tokenizer->get_token()==GDTokenizer::TK_COMMA ) {
+
+ tokenizer->advance();
+
+ if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER || !(tokenizer->get_token_identifier()=="GLOBAL")) {
+ _set_error("Expected 'GLOBAL' after comma in directory hint.");
+ return;
+ }
+ if (!p_class->tool) {
+ _set_error("Global filesystem hints may only be used in tool scripts.");
+ return;
+ }
+ current_export.hint=PROPERTY_HINT_GLOBAL_DIR;
+ tokenizer->advance();
+
+ if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) {
+ _set_error("Expected ')' in hint.");
+ return;
+ }
+ }
+ else {
+ _set_error("Expected ')' or ',' in hint.");
return;
}
break;
@@ -2477,9 +2680,32 @@ void GDParser::_parse_class(ClassNode *p_class) {
if (tokenizer->get_token()==GDTokenizer::TK_COMMA) {
tokenizer->advance();
+
+ if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier()=="GLOBAL") {
+
+ if (!p_class->tool) {
+ _set_error("Global filesystem hints may only be used in tool scripts.");
+ return;
+ }
+ current_export.hint=PROPERTY_HINT_GLOBAL_FILE;
+ tokenizer->advance();
+
+ if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE)
+ break;
+ else if (tokenizer->get_token()==GDTokenizer::TK_COMMA)
+ tokenizer->advance();
+ else {
+ _set_error("Expected ')' or ',' in hint.");
+ return;
+ }
+ }
+
if (tokenizer->get_token()!=GDTokenizer::TK_CONSTANT || tokenizer->get_token_constant().get_type()!=Variant::STRING) {
- _set_error("Expected string constant with filter");
+ if (current_export.hint==PROPERTY_HINT_GLOBAL_FILE)
+ _set_error("Expected string constant with filter");
+ else
+ _set_error("Expected 'GLOBAL' or string constant with filter");
return;
}
current_export.hint_string=tokenizer->get_token_constant();
@@ -2493,6 +2719,17 @@ void GDParser::_parse_class(ClassNode *p_class) {
}
break;
}
+
+ if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER && tokenizer->get_token_identifier()=="MULTILINE") {
+
+ current_export.hint=PROPERTY_HINT_MULTILINE_TEXT;
+ tokenizer->advance();
+ if (tokenizer->get_token()!=GDTokenizer::TK_PARENTHESIS_CLOSE) {
+ _set_error("Expected ')' in hint.");
+ return;
+ }
+ break;
+ }
} break;
case Variant::COLOR: {
@@ -2562,6 +2799,17 @@ void GDParser::_parse_class(ClassNode *p_class) {
}
}; //fallthrough to var
+ case GDTokenizer::TK_PR_ONREADY: {
+
+ if (token==GDTokenizer::TK_PR_ONREADY) {
+ //may be fallthrough from export, ignore if so
+ tokenizer->advance();
+ if (tokenizer->get_token()!=GDTokenizer::TK_PR_VAR) {
+ _set_error("Expected 'var'.");
+ return;
+ }
+ }
+ }; //fallthrough to var
case GDTokenizer::TK_PR_VAR: {
//variale declaration and (eventual) initialization
@@ -2572,6 +2820,8 @@ void GDParser::_parse_class(ClassNode *p_class) {
current_export=PropertyInfo();
}
+ bool onready = tokenizer->get_token(-1)==GDTokenizer::TK_PR_ONREADY;
+
tokenizer->advance();
if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) {
@@ -2594,14 +2844,33 @@ void GDParser::_parse_class(ClassNode *p_class) {
Node *subexpr=NULL;
- subexpr = _parse_and_reduce_expression(p_class,false);
- if (!subexpr)
+ subexpr = _parse_and_reduce_expression(p_class,false,autoexport);
+ if (!subexpr) {
+ if (_recover_from_completion()) {
+ break;
+ }
return;
+ }
+
+ //discourage common error
+ if (!onready && subexpr->type==Node::TYPE_OPERATOR) {
+
+ OperatorNode *op=static_cast<OperatorNode*>(subexpr);
+ if (op->op==OperatorNode::OP_CALL && op->arguments[0]->type==Node::TYPE_SELF && op->arguments[1]->type==Node::TYPE_IDENTIFIER) {
+ IdentifierNode *id=static_cast<IdentifierNode*>(op->arguments[1]);
+ if (id->name=="get_node") {
+
+ _set_error("Use 'onready var "+String(member.identifier)+" = get_node(..)' instead");
+ return;
+
+ }
+ }
+ }
member.expression=subexpr;
if (autoexport) {
- if (subexpr->type==Node::TYPE_ARRAY) {
+ if (1)/*(subexpr->type==Node::TYPE_ARRAY) {
member._export.type=Variant::ARRAY;
@@ -2609,7 +2878,7 @@ void GDParser::_parse_class(ClassNode *p_class) {
member._export.type=Variant::DICTIONARY;
- } else {
+ } else*/ {
if (subexpr->type!=Node::TYPE_CONSTANT) {
@@ -2644,12 +2913,19 @@ void GDParser::_parse_class(ClassNode *p_class) {
op->arguments.push_back(id);
op->arguments.push_back(subexpr);
+
#ifdef DEBUG_ENABLED
NewLineNode *nl = alloc_node<NewLineNode>();
nl->line=line;
- p_class->initializer->statements.push_back(nl);
+ if (onready)
+ p_class->ready->statements.push_back(nl);
+ else
+ p_class->initializer->statements.push_back(nl);
#endif
- p_class->initializer->statements.push_back(op);
+ if (onready)
+ p_class->ready->statements.push_back(op);
+ else
+ p_class->initializer->statements.push_back(op);
@@ -2725,8 +3001,12 @@ void GDParser::_parse_class(ClassNode *p_class) {
Node *subexpr=NULL;
subexpr = _parse_and_reduce_expression(p_class,true,true);
- if (!subexpr)
+ if (!subexpr) {
+ if (_recover_from_completion()) {
+ break;
+ }
return;
+ }
if (subexpr->type!=Node::TYPE_CONSTANT) {
_set_error("Expected constant expression");
@@ -2796,6 +3076,8 @@ Error GDParser::_parse(const String& p_base_path) {
ClassNode *main_class = alloc_node<ClassNode>();
main_class->initializer = alloc_node<BlockNode>();
main_class->initializer->parent_class=main_class;
+ main_class->ready = alloc_node<BlockNode>();
+ main_class->ready->parent_class=main_class;
current_class=main_class;
_parse_class(main_class);
@@ -2814,11 +3096,14 @@ Error GDParser::_parse(const String& p_base_path) {
Error GDParser::parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p_base_path, const String &p_self_path) {
+ for_completion=false;
+ validating=false;
completion_type=COMPLETION_NONE;
completion_node=NULL;
completion_class=NULL;
completion_function=NULL;
completion_block=NULL;
+ completion_found=false;
current_block=NULL;
current_class=NULL;
current_function=NULL;
@@ -2834,13 +3119,14 @@ Error GDParser::parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p
}
-Error GDParser::parse(const String& p_code, const String& p_base_path, bool p_just_validate, const String &p_self_path) {
+Error GDParser::parse(const String& p_code, const String& p_base_path, bool p_just_validate, const String &p_self_path,bool p_for_completion) {
completion_type=COMPLETION_NONE;
completion_node=NULL;
completion_class=NULL;
completion_function=NULL;
completion_block=NULL;
+ completion_found=false;
current_block=NULL;
current_class=NULL;
@@ -2851,6 +3137,7 @@ Error GDParser::parse(const String& p_code, const String& p_base_path, bool p_ju
tt->set_code(p_code);
validating=p_just_validate;
+ for_completion=p_for_completion;
tokenizer=tt;
Error ret = _parse(p_base_path);
memdelete(tt);
@@ -2883,9 +3170,12 @@ void GDParser::clear() {
current_block=NULL;
current_class=NULL;
+ completion_found=false;
+
current_function=NULL;
validating=false;
+ for_completion=false;
error_set=false;
tab_level.clear();
tab_level.push_back(0);
diff --git a/modules/gdscript/gd_parser.h b/modules/gdscript/gd_parser.h
index fd5c0802ea..9ad8633968 100644
--- a/modules/gdscript/gd_parser.h
+++ b/modules/gdscript/gd_parser.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -54,6 +54,7 @@ public:
TYPE_CONTROL_FLOW,
TYPE_LOCAL_VAR,
TYPE_ASSERT,
+ TYPE_BREAKPOINT,
TYPE_NEWLINE,
};
@@ -105,6 +106,7 @@ public:
Vector<FunctionNode*> static_functions;
Vector<Signal> _signals;
BlockNode *initializer;
+ BlockNode *ready;
ClassNode *owner;
//Vector<Node*> initializers;
int end_line;
@@ -275,8 +277,11 @@ public:
AssertNode() { type=TYPE_ASSERT; }
};
+ struct BreakpointNode : public Node {
+ BreakpointNode() { type=TYPE_BREAKPOINT; }
+ };
+
struct NewLineNode : public Node {
- int line;
NewLineNode() { type=TYPE_NEWLINE; }
};
@@ -387,6 +392,7 @@ private:
T* alloc_node();
bool validating;
+ bool for_completion;
int parenthesis;
bool error_set;
String error;
@@ -418,10 +424,12 @@ private:
BlockNode *completion_block;
int completion_line;
int completion_argument;
+ bool completion_found;
PropertyInfo current_export;
void _set_error(const String& p_error, int p_line=-1, int p_column=-1);
+ bool _recover_from_completion();
bool _parse_arguments(Node* p_parent, Vector<Node*>& p_args, bool p_static, bool p_can_codecomplete=false);
@@ -443,7 +451,7 @@ public:
String get_error() const;
int get_error_line() const;
int get_error_column() const;
- Error parse(const String& p_code, const String& p_base_path="", bool p_just_validate=false,const String& p_self_path="");
+ Error parse(const String& p_code, const String& p_base_path="", bool p_just_validate=false,const String& p_self_path="",bool p_for_completion=false);
Error parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p_base_path="",const String& p_self_path="");
const Node *get_parse_tree() const;
diff --git a/modules/gdscript/gd_pretty_print.cpp b/modules/gdscript/gd_pretty_print.cpp
index 9c290eac4a..cca3cd3984 100644
--- a/modules/gdscript/gd_pretty_print.cpp
+++ b/modules/gdscript/gd_pretty_print.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/gd_pretty_print.h b/modules/gdscript/gd_pretty_print.h
index 998fdc53ab..0106d873d9 100644
--- a/modules/gdscript/gd_pretty_print.h
+++ b/modules/gdscript/gd_pretty_print.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp
index b6ad7aa716..9a3f50d3b8 100644
--- a/modules/gdscript/gd_script.cpp
+++ b/modules/gdscript/gd_script.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,17 +33,6 @@
#include "os/file_access.h"
#include "io/file_access_encrypted.h"
-/* TODO:
-
- *populate globals
- *do checks as close to debugger as possible (but don't do debugger)
- *const check plz
- *check arguments and default arguments in GDFunction
- -get property list in instance?
- *missing opcodes
- -const checks
- -make thread safe
- */
@@ -232,6 +221,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
r_err.error=Variant::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
r_err.argument=_argument_count;
+
return Variant();
} else if (p_argcount < _argument_count - _default_arg_count) {
@@ -1077,6 +1067,14 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
ip+=2;
} continue;
+ case OPCODE_BREAKPOINT: {
+#ifdef DEBUG_ENABLED
+ if (ScriptDebugger::get_singleton()) {
+ GDScriptLanguage::get_singleton()->debug_break("Breakpoint Statement",true);
+ }
+#endif
+ ip+=1;
+ } continue;
case OPCODE_LINE: {
CHECK_SPACE(2);
@@ -1141,7 +1139,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
if (!GDScriptLanguage::get_singleton()->debug_break(err_text,false)) {
// debugger break did not happen
- _err_print_error(err_func.utf8().get_data(),err_file.utf8().get_data(),err_line,err_text.utf8().get_data());
+ _err_print_error(err_func.utf8().get_data(),err_file.utf8().get_data(),err_line,err_text.utf8().get_data(),ERR_HANDLER_SCRIPT);
}
@@ -1370,7 +1368,7 @@ Variant GDFunctionState::resume(const Variant& p_arg) {
void GDFunctionState::_bind_methods() {
- ObjectTypeDB::bind_method(_MD("resume:var","arg"),&GDFunctionState::resume,DEFVAL(Variant()));
+ ObjectTypeDB::bind_method(_MD("resume:Variant","arg"),&GDFunctionState::resume,DEFVAL(Variant()));
ObjectTypeDB::bind_method(_MD("is_valid"),&GDFunctionState::is_valid);
ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"_signal_callback",&GDFunctionState::_signal_callback,MethodInfo("_signal_callback"));
@@ -1449,7 +1447,7 @@ Object *GDNativeClass::instance() {
-GDInstance* GDScript::_create_instance(const Variant** p_args,int p_argcount,Object *p_owner,bool p_isref) {
+GDInstance* GDScript::_create_instance(const Variant** p_args,int p_argcount,Object *p_owner,bool p_isref,Variant::CallError& r_error) {
/* STEP 1, CREATE */
@@ -1465,14 +1463,13 @@ GDInstance* GDScript::_create_instance(const Variant** p_args,int p_argcount,Obj
instances.insert(instance->owner);
- Variant::CallError err;
- initializer->call(instance,p_args,p_argcount,err);
+ initializer->call(instance,p_args,p_argcount,r_error);
- if (err.error!=Variant::CallError::CALL_OK) {
+ if (r_error.error!=Variant::CallError::CALL_OK) {
instance->script=Ref<GDScript>();
instance->owner->set_script_instance(NULL);
instances.erase(p_owner);
- ERR_FAIL_COND_V(err.error!=Variant::CallError::CALL_OK, NULL); //error consrtucting
+ ERR_FAIL_COND_V(r_error.error!=Variant::CallError::CALL_OK, NULL); //error constructing
}
//@TODO make thread safe
@@ -1505,7 +1502,7 @@ Variant GDScript::_new(const Variant** p_args,int p_argcount,Variant::CallError&
}
- GDInstance* instance = _create_instance(p_args,p_argcount,owner,r!=NULL);
+ GDInstance* instance = _create_instance(p_args,p_argcount,owner,r!=NULL,r_error);
if (!instance) {
if (ref.is_null()) {
memdelete(owner); //no owner, sorry
@@ -1596,6 +1593,28 @@ void GDScript::_update_placeholder(PlaceHolderScriptInstance *p_placeholder) {
}*/
#endif
+
+bool GDScript::get_property_default_value(const StringName& p_property, Variant &r_value) const {
+
+#ifdef TOOLS_ENABLED
+
+ //for (const Map<StringName,Variant>::Element *I=member_default_values.front();I;I=I->next()) {
+ // print_line("\t"+String(String(I->key())+":"+String(I->get())));
+ //}
+ const Map<StringName,Variant>::Element *E=member_default_values_cache.find(p_property);
+ if (E) {
+ r_value=E->get();
+ return true;
+ }
+
+ if (base_cache.is_valid()) {
+ return base_cache->get_property_default_value(p_property,r_value);
+ }
+#endif
+ return false;
+
+}
+
ScriptInstance* GDScript::instance_create(Object *p_this) {
@@ -1637,7 +1656,8 @@ ScriptInstance* GDScript::instance_create(Object *p_this) {
}
}
- return _create_instance(NULL,0,p_this,p_this->cast_to<Reference>());
+ Variant::CallError unchecked_error;
+ return _create_instance(NULL,0,p_this,p_this->cast_to<Reference>(),unchecked_error);
}
bool GDScript::instance_has(const Object *p_this) const {
@@ -1732,16 +1752,21 @@ bool GDScript::_update_exports() {
}
}
- Ref<GDScript> bf = ResourceLoader::load(path);
+ if (path!=get_path()) {
+
+ Ref<GDScript> bf = ResourceLoader::load(path);
- if (bf.is_valid()) {
+ if (bf.is_valid()) {
- //print_line("parent is: "+bf->get_path());
- base_cache=bf;
- bf->inheriters_cache.insert(get_instance_ID());
+ //print_line("parent is: "+bf->get_path());
+ base_cache=bf;
+ bf->inheriters_cache.insert(get_instance_ID());
- //bf->_update_exports(p_instances,true,false);
+ //bf->_update_exports(p_instances,true,false);
+ }
+ } else {
+ ERR_PRINT(("Path extending itself in "+path).utf8().get_data());
}
}
@@ -1977,9 +2002,17 @@ void GDScript::_bind_methods() {
ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"new",&GDScript::_new,MethodInfo("new"));
+ ObjectTypeDB::bind_method(_MD("get_as_byte_code"),&GDScript::get_as_byte_code);
+
}
+Vector<uint8_t> GDScript::get_as_byte_code() const {
+
+ GDTokenizerBuffer tokenizer;
+ return tokenizer.parse_code_string(source);
+};
+
Error GDScript::load_byte_code(const String& p_path) {
@@ -2266,6 +2299,26 @@ bool GDInstance::get(const StringName& p_name, Variant &r_ret) const {
return false;
}
+
+Variant::Type GDInstance::get_property_type(const StringName& p_name,bool *r_is_valid) const {
+
+
+ const GDScript *sptr=script.ptr();
+ while(sptr) {
+
+ if (sptr->member_info.has(p_name)) {
+ if (r_is_valid)
+ *r_is_valid=true;
+ return sptr->member_info[p_name].type;
+ }
+ sptr = sptr->_base;
+ }
+
+ if (r_is_valid)
+ *r_is_valid=false;
+ return Variant::NIL;
+}
+
void GDInstance::get_property_list(List<PropertyInfo> *p_properties) const {
// exported members, not doen yet!
@@ -2542,6 +2595,12 @@ void GDScriptLanguage::_add_global(const StringName& p_name,const Variant& p_val
_global_array=global_array.ptr();
}
+void GDScriptLanguage::add_global_constant(const StringName& p_variable,const Variant& p_value) {
+
+ _add_global(p_variable,p_value);
+}
+
+
void GDScriptLanguage::init() {
@@ -2556,9 +2615,9 @@ void GDScriptLanguage::init() {
//populate native classes
- List<String> class_list;
+ List<StringName> class_list;
ObjectTypeDB::get_type_list(&class_list);
- for(List<String>::Element *E=class_list.front();E;E=E->next()) {
+ for(List<StringName>::Element *E=class_list.front();E;E=E->next()) {
StringName n = E->get();
String s = String(n);
@@ -2618,6 +2677,7 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
"elif",
"enum",
"extends" ,
+ "onready",
"for" ,
"func" ,
"if" ,
@@ -2637,6 +2697,7 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
"or",
"export",
"assert",
+ "breakpoint",
"yield",
"static",
"float",
@@ -2702,7 +2763,10 @@ GDScriptLanguage::~GDScriptLanguage() {
/*************** RESOURCE ***************/
-RES ResourceFormatLoaderGDScript::load(const String &p_path,const String& p_original_path) {
+RES ResourceFormatLoaderGDScript::load(const String &p_path, const String& p_original_path, Error *r_error) {
+
+ if (r_error)
+ *r_error=ERR_FILE_CANT_OPEN;
GDScript *script = memnew( GDScript );
@@ -2734,6 +2798,8 @@ RES ResourceFormatLoaderGDScript::load(const String &p_path,const String& p_orig
script->reload();
}
+ if (r_error)
+ *r_error=OK;
return scriptres;
}
diff --git a/modules/gdscript/gd_script.h b/modules/gdscript/gd_script.h
index 4672f3b8be..a69f99314a 100644
--- a/modules/gdscript/gd_script.h
+++ b/modules/gdscript/gd_script.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -71,6 +71,7 @@ public:
OPCODE_ITERATE_BEGIN,
OPCODE_ITERATE,
OPCODE_ASSERT,
+ OPCODE_BREAKPOINT,
OPCODE_LINE,
OPCODE_END
};
@@ -286,7 +287,7 @@ friend class GDScriptLanguage;
String name;
- GDInstance* _create_instance(const Variant** p_args,int p_argcount,Object *p_owner,bool p_isref);
+ GDInstance* _create_instance(const Variant** p_args,int p_argcount,Object *p_owner,bool p_isref,Variant::CallError &r_error);
void _set_subclass_path(Ref<GDScript>& p_sc,const String& p_path);
@@ -349,6 +350,10 @@ public:
Error load_source_code(const String& p_path);
Error load_byte_code(const String& p_path);
+ Vector<uint8_t> get_as_byte_code() const;
+
+ bool get_property_default_value(const StringName& p_property,Variant& r_value) const;
+
virtual ScriptLanguage *get_language() const;
GDScript();
@@ -371,6 +376,8 @@ public:
virtual bool set(const StringName& p_name, const Variant& p_value);
virtual bool get(const StringName& p_name, Variant &r_ret) const;
virtual void get_property_list(List<PropertyInfo> *p_properties) const;
+ virtual Variant::Type get_property_type(const StringName& p_name,bool *r_is_valid=NULL) const;
+
virtual void get_method_list(List<MethodInfo> *p_list) const;
virtual bool has_method(const StringName& p_method) const;
@@ -473,6 +480,19 @@ public:
}
+ virtual Vector<StackInfo> debug_get_current_stack_info() {
+ if (Thread::get_main_ID()!=Thread::get_caller_ID())
+ return Vector<StackInfo>();
+
+ Vector<StackInfo> csi;
+ csi.resize(_debug_call_stack_pos);
+ for(int i=0;i<_debug_call_stack_pos;i++) {
+ csi[_debug_call_stack_pos-i-1].line=_call_stack[i].line?*_call_stack[i].line:0;
+ csi[_debug_call_stack_pos-i-1].script=Ref<GDScript>(_call_stack[i].function->get_script());
+ }
+ return csi;
+ }
+
struct {
StringName _init;
@@ -512,6 +532,8 @@ public:
virtual String make_function(const String& p_class,const String& p_name,const StringArray& p_args) const;
virtual Error complete_code(const String& p_code, const String& p_base_path, Object*p_owner,List<String>* r_options,String& r_call_hint);
virtual void auto_indent_code(String& p_code,int p_from_line,int p_to_line) const;
+ virtual void add_global_constant(const StringName& p_variable,const Variant& p_value);
+
/* DEBUGGER FUNCTIONS */
@@ -542,7 +564,7 @@ public:
class ResourceFormatLoaderGDScript : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path,const String& p_original_path="");
+ virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String& p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/modules/gdscript/gd_tokenizer.cpp b/modules/gdscript/gd_tokenizer.cpp
index 656a015c66..71c56aba01 100644
--- a/modules/gdscript/gd_tokenizer.cpp
+++ b/modules/gdscript/gd_tokenizer.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -88,6 +88,7 @@ const char* GDTokenizer::token_names[TK_MAX]={
"func",
"class",
"extends",
+"onready",
"tool",
"static",
"export",
@@ -97,6 +98,8 @@ const char* GDTokenizer::token_names[TK_MAX]={
"preload",
"assert",
"yield",
+"signal",
+"breakpoint",
"'['",
"']'",
"'{'",
@@ -109,6 +112,7 @@ const char* GDTokenizer::token_names[TK_MAX]={
"'?'",
"':'",
"'\\n'",
+"PI",
"Error",
"EOF",
"Cursor"};
@@ -258,6 +262,7 @@ void GDTokenizerText::_advance() {
}
INCPOS(1);
+ line++;
while(GETCHAR(0)==' ' || GETCHAR(0)=='\t') {
INCPOS(1);
@@ -568,7 +573,10 @@ void GDTokenizerText::_advance() {
} else if( string_mode!=STRING_MULTILINE && CharType(GETCHAR(i))=='\n') {
_make_error("Unexpected EOL at String.");
return;
-
+ } else if( CharType(GETCHAR(i))==0xFFFF) {
+ //string ends here, next will be TK
+ i--;
+ break;
} else if (CharType(GETCHAR(i))=='\\') {
//escaped characters...
i++;
@@ -639,6 +647,11 @@ void GDTokenizerText::_advance() {
str+=res;
} else {
+ if (CharType(GETCHAR(i))=='\n') {
+ line++;
+ column=0;
+ }
+
str+=CharType(GETCHAR(i));
}
i++;
@@ -670,19 +683,19 @@ void GDTokenizerText::_advance() {
while(true) {
if (GETCHAR(i)=='.') {
if (period_found || exponent_found) {
- _make_error("Invalid numeric constant at '.'");
+ _make_error("Invalid numeric constant at '.'");
return;
}
period_found=true;
} else if (GETCHAR(i)=='x') {
- if (hexa_found || str.length()!=1 || !( (i==1 && str[0]=='0') || (i==2 && str[1]=='0' && str[0]=='-') ) ) {
- _make_error("Invalid numeric constant at 'x'");
+ if (hexa_found || str.length()!=1 || !( (i==1 && str[0]=='0') || (i==2 && str[1]=='0' && str[0]=='-') ) ) {
+ _make_error("Invalid numeric constant at 'x'");
return;
}
hexa_found=true;
- } else if (!hexa_found && GETCHAR(i)=='e') {
+ } else if (!hexa_found && GETCHAR(i)=='e') {
if (hexa_found || exponent_found) {
- _make_error("Invalid numeric constant at 'e'");
+ _make_error("Invalid numeric constant at 'e'");
return;
}
exponent_found=true;
@@ -692,7 +705,7 @@ void GDTokenizerText::_advance() {
} else if ((GETCHAR(i)=='-' || GETCHAR(i)=='+') && exponent_found) {
if (sign_found) {
- _make_error("Invalid numeric constant at '-'");
+ _make_error("Invalid numeric constant at '-'");
return;
}
sign_found=true;
@@ -703,20 +716,20 @@ void GDTokenizerText::_advance() {
i++;
}
- if (!( _is_number(str[str.length()-1]) || (hexa_found && _is_hex(str[str.length()-1])))) {
- _make_error("Invalid numeric constant: "+str);
+ if (!( _is_number(str[str.length()-1]) || (hexa_found && _is_hex(str[str.length()-1])))) {
+ _make_error("Invalid numeric constant: "+str);
return;
}
INCPOS(str.length());
- if (hexa_found) {
- int val = str.hex_to_int();
- _make_constant(val);
- } else if (period_found) {
+ if (hexa_found) {
+ int val = str.hex_to_int();
+ _make_constant(val);
+ } else if (period_found) {
real_t val = str.to_double();
//print_line("*%*%*%*% to convert: "+str+" result: "+rtos(val));
_make_constant(val);
- } else {
+ } else {
int val = str.to_int();
_make_constant(val);
@@ -765,20 +778,15 @@ void GDTokenizerText::_advance() {
{Variant::INT,"int"},
{Variant::REAL,"float"},
{Variant::STRING,"String"},
- {Variant::VECTOR2,"vec2"},
{Variant::VECTOR2,"Vector2"},
{Variant::RECT2,"Rect2"},
{Variant::MATRIX32,"Matrix32"},
- {Variant::MATRIX32,"mat32"},
- {Variant::VECTOR3,"vec3"},
{Variant::VECTOR3,"Vector3"},
{Variant::_AABB,"AABB"},
{Variant::_AABB,"Rect3"},
{Variant::PLANE,"Plane"},
{Variant::QUAT,"Quat"},
- {Variant::MATRIX3,"mat3"},
{Variant::MATRIX3,"Matrix3"},
- {Variant::TRANSFORM,"trn"},
{Variant::TRANSFORM,"Transform"},
{Variant::COLOR,"Color"},
{Variant::IMAGE,"Image"},
@@ -786,7 +794,6 @@ void GDTokenizerText::_advance() {
{Variant::OBJECT,"Object"},
{Variant::INPUT_EVENT,"InputEvent"},
{Variant::NODE_PATH,"NodePath"},
- {Variant::DICTIONARY,"dict"},
{Variant::DICTIONARY,"Dictionary"},
{Variant::ARRAY,"Array"},
{Variant::RAW_ARRAY,"RawArray"},
@@ -825,7 +832,7 @@ void GDTokenizerText::_advance() {
_make_built_in_func(GDFunctions::Function(i));
found=true;
- break;
+ break;
}
}
@@ -845,9 +852,9 @@ void GDTokenizerText::_advance() {
{TK_OP_AND,"and"},
//func
{TK_PR_FUNCTION,"func"},
- {TK_PR_FUNCTION,"function"},
{TK_PR_CLASS,"class"},
{TK_PR_EXTENDS,"extends"},
+ {TK_PR_ONREADY,"onready"},
{TK_PR_TOOL,"tool"},
{TK_PR_STATIC,"static"},
{TK_PR_EXPORT,"export"},
@@ -857,6 +864,7 @@ void GDTokenizerText::_advance() {
{TK_PR_ASSERT,"assert"},
{TK_PR_YIELD,"yield"},
{TK_PR_SIGNAL,"signal"},
+ {TK_PR_BREAKPOINT,"breakpoint"},
{TK_PR_CONST,"const"},
//controlflow
{TK_CF_IF,"if"},
@@ -871,6 +879,7 @@ void GDTokenizerText::_advance() {
{TK_CF_RETURN,"return"},
{TK_CF_PASS,"pass"},
{TK_SELF,"self"},
+ {TK_CONST_PI,"PI"},
{TK_ERROR,NULL}
};
@@ -1037,7 +1046,7 @@ void GDTokenizerText::advance(int p_amount) {
//////////////////////////////////////////////////////////////////////////////////////////////////////
-#define BYTECODE_VERSION 4
+#define BYTECODE_VERSION 10
Error GDTokenizerBuffer::set_code_buffer(const Vector<uint8_t> & p_buffer) {
diff --git a/modules/gdscript/gd_tokenizer.h b/modules/gdscript/gd_tokenizer.h
index d6bd63c5b8..aaff573090 100644
--- a/modules/gdscript/gd_tokenizer.h
+++ b/modules/gdscript/gd_tokenizer.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -95,6 +95,7 @@ public:
TK_PR_FUNCTION,
TK_PR_CLASS,
TK_PR_EXTENDS,
+ TK_PR_ONREADY,
TK_PR_TOOL,
TK_PR_STATIC,
TK_PR_EXPORT,
@@ -105,6 +106,7 @@ public:
TK_PR_ASSERT,
TK_PR_YIELD,
TK_PR_SIGNAL,
+ TK_PR_BREAKPOINT,
TK_BRACKET_OPEN,
TK_BRACKET_CLOSE,
TK_CURLY_BRACKET_OPEN,
@@ -117,6 +119,7 @@ public:
TK_QUESTION_MARK,
TK_COLON,
TK_NEWLINE,
+ TK_CONST_PI,
TK_ERROR,
TK_EOF,
TK_CURSOR, //used for code completion
diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp
index 4470b7ca0c..2aea494f39 100644
--- a/modules/gdscript/register_types.cpp
+++ b/modules/gdscript/register_types.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/*************************************************/
/* Source code within this file is: */
-/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
/* All Rights Reserved. */
/*************************************************/
diff --git a/modules/gdscript/register_types.h b/modules/gdscript/register_types.h
index 9eb5d1846b..aed11cd1d4 100644
--- a/modules/gdscript/register_types.h
+++ b/modules/gdscript/register_types.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gridmap/SCsub b/modules/gridmap/SCsub
index 4cb47e7e67..211a043468 100644
--- a/modules/gridmap/SCsub
+++ b/modules/gridmap/SCsub
@@ -1,6 +1,3 @@
Import('env')
env.add_source_files(env.modules_sources,"*.cpp")
-
-
-
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index 121b23001d..7d463b13d4 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,7 +34,7 @@
#include "scene/3d/baked_light_instance.h"
#include "io/marshalls.h"
#include "scene/scene_string_names.h"
-
+#include "os/os.h"
bool GridMap::_set(const StringName& p_name, const Variant& p_value) {
@@ -130,8 +130,8 @@ bool GridMap::_set(const StringName& p_name, const Variant& p_value) {
} else if (name.begins_with("areas/")) {
- int which = name.get_slice("/",1).to_int();
- String what=name.get_slice("/",2);
+ int which = name.get_slicec('/',1).to_int();
+ String what=name.get_slicec('/',2);
if (what=="bounds") {
ERR_FAIL_COND_V(area_map.has(which),false);
create_area(which,p_value);
@@ -215,8 +215,8 @@ bool GridMap::_get(const StringName& p_name,Variant &r_ret) const {
r_ret= d;
} else if (name.begins_with("areas/")) {
- int which = name.get_slice("/",1).to_int();
- String what=name.get_slice("/",2);
+ int which = name.get_slicec('/',1).to_int();
+ String what=name.get_slicec('/',2);
if (what=="bounds")
r_ret= area_get_bounds(which);
else if (what=="name")
@@ -393,8 +393,12 @@ void GridMap::set_cell_item(int p_x,int p_y,int p_z, int p_item,int p_rot){
if (g.items.empty()) {
PhysicsServer::get_singleton()->free(g.static_body);
+ if (g.collision_debug.is_valid()) {
+ PhysicsServer::get_singleton()->free(g.collision_debug);
+ PhysicsServer::get_singleton()->free(g.collision_debug_instance);
+ }
- memdelete(&g);
+ memdelete(&g);
octant_map.erase(octantkey);
} else {
@@ -422,6 +426,20 @@ void GridMap::set_cell_item(int p_x,int p_y,int p_z, int p_item,int p_rot){
if (is_inside_world())
PhysicsServer::get_singleton()->body_set_space(g->static_body,get_world()->get_space());
+ SceneTree *st=SceneTree::get_singleton();
+
+ if (st && st->is_debugging_collisions_hint()) {
+
+ g->collision_debug=VisualServer::get_singleton()->mesh_create();
+ g->collision_debug_instance=VisualServer::get_singleton()->instance_create();
+ VisualServer::get_singleton()->instance_set_base(g->collision_debug_instance,g->collision_debug);
+ if (is_inside_world()) {
+ VisualServer::get_singleton()->instance_set_scenario(g->collision_debug_instance,get_world()->get_scenario());
+ VisualServer::get_singleton()->instance_set_transform(g->collision_debug_instance,get_global_transform());
+ }
+
+ }
+
octant_map[octantkey]=g;
}
@@ -512,6 +530,13 @@ void GridMap::_octant_enter_world(const OctantKey &p_key) {
//print_line("BODYPOS: "+get_global_transform());
+ if (g.collision_debug_instance.is_valid()) {
+ VS::get_singleton()->instance_set_scenario(g.collision_debug_instance,get_world()->get_scenario());
+ VS::get_singleton()->instance_set_transform(g.collision_debug_instance,get_global_transform());
+ if (area_map.has(p_key.area)) {
+ VS::get_singleton()->instance_set_room(g.collision_debug_instance,area_map[p_key.area]->instance);
+ }
+ }
if (g.baked.is_valid()) {
Transform xf = get_global_transform();
@@ -545,6 +570,10 @@ void GridMap::_octant_transform(const OctantKey &p_key) {
Octant&g = *octant_map[p_key];
PhysicsServer::get_singleton()->body_set_state(g.static_body,PhysicsServer::BODY_STATE_TRANSFORM,get_global_transform());
+ if (g.collision_debug_instance.is_valid()) {
+ VS::get_singleton()->instance_set_transform(g.collision_debug_instance,get_global_transform());
+ }
+
if (g.baked.is_valid()) {
Transform xf = get_global_transform();
@@ -572,6 +601,13 @@ void GridMap::_octant_update(const OctantKey &p_key) {
PhysicsServer::get_singleton()->body_clear_shapes(g.static_body);
+ if (g.collision_debug.is_valid()) {
+
+ VS::get_singleton()->mesh_clear(g.collision_debug);
+ }
+
+ DVector<Vector3> col_debug;
+
for(Map<int,Octant::ItemInstances>::Element *E=g.items.front();E;E=E->next()) {
Octant::ItemInstances &ii=E->get();
@@ -609,6 +645,7 @@ void GridMap::_octant_update(const OctantKey &p_key) {
xform.basis.scale(Vector3(cell_scale,cell_scale,cell_scale));
ii.multimesh->set_instance_transform(idx,xform);
+ //ii.multimesh->set_instance_transform(idx,Transform() );
ii.multimesh->set_instance_color(idx,Color(1,1,1,1));
//print_line("MMINST: "+xform);
@@ -624,8 +661,11 @@ void GridMap::_octant_update(const OctantKey &p_key) {
if (ii.shape.is_valid()) {
PhysicsServer::get_singleton()->body_add_shape(g.static_body,ii.shape->get_rid(),xform);
- // print_line("PHIS x: "+xform);
+ if (g.collision_debug.is_valid()) {
+ ii.shape->add_vertices_to_array(col_debug,xform);
+ }
+ // print_line("PHIS x: "+xform);
}
idx++;
@@ -636,6 +676,20 @@ void GridMap::_octant_update(const OctantKey &p_key) {
}
+ if (col_debug.size()) {
+
+
+ Array arr;
+ arr.resize(VS::ARRAY_MAX);
+ arr[VS::ARRAY_VERTEX]=col_debug;
+
+ VS::get_singleton()->mesh_add_surface(g.collision_debug,VS::PRIMITIVE_LINES,arr);
+ SceneTree *st=SceneTree::get_singleton();
+ if (st) {
+ VS::get_singleton()->mesh_surface_set_material( g.collision_debug, 0,st->get_debug_collision_material()->get_rid() );
+ }
+ }
+
g.dirty=false;
}
@@ -656,6 +710,12 @@ void GridMap::_octant_exit_world(const OctantKey &p_key) {
}
+ if (g.collision_debug_instance.is_valid()) {
+
+ VS::get_singleton()->instance_set_room(g.collision_debug_instance,RID());
+ VS::get_singleton()->instance_set_scenario(g.collision_debug_instance,RID());
+ }
+
for(Map<int,Octant::ItemInstances>::Element *E=g.items.front();E;E=E->next()) {
VS::get_singleton()->instance_set_scenario(E->get().multimesh_instance,RID());
@@ -959,6 +1019,11 @@ void GridMap::_clear_internal(bool p_keep_areas) {
if (E->get()->bake_instance.is_valid())
VS::get_singleton()->free(E->get()->bake_instance);
+ if (E->get()->collision_debug.is_valid())
+ VS::get_singleton()->free(E->get()->collision_debug);
+ if (E->get()->collision_debug_instance.is_valid())
+ VS::get_singleton()->free(E->get()->collision_debug_instance);
+
PhysicsServer::get_singleton()->free(E->get()->static_body);
memdelete(E->get());
@@ -1031,7 +1096,7 @@ void GridMap::_bind_methods() {
// ObjectTypeDB::bind_method(_MD("_recreate_octants"),&GridMap::_recreate_octants);
ObjectTypeDB::bind_method(_MD("_update_dirty_map_callback"),&GridMap::_update_dirty_map_callback);
- ObjectTypeDB::bind_method(_MD("resource_changed"),&GridMap::resource_changed);
+ ObjectTypeDB::bind_method(_MD("resource_changed","resource"),&GridMap::resource_changed);
ObjectTypeDB::bind_method(_MD("set_center_x","enable"),&GridMap::set_center_x);
ObjectTypeDB::bind_method(_MD("get_center_x"),&GridMap::get_center_x);
diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h
index dff9fe3d68..66d3e6b44a 100644
--- a/modules/gridmap/grid_map.h
+++ b/modules/gridmap/grid_map.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -93,6 +93,8 @@ class GridMap : public Spatial {
Ref<Mesh> baked;
RID bake_instance;
+ RID collision_debug;
+ RID collision_debug_instance;
bool dirty;
RID static_body;
diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp
index 3d56b04cac..6043807db3 100644
--- a/modules/gridmap/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/grid_map_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -220,7 +220,9 @@ void GridMapEditor::_menu_option(int p_option) {
} break;
-
+ case MENU_OPTION_GRIDMAP_SETTINGS: {
+ settings_dialog->popup_centered(settings_vbc->get_combined_minimum_size() + Size2(50, 50));
+ } break;
}
}
@@ -304,7 +306,7 @@ bool GridMapEditor::do_input_action(Camera* p_camera,const Point2& p_point,bool
p.d=edit_floor[edit_axis]*node->get_cell_size();
Vector3 inters;
- if (!p.intersects_segment(from,from+normal*500,&inters))
+ if (!p.intersects_segment(from, from + normal * settings_pick_distance->get_val(), &inters))
return false;
@@ -1249,6 +1251,24 @@ GridMapEditor::GridMapEditor(EditorNode *p_editor) {
//options->get_popup()->add_separator();
//options->get_popup()->add_item("Configure",MENU_OPTION_CONFIGURE);
+ options->get_popup()->add_separator();
+ options->get_popup()->add_item("Settings", MENU_OPTION_GRIDMAP_SETTINGS);
+
+ settings_dialog = memnew(ConfirmationDialog);
+ settings_dialog->set_title("GridMap Settings");
+ add_child(settings_dialog);
+ settings_vbc = memnew(VBoxContainer);
+ settings_vbc->set_custom_minimum_size(Size2(200, 0));
+ settings_dialog->add_child(settings_vbc);
+ settings_dialog->set_child_rect(settings_vbc);
+
+ settings_pick_distance = memnew(SpinBox);
+ settings_pick_distance->set_max(10000.0f);
+ settings_pick_distance->set_min(500.0f);
+ settings_pick_distance->set_step(1.0f);
+ settings_pick_distance->set_val(EDITOR_DEF("gridmap_editor/pick_distance", 5000.0));
+ settings_vbc->add_margin_child("Pick Distance:", settings_pick_distance);
+
clip_mode=CLIP_DISABLED;
options->get_popup()->connect("item_pressed", this,"_menu_option");
diff --git a/modules/gridmap/grid_map_editor_plugin.h b/modules/gridmap/grid_map_editor_plugin.h
index 26fe8f20dc..fc43866ef3 100644
--- a/modules/gridmap/grid_map_editor_plugin.h
+++ b/modules/gridmap/grid_map_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -78,6 +78,9 @@ class GridMapEditor : public VBoxContainer {
ToolButton *mode_thumbnail;
ToolButton *mode_list;
HBoxContainer *spatial_editor_hb;
+ ConfirmationDialog *settings_dialog;
+ VBoxContainer *settings_vbc;
+ SpinBox *settings_pick_distance;
struct SetItem {
@@ -165,8 +168,8 @@ class GridMapEditor : public VBoxContainer {
MENU_OPTION_SELECTION_MAKE_AREA,
MENU_OPTION_SELECTION_MAKE_EXTERIOR_CONNECTOR,
MENU_OPTION_SELECTION_CLEAR,
- MENU_OPTION_REMOVE_AREA
-
+ MENU_OPTION_REMOVE_AREA,
+ MENU_OPTION_GRIDMAP_SETTINGS
};
diff --git a/modules/gridmap/register_types.cpp b/modules/gridmap/register_types.cpp
index 2bc440759d..9dcc04b22a 100644
--- a/modules/gridmap/register_types.cpp
+++ b/modules/gridmap/register_types.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gridmap/register_types.h b/modules/gridmap/register_types.h
index 326d7acf24..7b5c10f9e5 100644
--- a/modules/gridmap/register_types.h
+++ b/modules/gridmap/register_types.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/android/AndroidManifest.xml.template b/platform/android/AndroidManifest.xml.template
index c95c86c060..37dee4a9a5 100644
--- a/platform/android/AndroidManifest.xml.template
+++ b/platform/android/AndroidManifest.xml.template
@@ -3,7 +3,7 @@
package="com.godot.game"
android:versionCode="1"
android:versionName="1.0"
- android:installLocation="preferExternal"
+ android:installLocation="auto"
>
<supports-screens android:smallScreens="true"
android:normalScreens="true"
@@ -11,7 +11,7 @@
android:xlargeScreens="true"/>
<application android:label="@string/godot_project_name_string" android:icon="@drawable/icon" android:allowBackup="false" $$ADD_APPATTRIBUTE_CHUNKS$$ >
- <activity android:name="com.android.godot.Godot"
+ <activity android:name="org.godotengine.godot.Godot"
android:label="@string/godot_project_name_string"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:launchMode="singleTask"
@@ -23,7 +23,7 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
- <service android:name="com.android.godot.GodotDownloaderService" />
+ <service android:name="org.godotengine.godot.GodotDownloaderService" />
@@ -189,7 +189,7 @@ $$ADD_PERMISSION_CHUNKS$$
<uses-permission android:name="godot.custom.7"/>
<uses-permission android:name="godot.custom.8"/>
<uses-permission android:name="godot.custom.9"/>
-<uses-permission android:name="godot.custom.0"/>
+<uses-permission android:name="godot.custom.10"/>
<uses-permission android:name="godot.custom.11"/>
<uses-permission android:name="godot.custom.12"/>
<uses-permission android:name="godot.custom.13"/>
diff --git a/platform/android/SCsub b/platform/android/SCsub
index 6feeb8b365..3d645de38f 100644
--- a/platform/android/SCsub
+++ b/platform/android/SCsub
@@ -37,19 +37,59 @@ prog = None
abspath=env.Dir(".").abspath
-pp_basein = open(abspath+"/project.properties.template","rb")
-pp_baseout = open(abspath+"/java/project.properties","wb")
-pp_baseout.write( pp_basein.read() )
+gradle_basein = open(abspath+"/build.gradle.template","rb")
+gradle_baseout = open(abspath+"/java/build.gradle","wb")
-refcount=1
+gradle_text = gradle_basein.read()
-for x in env.android_source_modules:
- pp_baseout.write("android.library.reference."+str(refcount)+"="+x+"\n")
- refcount+=1
+gradle_maven_repos_text=""
+if len(env.android_maven_repos) > 0:
+ gradle_maven_repos_text+="maven {\n"
+ for x in env.android_maven_repos:
+ gradle_maven_repos_text+="\t\t"+x+"\n"
+ gradle_maven_repos_text+="\t}\n"
-pp_baseout.close()
+gradle_maven_dependencies_text=""
+
+for x in env.android_dependencies:
+ gradle_maven_dependencies_text+=x+"\n"
+
+gradle_java_dirs_text=""
+
+for x in env.android_java_dirs:
+ gradle_java_dirs_text+=",'"+x+"'"
+
+
+gradle_res_dirs_text=""
+
+for x in env.android_res_dirs:
+ gradle_res_dirs_text+=",'"+x+"'"
+
+gradle_aidl_dirs_text=""
+
+for x in env.android_aidl_dirs:
+ gradle_aidl_dirs_text+=",'"+x+"'"
+
+gradle_jni_dirs_text=""
+
+for x in env.android_jni_dirs:
+ gradle_jni_dirs_text+=",'"+x+"'"
+
+gradle_asset_dirs_text=""
+
+gradle_text = gradle_text.replace("$$GRADLE_REPOSITORY_URLS$$",gradle_maven_repos_text)
+gradle_text = gradle_text.replace("$$GRADLE_DEPENDENCIES$$",gradle_maven_dependencies_text)
+gradle_text = gradle_text.replace("$$GRADLE_JAVA_DIRS$$",gradle_java_dirs_text)
+gradle_text = gradle_text.replace("$$GRADLE_RES_DIRS$$",gradle_res_dirs_text)
+gradle_text = gradle_text.replace("$$GRADLE_ASSET_DIRS$$",gradle_asset_dirs_text)
+gradle_text = gradle_text.replace("$$GRADLE_AIDL_DIRS$$",gradle_aidl_dirs_text)
+gradle_text = gradle_text.replace("$$GRADLE_JNI_DIRS$$",gradle_jni_dirs_text)
+
+
+gradle_baseout.write( gradle_text )
+gradle_baseout.close()
pp_basein = open(abspath+"/AndroidManifest.xml.template","rb")
@@ -61,13 +101,6 @@ manifest = manifest.replace("$$ADD_APPATTRIBUTE_CHUNKS$$",env.android_appattribu
pp_baseout.write( manifest )
-for x in env.android_source_files:
- shutil.copy(x,abspath+"/java/src/com/android/godot")
-
-for x in env.android_module_libraries:
- shutil.copy(x,abspath+"/java/libs")
-
-
env_android.SharedLibrary("#bin/libgodot",[android_objects],SHLIBSUFFIX=env["SHLIBSUFFIX"])
#env.Command('#bin/libgodot_android.so', '#platform/android/libgodot_android.so', Copy('bin/libgodot_android.so', 'platform/android/libgodot_android.so'))
diff --git a/platform/android/android_native_app_glue.h b/platform/android/android_native_app_glue.h
index f5ba27ae66..3e7a4ea7a0 100644
--- a/platform/android/android_native_app_glue.h
+++ b/platform/android/android_native_app_glue.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/android/audio_driver_jandroid.cpp b/platform/android/audio_driver_jandroid.cpp
index 1a3a1cb563..6d428e3fe5 100644
--- a/platform/android/audio_driver_jandroid.cpp
+++ b/platform/android/audio_driver_jandroid.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -147,13 +147,13 @@ void AudioDriverAndroid::setup( jobject p_io) {
void AudioDriverAndroid::thread_func(JNIEnv *env) {
- jclass cls = env->FindClass("com/android/godot/Godot");
+ jclass cls = env->FindClass("org/godotengine/godot/Godot");
if (cls) {
cls=(jclass)env->NewGlobalRef(cls);
__android_log_print(ANDROID_LOG_INFO,"godot","*******CLASS FOUND!!!");
}
- jfieldID fid = env->GetStaticFieldID(cls, "io", "Lcom/android/godot/GodotIO;");
+ jfieldID fid = env->GetStaticFieldID(cls, "io", "Lorg/godotengine/godot/GodotIO;");
jobject ob = env->GetStaticObjectField(cls,fid);
jobject gob = env->NewGlobalRef(ob);
jclass c = env->GetObjectClass(gob);
diff --git a/platform/android/audio_driver_jandroid.h b/platform/android/audio_driver_jandroid.h
index bf8584051d..f79057efe5 100644
--- a/platform/android/audio_driver_jandroid.h
+++ b/platform/android/audio_driver_jandroid.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/android/audio_driver_opensl.cpp b/platform/android/audio_driver_opensl.cpp
index a08bc8943c..a908f6193e 100644
--- a/platform/android/audio_driver_opensl.cpp
+++ b/platform/android/audio_driver_opensl.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -236,13 +236,12 @@ void AudioDriverOpenSL::start(){
ERR_FAIL_COND( res !=SL_RESULT_SUCCESS );
/* Initialize arrays required[] and iidArray[] */
- int i;
SLboolean required[MAX_NUMBER_INTERFACES];
SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
#if 0
- for (i=0; i<MAX_NUMBER_INTERFACES; i++)
+ for (int i=0; i<MAX_NUMBER_INTERFACES; i++)
{
required[i] = SL_BOOLEAN_FALSE;
iidArray[i] = SL_IID_NULL;
diff --git a/platform/android/audio_driver_opensl.h b/platform/android/audio_driver_opensl.h
index e9d7c7a7ea..1b04f32fd2 100644
--- a/platform/android/audio_driver_opensl.h
+++ b/platform/android/audio_driver_opensl.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/android/build.gradle.template b/platform/android/build.gradle.template
new file mode 100644
index 0000000000..9461cd2e99
--- /dev/null
+++ b/platform/android/build.gradle.template
@@ -0,0 +1,70 @@
+buildscript {
+ repositories {
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:1.2.0'
+ }
+}
+
+apply plugin: 'com.android.application'
+
+allprojects {
+ repositories {
+ mavenCentral()
+ $$GRADLE_REPOSITORY_URLS$$
+ }
+}
+
+dependencies {
+
+ $$GRADLE_DEPENDENCIES$$
+}
+
+android {
+
+ lintOptions {
+ abortOnError false
+ }
+
+ compileSdkVersion 19
+ buildToolsVersion "19.1"
+
+ packagingOptions {
+ exclude 'META-INF/LICENSE'
+ exclude 'META-INF/NOTICE'
+ }
+ defaultConfig {
+ minSdkVersion 14
+ targetSdkVersion 19
+ }
+ sourceSets {
+ main {
+ manifest.srcFile 'AndroidManifest.xml'
+ java.srcDirs = ['src'
+ $$GRADLE_JAVA_DIRS$$
+ ]
+ resources.srcDirs = [
+ 'res'
+ $$GRADLE_RES_DIRS$$
+ ]
+ res.srcDirs = ['res']
+ // libs.srcDirs = ['libs']
+ aidl.srcDirs = [
+ 'aidl'
+ $$GRADLE_AIDL_DIRS$$
+ ]
+ assets.srcDirs = [
+ 'assets'
+ $$GRADLE_ASSET_DIRS$$
+ ]
+ jniLibs.srcDirs = [
+ 'libs'
+ $$GRADLE_JNI_DIRS$$
+ ]
+ }
+
+ }
+
+
+}
diff --git a/platform/android/cpu-features.c b/platform/android/cpu-features.c
index 156d464729..9cdadd5407 100644
--- a/platform/android/cpu-features.c
+++ b/platform/android/cpu-features.c
@@ -127,7 +127,7 @@ static __inline__ void x86_cpuid(int func, int values[4])
static int
get_file_size(const char* pathname)
{
- int fd, ret, result = 0;
+ int fd, result = 0;
char buffer[256];
fd = open(pathname, O_RDONLY);
diff --git a/platform/android/detect.py b/platform/android/detect.py
index 5ef405f7b6..ee3dc119c2 100644
--- a/platform/android/detect.py
+++ b/platform/android/detect.py
@@ -20,15 +20,14 @@ def can_build():
def get_opts():
return [
- ('ANDROID_NDK_ROOT', 'the path to Android NDK', os.environ.get("ANDROID_NDK_ROOT", 0)),
- ('NDK_TOOLCHAIN', 'toolchain to use for the NDK',"arm-eabi-4.4.0"),
- #android 2.3
- ('ndk_platform', 'compile for platform: (2.2,2.3)',"2.2"),
- ('NDK_TARGET', 'toolchain to use for the NDK',"arm-linux-androideabi-4.8"),
- ('android_stl','enable STL support in android port (for modules)','no'),
- ('armv6','compile for older phones running arm v6 (instead of v7+neon+smp)','no'),
- ('x86','Xompile for Android-x86','no')
-
+ ('ANDROID_NDK_ROOT', 'the path to Android NDK', os.environ.get("ANDROID_NDK_ROOT", 0)),
+ ('NDK_TOOLCHAIN', 'toolchain to use for the NDK',"arm-eabi-4.4.0"),
+ ('NDK_TARGET', 'toolchain to use for the NDK',"arm-linux-androideabi-4.8"),
+ ('NDK_TARGET_X86', 'toolchain to use for the NDK x86',"x86-4.8"),
+ ('ndk_platform', 'compile for platform: (android-<api> , example: android-15)',"android-15"),
+ ('android_arch', 'select compiler architecture: (armv7/armv6/x86)',"armv7"),
+ ('android_neon','enable neon (armv7 only)',"yes"),
+ ('android_stl','enable STL support in android port (for modules)',"no")
]
def get_flags():
@@ -38,8 +37,6 @@ def get_flags():
('nedmalloc', 'no'),
('builtin_zlib', 'no'),
('openssl','builtin'), #use builtin openssl
- ('theora','no'), #use builtin openssl
-
]
@@ -54,31 +51,79 @@ def create(env):
def configure(env):
- if env['x86']=='yes':
- env['NDK_TARGET']='x86-4.8'
+ # Workaround for MinGW. See:
+ # http://www.scons.org/wiki/LongCmdLinesOnWin32
+ import os
+ if (os.name=="nt"):
+
+ import subprocess
+
+ def mySubProcess(cmdline,env):
+ #print "SPAWNED : " + cmdline
+ startupinfo = subprocess.STARTUPINFO()
+ startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
+ proc = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE, startupinfo=startupinfo, shell = False, env = env)
+ data, err = proc.communicate()
+ rv = proc.wait()
+ if rv:
+ print "====="
+ print err
+ print "====="
+ return rv
+
+ def mySpawn(sh, escape, cmd, args, env):
+
+ newargs = ' '.join(args[1:])
+ cmdline = cmd + " " + newargs
+
+ rv=0
+ if len(cmdline) > 32000 and cmd.endswith("ar") :
+ cmdline = cmd + " " + args[1] + " " + args[2] + " "
+ for i in range(3,len(args)) :
+ rv = mySubProcess( cmdline + args[i], env )
+ if rv :
+ break
+ else:
+ rv = mySubProcess( cmdline, env )
+
+ return rv
+
+ env['SPAWN'] = mySpawn
+
+ ndk_platform=env['ndk_platform']
+
+ if env['android_arch'] not in ['armv7','armv6','x86']:
+ env['android_arch']='armv7'
+
+ if env['android_arch']=='x86':
+ env['NDK_TARGET']=env['NDK_TARGET_X86']
+ env["x86_opt_gcc"]=True
if env['PLATFORM'] == 'win32':
import methods
env.Tool('gcc')
- env['SPAWN'] = methods.win32_spawn
+ #env['SPAWN'] = methods.win32_spawn
env['SHLIBSUFFIX'] = '.so'
-# env.android_source_modules.append("../libs/apk_expansion")
- env.android_source_modules.append("../libs/google_play_services")
- env.android_source_modules.append("../libs/downloader_library")
- env.android_source_modules.append("../libs/play_licensing")
-
- ndk_platform=""
-
- ndk_platform="android-15"
- print("Godot Android!!!!!")
+ neon_text=""
+ if env["android_arch"]=="armv7" and env['android_neon']=='yes':
+ neon_text=" (with neon)"
+ print("Godot Android!!!!! ("+env['android_arch']+")"+neon_text)
env.Append(CPPPATH=['#platform/android'])
- if env['x86']=='yes':
- env.extra_suffix=".x86"
-
+ if env['android_arch']=='x86':
+ env.extra_suffix=".x86"+env.extra_suffix
+ elif env['android_arch']=='armv6':
+ env.extra_suffix=".armv6"+env.extra_suffix
+ elif env["android_arch"]=="armv7":
+ if env['android_neon']=='yes':
+ env.extra_suffix=".armv7.neon"+env.extra_suffix
+ else:
+ env.extra_suffix=".armv7"+env.extra_suffix
+
gcc_path=env["ANDROID_NDK_ROOT"]+"/toolchains/"+env["NDK_TARGET"]+"/prebuilt/";
import os
@@ -96,7 +141,7 @@ def configure(env):
env['ENV']['PATH'] = gcc_path+":"+env['ENV']['PATH']
- if env['x86']=='yes':
+ if env['android_arch']=='x86':
env['CC'] = gcc_path+'/i686-linux-android-gcc'
env['CXX'] = gcc_path+'/i686-linux-android-g++'
env['AR'] = gcc_path+"/i686-linux-android-ar"
@@ -109,7 +154,7 @@ def configure(env):
env['RANLIB'] = gcc_path+"/arm-linux-androideabi-ranlib"
env['AS'] = gcc_path+"/arm-linux-androideabi-as"
- if env['x86']=='yes':
+ if env['android_arch']=='x86':
env['ARCH'] = 'arch-x86'
else:
env['ARCH'] = 'arch-arm'
@@ -123,18 +168,23 @@ def configure(env):
env.Append(CPPPATH=[gcc_include])
# env['CCFLAGS'] = string.split('-DNO_THREADS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ -Wno-psabi -march=armv5te -mtune=xscale -msoft-float -fno-exceptions -mthumb -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED ')
- if env['x86']=='yes':
+ env['neon_enabled']=False
+ if env['android_arch']=='x86':
env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -fvisibility=hidden -D__GLIBC__ -Wno-psabi -ftree-vectorize -funsafe-math-optimizations -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED')
- elif env["armv6"]!="no":
+ elif env["android_arch"]=="armv6":
env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -fvisibility=hidden -D__ARM_ARCH_6__ -D__GLIBC__ -Wno-psabi -march=armv6 -mfpu=vfp -mfloat-abi=softfp -funsafe-math-optimizations -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED')
- else:
- env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -fvisibility=hidden -D__ARM_ARCH_7__ -D__GLIBC__ -Wno-psabi -march=armv6 -mfpu=neon -mfloat-abi=softfp -ftree-vectorize -funsafe-math-optimizations -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED')
+ elif env["android_arch"]=="armv7":
+ env['CCFLAGS'] = string.split('-DNO_STATVFS -MMD -MP -MF -fpic -ffunction-sections -funwind-tables -fstack-protector -fvisibility=hidden -D__ARM_ARCH_7__ -D__ARM_ARCH_7A__ -D__GLIBC__ -Wno-psabi -march=armv7-a -mfloat-abi=softfp -ftree-vectorize -funsafe-math-optimizations -fno-strict-aliasing -DANDROID -Wa,--noexecstack -DGLES2_ENABLED')
+ if env['android_neon']=='yes':
+ env['neon_enabled']=True
+ env.Append(CCFLAGS=['-mfpu=neon','-D__ARM_NEON__'])
+ else:
+ env.Append(CCFLAGS=['-mfpu=vfpv3-d16'])
env.Append(LDPATH=[ld_path])
env.Append(LIBS=['OpenSLES'])
# env.Append(LIBS=['c','m','stdc++','log','EGL','GLESv1_CM','GLESv2','OpenSLES','supc++','android'])
- if (env["ndk_platform"]!="2.2"):
- env.Append(LIBS=['EGL','OpenSLES','android'])
+ env.Append(LIBS=['EGL','OpenSLES','android'])
env.Append(LIBS=['c','m','stdc++','log','GLESv1_CM','GLESv2', 'z'])
env["LINKFLAGS"]= string.split(" -g --sysroot="+ld_sysroot+" -Wl,--no-undefined -Wl,-z,noexecstack ")
@@ -153,17 +203,27 @@ def configure(env):
env.Append(CCFLAGS=['-D_DEBUG', '-g1', '-Wall', '-O0', '-DDEBUG_ENABLED'])
env.Append(CPPFLAGS=['-DDEBUG_MEMORY_ALLOC'])
- if env["armv6"] == "no" and env['x86'] != 'yes':
- env['neon_enabled']=True
-
env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED', '-DNO_FCNTL','-DMPC_FIXED_POINT'])
# env.Append(CPPFLAGS=['-DANDROID_ENABLED', '-DUNIX_ENABLED','-DMPC_FIXED_POINT'])
+ if(env["opus"]=="yes"):
+ if (env["android_arch"]=="armv6" or env["android_arch"]=="armv7"):
+ env.Append(CFLAGS=["-DOPUS_ARM_OPT"])
+ env.opus_fixed_point="yes"
+
if (env['android_stl']=='yes'):
#env.Append(CCFLAGS=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/system/include"])
- env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.4.3/include"])
- env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.4.3/libs/armeabi/include"])
- env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.4.3/libs/armeabi"])
+ env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.8/include"])
+ if env['android_arch']=='x86':
+ env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.8/libs/x86/include"])
+ env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.8/libs/x86"])
+ elif env['android_arch']=='armv6':
+ env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi/include"])
+ env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi"])
+ elif env["android_arch"]=="armv7":
+ env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi-v7a/include"])
+ env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi-v7a"])
+
env.Append(LIBS=["gnustl_static","supc++"])
env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cpufeatures"])
@@ -174,10 +234,12 @@ def configure(env):
env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gabi++/include"])
env.Append(CPPPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cpufeatures"])
- if env['x86']=='yes':
+ if env['android_arch']=='x86':
env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gabi++/libs/x86"])
- else:
+ elif env["android_arch"]=="armv6":
env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gabi++/libs/armeabi"])
+ elif env["android_arch"]=="armv7":
+ env.Append(LIBPATH=[env["ANDROID_NDK_ROOT"]+"/sources/cxx-stl/gabi++/libs/armeabi-v7a"])
env.Append(LIBS=['gabi++_static'])
env.Append(CCFLAGS=["-fno-exceptions",'-DNO_SAFE_CAST'])
diff --git a/platform/android/dir_access_android.cpp b/platform/android/dir_access_android.cpp
index ca1e58da3f..85df5dc37a 100644
--- a/platform/android/dir_access_android.cpp
+++ b/platform/android/dir_access_android.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/android/dir_access_android.h b/platform/android/dir_access_android.h
index cbbcdb71bb..9477ca48fd 100644
--- a/platform/android/dir_access_android.h
+++ b/platform/android/dir_access_android.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp
index 2b5fc6a50a..8b7cb992d9 100644
--- a/platform/android/dir_access_jandroid.cpp
+++ b/platform/android/dir_access_jandroid.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -96,7 +96,7 @@ void DirAccessJAndroid::list_dir_end(){
return;
JNIEnv *env = ThreadAndroid::get_env();
- env->CallObjectMethod(io,_dir_close,id);
+ env->CallVoidMethod(io,_dir_close,id);
id=0;
@@ -143,7 +143,7 @@ Error DirAccessJAndroid::change_dir(String p_dir){
if (res<=0)
return ERR_INVALID_PARAMETER;
- env->CallObjectMethod(io,_dir_close,res);
+ env->CallVoidMethod(io,_dir_close,res);
current_dir=new_dir;
diff --git a/platform/android/dir_access_jandroid.h b/platform/android/dir_access_jandroid.h
index 7b6242ca32..356828dcc1 100644
--- a/platform/android/dir_access_jandroid.h
+++ b/platform/android/dir_access_jandroid.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index d169ec51d5..c908f6729b 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -228,7 +228,7 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
String get_package_name();
String get_project_name() const;
- void _fix_manifest(Vector<uint8_t>& p_manifest);
+ void _fix_manifest(Vector<uint8_t>& p_manifest, bool p_give_internet);
void _fix_resources(Vector<uint8_t>& p_manifest);
static Error save_apk_file(void *p_userdata,const String& p_path, const Vector<uint8_t>& p_data,int p_file,int p_total);
@@ -249,11 +249,11 @@ public:
virtual int get_device_count() const;
virtual String get_device_name(int p_device) const;
virtual String get_device_info(int p_device) const;
- virtual Error run(int p_device,bool p_dumb=false);
+ virtual Error run(int p_device,int p_flags=0);
virtual bool requieres_password(bool p_debug) const { return !p_debug; }
virtual String get_binary_extension() const { return "apk"; }
- virtual Error export_project(const String& p_path,bool p_debug,bool p_dumb=false);
+ virtual Error export_project(const String& p_path, bool p_debug, int p_flags=0);
virtual bool can_export(String *r_error=NULL) const;
@@ -317,7 +317,7 @@ bool EditorExportPlatformAndroid::_set(const StringName& p_name, const Variant&
apk_expansion_pkey=p_value;
else if (n.begins_with("permissions/")) {
- String what = n.get_slice("/",1).to_upper();
+ String what = n.get_slicec('/',1).to_upper();
bool state = p_value;
if (state)
perms.insert(what);
@@ -325,7 +325,7 @@ bool EditorExportPlatformAndroid::_set(const StringName& p_name, const Variant&
perms.erase(what);
} else if (n.begins_with("user_permissions/")) {
- int which = n.get_slice("/",1).to_int();
+ int which = n.get_slicec('/',1).to_int();
ERR_FAIL_INDEX_V(which,MAX_USER_PERMISSIONS,false);
user_perms[which]=p_value;
@@ -390,11 +390,11 @@ bool EditorExportPlatformAndroid::_get(const StringName& p_name,Variant &r_ret)
r_ret=apk_expansion_pkey;
else if (n.begins_with("permissions/")) {
- String what = n.get_slice("/",1).to_upper();
+ String what = n.get_slicec('/',1).to_upper();
r_ret = perms.has(what);
} else if (n.begins_with("user_permissions/")) {
- int which = n.get_slice("/",1).to_int();
+ int which = n.get_slicec('/',1).to_int();
ERR_FAIL_INDEX_V(which,MAX_USER_PERMISSIONS,false);
r_ret=user_perms[which];
} else
@@ -608,7 +608,7 @@ String EditorExportPlatformAndroid::get_project_name() const {
}
-void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest) {
+void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest,bool p_give_internet) {
const int CHUNK_AXML_FILE = 0x00080003;
@@ -838,7 +838,10 @@ void EditorExportPlatformAndroid::_fix_manifest(Vector<uint8_t>& p_manifest) {
} else if (value.begins_with("godot.")) {
String perm = value.get_slice(".",1);
- if (perms.has(perm)) {
+ print_line("PERM: "+perm+" HAS: "+itos(perms.has(perm)));
+
+ if (perms.has(perm) || (p_give_internet && perm=="INTERNET")) {
+
string_table[attr_value]="android.permission."+perm;
}
@@ -1011,24 +1014,30 @@ Error EditorExportPlatformAndroid::save_apk_file(void *p_userdata,const String&
-Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_debug, bool p_dumb) {
+Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_debug, int p_flags) {
String src_apk;
EditorProgress ep("export","Exporting for Android",104);
- String apk_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/";
-
- if (p_debug) {
-
- src_apk=custom_debug_package!=""?custom_debug_package:apk_path+"android_debug.apk";
- } else {
-
- src_apk=custom_release_package!=""?custom_release_package:apk_path+"android_release.apk";
+ if (p_debug)
+ src_apk=custom_debug_package;
+ else
+ src_apk=custom_release_package;
+ if (src_apk=="") {
+ String err;
+ if (p_debug) {
+ src_apk=find_export_template("android_debug.apk", &err);
+ } else {
+ src_apk=find_export_template("android_release.apk", &err);
+ }
+ if (src_apk=="") {
+ EditorNode::add_io_error(err);
+ return ERR_FILE_NOT_FOUND;
+ }
}
-
FileAccess *src_f=NULL;
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
@@ -1075,7 +1084,7 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
if (file=="AndroidManifest.xml") {
- _fix_manifest(data);
+ _fix_manifest(data,p_flags&(EXPORT_DUMB_CLIENT|EXPORT_REMOTE_DEBUG));
}
if (file=="resources.arsc") {
@@ -1120,6 +1129,10 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
if (file=="lib/armeabi/libgodot_android.so" && !export_arm) {
skip=true;
}
+
+ if (file.begins_with("META-INF") && _signed) {
+ skip=true;
+ }
print_line("ADDING: "+file);
@@ -1153,9 +1166,11 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
}
}
- if (p_dumb) {
+ gen_export_flags(cl,p_flags);
- String host = EditorSettings::get_singleton()->get("file_server/host");
+ if (p_flags) {
+
+ /*String host = EditorSettings::get_singleton()->get("file_server/host");
int port = EditorSettings::get_singleton()->get("file_server/post");
String passwd = EditorSettings::get_singleton()->get("file_server/password");
cl.push_back("-rfs");
@@ -1163,7 +1178,7 @@ Error EditorExportPlatformAndroid::export_project(const String& p_path, bool p_d
if (passwd!="") {
cl.push_back("-rfs_pass");
cl.push_back(passwd);
- }
+ }*/
} else {
@@ -1480,7 +1495,7 @@ void EditorExportPlatformAndroid::_device_poll_thread(void *ud) {
}
-Error EditorExportPlatformAndroid::run(int p_device, bool p_dumb) {
+Error EditorExportPlatformAndroid::run(int p_device, int p_flags) {
ERR_FAIL_INDEX_V(p_device,devices.size(),ERR_INVALID_PARAMETER);
device_lock->lock();
@@ -1499,7 +1514,7 @@ Error EditorExportPlatformAndroid::run(int p_device, bool p_dumb) {
ep.step("Exporting APK",0);
String export_to=EditorSettings::get_singleton()->get_settings_path()+"/tmp/tmpexport.apk";
- Error err = export_project(export_to,true,p_dumb);
+ Error err = export_project(export_to,true,p_flags);
if (err) {
device_lock->unlock();
return err;
@@ -1554,7 +1569,7 @@ Error EditorExportPlatformAndroid::run(int p_device, bool p_dumb) {
args.push_back("-a");
args.push_back("android.intent.action.MAIN");
args.push_back("-n");
- args.push_back(get_package_name()+"/com.android.godot.Godot");
+ args.push_back(get_package_name()+"/org.godotengine.godot.Godot");
err = OS::get_singleton()->execute(adb,args,true,NULL,NULL,&rv);
if (err || rv!=0) {
@@ -1650,10 +1665,7 @@ bool EditorExportPlatformAndroid::can_export(String *r_error) const {
err+="Debug Keystore not configured in editor settings.\n";
}
-
- String exe_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/";
-
- if (!FileAccess::exists(exe_path+"android_debug.apk") || !FileAccess::exists(exe_path+"android_release.apk")) {
+ if (!exists_export_template("android_debug.apk") || !exists_export_template("android_release.apk")) {
valid=false;
err+="No export templates found.\nDownload and install export templates.\n";
}
diff --git a/platform/android/file_access_android.cpp b/platform/android/file_access_android.cpp
index da3a37fb42..7a038cca64 100644
--- a/platform/android/file_access_android.cpp
+++ b/platform/android/file_access_android.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,16 +29,16 @@
#include "file_access_android.h"
#include "print_string.h"
-#ifdef ANDROID_NATIVE_ACTIVITY
+
AAssetManager *FileAccessAndroid::asset_manager=NULL;
-void FileAccessAndroid::make_default() {
+/*void FileAccessAndroid::make_default() {
create_func=create_android;
-}
+}*/
FileAccess* FileAccessAndroid::create_android() {
@@ -46,7 +46,7 @@ FileAccess* FileAccessAndroid::create_android() {
}
-Error FileAccessAndroid::open(const String& p_path, int p_mode_flags) {
+Error FileAccessAndroid::_open(const String& p_path, int p_mode_flags) {
String path=fix_path(p_path).simplify_path();
if (path.begins_with("/"))
@@ -55,7 +55,6 @@ Error FileAccessAndroid::open(const String& p_path, int p_mode_flags) {
path=path.substr(6,path.length());
-
ERR_FAIL_COND_V(p_mode_flags&FileAccess::WRITE,ERR_UNAVAILABLE); //can't write on android..
a=AAssetManager_open(asset_manager,path.utf8().get_data(),AASSET_MODE_STREAMING);
if (!a)
@@ -133,12 +132,18 @@ int FileAccessAndroid::get_buffer(uint8_t *p_dst, int p_length) const {
off_t r = AAsset_read(a,p_dst,p_length);
+
+ if (pos+p_length >len ) {
+ eof=true;
+ }
+
if (r>=0) {
+
pos+=r;
if (pos>len) {
pos=len;
- eof=true;
}
+
}
return r;
@@ -184,4 +189,4 @@ FileAccessAndroid::~FileAccessAndroid()
{
close();
}
-#endif
+
diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h
index f477920ae9..3fcd7836c3 100644
--- a/platform/android/file_access_android.h
+++ b/platform/android/file_access_android.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,14 +29,13 @@
#ifndef FILE_ACCESS_ANDROID_H
#define FILE_ACCESS_ANDROID_H
-#ifdef ANDROID_NATIVE_ACTIVITY
#include "os/file_access.h"
#include <stdio.h>
#include <android/asset_manager.h>
#include <android/log.h>
-#include <android_native_app_glue.h>
+//#include <android_native_app_glue.h>
class FileAccessAndroid : public FileAccess {
@@ -51,7 +50,7 @@ public:
static AAssetManager *asset_manager;
- virtual Error open(const String& p_path, int p_mode_flags); ///< open a file
+ virtual Error _open(const String& p_path, int p_mode_flags); ///< open a file
virtual void close(); ///< close a file
virtual bool is_open() const; ///< true when file is open
@@ -71,12 +70,13 @@ public:
virtual bool file_exists(const String& p_path); ///< return true if a file exists
+ virtual uint64_t _get_modified_time(const String& p_file) { return 0; }
- static void make_default();
+ //static void make_default();
FileAccessAndroid();
~FileAccessAndroid();
};
#endif // FILE_ACCESS_ANDROID_H
-#endif
+
diff --git a/platform/android/file_access_jandroid.cpp b/platform/android/file_access_jandroid.cpp
index 971d4f84ab..b1b758edb1 100644
--- a/platform/android/file_access_jandroid.cpp
+++ b/platform/android/file_access_jandroid.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -62,13 +62,15 @@ Error FileAccessJAndroid::_open(const String& p_path, int p_mode_flags) {
JNIEnv *env = ThreadAndroid::get_env();
- //OS::get_singleton()->print("env: %p, io %p, fo: %p\n",env,io,_file_open);
jstring js = env->NewStringUTF(path.utf8().get_data());
int res = env->CallIntMethod(io,_file_open,js,p_mode_flags&WRITE?true:false);
env->DeleteLocalRef(js);
+ OS::get_singleton()->print("fopen: '%s' ret %i\n",path.utf8().get_data(),res);
+
+
if (res<=0)
return ERR_FILE_CANT_OPEN;
id=res;
diff --git a/platform/android/file_access_jandroid.h b/platform/android/file_access_jandroid.h
index 13ac4e17b8..d576af93d6 100644
--- a/platform/android/file_access_jandroid.h
+++ b/platform/android/file_access_jandroid.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/android/godot_android.cpp b/platform/android/godot_android.cpp
index 388ff06c10..f9feb3481f 100644
--- a/platform/android/godot_android.cpp
+++ b/platform/android/godot_android.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -50,9 +50,9 @@
extern "C" {
- JNIEXPORT void JNICALL Java_com_android_godot_Godot_registerSingleton(JNIEnv * env, jobject obj, jstring name,jobject p_object);
- JNIEXPORT void JNICALL Java_com_android_godot_Godot_registerMethod(JNIEnv * env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args);
- JNIEXPORT jstring JNICALL Java_com_android_godot_Godot_getGlobal(JNIEnv * env, jobject obj, jstring path);
+ JNIEXPORT void JNICALL Java_org_godotengine_godot_Godot_registerSingleton(JNIEnv * env, jobject obj, jstring name,jobject p_object);
+ JNIEXPORT void JNICALL Java_org_godotengine_godot_Godot_registerMethod(JNIEnv * env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args);
+ JNIEXPORT jstring JNICALL Java_org_godotengine_godot_Godot_getGlobal(JNIEnv * env, jobject obj, jstring path);
};
class JNISingleton : public Object {
@@ -671,12 +671,12 @@ static void engine_handle_cmd(struct android_app* app, int32_t cmd) {
static JNINativeMethod methods[] = {
- {"registerSingleton", "(Ljava/lang/String;Ljava/lang/Object;)V",(void *)&Java_com_android_godot_Godot_registerSingleton},
- {"registerMethod", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V",(void *)&Java_com_android_godot_Godot_registerMethod},
- {"getGlobal", "(Ljava/lang/String;)Ljava/lang/String;", (void *)&Java_com_android_godot_Godot_getGlobal},
+ {"registerSingleton", "(Ljava/lang/String;Ljava/lang/Object;)V",(void *)&Java_org_godotengine_godot_Godot_registerSingleton},
+ {"registerMethod", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V",(void *)&Java_org_godotengine_godot_Godot_registerMethod},
+ {"getGlobal", "(Ljava/lang/String;)Ljava/lang/String;", (void *)&Java_org_godotengine_godot_Godot_getGlobal},
};
- jstring gstrClassName = engine->jni->NewStringUTF("com/android/godot/Godot");
+ jstring gstrClassName = engine->jni->NewStringUTF("org/godotengine/godot/Godot");
jclass GodotClass = (jclass)engine->jni->CallObjectMethod(cls, findClass, gstrClassName);
__android_log_print(ANDROID_LOG_INFO,"godot","godot ****^*^*?^*^*class data %x",GodotClass);
@@ -692,7 +692,7 @@ static void engine_handle_cmd(struct android_app* app, int32_t cmd) {
jclass singletonClass = (jclass)engine->jni->CallObjectMethod(cls, findClass, strClassName);
__android_log_print(ANDROID_LOG_INFO,"godot","****^*^*?^*^*class data %x",singletonClass);
- jmethodID initialize = engine->jni->GetStaticMethodID(singletonClass, "initialize", "(Landroid/app/Activity;)Lcom/android/godot/Godot$SingletonBase;");
+ jmethodID initialize = engine->jni->GetStaticMethodID(singletonClass, "initialize", "(Landroid/app/Activity;)Lorg/godotengine/godot/Godot$SingletonBase;");
jobject obj = engine->jni->CallStaticObjectMethod(singletonClass,initialize,app->activity->clazz);
@@ -863,7 +863,7 @@ void android_main(struct android_app* state) {
-JNIEXPORT void JNICALL Java_com_android_godot_Godot_registerSingleton(JNIEnv * env, jobject obj, jstring name,jobject p_object){
+JNIEXPORT void JNICALL Java_org_godotengine_godot_Godot_registerSingleton(JNIEnv * env, jobject obj, jstring name,jobject p_object){
String singname = env->GetStringUTFChars( name, NULL );
JNISingleton *s = memnew( JNISingleton );
@@ -938,7 +938,7 @@ static const char* get_jni_sig(const String& p_type) {
return "";
}
-JNIEXPORT jstring JNICALL Java_com_android_godot_Godot_getGlobal(JNIEnv * env, jobject obj, jstring path) {
+JNIEXPORT jstring JNICALL Java_org_godotengine_godot_Godot_getGlobal(JNIEnv * env, jobject obj, jstring path) {
String js = env->GetStringUTFChars( path, NULL );
@@ -949,7 +949,7 @@ JNIEXPORT jstring JNICALL Java_com_android_godot_Godot_getGlobal(JNIEnv * env, j
-JNIEXPORT void JNICALL Java_com_android_godot_Godot_registerMethod(JNIEnv * env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args){
+JNIEXPORT void JNICALL Java_org_godotengine_godot_Godot_registerMethod(JNIEnv * env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args){
String singname = env->GetStringUTFChars( sname, NULL );
diff --git a/platform/android/java/aidl/com/android/vending/billing/IInAppBillingService.aidl b/platform/android/java/aidl/com/android/vending/billing/IInAppBillingService.aidl
new file mode 100644
index 0000000000..2a492f7845
--- /dev/null
+++ b/platform/android/java/aidl/com/android/vending/billing/IInAppBillingService.aidl
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.vending.billing;
+
+import android.os.Bundle;
+
+/**
+ * InAppBillingService is the service that provides in-app billing version 3 and beyond.
+ * This service provides the following features:
+ * 1. Provides a new API to get details of in-app items published for the app including
+ * price, type, title and description.
+ * 2. The purchase flow is synchronous and purchase information is available immediately
+ * after it completes.
+ * 3. Purchase information of in-app purchases is maintained within the Google Play system
+ * till the purchase is consumed.
+ * 4. An API to consume a purchase of an inapp item. All purchases of one-time
+ * in-app items are consumable and thereafter can be purchased again.
+ * 5. An API to get current purchases of the user immediately. This will not contain any
+ * consumed purchases.
+ *
+ * All calls will give a response code with the following possible values
+ * RESULT_OK = 0 - success
+ * RESULT_USER_CANCELED = 1 - user pressed back or canceled a dialog
+ * RESULT_BILLING_UNAVAILABLE = 3 - this billing API version is not supported for the type requested
+ * RESULT_ITEM_UNAVAILABLE = 4 - requested SKU is not available for purchase
+ * RESULT_DEVELOPER_ERROR = 5 - invalid arguments provided to the API
+ * RESULT_ERROR = 6 - Fatal error during the API action
+ * RESULT_ITEM_ALREADY_OWNED = 7 - Failure to purchase since item is already owned
+ * RESULT_ITEM_NOT_OWNED = 8 - Failure to consume since item is not owned
+ */
+interface IInAppBillingService {
+ /**
+ * Checks support for the requested billing API version, package and in-app type.
+ * Minimum API version supported by this interface is 3.
+ * @param apiVersion the billing version which the app is using
+ * @param packageName the package name of the calling app
+ * @param type type of the in-app item being purchased "inapp" for one-time purchases
+ * and "subs" for subscription.
+ * @return RESULT_OK(0) on success, corresponding result code on failures
+ */
+ int isBillingSupported(int apiVersion, String packageName, String type);
+
+ /**
+ * Provides details of a list of SKUs
+ * Given a list of SKUs of a valid type in the skusBundle, this returns a bundle
+ * with a list JSON strings containing the productId, price, title and description.
+ * This API can be called with a maximum of 20 SKUs.
+ * @param apiVersion billing API version that the Third-party is using
+ * @param packageName the package name of the calling app
+ * @param skusBundle bundle containing a StringArrayList of SKUs with key "ITEM_ID_LIST"
+ * @return Bundle containing the following key-value pairs
+ * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
+ * failure as listed above.
+ * "DETAILS_LIST" with a StringArrayList containing purchase information
+ * in JSON format similar to:
+ * '{ "productId" : "exampleSku", "type" : "inapp", "price" : "$5.00",
+ * "title : "Example Title", "description" : "This is an example description" }'
+ */
+ Bundle getSkuDetails(int apiVersion, String packageName, String type, in Bundle skusBundle);
+
+ /**
+ * Returns a pending intent to launch the purchase flow for an in-app item by providing a SKU,
+ * the type, a unique purchase token and an optional developer payload.
+ * @param apiVersion billing API version that the app is using
+ * @param packageName package name of the calling app
+ * @param sku the SKU of the in-app item as published in the developer console
+ * @param type the type of the in-app item ("inapp" for one-time purchases
+ * and "subs" for subscription).
+ * @param developerPayload optional argument to be sent back with the purchase information
+ * @return Bundle containing the following key-value pairs
+ * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
+ * failure as listed above.
+ * "BUY_INTENT" - PendingIntent to start the purchase flow
+ *
+ * The Pending intent should be launched with startIntentSenderForResult. When purchase flow
+ * has completed, the onActivityResult() will give a resultCode of OK or CANCELED.
+ * If the purchase is successful, the result data will contain the following key-value pairs
+ * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
+ * failure as listed above.
+ * "INAPP_PURCHASE_DATA" - String in JSON format similar to
+ * '{"orderId":"12999763169054705758.1371079406387615",
+ * "packageName":"com.example.app",
+ * "productId":"exampleSku",
+ * "purchaseTime":1345678900000,
+ * "purchaseToken" : "122333444455555",
+ * "developerPayload":"example developer payload" }'
+ * "INAPP_DATA_SIGNATURE" - String containing the signature of the purchase data that
+ * was signed with the private key of the developer
+ * TODO: change this to app-specific keys.
+ */
+ Bundle getBuyIntent(int apiVersion, String packageName, String sku, String type,
+ String developerPayload);
+
+ /**
+ * Returns the current SKUs owned by the user of the type and package name specified along with
+ * purchase information and a signature of the data to be validated.
+ * This will return all SKUs that have been purchased in V3 and managed items purchased using
+ * V1 and V2 that have not been consumed.
+ * @param apiVersion billing API version that the app is using
+ * @param packageName package name of the calling app
+ * @param type the type of the in-app items being requested
+ * ("inapp" for one-time purchases and "subs" for subscription).
+ * @param continuationToken to be set as null for the first call, if the number of owned
+ * skus are too many, a continuationToken is returned in the response bundle.
+ * This method can be called again with the continuation token to get the next set of
+ * owned skus.
+ * @return Bundle containing the following key-value pairs
+ * "RESPONSE_CODE" with int value, RESULT_OK(0) if success, other response codes on
+ * failure as listed above.
+ * "INAPP_PURCHASE_ITEM_LIST" - StringArrayList containing the list of SKUs
+ * "INAPP_PURCHASE_DATA_LIST" - StringArrayList containing the purchase information
+ * "INAPP_DATA_SIGNATURE_LIST"- StringArrayList containing the signatures
+ * of the purchase information
+ * "INAPP_CONTINUATION_TOKEN" - String containing a continuation token for the
+ * next set of in-app purchases. Only set if the
+ * user has more owned skus than the current list.
+ */
+ Bundle getPurchases(int apiVersion, String packageName, String type, String continuationToken);
+
+ /**
+ * Consume the last purchase of the given SKU. This will result in this item being removed
+ * from all subsequent responses to getPurchases() and allow re-purchase of this item.
+ * @param apiVersion billing API version that the app is using
+ * @param packageName package name of the calling app
+ * @param purchaseToken token in the purchase information JSON that identifies the purchase
+ * to be consumed
+ * @return 0 if consumption succeeded. Appropriate error values for failures.
+ */
+ int consumePurchase(int apiVersion, String packageName, String purchaseToken);
+}
diff --git a/platform/android/java/ant.properties b/platform/android/java/ant.properties
deleted file mode 100644
index b0971e891e..0000000000
--- a/platform/android/java/ant.properties
+++ /dev/null
@@ -1,17 +0,0 @@
-# This file is used to override default values used by the Ant build system.
-#
-# This file must be checked into Version Control Systems, as it is
-# integral to the build system of your project.
-
-# This file is only used by the Ant script.
-
-# You can use this to override default values such as
-# 'source.dir' for the location of your java source folder and
-# 'out.dir' for the location of your output folder.
-
-# You can also use it define how the release builds are signed by declaring
-# the following properties:
-# 'key.store' for the location of your keystore and
-# 'key.alias' for the name of the key to use.
-# The password will be asked during the build when you use the 'release' target.
-
diff --git a/platform/android/java/build.properties b/platform/android/java/build.properties
deleted file mode 100644
index ee52d86d94..0000000000
--- a/platform/android/java/build.properties
+++ /dev/null
@@ -1,17 +0,0 @@
-# This file is used to override default values used by the Ant build system.
-#
-# This file must be checked in Version Control Systems, as it is
-# integral to the build system of your project.
-
-# This file is only used by the Ant script.
-
-# You can use this to override default values such as
-# 'source.dir' for the location of your java source folder and
-# 'out.dir' for the location of your output folder.
-
-# You can also use it define how the release builds are signed by declaring
-# the following properties:
-# 'key.store' for the location of your keystore and
-# 'key.alias' for the name of the key to use.
-# The password will be asked during the build when you use the 'release' target.
-
diff --git a/platform/android/java/build.xml b/platform/android/java/build.xml
deleted file mode 100644
index 424e2827dc..0000000000
--- a/platform/android/java/build.xml
+++ /dev/null
@@ -1,92 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project name="Godot" default="help">
-
- <!-- The local.properties file is created and updated by the 'android' tool.
- It contains the path to the SDK. It should *NOT* be checked into
- Version Control Systems. -->
- <property file="local.properties" />
-
- <!-- The ant.properties file can be created by you. It is only edited by the
- 'android' tool to add properties to it.
- This is the place to change some Ant specific build properties.
- Here are some properties you may want to change/update:
-
- source.dir
- The name of the source directory. Default is 'src'.
- out.dir
- The name of the output directory. Default is 'bin'.
-
- For other overridable properties, look at the beginning of the rules
- files in the SDK, at tools/ant/build.xml
-
- Properties related to the SDK location or the project target should
- be updated using the 'android' tool with the 'update' action.
-
- This file is an integral part of the build system for your
- application and should be checked into Version Control Systems.
-
- -->
- <property file="ant.properties" />
-
- <!-- if sdk.dir was not set from one of the property file, then
- get it from the ANDROID_HOME env var.
- This must be done before we load project.properties since
- the proguard config can use sdk.dir -->
- <property environment="env" />
- <condition property="sdk.dir" value="${env.ANDROID_HOME}">
- <isset property="env.ANDROID_HOME" />
- </condition>
-
- <!-- The project.properties file is created and updated by the 'android'
- tool, as well as ADT.
-
- This contains project specific properties such as project target, and library
- dependencies. Lower level build properties are stored in ant.properties
- (or in .classpath for Eclipse projects).
-
- This file is an integral part of the build system for your
- application and should be checked into Version Control Systems. -->
- <loadproperties srcFile="project.properties" />
-
- <!-- quick check on sdk.dir -->
- <fail
- message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
- unless="sdk.dir"
- />
-
- <!--
- Import per project custom build rules if present at the root of the project.
- This is the place to put custom intermediary targets such as:
- -pre-build
- -pre-compile
- -post-compile (This is typically used for code obfuscation.
- Compiled code location: ${out.classes.absolute.dir}
- If this is not done in place, override ${out.dex.input.absolute.dir})
- -post-package
- -post-build
- -pre-clean
- -->
- <import file="custom_rules.xml" optional="true" />
-
- <!-- Import the actual build file.
-
- To customize existing targets, there are two options:
- - Customize only one target:
- - copy/paste the target into this file, *before* the
- <import> task.
- - customize it to your needs.
- - Customize the whole content of build.xml
- - copy/paste the content of the rules files (minus the top node)
- into this file, replacing the <import> task.
- - customize to your needs.
-
- ***********************
- ****** IMPORTANT ******
- ***********************
- In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
- in order to avoid having your file be overridden by tools such as "android update project"
- -->
- <!-- version-tag: 1 -->
- <import file="${sdk.dir}/tools/ant/build.xml" />
-
-</project>
diff --git a/platform/android/java/default.properties b/platform/android/java/default.properties
deleted file mode 100644
index e2e8061f26..0000000000
--- a/platform/android/java/default.properties
+++ /dev/null
@@ -1,11 +0,0 @@
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must be checked in Version Control Systems.
-#
-# To customize properties used by the Ant build system use,
-# "build.properties", and override values to adapt the script to your
-# project structure.
-
-# Project target.
-target=android-8
diff --git a/platform/android/java/gradle/wrapper/gradle-wrapper.jar b/platform/android/java/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000..8c0fb64a86
--- /dev/null
+++ b/platform/android/java/gradle/wrapper/gradle-wrapper.jar
Binary files differ
diff --git a/platform/android/java/gradle/wrapper/gradle-wrapper.properties b/platform/android/java/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000000..0c71e760dc
--- /dev/null
+++ b/platform/android/java/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Wed Apr 10 15:27:10 PDT 2013
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
diff --git a/platform/android/java/gradlew b/platform/android/java/gradlew
new file mode 100755
index 0000000000..91a7e269e1
--- /dev/null
+++ b/platform/android/java/gradlew
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/platform/android/java/gradlew.bat b/platform/android/java/gradlew.bat
new file mode 100644
index 0000000000..aec99730b4
--- /dev/null
+++ b/platform/android/java/gradlew.bat
@@ -0,0 +1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/platform/android/java/my-release-key.keystore b/platform/android/java/my-release-key.keystore
deleted file mode 100644
index 410cccd865..0000000000
--- a/platform/android/java/my-release-key.keystore
+++ /dev/null
Binary files differ
diff --git a/platform/android/java/proguard-project.txt b/platform/android/java/proguard-project.txt
deleted file mode 100644
index f2fe1559a2..0000000000
--- a/platform/android/java/proguard-project.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-# To enable ProGuard in your project, edit project.properties
-# to define the proguard.config property as described in that file.
-#
-# Add project specific ProGuard rules here.
-# By default, the flags in this file are appended to flags specified
-# in ${sdk.dir}/tools/proguard/proguard-android.txt
-# You can edit the include path and order by changing the ProGuard
-# include property in project.properties.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# Add any project specific keep options here:
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
diff --git a/platform/android/java/proguard.cfg b/platform/android/java/proguard.cfg
deleted file mode 100644
index 12dd0392c0..0000000000
--- a/platform/android/java/proguard.cfg
+++ /dev/null
@@ -1,36 +0,0 @@
--optimizationpasses 5
--dontusemixedcaseclassnames
--dontskipnonpubliclibraryclasses
--dontpreverify
--verbose
--optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
-
--keep public class * extends android.app.Activity
--keep public class * extends android.app.Application
--keep public class * extends android.app.Service
--keep public class * extends android.content.BroadcastReceiver
--keep public class * extends android.content.ContentProvider
--keep public class * extends android.app.backup.BackupAgentHelper
--keep public class * extends android.preference.Preference
--keep public class com.android.vending.licensing.ILicensingService
-
--keepclasseswithmembernames class * {
- native <methods>;
-}
-
--keepclasseswithmembernames class * {
- public <init>(android.content.Context, android.util.AttributeSet);
-}
-
--keepclasseswithmembernames class * {
- public <init>(android.content.Context, android.util.AttributeSet, int);
-}
-
--keepclassmembers enum * {
- public static **[] values();
- public static ** valueOf(java.lang.String);
-}
-
--keep class * implements android.os.Parcelable {
- public static final android.os.Parcelable$Creator *;
-}
diff --git a/platform/android/libs/apk_expansion/res/drawable-hdpi/notify_panel_notification_icon_bg.png b/platform/android/java/res/drawable-hdpi/notify_panel_notification_icon_bg.png
index f5b762ecf3..f5b762ecf3 100644
--- a/platform/android/libs/apk_expansion/res/drawable-hdpi/notify_panel_notification_icon_bg.png
+++ b/platform/android/java/res/drawable-hdpi/notify_panel_notification_icon_bg.png
Binary files differ
diff --git a/platform/android/libs/apk_expansion/res/drawable-mdpi/notify_panel_notification_icon_bg.png b/platform/android/java/res/drawable-mdpi/notify_panel_notification_icon_bg.png
index 9ecb8af06c..9ecb8af06c 100644
--- a/platform/android/libs/apk_expansion/res/drawable-mdpi/notify_panel_notification_icon_bg.png
+++ b/platform/android/java/res/drawable-mdpi/notify_panel_notification_icon_bg.png
Binary files differ
diff --git a/platform/android/java/res/drawable/icon.png b/platform/android/java/res/drawable/icon.png
index 78757e9035..013632ddf1 100644
--- a/platform/android/java/res/drawable/icon.png
+++ b/platform/android/java/res/drawable/icon.png
Binary files differ
diff --git a/platform/android/libs/apk_expansion/res/layout/status_bar_ongoing_event_progress_bar.xml b/platform/android/java/res/layout/status_bar_ongoing_event_progress_bar.xml
index 23bac02294..23bac02294 100644
--- a/platform/android/libs/apk_expansion/res/layout/status_bar_ongoing_event_progress_bar.xml
+++ b/platform/android/java/res/layout/status_bar_ongoing_event_progress_bar.xml
diff --git a/platform/android/java/res/values-fa/strings.xml b/platform/android/java/res/values-fa/strings.xml
new file mode 100644
index 0000000000..450f9fe212
--- /dev/null
+++ b/platform/android/java/res/values-fa/strings.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="godot_project_name_string">godot-project-name-fa</string>
+ <string name="testuf8">سلام</string>
+ <string name="text_paused_cellular">آیا می خواهید بر روی اتصال داده همراه دانلود را شروع کنید؟ بر اساس نوع سطح داده شما این ممکن است برای شما هزینه مالی داشته باشد.</string>
+ <string name="text_paused_cellular_2">اگر نمی خواهید بر روی اتصال داده همراه دانلود را شروع کنید ، دانلود به صورت خودکار در زمان دسترسی به وای-فای شروع می شود.</string>
+ <string name="text_button_resume_cellular">ادامه دانلود</string>
+ <string name="text_button_wifi_settings">تنظیمات وای-فای</string>
+ <string name="text_verifying_download">درحال تایید دانلود</string>
+ <string name="text_validation_complete">تایید فایل XAPK تکمیل شد. برای خروج تایید کنید.</string>
+ <string name="text_validation_failed">اعتبارسنجی فایل XAPK ناموق.</string>
+ <string name="text_button_pause">توقف دانلود</string>
+ <string name="text_button_resume">ادامه دانلود</string>
+ <string name="text_button_cancel">انصراف</string>
+ <string name="text_button_cancel_verify">انصراف از تایید شدن</string>
+</resources>
diff --git a/platform/android/libs/apk_expansion/res/values-v11/styles.xml b/platform/android/java/res/values-v11/styles.xml
index f2013bc0bf..f2013bc0bf 100644
--- a/platform/android/libs/apk_expansion/res/values-v11/styles.xml
+++ b/platform/android/java/res/values-v11/styles.xml
diff --git a/platform/android/libs/apk_expansion/res/values-v9/styles.xml b/platform/android/java/res/values-v9/styles.xml
index 736e77a5d6..736e77a5d6 100644
--- a/platform/android/libs/apk_expansion/res/values-v9/styles.xml
+++ b/platform/android/java/res/values-v9/styles.xml
diff --git a/platform/android/java/res/values/strings.xml b/platform/android/java/res/values/strings.xml
index 49ebcc06f9..e1dbdfc062 100644
--- a/platform/android/java/res/values/strings.xml
+++ b/platform/android/java/res/values/strings.xml
@@ -14,4 +14,44 @@
<string name="text_button_resume">Resume Download</string>
<string name="text_button_cancel">Cancel</string>
<string name="text_button_cancel_verify">Cancel Verification</string>
-</resources>
+
+ <!-- APK Expansion Strings -->
+
+ <!-- When a download completes, a notification is displayed, and this
+ string is used to indicate that the download successfully completed.
+ Note that such a download could have been initiated by a variety of
+ applications, including (but not limited to) the browser, an email
+ application, a content marketplace. -->
+ <string name="notification_download_complete">Download complete</string>
+
+ <!-- When a download completes, a notification is displayed, and this
+ string is used to indicate that the download failed.
+ Note that such a download could have been initiated by a variety of
+ applications, including (but not limited to) the browser, an email
+ application, a content marketplace. -->
+ <string name="notification_download_failed">Download unsuccessful</string>
+
+
+ <string name="state_unknown">Starting..."</string>
+ <string name="state_idle">Waiting for download to start</string>
+ <string name="state_fetching_url">Looking for resources to download</string>
+ <string name="state_connecting">Connecting to the download server</string>
+ <string name="state_downloading">Downloading resources</string>
+ <string name="state_completed">Download finished</string>
+ <string name="state_paused_network_unavailable">Download paused because no network is available</string>
+ <string name="state_paused_network_setup_failure">Download paused. Test a website in browser</string>
+ <string name="state_paused_by_request">Download paused</string>
+ <string name="state_paused_wifi_unavailable">Download paused because wifi is unavailable</string>
+ <string name="state_paused_wifi_disabled">Download paused because wifi is disabled</string>
+ <string name="state_paused_roaming">Download paused because you are roaming</string>
+ <string name="state_paused_sdcard_unavailable">Download paused because the external storage is unavailable</string>
+ <string name="state_failed_unlicensed">Download failed because you may not have purchased this app</string>
+ <string name="state_failed_fetching_url">Download failed because the resources could not be found</string>
+ <string name="state_failed_sdcard_full">Download failed because the external storage is full</string>
+ <string name="state_failed_cancelled">Download cancelled</string>
+ <string name="state_failed">Download failed</string>
+
+ <string name="kilobytes_per_second">%1$s KB/s</string>
+ <string name="time_remaining">Time remaining: %1$s</string>
+ <string name="time_remaining_notification">%1$s left</string>
+</resources> \ No newline at end of file
diff --git a/platform/android/libs/apk_expansion/res/values/styles.xml b/platform/android/java/res/values/styles.xml
index a442f61e7e..a442f61e7e 100644
--- a/platform/android/libs/apk_expansion/res/values/styles.xml
+++ b/platform/android/java/res/values/styles.xml
diff --git a/platform/android/java/src/com/android/godot/Dictionary.java b/platform/android/java/src/com/android/godot/Dictionary.java
deleted file mode 100644
index 4ed12f5818..0000000000
--- a/platform/android/java/src/com/android/godot/Dictionary.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*************************************************************************/
-/* Dictionary.java */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* http://www.godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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. */
-/*************************************************************************/
-package com.android.godot;
-
-import java.util.HashMap;
-import java.util.Set;
-
-
-public class Dictionary extends HashMap<String, Object> {
-
- protected String[] keys_cache;
-
- public String[] get_keys() {
-
- String[] ret = new String[size()];
- int i=0;
- Set<String> keys = keySet();
- for (String key : keys) {
-
- ret[i] = key;
- i++;
- };
-
- return ret;
- };
-
- public Object[] get_values() {
-
- Object[] ret = new Object[size()];
- int i=0;
- Set<String> keys = keySet();
- for (String key : keys) {
-
- ret[i] = get(key);
- i++;
- };
-
- return ret;
- };
-
- public void set_keys(String[] keys) {
- keys_cache = keys;
- };
-
- public void set_values(Object[] vals) {
-
- int i=0;
- for (String key : keys_cache) {
- put(key, vals[i]);
- i++;
- };
- keys_cache = null;
- };
-};
diff --git a/platform/android/java/src/com/android/godot/Godot.java b/platform/android/java/src/com/android/godot/Godot.java
deleted file mode 100644
index 9b9b1ab2ad..0000000000
--- a/platform/android/java/src/com/android/godot/Godot.java
+++ /dev/null
@@ -1,925 +0,0 @@
-/*************************************************************************/
-/* Godot.java */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* http://www.godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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. */
-/*************************************************************************/
-package com.android.godot;
-
-import android.R;
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.MotionEvent;
-import android.view.View;
-import android.widget.Button;
-import android.widget.ProgressBar;
-import android.widget.RelativeLayout;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-import android.view.ViewGroup.LayoutParams;
-import android.app.*;
-import android.content.*;
-import android.content.SharedPreferences.Editor;
-import android.view.*;
-import android.view.inputmethod.InputMethodManager;
-import android.os.*;
-import android.util.Log;
-import android.graphics.*;
-import android.text.method.*;
-import android.text.*;
-import android.media.*;
-import android.hardware.*;
-import android.content.*;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.net.Uri;
-import android.media.MediaPlayer;
-
-import java.lang.reflect.Method;
-import java.util.List;
-import java.util.ArrayList;
-
-import com.android.godot.payments.PaymentsManager;
-
-import java.io.IOException;
-
-import android.provider.Settings.Secure;
-import android.widget.FrameLayout;
-
-import com.android.godot.input.*;
-
-import java.io.InputStream;
-import javax.microedition.khronos.opengles.GL10;
-import java.security.MessageDigest;
-import java.io.File;
-import java.io.FileInputStream;
-import java.util.LinkedList;
-
-import com.google.android.vending.expansion.downloader.Constants;
-import com.google.android.vending.expansion.downloader.DownloadProgressInfo;
-import com.google.android.vending.expansion.downloader.DownloaderClientMarshaller;
-import com.google.android.vending.expansion.downloader.DownloaderServiceMarshaller;
-import com.google.android.vending.expansion.downloader.Helpers;
-import com.google.android.vending.expansion.downloader.IDownloaderClient;
-import com.google.android.vending.expansion.downloader.IDownloaderService;
-import com.google.android.vending.expansion.downloader.IStub;
-
-import android.os.Bundle;
-import android.os.Messenger;
-import android.os.SystemClock;
-
-
-public class Godot extends Activity implements SensorEventListener, IDownloaderClient
-{
-
- static final int MAX_SINGLETONS = 64;
- private IStub mDownloaderClientStub;
- private IDownloaderService mRemoteService;
- private TextView mStatusText;
- private TextView mProgressFraction;
- private TextView mProgressPercent;
- private TextView mAverageSpeed;
- private TextView mTimeRemaining;
- private ProgressBar mPB;
-
- private View mDashboard;
- private View mCellMessage;
-
- private Button mPauseButton;
- private Button mWiFiSettingsButton;
-
- private boolean use_32_bits=false;
- private boolean use_immersive=false;
- private boolean mStatePaused;
- private int mState;
-
- private void setState(int newState) {
- if (mState != newState) {
- mState = newState;
- mStatusText.setText(Helpers.getDownloaderStringResourceIDFromState(newState));
- }
- }
-
- private void setButtonPausedState(boolean paused) {
- mStatePaused = paused;
- int stringResourceID = paused ? com.godot.game.R.string.text_button_resume :
- com.godot.game.R.string.text_button_pause;
- mPauseButton.setText(stringResourceID);
- }
-
- static public class SingletonBase {
-
- protected void registerClass(String p_name, String[] p_methods) {
-
- GodotLib.singleton(p_name,this);
-
- Class clazz = getClass();
- Method[] methods = clazz.getDeclaredMethods();
- for (Method method : methods) {
- boolean found=false;
- Log.d("XXX","METHOD: %s\n" + method.getName());
-
- for (String s : p_methods) {
- Log.d("XXX", "METHOD CMP WITH: %s\n" + s);
- if (s.equals(method.getName())) {
- found=true;
- Log.d("XXX","METHOD CMP VALID");
- break;
- }
- }
- if (!found)
- continue;
-
- Log.d("XXX","METHOD FOUND: %s\n" + method.getName());
-
- List<String> ptr = new ArrayList<String>();
-
- Class[] paramTypes = method.getParameterTypes();
- for (Class c : paramTypes) {
- ptr.add(c.getName());
- }
-
- String[] pt = new String[ptr.size()];
- ptr.toArray(pt);
-
- GodotLib.method(p_name,method.getName(),method.getReturnType().getName(),pt);
-
-
- }
-
- Godot.singletons[Godot.singleton_count++]=this;
- }
-
- protected void onMainActivityResult(int requestCode, int resultCode, Intent data) {
-
-
- }
-
- protected void onMainPause() {}
- protected void onMainResume() {}
- protected void onMainDestroy() {}
-
- protected void onGLDrawFrame(GL10 gl) {}
- protected void onGLSurfaceChanged(GL10 gl, int width, int height) {} // singletons will always miss first onGLSurfaceChanged call
- //protected void onGLSurfaceCreated(GL10 gl, EGLConfig config) {} // singletons won't be ready until first GodotLib.step()
-
- public void registerMethods() {}
- }
-
-/*
- protected List<SingletonBase> singletons = new ArrayList<SingletonBase>();
- protected void instanceSingleton(SingletonBase s) {
-
- s.registerMethods();
- singletons.add(s);
- }
-
-*/
-
- private String[] command_line;
-
- public GodotView mView;
- private boolean godot_initialized=false;
-
-
- private SensorManager mSensorManager;
- private Sensor mAccelerometer;
-
- public FrameLayout layout;
- public RelativeLayout adLayout;
-
-
- static public GodotIO io;
-
- public static void setWindowTitle(String title) {
- //setTitle(title);
- }
-
-
- static SingletonBase singletons[] = new SingletonBase[MAX_SINGLETONS];
- static int singleton_count=0;
-
-
- public interface ResultCallback {
- public void callback(int requestCode, int resultCode, Intent data);
- };
- public ResultCallback result_callback;
-
- private PaymentsManager mPaymentsManager = null;
-
- @Override protected void onActivityResult (int requestCode, int resultCode, Intent data) {
- if(requestCode == PaymentsManager.REQUEST_CODE_FOR_PURCHASE){
- mPaymentsManager.processPurchaseResponse(resultCode, data);
- }else if (result_callback != null) {
- result_callback.callback(requestCode, resultCode, data);
- result_callback = null;
- };
-
- for(int i=0;i<singleton_count;i++) {
-
- singletons[i].onMainActivityResult(requestCode,resultCode,data);
- }
- };
-
- public void onVideoInit(boolean use_gl2) {
-
-// mView = new GodotView(getApplication(),io,use_gl2);
-// setContentView(mView);
-
- layout = new FrameLayout(this);
- layout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
- setContentView(layout);
-
- // GodotEditText layout
- GodotEditText edittext = new GodotEditText(this);
- edittext.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT));
- // ...add to FrameLayout
- layout.addView(edittext);
-
- mView = new GodotView(getApplication(),io,use_gl2,use_32_bits, this);
- layout.addView(mView,new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
- mView.setKeepScreenOn(true);
-
- edittext.setView(mView);
- io.setEdit(edittext);
-
- // Ad layout
- adLayout = new RelativeLayout(this);
- adLayout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
- layout.addView(adLayout);
-
- }
-
- private static Godot _self;
-
- public static Godot getInstance(){
- return Godot._self;
- }
-
-
- private String[] getCommandLine() {
- InputStream is;
- try {
- is = getAssets().open("_cl_");
- byte[] len = new byte[4];
- int r = is.read(len);
- if (r<4) {
- Log.d("XXX","**ERROR** Wrong cmdline length.\n");
- Log.d("GODOT", "**ERROR** Wrong cmdline length.\n");
- return new String[0];
- }
- int argc=((int)(len[3]&0xFF)<<24) | ((int)(len[2]&0xFF)<<16) | ((int)(len[1]&0xFF)<<8) | ((int)(len[0]&0xFF));
- String[] cmdline = new String[argc];
-
- for(int i=0;i<argc;i++) {
- r = is.read(len);
- if (r<4) {
-
- Log.d("GODOT", "**ERROR** Wrong cmdline param lenght.\n");
- return new String[0];
- }
- int strlen=((int)(len[3]&0xFF)<<24) | ((int)(len[2]&0xFF)<<16) | ((int)(len[1]&0xFF)<<8) | ((int)(len[0]&0xFF));
- if (strlen>65535) {
- Log.d("GODOT", "**ERROR** Wrong command len\n");
- return new String[0];
- }
- byte[] arg = new byte[strlen];
- r = is.read(arg);
- if (r==strlen) {
- cmdline[i]=new String(arg,"UTF-8");
- }
- }
- return cmdline;
- } catch (Exception e) {
- e.printStackTrace();
- Log.d("GODOT", "**ERROR** Exception " + e.getClass().getName() + ":" + e.getMessage());
- return new String[0];
- }
-
-
- }
-
-
- String expansion_pack_path;
-
-
- private void initializeGodot() {
-
- if (expansion_pack_path!=null) {
-
- String[] new_cmdline;
- int cll=0;
- if (command_line!=null) {
- Log.d("GODOT", "initializeGodot: command_line: is not null" );
- new_cmdline = new String[ command_line.length + 2 ];
- cll=command_line.length;
- for(int i=0;i<command_line.length;i++) {
- new_cmdline[i]=command_line[i];
- }
- } else {
- Log.d("GODOT", "initializeGodot: command_line: is null" );
- new_cmdline = new String[ 2 ];
- }
-
- new_cmdline[cll]="-main_pack";
- new_cmdline[cll+1]=expansion_pack_path;
- command_line=new_cmdline;
- }
-
- io = new GodotIO(this);
- io.unique_id = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
- GodotLib.io=io;
- Log.d("GODOT", "command_line is null? " + ((command_line == null)?"yes":"no"));
- /*if(command_line != null){
- Log.d("GODOT", "Command Line:");
- for(int w=0;w <command_line.length;w++){
- Log.d("GODOT"," " + command_line[w]);
- }
- }*/
- GodotLib.initialize(this,io.needsReloadHooks(),command_line);
- mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
- mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
- mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
-
- result_callback = null;
-
- mPaymentsManager = PaymentsManager.createManager(this).initService();
- godot_initialized=true;
-
- }
-
- @Override
- public void onServiceConnected(Messenger m) {
- mRemoteService = DownloaderServiceMarshaller.CreateProxy(m);
- mRemoteService.onClientUpdated(mDownloaderClientStub.getMessenger());
- }
-
-
-
- @Override
- protected void onCreate(Bundle icicle) {
-
- Log.d("GODOT", "** GODOT ACTIVITY CREATED HERE ***\n");
-
- super.onCreate(icicle);
- _self = this;
- Window window = getWindow();
- window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
- | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-
-
- //check for apk expansion API
- if (true) {
- boolean md5mismatch = false;
- command_line = getCommandLine();
- boolean use_apk_expansion=false;
- String main_pack_md5=null;
- String main_pack_key=null;
-
- List<String> new_args = new LinkedList<String>();
-
-
- for(int i=0;i<command_line.length;i++) {
-
- boolean has_extra = i< command_line.length -1;
- if (command_line[i].equals("-use_depth_32")) {
- use_32_bits=true;
- } else if (command_line[i].equals("-use_immersive")) {
- use_immersive=true;
- if(Build.VERSION.SDK_INT >= 19.0){ // check if the application runs on an android 4.4+
- window.getDecorView().setSystemUiVisibility(
- View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
- | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
- | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
-
- UiChangeListener();
- }
- } else if (command_line[i].equals("-use_apk_expansion")) {
- use_apk_expansion=true;
- } else if (has_extra && command_line[i].equals("-apk_expansion_md5")) {
- main_pack_md5=command_line[i+1];
- i++;
- } else if (has_extra && command_line[i].equals("-apk_expansion_key")) {
- main_pack_key=command_line[i+1];
- SharedPreferences prefs = getSharedPreferences("app_data_keys", MODE_PRIVATE);
- Editor editor = prefs.edit();
- editor.putString("store_public_key", main_pack_key);
-
- editor.commit();
- i++;
- } else if (command_line[i].trim().length()!=0){
- new_args.add(command_line[i]);
- }
- }
-
- if (new_args.isEmpty()){
- command_line=null;
- }else{
-
- command_line = new_args.toArray(new String[new_args.size()]);
- }
- if (use_apk_expansion && main_pack_md5!=null && main_pack_key!=null) {
- //check that environment is ok!
- if (!Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED )) {
- Log.d("GODOT", "**ERROR! No media mounted!");
- //show popup and die
- }
-
- // Build the full path to the app's expansion files
- try {
- expansion_pack_path = Environment.getExternalStorageDirectory().toString() + "/Android/obb/"+this.getPackageName();
- expansion_pack_path+="/"+"main."+getPackageManager().getPackageInfo(getPackageName(), 0).versionCode+"."+this.getPackageName()+".obb";
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- File f = new File(expansion_pack_path);
-
- boolean pack_valid = true;
- Log.d("GODOT","**PACK** - Path "+expansion_pack_path);
-
- if (!f.exists()) {
-
- pack_valid=false;
- Log.d("GODOT","**PACK** - File does not exist");
-
- } else if( obbIsCorrupted(expansion_pack_path, main_pack_md5)){
- Log.d("GODOT", "**PACK** - Expansion pack (obb) is corrupted");
- pack_valid = false;
- try{
- f.delete();
- }catch(Exception e){
- Log.d("GODOT", "**PACK** - Error deleting corrupted expansion pack (obb)");
- }
- }
-
- if (!pack_valid) {
- Log.d("GODOT", "Pack Invalid, try re-downloading.");
-
- Intent notifierIntent = new Intent(this, this.getClass());
- notifierIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
- Intent.FLAG_ACTIVITY_CLEAR_TOP);
-
- PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
- notifierIntent, PendingIntent.FLAG_UPDATE_CURRENT);
-
- int startResult;
- try {
- Log.d("GODOT", "INITIALIZING DOWNLOAD");
- startResult = DownloaderClientMarshaller.startDownloadServiceIfRequired(
- getApplicationContext(),
- pendingIntent,
- GodotDownloaderService.class);
- Log.d("GODOT", "DOWNLOAD SERVICE FINISHED:" + startResult);
-
- if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) {
- Log.d("GODOT", "DOWNLOAD REQUIRED");
- // This is where you do set up to display the download
- // progress (next step)
- mDownloaderClientStub = DownloaderClientMarshaller.CreateStub(this,
- GodotDownloaderService.class);
-
- setContentView(com.godot.game.R.layout.downloading_expansion);
- mPB = (ProgressBar) findViewById(com.godot.game.R.id.progressBar);
- mStatusText = (TextView) findViewById(com.godot.game.R.id.statusText);
- mProgressFraction = (TextView) findViewById(com.godot.game.R.id.progressAsFraction);
- mProgressPercent = (TextView) findViewById(com.godot.game.R.id.progressAsPercentage);
- mAverageSpeed = (TextView) findViewById(com.godot.game.R.id.progressAverageSpeed);
- mTimeRemaining = (TextView) findViewById(com.godot.game.R.id.progressTimeRemaining);
- mDashboard = findViewById(com.godot.game.R.id.downloaderDashboard);
- mCellMessage = findViewById(com.godot.game.R.id.approveCellular);
- mPauseButton = (Button) findViewById(com.godot.game.R.id.pauseButton);
- mWiFiSettingsButton = (Button) findViewById(com.godot.game.R.id.wifiSettingsButton);
-
- return;
- } else{
- Log.d("GODOT", "NO DOWNLOAD REQUIRED");
- }
- } catch (NameNotFoundException e) {
- // TODO Auto-generated catch block
- Log.d("GODOT", "Error downloading expansion package:" + e.getMessage());
- }
-
- }
-
- }
- }
-
- initializeGodot();
-
-
- // instanceSingleton( new GodotFacebook(this) );
-
-
- }
-
-
- @Override protected void onDestroy(){
-
- if(mPaymentsManager != null ) mPaymentsManager.destroy();
- for(int i=0;i<singleton_count;i++) {
- singletons[i].onMainDestroy();
- }
- super.onDestroy();
- }
-
- @Override protected void onPause() {
- super.onPause();
- if (!godot_initialized){
- if (null != mDownloaderClientStub) {
- mDownloaderClientStub.disconnect(this);
- }
- return;
- }
- mView.onPause();
- mSensorManager.unregisterListener(this);
- GodotLib.focusout();
-
- for(int i=0;i<singleton_count;i++) {
- singletons[i].onMainPause();
- }
- }
-
- @Override protected void onResume() {
- super.onResume();
- if (!godot_initialized){
- if (null != mDownloaderClientStub) {
- mDownloaderClientStub.connect(this);
- }
- return;
- }
-
- mView.onResume();
- mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
- GodotLib.focusin();
- if(use_immersive && Build.VERSION.SDK_INT >= 19.0){ // check if the application runs on an android 4.4+
- Window window = getWindow();
- window.getDecorView().setSystemUiVisibility(
- View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
- | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
- | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
- }
-
- for(int i=0;i<singleton_count;i++) {
-
- singletons[i].onMainResume();
- }
-
-
-
- }
-
- public void UiChangeListener() {
- final View decorView = getWindow().getDecorView();
- decorView.setOnSystemUiVisibilityChangeListener (new View.OnSystemUiVisibilityChangeListener() {
- @Override
- public void onSystemUiVisibilityChange(int visibility) {
- if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
- decorView.setSystemUiVisibility(
- View.SYSTEM_UI_FLAG_LAYOUT_STABLE
- | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
- | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
- | View.SYSTEM_UI_FLAG_FULLSCREEN
- | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
- }
- }
- });
- }
-
- @Override public void onSensorChanged(SensorEvent event) {
- Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
- int displayRotation = display.getRotation();
-
- float[] adjustedValues = new float[3];
- final int axisSwap[][] = {
- { 1, -1, 0, 1 }, // ROTATION_0
- {-1, -1, 1, 0 }, // ROTATION_90
- {-1, 1, 0, 1 }, // ROTATION_180
- { 1, 1, 1, 0 } }; // ROTATION_270
-
- final int[] as = axisSwap[displayRotation];
- adjustedValues[0] = (float)as[0] * event.values[ as[2] ];
- adjustedValues[1] = (float)as[1] * event.values[ as[3] ];
- adjustedValues[2] = event.values[2];
-
- float x = adjustedValues[0];
- float y = adjustedValues[1];
- float z = adjustedValues[2];
- GodotLib.accelerometer(x,y,z);
- }
-
- @Override public final void onAccuracyChanged(Sensor sensor, int accuracy) {
- // Do something here if sensor accuracy changes.
- }
-
-/*
- @Override public boolean dispatchKeyEvent(KeyEvent event) {
-
- if (event.getKeyCode()==KeyEvent.KEYCODE_BACK) {
-
- System.out.printf("** BACK REQUEST!\n");
-
- GodotLib.quit();
- return true;
- }
- System.out.printf("** OTHER KEY!\n");
-
- return false;
- }
-*/
-
- @Override public void onBackPressed() {
-
- System.out.printf("** BACK REQUEST!\n");
- GodotLib.quit();
- }
-
- public void forceQuit() {
-
- System.exit(0);
- }
-
-
-
- private boolean obbIsCorrupted(String f, String main_pack_md5){
-
- try {
-
- InputStream fis = new FileInputStream(f);
-
- // Create MD5 Hash
- byte[] buffer = new byte[16384];
-
- MessageDigest complete = MessageDigest.getInstance("MD5");
- int numRead;
- do {
- numRead = fis.read(buffer);
- if (numRead > 0) {
- complete.update(buffer, 0, numRead);
- }
- } while (numRead != -1);
-
-
- fis.close();
- byte[] messageDigest = complete.digest();
-
- // Create Hex String
- StringBuffer hexString = new StringBuffer();
- for (int i=0; i<messageDigest.length; i++) {
- String s = Integer.toHexString(0xFF & messageDigest[i]);
-
- if (s.length()==1) {
- s="0"+s;
- }
- hexString.append(s);
- }
- String md5str = hexString.toString();
-
- //Log.d("GODOT","**PACK** - My MD5: "+hexString+" - APK md5: "+main_pack_md5);
- if (!md5str.equals(main_pack_md5)) {
- Log.d("GODOT","**PACK MD5 MISMATCH???** - MD5 Found: "+md5str+" "+Integer.toString(md5str.length())+" - MD5 Expected: "+main_pack_md5+" "+Integer.toString(main_pack_md5.length()));
- return true;
- }
- return false;
- } catch (Exception e) {
- e.printStackTrace();
- Log.d("GODOT","**PACK FAIL**");
- return true;
- }
- }
-
- //@Override public boolean dispatchTouchEvent (MotionEvent event) {
- public boolean gotTouchEvent(MotionEvent event) {
-
- super.onTouchEvent(event);
- int evcount=event.getPointerCount();
- if (evcount==0)
- return true;
-
- int[] arr = new int[event.getPointerCount()*3];
-
- for(int i=0;i<event.getPointerCount();i++) {
-
- arr[i*3+0]=(int)event.getPointerId(i);
- arr[i*3+1]=(int)event.getX(i);
- arr[i*3+2]=(int)event.getY(i);
- }
-
- //System.out.printf("gaction: %d\n",event.getAction());
- switch(event.getAction()&MotionEvent.ACTION_MASK) {
-
- case MotionEvent.ACTION_DOWN: {
- GodotLib.touch(0,0,evcount,arr);
- //System.out.printf("action down at: %f,%f\n", event.getX(),event.getY());
- } break;
- case MotionEvent.ACTION_MOVE: {
- GodotLib.touch(1,0,evcount,arr);
- //for(int i=0;i<event.getPointerCount();i++) {
- // System.out.printf("%d - moved to: %f,%f\n",i, event.getX(i),event.getY(i));
- //}
- } break;
- case MotionEvent.ACTION_POINTER_UP: {
- final int indexPointUp = event.getActionIndex();
- final int pointer_idx = event.getPointerId(indexPointUp);
- GodotLib.touch(4,pointer_idx,evcount,arr);
- //System.out.printf("%d - s.up at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
- } break;
- case MotionEvent.ACTION_POINTER_DOWN: {
- int pointer_idx = event.getActionIndex();
- GodotLib.touch(3,pointer_idx,evcount,arr);
- //System.out.printf("%d - s.down at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
- } break;
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP: {
- GodotLib.touch(2,0,evcount,arr);
- //for(int i=0;i<event.getPointerCount();i++) {
- // System.out.printf("%d - up! %f,%f\n",i, event.getX(i),event.getY(i));
- //}
- } break;
-
- }
- return true;
- }
-
- @Override public boolean onKeyMultiple(final int inKeyCode, int repeatCount, KeyEvent event) {
- String s = event.getCharacters();
- if (s == null || s.length() == 0)
- return super.onKeyMultiple(inKeyCode, repeatCount, event);
-
- final char[] cc = s.toCharArray();
- int cnt = 0;
- for (int i = cc.length; --i >= 0; cnt += cc[i] != 0 ? 1 : 0);
- if (cnt == 0) return super.onKeyMultiple(inKeyCode, repeatCount, event);
- final Activity me = this;
- queueEvent(new Runnable() {
- // This method will be called on the rendering thread:
- public void run() {
- for (int i = 0, n = cc.length; i < n; i++) {
- int keyCode;
- if ((keyCode = cc[i]) != 0) {
- // Simulate key down and up...
- GodotLib.key(0, keyCode, true);
- GodotLib.key(0, keyCode, false);
- }
- }
- }
- });
- return true;
- }
-
- private void queueEvent(Runnable runnable) {
- // TODO Auto-generated method stub
-
- }
-
- public PaymentsManager getPaymentsManager() {
- return mPaymentsManager;
- }
-
-// public void setPaymentsManager(PaymentsManager mPaymentsManager) {
-// this.mPaymentsManager = mPaymentsManager;
-// };
-
-
- // Audio
-
- /**
- * The download state should trigger changes in the UI --- it may be useful
- * to show the state as being indeterminate at times. This sample can be
- * considered a guideline.
- */
- @Override
- public void onDownloadStateChanged(int newState) {
- Log.d("GODOT", "onDownloadStateChanged:" + newState);
- setState(newState);
- boolean showDashboard = true;
- boolean showCellMessage = false;
- boolean paused;
- boolean indeterminate;
- switch (newState) {
- case IDownloaderClient.STATE_IDLE:
- Log.d("GODOT", "STATE IDLE");
- // STATE_IDLE means the service is listening, so it's
- // safe to start making calls via mRemoteService.
- paused = false;
- indeterminate = true;
- break;
- case IDownloaderClient.STATE_CONNECTING:
- case IDownloaderClient.STATE_FETCHING_URL:
- Log.d("GODOT", "STATE CONNECTION / FETCHING URL");
- showDashboard = true;
- paused = false;
- indeterminate = true;
- break;
- case IDownloaderClient.STATE_DOWNLOADING:
- Log.d("GODOT", "STATE DOWNLOADING");
- paused = false;
- showDashboard = true;
- indeterminate = false;
- break;
-
- case IDownloaderClient.STATE_FAILED_CANCELED:
- case IDownloaderClient.STATE_FAILED:
- case IDownloaderClient.STATE_FAILED_FETCHING_URL:
- case IDownloaderClient.STATE_FAILED_UNLICENSED:
- Log.d("GODOT", "MANY TYPES OF FAILING");
- paused = true;
- showDashboard = false;
- indeterminate = false;
- break;
- case IDownloaderClient.STATE_PAUSED_NEED_CELLULAR_PERMISSION:
- case IDownloaderClient.STATE_PAUSED_WIFI_DISABLED_NEED_CELLULAR_PERMISSION:
- Log.d("GODOT", "PAUSED FOR SOME STUPID REASON");
- showDashboard = false;
- paused = true;
- indeterminate = false;
- showCellMessage = true;
- break;
-
- case IDownloaderClient.STATE_PAUSED_BY_REQUEST:
- Log.d("GODOT", "PAUSED BY STUPID USER");
- paused = true;
- indeterminate = false;
- break;
- case IDownloaderClient.STATE_PAUSED_ROAMING:
- case IDownloaderClient.STATE_PAUSED_SDCARD_UNAVAILABLE:
- Log.d("GODOT", "PAUSED BY ROAMING WTF!?");
- paused = true;
- indeterminate = false;
- break;
- case IDownloaderClient.STATE_COMPLETED:
- Log.d("GODOT", "COMPLETED");
- showDashboard = false;
- paused = false;
- indeterminate = false;
-// validateXAPKZipFiles();
- initializeGodot();
- return;
- default:
- Log.d("GODOT", "DEFAULT ????");
- paused = true;
- indeterminate = true;
- showDashboard = true;
- }
- int newDashboardVisibility = showDashboard ? View.VISIBLE : View.GONE;
- if (mDashboard.getVisibility() != newDashboardVisibility) {
- mDashboard.setVisibility(newDashboardVisibility);
- }
- int cellMessageVisibility = showCellMessage ? View.VISIBLE : View.GONE;
- if (mCellMessage.getVisibility() != cellMessageVisibility) {
- mCellMessage.setVisibility(cellMessageVisibility);
- }
-
- mPB.setIndeterminate(indeterminate);
- setButtonPausedState(paused);
- }
-
-
- @Override
- public void onDownloadProgress(DownloadProgressInfo progress) {
- mAverageSpeed.setText(getString(com.godot.game.R.string.kilobytes_per_second,
- Helpers.getSpeedString(progress.mCurrentSpeed)));
- mTimeRemaining.setText(getString(com.godot.game.R.string.time_remaining,
- Helpers.getTimeRemaining(progress.mTimeRemaining)));
-
- progress.mOverallTotal = progress.mOverallTotal;
- mPB.setMax((int) (progress.mOverallTotal >> 8));
- mPB.setProgress((int) (progress.mOverallProgress >> 8));
- mProgressPercent.setText(Long.toString(progress.mOverallProgress
- * 100 /
- progress.mOverallTotal) + "%");
- mProgressFraction.setText(Helpers.getDownloadProgressString
- (progress.mOverallProgress,
- progress.mOverallTotal));
-
- }
-
-}
diff --git a/platform/android/java/src/com/android/godot/GodotDownloaderAlarmReceiver.java b/platform/android/java/src/com/android/godot/GodotDownloaderAlarmReceiver.java
deleted file mode 100644
index e82c3eb0fe..0000000000
--- a/platform/android/java/src/com/android/godot/GodotDownloaderAlarmReceiver.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.android.godot;
-
-import com.google.android.vending.expansion.downloader.DownloaderClientMarshaller;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.util.Log;
-
-/**
- * You should start your derived downloader class when this receiver gets the message
- * from the alarm service using the provided service helper function within the
- * DownloaderClientMarshaller. This class must be then registered in your AndroidManifest.xml
- * file with a section like this:
- * <receiver android:name=".GodotDownloaderAlarmReceiver"/>
- */
-public class GodotDownloaderAlarmReceiver extends BroadcastReceiver {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.d("GODOT", "Alarma recivida");
- try {
- DownloaderClientMarshaller.startDownloadServiceIfRequired(context, intent, GodotDownloaderService.class);
- } catch (NameNotFoundException e) {
- e.printStackTrace();
- Log.d("GODOT", "Exception: " + e.getClass().getName() + ":" + e.getMessage());
- }
- }
-}
diff --git a/platform/android/java/src/com/android/godot/GodotDownloaderService.java b/platform/android/java/src/com/android/godot/GodotDownloaderService.java
deleted file mode 100644
index 2657edc1d2..0000000000
--- a/platform/android/java/src/com/android/godot/GodotDownloaderService.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.android.godot;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.util.Log;
-
-import com.google.android.vending.expansion.downloader.impl.DownloaderService;
-
-/**
- * This class demonstrates the minimal client implementation of the
- * DownloaderService from the Downloader library.
- */
-public class GodotDownloaderService extends DownloaderService {
- // stuff for LVL -- MODIFY FOR YOUR APPLICATION!
- private static final String BASE64_PUBLIC_KEY = "REPLACE THIS WITH YOUR PUBLIC KEY";
- // used by the preference obfuscater
- private static final byte[] SALT = new byte[] {
- 1, 43, -12, -1, 54, 98,
- -100, -12, 43, 2, -8, -4, 9, 5, -106, -108, -33, 45, -1, 84
- };
-
- /**
- * This public key comes from your Android Market publisher account, and it
- * used by the LVL to validate responses from Market on your behalf.
- */
- @Override
- public String getPublicKey() {
- SharedPreferences prefs = getApplicationContext().getSharedPreferences("app_data_keys", Context.MODE_PRIVATE);
- Log.d("GODOT", "getting public key:" + prefs.getString("store_public_key", null));
- return prefs.getString("store_public_key", null);
-
-// return BASE64_PUBLIC_KEY;
- }
-
- /**
- * This is used by the preference obfuscater to make sure that your
- * obfuscated preferences are different than the ones used by other
- * applications.
- */
- @Override
- public byte[] getSALT() {
- return SALT;
- }
-
- /**
- * Fill this in with the class name for your alarm receiver. We do this
- * because receivers must be unique across all of Android (it's a good idea
- * to make sure that your receiver is in your unique package)
- */
- @Override
- public String getAlarmReceiverClassName() {
- Log.d("GODOT", "getAlarmReceiverClassName()");
- return GodotDownloaderAlarmReceiver.class.getName();
- }
-
-}
diff --git a/platform/android/java/src/com/android/godot/GodotIO.java b/platform/android/java/src/com/android/godot/GodotIO.java
deleted file mode 100644
index addceb1528..0000000000
--- a/platform/android/java/src/com/android/godot/GodotIO.java
+++ /dev/null
@@ -1,672 +0,0 @@
-/*************************************************************************/
-/* GodotIO.java */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* http://www.godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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. */
-/*************************************************************************/
-package com.android.godot;
-import java.util.HashMap;
-import java.util.Locale;
-import android.net.Uri;
-import android.content.Intent;
-import android.content.res.AssetManager;
-import java.io.InputStream;
-import java.io.IOException;
-import android.app.*;
-import android.content.*;
-import android.view.*;
-import android.view.inputmethod.InputMethodManager;
-import android.os.*;
-import android.util.Log;
-import android.graphics.*;
-import android.text.method.*;
-import android.text.*;
-import android.media.*;
-import android.hardware.*;
-import android.content.*;
-import android.content.pm.ActivityInfo;
-import com.android.godot.input.*;
-//android.os.Build
-
-// Wrapper for native library
-
-public class GodotIO {
-
-
- AssetManager am;
- Godot activity;
- GodotEditText edit;
-
- Context applicationContext;
- MediaPlayer mediaPlayer;
-
- final int SCREEN_LANDSCAPE=0;
- final int SCREEN_PORTRAIT=1;
- final int SCREEN_REVERSE_LANDSCAPE=2;
- final int SCREEN_REVERSE_PORTRAIT=3;
- final int SCREEN_SENSOR_LANDSCAPE=4;
- final int SCREEN_SENSOR_PORTRAIT=5;
- final int SCREEN_SENSOR=6;
-
- /////////////////////////
- /// FILES
- /////////////////////////
-
- public int last_file_id=1;
-
- class AssetData {
-
-
- public boolean eof=false;
- public String path;
- public InputStream is;
- public int len;
- public int pos;
- }
-
-
- HashMap<Integer,AssetData> streams;
-
-
- public int file_open(String path,boolean write) {
-
- //System.out.printf("file_open: Attempt to Open %s\n",path);
-
- if (write)
- return -1;
-
-
- AssetData ad = new AssetData();
-
- try {
- ad.is = am.open(path);
-
- } catch (Exception e) {
-
- //System.out.printf("Exception on file_open: %s\n",e);
- return -1;
- }
-
- try {
- ad.len=ad.is.available();
- } catch (Exception e) {
-
- System.out.printf("Exception availabling on file_open: %s\n",e);
- return -1;
- }
-
- ad.path=path;
- ad.pos=0;
- ++last_file_id;
- streams.put(last_file_id,ad);
-
- return last_file_id;
- }
- public int file_get_size(int id) {
-
- if (!streams.containsKey(id)) {
- System.out.printf("file_get_size: Invalid file id: %d\n",id);
- return -1;
- }
-
- return streams.get(id).len;
-
- }
- public void file_seek(int id,int bytes) {
-
- if (!streams.containsKey(id)) {
- System.out.printf("file_get_size: Invalid file id: %d\n",id);
- return;
- }
- //seek sucks
- AssetData ad = streams.get(id);
- if (bytes>ad.len)
- bytes=ad.len;
- if (bytes<0)
- bytes=0;
-
- try {
-
- if (bytes > (int)ad.pos) {
- int todo=bytes-(int)ad.pos;
- while(todo>0) {
- todo-=ad.is.skip(todo);
- }
- ad.pos=bytes;
- } else if (bytes<(int)ad.pos) {
-
- ad.is=am.open(ad.path);
-
- ad.pos=bytes;
- int todo=bytes;
- while(todo>0) {
- todo-=ad.is.skip(todo);
- }
- }
-
- ad.eof=false;
- } catch (IOException e) {
-
- System.out.printf("Exception on file_seek: %s\n",e);
- return;
- }
-
-
- }
-
- public int file_tell(int id) {
-
- if (!streams.containsKey(id)) {
- System.out.printf("file_read: Can't tell eof for invalid file id: %d\n",id);
- return 0;
- }
-
- AssetData ad = streams.get(id);
- return ad.pos;
- }
- public boolean file_eof(int id) {
-
- if (!streams.containsKey(id)) {
- System.out.printf("file_read: Can't check eof for invalid file id: %d\n",id);
- return false;
- }
-
- AssetData ad = streams.get(id);
- return ad.eof;
- }
-
- public byte[] file_read(int id, int bytes) {
-
- if (!streams.containsKey(id)) {
- System.out.printf("file_read: Can't read invalid file id: %d\n",id);
- return new byte[0];
- }
-
-
- AssetData ad = streams.get(id);
-
- if (ad.pos + bytes > ad.len) {
-
- bytes=ad.len-ad.pos;
- ad.eof=true;
- }
-
-
- if (bytes==0) {
-
- return new byte[0];
- }
-
-
-
- byte[] buf1=new byte[bytes];
- int r=0;
- try {
- r = ad.is.read(buf1);
- } catch (IOException e) {
-
- System.out.printf("Exception on file_read: %s\n",e);
- return new byte[bytes];
- }
-
- if (r==0) {
- return new byte[0];
- }
-
- ad.pos+=r;
-
- if (r<bytes) {
-
- byte[] buf2=new byte[r];
- for(int i=0;i<r;i++)
- buf2[i]=buf1[i];
- return buf2;
- } else {
-
- return buf1;
- }
-
- }
-
- public void file_close(int id) {
-
- if (!streams.containsKey(id)) {
- System.out.printf("file_close: Can't close invalid file id: %d\n",id);
- return;
- }
-
- streams.remove(id);
-
- }
-
-
- /////////////////////////
- /// DIRECTORIES
- /////////////////////////
-
-
- class AssetDir {
-
- public String[] files;
- public int current;
- public String path;
- }
-
- public int last_dir_id=1;
-
- HashMap<Integer,AssetDir> dirs;
-
- public int dir_open(String path) {
-
- AssetDir ad = new AssetDir();
- ad.current=0;
- ad.path=path;
-
- try {
- ad.files = am.list(path);
- } catch (IOException e) {
-
- System.out.printf("Exception on dir_open: %s\n",e);
- return -1;
- }
-
- //System.out.printf("Opened dir: %s\n",path);
- ++last_dir_id;
- dirs.put(last_dir_id,ad);
-
- return last_dir_id;
-
- }
-
- public boolean dir_is_dir(int id) {
- if (!dirs.containsKey(id)) {
- System.out.printf("dir_next: invalid dir id: %d\n",id);
- return false;
- }
- AssetDir ad = dirs.get(id);
- //System.out.printf("go next: %d,%d\n",ad.current,ad.files.length);
- int idx = ad.current;
- if (idx>0)
- idx--;
-
- if (idx>=ad.files.length)
- return false;
- String fname = ad.files[idx];
-
- try {
- if (ad.path.equals(""))
- am.open(fname);
- else
- am.open(ad.path+"/"+fname);
- return false;
- } catch (Exception e) {
- return true;
- }
- }
-
- public String dir_next(int id) {
-
- if (!dirs.containsKey(id)) {
- System.out.printf("dir_next: invalid dir id: %d\n",id);
- return "";
- }
-
- AssetDir ad = dirs.get(id);
- //System.out.printf("go next: %d,%d\n",ad.current,ad.files.length);
-
- if (ad.current>=ad.files.length) {
- ad.current++;
- return "";
- }
- String r = ad.files[ad.current];
- ad.current++;
- return r;
-
- }
-
- public void dir_close(int id) {
-
- if (!dirs.containsKey(id)) {
- System.out.printf("dir_close: invalid dir id: %d\n",id);
- return;
- }
-
- dirs.remove(id);
- }
-
-
-
- GodotIO(Godot p_activity) {
-
- am=p_activity.getAssets();
- activity=p_activity;
- streams=new HashMap<Integer,AssetData>();
- dirs=new HashMap<Integer,AssetDir>();
- applicationContext = activity.getApplicationContext();
-
- }
-
-
- /////////////////////////
- // AUDIO
- /////////////////////////
-
- private Object buf;
- private Thread mAudioThread;
- private AudioTrack mAudioTrack;
-
- public Object audioInit(int sampleRate, int desiredFrames) {
- int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
- int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
- int frameSize = 4;
-
- System.out.printf("audioInit: initializing audio:\n");
-
- //Log.v("Godot", "Godot audio: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + ((float)sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer");
-
- // Let the user pick a larger buffer if they really want -- but ye
- // gods they probably shouldn't, the minimums are horrifyingly high
- // latency already
- desiredFrames = Math.max(desiredFrames, (AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
-
- mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
- channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM);
-
- audioStartThread();
-
- //Log.v("Godot", "Godot audio: got " + ((mAudioTrack.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioTrack.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + ((float)mAudioTrack.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer");
-
- buf = new short[desiredFrames * 2];
- return buf;
- }
-
- public void audioStartThread() {
- mAudioThread = new Thread(new Runnable() {
- public void run() {
- mAudioTrack.play();
- GodotLib.audio();
- }
- });
-
- // I'd take REALTIME if I could get it!
- mAudioThread.setPriority(Thread.MAX_PRIORITY);
- mAudioThread.start();
- }
-
- public void audioWriteShortBuffer(short[] buffer) {
- for (int i = 0; i < buffer.length; ) {
- int result = mAudioTrack.write(buffer, i, buffer.length - i);
- if (result > 0) {
- i += result;
- } else if (result == 0) {
- try {
- Thread.sleep(1);
- } catch(InterruptedException e) {
- // Nom nom
- }
- } else {
- Log.w("Godot", "Godot audio: error return from write(short)");
- return;
- }
- }
- }
-
-
-
- public void audioQuit() {
- if (mAudioThread != null) {
- try {
- mAudioThread.join();
- } catch(Exception e) {
- Log.v("Godot", "Problem stopping audio thread: " + e);
- }
- mAudioThread = null;
-
- //Log.v("Godot", "Finished waiting for audio thread");
- }
-
- if (mAudioTrack != null) {
- mAudioTrack.stop();
- mAudioTrack = null;
- }
- }
-
- public void audioPause(boolean p_pause) {
-
- if (p_pause)
- mAudioTrack.pause();
- else
- mAudioTrack.play();
- }
-
- /////////////////////////
- // MISCELANEOUS OS IO
- /////////////////////////
-
-
-
- public int openURI(String p_uri) {
-
- try {
- Log.v("MyApp", "TRYING TO OPEN URI: " + p_uri);
- String path = p_uri;
- String type="";
- if (path.startsWith("/")) {
- //absolute path to filesystem, prepend file://
- path="file://"+path;
- if (p_uri.endsWith(".png") || p_uri.endsWith(".jpg") || p_uri.endsWith(".gif") || p_uri.endsWith(".webp")) {
-
- type="image/*";
- }
- }
-
- Intent intent = new Intent();
- intent.setAction(Intent.ACTION_VIEW);
- if (!type.equals("")) {
- intent.setDataAndType(Uri.parse(path), type);
- } else {
- intent.setData(Uri.parse(path));
- }
-
- activity.startActivity(intent);
- return 0;
- } catch (ActivityNotFoundException e) {
-
- return 1;
- }
- }
-
- public String getDataDir() {
-
- return activity.getFilesDir().getAbsolutePath();
- }
-
- public String getLocale() {
-
- return Locale.getDefault().toString();
- }
-
- public String getModel() {
- return Build.MODEL;
- }
-
- public boolean needsReloadHooks() {
-
- return android.os.Build.VERSION.SDK_INT < 11;
- }
-
- public void showKeyboard(String p_existing_text) {
- if(edit != null)
- edit.showKeyboard(p_existing_text);
-
- //InputMethodManager inputMgr = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE);
- //inputMgr.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
- };
-
- public void hideKeyboard() {
- if(edit != null)
- edit.hideKeyboard();
-
- InputMethodManager inputMgr = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE);
- View v = activity.getCurrentFocus();
- if (v != null) {
- inputMgr.hideSoftInputFromWindow(v.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
- } else {
- inputMgr.hideSoftInputFromWindow(new View(activity).getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
- }
- };
-
- public void setScreenOrientation(int p_orientation) {
-
- switch(p_orientation) {
-
- case SCREEN_LANDSCAPE: {
- activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
- } break;
- case SCREEN_PORTRAIT: {
- activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
- } break;
- case SCREEN_REVERSE_LANDSCAPE: {
- activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
- } break;
- case SCREEN_REVERSE_PORTRAIT: {
- activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
- } break;
- case SCREEN_SENSOR_LANDSCAPE: {
- activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
- } break;
- case SCREEN_SENSOR_PORTRAIT: {
- activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
- } break;
- case SCREEN_SENSOR: {
- activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
- } break;
-
- }
- };
-
- public void setEdit(GodotEditText _edit) {
- edit = _edit;
- }
-
- public void playVideo(String p_path)
- {
- Uri filePath = Uri.parse(p_path);
- mediaPlayer = new MediaPlayer();
-
- try {
- mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
- mediaPlayer.setDataSource(applicationContext, filePath);
- mediaPlayer.prepare();
- mediaPlayer.start();
- }
- catch(IOException e)
- {
- System.out.println("IOError while playing video");
- }
- }
-
- public boolean isVideoPlaying() {
- if (mediaPlayer != null) {
- return mediaPlayer.isPlaying();
- }
- return false;
- }
-
- public void pauseVideo() {
- if (mediaPlayer != null) {
- mediaPlayer.pause();
- }
- }
-
- public void stopVideo() {
- if (mediaPlayer != null) {
- mediaPlayer.release();
- mediaPlayer = null;
- }
- }
-
-
- public static final int SYSTEM_DIR_DESKTOP=0;
- public static final int SYSTEM_DIR_DCIM=1;
- public static final int SYSTEM_DIR_DOCUMENTS=2;
- public static final int SYSTEM_DIR_DOWNLOADS=3;
- public static final int SYSTEM_DIR_MOVIES=4;
- public static final int SYSTEM_DIR_MUSIC=5;
- public static final int SYSTEM_DIR_PICTURES=6;
- public static final int SYSTEM_DIR_RINGTONES=7;
-
-
- public String getSystemDir(int idx) {
-
- String what="";
- switch(idx) {
- case SYSTEM_DIR_DESKTOP: {
- //what=Environment.DIRECTORY_DOCUMENTS;
- what=Environment.DIRECTORY_DOWNLOADS;
- } break;
- case SYSTEM_DIR_DCIM: {
- what=Environment.DIRECTORY_DCIM;
-
- } break;
- case SYSTEM_DIR_DOCUMENTS: {
- what=Environment.DIRECTORY_DOWNLOADS;
- //what=Environment.DIRECTORY_DOCUMENTS;
- } break;
- case SYSTEM_DIR_DOWNLOADS: {
- what=Environment.DIRECTORY_DOWNLOADS;
-
- } break;
- case SYSTEM_DIR_MOVIES: {
- what=Environment.DIRECTORY_MOVIES;
-
- } break;
- case SYSTEM_DIR_MUSIC: {
- what=Environment.DIRECTORY_MUSIC;
- } break;
- case SYSTEM_DIR_PICTURES: {
- what=Environment.DIRECTORY_PICTURES;
- } break;
- case SYSTEM_DIR_RINGTONES: {
- what=Environment.DIRECTORY_RINGTONES;
-
- } break;
- }
-
- if (what.equals(""))
- return "";
- return Environment.getExternalStoragePublicDirectory(what).getAbsolutePath();
- }
-
- protected static final String PREFS_FILE = "device_id.xml";
- protected static final String PREFS_DEVICE_ID = "device_id";
-
- public static String unique_id="";
- public String getUniqueID() {
-
- return unique_id;
- }
-
-}
diff --git a/platform/android/java/src/com/android/godot/GodotLib.java b/platform/android/java/src/com/android/godot/GodotLib.java
deleted file mode 100644
index 71c31e9f83..0000000000
--- a/platform/android/java/src/com/android/godot/GodotLib.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*************************************************************************/
-/* GodotLib.java */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* http://www.godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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. */
-/*************************************************************************/
-package com.android.godot;
-
-// Wrapper for native library
-
-public class GodotLib {
-
-
- public static GodotIO io;
-
- static {
- System.loadLibrary("godot_android");
- }
-
- /**
- * @param width the current view width
- * @param height the current view height
- */
-
- public static native void initialize(Godot p_instance,boolean need_reload_hook,String[] p_cmdline);
- public static native void resize(int width, int height,boolean reload);
- public static native void newcontext();
- public static native void quit();
- public static native void step();
- public static native void touch(int what,int pointer,int howmany, int[] arr);
- public static native void accelerometer(float x, float y, float z);
- public static native void key(int p_scancode, int p_unicode_char, boolean p_pressed);
- public static native void joybutton(int p_device, int p_but, boolean p_pressed);
- public static native void joyaxis(int p_device, int p_axis, float p_value);
- public static native void focusin();
- public static native void focusout();
- public static native void audio();
- public static native void singleton(String p_name,Object p_object);
- public static native void method(String p_sname,String p_name,String p_ret,String[] p_params);
- public static native String getGlobal(String p_key);
- public static native void callobject(int p_ID, String p_method, Object[] p_params);
- public static native void calldeferred(int p_ID, String p_method, Object[] p_params);
-
-}
diff --git a/platform/android/java/src/com/android/godot/GodotPaymentV3.java b/platform/android/java/src/com/android/godot/GodotPaymentV3.java
deleted file mode 100644
index 0fd102ac55..0000000000
--- a/platform/android/java/src/com/android/godot/GodotPaymentV3.java
+++ /dev/null
@@ -1,128 +0,0 @@
-package com.android.godot;
-
-import com.android.godot.Dictionary;
-import android.app.Activity;
-import android.util.Log;
-
-
-public class GodotPaymentV3 extends Godot.SingletonBase {
-
- private Godot activity;
-
- private Integer purchaseCallbackId = 0;
-
- private String accessToken;
-
- private String purchaseValidationUrlPrefix;
-
- private String transactionId;
-
- public void purchase( String _sku, String _transactionId) {
- final String sku = _sku;
- final String transactionId = _transactionId;
- activity.getPaymentsManager().setBaseSingleton(this);
- activity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- activity.getPaymentsManager().requestPurchase(sku, transactionId);
- }
- });
- };
-
-/* public string requestPurchasedTicket(){
- activity.getPaymentsManager()
- }
-
-*/
- static public Godot.SingletonBase initialize(Activity p_activity) {
-
- return new GodotPaymentV3(p_activity);
- }
-
-
- public GodotPaymentV3(Activity p_activity) {
-
- registerClass("GodotPayments", new String[] {"purchase", "setPurchaseCallbackId", "setPurchaseValidationUrlPrefix", "setTransactionId", "getSignature", "consumeUnconsumedPurchases"});
- activity=(Godot) p_activity;
- }
-
- public void consumeUnconsumedPurchases(){
- activity.getPaymentsManager().setBaseSingleton(this);
- activity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- activity.getPaymentsManager().consumeUnconsumedPurchases();
- }
- });
-
- }
-
- private String signature;
- public String getSignature(){
- return this.signature;
- }
-
-
- public void callbackSuccess(String ticket, String signature){
-// Log.d(this.getClass().getName(), "PRE-Send callback to purchase success");
- GodotLib.callobject(purchaseCallbackId, "purchase_success", new Object[]{ticket, signature});
-// Log.d(this.getClass().getName(), "POST-Send callback to purchase success");
-}
-
- public void callbackSuccessProductMassConsumed(String ticket, String signature, String sku){
-// Log.d(this.getClass().getName(), "PRE-Send callback to consume success");
- GodotLib.calldeferred(purchaseCallbackId, "consume_success", new Object[]{ticket, signature, sku});
-// Log.d(this.getClass().getName(), "POST-Send callback to consume success");
- }
-
- public void callbackSuccessNoUnconsumedPurchases(){
- GodotLib.calldeferred(purchaseCallbackId, "no_validation_required", new Object[]{});
- }
-
- public void callbackFail(){
- GodotLib.calldeferred(purchaseCallbackId, "purchase_fail", new Object[]{});
-// GodotLib.callobject(purchaseCallbackId, "purchase_fail", new Object[]{});
- }
-
- public void callbackCancel(){
- GodotLib.calldeferred(purchaseCallbackId, "purchase_cancel", new Object[]{});
-// GodotLib.callobject(purchaseCallbackId, "purchase_cancel", new Object[]{});
- }
-
- public int getPurchaseCallbackId() {
- return purchaseCallbackId;
- }
-
- public void setPurchaseCallbackId(int purchaseCallbackId) {
- this.purchaseCallbackId = purchaseCallbackId;
- }
-
-
-
- public String getPurchaseValidationUrlPrefix(){
- return this.purchaseValidationUrlPrefix ;
- }
-
- public void setPurchaseValidationUrlPrefix(String url){
- this.purchaseValidationUrlPrefix = url;
- }
-
-
- public String getAccessToken() {
- return accessToken;
- }
-
-
- public void setAccessToken(String accessToken) {
- this.accessToken = accessToken;
- }
-
- public void setTransactionId(String transactionId){
- this.transactionId = transactionId;
- }
-
- public String getTransactionId(){
- return this.transactionId;
- }
-
-}
diff --git a/platform/android/java/src/com/android/godot/GodotView.java b/platform/android/java/src/com/android/godot/GodotView.java
deleted file mode 100644
index ad0354e624..0000000000
--- a/platform/android/java/src/com/android/godot/GodotView.java
+++ /dev/null
@@ -1,641 +0,0 @@
-/*************************************************************************/
-/* GodotView.java */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* http://www.godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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. */
-/*************************************************************************/
-package com.android.godot;
-import android.content.Context;
-import android.graphics.PixelFormat;
-import android.opengl.GLSurfaceView;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.content.ContextWrapper;
-import android.view.InputDevice;
-
-import java.io.File;
-import javax.microedition.khronos.egl.EGL10;
-import javax.microedition.khronos.egl.EGLConfig;
-import javax.microedition.khronos.egl.EGLContext;
-import javax.microedition.khronos.egl.EGLDisplay;
-import javax.microedition.khronos.opengles.GL10;
-
-/**
- * A simple GLSurfaceView sub-class that demonstrate how to perform
- * OpenGL ES 2.0 rendering into a GL Surface. Note the following important
- * details:
- *
- * - The class must use a custom context factory to enable 2.0 rendering.
- * See ContextFactory class definition below.
- *
- * - The class must use a custom EGLConfigChooser to be able to select
- * an EGLConfig that supports 2.0. This is done by providing a config
- * specification to eglChooseConfig() that has the attribute
- * EGL10.ELG_RENDERABLE_TYPE containing the EGL_OPENGL_ES2_BIT flag
- * set. See ConfigChooser class definition below.
- *
- * - The class must select the surface's format, then choose an EGLConfig
- * that matches it exactly (with regards to red/green/blue/alpha channels
- * bit depths). Failure to do so would result in an EGL_BAD_MATCH error.
- */
-public class GodotView extends GLSurfaceView {
-
- private static String TAG = "GodotView";
- private static final boolean DEBUG = false;
- private static Context ctx;
-
- private static GodotIO io;
- private static boolean firsttime=true;
- private static boolean use_gl2=false;
- private static boolean use_32=false;
-
- private Godot activity;
-
- public GodotView(Context context,GodotIO p_io,boolean p_use_gl2, boolean p_use_32_bits, Godot p_activity) {
- super(context);
- ctx=context;
- io=p_io;
- use_gl2=p_use_gl2;
- use_32=p_use_32_bits;
-
- activity = p_activity;
-
- if (!p_io.needsReloadHooks()) {
- //will only work on SDK 11+!!
- setPreserveEGLContextOnPause(true);
- }
-
- init(false, 16, 0);
- }
-
- public GodotView(Context context, boolean translucent, int depth, int stencil) {
- super(context);
- init(translucent, depth, stencil);
- }
-
- @Override public boolean onTouchEvent (MotionEvent event) {
-
- return activity.gotTouchEvent(event);
- };
-
- public int get_godot_button(int keyCode) {
-
- int button = 0;
- switch (keyCode) {
- case KeyEvent.KEYCODE_BUTTON_A: // Android A is SNES B
- button = 0;
- break;
- case KeyEvent.KEYCODE_BUTTON_B:
- button = 1;
- break;
- case KeyEvent.KEYCODE_BUTTON_X: // Android X is SNES Y
- button = 2;
- break;
- case KeyEvent.KEYCODE_BUTTON_Y:
- button = 3;
- break;
- case KeyEvent.KEYCODE_BUTTON_L1:
- button = 4;
- break;
- case KeyEvent.KEYCODE_BUTTON_L2:
- button = 6;
- break;
- case KeyEvent.KEYCODE_BUTTON_R1:
- button = 5;
- break;
- case KeyEvent.KEYCODE_BUTTON_R2:
- button = 7;
- break;
- case KeyEvent.KEYCODE_BUTTON_SELECT:
- button = 10;
- break;
- case KeyEvent.KEYCODE_BUTTON_START:
- button = 11;
- break;
- case KeyEvent.KEYCODE_BUTTON_THUMBL:
- button = 8;
- break;
- case KeyEvent.KEYCODE_BUTTON_THUMBR:
- button = 9;
- break;
- case KeyEvent.KEYCODE_DPAD_UP:
- button = 12;
- break;
- case KeyEvent.KEYCODE_DPAD_DOWN:
- button = 13;
- break;
- case KeyEvent.KEYCODE_DPAD_LEFT:
- button = 14;
- break;
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- button = 15;
- break;
-
- default:
- button = keyCode - KeyEvent.KEYCODE_BUTTON_1;
- break;
- };
-
- return button;
- };
-
- @Override public boolean onKeyUp(int keyCode, KeyEvent event) {
-
- if (keyCode == KeyEvent.KEYCODE_BACK) {
- return true;
- }
-
- if (keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
- return super.onKeyUp(keyCode, event);
- };
-
- int source = event.getSource();
- if ((source & InputDevice.SOURCE_JOYSTICK) != 0 || (source & InputDevice.SOURCE_DPAD) != 0 || (source & InputDevice.SOURCE_GAMEPAD) != 0) {
-
- int button = get_godot_button(keyCode);
- int device = event.getDeviceId();
-
- GodotLib.joybutton(device, button, false);
- return true;
- } else {
-
- GodotLib.key(keyCode, event.getUnicodeChar(0), false);
- };
- return super.onKeyUp(keyCode, event);
- };
-
- @Override public boolean onKeyDown(int keyCode, KeyEvent event) {
-
- if (keyCode == KeyEvent.KEYCODE_BACK) {
- GodotLib.quit();
- // press 'back' button should not terminate program
- // normal handle 'back' event in game logic
- return true;
- }
-
- if (keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
- return super.onKeyDown(keyCode, event);
- };
-
- int source = event.getSource();
- //Log.e(TAG, String.format("Key down! source %d, device %d, joystick %d, %d, %d", event.getDeviceId(), source, (source & InputDevice.SOURCE_JOYSTICK), (source & InputDevice.SOURCE_DPAD), (source & InputDevice.SOURCE_GAMEPAD)));
-
- if ((source & InputDevice.SOURCE_JOYSTICK) != 0 || (source & InputDevice.SOURCE_DPAD) != 0 || (source & InputDevice.SOURCE_GAMEPAD) != 0) {
-
- if (event.getRepeatCount() > 0) // ignore key echo
- return true;
- int button = get_godot_button(keyCode);
- int device = event.getDeviceId();
- //Log.e(TAG, String.format("joy button down! button %x, %d, device %d", keyCode, button, device));
-
- GodotLib.joybutton(device, button, true);
- return true;
-
- } else {
- GodotLib.key(keyCode, event.getUnicodeChar(0), true);
- };
- return super.onKeyDown(keyCode, event);
- }
-
- public float axis_value(MotionEvent p_event, InputDevice p_device, int p_axis, int p_pos) {
-
- final InputDevice.MotionRange range = p_device.getMotionRange(p_axis, p_event.getSource());
- if (range == null)
- return 0;
-
- //Log.e(TAG, String.format("axis ranges %f, %f, %f", range.getRange(), range.getMin(), range.getMax()));
-
- final float flat = range.getFlat();
- final float value =
- p_pos < 0 ? p_event.getAxisValue(p_axis):
- p_event.getHistoricalAxisValue(p_axis, p_pos);
-
- final float absval = Math.abs(value);
- if (absval <= flat) {
- return 0;
- };
-
- final float ret = (value - range.getMin()) / range.getRange() * 2 - 1.0f;
-
- return ret;
- };
-
- float[] last_axis_values = { 0, 0, 0, 0, -1, -1 };
- boolean[] last_axis_buttons = { false, false, false, false, false, false }; // dpad up down left right, ltrigger, rtrigger
-
- public void process_axis_state(MotionEvent p_event, int p_pos) {
-
- int device_id = p_event.getDeviceId();
- InputDevice device = p_event.getDevice();
- float val;
-
- val = axis_value(p_event, device, MotionEvent.AXIS_X, p_pos);
- if (val != last_axis_values[0]) {
- last_axis_values[0] = val;
- //Log.e(TAG, String.format("axis moved! axis %d, value %f", 0, val));
- GodotLib.joyaxis(device_id, 0, val);
- };
-
- val = axis_value(p_event, device, MotionEvent.AXIS_Y, p_pos);
- if (val != last_axis_values[1]) {
- last_axis_values[1] = val;
- //Log.e(TAG, String.format("axis moved! axis %d, value %f", 1, val));
- GodotLib.joyaxis(device_id, 1, val);
- };
-
- val = axis_value(p_event, device, MotionEvent.AXIS_Z, p_pos);
- if (val != last_axis_values[2]) {
- last_axis_values[2] = val;
- //Log.e(TAG, String.format("axis moved! axis %d, value %f", 2, val));
- GodotLib.joyaxis(device_id, 2, val);
- };
-
- val = axis_value(p_event, device, MotionEvent.AXIS_RZ, p_pos);
- if (val != last_axis_values[3]) {
- last_axis_values[3] = val;
- //Log.e(TAG, String.format("axis moved! axis %d, value %f", 3, val));
- GodotLib.joyaxis(device_id, 3, val);
- };
-
- val = axis_value(p_event, device, MotionEvent.AXIS_LTRIGGER, p_pos);
- if (val != last_axis_values[4]) {
- last_axis_values[4] = val;
- if ((val != 0) != (last_axis_buttons[4])) {
- last_axis_buttons[4] = (val != 0);
- GodotLib.joybutton(device_id, 6, (val != 0));
- };
- };
-
- val = axis_value(p_event, device, MotionEvent.AXIS_RTRIGGER, p_pos);
- if (val != last_axis_values[5]) {
- last_axis_values[5] = val;
- if ((val != 0) != (last_axis_buttons[5])) {
- last_axis_buttons[5] = (val != 0);
- GodotLib.joybutton(device_id, 7, (val != 0));
- };
- };
-
- val = axis_value(p_event, device, MotionEvent.AXIS_HAT_Y, p_pos);
-
- if (last_axis_buttons[0] != (val > 0)) {
- last_axis_buttons[0] = val > 0;
- GodotLib.joybutton(device_id, 12, val > 0);
- };
- if (last_axis_buttons[1] != (val < 0)) {
- last_axis_buttons[1] = val < 0;
- GodotLib.joybutton(device_id, 13, val > 0);
- };
-
- val = axis_value(p_event, device, MotionEvent.AXIS_HAT_X, p_pos);
- if (last_axis_buttons[2] != (val < 0)) {
- last_axis_buttons[2] = val < 0;
- GodotLib.joybutton(device_id, 14, val < 0);
- };
- if (last_axis_buttons[3] != (val > 0)) {
- last_axis_buttons[3] = val > 0;
- GodotLib.joybutton(device_id, 15, val > 0);
- };
- };
-
- @Override public boolean onGenericMotionEvent(MotionEvent event) {
-
- if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK && event.getAction() == MotionEvent.ACTION_MOVE) {
-
- // Process all historical movement samples in the batch
- final int historySize = event.getHistorySize();
-
- // Process the movements starting from the
- // earliest historical position in the batch
- for (int i = 0; i < historySize; i++) {
- // Process the event at historical position i
- process_axis_state(event, i);
- }
-
- // Process the current movement sample in the batch (position -1)
- process_axis_state(event, -1);
- return true;
-
-
- };
-
- return super.onGenericMotionEvent(event);
- };
-
-
- private void init(boolean translucent, int depth, int stencil) {
-
- this.setFocusableInTouchMode(true);
- /* By default, GLSurfaceView() creates a RGB_565 opaque surface.
- * If we want a translucent one, we should change the surface's
- * format here, using PixelFormat.TRANSLUCENT for GL Surfaces
- * is interpreted as any 32-bit surface with alpha by SurfaceFlinger.
- */
- if (translucent) {
- this.getHolder().setFormat(PixelFormat.TRANSLUCENT);
- }
-
- /* Setup the context factory for 2.0 rendering.
- * See ContextFactory class definition below
- */
- setEGLContextFactory(new ContextFactory());
-
- /* We need to choose an EGLConfig that matches the format of
- * our surface exactly. This is going to be done in our
- * custom config chooser. See ConfigChooser class definition
- * below.
- */
-
- if (use_32) {
- setEGLConfigChooser( translucent ?
- new ConfigChooser(8, 8, 8, 8, 24, stencil) :
- new ConfigChooser(8, 8, 8, 8, 24, stencil) );
-
- } else {
- setEGLConfigChooser( translucent ?
- new ConfigChooser(8, 8, 8, 8, 16, stencil) :
- new ConfigChooser(5, 6, 5, 0, 16, stencil) );
- }
-
- /* Set the renderer responsible for frame rendering */
- setRenderer(new Renderer());
- }
-
- private static class ContextFactory implements GLSurfaceView.EGLContextFactory {
- private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
- public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {
- if (use_gl2)
- Log.w(TAG, "creating OpenGL ES 2.0 context :");
- else
- Log.w(TAG, "creating OpenGL ES 1.1 context :");
-
- checkEglError("Before eglCreateContext", egl);
- int[] attrib_list2 = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
- EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, use_gl2?attrib_list2:null);
- checkEglError("After eglCreateContext", egl);
- return context;
- }
-
- public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {
- egl.eglDestroyContext(display, context);
- }
- }
-
- private static void checkEglError(String prompt, EGL10 egl) {
- int error;
- while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) {
- Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error));
- }
- }
-
- private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser {
-
- public ConfigChooser(int r, int g, int b, int a, int depth, int stencil) {
- mRedSize = r;
- mGreenSize = g;
- mBlueSize = b;
- mAlphaSize = a;
- mDepthSize = depth;
- mStencilSize = stencil;
- }
-
- /* This EGL config specification is used to specify 2.0 rendering.
- * We use a minimum size of 4 bits for red/green/blue, but will
- * perform actual matching in chooseConfig() below.
- */
- private static int EGL_OPENGL_ES2_BIT = 4;
- private static int[] s_configAttribs2 =
- {
- EGL10.EGL_RED_SIZE, 4,
- EGL10.EGL_GREEN_SIZE, 4,
- EGL10.EGL_BLUE_SIZE, 4,
- // EGL10.EGL_DEPTH_SIZE, 16,
- // EGL10.EGL_STENCIL_SIZE, EGL10.EGL_DONT_CARE,
- EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
- EGL10.EGL_NONE
- };
- private static int[] s_configAttribs =
- {
- EGL10.EGL_RED_SIZE, 4,
- EGL10.EGL_GREEN_SIZE, 4,
- EGL10.EGL_BLUE_SIZE, 4,
- // EGL10.EGL_DEPTH_SIZE, 16,
- // EGL10.EGL_STENCIL_SIZE, EGL10.EGL_DONT_CARE,
- EGL10.EGL_NONE
- };
-
- public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
-
- /* Get the number of minimally matching EGL configurations
- */
- int[] num_config = new int[1];
- egl.eglChooseConfig(display, use_gl2?s_configAttribs2:s_configAttribs, null, 0, num_config);
-
- int numConfigs = num_config[0];
-
- if (numConfigs <= 0) {
- throw new IllegalArgumentException("No configs match configSpec");
- }
-
- /* Allocate then read the array of minimally matching EGL configs
- */
- EGLConfig[] configs = new EGLConfig[numConfigs];
- egl.eglChooseConfig(display, use_gl2?s_configAttribs2:s_configAttribs, configs, numConfigs, num_config);
-
- if (DEBUG) {
- printConfigs(egl, display, configs);
- }
- /* Now return the "best" one
- */
- return chooseConfig(egl, display, configs);
- }
-
- public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
- EGLConfig[] configs) {
- for(EGLConfig config : configs) {
- int d = findConfigAttrib(egl, display, config,
- EGL10.EGL_DEPTH_SIZE, 0);
- int s = findConfigAttrib(egl, display, config,
- EGL10.EGL_STENCIL_SIZE, 0);
-
- // We need at least mDepthSize and mStencilSize bits
- if (d < mDepthSize || s < mStencilSize)
- continue;
-
- // We want an *exact* match for red/green/blue/alpha
- int r = findConfigAttrib(egl, display, config,
- EGL10.EGL_RED_SIZE, 0);
- int g = findConfigAttrib(egl, display, config,
- EGL10.EGL_GREEN_SIZE, 0);
- int b = findConfigAttrib(egl, display, config,
- EGL10.EGL_BLUE_SIZE, 0);
- int a = findConfigAttrib(egl, display, config,
- EGL10.EGL_ALPHA_SIZE, 0);
-
- if (r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize)
- return config;
- }
- return null;
- }
-
- private int findConfigAttrib(EGL10 egl, EGLDisplay display,
- EGLConfig config, int attribute, int defaultValue) {
-
- if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
- return mValue[0];
- }
- return defaultValue;
- }
-
- private void printConfigs(EGL10 egl, EGLDisplay display,
- EGLConfig[] configs) {
- int numConfigs = configs.length;
- Log.w(TAG, String.format("%d configurations", numConfigs));
- for (int i = 0; i < numConfigs; i++) {
- Log.w(TAG, String.format("Configuration %d:\n", i));
- printConfig(egl, display, configs[i]);
- }
- }
-
- private void printConfig(EGL10 egl, EGLDisplay display,
- EGLConfig config) {
- int[] attributes = {
- EGL10.EGL_BUFFER_SIZE,
- EGL10.EGL_ALPHA_SIZE,
- EGL10.EGL_BLUE_SIZE,
- EGL10.EGL_GREEN_SIZE,
- EGL10.EGL_RED_SIZE,
- EGL10.EGL_DEPTH_SIZE,
- EGL10.EGL_STENCIL_SIZE,
- EGL10.EGL_CONFIG_CAVEAT,
- EGL10.EGL_CONFIG_ID,
- EGL10.EGL_LEVEL,
- EGL10.EGL_MAX_PBUFFER_HEIGHT,
- EGL10.EGL_MAX_PBUFFER_PIXELS,
- EGL10.EGL_MAX_PBUFFER_WIDTH,
- EGL10.EGL_NATIVE_RENDERABLE,
- EGL10.EGL_NATIVE_VISUAL_ID,
- EGL10.EGL_NATIVE_VISUAL_TYPE,
- 0x3030, // EGL10.EGL_PRESERVED_RESOURCES,
- EGL10.EGL_SAMPLES,
- EGL10.EGL_SAMPLE_BUFFERS,
- EGL10.EGL_SURFACE_TYPE,
- EGL10.EGL_TRANSPARENT_TYPE,
- EGL10.EGL_TRANSPARENT_RED_VALUE,
- EGL10.EGL_TRANSPARENT_GREEN_VALUE,
- EGL10.EGL_TRANSPARENT_BLUE_VALUE,
- 0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB,
- 0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA,
- 0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL,
- 0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL,
- EGL10.EGL_LUMINANCE_SIZE,
- EGL10.EGL_ALPHA_MASK_SIZE,
- EGL10.EGL_COLOR_BUFFER_TYPE,
- EGL10.EGL_RENDERABLE_TYPE,
- 0x3042 // EGL10.EGL_CONFORMANT
- };
- String[] names = {
- "EGL_BUFFER_SIZE",
- "EGL_ALPHA_SIZE",
- "EGL_BLUE_SIZE",
- "EGL_GREEN_SIZE",
- "EGL_RED_SIZE",
- "EGL_DEPTH_SIZE",
- "EGL_STENCIL_SIZE",
- "EGL_CONFIG_CAVEAT",
- "EGL_CONFIG_ID",
- "EGL_LEVEL",
- "EGL_MAX_PBUFFER_HEIGHT",
- "EGL_MAX_PBUFFER_PIXELS",
- "EGL_MAX_PBUFFER_WIDTH",
- "EGL_NATIVE_RENDERABLE",
- "EGL_NATIVE_VISUAL_ID",
- "EGL_NATIVE_VISUAL_TYPE",
- "EGL_PRESERVED_RESOURCES",
- "EGL_SAMPLES",
- "EGL_SAMPLE_BUFFERS",
- "EGL_SURFACE_TYPE",
- "EGL_TRANSPARENT_TYPE",
- "EGL_TRANSPARENT_RED_VALUE",
- "EGL_TRANSPARENT_GREEN_VALUE",
- "EGL_TRANSPARENT_BLUE_VALUE",
- "EGL_BIND_TO_TEXTURE_RGB",
- "EGL_BIND_TO_TEXTURE_RGBA",
- "EGL_MIN_SWAP_INTERVAL",
- "EGL_MAX_SWAP_INTERVAL",
- "EGL_LUMINANCE_SIZE",
- "EGL_ALPHA_MASK_SIZE",
- "EGL_COLOR_BUFFER_TYPE",
- "EGL_RENDERABLE_TYPE",
- "EGL_CONFORMANT"
- };
- int[] value = new int[1];
- for (int i = 0; i < attributes.length; i++) {
- int attribute = attributes[i];
- String name = names[i];
- if ( egl.eglGetConfigAttrib(display, config, attribute, value)) {
- Log.w(TAG, String.format(" %s: %d\n", name, value[0]));
- } else {
- // Log.w(TAG, String.format(" %s: failed\n", name));
- while (egl.eglGetError() != EGL10.EGL_SUCCESS);
- }
- }
- }
-
- // Subclasses can adjust these values:
- protected int mRedSize;
- protected int mGreenSize;
- protected int mBlueSize;
- protected int mAlphaSize;
- protected int mDepthSize;
- protected int mStencilSize;
- private int[] mValue = new int[1];
- }
-
- private static class Renderer implements GLSurfaceView.Renderer {
-
-
- public void onDrawFrame(GL10 gl) {
- GodotLib.step();
- for(int i=0;i<Godot.singleton_count;i++) {
- Godot.singletons[i].onGLDrawFrame(gl);
- }
- }
-
- public void onSurfaceChanged(GL10 gl, int width, int height) {
-
- GodotLib.resize(width, height,!firsttime);
- firsttime=false;
- for(int i=0;i<Godot.singleton_count;i++) {
- Godot.singletons[i].onGLSurfaceChanged(gl, width, height);
- }
- }
-
- public void onSurfaceCreated(GL10 gl, EGLConfig config) {
- GodotLib.newcontext();
- }
- }
-}
diff --git a/platform/android/java/src/com/android/godot/input/GodotEditText.java b/platform/android/java/src/com/android/godot/input/GodotEditText.java
deleted file mode 100644
index 5898e95423..0000000000
--- a/platform/android/java/src/com/android/godot/input/GodotEditText.java
+++ /dev/null
@@ -1,133 +0,0 @@
-package com.android.godot.input;
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.KeyEvent;
-import android.widget.EditText;
-import com.android.godot.*;
-import android.os.Handler;
-import android.os.Message;
-import android.view.inputmethod.InputMethodManager;
-import android.view.inputmethod.EditorInfo;
-
-public class GodotEditText extends EditText {
- // ===========================================================
- // Constants
- // ===========================================================
- private final static int HANDLER_OPEN_IME_KEYBOARD = 2;
- private final static int HANDLER_CLOSE_IME_KEYBOARD = 3;
-
- // ===========================================================
- // Fields
- // ===========================================================
- private GodotView mView;
- private GodotTextInputWrapper mInputWrapper;
- private static Handler sHandler;
- private String mOriginText;
-
- // ===========================================================
- // Constructors
- // ===========================================================
- public GodotEditText(final Context context) {
- super(context);
- this.initView();
- }
-
- public GodotEditText(final Context context, final AttributeSet attrs) {
- super(context, attrs);
- this.initView();
- }
-
- public GodotEditText(final Context context, final AttributeSet attrs, final int defStyle) {
- super(context, attrs, defStyle);
- this.initView();
- }
-
- protected void initView() {
- this.setPadding(0, 0, 0, 0);
- this.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);
-
- sHandler = new Handler() {
- @Override
- public void handleMessage(final Message msg) {
- switch (msg.what) {
- case HANDLER_OPEN_IME_KEYBOARD:
- {
- GodotEditText edit = (GodotEditText) msg.obj;
- String text = edit.mOriginText;
- if (edit.requestFocus())
- {
- edit.removeTextChangedListener(edit.mInputWrapper);
- edit.setText("");
- edit.append(text);
- edit.mInputWrapper.setOriginText(text);
- edit.addTextChangedListener(edit.mInputWrapper);
- final InputMethodManager imm = (InputMethodManager) mView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
- imm.showSoftInput(edit, 0);
- }
- }
- break;
-
- case HANDLER_CLOSE_IME_KEYBOARD:
- {
- GodotEditText edit = (GodotEditText) msg.obj;
-
- edit.removeTextChangedListener(mInputWrapper);
- final InputMethodManager imm = (InputMethodManager) mView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
- imm.hideSoftInputFromWindow(edit.getWindowToken(), 0);
- edit.mView.requestFocus();
- }
- break;
- }
- }
- };
- }
-
- // ===========================================================
- // Getter & Setter
- // ===========================================================
- public void setView(final GodotView view) {
- this.mView = view;
- if(mInputWrapper == null)
- mInputWrapper = new GodotTextInputWrapper(mView, this);
- this.setOnEditorActionListener(mInputWrapper);
- view.requestFocus();
- }
-
- // ===========================================================
- // Methods for/from SuperClass/Interfaces
- // ===========================================================
- @Override
- public boolean onKeyDown(final int keyCode, final KeyEvent keyEvent) {
- super.onKeyDown(keyCode, keyEvent);
-
- /* Let GlSurfaceView get focus if back key is input. */
- if (keyCode == KeyEvent.KEYCODE_BACK) {
- this.mView.requestFocus();
- }
-
- return true;
- }
-
- // ===========================================================
- // Methods
- // ===========================================================
- public void showKeyboard(String p_existing_text) {
- this.mOriginText = p_existing_text;
-
- final Message msg = new Message();
- msg.what = HANDLER_OPEN_IME_KEYBOARD;
- msg.obj = this;
- sHandler.sendMessage(msg);
- }
-
- public void hideKeyboard() {
- final Message msg = new Message();
- msg.what = HANDLER_CLOSE_IME_KEYBOARD;
- msg.obj = this;
- sHandler.sendMessage(msg);
- }
-
- // ===========================================================
- // Inner and Anonymous Classes
- // ===========================================================
-}
diff --git a/platform/android/java/src/com/android/godot/input/GodotTextInputWrapper.java b/platform/android/java/src/com/android/godot/input/GodotTextInputWrapper.java
deleted file mode 100644
index 537fa6aa76..0000000000
--- a/platform/android/java/src/com/android/godot/input/GodotTextInputWrapper.java
+++ /dev/null
@@ -1,154 +0,0 @@
-package com.android.godot.input;
-import android.content.Context;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.TextView;
-import android.widget.TextView.OnEditorActionListener;
-import com.android.godot.*;
-
-public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListener {
- // ===========================================================
- // Constants
- // ===========================================================
- private static final String TAG = GodotTextInputWrapper.class.getSimpleName();
-
- // ===========================================================
- // Fields
- // ===========================================================
- private final GodotView mView;
- private final GodotEditText mEdit;
- private String mText;
- private String mOriginText;
-
- // ===========================================================
- // Constructors
- // ===========================================================
-
- public GodotTextInputWrapper(final GodotView view, final GodotEditText edit) {
- this.mView = view;
- this.mEdit = edit;
- }
-
- // ===========================================================
- // Getter & Setter
- // ===========================================================
-
- private boolean isFullScreenEdit() {
- final TextView textField = this.mEdit;
- final InputMethodManager imm = (InputMethodManager) textField.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
- return imm.isFullscreenMode();
- }
-
- public void setOriginText(final String originText) {
- this.mOriginText = originText;
- }
-
- // ===========================================================
- // Methods for/from SuperClass/Interfaces
- // ===========================================================
-
- @Override
- public void afterTextChanged(final Editable s) {
- if (this.isFullScreenEdit()) {
- return;
- }
-
- //if (BuildConfig.DEBUG) {
- //Log.d(TAG, "afterTextChanged: " + s);
- //}
- int nModified = s.length() - this.mText.length();
- if (nModified > 0) {
- final String insertText = s.subSequence(this.mText.length(), s.length()).toString();
- for(int i = 0; i < insertText.length(); i++) {
- int ch = insertText.codePointAt(i);
- GodotLib.key(0, ch, true);
- GodotLib.key(0, ch, false);
- }
- /*
- if (BuildConfig.DEBUG) {
- Log.d(TAG, "insertText(" + insertText + ")");
- }
- */
- } else {
- for (; nModified < 0; ++nModified) {
- GodotLib.key(KeyEvent.KEYCODE_DEL, 0, true);
- GodotLib.key(KeyEvent.KEYCODE_DEL, 0, false);
- /*
- if (BuildConfig.DEBUG) {
- Log.d(TAG, "deleteBackward");
- }
- */
- }
- }
- this.mText = s.toString();
- }
-
- @Override
- public void beforeTextChanged(final CharSequence pCharSequence, final int start, final int count, final int after) {
- /*
- if (BuildConfig.DEBUG) {
- Log.d(TAG, "beforeTextChanged(" + pCharSequence + ")start: " + start + ",count: " + count + ",after: " + after);
- }
- */
- this.mText = pCharSequence.toString();
- }
-
- @Override
- public void onTextChanged(final CharSequence pCharSequence, final int start, final int before, final int count) {
-
- }
-
- @Override
- public boolean onEditorAction(final TextView pTextView, final int pActionID, final KeyEvent pKeyEvent) {
- if (this.mEdit == pTextView && this.isFullScreenEdit()) {
- // user press the action button, delete all old text and insert new text
- for (int i = this.mOriginText.length(); i > 0; i--) {
- GodotLib.key(KeyEvent.KEYCODE_DEL, 0, true);
- GodotLib.key(KeyEvent.KEYCODE_DEL, 0, false);
- /*
- if (BuildConfig.DEBUG) {
- Log.d(TAG, "deleteBackward");
- }
- */
- }
- String text = pTextView.getText().toString();
-
- /* If user input nothing, translate "\n" to engine. */
- if (text.compareTo("") == 0) {
- text = "\n";
- }
-
- if ('\n' != text.charAt(text.length() - 1)) {
- text += '\n';
- }
-
- for(int i = 0; i < text.length(); i++) {
- int ch = text.codePointAt(i);
- GodotLib.key(0, ch, true);
- GodotLib.key(0, ch, false);
- }
- /*
- if (BuildConfig.DEBUG) {
- Log.d(TAG, "insertText(" + insertText + ")");
- }
- */
- }
-
- if (pActionID == EditorInfo.IME_ACTION_DONE) {
- this.mView.requestFocus();
- }
- return false;
- }
-
- // ===========================================================
- // Methods
- // ===========================================================
-
- // ===========================================================
- // Inner and Anonymous Classes
- // ===========================================================
-}
diff --git a/platform/android/java/src/com/android/godot/payments/ConsumeTask.java b/platform/android/java/src/com/android/godot/payments/ConsumeTask.java
deleted file mode 100644
index c983960770..0000000000
--- a/platform/android/java/src/com/android/godot/payments/ConsumeTask.java
+++ /dev/null
@@ -1,71 +0,0 @@
-package com.android.godot.payments;
-
-import com.android.vending.billing.IInAppBillingService;
-
-import android.content.Context;
-import android.os.AsyncTask;
-import android.os.RemoteException;
-import android.util.Log;
-
-abstract public class ConsumeTask {
-
- private Context context;
-
- private IInAppBillingService mService;
- public ConsumeTask(IInAppBillingService mService, Context context ){
- this.context = context;
- this.mService = mService;
- }
-
-
- public void consume(final String sku){
-// Log.d("XXX", "Consuming product " + sku);
- PaymentsCache pc = new PaymentsCache(context);
- Boolean isBlocked = pc.getConsumableFlag("block", sku);
- String _token = pc.getConsumableValue("token", sku);
-// Log.d("XXX", "token " + _token);
- if(!isBlocked && _token == null){
-// _token = "inapp:"+context.getPackageName()+":android.test.purchased";
-// Log.d("XXX", "Consuming product " + sku + " with token " + _token);
- }else if(!isBlocked){
-// Log.d("XXX", "It is not blocked ¿?");
- return;
- }else if(_token == null){
-// Log.d("XXX", "No token available");
- this.error("No token for sku:" + sku);
- return;
- }
- final String token = _token;
- new AsyncTask<String, String, String>(){
-
- @Override
- protected String doInBackground(String... params) {
- try {
-// Log.d("XXX", "Requesting to release item.");
- int response = mService.consumePurchase(3, context.getPackageName(), token);
-// Log.d("XXX", "release response code: " + response);
- if(response == 0 || response == 8){
- return null;
- }
- } catch (RemoteException e) {
- return e.getMessage();
-
- }
- return "Some error";
- }
-
- protected void onPostExecute(String param){
- if(param == null){
- success( new PaymentsCache(context).getConsumableValue("ticket", sku) );
- }else{
- error(param);
- }
- }
-
- }.execute();
- }
-
- abstract protected void success(String ticket);
- abstract protected void error(String message);
-
-}
diff --git a/platform/android/java/src/com/android/godot/payments/GenericConsumeTask.java b/platform/android/java/src/com/android/godot/payments/GenericConsumeTask.java
deleted file mode 100644
index d68f029246..0000000000
--- a/platform/android/java/src/com/android/godot/payments/GenericConsumeTask.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package com.android.godot.payments;
-
-import com.android.vending.billing.IInAppBillingService;
-
-import android.content.Context;
-import android.os.AsyncTask;
-import android.os.RemoteException;
-import android.util.Log;
-
-abstract public class GenericConsumeTask extends AsyncTask<String, String, String>{
-
- private Context context;
- private IInAppBillingService mService;
-
-
-
-
- public GenericConsumeTask(Context context, IInAppBillingService mService, String sku, String receipt, String signature, String token){
- this.context = context;
- this.mService = mService;
- this.sku = sku;
- this.receipt = receipt;
- this.signature = signature;
- this.token = token;
- }
-
- private String sku;
- private String receipt;
- private String signature;
- private String token;
-
- @Override
- protected String doInBackground(String... params) {
- try {
-// Log.d("godot", "Requesting to consume an item with token ." + token);
- int response = mService.consumePurchase(3, context.getPackageName(), token);
-// Log.d("godot", "consumePurchase response: " + response);
- if(response == 0 || response == 8){
- return null;
- }
- } catch (Exception e) {
- Log.d("godot", "Error " + e.getClass().getName() + ":" + e.getMessage());
- }
- return null;
- }
-
- protected void onPostExecute(String sarasa){
- onSuccess(sku, receipt, signature, token);
- }
-
- abstract public void onSuccess(String sku, String receipt, String signature, String token);
-
-}
diff --git a/platform/android/java/src/com/android/godot/payments/HandlePurchaseTask.java b/platform/android/java/src/com/android/godot/payments/HandlePurchaseTask.java
deleted file mode 100644
index 4c31704cc8..0000000000
--- a/platform/android/java/src/com/android/godot/payments/HandlePurchaseTask.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package com.android.godot.payments;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import com.android.godot.GodotLib;
-import com.android.godot.utils.Crypt;
-import com.android.vending.billing.IInAppBillingService;
-
-import android.app.Activity;
-import android.app.PendingIntent;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentSender.SendIntentException;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.util.Log;
-
-abstract public class HandlePurchaseTask {
-
- private Activity context;
-
- public HandlePurchaseTask(Activity context ){
- this.context = context;
- }
-
-
- public void handlePurchaseRequest(int resultCode, Intent data){
-// Log.d("XXX", "Handling purchase response");
-// int responseCode = data.getIntExtra("RESPONSE_CODE", 0);
- PaymentsCache pc = new PaymentsCache(context);
-
- String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
-// Log.d("XXX", "Purchase data:" + purchaseData);
- String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");
- //Log.d("XXX", "Purchase signature:" + dataSignature);
-
- if (resultCode == Activity.RESULT_OK) {
-
- try {
-// Log.d("SARLANGA", purchaseData);
-
-
- JSONObject jo = new JSONObject(purchaseData);
-// String sku = jo.getString("productId");
-// alert("You have bought the " + sku + ". Excellent choice, aventurer!");
-// String orderId = jo.getString("orderId");
-// String packageName = jo.getString("packageName");
- String productId = jo.getString("productId");
-// Long purchaseTime = jo.getLong("purchaseTime");
-// Integer state = jo.getInt("purchaseState");
- String developerPayload = jo.getString("developerPayload");
- String purchaseToken = jo.getString("purchaseToken");
-
- if(! pc.getConsumableValue("validation_hash", productId).equals(developerPayload) ) {
- error("Untrusted callback");
- return;
- }
-// Log.d("XXX", "Este es el product ID:" + productId);
- pc.setConsumableValue("ticket_signautre", productId, dataSignature);
- pc.setConsumableValue("ticket", productId, purchaseData);
- pc.setConsumableFlag("block", productId, true);
- pc.setConsumableValue("token", productId, purchaseToken);
-
- success(productId, dataSignature, purchaseData);
- return;
- } catch (JSONException e) {
- error(e.getMessage());
- }
- }else if( resultCode == Activity.RESULT_CANCELED){
- canceled();
- }
- }
-
- abstract protected void success(String sku, String signature, String ticket);
- abstract protected void error(String message);
- abstract protected void canceled();
-
-
-}
diff --git a/platform/android/java/src/com/android/godot/payments/PaymentsCache.java b/platform/android/java/src/com/android/godot/payments/PaymentsCache.java
deleted file mode 100644
index 1de772bf28..0000000000
--- a/platform/android/java/src/com/android/godot/payments/PaymentsCache.java
+++ /dev/null
@@ -1,45 +0,0 @@
-package com.android.godot.payments;
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.util.Log;
-
-public class PaymentsCache {
-
- public Context context;
-
- public PaymentsCache(Context context){
- this.context = context;
- }
-
-
- public void setConsumableFlag(String set, String sku, Boolean flag){
- SharedPreferences sharedPref = context.getSharedPreferences("consumables_" + set, Context.MODE_PRIVATE);
- SharedPreferences.Editor editor = sharedPref.edit();
- editor.putBoolean(sku, flag);
- editor.commit();
-}
-
- public boolean getConsumableFlag(String set, String sku){
- SharedPreferences sharedPref = context.getSharedPreferences(
- "consumables_" + set, Context.MODE_PRIVATE);
- return sharedPref.getBoolean(sku, false);
- }
-
-
- public void setConsumableValue(String set, String sku, String value){
- SharedPreferences sharedPref = context.getSharedPreferences("consumables_" + set, Context.MODE_PRIVATE);
- SharedPreferences.Editor editor = sharedPref.edit();
- editor.putString(sku, value);
-// Log.d("XXX", "Setting asset: consumables_" + set + ":" + sku);
- editor.commit();
- }
-
- public String getConsumableValue(String set, String sku){
- SharedPreferences sharedPref = context.getSharedPreferences(
- "consumables_" + set, Context.MODE_PRIVATE);
-// Log.d("XXX", "Getting asset: consumables_" + set + ":" + sku);
- return sharedPref.getString(sku, null);
- }
-
-}
diff --git a/platform/android/java/src/com/android/godot/payments/PaymentsManager.java b/platform/android/java/src/com/android/godot/payments/PaymentsManager.java
deleted file mode 100644
index fd1a62738a..0000000000
--- a/platform/android/java/src/com/android/godot/payments/PaymentsManager.java
+++ /dev/null
@@ -1,201 +0,0 @@
-package com.android.godot.payments;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import android.os.RemoteException;
-import android.app.Activity;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.IBinder;
-import android.util.Log;
-import android.os.Bundle;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.json.JSONStringer;
-
-import com.android.godot.Dictionary;
-import com.android.godot.Godot;
-import com.android.godot.GodotPaymentV3;
-import com.android.vending.billing.IInAppBillingService;
-
-public class PaymentsManager {
-
- public static final int BILLING_RESPONSE_RESULT_OK = 0;
-
-
- public static final int REQUEST_CODE_FOR_PURCHASE = 0x1001;
-
-
- private Activity activity;
- IInAppBillingService mService;
-
- public void setActivity(Activity activity){
- this.activity = activity;
- }
-
- public static PaymentsManager createManager(Activity activity){
- PaymentsManager manager = new PaymentsManager(activity);
- return manager;
- }
-
- private PaymentsManager(Activity activity){
- this.activity = activity;
- }
-
- public PaymentsManager initService(){
- activity.bindService(
- new Intent("com.android.vending.billing.InAppBillingService.BIND"),
- mServiceConn,
- Context.BIND_AUTO_CREATE);
- return this;
- }
-
- public void destroy(){
- if (mService != null) {
- activity.unbindService(mServiceConn);
- }
- }
-
- ServiceConnection mServiceConn = new ServiceConnection() {
- @Override
- public void onServiceDisconnected(ComponentName name) {
- mService = null;
- }
-
- @Override
- public void onServiceConnected(ComponentName name,
- IBinder service) {
- mService = IInAppBillingService.Stub.asInterface(service);
- }
- };
-
- public void requestPurchase(String sku, String transactionId){
- new PurchaseTask(mService, Godot.getInstance()) {
-
- @Override
- protected void error(String message) {
- godotPaymentV3.callbackFail();
-
- }
-
- @Override
- protected void canceled() {
- godotPaymentV3.callbackCancel();
- }
- }.purchase(sku, transactionId);
-
- }
-
- public void consumeUnconsumedPurchases(){
- new ReleaseAllConsumablesTask(mService, activity) {
-
- @Override
- protected void success(String sku, String receipt, String signature, String token) {
- godotPaymentV3.callbackSuccessProductMassConsumed(receipt, signature, sku);
- }
-
- @Override
- protected void error(String message) {
- godotPaymentV3.callbackFail();
-
- }
-
- @Override
- protected void notRequired() {
- godotPaymentV3.callbackSuccessNoUnconsumedPurchases();
-
- }
- }.consumeItAll();
- }
-
- public void processPurchaseResponse(int resultCode, Intent data) {
- new HandlePurchaseTask(activity){
-
- @Override
- protected void success(final String sku, final String signature, final String ticket) {
- godotPaymentV3.callbackSuccess(ticket, signature);
- new ConsumeTask(mService, activity) {
-
- @Override
- protected void success(String ticket) {
-// godotPaymentV3.callbackSuccess("");
- }
-
- @Override
- protected void error(String message) {
- godotPaymentV3.callbackFail();
-
- }
- }.consume(sku);
-
-
-// godotPaymentV3.callbackSuccess(new PaymentsCache(activity).getConsumableValue("ticket", sku),signature);
-// godotPaymentV3.callbackSuccess(ticket);
- //validatePurchase(purchaseToken, sku);
- }
-
- @Override
- protected void error(String message) {
- godotPaymentV3.callbackFail();
-
- }
-
- @Override
- protected void canceled() {
- godotPaymentV3.callbackCancel();
-
- }
- }.handlePurchaseRequest(resultCode, data);
- }
-
- public void validatePurchase(String purchaseToken, final String sku){
-
- new ValidateTask(activity, godotPaymentV3){
-
- @Override
- protected void success() {
-
- new ConsumeTask(mService, activity) {
-
- @Override
- protected void success(String ticket) {
- godotPaymentV3.callbackSuccess(ticket, null);
-
- }
-
- @Override
- protected void error(String message) {
- godotPaymentV3.callbackFail();
-
- }
- }.consume(sku);
-
- }
-
- @Override
- protected void error(String message) {
- godotPaymentV3.callbackFail();
-
- }
-
- @Override
- protected void canceled() {
- godotPaymentV3.callbackCancel();
-
- }
- }.validatePurchase(sku);
- }
-
- private GodotPaymentV3 godotPaymentV3;
-
- public void setBaseSingleton(GodotPaymentV3 godotPaymentV3) {
- this.godotPaymentV3 = godotPaymentV3;
-
- }
-
-}
-
diff --git a/platform/android/java/src/com/android/godot/payments/PurchaseTask.java b/platform/android/java/src/com/android/godot/payments/PurchaseTask.java
deleted file mode 100644
index 75662a442e..0000000000
--- a/platform/android/java/src/com/android/godot/payments/PurchaseTask.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package com.android.godot.payments;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import com.android.godot.GodotLib;
-import com.android.godot.utils.Crypt;
-import com.android.vending.billing.IInAppBillingService;
-
-import android.app.Activity;
-import android.app.PendingIntent;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentSender.SendIntentException;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.util.Log;
-
-abstract public class PurchaseTask {
-
- private Activity context;
-
- private IInAppBillingService mService;
- public PurchaseTask(IInAppBillingService mService, Activity context ){
- this.context = context;
- this.mService = mService;
- }
-
-
- private boolean isLooping = false;
-
- public void purchase(final String sku, final String transactionId){
- Log.d("XXX", "Starting purchase for: " + sku);
- PaymentsCache pc = new PaymentsCache(context);
- Boolean isBlocked = pc.getConsumableFlag("block", sku);
-// if(isBlocked){
-// Log.d("XXX", "Is awaiting payment confirmation");
-// error("Awaiting payment confirmation");
-// return;
-// }
- final String hash = transactionId;
-
- Bundle buyIntentBundle;
- try {
- buyIntentBundle = mService.getBuyIntent(3, context.getApplicationContext().getPackageName(), sku, "inapp", hash );
- } catch (RemoteException e) {
-// Log.d("XXX", "Error: " + e.getMessage());
- error(e.getMessage());
- return;
- }
- Object rc = buyIntentBundle.get("RESPONSE_CODE");
- int responseCode = 0;
- if(rc == null){
- responseCode = PaymentsManager.BILLING_RESPONSE_RESULT_OK;
- }else if( rc instanceof Integer){
- responseCode = ((Integer)rc).intValue();
- }else if( rc instanceof Long){
- responseCode = (int)((Long)rc).longValue();
- }
-// Log.d("XXX", "Buy intent response code: " + responseCode);
- if(responseCode == 1 || responseCode == 3 || responseCode == 4){
- canceled();
- return ;
- }
-
-
- PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT");
- pc.setConsumableValue("validation_hash", sku, hash);
- try {
- if(context == null){
-// Log.d("XXX", "No context!");
- }
- if(pendingIntent == null){
-// Log.d("XXX", "No pending intent");
- }
-// Log.d("XXX", "Starting activity for purchase!");
- context.startIntentSenderForResult(
- pendingIntent.getIntentSender(),
- PaymentsManager.REQUEST_CODE_FOR_PURCHASE,
- new Intent(),
- Integer.valueOf(0), Integer.valueOf(0),
- Integer.valueOf(0));
- } catch (SendIntentException e) {
- error(e.getMessage());
- }
-
-
-
- }
-
- abstract protected void error(String message);
- abstract protected void canceled();
-
-
-}
diff --git a/platform/android/java/src/com/android/godot/payments/ReleaseAllConsumablesTask.java b/platform/android/java/src/com/android/godot/payments/ReleaseAllConsumablesTask.java
deleted file mode 100644
index c1a9c5d421..0000000000
--- a/platform/android/java/src/com/android/godot/payments/ReleaseAllConsumablesTask.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package com.android.godot.payments;
-
-import java.util.ArrayList;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import com.android.godot.Dictionary;
-import com.android.godot.Godot;
-import com.android.vending.billing.IInAppBillingService;
-
-import android.content.Context;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.util.Log;
-
-abstract public class ReleaseAllConsumablesTask {
-
- private Context context;
- private IInAppBillingService mService;
-
- public ReleaseAllConsumablesTask(IInAppBillingService mService, Context context ){
- this.context = context;
- this.mService = mService;
- }
-
-
- public void consumeItAll(){
- try{
-// Log.d("godot", "consumeItall for " + context.getPackageName());
- Bundle bundle = mService.getPurchases(3, context.getPackageName(), "inapp",null);
-
- for (String key : bundle.keySet()) {
- Object value = bundle.get(key);
-// Log.d("godot", String.format("%s %s (%s)", key,
-// value.toString(), value.getClass().getName()));
- }
-
-
- if (bundle.getInt("RESPONSE_CODE") == 0){
-
- final ArrayList<String> myPurchases = bundle.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
- final ArrayList<String> mySignatures = bundle.getStringArrayList("INAPP_DATA_SIGNATURE_LIST");
-
-
- if (myPurchases == null || myPurchases.size() == 0){
-// Log.d("godot", "No purchases!");
- notRequired();
- return;
- }
-
-
-// Log.d("godot", "# products to be consumed:" + myPurchases.size());
- for (int i=0;i<myPurchases.size();i++)
- {
-
- try{
- String receipt = myPurchases.get(i);
- JSONObject inappPurchaseData = new JSONObject(receipt);
- String sku = inappPurchaseData.getString("productId");
- String token = inappPurchaseData.getString("purchaseToken");
- String signature = mySignatures.get(i);
-// Log.d("godot", "A punto de consumir un item con token:" + token + "\n" + receipt);
- new GenericConsumeTask(context, mService, sku, receipt,signature, token) {
-
- @Override
- public void onSuccess(String sku, String receipt, String signature, String token) {
- ReleaseAllConsumablesTask.this.success(sku, receipt, signature, token);
- }
- }.execute();
-
- } catch (JSONException e) {
- }
- }
-
- }
- }catch(Exception e){
- Log.d("godot", "Error releasing products:" + e.getClass().getName() + ":" + e.getMessage());
- }
- }
-
- abstract protected void success(String sku, String receipt, String signature, String token);
- abstract protected void error(String message);
- abstract protected void notRequired();
-
-}
diff --git a/platform/android/java/src/com/android/godot/payments/ValidateTask.java b/platform/android/java/src/com/android/godot/payments/ValidateTask.java
deleted file mode 100644
index 6ea415e8a9..0000000000
--- a/platform/android/java/src/com/android/godot/payments/ValidateTask.java
+++ /dev/null
@@ -1,97 +0,0 @@
-package com.android.godot.payments;
-
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import com.android.godot.Godot;
-import com.android.godot.GodotLib;
-import com.android.godot.GodotPaymentV3;
-import com.android.godot.utils.Crypt;
-import com.android.godot.utils.HttpRequester;
-import com.android.godot.utils.RequestParams;
-import com.android.vending.billing.IInAppBillingService;
-
-import android.app.Activity;
-import android.app.PendingIntent;
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentSender.SendIntentException;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.util.Log;
-
-abstract public class ValidateTask {
-
- private Activity context;
- private GodotPaymentV3 godotPaymentsV3;
- public ValidateTask(Activity context, GodotPaymentV3 godotPaymentsV3){
- this.context = context;
- this.godotPaymentsV3 = godotPaymentsV3;
- }
-
- public void validatePurchase(final String sku){
- new AsyncTask<String, String, String>(){
-
-
- private ProgressDialog dialog;
-
- @Override
- protected void onPreExecute(){
- dialog = ProgressDialog.show(context, null, "Please wait...");
- }
-
- @Override
- protected String doInBackground(String... params) {
- PaymentsCache pc = new PaymentsCache(context);
- String url = godotPaymentsV3.getPurchaseValidationUrlPrefix();
- RequestParams param = new RequestParams();
- param.setUrl(url);
- param.put("ticket", pc.getConsumableValue("ticket", sku));
- param.put("purchaseToken", pc.getConsumableValue("token", sku));
- param.put("sku", sku);
-// Log.d("XXX", "Haciendo request a " + url);
-// Log.d("XXX", "ticket: " + pc.getConsumableValue("ticket", sku));
-// Log.d("XXX", "purchaseToken: " + pc.getConsumableValue("token", sku));
-// Log.d("XXX", "sku: " + sku);
- param.put("package", context.getApplicationContext().getPackageName());
- HttpRequester requester = new HttpRequester();
- String jsonResponse = requester.post(param);
-// Log.d("XXX", "Validation response:\n"+jsonResponse);
- return jsonResponse;
- }
-
- @Override
- protected void onPostExecute(String response){
- if(dialog != null){
- dialog.dismiss();
- }
- JSONObject j;
- try {
- j = new JSONObject(response);
- if(j.getString("status").equals("OK")){
- success();
- return;
- }else if(j.getString("status") != null){
- error(j.getString("message"));
- }else{
- error("Connection error");
- }
- } catch (JSONException e) {
- error(e.getMessage());
- }catch (Exception e){
- error(e.getMessage());
- }
-
-
- }
-
- }.execute();
- }
- abstract protected void success();
- abstract protected void error(String message);
- abstract protected void canceled();
-
-
-}
diff --git a/platform/android/java/src/com/android/godot/utils/Crypt.java b/platform/android/java/src/com/android/godot/utils/Crypt.java
deleted file mode 100644
index 7801f474b9..0000000000
--- a/platform/android/java/src/com/android/godot/utils/Crypt.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package com.android.godot.utils;
-
-import java.security.MessageDigest;
-import java.util.Random;
-
-public class Crypt {
-
- public static String md5(String input){
- try {
- // Create MD5 Hash
- MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
- digest.update(input.getBytes());
- byte messageDigest[] = digest.digest();
-
- // Create Hex String
- StringBuffer hexString = new StringBuffer();
- for (int i=0; i<messageDigest.length; i++)
- hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
- return hexString.toString();
-
- } catch (Exception e) {
- e.printStackTrace();
- }
- return "";
- }
-
- public static String createRandomHash(){
- return md5(Long.toString(createRandomLong()));
- }
-
- public static long createAbsRandomLong(){
- return Math.abs(createRandomLong());
- }
-
- public static long createRandomLong(){
- Random r = new Random();
- return r.nextLong();
- }
-}
diff --git a/platform/android/java/src/com/android/godot/utils/CustomSSLSocketFactory.java b/platform/android/java/src/com/android/godot/utils/CustomSSLSocketFactory.java
deleted file mode 100644
index 5f2b44fc8c..0000000000
--- a/platform/android/java/src/com/android/godot/utils/CustomSSLSocketFactory.java
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.android.godot.utils;
-import java.io.IOException;
-import java.net.Socket;
-import java.net.UnknownHostException;
-import java.security.KeyManagementException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
-
-import org.apache.http.conn.ssl.SSLSocketFactory;
-
-
-/**
- *
- * @author Luis Linietsky <luis.linietsky@gmail.com>
- */
-public class CustomSSLSocketFactory extends SSLSocketFactory {
- SSLContext sslContext = SSLContext.getInstance("TLS");
-
- public CustomSSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
- super(truststore);
-
- TrustManager tm = new X509TrustManager() {
- public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
- }
-
- public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
- }
-
- public X509Certificate[] getAcceptedIssuers() {
- return null;
- }
- };
-
- sslContext.init(null, new TrustManager[] { tm }, null);
- }
-
- @Override
- public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
- return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
- }
-
- @Override
- public Socket createSocket() throws IOException {
- return sslContext.getSocketFactory().createSocket();
- }
-} \ No newline at end of file
diff --git a/platform/android/java/src/com/android/godot/utils/HttpRequester.java b/platform/android/java/src/com/android/godot/utils/HttpRequester.java
deleted file mode 100644
index 7de77881d0..0000000000
--- a/platform/android/java/src/com/android/godot/utils/HttpRequester.java
+++ /dev/null
@@ -1,206 +0,0 @@
-package com.android.godot.utils;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.UnsupportedEncodingException;
-import java.security.KeyStore;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
-import org.apache.http.HttpResponse;
-import org.apache.http.HttpVersion;
-import org.apache.http.NameValuePair;
-import org.apache.http.client.ClientProtocolException;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.entity.UrlEncodedFormEntity;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.conn.ClientConnectionManager;
-import org.apache.http.conn.scheme.PlainSocketFactory;
-import org.apache.http.conn.scheme.Scheme;
-import org.apache.http.conn.scheme.SchemeRegistry;
-import org.apache.http.conn.ssl.SSLSocketFactory;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
-import org.apache.http.message.BasicNameValuePair;
-import org.apache.http.params.BasicHttpParams;
-import org.apache.http.params.HttpConnectionParams;
-import org.apache.http.params.HttpParams;
-import org.apache.http.params.HttpProtocolParams;
-import org.apache.http.protocol.HTTP;
-import org.apache.http.util.EntityUtils;
-
-
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.util.Log;
-
-/**
- *
- * @author Luis Linietsky <luis.linietsky@gmail.com>
- */
-public class HttpRequester {
-
- private Context context;
- private static final int TTL = 600000; // 10 minutos
- private long cttl=0;
-
- public HttpRequester(){
-// Log.d("XXX", "Creando http request sin contexto");
- }
-
- public HttpRequester(Context context){
- this.context=context;
-// Log.d("XXX", "Creando http request con contexto");
- }
-
- public String post(RequestParams params){
- HttpPost httppost = new HttpPost(params.getUrl());
- try {
- httppost.setEntity(new UrlEncodedFormEntity(params.toPairsList()));
- return request(httppost);
- } catch (UnsupportedEncodingException e) {
- return null;
- }
- }
-
- public String get(RequestParams params){
- String response = getResponseFromCache(params.getUrl());
- if(response == null){
-// Log.d("XXX", "Cache miss!");
- HttpGet httpget = new HttpGet(params.getUrl());
- long timeInit = new Date().getTime();
- response = request(httpget);
- long delay = new Date().getTime() - timeInit;
- Log.d("com.app11tt.android.utils.HttpRequest::get(url)", "Url: " + params.getUrl() + " downloaded in " + String.format("%.03f", delay/1000.0f) + " seconds");
- if(response == null || response.length() == 0){
- response = "";
- }else{
- saveResponseIntoCache(params.getUrl(), response);
- }
- }
- Log.d("XXX", "Req: " + params.getUrl());
- Log.d("XXX", "Resp: " + response);
- return response;
- }
-
- private String request(HttpUriRequest request){
-// Log.d("XXX", "Haciendo request a: " + request.getURI() );
- Log.d("PPP", "Haciendo request a: " + request.getURI() );
- long init = new Date().getTime();
- HttpClient httpclient = getNewHttpClient();
- HttpParams httpParameters = httpclient.getParams();
- HttpConnectionParams.setConnectionTimeout(httpParameters, 0);
- HttpConnectionParams.setSoTimeout(httpParameters, 0);
- HttpConnectionParams.setTcpNoDelay(httpParameters, true);
- try {
- HttpResponse response = httpclient.execute(request);
- Log.d("PPP", "Fin de request (" + (new Date().getTime() - init) + ") a: " + request.getURI() );
-// Log.d("XXX1", "Status:" + response.getStatusLine().toString());
- if(response.getStatusLine().getStatusCode() == 200){
- String strResponse = EntityUtils.toString(response.getEntity());
-// Log.d("XXX2", strResponse);
- return strResponse;
- }else{
- Log.d("XXX3", "Response status code:" + response.getStatusLine().getStatusCode() + "\n" + EntityUtils.toString(response.getEntity()));
- return null;
- }
-
- } catch (ClientProtocolException e) {
- Log.d("XXX3", e.getMessage());
- } catch (IOException e) {
- Log.d("XXX4", e.getMessage());
- }
- return null;
- }
-
- private HttpClient getNewHttpClient() {
- try {
- KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
- trustStore.load(null, null);
-
- SSLSocketFactory sf = new CustomSSLSocketFactory(trustStore);
- sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
-
- HttpParams params = new BasicHttpParams();
- HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
- HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
-
- SchemeRegistry registry = new SchemeRegistry();
- registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
- registry.register(new Scheme("https", sf, 443));
-
- ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
-
- return new DefaultHttpClient(ccm, params);
- } catch (Exception e) {
- return new DefaultHttpClient();
- }
- }
-
- private static String convertStreamToString(InputStream is) {
- BufferedReader reader = new BufferedReader(new InputStreamReader(is));
- StringBuilder sb = new StringBuilder();
- String line = null;
- try {
- while ((line = reader.readLine()) != null) {
- sb.append((line + "\n"));
- }
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- try {
- is.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- return sb.toString();
- }
-
- public void saveResponseIntoCache(String request, String response){
- if(context == null){
-// Log.d("XXX", "No context, cache failed!");
- return;
- }
- SharedPreferences sharedPref = context.getSharedPreferences("http_get_cache", Context.MODE_PRIVATE);
- SharedPreferences.Editor editor = sharedPref.edit();
- editor.putString("request_" + Crypt.md5(request), response);
- editor.putLong("request_" + Crypt.md5(request) + "_ttl", new Date().getTime() + getTtl());
- editor.commit();
- }
-
-
- public String getResponseFromCache(String request){
- if(context == null){
- Log.d("XXX", "No context, cache miss");
- return null;
- }
- SharedPreferences sharedPref = context.getSharedPreferences( "http_get_cache", Context.MODE_PRIVATE);
- long ttl = getResponseTtl(request);
- if(ttl == 0l || (new Date().getTime() - ttl) > 0l){
- Log.d("XXX", "Cache invalid ttl:" + ttl + " vs now:" + new Date().getTime());
- return null;
- }
- return sharedPref.getString("request_" + Crypt.md5(request), null);
- }
-
- public long getResponseTtl(String request){
- SharedPreferences sharedPref = context.getSharedPreferences(
- "http_get_cache", Context.MODE_PRIVATE);
- return sharedPref.getLong("request_" + Crypt.md5(request) + "_ttl", 0l);
- }
-
- public long getTtl() {
- return cttl > 0 ? cttl : TTL;
- }
-
- public void setTtl(long ttl) {
- this.cttl = (ttl*1000) + new Date().getTime();
- }
-
-}
diff --git a/platform/android/java/src/com/android/godot/utils/RequestParams.java b/platform/android/java/src/com/android/godot/utils/RequestParams.java
deleted file mode 100644
index 31bf1940ad..0000000000
--- a/platform/android/java/src/com/android/godot/utils/RequestParams.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.android.godot.utils;
-
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-
-import org.apache.http.NameValuePair;
-import org.apache.http.message.BasicNameValuePair;
-
-/**
- *
- * @author Luis Linietsky <luis.linietsky@gmail.com>
- */
-public class RequestParams {
-
- private HashMap<String,String> params;
- private String url;
-
- public RequestParams(){
- params = new HashMap<String,String>();
- }
-
- public void put(String key, String value){
- params.put(key, value);
- }
-
- public String get(String key){
- return params.get(key);
- }
-
- public void remove(Object key){
- params.remove(key);
- }
-
- public boolean has(String key){
- return params.containsKey(key);
- }
-
- public List<NameValuePair> toPairsList(){
- List<NameValuePair> fields = new ArrayList<NameValuePair>();
-
- for(String key : params.keySet()){
- fields.add(new BasicNameValuePair(key, this.get(key)));
- }
- return fields;
- }
-
- public String getUrl() {
- return url;
- }
-
- public void setUrl(String url) {
- this.url = url;
- }
-
-
-}
diff --git a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/AESObfuscator.java b/platform/android/java/src/com/android/vending/licensing/AESObfuscator.java
index ee12c68deb..ee12c68deb 100644
--- a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/AESObfuscator.java
+++ b/platform/android/java/src/com/android/vending/licensing/AESObfuscator.java
diff --git a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/APKExpansionPolicy.java b/platform/android/java/src/com/android/vending/licensing/APKExpansionPolicy.java
index 17cc7a7cfd..17cc7a7cfd 100644
--- a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/APKExpansionPolicy.java
+++ b/platform/android/java/src/com/android/vending/licensing/APKExpansionPolicy.java
diff --git a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/DeviceLimiter.java b/platform/android/java/src/com/android/vending/licensing/DeviceLimiter.java
index e5c5e2d7ca..e5c5e2d7ca 100644
--- a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/DeviceLimiter.java
+++ b/platform/android/java/src/com/android/vending/licensing/DeviceLimiter.java
diff --git a/platform/android/libs/play_licensing/aidl/ILicenseResultListener.aidl b/platform/android/java/src/com/android/vending/licensing/ILicenseResultListener.aidl
index c816558afc..c816558afc 100644
--- a/platform/android/libs/play_licensing/aidl/ILicenseResultListener.aidl
+++ b/platform/android/java/src/com/android/vending/licensing/ILicenseResultListener.aidl
diff --git a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/ILicenseResultListener.java b/platform/android/java/src/com/android/vending/licensing/ILicenseResultListener.java
index d90d6eac7b..d90d6eac7b 100644
--- a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/ILicenseResultListener.java
+++ b/platform/android/java/src/com/android/vending/licensing/ILicenseResultListener.java
diff --git a/platform/android/libs/play_licensing/aidl/ILicensingService.aidl b/platform/android/java/src/com/android/vending/licensing/ILicensingService.aidl
index 664510ce0c..664510ce0c 100644
--- a/platform/android/libs/play_licensing/aidl/ILicensingService.aidl
+++ b/platform/android/java/src/com/android/vending/licensing/ILicensingService.aidl
diff --git a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/ILicensingService.java b/platform/android/java/src/com/android/vending/licensing/ILicensingService.java
index 95599544e4..95599544e4 100644
--- a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/ILicensingService.java
+++ b/platform/android/java/src/com/android/vending/licensing/ILicensingService.java
diff --git a/platform/android/java/src/com/android/vending/licensing/LicenseChecker.java b/platform/android/java/src/com/android/vending/licensing/LicenseChecker.java
new file mode 100644
index 0000000000..0b1c4b6cca
--- /dev/null
+++ b/platform/android/java/src/com/android/vending/licensing/LicenseChecker.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.vending.licensing;
+
+import com.google.android.vending.licensing.util.Base64;
+import com.google.android.vending.licensing.util.Base64DecoderException;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.provider.Settings.Secure;
+import android.util.Log;
+
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.SecureRandom;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.Set;
+
+/**
+ * Client library for Android Market license verifications.
+ * <p>
+ * The LicenseChecker is configured via a {@link Policy} which contains the
+ * logic to determine whether a user should have access to the application. For
+ * example, the Policy can define a threshold for allowable number of server or
+ * client failures before the library reports the user as not having access.
+ * <p>
+ * Must also provide the Base64-encoded RSA public key associated with your
+ * developer account. The public key is obtainable from the publisher site.
+ */
+public class LicenseChecker implements ServiceConnection {
+ private static final String TAG = "LicenseChecker";
+
+ private static final String KEY_FACTORY_ALGORITHM = "RSA";
+
+ // Timeout value (in milliseconds) for calls to service.
+ private static final int TIMEOUT_MS = 10 * 1000;
+
+ private static final SecureRandom RANDOM = new SecureRandom();
+ private static final boolean DEBUG_LICENSE_ERROR = false;
+
+ private ILicensingService mService;
+
+ private PublicKey mPublicKey;
+ private final Context mContext;
+ private final Policy mPolicy;
+ /**
+ * A handler for running tasks on a background thread. We don't want license
+ * processing to block the UI thread.
+ */
+ private Handler mHandler;
+ private final String mPackageName;
+ private final String mVersionCode;
+ private final Set<LicenseValidator> mChecksInProgress = new HashSet<LicenseValidator>();
+ private final Queue<LicenseValidator> mPendingChecks = new LinkedList<LicenseValidator>();
+
+ /**
+ * @param context a Context
+ * @param policy implementation of Policy
+ * @param encodedPublicKey Base64-encoded RSA public key
+ * @throws IllegalArgumentException if encodedPublicKey is invalid
+ */
+ public LicenseChecker(Context context, Policy policy, String encodedPublicKey) {
+ mContext = context;
+ mPolicy = policy;
+ mPublicKey = generatePublicKey(encodedPublicKey);
+ mPackageName = mContext.getPackageName();
+ mVersionCode = getVersionCode(context, mPackageName);
+ HandlerThread handlerThread = new HandlerThread("background thread");
+ handlerThread.start();
+ mHandler = new Handler(handlerThread.getLooper());
+ }
+
+ /**
+ * Generates a PublicKey instance from a string containing the
+ * Base64-encoded public key.
+ *
+ * @param encodedPublicKey Base64-encoded public key
+ * @throws IllegalArgumentException if encodedPublicKey is invalid
+ */
+ private static PublicKey generatePublicKey(String encodedPublicKey) {
+ try {
+ byte[] decodedKey = Base64.decode(encodedPublicKey);
+ KeyFactory keyFactory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM);
+
+ return keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey));
+ } catch (NoSuchAlgorithmException e) {
+ // This won't happen in an Android-compatible environment.
+ throw new RuntimeException(e);
+ } catch (Base64DecoderException e) {
+ Log.e(TAG, "Could not decode from Base64.");
+ throw new IllegalArgumentException(e);
+ } catch (InvalidKeySpecException e) {
+ Log.e(TAG, "Invalid key specification.");
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ /**
+ * Checks if the user should have access to the app. Binds the service if necessary.
+ * <p>
+ * NOTE: This call uses a trivially obfuscated string (base64-encoded). For best security,
+ * we recommend obfuscating the string that is passed into bindService using another method
+ * of your own devising.
+ * <p>
+ * source string: "com.android.vending.licensing.ILicensingService"
+ * <p>
+ * @param callback
+ */
+ public synchronized void checkAccess(LicenseCheckerCallback callback) {
+ // If we have a valid recent LICENSED response, we can skip asking
+ // Market.
+ if (mPolicy.allowAccess()) {
+ Log.i(TAG, "Using cached license response");
+ callback.allow(Policy.LICENSED);
+ } else {
+ LicenseValidator validator = new LicenseValidator(mPolicy, new NullDeviceLimiter(),
+ callback, generateNonce(), mPackageName, mVersionCode);
+
+ if (mService == null) {
+ Log.i(TAG, "Binding to licensing service.");
+ try {
+ boolean bindResult = mContext
+ .bindService(
+ new Intent(
+ new String(
+ Base64.decode("Y29tLmFuZHJvaWQudmVuZGluZy5saWNlbnNpbmcuSUxpY2Vuc2luZ1NlcnZpY2U="))),
+ this, // ServiceConnection.
+ Context.BIND_AUTO_CREATE);
+
+ if (bindResult) {
+ mPendingChecks.offer(validator);
+ } else {
+ Log.e(TAG, "Could not bind to service.");
+ handleServiceConnectionError(validator);
+ }
+ } catch (SecurityException e) {
+ callback.applicationError(LicenseCheckerCallback.ERROR_MISSING_PERMISSION);
+ } catch (Base64DecoderException e) {
+ e.printStackTrace();
+ }
+ } else {
+ mPendingChecks.offer(validator);
+ runChecks();
+ }
+ }
+ }
+
+ private void runChecks() {
+ LicenseValidator validator;
+ while ((validator = mPendingChecks.poll()) != null) {
+ try {
+ Log.i(TAG, "Calling checkLicense on service for " + validator.getPackageName());
+ mService.checkLicense(
+ validator.getNonce(), validator.getPackageName(),
+ new ResultListener(validator));
+ mChecksInProgress.add(validator);
+ } catch (RemoteException e) {
+ Log.w(TAG, "RemoteException in checkLicense call.", e);
+ handleServiceConnectionError(validator);
+ }
+ }
+ }
+
+ private synchronized void finishCheck(LicenseValidator validator) {
+ mChecksInProgress.remove(validator);
+ if (mChecksInProgress.isEmpty()) {
+ cleanupService();
+ }
+ }
+
+ private class ResultListener extends ILicenseResultListener.Stub {
+ private final LicenseValidator mValidator;
+ private Runnable mOnTimeout;
+
+ public ResultListener(LicenseValidator validator) {
+ mValidator = validator;
+ mOnTimeout = new Runnable() {
+ public void run() {
+ Log.i(TAG, "Check timed out.");
+ handleServiceConnectionError(mValidator);
+ finishCheck(mValidator);
+ }
+ };
+ startTimeout();
+ }
+
+ private static final int ERROR_CONTACTING_SERVER = 0x101;
+ private static final int ERROR_INVALID_PACKAGE_NAME = 0x102;
+ private static final int ERROR_NON_MATCHING_UID = 0x103;
+
+ // Runs in IPC thread pool. Post it to the Handler, so we can guarantee
+ // either this or the timeout runs.
+ public void verifyLicense(final int responseCode, final String signedData,
+ final String signature) {
+ mHandler.post(new Runnable() {
+ public void run() {
+ Log.i(TAG, "Received response.");
+ // Make sure it hasn't already timed out.
+ if (mChecksInProgress.contains(mValidator)) {
+ clearTimeout();
+ mValidator.verify(mPublicKey, responseCode, signedData, signature);
+ finishCheck(mValidator);
+ }
+ if (DEBUG_LICENSE_ERROR) {
+ boolean logResponse;
+ String stringError = null;
+ switch (responseCode) {
+ case ERROR_CONTACTING_SERVER:
+ logResponse = true;
+ stringError = "ERROR_CONTACTING_SERVER";
+ break;
+ case ERROR_INVALID_PACKAGE_NAME:
+ logResponse = true;
+ stringError = "ERROR_INVALID_PACKAGE_NAME";
+ break;
+ case ERROR_NON_MATCHING_UID:
+ logResponse = true;
+ stringError = "ERROR_NON_MATCHING_UID";
+ break;
+ default:
+ logResponse = false;
+ }
+
+ if (logResponse) {
+ String android_id = Secure.getString(mContext.getContentResolver(),
+ Secure.ANDROID_ID);
+ Date date = new Date();
+ Log.d(TAG, "Server Failure: " + stringError);
+ Log.d(TAG, "Android ID: " + android_id);
+ Log.d(TAG, "Time: " + date.toGMTString());
+ }
+ }
+
+ }
+ });
+ }
+
+ private void startTimeout() {
+ Log.i(TAG, "Start monitoring timeout.");
+ mHandler.postDelayed(mOnTimeout, TIMEOUT_MS);
+ }
+
+ private void clearTimeout() {
+ Log.i(TAG, "Clearing timeout.");
+ mHandler.removeCallbacks(mOnTimeout);
+ }
+ }
+
+ public synchronized void onServiceConnected(ComponentName name, IBinder service) {
+ mService = ILicensingService.Stub.asInterface(service);
+ runChecks();
+ }
+
+ public synchronized void onServiceDisconnected(ComponentName name) {
+ // Called when the connection with the service has been
+ // unexpectedly disconnected. That is, Market crashed.
+ // If there are any checks in progress, the timeouts will handle them.
+ Log.w(TAG, "Service unexpectedly disconnected.");
+ mService = null;
+ }
+
+ /**
+ * Generates policy response for service connection errors, as a result of
+ * disconnections or timeouts.
+ */
+ private synchronized void handleServiceConnectionError(LicenseValidator validator) {
+ mPolicy.processServerResponse(Policy.RETRY, null);
+
+ if (mPolicy.allowAccess()) {
+ validator.getCallback().allow(Policy.RETRY);
+ } else {
+ validator.getCallback().dontAllow(Policy.RETRY);
+ }
+ }
+
+ /** Unbinds service if necessary and removes reference to it. */
+ private void cleanupService() {
+ if (mService != null) {
+ try {
+ mContext.unbindService(this);
+ } catch (IllegalArgumentException e) {
+ // Somehow we've already been unbound. This is a non-fatal
+ // error.
+ Log.e(TAG, "Unable to unbind from licensing service (already unbound)");
+ }
+ mService = null;
+ }
+ }
+
+ /**
+ * Inform the library that the context is about to be destroyed, so that any
+ * open connections can be cleaned up.
+ * <p>
+ * Failure to call this method can result in a crash under certain
+ * circumstances, such as during screen rotation if an Activity requests the
+ * license check or when the user exits the application.
+ */
+ public synchronized void onDestroy() {
+ cleanupService();
+ mHandler.getLooper().quit();
+ }
+
+ /** Generates a nonce (number used once). */
+ private int generateNonce() {
+ return RANDOM.nextInt();
+ }
+
+ /**
+ * Get version code for the application package name.
+ *
+ * @param context
+ * @param packageName application package name
+ * @return the version code or empty string if package not found
+ */
+ private static String getVersionCode(Context context, String packageName) {
+ try {
+ return String.valueOf(context.getPackageManager().getPackageInfo(packageName, 0).
+ versionCode);
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Package not found. could not get version code.");
+ return "";
+ }
+ }
+}
diff --git a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/LicenseCheckerCallback.java b/platform/android/java/src/com/android/vending/licensing/LicenseCheckerCallback.java
index b250a7147b..b250a7147b 100644
--- a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/LicenseCheckerCallback.java
+++ b/platform/android/java/src/com/android/vending/licensing/LicenseCheckerCallback.java
diff --git a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/LicenseValidator.java b/platform/android/java/src/com/android/vending/licensing/LicenseValidator.java
index 61d3c7e79e..61d3c7e79e 100644
--- a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/LicenseValidator.java
+++ b/platform/android/java/src/com/android/vending/licensing/LicenseValidator.java
diff --git a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/NullDeviceLimiter.java b/platform/android/java/src/com/android/vending/licensing/NullDeviceLimiter.java
index d87af3153f..d87af3153f 100644
--- a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/NullDeviceLimiter.java
+++ b/platform/android/java/src/com/android/vending/licensing/NullDeviceLimiter.java
diff --git a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/Obfuscator.java b/platform/android/java/src/com/android/vending/licensing/Obfuscator.java
index b5d510d72d..b5d510d72d 100644
--- a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/Obfuscator.java
+++ b/platform/android/java/src/com/android/vending/licensing/Obfuscator.java
diff --git a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/Policy.java b/platform/android/java/src/com/android/vending/licensing/Policy.java
index fa267fc71a..fa267fc71a 100644
--- a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/Policy.java
+++ b/platform/android/java/src/com/android/vending/licensing/Policy.java
diff --git a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/PreferenceObfuscator.java b/platform/android/java/src/com/android/vending/licensing/PreferenceObfuscator.java
index 7c42bfc28a..7c42bfc28a 100644
--- a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/PreferenceObfuscator.java
+++ b/platform/android/java/src/com/android/vending/licensing/PreferenceObfuscator.java
diff --git a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/ResponseData.java b/platform/android/java/src/com/android/vending/licensing/ResponseData.java
index 2adef3709e..2adef3709e 100644
--- a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/ResponseData.java
+++ b/platform/android/java/src/com/android/vending/licensing/ResponseData.java
diff --git a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/ServerManagedPolicy.java b/platform/android/java/src/com/android/vending/licensing/ServerManagedPolicy.java
index fbf8cf6d00..fbf8cf6d00 100644
--- a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/ServerManagedPolicy.java
+++ b/platform/android/java/src/com/android/vending/licensing/ServerManagedPolicy.java
diff --git a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/StrictPolicy.java b/platform/android/java/src/com/android/vending/licensing/StrictPolicy.java
index d8d83b4e4b..d8d83b4e4b 100644
--- a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/StrictPolicy.java
+++ b/platform/android/java/src/com/android/vending/licensing/StrictPolicy.java
diff --git a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/ValidationException.java b/platform/android/java/src/com/android/vending/licensing/ValidationException.java
index ee4df47c68..ee4df47c68 100644
--- a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/ValidationException.java
+++ b/platform/android/java/src/com/android/vending/licensing/ValidationException.java
diff --git a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/util/Base64.java b/platform/android/java/src/com/android/vending/licensing/util/Base64.java
index a0d2779af2..a0d2779af2 100644
--- a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/util/Base64.java
+++ b/platform/android/java/src/com/android/vending/licensing/util/Base64.java
diff --git a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/util/Base64DecoderException.java b/platform/android/java/src/com/android/vending/licensing/util/Base64DecoderException.java
index 1aef1b54b8..1aef1b54b8 100644
--- a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/util/Base64DecoderException.java
+++ b/platform/android/java/src/com/android/vending/licensing/util/Base64DecoderException.java
diff --git a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/Constants.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/Constants.java
index ff2c6f535a..ff2c6f535a 100644
--- a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/Constants.java
+++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/Constants.java
diff --git a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/DownloadProgressInfo.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/DownloadProgressInfo.java
index 9cb294d721..9cb294d721 100644
--- a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/DownloadProgressInfo.java
+++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/DownloadProgressInfo.java
diff --git a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/DownloaderClientMarshaller.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/DownloaderClientMarshaller.java
index 2201751254..2201751254 100644
--- a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/DownloaderClientMarshaller.java
+++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/DownloaderClientMarshaller.java
diff --git a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/DownloaderServiceMarshaller.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/DownloaderServiceMarshaller.java
index 054eaa9895..054eaa9895 100644
--- a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/DownloaderServiceMarshaller.java
+++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/DownloaderServiceMarshaller.java
diff --git a/platform/android/java/src/com/google/android/vending/expansion/downloader/Helpers.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/Helpers.java
new file mode 100644
index 0000000000..b4c28d36e7
--- /dev/null
+++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/Helpers.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.vending.expansion.downloader;
+
+import com.godot.game.R;
+
+import android.content.Context;
+import android.os.Environment;
+import android.os.StatFs;
+import android.os.SystemClock;
+import android.util.Log;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Random;
+import java.util.TimeZone;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Some helper functions for the download manager
+ */
+public class Helpers {
+
+ public static Random sRandom = new Random(SystemClock.uptimeMillis());
+
+ /** Regex used to parse content-disposition headers */
+ private static final Pattern CONTENT_DISPOSITION_PATTERN = Pattern
+ .compile("attachment;\\s*filename\\s*=\\s*\"([^\"]*)\"");
+
+ private Helpers() {
+ }
+
+ /*
+ * Parse the Content-Disposition HTTP Header. The format of the header is
+ * defined here: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html This
+ * header provides a filename for content that is going to be downloaded to
+ * the file system. We only support the attachment type.
+ */
+ static String parseContentDisposition(String contentDisposition) {
+ try {
+ Matcher m = CONTENT_DISPOSITION_PATTERN.matcher(contentDisposition);
+ if (m.find()) {
+ return m.group(1);
+ }
+ } catch (IllegalStateException ex) {
+ // This function is defined as returning null when it can't parse
+ // the header
+ }
+ return null;
+ }
+
+ /**
+ * @return the root of the filesystem containing the given path
+ */
+ public static File getFilesystemRoot(String path) {
+ File cache = Environment.getDownloadCacheDirectory();
+ if (path.startsWith(cache.getPath())) {
+ return cache;
+ }
+ File external = Environment.getExternalStorageDirectory();
+ if (path.startsWith(external.getPath())) {
+ return external;
+ }
+ throw new IllegalArgumentException(
+ "Cannot determine filesystem root for " + path);
+ }
+
+ public static boolean isExternalMediaMounted() {
+ if (!Environment.getExternalStorageState().equals(
+ Environment.MEDIA_MOUNTED)) {
+ // No SD card found.
+ if ( Constants.LOGVV ) {
+ Log.d(Constants.TAG, "no external storage");
+ }
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @return the number of bytes available on the filesystem rooted at the
+ * given File
+ */
+ public static long getAvailableBytes(File root) {
+ StatFs stat = new StatFs(root.getPath());
+ // put a bit of margin (in case creating the file grows the system by a
+ // few blocks)
+ long availableBlocks = (long) stat.getAvailableBlocks() - 4;
+ return stat.getBlockSize() * availableBlocks;
+ }
+
+ /**
+ * Checks whether the filename looks legitimate
+ */
+ public static boolean isFilenameValid(String filename) {
+ filename = filename.replaceFirst("/+", "/"); // normalize leading
+ // slashes
+ return filename.startsWith(Environment.getDownloadCacheDirectory().toString())
+ || filename.startsWith(Environment.getExternalStorageDirectory().toString());
+ }
+
+ /*
+ * Delete the given file from device
+ */
+ /* package */static void deleteFile(String path) {
+ try {
+ File file = new File(path);
+ file.delete();
+ } catch (Exception e) {
+ Log.w(Constants.TAG, "file: '" + path + "' couldn't be deleted", e);
+ }
+ }
+
+ /**
+ * Showing progress in MB here. It would be nice to choose the unit (KB, MB,
+ * GB) based on total file size, but given what we know about the expected
+ * ranges of file sizes for APK expansion files, it's probably not necessary.
+ *
+ * @param overallProgress
+ * @param overallTotal
+ * @return
+ */
+
+ static public String getDownloadProgressString(long overallProgress, long overallTotal) {
+ if (overallTotal == 0) {
+ if ( Constants.LOGVV ) {
+ Log.e(Constants.TAG, "Notification called when total is zero");
+ }
+ return "";
+ }
+ return String.format("%.2f",
+ (float) overallProgress / (1024.0f * 1024.0f))
+ + "MB /" +
+ String.format("%.2f", (float) overallTotal /
+ (1024.0f * 1024.0f)) + "MB";
+ }
+
+ /**
+ * Adds a percentile to getDownloadProgressString.
+ *
+ * @param overallProgress
+ * @param overallTotal
+ * @return
+ */
+ static public String getDownloadProgressStringNotification(long overallProgress,
+ long overallTotal) {
+ if (overallTotal == 0) {
+ if ( Constants.LOGVV ) {
+ Log.e(Constants.TAG, "Notification called when total is zero");
+ }
+ return "";
+ }
+ return getDownloadProgressString(overallProgress, overallTotal) + " (" +
+ getDownloadProgressPercent(overallProgress, overallTotal) + ")";
+ }
+
+ public static String getDownloadProgressPercent(long overallProgress, long overallTotal) {
+ if (overallTotal == 0) {
+ if ( Constants.LOGVV ) {
+ Log.e(Constants.TAG, "Notification called when total is zero");
+ }
+ return "";
+ }
+ return Long.toString(overallProgress * 100 / overallTotal) + "%";
+ }
+
+ public static String getSpeedString(float bytesPerMillisecond) {
+ return String.format("%.2f", bytesPerMillisecond * 1000 / 1024);
+ }
+
+ public static String getTimeRemaining(long durationInMilliseconds) {
+ SimpleDateFormat sdf;
+ if (durationInMilliseconds > 1000 * 60 * 60) {
+ sdf = new SimpleDateFormat("HH:mm", Locale.getDefault());
+ } else {
+ sdf = new SimpleDateFormat("mm:ss", Locale.getDefault());
+ }
+ return sdf.format(new Date(durationInMilliseconds - TimeZone.getDefault().getRawOffset()));
+ }
+
+ /**
+ * Returns the file name (without full path) for an Expansion APK file from
+ * the given context.
+ *
+ * @param c the context
+ * @param mainFile true for main file, false for patch file
+ * @param versionCode the version of the file
+ * @return String the file name of the expansion file
+ */
+ public static String getExpansionAPKFileName(Context c, boolean mainFile, int versionCode) {
+ return (mainFile ? "main." : "patch.") + versionCode + "." + c.getPackageName() + ".obb";
+ }
+
+ /**
+ * Returns the filename (where the file should be saved) from info about a
+ * download
+ */
+ static public String generateSaveFileName(Context c, String fileName) {
+ String path = getSaveFilePath(c)
+ + File.separator + fileName;
+ return path;
+ }
+
+ static public String getSaveFilePath(Context c) {
+ File root = Environment.getExternalStorageDirectory();
+ String path = root.toString() + Constants.EXP_PATH + c.getPackageName();
+ return path;
+ }
+
+ /**
+ * Helper function to ascertain the existence of a file and return
+ * true/false appropriately
+ *
+ * @param c the app/activity/service context
+ * @param fileName the name (sans path) of the file to query
+ * @param fileSize the size that the file must match
+ * @param deleteFileOnMismatch if the file sizes do not match, delete the
+ * file
+ * @return true if it does exist, false otherwise
+ */
+ static public boolean doesFileExist(Context c, String fileName, long fileSize,
+ boolean deleteFileOnMismatch) {
+ // the file may have been delivered by Market --- let's make sure
+ // it's the size we expect
+ File fileForNewFile = new File(Helpers.generateSaveFileName(c, fileName));
+ if (fileForNewFile.exists()) {
+ if (fileForNewFile.length() == fileSize) {
+ return true;
+ }
+ if (deleteFileOnMismatch) {
+ // delete the file --- we won't be able to resume
+ // because we cannot confirm the integrity of the file
+ fileForNewFile.delete();
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Converts download states that are returned by the {@link
+ * IDownloaderClient#onDownloadStateChanged} callback into usable strings.
+ * This is useful if using the state strings built into the library to display user messages.
+ * @param state One of the STATE_* constants from {@link IDownloaderClient}.
+ * @return string resource ID for the corresponding string.
+ */
+ static public int getDownloaderStringResourceIDFromState(int state) {
+ switch (state) {
+ case IDownloaderClient.STATE_IDLE:
+ return R.string.state_idle;
+ case IDownloaderClient.STATE_FETCHING_URL:
+ return R.string.state_fetching_url;
+ case IDownloaderClient.STATE_CONNECTING:
+ return R.string.state_connecting;
+ case IDownloaderClient.STATE_DOWNLOADING:
+ return R.string.state_downloading;
+ case IDownloaderClient.STATE_COMPLETED:
+ return R.string.state_completed;
+ case IDownloaderClient.STATE_PAUSED_NETWORK_UNAVAILABLE:
+ return R.string.state_paused_network_unavailable;
+ case IDownloaderClient.STATE_PAUSED_BY_REQUEST:
+ return R.string.state_paused_by_request;
+ case IDownloaderClient.STATE_PAUSED_WIFI_DISABLED_NEED_CELLULAR_PERMISSION:
+ return R.string.state_paused_wifi_disabled;
+ case IDownloaderClient.STATE_PAUSED_NEED_CELLULAR_PERMISSION:
+ return R.string.state_paused_wifi_unavailable;
+ case IDownloaderClient.STATE_PAUSED_WIFI_DISABLED:
+ return R.string.state_paused_wifi_disabled;
+ case IDownloaderClient.STATE_PAUSED_NEED_WIFI:
+ return R.string.state_paused_wifi_unavailable;
+ case IDownloaderClient.STATE_PAUSED_ROAMING:
+ return R.string.state_paused_roaming;
+ case IDownloaderClient.STATE_PAUSED_NETWORK_SETUP_FAILURE:
+ return R.string.state_paused_network_setup_failure;
+ case IDownloaderClient.STATE_PAUSED_SDCARD_UNAVAILABLE:
+ return R.string.state_paused_sdcard_unavailable;
+ case IDownloaderClient.STATE_FAILED_UNLICENSED:
+ return R.string.state_failed_unlicensed;
+ case IDownloaderClient.STATE_FAILED_FETCHING_URL:
+ return R.string.state_failed_fetching_url;
+ case IDownloaderClient.STATE_FAILED_SDCARD_FULL:
+ return R.string.state_failed_sdcard_full;
+ case IDownloaderClient.STATE_FAILED_CANCELED:
+ return R.string.state_failed_cancelled;
+ default:
+ return R.string.state_unknown;
+ }
+ }
+
+}
diff --git a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/IDownloaderClient.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/IDownloaderClient.java
index b8511a62a0..b8511a62a0 100644
--- a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/IDownloaderClient.java
+++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/IDownloaderClient.java
diff --git a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/IDownloaderService.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/IDownloaderService.java
index 4789afe19c..4789afe19c 100644
--- a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/IDownloaderService.java
+++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/IDownloaderService.java
diff --git a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/IStub.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/IStub.java
index d5bc3a843e..d5bc3a843e 100644
--- a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/IStub.java
+++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/IStub.java
diff --git a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/SystemFacade.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/SystemFacade.java
index 12edd97ab2..12edd97ab2 100644
--- a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/SystemFacade.java
+++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/SystemFacade.java
diff --git a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/AndroidHttpClient.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/AndroidHttpClient.java
index 4667acce67..4667acce67 100644
--- a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/AndroidHttpClient.java
+++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/AndroidHttpClient.java
diff --git a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/CustomIntentService.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/CustomIntentService.java
index b77af7e085..b77af7e085 100755
--- a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/CustomIntentService.java
+++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/CustomIntentService.java
diff --git a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/CustomNotificationFactory.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/CustomNotificationFactory.java
index 9a0ca02122..9a0ca02122 100644
--- a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/CustomNotificationFactory.java
+++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/CustomNotificationFactory.java
diff --git a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/DownloadInfo.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadInfo.java
index 45111b16a3..45111b16a3 100644
--- a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/DownloadInfo.java
+++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadInfo.java
diff --git a/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java
new file mode 100644
index 0000000000..d82b658bc3
--- /dev/null
+++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.vending.expansion.downloader.impl;
+
+import com.godot.game.R;
+import com.google.android.vending.expansion.downloader.DownloadProgressInfo;
+import com.google.android.vending.expansion.downloader.DownloaderClientMarshaller;
+import com.google.android.vending.expansion.downloader.Helpers;
+import com.google.android.vending.expansion.downloader.IDownloaderClient;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.os.Messenger;
+
+/**
+ * This class handles displaying the notification associated with the download
+ * queue going on in the download manager. It handles multiple status types;
+ * Some require user interaction and some do not. Some of the user interactions
+ * may be transient. (for example: the user is queried to continue the download
+ * on 3G when it started on WiFi, but then the phone locks onto WiFi again so
+ * the prompt automatically goes away)
+ * <p/>
+ * The application interface for the downloader also needs to understand and
+ * handle these transient states.
+ */
+public class DownloadNotification implements IDownloaderClient {
+
+ private int mState;
+ private final Context mContext;
+ private final NotificationManager mNotificationManager;
+ private String mCurrentTitle;
+
+ private IDownloaderClient mClientProxy;
+ final ICustomNotification mCustomNotification;
+ private Notification mNotification;
+ private Notification mCurrentNotification;
+ private CharSequence mLabel;
+ private String mCurrentText;
+ private PendingIntent mContentIntent;
+ private DownloadProgressInfo mProgressInfo;
+
+ static final String LOGTAG = "DownloadNotification";
+ static final int NOTIFICATION_ID = LOGTAG.hashCode();
+
+ public PendingIntent getClientIntent() {
+ return mContentIntent;
+ }
+
+ public void setClientIntent(PendingIntent mClientIntent) {
+ this.mContentIntent = mClientIntent;
+ }
+
+ public void resendState() {
+ if (null != mClientProxy) {
+ mClientProxy.onDownloadStateChanged(mState);
+ }
+ }
+
+ @Override
+ public void onDownloadStateChanged(int newState) {
+ if (null != mClientProxy) {
+ mClientProxy.onDownloadStateChanged(newState);
+ }
+ if (newState != mState) {
+ mState = newState;
+ if (newState == IDownloaderClient.STATE_IDLE || null == mContentIntent) {
+ return;
+ }
+ int stringDownloadID;
+ int iconResource;
+ boolean ongoingEvent;
+
+ // get the new title string and paused text
+ switch (newState) {
+ case 0:
+ iconResource = android.R.drawable.stat_sys_warning;
+ stringDownloadID = R.string.state_unknown;
+ ongoingEvent = false;
+ break;
+
+ case IDownloaderClient.STATE_DOWNLOADING:
+ iconResource = android.R.drawable.stat_sys_download;
+ stringDownloadID = Helpers.getDownloaderStringResourceIDFromState(newState);
+ ongoingEvent = true;
+ break;
+
+ case IDownloaderClient.STATE_FETCHING_URL:
+ case IDownloaderClient.STATE_CONNECTING:
+ iconResource = android.R.drawable.stat_sys_download_done;
+ stringDownloadID = Helpers.getDownloaderStringResourceIDFromState(newState);
+ ongoingEvent = true;
+ break;
+
+ case IDownloaderClient.STATE_COMPLETED:
+ case IDownloaderClient.STATE_PAUSED_BY_REQUEST:
+ iconResource = android.R.drawable.stat_sys_download_done;
+ stringDownloadID = Helpers.getDownloaderStringResourceIDFromState(newState);
+ ongoingEvent = false;
+ break;
+
+ case IDownloaderClient.STATE_FAILED:
+ case IDownloaderClient.STATE_FAILED_CANCELED:
+ case IDownloaderClient.STATE_FAILED_FETCHING_URL:
+ case IDownloaderClient.STATE_FAILED_SDCARD_FULL:
+ case IDownloaderClient.STATE_FAILED_UNLICENSED:
+ iconResource = android.R.drawable.stat_sys_warning;
+ stringDownloadID = Helpers.getDownloaderStringResourceIDFromState(newState);
+ ongoingEvent = false;
+ break;
+
+ default:
+ iconResource = android.R.drawable.stat_sys_warning;
+ stringDownloadID = Helpers.getDownloaderStringResourceIDFromState(newState);
+ ongoingEvent = true;
+ break;
+ }
+ mCurrentText = mContext.getString(stringDownloadID);
+ mCurrentTitle = mLabel.toString();
+ mCurrentNotification.tickerText = mLabel + ": " + mCurrentText;
+ mCurrentNotification.icon = iconResource;
+ mCurrentNotification.setLatestEventInfo(mContext, mCurrentTitle, mCurrentText,
+ mContentIntent);
+ if (ongoingEvent) {
+ mCurrentNotification.flags |= Notification.FLAG_ONGOING_EVENT;
+ } else {
+ mCurrentNotification.flags &= ~Notification.FLAG_ONGOING_EVENT;
+ mCurrentNotification.flags |= Notification.FLAG_AUTO_CANCEL;
+ }
+ mNotificationManager.notify(NOTIFICATION_ID, mCurrentNotification);
+ }
+ }
+
+ @Override
+ public void onDownloadProgress(DownloadProgressInfo progress) {
+ mProgressInfo = progress;
+ if (null != mClientProxy) {
+ mClientProxy.onDownloadProgress(progress);
+ }
+ if (progress.mOverallTotal <= 0) {
+ // we just show the text
+ mNotification.tickerText = mCurrentTitle;
+ mNotification.icon = android.R.drawable.stat_sys_download;
+ mNotification.setLatestEventInfo(mContext, mLabel, mCurrentText, mContentIntent);
+ mCurrentNotification = mNotification;
+ } else {
+ mCustomNotification.setCurrentBytes(progress.mOverallProgress);
+ mCustomNotification.setTotalBytes(progress.mOverallTotal);
+ mCustomNotification.setIcon(android.R.drawable.stat_sys_download);
+ mCustomNotification.setPendingIntent(mContentIntent);
+ mCustomNotification.setTicker(mLabel + ": " + mCurrentText);
+ mCustomNotification.setTitle(mLabel);
+ mCustomNotification.setTimeRemaining(progress.mTimeRemaining);
+ mCurrentNotification = mCustomNotification.updateNotification(mContext);
+ }
+ mNotificationManager.notify(NOTIFICATION_ID, mCurrentNotification);
+ }
+
+ public interface ICustomNotification {
+ void setTitle(CharSequence title);
+
+ void setTicker(CharSequence ticker);
+
+ void setPendingIntent(PendingIntent mContentIntent);
+
+ void setTotalBytes(long totalBytes);
+
+ void setCurrentBytes(long currentBytes);
+
+ void setIcon(int iconResource);
+
+ void setTimeRemaining(long timeRemaining);
+
+ Notification updateNotification(Context c);
+ }
+
+ /**
+ * Called in response to onClientUpdated. Creates a new proxy and notifies
+ * it of the current state.
+ *
+ * @param msg the client Messenger to notify
+ */
+ public void setMessenger(Messenger msg) {
+ mClientProxy = DownloaderClientMarshaller.CreateProxy(msg);
+ if (null != mProgressInfo) {
+ mClientProxy.onDownloadProgress(mProgressInfo);
+ }
+ if (mState != -1) {
+ mClientProxy.onDownloadStateChanged(mState);
+ }
+ }
+
+ /**
+ * Constructor
+ *
+ * @param ctx The context to use to obtain access to the Notification
+ * Service
+ */
+ DownloadNotification(Context ctx, CharSequence applicationLabel) {
+ mState = -1;
+ mContext = ctx;
+ mLabel = applicationLabel;
+ mNotificationManager = (NotificationManager)
+ mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+ mCustomNotification = CustomNotificationFactory
+ .createCustomNotification();
+ mNotification = new Notification();
+ mCurrentNotification = mNotification;
+
+ }
+
+ @Override
+ public void onServiceConnected(Messenger m) {
+ }
+
+}
diff --git a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/DownloadThread.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadThread.java
index 056d1eca0b..056d1eca0b 100644
--- a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/DownloadThread.java
+++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadThread.java
diff --git a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/DownloaderService.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloaderService.java
index 627bf3eedd..627bf3eedd 100644
--- a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/DownloaderService.java
+++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloaderService.java
diff --git a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/DownloadsDB.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadsDB.java
index 250299c400..250299c400 100755
--- a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/DownloadsDB.java
+++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/DownloadsDB.java
diff --git a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/HttpDateTime.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/HttpDateTime.java
index 3f440e9893..3f440e9893 100644
--- a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/HttpDateTime.java
+++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/HttpDateTime.java
diff --git a/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/V14CustomNotification.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/V14CustomNotification.java
new file mode 100644
index 0000000000..2e049a4d47
--- /dev/null
+++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/V14CustomNotification.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.vending.expansion.downloader.impl;
+
+import com.godot.game.R;
+import com.google.android.vending.expansion.downloader.Helpers;
+
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.content.Context;
+
+public class V14CustomNotification implements DownloadNotification.ICustomNotification {
+
+ CharSequence mTitle;
+ CharSequence mTicker;
+ int mIcon;
+ long mTotalKB = -1;
+ long mCurrentKB = -1;
+ long mTimeRemaining;
+ PendingIntent mPendingIntent;
+
+ @Override
+ public void setIcon(int icon) {
+ mIcon = icon;
+ }
+
+ @Override
+ public void setTitle(CharSequence title) {
+ mTitle = title;
+ }
+
+ @Override
+ public void setTotalBytes(long totalBytes) {
+ mTotalKB = totalBytes;
+ }
+
+ @Override
+ public void setCurrentBytes(long currentBytes) {
+ mCurrentKB = currentBytes;
+ }
+
+ void setProgress(Notification.Builder builder) {
+
+ }
+
+ @Override
+ public Notification updateNotification(Context c) {
+ Notification.Builder builder = new Notification.Builder(c);
+ builder.setContentTitle(mTitle);
+ if (mTotalKB > 0 && -1 != mCurrentKB) {
+ builder.setProgress((int) (mTotalKB >> 8), (int) (mCurrentKB >> 8), false);
+ } else {
+ builder.setProgress(0, 0, true);
+ }
+ builder.setContentText(Helpers.getDownloadProgressString(mCurrentKB, mTotalKB));
+ builder.setContentInfo(c.getString(R.string.time_remaining_notification,
+ Helpers.getTimeRemaining(mTimeRemaining)));
+ if (mIcon != 0) {
+ builder.setSmallIcon(mIcon);
+ } else {
+ int iconResource = android.R.drawable.stat_sys_download;
+ builder.setSmallIcon(iconResource);
+ }
+ builder.setOngoing(true);
+ builder.setTicker(mTicker);
+ builder.setContentIntent(mPendingIntent);
+ builder.setOnlyAlertOnce(true);
+
+ return builder.getNotification();
+ }
+
+ @Override
+ public void setPendingIntent(PendingIntent contentIntent) {
+ mPendingIntent = contentIntent;
+ }
+
+ @Override
+ public void setTicker(CharSequence ticker) {
+ mTicker = ticker;
+ }
+
+ @Override
+ public void setTimeRemaining(long timeRemaining) {
+ mTimeRemaining = timeRemaining;
+ }
+
+}
diff --git a/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/V3CustomNotification.java b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/V3CustomNotification.java
new file mode 100644
index 0000000000..94e21de7ca
--- /dev/null
+++ b/platform/android/java/src/com/google/android/vending/expansion/downloader/impl/V3CustomNotification.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.vending.expansion.downloader.impl;
+
+import com.godot.game.R;
+import com.google.android.vending.expansion.downloader.Helpers;
+
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.graphics.BitmapFactory;
+import android.view.View;
+import android.widget.RemoteViews;
+
+public class V3CustomNotification implements DownloadNotification.ICustomNotification {
+
+ CharSequence mTitle;
+ CharSequence mTicker;
+ int mIcon;
+ long mTotalBytes = -1;
+ long mCurrentBytes = -1;
+ long mTimeRemaining;
+ PendingIntent mPendingIntent;
+ Notification mNotification = new Notification();
+
+ @Override
+ public void setIcon(int icon) {
+ mIcon = icon;
+ }
+
+ @Override
+ public void setTitle(CharSequence title) {
+ mTitle = title;
+ }
+
+ @Override
+ public void setTotalBytes(long totalBytes) {
+ mTotalBytes = totalBytes;
+ }
+
+ @Override
+ public void setCurrentBytes(long currentBytes) {
+ mCurrentBytes = currentBytes;
+ }
+
+ @Override
+ public Notification updateNotification(Context c) {
+ Notification n = mNotification;
+
+ n.icon = mIcon;
+
+ n.flags |= Notification.FLAG_ONGOING_EVENT;
+
+ if (android.os.Build.VERSION.SDK_INT > 10) {
+ n.flags |= Notification.FLAG_ONLY_ALERT_ONCE; // only matters for
+ // Honeycomb
+ }
+
+ // Build the RemoteView object
+ RemoteViews expandedView = new RemoteViews(
+ c.getPackageName(),
+ R.layout.status_bar_ongoing_event_progress_bar);
+
+ expandedView.setTextViewText(R.id.title, mTitle);
+ // look at strings
+ expandedView.setViewVisibility(R.id.description, View.VISIBLE);
+ expandedView.setTextViewText(R.id.description,
+ Helpers.getDownloadProgressString(mCurrentBytes, mTotalBytes));
+ expandedView.setViewVisibility(R.id.progress_bar_frame, View.VISIBLE);
+ expandedView.setProgressBar(R.id.progress_bar,
+ (int) (mTotalBytes >> 8),
+ (int) (mCurrentBytes >> 8),
+ mTotalBytes <= 0);
+ expandedView.setViewVisibility(R.id.time_remaining, View.VISIBLE);
+ expandedView.setTextViewText(
+ R.id.time_remaining,
+ c.getString(R.string.time_remaining_notification,
+ Helpers.getTimeRemaining(mTimeRemaining)));
+ expandedView.setTextViewText(R.id.progress_text,
+ Helpers.getDownloadProgressPercent(mCurrentBytes, mTotalBytes));
+ expandedView.setImageViewResource(R.id.appIcon, mIcon);
+ n.contentView = expandedView;
+ n.contentIntent = mPendingIntent;
+ return n;
+ }
+
+ @Override
+ public void setPendingIntent(PendingIntent contentIntent) {
+ mPendingIntent = contentIntent;
+ }
+
+ @Override
+ public void setTicker(CharSequence ticker) {
+ mTicker = ticker;
+ }
+
+ @Override
+ public void setTimeRemaining(long timeRemaining) {
+ mTimeRemaining = timeRemaining;
+ }
+
+}
diff --git a/platform/android/java/src/org/godotengine/godot/Dictionary.java b/platform/android/java/src/org/godotengine/godot/Dictionary.java
new file mode 100644
index 0000000000..34051c4bb8
--- /dev/null
+++ b/platform/android/java/src/org/godotengine/godot/Dictionary.java
@@ -0,0 +1,80 @@
+/*************************************************************************/
+/* Dictionary.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
+package org.godotengine.godot;
+
+import java.util.HashMap;
+import java.util.Set;
+
+
+public class Dictionary extends HashMap<String, Object> {
+
+ protected String[] keys_cache;
+
+ public String[] get_keys() {
+
+ String[] ret = new String[size()];
+ int i=0;
+ Set<String> keys = keySet();
+ for (String key : keys) {
+
+ ret[i] = key;
+ i++;
+ };
+
+ return ret;
+ };
+
+ public Object[] get_values() {
+
+ Object[] ret = new Object[size()];
+ int i=0;
+ Set<String> keys = keySet();
+ for (String key : keys) {
+
+ ret[i] = get(key);
+ i++;
+ };
+
+ return ret;
+ };
+
+ public void set_keys(String[] keys) {
+ keys_cache = keys;
+ };
+
+ public void set_values(Object[] vals) {
+
+ int i=0;
+ for (String key : keys_cache) {
+ put(key, vals[i]);
+ i++;
+ };
+ keys_cache = null;
+ };
+};
diff --git a/platform/android/java/src/org/godotengine/godot/Godot.java b/platform/android/java/src/org/godotengine/godot/Godot.java
new file mode 100644
index 0000000000..1f208f8fb6
--- /dev/null
+++ b/platform/android/java/src/org/godotengine/godot/Godot.java
@@ -0,0 +1,938 @@
+/*************************************************************************/
+/* Godot.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
+package org.godotengine.godot;
+
+import android.R;
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ProgressBar;
+import android.widget.RelativeLayout;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.view.ViewGroup.LayoutParams;
+import android.app.*;
+import android.content.*;
+import android.content.SharedPreferences.Editor;
+import android.view.*;
+import android.view.inputmethod.InputMethodManager;
+import android.os.*;
+import android.util.Log;
+import android.graphics.*;
+import android.text.method.*;
+import android.text.*;
+import android.media.*;
+import android.hardware.*;
+import android.content.*;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.net.Uri;
+import android.media.MediaPlayer;
+
+import java.lang.reflect.Method;
+import java.util.List;
+import java.util.ArrayList;
+
+import org.godotengine.godot.payments.PaymentsManager;
+
+import java.io.IOException;
+
+import android.provider.Settings.Secure;
+import android.widget.FrameLayout;
+
+import org.godotengine.godot.input.*;
+
+import java.io.InputStream;
+import javax.microedition.khronos.opengles.GL10;
+import java.security.MessageDigest;
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.LinkedList;
+
+import com.google.android.vending.expansion.downloader.Constants;
+import com.google.android.vending.expansion.downloader.DownloadProgressInfo;
+import com.google.android.vending.expansion.downloader.DownloaderClientMarshaller;
+import com.google.android.vending.expansion.downloader.DownloaderServiceMarshaller;
+import com.google.android.vending.expansion.downloader.Helpers;
+import com.google.android.vending.expansion.downloader.IDownloaderClient;
+import com.google.android.vending.expansion.downloader.IDownloaderService;
+import com.google.android.vending.expansion.downloader.IStub;
+
+import android.os.Bundle;
+import android.os.Messenger;
+import android.os.SystemClock;
+
+
+public class Godot extends Activity implements SensorEventListener, IDownloaderClient
+{
+
+ static final int MAX_SINGLETONS = 64;
+ private IStub mDownloaderClientStub;
+ private IDownloaderService mRemoteService;
+ private TextView mStatusText;
+ private TextView mProgressFraction;
+ private TextView mProgressPercent;
+ private TextView mAverageSpeed;
+ private TextView mTimeRemaining;
+ private ProgressBar mPB;
+
+ private View mDashboard;
+ private View mCellMessage;
+
+ private Button mPauseButton;
+ private Button mWiFiSettingsButton;
+
+ private boolean use_32_bits=false;
+ private boolean use_immersive=false;
+ private boolean mStatePaused;
+ private int mState;
+ private boolean keep_screen_on=true;
+
+ private void setState(int newState) {
+ if (mState != newState) {
+ mState = newState;
+ mStatusText.setText(Helpers.getDownloaderStringResourceIDFromState(newState));
+ }
+ }
+
+ private void setButtonPausedState(boolean paused) {
+ mStatePaused = paused;
+ int stringResourceID = paused ? com.godot.game.R.string.text_button_resume :
+ com.godot.game.R.string.text_button_pause;
+ mPauseButton.setText(stringResourceID);
+ }
+
+ static public class SingletonBase {
+
+ protected void registerClass(String p_name, String[] p_methods) {
+
+ GodotLib.singleton(p_name,this);
+
+ Class clazz = getClass();
+ Method[] methods = clazz.getDeclaredMethods();
+ for (Method method : methods) {
+ boolean found=false;
+ Log.d("XXX","METHOD: %s\n" + method.getName());
+
+ for (String s : p_methods) {
+ Log.d("XXX", "METHOD CMP WITH: %s\n" + s);
+ if (s.equals(method.getName())) {
+ found=true;
+ Log.d("XXX","METHOD CMP VALID");
+ break;
+ }
+ }
+ if (!found)
+ continue;
+
+ Log.d("XXX","METHOD FOUND: %s\n" + method.getName());
+
+ List<String> ptr = new ArrayList<String>();
+
+ Class[] paramTypes = method.getParameterTypes();
+ for (Class c : paramTypes) {
+ ptr.add(c.getName());
+ }
+
+ String[] pt = new String[ptr.size()];
+ ptr.toArray(pt);
+
+ GodotLib.method(p_name,method.getName(),method.getReturnType().getName(),pt);
+
+
+ }
+
+ Godot.singletons[Godot.singleton_count++]=this;
+ }
+
+ protected void onMainActivityResult(int requestCode, int resultCode, Intent data) {
+
+
+ }
+
+ protected void onMainPause() {}
+ protected void onMainResume() {}
+ protected void onMainDestroy() {}
+
+ protected void onGLDrawFrame(GL10 gl) {}
+ protected void onGLSurfaceChanged(GL10 gl, int width, int height) {} // singletons will always miss first onGLSurfaceChanged call
+ //protected void onGLSurfaceCreated(GL10 gl, EGLConfig config) {} // singletons won't be ready until first GodotLib.step()
+
+ public void registerMethods() {}
+ }
+
+/*
+ protected List<SingletonBase> singletons = new ArrayList<SingletonBase>();
+ protected void instanceSingleton(SingletonBase s) {
+
+ s.registerMethods();
+ singletons.add(s);
+ }
+
+*/
+
+ private String[] command_line;
+
+ public GodotView mView;
+ private boolean godot_initialized=false;
+
+
+ private SensorManager mSensorManager;
+ private Sensor mAccelerometer;
+
+ public FrameLayout layout;
+ public RelativeLayout adLayout;
+
+
+ static public GodotIO io;
+
+ public static void setWindowTitle(String title) {
+ //setTitle(title);
+ }
+
+
+ static SingletonBase singletons[] = new SingletonBase[MAX_SINGLETONS];
+ static int singleton_count=0;
+
+
+ public interface ResultCallback {
+ public void callback(int requestCode, int resultCode, Intent data);
+ };
+ public ResultCallback result_callback;
+
+ private PaymentsManager mPaymentsManager = null;
+
+ @Override protected void onActivityResult (int requestCode, int resultCode, Intent data) {
+ if(requestCode == PaymentsManager.REQUEST_CODE_FOR_PURCHASE){
+ mPaymentsManager.processPurchaseResponse(resultCode, data);
+ }else if (result_callback != null) {
+ result_callback.callback(requestCode, resultCode, data);
+ result_callback = null;
+ };
+
+ for(int i=0;i<singleton_count;i++) {
+
+ singletons[i].onMainActivityResult(requestCode,resultCode,data);
+ }
+ };
+
+ public void onVideoInit(boolean use_gl2) {
+
+// mView = new GodotView(getApplication(),io,use_gl2);
+// setContentView(mView);
+
+ layout = new FrameLayout(this);
+ layout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
+ setContentView(layout);
+
+ // GodotEditText layout
+ GodotEditText edittext = new GodotEditText(this);
+ edittext.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.WRAP_CONTENT));
+ // ...add to FrameLayout
+ layout.addView(edittext);
+
+ mView = new GodotView(getApplication(),io,use_gl2,use_32_bits, this);
+ layout.addView(mView,new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
+ setKeepScreenOn(GodotLib.getGlobal("display/keep_screen_on").equals("True"));
+
+ edittext.setView(mView);
+ io.setEdit(edittext);
+
+ // Ad layout
+ adLayout = new RelativeLayout(this);
+ adLayout.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
+ layout.addView(adLayout);
+
+ }
+
+ public void setKeepScreenOn(final boolean p_enabled) {
+ keep_screen_on = p_enabled;
+ if (mView != null){
+ runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mView.setKeepScreenOn(p_enabled);
+ }
+ });
+ }
+ }
+
+ private static Godot _self;
+
+ public static Godot getInstance(){
+ return Godot._self;
+ }
+
+
+ private String[] getCommandLine() {
+ InputStream is;
+ try {
+ is = getAssets().open("_cl_");
+ byte[] len = new byte[4];
+ int r = is.read(len);
+ if (r<4) {
+ Log.d("XXX","**ERROR** Wrong cmdline length.\n");
+ Log.d("GODOT", "**ERROR** Wrong cmdline length.\n");
+ return new String[0];
+ }
+ int argc=((int)(len[3]&0xFF)<<24) | ((int)(len[2]&0xFF)<<16) | ((int)(len[1]&0xFF)<<8) | ((int)(len[0]&0xFF));
+ String[] cmdline = new String[argc];
+
+ for(int i=0;i<argc;i++) {
+ r = is.read(len);
+ if (r<4) {
+
+ Log.d("GODOT", "**ERROR** Wrong cmdline param lenght.\n");
+ return new String[0];
+ }
+ int strlen=((int)(len[3]&0xFF)<<24) | ((int)(len[2]&0xFF)<<16) | ((int)(len[1]&0xFF)<<8) | ((int)(len[0]&0xFF));
+ if (strlen>65535) {
+ Log.d("GODOT", "**ERROR** Wrong command len\n");
+ return new String[0];
+ }
+ byte[] arg = new byte[strlen];
+ r = is.read(arg);
+ if (r==strlen) {
+ cmdline[i]=new String(arg,"UTF-8");
+ }
+ }
+ return cmdline;
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.d("GODOT", "**ERROR** Exception " + e.getClass().getName() + ":" + e.getMessage());
+ return new String[0];
+ }
+
+
+ }
+
+
+ String expansion_pack_path;
+
+
+ private void initializeGodot() {
+
+ if (expansion_pack_path!=null) {
+
+ String[] new_cmdline;
+ int cll=0;
+ if (command_line!=null) {
+ Log.d("GODOT", "initializeGodot: command_line: is not null" );
+ new_cmdline = new String[ command_line.length + 2 ];
+ cll=command_line.length;
+ for(int i=0;i<command_line.length;i++) {
+ new_cmdline[i]=command_line[i];
+ }
+ } else {
+ Log.d("GODOT", "initializeGodot: command_line: is null" );
+ new_cmdline = new String[ 2 ];
+ }
+
+ new_cmdline[cll]="-main_pack";
+ new_cmdline[cll+1]=expansion_pack_path;
+ command_line=new_cmdline;
+ }
+
+ io = new GodotIO(this);
+ io.unique_id = Secure.getString(getContentResolver(), Secure.ANDROID_ID);
+ GodotLib.io=io;
+ Log.d("GODOT", "command_line is null? " + ((command_line == null)?"yes":"no"));
+ /*if(command_line != null){
+ Log.d("GODOT", "Command Line:");
+ for(int w=0;w <command_line.length;w++){
+ Log.d("GODOT"," " + command_line[w]);
+ }
+ }*/
+ GodotLib.initialize(this,io.needsReloadHooks(),command_line,getAssets());
+ mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
+ mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
+ mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME);
+
+ result_callback = null;
+
+ mPaymentsManager = PaymentsManager.createManager(this).initService();
+ godot_initialized=true;
+
+ }
+
+ @Override
+ public void onServiceConnected(Messenger m) {
+ mRemoteService = DownloaderServiceMarshaller.CreateProxy(m);
+ mRemoteService.onClientUpdated(mDownloaderClientStub.getMessenger());
+ }
+
+
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+
+ Log.d("GODOT", "** GODOT ACTIVITY CREATED HERE ***\n");
+
+ super.onCreate(icicle);
+ _self = this;
+ Window window = getWindow();
+ //window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+ window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
+
+
+ //check for apk expansion API
+ if (true) {
+ boolean md5mismatch = false;
+ command_line = getCommandLine();
+ boolean use_apk_expansion=false;
+ String main_pack_md5=null;
+ String main_pack_key=null;
+
+ List<String> new_args = new LinkedList<String>();
+
+
+ for(int i=0;i<command_line.length;i++) {
+
+ boolean has_extra = i< command_line.length -1;
+ if (command_line[i].equals("-use_depth_32")) {
+ use_32_bits=true;
+ } else if (command_line[i].equals("-use_immersive")) {
+ use_immersive=true;
+ if(Build.VERSION.SDK_INT >= 19.0){ // check if the application runs on an android 4.4+
+ window.getDecorView().setSystemUiVisibility(
+ View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
+ | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
+ | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
+
+ UiChangeListener();
+ }
+ } else if (command_line[i].equals("-use_apk_expansion")) {
+ use_apk_expansion=true;
+ } else if (has_extra && command_line[i].equals("-apk_expansion_md5")) {
+ main_pack_md5=command_line[i+1];
+ i++;
+ } else if (has_extra && command_line[i].equals("-apk_expansion_key")) {
+ main_pack_key=command_line[i+1];
+ SharedPreferences prefs = getSharedPreferences("app_data_keys", MODE_PRIVATE);
+ Editor editor = prefs.edit();
+ editor.putString("store_public_key", main_pack_key);
+
+ editor.commit();
+ i++;
+ } else if (command_line[i].trim().length()!=0){
+ new_args.add(command_line[i]);
+ }
+ }
+
+ if (new_args.isEmpty()){
+ command_line=null;
+ }else{
+
+ command_line = new_args.toArray(new String[new_args.size()]);
+ }
+ if (use_apk_expansion && main_pack_md5!=null && main_pack_key!=null) {
+ //check that environment is ok!
+ if (!Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED )) {
+ Log.d("GODOT", "**ERROR! No media mounted!");
+ //show popup and die
+ }
+
+ // Build the full path to the app's expansion files
+ try {
+ expansion_pack_path = Environment.getExternalStorageDirectory().toString() + "/Android/obb/"+this.getPackageName();
+ expansion_pack_path+="/"+"main."+getPackageManager().getPackageInfo(getPackageName(), 0).versionCode+"."+this.getPackageName()+".obb";
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ File f = new File(expansion_pack_path);
+
+ boolean pack_valid = true;
+ Log.d("GODOT","**PACK** - Path "+expansion_pack_path);
+
+ if (!f.exists()) {
+
+ pack_valid=false;
+ Log.d("GODOT","**PACK** - File does not exist");
+
+ } else if( obbIsCorrupted(expansion_pack_path, main_pack_md5)){
+ Log.d("GODOT", "**PACK** - Expansion pack (obb) is corrupted");
+ pack_valid = false;
+ try{
+ f.delete();
+ }catch(Exception e){
+ Log.d("GODOT", "**PACK** - Error deleting corrupted expansion pack (obb)");
+ }
+ }
+
+ if (!pack_valid) {
+ Log.d("GODOT", "Pack Invalid, try re-downloading.");
+
+ Intent notifierIntent = new Intent(this, this.getClass());
+ notifierIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
+ Intent.FLAG_ACTIVITY_CLEAR_TOP);
+
+ PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
+ notifierIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+
+ int startResult;
+ try {
+ Log.d("GODOT", "INITIALIZING DOWNLOAD");
+ startResult = DownloaderClientMarshaller.startDownloadServiceIfRequired(
+ getApplicationContext(),
+ pendingIntent,
+ GodotDownloaderService.class);
+ Log.d("GODOT", "DOWNLOAD SERVICE FINISHED:" + startResult);
+
+ if (startResult != DownloaderClientMarshaller.NO_DOWNLOAD_REQUIRED) {
+ Log.d("GODOT", "DOWNLOAD REQUIRED");
+ // This is where you do set up to display the download
+ // progress (next step)
+ mDownloaderClientStub = DownloaderClientMarshaller.CreateStub(this,
+ GodotDownloaderService.class);
+
+ setContentView(com.godot.game.R.layout.downloading_expansion);
+ mPB = (ProgressBar) findViewById(com.godot.game.R.id.progressBar);
+ mStatusText = (TextView) findViewById(com.godot.game.R.id.statusText);
+ mProgressFraction = (TextView) findViewById(com.godot.game.R.id.progressAsFraction);
+ mProgressPercent = (TextView) findViewById(com.godot.game.R.id.progressAsPercentage);
+ mAverageSpeed = (TextView) findViewById(com.godot.game.R.id.progressAverageSpeed);
+ mTimeRemaining = (TextView) findViewById(com.godot.game.R.id.progressTimeRemaining);
+ mDashboard = findViewById(com.godot.game.R.id.downloaderDashboard);
+ mCellMessage = findViewById(com.godot.game.R.id.approveCellular);
+ mPauseButton = (Button) findViewById(com.godot.game.R.id.pauseButton);
+ mWiFiSettingsButton = (Button) findViewById(com.godot.game.R.id.wifiSettingsButton);
+
+ return;
+ } else{
+ Log.d("GODOT", "NO DOWNLOAD REQUIRED");
+ }
+ } catch (NameNotFoundException e) {
+ // TODO Auto-generated catch block
+ Log.d("GODOT", "Error downloading expansion package:" + e.getMessage());
+ }
+
+ }
+
+ }
+ }
+
+ initializeGodot();
+
+
+ // instanceSingleton( new GodotFacebook(this) );
+
+
+ }
+
+
+ @Override protected void onDestroy(){
+
+ if(mPaymentsManager != null ) mPaymentsManager.destroy();
+ for(int i=0;i<singleton_count;i++) {
+ singletons[i].onMainDestroy();
+ }
+ super.onDestroy();
+ }
+
+ @Override protected void onPause() {
+ super.onPause();
+ if (!godot_initialized){
+ if (null != mDownloaderClientStub) {
+ mDownloaderClientStub.disconnect(this);
+ }
+ return;
+ }
+ mView.onPause();
+ mSensorManager.unregisterListener(this);
+ GodotLib.focusout();
+
+ for(int i=0;i<singleton_count;i++) {
+ singletons[i].onMainPause();
+ }
+ }
+
+ @Override protected void onResume() {
+ super.onResume();
+ if (!godot_initialized){
+ if (null != mDownloaderClientStub) {
+ mDownloaderClientStub.connect(this);
+ }
+ return;
+ }
+
+ mView.onResume();
+ mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
+ GodotLib.focusin();
+ if(use_immersive && Build.VERSION.SDK_INT >= 19.0){ // check if the application runs on an android 4.4+
+ Window window = getWindow();
+ window.getDecorView().setSystemUiVisibility(
+ View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION // hide nav bar
+ | View.SYSTEM_UI_FLAG_FULLSCREEN // hide status bar
+ | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
+ }
+
+ for(int i=0;i<singleton_count;i++) {
+
+ singletons[i].onMainResume();
+ }
+
+
+
+ }
+
+ public void UiChangeListener() {
+ final View decorView = getWindow().getDecorView();
+ decorView.setOnSystemUiVisibilityChangeListener (new View.OnSystemUiVisibilityChangeListener() {
+ @Override
+ public void onSystemUiVisibilityChange(int visibility) {
+ if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
+ decorView.setSystemUiVisibility(
+ View.SYSTEM_UI_FLAG_LAYOUT_STABLE
+ | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
+ | View.SYSTEM_UI_FLAG_FULLSCREEN
+ | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
+ }
+ }
+ });
+ }
+
+ @Override public void onSensorChanged(SensorEvent event) {
+ Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
+ int displayRotation = display.getRotation();
+
+ float[] adjustedValues = new float[3];
+ final int axisSwap[][] = {
+ { 1, -1, 0, 1 }, // ROTATION_0
+ {-1, -1, 1, 0 }, // ROTATION_90
+ {-1, 1, 0, 1 }, // ROTATION_180
+ { 1, 1, 1, 0 } }; // ROTATION_270
+
+ final int[] as = axisSwap[displayRotation];
+ adjustedValues[0] = (float)as[0] * event.values[ as[2] ];
+ adjustedValues[1] = (float)as[1] * event.values[ as[3] ];
+ adjustedValues[2] = event.values[2];
+
+ float x = adjustedValues[0];
+ float y = adjustedValues[1];
+ float z = adjustedValues[2];
+ GodotLib.accelerometer(x,y,z);
+ }
+
+ @Override public final void onAccuracyChanged(Sensor sensor, int accuracy) {
+ // Do something here if sensor accuracy changes.
+ }
+
+/*
+ @Override public boolean dispatchKeyEvent(KeyEvent event) {
+
+ if (event.getKeyCode()==KeyEvent.KEYCODE_BACK) {
+
+ System.out.printf("** BACK REQUEST!\n");
+
+ GodotLib.quit();
+ return true;
+ }
+ System.out.printf("** OTHER KEY!\n");
+
+ return false;
+ }
+*/
+
+ @Override public void onBackPressed() {
+
+ System.out.printf("** BACK REQUEST!\n");
+ GodotLib.quit();
+ }
+
+ public void forceQuit() {
+
+ System.exit(0);
+ }
+
+
+
+ private boolean obbIsCorrupted(String f, String main_pack_md5){
+
+ try {
+
+ InputStream fis = new FileInputStream(f);
+
+ // Create MD5 Hash
+ byte[] buffer = new byte[16384];
+
+ MessageDigest complete = MessageDigest.getInstance("MD5");
+ int numRead;
+ do {
+ numRead = fis.read(buffer);
+ if (numRead > 0) {
+ complete.update(buffer, 0, numRead);
+ }
+ } while (numRead != -1);
+
+
+ fis.close();
+ byte[] messageDigest = complete.digest();
+
+ // Create Hex String
+ StringBuffer hexString = new StringBuffer();
+ for (int i=0; i<messageDigest.length; i++) {
+ String s = Integer.toHexString(0xFF & messageDigest[i]);
+
+ if (s.length()==1) {
+ s="0"+s;
+ }
+ hexString.append(s);
+ }
+ String md5str = hexString.toString();
+
+ //Log.d("GODOT","**PACK** - My MD5: "+hexString+" - APK md5: "+main_pack_md5);
+ if (!md5str.equals(main_pack_md5)) {
+ Log.d("GODOT","**PACK MD5 MISMATCH???** - MD5 Found: "+md5str+" "+Integer.toString(md5str.length())+" - MD5 Expected: "+main_pack_md5+" "+Integer.toString(main_pack_md5.length()));
+ return true;
+ }
+ return false;
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.d("GODOT","**PACK FAIL**");
+ return true;
+ }
+ }
+
+ //@Override public boolean dispatchTouchEvent (MotionEvent event) {
+ public boolean gotTouchEvent(MotionEvent event) {
+
+ super.onTouchEvent(event);
+ int evcount=event.getPointerCount();
+ if (evcount==0)
+ return true;
+
+ int[] arr = new int[event.getPointerCount()*3];
+
+ for(int i=0;i<event.getPointerCount();i++) {
+
+ arr[i*3+0]=(int)event.getPointerId(i);
+ arr[i*3+1]=(int)event.getX(i);
+ arr[i*3+2]=(int)event.getY(i);
+ }
+
+ //System.out.printf("gaction: %d\n",event.getAction());
+ switch(event.getAction()&MotionEvent.ACTION_MASK) {
+
+ case MotionEvent.ACTION_DOWN: {
+ GodotLib.touch(0,0,evcount,arr);
+ //System.out.printf("action down at: %f,%f\n", event.getX(),event.getY());
+ } break;
+ case MotionEvent.ACTION_MOVE: {
+ GodotLib.touch(1,0,evcount,arr);
+ //for(int i=0;i<event.getPointerCount();i++) {
+ // System.out.printf("%d - moved to: %f,%f\n",i, event.getX(i),event.getY(i));
+ //}
+ } break;
+ case MotionEvent.ACTION_POINTER_UP: {
+ final int indexPointUp = event.getActionIndex();
+ final int pointer_idx = event.getPointerId(indexPointUp);
+ GodotLib.touch(4,pointer_idx,evcount,arr);
+ //System.out.printf("%d - s.up at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
+ } break;
+ case MotionEvent.ACTION_POINTER_DOWN: {
+ int pointer_idx = event.getActionIndex();
+ GodotLib.touch(3,pointer_idx,evcount,arr);
+ //System.out.printf("%d - s.down at: %f,%f\n",pointer_idx, event.getX(pointer_idx),event.getY(pointer_idx));
+ } break;
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP: {
+ GodotLib.touch(2,0,evcount,arr);
+ //for(int i=0;i<event.getPointerCount();i++) {
+ // System.out.printf("%d - up! %f,%f\n",i, event.getX(i),event.getY(i));
+ //}
+ } break;
+
+ }
+ return true;
+ }
+
+ @Override public boolean onKeyMultiple(final int inKeyCode, int repeatCount, KeyEvent event) {
+ String s = event.getCharacters();
+ if (s == null || s.length() == 0)
+ return super.onKeyMultiple(inKeyCode, repeatCount, event);
+
+ final char[] cc = s.toCharArray();
+ int cnt = 0;
+ for (int i = cc.length; --i >= 0; cnt += cc[i] != 0 ? 1 : 0);
+ if (cnt == 0) return super.onKeyMultiple(inKeyCode, repeatCount, event);
+ final Activity me = this;
+ queueEvent(new Runnable() {
+ // This method will be called on the rendering thread:
+ public void run() {
+ for (int i = 0, n = cc.length; i < n; i++) {
+ int keyCode;
+ if ((keyCode = cc[i]) != 0) {
+ // Simulate key down and up...
+ GodotLib.key(0, keyCode, true);
+ GodotLib.key(0, keyCode, false);
+ }
+ }
+ }
+ });
+ return true;
+ }
+
+ private void queueEvent(Runnable runnable) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public PaymentsManager getPaymentsManager() {
+ return mPaymentsManager;
+ }
+
+// public void setPaymentsManager(PaymentsManager mPaymentsManager) {
+// this.mPaymentsManager = mPaymentsManager;
+// };
+
+
+ // Audio
+
+ /**
+ * The download state should trigger changes in the UI --- it may be useful
+ * to show the state as being indeterminate at times. This sample can be
+ * considered a guideline.
+ */
+ @Override
+ public void onDownloadStateChanged(int newState) {
+ Log.d("GODOT", "onDownloadStateChanged:" + newState);
+ setState(newState);
+ boolean showDashboard = true;
+ boolean showCellMessage = false;
+ boolean paused;
+ boolean indeterminate;
+ switch (newState) {
+ case IDownloaderClient.STATE_IDLE:
+ Log.d("GODOT", "STATE IDLE");
+ // STATE_IDLE means the service is listening, so it's
+ // safe to start making calls via mRemoteService.
+ paused = false;
+ indeterminate = true;
+ break;
+ case IDownloaderClient.STATE_CONNECTING:
+ case IDownloaderClient.STATE_FETCHING_URL:
+ Log.d("GODOT", "STATE CONNECTION / FETCHING URL");
+ showDashboard = true;
+ paused = false;
+ indeterminate = true;
+ break;
+ case IDownloaderClient.STATE_DOWNLOADING:
+ Log.d("GODOT", "STATE DOWNLOADING");
+ paused = false;
+ showDashboard = true;
+ indeterminate = false;
+ break;
+
+ case IDownloaderClient.STATE_FAILED_CANCELED:
+ case IDownloaderClient.STATE_FAILED:
+ case IDownloaderClient.STATE_FAILED_FETCHING_URL:
+ case IDownloaderClient.STATE_FAILED_UNLICENSED:
+ Log.d("GODOT", "MANY TYPES OF FAILING");
+ paused = true;
+ showDashboard = false;
+ indeterminate = false;
+ break;
+ case IDownloaderClient.STATE_PAUSED_NEED_CELLULAR_PERMISSION:
+ case IDownloaderClient.STATE_PAUSED_WIFI_DISABLED_NEED_CELLULAR_PERMISSION:
+ Log.d("GODOT", "PAUSED FOR SOME STUPID REASON");
+ showDashboard = false;
+ paused = true;
+ indeterminate = false;
+ showCellMessage = true;
+ break;
+
+ case IDownloaderClient.STATE_PAUSED_BY_REQUEST:
+ Log.d("GODOT", "PAUSED BY STUPID USER");
+ paused = true;
+ indeterminate = false;
+ break;
+ case IDownloaderClient.STATE_PAUSED_ROAMING:
+ case IDownloaderClient.STATE_PAUSED_SDCARD_UNAVAILABLE:
+ Log.d("GODOT", "PAUSED BY ROAMING WTF!?");
+ paused = true;
+ indeterminate = false;
+ break;
+ case IDownloaderClient.STATE_COMPLETED:
+ Log.d("GODOT", "COMPLETED");
+ showDashboard = false;
+ paused = false;
+ indeterminate = false;
+// validateXAPKZipFiles();
+ initializeGodot();
+ return;
+ default:
+ Log.d("GODOT", "DEFAULT ????");
+ paused = true;
+ indeterminate = true;
+ showDashboard = true;
+ }
+ int newDashboardVisibility = showDashboard ? View.VISIBLE : View.GONE;
+ if (mDashboard.getVisibility() != newDashboardVisibility) {
+ mDashboard.setVisibility(newDashboardVisibility);
+ }
+ int cellMessageVisibility = showCellMessage ? View.VISIBLE : View.GONE;
+ if (mCellMessage.getVisibility() != cellMessageVisibility) {
+ mCellMessage.setVisibility(cellMessageVisibility);
+ }
+
+ mPB.setIndeterminate(indeterminate);
+ setButtonPausedState(paused);
+ }
+
+
+ @Override
+ public void onDownloadProgress(DownloadProgressInfo progress) {
+ mAverageSpeed.setText(getString(com.godot.game.R.string.kilobytes_per_second,
+ Helpers.getSpeedString(progress.mCurrentSpeed)));
+ mTimeRemaining.setText(getString(com.godot.game.R.string.time_remaining,
+ Helpers.getTimeRemaining(progress.mTimeRemaining)));
+
+ progress.mOverallTotal = progress.mOverallTotal;
+ mPB.setMax((int) (progress.mOverallTotal >> 8));
+ mPB.setProgress((int) (progress.mOverallProgress >> 8));
+ mProgressPercent.setText(Long.toString(progress.mOverallProgress
+ * 100 /
+ progress.mOverallTotal) + "%");
+ mProgressFraction.setText(Helpers.getDownloadProgressString
+ (progress.mOverallProgress,
+ progress.mOverallTotal));
+
+ }
+
+}
diff --git a/platform/android/java/src/org/godotengine/godot/GodotDownloaderAlarmReceiver.java b/platform/android/java/src/org/godotengine/godot/GodotDownloaderAlarmReceiver.java
new file mode 100644
index 0000000000..b602f4757c
--- /dev/null
+++ b/platform/android/java/src/org/godotengine/godot/GodotDownloaderAlarmReceiver.java
@@ -0,0 +1,30 @@
+package org.godotengine.godot;
+
+import com.google.android.vending.expansion.downloader.DownloaderClientMarshaller;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.util.Log;
+
+/**
+ * You should start your derived downloader class when this receiver gets the message
+ * from the alarm service using the provided service helper function within the
+ * DownloaderClientMarshaller. This class must be then registered in your AndroidManifest.xml
+ * file with a section like this:
+ * <receiver android:name=".GodotDownloaderAlarmReceiver"/>
+ */
+public class GodotDownloaderAlarmReceiver extends BroadcastReceiver {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.d("GODOT", "Alarma recivida");
+ try {
+ DownloaderClientMarshaller.startDownloadServiceIfRequired(context, intent, GodotDownloaderService.class);
+ } catch (NameNotFoundException e) {
+ e.printStackTrace();
+ Log.d("GODOT", "Exception: " + e.getClass().getName() + ":" + e.getMessage());
+ }
+ }
+}
diff --git a/platform/android/java/src/org/godotengine/godot/GodotDownloaderService.java b/platform/android/java/src/org/godotengine/godot/GodotDownloaderService.java
new file mode 100644
index 0000000000..6735d387f3
--- /dev/null
+++ b/platform/android/java/src/org/godotengine/godot/GodotDownloaderService.java
@@ -0,0 +1,56 @@
+package org.godotengine.godot;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.util.Log;
+
+import com.google.android.vending.expansion.downloader.impl.DownloaderService;
+
+/**
+ * This class demonstrates the minimal client implementation of the
+ * DownloaderService from the Downloader library.
+ */
+public class GodotDownloaderService extends DownloaderService {
+ // stuff for LVL -- MODIFY FOR YOUR APPLICATION!
+ private static final String BASE64_PUBLIC_KEY = "REPLACE THIS WITH YOUR PUBLIC KEY";
+ // used by the preference obfuscater
+ private static final byte[] SALT = new byte[] {
+ 1, 43, -12, -1, 54, 98,
+ -100, -12, 43, 2, -8, -4, 9, 5, -106, -108, -33, 45, -1, 84
+ };
+
+ /**
+ * This public key comes from your Android Market publisher account, and it
+ * used by the LVL to validate responses from Market on your behalf.
+ */
+ @Override
+ public String getPublicKey() {
+ SharedPreferences prefs = getApplicationContext().getSharedPreferences("app_data_keys", Context.MODE_PRIVATE);
+ Log.d("GODOT", "getting public key:" + prefs.getString("store_public_key", null));
+ return prefs.getString("store_public_key", null);
+
+// return BASE64_PUBLIC_KEY;
+ }
+
+ /**
+ * This is used by the preference obfuscater to make sure that your
+ * obfuscated preferences are different than the ones used by other
+ * applications.
+ */
+ @Override
+ public byte[] getSALT() {
+ return SALT;
+ }
+
+ /**
+ * Fill this in with the class name for your alarm receiver. We do this
+ * because receivers must be unique across all of Android (it's a good idea
+ * to make sure that your receiver is in your unique package)
+ */
+ @Override
+ public String getAlarmReceiverClassName() {
+ Log.d("GODOT", "getAlarmReceiverClassName()");
+ return GodotDownloaderAlarmReceiver.class.getName();
+ }
+
+}
diff --git a/platform/android/java/src/org/godotengine/godot/GodotIO.java b/platform/android/java/src/org/godotengine/godot/GodotIO.java
new file mode 100644
index 0000000000..3e6919c2ad
--- /dev/null
+++ b/platform/android/java/src/org/godotengine/godot/GodotIO.java
@@ -0,0 +1,673 @@
+/*************************************************************************/
+/* GodotIO.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
+package org.godotengine.godot;
+import java.util.HashMap;
+import java.util.Locale;
+import android.net.Uri;
+import android.content.Intent;
+import android.content.res.AssetManager;
+import java.io.InputStream;
+import java.io.IOException;
+import android.app.*;
+import android.content.*;
+import android.view.*;
+import android.view.inputmethod.InputMethodManager;
+import android.os.*;
+import android.util.Log;
+import android.graphics.*;
+import android.text.method.*;
+import android.text.*;
+import android.media.*;
+import android.hardware.*;
+import android.content.*;
+import android.content.pm.ActivityInfo;
+import org.godotengine.godot.input.*;
+//android.os.Build
+
+// Wrapper for native library
+
+public class GodotIO {
+
+
+ AssetManager am;
+ Godot activity;
+ GodotEditText edit;
+
+ Context applicationContext;
+ MediaPlayer mediaPlayer;
+
+ final int SCREEN_LANDSCAPE=0;
+ final int SCREEN_PORTRAIT=1;
+ final int SCREEN_REVERSE_LANDSCAPE=2;
+ final int SCREEN_REVERSE_PORTRAIT=3;
+ final int SCREEN_SENSOR_LANDSCAPE=4;
+ final int SCREEN_SENSOR_PORTRAIT=5;
+ final int SCREEN_SENSOR=6;
+
+ /////////////////////////
+ /// FILES
+ /////////////////////////
+
+ public int last_file_id=1;
+
+ class AssetData {
+
+
+ public boolean eof=false;
+ public String path;
+ public InputStream is;
+ public int len;
+ public int pos;
+ }
+
+
+ HashMap<Integer,AssetData> streams;
+
+
+ public int file_open(String path,boolean write) {
+
+ //System.out.printf("file_open: Attempt to Open %s\n",path);
+
+ //Log.v("MyApp", "TRYING TO OPEN FILE: " + path);
+ if (write)
+ return -1;
+
+
+ AssetData ad = new AssetData();
+
+ try {
+ ad.is = am.open(path);
+
+ } catch (Exception e) {
+
+ //System.out.printf("Exception on file_open: %s\n",path);
+ return -1;
+ }
+
+ try {
+ ad.len=ad.is.available();
+ } catch (Exception e) {
+
+ System.out.printf("Exception availabling on file_open: %s\n",path);
+ return -1;
+ }
+
+ ad.path=path;
+ ad.pos=0;
+ ++last_file_id;
+ streams.put(last_file_id,ad);
+
+ return last_file_id;
+ }
+ public int file_get_size(int id) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_get_size: Invalid file id: %d\n",id);
+ return -1;
+ }
+
+ return streams.get(id).len;
+
+ }
+ public void file_seek(int id,int bytes) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_get_size: Invalid file id: %d\n",id);
+ return;
+ }
+ //seek sucks
+ AssetData ad = streams.get(id);
+ if (bytes>ad.len)
+ bytes=ad.len;
+ if (bytes<0)
+ bytes=0;
+
+ try {
+
+ if (bytes > (int)ad.pos) {
+ int todo=bytes-(int)ad.pos;
+ while(todo>0) {
+ todo-=ad.is.skip(todo);
+ }
+ ad.pos=bytes;
+ } else if (bytes<(int)ad.pos) {
+
+ ad.is=am.open(ad.path);
+
+ ad.pos=bytes;
+ int todo=bytes;
+ while(todo>0) {
+ todo-=ad.is.skip(todo);
+ }
+ }
+
+ ad.eof=false;
+ } catch (IOException e) {
+
+ System.out.printf("Exception on file_seek: %s\n",e);
+ return;
+ }
+
+
+ }
+
+ public int file_tell(int id) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_read: Can't tell eof for invalid file id: %d\n",id);
+ return 0;
+ }
+
+ AssetData ad = streams.get(id);
+ return ad.pos;
+ }
+ public boolean file_eof(int id) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_read: Can't check eof for invalid file id: %d\n",id);
+ return false;
+ }
+
+ AssetData ad = streams.get(id);
+ return ad.eof;
+ }
+
+ public byte[] file_read(int id, int bytes) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_read: Can't read invalid file id: %d\n",id);
+ return new byte[0];
+ }
+
+
+ AssetData ad = streams.get(id);
+
+ if (ad.pos + bytes > ad.len) {
+
+ bytes=ad.len-ad.pos;
+ ad.eof=true;
+ }
+
+
+ if (bytes==0) {
+
+ return new byte[0];
+ }
+
+
+
+ byte[] buf1=new byte[bytes];
+ int r=0;
+ try {
+ r = ad.is.read(buf1);
+ } catch (IOException e) {
+
+ System.out.printf("Exception on file_read: %s\n",e);
+ return new byte[bytes];
+ }
+
+ if (r==0) {
+ return new byte[0];
+ }
+
+ ad.pos+=r;
+
+ if (r<bytes) {
+
+ byte[] buf2=new byte[r];
+ for(int i=0;i<r;i++)
+ buf2[i]=buf1[i];
+ return buf2;
+ } else {
+
+ return buf1;
+ }
+
+ }
+
+ public void file_close(int id) {
+
+ if (!streams.containsKey(id)) {
+ System.out.printf("file_close: Can't close invalid file id: %d\n",id);
+ return;
+ }
+
+ streams.remove(id);
+
+ }
+
+
+ /////////////////////////
+ /// DIRECTORIES
+ /////////////////////////
+
+
+ class AssetDir {
+
+ public String[] files;
+ public int current;
+ public String path;
+ }
+
+ public int last_dir_id=1;
+
+ HashMap<Integer,AssetDir> dirs;
+
+ public int dir_open(String path) {
+
+ AssetDir ad = new AssetDir();
+ ad.current=0;
+ ad.path=path;
+
+ try {
+ ad.files = am.list(path);
+ } catch (IOException e) {
+
+ System.out.printf("Exception on dir_open: %s\n",e);
+ return -1;
+ }
+
+ //System.out.printf("Opened dir: %s\n",path);
+ ++last_dir_id;
+ dirs.put(last_dir_id,ad);
+
+ return last_dir_id;
+
+ }
+
+ public boolean dir_is_dir(int id) {
+ if (!dirs.containsKey(id)) {
+ System.out.printf("dir_next: invalid dir id: %d\n",id);
+ return false;
+ }
+ AssetDir ad = dirs.get(id);
+ //System.out.printf("go next: %d,%d\n",ad.current,ad.files.length);
+ int idx = ad.current;
+ if (idx>0)
+ idx--;
+
+ if (idx>=ad.files.length)
+ return false;
+ String fname = ad.files[idx];
+
+ try {
+ if (ad.path.equals(""))
+ am.open(fname);
+ else
+ am.open(ad.path+"/"+fname);
+ return false;
+ } catch (Exception e) {
+ return true;
+ }
+ }
+
+ public String dir_next(int id) {
+
+ if (!dirs.containsKey(id)) {
+ System.out.printf("dir_next: invalid dir id: %d\n",id);
+ return "";
+ }
+
+ AssetDir ad = dirs.get(id);
+ //System.out.printf("go next: %d,%d\n",ad.current,ad.files.length);
+
+ if (ad.current>=ad.files.length) {
+ ad.current++;
+ return "";
+ }
+ String r = ad.files[ad.current];
+ ad.current++;
+ return r;
+
+ }
+
+ public void dir_close(int id) {
+
+ if (!dirs.containsKey(id)) {
+ System.out.printf("dir_close: invalid dir id: %d\n",id);
+ return;
+ }
+
+ dirs.remove(id);
+ }
+
+
+
+ GodotIO(Godot p_activity) {
+
+ am=p_activity.getAssets();
+ activity=p_activity;
+ streams=new HashMap<Integer,AssetData>();
+ dirs=new HashMap<Integer,AssetDir>();
+ applicationContext = activity.getApplicationContext();
+
+ }
+
+
+ /////////////////////////
+ // AUDIO
+ /////////////////////////
+
+ private Object buf;
+ private Thread mAudioThread;
+ private AudioTrack mAudioTrack;
+
+ public Object audioInit(int sampleRate, int desiredFrames) {
+ int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
+ int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
+ int frameSize = 4;
+
+ System.out.printf("audioInit: initializing audio:\n");
+
+ //Log.v("Godot", "Godot audio: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + ((float)sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer");
+
+ // Let the user pick a larger buffer if they really want -- but ye
+ // gods they probably shouldn't, the minimums are horrifyingly high
+ // latency already
+ desiredFrames = Math.max(desiredFrames, (AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
+
+ mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
+ channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM);
+
+ audioStartThread();
+
+ //Log.v("Godot", "Godot audio: got " + ((mAudioTrack.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioTrack.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + ((float)mAudioTrack.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer");
+
+ buf = new short[desiredFrames * 2];
+ return buf;
+ }
+
+ public void audioStartThread() {
+ mAudioThread = new Thread(new Runnable() {
+ public void run() {
+ mAudioTrack.play();
+ GodotLib.audio();
+ }
+ });
+
+ // I'd take REALTIME if I could get it!
+ mAudioThread.setPriority(Thread.MAX_PRIORITY);
+ mAudioThread.start();
+ }
+
+ public void audioWriteShortBuffer(short[] buffer) {
+ for (int i = 0; i < buffer.length; ) {
+ int result = mAudioTrack.write(buffer, i, buffer.length - i);
+ if (result > 0) {
+ i += result;
+ } else if (result == 0) {
+ try {
+ Thread.sleep(1);
+ } catch(InterruptedException e) {
+ // Nom nom
+ }
+ } else {
+ Log.w("Godot", "Godot audio: error return from write(short)");
+ return;
+ }
+ }
+ }
+
+
+
+ public void audioQuit() {
+ if (mAudioThread != null) {
+ try {
+ mAudioThread.join();
+ } catch(Exception e) {
+ Log.v("Godot", "Problem stopping audio thread: " + e);
+ }
+ mAudioThread = null;
+
+ //Log.v("Godot", "Finished waiting for audio thread");
+ }
+
+ if (mAudioTrack != null) {
+ mAudioTrack.stop();
+ mAudioTrack = null;
+ }
+ }
+
+ public void audioPause(boolean p_pause) {
+
+ if (p_pause)
+ mAudioTrack.pause();
+ else
+ mAudioTrack.play();
+ }
+
+ /////////////////////////
+ // MISCELANEOUS OS IO
+ /////////////////////////
+
+
+
+ public int openURI(String p_uri) {
+
+ try {
+ Log.v("MyApp", "TRYING TO OPEN URI: " + p_uri);
+ String path = p_uri;
+ String type="";
+ if (path.startsWith("/")) {
+ //absolute path to filesystem, prepend file://
+ path="file://"+path;
+ if (p_uri.endsWith(".png") || p_uri.endsWith(".jpg") || p_uri.endsWith(".gif") || p_uri.endsWith(".webp")) {
+
+ type="image/*";
+ }
+ }
+
+ Intent intent = new Intent();
+ intent.setAction(Intent.ACTION_VIEW);
+ if (!type.equals("")) {
+ intent.setDataAndType(Uri.parse(path), type);
+ } else {
+ intent.setData(Uri.parse(path));
+ }
+
+ activity.startActivity(intent);
+ return 0;
+ } catch (ActivityNotFoundException e) {
+
+ return 1;
+ }
+ }
+
+ public String getDataDir() {
+
+ return activity.getFilesDir().getAbsolutePath();
+ }
+
+ public String getLocale() {
+
+ return Locale.getDefault().toString();
+ }
+
+ public String getModel() {
+ return Build.MODEL;
+ }
+
+ public boolean needsReloadHooks() {
+
+ return android.os.Build.VERSION.SDK_INT < 11;
+ }
+
+ public void showKeyboard(String p_existing_text) {
+ if(edit != null)
+ edit.showKeyboard(p_existing_text);
+
+ //InputMethodManager inputMgr = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE);
+ //inputMgr.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
+ };
+
+ public void hideKeyboard() {
+ if(edit != null)
+ edit.hideKeyboard();
+
+ InputMethodManager inputMgr = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE);
+ View v = activity.getCurrentFocus();
+ if (v != null) {
+ inputMgr.hideSoftInputFromWindow(v.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
+ } else {
+ inputMgr.hideSoftInputFromWindow(new View(activity).getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
+ }
+ };
+
+ public void setScreenOrientation(int p_orientation) {
+
+ switch(p_orientation) {
+
+ case SCREEN_LANDSCAPE: {
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+ } break;
+ case SCREEN_PORTRAIT: {
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+ } break;
+ case SCREEN_REVERSE_LANDSCAPE: {
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
+ } break;
+ case SCREEN_REVERSE_PORTRAIT: {
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);
+ } break;
+ case SCREEN_SENSOR_LANDSCAPE: {
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
+ } break;
+ case SCREEN_SENSOR_PORTRAIT: {
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
+ } break;
+ case SCREEN_SENSOR: {
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR);
+ } break;
+
+ }
+ };
+
+ public void setEdit(GodotEditText _edit) {
+ edit = _edit;
+ }
+
+ public void playVideo(String p_path)
+ {
+ Uri filePath = Uri.parse(p_path);
+ mediaPlayer = new MediaPlayer();
+
+ try {
+ mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
+ mediaPlayer.setDataSource(applicationContext, filePath);
+ mediaPlayer.prepare();
+ mediaPlayer.start();
+ }
+ catch(IOException e)
+ {
+ System.out.println("IOError while playing video");
+ }
+ }
+
+ public boolean isVideoPlaying() {
+ if (mediaPlayer != null) {
+ return mediaPlayer.isPlaying();
+ }
+ return false;
+ }
+
+ public void pauseVideo() {
+ if (mediaPlayer != null) {
+ mediaPlayer.pause();
+ }
+ }
+
+ public void stopVideo() {
+ if (mediaPlayer != null) {
+ mediaPlayer.release();
+ mediaPlayer = null;
+ }
+ }
+
+
+ public static final int SYSTEM_DIR_DESKTOP=0;
+ public static final int SYSTEM_DIR_DCIM=1;
+ public static final int SYSTEM_DIR_DOCUMENTS=2;
+ public static final int SYSTEM_DIR_DOWNLOADS=3;
+ public static final int SYSTEM_DIR_MOVIES=4;
+ public static final int SYSTEM_DIR_MUSIC=5;
+ public static final int SYSTEM_DIR_PICTURES=6;
+ public static final int SYSTEM_DIR_RINGTONES=7;
+
+
+ public String getSystemDir(int idx) {
+
+ String what="";
+ switch(idx) {
+ case SYSTEM_DIR_DESKTOP: {
+ //what=Environment.DIRECTORY_DOCUMENTS;
+ what=Environment.DIRECTORY_DOWNLOADS;
+ } break;
+ case SYSTEM_DIR_DCIM: {
+ what=Environment.DIRECTORY_DCIM;
+
+ } break;
+ case SYSTEM_DIR_DOCUMENTS: {
+ what=Environment.DIRECTORY_DOWNLOADS;
+ //what=Environment.DIRECTORY_DOCUMENTS;
+ } break;
+ case SYSTEM_DIR_DOWNLOADS: {
+ what=Environment.DIRECTORY_DOWNLOADS;
+
+ } break;
+ case SYSTEM_DIR_MOVIES: {
+ what=Environment.DIRECTORY_MOVIES;
+
+ } break;
+ case SYSTEM_DIR_MUSIC: {
+ what=Environment.DIRECTORY_MUSIC;
+ } break;
+ case SYSTEM_DIR_PICTURES: {
+ what=Environment.DIRECTORY_PICTURES;
+ } break;
+ case SYSTEM_DIR_RINGTONES: {
+ what=Environment.DIRECTORY_RINGTONES;
+
+ } break;
+ }
+
+ if (what.equals(""))
+ return "";
+ return Environment.getExternalStoragePublicDirectory(what).getAbsolutePath();
+ }
+
+ protected static final String PREFS_FILE = "device_id.xml";
+ protected static final String PREFS_DEVICE_ID = "device_id";
+
+ public static String unique_id="";
+ public String getUniqueID() {
+
+ return unique_id;
+ }
+
+}
diff --git a/platform/android/java/src/org/godotengine/godot/GodotLib.java b/platform/android/java/src/org/godotengine/godot/GodotLib.java
new file mode 100644
index 0000000000..aef6591864
--- /dev/null
+++ b/platform/android/java/src/org/godotengine/godot/GodotLib.java
@@ -0,0 +1,66 @@
+/*************************************************************************/
+/* GodotLib.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
+package org.godotengine.godot;
+
+// Wrapper for native library
+
+public class GodotLib {
+
+
+ public static GodotIO io;
+
+ static {
+ System.loadLibrary("godot_android");
+ }
+
+ /**
+ * @param width the current view width
+ * @param height the current view height
+ */
+
+ public static native void initialize(Godot p_instance,boolean need_reload_hook,String[] p_cmdline,Object p_asset_manager);
+ public static native void resize(int width, int height,boolean reload);
+ public static native void newcontext(boolean p_32_bits);
+ public static native void quit();
+ public static native void step();
+ public static native void touch(int what,int pointer,int howmany, int[] arr);
+ public static native void accelerometer(float x, float y, float z);
+ public static native void key(int p_scancode, int p_unicode_char, boolean p_pressed);
+ public static native void joybutton(int p_device, int p_but, boolean p_pressed);
+ public static native void joyaxis(int p_device, int p_axis, float p_value);
+ public static native void focusin();
+ public static native void focusout();
+ public static native void audio();
+ public static native void singleton(String p_name,Object p_object);
+ public static native void method(String p_sname,String p_name,String p_ret,String[] p_params);
+ public static native String getGlobal(String p_key);
+ public static native void callobject(int p_ID, String p_method, Object[] p_params);
+ public static native void calldeferred(int p_ID, String p_method, Object[] p_params);
+
+}
diff --git a/platform/android/java/src/org/godotengine/godot/GodotPaymentV3.java b/platform/android/java/src/org/godotengine/godot/GodotPaymentV3.java
new file mode 100644
index 0000000000..6bec49410d
--- /dev/null
+++ b/platform/android/java/src/org/godotengine/godot/GodotPaymentV3.java
@@ -0,0 +1,154 @@
+package org.godotengine.godot;
+
+import org.godotengine.godot.Dictionary;
+import android.app.Activity;
+import android.util.Log;
+
+
+public class GodotPaymentV3 extends Godot.SingletonBase {
+
+ private Godot activity;
+
+ private Integer purchaseCallbackId = 0;
+
+ private String accessToken;
+
+ private String purchaseValidationUrlPrefix;
+
+ private String transactionId;
+
+ public void purchase( String _sku, String _transactionId) {
+ final String sku = _sku;
+ final String transactionId = _transactionId;
+ activity.getPaymentsManager().setBaseSingleton(this);
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ activity.getPaymentsManager().requestPurchase(sku, transactionId);
+ }
+ });
+ }
+
+/* public string requestPurchasedTicket(){
+ activity.getPaymentsManager()
+ }
+
+*/
+ static public Godot.SingletonBase initialize(Activity p_activity) {
+
+ return new GodotPaymentV3(p_activity);
+ }
+
+
+ public GodotPaymentV3(Activity p_activity) {
+
+ registerClass("GodotPayments", new String[] {"purchase", "setPurchaseCallbackId", "setPurchaseValidationUrlPrefix", "setTransactionId", "getSignature", "consumeUnconsumedPurchases", "requestPurchased", "setAutoConsume", "consume"});
+ activity=(Godot) p_activity;
+ }
+
+ public void consumeUnconsumedPurchases(){
+ activity.getPaymentsManager().setBaseSingleton(this);
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ activity.getPaymentsManager().consumeUnconsumedPurchases();
+ }
+ });
+ }
+
+ private String signature;
+ public String getSignature(){
+ return this.signature;
+ }
+
+
+ public void callbackSuccess(String ticket, String signature, String sku){
+// Log.d(this.getClass().getName(), "PRE-Send callback to purchase success");
+ GodotLib.callobject(purchaseCallbackId, "purchase_success", new Object[]{ticket, signature, sku});
+// Log.d(this.getClass().getName(), "POST-Send callback to purchase success");
+}
+
+ public void callbackSuccessProductMassConsumed(String ticket, String signature, String sku){
+// Log.d(this.getClass().getName(), "PRE-Send callback to consume success");
+ Log.d(this.getClass().getName(), "callbackSuccessProductMassConsumed > "+ticket+","+signature+","+sku);
+ GodotLib.calldeferred(purchaseCallbackId, "consume_success", new Object[]{ticket, signature, sku});
+// Log.d(this.getClass().getName(), "POST-Send callback to consume success");
+ }
+
+ public void callbackSuccessNoUnconsumedPurchases(){
+ GodotLib.calldeferred(purchaseCallbackId, "no_validation_required", new Object[]{});
+ }
+
+ public void callbackFail(){
+ GodotLib.calldeferred(purchaseCallbackId, "purchase_fail", new Object[]{});
+// GodotLib.callobject(purchaseCallbackId, "purchase_fail", new Object[]{});
+ }
+
+ public void callbackCancel(){
+ GodotLib.calldeferred(purchaseCallbackId, "purchase_cancel", new Object[]{});
+// GodotLib.callobject(purchaseCallbackId, "purchase_cancel", new Object[]{});
+ }
+
+ public void callbackAlreadyOwned(String sku){
+ GodotLib.calldeferred(purchaseCallbackId, "purchase_owned", new Object[]{sku});
+ }
+
+ public int getPurchaseCallbackId() {
+ return purchaseCallbackId;
+ }
+
+ public void setPurchaseCallbackId(int purchaseCallbackId) {
+ this.purchaseCallbackId = purchaseCallbackId;
+ }
+
+ public String getPurchaseValidationUrlPrefix(){
+ return this.purchaseValidationUrlPrefix ;
+ }
+
+ public void setPurchaseValidationUrlPrefix(String url){
+ this.purchaseValidationUrlPrefix = url;
+ }
+
+ public String getAccessToken() {
+ return accessToken;
+ }
+
+ public void setAccessToken(String accessToken) {
+ this.accessToken = accessToken;
+ }
+
+ public void setTransactionId(String transactionId){
+ this.transactionId = transactionId;
+ }
+
+ public String getTransactionId(){
+ return this.transactionId;
+ }
+
+ // request purchased items are not consumed
+ public void requestPurchased(){
+ activity.getPaymentsManager().setBaseSingleton(this);
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ activity.getPaymentsManager().requestPurchased();
+ }
+ });
+ }
+
+ // callback for requestPurchased()
+ public void callbackPurchased(String receipt, String signature, String sku){
+ GodotLib.calldeferred(purchaseCallbackId, "has_purchased", new Object[]{receipt, signature, sku});
+ }
+
+ // consume item automatically after purchase. default is true.
+ public void setAutoConsume(boolean autoConsume){
+ activity.getPaymentsManager().setAutoConsume(autoConsume);
+ }
+
+ // consume a specific item
+ public void consume(String sku){
+ activity.getPaymentsManager().consume(sku);
+ }
+}
+
diff --git a/platform/android/java/src/org/godotengine/godot/GodotView.java b/platform/android/java/src/org/godotengine/godot/GodotView.java
new file mode 100644
index 0000000000..492eb4cb54
--- /dev/null
+++ b/platform/android/java/src/org/godotengine/godot/GodotView.java
@@ -0,0 +1,661 @@
+/*************************************************************************/
+/* GodotView.java */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
+package org.godotengine.godot;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.opengl.GLSurfaceView;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.content.ContextWrapper;
+import android.view.InputDevice;
+
+import java.io.File;
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * A simple GLSurfaceView sub-class that demonstrate how to perform
+ * OpenGL ES 2.0 rendering into a GL Surface. Note the following important
+ * details:
+ *
+ * - The class must use a custom context factory to enable 2.0 rendering.
+ * See ContextFactory class definition below.
+ *
+ * - The class must use a custom EGLConfigChooser to be able to select
+ * an EGLConfig that supports 2.0. This is done by providing a config
+ * specification to eglChooseConfig() that has the attribute
+ * EGL10.ELG_RENDERABLE_TYPE containing the EGL_OPENGL_ES2_BIT flag
+ * set. See ConfigChooser class definition below.
+ *
+ * - The class must select the surface's format, then choose an EGLConfig
+ * that matches it exactly (with regards to red/green/blue/alpha channels
+ * bit depths). Failure to do so would result in an EGL_BAD_MATCH error.
+ */
+public class GodotView extends GLSurfaceView {
+
+ private static String TAG = "GodotView";
+ private static final boolean DEBUG = false;
+ private static Context ctx;
+
+ private static GodotIO io;
+ private static boolean firsttime=true;
+ private static boolean use_gl2=false;
+ private static boolean use_32=false;
+
+ private Godot activity;
+
+ public GodotView(Context context,GodotIO p_io,boolean p_use_gl2, boolean p_use_32_bits, Godot p_activity) {
+ super(context);
+ ctx=context;
+ io=p_io;
+ use_gl2=p_use_gl2;
+ use_32=p_use_32_bits;
+
+ activity = p_activity;
+
+ if (!p_io.needsReloadHooks()) {
+ //will only work on SDK 11+!!
+ setPreserveEGLContextOnPause(true);
+ }
+
+ init(false, 16, 0);
+ }
+
+ public GodotView(Context context, boolean translucent, int depth, int stencil) {
+ super(context);
+ init(translucent, depth, stencil);
+ }
+
+ @Override public boolean onTouchEvent (MotionEvent event) {
+
+ return activity.gotTouchEvent(event);
+ };
+
+ public int get_godot_button(int keyCode) {
+
+ int button = 0;
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_BUTTON_A: // Android A is SNES B
+ button = 0;
+ break;
+ case KeyEvent.KEYCODE_BUTTON_B:
+ button = 1;
+ break;
+ case KeyEvent.KEYCODE_BUTTON_X: // Android X is SNES Y
+ button = 2;
+ break;
+ case KeyEvent.KEYCODE_BUTTON_Y:
+ button = 3;
+ break;
+ case KeyEvent.KEYCODE_BUTTON_L1:
+ button = 4;
+ break;
+ case KeyEvent.KEYCODE_BUTTON_L2:
+ button = 6;
+ break;
+ case KeyEvent.KEYCODE_BUTTON_R1:
+ button = 5;
+ break;
+ case KeyEvent.KEYCODE_BUTTON_R2:
+ button = 7;
+ break;
+ case KeyEvent.KEYCODE_BUTTON_SELECT:
+ button = 10;
+ break;
+ case KeyEvent.KEYCODE_BUTTON_START:
+ button = 11;
+ break;
+ case KeyEvent.KEYCODE_BUTTON_THUMBL:
+ button = 8;
+ break;
+ case KeyEvent.KEYCODE_BUTTON_THUMBR:
+ button = 9;
+ break;
+ case KeyEvent.KEYCODE_DPAD_UP:
+ button = 12;
+ break;
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ button = 13;
+ break;
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ button = 14;
+ break;
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ button = 15;
+ break;
+
+ default:
+ button = keyCode - KeyEvent.KEYCODE_BUTTON_1;
+ break;
+ };
+
+ return button;
+ };
+
+ @Override public boolean onKeyUp(int keyCode, KeyEvent event) {
+
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ return true;
+ }
+
+ if (keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
+ return super.onKeyUp(keyCode, event);
+ };
+
+ int source = event.getSource();
+ if ((source & InputDevice.SOURCE_JOYSTICK) != 0 || (source & InputDevice.SOURCE_DPAD) != 0 || (source & InputDevice.SOURCE_GAMEPAD) != 0) {
+
+ int button = get_godot_button(keyCode);
+ int device = event.getDeviceId();
+
+ GodotLib.joybutton(device, button, false);
+ return true;
+ } else {
+
+ GodotLib.key(keyCode, event.getUnicodeChar(0), false);
+ };
+ return super.onKeyUp(keyCode, event);
+ };
+
+ @Override public boolean onKeyDown(int keyCode, KeyEvent event) {
+
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ GodotLib.quit();
+ // press 'back' button should not terminate program
+ // normal handle 'back' event in game logic
+ return true;
+ }
+
+ if (keyCode == KeyEvent.KEYCODE_VOLUME_UP || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
+ return super.onKeyDown(keyCode, event);
+ };
+
+ int source = event.getSource();
+ //Log.e(TAG, String.format("Key down! source %d, device %d, joystick %d, %d, %d", event.getDeviceId(), source, (source & InputDevice.SOURCE_JOYSTICK), (source & InputDevice.SOURCE_DPAD), (source & InputDevice.SOURCE_GAMEPAD)));
+
+ if ((source & InputDevice.SOURCE_JOYSTICK) != 0 || (source & InputDevice.SOURCE_DPAD) != 0 || (source & InputDevice.SOURCE_GAMEPAD) != 0) {
+
+ if (event.getRepeatCount() > 0) // ignore key echo
+ return true;
+ int button = get_godot_button(keyCode);
+ int device = event.getDeviceId();
+ //Log.e(TAG, String.format("joy button down! button %x, %d, device %d", keyCode, button, device));
+
+ GodotLib.joybutton(device, button, true);
+ return true;
+
+ } else {
+ GodotLib.key(keyCode, event.getUnicodeChar(0), true);
+ };
+ return super.onKeyDown(keyCode, event);
+ }
+
+ public float axis_value(MotionEvent p_event, InputDevice p_device, int p_axis, int p_pos) {
+
+ final InputDevice.MotionRange range = p_device.getMotionRange(p_axis, p_event.getSource());
+ if (range == null)
+ return 0;
+
+ //Log.e(TAG, String.format("axis ranges %f, %f, %f", range.getRange(), range.getMin(), range.getMax()));
+
+ final float flat = range.getFlat();
+ final float value =
+ p_pos < 0 ? p_event.getAxisValue(p_axis):
+ p_event.getHistoricalAxisValue(p_axis, p_pos);
+
+ final float absval = Math.abs(value);
+ if (absval <= flat) {
+ return 0;
+ };
+
+ final float ret = (value - range.getMin()) / range.getRange() * 2 - 1.0f;
+
+ return ret;
+ };
+
+ float[] last_axis_values = { 0, 0, 0, 0, -1, -1 };
+ boolean[] last_axis_buttons = { false, false, false, false, false, false }; // dpad up down left right, ltrigger, rtrigger
+
+ public void process_axis_state(MotionEvent p_event, int p_pos) {
+
+ int device_id = p_event.getDeviceId();
+ InputDevice device = p_event.getDevice();
+ float val;
+
+ val = axis_value(p_event, device, MotionEvent.AXIS_X, p_pos);
+ if (val != last_axis_values[0]) {
+ last_axis_values[0] = val;
+ //Log.e(TAG, String.format("axis moved! axis %d, value %f", 0, val));
+ GodotLib.joyaxis(device_id, 0, val);
+ };
+
+ val = axis_value(p_event, device, MotionEvent.AXIS_Y, p_pos);
+ if (val != last_axis_values[1]) {
+ last_axis_values[1] = val;
+ //Log.e(TAG, String.format("axis moved! axis %d, value %f", 1, val));
+ GodotLib.joyaxis(device_id, 1, val);
+ };
+
+ val = axis_value(p_event, device, MotionEvent.AXIS_Z, p_pos);
+ if (val != last_axis_values[2]) {
+ last_axis_values[2] = val;
+ //Log.e(TAG, String.format("axis moved! axis %d, value %f", 2, val));
+ GodotLib.joyaxis(device_id, 2, val);
+ };
+
+ val = axis_value(p_event, device, MotionEvent.AXIS_RZ, p_pos);
+ if (val != last_axis_values[3]) {
+ last_axis_values[3] = val;
+ //Log.e(TAG, String.format("axis moved! axis %d, value %f", 3, val));
+ GodotLib.joyaxis(device_id, 3, val);
+ };
+
+ val = axis_value(p_event, device, MotionEvent.AXIS_LTRIGGER, p_pos);
+ if (val != last_axis_values[4]) {
+ last_axis_values[4] = val;
+ if ((val != 0) != (last_axis_buttons[4])) {
+ last_axis_buttons[4] = (val != 0);
+ GodotLib.joybutton(device_id, 6, (val != 0));
+ };
+ };
+
+ val = axis_value(p_event, device, MotionEvent.AXIS_RTRIGGER, p_pos);
+ if (val != last_axis_values[5]) {
+ last_axis_values[5] = val;
+ if ((val != 0) != (last_axis_buttons[5])) {
+ last_axis_buttons[5] = (val != 0);
+ GodotLib.joybutton(device_id, 7, (val != 0));
+ };
+ };
+
+ val = axis_value(p_event, device, MotionEvent.AXIS_HAT_Y, p_pos);
+
+ if (last_axis_buttons[0] != (val > 0)) {
+ last_axis_buttons[0] = val > 0;
+ GodotLib.joybutton(device_id, 12, val > 0);
+ };
+ if (last_axis_buttons[1] != (val < 0)) {
+ last_axis_buttons[1] = val < 0;
+ GodotLib.joybutton(device_id, 13, val > 0);
+ };
+
+ val = axis_value(p_event, device, MotionEvent.AXIS_HAT_X, p_pos);
+ if (last_axis_buttons[2] != (val < 0)) {
+ last_axis_buttons[2] = val < 0;
+ GodotLib.joybutton(device_id, 14, val < 0);
+ };
+ if (last_axis_buttons[3] != (val > 0)) {
+ last_axis_buttons[3] = val > 0;
+ GodotLib.joybutton(device_id, 15, val > 0);
+ };
+ };
+
+ @Override public boolean onGenericMotionEvent(MotionEvent event) {
+
+ if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK && event.getAction() == MotionEvent.ACTION_MOVE) {
+
+ // Process all historical movement samples in the batch
+ final int historySize = event.getHistorySize();
+
+ // Process the movements starting from the
+ // earliest historical position in the batch
+ for (int i = 0; i < historySize; i++) {
+ // Process the event at historical position i
+ process_axis_state(event, i);
+ }
+
+ // Process the current movement sample in the batch (position -1)
+ process_axis_state(event, -1);
+ return true;
+
+
+ };
+
+ return super.onGenericMotionEvent(event);
+ };
+
+
+ private void init(boolean translucent, int depth, int stencil) {
+
+ this.setFocusableInTouchMode(true);
+ /* By default, GLSurfaceView() creates a RGB_565 opaque surface.
+ * If we want a translucent one, we should change the surface's
+ * format here, using PixelFormat.TRANSLUCENT for GL Surfaces
+ * is interpreted as any 32-bit surface with alpha by SurfaceFlinger.
+ */
+ if (translucent) {
+ this.getHolder().setFormat(PixelFormat.TRANSLUCENT);
+ }
+
+ /* Setup the context factory for 2.0 rendering.
+ * See ContextFactory class definition below
+ */
+ setEGLContextFactory(new ContextFactory());
+
+ /* We need to choose an EGLConfig that matches the format of
+ * our surface exactly. This is going to be done in our
+ * custom config chooser. See ConfigChooser class definition
+ * below.
+ */
+
+ if (use_32) {
+ setEGLConfigChooser( translucent ?
+ new FallbackConfigChooser(8, 8, 8, 8, 24, stencil, new ConfigChooser(8, 8, 8, 8, 16, stencil)) :
+ new FallbackConfigChooser(8, 8, 8, 8, 24, stencil, new ConfigChooser(5, 6, 5, 0, 16, stencil)) );
+
+ } else {
+ setEGLConfigChooser( translucent ?
+ new ConfigChooser(8, 8, 8, 8, 16, stencil) :
+ new ConfigChooser(5, 6, 5, 0, 16, stencil) );
+ }
+
+ /* Set the renderer responsible for frame rendering */
+ setRenderer(new Renderer());
+ }
+
+ private static class ContextFactory implements GLSurfaceView.EGLContextFactory {
+ private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+ public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) {
+ if (use_gl2)
+ Log.w(TAG, "creating OpenGL ES 2.0 context :");
+ else
+ Log.w(TAG, "creating OpenGL ES 1.1 context :");
+
+ checkEglError("Before eglCreateContext", egl);
+ int[] attrib_list2 = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
+ EGLContext context = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, use_gl2?attrib_list2:null);
+ checkEglError("After eglCreateContext", egl);
+ return context;
+ }
+
+ public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context) {
+ egl.eglDestroyContext(display, context);
+ }
+ }
+
+ private static void checkEglError(String prompt, EGL10 egl) {
+ int error;
+ while ((error = egl.eglGetError()) != EGL10.EGL_SUCCESS) {
+ Log.e(TAG, String.format("%s: EGL error: 0x%x", prompt, error));
+ }
+ }
+ /* Fallback if 32bit View is not supported*/
+ private static class FallbackConfigChooser extends ConfigChooser {
+ private ConfigChooser fallback;
+
+ public FallbackConfigChooser(int r, int g, int b, int a, int depth, int stencil, ConfigChooser fallback) {
+ super(r, g, b, a, depth, stencil);
+ this.fallback = fallback;
+ }
+
+ @Override
+ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs) {
+ EGLConfig ec = super.chooseConfig(egl, display, configs);
+ if (ec == null) {
+ Log.w(TAG, "Trying ConfigChooser fallback");
+ ec = fallback.chooseConfig(egl, display, configs);
+ use_32=false;
+ }
+ return ec;
+ }
+ }
+
+ private static class ConfigChooser implements GLSurfaceView.EGLConfigChooser {
+
+ public ConfigChooser(int r, int g, int b, int a, int depth, int stencil) {
+ mRedSize = r;
+ mGreenSize = g;
+ mBlueSize = b;
+ mAlphaSize = a;
+ mDepthSize = depth;
+ mStencilSize = stencil;
+ }
+
+ /* This EGL config specification is used to specify 2.0 rendering.
+ * We use a minimum size of 4 bits for red/green/blue, but will
+ * perform actual matching in chooseConfig() below.
+ */
+ private static int EGL_OPENGL_ES2_BIT = 4;
+ private static int[] s_configAttribs2 =
+ {
+ EGL10.EGL_RED_SIZE, 4,
+ EGL10.EGL_GREEN_SIZE, 4,
+ EGL10.EGL_BLUE_SIZE, 4,
+ // EGL10.EGL_DEPTH_SIZE, 16,
+ // EGL10.EGL_STENCIL_SIZE, EGL10.EGL_DONT_CARE,
+ EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL10.EGL_NONE
+ };
+ private static int[] s_configAttribs =
+ {
+ EGL10.EGL_RED_SIZE, 4,
+ EGL10.EGL_GREEN_SIZE, 4,
+ EGL10.EGL_BLUE_SIZE, 4,
+ // EGL10.EGL_DEPTH_SIZE, 16,
+ // EGL10.EGL_STENCIL_SIZE, EGL10.EGL_DONT_CARE,
+ EGL10.EGL_NONE
+ };
+
+ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
+
+ /* Get the number of minimally matching EGL configurations
+ */
+ int[] num_config = new int[1];
+ egl.eglChooseConfig(display, use_gl2?s_configAttribs2:s_configAttribs, null, 0, num_config);
+
+ int numConfigs = num_config[0];
+
+ if (numConfigs <= 0) {
+ throw new IllegalArgumentException("No configs match configSpec");
+ }
+
+ /* Allocate then read the array of minimally matching EGL configs
+ */
+ EGLConfig[] configs = new EGLConfig[numConfigs];
+ egl.eglChooseConfig(display, use_gl2?s_configAttribs2:s_configAttribs, configs, numConfigs, num_config);
+
+ if (DEBUG) {
+ printConfigs(egl, display, configs);
+ }
+ /* Now return the "best" one
+ */
+ return chooseConfig(egl, display, configs);
+ }
+
+ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
+ EGLConfig[] configs) {
+ for(EGLConfig config : configs) {
+ int d = findConfigAttrib(egl, display, config,
+ EGL10.EGL_DEPTH_SIZE, 0);
+ int s = findConfigAttrib(egl, display, config,
+ EGL10.EGL_STENCIL_SIZE, 0);
+
+ // We need at least mDepthSize and mStencilSize bits
+ if (d < mDepthSize || s < mStencilSize)
+ continue;
+
+ // We want an *exact* match for red/green/blue/alpha
+ int r = findConfigAttrib(egl, display, config,
+ EGL10.EGL_RED_SIZE, 0);
+ int g = findConfigAttrib(egl, display, config,
+ EGL10.EGL_GREEN_SIZE, 0);
+ int b = findConfigAttrib(egl, display, config,
+ EGL10.EGL_BLUE_SIZE, 0);
+ int a = findConfigAttrib(egl, display, config,
+ EGL10.EGL_ALPHA_SIZE, 0);
+
+ if (r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize)
+ return config;
+ }
+ return null;
+ }
+
+ private int findConfigAttrib(EGL10 egl, EGLDisplay display,
+ EGLConfig config, int attribute, int defaultValue) {
+
+ if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
+ return mValue[0];
+ }
+ return defaultValue;
+ }
+
+ private void printConfigs(EGL10 egl, EGLDisplay display,
+ EGLConfig[] configs) {
+ int numConfigs = configs.length;
+ Log.w(TAG, String.format("%d configurations", numConfigs));
+ for (int i = 0; i < numConfigs; i++) {
+ Log.w(TAG, String.format("Configuration %d:\n", i));
+ printConfig(egl, display, configs[i]);
+ }
+ }
+
+ private void printConfig(EGL10 egl, EGLDisplay display,
+ EGLConfig config) {
+ int[] attributes = {
+ EGL10.EGL_BUFFER_SIZE,
+ EGL10.EGL_ALPHA_SIZE,
+ EGL10.EGL_BLUE_SIZE,
+ EGL10.EGL_GREEN_SIZE,
+ EGL10.EGL_RED_SIZE,
+ EGL10.EGL_DEPTH_SIZE,
+ EGL10.EGL_STENCIL_SIZE,
+ EGL10.EGL_CONFIG_CAVEAT,
+ EGL10.EGL_CONFIG_ID,
+ EGL10.EGL_LEVEL,
+ EGL10.EGL_MAX_PBUFFER_HEIGHT,
+ EGL10.EGL_MAX_PBUFFER_PIXELS,
+ EGL10.EGL_MAX_PBUFFER_WIDTH,
+ EGL10.EGL_NATIVE_RENDERABLE,
+ EGL10.EGL_NATIVE_VISUAL_ID,
+ EGL10.EGL_NATIVE_VISUAL_TYPE,
+ 0x3030, // EGL10.EGL_PRESERVED_RESOURCES,
+ EGL10.EGL_SAMPLES,
+ EGL10.EGL_SAMPLE_BUFFERS,
+ EGL10.EGL_SURFACE_TYPE,
+ EGL10.EGL_TRANSPARENT_TYPE,
+ EGL10.EGL_TRANSPARENT_RED_VALUE,
+ EGL10.EGL_TRANSPARENT_GREEN_VALUE,
+ EGL10.EGL_TRANSPARENT_BLUE_VALUE,
+ 0x3039, // EGL10.EGL_BIND_TO_TEXTURE_RGB,
+ 0x303A, // EGL10.EGL_BIND_TO_TEXTURE_RGBA,
+ 0x303B, // EGL10.EGL_MIN_SWAP_INTERVAL,
+ 0x303C, // EGL10.EGL_MAX_SWAP_INTERVAL,
+ EGL10.EGL_LUMINANCE_SIZE,
+ EGL10.EGL_ALPHA_MASK_SIZE,
+ EGL10.EGL_COLOR_BUFFER_TYPE,
+ EGL10.EGL_RENDERABLE_TYPE,
+ 0x3042 // EGL10.EGL_CONFORMANT
+ };
+ String[] names = {
+ "EGL_BUFFER_SIZE",
+ "EGL_ALPHA_SIZE",
+ "EGL_BLUE_SIZE",
+ "EGL_GREEN_SIZE",
+ "EGL_RED_SIZE",
+ "EGL_DEPTH_SIZE",
+ "EGL_STENCIL_SIZE",
+ "EGL_CONFIG_CAVEAT",
+ "EGL_CONFIG_ID",
+ "EGL_LEVEL",
+ "EGL_MAX_PBUFFER_HEIGHT",
+ "EGL_MAX_PBUFFER_PIXELS",
+ "EGL_MAX_PBUFFER_WIDTH",
+ "EGL_NATIVE_RENDERABLE",
+ "EGL_NATIVE_VISUAL_ID",
+ "EGL_NATIVE_VISUAL_TYPE",
+ "EGL_PRESERVED_RESOURCES",
+ "EGL_SAMPLES",
+ "EGL_SAMPLE_BUFFERS",
+ "EGL_SURFACE_TYPE",
+ "EGL_TRANSPARENT_TYPE",
+ "EGL_TRANSPARENT_RED_VALUE",
+ "EGL_TRANSPARENT_GREEN_VALUE",
+ "EGL_TRANSPARENT_BLUE_VALUE",
+ "EGL_BIND_TO_TEXTURE_RGB",
+ "EGL_BIND_TO_TEXTURE_RGBA",
+ "EGL_MIN_SWAP_INTERVAL",
+ "EGL_MAX_SWAP_INTERVAL",
+ "EGL_LUMINANCE_SIZE",
+ "EGL_ALPHA_MASK_SIZE",
+ "EGL_COLOR_BUFFER_TYPE",
+ "EGL_RENDERABLE_TYPE",
+ "EGL_CONFORMANT"
+ };
+ int[] value = new int[1];
+ for (int i = 0; i < attributes.length; i++) {
+ int attribute = attributes[i];
+ String name = names[i];
+ if ( egl.eglGetConfigAttrib(display, config, attribute, value)) {
+ Log.w(TAG, String.format(" %s: %d\n", name, value[0]));
+ } else {
+ // Log.w(TAG, String.format(" %s: failed\n", name));
+ while (egl.eglGetError() != EGL10.EGL_SUCCESS);
+ }
+ }
+ }
+
+ // Subclasses can adjust these values:
+ protected int mRedSize;
+ protected int mGreenSize;
+ protected int mBlueSize;
+ protected int mAlphaSize;
+ protected int mDepthSize;
+ protected int mStencilSize;
+ private int[] mValue = new int[1];
+ }
+
+ private static class Renderer implements GLSurfaceView.Renderer {
+
+
+ public void onDrawFrame(GL10 gl) {
+ GodotLib.step();
+ for(int i=0;i<Godot.singleton_count;i++) {
+ Godot.singletons[i].onGLDrawFrame(gl);
+ }
+ }
+
+ public void onSurfaceChanged(GL10 gl, int width, int height) {
+
+ GodotLib.resize(width, height,!firsttime);
+ firsttime=false;
+ for(int i=0;i<Godot.singleton_count;i++) {
+ Godot.singletons[i].onGLSurfaceChanged(gl, width, height);
+ }
+ }
+
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ GodotLib.newcontext(use_32);
+ }
+ }
+}
diff --git a/platform/android/java/src/org/godotengine/godot/input/GodotEditText.java b/platform/android/java/src/org/godotengine/godot/input/GodotEditText.java
new file mode 100644
index 0000000000..c8ffa74ecd
--- /dev/null
+++ b/platform/android/java/src/org/godotengine/godot/input/GodotEditText.java
@@ -0,0 +1,133 @@
+package org.godotengine.godot.input;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.widget.EditText;
+import org.godotengine.godot.*;
+import android.os.Handler;
+import android.os.Message;
+import android.view.inputmethod.InputMethodManager;
+import android.view.inputmethod.EditorInfo;
+
+public class GodotEditText extends EditText {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+ private final static int HANDLER_OPEN_IME_KEYBOARD = 2;
+ private final static int HANDLER_CLOSE_IME_KEYBOARD = 3;
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+ private GodotView mView;
+ private GodotTextInputWrapper mInputWrapper;
+ private static Handler sHandler;
+ private String mOriginText;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+ public GodotEditText(final Context context) {
+ super(context);
+ this.initView();
+ }
+
+ public GodotEditText(final Context context, final AttributeSet attrs) {
+ super(context, attrs);
+ this.initView();
+ }
+
+ public GodotEditText(final Context context, final AttributeSet attrs, final int defStyle) {
+ super(context, attrs, defStyle);
+ this.initView();
+ }
+
+ protected void initView() {
+ this.setPadding(0, 0, 0, 0);
+ this.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);
+
+ sHandler = new Handler() {
+ @Override
+ public void handleMessage(final Message msg) {
+ switch (msg.what) {
+ case HANDLER_OPEN_IME_KEYBOARD:
+ {
+ GodotEditText edit = (GodotEditText) msg.obj;
+ String text = edit.mOriginText;
+ if (edit.requestFocus())
+ {
+ edit.removeTextChangedListener(edit.mInputWrapper);
+ edit.setText("");
+ edit.append(text);
+ edit.mInputWrapper.setOriginText(text);
+ edit.addTextChangedListener(edit.mInputWrapper);
+ final InputMethodManager imm = (InputMethodManager) mView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.showSoftInput(edit, 0);
+ }
+ }
+ break;
+
+ case HANDLER_CLOSE_IME_KEYBOARD:
+ {
+ GodotEditText edit = (GodotEditText) msg.obj;
+
+ edit.removeTextChangedListener(mInputWrapper);
+ final InputMethodManager imm = (InputMethodManager) mView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(edit.getWindowToken(), 0);
+ edit.mView.requestFocus();
+ }
+ break;
+ }
+ }
+ };
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+ public void setView(final GodotView view) {
+ this.mView = view;
+ if(mInputWrapper == null)
+ mInputWrapper = new GodotTextInputWrapper(mView, this);
+ this.setOnEditorActionListener(mInputWrapper);
+ view.requestFocus();
+ }
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+ @Override
+ public boolean onKeyDown(final int keyCode, final KeyEvent keyEvent) {
+ super.onKeyDown(keyCode, keyEvent);
+
+ /* Let GlSurfaceView get focus if back key is input. */
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ this.mView.requestFocus();
+ }
+
+ return true;
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+ public void showKeyboard(String p_existing_text) {
+ this.mOriginText = p_existing_text;
+
+ final Message msg = new Message();
+ msg.what = HANDLER_OPEN_IME_KEYBOARD;
+ msg.obj = this;
+ sHandler.sendMessage(msg);
+ }
+
+ public void hideKeyboard() {
+ final Message msg = new Message();
+ msg.what = HANDLER_CLOSE_IME_KEYBOARD;
+ msg.obj = this;
+ sHandler.sendMessage(msg);
+ }
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/platform/android/java/src/org/godotengine/godot/input/GodotTextInputWrapper.java b/platform/android/java/src/org/godotengine/godot/input/GodotTextInputWrapper.java
new file mode 100644
index 0000000000..64d8826b44
--- /dev/null
+++ b/platform/android/java/src/org/godotengine/godot/input/GodotTextInputWrapper.java
@@ -0,0 +1,154 @@
+package org.godotengine.godot.input;
+import android.content.Context;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.TextView;
+import android.widget.TextView.OnEditorActionListener;
+import org.godotengine.godot.*;
+
+public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListener {
+ // ===========================================================
+ // Constants
+ // ===========================================================
+ private static final String TAG = GodotTextInputWrapper.class.getSimpleName();
+
+ // ===========================================================
+ // Fields
+ // ===========================================================
+ private final GodotView mView;
+ private final GodotEditText mEdit;
+ private String mText;
+ private String mOriginText;
+
+ // ===========================================================
+ // Constructors
+ // ===========================================================
+
+ public GodotTextInputWrapper(final GodotView view, final GodotEditText edit) {
+ this.mView = view;
+ this.mEdit = edit;
+ }
+
+ // ===========================================================
+ // Getter & Setter
+ // ===========================================================
+
+ private boolean isFullScreenEdit() {
+ final TextView textField = this.mEdit;
+ final InputMethodManager imm = (InputMethodManager) textField.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ return imm.isFullscreenMode();
+ }
+
+ public void setOriginText(final String originText) {
+ this.mOriginText = originText;
+ }
+
+ // ===========================================================
+ // Methods for/from SuperClass/Interfaces
+ // ===========================================================
+
+ @Override
+ public void afterTextChanged(final Editable s) {
+ if (this.isFullScreenEdit()) {
+ return;
+ }
+
+ //if (BuildConfig.DEBUG) {
+ //Log.d(TAG, "afterTextChanged: " + s);
+ //}
+ int nModified = s.length() - this.mText.length();
+ if (nModified > 0) {
+ final String insertText = s.subSequence(this.mText.length(), s.length()).toString();
+ for(int i = 0; i < insertText.length(); i++) {
+ int ch = insertText.codePointAt(i);
+ GodotLib.key(0, ch, true);
+ GodotLib.key(0, ch, false);
+ }
+ /*
+ if (BuildConfig.DEBUG) {
+ Log.d(TAG, "insertText(" + insertText + ")");
+ }
+ */
+ } else {
+ for (; nModified < 0; ++nModified) {
+ GodotLib.key(KeyEvent.KEYCODE_DEL, 0, true);
+ GodotLib.key(KeyEvent.KEYCODE_DEL, 0, false);
+ /*
+ if (BuildConfig.DEBUG) {
+ Log.d(TAG, "deleteBackward");
+ }
+ */
+ }
+ }
+ this.mText = s.toString();
+ }
+
+ @Override
+ public void beforeTextChanged(final CharSequence pCharSequence, final int start, final int count, final int after) {
+ /*
+ if (BuildConfig.DEBUG) {
+ Log.d(TAG, "beforeTextChanged(" + pCharSequence + ")start: " + start + ",count: " + count + ",after: " + after);
+ }
+ */
+ this.mText = pCharSequence.toString();
+ }
+
+ @Override
+ public void onTextChanged(final CharSequence pCharSequence, final int start, final int before, final int count) {
+
+ }
+
+ @Override
+ public boolean onEditorAction(final TextView pTextView, final int pActionID, final KeyEvent pKeyEvent) {
+ if (this.mEdit == pTextView && this.isFullScreenEdit()) {
+ // user press the action button, delete all old text and insert new text
+ for (int i = this.mOriginText.length(); i > 0; i--) {
+ GodotLib.key(KeyEvent.KEYCODE_DEL, 0, true);
+ GodotLib.key(KeyEvent.KEYCODE_DEL, 0, false);
+ /*
+ if (BuildConfig.DEBUG) {
+ Log.d(TAG, "deleteBackward");
+ }
+ */
+ }
+ String text = pTextView.getText().toString();
+
+ /* If user input nothing, translate "\n" to engine. */
+ if (text.compareTo("") == 0) {
+ text = "\n";
+ }
+
+ if ('\n' != text.charAt(text.length() - 1)) {
+ text += '\n';
+ }
+
+ for(int i = 0; i < text.length(); i++) {
+ int ch = text.codePointAt(i);
+ GodotLib.key(0, ch, true);
+ GodotLib.key(0, ch, false);
+ }
+ /*
+ if (BuildConfig.DEBUG) {
+ Log.d(TAG, "insertText(" + insertText + ")");
+ }
+ */
+ }
+
+ if (pActionID == EditorInfo.IME_ACTION_DONE) {
+ this.mView.requestFocus();
+ }
+ return false;
+ }
+
+ // ===========================================================
+ // Methods
+ // ===========================================================
+
+ // ===========================================================
+ // Inner and Anonymous Classes
+ // ===========================================================
+}
diff --git a/platform/android/java/src/org/godotengine/godot/payments/ConsumeTask.java b/platform/android/java/src/org/godotengine/godot/payments/ConsumeTask.java
new file mode 100644
index 0000000000..61ccb97161
--- /dev/null
+++ b/platform/android/java/src/org/godotengine/godot/payments/ConsumeTask.java
@@ -0,0 +1,71 @@
+package org.godotengine.godot.payments;
+
+import com.android.vending.billing.IInAppBillingService;
+
+import android.content.Context;
+import android.os.AsyncTask;
+import android.os.RemoteException;
+import android.util.Log;
+
+abstract public class ConsumeTask {
+
+ private Context context;
+
+ private IInAppBillingService mService;
+ public ConsumeTask(IInAppBillingService mService, Context context ){
+ this.context = context;
+ this.mService = mService;
+ }
+
+
+ public void consume(final String sku){
+// Log.d("XXX", "Consuming product " + sku);
+ PaymentsCache pc = new PaymentsCache(context);
+ Boolean isBlocked = pc.getConsumableFlag("block", sku);
+ String _token = pc.getConsumableValue("token", sku);
+// Log.d("XXX", "token " + _token);
+ if(!isBlocked && _token == null){
+// _token = "inapp:"+context.getPackageName()+":android.test.purchased";
+// Log.d("XXX", "Consuming product " + sku + " with token " + _token);
+ }else if(!isBlocked){
+// Log.d("XXX", "It is not blocked ¿?");
+ return;
+ }else if(_token == null){
+// Log.d("XXX", "No token available");
+ this.error("No token for sku:" + sku);
+ return;
+ }
+ final String token = _token;
+ new AsyncTask<String, String, String>(){
+
+ @Override
+ protected String doInBackground(String... params) {
+ try {
+// Log.d("XXX", "Requesting to release item.");
+ int response = mService.consumePurchase(3, context.getPackageName(), token);
+// Log.d("XXX", "release response code: " + response);
+ if(response == 0 || response == 8){
+ return null;
+ }
+ } catch (RemoteException e) {
+ return e.getMessage();
+
+ }
+ return "Some error";
+ }
+
+ protected void onPostExecute(String param){
+ if(param == null){
+ success( new PaymentsCache(context).getConsumableValue("ticket", sku) );
+ }else{
+ error(param);
+ }
+ }
+
+ }.execute();
+ }
+
+ abstract protected void success(String ticket);
+ abstract protected void error(String message);
+
+}
diff --git a/platform/android/java/src/org/godotengine/godot/payments/GenericConsumeTask.java b/platform/android/java/src/org/godotengine/godot/payments/GenericConsumeTask.java
new file mode 100644
index 0000000000..293e903284
--- /dev/null
+++ b/platform/android/java/src/org/godotengine/godot/payments/GenericConsumeTask.java
@@ -0,0 +1,53 @@
+package org.godotengine.godot.payments;
+
+import com.android.vending.billing.IInAppBillingService;
+
+import android.content.Context;
+import android.os.AsyncTask;
+import android.os.RemoteException;
+import android.util.Log;
+
+abstract public class GenericConsumeTask extends AsyncTask<String, String, String>{
+
+ private Context context;
+ private IInAppBillingService mService;
+
+
+
+
+ public GenericConsumeTask(Context context, IInAppBillingService mService, String sku, String receipt, String signature, String token){
+ this.context = context;
+ this.mService = mService;
+ this.sku = sku;
+ this.receipt = receipt;
+ this.signature = signature;
+ this.token = token;
+ }
+
+ private String sku;
+ private String receipt;
+ private String signature;
+ private String token;
+
+ @Override
+ protected String doInBackground(String... params) {
+ try {
+// Log.d("godot", "Requesting to consume an item with token ." + token);
+ int response = mService.consumePurchase(3, context.getPackageName(), token);
+// Log.d("godot", "consumePurchase response: " + response);
+ if(response == 0 || response == 8){
+ return null;
+ }
+ } catch (Exception e) {
+ Log.d("godot", "Error " + e.getClass().getName() + ":" + e.getMessage());
+ }
+ return null;
+ }
+
+ protected void onPostExecute(String sarasa){
+ onSuccess(sku, receipt, signature, token);
+ }
+
+ abstract public void onSuccess(String sku, String receipt, String signature, String token);
+
+}
diff --git a/platform/android/java/src/org/godotengine/godot/payments/HandlePurchaseTask.java b/platform/android/java/src/org/godotengine/godot/payments/HandlePurchaseTask.java
new file mode 100644
index 0000000000..d120551e4a
--- /dev/null
+++ b/platform/android/java/src/org/godotengine/godot/payments/HandlePurchaseTask.java
@@ -0,0 +1,82 @@
+package org.godotengine.godot.payments;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import org.godotengine.godot.GodotLib;
+import org.godotengine.godot.utils.Crypt;
+import com.android.vending.billing.IInAppBillingService;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentSender.SendIntentException;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+
+abstract public class HandlePurchaseTask {
+
+ private Activity context;
+
+ public HandlePurchaseTask(Activity context ){
+ this.context = context;
+ }
+
+
+ public void handlePurchaseRequest(int resultCode, Intent data){
+// Log.d("XXX", "Handling purchase response");
+// int responseCode = data.getIntExtra("RESPONSE_CODE", 0);
+ PaymentsCache pc = new PaymentsCache(context);
+
+ String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
+// Log.d("XXX", "Purchase data:" + purchaseData);
+ String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");
+ //Log.d("XXX", "Purchase signature:" + dataSignature);
+
+ if (resultCode == Activity.RESULT_OK) {
+
+ try {
+// Log.d("SARLANGA", purchaseData);
+
+
+ JSONObject jo = new JSONObject(purchaseData);
+// String sku = jo.getString("productId");
+// alert("You have bought the " + sku + ". Excellent choice, aventurer!");
+// String orderId = jo.getString("orderId");
+// String packageName = jo.getString("packageName");
+ String productId = jo.getString("productId");
+// Long purchaseTime = jo.getLong("purchaseTime");
+// Integer state = jo.getInt("purchaseState");
+ String developerPayload = jo.getString("developerPayload");
+ String purchaseToken = jo.getString("purchaseToken");
+
+ if(! pc.getConsumableValue("validation_hash", productId).equals(developerPayload) ) {
+ error("Untrusted callback");
+ return;
+ }
+// Log.d("XXX", "Este es el product ID:" + productId);
+ pc.setConsumableValue("ticket_signautre", productId, dataSignature);
+ pc.setConsumableValue("ticket", productId, purchaseData);
+ pc.setConsumableFlag("block", productId, true);
+ pc.setConsumableValue("token", productId, purchaseToken);
+
+ success(productId, dataSignature, purchaseData);
+ return;
+ } catch (JSONException e) {
+ error(e.getMessage());
+ }
+ }else if( resultCode == Activity.RESULT_CANCELED){
+ canceled();
+ }
+ }
+
+ abstract protected void success(String sku, String signature, String ticket);
+ abstract protected void error(String message);
+ abstract protected void canceled();
+
+
+}
diff --git a/platform/android/java/src/org/godotengine/godot/payments/PaymentsCache.java b/platform/android/java/src/org/godotengine/godot/payments/PaymentsCache.java
new file mode 100644
index 0000000000..5f3d931593
--- /dev/null
+++ b/platform/android/java/src/org/godotengine/godot/payments/PaymentsCache.java
@@ -0,0 +1,45 @@
+package org.godotengine.godot.payments;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.util.Log;
+
+public class PaymentsCache {
+
+ public Context context;
+
+ public PaymentsCache(Context context){
+ this.context = context;
+ }
+
+
+ public void setConsumableFlag(String set, String sku, Boolean flag){
+ SharedPreferences sharedPref = context.getSharedPreferences("consumables_" + set, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = sharedPref.edit();
+ editor.putBoolean(sku, flag);
+ editor.commit();
+}
+
+ public boolean getConsumableFlag(String set, String sku){
+ SharedPreferences sharedPref = context.getSharedPreferences(
+ "consumables_" + set, Context.MODE_PRIVATE);
+ return sharedPref.getBoolean(sku, false);
+ }
+
+
+ public void setConsumableValue(String set, String sku, String value){
+ SharedPreferences sharedPref = context.getSharedPreferences("consumables_" + set, Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = sharedPref.edit();
+ editor.putString(sku, value);
+// Log.d("XXX", "Setting asset: consumables_" + set + ":" + sku);
+ editor.commit();
+ }
+
+ public String getConsumableValue(String set, String sku){
+ SharedPreferences sharedPref = context.getSharedPreferences(
+ "consumables_" + set, Context.MODE_PRIVATE);
+// Log.d("XXX", "Getting asset: consumables_" + set + ":" + sku);
+ return sharedPref.getString(sku, null);
+ }
+
+}
diff --git a/platform/android/java/src/org/godotengine/godot/payments/PaymentsManager.java b/platform/android/java/src/org/godotengine/godot/payments/PaymentsManager.java
new file mode 100644
index 0000000000..effb58aa35
--- /dev/null
+++ b/platform/android/java/src/org/godotengine/godot/payments/PaymentsManager.java
@@ -0,0 +1,282 @@
+package org.godotengine.godot.payments;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.os.RemoteException;
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.util.Log;
+import android.os.Bundle;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.json.JSONStringer;
+
+import org.godotengine.godot.Dictionary;
+import org.godotengine.godot.Godot;
+import org.godotengine.godot.GodotPaymentV3;
+import com.android.vending.billing.IInAppBillingService;
+
+public class PaymentsManager {
+
+ public static final int BILLING_RESPONSE_RESULT_OK = 0;
+ public static final int REQUEST_CODE_FOR_PURCHASE = 0x1001;
+ private static boolean auto_consume = true;
+
+ private Activity activity;
+ IInAppBillingService mService;
+
+ public void setActivity(Activity activity){
+ this.activity = activity;
+ }
+
+ public static PaymentsManager createManager(Activity activity){
+ PaymentsManager manager = new PaymentsManager(activity);
+ return manager;
+ }
+
+ private PaymentsManager(Activity activity){
+ this.activity = activity;
+ }
+
+ public PaymentsManager initService(){
+ Intent intent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
+ intent.setPackage("com.android.vending");
+ activity.bindService(
+ intent,
+ mServiceConn,
+ Context.BIND_AUTO_CREATE);
+ return this;
+ }
+
+ public void destroy(){
+ if (mService != null) {
+ activity.unbindService(mServiceConn);
+ }
+ }
+
+ ServiceConnection mServiceConn = new ServiceConnection() {
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ mService = null;
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ mService = IInAppBillingService.Stub.asInterface(service);
+ }
+ };
+
+ public void requestPurchase(final String sku, String transactionId){
+ new PurchaseTask(mService, Godot.getInstance()) {
+
+ @Override
+ protected void error(String message) {
+ godotPaymentV3.callbackFail();
+
+ }
+
+ @Override
+ protected void canceled() {
+ godotPaymentV3.callbackCancel();
+ }
+
+ @Override
+ protected void alreadyOwned() {
+ godotPaymentV3.callbackAlreadyOwned(sku);
+ }
+
+ }.purchase(sku, transactionId);
+
+ }
+
+ public void consumeUnconsumedPurchases(){
+ new ReleaseAllConsumablesTask(mService, activity) {
+
+ @Override
+ protected void success(String sku, String receipt, String signature, String token) {
+ godotPaymentV3.callbackSuccessProductMassConsumed(receipt, signature, sku);
+ }
+
+ @Override
+ protected void error(String message) {
+ godotPaymentV3.callbackFail();
+
+ }
+
+ @Override
+ protected void notRequired() {
+ godotPaymentV3.callbackSuccessNoUnconsumedPurchases();
+
+ }
+ }.consumeItAll();
+ }
+
+ public void requestPurchased(){
+ try{
+ PaymentsCache pc = new PaymentsCache(Godot.getInstance());
+
+// Log.d("godot", "requestPurchased for " + activity.getPackageName());
+ Bundle bundle = mService.getPurchases(3, activity.getPackageName(), "inapp",null);
+
+/*
+ for (String key : bundle.keySet()) {
+ Object value = bundle.get(key);
+ Log.d("godot", String.format("%s %s (%s)", key, value.toString(), value.getClass().getName()));
+ }
+*/
+
+ if (bundle.getInt("RESPONSE_CODE") == 0){
+
+ final ArrayList<String> myPurchases = bundle.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
+ final ArrayList<String> mySignatures = bundle.getStringArrayList("INAPP_DATA_SIGNATURE_LIST");
+
+
+ if (myPurchases == null || myPurchases.size() == 0){
+// Log.d("godot", "No purchases!");
+ godotPaymentV3.callbackPurchased("", "", "");
+ return;
+ }
+
+// Log.d("godot", "# products are purchased:" + myPurchases.size());
+ for (int i=0;i<myPurchases.size();i++)
+ {
+
+ try{
+ String receipt = myPurchases.get(i);
+ JSONObject inappPurchaseData = new JSONObject(receipt);
+ String sku = inappPurchaseData.getString("productId");
+ String token = inappPurchaseData.getString("purchaseToken");
+ String signature = mySignatures.get(i);
+// Log.d("godot", "purchased item:" + token + "\n" + receipt);
+
+ pc.setConsumableValue("ticket_signautre", sku, signature);
+ pc.setConsumableValue("ticket", sku, receipt);
+ pc.setConsumableFlag("block", sku, true);
+ pc.setConsumableValue("token", sku, token);
+
+ godotPaymentV3.callbackPurchased(receipt, signature, sku);
+ } catch (JSONException e) {
+ }
+ }
+
+ }
+ }catch(Exception e){
+ Log.d("godot", "Error requesting purchased products:" + e.getClass().getName() + ":" + e.getMessage());
+ }
+ }
+
+ public void processPurchaseResponse(int resultCode, Intent data) {
+ new HandlePurchaseTask(activity){
+
+ @Override
+ protected void success(final String sku, final String signature, final String ticket) {
+ godotPaymentV3.callbackSuccess(ticket, signature, sku);
+
+ if (auto_consume){
+ new ConsumeTask(mService, activity) {
+
+ @Override
+ protected void success(String ticket) {
+// godotPaymentV3.callbackSuccess("");
+ }
+
+ @Override
+ protected void error(String message) {
+ godotPaymentV3.callbackFail();
+
+ }
+ }.consume(sku);
+ }
+
+// godotPaymentV3.callbackSuccess(new PaymentsCache(activity).getConsumableValue("ticket", sku),signature);
+// godotPaymentV3.callbackSuccess(ticket);
+ //validatePurchase(purchaseToken, sku);
+ }
+
+ @Override
+ protected void error(String message) {
+ godotPaymentV3.callbackFail();
+
+ }
+
+ @Override
+ protected void canceled() {
+ godotPaymentV3.callbackCancel();
+
+ }
+ }.handlePurchaseRequest(resultCode, data);
+ }
+
+ public void validatePurchase(String purchaseToken, final String sku){
+
+ new ValidateTask(activity, godotPaymentV3){
+
+ @Override
+ protected void success() {
+
+ new ConsumeTask(mService, activity) {
+
+ @Override
+ protected void success(String ticket) {
+ godotPaymentV3.callbackSuccess(ticket, null, sku);
+
+ }
+
+ @Override
+ protected void error(String message) {
+ godotPaymentV3.callbackFail();
+
+ }
+ }.consume(sku);
+
+ }
+
+ @Override
+ protected void error(String message) {
+ godotPaymentV3.callbackFail();
+
+ }
+
+ @Override
+ protected void canceled() {
+ godotPaymentV3.callbackCancel();
+
+ }
+ }.validatePurchase(sku);
+ }
+
+ public void setAutoConsume(boolean autoConsume){
+ auto_consume = autoConsume;
+ }
+
+ public void consume(final String sku){
+ new ConsumeTask(mService, activity) {
+
+ @Override
+ protected void success(String ticket) {
+ godotPaymentV3.callbackSuccessProductMassConsumed(ticket, "", sku);
+
+ }
+
+ @Override
+ protected void error(String message) {
+ godotPaymentV3.callbackFail();
+
+ }
+ }.consume(sku);
+ }
+
+ private GodotPaymentV3 godotPaymentV3;
+
+ public void setBaseSingleton(GodotPaymentV3 godotPaymentV3) {
+ this.godotPaymentV3 = godotPaymentV3;
+ }
+
+}
+
diff --git a/platform/android/java/src/org/godotengine/godot/payments/PurchaseTask.java b/platform/android/java/src/org/godotengine/godot/payments/PurchaseTask.java
new file mode 100644
index 0000000000..8b048d8065
--- /dev/null
+++ b/platform/android/java/src/org/godotengine/godot/payments/PurchaseTask.java
@@ -0,0 +1,101 @@
+package org.godotengine.godot.payments;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import org.godotengine.godot.GodotLib;
+import org.godotengine.godot.utils.Crypt;
+import com.android.vending.billing.IInAppBillingService;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentSender.SendIntentException;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+
+abstract public class PurchaseTask {
+
+ private Activity context;
+
+ private IInAppBillingService mService;
+ public PurchaseTask(IInAppBillingService mService, Activity context ){
+ this.context = context;
+ this.mService = mService;
+ }
+
+
+ private boolean isLooping = false;
+
+ public void purchase(final String sku, final String transactionId){
+ Log.d("XXX", "Starting purchase for: " + sku);
+ PaymentsCache pc = new PaymentsCache(context);
+ Boolean isBlocked = pc.getConsumableFlag("block", sku);
+// if(isBlocked){
+// Log.d("XXX", "Is awaiting payment confirmation");
+// error("Awaiting payment confirmation");
+// return;
+// }
+ final String hash = transactionId;
+
+ Bundle buyIntentBundle;
+ try {
+ buyIntentBundle = mService.getBuyIntent(3, context.getApplicationContext().getPackageName(), sku, "inapp", hash );
+ } catch (RemoteException e) {
+// Log.d("XXX", "Error: " + e.getMessage());
+ error(e.getMessage());
+ return;
+ }
+ Object rc = buyIntentBundle.get("RESPONSE_CODE");
+ int responseCode = 0;
+ if(rc == null){
+ responseCode = PaymentsManager.BILLING_RESPONSE_RESULT_OK;
+ }else if( rc instanceof Integer){
+ responseCode = ((Integer)rc).intValue();
+ }else if( rc instanceof Long){
+ responseCode = (int)((Long)rc).longValue();
+ }
+// Log.d("XXX", "Buy intent response code: " + responseCode);
+ if(responseCode == 1 || responseCode == 3 || responseCode == 4){
+ canceled();
+ return;
+ }
+ if(responseCode == 7){
+ alreadyOwned();
+ return;
+ }
+
+
+ PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT");
+ pc.setConsumableValue("validation_hash", sku, hash);
+ try {
+ if(context == null){
+// Log.d("XXX", "No context!");
+ }
+ if(pendingIntent == null){
+// Log.d("XXX", "No pending intent");
+ }
+// Log.d("XXX", "Starting activity for purchase!");
+ context.startIntentSenderForResult(
+ pendingIntent.getIntentSender(),
+ PaymentsManager.REQUEST_CODE_FOR_PURCHASE,
+ new Intent(),
+ Integer.valueOf(0), Integer.valueOf(0),
+ Integer.valueOf(0));
+ } catch (SendIntentException e) {
+ error(e.getMessage());
+ }
+
+
+
+ }
+
+ abstract protected void error(String message);
+ abstract protected void canceled();
+ abstract protected void alreadyOwned();
+
+}
diff --git a/platform/android/java/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java b/platform/android/java/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java
new file mode 100644
index 0000000000..7bb5131b49
--- /dev/null
+++ b/platform/android/java/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java
@@ -0,0 +1,87 @@
+package org.godotengine.godot.payments;
+
+import java.util.ArrayList;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import org.godotengine.godot.Dictionary;
+import org.godotengine.godot.Godot;
+import com.android.vending.billing.IInAppBillingService;
+
+import android.content.Context;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+
+abstract public class ReleaseAllConsumablesTask {
+
+ private Context context;
+ private IInAppBillingService mService;
+
+ public ReleaseAllConsumablesTask(IInAppBillingService mService, Context context ){
+ this.context = context;
+ this.mService = mService;
+ }
+
+
+ public void consumeItAll(){
+ try{
+// Log.d("godot", "consumeItall for " + context.getPackageName());
+ Bundle bundle = mService.getPurchases(3, context.getPackageName(), "inapp",null);
+
+ for (String key : bundle.keySet()) {
+ Object value = bundle.get(key);
+// Log.d("godot", String.format("%s %s (%s)", key,
+// value.toString(), value.getClass().getName()));
+ }
+
+
+ if (bundle.getInt("RESPONSE_CODE") == 0){
+
+ final ArrayList<String> myPurchases = bundle.getStringArrayList("INAPP_PURCHASE_DATA_LIST");
+ final ArrayList<String> mySignatures = bundle.getStringArrayList("INAPP_DATA_SIGNATURE_LIST");
+
+
+ if (myPurchases == null || myPurchases.size() == 0){
+// Log.d("godot", "No purchases!");
+ notRequired();
+ return;
+ }
+
+
+// Log.d("godot", "# products to be consumed:" + myPurchases.size());
+ for (int i=0;i<myPurchases.size();i++)
+ {
+
+ try{
+ String receipt = myPurchases.get(i);
+ JSONObject inappPurchaseData = new JSONObject(receipt);
+ String sku = inappPurchaseData.getString("productId");
+ String token = inappPurchaseData.getString("purchaseToken");
+ String signature = mySignatures.get(i);
+// Log.d("godot", "A punto de consumir un item con token:" + token + "\n" + receipt);
+ new GenericConsumeTask(context, mService, sku, receipt,signature, token) {
+
+ @Override
+ public void onSuccess(String sku, String receipt, String signature, String token) {
+ ReleaseAllConsumablesTask.this.success(sku, receipt, signature, token);
+ }
+ }.execute();
+
+ } catch (JSONException e) {
+ }
+ }
+
+ }
+ }catch(Exception e){
+ Log.d("godot", "Error releasing products:" + e.getClass().getName() + ":" + e.getMessage());
+ }
+ }
+
+ abstract protected void success(String sku, String receipt, String signature, String token);
+ abstract protected void error(String message);
+ abstract protected void notRequired();
+
+}
diff --git a/platform/android/java/src/org/godotengine/godot/payments/ValidateTask.java b/platform/android/java/src/org/godotengine/godot/payments/ValidateTask.java
new file mode 100644
index 0000000000..2fcf7483b4
--- /dev/null
+++ b/platform/android/java/src/org/godotengine/godot/payments/ValidateTask.java
@@ -0,0 +1,97 @@
+package org.godotengine.godot.payments;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import org.godotengine.godot.Godot;
+import org.godotengine.godot.GodotLib;
+import org.godotengine.godot.GodotPaymentV3;
+import org.godotengine.godot.utils.Crypt;
+import org.godotengine.godot.utils.HttpRequester;
+import org.godotengine.godot.utils.RequestParams;
+import com.android.vending.billing.IInAppBillingService;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentSender.SendIntentException;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.util.Log;
+
+abstract public class ValidateTask {
+
+ private Activity context;
+ private GodotPaymentV3 godotPaymentsV3;
+ public ValidateTask(Activity context, GodotPaymentV3 godotPaymentsV3){
+ this.context = context;
+ this.godotPaymentsV3 = godotPaymentsV3;
+ }
+
+ public void validatePurchase(final String sku){
+ new AsyncTask<String, String, String>(){
+
+
+ private ProgressDialog dialog;
+
+ @Override
+ protected void onPreExecute(){
+ dialog = ProgressDialog.show(context, null, "Please wait...");
+ }
+
+ @Override
+ protected String doInBackground(String... params) {
+ PaymentsCache pc = new PaymentsCache(context);
+ String url = godotPaymentsV3.getPurchaseValidationUrlPrefix();
+ RequestParams param = new RequestParams();
+ param.setUrl(url);
+ param.put("ticket", pc.getConsumableValue("ticket", sku));
+ param.put("purchaseToken", pc.getConsumableValue("token", sku));
+ param.put("sku", sku);
+// Log.d("XXX", "Haciendo request a " + url);
+// Log.d("XXX", "ticket: " + pc.getConsumableValue("ticket", sku));
+// Log.d("XXX", "purchaseToken: " + pc.getConsumableValue("token", sku));
+// Log.d("XXX", "sku: " + sku);
+ param.put("package", context.getApplicationContext().getPackageName());
+ HttpRequester requester = new HttpRequester();
+ String jsonResponse = requester.post(param);
+// Log.d("XXX", "Validation response:\n"+jsonResponse);
+ return jsonResponse;
+ }
+
+ @Override
+ protected void onPostExecute(String response){
+ if(dialog != null){
+ dialog.dismiss();
+ }
+ JSONObject j;
+ try {
+ j = new JSONObject(response);
+ if(j.getString("status").equals("OK")){
+ success();
+ return;
+ }else if(j.getString("status") != null){
+ error(j.getString("message"));
+ }else{
+ error("Connection error");
+ }
+ } catch (JSONException e) {
+ error(e.getMessage());
+ }catch (Exception e){
+ error(e.getMessage());
+ }
+
+
+ }
+
+ }.execute();
+ }
+ abstract protected void success();
+ abstract protected void error(String message);
+ abstract protected void canceled();
+
+
+}
diff --git a/platform/android/java/src/org/godotengine/godot/utils/Crypt.java b/platform/android/java/src/org/godotengine/godot/utils/Crypt.java
new file mode 100644
index 0000000000..2fb81cef8c
--- /dev/null
+++ b/platform/android/java/src/org/godotengine/godot/utils/Crypt.java
@@ -0,0 +1,39 @@
+package org.godotengine.godot.utils;
+
+import java.security.MessageDigest;
+import java.util.Random;
+
+public class Crypt {
+
+ public static String md5(String input){
+ try {
+ // Create MD5 Hash
+ MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
+ digest.update(input.getBytes());
+ byte messageDigest[] = digest.digest();
+
+ // Create Hex String
+ StringBuffer hexString = new StringBuffer();
+ for (int i=0; i<messageDigest.length; i++)
+ hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
+ return hexString.toString();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return "";
+ }
+
+ public static String createRandomHash(){
+ return md5(Long.toString(createRandomLong()));
+ }
+
+ public static long createAbsRandomLong(){
+ return Math.abs(createRandomLong());
+ }
+
+ public static long createRandomLong(){
+ Random r = new Random();
+ return r.nextLong();
+ }
+}
diff --git a/platform/android/java/src/org/godotengine/godot/utils/CustomSSLSocketFactory.java b/platform/android/java/src/org/godotengine/godot/utils/CustomSSLSocketFactory.java
new file mode 100644
index 0000000000..2db88fcc9b
--- /dev/null
+++ b/platform/android/java/src/org/godotengine/godot/utils/CustomSSLSocketFactory.java
@@ -0,0 +1,54 @@
+package org.godotengine.godot.utils;
+import java.io.IOException;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+import org.apache.http.conn.ssl.SSLSocketFactory;
+
+
+/**
+ *
+ * @author Luis Linietsky <luis.linietsky@gmail.com>
+ */
+public class CustomSSLSocketFactory extends SSLSocketFactory {
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+
+ public CustomSSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
+ super(truststore);
+
+ TrustManager tm = new X509TrustManager() {
+ public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+ }
+
+ public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+ }
+
+ public X509Certificate[] getAcceptedIssuers() {
+ return null;
+ }
+ };
+
+ sslContext.init(null, new TrustManager[] { tm }, null);
+ }
+
+ @Override
+ public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
+ return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
+ }
+
+ @Override
+ public Socket createSocket() throws IOException {
+ return sslContext.getSocketFactory().createSocket();
+ }
+} \ No newline at end of file
diff --git a/platform/android/java/src/org/godotengine/godot/utils/HttpRequester.java b/platform/android/java/src/org/godotengine/godot/utils/HttpRequester.java
new file mode 100644
index 0000000000..14346702cc
--- /dev/null
+++ b/platform/android/java/src/org/godotengine/godot/utils/HttpRequester.java
@@ -0,0 +1,206 @@
+package org.godotengine.godot.utils;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.security.KeyStore;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpVersion;
+import org.apache.http.NameValuePair;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.scheme.PlainSocketFactory;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.HttpConnectionParams;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.HttpProtocolParams;
+import org.apache.http.protocol.HTTP;
+import org.apache.http.util.EntityUtils;
+
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.util.Log;
+
+/**
+ *
+ * @author Luis Linietsky <luis.linietsky@gmail.com>
+ */
+public class HttpRequester {
+
+ private Context context;
+ private static final int TTL = 600000; // 10 minutos
+ private long cttl=0;
+
+ public HttpRequester(){
+// Log.d("XXX", "Creando http request sin contexto");
+ }
+
+ public HttpRequester(Context context){
+ this.context=context;
+// Log.d("XXX", "Creando http request con contexto");
+ }
+
+ public String post(RequestParams params){
+ HttpPost httppost = new HttpPost(params.getUrl());
+ try {
+ httppost.setEntity(new UrlEncodedFormEntity(params.toPairsList()));
+ return request(httppost);
+ } catch (UnsupportedEncodingException e) {
+ return null;
+ }
+ }
+
+ public String get(RequestParams params){
+ String response = getResponseFromCache(params.getUrl());
+ if(response == null){
+// Log.d("XXX", "Cache miss!");
+ HttpGet httpget = new HttpGet(params.getUrl());
+ long timeInit = new Date().getTime();
+ response = request(httpget);
+ long delay = new Date().getTime() - timeInit;
+ Log.d("com.app11tt.android.utils.HttpRequest::get(url)", "Url: " + params.getUrl() + " downloaded in " + String.format("%.03f", delay/1000.0f) + " seconds");
+ if(response == null || response.length() == 0){
+ response = "";
+ }else{
+ saveResponseIntoCache(params.getUrl(), response);
+ }
+ }
+ Log.d("XXX", "Req: " + params.getUrl());
+ Log.d("XXX", "Resp: " + response);
+ return response;
+ }
+
+ private String request(HttpUriRequest request){
+// Log.d("XXX", "Haciendo request a: " + request.getURI() );
+ Log.d("PPP", "Haciendo request a: " + request.getURI() );
+ long init = new Date().getTime();
+ HttpClient httpclient = getNewHttpClient();
+ HttpParams httpParameters = httpclient.getParams();
+ HttpConnectionParams.setConnectionTimeout(httpParameters, 0);
+ HttpConnectionParams.setSoTimeout(httpParameters, 0);
+ HttpConnectionParams.setTcpNoDelay(httpParameters, true);
+ try {
+ HttpResponse response = httpclient.execute(request);
+ Log.d("PPP", "Fin de request (" + (new Date().getTime() - init) + ") a: " + request.getURI() );
+// Log.d("XXX1", "Status:" + response.getStatusLine().toString());
+ if(response.getStatusLine().getStatusCode() == 200){
+ String strResponse = EntityUtils.toString(response.getEntity());
+// Log.d("XXX2", strResponse);
+ return strResponse;
+ }else{
+ Log.d("XXX3", "Response status code:" + response.getStatusLine().getStatusCode() + "\n" + EntityUtils.toString(response.getEntity()));
+ return null;
+ }
+
+ } catch (ClientProtocolException e) {
+ Log.d("XXX3", e.getMessage());
+ } catch (IOException e) {
+ Log.d("XXX4", e.getMessage());
+ }
+ return null;
+ }
+
+ private HttpClient getNewHttpClient() {
+ try {
+ KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
+ trustStore.load(null, null);
+
+ SSLSocketFactory sf = new CustomSSLSocketFactory(trustStore);
+ sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
+
+ HttpParams params = new BasicHttpParams();
+ HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
+ HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
+
+ SchemeRegistry registry = new SchemeRegistry();
+ registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
+ registry.register(new Scheme("https", sf, 443));
+
+ ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
+
+ return new DefaultHttpClient(ccm, params);
+ } catch (Exception e) {
+ return new DefaultHttpClient();
+ }
+ }
+
+ private static String convertStreamToString(InputStream is) {
+ BufferedReader reader = new BufferedReader(new InputStreamReader(is));
+ StringBuilder sb = new StringBuilder();
+ String line = null;
+ try {
+ while ((line = reader.readLine()) != null) {
+ sb.append((line + "\n"));
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ is.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return sb.toString();
+ }
+
+ public void saveResponseIntoCache(String request, String response){
+ if(context == null){
+// Log.d("XXX", "No context, cache failed!");
+ return;
+ }
+ SharedPreferences sharedPref = context.getSharedPreferences("http_get_cache", Context.MODE_PRIVATE);
+ SharedPreferences.Editor editor = sharedPref.edit();
+ editor.putString("request_" + Crypt.md5(request), response);
+ editor.putLong("request_" + Crypt.md5(request) + "_ttl", new Date().getTime() + getTtl());
+ editor.commit();
+ }
+
+
+ public String getResponseFromCache(String request){
+ if(context == null){
+ Log.d("XXX", "No context, cache miss");
+ return null;
+ }
+ SharedPreferences sharedPref = context.getSharedPreferences( "http_get_cache", Context.MODE_PRIVATE);
+ long ttl = getResponseTtl(request);
+ if(ttl == 0l || (new Date().getTime() - ttl) > 0l){
+ Log.d("XXX", "Cache invalid ttl:" + ttl + " vs now:" + new Date().getTime());
+ return null;
+ }
+ return sharedPref.getString("request_" + Crypt.md5(request), null);
+ }
+
+ public long getResponseTtl(String request){
+ SharedPreferences sharedPref = context.getSharedPreferences(
+ "http_get_cache", Context.MODE_PRIVATE);
+ return sharedPref.getLong("request_" + Crypt.md5(request) + "_ttl", 0l);
+ }
+
+ public long getTtl() {
+ return cttl > 0 ? cttl : TTL;
+ }
+
+ public void setTtl(long ttl) {
+ this.cttl = (ttl*1000) + new Date().getTime();
+ }
+
+}
diff --git a/platform/android/java/src/org/godotengine/godot/utils/RequestParams.java b/platform/android/java/src/org/godotengine/godot/utils/RequestParams.java
new file mode 100644
index 0000000000..36753e368c
--- /dev/null
+++ b/platform/android/java/src/org/godotengine/godot/utils/RequestParams.java
@@ -0,0 +1,58 @@
+package org.godotengine.godot.utils;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+
+import org.apache.http.NameValuePair;
+import org.apache.http.message.BasicNameValuePair;
+
+/**
+ *
+ * @author Luis Linietsky <luis.linietsky@gmail.com>
+ */
+public class RequestParams {
+
+ private HashMap<String,String> params;
+ private String url;
+
+ public RequestParams(){
+ params = new HashMap<String,String>();
+ }
+
+ public void put(String key, String value){
+ params.put(key, value);
+ }
+
+ public String get(String key){
+ return params.get(key);
+ }
+
+ public void remove(Object key){
+ params.remove(key);
+ }
+
+ public boolean has(String key){
+ return params.containsKey(key);
+ }
+
+ public List<NameValuePair> toPairsList(){
+ List<NameValuePair> fields = new ArrayList<NameValuePair>();
+
+ for(String key : params.keySet()){
+ fields.add(new BasicNameValuePair(key, this.get(key)));
+ }
+ return fields;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+
+}
diff --git a/platform/android/java_class_wrapper.cpp b/platform/android/java_class_wrapper.cpp
index d4cf848484..283ea81152 100644
--- a/platform/android/java_class_wrapper.cpp
+++ b/platform/android/java_class_wrapper.cpp
@@ -1281,7 +1281,7 @@ JavaClassWrapper::JavaClassWrapper(jobject p_activity) {
JNIEnv *env = ThreadAndroid::get_env();
- jclass activityClass = env->FindClass("com/android/godot/Godot");
+ jclass activityClass = env->FindClass("org/godotengine/godot/Godot");
jmethodID getClassLoader = env->GetMethodID(activityClass,"getClassLoader", "()Ljava/lang/ClassLoader;");
classLoader = env->CallObjectMethod(p_activity, getClassLoader);
classLoader=(jclass)env->NewGlobalRef(classLoader);
diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp
index 3158254781..75c1d78151 100644
--- a/platform/android/java_glue.cpp
+++ b/platform/android/java_glue.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,13 +33,14 @@
#include "main/main.h"
#include <unistd.h>
#include "file_access_jandroid.h"
+#include "file_access_android.h"
#include "dir_access_jandroid.h"
#include "audio_driver_jandroid.h"
#include "globals.h"
#include "thread_jandroid.h"
#include "core/os/keyboard.h"
#include "java_class_wrapper.h"
-
+#include "android/asset_manager_jni.h"
static JavaClassWrapper *java_class_wrapper=NULL;
static OS_Android *os_android=NULL;
@@ -137,7 +138,7 @@ jvalret _variant_to_jvalue(JNIEnv *env, Variant::Type p_type, const Variant* p_a
case Variant::DICTIONARY: {
Dictionary dict = *p_arg;
- jclass dclass = env->FindClass("com/android/godot/Dictionary");
+ jclass dclass = env->FindClass("org/godotengine/godot/Dictionary");
jmethodID ctor = env->GetMethodID(dclass, "<init>", "()V");
jobject jdict = env->NewObject(dclass, ctor);
@@ -372,7 +373,7 @@ Variant _jobject_to_variant(JNIEnv * env, jobject obj) {
return varr;
};
- if (name == "java.util.HashMap" || name == "com.android.godot.Dictionary") {
+ if (name == "java.util.HashMap" || name == "org.godotengine.godot.Dictionary") {
Dictionary ret(true);
jclass oclass = c;
@@ -670,7 +671,7 @@ static jmethodID _playVideo=0;
static jmethodID _isVideoPlaying=0;
static jmethodID _pauseVideo=0;
static jmethodID _stopVideo=0;
-
+static jmethodID _setKeepScreenOn=0;
static void _gfx_init_func(void* ud, bool gl2) {
@@ -764,7 +765,12 @@ static void _stop_video() {
env->CallVoidMethod(godot_io, _stopVideo);
}
-JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_initialize(JNIEnv * env, jobject obj, jobject activity,jboolean p_need_reload_hook, jobjectArray p_cmdline) {
+static void _set_keep_screen_on(bool p_enabled) {
+ JNIEnv* env = ThreadAndroid::get_env();
+ env->CallVoidMethod(_godot_instance, _setKeepScreenOn, p_enabled);
+}
+
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv * env, jobject obj, jobject activity,jboolean p_need_reload_hook, jobjectArray p_cmdline,jobject p_asset_manager) {
__android_log_print(ANDROID_LOG_INFO,"godot","**INIT EVENT! - %p\n",env);
@@ -782,7 +788,7 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_initialize(JNIEnv * env,
{
//setup IO Object
- jclass cls = env->FindClass("com/android/godot/Godot");
+ jclass cls = env->FindClass("org/godotengine/godot/Godot");
if (cls) {
cls=(jclass)env->NewGlobalRef(cls);
@@ -790,7 +796,7 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_initialize(JNIEnv * env,
}
__android_log_print(ANDROID_LOG_INFO,"godot","STEP2, %p",cls);
- jfieldID fid = env->GetStaticFieldID(cls, "io", "Lcom/android/godot/GodotIO;");
+ jfieldID fid = env->GetStaticFieldID(cls, "io", "Lorg/godotengine/godot/GodotIO;");
__android_log_print(ANDROID_LOG_INFO,"godot","STEP3 %i",fid);
jobject ob = env->GetStaticObjectField(cls,fid);
__android_log_print(ANDROID_LOG_INFO,"godot","STEP4, %p",ob);
@@ -800,8 +806,9 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_initialize(JNIEnv * env,
godot_io=gob;
_on_video_init = env->GetMethodID(cls, "onVideoInit", "(Z)V");
+ _setKeepScreenOn = env->GetMethodID(cls,"setKeepScreenOn","(Z)V");
- jclass clsio = env->FindClass("com/android/godot/Godot");
+ jclass clsio = env->FindClass("org/godotengine/godot/Godot");
if (cls) {
jclass c = env->GetObjectClass(gob);
_openURI = env->GetMethodID(c,"openURI","(Ljava/lang/String;)I");
@@ -820,7 +827,14 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_initialize(JNIEnv * env,
}
ThreadAndroid::make_default(jvm);
+#ifdef USE_JAVA_FILE_ACCESS
FileAccessJAndroid::setup(gob);
+#else
+
+ jobject amgr = env->NewGlobalRef(p_asset_manager);
+
+ FileAccessAndroid::asset_manager=AAssetManager_fromJava(env,amgr);
+#endif
DirAccessJAndroid::setup(gob);
AudioDriverAndroid::setup(gob);
}
@@ -855,7 +869,7 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_initialize(JNIEnv * env,
__android_log_print(ANDROID_LOG_INFO,"godot","CMDLINE LEN %i - APK EXPANSION %I\n",cmdlen,int(use_apk_expansion));
- os_android = new OS_Android(_gfx_init_func,env,_open_uri,_get_data_dir,_get_locale, _get_model,_show_vk, _hide_vk,_set_screen_orient,_get_unique_id, _get_system_dir, _play_video,_is_video_playing, _pause_video, _stop_video,use_apk_expansion);
+ os_android = new OS_Android(_gfx_init_func,env,_open_uri,_get_data_dir,_get_locale, _get_model,_show_vk, _hide_vk,_set_screen_orient,_get_unique_id, _get_system_dir, _play_video,_is_video_playing, _pause_video, _stop_video, _set_keep_screen_on, use_apk_expansion);
os_android->set_need_reload_hooks(p_need_reload_hook);
char wd[500];
@@ -897,7 +911,7 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_initialize(JNIEnv * env,
}
-JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_resize(JNIEnv * env, jobject obj, jint width, jint height, jboolean reload) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv * env, jobject obj, jint width, jint height, jboolean reload) {
__android_log_print(ANDROID_LOG_INFO,"godot","^_^_^_^_^ resize %lld, %i, %i\n",Thread::get_caller_ID(),width,height);
if (os_android)
@@ -912,18 +926,24 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_resize(JNIEnv * env, jobj
}
-JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_newcontext(JNIEnv * env, jobject obj) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv * env, jobject obj,bool p_32_bits) {
__android_log_print(ANDROID_LOG_INFO,"godot","^_^_^_^_^ newcontext %lld\n",Thread::get_caller_ID());
+
+ if (os_android) {
+ os_android->set_context_is_16_bits(!p_32_bits);
+ }
+
if (os_android && step > 0) {
os_android->reload_gfx();
}
+
}
-JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_quit(JNIEnv * env, jobject obj) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_quit(JNIEnv * env, jobject obj) {
input_mutex->lock();
quit_request=true;
@@ -944,7 +964,7 @@ static void _initialize_java_modules() {
JNIEnv *env = ThreadAndroid::get_env();
- jclass activityClass = env->FindClass("com/android/godot/Godot");
+ jclass activityClass = env->FindClass("org/godotengine/godot/Godot");
jmethodID getClassLoader = env->GetMethodID(activityClass,"getClassLoader", "()Ljava/lang/ClassLoader;");
@@ -973,7 +993,7 @@ static void _initialize_java_modules() {
//singletonClass=(jclass)env->NewGlobalRef(singletonClass);
__android_log_print(ANDROID_LOG_INFO,"godot","****^*^*?^*^*class data %x",singletonClass);
- jmethodID initialize = env->GetStaticMethodID(singletonClass, "initialize", "(Landroid/app/Activity;)Lcom/android/godot/Godot$SingletonBase;");
+ jmethodID initialize = env->GetStaticMethodID(singletonClass, "initialize", "(Landroid/app/Activity;)Lorg/godotengine/godot/Godot$SingletonBase;");
if (!initialize) {
@@ -993,7 +1013,7 @@ static void _initialize_java_modules() {
}
-JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_step(JNIEnv * env, jobject obj)
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv * env, jobject obj)
{
@@ -1060,7 +1080,7 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_step(JNIEnv * env, jobjec
if (os_android->main_loop_iterate()==true) {
- jclass cls = env->FindClass("com/android/godot/Godot");
+ jclass cls = env->FindClass("org/godotengine/godot/Godot");
jmethodID _finish = env->GetMethodID(cls, "forceQuit", "()V");
env->CallVoidMethod(_godot_instance, _finish);
__android_log_print(ANDROID_LOG_INFO,"godot","**FINISH REQUEST!!! - %p-%i\n",env,Thread::get_caller_ID());
@@ -1071,7 +1091,7 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_step(JNIEnv * env, jobjec
}
-JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_touch(JNIEnv * env, jobject obj, jint ev,jint pointer, jint count, jintArray positions) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch(JNIEnv * env, jobject obj, jint ev,jint pointer, jint count, jintArray positions) {
@@ -1376,7 +1396,7 @@ static int find_device(int p_device) {
return joy_device_ids.size() - 1;
};
-JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_joybutton(JNIEnv * env, jobject obj, jint p_device, jint p_button, jboolean p_pressed) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv * env, jobject obj, jint p_device, jint p_button, jboolean p_pressed) {
InputEvent ievent;
ievent.type = InputEvent::JOYSTICK_BUTTON;
@@ -1389,7 +1409,7 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_joybutton(JNIEnv * env, j
input_mutex->unlock();
};
-JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_joyaxis(JNIEnv * env, jobject obj, jint p_device, jint p_axis, jfloat p_value) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv * env, jobject obj, jint p_device, jint p_axis, jfloat p_value) {
InputEvent ievent;
ievent.type = InputEvent::JOYSTICK_MOTION;
@@ -1403,7 +1423,7 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_joyaxis(JNIEnv * env, job
};
-JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_key(JNIEnv * env, jobject obj, jint p_scancode, jint p_unicode_char, jboolean p_pressed) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv * env, jobject obj, jint p_scancode, jint p_unicode_char, jboolean p_pressed) {
InputEvent ievent;
ievent.type = InputEvent::KEY;
@@ -1441,7 +1461,7 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_key(JNIEnv * env, jobject
};
-JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_accelerometer(JNIEnv * env, jobject obj, jfloat x, jfloat y, jfloat z) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv * env, jobject obj, jfloat x, jfloat y, jfloat z) {
input_mutex->lock();
accelerometer=Vector3(x,y,z);
@@ -1449,7 +1469,7 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_accelerometer(JNIEnv * en
}
-JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_focusin(JNIEnv * env, jobject obj){
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusin(JNIEnv * env, jobject obj){
if (!suspend_mutex)
return;
@@ -1461,7 +1481,7 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_focusin(JNIEnv * env, job
suspend_mutex->unlock();
}
-JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_focusout(JNIEnv * env, jobject obj){
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusout(JNIEnv * env, jobject obj){
if (!suspend_mutex)
return;
@@ -1476,7 +1496,7 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_focusout(JNIEnv * env, jo
-JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_audio(JNIEnv * env, jobject obj) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_audio(JNIEnv * env, jobject obj) {
ThreadAndroid::setup_thread();
AudioDriverAndroid::thread_func(env);
@@ -1485,7 +1505,7 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_audio(JNIEnv * env, jobje
}
-JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_singleton(JNIEnv * env, jobject obj, jstring name,jobject p_object){
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_singleton(JNIEnv * env, jobject obj, jstring name,jobject p_object){
String singname = env->GetStringUTFChars( name, NULL );
JNISingleton *s = memnew( JNISingleton );
@@ -1514,7 +1534,7 @@ static Variant::Type get_jni_type(const String& p_type) {
{"[B",Variant::RAW_ARRAY},
{"[F",Variant::REAL_ARRAY},
{"[java.lang.String",Variant::STRING_ARRAY},
- {"com.android.godot.Dictionary", Variant::DICTIONARY},
+ {"org.godotengine.godot.Dictionary", Variant::DICTIONARY},
{NULL,Variant::NIL}
};
@@ -1545,7 +1565,7 @@ static const char* get_jni_sig(const String& p_type) {
{"float","F"},
{"double","D"},
{"java.lang.String","Ljava/lang/String;"},
- {"com.android.godot.Dictionary", "Lcom/android/godot/Dictionary;"},
+ {"org.godotengine.godot.Dictionary", "Lorg/godotengine/godot/Dictionary;"},
{"[I","[I"},
{"[B","[B"},
{"[F","[F"},
@@ -1567,7 +1587,7 @@ static const char* get_jni_sig(const String& p_type) {
return "Ljava/lang/Object;";
}
-JNIEXPORT jstring JNICALL Java_com_android_godot_GodotLib_getGlobal(JNIEnv * env, jobject obj, jstring path) {
+JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getGlobal(JNIEnv * env, jobject obj, jstring path) {
String js = env->GetStringUTFChars( path, NULL );
@@ -1577,7 +1597,7 @@ JNIEXPORT jstring JNICALL Java_com_android_godot_GodotLib_getGlobal(JNIEnv * env
}
-JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_method(JNIEnv * env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args){
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_method(JNIEnv * env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args){
String singname = env->GetStringUTFChars( sname, NULL );
@@ -1618,7 +1638,7 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_method(JNIEnv * env, jobj
}
-JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_callobject(JNIEnv * env, jobject p_obj, jint ID, jstring method, jobjectArray params) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv * env, jobject p_obj, jint ID, jstring method, jobjectArray params) {
Object* obj = ObjectDB::get_instance(ID);
ERR_FAIL_COND(!obj);
@@ -1653,7 +1673,7 @@ JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_callobject(JNIEnv * env,
};
-JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_calldeferred(JNIEnv * env, jobject p_obj, jint ID, jstring method, jobjectArray params) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv * env, jobject p_obj, jint ID, jstring method, jobjectArray params) {
Object* obj = ObjectDB::get_instance(ID);
diff --git a/platform/android/java_glue.h b/platform/android/java_glue.h
index 57a4cc8651..efa5b2839d 100644
--- a/platform/android/java_glue.h
+++ b/platform/android/java_glue.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -36,24 +36,24 @@
extern "C" {
- JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_initialize(JNIEnv * env, jobject obj, jobject activity,jboolean p_need_reload_hook, jobjectArray p_cmdline);
- JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_resize(JNIEnv * env, jobject obj, jint width, jint height, jboolean reload);
- JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_newcontext(JNIEnv * env, jobject obj);
- JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_step(JNIEnv * env, jobject obj);
- JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_quit(JNIEnv * env, jobject obj);
- JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_touch(JNIEnv * env, jobject obj, jint ev,jint pointer, jint count, jintArray positions);
- JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_key(JNIEnv * env, jobject obj, jint p_scancode, jint p_unicode_char, jboolean p_pressed);
- JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_joybutton(JNIEnv * env, jobject obj, jint p_device, jint p_button, jboolean p_pressed);
- JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_joyaxis(JNIEnv * env, jobject obj, jint p_device, jint p_axis, jfloat p_value);
- JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_audio(JNIEnv * env, jobject obj);
- JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_accelerometer(JNIEnv * env, jobject obj, jfloat x, jfloat y, jfloat z);
- JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_focusin(JNIEnv * env, jobject obj);
- JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_focusout(JNIEnv * env, jobject obj);
- JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_singleton(JNIEnv * env, jobject obj, jstring name,jobject p_object);
- JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_method(JNIEnv * env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args);
- JNIEXPORT jstring JNICALL Java_com_android_godot_GodotLib_getGlobal(JNIEnv * env, jobject obj, jstring path);
- JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_callobject(JNIEnv * env, jobject obj, jint ID, jstring method, jobjectArray params);
- JNIEXPORT void JNICALL Java_com_android_godot_GodotLib_calldeferred(JNIEnv * env, jobject obj, jint ID, jstring method, jobjectArray params);
+ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_initialize(JNIEnv * env, jobject obj, jobject activity,jboolean p_need_reload_hook, jobjectArray p_cmdline,jobject p_asset_manager);
+ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_resize(JNIEnv * env, jobject obj, jint width, jint height, jboolean reload);
+ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv * env, jobject obj, bool p_32_bits);
+ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv * env, jobject obj);
+ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_quit(JNIEnv * env, jobject obj);
+ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_touch(JNIEnv * env, jobject obj, jint ev,jint pointer, jint count, jintArray positions);
+ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_key(JNIEnv * env, jobject obj, jint p_scancode, jint p_unicode_char, jboolean p_pressed);
+ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joybutton(JNIEnv * env, jobject obj, jint p_device, jint p_button, jboolean p_pressed);
+ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_joyaxis(JNIEnv * env, jobject obj, jint p_device, jint p_axis, jfloat p_value);
+ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_audio(JNIEnv * env, jobject obj);
+ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_accelerometer(JNIEnv * env, jobject obj, jfloat x, jfloat y, jfloat z);
+ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusin(JNIEnv * env, jobject obj);
+ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusout(JNIEnv * env, jobject obj);
+ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_singleton(JNIEnv * env, jobject obj, jstring name,jobject p_object);
+ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_method(JNIEnv * env, jobject obj, jstring sname, jstring name, jstring ret, jobjectArray args);
+ JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getGlobal(JNIEnv * env, jobject obj, jstring path);
+ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv * env, jobject obj, jint ID, jstring method, jobjectArray params);
+ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv * env, jobject obj, jint ID, jstring method, jobjectArray params);
};
diff --git a/platform/android/libs/apk_expansion/AndroidManifest.xml b/platform/android/libs/apk_expansion/AndroidManifest.xml
deleted file mode 100644
index 20b74a2988..0000000000
--- a/platform/android/libs/apk_expansion/AndroidManifest.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.vending.expansion.downloader"
- android:versionCode="2"
- android:versionName="1.1" >
-
- <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="15"/>
-
-</manifest> \ No newline at end of file
diff --git a/platform/android/libs/apk_expansion/build.xml b/platform/android/libs/apk_expansion/build.xml
deleted file mode 100644
index 5b2f2c590e..0000000000
--- a/platform/android/libs/apk_expansion/build.xml
+++ /dev/null
@@ -1,92 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project name="apk_expansion" default="help">
-
- <!-- The local.properties file is created and updated by the 'android' tool.
- It contains the path to the SDK. It should *NOT* be checked into
- Version Control Systems. -->
- <property file="local.properties" />
-
- <!-- The ant.properties file can be created by you. It is only edited by the
- 'android' tool to add properties to it.
- This is the place to change some Ant specific build properties.
- Here are some properties you may want to change/update:
-
- source.dir
- The name of the source directory. Default is 'src'.
- out.dir
- The name of the output directory. Default is 'bin'.
-
- For other overridable properties, look at the beginning of the rules
- files in the SDK, at tools/ant/build.xml
-
- Properties related to the SDK location or the project target should
- be updated using the 'android' tool with the 'update' action.
-
- This file is an integral part of the build system for your
- application and should be checked into Version Control Systems.
-
- -->
- <property file="ant.properties" />
-
- <!-- if sdk.dir was not set from one of the property file, then
- get it from the ANDROID_HOME env var.
- This must be done before we load project.properties since
- the proguard config can use sdk.dir -->
- <property environment="env" />
- <condition property="sdk.dir" value="${env.ANDROID_HOME}">
- <isset property="env.ANDROID_HOME" />
- </condition>
-
- <!-- The project.properties file is created and updated by the 'android'
- tool, as well as ADT.
-
- This contains project specific properties such as project target, and library
- dependencies. Lower level build properties are stored in ant.properties
- (or in .classpath for Eclipse projects).
-
- This file is an integral part of the build system for your
- application and should be checked into Version Control Systems. -->
- <loadproperties srcFile="project.properties" />
-
- <!-- quick check on sdk.dir -->
- <fail
- message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
- unless="sdk.dir"
- />
-
- <!--
- Import per project custom build rules if present at the root of the project.
- This is the place to put custom intermediary targets such as:
- -pre-build
- -pre-compile
- -post-compile (This is typically used for code obfuscation.
- Compiled code location: ${out.classes.absolute.dir}
- If this is not done in place, override ${out.dex.input.absolute.dir})
- -post-package
- -post-build
- -pre-clean
- -->
- <import file="custom_rules.xml" optional="true" />
-
- <!-- Import the actual build file.
-
- To customize existing targets, there are two options:
- - Customize only one target:
- - copy/paste the target into this file, *before* the
- <import> task.
- - customize it to your needs.
- - Customize the whole content of build.xml
- - copy/paste the content of the rules files (minus the top node)
- into this file, replacing the <import> task.
- - customize to your needs.
-
- ***********************
- ****** IMPORTANT ******
- ***********************
- In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
- in order to avoid having your file be overridden by tools such as "android update project"
- -->
- <!-- version-tag: 1 -->
- <import file="${sdk.dir}/tools/ant/build.xml" />
-
-</project>
diff --git a/platform/android/libs/apk_expansion/proguard-project.txt b/platform/android/libs/apk_expansion/proguard-project.txt
deleted file mode 100644
index f2fe1559a2..0000000000
--- a/platform/android/libs/apk_expansion/proguard-project.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-# To enable ProGuard in your project, edit project.properties
-# to define the proguard.config property as described in that file.
-#
-# Add project specific ProGuard rules here.
-# By default, the flags in this file are appended to flags specified
-# in ${sdk.dir}/tools/proguard/proguard-android.txt
-# You can edit the include path and order by changing the ProGuard
-# include property in project.properties.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# Add any project specific keep options here:
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
diff --git a/platform/android/libs/apk_expansion/project.properties b/platform/android/libs/apk_expansion/project.properties
deleted file mode 100644
index eda83430bf..0000000000
--- a/platform/android/libs/apk_expansion/project.properties
+++ /dev/null
@@ -1,13 +0,0 @@
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must be checked in Version Control Systems.
-#
-# To customize properties used by the Ant build system use,
-# "ant.properties", and override values to adapt the script to your
-# project structure.
-
-# Project target.
-target=android-15
-android.library=true
-android.library.reference.1=../play_licensing
diff --git a/platform/android/libs/apk_expansion/res/values/strings.xml b/platform/android/libs/apk_expansion/res/values/strings.xml
deleted file mode 100644
index b84749faf2..0000000000
--- a/platform/android/libs/apk_expansion/res/values/strings.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-
- <!-- When a download completes, a notification is displayed, and this
- string is used to indicate that the download successfully completed.
- Note that such a download could have been initiated by a variety of
- applications, including (but not limited to) the browser, an email
- application, a content marketplace. -->
- <string name="notification_download_complete">Download complete</string>
-
- <!-- When a download completes, a notification is displayed, and this
- string is used to indicate that the download failed.
- Note that such a download could have been initiated by a variety of
- applications, including (but not limited to) the browser, an email
- application, a content marketplace. -->
- <string name="notification_download_failed">Download unsuccessful</string>
-
-
- <string name="state_unknown">Starting..."</string>
- <string name="state_idle">Waiting for download to start</string>
- <string name="state_fetching_url">Looking for resources to download</string>
- <string name="state_connecting">Connecting to the download server</string>
- <string name="state_downloading">Downloading resources</string>
- <string name="state_completed">Download finished</string>
- <string name="state_paused_network_unavailable">Download paused because no network is available</string>
- <string name="state_paused_network_setup_failure">Download paused. Test a website in browser</string>
- <string name="state_paused_by_request">Download paused</string>
- <string name="state_paused_wifi_unavailable">Download paused because wifi is unavailable</string>
- <string name="state_paused_wifi_disabled">Download paused because wifi is disabled</string>
- <string name="state_paused_roaming">Download paused because you are roaming</string>
- <string name="state_paused_sdcard_unavailable">Download paused because the external storage is unavailable</string>
- <string name="state_failed_unlicensed">Download failed because you may not have purchased this app</string>
- <string name="state_failed_fetching_url">Download failed because the resources could not be found</string>
- <string name="state_failed_sdcard_full">Download failed because the external storage is full</string>
- <string name="state_failed_cancelled">Download cancelled</string>
- <string name="state_failed">Download failed</string>
-
- <string name="kilobytes_per_second">%1$s KB/s</string>
- <string name="time_remaining">Time remaining: %1$s</string>
- <string name="time_remaining_notification">%1$s left</string>
-</resources> \ No newline at end of file
diff --git a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/Helpers.java b/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/Helpers.java
deleted file mode 100644
index 1e84e54a0f..0000000000
--- a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/Helpers.java
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.vending.expansion.downloader;
-
-import com.android.vending.expansion.downloader.R;
-
-import android.content.Context;
-import android.os.Environment;
-import android.os.StatFs;
-import android.os.SystemClock;
-import android.util.Log;
-
-import java.io.File;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Locale;
-import java.util.Random;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Some helper functions for the download manager
- */
-public class Helpers {
-
- public static Random sRandom = new Random(SystemClock.uptimeMillis());
-
- /** Regex used to parse content-disposition headers */
- private static final Pattern CONTENT_DISPOSITION_PATTERN = Pattern
- .compile("attachment;\\s*filename\\s*=\\s*\"([^\"]*)\"");
-
- private Helpers() {
- }
-
- /*
- * Parse the Content-Disposition HTTP Header. The format of the header is
- * defined here: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html This
- * header provides a filename for content that is going to be downloaded to
- * the file system. We only support the attachment type.
- */
- static String parseContentDisposition(String contentDisposition) {
- try {
- Matcher m = CONTENT_DISPOSITION_PATTERN.matcher(contentDisposition);
- if (m.find()) {
- return m.group(1);
- }
- } catch (IllegalStateException ex) {
- // This function is defined as returning null when it can't parse
- // the header
- }
- return null;
- }
-
- /**
- * @return the root of the filesystem containing the given path
- */
- public static File getFilesystemRoot(String path) {
- File cache = Environment.getDownloadCacheDirectory();
- if (path.startsWith(cache.getPath())) {
- return cache;
- }
- File external = Environment.getExternalStorageDirectory();
- if (path.startsWith(external.getPath())) {
- return external;
- }
- throw new IllegalArgumentException(
- "Cannot determine filesystem root for " + path);
- }
-
- public static boolean isExternalMediaMounted() {
- if (!Environment.getExternalStorageState().equals(
- Environment.MEDIA_MOUNTED)) {
- // No SD card found.
- if ( Constants.LOGVV ) {
- Log.d(Constants.TAG, "no external storage");
- }
- return false;
- }
- return true;
- }
-
- /**
- * @return the number of bytes available on the filesystem rooted at the
- * given File
- */
- public static long getAvailableBytes(File root) {
- StatFs stat = new StatFs(root.getPath());
- // put a bit of margin (in case creating the file grows the system by a
- // few blocks)
- long availableBlocks = (long) stat.getAvailableBlocks() - 4;
- return stat.getBlockSize() * availableBlocks;
- }
-
- /**
- * Checks whether the filename looks legitimate
- */
- public static boolean isFilenameValid(String filename) {
- filename = filename.replaceFirst("/+", "/"); // normalize leading
- // slashes
- return filename.startsWith(Environment.getDownloadCacheDirectory().toString())
- || filename.startsWith(Environment.getExternalStorageDirectory().toString());
- }
-
- /*
- * Delete the given file from device
- */
- /* package */static void deleteFile(String path) {
- try {
- File file = new File(path);
- file.delete();
- } catch (Exception e) {
- Log.w(Constants.TAG, "file: '" + path + "' couldn't be deleted", e);
- }
- }
-
- /**
- * Showing progress in MB here. It would be nice to choose the unit (KB, MB,
- * GB) based on total file size, but given what we know about the expected
- * ranges of file sizes for APK expansion files, it's probably not necessary.
- *
- * @param overallProgress
- * @param overallTotal
- * @return
- */
-
- static public String getDownloadProgressString(long overallProgress, long overallTotal) {
- if (overallTotal == 0) {
- if ( Constants.LOGVV ) {
- Log.e(Constants.TAG, "Notification called when total is zero");
- }
- return "";
- }
- return String.format("%.2f",
- (float) overallProgress / (1024.0f * 1024.0f))
- + "MB /" +
- String.format("%.2f", (float) overallTotal /
- (1024.0f * 1024.0f)) + "MB";
- }
-
- /**
- * Adds a percentile to getDownloadProgressString.
- *
- * @param overallProgress
- * @param overallTotal
- * @return
- */
- static public String getDownloadProgressStringNotification(long overallProgress,
- long overallTotal) {
- if (overallTotal == 0) {
- if ( Constants.LOGVV ) {
- Log.e(Constants.TAG, "Notification called when total is zero");
- }
- return "";
- }
- return getDownloadProgressString(overallProgress, overallTotal) + " (" +
- getDownloadProgressPercent(overallProgress, overallTotal) + ")";
- }
-
- public static String getDownloadProgressPercent(long overallProgress, long overallTotal) {
- if (overallTotal == 0) {
- if ( Constants.LOGVV ) {
- Log.e(Constants.TAG, "Notification called when total is zero");
- }
- return "";
- }
- return Long.toString(overallProgress * 100 / overallTotal) + "%";
- }
-
- public static String getSpeedString(float bytesPerMillisecond) {
- return String.format("%.2f", bytesPerMillisecond * 1000 / 1024);
- }
-
- public static String getTimeRemaining(long durationInMilliseconds) {
- SimpleDateFormat sdf;
- if (durationInMilliseconds > 1000 * 60 * 60) {
- sdf = new SimpleDateFormat("HH:mm", Locale.getDefault());
- } else {
- sdf = new SimpleDateFormat("mm:ss", Locale.getDefault());
- }
- return sdf.format(new Date(durationInMilliseconds - TimeZone.getDefault().getRawOffset()));
- }
-
- /**
- * Returns the file name (without full path) for an Expansion APK file from
- * the given context.
- *
- * @param c the context
- * @param mainFile true for main file, false for patch file
- * @param versionCode the version of the file
- * @return String the file name of the expansion file
- */
- public static String getExpansionAPKFileName(Context c, boolean mainFile, int versionCode) {
- return (mainFile ? "main." : "patch.") + versionCode + "." + c.getPackageName() + ".obb";
- }
-
- /**
- * Returns the filename (where the file should be saved) from info about a
- * download
- */
- static public String generateSaveFileName(Context c, String fileName) {
- String path = getSaveFilePath(c)
- + File.separator + fileName;
- return path;
- }
-
- static public String getSaveFilePath(Context c) {
- File root = Environment.getExternalStorageDirectory();
- String path = root.toString() + Constants.EXP_PATH + c.getPackageName();
- return path;
- }
-
- /**
- * Helper function to ascertain the existence of a file and return
- * true/false appropriately
- *
- * @param c the app/activity/service context
- * @param fileName the name (sans path) of the file to query
- * @param fileSize the size that the file must match
- * @param deleteFileOnMismatch if the file sizes do not match, delete the
- * file
- * @return true if it does exist, false otherwise
- */
- static public boolean doesFileExist(Context c, String fileName, long fileSize,
- boolean deleteFileOnMismatch) {
- // the file may have been delivered by Market --- let's make sure
- // it's the size we expect
- File fileForNewFile = new File(Helpers.generateSaveFileName(c, fileName));
- if (fileForNewFile.exists()) {
- if (fileForNewFile.length() == fileSize) {
- return true;
- }
- if (deleteFileOnMismatch) {
- // delete the file --- we won't be able to resume
- // because we cannot confirm the integrity of the file
- fileForNewFile.delete();
- }
- }
- return false;
- }
-
- /**
- * Converts download states that are returned by the {@link
- * IDownloaderClient#onDownloadStateChanged} callback into usable strings.
- * This is useful if using the state strings built into the library to display user messages.
- * @param state One of the STATE_* constants from {@link IDownloaderClient}.
- * @return string resource ID for the corresponding string.
- */
- static public int getDownloaderStringResourceIDFromState(int state) {
- switch (state) {
- case IDownloaderClient.STATE_IDLE:
- return R.string.state_idle;
- case IDownloaderClient.STATE_FETCHING_URL:
- return R.string.state_fetching_url;
- case IDownloaderClient.STATE_CONNECTING:
- return R.string.state_connecting;
- case IDownloaderClient.STATE_DOWNLOADING:
- return R.string.state_downloading;
- case IDownloaderClient.STATE_COMPLETED:
- return R.string.state_completed;
- case IDownloaderClient.STATE_PAUSED_NETWORK_UNAVAILABLE:
- return R.string.state_paused_network_unavailable;
- case IDownloaderClient.STATE_PAUSED_BY_REQUEST:
- return R.string.state_paused_by_request;
- case IDownloaderClient.STATE_PAUSED_WIFI_DISABLED_NEED_CELLULAR_PERMISSION:
- return R.string.state_paused_wifi_disabled;
- case IDownloaderClient.STATE_PAUSED_NEED_CELLULAR_PERMISSION:
- return R.string.state_paused_wifi_unavailable;
- case IDownloaderClient.STATE_PAUSED_WIFI_DISABLED:
- return R.string.state_paused_wifi_disabled;
- case IDownloaderClient.STATE_PAUSED_NEED_WIFI:
- return R.string.state_paused_wifi_unavailable;
- case IDownloaderClient.STATE_PAUSED_ROAMING:
- return R.string.state_paused_roaming;
- case IDownloaderClient.STATE_PAUSED_NETWORK_SETUP_FAILURE:
- return R.string.state_paused_network_setup_failure;
- case IDownloaderClient.STATE_PAUSED_SDCARD_UNAVAILABLE:
- return R.string.state_paused_sdcard_unavailable;
- case IDownloaderClient.STATE_FAILED_UNLICENSED:
- return R.string.state_failed_unlicensed;
- case IDownloaderClient.STATE_FAILED_FETCHING_URL:
- return R.string.state_failed_fetching_url;
- case IDownloaderClient.STATE_FAILED_SDCARD_FULL:
- return R.string.state_failed_sdcard_full;
- case IDownloaderClient.STATE_FAILED_CANCELED:
- return R.string.state_failed_cancelled;
- default:
- return R.string.state_unknown;
- }
- }
-
-}
diff --git a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java b/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java
deleted file mode 100644
index eef205d7b7..0000000000
--- a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.vending.expansion.downloader.impl;
-
-import com.android.vending.expansion.downloader.R;
-import com.google.android.vending.expansion.downloader.DownloadProgressInfo;
-import com.google.android.vending.expansion.downloader.DownloaderClientMarshaller;
-import com.google.android.vending.expansion.downloader.Helpers;
-import com.google.android.vending.expansion.downloader.IDownloaderClient;
-
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.os.Messenger;
-
-/**
- * This class handles displaying the notification associated with the download
- * queue going on in the download manager. It handles multiple status types;
- * Some require user interaction and some do not. Some of the user interactions
- * may be transient. (for example: the user is queried to continue the download
- * on 3G when it started on WiFi, but then the phone locks onto WiFi again so
- * the prompt automatically goes away)
- * <p/>
- * The application interface for the downloader also needs to understand and
- * handle these transient states.
- */
-public class DownloadNotification implements IDownloaderClient {
-
- private int mState;
- private final Context mContext;
- private final NotificationManager mNotificationManager;
- private String mCurrentTitle;
-
- private IDownloaderClient mClientProxy;
- final ICustomNotification mCustomNotification;
- private Notification mNotification;
- private Notification mCurrentNotification;
- private CharSequence mLabel;
- private String mCurrentText;
- private PendingIntent mContentIntent;
- private DownloadProgressInfo mProgressInfo;
-
- static final String LOGTAG = "DownloadNotification";
- static final int NOTIFICATION_ID = LOGTAG.hashCode();
-
- public PendingIntent getClientIntent() {
- return mContentIntent;
- }
-
- public void setClientIntent(PendingIntent mClientIntent) {
- this.mContentIntent = mClientIntent;
- }
-
- public void resendState() {
- if (null != mClientProxy) {
- mClientProxy.onDownloadStateChanged(mState);
- }
- }
-
- @Override
- public void onDownloadStateChanged(int newState) {
- if (null != mClientProxy) {
- mClientProxy.onDownloadStateChanged(newState);
- }
- if (newState != mState) {
- mState = newState;
- if (newState == IDownloaderClient.STATE_IDLE || null == mContentIntent) {
- return;
- }
- int stringDownloadID;
- int iconResource;
- boolean ongoingEvent;
-
- // get the new title string and paused text
- switch (newState) {
- case 0:
- iconResource = android.R.drawable.stat_sys_warning;
- stringDownloadID = R.string.state_unknown;
- ongoingEvent = false;
- break;
-
- case IDownloaderClient.STATE_DOWNLOADING:
- iconResource = android.R.drawable.stat_sys_download;
- stringDownloadID = Helpers.getDownloaderStringResourceIDFromState(newState);
- ongoingEvent = true;
- break;
-
- case IDownloaderClient.STATE_FETCHING_URL:
- case IDownloaderClient.STATE_CONNECTING:
- iconResource = android.R.drawable.stat_sys_download_done;
- stringDownloadID = Helpers.getDownloaderStringResourceIDFromState(newState);
- ongoingEvent = true;
- break;
-
- case IDownloaderClient.STATE_COMPLETED:
- case IDownloaderClient.STATE_PAUSED_BY_REQUEST:
- iconResource = android.R.drawable.stat_sys_download_done;
- stringDownloadID = Helpers.getDownloaderStringResourceIDFromState(newState);
- ongoingEvent = false;
- break;
-
- case IDownloaderClient.STATE_FAILED:
- case IDownloaderClient.STATE_FAILED_CANCELED:
- case IDownloaderClient.STATE_FAILED_FETCHING_URL:
- case IDownloaderClient.STATE_FAILED_SDCARD_FULL:
- case IDownloaderClient.STATE_FAILED_UNLICENSED:
- iconResource = android.R.drawable.stat_sys_warning;
- stringDownloadID = Helpers.getDownloaderStringResourceIDFromState(newState);
- ongoingEvent = false;
- break;
-
- default:
- iconResource = android.R.drawable.stat_sys_warning;
- stringDownloadID = Helpers.getDownloaderStringResourceIDFromState(newState);
- ongoingEvent = true;
- break;
- }
- mCurrentText = mContext.getString(stringDownloadID);
- mCurrentTitle = mLabel.toString();
- mCurrentNotification.tickerText = mLabel + ": " + mCurrentText;
- mCurrentNotification.icon = iconResource;
- mCurrentNotification.setLatestEventInfo(mContext, mCurrentTitle, mCurrentText,
- mContentIntent);
- if (ongoingEvent) {
- mCurrentNotification.flags |= Notification.FLAG_ONGOING_EVENT;
- } else {
- mCurrentNotification.flags &= ~Notification.FLAG_ONGOING_EVENT;
- mCurrentNotification.flags |= Notification.FLAG_AUTO_CANCEL;
- }
- mNotificationManager.notify(NOTIFICATION_ID, mCurrentNotification);
- }
- }
-
- @Override
- public void onDownloadProgress(DownloadProgressInfo progress) {
- mProgressInfo = progress;
- if (null != mClientProxy) {
- mClientProxy.onDownloadProgress(progress);
- }
- if (progress.mOverallTotal <= 0) {
- // we just show the text
- mNotification.tickerText = mCurrentTitle;
- mNotification.icon = android.R.drawable.stat_sys_download;
- mNotification.setLatestEventInfo(mContext, mLabel, mCurrentText, mContentIntent);
- mCurrentNotification = mNotification;
- } else {
- mCustomNotification.setCurrentBytes(progress.mOverallProgress);
- mCustomNotification.setTotalBytes(progress.mOverallTotal);
- mCustomNotification.setIcon(android.R.drawable.stat_sys_download);
- mCustomNotification.setPendingIntent(mContentIntent);
- mCustomNotification.setTicker(mLabel + ": " + mCurrentText);
- mCustomNotification.setTitle(mLabel);
- mCustomNotification.setTimeRemaining(progress.mTimeRemaining);
- mCurrentNotification = mCustomNotification.updateNotification(mContext);
- }
- mNotificationManager.notify(NOTIFICATION_ID, mCurrentNotification);
- }
-
- public interface ICustomNotification {
- void setTitle(CharSequence title);
-
- void setTicker(CharSequence ticker);
-
- void setPendingIntent(PendingIntent mContentIntent);
-
- void setTotalBytes(long totalBytes);
-
- void setCurrentBytes(long currentBytes);
-
- void setIcon(int iconResource);
-
- void setTimeRemaining(long timeRemaining);
-
- Notification updateNotification(Context c);
- }
-
- /**
- * Called in response to onClientUpdated. Creates a new proxy and notifies
- * it of the current state.
- *
- * @param msg the client Messenger to notify
- */
- public void setMessenger(Messenger msg) {
- mClientProxy = DownloaderClientMarshaller.CreateProxy(msg);
- if (null != mProgressInfo) {
- mClientProxy.onDownloadProgress(mProgressInfo);
- }
- if (mState != -1) {
- mClientProxy.onDownloadStateChanged(mState);
- }
- }
-
- /**
- * Constructor
- *
- * @param ctx The context to use to obtain access to the Notification
- * Service
- */
- DownloadNotification(Context ctx, CharSequence applicationLabel) {
- mState = -1;
- mContext = ctx;
- mLabel = applicationLabel;
- mNotificationManager = (NotificationManager)
- mContext.getSystemService(Context.NOTIFICATION_SERVICE);
- mCustomNotification = CustomNotificationFactory
- .createCustomNotification();
- mNotification = new Notification();
- mCurrentNotification = mNotification;
-
- }
-
- @Override
- public void onServiceConnected(Messenger m) {
- }
-
-}
diff --git a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/V14CustomNotification.java b/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/V14CustomNotification.java
deleted file mode 100644
index e736603e2a..0000000000
--- a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/V14CustomNotification.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.vending.expansion.downloader.impl;
-
-import com.android.vending.expansion.downloader.R;
-import com.google.android.vending.expansion.downloader.Helpers;
-
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.content.Context;
-
-public class V14CustomNotification implements DownloadNotification.ICustomNotification {
-
- CharSequence mTitle;
- CharSequence mTicker;
- int mIcon;
- long mTotalKB = -1;
- long mCurrentKB = -1;
- long mTimeRemaining;
- PendingIntent mPendingIntent;
-
- @Override
- public void setIcon(int icon) {
- mIcon = icon;
- }
-
- @Override
- public void setTitle(CharSequence title) {
- mTitle = title;
- }
-
- @Override
- public void setTotalBytes(long totalBytes) {
- mTotalKB = totalBytes;
- }
-
- @Override
- public void setCurrentBytes(long currentBytes) {
- mCurrentKB = currentBytes;
- }
-
- void setProgress(Notification.Builder builder) {
-
- }
-
- @Override
- public Notification updateNotification(Context c) {
- Notification.Builder builder = new Notification.Builder(c);
- builder.setContentTitle(mTitle);
- if (mTotalKB > 0 && -1 != mCurrentKB) {
- builder.setProgress((int) (mTotalKB >> 8), (int) (mCurrentKB >> 8), false);
- } else {
- builder.setProgress(0, 0, true);
- }
- builder.setContentText(Helpers.getDownloadProgressString(mCurrentKB, mTotalKB));
- builder.setContentInfo(c.getString(R.string.time_remaining_notification,
- Helpers.getTimeRemaining(mTimeRemaining)));
- if (mIcon != 0) {
- builder.setSmallIcon(mIcon);
- } else {
- int iconResource = android.R.drawable.stat_sys_download;
- builder.setSmallIcon(iconResource);
- }
- builder.setOngoing(true);
- builder.setTicker(mTicker);
- builder.setContentIntent(mPendingIntent);
- builder.setOnlyAlertOnce(true);
-
- return builder.getNotification();
- }
-
- @Override
- public void setPendingIntent(PendingIntent contentIntent) {
- mPendingIntent = contentIntent;
- }
-
- @Override
- public void setTicker(CharSequence ticker) {
- mTicker = ticker;
- }
-
- @Override
- public void setTimeRemaining(long timeRemaining) {
- mTimeRemaining = timeRemaining;
- }
-
-}
diff --git a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/V3CustomNotification.java b/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/V3CustomNotification.java
deleted file mode 100644
index e3666e05b9..0000000000
--- a/platform/android/libs/apk_expansion/src/com/google/android/vending/expansion/downloader/impl/V3CustomNotification.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.vending.expansion.downloader.impl;
-
-import com.android.vending.expansion.downloader.R;
-import com.google.android.vending.expansion.downloader.Helpers;
-
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.graphics.BitmapFactory;
-import android.view.View;
-import android.widget.RemoteViews;
-
-public class V3CustomNotification implements DownloadNotification.ICustomNotification {
-
- CharSequence mTitle;
- CharSequence mTicker;
- int mIcon;
- long mTotalBytes = -1;
- long mCurrentBytes = -1;
- long mTimeRemaining;
- PendingIntent mPendingIntent;
- Notification mNotification = new Notification();
-
- @Override
- public void setIcon(int icon) {
- mIcon = icon;
- }
-
- @Override
- public void setTitle(CharSequence title) {
- mTitle = title;
- }
-
- @Override
- public void setTotalBytes(long totalBytes) {
- mTotalBytes = totalBytes;
- }
-
- @Override
- public void setCurrentBytes(long currentBytes) {
- mCurrentBytes = currentBytes;
- }
-
- @Override
- public Notification updateNotification(Context c) {
- Notification n = mNotification;
-
- n.icon = mIcon;
-
- n.flags |= Notification.FLAG_ONGOING_EVENT;
-
- if (android.os.Build.VERSION.SDK_INT > 10) {
- n.flags |= Notification.FLAG_ONLY_ALERT_ONCE; // only matters for
- // Honeycomb
- }
-
- // Build the RemoteView object
- RemoteViews expandedView = new RemoteViews(
- c.getPackageName(),
- R.layout.status_bar_ongoing_event_progress_bar);
-
- expandedView.setTextViewText(R.id.title, mTitle);
- // look at strings
- expandedView.setViewVisibility(R.id.description, View.VISIBLE);
- expandedView.setTextViewText(R.id.description,
- Helpers.getDownloadProgressString(mCurrentBytes, mTotalBytes));
- expandedView.setViewVisibility(R.id.progress_bar_frame, View.VISIBLE);
- expandedView.setProgressBar(R.id.progress_bar,
- (int) (mTotalBytes >> 8),
- (int) (mCurrentBytes >> 8),
- mTotalBytes <= 0);
- expandedView.setViewVisibility(R.id.time_remaining, View.VISIBLE);
- expandedView.setTextViewText(
- R.id.time_remaining,
- c.getString(R.string.time_remaining_notification,
- Helpers.getTimeRemaining(mTimeRemaining)));
- expandedView.setTextViewText(R.id.progress_text,
- Helpers.getDownloadProgressPercent(mCurrentBytes, mTotalBytes));
- expandedView.setImageViewResource(R.id.appIcon, mIcon);
- n.contentView = expandedView;
- n.contentIntent = mPendingIntent;
- return n;
- }
-
- @Override
- public void setPendingIntent(PendingIntent contentIntent) {
- mPendingIntent = contentIntent;
- }
-
- @Override
- public void setTicker(CharSequence ticker) {
- mTicker = ticker;
- }
-
- @Override
- public void setTimeRemaining(long timeRemaining) {
- mTimeRemaining = timeRemaining;
- }
-
-}
diff --git a/platform/android/libs/downloader_library/.classpath b/platform/android/libs/downloader_library/.classpath
deleted file mode 100644
index 7bc01d9a9c..0000000000
--- a/platform/android/libs/downloader_library/.classpath
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="src" path="src"/>
- <classpathentry kind="src" path="gen"/>
- <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
- <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
- <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
- <classpathentry kind="output" path="bin/classes"/>
-</classpath>
diff --git a/platform/android/libs/downloader_library/.settings/org.eclipse.jdt.core.prefs b/platform/android/libs/downloader_library/.settings/org.eclipse.jdt.core.prefs
deleted file mode 100644
index b080d2ddc8..0000000000
--- a/platform/android/libs/downloader_library/.settings/org.eclipse.jdt.core.prefs
+++ /dev/null
@@ -1,4 +0,0 @@
-eclipse.preferences.version=1
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
-org.eclipse.jdt.core.compiler.compliance=1.6
-org.eclipse.jdt.core.compiler.source=1.6
diff --git a/platform/android/libs/downloader_library/AndroidManifest.xml b/platform/android/libs/downloader_library/AndroidManifest.xml
deleted file mode 100644
index 20b74a2988..0000000000
--- a/platform/android/libs/downloader_library/AndroidManifest.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.vending.expansion.downloader"
- android:versionCode="2"
- android:versionName="1.1" >
-
- <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="15"/>
-
-</manifest> \ No newline at end of file
diff --git a/platform/android/libs/downloader_library/build.xml b/platform/android/libs/downloader_library/build.xml
deleted file mode 100644
index d65c145148..0000000000
--- a/platform/android/libs/downloader_library/build.xml
+++ /dev/null
@@ -1,92 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project name="downloader_library" default="help">
-
- <!-- The local.properties file is created and updated by the 'android' tool.
- It contains the path to the SDK. It should *NOT* be checked into
- Version Control Systems. -->
- <property file="local.properties" />
-
- <!-- The ant.properties file can be created by you. It is only edited by the
- 'android' tool to add properties to it.
- This is the place to change some Ant specific build properties.
- Here are some properties you may want to change/update:
-
- source.dir
- The name of the source directory. Default is 'src'.
- out.dir
- The name of the output directory. Default is 'bin'.
-
- For other overridable properties, look at the beginning of the rules
- files in the SDK, at tools/ant/build.xml
-
- Properties related to the SDK location or the project target should
- be updated using the 'android' tool with the 'update' action.
-
- This file is an integral part of the build system for your
- application and should be checked into Version Control Systems.
-
- -->
- <property file="ant.properties" />
-
- <!-- if sdk.dir was not set from one of the property file, then
- get it from the ANDROID_HOME env var.
- This must be done before we load project.properties since
- the proguard config can use sdk.dir -->
- <property environment="env" />
- <condition property="sdk.dir" value="${env.ANDROID_HOME}">
- <isset property="env.ANDROID_HOME" />
- </condition>
-
- <!-- The project.properties file is created and updated by the 'android'
- tool, as well as ADT.
-
- This contains project specific properties such as project target, and library
- dependencies. Lower level build properties are stored in ant.properties
- (or in .classpath for Eclipse projects).
-
- This file is an integral part of the build system for your
- application and should be checked into Version Control Systems. -->
- <loadproperties srcFile="project.properties" />
-
- <!-- quick check on sdk.dir -->
- <fail
- message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
- unless="sdk.dir"
- />
-
- <!--
- Import per project custom build rules if present at the root of the project.
- This is the place to put custom intermediary targets such as:
- -pre-build
- -pre-compile
- -post-compile (This is typically used for code obfuscation.
- Compiled code location: ${out.classes.absolute.dir}
- If this is not done in place, override ${out.dex.input.absolute.dir})
- -post-package
- -post-build
- -pre-clean
- -->
- <import file="custom_rules.xml" optional="true" />
-
- <!-- Import the actual build file.
-
- To customize existing targets, there are two options:
- - Customize only one target:
- - copy/paste the target into this file, *before* the
- <import> task.
- - customize it to your needs.
- - Customize the whole content of build.xml
- - copy/paste the content of the rules files (minus the top node)
- into this file, replacing the <import> task.
- - customize to your needs.
-
- ***********************
- ****** IMPORTANT ******
- ***********************
- In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
- in order to avoid having your file be overridden by tools such as "android update project"
- -->
- <!-- version-tag: 1 -->
- <import file="${sdk.dir}/tools/ant/build.xml" />
-
-</project>
diff --git a/platform/android/libs/downloader_library/gen/com/android/vending/expansion/downloader/BuildConfig.java b/platform/android/libs/downloader_library/gen/com/android/vending/expansion/downloader/BuildConfig.java
deleted file mode 100644
index da9d06e63c..0000000000
--- a/platform/android/libs/downloader_library/gen/com/android/vending/expansion/downloader/BuildConfig.java
+++ /dev/null
@@ -1,6 +0,0 @@
-/** Automatically generated file. DO NOT MODIFY */
-package com.android.vending.expansion.downloader;
-
-public final class BuildConfig {
- public final static boolean DEBUG = false;
-} \ No newline at end of file
diff --git a/platform/android/libs/downloader_library/gen/com/android/vending/expansion/downloader/R.java b/platform/android/libs/downloader_library/gen/com/android/vending/expansion/downloader/R.java
deleted file mode 100644
index 330aed1856..0000000000
--- a/platform/android/libs/downloader_library/gen/com/android/vending/expansion/downloader/R.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/* AUTO-GENERATED FILE. DO NOT MODIFY.
- *
- * This class was automatically generated by the
- * aapt tool from the resource data it found. It
- * should not be modified by hand.
- */
-
-package com.android.vending.expansion.downloader;
-
-public final class R {
- public static final class attr {
- }
- public static final class drawable {
- public static int notify_panel_notification_icon_bg=0x7f020000;
- }
- public static final class id {
- public static int appIcon=0x7f060001;
- public static int description=0x7f060007;
- public static int notificationLayout=0x7f060000;
- public static int progress_bar=0x7f060006;
- public static int progress_bar_frame=0x7f060005;
- public static int progress_text=0x7f060002;
- public static int time_remaining=0x7f060004;
- public static int title=0x7f060003;
- }
- public static final class layout {
- public static int status_bar_ongoing_event_progress_bar=0x7f030000;
- }
- public static final class string {
- public static int kilobytes_per_second=0x7f040014;
- /** When a download completes, a notification is displayed, and this
- string is used to indicate that the download successfully completed.
- Note that such a download could have been initiated by a variety of
- applications, including (but not limited to) the browser, an email
- application, a content marketplace.
- */
- public static int notification_download_complete=0x7f040000;
- /** When a download completes, a notification is displayed, and this
- string is used to indicate that the download failed.
- Note that such a download could have been initiated by a variety of
- applications, including (but not limited to) the browser, an email
- application, a content marketplace.
- */
- public static int notification_download_failed=0x7f040001;
- public static int state_completed=0x7f040007;
- public static int state_connecting=0x7f040005;
- public static int state_downloading=0x7f040006;
- public static int state_failed=0x7f040013;
- public static int state_failed_cancelled=0x7f040012;
- public static int state_failed_fetching_url=0x7f040010;
- public static int state_failed_sdcard_full=0x7f040011;
- public static int state_failed_unlicensed=0x7f04000f;
- public static int state_fetching_url=0x7f040004;
- public static int state_idle=0x7f040003;
- public static int state_paused_by_request=0x7f04000a;
- public static int state_paused_network_setup_failure=0x7f040009;
- public static int state_paused_network_unavailable=0x7f040008;
- public static int state_paused_roaming=0x7f04000d;
- public static int state_paused_sdcard_unavailable=0x7f04000e;
- public static int state_paused_wifi_disabled=0x7f04000c;
- public static int state_paused_wifi_unavailable=0x7f04000b;
- public static int state_unknown=0x7f040002;
- public static int time_remaining=0x7f040015;
- public static int time_remaining_notification=0x7f040016;
- }
- public static final class style {
- public static int ButtonBackground=0x7f050003;
- public static int NotificationText=0x7f050000;
- public static int NotificationTextSecondary=0x7f050004;
- public static int NotificationTextShadow=0x7f050001;
- public static int NotificationTitle=0x7f050002;
- }
-}
diff --git a/platform/android/libs/downloader_library/proguard-project.txt b/platform/android/libs/downloader_library/proguard-project.txt
deleted file mode 100644
index f2fe1559a2..0000000000
--- a/platform/android/libs/downloader_library/proguard-project.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-# To enable ProGuard in your project, edit project.properties
-# to define the proguard.config property as described in that file.
-#
-# Add project specific ProGuard rules here.
-# By default, the flags in this file are appended to flags specified
-# in ${sdk.dir}/tools/proguard/proguard-android.txt
-# You can edit the include path and order by changing the ProGuard
-# include property in project.properties.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# Add any project specific keep options here:
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
diff --git a/platform/android/libs/downloader_library/project.properties b/platform/android/libs/downloader_library/project.properties
deleted file mode 100644
index eda83430bf..0000000000
--- a/platform/android/libs/downloader_library/project.properties
+++ /dev/null
@@ -1,13 +0,0 @@
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must be checked in Version Control Systems.
-#
-# To customize properties used by the Ant build system use,
-# "ant.properties", and override values to adapt the script to your
-# project structure.
-
-# Project target.
-target=android-15
-android.library=true
-android.library.reference.1=../play_licensing
diff --git a/platform/android/libs/downloader_library/res/drawable-hdpi/notify_panel_notification_icon_bg.png b/platform/android/libs/downloader_library/res/drawable-hdpi/notify_panel_notification_icon_bg.png
deleted file mode 100644
index f5b762ecf3..0000000000
--- a/platform/android/libs/downloader_library/res/drawable-hdpi/notify_panel_notification_icon_bg.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/downloader_library/res/drawable-mdpi/notify_panel_notification_icon_bg.png b/platform/android/libs/downloader_library/res/drawable-mdpi/notify_panel_notification_icon_bg.png
deleted file mode 100644
index 9ecb8af06c..0000000000
--- a/platform/android/libs/downloader_library/res/drawable-mdpi/notify_panel_notification_icon_bg.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/downloader_library/res/layout/status_bar_ongoing_event_progress_bar.xml b/platform/android/libs/downloader_library/res/layout/status_bar_ongoing_event_progress_bar.xml
deleted file mode 100644
index 23bac02294..0000000000
--- a/platform/android/libs/downloader_library/res/layout/status_bar_ongoing_event_progress_bar.xml
+++ /dev/null
@@ -1,104 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2008, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-** http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-
-<LinearLayout android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:baselineAligned="false"
- android:orientation="horizontal" android:id="@+id/notificationLayout" xmlns:android="http://schemas.android.com/apk/res/android">
-
- <RelativeLayout
- android:layout_width="35dp"
- android:layout_height="fill_parent"
- android:paddingTop="10dp"
- android:paddingBottom="8dp" >
-
- <ImageView
- android:id="@+id/appIcon"
- android:layout_width="fill_parent"
- android:layout_height="25dp"
- android:scaleType="centerInside"
- android:layout_alignParentLeft="true"
- android:layout_alignParentTop="true"
- android:src="@android:drawable/stat_sys_download" />
-
- <TextView
- android:id="@+id/progress_text"
- style="@style/NotificationText"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_alignParentBottom="true"
- android:layout_gravity="center_horizontal"
- android:singleLine="true"
- android:gravity="center" />
- </RelativeLayout>
-
- <RelativeLayout
- android:layout_width="0dip"
- android:layout_height="match_parent"
- android:layout_weight="1.0"
- android:clickable="true"
- android:focusable="true"
- android:paddingTop="10dp"
- android:paddingRight="8dp"
- android:paddingBottom="8dp" >
-
- <TextView
- android:id="@+id/title"
- style="@style/NotificationTitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:singleLine="true"/>
-
- <TextView
- android:id="@+id/time_remaining"
- style="@style/NotificationText"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentRight="true"
- android:singleLine="true"/>
- <!-- Only one of progress_bar and paused_text will be visible. -->
-
- <FrameLayout
- android:id="@+id/progress_bar_frame"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true" >
-
- <ProgressBar
- android:id="@+id/progress_bar"
- style="?android:attr/progressBarStyleHorizontal"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:paddingRight="25dp" />
-
- <TextView
- android:id="@+id/description"
- style="@style/NotificationTextShadow"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:paddingRight="25dp"
- android:singleLine="true" />
- </FrameLayout>
-
- </RelativeLayout>
-
-</LinearLayout> \ No newline at end of file
diff --git a/platform/android/libs/downloader_library/res/values-v11/styles.xml b/platform/android/libs/downloader_library/res/values-v11/styles.xml
deleted file mode 100644
index f2013bc0bf..0000000000
--- a/platform/android/libs/downloader_library/res/values-v11/styles.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <style name="NotificationTextSecondary" parent="NotificationText">
- <item name="android:textSize">12sp</item>
- </style>
-</resources> \ No newline at end of file
diff --git a/platform/android/libs/downloader_library/res/values-v9/styles.xml b/platform/android/libs/downloader_library/res/values-v9/styles.xml
deleted file mode 100644
index 736e77a5d6..0000000000
--- a/platform/android/libs/downloader_library/res/values-v9/styles.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <style name="NotificationText" parent="android:TextAppearance.StatusBar.EventContent" />
- <style name="NotificationTitle" parent="android:TextAppearance.StatusBar.EventContent.Title" />
-</resources> \ No newline at end of file
diff --git a/platform/android/libs/downloader_library/res/values/strings.xml b/platform/android/libs/downloader_library/res/values/strings.xml
deleted file mode 100644
index b84749faf2..0000000000
--- a/platform/android/libs/downloader_library/res/values/strings.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-
- <!-- When a download completes, a notification is displayed, and this
- string is used to indicate that the download successfully completed.
- Note that such a download could have been initiated by a variety of
- applications, including (but not limited to) the browser, an email
- application, a content marketplace. -->
- <string name="notification_download_complete">Download complete</string>
-
- <!-- When a download completes, a notification is displayed, and this
- string is used to indicate that the download failed.
- Note that such a download could have been initiated by a variety of
- applications, including (but not limited to) the browser, an email
- application, a content marketplace. -->
- <string name="notification_download_failed">Download unsuccessful</string>
-
-
- <string name="state_unknown">Starting..."</string>
- <string name="state_idle">Waiting for download to start</string>
- <string name="state_fetching_url">Looking for resources to download</string>
- <string name="state_connecting">Connecting to the download server</string>
- <string name="state_downloading">Downloading resources</string>
- <string name="state_completed">Download finished</string>
- <string name="state_paused_network_unavailable">Download paused because no network is available</string>
- <string name="state_paused_network_setup_failure">Download paused. Test a website in browser</string>
- <string name="state_paused_by_request">Download paused</string>
- <string name="state_paused_wifi_unavailable">Download paused because wifi is unavailable</string>
- <string name="state_paused_wifi_disabled">Download paused because wifi is disabled</string>
- <string name="state_paused_roaming">Download paused because you are roaming</string>
- <string name="state_paused_sdcard_unavailable">Download paused because the external storage is unavailable</string>
- <string name="state_failed_unlicensed">Download failed because you may not have purchased this app</string>
- <string name="state_failed_fetching_url">Download failed because the resources could not be found</string>
- <string name="state_failed_sdcard_full">Download failed because the external storage is full</string>
- <string name="state_failed_cancelled">Download cancelled</string>
- <string name="state_failed">Download failed</string>
-
- <string name="kilobytes_per_second">%1$s KB/s</string>
- <string name="time_remaining">Time remaining: %1$s</string>
- <string name="time_remaining_notification">%1$s left</string>
-</resources> \ No newline at end of file
diff --git a/platform/android/libs/downloader_library/res/values/styles.xml b/platform/android/libs/downloader_library/res/values/styles.xml
deleted file mode 100644
index a442f61e7e..0000000000
--- a/platform/android/libs/downloader_library/res/values/styles.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-
- <style name="NotificationText">
- <item name="android:textColor">?android:attr/textColorPrimary</item>
- </style>
-
- <style name="NotificationTextShadow" parent="NotificationText">
- <item name="android:textColor">?android:attr/textColorPrimary</item>
- <item name="android:shadowColor">@android:color/background_dark</item>
- <item name="android:shadowDx">1.0</item>
- <item name="android:shadowDy">1.0</item>
- <item name="android:shadowRadius">1</item>
- </style>
-
- <style name="NotificationTitle">
- <item name="android:textColor">?android:attr/textColorPrimary</item>
- <item name="android:textStyle">bold</item>
- </style>
-
- <style name="ButtonBackground">
- <item name="android:background">@android:color/background_dark</item>
- </style>
-
-</resources> \ No newline at end of file
diff --git a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/Constants.java b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/Constants.java
deleted file mode 100644
index ff2c6f535a..0000000000
--- a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/Constants.java
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.vending.expansion.downloader;
-
-import java.io.File;
-
-
-/**
- * Contains the internal constants that are used in the download manager.
- * As a general rule, modifying these constants should be done with care.
- */
-public class Constants {
- /** Tag used for debugging/logging */
- public static final String TAG = "LVLDL";
-
- /**
- * Expansion path where we store obb files
- */
- public static final String EXP_PATH = File.separator + "Android"
- + File.separator + "obb" + File.separator;
-
- /** The intent that gets sent when the service must wake up for a retry */
- public static final String ACTION_RETRY = "android.intent.action.DOWNLOAD_WAKEUP";
-
- /** the intent that gets sent when clicking a successful download */
- public static final String ACTION_OPEN = "android.intent.action.DOWNLOAD_OPEN";
-
- /** the intent that gets sent when clicking an incomplete/failed download */
- public static final String ACTION_LIST = "android.intent.action.DOWNLOAD_LIST";
-
- /** the intent that gets sent when deleting the notification of a completed download */
- public static final String ACTION_HIDE = "android.intent.action.DOWNLOAD_HIDE";
-
- /**
- * When a number has to be appended to the filename, this string is used to separate the
- * base filename from the sequence number
- */
- public static final String FILENAME_SEQUENCE_SEPARATOR = "-";
-
- /** The default user agent used for downloads */
- public static final String DEFAULT_USER_AGENT = "Android.LVLDM";
-
- /** The buffer size used to stream the data */
- public static final int BUFFER_SIZE = 4096;
-
- /** The minimum amount of progress that has to be done before the progress bar gets updated */
- public static final int MIN_PROGRESS_STEP = 4096;
-
- /** The minimum amount of time that has to elapse before the progress bar gets updated, in ms */
- public static final long MIN_PROGRESS_TIME = 1000;
-
- /** The maximum number of rows in the database (FIFO) */
- public static final int MAX_DOWNLOADS = 1000;
-
- /**
- * The number of times that the download manager will retry its network
- * operations when no progress is happening before it gives up.
- */
- public static final int MAX_RETRIES = 5;
-
- /**
- * The minimum amount of time that the download manager accepts for
- * a Retry-After response header with a parameter in delta-seconds.
- */
- public static final int MIN_RETRY_AFTER = 30; // 30s
-
- /**
- * The maximum amount of time that the download manager accepts for
- * a Retry-After response header with a parameter in delta-seconds.
- */
- public static final int MAX_RETRY_AFTER = 24 * 60 * 60; // 24h
-
- /**
- * The maximum number of redirects.
- */
- public static final int MAX_REDIRECTS = 5; // can't be more than 7.
-
- /**
- * The time between a failure and the first retry after an IOException.
- * Each subsequent retry grows exponentially, doubling each time.
- * The time is in seconds.
- */
- public static final int RETRY_FIRST_DELAY = 30;
-
- /** Enable separate connectivity logging */
- public static final boolean LOGX = true;
-
- /** Enable verbose logging */
- public static final boolean LOGV = false;
-
- /** Enable super-verbose logging */
- private static final boolean LOCAL_LOGVV = false;
- public static final boolean LOGVV = LOCAL_LOGVV && LOGV;
-
- /**
- * This download has successfully completed.
- * Warning: there might be other status values that indicate success
- * in the future.
- * Use isSucccess() to capture the entire category.
- */
- public static final int STATUS_SUCCESS = 200;
-
- /**
- * This request couldn't be parsed. This is also used when processing
- * requests with unknown/unsupported URI schemes.
- */
- public static final int STATUS_BAD_REQUEST = 400;
-
- /**
- * This download can't be performed because the content type cannot be
- * handled.
- */
- public static final int STATUS_NOT_ACCEPTABLE = 406;
-
- /**
- * This download cannot be performed because the length cannot be
- * determined accurately. This is the code for the HTTP error "Length
- * Required", which is typically used when making requests that require
- * a content length but don't have one, and it is also used in the
- * client when a response is received whose length cannot be determined
- * accurately (therefore making it impossible to know when a download
- * completes).
- */
- public static final int STATUS_LENGTH_REQUIRED = 411;
-
- /**
- * This download was interrupted and cannot be resumed.
- * This is the code for the HTTP error "Precondition Failed", and it is
- * also used in situations where the client doesn't have an ETag at all.
- */
- public static final int STATUS_PRECONDITION_FAILED = 412;
-
- /**
- * The lowest-valued error status that is not an actual HTTP status code.
- */
- public static final int MIN_ARTIFICIAL_ERROR_STATUS = 488;
-
- /**
- * The requested destination file already exists.
- */
- public static final int STATUS_FILE_ALREADY_EXISTS_ERROR = 488;
-
- /**
- * Some possibly transient error occurred, but we can't resume the download.
- */
- public static final int STATUS_CANNOT_RESUME = 489;
-
- /**
- * This download was canceled
- */
- public static final int STATUS_CANCELED = 490;
-
- /**
- * This download has completed with an error.
- * Warning: there will be other status values that indicate errors in
- * the future. Use isStatusError() to capture the entire category.
- */
- public static final int STATUS_UNKNOWN_ERROR = 491;
-
- /**
- * This download couldn't be completed because of a storage issue.
- * Typically, that's because the filesystem is missing or full.
- * Use the more specific {@link #STATUS_INSUFFICIENT_SPACE_ERROR}
- * and {@link #STATUS_DEVICE_NOT_FOUND_ERROR} when appropriate.
- */
- public static final int STATUS_FILE_ERROR = 492;
-
- /**
- * This download couldn't be completed because of an HTTP
- * redirect response that the download manager couldn't
- * handle.
- */
- public static final int STATUS_UNHANDLED_REDIRECT = 493;
-
- /**
- * This download couldn't be completed because of an
- * unspecified unhandled HTTP code.
- */
- public static final int STATUS_UNHANDLED_HTTP_CODE = 494;
-
- /**
- * This download couldn't be completed because of an
- * error receiving or processing data at the HTTP level.
- */
- public static final int STATUS_HTTP_DATA_ERROR = 495;
-
- /**
- * This download couldn't be completed because of an
- * HttpException while setting up the request.
- */
- public static final int STATUS_HTTP_EXCEPTION = 496;
-
- /**
- * This download couldn't be completed because there were
- * too many redirects.
- */
- public static final int STATUS_TOO_MANY_REDIRECTS = 497;
-
- /**
- * This download couldn't be completed due to insufficient storage
- * space. Typically, this is because the SD card is full.
- */
- public static final int STATUS_INSUFFICIENT_SPACE_ERROR = 498;
-
- /**
- * This download couldn't be completed because no external storage
- * device was found. Typically, this is because the SD card is not
- * mounted.
- */
- public static final int STATUS_DEVICE_NOT_FOUND_ERROR = 499;
-
- /**
- * The wake duration to check to see if a download is possible.
- */
- public static final long WATCHDOG_WAKE_TIMER = 60*1000;
-
- /**
- * The wake duration to check to see if the process was killed.
- */
- public static final long ACTIVE_THREAD_WATCHDOG = 5*1000;
-
-} \ No newline at end of file
diff --git a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/DownloadProgressInfo.java b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/DownloadProgressInfo.java
deleted file mode 100644
index 9cb294d721..0000000000
--- a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/DownloadProgressInfo.java
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.vending.expansion.downloader;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-
-/**
- * This class contains progress information about the active download(s).
- *
- * When you build the Activity that initiates a download and tracks the
- * progress by implementing the {@link IDownloaderClient} interface, you'll
- * receive a DownloadProgressInfo object in each call to the {@link
- * IDownloaderClient#onDownloadProgress} method. This allows you to update
- * your activity's UI with information about the download progress, such
- * as the progress so far, time remaining and current speed.
- */
-public class DownloadProgressInfo implements Parcelable {
- public long mOverallTotal;
- public long mOverallProgress;
- public long mTimeRemaining; // time remaining
- public float mCurrentSpeed; // speed in KB/S
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel p, int i) {
- p.writeLong(mOverallTotal);
- p.writeLong(mOverallProgress);
- p.writeLong(mTimeRemaining);
- p.writeFloat(mCurrentSpeed);
- }
-
- public DownloadProgressInfo(Parcel p) {
- mOverallTotal = p.readLong();
- mOverallProgress = p.readLong();
- mTimeRemaining = p.readLong();
- mCurrentSpeed = p.readFloat();
- }
-
- public DownloadProgressInfo(long overallTotal, long overallProgress,
- long timeRemaining,
- float currentSpeed) {
- this.mOverallTotal = overallTotal;
- this.mOverallProgress = overallProgress;
- this.mTimeRemaining = timeRemaining;
- this.mCurrentSpeed = currentSpeed;
- }
-
- public static final Creator<DownloadProgressInfo> CREATOR = new Creator<DownloadProgressInfo>() {
- @Override
- public DownloadProgressInfo createFromParcel(Parcel parcel) {
- return new DownloadProgressInfo(parcel);
- }
-
- @Override
- public DownloadProgressInfo[] newArray(int i) {
- return new DownloadProgressInfo[i];
- }
- };
-
-}
diff --git a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/DownloaderClientMarshaller.java b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/DownloaderClientMarshaller.java
deleted file mode 100644
index 2201751254..0000000000
--- a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/DownloaderClientMarshaller.java
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.vending.expansion.downloader;
-
-import com.google.android.vending.expansion.downloader.impl.DownloaderService;
-
-import android.app.PendingIntent;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
-import android.util.Log;
-
-
-
-/**
- * This class binds the service API to your application client. It contains the IDownloaderClient proxy,
- * which is used to call functions in your client as well as the Stub, which is used to call functions
- * in the client implementation of IDownloaderClient.
- *
- * <p>The IPC is implemented using an Android Messenger and a service Binder. The connect method
- * should be called whenever the client wants to bind to the service. It opens up a service connection
- * that ends up calling the onServiceConnected client API that passes the service messenger
- * in. If the client wants to be notified by the service, it is responsible for then passing its
- * messenger to the service in a separate call.
- *
- * <p>Critical methods are {@link #startDownloadServiceIfRequired} and {@link #CreateStub}.
- *
- * <p>When your application first starts, you should first check whether your app's expansion files are
- * already on the device. If not, you should then call {@link #startDownloadServiceIfRequired}, which
- * starts your {@link impl.DownloaderService} to download the expansion files if necessary. The method
- * returns a value indicating whether download is required or not.
- *
- * <p>If a download is required, {@link #startDownloadServiceIfRequired} begins the download through
- * the specified service and you should then call {@link #CreateStub} to instantiate a member {@link
- * IStub} object that you need in order to receive calls through your {@link IDownloaderClient}
- * interface.
- */
-public class DownloaderClientMarshaller {
- public static final int MSG_ONDOWNLOADSTATE_CHANGED = 10;
- public static final int MSG_ONDOWNLOADPROGRESS = 11;
- public static final int MSG_ONSERVICECONNECTED = 12;
-
- public static final String PARAM_NEW_STATE = "newState";
- public static final String PARAM_PROGRESS = "progress";
- public static final String PARAM_MESSENGER = DownloaderService.EXTRA_MESSAGE_HANDLER;
-
- public static final int NO_DOWNLOAD_REQUIRED = DownloaderService.NO_DOWNLOAD_REQUIRED;
- public static final int LVL_CHECK_REQUIRED = DownloaderService.LVL_CHECK_REQUIRED;
- public static final int DOWNLOAD_REQUIRED = DownloaderService.DOWNLOAD_REQUIRED;
-
- private static class Proxy implements IDownloaderClient {
- private Messenger mServiceMessenger;
-
- @Override
- public void onDownloadStateChanged(int newState) {
- Bundle params = new Bundle(1);
- params.putInt(PARAM_NEW_STATE, newState);
- send(MSG_ONDOWNLOADSTATE_CHANGED, params);
- }
-
- @Override
- public void onDownloadProgress(DownloadProgressInfo progress) {
- Bundle params = new Bundle(1);
- params.putParcelable(PARAM_PROGRESS, progress);
- send(MSG_ONDOWNLOADPROGRESS, params);
- }
-
- private void send(int method, Bundle params) {
- Message m = Message.obtain(null, method);
- m.setData(params);
- try {
- mServiceMessenger.send(m);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
-
- public Proxy(Messenger msg) {
- mServiceMessenger = msg;
- }
-
- @Override
- public void onServiceConnected(Messenger m) {
- /**
- * This is never called through the proxy.
- */
- }
- }
-
- private static class Stub implements IStub {
- private IDownloaderClient mItf = null;
- private Class<?> mDownloaderServiceClass;
- private boolean mBound;
- private Messenger mServiceMessenger;
- private Context mContext;
- /**
- * Target we publish for clients to send messages to IncomingHandler.
- */
- final Messenger mMessenger = new Messenger(new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_ONDOWNLOADPROGRESS:
- Bundle bun = msg.getData();
- if ( null != mContext ) {
- bun.setClassLoader(mContext.getClassLoader());
- DownloadProgressInfo dpi = (DownloadProgressInfo) msg.getData()
- .getParcelable(PARAM_PROGRESS);
- mItf.onDownloadProgress(dpi);
- }
- break;
- case MSG_ONDOWNLOADSTATE_CHANGED:
- mItf.onDownloadStateChanged(msg.getData().getInt(PARAM_NEW_STATE));
- break;
- case MSG_ONSERVICECONNECTED:
- mItf.onServiceConnected(
- (Messenger) msg.getData().getParcelable(PARAM_MESSENGER));
- break;
- }
- }
- });
-
- public Stub(IDownloaderClient itf, Class<?> downloaderService) {
- mItf = itf;
- mDownloaderServiceClass = downloaderService;
- }
-
- /**
- * Class for interacting with the main interface of the service.
- */
- private ServiceConnection mConnection = new ServiceConnection() {
- public void onServiceConnected(ComponentName className, IBinder service) {
- // This is called when the connection with the service has been
- // established, giving us the object we can use to
- // interact with the service. We are communicating with the
- // service using a Messenger, so here we get a client-side
- // representation of that from the raw IBinder object.
- mServiceMessenger = new Messenger(service);
- mItf.onServiceConnected(
- mServiceMessenger);
- }
-
- public void onServiceDisconnected(ComponentName className) {
- // This is called when the connection with the service has been
- // unexpectedly disconnected -- that is, its process crashed.
- mServiceMessenger = null;
- }
- };
-
- @Override
- public void connect(Context c) {
- mContext = c;
- Intent bindIntent = new Intent(c, mDownloaderServiceClass);
- bindIntent.putExtra(PARAM_MESSENGER, mMessenger);
- if ( !c.bindService(bindIntent, mConnection, Context.BIND_DEBUG_UNBIND) ) {
- if ( Constants.LOGVV ) {
- Log.d(Constants.TAG, "Service Unbound");
- }
- } else {
- mBound = true;
- }
-
- }
-
- @Override
- public void disconnect(Context c) {
- if (mBound) {
- c.unbindService(mConnection);
- mBound = false;
- }
- mContext = null;
- }
-
- @Override
- public Messenger getMessenger() {
- return mMessenger;
- }
- }
-
- /**
- * Returns a proxy that will marshal calls to IDownloaderClient methods
- *
- * @param msg
- * @return
- */
- public static IDownloaderClient CreateProxy(Messenger msg) {
- return new Proxy(msg);
- }
-
- /**
- * Returns a stub object that, when connected, will listen for marshaled
- * {@link IDownloaderClient} methods and translate them into calls to the supplied
- * interface.
- *
- * @param itf An implementation of IDownloaderClient that will be called
- * when remote method calls are unmarshaled.
- * @param downloaderService The class for your implementation of {@link
- * impl.DownloaderService}.
- * @return The {@link IStub} that allows you to connect to the service such that
- * your {@link IDownloaderClient} receives status updates.
- */
- public static IStub CreateStub(IDownloaderClient itf, Class<?> downloaderService) {
- return new Stub(itf, downloaderService);
- }
-
- /**
- * Starts the download if necessary. This function starts a flow that does `
- * many things. 1) Checks to see if the APK version has been checked and
- * the metadata database updated 2) If the APK version does not match,
- * checks the new LVL status to see if a new download is required 3) If the
- * APK version does match, then checks to see if the download(s) have been
- * completed 4) If the downloads have been completed, returns
- * NO_DOWNLOAD_REQUIRED The idea is that this can be called during the
- * startup of an application to quickly ascertain if the application needs
- * to wait to hear about any updated APK expansion files. Note that this does
- * mean that the application MUST be run for the first time with a network
- * connection, even if Market delivers all of the files.
- *
- * @param context Your application Context.
- * @param notificationClient A PendingIntent to start the Activity in your application
- * that shows the download progress and which will also start the application when download
- * completes.
- * @param serviceClass the class of your {@link imp.DownloaderService} implementation
- * @return whether the service was started and the reason for starting the service.
- * Either {@link #NO_DOWNLOAD_REQUIRED}, {@link #LVL_CHECK_REQUIRED}, or {@link
- * #DOWNLOAD_REQUIRED}.
- * @throws NameNotFoundException
- */
- public static int startDownloadServiceIfRequired(Context context, PendingIntent notificationClient,
- Class<?> serviceClass)
- throws NameNotFoundException {
- return DownloaderService.startDownloadServiceIfRequired(context, notificationClient,
- serviceClass);
- }
-
- /**
- * This version assumes that the intent contains the pending intent as a parameter. This
- * is used for responding to alarms.
- * <p>The pending intent must be in an extra with the key {@link
- * impl.DownloaderService#EXTRA_PENDING_INTENT}.
- *
- * @param context
- * @param notificationClient
- * @param serviceClass the class of the service to start
- * @return
- * @throws NameNotFoundException
- */
- public static int startDownloadServiceIfRequired(Context context, Intent notificationClient,
- Class<?> serviceClass)
- throws NameNotFoundException {
- return DownloaderService.startDownloadServiceIfRequired(context, notificationClient,
- serviceClass);
- }
-
-}
diff --git a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/DownloaderServiceMarshaller.java b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/DownloaderServiceMarshaller.java
deleted file mode 100644
index 054eaa9895..0000000000
--- a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/DownloaderServiceMarshaller.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.vending.expansion.downloader;
-
-import com.google.android.vending.expansion.downloader.impl.DownloaderService;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
-
-
-
-/**
- * This class is used by the client activity to proxy requests to the Downloader
- * Service.
- *
- * Most importantly, you must call {@link #CreateProxy} during the {@link
- * IDownloaderClient#onServiceConnected} callback in your activity in order to instantiate
- * an {@link IDownloaderService} object that you can then use to issue commands to the {@link
- * DownloaderService} (such as to pause and resume downloads).
- */
-public class DownloaderServiceMarshaller {
-
- public static final int MSG_REQUEST_ABORT_DOWNLOAD =
- 1;
- public static final int MSG_REQUEST_PAUSE_DOWNLOAD =
- 2;
- public static final int MSG_SET_DOWNLOAD_FLAGS =
- 3;
- public static final int MSG_REQUEST_CONTINUE_DOWNLOAD =
- 4;
- public static final int MSG_REQUEST_DOWNLOAD_STATE =
- 5;
- public static final int MSG_REQUEST_CLIENT_UPDATE =
- 6;
-
- public static final String PARAMS_FLAGS = "flags";
- public static final String PARAM_MESSENGER = DownloaderService.EXTRA_MESSAGE_HANDLER;
-
- private static class Proxy implements IDownloaderService {
- private Messenger mMsg;
-
- private void send(int method, Bundle params) {
- Message m = Message.obtain(null, method);
- m.setData(params);
- try {
- mMsg.send(m);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
-
- public Proxy(Messenger msg) {
- mMsg = msg;
- }
-
- @Override
- public void requestAbortDownload() {
- send(MSG_REQUEST_ABORT_DOWNLOAD, new Bundle());
- }
-
- @Override
- public void requestPauseDownload() {
- send(MSG_REQUEST_PAUSE_DOWNLOAD, new Bundle());
- }
-
- @Override
- public void setDownloadFlags(int flags) {
- Bundle params = new Bundle();
- params.putInt(PARAMS_FLAGS, flags);
- send(MSG_SET_DOWNLOAD_FLAGS, params);
- }
-
- @Override
- public void requestContinueDownload() {
- send(MSG_REQUEST_CONTINUE_DOWNLOAD, new Bundle());
- }
-
- @Override
- public void requestDownloadStatus() {
- send(MSG_REQUEST_DOWNLOAD_STATE, new Bundle());
- }
-
- @Override
- public void onClientUpdated(Messenger clientMessenger) {
- Bundle bundle = new Bundle(1);
- bundle.putParcelable(PARAM_MESSENGER, clientMessenger);
- send(MSG_REQUEST_CLIENT_UPDATE, bundle);
- }
- }
-
- private static class Stub implements IStub {
- private IDownloaderService mItf = null;
- final Messenger mMessenger = new Messenger(new Handler() {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_REQUEST_ABORT_DOWNLOAD:
- mItf.requestAbortDownload();
- break;
- case MSG_REQUEST_CONTINUE_DOWNLOAD:
- mItf.requestContinueDownload();
- break;
- case MSG_REQUEST_PAUSE_DOWNLOAD:
- mItf.requestPauseDownload();
- break;
- case MSG_SET_DOWNLOAD_FLAGS:
- mItf.setDownloadFlags(msg.getData().getInt(PARAMS_FLAGS));
- break;
- case MSG_REQUEST_DOWNLOAD_STATE:
- mItf.requestDownloadStatus();
- break;
- case MSG_REQUEST_CLIENT_UPDATE:
- mItf.onClientUpdated((Messenger) msg.getData().getParcelable(
- PARAM_MESSENGER));
- break;
- }
- }
- });
-
- public Stub(IDownloaderService itf) {
- mItf = itf;
- }
-
- @Override
- public Messenger getMessenger() {
- return mMessenger;
- }
-
- @Override
- public void connect(Context c) {
-
- }
-
- @Override
- public void disconnect(Context c) {
-
- }
- }
-
- /**
- * Returns a proxy that will marshall calls to IDownloaderService methods
- *
- * @param ctx
- * @return
- */
- public static IDownloaderService CreateProxy(Messenger msg) {
- return new Proxy(msg);
- }
-
- /**
- * Returns a stub object that, when connected, will listen for marshalled
- * IDownloaderService methods and translate them into calls to the supplied
- * interface.
- *
- * @param itf An implementation of IDownloaderService that will be called
- * when remote method calls are unmarshalled.
- * @return
- */
- public static IStub CreateStub(IDownloaderService itf) {
- return new Stub(itf);
- }
-
-}
diff --git a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/Helpers.java b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/Helpers.java
deleted file mode 100644
index 1e84e54a0f..0000000000
--- a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/Helpers.java
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.vending.expansion.downloader;
-
-import com.android.vending.expansion.downloader.R;
-
-import android.content.Context;
-import android.os.Environment;
-import android.os.StatFs;
-import android.os.SystemClock;
-import android.util.Log;
-
-import java.io.File;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Locale;
-import java.util.Random;
-import java.util.TimeZone;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Some helper functions for the download manager
- */
-public class Helpers {
-
- public static Random sRandom = new Random(SystemClock.uptimeMillis());
-
- /** Regex used to parse content-disposition headers */
- private static final Pattern CONTENT_DISPOSITION_PATTERN = Pattern
- .compile("attachment;\\s*filename\\s*=\\s*\"([^\"]*)\"");
-
- private Helpers() {
- }
-
- /*
- * Parse the Content-Disposition HTTP Header. The format of the header is
- * defined here: http://www.w3.org/Protocols/rfc2616/rfc2616-sec19.html This
- * header provides a filename for content that is going to be downloaded to
- * the file system. We only support the attachment type.
- */
- static String parseContentDisposition(String contentDisposition) {
- try {
- Matcher m = CONTENT_DISPOSITION_PATTERN.matcher(contentDisposition);
- if (m.find()) {
- return m.group(1);
- }
- } catch (IllegalStateException ex) {
- // This function is defined as returning null when it can't parse
- // the header
- }
- return null;
- }
-
- /**
- * @return the root of the filesystem containing the given path
- */
- public static File getFilesystemRoot(String path) {
- File cache = Environment.getDownloadCacheDirectory();
- if (path.startsWith(cache.getPath())) {
- return cache;
- }
- File external = Environment.getExternalStorageDirectory();
- if (path.startsWith(external.getPath())) {
- return external;
- }
- throw new IllegalArgumentException(
- "Cannot determine filesystem root for " + path);
- }
-
- public static boolean isExternalMediaMounted() {
- if (!Environment.getExternalStorageState().equals(
- Environment.MEDIA_MOUNTED)) {
- // No SD card found.
- if ( Constants.LOGVV ) {
- Log.d(Constants.TAG, "no external storage");
- }
- return false;
- }
- return true;
- }
-
- /**
- * @return the number of bytes available on the filesystem rooted at the
- * given File
- */
- public static long getAvailableBytes(File root) {
- StatFs stat = new StatFs(root.getPath());
- // put a bit of margin (in case creating the file grows the system by a
- // few blocks)
- long availableBlocks = (long) stat.getAvailableBlocks() - 4;
- return stat.getBlockSize() * availableBlocks;
- }
-
- /**
- * Checks whether the filename looks legitimate
- */
- public static boolean isFilenameValid(String filename) {
- filename = filename.replaceFirst("/+", "/"); // normalize leading
- // slashes
- return filename.startsWith(Environment.getDownloadCacheDirectory().toString())
- || filename.startsWith(Environment.getExternalStorageDirectory().toString());
- }
-
- /*
- * Delete the given file from device
- */
- /* package */static void deleteFile(String path) {
- try {
- File file = new File(path);
- file.delete();
- } catch (Exception e) {
- Log.w(Constants.TAG, "file: '" + path + "' couldn't be deleted", e);
- }
- }
-
- /**
- * Showing progress in MB here. It would be nice to choose the unit (KB, MB,
- * GB) based on total file size, but given what we know about the expected
- * ranges of file sizes for APK expansion files, it's probably not necessary.
- *
- * @param overallProgress
- * @param overallTotal
- * @return
- */
-
- static public String getDownloadProgressString(long overallProgress, long overallTotal) {
- if (overallTotal == 0) {
- if ( Constants.LOGVV ) {
- Log.e(Constants.TAG, "Notification called when total is zero");
- }
- return "";
- }
- return String.format("%.2f",
- (float) overallProgress / (1024.0f * 1024.0f))
- + "MB /" +
- String.format("%.2f", (float) overallTotal /
- (1024.0f * 1024.0f)) + "MB";
- }
-
- /**
- * Adds a percentile to getDownloadProgressString.
- *
- * @param overallProgress
- * @param overallTotal
- * @return
- */
- static public String getDownloadProgressStringNotification(long overallProgress,
- long overallTotal) {
- if (overallTotal == 0) {
- if ( Constants.LOGVV ) {
- Log.e(Constants.TAG, "Notification called when total is zero");
- }
- return "";
- }
- return getDownloadProgressString(overallProgress, overallTotal) + " (" +
- getDownloadProgressPercent(overallProgress, overallTotal) + ")";
- }
-
- public static String getDownloadProgressPercent(long overallProgress, long overallTotal) {
- if (overallTotal == 0) {
- if ( Constants.LOGVV ) {
- Log.e(Constants.TAG, "Notification called when total is zero");
- }
- return "";
- }
- return Long.toString(overallProgress * 100 / overallTotal) + "%";
- }
-
- public static String getSpeedString(float bytesPerMillisecond) {
- return String.format("%.2f", bytesPerMillisecond * 1000 / 1024);
- }
-
- public static String getTimeRemaining(long durationInMilliseconds) {
- SimpleDateFormat sdf;
- if (durationInMilliseconds > 1000 * 60 * 60) {
- sdf = new SimpleDateFormat("HH:mm", Locale.getDefault());
- } else {
- sdf = new SimpleDateFormat("mm:ss", Locale.getDefault());
- }
- return sdf.format(new Date(durationInMilliseconds - TimeZone.getDefault().getRawOffset()));
- }
-
- /**
- * Returns the file name (without full path) for an Expansion APK file from
- * the given context.
- *
- * @param c the context
- * @param mainFile true for main file, false for patch file
- * @param versionCode the version of the file
- * @return String the file name of the expansion file
- */
- public static String getExpansionAPKFileName(Context c, boolean mainFile, int versionCode) {
- return (mainFile ? "main." : "patch.") + versionCode + "." + c.getPackageName() + ".obb";
- }
-
- /**
- * Returns the filename (where the file should be saved) from info about a
- * download
- */
- static public String generateSaveFileName(Context c, String fileName) {
- String path = getSaveFilePath(c)
- + File.separator + fileName;
- return path;
- }
-
- static public String getSaveFilePath(Context c) {
- File root = Environment.getExternalStorageDirectory();
- String path = root.toString() + Constants.EXP_PATH + c.getPackageName();
- return path;
- }
-
- /**
- * Helper function to ascertain the existence of a file and return
- * true/false appropriately
- *
- * @param c the app/activity/service context
- * @param fileName the name (sans path) of the file to query
- * @param fileSize the size that the file must match
- * @param deleteFileOnMismatch if the file sizes do not match, delete the
- * file
- * @return true if it does exist, false otherwise
- */
- static public boolean doesFileExist(Context c, String fileName, long fileSize,
- boolean deleteFileOnMismatch) {
- // the file may have been delivered by Market --- let's make sure
- // it's the size we expect
- File fileForNewFile = new File(Helpers.generateSaveFileName(c, fileName));
- if (fileForNewFile.exists()) {
- if (fileForNewFile.length() == fileSize) {
- return true;
- }
- if (deleteFileOnMismatch) {
- // delete the file --- we won't be able to resume
- // because we cannot confirm the integrity of the file
- fileForNewFile.delete();
- }
- }
- return false;
- }
-
- /**
- * Converts download states that are returned by the {@link
- * IDownloaderClient#onDownloadStateChanged} callback into usable strings.
- * This is useful if using the state strings built into the library to display user messages.
- * @param state One of the STATE_* constants from {@link IDownloaderClient}.
- * @return string resource ID for the corresponding string.
- */
- static public int getDownloaderStringResourceIDFromState(int state) {
- switch (state) {
- case IDownloaderClient.STATE_IDLE:
- return R.string.state_idle;
- case IDownloaderClient.STATE_FETCHING_URL:
- return R.string.state_fetching_url;
- case IDownloaderClient.STATE_CONNECTING:
- return R.string.state_connecting;
- case IDownloaderClient.STATE_DOWNLOADING:
- return R.string.state_downloading;
- case IDownloaderClient.STATE_COMPLETED:
- return R.string.state_completed;
- case IDownloaderClient.STATE_PAUSED_NETWORK_UNAVAILABLE:
- return R.string.state_paused_network_unavailable;
- case IDownloaderClient.STATE_PAUSED_BY_REQUEST:
- return R.string.state_paused_by_request;
- case IDownloaderClient.STATE_PAUSED_WIFI_DISABLED_NEED_CELLULAR_PERMISSION:
- return R.string.state_paused_wifi_disabled;
- case IDownloaderClient.STATE_PAUSED_NEED_CELLULAR_PERMISSION:
- return R.string.state_paused_wifi_unavailable;
- case IDownloaderClient.STATE_PAUSED_WIFI_DISABLED:
- return R.string.state_paused_wifi_disabled;
- case IDownloaderClient.STATE_PAUSED_NEED_WIFI:
- return R.string.state_paused_wifi_unavailable;
- case IDownloaderClient.STATE_PAUSED_ROAMING:
- return R.string.state_paused_roaming;
- case IDownloaderClient.STATE_PAUSED_NETWORK_SETUP_FAILURE:
- return R.string.state_paused_network_setup_failure;
- case IDownloaderClient.STATE_PAUSED_SDCARD_UNAVAILABLE:
- return R.string.state_paused_sdcard_unavailable;
- case IDownloaderClient.STATE_FAILED_UNLICENSED:
- return R.string.state_failed_unlicensed;
- case IDownloaderClient.STATE_FAILED_FETCHING_URL:
- return R.string.state_failed_fetching_url;
- case IDownloaderClient.STATE_FAILED_SDCARD_FULL:
- return R.string.state_failed_sdcard_full;
- case IDownloaderClient.STATE_FAILED_CANCELED:
- return R.string.state_failed_cancelled;
- default:
- return R.string.state_unknown;
- }
- }
-
-}
diff --git a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/IDownloaderClient.java b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/IDownloaderClient.java
deleted file mode 100644
index b8511a62a0..0000000000
--- a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/IDownloaderClient.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.vending.expansion.downloader;
-
-import android.os.Messenger;
-
-/**
- * This interface should be implemented by the client activity for the
- * downloader. It is used to pass status from the service to the client.
- */
-public interface IDownloaderClient {
- static final int STATE_IDLE = 1;
- static final int STATE_FETCHING_URL = 2;
- static final int STATE_CONNECTING = 3;
- static final int STATE_DOWNLOADING = 4;
- static final int STATE_COMPLETED = 5;
-
- static final int STATE_PAUSED_NETWORK_UNAVAILABLE = 6;
- static final int STATE_PAUSED_BY_REQUEST = 7;
-
- /**
- * Both STATE_PAUSED_WIFI_DISABLED_NEED_CELLULAR_PERMISSION and
- * STATE_PAUSED_NEED_CELLULAR_PERMISSION imply that Wi-Fi is unavailable and
- * cellular permission will restart the service. Wi-Fi disabled means that
- * the Wi-Fi manager is returning that Wi-Fi is not enabled, while in the
- * other case Wi-Fi is enabled but not available.
- */
- static final int STATE_PAUSED_WIFI_DISABLED_NEED_CELLULAR_PERMISSION = 8;
- static final int STATE_PAUSED_NEED_CELLULAR_PERMISSION = 9;
-
- /**
- * Both STATE_PAUSED_WIFI_DISABLED and STATE_PAUSED_NEED_WIFI imply that
- * Wi-Fi is unavailable and cellular permission will NOT restart the
- * service. Wi-Fi disabled means that the Wi-Fi manager is returning that
- * Wi-Fi is not enabled, while in the other case Wi-Fi is enabled but not
- * available.
- * <p>
- * The service does not return these values. We recommend that app
- * developers with very large payloads do not allow these payloads to be
- * downloaded over cellular connections.
- */
- static final int STATE_PAUSED_WIFI_DISABLED = 10;
- static final int STATE_PAUSED_NEED_WIFI = 11;
-
- static final int STATE_PAUSED_ROAMING = 12;
-
- /**
- * Scary case. We were on a network that redirected us to another website
- * that delivered us the wrong file.
- */
- static final int STATE_PAUSED_NETWORK_SETUP_FAILURE = 13;
-
- static final int STATE_PAUSED_SDCARD_UNAVAILABLE = 14;
-
- static final int STATE_FAILED_UNLICENSED = 15;
- static final int STATE_FAILED_FETCHING_URL = 16;
- static final int STATE_FAILED_SDCARD_FULL = 17;
- static final int STATE_FAILED_CANCELED = 18;
-
- static final int STATE_FAILED = 19;
-
- /**
- * Called internally by the stub when the service is bound to the client.
- * <p>
- * Critical implementation detail. In onServiceConnected we create the
- * remote service and marshaler. This is how we pass the client information
- * back to the service so the client can be properly notified of changes. We
- * must do this every time we reconnect to the service.
- * <p>
- * That is, when you receive this callback, you should call
- * {@link DownloaderServiceMarshaller#CreateProxy} to instantiate a member
- * instance of {@link IDownloaderService}, then call
- * {@link IDownloaderService#onClientUpdated} with the Messenger retrieved
- * from your {@link IStub} proxy object.
- *
- * @param m the service Messenger. This Messenger is used to call the
- * service API from the client.
- */
- void onServiceConnected(Messenger m);
-
- /**
- * Called when the download state changes. Depending on the state, there may
- * be user requests. The service is free to change the download state in the
- * middle of a user request, so the client should be able to handle this.
- * <p>
- * The Downloader Library includes a collection of string resources that
- * correspond to each of the states, which you can use to provide users a
- * useful message based on the state provided in this callback. To fetch the
- * appropriate string for a state, call
- * {@link Helpers#getDownloaderStringResourceIDFromState}.
- * <p>
- * What this means to the developer: The application has gotten a message
- * that the download has paused due to lack of WiFi. The developer should
- * then show UI asking the user if they want to enable downloading over
- * cellular connections with appropriate warnings. If the application
- * suddenly starts downloading, the application should revert to showing the
- * progress again, rather than leaving up the download over cellular UI up.
- *
- * @param newState one of the STATE_* values defined in IDownloaderClient
- */
- void onDownloadStateChanged(int newState);
-
- /**
- * Shows the download progress. This is intended to be used to fill out a
- * client UI. This progress should only be shown in a few states such as
- * STATE_DOWNLOADING.
- *
- * @param progress the DownloadProgressInfo object containing the current
- * progress of all downloads.
- */
- void onDownloadProgress(DownloadProgressInfo progress);
-}
diff --git a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/IDownloaderService.java b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/IDownloaderService.java
deleted file mode 100644
index 4789afe19c..0000000000
--- a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/IDownloaderService.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.vending.expansion.downloader;
-
-import com.google.android.vending.expansion.downloader.impl.DownloaderService;
-import android.os.Messenger;
-
-/**
- * This interface is implemented by the DownloaderService and by the
- * DownloaderServiceMarshaller. It contains functions to control the service.
- * When a client binds to the service, it must call the onClientUpdated
- * function.
- * <p>
- * You can acquire a proxy that implements this interface for your service by
- * calling {@link DownloaderServiceMarshaller#CreateProxy} during the
- * {@link IDownloaderClient#onServiceConnected} callback. At which point, you
- * should immediately call {@link #onClientUpdated}.
- */
-public interface IDownloaderService {
- /**
- * Set this flag in response to the
- * IDownloaderClient.STATE_PAUSED_NEED_CELLULAR_PERMISSION state and then
- * call RequestContinueDownload to resume a download
- */
- public static final int FLAGS_DOWNLOAD_OVER_CELLULAR = 1;
-
- /**
- * Request that the service abort the current download. The service should
- * respond by changing the state to {@link IDownloaderClient.STATE_ABORTED}.
- */
- void requestAbortDownload();
-
- /**
- * Request that the service pause the current download. The service should
- * respond by changing the state to
- * {@link IDownloaderClient.STATE_PAUSED_BY_REQUEST}.
- */
- void requestPauseDownload();
-
- /**
- * Request that the service continue a paused download, when in any paused
- * or failed state, including
- * {@link IDownloaderClient.STATE_PAUSED_BY_REQUEST}.
- */
- void requestContinueDownload();
-
- /**
- * Set the flags for this download (e.g.
- * {@link DownloaderService.FLAGS_DOWNLOAD_OVER_CELLULAR}).
- *
- * @param flags
- */
- void setDownloadFlags(int flags);
-
- /**
- * Requests that the download status be sent to the client.
- */
- void requestDownloadStatus();
-
- /**
- * Call this when you get {@link
- * IDownloaderClient.onServiceConnected(Messenger m)} from the
- * DownloaderClient to register the client with the service. It will
- * automatically send the current status to the client.
- *
- * @param clientMessenger
- */
- void onClientUpdated(Messenger clientMessenger);
-}
diff --git a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/IStub.java b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/IStub.java
deleted file mode 100644
index d5bc3a843e..0000000000
--- a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/IStub.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.vending.expansion.downloader;
-
-import android.content.Context;
-import android.os.Messenger;
-
-/**
- * This is the interface that is used to connect/disconnect from the downloader
- * service.
- * <p>
- * You should get a proxy object that implements this interface by calling
- * {@link DownloaderClientMarshaller#CreateStub} in your activity when the
- * downloader service starts. Then, call {@link #connect} during your activity's
- * onResume() and call {@link #disconnect} during onStop().
- * <p>
- * Then during the {@link IDownloaderClient#onServiceConnected} callback, you
- * should call {@link #getMessenger} to pass the stub's Messenger object to
- * {@link IDownloaderService#onClientUpdated}.
- */
-public interface IStub {
- Messenger getMessenger();
-
- void connect(Context c);
-
- void disconnect(Context c);
-}
diff --git a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/SystemFacade.java b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/SystemFacade.java
deleted file mode 100644
index 12edd97ab2..0000000000
--- a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/SystemFacade.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.vending.expansion.downloader;
-
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-
-/**
- * Contains useful helper functions, typically tied to the application context.
- */
-class SystemFacade {
- private Context mContext;
- private NotificationManager mNotificationManager;
-
- public SystemFacade(Context context) {
- mContext = context;
- mNotificationManager = (NotificationManager)
- mContext.getSystemService(Context.NOTIFICATION_SERVICE);
- }
-
- public long currentTimeMillis() {
- return System.currentTimeMillis();
- }
-
- public Integer getActiveNetworkType() {
- ConnectivityManager connectivity =
- (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
- if (connectivity == null) {
- Log.w(Constants.TAG, "couldn't get connectivity manager");
- return null;
- }
-
- NetworkInfo activeInfo = connectivity.getActiveNetworkInfo();
- if (activeInfo == null) {
- if (Constants.LOGVV) {
- Log.v(Constants.TAG, "network is not available");
- }
- return null;
- }
- return activeInfo.getType();
- }
-
- public boolean isNetworkRoaming() {
- ConnectivityManager connectivity =
- (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
- if (connectivity == null) {
- Log.w(Constants.TAG, "couldn't get connectivity manager");
- return false;
- }
-
- NetworkInfo info = connectivity.getActiveNetworkInfo();
- boolean isMobile = (info != null && info.getType() == ConnectivityManager.TYPE_MOBILE);
- TelephonyManager tm = (TelephonyManager) mContext
- .getSystemService(Context.TELEPHONY_SERVICE);
- if (null == tm) {
- Log.w(Constants.TAG, "couldn't get telephony manager");
- return false;
- }
- boolean isRoaming = isMobile && tm.isNetworkRoaming();
- if (Constants.LOGVV && isRoaming) {
- Log.v(Constants.TAG, "network is roaming");
- }
- return isRoaming;
- }
-
- public Long getMaxBytesOverMobile() {
- return (long) Integer.MAX_VALUE;
- }
-
- public Long getRecommendedMaxBytesOverMobile() {
- return 2097152L;
- }
-
- public void sendBroadcast(Intent intent) {
- mContext.sendBroadcast(intent);
- }
-
- public boolean userOwnsPackage(int uid, String packageName) throws NameNotFoundException {
- return mContext.getPackageManager().getApplicationInfo(packageName, 0).uid == uid;
- }
-
- public void postNotification(long id, Notification notification) {
- /**
- * TODO: The system notification manager takes ints, not longs, as IDs,
- * but the download manager uses IDs take straight from the database,
- * which are longs. This will have to be dealt with at some point.
- */
- mNotificationManager.notify((int) id, notification);
- }
-
- public void cancelNotification(long id) {
- mNotificationManager.cancel((int) id);
- }
-
- public void cancelAllNotifications() {
- mNotificationManager.cancelAll();
- }
-
- public void startThread(Thread thread) {
- thread.start();
- }
-}
diff --git a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/AndroidHttpClient.java b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/AndroidHttpClient.java
deleted file mode 100644
index 4667acce67..0000000000
--- a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/AndroidHttpClient.java
+++ /dev/null
@@ -1,536 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * This is a port of AndroidHttpClient to pre-Froyo devices, that takes advantage of
- * the SSLSessionCache added Froyo devices using reflection.
- */
-
-package com.google.android.vending.expansion.downloader.impl;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.net.URI;
-import java.util.zip.GZIPInputStream;
-import java.util.zip.GZIPOutputStream;
-
-import org.apache.http.Header;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpEntityEnclosingRequest;
-import org.apache.http.HttpException;
-import org.apache.http.HttpHost;
-import org.apache.http.HttpRequest;
-import org.apache.http.HttpRequestInterceptor;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.ClientProtocolException;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.ResponseHandler;
-import org.apache.http.client.methods.HttpUriRequest;
-import org.apache.http.client.params.HttpClientParams;
-import org.apache.http.client.protocol.ClientContext;
-import org.apache.http.conn.ClientConnectionManager;
-import org.apache.http.conn.scheme.PlainSocketFactory;
-import org.apache.http.conn.scheme.Scheme;
-import org.apache.http.conn.scheme.SchemeRegistry;
-import org.apache.http.conn.scheme.SocketFactory;
-import org.apache.http.conn.ssl.SSLSocketFactory;
-import org.apache.http.entity.AbstractHttpEntity;
-import org.apache.http.entity.ByteArrayEntity;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.impl.client.RequestWrapper;
-import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
-import org.apache.http.params.BasicHttpParams;
-import org.apache.http.params.HttpConnectionParams;
-import org.apache.http.params.HttpParams;
-import org.apache.http.params.HttpProtocolParams;
-import org.apache.http.protocol.BasicHttpContext;
-import org.apache.http.protocol.BasicHttpProcessor;
-import org.apache.http.protocol.HttpContext;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.net.SSLCertificateSocketFactory;
-import android.os.Looper;
-import android.util.Log;
-
-/**
- * Subclass of the Apache {@link DefaultHttpClient} that is configured with
- * reasonable default settings and registered schemes for Android, and
- * also lets the user add {@link HttpRequestInterceptor} classes.
- * Don't create this directly, use the {@link #newInstance} factory method.
- *
- * <p>This client processes cookies but does not retain them by default.
- * To retain cookies, simply add a cookie store to the HttpContext:</p>
- *
- * <pre>context.setAttribute(ClientContext.COOKIE_STORE, cookieStore);</pre>
- */
-public final class AndroidHttpClient implements HttpClient {
-
- static Class<?> sSslSessionCacheClass;
- static {
- // if we are on Froyo+ devices, we can take advantage of the SSLSessionCache
- try {
- sSslSessionCacheClass = Class.forName("android.net.SSLSessionCache");
- } catch (Exception e) {
-
- }
- }
-
- // Gzip of data shorter than this probably won't be worthwhile
- public static long DEFAULT_SYNC_MIN_GZIP_BYTES = 256;
-
- // Default connection and socket timeout of 60 seconds. Tweak to taste.
- private static final int SOCKET_OPERATION_TIMEOUT = 60 * 1000;
-
- private static final String TAG = "AndroidHttpClient";
-
-
- /** Interceptor throws an exception if the executing thread is blocked */
- private static final HttpRequestInterceptor sThreadCheckInterceptor =
- new HttpRequestInterceptor() {
- public void process(HttpRequest request, HttpContext context) {
- // Prevent the HttpRequest from being sent on the main thread
- if (Looper.myLooper() != null && Looper.myLooper() == Looper.getMainLooper() ) {
- throw new RuntimeException("This thread forbids HTTP requests");
- }
- }
- };
-
- /**
- * Create a new HttpClient with reasonable defaults (which you can update).
- *
- * @param userAgent to report in your HTTP requests
- * @param context to use for caching SSL sessions (may be null for no caching)
- * @return AndroidHttpClient for you to use for all your requests.
- */
- public static AndroidHttpClient newInstance(String userAgent, Context context) {
- HttpParams params = new BasicHttpParams();
-
- // Turn off stale checking. Our connections break all the time anyway,
- // and it's not worth it to pay the penalty of checking every time.
- HttpConnectionParams.setStaleCheckingEnabled(params, false);
-
- HttpConnectionParams.setConnectionTimeout(params, SOCKET_OPERATION_TIMEOUT);
- HttpConnectionParams.setSoTimeout(params, SOCKET_OPERATION_TIMEOUT);
- HttpConnectionParams.setSocketBufferSize(params, 8192);
-
- // Don't handle redirects -- return them to the caller. Our code
- // often wants to re-POST after a redirect, which we must do ourselves.
- HttpClientParams.setRedirecting(params, false);
-
- Object sessionCache = null;
- // Use a session cache for SSL sockets -- Froyo only
- if ( null != context && null != sSslSessionCacheClass ) {
- Constructor<?> ct;
- try {
- ct = sSslSessionCacheClass.getConstructor(Context.class);
- sessionCache = ct.newInstance(context);
- } catch (SecurityException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (NoSuchMethodException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IllegalArgumentException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (InstantiationException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
-
- // Set the specified user agent and register standard protocols.
- HttpProtocolParams.setUserAgent(params, userAgent);
- SchemeRegistry schemeRegistry = new SchemeRegistry();
- schemeRegistry.register(new Scheme("http",
- PlainSocketFactory.getSocketFactory(), 80));
- SocketFactory sslCertificateSocketFactory = null;
- if ( null != sessionCache ) {
- Method getHttpSocketFactoryMethod;
- try {
- getHttpSocketFactoryMethod = SSLCertificateSocketFactory.class.getDeclaredMethod("getHttpSocketFactory",Integer.TYPE, sSslSessionCacheClass);
- sslCertificateSocketFactory = (SocketFactory)getHttpSocketFactoryMethod.invoke(null, SOCKET_OPERATION_TIMEOUT, sessionCache);
- } catch (SecurityException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (NoSuchMethodException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IllegalArgumentException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (InvocationTargetException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- if ( null == sslCertificateSocketFactory ) {
- sslCertificateSocketFactory = SSLSocketFactory.getSocketFactory();
- }
- schemeRegistry.register(new Scheme("https",
- sslCertificateSocketFactory, 443));
-
- ClientConnectionManager manager =
- new ThreadSafeClientConnManager(params, schemeRegistry);
-
- // We use a factory method to modify superclass initialization
- // parameters without the funny call-a-static-method dance.
- return new AndroidHttpClient(manager, params);
- }
-
- /**
- * Create a new HttpClient with reasonable defaults (which you can update).
- * @param userAgent to report in your HTTP requests.
- * @return AndroidHttpClient for you to use for all your requests.
- */
- public static AndroidHttpClient newInstance(String userAgent) {
- return newInstance(userAgent, null /* session cache */);
- }
-
- private final HttpClient delegate;
-
- private RuntimeException mLeakedException = new IllegalStateException(
- "AndroidHttpClient created and never closed");
-
- private AndroidHttpClient(ClientConnectionManager ccm, HttpParams params) {
- this.delegate = new DefaultHttpClient(ccm, params) {
- @Override
- protected BasicHttpProcessor createHttpProcessor() {
- // Add interceptor to prevent making requests from main thread.
- BasicHttpProcessor processor = super.createHttpProcessor();
- processor.addRequestInterceptor(sThreadCheckInterceptor);
- processor.addRequestInterceptor(new CurlLogger());
-
- return processor;
- }
-
- @Override
- protected HttpContext createHttpContext() {
- // Same as DefaultHttpClient.createHttpContext() minus the
- // cookie store.
- HttpContext context = new BasicHttpContext();
- context.setAttribute(
- ClientContext.AUTHSCHEME_REGISTRY,
- getAuthSchemes());
- context.setAttribute(
- ClientContext.COOKIESPEC_REGISTRY,
- getCookieSpecs());
- context.setAttribute(
- ClientContext.CREDS_PROVIDER,
- getCredentialsProvider());
- return context;
- }
- };
- }
-
- @Override
- protected void finalize() throws Throwable {
- super.finalize();
- if (mLeakedException != null) {
- Log.e(TAG, "Leak found", mLeakedException);
- mLeakedException = null;
- }
- }
-
- /**
- * Modifies a request to indicate to the server that we would like a
- * gzipped response. (Uses the "Accept-Encoding" HTTP header.)
- * @param request the request to modify
- * @see #getUngzippedContent
- */
- public static void modifyRequestToAcceptGzipResponse(HttpRequest request) {
- request.addHeader("Accept-Encoding", "gzip");
- }
-
- /**
- * Gets the input stream from a response entity. If the entity is gzipped
- * then this will get a stream over the uncompressed data.
- *
- * @param entity the entity whose content should be read
- * @return the input stream to read from
- * @throws IOException
- */
- public static InputStream getUngzippedContent(HttpEntity entity)
- throws IOException {
- InputStream responseStream = entity.getContent();
- if (responseStream == null) return responseStream;
- Header header = entity.getContentEncoding();
- if (header == null) return responseStream;
- String contentEncoding = header.getValue();
- if (contentEncoding == null) return responseStream;
- if (contentEncoding.contains("gzip")) responseStream
- = new GZIPInputStream(responseStream);
- return responseStream;
- }
-
- /**
- * Release resources associated with this client. You must call this,
- * or significant resources (sockets and memory) may be leaked.
- */
- public void close() {
- if (mLeakedException != null) {
- getConnectionManager().shutdown();
- mLeakedException = null;
- }
- }
-
- public HttpParams getParams() {
- return delegate.getParams();
- }
-
- public ClientConnectionManager getConnectionManager() {
- return delegate.getConnectionManager();
- }
-
- public HttpResponse execute(HttpUriRequest request) throws IOException {
- return delegate.execute(request);
- }
-
- public HttpResponse execute(HttpUriRequest request, HttpContext context)
- throws IOException {
- return delegate.execute(request, context);
- }
-
- public HttpResponse execute(HttpHost target, HttpRequest request)
- throws IOException {
- return delegate.execute(target, request);
- }
-
- public HttpResponse execute(HttpHost target, HttpRequest request,
- HttpContext context) throws IOException {
- return delegate.execute(target, request, context);
- }
-
- public <T> T execute(HttpUriRequest request,
- ResponseHandler<? extends T> responseHandler)
- throws IOException, ClientProtocolException {
- return delegate.execute(request, responseHandler);
- }
-
- public <T> T execute(HttpUriRequest request,
- ResponseHandler<? extends T> responseHandler, HttpContext context)
- throws IOException, ClientProtocolException {
- return delegate.execute(request, responseHandler, context);
- }
-
- public <T> T execute(HttpHost target, HttpRequest request,
- ResponseHandler<? extends T> responseHandler) throws IOException,
- ClientProtocolException {
- return delegate.execute(target, request, responseHandler);
- }
-
- public <T> T execute(HttpHost target, HttpRequest request,
- ResponseHandler<? extends T> responseHandler, HttpContext context)
- throws IOException, ClientProtocolException {
- return delegate.execute(target, request, responseHandler, context);
- }
-
- /**
- * Compress data to send to server.
- * Creates a Http Entity holding the gzipped data.
- * The data will not be compressed if it is too short.
- * @param data The bytes to compress
- * @return Entity holding the data
- */
- public static AbstractHttpEntity getCompressedEntity(byte data[], ContentResolver resolver)
- throws IOException {
- AbstractHttpEntity entity;
- if (data.length < getMinGzipSize(resolver)) {
- entity = new ByteArrayEntity(data);
- } else {
- ByteArrayOutputStream arr = new ByteArrayOutputStream();
- OutputStream zipper = new GZIPOutputStream(arr);
- zipper.write(data);
- zipper.close();
- entity = new ByteArrayEntity(arr.toByteArray());
- entity.setContentEncoding("gzip");
- }
- return entity;
- }
-
- /**
- * Retrieves the minimum size for compressing data.
- * Shorter data will not be compressed.
- */
- public static long getMinGzipSize(ContentResolver resolver) {
- return DEFAULT_SYNC_MIN_GZIP_BYTES; // For now, this is just a constant.
- }
-
- /* cURL logging support. */
-
- /**
- * Logging tag and level.
- */
- private static class LoggingConfiguration {
-
- private final String tag;
- private final int level;
-
- private LoggingConfiguration(String tag, int level) {
- this.tag = tag;
- this.level = level;
- }
-
- /**
- * Returns true if logging is turned on for this configuration.
- */
- private boolean isLoggable() {
- return Log.isLoggable(tag, level);
- }
-
- /**
- * Prints a message using this configuration.
- */
- private void println(String message) {
- Log.println(level, tag, message);
- }
- }
-
- /** cURL logging configuration. */
- private volatile LoggingConfiguration curlConfiguration;
-
- /**
- * Enables cURL request logging for this client.
- *
- * @param name to log messages with
- * @param level at which to log messages (see {@link android.util.Log})
- */
- public void enableCurlLogging(String name, int level) {
- if (name == null) {
- throw new NullPointerException("name");
- }
- if (level < Log.VERBOSE || level > Log.ASSERT) {
- throw new IllegalArgumentException("Level is out of range ["
- + Log.VERBOSE + ".." + Log.ASSERT + "]");
- }
-
- curlConfiguration = new LoggingConfiguration(name, level);
- }
-
- /**
- * Disables cURL logging for this client.
- */
- public void disableCurlLogging() {
- curlConfiguration = null;
- }
-
- /**
- * Logs cURL commands equivalent to requests.
- */
- private class CurlLogger implements HttpRequestInterceptor {
- public void process(HttpRequest request, HttpContext context)
- throws HttpException, IOException {
- LoggingConfiguration configuration = curlConfiguration;
- if (configuration != null
- && configuration.isLoggable()
- && request instanceof HttpUriRequest) {
- // Never print auth token -- we used to check ro.secure=0 to
- // enable that, but can't do that in unbundled code.
- configuration.println(toCurl((HttpUriRequest) request, false));
- }
- }
- }
-
- /**
- * Generates a cURL command equivalent to the given request.
- */
- private static String toCurl(HttpUriRequest request, boolean logAuthToken) throws IOException {
- StringBuilder builder = new StringBuilder();
-
- builder.append("curl ");
-
- for (Header header: request.getAllHeaders()) {
- if (!logAuthToken
- && (header.getName().equals("Authorization") ||
- header.getName().equals("Cookie"))) {
- continue;
- }
- builder.append("--header \"");
- builder.append(header.toString().trim());
- builder.append("\" ");
- }
-
- URI uri = request.getURI();
-
- // If this is a wrapped request, use the URI from the original
- // request instead. getURI() on the wrapper seems to return a
- // relative URI. We want an absolute URI.
- if (request instanceof RequestWrapper) {
- HttpRequest original = ((RequestWrapper) request).getOriginal();
- if (original instanceof HttpUriRequest) {
- uri = ((HttpUriRequest) original).getURI();
- }
- }
-
- builder.append("\"");
- builder.append(uri);
- builder.append("\"");
-
- if (request instanceof HttpEntityEnclosingRequest) {
- HttpEntityEnclosingRequest entityRequest =
- (HttpEntityEnclosingRequest) request;
- HttpEntity entity = entityRequest.getEntity();
- if (entity != null && entity.isRepeatable()) {
- if (entity.getContentLength() < 1024) {
- ByteArrayOutputStream stream = new ByteArrayOutputStream();
- entity.writeTo(stream);
- String entityString = stream.toString();
-
- // TODO: Check the content type, too.
- builder.append(" --data-ascii \"")
- .append(entityString)
- .append("\"");
- } else {
- builder.append(" [TOO MUCH DATA TO INCLUDE]");
- }
- }
- }
-
- return builder.toString();
- }
-
- /**
- * Returns the date of the given HTTP date string. This method can identify
- * and parse the date formats emitted by common HTTP servers, such as
- * <a href="http://www.ietf.org/rfc/rfc0822.txt">RFC 822</a>,
- * <a href="http://www.ietf.org/rfc/rfc0850.txt">RFC 850</a>,
- * <a href="http://www.ietf.org/rfc/rfc1036.txt">RFC 1036</a>,
- * <a href="http://www.ietf.org/rfc/rfc1123.txt">RFC 1123</a> and
- * <a href="http://www.opengroup.org/onlinepubs/007908799/xsh/asctime.html">ANSI
- * C's asctime()</a>.
- *
- * @return the number of milliseconds since Jan. 1, 1970, midnight GMT.
- * @throws IllegalArgumentException if {@code dateString} is not a date or
- * of an unsupported format.
- */
- public static long parseDate(String dateString) {
- return HttpDateTime.parse(dateString);
- }
-} \ No newline at end of file
diff --git a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/CustomIntentService.java b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/CustomIntentService.java
deleted file mode 100755
index b77af7e085..0000000000
--- a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/CustomIntentService.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.vending.expansion.downloader.impl;
-
-import android.app.Service;
-import android.content.Intent;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.Message;
-import android.util.Log;
-
-/**
- * This service differs from IntentService in a few minor ways/ It will not
- * auto-stop itself after the intent is handled unless the target returns "true"
- * in should stop. Since the goal of this service is to handle a single kind of
- * intent, it does not queue up batches of intents of the same type.
- */
-public abstract class CustomIntentService extends Service {
- private String mName;
- private boolean mRedelivery;
- private volatile ServiceHandler mServiceHandler;
- private volatile Looper mServiceLooper;
- private static final String LOG_TAG = "CancellableIntentService";
- private static final int WHAT_MESSAGE = -10;
-
- public CustomIntentService(String paramString) {
- this.mName = paramString;
- }
-
- @Override
- public IBinder onBind(Intent paramIntent) {
- return null;
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- HandlerThread localHandlerThread = new HandlerThread("IntentService["
- + this.mName + "]");
- localHandlerThread.start();
- this.mServiceLooper = localHandlerThread.getLooper();
- this.mServiceHandler = new ServiceHandler(this.mServiceLooper);
- }
-
- @Override
- public void onDestroy() {
- Thread localThread = this.mServiceLooper.getThread();
- if ((localThread != null) && (localThread.isAlive())) {
- localThread.interrupt();
- }
- this.mServiceLooper.quit();
- Log.d(LOG_TAG, "onDestroy");
- }
-
- protected abstract void onHandleIntent(Intent paramIntent);
-
- protected abstract boolean shouldStop();
-
- @Override
- public void onStart(Intent paramIntent, int startId) {
- if (!this.mServiceHandler.hasMessages(WHAT_MESSAGE)) {
- Message localMessage = this.mServiceHandler.obtainMessage();
- localMessage.arg1 = startId;
- localMessage.obj = paramIntent;
- localMessage.what = WHAT_MESSAGE;
- this.mServiceHandler.sendMessage(localMessage);
- }
- }
-
- @Override
- public int onStartCommand(Intent paramIntent, int flags, int startId) {
- onStart(paramIntent, startId);
- return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
- }
-
- public void setIntentRedelivery(boolean enabled) {
- this.mRedelivery = enabled;
- }
-
- private final class ServiceHandler extends Handler {
- public ServiceHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message paramMessage) {
- CustomIntentService.this
- .onHandleIntent((Intent) paramMessage.obj);
- if (shouldStop()) {
- Log.d(LOG_TAG, "stopSelf");
- CustomIntentService.this.stopSelf(paramMessage.arg1);
- Log.d(LOG_TAG, "afterStopSelf");
- }
- }
- }
-}
diff --git a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/CustomNotificationFactory.java b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/CustomNotificationFactory.java
deleted file mode 100644
index 9a0ca02122..0000000000
--- a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/CustomNotificationFactory.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.vending.expansion.downloader.impl;
-
-/**
- * Uses the class-loader model to utilize the updated notification builders in
- * Honeycomb while maintaining a compatible version for older devices.
- */
-public class CustomNotificationFactory {
- static public DownloadNotification.ICustomNotification createCustomNotification() {
- if (android.os.Build.VERSION.SDK_INT > 13)
- return new V14CustomNotification();
- else
- return new V3CustomNotification();
- }
-}
diff --git a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/DownloadInfo.java b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/DownloadInfo.java
deleted file mode 100644
index 45111b16a3..0000000000
--- a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/DownloadInfo.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.vending.expansion.downloader.impl;
-
-import com.google.android.vending.expansion.downloader.Constants;
-import com.google.android.vending.expansion.downloader.Helpers;
-
-import android.util.Log;
-
-/**
- * Representation of information about an individual download from the database.
- */
-public class DownloadInfo {
- public String mUri;
- public final int mIndex;
- public final String mFileName;
- public String mETag;
- public long mTotalBytes;
- public long mCurrentBytes;
- public long mLastMod;
- public int mStatus;
- public int mControl;
- public int mNumFailed;
- public int mRetryAfter;
- public int mRedirectCount;
-
- boolean mInitialized;
-
- public int mFuzz;
-
- public DownloadInfo(int index, String fileName, String pkg) {
- mFuzz = Helpers.sRandom.nextInt(1001);
- mFileName = fileName;
- mIndex = index;
- }
-
- public void resetDownload() {
- mCurrentBytes = 0;
- mETag = "";
- mLastMod = 0;
- mStatus = 0;
- mControl = 0;
- mNumFailed = 0;
- mRetryAfter = 0;
- mRedirectCount = 0;
- }
-
- /**
- * Returns the time when a download should be restarted.
- */
- public long restartTime(long now) {
- if (mNumFailed == 0) {
- return now;
- }
- if (mRetryAfter > 0) {
- return mLastMod + mRetryAfter;
- }
- return mLastMod +
- Constants.RETRY_FIRST_DELAY *
- (1000 + mFuzz) * (1 << (mNumFailed - 1));
- }
-
- public void logVerboseInfo() {
- Log.v(Constants.TAG, "Service adding new entry");
- Log.v(Constants.TAG, "FILENAME: " + mFileName);
- Log.v(Constants.TAG, "URI : " + mUri);
- Log.v(Constants.TAG, "FILENAME: " + mFileName);
- Log.v(Constants.TAG, "CONTROL : " + mControl);
- Log.v(Constants.TAG, "STATUS : " + mStatus);
- Log.v(Constants.TAG, "FAILED_C: " + mNumFailed);
- Log.v(Constants.TAG, "RETRY_AF: " + mRetryAfter);
- Log.v(Constants.TAG, "REDIRECT: " + mRedirectCount);
- Log.v(Constants.TAG, "LAST_MOD: " + mLastMod);
- Log.v(Constants.TAG, "TOTAL : " + mTotalBytes);
- Log.v(Constants.TAG, "CURRENT : " + mCurrentBytes);
- Log.v(Constants.TAG, "ETAG : " + mETag);
- }
-}
diff --git a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java
deleted file mode 100644
index eef205d7b7..0000000000
--- a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/DownloadNotification.java
+++ /dev/null
@@ -1,231 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.vending.expansion.downloader.impl;
-
-import com.android.vending.expansion.downloader.R;
-import com.google.android.vending.expansion.downloader.DownloadProgressInfo;
-import com.google.android.vending.expansion.downloader.DownloaderClientMarshaller;
-import com.google.android.vending.expansion.downloader.Helpers;
-import com.google.android.vending.expansion.downloader.IDownloaderClient;
-
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.os.Messenger;
-
-/**
- * This class handles displaying the notification associated with the download
- * queue going on in the download manager. It handles multiple status types;
- * Some require user interaction and some do not. Some of the user interactions
- * may be transient. (for example: the user is queried to continue the download
- * on 3G when it started on WiFi, but then the phone locks onto WiFi again so
- * the prompt automatically goes away)
- * <p/>
- * The application interface for the downloader also needs to understand and
- * handle these transient states.
- */
-public class DownloadNotification implements IDownloaderClient {
-
- private int mState;
- private final Context mContext;
- private final NotificationManager mNotificationManager;
- private String mCurrentTitle;
-
- private IDownloaderClient mClientProxy;
- final ICustomNotification mCustomNotification;
- private Notification mNotification;
- private Notification mCurrentNotification;
- private CharSequence mLabel;
- private String mCurrentText;
- private PendingIntent mContentIntent;
- private DownloadProgressInfo mProgressInfo;
-
- static final String LOGTAG = "DownloadNotification";
- static final int NOTIFICATION_ID = LOGTAG.hashCode();
-
- public PendingIntent getClientIntent() {
- return mContentIntent;
- }
-
- public void setClientIntent(PendingIntent mClientIntent) {
- this.mContentIntent = mClientIntent;
- }
-
- public void resendState() {
- if (null != mClientProxy) {
- mClientProxy.onDownloadStateChanged(mState);
- }
- }
-
- @Override
- public void onDownloadStateChanged(int newState) {
- if (null != mClientProxy) {
- mClientProxy.onDownloadStateChanged(newState);
- }
- if (newState != mState) {
- mState = newState;
- if (newState == IDownloaderClient.STATE_IDLE || null == mContentIntent) {
- return;
- }
- int stringDownloadID;
- int iconResource;
- boolean ongoingEvent;
-
- // get the new title string and paused text
- switch (newState) {
- case 0:
- iconResource = android.R.drawable.stat_sys_warning;
- stringDownloadID = R.string.state_unknown;
- ongoingEvent = false;
- break;
-
- case IDownloaderClient.STATE_DOWNLOADING:
- iconResource = android.R.drawable.stat_sys_download;
- stringDownloadID = Helpers.getDownloaderStringResourceIDFromState(newState);
- ongoingEvent = true;
- break;
-
- case IDownloaderClient.STATE_FETCHING_URL:
- case IDownloaderClient.STATE_CONNECTING:
- iconResource = android.R.drawable.stat_sys_download_done;
- stringDownloadID = Helpers.getDownloaderStringResourceIDFromState(newState);
- ongoingEvent = true;
- break;
-
- case IDownloaderClient.STATE_COMPLETED:
- case IDownloaderClient.STATE_PAUSED_BY_REQUEST:
- iconResource = android.R.drawable.stat_sys_download_done;
- stringDownloadID = Helpers.getDownloaderStringResourceIDFromState(newState);
- ongoingEvent = false;
- break;
-
- case IDownloaderClient.STATE_FAILED:
- case IDownloaderClient.STATE_FAILED_CANCELED:
- case IDownloaderClient.STATE_FAILED_FETCHING_URL:
- case IDownloaderClient.STATE_FAILED_SDCARD_FULL:
- case IDownloaderClient.STATE_FAILED_UNLICENSED:
- iconResource = android.R.drawable.stat_sys_warning;
- stringDownloadID = Helpers.getDownloaderStringResourceIDFromState(newState);
- ongoingEvent = false;
- break;
-
- default:
- iconResource = android.R.drawable.stat_sys_warning;
- stringDownloadID = Helpers.getDownloaderStringResourceIDFromState(newState);
- ongoingEvent = true;
- break;
- }
- mCurrentText = mContext.getString(stringDownloadID);
- mCurrentTitle = mLabel.toString();
- mCurrentNotification.tickerText = mLabel + ": " + mCurrentText;
- mCurrentNotification.icon = iconResource;
- mCurrentNotification.setLatestEventInfo(mContext, mCurrentTitle, mCurrentText,
- mContentIntent);
- if (ongoingEvent) {
- mCurrentNotification.flags |= Notification.FLAG_ONGOING_EVENT;
- } else {
- mCurrentNotification.flags &= ~Notification.FLAG_ONGOING_EVENT;
- mCurrentNotification.flags |= Notification.FLAG_AUTO_CANCEL;
- }
- mNotificationManager.notify(NOTIFICATION_ID, mCurrentNotification);
- }
- }
-
- @Override
- public void onDownloadProgress(DownloadProgressInfo progress) {
- mProgressInfo = progress;
- if (null != mClientProxy) {
- mClientProxy.onDownloadProgress(progress);
- }
- if (progress.mOverallTotal <= 0) {
- // we just show the text
- mNotification.tickerText = mCurrentTitle;
- mNotification.icon = android.R.drawable.stat_sys_download;
- mNotification.setLatestEventInfo(mContext, mLabel, mCurrentText, mContentIntent);
- mCurrentNotification = mNotification;
- } else {
- mCustomNotification.setCurrentBytes(progress.mOverallProgress);
- mCustomNotification.setTotalBytes(progress.mOverallTotal);
- mCustomNotification.setIcon(android.R.drawable.stat_sys_download);
- mCustomNotification.setPendingIntent(mContentIntent);
- mCustomNotification.setTicker(mLabel + ": " + mCurrentText);
- mCustomNotification.setTitle(mLabel);
- mCustomNotification.setTimeRemaining(progress.mTimeRemaining);
- mCurrentNotification = mCustomNotification.updateNotification(mContext);
- }
- mNotificationManager.notify(NOTIFICATION_ID, mCurrentNotification);
- }
-
- public interface ICustomNotification {
- void setTitle(CharSequence title);
-
- void setTicker(CharSequence ticker);
-
- void setPendingIntent(PendingIntent mContentIntent);
-
- void setTotalBytes(long totalBytes);
-
- void setCurrentBytes(long currentBytes);
-
- void setIcon(int iconResource);
-
- void setTimeRemaining(long timeRemaining);
-
- Notification updateNotification(Context c);
- }
-
- /**
- * Called in response to onClientUpdated. Creates a new proxy and notifies
- * it of the current state.
- *
- * @param msg the client Messenger to notify
- */
- public void setMessenger(Messenger msg) {
- mClientProxy = DownloaderClientMarshaller.CreateProxy(msg);
- if (null != mProgressInfo) {
- mClientProxy.onDownloadProgress(mProgressInfo);
- }
- if (mState != -1) {
- mClientProxy.onDownloadStateChanged(mState);
- }
- }
-
- /**
- * Constructor
- *
- * @param ctx The context to use to obtain access to the Notification
- * Service
- */
- DownloadNotification(Context ctx, CharSequence applicationLabel) {
- mState = -1;
- mContext = ctx;
- mLabel = applicationLabel;
- mNotificationManager = (NotificationManager)
- mContext.getSystemService(Context.NOTIFICATION_SERVICE);
- mCustomNotification = CustomNotificationFactory
- .createCustomNotification();
- mNotification = new Notification();
- mCurrentNotification = mNotification;
-
- }
-
- @Override
- public void onServiceConnected(Messenger m) {
- }
-
-}
diff --git a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/DownloadThread.java b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/DownloadThread.java
deleted file mode 100644
index 056d1eca0b..0000000000
--- a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/DownloadThread.java
+++ /dev/null
@@ -1,963 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.vending.expansion.downloader.impl;
-
-import com.google.android.vending.expansion.downloader.Constants;
-import com.google.android.vending.expansion.downloader.Helpers;
-import com.google.android.vending.expansion.downloader.IDownloaderClient;
-
-import org.apache.http.Header;
-import org.apache.http.HttpHost;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.conn.params.ConnRouteParams;
-
-import android.content.Context;
-import android.net.Proxy;
-import android.os.PowerManager;
-import android.os.Process;
-import android.util.Log;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.SyncFailedException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.Locale;
-
-/**
- * Runs an actual download
- */
-public class DownloadThread {
-
- private Context mContext;
- private DownloadInfo mInfo;
- private DownloaderService mService;
- private final DownloadsDB mDB;
- private final DownloadNotification mNotification;
- private String mUserAgent;
-
- public DownloadThread(DownloadInfo info, DownloaderService service,
- DownloadNotification notification) {
- mContext = service;
- mInfo = info;
- mService = service;
- mNotification = notification;
- mDB = DownloadsDB.getDB(service);
- mUserAgent = "APKXDL (Linux; U; Android " + android.os.Build.VERSION.RELEASE + ";"
- + Locale.getDefault().toString() + "; " + android.os.Build.DEVICE + "/"
- + android.os.Build.ID + ")" +
- service.getPackageName();
- }
-
- /**
- * Returns the default user agent
- */
- private String userAgent() {
- return mUserAgent;
- }
-
- /**
- * State for the entire run() method.
- */
- private static class State {
- public String mFilename;
- public FileOutputStream mStream;
- public boolean mCountRetry = false;
- public int mRetryAfter = 0;
- public int mRedirectCount = 0;
- public String mNewUri;
- public boolean mGotData = false;
- public String mRequestUri;
-
- public State(DownloadInfo info, DownloaderService service) {
- mRedirectCount = info.mRedirectCount;
- mRequestUri = info.mUri;
- mFilename = service.generateTempSaveFileName(info.mFileName);
- }
- }
-
- /**
- * State within executeDownload()
- */
- private static class InnerState {
- public int mBytesSoFar = 0;
- public int mBytesThisSession = 0;
- public String mHeaderETag;
- public boolean mContinuingDownload = false;
- public String mHeaderContentLength;
- public String mHeaderContentDisposition;
- public String mHeaderContentLocation;
- public int mBytesNotified = 0;
- public long mTimeLastNotification = 0;
- }
-
- /**
- * Raised from methods called by run() to indicate that the current request
- * should be stopped immediately. Note the message passed to this exception
- * will be logged and therefore must be guaranteed not to contain any PII,
- * meaning it generally can't include any information about the request URI,
- * headers, or destination filename.
- */
- private class StopRequest extends Throwable {
- /**
- *
- */
- private static final long serialVersionUID = 6338592678988347973L;
- public int mFinalStatus;
-
- public StopRequest(int finalStatus, String message) {
- super(message);
- mFinalStatus = finalStatus;
- }
-
- public StopRequest(int finalStatus, String message, Throwable throwable) {
- super(message, throwable);
- mFinalStatus = finalStatus;
- }
- }
-
- /**
- * Raised from methods called by executeDownload() to indicate that the
- * download should be retried immediately.
- */
- private class RetryDownload extends Throwable {
-
- /**
- *
- */
- private static final long serialVersionUID = 6196036036517540229L;
- }
-
- /**
- * Returns the preferred proxy to be used by clients. This is a wrapper
- * around {@link android.net.Proxy#getHost()}. Currently no proxy will be
- * returned for localhost or if the active network is Wi-Fi.
- *
- * @param context the context which will be passed to
- * {@link android.net.Proxy#getHost()}
- * @param url the target URL for the request
- * @note Calling this method requires permission
- * android.permission.ACCESS_NETWORK_STATE
- * @return The preferred proxy to be used by clients, or null if there is no
- * proxy.
- */
- public HttpHost getPreferredHttpHost(Context context,
- String url) {
- if (!isLocalHost(url) && !mService.isWiFi()) {
- final String proxyHost = Proxy.getHost(context);
- if (proxyHost != null) {
- return new HttpHost(proxyHost, Proxy.getPort(context), "http");
- }
- }
-
- return null;
- }
-
- static final private boolean isLocalHost(String url) {
- if (url == null) {
- return false;
- }
-
- try {
- final URI uri = URI.create(url);
- final String host = uri.getHost();
- if (host != null) {
- // TODO: InetAddress.isLoopbackAddress should be used to check
- // for localhost. However no public factory methods exist which
- // can be used without triggering DNS lookup if host is not
- // localhost.
- if (host.equalsIgnoreCase("localhost") ||
- host.equals("127.0.0.1") ||
- host.equals("[::1]")) {
- return true;
- }
- }
- } catch (IllegalArgumentException iex) {
- // Ignore (URI.create)
- }
-
- return false;
- }
-
- /**
- * Executes the download in a separate thread
- */
- public void run() {
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-
- State state = new State(mInfo, mService);
- AndroidHttpClient client = null;
- PowerManager.WakeLock wakeLock = null;
- int finalStatus = DownloaderService.STATUS_UNKNOWN_ERROR;
-
- try {
- PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
- wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, Constants.TAG);
- wakeLock.acquire();
-
- if (Constants.LOGV) {
- Log.v(Constants.TAG, "initiating download for " + mInfo.mFileName);
- Log.v(Constants.TAG, " at " + mInfo.mUri);
- }
-
- client = AndroidHttpClient.newInstance(userAgent(), mContext);
-
- boolean finished = false;
- while (!finished) {
- if (Constants.LOGV) {
- Log.v(Constants.TAG, "initiating download for " + mInfo.mFileName);
- Log.v(Constants.TAG, " at " + mInfo.mUri);
- }
- // Set or unset proxy, which may have changed since last GET
- // request.
- // setDefaultProxy() supports null as proxy parameter.
- ConnRouteParams.setDefaultProxy(client.getParams(),
- getPreferredHttpHost(mContext, state.mRequestUri));
- HttpGet request = new HttpGet(state.mRequestUri);
- try {
- executeDownload(state, client, request);
- finished = true;
- } catch (RetryDownload exc) {
- // fall through
- } finally {
- request.abort();
- request = null;
- }
- }
-
- if (Constants.LOGV) {
- Log.v(Constants.TAG, "download completed for " + mInfo.mFileName);
- Log.v(Constants.TAG, " at " + mInfo.mUri);
- }
- finalizeDestinationFile(state);
- finalStatus = DownloaderService.STATUS_SUCCESS;
- } catch (StopRequest error) {
- // remove the cause before printing, in case it contains PII
- Log.w(Constants.TAG,
- "Aborting request for download " + mInfo.mFileName + ": " + error.getMessage());
- error.printStackTrace();
- finalStatus = error.mFinalStatus;
- // fall through to finally block
- } catch (Throwable ex) { // sometimes the socket code throws unchecked
- // exceptions
- Log.w(Constants.TAG, "Exception for " + mInfo.mFileName + ": " + ex);
- finalStatus = DownloaderService.STATUS_UNKNOWN_ERROR;
- // falls through to the code that reports an error
- } finally {
- if (wakeLock != null) {
- wakeLock.release();
- wakeLock = null;
- }
- if (client != null) {
- client.close();
- client = null;
- }
- cleanupDestination(state, finalStatus);
- notifyDownloadCompleted(finalStatus, state.mCountRetry, state.mRetryAfter,
- state.mRedirectCount, state.mGotData, state.mFilename);
- }
- }
-
- /**
- * Fully execute a single download request - setup and send the request,
- * handle the response, and transfer the data to the destination file.
- */
- private void executeDownload(State state, AndroidHttpClient client, HttpGet request)
- throws StopRequest, RetryDownload {
- InnerState innerState = new InnerState();
- byte data[] = new byte[Constants.BUFFER_SIZE];
-
- checkPausedOrCanceled(state);
-
- setupDestinationFile(state, innerState);
- addRequestHeaders(innerState, request);
-
- // check just before sending the request to avoid using an invalid
- // connection at all
- checkConnectivity(state);
-
- mNotification.onDownloadStateChanged(IDownloaderClient.STATE_CONNECTING);
- HttpResponse response = sendRequest(state, client, request);
- handleExceptionalStatus(state, innerState, response);
-
- if (Constants.LOGV) {
- Log.v(Constants.TAG, "received response for " + mInfo.mUri);
- }
-
- processResponseHeaders(state, innerState, response);
- InputStream entityStream = openResponseEntity(state, response);
- mNotification.onDownloadStateChanged(IDownloaderClient.STATE_DOWNLOADING);
- transferData(state, innerState, data, entityStream);
- }
-
- /**
- * Check if current connectivity is valid for this request.
- */
- private void checkConnectivity(State state) throws StopRequest {
- switch (mService.getNetworkAvailabilityState(mDB)) {
- case DownloaderService.NETWORK_OK:
- return;
- case DownloaderService.NETWORK_NO_CONNECTION:
- throw new StopRequest(DownloaderService.STATUS_WAITING_FOR_NETWORK,
- "waiting for network to return");
- case DownloaderService.NETWORK_TYPE_DISALLOWED_BY_REQUESTOR:
- throw new StopRequest(
- DownloaderService.STATUS_QUEUED_FOR_WIFI_OR_CELLULAR_PERMISSION,
- "waiting for wifi or for download over cellular to be authorized");
- case DownloaderService.NETWORK_CANNOT_USE_ROAMING:
- throw new StopRequest(DownloaderService.STATUS_WAITING_FOR_NETWORK,
- "roaming is not allowed");
- case DownloaderService.NETWORK_UNUSABLE_DUE_TO_SIZE:
- throw new StopRequest(DownloaderService.STATUS_QUEUED_FOR_WIFI, "waiting for wifi");
- }
- }
-
- /**
- * Transfer as much data as possible from the HTTP response to the
- * destination file.
- *
- * @param data buffer to use to read data
- * @param entityStream stream for reading the HTTP response entity
- */
- private void transferData(State state, InnerState innerState, byte[] data,
- InputStream entityStream) throws StopRequest {
- for (;;) {
- int bytesRead = readFromResponse(state, innerState, data, entityStream);
- if (bytesRead == -1) { // success, end of stream already reached
- handleEndOfStream(state, innerState);
- return;
- }
-
- state.mGotData = true;
- writeDataToDestination(state, data, bytesRead);
- innerState.mBytesSoFar += bytesRead;
- innerState.mBytesThisSession += bytesRead;
- reportProgress(state, innerState);
-
- checkPausedOrCanceled(state);
- }
- }
-
- /**
- * Called after a successful completion to take any necessary action on the
- * downloaded file.
- */
- private void finalizeDestinationFile(State state) throws StopRequest {
- syncDestination(state);
- String tempFilename = state.mFilename;
- String finalFilename = Helpers.generateSaveFileName(mService, mInfo.mFileName);
- if (!state.mFilename.equals(finalFilename)) {
- File startFile = new File(tempFilename);
- File destFile = new File(finalFilename);
- if (mInfo.mTotalBytes != -1 && mInfo.mCurrentBytes == mInfo.mTotalBytes) {
- if (!startFile.renameTo(destFile)) {
- throw new StopRequest(DownloaderService.STATUS_FILE_ERROR,
- "unable to finalize destination file");
- }
- } else {
- throw new StopRequest(DownloaderService.STATUS_FILE_DELIVERED_INCORRECTLY,
- "file delivered with incorrect size. probably due to network not browser configured");
- }
- }
- }
-
- /**
- * Called just before the thread finishes, regardless of status, to take any
- * necessary action on the downloaded file.
- */
- private void cleanupDestination(State state, int finalStatus) {
- closeDestination(state);
- if (state.mFilename != null && DownloaderService.isStatusError(finalStatus)) {
- new File(state.mFilename).delete();
- state.mFilename = null;
- }
- }
-
- /**
- * Sync the destination file to storage.
- */
- private void syncDestination(State state) {
- FileOutputStream downloadedFileStream = null;
- try {
- downloadedFileStream = new FileOutputStream(state.mFilename, true);
- downloadedFileStream.getFD().sync();
- } catch (FileNotFoundException ex) {
- Log.w(Constants.TAG, "file " + state.mFilename + " not found: " + ex);
- } catch (SyncFailedException ex) {
- Log.w(Constants.TAG, "file " + state.mFilename + " sync failed: " + ex);
- } catch (IOException ex) {
- Log.w(Constants.TAG, "IOException trying to sync " + state.mFilename + ": " + ex);
- } catch (RuntimeException ex) {
- Log.w(Constants.TAG, "exception while syncing file: ", ex);
- } finally {
- if (downloadedFileStream != null) {
- try {
- downloadedFileStream.close();
- } catch (IOException ex) {
- Log.w(Constants.TAG, "IOException while closing synced file: ", ex);
- } catch (RuntimeException ex) {
- Log.w(Constants.TAG, "exception while closing file: ", ex);
- }
- }
- }
- }
-
- /**
- * Close the destination output stream.
- */
- private void closeDestination(State state) {
- try {
- // close the file
- if (state.mStream != null) {
- state.mStream.close();
- state.mStream = null;
- }
- } catch (IOException ex) {
- if (Constants.LOGV) {
- Log.v(Constants.TAG, "exception when closing the file after download : " + ex);
- }
- // nothing can really be done if the file can't be closed
- }
- }
-
- /**
- * Check if the download has been paused or canceled, stopping the request
- * appropriately if it has been.
- */
- private void checkPausedOrCanceled(State state) throws StopRequest {
- if (mService.getControl() == DownloaderService.CONTROL_PAUSED) {
- int status = mService.getStatus();
- switch (status) {
- case DownloaderService.STATUS_PAUSED_BY_APP:
- throw new StopRequest(mService.getStatus(),
- "download paused");
- }
- }
- }
-
- /**
- * Report download progress through the database if necessary.
- */
- private void reportProgress(State state, InnerState innerState) {
- long now = System.currentTimeMillis();
- if (innerState.mBytesSoFar - innerState.mBytesNotified
- > Constants.MIN_PROGRESS_STEP
- && now - innerState.mTimeLastNotification
- > Constants.MIN_PROGRESS_TIME) {
- // we store progress updates to the database here
- mInfo.mCurrentBytes = innerState.mBytesSoFar;
- mDB.updateDownloadCurrentBytes(mInfo);
-
- innerState.mBytesNotified = innerState.mBytesSoFar;
- innerState.mTimeLastNotification = now;
-
- long totalBytesSoFar = innerState.mBytesThisSession + mService.mBytesSoFar;
-
- if (Constants.LOGVV) {
- Log.v(Constants.TAG, "downloaded " + mInfo.mCurrentBytes + " out of "
- + mInfo.mTotalBytes);
- Log.v(Constants.TAG, " total " + totalBytesSoFar + " out of "
- + mService.mTotalLength);
- }
-
- mService.notifyUpdateBytes(totalBytesSoFar);
- }
- }
-
- /**
- * Write a data buffer to the destination file.
- *
- * @param data buffer containing the data to write
- * @param bytesRead how many bytes to write from the buffer
- */
- private void writeDataToDestination(State state, byte[] data, int bytesRead)
- throws StopRequest {
- for (;;) {
- try {
- if (state.mStream == null) {
- state.mStream = new FileOutputStream(state.mFilename, true);
- }
- state.mStream.write(data, 0, bytesRead);
- // we close after every write --- this may be too inefficient
- closeDestination(state);
- return;
- } catch (IOException ex) {
- if (!Helpers.isExternalMediaMounted()) {
- throw new StopRequest(DownloaderService.STATUS_DEVICE_NOT_FOUND_ERROR,
- "external media not mounted while writing destination file");
- }
-
- long availableBytes =
- Helpers.getAvailableBytes(Helpers.getFilesystemRoot(state.mFilename));
- if (availableBytes < bytesRead) {
- throw new StopRequest(DownloaderService.STATUS_INSUFFICIENT_SPACE_ERROR,
- "insufficient space while writing destination file", ex);
- }
- throw new StopRequest(DownloaderService.STATUS_FILE_ERROR,
- "while writing destination file: " + ex.toString(), ex);
- }
- }
- }
-
- /**
- * Called when we've reached the end of the HTTP response stream, to update
- * the database and check for consistency.
- */
- private void handleEndOfStream(State state, InnerState innerState) throws StopRequest {
- mInfo.mCurrentBytes = innerState.mBytesSoFar;
- // this should always be set from the market
- // if ( innerState.mHeaderContentLength == null ) {
- // mInfo.mTotalBytes = innerState.mBytesSoFar;
- // }
- mDB.updateDownload(mInfo);
-
- boolean lengthMismatched = (innerState.mHeaderContentLength != null)
- && (innerState.mBytesSoFar != Integer.parseInt(innerState.mHeaderContentLength));
- if (lengthMismatched) {
- if (cannotResume(innerState)) {
- throw new StopRequest(DownloaderService.STATUS_CANNOT_RESUME,
- "mismatched content length");
- } else {
- throw new StopRequest(getFinalStatusForHttpError(state),
- "closed socket before end of file");
- }
- }
- }
-
- private boolean cannotResume(InnerState innerState) {
- return innerState.mBytesSoFar > 0 && innerState.mHeaderETag == null;
- }
-
- /**
- * Read some data from the HTTP response stream, handling I/O errors.
- *
- * @param data buffer to use to read data
- * @param entityStream stream for reading the HTTP response entity
- * @return the number of bytes actually read or -1 if the end of the stream
- * has been reached
- */
- private int readFromResponse(State state, InnerState innerState, byte[] data,
- InputStream entityStream) throws StopRequest {
- try {
- return entityStream.read(data);
- } catch (IOException ex) {
- logNetworkState();
- mInfo.mCurrentBytes = innerState.mBytesSoFar;
- mDB.updateDownload(mInfo);
- if (cannotResume(innerState)) {
- String message = "while reading response: " + ex.toString()
- + ", can't resume interrupted download with no ETag";
- throw new StopRequest(DownloaderService.STATUS_CANNOT_RESUME,
- message, ex);
- } else {
- throw new StopRequest(getFinalStatusForHttpError(state),
- "while reading response: " + ex.toString(), ex);
- }
- }
- }
-
- /**
- * Open a stream for the HTTP response entity, handling I/O errors.
- *
- * @return an InputStream to read the response entity
- */
- private InputStream openResponseEntity(State state, HttpResponse response)
- throws StopRequest {
- try {
- return response.getEntity().getContent();
- } catch (IOException ex) {
- logNetworkState();
- throw new StopRequest(getFinalStatusForHttpError(state),
- "while getting entity: " + ex.toString(), ex);
- }
- }
-
- private void logNetworkState() {
- if (Constants.LOGX) {
- Log.i(Constants.TAG,
- "Net "
- + (mService.getNetworkAvailabilityState(mDB) == DownloaderService.NETWORK_OK ? "Up"
- : "Down"));
- }
- }
-
- /**
- * Read HTTP response headers and take appropriate action, including setting
- * up the destination file and updating the database.
- */
- private void processResponseHeaders(State state, InnerState innerState, HttpResponse response)
- throws StopRequest {
- if (innerState.mContinuingDownload) {
- // ignore response headers on resume requests
- return;
- }
-
- readResponseHeaders(state, innerState, response);
-
- try {
- state.mFilename = mService.generateSaveFile(mInfo.mFileName, mInfo.mTotalBytes);
- } catch (DownloaderService.GenerateSaveFileError exc) {
- throw new StopRequest(exc.mStatus, exc.mMessage);
- }
- try {
- state.mStream = new FileOutputStream(state.mFilename);
- } catch (FileNotFoundException exc) {
- // make sure the directory exists
- File pathFile = new File(Helpers.getSaveFilePath(mService));
- try {
- if (pathFile.mkdirs()) {
- state.mStream = new FileOutputStream(state.mFilename);
- }
- } catch (Exception ex) {
- throw new StopRequest(DownloaderService.STATUS_FILE_ERROR,
- "while opening destination file: " + exc.toString(), exc);
- }
- }
- if (Constants.LOGV) {
- Log.v(Constants.TAG, "writing " + mInfo.mUri + " to " + state.mFilename);
- }
-
- updateDatabaseFromHeaders(state, innerState);
- // check connectivity again now that we know the total size
- checkConnectivity(state);
- }
-
- /**
- * Update necessary database fields based on values of HTTP response headers
- * that have been read.
- */
- private void updateDatabaseFromHeaders(State state, InnerState innerState) {
- mInfo.mETag = innerState.mHeaderETag;
- mDB.updateDownload(mInfo);
- }
-
- /**
- * Read headers from the HTTP response and store them into local state.
- */
- private void readResponseHeaders(State state, InnerState innerState, HttpResponse response)
- throws StopRequest {
- Header header = response.getFirstHeader("Content-Disposition");
- if (header != null) {
- innerState.mHeaderContentDisposition = header.getValue();
- }
- header = response.getFirstHeader("Content-Location");
- if (header != null) {
- innerState.mHeaderContentLocation = header.getValue();
- }
- header = response.getFirstHeader("ETag");
- if (header != null) {
- innerState.mHeaderETag = header.getValue();
- }
- String headerTransferEncoding = null;
- header = response.getFirstHeader("Transfer-Encoding");
- if (header != null) {
- headerTransferEncoding = header.getValue();
- }
- String headerContentType = null;
- header = response.getFirstHeader("Content-Type");
- if (header != null) {
- headerContentType = header.getValue();
- if (!headerContentType.equals("application/vnd.android.obb")) {
- throw new StopRequest(DownloaderService.STATUS_FILE_DELIVERED_INCORRECTLY,
- "file delivered with incorrect Mime type");
- }
- }
-
- if (headerTransferEncoding == null) {
- header = response.getFirstHeader("Content-Length");
- if (header != null) {
- innerState.mHeaderContentLength = header.getValue();
- // this is always set from Market
- long contentLength = Long.parseLong(innerState.mHeaderContentLength);
- if (contentLength != -1 && contentLength != mInfo.mTotalBytes) {
- // we're most likely on a bad wifi connection -- we should
- // probably
- // also look at the mime type --- but the size mismatch is
- // enough
- // to tell us that something is wrong here
- Log.e(Constants.TAG, "Incorrect file size delivered.");
- }
- }
- } else {
- // Ignore content-length with transfer-encoding - 2616 4.4 3
- if (Constants.LOGVV) {
- Log.v(Constants.TAG,
- "ignoring content-length because of xfer-encoding");
- }
- }
- if (Constants.LOGVV) {
- Log.v(Constants.TAG, "Content-Disposition: " +
- innerState.mHeaderContentDisposition);
- Log.v(Constants.TAG, "Content-Length: " + innerState.mHeaderContentLength);
- Log.v(Constants.TAG, "Content-Location: " + innerState.mHeaderContentLocation);
- Log.v(Constants.TAG, "ETag: " + innerState.mHeaderETag);
- Log.v(Constants.TAG, "Transfer-Encoding: " + headerTransferEncoding);
- }
-
- boolean noSizeInfo = innerState.mHeaderContentLength == null
- && (headerTransferEncoding == null
- || !headerTransferEncoding.equalsIgnoreCase("chunked"));
- if (noSizeInfo) {
- throw new StopRequest(DownloaderService.STATUS_HTTP_DATA_ERROR,
- "can't know size of download, giving up");
- }
- }
-
- /**
- * Check the HTTP response status and handle anything unusual (e.g. not
- * 200/206).
- */
- private void handleExceptionalStatus(State state, InnerState innerState, HttpResponse response)
- throws StopRequest, RetryDownload {
- int statusCode = response.getStatusLine().getStatusCode();
- if (statusCode == 503 && mInfo.mNumFailed < Constants.MAX_RETRIES) {
- handleServiceUnavailable(state, response);
- }
- if (statusCode == 301 || statusCode == 302 || statusCode == 303 || statusCode == 307) {
- handleRedirect(state, response, statusCode);
- }
-
- int expectedStatus = innerState.mContinuingDownload ? 206
- : DownloaderService.STATUS_SUCCESS;
- if (statusCode != expectedStatus) {
- handleOtherStatus(state, innerState, statusCode);
- } else {
- // no longer redirected
- state.mRedirectCount = 0;
- }
- }
-
- /**
- * Handle a status that we don't know how to deal with properly.
- */
- private void handleOtherStatus(State state, InnerState innerState, int statusCode)
- throws StopRequest {
- int finalStatus;
- if (DownloaderService.isStatusError(statusCode)) {
- finalStatus = statusCode;
- } else if (statusCode >= 300 && statusCode < 400) {
- finalStatus = DownloaderService.STATUS_UNHANDLED_REDIRECT;
- } else if (innerState.mContinuingDownload && statusCode == DownloaderService.STATUS_SUCCESS) {
- finalStatus = DownloaderService.STATUS_CANNOT_RESUME;
- } else {
- finalStatus = DownloaderService.STATUS_UNHANDLED_HTTP_CODE;
- }
- throw new StopRequest(finalStatus, "http error " + statusCode);
- }
-
- /**
- * Handle a 3xx redirect status.
- */
- private void handleRedirect(State state, HttpResponse response, int statusCode)
- throws StopRequest, RetryDownload {
- if (Constants.LOGVV) {
- Log.v(Constants.TAG, "got HTTP redirect " + statusCode);
- }
- if (state.mRedirectCount >= Constants.MAX_REDIRECTS) {
- throw new StopRequest(DownloaderService.STATUS_TOO_MANY_REDIRECTS, "too many redirects");
- }
- Header header = response.getFirstHeader("Location");
- if (header == null) {
- return;
- }
- if (Constants.LOGVV) {
- Log.v(Constants.TAG, "Location :" + header.getValue());
- }
-
- String newUri;
- try {
- newUri = new URI(mInfo.mUri).resolve(new URI(header.getValue())).toString();
- } catch (URISyntaxException ex) {
- if (Constants.LOGV) {
- Log.d(Constants.TAG, "Couldn't resolve redirect URI " + header.getValue()
- + " for " + mInfo.mUri);
- }
- throw new StopRequest(DownloaderService.STATUS_HTTP_DATA_ERROR,
- "Couldn't resolve redirect URI");
- }
- ++state.mRedirectCount;
- state.mRequestUri = newUri;
- if (statusCode == 301 || statusCode == 303) {
- // use the new URI for all future requests (should a retry/resume be
- // necessary)
- state.mNewUri = newUri;
- }
- throw new RetryDownload();
- }
-
- /**
- * Add headers for this download to the HTTP request to allow for resume.
- */
- private void addRequestHeaders(InnerState innerState, HttpGet request) {
- if (innerState.mContinuingDownload) {
- if (innerState.mHeaderETag != null) {
- request.addHeader("If-Match", innerState.mHeaderETag);
- }
- request.addHeader("Range", "bytes=" + innerState.mBytesSoFar + "-");
- }
- }
-
- /**
- * Handle a 503 Service Unavailable status by processing the Retry-After
- * header.
- */
- private void handleServiceUnavailable(State state, HttpResponse response) throws StopRequest {
- if (Constants.LOGVV) {
- Log.v(Constants.TAG, "got HTTP response code 503");
- }
- state.mCountRetry = true;
- Header header = response.getFirstHeader("Retry-After");
- if (header != null) {
- try {
- if (Constants.LOGVV) {
- Log.v(Constants.TAG, "Retry-After :" + header.getValue());
- }
- state.mRetryAfter = Integer.parseInt(header.getValue());
- if (state.mRetryAfter < 0) {
- state.mRetryAfter = 0;
- } else {
- if (state.mRetryAfter < Constants.MIN_RETRY_AFTER) {
- state.mRetryAfter = Constants.MIN_RETRY_AFTER;
- } else if (state.mRetryAfter > Constants.MAX_RETRY_AFTER) {
- state.mRetryAfter = Constants.MAX_RETRY_AFTER;
- }
- state.mRetryAfter += Helpers.sRandom.nextInt(Constants.MIN_RETRY_AFTER + 1);
- state.mRetryAfter *= 1000;
- }
- } catch (NumberFormatException ex) {
- // ignored - retryAfter stays 0 in this case.
- }
- }
- throw new StopRequest(DownloaderService.STATUS_WAITING_TO_RETRY,
- "got 503 Service Unavailable, will retry later");
- }
-
- /**
- * Send the request to the server, handling any I/O exceptions.
- */
- private HttpResponse sendRequest(State state, AndroidHttpClient client, HttpGet request)
- throws StopRequest {
- try {
- return client.execute(request);
- } catch (IllegalArgumentException ex) {
- throw new StopRequest(DownloaderService.STATUS_HTTP_DATA_ERROR,
- "while trying to execute request: " + ex.toString(), ex);
- } catch (IOException ex) {
- logNetworkState();
- throw new StopRequest(getFinalStatusForHttpError(state),
- "while trying to execute request: " + ex.toString(), ex);
- }
- }
-
- private int getFinalStatusForHttpError(State state) {
- if (mService.getNetworkAvailabilityState(mDB) != DownloaderService.NETWORK_OK) {
- return DownloaderService.STATUS_WAITING_FOR_NETWORK;
- } else if (mInfo.mNumFailed < Constants.MAX_RETRIES) {
- state.mCountRetry = true;
- return DownloaderService.STATUS_WAITING_TO_RETRY;
- } else {
- Log.w(Constants.TAG, "reached max retries for " + mInfo.mNumFailed);
- return DownloaderService.STATUS_HTTP_DATA_ERROR;
- }
- }
-
- /**
- * Prepare the destination file to receive data. If the file already exists,
- * we'll set up appropriately for resumption.
- */
- private void setupDestinationFile(State state, InnerState innerState)
- throws StopRequest {
- if (state.mFilename != null) { // only true if we've already run a
- // thread for this download
- if (!Helpers.isFilenameValid(state.mFilename)) {
- // this should never happen
- throw new StopRequest(DownloaderService.STATUS_FILE_ERROR,
- "found invalid internal destination filename");
- }
- // We're resuming a download that got interrupted
- File f = new File(state.mFilename);
- if (f.exists()) {
- long fileLength = f.length();
- if (fileLength == 0) {
- // The download hadn't actually started, we can restart from
- // scratch
- f.delete();
- state.mFilename = null;
- } else if (mInfo.mETag == null) {
- // This should've been caught upon failure
- f.delete();
- throw new StopRequest(DownloaderService.STATUS_CANNOT_RESUME,
- "Trying to resume a download that can't be resumed");
- } else {
- // All right, we'll be able to resume this download
- try {
- state.mStream = new FileOutputStream(state.mFilename, true);
- } catch (FileNotFoundException exc) {
- throw new StopRequest(DownloaderService.STATUS_FILE_ERROR,
- "while opening destination for resuming: " + exc.toString(), exc);
- }
- innerState.mBytesSoFar = (int) fileLength;
- if (mInfo.mTotalBytes != -1) {
- innerState.mHeaderContentLength = Long.toString(mInfo.mTotalBytes);
- }
- innerState.mHeaderETag = mInfo.mETag;
- innerState.mContinuingDownload = true;
- }
- }
- }
-
- if (state.mStream != null) {
- closeDestination(state);
- }
- }
-
- /**
- * Stores information about the completed download, and notifies the
- * initiating application.
- */
- private void notifyDownloadCompleted(
- int status, boolean countRetry, int retryAfter, int redirectCount, boolean gotData,
- String filename) {
- updateDownloadDatabase(
- status, countRetry, retryAfter, redirectCount, gotData, filename);
- if (DownloaderService.isStatusCompleted(status)) {
- // TBD: send status update?
- }
- }
-
- private void updateDownloadDatabase(
- int status, boolean countRetry, int retryAfter, int redirectCount, boolean gotData,
- String filename) {
- mInfo.mStatus = status;
- mInfo.mRetryAfter = retryAfter;
- mInfo.mRedirectCount = redirectCount;
- mInfo.mLastMod = System.currentTimeMillis();
- if (!countRetry) {
- mInfo.mNumFailed = 0;
- } else if (gotData) {
- mInfo.mNumFailed = 1;
- } else {
- mInfo.mNumFailed++;
- }
- mDB.updateDownload(mInfo);
- }
-
-}
diff --git a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/DownloaderService.java b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/DownloaderService.java
deleted file mode 100644
index 627bf3eedd..0000000000
--- a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/DownloaderService.java
+++ /dev/null
@@ -1,1341 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.vending.expansion.downloader.impl;
-
-import com.google.android.vending.expansion.downloader.Constants;
-import com.google.android.vending.expansion.downloader.DownloadProgressInfo;
-import com.google.android.vending.expansion.downloader.DownloaderServiceMarshaller;
-import com.google.android.vending.expansion.downloader.Helpers;
-import com.google.android.vending.expansion.downloader.IDownloaderClient;
-import com.google.android.vending.expansion.downloader.IDownloaderService;
-import com.google.android.vending.expansion.downloader.IStub;
-import com.google.android.vending.licensing.AESObfuscator;
-import com.google.android.vending.licensing.APKExpansionPolicy;
-import com.google.android.vending.licensing.LicenseChecker;
-import com.google.android.vending.licensing.LicenseCheckerCallback;
-import com.google.android.vending.licensing.Policy;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.app.Service;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
-import android.net.wifi.WifiManager;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Messenger;
-import android.os.SystemClock;
-import android.provider.Settings.Secure;
-import android.telephony.TelephonyManager;
-import android.util.Log;
-
-import java.io.File;
-
-/**
- * Performs the background downloads requested by applications that use the
- * Downloads provider. This service does not run as a foreground task, so
- * Android may kill it off at will, but it will try to restart itself if it can.
- * Note that Android by default will kill off any process that has an open file
- * handle on the shared (SD Card) partition if the partition is unmounted.
- */
-public abstract class DownloaderService extends CustomIntentService implements IDownloaderService {
-
- public DownloaderService() {
- super("LVLDownloadService");
- }
-
- private static final String LOG_TAG = "LVLDL";
-
- // the following NETWORK_* constants are used to indicates specific reasons
- // for disallowing a
- // download from using a network, since specific causes can require special
- // handling
-
- /**
- * The network is usable for the given download.
- */
- public static final int NETWORK_OK = 1;
-
- /**
- * There is no network connectivity.
- */
- public static final int NETWORK_NO_CONNECTION = 2;
-
- /**
- * The download exceeds the maximum size for this network.
- */
- public static final int NETWORK_UNUSABLE_DUE_TO_SIZE = 3;
-
- /**
- * The download exceeds the recommended maximum size for this network, the
- * user must confirm for this download to proceed without WiFi.
- */
- public static final int NETWORK_RECOMMENDED_UNUSABLE_DUE_TO_SIZE = 4;
-
- /**
- * The current connection is roaming, and the download can't proceed over a
- * roaming connection.
- */
- public static final int NETWORK_CANNOT_USE_ROAMING = 5;
-
- /**
- * The app requesting the download specific that it can't use the current
- * network connection.
- */
- public static final int NETWORK_TYPE_DISALLOWED_BY_REQUESTOR = 6;
-
- /**
- * For intents used to notify the user that a download exceeds a size
- * threshold, if this extra is true, WiFi is required for this download
- * size; otherwise, it is only recommended.
- */
- public static final String EXTRA_IS_WIFI_REQUIRED = "isWifiRequired";
- public static final String EXTRA_FILE_NAME = "downloadId";
-
- /**
- * Used with DOWNLOAD_STATUS
- */
- public static final String EXTRA_STATUS_STATE = "ESS";
- public static final String EXTRA_STATUS_TOTAL_SIZE = "ETS";
- public static final String EXTRA_STATUS_CURRENT_FILE_SIZE = "CFS";
- public static final String EXTRA_STATUS_TOTAL_PROGRESS = "TFP";
- public static final String EXTRA_STATUS_CURRENT_PROGRESS = "CFP";
-
- public static final String ACTION_DOWNLOADS_CHANGED = "downloadsChanged";
-
- /**
- * Broadcast intent action sent by the download manager when a download
- * completes.
- */
- public final static String ACTION_DOWNLOAD_COMPLETE = "lvldownloader.intent.action.DOWNLOAD_COMPLETE";
-
- /**
- * Broadcast intent action sent by the download manager when download status
- * changes.
- */
- public final static String ACTION_DOWNLOAD_STATUS = "lvldownloader.intent.action.DOWNLOAD_STATUS";
-
- /*
- * Lists the states that the download manager can set on a download to
- * notify applications of the download progress. The codes follow the HTTP
- * families:<br> 1xx: informational<br> 2xx: success<br> 3xx: redirects (not
- * used by the download manager)<br> 4xx: client errors<br> 5xx: server
- * errors
- */
-
- /**
- * Returns whether the status is informational (i.e. 1xx).
- */
- public static boolean isStatusInformational(int status) {
- return (status >= 100 && status < 200);
- }
-
- /**
- * Returns whether the status is a success (i.e. 2xx).
- */
- public static boolean isStatusSuccess(int status) {
- return (status >= 200 && status < 300);
- }
-
- /**
- * Returns whether the status is an error (i.e. 4xx or 5xx).
- */
- public static boolean isStatusError(int status) {
- return (status >= 400 && status < 600);
- }
-
- /**
- * Returns whether the status is a client error (i.e. 4xx).
- */
- public static boolean isStatusClientError(int status) {
- return (status >= 400 && status < 500);
- }
-
- /**
- * Returns whether the status is a server error (i.e. 5xx).
- */
- public static boolean isStatusServerError(int status) {
- return (status >= 500 && status < 600);
- }
-
- /**
- * Returns whether the download has completed (either with success or
- * error).
- */
- public static boolean isStatusCompleted(int status) {
- return (status >= 200 && status < 300)
- || (status >= 400 && status < 600);
- }
-
- /**
- * This download hasn't stated yet
- */
- public static final int STATUS_PENDING = 190;
-
- /**
- * This download has started
- */
- public static final int STATUS_RUNNING = 192;
-
- /**
- * This download has been paused by the owning app.
- */
- public static final int STATUS_PAUSED_BY_APP = 193;
-
- /**
- * This download encountered some network error and is waiting before
- * retrying the request.
- */
- public static final int STATUS_WAITING_TO_RETRY = 194;
-
- /**
- * This download is waiting for network connectivity to proceed.
- */
- public static final int STATUS_WAITING_FOR_NETWORK = 195;
-
- /**
- * This download is waiting for a Wi-Fi connection to proceed or for
- * permission to download over cellular.
- */
- public static final int STATUS_QUEUED_FOR_WIFI_OR_CELLULAR_PERMISSION = 196;
-
- /**
- * This download is waiting for a Wi-Fi connection to proceed.
- */
- public static final int STATUS_QUEUED_FOR_WIFI = 197;
-
- /**
- * This download has successfully completed. Warning: there might be other
- * status values that indicate success in the future. Use isSucccess() to
- * capture the entire category.
- *
- * @hide
- */
- public static final int STATUS_SUCCESS = 200;
-
- /**
- * The requested URL is no longer available
- */
- public static final int STATUS_FORBIDDEN = 403;
-
- /**
- * The file was delivered incorrectly
- */
- public static final int STATUS_FILE_DELIVERED_INCORRECTLY = 487;
-
- /**
- * The requested destination file already exists.
- */
- public static final int STATUS_FILE_ALREADY_EXISTS_ERROR = 488;
-
- /**
- * Some possibly transient error occurred, but we can't resume the download.
- */
- public static final int STATUS_CANNOT_RESUME = 489;
-
- /**
- * This download was canceled
- *
- * @hide
- */
- public static final int STATUS_CANCELED = 490;
-
- /**
- * This download has completed with an error. Warning: there will be other
- * status values that indicate errors in the future. Use isStatusError() to
- * capture the entire category.
- */
- public static final int STATUS_UNKNOWN_ERROR = 491;
-
- /**
- * This download couldn't be completed because of a storage issue.
- * Typically, that's because the filesystem is missing or full. Use the more
- * specific {@link #STATUS_INSUFFICIENT_SPACE_ERROR} and
- * {@link #STATUS_DEVICE_NOT_FOUND_ERROR} when appropriate.
- *
- * @hide
- */
- public static final int STATUS_FILE_ERROR = 492;
-
- /**
- * This download couldn't be completed because of an HTTP redirect response
- * that the download manager couldn't handle.
- *
- * @hide
- */
- public static final int STATUS_UNHANDLED_REDIRECT = 493;
-
- /**
- * This download couldn't be completed because of an unspecified unhandled
- * HTTP code.
- *
- * @hide
- */
- public static final int STATUS_UNHANDLED_HTTP_CODE = 494;
-
- /**
- * This download couldn't be completed because of an error receiving or
- * processing data at the HTTP level.
- *
- * @hide
- */
- public static final int STATUS_HTTP_DATA_ERROR = 495;
-
- /**
- * This download couldn't be completed because of an HttpException while
- * setting up the request.
- *
- * @hide
- */
- public static final int STATUS_HTTP_EXCEPTION = 496;
-
- /**
- * This download couldn't be completed because there were too many
- * redirects.
- *
- * @hide
- */
- public static final int STATUS_TOO_MANY_REDIRECTS = 497;
-
- /**
- * This download couldn't be completed due to insufficient storage space.
- * Typically, this is because the SD card is full.
- *
- * @hide
- */
- public static final int STATUS_INSUFFICIENT_SPACE_ERROR = 498;
-
- /**
- * This download couldn't be completed because no external storage device
- * was found. Typically, this is because the SD card is not mounted.
- *
- * @hide
- */
- public static final int STATUS_DEVICE_NOT_FOUND_ERROR = 499;
-
- /**
- * This download is allowed to run.
- *
- * @hide
- */
- public static final int CONTROL_RUN = 0;
-
- /**
- * This download must pause at the first opportunity.
- *
- * @hide
- */
- public static final int CONTROL_PAUSED = 1;
-
- /**
- * This download is visible but only shows in the notifications while it's
- * in progress.
- *
- * @hide
- */
- public static final int VISIBILITY_VISIBLE = 0;
-
- /**
- * This download is visible and shows in the notifications while in progress
- * and after completion.
- *
- * @hide
- */
- public static final int VISIBILITY_VISIBLE_NOTIFY_COMPLETED = 1;
-
- /**
- * This download doesn't show in the UI or in the notifications.
- *
- * @hide
- */
- public static final int VISIBILITY_HIDDEN = 2;
-
- /**
- * Bit flag for {@link #setAllowedNetworkTypes} corresponding to
- * {@link ConnectivityManager#TYPE_MOBILE}.
- */
- public static final int NETWORK_MOBILE = 1 << 0;
-
- /**
- * Bit flag for {@link #setAllowedNetworkTypes} corresponding to
- * {@link ConnectivityManager#TYPE_WIFI}.
- */
- public static final int NETWORK_WIFI = 1 << 1;
-
- private final static String TEMP_EXT = ".tmp";
-
- /**
- * Service thread status
- */
- private static boolean sIsRunning;
-
- @Override
- public IBinder onBind(Intent paramIntent) {
- Log.d(Constants.TAG, "Service Bound");
- return this.mServiceMessenger.getBinder();
- }
-
- /**
- * Network state.
- */
- private boolean mIsConnected;
- private boolean mIsFailover;
- private boolean mIsCellularConnection;
- private boolean mIsRoaming;
- private boolean mIsAtLeast3G;
- private boolean mIsAtLeast4G;
- private boolean mStateChanged;
-
- /**
- * Download state
- */
- private int mControl;
- private int mStatus;
-
- public boolean isWiFi() {
- return mIsConnected && !mIsCellularConnection;
- }
-
- /**
- * Bindings to important services
- */
- private ConnectivityManager mConnectivityManager;
- private WifiManager mWifiManager;
-
- /**
- * Package we are downloading for (defaults to package of application)
- */
- private PackageInfo mPackageInfo;
-
- /**
- * Byte counts
- */
- long mBytesSoFar;
- long mTotalLength;
- int mFileCount;
-
- /**
- * Used for calculating time remaining and speed
- */
- long mBytesAtSample;
- long mMillisecondsAtSample;
- float mAverageDownloadSpeed;
-
- /**
- * Our binding to the network state broadcasts
- */
- private BroadcastReceiver mConnReceiver;
- final private IStub mServiceStub = DownloaderServiceMarshaller.CreateStub(this);
- final private Messenger mServiceMessenger = mServiceStub.getMessenger();
- private Messenger mClientMessenger;
- private DownloadNotification mNotification;
- private PendingIntent mPendingIntent;
- private PendingIntent mAlarmIntent;
-
- /**
- * Updates the network type based upon the type and subtype returned from
- * the connectivity manager. Subtype is only used for cellular signals.
- *
- * @param type
- * @param subType
- */
- private void updateNetworkType(int type, int subType) {
- switch (type) {
- case ConnectivityManager.TYPE_WIFI:
- case ConnectivityManager.TYPE_ETHERNET:
- case ConnectivityManager.TYPE_BLUETOOTH:
- mIsCellularConnection = false;
- mIsAtLeast3G = false;
- mIsAtLeast4G = false;
- break;
- case ConnectivityManager.TYPE_WIMAX:
- mIsCellularConnection = true;
- mIsAtLeast3G = true;
- mIsAtLeast4G = true;
- break;
- case ConnectivityManager.TYPE_MOBILE:
- mIsCellularConnection = true;
- switch (subType) {
- case TelephonyManager.NETWORK_TYPE_1xRTT:
- case TelephonyManager.NETWORK_TYPE_CDMA:
- case TelephonyManager.NETWORK_TYPE_EDGE:
- case TelephonyManager.NETWORK_TYPE_GPRS:
- case TelephonyManager.NETWORK_TYPE_IDEN:
- mIsAtLeast3G = false;
- mIsAtLeast4G = false;
- break;
- case TelephonyManager.NETWORK_TYPE_HSDPA:
- case TelephonyManager.NETWORK_TYPE_HSUPA:
- case TelephonyManager.NETWORK_TYPE_HSPA:
- case TelephonyManager.NETWORK_TYPE_EVDO_0:
- case TelephonyManager.NETWORK_TYPE_EVDO_A:
- case TelephonyManager.NETWORK_TYPE_UMTS:
- mIsAtLeast3G = true;
- mIsAtLeast4G = false;
- break;
- case TelephonyManager.NETWORK_TYPE_LTE: // 4G
- case TelephonyManager.NETWORK_TYPE_EHRPD: // 3G ++ interop
- // with 4G
- case TelephonyManager.NETWORK_TYPE_HSPAP: // 3G ++ but
- // marketed as
- // 4G
- mIsAtLeast3G = true;
- mIsAtLeast4G = true;
- break;
- default:
- mIsCellularConnection = false;
- mIsAtLeast3G = false;
- mIsAtLeast4G = false;
- }
- }
- }
-
- private void updateNetworkState(NetworkInfo info) {
- boolean isConnected = mIsConnected;
- boolean isFailover = mIsFailover;
- boolean isCellularConnection = mIsCellularConnection;
- boolean isRoaming = mIsRoaming;
- boolean isAtLeast3G = mIsAtLeast3G;
- if (null != info) {
- mIsRoaming = info.isRoaming();
- mIsFailover = info.isFailover();
- mIsConnected = info.isConnected();
- updateNetworkType(info.getType(), info.getSubtype());
- } else {
- mIsRoaming = false;
- mIsFailover = false;
- mIsConnected = false;
- updateNetworkType(-1, -1);
- }
- mStateChanged = (mStateChanged || isConnected != mIsConnected
- || isFailover != mIsFailover
- || isCellularConnection != mIsCellularConnection
- || isRoaming != mIsRoaming || isAtLeast3G != mIsAtLeast3G);
- if (Constants.LOGVV) {
- if (mStateChanged) {
- Log.v(LOG_TAG, "Network state changed: ");
- Log.v(LOG_TAG, "Starting State: " +
- (isConnected ? "Connected " : "Not Connected ") +
- (isCellularConnection ? "Cellular " : "WiFi ") +
- (isRoaming ? "Roaming " : "Local ") +
- (isAtLeast3G ? "3G+ " : "<3G "));
- Log.v(LOG_TAG, "Ending State: " +
- (mIsConnected ? "Connected " : "Not Connected ") +
- (mIsCellularConnection ? "Cellular " : "WiFi ") +
- (mIsRoaming ? "Roaming " : "Local ") +
- (mIsAtLeast3G ? "3G+ " : "<3G "));
-
- if (isServiceRunning()) {
- if (mIsRoaming) {
- mStatus = STATUS_WAITING_FOR_NETWORK;
- mControl = CONTROL_PAUSED;
- } else if (mIsCellularConnection) {
- DownloadsDB db = DownloadsDB.getDB(this);
- int flags = db.getFlags();
- if (0 == (flags & FLAGS_DOWNLOAD_OVER_CELLULAR)) {
- mStatus = STATUS_QUEUED_FOR_WIFI;
- mControl = CONTROL_PAUSED;
- }
- }
- }
-
- }
- }
- }
-
- /**
- * Polls the network state, setting the flags appropriately.
- */
- void pollNetworkState() {
- if (null == mConnectivityManager) {
- mConnectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
- }
- if (null == mWifiManager) {
- mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
- }
- if (mConnectivityManager == null) {
- Log.w(Constants.TAG,
- "couldn't get connectivity manager to poll network state");
- } else {
- NetworkInfo activeInfo = mConnectivityManager
- .getActiveNetworkInfo();
- updateNetworkState(activeInfo);
- }
- }
-
- public static final int NO_DOWNLOAD_REQUIRED = 0;
- public static final int LVL_CHECK_REQUIRED = 1;
- public static final int DOWNLOAD_REQUIRED = 2;
-
- public static final String EXTRA_PACKAGE_NAME = "EPN";
- public static final String EXTRA_PENDING_INTENT = "EPI";
- public static final String EXTRA_MESSAGE_HANDLER = "EMH";
-
- /**
- * Returns true if the LVL check is required
- *
- * @param db a downloads DB synchronized with the latest state
- * @param pi the package info for the project
- * @return returns true if the filenames need to be returned
- */
- private static boolean isLVLCheckRequired(DownloadsDB db, PackageInfo pi) {
- // we need to update the LVL check and get a successful status to
- // proceed
- if (db.mVersionCode != pi.versionCode) {
- return true;
- }
- return false;
- }
-
- /**
- * Careful! Only use this internally.
- *
- * @return whether we think the service is running
- */
- private static synchronized boolean isServiceRunning() {
- return sIsRunning;
- }
-
- private static synchronized void setServiceRunning(boolean isRunning) {
- sIsRunning = isRunning;
- }
-
- public static int startDownloadServiceIfRequired(Context context,
- Intent intent, Class<?> serviceClass) throws NameNotFoundException {
- final PendingIntent pendingIntent = (PendingIntent) intent
- .getParcelableExtra(EXTRA_PENDING_INTENT);
- return startDownloadServiceIfRequired(context, pendingIntent,
- serviceClass);
- }
-
- public static int startDownloadServiceIfRequired(Context context,
- PendingIntent pendingIntent, Class<?> serviceClass)
- throws NameNotFoundException
- {
- String packageName = context.getPackageName();
- String className = serviceClass.getName();
-
- return startDownloadServiceIfRequired(context, pendingIntent,
- packageName, className);
- }
-
- /**
- * Starts the download if necessary. This function starts a flow that does `
- * many things. 1) Checks to see if the APK version has been checked and the
- * metadata database updated 2) If the APK version does not match, checks
- * the new LVL status to see if a new download is required 3) If the APK
- * version does match, then checks to see if the download(s) have been
- * completed 4) If the downloads have been completed, returns
- * NO_DOWNLOAD_REQUIRED The idea is that this can be called during the
- * startup of an application to quickly ascertain if the application needs
- * to wait to hear about any updated APK expansion files. Note that this
- * does mean that the application MUST be run for the first time with a
- * network connection, even if Market delivers all of the files.
- *
- * @param context
- * @param thisIntent
- * @return true if the app should wait for more guidance from the
- * downloader, false if the app can continue
- * @throws NameNotFoundException
- */
- public static int startDownloadServiceIfRequired(Context context,
- PendingIntent pendingIntent, String classPackage, String className)
- throws NameNotFoundException {
- // first: do we need to do an LVL update?
- // we begin by getting our APK version from the package manager
- final PackageInfo pi = context.getPackageManager().getPackageInfo(
- context.getPackageName(), 0);
-
- int status = NO_DOWNLOAD_REQUIRED;
-
- // the database automatically reads the metadata for version code
- // and download status when the instance is created
- DownloadsDB db = DownloadsDB.getDB(context);
-
- // we need to update the LVL check and get a successful status to
- // proceed
- if (isLVLCheckRequired(db, pi)) {
- status = LVL_CHECK_REQUIRED;
- }
- // we don't have to update LVL. do we still have a download to start?
- if (db.mStatus == 0) {
- DownloadInfo[] infos = db.getDownloads();
- if (null != infos) {
- for (DownloadInfo info : infos) {
- if (!Helpers.doesFileExist(context, info.mFileName, info.mTotalBytes, true)) {
- status = DOWNLOAD_REQUIRED;
- db.updateStatus(-1);
- break;
- }
- }
- }
- } else {
- status = DOWNLOAD_REQUIRED;
- }
- switch (status) {
- case DOWNLOAD_REQUIRED:
- case LVL_CHECK_REQUIRED:
- Intent fileIntent = new Intent();
- fileIntent.setClassName(classPackage, className);
- fileIntent.putExtra(EXTRA_PENDING_INTENT, pendingIntent);
- context.startService(fileIntent);
- break;
- }
- return status;
- }
-
- @Override
- public void requestAbortDownload() {
- mControl = CONTROL_PAUSED;
- mStatus = STATUS_CANCELED;
- }
-
- @Override
- public void requestPauseDownload() {
- mControl = CONTROL_PAUSED;
- mStatus = STATUS_PAUSED_BY_APP;
- }
-
- @Override
- public void setDownloadFlags(int flags) {
- DownloadsDB.getDB(this).updateFlags(flags);
- }
-
- @Override
- public void requestContinueDownload() {
- if (mControl == CONTROL_PAUSED) {
- mControl = CONTROL_RUN;
- }
- Intent fileIntent = new Intent(this, this.getClass());
- fileIntent.putExtra(EXTRA_PENDING_INTENT, mPendingIntent);
- this.startService(fileIntent);
- }
-
- public abstract String getPublicKey();
-
- public abstract byte[] getSALT();
-
- public abstract String getAlarmReceiverClassName();
-
- private class LVLRunnable implements Runnable {
- LVLRunnable(Context context, PendingIntent intent) {
- mContext = context;
- mPendingIntent = intent;
- }
-
- final Context mContext;
-
- @Override
- public void run() {
- setServiceRunning(true);
- mNotification.onDownloadStateChanged(IDownloaderClient.STATE_FETCHING_URL);
- String deviceId = Secure.getString(mContext.getContentResolver(),
- Secure.ANDROID_ID);
-
- final APKExpansionPolicy aep = new APKExpansionPolicy(mContext,
- new AESObfuscator(getSALT(), mContext.getPackageName(), deviceId));
-
- // reset our policy back to the start of the world to force a
- // re-check
- aep.resetPolicy();
-
- // let's try and get the OBB file from LVL first
- // Construct the LicenseChecker with a Policy.
- final LicenseChecker checker = new LicenseChecker(mContext, aep,
- getPublicKey() // Your public licensing key.
- );
- checker.checkAccess(new LicenseCheckerCallback() {
-
- @Override
- public void allow(int reason) {
- try {
- int count = aep.getExpansionURLCount();
- DownloadsDB db = DownloadsDB.getDB(mContext);
- int status = 0;
- if (count != 0) {
- for (int i = 0; i < count; i++) {
- String currentFileName = aep
- .getExpansionFileName(i);
- if (null != currentFileName) {
- DownloadInfo di = new DownloadInfo(i,
- currentFileName, mContext.getPackageName());
-
- long fileSize = aep.getExpansionFileSize(i);
- if (handleFileUpdated(db, i, currentFileName,
- fileSize)) {
- status |= -1;
- di.resetDownload();
- di.mUri = aep.getExpansionURL(i);
- di.mTotalBytes = fileSize;
- di.mStatus = status;
- db.updateDownload(di);
- } else {
- // we need to read the download
- // information
- // from
- // the database
- DownloadInfo dbdi = db
- .getDownloadInfoByFileName(di.mFileName);
- if (null == dbdi) {
- // the file exists already and is
- // the
- // correct size
- // was delivered by Market or
- // through
- // another mechanism
- Log.d(LOG_TAG, "file " + di.mFileName
- + " found. Not downloading.");
- di.mStatus = STATUS_SUCCESS;
- di.mTotalBytes = fileSize;
- di.mCurrentBytes = fileSize;
- di.mUri = aep.getExpansionURL(i);
- db.updateDownload(di);
- } else if (dbdi.mStatus != STATUS_SUCCESS) {
- // we just update the URL
- dbdi.mUri = aep.getExpansionURL(i);
- db.updateDownload(dbdi);
- status |= -1;
- }
- }
- }
- }
- }
- // first: do we need to do an LVL update?
- // we begin by getting our APK version from the package
- // manager
- PackageInfo pi;
- try {
- pi = mContext.getPackageManager().getPackageInfo(
- mContext.getPackageName(), 0);
- db.updateMetadata(pi.versionCode, status);
- Class<?> serviceClass = DownloaderService.this.getClass();
- switch (startDownloadServiceIfRequired(mContext, mPendingIntent,
- serviceClass)) {
- case NO_DOWNLOAD_REQUIRED:
- mNotification
- .onDownloadStateChanged(IDownloaderClient.STATE_COMPLETED);
- break;
- case LVL_CHECK_REQUIRED:
- // DANGER WILL ROBINSON!
- Log.e(LOG_TAG, "In LVL checking loop!");
- mNotification
- .onDownloadStateChanged(IDownloaderClient.STATE_FAILED_UNLICENSED);
- throw new RuntimeException(
- "Error with LVL checking and database integrity");
- case DOWNLOAD_REQUIRED:
- // do nothing. the download will notify the
- // application
- // when things are done
- break;
- }
- } catch (NameNotFoundException e1) {
- e1.printStackTrace();
- throw new RuntimeException(
- "Error with getting information from package name");
- }
- } finally {
- setServiceRunning(false);
- }
- }
-
- @Override
- public void dontAllow(int reason) {
- try
- {
- switch (reason) {
- case Policy.NOT_LICENSED:
- mNotification
- .onDownloadStateChanged(IDownloaderClient.STATE_FAILED_UNLICENSED);
- break;
- case Policy.RETRY:
- mNotification
- .onDownloadStateChanged(IDownloaderClient.STATE_FAILED_FETCHING_URL);
- break;
- }
- } finally {
- setServiceRunning(false);
- }
-
- }
-
- @Override
- public void applicationError(int errorCode) {
- try {
- mNotification
- .onDownloadStateChanged(IDownloaderClient.STATE_FAILED_FETCHING_URL);
- } finally {
- setServiceRunning(false);
- }
- }
-
- });
-
- }
-
- };
-
- /**
- * Updates the LVL information from the server.
- *
- * @param context
- */
- public void updateLVL(final Context context) {
- Context c = context.getApplicationContext();
- Handler h = new Handler(c.getMainLooper());
- h.post(new LVLRunnable(c, mPendingIntent));
- }
-
- /**
- * The APK has been updated and a filename has been sent down from the
- * Market call. If the file has the same name as the previous file, we do
- * nothing as the file is guaranteed to be the same. If the file does not
- * have the same name, we download it if it hasn't already been delivered by
- * Market.
- *
- * @param index the index of the file from market (0 = main, 1 = patch)
- * @param filename the name of the new file
- * @param fileSize the size of the new file
- * @return
- */
- public boolean handleFileUpdated(DownloadsDB db, int index,
- String filename, long fileSize) {
- DownloadInfo di = db.getDownloadInfoByFileName(filename);
- if (null != di) {
- String oldFile = di.mFileName;
- // cleanup
- if (null != oldFile) {
- if (filename.equals(oldFile)) {
- return false;
- }
-
- // remove partially downloaded file if it is there
- String deleteFile = Helpers.generateSaveFileName(this, oldFile);
- File f = new File(deleteFile);
- if (f.exists())
- f.delete();
- }
- }
- return !Helpers.doesFileExist(this, filename, fileSize, true);
- }
-
- private void scheduleAlarm(long wakeUp) {
- AlarmManager alarms = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
- if (alarms == null) {
- Log.e(Constants.TAG, "couldn't get alarm manager");
- return;
- }
-
- if (Constants.LOGV) {
- Log.v(Constants.TAG, "scheduling retry in " + wakeUp + "ms");
- }
-
- String className = getAlarmReceiverClassName();
- Intent intent = new Intent(Constants.ACTION_RETRY);
- intent.putExtra(EXTRA_PENDING_INTENT, mPendingIntent);
- intent.setClassName(this.getPackageName(),
- className);
- mAlarmIntent = PendingIntent.getBroadcast(this, 0, intent,
- PendingIntent.FLAG_ONE_SHOT);
- alarms.set(
- AlarmManager.RTC_WAKEUP,
- System.currentTimeMillis() + wakeUp, mAlarmIntent
- );
- }
-
- private void cancelAlarms() {
- if (null != mAlarmIntent) {
- AlarmManager alarms = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
- if (alarms == null) {
- Log.e(Constants.TAG, "couldn't get alarm manager");
- return;
- }
- alarms.cancel(mAlarmIntent);
- mAlarmIntent = null;
- }
- }
-
- /**
- * We use this to track network state, such as when WiFi, Cellular, etc. is
- * enabled when downloads are paused or in progress.
- */
- private class InnerBroadcastReceiver extends BroadcastReceiver {
- final Service mService;
-
- InnerBroadcastReceiver(Service service) {
- mService = service;
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- pollNetworkState();
- if (mStateChanged
- && !isServiceRunning()) {
- Log.d(Constants.TAG, "InnerBroadcastReceiver Called");
- Intent fileIntent = new Intent(context, mService.getClass());
- fileIntent.putExtra(EXTRA_PENDING_INTENT, mPendingIntent);
- // send a new intent to the service
- context.startService(fileIntent);
- }
- }
- };
-
- /**
- * This is the main thread for the Downloader. This thread is responsible
- * for queuing up downloads and other goodness.
- */
- @Override
- protected void onHandleIntent(Intent intent) {
- setServiceRunning(true);
- try {
- // the database automatically reads the metadata for version code
- // and download status when the instance is created
- DownloadsDB db = DownloadsDB.getDB(this);
- final PendingIntent pendingIntent = (PendingIntent) intent
- .getParcelableExtra(EXTRA_PENDING_INTENT);
-
- if (null != pendingIntent)
- {
- mNotification.setClientIntent(pendingIntent);
- mPendingIntent = pendingIntent;
- } else if (null != mPendingIntent) {
- mNotification.setClientIntent(mPendingIntent);
- } else {
- Log.e(LOG_TAG, "Downloader started in bad state without notification intent.");
- return;
- }
-
- // when the LVL check completes, a successful response will update
- // the service
- if (isLVLCheckRequired(db, mPackageInfo)) {
- updateLVL(this);
- return;
- }
-
- // get each download
- DownloadInfo[] infos = db.getDownloads();
- mBytesSoFar = 0;
- mTotalLength = 0;
- mFileCount = infos.length;
- for (DownloadInfo info : infos) {
- // We do an (simple) integrity check on each file, just to make
- // sure
- if (info.mStatus == STATUS_SUCCESS) {
- // verify that the file matches the state
- if (!Helpers.doesFileExist(this, info.mFileName, info.mTotalBytes, true)) {
- info.mStatus = 0;
- info.mCurrentBytes = 0;
- }
- }
- // get aggregate data
- mTotalLength += info.mTotalBytes;
- mBytesSoFar += info.mCurrentBytes;
- }
-
- // loop through all downloads and fetch them
- pollNetworkState();
- if (null == mConnReceiver) {
-
- /**
- * We use this to track network state, such as when WiFi,
- * Cellular, etc. is enabled when downloads are paused or in
- * progress.
- */
- mConnReceiver = new InnerBroadcastReceiver(this);
- IntentFilter intentFilter = new IntentFilter(
- ConnectivityManager.CONNECTIVITY_ACTION);
- intentFilter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
- registerReceiver(mConnReceiver, intentFilter);
- }
-
- for (DownloadInfo info : infos) {
- long startingCount = info.mCurrentBytes;
-
- if (info.mStatus != STATUS_SUCCESS) {
- DownloadThread dt = new DownloadThread(info, this, mNotification);
- cancelAlarms();
- scheduleAlarm(Constants.ACTIVE_THREAD_WATCHDOG);
- dt.run();
- cancelAlarms();
- }
- db.updateFromDb(info);
- boolean setWakeWatchdog = false;
- int notifyStatus;
- switch (info.mStatus) {
- case STATUS_FORBIDDEN:
- // the URL is out of date
- updateLVL(this);
- return;
- case STATUS_SUCCESS:
- mBytesSoFar += info.mCurrentBytes - startingCount;
- db.updateMetadata(mPackageInfo.versionCode, 0);
- continue;
- case STATUS_FILE_DELIVERED_INCORRECTLY:
- // we may be on a network that is returning us a web
- // page on redirect
- notifyStatus = IDownloaderClient.STATE_PAUSED_NETWORK_SETUP_FAILURE;
- info.mCurrentBytes = 0;
- db.updateDownload(info);
- setWakeWatchdog = true;
- break;
- case STATUS_PAUSED_BY_APP:
- notifyStatus = IDownloaderClient.STATE_PAUSED_BY_REQUEST;
- break;
- case STATUS_WAITING_FOR_NETWORK:
- case STATUS_WAITING_TO_RETRY:
- notifyStatus = IDownloaderClient.STATE_PAUSED_NETWORK_UNAVAILABLE;
- setWakeWatchdog = true;
- break;
- case STATUS_QUEUED_FOR_WIFI_OR_CELLULAR_PERMISSION:
- case STATUS_QUEUED_FOR_WIFI:
- // look for more detail here
- if (null != mWifiManager) {
- if (!mWifiManager.isWifiEnabled()) {
- notifyStatus = IDownloaderClient.STATE_PAUSED_WIFI_DISABLED_NEED_CELLULAR_PERMISSION;
- setWakeWatchdog = true;
- break;
- }
- }
- notifyStatus = IDownloaderClient.STATE_PAUSED_NEED_CELLULAR_PERMISSION;
- setWakeWatchdog = true;
- break;
- case STATUS_CANCELED:
- notifyStatus = IDownloaderClient.STATE_FAILED_CANCELED;
- setWakeWatchdog = true;
- break;
-
- case STATUS_INSUFFICIENT_SPACE_ERROR:
- notifyStatus = IDownloaderClient.STATE_FAILED_SDCARD_FULL;
- setWakeWatchdog = true;
- break;
-
- case STATUS_DEVICE_NOT_FOUND_ERROR:
- notifyStatus = IDownloaderClient.STATE_PAUSED_SDCARD_UNAVAILABLE;
- setWakeWatchdog = true;
- break;
-
- default:
- notifyStatus = IDownloaderClient.STATE_FAILED;
- break;
- }
- if (setWakeWatchdog) {
- scheduleAlarm(Constants.WATCHDOG_WAKE_TIMER);
- } else {
- cancelAlarms();
- }
- // failure or pause state
- mNotification.onDownloadStateChanged(notifyStatus);
- return;
- }
-
- // all downloads complete
- mNotification.onDownloadStateChanged(IDownloaderClient.STATE_COMPLETED);
- } finally {
- setServiceRunning(false);
- }
- }
-
- @Override
- public void onDestroy() {
- if (null != mConnReceiver) {
- unregisterReceiver(mConnReceiver);
- mConnReceiver = null;
- }
- mServiceStub.disconnect(this);
- super.onDestroy();
- }
-
- public int getNetworkAvailabilityState(DownloadsDB db) {
- if (mIsConnected) {
- if (!mIsCellularConnection)
- return NETWORK_OK;
- int flags = db.mFlags;
- if (mIsRoaming)
- return NETWORK_CANNOT_USE_ROAMING;
- if (0 != (flags & FLAGS_DOWNLOAD_OVER_CELLULAR)) {
- return NETWORK_OK;
- } else {
- return NETWORK_TYPE_DISALLOWED_BY_REQUESTOR;
- }
- }
- return NETWORK_NO_CONNECTION;
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- try {
- mPackageInfo = getPackageManager().getPackageInfo(
- getPackageName(), 0);
- ApplicationInfo ai = getApplicationInfo();
- CharSequence applicationLabel = getPackageManager().getApplicationLabel(ai);
- mNotification = new DownloadNotification(this, applicationLabel);
-
- } catch (NameNotFoundException e) {
- e.printStackTrace();
- }
- }
-
- /**
- * Exception thrown from methods called by generateSaveFile() for any fatal
- * error.
- */
- public static class GenerateSaveFileError extends Exception {
- private static final long serialVersionUID = 3465966015408936540L;
- int mStatus;
- String mMessage;
-
- public GenerateSaveFileError(int status, String message) {
- mStatus = status;
- mMessage = message;
- }
- }
-
- /**
- * Returns the filename (where the file should be saved) from info about a
- * download
- */
- public String generateTempSaveFileName(String fileName) {
- String path = Helpers.getSaveFilePath(this)
- + File.separator + fileName + TEMP_EXT;
- return path;
- }
-
- /**
- * Creates a filename (where the file should be saved) from info about a
- * download.
- */
- public String generateSaveFile(String filename, long filesize)
- throws GenerateSaveFileError {
- String path = generateTempSaveFileName(filename);
- File expPath = new File(path);
- if (!Helpers.isExternalMediaMounted()) {
- Log.d(Constants.TAG, "External media not mounted: " + path);
- throw new GenerateSaveFileError(STATUS_DEVICE_NOT_FOUND_ERROR,
- "external media is not yet mounted");
-
- }
- if (expPath.exists()) {
- Log.d(Constants.TAG, "File already exists: " + path);
- throw new GenerateSaveFileError(STATUS_FILE_ALREADY_EXISTS_ERROR,
- "requested destination file already exists");
- }
- if (Helpers.getAvailableBytes(Helpers.getFilesystemRoot(path)) < filesize) {
- throw new GenerateSaveFileError(STATUS_INSUFFICIENT_SPACE_ERROR,
- "insufficient space on external storage");
- }
- return path;
- }
-
- /**
- * @return a non-localized string appropriate for logging corresponding to
- * one of the NETWORK_* constants.
- */
- public String getLogMessageForNetworkError(int networkError) {
- switch (networkError) {
- case NETWORK_RECOMMENDED_UNUSABLE_DUE_TO_SIZE:
- return "download size exceeds recommended limit for mobile network";
-
- case NETWORK_UNUSABLE_DUE_TO_SIZE:
- return "download size exceeds limit for mobile network";
-
- case NETWORK_NO_CONNECTION:
- return "no network connection available";
-
- case NETWORK_CANNOT_USE_ROAMING:
- return "download cannot use the current network connection because it is roaming";
-
- case NETWORK_TYPE_DISALLOWED_BY_REQUESTOR:
- return "download was requested to not use the current network type";
-
- default:
- return "unknown error with network connectivity";
- }
- }
-
- public int getControl() {
- return mControl;
- }
-
- public int getStatus() {
- return mStatus;
- }
-
- /**
- * Calculating a moving average for the speed so we don't get jumpy
- * calculations for time etc.
- */
- static private final float SMOOTHING_FACTOR = 0.005f;
-
- public void notifyUpdateBytes(long totalBytesSoFar) {
- long timeRemaining;
- long currentTime = SystemClock.uptimeMillis();
- if (0 != mMillisecondsAtSample) {
- // we have a sample.
- long timePassed = currentTime - mMillisecondsAtSample;
- long bytesInSample = totalBytesSoFar - mBytesAtSample;
- float currentSpeedSample = (float) bytesInSample / (float) timePassed;
- if (0 != mAverageDownloadSpeed) {
- mAverageDownloadSpeed = SMOOTHING_FACTOR * currentSpeedSample
- + (1 - SMOOTHING_FACTOR) * mAverageDownloadSpeed;
- } else {
- mAverageDownloadSpeed = currentSpeedSample;
- }
- timeRemaining = (long) ((mTotalLength - totalBytesSoFar) / mAverageDownloadSpeed);
- } else {
- timeRemaining = -1;
- }
- mMillisecondsAtSample = currentTime;
- mBytesAtSample = totalBytesSoFar;
- mNotification.onDownloadProgress(
- new DownloadProgressInfo(mTotalLength,
- totalBytesSoFar,
- timeRemaining,
- mAverageDownloadSpeed)
- );
-
- }
-
- @Override
- protected boolean shouldStop() {
- // the database automatically reads the metadata for version code
- // and download status when the instance is created
- DownloadsDB db = DownloadsDB.getDB(this);
- if (db.mStatus == 0) {
- return true;
- }
- return false;
- }
-
- @Override
- public void requestDownloadStatus() {
- mNotification.resendState();
- }
-
- @Override
- public void onClientUpdated(Messenger clientMessenger) {
- this.mClientMessenger = clientMessenger;
- mNotification.setMessenger(mClientMessenger);
- }
-
-}
diff --git a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/DownloadsDB.java b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/DownloadsDB.java
deleted file mode 100755
index 250299c400..0000000000
--- a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/DownloadsDB.java
+++ /dev/null
@@ -1,510 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.vending.expansion.downloader.impl;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteDoneException;
-import android.database.sqlite.SQLiteOpenHelper;
-import android.database.sqlite.SQLiteStatement;
-import android.provider.BaseColumns;
-import android.util.Log;
-
-public class DownloadsDB {
- private static final String DATABASE_NAME = "DownloadsDB";
- private static final int DATABASE_VERSION = 7;
- public static final String LOG_TAG = DownloadsDB.class.getName();
- final SQLiteOpenHelper mHelper;
- SQLiteStatement mGetDownloadByIndex;
- SQLiteStatement mUpdateCurrentBytes;
- private static DownloadsDB mDownloadsDB;
- long mMetadataRowID = -1;
- int mVersionCode = -1;
- int mStatus = -1;
- int mFlags;
-
- static public synchronized DownloadsDB getDB(Context paramContext) {
- if (null == mDownloadsDB) {
- return new DownloadsDB(paramContext);
- }
- return mDownloadsDB;
- }
-
- private SQLiteStatement getDownloadByIndexStatement() {
- if (null == mGetDownloadByIndex) {
- mGetDownloadByIndex = mHelper.getReadableDatabase().compileStatement(
- "SELECT " + BaseColumns._ID + " FROM "
- + DownloadColumns.TABLE_NAME + " WHERE "
- + DownloadColumns.INDEX + " = ?");
- }
- return mGetDownloadByIndex;
- }
-
- private SQLiteStatement getUpdateCurrentBytesStatement() {
- if (null == mUpdateCurrentBytes) {
- mUpdateCurrentBytes = mHelper.getReadableDatabase().compileStatement(
- "UPDATE " + DownloadColumns.TABLE_NAME + " SET " + DownloadColumns.CURRENTBYTES
- + " = ?" +
- " WHERE " + DownloadColumns.INDEX + " = ?");
- }
- return mUpdateCurrentBytes;
- }
-
- private DownloadsDB(Context paramContext) {
- this.mHelper = new DownloadsContentDBHelper(paramContext);
- final SQLiteDatabase sqldb = mHelper.getReadableDatabase();
- // Query for the version code, the row ID of the metadata (for future
- // updating) the status and the flags
- Cursor cur = sqldb.rawQuery("SELECT " +
- MetadataColumns.APKVERSION + "," +
- BaseColumns._ID + "," +
- MetadataColumns.DOWNLOAD_STATUS + "," +
- MetadataColumns.FLAGS +
- " FROM "
- + MetadataColumns.TABLE_NAME + " LIMIT 1", null);
- if (null != cur && cur.moveToFirst()) {
- mVersionCode = cur.getInt(0);
- mMetadataRowID = cur.getLong(1);
- mStatus = cur.getInt(2);
- mFlags = cur.getInt(3);
- cur.close();
- }
- mDownloadsDB = this;
- }
-
- protected DownloadInfo getDownloadInfoByFileName(String fileName) {
- final SQLiteDatabase sqldb = mHelper.getReadableDatabase();
- Cursor itemcur = null;
- try {
- itemcur = sqldb.query(DownloadColumns.TABLE_NAME, DC_PROJECTION,
- DownloadColumns.FILENAME + " = ?",
- new String[] {
- fileName
- }, null, null, null);
- if (null != itemcur && itemcur.moveToFirst()) {
- return getDownloadInfoFromCursor(itemcur);
- }
- } finally {
- if (null != itemcur)
- itemcur.close();
- }
- return null;
- }
-
- public long getIDForDownloadInfo(final DownloadInfo di) {
- return getIDByIndex(di.mIndex);
- }
-
- public long getIDByIndex(int index) {
- SQLiteStatement downloadByIndex = getDownloadByIndexStatement();
- downloadByIndex.clearBindings();
- downloadByIndex.bindLong(1, index);
- try {
- return downloadByIndex.simpleQueryForLong();
- } catch (SQLiteDoneException e) {
- return -1;
- }
- }
-
- public void updateDownloadCurrentBytes(final DownloadInfo di) {
- SQLiteStatement downloadCurrentBytes = getUpdateCurrentBytesStatement();
- downloadCurrentBytes.clearBindings();
- downloadCurrentBytes.bindLong(1, di.mCurrentBytes);
- downloadCurrentBytes.bindLong(2, di.mIndex);
- downloadCurrentBytes.execute();
- }
-
- public void close() {
- this.mHelper.close();
- }
-
- protected static class DownloadsContentDBHelper extends SQLiteOpenHelper {
- DownloadsContentDBHelper(Context paramContext) {
- super(paramContext, DATABASE_NAME, null, DATABASE_VERSION);
- }
-
- private String createTableQueryFromArray(String paramString,
- String[][] paramArrayOfString) {
- StringBuilder localStringBuilder = new StringBuilder();
- localStringBuilder.append("CREATE TABLE ");
- localStringBuilder.append(paramString);
- localStringBuilder.append(" (");
- int i = paramArrayOfString.length;
- for (int j = 0;; j++) {
- if (j >= i) {
- localStringBuilder
- .setLength(localStringBuilder.length() - 1);
- localStringBuilder.append(");");
- return localStringBuilder.toString();
- }
- String[] arrayOfString = paramArrayOfString[j];
- localStringBuilder.append(' ');
- localStringBuilder.append(arrayOfString[0]);
- localStringBuilder.append(' ');
- localStringBuilder.append(arrayOfString[1]);
- localStringBuilder.append(',');
- }
- }
-
- /**
- * These two arrays must match and have the same order. For every Schema
- * there must be a corresponding table name.
- */
- static final private String[][][] sSchemas = {
- DownloadColumns.SCHEMA, MetadataColumns.SCHEMA
- };
-
- static final private String[] sTables = {
- DownloadColumns.TABLE_NAME, MetadataColumns.TABLE_NAME
- };
-
- /**
- * Goes through all of the tables in sTables and drops each table if it
- * exists. Altered to no longer make use of reflection.
- */
- private void dropTables(SQLiteDatabase paramSQLiteDatabase) {
- for (String table : sTables) {
- try {
- paramSQLiteDatabase.execSQL("DROP TABLE IF EXISTS " + table);
- } catch (Exception localException) {
- localException.printStackTrace();
- }
- }
- }
-
- /**
- * Goes through all of the tables in sTables and creates a database with
- * the corresponding schema described in sSchemas. Altered to no longer
- * make use of reflection.
- */
- public void onCreate(SQLiteDatabase paramSQLiteDatabase) {
- int numSchemas = sSchemas.length;
- for (int i = 0; i < numSchemas; i++) {
- try {
- String[][] schema = (String[][]) sSchemas[i];
- paramSQLiteDatabase.execSQL(createTableQueryFromArray(
- sTables[i], schema));
- } catch (Exception localException) {
- while (true)
- localException.printStackTrace();
- }
- }
- }
-
- public void onUpgrade(SQLiteDatabase paramSQLiteDatabase,
- int paramInt1, int paramInt2) {
- Log.w(DownloadsContentDBHelper.class.getName(),
- "Upgrading database from version " + paramInt1 + " to "
- + paramInt2 + ", which will destroy all old data");
- dropTables(paramSQLiteDatabase);
- onCreate(paramSQLiteDatabase);
- }
- }
-
- public static class MetadataColumns implements BaseColumns {
- public static final String APKVERSION = "APKVERSION";
- public static final String DOWNLOAD_STATUS = "DOWNLOADSTATUS";
- public static final String FLAGS = "DOWNLOADFLAGS";
-
- public static final String[][] SCHEMA = {
- {
- BaseColumns._ID, "INTEGER PRIMARY KEY"
- },
- {
- APKVERSION, "INTEGER"
- }, {
- DOWNLOAD_STATUS, "INTEGER"
- },
- {
- FLAGS, "INTEGER"
- }
- };
- public static final String TABLE_NAME = "MetadataColumns";
- public static final String _ID = "MetadataColumns._id";
- }
-
- public static class DownloadColumns implements BaseColumns {
- public static final String INDEX = "FILEIDX";
- public static final String URI = "URI";
- public static final String FILENAME = "FN";
- public static final String ETAG = "ETAG";
-
- public static final String TOTALBYTES = "TOTALBYTES";
- public static final String CURRENTBYTES = "CURRENTBYTES";
- public static final String LASTMOD = "LASTMOD";
-
- public static final String STATUS = "STATUS";
- public static final String CONTROL = "CONTROL";
- public static final String NUM_FAILED = "FAILCOUNT";
- public static final String RETRY_AFTER = "RETRYAFTER";
- public static final String REDIRECT_COUNT = "REDIRECTCOUNT";
-
- public static final String[][] SCHEMA = {
- {
- BaseColumns._ID, "INTEGER PRIMARY KEY"
- },
- {
- INDEX, "INTEGER UNIQUE"
- }, {
- URI, "TEXT"
- },
- {
- FILENAME, "TEXT UNIQUE"
- }, {
- ETAG, "TEXT"
- },
- {
- TOTALBYTES, "INTEGER"
- }, {
- CURRENTBYTES, "INTEGER"
- },
- {
- LASTMOD, "INTEGER"
- }, {
- STATUS, "INTEGER"
- },
- {
- CONTROL, "INTEGER"
- }, {
- NUM_FAILED, "INTEGER"
- },
- {
- RETRY_AFTER, "INTEGER"
- }, {
- REDIRECT_COUNT, "INTEGER"
- }
- };
- public static final String TABLE_NAME = "DownloadColumns";
- public static final String _ID = "DownloadColumns._id";
- }
-
- private static final String[] DC_PROJECTION = {
- DownloadColumns.FILENAME,
- DownloadColumns.URI, DownloadColumns.ETAG,
- DownloadColumns.TOTALBYTES, DownloadColumns.CURRENTBYTES,
- DownloadColumns.LASTMOD, DownloadColumns.STATUS,
- DownloadColumns.CONTROL, DownloadColumns.NUM_FAILED,
- DownloadColumns.RETRY_AFTER, DownloadColumns.REDIRECT_COUNT,
- DownloadColumns.INDEX
- };
-
- private static final int FILENAME_IDX = 0;
- private static final int URI_IDX = 1;
- private static final int ETAG_IDX = 2;
- private static final int TOTALBYTES_IDX = 3;
- private static final int CURRENTBYTES_IDX = 4;
- private static final int LASTMOD_IDX = 5;
- private static final int STATUS_IDX = 6;
- private static final int CONTROL_IDX = 7;
- private static final int NUM_FAILED_IDX = 8;
- private static final int RETRY_AFTER_IDX = 9;
- private static final int REDIRECT_COUNT_IDX = 10;
- private static final int INDEX_IDX = 11;
-
- /**
- * This function will add a new file to the database if it does not exist.
- *
- * @param di DownloadInfo that we wish to store
- * @return the row id of the record to be updated/inserted, or -1
- */
- public boolean updateDownload(DownloadInfo di) {
- ContentValues cv = new ContentValues();
- cv.put(DownloadColumns.INDEX, di.mIndex);
- cv.put(DownloadColumns.FILENAME, di.mFileName);
- cv.put(DownloadColumns.URI, di.mUri);
- cv.put(DownloadColumns.ETAG, di.mETag);
- cv.put(DownloadColumns.TOTALBYTES, di.mTotalBytes);
- cv.put(DownloadColumns.CURRENTBYTES, di.mCurrentBytes);
- cv.put(DownloadColumns.LASTMOD, di.mLastMod);
- cv.put(DownloadColumns.STATUS, di.mStatus);
- cv.put(DownloadColumns.CONTROL, di.mControl);
- cv.put(DownloadColumns.NUM_FAILED, di.mNumFailed);
- cv.put(DownloadColumns.RETRY_AFTER, di.mRetryAfter);
- cv.put(DownloadColumns.REDIRECT_COUNT, di.mRedirectCount);
- return updateDownload(di, cv);
- }
-
- public boolean updateDownload(DownloadInfo di, ContentValues cv) {
- long id = di == null ? -1 : getIDForDownloadInfo(di);
- try {
- final SQLiteDatabase sqldb = mHelper.getWritableDatabase();
- if (id != -1) {
- if (1 != sqldb.update(DownloadColumns.TABLE_NAME,
- cv, DownloadColumns._ID + " = " + id, null)) {
- return false;
- }
- } else {
- return -1 != sqldb.insert(DownloadColumns.TABLE_NAME,
- DownloadColumns.URI, cv);
- }
- } catch (android.database.sqlite.SQLiteException ex) {
- ex.printStackTrace();
- }
- return false;
- }
-
- public int getLastCheckedVersionCode() {
- return mVersionCode;
- }
-
- public boolean isDownloadRequired() {
- final SQLiteDatabase sqldb = mHelper.getReadableDatabase();
- Cursor cur = sqldb.rawQuery("SELECT Count(*) FROM "
- + DownloadColumns.TABLE_NAME + " WHERE "
- + DownloadColumns.STATUS + " <> 0", null);
- try {
- if (null != cur && cur.moveToFirst()) {
- return 0 == cur.getInt(0);
- }
- } finally {
- if (null != cur)
- cur.close();
- }
- return true;
- }
-
- public int getFlags() {
- return mFlags;
- }
-
- public boolean updateFlags(int flags) {
- if (mFlags != flags) {
- ContentValues cv = new ContentValues();
- cv.put(MetadataColumns.FLAGS, flags);
- if (updateMetadata(cv)) {
- mFlags = flags;
- return true;
- } else {
- return false;
- }
- } else {
- return true;
- }
- };
-
- public boolean updateStatus(int status) {
- if (mStatus != status) {
- ContentValues cv = new ContentValues();
- cv.put(MetadataColumns.DOWNLOAD_STATUS, status);
- if (updateMetadata(cv)) {
- mStatus = status;
- return true;
- } else {
- return false;
- }
- } else {
- return true;
- }
- };
-
- public boolean updateMetadata(ContentValues cv) {
- final SQLiteDatabase sqldb = mHelper.getWritableDatabase();
- if (-1 == this.mMetadataRowID) {
- long newID = sqldb.insert(MetadataColumns.TABLE_NAME,
- MetadataColumns.APKVERSION, cv);
- if (-1 == newID)
- return false;
- mMetadataRowID = newID;
- } else {
- if (0 == sqldb.update(MetadataColumns.TABLE_NAME, cv,
- BaseColumns._ID + " = " + mMetadataRowID, null))
- return false;
- }
- return true;
- }
-
- public boolean updateMetadata(int apkVersion, int downloadStatus) {
- ContentValues cv = new ContentValues();
- cv.put(MetadataColumns.APKVERSION, apkVersion);
- cv.put(MetadataColumns.DOWNLOAD_STATUS, downloadStatus);
- if (updateMetadata(cv)) {
- mVersionCode = apkVersion;
- mStatus = downloadStatus;
- return true;
- } else {
- return false;
- }
- };
-
- public boolean updateFromDb(DownloadInfo di) {
- final SQLiteDatabase sqldb = mHelper.getReadableDatabase();
- Cursor cur = null;
- try {
- cur = sqldb.query(DownloadColumns.TABLE_NAME, DC_PROJECTION,
- DownloadColumns.FILENAME + "= ?",
- new String[] {
- di.mFileName
- }, null, null, null);
- if (null != cur && cur.moveToFirst()) {
- setDownloadInfoFromCursor(di, cur);
- return true;
- }
- return false;
- } finally {
- if (null != cur) {
- cur.close();
- }
- }
- }
-
- public void setDownloadInfoFromCursor(DownloadInfo di, Cursor cur) {
- di.mUri = cur.getString(URI_IDX);
- di.mETag = cur.getString(ETAG_IDX);
- di.mTotalBytes = cur.getLong(TOTALBYTES_IDX);
- di.mCurrentBytes = cur.getLong(CURRENTBYTES_IDX);
- di.mLastMod = cur.getLong(LASTMOD_IDX);
- di.mStatus = cur.getInt(STATUS_IDX);
- di.mControl = cur.getInt(CONTROL_IDX);
- di.mNumFailed = cur.getInt(NUM_FAILED_IDX);
- di.mRetryAfter = cur.getInt(RETRY_AFTER_IDX);
- di.mRedirectCount = cur.getInt(REDIRECT_COUNT_IDX);
- }
-
- public DownloadInfo getDownloadInfoFromCursor(Cursor cur) {
- DownloadInfo di = new DownloadInfo(cur.getInt(INDEX_IDX),
- cur.getString(FILENAME_IDX), this.getClass().getPackage()
- .getName());
- setDownloadInfoFromCursor(di, cur);
- return di;
- }
-
- public DownloadInfo[] getDownloads() {
- final SQLiteDatabase sqldb = mHelper.getReadableDatabase();
- Cursor cur = null;
- try {
- cur = sqldb.query(DownloadColumns.TABLE_NAME, DC_PROJECTION, null,
- null, null, null, null);
- if (null != cur && cur.moveToFirst()) {
- DownloadInfo[] retInfos = new DownloadInfo[cur.getCount()];
- int idx = 0;
- do {
- DownloadInfo di = getDownloadInfoFromCursor(cur);
- retInfos[idx++] = di;
- } while (cur.moveToNext());
- return retInfos;
- }
- return null;
- } finally {
- if (null != cur) {
- cur.close();
- }
- }
- }
-
-}
diff --git a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/HttpDateTime.java b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/HttpDateTime.java
deleted file mode 100644
index 3f440e9893..0000000000
--- a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/HttpDateTime.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.vending.expansion.downloader.impl;
-
-import android.text.format.Time;
-
-import java.util.Calendar;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Helper for parsing an HTTP date.
- */
-public final class HttpDateTime {
-
- /*
- * Regular expression for parsing HTTP-date. Wdy, DD Mon YYYY HH:MM:SS GMT
- * RFC 822, updated by RFC 1123 Weekday, DD-Mon-YY HH:MM:SS GMT RFC 850,
- * obsoleted by RFC 1036 Wdy Mon DD HH:MM:SS YYYY ANSI C's asctime() format
- * with following variations Wdy, DD-Mon-YYYY HH:MM:SS GMT Wdy, (SP)D Mon
- * YYYY HH:MM:SS GMT Wdy,DD Mon YYYY HH:MM:SS GMT Wdy, DD-Mon-YY HH:MM:SS
- * GMT Wdy, DD Mon YYYY HH:MM:SS -HHMM Wdy, DD Mon YYYY HH:MM:SS Wdy Mon
- * (SP)D HH:MM:SS YYYY Wdy Mon DD HH:MM:SS YYYY GMT HH can be H if the first
- * digit is zero. Mon can be the full name of the month.
- */
- private static final String HTTP_DATE_RFC_REGEXP =
- "([0-9]{1,2})[- ]([A-Za-z]{3,9})[- ]([0-9]{2,4})[ ]"
- + "([0-9]{1,2}:[0-9][0-9]:[0-9][0-9])";
-
- private static final String HTTP_DATE_ANSIC_REGEXP =
- "[ ]([A-Za-z]{3,9})[ ]+([0-9]{1,2})[ ]"
- + "([0-9]{1,2}:[0-9][0-9]:[0-9][0-9])[ ]([0-9]{2,4})";
-
- /**
- * The compiled version of the HTTP-date regular expressions.
- */
- private static final Pattern HTTP_DATE_RFC_PATTERN =
- Pattern.compile(HTTP_DATE_RFC_REGEXP);
- private static final Pattern HTTP_DATE_ANSIC_PATTERN =
- Pattern.compile(HTTP_DATE_ANSIC_REGEXP);
-
- private static class TimeOfDay {
- TimeOfDay(int h, int m, int s) {
- this.hour = h;
- this.minute = m;
- this.second = s;
- }
-
- int hour;
- int minute;
- int second;
- }
-
- public static long parse(String timeString)
- throws IllegalArgumentException {
-
- int date = 1;
- int month = Calendar.JANUARY;
- int year = 1970;
- TimeOfDay timeOfDay;
-
- Matcher rfcMatcher = HTTP_DATE_RFC_PATTERN.matcher(timeString);
- if (rfcMatcher.find()) {
- date = getDate(rfcMatcher.group(1));
- month = getMonth(rfcMatcher.group(2));
- year = getYear(rfcMatcher.group(3));
- timeOfDay = getTime(rfcMatcher.group(4));
- } else {
- Matcher ansicMatcher = HTTP_DATE_ANSIC_PATTERN.matcher(timeString);
- if (ansicMatcher.find()) {
- month = getMonth(ansicMatcher.group(1));
- date = getDate(ansicMatcher.group(2));
- timeOfDay = getTime(ansicMatcher.group(3));
- year = getYear(ansicMatcher.group(4));
- } else {
- throw new IllegalArgumentException();
- }
- }
-
- // FIXME: Y2038 BUG!
- if (year >= 2038) {
- year = 2038;
- month = Calendar.JANUARY;
- date = 1;
- }
-
- Time time = new Time(Time.TIMEZONE_UTC);
- time.set(timeOfDay.second, timeOfDay.minute, timeOfDay.hour, date,
- month, year);
- return time.toMillis(false /* use isDst */);
- }
-
- private static int getDate(String dateString) {
- if (dateString.length() == 2) {
- return (dateString.charAt(0) - '0') * 10
- + (dateString.charAt(1) - '0');
- } else {
- return (dateString.charAt(0) - '0');
- }
- }
-
- /*
- * jan = 9 + 0 + 13 = 22 feb = 5 + 4 + 1 = 10 mar = 12 + 0 + 17 = 29 apr = 0
- * + 15 + 17 = 32 may = 12 + 0 + 24 = 36 jun = 9 + 20 + 13 = 42 jul = 9 + 20
- * + 11 = 40 aug = 0 + 20 + 6 = 26 sep = 18 + 4 + 15 = 37 oct = 14 + 2 + 19
- * = 35 nov = 13 + 14 + 21 = 48 dec = 3 + 4 + 2 = 9
- */
- private static int getMonth(String monthString) {
- int hash = Character.toLowerCase(monthString.charAt(0)) +
- Character.toLowerCase(monthString.charAt(1)) +
- Character.toLowerCase(monthString.charAt(2)) - 3 * 'a';
- switch (hash) {
- case 22:
- return Calendar.JANUARY;
- case 10:
- return Calendar.FEBRUARY;
- case 29:
- return Calendar.MARCH;
- case 32:
- return Calendar.APRIL;
- case 36:
- return Calendar.MAY;
- case 42:
- return Calendar.JUNE;
- case 40:
- return Calendar.JULY;
- case 26:
- return Calendar.AUGUST;
- case 37:
- return Calendar.SEPTEMBER;
- case 35:
- return Calendar.OCTOBER;
- case 48:
- return Calendar.NOVEMBER;
- case 9:
- return Calendar.DECEMBER;
- default:
- throw new IllegalArgumentException();
- }
- }
-
- private static int getYear(String yearString) {
- if (yearString.length() == 2) {
- int year = (yearString.charAt(0) - '0') * 10
- + (yearString.charAt(1) - '0');
- if (year >= 70) {
- return year + 1900;
- } else {
- return year + 2000;
- }
- } else if (yearString.length() == 3) {
- // According to RFC 2822, three digit years should be added to 1900.
- int year = (yearString.charAt(0) - '0') * 100
- + (yearString.charAt(1) - '0') * 10
- + (yearString.charAt(2) - '0');
- return year + 1900;
- } else if (yearString.length() == 4) {
- return (yearString.charAt(0) - '0') * 1000
- + (yearString.charAt(1) - '0') * 100
- + (yearString.charAt(2) - '0') * 10
- + (yearString.charAt(3) - '0');
- } else {
- return 1970;
- }
- }
-
- private static TimeOfDay getTime(String timeString) {
- // HH might be H
- int i = 0;
- int hour = timeString.charAt(i++) - '0';
- if (timeString.charAt(i) != ':')
- hour = hour * 10 + (timeString.charAt(i++) - '0');
- // Skip ':'
- i++;
-
- int minute = (timeString.charAt(i++) - '0') * 10
- + (timeString.charAt(i++) - '0');
- // Skip ':'
- i++;
-
- int second = (timeString.charAt(i++) - '0') * 10
- + (timeString.charAt(i++) - '0');
-
- return new TimeOfDay(hour, minute, second);
- }
-}
diff --git a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/V14CustomNotification.java b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/V14CustomNotification.java
deleted file mode 100644
index e736603e2a..0000000000
--- a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/V14CustomNotification.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.vending.expansion.downloader.impl;
-
-import com.android.vending.expansion.downloader.R;
-import com.google.android.vending.expansion.downloader.Helpers;
-
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.content.Context;
-
-public class V14CustomNotification implements DownloadNotification.ICustomNotification {
-
- CharSequence mTitle;
- CharSequence mTicker;
- int mIcon;
- long mTotalKB = -1;
- long mCurrentKB = -1;
- long mTimeRemaining;
- PendingIntent mPendingIntent;
-
- @Override
- public void setIcon(int icon) {
- mIcon = icon;
- }
-
- @Override
- public void setTitle(CharSequence title) {
- mTitle = title;
- }
-
- @Override
- public void setTotalBytes(long totalBytes) {
- mTotalKB = totalBytes;
- }
-
- @Override
- public void setCurrentBytes(long currentBytes) {
- mCurrentKB = currentBytes;
- }
-
- void setProgress(Notification.Builder builder) {
-
- }
-
- @Override
- public Notification updateNotification(Context c) {
- Notification.Builder builder = new Notification.Builder(c);
- builder.setContentTitle(mTitle);
- if (mTotalKB > 0 && -1 != mCurrentKB) {
- builder.setProgress((int) (mTotalKB >> 8), (int) (mCurrentKB >> 8), false);
- } else {
- builder.setProgress(0, 0, true);
- }
- builder.setContentText(Helpers.getDownloadProgressString(mCurrentKB, mTotalKB));
- builder.setContentInfo(c.getString(R.string.time_remaining_notification,
- Helpers.getTimeRemaining(mTimeRemaining)));
- if (mIcon != 0) {
- builder.setSmallIcon(mIcon);
- } else {
- int iconResource = android.R.drawable.stat_sys_download;
- builder.setSmallIcon(iconResource);
- }
- builder.setOngoing(true);
- builder.setTicker(mTicker);
- builder.setContentIntent(mPendingIntent);
- builder.setOnlyAlertOnce(true);
-
- return builder.getNotification();
- }
-
- @Override
- public void setPendingIntent(PendingIntent contentIntent) {
- mPendingIntent = contentIntent;
- }
-
- @Override
- public void setTicker(CharSequence ticker) {
- mTicker = ticker;
- }
-
- @Override
- public void setTimeRemaining(long timeRemaining) {
- mTimeRemaining = timeRemaining;
- }
-
-}
diff --git a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/V3CustomNotification.java b/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/V3CustomNotification.java
deleted file mode 100644
index e3666e05b9..0000000000
--- a/platform/android/libs/downloader_library/src/com/google/android/vending/expansion/downloader/impl/V3CustomNotification.java
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.vending.expansion.downloader.impl;
-
-import com.android.vending.expansion.downloader.R;
-import com.google.android.vending.expansion.downloader.Helpers;
-
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.content.Context;
-import android.graphics.BitmapFactory;
-import android.view.View;
-import android.widget.RemoteViews;
-
-public class V3CustomNotification implements DownloadNotification.ICustomNotification {
-
- CharSequence mTitle;
- CharSequence mTicker;
- int mIcon;
- long mTotalBytes = -1;
- long mCurrentBytes = -1;
- long mTimeRemaining;
- PendingIntent mPendingIntent;
- Notification mNotification = new Notification();
-
- @Override
- public void setIcon(int icon) {
- mIcon = icon;
- }
-
- @Override
- public void setTitle(CharSequence title) {
- mTitle = title;
- }
-
- @Override
- public void setTotalBytes(long totalBytes) {
- mTotalBytes = totalBytes;
- }
-
- @Override
- public void setCurrentBytes(long currentBytes) {
- mCurrentBytes = currentBytes;
- }
-
- @Override
- public Notification updateNotification(Context c) {
- Notification n = mNotification;
-
- n.icon = mIcon;
-
- n.flags |= Notification.FLAG_ONGOING_EVENT;
-
- if (android.os.Build.VERSION.SDK_INT > 10) {
- n.flags |= Notification.FLAG_ONLY_ALERT_ONCE; // only matters for
- // Honeycomb
- }
-
- // Build the RemoteView object
- RemoteViews expandedView = new RemoteViews(
- c.getPackageName(),
- R.layout.status_bar_ongoing_event_progress_bar);
-
- expandedView.setTextViewText(R.id.title, mTitle);
- // look at strings
- expandedView.setViewVisibility(R.id.description, View.VISIBLE);
- expandedView.setTextViewText(R.id.description,
- Helpers.getDownloadProgressString(mCurrentBytes, mTotalBytes));
- expandedView.setViewVisibility(R.id.progress_bar_frame, View.VISIBLE);
- expandedView.setProgressBar(R.id.progress_bar,
- (int) (mTotalBytes >> 8),
- (int) (mCurrentBytes >> 8),
- mTotalBytes <= 0);
- expandedView.setViewVisibility(R.id.time_remaining, View.VISIBLE);
- expandedView.setTextViewText(
- R.id.time_remaining,
- c.getString(R.string.time_remaining_notification,
- Helpers.getTimeRemaining(mTimeRemaining)));
- expandedView.setTextViewText(R.id.progress_text,
- Helpers.getDownloadProgressPercent(mCurrentBytes, mTotalBytes));
- expandedView.setImageViewResource(R.id.appIcon, mIcon);
- n.contentView = expandedView;
- n.contentIntent = mPendingIntent;
- return n;
- }
-
- @Override
- public void setPendingIntent(PendingIntent contentIntent) {
- mPendingIntent = contentIntent;
- }
-
- @Override
- public void setTicker(CharSequence ticker) {
- mTicker = ticker;
- }
-
- @Override
- public void setTimeRemaining(long timeRemaining) {
- mTimeRemaining = timeRemaining;
- }
-
-}
diff --git a/platform/android/libs/google_play_services/.classpath b/platform/android/libs/google_play_services/.classpath
deleted file mode 100644
index 7bc01d9a9c..0000000000
--- a/platform/android/libs/google_play_services/.classpath
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<classpath>
- <classpathentry kind="src" path="src"/>
- <classpathentry kind="src" path="gen"/>
- <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
- <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
- <classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
- <classpathentry kind="output" path="bin/classes"/>
-</classpath>
diff --git a/platform/android/libs/google_play_services/AndroidManifest.xml b/platform/android/libs/google_play_services/AndroidManifest.xml
deleted file mode 100644
index aecd02b5d0..0000000000
--- a/platform/android/libs/google_play_services/AndroidManifest.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.gms"
- android:versionCode="4323030"
- android:versionName="4.3.23 (1069729-030)" >
-
- <uses-sdk android:minSdkVersion="9"/>
-
-</manifest>
diff --git a/platform/android/libs/google_play_services/README.txt b/platform/android/libs/google_play_services/README.txt
deleted file mode 100644
index 32f8d5eb85..0000000000
--- a/platform/android/libs/google_play_services/README.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-Library Project including Google Play services client jar.
-
-This can be used by an Android project to use the API's provided
-by Google Play services.
-
-There is technically no source, but the src folder is necessary
-to ensure that the build system works. The content is actually
-located in the libs/ directory.
-
-
-USAGE:
-
-Make sure you import this Android library project into your IDE
-and set this project as a dependency.
-
-Note that if you use proguard, you will want to include the
-options from proguard.txt in your configuration. \ No newline at end of file
diff --git a/platform/android/libs/google_play_services/build.xml b/platform/android/libs/google_play_services/build.xml
deleted file mode 100644
index 22ccf3aaf4..0000000000
--- a/platform/android/libs/google_play_services/build.xml
+++ /dev/null
@@ -1,92 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project name="google_play_services" default="help">
-
- <!-- The local.properties file is created and updated by the 'android' tool.
- It contains the path to the SDK. It should *NOT* be checked into
- Version Control Systems. -->
- <property file="local.properties" />
-
- <!-- The ant.properties file can be created by you. It is only edited by the
- 'android' tool to add properties to it.
- This is the place to change some Ant specific build properties.
- Here are some properties you may want to change/update:
-
- source.dir
- The name of the source directory. Default is 'src'.
- out.dir
- The name of the output directory. Default is 'bin'.
-
- For other overridable properties, look at the beginning of the rules
- files in the SDK, at tools/ant/build.xml
-
- Properties related to the SDK location or the project target should
- be updated using the 'android' tool with the 'update' action.
-
- This file is an integral part of the build system for your
- application and should be checked into Version Control Systems.
-
- -->
- <property file="ant.properties" />
-
- <!-- if sdk.dir was not set from one of the property file, then
- get it from the ANDROID_HOME env var.
- This must be done before we load project.properties since
- the proguard config can use sdk.dir -->
- <property environment="env" />
- <condition property="sdk.dir" value="${env.ANDROID_HOME}">
- <isset property="env.ANDROID_HOME" />
- </condition>
-
- <!-- The project.properties file is created and updated by the 'android'
- tool, as well as ADT.
-
- This contains project specific properties such as project target, and library
- dependencies. Lower level build properties are stored in ant.properties
- (or in .classpath for Eclipse projects).
-
- This file is an integral part of the build system for your
- application and should be checked into Version Control Systems. -->
- <loadproperties srcFile="project.properties" />
-
- <!-- quick check on sdk.dir -->
- <fail
- message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
- unless="sdk.dir"
- />
-
- <!--
- Import per project custom build rules if present at the root of the project.
- This is the place to put custom intermediary targets such as:
- -pre-build
- -pre-compile
- -post-compile (This is typically used for code obfuscation.
- Compiled code location: ${out.classes.absolute.dir}
- If this is not done in place, override ${out.dex.input.absolute.dir})
- -post-package
- -post-build
- -pre-clean
- -->
- <import file="custom_rules.xml" optional="true" />
-
- <!-- Import the actual build file.
-
- To customize existing targets, there are two options:
- - Customize only one target:
- - copy/paste the target into this file, *before* the
- <import> task.
- - customize it to your needs.
- - Customize the whole content of build.xml
- - copy/paste the content of the rules files (minus the top node)
- into this file, replacing the <import> task.
- - customize to your needs.
-
- ***********************
- ****** IMPORTANT ******
- ***********************
- In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
- in order to avoid having your file be overridden by tools such as "android update project"
- -->
- <!-- version-tag: 1 -->
- <import file="${sdk.dir}/tools/ant/build.xml" />
-
-</project>
diff --git a/platform/android/libs/google_play_services/libs/google-play-services.jar b/platform/android/libs/google_play_services/libs/google-play-services.jar
deleted file mode 100644
index 67d56476b6..0000000000
--- a/platform/android/libs/google_play_services/libs/google-play-services.jar
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/libs/google-play-services.jar.properties b/platform/android/libs/google_play_services/libs/google-play-services.jar.properties
deleted file mode 100644
index 429687b792..0000000000
--- a/platform/android/libs/google_play_services/libs/google-play-services.jar.properties
+++ /dev/null
@@ -1 +0,0 @@
-doc=../../../docs/reference
diff --git a/platform/android/libs/google_play_services/proguard-project.txt b/platform/android/libs/google_play_services/proguard-project.txt
deleted file mode 100644
index f2fe1559a2..0000000000
--- a/platform/android/libs/google_play_services/proguard-project.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-# To enable ProGuard in your project, edit project.properties
-# to define the proguard.config property as described in that file.
-#
-# Add project specific ProGuard rules here.
-# By default, the flags in this file are appended to flags specified
-# in ${sdk.dir}/tools/proguard/proguard-android.txt
-# You can edit the include path and order by changing the ProGuard
-# include property in project.properties.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# Add any project specific keep options here:
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
diff --git a/platform/android/libs/google_play_services/proguard.txt b/platform/android/libs/google_play_services/proguard.txt
deleted file mode 100644
index 0c9693a2c0..0000000000
--- a/platform/android/libs/google_play_services/proguard.txt
+++ /dev/null
@@ -1,20 +0,0 @@
--keep class * extends java.util.ListResourceBundle {
- protected Object[][] getContents();
-}
-
-# Keep SafeParcelable value, needed for reflection. This is required to support backwards
-# compatibility of some classes.
--keep public class com.google.android.gms.common.internal.safeparcel.SafeParcelable {
- public static final *** NULL;
-}
-
-# Keep the names of classes/members we need for client functionality.
--keepnames @com.google.android.gms.common.annotation.KeepName class *
--keepclassmembernames class * {
- @com.google.android.gms.common.annotation.KeepName *;
-}
-
-# Needed for Parcelable/SafeParcelable Creators to not get stripped
--keepnames class * implements android.os.Parcelable {
- public static final ** CREATOR;
-} \ No newline at end of file
diff --git a/platform/android/libs/google_play_services/project.properties b/platform/android/libs/google_play_services/project.properties
deleted file mode 100644
index 36f15941e2..0000000000
--- a/platform/android/libs/google_play_services/project.properties
+++ /dev/null
@@ -1,15 +0,0 @@
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must be checked in Version Control Systems.
-#
-# To customize properties used by the Ant build system edit
-# "ant.properties", and override values to adapt the script to your
-# project structure.
-#
-# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
-#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
-
-# Project target.
-target=android-15
-android.library=true
diff --git a/platform/android/libs/google_play_services/res/color/common_signin_btn_text_dark.xml b/platform/android/libs/google_play_services/res/color/common_signin_btn_text_dark.xml
deleted file mode 100644
index a615ba2747..0000000000
--- a/platform/android/libs/google_play_services/res/color/common_signin_btn_text_dark.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item
- android:state_pressed="true"
- android:color="@color/common_signin_btn_dark_text_pressed" />
- <item
- android:state_enabled="false"
- android:state_focused="true"
- android:color="@color/common_signin_btn_dark_text_disabled" />
- <item
- android:state_focused="true"
- android:color="@color/common_signin_btn_dark_text_focused" />
- <item
- android:state_enabled="false"
- android:color="@color/common_signin_btn_dark_text_disabled" />
- <item
- android:color="@color/common_signin_btn_dark_text_default" />
-</selector>
diff --git a/platform/android/libs/google_play_services/res/color/common_signin_btn_text_light.xml b/platform/android/libs/google_play_services/res/color/common_signin_btn_text_light.xml
deleted file mode 100644
index 662066899b..0000000000
--- a/platform/android/libs/google_play_services/res/color/common_signin_btn_text_light.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item
- android:state_pressed="true"
- android:color="@color/common_signin_btn_light_text_pressed" />
- <item
- android:state_enabled="false"
- android:state_focused="true"
- android:color="@color/common_signin_btn_light_text_disabled" />
- <item
- android:state_focused="true"
- android:color="@color/common_signin_btn_light_text_focused" />
- <item
- android:state_enabled="false"
- android:color="@color/common_signin_btn_light_text_disabled" />
- <item
- android:color="@color/common_signin_btn_light_text_default" />
-</selector>
diff --git a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_disabled_dark.9.png b/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_disabled_dark.9.png
deleted file mode 100644
index 0f9e7917e0..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_disabled_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_disabled_focus_dark.9.png b/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_disabled_focus_dark.9.png
deleted file mode 100644
index 570e432252..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_disabled_focus_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_disabled_focus_light.9.png b/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_disabled_focus_light.9.png
deleted file mode 100644
index 570e432252..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_disabled_focus_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_disabled_light.9.png b/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_disabled_light.9.png
deleted file mode 100644
index 0f9e7917e0..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_disabled_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_focus_dark.9.png b/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_focus_dark.9.png
deleted file mode 100644
index f507b9f7da..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_focus_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_focus_light.9.png b/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_focus_light.9.png
deleted file mode 100644
index d5625e5fc1..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_focus_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_normal_dark.9.png b/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_normal_dark.9.png
deleted file mode 100644
index aea3c0d168..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_normal_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_normal_light.9.png b/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_normal_light.9.png
deleted file mode 100644
index 849e89f3aa..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_normal_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_pressed_dark.9.png b/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_pressed_dark.9.png
deleted file mode 100644
index f4ab2f2a51..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_pressed_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_pressed_light.9.png b/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_pressed_light.9.png
deleted file mode 100644
index 9fe611d684..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_icon_pressed_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_disabled_dark.9.png b/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_disabled_dark.9.png
deleted file mode 100644
index bbcde39cf0..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_disabled_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_disabled_focus_dark.9.png b/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_disabled_focus_dark.9.png
deleted file mode 100644
index 53957b698f..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_disabled_focus_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_disabled_focus_light.9.png b/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_disabled_focus_light.9.png
deleted file mode 100644
index 53957b698f..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_disabled_focus_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_disabled_light.9.png b/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_disabled_light.9.png
deleted file mode 100644
index bbcde39cf0..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_disabled_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_focus_dark.9.png b/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_focus_dark.9.png
deleted file mode 100644
index 000d12e8e3..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_focus_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_focus_light.9.png b/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_focus_light.9.png
deleted file mode 100644
index d9279405c6..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_focus_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_normal_dark.9.png b/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_normal_dark.9.png
deleted file mode 100644
index 67f263c80e..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_normal_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_normal_light.9.png b/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_normal_light.9.png
deleted file mode 100644
index 96324c52f9..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_normal_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_pressed_dark.9.png b/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_pressed_dark.9.png
deleted file mode 100644
index e4503128f6..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_pressed_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_pressed_light.9.png b/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_pressed_light.9.png
deleted file mode 100644
index fb94b77616..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-hdpi/common_signin_btn_text_pressed_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-hdpi/ic_plusone_medium_off_client.png b/platform/android/libs/google_play_services/res/drawable-hdpi/ic_plusone_medium_off_client.png
deleted file mode 100644
index 894f1b9f93..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-hdpi/ic_plusone_medium_off_client.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-hdpi/ic_plusone_small_off_client.png b/platform/android/libs/google_play_services/res/drawable-hdpi/ic_plusone_small_off_client.png
deleted file mode 100644
index ac777614e6..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-hdpi/ic_plusone_small_off_client.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-hdpi/ic_plusone_standard_off_client.png b/platform/android/libs/google_play_services/res/drawable-hdpi/ic_plusone_standard_off_client.png
deleted file mode 100644
index f1c32d3b9e..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-hdpi/ic_plusone_standard_off_client.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-hdpi/ic_plusone_tall_off_client.png b/platform/android/libs/google_play_services/res/drawable-hdpi/ic_plusone_tall_off_client.png
deleted file mode 100644
index 08a4670c47..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-hdpi/ic_plusone_tall_off_client.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_disabled_dark.9.png b/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_disabled_dark.9.png
deleted file mode 100644
index dddcbebf12..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_disabled_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_disabled_focus_dark.9.png b/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_disabled_focus_dark.9.png
deleted file mode 100644
index 58b75bd7de..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_disabled_focus_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_disabled_focus_light.9.png b/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_disabled_focus_light.9.png
deleted file mode 100644
index 58b75bd7de..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_disabled_focus_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_disabled_light.9.png b/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_disabled_light.9.png
deleted file mode 100644
index dddcbebf12..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_disabled_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_focus_dark.9.png b/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_focus_dark.9.png
deleted file mode 100644
index 7d9ed7834d..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_focus_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_focus_light.9.png b/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_focus_light.9.png
deleted file mode 100644
index 0ca401d376..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_focus_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_normal_dark.9.png b/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_normal_dark.9.png
deleted file mode 100644
index f2c3f55717..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_normal_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_normal_light.9.png b/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_normal_light.9.png
deleted file mode 100644
index 83b4fc9d6d..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_normal_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_pressed_dark.9.png b/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_pressed_dark.9.png
deleted file mode 100644
index dd74fe8761..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_pressed_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_pressed_light.9.png b/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_pressed_light.9.png
deleted file mode 100644
index b7dc7aac7e..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_icon_pressed_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_disabled_dark.9.png b/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_disabled_dark.9.png
deleted file mode 100644
index efdfe2e616..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_disabled_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_disabled_focus_dark.9.png b/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_disabled_focus_dark.9.png
deleted file mode 100644
index c7650b09e3..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_disabled_focus_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_disabled_focus_light.9.png b/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_disabled_focus_light.9.png
deleted file mode 100644
index c7650b09e3..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_disabled_focus_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_disabled_light.9.png b/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_disabled_light.9.png
deleted file mode 100644
index efdfe2e616..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_disabled_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_focus_dark.9.png b/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_focus_dark.9.png
deleted file mode 100644
index 8c76283e50..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_focus_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_focus_light.9.png b/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_focus_light.9.png
deleted file mode 100644
index abd26bcd41..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_focus_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_normal_dark.9.png b/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_normal_dark.9.png
deleted file mode 100644
index 28181c338b..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_normal_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_normal_light.9.png b/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_normal_light.9.png
deleted file mode 100644
index 34957fad5f..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_normal_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_pressed_dark.9.png b/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_pressed_dark.9.png
deleted file mode 100644
index e923ee9c75..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_pressed_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_pressed_light.9.png b/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_pressed_light.9.png
deleted file mode 100644
index 34cf6bbad5..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-mdpi/common_signin_btn_text_pressed_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-mdpi/ic_plusone_medium_off_client.png b/platform/android/libs/google_play_services/res/drawable-mdpi/ic_plusone_medium_off_client.png
deleted file mode 100644
index d7e5777153..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-mdpi/ic_plusone_medium_off_client.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-mdpi/ic_plusone_small_off_client.png b/platform/android/libs/google_play_services/res/drawable-mdpi/ic_plusone_small_off_client.png
deleted file mode 100644
index af301c2dc9..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-mdpi/ic_plusone_small_off_client.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-mdpi/ic_plusone_standard_off_client.png b/platform/android/libs/google_play_services/res/drawable-mdpi/ic_plusone_standard_off_client.png
deleted file mode 100644
index f43e965fb8..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-mdpi/ic_plusone_standard_off_client.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-mdpi/ic_plusone_tall_off_client.png b/platform/android/libs/google_play_services/res/drawable-mdpi/ic_plusone_tall_off_client.png
deleted file mode 100644
index 0b2b5c9a98..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-mdpi/ic_plusone_tall_off_client.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_disabled_dark.9.png b/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_disabled_dark.9.png
deleted file mode 100644
index 9044a118af..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_disabled_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_disabled_focus_dark.9.png b/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_disabled_focus_dark.9.png
deleted file mode 100644
index e94a49b0ae..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_disabled_focus_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_disabled_focus_light.9.png b/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_disabled_focus_light.9.png
deleted file mode 100644
index e94a49b0ae..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_disabled_focus_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_disabled_light.9.png b/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_disabled_light.9.png
deleted file mode 100644
index 9044a118af..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_disabled_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_focus_dark.9.png b/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_focus_dark.9.png
deleted file mode 100644
index bfe4f04639..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_focus_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_focus_light.9.png b/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_focus_light.9.png
deleted file mode 100644
index 876884fad7..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_focus_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_normal_dark.9.png b/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_normal_dark.9.png
deleted file mode 100644
index b3e6dd5b40..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_normal_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_normal_light.9.png b/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_normal_light.9.png
deleted file mode 100644
index 5a888f28f5..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_normal_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_pressed_dark.9.png b/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_pressed_dark.9.png
deleted file mode 100644
index d0f7b4cbf3..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_pressed_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_pressed_light.9.png b/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_pressed_light.9.png
deleted file mode 100644
index 0db6b06450..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_icon_pressed_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_disabled_dark.9.png b/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_disabled_dark.9.png
deleted file mode 100644
index d182b5e2c3..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_disabled_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_disabled_focus_dark.9.png b/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_disabled_focus_dark.9.png
deleted file mode 100644
index 47e2aeaf32..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_disabled_focus_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_disabled_focus_light.9.png b/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_disabled_focus_light.9.png
deleted file mode 100644
index 47e2aeaf32..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_disabled_focus_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_disabled_light.9.png b/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_disabled_light.9.png
deleted file mode 100644
index d182b5e2c3..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_disabled_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_focus_dark.9.png b/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_focus_dark.9.png
deleted file mode 100644
index 64e9706874..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_focus_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_focus_light.9.png b/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_focus_light.9.png
deleted file mode 100644
index 0fd8cdda14..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_focus_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_normal_dark.9.png b/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_normal_dark.9.png
deleted file mode 100644
index 3427b47681..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_normal_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_normal_light.9.png b/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_normal_light.9.png
deleted file mode 100644
index 31e38c4c12..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_normal_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_pressed_dark.9.png b/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_pressed_dark.9.png
deleted file mode 100644
index e6a7880730..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_pressed_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_pressed_light.9.png b/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_pressed_light.9.png
deleted file mode 100644
index 972962dcfd..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xhdpi/common_signin_btn_text_pressed_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xhdpi/ic_plusone_medium_off_client.png b/platform/android/libs/google_play_services/res/drawable-xhdpi/ic_plusone_medium_off_client.png
deleted file mode 100644
index bb933092be..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xhdpi/ic_plusone_medium_off_client.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xhdpi/ic_plusone_small_off_client.png b/platform/android/libs/google_play_services/res/drawable-xhdpi/ic_plusone_small_off_client.png
deleted file mode 100644
index 6174fcd9b1..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xhdpi/ic_plusone_small_off_client.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xhdpi/ic_plusone_standard_off_client.png b/platform/android/libs/google_play_services/res/drawable-xhdpi/ic_plusone_standard_off_client.png
deleted file mode 100644
index 6a4c298e2d..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xhdpi/ic_plusone_standard_off_client.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xhdpi/ic_plusone_tall_off_client.png b/platform/android/libs/google_play_services/res/drawable-xhdpi/ic_plusone_tall_off_client.png
deleted file mode 100644
index f68e9133bb..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xhdpi/ic_plusone_tall_off_client.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_disabled_dark.9.png b/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_disabled_dark.9.png
deleted file mode 100644
index c97f349fae..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_disabled_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_disabled_focus_dark.9.png b/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_disabled_focus_dark.9.png
deleted file mode 100644
index 34cbff115c..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_disabled_focus_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_disabled_focus_light.9.png b/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_disabled_focus_light.9.png
deleted file mode 100644
index 34cbff115c..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_disabled_focus_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_disabled_light.9.png b/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_disabled_light.9.png
deleted file mode 100644
index c97f349fae..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_disabled_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_focus_dark.9.png b/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_focus_dark.9.png
deleted file mode 100644
index 702c49b74c..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_focus_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_focus_light.9.png b/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_focus_light.9.png
deleted file mode 100644
index 06ad5a5ae7..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_focus_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_normal_dark.9.png b/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_normal_dark.9.png
deleted file mode 100644
index af160fc73b..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_normal_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_normal_light.9.png b/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_normal_light.9.png
deleted file mode 100644
index c647fb4ce8..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_normal_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_pressed_dark.9.png b/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_pressed_dark.9.png
deleted file mode 100644
index fd0a4312b4..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_pressed_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_pressed_light.9.png b/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_pressed_light.9.png
deleted file mode 100644
index f8ce5a6aca..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_icon_pressed_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_disabled_dark.9.png b/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_disabled_dark.9.png
deleted file mode 100644
index b491f629fd..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_disabled_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_disabled_focus_dark.9.png b/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_disabled_focus_dark.9.png
deleted file mode 100644
index 777c8d6408..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_disabled_focus_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_disabled_focus_light.9.png b/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_disabled_focus_light.9.png
deleted file mode 100644
index 777c8d6408..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_disabled_focus_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_disabled_light.9.png b/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_disabled_light.9.png
deleted file mode 100644
index b491f629fd..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_disabled_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_focus_dark.9.png b/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_focus_dark.9.png
deleted file mode 100644
index c8a8f1cbdf..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_focus_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_focus_light.9.png b/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_focus_light.9.png
deleted file mode 100644
index bcd0d0caf4..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_focus_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_normal_dark.9.png b/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_normal_dark.9.png
deleted file mode 100644
index ac75dad52e..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_normal_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_normal_light.9.png b/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_normal_light.9.png
deleted file mode 100644
index c19afad669..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_normal_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_pressed_dark.9.png b/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_pressed_dark.9.png
deleted file mode 100644
index c49044185a..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_pressed_dark.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_pressed_light.9.png b/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_pressed_light.9.png
deleted file mode 100644
index c52be7455e..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xxhdpi/common_signin_btn_text_pressed_light.9.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xxhdpi/ic_plusone_medium_off_client.png b/platform/android/libs/google_play_services/res/drawable-xxhdpi/ic_plusone_medium_off_client.png
deleted file mode 100644
index 4f23739dc3..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xxhdpi/ic_plusone_medium_off_client.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xxhdpi/ic_plusone_small_off_client.png b/platform/android/libs/google_play_services/res/drawable-xxhdpi/ic_plusone_small_off_client.png
deleted file mode 100644
index 8ffa1d72e6..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xxhdpi/ic_plusone_small_off_client.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xxhdpi/ic_plusone_standard_off_client.png b/platform/android/libs/google_play_services/res/drawable-xxhdpi/ic_plusone_standard_off_client.png
deleted file mode 100644
index 4d81cf40cd..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xxhdpi/ic_plusone_standard_off_client.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable-xxhdpi/ic_plusone_tall_off_client.png b/platform/android/libs/google_play_services/res/drawable-xxhdpi/ic_plusone_tall_off_client.png
deleted file mode 100644
index fab5a79b45..0000000000
--- a/platform/android/libs/google_play_services/res/drawable-xxhdpi/ic_plusone_tall_off_client.png
+++ /dev/null
Binary files differ
diff --git a/platform/android/libs/google_play_services/res/drawable/common_signin_btn_icon_dark.xml b/platform/android/libs/google_play_services/res/drawable/common_signin_btn_icon_dark.xml
deleted file mode 100644
index dd1cf679fe..0000000000
--- a/platform/android/libs/google_play_services/res/drawable/common_signin_btn_icon_dark.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item
- android:state_pressed="true"
- android:drawable="@drawable/common_signin_btn_icon_pressed_dark" />
- <item
- android:state_enabled="false"
- android:state_focused="true"
- android:drawable="@drawable/common_signin_btn_icon_disabled_focus_dark" />
- <item
- android:state_focused="true"
- android:drawable="@drawable/common_signin_btn_icon_focus_dark" />
- <item
- android:state_enabled="false"
- android:drawable="@drawable/common_signin_btn_icon_disabled_dark" />
- <item
- android:drawable="@drawable/common_signin_btn_icon_normal_dark" />
-</selector>
diff --git a/platform/android/libs/google_play_services/res/drawable/common_signin_btn_icon_light.xml b/platform/android/libs/google_play_services/res/drawable/common_signin_btn_icon_light.xml
deleted file mode 100644
index abf412bda8..0000000000
--- a/platform/android/libs/google_play_services/res/drawable/common_signin_btn_icon_light.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item
- android:state_pressed="true"
- android:drawable="@drawable/common_signin_btn_icon_pressed_light" />
- <item
- android:state_enabled="false"
- android:state_focused="true"
- android:drawable="@drawable/common_signin_btn_icon_disabled_focus_light" />
- <item
- android:state_focused="true"
- android:drawable="@drawable/common_signin_btn_icon_focus_light" />
- <item
- android:state_enabled="false"
- android:drawable="@drawable/common_signin_btn_icon_disabled_light" />
- <item
- android:drawable="@drawable/common_signin_btn_icon_normal_light" />
-</selector>
diff --git a/platform/android/libs/google_play_services/res/drawable/common_signin_btn_text_dark.xml b/platform/android/libs/google_play_services/res/drawable/common_signin_btn_text_dark.xml
deleted file mode 100644
index 2d92217cdf..0000000000
--- a/platform/android/libs/google_play_services/res/drawable/common_signin_btn_text_dark.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item
- android:state_pressed="true"
- android:drawable="@drawable/common_signin_btn_text_pressed_dark" />
- <item
- android:state_enabled="false"
- android:state_focused="true"
- android:drawable="@drawable/common_signin_btn_text_disabled_focus_dark" />
- <item
- android:state_focused="true"
- android:drawable="@drawable/common_signin_btn_text_focus_dark" />
- <item
- android:state_enabled="false"
- android:drawable="@drawable/common_signin_btn_text_disabled_dark" />
- <item
- android:drawable="@drawable/common_signin_btn_text_normal_dark" />
-</selector>
diff --git a/platform/android/libs/google_play_services/res/drawable/common_signin_btn_text_light.xml b/platform/android/libs/google_play_services/res/drawable/common_signin_btn_text_light.xml
deleted file mode 100644
index 810c02112d..0000000000
--- a/platform/android/libs/google_play_services/res/drawable/common_signin_btn_text_light.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
- <item
- android:state_pressed="true"
- android:drawable="@drawable/common_signin_btn_text_pressed_light" />
- <item
- android:state_enabled="false"
- android:state_focused="true"
- android:drawable="@drawable/common_signin_btn_text_disabled_focus_light" />
- <item
- android:state_focused="true"
- android:drawable="@drawable/common_signin_btn_text_focus_light" />
- <item
- android:state_enabled="false"
- android:drawable="@drawable/common_signin_btn_text_disabled_light" />
- <item
- android:drawable="@drawable/common_signin_btn_text_normal_light" />
-</selector>
diff --git a/platform/android/libs/google_play_services/res/values-af/strings.xml b/platform/android/libs/google_play_services/res/values-af/strings.xml
deleted file mode 100644
index 1b211f5076..0000000000
--- a/platform/android/libs/google_play_services/res/values-af/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Kry Google Play-dienste"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Hierdie program sal nie loop sonder Google Play-dienste nie, wat nie op jou foon is nie."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Hierdie program sal nie loop sonder Google Play-dienste nie, wat nie op jou tablet is nie."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Kry Google Play-dienste"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Aktiveer Google Play-dienste"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Hierdie program sal nie werk tensy jy Google Play-dienste aktiveer nie."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Aktiveer Google Play-dienste"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Dateer Google Play-dienste op"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Hierdie program sal nie loop nie, tensy jy Google Play-dienste opdateer."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Netwerkfout"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"\'n Dataverbinding is nodig om aan Google Play-dienste te koppel."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Ongeldige rekening"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Die gespesifiseerde rekening bestaan nie op hierdie toestel nie. Kies asseblief \'n ander rekening."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Onbekende probleem met Google Play-dienste."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Google Play-dienste"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Google Play-dienste, waarop sommige van jou programme staatmaak, werk nie met jou toestel nie. Kontak asseblief die vervaardiger vir bystand."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Dit lyk of die datum op die toestel verkeerd is. Gaan asseblief die datum op die toestel na."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Dateer op"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Meld aan"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Meld aan met Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"\'n Program het probeer om \'n slegte weergawe van Google Play-dienste te gebruik."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"\'n Program vereis dat Google Play-dienste geaktiveer word."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"\'n Program vereis dat Google Play-dienste geïnstalleer word."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"\'n Program vereis \'n opdatering vir Google Play-dienste."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Google Play-dienstefout"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Versoek deur <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-am/strings.xml b/platform/android/libs/google_play_services/res/values-am/strings.xml
deleted file mode 100644
index 2585210fe0..0000000000
--- a/platform/android/libs/google_play_services/res/values-am/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Google Play አገልግሎቶችን አግኝ"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"ይህ መተግበሪያ ያለ Google Play አገልግሎቶች አይሰራም፣ እነሱ ደግሞ ስልክዎ ላይ የሉም።"</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"ይህ መተግበሪያ ያለ Google Play አገልግሎቶች አይሰራም፣ እነሱ ደግሞ ጡባዊዎ ላይ የሉም።"</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Google Play አገልግሎቶችን አግኝ"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Google Play አገልግሎቶችን አንቃ"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Google Play አገልግሎቶችን እስካላነቁ ድረስ ይህ መተግበሪያ አይሰራም።"</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Google Play አገልግሎቶችን አንቃ"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Google Play አገልግሎቶችን ያዘምኑ"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Google Play አገልግሎቶችን እስኪያዘምኑ ድረስ ይህ መተግበሪያ አይሰራም።"</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"የአውታረ መረብ ስህተት"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"ከGoogle Play አገልግሎቶች ጋር ለመገናኘት የውሂብ ግንኙነት ያስፈልጋል።"</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"ልክ ያልሆነ መለያ"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"የተገለጸው መለያ በዚህ መሣሪያ ላይ የለም። እባክው የተለየ መለያ ይምረጡ።"</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"በGoogle Play አገልግሎቶች ላይ ያልታወቀ ችግር።"</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Google Play አገልግሎቶች"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"የGoogle Play አገልግሎቶች፣ አንዳንድ መተግበሪያዎችዎ በእሱ ላይ ጥገኛ የሆኑት፣ በመሣሪያዎ አይደገፍም። እባክዎ ለእርዳታ አምራቹን ያግኙ።"</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"በመሣሪያው ላይ ያለው ቀን ትክክል አይመስልም። እባክዎ በመሣሪያው ላይ ያለውን ቀን ያረጋግጡ።"</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"ያዘምኑ"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"ግባ"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"በGoogle ይግቡ"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"መተግበሪያው የGoogle Play አገልግሎቶችን መጥፎ ስሪት ለመጠቀም ሞክሯል።"</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"መተግበሪያው Google Play አገልግሎቶች እንዲነቁ ይፈልጋል።"</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"መተግበሪያው Google Play አገልግሎቶች እንዲጫኑ ይፈልጋል።"</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"መተግበሪያው Google Play አገልግሎቶች እንዲዘምን ይፈልጋል።"</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"የGoogle Play አገልግሎቶች ስህተት"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"በ<xliff:g id="APP_NAME">%1$s</xliff:g> የተጠየቀ"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-ar/strings.xml b/platform/android/libs/google_play_services/res/values-ar/strings.xml
deleted file mode 100644
index 9451b37181..0000000000
--- a/platform/android/libs/google_play_services/res/values-ar/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"‏الحصول على خدمات Google Play"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"‏لن يتم تشغيل هذا التطبيق بدون خدمات Google Play، والتي لا تتوفر في هاتفك."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"‏لن يتم تشغيل هذا التطبيق بدون خدمات Google Play، والتي لا تتوفر في جهازك اللوحي."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"‏الحصول على خدمات Google Play"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"‏تمكين خدمات Google Play"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"‏لن يعمل هذا التطبيق ما لم يتم تمكين خدمات Google Play."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"‏تمكين خدمات Google Play"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"‏تحديث خدمات Google Play"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"‏لن يتم تشغيل هذا التطبيق ما لم تحدِّث خدمات Google Play."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"خطأ في الشبكة"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"‏يتطلب الاتصال بخدمات Google Play وجود اتصال بيانات."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"حساب غير صالح"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"الحساب الذي تمّ تحديده غير موجود على الجهاز. يُرجى اختيار حساب آخر."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"‏حدثت مشكلة غير معروفة في خدمات Google Play."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"‏خدمات Google Play"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"‏خدمات Google Play التي تستجيب لها بعض تطبيقاتك لا تعمل على جهازك. يُرجى الاتصال بجهة التصنيع للحصول على المساعدة."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"يبدو أن التاريخ على الجهاز غير صحيح. الرجاء التحقق من التاريخ على الجهاز."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"تحديث"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"تسجيل الدخول"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"‏تسجيل الدخول باستخدام Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"‏يحاول أحد التطبيقات استخدام إصدار غير صالح من خدمات Google Play."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"‏يتطلب أحد التطبيقات تمكين خدمات Google Play."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"‏يتطلب أحد التطبيقات تثبيت خدمات Google Play."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"‏يتطلب أحد التطبيقات تحديث خدمات Google Play."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"‏خطأ في خدمات Google Play"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"تم الطلب عن طريق <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-be/strings.xml b/platform/android/libs/google_play_services/res/values-be/strings.xml
deleted file mode 100644
index 81382d1c0f..0000000000
--- a/platform/android/libs/google_play_services/res/values-be/strings.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Атрымаць службы Google Play"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Гэта прыкладанне не будзе працаваць без службаў Google Play, якіх няма ў вашым тэлефоне."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Гэта прыкладанне не будзе працаваць без службаў Google Play, якіх няма на вашым планшэце."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Атрымаць службы Google Play"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Уключыць службы Google Play"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Гэта прыкладанне не будзе працаваць, пакуль вы не ўключыце службы Google Play."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Уключыць службы Google Play"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Абнаўленне службаў Google Play"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Гэта прыкладанне не будзе працаваць падчас абнаўлення службаў Google Play."</string>
- <!-- no translation found for common_google_play_services_network_error_title (3827284619958211114) -->
- <skip />
- <!-- no translation found for common_google_play_services_network_error_text (9038847255613537209) -->
- <skip />
- <!-- no translation found for common_google_play_services_invalid_account_title (1066672360770936753) -->
- <skip />
- <!-- no translation found for common_google_play_services_invalid_account_text (4983316348021735578) -->
- <skip />
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Невядомая праблема са службамі Google Play."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Службы Google Play"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Службы Google Play, да якiх прывязаны некаторыя прыкладаннi, не падтрымлiваюцца на вашай прыладзе. Па дапамогу звярнiцеся да вытворцы."</string>
- <!-- no translation found for common_google_play_services_unsupported_date_text (4725396522367789365) -->
- <skip />
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Абнавіць"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Увайсцi"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Увайсці ў Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Прыкладанне паспрабавала скарыстацца сапсаванай версіяй службаў Google Play."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Прыкладанне патрабуе ўключэння службаў Google Play."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Прыкладанне патрабуе ўсталявання службаў Google Play."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Прыкладанне патрабуе абнаўлення службаў Google Play."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Памылка службаў Google Play"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Запытана прыкладаннем <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-bg/strings.xml b/platform/android/libs/google_play_services/res/values-bg/strings.xml
deleted file mode 100644
index bb8da3c105..0000000000
--- a/platform/android/libs/google_play_services/res/values-bg/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Изтегляне на услугите за Google Play"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Това приложение няма да се изпълнява без услугите за Google Play, които липсват в телефона ви."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Това приложение няма да се изпълнява без услугите за Google Play, които липсват в таблета ви."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Услуги за Google Play: Изтегл."</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Активиране на услугите за Google Play"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Това приложение няма да работи, освен ако не активирате услугите за Google Play."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Услуги за Google Play: Актив."</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Актуализиране на услугите за Google Play"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Това приложение няма да се изпълнява, освен ако не актуализирате услугите за Google Play."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Грешка в мрежата"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"За свързване с услугите за Google Play се изисква връзка за данни."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Невалиден профил"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Посоченият профил не съществува на това устройство. Моля, изберете друг."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Неизвестен проблем с услугите за Google Play."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Услуги за Google Play"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Услугите за Google Play, на които разчитат някои от приложенията ви, не се поддържат от устройството ви. Моля, свържете се с производителя за помощ."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Изглежда, че датата на устройството е неправилна. Моля, проверете я."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Актуализиране"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Вход"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Вход с Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Приложение опита да ползва неправилна версия на услуг. за Google Play."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Приложение изисква активирането на услугите за Google Play."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Приложение изисква инсталирането на услугите за Google Play."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Приложение изисква актуализирането на услугите за Google Play."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Грешка в услугите за Google Play"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Заявено от <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-ca/strings.xml b/platform/android/libs/google_play_services/res/values-ca/strings.xml
deleted file mode 100644
index 5b63e86af7..0000000000
--- a/platform/android/libs/google_play_services/res/values-ca/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Baixa els serveis de Google Play"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Aquesta aplicació no s\'executarà si el telèfon no té instal·lats els serveis de Google Play."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Aquesta aplicació no funcionarà si la tauleta no té instal·lats els serveis de Google Play."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Baixa els serveis de Google Play"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Activa els serveis de Google Play"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Aquesta aplicació no funcionarà si no actives els serveis de Google Play."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Activa els serveis de Google Play"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Actualitza els serveis de Google Play"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Aquesta aplicació no s\'executarà si no actualitzes els serveis de Google Play."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Error de xarxa"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Es requereix una connexió de dades per connectar amb els serveis de Google Play."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Compte no vàlid"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"El compte especificat no existeix en aquest dispositiu. Tria un compte diferent."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Error desconegut relacionat amb els serveis de Google Play."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Serveis de Google Play"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"El teu dispositiu no és compatible amb els serveis de Google Play, en què es basen les teves aplicacions. Per obtenir assistència, contacta amb el fabricant."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Sembla que la data del dispositiu no és correcta. Comprova-la."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Actualitza"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Inicia sessió"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Inicia sessió amb Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Una aplic. ha intentat utilitzar una versió errònia de serveis de Play."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Una aplicació requereix que s\'activin els serveis de Google Play."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Una aplicació requereix que s\'instal·lin els serveis de Google Play."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Una aplicació requereix que s\'actualitzin els serveis de Google Play."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Error dels serveis de Google Play"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Sol·licitada per <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-cs/strings.xml b/platform/android/libs/google_play_services/res/values-cs/strings.xml
deleted file mode 100644
index 1b5423b039..0000000000
--- a/platform/android/libs/google_play_services/res/values-cs/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Instalovat služby Google Play"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Ke spuštění této aplikace jsou potřeba služby Google Play, které v telefonu nemáte."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Ke spuštění této aplikace jsou potřeba služby Google Play, které v tabletu nemáte."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Instalovat služby Google Play"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Aktivovat služby Google Play"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Ke spuštění této aplikace je třeba aktivovat služby Google Play."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Aktivovat služby Google Play"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Aktualizace služeb Google Play"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Ke spuštění této aplikace je třeba aktualizovat služby Google Play."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Chyba sítě"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Připojení ke službám Google Play vyžaduje datové připojení."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Neplatný účet"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Zadaný účet v tomto zařízení neexistuje. Zvolte prosím jiný účet."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Nastal neznámý problém se službami Google Play."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Služby Google Play"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Některé vaše aplikace vyžadují služby Google Play, které ve vašem zařízení nejsou podporovány. S žádostí o pomoc se prosím obraťte na výrobce."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Datum v zařízení není správně nastaveno. Zkontrolujte prosím datum."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Aktualizovat"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Přihlásit se"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Přihlásit se účtem Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Aplikace se pokusila použít nesprávnou verzi Služeb Google Play."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Aplikace vyžaduje aktivované Služby Google Play."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Aplikace vyžaduje instalaci Služeb Google Play."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Aplikace vyžaduje aktualizaci Služeb Google Play."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Chyba služeb Google Play"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Požadováno aplikací <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-da/strings.xml b/platform/android/libs/google_play_services/res/values-da/strings.xml
deleted file mode 100644
index daa2160d3b..0000000000
--- a/platform/android/libs/google_play_services/res/values-da/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Hent Google Play-tjenester"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Denne app kan ikke køre uden Google Play-tjenester, som mangler på din telefon."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Denne app kan ikke køre uden Google Play-tjenester, som mangler på din tablet."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Hent Google Play-tjenester"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Aktivér Google Play-tjenester"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Denne app virker ikke, medmindre du aktiverer Google Play-tjenester."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Aktivér Google Play-tjenester"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Opdater Google Play-tjenester"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Denne app kan ikke køre, medmindre du opdaterer Google Play-tjenester."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Netværksfejl"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Der kræves en dataforbindelse for at oprette forbindelse til Google Play-tjenester."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Ugyldig konto"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Den angivne konto findes ikke på denne enhed. Vælg en anden konto."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Ukendt problem med Google Play-tjenester."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Google Play-tjenester"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Google Play-tjenester, som nogle af dine applikationer er afhængige af, understøttes ikke af din enhed. Kontakt producenten for at få hjælp."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Datoen på enheden ser ud til at være forkert. Husk at kontrollere datoen på enheden."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Opdater"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Log ind"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Log ind med Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"En applikation forsøgte at bruge en defekt version af Google Play."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"En applikation kræver, at Google Play er aktiveret."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"En applikation kræver, at Google Play er installeret."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"En applikation kræver en opdatering af Google Play."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Fejl i Google Play-tjenester"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Anmodning fra <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-de/strings.xml b/platform/android/libs/google_play_services/res/values-de/strings.xml
deleted file mode 100644
index df8e88e9e2..0000000000
--- a/platform/android/libs/google_play_services/res/values-de/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Google Play-Dienste installieren"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Zur Nutzung dieser App sind Google Play-Dienste erforderlich, die auf Ihrem Telefon nicht installiert sind."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Zur Nutzung dieser App sind Google Play-Dienste erforderlich, die auf Ihrem Tablet nicht installiert sind."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Google Play-Dienste installieren"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Google Play-Dienste aktivieren"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Diese App funktioniert nur, wenn Sie die Google Play-Dienste aktivieren."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Google Play-Dienste aktivieren"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Google Play-Dienste aktualisieren"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Diese App wird nur ausgeführt, wenn Sie die Google Play-Dienste aktualisieren."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Netzwerkfehler"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Um eine Verbindung zu den Google Play-Diensten herzustellen, ist eine Datenverbindung erforderlich."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Ungültiges Konto"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Das angegebene Konto ist auf diesem Gerät nicht vorhanden. Bitte wählen Sie ein anderes Konto aus."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Unbekanntes Problem mit Google Play-Diensten"</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Google Play-Dienste"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Google Play-Dienste, auf denen einige Ihrer Apps basieren, werden von diesem Gerät nicht unterstützt. Wenden Sie sich für weitere Informationen an den Hersteller."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Das Datum auf dem Gerät scheint falsch zu sein. Bitte überprüfen Sie das Datum auf dem Gerät."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Aktualisieren"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Anmelden"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Über Google anmelden"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"App versuchte, defekte Google Play-Dienste-Version zu verwenden"</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"App erfordert aktivierte Google Play-Dienste"</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"App erfordert die Installation von Google Play-Diensten"</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"App erfordert ein Update für Google Play-Dienste"</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Fehler bei Google Play-Diensten"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Angefordert von <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-el/strings.xml b/platform/android/libs/google_play_services/res/values-el/strings.xml
deleted file mode 100644
index 13a5dc5ef3..0000000000
--- a/platform/android/libs/google_play_services/res/values-el/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Λήψη υπηρεσιών Google Play"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Αυτή η εφαρμογή δεν θα εκτελεστεί χωρίς τις υπηρεσίες Google Play, οι οποίες λείπουν από το τηλέφωνό σας."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Αυτή η εφαρμογή δεν θα εκτελεστεί χωρίς τις υπηρεσίες Google Play, οι οποίες λείπουν από το tablet σας."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Λήψη υπηρεσιών Google Play"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Ενεργοποίηση υπηρεσιών Google Play"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Αυτή η εφαρμογή δεν θα λειτουργήσει εάν δεν έχετε ενεργοποιήσει τις υπηρεσίες Google Play."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Ενεργοπ. υπηρεσιών Google Play"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Ενημέρωση υπηρεσιών Google Play"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Αυτή η εφαρμογή θα εκτελεστεί αφού ενημερώσετε τις υπηρεσίες Google Play."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Σφάλμα δικτύου"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Απαιτείται σύνδεση δεδομένων για να συνδεθείτε με τις Υπηρεσίες Google Play."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Μη έγκυρος λογαριασμός"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Ο συγκεκριμένος λογαριασμός δεν υπάρχει σε αυτήν τη συσκευή. Επιλέξτε έναν διαφορετικό λογαριασμό."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Άγνωστο πρόβλημα με τις υπηρεσίες Google Play."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Υπηρεσίες Google Play"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Οι υπηρεσίες Google Play, στις οποίες βασίζονται ορισμένες από τις εφαρμογές σας, δεν υποστηρίζονται στη συσκευή σας. Επικοινωνήστε με τον κατασκευαστή για υποστήριξη."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Η ημερομηνία στη συσκευή φαίνεται λανθασμένη. Ελέγξτε την ημερομηνία στη συσκευή."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Ενημέρωση"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Σύνδεση"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Συνδεθείτε στο Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Απόπειρα χρήσης ακατάλληλης έκδοσης Υπηρεσιών Google Play από εφαρμογή"</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Μια εφαρμογή απαιτεί τις Υπηρεσίες Google Play για ενεργοποίηση."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Μια εφαρμογή απαιτεί την εγκατάσταση των Υπηρεσιών Google Play."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Μια εφαρμογή απαιτεί μια ενημέρωση για τις Υπηρεσίες Google Play."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Σφάλμα υπηρεσιών Google Play"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Υποβλήθηκε αίτημα από την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-en-rGB/strings.xml b/platform/android/libs/google_play_services/res/values-en-rGB/strings.xml
deleted file mode 100644
index 106d390b3e..0000000000
--- a/platform/android/libs/google_play_services/res/values-en-rGB/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Get Google Play services"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"This app won\'t run without Google Play services, which are missing from your phone."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"This app won\'t run without Google Play services, which are missing from your tablet."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Get Google Play services"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Enable Google Play services"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"This app won\'t work unless you enable Google Play services."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Enable Google Play services"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Update Google Play services"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"This app won\'t run unless you update Google Play services."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Network Error"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"A data connection is required to connect to Google Play services."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Invalid Account"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"The specified account does not exist on this device. Please choose a different account."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Unknown issue with Google Play services."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Google Play services"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Google Play services, which some of your applications rely on, is not supported by your device. Please contact the manufacturer for assistance."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"The date on the device appears to be incorrect. Please check the date on the device."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Update"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Sign in"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Sign in with Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"An application attempted to use a bad version of Google Play Services."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"An application requires Google Play Services to be enabled."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"An application requires installation of Google Play Services."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"An application requires an update for Google Play Services."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Google Play services error"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Requested by <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-en-rIN/strings.xml b/platform/android/libs/google_play_services/res/values-en-rIN/strings.xml
deleted file mode 100644
index 106d390b3e..0000000000
--- a/platform/android/libs/google_play_services/res/values-en-rIN/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Get Google Play services"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"This app won\'t run without Google Play services, which are missing from your phone."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"This app won\'t run without Google Play services, which are missing from your tablet."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Get Google Play services"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Enable Google Play services"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"This app won\'t work unless you enable Google Play services."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Enable Google Play services"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Update Google Play services"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"This app won\'t run unless you update Google Play services."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Network Error"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"A data connection is required to connect to Google Play services."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Invalid Account"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"The specified account does not exist on this device. Please choose a different account."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Unknown issue with Google Play services."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Google Play services"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Google Play services, which some of your applications rely on, is not supported by your device. Please contact the manufacturer for assistance."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"The date on the device appears to be incorrect. Please check the date on the device."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Update"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Sign in"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Sign in with Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"An application attempted to use a bad version of Google Play Services."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"An application requires Google Play Services to be enabled."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"An application requires installation of Google Play Services."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"An application requires an update for Google Play Services."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Google Play services error"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Requested by <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-es-rUS/strings.xml b/platform/android/libs/google_play_services/res/values-es-rUS/strings.xml
deleted file mode 100644
index 6be905908c..0000000000
--- a/platform/android/libs/google_play_services/res/values-es-rUS/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Obtener Google Play Services"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Esta aplicación no se ejecutará si no instalasGoogle Play Services en tu dispositivo."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Esta aplicación no se ejecutará si no instalas Google Play Services en tu tablet."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Descargar Google Play Services"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Activar Google Play Services"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Esta aplicación no funcionará si no activas Google Play Services."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Activar Google Play Services"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Actualizar Google Play Services"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Esta aplicación no se ejecutará si no actualizas Google Play Services."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Error de red"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Se necesita una conexión de datos para establecer conexión con Google Play Services."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Cuenta no válida"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"La cuenta especificada no existe en este dispositivo. Elige otra cuenta."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Error desconocido relacionado con Google Play Services"</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Google Play Services"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Google Play Services, del cual dependen algunas de tus aplicaciones, no es compatible con tu dispositivo. Comunícate con el fabricante para obtener ayuda."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Parece que la fecha del dispositivo es incorrecta. ¿Puedes revisarla?"</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Actualizar"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Acceder"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Acceder con Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Una aplic. intentó usar una versión no válida de Google Play Services"</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Una aplicación requiere que se active Google Play Services"</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Una aplicación requiere que se instale Google Play Services"</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Una aplicación requiere que se actualice Google Play Services"</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Error de Google Play Services"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Solicitada por <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-es/strings.xml b/platform/android/libs/google_play_services/res/values-es/strings.xml
deleted file mode 100644
index ed32995cf2..0000000000
--- a/platform/android/libs/google_play_services/res/values-es/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Descargar servicios de Google Play"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Esta aplicación no se ejecutará si tu teléfono no tiene instalados los servicios de Google Play."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Esta aplicación no se ejecutará si tu tablet no tiene instalados los servicios de Google Play."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Descargar servicios de Google Play"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Habilitar servicios de Google Play"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Esta aplicación no funcionará si no habilitas los servicios de Google Play."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Habilitar servicios de Google Play"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Actualizar servicios de Google Play"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Esta aplicación no se ejecutará si no actualizas los servicios de Google Play."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Error de red"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Se necesita una conexión de datos para establecer conexión con los servicios de Google Play."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Cuenta no válida"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"La cuenta especificada no existe en este dispositivo. Selecciona otra cuenta."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Error desconocido relacionado con los servicios de Google Play"</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Servicios de Google Play"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Tu dispositivo no es compatible con los servicios de Google Play, de los cuales dependen tus aplicaciones. Para obtener asistencia, ponte en contacto el fabricante."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Parece que la fecha del dispositivo es incorrecta. Compruébala."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Actualizar"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Iniciar sesión"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Iniciar sesión con Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Una aplicación intentó usar versión incorrecta de servicios de Google Play."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Una aplicación requiere que se habiliten los servicios de Play."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Una aplicación requiere que se instalen los servicios de Google Play."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Una aplicación requiere que se actualicen los servicios de Google Play."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Error de los servicios de Google Play"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Solicitada por <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-et-rEE/strings.xml b/platform/android/libs/google_play_services/res/values-et-rEE/strings.xml
deleted file mode 100644
index 281caff497..0000000000
--- a/platform/android/libs/google_play_services/res/values-et-rEE/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Hankige Google Play teenused"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Selle rakenduse käitamiseks on vaja Google Play teenuseid, mida teie telefonis pole."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Selle rakenduse käitamiseks on vaja Google Play teenuseid, mida teie tahvelarvutis pole."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Hankige Google Play teenused"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Lubage Google Play teenused"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"See rakendus ei tööta, kui te ei luba Google Play teenuseid."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Lubage Google Play teenused"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Värskendage Google Play teenuseid"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Seda rakendust ei saa käitada, kui te ei värskenda Google Play teenuseid."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Võrgu viga"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Google Play teenustega ühenduse loomiseks on vajalik andmesideühendus."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Vale konto"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Määratud kontot pole selles seadmes olemas. Valige muu konto."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Google Play teenuste tundmatu probleem."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Google Play teenused"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Teie seade ei toeta Google Play teenuseid, millele mõni teie rakendustest toetub. Abi saamiseks võtke ühendust tootjaga."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Seadme kuupäev paistab olevat vale. Kontrollige seadme kuupäeva."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Värskenda"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Logi sisse"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Logi sisse Google\'iga"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Rakendus püüdis kasutada Google Play teenuste sobimatut versiooni."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Rakenduse kasutamiseks peavad olema lubatud Google Play teenused."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Rakenduse kasutamiseks peavad olema installitud Google Play teenused."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Rakenduse kasutamiseks tuleb värskendada Google Play teenuseid."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Viga Google Play teenustes"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Päringu esitas: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-fa/strings.xml b/platform/android/libs/google_play_services/res/values-fa/strings.xml
deleted file mode 100644
index 87e10d189c..0000000000
--- a/platform/android/libs/google_play_services/res/values-fa/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"‏دریافت خدمات Google Play"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"‏این برنامه بدون خدمات Google Play اجرا نمی‌شود، این خدمات در تلفن شما وجود ندارد."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"‏این برنامه بدون خدمات Google Play اجرا نمی‌شود، این خدمات در رایانهٔ لوحی شما وجود ندارد."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"‏دریافت خدمات Google Play"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"‏فعال کردن خدمات Google Play"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"‏تا زمانی‌که خدمات Google Play را فعال نکنید این برنامه کار نمی‌کند."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"‏فعال کردن خدمات Google Play"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"‏به‌روزرسانی خدمات Google Play"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"‏تا زمانی‌که خدمات Google Play را به‌روز نکنید این برنامه کار نمی‌کند."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"خطای شبکه"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"‏برای اتصال به خدمات Google Play اتصال داده لازم است."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"حساب نامعتبر"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"حسابی که تعیین کردید در این دستگاه وجود ندارد. لطفاً حساب دیگری را انتخاب کنید."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"‏مشکل نامشخص در خدمات Google Play."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"‏خدمات Google Play"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"‏خدمات Google Play، که برخی از برنامه‌های شما به آن وابسته است، توسط دستگاه شما پشتیبانی نمی‌شود. لطفاً برای دریافت کمک با سازنده تماس بگیرید."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"تاریخ روی دستگاه ظاهراً اشتباه است. لطفاً تاریخ روی دستگاه را بررسی کنید."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"به‌روزرسانی"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"ورود به سیستم"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"‏ورود به سیستم با Google‎"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"‏برنامه‌ای تلاش کرد از نسخه نادرستی از خدمات Google Play استفاده کند."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"‏برنامه‌ای به فعال کردن خدمات Google Play نیاز دارد."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"‏برنامه‌ای به نصب خدمات Google Play نیاز دارد."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"‏برنامه‌ای به به‌روزرسانی خدمات Google Play نیاز دارد."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"‏خطا در خدمات Google Play"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"درخواست توسط <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-fi/strings.xml b/platform/android/libs/google_play_services/res/values-fi/strings.xml
deleted file mode 100644
index 00d3ceb215..0000000000
--- a/platform/android/libs/google_play_services/res/values-fi/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Asenna Google Play -palvelut"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Tämä sovellus ei toimi ilman Google Play -palveluita, jotka puuttuvat puhelimesta."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Tämä sovellus ei toimi ilman Google Play -palveluita, jotka puuttuvat tablet-laitteesta."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Asenna Google Play -palvelut"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Ota Google Play -palvelut käyttöön"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Tämä sovellus ei toimi, ellet ota Google Play -palveluita käyttöön."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Ota Google Play -palv. käyttöön"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Päivitä Google Play -palvelut"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Tämä sovellus ei toimi, ellet päivitä Google Play -palveluita."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Verkkovirhe"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Google Play -palveluiden käyttöön tarvitaan tietoliikenneyhteys."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Tili ei kelpaa"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Kyseistä tiliä ei ole tällä laitteella. Valitse toinen tili."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Tuntematon ongelma käytettäessä Google Play -palveluita."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Google Play -palvelut"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Google Play -palveluita, joita osa sovelluksistasi käyttää, ei tueta laitteellasi. Pyydä ohjeita laitteen valmistajalta."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Laitteen päivämäärä vaikuttaa virheelliseltä. Tarkista laitteen päivämäärä."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Päivitä"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Kirjaudu"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Kirjaudu Google-tiliin"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Sovellus yritti käyttää virheellistä Google Play -palveluiden versiota"</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Ota käyttöön Google Play -palvelut, jotta sovellus toimii."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Asenna Google Play -palvelut, jotta sovellus toimii."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Päivitä Google Play -palvelut, jotta sovellus toimii."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Virhe Google Play -palveluissa"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Pyynnön teki <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-fr-rCA/strings.xml b/platform/android/libs/google_play_services/res/values-fr-rCA/strings.xml
deleted file mode 100644
index e915fe4067..0000000000
--- a/platform/android/libs/google_play_services/res/values-fr-rCA/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Installer les services Google Play"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Cette application ne fonctionnera pas sans les services Google Play, qui ne sont pas installés sur votre téléphone."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Cette application ne fonctionnera pas sans les services Google Play, qui ne sont pas installés sur votre tablette."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Installer les services Google Play"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Activer les services Google Play"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Cette application ne fonctionnera pas tant que vous n\'aurez pas activé les services Google Play."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Activer les services Google Play"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Mettre à jour les services Google Play"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Cette application ne fonctionnera pas tant que vous n\'aurez pas mis à jour les services Google Play."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Erreur réseau"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Vous devez disposer d\'une connexion de données pour utiliser les services Google Play."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Compte erroné"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Le compte indiqué n\'existe pas sur cet appareil. Veuillez sélectionner un autre compte."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Problème inconnu avec les services Google Play."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Services Google Play"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Les services Google Play, dont dépendent certaines de vos applications, ne sont pas compatibles avec votre appareil. Veuillez contacter le fabricant pour obtenir de l\'aide."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"La date sur l\'appareil semble incorrecte. Veuillez la vérifier."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Mettre à jour"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Connexion"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Se connecter via Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Une application requiert une version valide des services Google Play"</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Une application requiert l\'activation des services Google Play"</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Une application requiert l\'installation des services Google Play"</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Une application requiert la mise à jour des services Google Play"</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Erreur liée aux services Google Play"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Demandée par <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-fr/strings.xml b/platform/android/libs/google_play_services/res/values-fr/strings.xml
deleted file mode 100644
index 321b28370b..0000000000
--- a/platform/android/libs/google_play_services/res/values-fr/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Installer les services Google Play"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Cette application ne fonctionnera pas sans les services Google Play, qui ne sont pas installés sur votre téléphone."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Cette application ne fonctionnera pas sans les services Google Play, qui ne sont pas installés sur votre tablette."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Installer services Google Play"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Activer les services Google Play"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Cette application ne fonctionnera pas tant que vous n\'aurez pas activé les services Google Play."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Activer services Google Play"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Mettre à jour les services Google Play"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Cette application ne fonctionnera pas tant que vous n\'aurez pas mis à jour les services Google Play."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Erreur réseau"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Vous devez disposer d\'une connexion de données pour utiliser les services Google Play."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Compte erroné"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Le compte indiqué n\'existe pas sur cet appareil. Veuillez sélectionner un autre compte."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Problème inconnu avec les services Google Play."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Services Google Play"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Les services Google Play, dont dépendent certaines de vos applications, ne sont pas compatibles avec votre appareil. Veuillez contacter le fabricant pour obtenir de l\'aide."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"La date sur l\'appareil semble incorrecte. Veuillez la vérifier."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Mettre à jour"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Connexion"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Se connecter avec Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Une application requiert une version valide des services Google Play"</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Une application requiert l\'activation des services Google Play"</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Une application requiert l\'installation des services Google Play"</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Une application requiert la mise à jour des services Google Play"</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Erreur liée aux services Google Play"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Demandée par <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-hi/strings.xml b/platform/android/libs/google_play_services/res/values-hi/strings.xml
deleted file mode 100644
index b36feb00a7..0000000000
--- a/platform/android/libs/google_play_services/res/values-hi/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Google Play सेवाएं पाएं"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"यह ऐप्स Google Play सेवाओं के बिना नहीं चलेगा, जो आपके फ़ोन में नहीं हैं."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"यह ऐप्स Google Play सेवाओं के बिना नहीं चलेगा, जो आपके टेबलेट में नहीं हैं."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Google Play सेवाएं पाएं"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Google Play सेवाएं सक्षम करें"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"जब तक आप Google Play सेवाएं सक्षम नहीं करते, तब तक यह ऐप्स कार्य नहीं करेगा."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Google Play सेवाएं सक्षम करें"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Google Play सेवाएं से नई जानकारी"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"जब तक आप Google Play सेवाओं से नई जानकारी नहीं लेते हैं, तब तक यह ऐप्स नहीं चलेगा."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"नेटवर्क त्रुटि"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Google Play सेवाओं से कनेक्ट करने के लिए डेटा कनेक्शन की आवश्यकता है."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"अमान्य खाता"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"निर्दिष्ट खाता इस उपकरण पर मौजूद नहीं है. कृपया कोई भिन्न खाता चुनें."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Google Play सेवाओं के साथ अज्ञात समस्या."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Google Play सेवाएं"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Google Play सेवाएं, जिन पर आपके कुछ ऐप्स निर्भर करते हैं, आपके उपकरण द्वारा समर्थित नहीं हैं. कृपया सहायता के लिए निर्माता से संपर्क करें."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"उपकरण का दिनांक गलत प्रतीत हो रहा है. कृपया उपकरण का दिनांक जांचें."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"नई जानकारी पाएं"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"प्रवेश करें"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Google से प्रवेश करें"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"ऐप्स ने Google Play सेवाओं के खराब संस्करण के उपयोग का प्रयास किया."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"ऐप्स के लिए Google Play सेवाओं को सक्षम किए जाने की आवश्यकता है."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"ऐप्स के लिए Google Play सेवाओं के इंस्टॉलेशन की आवश्यकता है."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"ऐप्स के लिए Google Play सेवाओं में Google Play से नई जानकारी की आवश्यकता है."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Google Play सेवाएं त्रुटि"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"<xliff:g id="APP_NAME">%1$s</xliff:g> द्वारा अनुरोधित"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-hr/strings.xml b/platform/android/libs/google_play_services/res/values-hr/strings.xml
deleted file mode 100644
index b7d462d882..0000000000
--- a/platform/android/libs/google_play_services/res/values-hr/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Preuzmi usluge za Google Play"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Ova aplikacija neće funkcionirati bez usluga za Google Play, koje nisu instalirane na vašem telefonu."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Ova aplikacija neće funkcionirati bez usluga za Google Play, koje nisu instalirane na vašem tabletnom računalu."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Preuzmi usluge za Google Play"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Omogući usluge za Google Play"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Ova aplikacija neće raditi ako ne omogućite usluge za Google Play."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Omogući usluge za Google Play"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Ažuriraj usluge za Google Play"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Ova se aplikacija neće pokrenuti ako ne ažurirate usluge za Google Play."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Mrežna pogreška"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Potrebna je podatkovna veza za povezivanje s uslugama Google Play."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Nevažeći račun"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Navedeni račun ne postoji na ovom uređaju. Odaberite neki drugi račun."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Nepoznata poteškoća s uslugama za Google Play."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Usluge za Google Play"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Usluge za Google Play, koje su potrebne za funkcioniranje nekih vaših aplikacija, nisu podržane na vašem uređaju. Pomoć potražite od proizvođača."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Čini se da datum na uređaju nije točan. Provjerite datum na uređaju."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Ažuriranje"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Prijava"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Prijava uslugom Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Aplikacija je pokušala upotrijebiti lošu verziju Usluga za Google Play."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Aplikacija zahtijeva omogućavanje Usluga za Google Play."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Aplikacija zahtijeva instaliranje Usluga za Google Play."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Aplikacija zahtijeva ažuriranje Usluga za Google Play."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Pogreška usluga za Google Play"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Zahtijeva aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-hu/strings.xml b/platform/android/libs/google_play_services/res/values-hu/strings.xml
deleted file mode 100644
index cd15ad328f..0000000000
--- a/platform/android/libs/google_play_services/res/values-hu/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Play Szolgáltatások telepítése"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Az alkalmazás működéséhez a Google Play Szolgáltatások szükségesek, ezek nincsenek telepítve a telefonon."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Az alkalmazás működéséhez a Google Play Szolgáltatások szükségesek, ezek nincsenek telepítve a táblagépen."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Play Szolgáltatások telepítése"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Google Play Szolgáltatások aktiválása"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Az alkalmazás csak akkor fog működni, ha engedélyezi a Google Play Szolgáltatásokat."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Play Szolgáltatások aktiválása"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Play Szolgáltatások frissítése"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Az alkalmazás csak akkor fog működni, ha frissíti a Google Play Szolgáltatásokat."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Hálózati hiba"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"A Google Play Szolgáltatásokhoz történő kapcsolódáshoz adatkapcsolat szükséges."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Érvénytelen fiók"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"A megadott fiók nem létezik ezen az eszközön. Kérjük, válasszon másik fiókot."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Ismeretlen hiba a Google Play Szolgáltatásokban."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Google Play Szolgáltatások"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"A Google Play Szolgáltatásokat, amelyre egyes alkalmazások támaszkodnak, nem támogatja az eszköz. Segítségért forduljon az eszköz gyártójához."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Az eszközön beállított dátum helytelen. Kérjük, ellenőrizze azt."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Frissítés"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Belépés"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Google-bejelentkezés"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Egy alkalmazás a Play Szolgáltatások rossz verzióját akarta használni."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Egy alkalmazás kéri a Google Play Szolgáltatások engedélyezését."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Egy alkalmazás kéri a Google Play Szolgáltatások telepítését."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Egy alkalmazás kéri a Google Play Szolgáltatások frissítését."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Google Play szolgáltatási hiba"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Igénylő: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-hy-rAM/strings.xml b/platform/android/libs/google_play_services/res/values-hy-rAM/strings.xml
deleted file mode 100644
index d89be9bf64..0000000000
--- a/platform/android/libs/google_play_services/res/values-hy-rAM/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Տեղադրեք Google Play ծառայությունները"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Այս հավելվածը չի գործարկվի առանց Google Play ծառայությունների, որոնք բացակայում են ձեր հեռախոսում:"</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Այս հավելվածը չի գործարկվի առանց Google Play ծառայությունների, որոնք բացակայում են ձեր գրասալիկում:"</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Տեղադրել Google Play ծառայությունները"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Միացնել Google Play ծառայությունները"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Այս ծրագիրը չի աշխատի, եթե դուք չմիացնեք Google Play ծառայությունները:"</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Միացնել Google Play ծառայությունները"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Նորացրեք Google Play ծառայությունները"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Այս ծրագիրը չի գործարկվի, եթե դուք չնորացնեք Google Play ծառայությունները:"</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Ցանցի սխալ կա"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Պահանջվում է տվյալների կապ` Google Play ծառայություններին միանալու համար:"</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Հաշիվն անվավեր է"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Նշված հաշիվը գոյություն չունի այս սարքում: Ընտրեք այլ հաշիվ:"</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Անհայտ խնդիր՝ Google Play ծառայություններում:"</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Google Play ծառայություններ"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Google Play ծառայությունները, որոնց ապավինում են ձեր ծրագրերից որոշները, չեն աջակցվում ձեր սարքի կողմից: Խնդրում ենք կապվել արտադրողի հետ օգնության համար:"</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Սարքի ամսաթիվը կարծես սխալ է: Ստուգեք սարքի ամսաթիվը:"</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Նորացնել"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Մուտք գործել"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Մուտք գործեք Google-ով"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Հավելվածը փորձել է կիրառել Google Play ծառայությունների վատ տարբերակը:"</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Հավելվածը պահանջում է միացնել Google Play ծառայությունները:"</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Հավելվածը պահանջում է տեղադրել Google Play ծառայությունները:"</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Հավելվածը պահանջում է թարմացնել Google Play ծառայությունները:"</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Google Play ծառայությունների սխալ"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ի հարցմամբ"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-in/strings.xml b/platform/android/libs/google_play_services/res/values-in/strings.xml
deleted file mode 100644
index 526b84a816..0000000000
--- a/platform/android/libs/google_play_services/res/values-in/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Dapatkan layanan Google Play"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Aplikasi ini tidak akan berjalan tanpa layanan Google Play, yang tidak ada di ponsel Anda."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Aplikasi ini tidak akan berjalan tanpa layanan Google Play, yang tidak ada di tablet Anda."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Dapatkan layanan Google Play"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Aktifkan layanan Google Play"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Aplikasi ini tidak akan bekerja sampai Anda mengaktifkan layanan Google Play."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Aktifkan layanan Google Play"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Perbarui layanan Google Play"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Aplikasi ini tidak akan berjalan sampai Anda memperbarui layanan Google Play."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Kesalahan Jaringan"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Sambungan data diperlukan untuk tersambung ke layanan Google Play."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Akun Tidak Valid"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Akun yang ditentukan tidak ada di perangkat ini. Pilih akun lain."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Masalah tidak diketahui pada layanan Google Play."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Layanan Google Play"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Layanan Google Play, yang diandalkan oleh beberapa aplikasi Anda, tidak didukung oleh perangkat Anda. Hubungi pabrikan untuk mendapatkan bantuan."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Tampaknya tanggal di perangkat salah. Periksa tanggal di perangkat."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Perbarui"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Masuk"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Masuk dengan Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Aplikasi mencoba menggunakan versi Layanan Google Play yang rusak."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Aplikasi membutuhkan Layanan Google Play untuk dapat diaktifkan."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Aplikasi membutuhkan pemasangan Layanan Google Play."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Aplikasi membutuhkan pembaruan untuk Layanan Google Play."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Kesalahan layanan Google Play"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Diminta oleh <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-it/strings.xml b/platform/android/libs/google_play_services/res/values-it/strings.xml
deleted file mode 100644
index f3c9f1fa5c..0000000000
--- a/platform/android/libs/google_play_services/res/values-it/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Installa Google Play Services"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"L\'app non funzionerà senza Google Play Services, non presente sul tuo telefono."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"L\'app non funzionerà senza Google Play Services, non presente sul tuo tablet."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Installa Google Play Services"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Attiva Google Play Services"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"L\'app non funzionerà se non attivi Google Play Services."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Attiva Google Play Services"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Aggiorna Google Play Services"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"L\'app non funzionerà se non aggiorni Google Play Services."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Errore di rete"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"È necessaria una connessione dati per connettersi a Google Play Services."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Account non valido"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"L\'account specificato non esiste su questo dispositivo. Scegli un altro account."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Problema sconosciuto con Google Play Services."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Google Play Services"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"La piattaforma Google Play Services, su cui sono basate alcune delle tue applicazioni, non è supportata dal dispositivo in uso. Per assistenza, contatta il produttore."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"La data sul dispositivo sembra sbagliata. Controllala."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Aggiorna"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Accedi"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Accedi con Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Un\'app ha tentato di usare una versione non valida di Play Services."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Un\'applicazione richiede l\'attivazione di Google Play Services."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Un\'applicazione richiede l\'installazione di Google Play Services."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Un\'applicazione richiede un aggiornamento di Google Play Services."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Errore Google Play Services"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Richiesta da <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-iw/strings.xml b/platform/android/libs/google_play_services/res/values-iw/strings.xml
deleted file mode 100644
index 7474e53506..0000000000
--- a/platform/android/libs/google_play_services/res/values-iw/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"‏קבל את שירותי Google Play"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"‏אפליקציה זו לא תפעל ללא שירותי Google Play, החסרים בטלפון שלך."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"‏אפליקציה זו לא תפעל ללא שירותי Google Play, החסרים בטאבלט שלך."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"‏קבל את שירותי Google Play"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"‏הפעלת שירותי Google Play"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"‏אפליקציה זו לא תעבוד אם לא תפעיל את שירותי Google Play."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"‏הפעל את שירותי Google Play"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"‏עדכון שירותי Google Play"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"‏אפליקציה זו לא תפעל אם לא תעדכן את שירותי Google Play."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"שגיאת רשת."</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"‏דרוש חיבור נתונים כדי להתחבר לשירותי Google Play."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"חשבון לא חוקי"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"החשבון שצוין לא קיים במכשיר זה. בחר חשבון אחר."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"‏בעיה לא ידועה בשירותי Google Play."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"‏שירותי Google Play"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"‏שירותי Google Play, שחלק מהאפליקציות שלך מתבססות עליהם, אינם נתמכים על ידי המכשיר שברשותך. צור קשר עם היצרן לקבלת סיוע."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"נראה שהתאריך במכשיר שגוי. בדוק את התאריך במכשיר."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"עדכן"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"היכנס"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"‏היכנס באמצעות Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"‏יש אפליקציה שניסתה להשתמש בגרסה שגויה של שירותי Google Play."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"‏יש אפליקציה המחייבת הפעלה של שירותי Google Play."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"‏יש אפליקציה המחייבת התקנה של שירותי Google Play."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"‏יש אפליקציה המחייבת עדכון של שירותי Google Play."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"‏שגיאה בשירותי Google Play"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"התבקשה על ידי <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-ja/strings.xml b/platform/android/libs/google_play_services/res/values-ja/strings.xml
deleted file mode 100644
index 0d8b606230..0000000000
--- a/platform/android/libs/google_play_services/res/values-ja/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Play開発者サービスの入手"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"このアプリの実行にはGoogle Play開発者サービスが必要ですが、お使いの携帯端末にはインストールされていません。"</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"このアプリの実行にはGoogle Play開発者サービスが必要ですが、お使いのタブレットにはインストールされていません。"</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Play開発者サービスの入手"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Play開発者サービスの有効化"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"このアプリの実行には、Google Play開発者サービスの有効化が必要です。"</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Play開発者サービスの有効化"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Play開発者サービスの更新"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"このアプリの実行には、Google Play開発者サービスの更新が必要です。"</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"ネットワークエラー"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Google Play開発者サービスに接続するには、データ接続が必要です。"</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"無効なアカウント"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"指定したアカウントはこの端末上に存在しません。別のアカウントを選択してください。"</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Google Play開発者サービスで原因不明の問題が発生しました。"</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Google Play開発者サービス"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"一部のアプリが使用しているGoogle Play開発者サービスは、お使いの端末ではサポートされていません。詳しくは、端末メーカーまでお問い合わせください。"</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"端末上の日付が正しくないようです。端末上の日付をご確認ください。"</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"更新"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"ログイン"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Googleでログイン"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"アプリはGoogle Play開発者サービスの不適切なバージョンを使用しようとしました。"</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"アプリではGoogle Play開発者サービスを有効にする必要があります。"</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"アプリではGoogle Play開発者サービスをインストールする必要があります。"</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"アプリではGoogle Play開発者サービスをアップデートする必要があります。"</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Google Play開発者サービスのエラー"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"<xliff:g id="APP_NAME">%1$s</xliff:g>によるリクエスト"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-ka-rGE/strings.xml b/platform/android/libs/google_play_services/res/values-ka-rGE/strings.xml
deleted file mode 100644
index 8a2c74aa98..0000000000
--- a/platform/android/libs/google_play_services/res/values-ka-rGE/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Google Play სერვისების მიღება"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"ეს აპი ვერ გაეშვება Google Play სერვისების გარეშე, რაც თქვენს ტელეფონზე ვერ იძებნება."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"ეს აპი ვერ გაეშვება Google Play სერვისების გარეშე, რაც თქვენს ტელეფონზე ვერ იძებნება."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Google Play სერვისების მიღება"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Google Play სერვისების გააქტიურება"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"ეს აპი არ იმუშავებს, თუ არ გაააქტიურებთ Google Play სერვისებს."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Google Play სერვისების გააქტიურება"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Google Play სერვისების განახლება"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"ეს აპი ვერ გაეშვება, თუ Google Play სერვისებს არ განაახლებთ."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"ქსელის შეცდომა"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Google Play Services-თან დასაკავშირებლად მონაცემთა გადაცემა აუცილებელია."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"ანგარიში არასწორია"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"მითითებული ანგარიში ამ მოწყობილობაზე არ არსებობს. გთხოვთ, აირჩიოთ სხვა ანგარიში."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Google Play სერვისებთან დაკავშირებით უცნობი შეფერხება წარმოიშვა."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Google Play სერვისები"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Google Play სერვისები, რაც თქვენს ზოგიერთ აპს ჭირდება, თქვენს მოწყობილობაზე მხარდაჭერილი არ არის. გთხოვთ, დაუკავშირდეთ მწარმოებელს დახმარებისათვის."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"როგორც ჩანს, მოწყობილობის თარიღი არასწორია. გთხოვთ, შეამოწმოთ მოწყობილობის თარიღი."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"განახლება"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"შესვლა"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Google-ით შესვლა"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"აპლიკაცია შეეცადა გამოეყენებინა Google Play სერვისების არასწორი ვერსია."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"აპლიკაცია საჭიროებს გააქტიურებულ Google Play Services."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"აპლიკაცია საჭიროებს Google Play Services-ის ინსტალაციას."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"აპლიკაცია საჭიროებს Google Play Services-ის განახლებას."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Google Play სერვისების შეცდომა"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"მომთხოვნი: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-km-rKH/strings.xml b/platform/android/libs/google_play_services/res/values-km-rKH/strings.xml
deleted file mode 100644
index afebf30875..0000000000
--- a/platform/android/libs/google_play_services/res/values-km-rKH/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"ទទួល​សេវាកម្ម​កម្សាន្ត Google"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"កម្មវិធី​នេះ​នឹង​មិន​ដំណើរការ​​ទេ​បើ​គ្មាន​​សេវាកម្ម​កម្សាន្ត​ Google ដែល​ទូរស័ព្ទ​របស់​​អ្នក​មិន​មាន។"</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"​​កម្មវិធី​នេះ​នឹង​មិន​ដំណើរការ​​ទេ​បើ​គ្មាន​​សេវាកម្ម​កម្សាន្ត​ Google ដែល​​កុំព្យូទ័រ​បន្ទះ​របស់​អ្នក​មិន​មាន។"</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"ទទួល​សេវាកម្ម​កម្សាន្ត Google"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"បើក​សេវាកម្ម​កម្សាន្ត Google"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"កម្ម​វិធី​នេះ​នឹង​មិន​ដំណើរការ​ទេ​ លុះត្រាតែ​អ្នក​បើក​សេវាកម្ម​​កម្សាន្ត​ Google ។"</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"បើក​សេវាកម្ម​កម្សាន្ត Google"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"ធ្វើ​បច្ចុប្បន្នភាព​សេវាកម្ម​កម្សាន្ត Google"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"កម្មវិធី​នេះ​នឹង​មិន​ដំណើរការ​ទេ​ លុះត្រាតែ​អ្នក​ធ្វើ​បច្ចុប្បន្នភាព​សេវាកម្ម​កម្សាន្ត Google ។"</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"កំហុស​​បណ្ដាញ"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"បាន​ទាមទារ​ការ​តភ្ជាប់​ទិន្នន័យ ដើម្បី​ភ្ជាប់​សេវាកម្ម​ឃ្លាំង​កម្មវិធី។"</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"គណនី​មិន​ត្រឹមត្រូវ"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"គណនី​ដែល​បាន​បញ្ជាក់​មិន​មាន​នៅ​លើ​ឧបករណ៍​នេះ​ទេ។ សូម​ជ្រើស​គណនី​ផ្សេង​។"</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"មិន​ស្គាល់​បញ្ហា​ជាមួយ​សេវាកម្ម​កម្សាន្ត Google ។"</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"សេវាកម្ម​កម្សាន្ត​ Google"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"សេវាកម្ម​កម្សាន្ត Google អាស្រ័យ​លើ​កម្មវិធី​របស់​អ្នក មិន​ត្រូវ​បាន​គាំទ្រ​ដោយ​ឧបករណ៍​របស់​អ្នក។ សូម​ទាក់ទង​ក្រុមហ៊ុន​ផលិត​សម្រាប់​ជំនួយ។"</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"កាលបរិច្ឆេទ​លើ​ឧបករណ៍​បង្ហាញ​ថា​មិន​ត្រឹមត្រូវ។ សូម​ពិនិត្យ​កាលបរិច្ឆេទ​លើ​ឧបករណ៍។"</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"ធ្វើ​បច្ចុប្បន្នភាព"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"ចូល"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"ចូល​ដោយ​ប្រើ​ Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"កម្មវិធី​​​ព្យាយាម​ប្រើ​កំណែ​មិនល្អ​របស់​សេវា​កម្ម​ឃ្លាំ​កម្មវិធី។"</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"កម្មវិធី​ទាមទារ​​បើក​សេវាកម្ម​ឃ្លាំង​កម្មវិធី។"</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"កម្មវិធី​ទាមទារ​ការ​ដំឡើង​សេវាកម្ម​ឃ្លាំង​កម្មវិធី។"</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"កម្មវិធី​ទាមទារ​​ធ្វើ​បច្ចុប្បន្នភាព​សេវាកម្ម​ឃ្លាំង​កម្មវិធី។"</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"កំហុស​សេវា​កម្ម​កម្សាន្ត Google"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"បាន​ស្នើ​ដោយ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-ko/strings.xml b/platform/android/libs/google_play_services/res/values-ko/strings.xml
deleted file mode 100644
index e37f1fd02a..0000000000
--- a/platform/android/libs/google_play_services/res/values-ko/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Google Play 서비스 설치"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"휴대전화에 Google Play 서비스가 설치되어 있어야 이 앱이 실행됩니다."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"태블릿에 Google Play 서비스가 설치되어 있어야 이 앱이 실행됩니다."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Google Play 서비스 설치"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Google Play 서비스 사용"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Google Play 서비스를 사용하도록 설정해야 이 앱이 작동합니다."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Google Play 서비스 사용"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Google Play 서비스 업데이트"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Google Play 서비스를 업데이트해야만 이 앱이 실행됩니다."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"네트워크 오류"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Google Play 서비스에 연결하려면 데이터 연결이 필요합니다."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"올바르지 않은 계정"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"지정한 계정이 이 기기에 존재하지 않습니다. 다른 계정을 선택하세요."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Google Play 서비스에 알 수 없는 문제가 발생했습니다."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Google Play 서비스"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"일부 사용자 애플리케이션에 필요한 Google Play 서비스가 사용자 기기에서 지원되지 않습니다. 기기 제조업체에 문의하시기 바랍니다."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"기기의 날짜가 잘못된 것 같습니다. 기기의 날짜를 확인해 주세요."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"업데이트"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"로그인"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Google 계정으로 로그인"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"애플리케이션에서 잘못된 버전의 Google Play 서비스를 사용하려고 했습니다."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Google Play 서비스를 사용하도록 설정해야 하는 애플리케이션입니다."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Google Play 서비스를 설치해야 하는 애플리케이션입니다."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Google Play 서비스를 업데이트해야 하는 애플리케이션입니다."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Google Play 서비스 오류"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서 요청"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-lo-rLA/strings.xml b/platform/android/libs/google_play_services/res/values-lo-rLA/strings.xml
deleted file mode 100644
index 32bcb0b92b..0000000000
--- a/platform/android/libs/google_play_services/res/values-lo-rLA/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"ຕິດຕັ້ງບໍລິການ Google Play"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"ແອັບຯນີ້ຈະບໍ່ສາມາດເຮັດວຽກໄດ້ໂດຍທີ່ບໍ່ມີບໍລິການ Google Play ເຊິ່ງຂາດຫາຍໄປໃນໂທລະສັບຂອງທ່ານ."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"ແອັບຯນີ້ຈະບໍ່ສາມາດເຮັດວຽກໄດ້ໂດຍທີ່ບໍ່ມີບໍລິການ Google Play ເຊິ່ງຂາດຫາຍໄປໃນແທັບເລັດຂອງທ່ານ."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"ຕິດຕັ້ງບໍລິການ Google Play"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"ເປີດໃຊ້ບໍລິການ Google Play"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"ແອັບຯນີ້ຈະບໍ່ສາມາດເຮັດວຽກໄດ້ຈົນກວ່າທ່ານຈະເປີດໃຊ້ບໍລິການ Google Play"</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"ເປີດໃຊ້ບໍລິການ Google Play"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"ອັບເດດບໍລິການ Google Play"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"ແອັບຯນີ້ຈະບໍ່ສາມາດເຮັດວຽກໄດ້ຈົນກວ່າທ່ານຈະອັບເດດບໍລິການ Google Play."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"ເຄືອຂ່າຍຜິດພາດ"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"ຕ້ອງໃຊ້ການເຊື່ອມຕໍ່ອິນເຕີເນັດເພື່ອໃຊ້ Google Play Services."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"ບັນຊີບໍ່ຖືກຕ້ອງ"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"ບັນຊີທີ່ເລືອກບໍ່ມີໃນອຸປະກອນນີ້. ກະລຸນາເລືອກບັນຊີອື່ນ."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"ມີປັນຫາທີ່ບໍ່ຄາດຄິດໃນບໍລິການ Google Play."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"ບໍລິການ Google Play"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"ບໍລິການ Google Play ທີ່ບາງແອັບພລິເຄຊັນຂອງທ່ານຕ້ອງອາໄສນັ້ນ ບໍ່ຖືກຮອງຮັບໃນອຸປະກອນຂອງທ່ານ. ກະລຸນາຕິດຕໍ່ຜູ້ຜະລິດສຳລັບການແນະນຳ."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"ວັນທີຂອງອຸປະກອນບໍ່ຖືກຕ້ອງ. ກະລຸນາກວດສອບວັນທີຂອງອຸປະກອນຂອງທ່ານ."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"ອັບເດດ"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"ເຂົ້າສູ່ລະບົບ"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"ເຂົ້າສູ່ລະບົບດ້ວຍ Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"ແອັບພລິເຄຊັນໄດ້ພະຍາຍາມໃຊ້ Google Play Services ເວີຊັນທີ່ບໍ່ສາມາດໃຊ້ໄດ້."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"ແອັບພລິເຄຊັນຕ້ອງການເປີດນຳໃຊ້ Google Play Services."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"ແອັບພລິເຄຊັນຕ້ອງການໃຫ້ຕິດຕັ້ງ Google Play Services."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"ແອັບພລິເຄຊັນຕ້ອງການອັບເດດ Google Play Services."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"ບໍລິການ Google Play ຜິດພາດ"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"ຮ້ອງຂໍໂດຍ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-lt/strings.xml b/platform/android/libs/google_play_services/res/values-lt/strings.xml
deleted file mode 100644
index 73de5fa9aa..0000000000
--- a/platform/android/libs/google_play_services/res/values-lt/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Gauti „Google Play“ paslaugų"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Ši programa neveiks be „Google Play“ paslaugų, kurios neįdiegtos telefone."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Ši programa neveiks be „Google Play“ paslaugų, kurios neįdiegtos planšetiniame kompiuteryje."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Gauti „Google Play“ paslaugų"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Įgalinti „Google Play“ paslaugas"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Ši programa neveiks, jei neįgalinsite „Google Play“ paslaugų."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Įgal. „Google Play“ paslaugas"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Atnaujinti „Google Play“ paslaugas"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Ši programa neveiks, jei neatnaujinsite „Google Play“ paslaugų."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Tinklo klaida"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Norint prisijungti prie „Google Play“ paslaugų reikia duomenų ryšio."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Netinkama paskyra"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Nurodytos paskyros šiame įrenginyje nėra. Pasirinkite kitą paskyrą."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Nežinoma „Google Play“ paslaugų problema."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"„Google Play“ paslaugos"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Jūsų įrenginys nepalaiko „Google Play“ paslaugų, kuriomis remiasi kai kurios programos. Jei reikia pagalbos, susisiekite su gamintoju."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Įrenginyje nurodyta data neteisinga. Patikrinkite įrenginyje nurodytą datą."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Atnaujinti"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Prisij."</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Prisij. naud. „Google“"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Programa bandė naudotis netinkama „Google Play“ paslaugų versija."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Norint naudoti programą būtina įgalinti „Google Play“ paslaugas."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Norint naudoti programą būtina įdiegti „Google Play“ paslaugas."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Norint naudoti programą būtina atnaujinti „Google Play“ paslaugas."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"„Google Play“ paslaugų klaida"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Užklausą pateikė „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-lv/strings.xml b/platform/android/libs/google_play_services/res/values-lv/strings.xml
deleted file mode 100644
index 9e4b6ee6bd..0000000000
--- a/platform/android/libs/google_play_services/res/values-lv/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Google Play pakalpojumu iegūšana"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Lai šī lietotne darbotos, tālrunī ir jāinstalē Google Play pakalpojumi."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Lai šī lietotne darbotos, planšetdatorā ir jāinstalē Google Play pakalpojumi."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Iegūt Google Play pakalpojumus"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Google Play pakalpojumu iespējošana"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Lai šī lietotne darbotos, iespējojiet Google Play pakalpojumus."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Iespējot Google Play pakalpojumus"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Google Play pakalpojumu atjaunināšana"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Lai šī lietotne darbotos, atjauniniet Google Play pakalpojumus."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Tīkla kļūda"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Lai izveidotu savienojumu ar Google Play pakalpojumiem, ir nepieciešams datu savienojums."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Nederīgs konts"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Norādītais konts šajā ierīcē nepastāv. Lūdzu, izvēlieties citu kontu."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Nezināma problēma ar Google Play pakalpojumiem."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Google Play pakalpojumi"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Jūsu ierīce neatbalsta Google Play pakalpojumus, kuri nepieciešami dažu jūsu lietojumprogrammu darbībai. Lūdzu, sazinieties ar ražotāju, lai saņemtu palīdzību."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Šķiet, ka ierīcē ir iestatīts nepareizs datums. Lūdzu, pārbaudiet ierīces datumu."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Atjaunināt"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Pierakst."</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Pierakstīties Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Lietojumpr. mēģināja izmantot nederīgu Google Play pakalp. versiju."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Lai lietojumprogramma darbotos, ir jāiespējo Google Play pakalpojumi."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Lai lietojumprogramma darbotos, ir jāinstalē Google Play pakalpojumi."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Lai lietojumprogramma darbotos, jāatjaunina Google Play pakalpojumi."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Google Play pakalpojumu kļūda"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Pieprasījums no lietotnes <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-mn-rMN/strings.xml b/platform/android/libs/google_play_services/res/values-mn-rMN/strings.xml
deleted file mode 100644
index 1743256a11..0000000000
--- a/platform/android/libs/google_play_services/res/values-mn-rMN/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Google Play үйлчилгээ авах"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Таны утсанд байхгүй байгаа Google Play үйлчилгээг идэвхжүүлж байж энэ апп-г ажиллуулах боломжтой."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Таны таблетэд байхгүй Google Play үйлчилгээг идэвхжүүлж байж энэ апп-г ажиллуулах боломжтой."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Google Play үйлчилгээ авах"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Google Play үйлчилгээг идэвхжүүлэх"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Та Google Play үйлчилгээг идэвхжүүлж байж энэ апп-г ажиллуулах боломжтой."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Google Play үйлчилгээг идэвхжүүлэх"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Google Play үйлчилгээг шинэчлэх"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Та Google Play үйлчилгээг шинэчлэхгүй бол энэ апп ажиллах боломжгүй."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Сүлжээний алдаа"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Google Play үйлчилгээнд холбогдохын тулд дата холболт шаардлагатай."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Буруу акаунт"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Заасан акаунт энэ төхөөрөмж дээр байхгүй байна. Өөр акаунт сонгоно уу."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Google Play үйлчилгээтэй холбоотой тодорхойгүй алдаа."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Google Play үйлчилгээ"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Таны зарим аппликешнүүдийн хамаардаг Google Play үйлчилгээ таны төхөөрөмжид дэмжигдэхгүй байна. Тусламж авахын тулд үйлдвэрлэгчтэй холбоо барина уу."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Төхөөрөмжийн огноо буруу байгаа бололтой. Төхөөрөмжийн огноог шалгана уу."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Шинэчлэх"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Нэвтрэх"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Google-р нэвтрэх:"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Аппликешн Google Play Үйлчилгээний муу хувилбарыг ашиглахыг оролдлоо."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Аппликешн Google Play Үйлчилгээг идэвхжүүлсэн байхыг шаардана."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Аппликешн Google Play Үйлчилгээг суулгахыг шаардана."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Аппликешн Google Play Үйлчилгээг шинэчлэхийг шаардана."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Google Play үйлчилгээний алдаа"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Хүсэлт гаргасан <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-ms-rMY/strings.xml b/platform/android/libs/google_play_services/res/values-ms-rMY/strings.xml
deleted file mode 100644
index 8e8a4b9b8a..0000000000
--- a/platform/android/libs/google_play_services/res/values-ms-rMY/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Dapatkan perkhidmatan Google Play"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Apl ini tidak akan berfungsi tanpa perkhidmatan Google Play dan apl ini tiada pada telefon anda."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Apl ini tidak akan berfungsi tanpa perkhidmatan Google Play dan apl ini tiada pada tablet anda."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Dapatkan perkhidmatan Google Play"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Dayakan perkhidmatan Google Play"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Apl ini tidak akan berfungsi kecuali anda mendayakan perkhidmatan Google Play."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Dayakan perkhidmatan Google Play"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Kemas kini perkhidmatan Google Play"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Apl ini tidak akan berfungsi kecuali anda mengemas kini perkhidmatan Google Play."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Ralat Rangkaian"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Sambungan data diperlukan untuk menyambung ke perkhidmatan Google Play."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Akaun Tidak Sah"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Akaun yang dinyatakan tidak wujud pada peranti ini. Sila pilih akaun yang lain."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Isu tidak diketahui dengan perkhidmatan Google Play."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Perkhidmatan Google Play"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Peranti anda tidak menyokong perkhidmatan Google Play, sedangkan sesetengah aplikasi anda memerlukannya. Sila hubungi pengilang untuk bantuan."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Tarikh pada peranti kelihatan tidak betul. Sila semak tarikh pada peranti."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Kemas kini"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Log masuk"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Log masuk dengan Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Aplikasi cuba menggunakan versi Perkhidmatan Google Play yang rosak."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Perkhidmatan Google Play perlu didayakan untuk menggunakan aplikasi."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Perkhidmatan Google Play perlu dipasang untuk mengguankan aplikasi."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Perkhidmatan Google Play perlu dikemas kini untuk menggunakan aplikasi."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Ralat perkhidmatan Google Play"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Diminta oleh <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-nb/strings.xml b/platform/android/libs/google_play_services/res/values-nb/strings.xml
deleted file mode 100644
index 1e16bbb6d2..0000000000
--- a/platform/android/libs/google_play_services/res/values-nb/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Installer Google Play Tjenester"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Denne appen kan ikke kjøres uten Google Play Tjenester, som ikke er installert på telefonen din."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Denne appen kan ikke kjøres uten Google Play Tjenester, som ikke er installert på nettbrettet ditt."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Installer Google Play Tjenester"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Aktiver Google Play Tjenester"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Denne appen fungerer ikke med mindre du aktiverer Google Play Tjenester."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Aktiver Google Play Tjenester"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Oppdater Google Play Tjenester"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Denne appen kan ikke kjøres før du oppdaterer Google Play Tjenester."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Nettverksfeil"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Du må ha datatilkobling for å koble deg til Google Play-tjenester."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Ugyldig konto"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Den angitte kontoen finnes ikke på enheten. Velg en annen konto."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Det oppsto et ukjent problem med Google Play Tjenester."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Google Play-tjenester"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Google Play Tjenester, som noen av appene er avhengige av, støttes ikke av enheten. Ta kontakt med produsenten for å få hjelp."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Datoen på enheten ser ut til å være feil. Sjekk datoen på enheten."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Oppdater"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Logg på"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Logg inn med Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"En app prøvde å bruke en skadet versjon av Google Play Tjenester."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"En app krever Google Play Tjenester for å aktiveres."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"En app krever at Google Play Tjenester installeres."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"En app krever at Google Play Tjenester oppdateres."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Google Play Tjenester-feil"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Forespurt av <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-nl/strings.xml b/platform/android/libs/google_play_services/res/values-nl/strings.xml
deleted file mode 100644
index f38db5fcdb..0000000000
--- a/platform/android/libs/google_play_services/res/values-nl/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Google Play-services ophalen"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Deze app kan niet worden uitgevoerd zonder Google Play-services die ontbreken op uw telefoon."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Deze app kan niet worden uitgevoerd zonder Google Play-services die ontbreken op uw tablet."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Google Play-services ophalen"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Google Play-services inschakelen"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Deze app werkt niet, tenzij u Google Play-services inschakelt."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Google Play-services inschak."</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Google Play-services bijwerken"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Deze app kan niet worden uitgevoerd, tenzij u Google Play-services bijwerkt."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Netwerkfout"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Er is een gegevensverbinding nodig om verbinding te kunnen maken met Google Play-services."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Ongeldig account"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Het gespecificeerde account bestaat niet op dit apparaat. Kies een ander account."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Onbekend probleem met Google Play-services."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Google Play-services"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Google Play-services, dat vereist is voor een aantal van uw applicaties, wordt niet ondersteund door uw apparaat. Neem contact op met de fabrikant voor ondersteuning."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"De datum op het apparaat lijkt onjuist. Controleer de datum op het apparaat."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Bijwerken"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Inloggen"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Inloggen met Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Onjuiste versie van Google Play-services wordt gebruikt."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Google Play-services moet zijn ingeschakeld voor een applicatie."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Google Play-services moet zijn geïnstalleerd voor een applicatie."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Google Play-services moet worden geüpdatet voor een applicatie."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Fout met Google Play-services"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Aangevraagd door <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-pl/strings.xml b/platform/android/libs/google_play_services/res/values-pl/strings.xml
deleted file mode 100644
index 5eba15ff3a..0000000000
--- a/platform/android/libs/google_play_services/res/values-pl/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Pobierz Usługi Google Play"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Ta aplikacja nie będzie działać bez Usług Google Play, których nie masz na telefonie."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Ta aplikacja nie będzie działać bez Usług Google Play, których nie masz na tablecie."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Pobierz Usługi Google Play"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Włącz Usługi Google Play"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Ta aplikacja nie będzie działać, jeśli nie włączysz Usług Google Play."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Włącz Usługi Google Play"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Aktualizuj Usługi Google Play"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Ta aplikacja nie będzie działać, jeśli nie zaktualizujesz Usług Google Play."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Błąd sieci"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Korzystanie z usług Google Play wymaga połączenia z internetem."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Nieprawidłowe konto"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Podanego konta nie ma na tym urządzeniu. Wybierz inne konto."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Nieznany problem z Usługami Google Play."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Usługi Google Play"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Usługi Google Play, od których zależy działanie niektórych aplikacji, nie są obsługiwane na Twoim urządzeniu. Skontaktuj się z producentem, by uzyskać pomoc."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Data ustawiona na urządzeniu wydaje się nieprawidłowa. Sprawdź datę ustawioną na urządzeniu."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Aktualizuj"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Zaloguj się"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Zaloguj się przez Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Aplikacja próbowała skorzystać z nieprawidłowej wersji Usług Google Play."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Aplikacja wymaga włączenia Usług Google Play."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Aplikacja wymaga zainstalowania Usług Google Play."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Aplikacja wymaga aktualizacji Usług Google Play."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Błąd usług Google Play"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Żądanie z aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-pt-rBR/strings.xml b/platform/android/libs/google_play_services/res/values-pt-rBR/strings.xml
deleted file mode 100644
index 6db462d709..0000000000
--- a/platform/android/libs/google_play_services/res/values-pt-rBR/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Instale o Google Play Services"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Este aplicativo não funciona sem o Google Play Services, que não está instalado em seu telefone."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Este aplicativo não funciona sem o Google Play Services, que não está instalado em seu tablet."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Instalar o Google Play Services"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Ative o Google Play Services"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Este aplicativo só funciona com o Google Play Services ativado."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Ativar o Google Play Services"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Atualize o Google Play Services"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Este aplicativo só funciona com uma versão atualizada do Google Play Services."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Erro na rede"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"É necessária uma conexão de dados para conectar ao Google Play Services."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Conta inválida"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"A conta especificada não existe no dispositivo. Escolha outra conta."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Problema desconhecido com o Google Play Services."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Play Services"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"O Google Play Services, necessário para alguns dos aplicativos, não é compatível com seu dispositivo. Entre em contato com o fabricante para obter assistência."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"A data no dispositivo parece incorreta. Verifique a data no dispositivo."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Atualizar"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Login"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Fazer login com o Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Um aplicativo tentou usar uma versão errada do Google Play Services."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Um aplicativo requer a ativação do Google Play Services."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Um aplicativo requer a instalação do Google Play Services."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Um aplicativo requer a atualização do Google Play Services."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Ocorreu um erro no Google Play Services"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Solicitado por <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-pt-rPT/strings.xml b/platform/android/libs/google_play_services/res/values-pt-rPT/strings.xml
deleted file mode 100644
index 0ceafcb95f..0000000000
--- a/platform/android/libs/google_play_services/res/values-pt-rPT/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Obter serviços do Google Play"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Esta aplicação não será executada sem os serviços do Google Play, que estão em falta no seu telemóvel."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Esta aplicação não será executada sem os serviços do Google Play, que estão em falta no seu tablet."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Obter serviços do Google Play"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Ativar serviços do Google Play"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Esta aplicação não funcionará enquanto não ativar os serviços do Google Play."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Ativar serviços do Google Play"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Atualizar serviços do Google Play"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Esta aplicação não será executada enquanto não atualizar os serviços do Google Play."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Erro de Rede"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"É necessária uma ligação de dados para se ligar aos Serviços do Google Play."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Conta Inválida"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"A conta especificada não existe neste dispositivo. Escolha uma conta diferente."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Problema desconhecido nos serviços do Google Play."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Serviços do Google Play"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Os serviços do Google Play, dos quais dependem algumas das suas aplicações, não são suportados pelo seu dispositivo. Contacte o fabricante para obter assistência."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"A data no dispositivo parece estar incorreta. Verifique a data no dispositivo."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Atualizar"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Inic. ses."</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Inic. sessão com o Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Aplicação tentou utiliz. versão incorreta dos Serviços do Google Play."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Uma aplicação necessita da ativação dos Serviços do Google Play."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Uma aplicação necessita da instalação dos Serviços do Google Play."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Uma aplicação necessita da atualização dos Serviços do Google Play."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Erro dos serviços do Google Play"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Solicitado por <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-pt/strings.xml b/platform/android/libs/google_play_services/res/values-pt/strings.xml
deleted file mode 100644
index 6db462d709..0000000000
--- a/platform/android/libs/google_play_services/res/values-pt/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Instale o Google Play Services"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Este aplicativo não funciona sem o Google Play Services, que não está instalado em seu telefone."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Este aplicativo não funciona sem o Google Play Services, que não está instalado em seu tablet."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Instalar o Google Play Services"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Ative o Google Play Services"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Este aplicativo só funciona com o Google Play Services ativado."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Ativar o Google Play Services"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Atualize o Google Play Services"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Este aplicativo só funciona com uma versão atualizada do Google Play Services."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Erro na rede"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"É necessária uma conexão de dados para conectar ao Google Play Services."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Conta inválida"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"A conta especificada não existe no dispositivo. Escolha outra conta."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Problema desconhecido com o Google Play Services."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Play Services"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"O Google Play Services, necessário para alguns dos aplicativos, não é compatível com seu dispositivo. Entre em contato com o fabricante para obter assistência."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"A data no dispositivo parece incorreta. Verifique a data no dispositivo."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Atualizar"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Login"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Fazer login com o Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Um aplicativo tentou usar uma versão errada do Google Play Services."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Um aplicativo requer a ativação do Google Play Services."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Um aplicativo requer a instalação do Google Play Services."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Um aplicativo requer a atualização do Google Play Services."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Ocorreu um erro no Google Play Services"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Solicitado por <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-ro/strings.xml b/platform/android/libs/google_play_services/res/values-ro/strings.xml
deleted file mode 100644
index eb428964ec..0000000000
--- a/platform/android/libs/google_play_services/res/values-ro/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Descărcaţi Servicii Google Play"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Această aplicaţie nu poate rula fără Servicii Google Play, care lipsesc de pe telefon."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Această aplicaţie nu poate rula fără Servicii Google Play, care lipsesc de pe tabletă."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Obţineţi Servicii Google Play"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Activaţi Servicii Google Play"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Această aplicaţie nu va funcţiona decât dacă activaţi Servicii Google Play."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Activaţi Servicii Google Play"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Actualizaţi Servicii Google Play"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Această aplicaţie nu poate rula decât dacă actualizaţi Servicii Google Play."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Eroare de reţea"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Este necesară o conexiune de date pentru a vă conecta la serviciile Google Play."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Cont nevalid"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Contul menționat nu există pe acest dispozitiv. Alegeți alt cont."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Problemă necunoscută privind Servicii Google Play."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Servicii Google Play"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Gadgetul nu acceptă serviciile Google Play, pe care se bazează unele dintre aplicații. Pentru asistență, contactați producătorul gadgetului."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Data de pe dispozitiv pare să fie incorectă. Verificați data de pe dispozitiv."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Actualizaţi"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Conectați"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Conectați-vă cu Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Aplicația a încercat să utilizeze o vers. Servicii Google Play greșită"</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"O aplicație necesită activarea Serviciilor Google Play."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"O aplicație necesită instalarea Serviciilor Google Play."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"O aplicație necesită o actualizare pentru Servicii Google Play."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Eroare Servicii Google Play"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Solicitată de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-ru/strings.xml b/platform/android/libs/google_play_services/res/values-ru/strings.xml
deleted file mode 100644
index c784aae95c..0000000000
--- a/platform/android/libs/google_play_services/res/values-ru/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Установите Сервисы Google Play"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Для работы этого приложения требуется установить Сервисы Google Play."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Для работы этого приложения требуется установить Сервисы Google Play."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Установить"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Включите Сервисы Google Play"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Для работы этого приложения требуется включить Сервисы Google Play."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Включить"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Обновите Сервисы Google Play"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Для работы этого приложения требуется обновить Сервисы Google Play."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Ошибка сети"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Для работы с Google Play требуется подключение к сети."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Недействительный аккаунт"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Этого аккаунта нет на устройстве. Выберите другой."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Неизвестная ошибка с Сервисами Google Play."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Сервисы Google Play"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Сервисы Google Play, необходимые для работы некоторых приложений, не поддерживаются на вашем устройстве. Обратитесь к производителю."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Проверьте правильность даты, указанной на устройстве."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Обновить"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Войти"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Войти в аккаунт Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Версия сервисов Google Play неисправна"</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Для работы приложения требуется включить сервисы Google Play"</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Для работы приложения требуется установить сервисы Google Play"</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Для работы приложения требуется обновить сервисы Google Play"</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Ошибка сервисов Google Play"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Запрос от приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-sk/strings.xml b/platform/android/libs/google_play_services/res/values-sk/strings.xml
deleted file mode 100644
index 125d87f6da..0000000000
--- a/platform/android/libs/google_play_services/res/values-sk/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Inštalovať služby Google Play"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Na spustenie tejto aplikácie sa vyžadujú služby Google Play, ktoré v telefóne nemáte."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Na spustenie tejto aplikácie sa vyžadujú služby Google Play, ktoré v tablete nemáte."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Inštalovať služby Google Play"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Povoliť služby Google Play"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Táto aplikácia bude fungovať až po povolení služieb Google Play."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Povoliť služby Google Play"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Aktualizovať služby Google Play"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Túto aplikáciu bude možné spustiť až po aktualizácii služieb Google Play."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Chyba siete"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Pripojenie k službám Google Play si vyžaduje dátové pripojenie."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Neplatný účet"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Zadaný účet v tomto zariadení neexistuje. Vyberte iný účet."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Neznámy problém so službami Google Play."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Služby Google Play"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Niektoré vaše aplikácie vyžadujú služby Google Play, ktoré vo vašom zariadení nie sú podporované. Ak potrebujete pomoc, kontaktujte výrobcu."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Dátum nastavený v zariadení sa zdá byť nesprávny. Skontrolujte ho."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Aktualizovať"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Prihlásiť sa"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Prihlásiť sa do účtu Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Aplikácia sa pokúsila použiť nesprávnu verziu služieb Google Play."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Aplikácia vyžaduje povolenie služieb Google Play."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Aplikácia vyžaduje inštaláciu služieb Google Play."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Aplikácia vyžaduje aktualizáciu služieb Google Play."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Chyba služieb Google Play"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Vyžiadané aplikáciou <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-sl/strings.xml b/platform/android/libs/google_play_services/res/values-sl/strings.xml
deleted file mode 100644
index df5821f94c..0000000000
--- a/platform/android/libs/google_play_services/res/values-sl/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Namestite storitve Google Play"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Ta aplikacija ne deluje brez storitev Google Play, ki jih ni v telefonu."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Ta aplikacija ne deluje brez storitev Google Play, ki jih ni v tabličnem računalniku."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Namestite storitve Google Play"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Omogočite storitve Google Play"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Aplikacija ne bo delovala, če ne omogočite storitev Google Play."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Omogočite storitve Google Play"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Posodobite storitve Google Play"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Ta aplikacija ne deluje, če ne posodobite storitev Google Play."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Omrežna napaka"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Za povezavo s storitvami Google Play potrebujete internetno povezavo."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Neveljaven račun"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"V tej napravi ne obstaja navedeni račun. Izberite drugega."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Neznana težava s storitvami Google Play."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Storitve Google Play"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Vaša naprava na podpira storitev Google Play, ki jih potrebujejo nekatere od vaših aplikacij. Za pomoč se obrnite na izdelovalca."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Videti je, da je datum v napravi napačen. Preverite ga."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Posodobi"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Prijava"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Prijavite se v Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Aplikacija je poskusila uporabiti napačno različico Storitev Google Play."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Za delovanje aplikacije morate omogočiti Storitve Google Play."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Za delovanje aplikacije morate namestiti Storitve Google Play."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Za delovanje aplikacije morate posodobiti Storitve Google Play."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Napaka storitev Google Play"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Zahtevala aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-sr/strings.xml b/platform/android/libs/google_play_services/res/values-sr/strings.xml
deleted file mode 100644
index ad0b549547..0000000000
--- a/platform/android/libs/google_play_services/res/values-sr/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Преузимање Google Play услуга"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Ова апликација не може да се покрене без Google Play услуга, које недостају на телефону."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Ова апликација не може да се покрене без Google Play услуга, које недостају на таблету."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Преузми Google Play услуге"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Омогућавање Google Play услуга"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Ова апликација неће функционисати ако не омогућите Google Play услуге."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Омогући Google Play услуге"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Ажурирање Google Play услуга"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Ова апликација не може да се покрене ако не ажурирате Google Play услуге."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Грешка на мрежи"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"За повезивање са Google Play услугама потребна је веза за пренос података."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Неважећи налог"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Наведени налог не постоји на овом уређају. Одаберите други налог."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Непознат проблем са Google Play услугама."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Google Play услуге"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Google Play услуге, које су потребне за функционисање неких од апликација, нису подржане на уређају. Контактирајте произвођача да бисте добили помоћ."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Изгледа да су подаци на уређају нетачни. Проверите датум на уређају."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Ажурирај"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Пријави ме"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Пријави ме преко Google-а"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Апликација је покушала да користи лошу верзију Google Play услуга."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Апликација захтева да Google Play услуге буду омогућене."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Апликација захтева инсталирање Google Play услуга."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Апликација захтева ажурирање Google Play услуга."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Грешка Google Play услуга"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Захтева <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-sv/strings.xml b/platform/android/libs/google_play_services/res/values-sv/strings.xml
deleted file mode 100644
index 6a10395f4b..0000000000
--- a/platform/android/libs/google_play_services/res/values-sv/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Hämta Google Play Tjänster"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Den här appen kan inte köras utan Google Play Tjänster, som saknas på mobilen."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Den här appen kan inte köras utan Google Play Tjänster, som saknas på surfplattan."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Hämta Google Play Tjänster"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Aktivera Google Play Tjänster"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Du måste aktivera Google Play Tjänster för att den här appen ska fungera."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Aktivera Google Play Tjänster"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Uppdatera Google Play Tjänster"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Du måste uppdatera Google Play Tjänster innan du kan köra den här appen."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Nätverksfel"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"En dataanslutning krävs för att ansluta till Google Plays tjänster."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Ogiltigt konto"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Det angivna kontot finns inte på den här enheten. Välj ett annat konto."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Okänt problem med Google Play Tjänster"</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Google Play-tjänster"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Några av dina appar använder Google Play-tjänster som inte stöds av din enhet. Kontakta tillverkaren om du vill ha hjälp."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Datumet på enheten verkar inte vara rätt. Kontrollera datumet på enheten."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Uppdatera"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Logga in"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Logga in med Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"En olämplig version av Google Play Tjänster anropades av en app."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Google Play Tjänster måste aktiveras för en att app ska fungera."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Google Play Tjänster måste installeras för att en app ska fungera."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Google Play Tjänster måste uppdateras för en app ska fungera."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Fel på Google Play Tjänster"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Begärdes av <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-sw/strings.xml b/platform/android/libs/google_play_services/res/values-sw/strings.xml
deleted file mode 100644
index 7f29bf5f2e..0000000000
--- a/platform/android/libs/google_play_services/res/values-sw/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Pata huduma za Google Play"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Programu hii haiwezi kuendeshwa bila huduma za Google Play, ambazo hazipo kwenye simu yako."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Programu hii haiwezi kufanya kazi bila huduma za Google Play, ambazo hazipatikani kwenye kompyuta kibao yako."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Pata huduma za Google Play"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Wezesha huduma za Google Play"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Programu hii haitafanya kazi mpaka utakapowezesha huduma za Google Play."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Wezesha huduma za Google Play"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Sasisha huduma za Google Play"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Programu hii haiwezi kuendeshwa mpaka utakaposasisha huduma za Google Play."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Hitilafu ya Mtandao"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Muunganisho wa data unahitajika ili kuunganisha kwenye huduma za Google Play."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Akaunti Batili"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Akaunti iliyobainishwa haipo kwenye kifaa hiki. Tafadhali chagua akaunti tofauti."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Suala lisilojulikana na huduma za Google Play."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Huduma za Google Play"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Huduma za Google Play, ambazo baadhi ya programu zako zinategemea, si linganifu na kifaa chako. Tafadhali wasiliana na mtengenezaji kwa usaidizi."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Inaeonekana tarehe ya kifaa sio sahihi. Tafadhali angalia tarehe ya kifaa."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Sasisha"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Ingia"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Ingia ukitumia Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Programu ilijaribu kutumia toleo baya la Huduma za Google Play."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Programu inahitaji Huduma za Google Play ili kuwashwa."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Programu inahitaji usakinishaji wa Huduma za Google Play."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Programu inahitaji sasisho la Huduma za Google Play."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Hitilafu kwenye Huduma za Google Play"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Imeombwa na <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-th/strings.xml b/platform/android/libs/google_play_services/res/values-th/strings.xml
deleted file mode 100644
index 6f098fe801..0000000000
--- a/platform/android/libs/google_play_services/res/values-th/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"รับบริการ Google Play"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"แอปพลิเคชันนี้จะไม่ทำงานหากไม่มีบริการ Google Play ซึ่งไม่มีในโทรศัพท์ของคุณ"</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"แอปพลิเคชันนี้จะไม่ทำงานหากไม่มีบริการ Google Play ซึ่งไม่มีในแท็บเล็ตของคุณ"</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"รับบริการ Google Play"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"เปิดใช้งานบริการ Google Play"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"แอปพลิเคชันนี้จะไม่ทำงานจนกว่าคุณจะเปิดใช้งานบริการ Google Play"</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"เปิดใช้งานบริการ Google Play"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"อัปเดตบริการ Google Play"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"แอปพลิเคชันนี้จะไม่ทำงานจนกว่าคุณจะอัปเดตบริการ Google Play"</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"ข้อผิดพลาดของเครือข่าย"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"ต้องมีการเขื่อมต่อข้อมูลเพื่อเชื่อมต่อกับบริการ Google Play"</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"บัญชีไม่ถูกต้อง"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"บัญชีที่ระบุไม่มีอยู่บนอุปกรณ์นี้ โปรดเลือกบัญชีอื่น"</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"ปัญหาที่ไม่รู้จักของบริการ Google Play"</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"บริการ Google Play"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"บริการ Google Play ซึ่งใช้งานในบางแอปพลิเคชัน ไม่ได้รับการสนับสนุนโดยอุปกรณ์ของคุณ โปรดติดต่อผู้ผลิตเพื่อขอรับความช่วยเหลือ"</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"วันที่บนอุปกรณ์ไม่ถูกต้อง โปรดตรวจสอบวันที่บนอุปกรณ์"</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"อัปเดต"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"ลงชื่อใช้"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"ลงชื่อเข้าใช้ด้วย Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"แอปพลิเคชันหนึ่งพยายามใช้เวอร์ชันที่ไม่เหมาะสมของบริการ Google Play"</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"แอปพลิเคชันหนึ่งจำเป็นต้องมีบริการ Google Play เพื่อเปิดใช้งาน"</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"แอปพลิเคชันหนึ่งจำเป็นต้องมีการติดตั้งบริการ Google Play"</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"แอปพลิเคชันหนึ่งจำเป็นต้องมีการอัปเดตสำหรับบริการ Google Play"</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"ข้อผิดพลาดของบริการ Google Play"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"ขอโดย <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-tl/strings.xml b/platform/android/libs/google_play_services/res/values-tl/strings.xml
deleted file mode 100644
index 337f73c0cd..0000000000
--- a/platform/android/libs/google_play_services/res/values-tl/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Kumuha ng mga serbisyo ng Google Play"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Hindi tatakbo ang app na ito nang wala ang mga serbisyo ng Google Play, na wala sa iyong telepono."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Hindi gagana ang app na ito nang wala ang mga serbisyo ng Google Play, na wala sa iyong tablet."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Kumuha ng Google Play services"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Paganahin ang Google Play services"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Hindi gagana ang app na ito maliban kung papaganahin mo ang mga serbisyo ng Google Play."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Enable Google Play services"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"I-update ang mga serbisyo ng Google Play"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Hindi gagana ang app na ito maliban kung i-a-update mo ang mga serbisyo ng Google Play."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"May Error sa Network"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Kailangan ng koneksyon ng data upang makakonekta sa mga serbisyo ng Google Play."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Di-wasto ang Account"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Hindi umiiral ang tinukoy na account sa device na ito. Mangyaring pumili ng ibang account."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"May hindi alam na isyu sa mga serbisyo ng Google Play."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Mga serbisyo ng Google Play"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Ang mga serbisyo ng Google Play, kung saan nakadepende ang ilan sa iyong mga application, ay hindi sinusuportahan ng iyong device. Mangyaring makipag-ugnay sa manufacturer para sa tulong."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Mukhang hindi tama ang petsa sa device. Pakisuri ang petsa sa device."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"I-update"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Sign in"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Mag-sign in sa Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"May app na sumubok ng maling bersyon ng Mga Serbisyo ng Google Play."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Kailangan ng application na na-enable ang Mga Serbisyo ng Google Play."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Kailangan ng application na ma-install ang Serbisyo ng Google Play."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Kailangan ng application na i-update ang Mga Serbisyo ng Google Play."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Error sa mga serbisyo ng Google Play"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Hiniling ng <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-tr/strings.xml b/platform/android/libs/google_play_services/res/values-tr/strings.xml
deleted file mode 100644
index 17e61e5fcb..0000000000
--- a/platform/android/libs/google_play_services/res/values-tr/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Google Play hizmetlerini edinin"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Google Play Hizmetleri telefonunuzda yok ve bu uygulama Google Play Hizmetleri olmadan çalışmaz."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Google Play Hizmetleri tabletinizde yok ve bu uygulama Google Play Hizmetleri olmadan çalışmaz."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Google Play hizmetlerini edin"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Google Play hizmetlerini etkinleştir"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Bu uygulama, Google Play Hizmetleri etkinleştirilmeden çalışmaz"</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Google Play hizmetlerini etkinleştir"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Google Play hizmetlerini güncelle"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Bu uygulama Google Play Hizmetleri güncellenmeden çalışmaz."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Ağ Hatası"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Google Play hizmetlerine bağlanmak için bir veri bağlantısı gerekiyor."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Geçersiz Hesap"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Belirtilen hesap bu cihazda mevcut değil. Lütfen farklı bir hesap seçin."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Google Play hizmetleriyle ilgili bilinmeyen sorun."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Google Play hizmetleri"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Cihazınız, uygulamalarınızdan bazıları için gerekli olan Google Play hizmetlerini desteklemiyor. Lütfen yardım için üreticiyle iletişim kurun."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Cihazdaki tarih doğru görünmüyor. Lütfen cihazda ayarlı tarihi kontrol edin."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Güncelle"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Oturum aç"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Google\'da oturum aç"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Bir uygulama, Google Play Hizmetleri\'nin bozuk bir sürümünü kullanmayı denedi."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Bir uygulama, Google Play Hizmetleri\'nin etkin olmasını gerektiriyor."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Bir uygulama, Google Play Hizmetleri\'nin yüklenmesini gerektiriyor."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Bir uygulama, Google Play Hizmetleri için bir güncelleme gerektiriyor."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Google Play hizmetleri hatası"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"İstekte bulunan: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-uk/strings.xml b/platform/android/libs/google_play_services/res/values-uk/strings.xml
deleted file mode 100644
index d657aea68d..0000000000
--- a/platform/android/libs/google_play_services/res/values-uk/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Установити Google Play Послуги"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Ця програма не запуститься без Google Play Послуг, яких немає у вашому телефоні."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Ця програма не запуститься без Google Play Послуг, яких немає на вашому планшетному ПК."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Установити Google Play Послуги"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Увімкнути Google Play Послуги"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Ця програма не працюватиме, поки ви не ввімкнете Google Play Послуги."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Увімкнути Google Play Послуги"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Оновити Google Play Послуги"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Ця програма не запуститься, поки ви не оновите Google Play Послуги."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Помилка мережі"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Для під’єднання до сервісів Google Play потрібне з’єднання з мережею."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Недійсний обліковий запис"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Указаний обліковий запис не існує на цьому пристрої. Виберіть інший обліковий запис."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Google Play Послуги – невідома проблема."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Сервіси Google Play"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Ваш пристрій не підтримує Сервіси Google Play, від яких залежить робота деяких програм. Зверніться по допомогу до виробника."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Схоже, на пристрої вказано неправильну дату. Перевірте її."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Оновити"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Увійти"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Увійти в обл.запис Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Програма спробувала застосувати хибну версію Сервісів Google Play."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Щоб програма працювала, потрібно ввімкнути Сервіси Google Play."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Щоб програма працювала, потрібно встановити Сервіси Google Play."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Щоб програма працювала, потрібно оновити Сервіси Google Play."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Помилка Сервісів Google Play"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Запит від програми <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-vi/strings.xml b/platform/android/libs/google_play_services/res/values-vi/strings.xml
deleted file mode 100644
index a0434a08ac..0000000000
--- a/platform/android/libs/google_play_services/res/values-vi/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Cài đặt dịch vụ của Google Play"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Ứng dụng này sẽ không chạy nếu không có dịch vụ của Google Play. Điện thoại của bạn bị thiếu dịch vụ này."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Ứng dụng này sẽ không chạy nếu không có dịch vụ của Google Play. Máy tính bảng của bạn bị thiếu dịch vụ này."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Cài đặt dịch vụ của Google Play"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Bật dịch vụ của Google Play"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Ứng dụng này sẽ không hoạt động trừ khi bạn bật dịch vụ của Google Play."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Bật dịch vụ của Google Play"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Cập nhật dịch vụ của Google Play"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Ứng dụng này sẽ không chạy trừ khi bạn cập nhật dịch vụ của Google Play."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Lỗi mạng"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Cần có kết nối dữ liệu để kết nối với các dịch vụ của Google Play."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"Tài khoản không hợp lệ"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"Tài khoản đã chỉ định không tồn tại trên thiết bị này. Vui lòng chọn một tài khoản khác."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Sự cố không xác định với dịch vụ của Google Play."</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Dịch vụ của Google Play"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Các dịch vụ của Google Play mà một số ứng dụng của bạn dựa vào không được thiết bị của bạn hỗ trợ. Vui lòng liên hệ với nhà sản xuất để được hỗ trợ."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Ngày trên thiết bị có vẻ không chính xác. Vui lòng kiểm tra ngày trên thiết bị."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Cập nhật"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Đăng nhập"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Đăng nhập bằng Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Ứng dụng đã cố sử dụng phiên bản không đúng của Dịch vụ của Google Play."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Ứng dụng yêu cầu Dịch vụ của Google Play phải được bật."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Ứng dụng yêu cầu cài đặt Dịch vụ của Google Play."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Ứng dụng yêu cầu cập nhật dành cho Dịch vụ Google Play."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Lỗi dịch vụ của Google Play"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Được yêu cầu bởi <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-zh-rCN/strings.xml b/platform/android/libs/google_play_services/res/values-zh-rCN/strings.xml
deleted file mode 100644
index 4339e3eb01..0000000000
--- a/platform/android/libs/google_play_services/res/values-zh-rCN/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"获取 Google Play 服务"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"您的手机中没有 Google Play 服务,您必须先安装该服务才能运行此应用。"</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"您的平板电脑中没有 Google Play 服务,您必须先安装该服务才能运行此应用。"</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"获取 Google Play 服务"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"启用 Google Play 服务"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"您必须先启用 Google Play 服务才能运行此应用。"</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"启用 Google Play 服务"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"更新 Google Play 服务"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"您必须先更新 Google Play 服务才能运行此应用。"</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"网络错误"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"您必须有数据网络连接才能接入 Google Play 服务。"</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"无效帐户"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"此设备上不存在指定的帐户,请选择其他帐户。"</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Google Play 服务出现未知问题。"</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Google Play 服务"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"您的设备不支持部分应用所依赖的 Google Play 服务。请与设备制造商联系,以寻求帮助。"</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"设备上的日期似乎不正确,请在设备上检查日期。"</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"更新"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"登录"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"使用 Google 帐户登录"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"某个应用尝试使用的 Google Play 服务版本有误。"</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"某个应用要求启用 Google Play 服务。"</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"某个应用要求安装 Google Play 服务。"</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"某个应用要求更新 Google Play 服务。"</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Google Play 服务出错"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"由“<xliff:g id="APP_NAME">%1$s</xliff:g>”发出"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-zh-rHK/strings.xml b/platform/android/libs/google_play_services/res/values-zh-rHK/strings.xml
deleted file mode 100644
index abe6cf1457..0000000000
--- a/platform/android/libs/google_play_services/res/values-zh-rHK/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"取得 Google Play 服務"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"您的手機未安裝 Google Play 服務,安裝後才能執行這個應用程式。"</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"您的平板電腦未安裝 Google Play 服務,安裝後才能執行這個應用程式。"</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"取得 Google Play 服務"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"啟用 Google Play 服務"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"您必須啟用 Google Play 服務,才能執行這個應用程式。"</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"啟用 Google Play 服務"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"更新 Google Play 服務"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"您必須更新 Google Play 服務,才能執行這個應用程式。"</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"網絡錯誤"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"要連接 Google Play 服務,必需數據連線。"</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"無效的帳戶"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"這個裝置上沒有您指定的帳戶,請選擇其他帳戶。"</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Google Play 服務出現不明問題。"</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Google Play 服務"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"您的裝置不支援部分應用程式所需的 Google Play 服務。如需協助,請與您的裝置製造商聯絡。"</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"裝置上的日期看來不正確,請檢查裝置上的日期。"</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"更新"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"登入"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"登入 Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"應用程式嘗試使用錯誤版本的「Google Play 服務」。"</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"必須啟用「Google Play 服務」,才能使用應用程式。"</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"必須安裝「Google Play 服務」,才能使用應用程式。"</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"必須更新「Google Play 服務」,才能使用應用程式。"</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Google Play 服務錯誤"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」提出要求"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-zh-rTW/strings.xml b/platform/android/libs/google_play_services/res/values-zh-rTW/strings.xml
deleted file mode 100644
index a66018ab52..0000000000
--- a/platform/android/libs/google_play_services/res/values-zh-rTW/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"取得 Google Play 服務"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"您的手機並未安裝 Google Play 服務,所以無法執行這個應用程式。"</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"您的平板電腦並未安裝 Google Play 服務,所以無法執行這個應用程式。"</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"取得 Google Play 服務"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"啟用 Google Play 服務"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"您必須啟用 Google Play 服務,這個應用程式才能運作。"</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"啟用 Google Play 服務"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"更新 Google Play 服務"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"您必須更新 Google Play 服務,才能執行這個應用程式。"</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"網路錯誤"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"需要數據連線才能連上 Google Play 服務。"</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"無效的帳戶"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"這個裝置上沒有您所指定的帳戶,請選擇其他帳戶。"</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Google Play 服務發生不明問題。"</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Google Play 服務"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"您的裝置不支援部分應用程式所需的 Google Play 服務。如需協助,請與您的裝置製造商聯絡。"</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"裝置上的日期似乎不正確,請檢查裝置上的日期。"</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"更新"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"登入"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"使用 Google 帳戶登入"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"應用程式嘗試使用的 Google Play 服務版本有誤。"</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"應用程式需要啟用 Google Play 服務。"</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"應用程式需要安裝 Google Play 服務。"</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"應用程式需要更新 Google Play 服務。"</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Google Play 服務錯誤"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"提出要求的應用程式:<xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values-zu/strings.xml b/platform/android/libs/google_play_services/res/values-zu/strings.xml
deleted file mode 100644
index 572d9a52c4..0000000000
--- a/platform/android/libs/google_play_services/res/values-zu/strings.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="common_google_play_services_install_title" msgid="26645092511305524">"Thola amasevisi e-Google Play"</string>
- <string name="common_google_play_services_install_text_phone" msgid="8685301130651051380">"Lolu hlelo lokusebenza ngeke lusebenze ngaphandle kwamasevisi e-Google Play, angekho efonini yakho."</string>
- <string name="common_google_play_services_install_text_tablet" msgid="1589957570365247855">"Lolu hlelo lokusebenza ngeke lusebenze ngaphandle kwamasevisi e-Google Play, angekho kuthebulethi yakho."</string>
- <string name="common_google_play_services_install_button" msgid="8515591849428043265">"Thola amasevisi e-Google Play"</string>
- <string name="common_google_play_services_enable_title" msgid="529078775174559253">"Nika amandla amasevisi e-Google Play"</string>
- <string name="common_google_play_services_enable_text" msgid="7627896071867667758">"Lolu hlelo lokusebenza ngeke lusebenze ngaphandle nje kokuthi unike amandla amasevisi e-Google Play."</string>
- <string name="common_google_play_services_enable_button" msgid="4181637455539816337">"Nika amandla amasevisi e-Google Play"</string>
- <string name="common_google_play_services_update_title" msgid="6006316683626838685">"Buyekeza amasevisi e-Google Play"</string>
- <string name="common_google_play_services_update_text" msgid="448354684997260580">"Lolu hlelo lokusebenza ngeke lusebenze ngaphandle nje kokuthi ubuyekeze amasevisi e-Google Play."</string>
- <string name="common_google_play_services_network_error_title" msgid="3827284619958211114">"Iphutha lenethiwekhi"</string>
- <string name="common_google_play_services_network_error_text" msgid="9038847255613537209">"Kudingeka ukuxhumeka kwedatha ukuze kuxhunyekwe kumasevisi we-Google Play."</string>
- <string name="common_google_play_services_invalid_account_title" msgid="1066672360770936753">"I-Akhawunti engavumelekile"</string>
- <string name="common_google_play_services_invalid_account_text" msgid="4983316348021735578">"I-Akhawunti ecacisiwe ayikho kule divayisi. Sicela ukhethe i-akhawunti ehlukile."</string>
- <string name="common_google_play_services_unknown_issue" msgid="4762332809710093730">"Indaba engaziwa yamasevisi we-Google Play"</string>
- <string name="common_google_play_services_unsupported_title" msgid="6334768798839376943">"Amasevisi we-Google Play"</string>
- <string name="common_google_play_services_unsupported_text" msgid="3542578567569488671">"Amasevisi we-Google Play, okungukuthi ezinye izinhlelo zakho zithembele kuwo, awasekelwe yidivayisi yakho. Sicela uxhumane nomkhiqizi ukuze uthole usizo."</string>
- <string name="common_google_play_services_unsupported_date_text" msgid="4725396522367789365">"Idethi kudivayisi ibonakala ingalungile. Sicela uhlole idethi kudivayisi."</string>
- <string name="common_google_play_services_update_button" msgid="8932944190611227642">"Isibuyekezo"</string>
- <string name="common_signin_button_text" msgid="9071884888741449141">"Ngena ngemvume"</string>
- <string name="common_signin_button_text_long" msgid="2429381841831957106">"Ngena ngemvume nge-Google"</string>
-
- <string name="auth_client_using_bad_version_title" msgid="2534454398764507874">"Uhlelo lokusebenza luzame ukusebenzisa inguqulo embi yamasevisi we-Google Play."</string>
- <string name="auth_client_needs_enabling_title" msgid="3983201110833868073">"Uhlelo lokusebenza ludinga amasevisi we-Google Play ukuze anikwe amandla."</string>
- <string name="auth_client_needs_installation_title" msgid="7999585836145154206">"Uhlelo lokusebenza ludinga ukufakwa kwamasevisi we-Google Play."</string>
- <string name="auth_client_needs_update_title" msgid="6488605506794595966">"Uhlelo lokusebenza ludinga isibuyekezo samasevisi we-Google Play."</string>
- <string name="auth_client_play_services_err_notification_msg" msgid="3635065018897986478">"Iphutha lamasevisi we-Google Play"</string>
- <string name="auth_client_requested_by_msg" msgid="6304135633531965756">"Kucelwe yi-<xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values/ads_attrs.xml b/platform/android/libs/google_play_services/res/values/ads_attrs.xml
deleted file mode 100644
index 4e97a734a6..0000000000
--- a/platform/android/libs/google_play_services/res/values/ads_attrs.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2013 Google Inc. All Rights Reserved. -->
-<resources>
- <declare-styleable name="AdsAttrs">
- <!--
- The size of the ad. It must be one of BANNER, FULL_BANNER, LEADERBOARD,
- MEDIUM_RECTANGLE, SMART_BANNER, WIDE_SKYSCRAPER, or
- &lt;width&gt;x&lt;height&gt;.
- -->
- <attr name="adSize" format="string"/>
-
- <!--
- A comma-separated list of the supported ad sizes. The sizes must be one of
- BANNER, FULL_BANNER, LEADERBOARD, MEDIUM_RECTANGLE, SMART_BANNER,
- WIDE_SKYSCRAPER, or &lt;width&gt;x&lt;height&gt;.
- -->
- <attr name="adSizes" format="string"/>
-
- <!-- The ad unit ID. -->
- <attr name="adUnitId" format="string"/>
- </declare-styleable>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values/colors.xml b/platform/android/libs/google_play_services/res/values/colors.xml
deleted file mode 100644
index 6b2740a509..0000000000
--- a/platform/android/libs/google_play_services/res/values/colors.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<resources>
- <!-- Sign-in Button Colors -->
- <color name="common_signin_btn_dark_text_default">@android:color/white</color>
- <color name="common_signin_btn_dark_text_pressed">@android:color/white</color>
- <color name="common_signin_btn_dark_text_disabled">#FFAAAAAA</color>
- <color name="common_signin_btn_dark_text_focused">@android:color/white</color>
- <color name="common_signin_btn_light_text_default">#FF737373</color>
- <color name="common_signin_btn_light_text_pressed">@android:color/white</color>
- <color name="common_signin_btn_light_text_disabled">#FFAAAAAA</color>
- <color name="common_signin_btn_light_text_focused">#FF737373</color>
- <color name="common_signin_btn_default_background">#FFDD4B39</color>
- <color name="common_action_bar_splitter">#d2d2d2</color>
-</resources> \ No newline at end of file
diff --git a/platform/android/libs/google_play_services/res/values/maps_attrs.xml b/platform/android/libs/google_play_services/res/values/maps_attrs.xml
deleted file mode 100644
index aaf65c529e..0000000000
--- a/platform/android/libs/google_play_services/res/values/maps_attrs.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2012 Google Inc. All Rights Reserved. -->
-<resources>
- <declare-styleable name="MapAttrs">
- <attr name="mapType" format="enum">
- <enum name="none" value="0"/>
- <enum name="normal" value="1"/>
- <enum name="satellite" value="2"/>
- <enum name="terrain" value="3"/>
- <enum name="hybrid" value="4"/>
- </attr>
- <attr name="cameraBearing" format="float"/>
- <attr name="cameraTargetLat" format="float"/>
- <attr name="cameraTargetLng" format="float"/>
- <attr name="cameraTilt" format="float"/>
- <attr name="cameraZoom" format="float"/>
- <attr name="uiCompass" format="boolean"/>
- <attr name="uiRotateGestures" format="boolean"/>
- <attr name="uiScrollGestures" format="boolean"/>
- <attr name="uiTiltGestures" format="boolean"/>
- <attr name="uiZoomControls" format="boolean"/>
- <attr name="uiZoomGestures" format="boolean"/>
- <attr name="useViewLifecycle" format="boolean"/>
- <attr name="zOrderOnTop" format="boolean"/>
- </declare-styleable>
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values/strings.xml b/platform/android/libs/google_play_services/res/values/strings.xml
deleted file mode 100644
index 3e8731e056..0000000000
--- a/platform/android/libs/google_play_services/res/values/strings.xml
+++ /dev/null
@@ -1,111 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
- <!-- Title of confirmation dialog informing user that they need to install
- Google Play services (from Play Store) [CHAR LIMIT=40] -->
- <string name="common_google_play_services_install_title" msgid="7215213145546190223">Get Google Play services</string>
-
- <!-- (For phones) Message in confirmation dialog informing user that
- they need to install Google Play services (from Play Store) [CHAR LIMIT=NONE] -->
- <string name="common_google_play_services_install_text_phone" msgid="2122112764540849864">This app won\'t run without Google Play services, which are missing from your phone.</string>
-
- <!-- (For tablets) Message in confirmation dialog informing user that
- they need to install Google Play services (from Play Store) [CHAR LIMIT=NONE] -->
- <string name="common_google_play_services_install_text_tablet" msgid="7351599665250191022">This app won\'t run without Google Play services, which are missing from your tablet.</string>
-
- <!-- Button in confirmation dialog for installing Google Play services [CHAR LIMIT=40] -->
- <string name="common_google_play_services_install_button" msgid="7153882981874058840">Get Google Play services</string>
-
- <!-- Title of confirmation dialog informing user they need to enable
- Google Play services in application settings [CHAR LIMIT=40] -->
- <string name="common_google_play_services_enable_title" msgid="5122002158466380389">Enable Google Play services</string>
-
- <!-- Message in confirmation dialog informing user they need to enable
- Google Play services in application settings [CHAR LIMIT=NONE] -->
- <string name="common_google_play_services_enable_text" msgid="227660514972886228">This app won\'t work unless you enable Google Play services.</string>
-
- <!-- Button in confirmation dialog to enable Google Play services. Clicking it
- will direct user to application settings of Google Play services where they
- can enable it [CHAR LIMIT=40] -->
- <string name="common_google_play_services_enable_button" msgid="2523291102206661146">Enable Google Play services</string>
-
- <!-- Title of confirmation dialog informing user that they need to update
- Google Play services (from Play Store) [CHAR LIMIT=40] -->
- <string name="common_google_play_services_update_title" msgid="1788179980625863495">Update Google Play services</string>
-
- <!-- Message in confirmation dialog informing user that they need to update
- Google Play services (from Play Store) [CHAR LIMIT=NONE] -->
- <string name="common_google_play_services_update_text" msgid="9053896323427875356">This app won\'t run unless you update Google Play services.</string>
-
- <!-- Title of confirmation dialog informing the user that a network error occurred. [CHAR LIMIT=40] -->
- <string name="common_google_play_services_network_error_title">Network Error</string>
-
- <!-- Message in confirmation dialog informing the user that a network error occurred. [CHAR LIMIT=NONE] -->
- <string name="common_google_play_services_network_error_text">A data connection is required to connect to Google Play services.</string>
-
- <!-- Title of confirmation dialog informing the user that they provided an invalid account. [CHAR LIMIT=40] -->
- <string name="common_google_play_services_invalid_account_title">Invalid Account</string>
-
- <!-- Message in confirmation dialog informing the user that they provided an invalid account. [CHAR LIMIT=NONE] -->
- <string name="common_google_play_services_invalid_account_text">The specified account does not exist on this device. Please choose a different account.</string>
-
- <!-- Message in confirmation dialog informing user there is an unknown issue in Google Play
- services [CHAR LIMIT=NONE] -->
- <string name="common_google_play_services_unknown_issue">Unknown issue with Google Play services.</string>
-
- <!-- Title of confirmation dialog informing user that Google Play services is not supported on their device [CHAR LIMIT=40] -->
- <string name="common_google_play_services_unsupported_title">Google Play services</string>
-
- <!-- Message in confirmation dialog informing user that Google Play services is not supported on their device [CHAR LIMIT=NONE] -->
- <string name="common_google_play_services_unsupported_text">Google Play services, which some of your applications rely on, is not supported by your device. Please contact the manufacturer for assistance.</string>
-
- <!-- Message in confirmation dialog informing user that date on the device is not correct,
- causing certificate checks to fail. [CHAR LIMIT=NONE] -->
- <string name="common_google_play_services_unsupported_date_text">The date on the device appears to be incorrect. Please check the date on the device.</string>
-
- <!-- Button in confirmation dialog for updating Google Play services [CHAR LIMIT=40] -->
- <string name="common_google_play_services_update_button" msgid="6556509956452265614">Update</string>
-
- <!-- Sign-in button text [CHAR LIMIT=15] -->
- <string name="common_signin_button_text">Sign in</string>
-
- <!-- Long form sign-in button text [CHAR LIMIT=30] -->
- <string name="common_signin_button_text_long">Sign in with Google</string>
-
-
- <!-- Auth client code resources (prefix with auth_client --><skip />
- <!-- Title for notification shown when a bad version of GooglePlayServices
- has been installed and needs correction for an application to work.
- [CHAR LIMIT=70] -->
- <string name="auth_client_using_bad_version_title">
- An application attempted to use a bad version of Google Play Services.
- </string>
- <!-- Title for notification shown when GooglePlayServices needs to be
- enabled for a application to work. [CHAR LIMIT=70] -->
- <string name="auth_client_needs_enabling_title">
- An application requires Google Play Services to be enabled.
- </string>
- <!-- Title for notification shown when GooglePlayServices needs to be
- installed for a application to work. [CHAR LIMIT=70] -->
- <string name="auth_client_needs_installation_title">
- An application requires installation of Google Play Services.
- </string>
- <!-- Title for notification shown when GooglePlayServices needs to be
- udpated for a application to work. [CHAR LIMIT=70] -->
- <string name="auth_client_needs_update_title">
- An application requires an update for Google Play Services.
- </string>
-
- <!-- Title for notification shown when GooglePlayServices is unavailable [CHAR LIMIT=42] -->
- <string name="auth_client_play_services_err_notification_msg">Google Play services error</string>
-
- <!-- Requested by string saying which app requested the notification. [CHAR LIMIT=42] -->
- <string name="auth_client_requested_by_msg">Requested by <xliff:g id="app_name">%1$s</xliff:g></string>
- <!-- End Auth client resources --><skip />
-
- <!-- Location client code resources (prefix with location_client) -->
-
- <string name="location_client_powered_by_google">Powered by Google</string>
-
- <!-- End location client resources -->
-</resources>
diff --git a/platform/android/libs/google_play_services/res/values/version.xml b/platform/android/libs/google_play_services/res/values/version.xml
deleted file mode 100644
index 1e7fd4e7ef..0000000000
--- a/platform/android/libs/google_play_services/res/values/version.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <integer name="google_play_services_version">4323000</integer>
-</resources>
diff --git a/platform/android/libs/google_play_services/src/android/UnusedStub.java b/platform/android/libs/google_play_services/src/android/UnusedStub.java
deleted file mode 100644
index d546b0ba9f..0000000000
--- a/platform/android/libs/google_play_services/src/android/UnusedStub.java
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android;
-
-// Stub java file to make inclusion into some IDE's work.
-public final class UnusedStub {
- private UnusedStub() { }
-}
diff --git a/platform/android/libs/play_licensing/AndroidManifest.xml b/platform/android/libs/play_licensing/AndroidManifest.xml
deleted file mode 100644
index c7849130c3..0000000000
--- a/platform/android/libs/play_licensing/AndroidManifest.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2010 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.google.android.vending.licensing"
- android:versionCode="2"
- android:versionName="1.5">
- <!-- Devices >= 3 have version of Android Market that supports licensing. -->
- <uses-sdk android:minSdkVersion="3" android:targetSdkVersion="15" />
- <!-- Required permission to check licensing. -->
- <uses-permission android:name="com.android.vending.CHECK_LICENSE" />
-</manifest>
diff --git a/platform/android/libs/play_licensing/build.xml b/platform/android/libs/play_licensing/build.xml
deleted file mode 100644
index 0e800d6b9b..0000000000
--- a/platform/android/libs/play_licensing/build.xml
+++ /dev/null
@@ -1,92 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project name="play_licensing" default="help">
-
- <!-- The local.properties file is created and updated by the 'android' tool.
- It contains the path to the SDK. It should *NOT* be checked into
- Version Control Systems. -->
- <property file="local.properties" />
-
- <!-- The ant.properties file can be created by you. It is only edited by the
- 'android' tool to add properties to it.
- This is the place to change some Ant specific build properties.
- Here are some properties you may want to change/update:
-
- source.dir
- The name of the source directory. Default is 'src'.
- out.dir
- The name of the output directory. Default is 'bin'.
-
- For other overridable properties, look at the beginning of the rules
- files in the SDK, at tools/ant/build.xml
-
- Properties related to the SDK location or the project target should
- be updated using the 'android' tool with the 'update' action.
-
- This file is an integral part of the build system for your
- application and should be checked into Version Control Systems.
-
- -->
- <property file="ant.properties" />
-
- <!-- if sdk.dir was not set from one of the property file, then
- get it from the ANDROID_HOME env var.
- This must be done before we load project.properties since
- the proguard config can use sdk.dir -->
- <property environment="env" />
- <condition property="sdk.dir" value="${env.ANDROID_HOME}">
- <isset property="env.ANDROID_HOME" />
- </condition>
-
- <!-- The project.properties file is created and updated by the 'android'
- tool, as well as ADT.
-
- This contains project specific properties such as project target, and library
- dependencies. Lower level build properties are stored in ant.properties
- (or in .classpath for Eclipse projects).
-
- This file is an integral part of the build system for your
- application and should be checked into Version Control Systems. -->
- <loadproperties srcFile="project.properties" />
-
- <!-- quick check on sdk.dir -->
- <fail
- message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
- unless="sdk.dir"
- />
-
- <!--
- Import per project custom build rules if present at the root of the project.
- This is the place to put custom intermediary targets such as:
- -pre-build
- -pre-compile
- -post-compile (This is typically used for code obfuscation.
- Compiled code location: ${out.classes.absolute.dir}
- If this is not done in place, override ${out.dex.input.absolute.dir})
- -post-package
- -post-build
- -pre-clean
- -->
- <import file="custom_rules.xml" optional="true" />
-
- <!-- Import the actual build file.
-
- To customize existing targets, there are two options:
- - Customize only one target:
- - copy/paste the target into this file, *before* the
- <import> task.
- - customize it to your needs.
- - Customize the whole content of build.xml
- - copy/paste the content of the rules files (minus the top node)
- into this file, replacing the <import> task.
- - customize to your needs.
-
- ***********************
- ****** IMPORTANT ******
- ***********************
- In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
- in order to avoid having your file be overridden by tools such as "android update project"
- -->
- <!-- version-tag: 1 -->
- <import file="${sdk.dir}/tools/ant/build.xml" />
-
-</project>
diff --git a/platform/android/libs/play_licensing/proguard-project.txt b/platform/android/libs/play_licensing/proguard-project.txt
deleted file mode 100644
index f2fe1559a2..0000000000
--- a/platform/android/libs/play_licensing/proguard-project.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-# To enable ProGuard in your project, edit project.properties
-# to define the proguard.config property as described in that file.
-#
-# Add project specific ProGuard rules here.
-# By default, the flags in this file are appended to flags specified
-# in ${sdk.dir}/tools/proguard/proguard-android.txt
-# You can edit the include path and order by changing the ProGuard
-# include property in project.properties.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
-
-# Add any project specific keep options here:
-
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
-#}
diff --git a/platform/android/libs/play_licensing/project.properties b/platform/android/libs/play_licensing/project.properties
deleted file mode 100644
index f28bc833e1..0000000000
--- a/platform/android/libs/play_licensing/project.properties
+++ /dev/null
@@ -1,12 +0,0 @@
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must be checked in Version Control Systems.
-#
-# To customize properties used by the Ant build system use,
-# "ant.properties", and override values to adapt the script to your
-# project structure.
-
-android.library=true
-# Project target.
-target=android-15
diff --git a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/LicenseChecker.java b/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/LicenseChecker.java
deleted file mode 100644
index 8b53545e61..0000000000
--- a/platform/android/libs/play_licensing/src/com/google/android/vending/licensing/LicenseChecker.java
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.google.android.vending.licensing;
-
-import com.google.android.vending.licensing.util.Base64;
-import com.google.android.vending.licensing.util.Base64DecoderException;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.provider.Settings.Secure;
-import android.util.Log;
-
-import java.security.KeyFactory;
-import java.security.NoSuchAlgorithmException;
-import java.security.PublicKey;
-import java.security.SecureRandom;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.X509EncodedKeySpec;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.Queue;
-import java.util.Set;
-
-/**
- * Client library for Android Market license verifications.
- * <p>
- * The LicenseChecker is configured via a {@link Policy} which contains the
- * logic to determine whether a user should have access to the application. For
- * example, the Policy can define a threshold for allowable number of server or
- * client failures before the library reports the user as not having access.
- * <p>
- * Must also provide the Base64-encoded RSA public key associated with your
- * developer account. The public key is obtainable from the publisher site.
- */
-public class LicenseChecker implements ServiceConnection {
- private static final String TAG = "LicenseChecker";
-
- private static final String KEY_FACTORY_ALGORITHM = "RSA";
-
- // Timeout value (in milliseconds) for calls to service.
- private static final int TIMEOUT_MS = 10 * 1000;
-
- private static final SecureRandom RANDOM = new SecureRandom();
- private static final boolean DEBUG_LICENSE_ERROR = true;
-
- private ILicensingService mService;
-
- private PublicKey mPublicKey;
- private final Context mContext;
- private final Policy mPolicy;
- /**
- * A handler for running tasks on a background thread. We don't want license
- * processing to block the UI thread.
- */
- private Handler mHandler;
- private final String mPackageName;
- private final String mVersionCode;
- private final Set<LicenseValidator> mChecksInProgress = new HashSet<LicenseValidator>();
- private final Queue<LicenseValidator> mPendingChecks = new LinkedList<LicenseValidator>();
-
- /**
- * @param context a Context
- * @param policy implementation of Policy
- * @param encodedPublicKey Base64-encoded RSA public key
- * @throws IllegalArgumentException if encodedPublicKey is invalid
- */
- public LicenseChecker(Context context, Policy policy, String encodedPublicKey) {
- mContext = context;
- mPolicy = policy;
- mPublicKey = generatePublicKey(encodedPublicKey);
- mPackageName = mContext.getPackageName();
- mVersionCode = getVersionCode(context, mPackageName);
- HandlerThread handlerThread = new HandlerThread("background thread");
- handlerThread.start();
- mHandler = new Handler(handlerThread.getLooper());
- }
-
- /**
- * Generates a PublicKey instance from a string containing the
- * Base64-encoded public key.
- *
- * @param encodedPublicKey Base64-encoded public key
- * @throws IllegalArgumentException if encodedPublicKey is invalid
- */
- private static PublicKey generatePublicKey(String encodedPublicKey) {
- try {
- byte[] decodedKey = Base64.decode(encodedPublicKey);
- KeyFactory keyFactory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM);
-
- return keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey));
- } catch (NoSuchAlgorithmException e) {
- // This won't happen in an Android-compatible environment.
- throw new RuntimeException(e);
- } catch (Base64DecoderException e) {
- Log.e(TAG, "Could not decode from Base64.");
- throw new IllegalArgumentException(e);
- } catch (InvalidKeySpecException e) {
- Log.e(TAG, "Invalid key specification.");
- throw new IllegalArgumentException(e);
- }
- }
-
- /**
- * Checks if the user should have access to the app. Binds the service if necessary.
- * <p>
- * NOTE: This call uses a trivially obfuscated string (base64-encoded). For best security,
- * we recommend obfuscating the string that is passed into bindService using another method
- * of your own devising.
- * <p>
- * source string: "com.android.vending.licensing.ILicensingService"
- * <p>
- * @param callback
- */
- public synchronized void checkAccess(LicenseCheckerCallback callback) {
- // If we have a valid recent LICENSED response, we can skip asking
- // Market.
- if (mPolicy.allowAccess()) {
- Log.i(TAG, "Using cached license response");
- callback.allow(Policy.LICENSED);
- } else {
- LicenseValidator validator = new LicenseValidator(mPolicy, new NullDeviceLimiter(),
- callback, generateNonce(), mPackageName, mVersionCode);
-
- if (mService == null) {
- Log.i(TAG, "Binding to licensing service.");
- try {
- boolean bindResult = mContext
- .bindService(
- new Intent(
- new String(
- Base64.decode("Y29tLmFuZHJvaWQudmVuZGluZy5saWNlbnNpbmcuSUxpY2Vuc2luZ1NlcnZpY2U="))),
- this, // ServiceConnection.
- Context.BIND_AUTO_CREATE);
-
- if (bindResult) {
- mPendingChecks.offer(validator);
- } else {
- Log.e(TAG, "Could not bind to service.");
- handleServiceConnectionError(validator);
- }
- } catch (SecurityException e) {
- callback.applicationError(LicenseCheckerCallback.ERROR_MISSING_PERMISSION);
- } catch (Base64DecoderException e) {
- e.printStackTrace();
- }
- } else {
- mPendingChecks.offer(validator);
- runChecks();
- }
- }
- }
-
- private void runChecks() {
- LicenseValidator validator;
- while ((validator = mPendingChecks.poll()) != null) {
- try {
- Log.i(TAG, "Calling checkLicense on service for " + validator.getPackageName());
- mService.checkLicense(
- validator.getNonce(), validator.getPackageName(),
- new ResultListener(validator));
- mChecksInProgress.add(validator);
- } catch (RemoteException e) {
- Log.w(TAG, "RemoteException in checkLicense call.", e);
- handleServiceConnectionError(validator);
- }
- }
- }
-
- private synchronized void finishCheck(LicenseValidator validator) {
- mChecksInProgress.remove(validator);
- if (mChecksInProgress.isEmpty()) {
- cleanupService();
- }
- }
-
- private class ResultListener extends ILicenseResultListener.Stub {
- private final LicenseValidator mValidator;
- private Runnable mOnTimeout;
-
- public ResultListener(LicenseValidator validator) {
- mValidator = validator;
- mOnTimeout = new Runnable() {
- public void run() {
- Log.i(TAG, "Check timed out.");
- handleServiceConnectionError(mValidator);
- finishCheck(mValidator);
- }
- };
- startTimeout();
- }
-
- private static final int ERROR_CONTACTING_SERVER = 0x101;
- private static final int ERROR_INVALID_PACKAGE_NAME = 0x102;
- private static final int ERROR_NON_MATCHING_UID = 0x103;
-
- // Runs in IPC thread pool. Post it to the Handler, so we can guarantee
- // either this or the timeout runs.
- public void verifyLicense(final int responseCode, final String signedData,
- final String signature) {
- mHandler.post(new Runnable() {
- public void run() {
- Log.i(TAG, "Received response.");
- // Make sure it hasn't already timed out.
- if (mChecksInProgress.contains(mValidator)) {
- clearTimeout();
- mValidator.verify(mPublicKey, responseCode, signedData, signature);
- finishCheck(mValidator);
- }
- if (DEBUG_LICENSE_ERROR) {
- boolean logResponse;
- String stringError = null;
- switch (responseCode) {
- case ERROR_CONTACTING_SERVER:
- logResponse = true;
- stringError = "ERROR_CONTACTING_SERVER";
- break;
- case ERROR_INVALID_PACKAGE_NAME:
- logResponse = true;
- stringError = "ERROR_INVALID_PACKAGE_NAME";
- break;
- case ERROR_NON_MATCHING_UID:
- logResponse = true;
- stringError = "ERROR_NON_MATCHING_UID";
- break;
- default:
- logResponse = false;
- }
-
- if (logResponse) {
- String android_id = Secure.getString(mContext.getContentResolver(),
- Secure.ANDROID_ID);
- Date date = new Date();
- Log.d(TAG, "Server Failure: " + stringError);
- Log.d(TAG, "Android ID: " + android_id);
- Log.d(TAG, "Time: " + date.toGMTString());
- }
- }
-
- }
- });
- }
-
- private void startTimeout() {
- Log.i(TAG, "Start monitoring timeout.");
- mHandler.postDelayed(mOnTimeout, TIMEOUT_MS);
- }
-
- private void clearTimeout() {
- Log.i(TAG, "Clearing timeout.");
- mHandler.removeCallbacks(mOnTimeout);
- }
- }
-
- public synchronized void onServiceConnected(ComponentName name, IBinder service) {
- mService = ILicensingService.Stub.asInterface(service);
- runChecks();
- }
-
- public synchronized void onServiceDisconnected(ComponentName name) {
- // Called when the connection with the service has been
- // unexpectedly disconnected. That is, Market crashed.
- // If there are any checks in progress, the timeouts will handle them.
- Log.w(TAG, "Service unexpectedly disconnected.");
- mService = null;
- }
-
- /**
- * Generates policy response for service connection errors, as a result of
- * disconnections or timeouts.
- */
- private synchronized void handleServiceConnectionError(LicenseValidator validator) {
- mPolicy.processServerResponse(Policy.RETRY, null);
-
- if (mPolicy.allowAccess()) {
- validator.getCallback().allow(Policy.RETRY);
- } else {
- validator.getCallback().dontAllow(Policy.RETRY);
- }
- }
-
- /** Unbinds service if necessary and removes reference to it. */
- private void cleanupService() {
- if (mService != null) {
- try {
- mContext.unbindService(this);
- } catch (IllegalArgumentException e) {
- // Somehow we've already been unbound. This is a non-fatal
- // error.
- Log.e(TAG, "Unable to unbind from licensing service (already unbound)");
- }
- mService = null;
- }
- }
-
- /**
- * Inform the library that the context is about to be destroyed, so that any
- * open connections can be cleaned up.
- * <p>
- * Failure to call this method can result in a crash under certain
- * circumstances, such as during screen rotation if an Activity requests the
- * license check or when the user exits the application.
- */
- public synchronized void onDestroy() {
- cleanupService();
- mHandler.getLooper().quit();
- }
-
- /** Generates a nonce (number used once). */
- private int generateNonce() {
- return RANDOM.nextInt();
- }
-
- /**
- * Get version code for the application package name.
- *
- * @param context
- * @param packageName application package name
- * @return the version code or empty string if package not found
- */
- private static String getVersionCode(Context context, String packageName) {
- try {
- return String.valueOf(context.getPackageManager().getPackageInfo(packageName, 0).
- versionCode);
- } catch (NameNotFoundException e) {
- Log.e(TAG, "Package not found. could not get version code.");
- return "";
- }
- }
-}
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 612148418b..03177317af 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -37,6 +37,8 @@
#include "servers/visual/visual_server_wrap_mt.h"
#include "main/main.h"
+#include "file_access_android.h"
+
#include "core/globals.h"
#ifdef ANDROID_NATIVE_ACTIVITY
@@ -89,8 +91,14 @@ void OS_Android::initialize_core() {
if (use_apk_expansion)
FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_RESOURCES);
- else
+ else {
+#ifdef USE_JAVA_FILE_ACCESS
FileAccess::make_default<FileAccessBufferedFA<FileAccessJAndroid> >(FileAccess::ACCESS_RESOURCES);
+#else
+ //FileAccess::make_default<FileAccessBufferedFA<FileAccessAndroid> >(FileAccess::ACCESS_RESOURCES);
+ FileAccess::make_default<FileAccessAndroid>(FileAccess::ACCESS_RESOURCES);
+#endif
+ }
FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_USERDATA);
FileAccess::make_default<FileAccessUnix>(FileAccess::ACCESS_FILESYSTEM);
//FileAccessBufferedFA<FileAccessUnix>::make_default();
@@ -133,6 +141,8 @@ void OS_Android::initialize(const VideoMode& p_desired,int p_video_driver,int p_
}
+ rasterizer->set_force_16_bits_fbo(use_16bits_fbo);
+
visual_server = memnew( VisualServerRaster(rasterizer) );
if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
@@ -292,6 +302,14 @@ void OS_Android::get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen)
p_list->push_back(default_videomode);
}
+void OS_Android::set_keep_screen_on(bool p_enabled) {
+ OS::set_keep_screen_on(p_enabled);
+
+ if (set_keep_screen_on_func) {
+ set_keep_screen_on_func(p_enabled);
+ }
+}
+
Size2 OS_Android::get_window_size() const {
return Vector2(default_videomode.width,default_videomode.height);
@@ -717,7 +735,14 @@ void OS_Android::native_video_stop() {
video_stop_func();
}
-OS_Android::OS_Android(GFXInitFunc p_gfx_init_func,void*p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetDataDirFunc p_get_data_dir_func,GetLocaleFunc p_get_locale_func,GetModelFunc p_get_model_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, SetScreenOrientationFunc p_screen_orient,GetUniqueIDFunc p_get_unique_id,GetSystemDirFunc p_get_sdir_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func,bool p_use_apk_expansion) {
+void OS_Android::set_context_is_16_bits(bool p_is_16) {
+
+ use_16bits_fbo=p_is_16;
+ if (rasterizer)
+ rasterizer->set_force_16_bits_fbo(p_is_16);
+}
+
+OS_Android::OS_Android(GFXInitFunc p_gfx_init_func,void*p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetDataDirFunc p_get_data_dir_func,GetLocaleFunc p_get_locale_func,GetModelFunc p_get_model_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, SetScreenOrientationFunc p_screen_orient,GetUniqueIDFunc p_get_unique_id,GetSystemDirFunc p_get_sdir_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, bool p_use_apk_expansion) {
use_apk_expansion=p_use_apk_expansion;
@@ -750,6 +775,7 @@ OS_Android::OS_Android(GFXInitFunc p_gfx_init_func,void*p_gfx_init_ud, OpenURIFu
hide_virtual_keyboard_func = p_hide_vk;
set_screen_orientation_func=p_screen_orient;
+ set_keep_screen_on_func = p_set_keep_screen_on_func;
use_reload_hooks=false;
}
diff --git a/platform/android/os_android.h b/platform/android/os_android.h
index 7a5a55653f..1ae42e9cc7 100644
--- a/platform/android/os_android.h
+++ b/platform/android/os_android.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -39,6 +39,9 @@
#include "servers/physics_2d/physics_2d_server_sw.h"
#include "servers/physics_2d/physics_2d_server_wrap_mt.h"
#include "servers/visual/rasterizer.h"
+#include "main/input_default.h"
+
+//#ifdef USE_JAVA_FILE_ACCESS
#ifdef ANDROID_NATIVE_ACTIVITY
@@ -70,6 +73,7 @@ typedef void (*VideoPlayFunc)(const String&);
typedef bool (*VideoIsPlayingFunc)();
typedef void (*VideoPauseFunc)();
typedef void (*VideoStopFunc)();
+typedef void (*SetKeepScreenOnFunc)(bool p_enabled);
class OS_Android : public OS_Unix {
public:
@@ -92,6 +96,8 @@ private:
bool use_reload_hooks;
bool use_apk_expansion;
+ bool use_16bits_fbo;
+
Rasterizer *rasterizer;
VisualServer *visual_server;
AudioServerSW *audio_server;
@@ -127,6 +133,7 @@ private:
VideoIsPlayingFunc video_is_playing_func;
VideoPauseFunc video_pause_func;
VideoStopFunc video_stop_func;
+ SetKeepScreenOnFunc set_keep_screen_on_func;
public:
@@ -170,7 +177,9 @@ public:
virtual void set_video_mode(const VideoMode& p_video_mode,int p_screen=0);
virtual VideoMode get_video_mode(int p_screen=0) const;
virtual void get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen=0) const;
-
+
+ virtual void set_keep_screen_on(bool p_enabled);
+
virtual Size2 get_window_size() const;
virtual String get_name();
@@ -197,6 +206,7 @@ public:
void set_display_size(Size2 p_size);
void reload_gfx();
+ void set_context_is_16_bits(bool p_is_16);
void set_need_reload_hooks(bool p_needs_them);
virtual void set_screen_orientation(ScreenOrientation p_orientation);
@@ -222,7 +232,7 @@ public:
virtual void native_video_pause();
virtual void native_video_stop();
- OS_Android(GFXInitFunc p_gfx_init_func,void*p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetDataDirFunc p_get_data_dir_func,GetLocaleFunc p_get_locale_func,GetModelFunc p_get_model_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, SetScreenOrientationFunc p_screen_orient,GetUniqueIDFunc p_get_unique_id,GetSystemDirFunc p_get_sdir_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func,bool p_use_apk_expansion);
+ OS_Android(GFXInitFunc p_gfx_init_func,void*p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetDataDirFunc p_get_data_dir_func,GetLocaleFunc p_get_locale_func,GetModelFunc p_get_model_func, ShowVirtualKeyboardFunc p_show_vk, HideVirtualKeyboardFunc p_hide_vk, SetScreenOrientationFunc p_screen_orient,GetUniqueIDFunc p_get_unique_id,GetSystemDirFunc p_get_sdir_func, VideoPlayFunc p_video_play_func, VideoIsPlayingFunc p_video_is_playing_func, VideoPauseFunc p_video_pause_func, VideoStopFunc p_video_stop_func, SetKeepScreenOnFunc p_set_keep_screen_on_func, bool p_use_apk_expansion);
~OS_Android();
};
diff --git a/platform/android/platform_config.h b/platform/android/platform_config.h
index 1e7d066bb9..143f16c1fa 100644
--- a/platform/android/platform_config.h
+++ b/platform/android/platform_config.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/android/project.properties.template b/platform/android/project.properties.template
deleted file mode 100644
index 00cacd72bc..0000000000
--- a/platform/android/project.properties.template
+++ /dev/null
@@ -1,15 +0,0 @@
-# This file is automatically generated by Android Tools.
-# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
-#
-# This file must be checked in Version Control Systems.
-#
-# To customize properties used by the Ant build system edit
-# "ant.properties", and override values to adapt the script to your
-# project structure.
-#
-# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
-#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
-
-# Project target.
-#android.library=true
-target=android-19
diff --git a/platform/android/thread_jandroid.cpp b/platform/android/thread_jandroid.cpp
index 9314a1c013..1425e23c73 100644
--- a/platform/android/thread_jandroid.cpp
+++ b/platform/android/thread_jandroid.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/android/thread_jandroid.h b/platform/android/thread_jandroid.h
index 051f4e2c3d..c8ad6c8735 100644
--- a/platform/android/thread_jandroid.h
+++ b/platform/android/thread_jandroid.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/bb10/SCsub b/platform/bb10/SCsub
index 24f2b5d242..81f6e726e4 100644
--- a/platform/bb10/SCsub
+++ b/platform/bb10/SCsub
@@ -19,4 +19,3 @@ if env['bb10_lgles_override'] == "yes":
prog = None
prog = env_bps.Program('#bin/godot', bb10_lib)
-
diff --git a/platform/bb10/audio_driver_bb10.cpp b/platform/bb10/audio_driver_bb10.cpp
index 2f1d5a49b3..ef8adaf061 100644
--- a/platform/bb10/audio_driver_bb10.cpp
+++ b/platform/bb10/audio_driver_bb10.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -53,7 +53,6 @@ Error AudioDriverBB10::init(const char* p_name) {
dev_name = (char *) p_name;
}
printf("******** reconnecting to device %s\n", dev_name);
- int card, dev;
int ret = snd_pcm_open_name(&pcm_handle, dev_name, SND_PCM_OPEN_PLAYBACK);
ERR_FAIL_COND_V(ret < 0, FAILED);
pcm_open = true;
diff --git a/platform/bb10/audio_driver_bb10.h b/platform/bb10/audio_driver_bb10.h
index 82774bc533..0148448511 100644
--- a/platform/bb10/audio_driver_bb10.h
+++ b/platform/bb10/audio_driver_bb10.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/bb10/bbutil.h b/platform/bb10/bbutil.h
index 8df513cb7d..bc422cd9b9 100644
--- a/platform/bb10/bbutil.h
+++ b/platform/bb10/bbutil.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/bb10/export/export.cpp b/platform/bb10/export/export.cpp
index a807e184ce..2acd920f31 100644
--- a/platform/bb10/export/export.cpp
+++ b/platform/bb10/export/export.cpp
@@ -67,11 +67,11 @@ public:
virtual int get_device_count() const;
virtual String get_device_name(int p_device) const;
virtual String get_device_info(int p_device) const;
- virtual Error run(int p_device,bool p_dumb=false);
+ virtual Error run(int p_device,int p_flags=0);
virtual bool requieres_password(bool p_debug) const { return !p_debug; }
virtual String get_binary_extension() const { return "bar"; }
- virtual Error export_project(const String& p_path,bool p_debug,bool p_dumb=false);
+ virtual Error export_project(const String& p_path,bool p_debug,int p_flags=0);
virtual bool can_export(String *r_error=NULL) const;
@@ -270,15 +270,21 @@ void EditorExportPlatformBB10::_fix_descriptor(Vector<uint8_t>& p_descriptor) {
-Error EditorExportPlatformBB10::export_project(const String& p_path, bool p_debug, bool p_dumb) {
+Error EditorExportPlatformBB10::export_project(const String& p_path, bool p_debug, int p_flags) {
EditorProgress ep("export","Exporting for BlackBerry 10",104);
- String template_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/";
-
- String src_template=custom_package!=""?custom_package:template_path.plus_file("bb10.zip");
+ String src_template=custom_package;
+ if (src_template=="") {
+ String err;
+ src_template = find_export_template("bb10.zip", &err);
+ if (src_template=="") {
+ EditorNode::add_io_error(err);
+ return ERR_FILE_NOT_FOUND;
+ }
+ }
FileAccess *src_f=NULL;
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
@@ -619,7 +625,7 @@ void EditorExportPlatformBB10::_device_poll_thread(void *ud) {
}
-Error EditorExportPlatformBB10::run(int p_device, bool p_dumb) {
+Error EditorExportPlatformBB10::run(int p_device, int p_flags) {
ERR_FAIL_INDEX_V(p_device,devices.size(),ERR_INVALID_PARAMETER);
@@ -643,7 +649,7 @@ Error EditorExportPlatformBB10::run(int p_device, bool p_dumb) {
ep.step("Exporting APK",0);
String export_to=EditorSettings::get_singleton()->get_settings_path().plus_file("/tmp/tmpexport.bar");
- Error err = export_project(export_to,true);
+ Error err = export_project(export_to,true,p_flags);
if (err) {
device_lock->unlock();
return err;
@@ -733,9 +739,7 @@ bool EditorExportPlatformBB10::can_export(String *r_error) const {
err+="Blackberry host tools not configured in editor settings.\n";
}
- String exe_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/";
-
- if (!FileAccess::exists(exe_path+"bb10.zip")) {
+ if (!exists_export_template("bb10.zip")) {
valid=false;
err+="No export template found.\nDownload and install export templates.\n";
}
diff --git a/platform/bb10/godot_bb10.cpp b/platform/bb10/godot_bb10.cpp
index f7e154d647..cba9d200cb 100644
--- a/platform/bb10/godot_bb10.cpp
+++ b/platform/bb10/godot_bb10.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/bb10/os_bb10.cpp b/platform/bb10/os_bb10.cpp
index d89033b1df..d2a350cf83 100644
--- a/platform/bb10/os_bb10.cpp
+++ b/platform/bb10/os_bb10.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -195,9 +195,10 @@ void OSBB10::finalize() {
// memdelete(debugger_connection_console);
//}
+ memdelete(sample_manager);
+
audio_server->finish();
memdelete(audio_server);
- memdelete(sample_manager);
visual_server->finish();
memdelete(visual_server);
diff --git a/platform/bb10/os_bb10.h b/platform/bb10/os_bb10.h
index 28149c15b5..a0481d1190 100644
--- a/platform/bb10/os_bb10.h
+++ b/platform/bb10/os_bb10.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/bb10/payment_service.cpp b/platform/bb10/payment_service.cpp
index f01230796f..77ec122b3b 100644
--- a/platform/bb10/payment_service.cpp
+++ b/platform/bb10/payment_service.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/bb10/payment_service.h b/platform/bb10/payment_service.h
index 5036ca6660..856b8df306 100644
--- a/platform/bb10/payment_service.h
+++ b/platform/bb10/payment_service.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/bb10/platform_config.h b/platform/bb10/platform_config.h
index 38fc934ae4..143f16c1fa 100644
--- a/platform/bb10/platform_config.h
+++ b/platform/bb10/platform_config.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/flash/SCsub b/platform/flash/SCsub
index b7aef3b65d..4e5f26d52a 100644
--- a/platform/flash/SCsub
+++ b/platform/flash/SCsub
@@ -36,5 +36,3 @@ java -jar $ALCHEMY/usr/lib/asc2.jar -md -strict -optimize -AS3 \
-import ../platform/flash/lib/libGL.abc \
../platform/flash/Console.as
"""
-
-
diff --git a/platform/flash/detect.py b/platform/flash/detect.py
index 5507ce5177..f079f21fdd 100644
--- a/platform/flash/detect.py
+++ b/platform/flash/detect.py
@@ -89,6 +89,9 @@ def configure(env):
#env.Append(CXXFLAGS=['-fno-access-control'])
+ if(env["opus"]=="yes"):
+ env.opus_fixed_point="yes"
+
if (env["target"]=="release"):
env.Append(CCFLAGS=['-O4', '-ffast-math','-fomit-frame-pointer'])
diff --git a/platform/flash/dir_access_flash.cpp b/platform/flash/dir_access_flash.cpp
index 4b8992f9d6..443242fd99 100644
--- a/platform/flash/dir_access_flash.cpp
+++ b/platform/flash/dir_access_flash.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/*************************************************/
/* Source code within this file is: */
-/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
/* All Rights Reserved. */
/*************************************************/
diff --git a/platform/flash/dir_access_flash.h b/platform/flash/dir_access_flash.h
index 1378a6e56f..482120775d 100644
--- a/platform/flash/dir_access_flash.h
+++ b/platform/flash/dir_access_flash.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/*************************************************/
/* Source code within this file is: */
-/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
/* All Rights Reserved. */
/*************************************************/
diff --git a/platform/flash/os_flash.h b/platform/flash/os_flash.h
index 42ae3f0718..46fce117fc 100644
--- a/platform/flash/os_flash.h
+++ b/platform/flash/os_flash.h
@@ -1,87 +1,88 @@
-#ifndef OS_FLASH_H
-#define OS_FLASH_H
-
-#include "os/input.h"
-#include "drivers/unix/os_unix.h"
-#include "os/input.h"
-#include "servers/visual_server.h"
-#include "servers/visual/rasterizer.h"
-#include "servers/physics/physics_server_sw.h"
-#include "servers/spatial_sound/spatial_sound_server_sw.h"
-#include "servers/spatial_sound_2d/spatial_sound_2d_server_sw.h"
-#include "servers/audio/audio_server_sw.h"
-#include "servers/physics_2d/physics_2d_server_sw.h"
-
-class OSFlash : public OS_Unix {
-
- VideoMode default_videomode;
- MainLoop * main_loop;
- InputDefault *input;
- Rasterizer *rasterizer;
- VisualServer *visual_server;
- AudioDriverSW* audio_driver;
- AudioServerSW *audio_server;
- SampleManagerMallocSW *sample_manager;
- SpatialSoundServerSW *spatial_sound_server;
- SpatialSound2DServerSW *spatial_sound_2d_server;
- PhysicsServer *physics_server;
- Physics2DServer *physics_2d_server;
-
-public:
-
- virtual int get_video_driver_count() const;
- virtual const char * get_video_driver_name(int p_driver) const;
-
- virtual VideoMode get_default_video_mode() const;
-
- virtual int get_audio_driver_count() const;
- virtual const char * get_audio_driver_name(int p_driver) const;
-
- virtual void initialize_core();
- virtual void initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver);
-
- virtual void set_main_loop( MainLoop * p_main_loop );
- virtual void delete_main_loop();
-
- virtual void finalize();
-
- typedef int64_t ProcessID;
-
- static OS* get_singleton();
-
- virtual void set_mouse_show(bool p_show);
- virtual void set_mouse_grab(bool p_grab);
- virtual bool is_mouse_grab_enabled() const;
- virtual Point2 get_mouse_pos() const;
- virtual int get_mouse_button_state() const;
- virtual void set_window_title(const String& p_title);
-
- //virtual void set_clipboard(const String& p_text);
- //virtual String get_clipboard() const;
-
-
- virtual bool has_virtual_keyboard() const;
- virtual void show_virtual_keyboard(const String& p_existing_text,const Rect2& p_screen_rect);
- virtual void hide_virtual_keyboard();
-
- virtual void set_video_mode(const VideoMode& p_video_mode,int p_screen=0);
- virtual VideoMode get_video_mode(int p_screen=0) const;
- virtual void get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen=0) const;
-
- virtual String get_name();
- virtual MainLoop *get_main_loop() const;
-
- virtual bool can_draw() const;
-
- virtual void set_cursor_shape(CursorShape p_shape);
-
- virtual bool has_touchscreen_ui_hint() const;
-
- virtual void yield();
-
- virtual Error shell_open(String p_uri);
-
- bool iterate();
-};
-
-#endif
+#ifndef OS_FLASH_H
+#define OS_FLASH_H
+
+#include "os/input.h"
+#include "drivers/unix/os_unix.h"
+#include "os/input.h"
+#include "servers/visual_server.h"
+#include "servers/visual/rasterizer.h"
+#include "servers/physics/physics_server_sw.h"
+#include "servers/spatial_sound/spatial_sound_server_sw.h"
+#include "servers/spatial_sound_2d/spatial_sound_2d_server_sw.h"
+#include "servers/audio/audio_server_sw.h"
+#include "servers/physics_2d/physics_2d_server_sw.h"
+#include "main/input_default.h"
+
+class OSFlash : public OS_Unix {
+
+ VideoMode default_videomode;
+ MainLoop * main_loop;
+ InputDefault *input;
+ Rasterizer *rasterizer;
+ VisualServer *visual_server;
+ AudioDriverSW* audio_driver;
+ AudioServerSW *audio_server;
+ SampleManagerMallocSW *sample_manager;
+ SpatialSoundServerSW *spatial_sound_server;
+ SpatialSound2DServerSW *spatial_sound_2d_server;
+ PhysicsServer *physics_server;
+ Physics2DServer *physics_2d_server;
+
+public:
+
+ virtual int get_video_driver_count() const;
+ virtual const char * get_video_driver_name(int p_driver) const;
+
+ virtual VideoMode get_default_video_mode() const;
+
+ virtual int get_audio_driver_count() const;
+ virtual const char * get_audio_driver_name(int p_driver) const;
+
+ virtual void initialize_core();
+ virtual void initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver);
+
+ virtual void set_main_loop( MainLoop * p_main_loop );
+ virtual void delete_main_loop();
+
+ virtual void finalize();
+
+ typedef int64_t ProcessID;
+
+ static OS* get_singleton();
+
+ virtual void set_mouse_show(bool p_show);
+ virtual void set_mouse_grab(bool p_grab);
+ virtual bool is_mouse_grab_enabled() const;
+ virtual Point2 get_mouse_pos() const;
+ virtual int get_mouse_button_state() const;
+ virtual void set_window_title(const String& p_title);
+
+ //virtual void set_clipboard(const String& p_text);
+ //virtual String get_clipboard() const;
+
+
+ virtual bool has_virtual_keyboard() const;
+ virtual void show_virtual_keyboard(const String& p_existing_text,const Rect2& p_screen_rect);
+ virtual void hide_virtual_keyboard();
+
+ virtual void set_video_mode(const VideoMode& p_video_mode,int p_screen=0);
+ virtual VideoMode get_video_mode(int p_screen=0) const;
+ virtual void get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen=0) const;
+
+ virtual String get_name();
+ virtual MainLoop *get_main_loop() const;
+
+ virtual bool can_draw() const;
+
+ virtual void set_cursor_shape(CursorShape p_shape);
+
+ virtual bool has_touchscreen_ui_hint() const;
+
+ virtual void yield();
+
+ virtual Error shell_open(String p_uri);
+
+ bool iterate();
+};
+
+#endif
diff --git a/platform/flash/rasterizer_flash.cpp b/platform/flash/rasterizer_flash.cpp
index 121baa333c..a36890e3d8 100644
--- a/platform/flash/rasterizer_flash.cpp
+++ b/platform/flash/rasterizer_flash.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/*************************************************/
/* Source code within this file is: */
-/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
/* All Rights Reserved. */
/*************************************************/
diff --git a/platform/flash/rasterizer_flash.h b/platform/flash/rasterizer_flash.h
index af231f7954..1caf7f2c44 100644
--- a/platform/flash/rasterizer_flash.h
+++ b/platform/flash/rasterizer_flash.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/*************************************************/
/* Source code within this file is: */
-/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
/* All Rights Reserved. */
/*************************************************/
@@ -577,7 +577,7 @@ class RasterizerFlash : public Rasterizer {
}
} else {
- return B->material->shader_cache < B->material->shader_cache;
+ return A->material->shader_cache < B->material->shader_cache;
}
}
};
diff --git a/platform/haiku/SCsub b/platform/haiku/SCsub
new file mode 100644
index 0000000000..1952e6b59b
--- /dev/null
+++ b/platform/haiku/SCsub
@@ -0,0 +1,25 @@
+Import('env')
+
+common_haiku = [
+ 'os_haiku.cpp',
+ 'context_gl_haiku.cpp',
+ 'haiku_application.cpp',
+ 'haiku_direct_window.cpp',
+ 'haiku_gl_view.cpp',
+ 'key_mapping_haiku.cpp',
+ 'audio_driver_media_kit.cpp'
+]
+
+target = env.Program(
+ '#bin/godot',
+ ['godot_haiku.cpp'] + common_haiku
+)
+
+command = env.Command('#bin/godot.rsrc', '#platform/haiku/godot.rdef',
+ ['rc -o $TARGET $SOURCE'])
+
+def addResourcesAction(target = None, source = None, env = None):
+ return env.Execute('xres -o ' + File(target)[0].path + ' bin/godot.rsrc')
+
+env.AddPostAction(target, addResourcesAction)
+env.Depends(target, command)
diff --git a/platform/haiku/audio_driver_media_kit.cpp b/platform/haiku/audio_driver_media_kit.cpp
new file mode 100644
index 0000000000..c7eed1c7cd
--- /dev/null
+++ b/platform/haiku/audio_driver_media_kit.cpp
@@ -0,0 +1,142 @@
+/*************************************************************************/
+/* audio_driver_media_kit.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
+#include "audio_driver_media_kit.h"
+
+#ifdef MEDIA_KIT_ENABLED
+
+#include "globals.h"
+
+int32_t* AudioDriverMediaKit::samples_in = NULL;
+
+Error AudioDriverMediaKit::init() {
+ active = false;
+
+ mix_rate = 44100;
+ output_format = OUTPUT_STEREO;
+ channels = 2;
+
+ int latency = GLOBAL_DEF("audio/output_latency", 25);
+ buffer_size = nearest_power_of_2(latency * mix_rate / 1000);
+ samples_in = memnew_arr(int32_t, buffer_size * channels);
+
+ media_raw_audio_format format;
+ format = media_raw_audio_format::wildcard;
+ format.frame_rate = mix_rate;
+ format.channel_count = channels;
+ format.format = media_raw_audio_format::B_AUDIO_INT;
+ format.byte_order = B_MEDIA_LITTLE_ENDIAN;
+ format.buffer_size = buffer_size * sizeof(int32_t) * channels;
+
+ player = new BSoundPlayer(
+ &format,
+ "godot_sound_server",
+ AudioDriverMediaKit::PlayBuffer,
+ NULL,
+ this
+ );
+
+ if (player->InitCheck() != B_OK) {
+ fprintf(stderr, "MediaKit ERR: can not create a BSoundPlayer instance\n");
+ ERR_FAIL_COND_V(player == NULL, ERR_CANT_OPEN);
+ }
+
+ mutex = Mutex::create();
+ player->Start();
+
+ return OK;
+}
+
+void AudioDriverMediaKit::PlayBuffer(void* cookie, void* buffer, size_t size, const media_raw_audio_format& format) {
+ AudioDriverMediaKit* ad = (AudioDriverMediaKit*) cookie;
+ int32_t* buf = (int32_t*) buffer;
+
+ if (!ad->active) {
+ for (unsigned int i = 0; i < ad->buffer_size * ad->channels; i++) {
+ AudioDriverMediaKit::samples_in[i] = 0;
+ }
+ } else {
+ ad->lock();
+ ad->audio_server_process(ad->buffer_size, AudioDriverMediaKit::samples_in);
+ ad->unlock();
+ }
+
+ for (unsigned int i = 0; i < ad->buffer_size * ad->channels; i++) {
+ buf[i] = AudioDriverMediaKit::samples_in[i];
+ }
+}
+
+void AudioDriverMediaKit::start() {
+ active = true;
+}
+
+int AudioDriverMediaKit::get_mix_rate() const {
+ return mix_rate;
+}
+
+AudioDriverSW::OutputFormat AudioDriverMediaKit::get_output_format() const {
+ return output_format;
+}
+
+void AudioDriverMediaKit::lock() {
+ if (!mutex)
+ return;
+
+ mutex->lock();
+}
+
+void AudioDriverMediaKit::unlock() {
+ if (!mutex)
+ return;
+
+ mutex->unlock();
+}
+
+void AudioDriverMediaKit::finish() {
+ delete player;
+
+ if (samples_in) {
+ memdelete_arr(samples_in);
+ };
+
+ if (mutex) {
+ memdelete(mutex);
+ mutex = NULL;
+ }
+}
+
+AudioDriverMediaKit::AudioDriverMediaKit() {
+ mutex = NULL;
+ player = NULL;
+}
+
+AudioDriverMediaKit::~AudioDriverMediaKit() {
+
+}
+
+#endif
diff --git a/platform/haiku/audio_driver_media_kit.h b/platform/haiku/audio_driver_media_kit.h
new file mode 100644
index 0000000000..cdaf602831
--- /dev/null
+++ b/platform/haiku/audio_driver_media_kit.h
@@ -0,0 +1,72 @@
+/*************************************************************************/
+/* audio_driver_media_kit.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
+#include "servers/audio/audio_server_sw.h"
+
+#ifdef MEDIA_KIT_ENABLED
+
+#include "core/os/thread.h"
+#include "core/os/mutex.h"
+
+#include <kernel/image.h> // needed for image_id
+#include <SoundPlayer.h>
+
+class AudioDriverMediaKit : public AudioDriverSW {
+ Mutex* mutex;
+
+ BSoundPlayer* player;
+ static int32_t* samples_in;
+
+ static void PlayBuffer(void* cookie, void* buffer, size_t size, const media_raw_audio_format& format);
+
+ unsigned int mix_rate;
+ OutputFormat output_format;
+ unsigned int buffer_size;
+ int channels;
+
+ bool active;
+
+public:
+
+ const char* get_name() const {
+ return "MediaKit";
+ };
+
+ virtual Error init();
+ virtual void start();
+ virtual int get_mix_rate() const;
+ virtual OutputFormat get_output_format() const;
+ virtual void lock();
+ virtual void unlock();
+ virtual void finish();
+
+ AudioDriverMediaKit();
+ ~AudioDriverMediaKit();
+};
+
+#endif
diff --git a/platform/haiku/context_gl_haiku.cpp b/platform/haiku/context_gl_haiku.cpp
new file mode 100644
index 0000000000..21107a52a4
--- /dev/null
+++ b/platform/haiku/context_gl_haiku.cpp
@@ -0,0 +1,43 @@
+#include "context_gl_haiku.h"
+
+#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED)
+
+ContextGL_Haiku::ContextGL_Haiku(HaikuDirectWindow* p_window) {
+ window = p_window;
+
+ uint32 type = BGL_RGB | BGL_DOUBLE | BGL_DEPTH;
+ view = new HaikuGLView(window->Bounds(), type);
+}
+
+ContextGL_Haiku::~ContextGL_Haiku() {
+ delete view;
+}
+
+Error ContextGL_Haiku::initialize() {
+ window->AddChild(view);
+ window->SetHaikuGLView(view);
+
+ return OK;
+}
+
+void ContextGL_Haiku::release_current() {
+ view->UnlockGL();
+}
+
+void ContextGL_Haiku::make_current() {
+ view->LockGL();
+}
+
+void ContextGL_Haiku::swap_buffers() {
+ view->SwapBuffers();
+}
+
+int ContextGL_Haiku::get_window_width() {
+ return window->Bounds().IntegerWidth();
+}
+
+int ContextGL_Haiku::get_window_height() {
+ return window->Bounds().IntegerHeight();
+}
+
+#endif
diff --git a/platform/haiku/context_gl_haiku.h b/platform/haiku/context_gl_haiku.h
new file mode 100644
index 0000000000..e37fe14970
--- /dev/null
+++ b/platform/haiku/context_gl_haiku.h
@@ -0,0 +1,29 @@
+#ifndef CONTEXT_GL_HAIKU_H
+#define CONTEXT_GL_HAIKU_H
+
+#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED)
+
+#include "drivers/gl_context/context_gl.h"
+
+#include "haiku_direct_window.h"
+#include "haiku_gl_view.h"
+
+class ContextGL_Haiku : public ContextGL {
+private:
+ HaikuGLView* view;
+ HaikuDirectWindow* window;
+
+public:
+ ContextGL_Haiku(HaikuDirectWindow* p_window);
+ ~ContextGL_Haiku();
+
+ virtual Error initialize();
+ virtual void release_current();
+ virtual void make_current();
+ virtual void swap_buffers();
+ virtual int get_window_width();
+ virtual int get_window_height();
+};
+
+#endif
+#endif
diff --git a/platform/haiku/detect.py b/platform/haiku/detect.py
new file mode 100644
index 0000000000..637b42dc03
--- /dev/null
+++ b/platform/haiku/detect.py
@@ -0,0 +1,62 @@
+import os
+import sys
+
+def is_active():
+ return True
+
+def get_name():
+ return "Haiku"
+
+def can_build():
+ if (os.name != "posix"):
+ return False
+
+ if (sys.platform == "darwin"):
+ return False
+
+ return True
+
+def get_opts():
+ return [
+ ('debug_release', 'Add debug symbols to release version','no')
+ ]
+
+def get_flags():
+ return [
+ ('builtin_zlib', 'no')
+ ]
+
+def configure(env):
+ is64 = sys.maxsize > 2**32
+
+ if (env["bits"]=="default"):
+ if (is64):
+ env["bits"]="64"
+ else:
+ env["bits"]="32"
+
+ env.Append(CPPPATH = ['#platform/haiku'])
+
+ env["CC"] = "gcc"
+ env["CXX"] = "g++"
+
+ if (env["target"]=="release"):
+ if (env["debug_release"]=="yes"):
+ env.Append(CCFLAGS=['-g2'])
+ else:
+ env.Append(CCFLAGS=['-O3','-ffast-math'])
+ elif (env["target"]=="release_debug"):
+ env.Append(CCFLAGS=['-O2','-ffast-math','-DDEBUG_ENABLED'])
+ elif (env["target"]=="debug"):
+ env.Append(CCFLAGS=['-g2', '-Wall','-DDEBUG_ENABLED','-DDEBUG_MEMORY_ENABLED'])
+
+ #env.Append(CCFLAGS=['-DFREETYPE_ENABLED'])
+ env.Append(CPPFLAGS = ['-DPTHREAD_NO_RENAME']) # TODO: enable when we have pthread_setname_np
+ env.Append(CPPFLAGS = ['-DGLEW_ENABLED', '-DOPENGL_ENABLED', '-DMEDIA_KIT_ENABLED'])
+ env.Append(CPPFLAGS = ['-DUNIX_ENABLED', '-DGLES2_ENABLED', '-DGLES_OVER_GL'])
+ env.Append(LIBS = ['be', 'game', 'media', 'network', 'bnetapi', 'z', 'GL', 'GLEW'])
+
+ import methods
+ env.Append(BUILDERS = {'GLSL120' : env.Builder(action = methods.build_legacygl_headers, suffix = 'glsl.h',src_suffix = '.glsl')})
+ env.Append(BUILDERS = {'GLSL' : env.Builder(action = methods.build_glsl_headers, suffix = 'glsl.h',src_suffix = '.glsl')})
+ env.Append(BUILDERS = {'GLSL120GLES' : env.Builder(action = methods.build_gles2_headers, suffix = 'glsl.h',src_suffix = '.glsl')})
diff --git a/platform/haiku/godot.rdef b/platform/haiku/godot.rdef
new file mode 100644
index 0000000000..a55cddbf0d
--- /dev/null
+++ b/platform/haiku/godot.rdef
@@ -0,0 +1,60 @@
+resource app_version {
+ major = 2,
+ middle = 0,
+ minor = 0,
+
+ variety = B_APPV_FINAL,
+ internal = 0,
+
+ short_info = "Godot Game Engine",
+ long_info = "An advanced, feature packed, multi-platform 2D and 3D game engine."
+};
+
+resource app_signature "application/x-vnd.godot";
+
+resource vector_icon {
+ $"6E6369660403A39F9F05FF03478CBF03414042090A04B37FB379CC26B379CC26"
+ $"CC20B37FCC200A09B5E9C41B2AC240B8E1BDFBBFA1BDA4C6A7BDFFCA1AC45CC9"
+ $"7AC607C01CC75BB6F4C65A062AFE9FFF9F69FE7FFEDFCF0FC95FC3D7C95FC51E"
+ $"C95FC51EC95FC53EC92BC565C94AC55BC92BC565C728C60BC728C60BC712C612"
+ $"C6E6C600C6F9C60EC6D3C5F2C6C7C5C4C6C7C5DCC6C7C5C4C460C4E5C4BCC4E5"
+ $"C626C4E5C626C4E5C64BC4A5C670C4CAC66BC4A5C670C1EDC6CFC1EDC6CFC1E9"
+ $"C6CFC1E2C6D0C1E6C6D0C1D1C6D0C1B2C6BEC1BFC6C9C1A2C6AFC19851C198C6"
+ $"9BC19851C505C031C507C507C016C507BFFCC507C507BE94C505BE9451BE9451"
+ $"BE94C69BBE7BC6BEBE8BC6AFBE6DC6C9BE4AC6D0BE5CC6D0BE47C6D0BE40C6CF"
+ $"BE44C6CFBE40C6CFBB87C670BB87C670BB63C66BBB47C626BB47C64BBB47C626"
+ $"C4BCB965C460B965C5C4B965C5C4B965C5DCB947C600B95AC5F2B934C60EB904"
+ $"C60BB91BC612B904C60BB701C565B701C565B6E3C55BB6CEC51EB6CEC53EB6CE"
+ $"C51EC3D7B590C36CB590C36CB581C3B0B578C43AB578C3F5B578C78FBFF8CA27"
+ $"BA2ACA22BFF8CA27BFFABFFCCA27BFFCCA27C5CACA22CA7CC43ACA7CC78FCA7C"
+ $"C3FBCA67C37ECA754ACA67C37E0639F6F97FFEF8E7FFF9F6FFFFFFFFFF03B67D"
+ $"BDEEC31FB730C35CB730C35CB74EC3662BC3A22BC3822BC3A2C4E8B8D1C55EB8"
+ $"D1C406B8D1C406B8D1C3F0B8ECC3CDB8DBC3DBB8FDC3BFB929C3BDB913C3B9B9"
+ $"29C3BDBB9FC436BB9FC436BBC2C43CBBDCC47EBBDCC45BBBDCC47EC5E6BE00C6"
+ $"31BE00C4BBBE00C4BBBE00C4A7BE16C486BE08C494BE24C479BE4AC471BE37C4"
+ $"71BE4AC471BE4BC016C473C1E2C471C1E2C471C1F6C471C217C486C209C479C2"
+ $"25C494C22DC4BBC22DC4A7C22DC4BBC631C451C5E6C451C47EC451C47EC451C4"
+ $"5BC48DC436C46AC43CC48DC436C704C3BDC704C3BDC719C3B9C741C3CDC730C3"
+ $"BF53C3DBC75CC406C75CC3F0C75CC406C55EC8CAC4E8C8CAC3A2C8CAC3A2C8CA"
+ $"C382C8FDC35CC8DFC366C8FDC35CC977C333BDEEC97ABDEEC97ABDEEC9F1BD56"
+ $"CAC9BC0BCA60BCB6CA3DBB1CC8D9B981C991BA47C82FB9D7C6EDBAA0C789BA38"
+ $"C69FBA52C5F0B9D0C647BA12C59BB98BC4E0B91FC53BB959C4FBB855C50EB6C0"
+ $"C509B78FC424B64AC22DB5C4C32AB5FCC1C8B66DC11BB7D9C16BB725C0BCB7C9"
+ $"BFFCB7C2C05CB7C3BFFCB7C2BFFCB7C2BFFCB7C2BFFBB7C2BFFAB7C2BFFAB7C2"
+ $"BFF9B7C2BFF8B7C2BFF9B7C2BFF8B7C2BFF8B7C2BFF8B7C2BF98B7C3BED9B7D9"
+ $"BF38B7C9BE88B725BDC7B5C4BE2CB66DBCCAB5FCBAE6B6C0BBD0B64ABAEBB78F"
+ $"BB13B91F34B855BAB8B959BA04B9D0BA59B98BB9ADBA12B907BAA0B955BA52B8"
+ $"6ABA38B71AB981B7C5B9D7B663BA47B52BBC0BB5B7BB1CB594BCB6B679BDEEB6"
+ $"02BD56B679BDEE0005BD3EC06CBD3EC06CBD3EC197BB2147BC4C47B9F647B904"
+ $"C06CB904C197B904BF41BB21BE4FB9F6BE4FBC4CBE4FBD3EC06CBD3EBF41BD3E"
+ $"C06C0005BCBC42BCBC42BCBCC153BB55C1F3BC1BC1F3BA8EC1F3B9ED42B9EDC1"
+ $"53B9EDBFC6BB55BF25BA8EBF25BC1BBF25BCBC42BCBCBFC6BCBC420007C01BC2"
+ $"BBC01BC2BBBFBAC2BBBF6CC21CBF6CC274BF6CC21CBF6CC02ABF6CC02ABF6CBF"
+ $"D3C01BBF8CBFBABF8CC07BBF8CC0C9C02AC0C9BFD3C0C9C02AC0C9C21CC0C9C2"
+ $"1CC0C9C274C01BC2BBC07BC2BBC01BC2BB0005C2F7C06CC2F7C06CC2F7C197C5"
+ $"1547C3E947C64047C732C06CC732C197C732BF41C515BE4FC640BE4FC3E9BE4F"
+ $"C2F7C06CC2F7BF41C2F7C06C0005C37942C37942C379C153C4E1C1F3C41AC1F3"
+ $"C5A7C1F3C64842C648C153C648BFC6C4E1BF25C5A7BF25C41ABF25C37942C379"
+ $"BFC6C37942090A0000000A010101000A020102000A020103000A010104000A03"
+ $"0105000A010106000A010107000A03010800"
+};
diff --git a/platform/haiku/godot_haiku.cpp b/platform/haiku/godot_haiku.cpp
new file mode 100644
index 0000000000..b4e5e50891
--- /dev/null
+++ b/platform/haiku/godot_haiku.cpp
@@ -0,0 +1,19 @@
+#include "main/main.h"
+#include "os_haiku.h"
+
+int main(int argc, char* argv[]) {
+ OS_Haiku os;
+
+ Error error = Main::setup(argv[0], argc-1, &argv[1]);
+ if (error != OK) {
+ return 255;
+ }
+
+ if (Main::start()) {
+ os.run();
+ }
+
+ Main::cleanup();
+
+ return os.get_exit_code();
+}
diff --git a/platform/haiku/haiku_application.cpp b/platform/haiku/haiku_application.cpp
new file mode 100644
index 0000000000..180bd133fb
--- /dev/null
+++ b/platform/haiku/haiku_application.cpp
@@ -0,0 +1,7 @@
+#include "haiku_application.h"
+
+HaikuApplication::HaikuApplication()
+ : BApplication("application/x-vnd.godot")
+{
+
+}
diff --git a/platform/haiku/haiku_application.h b/platform/haiku/haiku_application.h
new file mode 100644
index 0000000000..a64b01c94d
--- /dev/null
+++ b/platform/haiku/haiku_application.h
@@ -0,0 +1,13 @@
+#ifndef HAIKU_APPLICATION_H
+#define HAIKU_APPLICATION_H
+
+#include <kernel/image.h> // needed for image_id
+#include <Application.h>
+
+class HaikuApplication : public BApplication
+{
+public:
+ HaikuApplication();
+};
+
+#endif
diff --git a/platform/haiku/haiku_direct_window.cpp b/platform/haiku/haiku_direct_window.cpp
new file mode 100644
index 0000000000..184d64f840
--- /dev/null
+++ b/platform/haiku/haiku_direct_window.cpp
@@ -0,0 +1,342 @@
+#include <UnicodeChar.h>
+
+#include "main/main.h"
+#include "os/keyboard.h"
+#include "haiku_direct_window.h"
+#include "key_mapping_haiku.h"
+
+HaikuDirectWindow::HaikuDirectWindow(BRect p_frame)
+ : BDirectWindow(p_frame, "Godot", B_TITLED_WINDOW, B_QUIT_ON_WINDOW_CLOSE)
+{
+ last_mouse_pos_valid = false;
+ last_buttons_state = 0;
+ last_button_mask = 0;
+ last_key_modifier_state = 0;
+}
+
+
+HaikuDirectWindow::~HaikuDirectWindow() {
+ delete update_runner;
+}
+
+void HaikuDirectWindow::SetHaikuGLView(HaikuGLView* p_view) {
+ view = p_view;
+}
+
+void HaikuDirectWindow::StartMessageRunner() {
+ update_runner = new BMessageRunner(BMessenger(this),
+ new BMessage(REDRAW_MSG), 1000000/30 /* 30 fps */);
+}
+
+void HaikuDirectWindow::StopMessageRunner() {
+ delete update_runner;
+}
+
+void HaikuDirectWindow::SetInput(InputDefault* p_input) {
+ input = p_input;
+}
+
+void HaikuDirectWindow::SetMainLoop(MainLoop* p_main_loop) {
+ main_loop = p_main_loop;
+}
+
+bool HaikuDirectWindow::QuitRequested() {
+ main_loop->notification(MainLoop::NOTIFICATION_WM_QUIT_REQUEST);
+ return false;
+}
+
+void HaikuDirectWindow::DirectConnected(direct_buffer_info* info) {
+ view->DirectConnected(info);
+ view->EnableDirectMode(true);
+}
+
+void HaikuDirectWindow::MessageReceived(BMessage* message) {
+ switch (message->what) {
+ case REDRAW_MSG:
+ if (Main::iteration() == true) {
+ view->EnableDirectMode(false);
+ Quit();
+ }
+ break;
+
+ default:
+ BDirectWindow::MessageReceived(message);
+ }
+}
+
+void HaikuDirectWindow::DispatchMessage(BMessage* message, BHandler* handler) {
+ switch (message->what) {
+ case B_MOUSE_DOWN:
+ case B_MOUSE_UP:
+ HandleMouseButton(message);
+ break;
+
+ case B_MOUSE_MOVED:
+ HandleMouseMoved(message);
+ break;
+
+ case B_MOUSE_WHEEL_CHANGED:
+ HandleMouseWheelChanged(message);
+ break;
+
+ case B_KEY_DOWN:
+ case B_KEY_UP:
+ HandleKeyboardEvent(message);
+ break;
+
+ case B_MODIFIERS_CHANGED:
+ HandleKeyboardModifierEvent(message);
+ break;
+
+ case B_WINDOW_RESIZED:
+ HandleWindowResized(message);
+ break;
+
+ case LOCKGL_MSG:
+ view->LockGL();
+ break;
+
+ case UNLOCKGL_MSG:
+ view->UnlockGL();
+ break;
+
+ default:
+ BDirectWindow::DispatchMessage(message, handler);
+ }
+}
+
+void HaikuDirectWindow::HandleMouseButton(BMessage* message) {
+ BPoint where;
+ if (message->FindPoint("where", &where) != B_OK) {
+ return;
+ }
+
+ uint32 modifiers = message->FindInt32("modifiers");
+ uint32 buttons = message->FindInt32("buttons");
+ uint32 button = buttons ^ last_buttons_state;
+ last_buttons_state = buttons;
+
+ // TODO: implement the mouse_mode checks
+ //if (mouse_mode == MOUSE_MODE_CAPTURED) {
+ // event.xbutton.x=last_mouse_pos.x;
+ // event.xbutton.y=last_mouse_pos.y;
+ //}
+
+ InputEvent mouse_event;
+ mouse_event.ID = ++event_id;
+ mouse_event.type = InputEvent::MOUSE_BUTTON;
+ mouse_event.device = 0;
+
+ mouse_event.mouse_button.mod = GetKeyModifierState(modifiers);
+ mouse_event.mouse_button.button_mask = GetMouseButtonState(buttons);
+ mouse_event.mouse_button.x = where.x;
+ mouse_event.mouse_button.y = where.y;
+ mouse_event.mouse_button.global_x = where.x;
+ mouse_event.mouse_button.global_y = where.y;
+
+ switch (button) {
+ default:
+ case B_PRIMARY_MOUSE_BUTTON:
+ mouse_event.mouse_button.button_index = 1;
+ break;
+
+ case B_SECONDARY_MOUSE_BUTTON:
+ mouse_event.mouse_button.button_index = 2;
+ break;
+
+ case B_TERTIARY_MOUSE_BUTTON:
+ mouse_event.mouse_button.button_index = 3;
+ break;
+ }
+
+ mouse_event.mouse_button.pressed = (message->what == B_MOUSE_DOWN);
+
+ if (message->what == B_MOUSE_DOWN && mouse_event.mouse_button.button_index == 1) {
+ int32 clicks = message->FindInt32("clicks");
+
+ if (clicks > 1) {
+ mouse_event.mouse_button.doubleclick=true;
+ }
+ }
+
+ input->parse_input_event(mouse_event);
+}
+
+void HaikuDirectWindow::HandleMouseMoved(BMessage* message) {
+ BPoint where;
+ if (message->FindPoint("where", &where) != B_OK) {
+ return;
+ }
+
+ Point2i pos(where.x, where.y);
+ uint32 modifiers = message->FindInt32("modifiers");
+ uint32 buttons = message->FindInt32("buttons");
+
+ if (!last_mouse_pos_valid) {
+ last_mouse_position = pos;
+ last_mouse_pos_valid = true;
+ }
+
+ Point2i rel = pos - last_mouse_position;
+
+ InputEvent motion_event;
+ motion_event.ID = ++event_id;
+ motion_event.type = InputEvent::MOUSE_MOTION;
+ motion_event.device = 0;
+
+ motion_event.mouse_motion.mod = GetKeyModifierState(modifiers);
+ motion_event.mouse_motion.button_mask = GetMouseButtonState(buttons);
+ motion_event.mouse_motion.x = pos.x;
+ motion_event.mouse_motion.y = pos.y;
+ input->set_mouse_pos(pos);
+ motion_event.mouse_motion.global_x = pos.x;
+ motion_event.mouse_motion.global_y = pos.y;
+ motion_event.mouse_motion.speed_x = input->get_mouse_speed().x;
+ motion_event.mouse_motion.speed_y = input->get_mouse_speed().y;
+
+ motion_event.mouse_motion.relative_x = rel.x;
+ motion_event.mouse_motion.relative_y = rel.y;
+
+ last_mouse_position = pos;
+
+ input->parse_input_event(motion_event);
+}
+
+void HaikuDirectWindow::HandleMouseWheelChanged(BMessage* message) {
+ float wheel_delta_y = 0;
+ if (message->FindFloat("be:wheel_delta_y", &wheel_delta_y) != B_OK) {
+ return;
+ }
+
+ InputEvent mouse_event;
+ mouse_event.ID = ++event_id;
+ mouse_event.type = InputEvent::MOUSE_BUTTON;
+ mouse_event.device = 0;
+
+ mouse_event.mouse_button.button_index = wheel_delta_y < 0 ? 4 : 5;
+ mouse_event.mouse_button.mod = GetKeyModifierState(last_key_modifier_state);
+ mouse_event.mouse_button.button_mask = last_button_mask;
+ mouse_event.mouse_button.x = last_mouse_position.x;
+ mouse_event.mouse_button.y = last_mouse_position.y;
+ mouse_event.mouse_button.global_x = last_mouse_position.x;
+ mouse_event.mouse_button.global_y = last_mouse_position.y;
+
+ mouse_event.mouse_button.pressed = true;
+ input->parse_input_event(mouse_event);
+
+ mouse_event.ID = ++event_id;
+ mouse_event.mouse_button.pressed = false;
+ input->parse_input_event(mouse_event);
+}
+
+void HaikuDirectWindow::HandleKeyboardEvent(BMessage* message) {
+ int32 raw_char = 0;
+ int32 key = 0;
+ int32 modifiers = 0;
+
+ if (message->FindInt32("raw_char", &raw_char) != B_OK) {
+ return;
+ }
+
+ if (message->FindInt32("key", &key) != B_OK) {
+ return;
+ }
+
+ if (message->FindInt32("modifiers", &modifiers) != B_OK) {
+ return;
+ }
+
+ InputEvent event;
+ event.ID = ++event_id;
+ event.type = InputEvent::KEY;
+ event.device = 0;
+ event.key.mod = GetKeyModifierState(modifiers);
+ event.key.pressed = (message->what == B_KEY_DOWN);
+ event.key.scancode = KeyMappingHaiku::get_keysym(raw_char, key);
+ event.key.echo = message->HasInt32("be:key_repeat");
+ event.key.unicode = 0;
+
+ const char* bytes = NULL;
+ if (message->FindString("bytes", &bytes) == B_OK) {
+ event.key.unicode = BUnicodeChar::FromUTF8(&bytes);
+ }
+
+ //make it consistent accross platforms.
+ if (event.key.scancode==KEY_BACKTAB) {
+ event.key.scancode=KEY_TAB;
+ event.key.mod.shift=true;
+ }
+
+ input->parse_input_event(event);
+}
+
+void HaikuDirectWindow::HandleKeyboardModifierEvent(BMessage* message) {
+ int32 old_modifiers = 0;
+ int32 modifiers = 0;
+
+ if (message->FindInt32("be:old_modifiers", &old_modifiers) != B_OK) {
+ return;
+ }
+
+ if (message->FindInt32("modifiers", &modifiers) != B_OK) {
+ return;
+ }
+
+ int32 key = old_modifiers ^ modifiers;
+
+ InputEvent event;
+ event.ID = ++event_id;
+ event.type = InputEvent::KEY;
+ event.device = 0;
+ event.key.mod = GetKeyModifierState(modifiers);
+ event.key.pressed = ((modifiers & key) != 0);
+ event.key.scancode = KeyMappingHaiku::get_modifier_keysym(key);
+ event.key.echo = false;
+ event.key.unicode = 0;
+
+ input->parse_input_event(event);
+}
+
+void HaikuDirectWindow::HandleWindowResized(BMessage* message) {
+ int32 width = 0;
+ int32 height = 0;
+
+ if ((message->FindInt32("width", &width) != B_OK) || (message->FindInt32("height", &height) != B_OK)) {
+ return;
+ }
+
+ current_video_mode->width = width;
+ current_video_mode->height = height;
+}
+
+inline InputModifierState HaikuDirectWindow::GetKeyModifierState(uint32 p_state) {
+ last_key_modifier_state = p_state;
+ InputModifierState state;
+
+ state.shift = (p_state & B_SHIFT_KEY) != 0;
+ state.control = (p_state & B_CONTROL_KEY) != 0;
+ state.alt = (p_state & B_OPTION_KEY) != 0;
+ state.meta = (p_state & B_COMMAND_KEY) != 0;
+
+ return state;
+}
+
+inline int HaikuDirectWindow::GetMouseButtonState(uint32 p_state) {
+ int state = 0;
+
+ if (p_state & B_PRIMARY_MOUSE_BUTTON) {
+ state |= 1 << 0;
+ }
+
+ if (p_state & B_SECONDARY_MOUSE_BUTTON) {
+ state |= 1 << 1;
+ }
+
+ if (p_state & B_TERTIARY_MOUSE_BUTTON) {
+ state |= 1 << 2;
+ }
+
+ last_button_mask = state;
+
+ return state;
+}
diff --git a/platform/haiku/haiku_direct_window.h b/platform/haiku/haiku_direct_window.h
new file mode 100644
index 0000000000..f0398df505
--- /dev/null
+++ b/platform/haiku/haiku_direct_window.h
@@ -0,0 +1,60 @@
+#ifndef HAIKU_DIRECT_WINDOW_H
+#define HAIKU_DIRECT_WINDOW_H
+
+#include <kernel/image.h> // needed for image_id
+#include <DirectWindow.h>
+
+#include "core/os/os.h"
+#include "main/input_default.h"
+
+#include "haiku_gl_view.h"
+
+#define REDRAW_MSG 'rdrw'
+#define LOCKGL_MSG 'glck'
+#define UNLOCKGL_MSG 'ulck'
+
+class HaikuDirectWindow : public BDirectWindow
+{
+private:
+ unsigned int event_id;
+ Point2i last_mouse_position;
+ bool last_mouse_pos_valid;
+ uint32 last_buttons_state;
+ uint32 last_key_modifier_state;
+ int last_button_mask;
+ OS::VideoMode* current_video_mode;
+
+ MainLoop* main_loop;
+ InputDefault* input;
+ HaikuGLView* view;
+ BMessageRunner* update_runner;
+
+ void HandleMouseButton(BMessage* message);
+ void HandleMouseMoved(BMessage* message);
+ void HandleMouseWheelChanged(BMessage* message);
+ void HandleWindowResized(BMessage* message);
+ void HandleKeyboardEvent(BMessage* message);
+ void HandleKeyboardModifierEvent(BMessage* message);
+ inline InputModifierState GetKeyModifierState(uint32 p_state);
+ inline int GetMouseButtonState(uint32 p_state);
+
+public:
+ HaikuDirectWindow(BRect p_frame);
+ ~HaikuDirectWindow();
+
+ void SetHaikuGLView(HaikuGLView* p_view);
+ void StartMessageRunner();
+ void StopMessageRunner();
+ void SetInput(InputDefault* p_input);
+ void SetMainLoop(MainLoop* p_main_loop);
+ inline void SetVideoMode(OS::VideoMode* video_mode) { current_video_mode = video_mode; };
+ virtual bool QuitRequested();
+ virtual void DirectConnected(direct_buffer_info* info);
+ virtual void MessageReceived(BMessage* message);
+ virtual void DispatchMessage(BMessage* message, BHandler* handler);
+
+ inline Point2i GetLastMousePosition() { return last_mouse_position; };
+ inline int GetLastButtonMask() { return last_button_mask; };
+};
+
+#endif
diff --git a/platform/haiku/haiku_gl_view.cpp b/platform/haiku/haiku_gl_view.cpp
new file mode 100644
index 0000000000..481d6098a7
--- /dev/null
+++ b/platform/haiku/haiku_gl_view.cpp
@@ -0,0 +1,18 @@
+#include "main/main.h"
+#include "haiku_gl_view.h"
+
+HaikuGLView::HaikuGLView(BRect frame, uint32 type)
+ : BGLView(frame, "GodotGLView", B_FOLLOW_ALL_SIDES, 0, type)
+{
+}
+
+void HaikuGLView::AttachedToWindow(void) {
+ LockGL();
+ BGLView::AttachedToWindow();
+ UnlockGL();
+ MakeFocus();
+}
+
+void HaikuGLView::Draw(BRect updateRect) {
+ Main::force_redraw();
+}
diff --git a/platform/haiku/haiku_gl_view.h b/platform/haiku/haiku_gl_view.h
new file mode 100644
index 0000000000..f44b6d4325
--- /dev/null
+++ b/platform/haiku/haiku_gl_view.h
@@ -0,0 +1,15 @@
+#ifndef HAIKU_GL_VIEW_H
+#define HAIKU_GL_VIEW_H
+
+#include <kernel/image.h> // needed for image_id
+#include <GLView.h>
+
+class HaikuGLView : public BGLView
+{
+public:
+ HaikuGLView(BRect frame, uint32 type);
+ virtual void AttachedToWindow(void);
+ virtual void Draw(BRect updateRect);
+};
+
+#endif
diff --git a/platform/haiku/key_mapping_haiku.cpp b/platform/haiku/key_mapping_haiku.cpp
new file mode 100644
index 0000000000..d7bde9a727
--- /dev/null
+++ b/platform/haiku/key_mapping_haiku.cpp
@@ -0,0 +1,193 @@
+#include <InterfaceDefs.h>
+
+#include "key_mapping_haiku.h"
+#include "os/keyboard.h"
+
+struct _HaikuTranslatePair {
+ unsigned int keysym;
+ int32 keycode;
+};
+
+static _HaikuTranslatePair _mod_to_keycode[] = {
+ { KEY_SHIFT, B_SHIFT_KEY },
+ { KEY_ALT, B_COMMAND_KEY },
+ { KEY_CONTROL, B_CONTROL_KEY },
+ { KEY_CAPSLOCK, B_CAPS_LOCK },
+ { KEY_SCROLLLOCK, B_SCROLL_LOCK },
+ { KEY_NUMLOCK, B_NUM_LOCK },
+ { KEY_SUPER_L, B_OPTION_KEY },
+ { KEY_MENU, B_MENU_KEY },
+ { KEY_SHIFT, B_LEFT_SHIFT_KEY },
+ { KEY_SHIFT, B_RIGHT_SHIFT_KEY },
+ { KEY_ALT, B_LEFT_COMMAND_KEY },
+ { KEY_ALT, B_RIGHT_COMMAND_KEY },
+ { KEY_CONTROL, B_LEFT_CONTROL_KEY },
+ { KEY_CONTROL, B_RIGHT_CONTROL_KEY },
+ { KEY_SUPER_L, B_LEFT_OPTION_KEY },
+ { KEY_SUPER_R, B_RIGHT_OPTION_KEY },
+ { KEY_UNKNOWN, 0 }
+};
+
+static _HaikuTranslatePair _fn_to_keycode[] = {
+ { KEY_F1, B_F1_KEY },
+ { KEY_F2, B_F2_KEY },
+ { KEY_F3, B_F3_KEY },
+ { KEY_F4, B_F4_KEY },
+ { KEY_F5, B_F5_KEY },
+ { KEY_F6, B_F6_KEY },
+ { KEY_F7, B_F7_KEY },
+ { KEY_F8, B_F8_KEY },
+ { KEY_F9, B_F9_KEY },
+ { KEY_F10, B_F10_KEY },
+ { KEY_F11, B_F11_KEY },
+ { KEY_F12, B_F12_KEY },
+ //{ KEY_F13, ? },
+ //{ KEY_F14, ? },
+ //{ KEY_F15, ? },
+ //{ KEY_F16, ? },
+ { KEY_PRINT, B_PRINT_KEY },
+ { KEY_SCROLLLOCK, B_SCROLL_KEY },
+ { KEY_PAUSE, B_PAUSE_KEY },
+ { KEY_UNKNOWN, 0 }
+};
+
+static _HaikuTranslatePair _hb_to_keycode[] = {
+ { KEY_BACKSPACE, B_BACKSPACE },
+ { KEY_TAB, B_TAB },
+ { KEY_RETURN, B_RETURN },
+ { KEY_CAPSLOCK, B_CAPS_LOCK },
+ { KEY_ESCAPE, B_ESCAPE },
+ { KEY_SPACE, B_SPACE },
+ { KEY_PAGEUP, B_PAGE_UP },
+ { KEY_PAGEDOWN, B_PAGE_DOWN },
+ { KEY_END, B_END },
+ { KEY_HOME, B_HOME },
+ { KEY_LEFT, B_LEFT_ARROW },
+ { KEY_UP, B_UP_ARROW },
+ { KEY_RIGHT, B_RIGHT_ARROW },
+ { KEY_DOWN, B_DOWN_ARROW },
+ { KEY_PRINT, B_PRINT_KEY },
+ { KEY_INSERT, B_INSERT },
+ { KEY_DELETE, B_DELETE },
+ // { KEY_HELP, ??? },
+
+ { KEY_0, (0x30) },
+ { KEY_1, (0x31) },
+ { KEY_2, (0x32) },
+ { KEY_3, (0x33) },
+ { KEY_4, (0x34) },
+ { KEY_5, (0x35) },
+ { KEY_6, (0x36) },
+ { KEY_7, (0x37) },
+ { KEY_8, (0x38) },
+ { KEY_9, (0x39) },
+ { KEY_A, (0x61) },
+ { KEY_B, (0x62) },
+ { KEY_C, (0x63) },
+ { KEY_D, (0x64) },
+ { KEY_E, (0x65) },
+ { KEY_F, (0x66) },
+ { KEY_G, (0x67) },
+ { KEY_H, (0x68) },
+ { KEY_I, (0x69) },
+ { KEY_J, (0x6A) },
+ { KEY_K, (0x6B) },
+ { KEY_L, (0x6C) },
+ { KEY_M, (0x6D) },
+ { KEY_N, (0x6E) },
+ { KEY_O, (0x6F) },
+ { KEY_P, (0x70) },
+ { KEY_Q, (0x71) },
+ { KEY_R, (0x72) },
+ { KEY_S, (0x73) },
+ { KEY_T, (0x74) },
+ { KEY_U, (0x75) },
+ { KEY_V, (0x76) },
+ { KEY_W, (0x77) },
+ { KEY_X, (0x78) },
+ { KEY_Y, (0x79) },
+ { KEY_Z, (0x7A) },
+
+/*
+{ KEY_PLAY, VK_PLAY},// (0xFA)
+{ KEY_STANDBY,VK_SLEEP },//(0x5F)
+{ KEY_BACK,VK_BROWSER_BACK},// (0xA6)
+{ KEY_FORWARD,VK_BROWSER_FORWARD},// (0xA7)
+{ KEY_REFRESH,VK_BROWSER_REFRESH},// (0xA8)
+{ KEY_STOP,VK_BROWSER_STOP},// (0xA9)
+{ KEY_SEARCH,VK_BROWSER_SEARCH},// (0xAA)
+{ KEY_FAVORITES, VK_BROWSER_FAVORITES},// (0xAB)
+{ KEY_HOMEPAGE,VK_BROWSER_HOME},// (0xAC)
+{ KEY_VOLUMEMUTE,VK_VOLUME_MUTE},// (0xAD)
+{ KEY_VOLUMEDOWN,VK_VOLUME_DOWN},// (0xAE)
+{ KEY_VOLUMEUP,VK_VOLUME_UP},// (0xAF)
+{ KEY_MEDIANEXT,VK_MEDIA_NEXT_TRACK},// (0xB0)
+{ KEY_MEDIAPREVIOUS,VK_MEDIA_PREV_TRACK},// (0xB1)
+{ KEY_MEDIASTOP,VK_MEDIA_STOP},// (0xB2)
+{ KEY_LAUNCHMAIL, VK_LAUNCH_MAIL},// (0xB4)
+{ KEY_LAUNCHMEDIA,VK_LAUNCH_MEDIA_SELECT},// (0xB5)
+{ KEY_LAUNCH0,VK_LAUNCH_APP1},// (0xB6)
+{ KEY_LAUNCH1,VK_LAUNCH_APP2},// (0xB7)
+*/
+
+ { KEY_SEMICOLON, 0x3B },
+ { KEY_EQUAL, 0x3D },
+ { KEY_COLON, 0x2C },
+ { KEY_MINUS, 0x2D },
+ { KEY_PERIOD, 0x2E },
+ { KEY_SLASH, 0x2F },
+ { KEY_KP_MULTIPLY, 0x2A },
+ { KEY_KP_ADD, 0x2B },
+
+ { KEY_QUOTELEFT, 0x60 },
+ { KEY_BRACKETLEFT, 0x5B },
+ { KEY_BACKSLASH, 0x5C },
+ { KEY_BRACKETRIGHT, 0x5D },
+ { KEY_APOSTROPHE, 0x27 },
+
+ { KEY_UNKNOWN, 0 }
+};
+
+unsigned int KeyMappingHaiku::get_keysym(int32 raw_char, int32 key) {
+ if (raw_char == B_INSERT && key == 0x64) { return KEY_KP_0; }
+ if (raw_char == B_END && key == 0x58) { return KEY_KP_1; }
+ if (raw_char == B_DOWN_ARROW && key == 0x59) { return KEY_KP_2; }
+ if (raw_char == B_PAGE_DOWN && key == 0x5A) { return KEY_KP_3; }
+ if (raw_char == B_LEFT_ARROW && key == 0x48) { return KEY_KP_4; }
+ if (raw_char == 0x35 && key == 0x49) { return KEY_KP_5; }
+ if (raw_char == B_RIGHT_ARROW && key == 0x4A) { return KEY_KP_6; }
+ if (raw_char == B_HOME && key == 0x37) { return KEY_KP_7; }
+ if (raw_char == B_UP_ARROW && key == 0x38) { return KEY_KP_8; }
+ if (raw_char == B_PAGE_UP && key == 0x39) { return KEY_KP_9; }
+ if (raw_char == 0x2F && key == 0x23) { return KEY_KP_DIVIDE; }
+ if (raw_char == 0x2D && key == 0x25) { return KEY_KP_SUBSTRACT; }
+ if (raw_char == B_DELETE && key == 0x65) { return KEY_KP_PERIOD; }
+
+ if (raw_char == 0x10) {
+ for(int i = 0; _fn_to_keycode[i].keysym != KEY_UNKNOWN; i++) {
+ if (_fn_to_keycode[i].keycode == key) {
+ return _fn_to_keycode[i].keysym;
+ }
+ }
+
+ return KEY_UNKNOWN;
+ }
+
+ for(int i = 0; _hb_to_keycode[i].keysym != KEY_UNKNOWN; i++) {
+ if (_hb_to_keycode[i].keycode == raw_char) {
+ return _hb_to_keycode[i].keysym;
+ }
+ }
+
+ return KEY_UNKNOWN;
+}
+
+unsigned int KeyMappingHaiku::get_modifier_keysym(int32 key) {
+ for(int i = 0; _mod_to_keycode[i].keysym != KEY_UNKNOWN; i++) {
+ if ((_mod_to_keycode[i].keycode & key) != 0) {
+ return _mod_to_keycode[i].keysym;
+ }
+ }
+
+ return KEY_UNKNOWN;
+}
diff --git a/platform/haiku/key_mapping_haiku.h b/platform/haiku/key_mapping_haiku.h
new file mode 100644
index 0000000000..e2864678a8
--- /dev/null
+++ b/platform/haiku/key_mapping_haiku.h
@@ -0,0 +1,13 @@
+#ifndef KEY_MAPPING_HAIKU_H
+#define KEY_MAPPING_HAIKU_H
+
+class KeyMappingHaiku
+{
+ KeyMappingHaiku() {};
+
+public:
+ static unsigned int get_keysym(int32 raw_char, int32 key);
+ static unsigned int get_modifier_keysym(int32 key);
+};
+
+#endif
diff --git a/platform/haiku/logo.png b/platform/haiku/logo.png
new file mode 100644
index 0000000000..42d7728da8
--- /dev/null
+++ b/platform/haiku/logo.png
Binary files differ
diff --git a/platform/haiku/os_haiku.cpp b/platform/haiku/os_haiku.cpp
new file mode 100644
index 0000000000..ef483657ca
--- /dev/null
+++ b/platform/haiku/os_haiku.cpp
@@ -0,0 +1,321 @@
+#include <Screen.h>
+
+#include "servers/visual/visual_server_raster.h"
+#include "servers/visual/visual_server_wrap_mt.h"
+#include "drivers/gles2/rasterizer_gles2.h"
+#include "servers/physics/physics_server_sw.h"
+//#include "servers/physics_2d/physics_2d_server_wrap_mt.h"
+#include "main/main.h"
+
+#include "os_haiku.h"
+
+
+OS_Haiku::OS_Haiku() {
+#ifdef MEDIA_KIT_ENABLED
+ AudioDriverManagerSW::add_driver(&driver_media_kit);
+#endif
+};
+
+void OS_Haiku::run() {
+ if (!main_loop) {
+ return;
+ }
+
+ main_loop->init();
+ context_gl->release_current();
+
+ // TODO: clean up
+ BMessenger* bms = new BMessenger(window);
+ BMessage* msg = new BMessage();
+ bms->SendMessage(LOCKGL_MSG, msg);
+
+ window->StartMessageRunner();
+ app->Run();
+ window->StopMessageRunner();
+
+ delete app;
+
+ delete bms;
+ delete msg;
+ main_loop->finish();
+}
+
+String OS_Haiku::get_name() {
+ return "Haiku";
+}
+
+int OS_Haiku::get_video_driver_count() const {
+ return 1;
+}
+
+const char* OS_Haiku::get_video_driver_name(int p_driver) const {
+ return "GLES2";
+}
+
+OS::VideoMode OS_Haiku::get_default_video_mode() const {
+ return OS::VideoMode(800, 600, false);
+}
+
+void OS_Haiku::initialize(const VideoMode& p_desired, int p_video_driver, int p_audio_driver) {
+ main_loop = NULL;
+ current_video_mode = p_desired;
+
+ app = new HaikuApplication();
+
+ BRect frame;
+ frame.Set(50, 50, 50 + current_video_mode.width - 1, 50 + current_video_mode.height - 1);
+
+ window = new HaikuDirectWindow(frame);
+ window->SetVideoMode(&current_video_mode);
+
+ if (current_video_mode.fullscreen) {
+ window->SetFullScreen(true);
+ }
+
+ if (!current_video_mode.resizable) {
+ uint32 flags = window->Flags();
+ flags |= B_NOT_RESIZABLE;
+ window->SetFlags(flags);
+ }
+
+#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED)
+ context_gl = memnew(ContextGL_Haiku(window));
+ context_gl->initialize();
+ context_gl->make_current();
+
+ rasterizer = memnew(RasterizerGLES2);
+#endif
+
+ visual_server = memnew(VisualServerRaster(rasterizer));
+
+ ERR_FAIL_COND(!visual_server);
+
+ // TODO: enable multithreaded VS
+ //if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
+ // visual_server = memnew(VisualServerWrapMT(visual_server, get_render_thread_mode() == RENDER_SEPARATE_THREAD));
+ //}
+
+ input = memnew(InputDefault);
+ window->SetInput(input);
+
+ window->Show();
+ visual_server->init();
+
+ physics_server = memnew(PhysicsServerSW);
+ physics_server->init();
+ physics_2d_server = memnew(Physics2DServerSW);
+ // TODO: enable multithreaded PS
+ //physics_2d_server = Physics2DServerWrapMT::init_server<Physics2DServerSW>();
+ physics_2d_server->init();
+
+ AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton();
+
+ if (AudioDriverManagerSW::get_driver(p_audio_driver)->init() != OK) {
+ ERR_PRINT("Initializing audio failed.");
+ }
+
+ sample_manager = memnew(SampleManagerMallocSW);
+ audio_server = memnew(AudioServerSW(sample_manager));
+ audio_server->init();
+
+ spatial_sound_server = memnew(SpatialSoundServerSW);
+ spatial_sound_server->init();
+ spatial_sound_2d_server = memnew(SpatialSound2DServerSW);
+ spatial_sound_2d_server->init();
+}
+
+void OS_Haiku::finalize() {
+ if (main_loop) {
+ memdelete(main_loop);
+ }
+
+ main_loop = NULL;
+
+ spatial_sound_server->finish();
+ memdelete(spatial_sound_server);
+
+ spatial_sound_2d_server->finish();
+ memdelete(spatial_sound_2d_server);
+
+ memdelete(sample_manager);
+
+ audio_server->finish();
+ memdelete(audio_server);
+
+ visual_server->finish();
+ memdelete(visual_server);
+ memdelete(rasterizer);
+
+ physics_server->finish();
+ memdelete(physics_server);
+
+ physics_2d_server->finish();
+ memdelete(physics_2d_server);
+
+ memdelete(input);
+
+#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED)
+ memdelete(context_gl);
+#endif
+}
+
+void OS_Haiku::set_main_loop(MainLoop* p_main_loop) {
+ main_loop = p_main_loop;
+ input->set_main_loop(p_main_loop);
+ window->SetMainLoop(p_main_loop);
+}
+
+MainLoop* OS_Haiku::get_main_loop() const {
+ return main_loop;
+}
+
+void OS_Haiku::delete_main_loop() {
+ if (main_loop) {
+ memdelete(main_loop);
+ }
+
+ main_loop = NULL;
+ window->SetMainLoop(NULL);
+}
+
+void OS_Haiku::release_rendering_thread() {
+ context_gl->release_current();
+}
+
+void OS_Haiku::make_rendering_thread() {
+ context_gl->make_current();
+}
+
+bool OS_Haiku::can_draw() const {
+ // TODO: implement
+ return true;
+}
+
+void OS_Haiku::swap_buffers() {
+ context_gl->swap_buffers();
+}
+
+Point2 OS_Haiku::get_mouse_pos() const {
+ return window->GetLastMousePosition();
+}
+
+int OS_Haiku::get_mouse_button_state() const {
+ return window->GetLastButtonMask();
+}
+
+void OS_Haiku::set_cursor_shape(CursorShape p_shape) {
+ //ERR_PRINT("set_cursor_shape() NOT IMPLEMENTED");
+}
+
+int OS_Haiku::get_screen_count() const {
+ // TODO: implement get_screen_count()
+ return 1;
+}
+
+int OS_Haiku::get_current_screen() const {
+ // TODO: implement get_current_screen()
+ return 0;
+}
+
+void OS_Haiku::set_current_screen(int p_screen) {
+ // TODO: implement set_current_screen()
+}
+
+Point2 OS_Haiku::get_screen_position(int p_screen) const {
+ // TODO: make this work with the p_screen parameter
+ BScreen* screen = new BScreen(window);
+ BRect frame = screen->Frame();
+ delete screen;
+ return Point2i(frame.left, frame.top);
+}
+
+Size2 OS_Haiku::get_screen_size(int p_screen) const {
+ // TODO: make this work with the p_screen parameter
+ BScreen* screen = new BScreen(window);
+ BRect frame = screen->Frame();
+ delete screen;
+ return Size2i(frame.IntegerWidth() + 1, frame.IntegerHeight() + 1);
+}
+
+void OS_Haiku::set_window_title(const String& p_title) {
+ window->SetTitle(p_title.utf8().get_data());
+}
+
+Size2 OS_Haiku::get_window_size() const {
+ BSize size = window->Size();
+ return Size2i(size.IntegerWidth() + 1, size.IntegerHeight() + 1);
+}
+
+void OS_Haiku::set_window_size(const Size2 p_size) {
+ // TODO: why does it stop redrawing after this is called?
+ window->ResizeTo(p_size.x, p_size.y);
+}
+
+Point2 OS_Haiku::get_window_position() const {
+ BPoint point(0, 0);
+ window->ConvertToScreen(&point);
+ return Point2i(point.x, point.y);
+}
+
+void OS_Haiku::set_window_position(const Point2& p_position) {
+ window->MoveTo(p_position.x, p_position.y);
+}
+
+void OS_Haiku::set_window_fullscreen(bool p_enabled) {
+ window->SetFullScreen(p_enabled);
+ current_video_mode.fullscreen = p_enabled;
+ visual_server->init();
+}
+
+bool OS_Haiku::is_window_fullscreen() const {
+ return current_video_mode.fullscreen;
+}
+
+void OS_Haiku::set_window_resizable(bool p_enabled) {
+ uint32 flags = window->Flags();
+
+ if (p_enabled) {
+ flags &= ~(B_NOT_RESIZABLE);
+ } else {
+ flags |= B_NOT_RESIZABLE;
+ }
+
+ window->SetFlags(flags);
+ current_video_mode.resizable = p_enabled;
+}
+
+bool OS_Haiku::is_window_resizable() const {
+ return current_video_mode.resizable;
+}
+
+void OS_Haiku::set_window_minimized(bool p_enabled) {
+ window->Minimize(p_enabled);
+}
+
+bool OS_Haiku::is_window_minimized() const {
+ return window->IsMinimized();
+}
+
+void OS_Haiku::set_window_maximized(bool p_enabled) {
+ window->Minimize(!p_enabled);
+}
+
+bool OS_Haiku::is_window_maximized() const {
+ return !window->IsMinimized();
+}
+
+void OS_Haiku::set_video_mode(const VideoMode& p_video_mode, int p_screen) {
+ ERR_PRINT("set_video_mode() NOT IMPLEMENTED");
+}
+
+OS::VideoMode OS_Haiku::get_video_mode(int p_screen) const {
+ return current_video_mode;
+}
+
+void OS_Haiku::get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen) const {
+ ERR_PRINT("get_fullscreen_mode_list() NOT IMPLEMENTED");
+}
+
+String OS_Haiku::get_executable_path() const {
+ return OS::get_executable_path();
+}
diff --git a/platform/haiku/os_haiku.h b/platform/haiku/os_haiku.h
new file mode 100644
index 0000000000..e1b0b86cf4
--- /dev/null
+++ b/platform/haiku/os_haiku.h
@@ -0,0 +1,99 @@
+#ifndef OS_HAIKU_H
+#define OS_HAIKU_H
+
+#include "drivers/unix/os_unix.h"
+#include "servers/visual_server.h"
+#include "servers/visual/rasterizer.h"
+#include "servers/physics_server.h"
+#include "servers/physics_2d/physics_2d_server_sw.h"
+#include "servers/audio/audio_server_sw.h"
+#include "servers/audio/sample_manager_sw.h"
+#include "servers/spatial_sound/spatial_sound_server_sw.h"
+#include "servers/spatial_sound_2d/spatial_sound_2d_server_sw.h"
+#include "main/input_default.h"
+
+#include "audio_driver_media_kit.h"
+#include "context_gl_haiku.h"
+#include "haiku_application.h"
+#include "haiku_direct_window.h"
+
+
+class OS_Haiku : public OS_Unix {
+private:
+ HaikuApplication* app;
+ HaikuDirectWindow* window;
+ MainLoop* main_loop;
+ InputDefault* input;
+ Rasterizer* rasterizer;
+ VisualServer* visual_server;
+ VideoMode current_video_mode;
+ PhysicsServer* physics_server;
+ Physics2DServer* physics_2d_server;
+ AudioServerSW* audio_server;
+ SampleManagerMallocSW* sample_manager;
+ SpatialSoundServerSW* spatial_sound_server;
+ SpatialSound2DServerSW* spatial_sound_2d_server;
+
+#ifdef MEDIA_KIT_ENABLED
+ AudioDriverMediaKit driver_media_kit;
+#endif
+
+#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED)
+ ContextGL_Haiku* context_gl;
+#endif
+
+ virtual void delete_main_loop();
+
+protected:
+ virtual int get_video_driver_count() const;
+ virtual const char* get_video_driver_name(int p_driver) const;
+ virtual VideoMode get_default_video_mode() const;
+
+ virtual void initialize(const VideoMode& p_desired, int p_video_driver, int p_audio_driver);
+ virtual void finalize();
+
+ virtual void set_main_loop(MainLoop* p_main_loop);
+
+public:
+ OS_Haiku();
+ void run();
+
+ virtual String get_name();
+
+ virtual MainLoop* get_main_loop() const;
+
+ virtual bool can_draw() const;
+ virtual void release_rendering_thread();
+ virtual void make_rendering_thread();
+ virtual void swap_buffers();
+
+ virtual Point2 get_mouse_pos() const;
+ virtual int get_mouse_button_state() const;
+ virtual void set_cursor_shape(CursorShape p_shape);
+
+ virtual int get_screen_count() const;
+ virtual int get_current_screen() const;
+ virtual void set_current_screen(int p_screen);
+ virtual Point2 get_screen_position(int p_screen=0) const;
+ virtual Size2 get_screen_size(int p_screen=0) const;
+ virtual void set_window_title(const String& p_title);
+ virtual Size2 get_window_size() const;
+ virtual void set_window_size(const Size2 p_size);
+ virtual Point2 get_window_position() const;
+ virtual void set_window_position(const Point2& p_position);
+ virtual void set_window_fullscreen(bool p_enabled);
+ virtual bool is_window_fullscreen() const;
+ virtual void set_window_resizable(bool p_enabled);
+ virtual bool is_window_resizable() const;
+ virtual void set_window_minimized(bool p_enabled);
+ virtual bool is_window_minimized() const;
+ virtual void set_window_maximized(bool p_enabled);
+ virtual bool is_window_maximized() const;
+
+ virtual void set_video_mode(const VideoMode& p_video_mode, int p_screen=0);
+ virtual VideoMode get_video_mode(int p_screen=0) const;
+ virtual void get_fullscreen_mode_list(List<VideoMode> *p_list, int p_screen=0) const;
+ virtual String get_executable_path() const;
+};
+
+#endif
diff --git a/platform/haiku/platform_config.h b/platform/haiku/platform_config.h
new file mode 100644
index 0000000000..691bdbdb9c
--- /dev/null
+++ b/platform/haiku/platform_config.h
@@ -0,0 +1,6 @@
+#include <alloca.h>
+
+// for ifaddrs.h needed in drivers/unix/ip_unix.cpp
+#define _BSD_SOURCE 1
+
+#define GLES2_INCLUDE_H <GL/glew.h>
diff --git a/platform/iphone/Appirater.h b/platform/iphone/Appirater.h
index f0bf2c01d5..6ff25532f7 100644
--- a/platform/iphone/Appirater.h
+++ b/platform/iphone/Appirater.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/iphone/SCsub b/platform/iphone/SCsub
index d495e3b5fc..922a324694 100644
--- a/platform/iphone/SCsub
+++ b/platform/iphone/SCsub
@@ -12,6 +12,7 @@ iphone_lib = [
'view_controller.mm',
'game_center.mm',
'in_app_store.mm',
+ 'icloud.mm',
'Appirater.m',
]
@@ -34,5 +35,5 @@ obj = env_ios.Object('godot_iphone.cpp')
prog = None
prog = env_ios.Program('#bin/godot', [obj] + iphone_lib)
-action = "dsymutil "+File(prog)[0].path+" -o " + File(prog)[0].path + ".dSYM"
+action = "$IPHONEPATH/usr/bin/dsymutil "+File(prog)[0].path+" -o " + File(prog)[0].path + ".dSYM"
env.AddPostAction(prog, action)
diff --git a/platform/iphone/app_delegate.h b/platform/iphone/app_delegate.h
index 0d20f886cc..54bfe78cf7 100644
--- a/platform/iphone/app_delegate.h
+++ b/platform/iphone/app_delegate.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/iphone/app_delegate.mm b/platform/iphone/app_delegate.mm
index 2c7a0a0790..a3af8ff163 100644
--- a/platform/iphone/app_delegate.mm
+++ b/platform/iphone/app_delegate.mm
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -43,6 +43,11 @@
#import <AdSupport/AdSupport.h>
#endif
+#ifdef MODULE_PARSE_ENABLED
+#import <Parse/Parse.h>
+#import "FBSDKCoreKit/FBSDKCoreKit.h"
+#endif
+
#define kFilteringFactor 0.1
#define kRenderingFrequency 60
#define kAccelerometerFrequency 100.0 // Hz
@@ -51,6 +56,9 @@
#import "Appirater.h"
#endif
+Error _shell_open(String);
+void _set_keep_screen_on(bool p_enabled);
+
Error _shell_open(String p_uri) {
NSString* url = [[NSString alloc] initWithUTF8String:p_uri.utf8().get_data()];
@@ -63,6 +71,10 @@ Error _shell_open(String p_uri) {
return OK;
};
+void _set_keep_screen_on(bool p_enabled) {
+ [[UIApplication sharedApplication] setIdleTimerDisabled:(BOOL)p_enabled];
+};
+
@implementation AppDelegate
@synthesize window;
@@ -138,6 +150,30 @@ static int frame_count = 0;
Main::setup2();
++frame_count;
+ // this might be necessary before here
+ NSDictionary* dict = [[NSBundle mainBundle] infoDictionary];
+ for (NSString* key in dict) {
+ NSObject* value = [dict objectForKey:key];
+ String ukey = String::utf8([key UTF8String]);
+
+ // we need a NSObject to Variant conversor
+
+ if ([value isKindOfClass:[NSString class]]) {
+ NSString* str = (NSString*)value;
+ String uval = String::utf8([str UTF8String]);
+
+ Globals::get_singleton()->set("Info.plist/"+ukey, uval);
+
+ } else if ([value isKindOfClass:[NSNumber class]]) {
+
+ NSNumber* n = (NSNumber*)value;
+ double dval = [n doubleValue];
+
+ Globals::get_singleton()->set("Info.plist/"+ukey, dval);
+ };
+ // do stuff
+ }
+
} break;
/*
case 3: {
@@ -181,8 +217,8 @@ static int frame_count = 0;
[application setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone];
// disable idle timer
- application.idleTimerDisabled = YES;
-
+ //application.idleTimerDisabled = YES;
+
//Create a full-screen window
window = [[UIWindow alloc] initWithFrame:rect];
//window.autoresizesSubviews = YES;
@@ -207,6 +243,9 @@ static int frame_count = 0;
view_controller.view = glView;
window.rootViewController = view_controller;
+ _set_keep_screen_on(bool(GLOBAL_DEF("display/keep_screen_on",true)) ? YES : NO);
+ glView.useCADisplayLink = bool(GLOBAL_DEF("display.iOS/use_cadisplaylink",true)) ? YES : NO;
+ printf("cadisaplylink: %d", glView.useCADisplayLink);
glView.animationInterval = 1.0 / kRenderingFrequency;
[glView startAnimation];
@@ -318,6 +357,15 @@ static int frame_count = 0;
// For 4.2+ support
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
+#ifdef MODULE_PARSE_ENABLED
+ NSLog(@"Handling application openURL");
+ return [[FBSDKApplicationDelegate sharedInstance] application:application
+ openURL:url
+ sourceApplication:sourceApplication
+ annotation:annotation];
+#endif
+
+
#ifdef MODULE_FACEBOOKSCORER_IOS_ENABLED
return [[[FacebookScorer sharedInstance] facebook] handleOpenURL:url];
#else
@@ -325,6 +373,32 @@ static int frame_count = 0;
#endif
}
+- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
+#ifdef MODULE_PARSE_ENABLED
+ // Store the deviceToken in the current installation and save it to Parse.
+ PFInstallation *currentInstallation = [PFInstallation currentInstallation];
+ //NSString* token = [[NSString alloc] initWithData:deviceToken encoding:NSUTF8StringEncoding];
+ NSLog(@"Device Token : %@ ", deviceToken);
+ [currentInstallation setDeviceTokenFromData:deviceToken];
+ [currentInstallation saveInBackground];
+#endif
+}
+
+- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
+#ifdef MODULE_PARSE_ENABLED
+ [PFPush handlePush:userInfo];
+ NSDictionary *aps = [userInfo objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
+ NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
+
+ NSLog(@"Push Notification Payload (app active) %@", aps);
+ [defaults setObject:aps forKey:@"notificationInfo"];
+ [defaults synchronize];
+ if (application.applicationState == UIApplicationStateInactive) {
+ [PFAnalytics trackAppOpenedWithRemoteNotificationPayload:userInfo];
+ }
+#endif
+}
+
- (void)dealloc
{
[window release];
diff --git a/platform/iphone/audio_driver_iphone.cpp b/platform/iphone/audio_driver_iphone.cpp
index a95cb436a7..0916c31f36 100644
--- a/platform/iphone/audio_driver_iphone.cpp
+++ b/platform/iphone/audio_driver_iphone.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/iphone/audio_driver_iphone.h b/platform/iphone/audio_driver_iphone.h
index 5d406940a3..0b143adf94 100644
--- a/platform/iphone/audio_driver_iphone.h
+++ b/platform/iphone/audio_driver_iphone.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py
index fb57876a83..9472f05e16 100644
--- a/platform/iphone/detect.py
+++ b/platform/iphone/detect.py
@@ -11,7 +11,8 @@ def get_name():
def can_build():
import sys
- if sys.platform == 'darwin':
+ import os
+ if sys.platform == 'darwin' or os.environ.has_key("OSXCROSS_IOS"):
return True
return False
@@ -25,9 +26,11 @@ def get_opts():
('IPHONESDK', 'path to the iphone SDK', '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/${IOS_SDK_VERSION}.sdk/'),
('game_center', 'Support for game center', 'yes'),
('store_kit', 'Support for in-app store', 'yes'),
+ ('icloud', 'Support for iCloud', 'yes'),
('ios_gles22_override', 'Force GLES2.0 on iOS', 'yes'),
('ios_appirater', 'Enable Appirater', 'no'),
('ios_exceptions', 'Use exceptions when compiling on playbook', 'yes'),
+ ('ios_triple', 'Triple for ios toolchain', ''),
]
def get_flags():
@@ -48,18 +51,19 @@ def configure(env):
# env['CC'] = '$IPHONEPATH/Developer/usr/bin/gcc'
# env['CXX'] = '$IPHONEPATH/Developer/usr/bin/g++'
- env['CC'] = '$IPHONEPATH/usr/bin/clang'
- env['CXX'] = '$IPHONEPATH/usr/bin/clang++'
- env['AR'] = 'ar'
+ env['CC'] = '$IPHONEPATH/usr/bin/${ios_triple}clang'
+ env['CXX'] = '$IPHONEPATH/usr/bin/${ios_triple}clang++'
+ env['AR'] = '$IPHONEPATH/usr/bin/${ios_triple}ar'
+ env['RANLIB'] = '$IPHONEPATH/usr/bin/${ios_triple}ranlib'
import string
if (env["bits"]=="64"):
#env['CCFLAGS'] = string.split('-arch arm64 -fmessage-length=0 -fdiagnostics-show-note-include-stack -fmacro-backtrace-limit=0 -Wno-trigraphs -fpascal-strings -O0 -Wno-missing-field-initializers -Wno-missing-prototypes -Wno-return-type -Wno-non-virtual-dtor -Wno-overloaded-virtual -Wno-exit-time-destructors -Wno-missing-braces -Wparentheses -Wswitch -Wno-unused-function -Wno-unused-label -Wno-unused-parameter -Wno-unused-variable -Wunused-value -Wno-empty-body -Wno-uninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wno-constant-conversion -Wno-int-conversion -Wno-bool-conversion -Wno-enum-conversion -Wshorten-64-to-32 -Wno-newline-eof -Wno-c++11-extensions -fstrict-aliasing -Wdeprecated-declarations -Winvalid-offsetof -g -Wno-sign-conversion -miphoneos-version-min=5.1.1 -Wmost -Wno-four-char-constants -Wno-unknown-pragmas -Wno-invalid-offsetof -ffast-math -m64 -DDEBUG -D_DEBUG -MMD -MT dependencies -isysroot $IPHONESDK')
- env['CCFLAGS'] = string.split('-fno-objc-arc -arch arm64 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -Wno-trigraphs -fpascal-strings -Wmissing-prototypes -Wreturn-type -Wparentheses -Wswitch -Wno-unused-parameter -Wunused-variable -Wunused-value -Wno-shorten-64-to-32 -gdwarf-2 -fvisibility=hidden -Wno-sign-conversion -MMD -MT dependencies -miphoneos-version-min=5.1.1 -isysroot $IPHONESDK')
+ env['CCFLAGS'] = string.split('-fno-objc-arc -arch arm64 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -Wno-trigraphs -fpascal-strings -Wmissing-prototypes -Wreturn-type -Wparentheses -Wswitch -Wno-unused-parameter -Wunused-variable -Wunused-value -Wno-shorten-64-to-32 -fvisibility=hidden -Wno-sign-conversion -MMD -MT dependencies -miphoneos-version-min=5.1.1 -isysroot $IPHONESDK')
env.Append(CPPFLAGS=['-DNEED_LONG_INT'])
env.Append(CPPFLAGS=['-DLIBYUV_DISABLE_NEON'])
else:
- env['CCFLAGS'] = string.split('-fno-objc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -Wno-trigraphs -fpascal-strings -Wmissing-prototypes -Wreturn-type -Wparentheses -Wswitch -Wno-unused-parameter -Wunused-variable -Wunused-value -Wno-shorten-64-to-32 -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk -gdwarf-2 -fvisibility=hidden -Wno-sign-conversion -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=4.3 -MMD -MT dependencies -isysroot $IPHONESDK')
+ env['CCFLAGS'] = string.split('-fno-objc-arc -arch armv7 -fmessage-length=0 -fno-strict-aliasing -fdiagnostics-print-source-range-info -fdiagnostics-show-category=id -fdiagnostics-parseable-fixits -Wno-trigraphs -fpascal-strings -Wmissing-prototypes -Wreturn-type -Wparentheses -Wswitch -Wno-unused-parameter -Wunused-variable -Wunused-value -Wno-shorten-64-to-32 -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk -fvisibility=hidden -Wno-sign-conversion -mthumb "-DIBOutlet=__attribute__((iboutlet))" "-DIBOutletCollection(ClassName)=__attribute__((iboutletcollection(ClassName)))" "-DIBAction=void)__attribute__((ibaction)" -miphoneos-version-min=5.1.1 -MMD -MT dependencies -isysroot $IPHONESDK')
if (env["bits"]=="64"):
env.Append(LINKFLAGS=['-arch', 'arm64', '-Wl,-dead_strip', '-miphoneos-version-min=5.1.1',
@@ -80,7 +84,7 @@ def configure(env):
'-framework', 'CoreMedia',
])
else:
- env.Append(LINKFLAGS=['-arch', 'armv7', '-Wl,-dead_strip', '-miphoneos-version-min=4.3',
+ env.Append(LINKFLAGS=['-arch', 'armv7', '-Wl,-dead_strip', '-miphoneos-version-min=5.1.1',
'-isysroot', '$IPHONESDK',
'-framework', 'Foundation',
'-framework', 'UIKit',
@@ -104,17 +108,20 @@ def configure(env):
if env['store_kit'] == 'yes':
env.Append(CPPFLAGS=['-DSTOREKIT_ENABLED'])
env.Append(LINKFLAGS=['-framework', 'StoreKit'])
+
+ if env['icloud'] == 'yes':
+ env.Append(CPPFLAGS=['-DICLOUD_ENABLED'])
env.Append(CPPPATH = ['$IPHONESDK/usr/include', '$IPHONESDK/System/Library/Frameworks/OpenGLES.framework/Headers', '$IPHONESDK/System/Library/Frameworks/AudioUnit.framework/Headers'])
if (env["target"]=="release"):
- env.Append(CCFLAGS=['-O3', '-ffast-math', '-DNS_BLOCK_ASSERTIONS=1','-Wall'])
- env.Append(LINKFLAGS=['-O3', '-ffast-math'])
+ env.Append(CCFLAGS=['-O3', '-DNS_BLOCK_ASSERTIONS=1','-Wall', '-gdwarf-2']) # removed -ffast-math
+ env.Append(LINKFLAGS=['-O3']) #
elif env["target"] == "release_debug":
- env.Append(CCFLAGS=['-Os', '-ffast-math', '-DNS_BLOCK_ASSERTIONS=1','-Wall','-DDEBUG_ENABLED'])
- env.Append(LINKFLAGS=['-Os', '-ffast-math'])
+ env.Append(CCFLAGS=['-Os', '-DNS_BLOCK_ASSERTIONS=1','-Wall','-DDEBUG_ENABLED'])
+ env.Append(LINKFLAGS=['-Os'])
env.Append(CPPFLAGS=['-DDEBUG_MEMORY_ENABLED'])
elif (env["target"]=="debug"):
@@ -124,12 +131,20 @@ def configure(env):
elif (env["target"]=="profile"):
- env.Append(CCFLAGS=['-g','-pg', '-Os', '-ffast-math'])
+ env.Append(CCFLAGS=['-g','-pg', '-Os'])
env.Append(LINKFLAGS=['-pg'])
env['ENV']['CODESIGN_ALLOCATE'] = '/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate'
env.Append(CPPFLAGS=['-DIPHONE_ENABLED', '-DUNIX_ENABLED', '-DGLES2_ENABLED', '-DMPC_FIXED_POINT'])
+
+ if(env["opus"]=="yes"):
+ env.opus_fixed_point="yes"
+ if(env["bits"]=="64"):
+ env.Append(CFLAGS=["-DOPUS_ARM64_OPT"])
+ else:
+ env.Append(CFLAGS=["-DOPUS_ARM_OPT"])
+
if env['ios_exceptions'] == 'yes':
env.Append(CPPFLAGS=['-fexceptions'])
else:
diff --git a/platform/iphone/game_center.h b/platform/iphone/game_center.h
index 8f180d1638..62477a0da2 100644
--- a/platform/iphone/game_center.h
+++ b/platform/iphone/game_center.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/iphone/game_center.mm b/platform/iphone/game_center.mm
index 79c056776d..3756b58699 100644
--- a/platform/iphone/game_center.mm
+++ b/platform/iphone/game_center.mm
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,8 +30,18 @@
#include "game_center.h"
+#ifdef __IPHONE_9_0
+
+#import <GameKit/GameKit.h>
+extern "C" {
+
+#else
+
extern "C" {
#import <GameKit/GameKit.h>
+
+#endif
+
#import "app_delegate.h"
};
diff --git a/platform/iphone/gl_view.h b/platform/iphone/gl_view.h
index c58c863510..e69ddc839a 100755
--- a/platform/iphone/gl_view.h
+++ b/platform/iphone/gl_view.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,8 +34,6 @@
#import <MediaPlayer/MediaPlayer.h>
#import <AVFoundation/AVFoundation.h>
-#define USE_CADISPLAYLINK 1 //iOS version 3.1+ is required
-
@protocol GLViewDelegate;
@interface GLView : UIView<UIKeyInput>
@@ -53,13 +51,13 @@
// OpenGL name for the depth buffer that is attached to viewFramebuffer, if it exists (0 if it does not exist)
GLuint depthRenderbuffer;
-#if USE_CADISPLAYLINK
+ BOOL useCADisplayLink;
// CADisplayLink available on 3.1+ synchronizes the animation timer & drawing with the refresh rate of the display, only supports animation intervals of 1/60 1/30 & 1/15
CADisplayLink *displayLink;
-#else
+
// An animation timer that, when animation is started, will periodically call -drawView at the given rate.
+ // Only used if CADisplayLink is not
NSTimer *animationTimer;
-#endif
NSTimeInterval animationInterval;
@@ -104,6 +102,7 @@
- (void)audioRouteChangeListenerCallback:(NSNotification*)notification;
@property NSTimeInterval animationInterval;
+@property(nonatomic, assign) BOOL useCADisplayLink;
@end
diff --git a/platform/iphone/gl_view.mm b/platform/iphone/gl_view.mm
index 3309fd0820..88361e87e4 100755
--- a/platform/iphone/gl_view.mm
+++ b/platform/iphone/gl_view.mm
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -54,6 +54,14 @@ static bool video_playing = false;
static float video_previous_volume = 0.0f;
static CMTime video_current_time;
+void _show_keyboard(String);
+void _hide_keyboard();
+bool _play_video(String, float, String, String);
+bool _is_video_playing();
+void _focus_out_video();
+void _unpause_video();
+void _stop_video();
+
void _show_keyboard(String p_existing) {
keyboard_text = p_existing;
printf("instance on show is %p\n", _instance);
@@ -334,17 +342,21 @@ static void clear_touches() {
delegateSetup = ![delegate respondsToSelector:@selector(setupView:)];
}
+@synthesize useCADisplayLink;
+
// If our view is resized, we'll be asked to layout subviews.
// This is the perfect opportunity to also update the framebuffer so that it is
// the same size as our display area.
-(void)layoutSubviews
{
- printf("HERE\n");
+ //printf("HERE\n");
[EAGLContext setCurrentContext:context];
[self destroyFramebuffer];
[self createFramebuffer];
[self drawView];
+ [self drawView];
+
}
- (BOOL)createFramebuffer
@@ -416,19 +428,21 @@ static void clear_touches() {
return;
active = TRUE;
printf("start animation!\n");
-#if USE_CADISPLAYLINK
- // Approximate frame rate
- // assumes device refreshes at 60 fps
- int frameInterval = (int) floor(animationInterval * 60.0f);
-
- displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(drawView)];
- [displayLink setFrameInterval:frameInterval];
-
- // Setup DisplayLink in main thread
- [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
-#else
- animationTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval target:self selector:@selector(drawView) userInfo:nil repeats:YES];
-#endif
+ if (useCADisplayLink) {
+
+ // Approximate frame rate
+ // assumes device refreshes at 60 fps
+ int frameInterval = (int) floor(animationInterval * 60.0f);
+
+ displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(drawView)];
+ [displayLink setFrameInterval:frameInterval];
+
+ // Setup DisplayLink in main thread
+ [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
+ }
+ else {
+ animationTimer = [NSTimer scheduledTimerWithTimeInterval:animationInterval target:self selector:@selector(drawView) userInfo:nil repeats:YES];
+ }
if (video_playing)
{
@@ -442,13 +456,16 @@ static void clear_touches() {
return;
active = FALSE;
printf("******** stop animation!\n");
-#if USE_CADISPLAYLINK
- [displayLink invalidate];
- displayLink = nil;
-#else
- [animationTimer invalidate];
- animationTimer = nil;
-#endif
+
+ if (useCADisplayLink) {
+ [displayLink invalidate];
+ displayLink = nil;
+ }
+ else {
+ [animationTimer invalidate];
+ animationTimer = nil;
+ }
+
clear_touches();
if (video_playing)
@@ -460,13 +477,7 @@ static void clear_touches() {
- (void)setAnimationInterval:(NSTimeInterval)interval
{
animationInterval = interval;
-
-#if USE_CADISPLAYLINK
- if(displayLink)
-#else
- if(animationTimer)
-#endif
- {
+ if ( (useCADisplayLink && displayLink) || ( !useCADisplayLink && animationTimer ) ) {
[self stopAnimation];
[self startAnimation];
}
@@ -475,16 +486,16 @@ static void clear_touches() {
// Updates the OpenGL view when the timer fires
- (void)drawView
{
-#if USE_CADISPLAYLINK
- // Pause the CADisplayLink to avoid recursion
- [displayLink setPaused: YES];
+ if (useCADisplayLink) {
+ // Pause the CADisplayLink to avoid recursion
+ [displayLink setPaused: YES];
- // Process all input events
- while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, TRUE) == kCFRunLoopRunHandledSource);
+ // Process all input events
+ while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, TRUE) == kCFRunLoopRunHandledSource);
- // We are good to go, resume the CADisplayLink
- [displayLink setPaused: NO];
-#endif
+ // We are good to go, resume the CADisplayLink
+ [displayLink setPaused: NO];
+ }
if (!active) {
printf("draw view not active!\n");
@@ -615,7 +626,7 @@ static void clear_touches() {
- (void)audioRouteChangeListenerCallback:(NSNotification*)notification
{
- printf("*********** route changed!%i\n");
+ printf("*********** route changed!\n");
NSDictionary *interuptionDict = notification.userInfo;
NSInteger routeChangeReason = [[interuptionDict valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue];
@@ -630,7 +641,7 @@ static void clear_touches() {
case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
NSLog(@"AVAudioSessionRouteChangeReasonOldDeviceUnavailable");
NSLog(@"Headphone/Line was pulled. Resuming video play....");
- if (_is_video_playing) {
+ if (_is_video_playing()) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.5f * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
[_instance.avPlayer play]; // NOTE: change this line according your current player implementation
diff --git a/platform/iphone/globals/global_defaults.cpp b/platform/iphone/globals/global_defaults.cpp
index a4929c57dc..18a51a5b4e 100644..100755
--- a/platform/iphone/globals/global_defaults.cpp
+++ b/platform/iphone/globals/global_defaults.cpp
@@ -9,4 +9,5 @@ void register_iphone_global_defaults() {
GLOBAL_DEF("rasterizer.iOS/fp16_framebuffer",false);
GLOBAL_DEF("display.iOS/driver","GLES2");
Globals::get_singleton()->set_custom_property_info("display.iOS/driver",PropertyInfo(Variant::STRING,"display.iOS/driver",PROPERTY_HINT_ENUM,"GLES1,GLES2"));
+ GLOBAL_DEF("display.iOS/use_cadisplaylink",true);
}
diff --git a/platform/iphone/godot_iphone.cpp b/platform/iphone/godot_iphone.cpp
index b7b9b747b4..2ecfe1545e 100644
--- a/platform/iphone/godot_iphone.cpp
+++ b/platform/iphone/godot_iphone.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -40,6 +40,8 @@ int add_path(int p_argc, char** p_args);
int add_cmdline(int p_argc, char** p_args);
};
+int iphone_main(int, int, int, char**);
+
int iphone_main(int width, int height, int argc, char** argv) {
int len = strlen(argv[0]);
diff --git a/platform/iphone/icloud.h b/platform/iphone/icloud.h
new file mode 100644
index 0000000000..c772555835
--- /dev/null
+++ b/platform/iphone/icloud.h
@@ -0,0 +1,66 @@
+/*************************************************************************/
+/* icloud.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
+#ifdef ICLOUD_ENABLED
+
+#ifndef ICLOUD_H
+#define ICLOUD_H
+
+#include "core/object.h"
+
+
+class ICloud : public Object {
+
+ OBJ_TYPE(ICloud, Object);
+
+ static ICloud* instance;
+ static void _bind_methods();
+
+ List<Variant> pending_events;
+
+public:
+
+ Error remove_key(Variant p_param);
+ Variant set_key_values(Variant p_param);
+ Variant get_key_value(Variant p_param);
+ Error synchronize_key_values();
+ Variant get_all_key_values();
+
+ int get_pending_event_count();
+ Variant pop_pending_event();
+
+ static ICloud* get_singleton();
+
+ ICloud();
+ ~ICloud();
+};
+
+
+#endif
+
+#endif
diff --git a/platform/iphone/icloud.mm b/platform/iphone/icloud.mm
new file mode 100644
index 0000000000..449670667f
--- /dev/null
+++ b/platform/iphone/icloud.mm
@@ -0,0 +1,385 @@
+/*************************************************************************/
+/* icloud.mm */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
+#ifdef ICLOUD_ENABLED
+
+#include "icloud.h"
+
+#ifndef __IPHONE_9_0
+extern "C" {
+#endif
+
+#import <Foundation/Foundation.h>
+#import "app_delegate.h"
+
+#ifndef __IPHONE_9_0
+};
+#endif
+
+ICloud* ICloud::instance = NULL;
+
+void ICloud::_bind_methods() {
+ ObjectTypeDB::bind_method(_MD("remove_key"),&ICloud::remove_key);
+ ObjectTypeDB::bind_method(_MD("set_key_values"),&ICloud::set_key_values);
+ ObjectTypeDB::bind_method(_MD("get_key_value"),&ICloud::get_key_value);
+ ObjectTypeDB::bind_method(_MD("synchronize_key_values"),&ICloud::synchronize_key_values);
+ ObjectTypeDB::bind_method(_MD("get_all_key_values"),&ICloud::get_all_key_values);
+
+ ObjectTypeDB::bind_method(_MD("get_pending_event_count"),&ICloud::get_pending_event_count);
+ ObjectTypeDB::bind_method(_MD("pop_pending_event"),&ICloud::pop_pending_event);
+};
+
+int ICloud::get_pending_event_count() {
+
+ return pending_events.size();
+};
+
+Variant ICloud::pop_pending_event() {
+
+ Variant front = pending_events.front()->get();
+ pending_events.pop_front();
+
+ return front;
+};
+
+ICloud* ICloud::get_singleton() {
+ return instance;
+};
+
+//convert from apple's abstract type to godot's abstract type....
+Variant nsobject_to_variant(NSObject* object) {
+ if ([object isKindOfClass:[NSString class]]) {
+ const char* str = [(NSString*)object UTF8String];
+ return String::utf8(str != NULL ? str : "");
+ }
+ else if ([object isKindOfClass:[NSData class]]) {
+ ByteArray ret;
+ NSData* data = (NSData*)object;
+ if ([data length] > 0) {
+ ret.resize([data length]);
+ {
+ ByteArray::Write w = ret.write();
+ copymem(w.ptr(), [data bytes], [data length]);
+ }
+ }
+ return ret;
+ }
+ else if ([object isKindOfClass:[NSArray class]]) {
+ Array result;
+ NSArray* array = (NSArray*)object;
+ for (unsigned int i = 0; i < [array count]; ++i) {
+ NSObject* value = [array objectAtIndex:i];
+ result.push_back(nsobject_to_variant(value));
+ }
+ return result;
+ }
+ else if ([object isKindOfClass:[NSDictionary class]]) {
+ Dictionary result;
+ NSDictionary* dic = (NSDictionary*)object;
+
+
+ NSArray* keys = [dic allKeys];
+ int count = [keys count];
+ for (int i=0; i < count; ++i) {
+ NSObject* k = [ keys objectAtIndex:i];
+ NSObject* v = [dic objectForKey:k];
+
+ result[nsobject_to_variant(k)] = nsobject_to_variant(v);
+ }
+ return result;
+ }
+ else if ([object isKindOfClass:[NSNumber class]]) {
+ //Every type except numbers can reliably identify its type. The following is comparing to the *internal* representation, which isn't guaranteed to match the type that was used to create it, and is not advised, particularly when dealing with potential platform differences (ie, 32/64 bit)
+ //To avoid errors, we'll cast as broadly as possible, and only return int or float.
+ //bool, char, int, uint, longlong -> int
+ //float, double -> float
+ NSNumber* num = (NSNumber*)object;
+ if(strcmp([num objCType], @encode(BOOL)) == 0) {
+ return Variant((int)[num boolValue]);
+ }
+ else if(strcmp([num objCType], @encode(char)) == 0) {
+ return Variant((int)[num charValue]);
+ }
+ else if(strcmp([num objCType], @encode(int)) == 0) {
+ return Variant([num intValue]);
+ }
+ else if(strcmp([num objCType], @encode(unsigned int)) == 0) {
+ return Variant((int)[num unsignedIntValue]);
+ }
+ else if(strcmp([num objCType], @encode(long long)) == 0) {
+ return Variant((int)[num longValue]);
+ }
+ else if(strcmp([num objCType], @encode(float)) == 0) {
+ return Variant([num floatValue]);
+ }
+ else if(strcmp([num objCType], @encode(double)) == 0) {
+ return Variant((float)[num doubleValue]);
+ }
+ }
+ else if ([object isKindOfClass:[NSDate class]]) {
+ //this is a type that icloud supports...but how did you submit it in the first place?
+ //I guess this is a type that *might* show up, if you were, say, trying to make your game
+ //compatible with existing cloud data written by another engine's version of your game
+ WARN_PRINT("NSDate unsupported, returning null Variant")
+ return Variant();
+ }
+ else if ([object isKindOfClass:[NSNull class]] or object == nil) {
+ return Variant();
+ }
+ else {
+ WARN_PRINT("Trying to convert unknown NSObject type to Variant");
+ return Variant();
+ }
+}
+
+NSObject* variant_to_nsobject(Variant v) {
+ if (v.get_type() == Variant::STRING) {
+ return [[[NSString alloc] initWithUTF8String:((String)v).utf8().get_data()] autorelease];
+ }
+ else if (v.get_type() == Variant::REAL) {
+ return [NSNumber numberWithDouble:(double)v];
+ }
+ else if (v.get_type() == Variant::INT) {
+ return [NSNumber numberWithLongLong:(long)(int)v];
+ }
+ else if (v.get_type() == Variant::BOOL) {
+ return [NSNumber numberWithBool:BOOL((bool)v)];
+ }
+ else if (v.get_type() == Variant::DICTIONARY) {
+ NSMutableDictionary* result = [[[NSMutableDictionary alloc] init] autorelease];
+ Dictionary dic = v;
+ Array keys = dic.keys();
+ for (unsigned int i = 0; i < keys.size(); ++i) {
+ NSString* key = [[[NSString alloc] initWithUTF8String:((String)(keys[i])).utf8().get_data()] autorelease];
+ NSObject* value = variant_to_nsobject(dic[keys[i]]);
+
+ if (key == NULL || value == NULL) {
+ return NULL;
+ }
+
+ [result setObject:value forKey:key];
+ }
+ return result;
+ }
+ else if (v.get_type() == Variant::ARRAY) {
+ NSMutableArray* result = [[[NSMutableArray alloc] init] autorelease];
+ Array arr = v;
+ for (unsigned int i = 0; i < arr.size(); ++i) {
+ NSObject* value = variant_to_nsobject(arr[i]);
+ if (value == NULL) {
+ //trying to add something unsupported to the array. cancel the whole array
+ return NULL;
+ }
+ [result addObject:value];
+ }
+ return result;
+ }
+ else if (v.get_type() == Variant::RAW_ARRAY) {
+ ByteArray arr = v;
+ ByteArray::Read r = arr.read();
+ NSData* result = [NSData dataWithBytes:r.ptr() length:arr.size()];
+ return result;
+ }
+ WARN_PRINT(String("Could not add unsupported type to iCloud: '" + Variant::get_type_name(v.get_type())+"'").utf8().get_data());
+ return NULL;
+}
+
+
+Error ICloud::remove_key(Variant p_param) {
+ String param = p_param;
+ NSString* key = [[[NSString alloc] initWithUTF8String:param.utf8().get_data()] autorelease];
+
+ NSUbiquitousKeyValueStore *store = [NSUbiquitousKeyValueStore defaultStore];
+
+ if (![[store dictionaryRepresentation] objectForKey:key]) {
+ return ERR_INVALID_PARAMETER;
+ }
+
+ [store removeObjectForKey:key];
+ return OK;
+}
+
+//return an array of the keys that could not be set
+Variant ICloud::set_key_values(Variant p_params) {
+ Dictionary params = p_params;
+ Array keys = params.keys();
+
+ Array error_keys;
+
+ for (unsigned int i = 0; i < keys.size(); ++i) {
+ String variant_key = keys[i];
+ Variant variant_value = params[variant_key];
+
+ NSString* key = [[[NSString alloc] initWithUTF8String:variant_key.utf8().get_data()] autorelease];
+ if (key == NULL) {
+ error_keys.push_back(variant_key);
+ continue;
+ }
+
+ NSObject* value = variant_to_nsobject(variant_value);
+
+ if (value == NULL) {
+ error_keys.push_back(variant_key);
+ continue;
+ }
+
+ NSUbiquitousKeyValueStore *store = [NSUbiquitousKeyValueStore defaultStore];
+ [store setObject:value forKey:key];
+ }
+
+ return error_keys;
+}
+
+Variant ICloud::get_key_value(Variant p_param) {
+ String param = p_param;
+
+ NSString* key = [[[NSString alloc] initWithUTF8String:param.utf8().get_data()] autorelease];
+ NSUbiquitousKeyValueStore *store = [NSUbiquitousKeyValueStore defaultStore];
+
+ if (![[store dictionaryRepresentation] objectForKey:key]) {
+ return Variant();
+ }
+
+ Variant result = nsobject_to_variant([[store dictionaryRepresentation] objectForKey:key]);
+
+ return result;
+}
+
+Variant ICloud::get_all_key_values() {
+ Dictionary result;
+
+ NSUbiquitousKeyValueStore* store = [NSUbiquitousKeyValueStore defaultStore];
+ NSDictionary* store_dictionary = [store dictionaryRepresentation];
+
+ NSArray* keys = [store_dictionary allKeys];
+ int count = [keys count];
+ for (int i=0; i < count; ++i) {
+ NSString* k = [ keys objectAtIndex:i];
+ NSObject* v = [store_dictionary objectForKey:k];
+
+ const char* str = [k UTF8String];
+ if (str != NULL) {
+ result[String::utf8(str)] = nsobject_to_variant(v);
+ }
+ }
+
+ return result;
+}
+
+Error ICloud::synchronize_key_values() {
+ NSUbiquitousKeyValueStore *store = [NSUbiquitousKeyValueStore defaultStore];
+ BOOL result = [store synchronize];
+ if (result == YES) {
+ return OK;
+ }
+ else {
+ return FAILED;
+ }
+}
+/*
+Error ICloud::initial_sync() {
+ //you sometimes have to write something to the store to get it to download new data. go apple!
+ NSUbiquitousKeyValueStore *store = [NSUbiquitousKeyValueStore defaultStore];
+ if ([store boolForKey:@"isb"])
+ {
+ [store setBool:NO forKey:@"isb"];
+ }
+ else
+ {
+ [store setBool:YES forKey:@"isb"];
+ }
+ return synchronize();
+}
+*/
+ICloud::ICloud() {
+ ERR_FAIL_COND(instance != NULL);
+ instance = this;
+ //connected = false;
+
+ [
+ //[NSNotificationCenter defaultCenter] addObserverForName: @"notify"
+ [NSNotificationCenter defaultCenter] addObserverForName: NSUbiquitousKeyValueStoreDidChangeExternallyNotification
+ object: [NSUbiquitousKeyValueStore defaultStore]
+ queue: nil
+ usingBlock: ^ (NSNotification * notification) {
+ NSDictionary* userInfo = [notification userInfo];
+ NSInteger change = [[userInfo objectForKey:NSUbiquitousKeyValueStoreChangeReasonKey] integerValue];
+
+ Dictionary ret;
+ ret["type"] = "key_value_changed";
+
+ //StringArray result_keys;
+ //Array result_values;
+ Dictionary keyValues;
+ String reason = "";
+
+ if (change == NSUbiquitousKeyValueStoreServerChange) {
+ reason = "server";
+ }
+ else if (change == NSUbiquitousKeyValueStoreInitialSyncChange) {
+ reason = "initial_sync";
+ }
+ else if (change == NSUbiquitousKeyValueStoreQuotaViolationChange) {
+ reason = "quota_violation";
+ }
+ else if (change == NSUbiquitousKeyValueStoreAccountChange) {
+ reason = "account";
+ }
+
+ ret["reason"] = reason;
+
+
+ NSUbiquitousKeyValueStore *store = [NSUbiquitousKeyValueStore defaultStore];
+
+ NSArray * keys = [userInfo objectForKey:NSUbiquitousKeyValueStoreChangedKeysKey];
+ for (NSString* key in keys) {
+ const char* str = [key UTF8String];
+ if (str == NULL) {
+ continue;
+ }
+
+ NSObject* object = [store objectForKey:key];
+
+ //figure out what kind of object it is
+ Variant value = nsobject_to_variant(object);
+
+ keyValues[String::utf8(str)] = value;
+ }
+
+ ret["changed_values"] = keyValues;
+ pending_events.push_back(ret);
+ }
+ ];
+}
+
+
+ICloud::~ICloud() {
+
+};
+
+#endif
diff --git a/platform/iphone/in_app_store.h b/platform/iphone/in_app_store.h
index 585cd19538..bd4215231e 100644
--- a/platform/iphone/in_app_store.h
+++ b/platform/iphone/in_app_store.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/iphone/in_app_store.mm b/platform/iphone/in_app_store.mm
index e3ba6bbd73..fec007b7b6 100644
--- a/platform/iphone/in_app_store.mm
+++ b/platform/iphone/in_app_store.mm
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -28,6 +28,10 @@
/*************************************************************************/
#ifdef STOREKIT_ENABLED
+#ifdef MODULE_FUSEBOXX_ENABLED
+#import "modules/fuseboxx/ios/FuseSDK.h"
+#endif
+
#include "in_app_store.h"
extern "C" {
@@ -222,6 +226,11 @@ Error InAppStore::request_product_info(Variant p_params) {
else{
[pending_transactions setObject:transaction forKey:transaction.payment.productIdentifier];
}
+
+ #ifdef MODULE_FUSEBOXX_ENABLED
+ printf("Registering transaction on Fuseboxx!\n");
+ [FuseSDK registerInAppPurchase: transaction];
+ #endif
} break;
case SKPaymentTransactionStateFailed: {
printf("status transaction failed!\n");
diff --git a/platform/iphone/os_iphone.cpp b/platform/iphone/os_iphone.cpp
index ade1c292a4..ec62cb5c26 100644
--- a/platform/iphone/os_iphone.cpp
+++ b/platform/iphone/os_iphone.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -160,6 +160,12 @@ void OSIPhone::initialize(const VideoMode& p_desired,int p_video_driver,int p_au
store_kit = memnew(InAppStore);
Globals::get_singleton()->add_singleton(Globals::Singleton("InAppStore", store_kit));
#endif
+
+#ifdef ICLOUD_ENABLED
+ icloud = memnew(ICloud);
+ Globals::get_singleton()->add_singleton(Globals::Singleton("ICloud", icloud));
+ //icloud->connect();
+#endif
};
MainLoop *OSIPhone::get_main_loop() const {
@@ -220,6 +226,8 @@ void OSIPhone::mouse_button(int p_idx, int p_x, int p_y, bool p_pressed, bool p_
queue_event(ev);
};
+ mouse_list.pressed[p_idx] = p_pressed;
+
if (p_use_as_mouse) {
InputEvent ev;
@@ -234,13 +242,13 @@ void OSIPhone::mouse_button(int p_idx, int p_x, int p_y, bool p_pressed, bool p_
ev.mouse_button.x = ev.mouse_button.global_x = p_x;
ev.mouse_button.y = ev.mouse_button.global_y = p_y;
+ //mouse_list.pressed[p_idx] = p_pressed;
+
input->set_mouse_pos(Point2(ev.mouse_motion.x,ev.mouse_motion.y));
ev.mouse_button.button_index = BUTTON_LEFT;
ev.mouse_button.doubleclick = p_doubleclick;
ev.mouse_button.pressed = p_pressed;
- mouse_list.pressed[p_idx] = p_pressed;
-
queue_event(ev);
};
};
@@ -446,6 +454,7 @@ bool OSIPhone::has_virtual_keyboard() const {
extern void _show_keyboard(String p_existing);
extern void _hide_keyboard();
extern Error _shell_open(String p_uri);
+extern void _set_keep_screen_on(bool p_enabled);
void OSIPhone::show_virtual_keyboard(const String& p_existing_text,const Rect2& p_screen_rect) {
_show_keyboard(p_existing_text);
@@ -459,6 +468,10 @@ Error OSIPhone::shell_open(String p_uri) {
return _shell_open(p_uri);
};
+void OSIPhone::set_keep_screen_on(bool p_enabled) {
+ OS::set_keep_screen_on(p_enabled);
+ _set_keep_screen_on(p_enabled);
+};
void OSIPhone::set_cursor_shape(CursorShape p_shape) {
diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h
index 844f067552..abe797fed1 100644
--- a/platform/iphone/os_iphone.h
+++ b/platform/iphone/os_iphone.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -43,8 +43,11 @@
#include "servers/audio/sample_manager_sw.h"
#include "servers/spatial_sound/spatial_sound_server_sw.h"
#include "servers/spatial_sound_2d/spatial_sound_2d_server_sw.h"
+#include "main/input_default.h"
#include "game_center.h"
#include "in_app_store.h"
+#include "icloud.h"
+
class AudioDriverIphone;
class RasterizerGLES2;
@@ -88,6 +91,9 @@ private:
#ifdef STOREKIT_ENABLED
InAppStore* store_kit;
#endif
+#ifdef ICLOUD_ENABLED
+ ICloud* icloud;
+#endif
MainLoop *main_loop;
@@ -160,6 +166,8 @@ public:
virtual void set_video_mode(const VideoMode& p_video_mode,int p_screen=0);
virtual VideoMode get_video_mode(int p_screen=0) const;
virtual void get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen=0) const;
+
+ virtual void set_keep_screen_on(bool p_enabled);
virtual bool can_draw() const;
diff --git a/platform/iphone/platform_config.h b/platform/iphone/platform_config.h
index 3cc74099c0..e40f670185 100644
--- a/platform/iphone/platform_config.h
+++ b/platform/iphone/platform_config.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,3 +31,5 @@
#define PLATFORM_REFCOUNT
+
+#define PTHREAD_RENAME_SELF
diff --git a/platform/iphone/rasterizer_iphone.cpp b/platform/iphone/rasterizer_iphone.cpp
index d2a0777af8..29364d091a 100644
--- a/platform/iphone/rasterizer_iphone.cpp
+++ b/platform/iphone/rasterizer_iphone.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/iphone/rasterizer_iphone.h b/platform/iphone/rasterizer_iphone.h
index 2a630e597a..add656b190 100644
--- a/platform/iphone/rasterizer_iphone.h
+++ b/platform/iphone/rasterizer_iphone.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/iphone/sem_iphone.cpp b/platform/iphone/sem_iphone.cpp
index 5afaa7b308..e9c54a002e 100644
--- a/platform/iphone/sem_iphone.cpp
+++ b/platform/iphone/sem_iphone.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,6 +31,11 @@
#include <unistd.h>
#include <fcntl.h>
+void cgsem_init(cgsem_t*);
+void cgsem_post(cgsem_t*);
+void cgsem_wait(cgsem_t*);
+void cgsem_destroy(cgsem_t*);
+
void cgsem_init(cgsem_t *cgsem)
{
int flags, fd, i;
diff --git a/platform/iphone/sem_iphone.h b/platform/iphone/sem_iphone.h
index 7a57b5dd99..bfeaf244e5 100644
--- a/platform/iphone/sem_iphone.h
+++ b/platform/iphone/sem_iphone.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/iphone/view_controller.h b/platform/iphone/view_controller.h
index 0cee2f6fbf..52c8ac9953 100644
--- a/platform/iphone/view_controller.h
+++ b/platform/iphone/view_controller.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/iphone/view_controller.mm b/platform/iphone/view_controller.mm
index bc9950979e..647ded30a7 100644
--- a/platform/iphone/view_controller.mm
+++ b/platform/iphone/view_controller.mm
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,6 +32,9 @@
extern "C" {
+int add_path(int, char**);
+int add_cmdline(int, char**);
+
int add_path(int p_argc, char** p_args) {
NSString* str = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"godot_path"];
@@ -129,10 +132,12 @@ int add_cmdline(int p_argc, char** p_args) {
return YES;
}
+#ifdef GAME_CENTER_ENABLED
- (void) gameCenterViewControllerDidFinish:(GKGameCenterViewController*) gameCenterViewController {
//[gameCenterViewController dismissViewControllerAnimated:YES completion:^{GameCenter::get_singleton()->game_center_closed();}];//version for signaling when overlay is completely gone
GameCenter::get_singleton()->game_center_closed();
[gameCenterViewController dismissViewControllerAnimated:YES completion:nil];
}
+#endif
@end
diff --git a/platform/isim/detect.py b/platform/isim/detect.py
index bd0fd2fea3..0adbd9f413 100644
--- a/platform/isim/detect.py
+++ b/platform/isim/detect.py
@@ -21,8 +21,8 @@ def get_opts():
return [
('ISIMPLATFORM', 'name of the iphone platform', 'iPhoneSimulator'),
- ('ISIMPATH', 'the path to iphone toolchain', '/Applications/Xcode.app/Contents/Developer/Platforms/${ISIMPLATFORM}.platform'),
- ('ISIMSDK', 'path to the iphone SDK', '$ISIMPATH/Developer/SDKs/${ISIMPLATFORM}.sdk'),
+ ('ISIMPATH', 'the path to iphone toolchain', '/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain'),
+ ('ISIMSDK', 'path to the iphone SDK', '/Applications/Xcode.app/Contents/Developer/Platforms/${ISIMPLATFORM}.platform/Developer/SDKs/${ISIMPLATFORM}.sdk'),
('game_center', 'Support for game center', 'yes'),
('store_kit', 'Support for in-app store', 'yes'),
('ios_gles22_override', 'Force GLES2.0 on iOS', 'yes'),
@@ -46,9 +46,10 @@ def configure(env):
env['ENV']['PATH'] = env['ISIMPATH']+"/Developer/usr/bin/:"+env['ENV']['PATH']
- env['CC'] = '$ISIMPATH/Developer/usr/bin/gcc'
- env['CXX'] = '$ISIMPATH/Developer/usr/bin/g++'
- env['AR'] = 'ar'
+ env['CC'] = '$ISIMPATH/usr/bin/${ios_triple}clang'
+ env['CXX'] = '$ISIMPATH/usr/bin/${ios_triple}clang++'
+ env['AR'] = '$ISIMPATH/usr/bin/${ios_triple}ar'
+ env['RANLIB'] = '$ISIMPATH/usr/bin/${ios_triple}ranlib'
import string
env['CCFLAGS'] = string.split('-arch i386 -fobjc-abi-version=2 -fobjc-legacy-dispatch -fmessage-length=0 -fpascal-strings -fasm-blocks -Wall -D__IPHONE_OS_VERSION_MIN_REQUIRED=40100 -isysroot $ISIMSDK -mios-simulator-version-min=4.3 -DCUSTOM_MATRIX_TRANSFORM_H=\\\"build/iphone/matrix4_iphone.h\\\" -DCUSTOM_VECTOR3_TRANSFORM_H=\\\"build/iphone/vector3_iphone.h\\\"')
@@ -97,4 +98,8 @@ def configure(env):
env['ENV']['CODESIGN_ALLOCATE'] = '/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/codesign_allocate'
env.Append(CPPFLAGS=['-DIPHONE_ENABLED', '-DUNIX_ENABLED', '-DGLES2_ENABLED', '-fexceptions'])
+ import methods
+ env.Append( BUILDERS = { 'GLSL120' : env.Builder(action = methods.build_legacygl_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
+ env.Append( BUILDERS = { 'GLSL' : env.Builder(action = methods.build_glsl_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
+ env.Append( BUILDERS = { 'GLSL120GLES' : env.Builder(action = methods.build_gles2_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
diff --git a/platform/javascript/SCsub b/platform/javascript/SCsub
index c1ba0c2283..cd96cf4f31 100644
--- a/platform/javascript/SCsub
+++ b/platform/javascript/SCsub
@@ -3,7 +3,8 @@ Import('env')
javascript_files = [
"os_javascript.cpp",
"audio_driver_javascript.cpp",
- "javascript_main.cpp"
+ "javascript_main.cpp",
+ "audio_server_javascript.cpp"
]
#obj = env.SharedObject('godot_javascript.cpp')
@@ -16,6 +17,8 @@ javascript_objects=[]
for x in javascript_files:
javascript_objects.append( env_javascript.Object( x ) )
+env.Append(LINKFLAGS=["-s","EXPORTED_FUNCTIONS=\"['_main','_audio_server_mix_function','_main_after_fs_sync']\""])
+
prog = None
#env_javascript.SharedLibrary("#platform/javascript/libgodot_javascript.so",[javascript_objects])
diff --git a/platform/javascript/audio_driver_javascript.cpp b/platform/javascript/audio_driver_javascript.cpp
index cc053cf136..1b949e64f9 100644
--- a/platform/javascript/audio_driver_javascript.cpp
+++ b/platform/javascript/audio_driver_javascript.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/javascript/audio_driver_javascript.h b/platform/javascript/audio_driver_javascript.h
index 0356ca87f9..c674a8566e 100644
--- a/platform/javascript/audio_driver_javascript.h
+++ b/platform/javascript/audio_driver_javascript.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/javascript/audio_server_javascript.cpp b/platform/javascript/audio_server_javascript.cpp
new file mode 100644
index 0000000000..fbd5d2e1c0
--- /dev/null
+++ b/platform/javascript/audio_server_javascript.cpp
@@ -0,0 +1,805 @@
+#include "audio_server_javascript.h"
+
+#include "emscripten.h"
+
+AudioMixer *AudioServerJavascript::get_mixer() {
+
+ return NULL;
+}
+
+void AudioServerJavascript::audio_mixer_chunk_callback(int p_frames){
+
+
+}
+
+
+RID AudioServerJavascript::sample_create(SampleFormat p_format, bool p_stereo, int p_length) {
+
+ Sample *sample = memnew( Sample );
+ sample->format=p_format;
+ sample->stereo=p_stereo;
+ sample->length=p_length;
+ sample->loop_begin=0;
+ sample->loop_end=p_length;
+ sample->loop_format=SAMPLE_LOOP_NONE;
+ sample->mix_rate=44100;
+ sample->index=-1;
+
+ return sample_owner.make_rid(sample);
+
+}
+
+void AudioServerJavascript::sample_set_description(RID p_sample, const String& p_description){
+
+
+}
+String AudioServerJavascript::sample_get_description(RID p_sample) const{
+
+ return String();
+}
+
+AudioServerJavascript::SampleFormat AudioServerJavascript::sample_get_format(RID p_sample) const{
+
+ return SAMPLE_FORMAT_PCM8;
+}
+bool AudioServerJavascript::sample_is_stereo(RID p_sample) const{
+
+ const Sample *sample = sample_owner.get(p_sample);
+ ERR_FAIL_COND_V(!sample,false);
+ return sample->stereo;
+
+}
+int AudioServerJavascript::sample_get_length(RID p_sample) const{
+ const Sample *sample = sample_owner.get(p_sample);
+ ERR_FAIL_COND_V(!sample,0);
+ return sample->length;
+}
+const void* AudioServerJavascript::sample_get_data_ptr(RID p_sample) const{
+
+ return NULL;
+}
+
+void AudioServerJavascript::sample_set_data(RID p_sample, const DVector<uint8_t>& p_buffer){
+
+ Sample *sample = sample_owner.get(p_sample);
+ ERR_FAIL_COND(!sample);
+ int chans = sample->stereo?2:1;
+
+ Vector<float> buffer;
+ buffer.resize(sample->length*chans);
+ DVector<uint8_t>::Read r=p_buffer.read();
+ if (sample->format==SAMPLE_FORMAT_PCM8) {
+ const int8_t*ptr = (const int8_t*)r.ptr();
+ for(int i=0;i<sample->length*chans;i++) {
+ buffer[i]=ptr[i]/128.0;
+ }
+ } else if (sample->format==SAMPLE_FORMAT_PCM16){
+ const int16_t*ptr = (const int16_t*)r.ptr();
+ for(int i=0;i<sample->length*chans;i++) {
+ buffer[i]=ptr[i]/32768.0;
+ }
+ } else {
+ ERR_EXPLAIN("Unsupported for now");
+ ERR_FAIL();
+ }
+
+ sample->tmp_data=buffer;
+
+
+
+}
+const DVector<uint8_t> AudioServerJavascript::sample_get_data(RID p_sample) const{
+
+
+ return DVector<uint8_t>();
+}
+
+void AudioServerJavascript::sample_set_mix_rate(RID p_sample,int p_rate){
+ Sample *sample = sample_owner.get(p_sample);
+ ERR_FAIL_COND(!sample);
+ sample->mix_rate=p_rate;
+
+}
+
+int AudioServerJavascript::sample_get_mix_rate(RID p_sample) const{
+ const Sample *sample = sample_owner.get(p_sample);
+ ERR_FAIL_COND_V(!sample,0);
+ return sample->mix_rate;
+}
+
+
+void AudioServerJavascript::sample_set_loop_format(RID p_sample,SampleLoopFormat p_format){
+
+ Sample *sample = sample_owner.get(p_sample);
+ ERR_FAIL_COND(!sample);
+ sample->loop_format=p_format;
+
+}
+
+AudioServerJavascript::SampleLoopFormat AudioServerJavascript::sample_get_loop_format(RID p_sample) const {
+
+ const Sample *sample = sample_owner.get(p_sample);
+ ERR_FAIL_COND_V(!sample,SAMPLE_LOOP_NONE);
+ return sample->loop_format;
+}
+
+void AudioServerJavascript::sample_set_loop_begin(RID p_sample,int p_pos){
+
+ Sample *sample = sample_owner.get(p_sample);
+ ERR_FAIL_COND(!sample);
+ sample->loop_begin=p_pos;
+
+}
+int AudioServerJavascript::sample_get_loop_begin(RID p_sample) const{
+
+ const Sample *sample = sample_owner.get(p_sample);
+ ERR_FAIL_COND_V(!sample,0);
+ return sample->loop_begin;
+}
+
+void AudioServerJavascript::sample_set_loop_end(RID p_sample,int p_pos){
+
+ Sample *sample = sample_owner.get(p_sample);
+ ERR_FAIL_COND(!sample);
+ sample->loop_end=p_pos;
+
+}
+int AudioServerJavascript::sample_get_loop_end(RID p_sample) const{
+
+ const Sample *sample = sample_owner.get(p_sample);
+ ERR_FAIL_COND_V(!sample,0);
+ return sample->loop_end;
+}
+
+
+/* VOICE API */
+
+RID AudioServerJavascript::voice_create(){
+
+ Voice *voice = memnew( Voice );
+
+ voice->index=voice_base;
+ voice->volume=1.0;
+ voice->pan=0.0;
+ voice->pan_depth=.0;
+ voice->pan_height=0.0;
+ voice->chorus=0;
+ voice->reverb_type=REVERB_SMALL;
+ voice->reverb=0;
+ voice->mix_rate=-1;
+ voice->positional=false;
+ voice->active=false;
+
+ EM_ASM_( {
+ _as_voices[$0]=null;
+ _as_voice_gain[$0]=_as_audioctx.createGain();
+ _as_voice_pan[$0]=_as_audioctx.createStereoPanner();
+ _as_voice_gain[$0].connect(_as_voice_pan[$0]);
+ _as_voice_pan[$0].connect(_as_audioctx.destination);
+
+ },voice_base);
+
+ voice_base++;
+
+ return voice_owner.make_rid( voice );
+}
+
+void AudioServerJavascript::voice_play(RID p_voice, RID p_sample){
+
+ Voice* voice=voice_owner.get(p_voice);
+ ERR_FAIL_COND(!voice);
+ Sample *sample=sample_owner.get(p_sample);
+ ERR_FAIL_COND(!sample);
+
+ // due to how webaudio works, sample cration is deferred until used
+ // sorry! WebAudio absolutely sucks
+
+
+ if (sample->index==-1) {
+ //create sample if not created
+ ERR_FAIL_COND(sample->tmp_data.size()==0);
+ sample->index=sample_base;
+ EM_ASM_( {
+ _as_samples[$0]=_as_audioctx.createBuffer($1,$2,$3);
+ },sample_base,sample->stereo?2:1,sample->length,sample->mix_rate);
+
+ sample_base++;
+ int chans = sample->stereo?2:1;
+
+
+ for(int i=0;i<chans;i++) {
+
+
+ EM_ASM_({
+ _as_edited_buffer=_as_samples[$0].getChannelData($1);
+ },sample->index,i);
+
+
+ for(int j=0;j<sample->length;j++) {
+
+ EM_ASM_({
+ _as_edited_buffer[$0]=$1;
+ },j,sample->tmp_data[j*chans+i]);
+ }
+ }
+
+ sample->tmp_data.clear();
+ }
+
+
+ voice->sample_mix_rate=sample->mix_rate;
+ if (voice->mix_rate==-1) {
+ voice->mix_rate=voice->sample_mix_rate;
+ }
+
+ float freq_diff = Math::log(float(voice->mix_rate)/float(voice->sample_mix_rate))/Math::log(2.0);
+ int detune = int(freq_diff*1200.0);
+
+ EM_ASM_( {
+ if (_as_voices[$0]!==null) {
+ _as_voices[$0].stop(); //stop and byebye
+ }
+ _as_voices[$0]=_as_audioctx.createBufferSource();
+ _as_voices[$0].connect(_as_voice_gain[$0]);
+ _as_voices[$0].buffer=_as_samples[$1];
+ _as_voices[$0].loopStart.value=$1;
+ _as_voices[$0].loopEnd.value=$2;
+ _as_voices[$0].loop.value=$3;
+ _as_voices[$0].detune.value=$6;
+ _as_voice_pan[$0].pan.value=$4;
+ _as_voice_gain[$0].gain.value=$5;
+ _as_voices[$0].start();
+ _as_voices[$0].onended=function() {
+ _as_voices[$0].disconnect(_as_voice_gain[$0]);
+ _as_voices[$0]=null;
+ }
+
+ },voice->index,sample->index,sample->mix_rate*sample->loop_begin,sample->mix_rate*sample->loop_end,sample->loop_format!=SAMPLE_LOOP_NONE,voice->pan,voice->volume*fx_volume_scale,detune);
+
+ voice->active=true;
+}
+
+void AudioServerJavascript::voice_set_volume(RID p_voice, float p_volume){
+
+ Voice* voice=voice_owner.get(p_voice);
+ ERR_FAIL_COND(!voice);
+
+ voice->volume=p_volume;
+
+ if (voice->active) {
+ EM_ASM_( {
+
+ _as_voice_gain[$0].gain.value=$1;
+
+ },voice->index,voice->volume*fx_volume_scale);
+ }
+
+}
+void AudioServerJavascript::voice_set_pan(RID p_voice, float p_pan, float p_depth,float height){
+
+ Voice* voice=voice_owner.get(p_voice);
+ ERR_FAIL_COND(!voice);
+
+ voice->pan=p_pan;
+ voice->pan_depth=p_depth;
+ voice->pan_height=height;
+
+ if (voice->active) {
+ EM_ASM_( {
+
+ _as_voice_pan[$0].pan.value=$1;
+
+ },voice->index,voice->pan);
+ }
+}
+void AudioServerJavascript::voice_set_filter(RID p_voice, FilterType p_type, float p_cutoff, float p_resonance, float p_gain){
+
+}
+void AudioServerJavascript::voice_set_chorus(RID p_voice, float p_chorus ){
+
+}
+void AudioServerJavascript::voice_set_reverb(RID p_voice, ReverbRoomType p_room_type, float p_reverb){
+
+}
+void AudioServerJavascript::voice_set_mix_rate(RID p_voice, int p_mix_rate){
+
+ Voice* voice=voice_owner.get(p_voice);
+ ERR_FAIL_COND(!voice);
+
+ voice->mix_rate=p_mix_rate;
+
+ if (voice->active) {
+
+ float freq_diff = Math::log(float(voice->mix_rate)/float(voice->sample_mix_rate))/Math::log(2.0);
+ int detune = int(freq_diff*1200.0);
+ EM_ASM_( {
+
+ _as_voices[$0].detune.value=$1;
+
+ },voice->index,detune);
+ }
+}
+void AudioServerJavascript::voice_set_positional(RID p_voice, bool p_positional){
+
+}
+
+float AudioServerJavascript::voice_get_volume(RID p_voice) const{
+
+ Voice* voice=voice_owner.get(p_voice);
+ ERR_FAIL_COND_V(!voice,0);
+
+ return voice->volume;
+}
+float AudioServerJavascript::voice_get_pan(RID p_voice) const{
+
+ Voice* voice=voice_owner.get(p_voice);
+ ERR_FAIL_COND_V(!voice,0);
+
+ return voice->pan;
+}
+float AudioServerJavascript::voice_get_pan_depth(RID p_voice) const{
+ Voice* voice=voice_owner.get(p_voice);
+ ERR_FAIL_COND_V(!voice,0);
+
+ return voice->pan_depth;
+}
+float AudioServerJavascript::voice_get_pan_height(RID p_voice) const{
+
+ Voice* voice=voice_owner.get(p_voice);
+ ERR_FAIL_COND_V(!voice,0);
+
+ return voice->pan_height;
+}
+AudioServerJavascript::FilterType AudioServerJavascript::voice_get_filter_type(RID p_voice) const{
+
+ return FILTER_NONE;
+}
+float AudioServerJavascript::voice_get_filter_cutoff(RID p_voice) const{
+
+ return 0;
+}
+float AudioServerJavascript::voice_get_filter_resonance(RID p_voice) const{
+
+ return 0;
+}
+float AudioServerJavascript::voice_get_chorus(RID p_voice) const{
+
+ return 0;
+}
+AudioServerJavascript::ReverbRoomType AudioServerJavascript::voice_get_reverb_type(RID p_voice) const{
+
+ return REVERB_SMALL;
+}
+float AudioServerJavascript::voice_get_reverb(RID p_voice) const{
+
+ return 0;
+}
+
+int AudioServerJavascript::voice_get_mix_rate(RID p_voice) const{
+
+ return 44100;
+}
+
+bool AudioServerJavascript::voice_is_positional(RID p_voice) const{
+
+ return false;
+}
+
+void AudioServerJavascript::voice_stop(RID p_voice){
+
+ Voice* voice=voice_owner.get(p_voice);
+ ERR_FAIL_COND(!voice);
+
+ if (voice->active) {
+
+ EM_ASM_( {
+ if (_as_voices[$0]!==null) {
+ _as_voices[$0].stop();
+ _as_voices[$0].disconnect(_as_voice_gain[$0]);
+ _as_voices[$0]=null;
+ }
+ },voice->index);
+
+ voice->active=false;
+ }
+
+
+}
+bool AudioServerJavascript::voice_is_active(RID p_voice) const{
+ Voice* voice=voice_owner.get(p_voice);
+ ERR_FAIL_COND_V(!voice,false);
+
+ return voice->active;
+}
+
+/* STREAM API */
+
+RID AudioServerJavascript::audio_stream_create(AudioStream *p_stream) {
+
+
+ Stream *s = memnew(Stream);
+ s->audio_stream=p_stream;
+ s->event_stream=NULL;
+ s->active=false;
+ s->E=NULL;
+ s->volume_scale=1.0;
+ p_stream->set_mix_rate(webaudio_mix_rate);
+
+ return stream_owner.make_rid(s);
+}
+
+RID AudioServerJavascript::event_stream_create(EventStream *p_stream) {
+
+
+ Stream *s = memnew(Stream);
+ s->audio_stream=NULL;
+ s->event_stream=p_stream;
+ s->active=false;
+ s->E=NULL;
+ s->volume_scale=1.0;
+ //p_stream->set_mix_rate(AudioDriverJavascript::get_singleton()->get_mix_rate());
+
+ return stream_owner.make_rid(s);
+
+
+}
+
+
+void AudioServerJavascript::stream_set_active(RID p_stream, bool p_active) {
+
+
+ Stream *s = stream_owner.get(p_stream);
+ ERR_FAIL_COND(!s);
+
+ if (s->active==p_active)
+ return;
+
+ s->active=p_active;
+ if (p_active)
+ s->E=active_audio_streams.push_back(s);
+ else {
+ active_audio_streams.erase(s->E);
+ s->E=NULL;
+ }
+}
+
+bool AudioServerJavascript::stream_is_active(RID p_stream) const {
+
+ Stream *s = stream_owner.get(p_stream);
+ ERR_FAIL_COND_V(!s,false);
+ return s->active;
+}
+
+void AudioServerJavascript::stream_set_volume_scale(RID p_stream, float p_scale) {
+
+ Stream *s = stream_owner.get(p_stream);
+ ERR_FAIL_COND(!s);
+ s->volume_scale=p_scale;
+
+}
+
+float AudioServerJavascript::stream_set_volume_scale(RID p_stream) const {
+
+ Stream *s = stream_owner.get(p_stream);
+ ERR_FAIL_COND_V(!s,0);
+ return s->volume_scale;
+
+}
+
+
+/* Audio Physics API */
+
+void AudioServerJavascript::free(RID p_id){
+
+ if (voice_owner.owns(p_id)) {
+ Voice* voice=voice_owner.get(p_id);
+ ERR_FAIL_COND(!voice);
+
+ if (voice->active) {
+ EM_ASM_( {
+ if (_as_voices[$0]!==null) {
+ _as_voices[$0].stop();
+ _as_voices[$0].disconnect(_as_voice_gain[$0]);
+ }
+ },voice->index);
+ }
+
+ EM_ASM_( {
+ delete _as_voices[$0];
+ _as_voice_gain[$0].disconnect(_as_voice_pan[$0]);
+ delete _as_voice_gain[$0];
+ _as_voice_pan[$0].disconnect(_as_audioctx.destination);
+ delete _as_voice_pan[$0];
+
+ },voice->index);
+
+ voice_owner.free(p_id);
+ memdelete(voice);
+
+ } else if (sample_owner.owns(p_id)) {
+
+ Sample *sample = sample_owner.get(p_id);
+ ERR_FAIL_COND(!sample);
+
+ EM_ASM_( {
+ delete _as_samples[$0];
+
+ },sample->index);
+
+ sample_owner.free(p_id);
+ memdelete(sample);
+
+ } else if (stream_owner.owns(p_id)) {
+
+
+ Stream *s=stream_owner.get(p_id);
+
+ if (s->active) {
+ stream_set_active(p_id,false);
+ }
+
+ memdelete(s);
+ stream_owner.free(p_id);
+ }
+}
+
+extern "C" {
+
+
+void audio_server_mix_function(int p_frames) {
+
+ //print_line("MIXI! "+itos(p_frames));
+ static_cast<AudioServerJavascript*>(AudioServerJavascript::get_singleton())->mix_to_js(p_frames);
+}
+
+}
+
+void AudioServerJavascript::mix_to_js(int p_frames) {
+
+
+ //process in chunks to make sure to never process more than INTERNAL_BUFFER_SIZE
+ int todo=p_frames;
+ int offset=0;
+
+ while(todo) {
+
+ int tomix=MIN(todo,INTERNAL_BUFFER_SIZE);
+ driver_process_chunk(tomix);
+
+
+ EM_ASM_({
+
+ var data = HEAPF32.subarray($0/4, $0/4 + $2*2);
+
+ for (var channel = 0; channel < _as_output_buffer.numberOfChannels; channel++) {
+ var outputData = _as_output_buffer.getChannelData(channel);
+ // Loop through samples
+ for (var sample = 0; sample < $2; sample++) {
+ // make output equal to the same as the input
+ outputData[sample+$1] = data[sample*2+channel];
+ }
+ }
+
+ },internal_buffer,offset,tomix);
+
+ todo-=tomix;
+ offset+=tomix;
+ }
+}
+
+void AudioServerJavascript::init(){
+
+ //EM_ASM(
+// console.log('server is '+audio_server);
+// );
+
+
+ //int latency = GLOBAL_DEF("javascript/audio_latency",16384);
+
+ internal_buffer_channels=2;
+ internal_buffer = memnew_arr(float,INTERNAL_BUFFER_SIZE*internal_buffer_channels);
+ stream_buffer = memnew_arr(int32_t,INTERNAL_BUFFER_SIZE*4); //max 4 channels
+
+ stream_volume=0.3;
+
+ int buffer_latency=16384;
+
+ EM_ASM_( {
+
+ _as_script_node = _as_audioctx.createScriptProcessor($0, 0, 2);
+ _as_script_node.connect(_as_audioctx.destination);
+ console.log(_as_script_node.bufferSize);
+
+
+ _as_script_node.onaudioprocess = function(audioProcessingEvent) {
+ // The output buffer contains the samples that will be modified and played
+ _as_output_buffer = audioProcessingEvent.outputBuffer;
+ audio_server_mix_function(_as_output_buffer.getChannelData(0).length);
+ }
+ },buffer_latency);
+
+
+}
+
+void AudioServerJavascript::finish(){
+
+}
+void AudioServerJavascript::update(){
+
+ for(List<Stream*>::Element *E=active_audio_streams.front();E;) { //stream might be removed durnig this callback
+
+ List<Stream*>::Element *N=E->next();
+
+ if (E->get()->audio_stream)
+ E->get()->audio_stream->update();
+
+ E=N;
+ }
+}
+
+/* MISC config */
+
+void AudioServerJavascript::lock(){
+
+}
+void AudioServerJavascript::unlock(){
+
+}
+int AudioServerJavascript::get_default_channel_count() const{
+
+ return 1;
+}
+int AudioServerJavascript::get_default_mix_rate() const{
+
+ return 44100;
+}
+
+void AudioServerJavascript::set_stream_global_volume_scale(float p_volume){
+
+ stream_volume_scale=p_volume;
+}
+void AudioServerJavascript::set_fx_global_volume_scale(float p_volume){
+
+ fx_volume_scale=p_volume;
+}
+void AudioServerJavascript::set_event_voice_global_volume_scale(float p_volume){
+
+}
+
+float AudioServerJavascript::get_stream_global_volume_scale() const{
+ return 1;
+}
+float AudioServerJavascript::get_fx_global_volume_scale() const{
+
+ return 1;
+}
+float AudioServerJavascript::get_event_voice_global_volume_scale() const{
+
+ return 1;
+}
+
+uint32_t AudioServerJavascript::read_output_peak() const{
+
+ return 0;
+}
+
+AudioServerJavascript *AudioServerJavascript::singleton=NULL;
+
+AudioServer *AudioServerJavascript::get_singleton() {
+ return singleton;
+}
+
+double AudioServerJavascript::get_mix_time() const{
+
+ return 0;
+}
+double AudioServerJavascript::get_output_delay() const {
+
+ return 0;
+}
+
+
+void AudioServerJavascript::driver_process_chunk(int p_frames) {
+
+
+
+ int samples=p_frames*internal_buffer_channels;
+
+ for(int i=0;i<samples;i++) {
+ internal_buffer[i]=0;
+ }
+
+
+ for(List<Stream*>::Element *E=active_audio_streams.front();E;E=E->next()) {
+
+ ERR_CONTINUE(!E->get()->active); // bug?
+
+
+ AudioStream *as=E->get()->audio_stream;
+ if (!as)
+ continue;
+
+ int channels=as->get_channel_count();
+ if (channels==0)
+ continue; // does not want mix
+ if (!as->mix(stream_buffer,p_frames))
+ continue; //nothing was mixed!!
+
+ int32_t stream_vol_scale=(stream_volume*stream_volume_scale*E->get()->volume_scale)*(1<<STREAM_SCALE_BITS);
+
+#define STRSCALE(m_val) ((((m_val>>STREAM_SCALE_BITS)*stream_vol_scale)>>8)/8388608.0)
+ switch(channels) {
+ case 1: {
+
+ for(int i=0;i<p_frames;i++) {
+
+ internal_buffer[(i<<1)+0]+=STRSCALE(stream_buffer[i]);
+ internal_buffer[(i<<1)+1]+=STRSCALE(stream_buffer[i]);
+ }
+ } break;
+ case 2: {
+
+ for(int i=0;i<p_frames*2;i++) {
+
+ internal_buffer[i]+=STRSCALE(stream_buffer[i]);
+ }
+ } break;
+ case 4: {
+
+ for(int i=0;i<p_frames;i++) {
+
+ internal_buffer[(i<<2)+0]+=STRSCALE((stream_buffer[(i<<2)+0]+stream_buffer[(i<<2)+2])>>1);
+ internal_buffer[(i<<2)+1]+=STRSCALE((stream_buffer[(i<<2)+1]+stream_buffer[(i<<2)+3])>>1);
+ }
+ } break;
+
+
+ }
+
+#undef STRSCALE
+ }
+}
+
+
+/*void AudioServerSW::driver_process(int p_frames,int32_t *p_buffer) {
+
+
+ _output_delay=p_frames/double(AudioDriverSW::get_singleton()->get_mix_rate());
+ //process in chunks to make sure to never process more than INTERNAL_BUFFER_SIZE
+ int todo=p_frames;
+ while(todo) {
+
+ int tomix=MIN(todo,INTERNAL_BUFFER_SIZE);
+ driver_process_chunk(tomix,p_buffer);
+ p_buffer+=tomix;
+ todo-=tomix;
+ }
+
+
+}*/
+
+AudioServerJavascript::AudioServerJavascript() {
+
+ singleton=this;
+ sample_base=1;
+ voice_base=1;
+ EM_ASM(
+ _as_samples={};
+ _as_voices={};
+ _as_voice_pan={};
+ _as_voice_gain={};
+
+ _as_audioctx = new (window.AudioContext || window.webkitAudioContext)();
+
+ audio_server_mix_function = Module.cwrap('audio_server_mix_function', 'void', ['number']);
+ );
+
+ webaudio_mix_rate = EM_ASM_INT_V(
+ return _as_audioctx.sampleRate;
+ );
+ print_line("WEBAUDIO MIX RATE: "+itos(webaudio_mix_rate));
+ event_voice_scale=1.0;
+ fx_volume_scale=1.0;
+ stream_volume_scale=1.0;
+
+}
diff --git a/platform/javascript/audio_server_javascript.h b/platform/javascript/audio_server_javascript.h
new file mode 100644
index 0000000000..1dc90c48ee
--- /dev/null
+++ b/platform/javascript/audio_server_javascript.h
@@ -0,0 +1,198 @@
+#ifndef AUDIO_SERVER_JAVASCRIPT_H
+#define AUDIO_SERVER_JAVASCRIPT_H
+
+
+#include "servers/audio_server.h"
+
+class AudioServerJavascript : public AudioServer {
+
+ OBJ_TYPE(AudioServerJavascript,AudioServer);
+
+ enum {
+ INTERNAL_BUFFER_SIZE=4096,
+ STREAM_SCALE_BITS=12
+
+ };
+
+ AudioMixer *get_mixer();
+ void audio_mixer_chunk_callback(int p_frames);
+
+ struct Sample {
+ SampleFormat format;
+ SampleLoopFormat loop_format;
+ int loop_begin;
+ int loop_end;
+ int length;
+ int index;
+ int mix_rate;
+ bool stereo;
+
+ Vector<float> tmp_data;
+ };
+
+ mutable RID_Owner<Sample> sample_owner;
+ int sample_base;
+
+ struct Voice {
+ int index;
+ float volume;
+ float pan;
+ float pan_depth;
+ float pan_height;
+
+ float chorus;
+ ReverbRoomType reverb_type;
+ float reverb;
+
+ int mix_rate;
+ int sample_mix_rate;
+ bool positional;
+
+ bool active;
+
+ };
+
+ mutable RID_Owner<Voice> voice_owner;
+
+ int voice_base;
+
+ struct Stream {
+ bool active;
+ List<Stream*>::Element *E;
+ AudioStream *audio_stream;
+ EventStream *event_stream;
+ float volume_scale;
+ };
+
+ List<Stream*> active_audio_streams;
+
+ //List<Stream*> event_streams;
+
+ float * internal_buffer;
+ int internal_buffer_channels;
+ int32_t * stream_buffer;
+
+ mutable RID_Owner<Stream> stream_owner;
+
+ float stream_volume;
+ float stream_volume_scale;
+
+ float event_voice_scale;
+ float fx_volume_scale;
+
+
+ void driver_process_chunk(int p_frames);
+
+ int webaudio_mix_rate;
+
+
+ static AudioServerJavascript *singleton;
+public:
+
+ void mix_to_js(int p_frames);
+ /* SAMPLE API */
+
+ virtual RID sample_create(SampleFormat p_format, bool p_stereo, int p_length);
+
+ virtual void sample_set_description(RID p_sample, const String& p_description);
+ virtual String sample_get_description(RID p_sample) const;
+
+ virtual SampleFormat sample_get_format(RID p_sample) const;
+ virtual bool sample_is_stereo(RID p_sample) const;
+ virtual int sample_get_length(RID p_sample) const;
+ virtual const void* sample_get_data_ptr(RID p_sample) const;
+
+
+ virtual void sample_set_data(RID p_sample, const DVector<uint8_t>& p_buffer);
+ virtual const DVector<uint8_t> sample_get_data(RID p_sample) const;
+
+ virtual void sample_set_mix_rate(RID p_sample,int p_rate);
+ virtual int sample_get_mix_rate(RID p_sample) const;
+
+ virtual void sample_set_loop_format(RID p_sample,SampleLoopFormat p_format);
+ virtual SampleLoopFormat sample_get_loop_format(RID p_sample) const;
+
+ virtual void sample_set_loop_begin(RID p_sample,int p_pos);
+ virtual int sample_get_loop_begin(RID p_sample) const;
+
+ virtual void sample_set_loop_end(RID p_sample,int p_pos);
+ virtual int sample_get_loop_end(RID p_sample) const;
+
+
+ /* VOICE API */
+
+ virtual RID voice_create();
+
+ virtual void voice_play(RID p_voice, RID p_sample);
+
+ virtual void voice_set_volume(RID p_voice, float p_volume);
+ virtual void voice_set_pan(RID p_voice, float p_pan, float p_depth=0,float height=0); //pan and depth go from -1 to 1
+ virtual void voice_set_filter(RID p_voice, FilterType p_type, float p_cutoff, float p_resonance, float p_gain=0);
+ virtual void voice_set_chorus(RID p_voice, float p_chorus );
+ virtual void voice_set_reverb(RID p_voice, ReverbRoomType p_room_type, float p_reverb);
+ virtual void voice_set_mix_rate(RID p_voice, int p_mix_rate);
+ virtual void voice_set_positional(RID p_voice, bool p_positional);
+
+ virtual float voice_get_volume(RID p_voice) const;
+ virtual float voice_get_pan(RID p_voice) const; //pan and depth go from -1 to 1
+ virtual float voice_get_pan_depth(RID p_voice) const; //pan and depth go from -1 to 1
+ virtual float voice_get_pan_height(RID p_voice) const; //pan and depth go from -1 to 1
+ virtual FilterType voice_get_filter_type(RID p_voice) const;
+ virtual float voice_get_filter_cutoff(RID p_voice) const;
+ virtual float voice_get_filter_resonance(RID p_voice) const;
+ virtual float voice_get_chorus(RID p_voice) const;
+ virtual ReverbRoomType voice_get_reverb_type(RID p_voice) const;
+ virtual float voice_get_reverb(RID p_voice) const;
+
+ virtual int voice_get_mix_rate(RID p_voice) const;
+ virtual bool voice_is_positional(RID p_voice) const;
+
+ virtual void voice_stop(RID p_voice);
+ virtual bool voice_is_active(RID p_voice) const;
+
+ /* STREAM API */
+
+ virtual RID audio_stream_create(AudioStream *p_stream);
+ virtual RID event_stream_create(EventStream *p_stream);
+
+ virtual void stream_set_active(RID p_stream, bool p_active);
+ virtual bool stream_is_active(RID p_stream) const;
+
+ virtual void stream_set_volume_scale(RID p_stream, float p_scale);
+ virtual float stream_set_volume_scale(RID p_stream) const;
+
+ /* Audio Physics API */
+
+ virtual void free(RID p_id);
+
+ virtual void init();
+ virtual void finish();
+ virtual void update();
+
+ /* MISC config */
+
+ virtual void lock();
+ virtual void unlock();
+ virtual int get_default_channel_count() const;
+ virtual int get_default_mix_rate() const;
+
+ virtual void set_stream_global_volume_scale(float p_volume);
+ virtual void set_fx_global_volume_scale(float p_volume);
+ virtual void set_event_voice_global_volume_scale(float p_volume);
+
+ virtual float get_stream_global_volume_scale() const;
+ virtual float get_fx_global_volume_scale() const;
+ virtual float get_event_voice_global_volume_scale() const;
+
+ virtual uint32_t read_output_peak() const;
+
+ static AudioServer *get_singleton();
+
+ virtual double get_mix_time() const; //useful for video -> audio sync
+ virtual double get_output_delay() const;
+
+
+ AudioServerJavascript();
+};
+
+#endif // AUDIO_SERVER_JAVASCRIPT_H
diff --git a/platform/javascript/detect.py b/platform/javascript/detect.py
index 947a637fb9..0a6c8b1457 100644
--- a/platform/javascript/detect.py
+++ b/platform/javascript/detect.py
@@ -30,7 +30,6 @@ def get_flags():
('theora', 'no'),
('tools', 'no'),
('nedmalloc', 'no'),
- ('vorbis', 'no'),
('musepack', 'no'),
('squirrel', 'no'),
('squish', 'no'),
@@ -77,8 +76,11 @@ def configure(env):
#env.Append(CCFLAGS=['-D_DEBUG', '-Wall', '-g4', '-DDEBUG_ENABLED'])
env.Append(CPPFLAGS=['-DDEBUG_MEMORY_ALLOC'])
+ if(env["opus"]=="yes"):
+ env.opus_fixed_point="yes"
+
env.Append(CPPFLAGS=["-fno-exceptions",'-DNO_SAFE_CAST','-fno-rtti'])
- env.Append(CPPFLAGS=['-DJAVASCRIPT_ENABLED', '-DUNIX_ENABLED', '-DNO_FCNTL','-DMPC_FIXED_POINT','-DTYPED_METHOD_BIND','-DNO_THREADS'])
+ env.Append(CPPFLAGS=['-DJAVASCRIPT_ENABLED', '-DUNIX_ENABLED', '-DPTHREAD_NO_RENAME', '-DNO_FCNTL','-DMPC_FIXED_POINT','-DTYPED_METHOD_BIND','-DNO_THREADS'])
env.Append(CPPFLAGS=['-DGLES2_ENABLED'])
env.Append(CPPFLAGS=['-DGLES_NO_CLIENT_ARRAYS'])
env.Append(CPPFLAGS=['-s','ASM_JS=1'])
@@ -96,3 +98,10 @@ def configure(env):
#print "CCCOM is:", env.subst('$CCCOM')
#print "P: ", env['p'], " Platofrm: ", env['platform']
+
+ import methods
+
+ env.Append( BUILDERS = { 'GLSL120' : env.Builder(action = methods.build_legacygl_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
+ env.Append( BUILDERS = { 'GLSL' : env.Builder(action = methods.build_glsl_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
+ env.Append( BUILDERS = { 'GLSL120GLES' : env.Builder(action = methods.build_gles2_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
+ #env.Append( BUILDERS = { 'HLSL9' : env.Builder(action = methods.build_hlsl_dx9_headers, suffix = 'hlsl.h',src_suffix = '.hlsl') } )
diff --git a/platform/javascript/export/export.cpp b/platform/javascript/export/export.cpp
index 55b1ccbcaa..c769d2082a 100644
--- a/platform/javascript/export/export.cpp
+++ b/platform/javascript/export/export.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -77,11 +77,11 @@ public:
virtual int get_device_count() const { return show_run?1:0; };
virtual String get_device_name(int p_device) const { return "Run in Browser"; }
virtual String get_device_info(int p_device) const { return "Run exported HTML in the system's default browser."; }
- virtual Error run(int p_device,bool p_dumb=false);
+ virtual Error run(int p_device,int p_flags=0);
virtual bool requieres_password(bool p_debug) const { return false; }
virtual String get_binary_extension() const { return "html"; }
- virtual Error export_project(const String& p_path,bool p_debug,bool p_dumb=false);
+ virtual Error export_project(const String& p_path,bool p_debug,int p_flags=0);
virtual bool can_export(String *r_error=NULL) const;
@@ -144,12 +144,16 @@ static void _fix_html(Vector<uint8_t>& html,const String& name,int max_memory) {
str.parse_utf8((const char*)html.ptr(),html.size());
Vector<String> lines=str.split("\n");
for(int i=0;i<lines.size();i++) {
- if (lines[i].find("godot.js")!=-1) {
- strnew+="<script type=\"text/javascript\" src=\""+name+"_filesystem.js\"></script>\n";
- strnew+="<script async type=\"text/javascript\" src=\""+name+".js\"></script>\n";
- } else if (lines[i].find("var Module")!=-1) {
- strnew+=lines[i];
- strnew+="TOTAL_MEMORY:"+itos(max_memory*1024*1024)+",";
+
+ if (lines[i].find("$GODOTTMEM")!=-1) {
+
+ strnew+=lines[i].replace("$GODOTTMEM",itos(max_memory*1024*1024))+"\n";
+ } else if (lines[i].find("$GODOTFS")!=-1) {
+ strnew+=lines[i].replace("$GODOTFS",name+"fs.js")+"\n";
+ } else if (lines[i].find("$GODOTMEM")!=-1) {
+ strnew+=lines[i].replace("$GODOTMEM",name+".mem")+"\n";
+ } else if (lines[i].find("$GODOTJS")!=-1) {
+ strnew+=lines[i].replace("$GODOTJS",name+".js")+"\n";
} else {
strnew+=lines[i]+"\n";
}
@@ -194,25 +198,31 @@ struct JSExportData {
-Error EditorExportPlatformJavaScript::export_project(const String& p_path, bool p_debug, bool p_dumb) {
+Error EditorExportPlatformJavaScript::export_project(const String& p_path, bool p_debug, int p_flags) {
String src_template;
EditorProgress ep("export","Exporting for javascript",104);
- String template_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/";
-
- if (p_debug) {
-
- src_template=custom_debug_package!=""?custom_debug_package:template_path+"javascript_debug.zip";
- } else {
-
- src_template=custom_release_package!=""?custom_release_package:template_path+"javascript_release.zip";
+ if (p_debug)
+ src_template=custom_debug_package;
+ else
+ src_template=custom_release_package;
+ if (src_template=="") {
+ String err;
+ if (p_debug) {
+ src_template=find_export_template("javascript_debug.zip", &err);
+ } else {
+ src_template=find_export_template("javascript_release.zip", &err);
+ }
+ if (src_template=="") {
+ EditorNode::add_io_error(err);
+ return ERR_FILE_NOT_FOUND;
+ }
}
-
FileAccess *src_f=NULL;
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
@@ -267,10 +277,10 @@ Error EditorExportPlatformJavaScript::export_project(const String& p_path, bool
_fix_html(data,p_path.get_file().basename(),1<<(max_memory+5));
file=p_path.get_file();
}
- if (file=="filesystem.js") {
+ if (file=="godotfs.js") {
_fix_files(data,len);
- file=p_path.get_file().basename()+"_filesystem.js";
+ file=p_path.get_file().basename()+"fs.js";
}
if (file=="godot.js") {
@@ -278,6 +288,12 @@ Error EditorExportPlatformJavaScript::export_project(const String& p_path, bool
file=p_path.get_file().basename()+".js";
}
+ if (file=="godot.mem") {
+
+ //_fix_godot(data);
+ file=p_path.get_file().basename()+".mem";
+ }
+
String dst = p_path.get_base_dir().plus_file(file);
FileAccess *f=FileAccess::open(dst,FileAccess::WRITE);
if (!f) {
@@ -299,10 +315,10 @@ Error EditorExportPlatformJavaScript::export_project(const String& p_path, bool
}
-Error EditorExportPlatformJavaScript::run(int p_device, bool p_dumb) {
+Error EditorExportPlatformJavaScript::run(int p_device, int p_flags) {
String path = EditorSettings::get_singleton()->get_settings_path()+"/tmp/tmp_export.html";
- Error err = export_project(path,true,"");
+ Error err = export_project(path,true,p_flags);
if (err)
return err;
@@ -327,9 +343,8 @@ bool EditorExportPlatformJavaScript::can_export(String *r_error) const {
bool valid=true;
String err;
- String exe_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/";
- if (!FileAccess::exists(exe_path+"javascript_debug.zip") || !FileAccess::exists(exe_path+"javascript_release.zip")) {
+ if (!exists_export_template("javascript_debug.zip") || !exists_export_template("javascript_release.zip")) {
valid=false;
err+="No export templates found.\nDownload and install export templates.\n";
}
diff --git a/platform/javascript/export/export.h b/platform/javascript/export/export.h
index a126675983..2105141e58 100644
--- a/platform/javascript/export/export.h
+++ b/platform/javascript/export/export.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/javascript/javascript_main.cpp b/platform/javascript/javascript_main.cpp
index 5be6c5b647..e66110b655 100644
--- a/platform/javascript/javascript_main.cpp
+++ b/platform/javascript/javascript_main.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,6 +31,9 @@
#include "main/main.h"
#include "io/resource_loader.h"
#include "os/keyboard.h"
+#include "emscripten.h"
+#include <string.h>
+
OS_JavaScript *os=NULL;
static void _gfx_init(void *ud,bool gl2,int w, int h,bool fs) {
@@ -196,15 +199,39 @@ static void _gfx_idle() {
glutPostRedisplay();
}
+int start_step=0;
+
static void _godot_draw(void) {
- os->main_loop_iterate();
+ if (start_step==1) {
+ start_step=2;
+ Main::start();
+ os->main_loop_begin();
+ }
+
+ if (start_step==2) {
+ os->main_loop_iterate();
+ }
+
glutSwapBuffers();
}
+
+
+extern "C" {
+
+void main_after_fs_sync(int value) {
+
+ start_step=1;
+ printf("FS SYNCHED!\n");
+}
+
+}
+
int main(int argc, char *argv[]) {
- /* Initialize the window */
+
+ /* Initialize the window */
printf("let it go!\n");
glutInit(&argc, argv);
os = new OS_JavaScript(_gfx_init,NULL,NULL,NULL,NULL);
@@ -218,7 +245,7 @@ int main(int argc, char *argv[]) {
#endif
ResourceLoader::set_abort_on_missing_resources(false); //ease up compatibility
- Main::start();
+
glutSpecialUpFunc(_glut_skey_up);
glutSpecialFunc(_glut_skey_down);
@@ -236,10 +263,32 @@ int main(int argc, char *argv[]) {
// glutReshapeFunc(gears_reshape);
glutDisplayFunc(_godot_draw);
//glutSpecialFunc(gears_special);
- os->main_loop_begin();
+
+
+
+ //mount persistent filesystem
+ EM_ASM(
+ FS.mkdir('/userfs');
+ FS.mount(IDBFS, {}, '/userfs');
+
+
+
+ // sync from persisted state into memory and then
+ // run the 'test' function
+ FS.syncfs(true, function (err) {
+ assert(!err);
+ console.log("done syncinc!");
+ _after_sync_cb = Module.cwrap('main_after_fs_sync', 'void',['number']);
+ _after_sync_cb(0);
+
+ });
+
+ );
glutMainLoop();
+
+
return 0;
}
diff --git a/platform/javascript/os_javascript.cpp b/platform/javascript/os_javascript.cpp
index a422f77b4b..7bb47881a3 100644
--- a/platform/javascript/os_javascript.cpp
+++ b/platform/javascript/os_javascript.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -37,6 +37,7 @@
#include "main/main.h"
#include "core/globals.h"
+#include "emscripten.h"
int OS_JavaScript::get_video_driver_count() const {
@@ -104,21 +105,21 @@ void OS_JavaScript::initialize(const VideoMode& p_desired,int p_video_driver,int
visual_server->init();
visual_server->cursor_set_visible(false, 0);
- AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton();
+ /*AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton();
if (AudioDriverManagerSW::get_driver(p_audio_driver)->init()!=OK) {
ERR_PRINT("Initializing audio failed.");
- }
+ }*/
print_line("Init SM");
- sample_manager = memnew( SampleManagerMallocSW );
- audio_server = memnew( AudioServerSW(sample_manager) );
+ //sample_manager = memnew( SampleManagerMallocSW );
+ audio_server = memnew( AudioServerJavascript );
print_line("Init Mixer");
- audio_server->set_mixer_params(AudioMixerSW::INTERPOLATION_LINEAR,false);
+ //audio_server->set_mixer_params(AudioMixerSW::INTERPOLATION_LINEAR,false);
audio_server->init();
print_line("Init SoundServer");
@@ -270,6 +271,32 @@ bool OS_JavaScript::main_loop_iterate() {
if (!main_loop)
return false;
+
+ if (time_to_save_sync>=0) {
+ int64_t newtime = get_ticks_msec();
+ int64_t elapsed = newtime - last_sync_time;
+ last_sync_time=newtime;
+
+ time_to_save_sync-=elapsed;
+
+ print_line("elapsed "+itos(elapsed)+" tts "+itos(time_to_save_sync));
+
+ if (time_to_save_sync<0) {
+ //time to sync, for real
+ // run 'success'
+ print_line("DOING SYNCH!");
+ EM_ASM(
+ FS.syncfs(function (err) {
+ assert(!err);
+ console.log("Synched!");
+ //ccall('success', 'v');
+ });
+ );
+ }
+
+
+ }
+
return Main::iteration();
}
@@ -562,14 +589,21 @@ String OS_JavaScript::get_locale() const {
String OS_JavaScript::get_data_dir() const {
- if (get_data_dir_func)
- return get_data_dir_func();
- return "/";
+ //if (get_data_dir_func)
+ // return get_data_dir_func();
+ return "/userfs";
//return Globals::get_singleton()->get_singleton_object("GodotOS")->call("get_data_dir");
};
+void OS_JavaScript::_close_notification_funcs(const String& p_file,int p_flags) {
+ print_line("close "+p_file+" flags "+itos(p_flags));
+ if (p_file.begins_with("/userfs") && p_flags&FileAccess::WRITE) {
+ static_cast<OS_JavaScript*>(get_singleton())->last_sync_time=OS::get_singleton()->get_ticks_msec();
+ static_cast<OS_JavaScript*>(get_singleton())->time_to_save_sync=5000; //five seconds since last save
+ }
+}
OS_JavaScript::OS_JavaScript(GFXInitFunc p_gfx_init_func,void*p_gfx_init_ud, OpenURIFunc p_open_uri_func, GetDataDirFunc p_get_data_dir_func,GetLocaleFunc p_get_locale_func) {
@@ -589,6 +623,9 @@ OS_JavaScript::OS_JavaScript(GFXInitFunc p_gfx_init_func,void*p_gfx_init_ud, Ope
open_uri_func=p_open_uri_func;
get_data_dir_func=p_get_data_dir_func;
get_locale_func=p_get_locale_func;
+ FileAccessUnix::close_notification_func=_close_notification_funcs;
+
+ time_to_save_sync=-1;
}
diff --git a/platform/javascript/os_javascript.h b/platform/javascript/os_javascript.h
index 81bb474401..61eecd8f32 100644
--- a/platform/javascript/os_javascript.h
+++ b/platform/javascript/os_javascript.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -38,8 +38,9 @@
#include "servers/audio/audio_server_sw.h"
#include "servers/physics_2d/physics_2d_server_sw.h"
#include "servers/visual/rasterizer.h"
-
+#include "audio_server_javascript.h"
#include "audio_driver_javascript.h"
+#include "main/input_default.h"
typedef void (*GFXInitFunc)(void *ud,bool gl2,int w, int h, bool fs);
typedef int (*OpenURIFunc)(const String&);
@@ -65,10 +66,13 @@ private:
bool use_gl2;
+ int64_t time_to_save_sync;
+ int64_t last_sync_time;
+
Rasterizer *rasterizer;
VisualServer *visual_server;
- AudioServerSW *audio_server;
- SampleManagerMallocSW *sample_manager;
+ AudioServerJavascript *audio_server;
+ //SampleManagerMallocSW *sample_manager;
SpatialSoundServerSW *spatial_sound_server;
SpatialSound2DServerSW *spatial_sound_2d_server;
PhysicsServer *physics_server;
@@ -84,6 +88,8 @@ private:
GetDataDirFunc get_data_dir_func;
GetLocaleFunc get_locale_func;
+ static void _close_notification_funcs(const String& p_file,int p_flags);
+
public:
// functions used by main to initialize/deintialize the OS
@@ -106,7 +112,7 @@ public:
typedef int64_t ProcessID;
- static OS* get_singleton();
+ //static OS* get_singleton();
virtual void vprint(const char* p_format, va_list p_list, bool p_stderr=false);
virtual void print(const char *p_format, ... );
diff --git a/platform/javascript/platform_config.h b/platform/javascript/platform_config.h
index 1e7d066bb9..143f16c1fa 100644
--- a/platform/javascript/platform_config.h
+++ b/platform/javascript/platform_config.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/nacl/audio_driver_nacl.cpp b/platform/nacl/audio_driver_nacl.cpp
index 27197ad2b2..dac9521487 100644
--- a/platform/nacl/audio_driver_nacl.cpp
+++ b/platform/nacl/audio_driver_nacl.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/nacl/audio_driver_nacl.h b/platform/nacl/audio_driver_nacl.h
index be5a4cba67..d14e60717a 100644
--- a/platform/nacl/audio_driver_nacl.h
+++ b/platform/nacl/audio_driver_nacl.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/nacl/context_gl_nacl.cpp b/platform/nacl/context_gl_nacl.cpp
index 8ba3fe49d2..ce2f25b69f 100644
--- a/platform/nacl/context_gl_nacl.cpp
+++ b/platform/nacl/context_gl_nacl.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/nacl/context_gl_nacl.h b/platform/nacl/context_gl_nacl.h
index 18da070e35..82b9ba0775 100644
--- a/platform/nacl/context_gl_nacl.h
+++ b/platform/nacl/context_gl_nacl.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/nacl/geturl_handler.cpp b/platform/nacl/geturl_handler.cpp
index 40583891a9..6be82f3f5a 100644
--- a/platform/nacl/geturl_handler.cpp
+++ b/platform/nacl/geturl_handler.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/nacl/geturl_handler.h b/platform/nacl/geturl_handler.h
index 901210febd..c310ed942d 100644
--- a/platform/nacl/geturl_handler.h
+++ b/platform/nacl/geturl_handler.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/nacl/godot_module.cpp b/platform/nacl/godot_module.cpp
index 490edf62cd..5c558f5ece 100644
--- a/platform/nacl/godot_module.cpp
+++ b/platform/nacl/godot_module.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/nacl/godot_nacl.cpp b/platform/nacl/godot_nacl.cpp
index 7302a0b5d5..d8447390c1 100644
--- a/platform/nacl/godot_nacl.cpp
+++ b/platform/nacl/godot_nacl.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/nacl/html/icon_128.png b/platform/nacl/html/icon_128.png
index 1793aa7e7a..653669c38d 100644
--- a/platform/nacl/html/icon_128.png
+++ b/platform/nacl/html/icon_128.png
Binary files differ
diff --git a/platform/nacl/html/icon_16.png b/platform/nacl/html/icon_16.png
index 09de19e418..9f6678c289 100644
--- a/platform/nacl/html/icon_16.png
+++ b/platform/nacl/html/icon_16.png
Binary files differ
diff --git a/platform/nacl/nacl_keycodes.h b/platform/nacl/nacl_keycodes.h
index b8ff5874cf..45dba075db 100644
--- a/platform/nacl/nacl_keycodes.h
+++ b/platform/nacl/nacl_keycodes.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/nacl/opengl_context.cpp b/platform/nacl/opengl_context.cpp
index 285e8df9ce..ae72e4ddbb 100644
--- a/platform/nacl/opengl_context.cpp
+++ b/platform/nacl/opengl_context.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/nacl/opengl_context.h b/platform/nacl/opengl_context.h
index 6c73873f4b..f03a4b3e53 100644
--- a/platform/nacl/opengl_context.h
+++ b/platform/nacl/opengl_context.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/nacl/os_nacl.cpp b/platform/nacl/os_nacl.cpp
index b282209d72..de6a15525b 100644
--- a/platform/nacl/os_nacl.cpp
+++ b/platform/nacl/os_nacl.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -144,8 +144,7 @@ void OSNacl::finalize_core() {
if (mempool_dynamic)
memdelete( mempool_dynamic );
- if (mempool_static)
- delete mempool_static;
+ delete mempool_static;
};
diff --git a/platform/nacl/os_nacl.h b/platform/nacl/os_nacl.h
index e033abb68d..689aa07e20 100644
--- a/platform/nacl/os_nacl.h
+++ b/platform/nacl/os_nacl.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/nacl/pepper_main.cpp b/platform/nacl/pepper_main.cpp
index 406d84419b..fe10db19a9 100644
--- a/platform/nacl/pepper_main.cpp
+++ b/platform/nacl/pepper_main.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/nacl/platform_config.h b/platform/nacl/platform_config.h
index 1e7d066bb9..143f16c1fa 100644
--- a/platform/nacl/platform_config.h
+++ b/platform/nacl/platform_config.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/osx/SCsub b/platform/osx/SCsub
index 4904636afd..3785eb3fb3 100644
--- a/platform/osx/SCsub
+++ b/platform/osx/SCsub
@@ -6,6 +6,7 @@ files = [
'audio_driver_osx.cpp',
'sem_osx.cpp',
# 'context_gl_osx.cpp',
+ 'dir_access_osx.mm',
]
env.Program('#bin/godot',files)
diff --git a/platform/osx/audio_driver_osx.cpp b/platform/osx/audio_driver_osx.cpp
index 6904b7a398..a74303e6c2 100644
--- a/platform/osx/audio_driver_osx.cpp
+++ b/platform/osx/audio_driver_osx.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/osx/audio_driver_osx.h b/platform/osx/audio_driver_osx.h
index bcf6b23864..92893c64dc 100644
--- a/platform/osx/audio_driver_osx.h
+++ b/platform/osx/audio_driver_osx.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/osx/context_gl_osx.cpp b/platform/osx/context_gl_osx.cpp
index f856e1e4a8..df1c14c643 100644
--- a/platform/osx/context_gl_osx.cpp
+++ b/platform/osx/context_gl_osx.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/osx/context_gl_osx.h b/platform/osx/context_gl_osx.h
index 770ec74737..4a94c20c00 100644
--- a/platform/osx/context_gl_osx.h
+++ b/platform/osx/context_gl_osx.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/osx/detect.py b/platform/osx/detect.py
index 5703cbc546..f7cf5111f5 100644
--- a/platform/osx/detect.py
+++ b/platform/osx/detect.py
@@ -11,15 +11,17 @@ def get_name():
def can_build():
- if (sys.platform != "darwin"):
- return False
+ if (sys.platform == "darwin" or os.environ.has_key("OSXCROSS_ROOT")):
+ return True
- return True # osx enabled
+
+ return False
def get_opts():
return [
('force_64_bits','Force 64 bits binary','no'),
+ ('osxcross_sdk','OSXCross SDK version','darwin14'),
]
@@ -59,12 +61,31 @@ def configure(env):
env.Append(CPPPATH=['#tools/freetype'])
env.Append(CPPPATH=['#tools/freetype/freetype/include'])
- if (env["bits"]=="64"):
- env.Append(CCFLAGS=['-arch', 'x86_64'])
- env.Append(LINKFLAGS=['-arch', 'x86_64'])
+
+
+ if (not os.environ.has_key("OSXCROSS_ROOT")):
+ #regular native build
+ if (env["bits"]=="64"):
+ env.Append(CCFLAGS=['-arch', 'x86_64'])
+ env.Append(LINKFLAGS=['-arch', 'x86_64'])
+ else:
+ env.Append(CCFLAGS=['-arch', 'i386'])
+ env.Append(LINKFLAGS=['-arch', 'i386'])
else:
- env.Append(CCFLAGS=['-arch', 'i386'])
- env.Append(LINKFLAGS=['-arch', 'i386'])
+ #osxcross build
+ root=os.environ.get("OSXCROSS_ROOT",0)
+ if env["bits"]=="64":
+ basecmd=root+"/target/bin/x86_64-apple-"+env["osxcross_sdk"]+"-"
+ else:
+ basecmd=root+"/target/bin/i386-apple-"+env["osxcross_sdk"]+"-"
+
+
+ env['CC'] = basecmd+"cc"
+ env['CXX'] = basecmd+"c++"
+ env['AR'] = basecmd+"ar"
+ env['RANLIB'] = basecmd+"ranlib"
+ env['AS'] = basecmd+"as"
+
# env.Append(CPPPATH=['#platform/osx/include/freetype2', '#platform/osx/include'])
# env.Append(LIBPATH=['#platform/osx/lib'])
@@ -95,4 +116,4 @@ def configure(env):
env.Append( BUILDERS = { 'GLSL120GLES' : env.Builder(action = methods.build_gles2_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
#env.Append( BUILDERS = { 'HLSL9' : env.Builder(action = methods.build_hlsl_dx9_headers, suffix = 'hlsl.h',src_suffix = '.hlsl') } )
-
+ env["x86_opt_gcc"]=True
diff --git a/platform/osx/dir_access_osx.h b/platform/osx/dir_access_osx.h
new file mode 100644
index 0000000000..caeeaf643c
--- /dev/null
+++ b/platform/osx/dir_access_osx.h
@@ -0,0 +1,92 @@
+/*************************************************************************/
+/* dir_access_unix.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
+#ifndef DIR_ACCESS_OSX_H
+#define DIR_ACCESS_OSX_H
+
+#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED)
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#include "os/dir_access.h"
+
+
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+class DirAccessOSX : public DirAccess {
+
+ DIR *dir_stream;
+
+ static DirAccess *create_fs();
+
+ String current_dir;
+ bool _cisdir;
+ bool _cishidden;
+
+public:
+
+ virtual bool list_dir_begin(); ///< This starts dir listing
+ virtual String get_next();
+ virtual bool current_is_dir() const;
+ virtual bool current_is_hidden() const;
+
+ virtual void list_dir_end(); ///<
+
+ virtual int get_drive_count();
+ virtual String get_drive(int p_drive);
+
+ virtual Error change_dir(String p_dir); ///< can be relative or absolute, return false on success
+ virtual String get_current_dir(); ///< return current dir location
+ virtual Error make_dir(String p_dir);
+
+ virtual bool file_exists(String p_file);
+ virtual bool dir_exists(String p_dir);
+
+ virtual uint64_t get_modified_time(String p_file);
+
+
+
+ virtual Error rename(String p_from, String p_to);
+ virtual Error remove(String p_name);
+
+ virtual size_t get_space_left();
+
+
+ DirAccessOSX();
+ ~DirAccessOSX();
+
+};
+
+
+
+#endif //UNIX ENABLED
+#endif
diff --git a/platform/osx/dir_access_osx.mm b/platform/osx/dir_access_osx.mm
new file mode 100644
index 0000000000..e345bea60a
--- /dev/null
+++ b/platform/osx/dir_access_osx.mm
@@ -0,0 +1,350 @@
+/*************************************************************************/
+/* dir_access_unix.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
+#include "dir_access_osx.h"
+
+#if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED)
+
+#ifndef ANDROID_ENABLED
+#include <sys/statvfs.h>
+#endif
+
+#include <stdio.h>
+#include "os/memory.h"
+#include "print_string.h"
+#include <errno.h>
+
+#include <Foundation/NSString.h>
+
+DirAccess *DirAccessOSX::create_fs() {
+
+ return memnew( DirAccessOSX );
+}
+
+bool DirAccessOSX::list_dir_begin() {
+
+ list_dir_end(); //close any previous dir opening!
+
+
+// char real_current_dir_name[2048]; //is this enough?!
+ //getcwd(real_current_dir_name,2048);
+ //chdir(curent_path.utf8().get_data());
+ dir_stream = opendir(current_dir.utf8().get_data());
+ //chdir(real_current_dir_name);
+ if (!dir_stream)
+ return true; //error!
+
+ return false;
+}
+
+bool DirAccessOSX::file_exists(String p_file) {
+
+ GLOBAL_LOCK_FUNCTION
+
+
+ if (p_file.is_rel_path())
+ p_file=current_dir+"/"+p_file;
+ else
+ p_file=fix_path(p_file);
+
+ struct stat flags;
+ bool success = (stat(p_file.utf8().get_data(),&flags)==0);
+
+ if (success && S_ISDIR(flags.st_mode)) {
+ success=false;
+ }
+
+ return success;
+
+}
+
+bool DirAccessOSX::dir_exists(String p_dir) {
+
+ GLOBAL_LOCK_FUNCTION
+
+
+ if (p_dir.is_rel_path())
+ p_dir=get_current_dir().plus_file(p_dir);
+ else
+ p_dir=fix_path(p_dir);
+
+ struct stat flags;
+ bool success = (stat(p_dir.utf8().get_data(),&flags)==0);
+
+ if (success && S_ISDIR(flags.st_mode))
+ return true;
+
+ return false;
+
+}
+
+uint64_t DirAccessOSX::get_modified_time(String p_file) {
+
+ if (p_file.is_rel_path())
+ p_file=current_dir+"/"+p_file;
+ else
+ p_file=fix_path(p_file);
+
+ struct stat flags;
+ bool success = (stat(p_file.utf8().get_data(),&flags)==0);
+
+ if (success) {
+ return flags.st_mtime;
+ } else {
+
+ ERR_FAIL_V(0);
+ };
+ return 0;
+};
+
+
+String DirAccessOSX::get_next() {
+
+ if (!dir_stream)
+ return "";
+ dirent *entry;
+
+ entry=readdir(dir_stream);
+
+ if (entry==NULL) {
+
+ list_dir_end();
+ return "";
+ }
+
+ //typedef struct stat Stat;
+ struct stat flags;
+
+ String fname;
+ NSString* nsstr = [[NSString stringWithUTF8String: entry->d_name] precomposedStringWithCanonicalMapping];
+
+ fname.parse_utf8([nsstr UTF8String]);
+
+ //[nsstr autorelease];
+
+ String f=current_dir+"/"+fname;
+
+ if (stat(f.utf8().get_data(),&flags)==0) {
+
+ if (S_ISDIR(flags.st_mode)) {
+
+ _cisdir=true;
+
+ } else {
+
+ _cisdir=false;
+ }
+
+ } else {
+
+ _cisdir=false;
+
+ }
+
+ _cishidden=(fname!="." && fname!=".." && fname.begins_with("."));
+
+
+
+ return fname;
+
+}
+
+bool DirAccessOSX::current_is_dir() const {
+
+ return _cisdir;
+}
+
+bool DirAccessOSX::current_is_hidden() const {
+
+ return _cishidden;
+}
+
+
+void DirAccessOSX::list_dir_end() {
+
+ if (dir_stream)
+ closedir(dir_stream);
+ dir_stream=0;
+ _cisdir=false;
+}
+
+int DirAccessOSX::get_drive_count() {
+
+ return 0;
+}
+String DirAccessOSX::get_drive(int p_drive) {
+
+ return "";
+}
+
+Error DirAccessOSX::make_dir(String p_dir) {
+
+ GLOBAL_LOCK_FUNCTION
+
+ p_dir=fix_path(p_dir);
+
+ char real_current_dir_name[2048];
+ getcwd(real_current_dir_name,2048);
+ chdir(current_dir.utf8().get_data()); //ascii since this may be unicode or wathever the host os wants
+
+ bool success=(mkdir(p_dir.utf8().get_data(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)==0);
+ int err = errno;
+
+ chdir(real_current_dir_name);
+
+ if (success) {
+ return OK;
+ };
+
+ if (err == EEXIST) {
+ return ERR_ALREADY_EXISTS;
+ };
+
+ return ERR_CANT_CREATE;
+}
+
+
+Error DirAccessOSX::change_dir(String p_dir) {
+
+ GLOBAL_LOCK_FUNCTION
+ p_dir=fix_path(p_dir);
+
+
+ char real_current_dir_name[2048];
+ getcwd(real_current_dir_name,2048);
+ String prev_dir;
+ if (prev_dir.parse_utf8(real_current_dir_name))
+ prev_dir=real_current_dir_name; //no utf8, maybe latin?
+
+ chdir(current_dir.utf8().get_data()); //ascii since this may be unicode or wathever the host os wants
+ bool worked=(chdir(p_dir.utf8().get_data())==0); // we can only give this utf8
+#ifndef IPHONE_ENABLED
+ String base = _get_root_path();
+ if (base!="") {
+
+ getcwd(real_current_dir_name,2048);
+ String new_dir;
+ new_dir.parse_utf8(real_current_dir_name);
+ if (!new_dir.begins_with(base))
+ worked=false;
+ }
+#endif
+ if (worked) {
+
+ getcwd(real_current_dir_name,2048);
+ if (current_dir.parse_utf8(real_current_dir_name))
+ current_dir=real_current_dir_name; //no utf8, maybe latin?
+ }
+
+ chdir(prev_dir.utf8().get_data());
+ return worked?OK:ERR_INVALID_PARAMETER;
+
+}
+
+String DirAccessOSX::get_current_dir() {
+
+ String base = _get_root_path();
+ if (base!="") {
+
+ String bd = current_dir.replace_first(base,"");
+ if (bd.begins_with("/"))
+ return _get_root_string()+bd.substr(1,bd.length());
+ else
+ return _get_root_string()+bd;
+
+ }
+ return current_dir;
+}
+
+Error DirAccessOSX::rename(String p_path,String p_new_path) {
+
+ if (p_path.is_rel_path())
+ p_path=get_current_dir().plus_file(p_path);
+ else
+ p_path=fix_path(p_path);
+
+ if (p_new_path.is_rel_path())
+ p_new_path=get_current_dir().plus_file(p_new_path);
+ else
+ p_new_path=fix_path(p_new_path);
+
+ return ::rename(p_path.utf8().get_data(),p_new_path.utf8().get_data())==0?OK:FAILED;
+}
+Error DirAccessOSX::remove(String p_path) {
+
+ p_path=fix_path(p_path);
+
+ struct stat flags;
+ if ((stat(p_path.utf8().get_data(),&flags)!=0))
+ return FAILED;
+
+ if (S_ISDIR(flags.st_mode))
+ return ::rmdir(p_path.utf8().get_data())==0?OK:FAILED;
+ else
+ return ::unlink(p_path.utf8().get_data())==0?OK:FAILED;
+}
+
+
+size_t DirAccessOSX::get_space_left() {
+
+#ifndef NO_STATVFS
+ struct statvfs vfs;
+ if (statvfs(current_dir.utf8().get_data(), &vfs) != 0) {
+
+ return -1;
+ };
+
+ return vfs.f_bfree * vfs.f_bsize;
+#else
+#warning THIS IS BROKEN
+ return 0;
+#endif
+};
+
+
+
+DirAccessOSX::DirAccessOSX() {
+
+ dir_stream=0;
+ current_dir=".";
+ _cisdir=false;
+
+ /* determine drive count */
+
+ change_dir(current_dir);
+
+}
+
+
+DirAccessOSX::~DirAccessOSX() {
+
+ list_dir_end();
+}
+
+
+#endif //posix_enabled
diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp
index 885f234a0a..0bece6ec76 100644
--- a/platform/osx/export/export.cpp
+++ b/platform/osx/export/export.cpp
@@ -57,11 +57,11 @@ public:
virtual int get_device_count() const { return 0; };
virtual String get_device_name(int p_device) const { return String(); }
virtual String get_device_info(int p_device) const { return String(); }
- virtual Error run(int p_device,bool p_dumb=false);
+ virtual Error run(int p_device,int p_flags=0);
virtual bool requieres_password(bool p_debug) const { return false; }
virtual String get_binary_extension() const { return "zip"; }
- virtual Error export_project(const String& p_path,bool p_debug,bool p_dumb=false);
+ virtual Error export_project(const String& p_path,bool p_debug,int p_flags=0);
virtual bool can_export(String *r_error=NULL) const;
@@ -245,21 +245,25 @@ void EditorExportPlatformOSX::_fix_plist(Vector<uint8_t>& plist,const String& p_
}
}
-Error EditorExportPlatformOSX::export_project(const String& p_path, bool p_debug, bool p_dumb) {
+Error EditorExportPlatformOSX::export_project(const String& p_path, bool p_debug, int p_flags) {
String src_pkg;
EditorProgress ep("export","Exporting for OSX",104);
- String pkg_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/osx.zip";
-
- if (p_debug) {
-
- src_pkg=custom_debug_package!=""?custom_debug_package:pkg_path;
- } else {
-
- src_pkg=custom_release_package!=""?custom_release_package:pkg_path;
+ if (p_debug)
+ src_pkg=custom_debug_package;
+ else
+ src_pkg=custom_release_package;
+
+ if (src_pkg=="") {
+ String err;
+ src_pkg=find_export_template("osx.zip", &err);
+ if (src_pkg=="") {
+ EditorNode::add_io_error(err);
+ return ERR_FILE_NOT_FOUND;
+ }
}
@@ -437,7 +441,7 @@ Error EditorExportPlatformOSX::export_project(const String& p_path, bool p_debug
}
-Error EditorExportPlatformOSX::run(int p_device, bool p_dumb) {
+Error EditorExportPlatformOSX::run(int p_device, int p_flags) {
return OK;
}
@@ -464,9 +468,8 @@ bool EditorExportPlatformOSX::can_export(String *r_error) const {
bool valid=true;
String err;
- String exe_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/";
- if (!FileAccess::exists(exe_path+"osx.zip")) {
+ if (!exists_export_template("osx.zip")) {
valid=false;
err+="No export templates found.\nDownload and install export templates.\n";
}
diff --git a/platform/osx/godot_main_osx.mm b/platform/osx/godot_main_osx.mm
index 92fa6ddbc2..391fd1f74a 100644
--- a/platform/osx/godot_main_osx.mm
+++ b/platform/osx/godot_main_osx.mm
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/osx/godot_osx.h b/platform/osx/godot_osx.h
index 270ba9966f..de363d8483 100644
--- a/platform/osx/godot_osx.h
+++ b/platform/osx/godot_osx.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/osx/godot_osx.mm b/platform/osx/godot_osx.mm
index 39119393ff..0c32016216 100644
--- a/platform/osx/godot_osx.mm
+++ b/platform/osx/godot_osx.mm
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h
index 144037b1cb..a1fd34def7 100644
--- a/platform/osx/os_osx.h
+++ b/platform/osx/os_osx.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,7 +32,7 @@
#include "os/input.h"
#include "drivers/unix/os_unix.h"
-
+#include "main/input_default.h"
#include "servers/visual_server.h"
#include "servers/visual/visual_server_wrap_mt.h"
#include "servers/visual/rasterizer.h"
@@ -157,6 +157,8 @@ public:
Error shell_open(String p_uri);
void push_input(const InputEvent& p_event);
+ String get_locale() const;
+
virtual void set_video_mode(const VideoMode& p_video_mode,int p_screen=0);
virtual VideoMode get_video_mode(int p_screen=0) const;
virtual void get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen=0) const;
@@ -170,7 +172,7 @@ public:
virtual int get_screen_count() const;
virtual int get_current_screen() const;
virtual void set_current_screen(int p_screen);
- virtual Point2 get_screen_position(int p_screen=0);
+ virtual Point2 get_screen_position(int p_screen=0) const;
virtual Point2 get_window_position() const;
virtual void set_window_position(const Point2& p_position);
virtual void set_window_size(const Size2 p_size);
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index 72699366c4..2690ee3ba9 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -47,6 +47,7 @@
#include "servers/visual/visual_server_wrap_mt.h"
#include "main/main.h"
#include "os/keyboard.h"
+#include "dir_access_osx.h"
#include <sys/types.h>
#include <sys/stat.h>
@@ -512,12 +513,26 @@ static int button_mask=0;
- (void)mouseExited:(NSEvent *)event
{
+ if (!OS_OSX::singleton)
+ return;
+
+ if (OS_OSX::singleton->main_loop && OS_OSX::singleton->mouse_mode!=OS::MOUSE_MODE_CAPTURED)
+ OS_OSX::singleton->main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_EXIT);
+ if (OS_OSX::singleton->input)
+ OS_OSX::singleton->input->set_mouse_in_window(false);
// _glfwInputCursorEnter(window, GL_FALSE);
}
- (void)mouseEntered:(NSEvent *)event
{
// _glfwInputCursorEnter(window, GL_TRUE);
+ if (!OS_OSX::singleton)
+ return;
+ if (OS_OSX::singleton->main_loop && OS_OSX::singleton->mouse_mode!=OS::MOUSE_MODE_CAPTURED)
+ OS_OSX::singleton->main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER);
+ if (OS_OSX::singleton->input)
+ OS_OSX::singleton->input->set_mouse_in_window(true);
+
}
- (void)viewDidChangeBackingProperties
@@ -835,6 +850,11 @@ OS::VideoMode OS_OSX::get_default_video_mode() const {
void OS_OSX::initialize_core() {
OS_Unix::initialize_core();
+
+ DirAccess::make_default<DirAccessOSX>(DirAccess::ACCESS_RESOURCES);
+ DirAccess::make_default<DirAccessOSX>(DirAccess::ACCESS_USERDATA);
+ DirAccess::make_default<DirAccessOSX>(DirAccess::ACCESS_FILESYSTEM);
+
SemaphoreOSX::make_default();
}
@@ -1036,6 +1056,33 @@ void OS_OSX::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
void OS_OSX::finalize() {
CFNotificationCenterRemoveObserver(CFNotificationCenterGetDistributedCenter(), NULL, kTISNotifySelectedKeyboardInputSourceChanged, NULL);
+ delete_main_loop();
+
+ spatial_sound_server->finish();
+ memdelete(spatial_sound_server);
+ spatial_sound_2d_server->finish();
+ memdelete(spatial_sound_2d_server);
+
+
+ memdelete(input);
+
+ memdelete(sample_manager);
+
+ audio_server->finish();
+ memdelete(audio_server);
+
+ visual_server->finish();
+ memdelete(visual_server);
+ memdelete(rasterizer);
+
+ physics_server->finish();
+ memdelete(physics_server);
+
+ physics_2d_server->finish();
+ memdelete(physics_2d_server);
+
+ screens.clear();
+
}
@@ -1048,6 +1095,8 @@ void OS_OSX::set_main_loop( MainLoop * p_main_loop ) {
void OS_OSX::delete_main_loop() {
+ if (!main_loop)
+ return;
memdelete(main_loop);
main_loop=NULL;
}
@@ -1240,6 +1289,11 @@ Error OS_OSX::shell_open(String p_uri) {
return OK;
}
+String OS_OSX::get_locale() const {
+ NSString* preferredLang = [[NSLocale preferredLanguages] objectAtIndex:0];
+ return [preferredLang UTF8String];
+}
+
void OS_OSX::swap_buffers() {
[context flushBuffer];
@@ -1279,7 +1333,7 @@ void OS_OSX::set_current_screen(int p_screen) {
current_screen = p_screen;
};
-Point2 OS_OSX::get_screen_position(int p_screen) {
+Point2 OS_OSX::get_screen_position(int p_screen) const {
ERR_FAIL_INDEX_V(p_screen, screens.size(), Point2());
return screens[p_screen].pos;
diff --git a/platform/osx/platform_config.h b/platform/osx/platform_config.h
index 285d8d0c02..085f13df73 100644
--- a/platform/osx/platform_config.h
+++ b/platform/osx/platform_config.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,3 +29,4 @@
#include <alloca.h>
#define GLES2_INCLUDE_H "gl_context/glew.h"
#define GLES1_INCLUDE_H "gl_context/glew.h"
+#define PTHREAD_RENAME_SELF
diff --git a/platform/osx/sem_osx.cpp b/platform/osx/sem_osx.cpp
index be70bedf84..6909097fec 100644
--- a/platform/osx/sem_osx.cpp
+++ b/platform/osx/sem_osx.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/osx/sem_osx.h b/platform/osx/sem_osx.h
index 65bed7397f..ec5ddac4e0 100644
--- a/platform/osx/sem_osx.h
+++ b/platform/osx/sem_osx.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/server/godot_server.cpp b/platform/server/godot_server.cpp
index 41e48302c4..db6c13633d 100644
--- a/platform/server/godot_server.cpp
+++ b/platform/server/godot_server.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/server/os_server.cpp b/platform/server/os_server.cpp
index 75e0878bac..f042318f78 100644
--- a/platform/server/os_server.cpp
+++ b/platform/server/os_server.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -107,9 +107,10 @@ void OS_Server::finalize() {
// memdelete(debugger_connection_console);
//}
+ memdelete(sample_manager);
+
audio_server->finish();
memdelete(audio_server);
- memdelete(sample_manager);
visual_server->finish();
memdelete(visual_server);
diff --git a/platform/server/os_server.h b/platform/server/os_server.h
index 4e7721f068..2487c7b3fb 100644
--- a/platform/server/os_server.h
+++ b/platform/server/os_server.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,7 +30,7 @@
#define OS_SERVER_H
-#include "os/input.h"
+#include "main/input_default.h"
#include "drivers/unix/os_unix.h"
#include "servers/visual_server.h"
#include "servers/visual/rasterizer.h"
diff --git a/platform/server/platform_config.h b/platform/server/platform_config.h
index 43dda9e64e..72b10a0fb2 100644
--- a/platform/server/platform_config.h
+++ b/platform/server/platform_config.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/windows/SCsub b/platform/windows/SCsub
index 1ad32e7989..914cee0fa1 100644
--- a/platform/windows/SCsub
+++ b/platform/windows/SCsub
@@ -9,12 +9,19 @@ common_win=[
"tcp_server_winsock.cpp",
"packet_peer_udp_winsock.cpp",
"stream_peer_winsock.cpp",
+ "joystick.cpp",
]
+restarget="godot_res"+env["OBJSUFFIX"]
+
+obj = env.RES(restarget,'godot_res.rc')
+
+common_win.append(obj)
+
env.Program('#bin/godot',['godot_win.cpp']+common_win,PROGSUFFIX=env["PROGSUFFIX"])
-# Microsoft Visual Studio Project Generation
+# Microsoft Visual Studio Project Generation
if (env['vsproj'])=="yes":
env.vs_srcs = env.vs_srcs + ["platform/windows/godot_win.cpp"]
for x in common_win:
- env.vs_srcs = env.vs_srcs + ["platform/windows/" + x]
+ env.vs_srcs = env.vs_srcs + ["platform/windows/" + str(x)]
diff --git a/platform/windows/context_gl_win.cpp b/platform/windows/context_gl_win.cpp
index 5a9c8edc63..e671101432 100644
--- a/platform/windows/context_gl_win.cpp
+++ b/platform/windows/context_gl_win.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/windows/context_gl_win.h b/platform/windows/context_gl_win.h
index 5397676c8e..af15ad2659 100644
--- a/platform/windows/context_gl_win.h
+++ b/platform/windows/context_gl_win.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/windows/ctxgl_procaddr.cpp b/platform/windows/ctxgl_procaddr.cpp
index 6e5f53eb96..1072197f89 100644
--- a/platform/windows/ctxgl_procaddr.cpp
+++ b/platform/windows/ctxgl_procaddr.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/windows/ctxgl_procaddr.h b/platform/windows/ctxgl_procaddr.h
index 916b480639..2118e20e02 100644
--- a/platform/windows/ctxgl_procaddr.h
+++ b/platform/windows/ctxgl_procaddr.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index 0fe4f9f3b5..81247db388 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -1,376 +1,403 @@
-#
-# tested on | Windows native | Linux cross-compilation
-# ------------------------+-------------------+---------------------------
-# MSVS C++ 2010 Express | WORKS | n/a
-# Mingw-w64 | WORKS | WORKS
-# Mingw-w32 | WORKS | WORKS
-# MinGW | WORKS | untested
-#
-#####
-# Notes about MSVS C++ :
-#
-# - MSVC2010-Express compiles to 32bits only.
-#
-#####
-# Notes about Mingw-w64 and Mingw-w32 under Windows :
-#
-# - both can be installed using the official installer :
-# http://mingw-w64.sourceforge.net/download.php#mingw-builds
-#
-# - if you want to compile both 32bits and 64bits, don't forget to
-# run the installer twice to install them both.
-#
-# - install them into a path that does not contain spaces
-# ( example : "C:/Mingw-w32", "C:/Mingw-w64" )
-#
-# - if you want to compile faster using the "-j" option, don't forget
-# to install the appropriate version of the Pywin32 python extension
-# available from : http://sourceforge.net/projects/pywin32/files/
-#
-# - before running scons, you must add into the environment path
-# the path to the "/bin" directory of the Mingw version you want
-# to use :
-#
-# set PATH=C:/Mingw-w32/bin;%PATH%
-#
-# - then, scons should be able to detect gcc.
-# - Mingw-w32 only compiles 32bits.
-# - Mingw-w64 only compiles 64bits.
-#
-# - it is possible to add them both at the same time into the PATH env,
-# if you also define the MINGW32_PREFIX and MINGW64_PREFIX environment
-# variables.
-# For instance, you could store that set of commands into a .bat script
-# that you would run just before scons :
-#
-# set PATH=C:\mingw-w32\bin;%PATH%
-# set PATH=C:\mingw-w64\bin;%PATH%
-# set MINGW32_PREFIX=C:\mingw-w32\bin\
-# set MINGW64_PREFIX=C:\mingw-w64\bin\
-#
-#####
-# Notes about Mingw, Mingw-w64 and Mingw-w32 under Linux :
-#
-# - default toolchain prefixes are :
-# "i586-mingw32msvc-" for MinGW
-# "i686-w64-mingw32-" for Mingw-w32
-# "x86_64-w64-mingw32-" for Mingw-w64
-#
-# - if both MinGW and Mingw-w32 are installed on your system
-# Mingw-w32 should take the priority over MinGW.
-#
-# - it is possible to manually override prefixes by defining
-# the MINGW32_PREFIX and MINGW64_PREFIX environment variables.
-#
-#####
-# Notes about Mingw under Windows :
-#
-# - this is the MinGW version from http://mingw.org/
-# - install it into a path that does not contain spaces
-# ( example : "C:/MinGW" )
-# - several DirectX headers might be missing. You can copy them into
-# the C:/MinGW/include" directory from this page :
-# https://code.google.com/p/mingw-lib/source/browse/trunk/working/avcodec_to_widget_5/directx_include/
-# - before running scons, add the path to the "/bin" directory :
-# set PATH=C:/MinGW/bin;%PATH%
-# - scons should be able to detect gcc.
-#
-
-#####
-# TODO :
-#
-# - finish to cleanup this script to remove all the remains of previous hacks and workarounds
-# - make it work with the Windows7 SDK that is supposed to enable 64bits compilation for MSVC2010-Express
-# - confirm it works well with other Visual Studio versions.
-# - update the wiki about the pywin32 extension required for the "-j" option under Windows.
-# - update the wiki to document MINGW32_PREFIX and MINGW64_PREFIX
-#
-
-import os
-
-import sys
-
-
-def is_active():
- return True
-
-def get_name():
- return "Windows"
-
-def can_build():
-
- if (os.name=="nt"):
- #building natively on windows!
- if (os.getenv("VSINSTALLDIR")):
- return True
- else:
- print("\nMSVC not detected, attempting Mingw.")
- mingw32 = ""
- mingw64 = ""
- if ( os.getenv("MINGW32_PREFIX") ) :
- mingw32 = os.getenv("MINGW32_PREFIX")
- if ( os.getenv("MINGW64_PREFIX") ) :
- mingw64 = os.getenv("MINGW64_PREFIX")
-
- test = "gcc --version > NUL 2>&1"
- if os.system(test)!= 0 and os.system(mingw32+test)!=0 and os.system(mingw64+test)!=0 :
- print("- could not detect gcc.")
- print("Please, make sure a path to a Mingw /bin directory is accessible into the environment PATH.\n")
- return False
- else:
- print("- gcc detected.")
-
- return True
-
- if (os.name=="posix"):
-
- mingw = "i586-mingw32msvc-"
- mingw64 = "x86_64-w64-mingw32-"
- mingw32 = "i686-w64-mingw32-"
-
- if (os.getenv("MINGW32_PREFIX")):
- mingw32=os.getenv("MINGW32_PREFIX")
- mingw = mingw32
- if (os.getenv("MINGW64_PREFIX")):
- mingw64=os.getenv("MINGW64_PREFIX")
-
- test = "gcc --version >/dev/null"
- if os.system(mingw+test) == 0 or os.system(mingw64+test) ==0 or os.system(mingw32+test) ==0 :
- return True
-
- return False
-
-def get_opts():
-
- mingw=""
- mingw32=""
- mingw64=""
- if ( os.name == "posix" ):
- mingw = "i586-mingw32msvc-"
- mingw32 = "i686-w64-mingw32-"
- mingw64 = "x86_64-w64-mingw32-"
-
- if os.system(mingw32+"gcc --version >/dev/null") != 0 :
- mingw32 = mingw
-
- if (os.getenv("MINGW32_PREFIX")):
- mingw32=os.getenv("MINGW32_PREFIX")
- mingw = mingw32
- if (os.getenv("MINGW64_PREFIX")):
- mingw64=os.getenv("MINGW64_PREFIX")
-
-
- return [
- ('mingw_prefix','Mingw Prefix',mingw32),
- ('mingw_prefix_64','Mingw Prefix 64 bits',mingw64),
- ]
-
-def get_flags():
-
- return [
- ('freetype','builtin'), #use builtin freetype
- ('openssl','builtin'), #use builtin openssl
- ('theora','no'),
- ]
-
-
-
-def configure(env):
-
- env.Append(CPPPATH=['#platform/windows'])
-
-
- if (os.name=="nt" and os.getenv("VSINSTALLDIR")!=None):
- #build using visual studio
- env['ENV']['TMP'] = os.environ['TMP']
- env.Append(CPPPATH=['#platform/windows/include'])
- env.Append(LIBPATH=['#platform/windows/lib'])
-
- if (env["freetype"]!="no"):
- env.Append(CCFLAGS=['/DFREETYPE_ENABLED'])
- env.Append(CPPPATH=['#tools/freetype'])
- env.Append(CPPPATH=['#tools/freetype/freetype/include'])
-
- if (env["target"]=="release"):
-
- env.Append(CCFLAGS=['/O2'])
- env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS'])
- env.Append(LINKFLAGS=['/ENTRY:mainCRTStartup'])
-
- elif (env["target"]=="release_debug"):
-
- env.Append(CCFLAGS=['/O2','/DDEBUG_ENABLED'])
- env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
- elif (env["target"]=="debug_release"):
-
- env.Append(CCFLAGS=['/Zi','/Od'])
- env.Append(LINKFLAGS=['/DEBUG'])
- env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS'])
- env.Append(LINKFLAGS=['/ENTRY:mainCRTStartup'])
-
- elif (env["target"]=="debug"):
-
- env.Append(CCFLAGS=['/Zi','/DDEBUG_ENABLED','/DDEBUG_MEMORY_ENABLED','/DD3D_DEBUG_INFO','/Od'])
- env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
- env.Append(LINKFLAGS=['/DEBUG'])
-
-
- env.Append(CCFLAGS=['/MT','/Gd','/GR','/nologo'])
- env.Append(CXXFLAGS=['/TP'])
- env.Append(CPPFLAGS=['/DMSVC', '/GR', ])
- env.Append(CCFLAGS=['/I'+os.getenv("WindowsSdkDir")+"/Include"])
- env.Append(CCFLAGS=['/DWINDOWS_ENABLED'])
- env.Append(CCFLAGS=['/DRTAUDIO_ENABLED'])
- env.Append(CCFLAGS=['/DWIN32'])
- env.Append(CCFLAGS=['/DTYPED_METHOD_BIND'])
-
- env.Append(CCFLAGS=['/DGLES2_ENABLED'])
-
- env.Append(CCFLAGS=['/DGLEW_ENABLED'])
- LIBS=['winmm','opengl32','dsound','kernel32','ole32','user32','gdi32', 'IPHLPAPI','Shlwapi', 'wsock32', 'shell32','advapi32']
- env.Append(LINKFLAGS=[p+env["LIBSUFFIX"] for p in LIBS])
-
- env.Append(LIBPATH=[os.getenv("WindowsSdkDir")+"/Lib"])
- if (os.getenv("DXSDK_DIR")):
- DIRECTX_PATH=os.getenv("DXSDK_DIR")
- else:
- DIRECTX_PATH="C:/Program Files/Microsoft DirectX SDK (March 2009)"
-
- if (os.getenv("VCINSTALLDIR")):
- VC_PATH=os.getenv("VCINSTALLDIR")
- else:
- VC_PATH=""
-
- env.Append(CCFLAGS=["/I" + p for p in os.getenv("INCLUDE").split(";")])
- env.Append(LIBPATH=[p for p in os.getenv("LIB").split(";")])
- env.Append(CCFLAGS=["/I"+DIRECTX_PATH+"/Include"])
- env.Append(LIBPATH=[DIRECTX_PATH+"/Lib/x86"])
- env['ENV'] = os.environ;
- else:
-
- # Workaround for MinGW. See:
- # http://www.scons.org/wiki/LongCmdLinesOnWin32
- if (os.name=="nt"):
- import subprocess
-
- def mySubProcess(cmdline,env):
- #print "SPAWNED : " + cmdline
- startupinfo = subprocess.STARTUPINFO()
- startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
- proc = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
- stderr=subprocess.PIPE, startupinfo=startupinfo, shell = False, env = env)
- data, err = proc.communicate()
- rv = proc.wait()
- if rv:
- print "====="
- print err
- print "====="
- return rv
-
- def mySpawn(sh, escape, cmd, args, env):
-
- newargs = ' '.join(args[1:])
- cmdline = cmd + " " + newargs
-
- rv=0
- if len(cmdline) > 32000 and cmd.endswith("ar") :
- cmdline = cmd + " " + args[1] + " " + args[2] + " "
- for i in range(3,len(args)) :
- rv = mySubProcess( cmdline + args[i], env )
- if rv :
- break
- else:
- rv = mySubProcess( cmdline, env )
-
- return rv
-
- env['SPAWN'] = mySpawn
-
- #build using mingw
- if (os.name=="nt"):
- env['ENV']['TMP'] = os.environ['TMP'] #way to go scons, you can be so stupid sometimes
- else:
- env["PROGSUFFIX"]=env["PROGSUFFIX"]+".exe" # for linux cross-compilation
-
- mingw_prefix=""
-
- if (env["bits"]=="default"):
- env["bits"]="32"
-
- if (env["bits"]=="32"):
- env.Append(LINKFLAGS=['-static'])
- env.Append(LINKFLAGS=['-static-libgcc'])
- env.Append(LINKFLAGS=['-static-libstdc++'])
- mingw_prefix=env["mingw_prefix"];
- else:
- env.Append(LINKFLAGS=['-static'])
- mingw_prefix=env["mingw_prefix_64"];
-
- nulstr=""
-
- if (os.name=="posix"):
- nulstr=">/dev/null"
- else:
- nulstr=">nul"
-
-
-
- # if os.system(mingw_prefix+"gcc --version"+nulstr)!=0:
- # #not really super consistent but..
- # print("Can't find Windows compiler: "+mingw_prefix)
- # sys.exit(255)
-
- if (env["target"]=="release"):
-
- env.Append(CCFLAGS=['-O3','-ffast-math','-fomit-frame-pointer','-msse2'])
- env.Append(LINKFLAGS=['-Wl,--subsystem,windows'])
-
- elif (env["target"]=="release_debug"):
-
- env.Append(CCFLAGS=['-O2','-DDEBUG_ENABLED'])
-
- elif (env["target"]=="debug"):
-
- env.Append(CCFLAGS=['-g', '-Wall','-DDEBUG_ENABLED','-DDEBUG_MEMORY_ENABLED'])
-
- if (env["freetype"]!="no"):
- env.Append(CCFLAGS=['-DFREETYPE_ENABLED'])
- env.Append(CPPPATH=['#tools/freetype'])
- env.Append(CPPPATH=['#tools/freetype/freetype/include'])
-
- env["CC"]=mingw_prefix+"gcc"
- env['AS']=mingw_prefix+"as"
- env['CXX'] = mingw_prefix+"g++"
- env['AR'] = mingw_prefix+"ar"
- env['RANLIB'] = mingw_prefix+"ranlib"
- env['LD'] = mingw_prefix+"g++"
-
- #env['CC'] = "winegcc"
- #env['CXX'] = "wineg++"
-
- env.Append(CCFLAGS=['-DWINDOWS_ENABLED','-mwindows'])
- env.Append(CPPFLAGS=['-DRTAUDIO_ENABLED'])
- env.Append(CCFLAGS=['-DGLES2_ENABLED','-DGLEW_ENABLED'])
- env.Append(LIBS=['mingw32','opengl32', 'dsound', 'ole32', 'd3d9','winmm','gdi32','iphlpapi','shlwapi','wsock32','kernel32'])
-
- # if (env["bits"]=="32"):
-# # env.Append(LIBS=['gcc_s'])
- # #--with-arch=i686
- # env.Append(CPPFLAGS=['-march=i686'])
- # env.Append(LINKFLAGS=['-march=i686'])
-
-
-
-
- #'d3dx9d'
- env.Append(CPPFLAGS=['-DMINGW_ENABLED'])
- env.Append(LINKFLAGS=['-g'])
-
- import methods
- env.Append( BUILDERS = { 'GLSL120' : env.Builder(action = methods.build_legacygl_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
- env.Append( BUILDERS = { 'GLSL' : env.Builder(action = methods.build_glsl_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
- env.Append( BUILDERS = { 'HLSL9' : env.Builder(action = methods.build_hlsl_dx9_headers, suffix = 'hlsl.h',src_suffix = '.hlsl') } )
- env.Append( BUILDERS = { 'GLSL120GLES' : env.Builder(action = methods.build_gles2_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
-
-
-
+#
+# tested on | Windows native | Linux cross-compilation
+# ------------------------+-------------------+---------------------------
+# MSVS C++ 2010 Express | WORKS | n/a
+# Mingw-w64 | WORKS | WORKS
+# Mingw-w32 | WORKS | WORKS
+# MinGW | WORKS | untested
+#
+#####
+# Notes about MSVS C++ :
+#
+# - MSVC2010-Express compiles to 32bits only.
+#
+#####
+# Notes about Mingw-w64 and Mingw-w32 under Windows :
+#
+# - both can be installed using the official installer :
+# http://mingw-w64.sourceforge.net/download.php#mingw-builds
+#
+# - if you want to compile both 32bits and 64bits, don't forget to
+# run the installer twice to install them both.
+#
+# - install them into a path that does not contain spaces
+# ( example : "C:/Mingw-w32", "C:/Mingw-w64" )
+#
+# - if you want to compile faster using the "-j" option, don't forget
+# to install the appropriate version of the Pywin32 python extension
+# available from : http://sourceforge.net/projects/pywin32/files/
+#
+# - before running scons, you must add into the environment path
+# the path to the "/bin" directory of the Mingw version you want
+# to use :
+#
+# set PATH=C:/Mingw-w32/bin;%PATH%
+#
+# - then, scons should be able to detect gcc.
+# - Mingw-w32 only compiles 32bits.
+# - Mingw-w64 only compiles 64bits.
+#
+# - it is possible to add them both at the same time into the PATH env,
+# if you also define the MINGW32_PREFIX and MINGW64_PREFIX environment
+# variables.
+# For instance, you could store that set of commands into a .bat script
+# that you would run just before scons :
+#
+# set PATH=C:\mingw-w32\bin;%PATH%
+# set PATH=C:\mingw-w64\bin;%PATH%
+# set MINGW32_PREFIX=C:\mingw-w32\bin\
+# set MINGW64_PREFIX=C:\mingw-w64\bin\
+#
+#####
+# Notes about Mingw, Mingw-w64 and Mingw-w32 under Linux :
+#
+# - default toolchain prefixes are :
+# "i586-mingw32msvc-" for MinGW
+# "i686-w64-mingw32-" for Mingw-w32
+# "x86_64-w64-mingw32-" for Mingw-w64
+#
+# - if both MinGW and Mingw-w32 are installed on your system
+# Mingw-w32 should take the priority over MinGW.
+#
+# - it is possible to manually override prefixes by defining
+# the MINGW32_PREFIX and MINGW64_PREFIX environment variables.
+#
+#####
+# Notes about Mingw under Windows :
+#
+# - this is the MinGW version from http://mingw.org/
+# - install it into a path that does not contain spaces
+# ( example : "C:/MinGW" )
+# - several DirectX headers might be missing. You can copy them into
+# the C:/MinGW/include" directory from this page :
+# https://code.google.com/p/mingw-lib/source/browse/trunk/working/avcodec_to_widget_5/directx_include/
+# - before running scons, add the path to the "/bin" directory :
+# set PATH=C:/MinGW/bin;%PATH%
+# - scons should be able to detect gcc.
+#
+
+#####
+# TODO :
+#
+# - finish to cleanup this script to remove all the remains of previous hacks and workarounds
+# - make it work with the Windows7 SDK that is supposed to enable 64bits compilation for MSVC2010-Express
+# - confirm it works well with other Visual Studio versions.
+# - update the wiki about the pywin32 extension required for the "-j" option under Windows.
+# - update the wiki to document MINGW32_PREFIX and MINGW64_PREFIX
+#
+
+import os
+
+import sys
+
+
+def is_active():
+ return True
+
+def get_name():
+ return "Windows"
+
+def can_build():
+
+ if (os.name=="nt"):
+ #building natively on windows!
+ if (os.getenv("VSINSTALLDIR")):
+ return True
+ else:
+ print("\nMSVC not detected, attempting Mingw.")
+ mingw32 = ""
+ mingw64 = ""
+ if ( os.getenv("MINGW32_PREFIX") ) :
+ mingw32 = os.getenv("MINGW32_PREFIX")
+ if ( os.getenv("MINGW64_PREFIX") ) :
+ mingw64 = os.getenv("MINGW64_PREFIX")
+
+ test = "gcc --version > NUL 2>&1"
+ if os.system(test)!= 0 and os.system(mingw32+test)!=0 and os.system(mingw64+test)!=0 :
+ print("- could not detect gcc.")
+ print("Please, make sure a path to a Mingw /bin directory is accessible into the environment PATH.\n")
+ return False
+ else:
+ print("- gcc detected.")
+
+ return True
+
+ if (os.name=="posix"):
+
+ mingw = "i586-mingw32msvc-"
+ mingw64 = "x86_64-w64-mingw32-"
+ mingw32 = "i686-w64-mingw32-"
+
+ if (os.getenv("MINGW32_PREFIX")):
+ mingw32=os.getenv("MINGW32_PREFIX")
+ mingw = mingw32
+ if (os.getenv("MINGW64_PREFIX")):
+ mingw64=os.getenv("MINGW64_PREFIX")
+
+ test = "gcc --version &>/dev/null"
+ if (os.system(mingw+test) == 0 or os.system(mingw64+test) == 0 or os.system(mingw32+test) == 0):
+ return True
+
+ return False
+
+def get_opts():
+
+ mingw=""
+ mingw32=""
+ mingw64=""
+ if ( os.name == "posix" ):
+ mingw = "i586-mingw32msvc-"
+ mingw32 = "i686-w64-mingw32-"
+ mingw64 = "x86_64-w64-mingw32-"
+
+ if os.system(mingw32+"gcc --version &>/dev/null") != 0 :
+ mingw32 = mingw
+
+ if (os.getenv("MINGW32_PREFIX")):
+ mingw32=os.getenv("MINGW32_PREFIX")
+ mingw = mingw32
+ if (os.getenv("MINGW64_PREFIX")):
+ mingw64=os.getenv("MINGW64_PREFIX")
+
+
+ return [
+ ('mingw_prefix','Mingw Prefix',mingw32),
+ ('mingw_prefix_64','Mingw Prefix 64 bits',mingw64),
+ ]
+
+def get_flags():
+
+ return [
+ ('freetype','builtin'), #use builtin freetype
+ ('openssl','builtin'), #use builtin openssl
+ ]
+
+def build_res_file( target, source, env ):
+
+ cmdbase = ""
+ if (env["bits"] == "32"):
+ cmdbase = env['mingw_prefix']
+ else:
+ cmdbase = env['mingw_prefix_64']
+ CPPPATH = env['CPPPATH']
+ cmdbase = cmdbase + 'windres --include-dir . '
+ import subprocess
+ for x in range(len(source)):
+ cmd = cmdbase + '-i ' + str(source[x]) + ' -o ' + str(target[x])
+ try:
+ out = subprocess.Popen(cmd,shell = True,stderr = subprocess.PIPE).communicate()
+ if len(out[1]):
+ return 1
+ except:
+ return 1
+ return 0
+
+def configure(env):
+
+ env.Append(CPPPATH=['#platform/windows'])
+ env['is_mingw']=False
+ if (os.name=="nt" and os.getenv("VSINSTALLDIR")!=None):
+ #build using visual studio
+ env['ENV']['TMP'] = os.environ['TMP']
+ env.Append(CPPPATH=['#platform/windows/include'])
+ env.Append(LIBPATH=['#platform/windows/lib'])
+
+ if (env["freetype"]!="no"):
+ env.Append(CCFLAGS=['/DFREETYPE_ENABLED'])
+ env.Append(CPPPATH=['#tools/freetype'])
+ env.Append(CPPPATH=['#tools/freetype/freetype/include'])
+
+ if (env["target"]=="release"):
+
+ env.Append(CCFLAGS=['/O2'])
+ env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS'])
+ env.Append(LINKFLAGS=['/ENTRY:mainCRTStartup'])
+
+ elif (env["target"]=="release_debug"):
+
+ env.Append(CCFLAGS=['/O2','/DDEBUG_ENABLED'])
+ env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
+ elif (env["target"]=="debug_release"):
+
+ env.Append(CCFLAGS=['/Z7','/Od'])
+ env.Append(LINKFLAGS=['/DEBUG'])
+ env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS'])
+ env.Append(LINKFLAGS=['/ENTRY:mainCRTStartup'])
+
+ elif (env["target"]=="debug"):
+
+ env.Append(CCFLAGS=['/Z7','/DDEBUG_ENABLED','/DDEBUG_MEMORY_ENABLED','/DD3D_DEBUG_INFO','/Od'])
+ env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
+ env.Append(LINKFLAGS=['/DEBUG'])
+
+
+ env.Append(CCFLAGS=['/MT','/Gd','/GR','/nologo'])
+ env.Append(CXXFLAGS=['/TP'])
+ env.Append(CPPFLAGS=['/DMSVC', '/GR', ])
+ env.Append(CCFLAGS=['/I'+os.getenv("WindowsSdkDir")+"/Include"])
+ env.Append(CCFLAGS=['/DWINDOWS_ENABLED'])
+ env.Append(CCFLAGS=['/DRTAUDIO_ENABLED'])
+ env.Append(CCFLAGS=['/DWIN32'])
+ env.Append(CCFLAGS=['/DTYPED_METHOD_BIND'])
+
+ env.Append(CCFLAGS=['/DGLES2_ENABLED'])
+
+ env.Append(CCFLAGS=['/DGLEW_ENABLED'])
+ LIBS=['winmm','opengl32','dsound','kernel32','ole32','oleaut32','user32','gdi32', 'IPHLPAPI','Shlwapi', 'wsock32', 'shell32','advapi32','dinput8','dxguid']
+ env.Append(LINKFLAGS=[p+env["LIBSUFFIX"] for p in LIBS])
+
+ env.Append(LIBPATH=[os.getenv("WindowsSdkDir")+"/Lib"])
+ if (os.getenv("DXSDK_DIR")):
+ DIRECTX_PATH=os.getenv("DXSDK_DIR")
+ else:
+ DIRECTX_PATH="C:/Program Files/Microsoft DirectX SDK (March 2009)"
+
+ if (os.getenv("VCINSTALLDIR")):
+ VC_PATH=os.getenv("VCINSTALLDIR")
+ else:
+ VC_PATH=""
+
+ env.Append(CCFLAGS=["/I" + p for p in os.getenv("INCLUDE").split(";")])
+ env.Append(LIBPATH=[p for p in os.getenv("LIB").split(";")])
+ env.Append(CCFLAGS=["/I"+DIRECTX_PATH+"/Include"])
+ env.Append(LIBPATH=[DIRECTX_PATH+"/Lib/x86"])
+ env['ENV'] = os.environ;
+ env["x86_opt_vc"]=env["bits"]!="64"
+ else:
+
+ # Workaround for MinGW. See:
+ # http://www.scons.org/wiki/LongCmdLinesOnWin32
+ if (os.name=="nt"):
+ import subprocess
+
+ def mySubProcess(cmdline,env):
+ #print "SPAWNED : " + cmdline
+ startupinfo = subprocess.STARTUPINFO()
+ startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
+ proc = subprocess.Popen(cmdline, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE, startupinfo=startupinfo, shell = False, env = env)
+ data, err = proc.communicate()
+ rv = proc.wait()
+ if rv:
+ print "====="
+ print err
+ print "====="
+ return rv
+
+ def mySpawn(sh, escape, cmd, args, env):
+
+ newargs = ' '.join(args[1:])
+ cmdline = cmd + " " + newargs
+
+ rv=0
+ if len(cmdline) > 32000 and cmd.endswith("ar") :
+ cmdline = cmd + " " + args[1] + " " + args[2] + " "
+ for i in range(3,len(args)) :
+ rv = mySubProcess( cmdline + args[i], env )
+ if rv :
+ break
+ else:
+ rv = mySubProcess( cmdline, env )
+
+ return rv
+
+ env['SPAWN'] = mySpawn
+
+ #build using mingw
+ if (os.name=="nt"):
+ env['ENV']['TMP'] = os.environ['TMP'] #way to go scons, you can be so stupid sometimes
+ else:
+ env["PROGSUFFIX"]=env["PROGSUFFIX"]+".exe" # for linux cross-compilation
+
+ mingw_prefix=""
+
+ if (env["bits"]=="default"):
+ env["bits"]="32"
+
+ if (env["bits"]=="32"):
+ env.Append(LINKFLAGS=['-static'])
+ env.Append(LINKFLAGS=['-static-libgcc'])
+ env.Append(LINKFLAGS=['-static-libstdc++'])
+ mingw_prefix=env["mingw_prefix"];
+ else:
+ env.Append(LINKFLAGS=['-static'])
+ mingw_prefix=env["mingw_prefix_64"];
+
+ nulstr=""
+
+ if (os.name=="posix"):
+ nulstr=">/dev/null"
+ else:
+ nulstr=">nul"
+
+
+
+ # if os.system(mingw_prefix+"gcc --version"+nulstr)!=0:
+ # #not really super consistent but..
+ # print("Can't find Windows compiler: "+mingw_prefix)
+ # sys.exit(255)
+
+ if (env["target"]=="release"):
+
+ env.Append(CCFLAGS=['-ffast-math','-fomit-frame-pointer','-msse2'])
+
+ if (env["bits"]=="64"):
+ env.Append(CCFLAGS=['-O3'])
+ else:
+ env.Append(CCFLAGS=['-O2'])
+
+ env.Append(LINKFLAGS=['-Wl,--subsystem,windows'])
+
+ elif (env["target"]=="release_debug"):
+
+ env.Append(CCFLAGS=['-O2','-DDEBUG_ENABLED'])
+
+ elif (env["target"]=="debug"):
+
+ env.Append(CCFLAGS=['-g', '-Wall','-DDEBUG_ENABLED','-DDEBUG_MEMORY_ENABLED'])
+
+ if (env["freetype"]!="no"):
+ env.Append(CCFLAGS=['-DFREETYPE_ENABLED'])
+ env.Append(CPPPATH=['#tools/freetype'])
+ env.Append(CPPPATH=['#tools/freetype/freetype/include'])
+
+ env["CC"]=mingw_prefix+"gcc"
+ env['AS']=mingw_prefix+"as"
+ env['CXX'] = mingw_prefix+"g++"
+ env['AR'] = mingw_prefix+"ar"
+ env['RANLIB'] = mingw_prefix+"ranlib"
+ env['LD'] = mingw_prefix+"g++"
+ env["x86_opt_gcc"]=True
+
+ #env['CC'] = "winegcc"
+ #env['CXX'] = "wineg++"
+
+ env.Append(CCFLAGS=['-DWINDOWS_ENABLED','-mwindows'])
+ env.Append(CPPFLAGS=['-DRTAUDIO_ENABLED'])
+ env.Append(CCFLAGS=['-DGLES2_ENABLED','-DGLEW_ENABLED'])
+ env.Append(LIBS=['mingw32','opengl32', 'dsound', 'ole32', 'd3d9','winmm','gdi32','iphlpapi','shlwapi','wsock32','kernel32', 'oleaut32', 'dinput8', 'dxguid'])
+
+ # if (env["bits"]=="32"):
+ # env.Append(LIBS=['gcc_s'])
+ # #--with-arch=i686
+ # env.Append(CPPFLAGS=['-march=i686'])
+ # env.Append(LINKFLAGS=['-march=i686'])
+
+
+
+
+ #'d3dx9d'
+ env.Append(CPPFLAGS=['-DMINGW_ENABLED'])
+ #env.Append(LINKFLAGS=['-g'])
+
+ # resrc
+ env['is_mingw']=True
+ env.Append( BUILDERS = { 'RES' : env.Builder(action = build_res_file, suffix = '.o',src_suffix = '.rc') } )
+
+ import methods
+ env.Append( BUILDERS = { 'GLSL120' : env.Builder(action = methods.build_legacygl_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
+ env.Append( BUILDERS = { 'GLSL' : env.Builder(action = methods.build_glsl_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
+ env.Append( BUILDERS = { 'HLSL9' : env.Builder(action = methods.build_hlsl_dx9_headers, suffix = 'hlsl.h',src_suffix = '.hlsl') } )
+ env.Append( BUILDERS = { 'GLSL120GLES' : env.Builder(action = methods.build_gles2_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
+
+
diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp
index 952f51fdd4..899edde087 100644
--- a/platform/windows/export/export.cpp
+++ b/platform/windows/export/export.cpp
@@ -1,6 +1,345 @@
+/*************************************************************************/
+/* export.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
+
#include "export.h"
#include "platform/windows/logo.h"
-#include "tools/editor/editor_import_export.h"
+#include "os/os.h"
+#include "globals.h"
+#include "tools/editor/editor_node.h"
+#include "tools/pe_bliss/pe_bliss_godot.h"
+
+/**
+ @author Masoud BaniHashemian <masoudbh3@gmail.com>
+*/
+
+
+void EditorExportPlatformWindows::store_16(DVector<uint8_t>& vector, uint16_t value) {
+ const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&value);
+ int size = vector.size();
+ vector.resize( size + 2 );
+ DVector<uint8_t>::Write w = vector.write();
+ w[size]=bytes[0];
+ w[size+1]=bytes[1];
+}
+void EditorExportPlatformWindows::store_32(DVector<uint8_t>& vector, uint32_t value) {
+ const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&value);
+ int size = vector.size();
+ vector.resize( size + 4 );
+ DVector<uint8_t>::Write w = vector.write();
+ w[size]=bytes[0];
+ w[size+1]=bytes[1];
+ w[size+2]=bytes[2];
+ w[size+3]=bytes[3];
+}
+
+bool EditorExportPlatformWindows::_set(const StringName& p_name, const Variant& p_value) {
+
+ String n = p_name;
+
+ if (n=="icon/icon_ico") {
+
+ icon_ico=p_value;
+ } else if (n=="icon/icon_png") {
+
+ icon_png=p_value;
+ } else if (n=="icon/icon_png16x16") {
+
+ icon16=p_value;
+ } else if (n=="icon/icon_png32x32") {
+
+ icon32=p_value;
+ } else if (n=="icon/icon_png48x48") {
+
+ icon48=p_value;
+ } else if (n=="icon/icon_png64x64") {
+
+ icon64=p_value;
+ } else if (n=="icon/icon_png128x128") {
+
+ icon128=p_value;
+ } else if (n=="icon/icon_png256x256") {
+
+ icon256=p_value;
+ } else if (n=="version_info/version_major") {
+
+ version_major=p_value;
+ } else if (n=="version_info/version_minor") {
+
+ version_minor=p_value;
+ } else if (n=="version_info/version_text") {
+
+ version_text=p_value;
+ } else if (n=="version_info/company_name") {
+
+ company_name=p_value;
+ } else if (n=="version_info/file_description") {
+
+ file_description=p_value;
+ } else if (n=="version_info/product_name") {
+
+ product_name=p_value;
+ } else if (n=="version_info/legal_copyright") {
+
+ legal_copyright=p_value;
+ } else if (n=="version_info/add_godot_version") {
+
+ set_godot_version=p_value;
+ } else
+ return false;
+
+ return true;
+
+}
+
+bool EditorExportPlatformWindows::_get(const StringName& p_name,Variant &r_ret) const {
+
+ String n = p_name;
+
+ if (n=="icon/icon_ico") {
+
+ r_ret=icon_ico;
+ } else if (n=="icon/icon_png") {
+
+ r_ret=icon_png;
+ } else if (n=="icon/icon_png16x16") {
+
+ r_ret=icon16;
+ } else if (n=="icon/icon_png32x32") {
+
+ r_ret=icon32;
+ } else if (n=="icon/icon_png48x48") {
+
+ r_ret=icon48;
+ } else if (n=="icon/icon_png64x64") {
+
+ r_ret=icon64;
+ } else if (n=="icon/icon_png128x128") {
+
+ r_ret=icon128;
+ } else if (n=="icon/icon_png256x256") {
+
+ r_ret=icon256;
+ } else if (n=="version_info/version_major") {
+
+ r_ret=version_major;
+ } else if (n=="version_info/version_minor") {
+
+ r_ret=version_minor;
+ } else if (n=="version_info/version_text") {
+
+ r_ret=version_text;
+ } else if (n=="version_info/company_name") {
+
+ r_ret=company_name;
+ } else if (n=="version_info/file_description") {
+
+ r_ret=file_description;
+ } else if (n=="version_info/product_name") {
+
+ r_ret=product_name;
+ } else if (n=="version_info/legal_copyright") {
+
+ r_ret=legal_copyright;
+ } else if (n=="version_info/add_godot_version") {
+
+ r_ret=set_godot_version;
+ } else
+ return false;
+
+ return true;
+
+}
+
+void EditorExportPlatformWindows::_get_property_list( List<PropertyInfo> *p_list) const {
+
+ p_list->push_back( PropertyInfo( Variant::STRING, "icon/icon_ico",PROPERTY_HINT_FILE,"ico") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "icon/icon_png",PROPERTY_HINT_FILE,"png") );
+ p_list->push_back( PropertyInfo( Variant::BOOL, "icon/icon_png16x16") );
+ p_list->push_back( PropertyInfo( Variant::BOOL, "icon/icon_png32x32") );
+ p_list->push_back( PropertyInfo( Variant::BOOL, "icon/icon_png48x48") );
+ p_list->push_back( PropertyInfo( Variant::BOOL, "icon/icon_png64x64") );
+ p_list->push_back( PropertyInfo( Variant::BOOL, "icon/icon_png128x128") );
+ p_list->push_back( PropertyInfo( Variant::BOOL, "icon/icon_png256x256") );
+ p_list->push_back( PropertyInfo( Variant::INT, "version_info/version_major", PROPERTY_HINT_RANGE,"0,65535,1"));
+ p_list->push_back( PropertyInfo( Variant::INT, "version_info/version_minor", PROPERTY_HINT_RANGE,"0,65535,0"));
+ p_list->push_back( PropertyInfo( Variant::STRING, "version_info/version_text") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "version_info/company_name") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "version_info/file_description") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "version_info/product_name") );
+ p_list->push_back( PropertyInfo( Variant::STRING, "version_info/legal_copyright") );
+ p_list->push_back( PropertyInfo( Variant::BOOL, "version_info/add_godot_version") );
+
+}
+
+Error EditorExportPlatformWindows::export_project(const String& p_path, bool p_debug, int p_flags) {
+
+ Error err = EditorExportPlatformPC::export_project(p_path, p_debug, p_flags);
+ if(err != OK)
+ {
+ return err;
+ }
+ EditorProgress ep("editexe","Edit EXE File",102);
+ ep.step("Create ico file..",0);
+
+ DVector<uint8_t> icon_content;
+ if (this->icon_ico!="" && this->icon_ico.ends_with(".ico")) {
+ FileAccess *f = FileAccess::open(this->icon_ico,FileAccess::READ);
+ if (f) {
+ icon_content.resize(f->get_len());
+ DVector<uint8_t>::Write write = icon_content.write();
+ f->get_buffer(write.ptr(),icon_content.size());
+ f->close();
+ memdelete(f);
+ }
+ } else if (this->icon_png!="" && this->icon_png.ends_with(".png") && (icon16 || icon32 || icon48 || icon64 || icon128 || icon256)) {
+ #ifdef PNG_ENABLED
+ Vector<Image> pngs;
+ Image png;
+ Error err_png = png.load(this->icon_png);
+ if (err_png==OK && !png.empty()) {
+ if(icon256) {
+ Image icon_256(png);
+ if(!(png.get_height()==256 && png.get_width()==256)) icon_256.resize(256,256);
+ pngs.push_back(icon_256);
+ }
+ if(icon128) {
+ Image icon_128(png);
+ if(!(png.get_height()==128 && png.get_width()==128)) icon_128.resize(128,128);
+ pngs.push_back(icon_128);
+ }
+ if(icon64) {
+ Image icon_64(png);
+ if(!(png.get_height()==64 && png.get_width()==64)) icon_64.resize(64,64);
+ pngs.push_back(icon_64);
+ }
+ if(icon48) {
+ Image icon_48(png);
+ if(!(png.get_height()==48 && png.get_width()==48)) icon_48.resize(48,48);
+ pngs.push_back(icon_48);
+ }
+ if(icon32) {
+ Image icon_32(png);
+ if(!(png.get_height()==32 && png.get_width()==32)) icon_32.resize(32,32);
+ pngs.push_back(icon_32);
+ }
+ if(icon16) {
+ Image icon_16(png);
+ if(!(png.get_height()==16 && png.get_width()==16)) icon_16.resize(16,16);
+ pngs.push_back(icon_16);
+ }
+ // create icon according to https://www.daubnet.com/en/file-format-ico
+ store_16(icon_content,0); //Reserved
+ store_16(icon_content,1); //Type
+ store_16(icon_content,pngs.size()); //Count
+ int offset = 6+pngs.size()*16;
+ //List of bitmaps
+ for(int i=0;i<pngs.size();i++) {
+ int w = pngs[i].get_width();
+ int h = pngs[i].get_height();
+ icon_content.push_back(w<256?w:0); //width
+ icon_content.push_back(h<256?h:0); //height
+ icon_content.push_back(0); //ColorCount = 0
+ icon_content.push_back(0); //Reserved
+ store_16(icon_content,1); //Planes
+ store_16(icon_content,32); //BitCount (bit per pixel)
+ int size = 40 + (w * h * 4) + (w * h / 8);
+ store_32(icon_content,size); //Size of (InfoHeader + ANDbitmap + XORbitmap)
+ store_32(icon_content,offset); //FileOffset
+ offset += size;
+ }
+ //Write bmp files.
+ for(int i=0;i<pngs.size();i++) {
+ int w = pngs[i].get_width();
+ int h = pngs[i].get_height();
+ store_32(icon_content,40); //Size of InfoHeader structure = 40
+ store_32(icon_content,w); //Width
+ store_32(icon_content,h*2); //Height
+ store_16(icon_content,1); //Planes
+ store_16(icon_content,32); //BitCount
+ store_32(icon_content,0); //Compression
+ store_32(icon_content,w*h*4); //ImageSize = Size of Image in Bytes
+ store_32(icon_content,0); //unused = 0
+ store_32(icon_content,0); //unused = 0
+ store_32(icon_content,0); //unused = 0
+ store_32(icon_content,0); //unused = 0
+ //XORBitmap
+ for(int y=h-1;y>=0;y--) {
+ for(int x=0;x<w;x++) {
+ store_32(icon_content,pngs[i].get_pixel(x,y).to_32());
+ }
+ }
+ //ANDBitmap
+ for(int m=0;m<(w * h / 8);m+=4) store_32(icon_content,0x00000000); // Add empty ANDBitmap , TODO create full ANDBitmap Structure if need.
+ }
+ }
+ #endif
+ }
+
+ ep.step("Add rsrc..",50);
+
+ String basename = Globals::get_singleton()->get("application/name");
+ product_name=product_name.replace("$genname",basename);
+ String godot_version;
+ if(set_godot_version) godot_version = String( VERSION_MKSTRING );
+ String ret = pe_bliss_add_resrc(p_path.utf8(), version_major, version_minor,
+ company_name, file_description, legal_copyright, version_text,
+ product_name, godot_version, icon_content);
+ if (ret.empty()) {
+ return OK;
+ } else {
+ EditorNode::add_io_error(ret);
+ return ERR_FILE_CANT_WRITE;
+ }
+}
+
+EditorExportPlatformWindows::EditorExportPlatformWindows() {
+
+ icon16=true;
+ icon32=true;
+ icon48=true;
+ icon64=true;
+ icon128=true;
+ icon256=true;
+ product_name="$genname";
+ company_name="Godot Engine";
+ file_description="Created With Godot Engine";
+ version_text="1.0";
+ OS::Date date = OS::get_singleton()->get_date();
+ legal_copyright="Copyright (c) 2007-";
+ legal_copyright+=String::num(date.year);
+ legal_copyright+=" Juan Linietsky, Ariel Manzur";
+ version_major=1;
+ version_minor=0;
+ set_godot_version=true;
+}
+
+
void register_windows_exporter() {
@@ -9,7 +348,7 @@ void register_windows_exporter() {
logo->create_from_image(img);
{
- Ref<EditorExportPlatformPC> exporter = Ref<EditorExportPlatformPC>( memnew(EditorExportPlatformPC) );
+ Ref<EditorExportPlatformWindows> exporter = Ref<EditorExportPlatformWindows>( memnew(EditorExportPlatformWindows) );
exporter->set_binary_extension("exe");
exporter->set_release_binary32("windows_32_release.exe");
exporter->set_debug_binary32("windows_32_debug.exe");
diff --git a/platform/windows/export/export.h b/platform/windows/export/export.h
index de3dc3fa50..2424efc861 100644
--- a/platform/windows/export/export.h
+++ b/platform/windows/export/export.h
@@ -1,3 +1,37 @@
+#include "tools/editor/editor_import_export.h"
+
+class EditorExportPlatformWindows : public EditorExportPlatformPC {
+ OBJ_TYPE( EditorExportPlatformWindows,EditorExportPlatformPC );
+
+private:
+ String icon_ico;
+ String icon_png;
+ bool icon16;
+ bool icon32;
+ bool icon48;
+ bool icon64;
+ bool icon128;
+ bool icon256;
+ String company_name;
+ String file_description;
+ String product_name;
+ String legal_copyright;
+ String version_text;
+ int version_major;
+ int version_minor;
+ bool set_godot_version;
+ void store_16(DVector<uint8_t>& vector, uint16_t value); ///< store 16 bits uint
+ void store_32(DVector<uint8_t>& vector, uint32_t value); ///< store 32 bits uint
+
+protected:
+ bool _set(const StringName& p_name, const Variant& p_value);
+ bool _get(const StringName& p_name,Variant &r_ret) const;
+ void _get_property_list( List<PropertyInfo> *p_list) const;
+
+public:
+ Error export_project(const String& p_path, bool p_debug,int p_flags=0);
+ EditorExportPlatformWindows();
+};
void register_windows_exporter();
diff --git a/platform/windows/godot.ico b/platform/windows/godot.ico
new file mode 100644
index 0000000000..e57ce36529
--- /dev/null
+++ b/platform/windows/godot.ico
Binary files differ
diff --git a/platform/windows/godot_res.rc b/platform/windows/godot_res.rc
new file mode 100644
index 0000000000..5f1e951e0f
--- /dev/null
+++ b/platform/windows/godot_res.rc
@@ -0,0 +1,33 @@
+#include "core/version.h"
+#ifndef _STR
+#define _STR(m_x) #m_x
+#define _MKSTR(m_x) _STR(m_x)
+#endif
+
+GODOT_ICON ICON platform/windows/godot.ico
+
+1 VERSIONINFO
+FILEVERSION VERSION_MAJOR,VERSION_MINOR,0,0
+PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,0,0
+FILEOS 4
+FILETYPE 1
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Godot Engine"
+ VALUE "FileDescription", _MKSTR(VERSION_NAME) " Editor (" _MKSTR(VERSION_STATUS) ")"
+ VALUE "FileVersion", _MKSTR(VERSION_MAJOR) "." _MKSTR(VERSION_MINOR) "."_MKSTR(VERSION_REVISION)
+ VALUE "ProductName", _MKSTR(VERSION_NAME)
+ VALUE "Licence", "MIT"
+ VALUE "LegalCopyright", "Copyright (c) 2007-" _MKSTR(VERSION_YEAR) " Juan Linietsky, Ariel Manzur"
+ VALUE "Info", "http://www.godotengine.org"
+ VALUE "ProductVersion", _MKSTR(VERSION_MAJOR) "." _MKSTR(VERSION_MINOR) "."_MKSTR(VERSION_REVISION)
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/platform/windows/godot_win.cpp b/platform/windows/godot_win.cpp
index fe39051670..fa7989c726 100644
--- a/platform/windows/godot_win.cpp
+++ b/platform/windows/godot_win.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/windows/joystick.cpp b/platform/windows/joystick.cpp
new file mode 100644
index 0000000000..f4fb09820f
--- /dev/null
+++ b/platform/windows/joystick.cpp
@@ -0,0 +1,536 @@
+/*************************************************************************/
+/* joystick.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
+//author: Andreas Haas <hondres, liugam3@gmail.com>
+#include "joystick.h"
+#include <iostream>
+#include <wbemidl.h>
+#include <oleauto.h>
+
+#ifndef __GNUC__
+#define __builtin_bswap32 _byteswap_ulong
+#endif
+
+DWORD WINAPI _xinput_get_state(DWORD dwUserIndex, XINPUT_STATE* pState) { return ERROR_DEVICE_NOT_CONNECTED; }
+
+joystick_windows::joystick_windows() {
+
+}
+
+joystick_windows::joystick_windows(InputDefault* _input, HWND* hwnd) {
+
+ input = _input;
+ hWnd = hwnd;
+ joystick_count = 0;
+ dinput = NULL;
+ xinput_dll = NULL;
+ xinput_get_state = NULL;
+
+ load_xinput();
+
+ for (int i = 0; i < JOYSTICKS_MAX; i++)
+ attached_joysticks[i] = false;
+
+
+ HRESULT result;
+ result = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&dinput, NULL);
+ if (FAILED(result)) {
+ printf("failed init DINPUT: %ld\n", result);
+ }
+ probe_joysticks();
+}
+
+joystick_windows::~joystick_windows() {
+
+ close_joystick();
+ dinput->Release();
+ unload_xinput();
+}
+
+
+bool joystick_windows::have_device(const GUID &p_guid) {
+
+ for (int i = 0; i < JOYSTICKS_MAX; i++) {
+
+ if (d_joysticks[i].guid == p_guid) {
+
+ d_joysticks[i].confirmed = true;
+ return true;
+ }
+ }
+ return false;
+}
+
+int joystick_windows::check_free_joy_slot() const {
+
+ for (int i = 0; i < JOYSTICKS_MAX; i++) {
+
+ if (!attached_joysticks[i])
+ return i;
+ }
+ return -1;
+}
+
+
+// adapted from SDL2, works a lot better than the MSDN version
+bool joystick_windows::is_xinput_device(const GUID *p_guid) {
+
+ static GUID IID_ValveStreamingGamepad = { MAKELONG(0x28DE, 0x11FF), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
+ static GUID IID_X360WiredGamepad = { MAKELONG(0x045E, 0x02A1), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
+ static GUID IID_X360WirelessGamepad = { MAKELONG(0x045E, 0x028E), 0x0000, 0x0000, { 0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44 } };
+
+ if (p_guid == &IID_ValveStreamingGamepad || p_guid == &IID_X360WiredGamepad || p_guid == &IID_X360WirelessGamepad)
+ return true;
+
+ PRAWINPUTDEVICELIST dev_list = NULL;
+ unsigned int dev_list_count = 0;
+
+ if (GetRawInputDeviceList(NULL, &dev_list_count, sizeof(RAWINPUTDEVICELIST)) == -1) {
+ return false;
+ }
+ dev_list = (PRAWINPUTDEVICELIST) malloc(sizeof(RAWINPUTDEVICELIST) * dev_list_count);
+ if (!dev_list) return false;
+
+ if (GetRawInputDeviceList(dev_list, &dev_list_count, sizeof(RAWINPUTDEVICELIST)) == -1) {
+ free(dev_list);
+ return false;
+ }
+ for (int i = 0; i < dev_list_count; i++) {
+
+ RID_DEVICE_INFO rdi;
+ char dev_name[128];
+ UINT rdiSize = sizeof(rdi);
+ UINT nameSize = sizeof(dev_name);
+
+ rdi.cbSize = rdiSize;
+ if ( (dev_list[i].dwType == RIM_TYPEHID) &&
+ (GetRawInputDeviceInfoA(dev_list[i].hDevice, RIDI_DEVICEINFO, &rdi, &rdiSize) != (UINT)-1) &&
+ (MAKELONG(rdi.hid.dwVendorId, rdi.hid.dwProductId) == (LONG)p_guid->Data1) &&
+ (GetRawInputDeviceInfoA(dev_list[i].hDevice, RIDI_DEVICENAME, &dev_name, &nameSize) != (UINT)-1) &&
+ (strstr(dev_name, "IG_") != NULL)) {
+
+ free(dev_list);
+ return true;
+ }
+ }
+ free(dev_list);
+ return false;
+}
+
+bool joystick_windows::setup_dinput_joystick(const DIDEVICEINSTANCE* instance) {
+
+ HRESULT hr;
+ int num = check_free_joy_slot();
+
+ if (have_device(instance->guidInstance) || num == -1)
+ return false;
+
+ d_joysticks[joystick_count] = dinput_gamepad();
+ dinput_gamepad* joy = &d_joysticks[joystick_count];
+
+ const DWORD devtype = (instance->dwDevType & 0xFF);
+
+ if ((devtype != DI8DEVTYPE_JOYSTICK) && (devtype != DI8DEVTYPE_GAMEPAD) && (devtype != DI8DEVTYPE_1STPERSON)) {
+ //printf("ignore device %s, type %x\n", instance->tszProductName, devtype);
+ return false;
+ }
+
+ hr = dinput->CreateDevice(instance->guidInstance, &joy->di_joy, NULL);
+
+ if (FAILED(hr)) {
+
+ //std::wcout << "failed to create device: " << instance->tszProductName << std::endl;
+ return false;
+ }
+
+ const GUID &guid = instance->guidProduct;
+ char uid[128];
+ sprintf(uid, "%08lx%04hx%04hx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
+ __builtin_bswap32(guid.Data1), guid.Data2, guid.Data3,
+ guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
+ guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
+
+ id_to_change = joystick_count;
+
+ joy->di_joy->SetDataFormat(&c_dfDIJoystick2);
+ joy->di_joy->SetCooperativeLevel(*hWnd, DISCL_FOREGROUND);
+ joy->di_joy->EnumObjects(objectsCallback, this, NULL);
+ joy->joy_axis.sort();
+
+ joy->guid = instance->guidInstance;
+ input->joy_connection_changed(num, true, instance->tszProductName, uid);
+ joy->attached = true;
+ joy->id = num;
+ attached_joysticks[num] = true;
+ joy->confirmed = true;
+ joystick_count++;
+ return true;
+}
+
+void joystick_windows::setup_joystick_object(const DIDEVICEOBJECTINSTANCE *ob, int p_joy_id) {
+
+ if (ob->dwType & DIDFT_AXIS) {
+
+ HRESULT res;
+ DIPROPRANGE prop_range;
+ DIPROPDWORD dilong;
+ DWORD ofs;
+ if (ob->guidType == GUID_XAxis)
+ ofs = DIJOFS_X;
+ else if (ob->guidType == GUID_YAxis)
+ ofs = DIJOFS_Y;
+ else if (ob->guidType == GUID_ZAxis)
+ ofs = DIJOFS_Z;
+ else if (ob->guidType == GUID_RxAxis)
+ ofs = DIJOFS_RX;
+ else if (ob->guidType == GUID_RyAxis)
+ ofs = DIJOFS_RY;
+ else if (ob->guidType == GUID_RzAxis)
+ ofs = DIJOFS_RZ;
+ else if (ob->guidType == GUID_Slider)
+ ofs = DIJOFS_SLIDER(0);
+ else
+ return;
+ prop_range.diph.dwSize = sizeof(DIPROPRANGE);
+ prop_range.diph.dwHeaderSize = sizeof(DIPROPHEADER);
+ prop_range.diph.dwObj = ob->dwType;
+ prop_range.diph.dwHow = DIPH_BYID;
+ prop_range.lMin = -MAX_JOY_AXIS;
+ prop_range.lMax = +MAX_JOY_AXIS;
+
+ dinput_gamepad &joy = d_joysticks[p_joy_id];
+
+
+ res = IDirectInputDevice8_SetProperty(joy.di_joy, DIPROP_RANGE, &prop_range.diph);
+ if (FAILED(res))
+ return;
+
+ dilong.diph.dwSize = sizeof(dilong);
+ dilong.diph.dwHeaderSize = sizeof(dilong.diph);
+ dilong.diph.dwObj = ob->dwType;
+ dilong.diph.dwHow = DIPH_BYID;
+ dilong.dwData = 0;
+
+ res = IDirectInputDevice8_SetProperty(joy.di_joy, DIPROP_DEADZONE, &dilong.diph);
+ if (FAILED(res))
+ return;
+
+ joy.joy_axis.push_back(ofs);
+ }
+}
+
+BOOL CALLBACK joystick_windows::enumCallback(const DIDEVICEINSTANCE* instance, void* pContext) {
+
+
+ joystick_windows* self = (joystick_windows*)pContext;
+ if (self->is_xinput_device(&instance->guidProduct)) {;
+ return DIENUM_CONTINUE;
+ }
+ self->setup_dinput_joystick(instance);
+ return DIENUM_CONTINUE;
+}
+
+BOOL CALLBACK joystick_windows::objectsCallback(const DIDEVICEOBJECTINSTANCE *instance, void *context) {
+
+ joystick_windows* self = (joystick_windows*)context;
+ self->setup_joystick_object(instance, self->id_to_change);
+
+ return DIENUM_CONTINUE;
+}
+
+void joystick_windows::close_joystick(int id) {
+
+ if (id == -1) {
+
+ for (int i = 0; i < JOYSTICKS_MAX; i++) {
+
+ close_joystick(i);
+ }
+ return;
+ }
+
+ if (!d_joysticks[id].attached) return;
+
+ d_joysticks[id].di_joy->Unacquire();
+ d_joysticks[id].di_joy->Release();
+ d_joysticks[id].attached = false;
+ attached_joysticks[d_joysticks[id].id] = false;
+ d_joysticks[id].guid.Data1 = d_joysticks[id].guid.Data2 = d_joysticks[id].guid.Data3 = 0;
+ input->joy_connection_changed(id, false, "");
+ joystick_count--;
+}
+
+void joystick_windows::probe_joysticks() {
+
+ DWORD dwResult;
+ for (DWORD i = 0; i < XUSER_MAX_COUNT; i++) {
+
+ ZeroMemory(&x_joysticks[i].state, sizeof(XINPUT_STATE));
+
+ dwResult = xinput_get_state(i, &x_joysticks[i].state);
+ if ( dwResult == ERROR_SUCCESS) {
+
+ int id = check_free_joy_slot();
+ if (id != -1 && !x_joysticks[i].attached) {
+
+ x_joysticks[i].attached = true;
+ x_joysticks[i].id = id;
+ attached_joysticks[id] = true;
+ input->joy_connection_changed(id, true, "XInput Gamepad","__XINPUT_DEVICE__");
+ }
+ }
+ else if (x_joysticks[i].attached) {
+
+ x_joysticks[i].attached = false;
+ attached_joysticks[x_joysticks[i].id] = false;
+ input->joy_connection_changed(x_joysticks[i].id, false, "");
+ }
+ }
+
+ for (int i = 0; i < joystick_count; i++) {
+
+ d_joysticks[i].confirmed = false;
+ }
+
+ dinput->EnumDevices(DI8DEVCLASS_GAMECTRL, enumCallback, this, DIEDFL_ATTACHEDONLY);
+
+ for (int i = 0; i < joystick_count; i++) {
+
+ if (!d_joysticks[i].confirmed) {
+
+ close_joystick(i);
+ }
+ }
+}
+
+unsigned int joystick_windows::process_joysticks(unsigned int p_last_id) {
+
+ HRESULT hr;
+
+ for (int i = 0; i < XUSER_MAX_COUNT; i++) {
+
+ xinput_gamepad &joy = x_joysticks[i];
+ if (!joy.attached) {
+ continue;
+ }
+ ZeroMemory(&joy.state, sizeof(XINPUT_STATE));
+
+ xinput_get_state(i, &joy.state);
+ if (joy.state.dwPacketNumber != joy.last_packet) {
+
+ int button_mask = XINPUT_GAMEPAD_DPAD_UP;
+ for (int i = 0; i <= 16; i++) {
+
+ p_last_id = input->joy_button(p_last_id, joy.id, i, joy.state.Gamepad.wButtons & button_mask);
+ button_mask = button_mask * 2;
+ }
+
+ p_last_id = input->joy_axis(p_last_id, joy.id, JOY_AXIS_0, axis_correct(joy.state.Gamepad.sThumbLX, true));
+ p_last_id = input->joy_axis(p_last_id, joy.id, JOY_AXIS_1, axis_correct(joy.state.Gamepad.sThumbLY, true, false, true));
+ p_last_id = input->joy_axis(p_last_id, joy.id, JOY_AXIS_2, axis_correct(joy.state.Gamepad.sThumbRX, true));
+ p_last_id = input->joy_axis(p_last_id, joy.id, JOY_AXIS_3, axis_correct(joy.state.Gamepad.sThumbRY, true, false, true));
+ p_last_id = input->joy_axis(p_last_id, joy.id, JOY_AXIS_4, axis_correct(joy.state.Gamepad.bLeftTrigger, true, true));
+ p_last_id = input->joy_axis(p_last_id, joy.id, JOY_AXIS_5, axis_correct(joy.state.Gamepad.bRightTrigger, true, true));
+ joy.last_packet = joy.state.dwPacketNumber;
+ }
+ }
+
+ for (int i = 0; i < JOYSTICKS_MAX; i++) {
+
+ dinput_gamepad* joy = &d_joysticks[i];
+
+ if (!joy->attached)
+ continue;
+
+ DIJOYSTATE2 js;
+ hr = joy->di_joy->Poll();
+ if (hr == DIERR_INPUTLOST || hr == DIERR_NOTACQUIRED) {
+ IDirectInputDevice8_Acquire(joy->di_joy);
+ joy->di_joy->Poll();
+ }
+ if (FAILED(hr = joy->di_joy->GetDeviceState(sizeof(DIJOYSTATE2), &js))) {
+
+ //printf("failed to read joy #%d\n", i);
+ continue;
+ }
+
+ p_last_id = post_hat(p_last_id, joy->id, js.rgdwPOV[0]);
+
+ for (int j = 0; j < 128; j++) {
+
+ if (js.rgbButtons[j] & 0x80) {
+
+ if (!joy->last_buttons[j]) {
+
+ p_last_id = input->joy_button(p_last_id, joy->id, j, true);
+ joy->last_buttons[j] = true;
+ }
+ }
+ else {
+
+ if (joy->last_buttons[j]) {
+
+ p_last_id = input->joy_button(p_last_id, joy->id, j, false);
+ joy->last_buttons[j] = false;
+ }
+ }
+ }
+
+ // on mingw, these constants are not constants
+ int count = 6;
+ int axes[] = { DIJOFS_X, DIJOFS_Y, DIJOFS_Z, DIJOFS_RX, DIJOFS_RY, DIJOFS_RZ };
+ int values[] = { js.lX, js.lY, js.lZ, js.lRx, js.lRy, js.lRz };
+
+ for (int j = 0; j < joy->joy_axis.size(); j++) {
+
+ for (int k=0; k<count; k++) {
+ if (joy->joy_axis[j] == axes[k]) {
+ p_last_id = input->joy_axis(p_last_id, joy->id, j, axis_correct(values[k]));
+ break;
+ };
+ };
+ };
+ }
+ return p_last_id;
+}
+
+unsigned int joystick_windows::post_hat(unsigned int p_last_id, int p_device, DWORD p_dpad) {
+
+ int dpad_val = 0;
+
+ if (p_dpad == -1) {
+ dpad_val = InputDefault::HAT_MASK_CENTER;
+ }
+ if (p_dpad == 0) {
+
+ dpad_val = InputDefault::HAT_MASK_UP;
+
+ }
+ else if (p_dpad == 4500) {
+
+ dpad_val = (InputDefault::HAT_MASK_UP | InputDefault::HAT_MASK_RIGHT);
+
+ }
+ else if (p_dpad == 9000) {
+
+ dpad_val = InputDefault::HAT_MASK_RIGHT;
+
+ }
+ else if (p_dpad == 13500) {
+
+ dpad_val = (InputDefault::HAT_MASK_RIGHT | InputDefault::HAT_MASK_DOWN);
+
+ }
+ else if (p_dpad == 18000) {
+
+ dpad_val = InputDefault::HAT_MASK_DOWN;
+
+ }
+ else if (p_dpad == 22500) {
+
+ dpad_val = (InputDefault::HAT_MASK_DOWN | InputDefault::HAT_MASK_LEFT);
+
+ }
+ else if (p_dpad == 27000) {
+
+ dpad_val = InputDefault::HAT_MASK_LEFT;
+
+ }
+ else if (p_dpad == 31500) {
+
+ dpad_val = (InputDefault::HAT_MASK_LEFT | InputDefault::HAT_MASK_UP);
+ }
+ return input->joy_hat(p_last_id, p_device, dpad_val);
+};
+
+InputDefault::JoyAxis joystick_windows::axis_correct(int p_val, bool p_xinput, bool p_trigger, bool p_negate) const {
+
+ InputDefault::JoyAxis jx;
+ if (Math::abs(p_val) < MIN_JOY_AXIS) {
+ jx.min = -1;
+ jx.value = 0.0f;
+ return jx;
+ }
+ if (p_xinput) {
+
+ if (p_trigger) {
+ jx.min = 0;
+ jx.value = (float)p_val / MAX_TRIGGER;
+ return jx;
+ }
+ jx.min = -1;
+ if (p_val < 0) {
+ jx.value = (float)p_val / MAX_JOY_AXIS;
+ }
+ else {
+ jx.value = (float)p_val / (MAX_JOY_AXIS - 1);
+ }
+ if (p_negate) {
+ jx.value = -jx.value;
+ }
+ return jx;
+ }
+ jx.min = -1;
+ jx.value = (float)p_val / MAX_JOY_AXIS;
+ return jx;
+}
+
+void joystick_windows::load_xinput() {
+
+ xinput_get_state = &_xinput_get_state;
+ xinput_dll = LoadLibrary( "XInput1_4.dll" );
+ if (!xinput_dll) {
+ xinput_dll = LoadLibrary("XInput1_3.dll");
+ if (!xinput_dll) {
+ xinput_dll = LoadLibrary("XInput9_1_0.dll");
+ }
+ }
+
+ if (!xinput_dll) {
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ print_line("Could not find XInput, using DirectInput only");
+ }
+ return;
+ }
+
+ XInputGetState_t func = (XInputGetState_t)GetProcAddress((HMODULE)xinput_dll, "XInputGetState");
+ if (!func) {
+ unload_xinput();
+ return;
+ }
+ xinput_get_state = func;
+ return;
+}
+
+void joystick_windows::unload_xinput() {
+
+ if (xinput_dll) {
+
+ FreeLibrary((HMODULE)xinput_dll);
+ }
+}
diff --git a/platform/windows/joystick.h b/platform/windows/joystick.h
new file mode 100644
index 0000000000..332e86fbb8
--- /dev/null
+++ b/platform/windows/joystick.h
@@ -0,0 +1,142 @@
+/*************************************************************************/
+/* joystick.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
+//author: Andreas Haas <hondres, liugam3@gmail.com>
+#ifndef JOYSTICK_H
+#define JOYSTICK_H
+
+#include "os_windows.h"
+#define DIRECTINPUT_VERSION 0x0800
+#include <dinput.h>
+#include <xinput.h> // on unix the file is called "xinput.h", on windows I'm sure it won't mind
+
+#ifndef SAFE_RELEASE // when Windows Media Device M? is not present
+#define SAFE_RELEASE(x) \
+if(x != NULL) \
+{ \
+ x->Release(); \
+ x = NULL; \
+}
+#endif
+
+#ifndef XUSER_MAX_COUNT
+#define XUSER_MAX_COUNT 4
+#endif
+
+class joystick_windows
+{
+public:
+ joystick_windows();
+ joystick_windows(InputDefault* _input, HWND* hwnd);
+ ~joystick_windows();
+
+ void probe_joysticks();
+ unsigned int process_joysticks(unsigned int p_last_id);
+private:
+
+ enum {
+ JOYSTICKS_MAX = 16,
+ JOY_AXIS_COUNT = 6,
+ MIN_JOY_AXIS = 10,
+ MAX_JOY_AXIS = 32768,
+ MAX_JOY_BUTTONS = 128,
+ KEY_EVENT_BUFFER_SIZE = 512,
+ MAX_TRIGGER = 255
+ };
+
+ struct dinput_gamepad {
+
+ int id;
+ bool attached;
+ bool confirmed;
+ bool last_buttons[MAX_JOY_BUTTONS];
+ DWORD last_pad;
+
+ LPDIRECTINPUTDEVICE8 di_joy;
+ List<DWORD> joy_axis;
+ GUID guid;
+
+ dinput_gamepad() {
+ id = -1;
+ last_pad = -1;
+ attached = false;
+ confirmed = false;
+
+ for (int i = 0; i < MAX_JOY_BUTTONS; i++)
+ last_buttons[i] = false;
+ }
+ };
+
+ struct xinput_gamepad {
+
+ int id;
+ bool attached;
+ DWORD last_packet;
+ XINPUT_STATE state;
+
+ xinput_gamepad() {
+ attached = false;
+ last_packet = 0;
+ }
+ };
+
+ typedef DWORD (WINAPI *XInputGetState_t) (DWORD dwUserIndex, XINPUT_STATE* pState);
+
+ HWND* hWnd;
+ HANDLE xinput_dll;
+ LPDIRECTINPUT8 dinput;
+ InputDefault* input;
+
+ int id_to_change;
+ int joystick_count;
+ bool attached_joysticks[JOYSTICKS_MAX];
+ dinput_gamepad d_joysticks[JOYSTICKS_MAX];
+ xinput_gamepad x_joysticks[XUSER_MAX_COUNT];
+
+ static BOOL CALLBACK enumCallback(const DIDEVICEINSTANCE* p_instance, void* p_context);
+ static BOOL CALLBACK objectsCallback(const DIDEVICEOBJECTINSTANCE* instance, void* context);
+
+ void setup_joystick_object(const DIDEVICEOBJECTINSTANCE* ob, int p_joy_id);
+ void close_joystick(int id = -1);
+ void load_xinput();
+ void unload_xinput();
+
+ int check_free_joy_slot() const;
+ unsigned int post_hat(unsigned int p_last_id, int p_device, DWORD p_dpad);
+
+ bool have_device(const GUID &p_guid);
+ bool is_xinput_device(const GUID* p_guid);
+ bool setup_dinput_joystick(const DIDEVICEINSTANCE* instance);
+
+ InputDefault::JoyAxis axis_correct(int p_val, bool p_xinput = false, bool p_trigger = false, bool p_negate = false) const;
+ XInputGetState_t xinput_get_state;
+};
+
+#endif
+
+
diff --git a/platform/windows/key_mapping_win.cpp b/platform/windows/key_mapping_win.cpp
index f07b7c6eaa..07d5f32253 100644
--- a/platform/windows/key_mapping_win.cpp
+++ b/platform/windows/key_mapping_win.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/windows/key_mapping_win.h b/platform/windows/key_mapping_win.h
index 288fcdd8de..da649d0115 100644
--- a/platform/windows/key_mapping_win.h
+++ b/platform/windows/key_mapping_win.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/windows/lang_table.h b/platform/windows/lang_table.h
index bfdf2b6ebe..c9551b2d38 100644
--- a/platform/windows/lang_table.h
+++ b/platform/windows/lang_table.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index ec9e17c4f0..6f19f8bdfe 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -52,6 +52,7 @@
#include "os/memory_pool_dynamic_prealloc.h"
#include "globals.h"
#include "io/marshalls.h"
+#include "joystick.h"
#include "shlobj.h"
#include <regstr.h>
@@ -148,7 +149,7 @@ const char * OS_Windows::get_video_driver_name(int p_driver) const {
OS::VideoMode OS_Windows::get_default_video_mode() const {
- return VideoMode(800,600,false);
+ return VideoMode(1280,720,false);
}
int OS_Windows::get_audio_driver_count() const {
@@ -323,11 +324,21 @@ LRESULT OS_Windows::WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
old_invalid=true;
outside=true;
+ if (main_loop && mouse_mode!=MOUSE_MODE_CAPTURED)
+ main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_EXIT);
+ if (input)
+ input->set_mouse_in_window(false);
} break;
case WM_MOUSEMOVE: {
if (outside) {
+ //mouse enter
+
+ if (main_loop && mouse_mode!=MOUSE_MODE_CAPTURED)
+ main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER);
+ if (input)
+ input->set_mouse_in_window(true);
CursorShape c=cursor_shape;
cursor_shape=CURSOR_MAX;
@@ -672,6 +683,10 @@ LRESULT OS_Windows::WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
} break;
#endif
+ case WM_DEVICECHANGE: {
+
+ joystick->probe_joysticks();
+ } break;
default: {
@@ -696,108 +711,6 @@ LRESULT CALLBACK WndProc(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam) {
}
-
-String OS_Windows::get_joystick_name(int id, JOYCAPS jcaps)
-{
- char buffer [256];
- char OEM [256];
- HKEY hKey;
- DWORD sz;
- int res;
-
- _snprintf(buffer, sizeof(buffer), "%s\\%s\\%s",
- REGSTR_PATH_JOYCONFIG, jcaps.szRegKey,
- REGSTR_KEY_JOYCURR );
- res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey);
- if (res != ERROR_SUCCESS)
- {
- res = RegOpenKeyEx(HKEY_CURRENT_USER, buffer, 0, KEY_QUERY_VALUE, &hKey);
- if (res != ERROR_SUCCESS)
- return "";
- }
-
- sz = sizeof(OEM);
- _snprintf( buffer, sizeof(buffer), "Joystick%d%s", id + 1, REGSTR_VAL_JOYOEMNAME);
- res = RegQueryValueEx ( hKey, buffer, 0, 0, (LPBYTE) OEM, &sz);
- RegCloseKey ( hKey );
- if (res != ERROR_SUCCESS)
- return "";
-
- _snprintf( buffer, sizeof(buffer), "%s\\%s", REGSTR_PATH_JOYOEM, OEM);
- res = RegOpenKeyEx(HKEY_LOCAL_MACHINE, buffer, 0, KEY_QUERY_VALUE, &hKey);
- if (res != ERROR_SUCCESS)
- {
- res = RegOpenKeyEx(HKEY_CURRENT_USER, buffer, 0, KEY_QUERY_VALUE, &hKey);
- if (res != ERROR_SUCCESS)
- return "";
- }
-
-
- sz = sizeof(buffer);
- res = RegQueryValueEx(hKey, REGSTR_VAL_JOYOEMNAME, 0, 0, (LPBYTE) buffer,
- &sz);
- RegCloseKey(hKey);
- if (res != ERROR_SUCCESS)
- return "";
-
- return String(buffer);
-}
-
-void OS_Windows::probe_joysticks() {
-
- static uint32_t last_attached = 0;
-
- int device_count = joyGetNumDevs();
-
- JOYINFOEX jinfo;
- jinfo.dwSize = sizeof(JOYINFOEX);
- jinfo.dwFlags = JOY_RETURNALL;
-
- for (int i=0; i<JOYSTICKS_MAX; i++) {
-
- Joystick joy;
- joy.id = i;
- joy.attached = (device_count > 0) && (joyGetPosEx(JOYSTICKID1 + i, &jinfo) == JOYERR_NOERROR);
-
- if (joy.attached == (last_attached & (1 << i) != 0)) {
- continue;
- };
-
- // there's been a change since last call
-
- if (joy.attached)
- last_attached = last_attached | (1 << i);
- else
- last_attached &= ~(1 << i);
-
- if (joy.attached) {
-
- joy.last_buttons = jinfo.dwButtons;
-
- joy.last_axis[0] = jinfo.dwXpos;
- joy.last_axis[1] = jinfo.dwYpos;
- joy.last_axis[2] = jinfo.dwZpos;
- joy.last_axis[3] = jinfo.dwRpos;
- joy.last_axis[4] = jinfo.dwUpos;
- joy.last_axis[5] = jinfo.dwVpos;
-
- JOYCAPS jcaps;
- MMRESULT res = joyGetDevCaps(JOYSTICKID1 + i, &jcaps, sizeof(jcaps));
- if (res == JOYERR_NOERROR) {
- String name = get_joystick_name(JOYSTICKID1 + i, jcaps);
- if ( name == "")
- joy.name = jcaps.szPname;
- else
- joy.name = name;
-
-
- };
- };
-
- joystick_change_queue.push_back(joy);
- };
-};
-
void OS_Windows::process_key_events() {
for(int i=0;i<key_event_pos;i++) {
@@ -869,154 +782,6 @@ void OS_Windows::process_key_events() {
key_event_pos=0;
}
-void OS_Windows::_post_dpad(DWORD p_dpad, int p_device, bool p_pressed) {
-
- InputEvent ievent;
- ievent.device = p_device;
- ievent.type = InputEvent::JOYSTICK_BUTTON;
- ievent.joy_button.pressed = p_pressed;
- ievent.joy_button.pressure = p_pressed ? 1.0 : 0.0;
-
- if (p_dpad == 0) {
-
- ievent.joy_button.button_index = JOY_DPAD_UP;
- ievent.ID = ++last_id;
- input->parse_input_event(ievent);
-
- } else if (p_dpad == 4500) {
-
- ievent.joy_button.button_index = JOY_DPAD_UP;
- ievent.ID = ++last_id;
- input->parse_input_event(ievent);
-
- ievent.joy_button.button_index = JOY_DPAD_RIGHT;
- ievent.ID = ++last_id;
- input->parse_input_event(ievent);
-
- } else if (p_dpad == 9000) {
-
- ievent.joy_button.button_index = JOY_DPAD_RIGHT;
- ievent.ID = ++last_id;
- input->parse_input_event(ievent);
-
- } else if (p_dpad == 13500) {
-
- ievent.joy_button.button_index = JOY_DPAD_RIGHT;
- ievent.ID = ++last_id;
- input->parse_input_event(ievent);
-
- ievent.joy_button.button_index = JOY_DPAD_DOWN;
- ievent.ID = ++last_id;
- input->parse_input_event(ievent);
-
- } else if (p_dpad == 18000) {
-
- ievent.joy_button.button_index = JOY_DPAD_DOWN;
- ievent.ID = ++last_id;
- input->parse_input_event(ievent);
-
- } else if (p_dpad == 22500) {
-
- ievent.joy_button.button_index = JOY_DPAD_DOWN;
- ievent.ID = ++last_id;
- input->parse_input_event(ievent);
-
- ievent.joy_button.button_index = JOY_DPAD_LEFT;
- ievent.ID = ++last_id;
- input->parse_input_event(ievent);
-
- } else if (p_dpad == 27000) {
-
- ievent.joy_button.button_index = JOY_DPAD_LEFT;
- ievent.ID = ++last_id;
- input->parse_input_event(ievent);
-
- } else if (p_dpad == 31500) {
-
- ievent.joy_button.button_index = JOY_DPAD_LEFT;
- ievent.ID = ++last_id;
- input->parse_input_event(ievent);
-
- ievent.joy_button.button_index = JOY_DPAD_UP;
- ievent.ID = ++last_id;
- input->parse_input_event(ievent);
- };
-};
-
-void OS_Windows::process_joysticks() {
-
- if (!main_loop) {
- return;
- };
-
- InputEvent ievent;
-
- JOYINFOEX jinfo;
- jinfo.dwSize = sizeof(JOYINFOEX);
- jinfo.dwFlags = JOY_RETURNALL;
-
- for (int i=0; i<JOYSTICKS_MAX; i++) {
-
- if (!joysticks[i].attached) {
- continue;
- };
-
- if (joyGetPosEx(JOYSTICKID1 + i, &jinfo) != JOYERR_NOERROR) {
-
- continue;
- };
-
- ievent.device = i;
-
- #define CHECK_AXIS(n, var) \
- if (joysticks[i].last_axis[n] != var) {\
- ievent.type = InputEvent::JOYSTICK_MOTION;\
- ievent.ID = ++last_id;\
- ievent.joy_motion.axis = n;\
- ievent.joy_motion.axis_value = (float)((int)var - MAX_JOY_AXIS) / (float)MAX_JOY_AXIS;\
- joysticks[i].last_axis[n] = var;\
- input->parse_input_event(ievent);\
- };
-
- CHECK_AXIS(0, jinfo.dwXpos);
- CHECK_AXIS(1, jinfo.dwYpos);
- CHECK_AXIS(2, jinfo.dwZpos);
- CHECK_AXIS(3, jinfo.dwRpos);
- CHECK_AXIS(4, jinfo.dwUpos);
- CHECK_AXIS(5, jinfo.dwVpos);
-
- if (joysticks[i].last_pov != jinfo.dwPOV) {
-
- if (joysticks[i].last_pov != JOY_POVCENTERED)
- _post_dpad(joysticks[i].last_pov, i, false);
-
- if (jinfo.dwPOV != JOY_POVCENTERED)
- _post_dpad(jinfo.dwPOV, i, true);
-
- joysticks[i].last_pov = jinfo.dwPOV;
- };
-
- if (joysticks[i].last_buttons == jinfo.dwButtons) {
- continue;
- };
-
- ievent.type = InputEvent::JOYSTICK_BUTTON;
- for (int j=0; j<32; j++) {
-
- if ( (joysticks[i].last_buttons & (1<<j)) != (jinfo.dwButtons & (1<<j)) ) {
-
- ievent.joy_button.button_index = j; //_pc_joystick_get_native_button(j);
- ievent.joy_button.pressed = jinfo.dwButtons & 1<<j;
- ievent.ID = ++last_id;
- input->parse_input_event(ievent);
- };
- };
-
- joysticks[i].last_buttons = jinfo.dwButtons;
- };
-};
-
-
BOOL CALLBACK OS_Windows::MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData) {
OS_Windows *self=(OS_Windows*)OS::get_singleton();
MonitorInfo minfo;
@@ -1203,6 +968,7 @@ void OS_Windows::initialize(const VideoMode& p_desired,int p_video_driver,int p_
visual_server->init();
input = memnew( InputDefault );
+ joystick = memnew (joystick_windows(input, &hWnd));
AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton();
@@ -1221,14 +987,6 @@ void OS_Windows::initialize(const VideoMode& p_desired,int p_video_driver,int p_
spatial_sound_2d_server = memnew( SpatialSound2DServerSW );
spatial_sound_2d_server->init();
- probe_joysticks(); // todo: move this to a thread
- while (joystick_change_queue.size() > 0) {
- Joystick joy = joystick_change_queue.front()->get();
- joystick_change_queue.pop_front();
- joysticks[joy.id] = joy;
- input->joy_connection_changed(joy.id, joy.attached, joy.name);
- };
-
TRACKMOUSEEVENT tme;
tme.cbSize=sizeof(TRACKMOUSEEVENT);
tme.dwFlags=TME_LEAVE;
@@ -1340,7 +1098,10 @@ void OS_Windows::finalize() {
memdelete(main_loop);
main_loop=NULL;
-
+
+ memdelete(joystick);
+ memdelete(input);
+
visual_server->finish();
memdelete(visual_server);
#ifdef OPENGL_ENABLED
@@ -1363,11 +1124,10 @@ void OS_Windows::finalize() {
// memdelete(debugger_connection_console);
//}
- audio_server->finish();
- memdelete(audio_server);
memdelete(sample_manager);
- memdelete(input);
+ audio_server->finish();
+ memdelete(audio_server);
physics_server->finish();
memdelete(physics_server);
@@ -1375,7 +1135,6 @@ void OS_Windows::finalize() {
physics_2d_server->finish();
memdelete(physics_2d_server);
- joystick_change_queue.clear();
monitor_info.clear();
}
@@ -1385,8 +1144,7 @@ void OS_Windows::finalize_core() {
if (mempool_dynamic)
memdelete( mempool_dynamic );
- if (mempool_static)
- delete mempool_static;
+ delete mempool_static;
TCPServerWinsock::cleanup();
@@ -1754,73 +1512,96 @@ bool OS_Windows::is_window_maximized() const{
}
-void OS_Windows::print_error(const char* p_function,const char* p_file,int p_line,const char *p_code,const char*p_rationale,ErrorType p_type) {
-
- HANDLE hCon=GetStdHandle(STD_OUTPUT_HANDLE);
- if (!hCon || hCon==INVALID_HANDLE_VALUE) {
- if (p_rationale && p_rationale[0]) {
+void OS_Windows::print_error(const char* p_function, const char* p_file, int p_line, const char* p_code, const char* p_rationale, ErrorType p_type) {
- print("\E[1;31;40mERROR: %s: \E[1;37;40m%s\n",p_function,p_rationale);
- print("\E[0;31;40m At: %s:%i.\E[0;0;37m\n",p_file,p_line);
+ HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (!hCon || hCon == INVALID_HANDLE_VALUE) {
- } else {
- print("\E[1;31;40mERROR: %s: \E[1;37;40m%s\n",p_function,p_code);
- print("\E[0;31;40m At: %s:%i.\E[0;0;37m\n",p_file,p_line);
+ const char* err_details;
+ if (p_rationale && p_rationale[0])
+ err_details = p_rationale;
+ else
+ err_details = p_code;
+ switch(p_type) {
+ case ERR_ERROR:
+ print("ERROR: %s: %s\n", p_function, err_details);
+ print(" At: %s:%i\n", p_file, p_line);
+ break;
+ case ERR_WARNING:
+ print("WARNING: %s: %s\n", p_function, err_details);
+ print(" At: %s:%i\n", p_file, p_line);
+ break;
+ case ERR_SCRIPT:
+ print("SCRIPT ERROR: %s: %s\n", p_function, err_details);
+ print(" At: %s:%i\n", p_file, p_line);
+ break;
}
+
} else {
CONSOLE_SCREEN_BUFFER_INFO sbi; //original
- GetConsoleScreenBufferInfo(hCon,&sbi);
-
- SetConsoleTextAttribute(hCon,sbi.wAttributes);
+ GetConsoleScreenBufferInfo(hCon, &sbi);
+ WORD current_fg = sbi.wAttributes & (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
+ WORD current_bg = sbi.wAttributes & (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY);
-
- uint32_t basecol=0;
+ uint32_t basecol = 0;
switch(p_type) {
case ERR_ERROR: basecol = FOREGROUND_RED; break;
- case ERR_WARNING: basecol = FOREGROUND_RED|FOREGROUND_GREEN; break;
- case ERR_SCRIPT: basecol = FOREGROUND_GREEN; break;
+ case ERR_WARNING: basecol = FOREGROUND_RED | FOREGROUND_GREEN; break;
+ case ERR_SCRIPT: basecol = FOREGROUND_RED | FOREGROUND_BLUE; break;
}
- if (p_rationale && p_rationale[0]) {
-
- SetConsoleTextAttribute(hCon,basecol|FOREGROUND_INTENSITY);
+ basecol |= current_bg;
+ if (p_rationale && p_rationale[0]) {
+ SetConsoleTextAttribute(hCon, basecol | FOREGROUND_INTENSITY);
switch(p_type) {
case ERR_ERROR: print("ERROR: "); break;
case ERR_WARNING: print("WARNING: "); break;
case ERR_SCRIPT: print("SCRIPT ERROR: "); break;
}
- SetConsoleTextAttribute(hCon,FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_INTENSITY);
- print(" %s\n",p_rationale);
- SetConsoleTextAttribute(hCon,basecol);
- print("At: ");
- SetConsoleTextAttribute(hCon,FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN);
- print(" %s:%i\n",p_file,p_line);
+ SetConsoleTextAttribute(hCon, current_fg | current_bg | FOREGROUND_INTENSITY);
+ print("%s\n", p_rationale);
+
+ SetConsoleTextAttribute(hCon, basecol);
+ switch (p_type) {
+ case ERR_ERROR: print(" At: "); break;
+ case ERR_WARNING: print(" At: "); break;
+ case ERR_SCRIPT: print(" At: "); break;
+ }
+ SetConsoleTextAttribute(hCon, current_fg | current_bg);
+ print("%s:%i\n", p_file, p_line);
} else {
- SetConsoleTextAttribute(hCon,basecol|FOREGROUND_INTENSITY);
+
+ SetConsoleTextAttribute(hCon, basecol | FOREGROUND_INTENSITY);
switch(p_type) {
- case ERR_ERROR: print("ERROR: %s: ",p_function); break;
- case ERR_WARNING: print("WARNING: %s: ",p_function); break;
- case ERR_SCRIPT: print("SCRIPT ERROR: %s: ",p_function); break;
+ case ERR_ERROR: print("ERROR: %s: ", p_function); break;
+ case ERR_WARNING: print("WARNING: %s: ", p_function); break;
+ case ERR_SCRIPT: print("SCRIPT ERROR: %s: ", p_function); break;
+ }
+
+ SetConsoleTextAttribute(hCon, current_fg | current_bg | FOREGROUND_INTENSITY);
+ print("%s\n", p_code);
+
+ SetConsoleTextAttribute(hCon, basecol);
+ switch (p_type) {
+ case ERR_ERROR: print(" At: "); break;
+ case ERR_WARNING: print(" At: "); break;
+ case ERR_SCRIPT: print(" At: "); break;
}
- SetConsoleTextAttribute(hCon,FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_INTENSITY);
- print(" %s\n",p_code);
- SetConsoleTextAttribute(hCon,basecol);
- print("At: ");
- SetConsoleTextAttribute(hCon,FOREGROUND_RED|FOREGROUND_BLUE|FOREGROUND_GREEN);
- print(" %s:%i\n",p_file,p_line);
+
+ SetConsoleTextAttribute(hCon, current_fg | current_bg);
+ print("%s:%i\n", p_file, p_line);
}
- SetConsoleTextAttribute(hCon,sbi.wAttributes);
+ SetConsoleTextAttribute(hCon, sbi.wAttributes);
}
-
}
@@ -1899,6 +1680,18 @@ uint64_t OS_Windows::get_unix_time() const {
return (*(uint64_t*)&ft - *(uint64_t*)&fep) / 10000000;
};
+uint64_t OS_Windows::get_system_time_secs() const {
+ SYSTEMTIME st;
+ GetSystemTime(&st);
+ FILETIME ft;
+ SystemTimeToFileTime(&st,&ft);
+ uint64_t ret;
+ ret=ft.dwHighDateTime;
+ ret<<=32;
+ ret|=ft.dwLowDateTime;
+ return ret;
+}
+
void OS_Windows::delay_usec(uint32_t p_usec) const {
if (p_usec < 1000)
@@ -1927,7 +1720,7 @@ void OS_Windows::process_events() {
MSG msg;
- process_joysticks();
+ last_id = joystick->process_joysticks(last_id);
while(PeekMessageW(&msg,NULL,0,0,PM_REMOVE)) {
@@ -2311,6 +2104,13 @@ String OS_Windows::get_data_dir() const {
}
+bool OS_Windows::is_joy_known(int p_device) {
+ return input->is_joy_mapped(p_device);
+}
+
+String OS_Windows::get_joy_guid(int p_device) const {
+ return input->get_joy_guid_remapped(p_device);
+}
OS_Windows::OS_Windows(HINSTANCE _hInstance) {
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index 31e030d02e..e433d5cc11 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -47,6 +47,7 @@
#include "servers/physics_2d/physics_2d_server_sw.h"
#include "servers/physics_2d/physics_2d_server_wrap_mt.h"
+#include "main/input_default.h"
#include <windows.h>
@@ -59,13 +60,11 @@
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
+class joystick_windows;
class OS_Windows : public OS {
- enum {
- JOYSTICKS_MAX = 8,
- JOY_AXIS_COUNT = 6,
- MAX_JOY_AXIS = 32768, // I've no idea
- KEY_EVENT_BUFFER_SIZE=512
+ enum {
+ KEY_EVENT_BUFFER_SIZE=512
};
FILE *stdo;
@@ -105,32 +104,6 @@ class OS_Windows : public OS {
HINSTANCE hInstance; // Holds The Instance Of The Application
HWND hWnd;
- struct Joystick {
-
- int id;
- bool attached;
-
- DWORD last_axis[JOY_AXIS_COUNT];
- DWORD last_buttons;
- DWORD last_pov;
- String name;
-
- Joystick() {
- id = -1;
- attached = false;
- for (int i=0; i<JOY_AXIS_COUNT; i++) {
-
- last_axis[i] = 0;
- };
- last_buttons = 0;
- last_pov = 0;
- };
- };
-
- List<Joystick> joystick_change_queue;
- int joystick_count;
- Joystick joysticks[JOYSTICKS_MAX];
-
Size2 window_rect;
VideoMode video_mode;
@@ -155,13 +128,12 @@ class OS_Windows : public OS {
CursorShape cursor_shape;
InputDefault *input;
+ joystick_windows *joystick;
#ifdef RTAUDIO_ENABLED
AudioDriverRtAudio driver_rtaudio;
#endif
- void _post_dpad(DWORD p_dpad, int p_device, bool p_pressed);
-
void _drag_event(int p_x, int p_y, int idx);
void _touch_event(bool p_pressed, int p_x, int p_y, int idx);
@@ -185,11 +157,7 @@ protected:
virtual void finalize_core();
void process_events();
-
- void probe_joysticks();
- void process_joysticks();
void process_key_events();
- String get_joystick_name( int id, JOYCAPS jcaps);
struct ProcessInfo {
@@ -263,6 +231,7 @@ public:
virtual Time get_time(bool utc) const;
virtual TimeZoneInfo get_time_zone_info() const;
virtual uint64_t get_unix_time() const;
+ virtual uint64_t get_system_time_secs() const;
virtual bool can_draw() const;
virtual Error set_cwd(const String& p_cwd);
@@ -272,7 +241,7 @@ public:
virtual Error execute(const String& p_path, const List<String>& p_arguments,bool p_blocking,ProcessID *r_child_id=NULL,String* r_pipe=NULL,int *r_exitcode=NULL);
virtual Error kill(const ProcessID& p_pid);
-
+
virtual bool has_environment(const String& p_var) const;
virtual String get_environment(const String& p_var) const;
@@ -301,6 +270,9 @@ public:
virtual bool get_swap_ok_cancel() { return true; }
+ virtual bool is_joy_known(int p_device);
+ virtual String get_joy_guid(int p_device) const;
+
OS_Windows(HINSTANCE _hInstance);
~OS_Windows();
diff --git a/platform/windows/packet_peer_udp_winsock.cpp b/platform/windows/packet_peer_udp_winsock.cpp
index aff92b8fc8..0ca2d358af 100644
--- a/platform/windows/packet_peer_udp_winsock.cpp
+++ b/platform/windows/packet_peer_udp_winsock.cpp
@@ -121,7 +121,7 @@ Error PacketPeerUDPWinsock::_poll(bool p_wait) {
struct sockaddr_in from = {0};
int len = sizeof(struct sockaddr_in);
int ret;
- while ( (ret = recvfrom(sockfd, (char*)recv_buffer, MIN(sizeof(recv_buffer),rb.data_left()-12), 0, (struct sockaddr*)&from, &len)) > 0) {
+ while ( (ret = recvfrom(sockfd, (char*)recv_buffer, MIN((int)sizeof(recv_buffer),MAX(rb.space_left()-12, 0)), 0, (struct sockaddr*)&from, &len)) > 0) {
rb.write((uint8_t*)&from.sin_addr, 4);
uint32_t port = ntohs(from.sin_port);
rb.write((uint8_t*)&port, 4);
@@ -132,8 +132,25 @@ Error PacketPeerUDPWinsock::_poll(bool p_wait) {
++queue_count;
};
+ if (ret == SOCKET_ERROR){
+ int error = WSAGetLastError();
+
+ if (error == WSAEWOULDBLOCK){
+ // Expected when doing non-blocking sockets, retry later.
+ }
+ else if (error == WSAECONNRESET){
+ // If the remote target does not accept messages, this error may occur, but is harmless.
+ // Once the remote target gets available, this message will disappear for new messages.
+ }
+ else
+ {
+ close();
+ return FAILED;
+ }
+ }
+
- if (ret == 0 || (ret == SOCKET_ERROR && WSAGetLastError() != WSAEWOULDBLOCK) ) {
+ if (ret == 0) {
close();
return FAILED;
};
diff --git a/platform/windows/platform_config.h b/platform/windows/platform_config.h
index e6b561552e..55f6b5547e 100644
--- a/platform/windows/platform_config.h
+++ b/platform/windows/platform_config.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/windows/stream_peer_winsock.cpp b/platform/windows/stream_peer_winsock.cpp
index e8245c92e5..fcf0cb1640 100644
--- a/platform/windows/stream_peer_winsock.cpp
+++ b/platform/windows/stream_peer_winsock.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -342,6 +342,14 @@ void StreamPeerWinsock::set_nodelay(bool p_enabled) {
setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char*)&flag, sizeof(int));
}
+int StreamPeerWinsock::get_available_bytes() const {
+
+ unsigned long len;
+ int ret = ioctlsocket(sockfd,FIONREAD,&len);
+ ERR_FAIL_COND_V(ret==-1,0)
+ return len;
+
+}
IP_Address StreamPeerWinsock::get_connected_host() const {
diff --git a/platform/windows/stream_peer_winsock.h b/platform/windows/stream_peer_winsock.h
index 373b502d2c..bbff661490 100644
--- a/platform/windows/stream_peer_winsock.h
+++ b/platform/windows/stream_peer_winsock.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -66,6 +66,8 @@ public:
virtual Error get_data(uint8_t* p_buffer, int p_bytes);
virtual Error get_partial_data(uint8_t* p_buffer, int p_bytes,int &r_received);
+ virtual int get_available_bytes() const;
+
void set_socket(int p_sockfd, IP_Address p_host, int p_port);
virtual IP_Address get_connected_host() const;
diff --git a/platform/windows/tcp_server_winsock.cpp b/platform/windows/tcp_server_winsock.cpp
index bf7e85aebb..dd1cf43f3b 100644
--- a/platform/windows/tcp_server_winsock.cpp
+++ b/platform/windows/tcp_server_winsock.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -79,6 +79,13 @@ Error TCPServerWinsock::listen(uint16_t p_port,const List<String> *p_accepted_ho
my_addr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP TODO: use p_accepted_hosts
memset(my_addr.sin_zero, '\0', sizeof my_addr.sin_zero);
+ int reuse=1;
+ if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0) {
+
+ printf("REUSEADDR failed!");
+ }
+
+
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof my_addr) != SOCKET_ERROR) {
if (::listen(sockfd, SOMAXCONN) == SOCKET_ERROR) {
diff --git a/platform/windows/tcp_server_winsock.h b/platform/windows/tcp_server_winsock.h
index 2516123908..bd6a05c74d 100644
--- a/platform/windows/tcp_server_winsock.h
+++ b/platform/windows/tcp_server_winsock.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/winrt/app.cpp b/platform/winrt/app.cpp
index 662229b04e..263cd684c4 100644
--- a/platform/winrt/app.cpp
+++ b/platform/winrt/app.cpp
@@ -1,385 +1,385 @@
-//
-// This file demonstrates how to initialize EGL in a Windows Store app, using ICoreWindow.
-//
-
-#include "app.h"
-
-#include "main/main.h"
-#include "core/os/dir_access.h"
-#include "core/os/file_access.h"
-
-using namespace Windows::ApplicationModel::Core;
-using namespace Windows::ApplicationModel::Activation;
-using namespace Windows::UI::Core;
-using namespace Windows::UI::Input;
-using namespace Windows::Foundation;
-using namespace Windows::Graphics::Display;
-using namespace Microsoft::WRL;
-using namespace Platform;
-
-using namespace $ext_safeprojectname$;
-
-// Helper to convert a length in device-independent pixels (DIPs) to a length in physical pixels.
-inline float ConvertDipsToPixels(float dips, float dpi)
-{
- static const float dipsPerInch = 96.0f;
- return floor(dips * dpi / dipsPerInch + 0.5f); // Round to nearest integer.
-}
-
-// Implementation of the IFrameworkViewSource interface, necessary to run our app.
-ref class HelloTriangleApplicationSource sealed : Windows::ApplicationModel::Core::IFrameworkViewSource
-{
-public:
- virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView()
- {
- return ref new App();
- }
-};
-
-// The main function creates an IFrameworkViewSource for our app, and runs the app.
-[Platform::MTAThread]
-int main(Platform::Array<Platform::String^>^)
-{
- auto helloTriangleApplicationSource = ref new HelloTriangleApplicationSource();
- CoreApplication::Run(helloTriangleApplicationSource);
- return 0;
-}
-
-App::App() :
- mWindowClosed(false),
- mWindowVisible(true),
- mWindowWidth(0),
- mWindowHeight(0),
- mEglDisplay(EGL_NO_DISPLAY),
- mEglContext(EGL_NO_CONTEXT),
- mEglSurface(EGL_NO_SURFACE)
-{
-}
-
-// The first method called when the IFrameworkView is being created.
-void App::Initialize(CoreApplicationView^ applicationView)
-{
- // Register event handlers for app lifecycle. This example includes Activated, so that we
- // can make the CoreWindow active and start rendering on the window.
- applicationView->Activated +=
- ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &App::OnActivated);
-
- // Logic for other event handlers could go here.
- // Information about the Suspending and Resuming event handlers can be found here:
- // http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh994930.aspx
-
- os = new OSWinrt;
-}
-
-// Called when the CoreWindow object is created (or re-created).
-void App::SetWindow(CoreWindow^ p_window)
-{
- window = p_window;
- window->VisibilityChanged +=
- ref new TypedEventHandler<CoreWindow^, VisibilityChangedEventArgs^>(this, &App::OnVisibilityChanged);
-
- window->Closed +=
- ref new TypedEventHandler<CoreWindow^, CoreWindowEventArgs^>(this, &App::OnWindowClosed);
-
- window->SizeChanged +=
- ref new TypedEventHandler<CoreWindow^, WindowSizeChangedEventArgs^>(this, &App::OnWindowSizeChanged);
-
-#if !(WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
- // Disable all pointer visual feedback for better performance when touching.
- // This is not supported on Windows Phone applications.
- auto pointerVisualizationSettings = PointerVisualizationSettings::GetForCurrentView();
- pointerVisualizationSettings->IsContactFeedbackEnabled = false;
- pointerVisualizationSettings->IsBarrelButtonFeedbackEnabled = false;
-#endif
-
-
- window->PointerPressed +=
- ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &App::OnPointerPressed);
-
- window->PointerMoved +=
- ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &App::OnPointerMoved);
-
- window->PointerReleased +=
- ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &App::OnPointerReleased);
-
- //window->PointerWheelChanged +=
- // ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &App::OnPointerWheelChanged);
-
-
-
- char* args[] = {"-path", "game", NULL};
- Main::setup("winrt", 2, args, false);
-
- // The CoreWindow has been created, so EGL can be initialized.
- ContextEGL* context = memnew(ContextEGL(window));
- os->set_gl_context(context);
- UpdateWindowSize(Size(window->Bounds.Width, window->Bounds.Height));
-
- Main::setup2();
-}
-
-static int _get_button(Windows::UI::Input::PointerPoint ^pt) {
-
- using namespace Windows::UI::Input;
-
-#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
- return BUTTON_LEFT;
-#else
- switch (pt->Properties->PointerUpdateKind)
- {
- case PointerUpdateKind::LeftButtonPressed:
- case PointerUpdateKind::LeftButtonReleased:
- return BUTTON_LEFT;
-
- case PointerUpdateKind::RightButtonPressed:
- case PointerUpdateKind::RightButtonReleased:
- return BUTTON_RIGHT;
-
- case PointerUpdateKind::MiddleButtonPressed:
- case PointerUpdateKind::MiddleButtonReleased:
- return BUTTON_MIDDLE;
-
- case PointerUpdateKind::XButton1Pressed:
- case PointerUpdateKind::XButton1Released:
- return BUTTON_WHEEL_UP;
-
- case PointerUpdateKind::XButton2Pressed:
- case PointerUpdateKind::XButton2Released:
- return BUTTON_WHEEL_DOWN;
-
- default:
- break;
- }
-#endif
-
- return 0;
-};
-
-static bool _is_touch(Windows::UI::Input::PointerPoint ^pointerPoint) {
-#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
- return true;
-#else
- using namespace Windows::Devices::Input;
- switch (pointerPoint->PointerDevice->PointerDeviceType) {
- case PointerDeviceType::Touch:
- case PointerDeviceType::Pen:
- return true;
- default:
- return false;
- }
-#endif
-}
-
-
-static Windows::Foundation::Point _get_pixel_position(CoreWindow^ window, Windows::Foundation::Point rawPosition, OS* os) {
-
- Windows::Foundation::Point outputPosition;
-
- // Compute coordinates normalized from 0..1.
- // If the coordinates need to be sized to the SDL window,
- // we'll do that after.
- #if 1 || WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
- outputPosition.X = rawPosition.X / window->Bounds.Width;
- outputPosition.Y = rawPosition.Y / window->Bounds.Height;
- #else
- switch (DisplayProperties::CurrentOrientation)
- {
- case DisplayOrientations::Portrait:
- outputPosition.X = rawPosition.X / window->Bounds.Width;
- outputPosition.Y = rawPosition.Y / window->Bounds.Height;
- break;
- case DisplayOrientations::PortraitFlipped:
- outputPosition.X = 1.0f - (rawPosition.X / window->Bounds.Width);
- outputPosition.Y = 1.0f - (rawPosition.Y / window->Bounds.Height);
- break;
- case DisplayOrientations::Landscape:
- outputPosition.X = rawPosition.Y / window->Bounds.Height;
- outputPosition.Y = 1.0f - (rawPosition.X / window->Bounds.Width);
- break;
- case DisplayOrientations::LandscapeFlipped:
- outputPosition.X = 1.0f - (rawPosition.Y / window->Bounds.Height);
- outputPosition.Y = rawPosition.X / window->Bounds.Width;
- break;
- default:
- break;
- }
- #endif
-
- OS::VideoMode vm = os->get_video_mode();
- outputPosition.X *= vm.width;
- outputPosition.Y *= vm.height;
-
- return outputPosition;
-};
-
-static int _get_finger(uint32_t p_touch_id) {
-
- return p_touch_id % 31; // for now
-};
-
-void App::pointer_event(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args, bool p_pressed) {
-
- Windows::UI::Input::PointerPoint ^point = args->CurrentPoint;
- Windows::Foundation::Point pos = _get_pixel_position(window, point->Position, os);
- int but = _get_button(point);
- if (_is_touch(point)) {
-
- InputEvent event;
- event.type = InputEvent::SCREEN_TOUCH;
- event.device = 0;
- event.screen_touch.pressed = p_pressed;
- event.screen_touch.x = pos.X;
- event.screen_touch.y = pos.Y;
- event.screen_touch.index = _get_finger(point->PointerId);
-
- last_touch_x[event.screen_touch.index] = pos.X;
- last_touch_y[event.screen_touch.index] = pos.Y;
-
- os->input_event(event);
- if (event.screen_touch.index != 0)
- return;
-
- }; // fallthrought of sorts
-
- InputEvent event;
- event.type = InputEvent::MOUSE_BUTTON;
- event.device = 0;
- event.mouse_button.pressed = p_pressed;
- event.mouse_button.button_index = but;
- event.mouse_button.x = pos.X;
- event.mouse_button.y = pos.Y;
- event.mouse_button.global_x = pos.X;
- event.mouse_button.global_y = pos.Y;
-
- last_touch_x[31] = pos.X;
- last_touch_y[31] = pos.Y;
-
- os->input_event(event);
-};
-
-
-void App::OnPointerPressed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args) {
-
- pointer_event(sender, args, true);
-};
-
-
-void App::OnPointerReleased(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args) {
-
- pointer_event(sender, args, false);
-};
-
-void App::OnPointerMoved(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args) {
-
- Windows::UI::Input::PointerPoint ^point = args->CurrentPoint;
- Windows::Foundation::Point pos = _get_pixel_position(window, point->Position, os);
-
- if (_is_touch(point)) {
-
- InputEvent event;
- event.type = InputEvent::SCREEN_DRAG;
- event.device = 0;
- event.screen_drag.x = pos.X;
- event.screen_drag.y = pos.Y;
- event.screen_drag.index = _get_finger(point->PointerId);
- event.screen_drag.relative_x = event.screen_drag.x - last_touch_x[event.screen_drag.index];
- event.screen_drag.relative_y = event.screen_drag.y - last_touch_y[event.screen_drag.index];
-
- os->input_event(event);
- if (event.screen_drag.index != 0)
- return;
-
- }; // fallthrought of sorts
-
- InputEvent event;
- event.type = InputEvent::MOUSE_MOTION;
- event.device = 0;
- event.mouse_motion.x = pos.X;
- event.mouse_motion.y = pos.Y;
- event.mouse_motion.global_x = pos.X;
- event.mouse_motion.global_y = pos.Y;
- event.mouse_motion.relative_x = pos.X - last_touch_x[31];
- event.mouse_motion.relative_y = pos.Y - last_touch_y[31];
-
- os->input_event(event);
-
-};
-
-
-// Initializes scene resources
-void App::Load(Platform::String^ entryPoint)
-{
- //char* args[] = {"-test", "render", NULL};
- //Main::setup("winrt", 2, args);
-}
-
-// This method is called after the window becomes active.
-void App::Run()
-{
- if (Main::start())
- os->run();
-}
-
-// Terminate events do not cause Uninitialize to be called. It will be called if your IFrameworkView
-// class is torn down while the app is in the foreground.
-void App::Uninitialize()
-{
- Main::cleanup();
- delete os;
-}
-
-// Application lifecycle event handler.
-void App::OnActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args)
-{
- // Run() won't start until the CoreWindow is activated.
- CoreWindow::GetForCurrentThread()->Activate();
-}
-
-// Window event handlers.
-void App::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args)
-{
- mWindowVisible = args->Visible;
-}
-
-void App::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args)
-{
- mWindowClosed = true;
-}
-
-void App::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ args)
-{
-#if (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP)
- // On Windows 8.1, apps are resized when they are snapped alongside other apps, or when the device is rotated.
- // The default framebuffer will be automatically resized when either of these occur.
- // In particular, on a 90 degree rotation, the default framebuffer's width and height will switch.
- UpdateWindowSize(args->Size);
-#else if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
- // On Windows Phone 8.1, the window size changes when the device is rotated.
- // The default framebuffer will not be automatically resized when this occurs.
- // It is therefore up to the app to handle rotation-specific logic in its rendering code.
- //os->screen_size_changed();
- UpdateWindowSize(args->Size);
-#endif
-}
-
-void App::UpdateWindowSize(Size size)
-{
- float dpi;
-#if (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP)
- DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
- dpi = currentDisplayInformation->LogicalDpi;
-#else if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
- dpi = DisplayProperties::LogicalDpi;
-#endif
- Size pixelSize(ConvertDipsToPixels(size.Width, dpi), ConvertDipsToPixels(size.Height, dpi));
-
- mWindowWidth = static_cast<GLsizei>(pixelSize.Width);
- mWindowHeight = static_cast<GLsizei>(pixelSize.Height);
-
- OS::VideoMode vm;
- vm.width = mWindowWidth;
- vm.height = mWindowHeight;
- vm.fullscreen = true;
- vm.resizable = false;
- os->set_video_mode(vm);
-}
+//
+// This file demonstrates how to initialize EGL in a Windows Store app, using ICoreWindow.
+//
+
+#include "app.h"
+
+#include "main/main.h"
+#include "core/os/dir_access.h"
+#include "core/os/file_access.h"
+
+using namespace Windows::ApplicationModel::Core;
+using namespace Windows::ApplicationModel::Activation;
+using namespace Windows::UI::Core;
+using namespace Windows::UI::Input;
+using namespace Windows::Foundation;
+using namespace Windows::Graphics::Display;
+using namespace Microsoft::WRL;
+using namespace Platform;
+
+using namespace $ext_safeprojectname$;
+
+// Helper to convert a length in device-independent pixels (DIPs) to a length in physical pixels.
+inline float ConvertDipsToPixels(float dips, float dpi)
+{
+ static const float dipsPerInch = 96.0f;
+ return floor(dips * dpi / dipsPerInch + 0.5f); // Round to nearest integer.
+}
+
+// Implementation of the IFrameworkViewSource interface, necessary to run our app.
+ref class HelloTriangleApplicationSource sealed : Windows::ApplicationModel::Core::IFrameworkViewSource
+{
+public:
+ virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView()
+ {
+ return ref new App();
+ }
+};
+
+// The main function creates an IFrameworkViewSource for our app, and runs the app.
+[Platform::MTAThread]
+int main(Platform::Array<Platform::String^>^)
+{
+ auto helloTriangleApplicationSource = ref new HelloTriangleApplicationSource();
+ CoreApplication::Run(helloTriangleApplicationSource);
+ return 0;
+}
+
+App::App() :
+ mWindowClosed(false),
+ mWindowVisible(true),
+ mWindowWidth(0),
+ mWindowHeight(0),
+ mEglDisplay(EGL_NO_DISPLAY),
+ mEglContext(EGL_NO_CONTEXT),
+ mEglSurface(EGL_NO_SURFACE)
+{
+}
+
+// The first method called when the IFrameworkView is being created.
+void App::Initialize(CoreApplicationView^ applicationView)
+{
+ // Register event handlers for app lifecycle. This example includes Activated, so that we
+ // can make the CoreWindow active and start rendering on the window.
+ applicationView->Activated +=
+ ref new TypedEventHandler<CoreApplicationView^, IActivatedEventArgs^>(this, &App::OnActivated);
+
+ // Logic for other event handlers could go here.
+ // Information about the Suspending and Resuming event handlers can be found here:
+ // http://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh994930.aspx
+
+ os = new OSWinrt;
+}
+
+// Called when the CoreWindow object is created (or re-created).
+void App::SetWindow(CoreWindow^ p_window)
+{
+ window = p_window;
+ window->VisibilityChanged +=
+ ref new TypedEventHandler<CoreWindow^, VisibilityChangedEventArgs^>(this, &App::OnVisibilityChanged);
+
+ window->Closed +=
+ ref new TypedEventHandler<CoreWindow^, CoreWindowEventArgs^>(this, &App::OnWindowClosed);
+
+ window->SizeChanged +=
+ ref new TypedEventHandler<CoreWindow^, WindowSizeChangedEventArgs^>(this, &App::OnWindowSizeChanged);
+
+#if !(WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
+ // Disable all pointer visual feedback for better performance when touching.
+ // This is not supported on Windows Phone applications.
+ auto pointerVisualizationSettings = PointerVisualizationSettings::GetForCurrentView();
+ pointerVisualizationSettings->IsContactFeedbackEnabled = false;
+ pointerVisualizationSettings->IsBarrelButtonFeedbackEnabled = false;
+#endif
+
+
+ window->PointerPressed +=
+ ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &App::OnPointerPressed);
+
+ window->PointerMoved +=
+ ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &App::OnPointerMoved);
+
+ window->PointerReleased +=
+ ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &App::OnPointerReleased);
+
+ //window->PointerWheelChanged +=
+ // ref new TypedEventHandler<CoreWindow^, PointerEventArgs^>(this, &App::OnPointerWheelChanged);
+
+
+
+ char* args[] = {"-path", "game", NULL};
+ Main::setup("winrt", 2, args, false);
+
+ // The CoreWindow has been created, so EGL can be initialized.
+ ContextEGL* context = memnew(ContextEGL(window));
+ os->set_gl_context(context);
+ UpdateWindowSize(Size(window->Bounds.Width, window->Bounds.Height));
+
+ Main::setup2();
+}
+
+static int _get_button(Windows::UI::Input::PointerPoint ^pt) {
+
+ using namespace Windows::UI::Input;
+
+#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+ return BUTTON_LEFT;
+#else
+ switch (pt->Properties->PointerUpdateKind)
+ {
+ case PointerUpdateKind::LeftButtonPressed:
+ case PointerUpdateKind::LeftButtonReleased:
+ return BUTTON_LEFT;
+
+ case PointerUpdateKind::RightButtonPressed:
+ case PointerUpdateKind::RightButtonReleased:
+ return BUTTON_RIGHT;
+
+ case PointerUpdateKind::MiddleButtonPressed:
+ case PointerUpdateKind::MiddleButtonReleased:
+ return BUTTON_MIDDLE;
+
+ case PointerUpdateKind::XButton1Pressed:
+ case PointerUpdateKind::XButton1Released:
+ return BUTTON_WHEEL_UP;
+
+ case PointerUpdateKind::XButton2Pressed:
+ case PointerUpdateKind::XButton2Released:
+ return BUTTON_WHEEL_DOWN;
+
+ default:
+ break;
+ }
+#endif
+
+ return 0;
+};
+
+static bool _is_touch(Windows::UI::Input::PointerPoint ^pointerPoint) {
+#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+ return true;
+#else
+ using namespace Windows::Devices::Input;
+ switch (pointerPoint->PointerDevice->PointerDeviceType) {
+ case PointerDeviceType::Touch:
+ case PointerDeviceType::Pen:
+ return true;
+ default:
+ return false;
+ }
+#endif
+}
+
+
+static Windows::Foundation::Point _get_pixel_position(CoreWindow^ window, Windows::Foundation::Point rawPosition, OS* os) {
+
+ Windows::Foundation::Point outputPosition;
+
+ // Compute coordinates normalized from 0..1.
+ // If the coordinates need to be sized to the SDL window,
+ // we'll do that after.
+ #if 1 || WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
+ outputPosition.X = rawPosition.X / window->Bounds.Width;
+ outputPosition.Y = rawPosition.Y / window->Bounds.Height;
+ #else
+ switch (DisplayProperties::CurrentOrientation)
+ {
+ case DisplayOrientations::Portrait:
+ outputPosition.X = rawPosition.X / window->Bounds.Width;
+ outputPosition.Y = rawPosition.Y / window->Bounds.Height;
+ break;
+ case DisplayOrientations::PortraitFlipped:
+ outputPosition.X = 1.0f - (rawPosition.X / window->Bounds.Width);
+ outputPosition.Y = 1.0f - (rawPosition.Y / window->Bounds.Height);
+ break;
+ case DisplayOrientations::Landscape:
+ outputPosition.X = rawPosition.Y / window->Bounds.Height;
+ outputPosition.Y = 1.0f - (rawPosition.X / window->Bounds.Width);
+ break;
+ case DisplayOrientations::LandscapeFlipped:
+ outputPosition.X = 1.0f - (rawPosition.Y / window->Bounds.Height);
+ outputPosition.Y = rawPosition.X / window->Bounds.Width;
+ break;
+ default:
+ break;
+ }
+ #endif
+
+ OS::VideoMode vm = os->get_video_mode();
+ outputPosition.X *= vm.width;
+ outputPosition.Y *= vm.height;
+
+ return outputPosition;
+};
+
+static int _get_finger(uint32_t p_touch_id) {
+
+ return p_touch_id % 31; // for now
+};
+
+void App::pointer_event(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args, bool p_pressed) {
+
+ Windows::UI::Input::PointerPoint ^point = args->CurrentPoint;
+ Windows::Foundation::Point pos = _get_pixel_position(window, point->Position, os);
+ int but = _get_button(point);
+ if (_is_touch(point)) {
+
+ InputEvent event;
+ event.type = InputEvent::SCREEN_TOUCH;
+ event.device = 0;
+ event.screen_touch.pressed = p_pressed;
+ event.screen_touch.x = pos.X;
+ event.screen_touch.y = pos.Y;
+ event.screen_touch.index = _get_finger(point->PointerId);
+
+ last_touch_x[event.screen_touch.index] = pos.X;
+ last_touch_y[event.screen_touch.index] = pos.Y;
+
+ os->input_event(event);
+ if (event.screen_touch.index != 0)
+ return;
+
+ }; // fallthrought of sorts
+
+ InputEvent event;
+ event.type = InputEvent::MOUSE_BUTTON;
+ event.device = 0;
+ event.mouse_button.pressed = p_pressed;
+ event.mouse_button.button_index = but;
+ event.mouse_button.x = pos.X;
+ event.mouse_button.y = pos.Y;
+ event.mouse_button.global_x = pos.X;
+ event.mouse_button.global_y = pos.Y;
+
+ last_touch_x[31] = pos.X;
+ last_touch_y[31] = pos.Y;
+
+ os->input_event(event);
+};
+
+
+void App::OnPointerPressed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args) {
+
+ pointer_event(sender, args, true);
+};
+
+
+void App::OnPointerReleased(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args) {
+
+ pointer_event(sender, args, false);
+};
+
+void App::OnPointerMoved(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args) {
+
+ Windows::UI::Input::PointerPoint ^point = args->CurrentPoint;
+ Windows::Foundation::Point pos = _get_pixel_position(window, point->Position, os);
+
+ if (_is_touch(point)) {
+
+ InputEvent event;
+ event.type = InputEvent::SCREEN_DRAG;
+ event.device = 0;
+ event.screen_drag.x = pos.X;
+ event.screen_drag.y = pos.Y;
+ event.screen_drag.index = _get_finger(point->PointerId);
+ event.screen_drag.relative_x = event.screen_drag.x - last_touch_x[event.screen_drag.index];
+ event.screen_drag.relative_y = event.screen_drag.y - last_touch_y[event.screen_drag.index];
+
+ os->input_event(event);
+ if (event.screen_drag.index != 0)
+ return;
+
+ }; // fallthrought of sorts
+
+ InputEvent event;
+ event.type = InputEvent::MOUSE_MOTION;
+ event.device = 0;
+ event.mouse_motion.x = pos.X;
+ event.mouse_motion.y = pos.Y;
+ event.mouse_motion.global_x = pos.X;
+ event.mouse_motion.global_y = pos.Y;
+ event.mouse_motion.relative_x = pos.X - last_touch_x[31];
+ event.mouse_motion.relative_y = pos.Y - last_touch_y[31];
+
+ os->input_event(event);
+
+};
+
+
+// Initializes scene resources
+void App::Load(Platform::String^ entryPoint)
+{
+ //char* args[] = {"-test", "render", NULL};
+ //Main::setup("winrt", 2, args);
+}
+
+// This method is called after the window becomes active.
+void App::Run()
+{
+ if (Main::start())
+ os->run();
+}
+
+// Terminate events do not cause Uninitialize to be called. It will be called if your IFrameworkView
+// class is torn down while the app is in the foreground.
+void App::Uninitialize()
+{
+ Main::cleanup();
+ delete os;
+}
+
+// Application lifecycle event handler.
+void App::OnActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args)
+{
+ // Run() won't start until the CoreWindow is activated.
+ CoreWindow::GetForCurrentThread()->Activate();
+}
+
+// Window event handlers.
+void App::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args)
+{
+ mWindowVisible = args->Visible;
+}
+
+void App::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args)
+{
+ mWindowClosed = true;
+}
+
+void App::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ args)
+{
+#if (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP)
+ // On Windows 8.1, apps are resized when they are snapped alongside other apps, or when the device is rotated.
+ // The default framebuffer will be automatically resized when either of these occur.
+ // In particular, on a 90 degree rotation, the default framebuffer's width and height will switch.
+ UpdateWindowSize(args->Size);
+#else if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
+ // On Windows Phone 8.1, the window size changes when the device is rotated.
+ // The default framebuffer will not be automatically resized when this occurs.
+ // It is therefore up to the app to handle rotation-specific logic in its rendering code.
+ //os->screen_size_changed();
+ UpdateWindowSize(args->Size);
+#endif
+}
+
+void App::UpdateWindowSize(Size size)
+{
+ float dpi;
+#if (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP)
+ DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
+ dpi = currentDisplayInformation->LogicalDpi;
+#else if (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP)
+ dpi = DisplayProperties::LogicalDpi;
+#endif
+ Size pixelSize(ConvertDipsToPixels(size.Width, dpi), ConvertDipsToPixels(size.Height, dpi));
+
+ mWindowWidth = static_cast<GLsizei>(pixelSize.Width);
+ mWindowHeight = static_cast<GLsizei>(pixelSize.Height);
+
+ OS::VideoMode vm;
+ vm.width = mWindowWidth;
+ vm.height = mWindowHeight;
+ vm.fullscreen = true;
+ vm.resizable = false;
+ os->set_video_mode(vm);
+}
diff --git a/platform/winrt/app.h b/platform/winrt/app.h
index 7926465ff8..9ce2fe560f 100644
--- a/platform/winrt/app.h
+++ b/platform/winrt/app.h
@@ -1,61 +1,61 @@
-#pragma once
-
-#include <string>
-
-#include <wrl.h>
-
-#include "os_winrt.h"
-#include "GLES2/gl2.h"
-
-namespace $ext_safeprojectname$
-{
- ref class App sealed : public Windows::ApplicationModel::Core::IFrameworkView
- {
- public:
- App();
-
- // IFrameworkView Methods.
- virtual void Initialize(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView);
- virtual void SetWindow(Windows::UI::Core::CoreWindow^ window);
- virtual void Load(Platform::String^ entryPoint);
- virtual void Run();
- virtual void Uninitialize();
-
- private:
- void RecreateRenderer();
-
- // Application lifecycle event handlers.
- void OnActivated(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView, Windows::ApplicationModel::Activation::IActivatedEventArgs^ args);
-
- // Window event handlers.
- void OnWindowSizeChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ args);
- void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args);
- void OnWindowClosed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CoreWindowEventArgs^ args);
-
- void pointer_event(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args, bool p_pressed);
- void OnPointerPressed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
- void OnPointerReleased(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
- void OnPointerMoved(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
-
-
- void UpdateWindowSize(Windows::Foundation::Size size);
- void InitializeEGL(Windows::UI::Core::CoreWindow^ window);
- void CleanupEGL();
-
- bool mWindowClosed;
- bool mWindowVisible;
- GLsizei mWindowWidth;
- GLsizei mWindowHeight;
-
- EGLDisplay mEglDisplay;
- EGLContext mEglContext;
- EGLSurface mEglSurface;
-
- CoreWindow^ window;
- OSWinrt* os;
-
- int last_touch_x[32]; // 20 fingers, index 31 reserved for the mouse
- int last_touch_y[32];
- };
-
-}
+#pragma once
+
+#include <string>
+
+#include <wrl.h>
+
+#include "os_winrt.h"
+#include "GLES2/gl2.h"
+
+namespace $ext_safeprojectname$
+{
+ ref class App sealed : public Windows::ApplicationModel::Core::IFrameworkView
+ {
+ public:
+ App();
+
+ // IFrameworkView Methods.
+ virtual void Initialize(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView);
+ virtual void SetWindow(Windows::UI::Core::CoreWindow^ window);
+ virtual void Load(Platform::String^ entryPoint);
+ virtual void Run();
+ virtual void Uninitialize();
+
+ private:
+ void RecreateRenderer();
+
+ // Application lifecycle event handlers.
+ void OnActivated(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView, Windows::ApplicationModel::Activation::IActivatedEventArgs^ args);
+
+ // Window event handlers.
+ void OnWindowSizeChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ args);
+ void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args);
+ void OnWindowClosed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CoreWindowEventArgs^ args);
+
+ void pointer_event(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args, bool p_pressed);
+ void OnPointerPressed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
+ void OnPointerReleased(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
+ void OnPointerMoved(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
+
+
+ void UpdateWindowSize(Windows::Foundation::Size size);
+ void InitializeEGL(Windows::UI::Core::CoreWindow^ window);
+ void CleanupEGL();
+
+ bool mWindowClosed;
+ bool mWindowVisible;
+ GLsizei mWindowWidth;
+ GLsizei mWindowHeight;
+
+ EGLDisplay mEglDisplay;
+ EGLContext mEglContext;
+ EGLSurface mEglSurface;
+
+ CoreWindow^ window;
+ OSWinrt* os;
+
+ int last_touch_x[32]; // 20 fingers, index 31 reserved for the mouse
+ int last_touch_y[32];
+ };
+
+}
diff --git a/platform/winrt/detect.py b/platform/winrt/detect.py
index d97d974a19..7439f0cd55 100644
--- a/platform/winrt/detect.py
+++ b/platform/winrt/detect.py
@@ -1,156 +1,156 @@
-
-
-import os
-
-import sys
-import string
-
-
-def is_active():
- return True
-
-def get_name():
- return "WinRT"
-
-def can_build():
- if (os.name=="nt"):
- #building natively on windows!
- if (os.getenv("VSINSTALLDIR")):
- return True
- return False
-
-def get_opts():
- return []
-
-def get_flags():
-
- return []
-
-
-def configure(env):
-
- env.Append(CPPPATH=['#platform/winrt', '#platform/winrt/include'])
- arch = ""
-
- if os.getenv('PLATFORM') == "ARM":
-
- # compiler commandline
- # debug: /Yu"pch.h" /MP /GS /analyze- /W3 /wd"4453" /wd"28204" /Zc:wchar_t /I"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\App2\App2.WindowsPhone\" /I"Generated Files\" /I"ARM\Debug\" /I"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\App2\App2.Shared\" /ZW:nostdlib /Zi /Gm- /Od /sdl /Fd"ARM\Debug\vc120.pdb" /fp:precise /D "PSAPI_VERSION=2" /D "WINAPI_FAMILY=WINAPI_FAMILY_PHONE_APP" /D "_UITHREADCTXT_SUPPORT=0" /D "_UNICODE" /D "UNICODE" /D "_DEBUG" /errorReport:prompt /WX- /Zc:forScope /RTC1 /ZW /Gd /Oy- /MDd /Fa"ARM\Debug\" /EHsc /nologo /Fo"ARM\Debug\" /Fp"ARM\Debug\App2.WindowsPhone.pch"
- # release: /Yu"pch.h" /MP /GS /GL /analyze- /W3 /wd"4453" /wd"28204" /Gy /Zc:wchar_t /I"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\App2\App2.WindowsPhone\" /I"Generated Files\" /I"ARM\Release\" /I"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\App2\App2.Shared\" /ZW:nostdlib /Zi /Gm- /O2 /sdl /Fd"ARM\Release\vc120.pdb" /fp:precise /D "PSAPI_VERSION=2" /D "WINAPI_FAMILY=WINAPI_FAMILY_PHONE_APP" /D "_UITHREADCTXT_SUPPORT=0" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /ZW /Gd /Oy- /Oi /MD /Fa"ARM\Release\" /EHsc /nologo /Fo"ARM\Release\" /Fp"ARM\Release\App2.WindowsPhone.pch"
-
- # linker commandline
- # debug: /OUT:"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\ARM\Debug\App2.WindowsPhone\App2.WindowsPhone.exe" /MANIFEST:NO /NXCOMPAT /PDB:"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\ARM\Debug\App2.WindowsPhone\App2.WindowsPhone.pdb" /DYNAMICBASE "WindowsPhoneCore.lib" "RuntimeObject.lib" "PhoneAppModelHost.lib" /DEBUG /MACHINE:ARM /NODEFAULTLIB:"kernel32.lib" /NODEFAULTLIB:"ole32.lib" /WINMD /APPCONTAINER /INCREMENTAL /PGD:"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\ARM\Debug\App2.WindowsPhone\App2.WindowsPhone.pgd" /WINMDFILE:"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\ARM\Debug\App2.WindowsPhone\App2.winmd" /SUBSYSTEM:WINDOWS /MANIFESTUAC:NO /ManifestFile:"ARM\Debug\App2.WindowsPhone.exe.intermediate.manifest" /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
- # release: /OUT:"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\ARM\Release\App2.WindowsPhone\App2.WindowsPhone.exe" /MANIFEST:NO /LTCG /NXCOMPAT /PDB:"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\ARM\Release\App2.WindowsPhone\App2.WindowsPhone.pdb" /DYNAMICBASE "WindowsPhoneCore.lib" "RuntimeObject.lib" "PhoneAppModelHost.lib" /DEBUG /MACHINE:ARM /NODEFAULTLIB:"kernel32.lib" /NODEFAULTLIB:"ole32.lib" /WINMD /APPCONTAINER /OPT:REF /PGD:"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\ARM\Release\App2.WindowsPhone\App2.WindowsPhone.pgd" /WINMDFILE:"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\ARM\Release\App2.WindowsPhone\App2.winmd" /SUBSYSTEM:WINDOWS /MANIFESTUAC:NO /ManifestFile:"ARM\Release\App2.WindowsPhone.exe.intermediate.manifest" /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
-
- arch = "arm"
-
- env.Append(LINKFLAGS=['/INCREMENTAL:NO', '/MANIFEST:NO', '/NXCOMPAT', '/DYNAMICBASE', "WindowsPhoneCore.lib", "RuntimeObject.lib", "PhoneAppModelHost.lib", "/DEBUG", "/MACHINE:ARM", '/NODEFAULTLIB:"kernel32.lib"', '/NODEFAULTLIB:"ole32.lib"', '/WINMD', '/APPCONTAINER', '/MANIFESTUAC:NO', '/ERRORREPORT:PROMPT', '/NOLOGO', '/TLBID:1'])
- env.Append(LIBPATH=['#platform/winrt/ARM/lib'])
-
- env.Append(CCFLAGS=string.split('/MP /GS /wd"4453" /wd"28204" /analyze- /Zc:wchar_t /Zi /Gm- /Od /fp:precise /fp:precise /D "PSAPI_VERSION=2" /D "WINAPI_FAMILY=WINAPI_FAMILY_PHONE_APP" /DWINDOWSPHONE_ENABLED /D "_UITHREADCTXT_SUPPORT=0" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /Gd /Oy- /Oi /MD /RTC1 /Gd /EHsc /nologo'))
- env.Append(CXXFLAGS=string.split('/ZW'))
-
- if (env["target"]=="release"):
-
- env.Append(CCFLAGS=['/O2'])
- env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS'])
-
- elif (env["target"]=="test"):
-
- env.Append(CCFLAGS=['/O2','/DDEBUG_ENABLED','/DD3D_DEBUG_INFO'])
- env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
-
- elif (env["target"]=="debug"):
-
- env.Append(CCFLAGS=['/Zi','/DDEBUG_ENABLED','/DD3D_DEBUG_INFO'])
- env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
- env.Append(LINKFLAGS=['/DEBUG', '/D_DEBUG'])
-
- elif (env["target"]=="profile"):
-
- env.Append(CCFLAGS=['-g','-pg'])
- env.Append(LINKFLAGS=['-pg'])
-
-
- env['ENV'] = os.environ;
- # fix environment for windows phone 8.1
- env['ENV']['WINDOWSPHONEKITDIR'] = env['ENV']['WINDOWSPHONEKITDIR'].replace("8.0", "8.1") # wtf
- env['ENV']['INCLUDE'] = env['ENV']['INCLUDE'].replace("8.0", "8.1")
- env['ENV']['LIB'] = env['ENV']['LIB'].replace("8.0", "8.1")
- env['ENV']['PATH'] = env['ENV']['PATH'].replace("8.0", "8.1")
- env['ENV']['LIBPATH'] = env['ENV']['LIBPATH'].replace("8.0\\Windows Metadata", "8.1\\References\\CommonConfiguration\\Neutral")
-
- else:
-
- arch = "x64"
- env.Append(LINKFLAGS=['/MANIFEST:NO', '/NXCOMPAT', '/DYNAMICBASE', "kernel32.lib", '/MACHINE:X64', '/WINMD', '/APPCONTAINER', '/MANIFESTUAC:NO', '/ERRORREPORT:PROMPT', '/NOLOGO', '/TLBID:1'])
-
- env.Append(LIBPATH=['#platform/winrt/x64/lib'])
-
-
- if (env["target"]=="release"):
-
- env.Append(CCFLAGS=['/O2'])
- env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS'])
- env.Append(LINKFLAGS=['/ENTRY:mainCRTStartup'])
-
- elif (env["target"]=="test"):
-
- env.Append(CCFLAGS=['/O2','/DDEBUG_ENABLED','/DD3D_DEBUG_INFO'])
- env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
-
- elif (env["target"]=="debug"):
-
- env.Append(CCFLAGS=['/Zi','/DDEBUG_ENABLED','/DD3D_DEBUG_INFO'])
- env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
- env.Append(LINKFLAGS=['/DEBUG', '/D_DEBUG'])
-
- elif (env["target"]=="profile"):
-
- env.Append(CCFLAGS=['-g','-pg'])
- env.Append(LINKFLAGS=['-pg'])
-
-
- env.Append(CCFLAGS=string.split('/MP /GS /wd"4453" /wd"28204" /Zc:wchar_t /Gm- /Od /fp:precise /D "_UNICODE" /D "UNICODE" /D "WINAPI_FAMILY=WINAPI_FAMILY_APP" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /MDd /EHsc /nologo'))
- env.Append(CXXFLAGS=string.split('/ZW'))
- env.Append(CCFLAGS=['/AI', os.environ['VCINSTALLDIR']+'\\vcpackages', '/AI', os.environ['WINDOWSSDKDIR']+'\\References\\CommonConfiguration\\Neutral'])
- env.Append(CCFLAGS=['/DWINAPI_FAMILY=WINAPI_FAMILY_APP', '/D_WIN32_WINNT=0x0603', '/DNTDDI_VERSION=0x06030000'])
-
- env['ENV'] = os.environ;
-
-
- env["PROGSUFFIX"]="."+arch+env["PROGSUFFIX"]
- env["OBJSUFFIX"]="."+arch+env["OBJSUFFIX"]
- env["LIBSUFFIX"]="."+arch+env["LIBSUFFIX"]
-
-
- #env.Append(CCFLAGS=['/Gd','/GR','/nologo', '/EHsc'])
- #env.Append(CXXFLAGS=['/TP', '/ZW'])
- #env.Append(CPPFLAGS=['/DMSVC', '/GR', ])
- ##env.Append(CCFLAGS=['/I'+os.getenv("WindowsSdkDir")+"/Include"])
- env.Append(CCFLAGS=['/DWINRT_ENABLED'])
- env.Append(CCFLAGS=['/DWINDOWS_ENABLED'])
- env.Append(CCFLAGS=['/DRTAUDIO_ENABLED'])
- #env.Append(CCFLAGS=['/DWIN32'])
- env.Append(CCFLAGS=['/DTYPED_METHOD_BIND'])
-
- env.Append(CCFLAGS=['/DGLES2_ENABLED'])
- #env.Append(CCFLAGS=['/DGLES1_ENABLED'])
-
- LIBS=[
- #'winmm',
- 'libEGL',
- 'libGLESv2',
- 'libANGLE',
- #'kernel32','ole32','user32', 'advapi32'
- ]
- env.Append(LINKFLAGS=[p+".lib" for p in LIBS])
-
- import methods
- env.Append( BUILDERS = { 'GLSL120' : env.Builder(action = methods.build_legacygl_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
- env.Append( BUILDERS = { 'GLSL' : env.Builder(action = methods.build_glsl_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
- env.Append( BUILDERS = { 'HLSL9' : env.Builder(action = methods.build_hlsl_dx9_headers, suffix = 'hlsl.h',src_suffix = '.hlsl') } )
- env.Append( BUILDERS = { 'GLSL120GLES' : env.Builder(action = methods.build_gles2_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
-
-
-#/c/Program Files (x86)/Windows Phone Kits/8.1/lib/ARM/WindowsPhoneCore.lib
+
+
+import os
+
+import sys
+import string
+
+
+def is_active():
+ return True
+
+def get_name():
+ return "WinRT"
+
+def can_build():
+ if (os.name=="nt"):
+ #building natively on windows!
+ if (os.getenv("VSINSTALLDIR")):
+ return True
+ return False
+
+def get_opts():
+ return []
+
+def get_flags():
+
+ return []
+
+
+def configure(env):
+
+ env.Append(CPPPATH=['#platform/winrt', '#platform/winrt/include'])
+ arch = ""
+
+ if os.getenv('PLATFORM') == "ARM":
+
+ # compiler commandline
+ # debug: /Yu"pch.h" /MP /GS /analyze- /W3 /wd"4453" /wd"28204" /Zc:wchar_t /I"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\App2\App2.WindowsPhone\" /I"Generated Files\" /I"ARM\Debug\" /I"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\App2\App2.Shared\" /ZW:nostdlib /Zi /Gm- /Od /sdl /Fd"ARM\Debug\vc120.pdb" /fp:precise /D "PSAPI_VERSION=2" /D "WINAPI_FAMILY=WINAPI_FAMILY_PHONE_APP" /D "_UITHREADCTXT_SUPPORT=0" /D "_UNICODE" /D "UNICODE" /D "_DEBUG" /errorReport:prompt /WX- /Zc:forScope /RTC1 /ZW /Gd /Oy- /MDd /Fa"ARM\Debug\" /EHsc /nologo /Fo"ARM\Debug\" /Fp"ARM\Debug\App2.WindowsPhone.pch"
+ # release: /Yu"pch.h" /MP /GS /GL /analyze- /W3 /wd"4453" /wd"28204" /Gy /Zc:wchar_t /I"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\App2\App2.WindowsPhone\" /I"Generated Files\" /I"ARM\Release\" /I"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\App2\App2.Shared\" /ZW:nostdlib /Zi /Gm- /O2 /sdl /Fd"ARM\Release\vc120.pdb" /fp:precise /D "PSAPI_VERSION=2" /D "WINAPI_FAMILY=WINAPI_FAMILY_PHONE_APP" /D "_UITHREADCTXT_SUPPORT=0" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /ZW /Gd /Oy- /Oi /MD /Fa"ARM\Release\" /EHsc /nologo /Fo"ARM\Release\" /Fp"ARM\Release\App2.WindowsPhone.pch"
+
+ # linker commandline
+ # debug: /OUT:"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\ARM\Debug\App2.WindowsPhone\App2.WindowsPhone.exe" /MANIFEST:NO /NXCOMPAT /PDB:"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\ARM\Debug\App2.WindowsPhone\App2.WindowsPhone.pdb" /DYNAMICBASE "WindowsPhoneCore.lib" "RuntimeObject.lib" "PhoneAppModelHost.lib" /DEBUG /MACHINE:ARM /NODEFAULTLIB:"kernel32.lib" /NODEFAULTLIB:"ole32.lib" /WINMD /APPCONTAINER /INCREMENTAL /PGD:"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\ARM\Debug\App2.WindowsPhone\App2.WindowsPhone.pgd" /WINMDFILE:"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\ARM\Debug\App2.WindowsPhone\App2.winmd" /SUBSYSTEM:WINDOWS /MANIFESTUAC:NO /ManifestFile:"ARM\Debug\App2.WindowsPhone.exe.intermediate.manifest" /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
+ # release: /OUT:"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\ARM\Release\App2.WindowsPhone\App2.WindowsPhone.exe" /MANIFEST:NO /LTCG /NXCOMPAT /PDB:"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\ARM\Release\App2.WindowsPhone\App2.WindowsPhone.pdb" /DYNAMICBASE "WindowsPhoneCore.lib" "RuntimeObject.lib" "PhoneAppModelHost.lib" /DEBUG /MACHINE:ARM /NODEFAULTLIB:"kernel32.lib" /NODEFAULTLIB:"ole32.lib" /WINMD /APPCONTAINER /OPT:REF /PGD:"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\ARM\Release\App2.WindowsPhone\App2.WindowsPhone.pgd" /WINMDFILE:"C:\Users\ariel\Documents\Visual Studio 2013\Projects\App2\ARM\Release\App2.WindowsPhone\App2.winmd" /SUBSYSTEM:WINDOWS /MANIFESTUAC:NO /ManifestFile:"ARM\Release\App2.WindowsPhone.exe.intermediate.manifest" /OPT:ICF /ERRORREPORT:PROMPT /NOLOGO /TLBID:1
+
+ arch = "arm"
+
+ env.Append(LINKFLAGS=['/INCREMENTAL:NO', '/MANIFEST:NO', '/NXCOMPAT', '/DYNAMICBASE', "WindowsPhoneCore.lib", "RuntimeObject.lib", "PhoneAppModelHost.lib", "/DEBUG", "/MACHINE:ARM", '/NODEFAULTLIB:"kernel32.lib"', '/NODEFAULTLIB:"ole32.lib"', '/WINMD', '/APPCONTAINER', '/MANIFESTUAC:NO', '/ERRORREPORT:PROMPT', '/NOLOGO', '/TLBID:1'])
+ env.Append(LIBPATH=['#platform/winrt/ARM/lib'])
+
+ env.Append(CCFLAGS=string.split('/MP /GS /wd"4453" /wd"28204" /analyze- /Zc:wchar_t /Zi /Gm- /Od /fp:precise /fp:precise /D "PSAPI_VERSION=2" /D "WINAPI_FAMILY=WINAPI_FAMILY_PHONE_APP" /DWINDOWSPHONE_ENABLED /D "_UITHREADCTXT_SUPPORT=0" /D "_UNICODE" /D "UNICODE" /errorReport:prompt /WX- /Zc:forScope /Gd /Oy- /Oi /MD /RTC1 /Gd /EHsc /nologo'))
+ env.Append(CXXFLAGS=string.split('/ZW'))
+
+ if (env["target"]=="release"):
+
+ env.Append(CCFLAGS=['/O2'])
+ env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS'])
+
+ elif (env["target"]=="test"):
+
+ env.Append(CCFLAGS=['/O2','/DDEBUG_ENABLED','/DD3D_DEBUG_INFO'])
+ env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
+
+ elif (env["target"]=="debug"):
+
+ env.Append(CCFLAGS=['/Zi','/DDEBUG_ENABLED','/DD3D_DEBUG_INFO'])
+ env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
+ env.Append(LINKFLAGS=['/DEBUG', '/D_DEBUG'])
+
+ elif (env["target"]=="profile"):
+
+ env.Append(CCFLAGS=['-g','-pg'])
+ env.Append(LINKFLAGS=['-pg'])
+
+
+ env['ENV'] = os.environ;
+ # fix environment for windows phone 8.1
+ env['ENV']['WINDOWSPHONEKITDIR'] = env['ENV']['WINDOWSPHONEKITDIR'].replace("8.0", "8.1") # wtf
+ env['ENV']['INCLUDE'] = env['ENV']['INCLUDE'].replace("8.0", "8.1")
+ env['ENV']['LIB'] = env['ENV']['LIB'].replace("8.0", "8.1")
+ env['ENV']['PATH'] = env['ENV']['PATH'].replace("8.0", "8.1")
+ env['ENV']['LIBPATH'] = env['ENV']['LIBPATH'].replace("8.0\\Windows Metadata", "8.1\\References\\CommonConfiguration\\Neutral")
+
+ else:
+
+ arch = "x64"
+ env.Append(LINKFLAGS=['/MANIFEST:NO', '/NXCOMPAT', '/DYNAMICBASE', "kernel32.lib", '/MACHINE:X64', '/WINMD', '/APPCONTAINER', '/MANIFESTUAC:NO', '/ERRORREPORT:PROMPT', '/NOLOGO', '/TLBID:1'])
+
+ env.Append(LIBPATH=['#platform/winrt/x64/lib'])
+
+
+ if (env["target"]=="release"):
+
+ env.Append(CCFLAGS=['/O2'])
+ env.Append(LINKFLAGS=['/SUBSYSTEM:WINDOWS'])
+ env.Append(LINKFLAGS=['/ENTRY:mainCRTStartup'])
+
+ elif (env["target"]=="test"):
+
+ env.Append(CCFLAGS=['/O2','/DDEBUG_ENABLED','/DD3D_DEBUG_INFO'])
+ env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
+
+ elif (env["target"]=="debug"):
+
+ env.Append(CCFLAGS=['/Zi','/DDEBUG_ENABLED','/DD3D_DEBUG_INFO'])
+ env.Append(LINKFLAGS=['/SUBSYSTEM:CONSOLE'])
+ env.Append(LINKFLAGS=['/DEBUG', '/D_DEBUG'])
+
+ elif (env["target"]=="profile"):
+
+ env.Append(CCFLAGS=['-g','-pg'])
+ env.Append(LINKFLAGS=['-pg'])
+
+
+ env.Append(CCFLAGS=string.split('/MP /GS /wd"4453" /wd"28204" /Zc:wchar_t /Gm- /Od /fp:precise /D "_UNICODE" /D "UNICODE" /D "WINAPI_FAMILY=WINAPI_FAMILY_APP" /errorReport:prompt /WX- /Zc:forScope /RTC1 /Gd /MDd /EHsc /nologo'))
+ env.Append(CXXFLAGS=string.split('/ZW'))
+ env.Append(CCFLAGS=['/AI', os.environ['VCINSTALLDIR']+'\\vcpackages', '/AI', os.environ['WINDOWSSDKDIR']+'\\References\\CommonConfiguration\\Neutral'])
+ env.Append(CCFLAGS=['/DWINAPI_FAMILY=WINAPI_FAMILY_APP', '/D_WIN32_WINNT=0x0603', '/DNTDDI_VERSION=0x06030000'])
+
+ env['ENV'] = os.environ;
+
+
+ env["PROGSUFFIX"]="."+arch+env["PROGSUFFIX"]
+ env["OBJSUFFIX"]="."+arch+env["OBJSUFFIX"]
+ env["LIBSUFFIX"]="."+arch+env["LIBSUFFIX"]
+
+
+ #env.Append(CCFLAGS=['/Gd','/GR','/nologo', '/EHsc'])
+ #env.Append(CXXFLAGS=['/TP', '/ZW'])
+ #env.Append(CPPFLAGS=['/DMSVC', '/GR', ])
+ ##env.Append(CCFLAGS=['/I'+os.getenv("WindowsSdkDir")+"/Include"])
+ env.Append(CCFLAGS=['/DWINRT_ENABLED'])
+ env.Append(CCFLAGS=['/DWINDOWS_ENABLED'])
+ env.Append(CCFLAGS=['/DRTAUDIO_ENABLED'])
+ #env.Append(CCFLAGS=['/DWIN32'])
+ env.Append(CCFLAGS=['/DTYPED_METHOD_BIND'])
+
+ env.Append(CCFLAGS=['/DGLES2_ENABLED'])
+ #env.Append(CCFLAGS=['/DGLES1_ENABLED'])
+
+ LIBS=[
+ #'winmm',
+ 'libEGL',
+ 'libGLESv2',
+ 'libANGLE',
+ #'kernel32','ole32','user32', 'advapi32'
+ ]
+ env.Append(LINKFLAGS=[p+".lib" for p in LIBS])
+
+ import methods
+ env.Append( BUILDERS = { 'GLSL120' : env.Builder(action = methods.build_legacygl_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
+ env.Append( BUILDERS = { 'GLSL' : env.Builder(action = methods.build_glsl_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
+ env.Append( BUILDERS = { 'HLSL9' : env.Builder(action = methods.build_hlsl_dx9_headers, suffix = 'hlsl.h',src_suffix = '.hlsl') } )
+ env.Append( BUILDERS = { 'GLSL120GLES' : env.Builder(action = methods.build_gles2_headers, suffix = 'glsl.h',src_suffix = '.glsl') } )
+
+
+#/c/Program Files (x86)/Windows Phone Kits/8.1/lib/ARM/WindowsPhoneCore.lib
diff --git a/platform/winrt/include/EGL/egl.h b/platform/winrt/include/EGL/egl.h
index fb6f9b71e0..12590a0e20 100644
--- a/platform/winrt/include/EGL/egl.h
+++ b/platform/winrt/include/EGL/egl.h
@@ -1,298 +1,298 @@
-#ifndef __egl_h_
-#define __egl_h_ 1
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
-** Copyright (c) 2013-2014 The Khronos Group Inc.
-**
-** Permission is hereby granted, free of charge, to any person obtaining a
-** copy of this software and/or associated documentation files (the
-** "Materials"), to deal in the Materials without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Materials, and to
-** permit persons to whom the Materials are 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 Materials.
-**
-** THE MATERIALS ARE 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
-** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-*/
-/*
-** This header is generated from the Khronos OpenGL / OpenGL ES XML
-** API Registry. The current version of the Registry, generator scripts
-** used to make the header, and the header can be found at
-** http://www.opengl.org/registry/
-**
-** Khronos $Revision: 27018 $ on $Date: 2014-06-10 08:06:12 -0700 (Tue, 10 Jun 2014) $
-*/
-
-#include <EGL/eglplatform.h>
-
-/* Generated on date 20140610 */
-
-/* Generated C header for:
- * API: egl
- * Versions considered: .*
- * Versions emitted: .*
- * Default extensions included: None
- * Additional extensions included: _nomatch_^
- * Extensions removed: _nomatch_^
- */
-
-#ifndef EGL_VERSION_1_0
-#define EGL_VERSION_1_0 1
-typedef unsigned int EGLBoolean;
-typedef void *EGLDisplay;
-#include <KHR/khrplatform.h>
-#include <EGL/eglplatform.h>
-typedef void *EGLConfig;
-typedef void *EGLSurface;
-typedef void *EGLContext;
-typedef void (*__eglMustCastToProperFunctionPointerType)(void);
-#define EGL_ALPHA_SIZE 0x3021
-#define EGL_BAD_ACCESS 0x3002
-#define EGL_BAD_ALLOC 0x3003
-#define EGL_BAD_ATTRIBUTE 0x3004
-#define EGL_BAD_CONFIG 0x3005
-#define EGL_BAD_CONTEXT 0x3006
-#define EGL_BAD_CURRENT_SURFACE 0x3007
-#define EGL_BAD_DISPLAY 0x3008
-#define EGL_BAD_MATCH 0x3009
-#define EGL_BAD_NATIVE_PIXMAP 0x300A
-#define EGL_BAD_NATIVE_WINDOW 0x300B
-#define EGL_BAD_PARAMETER 0x300C
-#define EGL_BAD_SURFACE 0x300D
-#define EGL_BLUE_SIZE 0x3022
-#define EGL_BUFFER_SIZE 0x3020
-#define EGL_CONFIG_CAVEAT 0x3027
-#define EGL_CONFIG_ID 0x3028
-#define EGL_CORE_NATIVE_ENGINE 0x305B
-#define EGL_DEPTH_SIZE 0x3025
-#define EGL_DONT_CARE ((EGLint)-1)
-#define EGL_DRAW 0x3059
-#define EGL_EXTENSIONS 0x3055
-#define EGL_FALSE 0
-#define EGL_GREEN_SIZE 0x3023
-#define EGL_HEIGHT 0x3056
-#define EGL_LARGEST_PBUFFER 0x3058
-#define EGL_LEVEL 0x3029
-#define EGL_MAX_PBUFFER_HEIGHT 0x302A
-#define EGL_MAX_PBUFFER_PIXELS 0x302B
-#define EGL_MAX_PBUFFER_WIDTH 0x302C
-#define EGL_NATIVE_RENDERABLE 0x302D
-#define EGL_NATIVE_VISUAL_ID 0x302E
-#define EGL_NATIVE_VISUAL_TYPE 0x302F
-#define EGL_NONE 0x3038
-#define EGL_NON_CONFORMANT_CONFIG 0x3051
-#define EGL_NOT_INITIALIZED 0x3001
-#define EGL_NO_CONTEXT ((EGLContext)0)
-#define EGL_NO_DISPLAY ((EGLDisplay)0)
-#define EGL_NO_SURFACE ((EGLSurface)0)
-#define EGL_PBUFFER_BIT 0x0001
-#define EGL_PIXMAP_BIT 0x0002
-#define EGL_READ 0x305A
-#define EGL_RED_SIZE 0x3024
-#define EGL_SAMPLES 0x3031
-#define EGL_SAMPLE_BUFFERS 0x3032
-#define EGL_SLOW_CONFIG 0x3050
-#define EGL_STENCIL_SIZE 0x3026
-#define EGL_SUCCESS 0x3000
-#define EGL_SURFACE_TYPE 0x3033
-#define EGL_TRANSPARENT_BLUE_VALUE 0x3035
-#define EGL_TRANSPARENT_GREEN_VALUE 0x3036
-#define EGL_TRANSPARENT_RED_VALUE 0x3037
-#define EGL_TRANSPARENT_RGB 0x3052
-#define EGL_TRANSPARENT_TYPE 0x3034
-#define EGL_TRUE 1
-#define EGL_VENDOR 0x3053
-#define EGL_VERSION 0x3054
-#define EGL_WIDTH 0x3057
-#define EGL_WINDOW_BIT 0x0004
-EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig (EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
-EGLAPI EGLBoolean EGLAPIENTRY eglCopyBuffers (EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target);
-EGLAPI EGLContext EGLAPIENTRY eglCreateContext (EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list);
-EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferSurface (EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);
-EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurface (EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list);
-EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface (EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list);
-EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext (EGLDisplay dpy, EGLContext ctx);
-EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface (EGLDisplay dpy, EGLSurface surface);
-EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib (EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);
-EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs (EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);
-EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay (void);
-EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface (EGLint readdraw);
-EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay (EGLNativeDisplayType display_id);
-EGLAPI EGLint EGLAPIENTRY eglGetError (void);
-EGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddress (const char *procname);
-EGLAPI EGLBoolean EGLAPIENTRY eglInitialize (EGLDisplay dpy, EGLint *major, EGLint *minor);
-EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent (EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
-EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext (EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value);
-EGLAPI const char *EGLAPIENTRY eglQueryString (EGLDisplay dpy, EGLint name);
-EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value);
-EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers (EGLDisplay dpy, EGLSurface surface);
-EGLAPI EGLBoolean EGLAPIENTRY eglTerminate (EGLDisplay dpy);
-EGLAPI EGLBoolean EGLAPIENTRY eglWaitGL (void);
-EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative (EGLint engine);
-#endif /* EGL_VERSION_1_0 */
-
-#ifndef EGL_VERSION_1_1
-#define EGL_VERSION_1_1 1
-#define EGL_BACK_BUFFER 0x3084
-#define EGL_BIND_TO_TEXTURE_RGB 0x3039
-#define EGL_BIND_TO_TEXTURE_RGBA 0x303A
-#define EGL_CONTEXT_LOST 0x300E
-#define EGL_MIN_SWAP_INTERVAL 0x303B
-#define EGL_MAX_SWAP_INTERVAL 0x303C
-#define EGL_MIPMAP_TEXTURE 0x3082
-#define EGL_MIPMAP_LEVEL 0x3083
-#define EGL_NO_TEXTURE 0x305C
-#define EGL_TEXTURE_2D 0x305F
-#define EGL_TEXTURE_FORMAT 0x3080
-#define EGL_TEXTURE_RGB 0x305D
-#define EGL_TEXTURE_RGBA 0x305E
-#define EGL_TEXTURE_TARGET 0x3081
-EGLAPI EGLBoolean EGLAPIENTRY eglBindTexImage (EGLDisplay dpy, EGLSurface surface, EGLint buffer);
-EGLAPI EGLBoolean EGLAPIENTRY eglReleaseTexImage (EGLDisplay dpy, EGLSurface surface, EGLint buffer);
-EGLAPI EGLBoolean EGLAPIENTRY eglSurfaceAttrib (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value);
-EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval (EGLDisplay dpy, EGLint interval);
-#endif /* EGL_VERSION_1_1 */
-
-#ifndef EGL_VERSION_1_2
-#define EGL_VERSION_1_2 1
-typedef unsigned int EGLenum;
-typedef void *EGLClientBuffer;
-#define EGL_ALPHA_FORMAT 0x3088
-#define EGL_ALPHA_FORMAT_NONPRE 0x308B
-#define EGL_ALPHA_FORMAT_PRE 0x308C
-#define EGL_ALPHA_MASK_SIZE 0x303E
-#define EGL_BUFFER_PRESERVED 0x3094
-#define EGL_BUFFER_DESTROYED 0x3095
-#define EGL_CLIENT_APIS 0x308D
-#define EGL_COLORSPACE 0x3087
-#define EGL_COLORSPACE_sRGB 0x3089
-#define EGL_COLORSPACE_LINEAR 0x308A
-#define EGL_COLOR_BUFFER_TYPE 0x303F
-#define EGL_CONTEXT_CLIENT_TYPE 0x3097
-#define EGL_DISPLAY_SCALING 10000
-#define EGL_HORIZONTAL_RESOLUTION 0x3090
-#define EGL_LUMINANCE_BUFFER 0x308F
-#define EGL_LUMINANCE_SIZE 0x303D
-#define EGL_OPENGL_ES_BIT 0x0001
-#define EGL_OPENVG_BIT 0x0002
-#define EGL_OPENGL_ES_API 0x30A0
-#define EGL_OPENVG_API 0x30A1
-#define EGL_OPENVG_IMAGE 0x3096
-#define EGL_PIXEL_ASPECT_RATIO 0x3092
-#define EGL_RENDERABLE_TYPE 0x3040
-#define EGL_RENDER_BUFFER 0x3086
-#define EGL_RGB_BUFFER 0x308E
-#define EGL_SINGLE_BUFFER 0x3085
-#define EGL_SWAP_BEHAVIOR 0x3093
-#define EGL_UNKNOWN ((EGLint)-1)
-#define EGL_VERTICAL_RESOLUTION 0x3091
-EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI (EGLenum api);
-EGLAPI EGLenum EGLAPIENTRY eglQueryAPI (void);
-EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer (EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list);
-EGLAPI EGLBoolean EGLAPIENTRY eglReleaseThread (void);
-EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient (void);
-#endif /* EGL_VERSION_1_2 */
-
-#ifndef EGL_VERSION_1_3
-#define EGL_VERSION_1_3 1
-#define EGL_CONFORMANT 0x3042
-#define EGL_CONTEXT_CLIENT_VERSION 0x3098
-#define EGL_MATCH_NATIVE_PIXMAP 0x3041
-#define EGL_OPENGL_ES2_BIT 0x0004
-#define EGL_VG_ALPHA_FORMAT 0x3088
-#define EGL_VG_ALPHA_FORMAT_NONPRE 0x308B
-#define EGL_VG_ALPHA_FORMAT_PRE 0x308C
-#define EGL_VG_ALPHA_FORMAT_PRE_BIT 0x0040
-#define EGL_VG_COLORSPACE 0x3087
-#define EGL_VG_COLORSPACE_sRGB 0x3089
-#define EGL_VG_COLORSPACE_LINEAR 0x308A
-#define EGL_VG_COLORSPACE_LINEAR_BIT 0x0020
-#endif /* EGL_VERSION_1_3 */
-
-#ifndef EGL_VERSION_1_4
-#define EGL_VERSION_1_4 1
-#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0)
-#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200
-#define EGL_MULTISAMPLE_RESOLVE 0x3099
-#define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A
-#define EGL_MULTISAMPLE_RESOLVE_BOX 0x309B
-#define EGL_OPENGL_API 0x30A2
-#define EGL_OPENGL_BIT 0x0008
-#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400
-EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext (void);
-#endif /* EGL_VERSION_1_4 */
-
-#ifndef EGL_VERSION_1_5
-#define EGL_VERSION_1_5 1
-typedef void *EGLSync;
-typedef intptr_t EGLAttrib;
-typedef khronos_utime_nanoseconds_t EGLTime;
-#define EGL_CONTEXT_MAJOR_VERSION 0x3098
-#define EGL_CONTEXT_MINOR_VERSION 0x30FB
-#define EGL_CONTEXT_OPENGL_PROFILE_MASK 0x30FD
-#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY 0x31BD
-#define EGL_NO_RESET_NOTIFICATION 0x31BE
-#define EGL_LOSE_CONTEXT_ON_RESET 0x31BF
-#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT 0x00000001
-#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT 0x00000002
-#define EGL_CONTEXT_OPENGL_DEBUG 0x31B0
-#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE 0x31B1
-#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS 0x31B2
-#define EGL_OPENGL_ES3_BIT 0x00000040
-#define EGL_CL_EVENT_HANDLE 0x309C
-#define EGL_SYNC_CL_EVENT 0x30FE
-#define EGL_SYNC_CL_EVENT_COMPLETE 0x30FF
-#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE 0x30F0
-#define EGL_SYNC_TYPE 0x30F7
-#define EGL_SYNC_STATUS 0x30F1
-#define EGL_SYNC_CONDITION 0x30F8
-#define EGL_SIGNALED 0x30F2
-#define EGL_UNSIGNALED 0x30F3
-#define EGL_SYNC_FLUSH_COMMANDS_BIT 0x0001
-#define EGL_FOREVER 0xFFFFFFFFFFFFFFFFull
-#define EGL_TIMEOUT_EXPIRED 0x30F5
-#define EGL_CONDITION_SATISFIED 0x30F6
-#define EGL_NO_SYNC ((EGLSync)0)
-#define EGL_SYNC_FENCE 0x30F9
-#define EGL_GL_COLORSPACE 0x309D
-#define EGL_GL_COLORSPACE_SRGB 0x3089
-#define EGL_GL_COLORSPACE_LINEAR 0x308A
-#define EGL_GL_RENDERBUFFER 0x30B9
-#define EGL_GL_TEXTURE_2D 0x30B1
-#define EGL_GL_TEXTURE_LEVEL 0x30BC
-#define EGL_GL_TEXTURE_3D 0x30B2
-#define EGL_GL_TEXTURE_ZOFFSET 0x30BD
-#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x30B3
-#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x30B4
-#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x30B5
-#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x30B6
-#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x30B7
-#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x30B8
-EGLAPI EGLSync EGLAPIENTRY eglCreateSync (EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list);
-EGLAPI EGLBoolean EGLAPIENTRY eglDestroySync (EGLDisplay dpy, EGLSync sync);
-EGLAPI EGLint EGLAPIENTRY eglClientWaitSync (EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout);
-EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttrib (EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value);
-EGLAPI EGLDisplay EGLAPIENTRY eglGetPlatformDisplay (EGLenum platform, void *native_display, const EGLAttrib *attrib_list);
-EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformWindowSurface (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list);
-EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformPixmapSurface (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list);
-EGLAPI EGLBoolean EGLAPIENTRY eglWaitSync (EGLDisplay dpy, EGLSync sync, EGLint flags);
-#endif /* EGL_VERSION_1_5 */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
+#ifndef __egl_h_
+#define __egl_h_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** Copyright (c) 2013-2014 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are 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 Materials.
+**
+** THE MATERIALS ARE 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
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+/*
+** This header is generated from the Khronos OpenGL / OpenGL ES XML
+** API Registry. The current version of the Registry, generator scripts
+** used to make the header, and the header can be found at
+** http://www.opengl.org/registry/
+**
+** Khronos $Revision: 27018 $ on $Date: 2014-06-10 08:06:12 -0700 (Tue, 10 Jun 2014) $
+*/
+
+#include <EGL/eglplatform.h>
+
+/* Generated on date 20140610 */
+
+/* Generated C header for:
+ * API: egl
+ * Versions considered: .*
+ * Versions emitted: .*
+ * Default extensions included: None
+ * Additional extensions included: _nomatch_^
+ * Extensions removed: _nomatch_^
+ */
+
+#ifndef EGL_VERSION_1_0
+#define EGL_VERSION_1_0 1
+typedef unsigned int EGLBoolean;
+typedef void *EGLDisplay;
+#include <KHR/khrplatform.h>
+#include <EGL/eglplatform.h>
+typedef void *EGLConfig;
+typedef void *EGLSurface;
+typedef void *EGLContext;
+typedef void (*__eglMustCastToProperFunctionPointerType)(void);
+#define EGL_ALPHA_SIZE 0x3021
+#define EGL_BAD_ACCESS 0x3002
+#define EGL_BAD_ALLOC 0x3003
+#define EGL_BAD_ATTRIBUTE 0x3004
+#define EGL_BAD_CONFIG 0x3005
+#define EGL_BAD_CONTEXT 0x3006
+#define EGL_BAD_CURRENT_SURFACE 0x3007
+#define EGL_BAD_DISPLAY 0x3008
+#define EGL_BAD_MATCH 0x3009
+#define EGL_BAD_NATIVE_PIXMAP 0x300A
+#define EGL_BAD_NATIVE_WINDOW 0x300B
+#define EGL_BAD_PARAMETER 0x300C
+#define EGL_BAD_SURFACE 0x300D
+#define EGL_BLUE_SIZE 0x3022
+#define EGL_BUFFER_SIZE 0x3020
+#define EGL_CONFIG_CAVEAT 0x3027
+#define EGL_CONFIG_ID 0x3028
+#define EGL_CORE_NATIVE_ENGINE 0x305B
+#define EGL_DEPTH_SIZE 0x3025
+#define EGL_DONT_CARE ((EGLint)-1)
+#define EGL_DRAW 0x3059
+#define EGL_EXTENSIONS 0x3055
+#define EGL_FALSE 0
+#define EGL_GREEN_SIZE 0x3023
+#define EGL_HEIGHT 0x3056
+#define EGL_LARGEST_PBUFFER 0x3058
+#define EGL_LEVEL 0x3029
+#define EGL_MAX_PBUFFER_HEIGHT 0x302A
+#define EGL_MAX_PBUFFER_PIXELS 0x302B
+#define EGL_MAX_PBUFFER_WIDTH 0x302C
+#define EGL_NATIVE_RENDERABLE 0x302D
+#define EGL_NATIVE_VISUAL_ID 0x302E
+#define EGL_NATIVE_VISUAL_TYPE 0x302F
+#define EGL_NONE 0x3038
+#define EGL_NON_CONFORMANT_CONFIG 0x3051
+#define EGL_NOT_INITIALIZED 0x3001
+#define EGL_NO_CONTEXT ((EGLContext)0)
+#define EGL_NO_DISPLAY ((EGLDisplay)0)
+#define EGL_NO_SURFACE ((EGLSurface)0)
+#define EGL_PBUFFER_BIT 0x0001
+#define EGL_PIXMAP_BIT 0x0002
+#define EGL_READ 0x305A
+#define EGL_RED_SIZE 0x3024
+#define EGL_SAMPLES 0x3031
+#define EGL_SAMPLE_BUFFERS 0x3032
+#define EGL_SLOW_CONFIG 0x3050
+#define EGL_STENCIL_SIZE 0x3026
+#define EGL_SUCCESS 0x3000
+#define EGL_SURFACE_TYPE 0x3033
+#define EGL_TRANSPARENT_BLUE_VALUE 0x3035
+#define EGL_TRANSPARENT_GREEN_VALUE 0x3036
+#define EGL_TRANSPARENT_RED_VALUE 0x3037
+#define EGL_TRANSPARENT_RGB 0x3052
+#define EGL_TRANSPARENT_TYPE 0x3034
+#define EGL_TRUE 1
+#define EGL_VENDOR 0x3053
+#define EGL_VERSION 0x3054
+#define EGL_WIDTH 0x3057
+#define EGL_WINDOW_BIT 0x0004
+EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig (EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
+EGLAPI EGLBoolean EGLAPIENTRY eglCopyBuffers (EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target);
+EGLAPI EGLContext EGLAPIENTRY eglCreateContext (EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferSurface (EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurface (EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface (EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext (EGLDisplay dpy, EGLContext ctx);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface (EGLDisplay dpy, EGLSurface surface);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib (EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs (EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);
+EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay (void);
+EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface (EGLint readdraw);
+EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay (EGLNativeDisplayType display_id);
+EGLAPI EGLint EGLAPIENTRY eglGetError (void);
+EGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddress (const char *procname);
+EGLAPI EGLBoolean EGLAPIENTRY eglInitialize (EGLDisplay dpy, EGLint *major, EGLint *minor);
+EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent (EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext (EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value);
+EGLAPI const char *EGLAPIENTRY eglQueryString (EGLDisplay dpy, EGLint name);
+EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value);
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers (EGLDisplay dpy, EGLSurface surface);
+EGLAPI EGLBoolean EGLAPIENTRY eglTerminate (EGLDisplay dpy);
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitGL (void);
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative (EGLint engine);
+#endif /* EGL_VERSION_1_0 */
+
+#ifndef EGL_VERSION_1_1
+#define EGL_VERSION_1_1 1
+#define EGL_BACK_BUFFER 0x3084
+#define EGL_BIND_TO_TEXTURE_RGB 0x3039
+#define EGL_BIND_TO_TEXTURE_RGBA 0x303A
+#define EGL_CONTEXT_LOST 0x300E
+#define EGL_MIN_SWAP_INTERVAL 0x303B
+#define EGL_MAX_SWAP_INTERVAL 0x303C
+#define EGL_MIPMAP_TEXTURE 0x3082
+#define EGL_MIPMAP_LEVEL 0x3083
+#define EGL_NO_TEXTURE 0x305C
+#define EGL_TEXTURE_2D 0x305F
+#define EGL_TEXTURE_FORMAT 0x3080
+#define EGL_TEXTURE_RGB 0x305D
+#define EGL_TEXTURE_RGBA 0x305E
+#define EGL_TEXTURE_TARGET 0x3081
+EGLAPI EGLBoolean EGLAPIENTRY eglBindTexImage (EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+EGLAPI EGLBoolean EGLAPIENTRY eglReleaseTexImage (EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+EGLAPI EGLBoolean EGLAPIENTRY eglSurfaceAttrib (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value);
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval (EGLDisplay dpy, EGLint interval);
+#endif /* EGL_VERSION_1_1 */
+
+#ifndef EGL_VERSION_1_2
+#define EGL_VERSION_1_2 1
+typedef unsigned int EGLenum;
+typedef void *EGLClientBuffer;
+#define EGL_ALPHA_FORMAT 0x3088
+#define EGL_ALPHA_FORMAT_NONPRE 0x308B
+#define EGL_ALPHA_FORMAT_PRE 0x308C
+#define EGL_ALPHA_MASK_SIZE 0x303E
+#define EGL_BUFFER_PRESERVED 0x3094
+#define EGL_BUFFER_DESTROYED 0x3095
+#define EGL_CLIENT_APIS 0x308D
+#define EGL_COLORSPACE 0x3087
+#define EGL_COLORSPACE_sRGB 0x3089
+#define EGL_COLORSPACE_LINEAR 0x308A
+#define EGL_COLOR_BUFFER_TYPE 0x303F
+#define EGL_CONTEXT_CLIENT_TYPE 0x3097
+#define EGL_DISPLAY_SCALING 10000
+#define EGL_HORIZONTAL_RESOLUTION 0x3090
+#define EGL_LUMINANCE_BUFFER 0x308F
+#define EGL_LUMINANCE_SIZE 0x303D
+#define EGL_OPENGL_ES_BIT 0x0001
+#define EGL_OPENVG_BIT 0x0002
+#define EGL_OPENGL_ES_API 0x30A0
+#define EGL_OPENVG_API 0x30A1
+#define EGL_OPENVG_IMAGE 0x3096
+#define EGL_PIXEL_ASPECT_RATIO 0x3092
+#define EGL_RENDERABLE_TYPE 0x3040
+#define EGL_RENDER_BUFFER 0x3086
+#define EGL_RGB_BUFFER 0x308E
+#define EGL_SINGLE_BUFFER 0x3085
+#define EGL_SWAP_BEHAVIOR 0x3093
+#define EGL_UNKNOWN ((EGLint)-1)
+#define EGL_VERTICAL_RESOLUTION 0x3091
+EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI (EGLenum api);
+EGLAPI EGLenum EGLAPIENTRY eglQueryAPI (void);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer (EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglReleaseThread (void);
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient (void);
+#endif /* EGL_VERSION_1_2 */
+
+#ifndef EGL_VERSION_1_3
+#define EGL_VERSION_1_3 1
+#define EGL_CONFORMANT 0x3042
+#define EGL_CONTEXT_CLIENT_VERSION 0x3098
+#define EGL_MATCH_NATIVE_PIXMAP 0x3041
+#define EGL_OPENGL_ES2_BIT 0x0004
+#define EGL_VG_ALPHA_FORMAT 0x3088
+#define EGL_VG_ALPHA_FORMAT_NONPRE 0x308B
+#define EGL_VG_ALPHA_FORMAT_PRE 0x308C
+#define EGL_VG_ALPHA_FORMAT_PRE_BIT 0x0040
+#define EGL_VG_COLORSPACE 0x3087
+#define EGL_VG_COLORSPACE_sRGB 0x3089
+#define EGL_VG_COLORSPACE_LINEAR 0x308A
+#define EGL_VG_COLORSPACE_LINEAR_BIT 0x0020
+#endif /* EGL_VERSION_1_3 */
+
+#ifndef EGL_VERSION_1_4
+#define EGL_VERSION_1_4 1
+#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0)
+#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200
+#define EGL_MULTISAMPLE_RESOLVE 0x3099
+#define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A
+#define EGL_MULTISAMPLE_RESOLVE_BOX 0x309B
+#define EGL_OPENGL_API 0x30A2
+#define EGL_OPENGL_BIT 0x0008
+#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400
+EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext (void);
+#endif /* EGL_VERSION_1_4 */
+
+#ifndef EGL_VERSION_1_5
+#define EGL_VERSION_1_5 1
+typedef void *EGLSync;
+typedef intptr_t EGLAttrib;
+typedef khronos_utime_nanoseconds_t EGLTime;
+#define EGL_CONTEXT_MAJOR_VERSION 0x3098
+#define EGL_CONTEXT_MINOR_VERSION 0x30FB
+#define EGL_CONTEXT_OPENGL_PROFILE_MASK 0x30FD
+#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY 0x31BD
+#define EGL_NO_RESET_NOTIFICATION 0x31BE
+#define EGL_LOSE_CONTEXT_ON_RESET 0x31BF
+#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT 0x00000001
+#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT 0x00000002
+#define EGL_CONTEXT_OPENGL_DEBUG 0x31B0
+#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE 0x31B1
+#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS 0x31B2
+#define EGL_OPENGL_ES3_BIT 0x00000040
+#define EGL_CL_EVENT_HANDLE 0x309C
+#define EGL_SYNC_CL_EVENT 0x30FE
+#define EGL_SYNC_CL_EVENT_COMPLETE 0x30FF
+#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE 0x30F0
+#define EGL_SYNC_TYPE 0x30F7
+#define EGL_SYNC_STATUS 0x30F1
+#define EGL_SYNC_CONDITION 0x30F8
+#define EGL_SIGNALED 0x30F2
+#define EGL_UNSIGNALED 0x30F3
+#define EGL_SYNC_FLUSH_COMMANDS_BIT 0x0001
+#define EGL_FOREVER 0xFFFFFFFFFFFFFFFFull
+#define EGL_TIMEOUT_EXPIRED 0x30F5
+#define EGL_CONDITION_SATISFIED 0x30F6
+#define EGL_NO_SYNC ((EGLSync)0)
+#define EGL_SYNC_FENCE 0x30F9
+#define EGL_GL_COLORSPACE 0x309D
+#define EGL_GL_COLORSPACE_SRGB 0x3089
+#define EGL_GL_COLORSPACE_LINEAR 0x308A
+#define EGL_GL_RENDERBUFFER 0x30B9
+#define EGL_GL_TEXTURE_2D 0x30B1
+#define EGL_GL_TEXTURE_LEVEL 0x30BC
+#define EGL_GL_TEXTURE_3D 0x30B2
+#define EGL_GL_TEXTURE_ZOFFSET 0x30BD
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x30B3
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x30B4
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x30B5
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x30B6
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x30B7
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x30B8
+EGLAPI EGLSync EGLAPIENTRY eglCreateSync (EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySync (EGLDisplay dpy, EGLSync sync);
+EGLAPI EGLint EGLAPIENTRY eglClientWaitSync (EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttrib (EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value);
+EGLAPI EGLDisplay EGLAPIENTRY eglGetPlatformDisplay (EGLenum platform, void *native_display, const EGLAttrib *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformWindowSurface (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformPixmapSurface (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitSync (EGLDisplay dpy, EGLSync sync, EGLint flags);
+#endif /* EGL_VERSION_1_5 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/platform/winrt/include/EGL/eglext.h b/platform/winrt/include/EGL/eglext.h
index 459ecf4a3d..05b2555f31 100644
--- a/platform/winrt/include/EGL/eglext.h
+++ b/platform/winrt/include/EGL/eglext.h
@@ -1,766 +1,766 @@
-#ifndef __eglext_h_
-#define __eglext_h_ 1
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
-** Copyright (c) 2013-2014 The Khronos Group Inc.
-**
-** Permission is hereby granted, free of charge, to any person obtaining a
-** copy of this software and/or associated documentation files (the
-** "Materials"), to deal in the Materials without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Materials, and to
-** permit persons to whom the Materials are 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 Materials.
-**
-** THE MATERIALS ARE 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
-** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-*/
-/*
-** This header is generated from the Khronos OpenGL / OpenGL ES XML
-** API Registry. The current version of the Registry, generator scripts
-** used to make the header, and the header can be found at
-** http://www.opengl.org/registry/
-**
-** Khronos $Revision: 27018 $ on $Date: 2014-06-10 08:06:12 -0700 (Tue, 10 Jun 2014) $
-*/
-
-#include <EGL/eglplatform.h>
-
-#define EGL_EGLEXT_VERSION 20140610
-
-/* Generated C header for:
- * API: egl
- * Versions considered: .*
- * Versions emitted: _nomatch_^
- * Default extensions included: egl
- * Additional extensions included: _nomatch_^
- * Extensions removed: _nomatch_^
- */
-
-#ifndef EGL_KHR_cl_event
-#define EGL_KHR_cl_event 1
-#define EGL_CL_EVENT_HANDLE_KHR 0x309C
-#define EGL_SYNC_CL_EVENT_KHR 0x30FE
-#define EGL_SYNC_CL_EVENT_COMPLETE_KHR 0x30FF
-#endif /* EGL_KHR_cl_event */
-
-#ifndef EGL_KHR_cl_event2
-#define EGL_KHR_cl_event2 1
-typedef void *EGLSyncKHR;
-typedef intptr_t EGLAttribKHR;
-typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESYNC64KHRPROC) (EGLDisplay dpy, EGLenum type, const EGLAttribKHR *attrib_list);
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSync64KHR (EGLDisplay dpy, EGLenum type, const EGLAttribKHR *attrib_list);
-#endif
-#endif /* EGL_KHR_cl_event2 */
-
-#ifndef EGL_KHR_client_get_all_proc_addresses
-#define EGL_KHR_client_get_all_proc_addresses 1
-#endif /* EGL_KHR_client_get_all_proc_addresses */
-
-#ifndef EGL_KHR_config_attribs
-#define EGL_KHR_config_attribs 1
-#define EGL_CONFORMANT_KHR 0x3042
-#define EGL_VG_COLORSPACE_LINEAR_BIT_KHR 0x0020
-#define EGL_VG_ALPHA_FORMAT_PRE_BIT_KHR 0x0040
-#endif /* EGL_KHR_config_attribs */
-
-#ifndef EGL_KHR_create_context
-#define EGL_KHR_create_context 1
-#define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098
-#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB
-#define EGL_CONTEXT_FLAGS_KHR 0x30FC
-#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD
-#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31BD
-#define EGL_NO_RESET_NOTIFICATION_KHR 0x31BE
-#define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31BF
-#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001
-#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002
-#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004
-#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001
-#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002
-#define EGL_OPENGL_ES3_BIT_KHR 0x00000040
-#endif /* EGL_KHR_create_context */
-
-#ifndef EGL_KHR_fence_sync
-#define EGL_KHR_fence_sync 1
-#ifdef KHRONOS_SUPPORT_INT64
-#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR 0x30F0
-#define EGL_SYNC_CONDITION_KHR 0x30F8
-#define EGL_SYNC_FENCE_KHR 0x30F9
-#endif /* KHRONOS_SUPPORT_INT64 */
-#endif /* EGL_KHR_fence_sync */
-
-#ifndef EGL_KHR_get_all_proc_addresses
-#define EGL_KHR_get_all_proc_addresses 1
-#endif /* EGL_KHR_get_all_proc_addresses */
-
-#ifndef EGL_KHR_gl_colorspace
-#define EGL_KHR_gl_colorspace 1
-#define EGL_GL_COLORSPACE_KHR 0x309D
-#define EGL_GL_COLORSPACE_SRGB_KHR 0x3089
-#define EGL_GL_COLORSPACE_LINEAR_KHR 0x308A
-#endif /* EGL_KHR_gl_colorspace */
-
-#ifndef EGL_KHR_gl_renderbuffer_image
-#define EGL_KHR_gl_renderbuffer_image 1
-#define EGL_GL_RENDERBUFFER_KHR 0x30B9
-#endif /* EGL_KHR_gl_renderbuffer_image */
-
-#ifndef EGL_KHR_gl_texture_2D_image
-#define EGL_KHR_gl_texture_2D_image 1
-#define EGL_GL_TEXTURE_2D_KHR 0x30B1
-#define EGL_GL_TEXTURE_LEVEL_KHR 0x30BC
-#endif /* EGL_KHR_gl_texture_2D_image */
-
-#ifndef EGL_KHR_gl_texture_3D_image
-#define EGL_KHR_gl_texture_3D_image 1
-#define EGL_GL_TEXTURE_3D_KHR 0x30B2
-#define EGL_GL_TEXTURE_ZOFFSET_KHR 0x30BD
-#endif /* EGL_KHR_gl_texture_3D_image */
-
-#ifndef EGL_KHR_gl_texture_cubemap_image
-#define EGL_KHR_gl_texture_cubemap_image 1
-#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR 0x30B3
-#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR 0x30B4
-#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR 0x30B5
-#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR 0x30B6
-#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR 0x30B7
-#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR 0x30B8
-#endif /* EGL_KHR_gl_texture_cubemap_image */
-
-#ifndef EGL_KHR_image
-#define EGL_KHR_image 1
-typedef void *EGLImageKHR;
-#define EGL_NATIVE_PIXMAP_KHR 0x30B0
-#define EGL_NO_IMAGE_KHR ((EGLImageKHR)0)
-typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGLImageKHR image);
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLImageKHR EGLAPIENTRY eglCreateImageKHR (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
-EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image);
-#endif
-#endif /* EGL_KHR_image */
-
-#ifndef EGL_KHR_image_base
-#define EGL_KHR_image_base 1
-#define EGL_IMAGE_PRESERVED_KHR 0x30D2
-#endif /* EGL_KHR_image_base */
-
-#ifndef EGL_KHR_image_pixmap
-#define EGL_KHR_image_pixmap 1
-#endif /* EGL_KHR_image_pixmap */
-
-#ifndef EGL_KHR_lock_surface
-#define EGL_KHR_lock_surface 1
-#define EGL_READ_SURFACE_BIT_KHR 0x0001
-#define EGL_WRITE_SURFACE_BIT_KHR 0x0002
-#define EGL_LOCK_SURFACE_BIT_KHR 0x0080
-#define EGL_OPTIMAL_FORMAT_BIT_KHR 0x0100
-#define EGL_MATCH_FORMAT_KHR 0x3043
-#define EGL_FORMAT_RGB_565_EXACT_KHR 0x30C0
-#define EGL_FORMAT_RGB_565_KHR 0x30C1
-#define EGL_FORMAT_RGBA_8888_EXACT_KHR 0x30C2
-#define EGL_FORMAT_RGBA_8888_KHR 0x30C3
-#define EGL_MAP_PRESERVE_PIXELS_KHR 0x30C4
-#define EGL_LOCK_USAGE_HINT_KHR 0x30C5
-#define EGL_BITMAP_POINTER_KHR 0x30C6
-#define EGL_BITMAP_PITCH_KHR 0x30C7
-#define EGL_BITMAP_ORIGIN_KHR 0x30C8
-#define EGL_BITMAP_PIXEL_RED_OFFSET_KHR 0x30C9
-#define EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR 0x30CA
-#define EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR 0x30CB
-#define EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR 0x30CC
-#define EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR 0x30CD
-#define EGL_LOWER_LEFT_KHR 0x30CE
-#define EGL_UPPER_LEFT_KHR 0x30CF
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLLOCKSURFACEKHRPROC) (EGLDisplay dpy, EGLSurface surface, const EGLint *attrib_list);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNLOCKSURFACEKHRPROC) (EGLDisplay dpy, EGLSurface surface);
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLBoolean EGLAPIENTRY eglLockSurfaceKHR (EGLDisplay dpy, EGLSurface surface, const EGLint *attrib_list);
-EGLAPI EGLBoolean EGLAPIENTRY eglUnlockSurfaceKHR (EGLDisplay dpy, EGLSurface surface);
-#endif
-#endif /* EGL_KHR_lock_surface */
-
-#ifndef EGL_KHR_lock_surface2
-#define EGL_KHR_lock_surface2 1
-#define EGL_BITMAP_PIXEL_SIZE_KHR 0x3110
-#endif /* EGL_KHR_lock_surface2 */
-
-#ifndef EGL_KHR_lock_surface3
-#define EGL_KHR_lock_surface3 1
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSURFACE64KHRPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLAttribKHR *value);
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface64KHR (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLAttribKHR *value);
-#endif
-#endif /* EGL_KHR_lock_surface3 */
-
-#ifndef EGL_KHR_platform_android
-#define EGL_KHR_platform_android 1
-#define EGL_PLATFORM_ANDROID_KHR 0x3141
-#endif /* EGL_KHR_platform_android */
-
-#ifndef EGL_KHR_platform_gbm
-#define EGL_KHR_platform_gbm 1
-#define EGL_PLATFORM_GBM_KHR 0x31D7
-#endif /* EGL_KHR_platform_gbm */
-
-#ifndef EGL_KHR_platform_wayland
-#define EGL_KHR_platform_wayland 1
-#define EGL_PLATFORM_WAYLAND_KHR 0x31D8
-#endif /* EGL_KHR_platform_wayland */
-
-#ifndef EGL_KHR_platform_x11
-#define EGL_KHR_platform_x11 1
-#define EGL_PLATFORM_X11_KHR 0x31D5
-#define EGL_PLATFORM_X11_SCREEN_KHR 0x31D6
-#endif /* EGL_KHR_platform_x11 */
-
-#ifndef EGL_KHR_reusable_sync
-#define EGL_KHR_reusable_sync 1
-typedef khronos_utime_nanoseconds_t EGLTimeKHR;
-#ifdef KHRONOS_SUPPORT_INT64
-#define EGL_SYNC_STATUS_KHR 0x30F1
-#define EGL_SIGNALED_KHR 0x30F2
-#define EGL_UNSIGNALED_KHR 0x30F3
-#define EGL_TIMEOUT_EXPIRED_KHR 0x30F5
-#define EGL_CONDITION_SATISFIED_KHR 0x30F6
-#define EGL_SYNC_TYPE_KHR 0x30F7
-#define EGL_SYNC_REUSABLE_KHR 0x30FA
-#define EGL_SYNC_FLUSH_COMMANDS_BIT_KHR 0x0001
-#define EGL_FOREVER_KHR 0xFFFFFFFFFFFFFFFFull
-#define EGL_NO_SYNC_KHR ((EGLSyncKHR)0)
-typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESYNCKHRPROC) (EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync);
-typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value);
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSyncKHR (EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);
-EGLAPI EGLBoolean EGLAPIENTRY eglDestroySyncKHR (EGLDisplay dpy, EGLSyncKHR sync);
-EGLAPI EGLint EGLAPIENTRY eglClientWaitSyncKHR (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout);
-EGLAPI EGLBoolean EGLAPIENTRY eglSignalSyncKHR (EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode);
-EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttribKHR (EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value);
-#endif
-#endif /* KHRONOS_SUPPORT_INT64 */
-#endif /* EGL_KHR_reusable_sync */
-
-#ifndef EGL_KHR_stream
-#define EGL_KHR_stream 1
-typedef void *EGLStreamKHR;
-typedef khronos_uint64_t EGLuint64KHR;
-#ifdef KHRONOS_SUPPORT_INT64
-#define EGL_NO_STREAM_KHR ((EGLStreamKHR)0)
-#define EGL_CONSUMER_LATENCY_USEC_KHR 0x3210
-#define EGL_PRODUCER_FRAME_KHR 0x3212
-#define EGL_CONSUMER_FRAME_KHR 0x3213
-#define EGL_STREAM_STATE_KHR 0x3214
-#define EGL_STREAM_STATE_CREATED_KHR 0x3215
-#define EGL_STREAM_STATE_CONNECTING_KHR 0x3216
-#define EGL_STREAM_STATE_EMPTY_KHR 0x3217
-#define EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR 0x3218
-#define EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR 0x3219
-#define EGL_STREAM_STATE_DISCONNECTED_KHR 0x321A
-#define EGL_BAD_STREAM_KHR 0x321B
-#define EGL_BAD_STATE_KHR 0x321C
-typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMKHRPROC) (EGLDisplay dpy, const EGLint *attrib_list);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSTREAMKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint value);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint *value);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMU64KHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLuint64KHR *value);
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamKHR (EGLDisplay dpy, const EGLint *attrib_list);
-EGLAPI EGLBoolean EGLAPIENTRY eglDestroyStreamKHR (EGLDisplay dpy, EGLStreamKHR stream);
-EGLAPI EGLBoolean EGLAPIENTRY eglStreamAttribKHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint value);
-EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamKHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint *value);
-EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamu64KHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLuint64KHR *value);
-#endif
-#endif /* KHRONOS_SUPPORT_INT64 */
-#endif /* EGL_KHR_stream */
-
-#ifndef EGL_KHR_stream_consumer_gltexture
-#define EGL_KHR_stream_consumer_gltexture 1
-#ifdef EGL_KHR_stream
-#define EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR 0x321E
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERACQUIREKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERRELEASEKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerGLTextureExternalKHR (EGLDisplay dpy, EGLStreamKHR stream);
-EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerAcquireKHR (EGLDisplay dpy, EGLStreamKHR stream);
-EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerReleaseKHR (EGLDisplay dpy, EGLStreamKHR stream);
-#endif
-#endif /* EGL_KHR_stream */
-#endif /* EGL_KHR_stream_consumer_gltexture */
-
-#ifndef EGL_KHR_stream_cross_process_fd
-#define EGL_KHR_stream_cross_process_fd 1
-typedef int EGLNativeFileDescriptorKHR;
-#ifdef EGL_KHR_stream
-#define EGL_NO_FILE_DESCRIPTOR_KHR ((EGLNativeFileDescriptorKHR)(-1))
-typedef EGLNativeFileDescriptorKHR (EGLAPIENTRYP PFNEGLGETSTREAMFILEDESCRIPTORKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
-typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC) (EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor);
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLNativeFileDescriptorKHR EGLAPIENTRY eglGetStreamFileDescriptorKHR (EGLDisplay dpy, EGLStreamKHR stream);
-EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamFromFileDescriptorKHR (EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor);
-#endif
-#endif /* EGL_KHR_stream */
-#endif /* EGL_KHR_stream_cross_process_fd */
-
-#ifndef EGL_KHR_stream_fifo
-#define EGL_KHR_stream_fifo 1
-#ifdef EGL_KHR_stream
-#define EGL_STREAM_FIFO_LENGTH_KHR 0x31FC
-#define EGL_STREAM_TIME_NOW_KHR 0x31FD
-#define EGL_STREAM_TIME_CONSUMER_KHR 0x31FE
-#define EGL_STREAM_TIME_PRODUCER_KHR 0x31FF
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMTIMEKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLTimeKHR *value);
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamTimeKHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLTimeKHR *value);
-#endif
-#endif /* EGL_KHR_stream */
-#endif /* EGL_KHR_stream_fifo */
-
-#ifndef EGL_KHR_stream_producer_aldatalocator
-#define EGL_KHR_stream_producer_aldatalocator 1
-#ifdef EGL_KHR_stream
-#endif /* EGL_KHR_stream */
-#endif /* EGL_KHR_stream_producer_aldatalocator */
-
-#ifndef EGL_KHR_stream_producer_eglsurface
-#define EGL_KHR_stream_producer_eglsurface 1
-#ifdef EGL_KHR_stream
-#define EGL_STREAM_BIT_KHR 0x0800
-typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC) (EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint *attrib_list);
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLSurface EGLAPIENTRY eglCreateStreamProducerSurfaceKHR (EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint *attrib_list);
-#endif
-#endif /* EGL_KHR_stream */
-#endif /* EGL_KHR_stream_producer_eglsurface */
-
-#ifndef EGL_KHR_surfaceless_context
-#define EGL_KHR_surfaceless_context 1
-#endif /* EGL_KHR_surfaceless_context */
-
-#ifndef EGL_KHR_vg_parent_image
-#define EGL_KHR_vg_parent_image 1
-#define EGL_VG_PARENT_IMAGE_KHR 0x30BA
-#endif /* EGL_KHR_vg_parent_image */
-
-#ifndef EGL_KHR_wait_sync
-#define EGL_KHR_wait_sync 1
-typedef EGLint (EGLAPIENTRYP PFNEGLWAITSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags);
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLint EGLAPIENTRY eglWaitSyncKHR (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags);
-#endif
-#endif /* EGL_KHR_wait_sync */
-
-#ifndef EGL_ANDROID_blob_cache
-#define EGL_ANDROID_blob_cache 1
-typedef khronos_ssize_t EGLsizeiANDROID;
-typedef void (*EGLSetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, const void *value, EGLsizeiANDROID valueSize);
-typedef EGLsizeiANDROID (*EGLGetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, void *value, EGLsizeiANDROID valueSize);
-typedef void (EGLAPIENTRYP PFNEGLSETBLOBCACHEFUNCSANDROIDPROC) (EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get);
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI void EGLAPIENTRY eglSetBlobCacheFuncsANDROID (EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get);
-#endif
-#endif /* EGL_ANDROID_blob_cache */
-
-#ifndef EGL_ANDROID_framebuffer_target
-#define EGL_ANDROID_framebuffer_target 1
-#define EGL_FRAMEBUFFER_TARGET_ANDROID 0x3147
-#endif /* EGL_ANDROID_framebuffer_target */
-
-#ifndef EGL_ANDROID_image_native_buffer
-#define EGL_ANDROID_image_native_buffer 1
-#define EGL_NATIVE_BUFFER_ANDROID 0x3140
-#endif /* EGL_ANDROID_image_native_buffer */
-
-#ifndef EGL_ANDROID_native_fence_sync
-#define EGL_ANDROID_native_fence_sync 1
-#define EGL_SYNC_NATIVE_FENCE_ANDROID 0x3144
-#define EGL_SYNC_NATIVE_FENCE_FD_ANDROID 0x3145
-#define EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID 0x3146
-#define EGL_NO_NATIVE_FENCE_FD_ANDROID -1
-typedef EGLint (EGLAPIENTRYP PFNEGLDUPNATIVEFENCEFDANDROIDPROC) (EGLDisplay dpy, EGLSyncKHR sync);
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLint EGLAPIENTRY eglDupNativeFenceFDANDROID (EGLDisplay dpy, EGLSyncKHR sync);
-#endif
-#endif /* EGL_ANDROID_native_fence_sync */
-
-#ifndef EGL_ANDROID_recordable
-#define EGL_ANDROID_recordable 1
-#define EGL_RECORDABLE_ANDROID 0x3142
-#endif /* EGL_ANDROID_recordable */
-
-#ifndef EGL_ANGLE_d3d_share_handle_client_buffer
-#define EGL_ANGLE_d3d_share_handle_client_buffer 1
-#define EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE 0x3200
-#endif /* EGL_ANGLE_d3d_share_handle_client_buffer */
-
-#ifndef EGL_ANGLE_window_fixed_size
-#define EGL_ANGLE_window_fixed_size 1
-#define EGL_FIXED_SIZE_ANGLE 0x3201
-#endif /* EGL_ANGLE_window_fixed_size */
-
-#ifndef EGL_ANGLE_query_surface_pointer
-#define EGL_ANGLE_query_surface_pointer 1
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSURFACEPOINTERANGLEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value);
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurfacePointerANGLE (EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value);
-#endif
-#endif /* EGL_ANGLE_query_surface_pointer */
-
-#ifndef EGL_ANGLE_software_display
-#define EGL_ANGLE_software_display 1
-#define EGL_SOFTWARE_DISPLAY_ANGLE ((EGLNativeDisplayType)-1)
-#endif /* EGL_ANGLE_software_display */
-
-#ifndef EGL_ANGLE_direct3d_display
-#define EGL_ANGLE_direct3d_display 1
-#define EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE ((EGLNativeDisplayType)-2)
-#define EGL_D3D11_ONLY_DISPLAY_ANGLE ((EGLNativeDisplayType)-3)
-#endif /* EGL_ANGLE_direct3d_display */
-
-#ifndef EGL_ANGLE_surface_d3d_texture_2d_share_handle
-#define EGL_ANGLE_surface_d3d_texture_2d_share_handle 1
-#endif /* EGL_ANGLE_surface_d3d_texture_2d_share_handle */
-
-#ifndef EGL_ANGLE_surface_d3d_render_to_back_buffer
-#define EGL_ANGLE_surface_d3d_render_to_back_buffer 1
-#define EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER 0x320B
-#define EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER 0x320C
-#endif /* EGL_ANGLE_surface_d3d_render_to_back_buffer */
-
-#ifndef EGL_ANGLE_platform_angle
-#define EGL_ANGLE_platform_angle 1
-#define EGL_PLATFORM_ANGLE_ANGLE 0x3201
-#define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3202
-#define EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE 0x3203
-#define EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE 0x3204
-#define EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE 0x3205
-#endif /* EGL_ANGLE_platform_angle */
-
-#ifndef EGL_ANGLE_platform_angle_d3d
-#define EGL_ANGLE_platform_angle_d3d 1
-#define EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE 0x3206
-#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3207
-#define EGL_PLATFORM_ANGLE_USE_WARP_ANGLE 0x3208
-#endif /* EGL_ANGLE_platform_angle_d3d */
-
-#ifndef EGL_ANGLE_platform_angle_opengl
-#define EGL_ANGLE_platform_angle_opengl 1
-#define EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE 0x3209
-#define EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE 0x320A
-#endif /* EGL_ANGLE_platform_angle_opengl */
-
-#ifndef EGL_ARM_pixmap_multisample_discard
-#define EGL_ARM_pixmap_multisample_discard 1
-#define EGL_DISCARD_SAMPLES_ARM 0x3286
-#endif /* EGL_ARM_pixmap_multisample_discard */
-
-#ifndef EGL_EXT_buffer_age
-#define EGL_EXT_buffer_age 1
-#define EGL_BUFFER_AGE_EXT 0x313D
-#endif /* EGL_EXT_buffer_age */
-
-#ifndef EGL_EXT_client_extensions
-#define EGL_EXT_client_extensions 1
-#endif /* EGL_EXT_client_extensions */
-
-#ifndef EGL_EXT_create_context_robustness
-#define EGL_EXT_create_context_robustness 1
-#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT 0x30BF
-#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT 0x3138
-#define EGL_NO_RESET_NOTIFICATION_EXT 0x31BE
-#define EGL_LOSE_CONTEXT_ON_RESET_EXT 0x31BF
-#endif /* EGL_EXT_create_context_robustness */
-
-#ifndef EGL_EXT_device_base
-#define EGL_EXT_device_base 1
-typedef void *EGLDeviceEXT;
-#define EGL_NO_DEVICE_EXT ((EGLDeviceEXT)(0))
-#define EGL_BAD_DEVICE_EXT 0x322B
-#define EGL_DEVICE_EXT 0x322C
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDEVICEATTRIBEXTPROC) (EGLDeviceEXT device, EGLint attribute, EGLAttrib *value);
-typedef const char *(EGLAPIENTRYP PFNEGLQUERYDEVICESTRINGEXTPROC) (EGLDeviceEXT device, EGLint name);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDEVICESEXTPROC) (EGLint max_devices, EGLDeviceEXT *devices, EGLint *num_devices);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDISPLAYATTRIBEXTPROC) (EGLDisplay dpy, EGLint attribute, EGLAttrib *value);
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLBoolean EGLAPIENTRY eglQueryDeviceAttribEXT (EGLDeviceEXT device, EGLint attribute, EGLAttrib *value);
-EGLAPI const char *EGLAPIENTRY eglQueryDeviceStringEXT (EGLDeviceEXT device, EGLint name);
-EGLAPI EGLBoolean EGLAPIENTRY eglQueryDevicesEXT (EGLint max_devices, EGLDeviceEXT *devices, EGLint *num_devices);
-EGLAPI EGLBoolean EGLAPIENTRY eglQueryDisplayAttribEXT (EGLDisplay dpy, EGLint attribute, EGLAttrib *value);
-#endif
-#endif /* EGL_EXT_device_base */
-
-#ifndef EGL_EXT_image_dma_buf_import
-#define EGL_EXT_image_dma_buf_import 1
-#define EGL_LINUX_DMA_BUF_EXT 0x3270
-#define EGL_LINUX_DRM_FOURCC_EXT 0x3271
-#define EGL_DMA_BUF_PLANE0_FD_EXT 0x3272
-#define EGL_DMA_BUF_PLANE0_OFFSET_EXT 0x3273
-#define EGL_DMA_BUF_PLANE0_PITCH_EXT 0x3274
-#define EGL_DMA_BUF_PLANE1_FD_EXT 0x3275
-#define EGL_DMA_BUF_PLANE1_OFFSET_EXT 0x3276
-#define EGL_DMA_BUF_PLANE1_PITCH_EXT 0x3277
-#define EGL_DMA_BUF_PLANE2_FD_EXT 0x3278
-#define EGL_DMA_BUF_PLANE2_OFFSET_EXT 0x3279
-#define EGL_DMA_BUF_PLANE2_PITCH_EXT 0x327A
-#define EGL_YUV_COLOR_SPACE_HINT_EXT 0x327B
-#define EGL_SAMPLE_RANGE_HINT_EXT 0x327C
-#define EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT 0x327D
-#define EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT 0x327E
-#define EGL_ITU_REC601_EXT 0x327F
-#define EGL_ITU_REC709_EXT 0x3280
-#define EGL_ITU_REC2020_EXT 0x3281
-#define EGL_YUV_FULL_RANGE_EXT 0x3282
-#define EGL_YUV_NARROW_RANGE_EXT 0x3283
-#define EGL_YUV_CHROMA_SITING_0_EXT 0x3284
-#define EGL_YUV_CHROMA_SITING_0_5_EXT 0x3285
-#endif /* EGL_EXT_image_dma_buf_import */
-
-#ifndef EGL_EXT_multiview_window
-#define EGL_EXT_multiview_window 1
-#define EGL_MULTIVIEW_VIEW_COUNT_EXT 0x3134
-#endif /* EGL_EXT_multiview_window */
-
-#ifndef EGL_EXT_platform_base
-#define EGL_EXT_platform_base 1
-typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void *native_display, const EGLint *attrib_list);
-typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list);
-typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLint *attrib_list);
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLDisplay EGLAPIENTRY eglGetPlatformDisplayEXT (EGLenum platform, void *native_display, const EGLint *attrib_list);
-EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformWindowSurfaceEXT (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list);
-EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformPixmapSurfaceEXT (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLint *attrib_list);
-#endif
-#endif /* EGL_EXT_platform_base */
-
-#ifndef EGL_EXT_platform_device
-#define EGL_EXT_platform_device 1
-#define EGL_PLATFORM_DEVICE_EXT 0x313F
-#endif /* EGL_EXT_platform_device */
-
-#ifndef EGL_EXT_platform_wayland
-#define EGL_EXT_platform_wayland 1
-#define EGL_PLATFORM_WAYLAND_EXT 0x31D8
-#endif /* EGL_EXT_platform_wayland */
-
-#ifndef EGL_EXT_platform_x11
-#define EGL_EXT_platform_x11 1
-#define EGL_PLATFORM_X11_EXT 0x31D5
-#define EGL_PLATFORM_X11_SCREEN_EXT 0x31D6
-#endif /* EGL_EXT_platform_x11 */
-
-#ifndef EGL_EXT_protected_surface
-#define EGL_EXT_protected_surface 1
-#define EGL_PROTECTED_CONTENT_EXT 0x32C0
-#endif /* EGL_EXT_protected_surface */
-
-#ifndef EGL_EXT_swap_buffers_with_damage
-#define EGL_EXT_swap_buffers_with_damage 1
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC) (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersWithDamageEXT (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
-#endif
-#endif /* EGL_EXT_swap_buffers_with_damage */
-
-#ifndef EGL_HI_clientpixmap
-#define EGL_HI_clientpixmap 1
-struct EGLClientPixmapHI {
- void *pData;
- EGLint iWidth;
- EGLint iHeight;
- EGLint iStride;
-};
-#define EGL_CLIENT_PIXMAP_POINTER_HI 0x8F74
-typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPIXMAPSURFACEHIPROC) (EGLDisplay dpy, EGLConfig config, struct EGLClientPixmapHI *pixmap);
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurfaceHI (EGLDisplay dpy, EGLConfig config, struct EGLClientPixmapHI *pixmap);
-#endif
-#endif /* EGL_HI_clientpixmap */
-
-#ifndef EGL_HI_colorformats
-#define EGL_HI_colorformats 1
-#define EGL_COLOR_FORMAT_HI 0x8F70
-#define EGL_COLOR_RGB_HI 0x8F71
-#define EGL_COLOR_RGBA_HI 0x8F72
-#define EGL_COLOR_ARGB_HI 0x8F73
-#endif /* EGL_HI_colorformats */
-
-#ifndef EGL_IMG_context_priority
-#define EGL_IMG_context_priority 1
-#define EGL_CONTEXT_PRIORITY_LEVEL_IMG 0x3100
-#define EGL_CONTEXT_PRIORITY_HIGH_IMG 0x3101
-#define EGL_CONTEXT_PRIORITY_MEDIUM_IMG 0x3102
-#define EGL_CONTEXT_PRIORITY_LOW_IMG 0x3103
-#endif /* EGL_IMG_context_priority */
-
-#ifndef EGL_MESA_drm_image
-#define EGL_MESA_drm_image 1
-#define EGL_DRM_BUFFER_FORMAT_MESA 0x31D0
-#define EGL_DRM_BUFFER_USE_MESA 0x31D1
-#define EGL_DRM_BUFFER_FORMAT_ARGB32_MESA 0x31D2
-#define EGL_DRM_BUFFER_MESA 0x31D3
-#define EGL_DRM_BUFFER_STRIDE_MESA 0x31D4
-#define EGL_DRM_BUFFER_USE_SCANOUT_MESA 0x00000001
-#define EGL_DRM_BUFFER_USE_SHARE_MESA 0x00000002
-typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEDRMIMAGEMESAPROC) (EGLDisplay dpy, const EGLint *attrib_list);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLEXPORTDRMIMAGEMESAPROC) (EGLDisplay dpy, EGLImageKHR image, EGLint *name, EGLint *handle, EGLint *stride);
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLImageKHR EGLAPIENTRY eglCreateDRMImageMESA (EGLDisplay dpy, const EGLint *attrib_list);
-EGLAPI EGLBoolean EGLAPIENTRY eglExportDRMImageMESA (EGLDisplay dpy, EGLImageKHR image, EGLint *name, EGLint *handle, EGLint *stride);
-#endif
-#endif /* EGL_MESA_drm_image */
-
-#ifndef EGL_MESA_platform_gbm
-#define EGL_MESA_platform_gbm 1
-#define EGL_PLATFORM_GBM_MESA 0x31D7
-#endif /* EGL_MESA_platform_gbm */
-
-#ifndef EGL_NOK_swap_region
-#define EGL_NOK_swap_region 1
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSREGIONNOKPROC) (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects);
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersRegionNOK (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects);
-#endif
-#endif /* EGL_NOK_swap_region */
-
-#ifndef EGL_NOK_swap_region2
-#define EGL_NOK_swap_region2 1
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSREGION2NOKPROC) (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects);
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersRegion2NOK (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects);
-#endif
-#endif /* EGL_NOK_swap_region2 */
-
-#ifndef EGL_NOK_texture_from_pixmap
-#define EGL_NOK_texture_from_pixmap 1
-#define EGL_Y_INVERTED_NOK 0x307F
-#endif /* EGL_NOK_texture_from_pixmap */
-
-#ifndef EGL_NV_3dvision_surface
-#define EGL_NV_3dvision_surface 1
-#define EGL_AUTO_STEREO_NV 0x3136
-#endif /* EGL_NV_3dvision_surface */
-
-#ifndef EGL_NV_coverage_sample
-#define EGL_NV_coverage_sample 1
-#define EGL_COVERAGE_BUFFERS_NV 0x30E0
-#define EGL_COVERAGE_SAMPLES_NV 0x30E1
-#endif /* EGL_NV_coverage_sample */
-
-#ifndef EGL_NV_coverage_sample_resolve
-#define EGL_NV_coverage_sample_resolve 1
-#define EGL_COVERAGE_SAMPLE_RESOLVE_NV 0x3131
-#define EGL_COVERAGE_SAMPLE_RESOLVE_DEFAULT_NV 0x3132
-#define EGL_COVERAGE_SAMPLE_RESOLVE_NONE_NV 0x3133
-#endif /* EGL_NV_coverage_sample_resolve */
-
-#ifndef EGL_NV_depth_nonlinear
-#define EGL_NV_depth_nonlinear 1
-#define EGL_DEPTH_ENCODING_NV 0x30E2
-#define EGL_DEPTH_ENCODING_NONE_NV 0
-#define EGL_DEPTH_ENCODING_NONLINEAR_NV 0x30E3
-#endif /* EGL_NV_depth_nonlinear */
-
-#ifndef EGL_NV_native_query
-#define EGL_NV_native_query 1
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEDISPLAYNVPROC) (EGLDisplay dpy, EGLNativeDisplayType *display_id);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEWINDOWNVPROC) (EGLDisplay dpy, EGLSurface surf, EGLNativeWindowType *window);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEPIXMAPNVPROC) (EGLDisplay dpy, EGLSurface surf, EGLNativePixmapType *pixmap);
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLBoolean EGLAPIENTRY eglQueryNativeDisplayNV (EGLDisplay dpy, EGLNativeDisplayType *display_id);
-EGLAPI EGLBoolean EGLAPIENTRY eglQueryNativeWindowNV (EGLDisplay dpy, EGLSurface surf, EGLNativeWindowType *window);
-EGLAPI EGLBoolean EGLAPIENTRY eglQueryNativePixmapNV (EGLDisplay dpy, EGLSurface surf, EGLNativePixmapType *pixmap);
-#endif
-#endif /* EGL_NV_native_query */
-
-#ifndef EGL_NV_post_convert_rounding
-#define EGL_NV_post_convert_rounding 1
-#endif /* EGL_NV_post_convert_rounding */
-
-#ifndef EGL_NV_post_sub_buffer
-#define EGL_NV_post_sub_buffer 1
-#define EGL_POST_SUB_BUFFER_SUPPORTED_NV 0x30BE
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLPOSTSUBBUFFERNVPROC) (EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height);
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLBoolean EGLAPIENTRY eglPostSubBufferNV (EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height);
-#endif
-#endif /* EGL_NV_post_sub_buffer */
-
-#ifndef EGL_NV_stream_sync
-#define EGL_NV_stream_sync 1
-#define EGL_SYNC_NEW_FRAME_NV 0x321F
-typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESTREAMSYNCNVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum type, const EGLint *attrib_list);
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateStreamSyncNV (EGLDisplay dpy, EGLStreamKHR stream, EGLenum type, const EGLint *attrib_list);
-#endif
-#endif /* EGL_NV_stream_sync */
-
-#ifndef EGL_NV_sync
-#define EGL_NV_sync 1
-typedef void *EGLSyncNV;
-typedef khronos_utime_nanoseconds_t EGLTimeNV;
-#ifdef KHRONOS_SUPPORT_INT64
-#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_NV 0x30E6
-#define EGL_SYNC_STATUS_NV 0x30E7
-#define EGL_SIGNALED_NV 0x30E8
-#define EGL_UNSIGNALED_NV 0x30E9
-#define EGL_SYNC_FLUSH_COMMANDS_BIT_NV 0x0001
-#define EGL_FOREVER_NV 0xFFFFFFFFFFFFFFFFull
-#define EGL_ALREADY_SIGNALED_NV 0x30EA
-#define EGL_TIMEOUT_EXPIRED_NV 0x30EB
-#define EGL_CONDITION_SATISFIED_NV 0x30EC
-#define EGL_SYNC_TYPE_NV 0x30ED
-#define EGL_SYNC_CONDITION_NV 0x30EE
-#define EGL_SYNC_FENCE_NV 0x30EF
-#define EGL_NO_SYNC_NV ((EGLSyncNV)0)
-typedef EGLSyncNV (EGLAPIENTRYP PFNEGLCREATEFENCESYNCNVPROC) (EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCNVPROC) (EGLSyncNV sync);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLFENCENVPROC) (EGLSyncNV sync);
-typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCNVPROC) (EGLSyncNV sync, EGLint flags, EGLTimeNV timeout);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCNVPROC) (EGLSyncNV sync, EGLenum mode);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBNVPROC) (EGLSyncNV sync, EGLint attribute, EGLint *value);
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLSyncNV EGLAPIENTRY eglCreateFenceSyncNV (EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list);
-EGLAPI EGLBoolean EGLAPIENTRY eglDestroySyncNV (EGLSyncNV sync);
-EGLAPI EGLBoolean EGLAPIENTRY eglFenceNV (EGLSyncNV sync);
-EGLAPI EGLint EGLAPIENTRY eglClientWaitSyncNV (EGLSyncNV sync, EGLint flags, EGLTimeNV timeout);
-EGLAPI EGLBoolean EGLAPIENTRY eglSignalSyncNV (EGLSyncNV sync, EGLenum mode);
-EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttribNV (EGLSyncNV sync, EGLint attribute, EGLint *value);
-#endif
-#endif /* KHRONOS_SUPPORT_INT64 */
-#endif /* EGL_NV_sync */
-
-#ifndef EGL_NV_system_time
-#define EGL_NV_system_time 1
-typedef khronos_utime_nanoseconds_t EGLuint64NV;
-#ifdef KHRONOS_SUPPORT_INT64
-typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC) (void);
-typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMENVPROC) (void);
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeFrequencyNV (void);
-EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeNV (void);
-#endif
-#endif /* KHRONOS_SUPPORT_INT64 */
-#endif /* EGL_NV_system_time */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
+#ifndef __eglext_h_
+#define __eglext_h_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** Copyright (c) 2013-2014 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are 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 Materials.
+**
+** THE MATERIALS ARE 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
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+/*
+** This header is generated from the Khronos OpenGL / OpenGL ES XML
+** API Registry. The current version of the Registry, generator scripts
+** used to make the header, and the header can be found at
+** http://www.opengl.org/registry/
+**
+** Khronos $Revision: 27018 $ on $Date: 2014-06-10 08:06:12 -0700 (Tue, 10 Jun 2014) $
+*/
+
+#include <EGL/eglplatform.h>
+
+#define EGL_EGLEXT_VERSION 20140610
+
+/* Generated C header for:
+ * API: egl
+ * Versions considered: .*
+ * Versions emitted: _nomatch_^
+ * Default extensions included: egl
+ * Additional extensions included: _nomatch_^
+ * Extensions removed: _nomatch_^
+ */
+
+#ifndef EGL_KHR_cl_event
+#define EGL_KHR_cl_event 1
+#define EGL_CL_EVENT_HANDLE_KHR 0x309C
+#define EGL_SYNC_CL_EVENT_KHR 0x30FE
+#define EGL_SYNC_CL_EVENT_COMPLETE_KHR 0x30FF
+#endif /* EGL_KHR_cl_event */
+
+#ifndef EGL_KHR_cl_event2
+#define EGL_KHR_cl_event2 1
+typedef void *EGLSyncKHR;
+typedef intptr_t EGLAttribKHR;
+typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESYNC64KHRPROC) (EGLDisplay dpy, EGLenum type, const EGLAttribKHR *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSync64KHR (EGLDisplay dpy, EGLenum type, const EGLAttribKHR *attrib_list);
+#endif
+#endif /* EGL_KHR_cl_event2 */
+
+#ifndef EGL_KHR_client_get_all_proc_addresses
+#define EGL_KHR_client_get_all_proc_addresses 1
+#endif /* EGL_KHR_client_get_all_proc_addresses */
+
+#ifndef EGL_KHR_config_attribs
+#define EGL_KHR_config_attribs 1
+#define EGL_CONFORMANT_KHR 0x3042
+#define EGL_VG_COLORSPACE_LINEAR_BIT_KHR 0x0020
+#define EGL_VG_ALPHA_FORMAT_PRE_BIT_KHR 0x0040
+#endif /* EGL_KHR_config_attribs */
+
+#ifndef EGL_KHR_create_context
+#define EGL_KHR_create_context 1
+#define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098
+#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB
+#define EGL_CONTEXT_FLAGS_KHR 0x30FC
+#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD
+#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31BD
+#define EGL_NO_RESET_NOTIFICATION_KHR 0x31BE
+#define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31BF
+#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001
+#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002
+#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004
+#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001
+#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002
+#define EGL_OPENGL_ES3_BIT_KHR 0x00000040
+#endif /* EGL_KHR_create_context */
+
+#ifndef EGL_KHR_fence_sync
+#define EGL_KHR_fence_sync 1
+#ifdef KHRONOS_SUPPORT_INT64
+#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR 0x30F0
+#define EGL_SYNC_CONDITION_KHR 0x30F8
+#define EGL_SYNC_FENCE_KHR 0x30F9
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_KHR_fence_sync */
+
+#ifndef EGL_KHR_get_all_proc_addresses
+#define EGL_KHR_get_all_proc_addresses 1
+#endif /* EGL_KHR_get_all_proc_addresses */
+
+#ifndef EGL_KHR_gl_colorspace
+#define EGL_KHR_gl_colorspace 1
+#define EGL_GL_COLORSPACE_KHR 0x309D
+#define EGL_GL_COLORSPACE_SRGB_KHR 0x3089
+#define EGL_GL_COLORSPACE_LINEAR_KHR 0x308A
+#endif /* EGL_KHR_gl_colorspace */
+
+#ifndef EGL_KHR_gl_renderbuffer_image
+#define EGL_KHR_gl_renderbuffer_image 1
+#define EGL_GL_RENDERBUFFER_KHR 0x30B9
+#endif /* EGL_KHR_gl_renderbuffer_image */
+
+#ifndef EGL_KHR_gl_texture_2D_image
+#define EGL_KHR_gl_texture_2D_image 1
+#define EGL_GL_TEXTURE_2D_KHR 0x30B1
+#define EGL_GL_TEXTURE_LEVEL_KHR 0x30BC
+#endif /* EGL_KHR_gl_texture_2D_image */
+
+#ifndef EGL_KHR_gl_texture_3D_image
+#define EGL_KHR_gl_texture_3D_image 1
+#define EGL_GL_TEXTURE_3D_KHR 0x30B2
+#define EGL_GL_TEXTURE_ZOFFSET_KHR 0x30BD
+#endif /* EGL_KHR_gl_texture_3D_image */
+
+#ifndef EGL_KHR_gl_texture_cubemap_image
+#define EGL_KHR_gl_texture_cubemap_image 1
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR 0x30B3
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR 0x30B4
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR 0x30B5
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR 0x30B6
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR 0x30B7
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR 0x30B8
+#endif /* EGL_KHR_gl_texture_cubemap_image */
+
+#ifndef EGL_KHR_image
+#define EGL_KHR_image 1
+typedef void *EGLImageKHR;
+#define EGL_NATIVE_PIXMAP_KHR 0x30B0
+#define EGL_NO_IMAGE_KHR ((EGLImageKHR)0)
+typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGLImageKHR image);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLImageKHR EGLAPIENTRY eglCreateImageKHR (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image);
+#endif
+#endif /* EGL_KHR_image */
+
+#ifndef EGL_KHR_image_base
+#define EGL_KHR_image_base 1
+#define EGL_IMAGE_PRESERVED_KHR 0x30D2
+#endif /* EGL_KHR_image_base */
+
+#ifndef EGL_KHR_image_pixmap
+#define EGL_KHR_image_pixmap 1
+#endif /* EGL_KHR_image_pixmap */
+
+#ifndef EGL_KHR_lock_surface
+#define EGL_KHR_lock_surface 1
+#define EGL_READ_SURFACE_BIT_KHR 0x0001
+#define EGL_WRITE_SURFACE_BIT_KHR 0x0002
+#define EGL_LOCK_SURFACE_BIT_KHR 0x0080
+#define EGL_OPTIMAL_FORMAT_BIT_KHR 0x0100
+#define EGL_MATCH_FORMAT_KHR 0x3043
+#define EGL_FORMAT_RGB_565_EXACT_KHR 0x30C0
+#define EGL_FORMAT_RGB_565_KHR 0x30C1
+#define EGL_FORMAT_RGBA_8888_EXACT_KHR 0x30C2
+#define EGL_FORMAT_RGBA_8888_KHR 0x30C3
+#define EGL_MAP_PRESERVE_PIXELS_KHR 0x30C4
+#define EGL_LOCK_USAGE_HINT_KHR 0x30C5
+#define EGL_BITMAP_POINTER_KHR 0x30C6
+#define EGL_BITMAP_PITCH_KHR 0x30C7
+#define EGL_BITMAP_ORIGIN_KHR 0x30C8
+#define EGL_BITMAP_PIXEL_RED_OFFSET_KHR 0x30C9
+#define EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR 0x30CA
+#define EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR 0x30CB
+#define EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR 0x30CC
+#define EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR 0x30CD
+#define EGL_LOWER_LEFT_KHR 0x30CE
+#define EGL_UPPER_LEFT_KHR 0x30CF
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLLOCKSURFACEKHRPROC) (EGLDisplay dpy, EGLSurface surface, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNLOCKSURFACEKHRPROC) (EGLDisplay dpy, EGLSurface surface);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglLockSurfaceKHR (EGLDisplay dpy, EGLSurface surface, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglUnlockSurfaceKHR (EGLDisplay dpy, EGLSurface surface);
+#endif
+#endif /* EGL_KHR_lock_surface */
+
+#ifndef EGL_KHR_lock_surface2
+#define EGL_KHR_lock_surface2 1
+#define EGL_BITMAP_PIXEL_SIZE_KHR 0x3110
+#endif /* EGL_KHR_lock_surface2 */
+
+#ifndef EGL_KHR_lock_surface3
+#define EGL_KHR_lock_surface3 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSURFACE64KHRPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLAttribKHR *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface64KHR (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLAttribKHR *value);
+#endif
+#endif /* EGL_KHR_lock_surface3 */
+
+#ifndef EGL_KHR_platform_android
+#define EGL_KHR_platform_android 1
+#define EGL_PLATFORM_ANDROID_KHR 0x3141
+#endif /* EGL_KHR_platform_android */
+
+#ifndef EGL_KHR_platform_gbm
+#define EGL_KHR_platform_gbm 1
+#define EGL_PLATFORM_GBM_KHR 0x31D7
+#endif /* EGL_KHR_platform_gbm */
+
+#ifndef EGL_KHR_platform_wayland
+#define EGL_KHR_platform_wayland 1
+#define EGL_PLATFORM_WAYLAND_KHR 0x31D8
+#endif /* EGL_KHR_platform_wayland */
+
+#ifndef EGL_KHR_platform_x11
+#define EGL_KHR_platform_x11 1
+#define EGL_PLATFORM_X11_KHR 0x31D5
+#define EGL_PLATFORM_X11_SCREEN_KHR 0x31D6
+#endif /* EGL_KHR_platform_x11 */
+
+#ifndef EGL_KHR_reusable_sync
+#define EGL_KHR_reusable_sync 1
+typedef khronos_utime_nanoseconds_t EGLTimeKHR;
+#ifdef KHRONOS_SUPPORT_INT64
+#define EGL_SYNC_STATUS_KHR 0x30F1
+#define EGL_SIGNALED_KHR 0x30F2
+#define EGL_UNSIGNALED_KHR 0x30F3
+#define EGL_TIMEOUT_EXPIRED_KHR 0x30F5
+#define EGL_CONDITION_SATISFIED_KHR 0x30F6
+#define EGL_SYNC_TYPE_KHR 0x30F7
+#define EGL_SYNC_REUSABLE_KHR 0x30FA
+#define EGL_SYNC_FLUSH_COMMANDS_BIT_KHR 0x0001
+#define EGL_FOREVER_KHR 0xFFFFFFFFFFFFFFFFull
+#define EGL_NO_SYNC_KHR ((EGLSyncKHR)0)
+typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESYNCKHRPROC) (EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync);
+typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSyncKHR (EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySyncKHR (EGLDisplay dpy, EGLSyncKHR sync);
+EGLAPI EGLint EGLAPIENTRY eglClientWaitSyncKHR (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout);
+EGLAPI EGLBoolean EGLAPIENTRY eglSignalSyncKHR (EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttribKHR (EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value);
+#endif
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_KHR_reusable_sync */
+
+#ifndef EGL_KHR_stream
+#define EGL_KHR_stream 1
+typedef void *EGLStreamKHR;
+typedef khronos_uint64_t EGLuint64KHR;
+#ifdef KHRONOS_SUPPORT_INT64
+#define EGL_NO_STREAM_KHR ((EGLStreamKHR)0)
+#define EGL_CONSUMER_LATENCY_USEC_KHR 0x3210
+#define EGL_PRODUCER_FRAME_KHR 0x3212
+#define EGL_CONSUMER_FRAME_KHR 0x3213
+#define EGL_STREAM_STATE_KHR 0x3214
+#define EGL_STREAM_STATE_CREATED_KHR 0x3215
+#define EGL_STREAM_STATE_CONNECTING_KHR 0x3216
+#define EGL_STREAM_STATE_EMPTY_KHR 0x3217
+#define EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR 0x3218
+#define EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR 0x3219
+#define EGL_STREAM_STATE_DISCONNECTED_KHR 0x321A
+#define EGL_BAD_STREAM_KHR 0x321B
+#define EGL_BAD_STATE_KHR 0x321C
+typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMKHRPROC) (EGLDisplay dpy, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSTREAMKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint *value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMU64KHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLuint64KHR *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamKHR (EGLDisplay dpy, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyStreamKHR (EGLDisplay dpy, EGLStreamKHR stream);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamAttribKHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint value);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamKHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint *value);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamu64KHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLuint64KHR *value);
+#endif
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_KHR_stream */
+
+#ifndef EGL_KHR_stream_consumer_gltexture
+#define EGL_KHR_stream_consumer_gltexture 1
+#ifdef EGL_KHR_stream
+#define EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR 0x321E
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERACQUIREKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERRELEASEKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerGLTextureExternalKHR (EGLDisplay dpy, EGLStreamKHR stream);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerAcquireKHR (EGLDisplay dpy, EGLStreamKHR stream);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerReleaseKHR (EGLDisplay dpy, EGLStreamKHR stream);
+#endif
+#endif /* EGL_KHR_stream */
+#endif /* EGL_KHR_stream_consumer_gltexture */
+
+#ifndef EGL_KHR_stream_cross_process_fd
+#define EGL_KHR_stream_cross_process_fd 1
+typedef int EGLNativeFileDescriptorKHR;
+#ifdef EGL_KHR_stream
+#define EGL_NO_FILE_DESCRIPTOR_KHR ((EGLNativeFileDescriptorKHR)(-1))
+typedef EGLNativeFileDescriptorKHR (EGLAPIENTRYP PFNEGLGETSTREAMFILEDESCRIPTORKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC) (EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLNativeFileDescriptorKHR EGLAPIENTRY eglGetStreamFileDescriptorKHR (EGLDisplay dpy, EGLStreamKHR stream);
+EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamFromFileDescriptorKHR (EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor);
+#endif
+#endif /* EGL_KHR_stream */
+#endif /* EGL_KHR_stream_cross_process_fd */
+
+#ifndef EGL_KHR_stream_fifo
+#define EGL_KHR_stream_fifo 1
+#ifdef EGL_KHR_stream
+#define EGL_STREAM_FIFO_LENGTH_KHR 0x31FC
+#define EGL_STREAM_TIME_NOW_KHR 0x31FD
+#define EGL_STREAM_TIME_CONSUMER_KHR 0x31FE
+#define EGL_STREAM_TIME_PRODUCER_KHR 0x31FF
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMTIMEKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLTimeKHR *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamTimeKHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLTimeKHR *value);
+#endif
+#endif /* EGL_KHR_stream */
+#endif /* EGL_KHR_stream_fifo */
+
+#ifndef EGL_KHR_stream_producer_aldatalocator
+#define EGL_KHR_stream_producer_aldatalocator 1
+#ifdef EGL_KHR_stream
+#endif /* EGL_KHR_stream */
+#endif /* EGL_KHR_stream_producer_aldatalocator */
+
+#ifndef EGL_KHR_stream_producer_eglsurface
+#define EGL_KHR_stream_producer_eglsurface 1
+#ifdef EGL_KHR_stream
+#define EGL_STREAM_BIT_KHR 0x0800
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC) (EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSurface EGLAPIENTRY eglCreateStreamProducerSurfaceKHR (EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint *attrib_list);
+#endif
+#endif /* EGL_KHR_stream */
+#endif /* EGL_KHR_stream_producer_eglsurface */
+
+#ifndef EGL_KHR_surfaceless_context
+#define EGL_KHR_surfaceless_context 1
+#endif /* EGL_KHR_surfaceless_context */
+
+#ifndef EGL_KHR_vg_parent_image
+#define EGL_KHR_vg_parent_image 1
+#define EGL_VG_PARENT_IMAGE_KHR 0x30BA
+#endif /* EGL_KHR_vg_parent_image */
+
+#ifndef EGL_KHR_wait_sync
+#define EGL_KHR_wait_sync 1
+typedef EGLint (EGLAPIENTRYP PFNEGLWAITSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLint EGLAPIENTRY eglWaitSyncKHR (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags);
+#endif
+#endif /* EGL_KHR_wait_sync */
+
+#ifndef EGL_ANDROID_blob_cache
+#define EGL_ANDROID_blob_cache 1
+typedef khronos_ssize_t EGLsizeiANDROID;
+typedef void (*EGLSetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, const void *value, EGLsizeiANDROID valueSize);
+typedef EGLsizeiANDROID (*EGLGetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, void *value, EGLsizeiANDROID valueSize);
+typedef void (EGLAPIENTRYP PFNEGLSETBLOBCACHEFUNCSANDROIDPROC) (EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI void EGLAPIENTRY eglSetBlobCacheFuncsANDROID (EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get);
+#endif
+#endif /* EGL_ANDROID_blob_cache */
+
+#ifndef EGL_ANDROID_framebuffer_target
+#define EGL_ANDROID_framebuffer_target 1
+#define EGL_FRAMEBUFFER_TARGET_ANDROID 0x3147
+#endif /* EGL_ANDROID_framebuffer_target */
+
+#ifndef EGL_ANDROID_image_native_buffer
+#define EGL_ANDROID_image_native_buffer 1
+#define EGL_NATIVE_BUFFER_ANDROID 0x3140
+#endif /* EGL_ANDROID_image_native_buffer */
+
+#ifndef EGL_ANDROID_native_fence_sync
+#define EGL_ANDROID_native_fence_sync 1
+#define EGL_SYNC_NATIVE_FENCE_ANDROID 0x3144
+#define EGL_SYNC_NATIVE_FENCE_FD_ANDROID 0x3145
+#define EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID 0x3146
+#define EGL_NO_NATIVE_FENCE_FD_ANDROID -1
+typedef EGLint (EGLAPIENTRYP PFNEGLDUPNATIVEFENCEFDANDROIDPROC) (EGLDisplay dpy, EGLSyncKHR sync);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLint EGLAPIENTRY eglDupNativeFenceFDANDROID (EGLDisplay dpy, EGLSyncKHR sync);
+#endif
+#endif /* EGL_ANDROID_native_fence_sync */
+
+#ifndef EGL_ANDROID_recordable
+#define EGL_ANDROID_recordable 1
+#define EGL_RECORDABLE_ANDROID 0x3142
+#endif /* EGL_ANDROID_recordable */
+
+#ifndef EGL_ANGLE_d3d_share_handle_client_buffer
+#define EGL_ANGLE_d3d_share_handle_client_buffer 1
+#define EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE 0x3200
+#endif /* EGL_ANGLE_d3d_share_handle_client_buffer */
+
+#ifndef EGL_ANGLE_window_fixed_size
+#define EGL_ANGLE_window_fixed_size 1
+#define EGL_FIXED_SIZE_ANGLE 0x3201
+#endif /* EGL_ANGLE_window_fixed_size */
+
+#ifndef EGL_ANGLE_query_surface_pointer
+#define EGL_ANGLE_query_surface_pointer 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSURFACEPOINTERANGLEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurfacePointerANGLE (EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value);
+#endif
+#endif /* EGL_ANGLE_query_surface_pointer */
+
+#ifndef EGL_ANGLE_software_display
+#define EGL_ANGLE_software_display 1
+#define EGL_SOFTWARE_DISPLAY_ANGLE ((EGLNativeDisplayType)-1)
+#endif /* EGL_ANGLE_software_display */
+
+#ifndef EGL_ANGLE_direct3d_display
+#define EGL_ANGLE_direct3d_display 1
+#define EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE ((EGLNativeDisplayType)-2)
+#define EGL_D3D11_ONLY_DISPLAY_ANGLE ((EGLNativeDisplayType)-3)
+#endif /* EGL_ANGLE_direct3d_display */
+
+#ifndef EGL_ANGLE_surface_d3d_texture_2d_share_handle
+#define EGL_ANGLE_surface_d3d_texture_2d_share_handle 1
+#endif /* EGL_ANGLE_surface_d3d_texture_2d_share_handle */
+
+#ifndef EGL_ANGLE_surface_d3d_render_to_back_buffer
+#define EGL_ANGLE_surface_d3d_render_to_back_buffer 1
+#define EGL_ANGLE_DISPLAY_ALLOW_RENDER_TO_BACK_BUFFER 0x320B
+#define EGL_ANGLE_SURFACE_RENDER_TO_BACK_BUFFER 0x320C
+#endif /* EGL_ANGLE_surface_d3d_render_to_back_buffer */
+
+#ifndef EGL_ANGLE_platform_angle
+#define EGL_ANGLE_platform_angle 1
+#define EGL_PLATFORM_ANGLE_ANGLE 0x3201
+#define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3202
+#define EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE 0x3203
+#define EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE 0x3204
+#define EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE 0x3205
+#endif /* EGL_ANGLE_platform_angle */
+
+#ifndef EGL_ANGLE_platform_angle_d3d
+#define EGL_ANGLE_platform_angle_d3d 1
+#define EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE 0x3206
+#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3207
+#define EGL_PLATFORM_ANGLE_USE_WARP_ANGLE 0x3208
+#endif /* EGL_ANGLE_platform_angle_d3d */
+
+#ifndef EGL_ANGLE_platform_angle_opengl
+#define EGL_ANGLE_platform_angle_opengl 1
+#define EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE 0x3209
+#define EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE 0x320A
+#endif /* EGL_ANGLE_platform_angle_opengl */
+
+#ifndef EGL_ARM_pixmap_multisample_discard
+#define EGL_ARM_pixmap_multisample_discard 1
+#define EGL_DISCARD_SAMPLES_ARM 0x3286
+#endif /* EGL_ARM_pixmap_multisample_discard */
+
+#ifndef EGL_EXT_buffer_age
+#define EGL_EXT_buffer_age 1
+#define EGL_BUFFER_AGE_EXT 0x313D
+#endif /* EGL_EXT_buffer_age */
+
+#ifndef EGL_EXT_client_extensions
+#define EGL_EXT_client_extensions 1
+#endif /* EGL_EXT_client_extensions */
+
+#ifndef EGL_EXT_create_context_robustness
+#define EGL_EXT_create_context_robustness 1
+#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT 0x30BF
+#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT 0x3138
+#define EGL_NO_RESET_NOTIFICATION_EXT 0x31BE
+#define EGL_LOSE_CONTEXT_ON_RESET_EXT 0x31BF
+#endif /* EGL_EXT_create_context_robustness */
+
+#ifndef EGL_EXT_device_base
+#define EGL_EXT_device_base 1
+typedef void *EGLDeviceEXT;
+#define EGL_NO_DEVICE_EXT ((EGLDeviceEXT)(0))
+#define EGL_BAD_DEVICE_EXT 0x322B
+#define EGL_DEVICE_EXT 0x322C
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDEVICEATTRIBEXTPROC) (EGLDeviceEXT device, EGLint attribute, EGLAttrib *value);
+typedef const char *(EGLAPIENTRYP PFNEGLQUERYDEVICESTRINGEXTPROC) (EGLDeviceEXT device, EGLint name);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDEVICESEXTPROC) (EGLint max_devices, EGLDeviceEXT *devices, EGLint *num_devices);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDISPLAYATTRIBEXTPROC) (EGLDisplay dpy, EGLint attribute, EGLAttrib *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDeviceAttribEXT (EGLDeviceEXT device, EGLint attribute, EGLAttrib *value);
+EGLAPI const char *EGLAPIENTRY eglQueryDeviceStringEXT (EGLDeviceEXT device, EGLint name);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDevicesEXT (EGLint max_devices, EGLDeviceEXT *devices, EGLint *num_devices);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDisplayAttribEXT (EGLDisplay dpy, EGLint attribute, EGLAttrib *value);
+#endif
+#endif /* EGL_EXT_device_base */
+
+#ifndef EGL_EXT_image_dma_buf_import
+#define EGL_EXT_image_dma_buf_import 1
+#define EGL_LINUX_DMA_BUF_EXT 0x3270
+#define EGL_LINUX_DRM_FOURCC_EXT 0x3271
+#define EGL_DMA_BUF_PLANE0_FD_EXT 0x3272
+#define EGL_DMA_BUF_PLANE0_OFFSET_EXT 0x3273
+#define EGL_DMA_BUF_PLANE0_PITCH_EXT 0x3274
+#define EGL_DMA_BUF_PLANE1_FD_EXT 0x3275
+#define EGL_DMA_BUF_PLANE1_OFFSET_EXT 0x3276
+#define EGL_DMA_BUF_PLANE1_PITCH_EXT 0x3277
+#define EGL_DMA_BUF_PLANE2_FD_EXT 0x3278
+#define EGL_DMA_BUF_PLANE2_OFFSET_EXT 0x3279
+#define EGL_DMA_BUF_PLANE2_PITCH_EXT 0x327A
+#define EGL_YUV_COLOR_SPACE_HINT_EXT 0x327B
+#define EGL_SAMPLE_RANGE_HINT_EXT 0x327C
+#define EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT 0x327D
+#define EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT 0x327E
+#define EGL_ITU_REC601_EXT 0x327F
+#define EGL_ITU_REC709_EXT 0x3280
+#define EGL_ITU_REC2020_EXT 0x3281
+#define EGL_YUV_FULL_RANGE_EXT 0x3282
+#define EGL_YUV_NARROW_RANGE_EXT 0x3283
+#define EGL_YUV_CHROMA_SITING_0_EXT 0x3284
+#define EGL_YUV_CHROMA_SITING_0_5_EXT 0x3285
+#endif /* EGL_EXT_image_dma_buf_import */
+
+#ifndef EGL_EXT_multiview_window
+#define EGL_EXT_multiview_window 1
+#define EGL_MULTIVIEW_VIEW_COUNT_EXT 0x3134
+#endif /* EGL_EXT_multiview_window */
+
+#ifndef EGL_EXT_platform_base
+#define EGL_EXT_platform_base 1
+typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void *native_display, const EGLint *attrib_list);
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list);
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLint *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLDisplay EGLAPIENTRY eglGetPlatformDisplayEXT (EGLenum platform, void *native_display, const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformWindowSurfaceEXT (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformPixmapSurfaceEXT (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLint *attrib_list);
+#endif
+#endif /* EGL_EXT_platform_base */
+
+#ifndef EGL_EXT_platform_device
+#define EGL_EXT_platform_device 1
+#define EGL_PLATFORM_DEVICE_EXT 0x313F
+#endif /* EGL_EXT_platform_device */
+
+#ifndef EGL_EXT_platform_wayland
+#define EGL_EXT_platform_wayland 1
+#define EGL_PLATFORM_WAYLAND_EXT 0x31D8
+#endif /* EGL_EXT_platform_wayland */
+
+#ifndef EGL_EXT_platform_x11
+#define EGL_EXT_platform_x11 1
+#define EGL_PLATFORM_X11_EXT 0x31D5
+#define EGL_PLATFORM_X11_SCREEN_EXT 0x31D6
+#endif /* EGL_EXT_platform_x11 */
+
+#ifndef EGL_EXT_protected_surface
+#define EGL_EXT_protected_surface 1
+#define EGL_PROTECTED_CONTENT_EXT 0x32C0
+#endif /* EGL_EXT_protected_surface */
+
+#ifndef EGL_EXT_swap_buffers_with_damage
+#define EGL_EXT_swap_buffers_with_damage 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC) (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersWithDamageEXT (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
+#endif
+#endif /* EGL_EXT_swap_buffers_with_damage */
+
+#ifndef EGL_HI_clientpixmap
+#define EGL_HI_clientpixmap 1
+struct EGLClientPixmapHI {
+ void *pData;
+ EGLint iWidth;
+ EGLint iHeight;
+ EGLint iStride;
+};
+#define EGL_CLIENT_PIXMAP_POINTER_HI 0x8F74
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPIXMAPSURFACEHIPROC) (EGLDisplay dpy, EGLConfig config, struct EGLClientPixmapHI *pixmap);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurfaceHI (EGLDisplay dpy, EGLConfig config, struct EGLClientPixmapHI *pixmap);
+#endif
+#endif /* EGL_HI_clientpixmap */
+
+#ifndef EGL_HI_colorformats
+#define EGL_HI_colorformats 1
+#define EGL_COLOR_FORMAT_HI 0x8F70
+#define EGL_COLOR_RGB_HI 0x8F71
+#define EGL_COLOR_RGBA_HI 0x8F72
+#define EGL_COLOR_ARGB_HI 0x8F73
+#endif /* EGL_HI_colorformats */
+
+#ifndef EGL_IMG_context_priority
+#define EGL_IMG_context_priority 1
+#define EGL_CONTEXT_PRIORITY_LEVEL_IMG 0x3100
+#define EGL_CONTEXT_PRIORITY_HIGH_IMG 0x3101
+#define EGL_CONTEXT_PRIORITY_MEDIUM_IMG 0x3102
+#define EGL_CONTEXT_PRIORITY_LOW_IMG 0x3103
+#endif /* EGL_IMG_context_priority */
+
+#ifndef EGL_MESA_drm_image
+#define EGL_MESA_drm_image 1
+#define EGL_DRM_BUFFER_FORMAT_MESA 0x31D0
+#define EGL_DRM_BUFFER_USE_MESA 0x31D1
+#define EGL_DRM_BUFFER_FORMAT_ARGB32_MESA 0x31D2
+#define EGL_DRM_BUFFER_MESA 0x31D3
+#define EGL_DRM_BUFFER_STRIDE_MESA 0x31D4
+#define EGL_DRM_BUFFER_USE_SCANOUT_MESA 0x00000001
+#define EGL_DRM_BUFFER_USE_SHARE_MESA 0x00000002
+typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEDRMIMAGEMESAPROC) (EGLDisplay dpy, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLEXPORTDRMIMAGEMESAPROC) (EGLDisplay dpy, EGLImageKHR image, EGLint *name, EGLint *handle, EGLint *stride);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLImageKHR EGLAPIENTRY eglCreateDRMImageMESA (EGLDisplay dpy, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglExportDRMImageMESA (EGLDisplay dpy, EGLImageKHR image, EGLint *name, EGLint *handle, EGLint *stride);
+#endif
+#endif /* EGL_MESA_drm_image */
+
+#ifndef EGL_MESA_platform_gbm
+#define EGL_MESA_platform_gbm 1
+#define EGL_PLATFORM_GBM_MESA 0x31D7
+#endif /* EGL_MESA_platform_gbm */
+
+#ifndef EGL_NOK_swap_region
+#define EGL_NOK_swap_region 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSREGIONNOKPROC) (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersRegionNOK (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects);
+#endif
+#endif /* EGL_NOK_swap_region */
+
+#ifndef EGL_NOK_swap_region2
+#define EGL_NOK_swap_region2 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSREGION2NOKPROC) (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersRegion2NOK (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects);
+#endif
+#endif /* EGL_NOK_swap_region2 */
+
+#ifndef EGL_NOK_texture_from_pixmap
+#define EGL_NOK_texture_from_pixmap 1
+#define EGL_Y_INVERTED_NOK 0x307F
+#endif /* EGL_NOK_texture_from_pixmap */
+
+#ifndef EGL_NV_3dvision_surface
+#define EGL_NV_3dvision_surface 1
+#define EGL_AUTO_STEREO_NV 0x3136
+#endif /* EGL_NV_3dvision_surface */
+
+#ifndef EGL_NV_coverage_sample
+#define EGL_NV_coverage_sample 1
+#define EGL_COVERAGE_BUFFERS_NV 0x30E0
+#define EGL_COVERAGE_SAMPLES_NV 0x30E1
+#endif /* EGL_NV_coverage_sample */
+
+#ifndef EGL_NV_coverage_sample_resolve
+#define EGL_NV_coverage_sample_resolve 1
+#define EGL_COVERAGE_SAMPLE_RESOLVE_NV 0x3131
+#define EGL_COVERAGE_SAMPLE_RESOLVE_DEFAULT_NV 0x3132
+#define EGL_COVERAGE_SAMPLE_RESOLVE_NONE_NV 0x3133
+#endif /* EGL_NV_coverage_sample_resolve */
+
+#ifndef EGL_NV_depth_nonlinear
+#define EGL_NV_depth_nonlinear 1
+#define EGL_DEPTH_ENCODING_NV 0x30E2
+#define EGL_DEPTH_ENCODING_NONE_NV 0
+#define EGL_DEPTH_ENCODING_NONLINEAR_NV 0x30E3
+#endif /* EGL_NV_depth_nonlinear */
+
+#ifndef EGL_NV_native_query
+#define EGL_NV_native_query 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEDISPLAYNVPROC) (EGLDisplay dpy, EGLNativeDisplayType *display_id);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEWINDOWNVPROC) (EGLDisplay dpy, EGLSurface surf, EGLNativeWindowType *window);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEPIXMAPNVPROC) (EGLDisplay dpy, EGLSurface surf, EGLNativePixmapType *pixmap);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryNativeDisplayNV (EGLDisplay dpy, EGLNativeDisplayType *display_id);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryNativeWindowNV (EGLDisplay dpy, EGLSurface surf, EGLNativeWindowType *window);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryNativePixmapNV (EGLDisplay dpy, EGLSurface surf, EGLNativePixmapType *pixmap);
+#endif
+#endif /* EGL_NV_native_query */
+
+#ifndef EGL_NV_post_convert_rounding
+#define EGL_NV_post_convert_rounding 1
+#endif /* EGL_NV_post_convert_rounding */
+
+#ifndef EGL_NV_post_sub_buffer
+#define EGL_NV_post_sub_buffer 1
+#define EGL_POST_SUB_BUFFER_SUPPORTED_NV 0x30BE
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLPOSTSUBBUFFERNVPROC) (EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglPostSubBufferNV (EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height);
+#endif
+#endif /* EGL_NV_post_sub_buffer */
+
+#ifndef EGL_NV_stream_sync
+#define EGL_NV_stream_sync 1
+#define EGL_SYNC_NEW_FRAME_NV 0x321F
+typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESTREAMSYNCNVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum type, const EGLint *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateStreamSyncNV (EGLDisplay dpy, EGLStreamKHR stream, EGLenum type, const EGLint *attrib_list);
+#endif
+#endif /* EGL_NV_stream_sync */
+
+#ifndef EGL_NV_sync
+#define EGL_NV_sync 1
+typedef void *EGLSyncNV;
+typedef khronos_utime_nanoseconds_t EGLTimeNV;
+#ifdef KHRONOS_SUPPORT_INT64
+#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_NV 0x30E6
+#define EGL_SYNC_STATUS_NV 0x30E7
+#define EGL_SIGNALED_NV 0x30E8
+#define EGL_UNSIGNALED_NV 0x30E9
+#define EGL_SYNC_FLUSH_COMMANDS_BIT_NV 0x0001
+#define EGL_FOREVER_NV 0xFFFFFFFFFFFFFFFFull
+#define EGL_ALREADY_SIGNALED_NV 0x30EA
+#define EGL_TIMEOUT_EXPIRED_NV 0x30EB
+#define EGL_CONDITION_SATISFIED_NV 0x30EC
+#define EGL_SYNC_TYPE_NV 0x30ED
+#define EGL_SYNC_CONDITION_NV 0x30EE
+#define EGL_SYNC_FENCE_NV 0x30EF
+#define EGL_NO_SYNC_NV ((EGLSyncNV)0)
+typedef EGLSyncNV (EGLAPIENTRYP PFNEGLCREATEFENCESYNCNVPROC) (EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCNVPROC) (EGLSyncNV sync);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLFENCENVPROC) (EGLSyncNV sync);
+typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCNVPROC) (EGLSyncNV sync, EGLint flags, EGLTimeNV timeout);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCNVPROC) (EGLSyncNV sync, EGLenum mode);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBNVPROC) (EGLSyncNV sync, EGLint attribute, EGLint *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSyncNV EGLAPIENTRY eglCreateFenceSyncNV (EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySyncNV (EGLSyncNV sync);
+EGLAPI EGLBoolean EGLAPIENTRY eglFenceNV (EGLSyncNV sync);
+EGLAPI EGLint EGLAPIENTRY eglClientWaitSyncNV (EGLSyncNV sync, EGLint flags, EGLTimeNV timeout);
+EGLAPI EGLBoolean EGLAPIENTRY eglSignalSyncNV (EGLSyncNV sync, EGLenum mode);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttribNV (EGLSyncNV sync, EGLint attribute, EGLint *value);
+#endif
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_NV_sync */
+
+#ifndef EGL_NV_system_time
+#define EGL_NV_system_time 1
+typedef khronos_utime_nanoseconds_t EGLuint64NV;
+#ifdef KHRONOS_SUPPORT_INT64
+typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC) (void);
+typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMENVPROC) (void);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeFrequencyNV (void);
+EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeNV (void);
+#endif
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_NV_system_time */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/platform/winrt/include/EGL/eglplatform.h b/platform/winrt/include/EGL/eglplatform.h
index b0e88f94d4..71dadc79d5 100644
--- a/platform/winrt/include/EGL/eglplatform.h
+++ b/platform/winrt/include/EGL/eglplatform.h
@@ -1,131 +1,131 @@
-#ifndef __eglplatform_h_
-#define __eglplatform_h_
-
-/*
-** Copyright (c) 2007-2013 The Khronos Group Inc.
-**
-** Permission is hereby granted, free of charge, to any person obtaining a
-** copy of this software and/or associated documentation files (the
-** "Materials"), to deal in the Materials without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Materials, and to
-** permit persons to whom the Materials are 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 Materials.
-**
-** THE MATERIALS ARE 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
-** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-*/
-
-/* Platform-specific types and definitions for egl.h
- * $Revision: 23432 $ on $Date: 2013-10-09 00:57:24 -0700 (Wed, 09 Oct 2013) $
- *
- * Adopters may modify khrplatform.h and this file to suit their platform.
- * You are encouraged to submit all modifications to the Khronos group so that
- * they can be included in future versions of this file. Please submit changes
- * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
- * by filing a bug against product "EGL" component "Registry".
- */
-
-#include <KHR/khrplatform.h>
-
-/* Macros used in EGL function prototype declarations.
- *
- * EGL functions should be prototyped as:
- *
- * EGLAPI return-type EGLAPIENTRY eglFunction(arguments);
- * typedef return-type (EXPAPIENTRYP PFNEGLFUNCTIONPROC) (arguments);
- *
- * KHRONOS_APICALL and KHRONOS_APIENTRY are defined in KHR/khrplatform.h
- */
-
-#ifndef EGLAPI
-#define EGLAPI KHRONOS_APICALL
-#endif
-
-#ifndef EGLAPIENTRY
-#define EGLAPIENTRY KHRONOS_APIENTRY
-#endif
-#define EGLAPIENTRYP EGLAPIENTRY*
-
-/* The types NativeDisplayType, NativeWindowType, and NativePixmapType
- * are aliases of window-system-dependent types, such as X Display * or
- * Windows Device Context. They must be defined in platform-specific
- * code below. The EGL-prefixed versions of Native*Type are the same
- * types, renamed in EGL 1.3 so all types in the API start with "EGL".
- *
- * Khronos STRONGLY RECOMMENDS that you use the default definitions
- * provided below, since these changes affect both binary and source
- * portability of applications using EGL running on different EGL
- * implementations.
- */
-
-#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */
-#ifndef WIN32_LEAN_AND_MEAN
-#define WIN32_LEAN_AND_MEAN 1
-#endif
-#include <windows.h>
-
-typedef HDC EGLNativeDisplayType;
-typedef HBITMAP EGLNativePixmapType;
-
-#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) /* Windows Store */
-#include <inspectable.h>
-typedef IInspectable* EGLNativeWindowType;
-#else
-typedef HWND EGLNativeWindowType;
-#endif
-
-#elif defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */
-
-typedef int EGLNativeDisplayType;
-typedef void *EGLNativeWindowType;
-typedef void *EGLNativePixmapType;
-
-#elif defined(__ANDROID__) || defined(ANDROID)
-
-#include <android/native_window.h>
-
-struct egl_native_pixmap_t;
-
-typedef struct ANativeWindow* EGLNativeWindowType;
-typedef struct egl_native_pixmap_t* EGLNativePixmapType;
-typedef void* EGLNativeDisplayType;
-
-#elif defined(__unix__)
-
-/* X11 (tentative) */
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
-
-typedef Display *EGLNativeDisplayType;
-typedef Pixmap EGLNativePixmapType;
-typedef Window EGLNativeWindowType;
-
-#else
-#error "Platform not recognized"
-#endif
-
-/* EGL 1.2 types, renamed for consistency in EGL 1.3 */
-typedef EGLNativeDisplayType NativeDisplayType;
-typedef EGLNativePixmapType NativePixmapType;
-typedef EGLNativeWindowType NativeWindowType;
-
-
-/* Define EGLint. This must be a signed integral type large enough to contain
- * all legal attribute names and values passed into and out of EGL, whether
- * their type is boolean, bitmask, enumerant (symbolic constant), integer,
- * handle, or other. While in general a 32-bit integer will suffice, if
- * handles are 64 bit types, then EGLint should be defined as a signed 64-bit
- * integer type.
- */
-typedef khronos_int32_t EGLint;
-
-#endif /* __eglplatform_h */
+#ifndef __eglplatform_h_
+#define __eglplatform_h_
+
+/*
+** Copyright (c) 2007-2013 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are 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 Materials.
+**
+** THE MATERIALS ARE 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
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+/* Platform-specific types and definitions for egl.h
+ * $Revision: 23432 $ on $Date: 2013-10-09 00:57:24 -0700 (Wed, 09 Oct 2013) $
+ *
+ * Adopters may modify khrplatform.h and this file to suit their platform.
+ * You are encouraged to submit all modifications to the Khronos group so that
+ * they can be included in future versions of this file. Please submit changes
+ * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
+ * by filing a bug against product "EGL" component "Registry".
+ */
+
+#include <KHR/khrplatform.h>
+
+/* Macros used in EGL function prototype declarations.
+ *
+ * EGL functions should be prototyped as:
+ *
+ * EGLAPI return-type EGLAPIENTRY eglFunction(arguments);
+ * typedef return-type (EXPAPIENTRYP PFNEGLFUNCTIONPROC) (arguments);
+ *
+ * KHRONOS_APICALL and KHRONOS_APIENTRY are defined in KHR/khrplatform.h
+ */
+
+#ifndef EGLAPI
+#define EGLAPI KHRONOS_APICALL
+#endif
+
+#ifndef EGLAPIENTRY
+#define EGLAPIENTRY KHRONOS_APIENTRY
+#endif
+#define EGLAPIENTRYP EGLAPIENTRY*
+
+/* The types NativeDisplayType, NativeWindowType, and NativePixmapType
+ * are aliases of window-system-dependent types, such as X Display * or
+ * Windows Device Context. They must be defined in platform-specific
+ * code below. The EGL-prefixed versions of Native*Type are the same
+ * types, renamed in EGL 1.3 so all types in the API start with "EGL".
+ *
+ * Khronos STRONGLY RECOMMENDS that you use the default definitions
+ * provided below, since these changes affect both binary and source
+ * portability of applications using EGL running on different EGL
+ * implementations.
+ */
+
+#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif
+#include <windows.h>
+
+typedef HDC EGLNativeDisplayType;
+typedef HBITMAP EGLNativePixmapType;
+
+#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PC_APP || WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP) /* Windows Store */
+#include <inspectable.h>
+typedef IInspectable* EGLNativeWindowType;
+#else
+typedef HWND EGLNativeWindowType;
+#endif
+
+#elif defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */
+
+typedef int EGLNativeDisplayType;
+typedef void *EGLNativeWindowType;
+typedef void *EGLNativePixmapType;
+
+#elif defined(__ANDROID__) || defined(ANDROID)
+
+#include <android/native_window.h>
+
+struct egl_native_pixmap_t;
+
+typedef struct ANativeWindow* EGLNativeWindowType;
+typedef struct egl_native_pixmap_t* EGLNativePixmapType;
+typedef void* EGLNativeDisplayType;
+
+#elif defined(__unix__)
+
+/* X11 (tentative) */
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+typedef Display *EGLNativeDisplayType;
+typedef Pixmap EGLNativePixmapType;
+typedef Window EGLNativeWindowType;
+
+#else
+#error "Platform not recognized"
+#endif
+
+/* EGL 1.2 types, renamed for consistency in EGL 1.3 */
+typedef EGLNativeDisplayType NativeDisplayType;
+typedef EGLNativePixmapType NativePixmapType;
+typedef EGLNativeWindowType NativeWindowType;
+
+
+/* Define EGLint. This must be a signed integral type large enough to contain
+ * all legal attribute names and values passed into and out of EGL, whether
+ * their type is boolean, bitmask, enumerant (symbolic constant), integer,
+ * handle, or other. While in general a 32-bit integer will suffice, if
+ * handles are 64 bit types, then EGLint should be defined as a signed 64-bit
+ * integer type.
+ */
+typedef khronos_int32_t EGLint;
+
+#endif /* __eglplatform_h */
diff --git a/platform/winrt/include/GLES2/gl2.h b/platform/winrt/include/GLES2/gl2.h
index 5b3fa03c89..c2d8357268 100644
--- a/platform/winrt/include/GLES2/gl2.h
+++ b/platform/winrt/include/GLES2/gl2.h
@@ -1,620 +1,620 @@
-#ifndef __gl2_h_
-#define __gl2_h_
-
-/* $Revision: 20555 $ on $Date:: 2013-02-12 14:32:47 -0800 #$ */
-
-#include <GLES2/gl2platform.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * This document is licensed under the SGI Free Software B License Version
- * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
- */
-
-/*-------------------------------------------------------------------------
- * Data type definitions
- *-----------------------------------------------------------------------*/
-
-typedef void GLvoid;
-typedef char GLchar;
-typedef unsigned int GLenum;
-typedef unsigned char GLboolean;
-typedef unsigned int GLbitfield;
-typedef khronos_int8_t GLbyte;
-typedef short GLshort;
-typedef int GLint;
-typedef int GLsizei;
-typedef khronos_uint8_t GLubyte;
-typedef unsigned short GLushort;
-typedef unsigned int GLuint;
-typedef khronos_float_t GLfloat;
-typedef khronos_float_t GLclampf;
-typedef khronos_int32_t GLfixed;
-
-/* GL types for handling large vertex buffer objects */
-typedef khronos_intptr_t GLintptr;
-typedef khronos_ssize_t GLsizeiptr;
-
-/* OpenGL ES core versions */
-#define GL_ES_VERSION_2_0 1
-
-/* ClearBufferMask */
-#define GL_DEPTH_BUFFER_BIT 0x00000100
-#define GL_STENCIL_BUFFER_BIT 0x00000400
-#define GL_COLOR_BUFFER_BIT 0x00004000
-
-/* Boolean */
-#define GL_FALSE 0
-#define GL_TRUE 1
-
-/* BeginMode */
-#define GL_POINTS 0x0000
-#define GL_LINES 0x0001
-#define GL_LINE_LOOP 0x0002
-#define GL_LINE_STRIP 0x0003
-#define GL_TRIANGLES 0x0004
-#define GL_TRIANGLE_STRIP 0x0005
-#define GL_TRIANGLE_FAN 0x0006
-
-/* AlphaFunction (not supported in ES20) */
-/* GL_NEVER */
-/* GL_LESS */
-/* GL_EQUAL */
-/* GL_LEQUAL */
-/* GL_GREATER */
-/* GL_NOTEQUAL */
-/* GL_GEQUAL */
-/* GL_ALWAYS */
-
-/* BlendingFactorDest */
-#define GL_ZERO 0
-#define GL_ONE 1
-#define GL_SRC_COLOR 0x0300
-#define GL_ONE_MINUS_SRC_COLOR 0x0301
-#define GL_SRC_ALPHA 0x0302
-#define GL_ONE_MINUS_SRC_ALPHA 0x0303
-#define GL_DST_ALPHA 0x0304
-#define GL_ONE_MINUS_DST_ALPHA 0x0305
-
-/* BlendingFactorSrc */
-/* GL_ZERO */
-/* GL_ONE */
-#define GL_DST_COLOR 0x0306
-#define GL_ONE_MINUS_DST_COLOR 0x0307
-#define GL_SRC_ALPHA_SATURATE 0x0308
-/* GL_SRC_ALPHA */
-/* GL_ONE_MINUS_SRC_ALPHA */
-/* GL_DST_ALPHA */
-/* GL_ONE_MINUS_DST_ALPHA */
-
-/* BlendEquationSeparate */
-#define GL_FUNC_ADD 0x8006
-#define GL_BLEND_EQUATION 0x8009
-#define GL_BLEND_EQUATION_RGB 0x8009 /* same as BLEND_EQUATION */
-#define GL_BLEND_EQUATION_ALPHA 0x883D
-
-/* BlendSubtract */
-#define GL_FUNC_SUBTRACT 0x800A
-#define GL_FUNC_REVERSE_SUBTRACT 0x800B
-
-/* Separate Blend Functions */
-#define GL_BLEND_DST_RGB 0x80C8
-#define GL_BLEND_SRC_RGB 0x80C9
-#define GL_BLEND_DST_ALPHA 0x80CA
-#define GL_BLEND_SRC_ALPHA 0x80CB
-#define GL_CONSTANT_COLOR 0x8001
-#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
-#define GL_CONSTANT_ALPHA 0x8003
-#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
-#define GL_BLEND_COLOR 0x8005
-
-/* Buffer Objects */
-#define GL_ARRAY_BUFFER 0x8892
-#define GL_ELEMENT_ARRAY_BUFFER 0x8893
-#define GL_ARRAY_BUFFER_BINDING 0x8894
-#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
-
-#define GL_STREAM_DRAW 0x88E0
-#define GL_STATIC_DRAW 0x88E4
-#define GL_DYNAMIC_DRAW 0x88E8
-
-#define GL_BUFFER_SIZE 0x8764
-#define GL_BUFFER_USAGE 0x8765
-
-#define GL_CURRENT_VERTEX_ATTRIB 0x8626
-
-/* CullFaceMode */
-#define GL_FRONT 0x0404
-#define GL_BACK 0x0405
-#define GL_FRONT_AND_BACK 0x0408
-
-/* DepthFunction */
-/* GL_NEVER */
-/* GL_LESS */
-/* GL_EQUAL */
-/* GL_LEQUAL */
-/* GL_GREATER */
-/* GL_NOTEQUAL */
-/* GL_GEQUAL */
-/* GL_ALWAYS */
-
-/* EnableCap */
-#define GL_TEXTURE_2D 0x0DE1
-#define GL_CULL_FACE 0x0B44
-#define GL_BLEND 0x0BE2
-#define GL_DITHER 0x0BD0
-#define GL_STENCIL_TEST 0x0B90
-#define GL_DEPTH_TEST 0x0B71
-#define GL_SCISSOR_TEST 0x0C11
-#define GL_POLYGON_OFFSET_FILL 0x8037
-#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
-#define GL_SAMPLE_COVERAGE 0x80A0
-
-/* ErrorCode */
-#define GL_NO_ERROR 0
-#define GL_INVALID_ENUM 0x0500
-#define GL_INVALID_VALUE 0x0501
-#define GL_INVALID_OPERATION 0x0502
-#define GL_OUT_OF_MEMORY 0x0505
-
-/* FrontFaceDirection */
-#define GL_CW 0x0900
-#define GL_CCW 0x0901
-
-/* GetPName */
-#define GL_LINE_WIDTH 0x0B21
-#define GL_ALIASED_POINT_SIZE_RANGE 0x846D
-#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
-#define GL_CULL_FACE_MODE 0x0B45
-#define GL_FRONT_FACE 0x0B46
-#define GL_DEPTH_RANGE 0x0B70
-#define GL_DEPTH_WRITEMASK 0x0B72
-#define GL_DEPTH_CLEAR_VALUE 0x0B73
-#define GL_DEPTH_FUNC 0x0B74
-#define GL_STENCIL_CLEAR_VALUE 0x0B91
-#define GL_STENCIL_FUNC 0x0B92
-#define GL_STENCIL_FAIL 0x0B94
-#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
-#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
-#define GL_STENCIL_REF 0x0B97
-#define GL_STENCIL_VALUE_MASK 0x0B93
-#define GL_STENCIL_WRITEMASK 0x0B98
-#define GL_STENCIL_BACK_FUNC 0x8800
-#define GL_STENCIL_BACK_FAIL 0x8801
-#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802
-#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803
-#define GL_STENCIL_BACK_REF 0x8CA3
-#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4
-#define GL_STENCIL_BACK_WRITEMASK 0x8CA5
-#define GL_VIEWPORT 0x0BA2
-#define GL_SCISSOR_BOX 0x0C10
-/* GL_SCISSOR_TEST */
-#define GL_COLOR_CLEAR_VALUE 0x0C22
-#define GL_COLOR_WRITEMASK 0x0C23
-#define GL_UNPACK_ALIGNMENT 0x0CF5
-#define GL_PACK_ALIGNMENT 0x0D05
-#define GL_MAX_TEXTURE_SIZE 0x0D33
-#define GL_MAX_VIEWPORT_DIMS 0x0D3A
-#define GL_SUBPIXEL_BITS 0x0D50
-#define GL_RED_BITS 0x0D52
-#define GL_GREEN_BITS 0x0D53
-#define GL_BLUE_BITS 0x0D54
-#define GL_ALPHA_BITS 0x0D55
-#define GL_DEPTH_BITS 0x0D56
-#define GL_STENCIL_BITS 0x0D57
-#define GL_POLYGON_OFFSET_UNITS 0x2A00
-/* GL_POLYGON_OFFSET_FILL */
-#define GL_POLYGON_OFFSET_FACTOR 0x8038
-#define GL_TEXTURE_BINDING_2D 0x8069
-#define GL_SAMPLE_BUFFERS 0x80A8
-#define GL_SAMPLES 0x80A9
-#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
-#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
-
-/* GetTextureParameter */
-/* GL_TEXTURE_MAG_FILTER */
-/* GL_TEXTURE_MIN_FILTER */
-/* GL_TEXTURE_WRAP_S */
-/* GL_TEXTURE_WRAP_T */
-
-#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
-#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
-
-/* HintMode */
-#define GL_DONT_CARE 0x1100
-#define GL_FASTEST 0x1101
-#define GL_NICEST 0x1102
-
-/* HintTarget */
-#define GL_GENERATE_MIPMAP_HINT 0x8192
-
-/* DataType */
-#define GL_BYTE 0x1400
-#define GL_UNSIGNED_BYTE 0x1401
-#define GL_SHORT 0x1402
-#define GL_UNSIGNED_SHORT 0x1403
-#define GL_INT 0x1404
-#define GL_UNSIGNED_INT 0x1405
-#define GL_FLOAT 0x1406
-#define GL_FIXED 0x140C
-
-/* PixelFormat */
-#define GL_DEPTH_COMPONENT 0x1902
-#define GL_ALPHA 0x1906
-#define GL_RGB 0x1907
-#define GL_RGBA 0x1908
-#define GL_LUMINANCE 0x1909
-#define GL_LUMINANCE_ALPHA 0x190A
-
-/* PixelType */
-/* GL_UNSIGNED_BYTE */
-#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
-#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
-#define GL_UNSIGNED_SHORT_5_6_5 0x8363
-
-/* Shaders */
-#define GL_FRAGMENT_SHADER 0x8B30
-#define GL_VERTEX_SHADER 0x8B31
-#define GL_MAX_VERTEX_ATTRIBS 0x8869
-#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
-#define GL_MAX_VARYING_VECTORS 0x8DFC
-#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
-#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
-#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
-#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
-#define GL_SHADER_TYPE 0x8B4F
-#define GL_DELETE_STATUS 0x8B80
-#define GL_LINK_STATUS 0x8B82
-#define GL_VALIDATE_STATUS 0x8B83
-#define GL_ATTACHED_SHADERS 0x8B85
-#define GL_ACTIVE_UNIFORMS 0x8B86
-#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
-#define GL_ACTIVE_ATTRIBUTES 0x8B89
-#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
-#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
-#define GL_CURRENT_PROGRAM 0x8B8D
-
-/* StencilFunction */
-#define GL_NEVER 0x0200
-#define GL_LESS 0x0201
-#define GL_EQUAL 0x0202
-#define GL_LEQUAL 0x0203
-#define GL_GREATER 0x0204
-#define GL_NOTEQUAL 0x0205
-#define GL_GEQUAL 0x0206
-#define GL_ALWAYS 0x0207
-
-/* StencilOp */
-/* GL_ZERO */
-#define GL_KEEP 0x1E00
-#define GL_REPLACE 0x1E01
-#define GL_INCR 0x1E02
-#define GL_DECR 0x1E03
-#define GL_INVERT 0x150A
-#define GL_INCR_WRAP 0x8507
-#define GL_DECR_WRAP 0x8508
-
-/* StringName */
-#define GL_VENDOR 0x1F00
-#define GL_RENDERER 0x1F01
-#define GL_VERSION 0x1F02
-#define GL_EXTENSIONS 0x1F03
-
-/* TextureMagFilter */
-#define GL_NEAREST 0x2600
-#define GL_LINEAR 0x2601
-
-/* TextureMinFilter */
-/* GL_NEAREST */
-/* GL_LINEAR */
-#define GL_NEAREST_MIPMAP_NEAREST 0x2700
-#define GL_LINEAR_MIPMAP_NEAREST 0x2701
-#define GL_NEAREST_MIPMAP_LINEAR 0x2702
-#define GL_LINEAR_MIPMAP_LINEAR 0x2703
-
-/* TextureParameterName */
-#define GL_TEXTURE_MAG_FILTER 0x2800
-#define GL_TEXTURE_MIN_FILTER 0x2801
-#define GL_TEXTURE_WRAP_S 0x2802
-#define GL_TEXTURE_WRAP_T 0x2803
-
-/* TextureTarget */
-/* GL_TEXTURE_2D */
-#define GL_TEXTURE 0x1702
-
-#define GL_TEXTURE_CUBE_MAP 0x8513
-#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514
-#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
-#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
-#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
-#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
-#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
-#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
-#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
-
-/* TextureUnit */
-#define GL_TEXTURE0 0x84C0
-#define GL_TEXTURE1 0x84C1
-#define GL_TEXTURE2 0x84C2
-#define GL_TEXTURE3 0x84C3
-#define GL_TEXTURE4 0x84C4
-#define GL_TEXTURE5 0x84C5
-#define GL_TEXTURE6 0x84C6
-#define GL_TEXTURE7 0x84C7
-#define GL_TEXTURE8 0x84C8
-#define GL_TEXTURE9 0x84C9
-#define GL_TEXTURE10 0x84CA
-#define GL_TEXTURE11 0x84CB
-#define GL_TEXTURE12 0x84CC
-#define GL_TEXTURE13 0x84CD
-#define GL_TEXTURE14 0x84CE
-#define GL_TEXTURE15 0x84CF
-#define GL_TEXTURE16 0x84D0
-#define GL_TEXTURE17 0x84D1
-#define GL_TEXTURE18 0x84D2
-#define GL_TEXTURE19 0x84D3
-#define GL_TEXTURE20 0x84D4
-#define GL_TEXTURE21 0x84D5
-#define GL_TEXTURE22 0x84D6
-#define GL_TEXTURE23 0x84D7
-#define GL_TEXTURE24 0x84D8
-#define GL_TEXTURE25 0x84D9
-#define GL_TEXTURE26 0x84DA
-#define GL_TEXTURE27 0x84DB
-#define GL_TEXTURE28 0x84DC
-#define GL_TEXTURE29 0x84DD
-#define GL_TEXTURE30 0x84DE
-#define GL_TEXTURE31 0x84DF
-#define GL_ACTIVE_TEXTURE 0x84E0
-
-/* TextureWrapMode */
-#define GL_REPEAT 0x2901
-#define GL_CLAMP_TO_EDGE 0x812F
-#define GL_MIRRORED_REPEAT 0x8370
-
-/* Uniform Types */
-#define GL_FLOAT_VEC2 0x8B50
-#define GL_FLOAT_VEC3 0x8B51
-#define GL_FLOAT_VEC4 0x8B52
-#define GL_INT_VEC2 0x8B53
-#define GL_INT_VEC3 0x8B54
-#define GL_INT_VEC4 0x8B55
-#define GL_BOOL 0x8B56
-#define GL_BOOL_VEC2 0x8B57
-#define GL_BOOL_VEC3 0x8B58
-#define GL_BOOL_VEC4 0x8B59
-#define GL_FLOAT_MAT2 0x8B5A
-#define GL_FLOAT_MAT3 0x8B5B
-#define GL_FLOAT_MAT4 0x8B5C
-#define GL_SAMPLER_2D 0x8B5E
-#define GL_SAMPLER_CUBE 0x8B60
-
-/* Vertex Arrays */
-#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
-#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
-#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
-#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
-#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
-#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
-#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
-
-/* Read Format */
-#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
-#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
-
-/* Shader Source */
-#define GL_COMPILE_STATUS 0x8B81
-#define GL_INFO_LOG_LENGTH 0x8B84
-#define GL_SHADER_SOURCE_LENGTH 0x8B88
-#define GL_SHADER_COMPILER 0x8DFA
-
-/* Shader Binary */
-#define GL_SHADER_BINARY_FORMATS 0x8DF8
-#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9
-
-/* Shader Precision-Specified Types */
-#define GL_LOW_FLOAT 0x8DF0
-#define GL_MEDIUM_FLOAT 0x8DF1
-#define GL_HIGH_FLOAT 0x8DF2
-#define GL_LOW_INT 0x8DF3
-#define GL_MEDIUM_INT 0x8DF4
-#define GL_HIGH_INT 0x8DF5
-
-/* Framebuffer Object. */
-#define GL_FRAMEBUFFER 0x8D40
-#define GL_RENDERBUFFER 0x8D41
-
-#define GL_RGBA4 0x8056
-#define GL_RGB5_A1 0x8057
-#define GL_RGB565 0x8D62
-#define GL_DEPTH_COMPONENT16 0x81A5
-#define GL_STENCIL_INDEX8 0x8D48
-
-#define GL_RENDERBUFFER_WIDTH 0x8D42
-#define GL_RENDERBUFFER_HEIGHT 0x8D43
-#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44
-#define GL_RENDERBUFFER_RED_SIZE 0x8D50
-#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51
-#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52
-#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53
-#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54
-#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55
-
-#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0
-#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1
-#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2
-#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
-
-#define GL_COLOR_ATTACHMENT0 0x8CE0
-#define GL_DEPTH_ATTACHMENT 0x8D00
-#define GL_STENCIL_ATTACHMENT 0x8D20
-
-#define GL_NONE 0
-
-#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
-#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
-#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
-#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9
-#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
-
-#define GL_FRAMEBUFFER_BINDING 0x8CA6
-#define GL_RENDERBUFFER_BINDING 0x8CA7
-#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
-
-#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
-
-/*-------------------------------------------------------------------------
- * GL core functions.
- *-----------------------------------------------------------------------*/
-
-GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture);
-GL_APICALL void GL_APIENTRY glAttachShader (GLuint program, GLuint shader);
-GL_APICALL void GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar* name);
-GL_APICALL void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer);
-GL_APICALL void GL_APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer);
-GL_APICALL void GL_APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer);
-GL_APICALL void GL_APIENTRY glBindTexture (GLenum target, GLuint texture);
-GL_APICALL void GL_APIENTRY glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
-GL_APICALL void GL_APIENTRY glBlendEquation ( GLenum mode );
-GL_APICALL void GL_APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha);
-GL_APICALL void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor);
-GL_APICALL void GL_APIENTRY glBlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
-GL_APICALL void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
-GL_APICALL void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
-GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatus (GLenum target);
-GL_APICALL void GL_APIENTRY glClear (GLbitfield mask);
-GL_APICALL void GL_APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
-GL_APICALL void GL_APIENTRY glClearDepthf (GLclampf depth);
-GL_APICALL void GL_APIENTRY glClearStencil (GLint s);
-GL_APICALL void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
-GL_APICALL void GL_APIENTRY glCompileShader (GLuint shader);
-GL_APICALL void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data);
-GL_APICALL void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data);
-GL_APICALL void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
-GL_APICALL void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
-GL_APICALL GLuint GL_APIENTRY glCreateProgram (void);
-GL_APICALL GLuint GL_APIENTRY glCreateShader (GLenum type);
-GL_APICALL void GL_APIENTRY glCullFace (GLenum mode);
-GL_APICALL void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint* buffers);
-GL_APICALL void GL_APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint* framebuffers);
-GL_APICALL void GL_APIENTRY glDeleteProgram (GLuint program);
-GL_APICALL void GL_APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint* renderbuffers);
-GL_APICALL void GL_APIENTRY glDeleteShader (GLuint shader);
-GL_APICALL void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint* textures);
-GL_APICALL void GL_APIENTRY glDepthFunc (GLenum func);
-GL_APICALL void GL_APIENTRY glDepthMask (GLboolean flag);
-GL_APICALL void GL_APIENTRY glDepthRangef (GLclampf zNear, GLclampf zFar);
-GL_APICALL void GL_APIENTRY glDetachShader (GLuint program, GLuint shader);
-GL_APICALL void GL_APIENTRY glDisable (GLenum cap);
-GL_APICALL void GL_APIENTRY glDisableVertexAttribArray (GLuint index);
-GL_APICALL void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);
-GL_APICALL void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid* indices);
-GL_APICALL void GL_APIENTRY glEnable (GLenum cap);
-GL_APICALL void GL_APIENTRY glEnableVertexAttribArray (GLuint index);
-GL_APICALL void GL_APIENTRY glFinish (void);
-GL_APICALL void GL_APIENTRY glFlush (void);
-GL_APICALL void GL_APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
-GL_APICALL void GL_APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
-GL_APICALL void GL_APIENTRY glFrontFace (GLenum mode);
-GL_APICALL void GL_APIENTRY glGenBuffers (GLsizei n, GLuint* buffers);
-GL_APICALL void GL_APIENTRY glGenerateMipmap (GLenum target);
-GL_APICALL void GL_APIENTRY glGenFramebuffers (GLsizei n, GLuint* framebuffers);
-GL_APICALL void GL_APIENTRY glGenRenderbuffers (GLsizei n, GLuint* renderbuffers);
-GL_APICALL void GL_APIENTRY glGenTextures (GLsizei n, GLuint* textures);
-GL_APICALL void GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
-GL_APICALL void GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
-GL_APICALL void GL_APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders);
-GL_APICALL GLint GL_APIENTRY glGetAttribLocation (GLuint program, const GLchar* name);
-GL_APICALL void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean* params);
-GL_APICALL void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params);
-GL_APICALL GLenum GL_APIENTRY glGetError (void);
-GL_APICALL void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat* params);
-GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params);
-GL_APICALL void GL_APIENTRY glGetIntegerv (GLenum pname, GLint* params);
-GL_APICALL void GL_APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint* params);
-GL_APICALL void GL_APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog);
-GL_APICALL void GL_APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params);
-GL_APICALL void GL_APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint* params);
-GL_APICALL void GL_APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog);
-GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
-GL_APICALL void GL_APIENTRY glGetShaderSource (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source);
-GL_APICALL const GLubyte* GL_APIENTRY glGetString (GLenum name);
-GL_APICALL void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat* params);
-GL_APICALL void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint* params);
-GL_APICALL void GL_APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat* params);
-GL_APICALL void GL_APIENTRY glGetUniformiv (GLuint program, GLint location, GLint* params);
-GL_APICALL GLint GL_APIENTRY glGetUniformLocation (GLuint program, const GLchar* name);
-GL_APICALL void GL_APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params);
-GL_APICALL void GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint* params);
-GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, GLvoid** pointer);
-GL_APICALL void GL_APIENTRY glHint (GLenum target, GLenum mode);
-GL_APICALL GLboolean GL_APIENTRY glIsBuffer (GLuint buffer);
-GL_APICALL GLboolean GL_APIENTRY glIsEnabled (GLenum cap);
-GL_APICALL GLboolean GL_APIENTRY glIsFramebuffer (GLuint framebuffer);
-GL_APICALL GLboolean GL_APIENTRY glIsProgram (GLuint program);
-GL_APICALL GLboolean GL_APIENTRY glIsRenderbuffer (GLuint renderbuffer);
-GL_APICALL GLboolean GL_APIENTRY glIsShader (GLuint shader);
-GL_APICALL GLboolean GL_APIENTRY glIsTexture (GLuint texture);
-GL_APICALL void GL_APIENTRY glLineWidth (GLfloat width);
-GL_APICALL void GL_APIENTRY glLinkProgram (GLuint program);
-GL_APICALL void GL_APIENTRY glPixelStorei (GLenum pname, GLint param);
-GL_APICALL void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units);
-GL_APICALL void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels);
-GL_APICALL void GL_APIENTRY glReleaseShaderCompiler (void);
-GL_APICALL void GL_APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
-GL_APICALL void GL_APIENTRY glSampleCoverage (GLclampf value, GLboolean invert);
-GL_APICALL void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
-GL_APICALL void GL_APIENTRY glShaderBinary (GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length);
-GL_APICALL void GL_APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length);
-GL_APICALL void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask);
-GL_APICALL void GL_APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask);
-GL_APICALL void GL_APIENTRY glStencilMask (GLuint mask);
-GL_APICALL void GL_APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask);
-GL_APICALL void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass);
-GL_APICALL void GL_APIENTRY glStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
-GL_APICALL void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
-GL_APICALL void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param);
-GL_APICALL void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat* params);
-GL_APICALL void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
-GL_APICALL void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint* params);
-GL_APICALL void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels);
-GL_APICALL void GL_APIENTRY glUniform1f (GLint location, GLfloat x);
-GL_APICALL void GL_APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat* v);
-GL_APICALL void GL_APIENTRY glUniform1i (GLint location, GLint x);
-GL_APICALL void GL_APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint* v);
-GL_APICALL void GL_APIENTRY glUniform2f (GLint location, GLfloat x, GLfloat y);
-GL_APICALL void GL_APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat* v);
-GL_APICALL void GL_APIENTRY glUniform2i (GLint location, GLint x, GLint y);
-GL_APICALL void GL_APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint* v);
-GL_APICALL void GL_APIENTRY glUniform3f (GLint location, GLfloat x, GLfloat y, GLfloat z);
-GL_APICALL void GL_APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat* v);
-GL_APICALL void GL_APIENTRY glUniform3i (GLint location, GLint x, GLint y, GLint z);
-GL_APICALL void GL_APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint* v);
-GL_APICALL void GL_APIENTRY glUniform4f (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
-GL_APICALL void GL_APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat* v);
-GL_APICALL void GL_APIENTRY glUniform4i (GLint location, GLint x, GLint y, GLint z, GLint w);
-GL_APICALL void GL_APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint* v);
-GL_APICALL void GL_APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
-GL_APICALL void GL_APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
-GL_APICALL void GL_APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
-GL_APICALL void GL_APIENTRY glUseProgram (GLuint program);
-GL_APICALL void GL_APIENTRY glValidateProgram (GLuint program);
-GL_APICALL void GL_APIENTRY glVertexAttrib1f (GLuint indx, GLfloat x);
-GL_APICALL void GL_APIENTRY glVertexAttrib1fv (GLuint indx, const GLfloat* values);
-GL_APICALL void GL_APIENTRY glVertexAttrib2f (GLuint indx, GLfloat x, GLfloat y);
-GL_APICALL void GL_APIENTRY glVertexAttrib2fv (GLuint indx, const GLfloat* values);
-GL_APICALL void GL_APIENTRY glVertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z);
-GL_APICALL void GL_APIENTRY glVertexAttrib3fv (GLuint indx, const GLfloat* values);
-GL_APICALL void GL_APIENTRY glVertexAttrib4f (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
-GL_APICALL void GL_APIENTRY glVertexAttrib4fv (GLuint indx, const GLfloat* values);
-GL_APICALL void GL_APIENTRY glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr);
-GL_APICALL void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __gl2_h_ */
+#ifndef __gl2_h_
+#define __gl2_h_
+
+/* $Revision: 20555 $ on $Date:: 2013-02-12 14:32:47 -0800 #$ */
+
+#include <GLES2/gl2platform.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+/*-------------------------------------------------------------------------
+ * Data type definitions
+ *-----------------------------------------------------------------------*/
+
+typedef void GLvoid;
+typedef char GLchar;
+typedef unsigned int GLenum;
+typedef unsigned char GLboolean;
+typedef unsigned int GLbitfield;
+typedef khronos_int8_t GLbyte;
+typedef short GLshort;
+typedef int GLint;
+typedef int GLsizei;
+typedef khronos_uint8_t GLubyte;
+typedef unsigned short GLushort;
+typedef unsigned int GLuint;
+typedef khronos_float_t GLfloat;
+typedef khronos_float_t GLclampf;
+typedef khronos_int32_t GLfixed;
+
+/* GL types for handling large vertex buffer objects */
+typedef khronos_intptr_t GLintptr;
+typedef khronos_ssize_t GLsizeiptr;
+
+/* OpenGL ES core versions */
+#define GL_ES_VERSION_2_0 1
+
+/* ClearBufferMask */
+#define GL_DEPTH_BUFFER_BIT 0x00000100
+#define GL_STENCIL_BUFFER_BIT 0x00000400
+#define GL_COLOR_BUFFER_BIT 0x00004000
+
+/* Boolean */
+#define GL_FALSE 0
+#define GL_TRUE 1
+
+/* BeginMode */
+#define GL_POINTS 0x0000
+#define GL_LINES 0x0001
+#define GL_LINE_LOOP 0x0002
+#define GL_LINE_STRIP 0x0003
+#define GL_TRIANGLES 0x0004
+#define GL_TRIANGLE_STRIP 0x0005
+#define GL_TRIANGLE_FAN 0x0006
+
+/* AlphaFunction (not supported in ES20) */
+/* GL_NEVER */
+/* GL_LESS */
+/* GL_EQUAL */
+/* GL_LEQUAL */
+/* GL_GREATER */
+/* GL_NOTEQUAL */
+/* GL_GEQUAL */
+/* GL_ALWAYS */
+
+/* BlendingFactorDest */
+#define GL_ZERO 0
+#define GL_ONE 1
+#define GL_SRC_COLOR 0x0300
+#define GL_ONE_MINUS_SRC_COLOR 0x0301
+#define GL_SRC_ALPHA 0x0302
+#define GL_ONE_MINUS_SRC_ALPHA 0x0303
+#define GL_DST_ALPHA 0x0304
+#define GL_ONE_MINUS_DST_ALPHA 0x0305
+
+/* BlendingFactorSrc */
+/* GL_ZERO */
+/* GL_ONE */
+#define GL_DST_COLOR 0x0306
+#define GL_ONE_MINUS_DST_COLOR 0x0307
+#define GL_SRC_ALPHA_SATURATE 0x0308
+/* GL_SRC_ALPHA */
+/* GL_ONE_MINUS_SRC_ALPHA */
+/* GL_DST_ALPHA */
+/* GL_ONE_MINUS_DST_ALPHA */
+
+/* BlendEquationSeparate */
+#define GL_FUNC_ADD 0x8006
+#define GL_BLEND_EQUATION 0x8009
+#define GL_BLEND_EQUATION_RGB 0x8009 /* same as BLEND_EQUATION */
+#define GL_BLEND_EQUATION_ALPHA 0x883D
+
+/* BlendSubtract */
+#define GL_FUNC_SUBTRACT 0x800A
+#define GL_FUNC_REVERSE_SUBTRACT 0x800B
+
+/* Separate Blend Functions */
+#define GL_BLEND_DST_RGB 0x80C8
+#define GL_BLEND_SRC_RGB 0x80C9
+#define GL_BLEND_DST_ALPHA 0x80CA
+#define GL_BLEND_SRC_ALPHA 0x80CB
+#define GL_CONSTANT_COLOR 0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
+#define GL_CONSTANT_ALPHA 0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
+#define GL_BLEND_COLOR 0x8005
+
+/* Buffer Objects */
+#define GL_ARRAY_BUFFER 0x8892
+#define GL_ELEMENT_ARRAY_BUFFER 0x8893
+#define GL_ARRAY_BUFFER_BINDING 0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
+
+#define GL_STREAM_DRAW 0x88E0
+#define GL_STATIC_DRAW 0x88E4
+#define GL_DYNAMIC_DRAW 0x88E8
+
+#define GL_BUFFER_SIZE 0x8764
+#define GL_BUFFER_USAGE 0x8765
+
+#define GL_CURRENT_VERTEX_ATTRIB 0x8626
+
+/* CullFaceMode */
+#define GL_FRONT 0x0404
+#define GL_BACK 0x0405
+#define GL_FRONT_AND_BACK 0x0408
+
+/* DepthFunction */
+/* GL_NEVER */
+/* GL_LESS */
+/* GL_EQUAL */
+/* GL_LEQUAL */
+/* GL_GREATER */
+/* GL_NOTEQUAL */
+/* GL_GEQUAL */
+/* GL_ALWAYS */
+
+/* EnableCap */
+#define GL_TEXTURE_2D 0x0DE1
+#define GL_CULL_FACE 0x0B44
+#define GL_BLEND 0x0BE2
+#define GL_DITHER 0x0BD0
+#define GL_STENCIL_TEST 0x0B90
+#define GL_DEPTH_TEST 0x0B71
+#define GL_SCISSOR_TEST 0x0C11
+#define GL_POLYGON_OFFSET_FILL 0x8037
+#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
+#define GL_SAMPLE_COVERAGE 0x80A0
+
+/* ErrorCode */
+#define GL_NO_ERROR 0
+#define GL_INVALID_ENUM 0x0500
+#define GL_INVALID_VALUE 0x0501
+#define GL_INVALID_OPERATION 0x0502
+#define GL_OUT_OF_MEMORY 0x0505
+
+/* FrontFaceDirection */
+#define GL_CW 0x0900
+#define GL_CCW 0x0901
+
+/* GetPName */
+#define GL_LINE_WIDTH 0x0B21
+#define GL_ALIASED_POINT_SIZE_RANGE 0x846D
+#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
+#define GL_CULL_FACE_MODE 0x0B45
+#define GL_FRONT_FACE 0x0B46
+#define GL_DEPTH_RANGE 0x0B70
+#define GL_DEPTH_WRITEMASK 0x0B72
+#define GL_DEPTH_CLEAR_VALUE 0x0B73
+#define GL_DEPTH_FUNC 0x0B74
+#define GL_STENCIL_CLEAR_VALUE 0x0B91
+#define GL_STENCIL_FUNC 0x0B92
+#define GL_STENCIL_FAIL 0x0B94
+#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
+#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
+#define GL_STENCIL_REF 0x0B97
+#define GL_STENCIL_VALUE_MASK 0x0B93
+#define GL_STENCIL_WRITEMASK 0x0B98
+#define GL_STENCIL_BACK_FUNC 0x8800
+#define GL_STENCIL_BACK_FAIL 0x8801
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803
+#define GL_STENCIL_BACK_REF 0x8CA3
+#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4
+#define GL_STENCIL_BACK_WRITEMASK 0x8CA5
+#define GL_VIEWPORT 0x0BA2
+#define GL_SCISSOR_BOX 0x0C10
+/* GL_SCISSOR_TEST */
+#define GL_COLOR_CLEAR_VALUE 0x0C22
+#define GL_COLOR_WRITEMASK 0x0C23
+#define GL_UNPACK_ALIGNMENT 0x0CF5
+#define GL_PACK_ALIGNMENT 0x0D05
+#define GL_MAX_TEXTURE_SIZE 0x0D33
+#define GL_MAX_VIEWPORT_DIMS 0x0D3A
+#define GL_SUBPIXEL_BITS 0x0D50
+#define GL_RED_BITS 0x0D52
+#define GL_GREEN_BITS 0x0D53
+#define GL_BLUE_BITS 0x0D54
+#define GL_ALPHA_BITS 0x0D55
+#define GL_DEPTH_BITS 0x0D56
+#define GL_STENCIL_BITS 0x0D57
+#define GL_POLYGON_OFFSET_UNITS 0x2A00
+/* GL_POLYGON_OFFSET_FILL */
+#define GL_POLYGON_OFFSET_FACTOR 0x8038
+#define GL_TEXTURE_BINDING_2D 0x8069
+#define GL_SAMPLE_BUFFERS 0x80A8
+#define GL_SAMPLES 0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
+
+/* GetTextureParameter */
+/* GL_TEXTURE_MAG_FILTER */
+/* GL_TEXTURE_MIN_FILTER */
+/* GL_TEXTURE_WRAP_S */
+/* GL_TEXTURE_WRAP_T */
+
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
+
+/* HintMode */
+#define GL_DONT_CARE 0x1100
+#define GL_FASTEST 0x1101
+#define GL_NICEST 0x1102
+
+/* HintTarget */
+#define GL_GENERATE_MIPMAP_HINT 0x8192
+
+/* DataType */
+#define GL_BYTE 0x1400
+#define GL_UNSIGNED_BYTE 0x1401
+#define GL_SHORT 0x1402
+#define GL_UNSIGNED_SHORT 0x1403
+#define GL_INT 0x1404
+#define GL_UNSIGNED_INT 0x1405
+#define GL_FLOAT 0x1406
+#define GL_FIXED 0x140C
+
+/* PixelFormat */
+#define GL_DEPTH_COMPONENT 0x1902
+#define GL_ALPHA 0x1906
+#define GL_RGB 0x1907
+#define GL_RGBA 0x1908
+#define GL_LUMINANCE 0x1909
+#define GL_LUMINANCE_ALPHA 0x190A
+
+/* PixelType */
+/* GL_UNSIGNED_BYTE */
+#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
+#define GL_UNSIGNED_SHORT_5_6_5 0x8363
+
+/* Shaders */
+#define GL_FRAGMENT_SHADER 0x8B30
+#define GL_VERTEX_SHADER 0x8B31
+#define GL_MAX_VERTEX_ATTRIBS 0x8869
+#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
+#define GL_MAX_VARYING_VECTORS 0x8DFC
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
+#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
+#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
+#define GL_SHADER_TYPE 0x8B4F
+#define GL_DELETE_STATUS 0x8B80
+#define GL_LINK_STATUS 0x8B82
+#define GL_VALIDATE_STATUS 0x8B83
+#define GL_ATTACHED_SHADERS 0x8B85
+#define GL_ACTIVE_UNIFORMS 0x8B86
+#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
+#define GL_ACTIVE_ATTRIBUTES 0x8B89
+#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
+#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
+#define GL_CURRENT_PROGRAM 0x8B8D
+
+/* StencilFunction */
+#define GL_NEVER 0x0200
+#define GL_LESS 0x0201
+#define GL_EQUAL 0x0202
+#define GL_LEQUAL 0x0203
+#define GL_GREATER 0x0204
+#define GL_NOTEQUAL 0x0205
+#define GL_GEQUAL 0x0206
+#define GL_ALWAYS 0x0207
+
+/* StencilOp */
+/* GL_ZERO */
+#define GL_KEEP 0x1E00
+#define GL_REPLACE 0x1E01
+#define GL_INCR 0x1E02
+#define GL_DECR 0x1E03
+#define GL_INVERT 0x150A
+#define GL_INCR_WRAP 0x8507
+#define GL_DECR_WRAP 0x8508
+
+/* StringName */
+#define GL_VENDOR 0x1F00
+#define GL_RENDERER 0x1F01
+#define GL_VERSION 0x1F02
+#define GL_EXTENSIONS 0x1F03
+
+/* TextureMagFilter */
+#define GL_NEAREST 0x2600
+#define GL_LINEAR 0x2601
+
+/* TextureMinFilter */
+/* GL_NEAREST */
+/* GL_LINEAR */
+#define GL_NEAREST_MIPMAP_NEAREST 0x2700
+#define GL_LINEAR_MIPMAP_NEAREST 0x2701
+#define GL_NEAREST_MIPMAP_LINEAR 0x2702
+#define GL_LINEAR_MIPMAP_LINEAR 0x2703
+
+/* TextureParameterName */
+#define GL_TEXTURE_MAG_FILTER 0x2800
+#define GL_TEXTURE_MIN_FILTER 0x2801
+#define GL_TEXTURE_WRAP_S 0x2802
+#define GL_TEXTURE_WRAP_T 0x2803
+
+/* TextureTarget */
+/* GL_TEXTURE_2D */
+#define GL_TEXTURE 0x1702
+
+#define GL_TEXTURE_CUBE_MAP 0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
+
+/* TextureUnit */
+#define GL_TEXTURE0 0x84C0
+#define GL_TEXTURE1 0x84C1
+#define GL_TEXTURE2 0x84C2
+#define GL_TEXTURE3 0x84C3
+#define GL_TEXTURE4 0x84C4
+#define GL_TEXTURE5 0x84C5
+#define GL_TEXTURE6 0x84C6
+#define GL_TEXTURE7 0x84C7
+#define GL_TEXTURE8 0x84C8
+#define GL_TEXTURE9 0x84C9
+#define GL_TEXTURE10 0x84CA
+#define GL_TEXTURE11 0x84CB
+#define GL_TEXTURE12 0x84CC
+#define GL_TEXTURE13 0x84CD
+#define GL_TEXTURE14 0x84CE
+#define GL_TEXTURE15 0x84CF
+#define GL_TEXTURE16 0x84D0
+#define GL_TEXTURE17 0x84D1
+#define GL_TEXTURE18 0x84D2
+#define GL_TEXTURE19 0x84D3
+#define GL_TEXTURE20 0x84D4
+#define GL_TEXTURE21 0x84D5
+#define GL_TEXTURE22 0x84D6
+#define GL_TEXTURE23 0x84D7
+#define GL_TEXTURE24 0x84D8
+#define GL_TEXTURE25 0x84D9
+#define GL_TEXTURE26 0x84DA
+#define GL_TEXTURE27 0x84DB
+#define GL_TEXTURE28 0x84DC
+#define GL_TEXTURE29 0x84DD
+#define GL_TEXTURE30 0x84DE
+#define GL_TEXTURE31 0x84DF
+#define GL_ACTIVE_TEXTURE 0x84E0
+
+/* TextureWrapMode */
+#define GL_REPEAT 0x2901
+#define GL_CLAMP_TO_EDGE 0x812F
+#define GL_MIRRORED_REPEAT 0x8370
+
+/* Uniform Types */
+#define GL_FLOAT_VEC2 0x8B50
+#define GL_FLOAT_VEC3 0x8B51
+#define GL_FLOAT_VEC4 0x8B52
+#define GL_INT_VEC2 0x8B53
+#define GL_INT_VEC3 0x8B54
+#define GL_INT_VEC4 0x8B55
+#define GL_BOOL 0x8B56
+#define GL_BOOL_VEC2 0x8B57
+#define GL_BOOL_VEC3 0x8B58
+#define GL_BOOL_VEC4 0x8B59
+#define GL_FLOAT_MAT2 0x8B5A
+#define GL_FLOAT_MAT3 0x8B5B
+#define GL_FLOAT_MAT4 0x8B5C
+#define GL_SAMPLER_2D 0x8B5E
+#define GL_SAMPLER_CUBE 0x8B60
+
+/* Vertex Arrays */
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
+
+/* Read Format */
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
+
+/* Shader Source */
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_INFO_LOG_LENGTH 0x8B84
+#define GL_SHADER_SOURCE_LENGTH 0x8B88
+#define GL_SHADER_COMPILER 0x8DFA
+
+/* Shader Binary */
+#define GL_SHADER_BINARY_FORMATS 0x8DF8
+#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9
+
+/* Shader Precision-Specified Types */
+#define GL_LOW_FLOAT 0x8DF0
+#define GL_MEDIUM_FLOAT 0x8DF1
+#define GL_HIGH_FLOAT 0x8DF2
+#define GL_LOW_INT 0x8DF3
+#define GL_MEDIUM_INT 0x8DF4
+#define GL_HIGH_INT 0x8DF5
+
+/* Framebuffer Object. */
+#define GL_FRAMEBUFFER 0x8D40
+#define GL_RENDERBUFFER 0x8D41
+
+#define GL_RGBA4 0x8056
+#define GL_RGB5_A1 0x8057
+#define GL_RGB565 0x8D62
+#define GL_DEPTH_COMPONENT16 0x81A5
+#define GL_STENCIL_INDEX8 0x8D48
+
+#define GL_RENDERBUFFER_WIDTH 0x8D42
+#define GL_RENDERBUFFER_HEIGHT 0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44
+#define GL_RENDERBUFFER_RED_SIZE 0x8D50
+#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51
+#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52
+#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53
+#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54
+#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55
+
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
+
+#define GL_COLOR_ATTACHMENT0 0x8CE0
+#define GL_DEPTH_ATTACHMENT 0x8D00
+#define GL_STENCIL_ATTACHMENT 0x8D20
+
+#define GL_NONE 0
+
+#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9
+#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
+
+#define GL_FRAMEBUFFER_BINDING 0x8CA6
+#define GL_RENDERBUFFER_BINDING 0x8CA7
+#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
+
+#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
+
+/*-------------------------------------------------------------------------
+ * GL core functions.
+ *-----------------------------------------------------------------------*/
+
+GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture);
+GL_APICALL void GL_APIENTRY glAttachShader (GLuint program, GLuint shader);
+GL_APICALL void GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar* name);
+GL_APICALL void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer);
+GL_APICALL void GL_APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer);
+GL_APICALL void GL_APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer);
+GL_APICALL void GL_APIENTRY glBindTexture (GLenum target, GLuint texture);
+GL_APICALL void GL_APIENTRY glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+GL_APICALL void GL_APIENTRY glBlendEquation ( GLenum mode );
+GL_APICALL void GL_APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha);
+GL_APICALL void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor);
+GL_APICALL void GL_APIENTRY glBlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+GL_APICALL void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
+GL_APICALL void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
+GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatus (GLenum target);
+GL_APICALL void GL_APIENTRY glClear (GLbitfield mask);
+GL_APICALL void GL_APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+GL_APICALL void GL_APIENTRY glClearDepthf (GLclampf depth);
+GL_APICALL void GL_APIENTRY glClearStencil (GLint s);
+GL_APICALL void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+GL_APICALL void GL_APIENTRY glCompileShader (GLuint shader);
+GL_APICALL void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+GL_APICALL void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL GLuint GL_APIENTRY glCreateProgram (void);
+GL_APICALL GLuint GL_APIENTRY glCreateShader (GLenum type);
+GL_APICALL void GL_APIENTRY glCullFace (GLenum mode);
+GL_APICALL void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint* buffers);
+GL_APICALL void GL_APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint* framebuffers);
+GL_APICALL void GL_APIENTRY glDeleteProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint* renderbuffers);
+GL_APICALL void GL_APIENTRY glDeleteShader (GLuint shader);
+GL_APICALL void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint* textures);
+GL_APICALL void GL_APIENTRY glDepthFunc (GLenum func);
+GL_APICALL void GL_APIENTRY glDepthMask (GLboolean flag);
+GL_APICALL void GL_APIENTRY glDepthRangef (GLclampf zNear, GLclampf zFar);
+GL_APICALL void GL_APIENTRY glDetachShader (GLuint program, GLuint shader);
+GL_APICALL void GL_APIENTRY glDisable (GLenum cap);
+GL_APICALL void GL_APIENTRY glDisableVertexAttribArray (GLuint index);
+GL_APICALL void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);
+GL_APICALL void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid* indices);
+GL_APICALL void GL_APIENTRY glEnable (GLenum cap);
+GL_APICALL void GL_APIENTRY glEnableVertexAttribArray (GLuint index);
+GL_APICALL void GL_APIENTRY glFinish (void);
+GL_APICALL void GL_APIENTRY glFlush (void);
+GL_APICALL void GL_APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+GL_APICALL void GL_APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GL_APICALL void GL_APIENTRY glFrontFace (GLenum mode);
+GL_APICALL void GL_APIENTRY glGenBuffers (GLsizei n, GLuint* buffers);
+GL_APICALL void GL_APIENTRY glGenerateMipmap (GLenum target);
+GL_APICALL void GL_APIENTRY glGenFramebuffers (GLsizei n, GLuint* framebuffers);
+GL_APICALL void GL_APIENTRY glGenRenderbuffers (GLsizei n, GLuint* renderbuffers);
+GL_APICALL void GL_APIENTRY glGenTextures (GLsizei n, GLuint* textures);
+GL_APICALL void GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
+GL_APICALL void GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
+GL_APICALL void GL_APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders);
+GL_APICALL GLint GL_APIENTRY glGetAttribLocation (GLuint program, const GLchar* name);
+GL_APICALL void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean* params);
+GL_APICALL void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL GLenum GL_APIENTRY glGetError (void);
+GL_APICALL void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetIntegerv (GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog);
+GL_APICALL void GL_APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog);
+GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
+GL_APICALL void GL_APIENTRY glGetShaderSource (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source);
+GL_APICALL const GLubyte* GL_APIENTRY glGetString (GLenum name);
+GL_APICALL void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetUniformiv (GLuint program, GLint location, GLint* params);
+GL_APICALL GLint GL_APIENTRY glGetUniformLocation (GLuint program, const GLchar* name);
+GL_APICALL void GL_APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, GLvoid** pointer);
+GL_APICALL void GL_APIENTRY glHint (GLenum target, GLenum mode);
+GL_APICALL GLboolean GL_APIENTRY glIsBuffer (GLuint buffer);
+GL_APICALL GLboolean GL_APIENTRY glIsEnabled (GLenum cap);
+GL_APICALL GLboolean GL_APIENTRY glIsFramebuffer (GLuint framebuffer);
+GL_APICALL GLboolean GL_APIENTRY glIsProgram (GLuint program);
+GL_APICALL GLboolean GL_APIENTRY glIsRenderbuffer (GLuint renderbuffer);
+GL_APICALL GLboolean GL_APIENTRY glIsShader (GLuint shader);
+GL_APICALL GLboolean GL_APIENTRY glIsTexture (GLuint texture);
+GL_APICALL void GL_APIENTRY glLineWidth (GLfloat width);
+GL_APICALL void GL_APIENTRY glLinkProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glPixelStorei (GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units);
+GL_APICALL void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glReleaseShaderCompiler (void);
+GL_APICALL void GL_APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glSampleCoverage (GLclampf value, GLboolean invert);
+GL_APICALL void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glShaderBinary (GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length);
+GL_APICALL void GL_APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length);
+GL_APICALL void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilMask (GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass);
+GL_APICALL void GL_APIENTRY glStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
+GL_APICALL void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param);
+GL_APICALL void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat* params);
+GL_APICALL void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint* params);
+GL_APICALL void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glUniform1f (GLint location, GLfloat x);
+GL_APICALL void GL_APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform1i (GLint location, GLint x);
+GL_APICALL void GL_APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform2f (GLint location, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform2i (GLint location, GLint x, GLint y);
+GL_APICALL void GL_APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform3f (GLint location, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform3i (GLint location, GLint x, GLint y, GLint z);
+GL_APICALL void GL_APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform4f (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform4i (GLint location, GLint x, GLint y, GLint z, GLint w);
+GL_APICALL void GL_APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUseProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glValidateProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glVertexAttrib1f (GLuint indx, GLfloat x);
+GL_APICALL void GL_APIENTRY glVertexAttrib1fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib2f (GLuint indx, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glVertexAttrib2fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glVertexAttrib3fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib4f (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glVertexAttrib4fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr);
+GL_APICALL void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gl2_h_ */
diff --git a/platform/winrt/include/GLES2/gl2ext.h b/platform/winrt/include/GLES2/gl2ext.h
index cc6997d4b2..d77fdbaebc 100644
--- a/platform/winrt/include/GLES2/gl2ext.h
+++ b/platform/winrt/include/GLES2/gl2ext.h
@@ -1,2013 +1,2013 @@
-#ifndef __gl2ext_h_
-#define __gl2ext_h_
-
-/* $Revision: 20795 $ on $Date:: 2013-03-07 01:01:58 -0800 #$ */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * This document is licensed under the SGI Free Software B License Version
- * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
- */
-
-#ifndef GL_APIENTRYP
-# define GL_APIENTRYP GL_APIENTRY*
-#endif
-
-/*------------------------------------------------------------------------*
- * OES extension tokens
- *------------------------------------------------------------------------*/
-
-/* GL_OES_compressed_ETC1_RGB8_texture */
-#ifndef GL_OES_compressed_ETC1_RGB8_texture
-#define GL_ETC1_RGB8_OES 0x8D64
-#endif
-
-/* GL_OES_compressed_paletted_texture */
-#ifndef GL_OES_compressed_paletted_texture
-#define GL_PALETTE4_RGB8_OES 0x8B90
-#define GL_PALETTE4_RGBA8_OES 0x8B91
-#define GL_PALETTE4_R5_G6_B5_OES 0x8B92
-#define GL_PALETTE4_RGBA4_OES 0x8B93
-#define GL_PALETTE4_RGB5_A1_OES 0x8B94
-#define GL_PALETTE8_RGB8_OES 0x8B95
-#define GL_PALETTE8_RGBA8_OES 0x8B96
-#define GL_PALETTE8_R5_G6_B5_OES 0x8B97
-#define GL_PALETTE8_RGBA4_OES 0x8B98
-#define GL_PALETTE8_RGB5_A1_OES 0x8B99
-#endif
-
-/* GL_OES_depth24 */
-#ifndef GL_OES_depth24
-#define GL_DEPTH_COMPONENT24_OES 0x81A6
-#endif
-
-/* GL_OES_depth32 */
-#ifndef GL_OES_depth32
-#define GL_DEPTH_COMPONENT32_OES 0x81A7
-#endif
-
-/* GL_OES_depth_texture */
-/* No new tokens introduced by this extension. */
-
-/* GL_OES_EGL_image */
-#ifndef GL_OES_EGL_image
-typedef void* GLeglImageOES;
-#endif
-
-/* GL_OES_EGL_image_external */
-#ifndef GL_OES_EGL_image_external
-/* GLeglImageOES defined in GL_OES_EGL_image already. */
-#define GL_TEXTURE_EXTERNAL_OES 0x8D65
-#define GL_SAMPLER_EXTERNAL_OES 0x8D66
-#define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67
-#define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES 0x8D68
-#endif
-
-/* GL_OES_element_index_uint */
-#ifndef GL_OES_element_index_uint
-#define GL_UNSIGNED_INT 0x1405
-#endif
-
-/* GL_OES_get_program_binary */
-#ifndef GL_OES_get_program_binary
-#define GL_PROGRAM_BINARY_LENGTH_OES 0x8741
-#define GL_NUM_PROGRAM_BINARY_FORMATS_OES 0x87FE
-#define GL_PROGRAM_BINARY_FORMATS_OES 0x87FF
-#endif
-
-/* GL_OES_mapbuffer */
-#ifndef GL_OES_mapbuffer
-#define GL_WRITE_ONLY_OES 0x88B9
-#define GL_BUFFER_ACCESS_OES 0x88BB
-#define GL_BUFFER_MAPPED_OES 0x88BC
-#define GL_BUFFER_MAP_POINTER_OES 0x88BD
-#endif
-
-/* GL_OES_packed_depth_stencil */
-#ifndef GL_OES_packed_depth_stencil
-#define GL_DEPTH_STENCIL_OES 0x84F9
-#define GL_UNSIGNED_INT_24_8_OES 0x84FA
-#define GL_DEPTH24_STENCIL8_OES 0x88F0
-#endif
-
-/* GL_OES_required_internalformat */
-#ifndef GL_OES_required_internalformat
-#define GL_ALPHA8_OES 0x803C
-#define GL_DEPTH_COMPONENT16_OES 0x81A5
-/* reuse GL_DEPTH_COMPONENT24_OES */
-/* reuse GL_DEPTH24_STENCIL8_OES */
-/* reuse GL_DEPTH_COMPONENT32_OES */
-#define GL_LUMINANCE4_ALPHA4_OES 0x8043
-#define GL_LUMINANCE8_ALPHA8_OES 0x8045
-#define GL_LUMINANCE8_OES 0x8040
-#define GL_RGBA4_OES 0x8056
-#define GL_RGB5_A1_OES 0x8057
-#define GL_RGB565_OES 0x8D62
-/* reuse GL_RGB8_OES */
-/* reuse GL_RGBA8_OES */
-/* reuse GL_RGB10_EXT */
-/* reuse GL_RGB10_A2_EXT */
-#endif
-
-/* GL_OES_rgb8_rgba8 */
-#ifndef GL_OES_rgb8_rgba8
-#define GL_RGB8_OES 0x8051
-#define GL_RGBA8_OES 0x8058
-#endif
-
-/* GL_OES_standard_derivatives */
-#ifndef GL_OES_standard_derivatives
-#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES 0x8B8B
-#endif
-
-/* GL_OES_stencil1 */
-#ifndef GL_OES_stencil1
-#define GL_STENCIL_INDEX1_OES 0x8D46
-#endif
-
-/* GL_OES_stencil4 */
-#ifndef GL_OES_stencil4
-#define GL_STENCIL_INDEX4_OES 0x8D47
-#endif
-
-#ifndef GL_OES_surfaceless_context
-#define GL_FRAMEBUFFER_UNDEFINED_OES 0x8219
-#endif
-
-/* GL_OES_texture_3D */
-#ifndef GL_OES_texture_3D
-#define GL_TEXTURE_WRAP_R_OES 0x8072
-#define GL_TEXTURE_3D_OES 0x806F
-#define GL_TEXTURE_BINDING_3D_OES 0x806A
-#define GL_MAX_3D_TEXTURE_SIZE_OES 0x8073
-#define GL_SAMPLER_3D_OES 0x8B5F
-#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_OES 0x8CD4
-#endif
-
-/* GL_OES_texture_float */
-/* No new tokens introduced by this extension. */
-
-/* GL_OES_texture_float_linear */
-/* No new tokens introduced by this extension. */
-
-/* GL_OES_texture_half_float */
-#ifndef GL_OES_texture_half_float
-#define GL_HALF_FLOAT_OES 0x8D61
-#endif
-
-/* GL_OES_texture_half_float_linear */
-/* No new tokens introduced by this extension. */
-
-/* GL_OES_texture_npot */
-/* No new tokens introduced by this extension. */
-
-/* GL_OES_vertex_array_object */
-#ifndef GL_OES_vertex_array_object
-#define GL_VERTEX_ARRAY_BINDING_OES 0x85B5
-#endif
-
-/* GL_OES_vertex_half_float */
-/* GL_HALF_FLOAT_OES defined in GL_OES_texture_half_float already. */
-
-/* GL_OES_vertex_type_10_10_10_2 */
-#ifndef GL_OES_vertex_type_10_10_10_2
-#define GL_UNSIGNED_INT_10_10_10_2_OES 0x8DF6
-#define GL_INT_10_10_10_2_OES 0x8DF7
-#endif
-
-/*------------------------------------------------------------------------*
- * KHR extension tokens
- *------------------------------------------------------------------------*/
-
-#ifndef GL_KHR_debug
-typedef void (GL_APIENTRYP GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,GLvoid *userParam);
-#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242
-#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243
-#define GL_DEBUG_CALLBACK_FUNCTION 0x8244
-#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245
-#define GL_DEBUG_SOURCE_API 0x8246
-#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247
-#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248
-#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249
-#define GL_DEBUG_SOURCE_APPLICATION 0x824A
-#define GL_DEBUG_SOURCE_OTHER 0x824B
-#define GL_DEBUG_TYPE_ERROR 0x824C
-#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D
-#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E
-#define GL_DEBUG_TYPE_PORTABILITY 0x824F
-#define GL_DEBUG_TYPE_PERFORMANCE 0x8250
-#define GL_DEBUG_TYPE_OTHER 0x8251
-#define GL_DEBUG_TYPE_MARKER 0x8268
-#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269
-#define GL_DEBUG_TYPE_POP_GROUP 0x826A
-#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B
-#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C
-#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D
-#define GL_BUFFER 0x82E0
-#define GL_SHADER 0x82E1
-#define GL_PROGRAM 0x82E2
-#define GL_QUERY 0x82E3
-/* PROGRAM_PIPELINE only in GL */
-#define GL_SAMPLER 0x82E6
-/* DISPLAY_LIST only in GL */
-#define GL_MAX_LABEL_LENGTH 0x82E8
-#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143
-#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144
-#define GL_DEBUG_LOGGED_MESSAGES 0x9145
-#define GL_DEBUG_SEVERITY_HIGH 0x9146
-#define GL_DEBUG_SEVERITY_MEDIUM 0x9147
-#define GL_DEBUG_SEVERITY_LOW 0x9148
-#define GL_DEBUG_OUTPUT 0x92E0
-#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
-#define GL_STACK_OVERFLOW 0x0503
-#define GL_STACK_UNDERFLOW 0x0504
-#endif
-
-#ifndef GL_KHR_texture_compression_astc_ldr
-#define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0
-#define GL_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1
-#define GL_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2
-#define GL_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3
-#define GL_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4
-#define GL_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5
-#define GL_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6
-#define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7
-#define GL_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8
-#define GL_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9
-#define GL_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA
-#define GL_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB
-#define GL_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC
-#define GL_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD
-#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0
-#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1
-#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2
-#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3
-#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4
-#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5
-#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6
-#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7
-#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8
-#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9
-#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA
-#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB
-#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC
-#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD
-#endif
-
-/*------------------------------------------------------------------------*
- * AMD extension tokens
- *------------------------------------------------------------------------*/
-
-/* GL_AMD_compressed_3DC_texture */
-#ifndef GL_AMD_compressed_3DC_texture
-#define GL_3DC_X_AMD 0x87F9
-#define GL_3DC_XY_AMD 0x87FA
-#endif
-
-/* GL_AMD_compressed_ATC_texture */
-#ifndef GL_AMD_compressed_ATC_texture
-#define GL_ATC_RGB_AMD 0x8C92
-#define GL_ATC_RGBA_EXPLICIT_ALPHA_AMD 0x8C93
-#define GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD 0x87EE
-#endif
-
-/* GL_AMD_performance_monitor */
-#ifndef GL_AMD_performance_monitor
-#define GL_COUNTER_TYPE_AMD 0x8BC0
-#define GL_COUNTER_RANGE_AMD 0x8BC1
-#define GL_UNSIGNED_INT64_AMD 0x8BC2
-#define GL_PERCENTAGE_AMD 0x8BC3
-#define GL_PERFMON_RESULT_AVAILABLE_AMD 0x8BC4
-#define GL_PERFMON_RESULT_SIZE_AMD 0x8BC5
-#define GL_PERFMON_RESULT_AMD 0x8BC6
-#endif
-
-/* GL_AMD_program_binary_Z400 */
-#ifndef GL_AMD_program_binary_Z400
-#define GL_Z400_BINARY_AMD 0x8740
-#endif
-
-/*------------------------------------------------------------------------*
- * ANGLE extension tokens
- *------------------------------------------------------------------------*/
-
-/* GL_ANGLE_depth_texture */
-#ifndef GL_ANGLE_depth_texture
-#define GL_DEPTH_COMPONENT 0x1902
-#define GL_DEPTH_STENCIL_OES 0x84F9
-#define GL_UNSIGNED_SHORT 0x1403
-#define GL_UNSIGNED_INT 0x1405
-#define GL_UNSIGNED_INT_24_8_OES 0x84FA
-#define GL_DEPTH_COMPONENT16 0x81A5
-#define GL_DEPTH_COMPONENT32_OES 0x81A7
-#define GL_DEPTH24_STENCIL8_OES 0x88F0
-#endif
-
-/* GL_ANGLE_framebuffer_blit */
-#ifndef GL_ANGLE_framebuffer_blit
-#define GL_READ_FRAMEBUFFER_ANGLE 0x8CA8
-#define GL_DRAW_FRAMEBUFFER_ANGLE 0x8CA9
-#define GL_DRAW_FRAMEBUFFER_BINDING_ANGLE 0x8CA6
-#define GL_READ_FRAMEBUFFER_BINDING_ANGLE 0x8CAA
-#endif
-
-/* GL_ANGLE_framebuffer_multisample */
-#ifndef GL_ANGLE_framebuffer_multisample
-#define GL_RENDERBUFFER_SAMPLES_ANGLE 0x8CAB
-#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE 0x8D56
-#define GL_MAX_SAMPLES_ANGLE 0x8D57
-#endif
-
-/* GL_ANGLE_instanced_arrays */
-#ifndef GL_ANGLE_instanced_arrays
-#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE 0x88FE
-#endif
-
-/* GL_ANGLE_pack_reverse_row_order */
-#ifndef GL_ANGLE_pack_reverse_row_order
-#define GL_PACK_REVERSE_ROW_ORDER_ANGLE 0x93A4
-#endif
-
-/* GL_ANGLE_program_binary */
-#ifndef GL_ANGLE_program_binary
-#define GL_PROGRAM_BINARY_ANGLE 0x93A6
-#endif
-
-/* GL_ANGLE_texture_compression_dxt3 */
-#ifndef GL_ANGLE_texture_compression_dxt3
-#define GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE 0x83F2
-#endif
-
-/* GL_ANGLE_texture_compression_dxt5 */
-#ifndef GL_ANGLE_texture_compression_dxt5
-#define GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE 0x83F3
-#endif
-
-/* GL_ANGLE_texture_usage */
-#ifndef GL_ANGLE_texture_usage
-#define GL_TEXTURE_USAGE_ANGLE 0x93A2
-#define GL_FRAMEBUFFER_ATTACHMENT_ANGLE 0x93A3
-#endif
-
-/* GL_ANGLE_translated_shader_source */
-#ifndef GL_ANGLE_translated_shader_source
-#define GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE 0x93A0
-#endif
-
-/*------------------------------------------------------------------------*
- * APPLE extension tokens
- *------------------------------------------------------------------------*/
-
-/* GL_APPLE_copy_texture_levels */
-/* No new tokens introduced by this extension. */
-
-/* GL_APPLE_framebuffer_multisample */
-#ifndef GL_APPLE_framebuffer_multisample
-#define GL_RENDERBUFFER_SAMPLES_APPLE 0x8CAB
-#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_APPLE 0x8D56
-#define GL_MAX_SAMPLES_APPLE 0x8D57
-#define GL_READ_FRAMEBUFFER_APPLE 0x8CA8
-#define GL_DRAW_FRAMEBUFFER_APPLE 0x8CA9
-#define GL_DRAW_FRAMEBUFFER_BINDING_APPLE 0x8CA6
-#define GL_READ_FRAMEBUFFER_BINDING_APPLE 0x8CAA
-#endif
-
-/* GL_APPLE_rgb_422 */
-#ifndef GL_APPLE_rgb_422
-#define GL_RGB_422_APPLE 0x8A1F
-#define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA
-#define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB
-#endif
-
-/* GL_APPLE_sync */
-#ifndef GL_APPLE_sync
-
-#ifndef __gl3_h_
-/* These types are defined with reference to <inttypes.h>
- * in the Apple extension spec, but here we use the Khronos
- * portable types in khrplatform.h, and assume those types
- * are always defined.
- * If any other extensions using these types are defined,
- * the typedefs must move out of this block and be shared.
- */
-typedef khronos_int64_t GLint64;
-typedef khronos_uint64_t GLuint64;
-typedef struct __GLsync *GLsync;
-#endif
-
-#define GL_SYNC_OBJECT_APPLE 0x8A53
-#define GL_MAX_SERVER_WAIT_TIMEOUT_APPLE 0x9111
-#define GL_OBJECT_TYPE_APPLE 0x9112
-#define GL_SYNC_CONDITION_APPLE 0x9113
-#define GL_SYNC_STATUS_APPLE 0x9114
-#define GL_SYNC_FLAGS_APPLE 0x9115
-#define GL_SYNC_FENCE_APPLE 0x9116
-#define GL_SYNC_GPU_COMMANDS_COMPLETE_APPLE 0x9117
-#define GL_UNSIGNALED_APPLE 0x9118
-#define GL_SIGNALED_APPLE 0x9119
-#define GL_ALREADY_SIGNALED_APPLE 0x911A
-#define GL_TIMEOUT_EXPIRED_APPLE 0x911B
-#define GL_CONDITION_SATISFIED_APPLE 0x911C
-#define GL_WAIT_FAILED_APPLE 0x911D
-#define GL_SYNC_FLUSH_COMMANDS_BIT_APPLE 0x00000001
-#define GL_TIMEOUT_IGNORED_APPLE 0xFFFFFFFFFFFFFFFFull
-#endif
-
-/* GL_APPLE_texture_format_BGRA8888 */
-#ifndef GL_APPLE_texture_format_BGRA8888
-#define GL_BGRA_EXT 0x80E1
-#endif
-
-/* GL_APPLE_texture_max_level */
-#ifndef GL_APPLE_texture_max_level
-#define GL_TEXTURE_MAX_LEVEL_APPLE 0x813D
-#endif
-
-/*------------------------------------------------------------------------*
- * ARM extension tokens
- *------------------------------------------------------------------------*/
-
-/* GL_ARM_mali_program_binary */
-#ifndef GL_ARM_mali_program_binary
-#define GL_MALI_PROGRAM_BINARY_ARM 0x8F61
-#endif
-
-/* GL_ARM_mali_shader_binary */
-#ifndef GL_ARM_mali_shader_binary
-#define GL_MALI_SHADER_BINARY_ARM 0x8F60
-#endif
-
-/* GL_ARM_rgba8 */
-/* No new tokens introduced by this extension. */
-
-/*------------------------------------------------------------------------*
- * EXT extension tokens
- *------------------------------------------------------------------------*/
-
-/* GL_EXT_blend_minmax */
-#ifndef GL_EXT_blend_minmax
-#define GL_MIN_EXT 0x8007
-#define GL_MAX_EXT 0x8008
-#endif
-
-/* GL_EXT_color_buffer_half_float */
-#ifndef GL_EXT_color_buffer_half_float
-#define GL_RGBA16F_EXT 0x881A
-#define GL_RGB16F_EXT 0x881B
-#define GL_RG16F_EXT 0x822F
-#define GL_R16F_EXT 0x822D
-#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT 0x8211
-#define GL_UNSIGNED_NORMALIZED_EXT 0x8C17
-#endif
-
-/* GL_EXT_debug_label */
-#ifndef GL_EXT_debug_label
-#define GL_PROGRAM_PIPELINE_OBJECT_EXT 0x8A4F
-#define GL_PROGRAM_OBJECT_EXT 0x8B40
-#define GL_SHADER_OBJECT_EXT 0x8B48
-#define GL_BUFFER_OBJECT_EXT 0x9151
-#define GL_QUERY_OBJECT_EXT 0x9153
-#define GL_VERTEX_ARRAY_OBJECT_EXT 0x9154
-#endif
-
-/* GL_EXT_debug_marker */
-/* No new tokens introduced by this extension. */
-
-/* GL_EXT_discard_framebuffer */
-#ifndef GL_EXT_discard_framebuffer
-#define GL_COLOR_EXT 0x1800
-#define GL_DEPTH_EXT 0x1801
-#define GL_STENCIL_EXT 0x1802
-#endif
-
-/* GL_EXT_map_buffer_range */
-#ifndef GL_EXT_map_buffer_range
-#define GL_MAP_READ_BIT_EXT 0x0001
-#define GL_MAP_WRITE_BIT_EXT 0x0002
-#define GL_MAP_INVALIDATE_RANGE_BIT_EXT 0x0004
-#define GL_MAP_INVALIDATE_BUFFER_BIT_EXT 0x0008
-#define GL_MAP_FLUSH_EXPLICIT_BIT_EXT 0x0010
-#define GL_MAP_UNSYNCHRONIZED_BIT_EXT 0x0020
-#endif
-
-/* GL_EXT_multisampled_render_to_texture */
-#ifndef GL_EXT_multisampled_render_to_texture
-#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT 0x8D6C
-/* reuse values from GL_EXT_framebuffer_multisample (desktop extension) */
-#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB
-#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56
-#define GL_MAX_SAMPLES_EXT 0x8D57
-#endif
-
-/* GL_EXT_multiview_draw_buffers */
-#ifndef GL_EXT_multiview_draw_buffers
-#define GL_COLOR_ATTACHMENT_EXT 0x90F0
-#define GL_MULTIVIEW_EXT 0x90F1
-#define GL_DRAW_BUFFER_EXT 0x0C01
-#define GL_READ_BUFFER_EXT 0x0C02
-#define GL_MAX_MULTIVIEW_BUFFERS_EXT 0x90F2
-#endif
-
-/* GL_EXT_multi_draw_arrays */
-/* No new tokens introduced by this extension. */
-
-/* GL_EXT_occlusion_query_boolean */
-#ifndef GL_EXT_occlusion_query_boolean
-#define GL_ANY_SAMPLES_PASSED_EXT 0x8C2F
-#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT 0x8D6A
-#define GL_CURRENT_QUERY_EXT 0x8865
-#define GL_QUERY_RESULT_EXT 0x8866
-#define GL_QUERY_RESULT_AVAILABLE_EXT 0x8867
-#endif
-
-/* GL_EXT_read_format_bgra */
-#ifndef GL_EXT_read_format_bgra
-#define GL_BGRA_EXT 0x80E1
-#define GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT 0x8365
-#define GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT 0x8366
-#endif
-
-/* GL_EXT_robustness */
-#ifndef GL_EXT_robustness
-/* reuse GL_NO_ERROR */
-#define GL_GUILTY_CONTEXT_RESET_EXT 0x8253
-#define GL_INNOCENT_CONTEXT_RESET_EXT 0x8254
-#define GL_UNKNOWN_CONTEXT_RESET_EXT 0x8255
-#define GL_CONTEXT_ROBUST_ACCESS_EXT 0x90F3
-#define GL_RESET_NOTIFICATION_STRATEGY_EXT 0x8256
-#define GL_LOSE_CONTEXT_ON_RESET_EXT 0x8252
-#define GL_NO_RESET_NOTIFICATION_EXT 0x8261
-#endif
-
-/* GL_EXT_separate_shader_objects */
-#ifndef GL_EXT_separate_shader_objects
-#define GL_VERTEX_SHADER_BIT_EXT 0x00000001
-#define GL_FRAGMENT_SHADER_BIT_EXT 0x00000002
-#define GL_ALL_SHADER_BITS_EXT 0xFFFFFFFF
-#define GL_PROGRAM_SEPARABLE_EXT 0x8258
-#define GL_ACTIVE_PROGRAM_EXT 0x8259
-#define GL_PROGRAM_PIPELINE_BINDING_EXT 0x825A
-#endif
-
-/* GL_EXT_shader_framebuffer_fetch */
-#ifndef GL_EXT_shader_framebuffer_fetch
-#define GL_FRAGMENT_SHADER_DISCARDS_SAMPLES_EXT 0x8A52
-#endif
-
-/* GL_EXT_shader_texture_lod */
-/* No new tokens introduced by this extension. */
-
-/* GL_EXT_shadow_samplers */
-#ifndef GL_EXT_shadow_samplers
-#define GL_TEXTURE_COMPARE_MODE_EXT 0x884C
-#define GL_TEXTURE_COMPARE_FUNC_EXT 0x884D
-#define GL_COMPARE_REF_TO_TEXTURE_EXT 0x884E
-#define GL_SAMPLER_2D_SHADOW_EXT 0x8B62
-#endif
-
-/* GL_EXT_sRGB */
-#ifndef GL_EXT_sRGB
-#define GL_SRGB_EXT 0x8C40
-#define GL_SRGB_ALPHA_EXT 0x8C42
-#define GL_SRGB8_ALPHA8_EXT 0x8C43
-#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT 0x8210
-#endif
-
-/* GL_EXT_texture_compression_dxt1 */
-#ifndef GL_EXT_texture_compression_dxt1
-#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
-#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
-#endif
-
-/* GL_EXT_texture_filter_anisotropic */
-#ifndef GL_EXT_texture_filter_anisotropic
-#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
-#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
-#endif
-
-/* GL_EXT_texture_format_BGRA8888 */
-#ifndef GL_EXT_texture_format_BGRA8888
-#define GL_BGRA_EXT 0x80E1
-#endif
-
-/* GL_EXT_texture_rg */
-#ifndef GL_EXT_texture_rg
-#define GL_RED_EXT 0x1903
-#define GL_RG_EXT 0x8227
-#define GL_R8_EXT 0x8229
-#define GL_RG8_EXT 0x822B
-#endif
-
-/* GL_EXT_texture_storage */
-#ifndef GL_EXT_texture_storage
-#define GL_TEXTURE_IMMUTABLE_FORMAT_EXT 0x912F
-#define GL_ALPHA8_EXT 0x803C
-#define GL_LUMINANCE8_EXT 0x8040
-#define GL_LUMINANCE8_ALPHA8_EXT 0x8045
-#define GL_RGBA32F_EXT 0x8814
-#define GL_RGB32F_EXT 0x8815
-#define GL_ALPHA32F_EXT 0x8816
-#define GL_LUMINANCE32F_EXT 0x8818
-#define GL_LUMINANCE_ALPHA32F_EXT 0x8819
-/* reuse GL_RGBA16F_EXT */
-/* reuse GL_RGB16F_EXT */
-#define GL_ALPHA16F_EXT 0x881C
-#define GL_LUMINANCE16F_EXT 0x881E
-#define GL_LUMINANCE_ALPHA16F_EXT 0x881F
-#define GL_RGB10_A2_EXT 0x8059
-#define GL_RGB10_EXT 0x8052
-#define GL_BGRA8_EXT 0x93A1
-#define GL_R8_EXT 0x8229
-#define GL_RG8_EXT 0x822B
-#define GL_R32F_EXT 0x822E
-#define GL_RG32F_EXT 0x8230
-#define GL_R16F_EXT 0x822D
-#define GL_RG16F_EXT 0x822F
-#endif
-
-/* GL_EXT_texture_type_2_10_10_10_REV */
-#ifndef GL_EXT_texture_type_2_10_10_10_REV
-#define GL_UNSIGNED_INT_2_10_10_10_REV_EXT 0x8368
-#endif
-
-/* GL_EXT_unpack_subimage */
-#ifndef GL_EXT_unpack_subimage
-#define GL_UNPACK_ROW_LENGTH_EXT 0x0CF2
-#define GL_UNPACK_SKIP_ROWS_EXT 0x0CF3
-#define GL_UNPACK_SKIP_PIXELS_EXT 0x0CF4
-#endif
-
-/*------------------------------------------------------------------------*
- * DMP extension tokens
- *------------------------------------------------------------------------*/
-
-/* GL_DMP_shader_binary */
-#ifndef GL_DMP_shader_binary
-#define GL_SHADER_BINARY_DMP 0x9250
-#endif
-
-/*------------------------------------------------------------------------*
- * FJ extension tokens
- *------------------------------------------------------------------------*/
-
-/* GL_FJ_shader_binary_GCCSO */
-#ifndef GL_FJ_shader_binary_GCCSO
-#define GL_GCCSO_SHADER_BINARY_F 0x9260
-#endif
-
-/*------------------------------------------------------------------------*
- * IMG extension tokens
- *------------------------------------------------------------------------*/
-
-/* GL_IMG_program_binary */
-#ifndef GL_IMG_program_binary
-#define GL_SGX_PROGRAM_BINARY_IMG 0x9130
-#endif
-
-/* GL_IMG_read_format */
-#ifndef GL_IMG_read_format
-#define GL_BGRA_IMG 0x80E1
-#define GL_UNSIGNED_SHORT_4_4_4_4_REV_IMG 0x8365
-#endif
-
-/* GL_IMG_shader_binary */
-#ifndef GL_IMG_shader_binary
-#define GL_SGX_BINARY_IMG 0x8C0A
-#endif
-
-/* GL_IMG_texture_compression_pvrtc */
-#ifndef GL_IMG_texture_compression_pvrtc
-#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00
-#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01
-#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02
-#define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03
-#endif
-
-/* GL_IMG_texture_compression_pvrtc2 */
-#ifndef GL_IMG_texture_compression_pvrtc2
-#define GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG 0x9137
-#define GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG 0x9138
-#endif
-
-/* GL_IMG_multisampled_render_to_texture */
-#ifndef GL_IMG_multisampled_render_to_texture
-#define GL_RENDERBUFFER_SAMPLES_IMG 0x9133
-#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG 0x9134
-#define GL_MAX_SAMPLES_IMG 0x9135
-#define GL_TEXTURE_SAMPLES_IMG 0x9136
-#endif
-
-/*------------------------------------------------------------------------*
- * NV extension tokens
- *------------------------------------------------------------------------*/
-
-/* GL_NV_coverage_sample */
-#ifndef GL_NV_coverage_sample
-#define GL_COVERAGE_COMPONENT_NV 0x8ED0
-#define GL_COVERAGE_COMPONENT4_NV 0x8ED1
-#define GL_COVERAGE_ATTACHMENT_NV 0x8ED2
-#define GL_COVERAGE_BUFFERS_NV 0x8ED3
-#define GL_COVERAGE_SAMPLES_NV 0x8ED4
-#define GL_COVERAGE_ALL_FRAGMENTS_NV 0x8ED5
-#define GL_COVERAGE_EDGE_FRAGMENTS_NV 0x8ED6
-#define GL_COVERAGE_AUTOMATIC_NV 0x8ED7
-#define GL_COVERAGE_BUFFER_BIT_NV 0x8000
-#endif
-
-/* GL_NV_depth_nonlinear */
-#ifndef GL_NV_depth_nonlinear
-#define GL_DEPTH_COMPONENT16_NONLINEAR_NV 0x8E2C
-#endif
-
-/* GL_NV_draw_buffers */
-#ifndef GL_NV_draw_buffers
-#define GL_MAX_DRAW_BUFFERS_NV 0x8824
-#define GL_DRAW_BUFFER0_NV 0x8825
-#define GL_DRAW_BUFFER1_NV 0x8826
-#define GL_DRAW_BUFFER2_NV 0x8827
-#define GL_DRAW_BUFFER3_NV 0x8828
-#define GL_DRAW_BUFFER4_NV 0x8829
-#define GL_DRAW_BUFFER5_NV 0x882A
-#define GL_DRAW_BUFFER6_NV 0x882B
-#define GL_DRAW_BUFFER7_NV 0x882C
-#define GL_DRAW_BUFFER8_NV 0x882D
-#define GL_DRAW_BUFFER9_NV 0x882E
-#define GL_DRAW_BUFFER10_NV 0x882F
-#define GL_DRAW_BUFFER11_NV 0x8830
-#define GL_DRAW_BUFFER12_NV 0x8831
-#define GL_DRAW_BUFFER13_NV 0x8832
-#define GL_DRAW_BUFFER14_NV 0x8833
-#define GL_DRAW_BUFFER15_NV 0x8834
-#define GL_COLOR_ATTACHMENT0_NV 0x8CE0
-#define GL_COLOR_ATTACHMENT1_NV 0x8CE1
-#define GL_COLOR_ATTACHMENT2_NV 0x8CE2
-#define GL_COLOR_ATTACHMENT3_NV 0x8CE3
-#define GL_COLOR_ATTACHMENT4_NV 0x8CE4
-#define GL_COLOR_ATTACHMENT5_NV 0x8CE5
-#define GL_COLOR_ATTACHMENT6_NV 0x8CE6
-#define GL_COLOR_ATTACHMENT7_NV 0x8CE7
-#define GL_COLOR_ATTACHMENT8_NV 0x8CE8
-#define GL_COLOR_ATTACHMENT9_NV 0x8CE9
-#define GL_COLOR_ATTACHMENT10_NV 0x8CEA
-#define GL_COLOR_ATTACHMENT11_NV 0x8CEB
-#define GL_COLOR_ATTACHMENT12_NV 0x8CEC
-#define GL_COLOR_ATTACHMENT13_NV 0x8CED
-#define GL_COLOR_ATTACHMENT14_NV 0x8CEE
-#define GL_COLOR_ATTACHMENT15_NV 0x8CEF
-#endif
-
-/* GL_EXT_draw_buffers */
-#ifndef GL_EXT_draw_buffers
-#define GL_MAX_DRAW_BUFFERS_EXT 0x8824
-#define GL_DRAW_BUFFER0_EXT 0x8825
-#define GL_DRAW_BUFFER1_EXT 0x8826
-#define GL_DRAW_BUFFER2_EXT 0x8827
-#define GL_DRAW_BUFFER3_EXT 0x8828
-#define GL_DRAW_BUFFER4_EXT 0x8829
-#define GL_DRAW_BUFFER5_EXT 0x882A
-#define GL_DRAW_BUFFER6_EXT 0x882B
-#define GL_DRAW_BUFFER7_EXT 0x882C
-#define GL_DRAW_BUFFER8_EXT 0x882D
-#define GL_DRAW_BUFFER9_EXT 0x882E
-#define GL_DRAW_BUFFER10_EXT 0x882F
-#define GL_DRAW_BUFFER11_EXT 0x8830
-#define GL_DRAW_BUFFER12_EXT 0x8831
-#define GL_DRAW_BUFFER13_EXT 0x8832
-#define GL_DRAW_BUFFER14_EXT 0x8833
-#define GL_DRAW_BUFFER15_EXT 0x8834
-#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0
-#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1
-#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2
-#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3
-#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4
-#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5
-#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6
-#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7
-#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8
-#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9
-#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA
-#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB
-#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC
-#define GL_COLOR_ATTACHMENT13_EXT 0x8CED
-#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE
-#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF
-#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF
-#endif
-
-/* GL_NV_draw_instanced */
-/* No new tokens introduced by this extension. */
-
-/* GL_NV_fbo_color_attachments */
-#ifndef GL_NV_fbo_color_attachments
-#define GL_MAX_COLOR_ATTACHMENTS_NV 0x8CDF
-/* GL_COLOR_ATTACHMENT{0-15}_NV defined in GL_NV_draw_buffers already. */
-#endif
-
-/* GL_NV_fence */
-#ifndef GL_NV_fence
-#define GL_ALL_COMPLETED_NV 0x84F2
-#define GL_FENCE_STATUS_NV 0x84F3
-#define GL_FENCE_CONDITION_NV 0x84F4
-#endif
-
-/* GL_NV_framebuffer_blit */
-#ifndef GL_NV_framebuffer_blit
-#define GL_READ_FRAMEBUFFER_NV 0x8CA8
-#define GL_DRAW_FRAMEBUFFER_NV 0x8CA9
-#define GL_DRAW_FRAMEBUFFER_BINDING_NV 0x8CA6
-#define GL_READ_FRAMEBUFFER_BINDING_NV 0x8CAA
-#endif
-
-/* GL_NV_framebuffer_multisample */
-#ifndef GL_NV_framebuffer_multisample
-#define GL_RENDERBUFFER_SAMPLES_NV 0x8CAB
-#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_NV 0x8D56
-#define GL_MAX_SAMPLES_NV 0x8D57
-#endif
-
-/* GL_NV_generate_mipmap_sRGB */
-/* No new tokens introduced by this extension. */
-
-/* GL_NV_instanced_arrays */
-#ifndef GL_NV_instanced_arrays
-#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_NV 0x88FE
-#endif
-
-/* GL_NV_read_buffer */
-#ifndef GL_NV_read_buffer
-#define GL_READ_BUFFER_NV 0x0C02
-#endif
-
-/* GL_NV_read_buffer_front */
-/* No new tokens introduced by this extension. */
-
-/* GL_NV_read_depth */
-/* No new tokens introduced by this extension. */
-
-/* GL_NV_read_depth_stencil */
-/* No new tokens introduced by this extension. */
-
-/* GL_NV_read_stencil */
-/* No new tokens introduced by this extension. */
-
-/* GL_NV_shadow_samplers_array */
-#ifndef GL_NV_shadow_samplers_array
-#define GL_SAMPLER_2D_ARRAY_SHADOW_NV 0x8DC4
-#endif
-
-/* GL_NV_shadow_samplers_cube */
-#ifndef GL_NV_shadow_samplers_cube
-#define GL_SAMPLER_CUBE_SHADOW_NV 0x8DC5
-#endif
-
-/* GL_NV_sRGB_formats */
-#ifndef GL_NV_sRGB_formats
-#define GL_SLUMINANCE_NV 0x8C46
-#define GL_SLUMINANCE_ALPHA_NV 0x8C44
-#define GL_SRGB8_NV 0x8C41
-#define GL_SLUMINANCE8_NV 0x8C47
-#define GL_SLUMINANCE8_ALPHA8_NV 0x8C45
-#define GL_COMPRESSED_SRGB_S3TC_DXT1_NV 0x8C4C
-#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_NV 0x8C4D
-#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_NV 0x8C4E
-#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_NV 0x8C4F
-#define GL_ETC1_SRGB8_NV 0x88EE
-#endif
-
-/* GL_NV_texture_border_clamp */
-#ifndef GL_NV_texture_border_clamp
-#define GL_TEXTURE_BORDER_COLOR_NV 0x1004
-#define GL_CLAMP_TO_BORDER_NV 0x812D
-#endif
-
-/* GL_NV_texture_compression_s3tc_update */
-/* No new tokens introduced by this extension. */
-
-/* GL_NV_texture_npot_2D_mipmap */
-/* No new tokens introduced by this extension. */
-
-/*------------------------------------------------------------------------*
- * QCOM extension tokens
- *------------------------------------------------------------------------*/
-
-/* GL_QCOM_alpha_test */
-#ifndef GL_QCOM_alpha_test
-#define GL_ALPHA_TEST_QCOM 0x0BC0
-#define GL_ALPHA_TEST_FUNC_QCOM 0x0BC1
-#define GL_ALPHA_TEST_REF_QCOM 0x0BC2
-#endif
-
-/* GL_QCOM_binning_control */
-#ifndef GL_QCOM_binning_control
-#define GL_BINNING_CONTROL_HINT_QCOM 0x8FB0
-#define GL_CPU_OPTIMIZED_QCOM 0x8FB1
-#define GL_GPU_OPTIMIZED_QCOM 0x8FB2
-#define GL_RENDER_DIRECT_TO_FRAMEBUFFER_QCOM 0x8FB3
-#endif
-
-/* GL_QCOM_driver_control */
-/* No new tokens introduced by this extension. */
-
-/* GL_QCOM_extended_get */
-#ifndef GL_QCOM_extended_get
-#define GL_TEXTURE_WIDTH_QCOM 0x8BD2
-#define GL_TEXTURE_HEIGHT_QCOM 0x8BD3
-#define GL_TEXTURE_DEPTH_QCOM 0x8BD4
-#define GL_TEXTURE_INTERNAL_FORMAT_QCOM 0x8BD5
-#define GL_TEXTURE_FORMAT_QCOM 0x8BD6
-#define GL_TEXTURE_TYPE_QCOM 0x8BD7
-#define GL_TEXTURE_IMAGE_VALID_QCOM 0x8BD8
-#define GL_TEXTURE_NUM_LEVELS_QCOM 0x8BD9
-#define GL_TEXTURE_TARGET_QCOM 0x8BDA
-#define GL_TEXTURE_OBJECT_VALID_QCOM 0x8BDB
-#define GL_STATE_RESTORE 0x8BDC
-#endif
-
-/* GL_QCOM_extended_get2 */
-/* No new tokens introduced by this extension. */
-
-/* GL_QCOM_perfmon_global_mode */
-#ifndef GL_QCOM_perfmon_global_mode
-#define GL_PERFMON_GLOBAL_MODE_QCOM 0x8FA0
-#endif
-
-/* GL_QCOM_writeonly_rendering */
-#ifndef GL_QCOM_writeonly_rendering
-#define GL_WRITEONLY_RENDERING_QCOM 0x8823
-#endif
-
-/* GL_QCOM_tiled_rendering */
-#ifndef GL_QCOM_tiled_rendering
-#define GL_COLOR_BUFFER_BIT0_QCOM 0x00000001
-#define GL_COLOR_BUFFER_BIT1_QCOM 0x00000002
-#define GL_COLOR_BUFFER_BIT2_QCOM 0x00000004
-#define GL_COLOR_BUFFER_BIT3_QCOM 0x00000008
-#define GL_COLOR_BUFFER_BIT4_QCOM 0x00000010
-#define GL_COLOR_BUFFER_BIT5_QCOM 0x00000020
-#define GL_COLOR_BUFFER_BIT6_QCOM 0x00000040
-#define GL_COLOR_BUFFER_BIT7_QCOM 0x00000080
-#define GL_DEPTH_BUFFER_BIT0_QCOM 0x00000100
-#define GL_DEPTH_BUFFER_BIT1_QCOM 0x00000200
-#define GL_DEPTH_BUFFER_BIT2_QCOM 0x00000400
-#define GL_DEPTH_BUFFER_BIT3_QCOM 0x00000800
-#define GL_DEPTH_BUFFER_BIT4_QCOM 0x00001000
-#define GL_DEPTH_BUFFER_BIT5_QCOM 0x00002000
-#define GL_DEPTH_BUFFER_BIT6_QCOM 0x00004000
-#define GL_DEPTH_BUFFER_BIT7_QCOM 0x00008000
-#define GL_STENCIL_BUFFER_BIT0_QCOM 0x00010000
-#define GL_STENCIL_BUFFER_BIT1_QCOM 0x00020000
-#define GL_STENCIL_BUFFER_BIT2_QCOM 0x00040000
-#define GL_STENCIL_BUFFER_BIT3_QCOM 0x00080000
-#define GL_STENCIL_BUFFER_BIT4_QCOM 0x00100000
-#define GL_STENCIL_BUFFER_BIT5_QCOM 0x00200000
-#define GL_STENCIL_BUFFER_BIT6_QCOM 0x00400000
-#define GL_STENCIL_BUFFER_BIT7_QCOM 0x00800000
-#define GL_MULTISAMPLE_BUFFER_BIT0_QCOM 0x01000000
-#define GL_MULTISAMPLE_BUFFER_BIT1_QCOM 0x02000000
-#define GL_MULTISAMPLE_BUFFER_BIT2_QCOM 0x04000000
-#define GL_MULTISAMPLE_BUFFER_BIT3_QCOM 0x08000000
-#define GL_MULTISAMPLE_BUFFER_BIT4_QCOM 0x10000000
-#define GL_MULTISAMPLE_BUFFER_BIT5_QCOM 0x20000000
-#define GL_MULTISAMPLE_BUFFER_BIT6_QCOM 0x40000000
-#define GL_MULTISAMPLE_BUFFER_BIT7_QCOM 0x80000000
-#endif
-
-/*------------------------------------------------------------------------*
- * VIV extension tokens
- *------------------------------------------------------------------------*/
-
-/* GL_VIV_shader_binary */
-#ifndef GL_VIV_shader_binary
-#define GL_SHADER_BINARY_VIV 0x8FC4
-#endif
-
-/*------------------------------------------------------------------------*
- * End of extension tokens, start of corresponding extension functions
- *------------------------------------------------------------------------*/
-
-/*------------------------------------------------------------------------*
- * OES extension functions
- *------------------------------------------------------------------------*/
-
-/* GL_OES_compressed_ETC1_RGB8_texture */
-#ifndef GL_OES_compressed_ETC1_RGB8_texture
-#define GL_OES_compressed_ETC1_RGB8_texture 1
-#endif
-
-/* GL_OES_compressed_paletted_texture */
-#ifndef GL_OES_compressed_paletted_texture
-#define GL_OES_compressed_paletted_texture 1
-#endif
-
-/* GL_OES_depth24 */
-#ifndef GL_OES_depth24
-#define GL_OES_depth24 1
-#endif
-
-/* GL_OES_depth32 */
-#ifndef GL_OES_depth32
-#define GL_OES_depth32 1
-#endif
-
-/* GL_OES_depth_texture */
-#ifndef GL_OES_depth_texture
-#define GL_OES_depth_texture 1
-#endif
-
-/* GL_OES_EGL_image */
-#ifndef GL_OES_EGL_image
-#define GL_OES_EGL_image 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image);
-GL_APICALL void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image);
-#endif
-typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
-typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
-#endif
-
-/* GL_OES_EGL_image_external */
-#ifndef GL_OES_EGL_image_external
-#define GL_OES_EGL_image_external 1
-/* glEGLImageTargetTexture2DOES defined in GL_OES_EGL_image already. */
-#endif
-
-/* GL_OES_element_index_uint */
-#ifndef GL_OES_element_index_uint
-#define GL_OES_element_index_uint 1
-#endif
-
-/* GL_OES_fbo_render_mipmap */
-#ifndef GL_OES_fbo_render_mipmap
-#define GL_OES_fbo_render_mipmap 1
-#endif
-
-/* GL_OES_fragment_precision_high */
-#ifndef GL_OES_fragment_precision_high
-#define GL_OES_fragment_precision_high 1
-#endif
-
-/* GL_OES_get_program_binary */
-#ifndef GL_OES_get_program_binary
-#define GL_OES_get_program_binary 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glGetProgramBinaryOES (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary);
-GL_APICALL void GL_APIENTRY glProgramBinaryOES (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length);
-#endif
-typedef void (GL_APIENTRYP PFNGLGETPROGRAMBINARYOESPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary);
-typedef void (GL_APIENTRYP PFNGLPROGRAMBINARYOESPROC) (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length);
-#endif
-
-/* GL_OES_mapbuffer */
-#ifndef GL_OES_mapbuffer
-#define GL_OES_mapbuffer 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void* GL_APIENTRY glMapBufferOES (GLenum target, GLenum access);
-GL_APICALL GLboolean GL_APIENTRY glUnmapBufferOES (GLenum target);
-GL_APICALL void GL_APIENTRY glGetBufferPointervOES (GLenum target, GLenum pname, GLvoid** params);
-#endif
-typedef void* (GL_APIENTRYP PFNGLMAPBUFFEROESPROC) (GLenum target, GLenum access);
-typedef GLboolean (GL_APIENTRYP PFNGLUNMAPBUFFEROESPROC) (GLenum target);
-typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, GLvoid** params);
-#endif
-
-/* GL_OES_packed_depth_stencil */
-#ifndef GL_OES_packed_depth_stencil
-#define GL_OES_packed_depth_stencil 1
-#endif
-
-/* GL_OES_required_internalformat */
-#ifndef GL_OES_required_internalformat
-#define GL_OES_required_internalformat 1
-#endif
-
-/* GL_OES_rgb8_rgba8 */
-#ifndef GL_OES_rgb8_rgba8
-#define GL_OES_rgb8_rgba8 1
-#endif
-
-/* GL_OES_standard_derivatives */
-#ifndef GL_OES_standard_derivatives
-#define GL_OES_standard_derivatives 1
-#endif
-
-/* GL_OES_stencil1 */
-#ifndef GL_OES_stencil1
-#define GL_OES_stencil1 1
-#endif
-
-/* GL_OES_stencil4 */
-#ifndef GL_OES_stencil4
-#define GL_OES_stencil4 1
-#endif
-
-#ifndef GL_OES_surfaceless_context
-#define GL_OES_surfaceless_context 1
-#endif
-
-/* GL_OES_texture_3D */
-#ifndef GL_OES_texture_3D
-#define GL_OES_texture_3D 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
-GL_APICALL void GL_APIENTRY glTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels);
-GL_APICALL void GL_APIENTRY glCopyTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
-GL_APICALL void GL_APIENTRY glCompressedTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data);
-GL_APICALL void GL_APIENTRY glCompressedTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data);
-GL_APICALL void GL_APIENTRY glFramebufferTexture3DOES (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
-#endif
-typedef void (GL_APIENTRYP PFNGLTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
-typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels);
-typedef void (GL_APIENTRYP PFNGLCOPYTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
-typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data);
-typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data);
-typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DOES) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
-#endif
-
-/* GL_OES_texture_float */
-#ifndef GL_OES_texture_float
-#define GL_OES_texture_float 1
-#endif
-
-/* GL_OES_texture_float_linear */
-#ifndef GL_OES_texture_float_linear
-#define GL_OES_texture_float_linear 1
-#endif
-
-/* GL_OES_texture_half_float */
-#ifndef GL_OES_texture_half_float
-#define GL_OES_texture_half_float 1
-#endif
-
-/* GL_OES_texture_half_float_linear */
-#ifndef GL_OES_texture_half_float_linear
-#define GL_OES_texture_half_float_linear 1
-#endif
-
-/* GL_OES_texture_npot */
-#ifndef GL_OES_texture_npot
-#define GL_OES_texture_npot 1
-#endif
-
-/* GL_OES_vertex_array_object */
-#ifndef GL_OES_vertex_array_object
-#define GL_OES_vertex_array_object 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glBindVertexArrayOES (GLuint array);
-GL_APICALL void GL_APIENTRY glDeleteVertexArraysOES (GLsizei n, const GLuint *arrays);
-GL_APICALL void GL_APIENTRY glGenVertexArraysOES (GLsizei n, GLuint *arrays);
-GL_APICALL GLboolean GL_APIENTRY glIsVertexArrayOES (GLuint array);
-#endif
-typedef void (GL_APIENTRYP PFNGLBINDVERTEXARRAYOESPROC) (GLuint array);
-typedef void (GL_APIENTRYP PFNGLDELETEVERTEXARRAYSOESPROC) (GLsizei n, const GLuint *arrays);
-typedef void (GL_APIENTRYP PFNGLGENVERTEXARRAYSOESPROC) (GLsizei n, GLuint *arrays);
-typedef GLboolean (GL_APIENTRYP PFNGLISVERTEXARRAYOESPROC) (GLuint array);
-#endif
-
-/* GL_OES_vertex_half_float */
-#ifndef GL_OES_vertex_half_float
-#define GL_OES_vertex_half_float 1
-#endif
-
-/* GL_OES_vertex_type_10_10_10_2 */
-#ifndef GL_OES_vertex_type_10_10_10_2
-#define GL_OES_vertex_type_10_10_10_2 1
-#endif
-
-/*------------------------------------------------------------------------*
- * KHR extension functions
- *------------------------------------------------------------------------*/
-
-#ifndef GL_KHR_debug
-#define GL_KHR_debug 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glDebugMessageControl (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
-GL_APICALL void GL_APIENTRY glDebugMessageInsert (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
-GL_APICALL void GL_APIENTRY glDebugMessageCallback (GLDEBUGPROC callback, const void *userParam);
-GL_APICALL GLuint GL_APIENTRY glGetDebugMessageLog (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
-GL_APICALL void GL_APIENTRY glPushDebugGroup (GLenum source, GLuint id, GLsizei length, const GLchar *message);
-GL_APICALL void GL_APIENTRY glPopDebugGroup (void);
-GL_APICALL void GL_APIENTRY glObjectLabel (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);
-GL_APICALL void GL_APIENTRY glGetObjectLabel (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);
-GL_APICALL void GL_APIENTRY glObjectPtrLabel (const void *ptr, GLsizei length, const GLchar *label);
-GL_APICALL void GL_APIENTRY glGetObjectPtrLabel (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);
-GL_APICALL void GL_APIENTRY glGetPointerv (GLenum pname, void **params);
-#endif
-typedef void (GL_APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
-typedef void (GL_APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
-typedef void (GL_APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, const void *userParam);
-typedef GLuint (GL_APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
-typedef void (GL_APIENTRYP PFNGLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message);
-typedef void (GL_APIENTRYP PFNGLPOPDEBUGGROUPPROC) (void);
-typedef void (GL_APIENTRYP PFNGLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);
-typedef void (GL_APIENTRYP PFNGLGETOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);
-typedef void (GL_APIENTRYP PFNGLOBJECTPTRLABELPROC) (const void *ptr, GLsizei length, const GLchar *label);
-typedef void (GL_APIENTRYP PFNGLGETOBJECTPTRLABELPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);
-typedef void (GL_APIENTRYP PFNGLGETPOINTERVPROC) (GLenum pname, void **params);
-#endif
-
-#ifndef GL_KHR_texture_compression_astc_ldr
-#define GL_KHR_texture_compression_astc_ldr 1
-#endif
-
-
-/*------------------------------------------------------------------------*
- * AMD extension functions
- *------------------------------------------------------------------------*/
-
-/* GL_AMD_compressed_3DC_texture */
-#ifndef GL_AMD_compressed_3DC_texture
-#define GL_AMD_compressed_3DC_texture 1
-#endif
-
-/* GL_AMD_compressed_ATC_texture */
-#ifndef GL_AMD_compressed_ATC_texture
-#define GL_AMD_compressed_ATC_texture 1
-#endif
-
-/* AMD_performance_monitor */
-#ifndef GL_AMD_performance_monitor
-#define GL_AMD_performance_monitor 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsSize, GLuint *groups);
-GL_APICALL void GL_APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters);
-GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString);
-GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString);
-GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, GLvoid *data);
-GL_APICALL void GL_APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors);
-GL_APICALL void GL_APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors);
-GL_APICALL void GL_APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList);
-GL_APICALL void GL_APIENTRY glBeginPerfMonitorAMD (GLuint monitor);
-GL_APICALL void GL_APIENTRY glEndPerfMonitorAMD (GLuint monitor);
-GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterDataAMD (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);
-#endif
-typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLsizei groupsSize, GLuint *groups);
-typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters);
-typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString);
-typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString);
-typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, GLvoid *data);
-typedef void (GL_APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);
-typedef void (GL_APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);
-typedef void (GL_APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList);
-typedef void (GL_APIENTRYP PFNGLBEGINPERFMONITORAMDPROC) (GLuint monitor);
-typedef void (GL_APIENTRYP PFNGLENDPERFMONITORAMDPROC) (GLuint monitor);
-typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);
-#endif
-
-/* GL_AMD_program_binary_Z400 */
-#ifndef GL_AMD_program_binary_Z400
-#define GL_AMD_program_binary_Z400 1
-#endif
-
-/*------------------------------------------------------------------------*
- * ANGLE extension functions
- *------------------------------------------------------------------------*/
-
-/* GL_ANGLE_depth_texture */
-#ifndef GL_ANGLE_depth_texture
-#define GL_ANGLE_depth_texture 1
-#endif
-
-/* GL_ANGLE_framebuffer_blit */
-#ifndef GL_ANGLE_framebuffer_blit
-#define GL_ANGLE_framebuffer_blit 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glBlitFramebufferANGLE (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
-#endif
-typedef void (GL_APIENTRYP PFNGLBLITFRAMEBUFFERANGLEPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
-#endif
-
-/* GL_ANGLE_framebuffer_multisample */
-#ifndef GL_ANGLE_framebuffer_multisample
-#define GL_ANGLE_framebuffer_multisample 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleANGLE (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
-#endif
-typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEANGLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
-#endif
-
-#ifndef GL_ANGLE_instanced_arrays
-#define GL_ANGLE_instanced_arrays 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glDrawArraysInstancedANGLE (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
-GL_APICALL void GL_APIENTRY glDrawElementsInstancedANGLE (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
-GL_APICALL void GL_APIENTRY glVertexAttribDivisorANGLE (GLuint index, GLuint divisor);
-#endif
-typedef void (GL_APIENTRYP PFNGLDRAWARRAYSINSTANCEDANGLEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
-typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDANGLEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
-typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBDIVISORANGLEPROC) (GLuint index, GLuint divisor);
-#endif
-
-/* GL_ANGLE_pack_reverse_row_order */
-#ifndef GL_ANGLE_pack_reverse_row_order
-#define GL_ANGLE_pack_reverse_row_order 1
-#endif
-
-/* GL_ANGLE_program_binary */
-#ifndef GL_ANGLE_program_binary
-#define GL_ANGLE_program_binary 1
-#endif
-
-/* GL_ANGLE_texture_compression_dxt3 */
-#ifndef GL_ANGLE_texture_compression_dxt3
-#define GL_ANGLE_texture_compression_dxt3 1
-#endif
-
-/* GL_ANGLE_texture_compression_dxt5 */
-#ifndef GL_ANGLE_texture_compression_dxt5
-#define GL_ANGLE_texture_compression_dxt5 1
-#endif
-
-/* GL_ANGLE_texture_usage */
-#ifndef GL_ANGLE_texture_usage
-#define GL_ANGLE_texture_usage 1
-#endif
-
-#ifndef GL_ANGLE_translated_shader_source
-#define GL_ANGLE_translated_shader_source 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glGetTranslatedShaderSourceANGLE (GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source);
-#endif
-typedef void (GL_APIENTRYP PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC) (GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source);
-#endif
-
-/*------------------------------------------------------------------------*
- * APPLE extension functions
- *------------------------------------------------------------------------*/
-
-/* GL_APPLE_copy_texture_levels */
-#ifndef GL_APPLE_copy_texture_levels
-#define GL_APPLE_copy_texture_levels 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glCopyTextureLevelsAPPLE (GLuint destinationTexture, GLuint sourceTexture, GLint sourceBaseLevel, GLsizei sourceLevelCount);
-#endif
-typedef void (GL_APIENTRYP PFNGLCOPYTEXTURELEVELSAPPLEPROC) (GLuint destinationTexture, GLuint sourceTexture, GLint sourceBaseLevel, GLsizei sourceLevelCount);
-#endif
-
-/* GL_APPLE_framebuffer_multisample */
-#ifndef GL_APPLE_framebuffer_multisample
-#define GL_APPLE_framebuffer_multisample 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleAPPLE (GLenum, GLsizei, GLenum, GLsizei, GLsizei);
-GL_APICALL void GL_APIENTRY glResolveMultisampleFramebufferAPPLE (void);
-#endif /* GL_GLEXT_PROTOTYPES */
-typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEAPPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
-typedef void (GL_APIENTRYP PFNGLRESOLVEMULTISAMPLEFRAMEBUFFERAPPLEPROC) (void);
-#endif
-
-/* GL_APPLE_rgb_422 */
-#ifndef GL_APPLE_rgb_422
-#define GL_APPLE_rgb_422 1
-#endif
-
-/* GL_APPLE_sync */
-#ifndef GL_APPLE_sync
-#define GL_APPLE_sync 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL GLsync GL_APIENTRY glFenceSyncAPPLE (GLenum condition, GLbitfield flags);
-GL_APICALL GLboolean GL_APIENTRY glIsSyncAPPLE (GLsync sync);
-GL_APICALL void GL_APIENTRY glDeleteSyncAPPLE (GLsync sync);
-GL_APICALL GLenum GL_APIENTRY glClientWaitSyncAPPLE (GLsync sync, GLbitfield flags, GLuint64 timeout);
-GL_APICALL void GL_APIENTRY glWaitSyncAPPLE (GLsync sync, GLbitfield flags, GLuint64 timeout);
-GL_APICALL void GL_APIENTRY glGetInteger64vAPPLE (GLenum pname, GLint64 *params);
-GL_APICALL void GL_APIENTRY glGetSyncivAPPLE (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values);
-#endif
-typedef GLsync (GL_APIENTRYP PFNGLFENCESYNCAPPLEPROC) (GLenum condition, GLbitfield flags);
-typedef GLboolean (GL_APIENTRYP PFNGLISSYNCAPPLEPROC) (GLsync sync);
-typedef void (GL_APIENTRYP PFNGLDELETESYNCAPPLEPROC) (GLsync sync);
-typedef GLenum (GL_APIENTRYP PFNGLCLIENTWAITSYNCAPPLEPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout);
-typedef void (GL_APIENTRYP PFNGLWAITSYNCAPPLEPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout);
-typedef void (GL_APIENTRYP PFNGLGETINTEGER64VAPPLEPROC) (GLenum pname, GLint64 *params);
-typedef void (GL_APIENTRYP PFNGLGETSYNCIVAPPLEPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values);
-#endif
-
-/* GL_APPLE_texture_format_BGRA8888 */
-#ifndef GL_APPLE_texture_format_BGRA8888
-#define GL_APPLE_texture_format_BGRA8888 1
-#endif
-
-/* GL_APPLE_texture_max_level */
-#ifndef GL_APPLE_texture_max_level
-#define GL_APPLE_texture_max_level 1
-#endif
-
-/*------------------------------------------------------------------------*
- * ARM extension functions
- *------------------------------------------------------------------------*/
-
-/* GL_ARM_mali_program_binary */
-#ifndef GL_ARM_mali_program_binary
-#define GL_ARM_mali_program_binary 1
-#endif
-
-/* GL_ARM_mali_shader_binary */
-#ifndef GL_ARM_mali_shader_binary
-#define GL_ARM_mali_shader_binary 1
-#endif
-
-/* GL_ARM_rgba8 */
-#ifndef GL_ARM_rgba8
-#define GL_ARM_rgba8 1
-#endif
-
-/*------------------------------------------------------------------------*
- * EXT extension functions
- *------------------------------------------------------------------------*/
-
-/* GL_EXT_blend_minmax */
-#ifndef GL_EXT_blend_minmax
-#define GL_EXT_blend_minmax 1
-#endif
-
-/* GL_EXT_color_buffer_half_float */
-#ifndef GL_EXT_color_buffer_half_float
-#define GL_EXT_color_buffer_half_float 1
-#endif
-
-/* GL_EXT_debug_label */
-#ifndef GL_EXT_debug_label
-#define GL_EXT_debug_label 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glLabelObjectEXT (GLenum type, GLuint object, GLsizei length, const GLchar *label);
-GL_APICALL void GL_APIENTRY glGetObjectLabelEXT (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);
-#endif
-typedef void (GL_APIENTRYP PFNGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar *label);
-typedef void (GL_APIENTRYP PFNGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);
-#endif
-
-/* GL_EXT_debug_marker */
-#ifndef GL_EXT_debug_marker
-#define GL_EXT_debug_marker 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glInsertEventMarkerEXT (GLsizei length, const GLchar *marker);
-GL_APICALL void GL_APIENTRY glPushGroupMarkerEXT (GLsizei length, const GLchar *marker);
-GL_APICALL void GL_APIENTRY glPopGroupMarkerEXT (void);
-#endif
-typedef void (GL_APIENTRYP PFNGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker);
-typedef void (GL_APIENTRYP PFNGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker);
-typedef void (GL_APIENTRYP PFNGLPOPGROUPMARKEREXTPROC) (void);
-#endif
-
-/* GL_EXT_discard_framebuffer */
-#ifndef GL_EXT_discard_framebuffer
-#define GL_EXT_discard_framebuffer 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glDiscardFramebufferEXT (GLenum target, GLsizei numAttachments, const GLenum *attachments);
-#endif
-typedef void (GL_APIENTRYP PFNGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);
-#endif
-
-/* GL_EXT_map_buffer_range */
-#ifndef GL_EXT_map_buffer_range
-#define GL_EXT_map_buffer_range 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void* GL_APIENTRY glMapBufferRangeEXT (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
-GL_APICALL void GL_APIENTRY glFlushMappedBufferRangeEXT (GLenum target, GLintptr offset, GLsizeiptr length);
-#endif
-typedef void* (GL_APIENTRYP PFNGLMAPBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
-typedef void (GL_APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length);
-#endif
-
-/* GL_EXT_multisampled_render_to_texture */
-#ifndef GL_EXT_multisampled_render_to_texture
-#define GL_EXT_multisampled_render_to_texture 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleEXT (GLenum, GLsizei, GLenum, GLsizei, GLsizei);
-GL_APICALL void GL_APIENTRY glFramebufferTexture2DMultisampleEXT (GLenum, GLenum, GLenum, GLuint, GLint, GLsizei);
-#endif
-typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
-typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
-#endif
-
-/* GL_EXT_multiview_draw_buffers */
-#ifndef GL_EXT_multiview_draw_buffers
-#define GL_EXT_multiview_draw_buffers 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glReadBufferIndexedEXT (GLenum src, GLint index);
-GL_APICALL void GL_APIENTRY glDrawBuffersIndexedEXT (GLint n, const GLenum *location, const GLint *indices);
-GL_APICALL void GL_APIENTRY glGetIntegeri_vEXT (GLenum target, GLuint index, GLint *data);
-#endif
-typedef void (GL_APIENTRYP PFNGLREADBUFFERINDEXEDEXTPROC) (GLenum src, GLint index);
-typedef void (GL_APIENTRYP PFNGLDRAWBUFFERSINDEXEDEXTPROC) (GLint n, const GLenum *location, const GLint *indices);
-typedef void (GL_APIENTRYP PFNGLGETINTEGERI_VEXTPROC) (GLenum target, GLuint index, GLint *data);
-#endif
-
-#ifndef GL_EXT_multi_draw_arrays
-#define GL_EXT_multi_draw_arrays 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glMultiDrawArraysEXT (GLenum, const GLint *, const GLsizei *, GLsizei);
-GL_APICALL void GL_APIENTRY glMultiDrawElementsEXT (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei);
-#endif /* GL_GLEXT_PROTOTYPES */
-typedef void (GL_APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount);
-typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount);
-#endif
-
-/* GL_EXT_occlusion_query_boolean */
-#ifndef GL_EXT_occlusion_query_boolean
-#define GL_EXT_occlusion_query_boolean 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glGenQueriesEXT (GLsizei n, GLuint *ids);
-GL_APICALL void GL_APIENTRY glDeleteQueriesEXT (GLsizei n, const GLuint *ids);
-GL_APICALL GLboolean GL_APIENTRY glIsQueryEXT (GLuint id);
-GL_APICALL void GL_APIENTRY glBeginQueryEXT (GLenum target, GLuint id);
-GL_APICALL void GL_APIENTRY glEndQueryEXT (GLenum target);
-GL_APICALL void GL_APIENTRY glGetQueryivEXT (GLenum target, GLenum pname, GLint *params);
-GL_APICALL void GL_APIENTRY glGetQueryObjectuivEXT (GLuint id, GLenum pname, GLuint *params);
-#endif
-typedef void (GL_APIENTRYP PFNGLGENQUERIESEXTPROC) (GLsizei n, GLuint *ids);
-typedef void (GL_APIENTRYP PFNGLDELETEQUERIESEXTPROC) (GLsizei n, const GLuint *ids);
-typedef GLboolean (GL_APIENTRYP PFNGLISQUERYEXTPROC) (GLuint id);
-typedef void (GL_APIENTRYP PFNGLBEGINQUERYEXTPROC) (GLenum target, GLuint id);
-typedef void (GL_APIENTRYP PFNGLENDQUERYEXTPROC) (GLenum target);
-typedef void (GL_APIENTRYP PFNGLGETQUERYIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
-typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTUIVEXTPROC) (GLuint id, GLenum pname, GLuint *params);
-#endif
-
-/* GL_EXT_read_format_bgra */
-#ifndef GL_EXT_read_format_bgra
-#define GL_EXT_read_format_bgra 1
-#endif
-
-/* GL_EXT_robustness */
-#ifndef GL_EXT_robustness
-#define GL_EXT_robustness 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL GLenum GL_APIENTRY glGetGraphicsResetStatusEXT (void);
-GL_APICALL void GL_APIENTRY glReadnPixelsEXT (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
-GL_APICALL void GL_APIENTRY glGetnUniformfvEXT (GLuint program, GLint location, GLsizei bufSize, float *params);
-GL_APICALL void GL_APIENTRY glGetnUniformivEXT (GLuint program, GLint location, GLsizei bufSize, GLint *params);
-#endif
-typedef GLenum (GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSEXTPROC) (void);
-typedef void (GL_APIENTRYP PFNGLREADNPIXELSEXTPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
-typedef void (GL_APIENTRYP PFNGLGETNUNIFORMFVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, float *params);
-typedef void (GL_APIENTRYP PFNGLGETNUNIFORMIVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
-#endif
-
-/* GL_EXT_separate_shader_objects */
-#ifndef GL_EXT_separate_shader_objects
-#define GL_EXT_separate_shader_objects 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glUseProgramStagesEXT (GLuint pipeline, GLbitfield stages, GLuint program);
-GL_APICALL void GL_APIENTRY glActiveShaderProgramEXT (GLuint pipeline, GLuint program);
-GL_APICALL GLuint GL_APIENTRY glCreateShaderProgramvEXT (GLenum type, GLsizei count, const GLchar **strings);
-GL_APICALL void GL_APIENTRY glBindProgramPipelineEXT (GLuint pipeline);
-GL_APICALL void GL_APIENTRY glDeleteProgramPipelinesEXT (GLsizei n, const GLuint *pipelines);
-GL_APICALL void GL_APIENTRY glGenProgramPipelinesEXT (GLsizei n, GLuint *pipelines);
-GL_APICALL GLboolean GL_APIENTRY glIsProgramPipelineEXT (GLuint pipeline);
-GL_APICALL void GL_APIENTRY glProgramParameteriEXT (GLuint program, GLenum pname, GLint value);
-GL_APICALL void GL_APIENTRY glGetProgramPipelineivEXT (GLuint pipeline, GLenum pname, GLint *params);
-GL_APICALL void GL_APIENTRY glProgramUniform1iEXT (GLuint program, GLint location, GLint x);
-GL_APICALL void GL_APIENTRY glProgramUniform2iEXT (GLuint program, GLint location, GLint x, GLint y);
-GL_APICALL void GL_APIENTRY glProgramUniform3iEXT (GLuint program, GLint location, GLint x, GLint y, GLint z);
-GL_APICALL void GL_APIENTRY glProgramUniform4iEXT (GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w);
-GL_APICALL void GL_APIENTRY glProgramUniform1fEXT (GLuint program, GLint location, GLfloat x);
-GL_APICALL void GL_APIENTRY glProgramUniform2fEXT (GLuint program, GLint location, GLfloat x, GLfloat y);
-GL_APICALL void GL_APIENTRY glProgramUniform3fEXT (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z);
-GL_APICALL void GL_APIENTRY glProgramUniform4fEXT (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
-GL_APICALL void GL_APIENTRY glProgramUniform1ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
-GL_APICALL void GL_APIENTRY glProgramUniform2ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
-GL_APICALL void GL_APIENTRY glProgramUniform3ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
-GL_APICALL void GL_APIENTRY glProgramUniform4ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
-GL_APICALL void GL_APIENTRY glProgramUniform1fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
-GL_APICALL void GL_APIENTRY glProgramUniform2fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
-GL_APICALL void GL_APIENTRY glProgramUniform3fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
-GL_APICALL void GL_APIENTRY glProgramUniform4fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
-GL_APICALL void GL_APIENTRY glProgramUniformMatrix2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
-GL_APICALL void GL_APIENTRY glProgramUniformMatrix3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
-GL_APICALL void GL_APIENTRY glProgramUniformMatrix4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
-GL_APICALL void GL_APIENTRY glValidateProgramPipelineEXT (GLuint pipeline);
-GL_APICALL void GL_APIENTRY glGetProgramPipelineInfoLogEXT (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
-#endif
-typedef void (GL_APIENTRYP PFNGLUSEPROGRAMSTAGESEXTPROC) (GLuint pipeline, GLbitfield stages, GLuint program);
-typedef void (GL_APIENTRYP PFNGLACTIVESHADERPROGRAMEXTPROC) (GLuint pipeline, GLuint program);
-typedef GLuint (GL_APIENTRYP PFNGLCREATESHADERPROGRAMVEXTPROC) (GLenum type, GLsizei count, const GLchar **strings);
-typedef void (GL_APIENTRYP PFNGLBINDPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
-typedef void (GL_APIENTRYP PFNGLDELETEPROGRAMPIPELINESEXTPROC) (GLsizei n, const GLuint *pipelines);
-typedef void (GL_APIENTRYP PFNGLGENPROGRAMPIPELINESEXTPROC) (GLsizei n, GLuint *pipelines);
-typedef GLboolean (GL_APIENTRYP PFNGLISPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
-typedef void (GL_APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value);
-typedef void (GL_APIENTRYP PFNGLGETPROGRAMPIPELINEIVEXTPROC) (GLuint pipeline, GLenum pname, GLint *params);
-typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint x);
-typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint x, GLint y);
-typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint x, GLint y, GLint z);
-typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w);
-typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat x);
-typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat x, GLfloat y);
-typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z);
-typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
-typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
-typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
-typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
-typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
-typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
-typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
-typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
-typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
-typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
-typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
-typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
-typedef void (GL_APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
-typedef void (GL_APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGEXTPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
-#endif
-
-/* GL_EXT_shader_framebuffer_fetch */
-#ifndef GL_EXT_shader_framebuffer_fetch
-#define GL_EXT_shader_framebuffer_fetch 1
-#endif
-
-/* GL_EXT_shader_texture_lod */
-#ifndef GL_EXT_shader_texture_lod
-#define GL_EXT_shader_texture_lod 1
-#endif
-
-/* GL_EXT_shadow_samplers */
-#ifndef GL_EXT_shadow_samplers
-#define GL_EXT_shadow_samplers 1
-#endif
-
-/* GL_EXT_sRGB */
-#ifndef GL_EXT_sRGB
-#define GL_EXT_sRGB 1
-#endif
-
-/* GL_EXT_texture_compression_dxt1 */
-#ifndef GL_EXT_texture_compression_dxt1
-#define GL_EXT_texture_compression_dxt1 1
-#endif
-
-/* GL_EXT_texture_filter_anisotropic */
-#ifndef GL_EXT_texture_filter_anisotropic
-#define GL_EXT_texture_filter_anisotropic 1
-#endif
-
-/* GL_EXT_texture_format_BGRA8888 */
-#ifndef GL_EXT_texture_format_BGRA8888
-#define GL_EXT_texture_format_BGRA8888 1
-#endif
-
-/* GL_EXT_texture_rg */
-#ifndef GL_EXT_texture_rg
-#define GL_EXT_texture_rg 1
-#endif
-
-/* GL_EXT_texture_storage */
-#ifndef GL_EXT_texture_storage
-#define GL_EXT_texture_storage 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glTexStorage1DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
-GL_APICALL void GL_APIENTRY glTexStorage2DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
-GL_APICALL void GL_APIENTRY glTexStorage3DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
-GL_APICALL void GL_APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
-GL_APICALL void GL_APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
-GL_APICALL void GL_APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
-#endif
-typedef void (GL_APIENTRYP PFNGLTEXSTORAGE1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
-typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
-typedef void (GL_APIENTRYP PFNGLTEXSTORAGE3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
-typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
-typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
-typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
-#endif
-
-/* GL_EXT_texture_type_2_10_10_10_REV */
-#ifndef GL_EXT_texture_type_2_10_10_10_REV
-#define GL_EXT_texture_type_2_10_10_10_REV 1
-#endif
-
-/* GL_EXT_unpack_subimage */
-#ifndef GL_EXT_unpack_subimage
-#define GL_EXT_unpack_subimage 1
-#endif
-
-/*------------------------------------------------------------------------*
- * DMP extension functions
- *------------------------------------------------------------------------*/
-
-/* GL_DMP_shader_binary */
-#ifndef GL_DMP_shader_binary
-#define GL_DMP_shader_binary 1
-#endif
-
-/*------------------------------------------------------------------------*
- * FJ extension functions
- *------------------------------------------------------------------------*/
-
-/* GL_FJ_shader_binary_GCCSO */
-#ifndef GL_FJ_shader_binary_GCCSO
-#define GL_FJ_shader_binary_GCCSO 1
-#endif
-
-/*------------------------------------------------------------------------*
- * IMG extension functions
- *------------------------------------------------------------------------*/
-
-/* GL_IMG_program_binary */
-#ifndef GL_IMG_program_binary
-#define GL_IMG_program_binary 1
-#endif
-
-/* GL_IMG_read_format */
-#ifndef GL_IMG_read_format
-#define GL_IMG_read_format 1
-#endif
-
-/* GL_IMG_shader_binary */
-#ifndef GL_IMG_shader_binary
-#define GL_IMG_shader_binary 1
-#endif
-
-/* GL_IMG_texture_compression_pvrtc */
-#ifndef GL_IMG_texture_compression_pvrtc
-#define GL_IMG_texture_compression_pvrtc 1
-#endif
-
-/* GL_IMG_texture_compression_pvrtc2 */
-#ifndef GL_IMG_texture_compression_pvrtc2
-#define GL_IMG_texture_compression_pvrtc2 1
-#endif
-
-/* GL_IMG_multisampled_render_to_texture */
-#ifndef GL_IMG_multisampled_render_to_texture
-#define GL_IMG_multisampled_render_to_texture 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleIMG (GLenum, GLsizei, GLenum, GLsizei, GLsizei);
-GL_APICALL void GL_APIENTRY glFramebufferTexture2DMultisampleIMG (GLenum, GLenum, GLenum, GLuint, GLint, GLsizei);
-#endif
-typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEIMGPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
-typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEIMGPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
-#endif
-
-/*------------------------------------------------------------------------*
- * NV extension functions
- *------------------------------------------------------------------------*/
-
-/* GL_NV_coverage_sample */
-#ifndef GL_NV_coverage_sample
-#define GL_NV_coverage_sample 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glCoverageMaskNV (GLboolean mask);
-GL_APICALL void GL_APIENTRY glCoverageOperationNV (GLenum operation);
-#endif
-typedef void (GL_APIENTRYP PFNGLCOVERAGEMASKNVPROC) (GLboolean mask);
-typedef void (GL_APIENTRYP PFNGLCOVERAGEOPERATIONNVPROC) (GLenum operation);
-#endif
-
-/* GL_NV_depth_nonlinear */
-#ifndef GL_NV_depth_nonlinear
-#define GL_NV_depth_nonlinear 1
-#endif
-
-/* GL_NV_draw_buffers */
-#ifndef GL_NV_draw_buffers
-#define GL_NV_draw_buffers 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glDrawBuffersNV (GLsizei n, const GLenum *bufs);
-#endif
-typedef void (GL_APIENTRYP PFNGLDRAWBUFFERSNVPROC) (GLsizei n, const GLenum *bufs);
-#endif
-
-/* GL_EXT_draw_buffers */
-#ifndef GL_EXT_draw_buffers
-#define GL_EXT_draw_buffers 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glDrawBuffersEXT (GLsizei n, const GLenum *bufs);
-#endif
-typedef void (GL_APIENTRYP PFNGLDRAWBUFFERSEXTPROC) (GLsizei n, const GLenum *bufs);
-#endif
-
-/* GL_NV_draw_instanced */
-#ifndef GL_NV_draw_instanced
-#define GL_NV_draw_instanced 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glDrawArraysInstancedNV (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
-GL_APICALL void GL_APIENTRY glDrawElementsInstancedNV (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount);
-#endif
-typedef void (GL_APIENTRYP PFNDRAWARRAYSINSTANCEDNVPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
-typedef void (GL_APIENTRYP PFNDRAWELEMENTSINSTANCEDNVPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount);
-#endif
-
-/* GL_NV_fbo_color_attachments */
-#ifndef GL_NV_fbo_color_attachments
-#define GL_NV_fbo_color_attachments 1
-#endif
-
-/* GL_NV_fence */
-#ifndef GL_NV_fence
-#define GL_NV_fence 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glDeleteFencesNV (GLsizei, const GLuint *);
-GL_APICALL void GL_APIENTRY glGenFencesNV (GLsizei, GLuint *);
-GL_APICALL GLboolean GL_APIENTRY glIsFenceNV (GLuint);
-GL_APICALL GLboolean GL_APIENTRY glTestFenceNV (GLuint);
-GL_APICALL void GL_APIENTRY glGetFenceivNV (GLuint, GLenum, GLint *);
-GL_APICALL void GL_APIENTRY glFinishFenceNV (GLuint);
-GL_APICALL void GL_APIENTRY glSetFenceNV (GLuint, GLenum);
-#endif
-typedef void (GL_APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences);
-typedef void (GL_APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences);
-typedef GLboolean (GL_APIENTRYP PFNGLISFENCENVPROC) (GLuint fence);
-typedef GLboolean (GL_APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence);
-typedef void (GL_APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params);
-typedef void (GL_APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence);
-typedef void (GL_APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition);
-#endif
-
-/* GL_NV_framebuffer_blit */
-#ifndef GL_NV_framebuffer_blit
-#define GL_NV_framebuffer_blit 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glBlitFramebufferNV (int srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
-#endif
-typedef void (GL_APIENTRYP PFNBLITFRAMEBUFFERNVPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
-#endif
-
-/* GL_NV_framebuffer_multisample */
-#ifndef GL_NV_framebuffer_multisample
-#define GL_NV_framebuffer_multisample 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleNV ( GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
-#endif
-typedef void (GL_APIENTRYP PFNRENDERBUFFERSTORAGEMULTISAMPLENVPROC) ( GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
-#endif
-
-/* GL_NV_generate_mipmap_sRGB */
-#ifndef GL_NV_generate_mipmap_sRGB
-#define GL_NV_generate_mipmap_sRGB 1
-#endif
-
-/* GL_NV_instanced_arrays */
-#ifndef GL_NV_instanced_arrays
-#define GL_NV_instanced_arrays 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glVertexAttribDivisorNV (GLuint index, GLuint divisor);
-#endif
-typedef void (GL_APIENTRYP PFNVERTEXATTRIBDIVISORNVPROC) (GLuint index, GLuint divisor);
-#endif
-
-/* GL_NV_read_buffer */
-#ifndef GL_NV_read_buffer
-#define GL_NV_read_buffer 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glReadBufferNV (GLenum mode);
-#endif
-typedef void (GL_APIENTRYP PFNGLREADBUFFERNVPROC) (GLenum mode);
-#endif
-
-/* GL_NV_read_buffer_front */
-#ifndef GL_NV_read_buffer_front
-#define GL_NV_read_buffer_front 1
-#endif
-
-/* GL_NV_read_depth */
-#ifndef GL_NV_read_depth
-#define GL_NV_read_depth 1
-#endif
-
-/* GL_NV_read_depth_stencil */
-#ifndef GL_NV_read_depth_stencil
-#define GL_NV_read_depth_stencil 1
-#endif
-
-/* GL_NV_read_stencil */
-#ifndef GL_NV_read_stencil
-#define GL_NV_read_stencil 1
-#endif
-
-/* GL_NV_shadow_samplers_array */
-#ifndef GL_NV_shadow_samplers_array
-#define GL_NV_shadow_samplers_array 1
-#endif
-
-/* GL_NV_shadow_samplers_cube */
-#ifndef GL_NV_shadow_samplers_cube
-#define GL_NV_shadow_samplers_cube 1
-#endif
-
-/* GL_NV_sRGB_formats */
-#ifndef GL_NV_sRGB_formats
-#define GL_NV_sRGB_formats 1
-#endif
-
-/* GL_NV_texture_border_clamp */
-#ifndef GL_NV_texture_border_clamp
-#define GL_NV_texture_border_clamp 1
-#endif
-
-/* GL_NV_texture_compression_s3tc_update */
-#ifndef GL_NV_texture_compression_s3tc_update
-#define GL_NV_texture_compression_s3tc_update 1
-#endif
-
-/* GL_NV_texture_npot_2D_mipmap */
-#ifndef GL_NV_texture_npot_2D_mipmap
-#define GL_NV_texture_npot_2D_mipmap 1
-#endif
-
-/*------------------------------------------------------------------------*
- * QCOM extension functions
- *------------------------------------------------------------------------*/
-
-/* GL_QCOM_alpha_test */
-#ifndef GL_QCOM_alpha_test
-#define GL_QCOM_alpha_test 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glAlphaFuncQCOM (GLenum func, GLclampf ref);
-#endif
-typedef void (GL_APIENTRYP PFNGLALPHAFUNCQCOMPROC) (GLenum func, GLclampf ref);
-#endif
-
-/* GL_QCOM_binning_control */
-#ifndef GL_QCOM_binning_control
-#define GL_QCOM_binning_control 1
-#endif
-
-/* GL_QCOM_driver_control */
-#ifndef GL_QCOM_driver_control
-#define GL_QCOM_driver_control 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glGetDriverControlsQCOM (GLint *num, GLsizei size, GLuint *driverControls);
-GL_APICALL void GL_APIENTRY glGetDriverControlStringQCOM (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString);
-GL_APICALL void GL_APIENTRY glEnableDriverControlQCOM (GLuint driverControl);
-GL_APICALL void GL_APIENTRY glDisableDriverControlQCOM (GLuint driverControl);
-#endif
-typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSQCOMPROC) (GLint *num, GLsizei size, GLuint *driverControls);
-typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSTRINGQCOMPROC) (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString);
-typedef void (GL_APIENTRYP PFNGLENABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);
-typedef void (GL_APIENTRYP PFNGLDISABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);
-#endif
-
-/* GL_QCOM_extended_get */
-#ifndef GL_QCOM_extended_get
-#define GL_QCOM_extended_get 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glExtGetTexturesQCOM (GLuint *textures, GLint maxTextures, GLint *numTextures);
-GL_APICALL void GL_APIENTRY glExtGetBuffersQCOM (GLuint *buffers, GLint maxBuffers, GLint *numBuffers);
-GL_APICALL void GL_APIENTRY glExtGetRenderbuffersQCOM (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers);
-GL_APICALL void GL_APIENTRY glExtGetFramebuffersQCOM (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers);
-GL_APICALL void GL_APIENTRY glExtGetTexLevelParameterivQCOM (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params);
-GL_APICALL void GL_APIENTRY glExtTexObjectStateOverrideiQCOM (GLenum target, GLenum pname, GLint param);
-GL_APICALL void GL_APIENTRY glExtGetTexSubImageQCOM (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels);
-GL_APICALL void GL_APIENTRY glExtGetBufferPointervQCOM (GLenum target, GLvoid **params);
-#endif
-typedef void (GL_APIENTRYP PFNGLEXTGETTEXTURESQCOMPROC) (GLuint *textures, GLint maxTextures, GLint *numTextures);
-typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERSQCOMPROC) (GLuint *buffers, GLint maxBuffers, GLint *numBuffers);
-typedef void (GL_APIENTRYP PFNGLEXTGETRENDERBUFFERSQCOMPROC) (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers);
-typedef void (GL_APIENTRYP PFNGLEXTGETFRAMEBUFFERSQCOMPROC) (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers);
-typedef void (GL_APIENTRYP PFNGLEXTGETTEXLEVELPARAMETERIVQCOMPROC) (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params);
-typedef void (GL_APIENTRYP PFNGLEXTTEXOBJECTSTATEOVERRIDEIQCOMPROC) (GLenum target, GLenum pname, GLint param);
-typedef void (GL_APIENTRYP PFNGLEXTGETTEXSUBIMAGEQCOMPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels);
-typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERPOINTERVQCOMPROC) (GLenum target, GLvoid **params);
-#endif
-
-/* GL_QCOM_extended_get2 */
-#ifndef GL_QCOM_extended_get2
-#define GL_QCOM_extended_get2 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glExtGetShadersQCOM (GLuint *shaders, GLint maxShaders, GLint *numShaders);
-GL_APICALL void GL_APIENTRY glExtGetProgramsQCOM (GLuint *programs, GLint maxPrograms, GLint *numPrograms);
-GL_APICALL GLboolean GL_APIENTRY glExtIsProgramBinaryQCOM (GLuint program);
-GL_APICALL void GL_APIENTRY glExtGetProgramBinarySourceQCOM (GLuint program, GLenum shadertype, GLchar *source, GLint *length);
-#endif
-typedef void (GL_APIENTRYP PFNGLEXTGETSHADERSQCOMPROC) (GLuint *shaders, GLint maxShaders, GLint *numShaders);
-typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMSQCOMPROC) (GLuint *programs, GLint maxPrograms, GLint *numPrograms);
-typedef GLboolean (GL_APIENTRYP PFNGLEXTISPROGRAMBINARYQCOMPROC) (GLuint program);
-typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMBINARYSOURCEQCOMPROC) (GLuint program, GLenum shadertype, GLchar *source, GLint *length);
-#endif
-
-/* GL_QCOM_perfmon_global_mode */
-#ifndef GL_QCOM_perfmon_global_mode
-#define GL_QCOM_perfmon_global_mode 1
-#endif
-
-/* GL_QCOM_writeonly_rendering */
-#ifndef GL_QCOM_writeonly_rendering
-#define GL_QCOM_writeonly_rendering 1
-#endif
-
-/* GL_QCOM_tiled_rendering */
-#ifndef GL_QCOM_tiled_rendering
-#define GL_QCOM_tiled_rendering 1
-#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glStartTilingQCOM (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask);
-GL_APICALL void GL_APIENTRY glEndTilingQCOM (GLbitfield preserveMask);
-#endif
-typedef void (GL_APIENTRYP PFNGLSTARTTILINGQCOMPROC) (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask);
-typedef void (GL_APIENTRYP PFNGLENDTILINGQCOMPROC) (GLbitfield preserveMask);
-#endif
-
-/*------------------------------------------------------------------------*
- * VIV extension tokens
- *------------------------------------------------------------------------*/
-
-/* GL_VIV_shader_binary */
-#ifndef GL_VIV_shader_binary
-#define GL_VIV_shader_binary 1
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __gl2ext_h_ */
+#ifndef __gl2ext_h_
+#define __gl2ext_h_
+
+/* $Revision: 20795 $ on $Date:: 2013-03-07 01:01:58 -0800 #$ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+#ifndef GL_APIENTRYP
+# define GL_APIENTRYP GL_APIENTRY*
+#endif
+
+/*------------------------------------------------------------------------*
+ * OES extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_OES_compressed_ETC1_RGB8_texture */
+#ifndef GL_OES_compressed_ETC1_RGB8_texture
+#define GL_ETC1_RGB8_OES 0x8D64
+#endif
+
+/* GL_OES_compressed_paletted_texture */
+#ifndef GL_OES_compressed_paletted_texture
+#define GL_PALETTE4_RGB8_OES 0x8B90
+#define GL_PALETTE4_RGBA8_OES 0x8B91
+#define GL_PALETTE4_R5_G6_B5_OES 0x8B92
+#define GL_PALETTE4_RGBA4_OES 0x8B93
+#define GL_PALETTE4_RGB5_A1_OES 0x8B94
+#define GL_PALETTE8_RGB8_OES 0x8B95
+#define GL_PALETTE8_RGBA8_OES 0x8B96
+#define GL_PALETTE8_R5_G6_B5_OES 0x8B97
+#define GL_PALETTE8_RGBA4_OES 0x8B98
+#define GL_PALETTE8_RGB5_A1_OES 0x8B99
+#endif
+
+/* GL_OES_depth24 */
+#ifndef GL_OES_depth24
+#define GL_DEPTH_COMPONENT24_OES 0x81A6
+#endif
+
+/* GL_OES_depth32 */
+#ifndef GL_OES_depth32
+#define GL_DEPTH_COMPONENT32_OES 0x81A7
+#endif
+
+/* GL_OES_depth_texture */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_EGL_image */
+#ifndef GL_OES_EGL_image
+typedef void* GLeglImageOES;
+#endif
+
+/* GL_OES_EGL_image_external */
+#ifndef GL_OES_EGL_image_external
+/* GLeglImageOES defined in GL_OES_EGL_image already. */
+#define GL_TEXTURE_EXTERNAL_OES 0x8D65
+#define GL_SAMPLER_EXTERNAL_OES 0x8D66
+#define GL_TEXTURE_BINDING_EXTERNAL_OES 0x8D67
+#define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES 0x8D68
+#endif
+
+/* GL_OES_element_index_uint */
+#ifndef GL_OES_element_index_uint
+#define GL_UNSIGNED_INT 0x1405
+#endif
+
+/* GL_OES_get_program_binary */
+#ifndef GL_OES_get_program_binary
+#define GL_PROGRAM_BINARY_LENGTH_OES 0x8741
+#define GL_NUM_PROGRAM_BINARY_FORMATS_OES 0x87FE
+#define GL_PROGRAM_BINARY_FORMATS_OES 0x87FF
+#endif
+
+/* GL_OES_mapbuffer */
+#ifndef GL_OES_mapbuffer
+#define GL_WRITE_ONLY_OES 0x88B9
+#define GL_BUFFER_ACCESS_OES 0x88BB
+#define GL_BUFFER_MAPPED_OES 0x88BC
+#define GL_BUFFER_MAP_POINTER_OES 0x88BD
+#endif
+
+/* GL_OES_packed_depth_stencil */
+#ifndef GL_OES_packed_depth_stencil
+#define GL_DEPTH_STENCIL_OES 0x84F9
+#define GL_UNSIGNED_INT_24_8_OES 0x84FA
+#define GL_DEPTH24_STENCIL8_OES 0x88F0
+#endif
+
+/* GL_OES_required_internalformat */
+#ifndef GL_OES_required_internalformat
+#define GL_ALPHA8_OES 0x803C
+#define GL_DEPTH_COMPONENT16_OES 0x81A5
+/* reuse GL_DEPTH_COMPONENT24_OES */
+/* reuse GL_DEPTH24_STENCIL8_OES */
+/* reuse GL_DEPTH_COMPONENT32_OES */
+#define GL_LUMINANCE4_ALPHA4_OES 0x8043
+#define GL_LUMINANCE8_ALPHA8_OES 0x8045
+#define GL_LUMINANCE8_OES 0x8040
+#define GL_RGBA4_OES 0x8056
+#define GL_RGB5_A1_OES 0x8057
+#define GL_RGB565_OES 0x8D62
+/* reuse GL_RGB8_OES */
+/* reuse GL_RGBA8_OES */
+/* reuse GL_RGB10_EXT */
+/* reuse GL_RGB10_A2_EXT */
+#endif
+
+/* GL_OES_rgb8_rgba8 */
+#ifndef GL_OES_rgb8_rgba8
+#define GL_RGB8_OES 0x8051
+#define GL_RGBA8_OES 0x8058
+#endif
+
+/* GL_OES_standard_derivatives */
+#ifndef GL_OES_standard_derivatives
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES 0x8B8B
+#endif
+
+/* GL_OES_stencil1 */
+#ifndef GL_OES_stencil1
+#define GL_STENCIL_INDEX1_OES 0x8D46
+#endif
+
+/* GL_OES_stencil4 */
+#ifndef GL_OES_stencil4
+#define GL_STENCIL_INDEX4_OES 0x8D47
+#endif
+
+#ifndef GL_OES_surfaceless_context
+#define GL_FRAMEBUFFER_UNDEFINED_OES 0x8219
+#endif
+
+/* GL_OES_texture_3D */
+#ifndef GL_OES_texture_3D
+#define GL_TEXTURE_WRAP_R_OES 0x8072
+#define GL_TEXTURE_3D_OES 0x806F
+#define GL_TEXTURE_BINDING_3D_OES 0x806A
+#define GL_MAX_3D_TEXTURE_SIZE_OES 0x8073
+#define GL_SAMPLER_3D_OES 0x8B5F
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_OES 0x8CD4
+#endif
+
+/* GL_OES_texture_float */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_texture_float_linear */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_texture_half_float */
+#ifndef GL_OES_texture_half_float
+#define GL_HALF_FLOAT_OES 0x8D61
+#endif
+
+/* GL_OES_texture_half_float_linear */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_texture_npot */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_vertex_array_object */
+#ifndef GL_OES_vertex_array_object
+#define GL_VERTEX_ARRAY_BINDING_OES 0x85B5
+#endif
+
+/* GL_OES_vertex_half_float */
+/* GL_HALF_FLOAT_OES defined in GL_OES_texture_half_float already. */
+
+/* GL_OES_vertex_type_10_10_10_2 */
+#ifndef GL_OES_vertex_type_10_10_10_2
+#define GL_UNSIGNED_INT_10_10_10_2_OES 0x8DF6
+#define GL_INT_10_10_10_2_OES 0x8DF7
+#endif
+
+/*------------------------------------------------------------------------*
+ * KHR extension tokens
+ *------------------------------------------------------------------------*/
+
+#ifndef GL_KHR_debug
+typedef void (GL_APIENTRYP GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,GLvoid *userParam);
+#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242
+#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243
+#define GL_DEBUG_CALLBACK_FUNCTION 0x8244
+#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245
+#define GL_DEBUG_SOURCE_API 0x8246
+#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247
+#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248
+#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249
+#define GL_DEBUG_SOURCE_APPLICATION 0x824A
+#define GL_DEBUG_SOURCE_OTHER 0x824B
+#define GL_DEBUG_TYPE_ERROR 0x824C
+#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D
+#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E
+#define GL_DEBUG_TYPE_PORTABILITY 0x824F
+#define GL_DEBUG_TYPE_PERFORMANCE 0x8250
+#define GL_DEBUG_TYPE_OTHER 0x8251
+#define GL_DEBUG_TYPE_MARKER 0x8268
+#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269
+#define GL_DEBUG_TYPE_POP_GROUP 0x826A
+#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B
+#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C
+#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D
+#define GL_BUFFER 0x82E0
+#define GL_SHADER 0x82E1
+#define GL_PROGRAM 0x82E2
+#define GL_QUERY 0x82E3
+/* PROGRAM_PIPELINE only in GL */
+#define GL_SAMPLER 0x82E6
+/* DISPLAY_LIST only in GL */
+#define GL_MAX_LABEL_LENGTH 0x82E8
+#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143
+#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144
+#define GL_DEBUG_LOGGED_MESSAGES 0x9145
+#define GL_DEBUG_SEVERITY_HIGH 0x9146
+#define GL_DEBUG_SEVERITY_MEDIUM 0x9147
+#define GL_DEBUG_SEVERITY_LOW 0x9148
+#define GL_DEBUG_OUTPUT 0x92E0
+#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
+#define GL_STACK_OVERFLOW 0x0503
+#define GL_STACK_UNDERFLOW 0x0504
+#endif
+
+#ifndef GL_KHR_texture_compression_astc_ldr
+#define GL_COMPRESSED_RGBA_ASTC_4x4_KHR 0x93B0
+#define GL_COMPRESSED_RGBA_ASTC_5x4_KHR 0x93B1
+#define GL_COMPRESSED_RGBA_ASTC_5x5_KHR 0x93B2
+#define GL_COMPRESSED_RGBA_ASTC_6x5_KHR 0x93B3
+#define GL_COMPRESSED_RGBA_ASTC_6x6_KHR 0x93B4
+#define GL_COMPRESSED_RGBA_ASTC_8x5_KHR 0x93B5
+#define GL_COMPRESSED_RGBA_ASTC_8x6_KHR 0x93B6
+#define GL_COMPRESSED_RGBA_ASTC_8x8_KHR 0x93B7
+#define GL_COMPRESSED_RGBA_ASTC_10x5_KHR 0x93B8
+#define GL_COMPRESSED_RGBA_ASTC_10x6_KHR 0x93B9
+#define GL_COMPRESSED_RGBA_ASTC_10x8_KHR 0x93BA
+#define GL_COMPRESSED_RGBA_ASTC_10x10_KHR 0x93BB
+#define GL_COMPRESSED_RGBA_ASTC_12x10_KHR 0x93BC
+#define GL_COMPRESSED_RGBA_ASTC_12x12_KHR 0x93BD
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR 0x93D0
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR 0x93D1
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR 0x93D2
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR 0x93D3
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR 0x93D4
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR 0x93D5
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR 0x93D6
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR 0x93D7
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR 0x93D8
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR 0x93D9
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR 0x93DA
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR 0x93DB
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR 0x93DC
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR 0x93DD
+#endif
+
+/*------------------------------------------------------------------------*
+ * AMD extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_AMD_compressed_3DC_texture */
+#ifndef GL_AMD_compressed_3DC_texture
+#define GL_3DC_X_AMD 0x87F9
+#define GL_3DC_XY_AMD 0x87FA
+#endif
+
+/* GL_AMD_compressed_ATC_texture */
+#ifndef GL_AMD_compressed_ATC_texture
+#define GL_ATC_RGB_AMD 0x8C92
+#define GL_ATC_RGBA_EXPLICIT_ALPHA_AMD 0x8C93
+#define GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD 0x87EE
+#endif
+
+/* GL_AMD_performance_monitor */
+#ifndef GL_AMD_performance_monitor
+#define GL_COUNTER_TYPE_AMD 0x8BC0
+#define GL_COUNTER_RANGE_AMD 0x8BC1
+#define GL_UNSIGNED_INT64_AMD 0x8BC2
+#define GL_PERCENTAGE_AMD 0x8BC3
+#define GL_PERFMON_RESULT_AVAILABLE_AMD 0x8BC4
+#define GL_PERFMON_RESULT_SIZE_AMD 0x8BC5
+#define GL_PERFMON_RESULT_AMD 0x8BC6
+#endif
+
+/* GL_AMD_program_binary_Z400 */
+#ifndef GL_AMD_program_binary_Z400
+#define GL_Z400_BINARY_AMD 0x8740
+#endif
+
+/*------------------------------------------------------------------------*
+ * ANGLE extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_ANGLE_depth_texture */
+#ifndef GL_ANGLE_depth_texture
+#define GL_DEPTH_COMPONENT 0x1902
+#define GL_DEPTH_STENCIL_OES 0x84F9
+#define GL_UNSIGNED_SHORT 0x1403
+#define GL_UNSIGNED_INT 0x1405
+#define GL_UNSIGNED_INT_24_8_OES 0x84FA
+#define GL_DEPTH_COMPONENT16 0x81A5
+#define GL_DEPTH_COMPONENT32_OES 0x81A7
+#define GL_DEPTH24_STENCIL8_OES 0x88F0
+#endif
+
+/* GL_ANGLE_framebuffer_blit */
+#ifndef GL_ANGLE_framebuffer_blit
+#define GL_READ_FRAMEBUFFER_ANGLE 0x8CA8
+#define GL_DRAW_FRAMEBUFFER_ANGLE 0x8CA9
+#define GL_DRAW_FRAMEBUFFER_BINDING_ANGLE 0x8CA6
+#define GL_READ_FRAMEBUFFER_BINDING_ANGLE 0x8CAA
+#endif
+
+/* GL_ANGLE_framebuffer_multisample */
+#ifndef GL_ANGLE_framebuffer_multisample
+#define GL_RENDERBUFFER_SAMPLES_ANGLE 0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE 0x8D56
+#define GL_MAX_SAMPLES_ANGLE 0x8D57
+#endif
+
+/* GL_ANGLE_instanced_arrays */
+#ifndef GL_ANGLE_instanced_arrays
+#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE 0x88FE
+#endif
+
+/* GL_ANGLE_pack_reverse_row_order */
+#ifndef GL_ANGLE_pack_reverse_row_order
+#define GL_PACK_REVERSE_ROW_ORDER_ANGLE 0x93A4
+#endif
+
+/* GL_ANGLE_program_binary */
+#ifndef GL_ANGLE_program_binary
+#define GL_PROGRAM_BINARY_ANGLE 0x93A6
+#endif
+
+/* GL_ANGLE_texture_compression_dxt3 */
+#ifndef GL_ANGLE_texture_compression_dxt3
+#define GL_COMPRESSED_RGBA_S3TC_DXT3_ANGLE 0x83F2
+#endif
+
+/* GL_ANGLE_texture_compression_dxt5 */
+#ifndef GL_ANGLE_texture_compression_dxt5
+#define GL_COMPRESSED_RGBA_S3TC_DXT5_ANGLE 0x83F3
+#endif
+
+/* GL_ANGLE_texture_usage */
+#ifndef GL_ANGLE_texture_usage
+#define GL_TEXTURE_USAGE_ANGLE 0x93A2
+#define GL_FRAMEBUFFER_ATTACHMENT_ANGLE 0x93A3
+#endif
+
+/* GL_ANGLE_translated_shader_source */
+#ifndef GL_ANGLE_translated_shader_source
+#define GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE 0x93A0
+#endif
+
+/*------------------------------------------------------------------------*
+ * APPLE extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_APPLE_copy_texture_levels */
+/* No new tokens introduced by this extension. */
+
+/* GL_APPLE_framebuffer_multisample */
+#ifndef GL_APPLE_framebuffer_multisample
+#define GL_RENDERBUFFER_SAMPLES_APPLE 0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_APPLE 0x8D56
+#define GL_MAX_SAMPLES_APPLE 0x8D57
+#define GL_READ_FRAMEBUFFER_APPLE 0x8CA8
+#define GL_DRAW_FRAMEBUFFER_APPLE 0x8CA9
+#define GL_DRAW_FRAMEBUFFER_BINDING_APPLE 0x8CA6
+#define GL_READ_FRAMEBUFFER_BINDING_APPLE 0x8CAA
+#endif
+
+/* GL_APPLE_rgb_422 */
+#ifndef GL_APPLE_rgb_422
+#define GL_RGB_422_APPLE 0x8A1F
+#define GL_UNSIGNED_SHORT_8_8_APPLE 0x85BA
+#define GL_UNSIGNED_SHORT_8_8_REV_APPLE 0x85BB
+#endif
+
+/* GL_APPLE_sync */
+#ifndef GL_APPLE_sync
+
+#ifndef __gl3_h_
+/* These types are defined with reference to <inttypes.h>
+ * in the Apple extension spec, but here we use the Khronos
+ * portable types in khrplatform.h, and assume those types
+ * are always defined.
+ * If any other extensions using these types are defined,
+ * the typedefs must move out of this block and be shared.
+ */
+typedef khronos_int64_t GLint64;
+typedef khronos_uint64_t GLuint64;
+typedef struct __GLsync *GLsync;
+#endif
+
+#define GL_SYNC_OBJECT_APPLE 0x8A53
+#define GL_MAX_SERVER_WAIT_TIMEOUT_APPLE 0x9111
+#define GL_OBJECT_TYPE_APPLE 0x9112
+#define GL_SYNC_CONDITION_APPLE 0x9113
+#define GL_SYNC_STATUS_APPLE 0x9114
+#define GL_SYNC_FLAGS_APPLE 0x9115
+#define GL_SYNC_FENCE_APPLE 0x9116
+#define GL_SYNC_GPU_COMMANDS_COMPLETE_APPLE 0x9117
+#define GL_UNSIGNALED_APPLE 0x9118
+#define GL_SIGNALED_APPLE 0x9119
+#define GL_ALREADY_SIGNALED_APPLE 0x911A
+#define GL_TIMEOUT_EXPIRED_APPLE 0x911B
+#define GL_CONDITION_SATISFIED_APPLE 0x911C
+#define GL_WAIT_FAILED_APPLE 0x911D
+#define GL_SYNC_FLUSH_COMMANDS_BIT_APPLE 0x00000001
+#define GL_TIMEOUT_IGNORED_APPLE 0xFFFFFFFFFFFFFFFFull
+#endif
+
+/* GL_APPLE_texture_format_BGRA8888 */
+#ifndef GL_APPLE_texture_format_BGRA8888
+#define GL_BGRA_EXT 0x80E1
+#endif
+
+/* GL_APPLE_texture_max_level */
+#ifndef GL_APPLE_texture_max_level
+#define GL_TEXTURE_MAX_LEVEL_APPLE 0x813D
+#endif
+
+/*------------------------------------------------------------------------*
+ * ARM extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_ARM_mali_program_binary */
+#ifndef GL_ARM_mali_program_binary
+#define GL_MALI_PROGRAM_BINARY_ARM 0x8F61
+#endif
+
+/* GL_ARM_mali_shader_binary */
+#ifndef GL_ARM_mali_shader_binary
+#define GL_MALI_SHADER_BINARY_ARM 0x8F60
+#endif
+
+/* GL_ARM_rgba8 */
+/* No new tokens introduced by this extension. */
+
+/*------------------------------------------------------------------------*
+ * EXT extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_EXT_blend_minmax */
+#ifndef GL_EXT_blend_minmax
+#define GL_MIN_EXT 0x8007
+#define GL_MAX_EXT 0x8008
+#endif
+
+/* GL_EXT_color_buffer_half_float */
+#ifndef GL_EXT_color_buffer_half_float
+#define GL_RGBA16F_EXT 0x881A
+#define GL_RGB16F_EXT 0x881B
+#define GL_RG16F_EXT 0x822F
+#define GL_R16F_EXT 0x822D
+#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT 0x8211
+#define GL_UNSIGNED_NORMALIZED_EXT 0x8C17
+#endif
+
+/* GL_EXT_debug_label */
+#ifndef GL_EXT_debug_label
+#define GL_PROGRAM_PIPELINE_OBJECT_EXT 0x8A4F
+#define GL_PROGRAM_OBJECT_EXT 0x8B40
+#define GL_SHADER_OBJECT_EXT 0x8B48
+#define GL_BUFFER_OBJECT_EXT 0x9151
+#define GL_QUERY_OBJECT_EXT 0x9153
+#define GL_VERTEX_ARRAY_OBJECT_EXT 0x9154
+#endif
+
+/* GL_EXT_debug_marker */
+/* No new tokens introduced by this extension. */
+
+/* GL_EXT_discard_framebuffer */
+#ifndef GL_EXT_discard_framebuffer
+#define GL_COLOR_EXT 0x1800
+#define GL_DEPTH_EXT 0x1801
+#define GL_STENCIL_EXT 0x1802
+#endif
+
+/* GL_EXT_map_buffer_range */
+#ifndef GL_EXT_map_buffer_range
+#define GL_MAP_READ_BIT_EXT 0x0001
+#define GL_MAP_WRITE_BIT_EXT 0x0002
+#define GL_MAP_INVALIDATE_RANGE_BIT_EXT 0x0004
+#define GL_MAP_INVALIDATE_BUFFER_BIT_EXT 0x0008
+#define GL_MAP_FLUSH_EXPLICIT_BIT_EXT 0x0010
+#define GL_MAP_UNSYNCHRONIZED_BIT_EXT 0x0020
+#endif
+
+/* GL_EXT_multisampled_render_to_texture */
+#ifndef GL_EXT_multisampled_render_to_texture
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT 0x8D6C
+/* reuse values from GL_EXT_framebuffer_multisample (desktop extension) */
+#define GL_RENDERBUFFER_SAMPLES_EXT 0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT 0x8D56
+#define GL_MAX_SAMPLES_EXT 0x8D57
+#endif
+
+/* GL_EXT_multiview_draw_buffers */
+#ifndef GL_EXT_multiview_draw_buffers
+#define GL_COLOR_ATTACHMENT_EXT 0x90F0
+#define GL_MULTIVIEW_EXT 0x90F1
+#define GL_DRAW_BUFFER_EXT 0x0C01
+#define GL_READ_BUFFER_EXT 0x0C02
+#define GL_MAX_MULTIVIEW_BUFFERS_EXT 0x90F2
+#endif
+
+/* GL_EXT_multi_draw_arrays */
+/* No new tokens introduced by this extension. */
+
+/* GL_EXT_occlusion_query_boolean */
+#ifndef GL_EXT_occlusion_query_boolean
+#define GL_ANY_SAMPLES_PASSED_EXT 0x8C2F
+#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT 0x8D6A
+#define GL_CURRENT_QUERY_EXT 0x8865
+#define GL_QUERY_RESULT_EXT 0x8866
+#define GL_QUERY_RESULT_AVAILABLE_EXT 0x8867
+#endif
+
+/* GL_EXT_read_format_bgra */
+#ifndef GL_EXT_read_format_bgra
+#define GL_BGRA_EXT 0x80E1
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT 0x8365
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT 0x8366
+#endif
+
+/* GL_EXT_robustness */
+#ifndef GL_EXT_robustness
+/* reuse GL_NO_ERROR */
+#define GL_GUILTY_CONTEXT_RESET_EXT 0x8253
+#define GL_INNOCENT_CONTEXT_RESET_EXT 0x8254
+#define GL_UNKNOWN_CONTEXT_RESET_EXT 0x8255
+#define GL_CONTEXT_ROBUST_ACCESS_EXT 0x90F3
+#define GL_RESET_NOTIFICATION_STRATEGY_EXT 0x8256
+#define GL_LOSE_CONTEXT_ON_RESET_EXT 0x8252
+#define GL_NO_RESET_NOTIFICATION_EXT 0x8261
+#endif
+
+/* GL_EXT_separate_shader_objects */
+#ifndef GL_EXT_separate_shader_objects
+#define GL_VERTEX_SHADER_BIT_EXT 0x00000001
+#define GL_FRAGMENT_SHADER_BIT_EXT 0x00000002
+#define GL_ALL_SHADER_BITS_EXT 0xFFFFFFFF
+#define GL_PROGRAM_SEPARABLE_EXT 0x8258
+#define GL_ACTIVE_PROGRAM_EXT 0x8259
+#define GL_PROGRAM_PIPELINE_BINDING_EXT 0x825A
+#endif
+
+/* GL_EXT_shader_framebuffer_fetch */
+#ifndef GL_EXT_shader_framebuffer_fetch
+#define GL_FRAGMENT_SHADER_DISCARDS_SAMPLES_EXT 0x8A52
+#endif
+
+/* GL_EXT_shader_texture_lod */
+/* No new tokens introduced by this extension. */
+
+/* GL_EXT_shadow_samplers */
+#ifndef GL_EXT_shadow_samplers
+#define GL_TEXTURE_COMPARE_MODE_EXT 0x884C
+#define GL_TEXTURE_COMPARE_FUNC_EXT 0x884D
+#define GL_COMPARE_REF_TO_TEXTURE_EXT 0x884E
+#define GL_SAMPLER_2D_SHADOW_EXT 0x8B62
+#endif
+
+/* GL_EXT_sRGB */
+#ifndef GL_EXT_sRGB
+#define GL_SRGB_EXT 0x8C40
+#define GL_SRGB_ALPHA_EXT 0x8C42
+#define GL_SRGB8_ALPHA8_EXT 0x8C43
+#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT 0x8210
+#endif
+
+/* GL_EXT_texture_compression_dxt1 */
+#ifndef GL_EXT_texture_compression_dxt1
+#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT 0x83F0
+#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
+#endif
+
+/* GL_EXT_texture_filter_anisotropic */
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
+#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
+#endif
+
+/* GL_EXT_texture_format_BGRA8888 */
+#ifndef GL_EXT_texture_format_BGRA8888
+#define GL_BGRA_EXT 0x80E1
+#endif
+
+/* GL_EXT_texture_rg */
+#ifndef GL_EXT_texture_rg
+#define GL_RED_EXT 0x1903
+#define GL_RG_EXT 0x8227
+#define GL_R8_EXT 0x8229
+#define GL_RG8_EXT 0x822B
+#endif
+
+/* GL_EXT_texture_storage */
+#ifndef GL_EXT_texture_storage
+#define GL_TEXTURE_IMMUTABLE_FORMAT_EXT 0x912F
+#define GL_ALPHA8_EXT 0x803C
+#define GL_LUMINANCE8_EXT 0x8040
+#define GL_LUMINANCE8_ALPHA8_EXT 0x8045
+#define GL_RGBA32F_EXT 0x8814
+#define GL_RGB32F_EXT 0x8815
+#define GL_ALPHA32F_EXT 0x8816
+#define GL_LUMINANCE32F_EXT 0x8818
+#define GL_LUMINANCE_ALPHA32F_EXT 0x8819
+/* reuse GL_RGBA16F_EXT */
+/* reuse GL_RGB16F_EXT */
+#define GL_ALPHA16F_EXT 0x881C
+#define GL_LUMINANCE16F_EXT 0x881E
+#define GL_LUMINANCE_ALPHA16F_EXT 0x881F
+#define GL_RGB10_A2_EXT 0x8059
+#define GL_RGB10_EXT 0x8052
+#define GL_BGRA8_EXT 0x93A1
+#define GL_R8_EXT 0x8229
+#define GL_RG8_EXT 0x822B
+#define GL_R32F_EXT 0x822E
+#define GL_RG32F_EXT 0x8230
+#define GL_R16F_EXT 0x822D
+#define GL_RG16F_EXT 0x822F
+#endif
+
+/* GL_EXT_texture_type_2_10_10_10_REV */
+#ifndef GL_EXT_texture_type_2_10_10_10_REV
+#define GL_UNSIGNED_INT_2_10_10_10_REV_EXT 0x8368
+#endif
+
+/* GL_EXT_unpack_subimage */
+#ifndef GL_EXT_unpack_subimage
+#define GL_UNPACK_ROW_LENGTH_EXT 0x0CF2
+#define GL_UNPACK_SKIP_ROWS_EXT 0x0CF3
+#define GL_UNPACK_SKIP_PIXELS_EXT 0x0CF4
+#endif
+
+/*------------------------------------------------------------------------*
+ * DMP extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_DMP_shader_binary */
+#ifndef GL_DMP_shader_binary
+#define GL_SHADER_BINARY_DMP 0x9250
+#endif
+
+/*------------------------------------------------------------------------*
+ * FJ extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_FJ_shader_binary_GCCSO */
+#ifndef GL_FJ_shader_binary_GCCSO
+#define GL_GCCSO_SHADER_BINARY_F 0x9260
+#endif
+
+/*------------------------------------------------------------------------*
+ * IMG extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_IMG_program_binary */
+#ifndef GL_IMG_program_binary
+#define GL_SGX_PROGRAM_BINARY_IMG 0x9130
+#endif
+
+/* GL_IMG_read_format */
+#ifndef GL_IMG_read_format
+#define GL_BGRA_IMG 0x80E1
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV_IMG 0x8365
+#endif
+
+/* GL_IMG_shader_binary */
+#ifndef GL_IMG_shader_binary
+#define GL_SGX_BINARY_IMG 0x8C0A
+#endif
+
+/* GL_IMG_texture_compression_pvrtc */
+#ifndef GL_IMG_texture_compression_pvrtc
+#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00
+#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01
+#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02
+#define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03
+#endif
+
+/* GL_IMG_texture_compression_pvrtc2 */
+#ifndef GL_IMG_texture_compression_pvrtc2
+#define GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG 0x9137
+#define GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG 0x9138
+#endif
+
+/* GL_IMG_multisampled_render_to_texture */
+#ifndef GL_IMG_multisampled_render_to_texture
+#define GL_RENDERBUFFER_SAMPLES_IMG 0x9133
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG 0x9134
+#define GL_MAX_SAMPLES_IMG 0x9135
+#define GL_TEXTURE_SAMPLES_IMG 0x9136
+#endif
+
+/*------------------------------------------------------------------------*
+ * NV extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_NV_coverage_sample */
+#ifndef GL_NV_coverage_sample
+#define GL_COVERAGE_COMPONENT_NV 0x8ED0
+#define GL_COVERAGE_COMPONENT4_NV 0x8ED1
+#define GL_COVERAGE_ATTACHMENT_NV 0x8ED2
+#define GL_COVERAGE_BUFFERS_NV 0x8ED3
+#define GL_COVERAGE_SAMPLES_NV 0x8ED4
+#define GL_COVERAGE_ALL_FRAGMENTS_NV 0x8ED5
+#define GL_COVERAGE_EDGE_FRAGMENTS_NV 0x8ED6
+#define GL_COVERAGE_AUTOMATIC_NV 0x8ED7
+#define GL_COVERAGE_BUFFER_BIT_NV 0x8000
+#endif
+
+/* GL_NV_depth_nonlinear */
+#ifndef GL_NV_depth_nonlinear
+#define GL_DEPTH_COMPONENT16_NONLINEAR_NV 0x8E2C
+#endif
+
+/* GL_NV_draw_buffers */
+#ifndef GL_NV_draw_buffers
+#define GL_MAX_DRAW_BUFFERS_NV 0x8824
+#define GL_DRAW_BUFFER0_NV 0x8825
+#define GL_DRAW_BUFFER1_NV 0x8826
+#define GL_DRAW_BUFFER2_NV 0x8827
+#define GL_DRAW_BUFFER3_NV 0x8828
+#define GL_DRAW_BUFFER4_NV 0x8829
+#define GL_DRAW_BUFFER5_NV 0x882A
+#define GL_DRAW_BUFFER6_NV 0x882B
+#define GL_DRAW_BUFFER7_NV 0x882C
+#define GL_DRAW_BUFFER8_NV 0x882D
+#define GL_DRAW_BUFFER9_NV 0x882E
+#define GL_DRAW_BUFFER10_NV 0x882F
+#define GL_DRAW_BUFFER11_NV 0x8830
+#define GL_DRAW_BUFFER12_NV 0x8831
+#define GL_DRAW_BUFFER13_NV 0x8832
+#define GL_DRAW_BUFFER14_NV 0x8833
+#define GL_DRAW_BUFFER15_NV 0x8834
+#define GL_COLOR_ATTACHMENT0_NV 0x8CE0
+#define GL_COLOR_ATTACHMENT1_NV 0x8CE1
+#define GL_COLOR_ATTACHMENT2_NV 0x8CE2
+#define GL_COLOR_ATTACHMENT3_NV 0x8CE3
+#define GL_COLOR_ATTACHMENT4_NV 0x8CE4
+#define GL_COLOR_ATTACHMENT5_NV 0x8CE5
+#define GL_COLOR_ATTACHMENT6_NV 0x8CE6
+#define GL_COLOR_ATTACHMENT7_NV 0x8CE7
+#define GL_COLOR_ATTACHMENT8_NV 0x8CE8
+#define GL_COLOR_ATTACHMENT9_NV 0x8CE9
+#define GL_COLOR_ATTACHMENT10_NV 0x8CEA
+#define GL_COLOR_ATTACHMENT11_NV 0x8CEB
+#define GL_COLOR_ATTACHMENT12_NV 0x8CEC
+#define GL_COLOR_ATTACHMENT13_NV 0x8CED
+#define GL_COLOR_ATTACHMENT14_NV 0x8CEE
+#define GL_COLOR_ATTACHMENT15_NV 0x8CEF
+#endif
+
+/* GL_EXT_draw_buffers */
+#ifndef GL_EXT_draw_buffers
+#define GL_MAX_DRAW_BUFFERS_EXT 0x8824
+#define GL_DRAW_BUFFER0_EXT 0x8825
+#define GL_DRAW_BUFFER1_EXT 0x8826
+#define GL_DRAW_BUFFER2_EXT 0x8827
+#define GL_DRAW_BUFFER3_EXT 0x8828
+#define GL_DRAW_BUFFER4_EXT 0x8829
+#define GL_DRAW_BUFFER5_EXT 0x882A
+#define GL_DRAW_BUFFER6_EXT 0x882B
+#define GL_DRAW_BUFFER7_EXT 0x882C
+#define GL_DRAW_BUFFER8_EXT 0x882D
+#define GL_DRAW_BUFFER9_EXT 0x882E
+#define GL_DRAW_BUFFER10_EXT 0x882F
+#define GL_DRAW_BUFFER11_EXT 0x8830
+#define GL_DRAW_BUFFER12_EXT 0x8831
+#define GL_DRAW_BUFFER13_EXT 0x8832
+#define GL_DRAW_BUFFER14_EXT 0x8833
+#define GL_DRAW_BUFFER15_EXT 0x8834
+#define GL_COLOR_ATTACHMENT0_EXT 0x8CE0
+#define GL_COLOR_ATTACHMENT1_EXT 0x8CE1
+#define GL_COLOR_ATTACHMENT2_EXT 0x8CE2
+#define GL_COLOR_ATTACHMENT3_EXT 0x8CE3
+#define GL_COLOR_ATTACHMENT4_EXT 0x8CE4
+#define GL_COLOR_ATTACHMENT5_EXT 0x8CE5
+#define GL_COLOR_ATTACHMENT6_EXT 0x8CE6
+#define GL_COLOR_ATTACHMENT7_EXT 0x8CE7
+#define GL_COLOR_ATTACHMENT8_EXT 0x8CE8
+#define GL_COLOR_ATTACHMENT9_EXT 0x8CE9
+#define GL_COLOR_ATTACHMENT10_EXT 0x8CEA
+#define GL_COLOR_ATTACHMENT11_EXT 0x8CEB
+#define GL_COLOR_ATTACHMENT12_EXT 0x8CEC
+#define GL_COLOR_ATTACHMENT13_EXT 0x8CED
+#define GL_COLOR_ATTACHMENT14_EXT 0x8CEE
+#define GL_COLOR_ATTACHMENT15_EXT 0x8CEF
+#define GL_MAX_COLOR_ATTACHMENTS_EXT 0x8CDF
+#endif
+
+/* GL_NV_draw_instanced */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_fbo_color_attachments */
+#ifndef GL_NV_fbo_color_attachments
+#define GL_MAX_COLOR_ATTACHMENTS_NV 0x8CDF
+/* GL_COLOR_ATTACHMENT{0-15}_NV defined in GL_NV_draw_buffers already. */
+#endif
+
+/* GL_NV_fence */
+#ifndef GL_NV_fence
+#define GL_ALL_COMPLETED_NV 0x84F2
+#define GL_FENCE_STATUS_NV 0x84F3
+#define GL_FENCE_CONDITION_NV 0x84F4
+#endif
+
+/* GL_NV_framebuffer_blit */
+#ifndef GL_NV_framebuffer_blit
+#define GL_READ_FRAMEBUFFER_NV 0x8CA8
+#define GL_DRAW_FRAMEBUFFER_NV 0x8CA9
+#define GL_DRAW_FRAMEBUFFER_BINDING_NV 0x8CA6
+#define GL_READ_FRAMEBUFFER_BINDING_NV 0x8CAA
+#endif
+
+/* GL_NV_framebuffer_multisample */
+#ifndef GL_NV_framebuffer_multisample
+#define GL_RENDERBUFFER_SAMPLES_NV 0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_NV 0x8D56
+#define GL_MAX_SAMPLES_NV 0x8D57
+#endif
+
+/* GL_NV_generate_mipmap_sRGB */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_instanced_arrays */
+#ifndef GL_NV_instanced_arrays
+#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR_NV 0x88FE
+#endif
+
+/* GL_NV_read_buffer */
+#ifndef GL_NV_read_buffer
+#define GL_READ_BUFFER_NV 0x0C02
+#endif
+
+/* GL_NV_read_buffer_front */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_read_depth */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_read_depth_stencil */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_read_stencil */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_shadow_samplers_array */
+#ifndef GL_NV_shadow_samplers_array
+#define GL_SAMPLER_2D_ARRAY_SHADOW_NV 0x8DC4
+#endif
+
+/* GL_NV_shadow_samplers_cube */
+#ifndef GL_NV_shadow_samplers_cube
+#define GL_SAMPLER_CUBE_SHADOW_NV 0x8DC5
+#endif
+
+/* GL_NV_sRGB_formats */
+#ifndef GL_NV_sRGB_formats
+#define GL_SLUMINANCE_NV 0x8C46
+#define GL_SLUMINANCE_ALPHA_NV 0x8C44
+#define GL_SRGB8_NV 0x8C41
+#define GL_SLUMINANCE8_NV 0x8C47
+#define GL_SLUMINANCE8_ALPHA8_NV 0x8C45
+#define GL_COMPRESSED_SRGB_S3TC_DXT1_NV 0x8C4C
+#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_NV 0x8C4D
+#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_NV 0x8C4E
+#define GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_NV 0x8C4F
+#define GL_ETC1_SRGB8_NV 0x88EE
+#endif
+
+/* GL_NV_texture_border_clamp */
+#ifndef GL_NV_texture_border_clamp
+#define GL_TEXTURE_BORDER_COLOR_NV 0x1004
+#define GL_CLAMP_TO_BORDER_NV 0x812D
+#endif
+
+/* GL_NV_texture_compression_s3tc_update */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_texture_npot_2D_mipmap */
+/* No new tokens introduced by this extension. */
+
+/*------------------------------------------------------------------------*
+ * QCOM extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_QCOM_alpha_test */
+#ifndef GL_QCOM_alpha_test
+#define GL_ALPHA_TEST_QCOM 0x0BC0
+#define GL_ALPHA_TEST_FUNC_QCOM 0x0BC1
+#define GL_ALPHA_TEST_REF_QCOM 0x0BC2
+#endif
+
+/* GL_QCOM_binning_control */
+#ifndef GL_QCOM_binning_control
+#define GL_BINNING_CONTROL_HINT_QCOM 0x8FB0
+#define GL_CPU_OPTIMIZED_QCOM 0x8FB1
+#define GL_GPU_OPTIMIZED_QCOM 0x8FB2
+#define GL_RENDER_DIRECT_TO_FRAMEBUFFER_QCOM 0x8FB3
+#endif
+
+/* GL_QCOM_driver_control */
+/* No new tokens introduced by this extension. */
+
+/* GL_QCOM_extended_get */
+#ifndef GL_QCOM_extended_get
+#define GL_TEXTURE_WIDTH_QCOM 0x8BD2
+#define GL_TEXTURE_HEIGHT_QCOM 0x8BD3
+#define GL_TEXTURE_DEPTH_QCOM 0x8BD4
+#define GL_TEXTURE_INTERNAL_FORMAT_QCOM 0x8BD5
+#define GL_TEXTURE_FORMAT_QCOM 0x8BD6
+#define GL_TEXTURE_TYPE_QCOM 0x8BD7
+#define GL_TEXTURE_IMAGE_VALID_QCOM 0x8BD8
+#define GL_TEXTURE_NUM_LEVELS_QCOM 0x8BD9
+#define GL_TEXTURE_TARGET_QCOM 0x8BDA
+#define GL_TEXTURE_OBJECT_VALID_QCOM 0x8BDB
+#define GL_STATE_RESTORE 0x8BDC
+#endif
+
+/* GL_QCOM_extended_get2 */
+/* No new tokens introduced by this extension. */
+
+/* GL_QCOM_perfmon_global_mode */
+#ifndef GL_QCOM_perfmon_global_mode
+#define GL_PERFMON_GLOBAL_MODE_QCOM 0x8FA0
+#endif
+
+/* GL_QCOM_writeonly_rendering */
+#ifndef GL_QCOM_writeonly_rendering
+#define GL_WRITEONLY_RENDERING_QCOM 0x8823
+#endif
+
+/* GL_QCOM_tiled_rendering */
+#ifndef GL_QCOM_tiled_rendering
+#define GL_COLOR_BUFFER_BIT0_QCOM 0x00000001
+#define GL_COLOR_BUFFER_BIT1_QCOM 0x00000002
+#define GL_COLOR_BUFFER_BIT2_QCOM 0x00000004
+#define GL_COLOR_BUFFER_BIT3_QCOM 0x00000008
+#define GL_COLOR_BUFFER_BIT4_QCOM 0x00000010
+#define GL_COLOR_BUFFER_BIT5_QCOM 0x00000020
+#define GL_COLOR_BUFFER_BIT6_QCOM 0x00000040
+#define GL_COLOR_BUFFER_BIT7_QCOM 0x00000080
+#define GL_DEPTH_BUFFER_BIT0_QCOM 0x00000100
+#define GL_DEPTH_BUFFER_BIT1_QCOM 0x00000200
+#define GL_DEPTH_BUFFER_BIT2_QCOM 0x00000400
+#define GL_DEPTH_BUFFER_BIT3_QCOM 0x00000800
+#define GL_DEPTH_BUFFER_BIT4_QCOM 0x00001000
+#define GL_DEPTH_BUFFER_BIT5_QCOM 0x00002000
+#define GL_DEPTH_BUFFER_BIT6_QCOM 0x00004000
+#define GL_DEPTH_BUFFER_BIT7_QCOM 0x00008000
+#define GL_STENCIL_BUFFER_BIT0_QCOM 0x00010000
+#define GL_STENCIL_BUFFER_BIT1_QCOM 0x00020000
+#define GL_STENCIL_BUFFER_BIT2_QCOM 0x00040000
+#define GL_STENCIL_BUFFER_BIT3_QCOM 0x00080000
+#define GL_STENCIL_BUFFER_BIT4_QCOM 0x00100000
+#define GL_STENCIL_BUFFER_BIT5_QCOM 0x00200000
+#define GL_STENCIL_BUFFER_BIT6_QCOM 0x00400000
+#define GL_STENCIL_BUFFER_BIT7_QCOM 0x00800000
+#define GL_MULTISAMPLE_BUFFER_BIT0_QCOM 0x01000000
+#define GL_MULTISAMPLE_BUFFER_BIT1_QCOM 0x02000000
+#define GL_MULTISAMPLE_BUFFER_BIT2_QCOM 0x04000000
+#define GL_MULTISAMPLE_BUFFER_BIT3_QCOM 0x08000000
+#define GL_MULTISAMPLE_BUFFER_BIT4_QCOM 0x10000000
+#define GL_MULTISAMPLE_BUFFER_BIT5_QCOM 0x20000000
+#define GL_MULTISAMPLE_BUFFER_BIT6_QCOM 0x40000000
+#define GL_MULTISAMPLE_BUFFER_BIT7_QCOM 0x80000000
+#endif
+
+/*------------------------------------------------------------------------*
+ * VIV extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_VIV_shader_binary */
+#ifndef GL_VIV_shader_binary
+#define GL_SHADER_BINARY_VIV 0x8FC4
+#endif
+
+/*------------------------------------------------------------------------*
+ * End of extension tokens, start of corresponding extension functions
+ *------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------*
+ * OES extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_OES_compressed_ETC1_RGB8_texture */
+#ifndef GL_OES_compressed_ETC1_RGB8_texture
+#define GL_OES_compressed_ETC1_RGB8_texture 1
+#endif
+
+/* GL_OES_compressed_paletted_texture */
+#ifndef GL_OES_compressed_paletted_texture
+#define GL_OES_compressed_paletted_texture 1
+#endif
+
+/* GL_OES_depth24 */
+#ifndef GL_OES_depth24
+#define GL_OES_depth24 1
+#endif
+
+/* GL_OES_depth32 */
+#ifndef GL_OES_depth32
+#define GL_OES_depth32 1
+#endif
+
+/* GL_OES_depth_texture */
+#ifndef GL_OES_depth_texture
+#define GL_OES_depth_texture 1
+#endif
+
+/* GL_OES_EGL_image */
+#ifndef GL_OES_EGL_image
+#define GL_OES_EGL_image 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image);
+GL_APICALL void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image);
+#endif
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
+#endif
+
+/* GL_OES_EGL_image_external */
+#ifndef GL_OES_EGL_image_external
+#define GL_OES_EGL_image_external 1
+/* glEGLImageTargetTexture2DOES defined in GL_OES_EGL_image already. */
+#endif
+
+/* GL_OES_element_index_uint */
+#ifndef GL_OES_element_index_uint
+#define GL_OES_element_index_uint 1
+#endif
+
+/* GL_OES_fbo_render_mipmap */
+#ifndef GL_OES_fbo_render_mipmap
+#define GL_OES_fbo_render_mipmap 1
+#endif
+
+/* GL_OES_fragment_precision_high */
+#ifndef GL_OES_fragment_precision_high
+#define GL_OES_fragment_precision_high 1
+#endif
+
+/* GL_OES_get_program_binary */
+#ifndef GL_OES_get_program_binary
+#define GL_OES_get_program_binary 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetProgramBinaryOES (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary);
+GL_APICALL void GL_APIENTRY glProgramBinaryOES (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETPROGRAMBINARYOESPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary);
+typedef void (GL_APIENTRYP PFNGLPROGRAMBINARYOESPROC) (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length);
+#endif
+
+/* GL_OES_mapbuffer */
+#ifndef GL_OES_mapbuffer
+#define GL_OES_mapbuffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void* GL_APIENTRY glMapBufferOES (GLenum target, GLenum access);
+GL_APICALL GLboolean GL_APIENTRY glUnmapBufferOES (GLenum target);
+GL_APICALL void GL_APIENTRY glGetBufferPointervOES (GLenum target, GLenum pname, GLvoid** params);
+#endif
+typedef void* (GL_APIENTRYP PFNGLMAPBUFFEROESPROC) (GLenum target, GLenum access);
+typedef GLboolean (GL_APIENTRYP PFNGLUNMAPBUFFEROESPROC) (GLenum target);
+typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, GLvoid** params);
+#endif
+
+/* GL_OES_packed_depth_stencil */
+#ifndef GL_OES_packed_depth_stencil
+#define GL_OES_packed_depth_stencil 1
+#endif
+
+/* GL_OES_required_internalformat */
+#ifndef GL_OES_required_internalformat
+#define GL_OES_required_internalformat 1
+#endif
+
+/* GL_OES_rgb8_rgba8 */
+#ifndef GL_OES_rgb8_rgba8
+#define GL_OES_rgb8_rgba8 1
+#endif
+
+/* GL_OES_standard_derivatives */
+#ifndef GL_OES_standard_derivatives
+#define GL_OES_standard_derivatives 1
+#endif
+
+/* GL_OES_stencil1 */
+#ifndef GL_OES_stencil1
+#define GL_OES_stencil1 1
+#endif
+
+/* GL_OES_stencil4 */
+#ifndef GL_OES_stencil4
+#define GL_OES_stencil4 1
+#endif
+
+#ifndef GL_OES_surfaceless_context
+#define GL_OES_surfaceless_context 1
+#endif
+
+/* GL_OES_texture_3D */
+#ifndef GL_OES_texture_3D
+#define GL_OES_texture_3D 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glCopyTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glCompressedTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void GL_APIENTRY glCompressedTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void GL_APIENTRY glFramebufferTexture3DOES (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+#endif
+typedef void (GL_APIENTRYP PFNGLTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels);
+typedef void (GL_APIENTRYP PFNGLCOPYTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data);
+typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DOES) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+#endif
+
+/* GL_OES_texture_float */
+#ifndef GL_OES_texture_float
+#define GL_OES_texture_float 1
+#endif
+
+/* GL_OES_texture_float_linear */
+#ifndef GL_OES_texture_float_linear
+#define GL_OES_texture_float_linear 1
+#endif
+
+/* GL_OES_texture_half_float */
+#ifndef GL_OES_texture_half_float
+#define GL_OES_texture_half_float 1
+#endif
+
+/* GL_OES_texture_half_float_linear */
+#ifndef GL_OES_texture_half_float_linear
+#define GL_OES_texture_half_float_linear 1
+#endif
+
+/* GL_OES_texture_npot */
+#ifndef GL_OES_texture_npot
+#define GL_OES_texture_npot 1
+#endif
+
+/* GL_OES_vertex_array_object */
+#ifndef GL_OES_vertex_array_object
+#define GL_OES_vertex_array_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glBindVertexArrayOES (GLuint array);
+GL_APICALL void GL_APIENTRY glDeleteVertexArraysOES (GLsizei n, const GLuint *arrays);
+GL_APICALL void GL_APIENTRY glGenVertexArraysOES (GLsizei n, GLuint *arrays);
+GL_APICALL GLboolean GL_APIENTRY glIsVertexArrayOES (GLuint array);
+#endif
+typedef void (GL_APIENTRYP PFNGLBINDVERTEXARRAYOESPROC) (GLuint array);
+typedef void (GL_APIENTRYP PFNGLDELETEVERTEXARRAYSOESPROC) (GLsizei n, const GLuint *arrays);
+typedef void (GL_APIENTRYP PFNGLGENVERTEXARRAYSOESPROC) (GLsizei n, GLuint *arrays);
+typedef GLboolean (GL_APIENTRYP PFNGLISVERTEXARRAYOESPROC) (GLuint array);
+#endif
+
+/* GL_OES_vertex_half_float */
+#ifndef GL_OES_vertex_half_float
+#define GL_OES_vertex_half_float 1
+#endif
+
+/* GL_OES_vertex_type_10_10_10_2 */
+#ifndef GL_OES_vertex_type_10_10_10_2
+#define GL_OES_vertex_type_10_10_10_2 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * KHR extension functions
+ *------------------------------------------------------------------------*/
+
+#ifndef GL_KHR_debug
+#define GL_KHR_debug 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDebugMessageControl (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
+GL_APICALL void GL_APIENTRY glDebugMessageInsert (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
+GL_APICALL void GL_APIENTRY glDebugMessageCallback (GLDEBUGPROC callback, const void *userParam);
+GL_APICALL GLuint GL_APIENTRY glGetDebugMessageLog (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
+GL_APICALL void GL_APIENTRY glPushDebugGroup (GLenum source, GLuint id, GLsizei length, const GLchar *message);
+GL_APICALL void GL_APIENTRY glPopDebugGroup (void);
+GL_APICALL void GL_APIENTRY glObjectLabel (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);
+GL_APICALL void GL_APIENTRY glGetObjectLabel (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);
+GL_APICALL void GL_APIENTRY glObjectPtrLabel (const void *ptr, GLsizei length, const GLchar *label);
+GL_APICALL void GL_APIENTRY glGetObjectPtrLabel (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);
+GL_APICALL void GL_APIENTRY glGetPointerv (GLenum pname, void **params);
+#endif
+typedef void (GL_APIENTRYP PFNGLDEBUGMESSAGECONTROLPROC) (GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
+typedef void (GL_APIENTRYP PFNGLDEBUGMESSAGEINSERTPROC) (GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
+typedef void (GL_APIENTRYP PFNGLDEBUGMESSAGECALLBACKPROC) (GLDEBUGPROC callback, const void *userParam);
+typedef GLuint (GL_APIENTRYP PFNGLGETDEBUGMESSAGELOGPROC) (GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
+typedef void (GL_APIENTRYP PFNGLPUSHDEBUGGROUPPROC) (GLenum source, GLuint id, GLsizei length, const GLchar *message);
+typedef void (GL_APIENTRYP PFNGLPOPDEBUGGROUPPROC) (void);
+typedef void (GL_APIENTRYP PFNGLOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei length, const GLchar *label);
+typedef void (GL_APIENTRYP PFNGLGETOBJECTLABELPROC) (GLenum identifier, GLuint name, GLsizei bufSize, GLsizei *length, GLchar *label);
+typedef void (GL_APIENTRYP PFNGLOBJECTPTRLABELPROC) (const void *ptr, GLsizei length, const GLchar *label);
+typedef void (GL_APIENTRYP PFNGLGETOBJECTPTRLABELPROC) (const void *ptr, GLsizei bufSize, GLsizei *length, GLchar *label);
+typedef void (GL_APIENTRYP PFNGLGETPOINTERVPROC) (GLenum pname, void **params);
+#endif
+
+#ifndef GL_KHR_texture_compression_astc_ldr
+#define GL_KHR_texture_compression_astc_ldr 1
+#endif
+
+
+/*------------------------------------------------------------------------*
+ * AMD extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_AMD_compressed_3DC_texture */
+#ifndef GL_AMD_compressed_3DC_texture
+#define GL_AMD_compressed_3DC_texture 1
+#endif
+
+/* GL_AMD_compressed_ATC_texture */
+#ifndef GL_AMD_compressed_ATC_texture
+#define GL_AMD_compressed_ATC_texture 1
+#endif
+
+/* AMD_performance_monitor */
+#ifndef GL_AMD_performance_monitor
+#define GL_AMD_performance_monitor 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsSize, GLuint *groups);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, GLvoid *data);
+GL_APICALL void GL_APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors);
+GL_APICALL void GL_APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors);
+GL_APICALL void GL_APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList);
+GL_APICALL void GL_APIENTRY glBeginPerfMonitorAMD (GLuint monitor);
+GL_APICALL void GL_APIENTRY glEndPerfMonitorAMD (GLuint monitor);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterDataAMD (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLsizei groupsSize, GLuint *groups);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, GLvoid *data);
+typedef void (GL_APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);
+typedef void (GL_APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);
+typedef void (GL_APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList);
+typedef void (GL_APIENTRYP PFNGLBEGINPERFMONITORAMDPROC) (GLuint monitor);
+typedef void (GL_APIENTRYP PFNGLENDPERFMONITORAMDPROC) (GLuint monitor);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);
+#endif
+
+/* GL_AMD_program_binary_Z400 */
+#ifndef GL_AMD_program_binary_Z400
+#define GL_AMD_program_binary_Z400 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * ANGLE extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_ANGLE_depth_texture */
+#ifndef GL_ANGLE_depth_texture
+#define GL_ANGLE_depth_texture 1
+#endif
+
+/* GL_ANGLE_framebuffer_blit */
+#ifndef GL_ANGLE_framebuffer_blit
+#define GL_ANGLE_framebuffer_blit 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glBlitFramebufferANGLE (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+#endif
+typedef void (GL_APIENTRYP PFNGLBLITFRAMEBUFFERANGLEPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+#endif
+
+/* GL_ANGLE_framebuffer_multisample */
+#ifndef GL_ANGLE_framebuffer_multisample
+#define GL_ANGLE_framebuffer_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleANGLE (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+#endif
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEANGLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+#endif
+
+#ifndef GL_ANGLE_instanced_arrays
+#define GL_ANGLE_instanced_arrays 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDrawArraysInstancedANGLE (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
+GL_APICALL void GL_APIENTRY glDrawElementsInstancedANGLE (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
+GL_APICALL void GL_APIENTRY glVertexAttribDivisorANGLE (GLuint index, GLuint divisor);
+#endif
+typedef void (GL_APIENTRYP PFNGLDRAWARRAYSINSTANCEDANGLEPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
+typedef void (GL_APIENTRYP PFNGLDRAWELEMENTSINSTANCEDANGLEPROC) (GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei primcount);
+typedef void (GL_APIENTRYP PFNGLVERTEXATTRIBDIVISORANGLEPROC) (GLuint index, GLuint divisor);
+#endif
+
+/* GL_ANGLE_pack_reverse_row_order */
+#ifndef GL_ANGLE_pack_reverse_row_order
+#define GL_ANGLE_pack_reverse_row_order 1
+#endif
+
+/* GL_ANGLE_program_binary */
+#ifndef GL_ANGLE_program_binary
+#define GL_ANGLE_program_binary 1
+#endif
+
+/* GL_ANGLE_texture_compression_dxt3 */
+#ifndef GL_ANGLE_texture_compression_dxt3
+#define GL_ANGLE_texture_compression_dxt3 1
+#endif
+
+/* GL_ANGLE_texture_compression_dxt5 */
+#ifndef GL_ANGLE_texture_compression_dxt5
+#define GL_ANGLE_texture_compression_dxt5 1
+#endif
+
+/* GL_ANGLE_texture_usage */
+#ifndef GL_ANGLE_texture_usage
+#define GL_ANGLE_texture_usage 1
+#endif
+
+#ifndef GL_ANGLE_translated_shader_source
+#define GL_ANGLE_translated_shader_source 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetTranslatedShaderSourceANGLE (GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETTRANSLATEDSHADERSOURCEANGLEPROC) (GLuint shader, GLsizei bufsize, GLsizei *length, GLchar *source);
+#endif
+
+/*------------------------------------------------------------------------*
+ * APPLE extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_APPLE_copy_texture_levels */
+#ifndef GL_APPLE_copy_texture_levels
+#define GL_APPLE_copy_texture_levels 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glCopyTextureLevelsAPPLE (GLuint destinationTexture, GLuint sourceTexture, GLint sourceBaseLevel, GLsizei sourceLevelCount);
+#endif
+typedef void (GL_APIENTRYP PFNGLCOPYTEXTURELEVELSAPPLEPROC) (GLuint destinationTexture, GLuint sourceTexture, GLint sourceBaseLevel, GLsizei sourceLevelCount);
+#endif
+
+/* GL_APPLE_framebuffer_multisample */
+#ifndef GL_APPLE_framebuffer_multisample
+#define GL_APPLE_framebuffer_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleAPPLE (GLenum, GLsizei, GLenum, GLsizei, GLsizei);
+GL_APICALL void GL_APIENTRY glResolveMultisampleFramebufferAPPLE (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEAPPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLRESOLVEMULTISAMPLEFRAMEBUFFERAPPLEPROC) (void);
+#endif
+
+/* GL_APPLE_rgb_422 */
+#ifndef GL_APPLE_rgb_422
+#define GL_APPLE_rgb_422 1
+#endif
+
+/* GL_APPLE_sync */
+#ifndef GL_APPLE_sync
+#define GL_APPLE_sync 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL GLsync GL_APIENTRY glFenceSyncAPPLE (GLenum condition, GLbitfield flags);
+GL_APICALL GLboolean GL_APIENTRY glIsSyncAPPLE (GLsync sync);
+GL_APICALL void GL_APIENTRY glDeleteSyncAPPLE (GLsync sync);
+GL_APICALL GLenum GL_APIENTRY glClientWaitSyncAPPLE (GLsync sync, GLbitfield flags, GLuint64 timeout);
+GL_APICALL void GL_APIENTRY glWaitSyncAPPLE (GLsync sync, GLbitfield flags, GLuint64 timeout);
+GL_APICALL void GL_APIENTRY glGetInteger64vAPPLE (GLenum pname, GLint64 *params);
+GL_APICALL void GL_APIENTRY glGetSyncivAPPLE (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values);
+#endif
+typedef GLsync (GL_APIENTRYP PFNGLFENCESYNCAPPLEPROC) (GLenum condition, GLbitfield flags);
+typedef GLboolean (GL_APIENTRYP PFNGLISSYNCAPPLEPROC) (GLsync sync);
+typedef void (GL_APIENTRYP PFNGLDELETESYNCAPPLEPROC) (GLsync sync);
+typedef GLenum (GL_APIENTRYP PFNGLCLIENTWAITSYNCAPPLEPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout);
+typedef void (GL_APIENTRYP PFNGLWAITSYNCAPPLEPROC) (GLsync sync, GLbitfield flags, GLuint64 timeout);
+typedef void (GL_APIENTRYP PFNGLGETINTEGER64VAPPLEPROC) (GLenum pname, GLint64 *params);
+typedef void (GL_APIENTRYP PFNGLGETSYNCIVAPPLEPROC) (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values);
+#endif
+
+/* GL_APPLE_texture_format_BGRA8888 */
+#ifndef GL_APPLE_texture_format_BGRA8888
+#define GL_APPLE_texture_format_BGRA8888 1
+#endif
+
+/* GL_APPLE_texture_max_level */
+#ifndef GL_APPLE_texture_max_level
+#define GL_APPLE_texture_max_level 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * ARM extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_ARM_mali_program_binary */
+#ifndef GL_ARM_mali_program_binary
+#define GL_ARM_mali_program_binary 1
+#endif
+
+/* GL_ARM_mali_shader_binary */
+#ifndef GL_ARM_mali_shader_binary
+#define GL_ARM_mali_shader_binary 1
+#endif
+
+/* GL_ARM_rgba8 */
+#ifndef GL_ARM_rgba8
+#define GL_ARM_rgba8 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * EXT extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_EXT_blend_minmax */
+#ifndef GL_EXT_blend_minmax
+#define GL_EXT_blend_minmax 1
+#endif
+
+/* GL_EXT_color_buffer_half_float */
+#ifndef GL_EXT_color_buffer_half_float
+#define GL_EXT_color_buffer_half_float 1
+#endif
+
+/* GL_EXT_debug_label */
+#ifndef GL_EXT_debug_label
+#define GL_EXT_debug_label 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glLabelObjectEXT (GLenum type, GLuint object, GLsizei length, const GLchar *label);
+GL_APICALL void GL_APIENTRY glGetObjectLabelEXT (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);
+#endif
+typedef void (GL_APIENTRYP PFNGLLABELOBJECTEXTPROC) (GLenum type, GLuint object, GLsizei length, const GLchar *label);
+typedef void (GL_APIENTRYP PFNGLGETOBJECTLABELEXTPROC) (GLenum type, GLuint object, GLsizei bufSize, GLsizei *length, GLchar *label);
+#endif
+
+/* GL_EXT_debug_marker */
+#ifndef GL_EXT_debug_marker
+#define GL_EXT_debug_marker 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glInsertEventMarkerEXT (GLsizei length, const GLchar *marker);
+GL_APICALL void GL_APIENTRY glPushGroupMarkerEXT (GLsizei length, const GLchar *marker);
+GL_APICALL void GL_APIENTRY glPopGroupMarkerEXT (void);
+#endif
+typedef void (GL_APIENTRYP PFNGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker);
+typedef void (GL_APIENTRYP PFNGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker);
+typedef void (GL_APIENTRYP PFNGLPOPGROUPMARKEREXTPROC) (void);
+#endif
+
+/* GL_EXT_discard_framebuffer */
+#ifndef GL_EXT_discard_framebuffer
+#define GL_EXT_discard_framebuffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDiscardFramebufferEXT (GLenum target, GLsizei numAttachments, const GLenum *attachments);
+#endif
+typedef void (GL_APIENTRYP PFNGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);
+#endif
+
+/* GL_EXT_map_buffer_range */
+#ifndef GL_EXT_map_buffer_range
+#define GL_EXT_map_buffer_range 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void* GL_APIENTRY glMapBufferRangeEXT (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
+GL_APICALL void GL_APIENTRY glFlushMappedBufferRangeEXT (GLenum target, GLintptr offset, GLsizeiptr length);
+#endif
+typedef void* (GL_APIENTRYP PFNGLMAPBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
+typedef void (GL_APIENTRYP PFNGLFLUSHMAPPEDBUFFERRANGEEXTPROC) (GLenum target, GLintptr offset, GLsizeiptr length);
+#endif
+
+/* GL_EXT_multisampled_render_to_texture */
+#ifndef GL_EXT_multisampled_render_to_texture
+#define GL_EXT_multisampled_render_to_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleEXT (GLenum, GLsizei, GLenum, GLsizei, GLsizei);
+GL_APICALL void GL_APIENTRY glFramebufferTexture2DMultisampleEXT (GLenum, GLenum, GLenum, GLuint, GLint, GLsizei);
+#endif
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+#endif
+
+/* GL_EXT_multiview_draw_buffers */
+#ifndef GL_EXT_multiview_draw_buffers
+#define GL_EXT_multiview_draw_buffers 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glReadBufferIndexedEXT (GLenum src, GLint index);
+GL_APICALL void GL_APIENTRY glDrawBuffersIndexedEXT (GLint n, const GLenum *location, const GLint *indices);
+GL_APICALL void GL_APIENTRY glGetIntegeri_vEXT (GLenum target, GLuint index, GLint *data);
+#endif
+typedef void (GL_APIENTRYP PFNGLREADBUFFERINDEXEDEXTPROC) (GLenum src, GLint index);
+typedef void (GL_APIENTRYP PFNGLDRAWBUFFERSINDEXEDEXTPROC) (GLint n, const GLenum *location, const GLint *indices);
+typedef void (GL_APIENTRYP PFNGLGETINTEGERI_VEXTPROC) (GLenum target, GLuint index, GLint *data);
+#endif
+
+#ifndef GL_EXT_multi_draw_arrays
+#define GL_EXT_multi_draw_arrays 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glMultiDrawArraysEXT (GLenum, const GLint *, const GLsizei *, GLsizei);
+GL_APICALL void GL_APIENTRY glMultiDrawElementsEXT (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (GL_APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount);
+typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount);
+#endif
+
+/* GL_EXT_occlusion_query_boolean */
+#ifndef GL_EXT_occlusion_query_boolean
+#define GL_EXT_occlusion_query_boolean 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGenQueriesEXT (GLsizei n, GLuint *ids);
+GL_APICALL void GL_APIENTRY glDeleteQueriesEXT (GLsizei n, const GLuint *ids);
+GL_APICALL GLboolean GL_APIENTRY glIsQueryEXT (GLuint id);
+GL_APICALL void GL_APIENTRY glBeginQueryEXT (GLenum target, GLuint id);
+GL_APICALL void GL_APIENTRY glEndQueryEXT (GLenum target);
+GL_APICALL void GL_APIENTRY glGetQueryivEXT (GLenum target, GLenum pname, GLint *params);
+GL_APICALL void GL_APIENTRY glGetQueryObjectuivEXT (GLuint id, GLenum pname, GLuint *params);
+#endif
+typedef void (GL_APIENTRYP PFNGLGENQUERIESEXTPROC) (GLsizei n, GLuint *ids);
+typedef void (GL_APIENTRYP PFNGLDELETEQUERIESEXTPROC) (GLsizei n, const GLuint *ids);
+typedef GLboolean (GL_APIENTRYP PFNGLISQUERYEXTPROC) (GLuint id);
+typedef void (GL_APIENTRYP PFNGLBEGINQUERYEXTPROC) (GLenum target, GLuint id);
+typedef void (GL_APIENTRYP PFNGLENDQUERYEXTPROC) (GLenum target);
+typedef void (GL_APIENTRYP PFNGLGETQUERYIVEXTPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLGETQUERYOBJECTUIVEXTPROC) (GLuint id, GLenum pname, GLuint *params);
+#endif
+
+/* GL_EXT_read_format_bgra */
+#ifndef GL_EXT_read_format_bgra
+#define GL_EXT_read_format_bgra 1
+#endif
+
+/* GL_EXT_robustness */
+#ifndef GL_EXT_robustness
+#define GL_EXT_robustness 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL GLenum GL_APIENTRY glGetGraphicsResetStatusEXT (void);
+GL_APICALL void GL_APIENTRY glReadnPixelsEXT (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+GL_APICALL void GL_APIENTRY glGetnUniformfvEXT (GLuint program, GLint location, GLsizei bufSize, float *params);
+GL_APICALL void GL_APIENTRY glGetnUniformivEXT (GLuint program, GLint location, GLsizei bufSize, GLint *params);
+#endif
+typedef GLenum (GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSEXTPROC) (void);
+typedef void (GL_APIENTRYP PFNGLREADNPIXELSEXTPROC) (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void *data);
+typedef void (GL_APIENTRYP PFNGLGETNUNIFORMFVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, float *params);
+typedef void (GL_APIENTRYP PFNGLGETNUNIFORMIVEXTPROC) (GLuint program, GLint location, GLsizei bufSize, GLint *params);
+#endif
+
+/* GL_EXT_separate_shader_objects */
+#ifndef GL_EXT_separate_shader_objects
+#define GL_EXT_separate_shader_objects 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glUseProgramStagesEXT (GLuint pipeline, GLbitfield stages, GLuint program);
+GL_APICALL void GL_APIENTRY glActiveShaderProgramEXT (GLuint pipeline, GLuint program);
+GL_APICALL GLuint GL_APIENTRY glCreateShaderProgramvEXT (GLenum type, GLsizei count, const GLchar **strings);
+GL_APICALL void GL_APIENTRY glBindProgramPipelineEXT (GLuint pipeline);
+GL_APICALL void GL_APIENTRY glDeleteProgramPipelinesEXT (GLsizei n, const GLuint *pipelines);
+GL_APICALL void GL_APIENTRY glGenProgramPipelinesEXT (GLsizei n, GLuint *pipelines);
+GL_APICALL GLboolean GL_APIENTRY glIsProgramPipelineEXT (GLuint pipeline);
+GL_APICALL void GL_APIENTRY glProgramParameteriEXT (GLuint program, GLenum pname, GLint value);
+GL_APICALL void GL_APIENTRY glGetProgramPipelineivEXT (GLuint pipeline, GLenum pname, GLint *params);
+GL_APICALL void GL_APIENTRY glProgramUniform1iEXT (GLuint program, GLint location, GLint x);
+GL_APICALL void GL_APIENTRY glProgramUniform2iEXT (GLuint program, GLint location, GLint x, GLint y);
+GL_APICALL void GL_APIENTRY glProgramUniform3iEXT (GLuint program, GLint location, GLint x, GLint y, GLint z);
+GL_APICALL void GL_APIENTRY glProgramUniform4iEXT (GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w);
+GL_APICALL void GL_APIENTRY glProgramUniform1fEXT (GLuint program, GLint location, GLfloat x);
+GL_APICALL void GL_APIENTRY glProgramUniform2fEXT (GLuint program, GLint location, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glProgramUniform3fEXT (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glProgramUniform4fEXT (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glProgramUniform1ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GL_APICALL void GL_APIENTRY glProgramUniform2ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GL_APICALL void GL_APIENTRY glProgramUniform3ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GL_APICALL void GL_APIENTRY glProgramUniform4ivEXT (GLuint program, GLint location, GLsizei count, const GLint *value);
+GL_APICALL void GL_APIENTRY glProgramUniform1fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniform2fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniform3fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniform4fvEXT (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniformMatrix2fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniformMatrix3fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glProgramUniformMatrix4fvEXT (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+GL_APICALL void GL_APIENTRY glValidateProgramPipelineEXT (GLuint pipeline);
+GL_APICALL void GL_APIENTRY glGetProgramPipelineInfoLogEXT (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+#endif
+typedef void (GL_APIENTRYP PFNGLUSEPROGRAMSTAGESEXTPROC) (GLuint pipeline, GLbitfield stages, GLuint program);
+typedef void (GL_APIENTRYP PFNGLACTIVESHADERPROGRAMEXTPROC) (GLuint pipeline, GLuint program);
+typedef GLuint (GL_APIENTRYP PFNGLCREATESHADERPROGRAMVEXTPROC) (GLenum type, GLsizei count, const GLchar **strings);
+typedef void (GL_APIENTRYP PFNGLBINDPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
+typedef void (GL_APIENTRYP PFNGLDELETEPROGRAMPIPELINESEXTPROC) (GLsizei n, const GLuint *pipelines);
+typedef void (GL_APIENTRYP PFNGLGENPROGRAMPIPELINESEXTPROC) (GLsizei n, GLuint *pipelines);
+typedef GLboolean (GL_APIENTRYP PFNGLISPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
+typedef void (GL_APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value);
+typedef void (GL_APIENTRYP PFNGLGETPROGRAMPIPELINEIVEXTPROC) (GLuint pipeline, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1IEXTPROC) (GLuint program, GLint location, GLint x);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2IEXTPROC) (GLuint program, GLint location, GLint x, GLint y);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3IEXTPROC) (GLuint program, GLint location, GLint x, GLint y, GLint z);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4IEXTPROC) (GLuint program, GLint location, GLint x, GLint y, GLint z, GLint w);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1FEXTPROC) (GLuint program, GLint location, GLfloat x);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2FEXTPROC) (GLuint program, GLint location, GLfloat x, GLfloat y);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3FEXTPROC) (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4FEXTPROC) (GLuint program, GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4IVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLint *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM1FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM2FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM3FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORM4FVEXTPROC) (GLuint program, GLint location, GLsizei count, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX2FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX3FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLPROGRAMUNIFORMMATRIX4FVEXTPROC) (GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (GL_APIENTRYP PFNGLVALIDATEPROGRAMPIPELINEEXTPROC) (GLuint pipeline);
+typedef void (GL_APIENTRYP PFNGLGETPROGRAMPIPELINEINFOLOGEXTPROC) (GLuint pipeline, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+#endif
+
+/* GL_EXT_shader_framebuffer_fetch */
+#ifndef GL_EXT_shader_framebuffer_fetch
+#define GL_EXT_shader_framebuffer_fetch 1
+#endif
+
+/* GL_EXT_shader_texture_lod */
+#ifndef GL_EXT_shader_texture_lod
+#define GL_EXT_shader_texture_lod 1
+#endif
+
+/* GL_EXT_shadow_samplers */
+#ifndef GL_EXT_shadow_samplers
+#define GL_EXT_shadow_samplers 1
+#endif
+
+/* GL_EXT_sRGB */
+#ifndef GL_EXT_sRGB
+#define GL_EXT_sRGB 1
+#endif
+
+/* GL_EXT_texture_compression_dxt1 */
+#ifndef GL_EXT_texture_compression_dxt1
+#define GL_EXT_texture_compression_dxt1 1
+#endif
+
+/* GL_EXT_texture_filter_anisotropic */
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_EXT_texture_filter_anisotropic 1
+#endif
+
+/* GL_EXT_texture_format_BGRA8888 */
+#ifndef GL_EXT_texture_format_BGRA8888
+#define GL_EXT_texture_format_BGRA8888 1
+#endif
+
+/* GL_EXT_texture_rg */
+#ifndef GL_EXT_texture_rg
+#define GL_EXT_texture_rg 1
+#endif
+
+/* GL_EXT_texture_storage */
+#ifndef GL_EXT_texture_storage
+#define GL_EXT_texture_storage 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glTexStorage1DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+GL_APICALL void GL_APIENTRY glTexStorage2DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glTexStorage3DEXT (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+GL_APICALL void GL_APIENTRY glTextureStorage1DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+GL_APICALL void GL_APIENTRY glTextureStorage2DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glTextureStorage3DEXT (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+#endif
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGE1DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGE2DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLTEXSTORAGE3DEXTPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE1DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE2DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLTEXTURESTORAGE3DEXTPROC) (GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+#endif
+
+/* GL_EXT_texture_type_2_10_10_10_REV */
+#ifndef GL_EXT_texture_type_2_10_10_10_REV
+#define GL_EXT_texture_type_2_10_10_10_REV 1
+#endif
+
+/* GL_EXT_unpack_subimage */
+#ifndef GL_EXT_unpack_subimage
+#define GL_EXT_unpack_subimage 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * DMP extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_DMP_shader_binary */
+#ifndef GL_DMP_shader_binary
+#define GL_DMP_shader_binary 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * FJ extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_FJ_shader_binary_GCCSO */
+#ifndef GL_FJ_shader_binary_GCCSO
+#define GL_FJ_shader_binary_GCCSO 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * IMG extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_IMG_program_binary */
+#ifndef GL_IMG_program_binary
+#define GL_IMG_program_binary 1
+#endif
+
+/* GL_IMG_read_format */
+#ifndef GL_IMG_read_format
+#define GL_IMG_read_format 1
+#endif
+
+/* GL_IMG_shader_binary */
+#ifndef GL_IMG_shader_binary
+#define GL_IMG_shader_binary 1
+#endif
+
+/* GL_IMG_texture_compression_pvrtc */
+#ifndef GL_IMG_texture_compression_pvrtc
+#define GL_IMG_texture_compression_pvrtc 1
+#endif
+
+/* GL_IMG_texture_compression_pvrtc2 */
+#ifndef GL_IMG_texture_compression_pvrtc2
+#define GL_IMG_texture_compression_pvrtc2 1
+#endif
+
+/* GL_IMG_multisampled_render_to_texture */
+#ifndef GL_IMG_multisampled_render_to_texture
+#define GL_IMG_multisampled_render_to_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleIMG (GLenum, GLsizei, GLenum, GLsizei, GLsizei);
+GL_APICALL void GL_APIENTRY glFramebufferTexture2DMultisampleIMG (GLenum, GLenum, GLenum, GLuint, GLint, GLsizei);
+#endif
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEIMGPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEIMGPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+#endif
+
+/*------------------------------------------------------------------------*
+ * NV extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_NV_coverage_sample */
+#ifndef GL_NV_coverage_sample
+#define GL_NV_coverage_sample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glCoverageMaskNV (GLboolean mask);
+GL_APICALL void GL_APIENTRY glCoverageOperationNV (GLenum operation);
+#endif
+typedef void (GL_APIENTRYP PFNGLCOVERAGEMASKNVPROC) (GLboolean mask);
+typedef void (GL_APIENTRYP PFNGLCOVERAGEOPERATIONNVPROC) (GLenum operation);
+#endif
+
+/* GL_NV_depth_nonlinear */
+#ifndef GL_NV_depth_nonlinear
+#define GL_NV_depth_nonlinear 1
+#endif
+
+/* GL_NV_draw_buffers */
+#ifndef GL_NV_draw_buffers
+#define GL_NV_draw_buffers 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDrawBuffersNV (GLsizei n, const GLenum *bufs);
+#endif
+typedef void (GL_APIENTRYP PFNGLDRAWBUFFERSNVPROC) (GLsizei n, const GLenum *bufs);
+#endif
+
+/* GL_EXT_draw_buffers */
+#ifndef GL_EXT_draw_buffers
+#define GL_EXT_draw_buffers 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDrawBuffersEXT (GLsizei n, const GLenum *bufs);
+#endif
+typedef void (GL_APIENTRYP PFNGLDRAWBUFFERSEXTPROC) (GLsizei n, const GLenum *bufs);
+#endif
+
+/* GL_NV_draw_instanced */
+#ifndef GL_NV_draw_instanced
+#define GL_NV_draw_instanced 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDrawArraysInstancedNV (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
+GL_APICALL void GL_APIENTRY glDrawElementsInstancedNV (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount);
+#endif
+typedef void (GL_APIENTRYP PFNDRAWARRAYSINSTANCEDNVPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
+typedef void (GL_APIENTRYP PFNDRAWELEMENTSINSTANCEDNVPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount);
+#endif
+
+/* GL_NV_fbo_color_attachments */
+#ifndef GL_NV_fbo_color_attachments
+#define GL_NV_fbo_color_attachments 1
+#endif
+
+/* GL_NV_fence */
+#ifndef GL_NV_fence
+#define GL_NV_fence 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDeleteFencesNV (GLsizei, const GLuint *);
+GL_APICALL void GL_APIENTRY glGenFencesNV (GLsizei, GLuint *);
+GL_APICALL GLboolean GL_APIENTRY glIsFenceNV (GLuint);
+GL_APICALL GLboolean GL_APIENTRY glTestFenceNV (GLuint);
+GL_APICALL void GL_APIENTRY glGetFenceivNV (GLuint, GLenum, GLint *);
+GL_APICALL void GL_APIENTRY glFinishFenceNV (GLuint);
+GL_APICALL void GL_APIENTRY glSetFenceNV (GLuint, GLenum);
+#endif
+typedef void (GL_APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences);
+typedef void (GL_APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences);
+typedef GLboolean (GL_APIENTRYP PFNGLISFENCENVPROC) (GLuint fence);
+typedef GLboolean (GL_APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence);
+typedef void (GL_APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence);
+typedef void (GL_APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition);
+#endif
+
+/* GL_NV_framebuffer_blit */
+#ifndef GL_NV_framebuffer_blit
+#define GL_NV_framebuffer_blit 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glBlitFramebufferNV (int srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+#endif
+typedef void (GL_APIENTRYP PFNBLITFRAMEBUFFERNVPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+#endif
+
+/* GL_NV_framebuffer_multisample */
+#ifndef GL_NV_framebuffer_multisample
+#define GL_NV_framebuffer_multisample 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleNV ( GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+#endif
+typedef void (GL_APIENTRYP PFNRENDERBUFFERSTORAGEMULTISAMPLENVPROC) ( GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+#endif
+
+/* GL_NV_generate_mipmap_sRGB */
+#ifndef GL_NV_generate_mipmap_sRGB
+#define GL_NV_generate_mipmap_sRGB 1
+#endif
+
+/* GL_NV_instanced_arrays */
+#ifndef GL_NV_instanced_arrays
+#define GL_NV_instanced_arrays 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glVertexAttribDivisorNV (GLuint index, GLuint divisor);
+#endif
+typedef void (GL_APIENTRYP PFNVERTEXATTRIBDIVISORNVPROC) (GLuint index, GLuint divisor);
+#endif
+
+/* GL_NV_read_buffer */
+#ifndef GL_NV_read_buffer
+#define GL_NV_read_buffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glReadBufferNV (GLenum mode);
+#endif
+typedef void (GL_APIENTRYP PFNGLREADBUFFERNVPROC) (GLenum mode);
+#endif
+
+/* GL_NV_read_buffer_front */
+#ifndef GL_NV_read_buffer_front
+#define GL_NV_read_buffer_front 1
+#endif
+
+/* GL_NV_read_depth */
+#ifndef GL_NV_read_depth
+#define GL_NV_read_depth 1
+#endif
+
+/* GL_NV_read_depth_stencil */
+#ifndef GL_NV_read_depth_stencil
+#define GL_NV_read_depth_stencil 1
+#endif
+
+/* GL_NV_read_stencil */
+#ifndef GL_NV_read_stencil
+#define GL_NV_read_stencil 1
+#endif
+
+/* GL_NV_shadow_samplers_array */
+#ifndef GL_NV_shadow_samplers_array
+#define GL_NV_shadow_samplers_array 1
+#endif
+
+/* GL_NV_shadow_samplers_cube */
+#ifndef GL_NV_shadow_samplers_cube
+#define GL_NV_shadow_samplers_cube 1
+#endif
+
+/* GL_NV_sRGB_formats */
+#ifndef GL_NV_sRGB_formats
+#define GL_NV_sRGB_formats 1
+#endif
+
+/* GL_NV_texture_border_clamp */
+#ifndef GL_NV_texture_border_clamp
+#define GL_NV_texture_border_clamp 1
+#endif
+
+/* GL_NV_texture_compression_s3tc_update */
+#ifndef GL_NV_texture_compression_s3tc_update
+#define GL_NV_texture_compression_s3tc_update 1
+#endif
+
+/* GL_NV_texture_npot_2D_mipmap */
+#ifndef GL_NV_texture_npot_2D_mipmap
+#define GL_NV_texture_npot_2D_mipmap 1
+#endif
+
+/*------------------------------------------------------------------------*
+ * QCOM extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_QCOM_alpha_test */
+#ifndef GL_QCOM_alpha_test
+#define GL_QCOM_alpha_test 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glAlphaFuncQCOM (GLenum func, GLclampf ref);
+#endif
+typedef void (GL_APIENTRYP PFNGLALPHAFUNCQCOMPROC) (GLenum func, GLclampf ref);
+#endif
+
+/* GL_QCOM_binning_control */
+#ifndef GL_QCOM_binning_control
+#define GL_QCOM_binning_control 1
+#endif
+
+/* GL_QCOM_driver_control */
+#ifndef GL_QCOM_driver_control
+#define GL_QCOM_driver_control 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetDriverControlsQCOM (GLint *num, GLsizei size, GLuint *driverControls);
+GL_APICALL void GL_APIENTRY glGetDriverControlStringQCOM (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString);
+GL_APICALL void GL_APIENTRY glEnableDriverControlQCOM (GLuint driverControl);
+GL_APICALL void GL_APIENTRY glDisableDriverControlQCOM (GLuint driverControl);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSQCOMPROC) (GLint *num, GLsizei size, GLuint *driverControls);
+typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSTRINGQCOMPROC) (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString);
+typedef void (GL_APIENTRYP PFNGLENABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);
+typedef void (GL_APIENTRYP PFNGLDISABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);
+#endif
+
+/* GL_QCOM_extended_get */
+#ifndef GL_QCOM_extended_get
+#define GL_QCOM_extended_get 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glExtGetTexturesQCOM (GLuint *textures, GLint maxTextures, GLint *numTextures);
+GL_APICALL void GL_APIENTRY glExtGetBuffersQCOM (GLuint *buffers, GLint maxBuffers, GLint *numBuffers);
+GL_APICALL void GL_APIENTRY glExtGetRenderbuffersQCOM (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers);
+GL_APICALL void GL_APIENTRY glExtGetFramebuffersQCOM (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers);
+GL_APICALL void GL_APIENTRY glExtGetTexLevelParameterivQCOM (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params);
+GL_APICALL void GL_APIENTRY glExtTexObjectStateOverrideiQCOM (GLenum target, GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY glExtGetTexSubImageQCOM (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels);
+GL_APICALL void GL_APIENTRY glExtGetBufferPointervQCOM (GLenum target, GLvoid **params);
+#endif
+typedef void (GL_APIENTRYP PFNGLEXTGETTEXTURESQCOMPROC) (GLuint *textures, GLint maxTextures, GLint *numTextures);
+typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERSQCOMPROC) (GLuint *buffers, GLint maxBuffers, GLint *numBuffers);
+typedef void (GL_APIENTRYP PFNGLEXTGETRENDERBUFFERSQCOMPROC) (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers);
+typedef void (GL_APIENTRYP PFNGLEXTGETFRAMEBUFFERSQCOMPROC) (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers);
+typedef void (GL_APIENTRYP PFNGLEXTGETTEXLEVELPARAMETERIVQCOMPROC) (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLEXTTEXOBJECTSTATEOVERRIDEIQCOMPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (GL_APIENTRYP PFNGLEXTGETTEXSUBIMAGEQCOMPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels);
+typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERPOINTERVQCOMPROC) (GLenum target, GLvoid **params);
+#endif
+
+/* GL_QCOM_extended_get2 */
+#ifndef GL_QCOM_extended_get2
+#define GL_QCOM_extended_get2 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glExtGetShadersQCOM (GLuint *shaders, GLint maxShaders, GLint *numShaders);
+GL_APICALL void GL_APIENTRY glExtGetProgramsQCOM (GLuint *programs, GLint maxPrograms, GLint *numPrograms);
+GL_APICALL GLboolean GL_APIENTRY glExtIsProgramBinaryQCOM (GLuint program);
+GL_APICALL void GL_APIENTRY glExtGetProgramBinarySourceQCOM (GLuint program, GLenum shadertype, GLchar *source, GLint *length);
+#endif
+typedef void (GL_APIENTRYP PFNGLEXTGETSHADERSQCOMPROC) (GLuint *shaders, GLint maxShaders, GLint *numShaders);
+typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMSQCOMPROC) (GLuint *programs, GLint maxPrograms, GLint *numPrograms);
+typedef GLboolean (GL_APIENTRYP PFNGLEXTISPROGRAMBINARYQCOMPROC) (GLuint program);
+typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMBINARYSOURCEQCOMPROC) (GLuint program, GLenum shadertype, GLchar *source, GLint *length);
+#endif
+
+/* GL_QCOM_perfmon_global_mode */
+#ifndef GL_QCOM_perfmon_global_mode
+#define GL_QCOM_perfmon_global_mode 1
+#endif
+
+/* GL_QCOM_writeonly_rendering */
+#ifndef GL_QCOM_writeonly_rendering
+#define GL_QCOM_writeonly_rendering 1
+#endif
+
+/* GL_QCOM_tiled_rendering */
+#ifndef GL_QCOM_tiled_rendering
+#define GL_QCOM_tiled_rendering 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glStartTilingQCOM (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask);
+GL_APICALL void GL_APIENTRY glEndTilingQCOM (GLbitfield preserveMask);
+#endif
+typedef void (GL_APIENTRYP PFNGLSTARTTILINGQCOMPROC) (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask);
+typedef void (GL_APIENTRYP PFNGLENDTILINGQCOMPROC) (GLbitfield preserveMask);
+#endif
+
+/*------------------------------------------------------------------------*
+ * VIV extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_VIV_shader_binary */
+#ifndef GL_VIV_shader_binary
+#define GL_VIV_shader_binary 1
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gl2ext_h_ */
diff --git a/platform/winrt/include/GLES2/gl2platform.h b/platform/winrt/include/GLES2/gl2platform.h
index 38cb3b7b6f..c9fa3c4d64 100644
--- a/platform/winrt/include/GLES2/gl2platform.h
+++ b/platform/winrt/include/GLES2/gl2platform.h
@@ -1,30 +1,30 @@
-#ifndef __gl2platform_h_
-#define __gl2platform_h_
-
-/* $Revision: 10602 $ on $Date:: 2010-03-04 22:35:34 -0800 #$ */
-
-/*
- * This document is licensed under the SGI Free Software B License Version
- * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
- */
-
-/* Platform-specific types and definitions for OpenGL ES 2.X gl2.h
- *
- * Adopters may modify khrplatform.h and this file to suit their platform.
- * You are encouraged to submit all modifications to the Khronos group so that
- * they can be included in future versions of this file. Please submit changes
- * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
- * by filing a bug against product "OpenGL-ES" component "Registry".
- */
-
-#include <KHR/khrplatform.h>
-
-#ifndef GL_APICALL
-#define GL_APICALL KHRONOS_APICALL
-#endif
-
-#ifndef GL_APIENTRY
-#define GL_APIENTRY KHRONOS_APIENTRY
-#endif
-
-#endif /* __gl2platform_h_ */
+#ifndef __gl2platform_h_
+#define __gl2platform_h_
+
+/* $Revision: 10602 $ on $Date:: 2010-03-04 22:35:34 -0800 #$ */
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+/* Platform-specific types and definitions for OpenGL ES 2.X gl2.h
+ *
+ * Adopters may modify khrplatform.h and this file to suit their platform.
+ * You are encouraged to submit all modifications to the Khronos group so that
+ * they can be included in future versions of this file. Please submit changes
+ * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
+ * by filing a bug against product "OpenGL-ES" component "Registry".
+ */
+
+#include <KHR/khrplatform.h>
+
+#ifndef GL_APICALL
+#define GL_APICALL KHRONOS_APICALL
+#endif
+
+#ifndef GL_APIENTRY
+#define GL_APIENTRY KHRONOS_APIENTRY
+#endif
+
+#endif /* __gl2platform_h_ */
diff --git a/platform/winrt/include/GLES3/gl3.h b/platform/winrt/include/GLES3/gl3.h
index 024edc4306..9c79862c0d 100644
--- a/platform/winrt/include/GLES3/gl3.h
+++ b/platform/winrt/include/GLES3/gl3.h
@@ -1,1061 +1,1061 @@
-#ifndef __gl3_h_
-#define __gl3_h_
-
-/*
- * gl3.h last updated on $Date: 2013-02-12 14:37:24 -0800 (Tue, 12 Feb 2013) $
- */
-
-#include <GLES3/gl3platform.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
-** Copyright (c) 2007-2013 The Khronos Group Inc.
-**
-** Permission is hereby granted, free of charge, to any person obtaining a
-** copy of this software and/or associated documentation files (the
-** "Materials"), to deal in the Materials without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Materials, and to
-** permit persons to whom the Materials are 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 Materials.
-**
-** THE MATERIALS ARE 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
-** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-*/
-
-/*-------------------------------------------------------------------------
- * Data type definitions
- *-----------------------------------------------------------------------*/
-
-/* OpenGL ES 2.0 */
-
-typedef void GLvoid;
-typedef char GLchar;
-typedef unsigned int GLenum;
-typedef unsigned char GLboolean;
-typedef unsigned int GLbitfield;
-typedef khronos_int8_t GLbyte;
-typedef short GLshort;
-typedef int GLint;
-typedef int GLsizei;
-typedef khronos_uint8_t GLubyte;
-typedef unsigned short GLushort;
-typedef unsigned int GLuint;
-typedef khronos_float_t GLfloat;
-typedef khronos_float_t GLclampf;
-typedef khronos_int32_t GLfixed;
-typedef khronos_intptr_t GLintptr;
-typedef khronos_ssize_t GLsizeiptr;
-
-/* OpenGL ES 3.0 */
-
-typedef unsigned short GLhalf;
-typedef khronos_int64_t GLint64;
-typedef khronos_uint64_t GLuint64;
-typedef struct __GLsync *GLsync;
-
-/*-------------------------------------------------------------------------
- * Token definitions
- *-----------------------------------------------------------------------*/
-
-/* OpenGL ES core versions */
-#define GL_ES_VERSION_3_0 1
-#define GL_ES_VERSION_2_0 1
-
-/* OpenGL ES 2.0 */
-
-/* ClearBufferMask */
-#define GL_DEPTH_BUFFER_BIT 0x00000100
-#define GL_STENCIL_BUFFER_BIT 0x00000400
-#define GL_COLOR_BUFFER_BIT 0x00004000
-
-/* Boolean */
-#define GL_FALSE 0
-#define GL_TRUE 1
-
-/* BeginMode */
-#define GL_POINTS 0x0000
-#define GL_LINES 0x0001
-#define GL_LINE_LOOP 0x0002
-#define GL_LINE_STRIP 0x0003
-#define GL_TRIANGLES 0x0004
-#define GL_TRIANGLE_STRIP 0x0005
-#define GL_TRIANGLE_FAN 0x0006
-
-/* BlendingFactorDest */
-#define GL_ZERO 0
-#define GL_ONE 1
-#define GL_SRC_COLOR 0x0300
-#define GL_ONE_MINUS_SRC_COLOR 0x0301
-#define GL_SRC_ALPHA 0x0302
-#define GL_ONE_MINUS_SRC_ALPHA 0x0303
-#define GL_DST_ALPHA 0x0304
-#define GL_ONE_MINUS_DST_ALPHA 0x0305
-
-/* BlendingFactorSrc */
-/* GL_ZERO */
-/* GL_ONE */
-#define GL_DST_COLOR 0x0306
-#define GL_ONE_MINUS_DST_COLOR 0x0307
-#define GL_SRC_ALPHA_SATURATE 0x0308
-/* GL_SRC_ALPHA */
-/* GL_ONE_MINUS_SRC_ALPHA */
-/* GL_DST_ALPHA */
-/* GL_ONE_MINUS_DST_ALPHA */
-
-/* BlendEquationSeparate */
-#define GL_FUNC_ADD 0x8006
-#define GL_BLEND_EQUATION 0x8009
-#define GL_BLEND_EQUATION_RGB 0x8009 /* same as BLEND_EQUATION */
-#define GL_BLEND_EQUATION_ALPHA 0x883D
-
-/* BlendSubtract */
-#define GL_FUNC_SUBTRACT 0x800A
-#define GL_FUNC_REVERSE_SUBTRACT 0x800B
-
-/* Separate Blend Functions */
-#define GL_BLEND_DST_RGB 0x80C8
-#define GL_BLEND_SRC_RGB 0x80C9
-#define GL_BLEND_DST_ALPHA 0x80CA
-#define GL_BLEND_SRC_ALPHA 0x80CB
-#define GL_CONSTANT_COLOR 0x8001
-#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
-#define GL_CONSTANT_ALPHA 0x8003
-#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
-#define GL_BLEND_COLOR 0x8005
-
-/* Buffer Objects */
-#define GL_ARRAY_BUFFER 0x8892
-#define GL_ELEMENT_ARRAY_BUFFER 0x8893
-#define GL_ARRAY_BUFFER_BINDING 0x8894
-#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
-
-#define GL_STREAM_DRAW 0x88E0
-#define GL_STATIC_DRAW 0x88E4
-#define GL_DYNAMIC_DRAW 0x88E8
-
-#define GL_BUFFER_SIZE 0x8764
-#define GL_BUFFER_USAGE 0x8765
-
-#define GL_CURRENT_VERTEX_ATTRIB 0x8626
-
-/* CullFaceMode */
-#define GL_FRONT 0x0404
-#define GL_BACK 0x0405
-#define GL_FRONT_AND_BACK 0x0408
-
-/* DepthFunction */
-/* GL_NEVER */
-/* GL_LESS */
-/* GL_EQUAL */
-/* GL_LEQUAL */
-/* GL_GREATER */
-/* GL_NOTEQUAL */
-/* GL_GEQUAL */
-/* GL_ALWAYS */
-
-/* EnableCap */
-#define GL_TEXTURE_2D 0x0DE1
-#define GL_CULL_FACE 0x0B44
-#define GL_BLEND 0x0BE2
-#define GL_DITHER 0x0BD0
-#define GL_STENCIL_TEST 0x0B90
-#define GL_DEPTH_TEST 0x0B71
-#define GL_SCISSOR_TEST 0x0C11
-#define GL_POLYGON_OFFSET_FILL 0x8037
-#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
-#define GL_SAMPLE_COVERAGE 0x80A0
-
-/* ErrorCode */
-#define GL_NO_ERROR 0
-#define GL_INVALID_ENUM 0x0500
-#define GL_INVALID_VALUE 0x0501
-#define GL_INVALID_OPERATION 0x0502
-#define GL_OUT_OF_MEMORY 0x0505
-
-/* FrontFaceDirection */
-#define GL_CW 0x0900
-#define GL_CCW 0x0901
-
-/* GetPName */
-#define GL_LINE_WIDTH 0x0B21
-#define GL_ALIASED_POINT_SIZE_RANGE 0x846D
-#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
-#define GL_CULL_FACE_MODE 0x0B45
-#define GL_FRONT_FACE 0x0B46
-#define GL_DEPTH_RANGE 0x0B70
-#define GL_DEPTH_WRITEMASK 0x0B72
-#define GL_DEPTH_CLEAR_VALUE 0x0B73
-#define GL_DEPTH_FUNC 0x0B74
-#define GL_STENCIL_CLEAR_VALUE 0x0B91
-#define GL_STENCIL_FUNC 0x0B92
-#define GL_STENCIL_FAIL 0x0B94
-#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
-#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
-#define GL_STENCIL_REF 0x0B97
-#define GL_STENCIL_VALUE_MASK 0x0B93
-#define GL_STENCIL_WRITEMASK 0x0B98
-#define GL_STENCIL_BACK_FUNC 0x8800
-#define GL_STENCIL_BACK_FAIL 0x8801
-#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802
-#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803
-#define GL_STENCIL_BACK_REF 0x8CA3
-#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4
-#define GL_STENCIL_BACK_WRITEMASK 0x8CA5
-#define GL_VIEWPORT 0x0BA2
-#define GL_SCISSOR_BOX 0x0C10
-/* GL_SCISSOR_TEST */
-#define GL_COLOR_CLEAR_VALUE 0x0C22
-#define GL_COLOR_WRITEMASK 0x0C23
-#define GL_UNPACK_ALIGNMENT 0x0CF5
-#define GL_PACK_ALIGNMENT 0x0D05
-#define GL_MAX_TEXTURE_SIZE 0x0D33
-#define GL_MAX_VIEWPORT_DIMS 0x0D3A
-#define GL_SUBPIXEL_BITS 0x0D50
-#define GL_RED_BITS 0x0D52
-#define GL_GREEN_BITS 0x0D53
-#define GL_BLUE_BITS 0x0D54
-#define GL_ALPHA_BITS 0x0D55
-#define GL_DEPTH_BITS 0x0D56
-#define GL_STENCIL_BITS 0x0D57
-#define GL_POLYGON_OFFSET_UNITS 0x2A00
-/* GL_POLYGON_OFFSET_FILL */
-#define GL_POLYGON_OFFSET_FACTOR 0x8038
-#define GL_TEXTURE_BINDING_2D 0x8069
-#define GL_SAMPLE_BUFFERS 0x80A8
-#define GL_SAMPLES 0x80A9
-#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
-#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
-
-/* GetTextureParameter */
-/* GL_TEXTURE_MAG_FILTER */
-/* GL_TEXTURE_MIN_FILTER */
-/* GL_TEXTURE_WRAP_S */
-/* GL_TEXTURE_WRAP_T */
-
-#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
-#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
-
-/* HintMode */
-#define GL_DONT_CARE 0x1100
-#define GL_FASTEST 0x1101
-#define GL_NICEST 0x1102
-
-/* HintTarget */
-#define GL_GENERATE_MIPMAP_HINT 0x8192
-
-/* DataType */
-#define GL_BYTE 0x1400
-#define GL_UNSIGNED_BYTE 0x1401
-#define GL_SHORT 0x1402
-#define GL_UNSIGNED_SHORT 0x1403
-#define GL_INT 0x1404
-#define GL_UNSIGNED_INT 0x1405
-#define GL_FLOAT 0x1406
-#define GL_FIXED 0x140C
-
-/* PixelFormat */
-#define GL_DEPTH_COMPONENT 0x1902
-#define GL_ALPHA 0x1906
-#define GL_RGB 0x1907
-#define GL_RGBA 0x1908
-#define GL_LUMINANCE 0x1909
-#define GL_LUMINANCE_ALPHA 0x190A
-
-/* PixelType */
-/* GL_UNSIGNED_BYTE */
-#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
-#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
-#define GL_UNSIGNED_SHORT_5_6_5 0x8363
-
-/* Shaders */
-#define GL_FRAGMENT_SHADER 0x8B30
-#define GL_VERTEX_SHADER 0x8B31
-#define GL_MAX_VERTEX_ATTRIBS 0x8869
-#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
-#define GL_MAX_VARYING_VECTORS 0x8DFC
-#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
-#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
-#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
-#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
-#define GL_SHADER_TYPE 0x8B4F
-#define GL_DELETE_STATUS 0x8B80
-#define GL_LINK_STATUS 0x8B82
-#define GL_VALIDATE_STATUS 0x8B83
-#define GL_ATTACHED_SHADERS 0x8B85
-#define GL_ACTIVE_UNIFORMS 0x8B86
-#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
-#define GL_ACTIVE_ATTRIBUTES 0x8B89
-#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
-#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
-#define GL_CURRENT_PROGRAM 0x8B8D
-
-/* StencilFunction */
-#define GL_NEVER 0x0200
-#define GL_LESS 0x0201
-#define GL_EQUAL 0x0202
-#define GL_LEQUAL 0x0203
-#define GL_GREATER 0x0204
-#define GL_NOTEQUAL 0x0205
-#define GL_GEQUAL 0x0206
-#define GL_ALWAYS 0x0207
-
-/* StencilOp */
-/* GL_ZERO */
-#define GL_KEEP 0x1E00
-#define GL_REPLACE 0x1E01
-#define GL_INCR 0x1E02
-#define GL_DECR 0x1E03
-#define GL_INVERT 0x150A
-#define GL_INCR_WRAP 0x8507
-#define GL_DECR_WRAP 0x8508
-
-/* StringName */
-#define GL_VENDOR 0x1F00
-#define GL_RENDERER 0x1F01
-#define GL_VERSION 0x1F02
-#define GL_EXTENSIONS 0x1F03
-
-/* TextureMagFilter */
-#define GL_NEAREST 0x2600
-#define GL_LINEAR 0x2601
-
-/* TextureMinFilter */
-/* GL_NEAREST */
-/* GL_LINEAR */
-#define GL_NEAREST_MIPMAP_NEAREST 0x2700
-#define GL_LINEAR_MIPMAP_NEAREST 0x2701
-#define GL_NEAREST_MIPMAP_LINEAR 0x2702
-#define GL_LINEAR_MIPMAP_LINEAR 0x2703
-
-/* TextureParameterName */
-#define GL_TEXTURE_MAG_FILTER 0x2800
-#define GL_TEXTURE_MIN_FILTER 0x2801
-#define GL_TEXTURE_WRAP_S 0x2802
-#define GL_TEXTURE_WRAP_T 0x2803
-
-/* TextureTarget */
-/* GL_TEXTURE_2D */
-#define GL_TEXTURE 0x1702
-
-#define GL_TEXTURE_CUBE_MAP 0x8513
-#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514
-#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
-#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
-#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
-#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
-#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
-#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
-#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
-
-/* TextureUnit */
-#define GL_TEXTURE0 0x84C0
-#define GL_TEXTURE1 0x84C1
-#define GL_TEXTURE2 0x84C2
-#define GL_TEXTURE3 0x84C3
-#define GL_TEXTURE4 0x84C4
-#define GL_TEXTURE5 0x84C5
-#define GL_TEXTURE6 0x84C6
-#define GL_TEXTURE7 0x84C7
-#define GL_TEXTURE8 0x84C8
-#define GL_TEXTURE9 0x84C9
-#define GL_TEXTURE10 0x84CA
-#define GL_TEXTURE11 0x84CB
-#define GL_TEXTURE12 0x84CC
-#define GL_TEXTURE13 0x84CD
-#define GL_TEXTURE14 0x84CE
-#define GL_TEXTURE15 0x84CF
-#define GL_TEXTURE16 0x84D0
-#define GL_TEXTURE17 0x84D1
-#define GL_TEXTURE18 0x84D2
-#define GL_TEXTURE19 0x84D3
-#define GL_TEXTURE20 0x84D4
-#define GL_TEXTURE21 0x84D5
-#define GL_TEXTURE22 0x84D6
-#define GL_TEXTURE23 0x84D7
-#define GL_TEXTURE24 0x84D8
-#define GL_TEXTURE25 0x84D9
-#define GL_TEXTURE26 0x84DA
-#define GL_TEXTURE27 0x84DB
-#define GL_TEXTURE28 0x84DC
-#define GL_TEXTURE29 0x84DD
-#define GL_TEXTURE30 0x84DE
-#define GL_TEXTURE31 0x84DF
-#define GL_ACTIVE_TEXTURE 0x84E0
-
-/* TextureWrapMode */
-#define GL_REPEAT 0x2901
-#define GL_CLAMP_TO_EDGE 0x812F
-#define GL_MIRRORED_REPEAT 0x8370
-
-/* Uniform Types */
-#define GL_FLOAT_VEC2 0x8B50
-#define GL_FLOAT_VEC3 0x8B51
-#define GL_FLOAT_VEC4 0x8B52
-#define GL_INT_VEC2 0x8B53
-#define GL_INT_VEC3 0x8B54
-#define GL_INT_VEC4 0x8B55
-#define GL_BOOL 0x8B56
-#define GL_BOOL_VEC2 0x8B57
-#define GL_BOOL_VEC3 0x8B58
-#define GL_BOOL_VEC4 0x8B59
-#define GL_FLOAT_MAT2 0x8B5A
-#define GL_FLOAT_MAT3 0x8B5B
-#define GL_FLOAT_MAT4 0x8B5C
-#define GL_SAMPLER_2D 0x8B5E
-#define GL_SAMPLER_CUBE 0x8B60
-
-/* Vertex Arrays */
-#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
-#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
-#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
-#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
-#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
-#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
-#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
-
-/* Read Format */
-#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
-#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
-
-/* Shader Source */
-#define GL_COMPILE_STATUS 0x8B81
-#define GL_INFO_LOG_LENGTH 0x8B84
-#define GL_SHADER_SOURCE_LENGTH 0x8B88
-#define GL_SHADER_COMPILER 0x8DFA
-
-/* Shader Binary */
-#define GL_SHADER_BINARY_FORMATS 0x8DF8
-#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9
-
-/* Shader Precision-Specified Types */
-#define GL_LOW_FLOAT 0x8DF0
-#define GL_MEDIUM_FLOAT 0x8DF1
-#define GL_HIGH_FLOAT 0x8DF2
-#define GL_LOW_INT 0x8DF3
-#define GL_MEDIUM_INT 0x8DF4
-#define GL_HIGH_INT 0x8DF5
-
-/* Framebuffer Object. */
-#define GL_FRAMEBUFFER 0x8D40
-#define GL_RENDERBUFFER 0x8D41
-
-#define GL_RGBA4 0x8056
-#define GL_RGB5_A1 0x8057
-#define GL_RGB565 0x8D62
-#define GL_DEPTH_COMPONENT16 0x81A5
-#define GL_STENCIL_INDEX8 0x8D48
-
-#define GL_RENDERBUFFER_WIDTH 0x8D42
-#define GL_RENDERBUFFER_HEIGHT 0x8D43
-#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44
-#define GL_RENDERBUFFER_RED_SIZE 0x8D50
-#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51
-#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52
-#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53
-#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54
-#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55
-
-#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0
-#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1
-#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2
-#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
-
-#define GL_COLOR_ATTACHMENT0 0x8CE0
-#define GL_DEPTH_ATTACHMENT 0x8D00
-#define GL_STENCIL_ATTACHMENT 0x8D20
-
-#define GL_NONE 0
-
-#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
-#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
-#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
-#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9
-#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
-
-#define GL_FRAMEBUFFER_BINDING 0x8CA6
-#define GL_RENDERBUFFER_BINDING 0x8CA7
-#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
-
-#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
-
-/* OpenGL ES 3.0 */
-
-#define GL_READ_BUFFER 0x0C02
-#define GL_UNPACK_ROW_LENGTH 0x0CF2
-#define GL_UNPACK_SKIP_ROWS 0x0CF3
-#define GL_UNPACK_SKIP_PIXELS 0x0CF4
-#define GL_PACK_ROW_LENGTH 0x0D02
-#define GL_PACK_SKIP_ROWS 0x0D03
-#define GL_PACK_SKIP_PIXELS 0x0D04
-#define GL_COLOR 0x1800
-#define GL_DEPTH 0x1801
-#define GL_STENCIL 0x1802
-#define GL_RED 0x1903
-#define GL_RGB8 0x8051
-#define GL_RGBA8 0x8058
-#define GL_RGB10_A2 0x8059
-#define GL_TEXTURE_BINDING_3D 0x806A
-#define GL_UNPACK_SKIP_IMAGES 0x806D
-#define GL_UNPACK_IMAGE_HEIGHT 0x806E
-#define GL_TEXTURE_3D 0x806F
-#define GL_TEXTURE_WRAP_R 0x8072
-#define GL_MAX_3D_TEXTURE_SIZE 0x8073
-#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
-#define GL_MAX_ELEMENTS_VERTICES 0x80E8
-#define GL_MAX_ELEMENTS_INDICES 0x80E9
-#define GL_TEXTURE_MIN_LOD 0x813A
-#define GL_TEXTURE_MAX_LOD 0x813B
-#define GL_TEXTURE_BASE_LEVEL 0x813C
-#define GL_TEXTURE_MAX_LEVEL 0x813D
-#define GL_MIN 0x8007
-#define GL_MAX 0x8008
-#define GL_DEPTH_COMPONENT24 0x81A6
-#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD
-#define GL_TEXTURE_COMPARE_MODE 0x884C
-#define GL_TEXTURE_COMPARE_FUNC 0x884D
-#define GL_CURRENT_QUERY 0x8865
-#define GL_QUERY_RESULT 0x8866
-#define GL_QUERY_RESULT_AVAILABLE 0x8867
-#define GL_BUFFER_MAPPED 0x88BC
-#define GL_BUFFER_MAP_POINTER 0x88BD
-#define GL_STREAM_READ 0x88E1
-#define GL_STREAM_COPY 0x88E2
-#define GL_STATIC_READ 0x88E5
-#define GL_STATIC_COPY 0x88E6
-#define GL_DYNAMIC_READ 0x88E9
-#define GL_DYNAMIC_COPY 0x88EA
-#define GL_MAX_DRAW_BUFFERS 0x8824
-#define GL_DRAW_BUFFER0 0x8825
-#define GL_DRAW_BUFFER1 0x8826
-#define GL_DRAW_BUFFER2 0x8827
-#define GL_DRAW_BUFFER3 0x8828
-#define GL_DRAW_BUFFER4 0x8829
-#define GL_DRAW_BUFFER5 0x882A
-#define GL_DRAW_BUFFER6 0x882B
-#define GL_DRAW_BUFFER7 0x882C
-#define GL_DRAW_BUFFER8 0x882D
-#define GL_DRAW_BUFFER9 0x882E
-#define GL_DRAW_BUFFER10 0x882F
-#define GL_DRAW_BUFFER11 0x8830
-#define GL_DRAW_BUFFER12 0x8831
-#define GL_DRAW_BUFFER13 0x8832
-#define GL_DRAW_BUFFER14 0x8833
-#define GL_DRAW_BUFFER15 0x8834
-#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49
-#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A
-#define GL_SAMPLER_3D 0x8B5F
-#define GL_SAMPLER_2D_SHADOW 0x8B62
-#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B
-#define GL_PIXEL_PACK_BUFFER 0x88EB
-#define GL_PIXEL_UNPACK_BUFFER 0x88EC
-#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED
-#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF
-#define GL_FLOAT_MAT2x3 0x8B65
-#define GL_FLOAT_MAT2x4 0x8B66
-#define GL_FLOAT_MAT3x2 0x8B67
-#define GL_FLOAT_MAT3x4 0x8B68
-#define GL_FLOAT_MAT4x2 0x8B69
-#define GL_FLOAT_MAT4x3 0x8B6A
-#define GL_SRGB 0x8C40
-#define GL_SRGB8 0x8C41
-#define GL_SRGB8_ALPHA8 0x8C43
-#define GL_COMPARE_REF_TO_TEXTURE 0x884E
-#define GL_MAJOR_VERSION 0x821B
-#define GL_MINOR_VERSION 0x821C
-#define GL_NUM_EXTENSIONS 0x821D
-#define GL_RGBA32F 0x8814
-#define GL_RGB32F 0x8815
-#define GL_RGBA16F 0x881A
-#define GL_RGB16F 0x881B
-#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD
-#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF
-#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904
-#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905
-#define GL_MAX_VARYING_COMPONENTS 0x8B4B
-#define GL_TEXTURE_2D_ARRAY 0x8C1A
-#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D
-#define GL_R11F_G11F_B10F 0x8C3A
-#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B
-#define GL_RGB9_E5 0x8C3D
-#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E
-#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76
-#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F
-#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80
-#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83
-#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84
-#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85
-#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88
-#define GL_RASTERIZER_DISCARD 0x8C89
-#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A
-#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B
-#define GL_INTERLEAVED_ATTRIBS 0x8C8C
-#define GL_SEPARATE_ATTRIBS 0x8C8D
-#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E
-#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F
-#define GL_RGBA32UI 0x8D70
-#define GL_RGB32UI 0x8D71
-#define GL_RGBA16UI 0x8D76
-#define GL_RGB16UI 0x8D77
-#define GL_RGBA8UI 0x8D7C
-#define GL_RGB8UI 0x8D7D
-#define GL_RGBA32I 0x8D82
-#define GL_RGB32I 0x8D83
-#define GL_RGBA16I 0x8D88
-#define GL_RGB16I 0x8D89
-#define GL_RGBA8I 0x8D8E
-#define GL_RGB8I 0x8D8F
-#define GL_RED_INTEGER 0x8D94
-#define GL_RGB_INTEGER 0x8D98
-#define GL_RGBA_INTEGER 0x8D99
-#define GL_SAMPLER_2D_ARRAY 0x8DC1
-#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4
-#define GL_SAMPLER_CUBE_SHADOW 0x8DC5
-#define GL_UNSIGNED_INT_VEC2 0x8DC6
-#define GL_UNSIGNED_INT_VEC3 0x8DC7
-#define GL_UNSIGNED_INT_VEC4 0x8DC8
-#define GL_INT_SAMPLER_2D 0x8DCA
-#define GL_INT_SAMPLER_3D 0x8DCB
-#define GL_INT_SAMPLER_CUBE 0x8DCC
-#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF
-#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2
-#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3
-#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4
-#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7
-#define GL_BUFFER_ACCESS_FLAGS 0x911F
-#define GL_BUFFER_MAP_LENGTH 0x9120
-#define GL_BUFFER_MAP_OFFSET 0x9121
-#define GL_DEPTH_COMPONENT32F 0x8CAC
-#define GL_DEPTH32F_STENCIL8 0x8CAD
-#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD
-#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210
-#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211
-#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212
-#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213
-#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214
-#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215
-#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216
-#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217
-#define GL_FRAMEBUFFER_DEFAULT 0x8218
-#define GL_FRAMEBUFFER_UNDEFINED 0x8219
-#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
-#define GL_DEPTH_STENCIL 0x84F9
-#define GL_UNSIGNED_INT_24_8 0x84FA
-#define GL_DEPTH24_STENCIL8 0x88F0
-#define GL_UNSIGNED_NORMALIZED 0x8C17
-#define GL_DRAW_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING
-#define GL_READ_FRAMEBUFFER 0x8CA8
-#define GL_DRAW_FRAMEBUFFER 0x8CA9
-#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA
-#define GL_RENDERBUFFER_SAMPLES 0x8CAB
-#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4
-#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF
-#define GL_COLOR_ATTACHMENT1 0x8CE1
-#define GL_COLOR_ATTACHMENT2 0x8CE2
-#define GL_COLOR_ATTACHMENT3 0x8CE3
-#define GL_COLOR_ATTACHMENT4 0x8CE4
-#define GL_COLOR_ATTACHMENT5 0x8CE5
-#define GL_COLOR_ATTACHMENT6 0x8CE6
-#define GL_COLOR_ATTACHMENT7 0x8CE7
-#define GL_COLOR_ATTACHMENT8 0x8CE8
-#define GL_COLOR_ATTACHMENT9 0x8CE9
-#define GL_COLOR_ATTACHMENT10 0x8CEA
-#define GL_COLOR_ATTACHMENT11 0x8CEB
-#define GL_COLOR_ATTACHMENT12 0x8CEC
-#define GL_COLOR_ATTACHMENT13 0x8CED
-#define GL_COLOR_ATTACHMENT14 0x8CEE
-#define GL_COLOR_ATTACHMENT15 0x8CEF
-#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56
-#define GL_MAX_SAMPLES 0x8D57
-#define GL_HALF_FLOAT 0x140B
-#define GL_MAP_READ_BIT 0x0001
-#define GL_MAP_WRITE_BIT 0x0002
-#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004
-#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008
-#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010
-#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020
-#define GL_RG 0x8227
-#define GL_RG_INTEGER 0x8228
-#define GL_R8 0x8229
-#define GL_RG8 0x822B
-#define GL_R16F 0x822D
-#define GL_R32F 0x822E
-#define GL_RG16F 0x822F
-#define GL_RG32F 0x8230
-#define GL_R8I 0x8231
-#define GL_R8UI 0x8232
-#define GL_R16I 0x8233
-#define GL_R16UI 0x8234
-#define GL_R32I 0x8235
-#define GL_R32UI 0x8236
-#define GL_RG8I 0x8237
-#define GL_RG8UI 0x8238
-#define GL_RG16I 0x8239
-#define GL_RG16UI 0x823A
-#define GL_RG32I 0x823B
-#define GL_RG32UI 0x823C
-#define GL_VERTEX_ARRAY_BINDING 0x85B5
-#define GL_R8_SNORM 0x8F94
-#define GL_RG8_SNORM 0x8F95
-#define GL_RGB8_SNORM 0x8F96
-#define GL_RGBA8_SNORM 0x8F97
-#define GL_SIGNED_NORMALIZED 0x8F9C
-#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69
-#define GL_COPY_READ_BUFFER 0x8F36
-#define GL_COPY_WRITE_BUFFER 0x8F37
-#define GL_COPY_READ_BUFFER_BINDING GL_COPY_READ_BUFFER
-#define GL_COPY_WRITE_BUFFER_BINDING GL_COPY_WRITE_BUFFER
-#define GL_UNIFORM_BUFFER 0x8A11
-#define GL_UNIFORM_BUFFER_BINDING 0x8A28
-#define GL_UNIFORM_BUFFER_START 0x8A29
-#define GL_UNIFORM_BUFFER_SIZE 0x8A2A
-#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B
-#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D
-#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E
-#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F
-#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30
-#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31
-#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33
-#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34
-#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35
-#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36
-#define GL_UNIFORM_TYPE 0x8A37
-#define GL_UNIFORM_SIZE 0x8A38
-#define GL_UNIFORM_NAME_LENGTH 0x8A39
-#define GL_UNIFORM_BLOCK_INDEX 0x8A3A
-#define GL_UNIFORM_OFFSET 0x8A3B
-#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C
-#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D
-#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E
-#define GL_UNIFORM_BLOCK_BINDING 0x8A3F
-#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40
-#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41
-#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42
-#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43
-#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44
-#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46
-#define GL_INVALID_INDEX 0xFFFFFFFFu
-#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122
-#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125
-#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111
-#define GL_OBJECT_TYPE 0x9112
-#define GL_SYNC_CONDITION 0x9113
-#define GL_SYNC_STATUS 0x9114
-#define GL_SYNC_FLAGS 0x9115
-#define GL_SYNC_FENCE 0x9116
-#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117
-#define GL_UNSIGNALED 0x9118
-#define GL_SIGNALED 0x9119
-#define GL_ALREADY_SIGNALED 0x911A
-#define GL_TIMEOUT_EXPIRED 0x911B
-#define GL_CONDITION_SATISFIED 0x911C
-#define GL_WAIT_FAILED 0x911D
-#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001
-#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull
-#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE
-#define GL_ANY_SAMPLES_PASSED 0x8C2F
-#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A
-#define GL_SAMPLER_BINDING 0x8919
-#define GL_RGB10_A2UI 0x906F
-#define GL_TEXTURE_SWIZZLE_R 0x8E42
-#define GL_TEXTURE_SWIZZLE_G 0x8E43
-#define GL_TEXTURE_SWIZZLE_B 0x8E44
-#define GL_TEXTURE_SWIZZLE_A 0x8E45
-#define GL_GREEN 0x1904
-#define GL_BLUE 0x1905
-#define GL_INT_2_10_10_10_REV 0x8D9F
-#define GL_TRANSFORM_FEEDBACK 0x8E22
-#define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23
-#define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24
-#define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25
-#define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257
-#define GL_PROGRAM_BINARY_LENGTH 0x8741
-#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE
-#define GL_PROGRAM_BINARY_FORMATS 0x87FF
-#define GL_COMPRESSED_R11_EAC 0x9270
-#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271
-#define GL_COMPRESSED_RG11_EAC 0x9272
-#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273
-#define GL_COMPRESSED_RGB8_ETC2 0x9274
-#define GL_COMPRESSED_SRGB8_ETC2 0x9275
-#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276
-#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277
-#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278
-#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279
-#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F
-#define GL_MAX_ELEMENT_INDEX 0x8D6B
-#define GL_NUM_SAMPLE_COUNTS 0x9380
-#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF
-
-/*-------------------------------------------------------------------------
- * Entrypoint definitions
- *-----------------------------------------------------------------------*/
-
-/* OpenGL ES 2.0 */
-
-GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture);
-GL_APICALL void GL_APIENTRY glAttachShader (GLuint program, GLuint shader);
-GL_APICALL void GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar* name);
-GL_APICALL void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer);
-GL_APICALL void GL_APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer);
-GL_APICALL void GL_APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer);
-GL_APICALL void GL_APIENTRY glBindTexture (GLenum target, GLuint texture);
-GL_APICALL void GL_APIENTRY glBlendColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
-GL_APICALL void GL_APIENTRY glBlendEquation (GLenum mode);
-GL_APICALL void GL_APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha);
-GL_APICALL void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor);
-GL_APICALL void GL_APIENTRY glBlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
-GL_APICALL void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
-GL_APICALL void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
-GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatus (GLenum target);
-GL_APICALL void GL_APIENTRY glClear (GLbitfield mask);
-GL_APICALL void GL_APIENTRY glClearColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
-GL_APICALL void GL_APIENTRY glClearDepthf (GLfloat depth);
-GL_APICALL void GL_APIENTRY glClearStencil (GLint s);
-GL_APICALL void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
-GL_APICALL void GL_APIENTRY glCompileShader (GLuint shader);
-GL_APICALL void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data);
-GL_APICALL void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data);
-GL_APICALL void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
-GL_APICALL void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
-GL_APICALL GLuint GL_APIENTRY glCreateProgram (void);
-GL_APICALL GLuint GL_APIENTRY glCreateShader (GLenum type);
-GL_APICALL void GL_APIENTRY glCullFace (GLenum mode);
-GL_APICALL void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint* buffers);
-GL_APICALL void GL_APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint* framebuffers);
-GL_APICALL void GL_APIENTRY glDeleteProgram (GLuint program);
-GL_APICALL void GL_APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint* renderbuffers);
-GL_APICALL void GL_APIENTRY glDeleteShader (GLuint shader);
-GL_APICALL void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint* textures);
-GL_APICALL void GL_APIENTRY glDepthFunc (GLenum func);
-GL_APICALL void GL_APIENTRY glDepthMask (GLboolean flag);
-GL_APICALL void GL_APIENTRY glDepthRangef (GLfloat n, GLfloat f);
-GL_APICALL void GL_APIENTRY glDetachShader (GLuint program, GLuint shader);
-GL_APICALL void GL_APIENTRY glDisable (GLenum cap);
-GL_APICALL void GL_APIENTRY glDisableVertexAttribArray (GLuint index);
-GL_APICALL void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);
-GL_APICALL void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid* indices);
-GL_APICALL void GL_APIENTRY glEnable (GLenum cap);
-GL_APICALL void GL_APIENTRY glEnableVertexAttribArray (GLuint index);
-GL_APICALL void GL_APIENTRY glFinish (void);
-GL_APICALL void GL_APIENTRY glFlush (void);
-GL_APICALL void GL_APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
-GL_APICALL void GL_APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
-GL_APICALL void GL_APIENTRY glFrontFace (GLenum mode);
-GL_APICALL void GL_APIENTRY glGenBuffers (GLsizei n, GLuint* buffers);
-GL_APICALL void GL_APIENTRY glGenerateMipmap (GLenum target);
-GL_APICALL void GL_APIENTRY glGenFramebuffers (GLsizei n, GLuint* framebuffers);
-GL_APICALL void GL_APIENTRY glGenRenderbuffers (GLsizei n, GLuint* renderbuffers);
-GL_APICALL void GL_APIENTRY glGenTextures (GLsizei n, GLuint* textures);
-GL_APICALL void GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
-GL_APICALL void GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
-GL_APICALL void GL_APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders);
-GL_APICALL GLint GL_APIENTRY glGetAttribLocation (GLuint program, const GLchar* name);
-GL_APICALL void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean* params);
-GL_APICALL void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params);
-GL_APICALL GLenum GL_APIENTRY glGetError (void);
-GL_APICALL void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat* params);
-GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params);
-GL_APICALL void GL_APIENTRY glGetIntegerv (GLenum pname, GLint* params);
-GL_APICALL void GL_APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint* params);
-GL_APICALL void GL_APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog);
-GL_APICALL void GL_APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params);
-GL_APICALL void GL_APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint* params);
-GL_APICALL void GL_APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog);
-GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
-GL_APICALL void GL_APIENTRY glGetShaderSource (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source);
-GL_APICALL const GLubyte* GL_APIENTRY glGetString (GLenum name);
-GL_APICALL void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat* params);
-GL_APICALL void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint* params);
-GL_APICALL void GL_APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat* params);
-GL_APICALL void GL_APIENTRY glGetUniformiv (GLuint program, GLint location, GLint* params);
-GL_APICALL GLint GL_APIENTRY glGetUniformLocation (GLuint program, const GLchar* name);
-GL_APICALL void GL_APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params);
-GL_APICALL void GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint* params);
-GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, GLvoid** pointer);
-GL_APICALL void GL_APIENTRY glHint (GLenum target, GLenum mode);
-GL_APICALL GLboolean GL_APIENTRY glIsBuffer (GLuint buffer);
-GL_APICALL GLboolean GL_APIENTRY glIsEnabled (GLenum cap);
-GL_APICALL GLboolean GL_APIENTRY glIsFramebuffer (GLuint framebuffer);
-GL_APICALL GLboolean GL_APIENTRY glIsProgram (GLuint program);
-GL_APICALL GLboolean GL_APIENTRY glIsRenderbuffer (GLuint renderbuffer);
-GL_APICALL GLboolean GL_APIENTRY glIsShader (GLuint shader);
-GL_APICALL GLboolean GL_APIENTRY glIsTexture (GLuint texture);
-GL_APICALL void GL_APIENTRY glLineWidth (GLfloat width);
-GL_APICALL void GL_APIENTRY glLinkProgram (GLuint program);
-GL_APICALL void GL_APIENTRY glPixelStorei (GLenum pname, GLint param);
-GL_APICALL void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units);
-GL_APICALL void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels);
-GL_APICALL void GL_APIENTRY glReleaseShaderCompiler (void);
-GL_APICALL void GL_APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
-GL_APICALL void GL_APIENTRY glSampleCoverage (GLfloat value, GLboolean invert);
-GL_APICALL void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
-GL_APICALL void GL_APIENTRY glShaderBinary (GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length);
-GL_APICALL void GL_APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length);
-GL_APICALL void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask);
-GL_APICALL void GL_APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask);
-GL_APICALL void GL_APIENTRY glStencilMask (GLuint mask);
-GL_APICALL void GL_APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask);
-GL_APICALL void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass);
-GL_APICALL void GL_APIENTRY glStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
-GL_APICALL void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
-GL_APICALL void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param);
-GL_APICALL void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat* params);
-GL_APICALL void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
-GL_APICALL void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint* params);
-GL_APICALL void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels);
-GL_APICALL void GL_APIENTRY glUniform1f (GLint location, GLfloat x);
-GL_APICALL void GL_APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat* v);
-GL_APICALL void GL_APIENTRY glUniform1i (GLint location, GLint x);
-GL_APICALL void GL_APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint* v);
-GL_APICALL void GL_APIENTRY glUniform2f (GLint location, GLfloat x, GLfloat y);
-GL_APICALL void GL_APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat* v);
-GL_APICALL void GL_APIENTRY glUniform2i (GLint location, GLint x, GLint y);
-GL_APICALL void GL_APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint* v);
-GL_APICALL void GL_APIENTRY glUniform3f (GLint location, GLfloat x, GLfloat y, GLfloat z);
-GL_APICALL void GL_APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat* v);
-GL_APICALL void GL_APIENTRY glUniform3i (GLint location, GLint x, GLint y, GLint z);
-GL_APICALL void GL_APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint* v);
-GL_APICALL void GL_APIENTRY glUniform4f (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
-GL_APICALL void GL_APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat* v);
-GL_APICALL void GL_APIENTRY glUniform4i (GLint location, GLint x, GLint y, GLint z, GLint w);
-GL_APICALL void GL_APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint* v);
-GL_APICALL void GL_APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
-GL_APICALL void GL_APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
-GL_APICALL void GL_APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
-GL_APICALL void GL_APIENTRY glUseProgram (GLuint program);
-GL_APICALL void GL_APIENTRY glValidateProgram (GLuint program);
-GL_APICALL void GL_APIENTRY glVertexAttrib1f (GLuint indx, GLfloat x);
-GL_APICALL void GL_APIENTRY glVertexAttrib1fv (GLuint indx, const GLfloat* values);
-GL_APICALL void GL_APIENTRY glVertexAttrib2f (GLuint indx, GLfloat x, GLfloat y);
-GL_APICALL void GL_APIENTRY glVertexAttrib2fv (GLuint indx, const GLfloat* values);
-GL_APICALL void GL_APIENTRY glVertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z);
-GL_APICALL void GL_APIENTRY glVertexAttrib3fv (GLuint indx, const GLfloat* values);
-GL_APICALL void GL_APIENTRY glVertexAttrib4f (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
-GL_APICALL void GL_APIENTRY glVertexAttrib4fv (GLuint indx, const GLfloat* values);
-GL_APICALL void GL_APIENTRY glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr);
-GL_APICALL void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
-
-/* OpenGL ES 3.0 */
-
-GL_APICALL void GL_APIENTRY glReadBuffer (GLenum mode);
-GL_APICALL void GL_APIENTRY glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices);
-GL_APICALL void GL_APIENTRY glTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
-GL_APICALL void GL_APIENTRY glTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels);
-GL_APICALL void GL_APIENTRY glCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
-GL_APICALL void GL_APIENTRY glCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data);
-GL_APICALL void GL_APIENTRY glCompressedTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data);
-GL_APICALL void GL_APIENTRY glGenQueries (GLsizei n, GLuint* ids);
-GL_APICALL void GL_APIENTRY glDeleteQueries (GLsizei n, const GLuint* ids);
-GL_APICALL GLboolean GL_APIENTRY glIsQuery (GLuint id);
-GL_APICALL void GL_APIENTRY glBeginQuery (GLenum target, GLuint id);
-GL_APICALL void GL_APIENTRY glEndQuery (GLenum target);
-GL_APICALL void GL_APIENTRY glGetQueryiv (GLenum target, GLenum pname, GLint* params);
-GL_APICALL void GL_APIENTRY glGetQueryObjectuiv (GLuint id, GLenum pname, GLuint* params);
-GL_APICALL GLboolean GL_APIENTRY glUnmapBuffer (GLenum target);
-GL_APICALL void GL_APIENTRY glGetBufferPointerv (GLenum target, GLenum pname, GLvoid** params);
-GL_APICALL void GL_APIENTRY glDrawBuffers (GLsizei n, const GLenum* bufs);
-GL_APICALL void GL_APIENTRY glUniformMatrix2x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
-GL_APICALL void GL_APIENTRY glUniformMatrix3x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
-GL_APICALL void GL_APIENTRY glUniformMatrix2x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
-GL_APICALL void GL_APIENTRY glUniformMatrix4x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
-GL_APICALL void GL_APIENTRY glUniformMatrix3x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
-GL_APICALL void GL_APIENTRY glUniformMatrix4x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
-GL_APICALL void GL_APIENTRY glBlitFramebuffer (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
-GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
-GL_APICALL void GL_APIENTRY glFramebufferTextureLayer (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
-GL_APICALL GLvoid* GL_APIENTRY glMapBufferRange (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
-GL_APICALL void GL_APIENTRY glFlushMappedBufferRange (GLenum target, GLintptr offset, GLsizeiptr length);
-GL_APICALL void GL_APIENTRY glBindVertexArray (GLuint array);
-GL_APICALL void GL_APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint* arrays);
-GL_APICALL void GL_APIENTRY glGenVertexArrays (GLsizei n, GLuint* arrays);
-GL_APICALL GLboolean GL_APIENTRY glIsVertexArray (GLuint array);
-GL_APICALL void GL_APIENTRY glGetIntegeri_v (GLenum target, GLuint index, GLint* data);
-GL_APICALL void GL_APIENTRY glBeginTransformFeedback (GLenum primitiveMode);
-GL_APICALL void GL_APIENTRY glEndTransformFeedback (void);
-GL_APICALL void GL_APIENTRY glBindBufferRange (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
-GL_APICALL void GL_APIENTRY glBindBufferBase (GLenum target, GLuint index, GLuint buffer);
-GL_APICALL void GL_APIENTRY glTransformFeedbackVaryings (GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode);
-GL_APICALL void GL_APIENTRY glGetTransformFeedbackVarying (GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, GLenum* type, GLchar* name);
-GL_APICALL void GL_APIENTRY glVertexAttribIPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer);
-GL_APICALL void GL_APIENTRY glGetVertexAttribIiv (GLuint index, GLenum pname, GLint* params);
-GL_APICALL void GL_APIENTRY glGetVertexAttribIuiv (GLuint index, GLenum pname, GLuint* params);
-GL_APICALL void GL_APIENTRY glVertexAttribI4i (GLuint index, GLint x, GLint y, GLint z, GLint w);
-GL_APICALL void GL_APIENTRY glVertexAttribI4ui (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
-GL_APICALL void GL_APIENTRY glVertexAttribI4iv (GLuint index, const GLint* v);
-GL_APICALL void GL_APIENTRY glVertexAttribI4uiv (GLuint index, const GLuint* v);
-GL_APICALL void GL_APIENTRY glGetUniformuiv (GLuint program, GLint location, GLuint* params);
-GL_APICALL GLint GL_APIENTRY glGetFragDataLocation (GLuint program, const GLchar *name);
-GL_APICALL void GL_APIENTRY glUniform1ui (GLint location, GLuint v0);
-GL_APICALL void GL_APIENTRY glUniform2ui (GLint location, GLuint v0, GLuint v1);
-GL_APICALL void GL_APIENTRY glUniform3ui (GLint location, GLuint v0, GLuint v1, GLuint v2);
-GL_APICALL void GL_APIENTRY glUniform4ui (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
-GL_APICALL void GL_APIENTRY glUniform1uiv (GLint location, GLsizei count, const GLuint* value);
-GL_APICALL void GL_APIENTRY glUniform2uiv (GLint location, GLsizei count, const GLuint* value);
-GL_APICALL void GL_APIENTRY glUniform3uiv (GLint location, GLsizei count, const GLuint* value);
-GL_APICALL void GL_APIENTRY glUniform4uiv (GLint location, GLsizei count, const GLuint* value);
-GL_APICALL void GL_APIENTRY glClearBufferiv (GLenum buffer, GLint drawbuffer, const GLint* value);
-GL_APICALL void GL_APIENTRY glClearBufferuiv (GLenum buffer, GLint drawbuffer, const GLuint* value);
-GL_APICALL void GL_APIENTRY glClearBufferfv (GLenum buffer, GLint drawbuffer, const GLfloat* value);
-GL_APICALL void GL_APIENTRY glClearBufferfi (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
-GL_APICALL const GLubyte* GL_APIENTRY glGetStringi (GLenum name, GLuint index);
-GL_APICALL void GL_APIENTRY glCopyBufferSubData (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
-GL_APICALL void GL_APIENTRY glGetUniformIndices (GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames, GLuint* uniformIndices);
-GL_APICALL void GL_APIENTRY glGetActiveUniformsiv (GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params);
-GL_APICALL GLuint GL_APIENTRY glGetUniformBlockIndex (GLuint program, const GLchar* uniformBlockName);
-GL_APICALL void GL_APIENTRY glGetActiveUniformBlockiv (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params);
-GL_APICALL void GL_APIENTRY glGetActiveUniformBlockName (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName);
-GL_APICALL void GL_APIENTRY glUniformBlockBinding (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
-GL_APICALL void GL_APIENTRY glDrawArraysInstanced (GLenum mode, GLint first, GLsizei count, GLsizei instanceCount);
-GL_APICALL void GL_APIENTRY glDrawElementsInstanced (GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei instanceCount);
-GL_APICALL GLsync GL_APIENTRY glFenceSync (GLenum condition, GLbitfield flags);
-GL_APICALL GLboolean GL_APIENTRY glIsSync (GLsync sync);
-GL_APICALL void GL_APIENTRY glDeleteSync (GLsync sync);
-GL_APICALL GLenum GL_APIENTRY glClientWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout);
-GL_APICALL void GL_APIENTRY glWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout);
-GL_APICALL void GL_APIENTRY glGetInteger64v (GLenum pname, GLint64* params);
-GL_APICALL void GL_APIENTRY glGetSynciv (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values);
-GL_APICALL void GL_APIENTRY glGetInteger64i_v (GLenum target, GLuint index, GLint64* data);
-GL_APICALL void GL_APIENTRY glGetBufferParameteri64v (GLenum target, GLenum pname, GLint64* params);
-GL_APICALL void GL_APIENTRY glGenSamplers (GLsizei count, GLuint* samplers);
-GL_APICALL void GL_APIENTRY glDeleteSamplers (GLsizei count, const GLuint* samplers);
-GL_APICALL GLboolean GL_APIENTRY glIsSampler (GLuint sampler);
-GL_APICALL void GL_APIENTRY glBindSampler (GLuint unit, GLuint sampler);
-GL_APICALL void GL_APIENTRY glSamplerParameteri (GLuint sampler, GLenum pname, GLint param);
-GL_APICALL void GL_APIENTRY glSamplerParameteriv (GLuint sampler, GLenum pname, const GLint* param);
-GL_APICALL void GL_APIENTRY glSamplerParameterf (GLuint sampler, GLenum pname, GLfloat param);
-GL_APICALL void GL_APIENTRY glSamplerParameterfv (GLuint sampler, GLenum pname, const GLfloat* param);
-GL_APICALL void GL_APIENTRY glGetSamplerParameteriv (GLuint sampler, GLenum pname, GLint* params);
-GL_APICALL void GL_APIENTRY glGetSamplerParameterfv (GLuint sampler, GLenum pname, GLfloat* params);
-GL_APICALL void GL_APIENTRY glVertexAttribDivisor (GLuint index, GLuint divisor);
-GL_APICALL void GL_APIENTRY glBindTransformFeedback (GLenum target, GLuint id);
-GL_APICALL void GL_APIENTRY glDeleteTransformFeedbacks (GLsizei n, const GLuint* ids);
-GL_APICALL void GL_APIENTRY glGenTransformFeedbacks (GLsizei n, GLuint* ids);
-GL_APICALL GLboolean GL_APIENTRY glIsTransformFeedback (GLuint id);
-GL_APICALL void GL_APIENTRY glPauseTransformFeedback (void);
-GL_APICALL void GL_APIENTRY glResumeTransformFeedback (void);
-GL_APICALL void GL_APIENTRY glGetProgramBinary (GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, GLvoid* binary);
-GL_APICALL void GL_APIENTRY glProgramBinary (GLuint program, GLenum binaryFormat, const GLvoid* binary, GLsizei length);
-GL_APICALL void GL_APIENTRY glProgramParameteri (GLuint program, GLenum pname, GLint value);
-GL_APICALL void GL_APIENTRY glInvalidateFramebuffer (GLenum target, GLsizei numAttachments, const GLenum* attachments);
-GL_APICALL void GL_APIENTRY glInvalidateSubFramebuffer (GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height);
-GL_APICALL void GL_APIENTRY glTexStorage2D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
-GL_APICALL void GL_APIENTRY glTexStorage3D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
-GL_APICALL void GL_APIENTRY glGetInternalformativ (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
+#ifndef __gl3_h_
+#define __gl3_h_
+
+/*
+ * gl3.h last updated on $Date: 2013-02-12 14:37:24 -0800 (Tue, 12 Feb 2013) $
+ */
+
+#include <GLES3/gl3platform.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** Copyright (c) 2007-2013 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are 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 Materials.
+**
+** THE MATERIALS ARE 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
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+/*-------------------------------------------------------------------------
+ * Data type definitions
+ *-----------------------------------------------------------------------*/
+
+/* OpenGL ES 2.0 */
+
+typedef void GLvoid;
+typedef char GLchar;
+typedef unsigned int GLenum;
+typedef unsigned char GLboolean;
+typedef unsigned int GLbitfield;
+typedef khronos_int8_t GLbyte;
+typedef short GLshort;
+typedef int GLint;
+typedef int GLsizei;
+typedef khronos_uint8_t GLubyte;
+typedef unsigned short GLushort;
+typedef unsigned int GLuint;
+typedef khronos_float_t GLfloat;
+typedef khronos_float_t GLclampf;
+typedef khronos_int32_t GLfixed;
+typedef khronos_intptr_t GLintptr;
+typedef khronos_ssize_t GLsizeiptr;
+
+/* OpenGL ES 3.0 */
+
+typedef unsigned short GLhalf;
+typedef khronos_int64_t GLint64;
+typedef khronos_uint64_t GLuint64;
+typedef struct __GLsync *GLsync;
+
+/*-------------------------------------------------------------------------
+ * Token definitions
+ *-----------------------------------------------------------------------*/
+
+/* OpenGL ES core versions */
+#define GL_ES_VERSION_3_0 1
+#define GL_ES_VERSION_2_0 1
+
+/* OpenGL ES 2.0 */
+
+/* ClearBufferMask */
+#define GL_DEPTH_BUFFER_BIT 0x00000100
+#define GL_STENCIL_BUFFER_BIT 0x00000400
+#define GL_COLOR_BUFFER_BIT 0x00004000
+
+/* Boolean */
+#define GL_FALSE 0
+#define GL_TRUE 1
+
+/* BeginMode */
+#define GL_POINTS 0x0000
+#define GL_LINES 0x0001
+#define GL_LINE_LOOP 0x0002
+#define GL_LINE_STRIP 0x0003
+#define GL_TRIANGLES 0x0004
+#define GL_TRIANGLE_STRIP 0x0005
+#define GL_TRIANGLE_FAN 0x0006
+
+/* BlendingFactorDest */
+#define GL_ZERO 0
+#define GL_ONE 1
+#define GL_SRC_COLOR 0x0300
+#define GL_ONE_MINUS_SRC_COLOR 0x0301
+#define GL_SRC_ALPHA 0x0302
+#define GL_ONE_MINUS_SRC_ALPHA 0x0303
+#define GL_DST_ALPHA 0x0304
+#define GL_ONE_MINUS_DST_ALPHA 0x0305
+
+/* BlendingFactorSrc */
+/* GL_ZERO */
+/* GL_ONE */
+#define GL_DST_COLOR 0x0306
+#define GL_ONE_MINUS_DST_COLOR 0x0307
+#define GL_SRC_ALPHA_SATURATE 0x0308
+/* GL_SRC_ALPHA */
+/* GL_ONE_MINUS_SRC_ALPHA */
+/* GL_DST_ALPHA */
+/* GL_ONE_MINUS_DST_ALPHA */
+
+/* BlendEquationSeparate */
+#define GL_FUNC_ADD 0x8006
+#define GL_BLEND_EQUATION 0x8009
+#define GL_BLEND_EQUATION_RGB 0x8009 /* same as BLEND_EQUATION */
+#define GL_BLEND_EQUATION_ALPHA 0x883D
+
+/* BlendSubtract */
+#define GL_FUNC_SUBTRACT 0x800A
+#define GL_FUNC_REVERSE_SUBTRACT 0x800B
+
+/* Separate Blend Functions */
+#define GL_BLEND_DST_RGB 0x80C8
+#define GL_BLEND_SRC_RGB 0x80C9
+#define GL_BLEND_DST_ALPHA 0x80CA
+#define GL_BLEND_SRC_ALPHA 0x80CB
+#define GL_CONSTANT_COLOR 0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
+#define GL_CONSTANT_ALPHA 0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
+#define GL_BLEND_COLOR 0x8005
+
+/* Buffer Objects */
+#define GL_ARRAY_BUFFER 0x8892
+#define GL_ELEMENT_ARRAY_BUFFER 0x8893
+#define GL_ARRAY_BUFFER_BINDING 0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
+
+#define GL_STREAM_DRAW 0x88E0
+#define GL_STATIC_DRAW 0x88E4
+#define GL_DYNAMIC_DRAW 0x88E8
+
+#define GL_BUFFER_SIZE 0x8764
+#define GL_BUFFER_USAGE 0x8765
+
+#define GL_CURRENT_VERTEX_ATTRIB 0x8626
+
+/* CullFaceMode */
+#define GL_FRONT 0x0404
+#define GL_BACK 0x0405
+#define GL_FRONT_AND_BACK 0x0408
+
+/* DepthFunction */
+/* GL_NEVER */
+/* GL_LESS */
+/* GL_EQUAL */
+/* GL_LEQUAL */
+/* GL_GREATER */
+/* GL_NOTEQUAL */
+/* GL_GEQUAL */
+/* GL_ALWAYS */
+
+/* EnableCap */
+#define GL_TEXTURE_2D 0x0DE1
+#define GL_CULL_FACE 0x0B44
+#define GL_BLEND 0x0BE2
+#define GL_DITHER 0x0BD0
+#define GL_STENCIL_TEST 0x0B90
+#define GL_DEPTH_TEST 0x0B71
+#define GL_SCISSOR_TEST 0x0C11
+#define GL_POLYGON_OFFSET_FILL 0x8037
+#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
+#define GL_SAMPLE_COVERAGE 0x80A0
+
+/* ErrorCode */
+#define GL_NO_ERROR 0
+#define GL_INVALID_ENUM 0x0500
+#define GL_INVALID_VALUE 0x0501
+#define GL_INVALID_OPERATION 0x0502
+#define GL_OUT_OF_MEMORY 0x0505
+
+/* FrontFaceDirection */
+#define GL_CW 0x0900
+#define GL_CCW 0x0901
+
+/* GetPName */
+#define GL_LINE_WIDTH 0x0B21
+#define GL_ALIASED_POINT_SIZE_RANGE 0x846D
+#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E
+#define GL_CULL_FACE_MODE 0x0B45
+#define GL_FRONT_FACE 0x0B46
+#define GL_DEPTH_RANGE 0x0B70
+#define GL_DEPTH_WRITEMASK 0x0B72
+#define GL_DEPTH_CLEAR_VALUE 0x0B73
+#define GL_DEPTH_FUNC 0x0B74
+#define GL_STENCIL_CLEAR_VALUE 0x0B91
+#define GL_STENCIL_FUNC 0x0B92
+#define GL_STENCIL_FAIL 0x0B94
+#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95
+#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96
+#define GL_STENCIL_REF 0x0B97
+#define GL_STENCIL_VALUE_MASK 0x0B93
+#define GL_STENCIL_WRITEMASK 0x0B98
+#define GL_STENCIL_BACK_FUNC 0x8800
+#define GL_STENCIL_BACK_FAIL 0x8801
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803
+#define GL_STENCIL_BACK_REF 0x8CA3
+#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4
+#define GL_STENCIL_BACK_WRITEMASK 0x8CA5
+#define GL_VIEWPORT 0x0BA2
+#define GL_SCISSOR_BOX 0x0C10
+/* GL_SCISSOR_TEST */
+#define GL_COLOR_CLEAR_VALUE 0x0C22
+#define GL_COLOR_WRITEMASK 0x0C23
+#define GL_UNPACK_ALIGNMENT 0x0CF5
+#define GL_PACK_ALIGNMENT 0x0D05
+#define GL_MAX_TEXTURE_SIZE 0x0D33
+#define GL_MAX_VIEWPORT_DIMS 0x0D3A
+#define GL_SUBPIXEL_BITS 0x0D50
+#define GL_RED_BITS 0x0D52
+#define GL_GREEN_BITS 0x0D53
+#define GL_BLUE_BITS 0x0D54
+#define GL_ALPHA_BITS 0x0D55
+#define GL_DEPTH_BITS 0x0D56
+#define GL_STENCIL_BITS 0x0D57
+#define GL_POLYGON_OFFSET_UNITS 0x2A00
+/* GL_POLYGON_OFFSET_FILL */
+#define GL_POLYGON_OFFSET_FACTOR 0x8038
+#define GL_TEXTURE_BINDING_2D 0x8069
+#define GL_SAMPLE_BUFFERS 0x80A8
+#define GL_SAMPLES 0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE 0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT 0x80AB
+
+/* GetTextureParameter */
+/* GL_TEXTURE_MAG_FILTER */
+/* GL_TEXTURE_MIN_FILTER */
+/* GL_TEXTURE_WRAP_S */
+/* GL_TEXTURE_WRAP_T */
+
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3
+
+/* HintMode */
+#define GL_DONT_CARE 0x1100
+#define GL_FASTEST 0x1101
+#define GL_NICEST 0x1102
+
+/* HintTarget */
+#define GL_GENERATE_MIPMAP_HINT 0x8192
+
+/* DataType */
+#define GL_BYTE 0x1400
+#define GL_UNSIGNED_BYTE 0x1401
+#define GL_SHORT 0x1402
+#define GL_UNSIGNED_SHORT 0x1403
+#define GL_INT 0x1404
+#define GL_UNSIGNED_INT 0x1405
+#define GL_FLOAT 0x1406
+#define GL_FIXED 0x140C
+
+/* PixelFormat */
+#define GL_DEPTH_COMPONENT 0x1902
+#define GL_ALPHA 0x1906
+#define GL_RGB 0x1907
+#define GL_RGBA 0x1908
+#define GL_LUMINANCE 0x1909
+#define GL_LUMINANCE_ALPHA 0x190A
+
+/* PixelType */
+/* GL_UNSIGNED_BYTE */
+#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
+#define GL_UNSIGNED_SHORT_5_6_5 0x8363
+
+/* Shaders */
+#define GL_FRAGMENT_SHADER 0x8B30
+#define GL_VERTEX_SHADER 0x8B31
+#define GL_MAX_VERTEX_ATTRIBS 0x8869
+#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
+#define GL_MAX_VARYING_VECTORS 0x8DFC
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C
+#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872
+#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
+#define GL_SHADER_TYPE 0x8B4F
+#define GL_DELETE_STATUS 0x8B80
+#define GL_LINK_STATUS 0x8B82
+#define GL_VALIDATE_STATUS 0x8B83
+#define GL_ATTACHED_SHADERS 0x8B85
+#define GL_ACTIVE_UNIFORMS 0x8B86
+#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87
+#define GL_ACTIVE_ATTRIBUTES 0x8B89
+#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A
+#define GL_SHADING_LANGUAGE_VERSION 0x8B8C
+#define GL_CURRENT_PROGRAM 0x8B8D
+
+/* StencilFunction */
+#define GL_NEVER 0x0200
+#define GL_LESS 0x0201
+#define GL_EQUAL 0x0202
+#define GL_LEQUAL 0x0203
+#define GL_GREATER 0x0204
+#define GL_NOTEQUAL 0x0205
+#define GL_GEQUAL 0x0206
+#define GL_ALWAYS 0x0207
+
+/* StencilOp */
+/* GL_ZERO */
+#define GL_KEEP 0x1E00
+#define GL_REPLACE 0x1E01
+#define GL_INCR 0x1E02
+#define GL_DECR 0x1E03
+#define GL_INVERT 0x150A
+#define GL_INCR_WRAP 0x8507
+#define GL_DECR_WRAP 0x8508
+
+/* StringName */
+#define GL_VENDOR 0x1F00
+#define GL_RENDERER 0x1F01
+#define GL_VERSION 0x1F02
+#define GL_EXTENSIONS 0x1F03
+
+/* TextureMagFilter */
+#define GL_NEAREST 0x2600
+#define GL_LINEAR 0x2601
+
+/* TextureMinFilter */
+/* GL_NEAREST */
+/* GL_LINEAR */
+#define GL_NEAREST_MIPMAP_NEAREST 0x2700
+#define GL_LINEAR_MIPMAP_NEAREST 0x2701
+#define GL_NEAREST_MIPMAP_LINEAR 0x2702
+#define GL_LINEAR_MIPMAP_LINEAR 0x2703
+
+/* TextureParameterName */
+#define GL_TEXTURE_MAG_FILTER 0x2800
+#define GL_TEXTURE_MIN_FILTER 0x2801
+#define GL_TEXTURE_WRAP_S 0x2802
+#define GL_TEXTURE_WRAP_T 0x2803
+
+/* TextureTarget */
+/* GL_TEXTURE_2D */
+#define GL_TEXTURE 0x1702
+
+#define GL_TEXTURE_CUBE_MAP 0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
+
+/* TextureUnit */
+#define GL_TEXTURE0 0x84C0
+#define GL_TEXTURE1 0x84C1
+#define GL_TEXTURE2 0x84C2
+#define GL_TEXTURE3 0x84C3
+#define GL_TEXTURE4 0x84C4
+#define GL_TEXTURE5 0x84C5
+#define GL_TEXTURE6 0x84C6
+#define GL_TEXTURE7 0x84C7
+#define GL_TEXTURE8 0x84C8
+#define GL_TEXTURE9 0x84C9
+#define GL_TEXTURE10 0x84CA
+#define GL_TEXTURE11 0x84CB
+#define GL_TEXTURE12 0x84CC
+#define GL_TEXTURE13 0x84CD
+#define GL_TEXTURE14 0x84CE
+#define GL_TEXTURE15 0x84CF
+#define GL_TEXTURE16 0x84D0
+#define GL_TEXTURE17 0x84D1
+#define GL_TEXTURE18 0x84D2
+#define GL_TEXTURE19 0x84D3
+#define GL_TEXTURE20 0x84D4
+#define GL_TEXTURE21 0x84D5
+#define GL_TEXTURE22 0x84D6
+#define GL_TEXTURE23 0x84D7
+#define GL_TEXTURE24 0x84D8
+#define GL_TEXTURE25 0x84D9
+#define GL_TEXTURE26 0x84DA
+#define GL_TEXTURE27 0x84DB
+#define GL_TEXTURE28 0x84DC
+#define GL_TEXTURE29 0x84DD
+#define GL_TEXTURE30 0x84DE
+#define GL_TEXTURE31 0x84DF
+#define GL_ACTIVE_TEXTURE 0x84E0
+
+/* TextureWrapMode */
+#define GL_REPEAT 0x2901
+#define GL_CLAMP_TO_EDGE 0x812F
+#define GL_MIRRORED_REPEAT 0x8370
+
+/* Uniform Types */
+#define GL_FLOAT_VEC2 0x8B50
+#define GL_FLOAT_VEC3 0x8B51
+#define GL_FLOAT_VEC4 0x8B52
+#define GL_INT_VEC2 0x8B53
+#define GL_INT_VEC3 0x8B54
+#define GL_INT_VEC4 0x8B55
+#define GL_BOOL 0x8B56
+#define GL_BOOL_VEC2 0x8B57
+#define GL_BOOL_VEC3 0x8B58
+#define GL_BOOL_VEC4 0x8B59
+#define GL_FLOAT_MAT2 0x8B5A
+#define GL_FLOAT_MAT3 0x8B5B
+#define GL_FLOAT_MAT4 0x8B5C
+#define GL_SAMPLER_2D 0x8B5E
+#define GL_SAMPLER_CUBE 0x8B60
+
+/* Vertex Arrays */
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
+
+/* Read Format */
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
+
+/* Shader Source */
+#define GL_COMPILE_STATUS 0x8B81
+#define GL_INFO_LOG_LENGTH 0x8B84
+#define GL_SHADER_SOURCE_LENGTH 0x8B88
+#define GL_SHADER_COMPILER 0x8DFA
+
+/* Shader Binary */
+#define GL_SHADER_BINARY_FORMATS 0x8DF8
+#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9
+
+/* Shader Precision-Specified Types */
+#define GL_LOW_FLOAT 0x8DF0
+#define GL_MEDIUM_FLOAT 0x8DF1
+#define GL_HIGH_FLOAT 0x8DF2
+#define GL_LOW_INT 0x8DF3
+#define GL_MEDIUM_INT 0x8DF4
+#define GL_HIGH_INT 0x8DF5
+
+/* Framebuffer Object. */
+#define GL_FRAMEBUFFER 0x8D40
+#define GL_RENDERBUFFER 0x8D41
+
+#define GL_RGBA4 0x8056
+#define GL_RGB5_A1 0x8057
+#define GL_RGB565 0x8D62
+#define GL_DEPTH_COMPONENT16 0x81A5
+#define GL_STENCIL_INDEX8 0x8D48
+
+#define GL_RENDERBUFFER_WIDTH 0x8D42
+#define GL_RENDERBUFFER_HEIGHT 0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44
+#define GL_RENDERBUFFER_RED_SIZE 0x8D50
+#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51
+#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52
+#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53
+#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54
+#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55
+
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
+
+#define GL_COLOR_ATTACHMENT0 0x8CE0
+#define GL_DEPTH_ATTACHMENT 0x8D00
+#define GL_STENCIL_ATTACHMENT 0x8D20
+
+#define GL_NONE 0
+
+#define GL_FRAMEBUFFER_COMPLETE 0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9
+#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD
+
+#define GL_FRAMEBUFFER_BINDING 0x8CA6
+#define GL_RENDERBUFFER_BINDING 0x8CA7
+#define GL_MAX_RENDERBUFFER_SIZE 0x84E8
+
+#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
+
+/* OpenGL ES 3.0 */
+
+#define GL_READ_BUFFER 0x0C02
+#define GL_UNPACK_ROW_LENGTH 0x0CF2
+#define GL_UNPACK_SKIP_ROWS 0x0CF3
+#define GL_UNPACK_SKIP_PIXELS 0x0CF4
+#define GL_PACK_ROW_LENGTH 0x0D02
+#define GL_PACK_SKIP_ROWS 0x0D03
+#define GL_PACK_SKIP_PIXELS 0x0D04
+#define GL_COLOR 0x1800
+#define GL_DEPTH 0x1801
+#define GL_STENCIL 0x1802
+#define GL_RED 0x1903
+#define GL_RGB8 0x8051
+#define GL_RGBA8 0x8058
+#define GL_RGB10_A2 0x8059
+#define GL_TEXTURE_BINDING_3D 0x806A
+#define GL_UNPACK_SKIP_IMAGES 0x806D
+#define GL_UNPACK_IMAGE_HEIGHT 0x806E
+#define GL_TEXTURE_3D 0x806F
+#define GL_TEXTURE_WRAP_R 0x8072
+#define GL_MAX_3D_TEXTURE_SIZE 0x8073
+#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
+#define GL_MAX_ELEMENTS_VERTICES 0x80E8
+#define GL_MAX_ELEMENTS_INDICES 0x80E9
+#define GL_TEXTURE_MIN_LOD 0x813A
+#define GL_TEXTURE_MAX_LOD 0x813B
+#define GL_TEXTURE_BASE_LEVEL 0x813C
+#define GL_TEXTURE_MAX_LEVEL 0x813D
+#define GL_MIN 0x8007
+#define GL_MAX 0x8008
+#define GL_DEPTH_COMPONENT24 0x81A6
+#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD
+#define GL_TEXTURE_COMPARE_MODE 0x884C
+#define GL_TEXTURE_COMPARE_FUNC 0x884D
+#define GL_CURRENT_QUERY 0x8865
+#define GL_QUERY_RESULT 0x8866
+#define GL_QUERY_RESULT_AVAILABLE 0x8867
+#define GL_BUFFER_MAPPED 0x88BC
+#define GL_BUFFER_MAP_POINTER 0x88BD
+#define GL_STREAM_READ 0x88E1
+#define GL_STREAM_COPY 0x88E2
+#define GL_STATIC_READ 0x88E5
+#define GL_STATIC_COPY 0x88E6
+#define GL_DYNAMIC_READ 0x88E9
+#define GL_DYNAMIC_COPY 0x88EA
+#define GL_MAX_DRAW_BUFFERS 0x8824
+#define GL_DRAW_BUFFER0 0x8825
+#define GL_DRAW_BUFFER1 0x8826
+#define GL_DRAW_BUFFER2 0x8827
+#define GL_DRAW_BUFFER3 0x8828
+#define GL_DRAW_BUFFER4 0x8829
+#define GL_DRAW_BUFFER5 0x882A
+#define GL_DRAW_BUFFER6 0x882B
+#define GL_DRAW_BUFFER7 0x882C
+#define GL_DRAW_BUFFER8 0x882D
+#define GL_DRAW_BUFFER9 0x882E
+#define GL_DRAW_BUFFER10 0x882F
+#define GL_DRAW_BUFFER11 0x8830
+#define GL_DRAW_BUFFER12 0x8831
+#define GL_DRAW_BUFFER13 0x8832
+#define GL_DRAW_BUFFER14 0x8833
+#define GL_DRAW_BUFFER15 0x8834
+#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49
+#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A
+#define GL_SAMPLER_3D 0x8B5F
+#define GL_SAMPLER_2D_SHADOW 0x8B62
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B
+#define GL_PIXEL_PACK_BUFFER 0x88EB
+#define GL_PIXEL_UNPACK_BUFFER 0x88EC
+#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED
+#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF
+#define GL_FLOAT_MAT2x3 0x8B65
+#define GL_FLOAT_MAT2x4 0x8B66
+#define GL_FLOAT_MAT3x2 0x8B67
+#define GL_FLOAT_MAT3x4 0x8B68
+#define GL_FLOAT_MAT4x2 0x8B69
+#define GL_FLOAT_MAT4x3 0x8B6A
+#define GL_SRGB 0x8C40
+#define GL_SRGB8 0x8C41
+#define GL_SRGB8_ALPHA8 0x8C43
+#define GL_COMPARE_REF_TO_TEXTURE 0x884E
+#define GL_MAJOR_VERSION 0x821B
+#define GL_MINOR_VERSION 0x821C
+#define GL_NUM_EXTENSIONS 0x821D
+#define GL_RGBA32F 0x8814
+#define GL_RGB32F 0x8815
+#define GL_RGBA16F 0x881A
+#define GL_RGB16F 0x881B
+#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD
+#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF
+#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904
+#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905
+#define GL_MAX_VARYING_COMPONENTS 0x8B4B
+#define GL_TEXTURE_2D_ARRAY 0x8C1A
+#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D
+#define GL_R11F_G11F_B10F 0x8C3A
+#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B
+#define GL_RGB9_E5 0x8C3D
+#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E
+#define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76
+#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F
+#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80
+#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83
+#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84
+#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85
+#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88
+#define GL_RASTERIZER_DISCARD 0x8C89
+#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A
+#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B
+#define GL_INTERLEAVED_ATTRIBS 0x8C8C
+#define GL_SEPARATE_ATTRIBS 0x8C8D
+#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E
+#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F
+#define GL_RGBA32UI 0x8D70
+#define GL_RGB32UI 0x8D71
+#define GL_RGBA16UI 0x8D76
+#define GL_RGB16UI 0x8D77
+#define GL_RGBA8UI 0x8D7C
+#define GL_RGB8UI 0x8D7D
+#define GL_RGBA32I 0x8D82
+#define GL_RGB32I 0x8D83
+#define GL_RGBA16I 0x8D88
+#define GL_RGB16I 0x8D89
+#define GL_RGBA8I 0x8D8E
+#define GL_RGB8I 0x8D8F
+#define GL_RED_INTEGER 0x8D94
+#define GL_RGB_INTEGER 0x8D98
+#define GL_RGBA_INTEGER 0x8D99
+#define GL_SAMPLER_2D_ARRAY 0x8DC1
+#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4
+#define GL_SAMPLER_CUBE_SHADOW 0x8DC5
+#define GL_UNSIGNED_INT_VEC2 0x8DC6
+#define GL_UNSIGNED_INT_VEC3 0x8DC7
+#define GL_UNSIGNED_INT_VEC4 0x8DC8
+#define GL_INT_SAMPLER_2D 0x8DCA
+#define GL_INT_SAMPLER_3D 0x8DCB
+#define GL_INT_SAMPLER_CUBE 0x8DCC
+#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF
+#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2
+#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3
+#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4
+#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7
+#define GL_BUFFER_ACCESS_FLAGS 0x911F
+#define GL_BUFFER_MAP_LENGTH 0x9120
+#define GL_BUFFER_MAP_OFFSET 0x9121
+#define GL_DEPTH_COMPONENT32F 0x8CAC
+#define GL_DEPTH32F_STENCIL8 0x8CAD
+#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD
+#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210
+#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211
+#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212
+#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213
+#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214
+#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215
+#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216
+#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217
+#define GL_FRAMEBUFFER_DEFAULT 0x8218
+#define GL_FRAMEBUFFER_UNDEFINED 0x8219
+#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A
+#define GL_DEPTH_STENCIL 0x84F9
+#define GL_UNSIGNED_INT_24_8 0x84FA
+#define GL_DEPTH24_STENCIL8 0x88F0
+#define GL_UNSIGNED_NORMALIZED 0x8C17
+#define GL_DRAW_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING
+#define GL_READ_FRAMEBUFFER 0x8CA8
+#define GL_DRAW_FRAMEBUFFER 0x8CA9
+#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA
+#define GL_RENDERBUFFER_SAMPLES 0x8CAB
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4
+#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF
+#define GL_COLOR_ATTACHMENT1 0x8CE1
+#define GL_COLOR_ATTACHMENT2 0x8CE2
+#define GL_COLOR_ATTACHMENT3 0x8CE3
+#define GL_COLOR_ATTACHMENT4 0x8CE4
+#define GL_COLOR_ATTACHMENT5 0x8CE5
+#define GL_COLOR_ATTACHMENT6 0x8CE6
+#define GL_COLOR_ATTACHMENT7 0x8CE7
+#define GL_COLOR_ATTACHMENT8 0x8CE8
+#define GL_COLOR_ATTACHMENT9 0x8CE9
+#define GL_COLOR_ATTACHMENT10 0x8CEA
+#define GL_COLOR_ATTACHMENT11 0x8CEB
+#define GL_COLOR_ATTACHMENT12 0x8CEC
+#define GL_COLOR_ATTACHMENT13 0x8CED
+#define GL_COLOR_ATTACHMENT14 0x8CEE
+#define GL_COLOR_ATTACHMENT15 0x8CEF
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56
+#define GL_MAX_SAMPLES 0x8D57
+#define GL_HALF_FLOAT 0x140B
+#define GL_MAP_READ_BIT 0x0001
+#define GL_MAP_WRITE_BIT 0x0002
+#define GL_MAP_INVALIDATE_RANGE_BIT 0x0004
+#define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008
+#define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010
+#define GL_MAP_UNSYNCHRONIZED_BIT 0x0020
+#define GL_RG 0x8227
+#define GL_RG_INTEGER 0x8228
+#define GL_R8 0x8229
+#define GL_RG8 0x822B
+#define GL_R16F 0x822D
+#define GL_R32F 0x822E
+#define GL_RG16F 0x822F
+#define GL_RG32F 0x8230
+#define GL_R8I 0x8231
+#define GL_R8UI 0x8232
+#define GL_R16I 0x8233
+#define GL_R16UI 0x8234
+#define GL_R32I 0x8235
+#define GL_R32UI 0x8236
+#define GL_RG8I 0x8237
+#define GL_RG8UI 0x8238
+#define GL_RG16I 0x8239
+#define GL_RG16UI 0x823A
+#define GL_RG32I 0x823B
+#define GL_RG32UI 0x823C
+#define GL_VERTEX_ARRAY_BINDING 0x85B5
+#define GL_R8_SNORM 0x8F94
+#define GL_RG8_SNORM 0x8F95
+#define GL_RGB8_SNORM 0x8F96
+#define GL_RGBA8_SNORM 0x8F97
+#define GL_SIGNED_NORMALIZED 0x8F9C
+#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69
+#define GL_COPY_READ_BUFFER 0x8F36
+#define GL_COPY_WRITE_BUFFER 0x8F37
+#define GL_COPY_READ_BUFFER_BINDING GL_COPY_READ_BUFFER
+#define GL_COPY_WRITE_BUFFER_BINDING GL_COPY_WRITE_BUFFER
+#define GL_UNIFORM_BUFFER 0x8A11
+#define GL_UNIFORM_BUFFER_BINDING 0x8A28
+#define GL_UNIFORM_BUFFER_START 0x8A29
+#define GL_UNIFORM_BUFFER_SIZE 0x8A2A
+#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B
+#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D
+#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E
+#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F
+#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30
+#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31
+#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33
+#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34
+#define GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH 0x8A35
+#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36
+#define GL_UNIFORM_TYPE 0x8A37
+#define GL_UNIFORM_SIZE 0x8A38
+#define GL_UNIFORM_NAME_LENGTH 0x8A39
+#define GL_UNIFORM_BLOCK_INDEX 0x8A3A
+#define GL_UNIFORM_OFFSET 0x8A3B
+#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C
+#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D
+#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E
+#define GL_UNIFORM_BLOCK_BINDING 0x8A3F
+#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40
+#define GL_UNIFORM_BLOCK_NAME_LENGTH 0x8A41
+#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42
+#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44
+#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46
+#define GL_INVALID_INDEX 0xFFFFFFFFu
+#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122
+#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125
+#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111
+#define GL_OBJECT_TYPE 0x9112
+#define GL_SYNC_CONDITION 0x9113
+#define GL_SYNC_STATUS 0x9114
+#define GL_SYNC_FLAGS 0x9115
+#define GL_SYNC_FENCE 0x9116
+#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117
+#define GL_UNSIGNALED 0x9118
+#define GL_SIGNALED 0x9119
+#define GL_ALREADY_SIGNALED 0x911A
+#define GL_TIMEOUT_EXPIRED 0x911B
+#define GL_CONDITION_SATISFIED 0x911C
+#define GL_WAIT_FAILED 0x911D
+#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001
+#define GL_TIMEOUT_IGNORED 0xFFFFFFFFFFFFFFFFull
+#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE
+#define GL_ANY_SAMPLES_PASSED 0x8C2F
+#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A
+#define GL_SAMPLER_BINDING 0x8919
+#define GL_RGB10_A2UI 0x906F
+#define GL_TEXTURE_SWIZZLE_R 0x8E42
+#define GL_TEXTURE_SWIZZLE_G 0x8E43
+#define GL_TEXTURE_SWIZZLE_B 0x8E44
+#define GL_TEXTURE_SWIZZLE_A 0x8E45
+#define GL_GREEN 0x1904
+#define GL_BLUE 0x1905
+#define GL_INT_2_10_10_10_REV 0x8D9F
+#define GL_TRANSFORM_FEEDBACK 0x8E22
+#define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23
+#define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24
+#define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25
+#define GL_PROGRAM_BINARY_RETRIEVABLE_HINT 0x8257
+#define GL_PROGRAM_BINARY_LENGTH 0x8741
+#define GL_NUM_PROGRAM_BINARY_FORMATS 0x87FE
+#define GL_PROGRAM_BINARY_FORMATS 0x87FF
+#define GL_COMPRESSED_R11_EAC 0x9270
+#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271
+#define GL_COMPRESSED_RG11_EAC 0x9272
+#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273
+#define GL_COMPRESSED_RGB8_ETC2 0x9274
+#define GL_COMPRESSED_SRGB8_ETC2 0x9275
+#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276
+#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277
+#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278
+#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279
+#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F
+#define GL_MAX_ELEMENT_INDEX 0x8D6B
+#define GL_NUM_SAMPLE_COUNTS 0x9380
+#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF
+
+/*-------------------------------------------------------------------------
+ * Entrypoint definitions
+ *-----------------------------------------------------------------------*/
+
+/* OpenGL ES 2.0 */
+
+GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture);
+GL_APICALL void GL_APIENTRY glAttachShader (GLuint program, GLuint shader);
+GL_APICALL void GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar* name);
+GL_APICALL void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer);
+GL_APICALL void GL_APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer);
+GL_APICALL void GL_APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer);
+GL_APICALL void GL_APIENTRY glBindTexture (GLenum target, GLuint texture);
+GL_APICALL void GL_APIENTRY glBlendColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+GL_APICALL void GL_APIENTRY glBlendEquation (GLenum mode);
+GL_APICALL void GL_APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha);
+GL_APICALL void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor);
+GL_APICALL void GL_APIENTRY glBlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+GL_APICALL void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
+GL_APICALL void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
+GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatus (GLenum target);
+GL_APICALL void GL_APIENTRY glClear (GLbitfield mask);
+GL_APICALL void GL_APIENTRY glClearColor (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+GL_APICALL void GL_APIENTRY glClearDepthf (GLfloat depth);
+GL_APICALL void GL_APIENTRY glClearStencil (GLint s);
+GL_APICALL void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+GL_APICALL void GL_APIENTRY glCompileShader (GLuint shader);
+GL_APICALL void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+GL_APICALL void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL GLuint GL_APIENTRY glCreateProgram (void);
+GL_APICALL GLuint GL_APIENTRY glCreateShader (GLenum type);
+GL_APICALL void GL_APIENTRY glCullFace (GLenum mode);
+GL_APICALL void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint* buffers);
+GL_APICALL void GL_APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint* framebuffers);
+GL_APICALL void GL_APIENTRY glDeleteProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint* renderbuffers);
+GL_APICALL void GL_APIENTRY glDeleteShader (GLuint shader);
+GL_APICALL void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint* textures);
+GL_APICALL void GL_APIENTRY glDepthFunc (GLenum func);
+GL_APICALL void GL_APIENTRY glDepthMask (GLboolean flag);
+GL_APICALL void GL_APIENTRY glDepthRangef (GLfloat n, GLfloat f);
+GL_APICALL void GL_APIENTRY glDetachShader (GLuint program, GLuint shader);
+GL_APICALL void GL_APIENTRY glDisable (GLenum cap);
+GL_APICALL void GL_APIENTRY glDisableVertexAttribArray (GLuint index);
+GL_APICALL void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);
+GL_APICALL void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid* indices);
+GL_APICALL void GL_APIENTRY glEnable (GLenum cap);
+GL_APICALL void GL_APIENTRY glEnableVertexAttribArray (GLuint index);
+GL_APICALL void GL_APIENTRY glFinish (void);
+GL_APICALL void GL_APIENTRY glFlush (void);
+GL_APICALL void GL_APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+GL_APICALL void GL_APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GL_APICALL void GL_APIENTRY glFrontFace (GLenum mode);
+GL_APICALL void GL_APIENTRY glGenBuffers (GLsizei n, GLuint* buffers);
+GL_APICALL void GL_APIENTRY glGenerateMipmap (GLenum target);
+GL_APICALL void GL_APIENTRY glGenFramebuffers (GLsizei n, GLuint* framebuffers);
+GL_APICALL void GL_APIENTRY glGenRenderbuffers (GLsizei n, GLuint* renderbuffers);
+GL_APICALL void GL_APIENTRY glGenTextures (GLsizei n, GLuint* textures);
+GL_APICALL void GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
+GL_APICALL void GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
+GL_APICALL void GL_APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders);
+GL_APICALL GLint GL_APIENTRY glGetAttribLocation (GLuint program, const GLchar* name);
+GL_APICALL void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean* params);
+GL_APICALL void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL GLenum GL_APIENTRY glGetError (void);
+GL_APICALL void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetIntegerv (GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog);
+GL_APICALL void GL_APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog);
+GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
+GL_APICALL void GL_APIENTRY glGetShaderSource (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source);
+GL_APICALL const GLubyte* GL_APIENTRY glGetString (GLenum name);
+GL_APICALL void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetUniformiv (GLuint program, GLint location, GLint* params);
+GL_APICALL GLint GL_APIENTRY glGetUniformLocation (GLuint program, const GLchar* name);
+GL_APICALL void GL_APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, GLvoid** pointer);
+GL_APICALL void GL_APIENTRY glHint (GLenum target, GLenum mode);
+GL_APICALL GLboolean GL_APIENTRY glIsBuffer (GLuint buffer);
+GL_APICALL GLboolean GL_APIENTRY glIsEnabled (GLenum cap);
+GL_APICALL GLboolean GL_APIENTRY glIsFramebuffer (GLuint framebuffer);
+GL_APICALL GLboolean GL_APIENTRY glIsProgram (GLuint program);
+GL_APICALL GLboolean GL_APIENTRY glIsRenderbuffer (GLuint renderbuffer);
+GL_APICALL GLboolean GL_APIENTRY glIsShader (GLuint shader);
+GL_APICALL GLboolean GL_APIENTRY glIsTexture (GLuint texture);
+GL_APICALL void GL_APIENTRY glLineWidth (GLfloat width);
+GL_APICALL void GL_APIENTRY glLinkProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glPixelStorei (GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units);
+GL_APICALL void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glReleaseShaderCompiler (void);
+GL_APICALL void GL_APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glSampleCoverage (GLfloat value, GLboolean invert);
+GL_APICALL void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glShaderBinary (GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length);
+GL_APICALL void GL_APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar* const* string, const GLint* length);
+GL_APICALL void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilMask (GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask);
+GL_APICALL void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass);
+GL_APICALL void GL_APIENTRY glStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
+GL_APICALL void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param);
+GL_APICALL void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat* params);
+GL_APICALL void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint* params);
+GL_APICALL void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glUniform1f (GLint location, GLfloat x);
+GL_APICALL void GL_APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform1i (GLint location, GLint x);
+GL_APICALL void GL_APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform2f (GLint location, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform2i (GLint location, GLint x, GLint y);
+GL_APICALL void GL_APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform3f (GLint location, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform3i (GLint location, GLint x, GLint y, GLint z);
+GL_APICALL void GL_APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniform4f (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void GL_APIENTRY glUniform4i (GLint location, GLint x, GLint y, GLint z, GLint w);
+GL_APICALL void GL_APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void GL_APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUseProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glValidateProgram (GLuint program);
+GL_APICALL void GL_APIENTRY glVertexAttrib1f (GLuint indx, GLfloat x);
+GL_APICALL void GL_APIENTRY glVertexAttrib1fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib2f (GLuint indx, GLfloat x, GLfloat y);
+GL_APICALL void GL_APIENTRY glVertexAttrib2fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void GL_APIENTRY glVertexAttrib3fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttrib4f (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void GL_APIENTRY glVertexAttrib4fv (GLuint indx, const GLfloat* values);
+GL_APICALL void GL_APIENTRY glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr);
+GL_APICALL void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
+
+/* OpenGL ES 3.0 */
+
+GL_APICALL void GL_APIENTRY glReadBuffer (GLenum mode);
+GL_APICALL void GL_APIENTRY glDrawRangeElements (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid* indices);
+GL_APICALL void GL_APIENTRY glTexImage3D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glCopyTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glCompressedTexImage3D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void GL_APIENTRY glCompressedTexSubImage3D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void GL_APIENTRY glGenQueries (GLsizei n, GLuint* ids);
+GL_APICALL void GL_APIENTRY glDeleteQueries (GLsizei n, const GLuint* ids);
+GL_APICALL GLboolean GL_APIENTRY glIsQuery (GLuint id);
+GL_APICALL void GL_APIENTRY glBeginQuery (GLenum target, GLuint id);
+GL_APICALL void GL_APIENTRY glEndQuery (GLenum target);
+GL_APICALL void GL_APIENTRY glGetQueryiv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetQueryObjectuiv (GLuint id, GLenum pname, GLuint* params);
+GL_APICALL GLboolean GL_APIENTRY glUnmapBuffer (GLenum target);
+GL_APICALL void GL_APIENTRY glGetBufferPointerv (GLenum target, GLenum pname, GLvoid** params);
+GL_APICALL void GL_APIENTRY glDrawBuffers (GLsizei n, const GLenum* bufs);
+GL_APICALL void GL_APIENTRY glUniformMatrix2x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUniformMatrix3x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUniformMatrix2x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUniformMatrix4x2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUniformMatrix3x4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glUniformMatrix4x3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glBlitFramebuffer (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisample (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glFramebufferTextureLayer (GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
+GL_APICALL GLvoid* GL_APIENTRY glMapBufferRange (GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access);
+GL_APICALL void GL_APIENTRY glFlushMappedBufferRange (GLenum target, GLintptr offset, GLsizeiptr length);
+GL_APICALL void GL_APIENTRY glBindVertexArray (GLuint array);
+GL_APICALL void GL_APIENTRY glDeleteVertexArrays (GLsizei n, const GLuint* arrays);
+GL_APICALL void GL_APIENTRY glGenVertexArrays (GLsizei n, GLuint* arrays);
+GL_APICALL GLboolean GL_APIENTRY glIsVertexArray (GLuint array);
+GL_APICALL void GL_APIENTRY glGetIntegeri_v (GLenum target, GLuint index, GLint* data);
+GL_APICALL void GL_APIENTRY glBeginTransformFeedback (GLenum primitiveMode);
+GL_APICALL void GL_APIENTRY glEndTransformFeedback (void);
+GL_APICALL void GL_APIENTRY glBindBufferRange (GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size);
+GL_APICALL void GL_APIENTRY glBindBufferBase (GLenum target, GLuint index, GLuint buffer);
+GL_APICALL void GL_APIENTRY glTransformFeedbackVaryings (GLuint program, GLsizei count, const GLchar* const* varyings, GLenum bufferMode);
+GL_APICALL void GL_APIENTRY glGetTransformFeedbackVarying (GLuint program, GLuint index, GLsizei bufSize, GLsizei* length, GLsizei* size, GLenum* type, GLchar* name);
+GL_APICALL void GL_APIENTRY glVertexAttribIPointer (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid* pointer);
+GL_APICALL void GL_APIENTRY glGetVertexAttribIiv (GLuint index, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetVertexAttribIuiv (GLuint index, GLenum pname, GLuint* params);
+GL_APICALL void GL_APIENTRY glVertexAttribI4i (GLuint index, GLint x, GLint y, GLint z, GLint w);
+GL_APICALL void GL_APIENTRY glVertexAttribI4ui (GLuint index, GLuint x, GLuint y, GLuint z, GLuint w);
+GL_APICALL void GL_APIENTRY glVertexAttribI4iv (GLuint index, const GLint* v);
+GL_APICALL void GL_APIENTRY glVertexAttribI4uiv (GLuint index, const GLuint* v);
+GL_APICALL void GL_APIENTRY glGetUniformuiv (GLuint program, GLint location, GLuint* params);
+GL_APICALL GLint GL_APIENTRY glGetFragDataLocation (GLuint program, const GLchar *name);
+GL_APICALL void GL_APIENTRY glUniform1ui (GLint location, GLuint v0);
+GL_APICALL void GL_APIENTRY glUniform2ui (GLint location, GLuint v0, GLuint v1);
+GL_APICALL void GL_APIENTRY glUniform3ui (GLint location, GLuint v0, GLuint v1, GLuint v2);
+GL_APICALL void GL_APIENTRY glUniform4ui (GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+GL_APICALL void GL_APIENTRY glUniform1uiv (GLint location, GLsizei count, const GLuint* value);
+GL_APICALL void GL_APIENTRY glUniform2uiv (GLint location, GLsizei count, const GLuint* value);
+GL_APICALL void GL_APIENTRY glUniform3uiv (GLint location, GLsizei count, const GLuint* value);
+GL_APICALL void GL_APIENTRY glUniform4uiv (GLint location, GLsizei count, const GLuint* value);
+GL_APICALL void GL_APIENTRY glClearBufferiv (GLenum buffer, GLint drawbuffer, const GLint* value);
+GL_APICALL void GL_APIENTRY glClearBufferuiv (GLenum buffer, GLint drawbuffer, const GLuint* value);
+GL_APICALL void GL_APIENTRY glClearBufferfv (GLenum buffer, GLint drawbuffer, const GLfloat* value);
+GL_APICALL void GL_APIENTRY glClearBufferfi (GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
+GL_APICALL const GLubyte* GL_APIENTRY glGetStringi (GLenum name, GLuint index);
+GL_APICALL void GL_APIENTRY glCopyBufferSubData (GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size);
+GL_APICALL void GL_APIENTRY glGetUniformIndices (GLuint program, GLsizei uniformCount, const GLchar* const* uniformNames, GLuint* uniformIndices);
+GL_APICALL void GL_APIENTRY glGetActiveUniformsiv (GLuint program, GLsizei uniformCount, const GLuint* uniformIndices, GLenum pname, GLint* params);
+GL_APICALL GLuint GL_APIENTRY glGetUniformBlockIndex (GLuint program, const GLchar* uniformBlockName);
+GL_APICALL void GL_APIENTRY glGetActiveUniformBlockiv (GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetActiveUniformBlockName (GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei* length, GLchar* uniformBlockName);
+GL_APICALL void GL_APIENTRY glUniformBlockBinding (GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding);
+GL_APICALL void GL_APIENTRY glDrawArraysInstanced (GLenum mode, GLint first, GLsizei count, GLsizei instanceCount);
+GL_APICALL void GL_APIENTRY glDrawElementsInstanced (GLenum mode, GLsizei count, GLenum type, const GLvoid* indices, GLsizei instanceCount);
+GL_APICALL GLsync GL_APIENTRY glFenceSync (GLenum condition, GLbitfield flags);
+GL_APICALL GLboolean GL_APIENTRY glIsSync (GLsync sync);
+GL_APICALL void GL_APIENTRY glDeleteSync (GLsync sync);
+GL_APICALL GLenum GL_APIENTRY glClientWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout);
+GL_APICALL void GL_APIENTRY glWaitSync (GLsync sync, GLbitfield flags, GLuint64 timeout);
+GL_APICALL void GL_APIENTRY glGetInteger64v (GLenum pname, GLint64* params);
+GL_APICALL void GL_APIENTRY glGetSynciv (GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length, GLint* values);
+GL_APICALL void GL_APIENTRY glGetInteger64i_v (GLenum target, GLuint index, GLint64* data);
+GL_APICALL void GL_APIENTRY glGetBufferParameteri64v (GLenum target, GLenum pname, GLint64* params);
+GL_APICALL void GL_APIENTRY glGenSamplers (GLsizei count, GLuint* samplers);
+GL_APICALL void GL_APIENTRY glDeleteSamplers (GLsizei count, const GLuint* samplers);
+GL_APICALL GLboolean GL_APIENTRY glIsSampler (GLuint sampler);
+GL_APICALL void GL_APIENTRY glBindSampler (GLuint unit, GLuint sampler);
+GL_APICALL void GL_APIENTRY glSamplerParameteri (GLuint sampler, GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY glSamplerParameteriv (GLuint sampler, GLenum pname, const GLint* param);
+GL_APICALL void GL_APIENTRY glSamplerParameterf (GLuint sampler, GLenum pname, GLfloat param);
+GL_APICALL void GL_APIENTRY glSamplerParameterfv (GLuint sampler, GLenum pname, const GLfloat* param);
+GL_APICALL void GL_APIENTRY glGetSamplerParameteriv (GLuint sampler, GLenum pname, GLint* params);
+GL_APICALL void GL_APIENTRY glGetSamplerParameterfv (GLuint sampler, GLenum pname, GLfloat* params);
+GL_APICALL void GL_APIENTRY glVertexAttribDivisor (GLuint index, GLuint divisor);
+GL_APICALL void GL_APIENTRY glBindTransformFeedback (GLenum target, GLuint id);
+GL_APICALL void GL_APIENTRY glDeleteTransformFeedbacks (GLsizei n, const GLuint* ids);
+GL_APICALL void GL_APIENTRY glGenTransformFeedbacks (GLsizei n, GLuint* ids);
+GL_APICALL GLboolean GL_APIENTRY glIsTransformFeedback (GLuint id);
+GL_APICALL void GL_APIENTRY glPauseTransformFeedback (void);
+GL_APICALL void GL_APIENTRY glResumeTransformFeedback (void);
+GL_APICALL void GL_APIENTRY glGetProgramBinary (GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, GLvoid* binary);
+GL_APICALL void GL_APIENTRY glProgramBinary (GLuint program, GLenum binaryFormat, const GLvoid* binary, GLsizei length);
+GL_APICALL void GL_APIENTRY glProgramParameteri (GLuint program, GLenum pname, GLint value);
+GL_APICALL void GL_APIENTRY glInvalidateFramebuffer (GLenum target, GLsizei numAttachments, const GLenum* attachments);
+GL_APICALL void GL_APIENTRY glInvalidateSubFramebuffer (GLenum target, GLsizei numAttachments, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glTexStorage2D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glTexStorage3D (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+GL_APICALL void GL_APIENTRY glGetInternalformativ (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint* params);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/platform/winrt/include/GLES3/gl3ext.h b/platform/winrt/include/GLES3/gl3ext.h
index 199436c082..4d4ea96c4d 100644
--- a/platform/winrt/include/GLES3/gl3ext.h
+++ b/platform/winrt/include/GLES3/gl3ext.h
@@ -1,24 +1,24 @@
-#ifndef __gl3ext_h_
-#define __gl3ext_h_
-
-/* $Revision: 17809 $ on $Date:: 2012-05-14 08:03:36 -0700 #$ */
-
-/*
- * This document is licensed under the SGI Free Software B License Version
- * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
- */
-
-/* OpenGL ES 3 Extensions
- *
- * After an OES extension's interactions with OpenGl ES 3.0 have been documented,
- * its tokens and function definitions should be added to this file in a manner
- * that does not conflict with gl2ext.h or gl3.h.
- *
- * Tokens and function definitions for extensions that have become standard
- * features in OpenGL ES 3.0 will not be added to this file.
- *
- * Applications using OpenGL-ES-2-only extensions should include gl2ext.h
- */
-
-#endif /* __gl3ext_h_ */
-
+#ifndef __gl3ext_h_
+#define __gl3ext_h_
+
+/* $Revision: 17809 $ on $Date:: 2012-05-14 08:03:36 -0700 #$ */
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+/* OpenGL ES 3 Extensions
+ *
+ * After an OES extension's interactions with OpenGl ES 3.0 have been documented,
+ * its tokens and function definitions should be added to this file in a manner
+ * that does not conflict with gl2ext.h or gl3.h.
+ *
+ * Tokens and function definitions for extensions that have become standard
+ * features in OpenGL ES 3.0 will not be added to this file.
+ *
+ * Applications using OpenGL-ES-2-only extensions should include gl2ext.h
+ */
+
+#endif /* __gl3ext_h_ */
+
diff --git a/platform/winrt/include/GLES3/gl3platform.h b/platform/winrt/include/GLES3/gl3platform.h
index 679e0dc3ca..1bd1a850fa 100644
--- a/platform/winrt/include/GLES3/gl3platform.h
+++ b/platform/winrt/include/GLES3/gl3platform.h
@@ -1,30 +1,30 @@
-#ifndef __gl3platform_h_
-#define __gl3platform_h_
-
-/* $Revision: 18437 $ on $Date:: 2012-07-08 23:31:39 -0700 #$ */
-
-/*
- * This document is licensed under the SGI Free Software B License Version
- * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
- */
-
-/* Platform-specific types and definitions for OpenGL ES 3.X gl3.h
- *
- * Adopters may modify khrplatform.h and this file to suit their platform.
- * You are encouraged to submit all modifications to the Khronos group so that
- * they can be included in future versions of this file. Please submit changes
- * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
- * by filing a bug against product "OpenGL-ES" component "Registry".
- */
-
-#include <KHR/khrplatform.h>
-
-#ifndef GL_APICALL
-#define GL_APICALL KHRONOS_APICALL
-#endif
-
-#ifndef GL_APIENTRY
-#define GL_APIENTRY KHRONOS_APIENTRY
-#endif
-
-#endif /* __gl3platform_h_ */
+#ifndef __gl3platform_h_
+#define __gl3platform_h_
+
+/* $Revision: 18437 $ on $Date:: 2012-07-08 23:31:39 -0700 #$ */
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+/* Platform-specific types and definitions for OpenGL ES 3.X gl3.h
+ *
+ * Adopters may modify khrplatform.h and this file to suit their platform.
+ * You are encouraged to submit all modifications to the Khronos group so that
+ * they can be included in future versions of this file. Please submit changes
+ * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
+ * by filing a bug against product "OpenGL-ES" component "Registry".
+ */
+
+#include <KHR/khrplatform.h>
+
+#ifndef GL_APICALL
+#define GL_APICALL KHRONOS_APICALL
+#endif
+
+#ifndef GL_APIENTRY
+#define GL_APIENTRY KHRONOS_APIENTRY
+#endif
+
+#endif /* __gl3platform_h_ */
diff --git a/platform/winrt/include/GLSLANG/ShaderLang.h b/platform/winrt/include/GLSLANG/ShaderLang.h
index d925b88f24..647fed6a02 100644
--- a/platform/winrt/include/GLSLANG/ShaderLang.h
+++ b/platform/winrt/include/GLSLANG/ShaderLang.h
@@ -1,411 +1,411 @@
-//
-// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-#ifndef _COMPILER_INTERFACE_INCLUDED_
-#define _COMPILER_INTERFACE_INCLUDED_
-
-#if defined(COMPONENT_BUILD) && !defined(ANGLE_TRANSLATOR_STATIC)
-#if defined(_WIN32) || defined(_WIN64)
-
-#if defined(ANGLE_TRANSLATOR_IMPLEMENTATION)
-#define COMPILER_EXPORT __declspec(dllexport)
-#else
-#define COMPILER_EXPORT __declspec(dllimport)
-#endif // defined(ANGLE_TRANSLATOR_IMPLEMENTATION)
-
-#else // defined(_WIN32) || defined(_WIN64)
-#define COMPILER_EXPORT __attribute__((visibility("default")))
-#endif
-
-#else // defined(COMPONENT_BUILD) && !defined(ANGLE_TRANSLATOR_STATIC)
-#define COMPILER_EXPORT
-#endif
-
-#include <stddef.h>
-
-#include "KHR/khrplatform.h"
-
-#include <map>
-#include <string>
-#include <vector>
-
-//
-// This is the platform independent interface between an OGL driver
-// and the shading language compiler.
-//
-
-namespace sh
-{
-// GLenum alias
-typedef unsigned int GLenum;
-}
-
-// Must be included after GLenum proxy typedef
-// Note: make sure to increment ANGLE_SH_VERSION when changing ShaderVars.h
-#include "ShaderVars.h"
-
-// Version number for shader translation API.
-// It is incremented every time the API changes.
-#define ANGLE_SH_VERSION 132
-
-typedef enum {
- SH_GLES2_SPEC = 0x8B40,
- SH_WEBGL_SPEC = 0x8B41,
-
- SH_GLES3_SPEC = 0x8B86,
- SH_WEBGL2_SPEC = 0x8B87,
-
- // The CSS Shaders spec is a subset of the WebGL spec.
- //
- // In both CSS vertex and fragment shaders, ANGLE:
- // (1) Reserves the "css_" prefix.
- // (2) Renames the main function to css_main.
- // (3) Disables the gl_MaxDrawBuffers built-in.
- //
- // In CSS fragment shaders, ANGLE:
- // (1) Disables the gl_FragColor built-in.
- // (2) Disables the gl_FragData built-in.
- // (3) Enables the css_MixColor built-in.
- // (4) Enables the css_ColorMatrix built-in.
- //
- // After passing a CSS shader through ANGLE, the browser is expected to append
- // a new main function to it.
- // This new main function will call the css_main function.
- // It may also perform additional operations like varying assignment, texture
- // access, and gl_FragColor assignment in order to implement the CSS Shaders
- // blend modes.
- //
- SH_CSS_SHADERS_SPEC = 0x8B42
-} ShShaderSpec;
-
-typedef enum {
- SH_ESSL_OUTPUT = 0x8B45,
- SH_GLSL_OUTPUT = 0x8B46,
- SH_HLSL_OUTPUT = 0x8B47,
- SH_HLSL9_OUTPUT = 0x8B47,
- SH_HLSL11_OUTPUT = 0x8B48
-} ShShaderOutput;
-
-// Compile options.
-typedef enum {
- SH_VALIDATE = 0,
- SH_VALIDATE_LOOP_INDEXING = 0x0001,
- SH_INTERMEDIATE_TREE = 0x0002,
- SH_OBJECT_CODE = 0x0004,
- SH_VARIABLES = 0x0008,
- SH_LINE_DIRECTIVES = 0x0010,
- SH_SOURCE_PATH = 0x0020,
- SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX = 0x0040,
- // If a sampler array index happens to be a loop index,
- // 1) if its type is integer, unroll the loop.
- // 2) if its type is float, fail the shader compile.
- // This is to work around a mac driver bug.
- SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX = 0x0080,
-
- // This is needed only as a workaround for certain OpenGL driver bugs.
- SH_EMULATE_BUILT_IN_FUNCTIONS = 0x0100,
-
- // This is an experimental flag to enforce restrictions that aim to prevent
- // timing attacks.
- // It generates compilation errors for shaders that could expose sensitive
- // texture information via the timing channel.
- // To use this flag, you must compile the shader under the WebGL spec
- // (using the SH_WEBGL_SPEC flag).
- SH_TIMING_RESTRICTIONS = 0x0200,
-
- // This flag prints the dependency graph that is used to enforce timing
- // restrictions on fragment shaders.
- // This flag only has an effect if all of the following are true:
- // - The shader spec is SH_WEBGL_SPEC.
- // - The compile options contain the SH_TIMING_RESTRICTIONS flag.
- // - The shader type is GL_FRAGMENT_SHADER.
- SH_DEPENDENCY_GRAPH = 0x0400,
-
- // Enforce the GLSL 1.017 Appendix A section 7 packing restrictions.
- // This flag only enforces (and can only enforce) the packing
- // restrictions for uniform variables in both vertex and fragment
- // shaders. ShCheckVariablesWithinPackingLimits() lets embedders
- // enforce the packing restrictions for varying variables during
- // program link time.
- SH_ENFORCE_PACKING_RESTRICTIONS = 0x0800,
-
- // This flag ensures all indirect (expression-based) array indexing
- // is clamped to the bounds of the array. This ensures, for example,
- // that you cannot read off the end of a uniform, whether an array
- // vec234, or mat234 type. The ShArrayIndexClampingStrategy enum,
- // specified in the ShBuiltInResources when constructing the
- // compiler, selects the strategy for the clamping implementation.
- SH_CLAMP_INDIRECT_ARRAY_BOUNDS = 0x1000,
-
- // This flag limits the complexity of an expression.
- SH_LIMIT_EXPRESSION_COMPLEXITY = 0x2000,
-
- // This flag limits the depth of the call stack.
- SH_LIMIT_CALL_STACK_DEPTH = 0x4000,
-
- // This flag initializes gl_Position to vec4(0,0,0,0) at the
- // beginning of the vertex shader's main(), and has no effect in the
- // fragment shader. It is intended as a workaround for drivers which
- // incorrectly fail to link programs if gl_Position is not written.
- SH_INIT_GL_POSITION = 0x8000,
-
- // This flag replaces
- // "a && b" with "a ? b : false",
- // "a || b" with "a ? true : b".
- // This is to work around a MacOSX driver bug that |b| is executed
- // independent of |a|'s value.
- SH_UNFOLD_SHORT_CIRCUIT = 0x10000,
-
- // This flag initializes varyings without static use in vertex shader
- // at the beginning of main(), and has no effects in the fragment shader.
- // It is intended as a workaround for drivers which incorrectly optimize
- // out such varyings and cause a link failure.
- SH_INIT_VARYINGS_WITHOUT_STATIC_USE = 0x20000,
-
- // This flag scalarizes vec/ivec/bvec/mat constructor args.
- // It is intended as a workaround for Linux/Mac driver bugs.
- SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS = 0x40000,
-
- // This flag overwrites a struct name with a unique prefix.
- // It is intended as a workaround for drivers that do not handle
- // struct scopes correctly, including all Mac drivers and Linux AMD.
- SH_REGENERATE_STRUCT_NAMES = 0x80000,
-} ShCompileOptions;
-
-// Defines alternate strategies for implementing array index clamping.
-typedef enum {
- // Use the clamp intrinsic for array index clamping.
- SH_CLAMP_WITH_CLAMP_INTRINSIC = 1,
-
- // Use a user-defined function for array index clamping.
- SH_CLAMP_WITH_USER_DEFINED_INT_CLAMP_FUNCTION
-} ShArrayIndexClampingStrategy;
-
-//
-// Driver must call this first, once, before doing any other
-// compiler operations.
-// If the function succeeds, the return value is true, else false.
-//
-COMPILER_EXPORT bool ShInitialize();
-//
-// Driver should call this at shutdown.
-// If the function succeeds, the return value is true, else false.
-//
-COMPILER_EXPORT bool ShFinalize();
-
-// The 64 bits hash function. The first parameter is the input string; the
-// second parameter is the string length.
-typedef khronos_uint64_t (*ShHashFunction64)(const char*, size_t);
-
-//
-// Implementation dependent built-in resources (constants and extensions).
-// The names for these resources has been obtained by stripping gl_/GL_.
-//
-typedef struct
-{
- // Constants.
- int MaxVertexAttribs;
- int MaxVertexUniformVectors;
- int MaxVaryingVectors;
- int MaxVertexTextureImageUnits;
- int MaxCombinedTextureImageUnits;
- int MaxTextureImageUnits;
- int MaxFragmentUniformVectors;
- int MaxDrawBuffers;
-
- // Extensions.
- // Set to 1 to enable the extension, else 0.
- int OES_standard_derivatives;
- int OES_EGL_image_external;
- int ARB_texture_rectangle;
- int EXT_draw_buffers;
- int EXT_frag_depth;
- int EXT_shader_texture_lod;
-
- // Set to 1 to enable replacing GL_EXT_draw_buffers #extension directives
- // with GL_NV_draw_buffers in ESSL output. This flag can be used to emulate
- // EXT_draw_buffers by using it in combination with GLES3.0 glDrawBuffers
- // function. This applies to Tegra K1 devices.
- int NV_draw_buffers;
-
- // Set to 1 if highp precision is supported in the fragment language.
- // Default is 0.
- int FragmentPrecisionHigh;
-
- // GLSL ES 3.0 constants.
- int MaxVertexOutputVectors;
- int MaxFragmentInputVectors;
- int MinProgramTexelOffset;
- int MaxProgramTexelOffset;
-
- // Name Hashing.
- // Set a 64 bit hash function to enable user-defined name hashing.
- // Default is NULL.
- ShHashFunction64 HashFunction;
-
- // Selects a strategy to use when implementing array index clamping.
- // Default is SH_CLAMP_WITH_CLAMP_INTRINSIC.
- ShArrayIndexClampingStrategy ArrayIndexClampingStrategy;
-
- // The maximum complexity an expression can be.
- int MaxExpressionComplexity;
-
- // The maximum depth a call stack can be.
- int MaxCallStackDepth;
-} ShBuiltInResources;
-
-//
-// Initialize built-in resources with minimum expected values.
-// Parameters:
-// resources: The object to initialize. Will be comparable with memcmp.
-//
-COMPILER_EXPORT void ShInitBuiltInResources(ShBuiltInResources *resources);
-
-//
-// ShHandle held by but opaque to the driver. It is allocated,
-// managed, and de-allocated by the compiler. Its contents
-// are defined by and used by the compiler.
-//
-// If handle creation fails, 0 will be returned.
-//
-typedef void *ShHandle;
-
-//
-// Returns the a concatenated list of the items in ShBuiltInResources as a
-// null-terminated string.
-// This function must be updated whenever ShBuiltInResources is changed.
-// Parameters:
-// handle: Specifies the handle of the compiler to be used.
-COMPILER_EXPORT const std::string &ShGetBuiltInResourcesString(const ShHandle handle);
-
-//
-// Driver calls these to create and destroy compiler objects.
-//
-// Returns the handle of constructed compiler, null if the requested compiler is
-// not supported.
-// Parameters:
-// type: Specifies the type of shader - GL_FRAGMENT_SHADER or GL_VERTEX_SHADER.
-// spec: Specifies the language spec the compiler must conform to -
-// SH_GLES2_SPEC or SH_WEBGL_SPEC.
-// output: Specifies the output code type - SH_ESSL_OUTPUT, SH_GLSL_OUTPUT,
-// SH_HLSL9_OUTPUT or SH_HLSL11_OUTPUT.
-// resources: Specifies the built-in resources.
-COMPILER_EXPORT ShHandle ShConstructCompiler(
- sh::GLenum type,
- ShShaderSpec spec,
- ShShaderOutput output,
- const ShBuiltInResources *resources);
-COMPILER_EXPORT void ShDestruct(ShHandle handle);
-
-//
-// Compiles the given shader source.
-// If the function succeeds, the return value is true, else false.
-// Parameters:
-// handle: Specifies the handle of compiler to be used.
-// shaderStrings: Specifies an array of pointers to null-terminated strings
-// containing the shader source code.
-// numStrings: Specifies the number of elements in shaderStrings array.
-// compileOptions: A mask containing the following parameters:
-// SH_VALIDATE: Validates shader to ensure that it conforms to the spec
-// specified during compiler construction.
-// SH_VALIDATE_LOOP_INDEXING: Validates loop and indexing in the shader to
-// ensure that they do not exceed the minimum
-// functionality mandated in GLSL 1.0 spec,
-// Appendix A, Section 4 and 5.
-// There is no need to specify this parameter when
-// compiling for WebGL - it is implied.
-// SH_INTERMEDIATE_TREE: Writes intermediate tree to info log.
-// Can be queried by calling ShGetInfoLog().
-// SH_OBJECT_CODE: Translates intermediate tree to glsl or hlsl shader.
-// Can be queried by calling ShGetObjectCode().
-// SH_VARIABLES: Extracts attributes, uniforms, and varyings.
-// Can be queried by calling ShGetVariableInfo().
-//
-COMPILER_EXPORT bool ShCompile(
- const ShHandle handle,
- const char * const shaderStrings[],
- size_t numStrings,
- int compileOptions);
-
-// Return the version of the shader language.
-COMPILER_EXPORT int ShGetShaderVersion(const ShHandle handle);
-
-// Return the currently set language output type.
-COMPILER_EXPORT ShShaderOutput ShGetShaderOutputType(
- const ShHandle handle);
-
-// Returns null-terminated information log for a compiled shader.
-// Parameters:
-// handle: Specifies the compiler
-COMPILER_EXPORT const std::string &ShGetInfoLog(const ShHandle handle);
-
-// Returns null-terminated object code for a compiled shader.
-// Parameters:
-// handle: Specifies the compiler
-COMPILER_EXPORT const std::string &ShGetObjectCode(const ShHandle handle);
-
-// Returns a (original_name, hash) map containing all the user defined
-// names in the shader, including variable names, function names, struct
-// names, and struct field names.
-// Parameters:
-// handle: Specifies the compiler
-COMPILER_EXPORT const std::map<std::string, std::string> *ShGetNameHashingMap(
- const ShHandle handle);
-
-// Shader variable inspection.
-// Returns a pointer to a list of variables of the designated type.
-// (See ShaderVars.h for type definitions, included above)
-// Returns NULL on failure.
-// Parameters:
-// handle: Specifies the compiler
-COMPILER_EXPORT const std::vector<sh::Uniform> *ShGetUniforms(const ShHandle handle);
-COMPILER_EXPORT const std::vector<sh::Varying> *ShGetVaryings(const ShHandle handle);
-COMPILER_EXPORT const std::vector<sh::Attribute> *ShGetAttributes(const ShHandle handle);
-COMPILER_EXPORT const std::vector<sh::Attribute> *ShGetOutputVariables(const ShHandle handle);
-COMPILER_EXPORT const std::vector<sh::InterfaceBlock> *ShGetInterfaceBlocks(const ShHandle handle);
-
-typedef struct
-{
- sh::GLenum type;
- int size;
-} ShVariableInfo;
-
-// Returns true if the passed in variables pack in maxVectors following
-// the packing rules from the GLSL 1.017 spec, Appendix A, section 7.
-// Returns false otherwise. Also look at the SH_ENFORCE_PACKING_RESTRICTIONS
-// flag above.
-// Parameters:
-// maxVectors: the available rows of registers.
-// varInfoArray: an array of variable info (types and sizes).
-// varInfoArraySize: the size of the variable array.
-COMPILER_EXPORT bool ShCheckVariablesWithinPackingLimits(
- int maxVectors,
- ShVariableInfo *varInfoArray,
- size_t varInfoArraySize);
-
-// Gives the compiler-assigned register for an interface block.
-// The method writes the value to the output variable "indexOut".
-// Returns true if it found a valid interface block, false otherwise.
-// Parameters:
-// handle: Specifies the compiler
-// interfaceBlockName: Specifies the interface block
-// indexOut: output variable that stores the assigned register
-COMPILER_EXPORT bool ShGetInterfaceBlockRegister(const ShHandle handle,
- const std::string &interfaceBlockName,
- unsigned int *indexOut);
-
-// Gives the compiler-assigned register for uniforms in the default
-// interface block.
-// The method writes the value to the output variable "indexOut".
-// Returns true if it found a valid default uniform, false otherwise.
-// Parameters:
-// handle: Specifies the compiler
-// interfaceBlockName: Specifies the uniform
-// indexOut: output variable that stores the assigned register
-COMPILER_EXPORT bool ShGetUniformRegister(const ShHandle handle,
- const std::string &uniformName,
- unsigned int *indexOut);
-
-#endif // _COMPILER_INTERFACE_INCLUDED_
+//
+// Copyright (c) 2002-2013 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+#ifndef _COMPILER_INTERFACE_INCLUDED_
+#define _COMPILER_INTERFACE_INCLUDED_
+
+#if defined(COMPONENT_BUILD) && !defined(ANGLE_TRANSLATOR_STATIC)
+#if defined(_WIN32) || defined(_WIN64)
+
+#if defined(ANGLE_TRANSLATOR_IMPLEMENTATION)
+#define COMPILER_EXPORT __declspec(dllexport)
+#else
+#define COMPILER_EXPORT __declspec(dllimport)
+#endif // defined(ANGLE_TRANSLATOR_IMPLEMENTATION)
+
+#else // defined(_WIN32) || defined(_WIN64)
+#define COMPILER_EXPORT __attribute__((visibility("default")))
+#endif
+
+#else // defined(COMPONENT_BUILD) && !defined(ANGLE_TRANSLATOR_STATIC)
+#define COMPILER_EXPORT
+#endif
+
+#include <stddef.h>
+
+#include "KHR/khrplatform.h"
+
+#include <map>
+#include <string>
+#include <vector>
+
+//
+// This is the platform independent interface between an OGL driver
+// and the shading language compiler.
+//
+
+namespace sh
+{
+// GLenum alias
+typedef unsigned int GLenum;
+}
+
+// Must be included after GLenum proxy typedef
+// Note: make sure to increment ANGLE_SH_VERSION when changing ShaderVars.h
+#include "ShaderVars.h"
+
+// Version number for shader translation API.
+// It is incremented every time the API changes.
+#define ANGLE_SH_VERSION 132
+
+typedef enum {
+ SH_GLES2_SPEC = 0x8B40,
+ SH_WEBGL_SPEC = 0x8B41,
+
+ SH_GLES3_SPEC = 0x8B86,
+ SH_WEBGL2_SPEC = 0x8B87,
+
+ // The CSS Shaders spec is a subset of the WebGL spec.
+ //
+ // In both CSS vertex and fragment shaders, ANGLE:
+ // (1) Reserves the "css_" prefix.
+ // (2) Renames the main function to css_main.
+ // (3) Disables the gl_MaxDrawBuffers built-in.
+ //
+ // In CSS fragment shaders, ANGLE:
+ // (1) Disables the gl_FragColor built-in.
+ // (2) Disables the gl_FragData built-in.
+ // (3) Enables the css_MixColor built-in.
+ // (4) Enables the css_ColorMatrix built-in.
+ //
+ // After passing a CSS shader through ANGLE, the browser is expected to append
+ // a new main function to it.
+ // This new main function will call the css_main function.
+ // It may also perform additional operations like varying assignment, texture
+ // access, and gl_FragColor assignment in order to implement the CSS Shaders
+ // blend modes.
+ //
+ SH_CSS_SHADERS_SPEC = 0x8B42
+} ShShaderSpec;
+
+typedef enum {
+ SH_ESSL_OUTPUT = 0x8B45,
+ SH_GLSL_OUTPUT = 0x8B46,
+ SH_HLSL_OUTPUT = 0x8B47,
+ SH_HLSL9_OUTPUT = 0x8B47,
+ SH_HLSL11_OUTPUT = 0x8B48
+} ShShaderOutput;
+
+// Compile options.
+typedef enum {
+ SH_VALIDATE = 0,
+ SH_VALIDATE_LOOP_INDEXING = 0x0001,
+ SH_INTERMEDIATE_TREE = 0x0002,
+ SH_OBJECT_CODE = 0x0004,
+ SH_VARIABLES = 0x0008,
+ SH_LINE_DIRECTIVES = 0x0010,
+ SH_SOURCE_PATH = 0x0020,
+ SH_UNROLL_FOR_LOOP_WITH_INTEGER_INDEX = 0x0040,
+ // If a sampler array index happens to be a loop index,
+ // 1) if its type is integer, unroll the loop.
+ // 2) if its type is float, fail the shader compile.
+ // This is to work around a mac driver bug.
+ SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX = 0x0080,
+
+ // This is needed only as a workaround for certain OpenGL driver bugs.
+ SH_EMULATE_BUILT_IN_FUNCTIONS = 0x0100,
+
+ // This is an experimental flag to enforce restrictions that aim to prevent
+ // timing attacks.
+ // It generates compilation errors for shaders that could expose sensitive
+ // texture information via the timing channel.
+ // To use this flag, you must compile the shader under the WebGL spec
+ // (using the SH_WEBGL_SPEC flag).
+ SH_TIMING_RESTRICTIONS = 0x0200,
+
+ // This flag prints the dependency graph that is used to enforce timing
+ // restrictions on fragment shaders.
+ // This flag only has an effect if all of the following are true:
+ // - The shader spec is SH_WEBGL_SPEC.
+ // - The compile options contain the SH_TIMING_RESTRICTIONS flag.
+ // - The shader type is GL_FRAGMENT_SHADER.
+ SH_DEPENDENCY_GRAPH = 0x0400,
+
+ // Enforce the GLSL 1.017 Appendix A section 7 packing restrictions.
+ // This flag only enforces (and can only enforce) the packing
+ // restrictions for uniform variables in both vertex and fragment
+ // shaders. ShCheckVariablesWithinPackingLimits() lets embedders
+ // enforce the packing restrictions for varying variables during
+ // program link time.
+ SH_ENFORCE_PACKING_RESTRICTIONS = 0x0800,
+
+ // This flag ensures all indirect (expression-based) array indexing
+ // is clamped to the bounds of the array. This ensures, for example,
+ // that you cannot read off the end of a uniform, whether an array
+ // vec234, or mat234 type. The ShArrayIndexClampingStrategy enum,
+ // specified in the ShBuiltInResources when constructing the
+ // compiler, selects the strategy for the clamping implementation.
+ SH_CLAMP_INDIRECT_ARRAY_BOUNDS = 0x1000,
+
+ // This flag limits the complexity of an expression.
+ SH_LIMIT_EXPRESSION_COMPLEXITY = 0x2000,
+
+ // This flag limits the depth of the call stack.
+ SH_LIMIT_CALL_STACK_DEPTH = 0x4000,
+
+ // This flag initializes gl_Position to vec4(0,0,0,0) at the
+ // beginning of the vertex shader's main(), and has no effect in the
+ // fragment shader. It is intended as a workaround for drivers which
+ // incorrectly fail to link programs if gl_Position is not written.
+ SH_INIT_GL_POSITION = 0x8000,
+
+ // This flag replaces
+ // "a && b" with "a ? b : false",
+ // "a || b" with "a ? true : b".
+ // This is to work around a MacOSX driver bug that |b| is executed
+ // independent of |a|'s value.
+ SH_UNFOLD_SHORT_CIRCUIT = 0x10000,
+
+ // This flag initializes varyings without static use in vertex shader
+ // at the beginning of main(), and has no effects in the fragment shader.
+ // It is intended as a workaround for drivers which incorrectly optimize
+ // out such varyings and cause a link failure.
+ SH_INIT_VARYINGS_WITHOUT_STATIC_USE = 0x20000,
+
+ // This flag scalarizes vec/ivec/bvec/mat constructor args.
+ // It is intended as a workaround for Linux/Mac driver bugs.
+ SH_SCALARIZE_VEC_AND_MAT_CONSTRUCTOR_ARGS = 0x40000,
+
+ // This flag overwrites a struct name with a unique prefix.
+ // It is intended as a workaround for drivers that do not handle
+ // struct scopes correctly, including all Mac drivers and Linux AMD.
+ SH_REGENERATE_STRUCT_NAMES = 0x80000,
+} ShCompileOptions;
+
+// Defines alternate strategies for implementing array index clamping.
+typedef enum {
+ // Use the clamp intrinsic for array index clamping.
+ SH_CLAMP_WITH_CLAMP_INTRINSIC = 1,
+
+ // Use a user-defined function for array index clamping.
+ SH_CLAMP_WITH_USER_DEFINED_INT_CLAMP_FUNCTION
+} ShArrayIndexClampingStrategy;
+
+//
+// Driver must call this first, once, before doing any other
+// compiler operations.
+// If the function succeeds, the return value is true, else false.
+//
+COMPILER_EXPORT bool ShInitialize();
+//
+// Driver should call this at shutdown.
+// If the function succeeds, the return value is true, else false.
+//
+COMPILER_EXPORT bool ShFinalize();
+
+// The 64 bits hash function. The first parameter is the input string; the
+// second parameter is the string length.
+typedef khronos_uint64_t (*ShHashFunction64)(const char*, size_t);
+
+//
+// Implementation dependent built-in resources (constants and extensions).
+// The names for these resources has been obtained by stripping gl_/GL_.
+//
+typedef struct
+{
+ // Constants.
+ int MaxVertexAttribs;
+ int MaxVertexUniformVectors;
+ int MaxVaryingVectors;
+ int MaxVertexTextureImageUnits;
+ int MaxCombinedTextureImageUnits;
+ int MaxTextureImageUnits;
+ int MaxFragmentUniformVectors;
+ int MaxDrawBuffers;
+
+ // Extensions.
+ // Set to 1 to enable the extension, else 0.
+ int OES_standard_derivatives;
+ int OES_EGL_image_external;
+ int ARB_texture_rectangle;
+ int EXT_draw_buffers;
+ int EXT_frag_depth;
+ int EXT_shader_texture_lod;
+
+ // Set to 1 to enable replacing GL_EXT_draw_buffers #extension directives
+ // with GL_NV_draw_buffers in ESSL output. This flag can be used to emulate
+ // EXT_draw_buffers by using it in combination with GLES3.0 glDrawBuffers
+ // function. This applies to Tegra K1 devices.
+ int NV_draw_buffers;
+
+ // Set to 1 if highp precision is supported in the fragment language.
+ // Default is 0.
+ int FragmentPrecisionHigh;
+
+ // GLSL ES 3.0 constants.
+ int MaxVertexOutputVectors;
+ int MaxFragmentInputVectors;
+ int MinProgramTexelOffset;
+ int MaxProgramTexelOffset;
+
+ // Name Hashing.
+ // Set a 64 bit hash function to enable user-defined name hashing.
+ // Default is NULL.
+ ShHashFunction64 HashFunction;
+
+ // Selects a strategy to use when implementing array index clamping.
+ // Default is SH_CLAMP_WITH_CLAMP_INTRINSIC.
+ ShArrayIndexClampingStrategy ArrayIndexClampingStrategy;
+
+ // The maximum complexity an expression can be.
+ int MaxExpressionComplexity;
+
+ // The maximum depth a call stack can be.
+ int MaxCallStackDepth;
+} ShBuiltInResources;
+
+//
+// Initialize built-in resources with minimum expected values.
+// Parameters:
+// resources: The object to initialize. Will be comparable with memcmp.
+//
+COMPILER_EXPORT void ShInitBuiltInResources(ShBuiltInResources *resources);
+
+//
+// ShHandle held by but opaque to the driver. It is allocated,
+// managed, and de-allocated by the compiler. Its contents
+// are defined by and used by the compiler.
+//
+// If handle creation fails, 0 will be returned.
+//
+typedef void *ShHandle;
+
+//
+// Returns the a concatenated list of the items in ShBuiltInResources as a
+// null-terminated string.
+// This function must be updated whenever ShBuiltInResources is changed.
+// Parameters:
+// handle: Specifies the handle of the compiler to be used.
+COMPILER_EXPORT const std::string &ShGetBuiltInResourcesString(const ShHandle handle);
+
+//
+// Driver calls these to create and destroy compiler objects.
+//
+// Returns the handle of constructed compiler, null if the requested compiler is
+// not supported.
+// Parameters:
+// type: Specifies the type of shader - GL_FRAGMENT_SHADER or GL_VERTEX_SHADER.
+// spec: Specifies the language spec the compiler must conform to -
+// SH_GLES2_SPEC or SH_WEBGL_SPEC.
+// output: Specifies the output code type - SH_ESSL_OUTPUT, SH_GLSL_OUTPUT,
+// SH_HLSL9_OUTPUT or SH_HLSL11_OUTPUT.
+// resources: Specifies the built-in resources.
+COMPILER_EXPORT ShHandle ShConstructCompiler(
+ sh::GLenum type,
+ ShShaderSpec spec,
+ ShShaderOutput output,
+ const ShBuiltInResources *resources);
+COMPILER_EXPORT void ShDestruct(ShHandle handle);
+
+//
+// Compiles the given shader source.
+// If the function succeeds, the return value is true, else false.
+// Parameters:
+// handle: Specifies the handle of compiler to be used.
+// shaderStrings: Specifies an array of pointers to null-terminated strings
+// containing the shader source code.
+// numStrings: Specifies the number of elements in shaderStrings array.
+// compileOptions: A mask containing the following parameters:
+// SH_VALIDATE: Validates shader to ensure that it conforms to the spec
+// specified during compiler construction.
+// SH_VALIDATE_LOOP_INDEXING: Validates loop and indexing in the shader to
+// ensure that they do not exceed the minimum
+// functionality mandated in GLSL 1.0 spec,
+// Appendix A, Section 4 and 5.
+// There is no need to specify this parameter when
+// compiling for WebGL - it is implied.
+// SH_INTERMEDIATE_TREE: Writes intermediate tree to info log.
+// Can be queried by calling ShGetInfoLog().
+// SH_OBJECT_CODE: Translates intermediate tree to glsl or hlsl shader.
+// Can be queried by calling ShGetObjectCode().
+// SH_VARIABLES: Extracts attributes, uniforms, and varyings.
+// Can be queried by calling ShGetVariableInfo().
+//
+COMPILER_EXPORT bool ShCompile(
+ const ShHandle handle,
+ const char * const shaderStrings[],
+ size_t numStrings,
+ int compileOptions);
+
+// Return the version of the shader language.
+COMPILER_EXPORT int ShGetShaderVersion(const ShHandle handle);
+
+// Return the currently set language output type.
+COMPILER_EXPORT ShShaderOutput ShGetShaderOutputType(
+ const ShHandle handle);
+
+// Returns null-terminated information log for a compiled shader.
+// Parameters:
+// handle: Specifies the compiler
+COMPILER_EXPORT const std::string &ShGetInfoLog(const ShHandle handle);
+
+// Returns null-terminated object code for a compiled shader.
+// Parameters:
+// handle: Specifies the compiler
+COMPILER_EXPORT const std::string &ShGetObjectCode(const ShHandle handle);
+
+// Returns a (original_name, hash) map containing all the user defined
+// names in the shader, including variable names, function names, struct
+// names, and struct field names.
+// Parameters:
+// handle: Specifies the compiler
+COMPILER_EXPORT const std::map<std::string, std::string> *ShGetNameHashingMap(
+ const ShHandle handle);
+
+// Shader variable inspection.
+// Returns a pointer to a list of variables of the designated type.
+// (See ShaderVars.h for type definitions, included above)
+// Returns NULL on failure.
+// Parameters:
+// handle: Specifies the compiler
+COMPILER_EXPORT const std::vector<sh::Uniform> *ShGetUniforms(const ShHandle handle);
+COMPILER_EXPORT const std::vector<sh::Varying> *ShGetVaryings(const ShHandle handle);
+COMPILER_EXPORT const std::vector<sh::Attribute> *ShGetAttributes(const ShHandle handle);
+COMPILER_EXPORT const std::vector<sh::Attribute> *ShGetOutputVariables(const ShHandle handle);
+COMPILER_EXPORT const std::vector<sh::InterfaceBlock> *ShGetInterfaceBlocks(const ShHandle handle);
+
+typedef struct
+{
+ sh::GLenum type;
+ int size;
+} ShVariableInfo;
+
+// Returns true if the passed in variables pack in maxVectors following
+// the packing rules from the GLSL 1.017 spec, Appendix A, section 7.
+// Returns false otherwise. Also look at the SH_ENFORCE_PACKING_RESTRICTIONS
+// flag above.
+// Parameters:
+// maxVectors: the available rows of registers.
+// varInfoArray: an array of variable info (types and sizes).
+// varInfoArraySize: the size of the variable array.
+COMPILER_EXPORT bool ShCheckVariablesWithinPackingLimits(
+ int maxVectors,
+ ShVariableInfo *varInfoArray,
+ size_t varInfoArraySize);
+
+// Gives the compiler-assigned register for an interface block.
+// The method writes the value to the output variable "indexOut".
+// Returns true if it found a valid interface block, false otherwise.
+// Parameters:
+// handle: Specifies the compiler
+// interfaceBlockName: Specifies the interface block
+// indexOut: output variable that stores the assigned register
+COMPILER_EXPORT bool ShGetInterfaceBlockRegister(const ShHandle handle,
+ const std::string &interfaceBlockName,
+ unsigned int *indexOut);
+
+// Gives the compiler-assigned register for uniforms in the default
+// interface block.
+// The method writes the value to the output variable "indexOut".
+// Returns true if it found a valid default uniform, false otherwise.
+// Parameters:
+// handle: Specifies the compiler
+// interfaceBlockName: Specifies the uniform
+// indexOut: output variable that stores the assigned register
+COMPILER_EXPORT bool ShGetUniformRegister(const ShHandle handle,
+ const std::string &uniformName,
+ unsigned int *indexOut);
+
+#endif // _COMPILER_INTERFACE_INCLUDED_
diff --git a/platform/winrt/include/GLSLANG/ShaderVars.h b/platform/winrt/include/GLSLANG/ShaderVars.h
index dc452b0cf4..da21c3e76e 100644
--- a/platform/winrt/include/GLSLANG/ShaderVars.h
+++ b/platform/winrt/include/GLSLANG/ShaderVars.h
@@ -1,185 +1,185 @@
-//
-// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// ShaderVars.h:
-// Types to represent GL variables (varyings, uniforms, etc)
-//
-
-#ifndef _COMPILER_INTERFACE_VARIABLES_
-#define _COMPILER_INTERFACE_VARIABLES_
-
-#include <string>
-#include <vector>
-#include <algorithm>
-
-// Assume ShaderLang.h is included before ShaderVars.h, for sh::GLenum
-// Note: make sure to increment ANGLE_SH_VERSION when changing ShaderVars.h
-
-namespace sh
-{
-
-// Varying interpolation qualifier, see section 4.3.9 of the ESSL 3.00.4 spec
-enum InterpolationType
-{
- INTERPOLATION_SMOOTH,
- INTERPOLATION_CENTROID,
- INTERPOLATION_FLAT
-};
-
-// Uniform block layout qualifier, see section 4.3.8.3 of the ESSL 3.00.4 spec
-enum BlockLayoutType
-{
- BLOCKLAYOUT_STANDARD,
- BLOCKLAYOUT_PACKED,
- BLOCKLAYOUT_SHARED
-};
-
-// Base class for all variables defined in shaders, including Varyings, Uniforms, etc
-// Note: we must override the copy constructor and assignment operator so we can
-// work around excessive GCC binary bloating:
-// See https://code.google.com/p/angleproject/issues/detail?id=697
-struct COMPILER_EXPORT ShaderVariable
-{
- ShaderVariable();
- ShaderVariable(GLenum typeIn, unsigned int arraySizeIn);
- ~ShaderVariable();
- ShaderVariable(const ShaderVariable &other);
- ShaderVariable &operator=(const ShaderVariable &other);
-
- bool isArray() const { return arraySize > 0; }
- unsigned int elementCount() const { return std::max(1u, arraySize); }
- bool isStruct() const { return !fields.empty(); }
-
- // All of the shader's variables are described using nested data
- // structures. This is needed in order to disambiguate similar looking
- // types, such as two structs containing the same fields, but in
- // different orders. "findInfoByMappedName" provides an easy query for
- // users to dive into the data structure and fetch the unique variable
- // instance corresponding to a dereferencing chain of the top-level
- // variable.
- // Given a mapped name like 'a[0].b.c[0]', return the ShaderVariable
- // that defines 'c' in |leafVar|, and the original name 'A[0].B.C[0]'
- // in |originalName|, based on the assumption that |this| defines 'a'.
- // If no match is found, return false.
- bool findInfoByMappedName(const std::string &mappedFullName,
- const ShaderVariable **leafVar,
- std::string* originalFullName) const;
-
- GLenum type;
- GLenum precision;
- std::string name;
- std::string mappedName;
- unsigned int arraySize;
- bool staticUse;
- std::vector<ShaderVariable> fields;
- std::string structName;
-
- protected:
- bool isSameVariableAtLinkTime(const ShaderVariable &other,
- bool matchPrecision) const;
-
- bool operator==(const ShaderVariable &other) const;
- bool operator!=(const ShaderVariable &other) const
- {
- return !operator==(other);
- }
-};
-
-struct COMPILER_EXPORT Uniform : public ShaderVariable
-{
- Uniform();
- ~Uniform();
- Uniform(const Uniform &other);
- Uniform &operator=(const Uniform &other);
- bool operator==(const Uniform &other) const;
- bool operator!=(const Uniform &other) const
- {
- return !operator==(other);
- }
-
- // Decide whether two uniforms are the same at shader link time,
- // assuming one from vertex shader and the other from fragment shader.
- // See GLSL ES Spec 3.00.3, sec 4.3.5.
- bool isSameUniformAtLinkTime(const Uniform &other) const;
-};
-
-struct COMPILER_EXPORT Attribute : public ShaderVariable
-{
- Attribute();
- ~Attribute();
- Attribute(const Attribute &other);
- Attribute &operator=(const Attribute &other);
- bool operator==(const Attribute &other) const;
- bool operator!=(const Attribute &other) const
- {
- return !operator==(other);
- }
-
- int location;
-};
-
-struct COMPILER_EXPORT InterfaceBlockField : public ShaderVariable
-{
- InterfaceBlockField();
- ~InterfaceBlockField();
- InterfaceBlockField(const InterfaceBlockField &other);
- InterfaceBlockField &operator=(const InterfaceBlockField &other);
- bool operator==(const InterfaceBlockField &other) const;
- bool operator!=(const InterfaceBlockField &other) const
- {
- return !operator==(other);
- }
-
- // Decide whether two InterfaceBlock fields are the same at shader
- // link time, assuming one from vertex shader and the other from
- // fragment shader.
- // See GLSL ES Spec 3.00.3, sec 4.3.7.
- bool isSameInterfaceBlockFieldAtLinkTime(
- const InterfaceBlockField &other) const;
-
- bool isRowMajorLayout;
-};
-
-struct COMPILER_EXPORT Varying : public ShaderVariable
-{
- Varying();
- ~Varying();
- Varying(const Varying &otherg);
- Varying &operator=(const Varying &other);
- bool operator==(const Varying &other) const;
- bool operator!=(const Varying &other) const
- {
- return !operator==(other);
- }
-
- // Decide whether two varyings are the same at shader link time,
- // assuming one from vertex shader and the other from fragment shader.
- // See GLSL ES Spec 3.00.3, sec 4.3.9.
- bool isSameVaryingAtLinkTime(const Varying &other) const;
-
- InterpolationType interpolation;
- bool isInvariant;
-};
-
-struct COMPILER_EXPORT InterfaceBlock
-{
- InterfaceBlock();
- ~InterfaceBlock();
- InterfaceBlock(const InterfaceBlock &other);
- InterfaceBlock &operator=(const InterfaceBlock &other);
-
- std::string name;
- std::string mappedName;
- std::string instanceName;
- unsigned int arraySize;
- BlockLayoutType layout;
- bool isRowMajorLayout;
- bool staticUse;
- std::vector<InterfaceBlockField> fields;
-};
-
-}
-
-#endif // _COMPILER_INTERFACE_VARIABLES_
+//
+// Copyright (c) 2013-2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// ShaderVars.h:
+// Types to represent GL variables (varyings, uniforms, etc)
+//
+
+#ifndef _COMPILER_INTERFACE_VARIABLES_
+#define _COMPILER_INTERFACE_VARIABLES_
+
+#include <string>
+#include <vector>
+#include <algorithm>
+
+// Assume ShaderLang.h is included before ShaderVars.h, for sh::GLenum
+// Note: make sure to increment ANGLE_SH_VERSION when changing ShaderVars.h
+
+namespace sh
+{
+
+// Varying interpolation qualifier, see section 4.3.9 of the ESSL 3.00.4 spec
+enum InterpolationType
+{
+ INTERPOLATION_SMOOTH,
+ INTERPOLATION_CENTROID,
+ INTERPOLATION_FLAT
+};
+
+// Uniform block layout qualifier, see section 4.3.8.3 of the ESSL 3.00.4 spec
+enum BlockLayoutType
+{
+ BLOCKLAYOUT_STANDARD,
+ BLOCKLAYOUT_PACKED,
+ BLOCKLAYOUT_SHARED
+};
+
+// Base class for all variables defined in shaders, including Varyings, Uniforms, etc
+// Note: we must override the copy constructor and assignment operator so we can
+// work around excessive GCC binary bloating:
+// See https://code.google.com/p/angleproject/issues/detail?id=697
+struct COMPILER_EXPORT ShaderVariable
+{
+ ShaderVariable();
+ ShaderVariable(GLenum typeIn, unsigned int arraySizeIn);
+ ~ShaderVariable();
+ ShaderVariable(const ShaderVariable &other);
+ ShaderVariable &operator=(const ShaderVariable &other);
+
+ bool isArray() const { return arraySize > 0; }
+ unsigned int elementCount() const { return std::max(1u, arraySize); }
+ bool isStruct() const { return !fields.empty(); }
+
+ // All of the shader's variables are described using nested data
+ // structures. This is needed in order to disambiguate similar looking
+ // types, such as two structs containing the same fields, but in
+ // different orders. "findInfoByMappedName" provides an easy query for
+ // users to dive into the data structure and fetch the unique variable
+ // instance corresponding to a dereferencing chain of the top-level
+ // variable.
+ // Given a mapped name like 'a[0].b.c[0]', return the ShaderVariable
+ // that defines 'c' in |leafVar|, and the original name 'A[0].B.C[0]'
+ // in |originalName|, based on the assumption that |this| defines 'a'.
+ // If no match is found, return false.
+ bool findInfoByMappedName(const std::string &mappedFullName,
+ const ShaderVariable **leafVar,
+ std::string* originalFullName) const;
+
+ GLenum type;
+ GLenum precision;
+ std::string name;
+ std::string mappedName;
+ unsigned int arraySize;
+ bool staticUse;
+ std::vector<ShaderVariable> fields;
+ std::string structName;
+
+ protected:
+ bool isSameVariableAtLinkTime(const ShaderVariable &other,
+ bool matchPrecision) const;
+
+ bool operator==(const ShaderVariable &other) const;
+ bool operator!=(const ShaderVariable &other) const
+ {
+ return !operator==(other);
+ }
+};
+
+struct COMPILER_EXPORT Uniform : public ShaderVariable
+{
+ Uniform();
+ ~Uniform();
+ Uniform(const Uniform &other);
+ Uniform &operator=(const Uniform &other);
+ bool operator==(const Uniform &other) const;
+ bool operator!=(const Uniform &other) const
+ {
+ return !operator==(other);
+ }
+
+ // Decide whether two uniforms are the same at shader link time,
+ // assuming one from vertex shader and the other from fragment shader.
+ // See GLSL ES Spec 3.00.3, sec 4.3.5.
+ bool isSameUniformAtLinkTime(const Uniform &other) const;
+};
+
+struct COMPILER_EXPORT Attribute : public ShaderVariable
+{
+ Attribute();
+ ~Attribute();
+ Attribute(const Attribute &other);
+ Attribute &operator=(const Attribute &other);
+ bool operator==(const Attribute &other) const;
+ bool operator!=(const Attribute &other) const
+ {
+ return !operator==(other);
+ }
+
+ int location;
+};
+
+struct COMPILER_EXPORT InterfaceBlockField : public ShaderVariable
+{
+ InterfaceBlockField();
+ ~InterfaceBlockField();
+ InterfaceBlockField(const InterfaceBlockField &other);
+ InterfaceBlockField &operator=(const InterfaceBlockField &other);
+ bool operator==(const InterfaceBlockField &other) const;
+ bool operator!=(const InterfaceBlockField &other) const
+ {
+ return !operator==(other);
+ }
+
+ // Decide whether two InterfaceBlock fields are the same at shader
+ // link time, assuming one from vertex shader and the other from
+ // fragment shader.
+ // See GLSL ES Spec 3.00.3, sec 4.3.7.
+ bool isSameInterfaceBlockFieldAtLinkTime(
+ const InterfaceBlockField &other) const;
+
+ bool isRowMajorLayout;
+};
+
+struct COMPILER_EXPORT Varying : public ShaderVariable
+{
+ Varying();
+ ~Varying();
+ Varying(const Varying &otherg);
+ Varying &operator=(const Varying &other);
+ bool operator==(const Varying &other) const;
+ bool operator!=(const Varying &other) const
+ {
+ return !operator==(other);
+ }
+
+ // Decide whether two varyings are the same at shader link time,
+ // assuming one from vertex shader and the other from fragment shader.
+ // See GLSL ES Spec 3.00.3, sec 4.3.9.
+ bool isSameVaryingAtLinkTime(const Varying &other) const;
+
+ InterpolationType interpolation;
+ bool isInvariant;
+};
+
+struct COMPILER_EXPORT InterfaceBlock
+{
+ InterfaceBlock();
+ ~InterfaceBlock();
+ InterfaceBlock(const InterfaceBlock &other);
+ InterfaceBlock &operator=(const InterfaceBlock &other);
+
+ std::string name;
+ std::string mappedName;
+ std::string instanceName;
+ unsigned int arraySize;
+ BlockLayoutType layout;
+ bool isRowMajorLayout;
+ bool staticUse;
+ std::vector<InterfaceBlockField> fields;
+};
+
+}
+
+#endif // _COMPILER_INTERFACE_VARIABLES_
diff --git a/platform/winrt/include/KHR/khrplatform.h b/platform/winrt/include/KHR/khrplatform.h
index 0921b895a5..c9e6f17d34 100644
--- a/platform/winrt/include/KHR/khrplatform.h
+++ b/platform/winrt/include/KHR/khrplatform.h
@@ -1,282 +1,282 @@
-#ifndef __khrplatform_h_
-#define __khrplatform_h_
-
-/*
-** Copyright (c) 2008-2009 The Khronos Group Inc.
-**
-** Permission is hereby granted, free of charge, to any person obtaining a
-** copy of this software and/or associated documentation files (the
-** "Materials"), to deal in the Materials without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Materials, and to
-** permit persons to whom the Materials are 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 Materials.
-**
-** THE MATERIALS ARE 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
-** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-*/
-
-/* Khronos platform-specific types and definitions.
- *
- * $Revision: 23298 $ on $Date: 2013-09-30 17:07:13 -0700 (Mon, 30 Sep 2013) $
- *
- * Adopters may modify this file to suit their platform. Adopters are
- * encouraged to submit platform specific modifications to the Khronos
- * group so that they can be included in future versions of this file.
- * Please submit changes by sending them to the public Khronos Bugzilla
- * (http://khronos.org/bugzilla) by filing a bug against product
- * "Khronos (general)" component "Registry".
- *
- * A predefined template which fills in some of the bug fields can be
- * reached using http://tinyurl.com/khrplatform-h-bugreport, but you
- * must create a Bugzilla login first.
- *
- *
- * See the Implementer's Guidelines for information about where this file
- * should be located on your system and for more details of its use:
- * http://www.khronos.org/registry/implementers_guide.pdf
- *
- * This file should be included as
- * #include <KHR/khrplatform.h>
- * by Khronos client API header files that use its types and defines.
- *
- * The types in khrplatform.h should only be used to define API-specific types.
- *
- * Types defined in khrplatform.h:
- * khronos_int8_t signed 8 bit
- * khronos_uint8_t unsigned 8 bit
- * khronos_int16_t signed 16 bit
- * khronos_uint16_t unsigned 16 bit
- * khronos_int32_t signed 32 bit
- * khronos_uint32_t unsigned 32 bit
- * khronos_int64_t signed 64 bit
- * khronos_uint64_t unsigned 64 bit
- * khronos_intptr_t signed same number of bits as a pointer
- * khronos_uintptr_t unsigned same number of bits as a pointer
- * khronos_ssize_t signed size
- * khronos_usize_t unsigned size
- * khronos_float_t signed 32 bit floating point
- * khronos_time_ns_t unsigned 64 bit time in nanoseconds
- * khronos_utime_nanoseconds_t unsigned time interval or absolute time in
- * nanoseconds
- * khronos_stime_nanoseconds_t signed time interval in nanoseconds
- * khronos_boolean_enum_t enumerated boolean type. This should
- * only be used as a base type when a client API's boolean type is
- * an enum. Client APIs which use an integer or other type for
- * booleans cannot use this as the base type for their boolean.
- *
- * Tokens defined in khrplatform.h:
- *
- * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
- *
- * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
- * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
- *
- * Calling convention macros defined in this file:
- * KHRONOS_APICALL
- * KHRONOS_APIENTRY
- * KHRONOS_APIATTRIBUTES
- *
- * These may be used in function prototypes as:
- *
- * KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
- * int arg1,
- * int arg2) KHRONOS_APIATTRIBUTES;
- */
-
-/*-------------------------------------------------------------------------
- * Definition of KHRONOS_APICALL
- *-------------------------------------------------------------------------
- * This precedes the return type of the function in the function prototype.
- */
-#if defined(_WIN32) && !defined(__SCITECH_SNAP__)
-# define KHRONOS_APICALL __declspec(dllimport)
-#elif defined (__SYMBIAN32__)
-# define KHRONOS_APICALL IMPORT_C
-#else
-# define KHRONOS_APICALL
-#endif
-
-/*-------------------------------------------------------------------------
- * Definition of KHRONOS_APIENTRY
- *-------------------------------------------------------------------------
- * This follows the return type of the function and precedes the function
- * name in the function prototype.
- */
-#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
- /* Win32 but not WinCE */
-# define KHRONOS_APIENTRY __stdcall
-#else
-# define KHRONOS_APIENTRY
-#endif
-
-/*-------------------------------------------------------------------------
- * Definition of KHRONOS_APIATTRIBUTES
- *-------------------------------------------------------------------------
- * This follows the closing parenthesis of the function prototype arguments.
- */
-#if defined (__ARMCC_2__)
-#define KHRONOS_APIATTRIBUTES __softfp
-#else
-#define KHRONOS_APIATTRIBUTES
-#endif
-
-/*-------------------------------------------------------------------------
- * basic type definitions
- *-----------------------------------------------------------------------*/
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
-
-
-/*
- * Using <stdint.h>
- */
-#include <stdint.h>
-typedef int32_t khronos_int32_t;
-typedef uint32_t khronos_uint32_t;
-typedef int64_t khronos_int64_t;
-typedef uint64_t khronos_uint64_t;
-#define KHRONOS_SUPPORT_INT64 1
-#define KHRONOS_SUPPORT_FLOAT 1
-
-#elif defined(__VMS ) || defined(__sgi)
-
-/*
- * Using <inttypes.h>
- */
-#include <inttypes.h>
-typedef int32_t khronos_int32_t;
-typedef uint32_t khronos_uint32_t;
-typedef int64_t khronos_int64_t;
-typedef uint64_t khronos_uint64_t;
-#define KHRONOS_SUPPORT_INT64 1
-#define KHRONOS_SUPPORT_FLOAT 1
-
-#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
-
-/*
- * Win32
- */
-typedef __int32 khronos_int32_t;
-typedef unsigned __int32 khronos_uint32_t;
-typedef __int64 khronos_int64_t;
-typedef unsigned __int64 khronos_uint64_t;
-#define KHRONOS_SUPPORT_INT64 1
-#define KHRONOS_SUPPORT_FLOAT 1
-
-#elif defined(__sun__) || defined(__digital__)
-
-/*
- * Sun or Digital
- */
-typedef int khronos_int32_t;
-typedef unsigned int khronos_uint32_t;
-#if defined(__arch64__) || defined(_LP64)
-typedef long int khronos_int64_t;
-typedef unsigned long int khronos_uint64_t;
-#else
-typedef long long int khronos_int64_t;
-typedef unsigned long long int khronos_uint64_t;
-#endif /* __arch64__ */
-#define KHRONOS_SUPPORT_INT64 1
-#define KHRONOS_SUPPORT_FLOAT 1
-
-#elif 0
-
-/*
- * Hypothetical platform with no float or int64 support
- */
-typedef int khronos_int32_t;
-typedef unsigned int khronos_uint32_t;
-#define KHRONOS_SUPPORT_INT64 0
-#define KHRONOS_SUPPORT_FLOAT 0
-
-#else
-
-/*
- * Generic fallback
- */
-#include <stdint.h>
-typedef int32_t khronos_int32_t;
-typedef uint32_t khronos_uint32_t;
-typedef int64_t khronos_int64_t;
-typedef uint64_t khronos_uint64_t;
-#define KHRONOS_SUPPORT_INT64 1
-#define KHRONOS_SUPPORT_FLOAT 1
-
-#endif
-
-
-/*
- * Types that are (so far) the same on all platforms
- */
-typedef signed char khronos_int8_t;
-typedef unsigned char khronos_uint8_t;
-typedef signed short int khronos_int16_t;
-typedef unsigned short int khronos_uint16_t;
-
-/*
- * Types that differ between LLP64 and LP64 architectures - in LLP64,
- * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
- * to be the only LLP64 architecture in current use.
- */
-#ifdef _WIN64
-typedef signed long long int khronos_intptr_t;
-typedef unsigned long long int khronos_uintptr_t;
-typedef signed long long int khronos_ssize_t;
-typedef unsigned long long int khronos_usize_t;
-#else
-typedef signed long int khronos_intptr_t;
-typedef unsigned long int khronos_uintptr_t;
-typedef signed long int khronos_ssize_t;
-typedef unsigned long int khronos_usize_t;
-#endif
-
-#if KHRONOS_SUPPORT_FLOAT
-/*
- * Float type
- */
-typedef float khronos_float_t;
-#endif
-
-#if KHRONOS_SUPPORT_INT64
-/* Time types
- *
- * These types can be used to represent a time interval in nanoseconds or
- * an absolute Unadjusted System Time. Unadjusted System Time is the number
- * of nanoseconds since some arbitrary system event (e.g. since the last
- * time the system booted). The Unadjusted System Time is an unsigned
- * 64 bit value that wraps back to 0 every 584 years. Time intervals
- * may be either signed or unsigned.
- */
-typedef khronos_uint64_t khronos_utime_nanoseconds_t;
-typedef khronos_int64_t khronos_stime_nanoseconds_t;
-#endif
-
-/*
- * Dummy value used to pad enum types to 32 bits.
- */
-#ifndef KHRONOS_MAX_ENUM
-#define KHRONOS_MAX_ENUM 0x7FFFFFFF
-#endif
-
-/*
- * Enumerated boolean type
- *
- * Values other than zero should be considered to be true. Therefore
- * comparisons should not be made against KHRONOS_TRUE.
- */
-typedef enum {
- KHRONOS_FALSE = 0,
- KHRONOS_TRUE = 1,
- KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
-} khronos_boolean_enum_t;
-
-#endif /* __khrplatform_h_ */
+#ifndef __khrplatform_h_
+#define __khrplatform_h_
+
+/*
+** Copyright (c) 2008-2009 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are 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 Materials.
+**
+** THE MATERIALS ARE 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
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+/* Khronos platform-specific types and definitions.
+ *
+ * $Revision: 23298 $ on $Date: 2013-09-30 17:07:13 -0700 (Mon, 30 Sep 2013) $
+ *
+ * Adopters may modify this file to suit their platform. Adopters are
+ * encouraged to submit platform specific modifications to the Khronos
+ * group so that they can be included in future versions of this file.
+ * Please submit changes by sending them to the public Khronos Bugzilla
+ * (http://khronos.org/bugzilla) by filing a bug against product
+ * "Khronos (general)" component "Registry".
+ *
+ * A predefined template which fills in some of the bug fields can be
+ * reached using http://tinyurl.com/khrplatform-h-bugreport, but you
+ * must create a Bugzilla login first.
+ *
+ *
+ * See the Implementer's Guidelines for information about where this file
+ * should be located on your system and for more details of its use:
+ * http://www.khronos.org/registry/implementers_guide.pdf
+ *
+ * This file should be included as
+ * #include <KHR/khrplatform.h>
+ * by Khronos client API header files that use its types and defines.
+ *
+ * The types in khrplatform.h should only be used to define API-specific types.
+ *
+ * Types defined in khrplatform.h:
+ * khronos_int8_t signed 8 bit
+ * khronos_uint8_t unsigned 8 bit
+ * khronos_int16_t signed 16 bit
+ * khronos_uint16_t unsigned 16 bit
+ * khronos_int32_t signed 32 bit
+ * khronos_uint32_t unsigned 32 bit
+ * khronos_int64_t signed 64 bit
+ * khronos_uint64_t unsigned 64 bit
+ * khronos_intptr_t signed same number of bits as a pointer
+ * khronos_uintptr_t unsigned same number of bits as a pointer
+ * khronos_ssize_t signed size
+ * khronos_usize_t unsigned size
+ * khronos_float_t signed 32 bit floating point
+ * khronos_time_ns_t unsigned 64 bit time in nanoseconds
+ * khronos_utime_nanoseconds_t unsigned time interval or absolute time in
+ * nanoseconds
+ * khronos_stime_nanoseconds_t signed time interval in nanoseconds
+ * khronos_boolean_enum_t enumerated boolean type. This should
+ * only be used as a base type when a client API's boolean type is
+ * an enum. Client APIs which use an integer or other type for
+ * booleans cannot use this as the base type for their boolean.
+ *
+ * Tokens defined in khrplatform.h:
+ *
+ * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
+ *
+ * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
+ * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
+ *
+ * Calling convention macros defined in this file:
+ * KHRONOS_APICALL
+ * KHRONOS_APIENTRY
+ * KHRONOS_APIATTRIBUTES
+ *
+ * These may be used in function prototypes as:
+ *
+ * KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
+ * int arg1,
+ * int arg2) KHRONOS_APIATTRIBUTES;
+ */
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APICALL
+ *-------------------------------------------------------------------------
+ * This precedes the return type of the function in the function prototype.
+ */
+#if defined(_WIN32) && !defined(__SCITECH_SNAP__)
+# define KHRONOS_APICALL __declspec(dllimport)
+#elif defined (__SYMBIAN32__)
+# define KHRONOS_APICALL IMPORT_C
+#else
+# define KHRONOS_APICALL
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APIENTRY
+ *-------------------------------------------------------------------------
+ * This follows the return type of the function and precedes the function
+ * name in the function prototype.
+ */
+#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
+ /* Win32 but not WinCE */
+# define KHRONOS_APIENTRY __stdcall
+#else
+# define KHRONOS_APIENTRY
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APIATTRIBUTES
+ *-------------------------------------------------------------------------
+ * This follows the closing parenthesis of the function prototype arguments.
+ */
+#if defined (__ARMCC_2__)
+#define KHRONOS_APIATTRIBUTES __softfp
+#else
+#define KHRONOS_APIATTRIBUTES
+#endif
+
+/*-------------------------------------------------------------------------
+ * basic type definitions
+ *-----------------------------------------------------------------------*/
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
+
+
+/*
+ * Using <stdint.h>
+ */
+#include <stdint.h>
+typedef int32_t khronos_int32_t;
+typedef uint32_t khronos_uint32_t;
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif defined(__VMS ) || defined(__sgi)
+
+/*
+ * Using <inttypes.h>
+ */
+#include <inttypes.h>
+typedef int32_t khronos_int32_t;
+typedef uint32_t khronos_uint32_t;
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
+
+/*
+ * Win32
+ */
+typedef __int32 khronos_int32_t;
+typedef unsigned __int32 khronos_uint32_t;
+typedef __int64 khronos_int64_t;
+typedef unsigned __int64 khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif defined(__sun__) || defined(__digital__)
+
+/*
+ * Sun or Digital
+ */
+typedef int khronos_int32_t;
+typedef unsigned int khronos_uint32_t;
+#if defined(__arch64__) || defined(_LP64)
+typedef long int khronos_int64_t;
+typedef unsigned long int khronos_uint64_t;
+#else
+typedef long long int khronos_int64_t;
+typedef unsigned long long int khronos_uint64_t;
+#endif /* __arch64__ */
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif 0
+
+/*
+ * Hypothetical platform with no float or int64 support
+ */
+typedef int khronos_int32_t;
+typedef unsigned int khronos_uint32_t;
+#define KHRONOS_SUPPORT_INT64 0
+#define KHRONOS_SUPPORT_FLOAT 0
+
+#else
+
+/*
+ * Generic fallback
+ */
+#include <stdint.h>
+typedef int32_t khronos_int32_t;
+typedef uint32_t khronos_uint32_t;
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#endif
+
+
+/*
+ * Types that are (so far) the same on all platforms
+ */
+typedef signed char khronos_int8_t;
+typedef unsigned char khronos_uint8_t;
+typedef signed short int khronos_int16_t;
+typedef unsigned short int khronos_uint16_t;
+
+/*
+ * Types that differ between LLP64 and LP64 architectures - in LLP64,
+ * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
+ * to be the only LLP64 architecture in current use.
+ */
+#ifdef _WIN64
+typedef signed long long int khronos_intptr_t;
+typedef unsigned long long int khronos_uintptr_t;
+typedef signed long long int khronos_ssize_t;
+typedef unsigned long long int khronos_usize_t;
+#else
+typedef signed long int khronos_intptr_t;
+typedef unsigned long int khronos_uintptr_t;
+typedef signed long int khronos_ssize_t;
+typedef unsigned long int khronos_usize_t;
+#endif
+
+#if KHRONOS_SUPPORT_FLOAT
+/*
+ * Float type
+ */
+typedef float khronos_float_t;
+#endif
+
+#if KHRONOS_SUPPORT_INT64
+/* Time types
+ *
+ * These types can be used to represent a time interval in nanoseconds or
+ * an absolute Unadjusted System Time. Unadjusted System Time is the number
+ * of nanoseconds since some arbitrary system event (e.g. since the last
+ * time the system booted). The Unadjusted System Time is an unsigned
+ * 64 bit value that wraps back to 0 every 584 years. Time intervals
+ * may be either signed or unsigned.
+ */
+typedef khronos_uint64_t khronos_utime_nanoseconds_t;
+typedef khronos_int64_t khronos_stime_nanoseconds_t;
+#endif
+
+/*
+ * Dummy value used to pad enum types to 32 bits.
+ */
+#ifndef KHRONOS_MAX_ENUM
+#define KHRONOS_MAX_ENUM 0x7FFFFFFF
+#endif
+
+/*
+ * Enumerated boolean type
+ *
+ * Values other than zero should be considered to be true. Therefore
+ * comparisons should not be made against KHRONOS_TRUE.
+ */
+typedef enum {
+ KHRONOS_FALSE = 0,
+ KHRONOS_TRUE = 1,
+ KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
+} khronos_boolean_enum_t;
+
+#endif /* __khrplatform_h_ */
diff --git a/platform/winrt/include/angle_gl.h b/platform/winrt/include/angle_gl.h
index fadae33e26..d093f75ee2 100644
--- a/platform/winrt/include/angle_gl.h
+++ b/platform/winrt/include/angle_gl.h
@@ -1,23 +1,23 @@
-//
-// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// angle_gl.h:
-// Includes all necessary GL headers and definitions for ANGLE.
-//
-
-#ifndef ANGLE_GL_H_
-#define ANGLE_GL_H_
-
-#include "GLES2/gl2.h"
-#include "GLES2/gl2ext.h"
-#include "GLES3/gl3.h"
-#include "GLES3/gl3ext.h"
-
-// The following enum is used in ANGLE, but is from desktop GL
-#ifndef GL_SAMPLER_2D_RECT_ARB
-#define GL_SAMPLER_2D_RECT_ARB 0x8B63
-#endif
-
-#endif // ANGLE_GL_H_
+//
+// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// angle_gl.h:
+// Includes all necessary GL headers and definitions for ANGLE.
+//
+
+#ifndef ANGLE_GL_H_
+#define ANGLE_GL_H_
+
+#include "GLES2/gl2.h"
+#include "GLES2/gl2ext.h"
+#include "GLES3/gl3.h"
+#include "GLES3/gl3ext.h"
+
+// The following enum is used in ANGLE, but is from desktop GL
+#ifndef GL_SAMPLER_2D_RECT_ARB
+#define GL_SAMPLER_2D_RECT_ARB 0x8B63
+#endif
+
+#endif // ANGLE_GL_H_
diff --git a/platform/winrt/include/angle_windowsstore.h b/platform/winrt/include/angle_windowsstore.h
index fe587bf269..53ec93e037 100644
--- a/platform/winrt/include/angle_windowsstore.h
+++ b/platform/winrt/include/angle_windowsstore.h
@@ -1,37 +1,37 @@
-//
-// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// angle_windowsstore.h:
-
-#ifndef ANGLE_WINDOWSSTORE_H_
-#define ANGLE_WINDOWSSTORE_H_
-
-// The following properties can be set on the CoreApplication to support additional
-// ANGLE configuration options.
-//
-// The Visual Studio sample templates provided with this version of ANGLE have examples
-// of how to set these property values.
-
-//
-// Property: EGLNativeWindowTypeProperty
-// Type: IInspectable
-// Description: Set this property to specify the window type to use for creating a surface.
-// If this property is missing, surface creation will fail.
-//
-const wchar_t EGLNativeWindowTypeProperty[] = L"EGLNativeWindowTypeProperty";
-
-//
-// Property: EGLRenderSurfaceSizeProperty
-// Type: Size
-// Description: Set this property to specify a preferred size in pixels of the render surface.
-// The render surface size width and height must be greater than 0.
-// If this property is set, then the render surface size is fixed.
-// If this property is missing, a default behavior will be provided.
-// The default behavior uses the window size if a CoreWindow is specified or
-// the size of the SwapChainPanel control if one is specified.
-//
-const wchar_t EGLRenderSurfaceSizeProperty[] = L"EGLRenderSurfaceSizeProperty";
-
-#endif // ANGLE_WINDOWSSTORE_H_
+//
+// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// angle_windowsstore.h:
+
+#ifndef ANGLE_WINDOWSSTORE_H_
+#define ANGLE_WINDOWSSTORE_H_
+
+// The following properties can be set on the CoreApplication to support additional
+// ANGLE configuration options.
+//
+// The Visual Studio sample templates provided with this version of ANGLE have examples
+// of how to set these property values.
+
+//
+// Property: EGLNativeWindowTypeProperty
+// Type: IInspectable
+// Description: Set this property to specify the window type to use for creating a surface.
+// If this property is missing, surface creation will fail.
+//
+const wchar_t EGLNativeWindowTypeProperty[] = L"EGLNativeWindowTypeProperty";
+
+//
+// Property: EGLRenderSurfaceSizeProperty
+// Type: Size
+// Description: Set this property to specify a preferred size in pixels of the render surface.
+// The render surface size width and height must be greater than 0.
+// If this property is set, then the render surface size is fixed.
+// If this property is missing, a default behavior will be provided.
+// The default behavior uses the window size if a CoreWindow is specified or
+// the size of the SwapChainPanel control if one is specified.
+//
+const wchar_t EGLRenderSurfaceSizeProperty[] = L"EGLRenderSurfaceSizeProperty";
+
+#endif // ANGLE_WINDOWSSTORE_H_
diff --git a/platform/winrt/os_winrt.cpp b/platform/winrt/os_winrt.cpp
index 3e06d9d59b..f507c1aae7 100644
--- a/platform/winrt/os_winrt.cpp
+++ b/platform/winrt/os_winrt.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -326,10 +326,11 @@ void OSWinrt::finalize() {
//if (debugger_connection_console) {
// memdelete(debugger_connection_console);
//}
+
+ memdelete(sample_manager);
audio_server->finish();
memdelete(audio_server);
- memdelete(sample_manager);
memdelete(input);
@@ -344,8 +345,7 @@ void OSWinrt::finalize_core() {
if (mempool_dynamic)
memdelete( mempool_dynamic );
- if (mempool_static)
- delete mempool_static;
+ delete mempool_static;
}
@@ -422,17 +422,27 @@ void OSWinrt::get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen) con
}
-void OSWinrt::print_error(const char* p_function,const char* p_file,int p_line,const char *p_code,const char*p_rationale,ErrorType p_type) {
-
- if (p_rationale && p_rationale[0]) {
-
- print("\E[1;31;40mERROR: %s: \E[1;37;40m%s\n",p_function,p_rationale);
- print("\E[0;31;40m At: %s:%i.\E[0;0;37m\n",p_file,p_line);
+void OSWinrt::print_error(const char* p_function, const char* p_file, int p_line, const char* p_code, const char* p_rationale, ErrorType p_type) {
- } else {
- print("\E[1;31;40mERROR: %s: \E[1;37;40m%s\n",p_function,p_code);
- print("\E[0;31;40m At: %s:%i.\E[0;0;37m\n",p_file,p_line);
+ const char* err_details;
+ if (p_rationale && p_rationale[0])
+ err_details = p_rationale;
+ else
+ err_details = p_code;
+ switch(p_type) {
+ case ERR_ERROR:
+ print("ERROR: %s: %s\n", p_function, err_details);
+ print(" At: %s:%i\n", p_file, p_line);
+ break;
+ case ERR_WARNING:
+ print("WARNING: %s: %s\n", p_function, err_details);
+ print(" At: %s:%i\n", p_file, p_line);
+ break;
+ case ERR_SCRIPT:
+ print("SCRIPT ERROR: %s: %s\n", p_function, err_details);
+ print(" At: %s:%i\n", p_file, p_line);
+ break;
}
}
diff --git a/platform/winrt/os_winrt.h b/platform/winrt/os_winrt.h
index b69feccae9..3fbb4a4c1b 100644
--- a/platform/winrt/os_winrt.h
+++ b/platform/winrt/os_winrt.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -50,6 +50,8 @@
#include <fcntl.h>
#include <stdio.h>
+#include "main/input_default.h"
+
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
diff --git a/platform/x11/SCsub b/platform/x11/SCsub
index 7a6f02daa5..80fd347ded 100644
--- a/platform/x11/SCsub
+++ b/platform/x11/SCsub
@@ -5,6 +5,7 @@ common_x11=[\
"context_gl_x11.cpp",\
"os_x11.cpp",\
"key_mapping_x11.cpp",\
+ "joystick_linux.cpp",\
]
env.Program('#bin/godot',['godot_x11.cpp']+common_x11)
diff --git a/platform/x11/context_gl_x11.cpp b/platform/x11/context_gl_x11.cpp
index dc0dc063b9..89bd5f58ff 100644
--- a/platform/x11/context_gl_x11.cpp
+++ b/platform/x11/context_gl_x11.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -46,7 +46,6 @@ struct ContextGL_X11_Private {
::GLXContext glx_context;
};
-
void ContextGL_X11::release_current() {
glXMakeCurrent(x11_display, None, NULL);
@@ -56,10 +55,12 @@ void ContextGL_X11::make_current() {
glXMakeCurrent(x11_display, x11_window, p->glx_context);
}
+
void ContextGL_X11::swap_buffers() {
glXSwapBuffers(x11_display,x11_window);
}
+
/*
static GLWrapperFuncPtr wrapper_get_proc_address(const char* p_function) {
@@ -154,6 +155,9 @@ Error ContextGL_X11::initialize() {
*/
//glXMakeCurrent(x11_display, None, NULL);
+ XFree( vi );
+ XFree( fbc );
+
return OK;
}
@@ -164,12 +168,12 @@ int ContextGL_X11::get_window_width() {
return xwa.width;
}
+
int ContextGL_X11::get_window_height() {
XWindowAttributes xwa;
XGetWindowAttributes(x11_display,x11_window,&xwa);
return xwa.height;
-
}
@@ -189,6 +193,8 @@ ContextGL_X11::ContextGL_X11(::Display *p_x11_display,::Window &p_x11_window,con
ContextGL_X11::~ContextGL_X11() {
+ release_current();
+ glXDestroyContext( x11_display, p->glx_context );
memdelete( p );
}
diff --git a/platform/x11/context_gl_x11.h b/platform/x11/context_gl_x11.h
index 8b81db9160..56404d0fae 100644
--- a/platform/x11/context_gl_x11.h
+++ b/platform/x11/context_gl_x11.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/x11/detect.py b/platform/x11/detect.py
index ff85e286db..e035c72993 100644
--- a/platform/x11/detect.py
+++ b/platform/x11/detect.py
@@ -1,6 +1,7 @@
import os
import sys
+import platform
def is_active():
@@ -44,7 +45,7 @@ def can_build():
print("xinerama not found.. x11 disabled.")
return False
-
+
return True # X11 enabled
def get_opts():
@@ -54,6 +55,7 @@ def get_opts():
('use_sanitizer','Use llvm compiler sanitize address','no'),
('use_leak_sanitizer','Use llvm compiler sanitize memory leaks','no'),
('pulseaudio','Detect & Use pulseaudio','yes'),
+ ('gamepad','Gamepad support, requires libudev and libevdev','yes'),
('new_wm_api', 'Use experimental window management API','no'),
('debug_release', 'Add debug symbols to release version','no'),
]
@@ -63,7 +65,7 @@ def get_flags():
return [
('builtin_zlib', 'no'),
("openssl", "yes"),
- ("theora","no"),
+ #("theora","no"),
]
@@ -118,6 +120,8 @@ def configure(env):
elif (env["target"]=="release_debug"):
env.Append(CCFLAGS=['-O2','-ffast-math','-DDEBUG_ENABLED'])
+ if (env["debug_release"]=="yes"):
+ env.Append(CCFLAGS=['-g2'])
elif (env["target"]=="debug"):
@@ -126,15 +130,49 @@ def configure(env):
env.ParseConfig('pkg-config x11 --cflags --libs')
env.ParseConfig('pkg-config xinerama --cflags --libs')
env.ParseConfig('pkg-config xcursor --cflags --libs')
- env.ParseConfig('pkg-config openssl --cflags --libs')
+ if (env["openssl"]=="yes"):
+ env.ParseConfig('pkg-config openssl --cflags --libs')
+
+
+ if (env["freetype"]=="yes"):
+ env.ParseConfig('pkg-config freetype2 --cflags --libs')
+
+
+ if (env["freetype"]!="no"):
+ env.Append(CCFLAGS=['-DFREETYPE_ENABLED'])
+ if (env["freetype"]=="builtin"):
+ env.Append(CPPPATH=['#tools/freetype'])
+ env.Append(CPPPATH=['#tools/freetype/freetype/include'])
- env.ParseConfig('pkg-config freetype2 --cflags --libs')
- env.Append(CCFLAGS=['-DFREETYPE_ENABLED'])
-
env.Append(CPPFLAGS=['-DOPENGL_ENABLED','-DGLEW_ENABLED'])
- env.Append(CPPFLAGS=["-DALSA_ENABLED"])
+
+ if os.system("pkg-config --exists alsa")==0:
+ print("Enabling ALSA")
+ env.Append(CPPFLAGS=["-DALSA_ENABLED"])
+ env.Append(LIBS=['asound'])
+ else:
+ print("ALSA libraries not found, disabling driver")
+
+ if (env["gamepad"]=="yes" and platform.system() == "Linux"):
+ # pkg-config returns 0 when the lib exists...
+ found_udev = not os.system("pkg-config --exists libudev")
+ found_evdev = not os.system("pkg-config --exists libevdev")
+
+ if (found_udev and found_evdev):
+ print("Enabling gamepad support with udev/evdev")
+ env.Append(CPPFLAGS=["-DJOYDEV_ENABLED"])
+ env.ParseConfig('pkg-config libudev --cflags --libs')
+ env.ParseConfig('pkg-config libevdev --cflags --libs')
+ else:
+ if (not found_udev):
+ print("libudev development libraries not found")
+ if (not found_evdev):
+ print("libevdev development libraries not found")
+ print("Some libraries are missing for the required gamepad support, aborting!")
+ print("Install the mentioned libraries or build with 'gamepad=no' to disable gamepad support.")
+ sys.exit(255)
if (env["pulseaudio"]=="yes"):
if not os.system("pkg-config --exists libpulse-simple"):
@@ -145,7 +183,7 @@ def configure(env):
print("PulseAudio development libraries not found, disabling driver")
env.Append(CPPFLAGS=['-DX11_ENABLED','-DUNIX_ENABLED','-DGLES2_ENABLED','-DGLES_OVER_GL'])
- env.Append(LIBS=['GL', 'GLU', 'pthread','asound','z']) #TODO detect linux/BSD!
+ env.Append(LIBS=['GL', 'GLU', 'pthread', 'z'])
#env.Append(CPPFLAGS=['-DMPC_FIXED_POINT'])
#host compiler is default..
@@ -169,3 +207,5 @@ def configure(env):
env.Append(CPPFLAGS=['-DNEW_WM_API'])
env.ParseConfig('pkg-config xinerama --cflags --libs')
+ env["x86_opt_gcc"]=True
+
diff --git a/platform/x11/godot_x11.cpp b/platform/x11/godot_x11.cpp
index f90d40fa5c..ee83da25c1 100644
--- a/platform/x11/godot_x11.cpp
+++ b/platform/x11/godot_x11.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/x11/joystick_linux.cpp b/platform/x11/joystick_linux.cpp
new file mode 100644
index 0000000000..6eb3671bc0
--- /dev/null
+++ b/platform/x11/joystick_linux.cpp
@@ -0,0 +1,416 @@
+/*************************************************************************/
+/* joystick_linux.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
+
+//author: Andreas Haas <hondres, liugam3@gmail.com>
+#ifdef JOYDEV_ENABLED
+
+#include "joystick_linux.h"
+#include "print_string.h"
+
+#include <libevdev/libevdev.h>
+#include <libudev.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <cstring>
+
+static const char* ignore_str = "/dev/input/js";
+
+joystick_linux::Joystick::Joystick() {
+ fd = -1;
+ dpad = 0;
+ dev = NULL;
+ devpath = "";
+}
+
+void joystick_linux::Joystick::reset() {
+ dpad = 0;
+ fd = -1;
+
+ InputDefault::JoyAxis jx;
+ jx.min = -1;
+ jx.value = 0.0f;
+ for (int i=0; i < MAX_ABS; i++) {
+ abs_map[i] = -1;
+ curr_axis[i] = jx;
+ }
+}
+
+joystick_linux::joystick_linux(InputDefault *in)
+{
+ exit_udev = false;
+ input = in;
+ joy_mutex = Mutex::create();
+ joy_thread = Thread::create(joy_thread_func, this);
+}
+
+joystick_linux::~joystick_linux() {
+ exit_udev = true;
+ Thread::wait_to_finish(joy_thread);
+ close_joystick();
+}
+
+void joystick_linux::joy_thread_func(void *p_user) {
+
+ if (p_user) {
+ joystick_linux* joy = (joystick_linux*) p_user;
+ joy->run_joystick_thread();
+ }
+ return;
+}
+
+void joystick_linux::run_joystick_thread() {
+
+ udev *_udev = udev_new();
+ ERR_FAIL_COND(!_udev);
+ enumerate_joysticks(_udev);
+ monitor_joysticks(_udev);
+ udev_unref(_udev);
+}
+
+void joystick_linux::enumerate_joysticks(udev *p_udev) {
+
+ udev_enumerate *enumerate;
+ udev_list_entry *devices, *dev_list_entry;
+ udev_device *dev;
+
+ enumerate = udev_enumerate_new(p_udev);
+ udev_enumerate_add_match_subsystem(enumerate,"input");
+ udev_enumerate_add_match_property(enumerate, "ID_INPUT_JOYSTICK", "1");
+
+ udev_enumerate_scan_devices(enumerate);
+ devices = udev_enumerate_get_list_entry(enumerate);
+ udev_list_entry_foreach(dev_list_entry, devices) {
+
+ const char* path = udev_list_entry_get_name(dev_list_entry);
+ dev = udev_device_new_from_syspath(p_udev, path);
+ const char* devnode = udev_device_get_devnode(dev);
+
+ if (devnode != NULL && strstr(devnode, ignore_str) == NULL) {
+ joy_mutex->lock();
+ open_joystick(devnode);
+ joy_mutex->unlock();
+ }
+ udev_device_unref(dev);
+ }
+ udev_enumerate_unref(enumerate);
+}
+
+void joystick_linux::monitor_joysticks(udev *p_udev) {
+
+ udev_device *dev = NULL;
+ udev_monitor *mon = udev_monitor_new_from_netlink(p_udev, "udev");
+ udev_monitor_filter_add_match_subsystem_devtype(mon, "input", NULL);
+ udev_monitor_enable_receiving(mon);
+ int fd = udev_monitor_get_fd(mon);
+
+ while (!exit_udev) {
+
+ fd_set fds;
+ struct timeval tv;
+ int ret;
+
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+
+ ret = select(fd+1, &fds, NULL, NULL, &tv);
+
+ /* Check if our file descriptor has received data. */
+ if (ret > 0 && FD_ISSET(fd, &fds)) {
+ /* Make the call to receive the device.
+ select() ensured that this will not block. */
+ dev = udev_monitor_receive_device(mon);
+
+ if (dev && udev_device_get_devnode(dev) != 0) {
+
+ joy_mutex->lock();
+ const char* action = udev_device_get_action(dev);
+ const char* devnode = udev_device_get_devnode(dev);
+
+ if (strstr(devnode, ignore_str) == NULL) {
+
+ if (strcmp(action, "add") == 0)
+ open_joystick(devnode);
+
+ else if (strcmp(action, "remove") == 0)
+ close_joystick(get_joy_from_path(devnode));
+ }
+
+ udev_device_unref(dev);
+ joy_mutex->unlock();
+ }
+ }
+ usleep(50000);
+ }
+ //printf("exit udev\n");
+ udev_monitor_unref(mon);
+}
+
+int joystick_linux::get_free_joy_slot() const {
+
+ for (int i = 0; i < JOYSTICKS_MAX; i++) {
+
+ if (joysticks[i].fd == -1) return i;
+ }
+ return -1;
+}
+
+int joystick_linux::get_joy_from_path(String p_path) const {
+
+ for (int i = 0; i < JOYSTICKS_MAX; i++) {
+
+ if (joysticks[i].devpath == p_path) {
+ return i;
+ }
+ }
+ return -2;
+}
+
+void joystick_linux::close_joystick(int p_id) {
+ if (p_id == -1) {
+ for (int i=0; i<JOYSTICKS_MAX; i++) {
+
+ close_joystick(i);
+ };
+ return;
+ }
+ else if (p_id < 0) return;
+
+ Joystick &joy = joysticks[p_id];
+
+ if (joy.fd != -1) {
+
+ libevdev_free(joy.dev);
+ close(joy.fd);
+ joy.fd = -1;
+ input->joy_connection_changed(p_id, false, "");
+ };
+};
+
+static String _hex_str(uint8_t p_byte) {
+
+ static const char* dict = "0123456789abcdef";
+ char ret[3];
+ ret[2] = 0;
+
+ ret[0] = dict[p_byte>>4];
+ ret[1] = dict[p_byte & 0xF];
+
+ return ret;
+};
+
+void joystick_linux::setup_joystick_properties(int p_id) {
+
+ Joystick* joy = &joysticks[p_id];
+ libevdev* dev = joy->dev;
+
+ int num_buttons = 0;
+ int num_axes = 0;
+
+ for (int i = BTN_JOYSTICK; i < KEY_MAX; ++i) {
+
+ if (libevdev_has_event_code(dev, EV_KEY, i)) {
+
+ joy->key_map[i] = num_buttons++;
+ }
+ }
+ for (int i = BTN_MISC; i < BTN_JOYSTICK; ++i) {
+
+ if (libevdev_has_event_code(dev, EV_KEY, i)) {
+
+ joy->key_map[i] = num_buttons++;
+ }
+ }
+ for (int i = 0; i < ABS_MISC; ++i) {
+ /* Skip hats */
+ if (i == ABS_HAT0X) {
+ i = ABS_HAT3Y;
+ continue;
+ }
+ if (libevdev_has_event_code(dev, EV_ABS, i)) {
+
+ joy->abs_map[i] = num_axes++;
+ }
+ }
+}
+
+void joystick_linux::open_joystick(const char *p_path) {
+
+ int joy_num = get_free_joy_slot();
+ int fd = open(p_path, O_RDONLY | O_NONBLOCK);
+ if (fd != -1 && joy_num != -1) {
+
+ int rc = libevdev_new_from_fd(fd, &joysticks[joy_num].dev);
+ if (rc < 0) {
+
+ fprintf(stderr, "Failed to init libevdev (%s)\n", strerror(-rc));
+ return;
+ }
+
+ libevdev *dev = joysticks[joy_num].dev;
+
+ //check if the device supports basic gamepad events, prevents certain keyboards from
+ //being detected as joysticks
+ if (libevdev_has_event_type(dev, EV_ABS) && libevdev_has_event_type(dev, EV_KEY) &&
+ (libevdev_has_event_code(dev, EV_KEY, BTN_A) || libevdev_has_event_code(dev, EV_KEY, BTN_THUMBL) || libevdev_has_event_code(dev, EV_KEY, BTN_TOP))) {
+
+ char uid[128];
+ String name = libevdev_get_name(dev);
+ uint16_t bus = __bswap_16(libevdev_get_id_bustype(dev));
+ uint16_t vendor = __bswap_16(libevdev_get_id_vendor(dev));
+ uint16_t product = __bswap_16(libevdev_get_id_product(dev));
+ uint16_t version = __bswap_16(libevdev_get_id_version(dev));
+
+ joysticks[joy_num].reset();
+
+ Joystick &joy = joysticks[joy_num];
+ joy.fd = fd;
+ joy.devpath = String(p_path);
+ setup_joystick_properties(joy_num);
+ sprintf(uid, "%04x%04x", bus, 0);
+ if (vendor && product && version) {
+
+ sprintf(uid + String(uid).length(), "%04x%04x%04x%04x%04x%04x", vendor,0,product,0,version,0);
+ input->joy_connection_changed(joy_num, true, name, uid);
+ }
+ else {
+ String uidname = uid;
+ int uidlen = MIN(name.length(), 11);
+ for (int i=0; i<uidlen; i++) {
+
+ uidname = uidname + _hex_str(name[i]);
+ }
+ uidname += "00";
+ input->joy_connection_changed(joy_num, true, name, uidname);
+
+ }
+ }
+ else {
+ //device is not a gamepad, clean up
+ libevdev_free(dev);
+ close(fd);
+ }
+ }
+}
+
+InputDefault::JoyAxis joystick_linux::axis_correct(const input_absinfo *p_abs, int p_value) const {
+
+ int min = p_abs->minimum;
+ int max = p_abs->maximum;
+ InputDefault::JoyAxis jx;
+
+ if (min < 0) {
+ jx.min = -1;
+ if (p_value < 0) {
+ jx.value = (float) -p_value / min;
+ }
+ jx.value = (float) p_value / max;
+ }
+ if (min == 0) {
+ jx.min = 0;
+ jx.value = 0.0f + (float) p_value / max;
+ }
+ return jx;
+}
+
+uint32_t joystick_linux::process_joysticks(uint32_t p_event_id) {
+
+ if (joy_mutex->try_lock() != OK) {
+ return p_event_id;
+ }
+ for (int i=0; i<JOYSTICKS_MAX; i++) {
+
+ if (joysticks[i].fd == -1) continue;
+
+ input_event ev;
+ Joystick* joy = &joysticks[i];
+ libevdev* dev = joy->dev;
+ int rc = 1;
+
+ rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev);
+
+ if (rc < 0 && rc != -EAGAIN) {
+ continue;
+ }
+
+ while (rc == LIBEVDEV_READ_STATUS_SYNC || rc == LIBEVDEV_READ_STATUS_SUCCESS) {
+
+ switch (ev.type) {
+ case EV_KEY:
+ p_event_id = input->joy_button(p_event_id, i, joy->key_map[ev.code], ev.value);
+ break;
+
+ case EV_ABS:
+
+ switch (ev.code) {
+ case ABS_HAT0X:
+ if (ev.value != 0) {
+ if (ev.value < 0) joy->dpad |= InputDefault::HAT_MASK_LEFT;
+ else joy->dpad |= InputDefault::HAT_MASK_RIGHT;
+
+ }
+ else joy->dpad &= ~(InputDefault::HAT_MASK_LEFT | InputDefault::HAT_MASK_RIGHT);
+
+ p_event_id = input->joy_hat(p_event_id, i, joy->dpad);
+ break;
+
+ case ABS_HAT0Y:
+ if (ev.value != 0) {
+ if (ev.value < 0) joy->dpad |= InputDefault::HAT_MASK_UP;
+ else joy->dpad |= InputDefault::HAT_MASK_DOWN;
+ }
+ else joy->dpad &= ~(InputDefault::HAT_MASK_UP | InputDefault::HAT_MASK_DOWN);
+
+ p_event_id = input->joy_hat(p_event_id, i, joy->dpad);
+ break;
+
+ default:
+ if (joy->abs_map[ev.code] != -1) {
+ InputDefault::JoyAxis value = axis_correct(libevdev_get_abs_info(dev, ev.code), ev.value);
+ joy->curr_axis[joy->abs_map[ev.code]] = value;
+ }
+ break;
+ }
+ break;
+ }
+ rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev);
+ }
+ for (int j = 0; j < MAX_ABS; j++) {
+ int index = joy->abs_map[j];
+ if (index != -1) {
+ p_event_id = input->joy_axis(p_event_id, i, index, joy->curr_axis[index]);
+ }
+ }
+ }
+ joy_mutex->unlock();
+ return p_event_id;
+}
+#endif
diff --git a/platform/x11/joystick_linux.h b/platform/x11/joystick_linux.h
new file mode 100644
index 0000000000..ee9bd0352a
--- /dev/null
+++ b/platform/x11/joystick_linux.h
@@ -0,0 +1,92 @@
+/*************************************************************************/
+/* joystick_linux.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
+
+//author: Andreas Haas <hondres, liugam3@gmail.com>
+#ifndef JOYSTICK_LINUX_H
+#define JOYSTICK_LINUX_H
+#ifdef JOYDEV_ENABLED
+#include "main/input_default.h"
+#include "os/thread.h"
+#include "os/mutex.h"
+
+struct input_absinfo;
+
+class joystick_linux
+{
+public:
+ joystick_linux(InputDefault *in);
+ ~joystick_linux();
+ uint32_t process_joysticks(uint32_t p_event_id);
+private:
+
+ enum {
+ JOYSTICKS_MAX = 16,
+ MAX_ABS = 63,
+ MAX_KEY = 767, // Hack because <linux/input.h> can't be included here
+ BT_MISC = 256,
+ HAT_MAX = 4,
+ };
+
+ struct Joystick {
+ InputDefault::JoyAxis curr_axis[MAX_ABS];
+ int key_map[MAX_KEY - BT_MISC];
+ int abs_map[MAX_ABS];
+ int dpad;
+ int fd;
+
+ String devpath;
+ struct libevdev *dev;
+
+ Joystick();
+ void reset();
+ };
+
+ bool exit_udev;
+ Mutex *joy_mutex;
+ Thread *joy_thread;
+ InputDefault *input;
+ Joystick joysticks[JOYSTICKS_MAX];
+
+ static void joy_thread_func(void *p_user);
+
+ int get_joy_from_path(String path) const;
+ int get_free_joy_slot() const;
+
+ void setup_joystick_properties(int p_id);
+ void close_joystick(int p_id = -1);
+ void enumerate_joysticks(struct udev *_udev);
+ void monitor_joysticks(struct udev *_udev);
+ void run_joystick_thread();
+ void open_joystick(const char* path);
+
+ InputDefault::JoyAxis axis_correct(const input_absinfo *abs, int value) const;
+};
+
+#endif
+#endif // JOYSTICK_LINUX_H
diff --git a/platform/x11/key_mapping_x11.cpp b/platform/x11/key_mapping_x11.cpp
index 9c68ac1a2c..48f415a730 100644
--- a/platform/x11/key_mapping_x11.cpp
+++ b/platform/x11/key_mapping_x11.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/x11/key_mapping_x11.h b/platform/x11/key_mapping_x11.h
index 7ab883878f..979d8a112f 100644
--- a/platform/x11/key_mapping_x11.h
+++ b/platform/x11/key_mapping_x11.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index f8c570a5c0..82df8dff60 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,9 +32,10 @@
#include "key_mapping_x11.h"
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include "print_string.h"
#include "servers/physics/physics_server_sw.h"
-
+#include "errno.h"
#include "X11/Xutil.h"
@@ -57,10 +58,6 @@
#include <fcntl.h>
#include <unistd.h>
-#ifdef __linux__
-#include <linux/joystick.h>
-#endif
-
//stupid linux.h
#ifdef KEY_TAB
#undef KEY_TAB
@@ -73,20 +70,18 @@
#undef CursorShape
int OS_X11::get_video_driver_count() const {
-
return 1;
}
-const char * OS_X11::get_video_driver_name(int p_driver) const {
+const char * OS_X11::get_video_driver_name(int p_driver) const {
return "GLES2";
}
-OS::VideoMode OS_X11::get_default_video_mode() const {
- return OS::VideoMode(800,600,false);
+OS::VideoMode OS_X11::get_default_video_mode() const {
+ return OS::VideoMode(1280,720,false);
}
int OS_X11::get_audio_driver_count() const {
-
return AudioDriverManagerSW::get_driver_count();
}
@@ -100,8 +95,6 @@ const char *OS_X11::get_audio_driver_name(int p_driver) const {
void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audio_driver) {
last_button_state=0;
- dpad_last[0]=0;
- dpad_last[1]=0;
xmbstring=NULL;
event_id=0;
@@ -153,6 +146,7 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
XFree (xim_styles);
}
+ XFree( imvalret );
}
/*
@@ -256,7 +250,6 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
}
#endif
-
AudioDriverManagerSW::get_driver(p_audio_driver)->set_singleton();
audio_driver_index=p_audio_driver;
@@ -267,6 +260,7 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
for(int i=0;i<AudioDriverManagerSW::get_driver_count();i++) {
if (i==p_audio_driver)
continue;
+ AudioDriverManagerSW::get_driver(i)->set_singleton();
if (AudioDriverManagerSW::get_driver(i)->init()==OK) {
success=true;
print_line("Audio Driver Failed: "+String(AudioDriverManagerSW::get_driver(p_audio_driver)->get_name()));
@@ -350,6 +344,7 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
for(int i=0;i<CURSOR_MAX;i++) {
cursors[i]=None;
+ img[i]=NULL;
}
current_cursor=CURSOR_ARROW;
@@ -378,16 +373,15 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
"question_arrow"
};
- XcursorImage *img = XcursorLibraryLoadImage(cursor_file[i],cursor_theme,cursor_size);
- if (img) {
- cursors[i]=XcursorImageLoadCursor(x11_display,img);
+ img[i] = XcursorLibraryLoadImage(cursor_file[i],cursor_theme,cursor_size);
+ if (img[i]) {
+ cursors[i]=XcursorImageLoadCursor(x11_display,img[i]);
//print_line("found cursor: "+String(cursor_file[i])+" id "+itos(cursors[i]));
} else {
if (OS::is_stdout_verbose())
print_line("failed cursor: "+String(cursor_file[i]));
}
}
-
}
@@ -398,9 +392,9 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
XColor col;
Cursor cursor;
- cursormask = XCreatePixmap(x11_display, RootWindow(x11_display,DefaultScreen(x11_display)), 1, 1, 1);
- xgc.function = GXclear;
- gc = XCreateGC(x11_display, cursormask, GCFunction, &xgc);
+ cursormask = XCreatePixmap(x11_display, RootWindow(x11_display,DefaultScreen(x11_display)), 1, 1, 1);
+ xgc.function = GXclear;
+ gc = XCreateGC(x11_display, cursormask, GCFunction, &xgc);
XFillRectangle(x11_display, cursormask, gc, 0, 0, 1, 1);
col.pixel = 0;
col.red = 0;
@@ -432,17 +426,12 @@ void OS_X11::initialize(const VideoMode& p_desired,int p_video_driver,int p_audi
physics_2d_server->init();
input = memnew( InputDefault );
-
- probe_joystick();
-
+#ifdef JOYDEV_ENABLED
+ joystick = memnew( joystick_linux(input));
+#endif
_ensure_data_dir();
-
- net_wm_icon = XInternAtom(x11_display, "_NET_WM_ICON", False);
-
-
- //printf("got map notify\n");
-
}
+
void OS_X11::finalize() {
if(main_loop)
@@ -458,9 +447,15 @@ void OS_X11::finalize() {
// memdelete(debugger_connection_console);
//}
+#ifdef JOYDEV_ENABLED
+ memdelete(joystick);
+#endif
+ memdelete(input);
+
+ memdelete(sample_manager);
+
audio_server->finish();
memdelete(audio_server);
- memdelete(sample_manager);
visual_server->finish();
memdelete(visual_server);
@@ -472,16 +467,26 @@ void OS_X11::finalize() {
physics_2d_server->finish();
memdelete(physics_2d_server);
- memdelete(input);
+ XUnmapWindow( x11_display, x11_window );
+ XDestroyWindow( x11_display, x11_window );
#if defined(OPENGL_ENABLED) || defined(LEGACYGL_ENABLED)
memdelete(context_gl);
#endif
-
+ for(int i=0;i<CURSOR_MAX;i++) {
+ if( cursors[i] != None )
+ XFreeCursor( x11_display, cursors[i] );
+ if( img[i] != NULL )
+ XcursorImageDestroy( img[i] );
+ };
+
+ XDestroyIC( xic );
+ XCloseIM( xim );
XCloseDisplay(x11_display);
if (xmbstring)
memfree(xmbstring);
+
args.clear();
}
@@ -503,6 +508,23 @@ void OS_X11::set_mouse_mode(MouseMode p_mode) {
mouse_mode=p_mode;
if (mouse_mode==MOUSE_MODE_CAPTURED) {
+
+ while(true) {
+ //flush pending motion events
+
+ if (XPending(x11_display) > 0) {
+ XEvent event;
+ XPeekEvent(x11_display, &event);
+ if (event.type==MotionNotify) {
+ XNextEvent(x11_display,&event);
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
if (XGrabPointer(x11_display, x11_window, True,
ButtonPressMask | ButtonReleaseMask |
PointerMotionMask, GrabModeAsync, GrabModeAsync,
@@ -517,6 +539,8 @@ void OS_X11::set_mouse_mode(MouseMode p_mode) {
0,0,0,0, (int)center.x, (int)center.y);
input->set_mouse_pos(center);
+ } else {
+ do_mouse_warp=false;
}
}
@@ -538,37 +562,29 @@ void OS_X11::warp_mouse_pos(const Point2& p_to) {
}
OS::MouseMode OS_X11::get_mouse_mode() const {
-
return mouse_mode;
}
-
-
int OS_X11::get_mouse_button_state() const {
return last_button_state;
}
Point2 OS_X11::get_mouse_pos() const {
-
return last_mouse_pos;
}
void OS_X11::set_window_title(const String& p_title) {
-
XStoreName(x11_display,x11_window,p_title.utf8().get_data());
}
void OS_X11::set_video_mode(const VideoMode& p_video_mode,int p_screen) {
-
-
}
-OS::VideoMode OS_X11::get_video_mode(int p_screen) const {
+OS::VideoMode OS_X11::get_video_mode(int p_screen) const {
return current_videomode;
}
-void OS_X11::get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen) const {
-
+void OS_X11::get_fullscreen_mode_list(List<VideoMode> *p_list,int p_screen) const {
}
//#ifdef NEW_WM_API
@@ -603,6 +619,7 @@ void OS_X11::set_wm_fullscreen(bool p_enabled) {
xev.xclient.data.l[2] = 0;
XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+
}
int OS_X11::get_screen_count() const {
@@ -654,14 +671,20 @@ Point2 OS_X11::get_screen_position(int p_screen) const {
// Using Xinerama Extension
int event_base, error_base;
const Bool ext_okay = XineramaQueryExtension(x11_display, &event_base, &error_base);
- if( !ext_okay ) return Point2i(0,0);
+ if( !ext_okay ) {
+ return Point2i(0,0);
+ }
int count;
XineramaScreenInfo* xsi = XineramaQueryScreens(x11_display, &count);
- if( p_screen >= count ) return Point2i(0,0);
+ if( p_screen >= count ) {
+ return Point2i(0,0);
+ }
Point2i position = Point2i(xsi[p_screen].x_org, xsi[p_screen].y_org);
+
XFree(xsi);
+
return position;
}
@@ -679,7 +702,6 @@ Size2 OS_X11::get_screen_size(int p_screen) const {
XFree(xsi);
return size;
}
-
Point2 OS_X11::get_window_position() const {
int x,y;
@@ -695,6 +717,7 @@ Point2 OS_X11::get_window_position() const {
void OS_X11::set_window_position(const Point2& p_position) {
// Using EWMH -- Extended Window Manager Hints
// to get the size of the decoration
+#if 0
Atom property = XInternAtom(x11_display,"_NET_FRAME_EXTENTS", True);
Atom type;
int format;
@@ -737,6 +760,9 @@ void OS_X11::set_window_position(const Point2& p_position) {
top -= screen_position.y;
XMoveWindow(x11_display,x11_window,p_position.x - left,p_position.y - top);
+#else
+ XMoveWindow(x11_display,x11_window,p_position.x,p_position.y);
+#endif
}
Size2 OS_X11::get_window_size() const {
@@ -752,8 +778,6 @@ void OS_X11::set_window_size(const Size2 p_size) {
void OS_X11::set_window_fullscreen(bool p_enabled) {
set_wm_fullscreen(p_enabled);
current_videomode.fullscreen = p_enabled;
-
- visual_server->init();
}
bool OS_X11::is_window_fullscreen() const {
@@ -859,6 +883,20 @@ void OS_X11::set_window_maximized(bool p_enabled) {
xev.xclient.data.l[2] = wm_max_vert;
XSendEvent(x11_display, DefaultRootWindow(x11_display), False, SubstructureRedirectMask | SubstructureNotifyMask, &xev);
+/* sorry this does not fix it, fails on multi monitor
+ XWindowAttributes xwa;
+ XGetWindowAttributes(x11_display,DefaultRootWindow(x11_display),&xwa);
+ current_videomode.width = xwa.width;
+ current_videomode.height = xwa.height;
+//*/
+
+// current_videomode.width = wm_max_horz;
+// current_videomode.height = wm_max_vert;
+
+ //Size2 ss = get_screen_size(get_current_screen());
+ //current_videomode.width=ss.width;
+ //current_videomode.height=ss.height;
+
maximized = p_enabled;
}
@@ -956,7 +994,6 @@ unsigned int OS_X11::get_mouse_button_state(unsigned int p_x11_state) {
}
void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) {
-
// X11 functions don't know what const is
XKeyEvent *xkeyevent = p_event;
@@ -1122,15 +1159,13 @@ void OS_X11::handle_key_event(XKeyEvent *p_event, bool p_echo) {
//printf("key: %x\n",event.key.scancode);
input->parse_input_event( event);
-
-
}
void OS_X11::process_xevents() {
//printf("checking events %i\n", XPending(x11_display));
- bool do_mouse_warp=false;
+ do_mouse_warp=false;
while (XPending(x11_display) > 0) {
XEvent event;
@@ -1149,13 +1184,26 @@ void OS_X11::process_xevents() {
XVisibilityEvent * visibility = (XVisibilityEvent *)&event;
minimized = (visibility->state == VisibilityFullyObscured);
} break;
+ case LeaveNotify: {
+
+ if (main_loop && mouse_mode!=MOUSE_MODE_CAPTURED)
+ main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_EXIT);
+ if (input)
+ input->set_mouse_in_window(false);
+
+ } break;
+ case EnterNotify: {
- case FocusIn:
+ if (main_loop && mouse_mode!=MOUSE_MODE_CAPTURED)
+ main_loop->notification(MainLoop::NOTIFICATION_WM_MOUSE_ENTER);
+ if (input)
+ input->set_mouse_in_window(true);
+ } break;
+ case FocusIn:
minimized = false;
#ifdef NEW_WM_API
if(current_videomode.fullscreen) {
set_wm_fullscreen(true);
- visual_server->init();
}
#endif
main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_IN);
@@ -1172,7 +1220,6 @@ void OS_X11::process_xevents() {
if(current_videomode.fullscreen) {
set_wm_fullscreen(false);
set_window_minimized(true);
- visual_server->init();
}
#endif
main_loop->notification(MainLoop::NOTIFICATION_WM_FOCUS_OUT);
@@ -1243,8 +1290,38 @@ void OS_X11::process_xevents() {
} break;
case MotionNotify: {
-
+
+ // FUCK YOU X11 API YOU SERIOUSLY GROSS ME OUT
+ // YOU ARE AS GROSS AS LOOKING AT A PUTRID PILE
+ // OF POOP STICKING OUT OF A CLOGGED TOILET
+ // HOW THE FUCK I AM SUPPOSED TO KNOW WHICH ONE
+ // OF THE MOTION NOTIFY EVENTS IS THE ONE GENERATED
+ // BY WARPING THE MOUSE POINTER?
+ // YOU ARE FORCING ME TO FILTER ONE BY ONE TO FIND IT
+ // PLEASE DO ME A FAVOR AND DIE DROWNED IN A FECAL
+ // MOUNTAIN BECAUSE THAT'S WHERE YOU BELONG.
+
+ while(true) {
+ if (mouse_mode==MOUSE_MODE_CAPTURED && event.xmotion.x==current_videomode.width/2 && event.xmotion.y==current_videomode.height/2) {
+ //this is likely the warp event since it was warped here
+ center=Vector2(event.xmotion.x,event.xmotion.y);
+ break;
+ }
+
+ if (XPending(x11_display) > 0) {
+ XEvent tevent;
+ XPeekEvent(x11_display, &tevent);
+ if (tevent.type==MotionNotify) {
+ XNextEvent(x11_display,&event);
+ } else {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
last_timestamp=event.xmotion.time;
// Motion is also simple.
@@ -1583,193 +1660,11 @@ String OS_X11::get_system_dir(SystemDir p_dir) const {
return pipe.strip_edges();
}
-
-void OS_X11::close_joystick(int p_id) {
-
- if (p_id == -1) {
- for (int i=0; i<JOYSTICKS_MAX; i++) {
-
- close_joystick(i);
- };
- return;
- };
-
-
- if (joysticks[p_id].fd != -1) {
- close(joysticks[p_id].fd);
- joysticks[p_id].fd = -1;
- };
- input->joy_connection_changed(p_id, false, "");
-};
-
-void OS_X11::probe_joystick(int p_id) {
- #ifndef __FreeBSD__
-
- if (p_id == -1) {
-
- for (int i=0; i<JOYSTICKS_MAX; i++) {
-
- probe_joystick(i);
- };
- return;
- };
-
- if (joysticks[p_id].fd != -1)
- close_joystick(p_id);
-
- const char *joy_names[] = {
- "/dev/input/js%d",
- "/dev/js%d",
- NULL
- };
-
- int i=0;
- while(joy_names[i]) {
-
- char fname[64];
- sprintf(fname, joy_names[i], p_id);
- int fd = open(fname, O_RDONLY|O_NONBLOCK);
- if (fd != -1) {
-
- //fcntl( fd, F_SETFL, O_NONBLOCK );
- joysticks[p_id] = Joystick(); // this will reset the axis array
- joysticks[p_id].fd = fd;
-
- String name;
- char namebuf[255] = {0};
- if (ioctl(fd, JSIOCGNAME(sizeof(namebuf)), namebuf) >= 0) {
- name = namebuf;
- } else {
- name = "error";
- };
-
- input->joy_connection_changed(p_id, true, name);
- break; // don't try the next name
- };
-
- ++i;
- };
- #endif
-};
-
void OS_X11::move_window_to_foreground() {
XRaiseWindow(x11_display,x11_window);
}
-void OS_X11::process_joysticks() {
- #ifndef __FreeBSD__
- int bytes;
- js_event events[32];
- InputEvent ievent;
- for (int i=0; i<JOYSTICKS_MAX; i++) {
-
- if (joysticks[i].fd == -1) {
- probe_joystick(i);
- if (joysticks[i].fd == -1)
- continue;
- };
- ievent.device = i;
-
- while ( (bytes = read(joysticks[i].fd, &events, sizeof(events))) > 0) {
-
- int ev_count = bytes / sizeof(js_event);
- for (int j=0; j<ev_count; j++) {
-
- js_event& event = events[j];
-
- //printf("got event on joystick %i, %i, %i, %i, %i\n", i, joysticks[i].fd, event.type, event.number, event.value);
- if (event.type & JS_EVENT_INIT)
- continue;
-
- switch (event.type & ~JS_EVENT_INIT) {
-
- case JS_EVENT_AXIS:
-
- //if (joysticks[i].last_axis[event.number] != event.value) {
-
- /*
- if (event.number==5 || event.number==6) {
-
- int axis=event.number-5;
- int val = event.value;
- if (val<0)
- val=-1;
- if (val>0)
- val=+1;
-
- InputEvent ev;
- ev.type = InputEvent::JOYSTICK_BUTTON;
- ev.ID = ++event_id;
-
-
- if (val!=dpad_last[axis]) {
-
- int prev_val = dpad_last[axis];
- if (prev_val!=0) {
-
- ev.joy_button.pressed=false;
- ev.joy_button.pressure=0.0;
- if (event.number==5)
- ev.joy_button.button_index=JOY_DPAD_LEFT+(prev_val+1)/2;
- if (event.number==6)
- ev.joy_button.button_index=JOY_DPAD_UP+(prev_val+1)/2;
-
- input->parse_input_event( ev );
- }
- }
-
- if (val!=0) {
-
- ev.joy_button.pressed=true;
- ev.joy_button.pressure=1.0;
- if (event.number==5)
- ev.joy_button.button_index=JOY_DPAD_LEFT+(val+1)/2;
- if (event.number==6)
- ev.joy_button.button_index=JOY_DPAD_UP+(val+1)/2;
-
- input->parse_input_event( ev );
- }
-
-
- dpad_last[axis]=val;
-
- }
- */
- //print_line("ev: "+itos(event.number)+" val: "+ rtos((float)event.value / (float)MAX_JOY_AXIS));
- //if (event.number >= JOY_AXIS_MAX)
- // break;
- //ERR_FAIL_COND(event.number >= JOY_AXIS_MAX);
- ievent.type = InputEvent::JOYSTICK_MOTION;
- ievent.ID = ++event_id;
- ievent.joy_motion.axis = event.number; //_pc_joystick_get_native_axis(event.number);
- ievent.joy_motion.axis_value = (float)event.value / (float)MAX_JOY_AXIS;
- if (event.number < JOY_AXIS_MAX)
- joysticks[i].last_axis[event.number] = event.value;
- input->parse_input_event( ievent );
- //};
- break;
-
- case JS_EVENT_BUTTON:
-
-
- ievent.type = InputEvent::JOYSTICK_BUTTON;
- ievent.ID = ++event_id;
- ievent.joy_button.button_index = event.number; // _pc_joystick_get_native_button(event.number);
- ievent.joy_button.pressed = event.value;
- input->parse_input_event( ievent );
- break;
- };
- };
- };
- if (bytes == 0 || (bytes < 0 && errno != EAGAIN)) {
- close_joystick(i);
- };
- };
- #endif
-};
-
-
void OS_X11::set_cursor_shape(CursorShape p_shape) {
ERR_FAIL_INDEX(p_shape,CURSOR_MAX);
@@ -1783,7 +1678,6 @@ void OS_X11::set_cursor_shape(CursorShape p_shape) {
XDefineCursor(x11_display,x11_window,cursors[CURSOR_ARROW]);
}
-
current_cursor=p_shape;
}
@@ -1804,8 +1698,20 @@ void OS_X11::swap_buffers() {
context_gl->swap_buffers();
}
+void OS_X11::alert(const String& p_alert,const String& p_title) {
+
+ List<String> args;
+ args.push_back("-center");
+ args.push_back("-title");
+ args.push_back(p_title);
+ args.push_back(p_alert);
+
+ execute("/usr/bin/xmessage",args,true);
+}
void OS_X11::set_icon(const Image& p_icon) {
+ Atom net_wm_icon = XInternAtom(x11_display, "_NET_WM_ICON", False);
+
if (!p_icon.empty()) {
Image img=p_icon;
img.convert(Image::FORMAT_RGBA);
@@ -1838,7 +1744,6 @@ void OS_X11::set_icon(const Image& p_icon) {
XDeleteProperty(x11_display, x11_window, net_wm_icon);
}
XFlush(x11_display);
-
}
@@ -1859,7 +1764,9 @@ void OS_X11::run() {
while (!force_quit) {
process_xevents(); // get rid of pending events
- process_joysticks();
+#ifdef JOYDEV_ENABLED
+ event_id = joystick->process_joysticks(event_id);
+#endif
if (Main::iteration()==true)
break;
};
@@ -1867,6 +1774,14 @@ void OS_X11::run() {
main_loop->finish();
}
+bool OS_X11::is_joy_known(int p_device) {
+ return input->is_joy_mapped(p_device);
+}
+
+String OS_X11::get_joy_guid(int p_device) const {
+ return input->get_joy_guid_remapped(p_device);
+}
+
OS_X11::OS_X11() {
#ifdef RTAUDIO_ENABLED
diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h
index 261a54dd25..91dbeac284 100644
--- a/platform/x11/os_x11.h
+++ b/platform/x11/os_x11.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -46,6 +46,8 @@
#include "drivers/pulseaudio/audio_driver_pulseaudio.h"
#include "servers/physics_2d/physics_2d_server_sw.h"
#include "servers/physics_2d/physics_2d_server_wrap_mt.h"
+#include "main/input_default.h"
+#include "joystick_linux.h"
#include <X11/keysym.h>
#include <X11/Xlib.h>
@@ -112,17 +114,22 @@ class OS_X11 : public OS_Unix {
bool force_quit;
bool minimized;
- int dpad_last[2];
+ bool do_mouse_warp;
const char *cursor_theme;
int cursor_size;
+ XcursorImage *img[CURSOR_MAX];
Cursor cursors[CURSOR_MAX];
Cursor null_cursor;
CursorShape current_cursor;
InputDefault *input;
+#ifdef JOYDEV_ENABLED
+ joystick_linux *joystick;
+#endif
+
#ifdef RTAUDIO_ENABLED
AudioDriverRtAudio driver_rtaudio;
#endif
@@ -135,32 +142,8 @@ class OS_X11 : public OS_Unix {
AudioDriverPulseAudio driver_pulseaudio;
#endif
- enum {
- JOYSTICKS_MAX = 8,
- MAX_JOY_AXIS = 32768, // I've no idea
- };
-
- struct Joystick {
-
- int fd;
- int last_axis[JOY_AXIS_MAX];
-
- Joystick() {
- fd = -1;
- for (int i=0; i<JOY_AXIS_MAX; i++) {
-
- last_axis[i] = 0;
- };
- };
- };
-
Atom net_wm_icon;
-
- int joystick_count;
-
- Joystick joysticks[JOYSTICKS_MAX];
-
int audio_driver_index;
unsigned int capture_idle;
bool maximized;
@@ -182,10 +165,6 @@ protected:
virtual void set_main_loop( MainLoop * p_main_loop );
- void probe_joystick(int p_id = -1);
- void process_joysticks();
- void close_joystick(int p_id = -1);
-
public:
@@ -242,6 +221,10 @@ public:
virtual bool is_window_maximized() const;
virtual void move_window_to_foreground();
+ virtual void alert(const String& p_alert,const String& p_title="ALERT!");
+
+ virtual bool is_joy_known(int p_device);
+ virtual String get_joy_guid(int p_device) const;
void run();
diff --git a/platform/x11/platform_config.h b/platform/x11/platform_config.h
index c01d0aa380..aac50c27c2 100644
--- a/platform/x11/platform_config.h
+++ b/platform/x11/platform_config.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,8 +29,9 @@
#ifdef __linux__
#include <alloca.h>
#endif
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
#include <stdlib.h>
+#define PTHREAD_BSD_SET_NAME
#endif
#define GLES2_INCLUDE_H "gl_context/glew.h"
diff --git a/scene/2d/SCsub b/scene/2d/SCsub
index 055d2f2474..bbe59b3054 100644
--- a/scene/2d/SCsub
+++ b/scene/2d/SCsub
@@ -3,5 +3,3 @@ Import('env')
env.add_source_files(env.scene_sources,"*.cpp")
Export('env')
-
-
diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp
index e350a34013..1ed508aed3 100644
--- a/scene/2d/animated_sprite.cpp
+++ b/scene/2d/animated_sprite.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -28,6 +28,8 @@
/*************************************************************************/
#include "animated_sprite.h"
#include "scene/scene_string_names.h"
+#include "os/os.h"
+
void AnimatedSprite::edit_set_pivot(const Point2& p_pivot) {
set_offset(p_pivot);
@@ -153,6 +155,9 @@ void AnimatedSprite::_notification(int p_what) {
if (centered)
ofs-=s/2;
+ if (OS::get_singleton()->get_use_pixel_snap()) {
+ ofs=ofs.floor();
+ }
Rect2 dst_rect(ofs,s);
if (hflip)
@@ -160,7 +165,8 @@ void AnimatedSprite::_notification(int p_what) {
if (vflip)
dst_rect.size.y=-dst_rect.size.y;
- texture->draw_rect(ci,dst_rect,false,modulate);
+ //texture->draw_rect(ci,dst_rect,false,modulate);
+ texture->draw_rect_region(ci,dst_rect,Rect2(Vector2(),texture->get_size()),modulate);
// VisualServer::get_singleton()->canvas_item_add_texture_rect_region(ci,dst_rect,texture->get_rid(),src_rect,modulate);
} break;
@@ -330,11 +336,11 @@ void AnimatedSprite::_bind_methods() {
ADD_PROPERTYNZ( PropertyInfo( Variant::OBJECT, "frames",PROPERTY_HINT_RESOURCE_TYPE,"SpriteFrames"), _SCS("set_sprite_frames"),_SCS("get_sprite_frames"));
ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "frame",PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"),_SCS("get_frame"));
- ADD_PROPERTY( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered"));
+ ADD_PROPERTYNO( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered"));
ADD_PROPERTYNZ( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset"));
- ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flip_h"), _SCS("set_flip_h"),_SCS("is_flipped_h"));
- ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flip_v"), _SCS("set_flip_v"),_SCS("is_flipped_v"));
- ADD_PROPERTY( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate"));
+ ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "flip_h"), _SCS("set_flip_h"),_SCS("is_flipped_h"));
+ ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "flip_v"), _SCS("set_flip_v"),_SCS("is_flipped_v"));
+ ADD_PROPERTYNO( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate"));
}
diff --git a/scene/2d/animated_sprite.h b/scene/2d/animated_sprite.h
index 425f516b14..da4f1b99af 100644
--- a/scene/2d/animated_sprite.h
+++ b/scene/2d/animated_sprite.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp
index f9e79e25bc..50a115174d 100644
--- a/scene/2d/area_2d.cpp
+++ b/scene/2d/area_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -383,7 +383,11 @@ void Area2D::_clear_monitoring() {
Object *obj = ObjectDB::get_instance(E->key());
Node *node = obj ? obj->cast_to<Node>() : NULL;
- ERR_CONTINUE(!node);
+
+ if (!node) //node may have been deleted in previous frame, this should not be an error
+ continue;
+ //ERR_CONTINUE(!node);
+
if (!E->get().in_tree)
continue;
@@ -416,20 +420,21 @@ void Area2D::_notification(int p_what) {
void Area2D::set_enable_monitoring(bool p_enable) {
- if (locked) {
- ERR_EXPLAIN("This function can't be used during the in/out signal.");
- }
- ERR_FAIL_COND(locked);
if (p_enable==monitoring)
return;
+ if (locked) {
+ ERR_EXPLAIN("Function blocked during in/out signal. Use call_deferred(\"set_enable_monitoring\",true/false)");
+ }
+ ERR_FAIL_COND(locked);
monitoring=p_enable;
if (monitoring) {
- Physics2DServer::get_singleton()->area_set_monitor_callback(get_rid(),this,"_body_inout");
- Physics2DServer::get_singleton()->area_set_area_monitor_callback(get_rid(),this,"_area_inout");
+ Physics2DServer::get_singleton()->area_set_monitor_callback(get_rid(),this,SceneStringNames::get_singleton()->_body_inout);
+ Physics2DServer::get_singleton()->area_set_area_monitor_callback(get_rid(),this,SceneStringNames::get_singleton()->_area_inout);
+
} else {
Physics2DServer::get_singleton()->area_set_monitor_callback(get_rid(),NULL,StringName());
Physics2DServer::get_singleton()->area_set_area_monitor_callback(get_rid(),NULL,StringName());
@@ -651,18 +656,18 @@ void Area2D::_bind_methods() {
ADD_SIGNAL( MethodInfo("area_exit",PropertyInfo(Variant::OBJECT,"area",PROPERTY_HINT_RESOURCE_TYPE,"Area2D")));
- ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"space_override",PROPERTY_HINT_ENUM,"Disabled,Combine,Replace"),_SCS("set_space_override_mode"),_SCS("get_space_override_mode"));
- ADD_PROPERTY( PropertyInfo(Variant::BOOL,"gravity_point"),_SCS("set_gravity_is_point"),_SCS("is_gravity_a_point"));
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"gravity_distance_scale", PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_gravity_distance_scale"),_SCS("get_gravity_distance_scale"));
+ ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"space_override",PROPERTY_HINT_ENUM,"Disabled,Combine,Combine-Replace,Replace,Replace-Combine"),_SCS("set_space_override_mode"),_SCS("get_space_override_mode"));
+ ADD_PROPERTYNZ( PropertyInfo(Variant::BOOL,"gravity_point"),_SCS("set_gravity_is_point"),_SCS("is_gravity_a_point"));
+ ADD_PROPERTYNZ( PropertyInfo(Variant::REAL,"gravity_distance_scale", PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_gravity_distance_scale"),_SCS("get_gravity_distance_scale"));
ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"gravity_vec"),_SCS("set_gravity_vector"),_SCS("get_gravity_vector"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"gravity",PROPERTY_HINT_RANGE,"-1024,1024,0.01"),_SCS("set_gravity"),_SCS("get_gravity"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"linear_damp",PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_linear_damp"),_SCS("get_linear_damp"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"angular_damp",PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_angular_damp"),_SCS("get_angular_damp"));
ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"priority",PROPERTY_HINT_RANGE,"0,128,1"),_SCS("set_priority"),_SCS("get_priority"));
- ADD_PROPERTY( PropertyInfo(Variant::BOOL,"monitoring"),_SCS("set_enable_monitoring"),_SCS("is_monitoring_enabled"));
- ADD_PROPERTY( PropertyInfo(Variant::BOOL,"monitorable"),_SCS("set_monitorable"),_SCS("is_monitorable"));
- ADD_PROPERTY( PropertyInfo(Variant::INT,"collision/layers",PROPERTY_HINT_ALL_FLAGS),_SCS("set_layer_mask"),_SCS("get_layer_mask"));
- ADD_PROPERTY( PropertyInfo(Variant::INT,"collision/mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_collision_mask"),_SCS("get_collision_mask"));
+ ADD_PROPERTYNO( PropertyInfo(Variant::BOOL,"monitoring"),_SCS("set_enable_monitoring"),_SCS("is_monitoring_enabled"));
+ ADD_PROPERTYNO( PropertyInfo(Variant::BOOL,"monitorable"),_SCS("set_monitorable"),_SCS("is_monitorable"));
+ ADD_PROPERTYNO( PropertyInfo(Variant::INT,"collision/layers",PROPERTY_HINT_ALL_FLAGS),_SCS("set_layer_mask"),_SCS("get_layer_mask"));
+ ADD_PROPERTYNO( PropertyInfo(Variant::INT,"collision/mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_collision_mask"),_SCS("get_collision_mask"));
}
diff --git a/scene/2d/area_2d.h b/scene/2d/area_2d.h
index f5a88390e7..7f3f9c93cf 100644
--- a/scene/2d/area_2d.h
+++ b/scene/2d/area_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -40,7 +40,9 @@ public:
enum SpaceOverride {
SPACE_OVERRIDE_DISABLED,
SPACE_OVERRIDE_COMBINE,
- SPACE_OVERRIDE_REPLACE
+ SPACE_OVERRIDE_COMBINE_REPLACE,
+ SPACE_OVERRIDE_REPLACE,
+ SPACE_OVERRIDE_REPLACE_COMBINE
};
private:
diff --git a/scene/2d/back_buffer_copy.cpp b/scene/2d/back_buffer_copy.cpp
index 245b3ba7eb..7a138830db 100644
--- a/scene/2d/back_buffer_copy.cpp
+++ b/scene/2d/back_buffer_copy.cpp
@@ -4,7 +4,7 @@ void BackBufferCopy::_update_copy_mode() {
switch(copy_mode) {
- case COPY_MODE_DISALED: {
+ case COPY_MODE_DISABLED: {
VS::get_singleton()->canvas_item_set_copy_to_backbuffer(get_canvas_item(),false,Rect2());
} break;
@@ -58,7 +58,7 @@ void BackBufferCopy::_bind_methods() {
ADD_PROPERTY( PropertyInfo(Variant::INT,"copy_mode",PROPERTY_HINT_ENUM,"Disabled,Rect,Viewport"),_SCS("set_copy_mode"),_SCS("get_copy_mode"));
ADD_PROPERTY( PropertyInfo(Variant::RECT2,"rect"),_SCS("set_rect"),_SCS("get_rect"));
- BIND_CONSTANT( COPY_MODE_DISALED );
+ BIND_CONSTANT( COPY_MODE_DISABLED );
BIND_CONSTANT( COPY_MODE_RECT );
BIND_CONSTANT( COPY_MODE_VIEWPORT );
diff --git a/scene/2d/back_buffer_copy.h b/scene/2d/back_buffer_copy.h
index 3a86ffa309..734cad458a 100644
--- a/scene/2d/back_buffer_copy.h
+++ b/scene/2d/back_buffer_copy.h
@@ -7,7 +7,7 @@ class BackBufferCopy : public Node2D {
OBJ_TYPE( BackBufferCopy,Node2D);
public:
enum CopyMode {
- COPY_MODE_DISALED,
+ COPY_MODE_DISABLED,
COPY_MODE_RECT,
COPY_MODE_VIEWPORT
};
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index 49683da226..67c1733759 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -57,7 +57,9 @@ void Camera2D::_update_scroll() {
void Camera2D::set_zoom(const Vector2 &p_zoom) {
zoom = p_zoom;
+ Point2 old_smoothed_camera_pos = smoothed_camera_pos;
_update_scroll();
+ smoothed_camera_pos = old_smoothed_camera_pos;
};
Vector2 Camera2D::get_zoom() const {
@@ -116,10 +118,10 @@ Matrix32 Camera2D::get_camera_transform() {
- if (smoothing>0.0) {
+ if (smoothing_enabled) {
float c = smoothing*get_fixed_process_delta_time();
- smoothed_camera_pos = ((new_camera_pos-smoothed_camera_pos)*c)+smoothed_camera_pos;
+ smoothed_camera_pos = ((camera_pos-smoothed_camera_pos)*c)+smoothed_camera_pos;
ret_camera_pos=smoothed_camera_pos;
// camera_pos=camera_pos*(1.0-smoothing)+new_camera_pos*smoothing;
} else {
@@ -438,6 +440,27 @@ float Camera2D::get_h_offset() const{
}
+void Camera2D::_set_old_smoothing(float p_val) {
+ //compatibility
+ if (p_val>0) {
+ smoothing_enabled=true;
+ set_follow_smoothing(p_val);
+ }
+
+}
+
+void Camera2D::set_enable_follow_smoothing(bool p_enabled) {
+
+ smoothing_enabled=p_enabled;
+
+}
+
+bool Camera2D::is_follow_smoothing_enabled() const {
+
+ return smoothing_enabled;
+}
+
+
void Camera2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_offset","offset"),&Camera2D::set_offset);
@@ -480,21 +503,24 @@ void Camera2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_camera_pos"),&Camera2D::get_camera_pos);
ObjectTypeDB::bind_method(_MD("get_camera_screen_center"),&Camera2D::get_camera_screen_center);
- ObjectTypeDB::bind_method(_MD("set_zoom"),&Camera2D::set_zoom);
+ ObjectTypeDB::bind_method(_MD("set_zoom","zoom"),&Camera2D::set_zoom);
ObjectTypeDB::bind_method(_MD("get_zoom"),&Camera2D::get_zoom);
ObjectTypeDB::bind_method(_MD("set_follow_smoothing","follow_smoothing"),&Camera2D::set_follow_smoothing);
ObjectTypeDB::bind_method(_MD("get_follow_smoothing"),&Camera2D::get_follow_smoothing);
+ ObjectTypeDB::bind_method(_MD("set_enable_follow_smoothing","follow_smoothing"),&Camera2D::set_enable_follow_smoothing);
+ ObjectTypeDB::bind_method(_MD("is_follow_smoothing_enabled"),&Camera2D::is_follow_smoothing_enabled);
+
ObjectTypeDB::bind_method(_MD("force_update_scroll"),&Camera2D::force_update_scroll);
+ ObjectTypeDB::bind_method(_MD("_set_old_smoothing","follow_smoothing"),&Camera2D::_set_old_smoothing);
ADD_PROPERTYNZ( PropertyInfo(Variant::VECTOR2,"offset"),_SCS("set_offset"),_SCS("get_offset"));
ADD_PROPERTY( PropertyInfo(Variant::INT,"anchor_mode",PROPERTY_HINT_ENUM,"Fixed TopLeft,Drag Center"),_SCS("set_anchor_mode"),_SCS("get_anchor_mode"));
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"rotating"),_SCS("set_rotating"),_SCS("is_rotating"));
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"current"),_SCS("_set_current"),_SCS("is_current"));
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"smoothing"),_SCS("set_follow_smoothing"),_SCS("get_follow_smoothing") );
ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"zoom"),_SCS("set_zoom"),_SCS("get_zoom") );
ADD_PROPERTYI( PropertyInfo(Variant::INT,"limit/left"),_SCS("set_limit"),_SCS("get_limit"),MARGIN_LEFT);
@@ -505,6 +531,12 @@ void Camera2D::_bind_methods() {
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"drag_margin/h_enabled"),_SCS("set_h_drag_enabled"),_SCS("is_h_drag_enabled") );
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"drag_margin/v_enabled"),_SCS("set_v_drag_enabled"),_SCS("is_v_drag_enabled") );
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"smoothing/enable"),_SCS("set_enable_follow_smoothing"),_SCS("is_follow_smoothing_enabled") );
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"smoothing/speed"),_SCS("set_follow_smoothing"),_SCS("get_follow_smoothing") );
+
+ //compatibility
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"smoothing",PROPERTY_HINT_NONE,"",0),_SCS("_set_old_smoothing"),_SCS("get_follow_smoothing") );
+
ADD_PROPERTYI( PropertyInfo(Variant::REAL,"drag_margin/left",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_drag_margin"),_SCS("get_drag_margin"),MARGIN_LEFT);
ADD_PROPERTYI( PropertyInfo(Variant::REAL,"drag_margin/top",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_drag_margin"),_SCS("get_drag_margin"),MARGIN_TOP);
ADD_PROPERTYI( PropertyInfo(Variant::REAL,"drag_margin/right",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_drag_margin"),_SCS("get_drag_margin"),MARGIN_RIGHT);
@@ -533,8 +565,9 @@ Camera2D::Camera2D() {
drag_margin[MARGIN_BOTTOM]=0.2;
camera_pos=Vector2();
first=true;
+ smoothing_enabled=false;
- smoothing=0.0;
+ smoothing=5.0;
zoom = Vector2(1, 1);
h_drag_enabled=true;
diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h
index 79d84f48d0..3c51bbf220 100644
--- a/scene/2d/camera_2d.h
+++ b/scene/2d/camera_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -59,6 +59,7 @@ protected:
bool rotating;
bool current;
float smoothing;
+ bool smoothing_enabled;
int limit[4];
float drag_margin[4];
@@ -73,6 +74,8 @@ protected:
void _make_current(Object *p_which);
void _set_current(bool p_current);
+
+ void _set_old_smoothing(float p_enable);
protected:
virtual Matrix32 get_camera_transform();
@@ -108,6 +111,9 @@ public:
void set_h_offset(float p_offset);
float get_h_offset() const;
+ void set_enable_follow_smoothing(bool p_enabled);
+ bool is_follow_smoothing_enabled() const;
+
void set_follow_smoothing(float p_speed);
float get_follow_smoothing() const;
diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp
index 6a1ea0728d..35b453d71d 100644
--- a/scene/2d/canvas_item.cpp
+++ b/scene/2d/canvas_item.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -265,7 +265,7 @@ void CanvasItem::_propagate_visibility_changed(bool p_visible) {
CanvasItem *c=get_child(i)->cast_to<CanvasItem>();
- if (c && c->hidden!=p_visible) //should the toplevels stop propagation? i think so but..
+ if (c && !c->hidden) //should the toplevels stop propagation? i think so but..
c->_propagate_visibility_changed(p_visible);
}
@@ -309,6 +309,15 @@ void CanvasItem::hide() {
_change_notify("visibility/visible");
}
+void CanvasItem::set_hidden(bool p_hidden) {
+
+ if (hidden == p_hidden) {
+ return;
+ }
+
+ _set_visible_(!p_hidden);
+}
+
Variant CanvasItem::edit_get_state() const {
@@ -380,8 +389,8 @@ Matrix32 CanvasItem::get_global_transform_with_canvas() const {
if (last_valid->canvas_layer)
return last_valid->canvas_layer->get_transform() * xform;
- else
- return xform;
+ else if (is_inside_tree())
+ return get_viewport()->get_canvas_transform() * xform;
}
Matrix32 CanvasItem::get_global_transform() const {
@@ -539,6 +548,7 @@ void CanvasItem::_notification(int p_what) {
get_parent()->cast_to<CanvasItem>()->children_items.erase(C);
C=NULL;
}
+ global_invalid=true;
} break;
case NOTIFICATION_DRAW: {
@@ -700,7 +710,7 @@ void CanvasItem::draw_circle(const Point2& p_pos, float p_radius, const Color& p
}
-void CanvasItem::draw_texture(const Ref<Texture>& p_texture,const Point2& p_pos) {
+void CanvasItem::draw_texture(const Ref<Texture>& p_texture,const Point2& p_pos,const Color& p_modulate) {
if (!drawing) {
ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
@@ -709,7 +719,7 @@ void CanvasItem::draw_texture(const Ref<Texture>& p_texture,const Point2& p_pos)
ERR_FAIL_COND(p_texture.is_null());
- p_texture->draw(canvas_item,p_pos);
+ p_texture->draw(canvas_item,p_pos,p_modulate);
}
void CanvasItem::draw_texture_rect(const Ref<Texture>& p_texture,const Rect2& p_rect, bool p_tile,const Color& p_modulate, bool p_transpose) {
@@ -764,7 +774,7 @@ void CanvasItem::draw_set_transform(const Point2& p_offset, float p_rot, const S
Matrix32 xform(p_rot,p_offset);
xform.scale_basis(p_scale);
- VisualServer::get_singleton()->canvas_item_set_transform(canvas_item,xform);
+ VisualServer::get_singleton()->canvas_item_add_set_transform(canvas_item,xform);
}
void CanvasItem::draw_polygon(const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs, Ref<Texture> p_texture) {
@@ -1043,6 +1053,7 @@ void CanvasItem::_bind_methods() {
ObjectTypeDB::bind_method(_MD("is_hidden"),&CanvasItem::is_hidden);
ObjectTypeDB::bind_method(_MD("show"),&CanvasItem::show);
ObjectTypeDB::bind_method(_MD("hide"),&CanvasItem::hide);
+ ObjectTypeDB::bind_method(_MD("set_hidden","hidden"),&CanvasItem::set_hidden);
ObjectTypeDB::bind_method(_MD("update"),&CanvasItem::update);
@@ -1070,9 +1081,9 @@ void CanvasItem::_bind_methods() {
ObjectTypeDB::bind_method(_MD("draw_line","from","to","color","width"),&CanvasItem::draw_line,DEFVAL(1.0));
ObjectTypeDB::bind_method(_MD("draw_rect","rect","color"),&CanvasItem::draw_rect);
ObjectTypeDB::bind_method(_MD("draw_circle","pos","radius","color"),&CanvasItem::draw_circle);
- ObjectTypeDB::bind_method(_MD("draw_texture","texture:Texture","pos"),&CanvasItem::draw_texture);
- ObjectTypeDB::bind_method(_MD("draw_texture_rect","texture:Texture","rect","tile","modulate"),&CanvasItem::draw_texture_rect,DEFVAL(false),DEFVAL(Color(1,1,1)));
- ObjectTypeDB::bind_method(_MD("draw_texture_rect_region","texture:Texture","rect","src_rect","modulate"),&CanvasItem::draw_texture_rect_region,DEFVAL(Color(1,1,1)));
+ ObjectTypeDB::bind_method(_MD("draw_texture","texture:Texture","pos","modulate"),&CanvasItem::draw_texture,DEFVAL(Color(1,1,1,1)));
+ ObjectTypeDB::bind_method(_MD("draw_texture_rect","texture:Texture","rect","tile","modulate","transpose"),&CanvasItem::draw_texture_rect,DEFVAL(Color(1,1,1)),DEFVAL(false));
+ ObjectTypeDB::bind_method(_MD("draw_texture_rect_region","texture:Texture","rect","src_rect","modulate","transpose"),&CanvasItem::draw_texture_rect_region,DEFVAL(Color(1,1,1)),DEFVAL(false));
ObjectTypeDB::bind_method(_MD("draw_style_box","style_box:StyleBox","rect"),&CanvasItem::draw_style_box);
ObjectTypeDB::bind_method(_MD("draw_primitive","points","colors","uvs","texture:Texture","width"),&CanvasItem::draw_primitive,DEFVAL(Array()),DEFVAL(Ref<Texture>()),DEFVAL(1.0));
ObjectTypeDB::bind_method(_MD("draw_polygon","points","colors","uvs","texture:Texture"),&CanvasItem::draw_polygon,DEFVAL(Array()),DEFVAL(Ref<Texture>()));
@@ -1103,14 +1114,14 @@ void CanvasItem::_bind_methods() {
BIND_VMETHOD(MethodInfo("_draw"));
- ADD_PROPERTY( PropertyInfo(Variant::BOOL,"visibility/visible"), _SCS("_set_visible_"),_SCS("_is_visible_") );
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"visibility/opacity",PROPERTY_HINT_RANGE, "0,1,0.01"), _SCS("set_opacity"),_SCS("get_opacity") );
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"visibility/self_opacity",PROPERTY_HINT_RANGE, "0,1,0.01"), _SCS("set_self_opacity"),_SCS("get_self_opacity") );
+ ADD_PROPERTYNO( PropertyInfo(Variant::BOOL,"visibility/visible"), _SCS("_set_visible_"),_SCS("_is_visible_") );
+ ADD_PROPERTYNO( PropertyInfo(Variant::REAL,"visibility/opacity",PROPERTY_HINT_RANGE, "0,1,0.01"), _SCS("set_opacity"),_SCS("get_opacity") );
+ ADD_PROPERTYNO( PropertyInfo(Variant::REAL,"visibility/self_opacity",PROPERTY_HINT_RANGE, "0,1,0.01"), _SCS("set_self_opacity"),_SCS("get_self_opacity") );
ADD_PROPERTYNZ( PropertyInfo(Variant::BOOL,"visibility/behind_parent"), _SCS("set_draw_behind_parent"),_SCS("is_draw_behind_parent_enabled") );
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"visibility/on_top",PROPERTY_HINT_NONE,"",0), _SCS("_set_on_top"),_SCS("_is_on_top") ); //compatibility
ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"visibility/blend_mode",PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul,PMAlpha"), _SCS("set_blend_mode"),_SCS("get_blend_mode") );
- ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"visibility/light_mask",PROPERTY_HINT_ALL_FLAGS), _SCS("set_light_mask"),_SCS("get_light_mask") );
+ ADD_PROPERTYNO( PropertyInfo(Variant::INT,"visibility/light_mask",PROPERTY_HINT_ALL_FLAGS), _SCS("set_light_mask"),_SCS("get_light_mask") );
ADD_PROPERTYNZ( PropertyInfo(Variant::OBJECT,"material/material",PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemMaterial"), _SCS("set_material"),_SCS("get_material") );
ADD_PROPERTYNZ( PropertyInfo(Variant::BOOL,"material/use_parent"), _SCS("set_use_parent_material"),_SCS("get_use_parent_material") );
//exporting these two things doesn't really make much sense i think
@@ -1146,6 +1157,8 @@ Matrix32 CanvasItem::get_canvas_transform() const {
if (canvas_layer)
return canvas_layer->get_transform();
+ else if (get_parent()->cast_to<CanvasItem>())
+ return get_parent()->cast_to<CanvasItem>()->get_canvas_transform();
else
return get_viewport()->get_canvas_transform();
@@ -1172,6 +1185,14 @@ Matrix32 CanvasItem::get_viewport_transform() const {
}
+void CanvasItem::set_notify_local_transform(bool p_enable) {
+ notify_local_transform=p_enable;
+}
+
+bool CanvasItem::is_local_transform_notification_enabled() const {
+ return notify_local_transform;
+}
+
CanvasItem::CanvasItem() : xform_change(this) {
@@ -1191,6 +1212,7 @@ CanvasItem::CanvasItem() : xform_change(this) {
canvas_layer=NULL;
use_parent_material=false;
global_invalid=true;
+ notify_local_transform=false;
light_mask=1;
C=NULL;
diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h
index 6d8308dbe4..5d10523261 100644
--- a/scene/2d/canvas_item.h
+++ b/scene/2d/canvas_item.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -126,6 +126,7 @@ private:
bool block_transform_notify;
bool behind;
bool use_parent_material;
+ bool notify_local_transform;
Ref<CanvasItemMaterial> material;
@@ -155,7 +156,7 @@ private:
protected:
- _FORCE_INLINE_ void _notify_transform() { if (!is_inside_tree()) return; _notify_transform(this); if (!block_transform_notify) notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); }
+ _FORCE_INLINE_ void _notify_transform() { if (!is_inside_tree()) return; _notify_transform(this); if (!block_transform_notify && notify_local_transform) notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); }
void item_rect_changed();
@@ -189,13 +190,14 @@ public:
bool is_hidden() const;
void show();
void hide();
+ void set_hidden(bool p_hidden);
void update();
void set_blend_mode(BlendMode p_blend_mode);
BlendMode get_blend_mode() const;
- void set_light_mask(int p_light_mask);
+ virtual void set_light_mask(int p_light_mask);
int get_light_mask() const;
void set_opacity(float p_opacity);
@@ -209,7 +211,7 @@ public:
void draw_line(const Point2& p_from, const Point2& p_to,const Color& p_color,float p_width=1.0);
void draw_rect(const Rect2& p_rect, const Color& p_color);
void draw_circle(const Point2& p_pos, float p_radius, const Color& p_color);
- void draw_texture(const Ref<Texture>& p_texture,const Point2& p_pos);
+ void draw_texture(const Ref<Texture>& p_texture, const Point2& p_pos, const Color &p_modulate=Color(1,1,1,1));
void draw_texture_rect(const Ref<Texture>& p_texture, const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1), bool p_transpose=false);
void draw_texture_rect_region(const Ref<Texture>& p_texture,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1), bool p_transpose=false);
void draw_style_box(const Ref<StyleBox>& p_style_box,const Rect2& p_rect);
@@ -263,6 +265,10 @@ public:
Vector2 get_global_mouse_pos() const;
Vector2 get_local_mouse_pos() const;
+ void set_notify_local_transform(bool p_enable);
+ bool is_local_transform_notification_enabled() const;
+
+
CanvasItem();
~CanvasItem();
};
diff --git a/scene/2d/canvas_modulate.cpp b/scene/2d/canvas_modulate.cpp
index 82dd8012a5..77203a7110 100644
--- a/scene/2d/canvas_modulate.cpp
+++ b/scene/2d/canvas_modulate.cpp
@@ -5,10 +5,19 @@ void CanvasModulate::_notification(int p_what) {
if (p_what==NOTIFICATION_ENTER_CANVAS) {
- VS::get_singleton()->canvas_set_modulate(get_canvas(),color);
+ if (is_visible())
+ VS::get_singleton()->canvas_set_modulate(get_canvas(),color);
} else if (p_what==NOTIFICATION_EXIT_CANVAS) {
- VS::get_singleton()->canvas_set_modulate(get_canvas(),Color(1,1,1,1));
+ if (is_visible())
+ VS::get_singleton()->canvas_set_modulate(get_canvas(),Color(1,1,1,1));
+ } else if (p_what==NOTIFICATION_VISIBILITY_CHANGED) {
+
+ if (is_visible()) {
+ VS::get_singleton()->canvas_set_modulate(get_canvas(),color);
+ } else {
+ VS::get_singleton()->canvas_set_modulate(get_canvas(),Color(1,1,1,1));
+ }
}
}
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index f577b81598..9b0c24ffd6 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -115,19 +115,16 @@ void CollisionObject2D::_update_shapes() {
bool CollisionObject2D::_set(const StringName& p_name, const Variant& p_value) {
String name=p_name;
- if (name=="shape_count") {
+ if (name.begins_with("shapes/")) {
- shapes.resize(p_value);
- _update_shapes();
- _change_notify();
-
- } else if (name.begins_with("shapes/")) {
-
- int idx=name.get_slice("/",1).to_int();
- String what=name.get_slice("/",2);
- if (what=="shape")
- set_shape(idx,RefPtr(p_value));
- else if (what=="transform")
+ int idx=name.get_slicec('/',1).to_int();
+ String what=name.get_slicec('/',2);
+ if (what=="shape") {
+ if (idx>=shapes.size())
+ add_shape(RefPtr(p_value));
+ else
+ set_shape(idx,RefPtr(p_value));
+ } else if (what=="transform")
set_shape_transform(idx,p_value);
else if (what=="trigger")
set_shape_as_trigger(idx,p_value);
@@ -143,12 +140,10 @@ bool CollisionObject2D::_get(const StringName& p_name,Variant &r_ret) const {
String name=p_name;
- if (name=="shape_count") {
- r_ret= shapes.size();
- } else if (name.begins_with("shapes/")) {
+ if (name.begins_with("shapes/")) {
- int idx=name.get_slice("/",1).to_int();
- String what=name.get_slice("/",2);
+ int idx=name.get_slicec('/',1).to_int();
+ String what=name.get_slicec('/',2);
if (what=="shape")
r_ret= get_shape(idx);
else if (what=="transform")
@@ -163,7 +158,7 @@ bool CollisionObject2D::_get(const StringName& p_name,Variant &r_ret) const {
void CollisionObject2D::_get_property_list( List<PropertyInfo> *p_list) const {
- p_list->push_back( PropertyInfo(Variant::INT,"shape_count",PROPERTY_HINT_RANGE,"0,256,1",PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_NO_INSTANCE_STATE) );
+ //p_list->push_back( PropertyInfo(Variant::INT,"shape_count",PROPERTY_HINT_RANGE,"0,256,1",PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_NO_INSTANCE_STATE) );
for(int i=0;i<shapes.size();i++) {
String path="shapes/"+itos(i)+"/";
@@ -254,12 +249,19 @@ void CollisionObject2D::_bind_methods() {
void CollisionObject2D::add_shape(const Ref<Shape2D>& p_shape, const Matrix32& p_transform) {
+ ERR_FAIL_COND(p_shape.is_null());
+
ShapeData sdata;
sdata.shape=p_shape;
sdata.xform=p_transform;
sdata.trigger=false;
- shapes.push_back(sdata);
- _update_shapes();
+
+ if (area)
+ Physics2DServer::get_singleton()->area_add_shape(get_rid(),p_shape->get_rid(),p_transform);
+ else
+ Physics2DServer::get_singleton()->body_add_shape(get_rid(),p_shape->get_rid(),p_transform);
+
+ shapes.push_back(sdata);
}
int CollisionObject2D::get_shape_count() const {
@@ -270,8 +272,15 @@ int CollisionObject2D::get_shape_count() const {
void CollisionObject2D::set_shape(int p_shape_idx, const Ref<Shape2D>& p_shape) {
ERR_FAIL_INDEX(p_shape_idx,shapes.size());
+ ERR_FAIL_COND(p_shape.is_null());
+
shapes[p_shape_idx].shape=p_shape;
- _update_shapes();
+ if (area)
+ Physics2DServer::get_singleton()->area_set_shape(get_rid(),p_shape_idx,p_shape->get_rid());
+ else
+ Physics2DServer::get_singleton()->body_set_shape(get_rid(),p_shape_idx,p_shape->get_rid());
+
+// _update_shapes();
}
void CollisionObject2D::set_shape_transform(int p_shape_idx, const Matrix32& p_transform) {
@@ -279,7 +288,12 @@ void CollisionObject2D::set_shape_transform(int p_shape_idx, const Matrix32& p_t
ERR_FAIL_INDEX(p_shape_idx,shapes.size());
shapes[p_shape_idx].xform=p_transform;
- _update_shapes();
+ if (area)
+ Physics2DServer::get_singleton()->area_set_shape_transform(get_rid(),p_shape_idx,p_transform);
+ else
+ Physics2DServer::get_singleton()->body_set_shape_transform(get_rid(),p_shape_idx,p_transform);
+
+// _update_shapes();
}
Ref<Shape2D> CollisionObject2D::get_shape(int p_shape_idx) const {
diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h
index 473f13d0ff..fc50c5c7cd 100644
--- a/scene/2d/collision_object_2d.h
+++ b/scene/2d/collision_object_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp
index ceea41d1c8..2a40a6207d 100644
--- a/scene/2d/collision_polygon_2d.cpp
+++ b/scene/2d/collision_polygon_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,10 +30,10 @@
#include "collision_object_2d.h"
#include "scene/resources/concave_polygon_shape_2d.h"
#include "scene/resources/convex_polygon_shape_2d.h"
-
+#include "triangulator.h"
void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) {
- if (unparenting)
+ if (unparenting || !can_update_body)
return;
CollisionObject2D *co = p_obj->cast_to<CollisionObject2D>();
@@ -48,7 +48,8 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) {
//here comes the sun, lalalala
//decompose concave into multiple convex polygons and add them
- Vector< Vector<Vector2> > decomp = Geometry::decompose_polygon(polygon);
+ Vector< Vector<Vector2> > decomp = _decompose_in_convex();
+ shape_from=co->get_shape_count();
for(int i=0;i<decomp.size();i++) {
Ref<ConvexPolygonShape2D> convex = memnew( ConvexPolygonShape2D );
convex->set_points(decomp[i]);
@@ -57,6 +58,11 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) {
co->set_shape_as_trigger(co->get_shape_count()-1,true);
}
+ shape_to=co->get_shape_count()-1;
+ if (shape_to<shape_from) {
+ shape_from=-1;
+ shape_to=-1;
+ }
} else {
@@ -78,6 +84,9 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) {
if (trigger)
co->set_shape_as_trigger(co->get_shape_count()-1,true);
+ shape_from=co->get_shape_count()-1;
+ shape_to=co->get_shape_count()-1;
+
}
@@ -86,6 +95,8 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) {
void CollisionPolygon2D::_update_parent() {
+ if (!can_update_body)
+ return;
Node *parent = get_parent();
if (!parent)
return;
@@ -95,39 +106,113 @@ void CollisionPolygon2D::_update_parent() {
co->_update_shapes_from_children();
}
+Vector< Vector<Vector2> > CollisionPolygon2D::_decompose_in_convex() {
+
+ Vector< Vector<Vector2> > decomp;
+#if 0
+ //fast but imprecise triangulator, gave us problems
+ decomp = Geometry::decompose_polygon(polygon);
+#else
+
+ List<TriangulatorPoly> in_poly,out_poly;
+
+ TriangulatorPoly inp;
+ inp.Init(polygon.size());
+ for(int i=0;i<polygon.size();i++) {
+ inp.GetPoint(i)=polygon[i];
+ }
+ inp.SetOrientation(TRIANGULATOR_CCW);
+ in_poly.push_back(inp);
+ TriangulatorPartition tpart;
+ if (tpart.ConvexPartition_HM(&in_poly,&out_poly)==0) { //failed!
+ ERR_PRINT("Convex decomposing failed!");
+ return decomp;
+ }
+
+ decomp.resize(out_poly.size());
+ int idx=0;
+
+ for(List<TriangulatorPoly>::Element*I = out_poly.front();I;I=I->next()) {
+
+ TriangulatorPoly& tp = I->get();
+
+ decomp[idx].resize(tp.GetNumPoints());
+
+ for(int i=0;i<tp.GetNumPoints();i++) {
+
+ decomp[idx][i]=tp.GetPoint(i);
+ }
+
+ idx++;
+ }
+
+#endif
+
+ return decomp;
+}
+
void CollisionPolygon2D::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_ENTER_TREE: {
unparenting=false;
+ can_update_body=get_tree()->is_editor_hint();
+ if (!get_tree()->is_editor_hint()) {
+ //display above all else
+ set_z_as_relative(false);
+ set_z(VS::CANVAS_ITEM_Z_MAX-1);
+ }
+
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+ can_update_body=false;
} break;
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
if (!is_inside_tree())
break;
- _update_parent();
+ if (can_update_body) {
+ _update_parent();
+ } else if (shape_from>=0 && shape_to>=0) {
+ CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>();
+ for(int i=shape_from;i<=shape_to;i++) {
+ co->set_shape_transform(i,get_transform());
+ }
+ }
+
} break;
case NOTIFICATION_DRAW: {
+
+ if (!get_tree()->is_editor_hint() && !get_tree()->is_debugging_collisions_hint()) {
+ break;
+ }
+
+
for(int i=0;i<polygon.size();i++) {
Vector2 p = polygon[i];
Vector2 n = polygon[(i+1)%polygon.size()];
- draw_line(p,n,Color(0,0.6,0.7,0.5),3);
+ draw_line(p,n,Color(0.9,0.2,0.0,0.8),3);
}
-
- Vector< Vector<Vector2> > decomp = Geometry::decompose_polygon(polygon);
#define DEBUG_DECOMPOSE
-#ifdef DEBUG_DECOMPOSE
+#if defined(TOOLS_ENABLED) && defined (DEBUG_DECOMPOSE)
+
+ Vector< Vector<Vector2> > decomp = _decompose_in_convex();
+
Color c(0.4,0.9,0.1);
for(int i=0;i<decomp.size();i++) {
c.set_hsv( Math::fmod(c.get_h() + 0.738,1),c.get_s(),c.get_v(),0.5);
draw_colored_polygon(decomp[i],c);
}
+#else
+ draw_colored_polygon(polygon,get_tree()->get_debug_collisions_color());
#endif
+
+
} break;
case NOTIFICATION_UNPARENTED: {
unparenting = true;
@@ -141,20 +226,22 @@ void CollisionPolygon2D::set_polygon(const Vector<Point2>& p_polygon) {
polygon=p_polygon;
- for(int i=0;i<polygon.size();i++) {
- if (i==0)
- aabb=Rect2(polygon[i],Size2());
- else
- aabb.expand_to(polygon[i]);
- }
- if (aabb==Rect2()) {
+ if (can_update_body) {
+ for(int i=0;i<polygon.size();i++) {
+ if (i==0)
+ aabb=Rect2(polygon[i],Size2());
+ else
+ aabb.expand_to(polygon[i]);
+ }
+ if (aabb==Rect2()) {
- aabb=Rect2(-10,-10,20,20);
- } else {
- aabb.pos-=aabb.size*0.3;
- aabb.size+=aabb.size*0.6;
+ aabb=Rect2(-10,-10,20,20);
+ } else {
+ aabb.pos-=aabb.size*0.3;
+ aabb.size+=aabb.size*0.6;
+ }
+ _update_parent();
}
- _update_parent();
update();
}
@@ -184,6 +271,13 @@ void CollisionPolygon2D::set_trigger(bool p_trigger) {
trigger=p_trigger;
_update_parent();
+ if (!can_update_body && is_inside_tree() && shape_from>=0 && shape_to>=0) {
+ CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>();
+ for(int i=shape_from;i<=shape_to;i++) {
+ co->set_shape_as_trigger(i,p_trigger);
+ }
+
+ }
}
bool CollisionPolygon2D::is_trigger() const{
@@ -192,21 +286,40 @@ bool CollisionPolygon2D::is_trigger() const{
}
+void CollisionPolygon2D::_set_shape_range(const Vector2& p_range) {
+
+ shape_from=p_range.x;
+ shape_to=p_range.y;
+}
+
+Vector2 CollisionPolygon2D::_get_shape_range() const {
+
+ return Vector2(shape_from,shape_to);
+}
+
void CollisionPolygon2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_add_to_collision_object"),&CollisionPolygon2D::_add_to_collision_object);
ObjectTypeDB::bind_method(_MD("set_polygon","polygon"),&CollisionPolygon2D::set_polygon);
ObjectTypeDB::bind_method(_MD("get_polygon"),&CollisionPolygon2D::get_polygon);
- ObjectTypeDB::bind_method(_MD("set_build_mode"),&CollisionPolygon2D::set_build_mode);
+ ObjectTypeDB::bind_method(_MD("set_build_mode","build_mode"),&CollisionPolygon2D::set_build_mode);
ObjectTypeDB::bind_method(_MD("get_build_mode"),&CollisionPolygon2D::get_build_mode);
- ObjectTypeDB::bind_method(_MD("set_trigger"),&CollisionPolygon2D::set_trigger);
+ ObjectTypeDB::bind_method(_MD("set_trigger","trigger"),&CollisionPolygon2D::set_trigger);
ObjectTypeDB::bind_method(_MD("is_trigger"),&CollisionPolygon2D::is_trigger);
+ ObjectTypeDB::bind_method(_MD("_set_shape_range","shape_range"),&CollisionPolygon2D::_set_shape_range);
+ ObjectTypeDB::bind_method(_MD("_get_shape_range"),&CollisionPolygon2D::_get_shape_range);
+
+ ObjectTypeDB::bind_method(_MD("get_collision_object_first_shape"),&CollisionPolygon2D::get_collision_object_first_shape);
+ ObjectTypeDB::bind_method(_MD("get_collision_object_last_shape"),&CollisionPolygon2D::get_collision_object_last_shape);
+
ADD_PROPERTY( PropertyInfo(Variant::INT,"build_mode",PROPERTY_HINT_ENUM,"Solids,Segments"),_SCS("set_build_mode"),_SCS("get_build_mode"));
ADD_PROPERTY( PropertyInfo(Variant::VECTOR2_ARRAY,"polygon"),_SCS("set_polygon"),_SCS("get_polygon"));
+ ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"shape_range",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_shape_range"),_SCS("_get_shape_range"));
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"trigger"),_SCS("set_trigger"),_SCS("is_trigger"));
+
}
CollisionPolygon2D::CollisionPolygon2D() {
@@ -215,6 +328,9 @@ CollisionPolygon2D::CollisionPolygon2D() {
build_mode=BUILD_SOLIDS;
trigger=false;
unparenting=false;
-
+ shape_from=-1;
+ shape_to=-1;
+ can_update_body=false;
+ set_notify_local_transform(true);
}
diff --git a/scene/2d/collision_polygon_2d.h b/scene/2d/collision_polygon_2d.h
index 4e78868082..b2bd4d189d 100644
--- a/scene/2d/collision_polygon_2d.h
+++ b/scene/2d/collision_polygon_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -56,6 +56,15 @@ protected:
void _add_to_collision_object(Object *p_obj);
void _update_parent();
+ bool can_update_body;
+ int shape_from;
+ int shape_to;
+
+ void _set_shape_range(const Vector2& p_range);
+ Vector2 _get_shape_range() const;
+
+ Vector< Vector<Vector2> > _decompose_in_convex();
+
protected:
void _notification(int p_what);
@@ -72,6 +81,10 @@ public:
Vector<Point2> get_polygon() const;
virtual Rect2 get_item_rect() const;
+
+ int get_collision_object_first_shape() const { return shape_from; }
+ int get_collision_object_last_shape() const { return shape_to; }
+
CollisionPolygon2D();
};
diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp
index 5012c54b17..405310450b 100644
--- a/scene/2d/collision_shape_2d.cpp
+++ b/scene/2d/collision_shape_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -44,10 +44,12 @@ void CollisionShape2D::_add_to_collision_object(Object *p_obj) {
CollisionObject2D *co = p_obj->cast_to<CollisionObject2D>();
ERR_FAIL_COND(!co);
+ update_shape_index=co->get_shape_count();
co->add_shape(shape,get_transform());
if (trigger)
co->set_shape_as_trigger(co->get_shape_count()-1,true);
+
}
void CollisionShape2D::_shape_changed() {
@@ -74,12 +76,32 @@ void CollisionShape2D::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
unparenting=false;
+ can_update_body=get_tree()->is_editor_hint();
+ if (!get_tree()->is_editor_hint()) {
+ //display above all else
+ set_z_as_relative(false);
+ set_z(VS::CANVAS_ITEM_Z_MAX-1);
+ }
+
} break;
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
if (!is_inside_tree())
break;
- _update_parent();
+ if (can_update_body) {
+ _update_parent();
+ } else if (update_shape_index>=0){
+
+ CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>();
+ if (co) {
+ co->set_shape_transform(update_shape_index,get_transform());
+ }
+
+ }
+
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+ can_update_body=false;
} break;
/*
@@ -92,106 +114,23 @@ void CollisionShape2D::_notification(int p_what) {
} break;*/
case NOTIFICATION_DRAW: {
- rect=Rect2();
-
- Color draw_col=Color(0,0.6,0.7,0.5);
-
- if (shape->cast_to<LineShape2D>()) {
-
- LineShape2D *l = shape->cast_to<LineShape2D>();
- Vector2 point = l->get_d() * l->get_normal();
-
- Vector2 l1[2]={point-l->get_normal().tangent()*100,point+l->get_normal().tangent()*100};
- draw_line(l1[0],l1[1],draw_col,3);
- Vector2 l2[2]={point,point+l->get_normal()*30};
- draw_line(l2[0],l2[1],draw_col,3);
- rect.pos=l1[0];
- rect.expand_to(l1[1]);
- rect.expand_to(l2[0]);
- rect.expand_to(l2[1]);
-
- } else if (shape->cast_to<SegmentShape2D>()) {
-
- SegmentShape2D *s = shape->cast_to<SegmentShape2D>();
- draw_line(s->get_a(),s->get_b(),draw_col,3);
- rect.pos=s->get_a();
- rect.expand_to(s->get_b());
-
- } else if (shape->cast_to<RayShape2D>()) {
-
- RayShape2D *s = shape->cast_to<RayShape2D>();
-
- Vector2 tip = Vector2(0,s->get_length());
- draw_line(Vector2(),tip,draw_col,3);
- Vector<Vector2> pts;
- float tsize=4;
- pts.push_back(tip+Vector2(0,tsize));
- pts.push_back(tip+Vector2(0.707*tsize,0));
- pts.push_back(tip+Vector2(-0.707*tsize,0));
- Vector<Color> cols;
- for(int i=0;i<3;i++)
- cols.push_back(draw_col);
-
- draw_primitive(pts,cols,Vector<Vector2>()); //small arrow
-
- rect.pos=Vector2();
- rect.expand_to(tip);
- rect=rect.grow(0.707*tsize);
-
- } else if (shape->cast_to<CircleShape2D>()) {
-
- CircleShape2D *s = shape->cast_to<CircleShape2D>();
- Vector<Vector2> points;
- for(int i=0;i<24;i++) {
-
- points.push_back(Vector2(Math::cos(i*Math_PI*2/24.0),Math::sin(i*Math_PI*2/24.0))*s->get_radius());
- }
-
- draw_colored_polygon(points,draw_col);
- rect.pos=-Point2(s->get_radius(),s->get_radius());
- rect.size=Point2(s->get_radius(),s->get_radius())*2.0;
-
- } else if (shape->cast_to<RectangleShape2D>()) {
-
- RectangleShape2D *s = shape->cast_to<RectangleShape2D>();
- Vector2 he = s->get_extents();
- rect=Rect2(-he,he*2.0);
- draw_rect(rect,draw_col);;
-
- } else if (shape->cast_to<CapsuleShape2D>()) {
-
- CapsuleShape2D *s = shape->cast_to<CapsuleShape2D>();
-
- Vector<Vector2> points;
- for(int i=0;i<24;i++) {
- Vector2 ofs = Vector2(0,(i>6 && i<=18) ? -s->get_height()*0.5 : s->get_height()*0.5);
-
- points.push_back(Vector2(Math::sin(i*Math_PI*2/24.0),Math::cos(i*Math_PI*2/24.0))*s->get_radius() + ofs);
- if (i==6 || i==18)
- points.push_back(Vector2(Math::sin(i*Math_PI*2/24.0),Math::cos(i*Math_PI*2/24.0))*s->get_radius() - ofs);
- }
+ if (!get_tree()->is_editor_hint() && !get_tree()->is_debugging_collisions_hint()) {
+ break;
+ }
- draw_colored_polygon(points,draw_col);
- Vector2 he=Point2(s->get_radius(),s->get_radius()+s->get_height()*0.5);
- rect.pos=-he;
- rect.size=he*2.0;
+ if (!shape.is_valid()) {
+ break;
+ }
- } else if (shape->cast_to<ConvexPolygonShape2D>()) {
+ rect=Rect2();
- ConvexPolygonShape2D *s = shape->cast_to<ConvexPolygonShape2D>();
- Vector<Vector2> points = s->get_points();
- for(int i=0;i<points.size();i++) {
- if (i==0)
- rect.pos=points[i];
- else
- rect.expand_to(points[i]);
- }
- draw_colored_polygon(points,draw_col);
+ Color draw_col=get_tree()->get_debug_collisions_color();
+ shape->draw(get_canvas_item(),draw_col);
- }
+ rect=shape->get_rect();
rect=rect.grow(3);
} break;
@@ -209,7 +148,14 @@ void CollisionShape2D::set_shape(const Ref<Shape2D>& p_shape) {
shape->disconnect("changed",this,"_shape_changed");
shape=p_shape;
update();
- _update_parent();
+ if (is_inside_tree() && can_update_body)
+ _update_parent();
+ if (is_inside_tree() && !can_update_body && update_shape_index>=0) {
+ CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>();
+ if (co) {
+ co->set_shape(update_shape_index,p_shape);
+ }
+ }
if (shape.is_valid())
shape->connect("changed",this,"_shape_changed");
@@ -228,7 +174,14 @@ Rect2 CollisionShape2D::get_item_rect() const {
void CollisionShape2D::set_trigger(bool p_trigger) {
trigger=p_trigger;
- _update_parent();
+ if (can_update_body) {
+ _update_parent();
+ } else if (is_inside_tree() && update_shape_index>=0){
+ CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>();
+ if (co) {
+ co->set_shape_as_trigger(update_shape_index,p_trigger);
+ }
+ }
}
bool CollisionShape2D::is_trigger() const{
@@ -236,6 +189,19 @@ bool CollisionShape2D::is_trigger() const{
return trigger;
}
+
+void CollisionShape2D::_set_update_shape_index(int p_index) {
+
+
+ update_shape_index=p_index;
+}
+
+int CollisionShape2D::_get_update_shape_index() const{
+
+ return update_shape_index;
+}
+
+
void CollisionShape2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_shape","shape"),&CollisionShape2D::set_shape);
@@ -245,14 +211,23 @@ void CollisionShape2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_trigger","enable"),&CollisionShape2D::set_trigger);
ObjectTypeDB::bind_method(_MD("is_trigger"),&CollisionShape2D::is_trigger);
+ ObjectTypeDB::bind_method(_MD("_set_update_shape_index","index"),&CollisionShape2D::_set_update_shape_index);
+ ObjectTypeDB::bind_method(_MD("_get_update_shape_index"),&CollisionShape2D::_get_update_shape_index);
+
+ ObjectTypeDB::bind_method(_MD("get_collision_object_shape_index"),&CollisionShape2D::get_collision_object_shape_index);
+
ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT,"shape",PROPERTY_HINT_RESOURCE_TYPE,"Shape2D"),_SCS("set_shape"),_SCS("get_shape"));
ADD_PROPERTY(PropertyInfo(Variant::BOOL,"trigger"),_SCS("set_trigger"),_SCS("is_trigger"));
+ ADD_PROPERTY( PropertyInfo( Variant::INT, "_update_shape_index", PROPERTY_HINT_NONE, "",PROPERTY_USAGE_NOEDITOR), _SCS("_set_update_shape_index"), _SCS("_get_update_shape_index"));
+
}
CollisionShape2D::CollisionShape2D() {
rect=Rect2(-Point2(10,10),Point2(20,20));
-
+ set_notify_local_transform(true);
trigger=false;
unparenting = false;
+ can_update_body = false;
+ update_shape_index=-1;
}
diff --git a/scene/2d/collision_shape_2d.h b/scene/2d/collision_shape_2d.h
index 507912d31e..b14dad73ba 100644
--- a/scene/2d/collision_shape_2d.h
+++ b/scene/2d/collision_shape_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -39,7 +39,13 @@ class CollisionShape2D : public Node2D {
Rect2 rect;
bool trigger;
bool unparenting;
+ bool can_update_body;
void _shape_changed();
+ int update_shape_index;
+
+ void _set_update_shape_index(int p_index);
+ int _get_update_shape_index() const;
+
protected:
void _update_parent();
@@ -55,6 +61,8 @@ public:
void set_trigger(bool p_trigger);
bool is_trigger() const;
+ int get_collision_object_shape_index() const { return _get_update_shape_index(); }
+
CollisionShape2D();
};
diff --git a/scene/2d/joints_2d.cpp b/scene/2d/joints_2d.cpp
index c1e91c2ecd..053fc2c9c2 100644
--- a/scene/2d/joints_2d.cpp
+++ b/scene/2d/joints_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -111,6 +111,19 @@ real_t Joint2D::get_bias() const{
return bias;
}
+void Joint2D::set_exclude_nodes_from_collision(bool p_enable) {
+
+ if (exclude_from_collision==p_enable)
+ return;
+ exclude_from_collision=p_enable;
+ _update_joint();
+}
+
+bool Joint2D::get_exclude_nodes_from_collision() const{
+
+ return exclude_from_collision;
+}
+
void Joint2D::_bind_methods() {
@@ -124,9 +137,14 @@ void Joint2D::_bind_methods() {
ObjectTypeDB::bind_method( _MD("set_bias","bias"), &Joint2D::set_bias );
ObjectTypeDB::bind_method( _MD("get_bias"), &Joint2D::get_bias );
+ ObjectTypeDB::bind_method( _MD("set_exclude_nodes_from_collision","enable"), &Joint2D::set_exclude_nodes_from_collision );
+ ObjectTypeDB::bind_method( _MD("get_exclude_nodes_from_collision"), &Joint2D::get_exclude_nodes_from_collision );
+
ADD_PROPERTY( PropertyInfo( Variant::NODE_PATH, "node_a"), _SCS("set_node_a"),_SCS("get_node_a") );
ADD_PROPERTY( PropertyInfo( Variant::NODE_PATH, "node_b"), _SCS("set_node_b"),_SCS("get_node_b") );
- ADD_PROPERTY( PropertyInfo( Variant::REAL, "bias/bias",PROPERTY_HINT_RANGE,"0,0.9,0.01"), _SCS("set_bias"),_SCS("get_bias") );
+ ADD_PROPERTY( PropertyInfo( Variant::REAL, "bias/bias",PROPERTY_HINT_RANGE,"0,0.9,0.001"), _SCS("set_bias"),_SCS("get_bias") );
+ ADD_PROPERTY( PropertyInfo( Variant::BOOL, "collision/exclude_nodes"), _SCS("set_exclude_nodes_from_collision"),_SCS("get_exclude_nodes_from_collision") );
+
}
@@ -135,6 +153,7 @@ void Joint2D::_bind_methods() {
Joint2D::Joint2D() {
bias=0;
+ exclude_from_collision=true;
}
///////////////////////////////////////////////////////////////////////////////
@@ -145,11 +164,17 @@ void PinJoint2D::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_DRAW: {
- if (is_inside_tree() && get_tree()->is_editor_hint()) {
- draw_line(Point2(-10,0),Point2(+10,0),Color(0.7,0.6,0.0,0.5),3);
- draw_line(Point2(0,-10),Point2(0,+10),Color(0.7,0.6,0.0,0.5),3);
+ if (!is_inside_tree())
+ break;
+
+ if (!get_tree()->is_editor_hint() && !get_tree()->is_debugging_collisions_hint()) {
+ break;
}
+
+
+ draw_line(Point2(-10,0),Point2(+10,0),Color(0.7,0.6,0.0,0.5),3);
+ draw_line(Point2(0,-10),Point2(0,+10),Color(0.7,0.6,0.0,0.5),3);
} break;
}
@@ -173,17 +198,42 @@ RID PinJoint2D::_configure_joint() {
SWAP(body_a,body_b);
} else if (body_b) {
//add a collision exception between both
- Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(),body_b->get_rid());
+ if (get_exclude_nodes_from_collision())
+ Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(),body_b->get_rid());
+ else
+ Physics2DServer::get_singleton()->body_remove_collision_exception(body_a->get_rid(),body_b->get_rid());
}
+ RID pj = Physics2DServer::get_singleton()->pin_joint_create(get_global_transform().get_origin(),body_a->get_rid(),body_b?body_b->get_rid():RID());
+ Physics2DServer::get_singleton()->pin_joint_set_param(pj, Physics2DServer::PIN_JOINT_SOFTNESS, softness);
+ return pj;
+
+}
- return Physics2DServer::get_singleton()->pin_joint_create(get_global_transform().get_origin(),body_a->get_rid(),body_b?body_b->get_rid():RID());
+void PinJoint2D::set_softness(real_t p_softness) {
+
+ softness=p_softness;
+ update();
+ if (get_joint().is_valid())
+ Physics2DServer::get_singleton()->pin_joint_set_param(get_joint(), Physics2DServer::PIN_JOINT_SOFTNESS, p_softness);
}
+real_t PinJoint2D::get_softness() const {
-PinJoint2D::PinJoint2D() {
+ return softness;
+}
+
+void PinJoint2D::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_softness","softness"), &PinJoint2D::set_softness);
+ ObjectTypeDB::bind_method(_MD("get_softness"), &PinJoint2D::get_softness);
+
+ ADD_PROPERTY( PropertyInfo( Variant::REAL, "softness", PROPERTY_HINT_EXP_RANGE,"0.00,16,0.01"), _SCS("set_softness"), _SCS("get_softness"));
+}
+PinJoint2D::PinJoint2D() {
+ softness = 0;
}
@@ -197,13 +247,17 @@ void GrooveJoint2D::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_DRAW: {
- if (is_inside_tree() && get_tree()->is_editor_hint()) {
+ if (!is_inside_tree())
+ break;
- draw_line(Point2(-10,0),Point2(+10,0),Color(0.7,0.6,0.0,0.5),3);
- draw_line(Point2(-10,length),Point2(+10,length),Color(0.7,0.6,0.0,0.5),3);
- draw_line(Point2(0,0),Point2(0,length),Color(0.7,0.6,0.0,0.5),3);
- draw_line(Point2(-10,initial_offset),Point2(+10,initial_offset),Color(0.8,0.8,0.9,0.5),5);
+ if (!get_tree()->is_editor_hint() && !get_tree()->is_debugging_collisions_hint()) {
+ break;
}
+
+ draw_line(Point2(-10,0),Point2(+10,0),Color(0.7,0.6,0.0,0.5),3);
+ draw_line(Point2(-10,length),Point2(+10,length),Color(0.7,0.6,0.0,0.5),3);
+ draw_line(Point2(0,0),Point2(0,length),Color(0.7,0.6,0.0,0.5),3);
+ draw_line(Point2(-10,initial_offset),Point2(+10,initial_offset),Color(0.8,0.8,0.9,0.5),5);
} break;
}
}
@@ -223,7 +277,11 @@ RID GrooveJoint2D::_configure_joint(){
if (!body_a || !body_b)
return RID();
- Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(),body_b->get_rid());
+
+ if (get_exclude_nodes_from_collision())
+ Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(),body_b->get_rid());
+ else
+ Physics2DServer::get_singleton()->body_remove_collision_exception(body_a->get_rid(),body_b->get_rid());
Matrix32 gt = get_global_transform();
Vector2 groove_A1 = gt.get_origin();
@@ -291,12 +349,17 @@ void DampedSpringJoint2D::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_DRAW: {
- if (is_inside_tree() && get_tree()->is_editor_hint()) {
- draw_line(Point2(-10,0),Point2(+10,0),Color(0.7,0.6,0.0,0.5),3);
- draw_line(Point2(-10,length),Point2(+10,length),Color(0.7,0.6,0.0,0.5),3);
- draw_line(Point2(0,0),Point2(0,length),Color(0.7,0.6,0.0,0.5),3);
+ if (!is_inside_tree())
+ break;
+
+ if (!get_tree()->is_editor_hint() && !get_tree()->is_debugging_collisions_hint()) {
+ break;
}
+
+ draw_line(Point2(-10,0),Point2(+10,0),Color(0.7,0.6,0.0,0.5),3);
+ draw_line(Point2(-10,length),Point2(+10,length),Color(0.7,0.6,0.0,0.5),3);
+ draw_line(Point2(0,0),Point2(0,length),Color(0.7,0.6,0.0,0.5),3);
} break;
}
}
@@ -316,7 +379,10 @@ RID DampedSpringJoint2D::_configure_joint(){
if (!body_a || !body_b)
return RID();
- Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(),body_b->get_rid());
+ if (get_exclude_nodes_from_collision())
+ Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(),body_b->get_rid());
+ else
+ Physics2DServer::get_singleton()->body_remove_collision_exception(body_a->get_rid(),body_b->get_rid());
Matrix32 gt = get_global_transform();
Vector2 anchor_A = gt.get_origin();
diff --git a/scene/2d/joints_2d.h b/scene/2d/joints_2d.h
index ac72c6ce59..52ffd86e7c 100644
--- a/scene/2d/joints_2d.h
+++ b/scene/2d/joints_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -42,6 +42,8 @@ class Joint2D : public Node2D {
NodePath b;
real_t bias;
+ bool exclude_from_collision;
+
protected:
@@ -62,6 +64,9 @@ public:
void set_bias(real_t p_bias);
real_t get_bias() const;
+ void set_exclude_nodes_from_collision(bool p_enable);
+ bool get_exclude_nodes_from_collision() const;
+
RID get_joint() const { return joint; }
Joint2D();
@@ -72,13 +77,17 @@ class PinJoint2D : public Joint2D {
OBJ_TYPE(PinJoint2D,Joint2D);
+ real_t softness;
+
protected:
void _notification(int p_what);
virtual RID _configure_joint();
+ static void _bind_methods();
public:
-
+ void set_softness(real_t p_stiffness);
+ real_t get_softness() const;
PinJoint2D();
};
diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp
index c0ab544d42..9715afeaa4 100644
--- a/scene/2d/light_2d.cpp
+++ b/scene/2d/light_2d.cpp
@@ -34,10 +34,19 @@ Rect2 Light2D::get_item_rect() const {
}
+void Light2D::_update_light_visibility() {
+
+ if (!is_inside_tree())
+ return;
+
+ VS::get_singleton()->canvas_light_set_enabled(canvas_light,enabled && is_visible());
+}
+
void Light2D::set_enabled( bool p_enabled) {
- VS::get_singleton()->canvas_light_set_enabled(canvas_light,p_enabled);
+
enabled=p_enabled;
+ _update_light_visibility();
}
bool Light2D::is_enabled() const {
@@ -237,22 +246,38 @@ float Light2D::get_shadow_esm_multiplier() const{
return shadow_esm_multiplier;
}
+void Light2D::set_shadow_color( const Color& p_shadow_color) {
+ shadow_color=p_shadow_color;
+ VS::get_singleton()->canvas_light_set_shadow_color(canvas_light,shadow_color);
+}
+
+Color Light2D::get_shadow_color() const {
+ return shadow_color;
+}
+
+
void Light2D::_notification(int p_what) {
if (p_what==NOTIFICATION_ENTER_TREE) {
VS::get_singleton()->canvas_light_attach_to_canvas( canvas_light, get_canvas() );
+ _update_light_visibility();
}
if (p_what==NOTIFICATION_TRANSFORM_CHANGED) {
VS::get_singleton()->canvas_light_set_transform( canvas_light, get_global_transform());
}
+ if (p_what==NOTIFICATION_VISIBILITY_CHANGED) {
+
+ _update_light_visibility();
+ }
if (p_what==NOTIFICATION_EXIT_TREE) {
VS::get_singleton()->canvas_light_attach_to_canvas( canvas_light, RID() );
+ _update_light_visibility();
}
}
@@ -313,13 +338,17 @@ void Light2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_shadow_esm_multiplier","multiplier"),&Light2D::set_shadow_esm_multiplier);
ObjectTypeDB::bind_method(_MD("get_shadow_esm_multiplier"),&Light2D::get_shadow_esm_multiplier);
+ ObjectTypeDB::bind_method(_MD("set_shadow_color","shadow_color"),&Light2D::set_shadow_color);
+ ObjectTypeDB::bind_method(_MD("get_shadow_color"),&Light2D::get_shadow_color);
+
+
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled"));
ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"));
ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"offset"),_SCS("set_texture_offset"),_SCS("get_texture_offset"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"scale",PROPERTY_HINT_RANGE,"0.01,4096,0.01"),_SCS("set_texture_scale"),_SCS("get_texture_scale"));
ADD_PROPERTY( PropertyInfo(Variant::COLOR,"color"),_SCS("set_color"),_SCS("get_color"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"energy"),_SCS("set_energy"),_SCS("get_energy"));
- ADD_PROPERTY( PropertyInfo(Variant::INT,"mode",PROPERTY_HINT_ENUM,"Add,Sub,Mix"),_SCS("set_mode"),_SCS("get_mode"));
+ ADD_PROPERTY( PropertyInfo(Variant::INT,"mode",PROPERTY_HINT_ENUM,"Add,Sub,Mix,Mask"),_SCS("set_mode"),_SCS("get_mode"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"range/height"),_SCS("set_height"),_SCS("get_height"));
ADD_PROPERTY( PropertyInfo(Variant::INT,"range/z_min",PROPERTY_HINT_RANGE,itos(VS::CANVAS_ITEM_Z_MIN)+","+itos(VS::CANVAS_ITEM_Z_MAX)+",1"),_SCS("set_z_range_min"),_SCS("get_z_range_min"));
ADD_PROPERTY( PropertyInfo(Variant::INT,"range/z_max",PROPERTY_HINT_RANGE,itos(VS::CANVAS_ITEM_Z_MIN)+","+itos(VS::CANVAS_ITEM_Z_MAX)+",1"),_SCS("set_z_range_max"),_SCS("get_z_range_max"));
@@ -327,6 +356,7 @@ void Light2D::_bind_methods() {
ADD_PROPERTY( PropertyInfo(Variant::INT,"range/layer_max",PROPERTY_HINT_RANGE,"-512,512,1"),_SCS("set_layer_range_max"),_SCS("get_layer_range_max"));
ADD_PROPERTY( PropertyInfo(Variant::INT,"range/item_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_item_mask"),_SCS("get_item_mask"));
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"shadow/enabled"),_SCS("set_shadow_enabled"),_SCS("is_shadow_enabled"));
+ ADD_PROPERTY( PropertyInfo(Variant::COLOR,"shadow/color"),_SCS("set_shadow_color"),_SCS("get_shadow_color"));
ADD_PROPERTY( PropertyInfo(Variant::INT,"shadow/buffer_size",PROPERTY_HINT_RANGE,"32,16384,1"),_SCS("set_shadow_buffer_size"),_SCS("get_shadow_buffer_size"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"shadow/esm_multiplier",PROPERTY_HINT_RANGE,"1,4096,0.1"),_SCS("set_shadow_esm_multiplier"),_SCS("get_shadow_esm_multiplier"));
ADD_PROPERTY( PropertyInfo(Variant::INT,"shadow/item_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_item_shadow_mask"),_SCS("get_item_shadow_mask"));
@@ -334,6 +364,7 @@ void Light2D::_bind_methods() {
BIND_CONSTANT( MODE_ADD );
BIND_CONSTANT( MODE_SUB );
BIND_CONSTANT( MODE_MIX );
+ BIND_CONSTANT( MODE_MASK );
}
@@ -356,6 +387,7 @@ Light2D::Light2D() {
shadow_buffer_size=2048;
shadow_esm_multiplier=80;
energy=1.0;
+ shadow_color=Color(0,0,0,0);
}
diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h
index ef875aec2f..ca437769e7 100644
--- a/scene/2d/light_2d.h
+++ b/scene/2d/light_2d.h
@@ -11,6 +11,7 @@ public:
MODE_ADD,
MODE_SUB,
MODE_MIX,
+ MODE_MASK,
};
private:
@@ -18,6 +19,7 @@ private:
bool enabled;
bool shadow;
Color color;
+ Color shadow_color;
float height;
float _scale;
float energy;
@@ -33,6 +35,7 @@ private:
Ref<Texture> texture;
Vector2 texture_offset;
+ void _update_light_visibility();
protected:
void _notification(int p_what);
@@ -95,6 +98,10 @@ public:
void set_shadow_esm_multiplier( float p_multiplier);
float get_shadow_esm_multiplier() const;
+ void set_shadow_color( const Color& p_shadow_color);
+ Color get_shadow_color() const;
+
+
virtual Rect2 get_item_rect() const;
Light2D();
diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp
index 6ebd499f71..d98bed0ea3 100644
--- a/scene/2d/light_occluder_2d.cpp
+++ b/scene/2d/light_occluder_2d.cpp
@@ -93,12 +93,17 @@ void LightOccluder2D::_notification(int p_what) {
VS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder,get_canvas());
VS::get_singleton()->canvas_light_occluder_set_transform(occluder,get_global_transform());
+ VS::get_singleton()->canvas_light_occluder_set_enabled(occluder,is_visible());
}
if (p_what==NOTIFICATION_TRANSFORM_CHANGED) {
VS::get_singleton()->canvas_light_occluder_set_transform(occluder,get_global_transform());
}
+ if (p_what==NOTIFICATION_VISIBILITY_CHANGED) {
+
+ VS::get_singleton()->canvas_light_occluder_set_enabled(occluder,is_visible());
+ }
if (p_what==NOTIFICATION_DRAW) {
diff --git a/scene/2d/navigation2d.cpp b/scene/2d/navigation2d.cpp
index 5db0e0a9fc..c7542407cb 100644
--- a/scene/2d/navigation2d.cpp
+++ b/scene/2d/navigation2d.cpp
@@ -8,8 +8,6 @@ void Navigation2D::_navpoly_link(int p_id) {
NavMesh &nm=navpoly_map[p_id];
ERR_FAIL_COND(nm.linked);
- print_line("LINK");
-
DVector<Vector2> vertices=nm.navpoly->get_vertices();
int len = vertices.size();
if (len==0)
@@ -48,7 +46,6 @@ void Navigation2D::_navpoly_link(int p_id) {
e.point=_get_point(ep);
p.edges[j]=e;
-
int idxn = indices[(j+1)%plen];
if (idxn<0 || idxn>=len) {
valid=false;
@@ -121,7 +118,7 @@ void Navigation2D::_navpoly_unlink(int p_id) {
NavMesh &nm=navpoly_map[p_id];
ERR_FAIL_COND(!nm.linked);
- print_line("UNLINK");
+ //print_line("UNLINK");
for (List<Polygon>::Element *E=nm.polygons.front();E;E=E->next()) {
@@ -358,7 +355,6 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2& p_start, const Vect
if (!begin_poly || !end_poly) {
- //print_line("No Path Path");
return Vector<Vector2>(); //no path
}
@@ -498,7 +494,26 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2& p_start, const Vect
open_list.erase(least_cost_poly);
}
-
+ {
+ Polygon *p=end_poly;
+ int idx=0;
+
+ while(true) {
+ int prev = p->prev_edge;
+ int prev_n = (p->prev_edge+1)%p->edges.size();
+ Vector2 point = (_get_vertex(p->edges[prev].point) + _get_vertex(p->edges[prev_n].point))*0.5;
+ String points;
+ for(int i=0;i<p->edges.size();i++) {
+ if (i>0)
+ points+=", ";
+ points+=_get_vertex(p->edges[i].point);
+ }
+ //print_line("poly "+itos(idx++)+" - "+points);
+ p = p->edges[prev].C;
+ if (p==begin_poly)
+ break;
+ }
+ }
if (found_route) {
Vector<Vector2> path;
@@ -542,22 +557,29 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2& p_start, const Vect
bool skip=false;
- /* print_line("-----\nAPEX: "+(apex_point-end_point));
+ /*
+ print_line("-----\nAPEX: "+(apex_point-end_point));
print_line("LEFT:");
print_line("\tPortal: "+(portal_left-end_point));
print_line("\tPoint: "+(left-end_point));
- print_line("\tFree: "+itos(CLOCK_TANGENT(apex_point,portal_left,left) >= 0));
+ print_line("\tLeft Tangent: "+rtos(CLOCK_TANGENT(apex_point,portal_left,left)));
+ print_line("\tLeft Distance: "+rtos(portal_left.distance_squared_to(apex_point)));
+ print_line("\tLeft Test: "+rtos(CLOCK_TANGENT(apex_point,left,portal_right)));
print_line("RIGHT:");
print_line("\tPortal: "+(portal_right-end_point));
print_line("\tPoint: "+(right-end_point));
- print_line("\tFree: "+itos(CLOCK_TANGENT(apex_point,portal_right,right) <= 0));
-*/
+ print_line("\tRight Tangent: "+rtos(CLOCK_TANGENT(apex_point,portal_right,right)));
+ print_line("\tRight Distance: "+rtos(portal_right.distance_squared_to(apex_point)));
+ print_line("\tRight Test: "+rtos(CLOCK_TANGENT(apex_point,right,portal_left)));
+ */
+
if (CLOCK_TANGENT(apex_point,portal_left,left) >= 0){
//process
if (portal_left.distance_squared_to(apex_point)<CMP_EPSILON || CLOCK_TANGENT(apex_point,left,portal_right) > 0) {
left_poly=p;
portal_left=left;
+ //print_line("***ADVANCE LEFT");
} else {
//_clip_path(path,apex_poly,portal_right,right_poly);
@@ -572,6 +594,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2& p_start, const Vect
path.push_back(apex_point);
skip=true;
//print_line("addpoint left");
+ //print_line("***CLIP LEFT");
}
}
@@ -580,6 +603,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2& p_start, const Vect
if (portal_right.distance_squared_to(apex_point)<CMP_EPSILON || CLOCK_TANGENT(apex_point,right,portal_left) < 0) {
right_poly=p;
portal_right=right;
+ //print_line("***ADVANCE RIGHT");
} else {
//_clip_path(path,apex_poly,portal_left,left_poly);
@@ -593,6 +617,7 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2& p_start, const Vect
if (path[path.size()-1].distance_to(apex_point)>CMP_EPSILON)
path.push_back(apex_point);
//print_line("addpoint right");
+ //print_line("***CLIP RIGHT");
}
}
diff --git a/scene/2d/navigation_polygon.cpp b/scene/2d/navigation_polygon.cpp
index fc69ea8a0d..4c00d8cec9 100644
--- a/scene/2d/navigation_polygon.cpp
+++ b/scene/2d/navigation_polygon.cpp
@@ -273,13 +273,13 @@ void NavigationPolygonInstance::set_enabled(bool p_enabled) {
if (navpoly.is_valid()) {
- nav_id = navigation->navpoly_create(navpoly,get_relative_transform(navigation),this);
+ nav_id = navigation->navpoly_create(navpoly,get_relative_transform_to_parent(navigation),this);
}
}
}
- if (get_tree()->is_editor_hint())
+ if (get_tree()->is_editor_hint() || get_tree()->is_debugging_navigation_hint())
update();
// update_gizmo();
@@ -309,7 +309,7 @@ void NavigationPolygonInstance::_notification(int p_what) {
if (enabled && navpoly.is_valid()) {
- nav_id = navigation->navpoly_create(navpoly,get_relative_transform(navigation),this);
+ nav_id = navigation->navpoly_create(navpoly,get_relative_transform_to_parent(navigation),this);
}
break;
}
@@ -321,7 +321,7 @@ void NavigationPolygonInstance::_notification(int p_what) {
case NOTIFICATION_TRANSFORM_CHANGED: {
if (navigation && nav_id!=-1) {
- navigation->navpoly_set_transform(nav_id,get_relative_transform(navigation));
+ navigation->navpoly_set_transform(nav_id,get_relative_transform_to_parent(navigation));
}
} break;
@@ -338,7 +338,7 @@ void NavigationPolygonInstance::_notification(int p_what) {
} break;
case NOTIFICATION_DRAW: {
- if (is_inside_tree() && get_tree()->is_editor_hint() && navpoly.is_valid()) {
+ if (is_inside_tree() && (get_tree()->is_editor_hint() || get_tree()->is_debugging_navigation_hint()) && navpoly.is_valid()) {
DVector<Vector2> verts=navpoly->get_vertices();
int vsize = verts.size();
@@ -348,9 +348,9 @@ void NavigationPolygonInstance::_notification(int p_what) {
Color color;
if (enabled) {
- color=Color(0.1,0.8,1.0,0.4);
+ color=get_tree()->get_debug_navigation_color();
} else {
- color=Color(1.0,0.8,0.1,0.4);
+ color=get_tree()->get_debug_navigation_disabled_color();
}
Vector<Color> colors;
Vector<Vector2> vertices;
@@ -409,7 +409,7 @@ void NavigationPolygonInstance::set_navigation_polygon(const Ref<NavigationPolyg
}
if (navigation && navpoly.is_valid() && enabled) {
- nav_id = navigation->navpoly_create(navpoly,get_relative_transform(navigation),this);
+ nav_id = navigation->navpoly_create(navpoly,get_relative_transform_to_parent(navigation),this);
}
//update_gizmo();
_change_notify("navpoly");
@@ -423,7 +423,7 @@ Ref<NavigationPolygon> NavigationPolygonInstance::get_navigation_polygon() const
void NavigationPolygonInstance::_navpoly_changed() {
- if (is_inside_tree() && get_tree()->is_editor_hint())
+ if (is_inside_tree() && (get_tree()->is_editor_hint() || get_tree()->is_debugging_navigation_hint()))
update();
}
diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp
index 99c33c787d..7ef81306b6 100644
--- a/scene/2d/node_2d.cpp
+++ b/scene/2d/node_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -333,17 +333,18 @@ int Node2D::get_z() const{
return z;
}
-Matrix32 Node2D::get_relative_transform(const Node *p_parent) const {
+Matrix32 Node2D::get_relative_transform_to_parent(const Node *p_parent) const {
if (p_parent==this)
return Matrix32();
Node2D *parent_2d = get_parent()->cast_to<Node2D>();
+
ERR_FAIL_COND_V(!parent_2d,Matrix32());
if (p_parent==parent_2d)
return get_transform();
else
- return parent_2d->get_relative_transform(p_parent) * get_transform();
+ return parent_2d->get_relative_transform_to_parent(p_parent) * get_transform();
}
@@ -354,7 +355,7 @@ void Node2D::look_at(const Vector2& p_pos) {
float Node2D::get_angle_to(const Vector2& p_pos) const {
- return (get_global_transform().affine_inverse().xform(p_pos)).atan2();
+ return (get_global_transform().affine_inverse().xform(p_pos)).angle();
}
void Node2D::_bind_methods() {
@@ -394,15 +395,15 @@ void Node2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_z_as_relative","enable"),&Node2D::set_z_as_relative);
ObjectTypeDB::bind_method(_MD("is_z_relative"),&Node2D::is_z_relative);
- ObjectTypeDB::bind_method(_MD("edit_set_pivot"),&Node2D::edit_set_pivot);
+ ObjectTypeDB::bind_method(_MD("edit_set_pivot","pivot"),&Node2D::edit_set_pivot);
- ObjectTypeDB::bind_method(_MD("get_relative_transform"),&Node2D::get_relative_transform);
+ ObjectTypeDB::bind_method(_MD("get_relative_transform_to_parent","parent"),&Node2D::get_relative_transform_to_parent);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"transform/pos"),_SCS("set_pos"),_SCS("get_pos"));
- ADD_PROPERTY(PropertyInfo(Variant::REAL,"transform/rot",PROPERTY_HINT_RANGE,"-1440,1440,0.1"),_SCS("_set_rotd"),_SCS("_get_rotd"));
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"transform/scale"),_SCS("set_scale"),_SCS("get_scale"));
- ADD_PROPERTY(PropertyInfo(Variant::INT,"z/z",PROPERTY_HINT_RANGE,itos(VS::CANVAS_ITEM_Z_MIN)+","+itos(VS::CANVAS_ITEM_Z_MAX)+",1"),_SCS("set_z"),_SCS("get_z"));
- ADD_PROPERTY(PropertyInfo(Variant::BOOL,"z/relative"),_SCS("set_z_as_relative"),_SCS("is_z_relative"));
+ ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2,"transform/pos"),_SCS("set_pos"),_SCS("get_pos"));
+ ADD_PROPERTYNZ(PropertyInfo(Variant::REAL,"transform/rot",PROPERTY_HINT_RANGE,"-1440,1440,0.1"),_SCS("_set_rotd"),_SCS("_get_rotd"));
+ ADD_PROPERTYNO(PropertyInfo(Variant::VECTOR2,"transform/scale"),_SCS("set_scale"),_SCS("get_scale"));
+ ADD_PROPERTYNZ(PropertyInfo(Variant::INT,"z/z",PROPERTY_HINT_RANGE,itos(VS::CANVAS_ITEM_Z_MIN)+","+itos(VS::CANVAS_ITEM_Z_MAX)+",1"),_SCS("set_z"),_SCS("get_z"));
+ ADD_PROPERTYNO(PropertyInfo(Variant::BOOL,"z/relative"),_SCS("set_z_as_relative"),_SCS("is_z_relative"));
}
diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h
index 8efce33cda..49d616fc1f 100644
--- a/scene/2d/node_2d.h
+++ b/scene/2d/node_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -99,7 +99,7 @@ public:
void set_z_as_relative(bool p_enabled);
bool is_z_relative() const;
- Matrix32 get_relative_transform(const Node *p_parent) const;
+ Matrix32 get_relative_transform_to_parent(const Node *p_parent) const;
diff --git a/scene/2d/node_2d_singleton.cpp b/scene/2d/node_2d_singleton.cpp
index 361edf7587..b26804fedf 100644
--- a/scene/2d/node_2d_singleton.cpp
+++ b/scene/2d/node_2d_singleton.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/2d/node_2d_singleton.h b/scene/2d/node_2d_singleton.h
index 6a21db2221..0aa6bbf992 100644
--- a/scene/2d/node_2d_singleton.h
+++ b/scene/2d/node_2d_singleton.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/2d/parallax_background.cpp b/scene/2d/parallax_background.cpp
index 109546bde3..7f2e9efd96 100644
--- a/scene/2d/parallax_background.cpp
+++ b/scene/2d/parallax_background.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -110,7 +110,10 @@ void ParallaxBackground::_update_scroll() {
if (!l)
continue;
- l->set_base_offset_and_scale(ofs,scale);
+ if (ignore_camera_zoom)
+ l->set_base_offset_and_scale(ofs, 1.0);
+ else
+ l->set_base_offset_and_scale(ofs, scale);
}
}
@@ -165,6 +168,18 @@ Point2 ParallaxBackground::get_limit_end() const {
return limit_end;
}
+void ParallaxBackground::set_ignore_camera_zoom(bool ignore){
+
+ ignore_camera_zoom = ignore;
+
+}
+
+bool ParallaxBackground::is_ignore_camera_zoom(){
+
+ return ignore_camera_zoom;
+
+}
+
void ParallaxBackground::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_camera_moved"),&ParallaxBackground::_camera_moved);
@@ -178,6 +193,8 @@ void ParallaxBackground::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_limit_begin"),&ParallaxBackground::get_limit_begin);
ObjectTypeDB::bind_method(_MD("set_limit_end","ofs"),&ParallaxBackground::set_limit_end);
ObjectTypeDB::bind_method(_MD("get_limit_end"),&ParallaxBackground::get_limit_end);
+ ObjectTypeDB::bind_method(_MD("set_ignore_camera_zoom","ignore"), &ParallaxBackground::set_ignore_camera_zoom);
+ ObjectTypeDB::bind_method(_MD("is_ignore_camera_zoom"), &ParallaxBackground::is_ignore_camera_zoom);
ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"scroll/offset"),_SCS("set_scroll_offset"),_SCS("get_scroll_offset"));
@@ -185,6 +202,7 @@ void ParallaxBackground::_bind_methods() {
ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"scroll/base_scale"),_SCS("set_scroll_base_scale"),_SCS("get_scroll_base_scale"));
ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"scroll/limit_begin"),_SCS("set_limit_begin"),_SCS("get_limit_begin"));
ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"scroll/limit_end"),_SCS("set_limit_end"),_SCS("get_limit_end"));
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL, "scroll/ignore_camera_zoom"), _SCS("set_ignore_camera_zoom"), _SCS("is_ignore_camera_zoom"));
}
diff --git a/scene/2d/parallax_background.h b/scene/2d/parallax_background.h
index 363236b2ad..bdaf7d241f 100644
--- a/scene/2d/parallax_background.h
+++ b/scene/2d/parallax_background.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -44,6 +44,7 @@ class ParallaxBackground : public CanvasLayer {
String group_name;
Point2 limit_begin;
Point2 limit_end;
+ bool ignore_camera_zoom;
void _update_scroll();
protected:
@@ -72,6 +73,9 @@ public:
void set_limit_end(const Point2& p_ofs);
Point2 get_limit_end() const;
+ void set_ignore_camera_zoom(bool ignore);
+ bool is_ignore_camera_zoom();
+
ParallaxBackground();
};
diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp
index 70612d7c9a..7a898e43c9 100644
--- a/scene/2d/parallax_layer.cpp
+++ b/scene/2d/parallax_layer.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/2d/parallax_layer.h b/scene/2d/parallax_layer.h
index 8fe2846897..6c24a9b9f7 100644
--- a/scene/2d/parallax_layer.h
+++ b/scene/2d/parallax_layer.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp
index f0b7c2be60..5b13c32d93 100644
--- a/scene/2d/particles_2d.cpp
+++ b/scene/2d/particles_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -697,7 +697,7 @@ bool Particles2D::is_emitting() const {
void Particles2D::set_amount(int p_amount) {
- ERR_FAIL_INDEX(p_amount,1024);
+ ERR_FAIL_INDEX(p_amount,1024+1);
particles.resize(p_amount);
}
@@ -719,7 +719,7 @@ float Particles2D::get_emit_timeout() const {
void Particles2D::set_lifetime(float p_lifetime) {
- ERR_FAIL_INDEX(p_lifetime,3600);
+ ERR_FAIL_INDEX(p_lifetime,3600+1);
lifetime=p_lifetime;
}
@@ -994,6 +994,15 @@ DVector<Vector2> Particles2D::get_emission_points() const{
return emission_points;
}
+void Particles2D::reset() {
+
+ for(int i=0;i<particles.size();i++) {
+ particles[i].active=false;
+ }
+ time=0;
+ active_count=0;
+}
+
void Particles2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_emitting","active"),&Particles2D::set_emitting);
@@ -1057,6 +1066,7 @@ void Particles2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_color_phase_pos","phase"),&Particles2D::get_color_phase_pos);
ObjectTypeDB::bind_method(_MD("pre_process","time"),&Particles2D::pre_process);
+ ObjectTypeDB::bind_method(_MD("reset"),&Particles2D::reset);
ObjectTypeDB::bind_method(_MD("set_use_local_space","enable"),&Particles2D::set_use_local_space);
ObjectTypeDB::bind_method(_MD("is_using_local_space"),&Particles2D::is_using_local_space);
@@ -1072,19 +1082,19 @@ void Particles2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT,"config/amount",PROPERTY_HINT_EXP_RANGE,"1,1024"),_SCS("set_amount"),_SCS("get_amount") );
ADD_PROPERTY(PropertyInfo(Variant::REAL,"config/lifetime",PROPERTY_HINT_EXP_RANGE,"0.1,3600,0.1"),_SCS("set_lifetime"),_SCS("get_lifetime") );
- ADD_PROPERTY(PropertyInfo(Variant::REAL,"config/time_scale",PROPERTY_HINT_EXP_RANGE,"0.01,128,0.01"),_SCS("set_time_scale"),_SCS("get_time_scale") );
- ADD_PROPERTY(PropertyInfo(Variant::REAL,"config/preprocess",PROPERTY_HINT_EXP_RANGE,"0.1,3600,0.1"),_SCS("set_pre_process_time"),_SCS("get_pre_process_time") );
- ADD_PROPERTY(PropertyInfo(Variant::REAL,"config/emit_timeout",PROPERTY_HINT_RANGE,"0,3600,0.1"),_SCS("set_emit_timeout"),_SCS("get_emit_timeout") );
- ADD_PROPERTY(PropertyInfo(Variant::BOOL,"config/emitting"),_SCS("set_emitting"),_SCS("is_emitting") );
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"config/offset"),_SCS("set_emissor_offset"),_SCS("get_emissor_offset"));
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"config/half_extents"),_SCS("set_emission_half_extents"),_SCS("get_emission_half_extents"));
- ADD_PROPERTY(PropertyInfo(Variant::BOOL,"config/local_space"),_SCS("set_use_local_space"),_SCS("is_using_local_space"));
- ADD_PROPERTY(PropertyInfo(Variant::REAL,"config/explosiveness",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_explosiveness"),_SCS("get_explosiveness"));
- ADD_PROPERTY(PropertyInfo(Variant::BOOL,"config/flip_h"),_SCS("set_flip_h"),_SCS("is_flipped_h"));
- ADD_PROPERTY(PropertyInfo(Variant::BOOL,"config/flip_v"),_SCS("set_flip_v"),_SCS("is_flipped_v"));
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"config/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"));
- ADD_PROPERTY(PropertyInfo(Variant::INT,"config/h_frames",PROPERTY_HINT_RANGE,"1,512,1"),_SCS("set_h_frames"),_SCS("get_h_frames"));
- ADD_PROPERTY(PropertyInfo(Variant::INT,"config/v_frames",PROPERTY_HINT_RANGE,"1,512,1"),_SCS("set_v_frames"),_SCS("get_v_frames"));
+ ADD_PROPERTYNO(PropertyInfo(Variant::REAL,"config/time_scale",PROPERTY_HINT_EXP_RANGE,"0.01,128,0.01"),_SCS("set_time_scale"),_SCS("get_time_scale") );
+ ADD_PROPERTYNZ(PropertyInfo(Variant::REAL,"config/preprocess",PROPERTY_HINT_EXP_RANGE,"0.1,3600,0.1"),_SCS("set_pre_process_time"),_SCS("get_pre_process_time") );
+ ADD_PROPERTYNZ(PropertyInfo(Variant::REAL,"config/emit_timeout",PROPERTY_HINT_RANGE,"0,3600,0.1"),_SCS("set_emit_timeout"),_SCS("get_emit_timeout") );
+ ADD_PROPERTYNO(PropertyInfo(Variant::BOOL,"config/emitting"),_SCS("set_emitting"),_SCS("is_emitting") );
+ ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2,"config/offset"),_SCS("set_emissor_offset"),_SCS("get_emissor_offset"));
+ ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2,"config/half_extents"),_SCS("set_emission_half_extents"),_SCS("get_emission_half_extents"));
+ ADD_PROPERTYNO(PropertyInfo(Variant::BOOL,"config/local_space"),_SCS("set_use_local_space"),_SCS("is_using_local_space"));
+ ADD_PROPERTYNO(PropertyInfo(Variant::REAL,"config/explosiveness",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_explosiveness"),_SCS("get_explosiveness"));
+ ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL,"config/flip_h"),_SCS("set_flip_h"),_SCS("is_flipped_h"));
+ ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL,"config/flip_v"),_SCS("set_flip_v"),_SCS("is_flipped_v"));
+ ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT,"config/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture"));
+ ADD_PROPERTYNO(PropertyInfo(Variant::INT,"config/h_frames",PROPERTY_HINT_RANGE,"1,512,1"),_SCS("set_h_frames"),_SCS("get_h_frames"));
+ ADD_PROPERTYNO(PropertyInfo(Variant::INT,"config/v_frames",PROPERTY_HINT_RANGE,"1,512,1"),_SCS("set_v_frames"),_SCS("get_v_frames"));
for(int i=0;i<PARAM_MAX;i++) {
@@ -1092,10 +1102,10 @@ void Particles2D::_bind_methods() {
}
for(int i=0;i<PARAM_MAX;i++) {
- ADD_PROPERTYI(PropertyInfo(Variant::REAL,_particlesframe_property_rnames[i],PROPERTY_HINT_RANGE,"-1,1,0.01"),_SCS("set_randomness"),_SCS("get_randomness"),i);
+ ADD_PROPERTYINZ(PropertyInfo(Variant::REAL,_particlesframe_property_rnames[i],PROPERTY_HINT_RANGE,"-1,1,0.01"),_SCS("set_randomness"),_SCS("get_randomness"),i);
}
- ADD_PROPERTY( PropertyInfo( Variant::INT, "color_phases/count",PROPERTY_HINT_RANGE,"0,4,1", 0), _SCS("set_color_phases"), _SCS("get_color_phases"));
+ ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "color_phases/count",PROPERTY_HINT_RANGE,"0,4,1", 0), _SCS("set_color_phases"), _SCS("get_color_phases"));
//Backward compatibility. They will be converted to color ramp
for(int i=0;i<MAX_COLOR_PHASES;i++) {
@@ -1104,10 +1114,10 @@ void Particles2D::_bind_methods() {
ADD_PROPERTYI( PropertyInfo( Variant::COLOR, phase+"color", PROPERTY_HINT_NONE, "", 0),_SCS("set_color_phase_color"),_SCS("get_color_phase_color"),i );
}
- ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color/color"),_SCS("set_color"),_SCS("get_color"));
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"color/color_ramp",PROPERTY_HINT_RESOURCE_TYPE,"ColorRamp"),_SCS("set_color_ramp"),_SCS("get_color_ramp"));
+ ADD_PROPERTYNO(PropertyInfo(Variant::COLOR, "color/color"),_SCS("set_color"),_SCS("get_color"));
+ ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT,"color/color_ramp",PROPERTY_HINT_RESOURCE_TYPE,"ColorRamp"),_SCS("set_color_ramp"),_SCS("get_color_ramp"));
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2_ARRAY,"emission_points",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_emission_points"),_SCS("get_emission_points"));
+ ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2_ARRAY,"emission_points",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_emission_points"),_SCS("get_emission_points"));
BIND_CONSTANT( PARAM_DIRECTION );
BIND_CONSTANT( PARAM_SPREAD );
diff --git a/scene/2d/particles_2d.h b/scene/2d/particles_2d.h
index 4ee0fcf8da..101395589e 100644
--- a/scene/2d/particles_2d.h
+++ b/scene/2d/particles_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -248,6 +248,7 @@ public:
DVector<Vector2> get_emission_points() const;
void pre_process(float p_delta);
+ void reset();
Particles2D();
};
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index 7ba1bb28b6..bd7415aa04 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,9 +31,13 @@
void Path2D::_notification(int p_what) {
- if (p_what==NOTIFICATION_DRAW && curve.is_valid() && is_inside_tree() && get_tree()->is_editor_hint()) {
+ if (p_what==NOTIFICATION_DRAW && curve.is_valid()) {
//draw the curve!!
+ if (!get_tree()->is_editor_hint() && !get_tree()->is_debugging_navigation_hint()) {
+ return;
+ }
+
for(int i=0;i<curve->get_point_count();i++) {
Vector2 prev_p=curve->get_point_pos(i);
@@ -70,6 +74,8 @@ void Path2D::set_curve(const Ref<Curve2D>& p_curve) {
curve->connect("changed",this,"_curve_changed");
}
+ _curve_changed();
+
}
Ref<Curve2D> Path2D::get_curve() const{
@@ -118,7 +124,7 @@ void PathFollow2D::_update_transform() {
pos+=n*h_offset;
pos+=t*v_offset;
- set_rot(t.atan2());
+ set_rot(t.angle());
} else {
diff --git a/scene/2d/path_2d.h b/scene/2d/path_2d.h
index c9114c5d7d..486a8ac9ac 100644
--- a/scene/2d/path_2d.h
+++ b/scene/2d/path_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index c30921eb69..cc2e5c0d72 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -310,14 +310,20 @@ void RigidBody2D::_body_enter_tree(ObjectID p_id) {
ERR_FAIL_COND(!E);
ERR_FAIL_COND(E->get().in_scene);
+ contact_monitor->locked=true;
+
E->get().in_scene=true;
emit_signal(SceneStringNames::get_singleton()->body_enter,node);
+
for(int i=0;i<E->get().shapes.size();i++) {
emit_signal(SceneStringNames::get_singleton()->body_enter_shape,p_id,node,E->get().shapes[i].body_shape,E->get().shapes[i].local_shape);
}
+ contact_monitor->locked=false;
+
+
}
void RigidBody2D::_body_exit_tree(ObjectID p_id) {
@@ -329,11 +335,18 @@ void RigidBody2D::_body_exit_tree(ObjectID p_id) {
ERR_FAIL_COND(!E);
ERR_FAIL_COND(!E->get().in_scene);
E->get().in_scene=false;
+
+ contact_monitor->locked=true;
+
emit_signal(SceneStringNames::get_singleton()->body_exit,node);
+
for(int i=0;i<E->get().shapes.size();i++) {
emit_signal(SceneStringNames::get_singleton()->body_exit_shape,p_id,node,E->get().shapes[i].body_shape,E->get().shapes[i].local_shape);
}
+
+ contact_monitor->locked=false;
+
}
void RigidBody2D::_body_inout(int p_status, ObjectID p_instance, int p_body_shape,int p_local_shape) {
@@ -439,6 +452,8 @@ void RigidBody2D::_direct_state_changed(Object *p_state) {
if (contact_monitor) {
+ contact_monitor->locked=true;
+
//untag all
int rc=0;
for( Map<ObjectID,BodyState>::Element *E=contact_monitor->body_map.front();E;E=E->next()) {
@@ -520,6 +535,8 @@ void RigidBody2D::_direct_state_changed(Object *p_state) {
_body_inout(1,toadd[i].id,toadd[i].shape,toadd[i].local_shape);
}
+ contact_monitor->locked=false;
+
}
set_block_transform_notify(true); // don't want notify (would feedback loop)
@@ -803,6 +820,11 @@ void RigidBody2D::set_contact_monitor(bool p_enabled) {
if (!p_enabled) {
+ if (contact_monitor->locked) {
+ ERR_EXPLAIN("Can't disable contact monitoring during in/out callback. Use call_deferred(\"set_contact_monitor\",false) instead");
+ }
+ ERR_FAIL_COND(contact_monitor->locked);
+
for(Map<ObjectID,BodyState>::Element *E=contact_monitor->body_map.front();E;E=E->next()) {
//clean up mess
@@ -813,6 +835,7 @@ void RigidBody2D::set_contact_monitor(bool p_enabled) {
} else {
contact_monitor = memnew( ContactMonitor );
+ contact_monitor->locked=false;
}
}
@@ -1250,7 +1273,7 @@ void KinematicBody2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_collider_velocity"),&KinematicBody2D::get_collider_velocity);
ObjectTypeDB::bind_method(_MD("get_collider:Object"),&KinematicBody2D::_get_collider);
ObjectTypeDB::bind_method(_MD("get_collider_shape"),&KinematicBody2D::get_collider_shape);
- ObjectTypeDB::bind_method(_MD("get_collider_metadata"),&KinematicBody2D::get_collider_metadata);
+ ObjectTypeDB::bind_method(_MD("get_collider_metadata:Variant"),&KinematicBody2D::get_collider_metadata);
ObjectTypeDB::bind_method(_MD("set_collision_margin","pixels"),&KinematicBody2D::set_collision_margin);
ObjectTypeDB::bind_method(_MD("get_collision_margin","pixels"),&KinematicBody2D::get_collision_margin);
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index b70fdd59cf..999e63dd5d 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -190,7 +190,7 @@ private:
struct ContactMonitor {
-
+ bool locked;
Map<ObjectID,BodyState> body_map;
};
diff --git a/scene/2d/position_2d.cpp b/scene/2d/position_2d.cpp
index f1591b5242..c293305cb2 100644
--- a/scene/2d/position_2d.cpp
+++ b/scene/2d/position_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/2d/position_2d.h b/scene/2d/position_2d.h
index 16404e6ce8..23821e62d4 100644
--- a/scene/2d/position_2d.h
+++ b/scene/2d/position_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp
index 20abe42cd9..4a774b0198 100644
--- a/scene/2d/ray_cast_2d.cpp
+++ b/scene/2d/ray_cast_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -53,6 +53,16 @@ uint32_t RayCast2D::get_layer_mask() const {
return layer_mask;
}
+void RayCast2D::set_type_mask(uint32_t p_mask) {
+
+ type_mask=p_mask;
+}
+
+uint32_t RayCast2D::get_type_mask() const {
+
+ return type_mask;
+}
+
bool RayCast2D::is_colliding() const{
return collided;
@@ -115,17 +125,17 @@ void RayCast2D::_notification(int p_what) {
set_fixed_process(false);
} break;
-#ifdef TOOLS_ENABLED
+
case NOTIFICATION_DRAW: {
- if (!get_tree()->is_editor_hint())
+ if (!get_tree()->is_editor_hint() && !get_tree()->is_debugging_collisions_hint())
break;
Matrix32 xf;
- xf.rotate(cast_to.atan2());
+ xf.rotate(cast_to.angle());
xf.translate(Vector2(0,cast_to.length()));
//Vector2 tip = Vector2(0,s->get_length());
- Color dcol(0.9,0.2,0.2,0.4);
+ Color dcol=get_tree()->get_debug_collisions_color();//0.9,0.2,0.2,0.4);
draw_line(Vector2(),cast_to,dcol,3);
Vector<Vector2> pts;
float tsize=4;
@@ -139,7 +149,7 @@ void RayCast2D::_notification(int p_what) {
draw_primitive(pts,cols,Vector<Vector2>()); //small arrow
} break;
-#endif
+
case NOTIFICATION_FIXED_PROCESS: {
@@ -162,7 +172,7 @@ void RayCast2D::_notification(int p_what) {
Physics2DDirectSpaceState::RayResult rr;
- if (dss->intersect_ray(gt.get_origin(),gt.xform(to),rr,exclude,layer_mask)) {
+ if (dss->intersect_ray(gt.get_origin(),gt.xform(to),rr,exclude,layer_mask,type_mask)) {
collided=true;
against=rr.collider_id;
@@ -241,9 +251,13 @@ void RayCast2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_layer_mask","mask"),&RayCast2D::set_layer_mask);
ObjectTypeDB::bind_method(_MD("get_layer_mask"),&RayCast2D::get_layer_mask);
+ ObjectTypeDB::bind_method(_MD("set_type_mask","mask"),&RayCast2D::set_type_mask);
+ ObjectTypeDB::bind_method(_MD("get_type_mask"),&RayCast2D::get_type_mask);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled"));
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"cast_to"),_SCS("set_cast_to"),_SCS("get_cast_to"));
ADD_PROPERTY(PropertyInfo(Variant::INT,"layer_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_layer_mask"),_SCS("get_layer_mask"));
+ ADD_PROPERTY(PropertyInfo(Variant::INT,"type_mask",PROPERTY_HINT_FLAGS,"Static,Kinematic,Rigid,Character,Area"),_SCS("set_type_mask"),_SCS("get_type_mask"));
}
RayCast2D::RayCast2D() {
@@ -253,5 +267,6 @@ RayCast2D::RayCast2D() {
collided=false;
against_shape=0;
layer_mask=1;
+ type_mask=Physics2DDirectSpaceState::TYPE_MASK_COLLISION;
cast_to=Vector2(0,50);
}
diff --git a/scene/2d/ray_cast_2d.h b/scene/2d/ray_cast_2d.h
index c7616be523..54ec42c53e 100644
--- a/scene/2d/ray_cast_2d.h
+++ b/scene/2d/ray_cast_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -44,6 +44,7 @@ class RayCast2D : public Node2D {
Vector2 collision_normal;
Set<RID> exclude;
uint32_t layer_mask;
+ uint32_t type_mask;
Vector2 cast_to;
@@ -62,6 +63,9 @@ public:
void set_layer_mask(uint32_t p_mask);
uint32_t get_layer_mask() const;
+ void set_type_mask(uint32_t p_mask);
+ uint32_t get_type_mask() const;
+
bool is_colliding() const;
Object *get_collider() const;
int get_collider_shape() const;
diff --git a/scene/2d/remote_transform_2d.cpp b/scene/2d/remote_transform_2d.cpp
index 0fbd140cfb..6dcd980822 100644
--- a/scene/2d/remote_transform_2d.cpp
+++ b/scene/2d/remote_transform_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/2d/remote_transform_2d.h b/scene/2d/remote_transform_2d.h
index 506bde8cd8..4a5f5f72ea 100644
--- a/scene/2d/remote_transform_2d.h
+++ b/scene/2d/remote_transform_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/2d/sample_player_2d.cpp b/scene/2d/sample_player_2d.cpp
index bb37475944..bf09130238 100644
--- a/scene/2d/sample_player_2d.cpp
+++ b/scene/2d/sample_player_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -214,7 +214,7 @@ void SamplePlayer2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_sample_library","library:SampleLibrary"),&SamplePlayer2D::set_sample_library);
ObjectTypeDB::bind_method(_MD("get_sample_library:SampleLibrary"),&SamplePlayer2D::get_sample_library);
- ObjectTypeDB::bind_method(_MD("set_polyphony","voices"),&SamplePlayer2D::set_polyphony);
+ ObjectTypeDB::bind_method(_MD("set_polyphony","max_voices"),&SamplePlayer2D::set_polyphony);
ObjectTypeDB::bind_method(_MD("get_polyphony"),&SamplePlayer2D::get_polyphony);
ObjectTypeDB::bind_method(_MD("play","sample","voice"),&SamplePlayer2D::play,DEFVAL(NEXT_VOICE));
diff --git a/scene/2d/sample_player_2d.h b/scene/2d/sample_player_2d.h
index c0f2734ad1..eddf84f77b 100644
--- a/scene/2d/sample_player_2d.h
+++ b/scene/2d/sample_player_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/2d/screen_button.cpp b/scene/2d/screen_button.cpp
index 0c3987e6b1..fac94f19dc 100644
--- a/scene/2d/screen_button.cpp
+++ b/scene/2d/screen_button.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -102,6 +102,10 @@ void TouchScreenButton::_notification(int p_what) {
action_id=-1;
}
} break;
+ case NOTIFICATION_EXIT_TREE: {
+ if (is_pressed())
+ Input::get_singleton()->action_release(action);
+ } break;
}
}
@@ -161,7 +165,7 @@ void TouchScreenButton::_input(const InputEvent& p_event) {
if (finger_pressed==-1 || p_event.screen_touch.index==finger_pressed) {
- Point2 coord = (get_global_transform()).affine_inverse().xform(Point2(p_event.screen_touch.x,p_event.screen_touch.y));
+ Point2 coord = (get_global_transform_with_canvas()).affine_inverse().xform(Point2(p_event.screen_touch.x,p_event.screen_touch.y));
bool touched=false;
if (bitmask.is_valid()) {
@@ -238,7 +242,7 @@ void TouchScreenButton::_input(const InputEvent& p_event) {
if (finger_pressed!=-1)
return; //already fingering
- Point2 coord = (get_global_transform()).affine_inverse().xform(Point2(p_event.screen_touch.x,p_event.screen_touch.y));
+ Point2 coord = (get_global_transform_with_canvas()).affine_inverse().xform(Point2(p_event.screen_touch.x,p_event.screen_touch.y));
bool touched=false;
if (bitmask.is_valid()) {
diff --git a/scene/2d/screen_button.h b/scene/2d/screen_button.h
index 159b829079..ff3b50bf5e 100644
--- a/scene/2d/screen_button.h
+++ b/scene/2d/screen_button.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/2d/sound_player_2d.cpp b/scene/2d/sound_player_2d.cpp
index 0eb18866af..41ce87faf9 100644
--- a/scene/2d/sound_player_2d.cpp
+++ b/scene/2d/sound_player_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/2d/sound_player_2d.h b/scene/2d/sound_player_2d.h
index a376cdbed7..0e75887235 100644
--- a/scene/2d/sound_player_2d.h
+++ b/scene/2d/sound_player_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp
index 0485033691..001a1366a9 100644
--- a/scene/2d/sprite.cpp
+++ b/scene/2d/sprite.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,6 +30,7 @@
#include "core/core_string_names.h"
#include "scene/scene_string_names.h"
#include "scene/main/viewport.h"
+#include "os/os.h"
void Sprite::edit_set_pivot(const Point2& p_pivot) {
@@ -85,6 +86,9 @@ void Sprite::_notification(int p_what) {
Point2 ofs=offset;
if (centered)
ofs-=s/2;
+ if (OS::get_singleton()->get_use_pixel_snap()) {
+ ofs=ofs.floor();
+ }
Rect2 dst_rect(ofs,s);
@@ -103,14 +107,18 @@ void Sprite::set_texture(const Ref<Texture>& p_texture) {
if (p_texture==texture)
return;
+#ifdef DEBUG_ENABLED
if (texture.is_valid()) {
texture->disconnect(CoreStringNames::get_singleton()->changed,this,SceneStringNames::get_singleton()->update);
}
+#endif
texture=p_texture;
+#ifdef DEBUG_ENABLED
if (texture.is_valid()) {
texture->set_flags(texture->get_flags()); //remove repeat from texture, it looks bad in sprites
texture->connect(CoreStringNames::get_singleton()->changed,this,SceneStringNames::get_singleton()->update);
}
+#endif
update();
item_rect_changed();
}
@@ -185,6 +193,7 @@ void Sprite::set_region_rect(const Rect2& p_region_rect) {
if (region && changed) {
update();
item_rect_changed();
+ _change_notify("region_rect");
}
}
@@ -313,17 +322,17 @@ void Sprite::_bind_methods() {
ADD_SIGNAL(MethodInfo("frame_changed"));
- ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_texture"),_SCS("get_texture"));
- ADD_PROPERTY( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered"));
- ADD_PROPERTY( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset"));
- ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flip_h"), _SCS("set_flip_h"),_SCS("is_flipped_h"));
- ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flip_v"), _SCS("set_flip_v"),_SCS("is_flipped_v"));
- ADD_PROPERTY( PropertyInfo( Variant::INT, "vframes"), _SCS("set_vframes"),_SCS("get_vframes"));
- ADD_PROPERTY( PropertyInfo( Variant::INT, "hframes"), _SCS("set_hframes"),_SCS("get_hframes"));
- ADD_PROPERTY( PropertyInfo( Variant::INT, "frame",PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"),_SCS("get_frame"));
- ADD_PROPERTY( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate"));
- ADD_PROPERTY( PropertyInfo( Variant::BOOL, "region"), _SCS("set_region"),_SCS("is_region"));
- ADD_PROPERTY( PropertyInfo( Variant::RECT2, "region_rect"), _SCS("set_region_rect"),_SCS("get_region_rect"));
+ ADD_PROPERTYNZ( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_texture"),_SCS("get_texture"));
+ ADD_PROPERTYNO( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered"));
+ ADD_PROPERTYNZ( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset"));
+ ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "flip_h"), _SCS("set_flip_h"),_SCS("is_flipped_h"));
+ ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "flip_v"), _SCS("set_flip_v"),_SCS("is_flipped_v"));
+ ADD_PROPERTYNO( PropertyInfo( Variant::INT, "vframes",PROPERTY_HINT_RANGE,"1,16384,1"), _SCS("set_vframes"),_SCS("get_vframes"));
+ ADD_PROPERTYNO( PropertyInfo( Variant::INT, "hframes",PROPERTY_HINT_RANGE,"1,16384,1"), _SCS("set_hframes"),_SCS("get_hframes"));
+ ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "frame",PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"),_SCS("get_frame"));
+ ADD_PROPERTYNO( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate"));
+ ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "region"), _SCS("set_region"),_SCS("is_region"));
+ ADD_PROPERTYNZ( PropertyInfo( Variant::RECT2, "region_rect"), _SCS("set_region_rect"),_SCS("get_region_rect"));
}
@@ -417,6 +426,9 @@ void ViewportSprite::_notification(int p_what) {
if (centered)
ofs-=s/2;
+ if (OS::get_singleton()->get_use_pixel_snap()) {
+ ofs=ofs.floor();
+ }
Rect2 dst_rect(ofs,s);
texture->draw_rect_region(ci,dst_rect,src_rect,modulate);
@@ -530,10 +542,10 @@ void ViewportSprite::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_modulate","modulate"),&ViewportSprite::set_modulate);
ObjectTypeDB::bind_method(_MD("get_modulate"),&ViewportSprite::get_modulate);
- ADD_PROPERTY( PropertyInfo( Variant::NODE_PATH, "viewport"), _SCS("set_viewport_path"),_SCS("get_viewport_path"));
- ADD_PROPERTY( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered"));
- ADD_PROPERTY( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset"));
- ADD_PROPERTY( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate"));
+ ADD_PROPERTYNZ( PropertyInfo( Variant::NODE_PATH, "viewport"), _SCS("set_viewport_path"),_SCS("get_viewport_path"));
+ ADD_PROPERTYNO( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered"));
+ ADD_PROPERTYNZ( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset"));
+ ADD_PROPERTYNO( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate"));
}
diff --git a/scene/2d/sprite.h b/scene/2d/sprite.h
index ad782e746b..cbcaec9aeb 100644
--- a/scene/2d/sprite.h
+++ b/scene/2d/sprite.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 2fca1e67e8..179d1f451a 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,6 +30,9 @@
#include "io/marshalls.h"
#include "servers/physics_2d_server.h"
#include "method_bind_ext.inc"
+#include "os/os.h"
+
+
int TileMap::_get_quadrant_size() const {
@@ -115,7 +118,7 @@ void TileMap::_update_quadrant_transform() {
Matrix32 nav_rel;
if (navigation)
- nav_rel = get_relative_transform(navigation);
+ nav_rel = get_relative_transform_to_parent(navigation);
for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) {
@@ -220,6 +223,14 @@ void TileMap::_fix_cell_transform(Matrix32& xform,const Cell& p_cell, const Vect
Size2 s=p_sc;
Vector2 offset = p_offset;
+ if (s.y > s.x) {
+ if ((p_cell.flip_h && (p_cell.flip_v || p_cell.transpose)) || (p_cell.flip_v && !p_cell.transpose))
+ offset.y += s.y - s.x;
+ } else if (s.y < s.x) {
+ if ((p_cell.flip_v && (p_cell.flip_h || p_cell.transpose)) || (p_cell.flip_h && !p_cell.transpose))
+ offset.x += s.x - s.y;
+ }
+
if (p_cell.transpose) {
SWAP(xform.elements[0].x, xform.elements[0].y);
SWAP(xform.elements[1].x, xform.elements[1].y);
@@ -258,10 +269,18 @@ void TileMap::_update_dirty_quadrants() {
Vector2 tcenter = cell_size/2;
Matrix32 nav_rel;
if (navigation)
- nav_rel = get_relative_transform(navigation);
+ nav_rel = get_relative_transform_to_parent(navigation);
Vector2 qofs;
+ SceneTree *st=SceneTree::get_singleton();
+ Color debug_collision_color;
+
+ bool debug_shapes = st && st->is_debugging_collisions_hint();
+ if (debug_shapes) {
+ debug_collision_color=st->get_debug_collisions_color();
+ }
+
while (dirty_quadrant_list.first()) {
Quadrant &q = *dirty_quadrant_list.first()->self();
@@ -290,6 +309,7 @@ void TileMap::_update_dirty_quadrants() {
q.occluder_instances.clear();
Ref<CanvasItemMaterial> prev_material;
RID prev_canvas_item;
+ RID prev_debug_canvas_item;
for(int i=0;i<q.cells.size();i++) {
@@ -310,6 +330,7 @@ void TileMap::_update_dirty_quadrants() {
Ref<CanvasItemMaterial> mat = tile_set->tile_get_material(c.id);
RID canvas_item;
+ RID debug_canvas_item;
if (prev_canvas_item==RID() || prev_material!=mat) {
@@ -320,13 +341,28 @@ void TileMap::_update_dirty_quadrants() {
Matrix32 xform;
xform.set_origin( q.pos );
vs->canvas_item_set_transform( canvas_item, xform );
+ vs->canvas_item_set_light_mask(canvas_item,get_light_mask());
+
q.canvas_items.push_back(canvas_item);
+ if (debug_shapes) {
+
+ debug_canvas_item=vs->canvas_item_create();
+ vs->canvas_item_set_parent( debug_canvas_item, canvas_item );
+ vs->canvas_item_set_z_as_relative_to_parent(debug_canvas_item,false);
+ vs->canvas_item_set_z(debug_canvas_item,VS::CANVAS_ITEM_Z_MAX-1);
+ q.canvas_items.push_back(debug_canvas_item);
+ prev_debug_canvas_item=debug_canvas_item;
+ }
+
prev_canvas_item=canvas_item;
prev_material=mat;
} else {
canvas_item=prev_canvas_item;
+ if (debug_shapes) {
+ debug_canvas_item=prev_debug_canvas_item;
+ }
}
@@ -348,13 +384,28 @@ void TileMap::_update_dirty_quadrants() {
rect.pos=offset.floor();
rect.size=s;
+ if (rect.size.y > rect.size.x) {
+ if ((c.flip_h && (c.flip_v || c.transpose)) || (c.flip_v && !c.transpose))
+ tile_ofs.y += rect.size.y - rect.size.x;
+ } else if (rect.size.y < rect.size.x) {
+ if ((c.flip_v && (c.flip_h || c.transpose)) || (c.flip_h && !c.transpose))
+ tile_ofs.x += rect.size.x - rect.size.y;
+ }
+
/* rect.size.x+=fp_adjust;
rect.size.y+=fp_adjust;*/
- if (c.flip_h)
+ if (c.transpose)
+ SWAP(tile_ofs.x, tile_ofs.y);
+
+ if (c.flip_h) {
rect.size.x=-rect.size.x;
- if (c.flip_v)
+ tile_ofs.x=-tile_ofs.x;
+ }
+ if (c.flip_v) {
rect.size.y=-rect.size.y;
+ tile_ofs.y=-tile_ofs.y;
+ }
Vector2 center_ofs;
@@ -398,7 +449,11 @@ void TileMap::_update_dirty_quadrants() {
_fix_cell_transform(xform,c,shape_ofs+center_ofs,s);
- ps->body_add_shape(q.body,shape->get_rid(),xform);
+ if (debug_canvas_item) {
+ shape->draw(debug_canvas_item,debug_collision_color);
+
+ }
+ ps->body_add_shape(q.body,shape->get_rid(),xform);
ps->body_set_shape_metadata(q.body,shape_idx++,Vector2(E->key().x,E->key().y));
}
@@ -412,6 +467,7 @@ void TileMap::_update_dirty_quadrants() {
xform.set_origin(offset.floor()+q.pos);
_fix_cell_transform(xform,c,npoly_ofs+center_ofs,s);
+
int pid = navigation->navpoly_create(navpoly,nav_rel * xform);
Quadrant::NavPoly np;
@@ -434,6 +490,7 @@ void TileMap::_update_dirty_quadrants() {
VS::get_singleton()->canvas_light_occluder_set_transform(orid,get_global_transform() * xform);
VS::get_singleton()->canvas_light_occluder_set_polygon(orid,occluder->get_rid());
VS::get_singleton()->canvas_light_occluder_attach_to_canvas(orid,get_canvas());
+ VS::get_singleton()->canvas_light_occluder_set_light_mask(orid,occluder_light_mask);
Quadrant::Occluder oc;
oc.xform=xform;
oc.id=orid;
@@ -579,6 +636,10 @@ void TileMap::_make_quadrant_dirty(Map<PosKey,Quadrant>::Element *Q) {
call_deferred("_update_dirty_quadrants");
}
+void TileMap::set_cellv(const Vector2& p_pos,int p_tile,bool p_flip_x,bool p_flip_y,bool p_transpose) {
+
+ set_cell(p_pos.x,p_pos.y,p_tile,p_flip_x,p_flip_y,p_transpose);
+}
void TileMap::set_cell(int p_x,int p_y,int p_tile,bool p_flip_x,bool p_flip_y,bool p_transpose) {
@@ -1009,13 +1070,12 @@ Vector2 TileMap::world_to_map(const Vector2& p_pos) const{
switch(half_offset) {
case HALF_OFFSET_X: {
- if (int(ret.y)&1) {
-
+ if ( ret.y > 0 ? int(ret.y)&1 : (int(ret.y)-1)&1 ) {
ret.x-=0.5;
}
} break;
case HALF_OFFSET_Y: {
- if (int(ret.x)&1) {
+ if ( ret.x > 0 ? int(ret.x)&1 : (int(ret.x)-1)&1) {
ret.y-=0.5;
}
} break;
@@ -1054,6 +1114,33 @@ Array TileMap::get_used_cells() const {
return a;
}
+void TileMap::set_occluder_light_mask(int p_mask) {
+
+ occluder_light_mask=p_mask;
+ for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) {
+
+ for (Map<PosKey,Quadrant::Occluder>::Element *F=E->get().occluder_instances.front();F;F=F->next()) {
+ VisualServer::get_singleton()->canvas_light_occluder_set_light_mask(F->get().id,occluder_light_mask);
+ }
+ }
+}
+
+int TileMap::get_occluder_light_mask() const{
+
+ return occluder_light_mask;
+}
+
+void TileMap::set_light_mask(int p_light_mask) {
+
+ CanvasItem::set_light_mask(p_light_mask);
+ for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) {
+
+ for (List<RID>::Element *F=E->get().canvas_items.front();F;F=F->next()) {
+ VisualServer::get_singleton()->canvas_item_set_light_mask(F->get(),get_light_mask());
+ }
+ }
+}
+
void TileMap::_bind_methods() {
@@ -1105,7 +1192,11 @@ void TileMap::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_collision_bounce","value"),&TileMap::set_collision_bounce);
ObjectTypeDB::bind_method(_MD("get_collision_bounce"),&TileMap::get_collision_bounce);
+ ObjectTypeDB::bind_method(_MD("set_occluder_light_mask","mask"),&TileMap::set_occluder_light_mask);
+ ObjectTypeDB::bind_method(_MD("get_occluder_light_mask"),&TileMap::get_occluder_light_mask);
+
ObjectTypeDB::bind_method(_MD("set_cell","x","y","tile","flip_x","flip_y","transpose"),&TileMap::set_cell,DEFVAL(false),DEFVAL(false),DEFVAL(false));
+ ObjectTypeDB::bind_method(_MD("set_cellv","pos","tile","flip_x","flip_y","transpose"),&TileMap::set_cellv,DEFVAL(false),DEFVAL(false),DEFVAL(false));
ObjectTypeDB::bind_method(_MD("get_cell","x","y"),&TileMap::get_cell);
ObjectTypeDB::bind_method(_MD("is_cell_x_flipped","x","y"),&TileMap::is_cell_x_flipped);
ObjectTypeDB::bind_method(_MD("is_cell_y_flipped","x","y"),&TileMap::is_cell_y_flipped);
@@ -1138,6 +1229,7 @@ void TileMap::_bind_methods() {
ADD_PROPERTY( PropertyInfo(Variant::REAL,"collision/bounce",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_collision_bounce"),_SCS("get_collision_bounce"));
ADD_PROPERTY( PropertyInfo(Variant::INT,"collision/layers",PROPERTY_HINT_ALL_FLAGS),_SCS("set_collision_layer"),_SCS("get_collision_layer"));
ADD_PROPERTY( PropertyInfo(Variant::INT,"collision/mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_collision_mask"),_SCS("get_collision_mask"));
+ ADD_PROPERTY( PropertyInfo(Variant::INT,"occluder/light_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_occluder_light_mask"),_SCS("get_occluder_light_mask"));
ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"tile_data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_tile_data"),_SCS("_get_tile_data"));
@@ -1175,6 +1267,7 @@ TileMap::TileMap() {
use_kinematic=false;
navigation=NULL;
y_sort_mode=false;
+ occluder_light_mask=1;
fp_adjust=0.00001;
tile_origin=TILE_ORIGIN_TOP_LEFT;
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index 84ca65da4f..14cb52b736 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -150,6 +150,8 @@ private:
TileOrigin tile_origin;
+ int occluder_light_mask;
+
void _fix_cell_transform(Matrix32& xform, const Cell& p_cell, const Vector2 &p_offset, const Size2 &p_sc);
Map<PosKey,Quadrant>::Element *_create_quadrant(const PosKey& p_qk);
@@ -187,6 +189,7 @@ public:
INVALID_CELL=-1
};
+
void set_tileset(const Ref<TileSet>& p_tileset);
Ref<TileSet> get_tileset() const;
@@ -207,6 +210,8 @@ public:
bool is_cell_y_flipped(int p_x,int p_y) const;
bool is_cell_transposed(int p_x,int p_y) const;
+ void set_cellv(const Vector2& p_pos,int p_tile,bool p_flip_x=false,bool p_flip_y=false,bool p_transpose=false);
+
Rect2 get_item_rect() const;
void set_collision_layer(uint32_t p_layer);
@@ -245,6 +250,11 @@ public:
void set_y_sort_mode(bool p_enable);
bool is_y_sort_mode_enabled() const;
+ void set_occluder_light_mask(int p_mask);
+ int get_occluder_light_mask() const;
+
+ virtual void set_light_mask(int p_light_mask);
+
void clear();
TileMap();
diff --git a/scene/2d/visibility_notifier_2d.cpp b/scene/2d/visibility_notifier_2d.cpp
index dc72c9a267..60fa7f69c8 100644
--- a/scene/2d/visibility_notifier_2d.cpp
+++ b/scene/2d/visibility_notifier_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/2d/visibility_notifier_2d.h b/scene/2d/visibility_notifier_2d.h
index 1f7e4c6d45..6ec24fd4d0 100644
--- a/scene/2d/visibility_notifier_2d.h
+++ b/scene/2d/visibility_notifier_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/SCsub b/scene/3d/SCsub
index 3c2144bedc..116e641593 100644
--- a/scene/3d/SCsub
+++ b/scene/3d/SCsub
@@ -4,10 +4,8 @@ Import('env')
if (env["disable_3d"]=="yes"):
env.scene_sources.append("3d/spatial.cpp")
- env.scene_sources.append("3d/skeleton.cpp")
+ env.scene_sources.append("3d/skeleton.cpp")
else:
env.add_source_files(env.scene_sources,"*.cpp")
Export('env')
-
-
diff --git a/scene/3d/area.cpp b/scene/3d/area.cpp
index a00946a07a..7d4235e051 100644
--- a/scene/3d/area.cpp
+++ b/scene/3d/area.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -83,15 +83,25 @@ real_t Area::get_gravity() const{
return gravity;
}
+void Area::set_linear_damp(real_t p_linear_damp){
-void Area::set_density(real_t p_density){
+ linear_damp=p_linear_damp;
+ PhysicsServer::get_singleton()->area_set_param(get_rid(),PhysicsServer::AREA_PARAM_LINEAR_DAMP,p_linear_damp);
+}
+real_t Area::get_linear_damp() const{
+
+ return linear_damp;
+}
- density=p_density;
- PhysicsServer::get_singleton()->area_set_param(get_rid(),PhysicsServer::AREA_PARAM_DENSITY,p_density);
+void Area::set_angular_damp(real_t p_angular_damp){
+
+ angular_damp=p_angular_damp;
+ PhysicsServer::get_singleton()->area_set_param(get_rid(),PhysicsServer::AREA_PARAM_ANGULAR_DAMP,p_angular_damp);
}
-real_t Area::get_density() const{
- return density;
+real_t Area::get_angular_damp() const{
+
+ return angular_damp;
}
void Area::set_priority(real_t p_priority){
@@ -299,8 +309,8 @@ void Area::set_enable_monitoring(bool p_enable) {
if (monitoring) {
- PhysicsServer::get_singleton()->area_set_monitor_callback(get_rid(),this,"_body_inout");
- PhysicsServer::get_singleton()->area_set_area_monitor_callback(get_rid(),this,"_area_inout");
+ PhysicsServer::get_singleton()->area_set_monitor_callback(get_rid(),this,SceneStringNames::get_singleton()->_body_inout);
+ PhysicsServer::get_singleton()->area_set_area_monitor_callback(get_rid(),this,SceneStringNames::get_singleton()->_area_inout);
} else {
PhysicsServer::get_singleton()->area_set_monitor_callback(get_rid(),NULL,StringName());
PhysicsServer::get_singleton()->area_set_area_monitor_callback(get_rid(),NULL,StringName());
@@ -533,8 +543,11 @@ void Area::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_gravity","gravity"),&Area::set_gravity);
ObjectTypeDB::bind_method(_MD("get_gravity"),&Area::get_gravity);
- ObjectTypeDB::bind_method(_MD("set_density","density"),&Area::set_density);
- ObjectTypeDB::bind_method(_MD("get_density"),&Area::get_density);
+ ObjectTypeDB::bind_method(_MD("set_angular_damp","angular_damp"),&Area::set_angular_damp);
+ ObjectTypeDB::bind_method(_MD("get_angular_damp"),&Area::get_angular_damp);
+
+ ObjectTypeDB::bind_method(_MD("set_linear_damp","linear_damp"),&Area::set_linear_damp);
+ ObjectTypeDB::bind_method(_MD("get_linear_damp"),&Area::get_linear_damp);
ObjectTypeDB::bind_method(_MD("set_priority","priority"),&Area::set_priority);
ObjectTypeDB::bind_method(_MD("get_priority"),&Area::get_priority);
@@ -566,12 +579,13 @@ void Area::_bind_methods() {
ADD_SIGNAL( MethodInfo("area_enter",PropertyInfo(Variant::OBJECT,"area",PROPERTY_HINT_RESOURCE_TYPE,"Area")));
ADD_SIGNAL( MethodInfo("area_exit",PropertyInfo(Variant::OBJECT,"area",PROPERTY_HINT_RESOURCE_TYPE,"Area")));
- ADD_PROPERTY( PropertyInfo(Variant::INT,"space_override",PROPERTY_HINT_ENUM,"Disabled,Combine,Replace"),_SCS("set_space_override_mode"),_SCS("get_space_override_mode"));
+ ADD_PROPERTY( PropertyInfo(Variant::INT,"space_override",PROPERTY_HINT_ENUM,"Disabled,Combine,Combine-Replace,Replace,Replace-Combine"),_SCS("set_space_override_mode"),_SCS("get_space_override_mode"));
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"gravity_point"),_SCS("set_gravity_is_point"),_SCS("is_gravity_a_point"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"gravity_distance_scale", PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_gravity_distance_scale"),_SCS("get_gravity_distance_scale"));
ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"gravity_vec"),_SCS("set_gravity_vector"),_SCS("get_gravity_vector"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"gravity",PROPERTY_HINT_RANGE,"-1024,1024,0.01"),_SCS("set_gravity"),_SCS("get_gravity"));
- ADD_PROPERTY( PropertyInfo(Variant::REAL,"density",PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_density"),_SCS("get_density"));
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"linear_damp",PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_linear_damp"),_SCS("get_linear_damp"));
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"angular_damp",PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_angular_damp"),_SCS("get_angular_damp"));
ADD_PROPERTY( PropertyInfo(Variant::INT,"priority",PROPERTY_HINT_RANGE,"0,128,1"),_SCS("set_priority"),_SCS("get_priority"));
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"monitoring"),_SCS("set_enable_monitoring"),_SCS("is_monitoring_enabled"));
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"monitorable"),_SCS("set_monitorable"),_SCS("is_monitorable"));
@@ -586,7 +600,8 @@ Area::Area() : CollisionObject(PhysicsServer::get_singleton()->area_create(),tru
set_gravity_vector(Vector3(0,-1,0));
gravity_is_point=false;
gravity_distance_scale=0;
- density=0.1;
+ linear_damp=0.1;
+ angular_damp=1;
priority=0;
monitoring=false;
set_ray_pickable(false);
diff --git a/scene/3d/area.h b/scene/3d/area.h
index fa7500c47c..c250d27fb1 100644
--- a/scene/3d/area.h
+++ b/scene/3d/area.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -40,7 +40,9 @@ public:
enum SpaceOverride {
SPACE_OVERRIDE_DISABLED,
SPACE_OVERRIDE_COMBINE,
- SPACE_OVERRIDE_REPLACE
+ SPACE_OVERRIDE_COMBINE_REPLACE,
+ SPACE_OVERRIDE_REPLACE,
+ SPACE_OVERRIDE_REPLACE_COMBINE
};
private:
@@ -50,7 +52,8 @@ private:
real_t gravity;
bool gravity_is_point;
real_t gravity_distance_scale;
- real_t density;
+ real_t angular_damp;
+ real_t linear_damp;
int priority;
bool monitoring;
bool monitorable;
@@ -139,8 +142,11 @@ public:
void set_gravity(real_t p_gravity);
real_t get_gravity() const;
- void set_density(real_t p_density);
- real_t get_density() const;
+ void set_angular_damp(real_t p_angular_damp);
+ real_t get_angular_damp() const;
+
+ void set_linear_damp(real_t p_linear_damp);
+ real_t get_linear_damp() const;
void set_priority(real_t p_priority);
real_t get_priority() const;
diff --git a/scene/3d/baked_light_instance.cpp b/scene/3d/baked_light_instance.cpp
index b55093a779..1ae7866f0b 100644
--- a/scene/3d/baked_light_instance.cpp
+++ b/scene/3d/baked_light_instance.cpp
@@ -81,7 +81,7 @@ float BakedLightSampler::get_param(Param p_param) const{
void BakedLightSampler::set_resolution(int p_resolution){
- ERR_FAIL_COND(p_resolution<4 && p_resolution>32);
+ ERR_FAIL_COND(p_resolution<4 || p_resolution>32);
resolution=p_resolution;
VS::get_singleton()->baked_light_sampler_set_resolution(base,resolution);
}
diff --git a/scene/3d/body_shape.cpp b/scene/3d/body_shape.cpp
index c49d1b028c..3a47371de3 100644
--- a/scene/3d/body_shape.cpp
+++ b/scene/3d/body_shape.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -43,7 +43,10 @@
void CollisionShape::_update_body() {
-
+ if (!is_inside_tree() || !can_update_body)
+ return;
+ if (!get_tree()->is_editor_hint())
+ return;
if (get_parent() && get_parent()->cast_to<CollisionObject>())
get_parent()->cast_to<CollisionObject>()->_update_shapes_from_children();
@@ -310,10 +313,13 @@ void CollisionShape::_add_to_collision_object(Object* p_cshape) {
if (shape.is_valid()) {
+ update_shape_index=co->get_shape_count();
co->add_shape(shape,get_transform());
- if (trigger)
- co->set_shape_as_trigger( co->get_shape_count() -1, true );
- }
+ if (trigger)
+ co->set_shape_as_trigger( co->get_shape_count() -1, true );
+ } else {
+ update_shape_index=-1;
+ }
}
void CollisionShape::_notification(int p_what) {
@@ -322,12 +328,18 @@ void CollisionShape::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
unparenting=false;
+ can_update_body=get_tree()->is_editor_hint();
+ set_notify_local_transform(!can_update_body);
+
+ if (get_tree()->is_debugging_collisions_hint()) {
+ _create_debug_shape();
+ }
//indicator_instance = VisualServer::get_singleton()->instance_create2(indicator,get_world()->get_scenario());
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
// VisualServer::get_singleton()->instance_set_transform(indicator_instance,get_global_transform());
- if (updating_body) {
+ if (can_update_body && updating_body) {
_update_body();
}
} break;
@@ -336,16 +348,34 @@ void CollisionShape::_notification(int p_what) {
VisualServer::get_singleton()->free(indicator_instance);
indicator_instance=RID();
}*/
+ can_update_body=false;
+ set_notify_local_transform(false);
+ if (debug_shape) {
+ debug_shape->queue_delete();
+ debug_shape=NULL;
+ }
} break;
case NOTIFICATION_UNPARENTED: {
unparenting=true;
- if (updating_body)
+ if (can_update_body && updating_body)
_update_body();
} break;
case NOTIFICATION_PARENTED: {
- if (updating_body)
+ if (can_update_body && updating_body)
_update_body();
} break;
+ case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
+
+ if (!can_update_body && update_shape_index>=0) {
+
+ CollisionObject *co = get_parent()->cast_to<CollisionObject>();
+ if (co) {
+ co->set_shape_transform(update_shape_index,get_transform());
+ }
+ }
+
+ } break;
+
}
}
@@ -357,10 +387,22 @@ void CollisionShape::resource_changed(RES res) {
}
+void CollisionShape::_set_update_shape_index(int p_index) {
+
+
+ update_shape_index=p_index;
+}
+
+int CollisionShape::_get_update_shape_index() const{
+
+ return update_shape_index;
+}
+
+
void CollisionShape::_bind_methods() {
//not sure if this should do anything
- ObjectTypeDB::bind_method(_MD("resource_changed"),&CollisionShape::resource_changed);
+ ObjectTypeDB::bind_method(_MD("resource_changed","resource"),&CollisionShape::resource_changed);
ObjectTypeDB::bind_method(_MD("set_shape","shape"),&CollisionShape::set_shape);
ObjectTypeDB::bind_method(_MD("get_shape"),&CollisionShape::get_shape);
ObjectTypeDB::bind_method(_MD("_add_to_collision_object"),&CollisionShape::_add_to_collision_object);
@@ -368,10 +410,14 @@ void CollisionShape::_bind_methods() {
ObjectTypeDB::bind_method(_MD("is_trigger"),&CollisionShape::is_trigger);
ObjectTypeDB::bind_method(_MD("make_convex_from_brothers"),&CollisionShape::make_convex_from_brothers);
ObjectTypeDB::set_method_flags("CollisionShape","make_convex_from_brothers",METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
+ ObjectTypeDB::bind_method(_MD("_set_update_shape_index","index"),&CollisionShape::_set_update_shape_index);
+ ObjectTypeDB::bind_method(_MD("_get_update_shape_index"),&CollisionShape::_get_update_shape_index);
+ ObjectTypeDB::bind_method(_MD("get_collision_object_shape_index"),&CollisionShape::get_collision_object_shape_index);
ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape"), _SCS("set_shape"), _SCS("get_shape"));
- ADD_PROPERTY(PropertyInfo(Variant::BOOL,"trigger"),_SCS("set_trigger"),_SCS("is_trigger"));
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL,"trigger"),_SCS("set_trigger"),_SCS("is_trigger"));
+ ADD_PROPERTY( PropertyInfo( Variant::INT, "_update_shape_index", PROPERTY_HINT_NONE, "",PROPERTY_USAGE_NOEDITOR), _SCS("_set_update_shape_index"), _SCS("_get_update_shape_index"));
}
@@ -383,8 +429,15 @@ void CollisionShape::set_shape(const Ref<Shape> &p_shape) {
if (!shape.is_null())
shape->register_owner(this);
update_gizmo();
- if (updating_body)
+ if (updating_body) {
_update_body();
+ } else if (can_update_body && update_shape_index>=0 && is_inside_tree()){
+ CollisionObject *co = get_parent()->cast_to<CollisionObject>();
+ if (co) {
+ co->set_shape(update_shape_index,p_shape);
+ }
+
+ }
}
Ref<Shape> CollisionShape::get_shape() const {
@@ -405,8 +458,14 @@ bool CollisionShape::is_updating_body() const {
void CollisionShape::set_trigger(bool p_trigger) {
trigger=p_trigger;
- if (updating_body)
+ if (updating_body) {
_update_body();
+ } else if (can_update_body && update_shape_index>=0 && is_inside_tree()){
+ CollisionObject *co = get_parent()->cast_to<CollisionObject>();
+ if (co) {
+ co->set_shape_as_trigger(update_shape_index,p_trigger);
+ }
+ }
}
bool CollisionShape::is_trigger() const{
@@ -419,7 +478,10 @@ CollisionShape::CollisionShape() {
//indicator = VisualServer::get_singleton()->mesh_create();
updating_body=true;
unparenting=false;
- trigger=false;
+ update_shape_index=-1;
+ trigger=false;
+ can_update_body=false;
+ debug_shape=NULL;
}
CollisionShape::~CollisionShape() {
@@ -428,6 +490,30 @@ CollisionShape::~CollisionShape() {
//VisualServer::get_singleton()->free(indicator);
}
+void CollisionShape::_create_debug_shape() {
+
+
+ if (debug_shape) {
+ debug_shape->queue_delete();;
+ debug_shape=NULL;
+ }
+
+ Ref<Shape> s = get_shape();
+
+ if (s.is_null())
+ return;
+
+
+ Ref<Mesh> mesh = s->get_debug_mesh();
+
+ MeshInstance *mi = memnew( MeshInstance );
+ mi->set_mesh(mesh);
+
+ add_child(mi);
+ debug_shape=mi;
+
+}
+
#if 0
#include "body_volume.h"
diff --git a/scene/3d/body_shape.h b/scene/3d/body_shape.h
index b3c0006d79..dd005c0edd 100644
--- a/scene/3d/body_shape.h
+++ b/scene/3d/body_shape.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -50,14 +50,26 @@ class CollisionShape : public Spatial {
RID indicator_instance;
*/
+ Node* debug_shape;
+
void resource_changed(RES res);
bool updating_body;
bool unparenting;
bool trigger;
+ bool can_update_body;
+
+ int update_shape_index;
+
void _update_body();
void _add_to_collision_object(Object* p_cshape);
+
+ void _set_update_shape_index(int p_index);
+ int _get_update_shape_index() const;
+
+ void _create_debug_shape();
+
protected:
void _notification(int p_what);
@@ -73,8 +85,10 @@ public:
void set_updating_body(bool p_update);
bool is_updating_body() const;
- void set_trigger(bool p_trigger);
- bool is_trigger() const;
+ void set_trigger(bool p_trigger);
+ bool is_trigger() const;
+
+ int get_collision_object_shape_index() const { return _get_update_shape_index(); }
CollisionShape();
~CollisionShape();
diff --git a/scene/3d/bone_attachment.cpp b/scene/3d/bone_attachment.cpp
index 9cc1719f94..1628ccc15e 100644
--- a/scene/3d/bone_attachment.cpp
+++ b/scene/3d/bone_attachment.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/bone_attachment.h b/scene/3d/bone_attachment.h
index ca36cc3694..f1c27a9650 100644
--- a/scene/3d/bone_attachment.h
+++ b/scene/3d/bone_attachment.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp
index dce5060a44..3e78fef147 100644
--- a/scene/3d/camera.cpp
+++ b/scene/3d/camera.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -125,7 +125,7 @@ bool Camera::_get(const StringName& p_name,Variant &r_ret) const {
r_ret= int(keep_aspect);
else if (p_name=="current") {
- if (is_inside_tree() && get_tree()->is_editor_hint()) {
+ if (is_inside_tree() && get_tree()->is_node_being_edited(this)) {
r_ret=current;
} else {
r_ret=is_current();
@@ -192,12 +192,11 @@ void Camera::_update_camera() {
// here goes listener stuff
// if (viewport_ptr && is_inside_scene() && is_current())
-// viewport_ptr->_camera_transform_changed_notify();
+// get_viewport()->_camera_transform_changed_notify();
if (is_inside_tree() && is_current()) {
- if (viewport_ptr) {
- viewport_ptr->_camera_transform_changed_notify();
- }
+ get_viewport()->_camera_transform_changed_notify();
+
}
if (is_current() && get_world().is_valid()) {
@@ -213,29 +212,10 @@ void Camera::_notification(int p_what) {
case NOTIFICATION_ENTER_WORLD: {
- viewport_ptr=NULL;
-
- { //find viewport stuff
- Node *parent=get_parent();
- while(parent) {
-
- Viewport* viewport = parent->cast_to<Viewport>();
-
- if (viewport) {
- viewport_ptr=viewport;
- break;
- }
- parent=parent->get_parent();
- }
-
- }
-
- camera_group = "_vp_cameras"+itos(get_viewport()->get_instance_ID());
- add_to_group(camera_group);
- if (viewport_ptr)
- viewport_ptr->cameras.insert(this);
- if (current)
+ bool first_camera = get_viewport()->cameras.size()==0;
+ get_viewport()->cameras.insert(this);
+ if (!get_tree()->is_node_being_edited(this) && (current || first_camera))
make_current();
@@ -246,17 +226,17 @@ void Camera::_notification(int p_what) {
} break;
case NOTIFICATION_EXIT_WORLD: {
- if (is_current()) {
- clear_current();
- current=true; //keep it true
+ if (!get_tree()->is_node_being_edited(this)) {
+ if (is_current()) {
+ clear_current();
+ current=true; //keep it true
- } else {
- current=false;
+ } else {
+ current=false;
+ }
}
- if (viewport_ptr)
- viewport_ptr->cameras.erase(this);
- viewport_ptr=NULL;
- remove_from_group(camera_group);
+
+ get_viewport()->cameras.erase(this);
} break;
@@ -324,25 +304,12 @@ void Camera::make_current() {
if (!is_inside_tree())
return;
- if (viewport_ptr) {
- viewport_ptr->_set_camera(this);
- }
+ get_viewport()->_set_camera(this);
//get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,camera_group,"_camera_make_current",this);
}
-void Camera::_camera_make_next_current(Node *p_exclude) {
-
- if (this==p_exclude)
- return;
- if (!is_inside_tree())
- return;
- if (get_viewport()->get_camera()!=NULL)
- return;
-
- make_current();
-}
void Camera::clear_current() {
@@ -351,12 +318,20 @@ void Camera::clear_current() {
if (!is_inside_tree())
return;
- if (viewport_ptr) {
- if (viewport_ptr->get_camera()==this) {
- viewport_ptr->_set_camera(NULL);
- //a group is used beause this needs to be in order to be deterministic
- get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,camera_group,"_camera_make_next_current",this);
+ if (get_viewport()->get_camera()==this) {
+ get_viewport()->_set_camera(NULL);
+ //a group is used beause this needs to be in order to be deterministic
+
+ for (Set<Camera*>::Element *E=get_viewport()->cameras.front();E;E=E->next()) {
+ if (this==E->get())
+ continue;
+ if (!E->get()->is_inside_tree())
+ continue;
+ if (get_viewport()->get_camera()!=NULL)
+ return;
+
+ E->get()->make_current();
}
}
@@ -364,9 +339,9 @@ void Camera::clear_current() {
bool Camera::is_current() const {
- if (is_inside_tree()) {
- if (viewport_ptr)
- return viewport_ptr->get_camera()==this;
+ if (is_inside_tree() && !get_tree()->is_node_being_edited(this)) {
+
+ return get_viewport()->get_camera()==this;
} else
return current;
@@ -481,12 +456,12 @@ Vector3 Camera::project_local_ray_normal(const Point2& p_pos) const {
#if 0
- Size2 viewport_size = viewport_ptr->get_visible_rect().size;
+ Size2 viewport_size = get_viewport()->get_visible_rect().size;
Vector2 cpos = p_pos;
#else
- Size2 viewport_size = viewport_ptr->get_camera_rect_size();
- Vector2 cpos = viewport_ptr->get_camera_coords(p_pos);
+ Size2 viewport_size = get_viewport()->get_camera_rect_size();
+ Vector2 cpos = get_viewport()->get_camera_coords(p_pos);
#endif
Vector3 ray;
@@ -514,12 +489,12 @@ Vector3 Camera::project_ray_origin(const Point2& p_pos) const {
}
#if 0
- Size2 viewport_size = viewport_ptr->get_visible_rect().size;
+ Size2 viewport_size = get_viewport()->get_visible_rect().size;
Vector2 cpos = p_pos;
#else
- Size2 viewport_size = viewport_ptr->get_camera_rect_size();
- Vector2 cpos = viewport_ptr->get_camera_coords(p_pos);
+ Size2 viewport_size = get_viewport()->get_camera_rect_size();
+ Vector2 cpos = get_viewport()->get_camera_coords(p_pos);
#endif
ERR_FAIL_COND_V( viewport_size.y == 0, Vector3() );
@@ -566,7 +541,7 @@ Point2 Camera::unproject_position(const Vector3& p_pos) const {
ERR_FAIL_COND_V(!is_inside_tree(),Vector2());
}
- Size2 viewport_size = viewport_ptr->get_visible_rect().size;
+ Size2 viewport_size = get_viewport()->get_visible_rect().size;
CameraMatrix cm;
@@ -597,7 +572,7 @@ Vector3 Camera::project_position(const Point2& p_point) const {
ERR_FAIL_COND_V(!is_inside_tree(),Vector3());
}
- Size2 viewport_size = viewport_ptr->get_visible_rect().size;
+ Size2 viewport_size = get_viewport()->get_visible_rect().size;
CameraMatrix cm;
@@ -692,7 +667,6 @@ void Camera::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_environment:Environment"),&Camera::get_environment);
ObjectTypeDB::bind_method(_MD("set_keep_aspect_mode","mode"),&Camera::set_keep_aspect_mode);
ObjectTypeDB::bind_method(_MD("get_keep_aspect_mode"),&Camera::get_keep_aspect_mode);
- ObjectTypeDB::bind_method(_MD("_camera_make_next_current"),&Camera::_camera_make_next_current);
//ObjectTypeDB::bind_method( _MD("_camera_make_current"),&Camera::_camera_make_current );
BIND_CONSTANT( PROJECTION_PERSPECTIVE );
@@ -745,7 +719,7 @@ Vector<Plane> Camera::get_frustum() const {
ERR_FAIL_COND_V(!is_inside_world(),Vector<Plane>());
- Size2 viewport_size = viewport_ptr->get_visible_rect().size;
+ Size2 viewport_size = get_viewport()->get_visible_rect().size;
CameraMatrix cm;
if (mode==PROJECTION_PERSPECTIVE)
cm.set_perspective(fov,viewport_size.get_aspect(),near,far,keep_aspect==KEEP_WIDTH);
@@ -789,7 +763,6 @@ Camera::Camera() {
near=0;
far=0;
current=false;
- viewport_ptr=NULL;
force_change=false;
mode=PROJECTION_PERSPECTIVE;
set_perspective(60.0,0.1,100.0);
diff --git a/scene/3d/camera.h b/scene/3d/camera.h
index e21f4865ec..02ca6ffb9a 100644
--- a/scene/3d/camera.h
+++ b/scene/3d/camera.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -68,18 +68,15 @@ private:
RID camera;
RID scenario_id;
- String camera_group;
+ //String camera_group;
uint32_t layers;
- Viewport *viewport_ptr;
Ref<Environment> environment;
virtual bool _can_gizmo_scale() const;
virtual RES _get_gizmo_geometry() const;
- void _camera_make_next_current(Node *p_exclude);
-
//void _camera_make_current(Node *p_camera);
friend class Viewport;
diff --git a/scene/3d/character_camera.cpp b/scene/3d/character_camera.cpp
index 19332bd056..2b22026fe9 100644
--- a/scene/3d/character_camera.cpp
+++ b/scene/3d/character_camera.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/character_camera.h b/scene/3d/character_camera.h
index 99b41c6eda..d636b4b1a5 100644
--- a/scene/3d/character_camera.h
+++ b/scene/3d/character_camera.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/collision_object.cpp b/scene/3d/collision_object.cpp
index efc5db50e1..b50878da07 100644
--- a/scene/3d/collision_object.cpp
+++ b/scene/3d/collision_object.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -122,8 +122,8 @@ bool CollisionObject::_set(const StringName& p_name, const Variant& p_value) {
} else if (name.begins_with("shapes/")) {
- int idx=name.get_slice("/",1).to_int();
- String what=name.get_slice("/",2);
+ int idx=name.get_slicec('/',1).to_int();
+ String what=name.get_slicec('/',2);
if (what=="shape")
set_shape(idx,RefPtr(p_value));
else if (what=="transform")
@@ -148,8 +148,8 @@ bool CollisionObject::_get(const StringName& p_name,Variant &r_ret) const {
r_ret= shapes.size();
} else if (name.begins_with("shapes/")) {
- int idx=name.get_slice("/",1).to_int();
- String what=name.get_slice("/",2);
+ int idx=name.get_slicec('/',1).to_int();
+ String what=name.get_slicec('/',2);
if (what=="shape")
r_ret= get_shape(idx);
else if (what=="transform")
diff --git a/scene/3d/collision_object.h b/scene/3d/collision_object.h
index 548c9fb85b..f8daeb3ed2 100644
--- a/scene/3d/collision_object.h
+++ b/scene/3d/collision_object.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/collision_polygon.cpp b/scene/3d/collision_polygon.cpp
index 4ab1a1a1ab..3b14e1d767 100644
--- a/scene/3d/collision_polygon.cpp
+++ b/scene/3d/collision_polygon.cpp
@@ -6,6 +6,8 @@
void CollisionPolygon::_add_to_collision_object(Object *p_obj) {
+ if (!can_update_body)
+ return;
CollisionObject *co = p_obj->cast_to<CollisionObject>();
ERR_FAIL_COND(!co);
@@ -23,6 +25,7 @@ void CollisionPolygon::_add_to_collision_object(Object *p_obj) {
//here comes the sun, lalalala
//decompose concave into multiple convex polygons and add them
+ shape_from=co->get_shape_count();
for(int i=0;i<decomp.size();i++) {
Ref<ConvexPolygonShape> convex = memnew( ConvexPolygonShape );
DVector<Vector3> cp;
@@ -43,6 +46,11 @@ void CollisionPolygon::_add_to_collision_object(Object *p_obj) {
co->add_shape(convex,get_transform());
}
+ shape_to=co->get_shape_count()-1;
+ if (shape_to<shape_from) {
+ shape_from=-1;
+ shape_to=-1;
+ }
} else {
#if 0
@@ -71,6 +79,9 @@ void CollisionPolygon::_add_to_collision_object(Object *p_obj) {
void CollisionPolygon::_update_parent() {
+ if (!can_update_body)
+ return;
+
Node *parent = get_parent();
if (!parent)
return;
@@ -80,15 +91,50 @@ void CollisionPolygon::_update_parent() {
co->_update_shapes_from_children();
}
+void CollisionPolygon::_set_shape_range(const Vector2& p_range) {
+
+ shape_from=p_range.x;
+ shape_to=p_range.y;
+}
+
+Vector2 CollisionPolygon::_get_shape_range() const {
+
+ return Vector2(shape_from,shape_to);
+}
+
void CollisionPolygon::_notification(int p_what) {
switch(p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ can_update_body=get_tree()->is_editor_hint();
+ set_notify_local_transform(!can_update_body);
+
+ //indicator_instance = VisualServer::get_singleton()->instance_create2(indicator,get_world()->get_scenario());
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+ can_update_body=false;
+ set_notify_local_transform(false);
+ } break;
case NOTIFICATION_TRANSFORM_CHANGED: {
if (!is_inside_tree())
break;
- _update_parent();
+ if (can_update_body) {
+ _update_parent();
+ }
+
+ } break;
+ case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
+ if (!can_update_body && shape_from>=0 && shape_to>=0) {
+
+ CollisionObject *co = get_parent()->cast_to<CollisionObject>();
+ if (co) {
+ for(int i=shape_from;i<=shape_to;i++) {
+ co->set_shape_transform(i,get_transform());
+ }
+ }
+ }
} break;
#if 0
@@ -119,29 +165,31 @@ void CollisionPolygon::_notification(int p_what) {
void CollisionPolygon::set_polygon(const Vector<Point2>& p_polygon) {
polygon=p_polygon;
+ if (can_update_body) {
- for(int i=0;i<polygon.size();i++) {
+ for(int i=0;i<polygon.size();i++) {
- Vector3 p1(polygon[i].x,polygon[i].y,depth*0.5);
+ Vector3 p1(polygon[i].x,polygon[i].y,depth*0.5);
- if (i==0)
- aabb=AABB(p1,Vector3());
- else
- aabb.expand_to(p1);
+ if (i==0)
+ aabb=AABB(p1,Vector3());
+ else
+ aabb.expand_to(p1);
- Vector3 p2(polygon[i].x,polygon[i].y,-depth*0.5);
- aabb.expand_to(p2);
+ Vector3 p2(polygon[i].x,polygon[i].y,-depth*0.5);
+ aabb.expand_to(p2);
- }
- if (aabb==AABB()) {
+ }
+ if (aabb==AABB()) {
- aabb=AABB(Vector3(-1,-1,-1),Vector3(2,2,2));
- } else {
- aabb.pos-=aabb.size*0.3;
- aabb.size+=aabb.size*0.6;
+ aabb=AABB(Vector3(-1,-1,-1),Vector3(2,2,2));
+ } else {
+ aabb.pos-=aabb.size*0.3;
+ aabb.size+=aabb.size*0.6;
+ }
+ _update_parent();
}
- _update_parent();
update_gizmo();
}
@@ -154,6 +202,8 @@ void CollisionPolygon::set_build_mode(BuildMode p_mode) {
ERR_FAIL_INDEX(p_mode,2);
build_mode=p_mode;
+ if (!can_update_body)
+ return;
_update_parent();
}
@@ -170,6 +220,8 @@ AABB CollisionPolygon::get_item_rect() const {
void CollisionPolygon::set_depth(float p_depth) {
depth=p_depth;
+ if (!can_update_body)
+ return;
_update_parent();
update_gizmo();
}
@@ -183,22 +235,34 @@ float CollisionPolygon::get_depth() const {
void CollisionPolygon::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_add_to_collision_object"),&CollisionPolygon::_add_to_collision_object);
- ObjectTypeDB::bind_method(_MD("set_polygon","polygon"),&CollisionPolygon::set_polygon);
- ObjectTypeDB::bind_method(_MD("get_polygon"),&CollisionPolygon::get_polygon);
+
+ ObjectTypeDB::bind_method(_MD("set_build_mode","build_mode"),&CollisionPolygon::set_build_mode);
+ ObjectTypeDB::bind_method(_MD("get_build_mode"),&CollisionPolygon::get_build_mode);
ObjectTypeDB::bind_method(_MD("set_depth","depth"),&CollisionPolygon::set_depth);
ObjectTypeDB::bind_method(_MD("get_depth"),&CollisionPolygon::get_depth);
- ObjectTypeDB::bind_method(_MD("set_build_mode"),&CollisionPolygon::set_build_mode);
- ObjectTypeDB::bind_method(_MD("get_build_mode"),&CollisionPolygon::get_build_mode);
+ ObjectTypeDB::bind_method(_MD("set_polygon","polygon"),&CollisionPolygon::set_polygon);
+ ObjectTypeDB::bind_method(_MD("get_polygon"),&CollisionPolygon::get_polygon);
+
+ ObjectTypeDB::bind_method(_MD("_set_shape_range","shape_range"),&CollisionPolygon::_set_shape_range);
+ ObjectTypeDB::bind_method(_MD("_get_shape_range"),&CollisionPolygon::_get_shape_range);
+
+ ObjectTypeDB::bind_method(_MD("get_collision_object_first_shape"),&CollisionPolygon::get_collision_object_first_shape);
+ ObjectTypeDB::bind_method(_MD("get_collision_object_last_shape"),&CollisionPolygon::get_collision_object_last_shape);
ADD_PROPERTY( PropertyInfo(Variant::INT,"build_mode",PROPERTY_HINT_ENUM,"Solids,Triangles"),_SCS("set_build_mode"),_SCS("get_build_mode"));
- ADD_PROPERTY( PropertyInfo(Variant::VECTOR2_ARRAY,"polygon"),_SCS("set_polygon"),_SCS("get_polygon"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"depth"),_SCS("set_depth"),_SCS("get_depth"));
+ ADD_PROPERTY( PropertyInfo(Variant::VECTOR2_ARRAY,"polygon"),_SCS("set_polygon"),_SCS("get_polygon"));
+ ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"shape_range",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_shape_range"),_SCS("_get_shape_range"));
}
CollisionPolygon::CollisionPolygon() {
+ shape_from=-1;
+ shape_to=-1;
+ can_update_body=false;
+
aabb=AABB(Vector3(-1,-1,-1),Vector3(2,2,2));
build_mode=BUILD_SOLIDS;
depth=1.0;
diff --git a/scene/3d/collision_polygon.h b/scene/3d/collision_polygon.h
index efb3666778..9b9afea34f 100644
--- a/scene/3d/collision_polygon.h
+++ b/scene/3d/collision_polygon.h
@@ -24,9 +24,17 @@ protected:
BuildMode build_mode;
Vector<Point2> polygon;
+
void _add_to_collision_object(Object *p_obj);
void _update_parent();
+ bool can_update_body;
+ int shape_from;
+ int shape_to;
+
+ void _set_shape_range(const Vector2& p_range);
+ Vector2 _get_shape_range() const;
+
protected:
void _notification(int p_what);
@@ -43,6 +51,10 @@ public:
Vector<Point2> get_polygon() const;
virtual AABB get_item_rect() const;
+
+ int get_collision_object_first_shape() const { return shape_from; }
+ int get_collision_object_last_shape() const { return shape_to; }
+
CollisionPolygon();
};
diff --git a/scene/3d/interpolated_camera.cpp b/scene/3d/interpolated_camera.cpp
index f44713e8a0..96306d1180 100644
--- a/scene/3d/interpolated_camera.cpp
+++ b/scene/3d/interpolated_camera.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/interpolated_camera.h b/scene/3d/interpolated_camera.h
index a8ed649c42..dbe84327fb 100644
--- a/scene/3d/interpolated_camera.h
+++ b/scene/3d/interpolated_camera.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp
index 9f9c87b675..18463742c6 100644
--- a/scene/3d/light.cpp
+++ b/scene/3d/light.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -487,9 +487,9 @@ bool Light::is_editor_only() const{
void Light::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_parameter","variable","value"), &Light::set_parameter );
- ObjectTypeDB::bind_method(_MD("get_parameter"), &Light::get_parameter );
+ ObjectTypeDB::bind_method(_MD("get_parameter","variable"), &Light::get_parameter );
ObjectTypeDB::bind_method(_MD("set_color","color","value"), &Light::set_color );
- ObjectTypeDB::bind_method(_MD("get_color"), &Light::get_color );
+ ObjectTypeDB::bind_method(_MD("get_color","color"), &Light::get_color );
ObjectTypeDB::bind_method(_MD("set_project_shadows","enable"), &Light::set_project_shadows );
ObjectTypeDB::bind_method(_MD("has_project_shadows"), &Light::has_project_shadows );
ObjectTypeDB::bind_method(_MD("set_projector","projector:Texture"), &Light::set_projector );
diff --git a/scene/3d/light.h b/scene/3d/light.h
index fb77ac9e64..b74085b7a9 100644
--- a/scene/3d/light.h
+++ b/scene/3d/light.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp
index 62b32729c3..997d2dea7c 100644
--- a/scene/3d/mesh_instance.cpp
+++ b/scene/3d/mesh_instance.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/mesh_instance.h b/scene/3d/mesh_instance.h
index 76a0eeea60..f26ef52000 100644
--- a/scene/3d/mesh_instance.h
+++ b/scene/3d/mesh_instance.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/multimesh_instance.cpp b/scene/3d/multimesh_instance.cpp
index cd620ff447..0e97a97943 100644
--- a/scene/3d/multimesh_instance.cpp
+++ b/scene/3d/multimesh_instance.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/multimesh_instance.h b/scene/3d/multimesh_instance.h
index be6b3677e2..7cd9a8ea82 100644
--- a/scene/3d/multimesh_instance.h
+++ b/scene/3d/multimesh_instance.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp
index bfa8add09c..ce28350be0 100644
--- a/scene/3d/navigation.cpp
+++ b/scene/3d/navigation.cpp
@@ -295,12 +295,14 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3& p_start, const Vector
}
}
+
if (!begin_poly || !end_poly) {
//print_line("No Path Path");
return Vector<Vector3>(); //no path
}
+
if (begin_poly==end_poly) {
Vector<Vector3> path;
diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp
index 8c52d4c35c..a238a8ff22 100644
--- a/scene/3d/navigation_mesh.cpp
+++ b/scene/3d/navigation_mesh.cpp
@@ -1,6 +1,6 @@
#include "navigation_mesh.h"
#include "navigation.h"
-
+#include "mesh_instance.h"
void NavigationMesh::create_from_mesh(const Ref<Mesh>& p_mesh) {
@@ -87,6 +87,97 @@ void NavigationMesh::clear_polygons(){
polygons.clear();
}
+Ref<Mesh> NavigationMesh::get_debug_mesh() {
+
+ if (debug_mesh.is_valid())
+ return debug_mesh;
+
+
+
+ DVector<Vector3> vertices = get_vertices();
+ DVector<Vector3>::Read vr=vertices.read();
+ List<Face3> faces;
+ for(int i=0;i<get_polygon_count();i++) {
+ Vector<int> p = get_polygon(i);
+
+ for(int j=2;j<p.size();j++) {
+ Face3 f;
+ f.vertex[0]=vr[p[0]];
+ f.vertex[1]=vr[p[j-1]];
+ f.vertex[2]=vr[p[j]];
+
+ faces.push_back(f);
+ }
+ }
+
+
+ Map<_EdgeKey,bool> edge_map;
+ DVector<Vector3> tmeshfaces;
+ tmeshfaces.resize(faces.size()*3);
+
+ {
+ DVector<Vector3>::Write tw=tmeshfaces.write();
+ int tidx=0;
+
+
+ for(List<Face3>::Element *E=faces.front();E;E=E->next()) {
+
+ const Face3 &f = E->get();
+
+ for(int j=0;j<3;j++) {
+
+ tw[tidx++]=f.vertex[j];
+ _EdgeKey ek;
+ ek.from=f.vertex[j].snapped(CMP_EPSILON);
+ ek.to=f.vertex[(j+1)%3].snapped(CMP_EPSILON);
+ if (ek.from<ek.to)
+ SWAP(ek.from,ek.to);
+
+ Map<_EdgeKey,bool>::Element *E=edge_map.find(ek);
+
+ if (E) {
+
+ E->get()=false;
+
+ } else {
+
+ edge_map[ek]=true;
+ }
+
+ }
+ }
+ }
+ List<Vector3> lines;
+
+ for(Map<_EdgeKey,bool>::Element *E=edge_map.front();E;E=E->next()) {
+
+ if (E->get()) {
+ lines.push_back(E->key().from);
+ lines.push_back(E->key().to);
+ }
+ }
+
+ DVector<Vector3> varr;
+ varr.resize(lines.size());
+ {
+ DVector<Vector3>::Write w = varr.write();
+ int idx=0;
+ for(List<Vector3>::Element *E=lines.front();E;E=E->next()) {
+ w[idx++]=E->get();
+ }
+ }
+
+ debug_mesh = Ref<Mesh>( memnew( Mesh ) );
+
+ Array arr;
+ arr.resize(Mesh::ARRAY_MAX);
+ arr[Mesh::ARRAY_VERTEX]=varr;
+
+ debug_mesh->add_surface(Mesh::PRIMITIVE_LINES,arr);
+
+ return debug_mesh;
+}
+
void NavigationMesh::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_vertices","vertices"),&NavigationMesh::set_vertices);
@@ -135,6 +226,16 @@ void NavigationMeshInstance::set_enabled(bool p_enabled) {
}
+ if (debug_view) {
+ MeshInstance *dm=debug_view->cast_to<MeshInstance>();
+ if (is_enabled()) {
+ dm->set_material_override( get_tree()->get_debug_navigation_material() );
+ } else {
+ dm->set_material_override( get_tree()->get_debug_navigation_disabled_material() );
+ }
+
+ }
+
update_gizmo();
}
@@ -170,6 +271,19 @@ void NavigationMeshInstance::_notification(int p_what) {
c=c->get_parent_spatial();
}
+ if (navmesh.is_valid() && get_tree()->is_debugging_navigation_hint()) {
+
+ MeshInstance *dm = memnew( MeshInstance );
+ dm->set_mesh( navmesh->get_debug_mesh() );
+ if (is_enabled()) {
+ dm->set_material_override( get_tree()->get_debug_navigation_material() );
+ } else {
+ dm->set_material_override( get_tree()->get_debug_navigation_disabled_material() );
+ }
+ add_child(dm);
+ debug_view=dm;
+ }
+
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
@@ -177,6 +291,8 @@ void NavigationMeshInstance::_notification(int p_what) {
navigation->navmesh_set_transform(nav_id,get_relative_transform(navigation));
}
+
+
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -187,6 +303,11 @@ void NavigationMeshInstance::_notification(int p_what) {
nav_id=-1;
}
}
+
+ if (debug_view) {
+ debug_view->queue_delete();
+ debug_view=NULL;
+ }
navigation=NULL;
} break;
}
@@ -230,6 +351,7 @@ void NavigationMeshInstance::_bind_methods() {
NavigationMeshInstance::NavigationMeshInstance() {
+ debug_view=NULL;
navigation=NULL;
nav_id=-1;
enabled=true;
diff --git a/scene/3d/navigation_mesh.h b/scene/3d/navigation_mesh.h
index fccf405f9d..1e53b2127a 100644
--- a/scene/3d/navigation_mesh.h
+++ b/scene/3d/navigation_mesh.h
@@ -4,6 +4,7 @@
#include "scene/3d/spatial.h"
#include "scene/resources/mesh.h"
+class Mesh;
class NavigationMesh : public Resource {
@@ -14,6 +15,16 @@ class NavigationMesh : public Resource {
Vector<int> indices;
};
Vector<Polygon> polygons;
+ Ref<Mesh> debug_mesh;
+
+ struct _EdgeKey {
+
+ Vector3 from;
+ Vector3 to;
+
+ bool operator<(const _EdgeKey& p_with) const { return from==p_with.from ? to < p_with.to : from < p_with.from; }
+ };
+
protected:
@@ -21,6 +32,7 @@ protected:
void _set_polygons(const Array& p_array);
Array _get_polygons() const;
+
public:
void create_from_mesh(const Ref<Mesh>& p_mesh);
@@ -33,6 +45,8 @@ public:
Vector<int> get_polygon(int p_idx);
void clear_polygons();
+ Ref<Mesh> get_debug_mesh();
+
NavigationMesh();
};
@@ -47,6 +61,9 @@ class NavigationMeshInstance : public Spatial {
int nav_id;
Navigation *navigation;
Ref<NavigationMesh> navmesh;
+
+ Node *debug_view;
+
protected:
void _notification(int p_what);
diff --git a/scene/3d/optimized_spatial_scene.cpp b/scene/3d/optimized_spatial_scene.cpp
index 85c1b79a9a..27631c7a74 100644
--- a/scene/3d/optimized_spatial_scene.cpp
+++ b/scene/3d/optimized_spatial_scene.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/optimized_spatial_scene.h b/scene/3d/optimized_spatial_scene.h
index a55b5235da..e1e6e14f73 100644
--- a/scene/3d/optimized_spatial_scene.h
+++ b/scene/3d/optimized_spatial_scene.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp
index 6868646c48..dfd5c38266 100644
--- a/scene/3d/particles.cpp
+++ b/scene/3d/particles.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -422,14 +422,14 @@ void Particles::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_variable","variable","value"),&Particles::set_variable);
ObjectTypeDB::bind_method(_MD("get_variable","variable"),&Particles::get_variable);
ObjectTypeDB::bind_method(_MD("set_randomness","variable","randomness"),&Particles::set_randomness);
- ObjectTypeDB::bind_method(_MD("get_randomness"),&Particles::get_randomness);
+ ObjectTypeDB::bind_method(_MD("get_randomness","variable"),&Particles::get_randomness);
ObjectTypeDB::bind_method(_MD("set_color_phase_pos","phase","pos"),&Particles::set_color_phase_pos);
ObjectTypeDB::bind_method(_MD("get_color_phase_pos","phase"),&Particles::get_color_phase_pos);
ObjectTypeDB::bind_method(_MD("set_color_phase_color","phase","color"),&Particles::set_color_phase_color);
ObjectTypeDB::bind_method(_MD("get_color_phase_color","phase"),&Particles::get_color_phase_color);
ObjectTypeDB::bind_method(_MD("set_material","material:Material"),&Particles::set_material);
ObjectTypeDB::bind_method(_MD("get_material:Material"),&Particles::get_material);
- ObjectTypeDB::bind_method(_MD("set_emit_timeout"),&Particles::set_emit_timeout);
+ ObjectTypeDB::bind_method(_MD("set_emit_timeout","timeout"),&Particles::set_emit_timeout);
ObjectTypeDB::bind_method(_MD("get_emit_timeout"),&Particles::get_emit_timeout);
ObjectTypeDB::bind_method(_MD("set_height_from_velocity","enable"),&Particles::set_height_from_velocity);
ObjectTypeDB::bind_method(_MD("has_height_from_velocity"),&Particles::has_height_from_velocity);
diff --git a/scene/3d/particles.h b/scene/3d/particles.h
index 260573fe5f..b9cae332e2 100644
--- a/scene/3d/particles.h
+++ b/scene/3d/particles.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/path.cpp b/scene/3d/path.cpp
index 9cd41b25f6..d6cd3da7c3 100644
--- a/scene/3d/path.cpp
+++ b/scene/3d/path.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/path.h b/scene/3d/path.h
index 1b40ec413d..2e3573df3e 100644
--- a/scene/3d/path.h
+++ b/scene/3d/path.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp
index 3d5091f667..1a2665b6ad 100644
--- a/scene/3d/physics_body.cpp
+++ b/scene/3d/physics_body.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -133,6 +133,8 @@ real_t StaticBody::get_bounce() const{
return bounce;
}
+
+
void StaticBody::set_constant_linear_velocity(const Vector3& p_vel) {
constant_linear_velocity=p_vel;
@@ -205,6 +207,9 @@ void RigidBody::_body_enter_tree(ObjectID p_id) {
ERR_FAIL_COND(E->get().in_tree);
E->get().in_tree=true;
+
+ contact_monitor->locked=true;
+
emit_signal(SceneStringNames::get_singleton()->body_enter,node);
for(int i=0;i<E->get().shapes.size();i++) {
@@ -212,6 +217,9 @@ void RigidBody::_body_enter_tree(ObjectID p_id) {
emit_signal(SceneStringNames::get_singleton()->body_enter_shape,p_id,node,E->get().shapes[i].body_shape,E->get().shapes[i].local_shape);
}
+ contact_monitor->locked=false;
+
+
}
void RigidBody::_body_exit_tree(ObjectID p_id) {
@@ -223,11 +231,18 @@ void RigidBody::_body_exit_tree(ObjectID p_id) {
ERR_FAIL_COND(!E);
ERR_FAIL_COND(!E->get().in_tree);
E->get().in_tree=false;
+
+ contact_monitor->locked=true;
+
emit_signal(SceneStringNames::get_singleton()->body_exit,node);
+
for(int i=0;i<E->get().shapes.size();i++) {
emit_signal(SceneStringNames::get_singleton()->body_exit_shape,p_id,node,E->get().shapes[i].body_shape,E->get().shapes[i].local_shape);
}
+
+ contact_monitor->locked=false;
+
}
void RigidBody::_body_inout(int p_status, ObjectID p_instance, int p_body_shape,int p_local_shape) {
@@ -315,6 +330,8 @@ void RigidBody::_direct_state_changed(Object *p_state) {
if (contact_monitor) {
+ contact_monitor->locked=true;
+
//untag all
int rc=0;
for( Map<ObjectID,BodyState>::Element *E=contact_monitor->body_map.front();E;E=E->next()) {
@@ -394,6 +411,8 @@ void RigidBody::_direct_state_changed(Object *p_state) {
_body_inout(1,toadd[i].id,toadd[i].shape,toadd[i].local_shape);
}
+ contact_monitor->locked=false;
+
}
set_ignore_transform_notification(true);
@@ -494,6 +513,42 @@ real_t RigidBody::get_bounce() const{
return bounce;
}
+
+void RigidBody::set_gravity_scale(real_t p_gravity_scale){
+
+ gravity_scale=p_gravity_scale;
+ PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_GRAVITY_SCALE,gravity_scale);
+
+}
+real_t RigidBody::get_gravity_scale() const{
+
+ return gravity_scale;
+}
+
+void RigidBody::set_linear_damp(real_t p_linear_damp){
+
+ ERR_FAIL_COND(p_linear_damp<-1);
+ linear_damp=p_linear_damp;
+ PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_LINEAR_DAMP,linear_damp);
+
+}
+real_t RigidBody::get_linear_damp() const{
+
+ return linear_damp;
+}
+
+void RigidBody::set_angular_damp(real_t p_angular_damp){
+
+ ERR_FAIL_COND(p_angular_damp<-1);
+ angular_damp=p_angular_damp;
+ PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_ANGULAR_DAMP,angular_damp);
+
+}
+real_t RigidBody::get_angular_damp() const{
+
+ return angular_damp;
+}
+
void RigidBody::set_axis_velocity(const Vector3& p_axis) {
Vector3 v = state? state->get_linear_velocity() : linear_velocity;
@@ -610,6 +665,11 @@ void RigidBody::set_contact_monitor(bool p_enabled) {
if (!p_enabled) {
+ if (contact_monitor->locked) {
+ ERR_EXPLAIN("Can't disable contact monitoring during in/out callback. Use call_deferred(\"set_contact_monitor\",false) instead");
+ }
+ ERR_FAIL_COND(contact_monitor->locked);
+
for(Map<ObjectID,BodyState>::Element *E=contact_monitor->body_map.front();E;E=E->next()) {
//clean up mess
@@ -620,6 +680,8 @@ void RigidBody::set_contact_monitor(bool p_enabled) {
} else {
contact_monitor = memnew( ContactMonitor );
+ contact_monitor->locked=false;
+
}
}
@@ -685,6 +747,16 @@ void RigidBody::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_angular_velocity","angular_velocity"),&RigidBody::set_angular_velocity);
ObjectTypeDB::bind_method(_MD("get_angular_velocity"),&RigidBody::get_angular_velocity);
+ ObjectTypeDB::bind_method(_MD("set_gravity_scale","gravity_scale"),&RigidBody::set_gravity_scale);
+ ObjectTypeDB::bind_method(_MD("get_gravity_scale"),&RigidBody::get_gravity_scale);
+
+ ObjectTypeDB::bind_method(_MD("set_linear_damp","linear_damp"),&RigidBody::set_linear_damp);
+ ObjectTypeDB::bind_method(_MD("get_linear_damp"),&RigidBody::get_linear_damp);
+
+ ObjectTypeDB::bind_method(_MD("set_angular_damp","angular_damp"),&RigidBody::set_angular_damp);
+ ObjectTypeDB::bind_method(_MD("get_angular_damp"),&RigidBody::get_angular_damp);
+
+
ObjectTypeDB::bind_method(_MD("set_max_contacts_reported","amount"),&RigidBody::set_max_contacts_reported);
ObjectTypeDB::bind_method(_MD("get_max_contacts_reported"),&RigidBody::get_max_contacts_reported);
@@ -722,6 +794,7 @@ void RigidBody::_bind_methods() {
ADD_PROPERTY( PropertyInfo(Variant::REAL,"weight",PROPERTY_HINT_EXP_RANGE,"0.01,65535,0.01",PROPERTY_USAGE_EDITOR),_SCS("set_weight"),_SCS("get_weight"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"friction",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_friction"),_SCS("get_friction"));
ADD_PROPERTY( PropertyInfo(Variant::REAL,"bounce",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_bounce"),_SCS("get_bounce"));
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"gravity_scale",PROPERTY_HINT_RANGE,"-128,128,0.01"),_SCS("set_gravity_scale"),_SCS("get_gravity_scale"));
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"custom_integrator"),_SCS("set_use_custom_integrator"),_SCS("is_using_custom_integrator"));
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"continuous_cd"),_SCS("set_use_continuous_collision_detection"),_SCS("is_using_continuous_collision_detection"));
ADD_PROPERTY( PropertyInfo(Variant::INT,"contacts_reported"),_SCS("set_max_contacts_reported"),_SCS("get_max_contacts_reported"));
@@ -731,6 +804,8 @@ void RigidBody::_bind_methods() {
ADD_PROPERTY( PropertyInfo(Variant::INT,"axis_lock",PROPERTY_HINT_ENUM,"Disabled,Lock X,Lock Y,Lock Z"),_SCS("set_axis_lock"),_SCS("get_axis_lock"));
ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"velocity/linear"),_SCS("set_linear_velocity"),_SCS("get_linear_velocity"));
ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"velocity/angular"),_SCS("set_angular_velocity"),_SCS("get_angular_velocity"));
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"damp_override/linear",PROPERTY_HINT_RANGE,"-1,128,0.01"),_SCS("set_linear_damp"),_SCS("get_linear_damp"));
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"damp_override/angular",PROPERTY_HINT_RANGE,"-1,128,0.01"),_SCS("set_angular_damp"),_SCS("get_angular_damp"));
ADD_SIGNAL( MethodInfo("body_enter_shape",PropertyInfo(Variant::INT,"body_id"),PropertyInfo(Variant::OBJECT,"body"),PropertyInfo(Variant::INT,"body_shape"),PropertyInfo(Variant::INT,"local_shape")));
ADD_SIGNAL( MethodInfo("body_exit_shape",PropertyInfo(Variant::INT,"body_id"),PropertyInfo(Variant::OBJECT,"body"),PropertyInfo(Variant::INT,"body_shape"),PropertyInfo(Variant::INT,"local_shape")));
@@ -753,6 +828,10 @@ RigidBody::RigidBody() : PhysicsBody(PhysicsServer::BODY_MODE_RIGID) {
max_contacts_reported=0;
state=NULL;
+ gravity_scale=1;
+ linear_damp=-1;
+ angular_damp=-1;
+
//angular_velocity=0;
sleeping=false;
ccd=false;
@@ -1018,7 +1097,7 @@ Vector3 KinematicBody::move_to(const Vector3& p_position) {
return move(p_position-get_global_transform().origin);
}
-bool KinematicBody::can_move_to(const Vector3& p_position, bool p_discrete) {
+bool KinematicBody::can_teleport_to(const Vector3& p_position) {
ERR_FAIL_COND_V(!is_inside_tree(),false);
PhysicsDirectSpaceState *dss = PhysicsServer::get_singleton()->space_get_direct_state(get_world()->get_space());
@@ -1034,25 +1113,18 @@ bool KinematicBody::can_move_to(const Vector3& p_position, bool p_discrete) {
if (collide_character)
mask|=PhysicsDirectSpaceState::TYPE_MASK_CHARACTER_BODY;
- Vector3 motion = p_position-get_global_transform().origin;
Transform xform=get_global_transform();
-
- if (true || p_discrete) {
-
- xform.origin+=motion;
- motion=Vector3();
- }
+ xform.origin=p_position;
Set<RID> exclude;
exclude.insert(get_rid());
- //fill exclude list..
for(int i=0;i<get_shape_count();i++) {
if (is_shape_set_as_trigger(i))
continue;
- bool col = dss->intersect_shape(get_shape(i)->get_rid(), xform * get_shape_transform(i),0,NULL,0,exclude,get_layer_mask(),mask);
+ bool col = dss->intersect_shape(get_shape(i)->get_rid(), xform * get_shape_transform(i),0,NULL,1,exclude,get_layer_mask(),mask);
if (col)
return false;
}
@@ -1150,7 +1222,7 @@ void KinematicBody::_bind_methods() {
ObjectTypeDB::bind_method(_MD("move","rel_vec"),&KinematicBody::move);
ObjectTypeDB::bind_method(_MD("move_to","position"),&KinematicBody::move_to);
- ObjectTypeDB::bind_method(_MD("can_move_to","position"),&KinematicBody::can_move_to);
+ ObjectTypeDB::bind_method(_MD("can_teleport_to","position"),&KinematicBody::can_teleport_to);
ObjectTypeDB::bind_method(_MD("is_colliding"),&KinematicBody::is_colliding);
diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h
index 0ff3b360af..da79d63f00 100644
--- a/scene/3d/physics_body.h
+++ b/scene/3d/physics_body.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -129,6 +129,10 @@ private:
Vector3 linear_velocity;
Vector3 angular_velocity;
+ real_t gravity_scale;
+ real_t linear_damp;
+ real_t angular_damp;
+
bool sleeping;
bool ccd;
@@ -171,7 +175,7 @@ private:
struct ContactMonitor {
-
+ bool locked;
Map<ObjectID,BodyState> body_map;
};
@@ -217,6 +221,16 @@ public:
void set_angular_velocity(const Vector3&p_velocity);
Vector3 get_angular_velocity() const;
+ void set_gravity_scale(real_t p_gravity_scale);
+ real_t get_gravity_scale() const;
+
+ void set_linear_damp(real_t p_linear_damp);
+ real_t get_linear_damp() const;
+
+ void set_angular_damp(real_t p_angular_damp);
+ real_t get_angular_damp() const;
+
+
void set_use_custom_integrator(bool p_enable);
bool is_using_custom_integrator();
@@ -290,7 +304,7 @@ public:
Vector3 move(const Vector3& p_motion);
Vector3 move_to(const Vector3& p_position);
- bool can_move_to(const Vector3& p_position,bool p_discrete=false);
+ bool can_teleport_to(const Vector3& p_position);
bool is_colliding() const;
Vector3 get_collision_pos() const;
Vector3 get_collision_normal() const;
diff --git a/scene/3d/physics_joint.cpp b/scene/3d/physics_joint.cpp
index 0cc72b28e5..3f03b2aab3 100644
--- a/scene/3d/physics_joint.cpp
+++ b/scene/3d/physics_joint.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,8 +34,15 @@ void Joint::_update_joint(bool p_only_free) {
if (joint.is_valid()) {
- if (ba.is_valid() && bb.is_valid())
- PhysicsServer::get_singleton()->body_remove_collision_exception(ba,bb);
+ if (ba.is_valid() && bb.is_valid()) {
+
+ if (exclude_from_collision)
+ PhysicsServer::get_singleton()->body_add_collision_exception(ba,bb);
+ else
+ PhysicsServer::get_singleton()->body_remove_collision_exception(ba,bb);
+
+ }
+
PhysicsServer::get_singleton()->free(joint);
joint=RID();
ba=RID();
@@ -134,7 +141,7 @@ void Joint::_notification(int p_what) {
case NOTIFICATION_EXIT_TREE: {
if (joint.is_valid()) {
_update_joint(true);
- PhysicsServer::get_singleton()->free(joint);
+ //PhysicsServer::get_singleton()->free(joint);
joint=RID();
}
} break;
@@ -144,6 +151,19 @@ void Joint::_notification(int p_what) {
}
+void Joint::set_exclude_nodes_from_collision(bool p_enable) {
+
+ if (exclude_from_collision==p_enable)
+ return;
+ exclude_from_collision=p_enable;
+ _update_joint();
+}
+
+bool Joint::get_exclude_nodes_from_collision() const{
+
+ return exclude_from_collision;
+}
+
void Joint::_bind_methods() {
@@ -156,10 +176,16 @@ void Joint::_bind_methods() {
ObjectTypeDB::bind_method( _MD("set_solver_priority","priority"), &Joint::set_solver_priority );
ObjectTypeDB::bind_method( _MD("get_solver_priority"), &Joint::get_solver_priority );
+ ObjectTypeDB::bind_method( _MD("set_exclude_nodes_from_collision","enable"), &Joint::set_exclude_nodes_from_collision );
+ ObjectTypeDB::bind_method( _MD("get_exclude_nodes_from_collision"), &Joint::get_exclude_nodes_from_collision );
+
ADD_PROPERTY( PropertyInfo( Variant::NODE_PATH, "nodes/node_a"), _SCS("set_node_a"),_SCS("get_node_a") );
ADD_PROPERTY( PropertyInfo( Variant::NODE_PATH, "nodes/node_b"), _SCS("set_node_b"),_SCS("get_node_b") );
ADD_PROPERTY( PropertyInfo( Variant::INT, "solver/priority",PROPERTY_HINT_RANGE,"1,8,1"), _SCS("set_solver_priority"),_SCS("get_solver_priority") );
+ ADD_PROPERTY( PropertyInfo( Variant::BOOL, "collision/exclude_nodes"), _SCS("set_exclude_nodes_from_collision"),_SCS("get_exclude_nodes_from_collision") );
+
+
}
@@ -167,6 +193,7 @@ void Joint::_bind_methods() {
Joint::Joint() {
+ exclude_from_collision=true;
solver_priority=1;
}
diff --git a/scene/3d/physics_joint.h b/scene/3d/physics_joint.h
index a5f4ea4bdb..55c26f296e 100644
--- a/scene/3d/physics_joint.h
+++ b/scene/3d/physics_joint.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -45,6 +45,7 @@ class Joint : public Spatial {
NodePath b;
int solver_priority;
+ bool exclude_from_collision;
protected:
@@ -67,6 +68,9 @@ public:
void set_solver_priority(int p_priority);
int get_solver_priority() const;
+ void set_exclude_nodes_from_collision(bool p_enable);
+ bool get_exclude_nodes_from_collision() const;
+
RID get_joint() const { return joint; }
Joint();
diff --git a/scene/3d/portal.cpp b/scene/3d/portal.cpp
index 34499578aa..84f94402d5 100644
--- a/scene/3d/portal.cpp
+++ b/scene/3d/portal.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/portal.h b/scene/3d/portal.h
index 14c1275312..388eac4dd3 100644
--- a/scene/3d/portal.h
+++ b/scene/3d/portal.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/position_3d.cpp b/scene/3d/position_3d.cpp
index d692c0f249..27130cbe6a 100644
--- a/scene/3d/position_3d.cpp
+++ b/scene/3d/position_3d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/position_3d.h b/scene/3d/position_3d.h
index 265c0b48c7..6bac540fcb 100644
--- a/scene/3d/position_3d.h
+++ b/scene/3d/position_3d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/proximity_group.cpp b/scene/3d/proximity_group.cpp
index 334246b033..a2182302a0 100644
--- a/scene/3d/proximity_group.cpp
+++ b/scene/3d/proximity_group.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/proximity_group.h b/scene/3d/proximity_group.h
index 35e3f3dd98..6d5c703827 100644
--- a/scene/3d/proximity_group.h
+++ b/scene/3d/proximity_group.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/quad.cpp b/scene/3d/quad.cpp
index 43bde8dc61..1a7eeef180 100644
--- a/scene/3d/quad.cpp
+++ b/scene/3d/quad.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/quad.h b/scene/3d/quad.h
index 5ef4af8b81..be55b0d1c9 100644
--- a/scene/3d/quad.h
+++ b/scene/3d/quad.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/ray_cast.cpp b/scene/3d/ray_cast.cpp
index 5f2c8e0ba3..ab2c4fc8dc 100644
--- a/scene/3d/ray_cast.cpp
+++ b/scene/3d/ray_cast.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/ray_cast.h b/scene/3d/ray_cast.h
index 06e9e31396..520b4d5313 100644
--- a/scene/3d/ray_cast.h
+++ b/scene/3d/ray_cast.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/room_instance.cpp b/scene/3d/room_instance.cpp
index 2ae75b8b68..e358da136b 100644
--- a/scene/3d/room_instance.cpp
+++ b/scene/3d/room_instance.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/room_instance.h b/scene/3d/room_instance.h
index 09fccc5ebc..c7df4ceadd 100644
--- a/scene/3d/room_instance.h
+++ b/scene/3d/room_instance.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/scenario_fx.cpp b/scene/3d/scenario_fx.cpp
index 59c8b5e0df..2e22ab36d3 100644
--- a/scene/3d/scenario_fx.cpp
+++ b/scene/3d/scenario_fx.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/scenario_fx.h b/scene/3d/scenario_fx.h
index b877cccc19..a3c13e03a1 100644
--- a/scene/3d/scenario_fx.h
+++ b/scene/3d/scenario_fx.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp
index ee1b28a8ae..64133f67b5 100644
--- a/scene/3d/skeleton.cpp
+++ b/scene/3d/skeleton.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -41,8 +41,8 @@ bool Skeleton::_set(const StringName& p_path, const Variant& p_value) {
if (!path.begins_with("bones/"))
return false;
- int which=path.get_slice("/",1).to_int();
- String what=path.get_slice("/",2);
+ int which=path.get_slicec('/',1).to_int();
+ String what=path.get_slicec('/',2);
if (which==bones.size() && what=="name") {
@@ -88,8 +88,8 @@ bool Skeleton::_get(const StringName& p_name,Variant &r_ret) const {
if (!path.begins_with("bones/"))
return false;
- int which=path.get_slice("/",1).to_int();
- String what=path.get_slice("/",2);
+ int which=path.get_slicec('/',1).to_int();
+ String what=path.get_slicec('/',2);
ERR_FAIL_INDEX_V( which, bones.size(), false );
@@ -187,30 +187,59 @@ void Skeleton::_notification(int p_what) {
Bone &b=bonesptr[i];
- if (b.enabled) {
+ if (b.disable_rest) {
+ if (b.enabled) {
- Transform pose=b.pose;
- if (b.custom_pose_enable) {
+ Transform pose=b.pose;
+ if (b.custom_pose_enable) {
- pose = b.custom_pose * pose;
- }
+ pose = b.custom_pose * pose;
+ }
+
+ if (b.parent>=0) {
+
+ b.pose_global=bonesptr[b.parent].pose_global * pose;
+ } else {
- if (b.parent>=0) {
-
- b.pose_global=bonesptr[b.parent].pose_global * (b.rest * pose);
+ b.pose_global=pose;
+ }
} else {
-
- b.pose_global=b.rest * pose;
+
+ if (b.parent>=0) {
+
+ b.pose_global=bonesptr[b.parent].pose_global;
+ } else {
+
+ b.pose_global=Transform();
+ }
}
+
} else {
-
- if (b.parent>=0) {
-
- b.pose_global=bonesptr[b.parent].pose_global * b.rest;
+ if (b.enabled) {
+
+ Transform pose=b.pose;
+ if (b.custom_pose_enable) {
+
+ pose = b.custom_pose * pose;
+ }
+
+ if (b.parent>=0) {
+
+ b.pose_global=bonesptr[b.parent].pose_global * (b.rest * pose);
+ } else {
+
+ b.pose_global=b.rest * pose;
+ }
} else {
-
- b.pose_global=b.rest;
- }
+
+ if (b.parent>=0) {
+
+ b.pose_global=bonesptr[b.parent].pose_global * b.rest;
+ } else {
+
+ b.pose_global=b.rest;
+ }
+ }
}
vs->skeleton_bone_set_transform( skeleton, i, b.pose_global * b.rest_global_inverse );
@@ -221,7 +250,7 @@ void Skeleton::_notification(int p_what) {
ERR_CONTINUE(!obj);
Spatial *sp = obj->cast_to<Spatial>();
ERR_CONTINUE(!sp);
- sp->set_transform(b.pose_global * b.rest_global_inverse);
+ sp->set_transform(b.pose_global);
}
}
@@ -315,6 +344,37 @@ void Skeleton::set_bone_parent(int p_bone, int p_parent) {
_make_dirty();
}
+void Skeleton::unparent_bone_and_rest(int p_bone) {
+
+ ERR_FAIL_INDEX( p_bone, bones.size() );
+
+ int parent=bones[p_bone].parent;
+ while(parent>=0) {
+ bones[p_bone].rest = bones[parent].rest * bones[p_bone].rest;
+ parent=bones[parent].parent;
+ }
+
+ bones[p_bone].parent=-1;
+ bones[p_bone].rest_global_inverse=bones[p_bone].rest.affine_inverse(); //same thing
+
+ _make_dirty();
+
+}
+
+void Skeleton::set_bone_disable_rest(int p_bone, bool p_disable) {
+
+ ERR_FAIL_INDEX( p_bone, bones.size() );
+ bones[p_bone].disable_rest=p_disable;
+
+}
+
+bool Skeleton::is_bone_rest_disabled(int p_bone) const {
+
+ ERR_FAIL_INDEX_V( p_bone, bones.size(), false );
+ return bones[p_bone].disable_rest;
+}
+
+
int Skeleton::get_bone_parent(int p_bone) const {
ERR_FAIL_INDEX_V( p_bone, bones.size(), -1 );
@@ -522,9 +582,14 @@ void Skeleton::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_bone_count"),&Skeleton::get_bone_count);
+ ObjectTypeDB::bind_method(_MD("unparent_bone_and_rest","bone_idx"),&Skeleton::unparent_bone_and_rest);
+
ObjectTypeDB::bind_method(_MD("get_bone_rest","bone_idx"),&Skeleton::get_bone_rest);
ObjectTypeDB::bind_method(_MD("set_bone_rest","bone_idx","rest"),&Skeleton::set_bone_rest);
+ ObjectTypeDB::bind_method(_MD("set_bone_disable_rest","bone_idx","disable"),&Skeleton::set_bone_disable_rest);
+ ObjectTypeDB::bind_method(_MD("is_bone_rest_disabled","bone_idx"),&Skeleton::is_bone_rest_disabled);
+
ObjectTypeDB::bind_method(_MD("bind_child_node_to_bone","bone_idx","node:Node"),&Skeleton::bind_child_node_to_bone);
ObjectTypeDB::bind_method(_MD("unbind_child_node_from_bone","bone_idx","node:Node"),&Skeleton::unbind_child_node_from_bone);
ObjectTypeDB::bind_method(_MD("get_bound_child_nodes_to_bone","bone_idx"),&Skeleton::_get_bound_child_nodes_to_bone);
diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h
index b7f84f44c9..033f212a58 100644
--- a/scene/3d/skeleton.h
+++ b/scene/3d/skeleton.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -46,6 +46,7 @@ class Skeleton : public Spatial {
bool enabled;
int parent;
+ bool disable_rest;
Transform rest;
Transform rest_global_inverse;
@@ -57,7 +58,7 @@ class Skeleton : public Spatial {
List<uint32_t> nodes_bound;
- Bone() { parent=-1; enabled=true; custom_pose_enable=false; }
+ Bone() { parent=-1; enabled=true; custom_pose_enable=false; disable_rest=false; }
};
bool rest_global_inverse_dirty;
@@ -111,6 +112,11 @@ public:
void set_bone_parent(int p_bone, int p_parent);
int get_bone_parent(int p_bone) const;
+ void unparent_bone_and_rest(int p_idx);
+
+ void set_bone_disable_rest(int p_bone, bool p_disable);
+ bool is_bone_rest_disabled(int p_bone) const;
+
int get_bone_count() const;
void set_bone_rest(int p_bone, const Transform& p_rest);
diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp
index c672d0e94f..0c1e1e2d1c 100644
--- a/scene/3d/spatial.cpp
+++ b/scene/3d/spatial.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -231,6 +231,11 @@ void Spatial::set_transform(const Transform& p_transform) {
_change_notify("transform/rotation");
_change_notify("transform/scale");
_propagate_transform_changed(this);
+ if (data.notify_local_transform) {
+ notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
+ }
+
+
}
@@ -335,6 +340,9 @@ void Spatial::set_translation(const Vector3& p_translation) {
data.local_transform.origin=p_translation;
_propagate_transform_changed(this);
+ if (data.notify_local_transform) {
+ notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
+ }
}
@@ -348,6 +356,9 @@ void Spatial::set_rotation(const Vector3& p_euler){
data.rotation=p_euler;
data.dirty|=DIRTY_LOCAL;
_propagate_transform_changed(this);
+ if (data.notify_local_transform) {
+ notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
+ }
}
void Spatial::set_scale(const Vector3& p_scale){
@@ -360,6 +371,9 @@ void Spatial::set_scale(const Vector3& p_scale){
data.scale=p_scale;
data.dirty|=DIRTY_LOCAL;
_propagate_transform_changed(this);
+ if (data.notify_local_transform) {
+ notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED);
+ }
}
@@ -580,6 +594,15 @@ bool Spatial::is_hidden() const{
return !data.visible;
}
+void Spatial::set_hidden(bool p_hidden) {
+
+ if (data.visible != p_hidden) {
+ return;
+ }
+
+ _set_visible_(!p_hidden);
+}
+
void Spatial::_set_visible_(bool p_visible) {
if (p_visible)
@@ -685,6 +708,13 @@ void Spatial::look_at_from_pos(const Vector3& p_pos,const Vector3& p_target, con
}
+void Spatial::set_notify_local_transform(bool p_enable) {
+ data.notify_local_transform=p_enable;
+}
+
+bool Spatial::is_local_transform_notification_enabled() const {
+ return data.notify_local_transform;
+}
void Spatial::_bind_methods() {
@@ -721,10 +751,14 @@ void Spatial::_bind_methods() {
ObjectTypeDB::bind_method(_MD("hide"), &Spatial::hide);
ObjectTypeDB::bind_method(_MD("is_visible"), &Spatial::is_visible);
ObjectTypeDB::bind_method(_MD("is_hidden"), &Spatial::is_hidden);
+ ObjectTypeDB::bind_method(_MD("set_hidden","hidden"), &Spatial::set_hidden);
ObjectTypeDB::bind_method(_MD("_set_visible_"), &Spatial::_set_visible_);
ObjectTypeDB::bind_method(_MD("_is_visible_"), &Spatial::_is_visible_);
+ ObjectTypeDB::bind_method(_MD("set_notify_local_transform","enable"), &Spatial::set_notify_local_transform);
+ ObjectTypeDB::bind_method(_MD("is_local_transform_notification_enabled"), &Spatial::is_local_transform_notification_enabled);
+
void rotate(const Vector3& p_normal,float p_radians);
void rotate_x(float p_radians);
void rotate_y(float p_radians);
@@ -758,7 +792,7 @@ void Spatial::_bind_methods() {
ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"transform/rotation",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_EDITOR), _SCS("_set_rotation_deg"), _SCS("_get_rotation_deg") );
ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"transform/rotation_rad",PROPERTY_HINT_NONE,"",0), _SCS("set_rotation"), _SCS("get_rotation") );
ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"transform/scale",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_EDITOR), _SCS("set_scale"), _SCS("get_scale") );
- ADD_PROPERTY( PropertyInfo(Variant::BOOL,"visibility/visible"), _SCS("_set_visible_"), _SCS("_is_visible_") );
+ ADD_PROPERTYNO( PropertyInfo(Variant::BOOL,"visibility/visible"), _SCS("_set_visible_"), _SCS("_is_visible_") );
//ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/local"), _SCS("set_transform"), _SCS("get_transform") );
ADD_SIGNAL( MethodInfo("visibility_changed" ) );
@@ -783,6 +817,7 @@ Spatial::Spatial() : xform_change(this)
data.gizmo_disabled=false;
data.gizmo_dirty=false;
#endif
+ data.notify_local_transform=false;
data.parent=NULL;
data.C=NULL;
diff --git a/scene/3d/spatial.h b/scene/3d/spatial.h
index 8b40786fb8..23f1c6d103 100644
--- a/scene/3d/spatial.h
+++ b/scene/3d/spatial.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -91,6 +91,7 @@ class Spatial : public Node {
List<Spatial*>::Element *C;
bool ignore_notification;
+ bool notify_local_transform;
bool visible;
@@ -134,6 +135,7 @@ public:
NOTIFICATION_ENTER_WORLD=41,
NOTIFICATION_EXIT_WORLD=42,
NOTIFICATION_VISIBILITY_CHANGED=43,
+ NOTIFICATION_LOCAL_TRANSFORM_CHANGED=44,
};
Spatial *get_parent_spatial() const;
@@ -179,6 +181,9 @@ public:
void look_at(const Vector3& p_target, const Vector3& p_up_normal);
void look_at_from_pos(const Vector3& p_pos,const Vector3& p_target, const Vector3& p_up_normal);
+ void set_notify_local_transform(bool p_enable);
+ bool is_local_transform_notification_enabled() const;
+
void orthonormalize();
void set_identity();
@@ -186,6 +191,7 @@ public:
void hide();
bool is_visible() const;
bool is_hidden() const;
+ void set_hidden(bool p_hidden);
#ifdef TOOLS_ENABLED
void set_import_transform(const Transform& p_transform) ;
diff --git a/scene/3d/spatial_indexer.cpp b/scene/3d/spatial_indexer.cpp
index 2f7aee5c67..d5be36b2cb 100644
--- a/scene/3d/spatial_indexer.cpp
+++ b/scene/3d/spatial_indexer.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/spatial_indexer.h b/scene/3d/spatial_indexer.h
index bc19b54d8f..13ce8badea 100644
--- a/scene/3d/spatial_indexer.h
+++ b/scene/3d/spatial_indexer.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/spatial_player.cpp b/scene/3d/spatial_player.cpp
index 5948c01ff8..c7cf03e284 100644
--- a/scene/3d/spatial_player.cpp
+++ b/scene/3d/spatial_player.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/spatial_player.h b/scene/3d/spatial_player.h
index 2f54497847..5a8687b854 100644
--- a/scene/3d/spatial_player.h
+++ b/scene/3d/spatial_player.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/spatial_sample_player.cpp b/scene/3d/spatial_sample_player.cpp
index 28b8fdd01e..7114fd4b77 100644
--- a/scene/3d/spatial_sample_player.cpp
+++ b/scene/3d/spatial_sample_player.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/spatial_sample_player.h b/scene/3d/spatial_sample_player.h
index 1d7bb8e238..9b3220458e 100644
--- a/scene/3d/spatial_sample_player.h
+++ b/scene/3d/spatial_sample_player.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/spatial_stream_player.cpp b/scene/3d/spatial_stream_player.cpp
index 84e68bf418..dfef0faf4b 100644
--- a/scene/3d/spatial_stream_player.cpp
+++ b/scene/3d/spatial_stream_player.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,21 +30,79 @@
-void SpatialStreamPlayer::_notification(int p_what) {
+int SpatialStreamPlayer::InternalStream::get_channel_count() const {
- switch(p_what) {
+ return player->sp_get_channel_count();
+}
+void SpatialStreamPlayer::InternalStream::set_mix_rate(int p_rate){
- case NOTIFICATION_ENTER_WORLD: {
+ return player->sp_set_mix_rate(p_rate);
+}
+bool SpatialStreamPlayer::InternalStream::mix(int32_t *p_buffer,int p_frames){
+
+ return player->sp_mix(p_buffer,p_frames);
+}
+void SpatialStreamPlayer::InternalStream::update(){
+
+ player->sp_update();
+}
+
+
+int SpatialStreamPlayer::sp_get_channel_count() const {
+
+ return playback->get_channels();
+}
+
+void SpatialStreamPlayer::sp_set_mix_rate(int p_rate){
+
+ server_mix_rate=p_rate;
+}
+
+bool SpatialStreamPlayer::sp_mix(int32_t *p_buffer,int p_frames) {
+
+ if (resampler.is_ready() && !paused) {
+ return resampler.mix(p_buffer,p_frames);
+ }
+
+ return false;
+}
+
+void SpatialStreamPlayer::sp_update() {
+
+ _THREAD_SAFE_METHOD_
+ if (!paused && resampler.is_ready() && playback.is_valid()) {
+
+ if (!playback->is_playing()) {
+ //stream depleted data, but there's still audio in the ringbuffer
+ //check that all this audio has been flushed before stopping the stream
+ int to_mix = resampler.get_total() - resampler.get_todo();
+ if (to_mix==0) {
+ stop();
+ return;
+ }
+
+ return;
+ }
+
+ int todo =resampler.get_todo();
+ int wrote = playback->mix(resampler.get_write_buffer(),todo);
+ resampler.write(wrote);
+ }
+}
-// set_idle_process(false); //don't annoy
- } break;
- case NOTIFICATION_PROCESS: {
-// if (!stream.is_null())
-// stream->update();
+void SpatialStreamPlayer::_notification(int p_what) {
+
+ switch(p_what) {
+
+ case NOTIFICATION_ENTER_TREE: {
+
+ //set_idle_process(false); //don't annoy
+ if (stream.is_valid() && autoplay && !get_tree()->is_editor_hint())
+ play();
} break;
- case NOTIFICATION_EXIT_WORLD: {
+ case NOTIFICATION_EXIT_TREE: {
stop(); //wathever it may be doing, stop
} break;
@@ -58,12 +116,20 @@ void SpatialStreamPlayer::set_stream(const Ref<AudioStream> &p_stream) {
stop();
stream=p_stream;
- if (!stream.is_null()) {
- stream->set_loop(loops);
+ if (!stream.is_null()) {
+ playback=stream->instance_playback();
+ playback->set_loop(loops);
+ playback->set_loop_restart_time(loop_point);
+ AudioServer::get_singleton()->lock();
+ resampler.setup(playback->get_channels(),playback->get_mix_rate(),server_mix_rate,buffering_ms,playback->get_minimum_buffer_size());
+ AudioServer::get_singleton()->unlock();
+ } else {
+ AudioServer::get_singleton()->lock();
+ resampler.clear();
+ playback.unref();
+ AudioServer::get_singleton()->unlock();
}
-
-
}
Ref<AudioStream> SpatialStreamPlayer::get_stream() const {
@@ -72,18 +138,25 @@ Ref<AudioStream> SpatialStreamPlayer::get_stream() const {
}
-void SpatialStreamPlayer::play() {
+void SpatialStreamPlayer::play(float p_from_offset) {
- if (!is_inside_tree())
+ ERR_FAIL_COND(!is_inside_tree());
+ if (playback.is_null())
return;
- if (stream.is_null())
- return;
- if (stream->is_playing())
+ if (playback->is_playing())
stop();
- stream->play();
- SpatialSoundServer::get_singleton()->source_set_audio_stream(get_source_rid(),stream->get_audio_stream());
- //if (stream->get_update_mode()!=AudioStream::UPDATE_NONE)
- // set_idle_process(true);
+
+ _THREAD_SAFE_METHOD_
+ playback->play(p_from_offset);
+ //feed the ringbuffer as long as no update callback is going on
+ sp_update();
+
+ SpatialSoundServer::get_singleton()->source_set_audio_stream(get_source_rid(),&internal_stream);
+
+// AudioServer::get_singleton()->stream_set_active(stream_rid,true);
+// AudioServer::get_singleton()->stream_set_volume_scale(stream_rid,volume);
+// if (stream->get_update_mode()!=AudioStream::UPDATE_NONE)
+// set_idle_process(true);
}
@@ -91,28 +164,31 @@ void SpatialStreamPlayer::stop() {
if (!is_inside_tree())
return;
- if (stream.is_null())
+ if (playback.is_null())
return;
+ _THREAD_SAFE_METHOD_
+ //AudioServer::get_singleton()->stream_set_active(stream_rid,false);
SpatialSoundServer::get_singleton()->source_set_audio_stream(get_source_rid(),NULL);
- stream->stop();
+ playback->stop();
+ resampler.flush();
//set_idle_process(false);
}
bool SpatialStreamPlayer::is_playing() const {
- if (stream.is_null())
+ if (playback.is_null())
return false;
- return stream->is_playing();
+ return playback->is_playing();
}
void SpatialStreamPlayer::set_loop(bool p_enable) {
loops=p_enable;
- if (stream.is_null())
+ if (playback.is_null())
return;
- stream->set_loop(loops);
+ playback->set_loop(loops);
}
bool SpatialStreamPlayer::has_loop() const {
@@ -120,6 +196,46 @@ bool SpatialStreamPlayer::has_loop() const {
return loops;
}
+void SpatialStreamPlayer::set_volume(float p_vol) {
+
+ volume=p_vol;
+ if (stream_rid.is_valid())
+ AudioServer::get_singleton()->stream_set_volume_scale(stream_rid,volume);
+}
+
+float SpatialStreamPlayer::get_volume() const {
+
+ return volume;
+}
+
+void SpatialStreamPlayer::set_loop_restart_time(float p_secs) {
+
+ loop_point=p_secs;
+ if (playback.is_valid())
+ playback->set_loop_restart_time(p_secs);
+}
+
+float SpatialStreamPlayer::get_loop_restart_time() const {
+
+ return loop_point;
+}
+
+
+void SpatialStreamPlayer::set_volume_db(float p_db) {
+
+ if (p_db<-79)
+ set_volume(0);
+ else
+ set_volume(Math::db2linear(p_db));
+}
+
+float SpatialStreamPlayer::get_volume_db() const {
+
+ if (volume==0)
+ return -80;
+ else
+ return Math::linear2db(volume);
+}
String SpatialStreamPlayer::get_stream_name() const {
@@ -132,59 +248,156 @@ String SpatialStreamPlayer::get_stream_name() const {
int SpatialStreamPlayer::get_loop_count() const {
- if (stream.is_null())
+ if (playback.is_null())
return 0;
- return stream->get_loop_count();
+ return playback->get_loop_count();
}
float SpatialStreamPlayer::get_pos() const {
- if (stream.is_null())
+ if (playback.is_null())
return 0;
- return stream->get_pos();
+ return playback->get_pos();
+
+}
+
+float SpatialStreamPlayer::get_length() const {
+ if (playback.is_null())
+ return 0;
+ return playback->get_length();
}
void SpatialStreamPlayer::seek_pos(float p_time) {
- if (stream.is_null())
+ if (playback.is_null())
return;
- return stream->seek_pos(p_time);
+ return playback->seek_pos(p_time);
+
+}
+
+void SpatialStreamPlayer::set_autoplay(bool p_enable) {
+
+ autoplay=p_enable;
+}
+
+bool SpatialStreamPlayer::has_autoplay() const {
+
+ return autoplay;
+}
+
+void SpatialStreamPlayer::set_paused(bool p_paused) {
+
+ paused=p_paused;
+ //if (stream.is_valid())
+ // stream->set_paused(p_paused);
+}
+
+bool SpatialStreamPlayer::is_paused() const {
+ return paused;
}
+void SpatialStreamPlayer::_set_play(bool p_play) {
+
+ _play=p_play;
+ if (is_inside_tree()) {
+ if(_play)
+ play();
+ else
+ stop();
+ }
+
+}
+
+bool SpatialStreamPlayer::_get_play() const{
+
+ return _play;
+}
+
+void SpatialStreamPlayer::set_buffering_msec(int p_msec) {
+
+ buffering_ms=p_msec;
+}
+
+int SpatialStreamPlayer::get_buffering_msec() const{
+
+ return buffering_ms;
+}
+
+
+
void SpatialStreamPlayer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_stream","stream:Stream"),&SpatialStreamPlayer::set_stream);
ObjectTypeDB::bind_method(_MD("get_stream:Stream"),&SpatialStreamPlayer::get_stream);
- ObjectTypeDB::bind_method(_MD("play"),&SpatialStreamPlayer::play);
+ ObjectTypeDB::bind_method(_MD("play","offset"),&SpatialStreamPlayer::play,DEFVAL(0));
ObjectTypeDB::bind_method(_MD("stop"),&SpatialStreamPlayer::stop);
ObjectTypeDB::bind_method(_MD("is_playing"),&SpatialStreamPlayer::is_playing);
+ ObjectTypeDB::bind_method(_MD("set_paused","paused"),&SpatialStreamPlayer::set_paused);
+ ObjectTypeDB::bind_method(_MD("is_paused"),&SpatialStreamPlayer::is_paused);
+
ObjectTypeDB::bind_method(_MD("set_loop","enabled"),&SpatialStreamPlayer::set_loop);
ObjectTypeDB::bind_method(_MD("has_loop"),&SpatialStreamPlayer::has_loop);
+ ObjectTypeDB::bind_method(_MD("set_volume","volume"),&SpatialStreamPlayer::set_volume);
+ ObjectTypeDB::bind_method(_MD("get_volume"),&SpatialStreamPlayer::get_volume);
+
+ ObjectTypeDB::bind_method(_MD("set_volume_db","db"),&SpatialStreamPlayer::set_volume_db);
+ ObjectTypeDB::bind_method(_MD("get_volume_db"),&SpatialStreamPlayer::get_volume_db);
+
+ ObjectTypeDB::bind_method(_MD("set_buffering_msec","msec"),&SpatialStreamPlayer::set_buffering_msec);
+ ObjectTypeDB::bind_method(_MD("get_buffering_msec"),&SpatialStreamPlayer::get_buffering_msec);
+
+ ObjectTypeDB::bind_method(_MD("set_loop_restart_time","secs"),&SpatialStreamPlayer::set_loop_restart_time);
+ ObjectTypeDB::bind_method(_MD("get_loop_restart_time"),&SpatialStreamPlayer::get_loop_restart_time);
+
ObjectTypeDB::bind_method(_MD("get_stream_name"),&SpatialStreamPlayer::get_stream_name);
ObjectTypeDB::bind_method(_MD("get_loop_count"),&SpatialStreamPlayer::get_loop_count);
ObjectTypeDB::bind_method(_MD("get_pos"),&SpatialStreamPlayer::get_pos);
ObjectTypeDB::bind_method(_MD("seek_pos","time"),&SpatialStreamPlayer::seek_pos);
- ADD_PROPERTY( PropertyInfo(Variant::OBJECT, "stream/stream", PROPERTY_HINT_RESOURCE_TYPE,"AudioStream"), _SCS("set_stream"),_SCS("get_stream") );
- ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/loop"), _SCS("set_loop"),_SCS("has_loop") );
+ ObjectTypeDB::bind_method(_MD("set_autoplay","enabled"),&SpatialStreamPlayer::set_autoplay);
+ ObjectTypeDB::bind_method(_MD("has_autoplay"),&SpatialStreamPlayer::has_autoplay);
+ ObjectTypeDB::bind_method(_MD("get_length"),&SpatialStreamPlayer::get_length);
+
+ ObjectTypeDB::bind_method(_MD("_set_play","play"),&SpatialStreamPlayer::_set_play);
+ ObjectTypeDB::bind_method(_MD("_get_play"),&SpatialStreamPlayer::_get_play);
+
+ ADD_PROPERTY( PropertyInfo(Variant::OBJECT, "stream/stream", PROPERTY_HINT_RESOURCE_TYPE,"AudioStream"), _SCS("set_stream"), _SCS("get_stream") );
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/play"), _SCS("_set_play"), _SCS("_get_play") );
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/loop"), _SCS("set_loop"), _SCS("has_loop") );
+ ADD_PROPERTY( PropertyInfo(Variant::REAL, "stream/volume_db", PROPERTY_HINT_RANGE,"-80,24,0.01"), _SCS("set_volume_db"), _SCS("get_volume_db") );
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/autoplay"), _SCS("set_autoplay"), _SCS("has_autoplay") );
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/paused"), _SCS("set_paused"), _SCS("is_paused") );
+ ADD_PROPERTY( PropertyInfo(Variant::INT, "stream/loop_restart_time"), _SCS("set_loop_restart_time"), _SCS("get_loop_restart_time") );
+ ADD_PROPERTY( PropertyInfo(Variant::INT, "stream/buffering_ms"), _SCS("set_buffering_msec"), _SCS("get_buffering_msec") );
}
SpatialStreamPlayer::SpatialStreamPlayer() {
+ volume=1;
loops=false;
+ paused=false;
+ autoplay=false;
+ _play=false;
+ server_mix_rate=1;
+ internal_stream.player=this;
+ stream_rid=AudioServer::get_singleton()->audio_stream_create(&internal_stream);
+ buffering_ms=500;
+ loop_point=0;
+
}
SpatialStreamPlayer::~SpatialStreamPlayer() {
-
-}
+ AudioServer::get_singleton()->free(stream_rid);
+ resampler.clear();
+}
diff --git a/scene/3d/spatial_stream_player.h b/scene/3d/spatial_stream_player.h
index 7e639a7232..0732b3fc10 100644
--- a/scene/3d/spatial_stream_player.h
+++ b/scene/3d/spatial_stream_player.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,16 +31,48 @@
#include "scene/resources/audio_stream.h"
#include "scene/3d/spatial_player.h"
-
+#include "servers/audio/audio_rb_resampler.h"
class SpatialStreamPlayer : public SpatialPlayer {
OBJ_TYPE(SpatialStreamPlayer,SpatialPlayer);
+ _THREAD_SAFE_CLASS_
+
+ struct InternalStream : public AudioServer::AudioStream {
+ SpatialStreamPlayer *player;
+ virtual int get_channel_count() const;
+ virtual void set_mix_rate(int p_rate); //notify the stream of the mix rate
+ virtual bool mix(int32_t *p_buffer,int p_frames);
+ virtual void update();
+ };
+
+
+ InternalStream internal_stream;
+ Ref<AudioStreamPlayback> playback;
Ref<AudioStream> stream;
+
+ int sp_get_channel_count() const;
+ void sp_set_mix_rate(int p_rate); //notify the stream of the mix rate
+ bool sp_mix(int32_t *p_buffer,int p_frames);
+ void sp_update();
+
+ int server_mix_rate;
+
+ RID stream_rid;
+ bool paused;
+ bool autoplay;
bool loops;
-protected:
+ float volume;
+ float loop_point;
+ int buffering_ms;
+ AudioRBResampler resampler;
+
+ bool _play;
+ void _set_play(bool p_play);
+ bool _get_play() const;
+protected:
void _notification(int p_what);
static void _bind_methods();
@@ -49,21 +81,37 @@ public:
void set_stream(const Ref<AudioStream> &p_stream);
Ref<AudioStream> get_stream() const;
- void play();
+ void play(float p_from_offset=0);
void stop();
bool is_playing() const;
+ void set_paused(bool p_paused);
+ bool is_paused() const;
+
void set_loop(bool p_enable);
bool has_loop() const;
+ void set_volume(float p_vol);
+ float get_volume() const;
+
+ void set_loop_restart_time(float p_secs);
+ float get_loop_restart_time() const;
+
+ void set_volume_db(float p_db);
+ float get_volume_db() const;
String get_stream_name() const;
- int get_loop_count() const;
+ int get_loop_count() const;
float get_pos() const;
void seek_pos(float p_time);
+ float get_length() const;
+ void set_autoplay(bool p_vol);
+ bool has_autoplay() const;
+ void set_buffering_msec(int p_msec);
+ int get_buffering_msec() const;
SpatialStreamPlayer();
~SpatialStreamPlayer();
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index e9da95f3fb..c7d1249a07 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -578,8 +578,8 @@ void Sprite3D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_hframes"),&Sprite3D::get_hframes);
ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_texture"),_SCS("get_texture"));
- ADD_PROPERTY( PropertyInfo( Variant::INT, "vframes"), _SCS("set_vframes"),_SCS("get_vframes"));
- ADD_PROPERTY( PropertyInfo( Variant::INT, "hframes"), _SCS("set_hframes"),_SCS("get_hframes"));
+ ADD_PROPERTY( PropertyInfo( Variant::INT, "vframes",PROPERTY_HINT_RANGE,"1,16384,1"), _SCS("set_vframes"),_SCS("get_vframes"));
+ ADD_PROPERTY( PropertyInfo( Variant::INT, "hframes",PROPERTY_HINT_RANGE,"1,16384,1"), _SCS("set_hframes"),_SCS("get_hframes"));
ADD_PROPERTY( PropertyInfo( Variant::INT, "frame",PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"),_SCS("get_frame"));
ADD_PROPERTY( PropertyInfo( Variant::BOOL, "region"), _SCS("set_region"),_SCS("is_region"));
ADD_PROPERTY( PropertyInfo( Variant::RECT2, "region_rect"), _SCS("set_region_rect"),_SCS("get_region_rect"));
diff --git a/scene/3d/test_cube.cpp b/scene/3d/test_cube.cpp
index 0acd1b3351..6440d95d55 100644
--- a/scene/3d/test_cube.cpp
+++ b/scene/3d/test_cube.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/test_cube.h b/scene/3d/test_cube.h
index 2dbd7c9856..21f2b3c794 100644
--- a/scene/3d/test_cube.h
+++ b/scene/3d/test_cube.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/visibility_notifier.cpp b/scene/3d/visibility_notifier.cpp
index ad62f6d809..60097ad482 100644
--- a/scene/3d/visibility_notifier.cpp
+++ b/scene/3d/visibility_notifier.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/visibility_notifier.h b/scene/3d/visibility_notifier.h
index 85c26bec94..a4709b7cf4 100644
--- a/scene/3d/visibility_notifier.h
+++ b/scene/3d/visibility_notifier.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp
index 41e8b6bf54..723b0a9af5 100644
--- a/scene/3d/visual_instance.cpp
+++ b/scene/3d/visual_instance.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/visual_instance.h b/scene/3d/visual_instance.h
index 3c69f09978..e49f4fb82f 100644
--- a/scene/3d/visual_instance.h
+++ b/scene/3d/visual_instance.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/SCsub b/scene/SCsub
index 8c4f0499c4..6d1dd0044f 100644
--- a/scene/SCsub
+++ b/scene/SCsub
@@ -18,5 +18,3 @@ SConscript('io/SCsub');
lib = env.Library("scene",env.scene_sources)
env.Prepend(LIBS=[lib])
-
-
diff --git a/scene/animation/SCsub b/scene/animation/SCsub
index 055d2f2474..bbe59b3054 100644
--- a/scene/animation/SCsub
+++ b/scene/animation/SCsub
@@ -3,5 +3,3 @@ Import('env')
env.add_source_files(env.scene_sources,"*.cpp")
Export('env')
-
-
diff --git a/scene/animation/animation_cache.cpp b/scene/animation/animation_cache.cpp
index b1d6da7294..b1123897b2 100644
--- a/scene/animation/animation_cache.cpp
+++ b/scene/animation/animation_cache.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/animation/animation_cache.h b/scene/animation/animation_cache.h
index e94530d924..c9b4ff298c 100644
--- a/scene/animation/animation_cache.h
+++ b/scene/animation/animation_cache.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 74ae2c0d55..f6d058c2fd 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,10 +35,10 @@ bool AnimationPlayer::_set(const StringName& p_name, const Variant& p_value) {
String name=p_name;
- if (name=="playback/speed" || name=="speed") { //bw compatibility
+ if (p_name==SceneStringNames::get_singleton()->playback_speed || p_name==SceneStringNames::get_singleton()->speed) { //bw compatibility
set_speed(p_value);
- } else if (name=="playback/active") {
+ } else if (p_name==SceneStringNames::get_singleton()->playback_active) {
set_active(p_value);
} else if (name.begins_with("playback/play")) {
@@ -52,16 +52,16 @@ bool AnimationPlayer::_set(const StringName& p_name, const Variant& p_value) {
} else if (name.begins_with("anims/")) {
- String which=name.get_slice("/",1);
+ String which=name.get_slicec('/',1);
add_animation(which,p_value);
} else if (name.begins_with("next/")) {
- String which=name.get_slice("/",1);
+ String which=name.get_slicec('/',1);
animation_set_next(which,p_value);
- } else if (name=="blend_times") {
+ } else if (p_name==SceneStringNames::get_singleton()->blend_times) {
Array array=p_value;
int len = array.size();
@@ -77,7 +77,7 @@ bool AnimationPlayer::_set(const StringName& p_name, const Variant& p_value) {
set_blend_time(from,to,time);
}
- } else if (name=="autoplay") {
+ } else if (p_name==SceneStringNames::get_singleton()->autoplay) {
autoplay=p_value;
} else
@@ -106,12 +106,12 @@ bool AnimationPlayer::_get(const StringName& p_name,Variant &r_ret) const {
} else if (name.begins_with("anims/")) {
- String which=name.get_slice("/",1);
+ String which=name.get_slicec('/',1);
r_ret= get_animation(which).get_ref_ptr();
} else if (name.begins_with("next/")) {
- String which=name.get_slice("/",1);
+ String which=name.get_slicec('/',1);
r_ret= animation_get_next(which);
@@ -268,6 +268,7 @@ void AnimationPlayer::_generate_node_caches(AnimationData* p_anim) {
TrackNodeCacheKey key;
key.id=id;
key.bone_idx=bone_idx;
+
if (node_cache_map.has(key)) {
@@ -278,6 +279,7 @@ void AnimationPlayer::_generate_node_caches(AnimationData* p_anim) {
node_cache_map[key]=TrackNodeCache();
p_anim->node_cache[i]=&node_cache_map[key];
+ p_anim->node_cache[i]->path=a->track_get_path(i);
p_anim->node_cache[i]->node=child;
p_anim->node_cache[i]->resource=resource;
p_anim->node_cache[i]->node_2d=child->cast_to<Node2D>();
@@ -320,6 +322,7 @@ void AnimationPlayer::_generate_node_caches(AnimationData* p_anim) {
pa.prop=property;
pa.object=resource.is_valid()?(Object*)resource.ptr():(Object*)child;
pa.special=SP_NONE;
+ pa.owner=p_anim->node_cache[i];
if (false && p_anim->node_cache[i]->node_2d) {
if (pa.prop==SceneStringNames::get_singleton()->transform_pos)
@@ -410,7 +413,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData* p_anim,float p
TrackNodeCache::PropertyAnim *pa = &E->get();
- if (a->value_track_is_continuous(i) || p_delta==0) {
+ if (a->value_track_is_continuous(i) || p_delta==0) { //delta == 0 means seek
Variant value=a->value_track_interpolate(i,p_time);
@@ -436,10 +439,42 @@ void AnimationPlayer::_animation_process_animation(AnimationData* p_anim,float p
Variant value=a->track_get_key_value(i,F->get());
switch(pa->special) {
- case SP_NONE: pa->object->set(pa->prop,value); break; //you are not speshul
- case SP_NODE2D_POS: static_cast<Node2D*>(pa->object)->set_pos(value); break;
- case SP_NODE2D_ROT: static_cast<Node2D*>(pa->object)->set_rot(Math::deg2rad(value)); break;
- case SP_NODE2D_SCALE: static_cast<Node2D*>(pa->object)->set_scale(value); break;
+ case SP_NONE: {
+ bool valid;
+ pa->object->set(pa->prop,value,&valid); //you are not speshul
+#ifdef DEBUG_ENABLED
+ if (!valid) {
+ ERR_PRINTS("Failed setting track value '"+String(pa->owner->path)+"'. Check if property exists or the type of key is valid");
+ }
+#endif
+
+ } break;
+ case SP_NODE2D_POS: {
+#ifdef DEBUG_ENABLED
+ if (value.get_type()!=Variant::VECTOR2) {
+ ERR_PRINTS("Position key at time "+rtos(p_time)+" in Animation Track '"+String(pa->owner->path)+"' not of type Vector2()");
+ }
+#endif
+ static_cast<Node2D*>(pa->object)->set_pos(value);
+ } break;
+ case SP_NODE2D_ROT: {
+#ifdef DEBUG_ENABLED
+ if (value.is_num()) {
+ ERR_PRINTS("Rotation key at time "+rtos(p_time)+" in Animation Track '"+String(pa->owner->path)+"' not numerical");
+ }
+#endif
+
+ static_cast<Node2D*>(pa->object)->set_rot(Math::deg2rad(value));
+ } break;
+ case SP_NODE2D_SCALE: {
+#ifdef DEBUG_ENABLED
+ if (value.get_type()!=Variant::VECTOR2) {
+ ERR_PRINTS("Scale key at time "+rtos(p_time)+" in Animation Track '"+String(pa->owner->path)+"' not of type Vector2()");
+ }
+#endif
+
+ static_cast<Node2D*>(pa->object)->set_scale(value);
+ } break;
}
}
@@ -607,13 +642,53 @@ void AnimationPlayer::_animation_update_transforms() {
ERR_CONTINUE( pa->accum_pass!=accum_pass );
#if 1
- switch(pa->special) {
+/* switch(pa->special) {
case SP_NONE: pa->object->set(pa->prop,pa->value_accum); break; //you are not speshul
case SP_NODE2D_POS: static_cast<Node2D*>(pa->object)->set_pos(pa->value_accum); break;
case SP_NODE2D_ROT: static_cast<Node2D*>(pa->object)->set_rot(Math::deg2rad(pa->value_accum)); break;
case SP_NODE2D_SCALE: static_cast<Node2D*>(pa->object)->set_scale(pa->value_accum); break;
+ }*/
+
+ switch(pa->special) {
+
+ case SP_NONE: {
+ bool valid;
+ pa->object->set(pa->prop,pa->value_accum,&valid); //you are not speshul
+#ifdef DEBUG_ENABLED
+ if (!valid) {
+ ERR_PRINTS("Failed setting key at time "+rtos(playback.current.pos)+" in Animation '"+get_current_animation()+"', Track '"+String(pa->owner->path)+"'. Check if property exists or the type of key is right for the property");
+ }
+#endif
+
+ } break;
+ case SP_NODE2D_POS: {
+#ifdef DEBUG_ENABLED
+ if (pa->value_accum.get_type()!=Variant::VECTOR2) {
+ ERR_PRINTS("Position key at time "+rtos(playback.current.pos)+" in Animation '"+get_current_animation()+"', Track '"+String(pa->owner->path)+"' not of type Vector2()");
+ }
+#endif
+ static_cast<Node2D*>(pa->object)->set_pos(pa->value_accum);
+ } break;
+ case SP_NODE2D_ROT: {
+#ifdef DEBUG_ENABLED
+ if (pa->value_accum.is_num()) {
+ ERR_PRINTS("Rotation key at time "+rtos(playback.current.pos)+" in Animation '"+get_current_animation()+"', Track '"+String(pa->owner->path)+"' not numerical");
+ }
+#endif
+
+ static_cast<Node2D*>(pa->object)->set_rot(Math::deg2rad(pa->value_accum));
+ } break;
+ case SP_NODE2D_SCALE: {
+#ifdef DEBUG_ENABLED
+ if (pa->value_accum.get_type()!=Variant::VECTOR2) {
+ ERR_PRINTS("Scale key at time "+rtos(playback.current.pos)+" in Animation '"+get_current_animation()+"', Track '"+String(pa->owner->path)+"' not of type Vector2()");
+ }
+#endif
+
+ static_cast<Node2D*>(pa->object)->set_scale(pa->value_accum);
+ } break;
}
#else
@@ -661,8 +736,11 @@ void AnimationPlayer::_animation_process(float p_delta) {
Error AnimationPlayer::add_animation(const StringName& p_name, const Ref<Animation>& p_animation) {
+#ifdef DEBUG_ENABLED
ERR_EXPLAIN("Invalid animation name: "+String(p_name));
ERR_FAIL_COND_V( String(p_name).find("/")!=-1 || String(p_name).find(":")!=-1 || String(p_name).find(",")!=-1 || String(p_name).find("[")!=-1, ERR_INVALID_PARAMETER );
+#endif
+
ERR_FAIL_COND_V( p_animation.is_null() , ERR_INVALID_PARAMETER );
//print_line("Add anim: "+String(p_name)+" name: "+p_animation->get_name());
@@ -854,6 +932,11 @@ void AnimationPlayer::clear_queue() {
queued.clear();
};
+void AnimationPlayer::play_backwards(const StringName& p_name,float p_custom_blend) {
+
+ play(p_name,p_custom_blend,-1,true);
+}
+
void AnimationPlayer::play(const StringName& p_name, float p_custom_blend, float p_custom_scale,bool p_from_end) {
//printf("animation is %ls\n", String(p_name).c_str());
@@ -1213,6 +1296,7 @@ void AnimationPlayer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_default_blend_time"),&AnimationPlayer::get_default_blend_time);
ObjectTypeDB::bind_method(_MD("play","name","custom_blend","custom_speed","from_end"),&AnimationPlayer::play,DEFVAL(""),DEFVAL(-1),DEFVAL(1.0),DEFVAL(false));
+ ObjectTypeDB::bind_method(_MD("play_backwards","name","custom_blend"),&AnimationPlayer::play_backwards,DEFVAL(""),DEFVAL(-1));
ObjectTypeDB::bind_method(_MD("stop","reset"),&AnimationPlayer::stop,DEFVAL(true));
ObjectTypeDB::bind_method(_MD("stop_all"),&AnimationPlayer::stop_all);
ObjectTypeDB::bind_method(_MD("is_playing"),&AnimationPlayer::is_playing);
@@ -1271,7 +1355,7 @@ AnimationPlayer::AnimationPlayer() {
animation_process_mode=ANIMATION_PROCESS_IDLE;
processing=false;
default_blend_time=0;
- root=NodePath("..");
+ root=SceneStringNames::get_singleton()->path_pp;
playing = false;
active=true;
}
diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h
index 3fddc283ae..853526c80a 100644
--- a/scene/animation/animation_player.h
+++ b/scene/animation/animation_player.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -68,6 +68,7 @@ private:
struct TrackNodeCache {
+ NodePath path;
uint32_t id;
RES resource;
Node *node;
@@ -84,6 +85,7 @@ private:
struct PropertyAnim {
+ TrackNodeCache *owner;
SpecialProperty special; //small optimization
StringName prop;
Object *object;
@@ -258,6 +260,7 @@ public:
float get_default_blend_time() const;
void play(const StringName& p_name=StringName(),float p_custom_blend=-1,float p_custom_scale=1.0,bool p_from_end=false);
+ void play_backwards(const StringName& p_name=StringName(),float p_custom_blend=-1);
void queue(const StringName& p_name);
void clear_queue();
void stop(bool p_reset=true);
diff --git a/scene/animation/animation_tree_player.cpp b/scene/animation/animation_tree_player.cpp
index 14f2110915..77d9f77bb5 100644
--- a/scene/animation/animation_tree_player.cpp
+++ b/scene/animation/animation_tree_player.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,6 +29,42 @@
#include "animation_tree_player.h"
#include "animation_player.h"
+#include "scene/scene_string_names.h"
+
+
+void AnimationTreePlayer::set_animation_process_mode(AnimationProcessMode p_mode) {
+
+ if (animation_process_mode == p_mode)
+ return;
+
+ bool pr = processing;
+ if (pr)
+ _set_process(false);
+ animation_process_mode = p_mode;
+ if (pr)
+ _set_process(true);
+
+}
+
+AnimationTreePlayer::AnimationProcessMode AnimationTreePlayer::get_animation_process_mode() const{
+
+ return animation_process_mode;
+}
+
+void AnimationTreePlayer::_set_process(bool p_process, bool p_force)
+{
+ if (processing == p_process && !p_force)
+ return;
+
+ switch (animation_process_mode) {
+
+ case ANIMATION_PROCESS_FIXED: set_fixed_process(p_process && active); break;
+ case ANIMATION_PROCESS_IDLE: set_process(p_process && active); break;
+ }
+
+ processing = p_process;
+}
+
bool AnimationTreePlayer::_set(const StringName& p_name, const Variant& p_value) {
@@ -42,6 +78,11 @@ bool AnimationTreePlayer::_set(const StringName& p_name, const Variant& p_value)
return true;
}
+ if(String(p_name) == SceneStringNames::get_singleton()->playback_active) {
+ set_active(p_value);
+ return true;
+ }
+
if (String(p_name)!="data")
return false;
@@ -190,6 +231,11 @@ bool AnimationTreePlayer::_get(const StringName& p_name,Variant &r_ret) const {
return true;
}
+ if (String(p_name) == "playback/active") {
+ r_ret=is_active();
+ return true;
+ }
+
if (String(p_name)!="data")
return false;
@@ -342,11 +388,24 @@ void AnimationTreePlayer::_get_property_list( List<PropertyInfo> *p_list) const
p_list->push_back( PropertyInfo(Variant::DICTIONARY,"data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_STORAGE|PROPERTY_USAGE_NETWORK) );
}
+void AnimationTreePlayer::advance(float p_time) {
+
+ _process_animation(p_time);
+}
void AnimationTreePlayer::_notification(int p_what) {
switch(p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+
+ if (!processing) {
+ //make sure that a previous process state was not saved
+ //only process if "processing" is set
+ set_fixed_process(false);
+ set_process(false);
+ }
+ } break;
case NOTIFICATION_READY: {
dirty_caches=true;
if (master!=NodePath()) {
@@ -354,14 +413,26 @@ void AnimationTreePlayer::_notification(int p_what) {
}
} break;
case NOTIFICATION_PROCESS: {
- _process_animation();
+ if (animation_process_mode==ANIMATION_PROCESS_FIXED)
+ break;
+
+ if (processing)
+ _process_animation( get_process_delta_time() );
+ } break;
+ case NOTIFICATION_FIXED_PROCESS: {
+
+ if (animation_process_mode==ANIMATION_PROCESS_IDLE)
+ break;
+
+ if (processing)
+ _process_animation(get_fixed_process_delta_time());
} break;
}
}
-float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode **r_prev_anim,float p_weight, float p_time, bool p_seek,const HashMap<NodePath,bool> *p_filter, float p_reverse_weight) {
+float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode **r_prev_anim,float p_weight, float p_time, bool switched, bool p_seek,const HashMap<NodePath,bool> *p_filter, float p_reverse_weight) {
ERR_FAIL_COND_V(!node_map.has(p_node), 0);
NodeBase *nb=node_map[p_node];
@@ -374,7 +445,7 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode
case NODE_OUTPUT: {
NodeOut *on = static_cast<NodeOut*>(nb);
- return _process_node(on->inputs[0].node,r_prev_anim,p_weight,p_time,p_seek);
+ return _process_node(on->inputs[0].node,r_prev_anim,p_weight,p_time,switched,p_seek);
} break;
case NODE_ANIMATION: {
@@ -408,6 +479,9 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode
an->time=anim_size;
}
+ if (switched && an->time >= anim_size) {
+ an->time = 0.0;
+ }
an->skip=true;
for (List<AnimationNode::TrackRef>::Element *E=an->tref.front();E;E=E->next()) {
@@ -449,7 +523,7 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode
if (!osn->active) {
//make it as if this node doesn't exist, pass input 0 by.
- return _process_node(osn->inputs[0].node,r_prev_anim,p_weight,p_time,p_seek,p_filter,p_reverse_weight);
+ return _process_node(osn->inputs[0].node,r_prev_anim,p_weight,p_time,switched,p_seek,p_filter,p_reverse_weight);
}
if (p_seek)
@@ -480,13 +554,13 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode
if (!osn->filter.empty()) {
- main_rem = _process_node(osn->inputs[0].node,r_prev_anim,(osn->mix?p_weight:p_weight*(1.0-blend)),p_time,p_seek,&osn->filter,p_weight);
- os_rem = _process_node(osn->inputs[1].node,r_prev_anim,p_weight*blend,p_time,p_seek,&osn->filter,-1);
+ main_rem = _process_node(osn->inputs[0].node,r_prev_anim,(osn->mix?p_weight:p_weight*(1.0-blend)),p_time,switched,p_seek,&osn->filter,p_weight);
+ os_rem = _process_node(osn->inputs[1].node,r_prev_anim,p_weight*blend,p_time,osn->start,p_seek,&osn->filter,-1);
} else {
- main_rem = _process_node(osn->inputs[0].node,r_prev_anim,(osn->mix?p_weight:p_weight*(1.0-blend)),p_time,p_seek);
- os_rem = _process_node(osn->inputs[1].node,r_prev_anim,p_weight*blend,p_time,p_seek);
+ main_rem = _process_node(osn->inputs[0].node,r_prev_anim,(osn->mix?p_weight:p_weight*(1.0-blend)),p_time,switched,p_seek);
+ os_rem = _process_node(osn->inputs[1].node,r_prev_anim,p_weight*blend,p_time,osn->start,p_seek);
}
if (osn->start) {
@@ -507,8 +581,8 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode
MixNode *mn = static_cast<MixNode*>(nb);
- float rem = _process_node(mn->inputs[0].node,r_prev_anim,p_weight,p_time,p_seek,p_filter,p_reverse_weight);
- _process_node(mn->inputs[1].node,r_prev_anim,p_weight*mn->amount,p_time,p_seek,p_filter,p_reverse_weight);
+ float rem = _process_node(mn->inputs[0].node,r_prev_anim,p_weight,p_time,switched,p_seek,p_filter,p_reverse_weight);
+ _process_node(mn->inputs[1].node,r_prev_anim,p_weight*mn->amount,p_time,switched,p_seek,p_filter,p_reverse_weight);
return rem;
} break;
@@ -519,12 +593,12 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode
float rem;
if (!bn->filter.empty()) {
- rem = _process_node(bn->inputs[0].node,r_prev_anim,p_weight*(1.0-bn->value),p_time,p_seek,&bn->filter,p_weight);
- _process_node(bn->inputs[1].node,r_prev_anim,p_weight*bn->value,p_time,p_seek,&bn->filter,-1);
+ rem = _process_node(bn->inputs[0].node,r_prev_anim,p_weight*(1.0-bn->value),p_time,switched,p_seek,&bn->filter,p_weight);
+ _process_node(bn->inputs[1].node,r_prev_anim,p_weight*bn->value,p_time,switched,p_seek,&bn->filter,-1);
} else {
- rem = _process_node(bn->inputs[0].node,r_prev_anim,p_weight*(1.0-bn->value),p_time,p_seek,p_filter,p_reverse_weight*(1.0-bn->value));
- _process_node(bn->inputs[1].node,r_prev_anim,p_weight*bn->value,p_time,p_seek,p_filter,p_reverse_weight*bn->value);
+ rem = _process_node(bn->inputs[0].node,r_prev_anim,p_weight*(1.0-bn->value),p_time,switched,p_seek,p_filter,p_reverse_weight*(1.0-bn->value));
+ _process_node(bn->inputs[1].node,r_prev_anim,p_weight*bn->value,p_time,switched,p_seek,p_filter,p_reverse_weight*bn->value);
}
return rem;
@@ -535,16 +609,16 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode
float rem;
if (bn->value==0) {
- rem = _process_node(bn->inputs[1].node,r_prev_anim,p_weight,p_time,p_seek,p_filter,p_reverse_weight);
+ rem = _process_node(bn->inputs[1].node,r_prev_anim,p_weight,p_time,switched,p_seek,p_filter,p_reverse_weight);
} else if (bn->value>0) {
- rem = _process_node(bn->inputs[1].node,r_prev_anim,p_weight*(1.0-bn->value),p_time,p_seek,p_filter,p_reverse_weight*(1.0-bn->value));
- _process_node(bn->inputs[2].node,r_prev_anim,p_weight*bn->value,p_time,p_seek,p_filter,p_reverse_weight*bn->value);
+ rem = _process_node(bn->inputs[1].node,r_prev_anim,p_weight*(1.0-bn->value),p_time,switched,p_seek,p_filter,p_reverse_weight*(1.0-bn->value));
+ _process_node(bn->inputs[2].node,r_prev_anim,p_weight*bn->value,p_time,switched,p_seek,p_filter,p_reverse_weight*bn->value);
} else {
- rem = _process_node(bn->inputs[1].node,r_prev_anim,p_weight*(1.0+bn->value),p_time,p_seek,p_filter,p_reverse_weight*(1.0+bn->value));
- _process_node(bn->inputs[0].node,r_prev_anim,p_weight*-bn->value,p_time,p_seek,p_filter,p_reverse_weight*-bn->value);
+ rem = _process_node(bn->inputs[1].node,r_prev_anim,p_weight*(1.0+bn->value),p_time,switched,p_seek,p_filter,p_reverse_weight*(1.0+bn->value));
+ _process_node(bn->inputs[0].node,r_prev_anim,p_weight*-bn->value,p_time,switched,p_seek,p_filter,p_reverse_weight*-bn->value);
}
return rem;
@@ -552,10 +626,10 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode
case NODE_BLEND4: {
Blend4Node *bn = static_cast<Blend4Node*>(nb);
- float rem = _process_node(bn->inputs[0].node,r_prev_anim,p_weight*(1.0-bn->value.x),p_time,p_seek,p_filter,p_reverse_weight*(1.0-bn->value.x));
- _process_node(bn->inputs[1].node,r_prev_anim,p_weight*bn->value.x,p_time,p_seek,p_filter,p_reverse_weight*bn->value.x);
- float rem2 = _process_node(bn->inputs[2].node,r_prev_anim,p_weight*(1.0-bn->value.y),p_time,p_seek,p_filter,p_reverse_weight*(1.0-bn->value.y));
- _process_node(bn->inputs[3].node,r_prev_anim,p_weight*bn->value.y,p_time,p_seek,p_filter,p_reverse_weight*bn->value.y);
+ float rem = _process_node(bn->inputs[0].node,r_prev_anim,p_weight*(1.0-bn->value.x),p_time,switched,p_seek,p_filter,p_reverse_weight*(1.0-bn->value.x));
+ _process_node(bn->inputs[1].node,r_prev_anim,p_weight*bn->value.x,p_time,switched,p_seek,p_filter,p_reverse_weight*bn->value.x);
+ float rem2 = _process_node(bn->inputs[2].node,r_prev_anim,p_weight*(1.0-bn->value.y),p_time,switched,p_seek,p_filter,p_reverse_weight*(1.0-bn->value.y));
+ _process_node(bn->inputs[3].node,r_prev_anim,p_weight*bn->value.y,p_time,switched,p_seek,p_filter,p_reverse_weight*bn->value.y);
return MAX(rem,rem2);
@@ -563,9 +637,9 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode
case NODE_TIMESCALE: {
TimeScaleNode *tsn = static_cast<TimeScaleNode*>(nb);
if (p_seek)
- return _process_node(tsn->inputs[0].node,r_prev_anim,p_weight,p_time,true,p_filter,p_reverse_weight);
+ return _process_node(tsn->inputs[0].node,r_prev_anim,p_weight,p_time,switched,true,p_filter,p_reverse_weight);
else
- return _process_node(tsn->inputs[0].node,r_prev_anim,p_weight,p_time*tsn->scale,false,p_filter,p_reverse_weight);
+ return _process_node(tsn->inputs[0].node,r_prev_anim,p_weight,p_time*tsn->scale,switched,false,p_filter,p_reverse_weight);
} break;
case NODE_TIMESEEK: {
@@ -573,12 +647,12 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode
TimeSeekNode *tsn = static_cast<TimeSeekNode*>(nb);
if (tsn->seek_pos>=0) {
- float res = _process_node(tsn->inputs[0].node,r_prev_anim,p_weight,tsn->seek_pos,true,p_filter,p_reverse_weight);
+ float res = _process_node(tsn->inputs[0].node,r_prev_anim,p_weight,tsn->seek_pos,switched,true,p_filter,p_reverse_weight);
tsn->seek_pos=-1;
return res;
} else
- return _process_node(tsn->inputs[0].node,r_prev_anim,p_weight,p_time,p_seek);
+ return _process_node(tsn->inputs[0].node,r_prev_anim,p_weight,p_time,switched,p_seek);
} break;
case NODE_TRANSITION: {
@@ -587,7 +661,7 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode
if (tn->prev<0) {
- float rem = _process_node(tn->inputs[tn->current].node,r_prev_anim,p_weight,p_time,p_seek,p_filter,p_reverse_weight);
+ float rem = _process_node(tn->inputs[tn->current].node,r_prev_anim,p_weight,p_time,switched,p_seek,p_filter,p_reverse_weight);
if (p_seek)
tn->time=p_time;
else
@@ -616,10 +690,10 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode
if (!p_seek && tn->switched) { //just switched
- rem = _process_node(tn->inputs[tn->current].node,r_prev_anim,p_weight*(1.0-blend),0,true,p_filter,p_reverse_weight*(1.0-blend));
+ rem = _process_node(tn->inputs[tn->current].node,r_prev_anim,p_weight*(1.0-blend),0,true,true,p_filter,p_reverse_weight*(1.0-blend));
} else {
- rem = _process_node(tn->inputs[tn->current].node,r_prev_anim,p_weight*(1.0-blend),p_time,p_seek,p_filter,p_reverse_weight*(1.0-blend));
+ rem = _process_node(tn->inputs[tn->current].node,r_prev_anim,p_weight*(1.0-blend),p_time,switched,p_seek,p_filter,p_reverse_weight*(1.0-blend));
}
@@ -629,10 +703,10 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode
if (p_seek) {
- _process_node(tn->inputs[tn->prev].node,r_prev_anim,p_weight*blend,0,false,p_filter,p_reverse_weight*blend);
+ _process_node(tn->inputs[tn->prev].node,r_prev_anim,p_weight*blend,0,true,false,p_filter,p_reverse_weight*blend);
tn->time=p_time;
} else {
- _process_node(tn->inputs[tn->prev].node,r_prev_anim,p_weight*blend,p_time,false,p_filter,p_reverse_weight*blend);
+ _process_node(tn->inputs[tn->prev].node,r_prev_anim,p_weight*blend,p_time,switched,false,p_filter,p_reverse_weight*blend);
tn->time+=p_time;
tn->prev_xfading-=p_time;
if (tn->prev_xfading<0) {
@@ -656,10 +730,7 @@ float AnimationTreePlayer::_process_node(const StringName& p_node,AnimationNode
}
-void AnimationTreePlayer::_process_animation() {
-
- if (!active)
- return;
+void AnimationTreePlayer::_process_animation(float p_delta) {
if (last_error!=CONNECT_OK)
return;
@@ -672,10 +743,10 @@ void AnimationTreePlayer::_process_animation() {
AnimationNode *prev=NULL;
if (reset_request) {
- _process_node(out_name,&prev, 1.0, 0, true );
+ _process_node(out_name,&prev, 1.0, 0, true, true );
reset_request=false;
} else
- _process_node(out_name,&prev, 1.0, get_process_delta_time(), false );
+ _process_node(out_name,&prev, 1.0, p_delta, false, false );
if (dirty_caches) {
//some animation changed.. ignore this pass
@@ -766,7 +837,7 @@ void AnimationTreePlayer::_process_animation() {
StringName method = a->method_track_get_name(tr.local_track,E->get());
Vector<Variant> args=a->method_track_get_params(tr.local_track,E->get());
- ERR_CONTINUE(args.size()!=VARIANT_ARG_MAX);
+ args.resize(VARIANT_ARG_MAX);
tr.track->node->call(method,args[0],args[1],args[2],args[3],args[4]);
}
} break;
@@ -1520,8 +1591,12 @@ void AnimationTreePlayer::recompute_caches() {
void AnimationTreePlayer::set_active(bool p_active) {
- active=p_active;
- set_process(active);
+ if (active == p_active)
+ return;
+
+ active = p_active;
+ processing = active;
+ _set_process(processing, true);
}
bool AnimationTreePlayer::is_active() const {
@@ -1743,13 +1818,18 @@ void AnimationTreePlayer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_node_list"),&AnimationTreePlayer::_get_node_list);
+ ObjectTypeDB::bind_method(_MD("set_animation_process_mode","mode"),&AnimationTreePlayer::set_animation_process_mode);
+ ObjectTypeDB::bind_method(_MD("get_animation_process_mode"),&AnimationTreePlayer::get_animation_process_mode);
+ ObjectTypeDB::bind_method(_MD("advance", "delta"), &AnimationTreePlayer::advance);
ObjectTypeDB::bind_method(_MD("reset"),&AnimationTreePlayer::reset);
ObjectTypeDB::bind_method(_MD("recompute_caches"),&AnimationTreePlayer::recompute_caches);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "playback/process_mode", PROPERTY_HINT_ENUM, "Fixed,Idle"), _SCS("set_animation_process_mode"), _SCS("get_animation_process_mode"));
+
BIND_CONSTANT( NODE_OUTPUT );
BIND_CONSTANT( NODE_ANIMATION );
BIND_CONSTANT( NODE_ONESHOT );
@@ -1770,6 +1850,9 @@ AnimationTreePlayer::AnimationTreePlayer() {
out_name="out";
out->pos=Point2(40,40);
node_map.insert( out_name , out);
+ AnimationProcessMode animation_process_mode;
+ animation_process_mode = ANIMATION_PROCESS_IDLE;
+ processing = false;
active=false;
dirty_caches=true;
reset_request=false;
diff --git a/scene/animation/animation_tree_player.h b/scene/animation/animation_tree_player.h
index 9e936304c6..0fec9a9551 100644
--- a/scene/animation/animation_tree_player.h
+++ b/scene/animation/animation_tree_player.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,6 +34,7 @@
#include "scene/3d/spatial.h"
#include "scene/3d/skeleton.h"
#include "scene/main/misc.h"
+#include "animation_player.h"
class AnimationTreePlayer : public Node {
@@ -42,7 +43,10 @@ class AnimationTreePlayer : public Node {
OBJ_CATEGORY("Animation Nodes");
public:
-
+ enum AnimationProcessMode {
+ ANIMATION_PROCESS_FIXED,
+ ANIMATION_PROCESS_IDLE,
+ };
enum NodeType {
@@ -256,13 +260,15 @@ private:
ConnectError last_error;
AnimationNode *active_list;
+ AnimationProcessMode animation_process_mode;
+ bool processing;
bool active;
bool dirty_caches;
Map<StringName,NodeBase*> node_map;
// return time left to finish animation
- float _process_node(const StringName& p_node,AnimationNode **r_prev_anim, float p_weight,float p_step, bool p_seek=false,const HashMap<NodePath,bool> *p_filter=NULL, float p_reverse_weight=0);
- void _process_animation();
+ float _process_node(const StringName& p_node,AnimationNode **r_prev_anim, float p_weight,float p_step, bool switched, bool p_seek=false,const HashMap<NodePath,bool> *p_filter=NULL, float p_reverse_weight=0);
+ void _process_animation(float p_delta);
bool reset_request;
ConnectError _cycle_test(const StringName &p_at_node);
@@ -409,12 +415,21 @@ public:
ConnectError get_last_error() const;
+ void set_animation_process_mode(AnimationProcessMode p_mode);
+ AnimationProcessMode get_animation_process_mode() const;
+
+ void _set_process(bool p_process, bool p_force = false);
+
+ void advance(float p_time);
+
AnimationTreePlayer();
~AnimationTreePlayer();
};
VARIANT_ENUM_CAST( AnimationTreePlayer::NodeType );
+VARIANT_ENUM_CAST( AnimationTreePlayer::AnimationProcessMode );
+
#endif // ANIMATION_TREE_PLAYER_H
diff --git a/scene/animation/transitioner.cpp b/scene/animation/transitioner.cpp
index d210f29db0..adcf73d489 100644
--- a/scene/animation/transitioner.cpp
+++ b/scene/animation/transitioner.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/animation/transitioner.h b/scene/animation/transitioner.h
index dba83cddd8..8b7ec4f3fa 100644
--- a/scene/animation/transitioner.h
+++ b/scene/animation/transitioner.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index 73d93e50ec..31f30dd1d9 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/animation/tween.h b/scene/animation/tween.h
index d504c63d8a..f06ca1e9e7 100644
--- a/scene/animation/tween.h
+++ b/scene/animation/tween.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/animation/tween_interpolaters.cpp b/scene/animation/tween_interpolaters.cpp
index 9128d220de..80588d643e 100644
--- a/scene/animation/tween_interpolaters.cpp
+++ b/scene/animation/tween_interpolaters.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/audio/SCsub b/scene/audio/SCsub
index 055d2f2474..bbe59b3054 100644
--- a/scene/audio/SCsub
+++ b/scene/audio/SCsub
@@ -3,5 +3,3 @@ Import('env')
env.add_source_files(env.scene_sources,"*.cpp")
Export('env')
-
-
diff --git a/scene/audio/event_player.cpp b/scene/audio/event_player.cpp
index 1bd692431d..b49b285f76 100644
--- a/scene/audio/event_player.cpp
+++ b/scene/audio/event_player.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -312,16 +312,14 @@ void EventPlayer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_pos"),&EventPlayer::get_pos);
ObjectTypeDB::bind_method(_MD("seek_pos","time"),&EventPlayer::seek_pos);
+ ObjectTypeDB::bind_method(_MD("get_length"),&EventPlayer::get_length);
+
ObjectTypeDB::bind_method(_MD("set_autoplay","enabled"),&EventPlayer::set_autoplay);
ObjectTypeDB::bind_method(_MD("has_autoplay"),&EventPlayer::has_autoplay);
ObjectTypeDB::bind_method(_MD("set_channel_volume","idx","channel_volume"),&EventPlayer::set_channel_volume);
- ObjectTypeDB::bind_method(_MD("get_channel_volume""idx"),&EventPlayer::get_channel_volume);
-
- ObjectTypeDB::bind_method(_MD("get_length"),&EventPlayer::get_length);
-
-
- ObjectTypeDB::bind_method(_MD("get_channel_last_note_time"),&EventPlayer::get_channel_last_note_time);
+ ObjectTypeDB::bind_method(_MD("get_channel_volume","idx"),&EventPlayer::get_channel_volume);
+ ObjectTypeDB::bind_method(_MD("get_channel_last_note_time","idx"),&EventPlayer::get_channel_last_note_time);
ObjectTypeDB::bind_method(_MD("_set_play","play"),&EventPlayer::_set_play);
ObjectTypeDB::bind_method(_MD("_get_play"),&EventPlayer::_get_play);
diff --git a/scene/audio/event_player.h b/scene/audio/event_player.h
index 05e78040d2..c04e85fe77 100644
--- a/scene/audio/event_player.h
+++ b/scene/audio/event_player.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/audio/sample_player.cpp b/scene/audio/sample_player.cpp
index 25e83df39d..d7605ed1a9 100644
--- a/scene/audio/sample_player.cpp
+++ b/scene/audio/sample_player.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -48,8 +48,8 @@ bool SamplePlayer::_set(const StringName& p_name, const Variant& p_value) {
}
} else if (name=="config/samples")
set_sample_library(p_value);
- else if (name=="config/voices")
- set_voice_count(p_value);
+ else if (name=="config/polyphony")
+ set_polyphony(p_value);
else if (name.begins_with("default/")) {
String what=name.right(8);
@@ -95,14 +95,14 @@ bool SamplePlayer::_get(const StringName& p_name,Variant &r_ret) const {
if (name=="play/play") {
r_ret=played_back;
- } else if (name=="config/voices") {
- r_ret= get_voice_count();
+ } else if (name=="config/polyphony") {
+ r_ret= get_polyphony();
} else if (name=="config/samples") {
r_ret= get_sample_library();
} else if (name.begins_with("default/")) {
- String what=name.get_slice("/",1);
+ String what=name.right(8);
if (what=="volume_db")
r_ret= get_default_volume_db();
@@ -153,7 +153,7 @@ void SamplePlayer::_get_property_list(List<PropertyInfo> *p_list) const {
}
p_list->push_back( PropertyInfo( Variant::STRING, "play/play", PROPERTY_HINT_ENUM, en,PROPERTY_USAGE_EDITOR));
- p_list->push_back( PropertyInfo( Variant::INT, "config/voices", PROPERTY_HINT_RANGE, "1,256,1"));
+ p_list->push_back( PropertyInfo( Variant::INT, "config/polyphony", PROPERTY_HINT_RANGE, "1,256,1"));
p_list->push_back( PropertyInfo( Variant::OBJECT, "config/samples", PROPERTY_HINT_RESOURCE_TYPE, "SampleLibrary"));
p_list->push_back( PropertyInfo( Variant::REAL, "default/volume_db", PROPERTY_HINT_RANGE, "-80,24,0.01"));
p_list->push_back( PropertyInfo( Variant::REAL, "default/pitch_scale", PROPERTY_HINT_RANGE, "0.01,48,0.01"));
@@ -164,7 +164,7 @@ void SamplePlayer::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back( PropertyInfo( Variant::REAL, "default/filter/cutoff", PROPERTY_HINT_RANGE, "20,16384.0,0.01"));
p_list->push_back( PropertyInfo( Variant::REAL, "default/filter/resonance", PROPERTY_HINT_RANGE, "0,4,0.01"));
p_list->push_back( PropertyInfo( Variant::REAL, "default/filter/gain", PROPERTY_HINT_RANGE, "0,2,0.01"));
- p_list->push_back( PropertyInfo( Variant::INT, "default/reverb_room", PROPERTY_HINT_ENUM, "Small,Medimum,Large,Hall"));
+ p_list->push_back( PropertyInfo( Variant::INT, "default/reverb_room", PROPERTY_HINT_ENUM, "Small,Medium,Large,Hall"));
p_list->push_back( PropertyInfo( Variant::REAL, "default/reverb_send", PROPERTY_HINT_RANGE, "0,1,0.01"));
p_list->push_back( PropertyInfo( Variant::REAL, "default/chorus_send", PROPERTY_HINT_RANGE, "0,1,0.01"));
@@ -203,14 +203,14 @@ SamplePlayer::Voice::~Voice() {
}
-void SamplePlayer::set_voice_count(int p_voice_count) {
+void SamplePlayer::set_polyphony(int p_voice_count) {
ERR_FAIL_COND( p_voice_count <1 || p_voice_count >0xFFFE );
voices.resize(p_voice_count);
}
-int SamplePlayer::get_voice_count() const {
+int SamplePlayer::get_polyphony() const {
return voices.size();
}
@@ -460,9 +460,9 @@ float SamplePlayer::get_chorus(VoiceID p_voice) const {
return v.chorus_send;
}
-float SamplePlayer::get_reverb_room(VoiceID p_voice) const {
+SamplePlayer::ReverbRoomType SamplePlayer::get_reverb_room(VoiceID p_voice) const {
- _GET_VOICE_V(0);
+ _GET_VOICE_V(REVERB_SMALL);
return v.reverb_room;
}
@@ -591,7 +591,7 @@ float SamplePlayer::get_default_chorus() const {
return _default.chorus_send;
}
-float SamplePlayer::get_default_reverb_room() const {
+SamplePlayer::ReverbRoomType SamplePlayer::get_default_reverb_room() const {
return _default.reverb_room;
}
@@ -606,8 +606,8 @@ void SamplePlayer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_sample_library","library:SampleLibrary"),&SamplePlayer::set_sample_library );
ObjectTypeDB::bind_method(_MD("get_sample_library:SampleLibrary"),&SamplePlayer::get_sample_library );
- ObjectTypeDB::bind_method(_MD("set_voice_count","max_voices"),&SamplePlayer::set_voice_count );
- ObjectTypeDB::bind_method(_MD("get_voice_count"),&SamplePlayer::get_voice_count );
+ ObjectTypeDB::bind_method(_MD("set_polyphony","max_voices"),&SamplePlayer::set_polyphony );
+ ObjectTypeDB::bind_method(_MD("get_polyphony"),&SamplePlayer::get_polyphony );
ObjectTypeDB::bind_method(_MD("play","name","unique"),&SamplePlayer::play, DEFVAL(false) );
ObjectTypeDB::bind_method(_MD("stop","voice"),&SamplePlayer::stop );
@@ -615,8 +615,8 @@ void SamplePlayer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_mix_rate","voice","hz"),&SamplePlayer::set_mix_rate );
ObjectTypeDB::bind_method(_MD("set_pitch_scale","voice","ratio"),&SamplePlayer::set_pitch_scale );
- ObjectTypeDB::bind_method(_MD("set_volume","voice","nrg"),&SamplePlayer::set_volume );
- ObjectTypeDB::bind_method(_MD("set_volume_db","voice","nrg"),&SamplePlayer::set_volume_db );
+ ObjectTypeDB::bind_method(_MD("set_volume","voice","volume"),&SamplePlayer::set_volume );
+ ObjectTypeDB::bind_method(_MD("set_volume_db","voice","db"),&SamplePlayer::set_volume_db );
ObjectTypeDB::bind_method(_MD("set_pan","voice","pan","depth","height"),&SamplePlayer::set_pan,DEFVAL(0),DEFVAL(0) );
ObjectTypeDB::bind_method(_MD("set_filter","voice","type","cutoff_hz","resonance","gain"),&SamplePlayer::set_filter,DEFVAL(0) );
ObjectTypeDB::bind_method(_MD("set_chorus","voice","send"),&SamplePlayer::set_chorus );
@@ -638,8 +638,8 @@ void SamplePlayer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_reverb","voice"),&SamplePlayer::get_reverb );
ObjectTypeDB::bind_method(_MD("set_default_pitch_scale","ratio"),&SamplePlayer::set_default_pitch_scale );
- ObjectTypeDB::bind_method(_MD("set_default_volume","nrg"),&SamplePlayer::set_default_volume );
- ObjectTypeDB::bind_method(_MD("set_default_volume_db","db"),&SamplePlayer::set_default_volume );
+ ObjectTypeDB::bind_method(_MD("set_default_volume","volume"),&SamplePlayer::set_default_volume );
+ ObjectTypeDB::bind_method(_MD("set_default_volume_db","db"),&SamplePlayer::set_default_volume_db );
ObjectTypeDB::bind_method(_MD("set_default_pan","pan","depth","height"),&SamplePlayer::set_default_pan,DEFVAL(0),DEFVAL(0) );
ObjectTypeDB::bind_method(_MD("set_default_filter","type","cutoff_hz","resonance","gain"),&SamplePlayer::set_default_filter,DEFVAL(0) );
ObjectTypeDB::bind_method(_MD("set_default_chorus","send"),&SamplePlayer::set_default_chorus );
@@ -647,7 +647,7 @@ void SamplePlayer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_default_pitch_scale"),&SamplePlayer::get_default_pitch_scale );
ObjectTypeDB::bind_method(_MD("get_default_volume"),&SamplePlayer::get_default_volume );
- ObjectTypeDB::bind_method(_MD("get_default_volume_db"),&SamplePlayer::get_default_volume );
+ ObjectTypeDB::bind_method(_MD("get_default_volume_db"),&SamplePlayer::get_default_volume_db );
ObjectTypeDB::bind_method(_MD("get_default_pan"),&SamplePlayer::get_default_pan );
ObjectTypeDB::bind_method(_MD("get_default_pan_depth"),&SamplePlayer::get_default_pan_depth );
ObjectTypeDB::bind_method(_MD("get_default_pan_height"),&SamplePlayer::get_default_pan_height );
@@ -677,6 +677,8 @@ void SamplePlayer::_bind_methods() {
BIND_CONSTANT( REVERB_LARGE );
BIND_CONSTANT( REVERB_HALL );
+ BIND_CONSTANT( INVALID_VOICE_ID );
+
}
diff --git a/scene/audio/sample_player.h b/scene/audio/sample_player.h
index 53e085b8d8..1821c671dc 100644
--- a/scene/audio/sample_player.h
+++ b/scene/audio/sample_player.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -130,8 +130,8 @@ public:
void set_sample_library(const Ref<SampleLibrary>& p_library);
Ref<SampleLibrary> get_sample_library() const;
- void set_voice_count(int p_voice_count);
- int get_voice_count() const;
+ void set_polyphony(int p_voice_count);
+ int get_polyphony() const;
VoiceID play(const String& p_name,bool unique=false);
void stop(VoiceID p_voice);
@@ -161,7 +161,7 @@ public:
float get_filter_resonance(VoiceID p_voice) const;
float get_filter_gain(VoiceID p_voice) const;
float get_chorus(VoiceID p_voice) const;
- float get_reverb_room(VoiceID p_voice) const;
+ ReverbRoomType get_reverb_room(VoiceID p_voice) const;
float get_reverb(VoiceID p_voice) const;
@@ -185,7 +185,7 @@ public:
float get_default_filter_resonance() const;
float get_default_filter_gain() const;
float get_default_chorus() const;
- float get_default_reverb_room() const;
+ ReverbRoomType get_default_reverb_room() const;
float get_default_reverb() const;
SamplePlayer();
diff --git a/scene/audio/sound_room_params.cpp b/scene/audio/sound_room_params.cpp
index 8886113e03..bb2285c97f 100644
--- a/scene/audio/sound_room_params.cpp
+++ b/scene/audio/sound_room_params.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/audio/sound_room_params.h b/scene/audio/sound_room_params.h
index 8af2ae8c12..4ca1eae2ce 100644
--- a/scene/audio/sound_room_params.h
+++ b/scene/audio/sound_room_params.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/audio/stream_player.cpp b/scene/audio/stream_player.cpp
index a097aacf19..f7cfc31b03 100644
--- a/scene/audio/stream_player.cpp
+++ b/scene/audio/stream_player.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -28,6 +28,70 @@
/*************************************************************************/
#include "stream_player.h"
+int StreamPlayer::InternalStream::get_channel_count() const {
+
+ return player->sp_get_channel_count();
+}
+void StreamPlayer::InternalStream::set_mix_rate(int p_rate){
+
+ return player->sp_set_mix_rate(p_rate);
+}
+bool StreamPlayer::InternalStream::mix(int32_t *p_buffer,int p_frames){
+
+ return player->sp_mix(p_buffer,p_frames);
+}
+void StreamPlayer::InternalStream::update(){
+
+ player->sp_update();
+}
+
+
+int StreamPlayer::sp_get_channel_count() const {
+
+ return playback->get_channels();
+}
+
+void StreamPlayer::sp_set_mix_rate(int p_rate){
+
+ server_mix_rate=p_rate;
+}
+
+bool StreamPlayer::sp_mix(int32_t *p_buffer,int p_frames) {
+
+ if (resampler.is_ready() && !paused) {
+ return resampler.mix(p_buffer,p_frames);
+ }
+
+ return false;
+}
+
+void StreamPlayer::sp_update() {
+
+ //_THREAD_SAFE_METHOD_
+ if (!paused && resampler.is_ready() && playback.is_valid()) {
+
+ if (!playback->is_playing()) {
+ //stream depleted data, but there's still audio in the ringbuffer
+ //check that all this audio has been flushed before stopping the stream
+ int to_mix = resampler.get_total() - resampler.get_todo();
+ if (to_mix==0) {
+ if (!stop_request) {
+ stop_request=true;
+ call_deferred("stop");
+ }
+ return;
+ }
+
+ return;
+ }
+
+ int todo =resampler.get_todo();
+ int wrote = playback->mix(resampler.get_write_buffer(),todo);
+ resampler.write(wrote);
+ }
+}
+
+
void StreamPlayer::_notification(int p_what) {
@@ -52,19 +116,21 @@ void StreamPlayer::set_stream(const Ref<AudioStream> &p_stream) {
stop();
- if (stream_rid.is_valid())
- AudioServer::get_singleton()->free(stream_rid);
- stream_rid=RID();
-
stream=p_stream;
- if (!stream.is_null()) {
- stream->set_loop(loops);
- stream->set_paused(paused);
- stream_rid=AudioServer::get_singleton()->audio_stream_create(stream->get_audio_stream());
+ if (!stream.is_null()) {
+ playback=stream->instance_playback();
+ playback->set_loop(loops);
+ playback->set_loop_restart_time(loop_point);
+ AudioServer::get_singleton()->lock();
+ resampler.setup(playback->get_channels(),playback->get_mix_rate(),server_mix_rate,buffering_ms,playback->get_minimum_buffer_size());
+ AudioServer::get_singleton()->unlock();
+ } else {
+ AudioServer::get_singleton()->lock();
+ resampler.clear();
+ playback.unref();
+ AudioServer::get_singleton()->unlock();
}
-
-
}
Ref<AudioStream> StreamPlayer::get_stream() const {
@@ -73,15 +139,18 @@ Ref<AudioStream> StreamPlayer::get_stream() const {
}
-void StreamPlayer::play() {
+void StreamPlayer::play(float p_from_offset) {
ERR_FAIL_COND(!is_inside_tree());
- if (stream.is_null())
+ if (playback.is_null())
return;
- if (stream->is_playing())
- stop();
+ //if (is_playing())
+ stop();
- stream->play();
+ //_THREAD_SAFE_METHOD_
+ playback->play(p_from_offset);
+ //feed the ringbuffer as long as no update callback is going on
+ sp_update();
AudioServer::get_singleton()->stream_set_active(stream_rid,true);
AudioServer::get_singleton()->stream_set_volume_scale(stream_rid,volume);
// if (stream->get_update_mode()!=AudioStream::UPDATE_NONE)
@@ -93,28 +162,33 @@ void StreamPlayer::stop() {
if (!is_inside_tree())
return;
- if (stream.is_null())
+ if (playback.is_null())
return;
+ //_THREAD_SAFE_METHOD_
AudioServer::get_singleton()->stream_set_active(stream_rid,false);
- stream->stop();
+ stop_request=false;
+ playback->stop();
+ resampler.flush();
+ emit_signal("finished");
+
//set_idle_process(false);
}
bool StreamPlayer::is_playing() const {
- if (stream.is_null())
+ if (playback.is_null())
return false;
- return stream->is_playing();
+ return playback->is_playing() || resampler.has_data();
}
void StreamPlayer::set_loop(bool p_enable) {
loops=p_enable;
- if (stream.is_null())
+ if (playback.is_null())
return;
- stream->set_loop(loops);
+ playback->set_loop(loops);
}
bool StreamPlayer::has_loop() const {
@@ -134,6 +208,19 @@ float StreamPlayer::get_volume() const {
return volume;
}
+void StreamPlayer::set_loop_restart_time(float p_secs) {
+
+ loop_point=p_secs;
+ if (playback.is_valid())
+ playback->set_loop_restart_time(p_secs);
+}
+
+float StreamPlayer::get_loop_restart_time() const {
+
+ return loop_point;
+}
+
+
void StreamPlayer::set_volume_db(float p_db) {
if (p_db<-79)
@@ -161,31 +248,33 @@ String StreamPlayer::get_stream_name() const {
int StreamPlayer::get_loop_count() const {
- if (stream.is_null())
+ if (playback.is_null())
return 0;
- return stream->get_loop_count();
+ return playback->get_loop_count();
}
float StreamPlayer::get_pos() const {
- if (stream.is_null())
+ if (playback.is_null())
return 0;
- return stream->get_pos();
+ return playback->get_pos();
}
float StreamPlayer::get_length() const {
- if (stream.is_null())
+ if (playback.is_null())
return 0;
- return stream->get_length();
+ return playback->get_length();
}
void StreamPlayer::seek_pos(float p_time) {
- if (stream.is_null())
+ if (playback.is_null())
return;
- return stream->seek_pos(p_time);
+ //works better...
+ stop();
+ playback->play(p_time);
}
@@ -202,8 +291,8 @@ bool StreamPlayer::has_autoplay() const {
void StreamPlayer::set_paused(bool p_paused) {
paused=p_paused;
- if (stream.is_valid())
- stream->set_paused(p_paused);
+ //if (stream.is_valid())
+ // stream->set_paused(p_paused);
}
bool StreamPlayer::is_paused() const {
@@ -228,13 +317,24 @@ bool StreamPlayer::_get_play() const{
return _play;
}
+void StreamPlayer::set_buffering_msec(int p_msec) {
+
+ buffering_ms=p_msec;
+}
+
+int StreamPlayer::get_buffering_msec() const{
+
+ return buffering_ms;
+}
+
+
void StreamPlayer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_stream","stream:Stream"),&StreamPlayer::set_stream);
ObjectTypeDB::bind_method(_MD("get_stream:Stream"),&StreamPlayer::get_stream);
- ObjectTypeDB::bind_method(_MD("play"),&StreamPlayer::play);
+ ObjectTypeDB::bind_method(_MD("play","offset"),&StreamPlayer::play,DEFVAL(0));
ObjectTypeDB::bind_method(_MD("stop"),&StreamPlayer::stop);
ObjectTypeDB::bind_method(_MD("is_playing"),&StreamPlayer::is_playing);
@@ -251,6 +351,12 @@ void StreamPlayer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_volume_db","db"),&StreamPlayer::set_volume_db);
ObjectTypeDB::bind_method(_MD("get_volume_db"),&StreamPlayer::get_volume_db);
+ ObjectTypeDB::bind_method(_MD("set_buffering_msec","msec"),&StreamPlayer::set_buffering_msec);
+ ObjectTypeDB::bind_method(_MD("get_buffering_msec"),&StreamPlayer::get_buffering_msec);
+
+ ObjectTypeDB::bind_method(_MD("set_loop_restart_time","secs"),&StreamPlayer::set_loop_restart_time);
+ ObjectTypeDB::bind_method(_MD("get_loop_restart_time"),&StreamPlayer::get_loop_restart_time);
+
ObjectTypeDB::bind_method(_MD("get_stream_name"),&StreamPlayer::get_stream_name);
ObjectTypeDB::bind_method(_MD("get_loop_count"),&StreamPlayer::get_loop_count);
@@ -271,6 +377,10 @@ void StreamPlayer::_bind_methods() {
ADD_PROPERTY( PropertyInfo(Variant::REAL, "stream/volume_db", PROPERTY_HINT_RANGE,"-80,24,0.01"), _SCS("set_volume_db"), _SCS("get_volume_db") );
ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/autoplay"), _SCS("set_autoplay"), _SCS("has_autoplay") );
ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/paused"), _SCS("set_paused"), _SCS("is_paused") );
+ ADD_PROPERTY( PropertyInfo(Variant::INT, "stream/loop_restart_time"), _SCS("set_loop_restart_time"), _SCS("get_loop_restart_time") );
+ ADD_PROPERTY( PropertyInfo(Variant::INT, "stream/buffering_ms"), _SCS("set_buffering_msec"), _SCS("get_buffering_msec") );
+
+ ADD_SIGNAL(MethodInfo("finished"));
}
@@ -281,10 +391,18 @@ StreamPlayer::StreamPlayer() {
paused=false;
autoplay=false;
_play=false;
+ server_mix_rate=1;
+ internal_stream.player=this;
+ stream_rid=AudioServer::get_singleton()->audio_stream_create(&internal_stream);
+ buffering_ms=500;
+ loop_point=0;
+ stop_request=false;
+
}
StreamPlayer::~StreamPlayer() {
- if (stream_rid.is_valid())
- AudioServer::get_singleton()->free(stream_rid);
+ AudioServer::get_singleton()->free(stream_rid);
+ resampler.clear();
+
}
diff --git a/scene/audio/stream_player.h b/scene/audio/stream_player.h
index 21e2162188..30840137e2 100644
--- a/scene/audio/stream_player.h
+++ b/scene/audio/stream_player.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,17 +31,44 @@
#include "scene/resources/audio_stream.h"
#include "scene/main/node.h"
+#include "servers/audio/audio_rb_resampler.h"
class StreamPlayer : public Node {
OBJ_TYPE(StreamPlayer,Node);
+ //_THREAD_SAFE_CLASS_
+
+ struct InternalStream : public AudioServer::AudioStream {
+ StreamPlayer *player;
+ virtual int get_channel_count() const;
+ virtual void set_mix_rate(int p_rate); //notify the stream of the mix rate
+ virtual bool mix(int32_t *p_buffer,int p_frames);
+ virtual void update();
+ };
+
+
+ InternalStream internal_stream;
+ Ref<AudioStreamPlayback> playback;
Ref<AudioStream> stream;
+
+ int sp_get_channel_count() const;
+ void sp_set_mix_rate(int p_rate); //notify the stream of the mix rate
+ bool sp_mix(int32_t *p_buffer,int p_frames);
+ void sp_update();
+
+ int server_mix_rate;
+
RID stream_rid;
bool paused;
bool autoplay;
bool loops;
float volume;
+ float loop_point;
+ int buffering_ms;
+ volatile bool stop_request;
+
+ AudioRBResampler resampler;
bool _play;
void _set_play(bool p_play);
@@ -55,7 +82,7 @@ public:
void set_stream(const Ref<AudioStream> &p_stream);
Ref<AudioStream> get_stream() const;
- void play();
+ void play(float p_from_offset=0);
void stop();
bool is_playing() const;
@@ -68,6 +95,9 @@ public:
void set_volume(float p_vol);
float get_volume() const;
+ void set_loop_restart_time(float p_secs);
+ float get_loop_restart_time() const;
+
void set_volume_db(float p_db);
float get_volume_db() const;
@@ -81,6 +111,8 @@ public:
void set_autoplay(bool p_vol);
bool has_autoplay() const;
+ void set_buffering_msec(int p_msec);
+ int get_buffering_msec() const;
StreamPlayer();
~StreamPlayer();
diff --git a/scene/gui/SCsub b/scene/gui/SCsub
index 055d2f2474..bbe59b3054 100644
--- a/scene/gui/SCsub
+++ b/scene/gui/SCsub
@@ -3,5 +3,3 @@ Import('env')
env.add_source_files(env.scene_sources,"*.cpp")
Export('env')
-
-
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index 8b6f433c9c..698dbce2b5 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -255,6 +255,16 @@ void BaseButton::_notification(int p_what) {
group->_remove_button(this);
}
+ if (p_what==NOTIFICATION_VISIBILITY_CHANGED && !is_visible()) {
+
+ if (!toggle_mode) {
+ status.pressed = false;
+ }
+ status.hovering = false;
+ status.press_attempt = false;
+ status.pressing_inside = false;
+ status.pressing_button = 0;
+ }
}
void BaseButton::pressed() {
@@ -390,10 +400,10 @@ void BaseButton::_bind_methods() {
ADD_SIGNAL( MethodInfo("pressed" ) );
ADD_SIGNAL( MethodInfo("released" ) );
ADD_SIGNAL( MethodInfo("toggled", PropertyInfo( Variant::BOOL,"pressed") ) );
- ADD_PROPERTY( PropertyInfo( Variant::BOOL, "disabled"), _SCS("set_disabled"), _SCS("is_disabled"));
+ ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "disabled"), _SCS("set_disabled"), _SCS("is_disabled"));
ADD_PROPERTY( PropertyInfo( Variant::BOOL, "toggle_mode"), _SCS("set_toggle_mode"), _SCS("is_toggle_mode"));
- ADD_PROPERTY( PropertyInfo( Variant::BOOL, "is_pressed"), _SCS("set_pressed"), _SCS("is_pressed"));
- ADD_PROPERTY( PropertyInfo( Variant::BOOL, "click_on_press"), _SCS("set_click_on_press"), _SCS("get_click_on_press"));
+ ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "is_pressed"), _SCS("set_pressed"), _SCS("is_pressed"));
+ ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "click_on_press"), _SCS("set_click_on_press"), _SCS("get_click_on_press"));
BIND_CONSTANT( DRAW_NORMAL );
diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h
index e187a85eae..83c66326c5 100644
--- a/scene/gui/base_button.h
+++ b/scene/gui/base_button.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp
index 6489cbccd5..6fff90809e 100644
--- a/scene/gui/box_container.cpp
+++ b/scene/gui/box_container.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -99,8 +99,10 @@ void BoxContainer::_resort() {
elements exist */
+ bool has_stretched = false;
while(stretch_ratio_total>0) { // first of all, dont even be here if no stretchable objects exist
+ has_stretched = true;
bool refit_successful=true; //assume refit-test will go well
for(int i=0;i<get_child_count();i++) {
@@ -143,6 +145,18 @@ void BoxContainer::_resort() {
int ofs=0;
+ if (!has_stretched) {
+ switch (align) {
+ case ALIGN_BEGIN:
+ break;
+ case ALIGN_CENTER:
+ ofs = stretch_diff / 2;
+ break;
+ case ALIGN_END:
+ ofs = stretch_diff;
+ break;
+ }
+ }
first=true;
int idx=0;
@@ -254,6 +268,15 @@ void BoxContainer::_notification(int p_what) {
}
}
+void BoxContainer::set_alignment(AlignMode p_align) {
+ align = p_align;
+ _resort();
+}
+
+BoxContainer::AlignMode BoxContainer::get_alignment() const {
+ return align;
+}
+
void BoxContainer::add_spacer(bool p_begin) {
Control *c = memnew( Control );
@@ -270,10 +293,23 @@ void BoxContainer::add_spacer(bool p_begin) {
BoxContainer::BoxContainer(bool p_vertical) {
vertical=p_vertical;
+ align = ALIGN_BEGIN;
// set_ignore_mouse(true);
set_stop_mouse(false);
}
+void BoxContainer::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("get_alignment"),&BoxContainer::get_alignment);
+ ObjectTypeDB::bind_method(_MD("set_alignment","alignment"),&BoxContainer::set_alignment);
+
+ BIND_CONSTANT( ALIGN_BEGIN );
+ BIND_CONSTANT( ALIGN_CENTER );
+ BIND_CONSTANT( ALIGN_END );
+
+ ADD_PROPERTY( PropertyInfo(Variant::INT,"alignment", PROPERTY_HINT_ENUM, "Begin,Center,End"), _SCS("set_alignment"),_SCS("get_alignment") );
+
+}
MarginContainer* VBoxContainer::add_margin_child(const String& p_label,Control *p_control,bool p_expand) {
diff --git a/scene/gui/box_container.h b/scene/gui/box_container.h
index d461b4aebe..6e63e8bdac 100644
--- a/scene/gui/box_container.h
+++ b/scene/gui/box_container.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,16 +35,31 @@ class BoxContainer : public Container {
OBJ_TYPE(BoxContainer,Container);
+public:
+
+ enum AlignMode {
+ ALIGN_BEGIN,
+ ALIGN_CENTER,
+ ALIGN_END
+ };
+
+private:
bool vertical;
+ AlignMode align;
void _resort();
protected:
void _notification(int p_what);
+
+ static void _bind_methods();
public:
void add_spacer(bool p_begin=false);
+ void set_alignment(AlignMode p_align);
+ AlignMode get_alignment() const;
+
virtual Size2 get_minimum_size() const;
BoxContainer(bool p_vertical=false);
@@ -73,4 +88,6 @@ public:
VBoxContainer() : BoxContainer(true) {}
};
+VARIANT_ENUM_CAST(BoxContainer::AlignMode);
+
#endif // BOX_CONTAINER_H
diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp
index b465db5c80..b9ce46d738 100644
--- a/scene/gui/button.cpp
+++ b/scene/gui/button.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -137,8 +137,10 @@ void Button::_notification(int p_what) {
text_ofs.y+=font->get_ascent();
font->draw( ci, text_ofs.floor(), text, color,clip_text?text_clip:-1);
if (!_icon.is_null()) {
+
+ int valign = size.height-style->get_minimum_size().y;
- _icon->draw(ci,Point2(style->get_offset().x, Math::floor( (size.height-_icon->get_height())/2.0 ) ),is_disabled()?Color(1,1,1,0.4):Color(1,1,1) );
+ _icon->draw(ci,style->get_offset()+Point2(0, Math::floor( (valign-_icon->get_height())/2.0 ) ),is_disabled()?Color(1,1,1,0.4):Color(1,1,1) );
}
@@ -225,11 +227,11 @@ void Button::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_text_align"),&Button::get_text_align);
ObjectTypeDB::bind_method(_MD("is_flat"),&Button::is_flat);
- ADD_PROPERTY( PropertyInfo( Variant::STRING, "text", PROPERTY_HINT_NONE,"",PROPERTY_USAGE_DEFAULT_INTL ), _SCS("set_text"),_SCS("get_text") );
- ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture" ), _SCS("set_button_icon"),_SCS("get_button_icon") );
+ ADD_PROPERTYNZ( PropertyInfo( Variant::STRING, "text", PROPERTY_HINT_NONE,"",PROPERTY_USAGE_DEFAULT_INTL ), _SCS("set_text"),_SCS("get_text") );
+ ADD_PROPERTYNZ( PropertyInfo( Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture" ), _SCS("set_button_icon"),_SCS("get_button_icon") );
ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flat" ), _SCS("set_flat"),_SCS("is_flat") );
- ADD_PROPERTY( PropertyInfo( Variant::BOOL, "clip_text" ), _SCS("set_clip_text"),_SCS("get_clip_text") );
- ADD_PROPERTY( PropertyInfo( Variant::INT, "align",PROPERTY_HINT_ENUM,"Left,Center,Right" ), _SCS("set_text_align"),_SCS("get_text_align") );
+ ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "clip_text" ), _SCS("set_clip_text"),_SCS("get_clip_text") );
+ ADD_PROPERTYNO( PropertyInfo( Variant::INT, "align",PROPERTY_HINT_ENUM,"Left,Center,Right" ), _SCS("set_text_align"),_SCS("get_text_align") );
}
diff --git a/scene/gui/button.h b/scene/gui/button.h
index 690179b90c..bd244f5087 100644
--- a/scene/gui/button.h
+++ b/scene/gui/button.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/button_array.cpp b/scene/gui/button_array.cpp
index 7f565de244..9e3476899f 100644
--- a/scene/gui/button_array.cpp
+++ b/scene/gui/button_array.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,7 +34,7 @@ bool ButtonArray::_set(const StringName& p_name, const Variant& p_value) {
String n=String(p_name);
if (n.begins_with("button/")) {
- String what = n.get_slice("/",1);
+ String what = n.get_slicec('/',1);
if (what=="count") {
int new_size=p_value;
if (new_size>0 && buttons.size()==0) {
@@ -57,7 +57,7 @@ bool ButtonArray::_set(const StringName& p_name, const Variant& p_value) {
} else {
int idx=what.to_int();
ERR_FAIL_INDEX_V(idx,buttons.size(),false);
- String f = n.get_slice("/",2);
+ String f = n.get_slicec('/',2);
if (f=="text")
buttons[idx].text=p_value;
else if (f=="icon")
@@ -80,7 +80,7 @@ bool ButtonArray::_get(const StringName& p_name,Variant &r_ret) const {
String n=String(p_name);
if (n.begins_with("button/")) {
- String what = n.get_slice("/",1);
+ String what = n.get_slicec('/',1);
if (what=="count") {
r_ret=buttons.size();
} else if (what=="align") {
@@ -92,7 +92,7 @@ bool ButtonArray::_get(const StringName& p_name,Variant &r_ret) const {
} else {
int idx=what.to_int();
ERR_FAIL_INDEX_V(idx,buttons.size(),false);
- String f = n.get_slice("/",2);
+ String f = n.get_slicec('/',2);
if (f=="text")
r_ret=buttons[idx].text;
else if (f=="icon")
diff --git a/scene/gui/button_array.h b/scene/gui/button_array.h
index ea2c1e4968..39661eaabd 100644
--- a/scene/gui/button_array.h
+++ b/scene/gui/button_array.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/button_group.cpp b/scene/gui/button_group.cpp
index 8d1fa80b84..04ba5fc06d 100644
--- a/scene/gui/button_group.cpp
+++ b/scene/gui/button_group.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -155,6 +155,6 @@ void ButtonGroup::_bind_methods() {
}
-ButtonGroup::ButtonGroup()
+ButtonGroup::ButtonGroup() : BoxContainer(true)
{
}
diff --git a/scene/gui/button_group.h b/scene/gui/button_group.h
index 24edf94994..38c61991b7 100644
--- a/scene/gui/button_group.h
+++ b/scene/gui/button_group.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,14 +29,14 @@
#ifndef BUTTON_GROUP_H
#define BUTTON_GROUP_H
-#include "scene/gui/control.h"
+#include "scene/gui/box_container.h"
class BaseButton;
-class ButtonGroup : public Control {
+class ButtonGroup : public BoxContainer {
- OBJ_TYPE(ButtonGroup,Control);
+ OBJ_TYPE(ButtonGroup,BoxContainer);
Set<BaseButton*> buttons;
diff --git a/scene/gui/center_container.cpp b/scene/gui/center_container.cpp
index 8a22a38980..844175e4c1 100644
--- a/scene/gui/center_container.cpp
+++ b/scene/gui/center_container.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/center_container.h b/scene/gui/center_container.h
index 4d8d06ac8c..dc95533525 100644
--- a/scene/gui/center_container.h
+++ b/scene/gui/center_container.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/check_box.cpp b/scene/gui/check_box.cpp
index 2aa82bc5f5..1381d6eb60 100644
--- a/scene/gui/check_box.cpp
+++ b/scene/gui/check_box.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/check_box.h b/scene/gui/check_box.h
index 171fd55351..95dd4891d4 100644
--- a/scene/gui/check_box.h
+++ b/scene/gui/check_box.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/check_button.cpp b/scene/gui/check_button.cpp
index d765aefe5e..ecaea251a5 100644
--- a/scene/gui/check_button.cpp
+++ b/scene/gui/check_button.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/check_button.h b/scene/gui/check_button.h
index b90bb31c2d..022ade2193 100644
--- a/scene/gui/check_button.h
+++ b/scene/gui/check_button.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index c30d473610..8685ec1c99 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -28,25 +28,43 @@
/*************************************************************************/
#include "color_picker.h"
+#include "scene/gui/separator.h"
+#include "scene/main/viewport.h"
+#include "os/os.h"
+#include "os/input.h"
+#include "os/keyboard.h"
+void update_material(Ref<CanvasItemMaterial>mat,const Color& p_color) {
+ if (!mat.is_valid())
+ return;
+ Ref<Shader> sdr = mat->get_shader();
+ if (!sdr.is_valid())
+ return;
+ mat->set_shader_param("R",p_color.r);
+ mat->set_shader_param("G",p_color.g);
+ mat->set_shader_param("B",p_color.b);
+ mat->set_shader_param("H",p_color.get_h());
+ mat->set_shader_param("S",p_color.get_s());
+ mat->set_shader_param("V",p_color.get_v());
+ mat->set_shader_param("A",p_color.a);
+}
void ColorPicker::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_THEME_CHANGED: {
-
+ uv_material->set_shader(get_shader("uv_editor"));
+ w_material->set_shader(get_shader("w_editor"));
+ update_material(uv_material,color);
+ update_material(w_material,color);
_update_controls();
} break;
-/* case NOTIFICATION_DRAW: {
-
- int w = get_constant("color_width");
- int h = ms.height;
- VisualServer::get_singleton()->canvas_item_add_rect(get_canvas_item(),Rect2(0,0,w,h),color);
-
- } break;*/
+ case NOTIFICATION_ENTER_TREE: {
+ btn_pick->set_icon(get_icon("screen_picker", "ColorPicker"));
+ }
}
}
@@ -64,10 +82,16 @@ void ColorPicker::_update_controls() {
}
-
void ColorPicker::set_color(const Color& p_color) {
color=p_color;
+ h=color.get_h();
+ s=color.get_s();
+ v=color.get_v();
+ update_material(uv_material, color);
+ update_material(w_material, color);
+ uv_edit->get_child(0)->cast_to<Control>()->update();
+ w_edit->get_child(0)->cast_to<Control>()->update();
_update_color();
}
@@ -77,7 +101,7 @@ void ColorPicker::set_edit_alpha(bool p_show) {
edit_alpha=p_show;
_update_controls();
_update_color();
- color_box->update();
+ sample->update();
}
bool ColorPicker::is_editing_alpha() const {
@@ -90,35 +114,17 @@ void ColorPicker::_value_changed(double) {
if (updating)
return;
- switch(mode) {
-
- case MODE_RGB: {
-
- for(int i=0;i<4;i++) {
- color.components[i] = scroll[i]->get_val() / 255.0;
- }
-
- } break;
- case MODE_HSV: {
-
- color.set_hsv( CLAMP(scroll[0]->get_val()/359,0,0.9972), scroll[1]->get_val()/100, scroll[2]->get_val()/100 );
- color.a=scroll[3]->get_val()/100.0;
-
- } break;
- case MODE_RAW: {
-
- for(int i=0;i<4;i++) {
- color.components[i] = scroll[i]->get_val();
- }
-
- } break;
-
+ for(int i=0;i<3;i++) {
+ color.components[i] = scroll[i]->get_val()/(raw_mode_enabled?1.0:255.0);
}
+ color.components[3] = scroll[3]->get_val()/255.0;
+ update_material(uv_material,color);
+ update_material(w_material,color);
html->set_text(color.to_html(edit_alpha && color.a<1));
- color_box->update();
+ sample->update();
emit_signal("color_changed",color);
@@ -138,144 +144,325 @@ void ColorPicker::_update_color() {
updating=true;
- switch(mode) {
-
- case MODE_RAW: {
-
- static const char*_lt[4]={"R","G","B","A"};
-
- for(int i=0;i<4;i++) {
- scroll[i]->set_max(255);
- scroll[i]->set_step(0.01);
- scroll[i]->set_val(color.components[i]);
- labels[i]->set_text(_lt[i]);
- }
- } break;
- case MODE_RGB: {
-
- static const char*_lt[4]={"R","G","B","A"};
-
- for(int i=0;i<4;i++) {
- scroll[i]->set_max(255);
- scroll[i]->set_step(1);
- scroll[i]->set_val(color.components[i]*255);
- labels[i]->set_text(_lt[i]);
- }
-
- } break;
- case MODE_HSV: {
-
- static const char*_lt[4]={"H","S","V","A"};
+ for(int i=0;i<4;i++) {
+ scroll[i]->set_max(255);
+ scroll[i]->set_step(0.01);
+ if (raw_mode_enabled && i != 3)
+ scroll[i]->set_val(color.components[i]);
+ else
+ scroll[i]->set_val(color.components[i]*255);
+ }
- for(int i=0;i<4;i++) {
- labels[i]->set_text(_lt[i]);
- }
+ html->set_text(color.to_html(edit_alpha && color.a<1));
- scroll[0]->set_max(359);
- scroll[0]->set_step(0.01);
- scroll[0]->set_val( color.get_h()*359 );
+ sample->update();
+ updating=false;
+}
- scroll[1]->set_max(100);
- scroll[1]->set_step(0.01);
- scroll[1]->set_val( color.get_s()*100 );
+void ColorPicker::_update_presets()
+{
+ Size2 size=bt_add_preset->get_size();
+ preset->set_custom_minimum_size(Size2(size.width*presets.size(),size.height));
+ Image i(size.x*presets.size(),size.y, false, Image::FORMAT_RGB);
+ for (int y=0;y<size.y;y++)
+ for (int x=0;x<size.x*presets.size();x++)
+ i.put_pixel(x,y,presets[(int)x/size.x]);
+ Ref<ImageTexture> t;
+ t.instance();
+ t->create_from_image(i);
+ preset->set_texture(t);
+}
- scroll[2]->set_max(100);
- scroll[2]->set_step(0.01);
- scroll[2]->set_val( color.get_v()*100 );
+Color ColorPicker::get_color() const {
- scroll[3]->set_max(100);
- scroll[3]->set_step(0.01);
- scroll[3]->set_val( color.a*100);
+ return color;
+}
- } break;
+void ColorPicker::add_preset(const Color &p_color)
+{
+ if (presets.find(p_color)) {
+ presets.move_to_back(presets.find(p_color));
+ } else {
+ presets.push_back(p_color);
}
+ _update_presets();
+ if (presets.size()==10)
+ bt_add_preset->hide();
+}
- html->set_text(color.to_html(edit_alpha && color.a<1));
+void ColorPicker::set_raw_mode(bool p_enabled) {
- color_box->update();
- updating=false;
+ if (raw_mode_enabled==p_enabled)
+ return;
+ raw_mode_enabled=p_enabled;
+ if (btn_mode->is_pressed()!=p_enabled)
+ btn_mode->set_pressed(p_enabled);
+
+ _update_controls();
+ _update_color();
}
-Color ColorPicker::get_color() const {
+bool ColorPicker::is_raw_mode() const {
- return color;
+ return raw_mode_enabled;
}
+void ColorPicker::_sample_draw() {
+ sample->draw_rect(Rect2(Point2(),Size2(256,20)),color);
+}
-void ColorPicker::set_mode(Mode p_mode) {
+void ColorPicker::_hsv_draw(int p_wich,Control* c)
+{
+ if (!c)
+ return;
+ if (p_wich==0) {
+ int x=c->get_size().x*color.get_s();
+ int y=c->get_size().y-c->get_size().y*color.get_v();
+ c->draw_line(Point2(x,0),Point2(x,c->get_size().y),color.inverted());
+ c->draw_line(Point2(0,y),Point2(c->get_size().x,y),color.inverted());
+ c->draw_line(Point2(x,y),Point2(x,y),Color(1,1,1),2);
+ } else if (p_wich==1) {
+ int y=c->get_size().y-c->get_size().y*color.get_h();
+ Color col=Color();
+ col.set_hsv(color.get_h(),1,1);
+ c->draw_line(Point2(0,y),Point2(c->get_size().x,y),col.inverted());
+ }
+}
- ERR_FAIL_INDEX(p_mode,3);
- mode=p_mode;
- if (mode_box->get_selected()!=p_mode)
- mode_box->select(p_mode);
+void ColorPicker::_uv_input(const InputEvent &ev) {
+ if (ev.type == InputEvent::MOUSE_BUTTON) {
+ const InputEventMouseButton &bev = ev.mouse_button;
+ if (bev.pressed) {
+ changing_color = true;
+ float x = CLAMP((float)bev.x,0,256);
+ float y = CLAMP((float)bev.y,0,256);
+ s=x/256;
+ v=1.0-y/256.0;
+ color.set_hsv(h,s,v,color.a);
+ set_color(color);
+ _update_color();
+ emit_signal("color_changed", color);
+ } else {
+ changing_color = false;
+ }
+ } else if (ev.type == InputEvent::MOUSE_MOTION) {
+ const InputEventMouse &bev = ev.mouse_motion;
+ if (!changing_color)
+ return;
+ float x = CLAMP((float)bev.x,0,256);
+ float y = CLAMP((float)bev.y,0,256);
+ s=x/256;
+ v=1.0-y/256.0;
+ color.set_hsv(h,s,v,color.a);
+ set_color(color);
+ _update_color();
+ emit_signal("color_changed", color);
+ }
+}
- _update_controls();
- _update_color();
+void ColorPicker::_w_input(const InputEvent &ev) {
+ if (ev.type == InputEvent::MOUSE_BUTTON) {
+ const InputEventMouseButton &bev = ev.mouse_button;
+ if (bev.pressed) {
+ changing_color = true;
+ h=1-((float)bev.y)/256.0;
+
+ } else {
+ changing_color = false;
+ }
+ color.set_hsv(h,s,v,color.a);
+ set_color(color);
+ _update_color();
+ emit_signal("color_changed", color);
+ } else if (ev.type == InputEvent::MOUSE_MOTION) {
+ const InputEventMouse &bev = ev.mouse_motion;
+ if (!changing_color)
+ return;
+ float y = CLAMP((float)bev.y,0,256);
+ h=1.0-y/256.0;
+ color.set_hsv(h,s,v,color.a);
+ set_color(color);
+ _update_color();
+ emit_signal("color_changed", color);
+ }
}
-ColorPicker::Mode ColorPicker::get_mode() const {
+void ColorPicker::_preset_input(const InputEvent &ev) {
+ if (ev.type == InputEvent::MOUSE_BUTTON) {
+ const InputEventMouseButton &bev = ev.mouse_button;
+ if (bev.pressed && bev.button_index==BUTTON_LEFT) {
+ int index = bev.x/(preset->get_size().x/presets.size());
+ set_color(presets[index]);
+ } else if (bev.pressed && bev.button_index==BUTTON_RIGHT) {
+ int index = bev.x/(preset->get_size().x/presets.size());
+ presets.erase(presets[index]);
+ _update_presets();
+ bt_add_preset->show();
+ }
+ _update_color();
+ emit_signal("color_changed", color);
+ } else if (ev.type == InputEvent::MOUSE_MOTION) {
+ const InputEventMouse &mev = ev.mouse_motion;
+ int index = mev.x/(preset->get_size().x/presets.size());
+ if (index<0 || index >= presets.size())
+ return;
+ preset->set_tooltip("Color: #"+presets[index].to_html(presets[index].a<1)+"\n"
+ "LMB: Set color\n"
+ "RMB: Remove preset");
+ }
+}
- return mode;
+void ColorPicker::_screen_input(const InputEvent &ev)
+{
+ if (ev.type==InputEvent::MOUSE_BUTTON) {
+ const InputEventMouseButton &bev = ev.mouse_button;
+ if (bev.button_index==BUTTON_LEFT&&!bev.pressed) {
+ emit_signal("color_changed", color);
+ screen->hide();
+ }
+ } else if (ev.type==InputEvent::MOUSE_MOTION) {
+ const InputEventMouse &mev = ev.mouse_motion;
+ Viewport *r=get_tree()->get_root();
+ if (!r->get_rect().has_point(Point2(mev.global_x,mev.global_y)))
+ return;
+ Image img =r->get_screen_capture();
+ if (!img.empty())
+ last_capture=img;
+ r->queue_screen_capture();
+ if (!last_capture.empty())
+ set_color(last_capture.get_pixel(mev.global_x,mev.global_y));
+ }
}
-void ColorPicker::_color_box_draw() {
+void ColorPicker::_add_preset_pressed() {
+ add_preset(color);
+}
- color_box->draw_rect( Rect2( Point2(), color_box->get_size()), color);
+void ColorPicker::_screen_pick_pressed()
+{
+ Viewport *r=get_tree()->get_root();
+ if (!screen) {
+ screen=memnew( Control );
+ r->add_child(screen);
+ screen->set_area_as_parent_rect();
+ screen->connect("input_event",this,"_screen_input");
+ }
+ screen->raise();
+ screen->show();
+ r->queue_screen_capture();
}
void ColorPicker::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_color","color"),&ColorPicker::set_color);
ObjectTypeDB::bind_method(_MD("get_color"),&ColorPicker::get_color);
- ObjectTypeDB::bind_method(_MD("set_mode","mode"),&ColorPicker::set_mode);
- ObjectTypeDB::bind_method(_MD("get_mode"),&ColorPicker::get_mode);
+ ObjectTypeDB::bind_method(_MD("set_raw_mode","mode"),&ColorPicker::set_raw_mode);
+ ObjectTypeDB::bind_method(_MD("is_raw_mode"),&ColorPicker::is_raw_mode);
ObjectTypeDB::bind_method(_MD("set_edit_alpha","show"),&ColorPicker::set_edit_alpha);
ObjectTypeDB::bind_method(_MD("is_editing_alpha"),&ColorPicker::is_editing_alpha);
+ ObjectTypeDB::bind_method(_MD("add_preset"), &ColorPicker::add_preset);
ObjectTypeDB::bind_method(_MD("_value_changed"),&ColorPicker::_value_changed);
ObjectTypeDB::bind_method(_MD("_html_entered"),&ColorPicker::_html_entered);
- ObjectTypeDB::bind_method(_MD("_color_box_draw"),&ColorPicker::_color_box_draw);
+ ObjectTypeDB::bind_method(_MD("_add_preset_pressed"), &ColorPicker::_add_preset_pressed);
+ ObjectTypeDB::bind_method(_MD("_screen_pick_pressed"), &ColorPicker::_screen_pick_pressed);
+ ObjectTypeDB::bind_method(_MD("_sample_draw"),&ColorPicker::_sample_draw);
+ ObjectTypeDB::bind_method(_MD("_hsv_draw"),&ColorPicker::_hsv_draw);
+ ObjectTypeDB::bind_method(_MD("_uv_input"),&ColorPicker::_uv_input);
+ ObjectTypeDB::bind_method(_MD("_w_input"),&ColorPicker::_w_input);
+ ObjectTypeDB::bind_method(_MD("_preset_input"),&ColorPicker::_preset_input);
+ ObjectTypeDB::bind_method(_MD("_screen_input"),&ColorPicker::_screen_input);
ADD_SIGNAL( MethodInfo("color_changed",PropertyInfo(Variant::COLOR,"color")));
}
+ColorPicker::ColorPicker() :
+ BoxContainer(true) {
-
-
-ColorPicker::ColorPicker() {
-
-
- //edit_alpha=false;
updating=true;
edit_alpha=true;
+ raw_mode_enabled=false;
+ changing_color=false;
+ screen=NULL;
+
+ HBoxContainer *hb_smpl = memnew( HBoxContainer );
+ btn_pick = memnew( ToolButton );
+ btn_pick->connect("pressed",this,"_screen_pick_pressed");
+
+ sample = memnew( TextureFrame );
+ sample->set_h_size_flags(SIZE_EXPAND_FILL);
+ sample->connect("draw",this,"_sample_draw");
+
+ hb_smpl->add_child(sample);
+ hb_smpl->add_child(btn_pick);
+ add_child(hb_smpl);
+
+ HBoxContainer *hb_edit = memnew( HBoxContainer );
+
+ uv_edit= memnew ( TextureFrame );
+ Image i(256, 256, false, Image::FORMAT_RGB);
+ for (int y=0;y<256;y++)
+ for (int x=0;x<256;x++)
+ i.put_pixel(x,y,Color());
+ Ref<ImageTexture> t;
+ t.instance();
+ t->create_from_image(i);
+ uv_edit->set_texture(t);
+ uv_edit->set_ignore_mouse(false);
+ uv_edit->set_custom_minimum_size(Size2(256,256));
+ uv_edit->connect("input_event", this, "_uv_input");
+ Control *c= memnew( Control );
+ uv_edit->add_child(c);
+ c->set_area_as_parent_rect();
+ c->set_stop_mouse(false);
+ c->set_material(memnew ( CanvasItemMaterial ));
+ Vector<Variant> args=Vector<Variant>();
+ args.push_back(0);
+ args.push_back(c);
+ c->connect("draw",this,"_hsv_draw",args);
+
+ add_child(hb_edit);
+ w_edit= memnew( TextureFrame );
+ i = Image(15, 256, false, Image::FORMAT_RGB);
+ for (int y=0;y<256;y++)
+ for (int x=0;x<15;x++)
+ i.put_pixel(x,y,Color());
+ Ref<ImageTexture> tw;
+ tw.instance();
+ tw->create_from_image(i);
+ w_edit->set_texture(tw);
+ w_edit->set_ignore_mouse(false);
+ w_edit->set_custom_minimum_size(Size2(15,256));
+ w_edit->connect("input_event", this, "_w_input");
+ c= memnew( Control );
+ w_edit->add_child(c);
+ c->set_area_as_parent_rect();
+ c->set_stop_mouse(false);
+ c->set_material(memnew ( CanvasItemMaterial ));
+ args.clear();
+ args.push_back(1);
+ args.push_back(c);
+ c->connect("draw",this,"_hsv_draw",args);
+
+ hb_edit->add_child(uv_edit);
+ hb_edit->add_child(memnew( VSeparator ));
+ hb_edit->add_child(w_edit);
VBoxContainer *vbl = memnew( VBoxContainer );
add_child(vbl);
- mode_box = memnew( OptionButton );
- mode_box->add_item("RGB");
- mode_box->add_item("HSV");
- mode_box->add_item("RAW");
- mode_box->connect("item_selected",this,"set_mode");
-
- color_box=memnew( Control );
- color_box->set_v_size_flags(SIZE_EXPAND_FILL);
- vbl->add_child(color_box);
- color_box->connect("draw",this,"_color_box_draw");
-
- vbl->add_child(mode_box);
-
+ add_child(memnew( HSeparator ));
VBoxContainer *vbr = memnew( VBoxContainer );
add_child(vbr);
vbr->set_h_size_flags(SIZE_EXPAND_FILL);
-
+ const char* lt[4] = {"R","G","B","A"};
for(int i=0;i<4;i++) {
HBoxContainer *hbc = memnew( HBoxContainer );
- labels[i]=memnew( Label );
+ labels[i]=memnew( Label(lt[i]) );
hbc->add_child(labels[i]);
scroll[i]=memnew( HSlider );
@@ -294,10 +481,14 @@ ColorPicker::ColorPicker() {
vbr->add_child(hbc);
-
}
HBoxContainer *hhb = memnew( HBoxContainer );
+
+ btn_mode = memnew( CheckButton );
+ btn_mode->set_text("RAW Mode");
+ btn_mode->connect("toggled", this, "set_raw_mode");
+ hhb->add_child(btn_mode);
vbr->add_child(hhb);
html_num = memnew( Label );
hhb->add_child(html_num);
@@ -309,11 +500,49 @@ ColorPicker::ColorPicker() {
html->set_h_size_flags(SIZE_EXPAND_FILL);
- mode=MODE_RGB;
_update_controls();
_update_color();
updating=false;
+ uv_material.instance();
+ Ref<Shader> s_uv = get_shader("uv_editor");
+ uv_material->set_shader(s_uv);
+
+ w_material.instance();
+
+ Ref<Shader> s_w = get_shader("w_editor");
+ w_material->set_shader(s_w);
+
+ uv_edit->set_material(uv_material);
+ w_edit->set_material(w_material);
+
+ set_color(Color(1,1,1));
+
+ i.create(256,20,false,Image::FORMAT_RGB);
+ for (int y=0;y<20;y++)
+ for(int x=0;x<256;x++)
+ if ((x/4+y/4)%2)
+ i.put_pixel(x,y,Color(1,1,1));
+ else
+ i.put_pixel(x,y,Color(0.6,0.6,0.6));
+ Ref<ImageTexture> t_smpl;
+ t_smpl.instance();
+ t_smpl->create_from_image(i);
+ sample->set_texture(t_smpl);
+
+ HBoxContainer *bbc = memnew( HBoxContainer );
+ add_child(bbc);
+
+ preset = memnew( TextureFrame );
+ bbc->add_child(preset);
+ preset->set_ignore_mouse(false);
+ preset->connect("input_event", this, "_preset_input");
+
+ bt_add_preset = memnew ( Button );
+ bt_add_preset->set_icon(get_icon("add_preset"));
+ bt_add_preset->set_tooltip("Add current color as a preset");
+ bt_add_preset->connect("pressed", this, "_add_preset_pressed");
+ bbc->add_child(bt_add_preset);
}
@@ -331,7 +560,7 @@ void ColorPickerButton::_color_changed(const Color& p_color) {
void ColorPickerButton::pressed() {
- Size2 ms = Size2(350, picker->get_combined_minimum_size().height+10);
+ Size2 ms = Size2(300, picker->get_combined_minimum_size().height+10);
popup->set_pos(get_global_pos()-Size2(0,ms.height));
popup->set_size(ms);
popup->popup();
@@ -347,7 +576,6 @@ void ColorPickerButton::_notification(int p_what) {
}
}
-
void ColorPickerButton::set_color(const Color& p_color){
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index 0756e88cf2..c6c7fe537d 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -36,25 +36,29 @@
#include "scene/gui/button.h"
#include "scene/gui/popup.h"
#include "scene/gui/box_container.h"
-#include "scene/gui/option_button.h"
+#include "scene/gui/texture_frame.h"
+#include "scene/gui/tool_button.h"
+#include "scene/gui/check_button.h"
+#include "scene/resources/material.h"
-class ColorPicker : public HBoxContainer {
+class ColorPicker : public BoxContainer {
- OBJ_TYPE(ColorPicker,HBoxContainer);
-public:
+ OBJ_TYPE(ColorPicker,BoxContainer);
- enum Mode {
- MODE_RGB,
- MODE_HSV,
- MODE_RAW
- };
private:
- Mode mode;
-
- OptionButton *mode_box;
-
- Control *color_box;
+ Control *screen;
+ Image last_capture;
+ TextureFrame *uv_edit;
+ TextureFrame *w_edit;
+ TextureFrame *sample;
+ TextureFrame *preset;
+ Button *bt_add_preset;
+ List<Color> presets;
+ ToolButton *btn_pick;
+ CheckButton *btn_mode;
+ Ref<CanvasItemMaterial> uv_material;
+ Ref<CanvasItemMaterial> w_material;
HSlider *scroll[4];
SpinBox *values[4];
Label *labels[4];
@@ -64,13 +68,25 @@ private:
Size2i ms;
Color color;
+ bool raw_mode_enabled;
bool updating;
+ bool changing_color;
+ float h,s,v;
void _html_entered(const String& p_html);
void _value_changed(double);
void _update_controls();
void _update_color();
- void _color_box_draw();
+ void _update_presets();
+ void _sample_draw();
+ void _hsv_draw(int p_wich,Control *c);
+
+ void _uv_input(const InputEvent& p_input);
+ void _w_input(const InputEvent& p_input);
+ void _preset_input(const InputEvent& p_input);
+ void _screen_input(const InputEvent& p_input);
+ void _add_preset_pressed();
+ void _screen_pick_pressed();
protected:
void _notification(int);
@@ -83,15 +99,14 @@ public:
void set_color(const Color& p_color);
Color get_color() const;
- void set_mode(Mode p_mode);
- Mode get_mode() const;
+ void add_preset(const Color& p_color);
+ void set_raw_mode(bool p_enabled);
+ bool is_raw_mode() const;
ColorPicker();
};
-VARIANT_ENUM_CAST( ColorPicker::Mode );
-
class ColorPickerButton : public Button {
OBJ_TYPE(ColorPickerButton,Button);
diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp
index 6c74bc3977..920c6bf1e6 100644
--- a/scene/gui/container.cpp
+++ b/scene/gui/container.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -52,6 +52,14 @@ void Container::add_child_notify(Node *p_child) {
}
+void Container::move_child_notify(Node *p_child) {
+
+ if (!p_child->cast_to<Control>())
+ return;
+
+ queue_sort();
+}
+
void Container::remove_child_notify(Node *p_child) {
@@ -97,6 +105,8 @@ void Container::fit_child_in_rect(Control *p_child,const Rect2& p_rect) {
p_child->set_pos(r.pos);
p_child->set_size(r.size);
+ p_child->set_rotation(0);
+ p_child->set_scale(Vector2(1,1));
}
void Container::queue_sort() {
diff --git a/scene/gui/container.h b/scene/gui/container.h
index ba9bf2d60f..1c7587c155 100644
--- a/scene/gui/container.h
+++ b/scene/gui/container.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -42,6 +42,7 @@ protected:
void queue_sort();
virtual void add_child_notify(Node *p_child);
+ virtual void move_child_notify(Node *p_child);
virtual void remove_child_notify(Node *p_child);
void _notification(int p_what);
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 2367c03e99..90c72989bd 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -42,37 +42,6 @@
#include <stdio.h>
-class TooltipPanel : public Panel {
-
- OBJ_TYPE(TooltipPanel,Panel)
-public:
- TooltipPanel() {};
-
-};
-
-class TooltipLabel : public Label {
-
- OBJ_TYPE(TooltipLabel,Label)
-public:
- TooltipLabel() {};
-
-};
-
-Control::Window::Window() {
-
-
- mouse_focus=NULL;
- mouse_focus_button=-1;
- key_focus=NULL;
- mouse_over=NULL;
- disable_input=false;
-
- cancelled_input_ID=0;
- tooltip=NULL;
- tooltip_popup=NULL;
- tooltip_label=NULL;
- subwindow_order_dirty=false;
-}
Variant Control::edit_get_state() const {
@@ -136,27 +105,32 @@ bool Control::_set(const StringName& p_name, const Variant& p_value) {
if (p_value.get_type()==Variant::NIL) {
if (name.begins_with("custom_icons/")) {
- String dname = name.get_slice("/",1);
+ String dname = name.get_slicec('/',1);
data.icon_override.erase(dname);
notification(NOTIFICATION_THEME_CHANGED);
update();
+ } else if (name.begins_with("custom_shaders/")) {
+ String dname = name.get_slicec('/',1);
+ data.shader_override.erase(dname);
+ notification(NOTIFICATION_THEME_CHANGED);
+ update();
} else if (name.begins_with("custom_styles/")) {
- String dname = name.get_slice("/",1);
+ String dname = name.get_slicec('/',1);
data.style_override.erase(dname);
notification(NOTIFICATION_THEME_CHANGED);
update();
} else if (name.begins_with("custom_fonts/")) {
- String dname = name.get_slice("/",1);
+ String dname = name.get_slicec('/',1);
data.font_override.erase(dname);
notification(NOTIFICATION_THEME_CHANGED);
update();
} else if (name.begins_with("custom_colors/")) {
- String dname = name.get_slice("/",1);
+ String dname = name.get_slicec('/',1);
data.color_override.erase(dname);
notification(NOTIFICATION_THEME_CHANGED);
update();
} else if (name.begins_with("custom_constants/")) {
- String dname = name.get_slice("/",1);
+ String dname = name.get_slicec('/',1);
data.constant_override.erase(dname);
notification(NOTIFICATION_THEME_CHANGED);
update();
@@ -165,23 +139,27 @@ bool Control::_set(const StringName& p_name, const Variant& p_value) {
} else {
if (name.begins_with("custom_icons/")) {
- String dname = name.get_slice("/",1);
+ String dname = name.get_slicec('/',1);
notification(NOTIFICATION_THEME_CHANGED);
add_icon_override(dname,p_value);
+ } else if (name.begins_with("custom_shaders/")) {
+ String dname = name.get_slicec('/',1);
+ add_shader_override(dname,p_value);
+ notification(NOTIFICATION_THEME_CHANGED);
} else if (name.begins_with("custom_styles/")) {
- String dname = name.get_slice("/",1);
+ String dname = name.get_slicec('/',1);
add_style_override(dname,p_value);
notification(NOTIFICATION_THEME_CHANGED);
} else if (name.begins_with("custom_fonts/")) {
- String dname = name.get_slice("/",1);
+ String dname = name.get_slicec('/',1);
add_font_override(dname,p_value);
notification(NOTIFICATION_THEME_CHANGED);
} else if (name.begins_with("custom_colors/")) {
- String dname = name.get_slice("/",1);
+ String dname = name.get_slicec('/',1);
add_color_override(dname,p_value);
notification(NOTIFICATION_THEME_CHANGED);
} else if (name.begins_with("custom_constants/")) {
- String dname = name.get_slice("/",1);
+ String dname = name.get_slicec('/',1);
add_constant_override(dname,p_value);
notification(NOTIFICATION_THEME_CHANGED);
} else
@@ -217,22 +195,26 @@ bool Control::_get(const StringName& p_name,Variant &r_ret) const {
return false;
if (sname.begins_with("custom_icons/")) {
- String name = sname.get_slice("/",1);
+ String name = sname.get_slicec('/',1);
r_ret= data.icon_override.has(name)?Variant(data.icon_override[name]):Variant();
+ } else if (sname.begins_with("custom_shaders/")) {
+ String name = sname.get_slicec('/',1);
+
+ r_ret= data.shader_override.has(name)?Variant(data.shader_override[name]):Variant();
} else if (sname.begins_with("custom_styles/")) {
- String name = sname.get_slice("/",1);
+ String name = sname.get_slicec('/',1);
r_ret= data.style_override.has(name)?Variant(data.style_override[name]):Variant();
} else if (sname.begins_with("custom_fonts/")) {
- String name = sname.get_slice("/",1);
+ String name = sname.get_slicec('/',1);
r_ret= data.font_override.has(name)?Variant(data.font_override[name]):Variant();
} else if (sname.begins_with("custom_colors/")) {
- String name = sname.get_slice("/",1);
+ String name = sname.get_slicec('/',1);
r_ret= data.color_override.has(name)?Variant(data.color_override[name]):Variant();
} else if (sname.begins_with("custom_constants/")) {
- String name = sname.get_slice("/",1);
+ String name = sname.get_slicec('/',1);
r_ret= data.constant_override.has(name)?Variant(data.constant_override[name]):Variant();
} else
@@ -269,6 +251,18 @@ void Control::_get_property_list( List<PropertyInfo> *p_list) const {
}
{
List<StringName> names;
+ theme->get_shader_list(get_type_name(),&names);
+ for(List<StringName>::Element *E=names.front();E;E=E->next()) {
+
+ uint32_t hint= PROPERTY_USAGE_EDITOR|PROPERTY_USAGE_CHECKABLE;
+ if (data.shader_override.has(E->get()))
+ hint|=PROPERTY_USAGE_STORAGE|PROPERTY_USAGE_CHECKED;
+
+ p_list->push_back( PropertyInfo(Variant::OBJECT,"custom_shaders/"+E->get(),PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemShader,CanvasItemShaderGraph",hint) );
+ }
+ }
+ {
+ List<StringName> names;
theme->get_stylebox_list(get_type_name(),&names);
for(List<StringName>::Element *E=names.front();E;E=E->next()) {
@@ -325,19 +319,6 @@ Control *Control::get_parent_control() const {
return data.parent;
}
-void Control::_input_text(const String& p_text) {
-
- if (!window)
- return;
- if (window->key_focus)
- window->key_focus->call("set_text",p_text);
-
-}
-
-void Control::_gui_input(const InputEvent& p_event) {
-
- _window_input_event(p_event);
-}
void Control::_resize(const Size2& p_size) {
@@ -353,79 +334,12 @@ void Control::_notification(int p_notification) {
case NOTIFICATION_ENTER_TREE: {
- if (data.window==this) {
-
- window = memnew( Window );
- add_to_group("_vp_gui_input"+itos(get_viewport()->get_instance_ID()));
- add_to_group("windows");
-
- window->tooltip_timer = memnew( Timer );
- add_child(window->tooltip_timer);
- window->tooltip_timer->force_parent_owned();
- window->tooltip_timer->set_wait_time( GLOBAL_DEF("display/tooltip_delay",0.7));
- window->tooltip_timer->connect("timeout",this,"_window_show_tooltip");
- window->tooltip=NULL;
- window->tooltip_popup = memnew( TooltipPanel );
- add_child(window->tooltip_popup);
- window->tooltip_popup->force_parent_owned();
- window->tooltip_label = memnew( TooltipLabel );
- window->tooltip_popup->add_child(window->tooltip_label);
- window->tooltip_popup->set_as_toplevel(true);
- window->tooltip_popup->hide();
- window->drag_attempted=false;
- window->drag_preview=NULL;
-
- if (get_tree()->is_editor_hint()) {
-
- Node *n = this;
- while(n) {
-
- if (n->has_meta("_editor_disable_input")) {
- window->disable_input=true;
- break;
- }
- n=n->get_parent();
- }
- }
-
- } else {
- window=NULL;
- }
-
_size_changed();
} break;
case NOTIFICATION_EXIT_TREE: {
- if (data.window) {
-
- if (data.window->window->mouse_focus == this)
- data.window->window->mouse_focus=NULL;
- if (data.window->window->key_focus == this)
- data.window->window->key_focus=NULL;
- if (data.window->window->mouse_over == this)
- data.window->window->mouse_over=NULL;
- if (data.window->window->tooltip == this)
- data.window->window->tooltip=NULL;
- }
-
- if (window) {
-
- remove_from_group("_vp_gui_input"+itos(get_viewport()->get_instance_ID()));
- remove_from_group("windows");
- if (window->tooltip_timer)
- memdelete(window->tooltip_timer);
- window->tooltip_timer=NULL;
- window->tooltip=NULL;
- if (window->tooltip_popup)
- memdelete(window->tooltip_popup);
- window->tooltip_popup=NULL;
-
- memdelete(window);
- window=NULL;
-
- }
-
+ get_viewport()->_gui_remove_control(this);
} break;
@@ -433,112 +347,94 @@ void Control::_notification(int p_notification) {
case NOTIFICATION_ENTER_CANVAS: {
- data.window=NULL;
- data.viewport=NULL;
- data.parent=NULL;
-
- Control *_window=this;
- bool gap=false;
- bool gap_valid=true;
- bool window_found=false;
+ data.parent=get_parent()->cast_to<Control>();
- Node *parent=_window->get_parent();
- if (parent && parent->cast_to<Control>()) {
+ if (is_set_as_toplevel()) {
+ data.SI=get_viewport()->_gui_add_subwindow_control(this);
+ } else {
- data.parent=parent->cast_to<Control>();
- }
- Viewport *viewport=NULL;
+ Node *parent=this; //meh
+ Node *parent_control=NULL;
+ bool subwindow=false;
- parent=this; //meh
+ while(parent) {
- while(parent) {
+ parent=parent->get_parent();
- Control *c=parent->cast_to<Control>();
+ if (!parent)
+ break;
- if (!window_found && c) {
- if (!gap && c!=this) {
- gap_valid=false;
+ CanvasItem *ci =parent->cast_to<CanvasItem>();
+ if (ci && ci->is_set_as_toplevel()) {
+ subwindow=true;
+ break;
}
- _window = c;
- }
-
- CanvasItem *ci =parent->cast_to<CanvasItem>();
+ if (parent->cast_to<Control>()) {
+ parent_control=parent->cast_to<Control>();
+ break;
+ } else if (ci) {
- if ((ci && ci->is_set_as_toplevel()) || !ci) {
- gap=true;
+ } else {
+ break;
+ }
}
- if (parent->cast_to<CanvasLayer>()) {
- window_found=true; //don't go beyond canvas layer
- }
- viewport =parent->cast_to<Viewport>();
- if (viewport) {
- break; //no go beyond viewport either
+ if (parent_control) {
+ //do nothing, has a parent control
+ } else if (subwindow) {
+ //is a subwindow (process input before other controls for that canvas)
+ data.SI=get_viewport()->_gui_add_subwindow_control(this);
+ } else {
+ //is a regular root control
+ data.RI=get_viewport()->_gui_add_root_control(this);
}
- parent=parent->get_parent();
- }
-
- data.window=_window;
- data.viewport=viewport;
- data.parent_canvas_item=get_parent_item();
-
- if (data.parent_canvas_item) {
+ data.parent_canvas_item=get_parent_item();
- data.parent_canvas_item->connect("item_rect_changed",this,"_size_changed");
- } else if (data.viewport) {
-
- //connect viewport
- data.viewport->connect("size_changed",this,"_size_changed");
- } else {
+ if (data.parent_canvas_item) {
+ data.parent_canvas_item->connect("item_rect_changed",this,"_size_changed");
+ } else {
+ //connect viewport
+ get_viewport()->connect("size_changed",this,"_size_changed");
+ }
}
- if (gap && gap_valid && data.window!=this) {
- //is a subwindow, conditions to meet subwindow status are quite complex..
- data.SI = data.window->window->subwindows.push_back(this);
- data.window->window->subwindow_order_dirty=true;
-
- }
-
} break;
case NOTIFICATION_EXIT_CANVAS: {
-
if (data.parent_canvas_item) {
data.parent_canvas_item->disconnect("item_rect_changed",this,"_size_changed");
data.parent_canvas_item=NULL;
- } else if (data.viewport) {
-
+ } else if (!is_set_as_toplevel()) {
//disconnect viewport
- data.viewport->disconnect("size_changed",this,"_size_changed");
- } else {
+ get_viewport()->disconnect("size_changed",this,"_size_changed");
}
if (data.MI) {
-
- if (data.window && data.window->window)
- data.window->window->modal_stack.erase(data.MI);
+ get_viewport()->_gui_remove_modal_control(data.MI);
data.MI=NULL;
}
if (data.SI) {
- //erase from subwindows
- if (data.window && data.window->window)
- data.window->window->subwindows.erase(data.SI);
+ get_viewport()->_gui_remove_subwindow_control(data.SI);
data.SI=NULL;
}
- data.viewport=NULL;
- data.window=NULL;
+ if (data.RI) {
+ get_viewport()->_gui_remove_root_control(data.RI);
+ data.RI=NULL;
+ }
+
data.parent=NULL;
+ data.parent_canvas_item=NULL;
} break;
@@ -569,8 +465,11 @@ void Control::_notification(int p_notification) {
data.parent->update();
update();
- if (data.SI && data.window) {
- data.window->window->subwindow_order_dirty=true;
+ if (data.SI) {
+ get_viewport()->_gui_set_subwindow_order_dirty();
+ }
+ if (data.RI) {
+ get_viewport()->_gui_set_root_order_dirty();
}
} break;
@@ -580,8 +479,8 @@ void Control::_notification(int p_notification) {
} break;
case NOTIFICATION_DRAW: {
- Matrix32 xform;
- xform.set_origin(get_pos());
+ Matrix32 xform=Matrix32(data.rotation,get_pos());
+ xform.scale_basis(data.scale);
VisualServer::get_singleton()->canvas_item_set_transform(get_canvas_item(),xform);
VisualServer::get_singleton()->canvas_item_set_custom_rect( get_canvas_item(),true, Rect2(Point2(),get_size()));
//emit_signal(SceneStringNames::get_singleton()->draw);
@@ -614,26 +513,8 @@ void Control::_notification(int p_notification) {
if (!is_visible()) {
- if (data.window->window->mouse_focus == this) {
- data.window->window->mouse_focus=NULL;
- }
- if (data.window==this) {
- window->drag_data=Variant();
- if (window->drag_preview) {
- memdelete( window->drag_preview);
- window->drag_preview=NULL;
- }
- }
-
- if (data.window->window->key_focus == this)
- data.window->window->key_focus=NULL;
- if (data.window->window->mouse_over == this)
- data.window->window->mouse_over=NULL;
- if (data.window->window->tooltip == this)
- data.window->window->tooltip=NULL;
- if (data.window->window->tooltip == this)
- data.window->window->tooltip=NULL;
+ get_viewport()->_gui_hid_control(this);
_modal_stack_remove();
minimum_size_changed();
@@ -647,10 +528,7 @@ void Control::_notification(int p_notification) {
} break;
case SceneTree::NOTIFICATION_WM_UNFOCUS_REQUEST: {
- if (!window)
- return;
- if (window->key_focus)
- window->key_focus->release_focus();
+ get_viewport()->_gui_unfocus_control(this);
} break;
@@ -726,605 +604,30 @@ void Control::drop_data(const Point2& p_point,const Variant& p_data){
void Control::force_drag(const Variant& p_data,Control *p_control) {
ERR_FAIL_COND(!is_inside_tree());
- ERR_FAIL_COND(!data.window);
ERR_FAIL_COND(p_data.get_type()==Variant::NIL);
+ get_viewport()->_gui_force_drag(p_data,p_control);
-
- data.window->window->drag_data=p_data;
- data.window->window->mouse_focus=NULL;
-
- if (p_control) {
- data.window->set_drag_preview(p_control);
- }
}
void Control::set_drag_preview(Control *p_control) {
- ERR_FAIL_NULL(p_control);
- ERR_FAIL_COND( !((Object*)p_control)->cast_to<Control>());
- ERR_FAIL_COND(!is_inside_tree() || !data.window);
- ERR_FAIL_COND(p_control->is_inside_tree());
- ERR_FAIL_COND(p_control->get_parent()!=NULL);
-
- if (data.window->window->drag_preview) {
- memdelete(data.window->window->drag_preview);
- }
- p_control->set_as_toplevel(true);
- p_control->set_pos(data.window->window->last_mouse_pos);
- data.window->add_child(p_control);
- if (data.window->window->drag_preview) {
- memdelete( data.window->window->drag_preview );
- }
-
- data.window->window->drag_preview=p_control;
-
-}
-
-
-Control* Control::_find_next_visible_control_at_pos(Node* p_node,const Point2& p_global,Matrix32& r_xform) const {
-
- return NULL;
+ ERR_FAIL_COND(!is_inside_tree());
+ get_viewport()->_gui_set_drag_preview(p_control);
}
-Control* Control::_find_control_at_pos(CanvasItem* p_node,const Point2& p_global,const Matrix32& p_xform,Matrix32& r_inv_xform) {
-
- if (p_node->cast_to<Viewport>())
- return NULL;
-
- Control *c=p_node->cast_to<Control>();
-
- if (c) {
- // print_line("at "+String(c->get_path())+" POS "+c->get_pos()+" bt "+p_xform);
- }
-
- if (c==data.window) {
- //try subwindows first!!
-
- c->_window_sort_subwindows(); // sort them
-
- for (List<Control*>::Element *E=c->window->subwindows.back();E;E=E->prev()) {
-
- Control *sw = E->get();
- if (!sw->is_visible())
- continue;
-
- Matrix32 xform;
- CanvasItem *pci = sw->get_parent_item();
- if (pci)
- xform=pci->get_global_transform();
-
- Control *ret = _find_control_at_pos(sw,p_global,xform,r_inv_xform);
- if (ret)
- return ret;
-
- }
- }
-
- if (p_node->is_hidden()) {
- //return _find_next_visible_control_at_pos(p_node,p_global,r_inv_xform);
- return NULL; //canvas item hidden, discard
- }
-
- Matrix32 matrix = p_xform * p_node->get_transform();
-
- if (!c || !c->clips_input() || c->has_point(matrix.affine_inverse().xform(p_global))) {
-
- for(int i=p_node->get_child_count()-1;i>=0;i--) {
-
- if (p_node==data.window->window->tooltip_popup)
- continue;
-
- CanvasItem *ci = p_node->get_child(i)->cast_to<CanvasItem>();
- if (!ci || ci->is_set_as_toplevel())
- continue;
-
- Control *ret=_find_control_at_pos(ci,p_global,matrix,r_inv_xform);;
- if (ret)
- return ret;
- }
- }
-
- if (!c)
- return NULL;
-
- matrix.affine_invert();
- //conditions for considering this as a valid control for return
- if (!c->data.ignore_mouse && c->has_point(matrix.xform(p_global)) && (!window->drag_preview || (c!=window->drag_preview && !window->drag_preview->is_a_parent_of(c)))) {
- r_inv_xform=matrix;
- return c;
- } else
- return NULL;
-}
-
-void Control::_window_cancel_input_ID(int p_input) {
-
- window->cancelled_input_ID=(unsigned int)p_input;
-}
-
-void Control::_window_remove_focus() {
-
- if (window->key_focus) {
- Node *f=window->key_focus;
- window->key_focus=NULL;
- f->notification( NOTIFICATION_FOCUS_EXIT,true );
-
- }
-}
-bool Control::window_has_modal_stack() const {
+bool Control::is_window_modal_on_top() const {
- if (!data.window)
+ if (!is_inside_tree())
return false;
- return data.window->window->modal_stack.size();
-}
-
-void Control::_window_cancel_tooltip() {
-
- window->tooltip=NULL;
- if (window->tooltip_timer)
- window->tooltip_timer->stop();
- if (window->tooltip_popup)
- window->tooltip_popup->hide();
+ return get_viewport()->_gui_is_modal_on_top(this);
}
-void Control::_window_show_tooltip() {
-
- if (!window->tooltip) {
- return;
- }
-
- String tooltip = window->tooltip->get_tooltip( window->tooltip->get_global_transform().xform_inv(window->tooltip_pos) );
- if (tooltip.length()==0)
- return; // bye
-
-
- if (!window->tooltip_label) {
- return;
- }
- Ref<StyleBox> ttp = get_stylebox("panel","TooltipPanel");
-
- window->tooltip_label->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_BEGIN,ttp->get_margin(MARGIN_LEFT));
- window->tooltip_label->set_anchor_and_margin(MARGIN_TOP,ANCHOR_BEGIN,ttp->get_margin(MARGIN_TOP));
- window->tooltip_label->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,ttp->get_margin(MARGIN_RIGHT));
- window->tooltip_label->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_END,ttp->get_margin(MARGIN_BOTTOM));
- window->tooltip_label->set_text(tooltip);
- Rect2 r(window->tooltip_pos+Point2(10,10),window->tooltip_label->get_combined_minimum_size()+ttp->get_minimum_size());
- Rect2 vr = get_viewport_rect();
- if (r.size.x+r.pos.x>vr.size.x)
- r.pos.x=vr.size.x-r.size.x;
- else if (r.pos.x<0)
- r.pos.x=0;
-
- if (r.size.y+r.pos.y>vr.size.y)
- r.pos.y=vr.size.y-r.size.y;
- else if (r.pos.y<0)
- r.pos.y=0;
-
- window->tooltip_popup->set_pos(r.pos);
- window->tooltip_popup->set_size(r.size);
-
- window->tooltip_popup->raise();
-
- window->tooltip_popup->show();
-}
-
-
-void Control::_window_call_input(Control *p_control,const InputEvent& p_input) {
-
-
- while(p_control) {
-
- p_control->call_multilevel(SceneStringNames::get_singleton()->_input_event,p_input);
- if (window->key_event_accepted)
- break;
- p_control->emit_signal(SceneStringNames::get_singleton()->input_event,p_input);
- if (p_control->is_set_as_toplevel()) {
- break;
- }
- if (window->key_event_accepted)
- break;
- if (p_control->data.stop_mouse && (p_input.type==InputEvent::MOUSE_BUTTON || p_input.type==InputEvent::MOUSE_MOTION))
- break;
- p_control=p_control->data.parent;
- }
-}
-
-void Control::_window_input_event(InputEvent p_event) {
-
-
-
- if (!window)
- return;
-
- if (window->disable_input)
- return;
-
- if (p_event.ID==window->cancelled_input_ID) {
- return;
- }
- if (!is_visible()) {
- return; //simple and plain
- }
- switch(p_event.type) {
-
- case InputEvent::MOUSE_BUTTON: {
-
-
- window->key_event_accepted=false;
-
- Point2 mpos =(get_canvas_transform()).affine_inverse().xform(Point2(p_event.mouse_button.x,p_event.mouse_button.y));
- if (p_event.mouse_button.pressed) {
-
-
-
- Size2 pos = mpos;
- if (window->mouse_focus && p_event.mouse_button.button_index!=window->mouse_focus_button) {
-
- //do not steal mouse focus and stuff
-
- } else {
-
-
- _window_sort_modal_stack();
- while (!window->modal_stack.empty()) {
-
- Control *top = window->modal_stack.back()->get();
- if (!top->has_point(top->get_global_transform().affine_inverse().xform(pos))) {
-
- if (top->data.modal_exclusive) {
- //cancel event, sorry, modal exclusive EATS UP ALL
- get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID);
- get_tree()->set_input_as_handled();
- return; // no one gets the event if exclusive NO ONE
- }
-
- top->notification(NOTIFICATION_MODAL_CLOSE);
- top->_modal_stack_remove();
- top->hide();
- } else {
- break;
- }
- }
-
-
-
- Matrix32 parent_xform;
-
- if (data.parent_canvas_item)
- parent_xform=data.parent_canvas_item->get_global_transform();
-
-
-
- window->mouse_focus = _find_control_at_pos(this,pos,parent_xform,window->focus_inv_xform);
- //print_line("has mf "+itos(window->mouse_focus!=NULL));
- window->mouse_focus_button=p_event.mouse_button.button_index;
-
- if (!window->mouse_focus) {
- break;
- }
-
- if (p_event.mouse_button.button_index==BUTTON_LEFT) {
- window->drag_accum=Vector2();
- window->drag_attempted=false;
- window->drag_data=Variant();
- }
-
-
- }
-
- p_event.mouse_button.global_x = pos.x;
- p_event.mouse_button.global_y = pos.y;
-
- pos = window->focus_inv_xform.xform(pos);
- p_event.mouse_button.x = pos.x;
- p_event.mouse_button.y = pos.y;
-
-#ifdef DEBUG_ENABLED
- if (ScriptDebugger::get_singleton()) {
-
- Array arr;
- arr.push_back(window->mouse_focus->get_path());
- arr.push_back(window->mouse_focus->get_type());
- ScriptDebugger::get_singleton()->send_message("click_ctrl",arr);
- }
-
- /*if (bool(GLOBAL_DEF("debug/print_clicked_control",false))) {
-
- print_line(String(window->mouse_focus->get_path())+" - "+pos);
- }*/
-#endif
-
- if (window->mouse_focus->get_focus_mode()!=FOCUS_NONE && window->mouse_focus!=window->key_focus && p_event.mouse_button.button_index==BUTTON_LEFT) {
- // also get keyboard focus
- window->mouse_focus->grab_focus();
- }
-
-
- if (window->mouse_focus->can_process()) {
- _window_call_input(window->mouse_focus,p_event);
- }
-
- get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID);
- get_tree()->set_input_as_handled();
-
- window->tooltip_popup->hide();
-
- } else {
-
- if (window->drag_preview && p_event.mouse_button.button_index==BUTTON_LEFT) {
- memdelete( window->drag_preview );
- window->drag_preview=NULL;
- }
-
- if (!window->mouse_focus) {
-
- if (window->mouse_over && window->drag_data.get_type()!=Variant::NIL && p_event.mouse_button.button_index==BUTTON_LEFT) {
-
- Size2 pos = mpos;
- pos = window->focus_inv_xform.xform(pos);
- window->mouse_over->drop_data(pos,window->drag_data);
- window->drag_data=Variant();
- //change mouse accordingly
- }
-
- break;
- }
-
- Size2 pos = mpos;
- p_event.mouse_button.global_x = pos.x;
- p_event.mouse_button.global_y = pos.y;
- pos = window->focus_inv_xform.xform(pos);
- p_event.mouse_button.x = pos.x;
- p_event.mouse_button.y = pos.y;
-
- if (window->mouse_focus->can_process()) {
- _window_call_input(window->mouse_focus,p_event);
- }
-
- if (p_event.mouse_button.button_index==window->mouse_focus_button) {
- window->mouse_focus=NULL;
- window->mouse_focus_button=-1;
- }
-
- if (window->drag_data.get_type()!=Variant::NIL && p_event.mouse_button.button_index==BUTTON_LEFT) {
- window->drag_data=Variant(); //always clear
- }
-
-
- get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID);
- get_tree()->set_input_as_handled();
-
- }
- } break;
- case InputEvent::MOUSE_MOTION: {
-
- window->key_event_accepted=false;
-
- Matrix32 localizer = (get_canvas_transform()).affine_inverse();
- Size2 pos = localizer.xform(Size2(p_event.mouse_motion.x,p_event.mouse_motion.y));
- Vector2 speed = localizer.basis_xform(Point2(p_event.mouse_motion.speed_x,p_event.mouse_motion.speed_y));
- Vector2 rel = localizer.basis_xform(Point2(p_event.mouse_motion.relative_x,p_event.mouse_motion.relative_y));
-
- window->last_mouse_pos=pos;
-
- Control *over = NULL;
-
- Matrix32 parent_xform;
- if (data.parent_canvas_item)
- parent_xform=data.parent_canvas_item->get_global_transform();
-
- // D&D
- if (!window->drag_attempted && window->mouse_focus && p_event.mouse_motion.button_mask&BUTTON_MASK_LEFT) {
-
- window->drag_accum+=rel;
- float len = window->drag_accum.length();
- if (len>10) {
- window->drag_data=window->mouse_focus->get_drag_data(window->focus_inv_xform.xform(pos)-window->drag_accum);
- if (window->drag_data.get_type()!=Variant::NIL) {
-
- window->mouse_focus=NULL;
- }
- window->drag_attempted=true;
- }
- }
-
-
- if (window->mouse_focus) {
- over=window->mouse_focus;
- //recompute focus_inv_xform again here
-
- } else {
-
- over = _find_control_at_pos(this,pos,parent_xform,window->focus_inv_xform);
- }
-
-
- if (window->drag_data.get_type()==Variant::NIL && over && !window->modal_stack.empty()) {
-
- Control *top = window->modal_stack.back()->get();
- if (over!=top && !top->is_a_parent_of(over)) {
-
- break; // don't send motion event to anything below modal stack top
- }
- }
-
- if (over!=window->mouse_over) {
-
- if (window->mouse_over)
- window->mouse_over->notification(NOTIFICATION_MOUSE_EXIT);
-
- if (over)
- over->notification(NOTIFICATION_MOUSE_ENTER);
-
- }
-
- window->mouse_over=over;
-
- get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_cancel_tooltip");
-
- if (window->drag_preview) {
- window->drag_preview->set_pos(pos);
- }
-
- if (!over) {
- OS::get_singleton()->set_cursor_shape(OS::CURSOR_ARROW);
- break;
- }
-
- p_event.mouse_motion.global_x = pos.x;
- p_event.mouse_motion.global_y = pos.y;
- p_event.mouse_motion.speed_x=speed.x;
- p_event.mouse_motion.speed_y=speed.y;
- p_event.mouse_motion.relative_x=rel.x;
- p_event.mouse_motion.relative_y=rel.y;
-
- if (p_event.mouse_motion.button_mask==0 && window->tooltip_timer) {
- //nothing pressed
-
- bool can_tooltip=true;
-
- if (!window->modal_stack.empty()) {
- if (window->modal_stack.back()->get()!=over && !window->modal_stack.back()->get()->is_a_parent_of(over))
- can_tooltip=false;
-
- }
-
-
- if (can_tooltip) {
-
- window->tooltip=over;
- window->tooltip_pos=(parent_xform * get_transform()).affine_inverse().xform(pos);
- window->tooltip_timer->start();
- }
- }
-
-
- pos = window->focus_inv_xform.xform(pos);
-
-
- p_event.mouse_motion.x = pos.x;
- p_event.mouse_motion.y = pos.y;
-
-
- CursorShape cursor_shape = over->get_cursor_shape(pos);
- OS::get_singleton()->set_cursor_shape( (OS::CursorShape)cursor_shape );
-
-
- if (over->can_process()) {
- _window_call_input(over,p_event);
- }
-
-
-
- get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID);
- get_tree()->set_input_as_handled();
-
-
- if (window->drag_data.get_type()!=Variant::NIL && p_event.mouse_motion.button_mask&BUTTON_MASK_LEFT) {
-
- /*bool can_drop =*/ over->can_drop_data(pos,window->drag_data);
- //change mouse accordingly i guess
- }
-
- } break;
- case InputEvent::ACTION:
- case InputEvent::JOYSTICK_BUTTON:
- case InputEvent::KEY: {
-
- if (window->key_focus) {
-
- window->key_event_accepted=false;
- if (window->key_focus->can_process()) {
- window->key_focus->call_multilevel("_input_event",p_event);
- if (window->key_focus) //maybe lost it
- window->key_focus->emit_signal(SceneStringNames::get_singleton()->input_event,p_event);
- }
-
-
- if (window->key_event_accepted) {
-
- get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID);
- break;
- }
- }
-
-
- if (p_event.is_pressed() && p_event.is_action("ui_cancel") && !window->modal_stack.empty()) {
-
- _window_sort_modal_stack();
- Control *top = window->modal_stack.back()->get();
- if (!top->data.modal_exclusive) {
-
- top->notification(NOTIFICATION_MODAL_CLOSE);
- top->_modal_stack_remove();
- top->hide();
- }
- }
-
-
- Control * from = window->key_focus ? window->key_focus : NULL; //hmm
-
- //keyboard focus
- //if (from && p_event.key.pressed && !p_event.key.mod.alt && !p_event.key.mod.meta && !p_event.key.mod.command) {
-
- if (from && p_event.is_pressed()) {
- Control * next=NULL;
-
- if (p_event.is_action("ui_focus_next")) {
-
- next = from->find_next_valid_focus();
- }
-
- if (p_event.is_action("ui_focus_prev")) {
-
- next = from->find_prev_valid_focus();
- }
-
- if (p_event.is_action("ui_up")) {
-
- next = from->_get_focus_neighbour(MARGIN_TOP);
- }
-
- if (p_event.is_action("ui_left")) {
-
- next = from->_get_focus_neighbour(MARGIN_LEFT);
- }
-
- if (p_event.is_action("ui_right")) {
-
- next = from->_get_focus_neighbour(MARGIN_RIGHT);
- }
-
- if (p_event.is_action("ui_down")) {
-
- next = from->_get_focus_neighbour(MARGIN_BOTTOM);
- }
-
-
- if (next) {
- next->grab_focus();
- get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID);
- }
- }
-
- } break;
- }
-}
-
-Control *Control::get_window() const {
-
- return data.window;
-}
-
-bool Control::is_window() const {
-
- return (is_inside_tree() && window);
-}
Size2 Control::get_minimum_size() const {
@@ -1372,6 +675,35 @@ Ref<Texture> Control::get_icon(const StringName& p_name,const StringName& p_type
}
+Ref<Shader> Control::get_shader(const StringName& p_name,const StringName& p_type) const {
+ if (p_type==StringName()) {
+
+ const Ref<Shader>* sdr = data.shader_override.getptr(p_name);
+ if (sdr)
+ return *sdr;
+ }
+
+ StringName type = p_type?p_type:get_type_name();
+
+ // try with custom themes
+ Control *theme_owner = data.theme_owner;
+
+ while(theme_owner) {
+
+ if (theme_owner->data.theme->has_shader(p_name, type))
+ return data.theme_owner->data.theme->get_shader(p_name, type );
+ Control *parent = theme_owner->get_parent()?theme_owner->get_parent()->cast_to<Control>():NULL;
+
+ if (parent)
+ theme_owner=parent->data.theme_owner;
+ else
+ theme_owner=NULL;
+
+ }
+
+ return Theme::get_default()->get_shader( p_name, type );
+}
+
Ref<StyleBox> Control::get_stylebox(const StringName& p_name,const StringName& p_type) const {
if (p_type==StringName()) {
@@ -1518,7 +850,37 @@ bool Control::has_icon(const StringName& p_name,const StringName& p_type) const
}
return Theme::get_default()->has_icon( p_name, type );
+
+}
+bool Control::has_shader(const StringName &p_name, const StringName &p_type) const
+{
+ if (p_type==StringName()) {
+ const Ref<Shader>* sdr = data.shader_override.getptr(p_name);
+ if (sdr)
+ return true;
+ }
+
+ StringName type = p_type?p_type:get_type_name();
+
+ // try with custom themes
+ Control *theme_owner = data.theme_owner;
+
+ while(theme_owner) {
+
+ if (theme_owner->data.theme->has_shader(p_name, type))
+ return true;
+ Control *parent = theme_owner->get_parent()?theme_owner->get_parent()->cast_to<Control>():NULL;
+
+ if (parent)
+ theme_owner=parent->data.theme_owner;
+ else
+ theme_owner=NULL;
+
+ }
+
+ return Theme::get_default()->has_shader( p_name, type );
+
}
bool Control::has_stylebox(const StringName& p_name,const StringName& p_type) const {
@@ -1650,9 +1012,9 @@ Size2 Control::get_parent_area_size() const {
if (data.parent_canvas_item) {
parent_size=data.parent_canvas_item->get_item_rect().size;
- } else if (data.viewport) {
+ } else {
- parent_size=data.viewport->get_visible_rect().size;
+ parent_size=get_viewport()->get_visible_rect().size;
}
return parent_size;
@@ -1720,8 +1082,8 @@ float Control::_get_parent_range(int p_idx) const {
} if (data.parent_canvas_item) {
return data.parent_canvas_item->get_item_rect().size[p_idx&1];
- } else if (data.viewport) {
- return data.viewport->get_visible_rect().size[p_idx&1];
+ } else {
+ return get_viewport()->get_visible_rect().size[p_idx&1];
}
return 1.0;
@@ -1927,6 +1289,7 @@ void Control::set_size(const Size2& p_size) {
data.margin[3] = _s2a( y+h, data.anchor[3], ph );
_size_changed();
+
}
@@ -1946,10 +1309,9 @@ Rect2 Control::get_global_rect() const {
}
Rect2 Control::get_window_rect() const {
-
+ ERR_FAIL_COND_V(!is_inside_tree(),Rect2());
Rect2 gr = get_global_rect();
- if (data.viewport)
- gr.pos+=data.viewport->get_visible_rect().pos;
+ gr.pos+=get_viewport()->get_visible_rect().pos;
return gr;
}
@@ -1983,7 +1345,14 @@ void Control::add_icon_override(const StringName& p_name, const Ref<Texture>& p_
data.icon_override[p_name]=p_icon;
notification(NOTIFICATION_THEME_CHANGED);
update();
+
+}
+void Control::add_shader_override(const StringName &p_name, const Ref<Shader> &p_shader) {
+ ERR_FAIL_COND(p_shader.is_null());
+ data.shader_override[p_name]=p_shader;
+ notification(NOTIFICATION_THEME_CHANGED);
+ update();
}
void Control::add_style_override(const StringName& p_name, const Ref<StyleBox>& p_style) {
@@ -2091,7 +1460,17 @@ Control *Control::find_next_valid_focus() const {
}
if (!next_child) {
- next_child=get_window();
+
+ next_child=const_cast<Control*>(this);;
+ while(next_child) {
+
+ if (next_child->data.SI || next_child->data.RI)
+ break;
+ next_child=next_child->get_parent_control();
+
+ }
+
+
}
}
@@ -2209,128 +1588,69 @@ Control::FocusMode Control::get_focus_mode() const {
}
bool Control::has_focus() const {
- return (data.window && data.window->window->key_focus==this);
+ return is_inside_tree() && get_viewport()->_gui_control_has_focus(this);
}
void Control::grab_focus() {
ERR_FAIL_COND(!is_inside_tree());
- ERR_FAIL_COND(!data.window);
-
if (data.focus_mode==FOCUS_NONE)
return;
-
- //no need for change
- if (data.window->window->key_focus && data.window->window->key_focus==this)
- return;
-
- get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_window_remove_focus");
- data.window->window->key_focus=this;
- notification(NOTIFICATION_FOCUS_ENTER);
-#ifdef DEBUG_ENABLED
- if (GLOBAL_DEF("debug/print_clicked_control", false)) {
- print_line(String(get_path())+" - focus");
- };
-#endif
- update();
+
+ get_viewport()->_gui_control_grab_focus(this);
}
void Control::release_focus() {
ERR_FAIL_COND(!is_inside_tree());
- ERR_FAIL_COND(!data.window);
if (!has_focus())
return;
- get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_window_remove_focus");
- //data.window->window->key_focus=this;
- //notification(NOTIFICATION_FOCUS_ENTER);
+ get_viewport()->_gui_remove_focus();
update();
}
bool Control::is_toplevel_control() const {
- return is_inside_tree() && (!data.parent_canvas_item && !window && is_set_as_toplevel());
+ return is_inside_tree() && (!data.parent_canvas_item && !data.RI && is_set_as_toplevel());
}
void Control::show_modal(bool p_exclusive) {
ERR_FAIL_COND(!is_inside_tree());
- ERR_FAIL_COND(!data.SI && data.window!=this);
- ERR_FAIL_COND(!data.window);
+ ERR_FAIL_COND(!data.SI);
if (is_visible())
hide();
- ERR_FAIL_COND( data.MI );
+ ERR_FAIL_COND( data.MI!=NULL );
show();
raise();
-
- data.window->window->modal_stack.push_back(this);
- data.MI = data.window->window->modal_stack.back();
data.modal_exclusive=p_exclusive;
- if (data.window->window->key_focus)
- data.modal_prev_focus_owner = data.window->window->key_focus->get_instance_ID();
- else
- data.modal_prev_focus_owner=0;
+ data.MI=get_viewport()->_gui_show_modal(this);
}
-void Control::_window_sort_subwindows() {
-
- if (!window->subwindow_order_dirty)
- return;
-
-
- window->modal_stack.sort_custom<CComparator>();
- window->subwindows.sort_custom<CComparator>();
-
- window->subwindow_order_dirty=false;
-
-}
-
-void Control::_window_sort_modal_stack() {
-
- window->modal_stack.sort_custom<CComparator>();
+void Control::_modal_set_prev_focus_owner(ObjectID p_prev) {
+ data.modal_prev_focus_owner=p_prev;
}
void Control::_modal_stack_remove() {
- List<Control*>::Element *next=NULL; //transfer the focus stack to the next
-
-
- if (data.window && data.MI) {
-
- next = data.MI->next();
-
-
- data.window->window->modal_stack.erase(data.MI);
- data.MI=NULL;
- }
-
- if (data.modal_prev_focus_owner) {
+ ERR_FAIL_COND(!is_inside_tree());
- if (!next) { //top of stack
+ if (!data.MI)
+ return;
- Object *pfo = ObjectDB::get_instance(data.modal_prev_focus_owner);
- Control *pfoc = pfo->cast_to<Control>();
- if (!pfoc)
- return;
+ get_viewport()->_gui_remove_from_modal_stack(data.MI,data.modal_prev_focus_owner);
- if (!pfoc->is_inside_tree() || !pfoc->is_visible())
- return;
- pfoc->grab_focus();
- } else {
-
- next->get()->data.modal_prev_focus_owner=data.modal_prev_focus_owner;
- }
+ data.MI=NULL;
+ data.modal_prev_focus_owner=0;
- data.modal_prev_focus_owner=0;
- }
}
void Control::_propagate_theme_changed(Control *p_owner) {
@@ -2368,17 +1688,11 @@ void Control::set_theme(const Ref<Theme>& p_theme) {
}
-void Control::_window_accept_event() {
+void Control::accept_event() {
- window->key_event_accepted=true;
if (is_inside_tree())
- get_tree()->set_input_as_handled();
+ get_viewport()->_gui_accept_event();
-}
-void Control::accept_event() {
-
- if (is_inside_tree() && get_window())
- get_window()->_window_accept_event();
}
@@ -2412,9 +1726,9 @@ Control::CursorShape Control::get_cursor_shape(const Point2& p_pos) const {
Matrix32 Control::get_transform() const {
- Matrix32 xf;
- xf.set_origin(get_pos());
- return xf;
+ Matrix32 xform=Matrix32(data.rotation,get_pos());
+ xform.scale_basis(data.scale);
+ return xform;
}
String Control::_get_tooltip() const {
@@ -2507,7 +1821,7 @@ Control *Control::_get_focus_neighbour(Margin p_margin,int p_count) {
if (c) {
if (c->data.SI)
break;
- if (c==data.window)
+ if (c->data.RI)
break;
}
base=base->get_parent();
@@ -2626,35 +1940,8 @@ void Control::grab_click_focus() {
ERR_FAIL_COND(!is_inside_tree());
- if (data.window && data.window->window->mouse_focus) {
-
- Window *w=data.window->window;
- if (w->mouse_focus==this)
- return;
- InputEvent ie;
- ie.type=InputEvent::MOUSE_BUTTON;
- InputEventMouseButton &mb=ie.mouse_button;
-
- //send unclic
-
- Point2 click =w->mouse_focus->get_global_transform().affine_inverse().xform(w->last_mouse_pos);
- mb.x=click.x;
- mb.y=click.y;
- mb.button_index=w->mouse_focus_button;
- mb.pressed=false;
- w->mouse_focus->call_deferred("_input_event",ie);
-
-
- w->mouse_focus=this;
- w->focus_inv_xform=w->mouse_focus->get_global_transform().affine_inverse();
- click =w->mouse_focus->get_global_transform().affine_inverse().xform(w->last_mouse_pos);
- mb.x=click.x;
- mb.y=click.y;
- mb.button_index=w->mouse_focus_button;
- mb.pressed=true;
- w->mouse_focus->call_deferred("_input_event",ie);
+ get_viewport()->_gui_grab_click_focus(this);
- }
}
void Control::minimum_size_changed() {
@@ -2703,8 +1990,7 @@ bool Control::is_stopping_mouse() const {
Control *Control::get_focus_owner() const {
ERR_FAIL_COND_V(!is_inside_tree(),NULL);
- ERR_FAIL_COND_V(!data.window,NULL);
- return data.window->window->key_focus;
+ return get_viewport()->_gui_get_focus_owner();
}
@@ -2713,24 +1999,64 @@ void Control::warp_mouse(const Point2& p_to_pos) {
get_viewport()->warp_mouse(get_global_transform().xform(p_to_pos));
}
+
+bool Control::is_text_field() const {
+/*
+ if (get_script_instance()) {
+ Variant v=p_point;
+ const Variant *p[2]={&v,&p_data};
+ Variant::CallError ce;
+ Variant ret = get_script_instance()->call("is_text_field",p,2,ce);
+ if (ce.error==Variant::CallError::CALL_OK)
+ return ret;
+ }
+ */
+ return false;
+}
+
+
+void Control::_set_rotation_deg(float p_rot) {
+ set_rotation(Math::deg2rad(p_rot));
+}
+
+float Control::_get_rotation_deg() const {
+ return Math::rad2deg(get_rotation());
+}
+
+void Control::set_rotation(float p_rotation) {
+
+ data.rotation=p_rotation;
+ update();
+ _notify_transform();
+}
+
+float Control::get_rotation() const{
+
+ return data.rotation;
+}
+
+void Control::set_scale(const Vector2& p_scale){
+
+ data.scale=p_scale;
+ update();
+ _notify_transform();
+}
+Vector2 Control::get_scale() const{
+
+ return data.scale;
+}
+
+
void Control::_bind_methods() {
- ObjectTypeDB::bind_method(_MD("_window_input_event"),&Control::_window_input_event);
- ObjectTypeDB::bind_method(_MD("_gui_input"),&Control::_gui_input);
- ObjectTypeDB::bind_method(_MD("_input_text"),&Control::_input_text);
+
// ObjectTypeDB::bind_method(_MD("_window_resize_event"),&Control::_window_resize_event);
- ObjectTypeDB::bind_method(_MD("_window_remove_focus"),&Control::_window_remove_focus);
- ObjectTypeDB::bind_method(_MD("_cancel_input_ID"),&Control::_window_cancel_input_ID);
- ObjectTypeDB::bind_method(_MD("_cancel_tooltip"),&Control::_window_cancel_tooltip);
- ObjectTypeDB::bind_method(_MD("_window_show_tooltip"),&Control::_window_show_tooltip);
ObjectTypeDB::bind_method(_MD("_size_changed"),&Control::_size_changed);
ObjectTypeDB::bind_method(_MD("_update_minimum_size"),&Control::_update_minimum_size);
ObjectTypeDB::bind_method(_MD("accept_event"),&Control::accept_event);
ObjectTypeDB::bind_method(_MD("get_minimum_size"),&Control::get_minimum_size);
ObjectTypeDB::bind_method(_MD("get_combined_minimum_size"),&Control::get_combined_minimum_size);
- ObjectTypeDB::bind_method(_MD("is_window"),&Control::is_window);
- ObjectTypeDB::bind_method(_MD("get_window"),&Control::get_window);
ObjectTypeDB::bind_method(_MD("set_anchor","margin","anchor_mode"),&Control::set_anchor);
ObjectTypeDB::bind_method(_MD("get_anchor","margin"),&Control::get_anchor);
ObjectTypeDB::bind_method(_MD("set_margin","margin","offset"),&Control::set_margin);
@@ -2741,15 +2067,21 @@ void Control::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_size","size"),&Control::set_size);
ObjectTypeDB::bind_method(_MD("set_custom_minimum_size","size"),&Control::set_custom_minimum_size);
ObjectTypeDB::bind_method(_MD("set_global_pos","pos"),&Control::set_global_pos);
+ ObjectTypeDB::bind_method(_MD("set_rotation","rotation"),&Control::set_rotation);
+ ObjectTypeDB::bind_method(_MD("_set_rotation_deg","rotation"),&Control::_set_rotation_deg);
+ ObjectTypeDB::bind_method(_MD("set_scale","scale"),&Control::set_scale);
ObjectTypeDB::bind_method(_MD("get_margin","margin"),&Control::get_margin);
ObjectTypeDB::bind_method(_MD("get_begin"),&Control::get_begin);
ObjectTypeDB::bind_method(_MD("get_end"),&Control::get_end);
ObjectTypeDB::bind_method(_MD("get_pos"),&Control::get_pos);
ObjectTypeDB::bind_method(_MD("get_size"),&Control::get_size);
+ ObjectTypeDB::bind_method(_MD("get_rotation"),&Control::get_rotation);
+ ObjectTypeDB::bind_method(_MD("get_scale"),&Control::get_scale);
ObjectTypeDB::bind_method(_MD("get_custom_minimum_size"),&Control::get_custom_minimum_size);
ObjectTypeDB::bind_method(_MD("get_parent_area_size"),&Control::get_size);
ObjectTypeDB::bind_method(_MD("get_global_pos"),&Control::get_global_pos);
ObjectTypeDB::bind_method(_MD("get_rect"),&Control::get_rect);
+ ObjectTypeDB::bind_method(_MD("_get_rotation_deg"),&Control::_get_rotation_deg);
ObjectTypeDB::bind_method(_MD("get_global_rect"),&Control::get_global_rect);
ObjectTypeDB::bind_method(_MD("set_area_as_parent_rect","margin"),&Control::set_area_as_parent_rect,DEFVAL(0));
ObjectTypeDB::bind_method(_MD("show_modal","exclusive"),&Control::show_modal,DEFVAL(false));
@@ -2770,8 +2102,9 @@ void Control::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_theme","theme:Theme"),&Control::set_theme);
ObjectTypeDB::bind_method(_MD("get_theme:Theme"),&Control::get_theme);
-
+
ObjectTypeDB::bind_method(_MD("add_icon_override","name","texture:Texture"),&Control::add_icon_override);
+ ObjectTypeDB::bind_method(_MD("add_shader_override","name","shader:Shader"),&Control::add_shader_override);
ObjectTypeDB::bind_method(_MD("add_style_override","name","stylebox:StyleBox"),&Control::add_style_override);
ObjectTypeDB::bind_method(_MD("add_font_override","name","font:Font"),&Control::add_font_override);
ObjectTypeDB::bind_method(_MD("add_color_override","name","color"),&Control::add_color_override);
@@ -2831,17 +2164,19 @@ void Control::_bind_methods() {
ADD_PROPERTYNZ( PropertyInfo(Variant::VECTOR2,"rect/pos", PROPERTY_HINT_NONE, "",PROPERTY_USAGE_EDITOR), _SCS("set_pos"),_SCS("get_pos") );
ADD_PROPERTYNZ( PropertyInfo(Variant::VECTOR2,"rect/size", PROPERTY_HINT_NONE, "",PROPERTY_USAGE_EDITOR), _SCS("set_size"),_SCS("get_size") );
ADD_PROPERTYNZ( PropertyInfo(Variant::VECTOR2,"rect/min_size"), _SCS("set_custom_minimum_size"),_SCS("get_custom_minimum_size") );
+ ADD_PROPERTYNZ( PropertyInfo(Variant::REAL,"rect/rotation",PROPERTY_HINT_RANGE,"-1080,1080,0.01"), _SCS("_set_rotation_deg"),_SCS("_get_rotation_deg") );
+ ADD_PROPERTYNO( PropertyInfo(Variant::VECTOR2,"rect/scale"), _SCS("set_scale"),_SCS("get_scale") );
ADD_PROPERTYNZ( PropertyInfo(Variant::STRING,"hint/tooltip", PROPERTY_HINT_MULTILINE_TEXT), _SCS("set_tooltip"),_SCS("_get_tooltip") );
- ADD_PROPERTYI( PropertyInfo(Variant::NODE_PATH,"focus_neighbour/left" ), _SCS("set_focus_neighbour"),_SCS("get_focus_neighbour"),MARGIN_LEFT );
- ADD_PROPERTYI( PropertyInfo(Variant::NODE_PATH,"focus_neighbour/top" ), _SCS("set_focus_neighbour"),_SCS("get_focus_neighbour"),MARGIN_TOP );
- ADD_PROPERTYI( PropertyInfo(Variant::NODE_PATH,"focus_neighbour/right" ), _SCS("set_focus_neighbour"),_SCS("get_focus_neighbour"),MARGIN_RIGHT );
- ADD_PROPERTYI( PropertyInfo(Variant::NODE_PATH,"focus_neighbour/bottom" ), _SCS("set_focus_neighbour"),_SCS("get_focus_neighbour"),MARGIN_BOTTOM );
+ ADD_PROPERTYINZ( PropertyInfo(Variant::NODE_PATH,"focus_neighbour/left" ), _SCS("set_focus_neighbour"),_SCS("get_focus_neighbour"),MARGIN_LEFT );
+ ADD_PROPERTYINZ( PropertyInfo(Variant::NODE_PATH,"focus_neighbour/top" ), _SCS("set_focus_neighbour"),_SCS("get_focus_neighbour"),MARGIN_TOP );
+ ADD_PROPERTYINZ( PropertyInfo(Variant::NODE_PATH,"focus_neighbour/right" ), _SCS("set_focus_neighbour"),_SCS("get_focus_neighbour"),MARGIN_RIGHT );
+ ADD_PROPERTYINZ( PropertyInfo(Variant::NODE_PATH,"focus_neighbour/bottom" ), _SCS("set_focus_neighbour"),_SCS("get_focus_neighbour"),MARGIN_BOTTOM );
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"focus/ignore_mouse"), _SCS("set_ignore_mouse"),_SCS("is_ignoring_mouse") );
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"focus/stop_mouse"), _SCS("set_stop_mouse"),_SCS("is_stopping_mouse") );
ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"size_flags/horizontal", PROPERTY_HINT_FLAGS, "Expand,Fill"), _SCS("set_h_size_flags"),_SCS("get_h_size_flags") );
ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"size_flags/vertical", PROPERTY_HINT_FLAGS, "Expand,Fill"), _SCS("set_v_size_flags"),_SCS("get_v_size_flags") );
- ADD_PROPERTY( PropertyInfo(Variant::INT,"size_flags/stretch_ratio", PROPERTY_HINT_RANGE, "1,128,0.01"), _SCS("set_stretch_ratio"),_SCS("get_stretch_ratio") );
+ ADD_PROPERTYNO( PropertyInfo(Variant::INT,"size_flags/stretch_ratio", PROPERTY_HINT_RANGE, "1,128,0.01"), _SCS("set_stretch_ratio"),_SCS("get_stretch_ratio") );
ADD_PROPERTYNZ( PropertyInfo(Variant::OBJECT,"theme/theme", PROPERTY_HINT_RESOURCE_TYPE, "Theme"), _SCS("set_theme"),_SCS("get_theme") );
BIND_CONSTANT( ANCHOR_BEGIN );
@@ -2896,15 +2231,15 @@ void Control::_bind_methods() {
}
Control::Control() {
- data.parent=NULL;
- data.window=NULL;
- data.viewport=NULL;
+ data.parent=NULL;
+
data.ignore_mouse=false;
data.stop_mouse=true;
- window=NULL;
+
data.SI=NULL;
data.MI=NULL;
+ data.RI=NULL;
data.modal=false;
data.theme_owner=NULL;
data.modal_exclusive=false;
@@ -2913,6 +2248,9 @@ Control::Control() {
data.v_size_flags=SIZE_FILL;
data.expand=1;
data.pending_min_size_update=false;
+ data.rotation=0;
+ data.parent_canvas_item=NULL;
+ data.scale=Vector2(1,1);
for (int i=0;i<4;i++) {
diff --git a/scene/gui/control.h b/scene/gui/control.h
index a759fafbc9..ab777a6a6c 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -107,7 +107,10 @@ private:
float margin[4];
AnchorType anchor[4];
- FocusMode focus_mode;
+ FocusMode focus_mode;
+
+ float rotation;
+ Vector2 scale;
bool pending_resize;
@@ -121,7 +124,6 @@ private:
bool stop_mouse;
Control *parent;
- Control *window;
bool modal;
bool modal_exclusive;
Ref<Theme> theme;
@@ -131,91 +133,55 @@ private:
List<Control*>::Element *MI; //modal item
List<Control*>::Element *SI;
+ List<Control*>::Element *RI;
CanvasItem *parent_canvas_item;
- Viewport *viewport;
-
ObjectID modal_prev_focus_owner;
NodePath focus_neighbour[4];
HashMap<StringName, Ref<Texture>, StringNameHasher > icon_override;
+ HashMap<StringName, Ref<Shader>, StringNameHasher > shader_override;
HashMap<StringName, Ref<StyleBox>, StringNameHasher > style_override;
HashMap<StringName, Ref<Font>, StringNameHasher > font_override;
HashMap<StringName, Color, StringNameHasher > color_override;
HashMap<StringName, int, StringNameHasher > constant_override;
} data;
-
- struct Window {
- // info used when this is a window
-
- bool key_event_accepted;
- Control *mouse_focus;
- int mouse_focus_button;
- Control *key_focus;
- Control *mouse_over;
- Control *tooltip;
- Panel *tooltip_popup;
- Label *tooltip_label;
- Point2 tooltip_pos;
- Point2 last_mouse_pos;
- Point2 drag_accum;
- bool drag_attempted;
- Variant drag_data;
- Control *drag_preview;
- Timer *tooltip_timer;
- List<Control*> modal_stack;
- unsigned int cancelled_input_ID;
- Matrix32 focus_inv_xform;
- bool subwindow_order_dirty;
- List<Control*> subwindows;
- bool disable_input;
-
- Window();
- };
-
- Window *window;
-
+
// used internally
- Control* _find_next_visible_control_at_pos(Node* p_node,const Point2& p_global,Matrix32& r_xform) const;
Control* _find_control_at_pos(CanvasItem* p_node,const Point2& p_pos,const Matrix32& p_xform,Matrix32& r_inv_xform);
- void _window_sort_subwindows();
- void _window_accept_event();
- void _window_remove_focus();
- void _window_cancel_input_ID(int p_input);
- void _window_sort_modal_stack();
void _window_find_focus_neighbour(const Vector2& p_dir, Node *p_at, const Point2* p_points ,float p_min,float &r_closest_dist,Control **r_closest);
Control *_get_focus_neighbour(Margin p_margin,int p_count=0);
- void _window_call_input(Control *p_control,const InputEvent& p_input);
+
float _get_parent_range(int p_idx) const;
float _get_range(int p_idx) const;
float _s2a(float p_val, AnchorType p_anchor,float p_range) const;
float _a2s(float p_val, AnchorType p_anchor,float p_range) const;
- void _modal_stack_remove();
void _propagate_theme_changed(Control *p_owner);
void _change_notify_margins();
- void _window_cancel_tooltip();
- void _window_show_tooltip();
void _update_minimum_size();
void _update_scroll();
- void _gui_input(const InputEvent& p_event); //used by scene main loop
- void _input_text(const String& p_text);
void _resize(const Size2& p_size);
void _size_changed();
String _get_tooltip() const;
+ void _set_rotation_deg(float p_rot);
+ float _get_rotation_deg() const;
+
+friend class Viewport;
+ void _modal_stack_remove();
+ void _modal_set_prev_focus_owner(ObjectID p_prev);
protected:
- bool window_has_modal_stack() const;
- virtual void _window_input_event(InputEvent p_event);
+ //virtual void _window_input_event(InputEvent p_event);
bool _set(const StringName& p_name, const Variant& p_value);
bool _get(const StringName& p_name,Variant &r_ret) const;
@@ -265,8 +231,8 @@ public:
void set_custom_minimum_size(const Size2& p_custom);
Size2 get_custom_minimum_size() const;
- bool is_window() const;
- Control *get_window() const;
+ bool is_window_modal_on_top() const;
+
Control *get_parent_control() const;
@@ -299,6 +265,13 @@ public:
Rect2 get_rect() const;
Rect2 get_global_rect() const;
Rect2 get_window_rect() const; ///< use with care, as it blocks waiting for the visual server
+
+ void set_rotation(float p_rotation);
+ float get_rotation() const;
+
+ void set_scale(const Vector2& p_scale);
+ Vector2 get_scale() const;
+
void set_area_as_parent_rect(int p_margin=0);
@@ -343,18 +316,21 @@ public:
/* SKINNING */
void add_icon_override(const StringName& p_name, const Ref<Texture>& p_icon);
+ void add_shader_override(const StringName& p_name, const Ref<Shader>& p_shader);
void add_style_override(const StringName& p_name, const Ref<StyleBox>& p_style);
void add_font_override(const StringName& p_name, const Ref<Font>& p_font);
void add_color_override(const StringName& p_name, const Color& p_color);
void add_constant_override(const StringName& p_name, int p_constant);
Ref<Texture> get_icon(const StringName& p_name,const StringName& p_type=StringName()) const;
+ Ref<Shader> get_shader(const StringName &p_name, const StringName &p_type=StringName()) const;
Ref<StyleBox> get_stylebox(const StringName& p_name,const StringName& p_type=StringName()) const;
Ref<Font> get_font(const StringName& p_name,const StringName& p_type=StringName()) const;
Color get_color(const StringName& p_name,const StringName& p_type=StringName()) const;
int get_constant(const StringName& p_name,const StringName& p_type=StringName()) const;
bool has_icon(const StringName& p_name,const StringName& p_type=StringName()) const;
+ bool has_shader(const StringName& p_name,const StringName& p_type=StringName()) const;
bool has_stylebox(const StringName& p_name,const StringName& p_type=StringName()) const;
bool has_font(const StringName& p_name,const StringName& p_type=StringName()) const;
bool has_color(const StringName& p_name,const StringName& p_type=StringName()) const;
@@ -382,9 +358,11 @@ public:
void warp_mouse(const Point2& p_to_pos);
+ virtual bool is_text_field() const;
+
Control();
~Control();
-
+
};
VARIANT_ENUM_CAST(Control::AnchorType);
diff --git a/scene/gui/custom_button.cpp b/scene/gui/custom_button.cpp
index 53a3bf0914..a70af05418 100644
--- a/scene/gui/custom_button.cpp
+++ b/scene/gui/custom_button.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/custom_button.h b/scene/gui/custom_button.h
index 49fcf7408f..2492750489 100644
--- a/scene/gui/custom_button.h
+++ b/scene/gui/custom_button.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index 3ddf23fc4a..9f08b6f845 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -274,7 +274,7 @@ Button* AcceptDialog::add_button(const String& p_text,bool p_right,const String&
}
if (p_action!="") {
- button->connect("pressed",this,"_custom_action",make_binds(p_action));
+ button->connect("pressed",this,"_custom_action",varray(p_action));
}
return button;
@@ -308,7 +308,9 @@ void AcceptDialog::_bind_methods() {
ADD_SIGNAL( MethodInfo("confirmed") );
ADD_SIGNAL( MethodInfo("custom_action",PropertyInfo(Variant::STRING,"action")) );
-
+ ADD_PROPERTYNZ( PropertyInfo(Variant::STRING,"dialog/text",PROPERTY_HINT_MULTILINE_TEXT,"",PROPERTY_USAGE_DEFAULT_INTL),_SCS("set_text"),_SCS("get_text"));
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL, "dialog/hide_on_ok"),_SCS("set_hide_on_ok"),_SCS("get_hide_on_ok") );
+
}
diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h
index 67c574a420..7c06ded866 100644
--- a/scene/gui/dialogs.h
+++ b/scene/gui/dialogs.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index 8e428fd71c..56b9260837 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -46,12 +46,56 @@ VBoxContainer *FileDialog::get_vbox() {
}
void FileDialog::_notification(int p_what) {
+
+ if (p_what==NOTIFICATION_ENTER_TREE) {
+
+ refresh->set_icon(get_icon("reload"));
+ }
if (p_what==NOTIFICATION_DRAW) {
//RID ci = get_canvas_item();
//get_stylebox("panel","PopupMenu")->draw(ci,Rect2(Point2(),get_size()));
- }
+ }
+
+ if (p_what==NOTIFICATION_POPUP_HIDE) {
+
+ set_process_unhandled_input(false);
+ }
+}
+
+void FileDialog::_unhandled_input(const InputEvent& p_event) {
+
+ if (p_event.type==InputEvent::KEY && is_window_modal_on_top()) {
+
+ const InputEventKey &k=p_event.key;
+
+ if (k.pressed) {
+
+ bool handled=true;
+
+ switch (k.scancode) {
+
+ case KEY_H: {
+
+ if (k.mod.command) {
+ set_show_hidden_files(!show_hidden_files);
+ } else {
+ handled=false;
+ }
+
+ } break;
+ case KEY_F5: {
+
+ invalidate();
+ } break;
+ default: { handled=false; }
+ }
+
+ if (handled)
+ accept_event();
+ }
+ }
}
void FileDialog::set_enable_multiple_selection(bool p_enable) {
@@ -109,6 +153,8 @@ void FileDialog::_post_popup() {
else
tree->grab_focus();
+ set_process_unhandled_input(true);
+
}
void FileDialog::_action_pressed() {
@@ -618,11 +664,13 @@ void FileDialog::_update_drives() {
}
}
-bool FileDialog::default_show_hidden_files=true;
+bool FileDialog::default_show_hidden_files=false;
void FileDialog::_bind_methods() {
+ ObjectTypeDB::bind_method(_MD("_unhandled_input"),&FileDialog::_unhandled_input);
+
ObjectTypeDB::bind_method(_MD("_tree_selected"),&FileDialog::_tree_selected);
ObjectTypeDB::bind_method(_MD("_tree_db_selected"),&FileDialog::_tree_dc_selected);
ObjectTypeDB::bind_method(_MD("_dir_entered"),&FileDialog::_dir_entered);
@@ -645,7 +693,7 @@ void FileDialog::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_vbox:VBoxContainer"),&FileDialog::get_vbox);
ObjectTypeDB::bind_method(_MD("set_access","access"),&FileDialog::set_access);
ObjectTypeDB::bind_method(_MD("get_access"),&FileDialog::get_access);
- ObjectTypeDB::bind_method(_MD("set_show_hidden_files"),&FileDialog::set_show_hidden_files);
+ ObjectTypeDB::bind_method(_MD("set_show_hidden_files","show"),&FileDialog::set_show_hidden_files);
ObjectTypeDB::bind_method(_MD("is_showing_hidden_files"),&FileDialog::is_showing_hidden_files);
ObjectTypeDB::bind_method(_MD("_select_drive"),&FileDialog::_select_drive);
ObjectTypeDB::bind_method(_MD("_make_dir"),&FileDialog::_make_dir);
@@ -700,6 +748,10 @@ FileDialog::FileDialog() {
pathhb->add_child(dir);
dir->set_h_size_flags(SIZE_EXPAND_FILL);
+ refresh = memnew( ToolButton );
+ refresh->connect("pressed",this,"_update_file_list");
+ pathhb->add_child(refresh);
+
drives = memnew( OptionButton );
pathhb->add_child(drives);
drives->connect("item_selected",this,"_select_drive");
diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h
index ec42c7744a..b71a157fa7 100644
--- a/scene/gui/file_dialog.h
+++ b/scene/gui/file_dialog.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,6 +34,7 @@
#include "scene/gui/line_edit.h"
#include "scene/gui/option_button.h"
#include "scene/gui/dialogs.h"
+#include "scene/gui/tool_button.h"
#include "os/dir_access.h"
#include "box_container.h"
/**
@@ -86,6 +87,8 @@ private:
OptionButton *filter;
DirAccess *dir_access;
ConfirmationDialog *confirm_save;
+
+ ToolButton *refresh;
Vector<String> filters;
@@ -114,6 +117,8 @@ private:
void _update_drives();
+ void _unhandled_input(const InputEvent& p_event);
+
virtual void _post_popup();
protected:
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 3cd0dd3d16..85f00f9d84 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -42,7 +42,6 @@ bool GraphEdit::is_node_connected(const StringName& p_from, int p_from_port,cons
void GraphEdit::disconnect_node(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port){
-
for(List<Connection>::Element *E=connections.front();E;E=E->next()) {
if (E->get().from==p_from && E->get().from_port==p_from_port && E->get().to==p_to && E->get().to_port==p_to_port) {
@@ -59,9 +58,12 @@ void GraphEdit::get_connection_list(List<Connection> *r_connections) const {
*r_connections=connections;
}
+Vector2 GraphEdit::get_scroll_ofs() const{
-void GraphEdit::_scroll_moved(double) {
+ return Vector2(h_scroll->get_val(),v_scroll->get_val());
+}
+void GraphEdit::_scroll_moved(double) {
_update_scroll_offset();
top_layer->update();
@@ -141,9 +143,6 @@ void GraphEdit::_graph_node_moved(Node *p_gn) {
GraphNode *gn=p_gn->cast_to<GraphNode>();
ERR_FAIL_COND(!gn);
-
- //gn->set_pos(gn->get_offset()+scroll_offset);
-
top_layer->update();
}
@@ -172,7 +171,6 @@ void GraphEdit::remove_child_notify(Node *p_child) {
void GraphEdit::_notification(int p_what) {
if (p_what==NOTIFICATION_READY) {
- Size2 size = top_layer->get_size();
Size2 hmin = h_scroll->get_combined_minimum_size();
Size2 vmin = v_scroll->get_combined_minimum_size();
@@ -491,7 +489,8 @@ void GraphEdit::_top_layer_draw() {
connections.erase(to_erase.front()->get());
to_erase.pop_front();
}
- //draw connections
+ if (box_selecting)
+ top_layer->draw_rect(box_selecting_rect,Color(0.7,0.7,1.0,0.3));
}
void GraphEdit::_input_event(const InputEvent& p_ev) {
@@ -500,6 +499,187 @@ void GraphEdit::_input_event(const InputEvent& p_ev) {
h_scroll->set_val( h_scroll->get_val() - p_ev.mouse_motion.relative_x );
v_scroll->set_val( v_scroll->get_val() - p_ev.mouse_motion.relative_y );
}
+
+ if (p_ev.type==InputEvent::MOUSE_MOTION && dragging) {
+
+ just_selected=true;
+ drag_accum+=Vector2(p_ev.mouse_motion.relative_x,p_ev.mouse_motion.relative_y);
+ for(int i=get_child_count()-1;i>=0;i--) {
+ GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+ if (gn && gn->is_selected())
+ gn->set_offset(gn->get_drag_from()+drag_accum);
+ }
+ }
+
+ if (p_ev.type==InputEvent::MOUSE_MOTION && box_selecting) {
+ box_selecting_to = get_local_mouse_pos();
+
+ box_selecting_rect = Rect2(MIN(box_selecting_from.x,box_selecting_to.x),
+ MIN(box_selecting_from.y,box_selecting_to.y),
+ ABS(box_selecting_from.x-box_selecting_to.x),
+ ABS(box_selecting_from.y-box_selecting_to.y));
+
+ for(int i=get_child_count()-1;i>=0;i--) {
+
+ GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+ if (!gn)
+ continue;
+
+ bool in_box = gn->get_rect().intersects(box_selecting_rect);
+
+ if (in_box)
+ gn->set_selected(box_selection_mode_aditive);
+ else
+ gn->set_selected(previus_selected.find(gn)!=NULL);
+ }
+
+ top_layer->update();
+ }
+
+ if (p_ev.type==InputEvent::MOUSE_BUTTON) {
+
+ const InputEventMouseButton &b=p_ev.mouse_button;
+
+ if (b.button_index==BUTTON_RIGHT && b.pressed)
+ {
+ if (box_selecting) {
+ box_selecting = false;
+ for(int i=get_child_count()-1;i>=0;i--) {
+
+ GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+ if (!gn)
+ continue;
+
+ gn->set_selected(previus_selected.find(gn)!=NULL);
+ }
+ top_layer->update();
+ } else {
+ emit_signal("popup_request", Vector2(b.global_x, b.global_y));
+ }
+ }
+
+ if (b.button_index==BUTTON_LEFT && !b.pressed && dragging) {
+ if (!just_selected && drag_accum==Vector2() && Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+ //deselect current node
+ for(int i=get_child_count()-1;i>=0;i--) {
+ GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+
+ if (gn && gn->get_rect().has_point(get_local_mouse_pos()))
+ gn->set_selected(false);
+ }
+ }
+
+ if (drag_accum!=Vector2()) {
+
+ emit_signal("_begin_node_move");
+
+ for(int i=get_child_count()-1;i>=0;i--) {
+ GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+ if (gn && gn->is_selected())
+ gn->set_drag(false);
+ }
+
+ emit_signal("_end_node_move");
+ }
+
+ dragging = false;
+
+ top_layer->update();
+ }
+
+ if (b.button_index==BUTTON_LEFT && b.pressed) {
+
+ GraphNode *gn;
+ for(int i=get_child_count()-1;i>=0;i--) {
+
+ gn=get_child(i)->cast_to<GraphNode>();
+
+ if (gn && gn->get_rect().has_point(get_local_mouse_pos()))
+ break;
+ }
+
+ if (gn) {
+
+ if (_filter_input(Vector2(b.x,b.y)))
+ return;
+
+ dragging = true;
+ drag_accum = Vector2();
+ just_selected = !gn->is_selected();
+ if(!gn->is_selected() && !Input::get_singleton()->is_key_pressed(KEY_CONTROL)) {
+ for (int i = 0; i < get_child_count(); i++) {
+ GraphNode *o_gn = get_child(i)->cast_to<GraphNode>();
+ if (o_gn)
+ o_gn->set_selected(o_gn == gn);
+ }
+ }
+
+ gn->set_selected(true);
+ for (int i = 0; i < get_child_count(); i++) {
+ GraphNode *o_gn = get_child(i)->cast_to<GraphNode>();
+ if (!o_gn)
+ continue;
+ if (o_gn->is_selected())
+ o_gn->set_drag(true);
+ }
+
+ } else {
+ box_selecting = true;
+ box_selecting_from = get_local_mouse_pos();
+ if (b.mod.control) {
+ box_selection_mode_aditive = true;
+ previus_selected.clear();
+ for(int i=get_child_count()-1;i>=0;i--) {
+
+ GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+ if (!gn || !gn->is_selected())
+ continue;
+
+ previus_selected.push_back(gn);
+ }
+ } else if (b.mod.shift) {
+ box_selection_mode_aditive = false;
+ previus_selected.clear();
+ for(int i=get_child_count()-1;i>=0;i--) {
+
+ GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+ if (!gn || !gn->is_selected())
+ continue;
+
+ previus_selected.push_back(gn);
+ }
+ } else {
+ box_selection_mode_aditive = true;
+ previus_selected.clear();
+ for(int i=get_child_count()-1;i>=0;i--) {
+
+ GraphNode *gn=get_child(i)->cast_to<GraphNode>();
+ if (!gn)
+ continue;
+
+ gn->set_selected(false);
+ }
+ }
+ }
+ }
+
+ if (b.button_index==BUTTON_LEFT && !b.pressed && box_selecting) {
+ box_selecting = false;
+ previus_selected.clear();
+ top_layer->update();
+ }
+ }
+
+ if (p_ev.type==InputEvent::KEY && p_ev.key.scancode==KEY_D && p_ev.key.pressed && p_ev.key.mod.command) {
+ emit_signal("duplicate_nodes_request");
+ accept_event();
+ }
+
+ if (p_ev.type==InputEvent::KEY && p_ev.key.scancode==KEY_DELETE && p_ev.key.pressed) {
+ emit_signal("delete_nodes_request");
+ accept_event();
+ }
+
}
void GraphEdit::clear_connections() {
@@ -540,6 +720,7 @@ void GraphEdit::_bind_methods() {
ObjectTypeDB::bind_method(_MD("is_node_connected","from","from_port","to","to_port"),&GraphEdit::is_node_connected);
ObjectTypeDB::bind_method(_MD("disconnect_node","from","from_port","to","to_port"),&GraphEdit::disconnect_node);
ObjectTypeDB::bind_method(_MD("get_connection_list"),&GraphEdit::_get_connection_list);
+ ObjectTypeDB::bind_method(_MD("get_scroll_ofs"),&GraphEdit::get_scroll_ofs);
ObjectTypeDB::bind_method(_MD("set_right_disconnects","enable"),&GraphEdit::set_right_disconnects);
ObjectTypeDB::bind_method(_MD("is_right_disconnects_enabled"),&GraphEdit::is_right_disconnects_enabled);
@@ -555,12 +736,18 @@ void GraphEdit::_bind_methods() {
ADD_SIGNAL(MethodInfo("connection_request",PropertyInfo(Variant::STRING,"from"),PropertyInfo(Variant::INT,"from_slot"),PropertyInfo(Variant::STRING,"to"),PropertyInfo(Variant::INT,"to_slot")));
ADD_SIGNAL(MethodInfo("disconnection_request",PropertyInfo(Variant::STRING,"from"),PropertyInfo(Variant::INT,"from_slot"),PropertyInfo(Variant::STRING,"to"),PropertyInfo(Variant::INT,"to_slot")));
-
+ ADD_SIGNAL(MethodInfo("popup_request", PropertyInfo(Variant::VECTOR2,"p_position")));
+ ADD_SIGNAL(MethodInfo("duplicate_nodes_request"));
+ ADD_SIGNAL(MethodInfo("delete_nodes_request"));
+ ADD_SIGNAL(MethodInfo("_begin_node_move"));
+ ADD_SIGNAL(MethodInfo("_end_node_move"));
}
GraphEdit::GraphEdit() {
+ set_focus_mode(FOCUS_ALL);
+
top_layer=NULL;
top_layer=memnew(GraphEditFilter(this));
add_child(top_layer);
@@ -581,6 +768,9 @@ GraphEdit::GraphEdit() {
connecting=false;
right_disconnects=false;
+ box_selecting = false;
+ dragging = false;
+
h_scroll->connect("value_changed", this,"_scroll_moved");
v_scroll->connect("value_changed", this,"_scroll_moved");
}
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index 0a9da73ab6..5e339e4e7e 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -10,7 +10,7 @@ class GraphEditFilter : public Control {
OBJ_TYPE(GraphEditFilter,Control);
-friend class GraphEdit;
+ friend class GraphEdit;
GraphEdit *ge;
virtual bool has_point(const Point2& p_point) const;
@@ -49,7 +49,16 @@ private:
String connecting_target_to;
int connecting_target_index;
+ bool dragging;
+ bool just_selected;
+ Vector2 drag_accum;
+ bool box_selecting;
+ bool box_selection_mode_aditive;
+ Point2 box_selecting_from;
+ Point2 box_selecting_to;
+ Rect2 box_selecting_rect;
+ List<GraphNode*> previus_selected;
bool right_disconnects;
bool updating;
@@ -71,7 +80,7 @@ private:
Array _get_connection_list() const;
-friend class GraphEditFilter;
+ friend class GraphEditFilter;
bool _filter_input(const Point2& p_point);
protected:
@@ -92,6 +101,8 @@ public:
void set_right_disconnects(bool p_enable);
bool is_right_disconnects_enabled() const;
+
+ Vector2 get_scroll_ofs() const;
GraphEdit();
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index 444b37855f..5efc9757b7 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -40,7 +40,7 @@ bool GraphNode::_get(const StringName& p_name,Variant &r_ret) const{
- if (!p_name.operator String().begins_with("slot/")) {
+ if (!p_name.operator String().begins_with("slot/")) {
return false;
}
@@ -160,7 +160,7 @@ void GraphNode::_notification(int p_what) {
if (p_what==NOTIFICATION_DRAW) {
- Ref<StyleBox> sb=get_stylebox("frame");
+ Ref<StyleBox> sb=get_stylebox(selected ? "selectedframe" : "frame");
Ref<Texture> port =get_icon("port");
Ref<Texture> close =get_icon("close");
int close_offset = get_constant("close_offset");
@@ -360,6 +360,29 @@ Vector2 GraphNode::get_offset() const {
return offset;
}
+void GraphNode::set_selected(bool p_selected)
+{
+ selected = p_selected;
+ update();
+}
+
+bool GraphNode::is_selected()
+{
+ return selected;
+}
+
+void GraphNode::set_drag(bool p_drag)
+{
+ if (p_drag)
+ drag_from=get_offset();
+ else
+ emit_signal("dragged",drag_from,get_offset()); //useful for undo/redo
+}
+
+Vector2 GraphNode::get_drag_from()
+{
+ return drag_from;
+}
void GraphNode::set_show_close_button(bool p_enable){
@@ -379,7 +402,6 @@ void GraphNode::_connpos_update() {
int sep=get_constant("separation");
Ref<StyleBox> sb=get_stylebox("frame");
- Ref<Texture> port =get_icon("port");
conn_input_cache.clear();
conn_output_cache.clear();
int vofs=0;
@@ -503,31 +525,17 @@ Color GraphNode::get_connection_output_color(int p_idx) {
void GraphNode::_input_event(const InputEvent& p_ev) {
- if (p_ev.type==InputEvent::MOUSE_BUTTON && p_ev.mouse_button.pressed && p_ev.mouse_button.button_index==BUTTON_LEFT) {
+ if (p_ev.type==InputEvent::MOUSE_BUTTON) {
+ get_parent_control()->grab_focus();
+ if(p_ev.mouse_button.pressed && p_ev.mouse_button.button_index==BUTTON_LEFT) {
- Vector2 mpos = Vector2(p_ev.mouse_button.x,p_ev.mouse_button.y);
- if (close_rect.size!=Size2() && close_rect.has_point(mpos)) {
- emit_signal("close_request");
- return;
+ Vector2 mpos = Vector2(p_ev.mouse_button.x,p_ev.mouse_button.y);
+ if (close_rect.size!=Size2() && close_rect.has_point(mpos)) {
+ emit_signal("close_request");
+ return;
+ }
+ emit_signal("raise_request");
}
-
- drag_from=get_offset();
- drag_accum=Vector2();
- dragging=true;
- emit_signal("raise_request");
-
- }
-
- if (p_ev.type==InputEvent::MOUSE_BUTTON && !p_ev.mouse_button.pressed && p_ev.mouse_button.button_index==BUTTON_LEFT) {
-
- dragging=false;
- emit_signal("dragged",drag_from,get_offset()); //useful for undo/redo
- }
-
- if (p_ev.type==InputEvent::MOUSE_MOTION && dragging) {
-
- drag_accum+=Vector2(p_ev.mouse_motion.relative_x,p_ev.mouse_motion.relative_y);
- set_offset(drag_from+drag_accum);
}
}
@@ -576,8 +584,6 @@ void GraphNode::_bind_methods() {
}
GraphNode::GraphNode() {
-
- dragging=false;
show_close=false;
connpos_dirty=true;
}
diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h
index 0d5cbf8dd3..201529380d 100644
--- a/scene/gui/graph_node.h
+++ b/scene/gui/graph_node.h
@@ -18,7 +18,7 @@ class GraphNode : public Container {
Color color_right;
- Slot() { enable_left=false; type_left=0; color_left=Color(1,1,1,1); enable_right=false; type_right=0; color_right=Color(1,1,1,1); };
+ Slot() { enable_left=false; type_left=0; color_left=Color(1,1,1,1); enable_right=false; type_right=0; color_right=Color(1,1,1,1); }
};
String title;
@@ -46,8 +46,7 @@ class GraphNode : public Container {
void _resort();
Vector2 drag_from;
- Vector2 drag_accum;
- bool dragging;
+ bool selected;
protected:
void _input_event(const InputEvent& p_ev);
@@ -79,6 +78,12 @@ public:
void set_offset(const Vector2& p_offset);
Vector2 get_offset() const;
+ void set_selected(bool p_selected);
+ bool is_selected();
+
+ void set_drag(bool p_drag);
+ Vector2 get_drag_from();
+
void set_show_close_button(bool p_enable);
bool is_close_button_visible() const;
diff --git a/scene/gui/grid_container.cpp b/scene/gui/grid_container.cpp
index 105f66f368..a514f1b3d7 100644
--- a/scene/gui/grid_container.cpp
+++ b/scene/gui/grid_container.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/grid_container.h b/scene/gui/grid_container.h
index 8d8bc27293..588bb17fa1 100644
--- a/scene/gui/grid_container.h
+++ b/scene/gui/grid_container.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index c29f6625d3..f035cb7722 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -187,6 +187,7 @@ void ItemList::select(int p_idx,bool p_single){
}
current=p_idx;
+ ensure_selected_visible=false;
} else {
if (items[p_idx].selectable) {
@@ -195,6 +196,7 @@ void ItemList::select(int p_idx,bool p_single){
}
update();
+
}
void ItemList::unselect(int p_idx){
@@ -233,6 +235,37 @@ int ItemList::get_current() const {
return current;
}
+void ItemList::move_item(int p_item,int p_to_pos) {
+
+ ERR_FAIL_INDEX(p_item,items.size());
+ ERR_FAIL_INDEX(p_to_pos,items.size()+1);
+
+ Item it=items[p_item];
+ items.remove(p_item);;
+
+ if (p_to_pos>p_item) {
+ p_to_pos--;
+ }
+
+ if (p_to_pos>=items.size()) {
+ items.push_back(it);
+ } else {
+ items.insert(p_to_pos,it);
+ }
+
+ if (current<0) {
+ //do none
+ } if (p_item==current) {
+ current=p_to_pos;
+ } else if (p_to_pos>p_item && current>p_item && current<p_to_pos) {
+ current--;
+ } else if (p_to_pos<p_item && current<p_item && current>p_to_pos) {
+ current++;
+ }
+
+
+ update();
+}
int ItemList::get_item_count() const{
@@ -246,12 +279,14 @@ void ItemList::remove_item(int p_idx){
update();
shape_changed=true;
+
}
void ItemList::clear(){
items.clear();
current=-1;
+ ensure_selected_visible=false;
update();
}
@@ -602,18 +637,8 @@ void ItemList::_input_event(const InputEvent& p_event) {
void ItemList::ensure_current_is_visible() {
- if (current>=0 && current <=items.size()) {
-
- Rect2 r = items[current].rect_cache;
- int from = scroll_bar->get_val();
- int to = from + scroll_bar->get_page();
-
- if (r.pos.y < from) {
- scroll_bar->set_val(r.pos.y);
- } else if (r.pos.y+r.size.y > to) {
- scroll_bar->set_val(r.pos.y+r.size.y - (to-from));
- }
- }
+ ensure_selected_visible=true;
+ update();
}
void ItemList::_notification(int p_what) {
@@ -928,6 +953,24 @@ void ItemList::_notification(int p_what) {
draw_line(Vector2(bg->get_margin(MARGIN_LEFT),base_ofs.y+separators[i]),Vector2(size.width-bg->get_margin(MARGIN_LEFT),base_ofs.y+separators[i]),guide_color);
}
+
+ if (ensure_selected_visible && current>=0 && current <=items.size()) {
+
+ Rect2 r = items[current].rect_cache;
+ int from = scroll_bar->get_val();
+ int to = from + scroll_bar->get_page();
+
+ if (r.pos.y < from) {
+ scroll_bar->set_val(r.pos.y);
+ } else if (r.pos.y+r.size.y > to) {
+ scroll_bar->set_val(r.pos.y+r.size.y - (to-from));
+ }
+
+
+ }
+
+ ensure_selected_visible=false;
+
}
}
@@ -1013,7 +1056,7 @@ void ItemList::_bind_methods(){
ObjectTypeDB::bind_method(_MD("get_item_text","idx"),&ItemList::get_item_text);
ObjectTypeDB::bind_method(_MD("set_item_icon","idx","icon:Texture"),&ItemList::set_item_icon);
- ObjectTypeDB::bind_method(_MD("get_item_icon:Tedture","idx"),&ItemList::get_item_icon);
+ ObjectTypeDB::bind_method(_MD("get_item_icon:Texture","idx"),&ItemList::get_item_icon);
ObjectTypeDB::bind_method(_MD("set_item_selectable","idx","selectable"),&ItemList::set_item_selectable);
ObjectTypeDB::bind_method(_MD("is_item_selectable","idx"),&ItemList::is_item_selectable);
@@ -1095,6 +1138,7 @@ ItemList::ItemList() {
set_focus_mode(FOCUS_ALL);
current_columns=1;
search_time_msec=0;
+ ensure_selected_visible=false;
}
diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h
index 237079c428..bd3cf6484e 100644
--- a/scene/gui/item_list.h
+++ b/scene/gui/item_list.h
@@ -41,6 +41,8 @@ private:
bool shape_changed;
+ bool ensure_selected_visible;
+
Vector<Item> items;
Vector<int> separators;
@@ -99,6 +101,7 @@ public:
void set_current(int p_current);
int get_current() const;
+ void move_item(int p_item,int p_to_pos);
int get_item_count() const;
void remove_item(int p_idx);
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index 27d0f568a2..e8097c79a4 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,15 +33,15 @@
void Label::set_autowrap(bool p_autowrap) {
-
+
autowrap=p_autowrap;
word_cache_dirty=true;
minimum_size_changed();
-
-
+ update();
+
}
bool Label::has_autowrap() const {
-
+
return autowrap;
}
@@ -51,6 +51,7 @@ void Label::set_uppercase(bool p_uppercase) {
uppercase=p_uppercase;
word_cache_dirty=true;
minimum_size_changed();
+ update();
}
bool Label::is_uppercase() const {
@@ -66,19 +67,18 @@ int Label::get_line_height() const {
void Label::_notification(int p_what) {
-
+
if (p_what==NOTIFICATION_DRAW) {
-
- if (clip && !autowrap)
- VisualServer::get_singleton()->canvas_item_set_clip(get_canvas_item(),true);
+ if (clip || autowrap)
+ VisualServer::get_singleton()->canvas_item_set_clip(get_canvas_item(),true);
if (word_cache_dirty)
regenerate_word_cache();
-
+
RID ci = get_canvas_item();
-
+
Size2 string_size;
Size2 size=get_size();
@@ -91,38 +91,43 @@ void Label::_notification(int p_what) {
VisualServer::get_singleton()->canvas_item_set_distance_field_mode(get_canvas_item(),font.is_valid() && font->is_distance_field_hint());
int font_h = font->get_height();
- int line_from=(int)get_val(); // + p_exposed.pos.y / font_h;
int lines_visible = size.y/font_h;
- int line_to=(int)get_val() + lines_visible; //p_exposed.pos.y+p_exposed.size.height / font_h;
int space_w=font->get_char_size(' ').width;
- int lines_total = get_max();
int chars_total=0;
int vbegin=0,vsep=0;
-
- if (lines_total && lines_total < lines_visible) {
+ if (lines_visible > line_count) {
+ lines_visible = line_count;
+
+ }
+
+ if (max_lines_visible >= 0 && lines_visible > max_lines_visible) {
+ lines_visible = max_lines_visible;
+
+ }
+
+ if (lines_visible > 0) {
switch(valign) {
case VALIGN_TOP: {
-
//nothing
} break;
case VALIGN_CENTER: {
-
- vbegin=(lines_visible-lines_total) * font_h / 2;
+ vbegin=(size.y - lines_visible * font_h) / 2;
vsep=0;
+
} break;
case VALIGN_BOTTOM: {
- vbegin=(lines_visible-lines_total) * font_h;
+ vbegin=size.y - lines_visible * font_h;
vsep=0;
} break;
case VALIGN_FILL: {
vbegin=0;
- if (lines_total>1) {
- vsep=(lines_visible-lines_total) * font_h / (lines_total-1);
+ if (lines_visible>1) {
+ vsep=(size.y - lines_visible * font_h) / (lines_visible - 1);
} else {
vsep=0;
}
@@ -130,20 +135,21 @@ void Label::_notification(int p_what) {
} break;
}
}
-
-
+
+
WordCache *wc = word_cache;
if (!wc)
return;
-
+
int c = 0;
int line=0;
+ int line_to=lines_skipped + (lines_visible>0?lines_visible:1);
while(wc) {
/* handle lines not meant to be drawn quickly */
- if (line>line_to)
+ if (line>=line_to)
break;
- if (line<line_from) {
-
+ if (line<lines_skipped) {
+
while (wc && wc->char_pos>=0)
wc=wc->next;
if (wc)
@@ -151,36 +157,36 @@ void Label::_notification(int p_what) {
line++;
continue;
}
-
+
/* handle lines normally */
-
+
if (wc->char_pos<0) {
//empty line
wc=wc->next;
line++;
continue;
}
-
+
WordCache *from=wc;
WordCache *to=wc;
-
+
int taken=0;
int spaces=0;
while(to && to->char_pos>=0) {
-
+
taken+=to->pixel_width;
if (to!=from && to->space_count) {
spaces+=to->space_count;
}
to=to->next;
}
-
+
bool can_fill = to && to->char_pos==WordCache::CHAR_WRAPLINE;
float x_ofs=0;
-
+
switch (align) {
-
+
case ALIGN_FILL:
case ALIGN_LEFT: {
@@ -198,16 +204,16 @@ void Label::_notification(int p_what) {
} break;
}
-
- int y_ofs=(line-(int)get_val())*font_h + font->get_ascent();
+
+ int y_ofs=(line-lines_skipped)*font_h + font->get_ascent();
y_ofs+=vbegin + line*vsep;
-
+
while(from!=to) {
-
+
// draw a word
int pos = from->char_pos;
if (from->char_pos<0) {
-
+
ERR_PRINT("BUG");
return;
}
@@ -221,15 +227,15 @@ void Label::_notification(int p_what) {
}
-
-
-
+
+
+
if (font_color_shadow.a>0) {
-
+
int chars_total_shadow = chars_total; //save chars drawn
float x_ofs_shadow=x_ofs;
for (int i=0;i<from->word_len;i++) {
-
+
if (visible_chars < 0 || chars_total_shadow<visible_chars) {
CharType c = text[i+pos];
CharType n = text[i+pos+1];
@@ -249,7 +255,7 @@ void Label::_notification(int p_what) {
}
}
-
+
}
for (int i=0;i<from->word_len;i++) {
@@ -268,73 +274,73 @@ void Label::_notification(int p_what) {
}
from=from->next;
}
-
+
wc=to?to->next:0;
line++;
-
- }
+
+ }
}
-
+
if (p_what==NOTIFICATION_THEME_CHANGED) {
word_cache_dirty=true;
update();
}
if (p_what==NOTIFICATION_RESIZED) {
-
+
word_cache_dirty=true;
}
-
+
}
Size2 Label::get_minimum_size() const {
-
+
if (autowrap)
return Size2(1,1);
else {
-
+
// don't want to mutable everything
- if(word_cache_dirty)
+ if(word_cache_dirty)
const_cast<Label*>(this)->regenerate_word_cache();
-
+
Size2 ms=minsize;
if (clip)
ms.width=1;
return ms;
- }
+ }
}
int Label::get_longest_line_width() const {
-
+
Ref<Font> font = get_font("font");
int max_line_width=0;
int line_width=0;
-
- for (int i=0;i<text.size()+1;i++) {
-
- CharType current=i<text.length()?text[i]:' '; //always a space at the end, so the algo works
+
+ for (int i=0;i<text.size();i++) {
+
+ CharType current=text[i];
if (uppercase)
current=String::char_uppercase(current);
if (current<32) {
-
+
if (current=='\n') {
-
+
if (line_width>max_line_width)
max_line_width=line_width;
line_width=0;
}
} else {
-
+
int char_width=font->get_char_size(current).width;
- line_width+=char_width;
+ line_width+=char_width;
}
-
+
}
if (line_width>max_line_width)
max_line_width=line_width;
-
+
return max_line_width;
}
@@ -349,15 +355,15 @@ int Label::get_line_count() const {
}
void Label::regenerate_word_cache() {
-
+
while (word_cache) {
-
+
WordCache *current=word_cache;
word_cache=current->next;
memdelete( current );
}
-
-
+
+
int width=autowrap?get_size().width:get_longest_line_width();
Ref<Font> font = get_font("font");
@@ -368,11 +374,11 @@ void Label::regenerate_word_cache() {
int space_width=font->get_char_size(' ').width;
line_count=1;
total_char_cache=0;
-
+
WordCache *last=NULL;
-
+
for (int i=0;i<text.size()+1;i++) {
-
+
CharType current=i<text.length()?text[i]:' '; //always a space at the end, so the algo works
if (uppercase)
@@ -429,12 +435,12 @@ void Label::regenerate_word_cache() {
if (current_word_size==0) {
word_pos=i;
}
-
+
char_width=font->get_char_size(current).width;
current_word_size+=char_width;
line_width+=char_width;
total_char_cache++;
-
+
}
if ((autowrap && (line_width >= width) && ((last && last->char_pos >= 0) || separatable)) || insert_newline) {
@@ -474,29 +480,22 @@ void Label::regenerate_word_cache() {
space_count=0;
}
-
+
}
-
- //total_char_cache -= line_count + 1; // do not count new lines (including the first one)
-
+
if (!autowrap) {
-
minsize.width=width;
- minsize.height=font->get_height()*line_count;
- set_page( line_count );
-
- } else {
-
- set_page( get_size().height / font->get_height() );
+ if (max_lines_visible > 0 && line_count > max_lines_visible) {
+ minsize.height=font->get_height()*max_lines_visible;
+ } else {
+ minsize.height=font->get_height()*line_count;
+ }
}
-
- set_max(line_count);
-
+
word_cache_dirty=false;
}
-
void Label::set_align(Align p_align) {
ERR_FAIL_INDEX(p_align,4);
@@ -505,7 +504,7 @@ void Label::set_align(Align p_align) {
}
Label::Align Label::get_align() const{
-
+
return align;
}
@@ -522,24 +521,23 @@ Label::VAlign Label::get_valign() const{
}
void Label::set_text(const String& p_string) {
-
+
String str = XL_MESSAGE(p_string);
if (text==str)
return;
-
+
text=str;
word_cache_dirty=true;
+ if (percent_visible<1)
+ visible_chars=get_total_character_count()*percent_visible;
update();
- if (!autowrap)
- minimum_size_changed();
-
+ minimum_size_changed();
+
}
void Label::set_clip_text(bool p_clip) {
- if (clip==p_clip)
- return;
clip=p_clip;
update();
minimum_size_changed();
@@ -551,23 +549,39 @@ bool Label::is_clipping_text() const {
}
String Label::get_text() const {
-
+
return text;
}
void Label::set_visible_characters(int p_amount) {
visible_chars=p_amount;
+ if (get_total_character_count() > 0) {
+ percent_visible=(float)p_amount/(float)total_char_cache;
+ }
update();
}
+int Label::get_visible_characters() const {
+
+ return visible_chars;
+}
+
void Label::set_percent_visible(float p_percent) {
- if (p_percent<0)
- set_visible_characters(-1);
- else
- set_visible_characters(get_total_character_count()*p_percent);
- percent_visible=p_percent;
+ if (p_percent<0 || p_percent>=1) {
+
+ visible_chars=-1;
+ percent_visible=1;
+
+ } else {
+
+ visible_chars=get_total_character_count()*p_percent;
+ percent_visible=p_percent;
+
+ }
+ update();
+
}
float Label::get_percent_visible() const{
@@ -575,6 +589,27 @@ float Label::get_percent_visible() const{
return percent_visible;
}
+void Label::set_lines_skipped(int p_lines) {
+
+ lines_skipped=p_lines;
+ update();
+}
+
+int Label::get_lines_skipped() const{
+
+ return lines_skipped;
+}
+
+void Label::set_max_lines_visible(int p_lines) {
+
+ max_lines_visible=p_lines;
+ update();
+}
+
+int Label::get_max_lines_visible() const{
+
+ return max_lines_visible;
+}
int Label::get_total_character_count() const {
@@ -585,7 +620,7 @@ int Label::get_total_character_count() const {
}
void Label::_bind_methods() {
-
+
ObjectTypeDB::bind_method(_MD("set_align","align"),&Label::set_align);
ObjectTypeDB::bind_method(_MD("get_align"),&Label::get_align);
ObjectTypeDB::bind_method(_MD("set_valign","valign"),&Label::set_valign);
@@ -594,14 +629,21 @@ void Label::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_text"),&Label::get_text);
ObjectTypeDB::bind_method(_MD("set_autowrap","enable"),&Label::set_autowrap);
ObjectTypeDB::bind_method(_MD("has_autowrap"),&Label::has_autowrap);
+ ObjectTypeDB::bind_method(_MD("set_clip_text","enable"),&Label::set_clip_text);
+ ObjectTypeDB::bind_method(_MD("is_clipping_text"),&Label::is_clipping_text);
ObjectTypeDB::bind_method(_MD("set_uppercase","enable"),&Label::set_uppercase);
ObjectTypeDB::bind_method(_MD("is_uppercase"),&Label::is_uppercase);
ObjectTypeDB::bind_method(_MD("get_line_height"),&Label::get_line_height);
ObjectTypeDB::bind_method(_MD("get_line_count"),&Label::get_line_count);
ObjectTypeDB::bind_method(_MD("get_total_character_count"),&Label::get_total_character_count);
- ObjectTypeDB::bind_method(_MD("set_visible_characters"),&Label::set_visible_characters);
+ ObjectTypeDB::bind_method(_MD("set_visible_characters","amount"),&Label::set_visible_characters);
+ ObjectTypeDB::bind_method(_MD("get_visible_characters"),&Label::get_visible_characters);
ObjectTypeDB::bind_method(_MD("set_percent_visible","percent_visible"),&Label::set_percent_visible);
ObjectTypeDB::bind_method(_MD("get_percent_visible"),&Label::get_percent_visible);
+ ObjectTypeDB::bind_method(_MD("set_lines_skipped","lines_skipped"),&Label::set_lines_skipped);
+ ObjectTypeDB::bind_method(_MD("get_lines_skipped"),&Label::get_lines_skipped);
+ ObjectTypeDB::bind_method(_MD("set_max_lines_visible","lines_visible"),&Label::set_max_lines_visible);
+ ObjectTypeDB::bind_method(_MD("get_max_lines_visible"),&Label::get_max_lines_visible);
BIND_CONSTANT( ALIGN_LEFT );
BIND_CONSTANT( ALIGN_CENTER );
@@ -613,22 +655,25 @@ void Label::_bind_methods() {
BIND_CONSTANT( VALIGN_BOTTOM );
BIND_CONSTANT( VALIGN_FILL );
- ADD_PROPERTY( PropertyInfo( Variant::STRING, "text",PROPERTY_HINT_MULTILINE_TEXT,"",PROPERTY_USAGE_DEFAULT_INTL), _SCS("set_text"),_SCS("get_text") );
- ADD_PROPERTY( PropertyInfo( Variant::INT, "align", PROPERTY_HINT_ENUM,"Left,Center,Right,Fill" ),_SCS("set_align"),_SCS("get_align") );
- ADD_PROPERTY( PropertyInfo( Variant::INT, "valign", PROPERTY_HINT_ENUM,"Top,Center,Bottom,Fill" ),_SCS("set_valign"),_SCS("get_valign") );
- ADD_PROPERTY( PropertyInfo( Variant::BOOL, "autowrap"),_SCS("set_autowrap"),_SCS("has_autowrap") );
- ADD_PROPERTY( PropertyInfo( Variant::BOOL, "uppercase"),_SCS("set_uppercase"),_SCS("is_uppercase") );
+ ADD_PROPERTYNZ( PropertyInfo( Variant::STRING, "text",PROPERTY_HINT_MULTILINE_TEXT,"",PROPERTY_USAGE_DEFAULT_INTL), _SCS("set_text"),_SCS("get_text") );
+ ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "align", PROPERTY_HINT_ENUM,"Left,Center,Right,Fill" ),_SCS("set_align"),_SCS("get_align") );
+ ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "valign", PROPERTY_HINT_ENUM,"Top,Center,Bottom,Fill" ),_SCS("set_valign"),_SCS("get_valign") );
+ ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "autowrap"),_SCS("set_autowrap"),_SCS("has_autowrap") );
+ ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "clip_text"),_SCS("set_clip_text"),_SCS("is_clipping_text") );
+ ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "uppercase"),_SCS("set_uppercase"),_SCS("is_uppercase") );
ADD_PROPERTY( PropertyInfo( Variant::REAL, "percent_visible", PROPERTY_HINT_RANGE,"0,1,0.001"),_SCS("set_percent_visible"),_SCS("get_percent_visible") );
+ ADD_PROPERTY( PropertyInfo( Variant::INT, "lines_skipped", PROPERTY_HINT_RANGE,"0,999,1"),_SCS("set_lines_skipped"),_SCS("get_lines_skipped") );
+ ADD_PROPERTY( PropertyInfo( Variant::INT, "max_lines_visible", PROPERTY_HINT_RANGE,"-1,999,1"),_SCS("set_max_lines_visible"),_SCS("get_max_lines_visible") );
}
Label::Label(const String &p_text) {
-
+
align=ALIGN_LEFT;
valign=VALIGN_TOP;
text="";
word_cache=NULL;
- word_cache_dirty=true;
+ word_cache_dirty=true;
autowrap=false;
line_count=0;
set_v_size_flags(0);
@@ -636,20 +681,22 @@ Label::Label(const String &p_text) {
set_ignore_mouse(true);
total_char_cache=0;
visible_chars=-1;
- percent_visible=-1;
+ percent_visible=1;
+ lines_skipped=0;
+ max_lines_visible=-1;
set_text(p_text);
uppercase=false;
}
Label::~Label() {
-
+
while (word_cache) {
-
+
WordCache *current=word_cache;
word_cache=current->next;
memdelete( current );
- }
+ }
}
diff --git a/scene/gui/label.h b/scene/gui/label.h
index 81e3ab5676..3c14add60d 100644
--- a/scene/gui/label.h
+++ b/scene/gui/label.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,17 +29,17 @@
#ifndef LABEL_H
#define LABEL_H
-#include "scene/gui/range.h"
+#include "scene/gui/control.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
-class Label : public Range {
-
- OBJ_TYPE( Label, Range );
-public:
-
+class Label : public Control {
+
+ OBJ_TYPE( Label, Control );
+public:
+
enum Align {
-
+
ALIGN_LEFT,
ALIGN_CENTER,
ALIGN_RIGHT,
@@ -63,11 +63,11 @@ private:
Size2 minsize;
int line_count;
bool uppercase;
-
+
int get_longest_line_width() const;
-
+
struct WordCache {
-
+
enum {
CHAR_NEWLINE=-1,
CHAR_WRAPLINE=-2
@@ -78,23 +78,25 @@ private:
int space_count;
WordCache *next;
WordCache() { char_pos=0; word_len=0; pixel_width=0; next=0; space_count=0;}
- };
-
+ };
+
bool word_cache_dirty;
void regenerate_word_cache();
float percent_visible;
-
+
WordCache *word_cache;
int total_char_cache;
int visible_chars;
-protected:
+ int lines_skipped;
+ int max_lines_visible;
+protected:
void _notification(int p_what);
static void _bind_methods();
// bind helpers
public:
-
+
virtual Size2 get_minimum_size() const;
void set_align(Align p_align);
@@ -105,7 +107,7 @@ public:
void set_text(const String& p_string);
String get_text() const;
-
+
void set_autowrap(bool p_autowrap);
bool has_autowrap() const;
@@ -113,6 +115,7 @@ public:
bool is_uppercase() const;
void set_visible_characters(int p_amount);
+ int get_visible_characters() const;
int get_total_character_count() const;
void set_clip_text(bool p_clip);
@@ -121,6 +124,11 @@ public:
void set_percent_visible(float p_percent);
float get_percent_visible() const;
+ void set_lines_skipped(int p_lines);
+ int get_lines_skipped() const;
+
+ void set_max_lines_visible(int p_lines);
+ int get_max_lines_visible() const;
int get_line_height() const;
int get_line_count() const;
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index fec9e401f1..fdced3f62f 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -145,6 +145,13 @@ void LineEdit::_input_event(InputEvent p_event) {
int old_cursor_pos = cursor_pos;
text = undo_text;
+
+ Ref<Font> font = get_font("font");
+
+ cached_width = 0;
+ for (int i = 0; i<text.length(); i++)
+ cached_width += font->get_char_size(text[i]).width;
+
if(old_cursor_pos > text.length()) {
set_cursor_pos(text.length());
} else {
@@ -164,6 +171,15 @@ void LineEdit::_input_event(InputEvent p_event) {
selection_clear();
undo_text = text;
text = text.substr(cursor_pos,text.length()-cursor_pos);
+
+ Ref<Font> font = get_font("font");
+
+ cached_width = 0;
+ if (font != NULL) {
+ for (int i = 0; i < text.length(); i++)
+ cached_width += font->get_char_size(text[i]).width;
+ }
+
set_cursor_pos(0);
emit_signal("text_changed",text);
_change_notify("text");
@@ -192,6 +208,9 @@ void LineEdit::_input_event(InputEvent p_event) {
}
} break;
+ case (KEY_A): { //Select All
+ select();
+ } break;
default: { handled=false;}
}
@@ -226,12 +245,26 @@ void LineEdit::_input_event(InputEvent p_event) {
delete_char();
}
} break;
+ case KEY_KP_4: {
+ if (k.unicode != 0) {
+ handled = false;
+ break;
+ }
+ // numlock disabled. fallthrough to key_left
+ }
case KEY_LEFT: {
shift_selection_check_pre(k.mod.shift);
set_cursor_pos(get_cursor_pos()-1);
shift_selection_check_post(k.mod.shift);
} break;
+ case KEY_KP_6: {
+ if (k.unicode != 0) {
+ handled = false;
+ break;
+ }
+ // numlock disabled. fallthrough to key_right
+ }
case KEY_RIGHT: {
shift_selection_check_pre(k.mod.shift);
@@ -252,12 +285,26 @@ void LineEdit::_input_event(InputEvent p_event) {
}
} break;
+ case KEY_KP_7: {
+ if (k.unicode != 0) {
+ handled = false;
+ break;
+ }
+ // numlock disabled. fallthrough to key_home
+ }
case KEY_HOME: {
shift_selection_check_pre(k.mod.shift);
set_cursor_pos(0);
shift_selection_check_post(k.mod.shift);
} break;
+ case KEY_KP_1: {
+ if (k.unicode != 0) {
+ handled = false;
+ break;
+ }
+ // numlock disabled. fallthrough to key_end
+ }
case KEY_END: {
shift_selection_check_pre(k.mod.shift);
@@ -268,26 +315,29 @@ void LineEdit::_input_event(InputEvent p_event) {
default: {
- if (k.unicode>=32 && k.scancode!=KEY_DELETE) {
-
- if (editable) {
- selection_delete();
- CharType ucodestr[2]={(CharType)k.unicode,0};
- append_at_cursor(ucodestr);
- emit_signal("text_changed",text);
- _change_notify("text");
- }
-
- } else {
- handled=false;
- }
+ handled=false;
} break;
}
- if (handled)
+ if (handled) {
accept_event();
- else
- return;
+ } else {
+ if (k.unicode>=32 && k.scancode!=KEY_DELETE) {
+
+ if (editable) {
+ selection_delete();
+ CharType ucodestr[2]={(CharType)k.unicode,0};
+ append_at_cursor(ucodestr);
+ emit_signal("text_changed",text);
+ _change_notify("text");
+
+ accept_event();
+ }
+
+ } else {
+ return;
+ }
+ }
selection.old_shift=k.mod.shift;
@@ -303,6 +353,18 @@ void LineEdit::_input_event(InputEvent p_event) {
}
}
+void LineEdit::set_align(Align p_align) {
+
+ ERR_FAIL_INDEX(p_align, 4);
+ align = p_align;
+ update();
+}
+
+LineEdit::Align LineEdit::get_align() const{
+
+ return align;
+}
+
Variant LineEdit::get_drag_data(const Point2& p_point) {
if (selection.drag_attempt && selection.enabled) {
@@ -325,7 +387,15 @@ void LineEdit::drop_data(const Point2& p_point,const Variant& p_data){
if (p_data.get_type()==Variant::STRING) {
set_cursor_at_pixel_pos(p_point.x);
int selected = selection.end - selection.begin;
+
+ Ref<Font> font = get_font("font");
+ if (font != NULL) {
+ for (int i = selection.begin; i < selection.end; i++)
+ cached_width -= font->get_char_size(text[i]).width;
+ }
+
text.erase(selection.begin, selected);
+
append_at_cursor(p_data);
selection.begin = cursor_pos-selected;
selection.end = cursor_pos;
@@ -365,8 +435,25 @@ void LineEdit::_notification(int p_what) {
get_stylebox("focus")->draw( ci, Rect2( Point2(), size ) );
}
-
- int ofs=style->get_offset().x;
+ int x_ofs=0;
+
+ switch (align) {
+
+ case ALIGN_FILL:
+ case ALIGN_LEFT: {
+
+ x_ofs=style->get_offset().x;
+ } break;
+ case ALIGN_CENTER: {
+
+ x_ofs=x_ofs=int(size.width-(cached_width))/2;
+ } break;
+ case ALIGN_RIGHT: {
+
+ x_ofs=x_ofs=int(size.width-style->get_offset().x-(cached_width));
+ } break;
+ }
+
int ofs_max=width-style->get_minimum_size().width;
int char_ofs=window_pos;
@@ -391,29 +478,29 @@ void LineEdit::_notification(int p_what) {
int char_width=font->get_char_size( cchar,next ).width;
// end of widget, break!
- if ( (ofs+char_width) > ofs_max )
+ if ((x_ofs + char_width) > ofs_max)
break;
bool selected=selection.enabled && char_ofs>=selection.begin && char_ofs<selection.end;
if (selected)
- VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2( Point2( ofs , y_ofs ),Size2( char_width, y_area )),selection_color);
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs), Size2(char_width, y_area)), selection_color);
- font->draw_char(ci,Point2( ofs , y_ofs+font_ascent ), cchar, next,selected?font_color_selected:font_color );
+ font->draw_char(ci, Point2(x_ofs, y_ofs + font_ascent), cchar, next, selected ? font_color_selected : font_color);
if (char_ofs==cursor_pos && has_focus())
VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(
- Point2( ofs , y_ofs ), Size2( 1, y_area ) ), cursor_color );
+ Point2( x_ofs , y_ofs ), Size2( 1, y_area ) ), cursor_color );
- ofs+=char_width;
+ x_ofs+=char_width;
char_ofs++;
}
if (char_ofs==cursor_pos && has_focus()) //may be at the end
VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(
- Point2( ofs , y_ofs ), Size2( 1, y_area ) ), cursor_color );
+ Point2( x_ofs , y_ofs ), Size2( 1, y_area ) ), cursor_color );
} break;
case NOTIFICATION_FOCUS_ENTER: {
@@ -484,13 +571,36 @@ void LineEdit::shift_selection_check_post(bool p_shift) {
void LineEdit::set_cursor_at_pixel_pos(int p_x) {
- int ofs=window_pos;
- int pixel_ofs=get_stylebox("normal")->get_offset().x;
- Ref<Font> font=get_font("font");
+ Ref<Font> font = get_font("font");
+ int ofs = window_pos;
+ Ref<StyleBox> style = get_stylebox("normal");
+ int pixel_ofs = 0;
+ Size2 size = get_size();
+
+ switch (align) {
+
+ case ALIGN_FILL:
+ case ALIGN_LEFT: {
+
+ pixel_ofs = int(style->get_offset().x);
+ } break;
+ case ALIGN_CENTER: {
+
+ pixel_ofs=int(size.width-(cached_width))/2;
+ } break;
+ case ALIGN_RIGHT: {
+
+ pixel_ofs=int(size.width-style->get_offset().x-(cached_width));
+ } break;
+ }
+
while (ofs<text.length()) {
- int char_w=font->get_char_size( text[ofs] ).width;
+ int char_w = 0;
+ if (font != NULL) {
+ char_w = font->get_char_size(text[ofs]).width;
+ }
pixel_ofs+=char_w;
if (pixel_ofs > p_x) { //found what we look for
@@ -523,6 +633,10 @@ void LineEdit::delete_char() {
if ((text.length()<=0) || (cursor_pos==0)) return;
+ Ref<Font> font = get_font("font");
+ if (font != NULL) {
+ cached_width -= font->get_char_size(text[cursor_pos - 1]).width;
+ }
text.erase( cursor_pos-1, 1 );
@@ -593,13 +707,15 @@ void LineEdit::set_cursor_pos(int p_pos) {
int width_to_cursor=0;
int wp=window_pos;
- for (int i=window_pos;i<cursor_pos;i++)
- width_to_cursor+=font->get_char_size( text[i] ).width;
+ if (font != NULL) {
+ for (int i=window_pos;i<cursor_pos;i++)
+ width_to_cursor+=font->get_char_size( text[i] ).width;
- while(width_to_cursor>=window_width && wp<text.length()) {
-
- width_to_cursor-=font->get_char_size( text[ wp ] ).width;
- wp++;
+ while (width_to_cursor >= window_width && wp < text.length()) {
+
+ width_to_cursor -= font->get_char_size(text[wp]).width;
+ wp++;
+ }
}
if (wp!=window_pos)
@@ -626,17 +742,26 @@ void LineEdit::append_at_cursor(String p_text) {
if ( ( max_length <= 0 ) || (text.length()+p_text.length() <= max_length)) {
undo_text = text;
+
+ Ref<Font> font = get_font("font");
+ if (font != NULL) {
+ for (int i = 0; i < p_text.length(); i++)
+ cached_width += font->get_char_size(p_text[i]).width;
+ }
+ else {
+ cached_width = 0;
+ }
+
String pre = text.substr( 0, cursor_pos );
String post = text.substr( cursor_pos, text.length()-cursor_pos );
text=pre+p_text+post;
set_cursor_pos(cursor_pos+p_text.length());
-
}
-
}
void LineEdit::clear_internal() {
+ cached_width = 0;
cursor_pos=0;
window_pos=0;
undo_text="";
@@ -676,6 +801,20 @@ void LineEdit::selection_delete() {
if (selection.enabled) {
undo_text = text;
+
+ if (text.size() > 0)
+ {
+ Ref<Font> font = get_font("font");
+ if (font != NULL) {
+ for (int i = selection.begin; i < selection.end; i++)
+ cached_width -= font->get_char_size(text[i]).width;
+ }
+ }
+ else
+ {
+ cached_width = 0;
+ }
+
text.erase(selection.begin,selection.end-selection.begin);
cursor_pos-=CLAMP( cursor_pos-selection.begin, 0, selection.end-selection.begin);
@@ -782,9 +921,15 @@ void LineEdit::select(int p_from, int p_to) {
update();
}
+bool LineEdit::is_text_field() const {
+
+ return true;
+}
void LineEdit::_bind_methods() {
+ ObjectTypeDB::bind_method(_MD("set_align", "align"), &LineEdit::set_align);
+ ObjectTypeDB::bind_method(_MD("get_align"), &LineEdit::get_align);
ObjectTypeDB::bind_method(_MD("_input_event"),&LineEdit::_input_event);
ObjectTypeDB::bind_method(_MD("clear"),&LineEdit::clear);
@@ -805,15 +950,22 @@ void LineEdit::_bind_methods() {
ADD_SIGNAL( MethodInfo("text_changed", PropertyInfo( Variant::STRING, "text" )) );
ADD_SIGNAL( MethodInfo("text_entered", PropertyInfo( Variant::STRING, "text" )) );
+ BIND_CONSTANT(ALIGN_LEFT);
+ BIND_CONSTANT(ALIGN_CENTER);
+ BIND_CONSTANT(ALIGN_RIGHT);
+ BIND_CONSTANT(ALIGN_FILL);
+
ADD_PROPERTY( PropertyInfo( Variant::STRING, "text" ), _SCS("set_text"),_SCS("get_text") );
+ ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "align", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), _SCS("set_align"), _SCS("get_align"));
ADD_PROPERTY( PropertyInfo( Variant::INT, "max_length" ), _SCS("set_max_length"),_SCS("get_max_length") );
ADD_PROPERTY( PropertyInfo( Variant::BOOL, "editable" ), _SCS("set_editable"),_SCS("is_editable") );
ADD_PROPERTY( PropertyInfo( Variant::BOOL, "secret" ), _SCS("set_secret"),_SCS("is_secret") );
-
}
LineEdit::LineEdit() {
+ align = ALIGN_LEFT;
+ cached_width = 0;
cursor_pos=0;
window_pos=0;
max_length = 0;
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index c19043e826..bf6459361a 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -36,7 +36,18 @@
class LineEdit : public Control {
OBJ_TYPE( LineEdit, Control );
-
+
+public:
+ enum Align {
+
+ ALIGN_LEFT,
+ ALIGN_CENTER,
+ ALIGN_RIGHT,
+ ALIGN_FILL
+ };
+private:
+ Align align;
+
bool editable;
bool pass;
@@ -46,6 +57,8 @@ class LineEdit : public Control {
int cursor_pos;
int window_pos;
int max_length; // 0 for no maximum
+
+ int cached_width;
struct Selection {
@@ -83,7 +96,8 @@ class LineEdit : public Control {
protected:
static void _bind_methods();
public:
-
+ void set_align(Align p_align);
+ Align get_align() const;
virtual Variant get_drag_data(const Point2& p_point);
virtual bool can_drop_data(const Point2& p_point,const Variant& p_data) const;
@@ -112,9 +126,14 @@ public:
void select(int p_from=0, int p_to=-1);
virtual Size2 get_minimum_size() const;
+
+ virtual bool is_text_field() const;
LineEdit();
~LineEdit();
};
+
+VARIANT_ENUM_CAST(LineEdit::Align);
+
#endif
diff --git a/scene/gui/margin_container.cpp b/scene/gui/margin_container.cpp
index f10ca6353a..fde5df6b72 100644
--- a/scene/gui/margin_container.cpp
+++ b/scene/gui/margin_container.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/margin_container.h b/scene/gui/margin_container.h
index 56f2344ea7..df9a5c9361 100644
--- a/scene/gui/margin_container.h
+++ b/scene/gui/margin_container.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index 68fcb4bda8..26540843de 100644
--- a/scene/gui/menu_button.cpp
+++ b/scene/gui/menu_button.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -54,6 +54,8 @@ void MenuButton::_unhandled_key_input(InputEvent p_event) {
int item = popup->find_item_by_accelerator(code);
+
+
if (item>=0 && ! popup->is_item_disabled(item))
popup->activate_item(item);
/*
@@ -124,7 +126,7 @@ void MenuButton::_set_items(const Array& p_items) {
void MenuButton::_bind_methods() {
- ObjectTypeDB::bind_method(_MD("get_popup"),&MenuButton::get_popup);
+ ObjectTypeDB::bind_method(_MD("get_popup:PopupMenu"),&MenuButton::get_popup);
ObjectTypeDB::bind_method(_MD("_unhandled_key_input"),&MenuButton::_unhandled_key_input);
ObjectTypeDB::bind_method(_MD("_set_items"),&MenuButton::_set_items);
ObjectTypeDB::bind_method(_MD("_get_items"),&MenuButton::_get_items);
diff --git a/scene/gui/menu_button.h b/scene/gui/menu_button.h
index 47e7382d34..2df632811f 100644
--- a/scene/gui/menu_button.h
+++ b/scene/gui/menu_button.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp
index ff94a37be0..5c8e5a7381 100644
--- a/scene/gui/option_button.cpp
+++ b/scene/gui/option_button.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -77,9 +77,14 @@ void OptionButton::_selected(int p_which) {
}
}
- ERR_FAIL_COND(selid==-1);
+ if (selid==-1 && p_which>=0 && p_which<popup->get_item_count()) {
+ _select(p_which,true);
+ } else {
- _select(selid,true);
+ ERR_FAIL_COND(selid==-1);
+
+ _select(selid,true);
+ }
}
@@ -299,7 +304,7 @@ void OptionButton::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_item_count"),&OptionButton::get_item_count);
ObjectTypeDB::bind_method(_MD("add_separator"),&OptionButton::add_separator);
ObjectTypeDB::bind_method(_MD("clear"),&OptionButton::clear);
- ObjectTypeDB::bind_method(_MD("select"),&OptionButton::select);
+ ObjectTypeDB::bind_method(_MD("select","idx"),&OptionButton::select);
ObjectTypeDB::bind_method(_MD("get_selected"),&OptionButton::get_selected);
ObjectTypeDB::bind_method(_MD("get_selected_ID"),&OptionButton::get_selected_ID);
ObjectTypeDB::bind_method(_MD("get_selected_metadata"),&OptionButton::get_selected_metadata);
diff --git a/scene/gui/option_button.h b/scene/gui/option_button.h
index 7d850479aa..34e2bdd384 100644
--- a/scene/gui/option_button.h
+++ b/scene/gui/option_button.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/panel.cpp b/scene/gui/panel.cpp
index d9ba20810b..d40daa972c 100644
--- a/scene/gui/panel.cpp
+++ b/scene/gui/panel.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/panel.h b/scene/gui/panel.h
index 7e6be62923..ee4bcd139e 100644
--- a/scene/gui/panel.h
+++ b/scene/gui/panel.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/panel_container.cpp b/scene/gui/panel_container.cpp
index 5ee061356e..bcf75b79f8 100644
--- a/scene/gui/panel_container.cpp
+++ b/scene/gui/panel_container.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/panel_container.h b/scene/gui/panel_container.h
index c09479241c..a40519c9f2 100644
--- a/scene/gui/panel_container.h
+++ b/scene/gui/panel_container.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/patch_9_frame.cpp b/scene/gui/patch_9_frame.cpp
new file mode 100644
index 0000000000..b6e261714c
--- /dev/null
+++ b/scene/gui/patch_9_frame.cpp
@@ -0,0 +1,132 @@
+#include "patch_9_frame.h"
+
+#include "servers/visual_server.h"
+
+void Patch9Frame::_notification(int p_what) {
+
+ if (p_what==NOTIFICATION_DRAW) {
+
+ if (texture.is_null())
+ return;
+
+
+ Size2 s=get_size();
+ RID ci = get_canvas_item();
+ VS::get_singleton()->canvas_item_add_style_box(ci,Rect2(Point2(),s),texture->get_rid(),Vector2(margin[MARGIN_LEFT],margin[MARGIN_TOP]),Vector2(margin[MARGIN_RIGHT],margin[MARGIN_BOTTOM]),draw_center,modulate);
+// draw_texture_rect(texture,Rect2(Point2(),s),false,modulate);
+
+/*
+ Vector<Point2> points;
+ points.resize(4);
+ points[0]=Point2(0,0);
+ points[1]=Point2(s.x,0);
+ points[2]=Point2(s.x,s.y);
+ points[3]=Point2(0,s.y);
+ Vector<Point2> uvs;
+ uvs.resize(4);
+ uvs[0]=Point2(0,0);
+ uvs[1]=Point2(1,0);
+ uvs[2]=Point2(1,1);
+ uvs[3]=Point2(0,1);
+
+ VisualServer::get_singleton()->canvas_item_add_primitive(ci,points,Vector<Color>(),uvs,texture->get_rid());
+*/
+ }
+}
+
+Size2 Patch9Frame::get_minimum_size() const {
+
+ return Size2(margin[MARGIN_LEFT]+margin[MARGIN_RIGHT],margin[MARGIN_TOP]+margin[MARGIN_BOTTOM]);
+}
+void Patch9Frame::_bind_methods() {
+
+
+ ObjectTypeDB::bind_method(_MD("set_texture","texture"), & Patch9Frame::set_texture );
+ ObjectTypeDB::bind_method(_MD("get_texture"), & Patch9Frame::get_texture );
+ ObjectTypeDB::bind_method(_MD("set_modulate","modulate"), & Patch9Frame::set_modulate );
+ ObjectTypeDB::bind_method(_MD("get_modulate"), & Patch9Frame::get_modulate );
+ ObjectTypeDB::bind_method(_MD("set_patch_margin","margin","value"), & Patch9Frame::set_patch_margin );
+ ObjectTypeDB::bind_method(_MD("get_patch_margin","margin"), & Patch9Frame::get_patch_margin );
+ ObjectTypeDB::bind_method(_MD("set_draw_center","draw_center"), & Patch9Frame::set_draw_center );
+ ObjectTypeDB::bind_method(_MD("get_draw_center"), & Patch9Frame::get_draw_center );
+
+ ADD_PROPERTYNZ( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), _SCS("set_texture"),_SCS("get_texture") );
+ ADD_PROPERTYNO( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate") );
+ ADD_PROPERTYNO( PropertyInfo( Variant::BOOL, "draw_center"), _SCS("set_draw_center"),_SCS("get_draw_center") );
+ ADD_PROPERTYINZ( PropertyInfo( Variant::INT, "patch_margin/left",PROPERTY_HINT_RANGE,"0,16384,1"), _SCS("set_patch_margin"),_SCS("get_patch_margin"),MARGIN_LEFT );
+ ADD_PROPERTYINZ( PropertyInfo( Variant::INT, "patch_margin/top",PROPERTY_HINT_RANGE,"0,16384,1"), _SCS("set_patch_margin"),_SCS("get_patch_margin"),MARGIN_TOP );
+ ADD_PROPERTYINZ( PropertyInfo( Variant::INT, "patch_margin/right",PROPERTY_HINT_RANGE,"0,16384,1"), _SCS("set_patch_margin"),_SCS("get_patch_margin"),MARGIN_RIGHT );
+ ADD_PROPERTYINZ( PropertyInfo( Variant::INT, "patch_margin/bottom",PROPERTY_HINT_RANGE,"0,16384,1"), _SCS("set_patch_margin"),_SCS("get_patch_margin"),MARGIN_BOTTOM );
+
+}
+
+
+void Patch9Frame::set_texture(const Ref<Texture>& p_tex) {
+
+ texture=p_tex;
+ update();
+ //if (texture.is_valid())
+ // texture->set_flags(texture->get_flags()&(~Texture::FLAG_REPEAT)); //remove repeat from texture, it looks bad in sprites
+ minimum_size_changed();
+}
+
+Ref<Texture> Patch9Frame::get_texture() const {
+
+ return texture;
+}
+
+void Patch9Frame::set_modulate(const Color& p_tex) {
+
+ modulate=p_tex;
+ update();
+}
+
+Color Patch9Frame::get_modulate() const{
+
+ return modulate;
+}
+
+
+void Patch9Frame::set_patch_margin(Margin p_margin,int p_size) {
+
+ ERR_FAIL_INDEX(p_margin,4);
+ margin[p_margin]=p_size;
+ update();
+ minimum_size_changed();
+}
+
+int Patch9Frame::get_patch_margin(Margin p_margin) const{
+
+ ERR_FAIL_INDEX_V(p_margin,4,0);
+ return margin[p_margin];
+}
+
+void Patch9Frame::set_draw_center(bool p_draw) {
+
+ draw_center=p_draw;
+ update();
+}
+
+bool Patch9Frame::get_draw_center() const{
+
+ return draw_center;
+}
+
+Patch9Frame::Patch9Frame() {
+
+
+ margin[MARGIN_LEFT]=0;
+ margin[MARGIN_RIGHT]=0;
+ margin[MARGIN_BOTTOM]=0;
+ margin[MARGIN_TOP]=0;
+ modulate=Color(1,1,1,1);
+ set_ignore_mouse(true);
+ draw_center=true;
+}
+
+
+Patch9Frame::~Patch9Frame()
+{
+}
+
+
diff --git a/scene/gui/patch_9_frame.h b/scene/gui/patch_9_frame.h
new file mode 100644
index 0000000000..562a5b1d77
--- /dev/null
+++ b/scene/gui/patch_9_frame.h
@@ -0,0 +1,40 @@
+#ifndef PATCH_9_FRAME_H
+#define PATCH_9_FRAME_H
+
+#include "scene/gui/control.h"
+/**
+ @author Juan Linietsky <reduzio@gmail.com>
+*/
+class Patch9Frame : public Control {
+
+ OBJ_TYPE(Patch9Frame,Control);
+
+ bool draw_center;
+ int margin[4];
+ Color modulate;
+ Ref<Texture> texture;
+protected:
+
+ void _notification(int p_what);
+ virtual Size2 get_minimum_size() const;
+ static void _bind_methods();
+
+public:
+
+ void set_texture(const Ref<Texture>& p_tex);
+ Ref<Texture> get_texture() const;
+
+ void set_modulate(const Color& p_tex);
+ Color get_modulate() const;
+
+ void set_patch_margin(Margin p_margin,int p_size);
+ int get_patch_margin(Margin p_margin) const;
+
+ void set_draw_center(bool p_enable);
+ bool get_draw_center() const;
+
+ Patch9Frame();
+ ~Patch9Frame();
+
+};
+#endif // PATCH_9_FRAME_H
diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp
index 5ce7e2e0d3..1f04985ec6 100644
--- a/scene/gui/popup.cpp
+++ b/scene/gui/popup.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -45,12 +45,20 @@ void Popup::_notification(int p_what) {
emit_signal("popup_hide");
}
}
+
+ if (p_what==NOTIFICATION_ENTER_TREE) {
+ //small helper to make editing of these easier in editor
+#ifdef TOOLS_ENABLED
+ if (get_tree()->is_editor_hint() && get_tree()->get_edited_scene_root() && get_tree()->get_edited_scene_root()->is_a_parent_of(this)) {
+ set_as_toplevel(false);
+ }
+#endif
+ }
+
}
void Popup::_fix_size() {
- Control *window = get_window();
- ERR_FAIL_COND(!window);
#if 0
Point2 pos = get_pos();
@@ -172,14 +180,12 @@ void Popup::popup_centered_minsize(const Size2& p_minsize) {
void Popup::popup_centered(const Size2& p_size) {
- Control *window = get_window();
- ERR_FAIL_COND(!window);
-
+ Point2 window_size = get_viewport_rect().size;
emit_signal("about_to_show");
Rect2 rect;
rect.size = p_size==Size2()?get_size():p_size;
- Point2 window_size = window==this ? get_parent_area_size() :window->get_size();
+
rect.pos = ((window_size-rect.size)/2.0).floor();
set_pos( rect.pos );
set_size( rect.size );
@@ -199,13 +205,11 @@ void Popup::popup_centered(const Size2& p_size) {
void Popup::popup_centered_ratio(float p_screen_ratio) {
- Control *window = get_window();
- ERR_FAIL_COND(!window);
emit_signal("about_to_show");
Rect2 rect;
- Point2 window_size = window==this ? get_parent_area_size() :window->get_size();
+ Point2 window_size = get_viewport_rect().size;
rect.size = (window_size * p_screen_ratio).floor();
rect.pos = ((window_size-rect.size)/2.0).floor();
set_pos( rect.pos );
diff --git a/scene/gui/popup.h b/scene/gui/popup.h
index 6c72a3c82b..9c66e6d7bd 100644
--- a/scene/gui/popup.h
+++ b/scene/gui/popup.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index e706053592..a93d8e524f 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -170,7 +170,14 @@ void PopupMenu::_activate_submenu(int over) {
Point2 p = get_global_pos();
Rect2 pr(p,get_size());
Ref<StyleBox> style = get_stylebox("panel");
- pm->set_pos(p+Point2(get_size().width,items[over]._ofs_cache-style->get_offset().y));
+
+ Point2 pos = p+Point2(get_size().width,items[over]._ofs_cache-style->get_offset().y);
+ Size2 size = pm->get_size();
+ // fix pos
+ if (pos.x+size.width > get_viewport_rect().size.width)
+ pos.x=p.x-size.width;
+
+ pm->set_pos(pos);
pm->popup();
PopupMenu *pum = pm->cast_to<PopupMenu>();
@@ -323,8 +330,13 @@ void PopupMenu::_input_event(const InputEvent &p_event) {
invalidated_click=false;
break;
}
- if (over<0 || items[over].separator || items[over].disabled)
+ if (over<0) {
+ hide();
break; //non-activable
+ }
+
+ if (items[over].separator || items[over].disabled)
+ break;
if (items[over].submenu!="") {
@@ -358,10 +370,13 @@ void PopupMenu::_input_event(const InputEvent &p_event) {
}
int over=_get_mouse_over(Point2(m.x,m.y));
- int id = (over<0 || items[over].separator || items[over].disabled)?-1:items[over].ID;
+ int id = (over<0 || items[over].separator || items[over].disabled)?-1:(items[over].ID>=0?items[over].ID:over);
- if (id<0)
+ if (id<0) {
+ mouse_over=-1;
+ update();
break;
+ }
if (items[over].submenu!="" && submenu_over!=over) {
submenu_over=over;
@@ -509,7 +524,7 @@ void PopupMenu::add_icon_item(const Ref<Texture>& p_icon,const String& p_label,i
item.icon=p_icon;
item.text=p_label;
item.accel=p_accel;
- item.ID=(p_ID<0)?idcount++:p_ID;
+ item.ID=p_ID;
items.push_back(item);
update();
}
@@ -518,7 +533,7 @@ void PopupMenu::add_item(const String& p_label,int p_ID,uint32_t p_accel) {
Item item;
item.text=XL_MESSAGE(p_label);
item.accel=p_accel;
- item.ID=(p_ID<0)?idcount++:p_ID;
+ item.ID=p_ID;
items.push_back(item);
update();
}
@@ -527,7 +542,7 @@ void PopupMenu::add_submenu_item(const String& p_label, const String& p_submenu,
Item item;
item.text=XL_MESSAGE(p_label);
- item.ID=(p_ID<0)?idcount++:p_ID;
+ item.ID=p_ID;
item.submenu=p_submenu;
items.push_back(item);
update();
@@ -539,7 +554,7 @@ void PopupMenu::add_icon_check_item(const Ref<Texture>& p_icon,const String& p_l
item.icon=p_icon;
item.text=XL_MESSAGE(p_label);
item.accel=p_accel;
- item.ID=(p_ID<0)?idcount++:p_ID;
+ item.ID=p_ID;
item.checkable=true;
items.push_back(item);
update();
@@ -549,7 +564,7 @@ void PopupMenu::add_check_item(const String& p_label,int p_ID,uint32_t p_accel)
Item item;
item.text=XL_MESSAGE(p_label);
item.accel=p_accel;
- item.ID=(p_ID<0)?idcount++:p_ID;
+ item.ID=p_ID;
item.checkable=true;
items.push_back(item);
update();
@@ -741,7 +756,17 @@ void PopupMenu::activate_item(int p_item) {
ERR_FAIL_INDEX(p_item,items.size());
ERR_FAIL_COND(items[p_item].separator);
- emit_signal("item_pressed",items[p_item].ID);
+ int id = items[p_item].ID>=0?items[p_item].ID:p_item;
+ emit_signal("item_pressed",id);
+
+ //hide all parent PopupMenue's
+ Node *next = get_parent();
+ PopupMenu *pop = next->cast_to<PopupMenu>();
+ while (pop) {
+ pop->hide();
+ next = next->get_parent();
+ pop = next->cast_to<PopupMenu>();
+ }
hide();
}
@@ -764,8 +789,9 @@ void PopupMenu::add_separator() {
void PopupMenu::clear() {
items.clear();
+ mouse_over=-1;
update();
- idcount=0;
+
}
@@ -872,7 +898,7 @@ void PopupMenu::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_item_icon","idx","icon"),&PopupMenu::set_item_icon);
ObjectTypeDB::bind_method(_MD("set_item_accelerator","idx","accel"),&PopupMenu::set_item_accelerator);
ObjectTypeDB::bind_method(_MD("set_item_metadata","idx","metadata"),&PopupMenu::set_item_metadata);
- ObjectTypeDB::bind_method(_MD("set_item_checked","idx"),&PopupMenu::set_item_checked);
+ ObjectTypeDB::bind_method(_MD("set_item_checked","idx","checked"),&PopupMenu::set_item_checked);
ObjectTypeDB::bind_method(_MD("set_item_disabled","idx","disabled"),&PopupMenu::set_item_disabled);
ObjectTypeDB::bind_method(_MD("set_item_submenu","idx","submenu"),&PopupMenu::set_item_submenu);
ObjectTypeDB::bind_method(_MD("set_item_as_separator","idx","enable"),&PopupMenu::set_item_as_separator);
@@ -913,7 +939,7 @@ void PopupMenu::set_invalidate_click_until_motion() {
PopupMenu::PopupMenu() {
- idcount=0;
+
mouse_over=-1;
set_focus_mode(FOCUS_ALL);
diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h
index ed78fe6738..624f4f542a 100644
--- a/scene/gui/popup_menu.h
+++ b/scene/gui/popup_menu.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -59,7 +59,6 @@ class PopupMenu : public Popup {
Timer *submenu_timer;
List<Rect2> autohide_areas;
Vector<Item> items;
- int idcount;
int mouse_over;
int submenu_over;
Rect2 parent_rect;
diff --git a/scene/gui/progress_bar.cpp b/scene/gui/progress_bar.cpp
index e7e2c88f4a..fc0e7be34f 100644
--- a/scene/gui/progress_bar.cpp
+++ b/scene/gui/progress_bar.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/progress_bar.h b/scene/gui/progress_bar.h
index 33b0d5c185..f50df346ac 100644
--- a/scene/gui/progress_bar.h
+++ b/scene/gui/progress_bar.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp
index ad708d16f0..ffcdf98519 100644
--- a/scene/gui/range.cpp
+++ b/scene/gui/range.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -48,20 +48,20 @@ void Range::Shared::emit_value_changed() {
}
}
-void Range::_changed_notify() {
+void Range::_changed_notify(const char *p_what) {
emit_signal("changed",shared->val);
update();
- _change_notify();
+ _change_notify(p_what);
}
-void Range::Shared::emit_changed() {
+void Range::Shared::emit_changed(const char *p_what) {
for (Set<Range*>::Element *E=owners.front();E;E=E->next()) {
Range *r=E->get();
if (!r->is_inside_tree())
continue;
- r->_changed_notify();
+ r->_changed_notify(p_what);
}
}
@@ -77,7 +77,11 @@ void Range::set_val(double p_val) {
if (p_val<shared->min)
p_val=shared->min;
-
+
+ //avoid to set -0
+ if (p_val == 0)
+ p_val = 0;
+
if (shared->val==p_val)
return;
@@ -90,20 +94,20 @@ void Range::set_min(double p_min) {
shared->min=p_min;
set_val(shared->val);
- shared->emit_changed();
+ shared->emit_changed("range/min");
}
void Range::set_max(double p_max) {
shared->max=p_max;
set_val(shared->val);
- shared->emit_changed();
+ shared->emit_changed("range/max");
}
void Range::set_step(double p_step) {
shared->step=p_step;
- shared->emit_changed();
+ shared->emit_changed("range/step");
}
void Range::set_page(double p_page) {
@@ -111,7 +115,7 @@ void Range::set_page(double p_page) {
shared->page=p_page;
set_val(shared->val);
- shared->emit_changed();
+ shared->emit_changed("range/page");
}
double Range::get_val() const {
@@ -216,11 +220,10 @@ void Range::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_val"),&Range::get_val);
ObjectTypeDB::bind_method(_MD("get_value"),&Range::get_val);
ObjectTypeDB::bind_method(_MD("get_min"),&Range::get_min);
- ObjectTypeDB::bind_method(_MD("get_max"),&Range::get_max);
- ObjectTypeDB::bind_method(_MD("get_step"),&Range::get_step);
- ObjectTypeDB::bind_method(_MD("get_page"),&Range::get_page);
- ObjectTypeDB::bind_method(_MD("get_unit_value"),&Range::get_unit_value);
- ObjectTypeDB::bind_method(_MD("get_rounded_values"),&Range::get_rounded_values);
+ ObjectTypeDB::bind_method(_MD("get_max"),&Range::get_max);
+ ObjectTypeDB::bind_method(_MD("get_step"),&Range::get_step);
+ ObjectTypeDB::bind_method(_MD("get_page"),&Range::get_page);
+ ObjectTypeDB::bind_method(_MD("get_unit_value"),&Range::get_unit_value);
ObjectTypeDB::bind_method(_MD("set_val","value"),&Range::set_val);
ObjectTypeDB::bind_method(_MD("set_value","value"),&Range::set_val);
ObjectTypeDB::bind_method(_MD("set_min","minimum"),&Range::set_min);
@@ -228,7 +231,8 @@ void Range::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_step","step"),&Range::set_step);
ObjectTypeDB::bind_method(_MD("set_page","pagesize"),&Range::set_page);
ObjectTypeDB::bind_method(_MD("set_unit_value","value"),&Range::set_unit_value);
- ObjectTypeDB::bind_method(_MD("set_rounded_values"),&Range::set_rounded_values);
+ ObjectTypeDB::bind_method(_MD("set_rounded_values","enabled"),&Range::set_rounded_values);
+ ObjectTypeDB::bind_method(_MD("is_rounded_values"),&Range::is_rounded_values);
ObjectTypeDB::bind_method(_MD("set_exp_unit_value","enabled"),&Range::set_exp_unit_value);
ObjectTypeDB::bind_method(_MD("is_unit_value_exp"),&Range::is_unit_value_exp);
@@ -243,17 +247,19 @@ void Range::_bind_methods() {
ADD_PROPERTY( PropertyInfo( Variant::REAL, "range/step" ), _SCS("set_step"), _SCS("get_step") );
ADD_PROPERTY( PropertyInfo( Variant::REAL, "range/page" ), _SCS("set_page"), _SCS("get_page") );
ADD_PROPERTY( PropertyInfo( Variant::REAL, "range/value" ), _SCS("set_val"), _SCS("get_val") );
- ADD_PROPERTY( PropertyInfo( Variant::REAL, "range/exp_edit" ), _SCS("set_exp_unit_value"), _SCS("is_unit_value_exp") );
- ADD_PROPERTY( PropertyInfo( Variant::BOOL, "rounded_values" ), _SCS("set_rounded_values"), _SCS("get_rounded_values") );
+ ADD_PROPERTY( PropertyInfo( Variant::BOOL, "range/exp_edit" ), _SCS("set_exp_unit_value"), _SCS("is_unit_value_exp") );
+ ADD_PROPERTY( PropertyInfo( Variant::BOOL, "range/rounded" ), _SCS("set_rounded_values"), _SCS("is_rounded_values") );
}
-void Range::set_rounded_values(bool p){
- _rounded_values = p;
+void Range::set_rounded_values(bool p_enable) {
+
+ _rounded_values = p_enable;
}
-bool Range::get_rounded_values() const{
- return _rounded_values;
+bool Range::is_rounded_values() const {
+
+ return _rounded_values;
}
void Range::set_exp_unit_value(bool p_enable) {
diff --git a/scene/gui/range.h b/scene/gui/range.h
index 48361ddb0e..d96ecdfb0b 100644
--- a/scene/gui/range.h
+++ b/scene/gui/range.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -44,7 +44,7 @@ class Range : public Control {
bool exp_unit_value;
Set<Range*> owners;
void emit_value_changed();
- void emit_changed();
+ void emit_changed(const char *p_what="");
};
Shared *shared;
@@ -55,7 +55,7 @@ class Range : public Control {
void _share(Node *p_range);
void _value_changed_notify();
- void _changed_notify();
+ void _changed_notify(const char *p_what="");
protected:
@@ -72,22 +72,23 @@ public:
void set_step(double p_step);
void set_page(double p_page);
void set_unit_value(double p_value);
- void set_rounded_values(bool);
-
+
double get_val() const;
double get_min() const;
double get_max() const;
double get_step() const;
double get_page() const;
double get_unit_value() const;
- bool get_rounded_values() const;
+
+ void set_rounded_values(bool p_enable);
+ bool is_rounded_values() const;
void set_exp_unit_value(bool p_enable);
bool is_unit_value_exp() const;
void share(Range *p_range);
void unshare();
-
+
Range();
~Range();
diff --git a/scene/gui/reference_frame.cpp b/scene/gui/reference_frame.cpp
index b90ea8292d..d037664a62 100644
--- a/scene/gui/reference_frame.cpp
+++ b/scene/gui/reference_frame.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/reference_frame.h b/scene/gui/reference_frame.h
index 8915b1df0c..5d3694e6e8 100644
--- a/scene/gui/reference_frame.h
+++ b/scene/gui/reference_frame.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 7a607786ee..d4ac2652dc 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,35 +30,62 @@
#include "scene/scene_string_names.h"
#include "os/keyboard.h"
#include "os/os.h"
-RichTextLabel::Item *RichTextLabel::_get_next_item(Item* p_item) {
+RichTextLabel::Item *RichTextLabel::_get_next_item(Item* p_item,bool p_free) {
- if (p_item->subitems.size()) {
+ if (p_free) {
- return p_item->subitems.front()->get();
- } else if (!p_item->parent) {
- return NULL;
- } else if (p_item->E->next()) {
+ if (p_item->subitems.size()) {
+
+ return p_item->subitems.front()->get();
+ } else if (!p_item->parent) {
+ return NULL;
+ } else if (p_item->E->next()) {
+
+ return p_item->E->next()->get();
+ } else {
+ //go up until something with a next is found
+ while (p_item->parent && !p_item->E->next()) {
+ p_item=p_item->parent;
+ }
+
+
+ if (p_item->parent)
+ return p_item->E->next()->get();
+ else
+ return NULL;
- return p_item->E->next()->get();
- } else {
- //go up until something with a next is found
- while (p_item->parent && !p_item->E->next()) {
- p_item=p_item->parent;
}
+ } else {
+ if (p_item->subitems.size() && p_item->type!=ITEM_TABLE) {
- if (p_item && p_item->parent)
- return p_item->E->next()->get();
- else
+ return p_item->subitems.front()->get();
+ } else if (p_item->type==ITEM_FRAME) {
return NULL;
+ } else if (p_item->E->next()) {
+
+ return p_item->E->next()->get();
+ } else {
+ //go up until something with a next is found
+ while (p_item->type!=ITEM_FRAME && !p_item->E->next()) {
+ p_item=p_item->parent;
+ }
+
+
+ if (p_item->type!=ITEM_FRAME)
+ return p_item->E->next()->get();
+ else
+ return NULL;
+ }
}
return NULL;
}
-void RichTextLabel::_process_line(int &y, int p_width, int p_line, ProcessMode p_mode,const Ref<Font> &p_base_font,const Color &p_base_color,const Point2i& p_click_pos,Item **r_click_item,int *r_click_char,bool *r_outside,int p_char_count) {
+
+void RichTextLabel::_process_line(ItemFrame *p_frame,const Vector2& p_ofs,int &y, int p_width, int p_line, ProcessMode p_mode,const Ref<Font> &p_base_font,const Color &p_base_color,const Point2i& p_click_pos,Item **r_click_item,int *r_click_char,bool *r_outside,int p_char_count) {
RID ci;
if (r_outside)
@@ -70,7 +97,7 @@ void RichTextLabel::_process_line(int &y, int p_width, int p_line, ProcessMode p
*r_click_item=NULL;
}
- Line &l = lines[p_line];
+ Line &l = p_frame->lines[p_line];
Item *it = l.from;
@@ -91,10 +118,13 @@ void RichTextLabel::_process_line(int &y, int p_width, int p_line, ProcessMode p
l.offset_caches.clear();
l.height_caches.clear();
l.char_count=0;
+ l.minimum_width=0;
}
int wofs=margin;
int spaces_size=0;
+ int align_ofs=0;
+
if (p_mode!=PROCESS_CACHE && align!=ALIGN_FILL)
wofs+=line_ofs;
@@ -125,7 +155,7 @@ void RichTextLabel::_process_line(int &y, int p_width, int p_line, ProcessMode p
case ALIGN_LEFT: l.offset_caches.push_back(0); break;\
case ALIGN_CENTER: l.offset_caches.push_back(((p_width-margin)-used)/2); break;\
case ALIGN_RIGHT: l.offset_caches.push_back(((p_width-margin)-used)); break;\
- case ALIGN_FILL: l.offset_caches.push_back((p_width-margin)-used+spaces_size); break;\
+ case ALIGN_FILL: l.offset_caches.push_back((p_width-margin)-used/*+spaces_size*/); break;\
}\
l.height_caches.push_back(line_height);\
l.space_caches.push_back(spaces);\
@@ -135,10 +165,11 @@ void RichTextLabel::_process_line(int &y, int p_width, int p_line, ProcessMode p
spaces=0;\
spaces_size=0;\
wofs=begin;\
+ align_ofs=0;\
if (p_mode!=PROCESS_CACHE) {\
lh=line<l.height_caches.size()?l.height_caches[line]:1;\
}\
- if (p_mode==PROCESS_POINTER && r_click_item && p_click_pos.y>=y && p_click_pos.y<=y+lh && p_click_pos.x<wofs) {\
+ if (p_mode==PROCESS_POINTER && r_click_item && p_click_pos.y>=p_ofs.y+y && p_click_pos.y<=p_ofs.y+y+lh && p_click_pos.x<p_ofs.x+wofs) {\
if (r_outside) *r_outside=true;\
*r_click_item=it;\
*r_click_char=rchar;\
@@ -148,12 +179,15 @@ void RichTextLabel::_process_line(int &y, int p_width, int p_line, ProcessMode p
#define ENSURE_WIDTH(m_width) \
+ if (p_mode==PROCESS_CACHE) { \
+ l.minimum_width=MAX(l.minimum_width,wofs+m_width);\
+ }\
if (wofs + m_width > p_width) {\
if (p_mode==PROCESS_CACHE) {\
if (spaces>0) \
spaces-=1;\
}\
- if (p_mode==PROCESS_POINTER && r_click_item && p_click_pos.y>=y && p_click_pos.y<=y+lh && p_click_pos.x>wofs) {\
+ if (p_mode==PROCESS_POINTER && r_click_item && p_click_pos.y>=p_ofs.y+y && p_click_pos.y<=p_ofs.y+y+lh && p_click_pos.x>p_ofs.x+wofs) {\
if (r_outside) *r_outside=true; \
*r_click_item=it;\
*r_click_char=rchar;\
@@ -165,7 +199,7 @@ void RichTextLabel::_process_line(int &y, int p_width, int p_line, ProcessMode p
#define ADVANCE(m_width) \
{\
- if (p_mode==PROCESS_POINTER && r_click_item && p_click_pos.y>=y && p_click_pos.y<=y+lh && p_click_pos.x>=wofs && p_click_pos.x<wofs+m_width) {\
+ if (p_mode==PROCESS_POINTER && r_click_item && p_click_pos.y>=p_ofs.y+y && p_click_pos.y<=p_ofs.y+y+lh && p_click_pos.x>=p_ofs.x+wofs && p_click_pos.x<p_ofs.x+wofs+m_width) {\
if (r_outside) *r_outside=false; \
*r_click_item=it;\
*r_click_char=rchar;\
@@ -218,8 +252,10 @@ if (m_height > line_height) {\
underline=true;
}
+
} else if (p_mode==PROCESS_CACHE) {
l.char_count+=text->text.length();
+
}
rchar=0;
@@ -246,6 +282,8 @@ if (m_height > line_height) {\
if (c[end]==' ') {
+ fw+=cw;
+ /*
if (p_mode==PROCESS_CACHE) {
fw+=cw;
} else if (align==ALIGN_FILL && line<l.space_caches.size() && l.space_caches[line]>0) {
@@ -254,7 +292,7 @@ if (m_height > line_height) {\
found_space=true;
} else {
fw+=cw;
- }
+ }*/
} else {
fw+=cw;
}
@@ -262,23 +300,26 @@ if (m_height > line_height) {\
end++;
}
-
-
ENSURE_WIDTH(w);
-
//print_line("END: "+String::chr(c[end])+".");
if (end && c[end-1]==' ') {
- spaces++;
if (p_mode==PROCESS_CACHE) {
spaces_size+=font->get_char_size(' ').width;
+ } else if (align==ALIGN_FILL) {
+ int ln = MIN(l.offset_caches.size()-1,line);
+ if (l.space_caches[ln]) {
+ align_ofs = spaces * l.offset_caches[ln] / l.space_caches[ln];
+ }
}
+ spaces++;
+ /*
if (found_space) {
int ln = MIN(l.offset_caches.size()-1,line);
fw+=l.offset_caches[ln]/l.space_caches[ln];
- }
+ }*/
}
@@ -294,7 +335,7 @@ if (m_height > line_height) {\
- if (p_mode==PROCESS_POINTER && r_click_char && p_click_pos.y>=y && p_click_pos.y<=y+lh) {
+ if (p_mode==PROCESS_POINTER && r_click_char && p_click_pos.y>=p_ofs.y+y && p_click_pos.y<=p_ofs.y+y+lh) {
//int o = (wofs+w)-p_click_pos.x;
@@ -303,7 +344,7 @@ if (m_height > line_height) {\
cw=tab_size*font->get_char_size(' ').width;
}
- if (p_click_pos.x-cw/2>pofs) {
+ if (p_click_pos.x-cw/2>p_ofs.x+align_ofs+pofs) {
rchar=int((&c[i])-cf);
//print_line("GOT: "+itos(rchar));
@@ -337,13 +378,13 @@ if (m_height > line_height) {\
if (selected) {
cw = font->get_char_size(c[i],c[i+1]).x;
- draw_rect(Rect2(pofs,y,cw,lh),selection_bg);
+ draw_rect(Rect2(p_ofs.x+pofs,p_ofs.y+y,cw,lh),selection_bg);
if (visible)
- font->draw_char(ci,Point2(pofs,y+lh-(fh-ascent)),c[i],c[i+1],selection_fg);
+ font->draw_char(ci,p_ofs+Point2(align_ofs+pofs,y+lh-(fh-ascent)),c[i],c[i+1],selection_fg);
} else {
if (visible)
- cw=font->draw_char(ci,Point2(pofs,y+lh-(fh-ascent)),c[i],c[i+1],color);
+ cw=font->draw_char(ci,p_ofs+Point2(align_ofs+pofs,y+lh-(fh-ascent)),c[i],c[i+1],color);
}
p_char_count++;
@@ -359,7 +400,7 @@ if (m_height > line_height) {\
uc.a*=0.5;
//VS::get_singleton()->canvas_item_add_line(ci,Point2(pofs,y+ascent+2),Point2(pofs+cw,y+ascent+2),uc);
int uy = y+lh-fh+ascent+2;
- VS::get_singleton()->canvas_item_add_line(ci,Point2(pofs,uy),Point2(pofs+cw,uy),uc);
+ VS::get_singleton()->canvas_item_add_line(ci,p_ofs+Point2(align_ofs+pofs,uy),p_ofs+Point2(align_ofs+pofs+cw,uy),uc);
}
ofs+=cw;
}
@@ -397,7 +438,7 @@ if (m_height > line_height) {\
bool visible = visible_characters<0 || p_char_count<visible_characters;
if (p_mode==PROCESS_DRAW && visible) {
- img->image->draw(ci,Point2(wofs,y+lh-font->get_descent()-img->image->get_height()));
+ img->image->draw(ci,p_ofs+Point2(align_ofs+wofs,y+lh-font->get_descent()-img->image->get_height()));
}
p_char_count++;
@@ -435,6 +476,148 @@ if (m_height > line_height) {\
#endif
} break;
+ case ITEM_TABLE: {
+
+ lh=0;
+ ItemTable *table = static_cast<ItemTable*>(it);
+ int hseparation=get_constant("table_hseparation");
+ int vseparation=get_constant("table_vseparation");
+ Color ccolor = _find_color(table,p_base_color);
+ Vector2 draw_ofs = Point2(wofs,y);
+ int max_y=get_size().height;
+
+ if (p_mode==PROCESS_CACHE) {
+
+ int idx=0;
+ //set minimums to zero
+ for(int i=0;i<table->columns.size();i++) {
+ table->columns[i].min_width=0;
+ table->columns[i].width=0;
+ }
+ //compute minimum width for each cell
+ for (List<Item*>::Element *E=table->subitems.front();E;E=E->next()) {
+ ERR_CONTINUE(E->get()->type!=ITEM_FRAME); //children should all be frames
+ ItemFrame *frame = static_cast<ItemFrame*>(E->get());
+
+ int column = idx % table->columns.size();
+
+ int ly=0;
+
+
+ for(int i=0;i<frame->lines.size();i++) {
+
+ _process_line(frame,Point2(),ly,p_width,i,PROCESS_CACHE,cfont,Color());
+ table->columns[column].min_width=MAX( table->columns[i].min_width, frame->lines[i].minimum_width );
+ }
+ idx++;
+ }
+
+ //compute available width and total radio (for expanders)
+
+
+ int total_ratio=0;
+ int available_width=p_width - hseparation * (table->columns.size() -1);
+ table->total_width=hseparation;
+
+ for(int i=0;i<table->columns.size();i++) {
+ available_width-=table->columns[i].min_width;
+ if (table->columns[i].expand)
+ total_ratio+=table->columns[i].expand_ratio;
+ }
+
+ //assign actual widths
+
+ for(int i=0;i<table->columns.size();i++) {
+ table->columns[i].width = table->columns[i].min_width;
+ if (table->columns[i].expand)
+ table->columns[i].width+=table->columns[i].expand_ratio*available_width/total_ratio;
+ table->total_width+=table->columns[i].width+hseparation;
+ }
+
+ //compute caches properly again with the right width
+ idx=0;
+ for (List<Item*>::Element *E=table->subitems.front();E;E=E->next()) {
+ ERR_CONTINUE(E->get()->type!=ITEM_FRAME); //children should all be frames
+ ItemFrame *frame = static_cast<ItemFrame*>(E->get());
+
+ int column = idx % table->columns.size();
+
+
+ for(int i=0;i<frame->lines.size();i++) {
+
+ int ly=0;
+ _process_line(frame,Point2(),ly,table->columns[column].width,i,PROCESS_CACHE,cfont,Color());
+ frame->lines[i].height_cache=ly; //actual height
+ frame->lines[i].height_accum_cache=ly; //actual height
+ }
+ idx++;
+ }
+
+ }
+
+
+
+ Point2 offset(align_ofs+hseparation,vseparation);
+
+ int row_height=0;
+ //draw using computed caches
+ int idx=0;
+ for (List<Item*>::Element *E=table->subitems.front();E;E=E->next()) {
+ ERR_CONTINUE(E->get()->type!=ITEM_FRAME); //children should all be frames
+ ItemFrame *frame = static_cast<ItemFrame*>(E->get());
+
+ int column = idx % table->columns.size();
+
+ int ly=0;
+ int yofs=0;
+
+
+ int lines_h = frame->lines[frame->lines.size()-1].height_accum_cache - (frame->lines[0].height_accum_cache - frame->lines[0].height_cache);
+ int lines_ofs = p_ofs.y+offset.y+draw_ofs.y;
+
+ bool visible = lines_ofs < get_size().height && lines_ofs+lines_h >=0;
+
+ for(int i=0;i<frame->lines.size();i++) {
+
+
+ if (visible) {
+ if (p_mode==PROCESS_DRAW) {
+ _process_line(frame,p_ofs+offset+draw_ofs+Vector2(0,yofs),ly,table->columns[column].width,i,PROCESS_DRAW,cfont,ccolor);
+ } else if (p_mode==PROCESS_POINTER) {
+ _process_line(frame,p_ofs+offset+draw_ofs+Vector2(0,yofs),ly,table->columns[column].width,i,PROCESS_POINTER,cfont,ccolor,p_click_pos,r_click_item,r_click_char,r_outside);
+ }
+ }
+
+ yofs+=frame->lines[i].height_cache;
+ if (p_mode==PROCESS_CACHE) {
+ frame->lines[i].height_accum_cache=offset.y+draw_ofs.y+frame->lines[i].height_cache;
+ }
+
+ }
+
+ row_height=MAX(yofs,row_height);
+ offset.x+=table->columns[column].width+hseparation;
+
+ if (column==table->columns.size()-1) {
+
+ offset.y+=row_height+vseparation;
+ offset.x=hseparation;
+ row_height=0;
+ }
+ idx++;
+ }
+
+ int total_height = offset.y;
+ if (row_height) {
+ total_height=row_height+vseparation;
+ }
+
+
+
+ ADVANCE( table->total_width );
+ CHECK_HEIGHT( total_height );
+
+ } break;
default: {}
@@ -445,7 +628,7 @@ if (m_height > line_height) {\
it = _get_next_item(it);
- if (p_mode == PROCESS_POINTER && r_click_item && itp && !it && p_click_pos.y>y+lh) {
+ if (p_mode == PROCESS_POINTER && r_click_item && itp && !it && p_click_pos.y>p_ofs.y+y+lh) {
//at the end of all, return this
if (r_outside) *r_outside=true;
*r_click_item=itp;
@@ -453,9 +636,9 @@ if (m_height > line_height) {\
return;
}
- if (it && (p_line+1 < lines.size()) && lines[p_line+1].from==it) {
+ if (it && (p_line+1 < p_frame->lines.size()) && p_frame->lines[p_line+1].from==it) {
- if (p_mode==PROCESS_POINTER && r_click_item && p_click_pos.y>=y && p_click_pos.y<=y+lh) {
+ if (p_mode==PROCESS_POINTER && r_click_item && p_click_pos.y>=p_ofs.y+y && p_click_pos.y<=p_ofs.y+y+lh) {
//went to next line, but pointer was on the previous one
if (r_outside) *r_outside=true;
*r_click_item=itp;
@@ -493,8 +676,8 @@ void RichTextLabel::_scroll_changed(double) {
void RichTextLabel::_update_scroll() {
int total_height=0;
- if (lines.size())
- total_height=lines[lines.size()-1].height_accum_cache;
+ if (main->lines.size())
+ total_height=main->lines[main->lines.size()-1].height_accum_cache;
bool exceeds = total_height > get_size().height && scroll_active;
@@ -503,18 +686,18 @@ void RichTextLabel::_update_scroll() {
if (exceeds) {
scroll_visible=true;
- first_invalid_line=0;
+ main->first_invalid_line=0;
scroll_w=vscroll->get_combined_minimum_size().width;
vscroll->show();
vscroll->set_anchor_and_margin( MARGIN_LEFT, ANCHOR_END,scroll_w);
- _validate_line_caches();
+ _validate_line_caches(main);
} else {
scroll_visible=false;
vscroll->hide();
scroll_w=0;
- _validate_line_caches();
+ _validate_line_caches(main);
}
}
@@ -527,7 +710,7 @@ void RichTextLabel::_notification(int p_what) {
case NOTIFICATION_RESIZED: {
- first_invalid_line=0; //invalidate ALL
+ main->first_invalid_line=0; //invalidate ALL
update();
} break;
@@ -535,7 +718,7 @@ void RichTextLabel::_notification(int p_what) {
if (use_bbcode)
parse_bbcode(bbcode);
- first_invalid_line=0; //invalidate ALL
+ main->first_invalid_line=0; //invalidate ALL
update();
} break;
@@ -550,7 +733,7 @@ void RichTextLabel::_notification(int p_what) {
} break;
case NOTIFICATION_DRAW: {
- _validate_line_caches();
+ _validate_line_caches(main);
_update_scroll();
@@ -571,25 +754,25 @@ void RichTextLabel::_notification(int p_what) {
int from_line = 0;
int total_chars = 0;
- while (from_line<lines.size()) {
+ while (from_line<main->lines.size()) {
- if (lines[from_line].height_accum_cache>=ofs)
+ if (main->lines[from_line].height_accum_cache>=ofs)
break;
from_line++;
- total_chars+=lines[from_line].char_count;
+ total_chars+=main->lines[from_line].char_count;
}
- if (from_line>=lines.size())
+ if (from_line>=main->lines.size())
break; //nothing to draw
- int y = (lines[from_line].height_accum_cache - lines[from_line].height_cache) - ofs;
+ int y = (main->lines[from_line].height_accum_cache - main->lines[from_line].height_cache) - ofs;
Ref<Font> base_font=get_font("normal_font");
Color base_color=get_color("default_color");
- while (y<size.height && from_line<lines.size()) {
+ while (y<size.height && from_line<main->lines.size()) {
- _process_line(y,size.width-scroll_w,from_line,PROCESS_DRAW,base_font,base_color,Point2i(),NULL,NULL,NULL,total_chars);
- total_chars+=lines[from_line].char_count;
+ _process_line(main,Point2(),y,size.width-scroll_w,from_line,PROCESS_DRAW,base_font,base_color,Point2i(),NULL,NULL,NULL,total_chars);
+ total_chars+=main->lines[from_line].char_count;
from_line++;
}
}
@@ -597,7 +780,7 @@ void RichTextLabel::_notification(int p_what) {
}
-void RichTextLabel::_find_click(const Point2i& p_click,Item **r_click_item,int *r_click_char,bool *r_outside) {
+void RichTextLabel::_find_click(ItemFrame* p_frame,const Point2i& p_click,Item **r_click_item,int *r_click_char,bool *r_outside) {
if (r_click_item)
*r_click_item=NULL;
@@ -609,26 +792,26 @@ void RichTextLabel::_find_click(const Point2i& p_click,Item **r_click_item,int *
//todo, change to binary search
int from_line = 0;
- while (from_line<lines.size()) {
+ while (from_line<p_frame->lines.size()) {
- if (lines[from_line].height_accum_cache>=ofs)
+ if (p_frame->lines[from_line].height_accum_cache>=ofs)
break;
from_line++;
}
- if (from_line>=lines.size())
+ if (from_line>=p_frame->lines.size())
return;
- int y = (lines[from_line].height_accum_cache - lines[from_line].height_cache) - ofs;
+ int y = (p_frame->lines[from_line].height_accum_cache - p_frame->lines[from_line].height_cache) - ofs;
Ref<Font> base_font=get_font("normal_font");
Color base_color=get_color("default_color");
- while (y<size.height && from_line<lines.size()) {
+ while (y<size.height && from_line<p_frame->lines.size()) {
- _process_line(y,size.width-scroll_w,from_line,PROCESS_POINTER,base_font,base_color,p_click,r_click_item,r_click_char,r_outside);
+ _process_line(p_frame,Point2(),y,size.width-scroll_w,from_line,PROCESS_POINTER,base_font,base_color,p_click,r_click_item,r_click_char,r_outside);
if (r_click_item && *r_click_item)
return;
from_line++;
@@ -643,13 +826,13 @@ Control::CursorShape RichTextLabel::get_cursor_shape(const Point2& p_pos) const
if (!underline_meta || selection.click)
return CURSOR_ARROW;
- if (first_invalid_line<lines.size())
+ if (main->first_invalid_line<main->lines.size())
return CURSOR_ARROW; //invalid
int line=0;
Item *item=NULL;
- ((RichTextLabel*)(this))->_find_click(p_pos,&item,&line);
+ ((RichTextLabel*)(this))->_find_click(main,p_pos,&item,&line);
if (item && ((RichTextLabel*)(this))->_find_meta(item,NULL))
@@ -665,7 +848,7 @@ void RichTextLabel::_input_event(InputEvent p_event) {
case InputEvent::MOUSE_BUTTON: {
- if (first_invalid_line<lines.size())
+ if (main->first_invalid_line<main->lines.size())
return;
const InputEventMouseButton& b = p_event.mouse_button;
@@ -680,7 +863,7 @@ void RichTextLabel::_input_event(InputEvent p_event) {
Item *item=NULL;
bool outside;
- _find_click(Point2i(b.x,b.y),&item,&line,&outside);
+ _find_click(main,Point2i(b.x,b.y),&item,&line,&outside);
if (item) {
@@ -719,7 +902,7 @@ void RichTextLabel::_input_event(InputEvent p_event) {
case InputEvent::KEY: {
const InputEventKey &k=p_event.key;
- if (k.pressed) {
+ if (k.pressed && !k.mod.alt && !k.mod.shift && !k.mod.meta) {
bool handled=true;
switch(k.scancode) {
case KEY_PAGEUP: {
@@ -765,6 +948,7 @@ void RichTextLabel::_input_event(InputEvent p_event) {
default: handled=false;
}
+
if (handled)
accept_event();
}
@@ -772,7 +956,7 @@ void RichTextLabel::_input_event(InputEvent p_event) {
} break;
case InputEvent::MOUSE_MOTION: {
- if (first_invalid_line<lines.size())
+ if (main->first_invalid_line<main->lines.size())
return;
const InputEventMouseMotion& m = p_event.mouse_motion;
@@ -781,7 +965,7 @@ void RichTextLabel::_input_event(InputEvent p_event) {
int line=0;
Item *item=NULL;
- _find_click(Point2i(m.x,m.y),&item,&line);
+ _find_click(main,Point2i(m.x,m.y),&item,&line);
if (!item)
return; // do not update
@@ -949,9 +1133,9 @@ bool RichTextLabel::_find_meta(Item *p_item,Variant *r_meta) {
}
-void RichTextLabel::_validate_line_caches() {
+void RichTextLabel::_validate_line_caches(ItemFrame* p_frame) {
- if (first_invalid_line==lines.size())
+ if (p_frame->first_invalid_line==p_frame->lines.size())
return;
//validate invalid lines!s
@@ -959,24 +1143,24 @@ void RichTextLabel::_validate_line_caches() {
Ref<Font> base_font=get_font("normal_font");
- for(int i=first_invalid_line;i<lines.size();i++) {
+ for(int i=p_frame->first_invalid_line;i<p_frame->lines.size();i++) {
int y=0;
- _process_line(y,size.width-scroll_w,i,PROCESS_CACHE,base_font,Color());
- lines[i].height_cache=y;
- lines[i].height_accum_cache=y;
+ _process_line(p_frame,Point2(),y,size.width-scroll_w,i,PROCESS_CACHE,base_font,Color());
+ p_frame->lines[i].height_cache=y;
+ p_frame->lines[i].height_accum_cache=y;
if (i>0)
- lines[i].height_accum_cache+=lines[i-1].height_accum_cache;
+ p_frame->lines[i].height_accum_cache+=p_frame->lines[i-1].height_accum_cache;
}
int total_height=0;
- if (lines.size())
- total_height=lines[lines.size()-1].height_accum_cache;
+ if (p_frame->lines.size())
+ total_height=p_frame->lines[p_frame->lines.size()-1].height_accum_cache;
- first_invalid_line=lines.size();
+ main->first_invalid_line=p_frame->lines.size();
updating_scroll=true;
vscroll->set_max(total_height);
@@ -989,17 +1173,20 @@ void RichTextLabel::_validate_line_caches() {
}
-void RichTextLabel::_invalidate_current_line() {
+void RichTextLabel::_invalidate_current_line(ItemFrame* p_frame) {
- if (lines.size()-1 <= first_invalid_line) {
+ if (p_frame->lines.size()-1 <= p_frame->first_invalid_line) {
- first_invalid_line=lines.size()-1;
+ p_frame->first_invalid_line=p_frame->lines.size()-1;
update();
}
}
void RichTextLabel::add_text(const String& p_text) {
+ if (current->type==ITEM_TABLE)
+ return; //can't add anything here
+
int pos=0;
while (pos<p_text.length()) {
@@ -1026,7 +1213,7 @@ void RichTextLabel::add_text(const String& p_text) {
//append text condition!
ItemText *ti = static_cast<ItemText*>(current->subitems.back()->get());
ti->text+=line;
- _invalidate_current_line();
+ _invalidate_current_line(main);
} else {
//append item condition
@@ -1042,11 +1229,11 @@ void RichTextLabel::add_text(const String& p_text) {
if (eol) {
ItemNewline *item = memnew( ItemNewline );
- item->line=lines.size();
+ item->line=current_frame->lines.size();
_add_item(item,false);
- lines.resize(lines.size()+1);
- lines[lines.size()-1].from=item;
- _invalidate_current_line();
+ current_frame->lines.resize(current_frame->lines.size()+1);
+ current_frame->lines[current_frame->lines.size()-1].from=item;
+ _invalidate_current_line(current_frame);
}
@@ -1054,25 +1241,38 @@ void RichTextLabel::add_text(const String& p_text) {
}
}
-void RichTextLabel::_add_item(Item *p_item, bool p_enter) {
+void RichTextLabel::_add_item(Item *p_item, bool p_enter, bool p_ensure_newline) {
+
+
p_item->parent=current;
p_item->E=current->subitems.push_back(p_item);
p_item->index=current_idx++;
+
if (p_enter)
current=p_item;
- if (lines[lines.size()-1].from==NULL) {
- lines[lines.size()-1].from=p_item;
+ if (p_ensure_newline && current_frame->lines[current_frame->lines.size()-1].from) {
+ _invalidate_current_line(current_frame);
+ current_frame->lines.resize( current_frame->lines.size() +1 );
+
}
- _invalidate_current_line();
+ if (current_frame->lines[current_frame->lines.size()-1].from==NULL) {
+ current_frame->lines[current_frame->lines.size()-1].from=p_item;
+ }
+ p_item->line=current_frame->lines.size()-1;
+
+ _invalidate_current_line(current_frame);
}
void RichTextLabel::add_image(const Ref<Texture>& p_image) {
+ if (current->type==ITEM_TABLE)
+ return;
+
ERR_FAIL_COND(p_image.is_null());
ItemImage *item = memnew( ItemImage );
@@ -1083,15 +1283,18 @@ void RichTextLabel::add_image(const Ref<Texture>& p_image) {
void RichTextLabel::add_newline() {
+ if (current->type==ITEM_TABLE)
+ return;
ItemNewline *item = memnew( ItemNewline );
- item->line=lines.size();
- lines.resize(lines.size()+1);
+ item->line=current_frame->lines.size();
+ current_frame->lines.resize(current_frame->lines.size()+1);
_add_item(item,false);
}
void RichTextLabel::push_font(const Ref<Font>& p_font) {
+ ERR_FAIL_COND(current->type==ITEM_TABLE);
ERR_FAIL_COND(p_font.is_null());
ItemFont *item = memnew( ItemFont );
@@ -1101,6 +1304,7 @@ void RichTextLabel::push_font(const Ref<Font>& p_font) {
}
void RichTextLabel::push_color(const Color& p_color) {
+ ERR_FAIL_COND(current->type==ITEM_TABLE);
ItemColor *item = memnew( ItemColor );
item->color=p_color;
@@ -1109,6 +1313,7 @@ void RichTextLabel::push_color(const Color& p_color) {
}
void RichTextLabel::push_underline() {
+ ERR_FAIL_COND(current->type==ITEM_TABLE);
ItemUnderline *item = memnew( ItemUnderline );
_add_item(item,true);
@@ -1117,47 +1322,40 @@ void RichTextLabel::push_underline() {
void RichTextLabel::push_align(Align p_align) {
- lines.resize(lines.size()+1);
+ ERR_FAIL_COND(current->type==ITEM_TABLE);
ItemAlign *item = memnew( ItemAlign );
item->align=p_align;
- _add_item(item,true);
-
- ItemNewline *itemnl = memnew( ItemNewline );
- itemnl->line=lines.size()-1;
- _add_item(itemnl,false);
+ _add_item(item,true,true);
}
void RichTextLabel::push_indent(int p_level) {
+ ERR_FAIL_COND(current->type==ITEM_TABLE);
ERR_FAIL_COND(p_level<0);
- lines.resize(lines.size()+1);
-
ItemIndent *item = memnew( ItemIndent );
item->level=p_level;
- _add_item(item,true);
-
- ItemNewline *itemnl = memnew( ItemNewline );
- itemnl->line=lines.size()-1;
- _add_item(itemnl,false);
+ _add_item(item,true,true);
}
void RichTextLabel::push_list(ListType p_list) {
+ ERR_FAIL_COND(current->type==ITEM_TABLE);
ERR_FAIL_INDEX(p_list,3);
ItemList *item = memnew( ItemList );
item->list_type=p_list;
- _add_item(item,true);
+ _add_item(item,true,true);
}
void RichTextLabel::push_meta(const Variant& p_meta) {
+ ERR_FAIL_COND(current->type==ITEM_TABLE);
ItemMeta *item = memnew( ItemMeta );
item->meta=p_meta;
@@ -1165,9 +1363,62 @@ void RichTextLabel::push_meta(const Variant& p_meta) {
}
+void RichTextLabel::push_table(int p_columns) {
+
+ ERR_FAIL_COND( p_columns < 1);
+ ItemTable *item = memnew( ItemTable );
+
+ item->columns.resize(p_columns);
+ item->total_width=0;
+ for(int i=0;i<item->columns.size();i++) {
+ item->columns[i].expand=false;
+ item->columns[i].expand_ratio=1;
+ }
+ _add_item(item,true,true);
+
+}
+
+void RichTextLabel::set_table_column_expand(int p_column,bool p_expand,int p_ratio) {
+
+ ERR_FAIL_COND(current->type!=ITEM_TABLE);
+ ItemTable *table = static_cast<ItemTable*>(current);
+ ERR_FAIL_INDEX(p_column,table->columns.size());
+ table->columns[p_column].expand=p_expand;
+ table->columns[p_column].expand_ratio=p_ratio;
+}
+
+void RichTextLabel::push_cell(){
+
+ ERR_FAIL_COND(current->type!=ITEM_TABLE);
+
+ ItemFrame *item = memnew( ItemFrame );
+ item->parent_frame=current_frame;
+ _add_item(item,true);
+ current_frame=item;
+ item->cell=true;
+ item->parent_line=item->parent_frame->lines.size()-1;
+ item->lines.resize(1);
+ item->lines[0].from=NULL;
+ item->first_invalid_line=0;
+
+}
+
+int RichTextLabel::get_current_table_column() const {
+
+ ERR_FAIL_COND_V(current->type!=ITEM_TABLE,-1);
+
+ ItemTable *table = static_cast<ItemTable*>(current);
+
+ return table->subitems.size() % table->columns.size();
+
+}
+
void RichTextLabel::pop() {
ERR_FAIL_COND(!current->parent);
+ if (current->type==ITEM_FRAME) {
+ current_frame = static_cast<ItemFrame*>(current)->parent_frame;
+ }
current=current->parent;
}
@@ -1175,9 +1426,10 @@ void RichTextLabel::clear() {
main->_clear_children();
current=main;
- lines.clear();
- lines.resize(1);
- first_invalid_line=0;
+ current_frame=main;
+ main->lines.clear();
+ main->lines.resize(1);
+ main->first_invalid_line=0;
update();
selection.click=NULL;
selection.active=false;
@@ -1188,7 +1440,7 @@ void RichTextLabel::clear() {
void RichTextLabel::set_tab_size(int p_spaces) {
tab_size=p_spaces;
- first_invalid_line=0;
+ main->first_invalid_line=0;
update();
}
@@ -1344,6 +1596,30 @@ Error RichTextLabel::append_bbcode(const String& p_bbcode) {
push_font(mono_font);
pos=brk_end+1;
tag_stack.push_front(tag);
+ } else if (tag.begins_with("table=")) {
+
+ int columns = tag.substr(6,tag.length()).to_int();
+ if (columns<1)
+ columns=1;
+ //use monospace font
+ push_table(columns);
+ pos=brk_end+1;
+ tag_stack.push_front("table");
+ } else if (tag=="cell") {
+
+ push_cell();
+ pos=brk_end+1;
+ tag_stack.push_front(tag);
+ } else if (tag.begins_with("cell=")) {
+
+ int ratio = tag.substr(6,tag.length()).to_int();
+ if (ratio<1)
+ ratio=1;
+ //use monospace font
+ set_table_column_expand(get_current_table_column(),true,ratio);
+ push_cell();
+ pos=brk_end+1;
+ tag_stack.push_front("cell");
} else if (tag=="u") {
//use underline
@@ -1503,16 +1779,15 @@ Error RichTextLabel::append_bbcode(const String& p_bbcode) {
void RichTextLabel::scroll_to_line(int p_line) {
- ERR_FAIL_INDEX(p_line,lines.size());
- _validate_line_caches();
- vscroll->set_val(lines[p_line].height_accum_cache);
-
+ ERR_FAIL_INDEX(p_line,main->lines.size());
+ _validate_line_caches(main);
+ vscroll->set_val(main->lines[p_line].height_accum_cache-main->lines[p_line].height_cache);
}
int RichTextLabel::get_line_count() const {
- return lines.size();
+ return current_frame->lines.size();
}
void RichTextLabel::set_selection_enabled(bool p_enabled) {
@@ -1556,40 +1831,35 @@ bool RichTextLabel::search(const String& p_string,bool p_from_selection) {
selection.active=true;
update();
- if (line==-1) {
+ _validate_line_caches(main);
- while(it) {
+ int fh = _find_font(t).is_valid()?_find_font(t)->get_height():get_font("normal_font")->get_height();
- if (it->type==ITEM_NEWLINE) {
+ float offset =0;
- line=static_cast<ItemNewline*>(it)->line;
- break;
+ int line = t->line;
+ Item *item =t;
+ while(item) {
+ if (item->type==ITEM_FRAME) {
+ ItemFrame *frame = static_cast<ItemFrame*>(item);
+ if (line>=0 && line<frame->lines.size()) {
+ offset+=frame->lines[line].height_accum_cache-frame->lines[line].height_cache;
+ line=frame->line;
}
-
- it=_get_next_item(it);
}
-
- if (!it)
- line=lines.size()-1;
+ item=item->parent;
}
-
- scroll_to_line(line-2);
+ vscroll->set_val(offset-fh);
return true;
}
- } else if (it->type==ITEM_NEWLINE) {
-
- line=static_cast<ItemNewline*>(it)->line;
}
-
- it=_get_next_item(it);
+ it=_get_next_item(it,true);
charidx=0;
}
-
-
return false;
}
@@ -1624,7 +1894,7 @@ void RichTextLabel::selection_copy() {
if (item==selection.to)
break;
- item=_get_next_item(item);
+ item=_get_next_item(item,true);
}
if (text!="") {
@@ -1677,6 +1947,9 @@ void RichTextLabel::_bind_methods() {
ObjectTypeDB::bind_method(_MD("push_list","type"),&RichTextLabel::push_list);
ObjectTypeDB::bind_method(_MD("push_meta","data"),&RichTextLabel::push_meta);
ObjectTypeDB::bind_method(_MD("push_underline"),&RichTextLabel::push_underline);
+ ObjectTypeDB::bind_method(_MD("push_table","columns"),&RichTextLabel::push_table);
+ ObjectTypeDB::bind_method(_MD("set_table_column_expand","column","expand","ratio"),&RichTextLabel::set_table_column_expand);
+ ObjectTypeDB::bind_method(_MD("push_cell"),&RichTextLabel::push_cell);
ObjectTypeDB::bind_method(_MD("pop"),&RichTextLabel::pop);
ObjectTypeDB::bind_method(_MD("clear"),&RichTextLabel::clear);
@@ -1692,10 +1965,11 @@ void RichTextLabel::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_v_scroll"),&RichTextLabel::get_v_scroll);
+ ObjectTypeDB::bind_method(_MD("scroll_to_line","line"),&RichTextLabel::scroll_to_line);
+
ObjectTypeDB::bind_method(_MD("set_tab_size","spaces"),&RichTextLabel::set_tab_size);
ObjectTypeDB::bind_method(_MD("get_tab_size"),&RichTextLabel::get_tab_size);
-
ObjectTypeDB::bind_method(_MD("set_selection_enabled","enabled"),&RichTextLabel::set_selection_enabled);
ObjectTypeDB::bind_method(_MD("is_selection_enabled"),&RichTextLabel::is_selection_enabled);
@@ -1728,7 +2002,7 @@ void RichTextLabel::_bind_methods() {
BIND_CONSTANT( LIST_LETTERS );
BIND_CONSTANT( LIST_DOTS );
- BIND_CONSTANT( ITEM_MAIN );
+ BIND_CONSTANT( ITEM_FRAME );
BIND_CONSTANT( ITEM_TEXT );
BIND_CONSTANT( ITEM_IMAGE );
BIND_CONSTANT( ITEM_NEWLINE );
@@ -1756,8 +2030,8 @@ int RichTextLabel::get_visible_characters() const {
int RichTextLabel::get_total_character_count() const {
int tc=0;
- for(int i=0;i<lines.size();i++)
- tc+=lines[i].char_count;
+ for(int i=0;i<current_frame->lines.size();i++)
+ tc+=current_frame->lines[i].char_count;
return tc;
}
@@ -1766,12 +2040,13 @@ int RichTextLabel::get_total_character_count() const {
RichTextLabel::RichTextLabel() {
- main = memnew( ItemMain );
+ main = memnew( ItemFrame );
main->index=0;
current=main;
- lines.resize(1);
- lines[0].from=main;
- first_invalid_line=0;
+ main->lines.resize(1);
+ main->lines[0].from=main;
+ main->first_invalid_line=0;
+ current_frame=main;
tab_size=4;
default_align=ALIGN_LEFT;
underline_meta=true;
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index eaa8d5d60a..635fe87ad4 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -54,7 +54,7 @@ public:
enum ItemType {
- ITEM_MAIN,
+ ITEM_FRAME,
ITEM_TEXT,
ITEM_IMAGE,
ITEM_NEWLINE,
@@ -64,6 +64,7 @@ public:
ITEM_ALIGN,
ITEM_INDENT,
ITEM_LIST,
+ ITEM_TABLE,
ITEM_META
};
@@ -72,6 +73,24 @@ protected:
static void _bind_methods();
private:
+ struct Item;
+
+ struct Line {
+
+ Item *from;
+ Vector<int> offset_caches;
+ Vector<int> height_caches;
+ Vector<int> space_caches;
+ int height_cache;
+ int height_accum_cache;
+ int char_count;
+ int minimum_width;
+
+ Line() { from=NULL; char_count=0; }
+ };
+
+
+
struct Item {
int index;
@@ -79,18 +98,26 @@ private:
ItemType type;
List<Item*> subitems;
List<Item*>::Element *E;
+ int line;
void _clear_children() { while (subitems.size()) { memdelete(subitems.front()->get()); subitems.pop_front(); } }
- Item() { parent=NULL; E=NULL; }
+ Item() { parent=NULL; E=NULL; line=0;}
virtual ~Item() { _clear_children(); }
};
- struct ItemMain : public Item {
+ struct ItemFrame : public Item{
+
+ int parent_line;
+ bool cell;
+ Vector<Line> lines;
+ int first_invalid_line;
+ ItemFrame *parent_frame;
- ItemMain() { type=ITEM_MAIN; }
+ ItemFrame() { type=ITEM_FRAME; parent_frame=NULL; cell=false; parent_line=0; }
};
+
struct ItemText : public Item {
String text;
@@ -150,11 +177,28 @@ private:
ItemNewline() { type=ITEM_NEWLINE; }
};
- ItemMain *main;
+
+ struct ItemTable : public Item{
+
+ struct Column {
+ bool expand;
+ int expand_ratio;
+ int min_width;
+ int width;
+ };
+
+ Vector<Column> columns;
+ int total_width;
+ ItemTable() { type=ITEM_TABLE; }
+ };
+
+ ItemFrame *main;
Item *current;
+ ItemFrame *current_frame;
VScrollBar *vscroll;
+
bool scroll_visible;
bool scroll_follow;
bool scroll_following;
@@ -163,34 +207,16 @@ private:
bool updating_scroll;
int current_idx;
- struct Line {
-
- Item *from;
- Vector<int> offset_caches;
- Vector<int> height_caches;
- Vector<int> space_caches;
- int height_cache;
- int height_accum_cache;
- int char_count;
-
- Line() { from=NULL; char_count=0; }
- };
-
-
-
-
- Vector<Line> lines;
- int first_invalid_line;
int tab_size;
bool underline_meta;
Align default_align;
- void _invalidate_current_line();
- void _validate_line_caches();
+ void _invalidate_current_line(ItemFrame *p_frame);
+ void _validate_line_caches(ItemFrame *p_frame);
- void _add_item(Item *p_item, bool p_enter=false);
+ void _add_item(Item *p_item, bool p_enter=false,bool p_ensure_newline=false);
@@ -227,8 +253,8 @@ private:
int visible_characters;
- void _process_line(int &y, int p_width, int p_line, ProcessMode p_mode,const Ref<Font> &p_base_font,const Color &p_base_color,const Point2i& p_click_pos=Point2i(),Item **r_click_item=NULL,int *r_click_char=NULL,bool *r_outside=NULL,int p_char_count=0);
- void _find_click(const Point2i& p_click,Item **r_click_item=NULL,int *r_click_char=NULL,bool *r_outside=NULL);
+ void _process_line(ItemFrame *p_frame,const Vector2& p_ofs,int &y, int p_width, int p_line, ProcessMode p_mode,const Ref<Font> &p_base_font,const Color &p_base_color,const Point2i& p_click_pos=Point2i(),Item **r_click_item=NULL,int *r_click_char=NULL,bool *r_outside=NULL,int p_char_count=0);
+ void _find_click(ItemFrame *p_frame, const Point2i& p_click,Item **r_click_item=NULL,int *r_click_char=NULL,bool *r_outside=NULL);
Ref<Font> _find_font(Item *p_item);
@@ -242,12 +268,12 @@ private:
void _scroll_changed(double);
void _input_event(InputEvent p_event);
- Item *_get_next_item(Item* p_item);
+ Item *_get_next_item(Item* p_item, bool p_free=false);
bool use_bbcode;
String bbcode;
-
+ void _update_all_lines();
protected:
void _notification(int p_what);
@@ -264,6 +290,10 @@ public:
void push_indent(int p_level);
void push_list(ListType p_list);
void push_meta(const Variant& p_data);
+ void push_table(int p_columns);
+ void set_table_column_expand(int p_column, bool p_expand, int p_ratio=1);
+ int get_current_table_column() const;
+ void push_cell();
void pop();
void clear();
diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp
index b1fd914fcd..0fd4286f38 100644
--- a/scene/gui/scroll_bar.cpp
+++ b/scene/gui/scroll_bar.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/scroll_bar.h b/scene/gui/scroll_bar.h
index 367bc3eb53..a629ddc56c 100644
--- a/scene/gui/scroll_bar.h
+++ b/scene/gui/scroll_bar.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index 8f753f51bc..a2fc038f9e 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -195,11 +195,19 @@ void ScrollContainer::_notification(int p_what) {
Rect2 r = Rect2(-scroll,minsize);
if (!scroll_h) {
r.pos.x=0;
- r.size.width=size.width;
+ if (c->get_h_size_flags()&SIZE_EXPAND)
+ r.size.width=MAX(size.width,minsize.width);
+ else
+ r.size.width=minsize.width;
}
if (!scroll_v) {
r.pos.y=0;
r.size.height=size.height;
+ if (c->get_v_size_flags()&SIZE_EXPAND)
+ r.size.height=MAX(size.height,minsize.height);
+ else
+ r.size.height=minsize.height;
+
}
fit_child_in_rect(c,r);
}
diff --git a/scene/gui/scroll_container.h b/scene/gui/scroll_container.h
index b8d37be08c..50ae236714 100644
--- a/scene/gui/scroll_container.h
+++ b/scene/gui/scroll_container.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/separator.cpp b/scene/gui/separator.cpp
index 5e822a10ad..626b093a2f 100644
--- a/scene/gui/separator.cpp
+++ b/scene/gui/separator.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/separator.h b/scene/gui/separator.h
index 17e9c11e34..7a7dc92b93 100644
--- a/scene/gui/separator.h
+++ b/scene/gui/separator.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp
index b6292c544b..7ef9d4216b 100644
--- a/scene/gui/slider.cpp
+++ b/scene/gui/slider.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -50,9 +50,9 @@ void Slider::_input_event(InputEvent p_event) {
grab.pos=orientation==VERTICAL?mb.y:mb.x;
double max = orientation==VERTICAL ? get_size().height : get_size().width ;
if (orientation==VERTICAL)
- set_val( ( ( -(double)grab.pos / max) * ( get_max() - get_min() ) ) + get_max() );
+ set_unit_value( 1 - ((double)grab.pos / max) );
else
- set_val( ( ( (double)grab.pos / max) * ( get_max() - get_min() ) ) + get_min() );
+ set_unit_value((double)grab.pos / max);
grab.active=true;
grab.uvalue=get_unit_value();
} else {
diff --git a/scene/gui/slider.h b/scene/gui/slider.h
index 5850c48ce3..f85e6d1807 100644
--- a/scene/gui/slider.h
+++ b/scene/gui/slider.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp
index 41e775bbff..38c61ded2c 100644
--- a/scene/gui/spin_box.cpp
+++ b/scene/gui/spin_box.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,7 +27,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "spin_box.h"
-
+#include "os/input.h"
Size2 SpinBox::get_minimum_size() const {
@@ -62,6 +62,32 @@ LineEdit *SpinBox::get_line_edit() {
}
+void SpinBox::_line_edit_input(const InputEvent& p_event) {
+
+
+
+}
+
+void SpinBox::_range_click_timeout() {
+
+ if (!drag.enabled && Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT)) {
+
+ int pos_y = Input::get_singleton()->get_mouse_pos().y-get_global_pos().y;
+ bool up = pos_y < (get_size().height/2);
+ set_val( get_val() + (up?get_step():-get_step()));
+
+ if (range_click_timer->is_one_shot()) {
+ range_click_timer->set_wait_time(0.075);
+ range_click_timer->set_one_shot(false);
+ range_click_timer->start();
+ }
+
+ } else {
+ range_click_timer->stop();
+ }
+}
+
+
void SpinBox::_input_event(const InputEvent& p_event) {
if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.pressed) {
@@ -78,6 +104,10 @@ void SpinBox::_input_event(const InputEvent& p_event) {
set_val( get_val() + (up?get_step():-get_step()));
+ range_click_timer->set_wait_time(0.6);
+ range_click_timer->set_one_shot(true);
+ range_click_timer->start();
+
} break;
case BUTTON_RIGHT: {
@@ -94,6 +124,50 @@ void SpinBox::_input_event(const InputEvent& p_event) {
} break;
}
}
+
+ if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.pressed && p_event.mouse_button.button_index==1) {
+
+ //set_default_cursor_shape(CURSOR_VSIZE);
+ Vector2 cpos = Vector2(p_event.mouse_button.x,p_event.mouse_button.y);
+ drag.mouse_pos=cpos;
+ }
+
+ if (p_event.type==InputEvent::MOUSE_BUTTON && !p_event.mouse_button.pressed && p_event.mouse_button.button_index==1) {
+
+ //set_default_cursor_shape(CURSOR_ARROW);
+ range_click_timer->stop();
+
+ if (drag.enabled) {
+ drag.enabled=false;
+ Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
+ warp_mouse(drag.capture_pos);
+ }
+ }
+
+ if (p_event.type==InputEvent::MOUSE_MOTION && p_event.mouse_button.button_mask&1) {
+
+ Vector2 cpos = Vector2(p_event.mouse_motion.x,p_event.mouse_motion.y);
+ if (drag.enabled) {
+
+ float diff_y = drag.mouse_pos.y - cpos.y;
+ diff_y=Math::pow(ABS(diff_y),1.8)*SGN(diff_y);
+ diff_y*=0.1;
+
+ drag.mouse_pos=cpos;
+ drag.base_val=CLAMP(drag.base_val + get_step() * diff_y, get_min(), get_max());
+
+ set_val( drag.base_val);
+
+ } else if (drag.mouse_pos.distance_to(cpos)>2) {
+
+ Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED);
+ drag.enabled=true;
+ drag.base_val=get_val();
+ drag.mouse_pos=cpos;
+ drag.capture_pos=cpos;
+
+ }
+ }
}
@@ -118,6 +192,7 @@ void SpinBox::_notification(int p_what) {
Size2i size = get_size();
updown->draw(ci,Point2i(size.width-updown->get_width(),(size.height-updown->get_height())/2));
+
} else if (p_what==NOTIFICATION_FOCUS_EXIT) {
@@ -177,6 +252,8 @@ void SpinBox::_bind_methods() {
ObjectTypeDB::bind_method(_MD("is_editable"),&SpinBox::is_editable);
ObjectTypeDB::bind_method(_MD("_line_edit_focus_exit"),&SpinBox::_line_edit_focus_exit);
ObjectTypeDB::bind_method(_MD("get_line_edit"),&SpinBox::get_line_edit);
+ ObjectTypeDB::bind_method(_MD("_line_edit_input"),&SpinBox::_line_edit_input);
+ ObjectTypeDB::bind_method(_MD("_range_click_timeout"),&SpinBox::_range_click_timeout);
ADD_PROPERTY(PropertyInfo(Variant::BOOL,"editable"),_SCS("set_editable"),_SCS("is_editable"));
@@ -196,4 +273,10 @@ SpinBox::SpinBox() {
//connect("value_changed",this,"_value_changed");
line_edit->connect("text_entered",this,"_text_entered",Vector<Variant>(),CONNECT_DEFERRED);
line_edit->connect("focus_exit",this,"_line_edit_focus_exit",Vector<Variant>(),CONNECT_DEFERRED);
+ line_edit->connect("input_event",this,"_line_edit_input");
+ drag.enabled=false;
+
+ range_click_timer = memnew( Timer );
+ range_click_timer->connect("timeout",this,"_range_click_timeout");
+ add_child(range_click_timer);
}
diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h
index 6ebe14631e..acaea822ab 100644
--- a/scene/gui/spin_box.h
+++ b/scene/gui/spin_box.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,6 +31,7 @@
#include "scene/gui/line_edit.h"
#include "scene/gui/range.h"
+#include "scene/main/timer.h"
class SpinBox : public Range {
@@ -39,11 +40,26 @@ class SpinBox : public Range {
LineEdit *line_edit;
int last_w;
+ Timer *range_click_timer;
+ void _range_click_timeout();
+
void _text_entered(const String& p_string);
virtual void _value_changed(double);
String prefix;
String suffix;
+ void _line_edit_input(const InputEvent& p_event);
+
+
+ struct Drag {
+ float base_val;
+ bool enabled;
+ Vector2 from;
+ Vector2 mouse_pos;
+ Vector2 capture_pos;
+ } drag;
+
+
void _line_edit_focus_exit();
protected:
diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp
index d7ee7a6b86..d22f6a0229 100644
--- a/scene/gui/split_container.cpp
+++ b/scene/gui/split_container.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -109,7 +109,7 @@ void SplitContainer::_resort() {
int sep=get_constant("separation");
Ref<Texture> g = get_icon("grabber");
- if (collapsed || !dragger_visible) {
+ if (dragger_visibility==DRAGGER_HIDDEN_COLLAPSED) {
sep=0;
} else {
sep=MAX(sep,vertical?g->get_height():g->get_width());
@@ -221,7 +221,7 @@ Size2 SplitContainer::get_minimum_size() const {
Size2i minimum;
int sep=get_constant("separation");
Ref<Texture> g = get_icon("grabber");
- sep=dragger_visible?MAX(sep,vertical?g->get_height():g->get_width()):0;
+ sep=(dragger_visibility!=DRAGGER_HIDDEN_COLLAPSED)?MAX(sep,vertical?g->get_height():g->get_width()):0;
for(int i=0;i<2;i++) {
@@ -278,19 +278,19 @@ void SplitContainer::_notification(int p_what) {
if (collapsed || (!mouse_inside && get_constant("autohide")))
return;
- int sep=dragger_visible?get_constant("separation"):0;
+ int sep=dragger_visibility!=DRAGGER_HIDDEN_COLLAPSED?get_constant("separation"):0;
Ref<Texture> tex = get_icon("grabber");
Size2 size=get_size();
if (vertical) {
//draw_style_box( get_stylebox("bg"), Rect2(0,middle_sep,get_size().width,sep));
- if (dragger_visible)
+ if (dragger_visibility==DRAGGER_VISIBLE)
draw_texture(tex,Point2i((size.x-tex->get_width())/2,middle_sep+(sep-tex->get_height())/2));
} else {
//draw_style_box( get_stylebox("bg"), Rect2(middle_sep,0,sep,get_size().height));
- if (dragger_visible)
+ if (dragger_visibility==DRAGGER_VISIBLE)
draw_texture(tex,Point2i(middle_sep+(sep-tex->get_width())/2,(size.y-tex->get_height())/2));
}
@@ -301,7 +301,7 @@ void SplitContainer::_notification(int p_what) {
void SplitContainer::_input_event(const InputEvent& p_event) {
- if (collapsed || !_getch(0) || !_getch(1) || !dragger_visible)
+ if (collapsed || !_getch(0) || !_getch(1) || dragger_visibility!=DRAGGER_VISIBLE)
return;
if (p_event.type==InputEvent::MOUSE_BUTTON) {
@@ -400,19 +400,19 @@ void SplitContainer::set_collapsed(bool p_collapsed) {
}
-void SplitContainer::set_dragger_visible(bool p_true) {
+void SplitContainer::set_dragger_visibility(DraggerVisibility p_visibility) {
- dragger_visible=p_true;
+ dragger_visibility=p_visibility;
queue_sort();
update();
}
-bool SplitContainer::is_dragger_visible() const{
+SplitContainer::DraggerVisibility SplitContainer::get_dragger_visibility() const {
-
- return dragger_visible;
+ return dragger_visibility;
}
+
bool SplitContainer::is_collapsed() const {
@@ -429,15 +429,18 @@ void SplitContainer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_collapsed","collapsed"),&SplitContainer::set_collapsed);
ObjectTypeDB::bind_method(_MD("is_collapsed"),&SplitContainer::is_collapsed);
- ObjectTypeDB::bind_method(_MD("set_dragger_visible","visible"),&SplitContainer::set_dragger_visible);
- ObjectTypeDB::bind_method(_MD("is_dragger_visible"),&SplitContainer::is_dragger_visible);
+ ObjectTypeDB::bind_method(_MD("set_dragger_visibility","mode"),&SplitContainer::set_dragger_visibility);
+ ObjectTypeDB::bind_method(_MD("get_dragger_visibility"),&SplitContainer::get_dragger_visibility);
ADD_SIGNAL( MethodInfo("dragged",PropertyInfo(Variant::INT,"offset")));
ADD_PROPERTY( PropertyInfo(Variant::INT,"split/offset"),_SCS("set_split_offset"),_SCS("get_split_offset"));
- ADD_PROPERTY( PropertyInfo(Variant::INT,"split/collapsed"),_SCS("set_collapsed"),_SCS("is_collapsed"));
- ADD_PROPERTY( PropertyInfo(Variant::INT,"split/dragger_visible"),_SCS("set_dragger_visible"),_SCS("is_dragger_visible"));
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"split/collapsed"),_SCS("set_collapsed"),_SCS("is_collapsed"));
+ ADD_PROPERTY( PropertyInfo(Variant::INT,"split/dragger_visibility",PROPERTY_HINT_ENUM,"Visible,Hidden,Hidden & Collapsed"),_SCS("set_dragger_visibility"),_SCS("get_dragger_visibility"));
+ BIND_CONSTANT( DRAGGER_VISIBLE );
+ BIND_CONSTANT( DRAGGER_HIDDEN );
+ BIND_CONSTANT( DRAGGER_HIDDEN_COLLAPSED );
}
@@ -450,7 +453,8 @@ SplitContainer::SplitContainer(bool p_vertical) {
vertical=p_vertical;
dragging=false;
collapsed=false;
- dragger_visible=true;
+ dragger_visibility=DRAGGER_VISIBLE;
+
}
diff --git a/scene/gui/split_container.h b/scene/gui/split_container.h
index d7f56c6fb4..f721d16310 100644
--- a/scene/gui/split_container.h
+++ b/scene/gui/split_container.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,7 +35,13 @@
class SplitContainer : public Container {
OBJ_TYPE(SplitContainer,Container);
-
+public:
+ enum DraggerVisibility {
+ DRAGGER_VISIBLE,
+ DRAGGER_HIDDEN,
+ DRAGGER_HIDDEN_COLLAPSED
+ };
+private:
bool vertical;
int expand_ofs;
int middle_sep;
@@ -43,7 +49,7 @@ class SplitContainer : public Container {
int drag_from;
int drag_ofs;
bool collapsed;
- bool dragger_visible;
+ DraggerVisibility dragger_visibility;
bool mouse_inside;
@@ -66,8 +72,8 @@ public:
void set_collapsed(bool p_collapsed);
bool is_collapsed() const;
- void set_dragger_visible(bool p_true);
- bool is_dragger_visible() const;
+ void set_dragger_visibility(DraggerVisibility p_visibility);
+ DraggerVisibility get_dragger_visibility() const;
virtual CursorShape get_cursor_shape(const Point2& p_pos=Point2i());
@@ -76,6 +82,7 @@ public:
SplitContainer(bool p_vertical=false);
};
+VARIANT_ENUM_CAST(SplitContainer::DraggerVisibility);
class HSplitContainer : public SplitContainer {
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index 3ed182c017..91d0fc157e 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -229,6 +229,18 @@ void TabContainer::_notification(int p_what) {
int w=0;
int idx=0;
+ Vector<int> offsets;
+ Vector<Control*> controls;
+ int from=0;
+ int limit=get_size().width;
+ if (popup) {
+ top_size.width-=menu->get_width();
+ limit-=menu->get_width();
+ }
+
+ bool notdone=false;
+ last_tab_cache=-1;
+
for(int i=0;i<get_child_count();i++) {
Control *c = get_child(i)->cast_to<Control>();
@@ -236,7 +248,20 @@ void TabContainer::_notification(int p_what) {
continue;
if (c->is_set_as_toplevel())
continue;
+ if (idx<tab_display_ofs) {
+ idx++;
+ from=idx;
+ continue;
+ }
+ if (w>=get_size().width) {
+ buttons_visible_cache=true;
+ notdone=true;
+ break;
+ }
+
+ offsets.push_back(w);
+ controls.push_back(c);
String s = c->has_meta("_tab_name")?String(XL_MESSAGE(String(c->get_meta("_tab_name")))):String(c->get_name());
w+=font->get_string_size(s).width;
@@ -257,55 +282,46 @@ void TabContainer::_notification(int p_what) {
w+=tab_bg->get_minimum_size().width;
}
- idx++;
- }
+ if (idx<tab_display_ofs) {
+ }
+ last_tab_cache=idx;
- int ofs;
- int limit=get_size().width;
- if (popup) {
- top_size.width-=menu->get_width();
- limit-=menu->get_width();
+ idx++;
}
- if (w<=limit) {
- switch(align) {
+ int ofs;
- case ALIGN_LEFT: ofs = side_margin; break;
- case ALIGN_CENTER: ofs = (int(limit) - w)/2; break;
- case ALIGN_RIGHT: ofs = int(limit) - w - side_margin; break;
- };
+ switch(align) {
- tab_display_ofs=0;
- buttons_visible_cache=false;
- } else {
+ case ALIGN_LEFT: ofs = side_margin; break;
+ case ALIGN_CENTER: ofs = (int(limit) - w)/2; break;
+ case ALIGN_RIGHT: ofs = int(limit) - w - side_margin; break;
+ };
- ofs=0;
- limit-=incr->get_width()+decr->get_width();
- buttons_visible_cache=true;
- }
+ tab_display_ofs=0;
tabs_ofs_cache=ofs;
- last_tab_cache=-1;
idx=0;
- bool notdone=false;
- for(int i=0;i<get_child_count();i++) {
- Control *c = get_child(i)->cast_to<Control>();
- if (!c)
- continue;
- if (c->is_set_as_toplevel())
- continue;
+ for(int i=0;i<controls.size();i++) {
- if (idx<tab_display_ofs) {
- idx++;
- continue;
+ idx=i+from;
+ if (current>=from && current<from+controls.size()-1) {
+ //current is visible! draw it last.
+ if (i==controls.size()-1) {
+ idx=current;
+ } else if (idx>=current) {
+ idx+=1;
+ }
}
+ Control *c = controls[idx-from];
+
String s = c->has_meta("_tab_name")?String(c->get_meta("_tab_name")):String(c->get_name());
int w=font->get_string_size(s).width;
Ref<Texture> icon;
@@ -336,14 +352,12 @@ void TabContainer::_notification(int p_what) {
col=color_bg;
}
+ int lofs = ofs + offsets[idx-from];
Size2i sb_ms = sb->get_minimum_size();
- Rect2 sb_rect = Rect2( ofs, 0, w+sb_ms.width, top_margin);
+ Rect2 sb_rect = Rect2( lofs, 0, w+sb_ms.width, top_margin);
+
- if (sb_ms.width+w+ofs > limit) {
- notdone=true;
- break;
- }
sb->draw(ci, sb_rect );
Point2i lpos = sb_rect.pos;
@@ -357,8 +371,7 @@ void TabContainer::_notification(int p_what) {
}
font->draw(ci, Point2i( lpos.x, sb->get_margin(MARGIN_TOP)+((sb_rect.size.y-sb_ms.y)-font->get_height())/2+font->get_ascent() ), s, col );
- ofs+=sb_ms.x+w;
- last_tab_cache=idx;
+ //ofs+=sb_ms.x+w;
/*
int sb_mw = sb->get_minimum_size().width;
diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h
index 602d248b46..979ce927a0 100644
--- a/scene/gui/tab_container.h
+++ b/scene/gui/tab_container.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp
index 40a6e20c37..a26acc9c05 100644
--- a/scene/gui/tabs.cpp
+++ b/scene/gui/tabs.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -56,9 +56,25 @@ Size2 Tabs::get_minimum_size() const {
else
ms.width+=tab_bg->get_minimum_size().width;
+ if (tabs[i].right_button.is_valid()) {
+ Ref<Texture> rb=tabs[i].right_button;
+ Size2 bms = rb->get_size();//+get_stylebox("button")->get_minimum_size();
+ bms.width+=get_constant("hseparation");
+ ms.width+=bms.width;
+ ms.height=MAX(bms.height+tab_bg->get_minimum_size().height,ms.height);
+ }
+
+ if (cb_displaypolicy==CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy==CLOSE_BUTTON_SHOW_ACTIVE_ONLY && i==current)) {
+ Ref<Texture> cb=get_icon("close");
+ Size2 bms = cb->get_size();//+get_stylebox("button")->get_minimum_size();
+ bms.width+=get_constant("hseparation");
+ ms.width+=bms.width;
+ ms.height=MAX(bms.height+tab_bg->get_minimum_size().height,ms.height);
+ }
}
+ ms.width=0; //should make this optional
return ms;
}
@@ -66,6 +82,90 @@ Size2 Tabs::get_minimum_size() const {
void Tabs::_input_event(const InputEvent& p_event) {
+ if (p_event.type==InputEvent::MOUSE_MOTION) {
+
+ Point2 pos( p_event.mouse_motion.x, p_event.mouse_motion.y );
+
+ hilite_arrow=-1;
+ if (buttons_visible) {
+
+ Ref<Texture> incr = get_icon("increment");
+ Ref<Texture> decr = get_icon("decrement");
+
+ int limit=get_size().width-incr->get_width()-decr->get_width();
+
+ if (pos.x>limit+decr->get_width()) {
+ hilite_arrow=1;
+ } else if (pos.x>limit) {
+ hilite_arrow=0;
+ }
+ }
+
+
+
+ int hover_buttons=-1;
+ hover=-1;
+ for(int i=0;i<tabs.size();i++) {
+
+ // test hovering tab to display close button if policy says so
+
+ // test hovering right button and close button
+ if (tabs[i].rb_rect.has_point(pos)) {
+ rb_hover=i;
+ cb_hover=-1;
+ hover_buttons = i;
+ break;
+ }
+ else if (tabs[i].cb_rect.has_point(pos)) {
+ cb_hover=i;
+ rb_hover=-1;
+ hover_buttons = i;
+ break;
+ }
+
+
+
+ }
+
+ if (hover_buttons == -1) { // no hover
+ rb_hover= hover_buttons;
+ cb_hover= hover_buttons;
+ }
+ update();
+
+ return;
+ }
+
+
+
+
+ if (rb_pressing && p_event.type==InputEvent::MOUSE_BUTTON &&
+ !p_event.mouse_button.pressed &&
+ p_event.mouse_button.button_index==BUTTON_LEFT) {
+
+ if (rb_hover!=-1) {
+ //pressed
+ emit_signal("right_button_pressed",rb_hover);
+ }
+
+ rb_pressing=false;
+ update();
+ }
+
+ if (cb_pressing && p_event.type==InputEvent::MOUSE_BUTTON &&
+ !p_event.mouse_button.pressed &&
+ p_event.mouse_button.button_index==BUTTON_LEFT) {
+
+ if (cb_hover!=-1) {
+ //pressed
+ emit_signal("tab_close",cb_hover);
+ }
+
+ cb_pressing=false;
+ update();
+ }
+
+
if (p_event.type==InputEvent::MOUSE_BUTTON &&
p_event.mouse_button.pressed &&
p_event.mouse_button.button_index==BUTTON_LEFT) {
@@ -73,9 +173,46 @@ void Tabs::_input_event(const InputEvent& p_event) {
// clicks
Point2 pos( p_event.mouse_button.x, p_event.mouse_button.y );
+ if (buttons_visible) {
+
+ Ref<Texture> incr = get_icon("increment");
+ Ref<Texture> decr = get_icon("decrement");
+
+ int limit=get_size().width-incr->get_width()-decr->get_width();
+
+ if (pos.x>limit+decr->get_width()) {
+ if (missing_right) {
+ offset++;
+ update();
+ }
+ return;
+ } else if (pos.x>limit) {
+ if (offset>0) {
+ offset--;
+ update();
+ }
+ return;
+ }
+ }
+
+
int found=-1;
for(int i=0;i<tabs.size();i++) {
+ if (i<offset)
+ continue;
+ if (tabs[i].rb_rect.has_point(pos)) {
+ rb_pressing=true;
+ update();
+ return;
+ }
+
+ if (tabs[i].cb_rect.has_point(pos)) {
+ cb_pressing=true;
+ update();
+ return;
+ }
+
int ofs=tabs[i].ofs_cache;
int size = tabs[i].ofs_cache;
if (pos.x >=tabs[i].ofs_cache && pos.x<tabs[i].ofs_cache+tabs[i].size_cache) {
@@ -100,7 +237,12 @@ void Tabs::_notification(int p_what) {
switch(p_what) {
-
+ case NOTIFICATION_MOUSE_EXIT: {
+ rb_hover=-1;
+ cb_hover=-1;
+ hover=-1;
+ update();
+ } break;
case NOTIFICATION_DRAW: {
RID ci = get_canvas_item();
@@ -110,15 +252,36 @@ void Tabs::_notification(int p_what) {
Ref<Font> font = get_font("font");
Color color_fg = get_color("font_color_fg");
Color color_bg = get_color("font_color_bg");
+ Ref<Texture> close=get_icon("close");
int h = get_size().height;
int label_valign_fg = get_constant("label_valign_fg");
int label_valign_bg = get_constant("label_valign_bg");
+
int w=0;
- int mw = get_minimum_size().width;
+ int mw = 0;
+
+ {
+
+
+ // h+=MIN( get_constant("label_valign_fg"), get_constant("label_valign_bg") );
+
+ for(int i=0;i<tabs.size();i++) {
+
+ int sz = get_tab_width(i);
+
+ tabs[i].ofs_cache=mw;
+ mw+=sz;
+
+
+ }
+
+ }
+
+
if (tab_align==ALIGN_CENTER) {
w=(get_size().width-mw)/2;
@@ -131,18 +294,31 @@ void Tabs::_notification(int p_what) {
w=0;
}
+ Ref<Texture> incr = get_icon("increment");
+ Ref<Texture> decr = get_icon("decrement");
+ Ref<Texture> incr_hl = get_icon("increment_hilite");
+ Ref<Texture> decr_hl = get_icon("decrement_hilite");
+
+ int limit=get_size().width - incr->get_size().width - decr->get_size().width;
+
+ missing_right=false;
+
for(int i=0;i<tabs.size();i++) {
+ if (i<offset)
+ continue;
tabs[i].ofs_cache=w;
String s = tabs[i].text;
int lsize=0;
- int slen=font->get_string_size(s).width;;
+ int slen=font->get_string_size(s).width;
lsize+=slen;
+
+
Ref<Texture> icon;
if (tabs[i].icon.is_valid()) {
- Ref<Texture> icon = tabs[i].icon;
+ icon = tabs[i].icon;
if (icon.is_valid()) {
lsize+=icon->get_width();
if (s!="")
@@ -151,6 +327,35 @@ void Tabs::_notification(int p_what) {
}
}
+ if (tabs[i].right_button.is_valid()) {
+ Ref<StyleBox> style = get_stylebox("button");
+ Ref<Texture> rb=tabs[i].right_button;
+
+ lsize+=get_constant("hseparation");
+ //lsize+=style->get_margin(MARGIN_LEFT);
+ lsize+=rb->get_width();
+ //lsize+=style->get_margin(MARGIN_RIGHT);
+
+ }
+
+
+ if (cb_displaypolicy==CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy==CLOSE_BUTTON_SHOW_ACTIVE_ONLY && i==current)) {
+
+ lsize+=get_constant("hseparation");
+ //lsize+=style->get_margin(MARGIN_LEFT);
+ lsize+=close->get_width();
+ //lsize+=style->get_margin(MARGIN_RIGHT);
+ }
+
+ if (w+lsize > limit) {
+ max_drawn_tab=i-1;
+ missing_right=true;
+ break;
+ } else {
+ max_drawn_tab=i;
+ }
+
+
Ref<StyleBox> sb;
int va;
@@ -184,12 +389,89 @@ void Tabs::_notification(int p_what) {
font->draw(ci, Point2i( w, sb->get_margin(MARGIN_TOP)+((sb_rect.size.y-sb_ms.y)-font->get_height())/2+font->get_ascent() ), s, col );
- w+=slen+sb->get_margin(MARGIN_RIGHT);
+ w+=slen;
+
+ if (tabs[i].right_button.is_valid()) {
+ Ref<StyleBox> style = get_stylebox("button");
+ Ref<Texture> rb=tabs[i].right_button;
+
+ w+=get_constant("hseparation");
+
+ Rect2 rb_rect;
+ rb_rect.size=style->get_minimum_size()+rb->get_size();
+ rb_rect.pos.x=w;
+ rb_rect.pos.y=sb->get_margin(MARGIN_TOP)+((sb_rect.size.y-sb_ms.y)-(rb_rect.size.y))/2;
+
+ if (rb_hover==i) {
+ if (rb_pressing)
+ get_stylebox("button_pressed")->draw(ci,rb_rect);
+ else
+ style->draw(ci,rb_rect);
+ }
+
+ w+=style->get_margin(MARGIN_LEFT);
+
+ rb->draw(ci,Point2i( w,rb_rect.pos.y+style->get_margin(MARGIN_TOP) ));
+ w+=rb->get_width();
+ w+=style->get_margin(MARGIN_RIGHT);
+ tabs[i].rb_rect=rb_rect;
+
+
+ }
+
+
+ if (cb_displaypolicy==CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy==CLOSE_BUTTON_SHOW_ACTIVE_ONLY && i==current)) {
+
+ Ref<StyleBox> style = get_stylebox("button");
+ Ref<Texture> cb=close;
+
+ w+=get_constant("hseparation");
+
+ Rect2 cb_rect;
+ cb_rect.size=style->get_minimum_size()+cb->get_size();
+ cb_rect.pos.x=w;
+ cb_rect.pos.y=sb->get_margin(MARGIN_TOP)+((sb_rect.size.y-sb_ms.y)-(cb_rect.size.y))/2;
+
+ if (cb_hover==i) {
+ if (cb_pressing)
+ get_stylebox("button_pressed")->draw(ci,cb_rect);
+ else
+ style->draw(ci,cb_rect);
+ }
+
+ //w+=style->get_margin(MARGIN_LEFT);
+
+ cb->draw(ci,Point2i( w,cb_rect.pos.y+style->get_margin(MARGIN_TOP) ));
+ w+=cb->get_width();
+ //w+=style->get_margin(MARGIN_RIGHT);
+ tabs[i].cb_rect=cb_rect;
+ }
+
+ w+=sb->get_margin(MARGIN_RIGHT);
tabs[i].size_cache=w-tabs[i].ofs_cache;
}
+ if (offset>0 || missing_right) {
+
+ int vofs = (get_size().height-incr->get_size().height)/2;
+
+ if (offset>0)
+ draw_texture(hilite_arrow==0?decr_hl:decr,Point2(limit,vofs));
+ else
+ draw_texture(decr,Point2(limit,vofs),Color(1,1,1,0.5));
+
+ if (missing_right)
+ draw_texture(hilite_arrow==1?incr_hl:incr,Point2(limit+decr->get_size().width,vofs));
+ else
+ draw_texture(incr,Point2(limit+decr->get_size().width,vofs),Color(1,1,1,0.5));
+
+ buttons_visible=true;
+ } else {
+ buttons_visible=false;
+ }
+
} break;
}
@@ -252,11 +534,30 @@ Ref<Texture> Tabs::get_tab_icon(int p_tab) const{
}
+
+
+void Tabs::set_tab_right_button(int p_tab,const Ref<Texture>& p_right_button){
+
+ ERR_FAIL_INDEX(p_tab,tabs.size());
+ tabs[p_tab].right_button=p_right_button;
+ update();
+ minimum_size_changed();
+
+}
+Ref<Texture> Tabs::get_tab_right_button(int p_tab) const{
+
+ ERR_FAIL_INDEX_V(p_tab,tabs.size(),Ref<Texture>());
+ return tabs[p_tab].right_button;
+
+}
+
+
void Tabs::add_tab(const String& p_str,const Ref<Texture>& p_icon) {
Tab t;
t.text=p_str;
t.icon=p_icon;
+
tabs.push_back(t);
update();
@@ -288,6 +589,7 @@ void Tabs::remove_tab(int p_idx) {
}
+
void Tabs::set_tab_align(TabAlign p_align) {
tab_align=p_align;
@@ -299,6 +601,94 @@ Tabs::TabAlign Tabs::get_tab_align() const {
return tab_align;
}
+int Tabs::get_tab_width(int p_idx) const {
+
+ ERR_FAIL_INDEX_V(p_idx,tabs.size(),0);
+
+ Ref<StyleBox> tab_bg = get_stylebox("tab_bg");
+ Ref<StyleBox> tab_fg = get_stylebox("tab_fg");
+ Ref<Font> font = get_font("font");
+ Ref<Texture> close=get_icon("close");
+
+ int x=0;
+
+ Ref<Texture> tex = tabs[p_idx].icon;
+ if (tex.is_valid()) {
+ if (tabs[p_idx].text!="")
+ x+=get_constant("hseparation");
+
+ }
+
+
+ x+=font->get_string_size(tabs[p_idx].text).width;
+ if (current==p_idx)
+ x+=tab_fg->get_minimum_size().width;
+ else
+ x+=tab_bg->get_minimum_size().width;
+
+ if (tabs[p_idx].right_button.is_valid()) {
+ print_line("has right");
+ Ref<Texture> rb=tabs[p_idx].right_button;
+ Size2 bms = rb->get_size();//+get_stylebox("button")->get_minimum_size();
+ bms.width+=get_constant("hseparation");
+
+ x+=bms.width;
+ }
+
+ if (cb_displaypolicy==CLOSE_BUTTON_SHOW_ALWAYS || (cb_displaypolicy==CLOSE_BUTTON_SHOW_ACTIVE_ONLY && p_idx==current)) {
+
+ Size2 bms = close->get_size();//+get_stylebox("button")->get_minimum_size();
+ bms.width+=get_constant("hseparation");
+ x+=bms.width;
+ }
+
+ return x;
+}
+
+void Tabs::ensure_tab_visible(int p_idx) {
+
+ if (!is_inside_tree())
+ return;
+
+ ERR_FAIL_INDEX(p_idx,tabs.size());
+
+ if (p_idx<=offset) {
+ offset=p_idx;
+ update();
+ return;
+ }
+
+ Ref<Texture> incr = get_icon("increment");
+ Ref<Texture> decr = get_icon("decrement");
+
+ int limit=get_size().width-incr->get_width()-decr->get_width();
+
+
+
+ int x=0;
+ for(int i=0;i<tabs.size();i++) {
+
+ if (i<offset)
+ continue;
+
+ int sz = get_tab_width(i);
+ tabs[i].x_cache=x;
+ tabs[i].x_size_cache=sz;
+ x+=sz;
+
+ }
+
+ while(offset<tabs.size() && ( (tabs[p_idx].x_cache + tabs[p_idx].x_size_cache) - tabs[offset].x_cache) > limit) {
+ offset++;
+ }
+
+ update();
+}
+
+void Tabs::set_tab_close_display_policy(CloseButtonDisplayPolicy p_policy) {
+ cb_displaypolicy=p_policy;
+ update();
+}
void Tabs::_bind_methods() {
@@ -314,19 +704,39 @@ void Tabs::_bind_methods() {
ObjectTypeDB::bind_method(_MD("add_tab","title","icon:Texture"),&Tabs::add_tab);
ObjectTypeDB::bind_method(_MD("set_tab_align","align"),&Tabs::set_tab_align);
ObjectTypeDB::bind_method(_MD("get_tab_align"),&Tabs::get_tab_align);
+ ObjectTypeDB::bind_method(_MD("ensure_tab_visible","idx"),&Tabs::ensure_tab_visible);
ADD_SIGNAL(MethodInfo("tab_changed",PropertyInfo(Variant::INT,"tab")));
+ ADD_SIGNAL(MethodInfo("right_button_pressed",PropertyInfo(Variant::INT,"tab")));
+ ADD_SIGNAL(MethodInfo("tab_close",PropertyInfo(Variant::INT,"tab")));
+
ADD_PROPERTY( PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE,"-1,4096,1",PROPERTY_USAGE_EDITOR), _SCS("set_current_tab"), _SCS("get_current_tab") );
BIND_CONSTANT( ALIGN_LEFT );
BIND_CONSTANT( ALIGN_CENTER );
BIND_CONSTANT( ALIGN_RIGHT );
+
+ BIND_CONSTANT( CLOSE_BUTTON_SHOW_ACTIVE_ONLY );
+ BIND_CONSTANT( CLOSE_BUTTON_SHOW_ALWAYS );
+ BIND_CONSTANT( CLOSE_BUTTON_SHOW_NEVER );
+
}
+
Tabs::Tabs() {
current=0;
tab_align=ALIGN_CENTER;
+ rb_hover=-1;
+ rb_pressing=false;
+ hilite_arrow=-1;
+
+ cb_hover=-1;
+ cb_pressing=false;
+ cb_displaypolicy = CLOSE_BUTTON_SHOW_NEVER; // Default : no close button
+ offset=0;
+ max_drawn_tab=0;
+
}
diff --git a/scene/gui/tabs.h b/scene/gui/tabs.h
index 8d4d0123f8..7f85280853 100644
--- a/scene/gui/tabs.h
+++ b/scene/gui/tabs.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -42,6 +42,13 @@ public:
ALIGN_CENTER,
ALIGN_RIGHT
};
+
+ enum CloseButtonDisplayPolicy {
+
+ CLOSE_BUTTON_SHOW_NEVER,
+ CLOSE_BUTTON_SHOW_ACTIVE_ONLY,
+ CLOSE_BUTTON_SHOW_ALWAYS,
+ };
private:
@@ -51,13 +58,36 @@ private:
Ref<Texture> icon;
int ofs_cache;
int size_cache;
+ int x_cache;
+ int x_size_cache;
+
+ Ref<Texture> right_button;
+ Rect2 rb_rect;
+ Rect2 cb_rect;
+
};
+
+ int offset;
+ int max_drawn_tab;
+ int hilite_arrow;
+ bool buttons_visible;
+ bool missing_right;
Vector<Tab> tabs;
int current;
Control *_get_tab(int idx) const;
int _get_top_margin() const;
TabAlign tab_align;
+ int rb_hover;
+ bool rb_pressing;
+
+ int cb_hover;
+ bool cb_pressing;
+ CloseButtonDisplayPolicy cb_displaypolicy;
+
+ int hover; // hovered tab
+
+ int get_tab_width(int p_idx) const;
protected:
@@ -75,9 +105,14 @@ public:
void set_tab_icon(int p_tab,const Ref<Texture>& p_icon);
Ref<Texture> get_tab_icon(int p_tab) const;
+ void set_tab_right_button(int p_tab,const Ref<Texture>& p_right_button);
+ Ref<Texture> get_tab_right_button(int p_tab) const;
+
void set_tab_align(TabAlign p_align);
TabAlign get_tab_align() const;
+ void set_tab_close_display_policy(CloseButtonDisplayPolicy p_policy);
+
int get_tab_count() const;
void set_current_tab(int p_current);
int get_current_tab() const;
@@ -86,6 +121,8 @@ public:
void clear_tabs();
+ void ensure_tab_visible(int p_idx);
+
Size2 get_minimum_size() const;
Tabs();
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index c497bc5363..7f7c8c023c 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,6 +29,7 @@
#include "text_edit.h"
#include "os/keyboard.h"
+#include "os/input.h"
#include "os/os.h"
#include "globals.h"
@@ -94,9 +95,9 @@ void TextEdit::Text::set_tab_size(int p_tab_size) {
void TextEdit::Text::_update_line_cache(int p_line) const {
- int w =0;
- int tab_w=font->get_char_size(' ').width;
-
+ int w = 0;
+ int tab_w=font->get_char_size(' ').width*tab_size;
+
int len = text[p_line].data.length();
const CharType *str = text[p_line].data.c_str();
@@ -292,7 +293,10 @@ void TextEdit::_update_scrollbars() {
int vscroll_pixels = v_scroll->get_combined_minimum_size().width;
int visible_width = size.width - cache.style_normal->get_minimum_size().width;
- int total_width = text.get_max_width();
+ int total_width = text.get_max_width() + vmin.x;
+
+ if (line_numbers)
+ total_width += cache.line_number_w;
bool use_hscroll=true;
bool use_vscroll=true;
@@ -322,7 +326,6 @@ void TextEdit::_update_scrollbars() {
v_scroll->show();
v_scroll->set_max(total_rows);
v_scroll->set_page(visible_rows);
-
v_scroll->set_val(cursor.line_ofs);
} else {
@@ -336,6 +339,7 @@ void TextEdit::_update_scrollbars() {
h_scroll->set_max(total_width);
h_scroll->set_page(visible_width);
h_scroll->set_val(cursor.x_ofs);
+
} else {
h_scroll->hide();
@@ -346,6 +350,29 @@ void TextEdit::_update_scrollbars() {
updating_scrolls=false;
}
+void TextEdit::_click_selection_held() {
+
+ if (Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT) && selection.selecting_mode!=Selection::MODE_NONE) {
+
+ Point2 mp = Input::get_singleton()->get_mouse_pos()-get_global_pos();
+
+ int row,col;
+ _get_mouse_pos(Point2i(mp.x,mp.y), row,col);
+
+ select(selection.selecting_line,selection.selecting_column,row,col);
+
+ cursor_set_line( row );
+ cursor_set_column( col );
+ update();
+
+ click_select_held->start();
+
+ } else {
+
+ click_select_held->stop();
+ }
+}
+
void TextEdit::_notification(int p_what) {
@@ -706,7 +733,7 @@ void TextEdit::_notification(int p_what) {
if (in_region==-1 && !in_keyword && is_char && !prev_is_char) {
int to=j;
- while(_is_text_char(str[to]) && to<str.length())
+ while(to<str.length() && _is_text_char(str[to]))
to++;
uint32_t hash = String::hash(&str[j],to-j);
@@ -812,7 +839,7 @@ void TextEdit::_notification(int p_what) {
}
- if (cursor.column==str.length() && cursor.line==line) {
+ if (cursor.column==str.length() && cursor.line==line && (char_ofs+char_margin)>=xmargin_beg) {
cursor_pos=Point2i( char_ofs+char_margin, ofs_y );
VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(1,get_row_height())),cache.font_color);
@@ -1091,16 +1118,16 @@ void TextEdit::backspace_at_cursor() {
}
-bool TextEdit::_get_mouse_pos(const Point2i& p_mouse, int &r_row, int &r_col) const {
-
- int row=p_mouse.y;
- row-=cache.style_normal->get_margin(MARGIN_TOP);
- row/=get_row_height();
-
- if (row<0 || row>=get_visible_rows())
- return false;
+void TextEdit::_get_mouse_pos(const Point2i& p_mouse, int &r_row, int &r_col) const {
- row+=cursor.line_ofs;
+ float rows=p_mouse.y;
+ rows-=cache.style_normal->get_margin(MARGIN_TOP);
+ rows/=get_row_height();
+ int row=cursor.line_ofs+rows;
+
+ if (row<0)
+ row=0;
+
int col=0;
if (row>=text.size()) {
@@ -1116,7 +1143,6 @@ bool TextEdit::_get_mouse_pos(const Point2i& p_mouse, int &r_row, int &r_col) co
r_row=row;
r_col=col;
- return true;
}
void TextEdit::_input_event(const InputEvent& p_input_event) {
@@ -1174,8 +1200,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
if (mb.button_index==BUTTON_LEFT) {
int row,col;
- if (!_get_mouse_pos(Point2i(mb.x,mb.y), row,col))
- return;
+ _get_mouse_pos(Point2i(mb.x,mb.y), row,col);
int prev_col=cursor.column;
int prev_line=cursor.line;
@@ -1207,27 +1232,30 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
update();
} else {
- if (cursor.line<selection.from_line || (cursor.line==selection.from_line && cursor.column<=selection.from_column)) {
- selection.from_column=cursor.column;
- selection.from_line=cursor.line;
- } else if (cursor.line>selection.to_line || (cursor.line==selection.to_line && cursor.column>=selection.to_column)) {
- selection.to_column=cursor.column;
- selection.to_line=cursor.line;
-
- } else if (!selection.shiftclick_left) {
+ if (cursor.line<selection.selecting_line || (cursor.line==selection.selecting_line && cursor.column<selection.selecting_column)) {
+ if (selection.shiftclick_left) {
+ SWAP(selection.from_column,selection.to_column);
+ SWAP(selection.from_line,selection.to_line);
+ selection.shiftclick_left = !selection.shiftclick_left;
+ }
selection.from_column=cursor.column;
selection.from_line=cursor.line;
- } else {
+ } else if (cursor.line>selection.selecting_line || (cursor.line==selection.selecting_line && cursor.column>selection.selecting_column)) {
+
+ if (!selection.shiftclick_left) {
+ SWAP(selection.from_column,selection.to_column);
+ SWAP(selection.from_line,selection.to_line);
+ selection.shiftclick_left = !selection.shiftclick_left;
+ }
selection.to_column=cursor.column;
selection.to_line=cursor.line;
- }
- if (selection.from_line>selection.to_line || (selection.from_line==selection.to_line && selection.from_column>selection.to_column)) {
- SWAP(selection.from_column,selection.to_column);
- SWAP(selection.from_line,selection.to_line);
+ } else {
+ selection.active=false;
}
+
update();
}
@@ -1252,6 +1280,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
if (!mb.doubleclick && (OS::get_singleton()->get_ticks_msec()-last_dblclk)<600 && cursor.line==prev_line) {
//tripleclick select line
select(cursor.line,0,cursor.line,text[cursor.line].length());
+ selection.selecting_column=0;
last_dblclk=0;
} else if (mb.doubleclick && text[cursor.line].length()) {
@@ -1276,6 +1305,8 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
end+=1;
select(cursor.line,beg,cursor.line,end);
+
+ selection.selecting_column=beg;
}
last_dblclk = OS::get_singleton()->get_ticks_msec();
@@ -1285,8 +1316,10 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
update();
}
} else {
+
+ if (mb.button_index==BUTTON_LEFT)
+ click_select_held->stop();
- selection.selecting_mode=Selection::MODE_NONE;
// notify to show soft keyboard
notification(NOTIFICATION_FOCUS_ENTER);
}
@@ -1298,17 +1331,18 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
if (mm.button_mask&BUTTON_MASK_LEFT) {
- int row,col;
- if (!_get_mouse_pos(Point2i(mm.x,mm.y), row,col))
- return;
-
- if (selection.selecting_mode==Selection::MODE_POINTER) {
+ if (selection.selecting_mode!=Selection::MODE_NONE) {
+
+ int row,col;
+ _get_mouse_pos(Point2i(mm.x,mm.y), row,col);
select(selection.selecting_line,selection.selecting_column,row,col);
cursor_set_line( row );
cursor_set_column( col );
update();
+
+ click_select_held->start();
}
@@ -1582,7 +1616,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
break;
}
- selection.selecting_test=false;
+ selection.selecting_text=false;
bool scancode_handled=true;
@@ -1605,6 +1639,13 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
else
break;
}
+ if(auto_indent){
+ // indent once again if previous line will end with ':'
+ // (i.e. colon precedes current cursor position)
+ if(cursor.column>0 && text[cursor.line][cursor.column-1]==':') {
+ ins+="\t";
+ }
+ }
_insert_text_at_cursor(ins);
_push_current_op();
@@ -1644,9 +1685,68 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
case KEY_BACKSPACE: {
if (readonly)
break;
- backspace_at_cursor();
-
+
+#ifdef APPLE_STYLE_KEYS
+ if (k.mod.alt) {
+#else
+ if (k.mod.alt) {
+ scancode_handled=false;
+ break;
+ } else if (k.mod.command) {
+#endif
+ int line=cursor.line;
+ int column=cursor.column;
+
+ bool prev_char=false;
+ bool only_whitespace=true;
+
+ while (only_whitespace && line > 0) {
+
+ while (column>0) {
+ CharType c=text[line][column-1];
+
+ if (c != '\t' && c != ' ') {
+ only_whitespace=false;
+ break;
+ }
+
+ column--;
+ }
+
+ if (only_whitespace) {
+ line--;
+ column=text[line].length();
+ }
+ }
+
+ while (column>0) {
+ bool ischar=_is_text_char(text[line][column-1]);
+
+ if (prev_char && !ischar)
+ break;
+
+ prev_char=ischar;
+ column--;
+
+ }
+
+ _remove_text(line, column, cursor.line, cursor.column);
+
+ cursor_set_line(line);
+ cursor_set_column(column);
+
+ } else {
+ backspace_at_cursor();
+ }
+
} break;
+ case KEY_KP_4: {
+ if (k.unicode != 0) {
+ scancode_handled = false;
+ break;
+ }
+ // numlock disabled. fallthrough to key_left
+ }
case KEY_LEFT: {
if (k.mod.shift)
@@ -1693,6 +1793,13 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
_post_shift_selection();
} break;
+ case KEY_KP_6: {
+ if (k.unicode != 0) {
+ scancode_handled = false;
+ break;
+ }
+ // numlock disabled. fallthrough to key_right
+ }
case KEY_RIGHT: {
if (k.mod.shift)
@@ -1736,6 +1843,13 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
_post_shift_selection();
} break;
+ case KEY_KP_8: {
+ if (k.unicode != 0) {
+ scancode_handled = false;
+ break;
+ }
+ // numlock disabled. fallthrough to key_up
+ }
case KEY_UP: {
if (k.mod.shift)
@@ -1756,6 +1870,13 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
_cancel_code_hint();
} break;
+ case KEY_KP_2: {
+ if (k.unicode != 0) {
+ scancode_handled = false;
+ break;
+ }
+ // numlock disabled. fallthrough to key_down
+ }
case KEY_DOWN: {
if (k.mod.shift)
@@ -1786,11 +1907,71 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
if (cursor.line==text.size()-1 && cursor.column==curline_len)
break; //nothing to do
- int next_line = cursor.column<curline_len?cursor.line:cursor.line+1;
- int next_column = cursor.column<curline_len?(cursor.column+1):0;
+ int next_line=cursor.column<curline_len?cursor.line:cursor.line+1;
+ int next_column;
+
+#ifdef APPLE_STYLE_KEYS
+ if (k.mod.alt) {
+#else
+ if (k.mod.alt) {
+ scancode_handled=false;
+ break;
+ } else if (k.mod.command) {
+#endif
+ int last_line=text.size()-1;
+
+ int line=cursor.line;
+ int column=cursor.column;
+
+ bool prev_char=false;
+ bool only_whitespace=true;
+
+ while (only_whitespace && line < last_line) {
+
+ while (column<text[line].length()) {
+ CharType c=text[line][column];
+
+ if (c != '\t' && c != ' ') {
+ only_whitespace=false;
+ break;
+ }
+
+ column++;
+ }
+
+ if (only_whitespace) {
+ line++;
+ column=0;
+ }
+ }
+
+ while (column<text[line].length()) {
+
+ bool ischar=_is_text_char(text[line][column]);
+
+ if (prev_char && !ischar)
+ break;
+ prev_char=ischar;
+ column++;
+ }
+
+ next_line=line;
+ next_column=column;
+ } else {
+ next_column=cursor.column<curline_len?(cursor.column+1):0;
+ }
+
_remove_text(cursor.line,cursor.column,next_line,next_column);
update();
+
} break;
+ case KEY_KP_7: {
+ if (k.unicode != 0) {
+ scancode_handled = false;
+ break;
+ }
+ // numlock disabled. fallthrough to key_home
+ }
#ifdef APPLE_STYLE_KEYS
case KEY_HOME: {
@@ -1804,18 +1985,6 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
_post_shift_selection();
} break;
- case KEY_END: {
-
- if (k.mod.shift)
- _pre_shift_selection();
-
- cursor_set_line(text.size()-1);
-
- if (k.mod.shift)
- _post_shift_selection();
-
- } break;
-
#else
case KEY_HOME: {
@@ -1842,8 +2011,31 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
if (k.mod.shift)
_post_shift_selection();
+ _cancel_completion();
+ completion_hint="";
} break;
+#endif
+ case KEY_KP_1: {
+ if (k.unicode != 0) {
+ scancode_handled = false;
+ break;
+ }
+ // numlock disabled. fallthrough to key_end
+ }
+#ifdef APPLE_STYLE_KEYS
+ case KEY_END: {
+
+ if (k.mod.shift)
+ _pre_shift_selection();
+
+ cursor_set_line(text.size()-1);
+
+ if (k.mod.shift)
+ _post_shift_selection();
+
+ } break;
+#else
case KEY_END: {
if (k.mod.shift)
@@ -1855,9 +2047,19 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
if (k.mod.shift)
_post_shift_selection();
+
+ _cancel_completion();
+ completion_hint="";
} break;
#endif
+ case KEY_KP_9: {
+ if (k.unicode != 0) {
+ scancode_handled = false;
+ break;
+ }
+ // numlock disabled. fallthrough to key_pageup
+ }
case KEY_PAGEUP: {
if (k.mod.shift)
@@ -1867,8 +2069,19 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
if (k.mod.shift)
_post_shift_selection();
+
+ _cancel_completion();
+ completion_hint="";
+
} break;
+ case KEY_KP_3: {
+ if (k.unicode != 0) {
+ scancode_handled = false;
+ break;
+ }
+ // numlock disabled. fallthrough to key_pageup
+ }
case KEY_PAGEDOWN: {
if (k.mod.shift)
@@ -1878,6 +2091,10 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
if (k.mod.shift)
_post_shift_selection();
+
+ _cancel_completion();
+ completion_hint="";
+
} break;
case KEY_A: {
@@ -1887,15 +2104,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
break;
}
- if (text.size()==1 && text[0].length()==0)
- break;
- selection.active=true;
- selection.from_line=0;
- selection.from_column=0;
- selection.to_line=text.size()-1;
- selection.to_column=text[selection.to_line].length();
- selection.selecting_mode=Selection::MODE_NONE;
- update();
+ select_all();
} break;
case KEY_X: {
@@ -2064,6 +2273,9 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
const CharType chr[2] = {(CharType)k.unicode, 0};
+ if (completion_hint!="" && k.unicode==')') {
+ completion_hint="";
+ }
if(auto_brace_completion_enabled && _is_pair_symbol(chr[0])) {
_consume_pair_symbol(chr[0]);
} else {
@@ -2077,12 +2289,6 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
}
}
-
- if (!selection.selecting_test) {
-
- selection.selecting_mode=Selection::MODE_NONE;
- }
-
return;
} break;
@@ -2094,13 +2300,14 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
void TextEdit::_pre_shift_selection() {
- if (!selection.active || selection.selecting_mode!=Selection::MODE_SHIFT) {
+ if (!selection.active || selection.selecting_mode==Selection::MODE_NONE) {
selection.selecting_line=cursor.line;
selection.selecting_column=cursor.column;
selection.active=true;
- selection.selecting_mode=Selection::MODE_SHIFT;
}
+
+ selection.selecting_mode=Selection::MODE_SHIFT;
}
void TextEdit::_post_shift_selection() {
@@ -2113,7 +2320,7 @@ void TextEdit::_post_shift_selection() {
}
- selection.selecting_test=true;
+ selection.selecting_text=true;
}
/**** TEXT EDIT CORE API ****/
@@ -2409,7 +2616,7 @@ void TextEdit::adjust_viewport_to_cursor() {
}
-void TextEdit::cursor_set_column(int p_col) {
+void TextEdit::cursor_set_column(int p_col, bool p_adjust_viewport) {
if (p_col<0)
p_col=0;
@@ -2420,7 +2627,8 @@ void TextEdit::cursor_set_column(int p_col) {
cursor.last_fit_x=get_column_x_offset(cursor.column,get_line(cursor.line));
- adjust_viewport_to_cursor();
+ if (p_adjust_viewport)
+ adjust_viewport_to_cursor();
if (!cursor_changed_dirty) {
if (is_inside_tree())
@@ -2431,7 +2639,7 @@ void TextEdit::cursor_set_column(int p_col) {
}
-void TextEdit::cursor_set_line(int p_row) {
+void TextEdit::cursor_set_line(int p_row, bool p_adjust_viewport) {
if (setting_row)
return;
@@ -2447,8 +2655,8 @@ void TextEdit::cursor_set_line(int p_row) {
cursor.line=p_row;
cursor.column=get_char_pos_for( cursor.last_fit_x, get_line( cursor.line) );
-
- adjust_viewport_to_cursor();
+ if (p_adjust_viewport)
+ adjust_viewport_to_cursor();
setting_row=false;
@@ -2755,6 +2963,10 @@ bool TextEdit::is_syntax_coloring_enabled() const {
return syntax_coloring;
}
+void TextEdit::set_auto_indent(bool p_auto_indent) {
+ auto_indent = p_auto_indent;
+}
+
void TextEdit::cut() {
if (!selection.active)
@@ -2813,9 +3025,14 @@ void TextEdit::select_all() {
selection.active=true;
selection.from_line=0;
selection.from_column=0;
+ selection.selecting_line=0;
+ selection.selecting_column=0;
selection.to_line=text.size()-1;
selection.to_column=text[selection.to_line].length();
- selection.selecting_mode=Selection::MODE_NONE;
+ selection.selecting_mode=Selection::MODE_SHIFT;
+ selection.shiftclick_left=true;
+ cursor_set_line( selection.to_line, false );
+ cursor_set_column( selection.to_column, false );
update();
}
@@ -2854,12 +3071,20 @@ void TextEdit::select(int p_from_line,int p_from_column,int p_to_line,int p_to_c
} else if (selection.from_column>selection.to_column) {
+ selection.shiftclick_left = false;
SWAP( selection.from_column, selection.to_column );
+ } else {
+
+ selection.shiftclick_left = true;
}
} else if (selection.from_line>selection.to_line) {
+ selection.shiftclick_left = false;
SWAP( selection.from_line, selection.to_line );
SWAP( selection.from_column, selection.to_column );
+ } else {
+
+ selection.shiftclick_left = true;
}
@@ -3323,9 +3548,32 @@ void TextEdit::_update_completion_candidates() {
//look for keywords first
- bool pre_keyword=false;
+ bool inquote=false;
+ int first_quote=-1;
+
+ int c=cofs-1;
+ while(c>=0) {
+ if (l[c]=='"' || l[c]=='\'') {
+ inquote=!inquote;
+ if (first_quote==-1)
+ first_quote=c;
+ }
+ c--;
+ }
- if (cofs>0 && l[cofs-1]==' ') {
+ bool pre_keyword=false;
+ bool cancel=false;
+
+ //print_line("inquote: "+itos(inquote)+"first quote "+itos(first_quote)+" cofs-1 "+itos(cofs-1));
+ if (!inquote && first_quote==cofs-1) {
+ //no completion here
+ //print_line("cancel!");
+ cancel=true;
+ } if (inquote && first_quote!=-1) {
+
+ s=l.substr(first_quote,cofs-first_quote);
+ //print_line("s: 1"+s);
+ } else if (cofs>0 && l[cofs-1]==' ') {
int kofs=cofs-1;
String kw;
while (kofs>=0 && l[kofs]==' ')
@@ -3337,7 +3585,7 @@ void TextEdit::_update_completion_candidates() {
}
pre_keyword=keywords.has(kw);
- print_line("KW "+kw+"? "+itos(pre_keyword));
+ //print_line("KW "+kw+"? "+itos(pre_keyword));
} else {
@@ -3354,7 +3602,7 @@ void TextEdit::_update_completion_candidates() {
update();
- if (!pre_keyword && s=="" && (cofs==0 || !completion_prefixes.has(String::chr(l[cofs-1])))) {
+ if (cancel || (!pre_keyword && s=="" && (cofs==0 || !completion_prefixes.has(String::chr(l[cofs-1]))))) {
//none to complete, cancel
_cancel_completion();
return;
@@ -3421,7 +3669,16 @@ void TextEdit::query_code_comple() {
String l = text[cursor.line];
int ofs = CLAMP(cursor.column,0,l.length());
- if (ofs>0 && (_is_completable(l[ofs-1]) || completion_prefixes.has(String::chr(l[ofs-1]))))
+ bool inquote=false;
+
+ int c=ofs-1;
+ while(c>=0) {
+ if (l[c]=='"' || l[c]=='\'')
+ inquote=!inquote;
+ c--;
+ }
+
+ if (ofs>0 && (inquote || _is_completable(l[ofs-1]) || completion_prefixes.has(String::chr(l[ofs-1]))))
emit_signal("request_completion");
}
@@ -3451,10 +3708,8 @@ String TextEdit::get_tooltip(const Point2& p_pos) const {
if (!tooltip_obj)
return Control::get_tooltip(p_pos);
int row,col;
- if (!_get_mouse_pos(p_pos, row,col)) {
- return Control::get_tooltip(p_pos);
- }
-
+ _get_mouse_pos(p_pos, row, col);
+
String s = text[row];
if (s.length()==0)
return Control::get_tooltip(p_pos);
@@ -3517,7 +3772,10 @@ void TextEdit::set_show_line_numbers(bool p_show) {
update();
}
+bool TextEdit::is_text_field() const {
+ return true;
+}
void TextEdit::_bind_methods() {
@@ -3526,6 +3784,7 @@ void TextEdit::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_cursor_changed_emit"),&TextEdit::_cursor_changed_emit);
ObjectTypeDB::bind_method(_MD("_text_changed_emit"),&TextEdit::_text_changed_emit);
ObjectTypeDB::bind_method(_MD("_push_current_op"),&TextEdit::_push_current_op);
+ ObjectTypeDB::bind_method(_MD("_click_selection_held"),&TextEdit::_click_selection_held);
BIND_CONSTANT( SEARCH_MATCH_CASE );
BIND_CONSTANT( SEARCH_WHOLE_WORDS );
@@ -3541,10 +3800,10 @@ void TextEdit::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_line_count"),&TextEdit::get_line_count);
ObjectTypeDB::bind_method(_MD("get_text"),&TextEdit::get_text);
- ObjectTypeDB::bind_method(_MD("get_line"),&TextEdit::get_line);
+ ObjectTypeDB::bind_method(_MD("get_line","line"),&TextEdit::get_line);
- ObjectTypeDB::bind_method(_MD("cursor_set_column","column"),&TextEdit::cursor_set_column);
- ObjectTypeDB::bind_method(_MD("cursor_set_line","line"),&TextEdit::cursor_set_line);
+ ObjectTypeDB::bind_method(_MD("cursor_set_column","column","adjust_viewport"),&TextEdit::cursor_set_column,DEFVAL(false));
+ ObjectTypeDB::bind_method(_MD("cursor_set_line","line","adjust_viewport"),&TextEdit::cursor_set_line,DEFVAL(false));
ObjectTypeDB::bind_method(_MD("cursor_get_column"),&TextEdit::cursor_get_column);
ObjectTypeDB::bind_method(_MD("cursor_get_line"),&TextEdit::cursor_get_line);
@@ -3630,7 +3889,7 @@ TextEdit::TextEdit() {
selection.selecting_mode=Selection::MODE_NONE;
selection.selecting_line=0;
selection.selecting_column=0;
- selection.selecting_test=false;
+ selection.selecting_text=false;
selection.active=false;
syntax_coloring=false;
@@ -3640,6 +3899,11 @@ TextEdit::TextEdit() {
idle_detect->set_one_shot(true);
idle_detect->set_wait_time(GLOBAL_DEF("display/text_edit_idle_detect_sec",3));
idle_detect->connect("timeout", this,"_push_current_op");
+
+ click_select_held = memnew( Timer );
+ add_child(click_select_held);
+ click_select_held->set_wait_time(0.05);
+ click_select_held->connect("timeout", this,"_click_selection_held");
#if 0
syntax_coloring=true;
@@ -3676,7 +3940,7 @@ TextEdit::TextEdit() {
next_operation_is_complex=false;
auto_brace_completion_enabled=false;
brace_matching_enabled=false;
-
+ auto_indent=false;
}
TextEdit::~TextEdit()
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 1b448bb782..2ca5ab054a 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -55,7 +55,7 @@ class TextEdit : public Control {
Mode selecting_mode;
int selecting_line,selecting_column;
- bool selecting_test;
+ bool selecting_text;
bool active;
@@ -213,11 +213,13 @@ class TextEdit : public Control {
bool auto_brace_completion_enabled;
bool brace_matching_enabled;
+ bool auto_indent;
bool cut_copy_line;
uint64_t last_dblclk;
Timer *idle_detect;
+ Timer *click_select_held;
HScrollBar *h_scroll;
VScrollBar *v_scroll;
bool updating_scrolls;
@@ -239,6 +241,7 @@ class TextEdit : public Control {
void adjust_viewport_to_cursor();
void _scroll_moved(double);
void _update_scrollbars();
+ void _click_selection_held();
void _pre_shift_selection();
void _post_shift_selection();
@@ -270,7 +273,7 @@ class TextEdit : public Control {
void _confirm_completion();
void _update_completion_candidates();
- bool _get_mouse_pos(const Point2i& p_mouse, int &r_row, int &r_col) const;
+ void _get_mouse_pos(const Point2i& p_mouse, int &r_row, int &r_col) const;
protected:
@@ -323,9 +326,10 @@ public:
brace_matching_enabled=p_enabled;
update();
}
+ void set_auto_indent(bool p_auto_indent);
- void cursor_set_column(int p_col);
- void cursor_set_line(int p_row);
+ void cursor_set_column(int p_col, bool p_adjust_viewport=true);
+ void cursor_set_line(int p_row, bool p_adjust_viewport=true);
int cursor_get_column() const;
int cursor_get_line() const;
@@ -393,6 +397,7 @@ public:
String get_text_for_completion();
+ virtual bool is_text_field() const;
TextEdit();
~TextEdit();
};
diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp
index 823fd55c6e..c885b2d73e 100644
--- a/scene/gui/texture_button.cpp
+++ b/scene/gui/texture_button.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -42,22 +42,22 @@ Size2 TextureButton::get_minimum_size() const {
else
rscale= hover->get_size();
} else
- rscale= pressed->get_size()*scale;
+ rscale=pressed->get_size();
} else
rscale= normal->get_size();
- return rscale*scale;
+ return rscale*scale.abs();
}
bool TextureButton::has_point(const Point2& p_point) const {
- if (scale[0] <= 0 || scale[1] <= 0) {
+ if (scale[0] == 0 || scale[1] == 0) {
return false;
}
- Point2 ppos = p_point/scale;
+ Point2 ppos = p_point/scale.abs();
if (click_mask.is_valid()) {
@@ -145,7 +145,7 @@ void TextureButton::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_disabled_texture","texture:Texture"),&TextureButton::set_disabled_texture);
ObjectTypeDB::bind_method(_MD("set_focused_texture","texture:Texture"),&TextureButton::set_focused_texture);
ObjectTypeDB::bind_method(_MD("set_click_mask","mask:BitMap"),&TextureButton::set_click_mask);
- ObjectTypeDB::bind_method(_MD("set_scale","scale"),&TextureButton::set_scale);
+ ObjectTypeDB::bind_method(_MD("set_texture_scale","scale"),&TextureButton::set_texture_scale);
ObjectTypeDB::bind_method(_MD("set_modulate","color"),&TextureButton::set_modulate);
ObjectTypeDB::bind_method(_MD("get_normal_texture:Texture"),&TextureButton::get_normal_texture);
@@ -154,17 +154,17 @@ void TextureButton::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_disabled_texture:Texture"),&TextureButton::get_disabled_texture);
ObjectTypeDB::bind_method(_MD("get_focused_texture:Texture"),&TextureButton::get_focused_texture);
ObjectTypeDB::bind_method(_MD("get_click_mask:BitMap"),&TextureButton::get_click_mask);
- ObjectTypeDB::bind_method(_MD("get_scale"),&TextureButton::get_scale);
+ ObjectTypeDB::bind_method(_MD("get_texture_scale"),&TextureButton::get_texture_scale);
ObjectTypeDB::bind_method(_MD("get_modulate"),&TextureButton::get_modulate);
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"textures/normal",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_normal_texture"), _SCS("get_normal_texture"));
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"textures/pressed",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_pressed_texture"), _SCS("get_pressed_texture"));
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"textures/hover",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_hover_texture"), _SCS("get_hover_texture"));
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"textures/disabled",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_disabled_texture"), _SCS("get_disabled_texture"));
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"textures/focused",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_focused_texture"), _SCS("get_focused_texture"));
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"textures/click_mask",PROPERTY_HINT_RESOURCE_TYPE,"BitMap"), _SCS("set_click_mask"), _SCS("get_click_mask")) ;
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"params/scale",PROPERTY_HINT_RANGE,"0.01,1024,0.01"), _SCS("set_scale"), _SCS("get_scale"));
- ADD_PROPERTY(PropertyInfo(Variant::COLOR,"params/modulate"), _SCS("set_modulate"), _SCS("get_modulate"));
+ ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT,"textures/normal",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_normal_texture"), _SCS("get_normal_texture"));
+ ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT,"textures/pressed",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_pressed_texture"), _SCS("get_pressed_texture"));
+ ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT,"textures/hover",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_hover_texture"), _SCS("get_hover_texture"));
+ ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT,"textures/disabled",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_disabled_texture"), _SCS("get_disabled_texture"));
+ ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT,"textures/focused",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_focused_texture"), _SCS("get_focused_texture"));
+ ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT,"textures/click_mask",PROPERTY_HINT_RESOURCE_TYPE,"BitMap"), _SCS("set_click_mask"), _SCS("get_click_mask")) ;
+ ADD_PROPERTYNO(PropertyInfo(Variant::VECTOR2,"params/scale",PROPERTY_HINT_RANGE,"0.01,1024,0.01"), _SCS("set_texture_scale"), _SCS("get_texture_scale"));
+ ADD_PROPERTYNO(PropertyInfo(Variant::COLOR,"params/modulate"), _SCS("set_modulate"), _SCS("get_modulate"));
}
@@ -232,14 +232,14 @@ void TextureButton::set_focused_texture(const Ref<Texture>& p_focused) {
focused = p_focused;
};
-void TextureButton::set_scale(Size2 p_scale) {
+void TextureButton::set_texture_scale(Size2 p_scale) {
scale=p_scale;
minimum_size_changed();
update();
}
-Size2 TextureButton::get_scale() const{
+Size2 TextureButton::get_texture_scale() const{
return scale;
}
diff --git a/scene/gui/texture_button.h b/scene/gui/texture_button.h
index 01924c1c15..0556df8061 100644
--- a/scene/gui/texture_button.h
+++ b/scene/gui/texture_button.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -68,8 +68,8 @@ public:
Ref<Texture> get_focused_texture() const;
Ref<BitMap> get_click_mask() const;
- void set_scale(Size2 p_scale);
- Size2 get_scale() const;
+ void set_texture_scale(Size2 p_scale);
+ Size2 get_texture_scale() const;
void set_modulate(const Color& p_modulate);
Color get_modulate() const;
diff --git a/scene/gui/texture_frame.cpp b/scene/gui/texture_frame.cpp
index 931fb1cb1a..73fecf591a 100644
--- a/scene/gui/texture_frame.cpp
+++ b/scene/gui/texture_frame.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -77,9 +77,9 @@ void TextureFrame::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_expand","enable"), & TextureFrame::set_expand );
ObjectTypeDB::bind_method(_MD("has_expand"), & TextureFrame::has_expand );
- ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), _SCS("set_texture"),_SCS("get_texture") );
- ADD_PROPERTY( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate") );
- ADD_PROPERTY( PropertyInfo( Variant::BOOL, "expand" ), _SCS("set_expand"),_SCS("has_expand") );
+ ADD_PROPERTYNZ( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), _SCS("set_texture"),_SCS("get_texture") );
+ ADD_PROPERTYNO( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate") );
+ ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "expand" ), _SCS("set_expand"),_SCS("has_expand") );
}
diff --git a/scene/gui/texture_frame.h b/scene/gui/texture_frame.h
index 0ccbf5a591..f6fe6ae89d 100644
--- a/scene/gui/texture_frame.h
+++ b/scene/gui/texture_frame.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/texture_progress.cpp b/scene/gui/texture_progress.cpp
index f61d63e4c3..e05d35a81d 100644
--- a/scene/gui/texture_progress.cpp
+++ b/scene/gui/texture_progress.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -80,9 +80,50 @@ Ref<Texture> TextureProgress::get_progress_texture() const{
}
+Point2 TextureProgress::unit_val_to_uv(float val) {
+ if (progress.is_null())
+ return Point2();
+
+ if (val<0)
+ val+=1;
+ if (val>1)
+ val-=1;
+
+ Point2 p=get_relative_center();
+
+ if (val<0.125)
+ return Point2(p.x+(1-p.x)*val*8,0);
+ if (val<0.25)
+ return Point2(1,p.y*(val-0.125)*8);
+ if (val<0.375)
+ return Point2(1,p.y+(1-p.y)*(val-0.25)*8);
+ if (val<0.5)
+ return Point2(1-(1-p.x)*(val-0.375)*8,1);
+ if (val<0.625)
+ return Point2(p.x*(1-(val-0.5)*8),1);
+ if (val<0.75)
+ return Point2(0,1-((1-p.y)*(val-0.625)*8));
+ if (val<0.875)
+ return Point2(0,p.y-p.y*(val-0.75)*8);
+ else
+ return Point2(p.x*(val-0.875)*8,0);
+}
-void TextureProgress::_notification(int p_what){
+Point2 TextureProgress::get_relative_center()
+{
+ if (progress.is_null())
+ return Point2();
+ Point2 p = progress->get_size()/2;
+ p+=rad_center_off;
+ p.x/=progress->get_width();
+ p.y/=progress->get_height();
+ p.x=CLAMP(p.x,0,1);
+ p.y=CLAMP(p.y,0,1);
+ return p;
+}
+void TextureProgress::_notification(int p_what){
+ const float corners[12]={-0.125,-0.375,-0.625,-0.875,0.125,0.375,0.625,0.875,1.125,1.375,1.625,1.875};
switch(p_what) {
case NOTIFICATION_DRAW: {
@@ -92,7 +133,69 @@ void TextureProgress::_notification(int p_what){
draw_texture(under,Point2());
if (progress.is_valid()) {
Size2 s = progress->get_size();
- draw_texture_rect_region(progress,Rect2(Point2(),Size2(s.x*get_unit_value(),s.y)),Rect2(Point2(),Size2(s.x*get_unit_value(),s.y)));
+ switch (mode) {
+ case FILL_LEFT_TO_RIGHT: {
+ Rect2 region=Rect2(Point2(),Size2(s.x*get_unit_value(),s.y));
+ draw_texture_rect_region(progress,region,region);
+ } break;
+ case FILL_RIGHT_TO_LEFT: {
+ Rect2 region=Rect2(Point2(s.x-s.x*get_unit_value(),0),Size2(s.x*get_unit_value(),s.y));
+ draw_texture_rect_region(progress,region,region);
+ } break;
+ case FILL_TOP_TO_BOTTOM: {
+ Rect2 region=Rect2(Point2(),Size2(s.x,s.y*get_unit_value()));
+ draw_texture_rect_region(progress,region,region);
+ } break;
+ case FILL_BOTTOM_TO_TOP: {
+ Rect2 region=Rect2(Point2(0,s.y-s.y*get_unit_value()),Size2(s.x,s.y*get_unit_value()));
+ draw_texture_rect_region(progress,region,region);
+ } break;
+ case FILL_CLOCKWISE:
+ case FILL_COUNTER_CLOCKWISE: {
+ float val=get_unit_value()*rad_max_degrees/360;
+ if (val==1) {
+ Rect2 region=Rect2(Point2(),s);
+ draw_texture_rect_region(progress,region,region);
+ } else if (val!=0) {
+ Array pts;
+ float direction=mode==FILL_CLOCKWISE?1:-1;
+ float start=rad_init_angle/360;
+ float end=start+direction*val;
+ pts.append(start);
+ pts.append(end);
+ float from=MIN(start,end);
+ float to=MAX(start,end);
+ for (int i=0;i<12;i++)
+ if (corners[i]>from&&corners[i]<to)
+ pts.append(corners[i]);
+ pts.sort();
+ Vector<Point2> uvs;
+ Vector<Point2> points;
+ uvs.push_back(get_relative_center());
+ points.push_back(Point2(s.x*get_relative_center().x,s.y*get_relative_center().y));
+ for (int i=0;i<pts.size();i++) {
+ Point2 uv=unit_val_to_uv(pts[i]);
+ if (uvs.find(uv)>=0)
+ continue;
+ uvs.push_back(uv);
+ points.push_back(Point2(uv.x*s.x,uv.y*s.y));
+ }
+ draw_polygon(points,Vector<Color>(),uvs,progress);
+ }
+ if (get_tree()->is_editor_hint()) {
+ Point2 p=progress->get_size();
+ p.x*=get_relative_center().x;
+ p.y*=get_relative_center().y;
+ p=p.floor();
+ draw_line(p-Point2(8,0),p+Point2(8,0),Color(0.9,0.5,0.5),2);
+ draw_line(p-Point2(0,8),p+Point2(0,8),Color(0.9,0.5,0.5),2);
+ }
+ } break;
+ default:
+ draw_texture_rect_region(progress,Rect2(Point2(),Size2(s.x*get_unit_value(),s.y)),Rect2(Point2(),Size2(s.x*get_unit_value(),s.y)));
+ }
+
+
}
if (over.is_valid())
draw_texture(over,Point2());
@@ -101,6 +204,55 @@ void TextureProgress::_notification(int p_what){
}
}
+void TextureProgress::set_fill_mode(int p_fill)
+{
+ ERR_FAIL_INDEX(p_fill,6);
+ mode=(FillMode)p_fill;
+ update();
+}
+
+int TextureProgress::get_fill_mode()
+{
+ return mode;
+}
+
+void TextureProgress::set_radial_initial_angle(float p_angle)
+{
+ while(p_angle>360)
+ p_angle-=360;
+ while (p_angle<0)
+ p_angle+=360;
+ rad_init_angle=p_angle;
+ update();
+}
+
+float TextureProgress::get_radial_initial_angle()
+{
+ return rad_init_angle;
+}
+
+void TextureProgress::set_fill_degrees(float p_angle)
+{
+ rad_max_degrees=CLAMP(p_angle,0,360);
+ update();
+}
+
+float TextureProgress::get_fill_degrees()
+{
+ return rad_max_degrees;
+}
+
+void TextureProgress::set_radial_center_offset(const Point2 &p_off)
+{
+ rad_center_off=p_off;
+ update();
+}
+
+Point2 TextureProgress::get_radial_center_offset()
+{
+ return rad_center_off;
+}
+
void TextureProgress::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_under_texture","tex"),&TextureProgress::set_under_texture);
@@ -112,13 +264,39 @@ void TextureProgress::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_over_texture","tex"),&TextureProgress::set_over_texture);
ObjectTypeDB::bind_method(_MD("get_over_texture"),&TextureProgress::get_over_texture);
+ ObjectTypeDB::bind_method(_MD("set_fill_mode","mode"),&TextureProgress::set_fill_mode);
+ ObjectTypeDB::bind_method(_MD("get_fill_mode"), &TextureProgress::get_fill_mode);
+
+ ObjectTypeDB::bind_method(_MD("set_radial_initial_angle","mode"),&TextureProgress::set_radial_initial_angle);
+ ObjectTypeDB::bind_method(_MD("get_radial_initial_angle"), &TextureProgress::get_radial_initial_angle);
+
+ ObjectTypeDB::bind_method(_MD("set_radial_center_offset","mode"),&TextureProgress::set_radial_center_offset);
+ ObjectTypeDB::bind_method(_MD("get_radial_center_offset"), &TextureProgress::get_radial_center_offset);
+
+ ObjectTypeDB::bind_method(_MD("set_fill_degrees","mode"),&TextureProgress::set_fill_degrees);
+ ObjectTypeDB::bind_method(_MD("get_fill_degrees"), &TextureProgress::get_fill_degrees);
+
ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"texture/under",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_under_texture"),_SCS("get_under_texture"));
ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"texture/over",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_over_texture"),_SCS("get_over_texture"));
ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"texture/progress",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_progress_texture"),_SCS("get_progress_texture"));
+ ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"mode",PROPERTY_HINT_ENUM,"Left to Right,Right to Left,Top to Bottom,Bottom to Top,Clockwise,Counter Clockwise"),_SCS("set_fill_mode"),_SCS("get_fill_mode"));
+ ADD_PROPERTYNZ( PropertyInfo(Variant::REAL,"radial_fill/initial_angle",PROPERTY_HINT_RANGE,"0.0,360.0,0.1,slider"),_SCS("set_radial_initial_angle"),_SCS("get_radial_initial_angle"));
+ ADD_PROPERTYNZ( PropertyInfo(Variant::REAL,"radial_fill/fill_degrees",PROPERTY_HINT_RANGE,"0.0,360.0,0.1,slider"),_SCS("set_fill_degrees"),_SCS("get_fill_degrees"));
+ ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"radial_fill/center_offset"),_SCS("set_radial_center_offset"),_SCS("get_radial_center_offset"));
+
+ BIND_CONSTANT( FILL_LEFT_TO_RIGHT );
+ BIND_CONSTANT( FILL_RIGHT_TO_LEFT );
+ BIND_CONSTANT( FILL_TOP_TO_BOTTOM );
+ BIND_CONSTANT( FILL_BOTTOM_TO_TOP );
+ BIND_CONSTANT( FILL_CLOCKWISE );
+ BIND_CONSTANT( FILL_COUNTER_CLOCKWISE );
}
TextureProgress::TextureProgress()
{
+ mode=FILL_LEFT_TO_RIGHT;
+ rad_center_off=Point2();
+ rad_max_degrees=360;
}
diff --git a/scene/gui/texture_progress.h b/scene/gui/texture_progress.h
index d97ebf27f5..a4bbd71e94 100644
--- a/scene/gui/texture_progress.h
+++ b/scene/gui/texture_progress.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -45,6 +45,27 @@ protected:
void _notification(int p_what);
public:
+ enum FillMode {
+ FILL_LEFT_TO_RIGHT=0,
+ FILL_RIGHT_TO_LEFT,
+ FILL_TOP_TO_BOTTOM,
+ FILL_BOTTOM_TO_TOP,
+ FILL_CLOCKWISE,
+ FILL_COUNTER_CLOCKWISE
+ };
+
+ void set_fill_mode(int p_fill);
+ int get_fill_mode();
+
+ void set_radial_initial_angle(float p_angle);
+ float get_radial_initial_angle();
+
+ void set_fill_degrees(float p_angle);
+ float get_fill_degrees();
+
+ void set_radial_center_offset(const Point2 &p_off);
+ Point2 get_radial_center_offset();
+
void set_under_texture(const Ref<Texture>& p_texture);
Ref<Texture> get_under_texture() const;
@@ -57,6 +78,16 @@ public:
Size2 get_minimum_size() const;
TextureProgress();
+
+private:
+
+ FillMode mode;
+ float rad_init_angle;
+ float rad_max_degrees;
+ Point2 rad_center_off;
+
+ Point2 unit_val_to_uv(float val);
+ Point2 get_relative_center();
};
#endif // TEXTURE_PROGRESS_H
diff --git a/scene/gui/tool_button.cpp b/scene/gui/tool_button.cpp
index d5bcb73476..fd27800384 100644
--- a/scene/gui/tool_button.cpp
+++ b/scene/gui/tool_button.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/tool_button.h b/scene/gui/tool_button.h
index 648d776b51..f48d7d413c 100644
--- a/scene/gui/tool_button.h
+++ b/scene/gui/tool_button.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index a09920cb2b..8d28180490 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,7 +31,7 @@
#include "os/os.h"
#include "os/keyboard.h"
#include "globals.h"
-
+#include "os/input.h"
@@ -70,6 +70,7 @@ Size2 TreeItem::Cell::get_icon_size() const {
else
return icon_region.size;
}
+
void TreeItem::Cell::draw_icon(const RID& p_where, const Point2& p_pos, const Size2& p_size) const{
if (icon.is_null())
@@ -120,7 +121,7 @@ void TreeItem::set_cell_mode( int p_column, TreeCellMode p_mode ) {
c.val=0;
c.checked=false;
c.icon=Ref<Texture>();
- c.text="";
+ c.text="";
c.icon_max_w=0;
_changed_notify(p_column);
}
@@ -152,9 +153,9 @@ void TreeItem::set_text(int p_column,String p_text) {
ERR_FAIL_INDEX( p_column, cells.size() );
cells[p_column].text=p_text;
-
+
if (cells[p_column].mode==TreeItem::CELL_MODE_RANGE) {
-
+
cells[p_column].min=0;
cells[p_column].max=p_text.get_slice_count(",");
cells[p_column].step=0;
@@ -224,7 +225,7 @@ void TreeItem::set_range(int p_column,double p_value) {
p_value=cells[p_column].min;
if (p_value>cells[p_column].max)
p_value=cells[p_column].max;
-
+
cells[p_column].val=p_value;
_changed_notify(p_column);
@@ -236,7 +237,7 @@ double TreeItem::get_range(int p_column) const {
return cells[p_column].val;
}
-
+
bool TreeItem::is_range_exponential(int p_column) const {
ERR_FAIL_INDEX_V( p_column, cells.size(), false);
@@ -303,7 +304,7 @@ void TreeItem::set_collapsed(bool p_collapsed) {
if (tree->select_mode==Tree::SELECT_MULTI) {
- tree->selected_item=this;
+ tree->selected_item=this;
emit_signal("cell_selected");
} else {
@@ -336,11 +337,11 @@ TreeItem *TreeItem::get_prev() {
if (!parent || parent->childs==this)
return NULL;
-
+
TreeItem *prev = parent->childs;
while(prev && prev->next!=this)
prev=prev->next;
-
+
return prev;
}
@@ -635,14 +636,14 @@ void TreeItem::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_range","column"),&TreeItem::get_range);
ObjectTypeDB::bind_method(_MD("set_range_config","column","min","max","step","expr"),&TreeItem::set_range_config,DEFVAL(false));
ObjectTypeDB::bind_method(_MD("get_range_config","column"),&TreeItem::_get_range_config);
-
+
ObjectTypeDB::bind_method(_MD("set_metadata","column","meta"),&TreeItem::set_metadata);
ObjectTypeDB::bind_method(_MD("get_metadata","column"),&TreeItem::get_metadata);
ObjectTypeDB::bind_method(_MD("set_custom_draw","column","object","callback"),&TreeItem::set_custom_draw);
ObjectTypeDB::bind_method(_MD("set_collapsed","enable"),&TreeItem::set_collapsed);
- ObjectTypeDB::bind_method(_MD("is_collapsed"),&TreeItem::is_collapsed);
+ ObjectTypeDB::bind_method(_MD("is_collapsed"),&TreeItem::is_collapsed);
ObjectTypeDB::bind_method(_MD("get_next:TreeItem"),&TreeItem::get_next);
ObjectTypeDB::bind_method(_MD("get_prev:TreeItem"),&TreeItem::get_prev);
@@ -653,17 +654,17 @@ void TreeItem::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_prev_visible:TreeItem"),&TreeItem::get_prev_visible);
ObjectTypeDB::bind_method(_MD("remove_child:TreeItem","child"),&TreeItem::_remove_child);
-
+
ObjectTypeDB::bind_method(_MD("set_selectable","column","selectable"),&TreeItem::set_selectable);
ObjectTypeDB::bind_method(_MD("is_selectable","column"),&TreeItem::is_selectable);
ObjectTypeDB::bind_method(_MD("is_selected","column"),&TreeItem::is_selected);
ObjectTypeDB::bind_method(_MD("select","column"),&TreeItem::select);
ObjectTypeDB::bind_method(_MD("deselect","column"),&TreeItem::deselect);
-
+
ObjectTypeDB::bind_method(_MD("set_editable","column","enabled"),&TreeItem::set_editable);
ObjectTypeDB::bind_method(_MD("is_editable","column"),&TreeItem::is_editable);
-
+
ObjectTypeDB::bind_method(_MD("set_custom_color","column","color"),&TreeItem::set_custom_color);
ObjectTypeDB::bind_method(_MD("clear_custom_color","column"),&TreeItem::clear_custom_color);
@@ -671,7 +672,7 @@ void TreeItem::_bind_methods() {
ObjectTypeDB::bind_method(_MD("clear_custom_bg_color","column"),&TreeItem::clear_custom_bg_color);
ObjectTypeDB::bind_method(_MD("get_custom_bg_color","column"),&TreeItem::get_custom_bg_color);
- ObjectTypeDB::bind_method(_MD("add_button","column","button:Texture"),&TreeItem::add_button);
+ ObjectTypeDB::bind_method(_MD("add_button","column","button:Texture","button_idx"),&TreeItem::add_button);
ObjectTypeDB::bind_method(_MD("get_button_count","column"),&TreeItem::get_button_count);
ObjectTypeDB::bind_method(_MD("get_button:Texture","column","button_idx"),&TreeItem::get_button);
ObjectTypeDB::bind_method(_MD("erase_button","column","button_idx"),&TreeItem::erase_button);
@@ -687,7 +688,7 @@ void TreeItem::_bind_methods() {
BIND_CONSTANT( CELL_MODE_RANGE );
BIND_CONSTANT( CELL_MODE_ICON );
BIND_CONSTANT( CELL_MODE_CUSTOM );
-
+
}
@@ -728,14 +729,20 @@ TreeItem::~TreeItem() {
tree->root=0;
}
- if (tree && tree->popup_edited_item==this)
+ if (tree && tree->popup_edited_item==this) {
tree->popup_edited_item=NULL;
+ tree->pressing_for_editor=false;
+
+ }
if (tree && tree->selected_item==this)
tree->selected_item=NULL;
- if (tree && tree->edited_item==this)
+ if (tree && tree->edited_item==this) {
tree->edited_item=NULL;
+ tree->pressing_for_editor=false;
+ }
+
}
@@ -767,7 +774,7 @@ void Tree::update_cache() {
cache.arrow =get_icon("arrow");
cache.select_arrow =get_icon("select_arrow");
cache.updown=get_icon("updown");
-
+
cache.font_color=get_color("font_color");
cache.font_color_selected=get_color("font_color_selected");
cache.guide_color=get_color("guide_color");
@@ -795,10 +802,10 @@ int Tree::compute_item_height(TreeItem *p_item) const {
if (p_item==root && hide_root)
return 0;
-
+
int height=cache.font->get_height();
-
+
for (int i=0;i<columns.size();i++) {
@@ -812,23 +819,23 @@ int Tree::compute_item_height(TreeItem *p_item) const {
}
switch(p_item->cells[i].mode) {
-
+
case TreeItem::CELL_MODE_CHECK: {
-
+
int check_icon_h = cache.checked->get_height();
if (height<check_icon_h)
height=check_icon_h;
-
-
-
+
+
+
}
case TreeItem::CELL_MODE_STRING:
case TreeItem::CELL_MODE_CUSTOM:
case TreeItem::CELL_MODE_ICON: {
-
+
Ref<Texture> icon = p_item->cells[i].icon;
if (!icon.is_null()) {
-
+
Size2i s = p_item->cells[i].get_icon_size();
if (p_item->cells[i].icon_max_w>0 && s.width > p_item->cells[i].icon_max_w ) {
s.height=s.height * p_item->cells[i].icon_max_w / s.width;
@@ -836,15 +843,15 @@ int Tree::compute_item_height(TreeItem *p_item) const {
if (s.height > height )
height=s.height;
}
-
+
} break;
default: {}
}
}
-
-
+
+
height += cache.vseparation;
-
+
return height;
}
@@ -920,7 +927,7 @@ void Tree::draw_item_text(String p_text,const Ref<Texture>& p_icon,int p_icon_ma
p_rect.size.x-=Math::floor(p_rect.size.y/2);
Ref<Font> font = cache.font;
-
+
p_rect.pos.y+=Math::floor((p_rect.size.y-font->get_height())/2.0) +font->get_ascent();
font->draw(ci,p_rect.pos,p_text,p_color,p_rect.size.x);
}
@@ -943,22 +950,24 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
Point2i guide_from;
- bool skip=(p_item==root && hide_root);
+ bool skip=(p_item==root && hide_root);
// printf("skip (%p == %p && %i) %i\n",p_item,root,hide_root,skip);
if (!skip && (p_pos.y+label_h-cache.offset.y)>0) {
- // printf("entering\n");
+ // printf("entering\n");
int height=label_h;
Point2i guide_space=Point2i( cache.guide_width , height );
- if (p_item->childs) { //has childs, draw the guide box
+
+
+ if (!hide_folding && p_item->childs) { //has childs, draw the guide box
Ref<Texture> arrow;
-
+
if (p_item->collapsed) {
arrow=cache.arrow_collapsed;
@@ -976,10 +985,10 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
// if (p_item->get_parent()!=root || !hide_root)
Ref<Font> font = cache.font;
-
+
int font_ascent=font->get_ascent();
- int ofs = p_pos.x + cache.item_margin;
+ int ofs = p_pos.x + (hide_folding?cache.hseparation:cache.item_margin);
for (int i=0;i<columns.size();i++) {
int w = get_column_width(i);
@@ -1055,11 +1064,14 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
if (p_item->cells[i].custom_bg_color) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci,cell_rect,p_item->cells[i].bg_color);
+ Rect2 r=cell_rect;
+ r.pos.x-=cache.hseparation;
+ r.size.x+=cache.hseparation;
+ VisualServer::get_singleton()->canvas_item_add_rect(ci,r,p_item->cells[i].bg_color);
}
Color col=p_item->cells[i].custom_color?p_item->cells[i].color:get_color( p_item->cells[i].selected?"font_color_selected":"font_color");
-
+
Point2i text_pos=item_rect.pos;
text_pos.y+=Math::floor((item_rect.size.y-font->get_height())/2) + font_ascent;
@@ -1097,7 +1109,7 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
} break;
case TreeItem::CELL_MODE_RANGE: {
-
+
if (p_item->cells[i].text!="") {
if (!p_item->cells[i].editable)
@@ -1106,7 +1118,7 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
int option = (int)p_item->cells[i].val;
String s = p_item->cells[i].text;
- s=s.get_slice(",",option);
+ s=s.get_slicec(',',option);
Ref<Texture> downarrow = cache.select_arrow;
@@ -1121,7 +1133,7 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
} else {
Ref<Texture> updown = cache.updown;
-
+
String valtext = String::num( p_item->cells[i].val, Math::decimals( p_item->cells[i].step ) );
font->draw( ci, text_pos, valtext, col, item_rect.size.x-updown->get_width());
@@ -1178,7 +1190,7 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
Rect2i ir=item_rect;
ir.size.width-=downarrow->get_width();
draw_item_rect(p_item->cells[i],ir,col);
-
+
Point2i arrow_pos=item_rect.pos;
arrow_pos.x+=item_rect.size.x-downarrow->get_width();
arrow_pos.y+=Math::floor(((item_rect.size.y-downarrow->get_height()))/2.0);
@@ -1220,7 +1232,7 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2&
children_pos.x+=cache.item_margin;
htotal+=label_h;
children_pos.y+=htotal;
-
+
}
@@ -1265,12 +1277,12 @@ void Tree::select_single_item(TreeItem *p_selected,TreeItem *p_current,int p_col
continue;
if (select_mode==SELECT_ROW) {
-
+
if (p_selected==p_current) {
-
+
if (!c.selected) {
-
+
c.selected=true;
selected_item=p_selected;
selected_col=0;
@@ -1279,28 +1291,29 @@ void Tree::select_single_item(TreeItem *p_selected,TreeItem *p_current,int p_col
//if (p_col==i)
// p_current->selected_signal.call(p_col);
}
-
+
} else {
-
+
if (c.selected) {
-
- c.selected=false;
+
+ c.selected=false;
//p_current->deselected_signal.call(p_col);
}
-
+
}
-
+
} else if (select_mode==SELECT_SINGLE || select_mode==SELECT_MULTI) {
-
- if (&selected_cell==&c) {
-
+
+ if (!r_in_range && &selected_cell==&c) {
+
if (!selected_cell.selected) {
-
+
selected_cell.selected=true;
-
+
selected_item=p_selected;
selected_col=i;
+
emit_signal("cell_selected");
if (select_mode==SELECT_MULTI)
emit_signal("multi_selected",p_current,i,true);
@@ -1313,10 +1326,11 @@ void Tree::select_single_item(TreeItem *p_selected,TreeItem *p_current,int p_col
}
} else {
-
+
if (r_in_range && *r_in_range) {
+
if (!c.selected && c.selectable) {
c.selected=true;
emit_signal("multi_selected",p_current,i,true);
@@ -1355,7 +1369,40 @@ Rect2 Tree::search_item_rect(TreeItem *p_from, TreeItem *p_item) {
}
+void Tree::_range_click_timeout() {
+ if (range_item_last && !range_drag_enabled && Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT)) {
+
+ Point2 pos = (Input::get_singleton()->get_mouse_pos()-get_global_pos())-cache.bg->get_offset();
+ if (show_column_titles) {
+ pos.y-=_get_title_button_height();
+
+ if (pos.y<0) {
+ range_click_timer->stop();
+ return;
+ }
+ }
+
+ click_handled=false;
+ InputModifierState mod = {}; // should be irrelevant..
+
+ blocked++;
+ propagate_mouse_event(pos+cache.offset, 0, 0, false, root, BUTTON_LEFT, mod);
+ blocked--;
+
+ if (range_click_timer->is_one_shot()) {
+ range_click_timer->set_wait_time(0.05);
+ range_click_timer->set_one_shot(false);
+ range_click_timer->start();
+ }
+
+ if (!click_handled)
+ range_click_timer->stop();
+
+ } else {
+ range_click_timer->stop();
+ }
+}
int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_doubleclick,TreeItem *p_item,int p_button,const InputModifierState& p_mod) {
@@ -1363,11 +1410,11 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
int item_h=compute_item_height( p_item )+cache.vseparation;
bool skip=(p_item==root && hide_root);
-
+
if (!skip && p_pos.y<item_h) {
// check event!
- if (p_pos.x >=x_ofs && p_pos.x < (x_ofs+cache.item_margin) ) {
+ if (!hide_folding && (p_pos.x >=x_ofs && p_pos.x < (x_ofs+cache.item_margin) )) {
if (p_item->childs)
@@ -1375,7 +1422,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
return -1; //handled!
}
-
+
int x=p_pos.x;
/* find clicked column */
int col=-1;
@@ -1394,7 +1441,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
break;
}
-
+
if (col==-1)
return -1;
@@ -1467,7 +1514,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
if (select_mode==SELECT_MULTI && p_mod.shift && selected_item && selected_item!=p_item) {
bool inrange=false;
- print_line("SELECT MULTI AND SHIFT AND ALL");
+
select_single_item( p_item, root, col,selected_item,&inrange );
} else {
select_single_item( p_item, root, col );
@@ -1478,8 +1525,8 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
//}
update();
}
-
-
+
+
}
}
@@ -1490,7 +1537,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
/* editing */
- bool bring_up_editor=c.selected && already_selected;
+ bool bring_up_editor=c.selected;// && already_selected;
bool bring_up_value_editor=false;
String editor_text=c.text;
@@ -1505,14 +1552,14 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
} break;
case TreeItem::CELL_MODE_CHECK: {
-
+
Ref<Texture> checked = cache.checked;
bring_up_editor=false; //checkboxes are not edited with editor
if (x>=0 && x<= checked->get_width()+cache.hseparation ) {
-
+
p_item->set_checked(col,!c.checked);
- item_edited(col,p_item);
+ item_edited(col,p_item);
click_handled=true;
//p_item->edited_signal.call(col);
}
@@ -1527,7 +1574,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
popup_menu->clear();
for (int i=0;i<c.text.get_slice_count(",");i++) {
- String s = c.text.get_slice(",",i);
+ String s = c.text.get_slicec(',',i);
popup_menu->add_item(s,i);
}
@@ -1540,37 +1587,53 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
//}
bring_up_editor=false;
} else {
-
+
Ref<Texture> updown = cache.updown;
-
-
+
+
if (x >= (col_width-item_h/2)) {
-
+
/* touching the combo */
bool up=p_pos.y < (item_h /2);
-
+
if (p_button==BUTTON_LEFT) {
+
+ if (range_click_timer->get_time_left() == 0) {
+
+ range_item_last=p_item;
+ range_up_last=up;
+
+ range_click_timer->set_wait_time(0.6);
+ range_click_timer->set_one_shot(true);
+ range_click_timer->start();
+
+ } else if (up != range_up_last) {
+
+ return -1; // break. avoid changing direction on mouse held
+ }
+
p_item->set_range( col, c.val + (up?1.0:-1.0) * c.step );
-
- item_edited(col,p_item);
+
+ item_edited(col,p_item);
+
} else if (p_button==BUTTON_RIGHT) {
-
+
p_item->set_range( col, (up?c.max:c.min) );
- item_edited(col,p_item);
+ item_edited(col,p_item);
} else if (p_button==BUTTON_WHEEL_UP) {
-
+
p_item->set_range( col, c.val + c.step );
- item_edited(col,p_item);
+ item_edited(col,p_item);
} else if (p_button==BUTTON_WHEEL_DOWN) {
-
+
p_item->set_range( col, c.val - c.step );
- item_edited(col,p_item);
+ item_edited(col,p_item);
}
-
- //p_item->edited_signal.call(col);
+
+ //p_item->edited_signal.call(col);
bring_up_editor=false;
-
-
+
+
} else {
editor_text=String::num( p_item->cells[col].val, Math::decimals( p_item->cells[col].step ) );
@@ -1578,7 +1641,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
if (select_mode==SELECT_MULTI && get_tree()->get_last_event_id() == focus_in_id)
bring_up_editor=false;
- }
+ }
}
click_handled=true;
@@ -1589,12 +1652,12 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
} break;
case TreeItem::CELL_MODE_CUSTOM: {
edited_item=p_item;
- edited_col=col;
+ edited_col=col;
custom_popup_rect=Rect2i(get_global_pos() + Point2i(col_ofs,_get_title_button_height()+y_ofs+item_h-cache.offset.y), Size2(get_column_width(col),item_h));
emit_signal("custom_popup_edited",((bool)(x >= (col_width-item_h/2))));
bring_up_editor=false;
- item_edited(col,p_item);
+ item_edited(col,p_item);
click_handled=true;
return -1;
} break;
@@ -1605,44 +1668,27 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_
return -1;
+
click_handled=true;
popup_edited_item=p_item;
popup_edited_item_col=col;
- text_editor->set_pos(get_global_pos() + Point2i(col_ofs,_get_title_button_height()+y_ofs)-cache.offset );
- text_editor->set_size( Size2(col_width,item_h));
- text_editor->clear();
- text_editor->set_text( editor_text );
- text_editor->select_all();
-
- if (bring_up_value_editor) {
-
- value_editor->set_pos(get_global_pos() + Point2i(col_ofs,_get_title_button_height()+y_ofs)-cache.offset+Point2i(0,text_editor->get_size().height) );
- value_editor->set_size( Size2(col_width,1));
- value_editor->show_modal();
- updating_value_editor=true;
- value_editor->set_min( c.min );
- value_editor->set_max( c.max );
- value_editor->set_step( c.step );
- value_editor->set_val( c.val );
- value_editor->set_exp_unit_value( c.expr );
- updating_value_editor=false;
- }
- text_editor->show_modal();
- text_editor->grab_focus();
+ pressing_item_rect=Rect2(get_global_pos() + Point2i(col_ofs,_get_title_button_height()+y_ofs)-cache.offset,Size2(col_width,item_h));
+ pressing_for_editor_text=editor_text;
+ pressing_for_editor=true;
return -1; //select
} else {
Point2i new_pos=p_pos;
-
+
if (!skip) {
x_ofs+=cache.item_margin;
//new_pos.x-=cache.item_margin;
y_ofs+=item_h;
new_pos.y-=item_h;
}
-
+
if (!p_item->collapsed) { /* if not collapsed, check the childs */
@@ -1675,6 +1721,7 @@ void Tree::text_editor_enter(String p_text) {
text_editor->hide();
+ value_editor->hide();
if (!popup_edited_item)
return;
@@ -1705,7 +1752,7 @@ void Tree::text_editor_enter(String p_text) {
default: { ERR_FAIL(); }
}
- item_edited(popup_edited_item_col,popup_edited_item);
+ item_edited(popup_edited_item_col,popup_edited_item);
update();
}
@@ -1733,19 +1780,19 @@ void Tree::popup_select(int p_option) {
if (popup_edited_item_col<0 || popup_edited_item_col>columns.size())
return;
-
+
popup_edited_item->cells[popup_edited_item_col].val=p_option;
//popup_edited_item->edited_signal.call( popup_edited_item_col );
update();
- item_edited(popup_edited_item_col,popup_edited_item);
+ item_edited(popup_edited_item_col,popup_edited_item);
}
void Tree::_input_event(InputEvent p_event) {
-
+
switch (p_event.type) {
-
+
case InputEvent::KEY: {
if (!p_event.key.pressed)
@@ -2027,6 +2074,8 @@ void Tree::_input_event(InputEvent p_event) {
update_cache();
const InputEventMouseMotion& b=p_event.mouse_motion;
+ range_click_timer->stop();
+
Ref<StyleBox> bg = cache.bg;
Point2 pos = Point2(b.x,b.y) - bg->get_offset();
@@ -2034,7 +2083,6 @@ void Tree::_input_event(InputEvent p_event) {
Cache::ClickType old_hover = cache.hover_type;
int old_index = cache.hover_index;
-
cache.hover_type=Cache::CLICK_NONE;
cache.hover_index=0;
if (show_column_titles) {
@@ -2062,6 +2110,32 @@ void Tree::_input_event(InputEvent p_event) {
update();
}
+ if (pressing_for_editor && popup_edited_item && popup_edited_item->get_cell_mode(popup_edited_item_col)==TreeItem::CELL_MODE_RANGE) {
+ //range drag
+
+ if (!range_drag_enabled) {
+
+ Vector2 cpos = Vector2(b.x,b.y);
+ if (cpos.distance_to(pressing_pos)>2) {
+ range_drag_enabled=true;
+ range_drag_capture_pos=cpos;
+ range_drag_base=popup_edited_item->get_range(popup_edited_item_col);
+ Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED);
+ }
+ } else {
+
+ TreeItem::Cell &c=popup_edited_item->cells[popup_edited_item_col];
+ float diff_y = -b.relative_y;
+ diff_y=Math::pow(ABS(diff_y),1.8)*SGN(diff_y);
+ diff_y*=0.1;
+ range_drag_base=CLAMP(range_drag_base + c.step * diff_y, c.min, c.max);
+ popup_edited_item->set_range(popup_edited_item_col,range_drag_base);
+ item_edited(popup_edited_item_col,popup_edited_item);
+
+ }
+
+ }
+
if (drag_touching && ! drag_touching_deaccel) {
@@ -2072,18 +2146,36 @@ void Tree::_input_event(InputEvent p_event) {
}
} break;
case InputEvent::MOUSE_BUTTON: {
-
+
if (cache.font.is_null()) // avoid a strange case that may fuckup stuff
update_cache();
- const InputEventMouseButton& b=p_event.mouse_button;
+ const InputEventMouseButton& b=p_event.mouse_button;
if (!b.pressed) {
if (b.button_index==BUTTON_LEFT) {
+ range_click_timer->stop();
+
+ if (pressing_for_editor) {
+
+ if (range_drag_enabled) {
+
+ range_drag_enabled=false;
+ Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
+ warp_mouse(range_drag_capture_pos);
+ } else
+ edit_selected();
+
+ pressing_for_editor=false;
+
+ }
+
+
+
if (cache.click_type==Cache::CLICK_BUTTON) {
emit_signal("button_pressed",cache.click_item,cache.click_column,cache.click_id);
@@ -2116,7 +2208,7 @@ void Tree::_input_event(InputEvent p_event) {
switch(b.button_index) {
case BUTTON_LEFT: {
Ref<StyleBox> bg = cache.bg;
-
+
Point2 pos = Point2(b.x,b.y) - bg->get_offset();
cache.click_type=Cache::CLICK_NONE;
if (show_column_titles) {
@@ -2145,11 +2237,15 @@ void Tree::_input_event(InputEvent p_event) {
break;
click_handled=false;
+ pressing_for_editor=false;
blocked++;
bool handled = propagate_mouse_event(pos+cache.offset,0,0,b.doubleclick,root,b.button_index,b.mod);
blocked--;
+ if (pressing_for_editor) {
+ pressing_pos=Point2(b.x,b.y);
+ }
if (drag_touching) {
@@ -2174,18 +2270,21 @@ void Tree::_input_event(InputEvent p_event) {
} break;
- case BUTTON_WHEEL_UP: {
+ case BUTTON_WHEEL_UP: {
+
+ range_click_timer->stop();
v_scroll->set_val( v_scroll->get_val()-v_scroll->get_page()/8 );
} break;
case BUTTON_WHEEL_DOWN: {
-
+
+ range_click_timer->stop();
v_scroll->set_val( v_scroll->get_val()+v_scroll->get_page()/8 );
} break;
}
-
+
} break;
}
-
+
}
@@ -2218,9 +2317,12 @@ bool Tree::edit_selected() {
TreeItem::Cell &c = s->cells[col];
+ if (c.mode==TreeItem::CELL_MODE_CHECK) {
-
- if (c.mode==TreeItem::CELL_MODE_CUSTOM) {
+ s->set_checked(col, !c.checked);
+ item_edited(col,s);
+ return true;
+ } else if (c.mode==TreeItem::CELL_MODE_CUSTOM) {
edited_item=s;
edited_col=col;
@@ -2234,7 +2336,7 @@ bool Tree::edit_selected() {
popup_menu->clear();
for (int i=0;i<c.text.get_slice_count(",");i++) {
- String s = c.text.get_slice(",",i);
+ String s = c.text.get_slicec(',',i);
popup_menu->add_item(s,i);
}
@@ -2283,10 +2385,10 @@ Size2 Tree::get_internal_min_size() const {
if (root)
size.height+=get_item_height(root);
for (int i=0;i<columns.size();i++) {
-
+
size.width+=columns[i].min_width;
}
-
+
return size;
}
@@ -2305,39 +2407,39 @@ void Tree::update_scrollbars() {
Size2 vmin = v_scroll->get_combined_minimum_size();
-
+
v_scroll->set_begin( Point2(size.width - vmin.width , cache.bg->get_margin(MARGIN_TOP)) );
v_scroll->set_end( Point2(size.width, size.height-cache.bg->get_margin(MARGIN_TOP)-cache.bg->get_margin(MARGIN_BOTTOM)) );
-
+
h_scroll->set_begin( Point2( 0, size.height - hmin.height) );
h_scroll->set_end( Point2(size.width-vmin.width, size.height) );
-
-
+
+
Size2 min = get_internal_min_size();
-
+
if (min.height < size.height - hmin.height) {
-
+
v_scroll->hide();
cache.offset.y=0;
} else {
-
+
v_scroll->show();
v_scroll->set_max(min.height);
v_scroll->set_page(size.height - hmin.height - tbh);
cache.offset.y=v_scroll->get_val();
}
-
+
if (min.width < size.width - vmin.width) {
-
+
h_scroll->hide();
cache.offset.x=0;
} else {
-
+
h_scroll->show();
h_scroll->set_max(min.width);
h_scroll->set_page(size.width - vmin.width);
cache.offset.x=h_scroll->get_val();
- }
+ }
}
@@ -2360,6 +2462,11 @@ void Tree::_notification(int p_what) {
}
}
+ if (p_what==NOTIFICATION_VISIBILITY_CHANGED) {
+
+ drag_touching=false;
+ }
+
if (p_what==NOTIFICATION_ENTER_TREE) {
update_cache();;
@@ -2411,16 +2518,16 @@ void Tree::_notification(int p_what) {
}
if (p_what==NOTIFICATION_DRAW) {
-
+
update_cache();
update_scrollbars();
- RID ci = get_canvas_item();
-
+ RID ci = get_canvas_item();
+
VisualServer::get_singleton()->canvas_item_set_clip(ci,true);
-
+
Ref<StyleBox> bg = cache.bg;
Ref<StyleBox> bg_focus = get_stylebox("bg_focus");
-
+
Point2 draw_ofs;
draw_ofs+=bg->get_offset();
Size2 draw_size=get_size()-bg->get_minimum_size();
@@ -2438,7 +2545,7 @@ void Tree::_notification(int p_what) {
draw_size.y-=tbh;
if (root) {
-
+
draw_item( Point2(),draw_ofs,draw_size,root);
@@ -2449,10 +2556,10 @@ void Tree::_notification(int p_what) {
// int size_y=exposed.size.height-bg->get_minimum_size().height;
for (int i=0;i<(columns.size()-1-1);i++) {
-
+
ofs+=get_column_width(i);
//get_painter()->draw_fill_rect( Point2(ofs+cache.hseparation/2, from_y), Size2( 1, size_y ),color( COLOR_TREE_GRID) );
- }
+ }
if (show_column_titles) {
@@ -2552,7 +2659,7 @@ TreeItem* Tree::get_last_item() {
}
void Tree::item_edited(int p_column,TreeItem *p_item) {
-
+
edited_item=p_item;
edited_col=p_column;
emit_signal("item_edited");
@@ -2560,14 +2667,14 @@ void Tree::item_edited(int p_column,TreeItem *p_item) {
void Tree::item_changed(int p_column,TreeItem *p_item) {
- update();
+ update();
}
void Tree::item_selected(int p_column,TreeItem *p_item) {
if (select_mode==SELECT_MULTI) {
-
+
if (!p_item->cells[p_column].selectable)
return;
@@ -2583,16 +2690,16 @@ void Tree::item_selected(int p_column,TreeItem *p_item) {
void Tree::item_deselected(int p_column,TreeItem *p_item) {
if (select_mode==SELECT_MULTI) {
-
+
p_item->cells[p_column].selected=false;
- }
+ }
update();
}
void Tree::set_select_mode(SelectMode p_mode) {
- select_mode=p_mode;
+ select_mode=p_mode;
}
void Tree::clear() {
@@ -2610,6 +2717,8 @@ void Tree::clear() {
selected_item=NULL;
edited_item=NULL;
popup_edited_item=NULL;
+ selected_item=NULL;
+ pressing_for_editor=false;
update();
};
@@ -2620,15 +2729,15 @@ void Tree::set_hide_root(bool p_enabled) {
- hide_root=p_enabled;
- update();
+ hide_root=p_enabled;
+ update();
}
void Tree::set_column_min_width(int p_column,int p_min_width) {
ERR_FAIL_INDEX(p_column,columns.size());
-
+
if (p_min_width<1)
return;
columns[p_column].min_width=p_min_width;
@@ -2638,8 +2747,8 @@ void Tree::set_column_min_width(int p_column,int p_min_width) {
void Tree::set_column_expand(int p_column,bool p_expand) {
ERR_FAIL_INDEX(p_column,columns.size());
-
- columns[p_column].expand=p_expand;
+
+ columns[p_column].expand=p_expand;
update();
}
@@ -2654,78 +2763,78 @@ int Tree::get_selected_column() const {
}
TreeItem *Tree::get_edited() const {
-
+
return edited_item;
}
int Tree::get_edited_column() const {
-
+
return edited_col;
}
TreeItem* Tree::get_next_selected( TreeItem* p_item) {
-
+
//if (!p_item)
// return NULL;
if (!root)
- return NULL;
-
+ return NULL;
+
while(true) {
-
-
+
+
if (!p_item) {
p_item=root;
} else {
-
+
if (p_item->childs) {
-
+
p_item=p_item->childs;
-
+
} else if (p_item->next) {
-
- p_item=p_item->next;
+
+ p_item=p_item->next;
} else {
-
+
while(!p_item->next) {
-
+
p_item=p_item->parent;
if (p_item==NULL)
return NULL;
}
-
+
p_item=p_item->next;
}
-
+
}
-
+
for (int i=0;i<columns.size();i++)
if (p_item->cells[i].selected)
return p_item;
}
-
+
return NULL;
}
int Tree::get_column_width(int p_column) const {
-
+
ERR_FAIL_INDEX_V(p_column,columns.size(),-1);
-
-
+
+
if (!columns[p_column].expand)
return columns[p_column].min_width;
-
+
Ref<StyleBox> bg = cache.bg;
-
+
int expand_area=get_size().width-(bg->get_margin(MARGIN_LEFT)+bg->get_margin(MARGIN_RIGHT));
-
+
if (v_scroll->is_visible())
expand_area-=v_scroll->get_combined_minimum_size().width;
-
+
int expanding_columns=0;
int expanding_total=0;
-
+
for (int i=0;i<columns.size();i++) {
-
+
if (!columns[i].expand) {
expand_area-=columns[i].min_width;
} else {
@@ -2736,30 +2845,30 @@ int Tree::get_column_width(int p_column) const {
if (expand_area<expanding_total)
return columns[p_column].min_width;
-
+
ERR_FAIL_COND_V(expanding_columns==0,-1); // shouldnt happen
-
+
return expand_area * columns[p_column].min_width / expanding_total;
}
void Tree::propagate_set_columns(TreeItem *p_item) {
-
+
p_item->cells.resize( columns.size() );
-
+
TreeItem *c = p_item->get_children();
while(c) {
-
+
propagate_set_columns(c);
c=c->get_next();
}
}
void Tree::set_columns(int p_columns) {
-
+
ERR_FAIL_COND(p_columns<1);
ERR_FAIL_COND(blocked>0);
columns.resize(p_columns);
-
+
if (root)
propagate_set_columns(root);
if (selected_col>=p_columns)
@@ -2769,17 +2878,17 @@ void Tree::set_columns(int p_columns) {
}
int Tree::get_columns() const {
-
+
return columns.size();
}
void Tree::_scroll_moved(float) {
-
+
update();
}
Rect2 Tree::get_custom_popup_rect() const {
-
+
return custom_popup_rect;
}
@@ -3059,9 +3168,20 @@ bool Tree::can_cursor_exit_tree() const {
return cursor_can_exit_tree;
}
+void Tree::set_hide_folding(bool p_hide) {
+ hide_folding=p_hide;
+ update();
+}
+
+bool Tree::is_folding_hidden() const {
+
+ return hide_folding;
+}
+
void Tree::_bind_methods() {
-
+
+ ObjectTypeDB::bind_method(_MD("_range_click_timeout"),&Tree::_range_click_timeout);
ObjectTypeDB::bind_method(_MD("_input_event"),&Tree::_input_event);
ObjectTypeDB::bind_method(_MD("_popup_select"),&Tree::popup_select);
ObjectTypeDB::bind_method(_MD("_text_editor_enter"),&Tree::text_editor_enter);
@@ -3072,11 +3192,11 @@ void Tree::_bind_methods() {
ObjectTypeDB::bind_method(_MD("create_item:TreeItem","parent:TreeItem"),&Tree::_create_item,DEFVAL((Object*)NULL));
ObjectTypeDB::bind_method(_MD("get_root:TreeItem"),&Tree::get_root);
- ObjectTypeDB::bind_method(_MD("set_column_min_width"),&Tree::set_column_min_width);
- ObjectTypeDB::bind_method(_MD("set_column_expand"),&Tree::set_column_expand);
- ObjectTypeDB::bind_method(_MD("get_column_width"),&Tree::get_column_width);
+ ObjectTypeDB::bind_method(_MD("set_column_min_width","column","min_width"),&Tree::set_column_min_width);
+ ObjectTypeDB::bind_method(_MD("set_column_expand","column","expand"),&Tree::set_column_expand);
+ ObjectTypeDB::bind_method(_MD("get_column_width","column"),&Tree::get_column_width);
- ObjectTypeDB::bind_method(_MD("set_hide_root"),&Tree::set_hide_root);
+ ObjectTypeDB::bind_method(_MD("set_hide_root","enable"),&Tree::set_hide_root);
ObjectTypeDB::bind_method(_MD("get_next_selected:TreeItem","from:TreeItem"),&Tree::_get_next_selected);
ObjectTypeDB::bind_method(_MD("get_selected:TreeItem"),&Tree::get_selected);
ObjectTypeDB::bind_method(_MD("get_selected_column"),&Tree::get_selected_column);
@@ -3085,7 +3205,7 @@ void Tree::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_columns","amount"),&Tree::set_columns);
ObjectTypeDB::bind_method(_MD("get_columns"),&Tree::get_columns);
-
+
ObjectTypeDB::bind_method(_MD("get_edited:TreeItem"),&Tree::get_edited);
ObjectTypeDB::bind_method(_MD("get_edited_column"),&Tree::get_edited_column);
ObjectTypeDB::bind_method(_MD("get_custom_popup_rect"),&Tree::get_custom_popup_rect);
@@ -3100,6 +3220,9 @@ void Tree::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_column_title","column"),&Tree::get_column_title);
ObjectTypeDB::bind_method(_MD("get_scroll"),&Tree::get_scroll);
+ ObjectTypeDB::bind_method(_MD("set_hide_folding","hide"),&Tree::set_hide_folding);
+ ObjectTypeDB::bind_method(_MD("is_folding_hidden"),&Tree::is_folding_hidden);
+
ADD_SIGNAL( MethodInfo("item_selected"));
ADD_SIGNAL( MethodInfo("cell_selected"));
@@ -3124,7 +3247,7 @@ Tree::Tree() {
edited_item=NULL;
selected_col=-1;
edited_col=-1;
-
+
hide_root=false;
select_mode=SELECT_SINGLE;
root=0;
@@ -3132,8 +3255,8 @@ Tree::Tree() {
popup_edited_item=NULL;
text_editor=NULL;
set_focus_mode(FOCUS_ALL);
-
-
+
+
popup_menu = memnew( PopupMenu );
popup_menu->hide();
add_child(popup_menu);
@@ -3149,10 +3272,14 @@ Tree::Tree() {
h_scroll = memnew( HScrollBar );
v_scroll = memnew( VScrollBar );
-
+
add_child(h_scroll);
add_child(v_scroll);
+ range_click_timer = memnew( Timer );
+ range_click_timer->connect("timeout",this,"_range_click_timeout");
+ add_child(range_click_timer);
+
h_scroll->connect("value_changed", this,"_scroll_moved");
v_scroll->connect("value_changed", this,"_scroll_moved");
text_editor->connect("text_entered", this,"_text_editor_enter");
@@ -3184,6 +3311,10 @@ Tree::Tree() {
drag_speed=0;
drag_touching=false;
drag_touching_deaccel=false;
+ pressing_for_editor=false;
+ range_drag_enabled=false;
+
+ hide_folding=false;
}
@@ -3193,6 +3324,6 @@ Tree::~Tree() {
if (root) {
memdelete( root );
}
-
+
}
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index 8ddddd0630..54e6a9c6b9 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -127,7 +127,7 @@ friend class Tree;
- TreeItem(Tree *p_tree);
+ TreeItem(Tree *p_tree);
void _changed_notify(int p_cell);
@@ -228,6 +228,7 @@ public:
void set_tooltip(int p_column, const String& p_tooltip);
String get_tooltip(int p_column) const;
+
void clear_children();
void move_to_top();
@@ -258,7 +259,18 @@ friend class TreeItem;
TreeItem *popup_edited_item;
TreeItem *selected_item;
TreeItem *edited_item;
+
+
int pressed_button;
+ bool pressing_for_editor;
+ String pressing_for_editor_text;
+ Vector2 pressing_pos;
+ Rect2 pressing_item_rect;
+
+ float range_drag_base;
+ bool range_drag_enabled;
+ Vector2 range_drag_capture_pos;
+
//TreeItem *cursor_item;
//int cursor_column;
@@ -289,6 +301,11 @@ friend class TreeItem;
Vector<ColumnInfo> columns;
+ Timer *range_click_timer;
+ TreeItem *range_item_last;
+ bool range_up_last;
+ void _range_click_timeout();
+
int compute_item_height(TreeItem *p_item) const;
int get_item_height(TreeItem *p_item) const;
// void draw_item_text(String p_text,const Ref<Texture>& p_icon,int p_icon_max_w,bool p_tool,Rect2i p_rect,const Color& p_color);
@@ -399,6 +416,8 @@ friend class TreeItem;
bool drag_touching_deaccel;
bool click_handled;
+ bool hide_folding;
+
protected:
static void _bind_methods();
@@ -456,6 +475,11 @@ public:
VScrollBar *get_vscroll_bar() { return v_scroll; }
+ void set_hide_folding(bool p_hide);
+ bool is_folding_hidden() const;
+
+
+
Tree();
~Tree();
diff --git a/scene/gui/video_player.cpp b/scene/gui/video_player.cpp
index c0b971cb33..517cd414c5 100644
--- a/scene/gui/video_player.cpp
+++ b/scene/gui/video_player.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,88 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "video_player.h"
+#include "os/os.h"
+
+
+int VideoPlayer::InternalStream::get_channel_count() const {
+
+ return player->sp_get_channel_count();
+}
+void VideoPlayer::InternalStream::set_mix_rate(int p_rate){
+
+ return player->sp_set_mix_rate(p_rate);
+}
+bool VideoPlayer::InternalStream::mix(int32_t *p_buffer,int p_frames){
+
+ return player->sp_mix(p_buffer,p_frames);
+}
+void VideoPlayer::InternalStream::update(){
+
+ player->sp_update();
+}
+
+
+int VideoPlayer::sp_get_channel_count() const {
+
+ return playback->get_channels();
+}
+
+void VideoPlayer::sp_set_mix_rate(int p_rate){
+
+ server_mix_rate=p_rate;
+}
+
+bool VideoPlayer::sp_mix(int32_t *p_buffer,int p_frames) {
+
+ if (resampler.is_ready()) {
+ return resampler.mix(p_buffer,p_frames);
+ }
+
+ return false;
+}
+
+void VideoPlayer::sp_update() {
+#if 0
+ _THREAD_SAFE_METHOD_
+ //update is unused
+ if (!paused && playback.is_valid()) {
+
+ if (!playback->is_playing()) {
+ //stream depleted data, but there's still audio in the ringbuffer
+ //check that all this audio has been flushed before stopping the stream
+ int to_mix = resampler.get_total() - resampler.get_todo();
+ if (to_mix==0) {
+ stop();
+ return;
+ }
+
+ return;
+ }
+
+ int todo =resampler.get_todo();
+ int wrote = playback->mix(resampler.get_write_buffer(),todo);
+ resampler.write(wrote);
+ }
+#endif
+}
+
+int VideoPlayer::_audio_mix_callback(void* p_udata,const int16_t *p_data,int p_frames) {
+
+ VideoPlayer *vp=(VideoPlayer*)p_udata;
+
+ int todo=MIN(vp->resampler.get_todo(),p_frames);
+
+ int16_t *wb = vp->resampler.get_write_buffer();
+ int c = vp->resampler.get_channel_count();
+
+ for(int i=0;i<todo*c;i++) {
+ wb[i]=p_data[i];
+ }
+ vp->resampler.write(todo);
+ return todo;
+}
+
+
void VideoPlayer::_notification(int p_notification) {
@@ -35,8 +117,9 @@ void VideoPlayer::_notification(int p_notification) {
case NOTIFICATION_ENTER_TREE: {
//set_idle_process(false); //don't annoy
- if (stream.is_valid() && autoplay && !get_tree()->is_editor_hint())
+ if (stream.is_valid() && autoplay && !get_tree()->is_editor_hint()) {
play();
+ }
} break;
case NOTIFICATION_PROCESS: {
@@ -45,16 +128,25 @@ void VideoPlayer::_notification(int p_notification) {
return;
if (paused)
return;
- if (!stream->is_playing())
+ if (!playback->is_playing())
+ return;
+
+ double audio_time = OS::get_singleton()->get_ticks_usec()/1000000.0; //AudioServer::get_singleton()->get_mix_time();
+
+ double delta = last_audio_time==0?0:audio_time-last_audio_time;
+ last_audio_time=audio_time;
+ if (delta==0)
return;
- stream->update(get_tree()->get_idle_process_time());
- int prev_width = texture->get_width();
+
+ playback->update(delta);
+
+ /*int prev_width = texture->get_width();
stream->pop_frame(texture);
if (prev_width == 0) {
update();
minimum_size_changed();
- };
+ };*/
} break;
@@ -75,6 +167,9 @@ void VideoPlayer::_notification(int p_notification) {
};
+
+
+
Size2 VideoPlayer::get_minimum_size() const {
if (!expand && !texture.is_null())
@@ -100,15 +195,33 @@ void VideoPlayer::set_stream(const Ref<VideoStream> &p_stream) {
stop();
- texture = Ref<ImageTexture>(memnew(ImageTexture));
-
stream=p_stream;
- if (!stream.is_null()) {
-
- stream->set_loop(loops);
- stream->set_paused(paused);
+ if (stream.is_valid()) {
+ stream->set_audio_track(audio_track);
+ playback=stream->instance_playback();
+ } else {
+ playback=Ref<VideoStreamPlayback>();
+ }
+
+ if (!playback.is_null()) {
+ playback->set_loop(loops);
+ playback->set_paused(paused);
+ texture=playback->get_texture();
+
+ AudioServer::get_singleton()->lock();
+ resampler.setup(playback->get_channels(),playback->get_mix_rate(),server_mix_rate,buffering_ms,0);
+ AudioServer::get_singleton()->unlock();
+ playback->set_mix_callback(_audio_mix_callback,this);
+
+ } else {
+ texture.unref();
+ AudioServer::get_singleton()->lock();
+ resampler.clear();
+ AudioServer::get_singleton()->unlock();
}
+ update();
+
};
Ref<VideoStream> VideoPlayer::get_stream() const {
@@ -119,44 +232,72 @@ Ref<VideoStream> VideoPlayer::get_stream() const {
void VideoPlayer::play() {
ERR_FAIL_COND(!is_inside_tree());
- if (stream.is_null())
+ if (playback.is_null())
return;
- stream->play();
+ playback->stop();
+ playback->play();
set_process(true);
+ AudioServer::get_singleton()->stream_set_active(stream_rid,true);
+ AudioServer::get_singleton()->stream_set_volume_scale(stream_rid,volume);
+ last_audio_time=0;
};
void VideoPlayer::stop() {
if (!is_inside_tree())
return;
- if (stream.is_null())
+ if (playback.is_null())
return;
- stream->stop();
+ playback->stop();
+ AudioServer::get_singleton()->stream_set_active(stream_rid,false);
+ resampler.clear();
set_process(false);
+ last_audio_time=0;
};
bool VideoPlayer::is_playing() const {
- if (stream.is_null())
+ if (playback.is_null())
return false;
- return stream->is_playing();
+ return playback->is_playing();
};
void VideoPlayer::set_paused(bool p_paused) {
paused=p_paused;
- if (stream.is_valid()) {
- stream->set_paused(p_paused);
+ if (playback.is_valid()) {
+ playback->set_paused(p_paused);
set_process(!p_paused);
};
+ last_audio_time = 0;
};
bool VideoPlayer::is_paused() const {
return paused;
-};
+}
+
+void VideoPlayer::set_buffering_msec(int p_msec) {
+
+ buffering_ms=p_msec;
+}
+
+int VideoPlayer::get_buffering_msec() const{
+
+ return buffering_ms;
+}
+
+void VideoPlayer::set_audio_track(int p_track) {
+ audio_track=p_track;
+}
+
+int VideoPlayer::get_audio_track() const {
+
+ return audio_track;
+}
+
void VideoPlayer::set_volume(float p_vol) {
@@ -194,11 +335,18 @@ String VideoPlayer::get_stream_name() const {
float VideoPlayer::get_stream_pos() const {
- if (stream.is_null())
+ if (playback.is_null())
return 0;
- return stream->get_pos();
+ return playback->get_pos();
};
+Ref<Texture> VideoPlayer::get_video_texture() {
+
+ if (playback.is_valid())
+ return playback->get_texture();
+
+ return Ref<Texture> ();
+}
void VideoPlayer::set_autoplay(bool p_enable) {
@@ -229,6 +377,9 @@ void VideoPlayer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_volume_db","db"),&VideoPlayer::set_volume_db);
ObjectTypeDB::bind_method(_MD("get_volume_db"),&VideoPlayer::get_volume_db);
+ ObjectTypeDB::bind_method(_MD("set_audio_track","track"),&VideoPlayer::set_audio_track);
+ ObjectTypeDB::bind_method(_MD("get_audio_track"),&VideoPlayer::get_audio_track);
+
ObjectTypeDB::bind_method(_MD("get_stream_name"),&VideoPlayer::get_stream_name);
ObjectTypeDB::bind_method(_MD("get_stream_pos"),&VideoPlayer::get_stream_pos);
@@ -239,7 +390,12 @@ void VideoPlayer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_expand","enable"), &VideoPlayer::set_expand );
ObjectTypeDB::bind_method(_MD("has_expand"), &VideoPlayer::has_expand );
+ ObjectTypeDB::bind_method(_MD("set_buffering_msec","msec"),&VideoPlayer::set_buffering_msec);
+ ObjectTypeDB::bind_method(_MD("get_buffering_msec"),&VideoPlayer::get_buffering_msec);
+
+ ObjectTypeDB::bind_method(_MD("get_video_texutre:Texture"), &VideoPlayer::get_video_texture );
+ ADD_PROPERTY( PropertyInfo(Variant::INT, "stream/audio_track",PROPERTY_HINT_RANGE,"0,128,1"), _SCS("set_audio_track"), _SCS("get_audio_track") );
ADD_PROPERTY( PropertyInfo(Variant::OBJECT, "stream/stream", PROPERTY_HINT_RESOURCE_TYPE,"VideoStream"), _SCS("set_stream"), _SCS("get_stream") );
// ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/loop"), _SCS("set_loop"), _SCS("has_loop") );
ADD_PROPERTY( PropertyInfo(Variant::REAL, "stream/volume_db", PROPERTY_HINT_RANGE,"-80,24,0.01"), _SCS("set_volume_db"), _SCS("get_volume_db") );
@@ -257,6 +413,16 @@ VideoPlayer::VideoPlayer() {
autoplay = false;
expand = true;
loops = false;
+
+ audio_track=0;
+
+ buffering_ms=500;
+ server_mix_rate=44100;
+
+ internal_stream.player=this;
+ stream_rid=AudioServer::get_singleton()->audio_stream_create(&internal_stream);
+ last_audio_time=0;
+
};
VideoPlayer::~VideoPlayer() {
diff --git a/scene/gui/video_player.h b/scene/gui/video_player.h
index 2b850ca509..9ce1ba78f4 100644
--- a/scene/gui/video_player.h
+++ b/scene/gui/video_player.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,22 +31,50 @@
#include "scene/resources/video_stream.h"
#include "scene/gui/control.h"
+#include "servers/audio/audio_rb_resampler.h"
class VideoPlayer : public Control {
OBJ_TYPE(VideoPlayer,Control);
+ struct InternalStream : public AudioServer::AudioStream {
+ VideoPlayer *player;
+ virtual int get_channel_count() const;
+ virtual void set_mix_rate(int p_rate); //notify the stream of the mix rate
+ virtual bool mix(int32_t *p_buffer,int p_frames);
+ virtual void update();
+ };
+
+
+ InternalStream internal_stream;
+ Ref<VideoStreamPlayback> playback;
Ref<VideoStream> stream;
+
+ int sp_get_channel_count() const;
+ void sp_set_mix_rate(int p_rate); //notify the stream of the mix rate
+ bool sp_mix(int32_t *p_buffer,int p_frames);
+ void sp_update();
+
+
RID stream_rid;
Ref<ImageTexture> texture;
Image last_frame;
+ AudioRBResampler resampler;
+
bool paused;
bool autoplay;
float volume;
+ double last_audio_time;
bool expand;
bool loops;
+ int buffering_ms;
+ int server_mix_rate;
+ int audio_track;
+
+ static int _audio_mix_callback(void* p_udata,const int16_t *p_data,int p_frames);
+
protected:
@@ -60,6 +88,8 @@ public:
bool has_expand() const;
+ Ref<Texture> get_video_texture();
+
void set_stream(const Ref<VideoStream> &p_stream);
Ref<VideoStream> get_stream() const;
@@ -82,6 +112,12 @@ public:
void set_autoplay(bool p_vol);
bool has_autoplay() const;
+ void set_audio_track(int p_track);
+ int get_audio_track() const;
+
+ void set_buffering_msec(int p_msec);
+ int get_buffering_msec() const;
+
VideoPlayer();
~VideoPlayer();
};
diff --git a/scene/io/SCsub b/scene/io/SCsub
index 055d2f2474..bbe59b3054 100644
--- a/scene/io/SCsub
+++ b/scene/io/SCsub
@@ -3,5 +3,3 @@ Import('env')
env.add_source_files(env.scene_sources,"*.cpp")
Export('env')
-
-
diff --git a/scene/io/resource_format_image.cpp b/scene/io/resource_format_image.cpp
index 2663ac0762..c80975dbfe 100644
--- a/scene/io/resource_format_image.cpp
+++ b/scene/io/resource_format_image.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,9 +31,11 @@
#include "io/image_loader.h"
#include "globals.h"
#include "os/os.h"
-RES ResourceFormatLoaderImage::load(const String &p_path,const String& p_original_path) {
-
+RES ResourceFormatLoaderImage::load(const String &p_path, const String& p_original_path, Error *r_error) {
+ if (r_error)
+ *r_error=ERR_CANT_OPEN;
+
if (p_path.extension()=="cube") {
// open as cubemap txture
@@ -83,6 +85,8 @@ RES ResourceFormatLoaderImage::load(const String &p_path,const String& p_origina
memdelete(f);
cubemap->set_name(p_path.get_file());
+ if (r_error)
+ *r_error=OK;
return cubemap;
@@ -112,6 +116,8 @@ RES ResourceFormatLoaderImage::load(const String &p_path,const String& p_origina
ERR_EXPLAIN("Failed loading image: "+p_path);
ERR_FAIL_COND_V(err, RES());
+ if (r_error)
+ *r_error=ERR_FILE_CORRUPT;
#ifdef DEBUG_ENABLED
#ifdef TOOLS_ENABLED
@@ -180,6 +186,11 @@ RES ResourceFormatLoaderImage::load(const String &p_path,const String& p_origina
if (flags_found["tolinear"])
flags|=Texture::FLAG_CONVERT_TO_LINEAR;
}
+
+ if (flags_found.has("mirroredrepeat")) {
+ if (flags_found["mirroredrepeat"])
+ flags|=Texture::FLAG_MIRRORED_REPEAT;
+ }
if (debug_load_times)
begtime=OS::get_singleton()->get_ticks_usec();
@@ -194,6 +205,9 @@ RES ResourceFormatLoaderImage::load(const String &p_path,const String& p_origina
print_line(" -make texture: "+rtos(total));
}
+ if (r_error)
+ *r_error=OK;
+
return RES( texture );
}
diff --git a/scene/io/resource_format_image.h b/scene/io/resource_format_image.h
index 1af65870f8..6388aa641f 100644
--- a/scene/io/resource_format_image.h
+++ b/scene/io/resource_format_image.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -40,7 +40,7 @@ class ResourceFormatLoaderImage : public ResourceFormatLoader {
int max_texture_size;
public:
- virtual RES load(const String &p_path,const String& p_original_path="");
+ virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String& p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/scene/io/resource_format_wav.cpp b/scene/io/resource_format_wav.cpp
index 7c90a4b3cd..9cf349eb7b 100644
--- a/scene/io/resource_format_wav.cpp
+++ b/scene/io/resource_format_wav.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,13 +31,18 @@
#include "scene/resources/sample.h"
-RES ResourceFormatLoaderWAV::load(const String &p_path,const String& p_original_path) {
+RES ResourceFormatLoaderWAV::load(const String &p_path, const String& p_original_path, Error *r_error) {
+ if (r_error)
+ *r_error=ERR_FILE_CANT_OPEN;
Error err;
FileAccess *file=FileAccess::open(p_path, FileAccess::READ,&err);
ERR_FAIL_COND_V( err!=OK, RES() );
+ if (r_error)
+ *r_error=ERR_FILE_CORRUPT;
+
/* CHECK RIFF */
char riff[5];
riff[4]=0;
@@ -244,6 +249,10 @@ RES ResourceFormatLoaderWAV::load(const String &p_path,const String& p_original_
file->close();
memdelete(file);
+ if (r_error)
+ *r_error=OK;
+
+
return sample;
}
diff --git a/scene/io/resource_format_wav.h b/scene/io/resource_format_wav.h
index 081a563d03..4918d5c2e7 100644
--- a/scene/io/resource_format_wav.h
+++ b/scene/io/resource_format_wav.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,7 +33,7 @@
class ResourceFormatLoaderWAV : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path,const String& p_original_path="");
+ virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String& p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/scene/main/SCsub b/scene/main/SCsub
index 055d2f2474..bbe59b3054 100644
--- a/scene/main/SCsub
+++ b/scene/main/SCsub
@@ -3,5 +3,3 @@ Import('env')
env.add_source_files(env.scene_sources,"*.cpp")
Export('env')
-
-
diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp
index ee3d7f5afd..e921795628 100644
--- a/scene/main/canvas_layer.cpp
+++ b/scene/main/canvas_layer.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/main/canvas_layer.h b/scene/main/canvas_layer.h
index edd00c1a7a..809b3fae7f 100644
--- a/scene/main/canvas_layer.h
+++ b/scene/main/canvas_layer.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/main/instance_placeholder.cpp b/scene/main/instance_placeholder.cpp
new file mode 100644
index 0000000000..12f6086bf0
--- /dev/null
+++ b/scene/main/instance_placeholder.cpp
@@ -0,0 +1,75 @@
+#include "instance_placeholder.h"
+
+#include "scene/resources/packed_scene.h"
+#include "io/resource_loader.h"
+
+bool InstancePlaceholder::_set(const StringName& p_name, const Variant& p_value) {
+
+ PropSet ps;
+ ps.name=p_name;
+ ps.value=p_value;
+ stored_values.push_back(ps);
+ return true;
+}
+
+bool InstancePlaceholder::_get(const StringName& p_name,Variant &r_ret) const{
+
+ return false;
+}
+void InstancePlaceholder::_get_property_list( List<PropertyInfo> *p_list) const{
+
+
+}
+
+
+void InstancePlaceholder::set_instance_path(const String& p_name) {
+
+ path=p_name;
+}
+
+String InstancePlaceholder::get_instance_path() const {
+
+ return path;
+}
+void InstancePlaceholder::replace_by_instance(const Ref<PackedScene> &p_custom_scene){
+
+ ERR_FAIL_COND(!is_inside_tree());
+
+ Node *base = get_parent();
+ if (!base)
+ return;
+
+ Ref<PackedScene> ps;
+ if (p_custom_scene.is_valid())
+ ps = p_custom_scene;
+ else
+ ps = ResourceLoader::load(path,"PackedScene");
+
+ if (!ps.is_valid())
+ return;
+ Node *scene = ps->instance();
+ scene->set_name(get_name());
+ int pos = get_position_in_parent();
+
+ for(List<PropSet>::Element *E=stored_values.front();E;E=E->next()) {
+ scene->set(E->get().name,E->get().value);
+ }
+
+ queue_delete();
+
+ base->remove_child(this);
+ base->add_child(scene);
+ base->move_child(scene,pos);
+
+}
+
+void InstancePlaceholder::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("replace_by_instance","custom_scene:PackedScene"),&InstancePlaceholder::replace_by_instance,DEFVAL(Variant()));
+ ObjectTypeDB::bind_method(_MD("get_instance_path"),&InstancePlaceholder::get_instance_path);
+}
+
+InstancePlaceholder::InstancePlaceholder() {
+
+
+}
diff --git a/scene/main/instance_placeholder.h b/scene/main/instance_placeholder.h
new file mode 100644
index 0000000000..9c47655ce7
--- /dev/null
+++ b/scene/main/instance_placeholder.h
@@ -0,0 +1,37 @@
+#ifndef INSTANCE_PLACEHOLDER_H
+#define INSTANCE_PLACEHOLDER_H
+
+#include "scene/main/node.h"
+
+class PackedScene;
+
+class InstancePlaceholder : public Node {
+
+ OBJ_TYPE(InstancePlaceholder,Node);
+
+ String path;
+ struct PropSet {
+ StringName name;
+ Variant value;
+ };
+
+ List<PropSet> stored_values;
+
+protected:
+ bool _set(const StringName& p_name, const Variant& p_value);
+ bool _get(const StringName& p_name,Variant &r_ret) const;
+ void _get_property_list( List<PropertyInfo> *p_list) const;
+
+ static void _bind_methods();
+
+public:
+
+ void set_instance_path(const String& p_name);
+ String get_instance_path() const;
+
+ void replace_by_instance(const Ref<PackedScene>& p_custom_scene=Ref<PackedScene>());
+
+ InstancePlaceholder();
+};
+
+#endif // INSTANCE_PLACEHOLDER_H
diff --git a/scene/main/misc.cpp b/scene/main/misc.cpp
index 108621baa5..35d8b4cdfb 100644
--- a/scene/main/misc.cpp
+++ b/scene/main/misc.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/main/misc.h b/scene/main/misc.h
index e7894aa68d..1c5bc7208e 100644
--- a/scene/main/misc.h
+++ b/scene/main/misc.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index b7fa5c8301..0780a4bdaf 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -196,6 +196,14 @@ void Node::_propagate_enter_tree() {
}
data.blocked--;
+
+#ifdef DEBUG_ENABLED
+
+ if (ScriptDebugger::get_singleton() && data.filename!=String()) {
+ //used for live edit
+ data.tree->live_scene_edit_cache[data.filename].insert(this);
+ }
+#endif
// enter groups
}
@@ -205,6 +213,28 @@ void Node::_propagate_exit_tree() {
//block while removing children
+#ifdef DEBUG_ENABLED
+
+ if (ScriptDebugger::get_singleton() && data.filename!=String()) {
+ //used for live edit
+ Map<String,Set<Node*> >::Element *E=data.tree->live_scene_edit_cache.find(data.filename);
+ if (E) {
+ E->get().erase(this);
+ if (E->get().size()==0) {
+ data.tree->live_scene_edit_cache.erase(E);
+ }
+ }
+
+ Map<Node*,Map<ObjectID,Node*> >::Element *F=data.tree->live_edit_remove_list.find(this);
+ if (F) {
+ for (Map<ObjectID,Node*>::Element*G=F->get().front();G;G=G->next()) {
+
+ memdelete(G->get());
+ }
+ data.tree->live_edit_remove_list.erase(F);
+ }
+ }
+#endif
data.blocked++;
for (int i=data.children.size()-1;i>=0;i--) {
@@ -552,11 +582,57 @@ void Node::set_human_readable_collision_renaming(bool p_enabled) {
}
-void Node::_validate_child_name(Node *p_child) {
+
+String Node::validate_child_name(const String& p_name) const {
+
+ //this approach to autoset node names is human readable but very slow
+ //it's turned on while running in the editor
+
+ String basename = p_name;
+
+ if (basename==String()) {
+
+ return String();
+ }
+
+ int val=1;
+
+ for(;;) {
+
+ String attempted = val > 1 ? (basename + " " +itos(val) ) : basename;
+
+ bool found=false;
+
+ for (int i=0;i<data.children.size();i++) {
+
+ //if (data.children[i]==p_child)
+ // continue;
+ if (data.children[i]->get_name() == attempted) {
+ found=true;
+ break;
+ }
+
+ }
+
+ if (found) {
+
+ val++;
+ continue;
+ }
+
+ return attempted;
+ break;
+ }
+
+ return basename;
+
+}
+
+void Node::_validate_child_name(Node *p_child, bool p_force_human_readable) {
/* Make sure the name is unique */
- if (node_hrcr) {
+ if (node_hrcr || p_force_human_readable) {
//this approach to autoset node names is human readable but very slow
//it's turned on while running in the editor
@@ -624,11 +700,7 @@ void Node::_validate_child_name(Node *p_child) {
if (!unique) {
node_hrcr_count.ref();
-#ifdef DEBUG_ENABLED
- String name = "@"+String(p_child->get_type_name())+itos(node_hrcr_count.get());
-#else
- String name = "@"+itos(node_hrcr_count.get());
-#endif
+ String name = "@"+String(p_child->get_name())+"@"+itos(node_hrcr_count.get());
p_child->data.name=name;
}
}
@@ -656,24 +728,27 @@ void Node::_add_child_nocheck(Node* p_child,const StringName& p_name) {
}
-void Node::add_child(Node *p_child) {
+void Node::add_child(Node *p_child, bool p_legible_unique_name) {
ERR_FAIL_NULL(p_child);
/* Fail if node has a parent */
- ERR_EXPLAIN("Can't add child "+p_child->get_name()+" to itself.")
- ERR_FAIL_COND( p_child==this ); // adding to itself!
+ if (p_child==this) {
+ ERR_EXPLAIN("Can't add child "+p_child->get_name()+" to itself.")
+ ERR_FAIL_COND( p_child==this ); // adding to itself!
+ }
ERR_EXPLAIN("Can't add child, already has a parent");
ERR_FAIL_COND( p_child->data.parent );
ERR_EXPLAIN("Can't add child while a notification is happening");
ERR_FAIL_COND( data.blocked > 0 );
/* Validate name */
- _validate_child_name(p_child);
+ _validate_child_name(p_child,p_legible_unique_name);
_add_child_nocheck(p_child,p_child->data.name);
}
+
void Node::_propagate_validate_owner() {
if (data.owner) {
@@ -727,6 +802,7 @@ void Node::remove_child(Node *p_child) {
}
ERR_FAIL_COND( idx==-1 );
+ //ERR_FAIL_COND( p_child->data.blocked > 0 );
//if (data.scene) { does not matter
@@ -765,9 +841,26 @@ Node *Node::get_child(int p_index) const {
return data.children[p_index];
}
+
+Node *Node::_get_child_by_name(const StringName& p_name) const {
+
+ int cc=data.children.size();
+ Node* const* cd=data.children.ptr();
+
+ for(int i=0;i<cc;i++){
+ if (cd[i]->data.name==p_name)
+ return cd[i];
+ }
+
+ return NULL;
+}
+
Node *Node::_get_node(const NodePath& p_path) const {
- ERR_FAIL_COND_V( !data.inside_tree && p_path.is_absolute(), NULL );
+ if (!data.inside_tree && p_path.is_absolute()) {
+ ERR_EXPLAIN("Can't use get_node() with absolute paths from outside the active scene tree.");
+ ERR_FAIL_V(NULL);
+ }
Node *current=NULL;
Node *root=NULL;
@@ -830,8 +923,10 @@ Node *Node::_get_node(const NodePath& p_path) const {
Node *Node::get_node(const NodePath& p_path) const {
Node *node = _get_node(p_path);
- ERR_EXPLAIN("Node not found: "+p_path);
- ERR_FAIL_COND_V(!node,NULL);
+ if (!node) {
+ ERR_EXPLAIN("Node not found: "+p_path);
+ ERR_FAIL_COND_V(!node,NULL);
+ }
return node;
}
@@ -960,6 +1055,7 @@ void Node::get_owned_by(Node *p_by,List<Node*> *p_owned) {
void Node::_set_owner_nocheck(Node* p_owner) {
+ ERR_FAIL_COND(data.owner);
data.owner=p_owner;
data.owner->data.owned.push_back( this );
data.OW = data.owner->data.owned.back();
@@ -1256,8 +1352,30 @@ String Node::get_filename() const {
return data.filename;
}
+void Node::set_editable_instance(Node* p_node,bool p_editable) {
+
+ ERR_FAIL_NULL(p_node);
+ ERR_FAIL_COND(!is_a_parent_of(p_node));
+ NodePath p = get_path_to(p_node);
+ if (!p_editable)
+ data.editable_instances.erase(p);
+ else
+ data.editable_instances[p]=true;
+
+}
+
+bool Node::is_editable_instance(Node *p_node) const {
+
+ if (!p_node)
+ return false; //easier, null is never editable :)
+ ERR_FAIL_COND_V(!is_a_parent_of(p_node),false);
+ NodePath p = get_path_to(p_node);
+ return data.editable_instances.has(p);
+}
+#if 0
+
void Node::generate_instance_state() {
List<PropertyInfo> properties;
@@ -1307,13 +1425,36 @@ Dictionary Node::get_instance_state() const {
return data.instance_state;
}
-Vector<StringName> Node::get_instance_groups() const {
+#endif
+
+void Node::set_scene_instance_state(const Ref<SceneState>& p_state) {
- return data.instance_groups;
+ data.instance_state=p_state;
}
-Vector<Node::Connection> Node::get_instance_connections() const{
- return data.instance_connections;
+Ref<SceneState> Node::get_scene_instance_state() const{
+
+ return data.instance_state;
+}
+
+void Node::set_scene_inherited_state(const Ref<SceneState>& p_state) {
+
+ data.inherited_state=p_state;
+}
+
+Ref<SceneState> Node::get_scene_inherited_state() const{
+
+ return data.inherited_state;
+}
+
+void Node::set_scene_instance_load_placeholder(bool p_enable) {
+
+ data.use_placeholder=p_enable;
+}
+
+bool Node::get_scene_instance_load_placeholder() const{
+
+ return data.use_placeholder;
}
int Node::get_position_in_parent() const {
@@ -1323,18 +1464,31 @@ int Node::get_position_in_parent() const {
-Node *Node::duplicate() const {
+Node *Node::duplicate(bool p_use_instancing) const {
Node *node=NULL;
- Object *obj = ObjectTypeDB::instance(get_type());
- ERR_FAIL_COND_V(!obj,NULL);
- node = obj->cast_to<Node>();
- if (!node)
- memdelete(obj);
- ERR_FAIL_COND_V(!node,NULL);
+ bool instanced=false;
+
+ if (p_use_instancing && get_filename()!=String()) {
+
+ Ref<PackedScene> res = ResourceLoader::load(get_filename());
+ ERR_FAIL_COND_V(res.is_null(),NULL);
+ node=res->instance();
+ ERR_FAIL_COND_V(!node,NULL);
+ instanced=true;
+
+ } else {
+
+ Object *obj = ObjectTypeDB::instance(get_type());
+ ERR_FAIL_COND_V(!obj,NULL);
+ node = obj->cast_to<Node>();
+ if (!node)
+ memdelete(obj);
+ ERR_FAIL_COND_V(!node,NULL);
+ }
if (get_filename()!="") { //an instance
@@ -1360,7 +1514,10 @@ Node *Node::duplicate() const {
if (get_child(i)->data.parent_owned)
continue;
- Node *dup = get_child(i)->duplicate();
+ if (instanced && get_child(i)->data.owner==this)
+ continue; //part of instance
+
+ Node *dup = get_child(i)->duplicate(p_use_instancing);
if (!dup) {
memdelete(node);
@@ -1830,7 +1987,7 @@ void Node::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_name","name"),&Node::set_name);
ObjectTypeDB::bind_method(_MD("get_name"),&Node::get_name);
- ObjectTypeDB::bind_method(_MD("add_child","node:Node"),&Node::add_child);
+ ObjectTypeDB::bind_method(_MD("add_child","node:Node","legible_unique_name"),&Node::add_child,DEFVAL(false));
ObjectTypeDB::bind_method(_MD("remove_child","node:Node"),&Node::remove_child);
//ObjectTypeDB::bind_method(_MD("remove_and_delete_child","node:Node"),&Node::remove_and_delete_child);
ObjectTypeDB::bind_method(_MD("get_child_count"),&Node::get_child_count);
@@ -1839,7 +1996,7 @@ void Node::_bind_methods() {
ObjectTypeDB::bind_method(_MD("has_node","path"),&Node::has_node);
ObjectTypeDB::bind_method(_MD("get_node:Node","path"),&Node::get_node);
ObjectTypeDB::bind_method(_MD("get_parent:Parent"),&Node::get_parent);
- ObjectTypeDB::bind_method(_MD("find_node:Node","mask","recursive","owned"),&Node::get_node,DEFVAL(true),DEFVAL(true));
+ ObjectTypeDB::bind_method(_MD("find_node:Node","mask","recursive","owned"),&Node::find_node,DEFVAL(true),DEFVAL(true));
ObjectTypeDB::bind_method(_MD("has_node_and_resource","path"),&Node::has_node_and_resource);
ObjectTypeDB::bind_method(_MD("get_node_and_resource","path"),&Node::_get_node_and_resource);
@@ -1848,7 +2005,7 @@ void Node::_bind_methods() {
ObjectTypeDB::bind_method(_MD("is_greater_than","node:Node"),&Node::is_greater_than);
ObjectTypeDB::bind_method(_MD("get_path"),&Node::get_path);
ObjectTypeDB::bind_method(_MD("get_path_to","node:Node"),&Node::get_path_to);
- ObjectTypeDB::bind_method(_MD("add_to_group","group"),&Node::add_to_group,DEFVAL(false));
+ ObjectTypeDB::bind_method(_MD("add_to_group","group","persistent"),&Node::add_to_group,DEFVAL(false));
ObjectTypeDB::bind_method(_MD("remove_from_group","group"),&Node::remove_from_group);
ObjectTypeDB::bind_method(_MD("is_in_group","group"),&Node::is_in_group);
ObjectTypeDB::bind_method(_MD("move_child","child_node:Node","to_pos"),&Node::move_child);
@@ -1882,16 +2039,20 @@ void Node::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_tree:SceneTree"),&Node::get_tree);
- ObjectTypeDB::bind_method(_MD("duplicate:Node"),&Node::duplicate);
+ ObjectTypeDB::bind_method(_MD("duplicate:Node","use_instancing"),&Node::duplicate,DEFVAL(false));
ObjectTypeDB::bind_method(_MD("replace_by","node:Node","keep_data"),&Node::replace_by,DEFVAL(false));
+ ObjectTypeDB::bind_method(_MD("set_scene_instance_load_placeholder","load_placeholder"),&Node::set_scene_instance_load_placeholder);
+ ObjectTypeDB::bind_method(_MD("get_scene_instance_load_placeholder"),&Node::get_scene_instance_load_placeholder);
+
+
ObjectTypeDB::bind_method(_MD("get_viewport"),&Node::get_viewport);
ObjectTypeDB::bind_method(_MD("queue_free"),&Node::queue_delete);
#ifdef TOOLS_ENABLED
ObjectTypeDB::bind_method(_MD("_set_import_path","import_path"),&Node::set_import_path);
ObjectTypeDB::bind_method(_MD("_get_import_path"),&Node::get_import_path);
- ADD_PROPERTY( PropertyInfo(Variant::NODE_PATH,"_import_path",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_import_path"),_SCS("_get_import_path"));
+ ADD_PROPERTYNZ( PropertyInfo(Variant::NODE_PATH,"_import_path",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_import_path"),_SCS("_get_import_path"));
#endif
@@ -1906,6 +2067,8 @@ void Node::_bind_methods() {
BIND_CONSTANT( NOTIFICATION_UNPARENTED );
BIND_CONSTANT( NOTIFICATION_PAUSED );
BIND_CONSTANT( NOTIFICATION_UNPAUSED );
+ BIND_CONSTANT( NOTIFICATION_INSTANCED );
+
BIND_CONSTANT( PAUSE_MODE_INHERIT );
@@ -1957,6 +2120,7 @@ Node::Node() {
data.parent_owned=false;
data.in_constructor=true;
data.viewport=NULL;
+ data.use_placeholder=false;
}
Node::~Node() {
@@ -1973,3 +2137,4 @@ Node::~Node() {
}
+////////////////////////////////
diff --git a/scene/main/node.h b/scene/main/node.h
index be91c6e1bb..4d05dd381c 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -38,6 +38,7 @@
class Viewport;
+class SceneState;
class Node : public Object {
OBJ_TYPE( Node, Object );
@@ -69,9 +70,10 @@ private:
struct Data {
String filename;
- Dictionary instance_state;
- Vector<StringName> instance_groups;
- Vector<Connection> instance_connections;
+ Ref<SceneState> instance_state;
+ Ref<SceneState> inherited_state;
+
+ HashMap<NodePath,int> editable_instances;
Node *parent;
Node *owner;
@@ -96,6 +98,7 @@ private:
PauseMode pause_mode;
Node *pause_owner;
// variables used to properly sort the node when processing, ignored otherwise
+ //should move all the stuff below to bits
bool fixed_process;
bool idle_process;
@@ -105,6 +108,9 @@ private:
bool parent_owned;
bool in_constructor;
+ bool use_placeholder;
+
+
} data;
@@ -112,10 +118,11 @@ private:
virtual bool _use_builtin_script() const { return true; }
Node *_get_node(const NodePath& p_path) const;
+ Node *_get_child_by_name(const StringName& p_name) const;
- void _validate_child_name(Node *p_name);
+ void _validate_child_name(Node *p_name, bool p_force_human_readable=false);
void _propagate_reverse_notification(int p_notification);
void _propagate_deferred_notification(int p_notification, bool p_reverse);
@@ -151,7 +158,7 @@ protected:
static void _bind_methods();
-friend class PackedScene;
+friend class SceneState;
void _add_child_nocheck(Node* p_child,const StringName& p_name);
void _set_owner_nocheck(Node* p_owner);
@@ -180,7 +187,7 @@ public:
StringName get_name() const;
void set_name(const String& p_name);
- void add_child(Node *p_child);
+ void add_child(Node *p_child,bool p_legible_unique_name=false);
void remove_child(Node *p_child);
int get_child_count() const;
@@ -208,7 +215,7 @@ public:
struct GroupInfo {
- String name;
+ StringName name;
bool persistent;
};
@@ -229,7 +236,11 @@ public:
void set_filename(const String& p_filename);
String get_filename() const;
-
+
+ void set_editable_instance(Node* p_node,bool p_editable);
+ bool is_editable_instance(Node* p_node) const;
+
+
/* NOTIFICATIONS */
void propagate_notification(int p_notification);
@@ -255,15 +266,20 @@ public:
int get_position_in_parent() const;
- Node *duplicate() const;
+ Node *duplicate(bool p_use_instancing=false) const;
Node *duplicate_and_reown(const Map<Node*,Node*>& p_reown_map) const;
+
//Node *clone_tree() const;
// used by editors, to save what has changed only
- void generate_instance_state();
- Dictionary get_instance_state() const;
- Vector<StringName> get_instance_groups() const;
- Vector<Connection> get_instance_connections() const;
+ void set_scene_instance_state(const Ref<SceneState>& p_state);
+ Ref<SceneState> get_scene_instance_state() const;
+
+ void set_scene_inherited_state(const Ref<SceneState>& p_state);
+ Ref<SceneState> get_scene_inherited_state() const;
+
+ void set_scene_instance_load_placeholder(bool p_enable);
+ bool get_scene_instance_load_placeholder() const;
static Vector<Variant> make_binds(VARIANT_ARG_LIST);
@@ -275,6 +291,8 @@ public:
static void print_stray_nodes();
+ String validate_child_name(const String& p_name) const;
+
void queue_delete();
//shitty hacks for speed
@@ -304,6 +322,4 @@ public:
typedef Set<Node*,Node::Comparator> NodeSet;
-
-
#endif
diff --git a/scene/main/resource_preloader.cpp b/scene/main/resource_preloader.cpp
index f49f626e78..219eea770a 100644
--- a/scene/main/resource_preloader.cpp
+++ b/scene/main/resource_preloader.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/main/resource_preloader.h b/scene/main/resource_preloader.h
index b3e7496fb7..b06e558b59 100644
--- a/scene/main/resource_preloader.h
+++ b/scene/main/resource_preloader.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/main/scene_main_loop.cpp b/scene/main/scene_main_loop.cpp
index 1664a9bea1..8e2d6aa669 100644
--- a/scene/main/scene_main_loop.cpp
+++ b/scene/main/scene_main_loop.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -42,6 +42,8 @@
#include "io/resource_loader.h"
#include "viewport.h"
#include "scene/resources/packed_scene.h"
+#include "scene/resources/material.h"
+#include "scene/resources/mesh.h"
void SceneTree::tree_changed() {
@@ -328,7 +330,8 @@ void SceneTree::input_text( const String& p_text ) {
root_lock++;
- call_group(GROUP_CALL_REALTIME|GROUP_CALL_MULIILEVEL,"input",p_text);
+ call_group(GROUP_CALL_REALTIME,"_viewports","_vp_input_text",p_text); //special one for GUI, as controls use their own process check
+
root_lock--;
}
@@ -470,7 +473,6 @@ void SceneTree::init() {
input_handled=false;
- editor_hint=false;
pause=false;
root->_set_tree(this);
@@ -619,11 +621,188 @@ void SceneTree::set_editor_hint(bool p_enabled) {
editor_hint=p_enabled;
}
+bool SceneTree::is_node_being_edited(const Node* p_node) const {
+#ifdef TOOLS_ENABLED
+ return editor_hint && edited_scene_root && edited_scene_root->is_a_parent_of(p_node);
+#else
+ return false;
+#endif
+}
+
bool SceneTree::is_editor_hint() const {
return editor_hint;
}
+void SceneTree::set_debug_collisions_hint(bool p_enabled) {
+
+ debug_collisions_hint=p_enabled;
+}
+
+bool SceneTree::is_debugging_collisions_hint() const {
+
+ return debug_collisions_hint;
+}
+
+void SceneTree::set_debug_navigation_hint(bool p_enabled) {
+
+ debug_navigation_hint=p_enabled;
+}
+
+bool SceneTree::is_debugging_navigation_hint() const {
+
+ return debug_navigation_hint;
+}
+
+void SceneTree::set_debug_collisions_color(const Color& p_color) {
+
+ debug_collisions_color=p_color;
+}
+
+Color SceneTree::get_debug_collisions_color() const {
+
+ return debug_collisions_color;
+}
+
+void SceneTree::set_debug_collision_contact_color(const Color& p_color) {
+
+ debug_collision_contact_color=p_color;
+}
+
+Color SceneTree::get_debug_collision_contact_color() const {
+
+ return debug_collision_contact_color;
+}
+
+void SceneTree::set_debug_navigation_color(const Color& p_color) {
+
+ debug_navigation_color=p_color;
+}
+
+Color SceneTree::get_debug_navigation_color() const {
+
+ return debug_navigation_color;
+}
+
+void SceneTree::set_debug_navigation_disabled_color(const Color& p_color) {
+
+ debug_navigation_disabled_color=p_color;
+}
+
+Color SceneTree::get_debug_navigation_disabled_color() const {
+
+ return debug_navigation_disabled_color;
+}
+
+Ref<Material> SceneTree::get_debug_navigation_material() {
+
+ if (navigation_material.is_valid())
+ return navigation_material;
+
+ Ref<FixedMaterial> line_material = Ref<FixedMaterial>( memnew( FixedMaterial ));
+ line_material->set_flag(Material::FLAG_UNSHADED, true);
+ line_material->set_line_width(3.0);
+ line_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
+ line_material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, true);
+ line_material->set_parameter(FixedMaterial::PARAM_DIFFUSE,get_debug_navigation_color());
+
+ navigation_material=line_material;
+
+ return navigation_material;
+
+}
+
+Ref<Material> SceneTree::get_debug_navigation_disabled_material(){
+
+ if (navigation_disabled_material.is_valid())
+ return navigation_disabled_material;
+
+ Ref<FixedMaterial> line_material = Ref<FixedMaterial>( memnew( FixedMaterial ));
+ line_material->set_flag(Material::FLAG_UNSHADED, true);
+ line_material->set_line_width(3.0);
+ line_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
+ line_material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, true);
+ line_material->set_parameter(FixedMaterial::PARAM_DIFFUSE,get_debug_navigation_disabled_color());
+
+ navigation_disabled_material=line_material;
+
+ return navigation_disabled_material;
+
+}
+Ref<Material> SceneTree::get_debug_collision_material() {
+
+ if (collision_material.is_valid())
+ return collision_material;
+
+
+ Ref<FixedMaterial> line_material = Ref<FixedMaterial>( memnew( FixedMaterial ));
+ line_material->set_flag(Material::FLAG_UNSHADED, true);
+ line_material->set_line_width(3.0);
+ line_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
+ line_material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, true);
+ line_material->set_parameter(FixedMaterial::PARAM_DIFFUSE,get_debug_collisions_color());
+
+ collision_material=line_material;
+
+ return collision_material;
+}
+
+Ref<Mesh> SceneTree::get_debug_contact_mesh() {
+
+ if (debug_contact_mesh.is_valid())
+ return debug_contact_mesh;
+
+ debug_contact_mesh = Ref<Mesh>( memnew( Mesh ) );
+
+ Ref<FixedMaterial> mat = memnew( FixedMaterial );
+ mat->set_flag(Material::FLAG_UNSHADED,true);
+ mat->set_flag(Material::FLAG_DOUBLE_SIDED,true);
+ mat->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA,true);
+ mat->set_parameter(FixedMaterial::PARAM_DIFFUSE,get_debug_collision_contact_color());
+
+ Vector3 diamond[6]={
+ Vector3(-1, 0, 0),
+ Vector3( 1, 0, 0),
+ Vector3( 0, -1, 0),
+ Vector3( 0, 1, 0),
+ Vector3( 0, 0, -1),
+ Vector3( 0, 0, 1)
+ };
+
+ int diamond_faces[8*3]={
+ 0,2,4,
+ 0,3,4,
+ 1,2,4,
+ 1,3,4,
+ 0,2,5,
+ 0,3,5,
+ 1,2,5,
+ 1,3,5,
+ };
+
+ DVector<int> indices;
+ for(int i=0;i<8*3;i++)
+ indices.push_back(diamond_faces[i]);
+
+ DVector<Vector3> vertices;
+ for(int i=0;i<6;i++)
+ vertices.push_back(diamond[i]*0.1);
+
+ Array arr;
+ arr.resize(Mesh::ARRAY_MAX);
+ arr[Mesh::ARRAY_VERTEX]=vertices;
+ arr[Mesh::ARRAY_INDEX]=indices;
+
+
+ debug_contact_mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES,arr);
+ debug_contact_mesh->surface_set_material(0,mat);
+
+ return debug_contact_mesh;
+
+}
+
+
+
void SceneTree::set_pause(bool p_enabled) {
if (p_enabled==pause)
@@ -795,6 +974,10 @@ Array SceneTree::_get_nodes_in_group(const StringName& p_group) {
return ret;
}
+bool SceneTree::has_group(const StringName& p_identifier) const {
+
+ return group_map.has(p_identifier);
+}
void SceneTree::get_nodes_in_group(const StringName& p_group,List<Node*> *p_list) {
@@ -1044,7 +1227,371 @@ void SceneTree::add_current_scene(Node * p_current) {
current_scene=p_current;
root->add_child(p_current);
}
+#ifdef DEBUG_ENABLED
+
+void SceneTree::_live_edit_node_path_func(const NodePath &p_path,int p_id) {
+
+ live_edit_node_path_cache[p_id]=p_path;
+}
+
+void SceneTree::_live_edit_res_path_func(const String &p_path,int p_id) {
+
+ live_edit_resource_cache[p_id]=p_path;
+}
+
+void SceneTree::_live_edit_node_set_func(int p_id,const StringName& p_prop,const Variant& p_value) {
+
+ if (!live_edit_node_path_cache.has(p_id))
+ return;
+
+ NodePath np = live_edit_node_path_cache[p_id];
+ Node *base = NULL;
+ if (root->has_node(live_edit_root))
+ base = root->get_node(live_edit_root);
+
+ Map<String,Set<Node*> >::Element *E=live_scene_edit_cache.find(live_edit_scene);
+ if (!E)
+ return; //scene not editable
+
+ for(Set<Node*>::Element *F=E->get().front();F;F=F->next()) {
+
+ Node *n=F->get();
+
+ if (base && !base->is_a_parent_of(n))
+ continue;
+
+ if (!n->has_node(np))
+ continue;
+ Node *n2 = n->get_node(np);
+
+ n2->set(p_prop,p_value);
+ }
+
+}
+
+void SceneTree::_live_edit_node_set_res_func(int p_id,const StringName& p_prop,const String& p_value) {
+
+ RES r = ResourceLoader::load(p_value);
+ if (!r.is_valid())
+ return;
+ _live_edit_node_set_func(p_id,p_prop,r);
+
+}
+void SceneTree::_live_edit_node_call_func(int p_id,const StringName& p_method,VARIANT_ARG_DECLARE) {
+
+ if (!live_edit_node_path_cache.has(p_id))
+ return;
+
+ NodePath np = live_edit_node_path_cache[p_id];
+ Node *base = NULL;
+ if (root->has_node(live_edit_root))
+ base = root->get_node(live_edit_root);
+
+ Map<String,Set<Node*> >::Element *E=live_scene_edit_cache.find(live_edit_scene);
+ if (!E)
+ return; //scene not editable
+
+ for(Set<Node*>::Element *F=E->get().front();F;F=F->next()) {
+
+ Node *n=F->get();
+
+ if (base && !base->is_a_parent_of(n))
+ continue;
+
+ if (!n->has_node(np))
+ continue;
+ Node *n2 = n->get_node(np);
+
+ n2->call(p_method,VARIANT_ARG_PASS);
+ }
+}
+void SceneTree::_live_edit_res_set_func(int p_id,const StringName& p_prop,const Variant& p_value) {
+
+ if (!live_edit_resource_cache.has(p_id))
+ return;
+
+ String resp = live_edit_resource_cache[p_id];
+
+ if (!ResourceCache::has(resp))
+ return;
+
+ RES r = ResourceCache::get(resp);
+ if (!r.is_valid())
+ return;
+
+ r->set(p_prop,p_value);
+}
+void SceneTree::_live_edit_res_set_res_func(int p_id,const StringName& p_prop,const String& p_value) {
+
+ RES r = ResourceLoader::load(p_value);
+ if (!r.is_valid())
+ return;
+ _live_edit_res_set_func(p_id,p_prop,r);
+
+}
+void SceneTree::_live_edit_res_call_func(int p_id,const StringName& p_method,VARIANT_ARG_DECLARE) {
+
+ if (!live_edit_resource_cache.has(p_id))
+ return;
+
+ String resp = live_edit_resource_cache[p_id];
+
+ if (!ResourceCache::has(resp))
+ return;
+
+ RES r = ResourceCache::get(resp);
+ if (!r.is_valid())
+ return;
+ r->call(p_method,VARIANT_ARG_PASS);
+}
+
+void SceneTree::_live_edit_root_func(const NodePath& p_scene_path,const String& p_scene_from) {
+
+ live_edit_root=p_scene_path;
+ live_edit_scene=p_scene_from;
+}
+
+void SceneTree::_live_edit_create_node_func(const NodePath& p_parent,const String& p_type,const String& p_name) {
+
+
+ Node *base = NULL;
+ if (root->has_node(live_edit_root))
+ base = root->get_node(live_edit_root);
+
+ Map<String,Set<Node*> >::Element *E=live_scene_edit_cache.find(live_edit_scene);
+ if (!E)
+ return; //scene not editable
+
+ for(Set<Node*>::Element *F=E->get().front();F;F=F->next()) {
+
+ Node *n=F->get();
+
+ if (base && !base->is_a_parent_of(n))
+ continue;
+
+ if (!n->has_node(p_parent))
+ continue;
+ Node *n2 = n->get_node(p_parent);
+
+ Object *o = ObjectTypeDB::instance(p_type);
+ if (!o)
+ continue;
+ Node *no=o->cast_to<Node>();
+ no->set_name(p_name);
+
+ n2->add_child(no);
+ }
+}
+void SceneTree::_live_edit_instance_node_func(const NodePath& p_parent,const String& p_path,const String& p_name){
+
+ Ref<PackedScene> ps = ResourceLoader::load(p_path);
+
+ if (!ps.is_valid())
+ return;
+
+ Node *base = NULL;
+ if (root->has_node(live_edit_root))
+ base = root->get_node(live_edit_root);
+
+ Map<String,Set<Node*> >::Element *E=live_scene_edit_cache.find(live_edit_scene);
+ if (!E)
+ return; //scene not editable
+
+ for(Set<Node*>::Element *F=E->get().front();F;F=F->next()) {
+
+ Node *n=F->get();
+
+ if (base && !base->is_a_parent_of(n))
+ continue;
+
+ if (!n->has_node(p_parent))
+ continue;
+ Node *n2 = n->get_node(p_parent);
+
+
+
+ Node *no=ps->instance();
+ no->set_name(p_name);
+
+ n2->add_child(no);
+ }
+}
+void SceneTree::_live_edit_remove_node_func(const NodePath& p_at){
+
+ Node *base = NULL;
+ if (root->has_node(live_edit_root))
+ base = root->get_node(live_edit_root);
+
+ Map<String,Set<Node*> >::Element *E=live_scene_edit_cache.find(live_edit_scene);
+ if (!E)
+ return; //scene not editable
+
+ for(Set<Node*>::Element *F=E->get().front();F;) {
+
+ Set<Node*>::Element *N=F->next();
+
+ Node *n=F->get();
+
+ if (base && !base->is_a_parent_of(n))
+ continue;
+
+ if (!n->has_node(p_at))
+ continue;
+ Node *n2 = n->get_node(p_at);
+
+ memdelete(n2);
+
+ F=N;
+
+ }
+}
+void SceneTree::_live_edit_remove_and_keep_node_func(const NodePath& p_at,ObjectID p_keep_id){
+
+ Node *base = NULL;
+ if (root->has_node(live_edit_root))
+ base = root->get_node(live_edit_root);
+
+ Map<String,Set<Node*> >::Element *E=live_scene_edit_cache.find(live_edit_scene);
+ if (!E)
+ return; //scene not editable
+
+
+ for(Set<Node*>::Element *F=E->get().front();F;) {
+
+ Set<Node*>::Element *N=F->next();
+
+ Node *n=F->get();
+
+ if (base && !base->is_a_parent_of(n))
+ continue;
+
+ if (!n->has_node(p_at))
+ continue;
+
+ Node *n2 = n->get_node(p_at);
+
+ n2->get_parent()->remove_child(n2);
+
+ live_edit_remove_list[n][p_keep_id]=n2;
+
+ F=N;
+
+ }
+}
+void SceneTree::_live_edit_restore_node_func(ObjectID p_id,const NodePath& p_at,int p_at_pos){
+
+
+ Node *base = NULL;
+ if (root->has_node(live_edit_root))
+ base = root->get_node(live_edit_root);
+
+ Map<String,Set<Node*> >::Element *E=live_scene_edit_cache.find(live_edit_scene);
+ if (!E)
+ return; //scene not editable
+
+ for(Set<Node*>::Element *F=E->get().front();F;) {
+
+ Set<Node*>::Element *N=F->next();
+
+ Node *n=F->get();
+
+ if (base && !base->is_a_parent_of(n))
+ continue;
+
+ if (!n->has_node(p_at))
+ continue;
+ Node *n2 = n->get_node(p_at);
+
+ Map<Node*,Map<ObjectID,Node*> >::Element *EN=live_edit_remove_list.find(n);
+
+ if (!EN)
+ continue;
+
+ Map<ObjectID,Node*>::Element *FN=EN->get().find(p_id);
+
+ if (!FN)
+ continue;
+ n2->add_child(FN->get());
+
+ EN->get().erase(FN);
+
+ if (EN->get().size()==0) {
+ live_edit_remove_list.erase(EN);
+ }
+
+ F=N;
+
+ }
+}
+void SceneTree::_live_edit_duplicate_node_func(const NodePath& p_at,const String& p_new_name){
+
+ Node *base = NULL;
+ if (root->has_node(live_edit_root))
+ base = root->get_node(live_edit_root);
+
+ Map<String,Set<Node*> >::Element *E=live_scene_edit_cache.find(live_edit_scene);
+ if (!E)
+ return; //scene not editable
+
+ for(Set<Node*>::Element *F=E->get().front();F;F=F->next()) {
+
+ Node *n=F->get();
+
+ if (base && !base->is_a_parent_of(n))
+ continue;
+
+ if (!n->has_node(p_at))
+ continue;
+ Node *n2 = n->get_node(p_at);
+
+ Node *dup = n2->duplicate(true);
+
+ if (!dup)
+ continue;
+
+ dup->set_name(p_new_name);
+ n2->get_parent()->add_child(dup);
+
+ }
+}
+void SceneTree::_live_edit_reparent_node_func(const NodePath& p_at,const NodePath& p_new_place,const String& p_new_name,int p_at_pos){
+
+ Node *base = NULL;
+ if (root->has_node(live_edit_root))
+ base = root->get_node(live_edit_root);
+
+ Map<String,Set<Node*> >::Element *E=live_scene_edit_cache.find(live_edit_scene);
+ if (!E)
+ return; //scene not editable
+
+ for(Set<Node*>::Element *F=E->get().front();F;F=F->next()) {
+
+ Node *n=F->get();
+
+ if (base && !base->is_a_parent_of(n))
+ continue;
+
+ if (!n->has_node(p_at))
+ continue;
+ Node *nfrom = n->get_node(p_at);
+
+ if (!n->has_node(p_new_place))
+ continue;
+ Node *nto = n->get_node(p_new_place);
+
+ nfrom->get_parent()->remove_child(nfrom);
+ nfrom->set_name(p_new_name);
+
+ nto->add_child(nfrom);
+ if (p_at_pos>=0)
+ nto->move_child(nfrom,p_at_pos);
+
+ }
+}
+
+
+#endif
void SceneTree::_bind_methods() {
@@ -1052,14 +1599,20 @@ void SceneTree::_bind_methods() {
ObjectTypeDB::bind_method(_MD("notify_group","call_flags","group","notification"),&SceneTree::notify_group);
ObjectTypeDB::bind_method(_MD("set_group","call_flags","group","property","value"),&SceneTree::set_group);
- ObjectTypeDB::bind_method(_MD("get_nodes_in_group"),&SceneTree::_get_nodes_in_group);
+ ObjectTypeDB::bind_method(_MD("get_nodes_in_group","group"),&SceneTree::_get_nodes_in_group);
ObjectTypeDB::bind_method(_MD("get_root:Viewport"),&SceneTree::get_root);
+ ObjectTypeDB::bind_method(_MD("has_group","name"),&SceneTree::has_group);
ObjectTypeDB::bind_method(_MD("set_auto_accept_quit","enabled"),&SceneTree::set_auto_accept_quit);
ObjectTypeDB::bind_method(_MD("set_editor_hint","enable"),&SceneTree::set_editor_hint);
ObjectTypeDB::bind_method(_MD("is_editor_hint"),&SceneTree::is_editor_hint);
+ ObjectTypeDB::bind_method(_MD("set_debug_collisions_hint","enable"),&SceneTree::set_debug_collisions_hint);
+ ObjectTypeDB::bind_method(_MD("is_debugging_collisions_hint"),&SceneTree::is_debugging_collisions_hint);
+ ObjectTypeDB::bind_method(_MD("set_debug_navigation_hint","enable"),&SceneTree::set_debug_navigation_hint);
+ ObjectTypeDB::bind_method(_MD("is_debugging_navigation_hint"),&SceneTree::is_debugging_navigation_hint);
+
#ifdef TOOLS_ENABLED
ObjectTypeDB::bind_method(_MD("set_edited_scene_root","scene"),&SceneTree::set_edited_scene_root);
ObjectTypeDB::bind_method(_MD("get_edited_scene_root"),&SceneTree::get_edited_scene_root);
@@ -1126,10 +1679,23 @@ void SceneTree::_bind_methods() {
}
+SceneTree *SceneTree::singleton=NULL;
+
SceneTree::SceneTree() {
+ singleton=this;
_quit=false;
initialized=false;
+ editor_hint=false;
+ debug_collisions_hint=false;
+ debug_navigation_hint=false;
+ debug_collisions_color=GLOBAL_DEF("debug/collision_shape_color",Color(0.0,0.6,0.7,0.5));
+ debug_collision_contact_color=GLOBAL_DEF("debug/collision_contact_color",Color(1.0,0.2,0.1,0.8));
+ debug_navigation_color=GLOBAL_DEF("debug/navigation_geometry_color",Color(0.1,1.0,0.7,0.4));
+ debug_navigation_disabled_color=GLOBAL_DEF("debug/navigation_disabled_geometry_color",Color(1.0,0.7,0.1,0.4));
+ collision_debug_contacts=GLOBAL_DEF("debug/collision_max_contacts_displayed",10000);
+
+
tree_version=1;
fixed_process_time=1;
idle_process_time=1;
@@ -1169,6 +1735,35 @@ SceneTree::SceneTree() {
edited_scene_root=NULL;
#endif
+#ifdef DEBUG_ENABLED
+
+
+ live_edit_funcs.udata=this;
+ live_edit_funcs.node_path_func=_live_edit_node_path_funcs;
+ live_edit_funcs.res_path_func=_live_edit_res_path_funcs;
+ live_edit_funcs.node_set_func=_live_edit_node_set_funcs;
+ live_edit_funcs.node_set_res_func=_live_edit_node_set_res_funcs;
+ live_edit_funcs.node_call_func=_live_edit_node_call_funcs;
+ live_edit_funcs.res_set_func=_live_edit_res_set_funcs;
+ live_edit_funcs.res_set_res_func=_live_edit_res_set_res_funcs;
+ live_edit_funcs.res_call_func=_live_edit_res_call_funcs;
+ live_edit_funcs.root_func=_live_edit_root_funcs;
+
+ live_edit_funcs.tree_create_node_func=_live_edit_create_node_funcs;
+ live_edit_funcs.tree_instance_node_func=_live_edit_instance_node_funcs;
+ live_edit_funcs.tree_remove_node_func=_live_edit_remove_node_funcs;
+ live_edit_funcs.tree_remove_and_keep_node_func=_live_edit_remove_and_keep_node_funcs;
+ live_edit_funcs.tree_restore_node_func=_live_edit_restore_node_funcs;
+ live_edit_funcs.tree_duplicate_node_func=_live_edit_duplicate_node_funcs;
+ live_edit_funcs.tree_reparent_node_func=_live_edit_reparent_node_funcs;
+
+ if (ScriptDebugger::get_singleton()) {
+ ScriptDebugger::get_singleton()->set_live_edit_funcs(&live_edit_funcs);
+ }
+
+ live_edit_root=NodePath("/root");
+
+#endif
}
diff --git a/scene/main/scene_main_loop.h b/scene/main/scene_main_loop.h
index e49c150fbf..c6fc124345 100644
--- a/scene/main/scene_main_loop.h
+++ b/scene/main/scene_main_loop.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -45,6 +45,8 @@ class SceneTree;
class PackedScene;
class Node;
class Viewport;
+class Material;
+class Mesh;
class SceneTree : public MainLoop {
@@ -87,6 +89,8 @@ private:
uint32_t last_id;
bool editor_hint;
+ bool debug_collisions_hint;
+ bool debug_navigation_hint;
bool pause;
int root_lock;
@@ -138,9 +142,20 @@ private:
Node *current_scene;
+ Color debug_collisions_color;
+ Color debug_collision_contact_color;
+ Color debug_navigation_color;
+ Color debug_navigation_disabled_color;
+ Ref<Mesh> debug_contact_mesh;
+ Ref<Material> navigation_material;
+ Ref<Material> navigation_disabled_material;
+ Ref<Material> collision_material;
+ int collision_debug_contacts;
+
void _change_scene(Node* p_to);
//void _call_group(uint32_t p_call_flags,const StringName& p_group,const StringName& p_function,const Variant& p_arg1,const Variant& p_arg2);
+ static SceneTree *singleton;
friend class Node;
void tree_changed();
@@ -164,6 +179,58 @@ friend class Viewport;
SelfList<Node>::List xform_change_list;
+#ifdef DEBUG_ENABLED
+
+ Map<int,NodePath> live_edit_node_path_cache;
+ Map<int,String> live_edit_resource_cache;
+
+ NodePath live_edit_root;
+ String live_edit_scene;
+
+ Map<String,Set<Node*> > live_scene_edit_cache;
+ Map<Node*,Map<ObjectID,Node*> > live_edit_remove_list;
+
+ ScriptDebugger::LiveEditFuncs live_edit_funcs;
+
+ void _live_edit_node_path_func(const NodePath &p_path,int p_id) ;
+ void _live_edit_res_path_func(const String &p_path,int p_id) ;
+
+ void _live_edit_node_set_func(int p_id,const StringName& p_prop,const Variant& p_value) ;
+ void _live_edit_node_set_res_func(int p_id,const StringName& p_prop,const String& p_value) ;
+ void _live_edit_node_call_func(int p_id,const StringName& p_method,VARIANT_ARG_DECLARE) ;
+ void _live_edit_res_set_func(int p_id,const StringName& p_prop,const Variant& p_value) ;
+ void _live_edit_res_set_res_func(int p_id,const StringName& p_prop,const String& p_value) ;
+ void _live_edit_res_call_func(int p_id,const StringName& p_method,VARIANT_ARG_DECLARE) ;
+ void _live_edit_root_func(const NodePath& p_scene_path,const String& p_scene_from) ;
+
+ void _live_edit_create_node_func(const NodePath& p_parent,const String& p_type,const String& p_name);
+ void _live_edit_instance_node_func(const NodePath& p_parent,const String& p_path,const String& p_name);
+ void _live_edit_remove_node_func(const NodePath& p_at);
+ void _live_edit_remove_and_keep_node_func(const NodePath& p_at,ObjectID p_keep_id);
+ void _live_edit_restore_node_func(ObjectID p_id,const NodePath& p_at,int p_at_pos);
+ void _live_edit_duplicate_node_func(const NodePath& p_at,const String& p_new_name);
+ void _live_edit_reparent_node_func(const NodePath& p_at,const NodePath& p_new_place,const String& p_new_name,int p_at_pos);
+
+ static void _live_edit_node_path_funcs(void *self,const NodePath &p_path,int p_id) { reinterpret_cast<SceneTree*>(self)->_live_edit_node_path_func(p_path,p_id); }
+ static void _live_edit_res_path_funcs(void *self,const String &p_path,int p_id) { reinterpret_cast<SceneTree*>(self)->_live_edit_res_path_func(p_path,p_id); }
+
+ static void _live_edit_node_set_funcs(void *self,int p_id,const StringName& p_prop,const Variant& p_value) { reinterpret_cast<SceneTree*>(self)->_live_edit_node_set_func(p_id,p_prop,p_value); }
+ static void _live_edit_node_set_res_funcs(void *self,int p_id,const StringName& p_prop,const String& p_value) { reinterpret_cast<SceneTree*>(self)->_live_edit_node_set_res_func(p_id,p_prop,p_value); }
+ static void _live_edit_node_call_funcs(void *self,int p_id,const StringName& p_method,VARIANT_ARG_DECLARE) { reinterpret_cast<SceneTree*>(self)->_live_edit_node_call_func(p_id,p_method,VARIANT_ARG_PASS); }
+ static void _live_edit_res_set_funcs(void *self,int p_id,const StringName& p_prop,const Variant& p_value) { reinterpret_cast<SceneTree*>(self)->_live_edit_res_set_func(p_id,p_prop,p_value); }
+ static void _live_edit_res_set_res_funcs(void *self,int p_id,const StringName& p_prop,const String& p_value) { reinterpret_cast<SceneTree*>(self)->_live_edit_res_set_res_func(p_id,p_prop,p_value); }
+ static void _live_edit_res_call_funcs(void *self,int p_id,const StringName& p_method,VARIANT_ARG_DECLARE) { reinterpret_cast<SceneTree*>(self)->_live_edit_res_call_func(p_id,p_method,VARIANT_ARG_PASS); }
+ static void _live_edit_root_funcs(void *self, const NodePath& p_scene_path,const String& p_scene_from) { reinterpret_cast<SceneTree*>(self)->_live_edit_root_func(p_scene_path,p_scene_from); }
+
+ static void _live_edit_create_node_funcs(void* self,const NodePath& p_parent,const String& p_type,const String& p_name) { reinterpret_cast<SceneTree*>(self)->_live_edit_create_node_func(p_parent,p_type,p_name); }
+ static void _live_edit_instance_node_funcs(void* self,const NodePath& p_parent,const String& p_path,const String& p_name) { reinterpret_cast<SceneTree*>(self)->_live_edit_instance_node_func(p_parent,p_path,p_name); }
+ static void _live_edit_remove_node_funcs(void* self,const NodePath& p_at) { reinterpret_cast<SceneTree*>(self)->_live_edit_remove_node_func(p_at); }
+ static void _live_edit_remove_and_keep_node_funcs(void* self,const NodePath& p_at,ObjectID p_keep_id) { reinterpret_cast<SceneTree*>(self)->_live_edit_remove_and_keep_node_func(p_at,p_keep_id); }
+ static void _live_edit_restore_node_funcs(void* self,ObjectID p_id,const NodePath& p_at,int p_at_pos) { reinterpret_cast<SceneTree*>(self)->_live_edit_restore_node_func(p_id,p_at,p_at_pos); }
+ static void _live_edit_duplicate_node_funcs(void* self,const NodePath& p_at,const String& p_new_name) { reinterpret_cast<SceneTree*>(self)->_live_edit_duplicate_node_func(p_at,p_new_name); }
+ static void _live_edit_reparent_node_funcs(void* self,const NodePath& p_at,const NodePath& p_new_place,const String& p_new_name,int p_at_pos) { reinterpret_cast<SceneTree*>(self)->_live_edit_reparent_node_func(p_at,p_new_place,p_new_name,p_at_pos); }
+
+#endif
protected:
void _notification(int p_notification);
@@ -212,12 +279,40 @@ public:
void set_editor_hint(bool p_enabled);
bool is_editor_hint() const;
+ bool is_node_being_edited(const Node* p_node) const;
+
void set_pause(bool p_enabled);
bool is_paused() const;
void set_camera(const RID& p_camera);
RID get_camera() const;
+ void set_debug_collisions_hint(bool p_enabled);
+ bool is_debugging_collisions_hint() const;
+
+ void set_debug_navigation_hint(bool p_enabled);
+ bool is_debugging_navigation_hint() const;
+
+ void set_debug_collisions_color(const Color& p_color);
+ Color get_debug_collisions_color() const;
+
+ void set_debug_collision_contact_color(const Color& p_color);
+ Color get_debug_collision_contact_color() const;
+
+ void set_debug_navigation_color(const Color& p_color);
+ Color get_debug_navigation_color() const;
+
+ void set_debug_navigation_disabled_color(const Color& p_color);
+ Color get_debug_navigation_disabled_color() const;
+
+
+ Ref<Material> get_debug_navigation_material();
+ Ref<Material> get_debug_navigation_disabled_material();
+ Ref<Material> get_debug_collision_material();
+ Ref<Mesh> get_debug_contact_mesh();
+
+ int get_collision_debug_contact_count() { return collision_debug_contacts; }
+
int64_t get_frame() const;
int get_node_count() const;
@@ -225,6 +320,8 @@ public:
void queue_delete(Object *p_object);
void get_nodes_in_group(const StringName& p_group,List<Node*> *p_list);
+ bool has_group(const StringName& p_identifier) const;
+
void set_screen_stretch(StretchMode p_mode,StretchAspect p_aspect,const Size2 p_minsize);
@@ -245,6 +342,7 @@ public:
//used by Main::start, don't use otherwise
void add_current_scene(Node * p_current);
+ static SceneTree* get_singleton() { return singleton; }
SceneTree();
diff --git a/scene/main/scene_singleton.cpp b/scene/main/scene_singleton.cpp
index 69eb6e24d9..3dcc6b1204 100644
--- a/scene/main/scene_singleton.cpp
+++ b/scene/main/scene_singleton.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/main/scene_singleton.h b/scene/main/scene_singleton.h
index 25157a26ac..0b209f7944 100644
--- a/scene/main/scene_singleton.h
+++ b/scene/main/scene_singleton.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/main/timer.cpp b/scene/main/timer.cpp
index 3a80382a40..2c23b62b12 100644
--- a/scene/main/timer.cpp
+++ b/scene/main/timer.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -182,11 +182,14 @@ void Timer::_bind_methods() {
ADD_SIGNAL( MethodInfo("timeout") );
- ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Fixed,Idle"), _SCS("set_timer_process_mode"), _SCS("get_timer_process_mode"));
+ ADD_PROPERTY( PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Fixed,Idle"), _SCS("set_timer_process_mode"), _SCS("get_timer_process_mode") );
ADD_PROPERTY( PropertyInfo(Variant::REAL, "wait_time", PROPERTY_HINT_EXP_RANGE, "0.01,4096,0.01" ), _SCS("set_wait_time"), _SCS("get_wait_time") );
ADD_PROPERTY( PropertyInfo(Variant::BOOL, "one_shot" ), _SCS("set_one_shot"), _SCS("is_one_shot") );
ADD_PROPERTY( PropertyInfo(Variant::BOOL, "autostart" ), _SCS("set_autostart"), _SCS("has_autostart") );
+ BIND_CONSTANT( TIMER_PROCESS_FIXED );
+ BIND_CONSTANT( TIMER_PROCESS_IDLE );
+
}
Timer::Timer() {
diff --git a/scene/main/timer.h b/scene/main/timer.h
index 4b9cecba84..0baea76fad 100644
--- a/scene/main/timer.h
+++ b/scene/main/timer.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 3bb64e54c6..f21142c739 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -37,11 +37,19 @@
#include "servers/spatial_sound_2d_server.h"
#include "scene/gui/control.h"
#include "scene/3d/camera.h"
+#include "scene/resources/mesh.h"
#include "scene/3d/spatial_indexer.h"
#include "scene/3d/collision_object.h"
#include "scene/2d/collision_object_2d.h"
+#include "scene/gui/panel.h"
+#include "scene/gui/label.h"
+#include "scene/main/timer.h"
+#include "scene/scene_string_names.h"
+
+#include "globals.h"
+
int RenderTargetTexture::get_width() const {
ERR_FAIL_COND_V(!vp,0);
@@ -91,8 +99,42 @@ RenderTargetTexture::RenderTargetTexture(Viewport *p_vp){
flags=0;
}
+/////////////////////////////////////
+
+class TooltipPanel : public Panel {
+
+ OBJ_TYPE(TooltipPanel,Panel)
+public:
+ TooltipPanel() {};
+
+};
+
+class TooltipLabel : public Label {
+
+ OBJ_TYPE(TooltipLabel,Label)
+public:
+ TooltipLabel() {};
+
+};
+Viewport::GUI::GUI() {
+
+
+ mouse_focus=NULL;
+ mouse_focus_button=-1;
+ key_focus=NULL;
+ mouse_over=NULL;
+
+ cancelled_input_ID=0;
+ tooltip=NULL;
+ tooltip_popup=NULL;
+ tooltip_label=NULL;
+ subwindow_order_dirty=false;
+}
+
+
+/////////////////////////////////////
void Viewport::_update_stretch_transform() {
if (size_override_stretch && size_override) {
@@ -120,11 +162,10 @@ void Viewport::_update_rect() {
if (!is_inside_tree())
return;
- Node *parent = get_parent();
- if (!render_target && parent && parent->cast_to<Control>()) {
+ if (!render_target && parent_control) {
- Control *c = parent->cast_to<Control>();
+ Control *c = parent_control;
rect.pos=Point2();
rect.size=c->get_size();
@@ -133,6 +174,7 @@ void Viewport::_update_rect() {
VisualServer::ViewportRect vr;
vr.x=rect.pos.x;
vr.y=rect.pos.y;
+
if (render_target) {
vr.x=0;
vr.y=0;
@@ -164,11 +206,10 @@ void Viewport::_parent_draw() {
void Viewport::_parent_visibility_changed() {
- Node *parent = get_parent();
- if (parent && parent->cast_to<Control>()) {
+ if (parent_control) {
- Control *c = parent->cast_to<Control>();
+ Control *c = parent_control;
VisualServer::get_singleton()->canvas_item_set_visible(canvas_item,c->is_visible());
_update_listener();
@@ -181,11 +222,9 @@ void Viewport::_parent_visibility_changed() {
void Viewport::_vp_enter_tree() {
- Node *parent = get_parent();
- //none?
- if (parent && parent->cast_to<Control>()) {
+ if (parent_control) {
- Control *cparent=parent->cast_to<Control>();
+ Control *cparent=parent_control;
RID parent_ci = cparent->get_canvas_item();
ERR_FAIL_COND(!parent_ci.is_valid());
canvas_item = VisualServer::get_singleton()->canvas_item_create();
@@ -193,8 +232,8 @@ void Viewport::_vp_enter_tree() {
VisualServer::get_singleton()->canvas_item_set_parent(canvas_item,parent_ci);
VisualServer::get_singleton()->canvas_item_set_visible(canvas_item,false);
VisualServer::get_singleton()->canvas_item_attach_viewport(canvas_item,viewport);
- parent->connect("resized",this,"_parent_resized");
- parent->connect("visibility_changed",this,"_parent_visibility_changed");
+ parent_control->connect("resized",this,"_parent_resized");
+ parent_control->connect("visibility_changed",this,"_parent_visibility_changed");
} else if (!parent){
VisualServer::get_singleton()->viewport_attach_to_screen(viewport,0);
@@ -206,15 +245,14 @@ void Viewport::_vp_enter_tree() {
void Viewport::_vp_exit_tree() {
- Node *parent = get_parent();
- if (parent && parent->cast_to<Control>()) {
+ if (parent_control) {
- parent->disconnect("resized",this,"_parent_resized");
+ parent_control->disconnect("resized",this,"_parent_resized");
}
- if (parent && parent->cast_to<Control>()) {
+ if (parent_control) {
- parent->disconnect("visibility_changed",this,"_parent_visibility_changed");
+ parent_control->disconnect("visibility_changed",this,"_parent_visibility_changed");
}
if (canvas_item.is_valid()) {
@@ -286,6 +324,12 @@ void Viewport::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
+ if (get_parent()) {
+ Node *parent=get_parent();
+ if (parent) {
+ parent_control=parent->cast_to<Control>();
+ }
+ }
if (!render_target)
_vp_enter_tree();
@@ -319,6 +363,23 @@ void Viewport::_notification(int p_what) {
}
add_to_group("_viewports");
+ if (get_tree()->is_debugging_collisions_hint()) {
+ //2D
+ Physics2DServer::get_singleton()->space_set_debug_contacts(find_world_2d()->get_space(),get_tree()->get_collision_debug_contact_count());
+ contact_2d_debug=VisualServer::get_singleton()->canvas_item_create();
+ VisualServer::get_singleton()->canvas_item_set_parent(contact_2d_debug,find_world_2d()->get_canvas());
+ //3D
+ PhysicsServer::get_singleton()->space_set_debug_contacts(find_world()->get_space(),get_tree()->get_collision_debug_contact_count());
+ contact_3d_debug_multimesh=VisualServer::get_singleton()->multimesh_create();
+ VisualServer::get_singleton()->multimesh_set_instance_count(contact_3d_debug_multimesh,get_tree()->get_collision_debug_contact_count());
+ VisualServer::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh,0);
+ VisualServer::get_singleton()->multimesh_set_mesh(contact_3d_debug_multimesh,get_tree()->get_debug_contact_mesh()->get_rid());
+ contact_3d_debug_instance=VisualServer::get_singleton()->instance_create();
+ VisualServer::get_singleton()->instance_set_base(contact_3d_debug_instance,contact_3d_debug_multimesh);
+ VisualServer::get_singleton()->instance_set_scenario(contact_3d_debug_instance,find_world()->get_scenario());
+ VisualServer::get_singleton()->instance_geometry_set_flag(contact_3d_debug_instance,VS::INSTANCE_FLAG_VISIBLE_IN_ALL_ROOMS,true);
+
+ }
} break;
case NOTIFICATION_READY: {
@@ -351,11 +412,70 @@ void Viewport::_notification(int p_what) {
VisualServer::get_singleton()->viewport_set_scenario(viewport,RID());
SpatialSoundServer::get_singleton()->listener_set_space(listener,RID());
VisualServer::get_singleton()->viewport_remove_canvas(viewport,current_canvas);
+ if (contact_2d_debug.is_valid()) {
+ VisualServer::get_singleton()->free(contact_2d_debug);
+ contact_2d_debug=RID();
+ }
+
+ if (contact_3d_debug_multimesh.is_valid()) {
+ VisualServer::get_singleton()->free(contact_3d_debug_multimesh);
+ VisualServer::get_singleton()->free(contact_3d_debug_instance);
+ contact_3d_debug_instance=RID();
+ contact_3d_debug_multimesh=RID();
+ }
+
remove_from_group("_viewports");
+ parent_control=NULL;
} break;
case NOTIFICATION_FIXED_PROCESS: {
+
+ if (get_tree()->is_debugging_collisions_hint() && contact_2d_debug.is_valid()) {
+
+ VisualServer::get_singleton()->canvas_item_clear(contact_2d_debug);
+ VisualServer::get_singleton()->canvas_item_raise(contact_2d_debug);
+
+ Vector<Vector2> points = Physics2DServer::get_singleton()->space_get_contacts(find_world_2d()->get_space());
+ int point_count = Physics2DServer::get_singleton()->space_get_contact_count(find_world_2d()->get_space());
+ Color ccol = get_tree()->get_debug_collision_contact_color();
+
+
+ for(int i=0;i<point_count;i++) {
+
+ VisualServer::get_singleton()->canvas_item_add_rect(contact_2d_debug,Rect2(points[i]-Vector2(2,2),Vector2(5,5)),ccol);
+ }
+ }
+
+ if (get_tree()->is_debugging_collisions_hint() && contact_3d_debug_multimesh.is_valid()) {
+
+
+ Vector<Vector3> points = PhysicsServer::get_singleton()->space_get_contacts(find_world()->get_space());
+ int point_count = PhysicsServer::get_singleton()->space_get_contact_count(find_world()->get_space());
+
+
+ VS::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh,point_count);
+
+ if (point_count>0) {
+ AABB aabb;
+
+ Transform t;
+ for(int i=0;i<point_count;i++) {
+
+ if (i==0)
+ aabb.pos=points[i];
+ else
+ aabb.expand_to(points[i]);
+ t.origin=points[i];
+ VisualServer::get_singleton()->multimesh_instance_set_transform(contact_3d_debug_multimesh,i,t);
+ }
+ aabb.grow(aabb.get_longest_axis_size()*0.01);
+ VisualServer::get_singleton()->multimesh_set_aabb(contact_3d_debug_multimesh,aabb);
+ }
+ }
+
+
+
if (physics_object_picking) {
Vector2 last_pos(1e20,1e20);
@@ -501,7 +621,7 @@ void Viewport::_notification(int p_what) {
PhysicsDirectSpaceState *space = PhysicsServer::get_singleton()->space_get_direct_state(find_world()->get_space());
if (space) {
- bool col = space->intersect_ray(from,from+dir*10000,result,Set<RID>(),0xFFFFFFFF,0xFFFFFFFF);
+ bool col = space->intersect_ray(from,from+dir*10000,result,Set<RID>(),0xFFFFFFFF,0xFFFFFFFF,true);
ObjectID new_collider=0;
if (col) {
@@ -541,7 +661,7 @@ void Viewport::_notification(int p_what) {
PhysicsDirectSpaceState *space = PhysicsServer::get_singleton()->space_get_direct_state(find_world()->get_space());
if (space) {
- bool col = space->intersect_ray(from,from+dir*10000,result,Set<RID>(),0xFFFFFFFF,0xFFFFFFFF);
+ bool col = space->intersect_ray(from,from+dir*10000,result,Set<RID>(),0xFFFFFFFF,0xFFFFFFFF,true);
ObjectID new_collider=0;
if (col) {
if (result.collider) {
@@ -1147,15 +1267,34 @@ void Viewport::_make_input_local(InputEvent& ev) {
}
+void Viewport::_vp_input_text(const String& p_text) {
+
+ if (gui.key_focus) {
+ gui.key_focus->call("set_text",p_text);
+ }
+}
void Viewport::_vp_input(const InputEvent& p_ev) {
+ if (disable_input)
+ return;
+
+#ifdef TOOLS_ENABLED
+ if (get_tree()->is_editor_hint() && get_tree()->get_edited_scene_root()->is_a_parent_of(this)) {
+ return;
+ }
+#endif
+
+ if (parent_control && !parent_control->is_visible())
+ return;
+
if (render_target && to_screen_rect==Rect2())
return; //if render target, can't get input events
//this one handles system input, p_ev are in system coordinates
//they are converted to viewport coordinates
+
InputEvent ev = p_ev;
_make_input_local(ev);
input(ev);
@@ -1164,6 +1303,17 @@ void Viewport::_vp_input(const InputEvent& p_ev) {
void Viewport::_vp_unhandled_input(const InputEvent& p_ev) {
+ if (disable_input)
+ return;
+
+#ifdef TOOLS_ENABLED
+ if (get_tree()->is_editor_hint() && get_tree()->get_edited_scene_root()->is_a_parent_of(this)) {
+ return;
+ }
+#endif
+
+ if (parent_control && !parent_control->is_visible())
+ return;
if (render_target && to_screen_rect==Rect2())
return; //if render target, can't get input events
@@ -1188,17 +1338,850 @@ void Viewport::warp_mouse(const Vector2& p_pos) {
Input::get_singleton()->warp_mouse_pos(gpos);
}
+
+
+void Viewport::_gui_sort_subwindows() {
+
+ if (!gui.subwindow_order_dirty)
+ return;
+
+
+ gui.modal_stack.sort_custom<Control::CComparator>();
+ gui.subwindows.sort_custom<Control::CComparator>();
+
+ gui.subwindow_order_dirty=false;
+}
+
+void Viewport::_gui_sort_modal_stack() {
+
+ gui.modal_stack.sort_custom<Control::CComparator>();
+}
+
+
+void Viewport::_gui_sort_roots() {
+
+ if (!gui.roots_order_dirty)
+ return;
+
+ gui.roots.sort_custom<Control::CComparator>();
+
+ gui.roots_order_dirty=false;
+}
+
+
+void Viewport::_gui_cancel_tooltip() {
+
+ gui.tooltip=NULL;
+ if (gui.tooltip_timer)
+ gui.tooltip_timer->stop();
+ if (gui.tooltip_popup)
+ gui.tooltip_popup->hide();
+
+}
+
+void Viewport::_gui_show_tooltip() {
+
+ if (!gui.tooltip) {
+ return;
+ }
+
+ String tooltip = gui.tooltip->get_tooltip( gui.tooltip->get_global_transform().xform_inv(gui.tooltip_pos) );
+ if (tooltip.length()==0)
+ return; // bye
+
+
+ if (!gui.tooltip_label) {
+ return;
+ }
+ Ref<StyleBox> ttp = gui.tooltip_label->get_stylebox("panel","TooltipPanel");
+
+ gui.tooltip_label->set_anchor_and_margin(MARGIN_LEFT,Control::ANCHOR_BEGIN,ttp->get_margin(MARGIN_LEFT));
+ gui.tooltip_label->set_anchor_and_margin(MARGIN_TOP,Control::ANCHOR_BEGIN,ttp->get_margin(MARGIN_TOP));
+ gui.tooltip_label->set_anchor_and_margin(MARGIN_RIGHT,Control::ANCHOR_END,ttp->get_margin(MARGIN_RIGHT));
+ gui.tooltip_label->set_anchor_and_margin(MARGIN_BOTTOM,Control::ANCHOR_END,ttp->get_margin(MARGIN_BOTTOM));
+ gui.tooltip_label->set_text(tooltip);
+ Rect2 r(gui.tooltip_pos+Point2(10,10),gui.tooltip_label->get_combined_minimum_size()+ttp->get_minimum_size());
+ Rect2 vr = gui.tooltip_label->get_viewport_rect();
+ if (r.size.x+r.pos.x>vr.size.x)
+ r.pos.x=vr.size.x-r.size.x;
+ else if (r.pos.x<0)
+ r.pos.x=0;
+
+ if (r.size.y+r.pos.y>vr.size.y)
+ r.pos.y=vr.size.y-r.size.y;
+ else if (r.pos.y<0)
+ r.pos.y=0;
+
+ gui.tooltip_popup->set_pos(r.pos);
+ gui.tooltip_popup->set_size(r.size);
+
+ gui.tooltip_popup->raise();
+
+ gui.tooltip_popup->show();
+}
+
+
+void Viewport::_gui_call_input(Control *p_control,const InputEvent& p_input) {
+
+// _block();
+
+ while(p_control) {
+
+ p_control->call_multilevel(SceneStringNames::get_singleton()->_input_event,p_input);
+ if (gui.key_event_accepted)
+ break;
+ if (!p_control->is_inside_tree())
+ break;
+ p_control->emit_signal(SceneStringNames::get_singleton()->input_event,p_input);
+ if (!p_control->is_inside_tree() || p_control->is_set_as_toplevel()) {
+ break;
+ }
+ if (gui.key_event_accepted)
+ break;
+ if (p_control->data.stop_mouse && (p_input.type==InputEvent::MOUSE_BUTTON || p_input.type==InputEvent::MOUSE_MOTION))
+ break;
+ p_control=p_control->data.parent;
+ }
+
+ //_unblock();
+
+}
+
+Control* Viewport::_gui_find_control(const Point2& p_global) {
+
+ _gui_sort_subwindows();
+
+ for (List<Control*>::Element *E=gui.subwindows.back();E;E=E->prev()) {
+
+ Control *sw = E->get();
+ if (!sw->is_visible())
+ continue;
+
+ Matrix32 xform;
+ CanvasItem *pci = sw->get_parent_item();
+ if (pci)
+ xform=pci->get_global_transform();
+
+
+ Control *ret = _gui_find_control_at_pos(sw,p_global,xform,gui.focus_inv_xform);
+ if (ret)
+ return ret;
+ }
+
+ for (List<Control*>::Element *E=gui.roots.back();E;E=E->prev()) {
+
+ Control *sw = E->get();
+ if (!sw->is_visible())
+ continue;
+
+ Matrix32 xform;
+ CanvasItem *pci = sw->get_parent_item();
+ if (pci)
+ xform=pci->get_global_transform();
+
+
+ Control *ret = _gui_find_control_at_pos(sw,p_global,xform,gui.focus_inv_xform);
+ if (ret)
+ return ret;
+ }
+
+ return NULL;
+
+}
+
+
+Control* Viewport::_gui_find_control_at_pos(CanvasItem* p_node,const Point2& p_global,const Matrix32& p_xform,Matrix32& r_inv_xform) {
+
+ if (p_node->cast_to<Viewport>())
+ return NULL;
+
+ Control *c=p_node->cast_to<Control>();
+
+ if (c) {
+ // print_line("at "+String(c->get_path())+" POS "+c->get_pos()+" bt "+p_xform);
+ }
+
+ //subwindows first!!
+
+ if (p_node->is_hidden()) {
+ //return _find_next_visible_control_at_pos(p_node,p_global,r_inv_xform);
+ return NULL; //canvas item hidden, discard
+ }
+
+ Matrix32 matrix = p_xform * p_node->get_transform();
+
+ if (!c || !c->clips_input() || c->has_point(matrix.affine_inverse().xform(p_global))) {
+
+ for(int i=p_node->get_child_count()-1;i>=0;i--) {
+
+ if (p_node==gui.tooltip_popup)
+ continue;
+
+ CanvasItem *ci = p_node->get_child(i)->cast_to<CanvasItem>();
+ if (!ci || ci->is_set_as_toplevel())
+ continue;
+
+ Control *ret=_gui_find_control_at_pos(ci,p_global,matrix,r_inv_xform);;
+ if (ret)
+ return ret;
+ }
+ }
+
+ if (!c)
+ return NULL;
+
+ matrix.affine_invert();
+
+ //conditions for considering this as a valid control for return
+ if (!c->data.ignore_mouse && c->has_point(matrix.xform(p_global)) && (!gui.drag_preview || (c!=gui.drag_preview && !gui.drag_preview->is_a_parent_of(c)))) {
+ r_inv_xform=matrix;
+ return c;
+ } else
+ return NULL;
+}
+
+void Viewport::_gui_input_event(InputEvent p_event) {
+
+
+
+ if (p_event.ID==gui.cancelled_input_ID) {
+ return;
+ }
+ //?
+// if (!is_visible()) {
+// return; //simple and plain
+// }
+
+
+ switch(p_event.type) {
+
+ case InputEvent::MOUSE_BUTTON: {
+
+
+ gui.key_event_accepted=false;
+
+ Point2 mpos=Point2(p_event.mouse_button.x,p_event.mouse_button.y);
+ if (p_event.mouse_button.pressed) {
+
+
+
+ Size2 pos = mpos;
+ if (gui.mouse_focus && p_event.mouse_button.button_index!=gui.mouse_focus_button) {
+
+ //do not steal mouse focus and stuff
+
+ } else {
+
+
+ _gui_sort_modal_stack();
+ while (!gui.modal_stack.empty()) {
+
+ Control *top = gui.modal_stack.back()->get();
+ Vector2 pos = top->get_global_transform_with_canvas().affine_inverse().xform(mpos);
+ if (!top->has_point(pos)) {
+
+ if (top->data.modal_exclusive) {
+ //cancel event, sorry, modal exclusive EATS UP ALL
+ //get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID);
+ get_tree()->set_input_as_handled();
+ return; // no one gets the event if exclusive NO ONE
+ }
+
+ top->notification(Control::NOTIFICATION_MODAL_CLOSE);
+ top->_modal_stack_remove();
+ top->hide();
+ } else {
+ break;
+ }
+ }
+
+
+
+ Matrix32 parent_xform;
+
+ //if (data.parent_canvas_item)
+ // parent_xform=data.parent_canvas_item->get_global_transform();
+
+
+
+ gui.mouse_focus = _gui_find_control(pos);
+ //print_line("has mf "+itos(gui.mouse_focus!=NULL));
+ gui.mouse_focus_button=p_event.mouse_button.button_index;
+
+ if (!gui.mouse_focus) {
+ break;
+ }
+
+ if (p_event.mouse_button.button_index==BUTTON_LEFT) {
+ gui.drag_accum=Vector2();
+ gui.drag_attempted=false;
+ gui.drag_data=Variant();
+ }
+
+
+ }
+
+ p_event.mouse_button.global_x = pos.x;
+ p_event.mouse_button.global_y = pos.y;
+
+ pos = gui.focus_inv_xform.xform(pos);
+ p_event.mouse_button.x = pos.x;
+ p_event.mouse_button.y = pos.y;
+
+#ifdef DEBUG_ENABLED
+ if (ScriptDebugger::get_singleton()) {
+
+ Array arr;
+ arr.push_back(gui.mouse_focus->get_path());
+ arr.push_back(gui.mouse_focus->get_type());
+ ScriptDebugger::get_singleton()->send_message("click_ctrl",arr);
+ }
+
+ /*if (bool(GLOBAL_DEF("debug/print_clicked_control",false))) {
+
+ print_line(String(gui.mouse_focus->get_path())+" - "+pos);
+ }*/
+#endif
+
+ if (gui.mouse_focus->get_focus_mode()!=Control::FOCUS_NONE && gui.mouse_focus!=gui.key_focus && p_event.mouse_button.button_index==BUTTON_LEFT) {
+ // also get keyboard focus
+ gui.mouse_focus->grab_focus();
+ }
+
+
+ if (gui.mouse_focus->can_process()) {
+ _gui_call_input(gui.mouse_focus,p_event);
+ }
+
+ get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID);
+ get_tree()->set_input_as_handled();
+
+ gui.tooltip_popup->hide();
+
+ } else {
+
+ if (gui.drag_preview && p_event.mouse_button.button_index==BUTTON_LEFT) {
+ memdelete( gui.drag_preview );
+ gui.drag_preview=NULL;
+ }
+
+ if (!gui.mouse_focus) {
+
+ if (gui.mouse_over && gui.drag_data.get_type()!=Variant::NIL && p_event.mouse_button.button_index==BUTTON_LEFT) {
+
+ Size2 pos = mpos;
+ pos = gui.focus_inv_xform.xform(pos);
+
+ gui.mouse_over->drop_data(pos,gui.drag_data);
+ gui.drag_data=Variant();
+ //change mouse accordingly
+ }
+
+ break;
+ }
+
+ Size2 pos = mpos;
+ p_event.mouse_button.global_x = pos.x;
+ p_event.mouse_button.global_y = pos.y;
+ pos = gui.focus_inv_xform.xform(pos);
+ p_event.mouse_button.x = pos.x;
+ p_event.mouse_button.y = pos.y;
+
+ if (gui.mouse_focus->can_process()) {
+ _gui_call_input(gui.mouse_focus,p_event);
+ }
+
+ if (p_event.mouse_button.button_index==gui.mouse_focus_button) {
+ gui.mouse_focus=NULL;
+ gui.mouse_focus_button=-1;
+ }
+
+ if (gui.drag_data.get_type()!=Variant::NIL && p_event.mouse_button.button_index==BUTTON_LEFT) {
+ gui.drag_data=Variant(); //always clear
+ }
+
+
+ get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID);
+ get_tree()->set_input_as_handled();
+
+ }
+ } break;
+ case InputEvent::MOUSE_MOTION: {
+
+ gui.key_event_accepted=false;
+ Point2 mpos=Point2(p_event.mouse_motion.x,p_event.mouse_motion.y);
+
+ gui.last_mouse_pos=mpos;
+
+ Control *over = NULL;
+
+
+ // D&D
+ if (!gui.drag_attempted && gui.mouse_focus && p_event.mouse_motion.button_mask&BUTTON_MASK_LEFT) {
+
+ gui.drag_accum+=Point2(p_event.mouse_motion.relative_x,p_event.mouse_motion.relative_y);;
+ float len = gui.drag_accum.length();
+ if (len>10) {
+ gui.drag_data=gui.mouse_focus->get_drag_data(gui.focus_inv_xform.xform(mpos)-gui.drag_accum);
+ if (gui.drag_data.get_type()!=Variant::NIL) {
+
+ gui.mouse_focus=NULL;
+ }
+ gui.drag_attempted=true;
+ }
+ }
+
+
+ if (gui.mouse_focus) {
+ over=gui.mouse_focus;
+ //recompute focus_inv_xform again here
+
+ } else {
+
+ over = _gui_find_control(mpos);
+ }
+
+
+ if (gui.drag_data.get_type()==Variant::NIL && over && !gui.modal_stack.empty()) {
+
+ Control *top = gui.modal_stack.back()->get();
+ if (over!=top && !top->is_a_parent_of(over)) {
+
+ break; // don't send motion event to anything below modal stack top
+ }
+ }
+
+ if (over!=gui.mouse_over) {
+
+ if (gui.mouse_over)
+ gui.mouse_over->notification(Control::NOTIFICATION_MOUSE_EXIT);
+
+ if (over)
+ over->notification(Control::NOTIFICATION_MOUSE_ENTER);
+
+ }
+
+ gui.mouse_over=over;
+
+ _gui_cancel_tooltip();
+
+ if (gui.drag_preview) {
+ gui.drag_preview->set_pos(mpos);
+ }
+
+ if (!over) {
+ OS::get_singleton()->set_cursor_shape(OS::CURSOR_ARROW);
+ break;
+ }
+
+
+ Matrix32 localizer = over->get_canvas_transform().affine_inverse();
+ Size2 pos = localizer.xform(mpos);
+ Vector2 speed = localizer.basis_xform(Point2(p_event.mouse_motion.speed_x,p_event.mouse_motion.speed_y));
+ Vector2 rel = localizer.basis_xform(Point2(p_event.mouse_motion.relative_x,p_event.mouse_motion.relative_y));
+
+
+ p_event.mouse_motion.global_x = mpos.x;
+ p_event.mouse_motion.global_y = mpos.y;
+ p_event.mouse_motion.speed_x=speed.x;
+ p_event.mouse_motion.speed_y=speed.y;
+ p_event.mouse_motion.relative_x=rel.x;
+ p_event.mouse_motion.relative_y=rel.y;
+
+ if (p_event.mouse_motion.button_mask==0 && gui.tooltip_timer) {
+ //nothing pressed
+
+ bool can_tooltip=true;
+
+ if (!gui.modal_stack.empty()) {
+ if (gui.modal_stack.back()->get()!=over && !gui.modal_stack.back()->get()->is_a_parent_of(over))
+ can_tooltip=false;
+
+ }
+
+
+ if (can_tooltip) {
+
+ gui.tooltip=over;
+ gui.tooltip_pos=mpos;//(parent_xform * get_transform()).affine_inverse().xform(pos);
+ gui.tooltip_timer->start();
+ }
+ }
+
+
+ pos = gui.focus_inv_xform.xform(pos);
+
+
+ p_event.mouse_motion.x = pos.x;
+ p_event.mouse_motion.y = pos.y;
+
+
+ Control::CursorShape cursor_shape = over->get_cursor_shape(pos);
+ OS::get_singleton()->set_cursor_shape( (OS::CursorShape)cursor_shape );
+
+
+ if (over->can_process()) {
+ _gui_call_input(over,p_event);
+ }
+
+
+
+ //get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID);
+ get_tree()->set_input_as_handled();
+
+
+ if (gui.drag_data.get_type()!=Variant::NIL && p_event.mouse_motion.button_mask&BUTTON_MASK_LEFT) {
+
+ /*bool can_drop =*/ over->can_drop_data(pos,gui.drag_data);
+ //change mouse accordingly i guess
+ }
+
+ } break;
+ case InputEvent::ACTION:
+ case InputEvent::JOYSTICK_BUTTON:
+ case InputEvent::KEY: {
+
+ if (gui.key_focus) {
+
+ gui.key_event_accepted=false;
+ if (gui.key_focus->can_process()) {
+ gui.key_focus->call_multilevel("_input_event",p_event);
+ if (gui.key_focus) //maybe lost it
+ gui.key_focus->emit_signal(SceneStringNames::get_singleton()->input_event,p_event);
+ }
+
+
+ if (gui.key_event_accepted) {
+
+ get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID);
+ break;
+ }
+ }
+
+
+ if (p_event.is_pressed() && p_event.is_action("ui_cancel") && !gui.modal_stack.empty()) {
+
+ _gui_sort_modal_stack();
+ Control *top = gui.modal_stack.back()->get();
+ if (!top->data.modal_exclusive) {
+
+ top->notification(Control::NOTIFICATION_MODAL_CLOSE);
+ top->_modal_stack_remove();
+ top->hide();
+ }
+ }
+
+
+ Control * from = gui.key_focus ? gui.key_focus : NULL; //hmm
+
+ //keyboard focus
+ //if (from && p_event.key.pressed && !p_event.key.mod.alt && !p_event.key.mod.meta && !p_event.key.mod.command) {
+
+ if (from && p_event.is_pressed()) {
+ Control * next=NULL;
+
+ if (p_event.is_action("ui_focus_next")) {
+
+ next = from->find_next_valid_focus();
+ }
+
+ if (p_event.is_action("ui_focus_prev")) {
+
+ next = from->find_prev_valid_focus();
+ }
+
+ if (p_event.is_action("ui_up")) {
+
+ next = from->_get_focus_neighbour(MARGIN_TOP);
+ }
+
+ if (p_event.is_action("ui_left")) {
+
+ next = from->_get_focus_neighbour(MARGIN_LEFT);
+ }
+
+ if (p_event.is_action("ui_right")) {
+
+ next = from->_get_focus_neighbour(MARGIN_RIGHT);
+ }
+
+ if (p_event.is_action("ui_down")) {
+
+ next = from->_get_focus_neighbour(MARGIN_BOTTOM);
+ }
+
+
+ if (next) {
+ next->grab_focus();
+ get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID);
+ }
+ }
+
+ } break;
+ }
+}
+
+
+List<Control*>::Element* Viewport::_gui_add_root_control(Control* p_control) {
+
+ gui.roots_order_dirty=true;
+ return gui.roots.push_back(p_control);
+}
+
+List<Control*>::Element* Viewport::_gui_add_subwindow_control(Control* p_control) {
+
+ gui.subwindow_order_dirty=true;
+ return gui.subwindows.push_back(p_control);
+
+}
+
+void Viewport::_gui_set_subwindow_order_dirty() {
+ gui.subwindow_order_dirty=true;
+}
+
+void Viewport::_gui_set_root_order_dirty() {
+ gui.roots_order_dirty=true;
+}
+
+void Viewport::_gui_remove_modal_control(List<Control*>::Element *MI) {
+
+ gui.modal_stack.erase(MI);
+}
+
+void Viewport::_gui_remove_from_modal_stack(List<Control*>::Element *MI,ObjectID p_prev_focus_owner) {
+
+ //transfer the focus stack to the next
+
+ List<Control*>::Element *next = MI->next();
+
+ gui.modal_stack.erase(MI);
+ MI=NULL;
+
+ if (p_prev_focus_owner) {
+
+ // for previous window in stack, pass the focus so it feels more
+ // natural
+
+ if (!next) { //top of stack
+
+ Object *pfo = ObjectDB::get_instance(p_prev_focus_owner);
+ Control *pfoc = pfo->cast_to<Control>();
+ if (!pfoc)
+ return;
+
+ if (!pfoc->is_inside_tree() || !pfoc->is_visible())
+ return;
+ pfoc->grab_focus();
+ } else {
+
+ next->get()->_modal_set_prev_focus_owner(p_prev_focus_owner);
+ }
+ }
+}
+
+void Viewport::_gui_force_drag(const Variant& p_data,Control *p_control) {
+
+ gui.drag_data=p_data;
+ gui.mouse_focus=NULL;
+
+ if (p_control) {
+ _gui_set_drag_preview(p_control);
+ }
+}
+
+void Viewport::_gui_set_drag_preview(Control *p_control) {
+
+ ERR_FAIL_NULL(p_control);
+ ERR_FAIL_COND( !((Object*)p_control)->cast_to<Control>());
+ ERR_FAIL_COND(p_control->is_inside_tree());
+ ERR_FAIL_COND(p_control->get_parent()!=NULL);
+
+ if (gui.drag_preview) {
+ memdelete(gui.drag_preview);
+ }
+ p_control->set_as_toplevel(true);
+ p_control->set_pos(gui.last_mouse_pos);
+ add_child(p_control); //add as child of viewport
+ p_control->raise();
+ if (gui.drag_preview) {
+ memdelete( gui.drag_preview );
+ }
+ gui.drag_preview=p_control;
+}
+
+
+void Viewport::_gui_remove_root_control(List<Control*>::Element *RI) {
+
+ gui.roots.erase(RI);
+}
+
+void Viewport::_gui_remove_subwindow_control(List<Control*>::Element* SI){
+
+ gui.subwindows.erase(SI);
+}
+
+void Viewport::_gui_unfocus_control(Control *p_control) {
+
+ if (gui.key_focus==p_control) {
+ gui.key_focus->release_focus();
+ }
+}
+
+void Viewport::_gui_hid_control(Control *p_control) {
+
+ if (gui.mouse_focus == p_control) {
+ gui.mouse_focus=NULL;
+ }
+
+ /* ???
+ if (data.window==p_control) {
+ window->drag_data=Variant();
+ if (window->drag_preview) {
+ memdelete( window->drag_preview);
+ window->drag_preview=NULL;
+ }
+ }
+ */
+
+ if (gui.key_focus == p_control)
+ gui.key_focus=NULL;
+ if (gui.mouse_over == p_control)
+ gui.mouse_over=NULL;
+ if (gui.tooltip == p_control)
+ gui.tooltip=NULL;
+ if (gui.tooltip == p_control)
+ gui.tooltip=NULL;
+
+}
+
+void Viewport::_gui_remove_control(Control *p_control) {
+
+
+ if (gui.mouse_focus == p_control)
+ gui.mouse_focus=NULL;
+ if (gui.key_focus == p_control)
+ gui.key_focus=NULL;
+ if (gui.mouse_over == p_control)
+ gui.mouse_over=NULL;
+ if (gui.tooltip == p_control)
+ gui.tooltip=NULL;
+
+
+}
+
+void Viewport::_gui_remove_focus() {
+
+ if (gui.key_focus) {
+ Node *f=gui.key_focus;
+ gui.key_focus=NULL;
+ f->notification( Control::NOTIFICATION_FOCUS_EXIT,true );
+
+
+ }
+}
+
+bool Viewport::_gui_is_modal_on_top(const Control* p_control) {
+
+ return (gui.modal_stack.size() && gui.modal_stack.back()->get()==p_control);
+
+}
+
+bool Viewport::_gui_control_has_focus(const Control* p_control) {
+
+ return gui.key_focus==p_control;
+}
+
+void Viewport::_gui_control_grab_focus(Control* p_control) {
+
+
+ //no need for change
+ if (gui.key_focus && gui.key_focus==p_control)
+ return;
+
+ _gui_remove_focus();
+ get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_gui_remove_focus");
+ gui.key_focus=p_control;
+ p_control->notification(Control::NOTIFICATION_FOCUS_ENTER);
+ p_control->update();
+
+}
+
+void Viewport::_gui_accept_event() {
+
+ gui.key_event_accepted=true;
+ if (is_inside_tree())
+ get_tree()->set_input_as_handled();
+}
+
+
+List<Control*>::Element* Viewport::_gui_show_modal(Control* p_control) {
+
+ gui.modal_stack.push_back(p_control);
+ if (gui.key_focus)
+ p_control->_modal_set_prev_focus_owner(gui.key_focus->get_instance_ID());
+ else
+ p_control->_modal_set_prev_focus_owner(0);
+
+ return gui.modal_stack.back();
+}
+
+Control *Viewport::_gui_get_focus_owner() {
+
+ return gui.key_focus;
+}
+
+void Viewport::_gui_grab_click_focus(Control *p_control) {
+
+ if (gui.mouse_focus) {
+
+
+ if (gui.mouse_focus==p_control)
+ return;
+ InputEvent ie;
+ ie.type=InputEvent::MOUSE_BUTTON;
+ InputEventMouseButton &mb=ie.mouse_button;
+
+ //send unclic
+
+ Point2 click =gui.mouse_focus->get_global_transform().affine_inverse().xform(gui.last_mouse_pos);
+ mb.x=click.x;
+ mb.y=click.y;
+ mb.button_index=gui.mouse_focus_button;
+ mb.pressed=false;
+ gui.mouse_focus->call_deferred("_input_event",ie);
+
+
+ gui.mouse_focus=p_control;
+ gui.focus_inv_xform=gui.mouse_focus->get_global_transform().affine_inverse();
+ click =gui.mouse_focus->get_global_transform().affine_inverse().xform(gui.last_mouse_pos);
+ mb.x=click.x;
+ mb.y=click.y;
+ mb.button_index=gui.mouse_focus_button;
+ mb.pressed=true;
+ gui.mouse_focus->call_deferred("_input_event",ie);
+
+ }
+}
+
+
+///////////////////////////////
+
+
void Viewport::input(const InputEvent& p_event) {
ERR_FAIL_COND(!is_inside_tree());
- get_tree()->_call_input_pause(input_group,"_input",p_event);
- get_tree()->call_group(SceneTree::GROUP_CALL_REVERSE|SceneTree::GROUP_CALL_REALTIME|SceneTree::GROUP_CALL_MULIILEVEL,gui_input_group,"_gui_input",p_event); //special one for GUI, as controls use their own process check
+
+
+ get_tree()->_call_input_pause(input_group,"_input",p_event);
+ _gui_input_event(p_event);
+ //get_tree()->call_group(SceneTree::GROUP_CALL_REVERSE|SceneTree::GROUP_CALL_REALTIME|SceneTree::GROUP_CALL_MULIILEVEL,gui_input_group,"_gui_input",p_event); //special one for GUI, as controls use their own process check
}
void Viewport::unhandled_input(const InputEvent& p_event) {
ERR_FAIL_COND(!is_inside_tree());
+
get_tree()->_call_input_pause(unhandled_input_group,"_unhandled_input",p_event);
//call_group(GROUP_CALL_REVERSE|GROUP_CALL_REALTIME|GROUP_CALL_MULIILEVEL,"unhandled_input","_unhandled_input",ev);
if (!get_tree()->input_handled && p_event.type==InputEvent::KEY) {
@@ -1301,6 +2284,19 @@ bool Viewport::get_physics_object_picking() {
return physics_object_picking;
}
+bool Viewport::gui_has_modal_stack() const {
+
+ return gui.modal_stack.size();
+}
+
+void Viewport::set_disable_input(bool p_disable) {
+ disable_input=p_disable;
+}
+
+bool Viewport::is_input_disabled() const {
+
+ return disable_input;
+}
void Viewport::_bind_methods() {
@@ -1329,6 +2325,7 @@ void Viewport::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_parent_resized"), &Viewport::_parent_resized);
ObjectTypeDB::bind_method(_MD("_vp_input"), &Viewport::_vp_input);
+ ObjectTypeDB::bind_method(_MD("_vp_input_text","text"), &Viewport::_vp_input_text);
ObjectTypeDB::bind_method(_MD("_vp_unhandled_input"), &Viewport::_vp_unhandled_input);
ObjectTypeDB::bind_method(_MD("set_size_override","enable","size","margin"), &Viewport::set_size_override,DEFVAL(Size2(-1,-1)),DEFVAL(Size2(0,0)));
@@ -1380,11 +2377,18 @@ void Viewport::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_as_audio_listener_2d","enable"), &Viewport::set_as_audio_listener_2d);
ObjectTypeDB::bind_method(_MD("is_audio_listener_2d","enable"), &Viewport::is_audio_listener_2d);
- ObjectTypeDB::bind_method(_MD("set_render_target_to_screen_rect"), &Viewport::set_render_target_to_screen_rect);
+ ObjectTypeDB::bind_method(_MD("set_render_target_to_screen_rect","rect"), &Viewport::set_render_target_to_screen_rect);
ObjectTypeDB::bind_method(_MD("get_mouse_pos"), &Viewport::get_mouse_pos);
ObjectTypeDB::bind_method(_MD("warp_mouse","to_pos"), &Viewport::warp_mouse);
+ ObjectTypeDB::bind_method(_MD("gui_has_modal_stack"), &Viewport::gui_has_modal_stack);
+
+ ObjectTypeDB::bind_method(_MD("set_disable_input","disable"), &Viewport::set_disable_input);
+ ObjectTypeDB::bind_method(_MD("is_input_disabled"), &Viewport::is_input_disabled);
+
+ ObjectTypeDB::bind_method(_MD("_gui_show_tooltip"), &Viewport::_gui_show_tooltip);
+
ADD_PROPERTY( PropertyInfo(Variant::RECT2,"rect"), _SCS("set_rect"), _SCS("get_rect") );
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"own_world"), _SCS("set_use_own_world"), _SCS("is_using_own_world") );
ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"world",PROPERTY_HINT_RESOURCE_TYPE,"World"), _SCS("set_world"), _SCS("get_world") );
@@ -1399,6 +2403,7 @@ void Viewport::_bind_methods() {
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"audio_listener/enable_2d"), _SCS("set_as_audio_listener_2d"), _SCS("is_audio_listener_2d") );
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"audio_listener/enable_3d"), _SCS("set_as_audio_listener"), _SCS("is_audio_listener") );
ADD_PROPERTY( PropertyInfo(Variant::BOOL,"physics/object_picking"), _SCS("set_physics_object_picking"), _SCS("get_physics_object_picking") );
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"gui/disable_input"), _SCS("set_disable_input"), _SCS("is_input_disabled") );
ADD_SIGNAL(MethodInfo("size_changed"));
@@ -1415,6 +2420,7 @@ void Viewport::_bind_methods() {
Viewport::Viewport() {
+
world_2d = Ref<World2D>( memnew( World2D ));
viewport = VisualServer::get_singleton()->viewport_create();
@@ -1448,6 +2454,27 @@ Viewport::Viewport() {
unhandled_input_group = "_vp_unhandled_input"+id;
unhandled_key_input_group = "_vp_unhandled_key_input"+id;
+ disable_input=false;
+
+ //window tooltip
+ gui.tooltip_timer = memnew( Timer );
+ add_child(gui.tooltip_timer);
+ gui.tooltip_timer->force_parent_owned();
+ gui.tooltip_timer->set_wait_time( GLOBAL_DEF("display/tooltip_delay",0.7));
+ gui.tooltip_timer->connect("timeout",this,"_gui_show_tooltip");
+ gui.tooltip=NULL;
+ gui.tooltip_popup = memnew( TooltipPanel );
+ add_child(gui.tooltip_popup);
+ gui.tooltip_popup->force_parent_owned();
+ gui.tooltip_label = memnew( TooltipLabel );
+ gui.tooltip_popup->add_child(gui.tooltip_label);
+ gui.tooltip_popup->set_as_toplevel(true);
+ gui.tooltip_popup->hide();
+ gui.drag_attempted=false;
+ gui.drag_preview=NULL;
+
+ parent_control=NULL;
+
}
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index c3c339ac5d..50e1f0e0f0 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -39,6 +39,11 @@
*/
class Camera;
+class Control;
+class CanvasItem;
+class Panel;
+class Label;
+class Timer;
class Viewport;
class RenderTargetTexture : public Texture {
@@ -82,6 +87,9 @@ public:
private:
friend class RenderTargetTexture;
+
+
+ Control *parent_control;
Viewport *parent;
Camera *camera;
@@ -104,6 +112,11 @@ friend class RenderTargetTexture;
Rect2 rect;
Rect2 to_screen_rect;
+ RID contact_2d_debug;
+ RID contact_3d_debug_multimesh;
+ RID contact_3d_debug_instance;
+
+
bool size_override;
bool size_override_stretch;
@@ -157,6 +170,48 @@ friend class RenderTargetTexture;
Ref<RenderTargetTexture> render_target_texture;
+ struct GUI {
+ // info used when this is a window
+
+ bool key_event_accepted;
+ Control *mouse_focus;
+ int mouse_focus_button;
+ Control *key_focus;
+ Control *mouse_over;
+ Control *tooltip;
+ Panel *tooltip_popup;
+ Label *tooltip_label;
+ Point2 tooltip_pos;
+ Point2 last_mouse_pos;
+ Point2 drag_accum;
+ bool drag_attempted;
+ Variant drag_data;
+ Control *drag_preview;
+ Timer *tooltip_timer;
+ List<Control*> modal_stack;
+ unsigned int cancelled_input_ID;
+ Matrix32 focus_inv_xform;
+ bool subwindow_order_dirty;
+ List<Control*> subwindows;
+ bool roots_order_dirty;
+ List<Control*> roots;
+
+
+ GUI();
+ } gui;
+
+ bool disable_input;
+
+ void _gui_call_input(Control *p_control,const InputEvent& p_input);
+ void _gui_sort_subwindows();
+ void _gui_sort_roots();
+ void _gui_sort_modal_stack();
+ Control* _gui_find_control(const Point2& p_global);
+ Control* _gui_find_control_at_pos(CanvasItem* p_node,const Point2& p_global,const Matrix32& p_xform,Matrix32& r_inv_xform);
+
+ void _gui_input_event(InputEvent p_event);
+
+
void update_worlds();
_FORCE_INLINE_ Matrix32 _get_input_pre_xform() const;
@@ -165,9 +220,47 @@ friend class RenderTargetTexture;
void _vp_exit_tree();
void _vp_input(const InputEvent& p_ev);
+ void _vp_input_text(const String& p_text);
void _vp_unhandled_input(const InputEvent& p_ev);
void _make_input_local(InputEvent& ev);
+
+friend class Control;
+
+ List<Control*>::Element* _gui_add_root_control(Control* p_control);
+ List<Control*>::Element* _gui_add_subwindow_control(Control* p_control);
+
+ void _gui_set_subwindow_order_dirty();
+ void _gui_set_root_order_dirty();
+
+
+ void _gui_remove_modal_control(List<Control*>::Element *MI);
+ void _gui_remove_from_modal_stack(List<Control*>::Element *MI,ObjectID p_prev_focus_owner);
+ void _gui_remove_root_control(List<Control*>::Element *RI);
+ void _gui_remove_subwindow_control(List<Control*>::Element* SI);
+
+ void _gui_cancel_tooltip();
+ void _gui_show_tooltip();
+
+
+ void _gui_remove_control(Control *p_control);
+ void _gui_hid_control(Control *p_control);
+
+ void _gui_force_drag(const Variant& p_data,Control *p_control);
+ void _gui_set_drag_preview(Control *p_control);
+
+ bool _gui_is_modal_on_top(const Control* p_control);
+ List<Control*>::Element* _gui_show_modal(Control* p_control);
+
+ void _gui_remove_focus();
+ void _gui_unfocus_control(Control *p_control);
+ bool _gui_control_has_focus(const Control* p_control);
+ void _gui_control_grab_focus(Control* p_control);
+ void _gui_grab_click_focus(Control *p_control);
+ void _gui_accept_event();
+
+ Control *_gui_get_focus_owner();
+
friend class Camera;
void _camera_transform_changed_notify();
void _set_camera(Camera* p_camera);
@@ -249,6 +342,9 @@ public:
void input(const InputEvent& p_event);
void unhandled_input(const InputEvent& p_event);
+ void set_disable_input(bool p_disable);
+ bool is_input_disabled() const;
+
void set_render_target_to_screen_rect(const Rect2& p_rect);
Rect2 get_render_target_to_screen_rect() const;
@@ -258,6 +354,9 @@ public:
void set_physics_object_picking(bool p_enable);
bool get_physics_object_picking();
+ bool gui_has_modal_stack() const;
+
+
Viewport();
~Viewport();
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 717ed93b16..6c4fe1be79 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -36,6 +36,7 @@
#include "resources/default_theme/default_theme.h"
#include "object_type_db.h"
#include "scene/main/canvas_layer.h"
+#include "scene/main/instance_placeholder.h"
#include "scene/main/viewport.h"
#include "scene/gui/control.h"
#include "scene/gui/texture_progress.h"
@@ -52,6 +53,7 @@
#include "scene/gui/option_button.h"
#include "scene/gui/color_picker.h"
#include "scene/gui/texture_frame.h"
+#include "scene/gui/patch_9_frame.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/check_box.h"
#include "scene/gui/check_button.h"
@@ -215,11 +217,11 @@
#include "scene/3d/collision_polygon.h"
#endif
-
+#include "scene/resources/scene_format_text.h"
static ResourceFormatLoaderImage *resource_loader_image=NULL;
static ResourceFormatLoaderWAV *resource_loader_wav=NULL;
-static ResourceFormatLoaderBitMap *resource_loader_bitmap=NULL;
+
#ifdef TOOLS_ENABLED
@@ -228,6 +230,9 @@ static ResourceFormatLoaderBitMap *resource_loader_bitmap=NULL;
static ResourceFormatLoaderTheme *resource_loader_theme=NULL;
static ResourceFormatLoaderShader *resource_loader_shader=NULL;
+static ResourceFormatSaverText *resource_saver_text=NULL;
+static ResourceFormatLoaderText *resource_loader_text=NULL;
+
//static SceneStringNames *string_names;
void register_scene_types() {
@@ -244,8 +249,6 @@ void register_scene_types() {
resource_loader_wav = memnew( ResourceFormatLoaderWAV );
ResourceLoader::add_resource_format_loader( resource_loader_wav );
- resource_loader_bitmap = memnew( ResourceFormatLoaderBitMap );
- ResourceLoader::add_resource_format_loader( resource_loader_bitmap );
#ifdef TOOLS_ENABLED
@@ -266,6 +269,7 @@ void register_scene_types() {
ObjectTypeDB::register_type<Object>();
ObjectTypeDB::register_type<Node>();
+ ObjectTypeDB::register_virtual_type<InstancePlaceholder>();
ObjectTypeDB::register_type<Viewport>();
ObjectTypeDB::register_virtual_type<RenderTargetTexture>();
@@ -302,6 +306,7 @@ void register_scene_types() {
OS::get_singleton()->yield(); //may take time to init
ObjectTypeDB::register_type<TextureFrame>();
+ ObjectTypeDB::register_type<Patch9Frame>();
ObjectTypeDB::register_type<TabContainer>();
ObjectTypeDB::register_type<Tabs>();
ObjectTypeDB::register_virtual_type<Separator>();
@@ -456,7 +461,6 @@ void register_scene_types() {
/* disable types by default, only editors should enable them */
- ObjectTypeDB::set_type_enabled("CollisionShape",false);
//ObjectTypeDB::set_type_enabled("BodyVolumeSphere",false);
//ObjectTypeDB::set_type_enabled("BodyVolumeBox",false);
//ObjectTypeDB::set_type_enabled("BodyVolumeCapsule",false);
@@ -490,9 +494,12 @@ void register_scene_types() {
ObjectTypeDB::register_type<OccluderPolygon2D>();
ObjectTypeDB::register_type<YSort>();
ObjectTypeDB::register_type<BackBufferCopy>();
-
- ObjectTypeDB::set_type_enabled("CollisionShape2D",false);
- ObjectTypeDB::set_type_enabled("CollisionPolygon2D",false);
+ if (bool(GLOBAL_DEF("physics/remove_collision_helpers_at_runtime",false))) {
+ ObjectTypeDB::set_type_enabled("CollisionShape2D",false);
+ ObjectTypeDB::set_type_enabled("CollisionPolygon2D",false);
+ ObjectTypeDB::set_type_enabled("CollisionShape",false);
+ ObjectTypeDB::set_type_enabled("CollisionPolygon",false);
+ }
OS::get_singleton()->yield(); //may take time to init
@@ -576,7 +583,8 @@ void register_scene_types() {
ObjectTypeDB::register_type<Sample>();
ObjectTypeDB::register_type<SampleLibrary>();
ObjectTypeDB::register_virtual_type<AudioStream>();
- ObjectTypeDB::register_type<AudioStreamGibberish>();
+ ObjectTypeDB::register_virtual_type<AudioStreamPlayback>();
+// ObjectTypeDB::register_type<AudioStreamGibberish>();
ObjectTypeDB::register_virtual_type<VideoStream>();
OS::get_singleton()->yield(); //may take time to init
@@ -607,6 +615,12 @@ void register_scene_types() {
OS::get_singleton()->yield(); //may take time to init
+ resource_saver_text = memnew( ResourceFormatSaverText );
+ ResourceSaver::add_resource_format_saver(resource_saver_text);
+
+ resource_loader_text = memnew( ResourceFormatLoaderText );
+ ResourceLoader::add_resource_format_loader(resource_loader_text);
+
}
void unregister_scene_types() {
@@ -615,7 +629,6 @@ void unregister_scene_types() {
memdelete( resource_loader_image );
memdelete( resource_loader_wav );
- memdelete( resource_loader_bitmap );
#ifdef TOOLS_ENABLED
@@ -624,5 +637,12 @@ void unregister_scene_types() {
memdelete( resource_loader_theme );
memdelete( resource_loader_shader );
+
+ if (resource_saver_text) {
+ memdelete(resource_saver_text);
+ }
+ if (resource_loader_text) {
+ memdelete(resource_loader_text);
+ }
SceneStringNames::free();
}
diff --git a/scene/register_scene_types.h b/scene/register_scene_types.h
index 7d36dbc101..15e1eb2980 100644
--- a/scene/register_scene_types.h
+++ b/scene/register_scene_types.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/SCsub b/scene/resources/SCsub
index eaa282ae1a..bb9766e1ca 100644
--- a/scene/resources/SCsub
+++ b/scene/resources/SCsub
@@ -6,4 +6,3 @@ env.add_source_files(env.scene_sources,"*.c")
Export('env')
SConscript("default_theme/SCsub");
-
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 095406dad9..e8bd6c14ad 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -42,8 +42,8 @@ bool Animation::_set(const StringName& p_name, const Variant& p_value) {
set_step(p_value);
else if (name.begins_with("tracks/")) {
- int track=name.get_slice("/",1).to_int();
- String what=name.get_slice("/",2);
+ int track=name.get_slicec('/',1).to_int();
+ String what=name.get_slicec('/',2);
if (tracks.size()==track && what=="type") {
@@ -257,8 +257,8 @@ bool Animation::_get(const StringName& p_name,Variant &r_ret) const {
r_ret= step;
else if (name.begins_with("tracks/")) {
- int track=name.get_slice("/",1).to_int();
- String what=name.get_slice("/",2);
+ int track=name.get_slicec('/',1).to_int();
+ String what=name.get_slicec('/',2);
ERR_FAIL_INDEX_V( track, tracks.size(), false );
if (what=="type") {
@@ -1718,7 +1718,7 @@ void Animation::clear() {
-bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0,const TKey<TransformKey> &t1, const TKey<TransformKey> &t2, float p_alowed_linear_err,float p_alowed_angular_err,float p_max_optimizable_angle) {
+bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0,const TKey<TransformKey> &t1, const TKey<TransformKey> &t2, float p_alowed_linear_err,float p_alowed_angular_err,float p_max_optimizable_angle,const Vector3& p_norm) {
real_t c = (t1.time-t0.time)/(t2.time-t0.time);
@@ -1754,6 +1754,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0,const
return false; //beyond allowed error for colinearity
}
+ if (p_norm!=Vector3() && Math::acos(pd.normalized().dot(p_norm))>p_alowed_angular_err)
+ return false;
+
t[0] = (d1-d0)/(d2-d0);
}
}
@@ -1905,16 +1908,21 @@ void Animation::_transform_track_optimize(int p_idx,float p_alowed_linear_err,fl
bool prev_erased=false;
TKey<TransformKey> first_erased;
+ Vector3 norm;
+
for(int i=1;i<tt->transforms.size()-1;i++) {
TKey<TransformKey> &t0 = tt->transforms[i-1];
TKey<TransformKey> &t1 = tt->transforms[i];
TKey<TransformKey> &t2 = tt->transforms[i+1];
- bool erase = _transform_track_optimize_key(t0,t1,t2,p_alowed_linear_err,p_alowed_angular_err,p_max_optimizable_angle);
+ bool erase = _transform_track_optimize_key(t0,t1,t2,p_alowed_linear_err,p_alowed_angular_err,p_max_optimizable_angle,norm);
+ if (erase && !prev_erased) {
+ norm=(t2.value.loc-t1.value.loc).normalized();
+ }
- if (prev_erased && !_transform_track_optimize_key(t0,first_erased,t2,p_alowed_linear_err,p_alowed_angular_err,p_max_optimizable_angle)) {
+ if (prev_erased && !_transform_track_optimize_key(t0,first_erased,t2,p_alowed_linear_err,p_alowed_angular_err,p_max_optimizable_angle,norm)) {
//avoid error to go beyond first erased key
erase=false;
}
@@ -1932,9 +1940,11 @@ void Animation::_transform_track_optimize(int p_idx,float p_alowed_linear_err,fl
} else {
prev_erased=false;
+ norm=Vector3();
}
+
// print_line(itos(i)+" could be eliminated: "+rtos(tr));
//}
}
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index d4042646fb..405b8b6a05 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -204,7 +204,7 @@ private:
return idxr;
}
- bool _transform_track_optimize_key(const TKey<TransformKey> &t0,const TKey<TransformKey> &t1, const TKey<TransformKey> &t2, float p_alowed_linear_err,float p_alowed_angular_err,float p_max_optimizable_angle);
+ bool _transform_track_optimize_key(const TKey<TransformKey> &t0,const TKey<TransformKey> &t1, const TKey<TransformKey> &t2, float p_alowed_linear_err,float p_alowed_angular_err,float p_max_optimizable_angle,const Vector3& p_norm);
void _transform_track_optimize(int p_idx, float p_allowed_err=0.05, float p_alowed_angular_err=0.01,float p_max_optimizable_angle=Math_PI*0.125);
protected:
diff --git a/scene/resources/audio_stream.cpp b/scene/resources/audio_stream.cpp
index 7694b8ef79..1dd702abd2 100644
--- a/scene/resources/audio_stream.cpp
+++ b/scene/resources/audio_stream.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -28,76 +28,34 @@
/*************************************************************************/
#include "audio_stream.h"
+//////////////////////////////
-int AudioStream::InternalAudioStream::get_channel_count() const {
+void AudioStreamPlayback::_bind_methods() {
- return owner->get_channel_count();
+ ObjectTypeDB::bind_method(_MD("play","from_pos_sec"),&AudioStreamPlayback::play,DEFVAL(0));
+ ObjectTypeDB::bind_method(_MD("stop"),&AudioStreamPlayback::stop);
+ ObjectTypeDB::bind_method(_MD("is_playing"),&AudioStreamPlayback::is_playing);
-}
-
-void AudioStream::InternalAudioStream::set_mix_rate(int p_rate) {
-
- owner->_mix_rate=p_rate;
-}
-
-bool AudioStream::InternalAudioStream::mix(int32_t *p_buffer,int p_frames) {
-
- return owner->mix(p_buffer,p_frames);
-}
-
-bool AudioStream::InternalAudioStream::can_update_mt() const {
+ ObjectTypeDB::bind_method(_MD("set_loop","enabled"),&AudioStreamPlayback::set_loop);
+ ObjectTypeDB::bind_method(_MD("has_loop"),&AudioStreamPlayback::has_loop);
- return owner->get_update_mode()==UPDATE_THREAD;
-}
+ ObjectTypeDB::bind_method(_MD("get_loop_count"),&AudioStreamPlayback::get_loop_count);
-void AudioStream::InternalAudioStream::update() {
+ ObjectTypeDB::bind_method(_MD("seek_pos","pos"),&AudioStreamPlayback::seek_pos);
+ ObjectTypeDB::bind_method(_MD("get_pos"),&AudioStreamPlayback::get_pos);
- owner->update();
-}
+ ObjectTypeDB::bind_method(_MD("get_length"),&AudioStreamPlayback::get_length);
+ ObjectTypeDB::bind_method(_MD("get_channels"),&AudioStreamPlayback::get_channels);
+ ObjectTypeDB::bind_method(_MD("get_mix_rate"),&AudioStreamPlayback::get_mix_rate);
+ ObjectTypeDB::bind_method(_MD("get_minimum_buffer_size"),&AudioStreamPlayback::get_minimum_buffer_size);
-AudioServer::AudioStream *AudioStream::get_audio_stream() {
- return internal_audio_stream;
}
void AudioStream::_bind_methods() {
- ObjectTypeDB::bind_method(_MD("play"),&AudioStream::play);
- ObjectTypeDB::bind_method(_MD("stop"),&AudioStream::stop);
- ObjectTypeDB::bind_method(_MD("is_playing"),&AudioStream::is_playing);
-
- ObjectTypeDB::bind_method(_MD("set_loop","enabled"),&AudioStream::set_loop);
- ObjectTypeDB::bind_method(_MD("has_loop"),&AudioStream::has_loop);
-
- ObjectTypeDB::bind_method(_MD("get_stream_name"),&AudioStream::get_stream_name);
- ObjectTypeDB::bind_method(_MD("get_loop_count"),&AudioStream::get_loop_count);
-
- ObjectTypeDB::bind_method(_MD("seek_pos","pos"),&AudioStream::seek_pos);
- ObjectTypeDB::bind_method(_MD("get_pos"),&AudioStream::get_pos);
-
- ObjectTypeDB::bind_method(_MD("get_length"),&AudioStream::get_length);
-
- ObjectTypeDB::bind_method(_MD("get_update_mode"),&AudioStream::get_update_mode);
-
- ObjectTypeDB::bind_method(_MD("update"),&AudioStream::update);
-
- BIND_CONSTANT( UPDATE_NONE );
- BIND_CONSTANT( UPDATE_IDLE );
- BIND_CONSTANT( UPDATE_THREAD );
}
-AudioStream::AudioStream() {
-
- _mix_rate=44100;
- internal_audio_stream = memnew( InternalAudioStream );
- internal_audio_stream->owner=this;
-}
-
-
-AudioStream::~AudioStream() {
-
- memdelete(internal_audio_stream);
-}
diff --git a/scene/resources/audio_stream.h b/scene/resources/audio_stream.h
index df33b64a4b..a4a2ad7599 100644
--- a/scene/resources/audio_stream.h
+++ b/scene/resources/audio_stream.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,72 +31,53 @@
#include "resource.h"
#include "servers/audio_server.h"
-#include "scene/resources/audio_stream.h"
-
-class AudioStream : public Resource {
-
- OBJ_TYPE( AudioStream, Resource );
- OBJ_SAVE_TYPE( AudioStream ); //children are all saved as AudioStream, so they can be exchanged
-
- friend class InternalAudioStream;
-
- struct InternalAudioStream : public AudioServer::AudioStream {
-
- ::AudioStream *owner;
- virtual int get_channel_count() const;
- virtual void set_mix_rate(int p_rate); //notify the stream of the mix rate
- virtual bool mix(int32_t *p_buffer,int p_frames);
- virtual bool can_update_mt() const;
- virtual void update();
- };
+class AudioStreamPlayback : public Reference {
- int _mix_rate;
- InternalAudioStream *internal_audio_stream;
+ OBJ_TYPE( AudioStreamPlayback, Reference );
protected:
-
- _FORCE_INLINE_ int get_mix_rate() const { return _mix_rate; }
- virtual int get_channel_count() const=0;
- virtual bool mix(int32_t *p_buffer, int p_frames)=0;
-
static void _bind_methods();
public:
- enum UpdateMode {
- UPDATE_NONE,
- UPDATE_IDLE,
- UPDATE_THREAD
- };
- AudioServer::AudioStream *get_audio_stream();
-
- virtual void play()=0;
+ virtual void play(float p_from_pos=0)=0;
virtual void stop()=0;
virtual bool is_playing() const=0;
- virtual void set_paused(bool p_paused)=0;
- virtual bool is_paused(bool p_paused) const=0;
-
virtual void set_loop(bool p_enable)=0;
virtual bool has_loop() const=0;
- virtual float get_length() const=0;
-
- virtual String get_stream_name() const=0;
+ virtual void set_loop_restart_time(float p_time)=0;
virtual int get_loop_count() const=0;
virtual float get_pos() const=0;
virtual void seek_pos(float p_time)=0;
- virtual UpdateMode get_update_mode() const=0;
- virtual void update()=0;
+ virtual int mix(int16_t* p_bufer,int p_frames)=0;
+
+ virtual float get_length() const=0;
+ virtual String get_stream_name() const=0;
+
+ virtual int get_channels() const=0;
+ virtual int get_mix_rate() const=0;
+ virtual int get_minimum_buffer_size() const=0;
- AudioStream();
- ~AudioStream();
};
+class AudioStream : public Resource {
+
+ OBJ_TYPE( AudioStream, Resource );
+ OBJ_SAVE_TYPE( AudioStream ); //children are all saved as AudioStream, so they can be exchanged
+
+protected:
+ static void _bind_methods();
+public:
+
+ virtual Ref<AudioStreamPlayback> instance_playback()=0;
+
+
+};
-VARIANT_ENUM_CAST( AudioStream::UpdateMode );
#endif // AUDIO_STREAM_H
diff --git a/scene/resources/audio_stream_resampled.cpp b/scene/resources/audio_stream_resampled.cpp
index 6317780bd3..3e10048f57 100644
--- a/scene/resources/audio_stream_resampled.cpp
+++ b/scene/resources/audio_stream_resampled.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -28,6 +28,9 @@
/*************************************************************************/
#include "audio_stream_resampled.h"
#include "globals.h"
+
+
+#if 0
int AudioStreamResampled::get_channel_count() const {
if (!rb)
@@ -382,3 +385,4 @@ AudioStreamResampled::~AudioStreamResampled() {
}
+#endif
diff --git a/scene/resources/audio_stream_resampled.h b/scene/resources/audio_stream_resampled.h
index 33cfb17e3f..64f9d17d88 100644
--- a/scene/resources/audio_stream_resampled.h
+++ b/scene/resources/audio_stream_resampled.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,6 +31,7 @@
#include "scene/resources/audio_stream.h"
+#if 0
class AudioStreamResampled : public AudioStream {
OBJ_TYPE(AudioStreamResampled,AudioStream);
@@ -160,5 +161,5 @@ public:
AudioStreamResampled();
~AudioStreamResampled();
};
-
+#endif
#endif // AUDIO_STREAM_RESAMPLED_H
diff --git a/scene/resources/baked_light.cpp b/scene/resources/baked_light.cpp
index 226edec9ae..31282a0274 100644
--- a/scene/resources/baked_light.cpp
+++ b/scene/resources/baked_light.cpp
@@ -311,11 +311,11 @@ bool BakedLight::_set(const StringName& p_name, const Variant& p_value) {
String n = p_name;
if (!n.begins_with("lightmap"))
return false;
- int idx = n.get_slice("/",1).to_int();
+ int idx = n.get_slicec('/',1).to_int();
ERR_FAIL_COND_V(idx<0,false);
ERR_FAIL_COND_V(idx>lightmaps.size(),false);
- String what = n.get_slice("/",2);
+ String what = n.get_slicec('/',2);
Ref<Texture> tex;
Size2 gens;
@@ -343,11 +343,11 @@ bool BakedLight::_get(const StringName& p_name,Variant &r_ret) const{
String n = p_name;
if (!n.begins_with("lightmap"))
return false;
- int idx = n.get_slice("/",1).to_int();
+ int idx = n.get_slicec('/',1).to_int();
ERR_FAIL_COND_V(idx<0,false);
ERR_FAIL_COND_V(idx>lightmaps.size(),false);
- String what = n.get_slice("/",2);
+ String what = n.get_slicec('/',2);
if (what=="texture") {
if (idx==lightmaps.size())
diff --git a/scene/resources/bit_mask.cpp b/scene/resources/bit_mask.cpp
index ef056a6230..f5bfce3ef8 100644
--- a/scene/resources/bit_mask.cpp
+++ b/scene/resources/bit_mask.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -204,52 +204,3 @@ BitMap::BitMap() {
//////////////////////////////////////
-
-RES ResourceFormatLoaderBitMap::load(const String &p_path,const String& p_original_path) {
-
- BitMap* ptr = memnew(BitMap);
- Ref<BitMap> bitmap( ptr );
-
-
- Image image;
-
- Error err = ImageLoader::load_image(p_path,&image);
-
- ERR_EXPLAIN("Failed loading image for BitMap: "+p_path);
- ERR_FAIL_COND_V(err, RES());
-
- bitmap->create_from_image_alpha(image);
-
- return bitmap;
-
-}
-
-bool ResourceFormatLoaderBitMap::handles_type(const String& p_type) const {
-
- return (p_type=="BitMap");
-}
-
-void ResourceFormatLoaderBitMap::get_recognized_extensions(List<String> *p_extensions) const {
-
- ImageLoader::get_recognized_extensions(p_extensions);
-}
-
-String ResourceFormatLoaderBitMap::get_resource_type(const String &p_path) const {
-
- List<String> extensions;
- ImageLoader::get_recognized_extensions(&extensions);
- String ext=p_path.extension().to_lower();
- for(List<String>::Element *E=extensions.front();E;E=E->next()) {
- if (E->get()==ext)
- return "BitMap";
- }
- return "";
-}
-
-
-ResourceFormatLoaderBitMap::ResourceFormatLoaderBitMap() {
-
-
-}
-
-
diff --git a/scene/resources/bit_mask.h b/scene/resources/bit_mask.h
index 29b7bc66f4..b245ea1542 100644
--- a/scene/resources/bit_mask.h
+++ b/scene/resources/bit_mask.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -62,16 +62,5 @@ public:
BitMap();
};
-class ResourceFormatLoaderBitMap : public ResourceFormatLoader {
-
-public:
-
- virtual RES load(const String &p_path,const String& p_original_path="");
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
- virtual bool handles_type(const String& p_type) const;
- virtual String get_resource_type(const String &p_path) const;
-
- ResourceFormatLoaderBitMap();
-};
#endif // BIT_MASK_H
diff --git a/scene/resources/bounds.cpp b/scene/resources/bounds.cpp
index 7382d60535..65ce5e49e8 100644
--- a/scene/resources/bounds.cpp
+++ b/scene/resources/bounds.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/bounds.h b/scene/resources/bounds.h
index 68aca6f6a0..a1610e2b57 100644
--- a/scene/resources/bounds.h
+++ b/scene/resources/bounds.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/box_shape.cpp b/scene/resources/box_shape.cpp
index 22ee9f8c09..9a6fedeb0b 100644
--- a/scene/resources/box_shape.cpp
+++ b/scene/resources/box_shape.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,6 +30,25 @@
#include "servers/physics_server.h"
+Vector<Vector3> BoxShape::_gen_debug_mesh_lines() {
+
+
+ Vector<Vector3> lines;
+ AABB aabb;
+ aabb.pos=-get_extents();
+ aabb.size=aabb.pos*-2;
+
+ for(int i=0;i<12;i++) {
+ Vector3 a,b;
+ aabb.get_edge(i,a,b);
+ lines.push_back(a);
+ lines.push_back(b);
+ }
+
+
+ return lines;
+}
+
void BoxShape::_update_shape() {
PhysicsServer::get_singleton()->shape_set_data(get_shape(),extents);
diff --git a/scene/resources/box_shape.h b/scene/resources/box_shape.h
index 18c5f5e5fb..88fca65eea 100644
--- a/scene/resources/box_shape.h
+++ b/scene/resources/box_shape.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -41,6 +41,7 @@ protected:
static void _bind_methods();
virtual void _update_shape();
+ virtual Vector<Vector3> _gen_debug_mesh_lines();
public:
diff --git a/scene/resources/canvas.cpp b/scene/resources/canvas.cpp
index 51953d9683..0c87d0473d 100644
--- a/scene/resources/canvas.cpp
+++ b/scene/resources/canvas.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/canvas.h b/scene/resources/canvas.h
index 71dc080e64..5120301a67 100644
--- a/scene/resources/canvas.h
+++ b/scene/resources/canvas.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/capsule_shape.cpp b/scene/resources/capsule_shape.cpp
index 2633b132cf..4c53645d2d 100644
--- a/scene/resources/capsule_shape.cpp
+++ b/scene/resources/capsule_shape.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,6 +30,46 @@
#include "servers/physics_server.h"
+Vector<Vector3> CapsuleShape::_gen_debug_mesh_lines() {
+
+
+ float radius = get_radius();
+ float height = get_height();
+
+
+ Vector<Vector3> points;
+
+ Vector3 d(0,0,height*0.5);
+ for(int i=0;i<360;i++) {
+
+ float ra=Math::deg2rad(i);
+ float rb=Math::deg2rad(i+1);
+ Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*radius;
+ Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*radius;
+
+ points.push_back(Vector3(a.x,a.y,0)+d);
+ points.push_back(Vector3(b.x,b.y,0)+d);
+
+ points.push_back(Vector3(a.x,a.y,0)-d);
+ points.push_back(Vector3(b.x,b.y,0)-d);
+
+ if (i%90==0) {
+
+ points.push_back(Vector3(a.x,a.y,0)+d);
+ points.push_back(Vector3(a.x,a.y,0)-d);
+ }
+
+ Vector3 dud = i<180?d:-d;
+
+ points.push_back(Vector3(0,a.y,a.x)+dud);
+ points.push_back(Vector3(0,b.y,b.x)+dud);
+ points.push_back(Vector3(a.y,0,a.x)+dud);
+ points.push_back(Vector3(b.y,0,b.x)+dud);
+
+ }
+
+ return points;
+}
void CapsuleShape::_update_shape() {
@@ -65,7 +105,6 @@ float CapsuleShape::get_height() const {
return height;
}
-
void CapsuleShape::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_radius","radius"),&CapsuleShape::set_radius);
diff --git a/scene/resources/capsule_shape.h b/scene/resources/capsule_shape.h
index 43b8331949..4263c3a554 100644
--- a/scene/resources/capsule_shape.h
+++ b/scene/resources/capsule_shape.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -43,6 +43,7 @@ protected:
virtual void _update_shape();
+ virtual Vector<Vector3> _gen_debug_mesh_lines();
public:
void set_radius(float p_radius);
@@ -50,6 +51,7 @@ public:
void set_height(float p_height);
float get_height() const;
+
CapsuleShape();
};
diff --git a/scene/resources/capsule_shape_2d.cpp b/scene/resources/capsule_shape_2d.cpp
index 135eb41d8f..1887ec11d7 100644
--- a/scene/resources/capsule_shape_2d.cpp
+++ b/scene/resources/capsule_shape_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,6 +29,7 @@
#include "capsule_shape_2d.h"
#include "servers/physics_2d_server.h"
+#include "servers/visual_server.h"
void CapsuleShape2D::_update_shape() {
@@ -60,6 +61,32 @@ real_t CapsuleShape2D::get_height() const {
}
+void CapsuleShape2D::draw(const RID& p_to_rid,const Color& p_color) {
+
+ Vector<Vector2> points;
+ for(int i=0;i<24;i++) {
+ Vector2 ofs = Vector2(0,(i>6 && i<=18) ? -get_height()*0.5 : get_height()*0.5);
+
+ points.push_back(Vector2(Math::sin(i*Math_PI*2/24.0),Math::cos(i*Math_PI*2/24.0))*get_radius() + ofs);
+ if (i==6 || i==18)
+ points.push_back(Vector2(Math::sin(i*Math_PI*2/24.0),Math::cos(i*Math_PI*2/24.0))*get_radius() - ofs);
+ }
+
+ Vector<Color> col;
+ col.push_back(p_color);
+ VisualServer::get_singleton()->canvas_item_add_polygon(p_to_rid,points,col);
+
+}
+
+Rect2 CapsuleShape2D::get_rect() const {
+
+ Vector2 he=Point2(get_radius(),get_radius()+get_height()*0.5);
+ Rect2 rect;
+ rect.pos=-he;
+ rect.size=he*2.0;
+ return rect;
+}
+
void CapsuleShape2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_radius","radius"),&CapsuleShape2D::set_radius);
diff --git a/scene/resources/capsule_shape_2d.h b/scene/resources/capsule_shape_2d.h
index 4dd6348282..18b5c12a52 100644
--- a/scene/resources/capsule_shape_2d.h
+++ b/scene/resources/capsule_shape_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -49,6 +49,9 @@ public:
void set_radius(real_t p_radius);
real_t get_radius() const;
+ virtual void draw(const RID& p_to_rid,const Color& p_color);
+ virtual Rect2 get_rect() const ;
+
CapsuleShape2D();
};
diff --git a/scene/resources/circle_shape_2d.cpp b/scene/resources/circle_shape_2d.cpp
index 4135bc7c3b..7171af9670 100644
--- a/scene/resources/circle_shape_2d.cpp
+++ b/scene/resources/circle_shape_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,7 +29,7 @@
#include "circle_shape_2d.h"
#include "servers/physics_2d_server.h"
-
+#include "servers/visual_server.h"
void CircleShape2D::_update_shape() {
Physics2DServer::get_singleton()->shape_set_data(get_rid(),radius);
@@ -58,6 +58,27 @@ void CircleShape2D::_bind_methods() {
}
+Rect2 CircleShape2D::get_rect() const {
+ Rect2 rect;
+ rect.pos=-Point2(get_radius(),get_radius());
+ rect.size=Point2(get_radius(),get_radius())*2.0;
+ return rect;
+}
+
+void CircleShape2D::draw(const RID& p_to_rid,const Color& p_color) {
+
+ Vector<Vector2> points;
+ for(int i=0;i<24;i++) {
+
+ points.push_back(Vector2(Math::cos(i*Math_PI*2/24.0),Math::sin(i*Math_PI*2/24.0))*get_radius());
+ }
+
+ Vector<Color> col;
+ col.push_back(p_color);
+ VisualServer::get_singleton()->canvas_item_add_polygon(p_to_rid,points,col);
+
+}
+
CircleShape2D::CircleShape2D() : Shape2D( Physics2DServer::get_singleton()->shape_create(Physics2DServer::SHAPE_CIRCLE)) {
radius=10;
diff --git a/scene/resources/circle_shape_2d.h b/scene/resources/circle_shape_2d.h
index d937af2979..c36e00d106 100644
--- a/scene/resources/circle_shape_2d.h
+++ b/scene/resources/circle_shape_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -44,6 +44,10 @@ public:
void set_radius(real_t p_radius);
real_t get_radius() const;
+ virtual void draw(const RID& p_to_rid,const Color& p_color);
+ virtual Rect2 get_rect() const;
+
+
CircleShape2D();
};
diff --git a/scene/resources/color_ramp.cpp b/scene/resources/color_ramp.cpp
index 97d3fafd58..bf1f298e7a 100644
--- a/scene/resources/color_ramp.cpp
+++ b/scene/resources/color_ramp.cpp
@@ -26,6 +26,23 @@ ColorRamp::~ColorRamp() {
void ColorRamp::_bind_methods() {
+
+
+
+
+ ObjectTypeDB::bind_method(_MD("add_point","offset","color"),&ColorRamp::add_point);
+ ObjectTypeDB::bind_method(_MD("remove_point","offset","color"),&ColorRamp::remove_point);
+
+ ObjectTypeDB::bind_method(_MD("set_offset","point","offset"),&ColorRamp::set_offset);
+ ObjectTypeDB::bind_method(_MD("get_offset","point"),&ColorRamp::get_offset);
+
+ ObjectTypeDB::bind_method(_MD("set_color","point","color"),&ColorRamp::set_color);
+ ObjectTypeDB::bind_method(_MD("get_color","point"),&ColorRamp::get_color);
+
+ ObjectTypeDB::bind_method(_MD("interpolate","offset"),&ColorRamp::get_color_at_offset);
+
+ ObjectTypeDB::bind_method(_MD("get_point_count"),&ColorRamp::get_points_count);
+
ObjectTypeDB::bind_method(_MD(COLOR_RAMP_SET_OFFSETS,"offsets"),&ColorRamp::set_offsets);
ObjectTypeDB::bind_method(_MD(COLOR_RAMP_GET_OFFSETS),&ColorRamp::get_offsets);
@@ -79,6 +96,23 @@ Vector<ColorRamp::Point>& ColorRamp::get_points() {
return points;
}
+void ColorRamp::add_point(float p_offset, const Color& p_color) {
+
+ Point p;
+ p.offset=p_offset;
+ p.color=p_color;
+ is_sorted=false;
+ points.push_back(p);
+
+}
+
+void ColorRamp::remove_point(int p_index) {
+
+ ERR_FAIL_INDEX(p_index,points.size());
+ ERR_FAIL_COND(points.size()<=2);
+ points.remove(p_index);
+}
+
void ColorRamp::set_points(Vector<ColorRamp::Point>& p_points) {
points = p_points;
is_sorted = false;
diff --git a/scene/resources/color_ramp.h b/scene/resources/color_ramp.h
index 8f6ba2c3e5..aab5698c2b 100644
--- a/scene/resources/color_ramp.h
+++ b/scene/resources/color_ramp.h
@@ -32,6 +32,9 @@ public:
ColorRamp();
virtual ~ColorRamp();
+ void add_point(float p_offset, const Color& p_color);
+ void remove_point(int p_index);
+
void set_points(Vector<Point>& points);
Vector<Point>& get_points();
diff --git a/scene/resources/concave_polygon_shape.cpp b/scene/resources/concave_polygon_shape.cpp
index 55bd5de690..34bea038f4 100644
--- a/scene/resources/concave_polygon_shape.cpp
+++ b/scene/resources/concave_polygon_shape.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,6 +30,40 @@
#include "servers/physics_server.h"
+Vector<Vector3> ConcavePolygonShape::_gen_debug_mesh_lines() {
+
+ Set<DrawEdge> edges;
+
+ DVector<Vector3> data=get_faces();
+ int datalen=data.size();
+ ERR_FAIL_COND_V( (datalen%3)!=0,Vector<Vector3>() );
+
+ DVector<Vector3>::Read r=data.read();
+
+ for(int i=0;i<datalen;i+=3) {
+
+ for(int j=0;j<3;j++) {
+
+ DrawEdge de(r[i+j],r[i+((j+1)%3)]);
+ edges.insert(de);
+ }
+
+ }
+
+ Vector<Vector3> points;
+ points.resize(edges.size()*2);
+ int idx=0;
+ for (Set<DrawEdge>::Element*E=edges.front();E;E=E->next()) {
+
+ points[idx+0]=E->get().a;
+ points[idx+1]=E->get().b;
+ idx+=2;
+ }
+
+ return points;
+
+}
+
bool ConcavePolygonShape::_set(const StringName& p_name, const Variant& p_value) {
if (p_name=="data")
diff --git a/scene/resources/concave_polygon_shape.h b/scene/resources/concave_polygon_shape.h
index 7bd80eb9c0..a4845e9220 100644
--- a/scene/resources/concave_polygon_shape.h
+++ b/scene/resources/concave_polygon_shape.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,16 +35,36 @@ class ConcavePolygonShape : public Shape {
OBJ_TYPE(ConcavePolygonShape,Shape);
+ struct DrawEdge {
+
+ Vector3 a;
+ Vector3 b;
+ bool operator<(const DrawEdge& p_edge) const {
+ if (a==p_edge.a)
+ return b<p_edge.b;
+ else
+ return a<p_edge.a;
+ }
+
+ DrawEdge(const Vector3& p_a=Vector3(),const Vector3& p_b=Vector3()) {
+ a=p_a;
+ b=p_b;
+ if (a<b) {
+ SWAP(a,b);
+ }
+ }
+ };
protected:
+
bool _set(const StringName& p_name, const Variant& p_value);
bool _get(const StringName& p_name,Variant &r_ret) const;
void _get_property_list( List<PropertyInfo> *p_list) const;
static void _bind_methods();
virtual void _update_shape();
-
+ virtual Vector<Vector3> _gen_debug_mesh_lines();
public:
void set_faces(const DVector<Vector3>& p_faces);
diff --git a/scene/resources/concave_polygon_shape_2d.cpp b/scene/resources/concave_polygon_shape_2d.cpp
index 0287d79dc6..2c66155cb8 100644
--- a/scene/resources/concave_polygon_shape_2d.cpp
+++ b/scene/resources/concave_polygon_shape_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,11 +29,12 @@
#include "concave_polygon_shape_2d.h"
#include "servers/physics_2d_server.h"
-
+#include "servers/visual_server.h"
void ConcavePolygonShape2D::set_segments(const DVector<Vector2>& p_segments) {
Physics2DServer::get_singleton()->shape_set_data(get_rid(),p_segments);
+ emit_changed();
}
DVector<Vector2> ConcavePolygonShape2D::get_segments() const {
@@ -41,6 +42,43 @@ DVector<Vector2> ConcavePolygonShape2D::get_segments() const {
return Physics2DServer::get_singleton()->shape_get_data(get_rid());
}
+void ConcavePolygonShape2D::draw(const RID& p_to_rid,const Color& p_color) {
+
+
+ DVector<Vector2> s = get_segments();
+ int len=s.size();
+ if (len==0 || (len%2)==1)
+ return;
+
+ DVector<Vector2>::Read r = s.read();
+ for(int i=0;i<len;i+=2) {
+ VisualServer::get_singleton()->canvas_item_add_line(p_to_rid,r[i],r[i+1],p_color,2);
+ }
+
+}
+
+Rect2 ConcavePolygonShape2D::get_rect() const {
+
+
+ DVector<Vector2> s = get_segments();
+ int len=s.size();
+ if (len==0)
+ return Rect2();
+
+ Rect2 rect;
+
+ DVector<Vector2>::Read r = s.read();
+ for(int i=0;i<len;i++) {
+ if (i==0)
+ rect.pos=r[i];
+ else
+ rect.expand_to(r[i]);
+ }
+
+ return rect;
+
+}
+
void ConcavePolygonShape2D::_bind_methods() {
diff --git a/scene/resources/concave_polygon_shape_2d.h b/scene/resources/concave_polygon_shape_2d.h
index b835096b2a..89b8914741 100644
--- a/scene/resources/concave_polygon_shape_2d.h
+++ b/scene/resources/concave_polygon_shape_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -41,6 +41,9 @@ public:
void set_segments(const DVector<Vector2>& p_segments);
DVector<Vector2> get_segments() const;
+ virtual void draw(const RID& p_to_rid,const Color& p_color);
+ virtual Rect2 get_rect() const ;
+
ConcavePolygonShape2D();
};
diff --git a/scene/resources/convex_polygon_shape.cpp b/scene/resources/convex_polygon_shape.cpp
index 326a0e5180..7fcc9e97c0 100644
--- a/scene/resources/convex_polygon_shape.cpp
+++ b/scene/resources/convex_polygon_shape.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -28,7 +28,34 @@
/*************************************************************************/
#include "convex_polygon_shape.h"
#include "servers/physics_server.h"
+#include "quick_hull.h"
+Vector<Vector3> ConvexPolygonShape::_gen_debug_mesh_lines() {
+
+ DVector<Vector3> points = get_points();
+
+ if (points.size()>3) {
+
+ QuickHull qh;
+ Vector<Vector3> varr = Variant(points);
+ Geometry::MeshData md;
+ Error err = qh.build(varr,md);
+ if (err==OK) {
+ Vector<Vector3> lines;
+ lines.resize(md.edges.size()*2);
+ for(int i=0;i<md.edges.size();i++) {
+ lines[i*2+0]=md.vertices[md.edges[i].a];
+ lines[i*2+1]=md.vertices[md.edges[i].b];
+ }
+ return lines;
+
+
+ }
+
+ }
+
+ return Vector<Vector3>();
+}
void ConvexPolygonShape::_update_shape() {
diff --git a/scene/resources/convex_polygon_shape.h b/scene/resources/convex_polygon_shape.h
index e0a590e09d..a4e504ee24 100644
--- a/scene/resources/convex_polygon_shape.h
+++ b/scene/resources/convex_polygon_shape.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -42,6 +42,7 @@ protected:
virtual void _update_shape();
+ virtual Vector<Vector3> _gen_debug_mesh_lines();
public:
void set_points(const DVector<Vector3>& p_points);
diff --git a/scene/resources/convex_polygon_shape_2d.cpp b/scene/resources/convex_polygon_shape_2d.cpp
index 74506f8600..5c0dadefc2 100644
--- a/scene/resources/convex_polygon_shape_2d.cpp
+++ b/scene/resources/convex_polygon_shape_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,17 +29,22 @@
#include "convex_polygon_shape_2d.h"
#include "servers/physics_2d_server.h"
+#include "servers/visual_server.h"
+#include "geometry.h"
void ConvexPolygonShape2D::_update_shape() {
Physics2DServer::get_singleton()->shape_set_data(get_rid(),points);
+ emit_changed();
}
void ConvexPolygonShape2D::set_point_cloud(const Vector<Vector2>& p_points) {
-
+ Vector<Point2> hull=Geometry::convex_hull_2d(p_points);
+ ERR_FAIL_COND(hull.size()<3);
+ set_points(hull);
}
void ConvexPolygonShape2D::set_points(const Vector<Vector2>& p_points) {
@@ -62,7 +67,30 @@ void ConvexPolygonShape2D::_bind_methods() {
- ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"points"),_SCS("set_points"),_SCS("get_points") );
+ ADD_PROPERTY( PropertyInfo(Variant::VECTOR2_ARRAY,"points"),_SCS("set_points"),_SCS("get_points") );
+
+}
+
+void ConvexPolygonShape2D::draw(const RID& p_to_rid,const Color& p_color) {
+
+
+ Vector<Color> col;
+ col.push_back(p_color);
+ VisualServer::get_singleton()->canvas_item_add_polygon(p_to_rid,points,col);
+}
+
+Rect2 ConvexPolygonShape2D::get_rect() const {
+
+
+ Rect2 rect;
+ for(int i=0;i<points.size();i++) {
+ if (i==0)
+ rect.pos=points[i];
+ else
+ rect.expand_to(points[i]);
+ }
+
+ return rect;
}
diff --git a/scene/resources/convex_polygon_shape_2d.h b/scene/resources/convex_polygon_shape_2d.h
index efcaa19be6..e1792a1075 100644
--- a/scene/resources/convex_polygon_shape_2d.h
+++ b/scene/resources/convex_polygon_shape_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -45,6 +45,9 @@ public:
void set_points(const Vector<Vector2>& p_points);
Vector<Vector2> get_points() const;
+ virtual void draw(const RID& p_to_rid,const Color& p_color);
+ virtual Rect2 get_rect() const ;
+
ConvexPolygonShape2D();
};
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index c1a389942f..7dec4029fc 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/curve.h b/scene/resources/curve.h
index 4818632dc3..262f22b7d1 100644
--- a/scene/resources/curve.h
+++ b/scene/resources/curve.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/default_theme/SCsub b/scene/resources/default_theme/SCsub
index 055d2f2474..bbe59b3054 100644
--- a/scene/resources/default_theme/SCsub
+++ b/scene/resources/default_theme/SCsub
@@ -3,5 +3,3 @@ Import('env')
env.add_source_files(env.scene_sources,"*.cpp")
Export('env')
-
-
diff --git a/scene/resources/default_theme/button_disabled.png b/scene/resources/default_theme/button_disabled.png
index e1d25c08fb..6228c16e7f 100644
--- a/scene/resources/default_theme/button_disabled.png
+++ b/scene/resources/default_theme/button_disabled.png
Binary files differ
diff --git a/scene/resources/default_theme/button_focus.png b/scene/resources/default_theme/button_focus.png
new file mode 100644
index 0000000000..52af26483e
--- /dev/null
+++ b/scene/resources/default_theme/button_focus.png
Binary files differ
diff --git a/scene/resources/default_theme/button_hover.png b/scene/resources/default_theme/button_hover.png
index b01af258f0..3420e71b0b 100644
--- a/scene/resources/default_theme/button_hover.png
+++ b/scene/resources/default_theme/button_hover.png
Binary files differ
diff --git a/scene/resources/default_theme/button_normal.png b/scene/resources/default_theme/button_normal.png
index d10df91b1d..b949477fc3 100644
--- a/scene/resources/default_theme/button_normal.png
+++ b/scene/resources/default_theme/button_normal.png
Binary files differ
diff --git a/scene/resources/default_theme/button_pressed.png b/scene/resources/default_theme/button_pressed.png
index 9d627936e6..2cdbc00f3d 100644
--- a/scene/resources/default_theme/button_pressed.png
+++ b/scene/resources/default_theme/button_pressed.png
Binary files differ
diff --git a/scene/resources/default_theme/checked.png b/scene/resources/default_theme/checked.png
index a41b33cccf..a2240c227f 100644
--- a/scene/resources/default_theme/checked.png
+++ b/scene/resources/default_theme/checked.png
Binary files differ
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 9a9048e3e5..f713b9e979 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/*************************************************/
/* Source code within this file is: */
-/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
/* All Rights Reserved. */
/*************************************************/
@@ -31,7 +31,7 @@ static TexCacheMap *tex_cache;
template<class T>
static Ref<StyleBoxTexture> make_stylebox(T p_src,float p_left, float p_top, float p_right, float p_botton,float p_margin_left=-1, float p_margin_top=-1, float p_margin_right=-1, float p_margin_botton=-1, bool p_draw_center=true) {
-
+
Ref<ImageTexture> texture;
@@ -56,26 +56,43 @@ static Ref<StyleBoxTexture> make_stylebox(T p_src,float p_left, float p_top, flo
style->set_default_margin( MARGIN_BOTTOM, p_margin_botton );
style->set_default_margin( MARGIN_TOP, p_margin_top );
style->set_draw_center(p_draw_center);
-
+
return style;
}
+
+static Ref<StyleBoxTexture> sb_expand(Ref<StyleBoxTexture> p_sbox,float p_left, float p_top, float p_right, float p_botton) {
+
+ p_sbox->set_expand_margin_size(MARGIN_LEFT,p_left);
+ p_sbox->set_expand_margin_size(MARGIN_TOP,p_top);
+ p_sbox->set_expand_margin_size(MARGIN_RIGHT,p_right);
+ p_sbox->set_expand_margin_size(MARGIN_BOTTOM,p_botton);
+ return p_sbox;
+}
+
template<class T>
static Ref<Texture> make_icon(T p_src) {
-
-
+
+
Ref<ImageTexture> texture( memnew( ImageTexture ) );
texture->create_from_image( Image(p_src),ImageTexture::FLAG_FILTER );
-
+
return texture;
}
+static Ref<Shader> make_shader(const char*vertex_code,const char*fragment_code,const char*lighting_code) {
+ Ref<Shader> shader = (memnew( Shader(Shader::MODE_CANVAS_ITEM) ));
+ shader->set_code(vertex_code, fragment_code, lighting_code);
+
+ return shader;
+}
+
static Ref<Font> make_font(int p_height,int p_ascent, int p_valign, int p_charcount, const int *p_chars,const Ref<Texture> &p_texture) {
Ref<Font> font( memnew( Font ) );
font->add_texture( p_texture );
-
+
for (int i=0;i<p_charcount;i++) {
const int *c = &p_chars[i*8];
@@ -91,9 +108,9 @@ static Ref<Font> make_font(int p_height,int p_ascent, int p_valign, int p_charco
font->add_char( chr, 0, frect, align,advance );
-
+
}
-
+
font->set_height( p_height );
font->set_ascent( p_ascent );
@@ -152,12 +169,12 @@ static Ref<Font> make_font2(int p_height,int p_ascent, int p_charcount, const in
static Ref<StyleBox> make_empty_stylebox(float p_margin_left=-1, float p_margin_top=-1, float p_margin_right=-1, float p_margin_botton=-1) {
Ref<StyleBox> style( memnew( StyleBoxEmpty) );
-
+
style->set_default_margin( MARGIN_LEFT, p_margin_left );
style->set_default_margin( MARGIN_RIGHT, p_margin_right );
style->set_default_margin( MARGIN_BOTTOM, p_margin_botton );
style->set_default_margin( MARGIN_TOP, p_margin_top );
-
+
return style;
}
@@ -178,6 +195,7 @@ void make_default_theme() {
// Font Colors
Color control_font_color = Color::html("e0e0e0");
+ Color control_font_color_lower = Color::html("a0a0a0");
Color control_font_color_low = Color::html("b0b0b0");
Color control_font_color_hover = Color::html("f0f0f0");
Color control_font_color_disabled = Color(0.9,0.9,0.9,0.2);
@@ -195,18 +213,24 @@ void make_default_theme() {
Ref<StyleBoxTexture> focus = make_stylebox( focus_png,5,5,5,5);
for(int i=0;i<4;i++) {
- focus->set_expand_margin_size(Margin(i),2);
+ focus->set_expand_margin_size(Margin(i),1);
}
// Button
- t->set_stylebox("normal","Button", make_stylebox( button_normal_png,4,4,4,4,8,4,8,4) );
- t->set_stylebox("pressed","Button", make_stylebox( button_pressed_png,4,4,4,4) );
- t->set_stylebox("hover","Button", make_stylebox( button_hover_png,4,4,4,4) );
- t->set_stylebox("disabled","Button", make_stylebox( button_disabled_png,4,4,4,4) );
- t->set_stylebox("focus","Button", focus );
+ Ref<StyleBox> sb_button_normal = sb_expand( make_stylebox( button_normal_png,4,4,4,4,6,3,6,3),2,2,2,2);
+ Ref<StyleBox> sb_button_pressed = sb_expand( make_stylebox( button_pressed_png,4,4,4,4,6,3,6,3),2,2,2,2);
+ Ref<StyleBox> sb_button_hover = sb_expand( make_stylebox( button_hover_png,4,4,4,4,6,2,6,2),2,2,2,2);
+ Ref<StyleBox> sb_button_disabled = sb_expand( make_stylebox( button_disabled_png,4,4,4,4,6,2,6,2),2,2,2,2);
+ Ref<StyleBox> sb_button_focus = sb_expand( make_stylebox( button_focus_png,4,4,4,4,6,2,6,2),2,2,2,2);
+
+ t->set_stylebox("normal","Button", sb_button_normal);
+ t->set_stylebox("pressed","Button", sb_button_pressed);
+ t->set_stylebox("hover","Button", sb_button_hover);
+ t->set_stylebox("disabled","Button", sb_button_disabled);
+ t->set_stylebox("focus","Button", sb_button_focus);
t->set_font("font","Button", default_font );
@@ -221,11 +245,11 @@ void make_default_theme() {
// ColorPickerButton
- t->set_stylebox("normal","ColorPickerButton", make_stylebox( button_normal_png,4,4,4,4) );
- t->set_stylebox("pressed","ColorPickerButton", make_stylebox( button_pressed_png,4,4,4,4) );
- t->set_stylebox("hover","ColorPickerButton", make_stylebox( button_hover_png,4,4,4,4) );
- t->set_stylebox("disabled","ColorPickerButton", make_stylebox( button_disabled_png,4,4,4,4) );
- t->set_stylebox("focus","ColorPickerButton", focus );
+ t->set_stylebox("normal","ColorPickerButton", sb_button_normal);
+ t->set_stylebox("pressed","ColorPickerButton", sb_button_pressed);
+ t->set_stylebox("hover","ColorPickerButton", sb_button_hover);
+ t->set_stylebox("disabled","ColorPickerButton", sb_button_disabled);
+ t->set_stylebox("focus","ColorPickerButton", sb_button_focus);
t->set_font("font","ColorPickerButton", default_font );
@@ -250,7 +274,6 @@ void make_default_theme() {
t->set_stylebox("hover","ToolButton", make_stylebox( button_normal_png,4,4,4,4) );
t->set_stylebox("disabled","ToolButton", make_empty_stylebox(4,4,4,4) );
t->set_stylebox("focus","ToolButton", focus );
-
t->set_font("font","ToolButton", default_font );
t->set_color("font_color","ToolButton", control_font_color );
@@ -258,17 +281,23 @@ void make_default_theme() {
t->set_color("font_color_hover","ToolButton", control_font_color_hover );
t->set_color("font_color_disabled","ToolButton", Color(0.9,0.95,1,0.3) );
- t->set_constant("hseparation","ToolButton", 0 );
+ t->set_constant("hseparation","ToolButton", 3 );
// OptionButton
- t->set_stylebox("normal","OptionButton", make_stylebox( option_button_normal_png,5,5,21,5,8,4,8,4) );
- t->set_stylebox("pressed","OptionButton", make_stylebox( option_button_pressed_png,5,5,21,5) );
- t->set_stylebox("hover","OptionButton", make_stylebox( option_button_hover_png,5,5,21,5) );
- t->set_stylebox("disabled","OptionButton", make_stylebox( option_button_disabled_png,5,5,21,5) );
- t->set_stylebox("focus","OptionButton", focus );
+ Ref<StyleBox> sb_optbutton_normal = sb_expand( make_stylebox( option_button_normal_png,4,4,21,4,6,3,21,3),2,2,2,2);
+ Ref<StyleBox> sb_optbutton_pressed = sb_expand( make_stylebox( option_button_pressed_png,4,4,21,4,6,3,21,3),2,2,2,2);
+ Ref<StyleBox> sb_optbutton_hover = sb_expand( make_stylebox( option_button_hover_png,4,4,21,4,6,2,21,2),2,2,2,2);
+ Ref<StyleBox> sb_optbutton_disabled = sb_expand( make_stylebox( option_button_disabled_png,4,4,21,4,6,2,21,2),2,2,2,2);
+ Ref<StyleBox> sb_optbutton_focus = sb_expand( make_stylebox( button_focus_png,4,4,4,4,6,2,6,2),2,2,2,2);
+
+ t->set_stylebox("normal","OptionButton", sb_optbutton_normal );
+ t->set_stylebox("pressed","OptionButton", sb_optbutton_pressed );
+ t->set_stylebox("hover","OptionButton", sb_optbutton_hover );
+ t->set_stylebox("disabled","OptionButton", sb_optbutton_disabled );
+ t->set_stylebox("focus","OptionButton", sb_button_focus );
t->set_icon("arrow","OptionButton", make_icon( option_arrow_png ) );
@@ -286,10 +315,11 @@ void make_default_theme() {
// MenuButton
- t->set_stylebox("normal","MenuButton", make_stylebox( button_normal_png,4,4,4,4,8,4,8,4) );
- t->set_stylebox("pressed","MenuButton", make_stylebox( tool_button_pressed_png ,4,4,4,4) );
- t->set_stylebox("hover","MenuButton", make_stylebox( button_normal_png,4,4,4,4) );
+ t->set_stylebox("normal","MenuButton", sb_button_normal );
+ t->set_stylebox("pressed","MenuButton", sb_button_pressed );
+ t->set_stylebox("hover","MenuButton", sb_button_pressed );
t->set_stylebox("disabled","MenuButton", make_empty_stylebox(0,0,0,0) );
+ t->set_stylebox("focus","MenuButton", sb_button_focus );
t->set_font("font","MenuButton", default_font );
@@ -298,51 +328,55 @@ void make_default_theme() {
t->set_color("font_color_hover","MenuButton", control_font_color_hover );
t->set_color("font_color_disabled","MenuButton", Color(1,1,1,0.3) );
- t->set_constant("hseparation","MenuButton", 0 );
+ t->set_constant("hseparation","MenuButton", 3 );
+
+ // ButtonGroup
+
+ t->set_stylebox("panel","ButtonGroup", memnew( StyleBoxEmpty ));
- // CheckBox
+ // CheckBox
- Ref<StyleBox> cbx_empty = memnew( StyleBoxEmpty );
- cbx_empty->set_default_margin(MARGIN_LEFT,22);
- cbx_empty->set_default_margin(MARGIN_RIGHT,4);
- cbx_empty->set_default_margin(MARGIN_TOP,4);
- cbx_empty->set_default_margin(MARGIN_BOTTOM,5);
- Ref<StyleBox> cbx_focus = focus;
- cbx_focus->set_default_margin(MARGIN_LEFT,4);
- cbx_focus->set_default_margin(MARGIN_RIGHT,22);
- cbx_focus->set_default_margin(MARGIN_TOP,4);
- cbx_focus->set_default_margin(MARGIN_BOTTOM,5);
+ Ref<StyleBox> cbx_empty = memnew( StyleBoxEmpty );
+ cbx_empty->set_default_margin(MARGIN_LEFT,22);
+ cbx_empty->set_default_margin(MARGIN_RIGHT,4);
+ cbx_empty->set_default_margin(MARGIN_TOP,4);
+ cbx_empty->set_default_margin(MARGIN_BOTTOM,5);
+ Ref<StyleBox> cbx_focus = focus;
+ cbx_focus->set_default_margin(MARGIN_LEFT,4);
+ cbx_focus->set_default_margin(MARGIN_RIGHT,22);
+ cbx_focus->set_default_margin(MARGIN_TOP,4);
+ cbx_focus->set_default_margin(MARGIN_BOTTOM,5);
- t->set_stylebox("normal","CheckBox", cbx_empty );
- t->set_stylebox("pressed","CheckBox", cbx_empty );
- t->set_stylebox("disabled","CheckBox", cbx_empty );
- t->set_stylebox("hover","CheckBox", cbx_empty );
- t->set_stylebox("focus","CheckBox", cbx_focus );
+ t->set_stylebox("normal","CheckBox", cbx_empty );
+ t->set_stylebox("pressed","CheckBox", cbx_empty );
+ t->set_stylebox("disabled","CheckBox", cbx_empty );
+ t->set_stylebox("hover","CheckBox", cbx_empty );
+ t->set_stylebox("focus","CheckBox", cbx_focus );
- t->set_icon("checked", "CheckBox", make_icon(checked_png));
- t->set_icon("unchecked", "CheckBox", make_icon(unchecked_png));
- t->set_icon("radio_checked", "CheckBox", make_icon(radio_checked_png));
- t->set_icon("radio_unchecked", "CheckBox", make_icon(radio_unchecked_png));
+ t->set_icon("checked", "CheckBox", make_icon(checked_png));
+ t->set_icon("unchecked", "CheckBox", make_icon(unchecked_png));
+ t->set_icon("radio_checked", "CheckBox", make_icon(radio_checked_png));
+ t->set_icon("radio_unchecked", "CheckBox", make_icon(radio_unchecked_png));
- t->set_font("font","CheckBox", default_font );
+ t->set_font("font","CheckBox", default_font );
- t->set_color("font_color","CheckBox", control_font_color );
- t->set_color("font_color_pressed","CheckBox", control_font_color_pressed );
- t->set_color("font_color_hover","CheckBox", control_font_color_hover );
- t->set_color("font_color_disabled","CheckBox", control_font_color_disabled );
+ t->set_color("font_color","CheckBox", control_font_color );
+ t->set_color("font_color_pressed","CheckBox", control_font_color_pressed );
+ t->set_color("font_color_hover","CheckBox", control_font_color_hover );
+ t->set_color("font_color_disabled","CheckBox", control_font_color_disabled );
- t->set_constant("hseparation","CheckBox",4);
- t->set_constant("check_vadjust","CheckBox",0);
+ t->set_constant("hseparation","CheckBox",4);
+ t->set_constant("check_vadjust","CheckBox",0);
// CheckButton
-
+
Ref<StyleBox> cb_empty = memnew( StyleBoxEmpty );
cb_empty->set_default_margin(MARGIN_LEFT,6);
cb_empty->set_default_margin(MARGIN_RIGHT,70);
cb_empty->set_default_margin(MARGIN_TOP,4);
- cb_empty->set_default_margin(MARGIN_BOTTOM,4);
+ cb_empty->set_default_margin(MARGIN_BOTTOM,4);
t->set_stylebox("normal","CheckButton", cb_empty );
t->set_stylebox("pressed","CheckButton", cb_empty );
@@ -366,7 +400,7 @@ void make_default_theme() {
// Label
-
+
t->set_font("font","Label", default_font );
t->set_color("font_color","Label", Color(1,1,1) );
@@ -439,10 +473,10 @@ void make_default_theme() {
// HScrollBar
- t->set_stylebox("scroll","HScrollBar", make_stylebox( scroll_bg_png,3,3,3,3,0,0,0,0) );
- t->set_stylebox("scroll_focus","HScrollBar", make_stylebox( scroll_bg_png,3,3,3,3,0,0,0,0) );
- t->set_stylebox("grabber","HScrollBar", make_stylebox( scroll_grabber_png,3,3,3,3,2,2,2,2) );
- t->set_stylebox("grabber_hilite","HScrollBar", make_stylebox( scroll_grabber_hl_png,3,3,3,3,2,2,2,2) );
+ t->set_stylebox("scroll","HScrollBar", make_stylebox( scroll_bg_png,5,5,5,5,0,0,0,0) );
+ t->set_stylebox("scroll_focus","HScrollBar", make_stylebox( scroll_bg_png,5,5,5,5,0,0,0,0) );
+ t->set_stylebox("grabber","HScrollBar", make_stylebox( scroll_grabber_png,5,5,5,5,2,2,2,2) );
+ t->set_stylebox("grabber_hilite","HScrollBar", make_stylebox( scroll_grabber_hl_png,5,5,5,5,2,2,2,2) );
t->set_icon("increment","HScrollBar",empty_icon);
t->set_icon("increment_hilite","HScrollBar",empty_icon);
@@ -453,10 +487,10 @@ void make_default_theme() {
// VScrollBar
- t->set_stylebox("scroll","VScrollBar", make_stylebox( scroll_bg_png,3,3,3,3,0,0,0,0) );
- t->set_stylebox("scroll_focus","VScrollBar", make_stylebox( scroll_bg_png,3,3,3,3,0,0,0,0) );
- t->set_stylebox("grabber","VScrollBar", make_stylebox( scroll_grabber_png,3,3,3,3,2,2,2,2) );
- t->set_stylebox("grabber_hilite","VScrollBar", make_stylebox( scroll_grabber_hl_png,3,3,3,3,2,2,2,2) );
+ t->set_stylebox("scroll","VScrollBar", make_stylebox( scroll_bg_png,5,5,5,5,0,0,0,0) );
+ t->set_stylebox("scroll_focus","VScrollBar", make_stylebox( scroll_bg_png,5,5,5,5,0,0,0,0) );
+ t->set_stylebox("grabber","VScrollBar", make_stylebox( scroll_grabber_png,5,5,5,5,2,2,2,2) );
+ t->set_stylebox("grabber_hilite","VScrollBar", make_stylebox( scroll_grabber_hl_png,5,5,5,5,2,2,2,2) );
t->set_icon("increment","VScrollBar",empty_icon);
t->set_icon("increment_hilite","VScrollBar",empty_icon);
@@ -498,10 +532,10 @@ void make_default_theme() {
// WindowDialog
- Ref<StyleBoxTexture> style_pp_win = make_stylebox( popup_window_png,6,28,6,7);
- for(int i=0;i<4;i++)
+ Ref<StyleBoxTexture> style_pp_win = sb_expand(make_stylebox( popup_window_png,10,30,10,8),8,26,8,4);
+ /*for(int i=0;i<4;i++)
style_pp_win->set_expand_margin_size((Margin)i,3);
- style_pp_win->set_expand_margin_size(MARGIN_TOP,26);
+ style_pp_win->set_expand_margin_size(MARGIN_TOP,26);*/
t->set_stylebox("panel","WindowDialog", style_pp_win );
@@ -516,12 +550,16 @@ void make_default_theme() {
t->set_constant("close_v_ofs","WindowDialog", 20 );
t->set_constant("titlebar_height","WindowDialog", 18 );
t->set_constant("title_height","WindowDialog", 20 );
-
+
+
+ // File Dialog
+
+ t->set_icon("reload","FileDialog",make_icon( icon_reload_png ));
// Popup
- Ref<StyleBoxTexture> style_pp = make_stylebox( popup_bg_png,4,4,4,4,8,8,8,8);
+ Ref<StyleBoxTexture> style_pp = sb_expand( make_stylebox( popup_bg_png,5,5,5,5,4,4,4,4),2,2,2,2);
Ref<StyleBoxTexture> selected = make_stylebox( selection_png,6,6,6,6);
for(int i=0;i<4;i++) {
@@ -557,10 +595,16 @@ void make_default_theme() {
// GraphNode
- Ref<StyleBoxTexture> graphsb = make_stylebox(graph_node_png,6,24,6,5,16,24,16,5);
+ Ref<StyleBoxTexture> graphsb = make_stylebox(graph_node_png,6,24,6,5,3,24,16,5);
+ Ref<StyleBoxTexture> graphsbselected = make_stylebox(graph_node_selected_png,6,24,6,5,3,24,16,5);
+ Ref<StyleBoxTexture> graphsbdefault = make_stylebox(graph_node_default_png,4,4,4,4,6,4,4,4);
+ Ref<StyleBoxTexture> graphsbdeffocus = make_stylebox(graph_node_default_focus_png,4,4,4,4,6,4,4,4);
//graphsb->set_expand_margin_size(MARGIN_LEFT,10);
//graphsb->set_expand_margin_size(MARGIN_RIGHT,10);
t->set_stylebox("frame","GraphNode", graphsb );
+ t->set_stylebox("selectedframe","GraphNode", graphsbselected );
+ t->set_stylebox("defaultframe", "GraphNode", graphsbdefault );
+ t->set_stylebox("defaultfocus", "GraphNode", graphsbdeffocus );
t->set_constant("separation","GraphNode", 1 );
t->set_icon("port","GraphNode", make_icon( graph_port_png ) );
t->set_icon("close","GraphNode", make_icon( graph_node_close_png ) );
@@ -622,7 +666,7 @@ void make_default_theme() {
t->set_constant("icon_margin","ItemList",4);
t->set_constant("line_separation","ItemList",2);
t->set_font("font","ItemList", default_font );
- t->set_color("font_color","ItemList", control_font_color_low );
+ t->set_color("font_color","ItemList", control_font_color_lower );
t->set_color("font_color_selected","ItemList", control_font_color_pressed );
t->set_color("guide_color","ItemList", Color(0,0,0,0.1) );
t->set_stylebox("selected","ItemList", item_selected_oof );
@@ -639,16 +683,13 @@ void make_default_theme() {
// TabContainer
- Ref<StyleBoxTexture> tc_sb = make_stylebox( tab_container_bg_png,4,4,4,4);
- for(int i=0;i<4;i++) {
- tc_sb->set_default_margin(Margin(i),4);
- tc_sb->set_expand_margin_size(Margin(i),2);
- }
+ Ref<StyleBoxTexture> tc_sb = sb_expand( make_stylebox( tab_container_bg_png,4,4,4,4,4,4,4,4),3,3,3,3);
+
tc_sb->set_expand_margin_size(MARGIN_TOP,2);
tc_sb->set_default_margin(MARGIN_TOP,8);
- t->set_stylebox("tab_fg","TabContainer", make_stylebox( tab_current_png,4,4,4,4,16,4,16,4) );
- t->set_stylebox("tab_bg","TabContainer", make_stylebox( tab_behind_png,4,4,4,4,16,6,16,4) );
+ t->set_stylebox("tab_fg","TabContainer", sb_expand( make_stylebox( tab_current_png,4,4,4,1,16,4,16,4),2,2,2,2) );
+ t->set_stylebox("tab_bg","TabContainer", sb_expand( make_stylebox( tab_behind_png,5,5,5,1,16,6,16,4),3,0,3,3) );
t->set_stylebox("panel","TabContainer", tc_sb );
t->set_icon("increment","TabContainer",make_icon( scroll_button_right_png));
@@ -673,9 +714,17 @@ void make_default_theme() {
// Tabs
- t->set_stylebox("tab_fg","Tabs", make_stylebox( tab_current_png,4,4,4,4,16,4,16,4) );
- t->set_stylebox("tab_bg","Tabs", make_stylebox( tab_behind_png,4,4,4,4,16,6,16,4) );
- t->set_stylebox("panel","Tabs", make_stylebox( tab_container_bg_png,4,4,4,4) );
+ t->set_stylebox("tab_fg","Tabs", sb_expand( make_stylebox( tab_current_png,4,3,4,1,16,3,16,2),2,2,2,2) );
+ t->set_stylebox("tab_bg","Tabs", sb_expand( make_stylebox( tab_behind_png,5,4,5,1,16,5,16,2),3,3,3,3) );
+ t->set_stylebox("panel","Tabs",tc_sb );
+ t->set_stylebox("button_pressed","Tabs", make_stylebox( button_pressed_png,4,4,4,4) );
+ t->set_stylebox("button","Tabs", make_stylebox( button_normal_png,4,4,4,4) );
+
+ t->set_icon("increment","Tabs",make_icon( scroll_button_right_png));
+ t->set_icon("increment_hilite","Tabs",make_icon( scroll_button_right_hl_png));
+ t->set_icon("decrement","Tabs",make_icon( scroll_button_left_png));
+ t->set_icon("decrement_hilite","Tabs",make_icon( scroll_button_left_hl_png));
+ t->set_icon("close","Tabs",make_icon( tab_close_png));
t->set_font("font","Tabs", default_font );
@@ -711,7 +760,7 @@ void make_default_theme() {
// FileDialog
-
+
t->set_icon("folder","FileDialog",make_icon(icon_folder_png));
t->set_color("files_disabled","FileDialog",Color(0,0,0,0.7));
@@ -725,7 +774,11 @@ void make_default_theme() {
t->set_constant("label_width","ColorPicker", 20);
t->set_constant("hseparator","ColorPicker", 4);
-
+ t->set_icon("screen_picker","ColorPicker", make_icon( icon_color_pick_png ) );
+ t->set_icon("add_preset","ColorPicker", make_icon( icon_add_png ) );
+
+ t->set_shader("uv_editor", "ColorPicker", make_shader("", uv_editor_shader_code, ""));
+ t->set_shader("w_editor", "ColorPicker", make_shader("", w_editor_shader_code, ""));
// TooltipPanel
@@ -760,6 +813,8 @@ void make_default_theme() {
t->set_color("selection_color","RichTextLabel", Color(0.1,0.1,1,0.8) );
t->set_constant("line_separation","RichTextLabel", 1 );
+ t->set_constant("table_hseparation","RichTextLabel", 3 );
+ t->set_constant("table_vseparation","RichTextLabel", 3 );
@@ -875,10 +930,10 @@ void make_default_theme() {
#endif
void clear_default_theme() {
-
+
Theme::set_default( Ref<Theme>() );
Theme::set_default_icon( Ref< Texture >() );
- Theme::set_default_style( Ref< StyleBox >() );
+ Theme::set_default_style( Ref< StyleBox >() );
Theme::set_default_font( Ref< Font >() );
}
diff --git a/scene/resources/default_theme/default_theme.h b/scene/resources/default_theme/default_theme.h
index ddd8af46f0..44569ba192 100644
--- a/scene/resources/default_theme/default_theme.h
+++ b/scene/resources/default_theme/default_theme.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/*************************************************/
/* Source code within this file is: */
-/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
/* All Rights Reserved. */
/*************************************************/
diff --git a/scene/resources/default_theme/focus.png b/scene/resources/default_theme/focus.png
index 1656fea188..fb1052bd79 100644
--- a/scene/resources/default_theme/focus.png
+++ b/scene/resources/default_theme/focus.png
Binary files differ
diff --git a/scene/resources/default_theme/frame_focus.png b/scene/resources/default_theme/frame_focus.png
new file mode 100644
index 0000000000..0df195d83e
--- /dev/null
+++ b/scene/resources/default_theme/frame_focus.png
Binary files differ
diff --git a/scene/resources/default_theme/graph_node_default.png b/scene/resources/default_theme/graph_node_default.png
new file mode 100644
index 0000000000..ea6ec52828
--- /dev/null
+++ b/scene/resources/default_theme/graph_node_default.png
Binary files differ
diff --git a/scene/resources/default_theme/graph_node_default_focus.png b/scene/resources/default_theme/graph_node_default_focus.png
new file mode 100644
index 0000000000..b7c38ae481
--- /dev/null
+++ b/scene/resources/default_theme/graph_node_default_focus.png
Binary files differ
diff --git a/scene/resources/default_theme/graph_node_selected.png b/scene/resources/default_theme/graph_node_selected.png
new file mode 100644
index 0000000000..06a9db4409
--- /dev/null
+++ b/scene/resources/default_theme/graph_node_selected.png
Binary files differ
diff --git a/scene/resources/default_theme/hslider_bg.png b/scene/resources/default_theme/hslider_bg.png
index 963e4c8456..701c1d43b5 100644
--- a/scene/resources/default_theme/hslider_bg.png
+++ b/scene/resources/default_theme/hslider_bg.png
Binary files differ
diff --git a/scene/resources/default_theme/hslider_grabber.png b/scene/resources/default_theme/hslider_grabber.png
index b72ec4d8f4..343d247bc5 100644
--- a/scene/resources/default_theme/hslider_grabber.png
+++ b/scene/resources/default_theme/hslider_grabber.png
Binary files differ
diff --git a/scene/resources/default_theme/hslider_grabber_hl.png b/scene/resources/default_theme/hslider_grabber_hl.png
index 0dc5f2b615..f0ba7dd212 100644
--- a/scene/resources/default_theme/hslider_grabber_hl.png
+++ b/scene/resources/default_theme/hslider_grabber_hl.png
Binary files differ
diff --git a/scene/resources/default_theme/icon_add.png b/scene/resources/default_theme/icon_add.png
new file mode 100644
index 0000000000..26283ca67c
--- /dev/null
+++ b/scene/resources/default_theme/icon_add.png
Binary files differ
diff --git a/scene/resources/default_theme/icon_color_pick.png b/scene/resources/default_theme/icon_color_pick.png
new file mode 100644
index 0000000000..2896763834
--- /dev/null
+++ b/scene/resources/default_theme/icon_color_pick.png
Binary files differ
diff --git a/scene/resources/default_theme/icon_reload.png b/scene/resources/default_theme/icon_reload.png
new file mode 100644
index 0000000000..f7c6530d77
--- /dev/null
+++ b/scene/resources/default_theme/icon_reload.png
Binary files differ
diff --git a/scene/resources/default_theme/line_edit.png b/scene/resources/default_theme/line_edit.png
index d0ce0b9d70..85f7dd2bb4 100644
--- a/scene/resources/default_theme/line_edit.png
+++ b/scene/resources/default_theme/line_edit.png
Binary files differ
diff --git a/scene/resources/default_theme/line_edit_disabled.png b/scene/resources/default_theme/line_edit_disabled.png
index edb6a7d5fc..fe3b0681f6 100644
--- a/scene/resources/default_theme/line_edit_disabled.png
+++ b/scene/resources/default_theme/line_edit_disabled.png
Binary files differ
diff --git a/scene/resources/default_theme/make_header.py b/scene/resources/default_theme/make_header.py
new file mode 100644
index 0000000000..2d3f989e01
--- /dev/null
+++ b/scene/resources/default_theme/make_header.py
@@ -0,0 +1,72 @@
+
+import os;
+import glob;
+import string;
+
+
+#Generate include files
+
+f=open("theme_data.h","wb")
+
+f.write("// THIS FILE HAS BEEN AUTOGENERATED, DONT EDIT!!\n");
+
+f.write("\n\n");
+
+#Generate png image block
+
+pixmaps = glob.glob("*.png");
+
+pixmaps.sort();
+
+f.write("\n\n\n");
+
+for x in pixmaps:
+
+ var_str=x[:-4]+"_png";
+
+ f.write("static const unsigned char "+ var_str +"[]={\n");
+
+ pngf=open(x,"rb");
+
+ b=pngf.read(1);
+ while(len(b)==1):
+ f.write(hex(ord(b)))
+ b=pngf.read(1);
+ if (len(b)==1):
+ f.write(",")
+
+ f.write("\n};\n\n\n");
+ pngf.close();
+
+#Generate shaders block
+
+shaders = glob.glob("*.gsl")
+
+shaders.sort();
+
+f.write("\n\n\n");
+
+for x in shaders:
+
+ var_str=x[:-4]+"_shader_code";
+
+ f.write("static const char *"+ var_str +"=\n");
+
+ sf=open(x,"rb");
+
+
+ b=sf.readline();
+ while(b!=""):
+ if (b.endswith("\r\n")):
+ b=b[:-2]
+ if (b.endswith("\n")):
+ b=b[:-1]
+ f.write(" \""+b)
+ b=sf.readline();
+ if (b!=""):
+ f.write("\"\n")
+
+ f.write("\";\n\n\n");
+ sf.close();
+
+f.close();
diff --git a/scene/resources/default_theme/make_png_header.py b/scene/resources/default_theme/make_png_header.py
deleted file mode 100644
index 0f0ce1808f..0000000000
--- a/scene/resources/default_theme/make_png_header.py
+++ /dev/null
@@ -1,41 +0,0 @@
-
-import os;
-import glob;
-import string;
-
-pixmaps = glob.glob("*.png");
-
-pixmaps.sort();
-
-#Generate include files
-
-f=open("theme_data.h","wb")
-
-f.write("// THIS FILE HAS BEEN AUTOGENERATED, DONT EDIT!!\n");
-
-f.write("\n\n");
-
-f.write("\n\n\n");
-
-
-
-for x in pixmaps:
-
- var_str=x[:-4]+"_png";
-
- f.write("static const unsigned char "+ var_str +"[]={\n");
-
- pngf=open(x,"rb");
-
- b=pngf.read(1);
- while(len(b)==1):
- f.write(hex(ord(b)))
- b=pngf.read(1);
- if (len(b)==1):
- f.write(",")
-
- f.write("\n};\n\n\n");
- pngf.close();
-
-f.close();
-
diff --git a/scene/resources/default_theme/option_button_disabled.png b/scene/resources/default_theme/option_button_disabled.png
index 6250e34ff8..839f555c3a 100644
--- a/scene/resources/default_theme/option_button_disabled.png
+++ b/scene/resources/default_theme/option_button_disabled.png
Binary files differ
diff --git a/scene/resources/default_theme/option_button_hover.png b/scene/resources/default_theme/option_button_hover.png
index 8962e8aef9..a10d0a3753 100644
--- a/scene/resources/default_theme/option_button_hover.png
+++ b/scene/resources/default_theme/option_button_hover.png
Binary files differ
diff --git a/scene/resources/default_theme/option_button_normal.png b/scene/resources/default_theme/option_button_normal.png
index dd47afcd41..cc0aa6a00f 100644
--- a/scene/resources/default_theme/option_button_normal.png
+++ b/scene/resources/default_theme/option_button_normal.png
Binary files differ
diff --git a/scene/resources/default_theme/option_button_pressed.png b/scene/resources/default_theme/option_button_pressed.png
index 916da52f07..cf42608e72 100644
--- a/scene/resources/default_theme/option_button_pressed.png
+++ b/scene/resources/default_theme/option_button_pressed.png
Binary files differ
diff --git a/scene/resources/default_theme/panel_bg.png b/scene/resources/default_theme/panel_bg.png
index df08179aac..cc25600ebd 100644
--- a/scene/resources/default_theme/panel_bg.png
+++ b/scene/resources/default_theme/panel_bg.png
Binary files differ
diff --git a/scene/resources/default_theme/popup_bg.png b/scene/resources/default_theme/popup_bg.png
index 3afd0b13dd..3dac534ec6 100644
--- a/scene/resources/default_theme/popup_bg.png
+++ b/scene/resources/default_theme/popup_bg.png
Binary files differ
diff --git a/scene/resources/default_theme/popup_window.png b/scene/resources/default_theme/popup_window.png
index 88fbb3bc83..fc42e725f8 100644
--- a/scene/resources/default_theme/popup_window.png
+++ b/scene/resources/default_theme/popup_window.png
Binary files differ
diff --git a/scene/resources/default_theme/scroll_bg.png b/scene/resources/default_theme/scroll_bg.png
index 53797886cd..e1e419d663 100644
--- a/scene/resources/default_theme/scroll_bg.png
+++ b/scene/resources/default_theme/scroll_bg.png
Binary files differ
diff --git a/scene/resources/default_theme/scroll_grabber.png b/scene/resources/default_theme/scroll_grabber.png
index 16beda1514..3a193e5448 100644
--- a/scene/resources/default_theme/scroll_grabber.png
+++ b/scene/resources/default_theme/scroll_grabber.png
Binary files differ
diff --git a/scene/resources/default_theme/scroll_grabber_hl.png b/scene/resources/default_theme/scroll_grabber_hl.png
index acfb7c835b..82c94c03c8 100644
--- a/scene/resources/default_theme/scroll_grabber_hl.png
+++ b/scene/resources/default_theme/scroll_grabber_hl.png
Binary files differ
diff --git a/scene/resources/default_theme/tab_behind.png b/scene/resources/default_theme/tab_behind.png
index 4997d9e441..e872446162 100644
--- a/scene/resources/default_theme/tab_behind.png
+++ b/scene/resources/default_theme/tab_behind.png
Binary files differ
diff --git a/scene/resources/default_theme/tab_close.png b/scene/resources/default_theme/tab_close.png
new file mode 100644
index 0000000000..10e56d5bb8
--- /dev/null
+++ b/scene/resources/default_theme/tab_close.png
Binary files differ
diff --git a/scene/resources/default_theme/tab_container_bg.png b/scene/resources/default_theme/tab_container_bg.png
index 5cfe85cfef..6b713f76b2 100644
--- a/scene/resources/default_theme/tab_container_bg.png
+++ b/scene/resources/default_theme/tab_container_bg.png
Binary files differ
diff --git a/scene/resources/default_theme/tab_current.png b/scene/resources/default_theme/tab_current.png
index f3cdd96fbf..b18dd88183 100644
--- a/scene/resources/default_theme/tab_current.png
+++ b/scene/resources/default_theme/tab_current.png
Binary files differ
diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h
index 03d851e749..4c440ab99a 100644
--- a/scene/resources/default_theme/theme_data.h
+++ b/scene/resources/default_theme/theme_data.h
@@ -25,27 +25,32 @@ static const unsigned char base_green_png[]={
static const unsigned char button_disabled_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x4c,0x0,0x4a,0x0,0x4e,0x88,0x29,0x6a,0xb6,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x10,0x13,0x3b,0x32,0x53,0xec,0x41,0x80,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0xb5,0x49,0x44,0x41,0x54,0x38,0x8d,0xed,0x93,0x3d,0xe,0x82,0x40,0x10,0x85,0xbf,0x95,0x1d,0x8b,0x85,0x84,0xe8,0x11,0xd8,0x4e,0x8f,0x60,0x8c,0x67,0x37,0x84,0x78,0x2,0xed,0xd6,0x23,0xd8,0x28,0x5b,0x38,0x31,0x58,0x8,0x96,0xb0,0x9,0x8d,0x85,0xd3,0xbd,0xcc,0xbc,0x9f,0x62,0x9e,0x1,0x2c,0xb0,0x4,0x4,0x30,0xa4,0x4d,0x7,0x28,0xf0,0x1c,0xc8,0x6b,0xa0,0x0,0xb2,0x44,0x81,0x17,0xf0,0x0,0x6e,0xb6,0x77,0x2e,0xf6,0xbb,0xc3,0xca,0x57,0x7e,0x23,0x22,0xa3,0x29,0x54,0xb5,0xb,0xd7,0x70,0xa9,0x9b,0x23,0xc0,0xdd,0xf6,0xb1,0x33,0x5f,0xf9,0x6d,0x8c,0x91,0x36,0xc6,0x51,0xeb,0xdc,0x39,0xe3,0x2b,0xbf,0xad,0x9b,0xe3,0x9,0x30,0x8b,0x61,0x21,0x22,0x93,0x64,0x80,0x36,0x46,0x44,0xe4,0x8b,0x17,0x23,0xb7,0x49,0xf3,0x17,0xf8,0x29,0x1,0x55,0x25,0x77,0x6e,0x92,0x90,0x3b,0x87,0xaa,0x7e,0xb1,0xe5,0x53,0x8c,0x57,0xb8,0x86,0xb3,0xaf,0xfc,0xa6,0x2c,0xcb,0xa4,0x57,0xe6,0xd3,0x87,0xce,0x0,0x8e,0x19,0x65,0x32,0xcc,0xac,0xf3,0x1b,0xb6,0xa2,0x3d,0xf4,0x28,0x24,0x4e,0x1c,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0xa,0x45,0x69,0x43,0x43,0x50,0x49,0x43,0x43,0x20,0x70,0x72,0x6f,0x66,0x69,0x6c,0x65,0x0,0x0,0x78,0xda,0x9d,0x53,0x67,0x54,0x53,0xe9,0x16,0x3d,0xf7,0xde,0xf4,0x42,0x4b,0x88,0x80,0x94,0x4b,0x6f,0x52,0x15,0x8,0x20,0x52,0x42,0x8b,0x80,0x14,0x91,0x26,0x2a,0x21,0x9,0x10,0x4a,0x88,0x21,0xa1,0xd9,0x15,0x51,0xc1,0x11,0x45,0x45,0x4,0x1b,0xc8,0xa0,0x88,0x3,0x8e,0x8e,0x80,0x8c,0x15,0x51,0x2c,0xc,0x8a,0xa,0xd8,0x7,0xe4,0x21,0xa2,0x8e,0x83,0xa3,0x88,0x8a,0xca,0xfb,0xe1,0x7b,0xa3,0x6b,0xd6,0xbc,0xf7,0xe6,0xcd,0xfe,0xb5,0xd7,0x3e,0xe7,0xac,0xf3,0x9d,0xb3,0xcf,0x7,0xc0,0x8,0xc,0x96,0x48,0x33,0x51,0x35,0x80,0xc,0xa9,0x42,0x1e,0x11,0xe0,0x83,0xc7,0xc4,0xc6,0xe1,0xe4,0x2e,0x40,0x81,0xa,0x24,0x70,0x0,0x10,0x8,0xb3,0x64,0x21,0x73,0xfd,0x23,0x1,0x0,0xf8,0x7e,0x3c,0x3c,0x2b,0x22,0xc0,0x7,0xbe,0x0,0x1,0x78,0xd3,0xb,0x8,0x0,0xc0,0x4d,0x9b,0xc0,0x30,0x1c,0x87,0xff,0xf,0xea,0x42,0x99,0x5c,0x1,0x80,0x84,0x1,0xc0,0x74,0x91,0x38,0x4b,0x8,0x80,0x14,0x0,0x40,0x7a,0x8e,0x42,0xa6,0x0,0x40,0x46,0x1,0x80,0x9d,0x98,0x26,0x53,0x0,0xa0,0x4,0x0,0x60,0xcb,0x63,0x62,0xe3,0x0,0x50,0x2d,0x0,0x60,0x27,0x7f,0xe6,0xd3,0x0,0x80,0x9d,0xf8,0x99,0x7b,0x1,0x0,0x5b,0x94,0x21,0x15,0x1,0xa0,0x91,0x0,0x20,0x13,0x65,0x88,0x44,0x0,0x68,0x3b,0x0,0xac,0xcf,0x56,0x8a,0x45,0x0,0x58,0x30,0x0,0x14,0x66,0x4b,0xc4,0x39,0x0,0xd8,0x2d,0x0,0x30,0x49,0x57,0x66,0x48,0x0,0xb0,0xb7,0x0,0xc0,0xce,0x10,0xb,0xb2,0x0,0x8,0xc,0x0,0x30,0x51,0x88,0x85,0x29,0x0,0x4,0x7b,0x0,0x60,0xc8,0x23,0x23,0x78,0x0,0x84,0x99,0x0,0x14,0x46,0xf2,0x57,0x3c,0xf1,0x2b,0xae,0x10,0xe7,0x2a,0x0,0x0,0x78,0x99,0xb2,0x3c,0xb9,0x24,0x39,0x45,0x81,0x5b,0x8,0x2d,0x71,0x7,0x57,0x57,0x2e,0x1e,0x28,0xce,0x49,0x17,0x2b,0x14,0x36,0x61,0x2,0x61,0x9a,0x40,0x2e,0xc2,0x79,0x99,0x19,0x32,0x81,0x34,0xf,0xe0,0xf3,0xcc,0x0,0x0,0xa0,0x91,0x15,0x11,0xe0,0x83,0xf3,0xfd,0x78,0xce,0xe,0xae,0xce,0xce,0x36,0x8e,0xb6,0xe,0x5f,0x2d,0xea,0xbf,0x6,0xff,0x22,0x62,0x62,0xe3,0xfe,0xe5,0xcf,0xab,0x70,0x40,0x0,0x0,0xe1,0x74,0x7e,0xd1,0xfe,0x2c,0x2f,0xb3,0x1a,0x80,0x3b,0x6,0x80,0x6d,0xfe,0xa2,0x25,0xee,0x4,0x68,0x5e,0xb,0xa0,0x75,0xf7,0x8b,0x66,0xb2,0xf,0x40,0xb5,0x0,0xa0,0xe9,0xda,0x57,0xf3,0x70,0xf8,0x7e,0x3c,0x3c,0x45,0xa1,0x90,0xb9,0xd9,0xd9,0xe5,0xe4,0xe4,0xd8,0x4a,0xc4,0x42,0x5b,0x61,0xca,0x57,0x7d,0xfe,0x67,0xc2,0x5f,0xc0,0x57,0xfd,0x6c,0xf9,0x7e,0x3c,0xfc,0xf7,0xf5,0xe0,0xbe,0xe2,0x24,0x81,0x32,0x5d,0x81,0x47,0x4,0xf8,0xe0,0xc2,0xcc,0xf4,0x4c,0xa5,0x1c,0xcf,0x92,0x9,0x84,0x62,0xdc,0xe6,0x8f,0x47,0xfc,0xb7,0xb,0xff,0xfc,0x1d,0xd3,0x22,0xc4,0x49,0x62,0xb9,0x58,0x2a,0x14,0xe3,0x51,0x12,0x71,0x8e,0x44,0x9a,0x8c,0xf3,0x32,0xa5,0x22,0x89,0x42,0x92,0x29,0xc5,0x25,0xd2,0xff,0x64,0xe2,0xdf,0x2c,0xfb,0x3,0x3e,0xdf,0x35,0x0,0xb0,0x6a,0x3e,0x1,0x7b,0x91,0x2d,0xa8,0x5d,0x63,0x3,0xf6,0x4b,0x27,0x10,0x58,0x74,0xc0,0xe2,0xf7,0x0,0x0,0xf2,0xbb,0x6f,0xc1,0xd4,0x28,0x8,0x3,0x80,0x68,0x83,0xe1,0xcf,0x77,0xff,0xef,0x3f,0xfd,0x47,0xa0,0x25,0x0,0x80,0x66,0x49,0x92,0x71,0x0,0x0,0x5e,0x44,0x24,0x2e,0x54,0xca,0xb3,0x3f,0xc7,0x8,0x0,0x0,0x44,0xa0,0x81,0x2a,0xb0,0x41,0x1b,0xf4,0xc1,0x18,0x2c,0xc0,0x6,0x1c,0xc1,0x5,0xdc,0xc1,0xb,0xfc,0x60,0x36,0x84,0x42,0x24,0xc4,0xc2,0x42,0x10,0x42,0xa,0x64,0x80,0x1c,0x72,0x60,0x29,0xac,0x82,0x42,0x28,0x86,0xcd,0xb0,0x1d,0x2a,0x60,0x2f,0xd4,0x40,0x1d,0x34,0xc0,0x51,0x68,0x86,0x93,0x70,0xe,0x2e,0xc2,0x55,0xb8,0xe,0x3d,0x70,0xf,0xfa,0x61,0x8,0x9e,0xc1,0x28,0xbc,0x81,0x9,0x4,0x41,0xc8,0x8,0x13,0x61,0x21,0xda,0x88,0x1,0x62,0x8a,0x58,0x23,0x8e,0x8,0x17,0x99,0x85,0xf8,0x21,0xc1,0x48,0x4,0x12,0x8b,0x24,0x20,0xc9,0x88,0x14,0x51,0x22,0x4b,0x91,0x35,0x48,0x31,0x52,0x8a,0x54,0x20,0x55,0x48,0x1d,0xf2,0x3d,0x72,0x2,0x39,0x87,0x5c,0x46,0xba,0x91,0x3b,0xc8,0x0,0x32,0x82,0xfc,0x86,0xbc,0x47,0x31,0x94,0x81,0xb2,0x51,0x3d,0xd4,0xc,0xb5,0x43,0xb9,0xa8,0x37,0x1a,0x84,0x46,0xa2,0xb,0xd0,0x64,0x74,0x31,0x9a,0x8f,0x16,0xa0,0x9b,0xd0,0x72,0xb4,0x1a,0x3d,0x8c,0x36,0xa1,0xe7,0xd0,0xab,0x68,0xf,0xda,0x8f,0x3e,0x43,0xc7,0x30,0xc0,0xe8,0x18,0x7,0x33,0xc4,0x6c,0x30,0x2e,0xc6,0xc3,0x42,0xb1,0x38,0x2c,0x9,0x93,0x63,0xcb,0xb1,0x22,0xac,0xc,0xab,0xc6,0x1a,0xb0,0x56,0xac,0x3,0xbb,0x89,0xf5,0x63,0xcf,0xb1,0x77,0x4,0x12,0x81,0x45,0xc0,0x9,0x36,0x4,0x77,0x42,0x20,0x61,0x1e,0x41,0x48,0x58,0x4c,0x58,0x4e,0xd8,0x48,0xa8,0x20,0x1c,0x24,0x34,0x11,0xda,0x9,0x37,0x9,0x3,0x84,0x51,0xc2,0x27,0x22,0x93,0xa8,0x4b,0xb4,0x26,0xba,0x11,0xf9,0xc4,0x18,0x62,0x32,0x31,0x87,0x58,0x48,0x2c,0x23,0xd6,0x12,0x8f,0x13,0x2f,0x10,0x7b,0x88,0x43,0xc4,0x37,0x24,0x12,0x89,0x43,0x32,0x27,0xb9,0x90,0x2,0x49,0xb1,0xa4,0x54,0xd2,0x12,0xd2,0x46,0xd2,0x6e,0x52,0x23,0xe9,0x2c,0xa9,0x9b,0x34,0x48,0x1a,0x23,0x93,0xc9,0xda,0x64,0x6b,0xb2,0x7,0x39,0x94,0x2c,0x20,0x2b,0xc8,0x85,0xe4,0x9d,0xe4,0xc3,0xe4,0x33,0xe4,0x1b,0xe4,0x21,0xf2,0x5b,0xa,0x9d,0x62,0x40,0x71,0xa4,0xf8,0x53,0xe2,0x28,0x52,0xca,0x6a,0x4a,0x19,0xe5,0x10,0xe5,0x34,0xe5,0x6,0x65,0x98,0x32,0x41,0x55,0xa3,0x9a,0x52,0xdd,0xa8,0xa1,0x54,0x11,0x35,0x8f,0x5a,0x42,0xad,0xa1,0xb6,0x52,0xaf,0x51,0x87,0xa8,0x13,0x34,0x75,0x9a,0x39,0xcd,0x83,0x16,0x49,0x4b,0xa5,0xad,0xa2,0x95,0xd3,0x1a,0x68,0x17,0x68,0xf7,0x69,0xaf,0xe8,0x74,0xba,0x11,0xdd,0x95,0x1e,0x4e,0x97,0xd0,0x57,0xd2,0xcb,0xe9,0x47,0xe8,0x97,0xe8,0x3,0xf4,0x77,0xc,0xd,0x86,0x15,0x83,0xc7,0x88,0x67,0x28,0x19,0x9b,0x18,0x7,0x18,0x67,0x19,0x77,0x18,0xaf,0x98,0x4c,0xa6,0x19,0xd3,0x8b,0x19,0xc7,0x54,0x30,0x37,0x31,0xeb,0x98,0xe7,0x99,0xf,0x99,0x6f,0x55,0x58,0x2a,0xb6,0x2a,0x7c,0x15,0x91,0xca,0xa,0x95,0x4a,0x95,0x26,0x95,0x1b,0x2a,0x2f,0x54,0xa9,0xaa,0xa6,0xaa,0xde,0xaa,0xb,0x55,0xf3,0x55,0xcb,0x54,0x8f,0xa9,0x5e,0x53,0x7d,0xae,0x46,0x55,0x33,0x53,0xe3,0xa9,0x9,0xd4,0x96,0xab,0x55,0xaa,0x9d,0x50,0xeb,0x53,0x1b,0x53,0x67,0xa9,0x3b,0xa8,0x87,0xaa,0x67,0xa8,0x6f,0x54,0x3f,0xa4,0x7e,0x59,0xfd,0x89,0x6,0x59,0xc3,0x4c,0xc3,0x4f,0x43,0xa4,0x51,0xa0,0xb1,0x5f,0xe3,0xbc,0xc6,0x20,0xb,0x63,0x19,0xb3,0x78,0x2c,0x21,0x6b,0xd,0xab,0x86,0x75,0x81,0x35,0xc4,0x26,0xb1,0xcd,0xd9,0x7c,0x76,0x2a,0xbb,0x98,0xfd,0x1d,0xbb,0x8b,0x3d,0xaa,0xa9,0xa1,0x39,0x43,0x33,0x4a,0x33,0x57,0xb3,0x52,0xf3,0x94,0x66,0x3f,0x7,0xe3,0x98,0x71,0xf8,0x9c,0x74,0x4e,0x9,0xe7,0x28,0xa7,0x97,0xf3,0x7e,0x8a,0xde,0x14,0xef,0x29,0xe2,0x29,0x1b,0xa6,0x34,0x4c,0xb9,0x31,0x65,0x5c,0x6b,0xaa,0x96,0x97,0x96,0x58,0xab,0x48,0xab,0x51,0xab,0x47,0xeb,0xbd,0x36,0xae,0xed,0xa7,0x9d,0xa6,0xbd,0x45,0xbb,0x59,0xfb,0x81,0xe,0x41,0xc7,0x4a,0x27,0x5c,0x27,0x47,0x67,0x8f,0xce,0x5,0x9d,0xe7,0x53,0xd9,0x53,0xdd,0xa7,0xa,0xa7,0x16,0x4d,0x3d,0x3a,0xf5,0xae,0x2e,0xaa,0x6b,0xa5,0x1b,0xa1,0xbb,0x44,0x77,0xbf,0x6e,0xa7,0xee,0x98,0x9e,0xbe,0x5e,0x80,0x9e,0x4c,0x6f,0xa7,0xde,0x79,0xbd,0xe7,0xfa,0x1c,0x7d,0x2f,0xfd,0x54,0xfd,0x6d,0xfa,0xa7,0xf5,0x47,0xc,0x58,0x6,0xb3,0xc,0x24,0x6,0xdb,0xc,0xce,0x18,0x3c,0xc5,0x35,0x71,0x6f,0x3c,0x1d,0x2f,0xc7,0xdb,0xf1,0x51,0x43,0x5d,0xc3,0x40,0x43,0xa5,0x61,0x95,0x61,0x97,0xe1,0x84,0x91,0xb9,0xd1,0x3c,0xa3,0xd5,0x46,0x8d,0x46,0xf,0x8c,0x69,0xc6,0x5c,0xe3,0x24,0xe3,0x6d,0xc6,0x6d,0xc6,0xa3,0x26,0x6,0x26,0x21,0x26,0x4b,0x4d,0xea,0x4d,0xee,0x9a,0x52,0x4d,0xb9,0xa6,0x29,0xa6,0x3b,0x4c,0x3b,0x4c,0xc7,0xcd,0xcc,0xcd,0xa2,0xcd,0xd6,0x99,0x35,0x9b,0x3d,0x31,0xd7,0x32,0xe7,0x9b,0xe7,0x9b,0xd7,0x9b,0xdf,0xb7,0x60,0x5a,0x78,0x5a,0x2c,0xb6,0xa8,0xb6,0xb8,0x65,0x49,0xb2,0xe4,0x5a,0xa6,0x59,0xee,0xb6,0xbc,0x6e,0x85,0x5a,0x39,0x59,0xa5,0x58,0x55,0x5a,0x5d,0xb3,0x46,0xad,0x9d,0xad,0x25,0xd6,0xbb,0xad,0xbb,0xa7,0x11,0xa7,0xb9,0x4e,0x93,0x4e,0xab,0x9e,0xd6,0x67,0xc3,0xb0,0xf1,0xb6,0xc9,0xb6,0xa9,0xb7,0x19,0xb0,0xe5,0xd8,0x6,0xdb,0xae,0xb6,0x6d,0xb6,0x7d,0x61,0x67,0x62,0x17,0x67,0xb7,0xc5,0xae,0xc3,0xee,0x93,0xbd,0x93,0x7d,0xba,0x7d,0x8d,0xfd,0x3d,0x7,0xd,0x87,0xd9,0xe,0xab,0x1d,0x5a,0x1d,0x7e,0x73,0xb4,0x72,0x14,0x3a,0x56,0x3a,0xde,0x9a,0xce,0x9c,0xee,0x3f,0x7d,0xc5,0xf4,0x96,0xe9,0x2f,0x67,0x58,0xcf,0x10,0xcf,0xd8,0x33,0xe3,0xb6,0x13,0xcb,0x29,0xc4,0x69,0x9d,0x53,0x9b,0xd3,0x47,0x67,0x17,0x67,0xb9,0x73,0x83,0xf3,0x88,0x8b,0x89,0x4b,0x82,0xcb,0x2e,0x97,0x3e,0x2e,0x9b,0x1b,0xc6,0xdd,0xc8,0xbd,0xe4,0x4a,0x74,0xf5,0x71,0x5d,0xe1,0x7a,0xd2,0xf5,0x9d,0x9b,0xb3,0x9b,0xc2,0xed,0xa8,0xdb,0xaf,0xee,0x36,0xee,0x69,0xee,0x87,0xdc,0x9f,0xcc,0x34,0x9f,0x29,0x9e,0x59,0x33,0x73,0xd0,0xc3,0xc8,0x43,0xe0,0x51,0xe5,0xd1,0x3f,0xb,0x9f,0x95,0x30,0x6b,0xdf,0xac,0x7e,0x4f,0x43,0x4f,0x81,0x67,0xb5,0xe7,0x23,0x2f,0x63,0x2f,0x91,0x57,0xad,0xd7,0xb0,0xb7,0xa5,0x77,0xaa,0xf7,0x61,0xef,0x17,0x3e,0xf6,0x3e,0x72,0x9f,0xe3,0x3e,0xe3,0x3c,0x37,0xde,0x32,0xde,0x59,0x5f,0xcc,0x37,0xc0,0xb7,0xc8,0xb7,0xcb,0x4f,0xc3,0x6f,0x9e,0x5f,0x85,0xdf,0x43,0x7f,0x23,0xff,0x64,0xff,0x7a,0xff,0xd1,0x0,0xa7,0x80,0x25,0x1,0x67,0x3,0x89,0x81,0x41,0x81,0x5b,0x2,0xfb,0xf8,0x7a,0x7c,0x21,0xbf,0x8e,0x3f,0x3a,0xdb,0x65,0xf6,0xb2,0xd9,0xed,0x41,0x8c,0xa0,0xb9,0x41,0x15,0x41,0x8f,0x82,0xad,0x82,0xe5,0xc1,0xad,0x21,0x68,0xc8,0xec,0x90,0xad,0x21,0xf7,0xe7,0x98,0xce,0x91,0xce,0x69,0xe,0x85,0x50,0x7e,0xe8,0xd6,0xd0,0x7,0x61,0xe6,0x61,0x8b,0xc3,0x7e,0xc,0x27,0x85,0x87,0x85,0x57,0x86,0x3f,0x8e,0x70,0x88,0x58,0x1a,0xd1,0x31,0x97,0x35,0x77,0xd1,0xdc,0x43,0x73,0xdf,0x44,0xfa,0x44,0x96,0x44,0xde,0x9b,0x67,0x31,0x4f,0x39,0xaf,0x2d,0x4a,0x35,0x2a,0x3e,0xaa,0x2e,0x6a,0x3c,0xda,0x37,0xba,0x34,0xba,0x3f,0xc6,0x2e,0x66,0x59,0xcc,0xd5,0x58,0x9d,0x58,0x49,0x6c,0x4b,0x1c,0x39,0x2e,0x2a,0xae,0x36,0x6e,0x6c,0xbe,0xdf,0xfc,0xed,0xf3,0x87,0xe2,0x9d,0xe2,0xb,0xe3,0x7b,0x17,0x98,0x2f,0xc8,0x5d,0x70,0x79,0xa1,0xce,0xc2,0xf4,0x85,0xa7,0x16,0xa9,0x2e,0x12,0x2c,0x3a,0x96,0x40,0x4c,0x88,0x4e,0x38,0x94,0xf0,0x41,0x10,0x2a,0xa8,0x16,0x8c,0x25,0xf2,0x13,0x77,0x25,0x8e,0xa,0x79,0xc2,0x1d,0xc2,0x67,0x22,0x2f,0xd1,0x36,0xd1,0x88,0xd8,0x43,0x5c,0x2a,0x1e,0x4e,0xf2,0x48,0x2a,0x4d,0x7a,0x92,0xec,0x91,0xbc,0x35,0x79,0x24,0xc5,0x33,0xa5,0x2c,0xe5,0xb9,0x84,0x27,0xa9,0x90,0xbc,0x4c,0xd,0x4c,0xdd,0x9b,0x3a,0x9e,0x16,0x9a,0x76,0x20,0x6d,0x32,0x3d,0x3a,0xbd,0x31,0x83,0x92,0x91,0x90,0x71,0x42,0xaa,0x21,0x4d,0x93,0xb6,0x67,0xea,0x67,0xe6,0x66,0x76,0xcb,0xac,0x65,0x85,0xb2,0xfe,0xc5,0x6e,0x8b,0xb7,0x2f,0x1e,0x95,0x7,0xc9,0x6b,0xb3,0x90,0xac,0x5,0x59,0x2d,0xa,0xb6,0x42,0xa6,0xe8,0x54,0x5a,0x28,0xd7,0x2a,0x7,0xb2,0x67,0x65,0x57,0x66,0xbf,0xcd,0x89,0xca,0x39,0x96,0xab,0x9e,0x2b,0xcd,0xed,0xcc,0xb3,0xca,0xdb,0x90,0x37,0x9c,0xef,0x9f,0xff,0xed,0x12,0xc2,0x12,0xe1,0x92,0xb6,0xa5,0x86,0x4b,0x57,0x2d,0x1d,0x58,0xe6,0xbd,0xac,0x6a,0x39,0xb2,0x3c,0x71,0x79,0xdb,0xa,0xe3,0x15,0x5,0x2b,0x86,0x56,0x6,0xac,0x3c,0xb8,0x8a,0xb6,0x2a,0x6d,0xd5,0x4f,0xab,0xed,0x57,0x97,0xae,0x7e,0xbd,0x26,0x7a,0x4d,0x6b,0x81,0x5e,0xc1,0xca,0x82,0xc1,0xb5,0x1,0x6b,0xeb,0xb,0x55,0xa,0xe5,0x85,0x7d,0xeb,0xdc,0xd7,0xed,0x5d,0x4f,0x58,0x2f,0x59,0xdf,0xb5,0x61,0xfa,0x86,0x9d,0x1b,0x3e,0x15,0x89,0x8a,0xae,0x14,0xdb,0x17,0x97,0x15,0x7f,0xd8,0x28,0xdc,0x78,0xe5,0x1b,0x87,0x6f,0xca,0xbf,0x99,0xdc,0x94,0xb4,0xa9,0xab,0xc4,0xb9,0x64,0xcf,0x66,0xd2,0x66,0xe9,0xe6,0xde,0x2d,0x9e,0x5b,0xe,0x96,0xaa,0x97,0xe6,0x97,0xe,0x6e,0xd,0xd9,0xda,0xb4,0xd,0xdf,0x56,0xb4,0xed,0xf5,0xf6,0x45,0xdb,0x2f,0x97,0xcd,0x28,0xdb,0xbb,0x83,0xb6,0x43,0xb9,0xa3,0xbf,0x3c,0xb8,0xbc,0x65,0xa7,0xc9,0xce,0xcd,0x3b,0x3f,0x54,0xa4,0x54,0xf4,0x54,0xfa,0x54,0x36,0xee,0xd2,0xdd,0xb5,0x61,0xd7,0xf8,0x6e,0xd1,0xee,0x1b,0x7b,0xbc,0xf6,0x34,0xec,0xd5,0xdb,0x5b,0xbc,0xf7,0xfd,0x3e,0xc9,0xbe,0xdb,0x55,0x1,0x55,0x4d,0xd5,0x66,0xd5,0x65,0xfb,0x49,0xfb,0xb3,0xf7,0x3f,0xae,0x89,0xaa,0xe9,0xf8,0x96,0xfb,0x6d,0x5d,0xad,0x4e,0x6d,0x71,0xed,0xc7,0x3,0xd2,0x3,0xfd,0x7,0x23,0xe,0xb6,0xd7,0xb9,0xd4,0xd5,0x1d,0xd2,0x3d,0x54,0x52,0x8f,0xd6,0x2b,0xeb,0x47,0xe,0xc7,0x1f,0xbe,0xfe,0x9d,0xef,0x77,0x2d,0xd,0x36,0xd,0x55,0x8d,0x9c,0xc6,0xe2,0x23,0x70,0x44,0x79,0xe4,0xe9,0xf7,0x9,0xdf,0xf7,0x1e,0xd,0x3a,0xda,0x76,0x8c,0x7b,0xac,0xe1,0x7,0xd3,0x1f,0x76,0x1d,0x67,0x1d,0x2f,0x6a,0x42,0x9a,0xf2,0x9a,0x46,0x9b,0x53,0x9a,0xfb,0x5b,0x62,0x5b,0xba,0x4f,0xcc,0x3e,0xd1,0xd6,0xea,0xde,0x7a,0xfc,0x47,0xdb,0x1f,0xf,0x9c,0x34,0x3c,0x59,0x79,0x4a,0xf3,0x54,0xc9,0x69,0xda,0xe9,0x82,0xd3,0x93,0x67,0xf2,0xcf,0x8c,0x9d,0x95,0x9d,0x7d,0x7e,0x2e,0xf9,0xdc,0x60,0xdb,0xa2,0xb6,0x7b,0xe7,0x63,0xce,0xdf,0x6a,0xf,0x6f,0xef,0xba,0x10,0x74,0xe1,0xd2,0x45,0xff,0x8b,0xe7,0x3b,0xbc,0x3b,0xce,0x5c,0xf2,0xb8,0x74,0xf2,0xb2,0xdb,0xe5,0x13,0x57,0xb8,0x57,0x9a,0xaf,0x3a,0x5f,0x6d,0xea,0x74,0xea,0x3c,0xfe,0x93,0xd3,0x4f,0xc7,0xbb,0x9c,0xbb,0x9a,0xae,0xb9,0x5c,0x6b,0xb9,0xee,0x7a,0xbd,0xb5,0x7b,0x66,0xf7,0xe9,0x1b,0x9e,0x37,0xce,0xdd,0xf4,0xbd,0x79,0xf1,0x16,0xff,0xd6,0xd5,0x9e,0x39,0x3d,0xdd,0xbd,0xf3,0x7a,0x6f,0xf7,0xc5,0xf7,0xf5,0xdf,0x16,0xdd,0x7e,0x72,0x27,0xfd,0xce,0xcb,0xbb,0xd9,0x77,0x27,0xee,0xad,0xbc,0x4f,0xbc,0x5f,0xf4,0x40,0xed,0x41,0xd9,0x43,0xdd,0x87,0xd5,0x3f,0x5b,0xfe,0xdc,0xd8,0xef,0xdc,0x7f,0x6a,0xc0,0x77,0xa0,0xf3,0xd1,0xdc,0x47,0xf7,0x6,0x85,0x83,0xcf,0xfe,0x91,0xf5,0x8f,0xf,0x43,0x5,0x8f,0x99,0x8f,0xcb,0x86,0xd,0x86,0xeb,0x9e,0x38,0x3e,0x39,0x39,0xe2,0x3f,0x72,0xfd,0xe9,0xfc,0xa7,0x43,0xcf,0x64,0xcf,0x26,0x9e,0x17,0xfe,0xa2,0xfe,0xcb,0xae,0x17,0x16,0x2f,0x7e,0xf8,0xd5,0xeb,0xd7,0xce,0xd1,0x98,0xd1,0xa1,0x97,0xf2,0x97,0x93,0xbf,0x6d,0x7c,0xa5,0xfd,0xea,0xc0,0xeb,0x19,0xaf,0xdb,0xc6,0xc2,0xc6,0x1e,0xbe,0xc9,0x78,0x33,0x31,0x5e,0xf4,0x56,0xfb,0xed,0xc1,0x77,0xdc,0x77,0x1d,0xef,0xa3,0xdf,0xf,0x4f,0xe4,0x7c,0x20,0x7f,0x28,0xff,0x68,0xf9,0xb1,0xf5,0x53,0xd0,0xa7,0xfb,0x93,0x19,0x93,0x93,0xff,0x4,0x3,0x98,0xf3,0xfc,0xef,0x35,0x94,0x82,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xa,0x14,0x2,0x2b,0x36,0x0,0x39,0x60,0xad,0x0,0x0,0x1,0x24,0x49,0x44,0x41,0x54,0x38,0xcb,0xa5,0x93,0x41,0x6e,0x2,0x31,0xc,0x45,0x5f,0x12,0x8b,0xa9,0xda,0x5,0xd9,0xb0,0x19,0xe,0xc3,0x1d,0x7a,0x9a,0x39,0x2,0xea,0x61,0x7a,0x83,0x2e,0x38,0xc,0x9b,0x59,0x8c,0x6,0x9,0x24,0x86,0x64,0xe2,0x6e,0x3c,0xa8,0xad,0xa,0x5,0x6a,0xc9,0x92,0x95,0x38,0xff,0xfb,0x3b,0xb6,0x3,0x4,0x98,0x1,0x15,0xf0,0x64,0x71,0x0,0x3c,0xdf,0xad,0x0,0x23,0x70,0x2,0x8e,0xc0,0x0,0x9c,0xa6,0xc7,0x2f,0x40,0x4,0xe6,0x16,0x57,0x80,0x33,0x7,0x50,0xf3,0x1,0x38,0x0,0x3b,0xa0,0xc7,0xd8,0x2b,0x20,0xae,0x56,0xab,0xd7,0xe5,0x72,0xd9,0xe4,0x9c,0x23,0x57,0x4c,0x44,0xfa,0xed,0x76,0xbb,0xde,0x6c,0x36,0xef,0x40,0x16,0x2b,0x7b,0x5e,0xd7,0x75,0xd3,0x75,0x5d,0xcc,0x39,0xa3,0xaa,0xbf,0x3e,0x76,0xce,0x21,0x22,0xb1,0xae,0xeb,0x6,0xf8,0x0,0xf6,0x67,0x9,0x29,0xa5,0x98,0x52,0xba,0x46,0x8e,0xaa,0x92,0x52,0x22,0xa5,0x14,0x4d,0xea,0x4c,0xac,0x61,0x55,0x29,0xe5,0x22,0xf3,0x4f,0x2b,0xa5,0x60,0xd2,0x83,0x58,0xb7,0x9d,0xaa,0x4e,0x17,0x7f,0x9a,0x11,0x39,0xc0,0xcb,0x24,0xef,0x81,0xa,0xdc,0xf4,0xb,0xe7,0xc3,0x3b,0x1,0xf8,0xa,0xa0,0xaa,0x7a,0x33,0x80,0xe5,0xe9,0x4,0x50,0x0,0x2d,0xa5,0xdc,0xdc,0x3,0xcb,0x53,0xa0,0x88,0x8d,0xe7,0xf0,0x40,0x5,0x3,0x30,0x7a,0x9b,0xed,0x83,0xf7,0xbe,0xf,0x21,0x30,0x1,0x5d,0xf2,0x10,0x2,0xde,0xfb,0xde,0x46,0xfa,0x24,0xb6,0x18,0xbb,0xb6,0x6d,0xd7,0x8b,0xc5,0xa2,0x19,0xc7,0x31,0x5e,0x9b,0xc4,0x10,0x42,0xd7,0xb6,0xed,0x9b,0xed,0xc3,0xd1,0x1,0xcf,0xff,0x58,0xa6,0x83,0x98,0x4,0x80,0xc,0xec,0xef,0x5d,0xe7,0x4f,0x9b,0xaf,0xbc,0xfd,0x3c,0x63,0x97,0x76,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+};
+
+
+static const unsigned char button_focus_png[]={
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0xa,0x45,0x69,0x43,0x43,0x50,0x49,0x43,0x43,0x20,0x70,0x72,0x6f,0x66,0x69,0x6c,0x65,0x0,0x0,0x78,0xda,0x9d,0x53,0x67,0x54,0x53,0xe9,0x16,0x3d,0xf7,0xde,0xf4,0x42,0x4b,0x88,0x80,0x94,0x4b,0x6f,0x52,0x15,0x8,0x20,0x52,0x42,0x8b,0x80,0x14,0x91,0x26,0x2a,0x21,0x9,0x10,0x4a,0x88,0x21,0xa1,0xd9,0x15,0x51,0xc1,0x11,0x45,0x45,0x4,0x1b,0xc8,0xa0,0x88,0x3,0x8e,0x8e,0x80,0x8c,0x15,0x51,0x2c,0xc,0x8a,0xa,0xd8,0x7,0xe4,0x21,0xa2,0x8e,0x83,0xa3,0x88,0x8a,0xca,0xfb,0xe1,0x7b,0xa3,0x6b,0xd6,0xbc,0xf7,0xe6,0xcd,0xfe,0xb5,0xd7,0x3e,0xe7,0xac,0xf3,0x9d,0xb3,0xcf,0x7,0xc0,0x8,0xc,0x96,0x48,0x33,0x51,0x35,0x80,0xc,0xa9,0x42,0x1e,0x11,0xe0,0x83,0xc7,0xc4,0xc6,0xe1,0xe4,0x2e,0x40,0x81,0xa,0x24,0x70,0x0,0x10,0x8,0xb3,0x64,0x21,0x73,0xfd,0x23,0x1,0x0,0xf8,0x7e,0x3c,0x3c,0x2b,0x22,0xc0,0x7,0xbe,0x0,0x1,0x78,0xd3,0xb,0x8,0x0,0xc0,0x4d,0x9b,0xc0,0x30,0x1c,0x87,0xff,0xf,0xea,0x42,0x99,0x5c,0x1,0x80,0x84,0x1,0xc0,0x74,0x91,0x38,0x4b,0x8,0x80,0x14,0x0,0x40,0x7a,0x8e,0x42,0xa6,0x0,0x40,0x46,0x1,0x80,0x9d,0x98,0x26,0x53,0x0,0xa0,0x4,0x0,0x60,0xcb,0x63,0x62,0xe3,0x0,0x50,0x2d,0x0,0x60,0x27,0x7f,0xe6,0xd3,0x0,0x80,0x9d,0xf8,0x99,0x7b,0x1,0x0,0x5b,0x94,0x21,0x15,0x1,0xa0,0x91,0x0,0x20,0x13,0x65,0x88,0x44,0x0,0x68,0x3b,0x0,0xac,0xcf,0x56,0x8a,0x45,0x0,0x58,0x30,0x0,0x14,0x66,0x4b,0xc4,0x39,0x0,0xd8,0x2d,0x0,0x30,0x49,0x57,0x66,0x48,0x0,0xb0,0xb7,0x0,0xc0,0xce,0x10,0xb,0xb2,0x0,0x8,0xc,0x0,0x30,0x51,0x88,0x85,0x29,0x0,0x4,0x7b,0x0,0x60,0xc8,0x23,0x23,0x78,0x0,0x84,0x99,0x0,0x14,0x46,0xf2,0x57,0x3c,0xf1,0x2b,0xae,0x10,0xe7,0x2a,0x0,0x0,0x78,0x99,0xb2,0x3c,0xb9,0x24,0x39,0x45,0x81,0x5b,0x8,0x2d,0x71,0x7,0x57,0x57,0x2e,0x1e,0x28,0xce,0x49,0x17,0x2b,0x14,0x36,0x61,0x2,0x61,0x9a,0x40,0x2e,0xc2,0x79,0x99,0x19,0x32,0x81,0x34,0xf,0xe0,0xf3,0xcc,0x0,0x0,0xa0,0x91,0x15,0x11,0xe0,0x83,0xf3,0xfd,0x78,0xce,0xe,0xae,0xce,0xce,0x36,0x8e,0xb6,0xe,0x5f,0x2d,0xea,0xbf,0x6,0xff,0x22,0x62,0x62,0xe3,0xfe,0xe5,0xcf,0xab,0x70,0x40,0x0,0x0,0xe1,0x74,0x7e,0xd1,0xfe,0x2c,0x2f,0xb3,0x1a,0x80,0x3b,0x6,0x80,0x6d,0xfe,0xa2,0x25,0xee,0x4,0x68,0x5e,0xb,0xa0,0x75,0xf7,0x8b,0x66,0xb2,0xf,0x40,0xb5,0x0,0xa0,0xe9,0xda,0x57,0xf3,0x70,0xf8,0x7e,0x3c,0x3c,0x45,0xa1,0x90,0xb9,0xd9,0xd9,0xe5,0xe4,0xe4,0xd8,0x4a,0xc4,0x42,0x5b,0x61,0xca,0x57,0x7d,0xfe,0x67,0xc2,0x5f,0xc0,0x57,0xfd,0x6c,0xf9,0x7e,0x3c,0xfc,0xf7,0xf5,0xe0,0xbe,0xe2,0x24,0x81,0x32,0x5d,0x81,0x47,0x4,0xf8,0xe0,0xc2,0xcc,0xf4,0x4c,0xa5,0x1c,0xcf,0x92,0x9,0x84,0x62,0xdc,0xe6,0x8f,0x47,0xfc,0xb7,0xb,0xff,0xfc,0x1d,0xd3,0x22,0xc4,0x49,0x62,0xb9,0x58,0x2a,0x14,0xe3,0x51,0x12,0x71,0x8e,0x44,0x9a,0x8c,0xf3,0x32,0xa5,0x22,0x89,0x42,0x92,0x29,0xc5,0x25,0xd2,0xff,0x64,0xe2,0xdf,0x2c,0xfb,0x3,0x3e,0xdf,0x35,0x0,0xb0,0x6a,0x3e,0x1,0x7b,0x91,0x2d,0xa8,0x5d,0x63,0x3,0xf6,0x4b,0x27,0x10,0x58,0x74,0xc0,0xe2,0xf7,0x0,0x0,0xf2,0xbb,0x6f,0xc1,0xd4,0x28,0x8,0x3,0x80,0x68,0x83,0xe1,0xcf,0x77,0xff,0xef,0x3f,0xfd,0x47,0xa0,0x25,0x0,0x80,0x66,0x49,0x92,0x71,0x0,0x0,0x5e,0x44,0x24,0x2e,0x54,0xca,0xb3,0x3f,0xc7,0x8,0x0,0x0,0x44,0xa0,0x81,0x2a,0xb0,0x41,0x1b,0xf4,0xc1,0x18,0x2c,0xc0,0x6,0x1c,0xc1,0x5,0xdc,0xc1,0xb,0xfc,0x60,0x36,0x84,0x42,0x24,0xc4,0xc2,0x42,0x10,0x42,0xa,0x64,0x80,0x1c,0x72,0x60,0x29,0xac,0x82,0x42,0x28,0x86,0xcd,0xb0,0x1d,0x2a,0x60,0x2f,0xd4,0x40,0x1d,0x34,0xc0,0x51,0x68,0x86,0x93,0x70,0xe,0x2e,0xc2,0x55,0xb8,0xe,0x3d,0x70,0xf,0xfa,0x61,0x8,0x9e,0xc1,0x28,0xbc,0x81,0x9,0x4,0x41,0xc8,0x8,0x13,0x61,0x21,0xda,0x88,0x1,0x62,0x8a,0x58,0x23,0x8e,0x8,0x17,0x99,0x85,0xf8,0x21,0xc1,0x48,0x4,0x12,0x8b,0x24,0x20,0xc9,0x88,0x14,0x51,0x22,0x4b,0x91,0x35,0x48,0x31,0x52,0x8a,0x54,0x20,0x55,0x48,0x1d,0xf2,0x3d,0x72,0x2,0x39,0x87,0x5c,0x46,0xba,0x91,0x3b,0xc8,0x0,0x32,0x82,0xfc,0x86,0xbc,0x47,0x31,0x94,0x81,0xb2,0x51,0x3d,0xd4,0xc,0xb5,0x43,0xb9,0xa8,0x37,0x1a,0x84,0x46,0xa2,0xb,0xd0,0x64,0x74,0x31,0x9a,0x8f,0x16,0xa0,0x9b,0xd0,0x72,0xb4,0x1a,0x3d,0x8c,0x36,0xa1,0xe7,0xd0,0xab,0x68,0xf,0xda,0x8f,0x3e,0x43,0xc7,0x30,0xc0,0xe8,0x18,0x7,0x33,0xc4,0x6c,0x30,0x2e,0xc6,0xc3,0x42,0xb1,0x38,0x2c,0x9,0x93,0x63,0xcb,0xb1,0x22,0xac,0xc,0xab,0xc6,0x1a,0xb0,0x56,0xac,0x3,0xbb,0x89,0xf5,0x63,0xcf,0xb1,0x77,0x4,0x12,0x81,0x45,0xc0,0x9,0x36,0x4,0x77,0x42,0x20,0x61,0x1e,0x41,0x48,0x58,0x4c,0x58,0x4e,0xd8,0x48,0xa8,0x20,0x1c,0x24,0x34,0x11,0xda,0x9,0x37,0x9,0x3,0x84,0x51,0xc2,0x27,0x22,0x93,0xa8,0x4b,0xb4,0x26,0xba,0x11,0xf9,0xc4,0x18,0x62,0x32,0x31,0x87,0x58,0x48,0x2c,0x23,0xd6,0x12,0x8f,0x13,0x2f,0x10,0x7b,0x88,0x43,0xc4,0x37,0x24,0x12,0x89,0x43,0x32,0x27,0xb9,0x90,0x2,0x49,0xb1,0xa4,0x54,0xd2,0x12,0xd2,0x46,0xd2,0x6e,0x52,0x23,0xe9,0x2c,0xa9,0x9b,0x34,0x48,0x1a,0x23,0x93,0xc9,0xda,0x64,0x6b,0xb2,0x7,0x39,0x94,0x2c,0x20,0x2b,0xc8,0x85,0xe4,0x9d,0xe4,0xc3,0xe4,0x33,0xe4,0x1b,0xe4,0x21,0xf2,0x5b,0xa,0x9d,0x62,0x40,0x71,0xa4,0xf8,0x53,0xe2,0x28,0x52,0xca,0x6a,0x4a,0x19,0xe5,0x10,0xe5,0x34,0xe5,0x6,0x65,0x98,0x32,0x41,0x55,0xa3,0x9a,0x52,0xdd,0xa8,0xa1,0x54,0x11,0x35,0x8f,0x5a,0x42,0xad,0xa1,0xb6,0x52,0xaf,0x51,0x87,0xa8,0x13,0x34,0x75,0x9a,0x39,0xcd,0x83,0x16,0x49,0x4b,0xa5,0xad,0xa2,0x95,0xd3,0x1a,0x68,0x17,0x68,0xf7,0x69,0xaf,0xe8,0x74,0xba,0x11,0xdd,0x95,0x1e,0x4e,0x97,0xd0,0x57,0xd2,0xcb,0xe9,0x47,0xe8,0x97,0xe8,0x3,0xf4,0x77,0xc,0xd,0x86,0x15,0x83,0xc7,0x88,0x67,0x28,0x19,0x9b,0x18,0x7,0x18,0x67,0x19,0x77,0x18,0xaf,0x98,0x4c,0xa6,0x19,0xd3,0x8b,0x19,0xc7,0x54,0x30,0x37,0x31,0xeb,0x98,0xe7,0x99,0xf,0x99,0x6f,0x55,0x58,0x2a,0xb6,0x2a,0x7c,0x15,0x91,0xca,0xa,0x95,0x4a,0x95,0x26,0x95,0x1b,0x2a,0x2f,0x54,0xa9,0xaa,0xa6,0xaa,0xde,0xaa,0xb,0x55,0xf3,0x55,0xcb,0x54,0x8f,0xa9,0x5e,0x53,0x7d,0xae,0x46,0x55,0x33,0x53,0xe3,0xa9,0x9,0xd4,0x96,0xab,0x55,0xaa,0x9d,0x50,0xeb,0x53,0x1b,0x53,0x67,0xa9,0x3b,0xa8,0x87,0xaa,0x67,0xa8,0x6f,0x54,0x3f,0xa4,0x7e,0x59,0xfd,0x89,0x6,0x59,0xc3,0x4c,0xc3,0x4f,0x43,0xa4,0x51,0xa0,0xb1,0x5f,0xe3,0xbc,0xc6,0x20,0xb,0x63,0x19,0xb3,0x78,0x2c,0x21,0x6b,0xd,0xab,0x86,0x75,0x81,0x35,0xc4,0x26,0xb1,0xcd,0xd9,0x7c,0x76,0x2a,0xbb,0x98,0xfd,0x1d,0xbb,0x8b,0x3d,0xaa,0xa9,0xa1,0x39,0x43,0x33,0x4a,0x33,0x57,0xb3,0x52,0xf3,0x94,0x66,0x3f,0x7,0xe3,0x98,0x71,0xf8,0x9c,0x74,0x4e,0x9,0xe7,0x28,0xa7,0x97,0xf3,0x7e,0x8a,0xde,0x14,0xef,0x29,0xe2,0x29,0x1b,0xa6,0x34,0x4c,0xb9,0x31,0x65,0x5c,0x6b,0xaa,0x96,0x97,0x96,0x58,0xab,0x48,0xab,0x51,0xab,0x47,0xeb,0xbd,0x36,0xae,0xed,0xa7,0x9d,0xa6,0xbd,0x45,0xbb,0x59,0xfb,0x81,0xe,0x41,0xc7,0x4a,0x27,0x5c,0x27,0x47,0x67,0x8f,0xce,0x5,0x9d,0xe7,0x53,0xd9,0x53,0xdd,0xa7,0xa,0xa7,0x16,0x4d,0x3d,0x3a,0xf5,0xae,0x2e,0xaa,0x6b,0xa5,0x1b,0xa1,0xbb,0x44,0x77,0xbf,0x6e,0xa7,0xee,0x98,0x9e,0xbe,0x5e,0x80,0x9e,0x4c,0x6f,0xa7,0xde,0x79,0xbd,0xe7,0xfa,0x1c,0x7d,0x2f,0xfd,0x54,0xfd,0x6d,0xfa,0xa7,0xf5,0x47,0xc,0x58,0x6,0xb3,0xc,0x24,0x6,0xdb,0xc,0xce,0x18,0x3c,0xc5,0x35,0x71,0x6f,0x3c,0x1d,0x2f,0xc7,0xdb,0xf1,0x51,0x43,0x5d,0xc3,0x40,0x43,0xa5,0x61,0x95,0x61,0x97,0xe1,0x84,0x91,0xb9,0xd1,0x3c,0xa3,0xd5,0x46,0x8d,0x46,0xf,0x8c,0x69,0xc6,0x5c,0xe3,0x24,0xe3,0x6d,0xc6,0x6d,0xc6,0xa3,0x26,0x6,0x26,0x21,0x26,0x4b,0x4d,0xea,0x4d,0xee,0x9a,0x52,0x4d,0xb9,0xa6,0x29,0xa6,0x3b,0x4c,0x3b,0x4c,0xc7,0xcd,0xcc,0xcd,0xa2,0xcd,0xd6,0x99,0x35,0x9b,0x3d,0x31,0xd7,0x32,0xe7,0x9b,0xe7,0x9b,0xd7,0x9b,0xdf,0xb7,0x60,0x5a,0x78,0x5a,0x2c,0xb6,0xa8,0xb6,0xb8,0x65,0x49,0xb2,0xe4,0x5a,0xa6,0x59,0xee,0xb6,0xbc,0x6e,0x85,0x5a,0x39,0x59,0xa5,0x58,0x55,0x5a,0x5d,0xb3,0x46,0xad,0x9d,0xad,0x25,0xd6,0xbb,0xad,0xbb,0xa7,0x11,0xa7,0xb9,0x4e,0x93,0x4e,0xab,0x9e,0xd6,0x67,0xc3,0xb0,0xf1,0xb6,0xc9,0xb6,0xa9,0xb7,0x19,0xb0,0xe5,0xd8,0x6,0xdb,0xae,0xb6,0x6d,0xb6,0x7d,0x61,0x67,0x62,0x17,0x67,0xb7,0xc5,0xae,0xc3,0xee,0x93,0xbd,0x93,0x7d,0xba,0x7d,0x8d,0xfd,0x3d,0x7,0xd,0x87,0xd9,0xe,0xab,0x1d,0x5a,0x1d,0x7e,0x73,0xb4,0x72,0x14,0x3a,0x56,0x3a,0xde,0x9a,0xce,0x9c,0xee,0x3f,0x7d,0xc5,0xf4,0x96,0xe9,0x2f,0x67,0x58,0xcf,0x10,0xcf,0xd8,0x33,0xe3,0xb6,0x13,0xcb,0x29,0xc4,0x69,0x9d,0x53,0x9b,0xd3,0x47,0x67,0x17,0x67,0xb9,0x73,0x83,0xf3,0x88,0x8b,0x89,0x4b,0x82,0xcb,0x2e,0x97,0x3e,0x2e,0x9b,0x1b,0xc6,0xdd,0xc8,0xbd,0xe4,0x4a,0x74,0xf5,0x71,0x5d,0xe1,0x7a,0xd2,0xf5,0x9d,0x9b,0xb3,0x9b,0xc2,0xed,0xa8,0xdb,0xaf,0xee,0x36,0xee,0x69,0xee,0x87,0xdc,0x9f,0xcc,0x34,0x9f,0x29,0x9e,0x59,0x33,0x73,0xd0,0xc3,0xc8,0x43,0xe0,0x51,0xe5,0xd1,0x3f,0xb,0x9f,0x95,0x30,0x6b,0xdf,0xac,0x7e,0x4f,0x43,0x4f,0x81,0x67,0xb5,0xe7,0x23,0x2f,0x63,0x2f,0x91,0x57,0xad,0xd7,0xb0,0xb7,0xa5,0x77,0xaa,0xf7,0x61,0xef,0x17,0x3e,0xf6,0x3e,0x72,0x9f,0xe3,0x3e,0xe3,0x3c,0x37,0xde,0x32,0xde,0x59,0x5f,0xcc,0x37,0xc0,0xb7,0xc8,0xb7,0xcb,0x4f,0xc3,0x6f,0x9e,0x5f,0x85,0xdf,0x43,0x7f,0x23,0xff,0x64,0xff,0x7a,0xff,0xd1,0x0,0xa7,0x80,0x25,0x1,0x67,0x3,0x89,0x81,0x41,0x81,0x5b,0x2,0xfb,0xf8,0x7a,0x7c,0x21,0xbf,0x8e,0x3f,0x3a,0xdb,0x65,0xf6,0xb2,0xd9,0xed,0x41,0x8c,0xa0,0xb9,0x41,0x15,0x41,0x8f,0x82,0xad,0x82,0xe5,0xc1,0xad,0x21,0x68,0xc8,0xec,0x90,0xad,0x21,0xf7,0xe7,0x98,0xce,0x91,0xce,0x69,0xe,0x85,0x50,0x7e,0xe8,0xd6,0xd0,0x7,0x61,0xe6,0x61,0x8b,0xc3,0x7e,0xc,0x27,0x85,0x87,0x85,0x57,0x86,0x3f,0x8e,0x70,0x88,0x58,0x1a,0xd1,0x31,0x97,0x35,0x77,0xd1,0xdc,0x43,0x73,0xdf,0x44,0xfa,0x44,0x96,0x44,0xde,0x9b,0x67,0x31,0x4f,0x39,0xaf,0x2d,0x4a,0x35,0x2a,0x3e,0xaa,0x2e,0x6a,0x3c,0xda,0x37,0xba,0x34,0xba,0x3f,0xc6,0x2e,0x66,0x59,0xcc,0xd5,0x58,0x9d,0x58,0x49,0x6c,0x4b,0x1c,0x39,0x2e,0x2a,0xae,0x36,0x6e,0x6c,0xbe,0xdf,0xfc,0xed,0xf3,0x87,0xe2,0x9d,0xe2,0xb,0xe3,0x7b,0x17,0x98,0x2f,0xc8,0x5d,0x70,0x79,0xa1,0xce,0xc2,0xf4,0x85,0xa7,0x16,0xa9,0x2e,0x12,0x2c,0x3a,0x96,0x40,0x4c,0x88,0x4e,0x38,0x94,0xf0,0x41,0x10,0x2a,0xa8,0x16,0x8c,0x25,0xf2,0x13,0x77,0x25,0x8e,0xa,0x79,0xc2,0x1d,0xc2,0x67,0x22,0x2f,0xd1,0x36,0xd1,0x88,0xd8,0x43,0x5c,0x2a,0x1e,0x4e,0xf2,0x48,0x2a,0x4d,0x7a,0x92,0xec,0x91,0xbc,0x35,0x79,0x24,0xc5,0x33,0xa5,0x2c,0xe5,0xb9,0x84,0x27,0xa9,0x90,0xbc,0x4c,0xd,0x4c,0xdd,0x9b,0x3a,0x9e,0x16,0x9a,0x76,0x20,0x6d,0x32,0x3d,0x3a,0xbd,0x31,0x83,0x92,0x91,0x90,0x71,0x42,0xaa,0x21,0x4d,0x93,0xb6,0x67,0xea,0x67,0xe6,0x66,0x76,0xcb,0xac,0x65,0x85,0xb2,0xfe,0xc5,0x6e,0x8b,0xb7,0x2f,0x1e,0x95,0x7,0xc9,0x6b,0xb3,0x90,0xac,0x5,0x59,0x2d,0xa,0xb6,0x42,0xa6,0xe8,0x54,0x5a,0x28,0xd7,0x2a,0x7,0xb2,0x67,0x65,0x57,0x66,0xbf,0xcd,0x89,0xca,0x39,0x96,0xab,0x9e,0x2b,0xcd,0xed,0xcc,0xb3,0xca,0xdb,0x90,0x37,0x9c,0xef,0x9f,0xff,0xed,0x12,0xc2,0x12,0xe1,0x92,0xb6,0xa5,0x86,0x4b,0x57,0x2d,0x1d,0x58,0xe6,0xbd,0xac,0x6a,0x39,0xb2,0x3c,0x71,0x79,0xdb,0xa,0xe3,0x15,0x5,0x2b,0x86,0x56,0x6,0xac,0x3c,0xb8,0x8a,0xb6,0x2a,0x6d,0xd5,0x4f,0xab,0xed,0x57,0x97,0xae,0x7e,0xbd,0x26,0x7a,0x4d,0x6b,0x81,0x5e,0xc1,0xca,0x82,0xc1,0xb5,0x1,0x6b,0xeb,0xb,0x55,0xa,0xe5,0x85,0x7d,0xeb,0xdc,0xd7,0xed,0x5d,0x4f,0x58,0x2f,0x59,0xdf,0xb5,0x61,0xfa,0x86,0x9d,0x1b,0x3e,0x15,0x89,0x8a,0xae,0x14,0xdb,0x17,0x97,0x15,0x7f,0xd8,0x28,0xdc,0x78,0xe5,0x1b,0x87,0x6f,0xca,0xbf,0x99,0xdc,0x94,0xb4,0xa9,0xab,0xc4,0xb9,0x64,0xcf,0x66,0xd2,0x66,0xe9,0xe6,0xde,0x2d,0x9e,0x5b,0xe,0x96,0xaa,0x97,0xe6,0x97,0xe,0x6e,0xd,0xd9,0xda,0xb4,0xd,0xdf,0x56,0xb4,0xed,0xf5,0xf6,0x45,0xdb,0x2f,0x97,0xcd,0x28,0xdb,0xbb,0x83,0xb6,0x43,0xb9,0xa3,0xbf,0x3c,0xb8,0xbc,0x65,0xa7,0xc9,0xce,0xcd,0x3b,0x3f,0x54,0xa4,0x54,0xf4,0x54,0xfa,0x54,0x36,0xee,0xd2,0xdd,0xb5,0x61,0xd7,0xf8,0x6e,0xd1,0xee,0x1b,0x7b,0xbc,0xf6,0x34,0xec,0xd5,0xdb,0x5b,0xbc,0xf7,0xfd,0x3e,0xc9,0xbe,0xdb,0x55,0x1,0x55,0x4d,0xd5,0x66,0xd5,0x65,0xfb,0x49,0xfb,0xb3,0xf7,0x3f,0xae,0x89,0xaa,0xe9,0xf8,0x96,0xfb,0x6d,0x5d,0xad,0x4e,0x6d,0x71,0xed,0xc7,0x3,0xd2,0x3,0xfd,0x7,0x23,0xe,0xb6,0xd7,0xb9,0xd4,0xd5,0x1d,0xd2,0x3d,0x54,0x52,0x8f,0xd6,0x2b,0xeb,0x47,0xe,0xc7,0x1f,0xbe,0xfe,0x9d,0xef,0x77,0x2d,0xd,0x36,0xd,0x55,0x8d,0x9c,0xc6,0xe2,0x23,0x70,0x44,0x79,0xe4,0xe9,0xf7,0x9,0xdf,0xf7,0x1e,0xd,0x3a,0xda,0x76,0x8c,0x7b,0xac,0xe1,0x7,0xd3,0x1f,0x76,0x1d,0x67,0x1d,0x2f,0x6a,0x42,0x9a,0xf2,0x9a,0x46,0x9b,0x53,0x9a,0xfb,0x5b,0x62,0x5b,0xba,0x4f,0xcc,0x3e,0xd1,0xd6,0xea,0xde,0x7a,0xfc,0x47,0xdb,0x1f,0xf,0x9c,0x34,0x3c,0x59,0x79,0x4a,0xf3,0x54,0xc9,0x69,0xda,0xe9,0x82,0xd3,0x93,0x67,0xf2,0xcf,0x8c,0x9d,0x95,0x9d,0x7d,0x7e,0x2e,0xf9,0xdc,0x60,0xdb,0xa2,0xb6,0x7b,0xe7,0x63,0xce,0xdf,0x6a,0xf,0x6f,0xef,0xba,0x10,0x74,0xe1,0xd2,0x45,0xff,0x8b,0xe7,0x3b,0xbc,0x3b,0xce,0x5c,0xf2,0xb8,0x74,0xf2,0xb2,0xdb,0xe5,0x13,0x57,0xb8,0x57,0x9a,0xaf,0x3a,0x5f,0x6d,0xea,0x74,0xea,0x3c,0xfe,0x93,0xd3,0x4f,0xc7,0xbb,0x9c,0xbb,0x9a,0xae,0xb9,0x5c,0x6b,0xb9,0xee,0x7a,0xbd,0xb5,0x7b,0x66,0xf7,0xe9,0x1b,0x9e,0x37,0xce,0xdd,0xf4,0xbd,0x79,0xf1,0x16,0xff,0xd6,0xd5,0x9e,0x39,0x3d,0xdd,0xbd,0xf3,0x7a,0x6f,0xf7,0xc5,0xf7,0xf5,0xdf,0x16,0xdd,0x7e,0x72,0x27,0xfd,0xce,0xcb,0xbb,0xd9,0x77,0x27,0xee,0xad,0xbc,0x4f,0xbc,0x5f,0xf4,0x40,0xed,0x41,0xd9,0x43,0xdd,0x87,0xd5,0x3f,0x5b,0xfe,0xdc,0xd8,0xef,0xdc,0x7f,0x6a,0xc0,0x77,0xa0,0xf3,0xd1,0xdc,0x47,0xf7,0x6,0x85,0x83,0xcf,0xfe,0x91,0xf5,0x8f,0xf,0x43,0x5,0x8f,0x99,0x8f,0xcb,0x86,0xd,0x86,0xeb,0x9e,0x38,0x3e,0x39,0x39,0xe2,0x3f,0x72,0xfd,0xe9,0xfc,0xa7,0x43,0xcf,0x64,0xcf,0x26,0x9e,0x17,0xfe,0xa2,0xfe,0xcb,0xae,0x17,0x16,0x2f,0x7e,0xf8,0xd5,0xeb,0xd7,0xce,0xd1,0x98,0xd1,0xa1,0x97,0xf2,0x97,0x93,0xbf,0x6d,0x7c,0xa5,0xfd,0xea,0xc0,0xeb,0x19,0xaf,0xdb,0xc6,0xc2,0xc6,0x1e,0xbe,0xc9,0x78,0x33,0x31,0x5e,0xf4,0x56,0xfb,0xed,0xc1,0x77,0xdc,0x77,0x1d,0xef,0xa3,0xdf,0xf,0x4f,0xe4,0x7c,0x20,0x7f,0x28,0xff,0x68,0xf9,0xb1,0xf5,0x53,0xd0,0xa7,0xfb,0x93,0x19,0x93,0x93,0xff,0x4,0x3,0x98,0xf3,0xfc,0xef,0x35,0x94,0x82,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xa,0x14,0x2,0x27,0xa,0x83,0xe3,0x53,0x26,0x0,0x0,0x0,0xaf,0x49,0x44,0x41,0x54,0x38,0xcb,0xcd,0xd2,0x31,0xe,0x1,0x41,0x18,0xc5,0xf1,0x1f,0x51,0xd0,0x28,0x5c,0x83,0x44,0xaf,0x53,0xed,0x19,0x68,0x89,0x13,0x38,0xc6,0x9e,0x0,0x17,0x51,0x6d,0x45,0x2f,0xe1,0x1a,0x12,0x1a,0x34,0x4b,0x33,0x9b,0x6c,0x36,0xbb,0xac,0x8a,0xd7,0xcc,0x4c,0xbe,0xf7,0xfe,0x33,0x93,0x3c,0x7e,0xad,0x46,0xb6,0x89,0xe2,0xa4,0x8b,0x3e,0x86,0xe8,0xe5,0x67,0x41,0x4f,0x9c,0x71,0xc0,0x69,0xbb,0x1c,0x5f,0xa1,0x95,0x33,0xc,0x30,0xc2,0x6,0xf7,0x8a,0xb,0xdb,0x98,0x7,0xf8,0xbe,0x8,0x18,0x62,0xbd,0x5d,0x8e,0x2f,0x6f,0x5e,0x7c,0x8f,0xe2,0x64,0x8d,0x69,0x6,0x68,0xe6,0x86,0x3d,0xdc,0x6a,0x7c,0xfb,0x16,0xbc,0x8a,0x80,0xb2,0x73,0x99,0x9a,0xdf,0x6,0xea,0xd3,0xfe,0x2,0x90,0xd6,0xc8,0xa4,0x55,0x80,0x33,0x3a,0x35,0x0,0xed,0xe0,0x55,0xec,0xc1,0x1,0x8b,0x28,0x4e,0x56,0x78,0x54,0x84,0x3b,0x98,0x65,0x1d,0x28,0x2,0x8e,0x61,0x9d,0x7c,0xa8,0xf2,0xe,0x27,0x7f,0xa3,0x17,0x70,0x92,0x23,0xf,0xde,0x2f,0xa7,0x24,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char button_hover_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x4c,0x0,0x4a,0x0,0x4e,0x88,0x29,0x6a,0xb6,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x10,0x13,0x3b,0xf,0xb,0x84,0xd,0x91,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0xba,0x49,0x44,0x41,0x54,0x38,0x8d,0xed,0xd3,0xb1,0x4e,0xc3,0x40,0x10,0x84,0xe1,0xef,0xc2,0x4a,0x9c,0x90,0xb,0x6a,0x9f,0xe0,0x9,0x2,0xbc,0x58,0xc2,0xcb,0xc0,0x8b,0x85,0xa4,0xa6,0x41,0x4e,0x4d,0x41,0x71,0x91,0xe,0x99,0x2,0xd7,0x76,0xa4,0x34,0x14,0x6c,0xb9,0xda,0xf9,0x47,0x2b,0xcd,0x24,0xdc,0xe0,0x16,0x1d,0xae,0x90,0xcc,0xcf,0x88,0x6f,0x7c,0xe1,0x33,0x26,0xf1,0x23,0xee,0x90,0xcf,0x4,0x54,0x7c,0xe0,0x2d,0x26,0xe7,0xfb,0x87,0xf5,0xd3,0xba,0xf4,0x65,0x13,0x11,0xb3,0x80,0xd6,0xda,0x38,0x1c,0x87,0xd7,0xfd,0x61,0x97,0xf0,0x1e,0x8,0x5c,0x97,0xbe,0x6c,0x6b,0xad,0x6a,0xad,0xb3,0xf6,0x39,0xe7,0x54,0xfa,0xb2,0xdd,0x1f,0x76,0xcf,0x88,0xd5,0xb4,0x4f,0x11,0xb1,0x28,0x86,0x5a,0xab,0x88,0x60,0x7a,0x75,0x35,0x7f,0xbe,0x3c,0xff,0x80,0xbf,0x4,0x18,0x5b,0x6b,0x72,0xce,0x8b,0x82,0x9c,0xb3,0xd6,0x1a,0xbf,0x91,0x16,0x68,0x38,0xd,0xc7,0xe1,0xa5,0xf4,0x65,0xd3,0x75,0xdd,0x59,0x51,0xc6,0x9,0x2d,0xa1,0x77,0x41,0x99,0x92,0xb,0xeb,0xfc,0x3,0xd0,0xc5,0x44,0x36,0x1d,0x79,0x84,0xde,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0xa,0x45,0x69,0x43,0x43,0x50,0x49,0x43,0x43,0x20,0x70,0x72,0x6f,0x66,0x69,0x6c,0x65,0x0,0x0,0x78,0xda,0x9d,0x53,0x67,0x54,0x53,0xe9,0x16,0x3d,0xf7,0xde,0xf4,0x42,0x4b,0x88,0x80,0x94,0x4b,0x6f,0x52,0x15,0x8,0x20,0x52,0x42,0x8b,0x80,0x14,0x91,0x26,0x2a,0x21,0x9,0x10,0x4a,0x88,0x21,0xa1,0xd9,0x15,0x51,0xc1,0x11,0x45,0x45,0x4,0x1b,0xc8,0xa0,0x88,0x3,0x8e,0x8e,0x80,0x8c,0x15,0x51,0x2c,0xc,0x8a,0xa,0xd8,0x7,0xe4,0x21,0xa2,0x8e,0x83,0xa3,0x88,0x8a,0xca,0xfb,0xe1,0x7b,0xa3,0x6b,0xd6,0xbc,0xf7,0xe6,0xcd,0xfe,0xb5,0xd7,0x3e,0xe7,0xac,0xf3,0x9d,0xb3,0xcf,0x7,0xc0,0x8,0xc,0x96,0x48,0x33,0x51,0x35,0x80,0xc,0xa9,0x42,0x1e,0x11,0xe0,0x83,0xc7,0xc4,0xc6,0xe1,0xe4,0x2e,0x40,0x81,0xa,0x24,0x70,0x0,0x10,0x8,0xb3,0x64,0x21,0x73,0xfd,0x23,0x1,0x0,0xf8,0x7e,0x3c,0x3c,0x2b,0x22,0xc0,0x7,0xbe,0x0,0x1,0x78,0xd3,0xb,0x8,0x0,0xc0,0x4d,0x9b,0xc0,0x30,0x1c,0x87,0xff,0xf,0xea,0x42,0x99,0x5c,0x1,0x80,0x84,0x1,0xc0,0x74,0x91,0x38,0x4b,0x8,0x80,0x14,0x0,0x40,0x7a,0x8e,0x42,0xa6,0x0,0x40,0x46,0x1,0x80,0x9d,0x98,0x26,0x53,0x0,0xa0,0x4,0x0,0x60,0xcb,0x63,0x62,0xe3,0x0,0x50,0x2d,0x0,0x60,0x27,0x7f,0xe6,0xd3,0x0,0x80,0x9d,0xf8,0x99,0x7b,0x1,0x0,0x5b,0x94,0x21,0x15,0x1,0xa0,0x91,0x0,0x20,0x13,0x65,0x88,0x44,0x0,0x68,0x3b,0x0,0xac,0xcf,0x56,0x8a,0x45,0x0,0x58,0x30,0x0,0x14,0x66,0x4b,0xc4,0x39,0x0,0xd8,0x2d,0x0,0x30,0x49,0x57,0x66,0x48,0x0,0xb0,0xb7,0x0,0xc0,0xce,0x10,0xb,0xb2,0x0,0x8,0xc,0x0,0x30,0x51,0x88,0x85,0x29,0x0,0x4,0x7b,0x0,0x60,0xc8,0x23,0x23,0x78,0x0,0x84,0x99,0x0,0x14,0x46,0xf2,0x57,0x3c,0xf1,0x2b,0xae,0x10,0xe7,0x2a,0x0,0x0,0x78,0x99,0xb2,0x3c,0xb9,0x24,0x39,0x45,0x81,0x5b,0x8,0x2d,0x71,0x7,0x57,0x57,0x2e,0x1e,0x28,0xce,0x49,0x17,0x2b,0x14,0x36,0x61,0x2,0x61,0x9a,0x40,0x2e,0xc2,0x79,0x99,0x19,0x32,0x81,0x34,0xf,0xe0,0xf3,0xcc,0x0,0x0,0xa0,0x91,0x15,0x11,0xe0,0x83,0xf3,0xfd,0x78,0xce,0xe,0xae,0xce,0xce,0x36,0x8e,0xb6,0xe,0x5f,0x2d,0xea,0xbf,0x6,0xff,0x22,0x62,0x62,0xe3,0xfe,0xe5,0xcf,0xab,0x70,0x40,0x0,0x0,0xe1,0x74,0x7e,0xd1,0xfe,0x2c,0x2f,0xb3,0x1a,0x80,0x3b,0x6,0x80,0x6d,0xfe,0xa2,0x25,0xee,0x4,0x68,0x5e,0xb,0xa0,0x75,0xf7,0x8b,0x66,0xb2,0xf,0x40,0xb5,0x0,0xa0,0xe9,0xda,0x57,0xf3,0x70,0xf8,0x7e,0x3c,0x3c,0x45,0xa1,0x90,0xb9,0xd9,0xd9,0xe5,0xe4,0xe4,0xd8,0x4a,0xc4,0x42,0x5b,0x61,0xca,0x57,0x7d,0xfe,0x67,0xc2,0x5f,0xc0,0x57,0xfd,0x6c,0xf9,0x7e,0x3c,0xfc,0xf7,0xf5,0xe0,0xbe,0xe2,0x24,0x81,0x32,0x5d,0x81,0x47,0x4,0xf8,0xe0,0xc2,0xcc,0xf4,0x4c,0xa5,0x1c,0xcf,0x92,0x9,0x84,0x62,0xdc,0xe6,0x8f,0x47,0xfc,0xb7,0xb,0xff,0xfc,0x1d,0xd3,0x22,0xc4,0x49,0x62,0xb9,0x58,0x2a,0x14,0xe3,0x51,0x12,0x71,0x8e,0x44,0x9a,0x8c,0xf3,0x32,0xa5,0x22,0x89,0x42,0x92,0x29,0xc5,0x25,0xd2,0xff,0x64,0xe2,0xdf,0x2c,0xfb,0x3,0x3e,0xdf,0x35,0x0,0xb0,0x6a,0x3e,0x1,0x7b,0x91,0x2d,0xa8,0x5d,0x63,0x3,0xf6,0x4b,0x27,0x10,0x58,0x74,0xc0,0xe2,0xf7,0x0,0x0,0xf2,0xbb,0x6f,0xc1,0xd4,0x28,0x8,0x3,0x80,0x68,0x83,0xe1,0xcf,0x77,0xff,0xef,0x3f,0xfd,0x47,0xa0,0x25,0x0,0x80,0x66,0x49,0x92,0x71,0x0,0x0,0x5e,0x44,0x24,0x2e,0x54,0xca,0xb3,0x3f,0xc7,0x8,0x0,0x0,0x44,0xa0,0x81,0x2a,0xb0,0x41,0x1b,0xf4,0xc1,0x18,0x2c,0xc0,0x6,0x1c,0xc1,0x5,0xdc,0xc1,0xb,0xfc,0x60,0x36,0x84,0x42,0x24,0xc4,0xc2,0x42,0x10,0x42,0xa,0x64,0x80,0x1c,0x72,0x60,0x29,0xac,0x82,0x42,0x28,0x86,0xcd,0xb0,0x1d,0x2a,0x60,0x2f,0xd4,0x40,0x1d,0x34,0xc0,0x51,0x68,0x86,0x93,0x70,0xe,0x2e,0xc2,0x55,0xb8,0xe,0x3d,0x70,0xf,0xfa,0x61,0x8,0x9e,0xc1,0x28,0xbc,0x81,0x9,0x4,0x41,0xc8,0x8,0x13,0x61,0x21,0xda,0x88,0x1,0x62,0x8a,0x58,0x23,0x8e,0x8,0x17,0x99,0x85,0xf8,0x21,0xc1,0x48,0x4,0x12,0x8b,0x24,0x20,0xc9,0x88,0x14,0x51,0x22,0x4b,0x91,0x35,0x48,0x31,0x52,0x8a,0x54,0x20,0x55,0x48,0x1d,0xf2,0x3d,0x72,0x2,0x39,0x87,0x5c,0x46,0xba,0x91,0x3b,0xc8,0x0,0x32,0x82,0xfc,0x86,0xbc,0x47,0x31,0x94,0x81,0xb2,0x51,0x3d,0xd4,0xc,0xb5,0x43,0xb9,0xa8,0x37,0x1a,0x84,0x46,0xa2,0xb,0xd0,0x64,0x74,0x31,0x9a,0x8f,0x16,0xa0,0x9b,0xd0,0x72,0xb4,0x1a,0x3d,0x8c,0x36,0xa1,0xe7,0xd0,0xab,0x68,0xf,0xda,0x8f,0x3e,0x43,0xc7,0x30,0xc0,0xe8,0x18,0x7,0x33,0xc4,0x6c,0x30,0x2e,0xc6,0xc3,0x42,0xb1,0x38,0x2c,0x9,0x93,0x63,0xcb,0xb1,0x22,0xac,0xc,0xab,0xc6,0x1a,0xb0,0x56,0xac,0x3,0xbb,0x89,0xf5,0x63,0xcf,0xb1,0x77,0x4,0x12,0x81,0x45,0xc0,0x9,0x36,0x4,0x77,0x42,0x20,0x61,0x1e,0x41,0x48,0x58,0x4c,0x58,0x4e,0xd8,0x48,0xa8,0x20,0x1c,0x24,0x34,0x11,0xda,0x9,0x37,0x9,0x3,0x84,0x51,0xc2,0x27,0x22,0x93,0xa8,0x4b,0xb4,0x26,0xba,0x11,0xf9,0xc4,0x18,0x62,0x32,0x31,0x87,0x58,0x48,0x2c,0x23,0xd6,0x12,0x8f,0x13,0x2f,0x10,0x7b,0x88,0x43,0xc4,0x37,0x24,0x12,0x89,0x43,0x32,0x27,0xb9,0x90,0x2,0x49,0xb1,0xa4,0x54,0xd2,0x12,0xd2,0x46,0xd2,0x6e,0x52,0x23,0xe9,0x2c,0xa9,0x9b,0x34,0x48,0x1a,0x23,0x93,0xc9,0xda,0x64,0x6b,0xb2,0x7,0x39,0x94,0x2c,0x20,0x2b,0xc8,0x85,0xe4,0x9d,0xe4,0xc3,0xe4,0x33,0xe4,0x1b,0xe4,0x21,0xf2,0x5b,0xa,0x9d,0x62,0x40,0x71,0xa4,0xf8,0x53,0xe2,0x28,0x52,0xca,0x6a,0x4a,0x19,0xe5,0x10,0xe5,0x34,0xe5,0x6,0x65,0x98,0x32,0x41,0x55,0xa3,0x9a,0x52,0xdd,0xa8,0xa1,0x54,0x11,0x35,0x8f,0x5a,0x42,0xad,0xa1,0xb6,0x52,0xaf,0x51,0x87,0xa8,0x13,0x34,0x75,0x9a,0x39,0xcd,0x83,0x16,0x49,0x4b,0xa5,0xad,0xa2,0x95,0xd3,0x1a,0x68,0x17,0x68,0xf7,0x69,0xaf,0xe8,0x74,0xba,0x11,0xdd,0x95,0x1e,0x4e,0x97,0xd0,0x57,0xd2,0xcb,0xe9,0x47,0xe8,0x97,0xe8,0x3,0xf4,0x77,0xc,0xd,0x86,0x15,0x83,0xc7,0x88,0x67,0x28,0x19,0x9b,0x18,0x7,0x18,0x67,0x19,0x77,0x18,0xaf,0x98,0x4c,0xa6,0x19,0xd3,0x8b,0x19,0xc7,0x54,0x30,0x37,0x31,0xeb,0x98,0xe7,0x99,0xf,0x99,0x6f,0x55,0x58,0x2a,0xb6,0x2a,0x7c,0x15,0x91,0xca,0xa,0x95,0x4a,0x95,0x26,0x95,0x1b,0x2a,0x2f,0x54,0xa9,0xaa,0xa6,0xaa,0xde,0xaa,0xb,0x55,0xf3,0x55,0xcb,0x54,0x8f,0xa9,0x5e,0x53,0x7d,0xae,0x46,0x55,0x33,0x53,0xe3,0xa9,0x9,0xd4,0x96,0xab,0x55,0xaa,0x9d,0x50,0xeb,0x53,0x1b,0x53,0x67,0xa9,0x3b,0xa8,0x87,0xaa,0x67,0xa8,0x6f,0x54,0x3f,0xa4,0x7e,0x59,0xfd,0x89,0x6,0x59,0xc3,0x4c,0xc3,0x4f,0x43,0xa4,0x51,0xa0,0xb1,0x5f,0xe3,0xbc,0xc6,0x20,0xb,0x63,0x19,0xb3,0x78,0x2c,0x21,0x6b,0xd,0xab,0x86,0x75,0x81,0x35,0xc4,0x26,0xb1,0xcd,0xd9,0x7c,0x76,0x2a,0xbb,0x98,0xfd,0x1d,0xbb,0x8b,0x3d,0xaa,0xa9,0xa1,0x39,0x43,0x33,0x4a,0x33,0x57,0xb3,0x52,0xf3,0x94,0x66,0x3f,0x7,0xe3,0x98,0x71,0xf8,0x9c,0x74,0x4e,0x9,0xe7,0x28,0xa7,0x97,0xf3,0x7e,0x8a,0xde,0x14,0xef,0x29,0xe2,0x29,0x1b,0xa6,0x34,0x4c,0xb9,0x31,0x65,0x5c,0x6b,0xaa,0x96,0x97,0x96,0x58,0xab,0x48,0xab,0x51,0xab,0x47,0xeb,0xbd,0x36,0xae,0xed,0xa7,0x9d,0xa6,0xbd,0x45,0xbb,0x59,0xfb,0x81,0xe,0x41,0xc7,0x4a,0x27,0x5c,0x27,0x47,0x67,0x8f,0xce,0x5,0x9d,0xe7,0x53,0xd9,0x53,0xdd,0xa7,0xa,0xa7,0x16,0x4d,0x3d,0x3a,0xf5,0xae,0x2e,0xaa,0x6b,0xa5,0x1b,0xa1,0xbb,0x44,0x77,0xbf,0x6e,0xa7,0xee,0x98,0x9e,0xbe,0x5e,0x80,0x9e,0x4c,0x6f,0xa7,0xde,0x79,0xbd,0xe7,0xfa,0x1c,0x7d,0x2f,0xfd,0x54,0xfd,0x6d,0xfa,0xa7,0xf5,0x47,0xc,0x58,0x6,0xb3,0xc,0x24,0x6,0xdb,0xc,0xce,0x18,0x3c,0xc5,0x35,0x71,0x6f,0x3c,0x1d,0x2f,0xc7,0xdb,0xf1,0x51,0x43,0x5d,0xc3,0x40,0x43,0xa5,0x61,0x95,0x61,0x97,0xe1,0x84,0x91,0xb9,0xd1,0x3c,0xa3,0xd5,0x46,0x8d,0x46,0xf,0x8c,0x69,0xc6,0x5c,0xe3,0x24,0xe3,0x6d,0xc6,0x6d,0xc6,0xa3,0x26,0x6,0x26,0x21,0x26,0x4b,0x4d,0xea,0x4d,0xee,0x9a,0x52,0x4d,0xb9,0xa6,0x29,0xa6,0x3b,0x4c,0x3b,0x4c,0xc7,0xcd,0xcc,0xcd,0xa2,0xcd,0xd6,0x99,0x35,0x9b,0x3d,0x31,0xd7,0x32,0xe7,0x9b,0xe7,0x9b,0xd7,0x9b,0xdf,0xb7,0x60,0x5a,0x78,0x5a,0x2c,0xb6,0xa8,0xb6,0xb8,0x65,0x49,0xb2,0xe4,0x5a,0xa6,0x59,0xee,0xb6,0xbc,0x6e,0x85,0x5a,0x39,0x59,0xa5,0x58,0x55,0x5a,0x5d,0xb3,0x46,0xad,0x9d,0xad,0x25,0xd6,0xbb,0xad,0xbb,0xa7,0x11,0xa7,0xb9,0x4e,0x93,0x4e,0xab,0x9e,0xd6,0x67,0xc3,0xb0,0xf1,0xb6,0xc9,0xb6,0xa9,0xb7,0x19,0xb0,0xe5,0xd8,0x6,0xdb,0xae,0xb6,0x6d,0xb6,0x7d,0x61,0x67,0x62,0x17,0x67,0xb7,0xc5,0xae,0xc3,0xee,0x93,0xbd,0x93,0x7d,0xba,0x7d,0x8d,0xfd,0x3d,0x7,0xd,0x87,0xd9,0xe,0xab,0x1d,0x5a,0x1d,0x7e,0x73,0xb4,0x72,0x14,0x3a,0x56,0x3a,0xde,0x9a,0xce,0x9c,0xee,0x3f,0x7d,0xc5,0xf4,0x96,0xe9,0x2f,0x67,0x58,0xcf,0x10,0xcf,0xd8,0x33,0xe3,0xb6,0x13,0xcb,0x29,0xc4,0x69,0x9d,0x53,0x9b,0xd3,0x47,0x67,0x17,0x67,0xb9,0x73,0x83,0xf3,0x88,0x8b,0x89,0x4b,0x82,0xcb,0x2e,0x97,0x3e,0x2e,0x9b,0x1b,0xc6,0xdd,0xc8,0xbd,0xe4,0x4a,0x74,0xf5,0x71,0x5d,0xe1,0x7a,0xd2,0xf5,0x9d,0x9b,0xb3,0x9b,0xc2,0xed,0xa8,0xdb,0xaf,0xee,0x36,0xee,0x69,0xee,0x87,0xdc,0x9f,0xcc,0x34,0x9f,0x29,0x9e,0x59,0x33,0x73,0xd0,0xc3,0xc8,0x43,0xe0,0x51,0xe5,0xd1,0x3f,0xb,0x9f,0x95,0x30,0x6b,0xdf,0xac,0x7e,0x4f,0x43,0x4f,0x81,0x67,0xb5,0xe7,0x23,0x2f,0x63,0x2f,0x91,0x57,0xad,0xd7,0xb0,0xb7,0xa5,0x77,0xaa,0xf7,0x61,0xef,0x17,0x3e,0xf6,0x3e,0x72,0x9f,0xe3,0x3e,0xe3,0x3c,0x37,0xde,0x32,0xde,0x59,0x5f,0xcc,0x37,0xc0,0xb7,0xc8,0xb7,0xcb,0x4f,0xc3,0x6f,0x9e,0x5f,0x85,0xdf,0x43,0x7f,0x23,0xff,0x64,0xff,0x7a,0xff,0xd1,0x0,0xa7,0x80,0x25,0x1,0x67,0x3,0x89,0x81,0x41,0x81,0x5b,0x2,0xfb,0xf8,0x7a,0x7c,0x21,0xbf,0x8e,0x3f,0x3a,0xdb,0x65,0xf6,0xb2,0xd9,0xed,0x41,0x8c,0xa0,0xb9,0x41,0x15,0x41,0x8f,0x82,0xad,0x82,0xe5,0xc1,0xad,0x21,0x68,0xc8,0xec,0x90,0xad,0x21,0xf7,0xe7,0x98,0xce,0x91,0xce,0x69,0xe,0x85,0x50,0x7e,0xe8,0xd6,0xd0,0x7,0x61,0xe6,0x61,0x8b,0xc3,0x7e,0xc,0x27,0x85,0x87,0x85,0x57,0x86,0x3f,0x8e,0x70,0x88,0x58,0x1a,0xd1,0x31,0x97,0x35,0x77,0xd1,0xdc,0x43,0x73,0xdf,0x44,0xfa,0x44,0x96,0x44,0xde,0x9b,0x67,0x31,0x4f,0x39,0xaf,0x2d,0x4a,0x35,0x2a,0x3e,0xaa,0x2e,0x6a,0x3c,0xda,0x37,0xba,0x34,0xba,0x3f,0xc6,0x2e,0x66,0x59,0xcc,0xd5,0x58,0x9d,0x58,0x49,0x6c,0x4b,0x1c,0x39,0x2e,0x2a,0xae,0x36,0x6e,0x6c,0xbe,0xdf,0xfc,0xed,0xf3,0x87,0xe2,0x9d,0xe2,0xb,0xe3,0x7b,0x17,0x98,0x2f,0xc8,0x5d,0x70,0x79,0xa1,0xce,0xc2,0xf4,0x85,0xa7,0x16,0xa9,0x2e,0x12,0x2c,0x3a,0x96,0x40,0x4c,0x88,0x4e,0x38,0x94,0xf0,0x41,0x10,0x2a,0xa8,0x16,0x8c,0x25,0xf2,0x13,0x77,0x25,0x8e,0xa,0x79,0xc2,0x1d,0xc2,0x67,0x22,0x2f,0xd1,0x36,0xd1,0x88,0xd8,0x43,0x5c,0x2a,0x1e,0x4e,0xf2,0x48,0x2a,0x4d,0x7a,0x92,0xec,0x91,0xbc,0x35,0x79,0x24,0xc5,0x33,0xa5,0x2c,0xe5,0xb9,0x84,0x27,0xa9,0x90,0xbc,0x4c,0xd,0x4c,0xdd,0x9b,0x3a,0x9e,0x16,0x9a,0x76,0x20,0x6d,0x32,0x3d,0x3a,0xbd,0x31,0x83,0x92,0x91,0x90,0x71,0x42,0xaa,0x21,0x4d,0x93,0xb6,0x67,0xea,0x67,0xe6,0x66,0x76,0xcb,0xac,0x65,0x85,0xb2,0xfe,0xc5,0x6e,0x8b,0xb7,0x2f,0x1e,0x95,0x7,0xc9,0x6b,0xb3,0x90,0xac,0x5,0x59,0x2d,0xa,0xb6,0x42,0xa6,0xe8,0x54,0x5a,0x28,0xd7,0x2a,0x7,0xb2,0x67,0x65,0x57,0x66,0xbf,0xcd,0x89,0xca,0x39,0x96,0xab,0x9e,0x2b,0xcd,0xed,0xcc,0xb3,0xca,0xdb,0x90,0x37,0x9c,0xef,0x9f,0xff,0xed,0x12,0xc2,0x12,0xe1,0x92,0xb6,0xa5,0x86,0x4b,0x57,0x2d,0x1d,0x58,0xe6,0xbd,0xac,0x6a,0x39,0xb2,0x3c,0x71,0x79,0xdb,0xa,0xe3,0x15,0x5,0x2b,0x86,0x56,0x6,0xac,0x3c,0xb8,0x8a,0xb6,0x2a,0x6d,0xd5,0x4f,0xab,0xed,0x57,0x97,0xae,0x7e,0xbd,0x26,0x7a,0x4d,0x6b,0x81,0x5e,0xc1,0xca,0x82,0xc1,0xb5,0x1,0x6b,0xeb,0xb,0x55,0xa,0xe5,0x85,0x7d,0xeb,0xdc,0xd7,0xed,0x5d,0x4f,0x58,0x2f,0x59,0xdf,0xb5,0x61,0xfa,0x86,0x9d,0x1b,0x3e,0x15,0x89,0x8a,0xae,0x14,0xdb,0x17,0x97,0x15,0x7f,0xd8,0x28,0xdc,0x78,0xe5,0x1b,0x87,0x6f,0xca,0xbf,0x99,0xdc,0x94,0xb4,0xa9,0xab,0xc4,0xb9,0x64,0xcf,0x66,0xd2,0x66,0xe9,0xe6,0xde,0x2d,0x9e,0x5b,0xe,0x96,0xaa,0x97,0xe6,0x97,0xe,0x6e,0xd,0xd9,0xda,0xb4,0xd,0xdf,0x56,0xb4,0xed,0xf5,0xf6,0x45,0xdb,0x2f,0x97,0xcd,0x28,0xdb,0xbb,0x83,0xb6,0x43,0xb9,0xa3,0xbf,0x3c,0xb8,0xbc,0x65,0xa7,0xc9,0xce,0xcd,0x3b,0x3f,0x54,0xa4,0x54,0xf4,0x54,0xfa,0x54,0x36,0xee,0xd2,0xdd,0xb5,0x61,0xd7,0xf8,0x6e,0xd1,0xee,0x1b,0x7b,0xbc,0xf6,0x34,0xec,0xd5,0xdb,0x5b,0xbc,0xf7,0xfd,0x3e,0xc9,0xbe,0xdb,0x55,0x1,0x55,0x4d,0xd5,0x66,0xd5,0x65,0xfb,0x49,0xfb,0xb3,0xf7,0x3f,0xae,0x89,0xaa,0xe9,0xf8,0x96,0xfb,0x6d,0x5d,0xad,0x4e,0x6d,0x71,0xed,0xc7,0x3,0xd2,0x3,0xfd,0x7,0x23,0xe,0xb6,0xd7,0xb9,0xd4,0xd5,0x1d,0xd2,0x3d,0x54,0x52,0x8f,0xd6,0x2b,0xeb,0x47,0xe,0xc7,0x1f,0xbe,0xfe,0x9d,0xef,0x77,0x2d,0xd,0x36,0xd,0x55,0x8d,0x9c,0xc6,0xe2,0x23,0x70,0x44,0x79,0xe4,0xe9,0xf7,0x9,0xdf,0xf7,0x1e,0xd,0x3a,0xda,0x76,0x8c,0x7b,0xac,0xe1,0x7,0xd3,0x1f,0x76,0x1d,0x67,0x1d,0x2f,0x6a,0x42,0x9a,0xf2,0x9a,0x46,0x9b,0x53,0x9a,0xfb,0x5b,0x62,0x5b,0xba,0x4f,0xcc,0x3e,0xd1,0xd6,0xea,0xde,0x7a,0xfc,0x47,0xdb,0x1f,0xf,0x9c,0x34,0x3c,0x59,0x79,0x4a,0xf3,0x54,0xc9,0x69,0xda,0xe9,0x82,0xd3,0x93,0x67,0xf2,0xcf,0x8c,0x9d,0x95,0x9d,0x7d,0x7e,0x2e,0xf9,0xdc,0x60,0xdb,0xa2,0xb6,0x7b,0xe7,0x63,0xce,0xdf,0x6a,0xf,0x6f,0xef,0xba,0x10,0x74,0xe1,0xd2,0x45,0xff,0x8b,0xe7,0x3b,0xbc,0x3b,0xce,0x5c,0xf2,0xb8,0x74,0xf2,0xb2,0xdb,0xe5,0x13,0x57,0xb8,0x57,0x9a,0xaf,0x3a,0x5f,0x6d,0xea,0x74,0xea,0x3c,0xfe,0x93,0xd3,0x4f,0xc7,0xbb,0x9c,0xbb,0x9a,0xae,0xb9,0x5c,0x6b,0xb9,0xee,0x7a,0xbd,0xb5,0x7b,0x66,0xf7,0xe9,0x1b,0x9e,0x37,0xce,0xdd,0xf4,0xbd,0x79,0xf1,0x16,0xff,0xd6,0xd5,0x9e,0x39,0x3d,0xdd,0xbd,0xf3,0x7a,0x6f,0xf7,0xc5,0xf7,0xf5,0xdf,0x16,0xdd,0x7e,0x72,0x27,0xfd,0xce,0xcb,0xbb,0xd9,0x77,0x27,0xee,0xad,0xbc,0x4f,0xbc,0x5f,0xf4,0x40,0xed,0x41,0xd9,0x43,0xdd,0x87,0xd5,0x3f,0x5b,0xfe,0xdc,0xd8,0xef,0xdc,0x7f,0x6a,0xc0,0x77,0xa0,0xf3,0xd1,0xdc,0x47,0xf7,0x6,0x85,0x83,0xcf,0xfe,0x91,0xf5,0x8f,0xf,0x43,0x5,0x8f,0x99,0x8f,0xcb,0x86,0xd,0x86,0xeb,0x9e,0x38,0x3e,0x39,0x39,0xe2,0x3f,0x72,0xfd,0xe9,0xfc,0xa7,0x43,0xcf,0x64,0xcf,0x26,0x9e,0x17,0xfe,0xa2,0xfe,0xcb,0xae,0x17,0x16,0x2f,0x7e,0xf8,0xd5,0xeb,0xd7,0xce,0xd1,0x98,0xd1,0xa1,0x97,0xf2,0x97,0x93,0xbf,0x6d,0x7c,0xa5,0xfd,0xea,0xc0,0xeb,0x19,0xaf,0xdb,0xc6,0xc2,0xc6,0x1e,0xbe,0xc9,0x78,0x33,0x31,0x5e,0xf4,0x56,0xfb,0xed,0xc1,0x77,0xdc,0x77,0x1d,0xef,0xa3,0xdf,0xf,0x4f,0xe4,0x7c,0x20,0x7f,0x28,0xff,0x68,0xf9,0xb1,0xf5,0x53,0xd0,0xa7,0xfb,0x93,0x19,0x93,0x93,0xff,0x4,0x3,0x98,0xf3,0xfc,0xef,0x35,0x94,0x82,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xa,0x14,0x2,0x26,0x1b,0xf0,0x48,0x42,0x95,0x0,0x0,0x1,0x3c,0x49,0x44,0x41,0x54,0x38,0xcb,0xa5,0x93,0xc1,0x4a,0x3,0x41,0xc,0x86,0xbf,0x99,0x8d,0xae,0xe8,0xa1,0x7b,0xd4,0xc2,0x42,0x7d,0x13,0xf1,0xea,0xcd,0xa7,0xe9,0x23,0x14,0x1f,0xc6,0x9b,0x47,0xc5,0x37,0x11,0x2a,0x68,0x41,0x28,0x5b,0x68,0xa1,0xdb,0x9d,0x9d,0x78,0x68,0xa6,0xda,0xa2,0x6b,0x8b,0x81,0x30,0x39,0x64,0x92,0xff,0x4f,0xfe,0x38,0x40,0x80,0x63,0x20,0x7,0x4e,0x2c,0xce,0x0,0xcf,0xb6,0x45,0xa0,0x5,0x56,0xc0,0x12,0xa8,0x81,0x55,0xfa,0x7c,0x6,0x14,0x40,0xcf,0xe2,0x1c,0x70,0xe6,0x0,0x6a,0x5e,0x3,0xb,0x60,0x6,0x54,0x58,0xf7,0x1c,0x28,0xae,0xaf,0x6e,0x6e,0xcb,0xfe,0xe5,0x30,0xb4,0xa1,0x50,0x55,0x7e,0x32,0xe7,0x1c,0x92,0x49,0xf5,0xfa,0xf6,0x32,0x7a,0x7a,0x7e,0xb8,0x7,0x82,0x18,0xec,0x5e,0xd9,0x1f,0xc,0xa7,0xd5,0x47,0x11,0x42,0x43,0x67,0x1,0x39,0x2a,0xca,0xfe,0x60,0x8,0x3c,0x2,0x73,0x9f,0x28,0x84,0xb6,0xe9,0xfc,0xc,0xa0,0xaa,0x84,0xd0,0x10,0xda,0xa6,0x30,0xaa,0xc7,0x62,0x3,0xcb,0x63,0x8c,0xc4,0x18,0xf9,0xcb,0x54,0x35,0xe5,0xe5,0x40,0x26,0x36,0x6d,0xa7,0xa,0x1d,0xcd,0x77,0x8a,0xac,0x19,0x1,0x5e,0x12,0xbd,0xa8,0xda,0x9,0x7f,0x6b,0x9f,0xeb,0x3c,0x97,0xb6,0xb0,0xb3,0xa9,0xbd,0x30,0x6c,0x22,0xd9,0xa0,0x8a,0x7,0x50,0x88,0x5f,0x55,0xc4,0x14,0xa6,0x9b,0x67,0x3f,0x12,0xa9,0x40,0x14,0x93,0x67,0xfd,0x7d,0xca,0x5d,0xe6,0x5c,0x12,0x27,0x35,0xd0,0x7a,0xd3,0xf6,0xc2,0x79,0xa9,0x32,0x2f,0xa0,0x8e,0xb4,0x91,0x5d,0x47,0x1d,0x99,0x17,0xbc,0x97,0xca,0x24,0xbd,0x12,0x3b,0x8c,0xd9,0x64,0x32,0x1e,0x5d,0x9c,0x97,0xc3,0xd0,0x86,0xe2,0xd7,0x61,0xac,0xa5,0x3c,0x7d,0x9f,0x8c,0xef,0xec,0x1e,0x96,0xe,0x38,0xfd,0xc7,0x31,0x2d,0xc4,0x28,0x0,0x4,0x60,0x7e,0xe8,0x39,0x7f,0x2,0x5b,0xc,0xa3,0x3f,0x1f,0xdb,0xad,0x8d,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char button_normal_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x14,0xe,0x27,0x37,0x5e,0x6d,0x4f,0x26,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0xb5,0x49,0x44,0x41,0x54,0x38,0x8d,0xed,0xd3,0x31,0x4e,0xc3,0x40,0x14,0x45,0xd1,0x33,0x61,0x24,0x10,0xa2,0x60,0x3a,0x32,0x23,0x58,0x41,0x80,0x8d,0x25,0x6c,0x6,0x36,0x16,0x92,0x9a,0x26,0x72,0x5a,0x53,0x50,0x38,0x52,0xd0,0x50,0x60,0x44,0x67,0x5b,0x4a,0x43,0xc1,0xab,0xdf,0xbd,0xbf,0x79,0x3f,0xe0,0x12,0xd7,0xb8,0xc2,0x19,0x82,0xe1,0x54,0x7c,0xe2,0x3,0xef,0xb1,0x87,0x1f,0x70,0x8b,0x8b,0x89,0x82,0xe,0x3b,0xbc,0xc6,0xfe,0xf2,0xdd,0xfd,0xe2,0x71,0x51,0x72,0x59,0xaa,0x23,0x82,0xa0,0x36,0xfb,0xe6,0x65,0xb3,0x5d,0x7,0xbc,0x45,0x44,0x9c,0x97,0x5c,0x56,0x5d,0xd7,0x69,0xdb,0x76,0x90,0x4f,0x29,0x85,0x92,0xcb,0x6a,0xb3,0x5d,0x3f,0x21,0xce,0x7e,0xbd,0x46,0x61,0xfa,0x4e,0xed,0x19,0xcc,0x6,0xdb,0x13,0xf2,0x2f,0xf8,0x4b,0x82,0x2a,0x90,0x52,0x1a,0x5,0x52,0x4a,0x3f,0x63,0xaf,0x7c,0xaf,0xf0,0x88,0x43,0xb3,0x6f,0x9e,0x4b,0x2e,0xcb,0xf9,0xcd,0x7c,0xd2,0x94,0x71,0xc0,0x31,0x20,0x3b,0xe1,0x99,0x82,0x13,0xdf,0xf9,0xb,0x7f,0x70,0x3b,0x69,0x4a,0x9d,0x12,0xc4,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0xa,0x45,0x69,0x43,0x43,0x50,0x49,0x43,0x43,0x20,0x70,0x72,0x6f,0x66,0x69,0x6c,0x65,0x0,0x0,0x78,0xda,0x9d,0x53,0x67,0x54,0x53,0xe9,0x16,0x3d,0xf7,0xde,0xf4,0x42,0x4b,0x88,0x80,0x94,0x4b,0x6f,0x52,0x15,0x8,0x20,0x52,0x42,0x8b,0x80,0x14,0x91,0x26,0x2a,0x21,0x9,0x10,0x4a,0x88,0x21,0xa1,0xd9,0x15,0x51,0xc1,0x11,0x45,0x45,0x4,0x1b,0xc8,0xa0,0x88,0x3,0x8e,0x8e,0x80,0x8c,0x15,0x51,0x2c,0xc,0x8a,0xa,0xd8,0x7,0xe4,0x21,0xa2,0x8e,0x83,0xa3,0x88,0x8a,0xca,0xfb,0xe1,0x7b,0xa3,0x6b,0xd6,0xbc,0xf7,0xe6,0xcd,0xfe,0xb5,0xd7,0x3e,0xe7,0xac,0xf3,0x9d,0xb3,0xcf,0x7,0xc0,0x8,0xc,0x96,0x48,0x33,0x51,0x35,0x80,0xc,0xa9,0x42,0x1e,0x11,0xe0,0x83,0xc7,0xc4,0xc6,0xe1,0xe4,0x2e,0x40,0x81,0xa,0x24,0x70,0x0,0x10,0x8,0xb3,0x64,0x21,0x73,0xfd,0x23,0x1,0x0,0xf8,0x7e,0x3c,0x3c,0x2b,0x22,0xc0,0x7,0xbe,0x0,0x1,0x78,0xd3,0xb,0x8,0x0,0xc0,0x4d,0x9b,0xc0,0x30,0x1c,0x87,0xff,0xf,0xea,0x42,0x99,0x5c,0x1,0x80,0x84,0x1,0xc0,0x74,0x91,0x38,0x4b,0x8,0x80,0x14,0x0,0x40,0x7a,0x8e,0x42,0xa6,0x0,0x40,0x46,0x1,0x80,0x9d,0x98,0x26,0x53,0x0,0xa0,0x4,0x0,0x60,0xcb,0x63,0x62,0xe3,0x0,0x50,0x2d,0x0,0x60,0x27,0x7f,0xe6,0xd3,0x0,0x80,0x9d,0xf8,0x99,0x7b,0x1,0x0,0x5b,0x94,0x21,0x15,0x1,0xa0,0x91,0x0,0x20,0x13,0x65,0x88,0x44,0x0,0x68,0x3b,0x0,0xac,0xcf,0x56,0x8a,0x45,0x0,0x58,0x30,0x0,0x14,0x66,0x4b,0xc4,0x39,0x0,0xd8,0x2d,0x0,0x30,0x49,0x57,0x66,0x48,0x0,0xb0,0xb7,0x0,0xc0,0xce,0x10,0xb,0xb2,0x0,0x8,0xc,0x0,0x30,0x51,0x88,0x85,0x29,0x0,0x4,0x7b,0x0,0x60,0xc8,0x23,0x23,0x78,0x0,0x84,0x99,0x0,0x14,0x46,0xf2,0x57,0x3c,0xf1,0x2b,0xae,0x10,0xe7,0x2a,0x0,0x0,0x78,0x99,0xb2,0x3c,0xb9,0x24,0x39,0x45,0x81,0x5b,0x8,0x2d,0x71,0x7,0x57,0x57,0x2e,0x1e,0x28,0xce,0x49,0x17,0x2b,0x14,0x36,0x61,0x2,0x61,0x9a,0x40,0x2e,0xc2,0x79,0x99,0x19,0x32,0x81,0x34,0xf,0xe0,0xf3,0xcc,0x0,0x0,0xa0,0x91,0x15,0x11,0xe0,0x83,0xf3,0xfd,0x78,0xce,0xe,0xae,0xce,0xce,0x36,0x8e,0xb6,0xe,0x5f,0x2d,0xea,0xbf,0x6,0xff,0x22,0x62,0x62,0xe3,0xfe,0xe5,0xcf,0xab,0x70,0x40,0x0,0x0,0xe1,0x74,0x7e,0xd1,0xfe,0x2c,0x2f,0xb3,0x1a,0x80,0x3b,0x6,0x80,0x6d,0xfe,0xa2,0x25,0xee,0x4,0x68,0x5e,0xb,0xa0,0x75,0xf7,0x8b,0x66,0xb2,0xf,0x40,0xb5,0x0,0xa0,0xe9,0xda,0x57,0xf3,0x70,0xf8,0x7e,0x3c,0x3c,0x45,0xa1,0x90,0xb9,0xd9,0xd9,0xe5,0xe4,0xe4,0xd8,0x4a,0xc4,0x42,0x5b,0x61,0xca,0x57,0x7d,0xfe,0x67,0xc2,0x5f,0xc0,0x57,0xfd,0x6c,0xf9,0x7e,0x3c,0xfc,0xf7,0xf5,0xe0,0xbe,0xe2,0x24,0x81,0x32,0x5d,0x81,0x47,0x4,0xf8,0xe0,0xc2,0xcc,0xf4,0x4c,0xa5,0x1c,0xcf,0x92,0x9,0x84,0x62,0xdc,0xe6,0x8f,0x47,0xfc,0xb7,0xb,0xff,0xfc,0x1d,0xd3,0x22,0xc4,0x49,0x62,0xb9,0x58,0x2a,0x14,0xe3,0x51,0x12,0x71,0x8e,0x44,0x9a,0x8c,0xf3,0x32,0xa5,0x22,0x89,0x42,0x92,0x29,0xc5,0x25,0xd2,0xff,0x64,0xe2,0xdf,0x2c,0xfb,0x3,0x3e,0xdf,0x35,0x0,0xb0,0x6a,0x3e,0x1,0x7b,0x91,0x2d,0xa8,0x5d,0x63,0x3,0xf6,0x4b,0x27,0x10,0x58,0x74,0xc0,0xe2,0xf7,0x0,0x0,0xf2,0xbb,0x6f,0xc1,0xd4,0x28,0x8,0x3,0x80,0x68,0x83,0xe1,0xcf,0x77,0xff,0xef,0x3f,0xfd,0x47,0xa0,0x25,0x0,0x80,0x66,0x49,0x92,0x71,0x0,0x0,0x5e,0x44,0x24,0x2e,0x54,0xca,0xb3,0x3f,0xc7,0x8,0x0,0x0,0x44,0xa0,0x81,0x2a,0xb0,0x41,0x1b,0xf4,0xc1,0x18,0x2c,0xc0,0x6,0x1c,0xc1,0x5,0xdc,0xc1,0xb,0xfc,0x60,0x36,0x84,0x42,0x24,0xc4,0xc2,0x42,0x10,0x42,0xa,0x64,0x80,0x1c,0x72,0x60,0x29,0xac,0x82,0x42,0x28,0x86,0xcd,0xb0,0x1d,0x2a,0x60,0x2f,0xd4,0x40,0x1d,0x34,0xc0,0x51,0x68,0x86,0x93,0x70,0xe,0x2e,0xc2,0x55,0xb8,0xe,0x3d,0x70,0xf,0xfa,0x61,0x8,0x9e,0xc1,0x28,0xbc,0x81,0x9,0x4,0x41,0xc8,0x8,0x13,0x61,0x21,0xda,0x88,0x1,0x62,0x8a,0x58,0x23,0x8e,0x8,0x17,0x99,0x85,0xf8,0x21,0xc1,0x48,0x4,0x12,0x8b,0x24,0x20,0xc9,0x88,0x14,0x51,0x22,0x4b,0x91,0x35,0x48,0x31,0x52,0x8a,0x54,0x20,0x55,0x48,0x1d,0xf2,0x3d,0x72,0x2,0x39,0x87,0x5c,0x46,0xba,0x91,0x3b,0xc8,0x0,0x32,0x82,0xfc,0x86,0xbc,0x47,0x31,0x94,0x81,0xb2,0x51,0x3d,0xd4,0xc,0xb5,0x43,0xb9,0xa8,0x37,0x1a,0x84,0x46,0xa2,0xb,0xd0,0x64,0x74,0x31,0x9a,0x8f,0x16,0xa0,0x9b,0xd0,0x72,0xb4,0x1a,0x3d,0x8c,0x36,0xa1,0xe7,0xd0,0xab,0x68,0xf,0xda,0x8f,0x3e,0x43,0xc7,0x30,0xc0,0xe8,0x18,0x7,0x33,0xc4,0x6c,0x30,0x2e,0xc6,0xc3,0x42,0xb1,0x38,0x2c,0x9,0x93,0x63,0xcb,0xb1,0x22,0xac,0xc,0xab,0xc6,0x1a,0xb0,0x56,0xac,0x3,0xbb,0x89,0xf5,0x63,0xcf,0xb1,0x77,0x4,0x12,0x81,0x45,0xc0,0x9,0x36,0x4,0x77,0x42,0x20,0x61,0x1e,0x41,0x48,0x58,0x4c,0x58,0x4e,0xd8,0x48,0xa8,0x20,0x1c,0x24,0x34,0x11,0xda,0x9,0x37,0x9,0x3,0x84,0x51,0xc2,0x27,0x22,0x93,0xa8,0x4b,0xb4,0x26,0xba,0x11,0xf9,0xc4,0x18,0x62,0x32,0x31,0x87,0x58,0x48,0x2c,0x23,0xd6,0x12,0x8f,0x13,0x2f,0x10,0x7b,0x88,0x43,0xc4,0x37,0x24,0x12,0x89,0x43,0x32,0x27,0xb9,0x90,0x2,0x49,0xb1,0xa4,0x54,0xd2,0x12,0xd2,0x46,0xd2,0x6e,0x52,0x23,0xe9,0x2c,0xa9,0x9b,0x34,0x48,0x1a,0x23,0x93,0xc9,0xda,0x64,0x6b,0xb2,0x7,0x39,0x94,0x2c,0x20,0x2b,0xc8,0x85,0xe4,0x9d,0xe4,0xc3,0xe4,0x33,0xe4,0x1b,0xe4,0x21,0xf2,0x5b,0xa,0x9d,0x62,0x40,0x71,0xa4,0xf8,0x53,0xe2,0x28,0x52,0xca,0x6a,0x4a,0x19,0xe5,0x10,0xe5,0x34,0xe5,0x6,0x65,0x98,0x32,0x41,0x55,0xa3,0x9a,0x52,0xdd,0xa8,0xa1,0x54,0x11,0x35,0x8f,0x5a,0x42,0xad,0xa1,0xb6,0x52,0xaf,0x51,0x87,0xa8,0x13,0x34,0x75,0x9a,0x39,0xcd,0x83,0x16,0x49,0x4b,0xa5,0xad,0xa2,0x95,0xd3,0x1a,0x68,0x17,0x68,0xf7,0x69,0xaf,0xe8,0x74,0xba,0x11,0xdd,0x95,0x1e,0x4e,0x97,0xd0,0x57,0xd2,0xcb,0xe9,0x47,0xe8,0x97,0xe8,0x3,0xf4,0x77,0xc,0xd,0x86,0x15,0x83,0xc7,0x88,0x67,0x28,0x19,0x9b,0x18,0x7,0x18,0x67,0x19,0x77,0x18,0xaf,0x98,0x4c,0xa6,0x19,0xd3,0x8b,0x19,0xc7,0x54,0x30,0x37,0x31,0xeb,0x98,0xe7,0x99,0xf,0x99,0x6f,0x55,0x58,0x2a,0xb6,0x2a,0x7c,0x15,0x91,0xca,0xa,0x95,0x4a,0x95,0x26,0x95,0x1b,0x2a,0x2f,0x54,0xa9,0xaa,0xa6,0xaa,0xde,0xaa,0xb,0x55,0xf3,0x55,0xcb,0x54,0x8f,0xa9,0x5e,0x53,0x7d,0xae,0x46,0x55,0x33,0x53,0xe3,0xa9,0x9,0xd4,0x96,0xab,0x55,0xaa,0x9d,0x50,0xeb,0x53,0x1b,0x53,0x67,0xa9,0x3b,0xa8,0x87,0xaa,0x67,0xa8,0x6f,0x54,0x3f,0xa4,0x7e,0x59,0xfd,0x89,0x6,0x59,0xc3,0x4c,0xc3,0x4f,0x43,0xa4,0x51,0xa0,0xb1,0x5f,0xe3,0xbc,0xc6,0x20,0xb,0x63,0x19,0xb3,0x78,0x2c,0x21,0x6b,0xd,0xab,0x86,0x75,0x81,0x35,0xc4,0x26,0xb1,0xcd,0xd9,0x7c,0x76,0x2a,0xbb,0x98,0xfd,0x1d,0xbb,0x8b,0x3d,0xaa,0xa9,0xa1,0x39,0x43,0x33,0x4a,0x33,0x57,0xb3,0x52,0xf3,0x94,0x66,0x3f,0x7,0xe3,0x98,0x71,0xf8,0x9c,0x74,0x4e,0x9,0xe7,0x28,0xa7,0x97,0xf3,0x7e,0x8a,0xde,0x14,0xef,0x29,0xe2,0x29,0x1b,0xa6,0x34,0x4c,0xb9,0x31,0x65,0x5c,0x6b,0xaa,0x96,0x97,0x96,0x58,0xab,0x48,0xab,0x51,0xab,0x47,0xeb,0xbd,0x36,0xae,0xed,0xa7,0x9d,0xa6,0xbd,0x45,0xbb,0x59,0xfb,0x81,0xe,0x41,0xc7,0x4a,0x27,0x5c,0x27,0x47,0x67,0x8f,0xce,0x5,0x9d,0xe7,0x53,0xd9,0x53,0xdd,0xa7,0xa,0xa7,0x16,0x4d,0x3d,0x3a,0xf5,0xae,0x2e,0xaa,0x6b,0xa5,0x1b,0xa1,0xbb,0x44,0x77,0xbf,0x6e,0xa7,0xee,0x98,0x9e,0xbe,0x5e,0x80,0x9e,0x4c,0x6f,0xa7,0xde,0x79,0xbd,0xe7,0xfa,0x1c,0x7d,0x2f,0xfd,0x54,0xfd,0x6d,0xfa,0xa7,0xf5,0x47,0xc,0x58,0x6,0xb3,0xc,0x24,0x6,0xdb,0xc,0xce,0x18,0x3c,0xc5,0x35,0x71,0x6f,0x3c,0x1d,0x2f,0xc7,0xdb,0xf1,0x51,0x43,0x5d,0xc3,0x40,0x43,0xa5,0x61,0x95,0x61,0x97,0xe1,0x84,0x91,0xb9,0xd1,0x3c,0xa3,0xd5,0x46,0x8d,0x46,0xf,0x8c,0x69,0xc6,0x5c,0xe3,0x24,0xe3,0x6d,0xc6,0x6d,0xc6,0xa3,0x26,0x6,0x26,0x21,0x26,0x4b,0x4d,0xea,0x4d,0xee,0x9a,0x52,0x4d,0xb9,0xa6,0x29,0xa6,0x3b,0x4c,0x3b,0x4c,0xc7,0xcd,0xcc,0xcd,0xa2,0xcd,0xd6,0x99,0x35,0x9b,0x3d,0x31,0xd7,0x32,0xe7,0x9b,0xe7,0x9b,0xd7,0x9b,0xdf,0xb7,0x60,0x5a,0x78,0x5a,0x2c,0xb6,0xa8,0xb6,0xb8,0x65,0x49,0xb2,0xe4,0x5a,0xa6,0x59,0xee,0xb6,0xbc,0x6e,0x85,0x5a,0x39,0x59,0xa5,0x58,0x55,0x5a,0x5d,0xb3,0x46,0xad,0x9d,0xad,0x25,0xd6,0xbb,0xad,0xbb,0xa7,0x11,0xa7,0xb9,0x4e,0x93,0x4e,0xab,0x9e,0xd6,0x67,0xc3,0xb0,0xf1,0xb6,0xc9,0xb6,0xa9,0xb7,0x19,0xb0,0xe5,0xd8,0x6,0xdb,0xae,0xb6,0x6d,0xb6,0x7d,0x61,0x67,0x62,0x17,0x67,0xb7,0xc5,0xae,0xc3,0xee,0x93,0xbd,0x93,0x7d,0xba,0x7d,0x8d,0xfd,0x3d,0x7,0xd,0x87,0xd9,0xe,0xab,0x1d,0x5a,0x1d,0x7e,0x73,0xb4,0x72,0x14,0x3a,0x56,0x3a,0xde,0x9a,0xce,0x9c,0xee,0x3f,0x7d,0xc5,0xf4,0x96,0xe9,0x2f,0x67,0x58,0xcf,0x10,0xcf,0xd8,0x33,0xe3,0xb6,0x13,0xcb,0x29,0xc4,0x69,0x9d,0x53,0x9b,0xd3,0x47,0x67,0x17,0x67,0xb9,0x73,0x83,0xf3,0x88,0x8b,0x89,0x4b,0x82,0xcb,0x2e,0x97,0x3e,0x2e,0x9b,0x1b,0xc6,0xdd,0xc8,0xbd,0xe4,0x4a,0x74,0xf5,0x71,0x5d,0xe1,0x7a,0xd2,0xf5,0x9d,0x9b,0xb3,0x9b,0xc2,0xed,0xa8,0xdb,0xaf,0xee,0x36,0xee,0x69,0xee,0x87,0xdc,0x9f,0xcc,0x34,0x9f,0x29,0x9e,0x59,0x33,0x73,0xd0,0xc3,0xc8,0x43,0xe0,0x51,0xe5,0xd1,0x3f,0xb,0x9f,0x95,0x30,0x6b,0xdf,0xac,0x7e,0x4f,0x43,0x4f,0x81,0x67,0xb5,0xe7,0x23,0x2f,0x63,0x2f,0x91,0x57,0xad,0xd7,0xb0,0xb7,0xa5,0x77,0xaa,0xf7,0x61,0xef,0x17,0x3e,0xf6,0x3e,0x72,0x9f,0xe3,0x3e,0xe3,0x3c,0x37,0xde,0x32,0xde,0x59,0x5f,0xcc,0x37,0xc0,0xb7,0xc8,0xb7,0xcb,0x4f,0xc3,0x6f,0x9e,0x5f,0x85,0xdf,0x43,0x7f,0x23,0xff,0x64,0xff,0x7a,0xff,0xd1,0x0,0xa7,0x80,0x25,0x1,0x67,0x3,0x89,0x81,0x41,0x81,0x5b,0x2,0xfb,0xf8,0x7a,0x7c,0x21,0xbf,0x8e,0x3f,0x3a,0xdb,0x65,0xf6,0xb2,0xd9,0xed,0x41,0x8c,0xa0,0xb9,0x41,0x15,0x41,0x8f,0x82,0xad,0x82,0xe5,0xc1,0xad,0x21,0x68,0xc8,0xec,0x90,0xad,0x21,0xf7,0xe7,0x98,0xce,0x91,0xce,0x69,0xe,0x85,0x50,0x7e,0xe8,0xd6,0xd0,0x7,0x61,0xe6,0x61,0x8b,0xc3,0x7e,0xc,0x27,0x85,0x87,0x85,0x57,0x86,0x3f,0x8e,0x70,0x88,0x58,0x1a,0xd1,0x31,0x97,0x35,0x77,0xd1,0xdc,0x43,0x73,0xdf,0x44,0xfa,0x44,0x96,0x44,0xde,0x9b,0x67,0x31,0x4f,0x39,0xaf,0x2d,0x4a,0x35,0x2a,0x3e,0xaa,0x2e,0x6a,0x3c,0xda,0x37,0xba,0x34,0xba,0x3f,0xc6,0x2e,0x66,0x59,0xcc,0xd5,0x58,0x9d,0x58,0x49,0x6c,0x4b,0x1c,0x39,0x2e,0x2a,0xae,0x36,0x6e,0x6c,0xbe,0xdf,0xfc,0xed,0xf3,0x87,0xe2,0x9d,0xe2,0xb,0xe3,0x7b,0x17,0x98,0x2f,0xc8,0x5d,0x70,0x79,0xa1,0xce,0xc2,0xf4,0x85,0xa7,0x16,0xa9,0x2e,0x12,0x2c,0x3a,0x96,0x40,0x4c,0x88,0x4e,0x38,0x94,0xf0,0x41,0x10,0x2a,0xa8,0x16,0x8c,0x25,0xf2,0x13,0x77,0x25,0x8e,0xa,0x79,0xc2,0x1d,0xc2,0x67,0x22,0x2f,0xd1,0x36,0xd1,0x88,0xd8,0x43,0x5c,0x2a,0x1e,0x4e,0xf2,0x48,0x2a,0x4d,0x7a,0x92,0xec,0x91,0xbc,0x35,0x79,0x24,0xc5,0x33,0xa5,0x2c,0xe5,0xb9,0x84,0x27,0xa9,0x90,0xbc,0x4c,0xd,0x4c,0xdd,0x9b,0x3a,0x9e,0x16,0x9a,0x76,0x20,0x6d,0x32,0x3d,0x3a,0xbd,0x31,0x83,0x92,0x91,0x90,0x71,0x42,0xaa,0x21,0x4d,0x93,0xb6,0x67,0xea,0x67,0xe6,0x66,0x76,0xcb,0xac,0x65,0x85,0xb2,0xfe,0xc5,0x6e,0x8b,0xb7,0x2f,0x1e,0x95,0x7,0xc9,0x6b,0xb3,0x90,0xac,0x5,0x59,0x2d,0xa,0xb6,0x42,0xa6,0xe8,0x54,0x5a,0x28,0xd7,0x2a,0x7,0xb2,0x67,0x65,0x57,0x66,0xbf,0xcd,0x89,0xca,0x39,0x96,0xab,0x9e,0x2b,0xcd,0xed,0xcc,0xb3,0xca,0xdb,0x90,0x37,0x9c,0xef,0x9f,0xff,0xed,0x12,0xc2,0x12,0xe1,0x92,0xb6,0xa5,0x86,0x4b,0x57,0x2d,0x1d,0x58,0xe6,0xbd,0xac,0x6a,0x39,0xb2,0x3c,0x71,0x79,0xdb,0xa,0xe3,0x15,0x5,0x2b,0x86,0x56,0x6,0xac,0x3c,0xb8,0x8a,0xb6,0x2a,0x6d,0xd5,0x4f,0xab,0xed,0x57,0x97,0xae,0x7e,0xbd,0x26,0x7a,0x4d,0x6b,0x81,0x5e,0xc1,0xca,0x82,0xc1,0xb5,0x1,0x6b,0xeb,0xb,0x55,0xa,0xe5,0x85,0x7d,0xeb,0xdc,0xd7,0xed,0x5d,0x4f,0x58,0x2f,0x59,0xdf,0xb5,0x61,0xfa,0x86,0x9d,0x1b,0x3e,0x15,0x89,0x8a,0xae,0x14,0xdb,0x17,0x97,0x15,0x7f,0xd8,0x28,0xdc,0x78,0xe5,0x1b,0x87,0x6f,0xca,0xbf,0x99,0xdc,0x94,0xb4,0xa9,0xab,0xc4,0xb9,0x64,0xcf,0x66,0xd2,0x66,0xe9,0xe6,0xde,0x2d,0x9e,0x5b,0xe,0x96,0xaa,0x97,0xe6,0x97,0xe,0x6e,0xd,0xd9,0xda,0xb4,0xd,0xdf,0x56,0xb4,0xed,0xf5,0xf6,0x45,0xdb,0x2f,0x97,0xcd,0x28,0xdb,0xbb,0x83,0xb6,0x43,0xb9,0xa3,0xbf,0x3c,0xb8,0xbc,0x65,0xa7,0xc9,0xce,0xcd,0x3b,0x3f,0x54,0xa4,0x54,0xf4,0x54,0xfa,0x54,0x36,0xee,0xd2,0xdd,0xb5,0x61,0xd7,0xf8,0x6e,0xd1,0xee,0x1b,0x7b,0xbc,0xf6,0x34,0xec,0xd5,0xdb,0x5b,0xbc,0xf7,0xfd,0x3e,0xc9,0xbe,0xdb,0x55,0x1,0x55,0x4d,0xd5,0x66,0xd5,0x65,0xfb,0x49,0xfb,0xb3,0xf7,0x3f,0xae,0x89,0xaa,0xe9,0xf8,0x96,0xfb,0x6d,0x5d,0xad,0x4e,0x6d,0x71,0xed,0xc7,0x3,0xd2,0x3,0xfd,0x7,0x23,0xe,0xb6,0xd7,0xb9,0xd4,0xd5,0x1d,0xd2,0x3d,0x54,0x52,0x8f,0xd6,0x2b,0xeb,0x47,0xe,0xc7,0x1f,0xbe,0xfe,0x9d,0xef,0x77,0x2d,0xd,0x36,0xd,0x55,0x8d,0x9c,0xc6,0xe2,0x23,0x70,0x44,0x79,0xe4,0xe9,0xf7,0x9,0xdf,0xf7,0x1e,0xd,0x3a,0xda,0x76,0x8c,0x7b,0xac,0xe1,0x7,0xd3,0x1f,0x76,0x1d,0x67,0x1d,0x2f,0x6a,0x42,0x9a,0xf2,0x9a,0x46,0x9b,0x53,0x9a,0xfb,0x5b,0x62,0x5b,0xba,0x4f,0xcc,0x3e,0xd1,0xd6,0xea,0xde,0x7a,0xfc,0x47,0xdb,0x1f,0xf,0x9c,0x34,0x3c,0x59,0x79,0x4a,0xf3,0x54,0xc9,0x69,0xda,0xe9,0x82,0xd3,0x93,0x67,0xf2,0xcf,0x8c,0x9d,0x95,0x9d,0x7d,0x7e,0x2e,0xf9,0xdc,0x60,0xdb,0xa2,0xb6,0x7b,0xe7,0x63,0xce,0xdf,0x6a,0xf,0x6f,0xef,0xba,0x10,0x74,0xe1,0xd2,0x45,0xff,0x8b,0xe7,0x3b,0xbc,0x3b,0xce,0x5c,0xf2,0xb8,0x74,0xf2,0xb2,0xdb,0xe5,0x13,0x57,0xb8,0x57,0x9a,0xaf,0x3a,0x5f,0x6d,0xea,0x74,0xea,0x3c,0xfe,0x93,0xd3,0x4f,0xc7,0xbb,0x9c,0xbb,0x9a,0xae,0xb9,0x5c,0x6b,0xb9,0xee,0x7a,0xbd,0xb5,0x7b,0x66,0xf7,0xe9,0x1b,0x9e,0x37,0xce,0xdd,0xf4,0xbd,0x79,0xf1,0x16,0xff,0xd6,0xd5,0x9e,0x39,0x3d,0xdd,0xbd,0xf3,0x7a,0x6f,0xf7,0xc5,0xf7,0xf5,0xdf,0x16,0xdd,0x7e,0x72,0x27,0xfd,0xce,0xcb,0xbb,0xd9,0x77,0x27,0xee,0xad,0xbc,0x4f,0xbc,0x5f,0xf4,0x40,0xed,0x41,0xd9,0x43,0xdd,0x87,0xd5,0x3f,0x5b,0xfe,0xdc,0xd8,0xef,0xdc,0x7f,0x6a,0xc0,0x77,0xa0,0xf3,0xd1,0xdc,0x47,0xf7,0x6,0x85,0x83,0xcf,0xfe,0x91,0xf5,0x8f,0xf,0x43,0x5,0x8f,0x99,0x8f,0xcb,0x86,0xd,0x86,0xeb,0x9e,0x38,0x3e,0x39,0x39,0xe2,0x3f,0x72,0xfd,0xe9,0xfc,0xa7,0x43,0xcf,0x64,0xcf,0x26,0x9e,0x17,0xfe,0xa2,0xfe,0xcb,0xae,0x17,0x16,0x2f,0x7e,0xf8,0xd5,0xeb,0xd7,0xce,0xd1,0x98,0xd1,0xa1,0x97,0xf2,0x97,0x93,0xbf,0x6d,0x7c,0xa5,0xfd,0xea,0xc0,0xeb,0x19,0xaf,0xdb,0xc6,0xc2,0xc6,0x1e,0xbe,0xc9,0x78,0x33,0x31,0x5e,0xf4,0x56,0xfb,0xed,0xc1,0x77,0xdc,0x77,0x1d,0xef,0xa3,0xdf,0xf,0x4f,0xe4,0x7c,0x20,0x7f,0x28,0xff,0x68,0xf9,0xb1,0xf5,0x53,0xd0,0xa7,0xfb,0x93,0x19,0x93,0x93,0xff,0x4,0x3,0x98,0xf3,0xfc,0xef,0x35,0x94,0x82,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xa,0x14,0x2,0x25,0x38,0x79,0x2,0x60,0x24,0x0,0x0,0x1,0x3a,0x49,0x44,0x41,0x54,0x38,0xcb,0xa5,0x93,0x41,0x4a,0x3,0x51,0xc,0x86,0xbf,0x37,0xef,0xd1,0x11,0x5d,0x74,0x40,0xc1,0x5a,0xea,0x45,0xc4,0xa5,0x27,0xf0,0x34,0x73,0x84,0xe2,0x61,0x3c,0x81,0xee,0xc4,0x8b,0x8,0x76,0xd3,0xea,0x14,0x5a,0xe8,0x74,0xde,0x4b,0x5c,0x4c,0x46,0x2a,0xd4,0x3a,0xc5,0x40,0x20,0x8b,0xe4,0x4f,0xfe,0xf0,0xff,0xe,0x8,0xc0,0x0,0xc8,0x81,0x13,0xab,0x3d,0x90,0xf1,0x33,0x4,0x48,0xc0,0x16,0xd8,0x0,0x35,0xb0,0xed,0x86,0xcf,0x80,0x2,0x18,0x5a,0x9d,0x3,0xce,0x12,0x40,0x2d,0x6b,0x60,0xd,0x2c,0x81,0xa,0xdb,0x9e,0x3,0xc5,0xed,0xcd,0xdd,0xfd,0xf8,0xea,0xba,0x8c,0x29,0x16,0xaa,0xec,0xd,0xe7,0x20,0xf8,0x50,0xbd,0xcf,0xde,0xa6,0x2f,0xaf,0x4f,0x8f,0x40,0xc,0x76,0xf6,0x70,0x3c,0x9a,0x94,0xd5,0xe7,0xa2,0x88,0x31,0xa2,0xec,0x47,0x70,0x38,0x42,0x8,0xc5,0x78,0x34,0x29,0x81,0x67,0x60,0xf5,0x4d,0xa1,0x89,0x4d,0xd1,0xc4,0xe6,0xd7,0xe1,0x96,0x87,0xd2,0xc4,0x86,0x26,0x36,0x85,0x51,0x1d,0x4,0x7b,0x58,0x2e,0x22,0x88,0xa,0x7f,0x85,0xa2,0x88,0x8,0x46,0xdd,0x7,0xfb,0xb6,0x53,0x51,0x54,0x94,0x3e,0x61,0x7d,0xe,0xc8,0x42,0x47,0x2f,0x69,0xea,0x75,0x1,0x40,0xd2,0xd4,0x1,0x10,0x76,0x51,0x55,0x8f,0xba,0x80,0x5d,0x0,0x55,0x3d,0x2,0xa0,0xed,0xd3,0xe,0x40,0x5a,0xd0,0x84,0xf6,0xa4,0x20,0x2d,0x5,0x5,0x24,0x98,0x3c,0x6b,0x84,0xde,0x4f,0xa4,0xdd,0x53,0x3,0x29,0x33,0x6d,0xaf,0x71,0x59,0x95,0x79,0x8f,0xa8,0x1e,0xcc,0xcc,0x7b,0x70,0x59,0x65,0x92,0xde,0x6,0x33,0xc6,0x72,0xbe,0x98,0x4d,0x2f,0xce,0x2f,0xcb,0x24,0xa9,0xe0,0x80,0x96,0x7d,0x16,0x3e,0xe6,0x8b,0xd9,0x83,0xf9,0x61,0xe3,0x80,0xd3,0x7f,0x98,0x69,0x1d,0x8c,0x2,0x40,0x4,0x56,0xc7,0xda,0xf9,0xb,0x57,0x2d,0xbb,0xf5,0x2d,0xe4,0x89,0x1b,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char button_pressed_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xc2,0x0,0xc2,0x0,0xcc,0x6a,0x6f,0xcc,0x71,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x12,0x0,0x7,0x31,0xd,0x7f,0xbc,0x67,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0xc7,0x49,0x44,0x41,0x54,0x38,0x8d,0xed,0xd3,0xc1,0x4a,0xc3,0x50,0x14,0x4,0xd0,0xf3,0x6a,0x1e,0x26,0x22,0xc1,0xb5,0x90,0xe4,0x7,0x44,0xd1,0xef,0x6a,0xfd,0x19,0xfd,0xae,0x96,0xfa,0x1,0x42,0xdb,0x7d,0x75,0x21,0xbc,0x96,0x57,0x89,0xb,0xb3,0x4e,0xb,0xdd,0xb8,0x70,0x96,0x97,0x3b,0x33,0xf7,0xc2,0x4c,0xc0,0x15,0x6e,0x70,0x8d,0xb,0x4,0xe3,0xe8,0xf1,0x8d,0x2f,0x7c,0x16,0x3,0xf9,0x1e,0xd,0xca,0x13,0x5,0x76,0xd8,0xe0,0xad,0x18,0x9c,0xdb,0xc7,0x87,0xa7,0xbb,0xb6,0xe9,0xa6,0x31,0xc6,0x51,0x81,0x9c,0x73,0xbf,0xde,0xac,0x5e,0x17,0xcb,0x79,0xc0,0x7b,0x81,0x2,0x97,0x6d,0xd3,0xcd,0x52,0x4a,0xb6,0x1f,0xdb,0x51,0xfb,0xaa,0xac,0x42,0xdb,0x74,0xb3,0xc5,0x72,0xfe,0x8c,0x62,0x32,0xcc,0x43,0x8c,0x51,0xda,0xa5,0x23,0xd7,0x93,0x76,0x49,0x8c,0x91,0xe1,0xd5,0xc9,0xf8,0xfa,0x71,0xfc,0xb,0xfc,0x25,0x81,0x3e,0xe7,0xac,0x2a,0xab,0xa3,0x84,0xaa,0xac,0xe4,0x9c,0xf9,0x8d,0xb4,0x2,0x7,0xec,0xd7,0x9b,0xd5,0x4b,0xdb,0x74,0xd3,0xba,0xae,0x4f,0x8a,0x32,0xf6,0x38,0x4,0xdc,0x3a,0xa3,0x4c,0xc1,0x99,0x75,0xfe,0x1,0x94,0xfc,0x44,0x1b,0xd0,0x15,0xb1,0x70,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0xa,0x45,0x69,0x43,0x43,0x50,0x49,0x43,0x43,0x20,0x70,0x72,0x6f,0x66,0x69,0x6c,0x65,0x0,0x0,0x78,0xda,0x9d,0x53,0x67,0x54,0x53,0xe9,0x16,0x3d,0xf7,0xde,0xf4,0x42,0x4b,0x88,0x80,0x94,0x4b,0x6f,0x52,0x15,0x8,0x20,0x52,0x42,0x8b,0x80,0x14,0x91,0x26,0x2a,0x21,0x9,0x10,0x4a,0x88,0x21,0xa1,0xd9,0x15,0x51,0xc1,0x11,0x45,0x45,0x4,0x1b,0xc8,0xa0,0x88,0x3,0x8e,0x8e,0x80,0x8c,0x15,0x51,0x2c,0xc,0x8a,0xa,0xd8,0x7,0xe4,0x21,0xa2,0x8e,0x83,0xa3,0x88,0x8a,0xca,0xfb,0xe1,0x7b,0xa3,0x6b,0xd6,0xbc,0xf7,0xe6,0xcd,0xfe,0xb5,0xd7,0x3e,0xe7,0xac,0xf3,0x9d,0xb3,0xcf,0x7,0xc0,0x8,0xc,0x96,0x48,0x33,0x51,0x35,0x80,0xc,0xa9,0x42,0x1e,0x11,0xe0,0x83,0xc7,0xc4,0xc6,0xe1,0xe4,0x2e,0x40,0x81,0xa,0x24,0x70,0x0,0x10,0x8,0xb3,0x64,0x21,0x73,0xfd,0x23,0x1,0x0,0xf8,0x7e,0x3c,0x3c,0x2b,0x22,0xc0,0x7,0xbe,0x0,0x1,0x78,0xd3,0xb,0x8,0x0,0xc0,0x4d,0x9b,0xc0,0x30,0x1c,0x87,0xff,0xf,0xea,0x42,0x99,0x5c,0x1,0x80,0x84,0x1,0xc0,0x74,0x91,0x38,0x4b,0x8,0x80,0x14,0x0,0x40,0x7a,0x8e,0x42,0xa6,0x0,0x40,0x46,0x1,0x80,0x9d,0x98,0x26,0x53,0x0,0xa0,0x4,0x0,0x60,0xcb,0x63,0x62,0xe3,0x0,0x50,0x2d,0x0,0x60,0x27,0x7f,0xe6,0xd3,0x0,0x80,0x9d,0xf8,0x99,0x7b,0x1,0x0,0x5b,0x94,0x21,0x15,0x1,0xa0,0x91,0x0,0x20,0x13,0x65,0x88,0x44,0x0,0x68,0x3b,0x0,0xac,0xcf,0x56,0x8a,0x45,0x0,0x58,0x30,0x0,0x14,0x66,0x4b,0xc4,0x39,0x0,0xd8,0x2d,0x0,0x30,0x49,0x57,0x66,0x48,0x0,0xb0,0xb7,0x0,0xc0,0xce,0x10,0xb,0xb2,0x0,0x8,0xc,0x0,0x30,0x51,0x88,0x85,0x29,0x0,0x4,0x7b,0x0,0x60,0xc8,0x23,0x23,0x78,0x0,0x84,0x99,0x0,0x14,0x46,0xf2,0x57,0x3c,0xf1,0x2b,0xae,0x10,0xe7,0x2a,0x0,0x0,0x78,0x99,0xb2,0x3c,0xb9,0x24,0x39,0x45,0x81,0x5b,0x8,0x2d,0x71,0x7,0x57,0x57,0x2e,0x1e,0x28,0xce,0x49,0x17,0x2b,0x14,0x36,0x61,0x2,0x61,0x9a,0x40,0x2e,0xc2,0x79,0x99,0x19,0x32,0x81,0x34,0xf,0xe0,0xf3,0xcc,0x0,0x0,0xa0,0x91,0x15,0x11,0xe0,0x83,0xf3,0xfd,0x78,0xce,0xe,0xae,0xce,0xce,0x36,0x8e,0xb6,0xe,0x5f,0x2d,0xea,0xbf,0x6,0xff,0x22,0x62,0x62,0xe3,0xfe,0xe5,0xcf,0xab,0x70,0x40,0x0,0x0,0xe1,0x74,0x7e,0xd1,0xfe,0x2c,0x2f,0xb3,0x1a,0x80,0x3b,0x6,0x80,0x6d,0xfe,0xa2,0x25,0xee,0x4,0x68,0x5e,0xb,0xa0,0x75,0xf7,0x8b,0x66,0xb2,0xf,0x40,0xb5,0x0,0xa0,0xe9,0xda,0x57,0xf3,0x70,0xf8,0x7e,0x3c,0x3c,0x45,0xa1,0x90,0xb9,0xd9,0xd9,0xe5,0xe4,0xe4,0xd8,0x4a,0xc4,0x42,0x5b,0x61,0xca,0x57,0x7d,0xfe,0x67,0xc2,0x5f,0xc0,0x57,0xfd,0x6c,0xf9,0x7e,0x3c,0xfc,0xf7,0xf5,0xe0,0xbe,0xe2,0x24,0x81,0x32,0x5d,0x81,0x47,0x4,0xf8,0xe0,0xc2,0xcc,0xf4,0x4c,0xa5,0x1c,0xcf,0x92,0x9,0x84,0x62,0xdc,0xe6,0x8f,0x47,0xfc,0xb7,0xb,0xff,0xfc,0x1d,0xd3,0x22,0xc4,0x49,0x62,0xb9,0x58,0x2a,0x14,0xe3,0x51,0x12,0x71,0x8e,0x44,0x9a,0x8c,0xf3,0x32,0xa5,0x22,0x89,0x42,0x92,0x29,0xc5,0x25,0xd2,0xff,0x64,0xe2,0xdf,0x2c,0xfb,0x3,0x3e,0xdf,0x35,0x0,0xb0,0x6a,0x3e,0x1,0x7b,0x91,0x2d,0xa8,0x5d,0x63,0x3,0xf6,0x4b,0x27,0x10,0x58,0x74,0xc0,0xe2,0xf7,0x0,0x0,0xf2,0xbb,0x6f,0xc1,0xd4,0x28,0x8,0x3,0x80,0x68,0x83,0xe1,0xcf,0x77,0xff,0xef,0x3f,0xfd,0x47,0xa0,0x25,0x0,0x80,0x66,0x49,0x92,0x71,0x0,0x0,0x5e,0x44,0x24,0x2e,0x54,0xca,0xb3,0x3f,0xc7,0x8,0x0,0x0,0x44,0xa0,0x81,0x2a,0xb0,0x41,0x1b,0xf4,0xc1,0x18,0x2c,0xc0,0x6,0x1c,0xc1,0x5,0xdc,0xc1,0xb,0xfc,0x60,0x36,0x84,0x42,0x24,0xc4,0xc2,0x42,0x10,0x42,0xa,0x64,0x80,0x1c,0x72,0x60,0x29,0xac,0x82,0x42,0x28,0x86,0xcd,0xb0,0x1d,0x2a,0x60,0x2f,0xd4,0x40,0x1d,0x34,0xc0,0x51,0x68,0x86,0x93,0x70,0xe,0x2e,0xc2,0x55,0xb8,0xe,0x3d,0x70,0xf,0xfa,0x61,0x8,0x9e,0xc1,0x28,0xbc,0x81,0x9,0x4,0x41,0xc8,0x8,0x13,0x61,0x21,0xda,0x88,0x1,0x62,0x8a,0x58,0x23,0x8e,0x8,0x17,0x99,0x85,0xf8,0x21,0xc1,0x48,0x4,0x12,0x8b,0x24,0x20,0xc9,0x88,0x14,0x51,0x22,0x4b,0x91,0x35,0x48,0x31,0x52,0x8a,0x54,0x20,0x55,0x48,0x1d,0xf2,0x3d,0x72,0x2,0x39,0x87,0x5c,0x46,0xba,0x91,0x3b,0xc8,0x0,0x32,0x82,0xfc,0x86,0xbc,0x47,0x31,0x94,0x81,0xb2,0x51,0x3d,0xd4,0xc,0xb5,0x43,0xb9,0xa8,0x37,0x1a,0x84,0x46,0xa2,0xb,0xd0,0x64,0x74,0x31,0x9a,0x8f,0x16,0xa0,0x9b,0xd0,0x72,0xb4,0x1a,0x3d,0x8c,0x36,0xa1,0xe7,0xd0,0xab,0x68,0xf,0xda,0x8f,0x3e,0x43,0xc7,0x30,0xc0,0xe8,0x18,0x7,0x33,0xc4,0x6c,0x30,0x2e,0xc6,0xc3,0x42,0xb1,0x38,0x2c,0x9,0x93,0x63,0xcb,0xb1,0x22,0xac,0xc,0xab,0xc6,0x1a,0xb0,0x56,0xac,0x3,0xbb,0x89,0xf5,0x63,0xcf,0xb1,0x77,0x4,0x12,0x81,0x45,0xc0,0x9,0x36,0x4,0x77,0x42,0x20,0x61,0x1e,0x41,0x48,0x58,0x4c,0x58,0x4e,0xd8,0x48,0xa8,0x20,0x1c,0x24,0x34,0x11,0xda,0x9,0x37,0x9,0x3,0x84,0x51,0xc2,0x27,0x22,0x93,0xa8,0x4b,0xb4,0x26,0xba,0x11,0xf9,0xc4,0x18,0x62,0x32,0x31,0x87,0x58,0x48,0x2c,0x23,0xd6,0x12,0x8f,0x13,0x2f,0x10,0x7b,0x88,0x43,0xc4,0x37,0x24,0x12,0x89,0x43,0x32,0x27,0xb9,0x90,0x2,0x49,0xb1,0xa4,0x54,0xd2,0x12,0xd2,0x46,0xd2,0x6e,0x52,0x23,0xe9,0x2c,0xa9,0x9b,0x34,0x48,0x1a,0x23,0x93,0xc9,0xda,0x64,0x6b,0xb2,0x7,0x39,0x94,0x2c,0x20,0x2b,0xc8,0x85,0xe4,0x9d,0xe4,0xc3,0xe4,0x33,0xe4,0x1b,0xe4,0x21,0xf2,0x5b,0xa,0x9d,0x62,0x40,0x71,0xa4,0xf8,0x53,0xe2,0x28,0x52,0xca,0x6a,0x4a,0x19,0xe5,0x10,0xe5,0x34,0xe5,0x6,0x65,0x98,0x32,0x41,0x55,0xa3,0x9a,0x52,0xdd,0xa8,0xa1,0x54,0x11,0x35,0x8f,0x5a,0x42,0xad,0xa1,0xb6,0x52,0xaf,0x51,0x87,0xa8,0x13,0x34,0x75,0x9a,0x39,0xcd,0x83,0x16,0x49,0x4b,0xa5,0xad,0xa2,0x95,0xd3,0x1a,0x68,0x17,0x68,0xf7,0x69,0xaf,0xe8,0x74,0xba,0x11,0xdd,0x95,0x1e,0x4e,0x97,0xd0,0x57,0xd2,0xcb,0xe9,0x47,0xe8,0x97,0xe8,0x3,0xf4,0x77,0xc,0xd,0x86,0x15,0x83,0xc7,0x88,0x67,0x28,0x19,0x9b,0x18,0x7,0x18,0x67,0x19,0x77,0x18,0xaf,0x98,0x4c,0xa6,0x19,0xd3,0x8b,0x19,0xc7,0x54,0x30,0x37,0x31,0xeb,0x98,0xe7,0x99,0xf,0x99,0x6f,0x55,0x58,0x2a,0xb6,0x2a,0x7c,0x15,0x91,0xca,0xa,0x95,0x4a,0x95,0x26,0x95,0x1b,0x2a,0x2f,0x54,0xa9,0xaa,0xa6,0xaa,0xde,0xaa,0xb,0x55,0xf3,0x55,0xcb,0x54,0x8f,0xa9,0x5e,0x53,0x7d,0xae,0x46,0x55,0x33,0x53,0xe3,0xa9,0x9,0xd4,0x96,0xab,0x55,0xaa,0x9d,0x50,0xeb,0x53,0x1b,0x53,0x67,0xa9,0x3b,0xa8,0x87,0xaa,0x67,0xa8,0x6f,0x54,0x3f,0xa4,0x7e,0x59,0xfd,0x89,0x6,0x59,0xc3,0x4c,0xc3,0x4f,0x43,0xa4,0x51,0xa0,0xb1,0x5f,0xe3,0xbc,0xc6,0x20,0xb,0x63,0x19,0xb3,0x78,0x2c,0x21,0x6b,0xd,0xab,0x86,0x75,0x81,0x35,0xc4,0x26,0xb1,0xcd,0xd9,0x7c,0x76,0x2a,0xbb,0x98,0xfd,0x1d,0xbb,0x8b,0x3d,0xaa,0xa9,0xa1,0x39,0x43,0x33,0x4a,0x33,0x57,0xb3,0x52,0xf3,0x94,0x66,0x3f,0x7,0xe3,0x98,0x71,0xf8,0x9c,0x74,0x4e,0x9,0xe7,0x28,0xa7,0x97,0xf3,0x7e,0x8a,0xde,0x14,0xef,0x29,0xe2,0x29,0x1b,0xa6,0x34,0x4c,0xb9,0x31,0x65,0x5c,0x6b,0xaa,0x96,0x97,0x96,0x58,0xab,0x48,0xab,0x51,0xab,0x47,0xeb,0xbd,0x36,0xae,0xed,0xa7,0x9d,0xa6,0xbd,0x45,0xbb,0x59,0xfb,0x81,0xe,0x41,0xc7,0x4a,0x27,0x5c,0x27,0x47,0x67,0x8f,0xce,0x5,0x9d,0xe7,0x53,0xd9,0x53,0xdd,0xa7,0xa,0xa7,0x16,0x4d,0x3d,0x3a,0xf5,0xae,0x2e,0xaa,0x6b,0xa5,0x1b,0xa1,0xbb,0x44,0x77,0xbf,0x6e,0xa7,0xee,0x98,0x9e,0xbe,0x5e,0x80,0x9e,0x4c,0x6f,0xa7,0xde,0x79,0xbd,0xe7,0xfa,0x1c,0x7d,0x2f,0xfd,0x54,0xfd,0x6d,0xfa,0xa7,0xf5,0x47,0xc,0x58,0x6,0xb3,0xc,0x24,0x6,0xdb,0xc,0xce,0x18,0x3c,0xc5,0x35,0x71,0x6f,0x3c,0x1d,0x2f,0xc7,0xdb,0xf1,0x51,0x43,0x5d,0xc3,0x40,0x43,0xa5,0x61,0x95,0x61,0x97,0xe1,0x84,0x91,0xb9,0xd1,0x3c,0xa3,0xd5,0x46,0x8d,0x46,0xf,0x8c,0x69,0xc6,0x5c,0xe3,0x24,0xe3,0x6d,0xc6,0x6d,0xc6,0xa3,0x26,0x6,0x26,0x21,0x26,0x4b,0x4d,0xea,0x4d,0xee,0x9a,0x52,0x4d,0xb9,0xa6,0x29,0xa6,0x3b,0x4c,0x3b,0x4c,0xc7,0xcd,0xcc,0xcd,0xa2,0xcd,0xd6,0x99,0x35,0x9b,0x3d,0x31,0xd7,0x32,0xe7,0x9b,0xe7,0x9b,0xd7,0x9b,0xdf,0xb7,0x60,0x5a,0x78,0x5a,0x2c,0xb6,0xa8,0xb6,0xb8,0x65,0x49,0xb2,0xe4,0x5a,0xa6,0x59,0xee,0xb6,0xbc,0x6e,0x85,0x5a,0x39,0x59,0xa5,0x58,0x55,0x5a,0x5d,0xb3,0x46,0xad,0x9d,0xad,0x25,0xd6,0xbb,0xad,0xbb,0xa7,0x11,0xa7,0xb9,0x4e,0x93,0x4e,0xab,0x9e,0xd6,0x67,0xc3,0xb0,0xf1,0xb6,0xc9,0xb6,0xa9,0xb7,0x19,0xb0,0xe5,0xd8,0x6,0xdb,0xae,0xb6,0x6d,0xb6,0x7d,0x61,0x67,0x62,0x17,0x67,0xb7,0xc5,0xae,0xc3,0xee,0x93,0xbd,0x93,0x7d,0xba,0x7d,0x8d,0xfd,0x3d,0x7,0xd,0x87,0xd9,0xe,0xab,0x1d,0x5a,0x1d,0x7e,0x73,0xb4,0x72,0x14,0x3a,0x56,0x3a,0xde,0x9a,0xce,0x9c,0xee,0x3f,0x7d,0xc5,0xf4,0x96,0xe9,0x2f,0x67,0x58,0xcf,0x10,0xcf,0xd8,0x33,0xe3,0xb6,0x13,0xcb,0x29,0xc4,0x69,0x9d,0x53,0x9b,0xd3,0x47,0x67,0x17,0x67,0xb9,0x73,0x83,0xf3,0x88,0x8b,0x89,0x4b,0x82,0xcb,0x2e,0x97,0x3e,0x2e,0x9b,0x1b,0xc6,0xdd,0xc8,0xbd,0xe4,0x4a,0x74,0xf5,0x71,0x5d,0xe1,0x7a,0xd2,0xf5,0x9d,0x9b,0xb3,0x9b,0xc2,0xed,0xa8,0xdb,0xaf,0xee,0x36,0xee,0x69,0xee,0x87,0xdc,0x9f,0xcc,0x34,0x9f,0x29,0x9e,0x59,0x33,0x73,0xd0,0xc3,0xc8,0x43,0xe0,0x51,0xe5,0xd1,0x3f,0xb,0x9f,0x95,0x30,0x6b,0xdf,0xac,0x7e,0x4f,0x43,0x4f,0x81,0x67,0xb5,0xe7,0x23,0x2f,0x63,0x2f,0x91,0x57,0xad,0xd7,0xb0,0xb7,0xa5,0x77,0xaa,0xf7,0x61,0xef,0x17,0x3e,0xf6,0x3e,0x72,0x9f,0xe3,0x3e,0xe3,0x3c,0x37,0xde,0x32,0xde,0x59,0x5f,0xcc,0x37,0xc0,0xb7,0xc8,0xb7,0xcb,0x4f,0xc3,0x6f,0x9e,0x5f,0x85,0xdf,0x43,0x7f,0x23,0xff,0x64,0xff,0x7a,0xff,0xd1,0x0,0xa7,0x80,0x25,0x1,0x67,0x3,0x89,0x81,0x41,0x81,0x5b,0x2,0xfb,0xf8,0x7a,0x7c,0x21,0xbf,0x8e,0x3f,0x3a,0xdb,0x65,0xf6,0xb2,0xd9,0xed,0x41,0x8c,0xa0,0xb9,0x41,0x15,0x41,0x8f,0x82,0xad,0x82,0xe5,0xc1,0xad,0x21,0x68,0xc8,0xec,0x90,0xad,0x21,0xf7,0xe7,0x98,0xce,0x91,0xce,0x69,0xe,0x85,0x50,0x7e,0xe8,0xd6,0xd0,0x7,0x61,0xe6,0x61,0x8b,0xc3,0x7e,0xc,0x27,0x85,0x87,0x85,0x57,0x86,0x3f,0x8e,0x70,0x88,0x58,0x1a,0xd1,0x31,0x97,0x35,0x77,0xd1,0xdc,0x43,0x73,0xdf,0x44,0xfa,0x44,0x96,0x44,0xde,0x9b,0x67,0x31,0x4f,0x39,0xaf,0x2d,0x4a,0x35,0x2a,0x3e,0xaa,0x2e,0x6a,0x3c,0xda,0x37,0xba,0x34,0xba,0x3f,0xc6,0x2e,0x66,0x59,0xcc,0xd5,0x58,0x9d,0x58,0x49,0x6c,0x4b,0x1c,0x39,0x2e,0x2a,0xae,0x36,0x6e,0x6c,0xbe,0xdf,0xfc,0xed,0xf3,0x87,0xe2,0x9d,0xe2,0xb,0xe3,0x7b,0x17,0x98,0x2f,0xc8,0x5d,0x70,0x79,0xa1,0xce,0xc2,0xf4,0x85,0xa7,0x16,0xa9,0x2e,0x12,0x2c,0x3a,0x96,0x40,0x4c,0x88,0x4e,0x38,0x94,0xf0,0x41,0x10,0x2a,0xa8,0x16,0x8c,0x25,0xf2,0x13,0x77,0x25,0x8e,0xa,0x79,0xc2,0x1d,0xc2,0x67,0x22,0x2f,0xd1,0x36,0xd1,0x88,0xd8,0x43,0x5c,0x2a,0x1e,0x4e,0xf2,0x48,0x2a,0x4d,0x7a,0x92,0xec,0x91,0xbc,0x35,0x79,0x24,0xc5,0x33,0xa5,0x2c,0xe5,0xb9,0x84,0x27,0xa9,0x90,0xbc,0x4c,0xd,0x4c,0xdd,0x9b,0x3a,0x9e,0x16,0x9a,0x76,0x20,0x6d,0x32,0x3d,0x3a,0xbd,0x31,0x83,0x92,0x91,0x90,0x71,0x42,0xaa,0x21,0x4d,0x93,0xb6,0x67,0xea,0x67,0xe6,0x66,0x76,0xcb,0xac,0x65,0x85,0xb2,0xfe,0xc5,0x6e,0x8b,0xb7,0x2f,0x1e,0x95,0x7,0xc9,0x6b,0xb3,0x90,0xac,0x5,0x59,0x2d,0xa,0xb6,0x42,0xa6,0xe8,0x54,0x5a,0x28,0xd7,0x2a,0x7,0xb2,0x67,0x65,0x57,0x66,0xbf,0xcd,0x89,0xca,0x39,0x96,0xab,0x9e,0x2b,0xcd,0xed,0xcc,0xb3,0xca,0xdb,0x90,0x37,0x9c,0xef,0x9f,0xff,0xed,0x12,0xc2,0x12,0xe1,0x92,0xb6,0xa5,0x86,0x4b,0x57,0x2d,0x1d,0x58,0xe6,0xbd,0xac,0x6a,0x39,0xb2,0x3c,0x71,0x79,0xdb,0xa,0xe3,0x15,0x5,0x2b,0x86,0x56,0x6,0xac,0x3c,0xb8,0x8a,0xb6,0x2a,0x6d,0xd5,0x4f,0xab,0xed,0x57,0x97,0xae,0x7e,0xbd,0x26,0x7a,0x4d,0x6b,0x81,0x5e,0xc1,0xca,0x82,0xc1,0xb5,0x1,0x6b,0xeb,0xb,0x55,0xa,0xe5,0x85,0x7d,0xeb,0xdc,0xd7,0xed,0x5d,0x4f,0x58,0x2f,0x59,0xdf,0xb5,0x61,0xfa,0x86,0x9d,0x1b,0x3e,0x15,0x89,0x8a,0xae,0x14,0xdb,0x17,0x97,0x15,0x7f,0xd8,0x28,0xdc,0x78,0xe5,0x1b,0x87,0x6f,0xca,0xbf,0x99,0xdc,0x94,0xb4,0xa9,0xab,0xc4,0xb9,0x64,0xcf,0x66,0xd2,0x66,0xe9,0xe6,0xde,0x2d,0x9e,0x5b,0xe,0x96,0xaa,0x97,0xe6,0x97,0xe,0x6e,0xd,0xd9,0xda,0xb4,0xd,0xdf,0x56,0xb4,0xed,0xf5,0xf6,0x45,0xdb,0x2f,0x97,0xcd,0x28,0xdb,0xbb,0x83,0xb6,0x43,0xb9,0xa3,0xbf,0x3c,0xb8,0xbc,0x65,0xa7,0xc9,0xce,0xcd,0x3b,0x3f,0x54,0xa4,0x54,0xf4,0x54,0xfa,0x54,0x36,0xee,0xd2,0xdd,0xb5,0x61,0xd7,0xf8,0x6e,0xd1,0xee,0x1b,0x7b,0xbc,0xf6,0x34,0xec,0xd5,0xdb,0x5b,0xbc,0xf7,0xfd,0x3e,0xc9,0xbe,0xdb,0x55,0x1,0x55,0x4d,0xd5,0x66,0xd5,0x65,0xfb,0x49,0xfb,0xb3,0xf7,0x3f,0xae,0x89,0xaa,0xe9,0xf8,0x96,0xfb,0x6d,0x5d,0xad,0x4e,0x6d,0x71,0xed,0xc7,0x3,0xd2,0x3,0xfd,0x7,0x23,0xe,0xb6,0xd7,0xb9,0xd4,0xd5,0x1d,0xd2,0x3d,0x54,0x52,0x8f,0xd6,0x2b,0xeb,0x47,0xe,0xc7,0x1f,0xbe,0xfe,0x9d,0xef,0x77,0x2d,0xd,0x36,0xd,0x55,0x8d,0x9c,0xc6,0xe2,0x23,0x70,0x44,0x79,0xe4,0xe9,0xf7,0x9,0xdf,0xf7,0x1e,0xd,0x3a,0xda,0x76,0x8c,0x7b,0xac,0xe1,0x7,0xd3,0x1f,0x76,0x1d,0x67,0x1d,0x2f,0x6a,0x42,0x9a,0xf2,0x9a,0x46,0x9b,0x53,0x9a,0xfb,0x5b,0x62,0x5b,0xba,0x4f,0xcc,0x3e,0xd1,0xd6,0xea,0xde,0x7a,0xfc,0x47,0xdb,0x1f,0xf,0x9c,0x34,0x3c,0x59,0x79,0x4a,0xf3,0x54,0xc9,0x69,0xda,0xe9,0x82,0xd3,0x93,0x67,0xf2,0xcf,0x8c,0x9d,0x95,0x9d,0x7d,0x7e,0x2e,0xf9,0xdc,0x60,0xdb,0xa2,0xb6,0x7b,0xe7,0x63,0xce,0xdf,0x6a,0xf,0x6f,0xef,0xba,0x10,0x74,0xe1,0xd2,0x45,0xff,0x8b,0xe7,0x3b,0xbc,0x3b,0xce,0x5c,0xf2,0xb8,0x74,0xf2,0xb2,0xdb,0xe5,0x13,0x57,0xb8,0x57,0x9a,0xaf,0x3a,0x5f,0x6d,0xea,0x74,0xea,0x3c,0xfe,0x93,0xd3,0x4f,0xc7,0xbb,0x9c,0xbb,0x9a,0xae,0xb9,0x5c,0x6b,0xb9,0xee,0x7a,0xbd,0xb5,0x7b,0x66,0xf7,0xe9,0x1b,0x9e,0x37,0xce,0xdd,0xf4,0xbd,0x79,0xf1,0x16,0xff,0xd6,0xd5,0x9e,0x39,0x3d,0xdd,0xbd,0xf3,0x7a,0x6f,0xf7,0xc5,0xf7,0xf5,0xdf,0x16,0xdd,0x7e,0x72,0x27,0xfd,0xce,0xcb,0xbb,0xd9,0x77,0x27,0xee,0xad,0xbc,0x4f,0xbc,0x5f,0xf4,0x40,0xed,0x41,0xd9,0x43,0xdd,0x87,0xd5,0x3f,0x5b,0xfe,0xdc,0xd8,0xef,0xdc,0x7f,0x6a,0xc0,0x77,0xa0,0xf3,0xd1,0xdc,0x47,0xf7,0x6,0x85,0x83,0xcf,0xfe,0x91,0xf5,0x8f,0xf,0x43,0x5,0x8f,0x99,0x8f,0xcb,0x86,0xd,0x86,0xeb,0x9e,0x38,0x3e,0x39,0x39,0xe2,0x3f,0x72,0xfd,0xe9,0xfc,0xa7,0x43,0xcf,0x64,0xcf,0x26,0x9e,0x17,0xfe,0xa2,0xfe,0xcb,0xae,0x17,0x16,0x2f,0x7e,0xf8,0xd5,0xeb,0xd7,0xce,0xd1,0x98,0xd1,0xa1,0x97,0xf2,0x97,0x93,0xbf,0x6d,0x7c,0xa5,0xfd,0xea,0xc0,0xeb,0x19,0xaf,0xdb,0xc6,0xc2,0xc6,0x1e,0xbe,0xc9,0x78,0x33,0x31,0x5e,0xf4,0x56,0xfb,0xed,0xc1,0x77,0xdc,0x77,0x1d,0xef,0xa3,0xdf,0xf,0x4f,0xe4,0x7c,0x20,0x7f,0x28,0xff,0x68,0xf9,0xb1,0xf5,0x53,0xd0,0xa7,0xfb,0x93,0x19,0x93,0x93,0xff,0x4,0x3,0x98,0xf3,0xfc,0xef,0x35,0x94,0x82,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xa,0x14,0x2,0x33,0x2,0xa3,0x96,0xc,0x41,0x0,0x0,0x1,0x42,0x49,0x44,0x41,0x54,0x38,0xcb,0xa5,0x93,0x51,0x4a,0xc3,0x40,0x10,0x86,0xbf,0x99,0xdd,0x4d,0x44,0x1f,0x9a,0x7,0x5b,0x5a,0x3c,0x84,0xf8,0xe4,0x3d,0x3c,0x4d,0x8e,0x50,0x3c,0x8c,0x37,0xf0,0x0,0x3e,0x89,0x87,0x50,0x3,0x8a,0xa4,0xd8,0x42,0x5b,0x76,0x13,0x1f,0x3a,0x29,0x55,0x4a,0x48,0xf1,0x87,0x81,0x61,0xd9,0xf9,0x67,0xfe,0xe1,0x1f,0x1,0x3c,0x90,0x1,0x39,0x70,0x66,0xb9,0x3,0x94,0xdf,0x68,0x80,0x4,0x6c,0x81,0x35,0xb0,0x1,0xb6,0x5d,0xf1,0x5,0x50,0x0,0x23,0xcb,0x73,0x40,0x2c,0x0,0x5a,0x8b,0xd,0xb0,0x2,0x16,0x40,0x8d,0x75,0xcf,0x81,0xe2,0xe6,0xfa,0xf6,0x6e,0x7c,0x39,0x2d,0x53,0x4a,0x45,0x4b,0xcb,0x31,0x8,0x82,0x73,0xae,0xfe,0xf8,0xac,0xe6,0xcf,0x2f,0x4f,0xf,0x40,0xf4,0x36,0xf6,0x68,0x32,0x9e,0x95,0xdf,0xcb,0x45,0x11,0x63,0xa4,0xf,0xde,0xfb,0x62,0x32,0x9e,0x95,0xc0,0x23,0xb0,0xdc,0x4b,0x48,0x4d,0x53,0xc4,0x98,0xe,0xa6,0x3e,0x8e,0x18,0x13,0xa9,0x69,0xa,0x93,0x9a,0x79,0x5b,0x58,0xae,0x8,0x2a,0xfd,0xc5,0x1d,0x74,0xd7,0x24,0x7,0x9c,0xb7,0x6d,0x8b,0x38,0x41,0x74,0x18,0x81,0x38,0xc1,0x46,0x55,0xdf,0xbd,0xa9,0x38,0x44,0x74,0xd8,0x4,0xe2,0x3a,0x2,0xfc,0x9e,0x55,0x4,0x19,0x28,0xe1,0xf0,0x5f,0x47,0xd0,0x8a,0x9e,0x40,0xb0,0x93,0xda,0x76,0x4,0xd,0xd0,0x3a,0x71,0xe8,0x40,0x9,0x6e,0x27,0xa1,0x5,0x1a,0x6f,0xf6,0xdc,0xa8,0x53,0x44,0xb5,0x23,0xee,0xeb,0x8f,0x3a,0xc5,0x5c,0x99,0xd4,0xbc,0xbd,0xa,0x21,0xd4,0x59,0x8,0xa8,0xe8,0x7e,0x1f,0x7f,0x43,0x45,0xc9,0x42,0x20,0x84,0xac,0x36,0x4b,0x6f,0xbd,0x1d,0xc6,0xa2,0xaa,0xde,0xe6,0xb3,0xe9,0x55,0x19,0x63,0xec,0xb5,0xb2,0xf7,0xfe,0xeb,0xbd,0x7a,0xbd,0xb7,0x7b,0x58,0xb,0x70,0xfe,0x8f,0x63,0x5a,0x79,0x93,0x0,0x10,0x81,0xe5,0xa9,0xe7,0xfc,0x3,0xc1,0x39,0x63,0x22,0xdc,0x9d,0xb2,0x6a,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char checked_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x0,0x0,0x0,0x0,0x0,0xf9,0x43,0xbb,0x7f,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x12,0x0,0x36,0x36,0x55,0x46,0x2e,0x76,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x1,0xbd,0x49,0x44,0x41,0x54,0x38,0x8d,0x8d,0x93,0x4f,0x6b,0x13,0x51,0x14,0xc5,0x7f,0x93,0x99,0x84,0xa1,0xd2,0x8c,0x90,0x49,0xba,0xea,0xb6,0x1f,0xa0,0x8,0x76,0xa3,0xad,0x6d,0x53,0x4a,0x96,0x22,0x4a,0xb,0x2e,0x55,0xfc,0x6,0x36,0x74,0x2b,0x45,0xba,0xaf,0x71,0x61,0x71,0x95,0x42,0x37,0x52,0xdc,0x34,0x85,0x92,0xa2,0xb8,0xb7,0x4,0x4d,0xd5,0xb8,0xd2,0x85,0x98,0xcc,0x22,0x23,0x99,0xc9,0xcc,0xa4,0x6f,0xba,0xc8,0x4c,0x9b,0x92,0x97,0xd2,0xb,0x8f,0xb,0xef,0xbd,0x73,0xce,0xfd,0xab,0xd0,0x37,0x5,0x48,0x0,0x5a,0xe4,0xaf,0x32,0x1,0xf4,0x22,0x1f,0x2a,0x11,0x38,0x9,0x64,0x80,0x49,0x20,0x7d,0x5,0x89,0x0,0x6c,0xe0,0x37,0x60,0x1,0x41,0xac,0x98,0xd1,0x54,0x6d,0x6e,0x61,0x3e,0x5f,0x4e,0x26,0x93,0x52,0x64,0x36,0x97,0x65,0xad,0xf8,0x2,0xd7,0x75,0x99,0x99,0xb9,0xfd,0xd8,0x75,0xdd,0x43,0xe0,0x9f,0xa,0xa4,0x80,0xa9,0xa5,0xfc,0xf2,0xbe,0xe7,0x79,0xd8,0xb6,0x8d,0xe3,0x38,0x43,0xe7,0xd9,0xd3,0x27,0x8c,0xa7,0xc7,0x29,0x6d,0xbd,0x21,0x97,0x9d,0xb8,0xff,0xfd,0xc7,0xc9,0x2e,0xd0,0x4c,0x44,0x11,0x18,0x9a,0xa6,0xd1,0xed,0x76,0xa5,0xea,0x85,0x42,0x81,0xe9,0x5b,0xd3,0xec,0xbd,0xdf,0xa3,0x56,0xab,0x11,0x86,0x21,0x80,0x1,0x24,0xe2,0x5c,0x95,0x41,0x80,0xaa,0xaa,0x97,0x8,0x1e,0x3e,0x7a,0x40,0xe3,0xe7,0x2f,0xaa,0xd5,0x23,0x82,0x20,0x40,0x8,0x41,0x24,0xac,0x48,0x8b,0xb5,0xb2,0xba,0x42,0xa9,0xf4,0x1a,0xc3,0x30,0xb8,0x3b,0x77,0x87,0xb1,0x1b,0x63,0x54,0x2a,0x7,0x74,0x3a,0x9d,0xa1,0xbf,0x9a,0x8c,0x60,0xa7,0xbc,0xc3,0xe2,0xe2,0x3c,0x1b,0x1b,0x2f,0xe9,0x7a,0x1e,0xdf,0xbe,0xd6,0x39,0xfe,0x72,0x2c,0x4d,0x4f,0x1a,0x81,0x10,0x82,0x62,0x71,0x9d,0xf4,0x4d,0x3,0xd3,0xcc,0x50,0xd9,0x3f,0xc0,0xb2,0xac,0xeb,0x13,0x84,0x61,0x88,0xd5,0x6a,0xb1,0xf9,0x6a,0x13,0xdb,0xfe,0x4f,0xbd,0x5e,0x97,0x82,0x47,0x12,0x0,0x78,0x9e,0x8f,0xe3,0xb8,0x6c,0xbf,0xdd,0xa6,0xdd,0x6e,0x8f,0x24,0x88,0x6b,0x10,0xca,0x1e,0x1b,0x8d,0x6,0xa6,0x99,0x89,0xdb,0x76,0xa1,0xda,0x6f,0xde,0x79,0x2b,0x4,0xd0,0xee,0xf5,0x7a,0xe8,0xba,0x3e,0x94,0x4a,0xb3,0xd9,0xba,0x74,0xa7,0xeb,0x3a,0xbe,0xef,0x43,0x7f,0xa4,0x4f,0x15,0x40,0x5,0x26,0x52,0xa9,0x54,0xfe,0xde,0xec,0xc2,0xbb,0x51,0xa3,0x1c,0x5b,0x10,0x4,0x7c,0xfa,0xfc,0xf1,0xb9,0xe3,0x74,0x3e,0x0,0x7f,0x7,0x97,0xc9,0xe4,0xfa,0xcb,0xf4,0x7,0x68,0x1,0x7e,0x3c,0x81,0x83,0xeb,0xac,0xca,0xb1,0xe7,0x76,0xca,0xc0,0x3a,0x9f,0x1,0x62,0x9,0xad,0x4a,0x1e,0xbc,0xe7,0x4d,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xb,0xd,0x16,0x30,0x0,0x6d,0xeb,0x4,0xa7,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x1,0xc1,0x49,0x44,0x41,0x54,0x38,0xcb,0xad,0x93,0x41,0x6b,0x13,0x51,0x14,0x85,0xbf,0x77,0x33,0xe3,0x80,0x5d,0x58,0x82,0x13,0x5b,0x28,0xa6,0xdb,0xda,0x3f,0xd0,0x76,0x67,0x17,0x5d,0xa4,0x2d,0x23,0xa,0x62,0xc0,0x5f,0xa0,0x69,0x37,0x82,0xd0,0x5d,0xb0,0x8b,0x52,0xa1,0x20,0x14,0x9,0x48,0x5,0x3,0x52,0x29,0x36,0x48,0x28,0x2e,0x14,0x8a,0xab,0x26,0xf5,0x7,0x84,0xb1,0xbb,0x11,0xa,0xb6,0x49,0x9,0xd9,0xa6,0x49,0xdf,0x73,0xe1,0x4c,0x48,0x71,0xd2,0x8d,0x5e,0x78,0xf0,0xe0,0x9e,0x7b,0xee,0xb9,0xf7,0x9d,0x7,0xff,0x18,0xa,0x60,0x71,0x3e,0xeb,0x0,0xe3,0xc0,0x4,0x90,0x2,0x24,0xe,0x3c,0x34,0x74,0x5d,0x1e,0x65,0xef,0xdf,0x7a,0xbb,0xf5,0x7e,0x1b,0x8,0xf6,0x3e,0x7f,0x68,0x5b,0x61,0x6e,0xbc,0x71,0xf6,0x6b,0xe3,0xe4,0xf4,0x78,0x4e,0x6b,0x6d,0x2b,0xa5,0x62,0xbb,0xe5,0x72,0x4f,0xf0,0xee,0x65,0xb8,0xe6,0x58,0x8f,0xb,0xaf,0xdf,0x65,0x80,0xa3,0x88,0x60,0xe2,0xe4,0xf4,0x78,0xe,0xb0,0x2d,0xcb,0x26,0x8e,0x20,0x9d,0x4e,0xb3,0xb4,0xf4,0x14,0x63,0xc,0xc5,0x62,0xf1,0x76,0xa8,0xf6,0x28,0x92,0x9a,0xd2,0x5a,0xdb,0x22,0x9,0x12,0x89,0x4,0x22,0xc2,0xe4,0xe4,0x9d,0xde,0x5d,0x44,0x58,0x5d,0xcd,0xe3,0x38,0xe,0xbb,0xbb,0x25,0xaa,0xd5,0x43,0x2b,0x1c,0xb5,0x37,0xab,0x28,0xa5,0x7a,0x9d,0x37,0x37,0x5f,0x51,0x2e,0x97,0x98,0x9e,0x9e,0x2,0xc0,0xf3,0x16,0x99,0x99,0x99,0xa2,0xd9,0x6c,0xb2,0xbe,0xbe,0x11,0xe1,0x84,0x41,0xcb,0xaa,0xd5,0x6a,0x0,0x64,0xb3,0xf,0x19,0x1e,0xbe,0xc1,0xca,0xca,0x73,0x0,0xd6,0xd6,0x5e,0xd2,0x6a,0xb5,0x2e,0x61,0xad,0x38,0x82,0x52,0xe9,0x13,0xcb,0xcb,0x39,0x66,0x67,0xef,0x72,0x7e,0xde,0x21,0x99,0x4c,0x52,0xa9,0x1c,0x52,0x2e,0xef,0xfd,0x85,0x8d,0x55,0xd0,0x68,0x9c,0xb1,0xbf,0xff,0xd,0xdb,0xb6,0x59,0x58,0xc8,0xd0,0x6e,0xb7,0xc9,0xe7,0x5f,0xc4,0xbe,0x8c,0xc,0x32,0xc8,0xce,0xce,0xc7,0x3f,0x46,0x51,0x8a,0x42,0xe1,0xd,0x41,0xf0,0x33,0x16,0x67,0xd,0x22,0x38,0x38,0xa8,0xe0,0x79,0xf,0x70,0xdd,0x9b,0x54,0xab,0xdf,0x7,0x3a,0x31,0x22,0xd0,0xc6,0x18,0x8c,0x31,0xbd,0x84,0x31,0x6,0xdf,0xff,0x81,0xef,0x5f,0x2e,0xe8,0xc3,0xe9,0x7e,0x82,0xba,0x88,0x74,0xb4,0xbe,0xb0,0x23,0xd9,0x71,0x61,0x8c,0x41,0xeb,0xb,0x44,0xa4,0xb,0xd4,0xfb,0x77,0xe0,0x8f,0xa4,0xc6,0xbe,0x2,0xdd,0x6e,0xb7,0xc3,0x55,0x7,0x54,0x67,0x24,0x35,0xf6,0x5,0xf0,0xfb,0x15,0x4,0xae,0x3b,0xfa,0xcc,0x75,0x47,0xb7,0xae,0xfa,0x4c,0xa1,0xec,0x7a,0x58,0x1c,0xf0,0x3f,0xe2,0x37,0x4f,0x82,0xa8,0x62,0xbb,0xcc,0x8d,0x11,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -80,7 +85,7 @@ static const unsigned char error_icon_png[]={
static const unsigned char focus_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0xf,0x14,0x37,0x23,0x98,0xdc,0x7f,0x32,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x1,0x33,0x49,0x44,0x41,0x54,0x38,0x8d,0xad,0x53,0x3b,0x6e,0xc2,0x50,0x10,0x9c,0x85,0xe7,0x8,0x65,0xe5,0x2,0x71,0x4,0xce,0x90,0x1b,0xa4,0xcd,0x2d,0x9c,0x23,0xb8,0x40,0xb2,0x84,0xa9,0x38,0x44,0x8e,0x91,0x36,0x15,0x25,0x39,0x3,0xfd,0x2b,0x48,0x85,0x5e,0x8c,0x60,0xf3,0x26,0x5,0x7e,0x91,0x45,0x70,0x94,0xdf,0x48,0xa3,0xad,0x66,0xa4,0xdd,0x9d,0x11,0xb4,0x20,0x29,0x0,0x6,0x2d,0xd1,0x99,0x9,0xb1,0x33,0xa3,0x88,0x10,0x0,0xa4,0x23,0x76,0x0,0xae,0x5a,0xba,0x33,0xb3,0xd8,0xd2,0x0,0x1c,0x5a,0x9a,0x88,0x50,0x3a,0xe2,0xd1,0x72,0xb9,0x7c,0xd8,0xed,0x76,0xb7,0xc7,0xe3,0x71,0x82,0xb,0xc8,0xb2,0xec,0x25,0xcf,0xf3,0xa7,0xd9,0x6c,0x76,0xf,0x60,0xf,0xc0,0x40,0x72,0x48,0x52,0xeb,0xba,0x5e,0x15,0x45,0x41,0xef,0xfd,0x45,0x31,0x0,0x78,0xef,0x27,0x45,0x51,0xb0,0xae,0xeb,0x15,0x49,0x25,0x39,0x4,0xc9,0x8c,0xe4,0xb8,0x2c,0xcb,0xc6,0xcc,0x44,0x55,0xa7,0x7d,0x6,0xaa,0x3a,0x35,0x33,0x29,0xcb,0xb2,0x21,0x39,0x26,0x99,0xa5,0x3d,0x1d,0xc9,0x91,0x73,0x8e,0x21,0x84,0x4d,0x9f,0x41,0x8,0x61,0xe3,0x9c,0x23,0xc9,0x51,0xba,0x53,0xdf,0xc5,0xbf,0x83,0x41,0x57,0xf8,0x67,0x83,0x5f,0xa3,0xfb,0xe7,0x9f,0x22,0xfe,0x9b,0x41,0xc4,0x29,0x55,0xcd,0x57,0x19,0x48,0xf0,0xde,0x4f,0x44,0xa4,0xc1,0x29,0x95,0x31,0x19,0x1c,0x54,0x75,0x5d,0x55,0xd5,0xd6,0xcc,0xf2,0x3e,0xb1,0x99,0xe5,0x55,0x55,0x6d,0x55,0x75,0x8d,0x53,0x9c,0x63,0x37,0xca,0xd7,0x8b,0xc5,0xe2,0x31,0x84,0x70,0xd3,0xfe,0xf9,0x13,0x44,0x64,0xaf,0xaa,0xcf,0xf3,0xf9,0xfc,0xe,0xc0,0x2b,0x0,0x4b,0x65,0x1a,0xb6,0xeb,0xfc,0xa4,0x4c,0x51,0x44,0xde,0x24,0xb9,0x9f,0xd5,0xb9,0xef,0xbd,0xc9,0xe8,0xa3,0xce,0xef,0x1,0xe9,0xa5,0x7b,0x14,0xf7,0x5d,0x8c,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0xc,0x0,0x0,0x0,0xc,0x8,0x6,0x0,0x0,0x0,0x56,0x75,0x5c,0xe7,0x0,0x0,0xa,0x45,0x69,0x43,0x43,0x50,0x49,0x43,0x43,0x20,0x70,0x72,0x6f,0x66,0x69,0x6c,0x65,0x0,0x0,0x78,0xda,0x9d,0x53,0x67,0x54,0x53,0xe9,0x16,0x3d,0xf7,0xde,0xf4,0x42,0x4b,0x88,0x80,0x94,0x4b,0x6f,0x52,0x15,0x8,0x20,0x52,0x42,0x8b,0x80,0x14,0x91,0x26,0x2a,0x21,0x9,0x10,0x4a,0x88,0x21,0xa1,0xd9,0x15,0x51,0xc1,0x11,0x45,0x45,0x4,0x1b,0xc8,0xa0,0x88,0x3,0x8e,0x8e,0x80,0x8c,0x15,0x51,0x2c,0xc,0x8a,0xa,0xd8,0x7,0xe4,0x21,0xa2,0x8e,0x83,0xa3,0x88,0x8a,0xca,0xfb,0xe1,0x7b,0xa3,0x6b,0xd6,0xbc,0xf7,0xe6,0xcd,0xfe,0xb5,0xd7,0x3e,0xe7,0xac,0xf3,0x9d,0xb3,0xcf,0x7,0xc0,0x8,0xc,0x96,0x48,0x33,0x51,0x35,0x80,0xc,0xa9,0x42,0x1e,0x11,0xe0,0x83,0xc7,0xc4,0xc6,0xe1,0xe4,0x2e,0x40,0x81,0xa,0x24,0x70,0x0,0x10,0x8,0xb3,0x64,0x21,0x73,0xfd,0x23,0x1,0x0,0xf8,0x7e,0x3c,0x3c,0x2b,0x22,0xc0,0x7,0xbe,0x0,0x1,0x78,0xd3,0xb,0x8,0x0,0xc0,0x4d,0x9b,0xc0,0x30,0x1c,0x87,0xff,0xf,0xea,0x42,0x99,0x5c,0x1,0x80,0x84,0x1,0xc0,0x74,0x91,0x38,0x4b,0x8,0x80,0x14,0x0,0x40,0x7a,0x8e,0x42,0xa6,0x0,0x40,0x46,0x1,0x80,0x9d,0x98,0x26,0x53,0x0,0xa0,0x4,0x0,0x60,0xcb,0x63,0x62,0xe3,0x0,0x50,0x2d,0x0,0x60,0x27,0x7f,0xe6,0xd3,0x0,0x80,0x9d,0xf8,0x99,0x7b,0x1,0x0,0x5b,0x94,0x21,0x15,0x1,0xa0,0x91,0x0,0x20,0x13,0x65,0x88,0x44,0x0,0x68,0x3b,0x0,0xac,0xcf,0x56,0x8a,0x45,0x0,0x58,0x30,0x0,0x14,0x66,0x4b,0xc4,0x39,0x0,0xd8,0x2d,0x0,0x30,0x49,0x57,0x66,0x48,0x0,0xb0,0xb7,0x0,0xc0,0xce,0x10,0xb,0xb2,0x0,0x8,0xc,0x0,0x30,0x51,0x88,0x85,0x29,0x0,0x4,0x7b,0x0,0x60,0xc8,0x23,0x23,0x78,0x0,0x84,0x99,0x0,0x14,0x46,0xf2,0x57,0x3c,0xf1,0x2b,0xae,0x10,0xe7,0x2a,0x0,0x0,0x78,0x99,0xb2,0x3c,0xb9,0x24,0x39,0x45,0x81,0x5b,0x8,0x2d,0x71,0x7,0x57,0x57,0x2e,0x1e,0x28,0xce,0x49,0x17,0x2b,0x14,0x36,0x61,0x2,0x61,0x9a,0x40,0x2e,0xc2,0x79,0x99,0x19,0x32,0x81,0x34,0xf,0xe0,0xf3,0xcc,0x0,0x0,0xa0,0x91,0x15,0x11,0xe0,0x83,0xf3,0xfd,0x78,0xce,0xe,0xae,0xce,0xce,0x36,0x8e,0xb6,0xe,0x5f,0x2d,0xea,0xbf,0x6,0xff,0x22,0x62,0x62,0xe3,0xfe,0xe5,0xcf,0xab,0x70,0x40,0x0,0x0,0xe1,0x74,0x7e,0xd1,0xfe,0x2c,0x2f,0xb3,0x1a,0x80,0x3b,0x6,0x80,0x6d,0xfe,0xa2,0x25,0xee,0x4,0x68,0x5e,0xb,0xa0,0x75,0xf7,0x8b,0x66,0xb2,0xf,0x40,0xb5,0x0,0xa0,0xe9,0xda,0x57,0xf3,0x70,0xf8,0x7e,0x3c,0x3c,0x45,0xa1,0x90,0xb9,0xd9,0xd9,0xe5,0xe4,0xe4,0xd8,0x4a,0xc4,0x42,0x5b,0x61,0xca,0x57,0x7d,0xfe,0x67,0xc2,0x5f,0xc0,0x57,0xfd,0x6c,0xf9,0x7e,0x3c,0xfc,0xf7,0xf5,0xe0,0xbe,0xe2,0x24,0x81,0x32,0x5d,0x81,0x47,0x4,0xf8,0xe0,0xc2,0xcc,0xf4,0x4c,0xa5,0x1c,0xcf,0x92,0x9,0x84,0x62,0xdc,0xe6,0x8f,0x47,0xfc,0xb7,0xb,0xff,0xfc,0x1d,0xd3,0x22,0xc4,0x49,0x62,0xb9,0x58,0x2a,0x14,0xe3,0x51,0x12,0x71,0x8e,0x44,0x9a,0x8c,0xf3,0x32,0xa5,0x22,0x89,0x42,0x92,0x29,0xc5,0x25,0xd2,0xff,0x64,0xe2,0xdf,0x2c,0xfb,0x3,0x3e,0xdf,0x35,0x0,0xb0,0x6a,0x3e,0x1,0x7b,0x91,0x2d,0xa8,0x5d,0x63,0x3,0xf6,0x4b,0x27,0x10,0x58,0x74,0xc0,0xe2,0xf7,0x0,0x0,0xf2,0xbb,0x6f,0xc1,0xd4,0x28,0x8,0x3,0x80,0x68,0x83,0xe1,0xcf,0x77,0xff,0xef,0x3f,0xfd,0x47,0xa0,0x25,0x0,0x80,0x66,0x49,0x92,0x71,0x0,0x0,0x5e,0x44,0x24,0x2e,0x54,0xca,0xb3,0x3f,0xc7,0x8,0x0,0x0,0x44,0xa0,0x81,0x2a,0xb0,0x41,0x1b,0xf4,0xc1,0x18,0x2c,0xc0,0x6,0x1c,0xc1,0x5,0xdc,0xc1,0xb,0xfc,0x60,0x36,0x84,0x42,0x24,0xc4,0xc2,0x42,0x10,0x42,0xa,0x64,0x80,0x1c,0x72,0x60,0x29,0xac,0x82,0x42,0x28,0x86,0xcd,0xb0,0x1d,0x2a,0x60,0x2f,0xd4,0x40,0x1d,0x34,0xc0,0x51,0x68,0x86,0x93,0x70,0xe,0x2e,0xc2,0x55,0xb8,0xe,0x3d,0x70,0xf,0xfa,0x61,0x8,0x9e,0xc1,0x28,0xbc,0x81,0x9,0x4,0x41,0xc8,0x8,0x13,0x61,0x21,0xda,0x88,0x1,0x62,0x8a,0x58,0x23,0x8e,0x8,0x17,0x99,0x85,0xf8,0x21,0xc1,0x48,0x4,0x12,0x8b,0x24,0x20,0xc9,0x88,0x14,0x51,0x22,0x4b,0x91,0x35,0x48,0x31,0x52,0x8a,0x54,0x20,0x55,0x48,0x1d,0xf2,0x3d,0x72,0x2,0x39,0x87,0x5c,0x46,0xba,0x91,0x3b,0xc8,0x0,0x32,0x82,0xfc,0x86,0xbc,0x47,0x31,0x94,0x81,0xb2,0x51,0x3d,0xd4,0xc,0xb5,0x43,0xb9,0xa8,0x37,0x1a,0x84,0x46,0xa2,0xb,0xd0,0x64,0x74,0x31,0x9a,0x8f,0x16,0xa0,0x9b,0xd0,0x72,0xb4,0x1a,0x3d,0x8c,0x36,0xa1,0xe7,0xd0,0xab,0x68,0xf,0xda,0x8f,0x3e,0x43,0xc7,0x30,0xc0,0xe8,0x18,0x7,0x33,0xc4,0x6c,0x30,0x2e,0xc6,0xc3,0x42,0xb1,0x38,0x2c,0x9,0x93,0x63,0xcb,0xb1,0x22,0xac,0xc,0xab,0xc6,0x1a,0xb0,0x56,0xac,0x3,0xbb,0x89,0xf5,0x63,0xcf,0xb1,0x77,0x4,0x12,0x81,0x45,0xc0,0x9,0x36,0x4,0x77,0x42,0x20,0x61,0x1e,0x41,0x48,0x58,0x4c,0x58,0x4e,0xd8,0x48,0xa8,0x20,0x1c,0x24,0x34,0x11,0xda,0x9,0x37,0x9,0x3,0x84,0x51,0xc2,0x27,0x22,0x93,0xa8,0x4b,0xb4,0x26,0xba,0x11,0xf9,0xc4,0x18,0x62,0x32,0x31,0x87,0x58,0x48,0x2c,0x23,0xd6,0x12,0x8f,0x13,0x2f,0x10,0x7b,0x88,0x43,0xc4,0x37,0x24,0x12,0x89,0x43,0x32,0x27,0xb9,0x90,0x2,0x49,0xb1,0xa4,0x54,0xd2,0x12,0xd2,0x46,0xd2,0x6e,0x52,0x23,0xe9,0x2c,0xa9,0x9b,0x34,0x48,0x1a,0x23,0x93,0xc9,0xda,0x64,0x6b,0xb2,0x7,0x39,0x94,0x2c,0x20,0x2b,0xc8,0x85,0xe4,0x9d,0xe4,0xc3,0xe4,0x33,0xe4,0x1b,0xe4,0x21,0xf2,0x5b,0xa,0x9d,0x62,0x40,0x71,0xa4,0xf8,0x53,0xe2,0x28,0x52,0xca,0x6a,0x4a,0x19,0xe5,0x10,0xe5,0x34,0xe5,0x6,0x65,0x98,0x32,0x41,0x55,0xa3,0x9a,0x52,0xdd,0xa8,0xa1,0x54,0x11,0x35,0x8f,0x5a,0x42,0xad,0xa1,0xb6,0x52,0xaf,0x51,0x87,0xa8,0x13,0x34,0x75,0x9a,0x39,0xcd,0x83,0x16,0x49,0x4b,0xa5,0xad,0xa2,0x95,0xd3,0x1a,0x68,0x17,0x68,0xf7,0x69,0xaf,0xe8,0x74,0xba,0x11,0xdd,0x95,0x1e,0x4e,0x97,0xd0,0x57,0xd2,0xcb,0xe9,0x47,0xe8,0x97,0xe8,0x3,0xf4,0x77,0xc,0xd,0x86,0x15,0x83,0xc7,0x88,0x67,0x28,0x19,0x9b,0x18,0x7,0x18,0x67,0x19,0x77,0x18,0xaf,0x98,0x4c,0xa6,0x19,0xd3,0x8b,0x19,0xc7,0x54,0x30,0x37,0x31,0xeb,0x98,0xe7,0x99,0xf,0x99,0x6f,0x55,0x58,0x2a,0xb6,0x2a,0x7c,0x15,0x91,0xca,0xa,0x95,0x4a,0x95,0x26,0x95,0x1b,0x2a,0x2f,0x54,0xa9,0xaa,0xa6,0xaa,0xde,0xaa,0xb,0x55,0xf3,0x55,0xcb,0x54,0x8f,0xa9,0x5e,0x53,0x7d,0xae,0x46,0x55,0x33,0x53,0xe3,0xa9,0x9,0xd4,0x96,0xab,0x55,0xaa,0x9d,0x50,0xeb,0x53,0x1b,0x53,0x67,0xa9,0x3b,0xa8,0x87,0xaa,0x67,0xa8,0x6f,0x54,0x3f,0xa4,0x7e,0x59,0xfd,0x89,0x6,0x59,0xc3,0x4c,0xc3,0x4f,0x43,0xa4,0x51,0xa0,0xb1,0x5f,0xe3,0xbc,0xc6,0x20,0xb,0x63,0x19,0xb3,0x78,0x2c,0x21,0x6b,0xd,0xab,0x86,0x75,0x81,0x35,0xc4,0x26,0xb1,0xcd,0xd9,0x7c,0x76,0x2a,0xbb,0x98,0xfd,0x1d,0xbb,0x8b,0x3d,0xaa,0xa9,0xa1,0x39,0x43,0x33,0x4a,0x33,0x57,0xb3,0x52,0xf3,0x94,0x66,0x3f,0x7,0xe3,0x98,0x71,0xf8,0x9c,0x74,0x4e,0x9,0xe7,0x28,0xa7,0x97,0xf3,0x7e,0x8a,0xde,0x14,0xef,0x29,0xe2,0x29,0x1b,0xa6,0x34,0x4c,0xb9,0x31,0x65,0x5c,0x6b,0xaa,0x96,0x97,0x96,0x58,0xab,0x48,0xab,0x51,0xab,0x47,0xeb,0xbd,0x36,0xae,0xed,0xa7,0x9d,0xa6,0xbd,0x45,0xbb,0x59,0xfb,0x81,0xe,0x41,0xc7,0x4a,0x27,0x5c,0x27,0x47,0x67,0x8f,0xce,0x5,0x9d,0xe7,0x53,0xd9,0x53,0xdd,0xa7,0xa,0xa7,0x16,0x4d,0x3d,0x3a,0xf5,0xae,0x2e,0xaa,0x6b,0xa5,0x1b,0xa1,0xbb,0x44,0x77,0xbf,0x6e,0xa7,0xee,0x98,0x9e,0xbe,0x5e,0x80,0x9e,0x4c,0x6f,0xa7,0xde,0x79,0xbd,0xe7,0xfa,0x1c,0x7d,0x2f,0xfd,0x54,0xfd,0x6d,0xfa,0xa7,0xf5,0x47,0xc,0x58,0x6,0xb3,0xc,0x24,0x6,0xdb,0xc,0xce,0x18,0x3c,0xc5,0x35,0x71,0x6f,0x3c,0x1d,0x2f,0xc7,0xdb,0xf1,0x51,0x43,0x5d,0xc3,0x40,0x43,0xa5,0x61,0x95,0x61,0x97,0xe1,0x84,0x91,0xb9,0xd1,0x3c,0xa3,0xd5,0x46,0x8d,0x46,0xf,0x8c,0x69,0xc6,0x5c,0xe3,0x24,0xe3,0x6d,0xc6,0x6d,0xc6,0xa3,0x26,0x6,0x26,0x21,0x26,0x4b,0x4d,0xea,0x4d,0xee,0x9a,0x52,0x4d,0xb9,0xa6,0x29,0xa6,0x3b,0x4c,0x3b,0x4c,0xc7,0xcd,0xcc,0xcd,0xa2,0xcd,0xd6,0x99,0x35,0x9b,0x3d,0x31,0xd7,0x32,0xe7,0x9b,0xe7,0x9b,0xd7,0x9b,0xdf,0xb7,0x60,0x5a,0x78,0x5a,0x2c,0xb6,0xa8,0xb6,0xb8,0x65,0x49,0xb2,0xe4,0x5a,0xa6,0x59,0xee,0xb6,0xbc,0x6e,0x85,0x5a,0x39,0x59,0xa5,0x58,0x55,0x5a,0x5d,0xb3,0x46,0xad,0x9d,0xad,0x25,0xd6,0xbb,0xad,0xbb,0xa7,0x11,0xa7,0xb9,0x4e,0x93,0x4e,0xab,0x9e,0xd6,0x67,0xc3,0xb0,0xf1,0xb6,0xc9,0xb6,0xa9,0xb7,0x19,0xb0,0xe5,0xd8,0x6,0xdb,0xae,0xb6,0x6d,0xb6,0x7d,0x61,0x67,0x62,0x17,0x67,0xb7,0xc5,0xae,0xc3,0xee,0x93,0xbd,0x93,0x7d,0xba,0x7d,0x8d,0xfd,0x3d,0x7,0xd,0x87,0xd9,0xe,0xab,0x1d,0x5a,0x1d,0x7e,0x73,0xb4,0x72,0x14,0x3a,0x56,0x3a,0xde,0x9a,0xce,0x9c,0xee,0x3f,0x7d,0xc5,0xf4,0x96,0xe9,0x2f,0x67,0x58,0xcf,0x10,0xcf,0xd8,0x33,0xe3,0xb6,0x13,0xcb,0x29,0xc4,0x69,0x9d,0x53,0x9b,0xd3,0x47,0x67,0x17,0x67,0xb9,0x73,0x83,0xf3,0x88,0x8b,0x89,0x4b,0x82,0xcb,0x2e,0x97,0x3e,0x2e,0x9b,0x1b,0xc6,0xdd,0xc8,0xbd,0xe4,0x4a,0x74,0xf5,0x71,0x5d,0xe1,0x7a,0xd2,0xf5,0x9d,0x9b,0xb3,0x9b,0xc2,0xed,0xa8,0xdb,0xaf,0xee,0x36,0xee,0x69,0xee,0x87,0xdc,0x9f,0xcc,0x34,0x9f,0x29,0x9e,0x59,0x33,0x73,0xd0,0xc3,0xc8,0x43,0xe0,0x51,0xe5,0xd1,0x3f,0xb,0x9f,0x95,0x30,0x6b,0xdf,0xac,0x7e,0x4f,0x43,0x4f,0x81,0x67,0xb5,0xe7,0x23,0x2f,0x63,0x2f,0x91,0x57,0xad,0xd7,0xb0,0xb7,0xa5,0x77,0xaa,0xf7,0x61,0xef,0x17,0x3e,0xf6,0x3e,0x72,0x9f,0xe3,0x3e,0xe3,0x3c,0x37,0xde,0x32,0xde,0x59,0x5f,0xcc,0x37,0xc0,0xb7,0xc8,0xb7,0xcb,0x4f,0xc3,0x6f,0x9e,0x5f,0x85,0xdf,0x43,0x7f,0x23,0xff,0x64,0xff,0x7a,0xff,0xd1,0x0,0xa7,0x80,0x25,0x1,0x67,0x3,0x89,0x81,0x41,0x81,0x5b,0x2,0xfb,0xf8,0x7a,0x7c,0x21,0xbf,0x8e,0x3f,0x3a,0xdb,0x65,0xf6,0xb2,0xd9,0xed,0x41,0x8c,0xa0,0xb9,0x41,0x15,0x41,0x8f,0x82,0xad,0x82,0xe5,0xc1,0xad,0x21,0x68,0xc8,0xec,0x90,0xad,0x21,0xf7,0xe7,0x98,0xce,0x91,0xce,0x69,0xe,0x85,0x50,0x7e,0xe8,0xd6,0xd0,0x7,0x61,0xe6,0x61,0x8b,0xc3,0x7e,0xc,0x27,0x85,0x87,0x85,0x57,0x86,0x3f,0x8e,0x70,0x88,0x58,0x1a,0xd1,0x31,0x97,0x35,0x77,0xd1,0xdc,0x43,0x73,0xdf,0x44,0xfa,0x44,0x96,0x44,0xde,0x9b,0x67,0x31,0x4f,0x39,0xaf,0x2d,0x4a,0x35,0x2a,0x3e,0xaa,0x2e,0x6a,0x3c,0xda,0x37,0xba,0x34,0xba,0x3f,0xc6,0x2e,0x66,0x59,0xcc,0xd5,0x58,0x9d,0x58,0x49,0x6c,0x4b,0x1c,0x39,0x2e,0x2a,0xae,0x36,0x6e,0x6c,0xbe,0xdf,0xfc,0xed,0xf3,0x87,0xe2,0x9d,0xe2,0xb,0xe3,0x7b,0x17,0x98,0x2f,0xc8,0x5d,0x70,0x79,0xa1,0xce,0xc2,0xf4,0x85,0xa7,0x16,0xa9,0x2e,0x12,0x2c,0x3a,0x96,0x40,0x4c,0x88,0x4e,0x38,0x94,0xf0,0x41,0x10,0x2a,0xa8,0x16,0x8c,0x25,0xf2,0x13,0x77,0x25,0x8e,0xa,0x79,0xc2,0x1d,0xc2,0x67,0x22,0x2f,0xd1,0x36,0xd1,0x88,0xd8,0x43,0x5c,0x2a,0x1e,0x4e,0xf2,0x48,0x2a,0x4d,0x7a,0x92,0xec,0x91,0xbc,0x35,0x79,0x24,0xc5,0x33,0xa5,0x2c,0xe5,0xb9,0x84,0x27,0xa9,0x90,0xbc,0x4c,0xd,0x4c,0xdd,0x9b,0x3a,0x9e,0x16,0x9a,0x76,0x20,0x6d,0x32,0x3d,0x3a,0xbd,0x31,0x83,0x92,0x91,0x90,0x71,0x42,0xaa,0x21,0x4d,0x93,0xb6,0x67,0xea,0x67,0xe6,0x66,0x76,0xcb,0xac,0x65,0x85,0xb2,0xfe,0xc5,0x6e,0x8b,0xb7,0x2f,0x1e,0x95,0x7,0xc9,0x6b,0xb3,0x90,0xac,0x5,0x59,0x2d,0xa,0xb6,0x42,0xa6,0xe8,0x54,0x5a,0x28,0xd7,0x2a,0x7,0xb2,0x67,0x65,0x57,0x66,0xbf,0xcd,0x89,0xca,0x39,0x96,0xab,0x9e,0x2b,0xcd,0xed,0xcc,0xb3,0xca,0xdb,0x90,0x37,0x9c,0xef,0x9f,0xff,0xed,0x12,0xc2,0x12,0xe1,0x92,0xb6,0xa5,0x86,0x4b,0x57,0x2d,0x1d,0x58,0xe6,0xbd,0xac,0x6a,0x39,0xb2,0x3c,0x71,0x79,0xdb,0xa,0xe3,0x15,0x5,0x2b,0x86,0x56,0x6,0xac,0x3c,0xb8,0x8a,0xb6,0x2a,0x6d,0xd5,0x4f,0xab,0xed,0x57,0x97,0xae,0x7e,0xbd,0x26,0x7a,0x4d,0x6b,0x81,0x5e,0xc1,0xca,0x82,0xc1,0xb5,0x1,0x6b,0xeb,0xb,0x55,0xa,0xe5,0x85,0x7d,0xeb,0xdc,0xd7,0xed,0x5d,0x4f,0x58,0x2f,0x59,0xdf,0xb5,0x61,0xfa,0x86,0x9d,0x1b,0x3e,0x15,0x89,0x8a,0xae,0x14,0xdb,0x17,0x97,0x15,0x7f,0xd8,0x28,0xdc,0x78,0xe5,0x1b,0x87,0x6f,0xca,0xbf,0x99,0xdc,0x94,0xb4,0xa9,0xab,0xc4,0xb9,0x64,0xcf,0x66,0xd2,0x66,0xe9,0xe6,0xde,0x2d,0x9e,0x5b,0xe,0x96,0xaa,0x97,0xe6,0x97,0xe,0x6e,0xd,0xd9,0xda,0xb4,0xd,0xdf,0x56,0xb4,0xed,0xf5,0xf6,0x45,0xdb,0x2f,0x97,0xcd,0x28,0xdb,0xbb,0x83,0xb6,0x43,0xb9,0xa3,0xbf,0x3c,0xb8,0xbc,0x65,0xa7,0xc9,0xce,0xcd,0x3b,0x3f,0x54,0xa4,0x54,0xf4,0x54,0xfa,0x54,0x36,0xee,0xd2,0xdd,0xb5,0x61,0xd7,0xf8,0x6e,0xd1,0xee,0x1b,0x7b,0xbc,0xf6,0x34,0xec,0xd5,0xdb,0x5b,0xbc,0xf7,0xfd,0x3e,0xc9,0xbe,0xdb,0x55,0x1,0x55,0x4d,0xd5,0x66,0xd5,0x65,0xfb,0x49,0xfb,0xb3,0xf7,0x3f,0xae,0x89,0xaa,0xe9,0xf8,0x96,0xfb,0x6d,0x5d,0xad,0x4e,0x6d,0x71,0xed,0xc7,0x3,0xd2,0x3,0xfd,0x7,0x23,0xe,0xb6,0xd7,0xb9,0xd4,0xd5,0x1d,0xd2,0x3d,0x54,0x52,0x8f,0xd6,0x2b,0xeb,0x47,0xe,0xc7,0x1f,0xbe,0xfe,0x9d,0xef,0x77,0x2d,0xd,0x36,0xd,0x55,0x8d,0x9c,0xc6,0xe2,0x23,0x70,0x44,0x79,0xe4,0xe9,0xf7,0x9,0xdf,0xf7,0x1e,0xd,0x3a,0xda,0x76,0x8c,0x7b,0xac,0xe1,0x7,0xd3,0x1f,0x76,0x1d,0x67,0x1d,0x2f,0x6a,0x42,0x9a,0xf2,0x9a,0x46,0x9b,0x53,0x9a,0xfb,0x5b,0x62,0x5b,0xba,0x4f,0xcc,0x3e,0xd1,0xd6,0xea,0xde,0x7a,0xfc,0x47,0xdb,0x1f,0xf,0x9c,0x34,0x3c,0x59,0x79,0x4a,0xf3,0x54,0xc9,0x69,0xda,0xe9,0x82,0xd3,0x93,0x67,0xf2,0xcf,0x8c,0x9d,0x95,0x9d,0x7d,0x7e,0x2e,0xf9,0xdc,0x60,0xdb,0xa2,0xb6,0x7b,0xe7,0x63,0xce,0xdf,0x6a,0xf,0x6f,0xef,0xba,0x10,0x74,0xe1,0xd2,0x45,0xff,0x8b,0xe7,0x3b,0xbc,0x3b,0xce,0x5c,0xf2,0xb8,0x74,0xf2,0xb2,0xdb,0xe5,0x13,0x57,0xb8,0x57,0x9a,0xaf,0x3a,0x5f,0x6d,0xea,0x74,0xea,0x3c,0xfe,0x93,0xd3,0x4f,0xc7,0xbb,0x9c,0xbb,0x9a,0xae,0xb9,0x5c,0x6b,0xb9,0xee,0x7a,0xbd,0xb5,0x7b,0x66,0xf7,0xe9,0x1b,0x9e,0x37,0xce,0xdd,0xf4,0xbd,0x79,0xf1,0x16,0xff,0xd6,0xd5,0x9e,0x39,0x3d,0xdd,0xbd,0xf3,0x7a,0x6f,0xf7,0xc5,0xf7,0xf5,0xdf,0x16,0xdd,0x7e,0x72,0x27,0xfd,0xce,0xcb,0xbb,0xd9,0x77,0x27,0xee,0xad,0xbc,0x4f,0xbc,0x5f,0xf4,0x40,0xed,0x41,0xd9,0x43,0xdd,0x87,0xd5,0x3f,0x5b,0xfe,0xdc,0xd8,0xef,0xdc,0x7f,0x6a,0xc0,0x77,0xa0,0xf3,0xd1,0xdc,0x47,0xf7,0x6,0x85,0x83,0xcf,0xfe,0x91,0xf5,0x8f,0xf,0x43,0x5,0x8f,0x99,0x8f,0xcb,0x86,0xd,0x86,0xeb,0x9e,0x38,0x3e,0x39,0x39,0xe2,0x3f,0x72,0xfd,0xe9,0xfc,0xa7,0x43,0xcf,0x64,0xcf,0x26,0x9e,0x17,0xfe,0xa2,0xfe,0xcb,0xae,0x17,0x16,0x2f,0x7e,0xf8,0xd5,0xeb,0xd7,0xce,0xd1,0x98,0xd1,0xa1,0x97,0xf2,0x97,0x93,0xbf,0x6d,0x7c,0xa5,0xfd,0xea,0xc0,0xeb,0x19,0xaf,0xdb,0xc6,0xc2,0xc6,0x1e,0xbe,0xc9,0x78,0x33,0x31,0x5e,0xf4,0x56,0xfb,0xed,0xc1,0x77,0xdc,0x77,0x1d,0xef,0xa3,0xdf,0xf,0x4f,0xe4,0x7c,0x20,0x7f,0x28,0xff,0x68,0xf9,0xb1,0xf5,0x53,0xd0,0xa7,0xfb,0x93,0x19,0x93,0x93,0xff,0x4,0x3,0x98,0xf3,0xfc,0xef,0x35,0x94,0x82,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xa,0x14,0x3,0x19,0x2c,0x11,0xe9,0xa7,0x91,0x0,0x0,0x0,0x95,0x49,0x44,0x41,0x54,0x28,0xcf,0xbd,0xd2,0x21,0xe,0xc2,0x50,0x10,0x45,0xd1,0xf3,0x9b,0xa,0x30,0x8,0xb6,0x1,0x9,0xbe,0x28,0x54,0xd7,0x0,0x16,0x96,0xc0,0x32,0xba,0x2,0xca,0x46,0x50,0x55,0xe0,0x49,0x60,0x1b,0x4d,0x50,0x80,0x29,0x98,0x8f,0x20,0xd0,0x50,0xc5,0x75,0x33,0x79,0x77,0x32,0xe2,0x85,0xbc,0xa8,0x6,0x18,0x61,0x82,0x21,0x82,0x77,0x1e,0xa8,0x71,0xc4,0x39,0xc5,0x18,0x19,0xb6,0xb8,0xf9,0x4e,0xf,0x2b,0x84,0x34,0x5e,0x2e,0x77,0xeb,0xd9,0x45,0x3b,0xb7,0xbc,0xa8,0x4a,0x2c,0x92,0xf8,0xc6,0xd5,0x6f,0xae,0x18,0x26,0x71,0x48,0x3a,0x8,0x49,0xd7,0xe0,0xa7,0xf5,0x17,0xa1,0xe9,0x90,0x6d,0x5e,0x42,0x8d,0x7e,0x7,0xa1,0x87,0x3a,0xe4,0x45,0x95,0x61,0x8a,0xd,0xee,0x2d,0xe1,0x3e,0x96,0x38,0xa4,0x38,0xc5,0xe5,0xfc,0x47,0x35,0xf6,0x38,0x3f,0x1,0xce,0x6b,0x1e,0x5e,0xd6,0x59,0x76,0xbd,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -99,6 +104,11 @@ static const unsigned char font_normal_png[]={
};
+static const unsigned char frame_focus_png[]={
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0xc,0x0,0x0,0x0,0xc,0x8,0x6,0x0,0x0,0x0,0x56,0x75,0x5c,0xe7,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xa,0x14,0x3,0x18,0x33,0x85,0xfa,0x9b,0x25,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0x95,0x49,0x44,0x41,0x54,0x28,0xcf,0xbd,0xd2,0x31,0xe,0xc1,0x70,0x18,0x86,0xf1,0xdf,0xbf,0xe9,0xa0,0x8b,0xc1,0x35,0x48,0xec,0xb5,0xd8,0xb8,0x2,0x2b,0x37,0x70,0xd,0x2e,0xa0,0xe,0x62,0xab,0x85,0x5d,0xc2,0x35,0x9a,0x98,0xb0,0x60,0xa9,0x41,0x68,0xda,0xc9,0xb3,0x7d,0x5f,0xde,0xe7,0xcb,0x37,0xbc,0x61,0xb4,0xcc,0xdb,0xe8,0xa2,0x8f,0xe,0x82,0x4f,0x9e,0x28,0x70,0xc4,0x39,0x46,0xf,0x29,0x36,0xb8,0xf9,0x4d,0xb,0x73,0x84,0xb8,0xbc,0x9c,0x6d,0x17,0xc3,0x8b,0x6a,0x6e,0xe3,0xd5,0x2e,0xc3,0x34,0x2a,0xdf,0xb8,0xaa,0xe7,0x8a,0x4e,0x54,0xe,0x51,0x3,0x21,0x6a,0x1a,0xfc,0xb6,0xfe,0x22,0x3c,0x1a,0x64,0x1f,0x6f,0xa1,0x40,0xd2,0x40,0x68,0xa1,0x8,0xa3,0x65,0x9e,0x62,0x80,0x35,0xee,0x15,0xe1,0x4,0x33,0x1c,0x62,0x9c,0xca,0xe5,0xa4,0xa6,0x1a,0x7b,0x9c,0x5f,0xce,0xb,0x1e,0x5e,0x4b,0xa1,0xce,0xa0,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+};
+
+
static const unsigned char full_panel_bg_png[]={
0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x20,0x8,0x6,0x0,0x0,0x0,0x73,0x7a,0x7a,0xf4,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x14,0xe,0x1c,0x26,0x8,0x6f,0x80,0xec,0x0,0x0,0x0,0xfb,0x49,0x44,0x41,0x54,0x58,0x85,0xed,0x97,0x31,0x6a,0x3,0x31,0x10,0x45,0x9f,0x66,0xa4,0xda,0x39,0x81,0xd,0x6e,0x16,0xdf,0xff,0x1a,0x29,0x72,0x2,0x83,0xdd,0x6,0x43,0x5c,0x6b,0x35,0x4a,0xe1,0x68,0x77,0x45,0x16,0xd2,0xac,0x36,0x8d,0x6,0x84,0x40,0xcd,0x7b,0xcc,0xa8,0x98,0xef,0x86,0xe1,0x92,0xf9,0xa9,0x9c,0x73,0x75,0x6f,0x5d,0xce,0xb9,0xea,0x6,0xf0,0x5,0xb8,0x76,0xb6,0x86,0xaf,0x9d,0x4a,0x20,0xa5,0x44,0x4a,0xa9,0xa9,0x80,0xaa,0xa2,0xaa,0xd3,0x9b,0x5f,0xc2,0xdf,0xe,0x7,0x4e,0xc7,0x33,0x66,0x23,0x66,0xb6,0xa9,0x80,0x88,0x20,0xe2,0xb9,0xdd,0xaf,0x7c,0x3d,0x9f,0xa8,0x2a,0x39,0xe7,0xb9,0x3,0x29,0x25,0x4e,0xc7,0x33,0x8f,0xc7,0x27,0x31,0xc6,0x4d,0xe1,0xa5,0x42,0x8,0x2f,0xc6,0xc7,0x3b,0x22,0xf2,0x12,0x5b,0xce,0xdc,0x6c,0x6c,0x6,0x7,0x88,0x31,0x62,0x36,0x56,0xff,0x4c,0x80,0x85,0xc0,0xb6,0x6d,0x5f,0x2b,0x33,0xab,0xfe,0x98,0x34,0x27,0xfe,0x51,0x5d,0xa0,0xb,0x74,0x81,0x2e,0xd0,0x5,0xba,0x40,0x17,0xe8,0x2,0x5d,0x40,0x60,0xde,0xd9,0xcb,0xa6,0xda,0x14,0x28,0x32,0xf1,0x0,0x64,0x99,0x52,0x44,0x3c,0x21,0x84,0x66,0xf0,0x10,0x2,0x22,0xfe,0x77,0x32,0x2a,0x89,0xe5,0x76,0xbf,0xee,0x12,0x4c,0x54,0x75,0xce,0x89,0xc3,0x70,0xc9,0x65,0x55,0xde,0x33,0x9a,0x95,0x91,0x4f,0x1d,0x0,0x50,0x55,0x44,0x64,0xb7,0x70,0xa,0xcc,0x2,0xce,0xb9,0x7f,0x89,0xe7,0xdf,0x5f,0xef,0xae,0xd,0xbd,0x13,0x36,0x6e,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -114,6 +124,21 @@ static const unsigned char graph_node_close_png[]={
};
+static const unsigned char graph_node_default_png[]={
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0x8,0x1a,0x17,0x2e,0xd,0x4c,0xb7,0x38,0x4,0x0,0x0,0x0,0x1d,0x69,0x54,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x0,0x0,0x0,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x64,0x2e,0x65,0x7,0x0,0x0,0x0,0x85,0x49,0x44,0x41,0x54,0x38,0xcb,0xed,0x93,0x31,0xa,0x83,0x40,0x14,0x44,0xdf,0xba,0xa5,0x20,0x41,0x30,0x20,0x4,0xab,0x40,0x20,0x7,0xc9,0x69,0xec,0x72,0x4e,0x9b,0xa0,0x1e,0xc1,0x2a,0x42,0x10,0x82,0xbb,0xc5,0x77,0x6d,0x4c,0x11,0x48,0xe3,0xb7,0x49,0xe1,0x6b,0x6,0xa6,0x78,0xd5,0x8c,0x1,0x6e,0x80,0xe1,0x9b,0xb0,0xe4,0xaf,0xde,0x3,0x4f,0xa0,0x3,0x6,0x93,0x67,0xa7,0xc0,0xa,0x44,0x64,0x72,0x7e,0x6c,0x87,0xf7,0xab,0x4,0x1e,0x68,0x38,0x17,0x97,0x90,0xc4,0x87,0xa,0xb8,0xa2,0xe5,0x98,0xe6,0x1,0xb8,0x47,0x5a,0x81,0xb5,0x16,0xa0,0x56,0xb,0x3e,0xec,0x82,0x3f,0x10,0x4c,0x6a,0x81,0x88,0x78,0xc0,0x45,0xda,0x29,0x3b,0x3f,0x36,0x40,0xbf,0xf9,0x4c,0x66,0xeb,0x9d,0x67,0x5c,0x46,0x37,0x51,0xb6,0x55,0x6d,0xc2,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+};
+
+
+static const unsigned char graph_node_default_focus_png[]={
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0x8,0x1b,0x1,0x9,0x1c,0x5c,0xd5,0x12,0x34,0x0,0x0,0x0,0x1d,0x69,0x54,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x0,0x0,0x0,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x64,0x2e,0x65,0x7,0x0,0x0,0x0,0xfc,0x49,0x44,0x41,0x54,0x38,0xcb,0xbd,0x93,0x41,0x4a,0x4,0x41,0xc,0x45,0x7f,0xca,0x6a,0x14,0x42,0x2f,0xc4,0x85,0x7,0xf0,0x3c,0xde,0xa2,0xbc,0x41,0xd7,0xa2,0xa1,0x60,0xea,0x60,0xae,0x5c,0xea,0x19,0xdc,0xd7,0x42,0x97,0xe5,0xc,0x12,0xeb,0xbb,0x69,0xa5,0x84,0xe9,0x41,0x1d,0xf1,0x43,0x8,0x84,0xe4,0x2d,0x92,0x1f,0xc1,0x22,0x92,0x2,0xc0,0x2d,0x81,0x2e,0x7f,0xa8,0x75,0xb9,0x89,0x8,0x1,0x40,0x48,0x5e,0x76,0xcd,0xad,0x6b,0x74,0x7b,0xea,0x6,0xe0,0x75,0x9,0x13,0x11,0xca,0x34,0x4d,0xc4,0x37,0x35,0xc,0xc3,0xf3,0x38,0x8e,0xb7,0xf3,0x3c,0xdf,0x0,0xd8,0x1,0x30,0x90,0x4,0x49,0xe4,0x9c,0x11,0x42,0x40,0x29,0x65,0x15,0x50,0x4a,0xb9,0x8,0x21,0x30,0xe7,0x7c,0x47,0x52,0x49,0x9e,0x7c,0x2,0x62,0x8c,0x30,0x33,0xa8,0xea,0x2a,0x40,0x55,0xaf,0xcc,0x4c,0x62,0x8c,0x5b,0x92,0xe7,0x24,0x7,0xd7,0x2d,0x11,0xde,0x7b,0xd4,0x5a,0x57,0x1,0xb5,0xd6,0x47,0xef,0x3d,0x49,0x9e,0x1,0xf0,0x0,0x9c,0xc3,0xef,0xe5,0xf6,0x9d,0xea,0x5f,0x1,0x38,0x16,0xd0,0xfe,0x16,0x20,0x22,0x7,0x3d,0xd0,0x7b,0x41,0x44,0xb6,0x8b,0x2b,0x9b,0xeb,0x6e,0x8c,0x94,0x12,0xcc,0x6c,0x75,0xd8,0xcc,0xc6,0x94,0xd2,0x93,0xaa,0xde,0x2f,0x76,0x6e,0x3f,0xb2,0xb2,0x88,0xec,0x54,0xf5,0x61,0xb3,0xd9,0x5c,0x3,0x78,0x1,0x60,0xc7,0x3c,0x53,0x13,0x91,0x37,0xe9,0x9d,0xd8,0xe9,0xf4,0xc0,0xe2,0xbe,0xbc,0xf3,0x3b,0x49,0xa0,0x89,0xbf,0x71,0xc6,0xcd,0x1c,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+};
+
+
+static const unsigned char graph_node_selected_png[]={
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x40,0x8,0x6,0x0,0x0,0x0,0x13,0x7d,0xf7,0x96,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0x7,0x12,0x1,0xc,0x6,0x23,0x98,0xc7,0x50,0x0,0x0,0x0,0x1d,0x69,0x54,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x0,0x0,0x0,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x64,0x2e,0x65,0x7,0x0,0x0,0x2,0x46,0x49,0x44,0x41,0x54,0x58,0xc3,0xed,0x97,0xcd,0x6a,0x13,0x51,0x14,0xc7,0x7f,0xe7,0xce,0x34,0x49,0xd,0xa6,0xb1,0x2a,0xe2,0x7,0x74,0xa1,0x6e,0x4,0x85,0xe2,0x3,0xb8,0x72,0x21,0xba,0x16,0x5c,0xb9,0x16,0x4,0x7d,0x84,0x3e,0x82,0x82,0xe0,0xda,0x95,0x2f,0x60,0x71,0xe1,0xca,0x7,0xd0,0x82,0xa5,0x6e,0xd4,0x45,0xc1,0x8f,0x4a,0x6c,0x9a,0x46,0x62,0x66,0xa6,0x73,0xef,0x71,0xe1,0x4c,0x92,0x99,0x4c,0x93,0x36,0xdd,0xc9,0xfc,0x37,0x77,0x3e,0xee,0xfd,0xdd,0x73,0xfe,0xf7,0xc,0xcc,0x11,0x86,0x12,0xc0,0x0,0x5e,0x32,0xa,0x59,0x29,0xe0,0x0,0x9b,0x8c,0xca,0xc8,0x24,0x3,0x1c,0x3,0x16,0x81,0xd3,0x40,0x3,0x98,0xcb,0x1,0xf6,0x80,0x2e,0xd0,0x2,0xda,0xc0,0x1f,0xc0,0xa5,0xbb,0xd6,0x81,0x4b,0xb,0xc7,0x9b,0xf,0x6a,0xd5,0xda,0xad,0x4a,0xa5,0x7a,0x81,0x2,0x45,0x51,0xf8,0x35,0x8,0x83,0xd7,0xbb,0xbf,0x3b,0xcf,0x81,0xcf,0x40,0x4f,0x92,0x9d,0x96,0x16,0x9b,0x27,0x9f,0x5c,0x5c,0xba,0x7c,0xfb,0xfe,0xcb,0x3b,0x34,0x2b,0x27,0x8a,0xd6,0xd3,0x89,0x76,0x78,0x71,0xef,0x15,0x5f,0x36,0x3f,0xad,0xb6,0x3b,0xdb,0x8f,0x81,0x4d,0x1,0x6a,0xc0,0xf2,0xd9,0x33,0xe7,0xdf,0xac,0xbc,0x7d,0x54,0xdf,0x73,0x11,0x81,0xed,0x17,0x2,0x6a,0xde,0x3c,0x73,0xa6,0xc2,0xca,0x8d,0xa7,0xbd,0x1f,0x3f,0xbf,0xdd,0x4,0xd6,0xfc,0xc4,0x87,0xba,0xef,0xf9,0xf5,0x6e,0xb4,0xc3,0x24,0xf5,0xe3,0x1e,0x7d,0x7a,0xf8,0x9e,0x5f,0x4f,0xd2,0x96,0x14,0xe0,0x1,0x58,0xb5,0x39,0xdb,0x1d,0x82,0x19,0x5c,0xe7,0xe4,0xa5,0x0,0x4d,0x8f,0x44,0x71,0xa8,0x2a,0x22,0x92,0x81,0x4c,0x92,0x3f,0x7a,0xe3,0xd4,0xe2,0x54,0x41,0xc1,0x13,0xf,0xc5,0xe1,0x54,0x31,0x22,0x8,0xa6,0x10,0x96,0x1,0x58,0x1d,0x4e,0x88,0x35,0x1e,0x79,0x9e,0xd6,0xd0,0x94,0x8,0x54,0xb3,0x93,0x1c,0x8a,0x41,0x6,0x63,0xfa,0x6c,0x5f,0x40,0xe4,0xa2,0xcc,0x4b,0x23,0x32,0xd8,0x37,0x4e,0x52,0x99,0x1c,0x41,0x2e,0x4c,0x9b,0xdd,0x6c,0xec,0xbe,0x20,0x5,0xe5,0xb0,0xca,0x99,0x68,0x93,0x48,0x14,0x41,0x30,0x22,0x3,0x63,0x5,0x41,0x51,0x3c,0x31,0x93,0x8f,0x31,0xf3,0xed,0x6a,0xf6,0x5b,0xfe,0xe7,0x85,0x9b,0x0,0x98,0x52,0x34,0x7,0x2a,0xa4,0xb4,0x74,0x8b,0x4c,0x2d,0x2a,0xa6,0xb1,0x42,0x32,0x8c,0x1b,0x39,0x3c,0x7b,0x37,0xbd,0x90,0xec,0x51,0x52,0x88,0x5d,0x3c,0x36,0x21,0xd,0x39,0x4d,0x4d,0x72,0xc5,0x94,0x1,0xac,0xde,0x7d,0x3f,0xbb,0x89,0xf1,0x9e,0x65,0xf9,0xea,0xf5,0x3,0x2d,0x5a,0x5b,0x7f,0x57,0x1c,0xc1,0x6e,0xb7,0x73,0xe8,0x8,0xc,0x47,0x54,0x9,0x28,0x1,0x25,0xa0,0x4,0x94,0x80,0x12,0x50,0x2,0xfe,0x4b,0x80,0x14,0xf4,0x88,0x87,0x8e,0xc0,0xcd,0xb0,0xd6,0xa5,0x0,0x7,0x4,0xd6,0xda,0xb0,0xe0,0x27,0x6d,0x7c,0x55,0xc,0xd6,0xda,0x10,0x8,0x0,0x67,0x92,0x56,0x76,0x3b,0x8,0xfb,0x1b,0xad,0xf6,0x16,0x93,0x20,0x2e,0x86,0x56,0x7b,0x8b,0x20,0xec,0x6f,0x0,0xdb,0x80,0x4d,0x3b,0xd7,0x5,0xe0,0x5a,0xa3,0xde,0x7c,0x56,0xab,0xce,0x5f,0xf1,0x3c,0xaf,0xd0,0x5c,0x6b,0xad,0xb,0xc2,0xfe,0xc7,0x6e,0xaf,0xf3,0x10,0xf8,0x0,0xec,0xca,0x48,0xb,0xd7,0x0,0xce,0x1,0xa7,0x80,0xea,0x3e,0xcd,0x77,0x8,0xfc,0x2,0xbe,0x27,0x7d,0xb4,0x95,0x9c,0xa1,0x7e,0xda,0xf,0xee,0x93,0x85,0x26,0x29,0xc7,0x33,0x1a,0x3f,0xae,0xbf,0xf0,0x27,0xf6,0x42,0xf6,0xf5,0xfd,0xae,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+};
+
+
static const unsigned char graph_port_png[]={
0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0xa,0x0,0x0,0x0,0xa,0x8,0x6,0x0,0x0,0x0,0x8d,0x32,0xcf,0xbd,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x0,0x0,0x0,0x0,0x0,0xf9,0x43,0xbb,0x7f,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0xc,0x14,0x17,0x20,0x3,0xeb,0x8f,0x3a,0xdb,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x1,0x65,0x49,0x44,0x41,0x54,0x18,0xd3,0x4d,0xd0,0x4f,0x6b,0xda,0x70,0x1c,0x7,0xe0,0xcf,0x37,0x7f,0x7e,0x49,0x66,0xd2,0x64,0x61,0x5,0x61,0x76,0x47,0xf1,0xa4,0x2d,0xdb,0x75,0x5,0x11,0x84,0xb0,0x5e,0xeb,0xd9,0xeb,0xf4,0x6d,0xec,0x2d,0xf8,0x26,0xb6,0x77,0xe0,0x45,0xba,0xa3,0x6c,0xa0,0x3b,0xad,0x39,0xb6,0x36,0x8,0x1b,0x4b,0x32,0xd2,0xc6,0x6c,0x9a,0x4f,0x4f,0x85,0x3e,0x2f,0xe1,0x11,0x0,0x20,0x29,0xd3,0xe9,0xd4,0xda,0x6e,0xb7,0x23,0xdf,0xf7,0xbb,0x0,0x90,0xe7,0xf9,0x8f,0x66,0xb3,0xf9,0x79,0x36,0x9b,0x55,0x22,0x42,0x83,0xa4,0x44,0x51,0xf4,0xea,0xe2,0xe2,0xc3,0xf7,0xf1,0x78,0xdc,0xa,0x82,0x40,0x8,0x20,0xcf,0x32,0x2e,0x97,0xcb,0x4f,0x51,0x14,0xbd,0x25,0xf9,0x5b,0x26,0x93,0x89,0xdd,0xe9,0x74,0xe2,0xf7,0xe7,0xe7,0x27,0x59,0xfa,0x87,0x65,0xb9,0x13,0x0,0xb0,0x1d,0x9b,0xe1,0xcb,0x50,0xbe,0x5e,0x5d,0xdd,0xfe,0xbc,0xbe,0x6e,0x6b,0x49,0x92,0x8c,0x4e,0x7b,0xa7,0xad,0xbf,0x79,0x4e,0xd3,0x54,0x12,0x86,0x21,0xc2,0x30,0x84,0x32,0x95,0xe4,0x79,0xc6,0xde,0xd9,0x59,0x2b,0x49,0xee,0x46,0x86,0xeb,0xba,0x5d,0xfb,0x85,0x23,0x87,0xfd,0x1e,0xb6,0xed,0x40,0xd7,0x35,0x0,0x40,0x7d,0x38,0xa0,0xdc,0xed,0x44,0x37,0x74,0xb8,0xae,0xd7,0x35,0x48,0x62,0xff,0xff,0x1f,0xfc,0x20,0x80,0xae,0xe9,0x78,0x42,0x0,0xca,0xb2,0x90,0x65,0x19,0x58,0xd7,0xd0,0x8a,0xa2,0x58,0xa7,0x69,0x56,0x6b,0xa2,0x51,0x29,0x5,0xcb,0x52,0xb0,0x94,0x5,0x4b,0x29,0x88,0x8,0xd3,0x34,0xad,0x8b,0xfb,0x62,0xad,0xf,0x6,0x83,0xb8,0xaa,0xaa,0xb1,0xe7,0x79,0xbe,0x77,0x74,0x44,0xb7,0xe1,0x89,0x69,0x1a,0x28,0xcb,0x92,0x9b,0xcd,0x46,0x56,0xab,0xd5,0x86,0xe4,0x47,0x21,0x29,0xc3,0xe1,0xf0,0xb8,0xdf,0xef,0x7f,0x6b,0xb7,0xdb,0xaf,0x1b,0x8d,0x86,0x46,0x10,0xf,0xf7,0xf,0x75,0x1c,0xc7,0x77,0x8b,0xc5,0xe2,0xdd,0x7c,0x3e,0xff,0x25,0xcf,0xc3,0x6f,0x6e,0x6f,0x2e,0x1d,0xdb,0xe9,0x9,0x80,0xb2,0x2a,0xd7,0x27,0xad,0x37,0x5f,0x9e,0xc2,0x1f,0x1,0x3a,0xe6,0xa5,0x7b,0xef,0xf2,0xf3,0xcd,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -125,17 +150,17 @@ static const unsigned char hseparator_png[]={
static const unsigned char hslider_bg_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xdd,0x0,0xdd,0x0,0xdd,0xf5,0x15,0x8,0x9d,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x14,0xf,0xc,0x8,0x9f,0xb9,0xf5,0x45,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0x4d,0x49,0x44,0x41,0x54,0x38,0x8d,0x63,0x60,0x18,0x5,0x14,0x3,0x46,0x18,0x43,0x42,0x42,0x62,0x1a,0x3,0x3,0x43,0x26,0x91,0xfa,0xa6,0xbf,0x78,0xf1,0x22,0xb,0xdd,0x80,0xff,0xec,0xec,0x9c,0x44,0xe9,0xfe,0xf9,0xf3,0x3b,0xc3,0x8b,0x17,0x2f,0x18,0x19,0x18,0x18,0x18,0x98,0x88,0x76,0x2b,0xe,0x30,0xf0,0x6,0xb0,0x20,0xb1,0xa7,0xff,0xfc,0xf9,0x9d,0xe8,0x40,0xa4,0xd4,0xe2,0x51,0x80,0x4,0x0,0x2b,0x51,0x10,0x8d,0x9f,0x1f,0x30,0xd7,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xb,0xd,0x16,0x2c,0x16,0x7f,0x48,0xec,0xab,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x1,0x47,0x49,0x44,0x41,0x54,0x38,0xcb,0xc5,0x92,0x31,0x8e,0x52,0x61,0x14,0x85,0xbf,0xff,0x5e,0x22,0xfc,0xbc,0x79,0x3a,0xcd,0xd3,0x4,0x42,0x62,0x61,0x78,0x15,0x95,0xcb,0x98,0xb8,0x0,0x13,0x66,0x1,0x66,0xda,0xd9,0x89,0xb1,0xb6,0x30,0xc1,0x5,0x18,0x97,0xe1,0x2,0x4,0xb,0xd,0x19,0xa,0x5f,0xcc,0x20,0x4f,0x78,0x23,0x70,0xff,0xdf,0x2,0xd0,0x40,0x43,0x22,0xc5,0x9c,0xe4,0x54,0xe7,0x7c,0xb7,0xb9,0x7,0xee,0x5b,0xe,0xe0,0xc5,0xc5,0xcb,0xff,0x82,0x3f,0x7c,0x7c,0x8f,0xdb,0xc2,0x35,0x20,0x3,0x72,0xa0,0x3,0x78,0x40,0xe,0xfa,0x1,0xa8,0x80,0x31,0xf0,0x19,0x28,0x80,0x75,0x6d,0xb,0x3f,0x2b,0xcb,0x9f,0x57,0xdf,0x8b,0x9b,0xcb,0x45,0x35,0x3f,0xb,0x21,0xaa,0x73,0xfb,0x74,0x8c,0x20,0xe2,0xac,0xe9,0x93,0x5f,0x8f,0xb3,0xf6,0xbb,0x34,0x7d,0xf4,0x6,0xf8,0xa2,0x79,0xb7,0xf7,0x64,0x56,0x4e,0xaf,0xbf,0x7e,0x1b,0xbd,0x5a,0xaf,0xd7,0x5e,0x44,0x45,0x55,0x10,0xd1,0x3d,0xab,0xa,0xce,0x89,0x2c,0x57,0xcb,0xc6,0xed,0xf4,0xc7,0x73,0xef,0x13,0xa9,0xd7,0x1b,0x9f,0x4,0xc8,0x8b,0x62,0xd2,0x77,0xce,0xa9,0xaa,0xa2,0xba,0x83,0xe4,0xc0,0x9b,0x4c,0x55,0x71,0xce,0x69,0x51,0x4c,0xfa,0x40,0x5e,0x3,0x3a,0x8b,0x6a,0x9e,0xee,0xa0,0x63,0x12,0x11,0x62,0x8c,0x2c,0xaa,0x79,0xa,0x74,0xe4,0xd4,0x37,0xa,0x30,0x6e,0xfa,0xa4,0xc,0x21,0x10,0x42,0x38,0xa,0xec,0x7a,0x4d,0x9f,0x94,0xc0,0x58,0x80,0x61,0x96,0xb5,0x6,0x31,0x46,0x33,0x33,0xcc,0x8c,0x10,0xec,0x6f,0xf1,0x9f,0x37,0x99,0x99,0x11,0x63,0xb4,0x2c,0x6b,0xd,0x80,0xa1,0xe6,0xdd,0x5e,0x55,0xaf,0x37,0x46,0xde,0x27,0xba,0x5a,0xde,0x75,0x97,0xab,0xdf,0xf,0xcc,0x82,0x8b,0x71,0xff,0x80,0x59,0x0,0x62,0x68,0xfa,0x64,0xd6,0x6e,0x3d,0x7d,0xfb,0x30,0x3d,0x7f,0xd,0x8c,0x4f,0x1e,0xd2,0xc9,0x53,0xbe,0x7f,0xfd,0x1,0xde,0x4b,0xa1,0x14,0xaf,0xc,0xa2,0x3a,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char hslider_grabber_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x92,0x0,0x92,0x0,0x99,0x25,0xc1,0x88,0x71,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x12,0x0,0x2,0x21,0x6d,0xbf,0x58,0x46,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x1,0x4b,0x49,0x44,0x41,0x54,0x38,0x8d,0xa5,0x93,0x31,0x6b,0xc2,0x40,0x14,0xc7,0xff,0x77,0xbd,0x34,0x26,0x97,0x5a,0x2c,0x41,0xa,0x9d,0x6b,0x8,0x86,0x2e,0xe,0xfd,0x4,0x1d,0xb2,0xf8,0x29,0x3a,0x15,0xec,0x87,0xa9,0x63,0xfb,0x3d,0x9c,0x3b,0x76,0xd0,0x82,0x8,0xe1,0x14,0xdc,0x82,0x74,0xc8,0x50,0xc4,0xdc,0x5d,0x32,0xd8,0xe5,0x22,0xa1,0x60,0x95,0xfa,0x1f,0x1f,0xef,0xf7,0xe3,0xdd,0xe3,0x1d,0x70,0x62,0xc8,0xef,0x42,0x10,0x4,0x37,0x0,0x6,0x0,0x62,0x0,0x1d,0x53,0x9e,0x3,0x18,0x1,0x18,0xa,0x21,0xd2,0xbd,0x82,0x20,0x8,0x1e,0x1,0xbc,0x84,0x61,0xe4,0xb8,0x2e,0x87,0x65,0x9d,0x3,0x0,0xca,0xb2,0x40,0x9e,0x6f,0x90,0x24,0x33,0x9,0xe0,0x59,0x8,0xf1,0x56,0x31,0x67,0x75,0xb8,0xd5,0xba,0x7a,0xed,0x76,0xef,0x2c,0xcf,0x6b,0x82,0x31,0x6,0x42,0x8,0x8,0x21,0x60,0x8c,0xc1,0x71,0x5c,0xb4,0xdb,0xd7,0x96,0x52,0xb2,0xcf,0x39,0x4f,0xb3,0x2c,0x9b,0xec,0x26,0x30,0x63,0x2f,0x7a,0xbd,0x7b,0xc7,0xb6,0x1b,0x7f,0xbe,0x59,0x6b,0x85,0xf1,0xf8,0x43,0x2,0xb8,0x15,0x42,0xa4,0xd4,0xd4,0x7,0x61,0x18,0x1d,0x84,0x1,0xc0,0xb6,0x1b,0x8,0xc3,0xc8,0x31,0x7b,0x42,0x25,0x88,0x5d,0x97,0x1f,0x84,0xab,0x98,0xde,0xb8,0x2e,0xe8,0x54,0xb,0x3b,0x26,0xa6,0xb7,0x53,0x17,0xfc,0x3b,0x95,0x60,0x5e,0x96,0xc5,0xd1,0x90,0xe9,0x9d,0xd7,0x5,0xa3,0x3c,0xdf,0x1c,0x2d,0x30,0xbd,0xa3,0xba,0x60,0x98,0x24,0x33,0xa9,0xb5,0x3a,0x8,0x6b,0xad,0xaa,0x83,0x1a,0x2,0xe6,0x90,0xb2,0x2c,0x5b,0xfb,0xbe,0xff,0xa5,0x94,0xec,0x37,0x9b,0x97,0x60,0x8c,0xed,0x85,0x97,0xcb,0x5,0x94,0x92,0x4f,0x42,0x88,0xf7,0x9d,0xc0,0x48,0x26,0x9c,0xf3,0x74,0xb5,0x4a,0x1f,0x3c,0xef,0xc2,0xa2,0x94,0x82,0x52,0x8a,0xed,0x76,0x8b,0xa2,0xd0,0x58,0xaf,0xbf,0x31,0x9d,0x7e,0x4a,0x3,0xef,0x4e,0xf9,0xe4,0xcf,0x74,0x72,0x7e,0x0,0xd9,0x87,0x82,0x9b,0x21,0x12,0xa2,0x6e,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xb,0xd,0x15,0x1a,0x26,0xd2,0xcb,0xf3,0x2b,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x1,0xae,0x49,0x44,0x41,0x54,0x38,0xcb,0xa5,0x93,0x3f,0x8f,0x12,0x41,0x18,0xc6,0x7f,0x3b,0xbb,0xcb,0xc2,0x62,0xb2,0x85,0xc5,0xd1,0x10,0x8b,0xa5,0x93,0x5c,0x61,0xc9,0x77,0xb0,0xa2,0xb1,0xb1,0xdd,0xca,0x4f,0xe0,0xa7,0xb0,0x20,0x39,0x42,0x63,0x41,0x63,0x48,0xae,0x54,0x1a,0xb,0xa,0xb,0x8b,0x23,0x4,0xa3,0xd,0x39,0x42,0x22,0x24,0x86,0x9c,0xde,0xf1,0x3f,0xcc,0x32,0xbb,0x63,0xb3,0x87,0x66,0xef,0xc0,0x4b,0x7c,0xab,0xc9,0x33,0x33,0xbf,0xbc,0xef,0xf3,0xcc,0xc0,0x7f,0x96,0x71,0x8f,0x66,0x2,0x2e,0xe0,0x1,0xf9,0x44,0x5b,0x3,0x73,0x60,0x3,0x44,0xc7,0x0,0x26,0xf0,0x38,0x8,0x82,0x17,0xbe,0xef,0x57,0x3d,0xcf,0x3b,0x5,0x98,0xcf,0xe7,0x5f,0x86,0xc3,0xe1,0x79,0xa3,0xd1,0x78,0x7,0xfc,0xfa,0x1b,0x62,0xa6,0x0,0x8f,0x82,0x20,0x78,0x59,0x2e,0x97,0x5f,0x1b,0x86,0xf1,0x74,0xb5,0x5a,0x65,0xb7,0xdb,0x6d,0x36,0x93,0xc9,0x3c,0x29,0x14,0xa,0xcf,0x8a,0xc5,0xe2,0x4d,0xb7,0xdb,0xfd,0x6,0x84,0xb7,0x17,0x44,0xa,0xe0,0xf9,0xbe,0x5f,0x55,0x4a,0x9d,0x6c,0x36,0x1b,0x94,0x52,0x28,0xa5,0x48,0xd6,0x27,0xbe,0xef,0x57,0x93,0xd1,0x38,0x4,0xc8,0x7b,0x9e,0x77,0x2a,0xa5,0x44,0x6b,0xbd,0x17,0xb5,0xd6,0x48,0x29,0x49,0x46,0xca,0x1f,0x3,0x18,0x71,0x1c,0x1b,0x87,0x1c,0x8f,0xa2,0xc8,0x48,0xfb,0x96,0x6,0x84,0x52,0xca,0x2b,0xd3,0x34,0xef,0xc6,0x65,0x18,0x48,0x29,0xaf,0x1,0x75,0xc,0xb0,0x5e,0x2c,0x16,0x5f,0x6d,0xdb,0xbe,0x3,0xb0,0x6d,0x1b,0xad,0xf5,0x8f,0x24,0xca,0x83,0x80,0x65,0xbf,0xdf,0xff,0xe0,0x38,0x4e,0x24,0xc4,0x9f,0x2d,0x21,0x4,0xb9,0x5c,0x4e,0x77,0x3a,0x9d,0xb7,0xc0,0xe2,0x18,0x40,0xf6,0x7a,0xbd,0xb,0x29,0xe5,0xc4,0xb2,0xac,0xbd,0x68,0x59,0x16,0xbb,0xdd,0xee,0x7b,0xbb,0xdd,0xfe,0xf4,0xaf,0xe,0xe2,0xd1,0x68,0x34,0x9e,0x4e,0xa7,0x1f,0x5d,0xd7,0x45,0x8,0x81,0x10,0x2,0xd7,0x75,0x19,0x8f,0xc7,0xef,0x95,0x52,0x57,0x40,0x7c,0xc,0xa0,0x81,0x79,0xad,0x56,0x7b,0x13,0x45,0xd1,0xa5,0xe3,0x38,0x38,0x8e,0x43,0x1c,0xc7,0xc3,0x7a,0xbd,0x7e,0x96,0x6e,0xff,0xbe,0x97,0x8,0x10,0x87,0x61,0xb8,0x9e,0xcd,0x66,0x97,0x95,0x4a,0xe5,0x79,0x36,0x9b,0x8d,0x5b,0xad,0xd6,0xab,0xc1,0x60,0x70,0x1,0x6c,0x1f,0x2,0x0,0x50,0x93,0xc9,0xe4,0x67,0xa9,0x54,0xba,0x59,0x2e,0x97,0x9f,0x9b,0xcd,0xe6,0x39,0x30,0x7b,0xe8,0x6f,0xdc,0x7b,0x7,0x38,0xc9,0x99,0x6d,0x3a,0xff,0xdb,0xfa,0xd,0x29,0xd4,0xb4,0x4b,0x76,0xdc,0xe7,0x79,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char hslider_grabber_hl_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x92,0x0,0x92,0x0,0x99,0x25,0xc1,0x88,0x71,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x12,0x0,0x2,0x1d,0x42,0xd0,0x24,0xc1,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x1,0x30,0x49,0x44,0x41,0x54,0x38,0x8d,0xa5,0x93,0xb1,0x6a,0xc2,0x50,0x14,0x86,0xbf,0x63,0xe2,0x90,0xd0,0x2e,0xc1,0xad,0x8b,0xad,0x60,0x9e,0xc0,0xbe,0x41,0x7,0x33,0x38,0x7,0x1d,0xba,0x74,0x2a,0xe8,0xc3,0xe8,0x68,0xc1,0x49,0xc8,0xec,0x10,0x9f,0xa1,0x8,0xee,0x71,0xcf,0x52,0x4d,0x70,0x73,0x8a,0xb7,0x83,0x37,0x72,0x11,0xb4,0xa1,0xfe,0xe3,0xe5,0x7c,0xdf,0xbd,0x1c,0xfe,0xb,0x77,0x46,0x2e,0xf,0x7c,0xdf,0x7f,0x2,0x86,0x40,0x17,0x68,0xeb,0xe3,0xd,0xb0,0x4,0x26,0x49,0x92,0xa4,0x57,0x5,0xbe,0xef,0x7f,0x0,0xe3,0x30,0x1c,0x38,0x9e,0xd7,0x40,0xa4,0x6,0x80,0x52,0x47,0xf2,0x7c,0x47,0x14,0xcd,0xf,0xc0,0x28,0x49,0x92,0xaf,0x92,0xb1,0x4c,0xb8,0xd9,0x7c,0x9e,0xf6,0xfb,0xef,0x75,0xd7,0x7d,0xd4,0xb0,0x0,0x82,0x48,0xd,0xd7,0x7d,0xa0,0xd3,0x79,0xad,0x6f,0xb7,0x3f,0x3d,0xdb,0xb6,0xd2,0x2c,0xcb,0xd6,0x0,0x35,0xe3,0xd9,0xe3,0x20,0xe8,0x21,0x62,0x71,0x2d,0x22,0x16,0x41,0xd0,0x3,0x18,0x6b,0xe6,0x24,0x0,0x86,0x61,0x38,0x70,0x6e,0xc1,0xa6,0x24,0xc,0x7,0x8e,0xde,0xd3,0x59,0xd0,0xf5,0xbc,0xc6,0x9f,0x70,0x19,0x3d,0xdb,0x35,0x5,0xed,0x72,0x61,0x55,0xa2,0x67,0xdb,0xa6,0xe0,0xdf,0x29,0x5,0x1b,0xa5,0x8e,0x95,0x21,0x3d,0xbb,0x31,0x5,0xcb,0x3c,0xdf,0x55,0x16,0xe8,0xd9,0xa5,0x29,0x98,0x44,0xd1,0xfc,0xa0,0x54,0x51,0xe1,0xf6,0xa2,0x2c,0xd4,0xe4,0x2c,0xd0,0xf5,0x1c,0xc5,0xf1,0x82,0x5b,0x12,0xa5,0xa,0xe2,0x78,0x1,0xa7,0x36,0xa6,0x60,0x34,0x31,0xcb,0xb2,0xb5,0x6d,0x5b,0xe9,0x6a,0xf5,0xfd,0xd6,0x6a,0xbd,0xd4,0x1d,0xc7,0x41,0x44,0x34,0x78,0x24,0xcf,0xb7,0xcc,0x66,0xd3,0xc3,0x7e,0xbf,0xff,0x34,0xab,0x7c,0xf7,0x67,0xba,0x3b,0xbf,0x4d,0x78,0x75,0x34,0x1f,0x21,0x5d,0xa6,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xb,0xd,0x15,0x17,0x2d,0xf0,0xb7,0x54,0xee,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x1,0xcb,0x49,0x44,0x41,0x54,0x38,0xcb,0xa5,0x93,0xcd,0x4a,0x1b,0x51,0x1c,0xc5,0xcf,0x9d,0x3b,0x33,0x4e,0x3a,0x43,0x7,0x9b,0x16,0x93,0x82,0x14,0x8b,0x50,0xa8,0x61,0x28,0xf5,0x1,0xba,0xb5,0xb,0x41,0xc8,0x46,0x4,0xdf,0xa0,0x4f,0x50,0x70,0x95,0x95,0xb8,0x77,0x5b,0x10,0x84,0x6e,0xa2,0xab,0x4a,0x17,0x42,0x5a,0x74,0xe1,0xc2,0x82,0xa8,0xb5,0x14,0x12,0xa,0x2a,0xda,0xd4,0xc4,0x4c,0x32,0x33,0x72,0xe7,0xeb,0x5e,0x37,0x93,0x5a,0x26,0x31,0x16,0x3c,0xcb,0xc3,0xbd,0x3f,0xce,0xff,0xb,0xb8,0xa7,0x48,0x1f,0x8f,0x2,0x78,0x0,0xc0,0x4,0xa0,0x27,0x9e,0x7,0xa0,0xd,0xe0,0xa,0x40,0x3c,0x8,0x40,0x1,0x64,0xa7,0x4a,0xa5,0xd9,0x5c,0xc1,0x2a,0x2a,0x46,0xde,0x2,0x80,0xd0,0x3d,0xdf,0xff,0x7d,0xb8,0x5f,0xfe,0xbc,0xb0,0xf0,0x11,0x40,0xf3,0x5f,0x8,0x4d,0x1,0x8c,0xa9,0x52,0x69,0x3e,0xff,0xea,0xcd,0x7b,0xb7,0x6d,0x4e,0xd8,0x67,0xbe,0xe6,0x36,0x23,0x8d,0x13,0xf3,0x59,0x76,0x6c,0xf4,0x75,0xee,0xe5,0xf3,0x56,0xb5,0x52,0xf9,0xe,0x20,0xe8,0x7e,0x90,0x52,0x0,0x33,0x57,0xb0,0x8a,0x4e,0x4b,0x1d,0x71,0x1b,0xc,0x21,0x8b,0x11,0xb2,0x18,0x6e,0x83,0xc1,0x69,0xa9,0x23,0xb9,0x82,0x55,0x4c,0x4a,0xc3,0x6d,0x0,0x5d,0x31,0xf2,0x16,0xeb,0x4,0x10,0x5c,0xfc,0x35,0x5,0x17,0x60,0x9d,0x0,0x49,0x49,0xfa,0x20,0x0,0xe1,0x11,0x27,0x42,0xf4,0x76,0x56,0x70,0x80,0x47,0x31,0x49,0xf7,0x2d,0xd,0x8,0x78,0xe4,0x5e,0xc8,0x8a,0xd4,0x3,0x90,0x64,0x82,0x38,0xf0,0x2e,0x1,0x44,0x83,0x0,0x5e,0xe0,0xd4,0xf,0x55,0x5d,0xee,0x1,0xa8,0x19,0x19,0x94,0x6,0xe7,0xc9,0x28,0x6f,0x5,0x38,0xbf,0xb6,0xb6,0x37,0x32,0xf,0x95,0x58,0xa2,0x37,0x49,0x25,0x4a,0xa0,0xf,0xab,0xe2,0x60,0xbd,0xfc,0x1,0x40,0x67,0x10,0xc0,0xaf,0x7d,0xfd,0xb2,0x2b,0x11,0xfb,0x54,0xd1,0x6e,0x52,0x28,0x9a,0xc,0x99,0x76,0x8e,0xbf,0xad,0xac,0x6c,0xdf,0x95,0x80,0xd7,0x8f,0x7e,0x9c,0x78,0xf5,0xda,0xa6,0xf1,0x78,0x8,0x12,0x25,0x90,0x28,0x81,0xf1,0x44,0x83,0x7d,0x72,0xf4,0x29,0xe,0xc3,0xb,0x0,0xfc,0xae,0x55,0x56,0x34,0xd3,0x7c,0x31,0xb7,0xba,0xb6,0x6e,0xff,0xc9,0x8c,0xb,0x1,0x3c,0x7a,0xea,0xd7,0x56,0x67,0x67,0x66,0x58,0xbb,0xfd,0x13,0x40,0x98,0x5e,0xdd,0xb4,0x78,0xe4,0xfb,0xde,0xd5,0x65,0xbd,0x5a,0x98,0x7e,0x3b,0x6d,0x64,0x15,0xbe,0xb3,0xbc,0xf4,0xee,0x6c,0x6f,0x6f,0x17,0x0,0xeb,0x77,0x38,0xfd,0x14,0x35,0xab,0xb5,0xc6,0xe8,0xe4,0x44,0x2b,0x70,0x1a,0x3b,0x95,0xc5,0xc5,0x32,0x0,0xfb,0x7f,0xaf,0xb1,0x2b,0x19,0xc0,0x50,0xf2,0x86,0xa5,0xe7,0xdf,0xd5,0x35,0xea,0x59,0xb2,0xa3,0x9f,0xba,0x1f,0x74,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -154,11 +179,21 @@ static const unsigned char hsplitter_png[]={
};
+static const unsigned char icon_add_png[]={
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x12,0x0,0x0,0xb,0x12,0x1,0xd2,0xdd,0x7e,0xfc,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0xec,0x49,0x44,0x41,0x54,0x38,0x8d,0xdd,0x92,0x41,0x4a,0xc4,0x30,0x18,0x85,0xbf,0x67,0x93,0xc,0xd9,0x28,0xb9,0x41,0xcf,0x21,0x7a,0x28,0xdd,0xcd,0x5,0x14,0x57,0x73,0x28,0xe7,0x20,0xbd,0x41,0x70,0x5c,0x14,0x93,0xe,0xbf,0xb,0xdb,0x61,0x5a,0x5a,0x70,0xab,0xf,0x2,0x21,0xfc,0xf9,0xf2,0xde,0x23,0xf0,0xe7,0xa5,0xb5,0xc3,0x9c,0xf3,0xae,0x94,0xf2,0xda,0xf7,0xfd,0x13,0x40,0x8c,0xf1,0x10,0x42,0xd8,0xa7,0x94,0xbe,0x96,0xb3,0x6e,0x3,0x6c,0x92,0x4e,0x40,0x1,0x90,0xf4,0x1,0xd8,0xda,0xe0,0xc,0x90,0x73,0xde,0x1,0x66,0x66,0xc1,0xcc,0x9a,0xb,0xcd,0xcc,0x99,0x59,0xc8,0x39,0x3,0xe8,0xda,0xc9,0xc,0x50,0x4a,0x79,0x91,0xf4,0x69,0x66,0xcd,0x30,0xc,0xf,0x40,0x3,0x30,0xee,0x91,0x74,0x36,0xb3,0x5b,0xe0,0x79,0xb5,0x83,0xae,0xeb,0x6c,0xb2,0x3d,0x5e,0x9e,0x5c,0x9c,0xc7,0x5,0x10,0xda,0xb6,0xbd,0xdc,0xbb,0xd9,0xe8,0xe0,0xd7,0x9a,0x45,0x88,0x31,0x1e,0x24,0x9d,0xa6,0x8,0xb5,0xd6,0x47,0x0,0xef,0xfd,0xbb,0x73,0xee,0x78,0x15,0x61,0x1d,0x10,0x42,0xd8,0x33,0x96,0x8,0x50,0x6b,0xbd,0x7,0x70,0xce,0x1d,0xbd,0xf7,0x6f,0x92,0xa,0x8b,0xd8,0x33,0xc0,0xd4,0x6e,0xce,0x19,0x49,0x53,0x66,0x24,0xd,0x92,0x4a,0x4a,0xa9,0xb0,0xd0,0xd6,0x3f,0xd0,0x68,0x35,0xf0,0x63,0xe9,0x6e,0xf9,0xf2,0x3f,0xd2,0x37,0xb9,0xed,0x67,0x29,0x9e,0xb,0x7f,0x1a,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+};
+
+
static const unsigned char icon_close_png[]={
0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x1,0x73,0x52,0x47,0x42,0x0,0xae,0xce,0x1c,0xe9,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xd9,0xb,0x17,0x6,0x11,0xd,0x6a,0x1e,0x9a,0x6f,0x0,0x0,0x0,0x5e,0x49,0x44,0x41,0x54,0x38,0xcb,0xd5,0x53,0xcb,0xe,0xc0,0x30,0x8,0x12,0xb2,0xff,0xff,0x65,0x77,0x5a,0xb3,0x36,0xf8,0x48,0xcc,0xe,0xf3,0xd4,0x3,0xa2,0x40,0x85,0x9b,0xdb,0xa4,0x68,0xc3,0x1a,0x13,0x5c,0xcf,0x3,0x86,0xa5,0xc5,0xcd,0xa1,0xc0,0xa,0x43,0xd5,0xf4,0x6,0x56,0x3,0x36,0x9,0x11,0x49,0xb6,0x1d,0x54,0xa,0x6a,0x83,0x48,0x1a,0xbb,0xc0,0xc8,0x97,0x6f,0x62,0xac,0x4c,0x4c,0x9,0x4e,0xc3,0xaa,0x74,0xd8,0x89,0x2a,0x23,0x61,0xf7,0x23,0x85,0x11,0xff,0xff,0x98,0x6e,0x7,0x20,0x33,0x1a,0x5b,0xf5,0xcc,0xfe,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
+static const unsigned char icon_color_pick_png[]={
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x1,0x73,0x52,0x47,0x42,0x0,0xae,0xce,0x1c,0xe9,0x0,0x0,0x0,0x4,0x67,0x41,0x4d,0x41,0x0,0x0,0xb1,0x8f,0xb,0xfc,0x61,0x5,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x11,0x0,0x0,0xb,0x11,0x1,0x7f,0x64,0x5f,0x91,0x0,0x0,0x0,0x18,0x74,0x45,0x58,0x74,0x53,0x6f,0x66,0x74,0x77,0x61,0x72,0x65,0x0,0x70,0x61,0x69,0x6e,0x74,0x2e,0x6e,0x65,0x74,0x20,0x34,0x2e,0x30,0x2e,0x36,0xfc,0x8c,0x63,0xdf,0x0,0x0,0x1,0xf7,0x49,0x44,0x41,0x54,0x38,0x4f,0x8d,0x90,0xbd,0x6b,0x53,0x51,0x18,0xc6,0xaf,0x26,0xed,0x62,0x70,0x71,0xd0,0xc1,0x2f,0x70,0xa9,0xda,0x4d,0xc7,0x8e,0xd6,0x42,0xc5,0x52,0xa5,0x42,0xa1,0xa4,0xb6,0x20,0x75,0x50,0xf4,0x52,0x41,0x1d,0x6a,0x87,0x96,0xfe,0x1,0x42,0xa1,0x20,0x52,0x71,0x56,0x50,0xf3,0xd5,0x94,0x24,0xed,0x50,0x5d,0xc4,0x41,0xa9,0x70,0xd3,0xc4,0xe7,0x9c,0xa0,0xc5,0xf,0x1c,0x2,0x6,0x29,0x4d,0xe2,0x7d,0x7d,0x4e,0x72,0xc,0xe9,0x7,0xb5,0xf,0xfc,0x48,0xee,0xcd,0xf3,0x7b,0xcf,0x7b,0xe2,0xfc,0x2f,0xc5,0x62,0x31,0x98,0xc8,0xfd,0x8,0x5c,0x8c,0xa1,0xa5,0x3f,0x81,0xe0,0x8d,0x14,0x4e,0xdc,0xcd,0x60,0x6a,0x64,0x1e,0x3,0x3d,0x31,0x84,0x6c,0x6d,0x6b,0x6,0xe6,0x10,0x1c,0x4a,0xe2,0xc0,0xf3,0x8f,0xab,0x7b,0x87,0x53,0x2a,0x40,0xf9,0x24,0xe5,0xa7,0xf7,0x17,0xf0,0xe7,0x5e,0x6,0x55,0x3e,0x7f,0xee,0x8c,0xe0,0xa0,0xad,0x3b,0x8e,0x88,0x34,0x30,0x19,0x4c,0x22,0x70,0x2b,0x85,0xa3,0x7d,0x71,0x1c,0xb9,0x1c,0x47,0x68,0x34,0x8d,0x35,0xca,0xe2,0xa6,0x21,0xe1,0x39,0xf8,0x5d,0x11,0xac,0x9f,0x8b,0xe0,0x71,0xad,0x6c,0xd2,0x2c,0x9b,0xf4,0xc6,0x70,0xfc,0xda,0x3c,0xd6,0x2e,0xc5,0xf0,0x75,0x38,0x89,0x99,0xb1,0x5,0xf8,0x77,0xd2,0xf0,0xaf,0xc4,0x51,0x3d,0x1f,0x41,0x99,0xb2,0x22,0xa7,0x6d,0x7d,0xeb,0x0,0x9e,0x70,0xa6,0x27,0x8a,0x32,0xd7,0x14,0x6e,0x20,0xdc,0xc0,0xe7,0xea,0x3e,0x4f,0x2f,0x71,0xc0,0x7,0xca,0x61,0xd2,0x62,0xeb,0xf5,0x1,0xcd,0x59,0xfe,0xa4,0xdd,0x47,0x6f,0x21,0xdd,0x51,0xf8,0x1c,0xe2,0xf3,0x2a,0xc2,0x3f,0xce,0x6c,0xf0,0x8e,0xc3,0x7,0x29,0xef,0xb3,0xd5,0x7a,0x9a,0x7,0x14,0xa,0x85,0x3e,0x52,0xc9,0x2b,0x5d,0x19,0x5d,0xc4,0x2c,0xcb,0x25,0xb3,0x9,0x87,0xc9,0x85,0x28,0xbe,0xf3,0xfb,0x31,0xbe,0xdb,0x63,0xeb,0xf5,0xfc,0xbb,0x2,0xc5,0xe,0x52,0x22,0x42,0x6e,0xba,0x8b,0xd8,0x3f,0xf5,0x46,0xe5,0x79,0xaa,0x50,0x32,0x54,0x49,0xe7,0xb6,0x3,0x28,0xb4,0x91,0xa2,0x95,0x27,0x49,0x90,0x3c,0xcb,0x42,0xcb,0xf8,0x92,0xfa,0x6d,0x65,0x9f,0xbc,0x22,0xad,0x56,0xad,0x87,0xc5,0x10,0xf1,0x88,0x91,0x9f,0x90,0x9a,0x6c,0x9f,0x7f,0x26,0x96,0xf5,0x59,0x4a,0x2e,0x79,0x49,0x4e,0x91,0x8d,0x1b,0xb0,0xf4,0x42,0xe7,0xb5,0x60,0x36,0xb7,0x8a,0xeb,0x5e,0xb8,0x49,0x36,0xd7,0xe9,0x30,0x1b,0x1a,0x89,0xb4,0x6e,0x27,0xf7,0xea,0xf7,0x4a,0x30,0xb1,0x52,0x46,0xd8,0x2b,0xe3,0x41,0xf6,0xcb,0x66,0x79,0x33,0x1b,0xc2,0x92,0xa7,0x1e,0xe6,0x4,0x57,0xbd,0x75,0xb8,0xd9,0x5f,0x5a,0xeb,0x1d,0x65,0x43,0x23,0x2c,0xb5,0xab,0xc,0x4,0x23,0x9e,0xe0,0xb6,0x57,0xd1,0x2b,0x35,0xf9,0xdb,0x4e,0xb2,0xa1,0x11,0x16,0xf,0x61,0x3a,0x57,0x55,0xaf,0x61,0x44,0x43,0x8a,0x1c,0xb6,0x3f,0xef,0x2e,0x14,0xda,0xc9,0x98,0xf9,0xb4,0xaf,0x76,0x19,0xc7,0xf9,0xb,0x8e,0xb3,0xf3,0x95,0xda,0x15,0xd3,0x79,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+};
+
+
static const unsigned char icon_folder_png[]={
0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0xf,0x14,0x33,0x39,0x1,0xd2,0x43,0x4c,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x1,0x36,0x49,0x44,0x41,0x54,0x38,0x8d,0xc5,0x92,0xcd,0x4a,0xc3,0x40,0x14,0x85,0xbf,0x7b,0x67,0x12,0x48,0x3,0x12,0x62,0x45,0xfa,0x30,0x7d,0x5,0x5d,0xfa,0x8,0xbe,0x88,0x3e,0x45,0x5f,0xc1,0x9d,0x4b,0x77,0x3e,0x81,0x2e,0xa4,0x15,0xa5,0x10,0xb2,0xc8,0xa2,0x9b,0x41,0x2c,0x62,0x4c,0x66,0x5c,0x34,0x8a,0x3f,0x95,0x26,0x2b,0xf,0xc,0xcc,0x9d,0x3b,0xe7,0xce,0x39,0x87,0x81,0xff,0x86,0x14,0x45,0x11,0xb6,0x35,0xe2,0x38,0xbe,0x9c,0x4c,0x26,0x47,0xce,0xb9,0x78,0x4b,0x3b,0x64,0x59,0xf6,0x6,0x20,0x65,0x59,0x56,0xde,0xfb,0x43,0x40,0x80,0x0,0x34,0xdd,0xa5,0x28,0x49,0x92,0x73,0x11,0x79,0xf9,0x49,0x16,0x91,0xd5,0x78,0x3c,0x9e,0x1,0x58,0x63,0x4c,0xe9,0xbd,0x3f,0x0,0xc,0x20,0xa3,0xd1,0xe8,0x2c,0x84,0x10,0x1,0x88,0xc8,0x6b,0x37,0xf8,0x9b,0xea,0x10,0xc2,0xa7,0x2a,0xa9,0xaa,0xea,0xa2,0xae,0xeb,0x63,0x40,0xd3,0x34,0x3d,0x5d,0xaf,0xd7,0xb3,0xde,0xfe,0x45,0x9e,0xd4,0x18,0x53,0x0,0x1e,0xd0,0x10,0x42,0xda,0x97,0xc,0x78,0x55,0xad,0x54,0x44,0x96,0x80,0xfd,0xf0,0x37,0x64,0x80,0x31,0x66,0xa1,0xaa,0xfa,0x8,0x68,0x77,0xb8,0x7,0xd4,0x83,0x6,0x88,0xc8,0x3,0x80,0x31,0x66,0xde,0x34,0xcd,0x94,0x4d,0x98,0x7d,0x10,0xab,0xea,0xad,0xe6,0x79,0xbe,0x4,0x88,0xa2,0xe8,0xba,0xae,0xeb,0xe9,0x17,0x35,0x3b,0xa1,0xaa,0x37,0xf6,0x4b,0x71,0x7,0x24,0x7d,0xc9,0x0,0x79,0x9e,0xcf,0x2d,0x80,0x88,0x3c,0xf,0x79,0x99,0x4d,0xd8,0x1e,0xba,0xf4,0x55,0x75,0xd5,0xed,0xdb,0x6e,0xed,0x42,0x63,0xad,0xbd,0x7,0xb0,0xce,0x39,0x6d,0xdb,0xf6,0x44,0x55,0x17,0x49,0x92,0xec,0xff,0xf1,0xfb,0x7e,0x29,0x50,0xd5,0x2b,0xe7,0x9c,0x8,0x80,0x73,0xce,0x74,0x92,0xa2,0x1,0x36,0xda,0x2c,0xcb,0xda,0x77,0xe3,0x5,0x64,0xf1,0xba,0x53,0xe9,0x44,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -169,18 +204,23 @@ static const unsigned char icon_play_png[]={
};
+static const unsigned char icon_reload_png[]={
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x12,0x0,0x0,0xb,0x12,0x1,0xd2,0xdd,0x7e,0xfc,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x1,0x94,0x49,0x44,0x41,0x54,0x38,0x8d,0x85,0xd3,0xbd,0x6a,0x55,0x41,0x14,0xc5,0xf1,0xdf,0xb9,0x1f,0x91,0x20,0x5a,0x89,0xd8,0x8,0x4b,0xd0,0x42,0x1f,0xc0,0x42,0x4,0x4b,0xb,0x1b,0x9b,0xbc,0x80,0x58,0x45,0xc5,0x56,0x51,0x50,0x6b,0x21,0x9d,0xa5,0x6f,0x20,0x88,0x20,0xa8,0xad,0xa8,0xa0,0x2f,0x60,0x21,0xe8,0x4e,0x63,0xa9,0x85,0x22,0x31,0x37,0x37,0xb1,0xb8,0x73,0xc2,0xf1,0x23,0x38,0xd5,0x9c,0x61,0xaf,0x3d,0x7b,0xfe,0x6b,0x9d,0xce,0x1e,0xab,0xaa,0xc6,0x18,0xa1,0xc3,0xe,0xb6,0x92,0xec,0xfc,0x59,0x37,0xda,0x43,0x8,0xc7,0x70,0x9,0x37,0xb0,0xd2,0xd7,0x56,0x55,0x57,0x55,0xbb,0xf5,0xdd,0x1f,0xe2,0xae,0x9,0x9f,0xe2,0x24,0xb6,0x6,0x97,0x8c,0xf0,0x32,0xc9,0xb9,0xaa,0x9a,0x62,0x96,0x64,0xd1,0xa0,0x75,0x1c,0xe3,0x2,0x9e,0x34,0xc1,0x2b,0x3c,0xc6,0x3a,0x8e,0xe3,0x76,0xab,0x59,0xc6,0x41,0xfc,0xc0,0xbc,0x6f,0x30,0xc6,0x61,0x7c,0x6e,0xe2,0x53,0x49,0xde,0x57,0xd5,0x12,0xb6,0xd1,0x25,0x99,0x55,0xd5,0x3,0xac,0x36,0x1e,0xd3,0x5d,0x6,0x49,0xe6,0x78,0xd4,0xc4,0xe7,0xf1,0xa9,0x9d,0x6f,0x26,0xd9,0xc2,0xac,0x7d,0x5f,0xc1,0x73,0xcc,0xab,0xea,0x7a,0x55,0x4d,0x7b,0x30,0x37,0x71,0x6,0xdf,0x70,0x34,0xc9,0xc6,0x90,0x4d,0x92,0x21,0xa3,0x15,0xec,0xc3,0x6a,0x92,0x59,0x57,0x55,0x13,0x4c,0xdb,0x9b,0x36,0x92,0x2c,0x57,0xd5,0xb8,0x4d,0xf5,0xcf,0x55,0x55,0x33,0x4c,0x92,0x74,0xa3,0x46,0x7a,0x8e,0x13,0x38,0xd8,0x1a,0xfe,0x53,0x3c,0xb0,0xef,0x4b,0xbf,0x19,0xb5,0xf1,0x36,0xf1,0x31,0xc9,0xcc,0x22,0x34,0xff,0x5b,0x87,0xf1,0x95,0xbf,0x73,0xb0,0x86,0x5b,0xf8,0x89,0xed,0xfe,0xed,0x83,0xdb,0x97,0x70,0x19,0x6b,0x78,0x88,0xab,0xbd,0x8d,0x13,0x9c,0xc6,0x6b,0xac,0x27,0x49,0xb3,0x70,0x96,0x64,0xa7,0xc1,0x9b,0xe0,0x90,0x66,0x75,0x92,0xae,0xaa,0xba,0xde,0xc6,0xad,0x24,0x6f,0xf0,0xc,0x47,0xaa,0xea,0x3b,0x2e,0xe,0xb2,0xbf,0xdf,0x22,0xd2,0x7d,0x4e,0xce,0xb7,0x34,0xee,0xec,0x26,0x71,0x60,0xd5,0x5d,0xdc,0xb1,0x0,0xd9,0xff,0x17,0x2c,0xb2,0x30,0xc5,0x59,0xbc,0xee,0xeb,0xfb,0x9,0x86,0x84,0xef,0xe1,0x0,0xee,0xe3,0x2d,0x3e,0xe0,0x5,0xae,0x25,0xe9,0xf0,0x6e,0xc8,0xe6,0x37,0x88,0x3,0x58,0x1d,0xc6,0x2d,0x85,0xfd,0xf9,0x92,0x85,0x5b,0x86,0xd,0x7e,0x1,0x82,0x4c,0xaa,0x69,0x77,0x3c,0x4b,0x15,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+};
+
+
static const unsigned char icon_stop_png[]={
0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0xf,0x14,0x33,0x24,0x62,0xd4,0x2f,0x95,0x0,0x0,0x0,0x39,0x49,0x44,0x41,0x54,0x38,0x8d,0x63,0x60,0xa0,0x6,0xf8,0xf0,0xe1,0x3,0x33,0xb9,0x7a,0x18,0x61,0x2,0xf,0x1f,0x3e,0xfc,0x4f,0x8a,0x1,0xf2,0xf2,0xf2,0x8c,0xc,0xc,0xc,0xc,0x4c,0xa4,0xda,0x8c,0xe,0x46,0xd,0x18,0x35,0x60,0x70,0x18,0xc0,0xc0,0xc0,0x40,0x59,0x66,0xa2,0x18,0x0,0x0,0x2a,0xc7,0xf,0x64,0xd5,0xe,0x11,0x85,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char line_edit_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x27,0x0,0x27,0x0,0x27,0x12,0xaa,0xad,0x65,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x11,0x16,0x1e,0x2f,0x66,0x6e,0x58,0x30,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0xba,0x49,0x44,0x41,0x54,0x38,0x8d,0xed,0xd3,0x3b,0x4e,0x3,0x41,0x10,0x84,0xe1,0x6f,0x4c,0x4b,0x1e,0x56,0x1b,0x10,0xef,0x8,0x4e,0xc0,0xe3,0x6c,0x9c,0x84,0xb3,0x19,0x3b,0x26,0x41,0xeb,0x98,0x0,0xd9,0x63,0x69,0x90,0x9,0xd8,0x78,0x17,0xc9,0x9,0x1,0x15,0xb6,0xba,0xfe,0xee,0xa0,0x2a,0xa1,0xc3,0xd,0x7a,0x5c,0x21,0x99,0xd7,0x19,0x5f,0xf8,0xc4,0x47,0x4c,0xe6,0x47,0xdc,0x22,0xff,0x12,0x50,0xf1,0x8e,0xd7,0x98,0x2e,0xdf,0x3d,0xdc,0x3f,0xbd,0x94,0xa1,0x74,0x11,0x31,0xeb,0x6e,0xad,0x19,0xf7,0xe3,0x61,0xbb,0xdb,0x3c,0xe3,0x2d,0x10,0x58,0x97,0xa1,0x74,0xb5,0x56,0xb5,0xd6,0x59,0x40,0xce,0x59,0x19,0x4a,0xb7,0xdd,0x6d,0xd6,0x88,0xd5,0x34,0x4f,0x11,0xb1,0x68,0x86,0x5a,0xab,0xe9,0xcb,0x4,0xab,0xf9,0xf5,0x65,0xfd,0x3,0xfe,0x12,0xe0,0xdc,0x5a,0x93,0x73,0x5e,0x34,0xe4,0x9c,0xb5,0xd6,0xf8,0x89,0xb4,0x40,0xc3,0x69,0xdc,0x8f,0xc7,0x32,0x94,0xeb,0xbe,0xef,0x67,0x1,0x53,0x94,0x8f,0x38,0xa1,0x25,0xc,0x2e,0x28,0x53,0x72,0x61,0x9d,0xbf,0x1,0x2c,0xf1,0x42,0x3f,0xf1,0x88,0x6f,0x8a,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0xa,0x0,0x0,0x0,0xa,0x8,0x6,0x0,0x0,0x0,0x8d,0x32,0xcf,0xbd,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xa,0x14,0x3,0x1d,0x2f,0xec,0x8c,0x33,0x2f,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0x9d,0x49,0x44,0x41,0x54,0x18,0xd3,0xb5,0x90,0x31,0xe,0xc2,0x40,0x10,0x3,0xed,0xbb,0xd5,0x25,0xa1,0xa1,0x3,0x9,0x41,0xc1,0x33,0x78,0x15,0x5f,0xc8,0x93,0x41,0x14,0x49,0x2e,0xbb,0xb7,0x29,0x2,0x52,0x20,0x14,0x34,0x58,0x72,0x63,0x4f,0x61,0x99,0xfb,0xdd,0xe1,0x9a,0x52,0xd5,0xc6,0x10,0x6b,0x92,0x58,0xca,0xdd,0x61,0xc5,0xfa,0x9c,0x87,0x96,0xa7,0xe3,0xf9,0x56,0xa5,0x7a,0x2b,0x22,0x0,0xde,0x41,0xc0,0xa1,0xaa,0x18,0x72,0x7f,0x97,0x18,0x62,0x23,0x22,0x88,0x22,0xe0,0x7,0xe8,0x70,0x0,0x80,0x6a,0x6c,0x2,0xc9,0x2,0x70,0x5,0x1,0x78,0x66,0x4,0xc9,0x12,0xf0,0xa3,0xfe,0x0,0xba,0x7b,0x98,0x67,0xfb,0xaa,0x9c,0x33,0x87,0xbb,0x7,0xb1,0x62,0x9d,0xaa,0xa6,0xd7,0xfc,0x6f,0xf7,0x58,0xb1,0x3e,0x36,0xf5,0xa6,0x3,0x70,0x29,0x66,0x30,0x53,0x5d,0x5a,0x75,0xd4,0x51,0xc7,0x47,0xce,0x43,0x3b,0x1,0xc,0x2e,0x55,0x5d,0x5f,0x72,0xb6,0x33,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char line_edit_disabled_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x27,0x0,0x27,0x0,0x27,0x12,0xaa,0xad,0x65,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x11,0x16,0x1e,0x28,0xf8,0xa,0xcd,0x93,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0xb8,0x49,0x44,0x41,0x54,0x38,0x8d,0xed,0x93,0x31,0xa,0xc2,0x50,0x10,0x44,0xdf,0x97,0x8d,0x59,0x24,0x8d,0xa4,0xcb,0x7,0x4f,0xa0,0x78,0x22,0x4f,0xe7,0x89,0x42,0x72,0x2,0x21,0x29,0x4,0x5b,0x59,0x75,0x31,0x16,0x89,0xa5,0x49,0xc0,0xc6,0xc2,0xe9,0x67,0x66,0x67,0x99,0x9,0x40,0xa,0xac,0x0,0x5,0x16,0xcc,0xc3,0x13,0x30,0xe0,0x2a,0x3,0x79,0x3,0xe4,0x40,0x2,0x84,0x9,0x72,0x7,0x3c,0x80,0xb,0x70,0x92,0xc1,0x39,0xdf,0x6d,0xf7,0x87,0x58,0xc4,0xa5,0x88,0x8c,0xa,0xb8,0x7b,0xd7,0xb4,0xcd,0xbd,0xaa,0xcb,0x23,0x70,0x96,0xe1,0xec,0x24,0x16,0x31,0x35,0x33,0xcc,0x6c,0xd4,0x5e,0x55,0x43,0x2c,0x62,0x5a,0xd5,0x65,0x2,0x2c,0xde,0x99,0x83,0x88,0x4c,0x92,0x1,0xcc,0xc,0x11,0x81,0x21,0xea,0xdc,0xa7,0x7d,0xc4,0x5f,0xe0,0x97,0x4,0x3a,0x77,0x47,0x55,0x27,0x9,0xaa,0x8a,0xbb,0x43,0x5f,0x69,0x84,0x7e,0x18,0x8f,0xa6,0x6d,0x6e,0xb1,0x88,0xcb,0x2c,0xcb,0x66,0x55,0x99,0x7e,0xf,0xcf,0x0,0xac,0xf9,0x62,0x4c,0x81,0x2f,0xe7,0xfc,0x2,0xba,0x32,0x42,0x24,0xee,0x6e,0x22,0x60,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0xa,0x0,0x0,0x0,0xa,0x8,0x6,0x0,0x0,0x0,0x8d,0x32,0xcf,0xbd,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xa,0x14,0x3,0x1e,0x2,0x82,0x7e,0x3c,0x99,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0x8e,0x49,0x44,0x41,0x54,0x18,0xd3,0xb5,0x90,0x31,0xe,0xc2,0x40,0xc,0x4,0x77,0xcf,0xd6,0x85,0xab,0x68,0x53,0xe5,0x1f,0xbc,0x8a,0x2f,0xe4,0xc9,0x20,0x8a,0x24,0x17,0xfb,0x4c,0x3,0x8,0x85,0x20,0xd1,0x30,0xd2,0x36,0xd6,0x14,0xbb,0x66,0xdf,0xf7,0xe7,0x9c,0xf3,0x28,0x22,0x7,0x92,0x78,0x27,0x22,0xe0,0xee,0x73,0xad,0x75,0xe4,0x30,0xc,0x97,0xae,0xeb,0x8e,0xaa,0x8a,0x3d,0xd1,0xcc,0xb0,0x2c,0xcb,0x55,0x45,0xa4,0xa8,0x2a,0xbe,0x89,0x0,0x60,0x66,0x25,0x91,0x6c,0x24,0x3f,0x24,0x0,0x78,0xde,0x49,0xb6,0x84,0x1f,0xf9,0x83,0x18,0x11,0x29,0x22,0x5e,0xc5,0xb7,0x63,0x1e,0x49,0xea,0xee,0x93,0x99,0xe5,0x67,0xf9,0xbd,0xf7,0xb8,0xfb,0x2c,0xa5,0x94,0x9,0xc0,0xa9,0xb5,0x6,0x77,0xb7,0x2d,0xeb,0xba,0xde,0x6a,0xad,0xe3,0x1d,0xd3,0x60,0x61,0x55,0x29,0xdd,0xd9,0x71,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -200,7 +240,7 @@ static const unsigned char option_arrow_png[]={
static const unsigned char option_button_disabled_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x77,0x0,0x7d,0x59,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x5a,0x0,0x5a,0x0,0x5a,0x61,0x75,0x7f,0x99,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x10,0x16,0x18,0x29,0x61,0xeb,0x3d,0xe6,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0xc9,0x49,0x44,0x41,0x54,0x48,0x89,0xed,0x95,0xb1,0xaa,0xc2,0x40,0x10,0x45,0xcf,0x86,0x11,0x46,0x4c,0x61,0xb1,0x55,0xb6,0x4f,0xa5,0xbc,0xff,0xff,0x87,0xd7,0x88,0x56,0xf6,0xb1,0x4a,0x61,0xa1,0x30,0xe0,0x10,0x2d,0x76,0x53,0x3f,0xf1,0x11,0xd3,0x64,0x60,0x58,0xd8,0x62,0xee,0xb9,0x53,0xdc,0x9,0x80,0x0,0xab,0xf2,0x86,0xd2,0x53,0xd6,0xb3,0xb4,0x3,0x8f,0x51,0x7c,0xb,0x6c,0x80,0xea,0x4b,0x0,0x3,0x70,0x7,0xae,0x42,0x76,0xbe,0xd9,0xef,0x7e,0xb6,0xa9,0x49,0xad,0x88,0x4c,0xaa,0xee,0xee,0x74,0x97,0xee,0x7c,0x3c,0x1d,0x0,0x6e,0x42,0x76,0x5d,0xa5,0x26,0xb5,0x66,0x86,0x99,0xfd,0x39,0x24,0xc6,0x48,0xdf,0xf7,0x1f,0x1,0xa8,0x2a,0xa9,0x49,0xed,0xf1,0x74,0xf8,0x5,0xaa,0xaa,0xfc,0x7,0x11,0x79,0x4b,0xfc,0xbf,0x65,0x66,0x94,0x2d,0x7,0xc8,0xee,0x67,0xad,0x5,0x60,0x1,0x58,0x0,0x46,0x80,0xa7,0xbb,0xa3,0xaa,0x93,0xb,0xaa,0x2a,0xee,0xe,0x39,0x92,0x11,0x72,0x2e,0xf,0xdd,0xa5,0x3b,0xa7,0x26,0xb5,0x75,0x5d,0xbf,0x35,0x28,0xc6,0xf8,0x11,0xc0,0x18,0xc5,0xa3,0x6e,0x0,0xd6,0xcc,0x78,0x8c,0x2,0x33,0x9f,0xe3,0x17,0x68,0xff,0x45,0x43,0x59,0xe8,0x6b,0xa8,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x77,0x0,0x7d,0x59,0x0,0x0,0xa,0x45,0x69,0x43,0x43,0x50,0x49,0x43,0x43,0x20,0x70,0x72,0x6f,0x66,0x69,0x6c,0x65,0x0,0x0,0x78,0xda,0x9d,0x53,0x67,0x54,0x53,0xe9,0x16,0x3d,0xf7,0xde,0xf4,0x42,0x4b,0x88,0x80,0x94,0x4b,0x6f,0x52,0x15,0x8,0x20,0x52,0x42,0x8b,0x80,0x14,0x91,0x26,0x2a,0x21,0x9,0x10,0x4a,0x88,0x21,0xa1,0xd9,0x15,0x51,0xc1,0x11,0x45,0x45,0x4,0x1b,0xc8,0xa0,0x88,0x3,0x8e,0x8e,0x80,0x8c,0x15,0x51,0x2c,0xc,0x8a,0xa,0xd8,0x7,0xe4,0x21,0xa2,0x8e,0x83,0xa3,0x88,0x8a,0xca,0xfb,0xe1,0x7b,0xa3,0x6b,0xd6,0xbc,0xf7,0xe6,0xcd,0xfe,0xb5,0xd7,0x3e,0xe7,0xac,0xf3,0x9d,0xb3,0xcf,0x7,0xc0,0x8,0xc,0x96,0x48,0x33,0x51,0x35,0x80,0xc,0xa9,0x42,0x1e,0x11,0xe0,0x83,0xc7,0xc4,0xc6,0xe1,0xe4,0x2e,0x40,0x81,0xa,0x24,0x70,0x0,0x10,0x8,0xb3,0x64,0x21,0x73,0xfd,0x23,0x1,0x0,0xf8,0x7e,0x3c,0x3c,0x2b,0x22,0xc0,0x7,0xbe,0x0,0x1,0x78,0xd3,0xb,0x8,0x0,0xc0,0x4d,0x9b,0xc0,0x30,0x1c,0x87,0xff,0xf,0xea,0x42,0x99,0x5c,0x1,0x80,0x84,0x1,0xc0,0x74,0x91,0x38,0x4b,0x8,0x80,0x14,0x0,0x40,0x7a,0x8e,0x42,0xa6,0x0,0x40,0x46,0x1,0x80,0x9d,0x98,0x26,0x53,0x0,0xa0,0x4,0x0,0x60,0xcb,0x63,0x62,0xe3,0x0,0x50,0x2d,0x0,0x60,0x27,0x7f,0xe6,0xd3,0x0,0x80,0x9d,0xf8,0x99,0x7b,0x1,0x0,0x5b,0x94,0x21,0x15,0x1,0xa0,0x91,0x0,0x20,0x13,0x65,0x88,0x44,0x0,0x68,0x3b,0x0,0xac,0xcf,0x56,0x8a,0x45,0x0,0x58,0x30,0x0,0x14,0x66,0x4b,0xc4,0x39,0x0,0xd8,0x2d,0x0,0x30,0x49,0x57,0x66,0x48,0x0,0xb0,0xb7,0x0,0xc0,0xce,0x10,0xb,0xb2,0x0,0x8,0xc,0x0,0x30,0x51,0x88,0x85,0x29,0x0,0x4,0x7b,0x0,0x60,0xc8,0x23,0x23,0x78,0x0,0x84,0x99,0x0,0x14,0x46,0xf2,0x57,0x3c,0xf1,0x2b,0xae,0x10,0xe7,0x2a,0x0,0x0,0x78,0x99,0xb2,0x3c,0xb9,0x24,0x39,0x45,0x81,0x5b,0x8,0x2d,0x71,0x7,0x57,0x57,0x2e,0x1e,0x28,0xce,0x49,0x17,0x2b,0x14,0x36,0x61,0x2,0x61,0x9a,0x40,0x2e,0xc2,0x79,0x99,0x19,0x32,0x81,0x34,0xf,0xe0,0xf3,0xcc,0x0,0x0,0xa0,0x91,0x15,0x11,0xe0,0x83,0xf3,0xfd,0x78,0xce,0xe,0xae,0xce,0xce,0x36,0x8e,0xb6,0xe,0x5f,0x2d,0xea,0xbf,0x6,0xff,0x22,0x62,0x62,0xe3,0xfe,0xe5,0xcf,0xab,0x70,0x40,0x0,0x0,0xe1,0x74,0x7e,0xd1,0xfe,0x2c,0x2f,0xb3,0x1a,0x80,0x3b,0x6,0x80,0x6d,0xfe,0xa2,0x25,0xee,0x4,0x68,0x5e,0xb,0xa0,0x75,0xf7,0x8b,0x66,0xb2,0xf,0x40,0xb5,0x0,0xa0,0xe9,0xda,0x57,0xf3,0x70,0xf8,0x7e,0x3c,0x3c,0x45,0xa1,0x90,0xb9,0xd9,0xd9,0xe5,0xe4,0xe4,0xd8,0x4a,0xc4,0x42,0x5b,0x61,0xca,0x57,0x7d,0xfe,0x67,0xc2,0x5f,0xc0,0x57,0xfd,0x6c,0xf9,0x7e,0x3c,0xfc,0xf7,0xf5,0xe0,0xbe,0xe2,0x24,0x81,0x32,0x5d,0x81,0x47,0x4,0xf8,0xe0,0xc2,0xcc,0xf4,0x4c,0xa5,0x1c,0xcf,0x92,0x9,0x84,0x62,0xdc,0xe6,0x8f,0x47,0xfc,0xb7,0xb,0xff,0xfc,0x1d,0xd3,0x22,0xc4,0x49,0x62,0xb9,0x58,0x2a,0x14,0xe3,0x51,0x12,0x71,0x8e,0x44,0x9a,0x8c,0xf3,0x32,0xa5,0x22,0x89,0x42,0x92,0x29,0xc5,0x25,0xd2,0xff,0x64,0xe2,0xdf,0x2c,0xfb,0x3,0x3e,0xdf,0x35,0x0,0xb0,0x6a,0x3e,0x1,0x7b,0x91,0x2d,0xa8,0x5d,0x63,0x3,0xf6,0x4b,0x27,0x10,0x58,0x74,0xc0,0xe2,0xf7,0x0,0x0,0xf2,0xbb,0x6f,0xc1,0xd4,0x28,0x8,0x3,0x80,0x68,0x83,0xe1,0xcf,0x77,0xff,0xef,0x3f,0xfd,0x47,0xa0,0x25,0x0,0x80,0x66,0x49,0x92,0x71,0x0,0x0,0x5e,0x44,0x24,0x2e,0x54,0xca,0xb3,0x3f,0xc7,0x8,0x0,0x0,0x44,0xa0,0x81,0x2a,0xb0,0x41,0x1b,0xf4,0xc1,0x18,0x2c,0xc0,0x6,0x1c,0xc1,0x5,0xdc,0xc1,0xb,0xfc,0x60,0x36,0x84,0x42,0x24,0xc4,0xc2,0x42,0x10,0x42,0xa,0x64,0x80,0x1c,0x72,0x60,0x29,0xac,0x82,0x42,0x28,0x86,0xcd,0xb0,0x1d,0x2a,0x60,0x2f,0xd4,0x40,0x1d,0x34,0xc0,0x51,0x68,0x86,0x93,0x70,0xe,0x2e,0xc2,0x55,0xb8,0xe,0x3d,0x70,0xf,0xfa,0x61,0x8,0x9e,0xc1,0x28,0xbc,0x81,0x9,0x4,0x41,0xc8,0x8,0x13,0x61,0x21,0xda,0x88,0x1,0x62,0x8a,0x58,0x23,0x8e,0x8,0x17,0x99,0x85,0xf8,0x21,0xc1,0x48,0x4,0x12,0x8b,0x24,0x20,0xc9,0x88,0x14,0x51,0x22,0x4b,0x91,0x35,0x48,0x31,0x52,0x8a,0x54,0x20,0x55,0x48,0x1d,0xf2,0x3d,0x72,0x2,0x39,0x87,0x5c,0x46,0xba,0x91,0x3b,0xc8,0x0,0x32,0x82,0xfc,0x86,0xbc,0x47,0x31,0x94,0x81,0xb2,0x51,0x3d,0xd4,0xc,0xb5,0x43,0xb9,0xa8,0x37,0x1a,0x84,0x46,0xa2,0xb,0xd0,0x64,0x74,0x31,0x9a,0x8f,0x16,0xa0,0x9b,0xd0,0x72,0xb4,0x1a,0x3d,0x8c,0x36,0xa1,0xe7,0xd0,0xab,0x68,0xf,0xda,0x8f,0x3e,0x43,0xc7,0x30,0xc0,0xe8,0x18,0x7,0x33,0xc4,0x6c,0x30,0x2e,0xc6,0xc3,0x42,0xb1,0x38,0x2c,0x9,0x93,0x63,0xcb,0xb1,0x22,0xac,0xc,0xab,0xc6,0x1a,0xb0,0x56,0xac,0x3,0xbb,0x89,0xf5,0x63,0xcf,0xb1,0x77,0x4,0x12,0x81,0x45,0xc0,0x9,0x36,0x4,0x77,0x42,0x20,0x61,0x1e,0x41,0x48,0x58,0x4c,0x58,0x4e,0xd8,0x48,0xa8,0x20,0x1c,0x24,0x34,0x11,0xda,0x9,0x37,0x9,0x3,0x84,0x51,0xc2,0x27,0x22,0x93,0xa8,0x4b,0xb4,0x26,0xba,0x11,0xf9,0xc4,0x18,0x62,0x32,0x31,0x87,0x58,0x48,0x2c,0x23,0xd6,0x12,0x8f,0x13,0x2f,0x10,0x7b,0x88,0x43,0xc4,0x37,0x24,0x12,0x89,0x43,0x32,0x27,0xb9,0x90,0x2,0x49,0xb1,0xa4,0x54,0xd2,0x12,0xd2,0x46,0xd2,0x6e,0x52,0x23,0xe9,0x2c,0xa9,0x9b,0x34,0x48,0x1a,0x23,0x93,0xc9,0xda,0x64,0x6b,0xb2,0x7,0x39,0x94,0x2c,0x20,0x2b,0xc8,0x85,0xe4,0x9d,0xe4,0xc3,0xe4,0x33,0xe4,0x1b,0xe4,0x21,0xf2,0x5b,0xa,0x9d,0x62,0x40,0x71,0xa4,0xf8,0x53,0xe2,0x28,0x52,0xca,0x6a,0x4a,0x19,0xe5,0x10,0xe5,0x34,0xe5,0x6,0x65,0x98,0x32,0x41,0x55,0xa3,0x9a,0x52,0xdd,0xa8,0xa1,0x54,0x11,0x35,0x8f,0x5a,0x42,0xad,0xa1,0xb6,0x52,0xaf,0x51,0x87,0xa8,0x13,0x34,0x75,0x9a,0x39,0xcd,0x83,0x16,0x49,0x4b,0xa5,0xad,0xa2,0x95,0xd3,0x1a,0x68,0x17,0x68,0xf7,0x69,0xaf,0xe8,0x74,0xba,0x11,0xdd,0x95,0x1e,0x4e,0x97,0xd0,0x57,0xd2,0xcb,0xe9,0x47,0xe8,0x97,0xe8,0x3,0xf4,0x77,0xc,0xd,0x86,0x15,0x83,0xc7,0x88,0x67,0x28,0x19,0x9b,0x18,0x7,0x18,0x67,0x19,0x77,0x18,0xaf,0x98,0x4c,0xa6,0x19,0xd3,0x8b,0x19,0xc7,0x54,0x30,0x37,0x31,0xeb,0x98,0xe7,0x99,0xf,0x99,0x6f,0x55,0x58,0x2a,0xb6,0x2a,0x7c,0x15,0x91,0xca,0xa,0x95,0x4a,0x95,0x26,0x95,0x1b,0x2a,0x2f,0x54,0xa9,0xaa,0xa6,0xaa,0xde,0xaa,0xb,0x55,0xf3,0x55,0xcb,0x54,0x8f,0xa9,0x5e,0x53,0x7d,0xae,0x46,0x55,0x33,0x53,0xe3,0xa9,0x9,0xd4,0x96,0xab,0x55,0xaa,0x9d,0x50,0xeb,0x53,0x1b,0x53,0x67,0xa9,0x3b,0xa8,0x87,0xaa,0x67,0xa8,0x6f,0x54,0x3f,0xa4,0x7e,0x59,0xfd,0x89,0x6,0x59,0xc3,0x4c,0xc3,0x4f,0x43,0xa4,0x51,0xa0,0xb1,0x5f,0xe3,0xbc,0xc6,0x20,0xb,0x63,0x19,0xb3,0x78,0x2c,0x21,0x6b,0xd,0xab,0x86,0x75,0x81,0x35,0xc4,0x26,0xb1,0xcd,0xd9,0x7c,0x76,0x2a,0xbb,0x98,0xfd,0x1d,0xbb,0x8b,0x3d,0xaa,0xa9,0xa1,0x39,0x43,0x33,0x4a,0x33,0x57,0xb3,0x52,0xf3,0x94,0x66,0x3f,0x7,0xe3,0x98,0x71,0xf8,0x9c,0x74,0x4e,0x9,0xe7,0x28,0xa7,0x97,0xf3,0x7e,0x8a,0xde,0x14,0xef,0x29,0xe2,0x29,0x1b,0xa6,0x34,0x4c,0xb9,0x31,0x65,0x5c,0x6b,0xaa,0x96,0x97,0x96,0x58,0xab,0x48,0xab,0x51,0xab,0x47,0xeb,0xbd,0x36,0xae,0xed,0xa7,0x9d,0xa6,0xbd,0x45,0xbb,0x59,0xfb,0x81,0xe,0x41,0xc7,0x4a,0x27,0x5c,0x27,0x47,0x67,0x8f,0xce,0x5,0x9d,0xe7,0x53,0xd9,0x53,0xdd,0xa7,0xa,0xa7,0x16,0x4d,0x3d,0x3a,0xf5,0xae,0x2e,0xaa,0x6b,0xa5,0x1b,0xa1,0xbb,0x44,0x77,0xbf,0x6e,0xa7,0xee,0x98,0x9e,0xbe,0x5e,0x80,0x9e,0x4c,0x6f,0xa7,0xde,0x79,0xbd,0xe7,0xfa,0x1c,0x7d,0x2f,0xfd,0x54,0xfd,0x6d,0xfa,0xa7,0xf5,0x47,0xc,0x58,0x6,0xb3,0xc,0x24,0x6,0xdb,0xc,0xce,0x18,0x3c,0xc5,0x35,0x71,0x6f,0x3c,0x1d,0x2f,0xc7,0xdb,0xf1,0x51,0x43,0x5d,0xc3,0x40,0x43,0xa5,0x61,0x95,0x61,0x97,0xe1,0x84,0x91,0xb9,0xd1,0x3c,0xa3,0xd5,0x46,0x8d,0x46,0xf,0x8c,0x69,0xc6,0x5c,0xe3,0x24,0xe3,0x6d,0xc6,0x6d,0xc6,0xa3,0x26,0x6,0x26,0x21,0x26,0x4b,0x4d,0xea,0x4d,0xee,0x9a,0x52,0x4d,0xb9,0xa6,0x29,0xa6,0x3b,0x4c,0x3b,0x4c,0xc7,0xcd,0xcc,0xcd,0xa2,0xcd,0xd6,0x99,0x35,0x9b,0x3d,0x31,0xd7,0x32,0xe7,0x9b,0xe7,0x9b,0xd7,0x9b,0xdf,0xb7,0x60,0x5a,0x78,0x5a,0x2c,0xb6,0xa8,0xb6,0xb8,0x65,0x49,0xb2,0xe4,0x5a,0xa6,0x59,0xee,0xb6,0xbc,0x6e,0x85,0x5a,0x39,0x59,0xa5,0x58,0x55,0x5a,0x5d,0xb3,0x46,0xad,0x9d,0xad,0x25,0xd6,0xbb,0xad,0xbb,0xa7,0x11,0xa7,0xb9,0x4e,0x93,0x4e,0xab,0x9e,0xd6,0x67,0xc3,0xb0,0xf1,0xb6,0xc9,0xb6,0xa9,0xb7,0x19,0xb0,0xe5,0xd8,0x6,0xdb,0xae,0xb6,0x6d,0xb6,0x7d,0x61,0x67,0x62,0x17,0x67,0xb7,0xc5,0xae,0xc3,0xee,0x93,0xbd,0x93,0x7d,0xba,0x7d,0x8d,0xfd,0x3d,0x7,0xd,0x87,0xd9,0xe,0xab,0x1d,0x5a,0x1d,0x7e,0x73,0xb4,0x72,0x14,0x3a,0x56,0x3a,0xde,0x9a,0xce,0x9c,0xee,0x3f,0x7d,0xc5,0xf4,0x96,0xe9,0x2f,0x67,0x58,0xcf,0x10,0xcf,0xd8,0x33,0xe3,0xb6,0x13,0xcb,0x29,0xc4,0x69,0x9d,0x53,0x9b,0xd3,0x47,0x67,0x17,0x67,0xb9,0x73,0x83,0xf3,0x88,0x8b,0x89,0x4b,0x82,0xcb,0x2e,0x97,0x3e,0x2e,0x9b,0x1b,0xc6,0xdd,0xc8,0xbd,0xe4,0x4a,0x74,0xf5,0x71,0x5d,0xe1,0x7a,0xd2,0xf5,0x9d,0x9b,0xb3,0x9b,0xc2,0xed,0xa8,0xdb,0xaf,0xee,0x36,0xee,0x69,0xee,0x87,0xdc,0x9f,0xcc,0x34,0x9f,0x29,0x9e,0x59,0x33,0x73,0xd0,0xc3,0xc8,0x43,0xe0,0x51,0xe5,0xd1,0x3f,0xb,0x9f,0x95,0x30,0x6b,0xdf,0xac,0x7e,0x4f,0x43,0x4f,0x81,0x67,0xb5,0xe7,0x23,0x2f,0x63,0x2f,0x91,0x57,0xad,0xd7,0xb0,0xb7,0xa5,0x77,0xaa,0xf7,0x61,0xef,0x17,0x3e,0xf6,0x3e,0x72,0x9f,0xe3,0x3e,0xe3,0x3c,0x37,0xde,0x32,0xde,0x59,0x5f,0xcc,0x37,0xc0,0xb7,0xc8,0xb7,0xcb,0x4f,0xc3,0x6f,0x9e,0x5f,0x85,0xdf,0x43,0x7f,0x23,0xff,0x64,0xff,0x7a,0xff,0xd1,0x0,0xa7,0x80,0x25,0x1,0x67,0x3,0x89,0x81,0x41,0x81,0x5b,0x2,0xfb,0xf8,0x7a,0x7c,0x21,0xbf,0x8e,0x3f,0x3a,0xdb,0x65,0xf6,0xb2,0xd9,0xed,0x41,0x8c,0xa0,0xb9,0x41,0x15,0x41,0x8f,0x82,0xad,0x82,0xe5,0xc1,0xad,0x21,0x68,0xc8,0xec,0x90,0xad,0x21,0xf7,0xe7,0x98,0xce,0x91,0xce,0x69,0xe,0x85,0x50,0x7e,0xe8,0xd6,0xd0,0x7,0x61,0xe6,0x61,0x8b,0xc3,0x7e,0xc,0x27,0x85,0x87,0x85,0x57,0x86,0x3f,0x8e,0x70,0x88,0x58,0x1a,0xd1,0x31,0x97,0x35,0x77,0xd1,0xdc,0x43,0x73,0xdf,0x44,0xfa,0x44,0x96,0x44,0xde,0x9b,0x67,0x31,0x4f,0x39,0xaf,0x2d,0x4a,0x35,0x2a,0x3e,0xaa,0x2e,0x6a,0x3c,0xda,0x37,0xba,0x34,0xba,0x3f,0xc6,0x2e,0x66,0x59,0xcc,0xd5,0x58,0x9d,0x58,0x49,0x6c,0x4b,0x1c,0x39,0x2e,0x2a,0xae,0x36,0x6e,0x6c,0xbe,0xdf,0xfc,0xed,0xf3,0x87,0xe2,0x9d,0xe2,0xb,0xe3,0x7b,0x17,0x98,0x2f,0xc8,0x5d,0x70,0x79,0xa1,0xce,0xc2,0xf4,0x85,0xa7,0x16,0xa9,0x2e,0x12,0x2c,0x3a,0x96,0x40,0x4c,0x88,0x4e,0x38,0x94,0xf0,0x41,0x10,0x2a,0xa8,0x16,0x8c,0x25,0xf2,0x13,0x77,0x25,0x8e,0xa,0x79,0xc2,0x1d,0xc2,0x67,0x22,0x2f,0xd1,0x36,0xd1,0x88,0xd8,0x43,0x5c,0x2a,0x1e,0x4e,0xf2,0x48,0x2a,0x4d,0x7a,0x92,0xec,0x91,0xbc,0x35,0x79,0x24,0xc5,0x33,0xa5,0x2c,0xe5,0xb9,0x84,0x27,0xa9,0x90,0xbc,0x4c,0xd,0x4c,0xdd,0x9b,0x3a,0x9e,0x16,0x9a,0x76,0x20,0x6d,0x32,0x3d,0x3a,0xbd,0x31,0x83,0x92,0x91,0x90,0x71,0x42,0xaa,0x21,0x4d,0x93,0xb6,0x67,0xea,0x67,0xe6,0x66,0x76,0xcb,0xac,0x65,0x85,0xb2,0xfe,0xc5,0x6e,0x8b,0xb7,0x2f,0x1e,0x95,0x7,0xc9,0x6b,0xb3,0x90,0xac,0x5,0x59,0x2d,0xa,0xb6,0x42,0xa6,0xe8,0x54,0x5a,0x28,0xd7,0x2a,0x7,0xb2,0x67,0x65,0x57,0x66,0xbf,0xcd,0x89,0xca,0x39,0x96,0xab,0x9e,0x2b,0xcd,0xed,0xcc,0xb3,0xca,0xdb,0x90,0x37,0x9c,0xef,0x9f,0xff,0xed,0x12,0xc2,0x12,0xe1,0x92,0xb6,0xa5,0x86,0x4b,0x57,0x2d,0x1d,0x58,0xe6,0xbd,0xac,0x6a,0x39,0xb2,0x3c,0x71,0x79,0xdb,0xa,0xe3,0x15,0x5,0x2b,0x86,0x56,0x6,0xac,0x3c,0xb8,0x8a,0xb6,0x2a,0x6d,0xd5,0x4f,0xab,0xed,0x57,0x97,0xae,0x7e,0xbd,0x26,0x7a,0x4d,0x6b,0x81,0x5e,0xc1,0xca,0x82,0xc1,0xb5,0x1,0x6b,0xeb,0xb,0x55,0xa,0xe5,0x85,0x7d,0xeb,0xdc,0xd7,0xed,0x5d,0x4f,0x58,0x2f,0x59,0xdf,0xb5,0x61,0xfa,0x86,0x9d,0x1b,0x3e,0x15,0x89,0x8a,0xae,0x14,0xdb,0x17,0x97,0x15,0x7f,0xd8,0x28,0xdc,0x78,0xe5,0x1b,0x87,0x6f,0xca,0xbf,0x99,0xdc,0x94,0xb4,0xa9,0xab,0xc4,0xb9,0x64,0xcf,0x66,0xd2,0x66,0xe9,0xe6,0xde,0x2d,0x9e,0x5b,0xe,0x96,0xaa,0x97,0xe6,0x97,0xe,0x6e,0xd,0xd9,0xda,0xb4,0xd,0xdf,0x56,0xb4,0xed,0xf5,0xf6,0x45,0xdb,0x2f,0x97,0xcd,0x28,0xdb,0xbb,0x83,0xb6,0x43,0xb9,0xa3,0xbf,0x3c,0xb8,0xbc,0x65,0xa7,0xc9,0xce,0xcd,0x3b,0x3f,0x54,0xa4,0x54,0xf4,0x54,0xfa,0x54,0x36,0xee,0xd2,0xdd,0xb5,0x61,0xd7,0xf8,0x6e,0xd1,0xee,0x1b,0x7b,0xbc,0xf6,0x34,0xec,0xd5,0xdb,0x5b,0xbc,0xf7,0xfd,0x3e,0xc9,0xbe,0xdb,0x55,0x1,0x55,0x4d,0xd5,0x66,0xd5,0x65,0xfb,0x49,0xfb,0xb3,0xf7,0x3f,0xae,0x89,0xaa,0xe9,0xf8,0x96,0xfb,0x6d,0x5d,0xad,0x4e,0x6d,0x71,0xed,0xc7,0x3,0xd2,0x3,0xfd,0x7,0x23,0xe,0xb6,0xd7,0xb9,0xd4,0xd5,0x1d,0xd2,0x3d,0x54,0x52,0x8f,0xd6,0x2b,0xeb,0x47,0xe,0xc7,0x1f,0xbe,0xfe,0x9d,0xef,0x77,0x2d,0xd,0x36,0xd,0x55,0x8d,0x9c,0xc6,0xe2,0x23,0x70,0x44,0x79,0xe4,0xe9,0xf7,0x9,0xdf,0xf7,0x1e,0xd,0x3a,0xda,0x76,0x8c,0x7b,0xac,0xe1,0x7,0xd3,0x1f,0x76,0x1d,0x67,0x1d,0x2f,0x6a,0x42,0x9a,0xf2,0x9a,0x46,0x9b,0x53,0x9a,0xfb,0x5b,0x62,0x5b,0xba,0x4f,0xcc,0x3e,0xd1,0xd6,0xea,0xde,0x7a,0xfc,0x47,0xdb,0x1f,0xf,0x9c,0x34,0x3c,0x59,0x79,0x4a,0xf3,0x54,0xc9,0x69,0xda,0xe9,0x82,0xd3,0x93,0x67,0xf2,0xcf,0x8c,0x9d,0x95,0x9d,0x7d,0x7e,0x2e,0xf9,0xdc,0x60,0xdb,0xa2,0xb6,0x7b,0xe7,0x63,0xce,0xdf,0x6a,0xf,0x6f,0xef,0xba,0x10,0x74,0xe1,0xd2,0x45,0xff,0x8b,0xe7,0x3b,0xbc,0x3b,0xce,0x5c,0xf2,0xb8,0x74,0xf2,0xb2,0xdb,0xe5,0x13,0x57,0xb8,0x57,0x9a,0xaf,0x3a,0x5f,0x6d,0xea,0x74,0xea,0x3c,0xfe,0x93,0xd3,0x4f,0xc7,0xbb,0x9c,0xbb,0x9a,0xae,0xb9,0x5c,0x6b,0xb9,0xee,0x7a,0xbd,0xb5,0x7b,0x66,0xf7,0xe9,0x1b,0x9e,0x37,0xce,0xdd,0xf4,0xbd,0x79,0xf1,0x16,0xff,0xd6,0xd5,0x9e,0x39,0x3d,0xdd,0xbd,0xf3,0x7a,0x6f,0xf7,0xc5,0xf7,0xf5,0xdf,0x16,0xdd,0x7e,0x72,0x27,0xfd,0xce,0xcb,0xbb,0xd9,0x77,0x27,0xee,0xad,0xbc,0x4f,0xbc,0x5f,0xf4,0x40,0xed,0x41,0xd9,0x43,0xdd,0x87,0xd5,0x3f,0x5b,0xfe,0xdc,0xd8,0xef,0xdc,0x7f,0x6a,0xc0,0x77,0xa0,0xf3,0xd1,0xdc,0x47,0xf7,0x6,0x85,0x83,0xcf,0xfe,0x91,0xf5,0x8f,0xf,0x43,0x5,0x8f,0x99,0x8f,0xcb,0x86,0xd,0x86,0xeb,0x9e,0x38,0x3e,0x39,0x39,0xe2,0x3f,0x72,0xfd,0xe9,0xfc,0xa7,0x43,0xcf,0x64,0xcf,0x26,0x9e,0x17,0xfe,0xa2,0xfe,0xcb,0xae,0x17,0x16,0x2f,0x7e,0xf8,0xd5,0xeb,0xd7,0xce,0xd1,0x98,0xd1,0xa1,0x97,0xf2,0x97,0x93,0xbf,0x6d,0x7c,0xa5,0xfd,0xea,0xc0,0xeb,0x19,0xaf,0xdb,0xc6,0xc2,0xc6,0x1e,0xbe,0xc9,0x78,0x33,0x31,0x5e,0xf4,0x56,0xfb,0xed,0xc1,0x77,0xdc,0x77,0x1d,0xef,0xa3,0xdf,0xf,0x4f,0xe4,0x7c,0x20,0x7f,0x28,0xff,0x68,0xf9,0xb1,0xf5,0x53,0xd0,0xa7,0xfb,0x93,0x19,0x93,0x93,0xff,0x4,0x3,0x98,0xf3,0xfc,0xef,0x35,0x94,0x82,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xa,0x14,0x3,0x3,0x10,0x8e,0xab,0x21,0xcd,0x0,0x0,0x1,0xba,0x49,0x44,0x41,0x54,0x48,0xc7,0xad,0x95,0x51,0x8e,0xd3,0x30,0x10,0x86,0xbf,0xb1,0x53,0x52,0x95,0x4a,0x9b,0x97,0x3e,0x6c,0x7b,0x98,0xde,0x81,0x2b,0x20,0x71,0x86,0x1e,0x81,0x4b,0x70,0xe,0xae,0xb0,0xf,0x48,0x48,0x7b,0x7,0xb4,0xa8,0xf,0x15,0xec,0x82,0x96,0x6d,0xec,0x19,0x1e,0x62,0x37,0x29,0x88,0xd4,0x51,0x19,0x69,0x94,0xb1,0x64,0xcf,0xfc,0xf9,0xe7,0xb7,0x47,0x80,0xa,0x78,0x5,0xd4,0xc0,0x3c,0xc5,0x1e,0x70,0x9c,0x9b,0x2,0x2d,0xf0,0x2,0x3c,0x3,0xc7,0xb4,0x56,0xae,0xb0,0x5c,0xfc,0x35,0xd0,0x0,0x37,0x29,0xae,0x1,0x49,0x9e,0xad,0x4d,0x85,0x9f,0x80,0x3,0xf0,0x8,0xc4,0xff,0x1,0xa0,0x6,0x9a,0xed,0x76,0xfb,0x66,0xb3,0xd9,0xec,0x42,0x8,0xcd,0xd8,0x81,0xe5,0x72,0xc9,0xdd,0xdd,0x67,0xc0,0xf0,0xbe,0xc2,0x39,0x37,0x5a,0xc0,0xcc,0x92,0x2b,0xaa,0x8a,0x88,0x3c,0x78,0xef,0xdf,0xde,0xdf,0x7f,0xfa,0x98,0x1,0xcc,0x81,0x9b,0xf5,0x7a,0xbd,0x3b,0x1c,0xe,0x4d,0x8,0x1,0x33,0xfb,0x67,0x42,0x55,0x25,0x84,0x23,0xaa,0x11,0xef,0x67,0xc5,0x0,0x54,0x15,0xd5,0x8,0x70,0x5b,0xd7,0xf3,0xf,0xc0,0xfa,0xac,0x5,0x6d,0xdb,0x36,0x6d,0xdb,0x16,0x12,0x27,0x88,0x38,0xbc,0x77,0x38,0xe7,0xb,0x0,0xe4,0x2e,0x19,0x31,0x6,0x62,0x8c,0xb7,0xc3,0x16,0x78,0xa0,0x56,0xd5,0xd1,0x3f,0x1f,0x32,0x0,0x20,0x22,0x80,0x43,0x64,0x9c,0x1,0x11,0x43,0x15,0x9c,0x23,0x1,0x91,0xbf,0x34,0xe0,0x0,0xc9,0x34,0x5d,0x32,0x33,0x43,0xc4,0x30,0x3,0x91,0xce,0xc7,0xf7,0xe7,0x3d,0x76,0x62,0x61,0xa8,0xdb,0x2a,0x3,0x9d,0xca,0xc0,0x14,0xfb,0x33,0xed,0x70,0x5d,0xd,0x13,0x97,0x2,0x50,0xe5,0x24,0x2c,0xb9,0x40,0x41,0x7f,0x3,0xb2,0x10,0xed,0xac,0x4e,0xd5,0xef,0xb3,0x22,0x0,0xdd,0xbe,0x98,0x62,0xc5,0xac,0xc,0x40,0xe7,0x1d,0xfd,0xbd,0x28,0x3b,0x0,0xa,0x58,0x87,0x4e,0x8b,0x19,0x80,0x7c,0xbd,0xac,0xf0,0x1a,0xf6,0xdf,0xe1,0x99,0x2a,0xbd,0x66,0x2f,0xa5,0xc,0x74,0xad,0x52,0xa0,0x5c,0xb4,0x99,0x35,0xd5,0x98,0x6a,0x9c,0x3,0x38,0x2,0x3f,0x9d,0x73,0xdf,0xbc,0xf7,0x4d,0x8,0xe1,0x62,0xc2,0xe,0xc8,0x14,0x0,0x7a,0xd2,0x58,0x27,0x19,0xf9,0x3a,0x4,0xf0,0xb,0xf8,0xbe,0xdf,0xef,0xdf,0xaf,0x56,0xab,0x5d,0x8c,0xb1,0x19,0x63,0x62,0xb1,0x58,0x30,0x9b,0xcd,0x0,0xf0,0xde,0x4f,0x78,0x9,0x23,0x31,0x46,0x80,0x2f,0x20,0xef,0xfa,0x27,0xd,0x16,0x57,0xc,0xa3,0x67,0x20,0x5c,0x3b,0x8c,0x8e,0x29,0xe,0xc0,0x8f,0x89,0xe3,0xf8,0xaa,0x49,0x8,0xf0,0x1b,0x2,0x90,0x57,0xd1,0xcd,0x3c,0xcc,0x3e,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -210,27 +250,27 @@ static const unsigned char option_button_focus_png[]={
static const unsigned char option_button_hover_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x77,0x0,0x7d,0x59,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x4b,0x0,0x49,0x0,0x4e,0x38,0x4f,0x8,0xff,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x10,0x16,0x17,0x13,0x20,0x7f,0xf8,0x9b,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0xd8,0x49,0x44,0x41,0x54,0x48,0x89,0xed,0xd5,0xb1,0x4e,0x2,0x51,0x10,0x85,0xe1,0xef,0xe2,0x46,0x8c,0x31,0x91,0x64,0xab,0xdd,0xe5,0xfa,0x4,0xa8,0x2f,0x26,0xbe,0x8c,0xbe,0x18,0x42,0x4d,0x73,0x59,0x68,0x97,0xc4,0x42,0x12,0xc,0x16,0x40,0x67,0x14,0x49,0x56,0x1a,0x4e,0x39,0x99,0x9c,0xf9,0x27,0x93,0x9c,0x9,0xb8,0x46,0xf,0x37,0xb8,0x40,0xd0,0xae,0x36,0xf8,0xc4,0x3b,0x9a,0x6c,0x37,0xfc,0x1,0x11,0x57,0xff,0x4,0xf0,0x81,0x84,0xb7,0xcc,0x76,0xf3,0xbb,0xfb,0xc1,0xe3,0xa0,0x2a,0xab,0xa7,0xd8,0x8f,0xad,0x2,0xa4,0x59,0xda,0xd4,0xf3,0xfa,0x75,0x3c,0x19,0x5,0x4c,0x33,0x64,0xe8,0x56,0x65,0x35,0xcc,0xf3,0xdc,0x7c,0xb1,0xf8,0xd5,0xa4,0x2c,0x8a,0x83,0xfa,0xbe,0x53,0x9e,0xe7,0x1,0xc3,0xf1,0x64,0xf4,0x8c,0xac,0xb3,0xab,0x87,0xd8,0x8f,0x9a,0x66,0x79,0x94,0xe9,0x5f,0xd4,0x34,0x4b,0xb1,0x1f,0xd9,0x9d,0xba,0xf3,0x73,0x7b,0xfb,0x3a,0x3,0x9c,0x1,0xce,0x0,0x7b,0x80,0x4d,0x9a,0x25,0xbd,0xde,0x6d,0xeb,0x3,0xbb,0xdd,0x4b,0x69,0x96,0xd8,0x46,0xb2,0xc,0x6b,0xac,0xea,0x79,0xfd,0x82,0x83,0xa3,0xb8,0x2c,0x8a,0xa3,0x0,0xf6,0x51,0x8c,0x15,0xd6,0x1,0xa5,0x13,0x3e,0xa3,0xe0,0xc4,0xef,0xf8,0xb,0x70,0x57,0x43,0xed,0x5d,0x76,0xf,0x70,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x77,0x0,0x7d,0x59,0x0,0x0,0xa,0x45,0x69,0x43,0x43,0x50,0x49,0x43,0x43,0x20,0x70,0x72,0x6f,0x66,0x69,0x6c,0x65,0x0,0x0,0x78,0xda,0x9d,0x53,0x67,0x54,0x53,0xe9,0x16,0x3d,0xf7,0xde,0xf4,0x42,0x4b,0x88,0x80,0x94,0x4b,0x6f,0x52,0x15,0x8,0x20,0x52,0x42,0x8b,0x80,0x14,0x91,0x26,0x2a,0x21,0x9,0x10,0x4a,0x88,0x21,0xa1,0xd9,0x15,0x51,0xc1,0x11,0x45,0x45,0x4,0x1b,0xc8,0xa0,0x88,0x3,0x8e,0x8e,0x80,0x8c,0x15,0x51,0x2c,0xc,0x8a,0xa,0xd8,0x7,0xe4,0x21,0xa2,0x8e,0x83,0xa3,0x88,0x8a,0xca,0xfb,0xe1,0x7b,0xa3,0x6b,0xd6,0xbc,0xf7,0xe6,0xcd,0xfe,0xb5,0xd7,0x3e,0xe7,0xac,0xf3,0x9d,0xb3,0xcf,0x7,0xc0,0x8,0xc,0x96,0x48,0x33,0x51,0x35,0x80,0xc,0xa9,0x42,0x1e,0x11,0xe0,0x83,0xc7,0xc4,0xc6,0xe1,0xe4,0x2e,0x40,0x81,0xa,0x24,0x70,0x0,0x10,0x8,0xb3,0x64,0x21,0x73,0xfd,0x23,0x1,0x0,0xf8,0x7e,0x3c,0x3c,0x2b,0x22,0xc0,0x7,0xbe,0x0,0x1,0x78,0xd3,0xb,0x8,0x0,0xc0,0x4d,0x9b,0xc0,0x30,0x1c,0x87,0xff,0xf,0xea,0x42,0x99,0x5c,0x1,0x80,0x84,0x1,0xc0,0x74,0x91,0x38,0x4b,0x8,0x80,0x14,0x0,0x40,0x7a,0x8e,0x42,0xa6,0x0,0x40,0x46,0x1,0x80,0x9d,0x98,0x26,0x53,0x0,0xa0,0x4,0x0,0x60,0xcb,0x63,0x62,0xe3,0x0,0x50,0x2d,0x0,0x60,0x27,0x7f,0xe6,0xd3,0x0,0x80,0x9d,0xf8,0x99,0x7b,0x1,0x0,0x5b,0x94,0x21,0x15,0x1,0xa0,0x91,0x0,0x20,0x13,0x65,0x88,0x44,0x0,0x68,0x3b,0x0,0xac,0xcf,0x56,0x8a,0x45,0x0,0x58,0x30,0x0,0x14,0x66,0x4b,0xc4,0x39,0x0,0xd8,0x2d,0x0,0x30,0x49,0x57,0x66,0x48,0x0,0xb0,0xb7,0x0,0xc0,0xce,0x10,0xb,0xb2,0x0,0x8,0xc,0x0,0x30,0x51,0x88,0x85,0x29,0x0,0x4,0x7b,0x0,0x60,0xc8,0x23,0x23,0x78,0x0,0x84,0x99,0x0,0x14,0x46,0xf2,0x57,0x3c,0xf1,0x2b,0xae,0x10,0xe7,0x2a,0x0,0x0,0x78,0x99,0xb2,0x3c,0xb9,0x24,0x39,0x45,0x81,0x5b,0x8,0x2d,0x71,0x7,0x57,0x57,0x2e,0x1e,0x28,0xce,0x49,0x17,0x2b,0x14,0x36,0x61,0x2,0x61,0x9a,0x40,0x2e,0xc2,0x79,0x99,0x19,0x32,0x81,0x34,0xf,0xe0,0xf3,0xcc,0x0,0x0,0xa0,0x91,0x15,0x11,0xe0,0x83,0xf3,0xfd,0x78,0xce,0xe,0xae,0xce,0xce,0x36,0x8e,0xb6,0xe,0x5f,0x2d,0xea,0xbf,0x6,0xff,0x22,0x62,0x62,0xe3,0xfe,0xe5,0xcf,0xab,0x70,0x40,0x0,0x0,0xe1,0x74,0x7e,0xd1,0xfe,0x2c,0x2f,0xb3,0x1a,0x80,0x3b,0x6,0x80,0x6d,0xfe,0xa2,0x25,0xee,0x4,0x68,0x5e,0xb,0xa0,0x75,0xf7,0x8b,0x66,0xb2,0xf,0x40,0xb5,0x0,0xa0,0xe9,0xda,0x57,0xf3,0x70,0xf8,0x7e,0x3c,0x3c,0x45,0xa1,0x90,0xb9,0xd9,0xd9,0xe5,0xe4,0xe4,0xd8,0x4a,0xc4,0x42,0x5b,0x61,0xca,0x57,0x7d,0xfe,0x67,0xc2,0x5f,0xc0,0x57,0xfd,0x6c,0xf9,0x7e,0x3c,0xfc,0xf7,0xf5,0xe0,0xbe,0xe2,0x24,0x81,0x32,0x5d,0x81,0x47,0x4,0xf8,0xe0,0xc2,0xcc,0xf4,0x4c,0xa5,0x1c,0xcf,0x92,0x9,0x84,0x62,0xdc,0xe6,0x8f,0x47,0xfc,0xb7,0xb,0xff,0xfc,0x1d,0xd3,0x22,0xc4,0x49,0x62,0xb9,0x58,0x2a,0x14,0xe3,0x51,0x12,0x71,0x8e,0x44,0x9a,0x8c,0xf3,0x32,0xa5,0x22,0x89,0x42,0x92,0x29,0xc5,0x25,0xd2,0xff,0x64,0xe2,0xdf,0x2c,0xfb,0x3,0x3e,0xdf,0x35,0x0,0xb0,0x6a,0x3e,0x1,0x7b,0x91,0x2d,0xa8,0x5d,0x63,0x3,0xf6,0x4b,0x27,0x10,0x58,0x74,0xc0,0xe2,0xf7,0x0,0x0,0xf2,0xbb,0x6f,0xc1,0xd4,0x28,0x8,0x3,0x80,0x68,0x83,0xe1,0xcf,0x77,0xff,0xef,0x3f,0xfd,0x47,0xa0,0x25,0x0,0x80,0x66,0x49,0x92,0x71,0x0,0x0,0x5e,0x44,0x24,0x2e,0x54,0xca,0xb3,0x3f,0xc7,0x8,0x0,0x0,0x44,0xa0,0x81,0x2a,0xb0,0x41,0x1b,0xf4,0xc1,0x18,0x2c,0xc0,0x6,0x1c,0xc1,0x5,0xdc,0xc1,0xb,0xfc,0x60,0x36,0x84,0x42,0x24,0xc4,0xc2,0x42,0x10,0x42,0xa,0x64,0x80,0x1c,0x72,0x60,0x29,0xac,0x82,0x42,0x28,0x86,0xcd,0xb0,0x1d,0x2a,0x60,0x2f,0xd4,0x40,0x1d,0x34,0xc0,0x51,0x68,0x86,0x93,0x70,0xe,0x2e,0xc2,0x55,0xb8,0xe,0x3d,0x70,0xf,0xfa,0x61,0x8,0x9e,0xc1,0x28,0xbc,0x81,0x9,0x4,0x41,0xc8,0x8,0x13,0x61,0x21,0xda,0x88,0x1,0x62,0x8a,0x58,0x23,0x8e,0x8,0x17,0x99,0x85,0xf8,0x21,0xc1,0x48,0x4,0x12,0x8b,0x24,0x20,0xc9,0x88,0x14,0x51,0x22,0x4b,0x91,0x35,0x48,0x31,0x52,0x8a,0x54,0x20,0x55,0x48,0x1d,0xf2,0x3d,0x72,0x2,0x39,0x87,0x5c,0x46,0xba,0x91,0x3b,0xc8,0x0,0x32,0x82,0xfc,0x86,0xbc,0x47,0x31,0x94,0x81,0xb2,0x51,0x3d,0xd4,0xc,0xb5,0x43,0xb9,0xa8,0x37,0x1a,0x84,0x46,0xa2,0xb,0xd0,0x64,0x74,0x31,0x9a,0x8f,0x16,0xa0,0x9b,0xd0,0x72,0xb4,0x1a,0x3d,0x8c,0x36,0xa1,0xe7,0xd0,0xab,0x68,0xf,0xda,0x8f,0x3e,0x43,0xc7,0x30,0xc0,0xe8,0x18,0x7,0x33,0xc4,0x6c,0x30,0x2e,0xc6,0xc3,0x42,0xb1,0x38,0x2c,0x9,0x93,0x63,0xcb,0xb1,0x22,0xac,0xc,0xab,0xc6,0x1a,0xb0,0x56,0xac,0x3,0xbb,0x89,0xf5,0x63,0xcf,0xb1,0x77,0x4,0x12,0x81,0x45,0xc0,0x9,0x36,0x4,0x77,0x42,0x20,0x61,0x1e,0x41,0x48,0x58,0x4c,0x58,0x4e,0xd8,0x48,0xa8,0x20,0x1c,0x24,0x34,0x11,0xda,0x9,0x37,0x9,0x3,0x84,0x51,0xc2,0x27,0x22,0x93,0xa8,0x4b,0xb4,0x26,0xba,0x11,0xf9,0xc4,0x18,0x62,0x32,0x31,0x87,0x58,0x48,0x2c,0x23,0xd6,0x12,0x8f,0x13,0x2f,0x10,0x7b,0x88,0x43,0xc4,0x37,0x24,0x12,0x89,0x43,0x32,0x27,0xb9,0x90,0x2,0x49,0xb1,0xa4,0x54,0xd2,0x12,0xd2,0x46,0xd2,0x6e,0x52,0x23,0xe9,0x2c,0xa9,0x9b,0x34,0x48,0x1a,0x23,0x93,0xc9,0xda,0x64,0x6b,0xb2,0x7,0x39,0x94,0x2c,0x20,0x2b,0xc8,0x85,0xe4,0x9d,0xe4,0xc3,0xe4,0x33,0xe4,0x1b,0xe4,0x21,0xf2,0x5b,0xa,0x9d,0x62,0x40,0x71,0xa4,0xf8,0x53,0xe2,0x28,0x52,0xca,0x6a,0x4a,0x19,0xe5,0x10,0xe5,0x34,0xe5,0x6,0x65,0x98,0x32,0x41,0x55,0xa3,0x9a,0x52,0xdd,0xa8,0xa1,0x54,0x11,0x35,0x8f,0x5a,0x42,0xad,0xa1,0xb6,0x52,0xaf,0x51,0x87,0xa8,0x13,0x34,0x75,0x9a,0x39,0xcd,0x83,0x16,0x49,0x4b,0xa5,0xad,0xa2,0x95,0xd3,0x1a,0x68,0x17,0x68,0xf7,0x69,0xaf,0xe8,0x74,0xba,0x11,0xdd,0x95,0x1e,0x4e,0x97,0xd0,0x57,0xd2,0xcb,0xe9,0x47,0xe8,0x97,0xe8,0x3,0xf4,0x77,0xc,0xd,0x86,0x15,0x83,0xc7,0x88,0x67,0x28,0x19,0x9b,0x18,0x7,0x18,0x67,0x19,0x77,0x18,0xaf,0x98,0x4c,0xa6,0x19,0xd3,0x8b,0x19,0xc7,0x54,0x30,0x37,0x31,0xeb,0x98,0xe7,0x99,0xf,0x99,0x6f,0x55,0x58,0x2a,0xb6,0x2a,0x7c,0x15,0x91,0xca,0xa,0x95,0x4a,0x95,0x26,0x95,0x1b,0x2a,0x2f,0x54,0xa9,0xaa,0xa6,0xaa,0xde,0xaa,0xb,0x55,0xf3,0x55,0xcb,0x54,0x8f,0xa9,0x5e,0x53,0x7d,0xae,0x46,0x55,0x33,0x53,0xe3,0xa9,0x9,0xd4,0x96,0xab,0x55,0xaa,0x9d,0x50,0xeb,0x53,0x1b,0x53,0x67,0xa9,0x3b,0xa8,0x87,0xaa,0x67,0xa8,0x6f,0x54,0x3f,0xa4,0x7e,0x59,0xfd,0x89,0x6,0x59,0xc3,0x4c,0xc3,0x4f,0x43,0xa4,0x51,0xa0,0xb1,0x5f,0xe3,0xbc,0xc6,0x20,0xb,0x63,0x19,0xb3,0x78,0x2c,0x21,0x6b,0xd,0xab,0x86,0x75,0x81,0x35,0xc4,0x26,0xb1,0xcd,0xd9,0x7c,0x76,0x2a,0xbb,0x98,0xfd,0x1d,0xbb,0x8b,0x3d,0xaa,0xa9,0xa1,0x39,0x43,0x33,0x4a,0x33,0x57,0xb3,0x52,0xf3,0x94,0x66,0x3f,0x7,0xe3,0x98,0x71,0xf8,0x9c,0x74,0x4e,0x9,0xe7,0x28,0xa7,0x97,0xf3,0x7e,0x8a,0xde,0x14,0xef,0x29,0xe2,0x29,0x1b,0xa6,0x34,0x4c,0xb9,0x31,0x65,0x5c,0x6b,0xaa,0x96,0x97,0x96,0x58,0xab,0x48,0xab,0x51,0xab,0x47,0xeb,0xbd,0x36,0xae,0xed,0xa7,0x9d,0xa6,0xbd,0x45,0xbb,0x59,0xfb,0x81,0xe,0x41,0xc7,0x4a,0x27,0x5c,0x27,0x47,0x67,0x8f,0xce,0x5,0x9d,0xe7,0x53,0xd9,0x53,0xdd,0xa7,0xa,0xa7,0x16,0x4d,0x3d,0x3a,0xf5,0xae,0x2e,0xaa,0x6b,0xa5,0x1b,0xa1,0xbb,0x44,0x77,0xbf,0x6e,0xa7,0xee,0x98,0x9e,0xbe,0x5e,0x80,0x9e,0x4c,0x6f,0xa7,0xde,0x79,0xbd,0xe7,0xfa,0x1c,0x7d,0x2f,0xfd,0x54,0xfd,0x6d,0xfa,0xa7,0xf5,0x47,0xc,0x58,0x6,0xb3,0xc,0x24,0x6,0xdb,0xc,0xce,0x18,0x3c,0xc5,0x35,0x71,0x6f,0x3c,0x1d,0x2f,0xc7,0xdb,0xf1,0x51,0x43,0x5d,0xc3,0x40,0x43,0xa5,0x61,0x95,0x61,0x97,0xe1,0x84,0x91,0xb9,0xd1,0x3c,0xa3,0xd5,0x46,0x8d,0x46,0xf,0x8c,0x69,0xc6,0x5c,0xe3,0x24,0xe3,0x6d,0xc6,0x6d,0xc6,0xa3,0x26,0x6,0x26,0x21,0x26,0x4b,0x4d,0xea,0x4d,0xee,0x9a,0x52,0x4d,0xb9,0xa6,0x29,0xa6,0x3b,0x4c,0x3b,0x4c,0xc7,0xcd,0xcc,0xcd,0xa2,0xcd,0xd6,0x99,0x35,0x9b,0x3d,0x31,0xd7,0x32,0xe7,0x9b,0xe7,0x9b,0xd7,0x9b,0xdf,0xb7,0x60,0x5a,0x78,0x5a,0x2c,0xb6,0xa8,0xb6,0xb8,0x65,0x49,0xb2,0xe4,0x5a,0xa6,0x59,0xee,0xb6,0xbc,0x6e,0x85,0x5a,0x39,0x59,0xa5,0x58,0x55,0x5a,0x5d,0xb3,0x46,0xad,0x9d,0xad,0x25,0xd6,0xbb,0xad,0xbb,0xa7,0x11,0xa7,0xb9,0x4e,0x93,0x4e,0xab,0x9e,0xd6,0x67,0xc3,0xb0,0xf1,0xb6,0xc9,0xb6,0xa9,0xb7,0x19,0xb0,0xe5,0xd8,0x6,0xdb,0xae,0xb6,0x6d,0xb6,0x7d,0x61,0x67,0x62,0x17,0x67,0xb7,0xc5,0xae,0xc3,0xee,0x93,0xbd,0x93,0x7d,0xba,0x7d,0x8d,0xfd,0x3d,0x7,0xd,0x87,0xd9,0xe,0xab,0x1d,0x5a,0x1d,0x7e,0x73,0xb4,0x72,0x14,0x3a,0x56,0x3a,0xde,0x9a,0xce,0x9c,0xee,0x3f,0x7d,0xc5,0xf4,0x96,0xe9,0x2f,0x67,0x58,0xcf,0x10,0xcf,0xd8,0x33,0xe3,0xb6,0x13,0xcb,0x29,0xc4,0x69,0x9d,0x53,0x9b,0xd3,0x47,0x67,0x17,0x67,0xb9,0x73,0x83,0xf3,0x88,0x8b,0x89,0x4b,0x82,0xcb,0x2e,0x97,0x3e,0x2e,0x9b,0x1b,0xc6,0xdd,0xc8,0xbd,0xe4,0x4a,0x74,0xf5,0x71,0x5d,0xe1,0x7a,0xd2,0xf5,0x9d,0x9b,0xb3,0x9b,0xc2,0xed,0xa8,0xdb,0xaf,0xee,0x36,0xee,0x69,0xee,0x87,0xdc,0x9f,0xcc,0x34,0x9f,0x29,0x9e,0x59,0x33,0x73,0xd0,0xc3,0xc8,0x43,0xe0,0x51,0xe5,0xd1,0x3f,0xb,0x9f,0x95,0x30,0x6b,0xdf,0xac,0x7e,0x4f,0x43,0x4f,0x81,0x67,0xb5,0xe7,0x23,0x2f,0x63,0x2f,0x91,0x57,0xad,0xd7,0xb0,0xb7,0xa5,0x77,0xaa,0xf7,0x61,0xef,0x17,0x3e,0xf6,0x3e,0x72,0x9f,0xe3,0x3e,0xe3,0x3c,0x37,0xde,0x32,0xde,0x59,0x5f,0xcc,0x37,0xc0,0xb7,0xc8,0xb7,0xcb,0x4f,0xc3,0x6f,0x9e,0x5f,0x85,0xdf,0x43,0x7f,0x23,0xff,0x64,0xff,0x7a,0xff,0xd1,0x0,0xa7,0x80,0x25,0x1,0x67,0x3,0x89,0x81,0x41,0x81,0x5b,0x2,0xfb,0xf8,0x7a,0x7c,0x21,0xbf,0x8e,0x3f,0x3a,0xdb,0x65,0xf6,0xb2,0xd9,0xed,0x41,0x8c,0xa0,0xb9,0x41,0x15,0x41,0x8f,0x82,0xad,0x82,0xe5,0xc1,0xad,0x21,0x68,0xc8,0xec,0x90,0xad,0x21,0xf7,0xe7,0x98,0xce,0x91,0xce,0x69,0xe,0x85,0x50,0x7e,0xe8,0xd6,0xd0,0x7,0x61,0xe6,0x61,0x8b,0xc3,0x7e,0xc,0x27,0x85,0x87,0x85,0x57,0x86,0x3f,0x8e,0x70,0x88,0x58,0x1a,0xd1,0x31,0x97,0x35,0x77,0xd1,0xdc,0x43,0x73,0xdf,0x44,0xfa,0x44,0x96,0x44,0xde,0x9b,0x67,0x31,0x4f,0x39,0xaf,0x2d,0x4a,0x35,0x2a,0x3e,0xaa,0x2e,0x6a,0x3c,0xda,0x37,0xba,0x34,0xba,0x3f,0xc6,0x2e,0x66,0x59,0xcc,0xd5,0x58,0x9d,0x58,0x49,0x6c,0x4b,0x1c,0x39,0x2e,0x2a,0xae,0x36,0x6e,0x6c,0xbe,0xdf,0xfc,0xed,0xf3,0x87,0xe2,0x9d,0xe2,0xb,0xe3,0x7b,0x17,0x98,0x2f,0xc8,0x5d,0x70,0x79,0xa1,0xce,0xc2,0xf4,0x85,0xa7,0x16,0xa9,0x2e,0x12,0x2c,0x3a,0x96,0x40,0x4c,0x88,0x4e,0x38,0x94,0xf0,0x41,0x10,0x2a,0xa8,0x16,0x8c,0x25,0xf2,0x13,0x77,0x25,0x8e,0xa,0x79,0xc2,0x1d,0xc2,0x67,0x22,0x2f,0xd1,0x36,0xd1,0x88,0xd8,0x43,0x5c,0x2a,0x1e,0x4e,0xf2,0x48,0x2a,0x4d,0x7a,0x92,0xec,0x91,0xbc,0x35,0x79,0x24,0xc5,0x33,0xa5,0x2c,0xe5,0xb9,0x84,0x27,0xa9,0x90,0xbc,0x4c,0xd,0x4c,0xdd,0x9b,0x3a,0x9e,0x16,0x9a,0x76,0x20,0x6d,0x32,0x3d,0x3a,0xbd,0x31,0x83,0x92,0x91,0x90,0x71,0x42,0xaa,0x21,0x4d,0x93,0xb6,0x67,0xea,0x67,0xe6,0x66,0x76,0xcb,0xac,0x65,0x85,0xb2,0xfe,0xc5,0x6e,0x8b,0xb7,0x2f,0x1e,0x95,0x7,0xc9,0x6b,0xb3,0x90,0xac,0x5,0x59,0x2d,0xa,0xb6,0x42,0xa6,0xe8,0x54,0x5a,0x28,0xd7,0x2a,0x7,0xb2,0x67,0x65,0x57,0x66,0xbf,0xcd,0x89,0xca,0x39,0x96,0xab,0x9e,0x2b,0xcd,0xed,0xcc,0xb3,0xca,0xdb,0x90,0x37,0x9c,0xef,0x9f,0xff,0xed,0x12,0xc2,0x12,0xe1,0x92,0xb6,0xa5,0x86,0x4b,0x57,0x2d,0x1d,0x58,0xe6,0xbd,0xac,0x6a,0x39,0xb2,0x3c,0x71,0x79,0xdb,0xa,0xe3,0x15,0x5,0x2b,0x86,0x56,0x6,0xac,0x3c,0xb8,0x8a,0xb6,0x2a,0x6d,0xd5,0x4f,0xab,0xed,0x57,0x97,0xae,0x7e,0xbd,0x26,0x7a,0x4d,0x6b,0x81,0x5e,0xc1,0xca,0x82,0xc1,0xb5,0x1,0x6b,0xeb,0xb,0x55,0xa,0xe5,0x85,0x7d,0xeb,0xdc,0xd7,0xed,0x5d,0x4f,0x58,0x2f,0x59,0xdf,0xb5,0x61,0xfa,0x86,0x9d,0x1b,0x3e,0x15,0x89,0x8a,0xae,0x14,0xdb,0x17,0x97,0x15,0x7f,0xd8,0x28,0xdc,0x78,0xe5,0x1b,0x87,0x6f,0xca,0xbf,0x99,0xdc,0x94,0xb4,0xa9,0xab,0xc4,0xb9,0x64,0xcf,0x66,0xd2,0x66,0xe9,0xe6,0xde,0x2d,0x9e,0x5b,0xe,0x96,0xaa,0x97,0xe6,0x97,0xe,0x6e,0xd,0xd9,0xda,0xb4,0xd,0xdf,0x56,0xb4,0xed,0xf5,0xf6,0x45,0xdb,0x2f,0x97,0xcd,0x28,0xdb,0xbb,0x83,0xb6,0x43,0xb9,0xa3,0xbf,0x3c,0xb8,0xbc,0x65,0xa7,0xc9,0xce,0xcd,0x3b,0x3f,0x54,0xa4,0x54,0xf4,0x54,0xfa,0x54,0x36,0xee,0xd2,0xdd,0xb5,0x61,0xd7,0xf8,0x6e,0xd1,0xee,0x1b,0x7b,0xbc,0xf6,0x34,0xec,0xd5,0xdb,0x5b,0xbc,0xf7,0xfd,0x3e,0xc9,0xbe,0xdb,0x55,0x1,0x55,0x4d,0xd5,0x66,0xd5,0x65,0xfb,0x49,0xfb,0xb3,0xf7,0x3f,0xae,0x89,0xaa,0xe9,0xf8,0x96,0xfb,0x6d,0x5d,0xad,0x4e,0x6d,0x71,0xed,0xc7,0x3,0xd2,0x3,0xfd,0x7,0x23,0xe,0xb6,0xd7,0xb9,0xd4,0xd5,0x1d,0xd2,0x3d,0x54,0x52,0x8f,0xd6,0x2b,0xeb,0x47,0xe,0xc7,0x1f,0xbe,0xfe,0x9d,0xef,0x77,0x2d,0xd,0x36,0xd,0x55,0x8d,0x9c,0xc6,0xe2,0x23,0x70,0x44,0x79,0xe4,0xe9,0xf7,0x9,0xdf,0xf7,0x1e,0xd,0x3a,0xda,0x76,0x8c,0x7b,0xac,0xe1,0x7,0xd3,0x1f,0x76,0x1d,0x67,0x1d,0x2f,0x6a,0x42,0x9a,0xf2,0x9a,0x46,0x9b,0x53,0x9a,0xfb,0x5b,0x62,0x5b,0xba,0x4f,0xcc,0x3e,0xd1,0xd6,0xea,0xde,0x7a,0xfc,0x47,0xdb,0x1f,0xf,0x9c,0x34,0x3c,0x59,0x79,0x4a,0xf3,0x54,0xc9,0x69,0xda,0xe9,0x82,0xd3,0x93,0x67,0xf2,0xcf,0x8c,0x9d,0x95,0x9d,0x7d,0x7e,0x2e,0xf9,0xdc,0x60,0xdb,0xa2,0xb6,0x7b,0xe7,0x63,0xce,0xdf,0x6a,0xf,0x6f,0xef,0xba,0x10,0x74,0xe1,0xd2,0x45,0xff,0x8b,0xe7,0x3b,0xbc,0x3b,0xce,0x5c,0xf2,0xb8,0x74,0xf2,0xb2,0xdb,0xe5,0x13,0x57,0xb8,0x57,0x9a,0xaf,0x3a,0x5f,0x6d,0xea,0x74,0xea,0x3c,0xfe,0x93,0xd3,0x4f,0xc7,0xbb,0x9c,0xbb,0x9a,0xae,0xb9,0x5c,0x6b,0xb9,0xee,0x7a,0xbd,0xb5,0x7b,0x66,0xf7,0xe9,0x1b,0x9e,0x37,0xce,0xdd,0xf4,0xbd,0x79,0xf1,0x16,0xff,0xd6,0xd5,0x9e,0x39,0x3d,0xdd,0xbd,0xf3,0x7a,0x6f,0xf7,0xc5,0xf7,0xf5,0xdf,0x16,0xdd,0x7e,0x72,0x27,0xfd,0xce,0xcb,0xbb,0xd9,0x77,0x27,0xee,0xad,0xbc,0x4f,0xbc,0x5f,0xf4,0x40,0xed,0x41,0xd9,0x43,0xdd,0x87,0xd5,0x3f,0x5b,0xfe,0xdc,0xd8,0xef,0xdc,0x7f,0x6a,0xc0,0x77,0xa0,0xf3,0xd1,0xdc,0x47,0xf7,0x6,0x85,0x83,0xcf,0xfe,0x91,0xf5,0x8f,0xf,0x43,0x5,0x8f,0x99,0x8f,0xcb,0x86,0xd,0x86,0xeb,0x9e,0x38,0x3e,0x39,0x39,0xe2,0x3f,0x72,0xfd,0xe9,0xfc,0xa7,0x43,0xcf,0x64,0xcf,0x26,0x9e,0x17,0xfe,0xa2,0xfe,0xcb,0xae,0x17,0x16,0x2f,0x7e,0xf8,0xd5,0xeb,0xd7,0xce,0xd1,0x98,0xd1,0xa1,0x97,0xf2,0x97,0x93,0xbf,0x6d,0x7c,0xa5,0xfd,0xea,0xc0,0xeb,0x19,0xaf,0xdb,0xc6,0xc2,0xc6,0x1e,0xbe,0xc9,0x78,0x33,0x31,0x5e,0xf4,0x56,0xfb,0xed,0xc1,0x77,0xdc,0x77,0x1d,0xef,0xa3,0xdf,0xf,0x4f,0xe4,0x7c,0x20,0x7f,0x28,0xff,0x68,0xf9,0xb1,0xf5,0x53,0xd0,0xa7,0xfb,0x93,0x19,0x93,0x93,0xff,0x4,0x3,0x98,0xf3,0xfc,0xef,0x35,0x94,0x82,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xa,0x14,0x3,0x2,0x26,0x58,0xa,0x85,0x15,0x0,0x0,0x1,0xc5,0x49,0x44,0x41,0x54,0x48,0xc7,0xad,0x95,0x4b,0x8e,0x13,0x31,0x10,0x40,0x5f,0xd9,0x1d,0x3a,0x62,0x88,0xd2,0x4b,0x12,0x29,0x12,0xdc,0x4,0xb1,0x65,0xc7,0x15,0x90,0x38,0x43,0x8e,0xc0,0x25,0x38,0x7,0xb,0x96,0x2c,0xd8,0xb0,0x9a,0x23,0x8c,0x34,0x22,0x12,0xd2,0x68,0xf8,0x69,0x98,0xc4,0xae,0x62,0x61,0x3b,0xe9,0x30,0x9a,0x6e,0x8f,0x42,0x49,0x25,0xdb,0xad,0xb6,0xeb,0xd5,0xcf,0x16,0xa0,0x1,0x1e,0x1,0x2d,0x30,0xcd,0x73,0xf,0x38,0x8e,0x45,0x81,0x1d,0x70,0xb,0xdc,0x0,0xdb,0xbc,0x56,0x4e,0x90,0x62,0xfc,0xc,0xe8,0x80,0x79,0x9e,0xb7,0x80,0x64,0x2d,0xb2,0xcb,0x86,0x7f,0x2,0x57,0xc0,0xf,0x20,0xfe,0xf,0x80,0x16,0xe8,0x5e,0xbe,0x78,0xf5,0x7a,0xb5,0x7c,0xbe,0xe,0x31,0x74,0x66,0x76,0xef,0x86,0xd9,0x6c,0xce,0xa7,0xcf,0x1f,0x1,0xc3,0xfb,0x6,0xe7,0xdc,0xa0,0x1,0x33,0xcb,0xaa,0xa8,0x2a,0x22,0xf2,0xd5,0x7b,0xff,0xe6,0xfc,0xfc,0xcb,0x87,0x2,0x30,0x5,0xe6,0xab,0xe5,0xb3,0xf5,0xd5,0xf5,0xb7,0x2e,0x84,0x1d,0x43,0x0,0xa0,0x84,0xb0,0x45,0x35,0xe2,0xfd,0xa4,0x1a,0x40,0x55,0x51,0x8d,0x0,0x8b,0xb6,0x9d,0xbe,0x7,0x96,0x47,0x29,0x8,0x71,0x57,0x61,0xbc,0x88,0x20,0xe2,0xf0,0xde,0xe1,0x9c,0xaf,0x0,0x28,0x59,0x32,0x62,0xc,0xc4,0x18,0x17,0xfd,0x14,0x78,0xa0,0x4d,0x84,0xe3,0xe9,0x2c,0x80,0x22,0x2,0x38,0x44,0x86,0x23,0x20,0x62,0xa8,0x82,0x73,0x64,0x10,0xb9,0x53,0x3,0xe,0x10,0x33,0xa8,0x71,0xde,0x2c,0x1d,0x9a,0xc6,0xa4,0xe3,0xff,0x27,0xef,0x4b,0x14,0xfa,0x75,0xdb,0x14,0x50,0xcd,0xb9,0x1a,0x13,0xad,0x4a,0xd1,0x5d,0x88,0xfb,0xd6,0x4d,0xef,0x73,0x8f,0x72,0xf0,0x38,0x54,0xd9,0x17,0x96,0x8c,0x84,0xe0,0xd0,0x1,0xa5,0x10,0x8f,0x1d,0x6d,0xf6,0xff,0x69,0x65,0xa,0x14,0xcc,0xe2,0x7e,0x93,0x59,0x1d,0x40,0xd2,0x14,0xfe,0x43,0x51,0x26,0x0,0x4d,0xae,0x6b,0x65,0x4,0x94,0x54,0xab,0xa5,0xbd,0xac,0xb2,0xd,0xf,0x63,0x7f,0x4f,0x93,0x6f,0xb3,0xdb,0x7f,0xab,0x7c,0xbc,0xad,0xac,0xba,0x6b,0x92,0x46,0x54,0x63,0x3e,0xff,0x18,0x60,0xb,0xfc,0x16,0xd7,0x5c,0x7b,0xd7,0x74,0x21,0x4,0x6c,0x20,0x12,0x85,0xaf,0xe4,0xb4,0xe,0x20,0xb5,0xb8,0x99,0xe5,0x8e,0x90,0x4d,0x1f,0xe0,0xf,0xf0,0x7d,0xb3,0xb9,0x78,0xb7,0x78,0xba,0x5a,0x87,0x18,0xba,0xa1,0x62,0x78,0x72,0x36,0x63,0x32,0x99,0x0,0xe0,0xbd,0x7f,0xc0,0x4d,0x18,0x89,0x31,0x2,0x5c,0x82,0xbc,0x3d,0x5c,0x69,0xf0,0xf8,0x84,0xc7,0xe8,0x6,0x8,0xa7,0x3e,0x46,0xdb,0x3c,0xf,0xc0,0xaf,0x7,0x3e,0xc7,0x27,0xbd,0x84,0x0,0x7f,0x1,0xeb,0x59,0x47,0x10,0x4f,0x87,0xd2,0x63,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char option_button_normal_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x77,0x0,0x7d,0x59,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xdd,0x0,0xdd,0x0,0xdd,0xf5,0x15,0x8,0x9d,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x10,0x16,0x11,0x12,0x1,0x22,0x6f,0x8b,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0xd5,0x49,0x44,0x41,0x54,0x48,0x89,0xed,0x95,0xb1,0x6e,0xc2,0x50,0xc,0x45,0xcf,0xa3,0x96,0x6a,0x55,0x19,0x3a,0xbc,0xe9,0x3d,0xc1,0x17,0xa4,0xed,0x8f,0x91,0xfe,0xc,0xfc,0x18,0x85,0x99,0x5,0x85,0x29,0x3,0x43,0x7,0x47,0x72,0x95,0xe,0x24,0x6b,0x8b,0x40,0x81,0x25,0x77,0xb4,0x2c,0xdf,0x63,0x59,0xba,0xe,0xc0,0xb,0xf0,0xa,0x14,0xc0,0x13,0x10,0x18,0x57,0x1d,0xf0,0x3,0x7c,0x3,0x27,0xe9,0xcd,0xdf,0x81,0x39,0xa0,0x77,0x2,0x30,0xe0,0x0,0x7c,0x9,0xe7,0xcd,0x17,0x6f,0xe5,0x47,0x99,0x53,0x5e,0x8a,0xc8,0xa8,0x0,0xee,0xde,0xd5,0xc7,0x7a,0xbd,0xdd,0x6d,0x2,0xb0,0x17,0x40,0x80,0xe7,0x9c,0x72,0x65,0x66,0x98,0xd9,0xbf,0x43,0x62,0x8c,0x34,0x4d,0x73,0x15,0x80,0xaa,0x86,0x9c,0x72,0xb5,0xdd,0x6d,0x3e,0x1,0x99,0xf5,0xf5,0x20,0x22,0x17,0x99,0xdf,0x2a,0x33,0x43,0x44,0xa0,0x3f,0xf5,0xec,0xef,0xf6,0xf1,0x35,0x1,0x4c,0x0,0x13,0xc0,0x0,0xd0,0xb9,0x3b,0xaa,0x3a,0xba,0xa1,0xaa,0xe2,0xee,0x70,0x8e,0x64,0x4,0x70,0xa0,0xad,0x8f,0xf5,0x2a,0xa7,0xbc,0x2c,0x8a,0xe2,0xa2,0x28,0x8e,0x31,0x5e,0x5,0x30,0x44,0x31,0xd0,0x2,0x1e,0x80,0xc4,0x3,0x9f,0x51,0xe0,0xc1,0xef,0xf8,0x17,0x29,0x4,0x47,0x72,0x2c,0x4,0x5,0x25,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x77,0x0,0x7d,0x59,0x0,0x0,0xa,0x45,0x69,0x43,0x43,0x50,0x49,0x43,0x43,0x20,0x70,0x72,0x6f,0x66,0x69,0x6c,0x65,0x0,0x0,0x78,0xda,0x9d,0x53,0x67,0x54,0x53,0xe9,0x16,0x3d,0xf7,0xde,0xf4,0x42,0x4b,0x88,0x80,0x94,0x4b,0x6f,0x52,0x15,0x8,0x20,0x52,0x42,0x8b,0x80,0x14,0x91,0x26,0x2a,0x21,0x9,0x10,0x4a,0x88,0x21,0xa1,0xd9,0x15,0x51,0xc1,0x11,0x45,0x45,0x4,0x1b,0xc8,0xa0,0x88,0x3,0x8e,0x8e,0x80,0x8c,0x15,0x51,0x2c,0xc,0x8a,0xa,0xd8,0x7,0xe4,0x21,0xa2,0x8e,0x83,0xa3,0x88,0x8a,0xca,0xfb,0xe1,0x7b,0xa3,0x6b,0xd6,0xbc,0xf7,0xe6,0xcd,0xfe,0xb5,0xd7,0x3e,0xe7,0xac,0xf3,0x9d,0xb3,0xcf,0x7,0xc0,0x8,0xc,0x96,0x48,0x33,0x51,0x35,0x80,0xc,0xa9,0x42,0x1e,0x11,0xe0,0x83,0xc7,0xc4,0xc6,0xe1,0xe4,0x2e,0x40,0x81,0xa,0x24,0x70,0x0,0x10,0x8,0xb3,0x64,0x21,0x73,0xfd,0x23,0x1,0x0,0xf8,0x7e,0x3c,0x3c,0x2b,0x22,0xc0,0x7,0xbe,0x0,0x1,0x78,0xd3,0xb,0x8,0x0,0xc0,0x4d,0x9b,0xc0,0x30,0x1c,0x87,0xff,0xf,0xea,0x42,0x99,0x5c,0x1,0x80,0x84,0x1,0xc0,0x74,0x91,0x38,0x4b,0x8,0x80,0x14,0x0,0x40,0x7a,0x8e,0x42,0xa6,0x0,0x40,0x46,0x1,0x80,0x9d,0x98,0x26,0x53,0x0,0xa0,0x4,0x0,0x60,0xcb,0x63,0x62,0xe3,0x0,0x50,0x2d,0x0,0x60,0x27,0x7f,0xe6,0xd3,0x0,0x80,0x9d,0xf8,0x99,0x7b,0x1,0x0,0x5b,0x94,0x21,0x15,0x1,0xa0,0x91,0x0,0x20,0x13,0x65,0x88,0x44,0x0,0x68,0x3b,0x0,0xac,0xcf,0x56,0x8a,0x45,0x0,0x58,0x30,0x0,0x14,0x66,0x4b,0xc4,0x39,0x0,0xd8,0x2d,0x0,0x30,0x49,0x57,0x66,0x48,0x0,0xb0,0xb7,0x0,0xc0,0xce,0x10,0xb,0xb2,0x0,0x8,0xc,0x0,0x30,0x51,0x88,0x85,0x29,0x0,0x4,0x7b,0x0,0x60,0xc8,0x23,0x23,0x78,0x0,0x84,0x99,0x0,0x14,0x46,0xf2,0x57,0x3c,0xf1,0x2b,0xae,0x10,0xe7,0x2a,0x0,0x0,0x78,0x99,0xb2,0x3c,0xb9,0x24,0x39,0x45,0x81,0x5b,0x8,0x2d,0x71,0x7,0x57,0x57,0x2e,0x1e,0x28,0xce,0x49,0x17,0x2b,0x14,0x36,0x61,0x2,0x61,0x9a,0x40,0x2e,0xc2,0x79,0x99,0x19,0x32,0x81,0x34,0xf,0xe0,0xf3,0xcc,0x0,0x0,0xa0,0x91,0x15,0x11,0xe0,0x83,0xf3,0xfd,0x78,0xce,0xe,0xae,0xce,0xce,0x36,0x8e,0xb6,0xe,0x5f,0x2d,0xea,0xbf,0x6,0xff,0x22,0x62,0x62,0xe3,0xfe,0xe5,0xcf,0xab,0x70,0x40,0x0,0x0,0xe1,0x74,0x7e,0xd1,0xfe,0x2c,0x2f,0xb3,0x1a,0x80,0x3b,0x6,0x80,0x6d,0xfe,0xa2,0x25,0xee,0x4,0x68,0x5e,0xb,0xa0,0x75,0xf7,0x8b,0x66,0xb2,0xf,0x40,0xb5,0x0,0xa0,0xe9,0xda,0x57,0xf3,0x70,0xf8,0x7e,0x3c,0x3c,0x45,0xa1,0x90,0xb9,0xd9,0xd9,0xe5,0xe4,0xe4,0xd8,0x4a,0xc4,0x42,0x5b,0x61,0xca,0x57,0x7d,0xfe,0x67,0xc2,0x5f,0xc0,0x57,0xfd,0x6c,0xf9,0x7e,0x3c,0xfc,0xf7,0xf5,0xe0,0xbe,0xe2,0x24,0x81,0x32,0x5d,0x81,0x47,0x4,0xf8,0xe0,0xc2,0xcc,0xf4,0x4c,0xa5,0x1c,0xcf,0x92,0x9,0x84,0x62,0xdc,0xe6,0x8f,0x47,0xfc,0xb7,0xb,0xff,0xfc,0x1d,0xd3,0x22,0xc4,0x49,0x62,0xb9,0x58,0x2a,0x14,0xe3,0x51,0x12,0x71,0x8e,0x44,0x9a,0x8c,0xf3,0x32,0xa5,0x22,0x89,0x42,0x92,0x29,0xc5,0x25,0xd2,0xff,0x64,0xe2,0xdf,0x2c,0xfb,0x3,0x3e,0xdf,0x35,0x0,0xb0,0x6a,0x3e,0x1,0x7b,0x91,0x2d,0xa8,0x5d,0x63,0x3,0xf6,0x4b,0x27,0x10,0x58,0x74,0xc0,0xe2,0xf7,0x0,0x0,0xf2,0xbb,0x6f,0xc1,0xd4,0x28,0x8,0x3,0x80,0x68,0x83,0xe1,0xcf,0x77,0xff,0xef,0x3f,0xfd,0x47,0xa0,0x25,0x0,0x80,0x66,0x49,0x92,0x71,0x0,0x0,0x5e,0x44,0x24,0x2e,0x54,0xca,0xb3,0x3f,0xc7,0x8,0x0,0x0,0x44,0xa0,0x81,0x2a,0xb0,0x41,0x1b,0xf4,0xc1,0x18,0x2c,0xc0,0x6,0x1c,0xc1,0x5,0xdc,0xc1,0xb,0xfc,0x60,0x36,0x84,0x42,0x24,0xc4,0xc2,0x42,0x10,0x42,0xa,0x64,0x80,0x1c,0x72,0x60,0x29,0xac,0x82,0x42,0x28,0x86,0xcd,0xb0,0x1d,0x2a,0x60,0x2f,0xd4,0x40,0x1d,0x34,0xc0,0x51,0x68,0x86,0x93,0x70,0xe,0x2e,0xc2,0x55,0xb8,0xe,0x3d,0x70,0xf,0xfa,0x61,0x8,0x9e,0xc1,0x28,0xbc,0x81,0x9,0x4,0x41,0xc8,0x8,0x13,0x61,0x21,0xda,0x88,0x1,0x62,0x8a,0x58,0x23,0x8e,0x8,0x17,0x99,0x85,0xf8,0x21,0xc1,0x48,0x4,0x12,0x8b,0x24,0x20,0xc9,0x88,0x14,0x51,0x22,0x4b,0x91,0x35,0x48,0x31,0x52,0x8a,0x54,0x20,0x55,0x48,0x1d,0xf2,0x3d,0x72,0x2,0x39,0x87,0x5c,0x46,0xba,0x91,0x3b,0xc8,0x0,0x32,0x82,0xfc,0x86,0xbc,0x47,0x31,0x94,0x81,0xb2,0x51,0x3d,0xd4,0xc,0xb5,0x43,0xb9,0xa8,0x37,0x1a,0x84,0x46,0xa2,0xb,0xd0,0x64,0x74,0x31,0x9a,0x8f,0x16,0xa0,0x9b,0xd0,0x72,0xb4,0x1a,0x3d,0x8c,0x36,0xa1,0xe7,0xd0,0xab,0x68,0xf,0xda,0x8f,0x3e,0x43,0xc7,0x30,0xc0,0xe8,0x18,0x7,0x33,0xc4,0x6c,0x30,0x2e,0xc6,0xc3,0x42,0xb1,0x38,0x2c,0x9,0x93,0x63,0xcb,0xb1,0x22,0xac,0xc,0xab,0xc6,0x1a,0xb0,0x56,0xac,0x3,0xbb,0x89,0xf5,0x63,0xcf,0xb1,0x77,0x4,0x12,0x81,0x45,0xc0,0x9,0x36,0x4,0x77,0x42,0x20,0x61,0x1e,0x41,0x48,0x58,0x4c,0x58,0x4e,0xd8,0x48,0xa8,0x20,0x1c,0x24,0x34,0x11,0xda,0x9,0x37,0x9,0x3,0x84,0x51,0xc2,0x27,0x22,0x93,0xa8,0x4b,0xb4,0x26,0xba,0x11,0xf9,0xc4,0x18,0x62,0x32,0x31,0x87,0x58,0x48,0x2c,0x23,0xd6,0x12,0x8f,0x13,0x2f,0x10,0x7b,0x88,0x43,0xc4,0x37,0x24,0x12,0x89,0x43,0x32,0x27,0xb9,0x90,0x2,0x49,0xb1,0xa4,0x54,0xd2,0x12,0xd2,0x46,0xd2,0x6e,0x52,0x23,0xe9,0x2c,0xa9,0x9b,0x34,0x48,0x1a,0x23,0x93,0xc9,0xda,0x64,0x6b,0xb2,0x7,0x39,0x94,0x2c,0x20,0x2b,0xc8,0x85,0xe4,0x9d,0xe4,0xc3,0xe4,0x33,0xe4,0x1b,0xe4,0x21,0xf2,0x5b,0xa,0x9d,0x62,0x40,0x71,0xa4,0xf8,0x53,0xe2,0x28,0x52,0xca,0x6a,0x4a,0x19,0xe5,0x10,0xe5,0x34,0xe5,0x6,0x65,0x98,0x32,0x41,0x55,0xa3,0x9a,0x52,0xdd,0xa8,0xa1,0x54,0x11,0x35,0x8f,0x5a,0x42,0xad,0xa1,0xb6,0x52,0xaf,0x51,0x87,0xa8,0x13,0x34,0x75,0x9a,0x39,0xcd,0x83,0x16,0x49,0x4b,0xa5,0xad,0xa2,0x95,0xd3,0x1a,0x68,0x17,0x68,0xf7,0x69,0xaf,0xe8,0x74,0xba,0x11,0xdd,0x95,0x1e,0x4e,0x97,0xd0,0x57,0xd2,0xcb,0xe9,0x47,0xe8,0x97,0xe8,0x3,0xf4,0x77,0xc,0xd,0x86,0x15,0x83,0xc7,0x88,0x67,0x28,0x19,0x9b,0x18,0x7,0x18,0x67,0x19,0x77,0x18,0xaf,0x98,0x4c,0xa6,0x19,0xd3,0x8b,0x19,0xc7,0x54,0x30,0x37,0x31,0xeb,0x98,0xe7,0x99,0xf,0x99,0x6f,0x55,0x58,0x2a,0xb6,0x2a,0x7c,0x15,0x91,0xca,0xa,0x95,0x4a,0x95,0x26,0x95,0x1b,0x2a,0x2f,0x54,0xa9,0xaa,0xa6,0xaa,0xde,0xaa,0xb,0x55,0xf3,0x55,0xcb,0x54,0x8f,0xa9,0x5e,0x53,0x7d,0xae,0x46,0x55,0x33,0x53,0xe3,0xa9,0x9,0xd4,0x96,0xab,0x55,0xaa,0x9d,0x50,0xeb,0x53,0x1b,0x53,0x67,0xa9,0x3b,0xa8,0x87,0xaa,0x67,0xa8,0x6f,0x54,0x3f,0xa4,0x7e,0x59,0xfd,0x89,0x6,0x59,0xc3,0x4c,0xc3,0x4f,0x43,0xa4,0x51,0xa0,0xb1,0x5f,0xe3,0xbc,0xc6,0x20,0xb,0x63,0x19,0xb3,0x78,0x2c,0x21,0x6b,0xd,0xab,0x86,0x75,0x81,0x35,0xc4,0x26,0xb1,0xcd,0xd9,0x7c,0x76,0x2a,0xbb,0x98,0xfd,0x1d,0xbb,0x8b,0x3d,0xaa,0xa9,0xa1,0x39,0x43,0x33,0x4a,0x33,0x57,0xb3,0x52,0xf3,0x94,0x66,0x3f,0x7,0xe3,0x98,0x71,0xf8,0x9c,0x74,0x4e,0x9,0xe7,0x28,0xa7,0x97,0xf3,0x7e,0x8a,0xde,0x14,0xef,0x29,0xe2,0x29,0x1b,0xa6,0x34,0x4c,0xb9,0x31,0x65,0x5c,0x6b,0xaa,0x96,0x97,0x96,0x58,0xab,0x48,0xab,0x51,0xab,0x47,0xeb,0xbd,0x36,0xae,0xed,0xa7,0x9d,0xa6,0xbd,0x45,0xbb,0x59,0xfb,0x81,0xe,0x41,0xc7,0x4a,0x27,0x5c,0x27,0x47,0x67,0x8f,0xce,0x5,0x9d,0xe7,0x53,0xd9,0x53,0xdd,0xa7,0xa,0xa7,0x16,0x4d,0x3d,0x3a,0xf5,0xae,0x2e,0xaa,0x6b,0xa5,0x1b,0xa1,0xbb,0x44,0x77,0xbf,0x6e,0xa7,0xee,0x98,0x9e,0xbe,0x5e,0x80,0x9e,0x4c,0x6f,0xa7,0xde,0x79,0xbd,0xe7,0xfa,0x1c,0x7d,0x2f,0xfd,0x54,0xfd,0x6d,0xfa,0xa7,0xf5,0x47,0xc,0x58,0x6,0xb3,0xc,0x24,0x6,0xdb,0xc,0xce,0x18,0x3c,0xc5,0x35,0x71,0x6f,0x3c,0x1d,0x2f,0xc7,0xdb,0xf1,0x51,0x43,0x5d,0xc3,0x40,0x43,0xa5,0x61,0x95,0x61,0x97,0xe1,0x84,0x91,0xb9,0xd1,0x3c,0xa3,0xd5,0x46,0x8d,0x46,0xf,0x8c,0x69,0xc6,0x5c,0xe3,0x24,0xe3,0x6d,0xc6,0x6d,0xc6,0xa3,0x26,0x6,0x26,0x21,0x26,0x4b,0x4d,0xea,0x4d,0xee,0x9a,0x52,0x4d,0xb9,0xa6,0x29,0xa6,0x3b,0x4c,0x3b,0x4c,0xc7,0xcd,0xcc,0xcd,0xa2,0xcd,0xd6,0x99,0x35,0x9b,0x3d,0x31,0xd7,0x32,0xe7,0x9b,0xe7,0x9b,0xd7,0x9b,0xdf,0xb7,0x60,0x5a,0x78,0x5a,0x2c,0xb6,0xa8,0xb6,0xb8,0x65,0x49,0xb2,0xe4,0x5a,0xa6,0x59,0xee,0xb6,0xbc,0x6e,0x85,0x5a,0x39,0x59,0xa5,0x58,0x55,0x5a,0x5d,0xb3,0x46,0xad,0x9d,0xad,0x25,0xd6,0xbb,0xad,0xbb,0xa7,0x11,0xa7,0xb9,0x4e,0x93,0x4e,0xab,0x9e,0xd6,0x67,0xc3,0xb0,0xf1,0xb6,0xc9,0xb6,0xa9,0xb7,0x19,0xb0,0xe5,0xd8,0x6,0xdb,0xae,0xb6,0x6d,0xb6,0x7d,0x61,0x67,0x62,0x17,0x67,0xb7,0xc5,0xae,0xc3,0xee,0x93,0xbd,0x93,0x7d,0xba,0x7d,0x8d,0xfd,0x3d,0x7,0xd,0x87,0xd9,0xe,0xab,0x1d,0x5a,0x1d,0x7e,0x73,0xb4,0x72,0x14,0x3a,0x56,0x3a,0xde,0x9a,0xce,0x9c,0xee,0x3f,0x7d,0xc5,0xf4,0x96,0xe9,0x2f,0x67,0x58,0xcf,0x10,0xcf,0xd8,0x33,0xe3,0xb6,0x13,0xcb,0x29,0xc4,0x69,0x9d,0x53,0x9b,0xd3,0x47,0x67,0x17,0x67,0xb9,0x73,0x83,0xf3,0x88,0x8b,0x89,0x4b,0x82,0xcb,0x2e,0x97,0x3e,0x2e,0x9b,0x1b,0xc6,0xdd,0xc8,0xbd,0xe4,0x4a,0x74,0xf5,0x71,0x5d,0xe1,0x7a,0xd2,0xf5,0x9d,0x9b,0xb3,0x9b,0xc2,0xed,0xa8,0xdb,0xaf,0xee,0x36,0xee,0x69,0xee,0x87,0xdc,0x9f,0xcc,0x34,0x9f,0x29,0x9e,0x59,0x33,0x73,0xd0,0xc3,0xc8,0x43,0xe0,0x51,0xe5,0xd1,0x3f,0xb,0x9f,0x95,0x30,0x6b,0xdf,0xac,0x7e,0x4f,0x43,0x4f,0x81,0x67,0xb5,0xe7,0x23,0x2f,0x63,0x2f,0x91,0x57,0xad,0xd7,0xb0,0xb7,0xa5,0x77,0xaa,0xf7,0x61,0xef,0x17,0x3e,0xf6,0x3e,0x72,0x9f,0xe3,0x3e,0xe3,0x3c,0x37,0xde,0x32,0xde,0x59,0x5f,0xcc,0x37,0xc0,0xb7,0xc8,0xb7,0xcb,0x4f,0xc3,0x6f,0x9e,0x5f,0x85,0xdf,0x43,0x7f,0x23,0xff,0x64,0xff,0x7a,0xff,0xd1,0x0,0xa7,0x80,0x25,0x1,0x67,0x3,0x89,0x81,0x41,0x81,0x5b,0x2,0xfb,0xf8,0x7a,0x7c,0x21,0xbf,0x8e,0x3f,0x3a,0xdb,0x65,0xf6,0xb2,0xd9,0xed,0x41,0x8c,0xa0,0xb9,0x41,0x15,0x41,0x8f,0x82,0xad,0x82,0xe5,0xc1,0xad,0x21,0x68,0xc8,0xec,0x90,0xad,0x21,0xf7,0xe7,0x98,0xce,0x91,0xce,0x69,0xe,0x85,0x50,0x7e,0xe8,0xd6,0xd0,0x7,0x61,0xe6,0x61,0x8b,0xc3,0x7e,0xc,0x27,0x85,0x87,0x85,0x57,0x86,0x3f,0x8e,0x70,0x88,0x58,0x1a,0xd1,0x31,0x97,0x35,0x77,0xd1,0xdc,0x43,0x73,0xdf,0x44,0xfa,0x44,0x96,0x44,0xde,0x9b,0x67,0x31,0x4f,0x39,0xaf,0x2d,0x4a,0x35,0x2a,0x3e,0xaa,0x2e,0x6a,0x3c,0xda,0x37,0xba,0x34,0xba,0x3f,0xc6,0x2e,0x66,0x59,0xcc,0xd5,0x58,0x9d,0x58,0x49,0x6c,0x4b,0x1c,0x39,0x2e,0x2a,0xae,0x36,0x6e,0x6c,0xbe,0xdf,0xfc,0xed,0xf3,0x87,0xe2,0x9d,0xe2,0xb,0xe3,0x7b,0x17,0x98,0x2f,0xc8,0x5d,0x70,0x79,0xa1,0xce,0xc2,0xf4,0x85,0xa7,0x16,0xa9,0x2e,0x12,0x2c,0x3a,0x96,0x40,0x4c,0x88,0x4e,0x38,0x94,0xf0,0x41,0x10,0x2a,0xa8,0x16,0x8c,0x25,0xf2,0x13,0x77,0x25,0x8e,0xa,0x79,0xc2,0x1d,0xc2,0x67,0x22,0x2f,0xd1,0x36,0xd1,0x88,0xd8,0x43,0x5c,0x2a,0x1e,0x4e,0xf2,0x48,0x2a,0x4d,0x7a,0x92,0xec,0x91,0xbc,0x35,0x79,0x24,0xc5,0x33,0xa5,0x2c,0xe5,0xb9,0x84,0x27,0xa9,0x90,0xbc,0x4c,0xd,0x4c,0xdd,0x9b,0x3a,0x9e,0x16,0x9a,0x76,0x20,0x6d,0x32,0x3d,0x3a,0xbd,0x31,0x83,0x92,0x91,0x90,0x71,0x42,0xaa,0x21,0x4d,0x93,0xb6,0x67,0xea,0x67,0xe6,0x66,0x76,0xcb,0xac,0x65,0x85,0xb2,0xfe,0xc5,0x6e,0x8b,0xb7,0x2f,0x1e,0x95,0x7,0xc9,0x6b,0xb3,0x90,0xac,0x5,0x59,0x2d,0xa,0xb6,0x42,0xa6,0xe8,0x54,0x5a,0x28,0xd7,0x2a,0x7,0xb2,0x67,0x65,0x57,0x66,0xbf,0xcd,0x89,0xca,0x39,0x96,0xab,0x9e,0x2b,0xcd,0xed,0xcc,0xb3,0xca,0xdb,0x90,0x37,0x9c,0xef,0x9f,0xff,0xed,0x12,0xc2,0x12,0xe1,0x92,0xb6,0xa5,0x86,0x4b,0x57,0x2d,0x1d,0x58,0xe6,0xbd,0xac,0x6a,0x39,0xb2,0x3c,0x71,0x79,0xdb,0xa,0xe3,0x15,0x5,0x2b,0x86,0x56,0x6,0xac,0x3c,0xb8,0x8a,0xb6,0x2a,0x6d,0xd5,0x4f,0xab,0xed,0x57,0x97,0xae,0x7e,0xbd,0x26,0x7a,0x4d,0x6b,0x81,0x5e,0xc1,0xca,0x82,0xc1,0xb5,0x1,0x6b,0xeb,0xb,0x55,0xa,0xe5,0x85,0x7d,0xeb,0xdc,0xd7,0xed,0x5d,0x4f,0x58,0x2f,0x59,0xdf,0xb5,0x61,0xfa,0x86,0x9d,0x1b,0x3e,0x15,0x89,0x8a,0xae,0x14,0xdb,0x17,0x97,0x15,0x7f,0xd8,0x28,0xdc,0x78,0xe5,0x1b,0x87,0x6f,0xca,0xbf,0x99,0xdc,0x94,0xb4,0xa9,0xab,0xc4,0xb9,0x64,0xcf,0x66,0xd2,0x66,0xe9,0xe6,0xde,0x2d,0x9e,0x5b,0xe,0x96,0xaa,0x97,0xe6,0x97,0xe,0x6e,0xd,0xd9,0xda,0xb4,0xd,0xdf,0x56,0xb4,0xed,0xf5,0xf6,0x45,0xdb,0x2f,0x97,0xcd,0x28,0xdb,0xbb,0x83,0xb6,0x43,0xb9,0xa3,0xbf,0x3c,0xb8,0xbc,0x65,0xa7,0xc9,0xce,0xcd,0x3b,0x3f,0x54,0xa4,0x54,0xf4,0x54,0xfa,0x54,0x36,0xee,0xd2,0xdd,0xb5,0x61,0xd7,0xf8,0x6e,0xd1,0xee,0x1b,0x7b,0xbc,0xf6,0x34,0xec,0xd5,0xdb,0x5b,0xbc,0xf7,0xfd,0x3e,0xc9,0xbe,0xdb,0x55,0x1,0x55,0x4d,0xd5,0x66,0xd5,0x65,0xfb,0x49,0xfb,0xb3,0xf7,0x3f,0xae,0x89,0xaa,0xe9,0xf8,0x96,0xfb,0x6d,0x5d,0xad,0x4e,0x6d,0x71,0xed,0xc7,0x3,0xd2,0x3,0xfd,0x7,0x23,0xe,0xb6,0xd7,0xb9,0xd4,0xd5,0x1d,0xd2,0x3d,0x54,0x52,0x8f,0xd6,0x2b,0xeb,0x47,0xe,0xc7,0x1f,0xbe,0xfe,0x9d,0xef,0x77,0x2d,0xd,0x36,0xd,0x55,0x8d,0x9c,0xc6,0xe2,0x23,0x70,0x44,0x79,0xe4,0xe9,0xf7,0x9,0xdf,0xf7,0x1e,0xd,0x3a,0xda,0x76,0x8c,0x7b,0xac,0xe1,0x7,0xd3,0x1f,0x76,0x1d,0x67,0x1d,0x2f,0x6a,0x42,0x9a,0xf2,0x9a,0x46,0x9b,0x53,0x9a,0xfb,0x5b,0x62,0x5b,0xba,0x4f,0xcc,0x3e,0xd1,0xd6,0xea,0xde,0x7a,0xfc,0x47,0xdb,0x1f,0xf,0x9c,0x34,0x3c,0x59,0x79,0x4a,0xf3,0x54,0xc9,0x69,0xda,0xe9,0x82,0xd3,0x93,0x67,0xf2,0xcf,0x8c,0x9d,0x95,0x9d,0x7d,0x7e,0x2e,0xf9,0xdc,0x60,0xdb,0xa2,0xb6,0x7b,0xe7,0x63,0xce,0xdf,0x6a,0xf,0x6f,0xef,0xba,0x10,0x74,0xe1,0xd2,0x45,0xff,0x8b,0xe7,0x3b,0xbc,0x3b,0xce,0x5c,0xf2,0xb8,0x74,0xf2,0xb2,0xdb,0xe5,0x13,0x57,0xb8,0x57,0x9a,0xaf,0x3a,0x5f,0x6d,0xea,0x74,0xea,0x3c,0xfe,0x93,0xd3,0x4f,0xc7,0xbb,0x9c,0xbb,0x9a,0xae,0xb9,0x5c,0x6b,0xb9,0xee,0x7a,0xbd,0xb5,0x7b,0x66,0xf7,0xe9,0x1b,0x9e,0x37,0xce,0xdd,0xf4,0xbd,0x79,0xf1,0x16,0xff,0xd6,0xd5,0x9e,0x39,0x3d,0xdd,0xbd,0xf3,0x7a,0x6f,0xf7,0xc5,0xf7,0xf5,0xdf,0x16,0xdd,0x7e,0x72,0x27,0xfd,0xce,0xcb,0xbb,0xd9,0x77,0x27,0xee,0xad,0xbc,0x4f,0xbc,0x5f,0xf4,0x40,0xed,0x41,0xd9,0x43,0xdd,0x87,0xd5,0x3f,0x5b,0xfe,0xdc,0xd8,0xef,0xdc,0x7f,0x6a,0xc0,0x77,0xa0,0xf3,0xd1,0xdc,0x47,0xf7,0x6,0x85,0x83,0xcf,0xfe,0x91,0xf5,0x8f,0xf,0x43,0x5,0x8f,0x99,0x8f,0xcb,0x86,0xd,0x86,0xeb,0x9e,0x38,0x3e,0x39,0x39,0xe2,0x3f,0x72,0xfd,0xe9,0xfc,0xa7,0x43,0xcf,0x64,0xcf,0x26,0x9e,0x17,0xfe,0xa2,0xfe,0xcb,0xae,0x17,0x16,0x2f,0x7e,0xf8,0xd5,0xeb,0xd7,0xce,0xd1,0x98,0xd1,0xa1,0x97,0xf2,0x97,0x93,0xbf,0x6d,0x7c,0xa5,0xfd,0xea,0xc0,0xeb,0x19,0xaf,0xdb,0xc6,0xc2,0xc6,0x1e,0xbe,0xc9,0x78,0x33,0x31,0x5e,0xf4,0x56,0xfb,0xed,0xc1,0x77,0xdc,0x77,0x1d,0xef,0xa3,0xdf,0xf,0x4f,0xe4,0x7c,0x20,0x7f,0x28,0xff,0x68,0xf9,0xb1,0xf5,0x53,0xd0,0xa7,0xfb,0x93,0x19,0x93,0x93,0xff,0x4,0x3,0x98,0xf3,0xfc,0xef,0x35,0x94,0x82,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xa,0x14,0x3,0x2,0x10,0x97,0xb0,0x10,0x8c,0x0,0x0,0x1,0xd3,0x49,0x44,0x41,0x54,0x48,0xc7,0xad,0x95,0x5f,0x6e,0xd4,0x30,0x10,0xc6,0x7f,0x63,0x67,0xc9,0x6a,0xb,0x6a,0x24,0x90,0x60,0x57,0x70,0x11,0xc4,0x23,0x27,0xe0,0xa,0x48,0x9c,0x61,0x8f,0xc0,0x25,0x7a,0xe,0x8e,0xc0,0xb,0x48,0xa8,0x77,0x40,0xe5,0x81,0x42,0xf9,0xa7,0xd2,0x8d,0x67,0x86,0x87,0x38,0xd9,0x4,0xd4,0x24,0xab,0x65,0x24,0x2b,0xb6,0xec,0xc9,0x7c,0xfe,0xe6,0x9b,0xb1,0x0,0x5,0x70,0x7,0x28,0x81,0x65,0x9e,0x47,0x20,0x30,0x34,0x3,0x6a,0xe0,0x6,0xb8,0x6,0x76,0x79,0x6d,0x1c,0x61,0x6d,0xf0,0x13,0xa0,0x2,0x4e,0xf3,0xbc,0x4,0x24,0x8f,0xd6,0xea,0x1c,0xf8,0x7,0xf0,0x5,0xf8,0xe,0xe8,0xff,0x0,0x50,0x2,0xd5,0xb3,0xa7,0xcf,0x5f,0x6c,0xd6,0x4f,0xb6,0x49,0x53,0xe5,0x7e,0xbb,0xc3,0xdd,0x93,0x7b,0xbc,0xff,0xf0,0x16,0x70,0x62,0x2c,0x8,0x21,0x8c,0x6,0x70,0xf7,0x3c,0xc,0x33,0x43,0x44,0x2e,0x62,0x8c,0x2f,0xcf,0xcf,0xdf,0xbd,0x69,0x1,0x2c,0x81,0xd3,0xcd,0xa3,0xc7,0xdb,0xab,0xaf,0x97,0x55,0x4a,0x9,0x67,0x4,0x81,0x1b,0x29,0xed,0x30,0x53,0x62,0x5c,0xcc,0x6,0x60,0x66,0x98,0x29,0xc0,0xba,0x2c,0x97,0x67,0xc0,0x66,0x90,0x82,0x3a,0xd5,0x55,0x9d,0xea,0xf1,0xe0,0x90,0xf7,0x5,0x91,0x40,0x8c,0x81,0x10,0xe2,0xc,0x0,0xd6,0x79,0xab,0x26,0x54,0x75,0xdd,0x4f,0x41,0x4,0x4a,0x33,0xc3,0x7c,0x3a,0x9d,0x6e,0xd,0x40,0x11,0x1,0x2,0x22,0xe3,0xc,0x88,0x38,0x66,0x10,0x2,0x19,0x88,0xfc,0xa3,0x81,0x0,0x88,0x9b,0x77,0x3f,0x9f,0x2,0x20,0xe2,0xb8,0x83,0x48,0x33,0xc6,0x19,0x68,0xcf,0x78,0xc7,0x42,0x5f,0xb7,0x45,0xb,0x54,0x5d,0x67,0x31,0xa0,0xae,0x7,0x2b,0xfd,0x6f,0x51,0xf7,0xd7,0x45,0xff,0x66,0xee,0xf3,0x18,0x30,0xa3,0x13,0x96,0x4c,0x50,0xb0,0xaf,0x80,0x56,0x88,0xc3,0x38,0xc5,0xfe,0xdc,0x4c,0x0,0xee,0x78,0x66,0xc1,0xdd,0x70,0x9f,0x7,0xa0,0x19,0xd,0xfd,0xee,0xc3,0x14,0x58,0x73,0x31,0x1d,0x6c,0xdc,0x66,0xe6,0x8a,0x59,0xae,0x7,0x77,0x6c,0x42,0x37,0xfb,0x32,0xdc,0x7f,0xfb,0x3e,0x45,0xee,0x66,0x37,0x18,0xf3,0x44,0xa8,0x6d,0x59,0x35,0x94,0xce,0x63,0xac,0x61,0xcd,0x4c,0x33,0xb,0x43,0x0,0x3b,0xe0,0x17,0x12,0xae,0x42,0x8c,0x55,0x4a,0x69,0x82,0x81,0xc6,0xb9,0xcd,0xe9,0x3c,0x0,0x4d,0x17,0x74,0xf7,0x5c,0x11,0xf2,0xa9,0xf,0xe0,0x37,0xf0,0xed,0xf3,0xe5,0xc5,0xeb,0x7,0xf7,0x1f,0x6e,0xd5,0xb4,0x62,0x44,0xb,0xab,0xd5,0x8a,0xc5,0x62,0x1,0x40,0x8c,0xf1,0x80,0x4e,0xa8,0xa8,0x2a,0xc0,0x47,0x90,0x57,0x5d,0x9f,0x0,0x56,0x47,0x3c,0x46,0xd7,0x40,0x3a,0xf6,0x31,0xda,0xe5,0x79,0x2,0x7e,0x1e,0xf8,0x1c,0x1f,0xf5,0x12,0x2,0xfc,0x1,0x80,0x59,0x58,0xd6,0x46,0x86,0xf,0x31,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char option_button_pressed_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x77,0x0,0x7d,0x59,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x2f,0x0,0x2d,0x0,0x31,0xdb,0x99,0xd6,0x23,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x10,0x16,0x15,0x22,0x43,0x97,0x9a,0x23,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0xd2,0x49,0x44,0x41,0x54,0x48,0x89,0xed,0xd5,0x31,0x4e,0xc3,0x50,0x10,0x84,0xe1,0xef,0x5,0x4b,0x20,0x44,0xc1,0xeb,0x6c,0x3f,0xc1,0x9,0x2,0x5c,0x2c,0xe1,0x32,0x70,0xb1,0x90,0xd4,0x34,0xc8,0x9,0x9d,0x29,0x28,0x1c,0x29,0xc8,0x14,0x76,0x44,0x7,0x51,0x90,0x93,0x26,0x53,0xaf,0x76,0xfe,0xd5,0x4a,0x33,0x1,0x97,0xb8,0xc6,0x15,0xce,0x10,0xc,0xab,0x16,0x5f,0xf8,0xc4,0x47,0xd6,0x9b,0xdf,0xe3,0x6,0x17,0x7,0x2,0x68,0xf0,0x86,0x97,0x4c,0x77,0xf9,0xed,0xdd,0xf8,0x61,0x9c,0xca,0x34,0xd1,0xe,0xc,0x10,0xb4,0xd5,0xb2,0x7a,0x9e,0x2f,0x66,0x1,0xaf,0x19,0x32,0x9c,0xa7,0x32,0x4d,0x9b,0xa6,0x51,0xd7,0xf5,0x9f,0x3b,0x8a,0xbc,0xb0,0x7a,0x5f,0xed,0xe5,0x1f,0x63,0xc,0xa9,0x4c,0xd3,0xf9,0x62,0xf6,0x88,0x6c,0xf4,0xc3,0x65,0x27,0xf3,0xff,0xaa,0xae,0xeb,0xee,0x9,0xfd,0xab,0x47,0xbf,0x4e,0x1f,0x40,0x27,0x80,0x13,0xc0,0x9,0x60,0xb,0xd0,0xa,0xc4,0x18,0x7,0x37,0x8c,0x31,0x6e,0xc3,0xbe,0xa5,0x4b,0xc1,0xd,0xd6,0xd5,0xb2,0x7a,0x4a,0x65,0x9a,0x14,0x79,0xb1,0x53,0x14,0x17,0x79,0xb1,0x1f,0x41,0x1f,0xc5,0x58,0x63,0x13,0x50,0x3a,0x62,0x19,0x5,0x47,0xae,0xe3,0x6f,0x22,0x6d,0x3e,0xb3,0x5c,0x94,0xd4,0xe,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x20,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x77,0x0,0x7d,0x59,0x0,0x0,0xa,0x45,0x69,0x43,0x43,0x50,0x49,0x43,0x43,0x20,0x70,0x72,0x6f,0x66,0x69,0x6c,0x65,0x0,0x0,0x78,0xda,0x9d,0x53,0x67,0x54,0x53,0xe9,0x16,0x3d,0xf7,0xde,0xf4,0x42,0x4b,0x88,0x80,0x94,0x4b,0x6f,0x52,0x15,0x8,0x20,0x52,0x42,0x8b,0x80,0x14,0x91,0x26,0x2a,0x21,0x9,0x10,0x4a,0x88,0x21,0xa1,0xd9,0x15,0x51,0xc1,0x11,0x45,0x45,0x4,0x1b,0xc8,0xa0,0x88,0x3,0x8e,0x8e,0x80,0x8c,0x15,0x51,0x2c,0xc,0x8a,0xa,0xd8,0x7,0xe4,0x21,0xa2,0x8e,0x83,0xa3,0x88,0x8a,0xca,0xfb,0xe1,0x7b,0xa3,0x6b,0xd6,0xbc,0xf7,0xe6,0xcd,0xfe,0xb5,0xd7,0x3e,0xe7,0xac,0xf3,0x9d,0xb3,0xcf,0x7,0xc0,0x8,0xc,0x96,0x48,0x33,0x51,0x35,0x80,0xc,0xa9,0x42,0x1e,0x11,0xe0,0x83,0xc7,0xc4,0xc6,0xe1,0xe4,0x2e,0x40,0x81,0xa,0x24,0x70,0x0,0x10,0x8,0xb3,0x64,0x21,0x73,0xfd,0x23,0x1,0x0,0xf8,0x7e,0x3c,0x3c,0x2b,0x22,0xc0,0x7,0xbe,0x0,0x1,0x78,0xd3,0xb,0x8,0x0,0xc0,0x4d,0x9b,0xc0,0x30,0x1c,0x87,0xff,0xf,0xea,0x42,0x99,0x5c,0x1,0x80,0x84,0x1,0xc0,0x74,0x91,0x38,0x4b,0x8,0x80,0x14,0x0,0x40,0x7a,0x8e,0x42,0xa6,0x0,0x40,0x46,0x1,0x80,0x9d,0x98,0x26,0x53,0x0,0xa0,0x4,0x0,0x60,0xcb,0x63,0x62,0xe3,0x0,0x50,0x2d,0x0,0x60,0x27,0x7f,0xe6,0xd3,0x0,0x80,0x9d,0xf8,0x99,0x7b,0x1,0x0,0x5b,0x94,0x21,0x15,0x1,0xa0,0x91,0x0,0x20,0x13,0x65,0x88,0x44,0x0,0x68,0x3b,0x0,0xac,0xcf,0x56,0x8a,0x45,0x0,0x58,0x30,0x0,0x14,0x66,0x4b,0xc4,0x39,0x0,0xd8,0x2d,0x0,0x30,0x49,0x57,0x66,0x48,0x0,0xb0,0xb7,0x0,0xc0,0xce,0x10,0xb,0xb2,0x0,0x8,0xc,0x0,0x30,0x51,0x88,0x85,0x29,0x0,0x4,0x7b,0x0,0x60,0xc8,0x23,0x23,0x78,0x0,0x84,0x99,0x0,0x14,0x46,0xf2,0x57,0x3c,0xf1,0x2b,0xae,0x10,0xe7,0x2a,0x0,0x0,0x78,0x99,0xb2,0x3c,0xb9,0x24,0x39,0x45,0x81,0x5b,0x8,0x2d,0x71,0x7,0x57,0x57,0x2e,0x1e,0x28,0xce,0x49,0x17,0x2b,0x14,0x36,0x61,0x2,0x61,0x9a,0x40,0x2e,0xc2,0x79,0x99,0x19,0x32,0x81,0x34,0xf,0xe0,0xf3,0xcc,0x0,0x0,0xa0,0x91,0x15,0x11,0xe0,0x83,0xf3,0xfd,0x78,0xce,0xe,0xae,0xce,0xce,0x36,0x8e,0xb6,0xe,0x5f,0x2d,0xea,0xbf,0x6,0xff,0x22,0x62,0x62,0xe3,0xfe,0xe5,0xcf,0xab,0x70,0x40,0x0,0x0,0xe1,0x74,0x7e,0xd1,0xfe,0x2c,0x2f,0xb3,0x1a,0x80,0x3b,0x6,0x80,0x6d,0xfe,0xa2,0x25,0xee,0x4,0x68,0x5e,0xb,0xa0,0x75,0xf7,0x8b,0x66,0xb2,0xf,0x40,0xb5,0x0,0xa0,0xe9,0xda,0x57,0xf3,0x70,0xf8,0x7e,0x3c,0x3c,0x45,0xa1,0x90,0xb9,0xd9,0xd9,0xe5,0xe4,0xe4,0xd8,0x4a,0xc4,0x42,0x5b,0x61,0xca,0x57,0x7d,0xfe,0x67,0xc2,0x5f,0xc0,0x57,0xfd,0x6c,0xf9,0x7e,0x3c,0xfc,0xf7,0xf5,0xe0,0xbe,0xe2,0x24,0x81,0x32,0x5d,0x81,0x47,0x4,0xf8,0xe0,0xc2,0xcc,0xf4,0x4c,0xa5,0x1c,0xcf,0x92,0x9,0x84,0x62,0xdc,0xe6,0x8f,0x47,0xfc,0xb7,0xb,0xff,0xfc,0x1d,0xd3,0x22,0xc4,0x49,0x62,0xb9,0x58,0x2a,0x14,0xe3,0x51,0x12,0x71,0x8e,0x44,0x9a,0x8c,0xf3,0x32,0xa5,0x22,0x89,0x42,0x92,0x29,0xc5,0x25,0xd2,0xff,0x64,0xe2,0xdf,0x2c,0xfb,0x3,0x3e,0xdf,0x35,0x0,0xb0,0x6a,0x3e,0x1,0x7b,0x91,0x2d,0xa8,0x5d,0x63,0x3,0xf6,0x4b,0x27,0x10,0x58,0x74,0xc0,0xe2,0xf7,0x0,0x0,0xf2,0xbb,0x6f,0xc1,0xd4,0x28,0x8,0x3,0x80,0x68,0x83,0xe1,0xcf,0x77,0xff,0xef,0x3f,0xfd,0x47,0xa0,0x25,0x0,0x80,0x66,0x49,0x92,0x71,0x0,0x0,0x5e,0x44,0x24,0x2e,0x54,0xca,0xb3,0x3f,0xc7,0x8,0x0,0x0,0x44,0xa0,0x81,0x2a,0xb0,0x41,0x1b,0xf4,0xc1,0x18,0x2c,0xc0,0x6,0x1c,0xc1,0x5,0xdc,0xc1,0xb,0xfc,0x60,0x36,0x84,0x42,0x24,0xc4,0xc2,0x42,0x10,0x42,0xa,0x64,0x80,0x1c,0x72,0x60,0x29,0xac,0x82,0x42,0x28,0x86,0xcd,0xb0,0x1d,0x2a,0x60,0x2f,0xd4,0x40,0x1d,0x34,0xc0,0x51,0x68,0x86,0x93,0x70,0xe,0x2e,0xc2,0x55,0xb8,0xe,0x3d,0x70,0xf,0xfa,0x61,0x8,0x9e,0xc1,0x28,0xbc,0x81,0x9,0x4,0x41,0xc8,0x8,0x13,0x61,0x21,0xda,0x88,0x1,0x62,0x8a,0x58,0x23,0x8e,0x8,0x17,0x99,0x85,0xf8,0x21,0xc1,0x48,0x4,0x12,0x8b,0x24,0x20,0xc9,0x88,0x14,0x51,0x22,0x4b,0x91,0x35,0x48,0x31,0x52,0x8a,0x54,0x20,0x55,0x48,0x1d,0xf2,0x3d,0x72,0x2,0x39,0x87,0x5c,0x46,0xba,0x91,0x3b,0xc8,0x0,0x32,0x82,0xfc,0x86,0xbc,0x47,0x31,0x94,0x81,0xb2,0x51,0x3d,0xd4,0xc,0xb5,0x43,0xb9,0xa8,0x37,0x1a,0x84,0x46,0xa2,0xb,0xd0,0x64,0x74,0x31,0x9a,0x8f,0x16,0xa0,0x9b,0xd0,0x72,0xb4,0x1a,0x3d,0x8c,0x36,0xa1,0xe7,0xd0,0xab,0x68,0xf,0xda,0x8f,0x3e,0x43,0xc7,0x30,0xc0,0xe8,0x18,0x7,0x33,0xc4,0x6c,0x30,0x2e,0xc6,0xc3,0x42,0xb1,0x38,0x2c,0x9,0x93,0x63,0xcb,0xb1,0x22,0xac,0xc,0xab,0xc6,0x1a,0xb0,0x56,0xac,0x3,0xbb,0x89,0xf5,0x63,0xcf,0xb1,0x77,0x4,0x12,0x81,0x45,0xc0,0x9,0x36,0x4,0x77,0x42,0x20,0x61,0x1e,0x41,0x48,0x58,0x4c,0x58,0x4e,0xd8,0x48,0xa8,0x20,0x1c,0x24,0x34,0x11,0xda,0x9,0x37,0x9,0x3,0x84,0x51,0xc2,0x27,0x22,0x93,0xa8,0x4b,0xb4,0x26,0xba,0x11,0xf9,0xc4,0x18,0x62,0x32,0x31,0x87,0x58,0x48,0x2c,0x23,0xd6,0x12,0x8f,0x13,0x2f,0x10,0x7b,0x88,0x43,0xc4,0x37,0x24,0x12,0x89,0x43,0x32,0x27,0xb9,0x90,0x2,0x49,0xb1,0xa4,0x54,0xd2,0x12,0xd2,0x46,0xd2,0x6e,0x52,0x23,0xe9,0x2c,0xa9,0x9b,0x34,0x48,0x1a,0x23,0x93,0xc9,0xda,0x64,0x6b,0xb2,0x7,0x39,0x94,0x2c,0x20,0x2b,0xc8,0x85,0xe4,0x9d,0xe4,0xc3,0xe4,0x33,0xe4,0x1b,0xe4,0x21,0xf2,0x5b,0xa,0x9d,0x62,0x40,0x71,0xa4,0xf8,0x53,0xe2,0x28,0x52,0xca,0x6a,0x4a,0x19,0xe5,0x10,0xe5,0x34,0xe5,0x6,0x65,0x98,0x32,0x41,0x55,0xa3,0x9a,0x52,0xdd,0xa8,0xa1,0x54,0x11,0x35,0x8f,0x5a,0x42,0xad,0xa1,0xb6,0x52,0xaf,0x51,0x87,0xa8,0x13,0x34,0x75,0x9a,0x39,0xcd,0x83,0x16,0x49,0x4b,0xa5,0xad,0xa2,0x95,0xd3,0x1a,0x68,0x17,0x68,0xf7,0x69,0xaf,0xe8,0x74,0xba,0x11,0xdd,0x95,0x1e,0x4e,0x97,0xd0,0x57,0xd2,0xcb,0xe9,0x47,0xe8,0x97,0xe8,0x3,0xf4,0x77,0xc,0xd,0x86,0x15,0x83,0xc7,0x88,0x67,0x28,0x19,0x9b,0x18,0x7,0x18,0x67,0x19,0x77,0x18,0xaf,0x98,0x4c,0xa6,0x19,0xd3,0x8b,0x19,0xc7,0x54,0x30,0x37,0x31,0xeb,0x98,0xe7,0x99,0xf,0x99,0x6f,0x55,0x58,0x2a,0xb6,0x2a,0x7c,0x15,0x91,0xca,0xa,0x95,0x4a,0x95,0x26,0x95,0x1b,0x2a,0x2f,0x54,0xa9,0xaa,0xa6,0xaa,0xde,0xaa,0xb,0x55,0xf3,0x55,0xcb,0x54,0x8f,0xa9,0x5e,0x53,0x7d,0xae,0x46,0x55,0x33,0x53,0xe3,0xa9,0x9,0xd4,0x96,0xab,0x55,0xaa,0x9d,0x50,0xeb,0x53,0x1b,0x53,0x67,0xa9,0x3b,0xa8,0x87,0xaa,0x67,0xa8,0x6f,0x54,0x3f,0xa4,0x7e,0x59,0xfd,0x89,0x6,0x59,0xc3,0x4c,0xc3,0x4f,0x43,0xa4,0x51,0xa0,0xb1,0x5f,0xe3,0xbc,0xc6,0x20,0xb,0x63,0x19,0xb3,0x78,0x2c,0x21,0x6b,0xd,0xab,0x86,0x75,0x81,0x35,0xc4,0x26,0xb1,0xcd,0xd9,0x7c,0x76,0x2a,0xbb,0x98,0xfd,0x1d,0xbb,0x8b,0x3d,0xaa,0xa9,0xa1,0x39,0x43,0x33,0x4a,0x33,0x57,0xb3,0x52,0xf3,0x94,0x66,0x3f,0x7,0xe3,0x98,0x71,0xf8,0x9c,0x74,0x4e,0x9,0xe7,0x28,0xa7,0x97,0xf3,0x7e,0x8a,0xde,0x14,0xef,0x29,0xe2,0x29,0x1b,0xa6,0x34,0x4c,0xb9,0x31,0x65,0x5c,0x6b,0xaa,0x96,0x97,0x96,0x58,0xab,0x48,0xab,0x51,0xab,0x47,0xeb,0xbd,0x36,0xae,0xed,0xa7,0x9d,0xa6,0xbd,0x45,0xbb,0x59,0xfb,0x81,0xe,0x41,0xc7,0x4a,0x27,0x5c,0x27,0x47,0x67,0x8f,0xce,0x5,0x9d,0xe7,0x53,0xd9,0x53,0xdd,0xa7,0xa,0xa7,0x16,0x4d,0x3d,0x3a,0xf5,0xae,0x2e,0xaa,0x6b,0xa5,0x1b,0xa1,0xbb,0x44,0x77,0xbf,0x6e,0xa7,0xee,0x98,0x9e,0xbe,0x5e,0x80,0x9e,0x4c,0x6f,0xa7,0xde,0x79,0xbd,0xe7,0xfa,0x1c,0x7d,0x2f,0xfd,0x54,0xfd,0x6d,0xfa,0xa7,0xf5,0x47,0xc,0x58,0x6,0xb3,0xc,0x24,0x6,0xdb,0xc,0xce,0x18,0x3c,0xc5,0x35,0x71,0x6f,0x3c,0x1d,0x2f,0xc7,0xdb,0xf1,0x51,0x43,0x5d,0xc3,0x40,0x43,0xa5,0x61,0x95,0x61,0x97,0xe1,0x84,0x91,0xb9,0xd1,0x3c,0xa3,0xd5,0x46,0x8d,0x46,0xf,0x8c,0x69,0xc6,0x5c,0xe3,0x24,0xe3,0x6d,0xc6,0x6d,0xc6,0xa3,0x26,0x6,0x26,0x21,0x26,0x4b,0x4d,0xea,0x4d,0xee,0x9a,0x52,0x4d,0xb9,0xa6,0x29,0xa6,0x3b,0x4c,0x3b,0x4c,0xc7,0xcd,0xcc,0xcd,0xa2,0xcd,0xd6,0x99,0x35,0x9b,0x3d,0x31,0xd7,0x32,0xe7,0x9b,0xe7,0x9b,0xd7,0x9b,0xdf,0xb7,0x60,0x5a,0x78,0x5a,0x2c,0xb6,0xa8,0xb6,0xb8,0x65,0x49,0xb2,0xe4,0x5a,0xa6,0x59,0xee,0xb6,0xbc,0x6e,0x85,0x5a,0x39,0x59,0xa5,0x58,0x55,0x5a,0x5d,0xb3,0x46,0xad,0x9d,0xad,0x25,0xd6,0xbb,0xad,0xbb,0xa7,0x11,0xa7,0xb9,0x4e,0x93,0x4e,0xab,0x9e,0xd6,0x67,0xc3,0xb0,0xf1,0xb6,0xc9,0xb6,0xa9,0xb7,0x19,0xb0,0xe5,0xd8,0x6,0xdb,0xae,0xb6,0x6d,0xb6,0x7d,0x61,0x67,0x62,0x17,0x67,0xb7,0xc5,0xae,0xc3,0xee,0x93,0xbd,0x93,0x7d,0xba,0x7d,0x8d,0xfd,0x3d,0x7,0xd,0x87,0xd9,0xe,0xab,0x1d,0x5a,0x1d,0x7e,0x73,0xb4,0x72,0x14,0x3a,0x56,0x3a,0xde,0x9a,0xce,0x9c,0xee,0x3f,0x7d,0xc5,0xf4,0x96,0xe9,0x2f,0x67,0x58,0xcf,0x10,0xcf,0xd8,0x33,0xe3,0xb6,0x13,0xcb,0x29,0xc4,0x69,0x9d,0x53,0x9b,0xd3,0x47,0x67,0x17,0x67,0xb9,0x73,0x83,0xf3,0x88,0x8b,0x89,0x4b,0x82,0xcb,0x2e,0x97,0x3e,0x2e,0x9b,0x1b,0xc6,0xdd,0xc8,0xbd,0xe4,0x4a,0x74,0xf5,0x71,0x5d,0xe1,0x7a,0xd2,0xf5,0x9d,0x9b,0xb3,0x9b,0xc2,0xed,0xa8,0xdb,0xaf,0xee,0x36,0xee,0x69,0xee,0x87,0xdc,0x9f,0xcc,0x34,0x9f,0x29,0x9e,0x59,0x33,0x73,0xd0,0xc3,0xc8,0x43,0xe0,0x51,0xe5,0xd1,0x3f,0xb,0x9f,0x95,0x30,0x6b,0xdf,0xac,0x7e,0x4f,0x43,0x4f,0x81,0x67,0xb5,0xe7,0x23,0x2f,0x63,0x2f,0x91,0x57,0xad,0xd7,0xb0,0xb7,0xa5,0x77,0xaa,0xf7,0x61,0xef,0x17,0x3e,0xf6,0x3e,0x72,0x9f,0xe3,0x3e,0xe3,0x3c,0x37,0xde,0x32,0xde,0x59,0x5f,0xcc,0x37,0xc0,0xb7,0xc8,0xb7,0xcb,0x4f,0xc3,0x6f,0x9e,0x5f,0x85,0xdf,0x43,0x7f,0x23,0xff,0x64,0xff,0x7a,0xff,0xd1,0x0,0xa7,0x80,0x25,0x1,0x67,0x3,0x89,0x81,0x41,0x81,0x5b,0x2,0xfb,0xf8,0x7a,0x7c,0x21,0xbf,0x8e,0x3f,0x3a,0xdb,0x65,0xf6,0xb2,0xd9,0xed,0x41,0x8c,0xa0,0xb9,0x41,0x15,0x41,0x8f,0x82,0xad,0x82,0xe5,0xc1,0xad,0x21,0x68,0xc8,0xec,0x90,0xad,0x21,0xf7,0xe7,0x98,0xce,0x91,0xce,0x69,0xe,0x85,0x50,0x7e,0xe8,0xd6,0xd0,0x7,0x61,0xe6,0x61,0x8b,0xc3,0x7e,0xc,0x27,0x85,0x87,0x85,0x57,0x86,0x3f,0x8e,0x70,0x88,0x58,0x1a,0xd1,0x31,0x97,0x35,0x77,0xd1,0xdc,0x43,0x73,0xdf,0x44,0xfa,0x44,0x96,0x44,0xde,0x9b,0x67,0x31,0x4f,0x39,0xaf,0x2d,0x4a,0x35,0x2a,0x3e,0xaa,0x2e,0x6a,0x3c,0xda,0x37,0xba,0x34,0xba,0x3f,0xc6,0x2e,0x66,0x59,0xcc,0xd5,0x58,0x9d,0x58,0x49,0x6c,0x4b,0x1c,0x39,0x2e,0x2a,0xae,0x36,0x6e,0x6c,0xbe,0xdf,0xfc,0xed,0xf3,0x87,0xe2,0x9d,0xe2,0xb,0xe3,0x7b,0x17,0x98,0x2f,0xc8,0x5d,0x70,0x79,0xa1,0xce,0xc2,0xf4,0x85,0xa7,0x16,0xa9,0x2e,0x12,0x2c,0x3a,0x96,0x40,0x4c,0x88,0x4e,0x38,0x94,0xf0,0x41,0x10,0x2a,0xa8,0x16,0x8c,0x25,0xf2,0x13,0x77,0x25,0x8e,0xa,0x79,0xc2,0x1d,0xc2,0x67,0x22,0x2f,0xd1,0x36,0xd1,0x88,0xd8,0x43,0x5c,0x2a,0x1e,0x4e,0xf2,0x48,0x2a,0x4d,0x7a,0x92,0xec,0x91,0xbc,0x35,0x79,0x24,0xc5,0x33,0xa5,0x2c,0xe5,0xb9,0x84,0x27,0xa9,0x90,0xbc,0x4c,0xd,0x4c,0xdd,0x9b,0x3a,0x9e,0x16,0x9a,0x76,0x20,0x6d,0x32,0x3d,0x3a,0xbd,0x31,0x83,0x92,0x91,0x90,0x71,0x42,0xaa,0x21,0x4d,0x93,0xb6,0x67,0xea,0x67,0xe6,0x66,0x76,0xcb,0xac,0x65,0x85,0xb2,0xfe,0xc5,0x6e,0x8b,0xb7,0x2f,0x1e,0x95,0x7,0xc9,0x6b,0xb3,0x90,0xac,0x5,0x59,0x2d,0xa,0xb6,0x42,0xa6,0xe8,0x54,0x5a,0x28,0xd7,0x2a,0x7,0xb2,0x67,0x65,0x57,0x66,0xbf,0xcd,0x89,0xca,0x39,0x96,0xab,0x9e,0x2b,0xcd,0xed,0xcc,0xb3,0xca,0xdb,0x90,0x37,0x9c,0xef,0x9f,0xff,0xed,0x12,0xc2,0x12,0xe1,0x92,0xb6,0xa5,0x86,0x4b,0x57,0x2d,0x1d,0x58,0xe6,0xbd,0xac,0x6a,0x39,0xb2,0x3c,0x71,0x79,0xdb,0xa,0xe3,0x15,0x5,0x2b,0x86,0x56,0x6,0xac,0x3c,0xb8,0x8a,0xb6,0x2a,0x6d,0xd5,0x4f,0xab,0xed,0x57,0x97,0xae,0x7e,0xbd,0x26,0x7a,0x4d,0x6b,0x81,0x5e,0xc1,0xca,0x82,0xc1,0xb5,0x1,0x6b,0xeb,0xb,0x55,0xa,0xe5,0x85,0x7d,0xeb,0xdc,0xd7,0xed,0x5d,0x4f,0x58,0x2f,0x59,0xdf,0xb5,0x61,0xfa,0x86,0x9d,0x1b,0x3e,0x15,0x89,0x8a,0xae,0x14,0xdb,0x17,0x97,0x15,0x7f,0xd8,0x28,0xdc,0x78,0xe5,0x1b,0x87,0x6f,0xca,0xbf,0x99,0xdc,0x94,0xb4,0xa9,0xab,0xc4,0xb9,0x64,0xcf,0x66,0xd2,0x66,0xe9,0xe6,0xde,0x2d,0x9e,0x5b,0xe,0x96,0xaa,0x97,0xe6,0x97,0xe,0x6e,0xd,0xd9,0xda,0xb4,0xd,0xdf,0x56,0xb4,0xed,0xf5,0xf6,0x45,0xdb,0x2f,0x97,0xcd,0x28,0xdb,0xbb,0x83,0xb6,0x43,0xb9,0xa3,0xbf,0x3c,0xb8,0xbc,0x65,0xa7,0xc9,0xce,0xcd,0x3b,0x3f,0x54,0xa4,0x54,0xf4,0x54,0xfa,0x54,0x36,0xee,0xd2,0xdd,0xb5,0x61,0xd7,0xf8,0x6e,0xd1,0xee,0x1b,0x7b,0xbc,0xf6,0x34,0xec,0xd5,0xdb,0x5b,0xbc,0xf7,0xfd,0x3e,0xc9,0xbe,0xdb,0x55,0x1,0x55,0x4d,0xd5,0x66,0xd5,0x65,0xfb,0x49,0xfb,0xb3,0xf7,0x3f,0xae,0x89,0xaa,0xe9,0xf8,0x96,0xfb,0x6d,0x5d,0xad,0x4e,0x6d,0x71,0xed,0xc7,0x3,0xd2,0x3,0xfd,0x7,0x23,0xe,0xb6,0xd7,0xb9,0xd4,0xd5,0x1d,0xd2,0x3d,0x54,0x52,0x8f,0xd6,0x2b,0xeb,0x47,0xe,0xc7,0x1f,0xbe,0xfe,0x9d,0xef,0x77,0x2d,0xd,0x36,0xd,0x55,0x8d,0x9c,0xc6,0xe2,0x23,0x70,0x44,0x79,0xe4,0xe9,0xf7,0x9,0xdf,0xf7,0x1e,0xd,0x3a,0xda,0x76,0x8c,0x7b,0xac,0xe1,0x7,0xd3,0x1f,0x76,0x1d,0x67,0x1d,0x2f,0x6a,0x42,0x9a,0xf2,0x9a,0x46,0x9b,0x53,0x9a,0xfb,0x5b,0x62,0x5b,0xba,0x4f,0xcc,0x3e,0xd1,0xd6,0xea,0xde,0x7a,0xfc,0x47,0xdb,0x1f,0xf,0x9c,0x34,0x3c,0x59,0x79,0x4a,0xf3,0x54,0xc9,0x69,0xda,0xe9,0x82,0xd3,0x93,0x67,0xf2,0xcf,0x8c,0x9d,0x95,0x9d,0x7d,0x7e,0x2e,0xf9,0xdc,0x60,0xdb,0xa2,0xb6,0x7b,0xe7,0x63,0xce,0xdf,0x6a,0xf,0x6f,0xef,0xba,0x10,0x74,0xe1,0xd2,0x45,0xff,0x8b,0xe7,0x3b,0xbc,0x3b,0xce,0x5c,0xf2,0xb8,0x74,0xf2,0xb2,0xdb,0xe5,0x13,0x57,0xb8,0x57,0x9a,0xaf,0x3a,0x5f,0x6d,0xea,0x74,0xea,0x3c,0xfe,0x93,0xd3,0x4f,0xc7,0xbb,0x9c,0xbb,0x9a,0xae,0xb9,0x5c,0x6b,0xb9,0xee,0x7a,0xbd,0xb5,0x7b,0x66,0xf7,0xe9,0x1b,0x9e,0x37,0xce,0xdd,0xf4,0xbd,0x79,0xf1,0x16,0xff,0xd6,0xd5,0x9e,0x39,0x3d,0xdd,0xbd,0xf3,0x7a,0x6f,0xf7,0xc5,0xf7,0xf5,0xdf,0x16,0xdd,0x7e,0x72,0x27,0xfd,0xce,0xcb,0xbb,0xd9,0x77,0x27,0xee,0xad,0xbc,0x4f,0xbc,0x5f,0xf4,0x40,0xed,0x41,0xd9,0x43,0xdd,0x87,0xd5,0x3f,0x5b,0xfe,0xdc,0xd8,0xef,0xdc,0x7f,0x6a,0xc0,0x77,0xa0,0xf3,0xd1,0xdc,0x47,0xf7,0x6,0x85,0x83,0xcf,0xfe,0x91,0xf5,0x8f,0xf,0x43,0x5,0x8f,0x99,0x8f,0xcb,0x86,0xd,0x86,0xeb,0x9e,0x38,0x3e,0x39,0x39,0xe2,0x3f,0x72,0xfd,0xe9,0xfc,0xa7,0x43,0xcf,0x64,0xcf,0x26,0x9e,0x17,0xfe,0xa2,0xfe,0xcb,0xae,0x17,0x16,0x2f,0x7e,0xf8,0xd5,0xeb,0xd7,0xce,0xd1,0x98,0xd1,0xa1,0x97,0xf2,0x97,0x93,0xbf,0x6d,0x7c,0xa5,0xfd,0xea,0xc0,0xeb,0x19,0xaf,0xdb,0xc6,0xc2,0xc6,0x1e,0xbe,0xc9,0x78,0x33,0x31,0x5e,0xf4,0x56,0xfb,0xed,0xc1,0x77,0xdc,0x77,0x1d,0xef,0xa3,0xdf,0xf,0x4f,0xe4,0x7c,0x20,0x7f,0x28,0xff,0x68,0xf9,0xb1,0xf5,0x53,0xd0,0xa7,0xfb,0x93,0x19,0x93,0x93,0xff,0x4,0x3,0x98,0xf3,0xfc,0xef,0x35,0x94,0x82,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xa,0x14,0x3,0x2,0x33,0x35,0xd7,0x61,0xfe,0x0,0x0,0x1,0xdb,0x49,0x44,0x41,0x54,0x48,0xc7,0xad,0x95,0x4d,0x6e,0x14,0x31,0x10,0x85,0xbf,0xaa,0x9a,0x4e,0xf,0x19,0x44,0x7a,0x41,0x50,0x6,0xe,0x81,0x58,0x71,0xf,0xae,0x80,0xc4,0x19,0xe6,0x8,0x5c,0x82,0x73,0x70,0x9,0x56,0xd9,0x22,0x21,0xb1,0x0,0x66,0x85,0x8,0x9,0xa,0x99,0xd8,0x55,0x2c,0xda,0x3d,0x3f,0x81,0x74,0xf7,0x68,0xb0,0x54,0x6a,0x5b,0x6a,0xdb,0xcf,0xef,0xbd,0xaa,0x12,0x60,0x2,0x1c,0x1,0x35,0x30,0x2d,0x73,0x3,0x94,0xdd,0xe1,0xc0,0x2d,0x70,0x3,0x5c,0x3,0xab,0xb2,0x76,0xe,0x18,0xdd,0xe5,0x33,0xa0,0x1,0x4e,0xca,0xbc,0x6,0xa4,0x44,0x37,0x6e,0xcb,0xc5,0x97,0xc0,0x77,0xe0,0x27,0x90,0xff,0x7,0x80,0x1a,0x68,0x5e,0x3c,0x7f,0xf9,0xea,0xf4,0xf1,0xd9,0x22,0xe7,0xdc,0x4,0x71,0xef,0x86,0xe3,0x7,0x33,0x3e,0x7d,0xfe,0x8,0x4,0x66,0x13,0x54,0xb5,0xf7,0x82,0x88,0x28,0xe1,0xb8,0x3b,0x22,0xf2,0xcd,0xcc,0x5e,0x9f,0x9f,0x7f,0x78,0xdf,0x1,0x98,0x2,0x27,0x4f,0x4e,0xe7,0x8b,0xcb,0xab,0x8b,0x26,0xa5,0xd4,0x7b,0xa0,0x8a,0x90,0xd2,0xa,0xf7,0x8c,0x59,0x35,0x1a,0x80,0xbb,0xe3,0x9e,0x1,0xe6,0x75,0x3d,0x7d,0x7,0x3c,0xdd,0x91,0x20,0xbb,0x37,0x29,0xe5,0x3b,0xac,0xff,0x13,0x2,0x20,0x88,0x28,0x66,0x8a,0xaa,0x8d,0x0,0xd0,0xa9,0x14,0xe4,0x9c,0xc8,0x39,0xcf,0xb7,0x25,0x30,0xa0,0x56,0x4,0x15,0x19,0xd4,0xac,0xfb,0x47,0x44,0x0,0x45,0xa4,0x9f,0x1,0x91,0xc0,0x1d,0x54,0x29,0x40,0xe4,0x2f,0xf,0x28,0x20,0x62,0x82,0xe8,0x30,0x0,0x31,0x41,0x24,0x88,0x0,0x91,0x36,0xfa,0x19,0xe8,0xfe,0x89,0x35,0xb,0xdb,0xbe,0x9d,0x74,0xe7,0xaa,0xd8,0xe0,0x6b,0x5a,0x6,0x6c,0x6f,0xa7,0x47,0xdc,0xbf,0x9e,0x6c,0xa8,0x92,0x42,0xeb,0x0,0x3,0x22,0xb8,0xb3,0x36,0xd6,0xd0,0x9e,0x4d,0x6,0x74,0x46,0x6c,0x4d,0x79,0x17,0x40,0x88,0x8e,0x4,0xa0,0x42,0x44,0x2e,0x87,0x3b,0x11,0xe3,0x0,0xb4,0xd1,0xd2,0xbf,0x31,0x65,0xb,0xc0,0x81,0x30,0x31,0x74,0x84,0x4,0x26,0x86,0x7b,0xab,0x65,0xcb,0x42,0x8c,0x4c,0xc3,0xcd,0x77,0x7b,0xcf,0xa4,0x54,0xb3,0x1b,0x35,0x45,0x54,0xb7,0xcc,0xd2,0xc7,0x80,0x3,0x2d,0xa5,0xc3,0xfa,0x77,0x85,0x28,0xe3,0x9e,0xb,0xb,0xbb,0x0,0x56,0xc0,0xaf,0xaa,0xaa,0x7e,0x1c,0x55,0x55,0x93,0x52,0xa2,0xaf,0x12,0x76,0x99,0xd2,0x69,0x3a,0xe,0x40,0x5b,0x5,0x23,0xa2,0x64,0x84,0x2c,0xb7,0x1,0xfc,0x6,0x2e,0x96,0xcb,0xaf,0x6f,0xe7,0x67,0xcf,0x16,0x29,0xa5,0xde,0x52,0xfc,0x70,0xf6,0x88,0xaa,0xaa,0x5a,0x39,0xcc,0xf6,0xa8,0x84,0x99,0x9c,0x33,0xc0,0x17,0x90,0x37,0xeb,0x7,0x1,0xc7,0x7,0x34,0xa3,0x6b,0x20,0x1d,0xda,0x8c,0x56,0x65,0x9e,0x80,0xab,0x3d,0xdb,0xf1,0x41,0x9d,0x10,0xe0,0xf,0xcc,0xf9,0x14,0xcf,0xbc,0x12,0x3b,0xca,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char panel_bg_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x8,0x8,0x6,0x0,0x0,0x0,0xc4,0xf,0xbe,0x8b,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x10,0x10,0x25,0xd,0x33,0x8d,0xed,0x3b,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0x15,0x49,0x44,0x41,0x54,0x18,0x95,0x63,0x54,0x57,0xd7,0xfc,0xcf,0x80,0x7,0x30,0xe1,0x93,0x1c,0x3e,0xa,0x0,0x86,0x1b,0x1,0x86,0x56,0xb4,0xba,0xe,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x8,0x8,0x6,0x0,0x0,0x0,0xc4,0xf,0xbe,0x8b,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x35,0x0,0x32,0x0,0x3b,0x6,0x66,0x54,0x53,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xa,0x15,0x2,0x31,0xf,0x57,0xad,0x75,0x1b,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0x16,0x49,0x44,0x41,0x54,0x18,0xd3,0x63,0x54,0x55,0xd5,0xfa,0xcf,0x80,0x7,0x30,0x31,0x10,0x0,0xc3,0x43,0x1,0x0,0x83,0x6,0x1,0x83,0xc0,0x1f,0xe3,0x5,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char popup_bg_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xd,0xd7,0x0,0x0,0xd,0xd7,0x1,0x42,0x28,0x9b,0x78,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x14,0xe,0x21,0x3,0x29,0x83,0x1c,0x15,0x0,0x0,0x0,0xc1,0x49,0x44,0x41,0x54,0x38,0x8d,0xed,0xd3,0x3d,0x4b,0xc3,0x60,0x14,0xc5,0xf1,0x5f,0xea,0x85,0xda,0xe0,0xe0,0x56,0x92,0x87,0xba,0x48,0x37,0x5f,0x3e,0x9b,0x9f,0xc4,0xcf,0x56,0xdb,0xd9,0x45,0xd2,0xd0,0xcd,0x41,0x34,0x85,0x47,0xe2,0x60,0xe6,0xa4,0xd0,0xc5,0xc1,0x3b,0x5e,0xee,0xf9,0x1f,0x2e,0x9c,0x53,0xa0,0xc4,0x35,0xae,0x70,0x81,0xc2,0xf8,0xf4,0xf8,0xc6,0x7,0xde,0x63,0x10,0x3f,0x60,0x85,0xcb,0x13,0x1,0x1d,0xde,0xf0,0x12,0x83,0xf3,0xcd,0xfd,0xdd,0xe3,0x73,0xaa,0xd3,0x22,0x22,0x46,0x1,0x39,0xe7,0xbe,0xd9,0x37,0x5f,0xdb,0xdd,0xe6,0x9,0xaf,0x81,0xc0,0x3c,0xd5,0xa9,0xec,0xba,0x4e,0x7b,0x68,0x47,0xed,0xab,0x65,0x55,0xa4,0x3a,0x95,0xdb,0xdd,0x66,0x8e,0x98,0xd,0xfb,0x22,0x22,0x26,0xc5,0xd0,0x1e,0x5a,0x11,0xc1,0xf0,0xea,0x6c,0xfc,0x7c,0x7a,0xfe,0x1,0x7f,0x9,0xd0,0xe7,0x9c,0x55,0xcb,0x6a,0x52,0x50,0x2d,0x2b,0x39,0x67,0x7e,0x23,0x2d,0x90,0x71,0x6c,0xf6,0xcd,0x67,0xaa,0xd3,0x62,0x7d,0xbb,0x3e,0x29,0xca,0x38,0x22,0x17,0xa8,0x9d,0x51,0xa6,0xc2,0x99,0x75,0xfe,0x1,0x7d,0xe1,0x44,0x88,0x9a,0x7d,0x74,0x9f,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0xa,0x45,0x69,0x43,0x43,0x50,0x49,0x43,0x43,0x20,0x70,0x72,0x6f,0x66,0x69,0x6c,0x65,0x0,0x0,0x78,0xda,0x9d,0x53,0x67,0x54,0x53,0xe9,0x16,0x3d,0xf7,0xde,0xf4,0x42,0x4b,0x88,0x80,0x94,0x4b,0x6f,0x52,0x15,0x8,0x20,0x52,0x42,0x8b,0x80,0x14,0x91,0x26,0x2a,0x21,0x9,0x10,0x4a,0x88,0x21,0xa1,0xd9,0x15,0x51,0xc1,0x11,0x45,0x45,0x4,0x1b,0xc8,0xa0,0x88,0x3,0x8e,0x8e,0x80,0x8c,0x15,0x51,0x2c,0xc,0x8a,0xa,0xd8,0x7,0xe4,0x21,0xa2,0x8e,0x83,0xa3,0x88,0x8a,0xca,0xfb,0xe1,0x7b,0xa3,0x6b,0xd6,0xbc,0xf7,0xe6,0xcd,0xfe,0xb5,0xd7,0x3e,0xe7,0xac,0xf3,0x9d,0xb3,0xcf,0x7,0xc0,0x8,0xc,0x96,0x48,0x33,0x51,0x35,0x80,0xc,0xa9,0x42,0x1e,0x11,0xe0,0x83,0xc7,0xc4,0xc6,0xe1,0xe4,0x2e,0x40,0x81,0xa,0x24,0x70,0x0,0x10,0x8,0xb3,0x64,0x21,0x73,0xfd,0x23,0x1,0x0,0xf8,0x7e,0x3c,0x3c,0x2b,0x22,0xc0,0x7,0xbe,0x0,0x1,0x78,0xd3,0xb,0x8,0x0,0xc0,0x4d,0x9b,0xc0,0x30,0x1c,0x87,0xff,0xf,0xea,0x42,0x99,0x5c,0x1,0x80,0x84,0x1,0xc0,0x74,0x91,0x38,0x4b,0x8,0x80,0x14,0x0,0x40,0x7a,0x8e,0x42,0xa6,0x0,0x40,0x46,0x1,0x80,0x9d,0x98,0x26,0x53,0x0,0xa0,0x4,0x0,0x60,0xcb,0x63,0x62,0xe3,0x0,0x50,0x2d,0x0,0x60,0x27,0x7f,0xe6,0xd3,0x0,0x80,0x9d,0xf8,0x99,0x7b,0x1,0x0,0x5b,0x94,0x21,0x15,0x1,0xa0,0x91,0x0,0x20,0x13,0x65,0x88,0x44,0x0,0x68,0x3b,0x0,0xac,0xcf,0x56,0x8a,0x45,0x0,0x58,0x30,0x0,0x14,0x66,0x4b,0xc4,0x39,0x0,0xd8,0x2d,0x0,0x30,0x49,0x57,0x66,0x48,0x0,0xb0,0xb7,0x0,0xc0,0xce,0x10,0xb,0xb2,0x0,0x8,0xc,0x0,0x30,0x51,0x88,0x85,0x29,0x0,0x4,0x7b,0x0,0x60,0xc8,0x23,0x23,0x78,0x0,0x84,0x99,0x0,0x14,0x46,0xf2,0x57,0x3c,0xf1,0x2b,0xae,0x10,0xe7,0x2a,0x0,0x0,0x78,0x99,0xb2,0x3c,0xb9,0x24,0x39,0x45,0x81,0x5b,0x8,0x2d,0x71,0x7,0x57,0x57,0x2e,0x1e,0x28,0xce,0x49,0x17,0x2b,0x14,0x36,0x61,0x2,0x61,0x9a,0x40,0x2e,0xc2,0x79,0x99,0x19,0x32,0x81,0x34,0xf,0xe0,0xf3,0xcc,0x0,0x0,0xa0,0x91,0x15,0x11,0xe0,0x83,0xf3,0xfd,0x78,0xce,0xe,0xae,0xce,0xce,0x36,0x8e,0xb6,0xe,0x5f,0x2d,0xea,0xbf,0x6,0xff,0x22,0x62,0x62,0xe3,0xfe,0xe5,0xcf,0xab,0x70,0x40,0x0,0x0,0xe1,0x74,0x7e,0xd1,0xfe,0x2c,0x2f,0xb3,0x1a,0x80,0x3b,0x6,0x80,0x6d,0xfe,0xa2,0x25,0xee,0x4,0x68,0x5e,0xb,0xa0,0x75,0xf7,0x8b,0x66,0xb2,0xf,0x40,0xb5,0x0,0xa0,0xe9,0xda,0x57,0xf3,0x70,0xf8,0x7e,0x3c,0x3c,0x45,0xa1,0x90,0xb9,0xd9,0xd9,0xe5,0xe4,0xe4,0xd8,0x4a,0xc4,0x42,0x5b,0x61,0xca,0x57,0x7d,0xfe,0x67,0xc2,0x5f,0xc0,0x57,0xfd,0x6c,0xf9,0x7e,0x3c,0xfc,0xf7,0xf5,0xe0,0xbe,0xe2,0x24,0x81,0x32,0x5d,0x81,0x47,0x4,0xf8,0xe0,0xc2,0xcc,0xf4,0x4c,0xa5,0x1c,0xcf,0x92,0x9,0x84,0x62,0xdc,0xe6,0x8f,0x47,0xfc,0xb7,0xb,0xff,0xfc,0x1d,0xd3,0x22,0xc4,0x49,0x62,0xb9,0x58,0x2a,0x14,0xe3,0x51,0x12,0x71,0x8e,0x44,0x9a,0x8c,0xf3,0x32,0xa5,0x22,0x89,0x42,0x92,0x29,0xc5,0x25,0xd2,0xff,0x64,0xe2,0xdf,0x2c,0xfb,0x3,0x3e,0xdf,0x35,0x0,0xb0,0x6a,0x3e,0x1,0x7b,0x91,0x2d,0xa8,0x5d,0x63,0x3,0xf6,0x4b,0x27,0x10,0x58,0x74,0xc0,0xe2,0xf7,0x0,0x0,0xf2,0xbb,0x6f,0xc1,0xd4,0x28,0x8,0x3,0x80,0x68,0x83,0xe1,0xcf,0x77,0xff,0xef,0x3f,0xfd,0x47,0xa0,0x25,0x0,0x80,0x66,0x49,0x92,0x71,0x0,0x0,0x5e,0x44,0x24,0x2e,0x54,0xca,0xb3,0x3f,0xc7,0x8,0x0,0x0,0x44,0xa0,0x81,0x2a,0xb0,0x41,0x1b,0xf4,0xc1,0x18,0x2c,0xc0,0x6,0x1c,0xc1,0x5,0xdc,0xc1,0xb,0xfc,0x60,0x36,0x84,0x42,0x24,0xc4,0xc2,0x42,0x10,0x42,0xa,0x64,0x80,0x1c,0x72,0x60,0x29,0xac,0x82,0x42,0x28,0x86,0xcd,0xb0,0x1d,0x2a,0x60,0x2f,0xd4,0x40,0x1d,0x34,0xc0,0x51,0x68,0x86,0x93,0x70,0xe,0x2e,0xc2,0x55,0xb8,0xe,0x3d,0x70,0xf,0xfa,0x61,0x8,0x9e,0xc1,0x28,0xbc,0x81,0x9,0x4,0x41,0xc8,0x8,0x13,0x61,0x21,0xda,0x88,0x1,0x62,0x8a,0x58,0x23,0x8e,0x8,0x17,0x99,0x85,0xf8,0x21,0xc1,0x48,0x4,0x12,0x8b,0x24,0x20,0xc9,0x88,0x14,0x51,0x22,0x4b,0x91,0x35,0x48,0x31,0x52,0x8a,0x54,0x20,0x55,0x48,0x1d,0xf2,0x3d,0x72,0x2,0x39,0x87,0x5c,0x46,0xba,0x91,0x3b,0xc8,0x0,0x32,0x82,0xfc,0x86,0xbc,0x47,0x31,0x94,0x81,0xb2,0x51,0x3d,0xd4,0xc,0xb5,0x43,0xb9,0xa8,0x37,0x1a,0x84,0x46,0xa2,0xb,0xd0,0x64,0x74,0x31,0x9a,0x8f,0x16,0xa0,0x9b,0xd0,0x72,0xb4,0x1a,0x3d,0x8c,0x36,0xa1,0xe7,0xd0,0xab,0x68,0xf,0xda,0x8f,0x3e,0x43,0xc7,0x30,0xc0,0xe8,0x18,0x7,0x33,0xc4,0x6c,0x30,0x2e,0xc6,0xc3,0x42,0xb1,0x38,0x2c,0x9,0x93,0x63,0xcb,0xb1,0x22,0xac,0xc,0xab,0xc6,0x1a,0xb0,0x56,0xac,0x3,0xbb,0x89,0xf5,0x63,0xcf,0xb1,0x77,0x4,0x12,0x81,0x45,0xc0,0x9,0x36,0x4,0x77,0x42,0x20,0x61,0x1e,0x41,0x48,0x58,0x4c,0x58,0x4e,0xd8,0x48,0xa8,0x20,0x1c,0x24,0x34,0x11,0xda,0x9,0x37,0x9,0x3,0x84,0x51,0xc2,0x27,0x22,0x93,0xa8,0x4b,0xb4,0x26,0xba,0x11,0xf9,0xc4,0x18,0x62,0x32,0x31,0x87,0x58,0x48,0x2c,0x23,0xd6,0x12,0x8f,0x13,0x2f,0x10,0x7b,0x88,0x43,0xc4,0x37,0x24,0x12,0x89,0x43,0x32,0x27,0xb9,0x90,0x2,0x49,0xb1,0xa4,0x54,0xd2,0x12,0xd2,0x46,0xd2,0x6e,0x52,0x23,0xe9,0x2c,0xa9,0x9b,0x34,0x48,0x1a,0x23,0x93,0xc9,0xda,0x64,0x6b,0xb2,0x7,0x39,0x94,0x2c,0x20,0x2b,0xc8,0x85,0xe4,0x9d,0xe4,0xc3,0xe4,0x33,0xe4,0x1b,0xe4,0x21,0xf2,0x5b,0xa,0x9d,0x62,0x40,0x71,0xa4,0xf8,0x53,0xe2,0x28,0x52,0xca,0x6a,0x4a,0x19,0xe5,0x10,0xe5,0x34,0xe5,0x6,0x65,0x98,0x32,0x41,0x55,0xa3,0x9a,0x52,0xdd,0xa8,0xa1,0x54,0x11,0x35,0x8f,0x5a,0x42,0xad,0xa1,0xb6,0x52,0xaf,0x51,0x87,0xa8,0x13,0x34,0x75,0x9a,0x39,0xcd,0x83,0x16,0x49,0x4b,0xa5,0xad,0xa2,0x95,0xd3,0x1a,0x68,0x17,0x68,0xf7,0x69,0xaf,0xe8,0x74,0xba,0x11,0xdd,0x95,0x1e,0x4e,0x97,0xd0,0x57,0xd2,0xcb,0xe9,0x47,0xe8,0x97,0xe8,0x3,0xf4,0x77,0xc,0xd,0x86,0x15,0x83,0xc7,0x88,0x67,0x28,0x19,0x9b,0x18,0x7,0x18,0x67,0x19,0x77,0x18,0xaf,0x98,0x4c,0xa6,0x19,0xd3,0x8b,0x19,0xc7,0x54,0x30,0x37,0x31,0xeb,0x98,0xe7,0x99,0xf,0x99,0x6f,0x55,0x58,0x2a,0xb6,0x2a,0x7c,0x15,0x91,0xca,0xa,0x95,0x4a,0x95,0x26,0x95,0x1b,0x2a,0x2f,0x54,0xa9,0xaa,0xa6,0xaa,0xde,0xaa,0xb,0x55,0xf3,0x55,0xcb,0x54,0x8f,0xa9,0x5e,0x53,0x7d,0xae,0x46,0x55,0x33,0x53,0xe3,0xa9,0x9,0xd4,0x96,0xab,0x55,0xaa,0x9d,0x50,0xeb,0x53,0x1b,0x53,0x67,0xa9,0x3b,0xa8,0x87,0xaa,0x67,0xa8,0x6f,0x54,0x3f,0xa4,0x7e,0x59,0xfd,0x89,0x6,0x59,0xc3,0x4c,0xc3,0x4f,0x43,0xa4,0x51,0xa0,0xb1,0x5f,0xe3,0xbc,0xc6,0x20,0xb,0x63,0x19,0xb3,0x78,0x2c,0x21,0x6b,0xd,0xab,0x86,0x75,0x81,0x35,0xc4,0x26,0xb1,0xcd,0xd9,0x7c,0x76,0x2a,0xbb,0x98,0xfd,0x1d,0xbb,0x8b,0x3d,0xaa,0xa9,0xa1,0x39,0x43,0x33,0x4a,0x33,0x57,0xb3,0x52,0xf3,0x94,0x66,0x3f,0x7,0xe3,0x98,0x71,0xf8,0x9c,0x74,0x4e,0x9,0xe7,0x28,0xa7,0x97,0xf3,0x7e,0x8a,0xde,0x14,0xef,0x29,0xe2,0x29,0x1b,0xa6,0x34,0x4c,0xb9,0x31,0x65,0x5c,0x6b,0xaa,0x96,0x97,0x96,0x58,0xab,0x48,0xab,0x51,0xab,0x47,0xeb,0xbd,0x36,0xae,0xed,0xa7,0x9d,0xa6,0xbd,0x45,0xbb,0x59,0xfb,0x81,0xe,0x41,0xc7,0x4a,0x27,0x5c,0x27,0x47,0x67,0x8f,0xce,0x5,0x9d,0xe7,0x53,0xd9,0x53,0xdd,0xa7,0xa,0xa7,0x16,0x4d,0x3d,0x3a,0xf5,0xae,0x2e,0xaa,0x6b,0xa5,0x1b,0xa1,0xbb,0x44,0x77,0xbf,0x6e,0xa7,0xee,0x98,0x9e,0xbe,0x5e,0x80,0x9e,0x4c,0x6f,0xa7,0xde,0x79,0xbd,0xe7,0xfa,0x1c,0x7d,0x2f,0xfd,0x54,0xfd,0x6d,0xfa,0xa7,0xf5,0x47,0xc,0x58,0x6,0xb3,0xc,0x24,0x6,0xdb,0xc,0xce,0x18,0x3c,0xc5,0x35,0x71,0x6f,0x3c,0x1d,0x2f,0xc7,0xdb,0xf1,0x51,0x43,0x5d,0xc3,0x40,0x43,0xa5,0x61,0x95,0x61,0x97,0xe1,0x84,0x91,0xb9,0xd1,0x3c,0xa3,0xd5,0x46,0x8d,0x46,0xf,0x8c,0x69,0xc6,0x5c,0xe3,0x24,0xe3,0x6d,0xc6,0x6d,0xc6,0xa3,0x26,0x6,0x26,0x21,0x26,0x4b,0x4d,0xea,0x4d,0xee,0x9a,0x52,0x4d,0xb9,0xa6,0x29,0xa6,0x3b,0x4c,0x3b,0x4c,0xc7,0xcd,0xcc,0xcd,0xa2,0xcd,0xd6,0x99,0x35,0x9b,0x3d,0x31,0xd7,0x32,0xe7,0x9b,0xe7,0x9b,0xd7,0x9b,0xdf,0xb7,0x60,0x5a,0x78,0x5a,0x2c,0xb6,0xa8,0xb6,0xb8,0x65,0x49,0xb2,0xe4,0x5a,0xa6,0x59,0xee,0xb6,0xbc,0x6e,0x85,0x5a,0x39,0x59,0xa5,0x58,0x55,0x5a,0x5d,0xb3,0x46,0xad,0x9d,0xad,0x25,0xd6,0xbb,0xad,0xbb,0xa7,0x11,0xa7,0xb9,0x4e,0x93,0x4e,0xab,0x9e,0xd6,0x67,0xc3,0xb0,0xf1,0xb6,0xc9,0xb6,0xa9,0xb7,0x19,0xb0,0xe5,0xd8,0x6,0xdb,0xae,0xb6,0x6d,0xb6,0x7d,0x61,0x67,0x62,0x17,0x67,0xb7,0xc5,0xae,0xc3,0xee,0x93,0xbd,0x93,0x7d,0xba,0x7d,0x8d,0xfd,0x3d,0x7,0xd,0x87,0xd9,0xe,0xab,0x1d,0x5a,0x1d,0x7e,0x73,0xb4,0x72,0x14,0x3a,0x56,0x3a,0xde,0x9a,0xce,0x9c,0xee,0x3f,0x7d,0xc5,0xf4,0x96,0xe9,0x2f,0x67,0x58,0xcf,0x10,0xcf,0xd8,0x33,0xe3,0xb6,0x13,0xcb,0x29,0xc4,0x69,0x9d,0x53,0x9b,0xd3,0x47,0x67,0x17,0x67,0xb9,0x73,0x83,0xf3,0x88,0x8b,0x89,0x4b,0x82,0xcb,0x2e,0x97,0x3e,0x2e,0x9b,0x1b,0xc6,0xdd,0xc8,0xbd,0xe4,0x4a,0x74,0xf5,0x71,0x5d,0xe1,0x7a,0xd2,0xf5,0x9d,0x9b,0xb3,0x9b,0xc2,0xed,0xa8,0xdb,0xaf,0xee,0x36,0xee,0x69,0xee,0x87,0xdc,0x9f,0xcc,0x34,0x9f,0x29,0x9e,0x59,0x33,0x73,0xd0,0xc3,0xc8,0x43,0xe0,0x51,0xe5,0xd1,0x3f,0xb,0x9f,0x95,0x30,0x6b,0xdf,0xac,0x7e,0x4f,0x43,0x4f,0x81,0x67,0xb5,0xe7,0x23,0x2f,0x63,0x2f,0x91,0x57,0xad,0xd7,0xb0,0xb7,0xa5,0x77,0xaa,0xf7,0x61,0xef,0x17,0x3e,0xf6,0x3e,0x72,0x9f,0xe3,0x3e,0xe3,0x3c,0x37,0xde,0x32,0xde,0x59,0x5f,0xcc,0x37,0xc0,0xb7,0xc8,0xb7,0xcb,0x4f,0xc3,0x6f,0x9e,0x5f,0x85,0xdf,0x43,0x7f,0x23,0xff,0x64,0xff,0x7a,0xff,0xd1,0x0,0xa7,0x80,0x25,0x1,0x67,0x3,0x89,0x81,0x41,0x81,0x5b,0x2,0xfb,0xf8,0x7a,0x7c,0x21,0xbf,0x8e,0x3f,0x3a,0xdb,0x65,0xf6,0xb2,0xd9,0xed,0x41,0x8c,0xa0,0xb9,0x41,0x15,0x41,0x8f,0x82,0xad,0x82,0xe5,0xc1,0xad,0x21,0x68,0xc8,0xec,0x90,0xad,0x21,0xf7,0xe7,0x98,0xce,0x91,0xce,0x69,0xe,0x85,0x50,0x7e,0xe8,0xd6,0xd0,0x7,0x61,0xe6,0x61,0x8b,0xc3,0x7e,0xc,0x27,0x85,0x87,0x85,0x57,0x86,0x3f,0x8e,0x70,0x88,0x58,0x1a,0xd1,0x31,0x97,0x35,0x77,0xd1,0xdc,0x43,0x73,0xdf,0x44,0xfa,0x44,0x96,0x44,0xde,0x9b,0x67,0x31,0x4f,0x39,0xaf,0x2d,0x4a,0x35,0x2a,0x3e,0xaa,0x2e,0x6a,0x3c,0xda,0x37,0xba,0x34,0xba,0x3f,0xc6,0x2e,0x66,0x59,0xcc,0xd5,0x58,0x9d,0x58,0x49,0x6c,0x4b,0x1c,0x39,0x2e,0x2a,0xae,0x36,0x6e,0x6c,0xbe,0xdf,0xfc,0xed,0xf3,0x87,0xe2,0x9d,0xe2,0xb,0xe3,0x7b,0x17,0x98,0x2f,0xc8,0x5d,0x70,0x79,0xa1,0xce,0xc2,0xf4,0x85,0xa7,0x16,0xa9,0x2e,0x12,0x2c,0x3a,0x96,0x40,0x4c,0x88,0x4e,0x38,0x94,0xf0,0x41,0x10,0x2a,0xa8,0x16,0x8c,0x25,0xf2,0x13,0x77,0x25,0x8e,0xa,0x79,0xc2,0x1d,0xc2,0x67,0x22,0x2f,0xd1,0x36,0xd1,0x88,0xd8,0x43,0x5c,0x2a,0x1e,0x4e,0xf2,0x48,0x2a,0x4d,0x7a,0x92,0xec,0x91,0xbc,0x35,0x79,0x24,0xc5,0x33,0xa5,0x2c,0xe5,0xb9,0x84,0x27,0xa9,0x90,0xbc,0x4c,0xd,0x4c,0xdd,0x9b,0x3a,0x9e,0x16,0x9a,0x76,0x20,0x6d,0x32,0x3d,0x3a,0xbd,0x31,0x83,0x92,0x91,0x90,0x71,0x42,0xaa,0x21,0x4d,0x93,0xb6,0x67,0xea,0x67,0xe6,0x66,0x76,0xcb,0xac,0x65,0x85,0xb2,0xfe,0xc5,0x6e,0x8b,0xb7,0x2f,0x1e,0x95,0x7,0xc9,0x6b,0xb3,0x90,0xac,0x5,0x59,0x2d,0xa,0xb6,0x42,0xa6,0xe8,0x54,0x5a,0x28,0xd7,0x2a,0x7,0xb2,0x67,0x65,0x57,0x66,0xbf,0xcd,0x89,0xca,0x39,0x96,0xab,0x9e,0x2b,0xcd,0xed,0xcc,0xb3,0xca,0xdb,0x90,0x37,0x9c,0xef,0x9f,0xff,0xed,0x12,0xc2,0x12,0xe1,0x92,0xb6,0xa5,0x86,0x4b,0x57,0x2d,0x1d,0x58,0xe6,0xbd,0xac,0x6a,0x39,0xb2,0x3c,0x71,0x79,0xdb,0xa,0xe3,0x15,0x5,0x2b,0x86,0x56,0x6,0xac,0x3c,0xb8,0x8a,0xb6,0x2a,0x6d,0xd5,0x4f,0xab,0xed,0x57,0x97,0xae,0x7e,0xbd,0x26,0x7a,0x4d,0x6b,0x81,0x5e,0xc1,0xca,0x82,0xc1,0xb5,0x1,0x6b,0xeb,0xb,0x55,0xa,0xe5,0x85,0x7d,0xeb,0xdc,0xd7,0xed,0x5d,0x4f,0x58,0x2f,0x59,0xdf,0xb5,0x61,0xfa,0x86,0x9d,0x1b,0x3e,0x15,0x89,0x8a,0xae,0x14,0xdb,0x17,0x97,0x15,0x7f,0xd8,0x28,0xdc,0x78,0xe5,0x1b,0x87,0x6f,0xca,0xbf,0x99,0xdc,0x94,0xb4,0xa9,0xab,0xc4,0xb9,0x64,0xcf,0x66,0xd2,0x66,0xe9,0xe6,0xde,0x2d,0x9e,0x5b,0xe,0x96,0xaa,0x97,0xe6,0x97,0xe,0x6e,0xd,0xd9,0xda,0xb4,0xd,0xdf,0x56,0xb4,0xed,0xf5,0xf6,0x45,0xdb,0x2f,0x97,0xcd,0x28,0xdb,0xbb,0x83,0xb6,0x43,0xb9,0xa3,0xbf,0x3c,0xb8,0xbc,0x65,0xa7,0xc9,0xce,0xcd,0x3b,0x3f,0x54,0xa4,0x54,0xf4,0x54,0xfa,0x54,0x36,0xee,0xd2,0xdd,0xb5,0x61,0xd7,0xf8,0x6e,0xd1,0xee,0x1b,0x7b,0xbc,0xf6,0x34,0xec,0xd5,0xdb,0x5b,0xbc,0xf7,0xfd,0x3e,0xc9,0xbe,0xdb,0x55,0x1,0x55,0x4d,0xd5,0x66,0xd5,0x65,0xfb,0x49,0xfb,0xb3,0xf7,0x3f,0xae,0x89,0xaa,0xe9,0xf8,0x96,0xfb,0x6d,0x5d,0xad,0x4e,0x6d,0x71,0xed,0xc7,0x3,0xd2,0x3,0xfd,0x7,0x23,0xe,0xb6,0xd7,0xb9,0xd4,0xd5,0x1d,0xd2,0x3d,0x54,0x52,0x8f,0xd6,0x2b,0xeb,0x47,0xe,0xc7,0x1f,0xbe,0xfe,0x9d,0xef,0x77,0x2d,0xd,0x36,0xd,0x55,0x8d,0x9c,0xc6,0xe2,0x23,0x70,0x44,0x79,0xe4,0xe9,0xf7,0x9,0xdf,0xf7,0x1e,0xd,0x3a,0xda,0x76,0x8c,0x7b,0xac,0xe1,0x7,0xd3,0x1f,0x76,0x1d,0x67,0x1d,0x2f,0x6a,0x42,0x9a,0xf2,0x9a,0x46,0x9b,0x53,0x9a,0xfb,0x5b,0x62,0x5b,0xba,0x4f,0xcc,0x3e,0xd1,0xd6,0xea,0xde,0x7a,0xfc,0x47,0xdb,0x1f,0xf,0x9c,0x34,0x3c,0x59,0x79,0x4a,0xf3,0x54,0xc9,0x69,0xda,0xe9,0x82,0xd3,0x93,0x67,0xf2,0xcf,0x8c,0x9d,0x95,0x9d,0x7d,0x7e,0x2e,0xf9,0xdc,0x60,0xdb,0xa2,0xb6,0x7b,0xe7,0x63,0xce,0xdf,0x6a,0xf,0x6f,0xef,0xba,0x10,0x74,0xe1,0xd2,0x45,0xff,0x8b,0xe7,0x3b,0xbc,0x3b,0xce,0x5c,0xf2,0xb8,0x74,0xf2,0xb2,0xdb,0xe5,0x13,0x57,0xb8,0x57,0x9a,0xaf,0x3a,0x5f,0x6d,0xea,0x74,0xea,0x3c,0xfe,0x93,0xd3,0x4f,0xc7,0xbb,0x9c,0xbb,0x9a,0xae,0xb9,0x5c,0x6b,0xb9,0xee,0x7a,0xbd,0xb5,0x7b,0x66,0xf7,0xe9,0x1b,0x9e,0x37,0xce,0xdd,0xf4,0xbd,0x79,0xf1,0x16,0xff,0xd6,0xd5,0x9e,0x39,0x3d,0xdd,0xbd,0xf3,0x7a,0x6f,0xf7,0xc5,0xf7,0xf5,0xdf,0x16,0xdd,0x7e,0x72,0x27,0xfd,0xce,0xcb,0xbb,0xd9,0x77,0x27,0xee,0xad,0xbc,0x4f,0xbc,0x5f,0xf4,0x40,0xed,0x41,0xd9,0x43,0xdd,0x87,0xd5,0x3f,0x5b,0xfe,0xdc,0xd8,0xef,0xdc,0x7f,0x6a,0xc0,0x77,0xa0,0xf3,0xd1,0xdc,0x47,0xf7,0x6,0x85,0x83,0xcf,0xfe,0x91,0xf5,0x8f,0xf,0x43,0x5,0x8f,0x99,0x8f,0xcb,0x86,0xd,0x86,0xeb,0x9e,0x38,0x3e,0x39,0x39,0xe2,0x3f,0x72,0xfd,0xe9,0xfc,0xa7,0x43,0xcf,0x64,0xcf,0x26,0x9e,0x17,0xfe,0xa2,0xfe,0xcb,0xae,0x17,0x16,0x2f,0x7e,0xf8,0xd5,0xeb,0xd7,0xce,0xd1,0x98,0xd1,0xa1,0x97,0xf2,0x97,0x93,0xbf,0x6d,0x7c,0xa5,0xfd,0xea,0xc0,0xeb,0x19,0xaf,0xdb,0xc6,0xc2,0xc6,0x1e,0xbe,0xc9,0x78,0x33,0x31,0x5e,0xf4,0x56,0xfb,0xed,0xc1,0x77,0xdc,0x77,0x1d,0xef,0xa3,0xdf,0xf,0x4f,0xe4,0x7c,0x20,0x7f,0x28,0xff,0x68,0xf9,0xb1,0xf5,0x53,0xd0,0xa7,0xfb,0x93,0x19,0x93,0x93,0xff,0x4,0x3,0x98,0xf3,0xfc,0xef,0x35,0x94,0x82,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x35,0x0,0x32,0x0,0x3b,0x6,0x66,0x54,0x53,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xa,0x15,0x2,0x2a,0x1d,0xd,0x22,0xcf,0xc9,0x0,0x0,0x1,0x42,0x49,0x44,0x41,0x54,0x38,0xcb,0xa5,0x93,0x4d,0x4e,0xc3,0x30,0x10,0x85,0x3f,0x3b,0x4e,0x42,0x5b,0xd4,0xaa,0x15,0xb7,0xe9,0x92,0x8b,0xd0,0x3,0x70,0x1a,0xe,0x40,0x39,0x8,0xcb,0x9e,0x6,0x55,0x48,0x15,0x85,0x24,0xfe,0x19,0x16,0x99,0x80,0x8b,0x42,0xbb,0xe8,0x48,0xa3,0x91,0x6c,0xcf,0xf3,0xb3,0xdf,0x1b,0x43,0x1f,0x6,0xb0,0x9a,0x85,0x56,0xc3,0x69,0x8,0x90,0x80,0xa8,0x35,0x1,0x62,0xf4,0x60,0x1,0x54,0xc0,0x44,0x6b,0xa5,0x6b,0x26,0x6b,0x8e,0x40,0xa7,0xf9,0xa5,0x35,0x3a,0xbd,0xad,0x2,0x6e,0x81,0x25,0x30,0x7,0xa6,0xba,0x96,0x3,0x74,0xc0,0x27,0x70,0x0,0xde,0x81,0xf,0xa0,0x1d,0x0,0x26,0xc0,0x72,0xbd,0xbe,0x7f,0xac,0xeb,0x9b,0x4d,0x8,0xa1,0x54,0x76,0x59,0x18,0x71,0xce,0xf9,0xb6,0x6d,0x9e,0x77,0xbb,0xd7,0x27,0x65,0xe4,0x5d,0x46,0x7f,0x5e,0x55,0xf5,0x66,0xbf,0x7f,0x9b,0xa6,0x14,0x19,0xb,0x6b,0x8b,0x72,0xb5,0xba,0xdb,0x0,0x2f,0xca,0xa4,0xc8,0x9f,0x30,0xb,0xc1,0xd7,0x29,0x45,0x44,0x64,0x14,0x20,0xa5,0x48,0x8,0xbe,0x6,0x66,0xda,0x63,0x5d,0xf6,0x89,0x65,0x4a,0x49,0x44,0xe4,0x5f,0x80,0x1e,0x24,0x9,0x50,0xe,0x9f,0xec,0x32,0x19,0x8d,0x88,0xd0,0xef,0x8f,0x3,0x88,0x30,0x80,0xf,0xea,0xe1,0x4e,0xd1,0x87,0xdb,0xcf,0x31,0x38,0xdd,0x73,0x99,0x4c,0x22,0x12,0x11,0x49,0x67,0x0,0xc,0x22,0xf1,0xe7,0xfc,0x0,0x30,0x98,0xc4,0x8b,0x88,0xb9,0xcc,0x20,0x19,0xc0,0x6b,0x8f,0x58,0xb5,0xa4,0x7,0x8e,0xd6,0x16,0xad,0xb5,0x26,0x7b,0xef,0x6f,0xf6,0x32,0x1a,0x8a,0xc2,0x75,0xc0,0x51,0x7b,0x92,0x53,0xa4,0x16,0x38,0xb4,0x6d,0xb3,0x5d,0x2c,0x56,0xf,0x21,0xf8,0x72,0x6c,0x16,0xca,0xd2,0x75,0x4d,0xd3,0x6c,0xd5,0x3,0x2d,0x10,0x7,0x9,0xeb,0x3f,0x56,0x9e,0xa9,0x54,0x17,0xad,0x7c,0xf5,0x30,0x99,0x6b,0xc7,0xf9,0x1b,0xc9,0xc8,0xb3,0xec,0x84,0x2f,0xf7,0x27,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -255,7 +295,7 @@ static const unsigned char popup_unchecked_png[]={
static const unsigned char popup_window_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x40,0x8,0x6,0x0,0x0,0x0,0x13,0x7d,0xf7,0x96,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xc2,0x0,0xc2,0x0,0xcc,0x6a,0x6f,0xcc,0x71,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x12,0x0,0x3,0x34,0x19,0x79,0x8d,0xec,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x1,0x64,0x49,0x44,0x41,0x54,0x58,0x85,0xed,0x97,0x3f,0x4e,0x2,0x41,0x14,0xc6,0x7f,0x33,0x2c,0x7f,0x62,0x34,0x84,0x92,0x25,0xf1,0x0,0x1e,0xc3,0xb,0x48,0xec,0xf4,0x2,0xd4,0x34,0x56,0x96,0x56,0x36,0xc4,0x92,0x13,0xd0,0x19,0xd,0xbd,0xc7,0xf0,0x0,0x26,0x2c,0x8d,0x81,0x10,0x35,0x61,0x99,0x61,0xc7,0x82,0x37,0x48,0x8,0xd1,0xcd,0x4a,0x42,0x33,0x2f,0x79,0xc9,0x4e,0xe6,0xfb,0x7e,0xf3,0xcd,0x6c,0xf5,0xe0,0xd0,0xa5,0x36,0x5a,0xc7,0x71,0x7c,0xa9,0x94,0xea,0x28,0xa5,0xce,0x77,0x89,0x9d,0x73,0x2f,0xce,0xb9,0x7e,0x92,0x24,0x8f,0x40,0x6,0x38,0x5,0x68,0xa0,0x14,0xc7,0xf1,0x4d,0xb3,0xd9,0xbc,0xeb,0xf5,0xfa,0xbf,0x9e,0xd8,0xed,0x76,0x18,0x8f,0xc7,0xb7,0x49,0x92,0xdc,0x3,0x4b,0x5,0x44,0x40,0xb5,0xd5,0x6a,0xbd,0xe,0x6,0xcf,0xa7,0x79,0x62,0x5f,0x5d,0x5d,0xbc,0x8d,0x46,0xa3,0x33,0x20,0xd5,0x40,0x9,0xa8,0x29,0xa5,0x72,0x99,0x1,0x44,0x5b,0x3,0x4a,0x1e,0x50,0xc9,0x6b,0xde,0xa8,0x8a,0x7,0x68,0xa0,0x5c,0x0,0x50,0x6,0xb4,0x46,0xfe,0x40,0x1,0x80,0x6,0x94,0x7,0x14,0x2d,0x55,0xe4,0xe4,0xb5,0xd9,0xc7,0xf8,0x57,0x5,0x40,0x0,0x4,0xc0,0x9e,0x0,0xd1,0xe6,0xe2,0xfa,0xba,0x5d,0x1c,0x60,0xad,0xa5,0x5e,0x6f,0xe4,0x32,0xcd,0x66,0xd3,0xf5,0xf7,0xe1,0xdf,0x20,0x0,0x2,0x20,0x0,0x2,0x20,0x0,0x2,0x20,0x0,0xf6,0x7,0x70,0x1e,0xe0,0x0,0x9c,0x73,0xef,0xb9,0x9d,0x3f,0x5a,0xe7,0x13,0x64,0xc6,0x98,0xa1,0x31,0xe9,0x9f,0x66,0x63,0x52,0x8c,0x31,0x43,0x56,0x83,0x27,0x11,0xb0,0x4,0xec,0x64,0x32,0x79,0x0,0x8e,0xa2,0x28,0x6a,0x6b,0xad,0xab,0xbb,0xcc,0x59,0x96,0xa5,0xd6,0xda,0x27,0xd1,0x5a,0x64,0xf0,0xac,0x1,0xc7,0x40,0x43,0xfa,0x84,0xd5,0x48,0xb7,0xfd,0x3e,0x19,0xb0,0x0,0x3e,0x80,0xa9,0xf4,0xa7,0x4f,0x30,0x97,0xd,0x44,0x54,0x66,0x35,0x4f,0xfa,0x81,0xcc,0x89,0xce,0x0,0x5f,0xa2,0x9d,0xfb,0x4,0x5a,0xae,0x52,0x91,0x34,0x55,0x31,0xeb,0x2d,0x40,0x26,0x90,0x54,0xcc,0xb,0xc0,0x7e,0x3,0xa,0x34,0x6f,0x6c,0x6b,0x15,0x5c,0x54,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x2a,0x0,0x0,0x0,0x46,0x8,0x6,0x0,0x0,0x0,0xba,0xf5,0x6,0x7a,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xa,0x14,0x17,0x39,0x1b,0x27,0xff,0x2d,0x90,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x3,0x82,0x49,0x44,0x41,0x54,0x68,0xde,0xed,0x5a,0xdd,0x6a,0x13,0x41,0x14,0xfe,0xce,0xcc,0x64,0xb7,0x55,0x63,0x8b,0xb6,0x96,0xa,0x52,0x11,0x4,0xbd,0x10,0xd1,0x52,0xf0,0x42,0x1f,0x40,0xbc,0xf0,0xda,0xbb,0x8a,0x2f,0xe1,0x23,0x88,0xef,0xe0,0x73,0xf8,0x14,0xe2,0xa5,0xb7,0x2d,0xc5,0x6a,0xa4,0x96,0xc6,0x5a,0xd2,0x6c,0x33,0x73,0xbc,0xd8,0xd9,0x36,0xa6,0x9b,0xdd,0xd9,0x74,0x67,0xba,0xd1,0x1e,0x58,0x8,0x21,0x99,0xf3,0xed,0x77,0xce,0x77,0x7e,0x36,0x1,0x2e,0xec,0xc2,0x9a,0x6d,0x54,0xf6,0x81,0xef,0x5f,0xbb,0xcf,0x1,0x7c,0x0,0xb0,0xec,0x9,0xc3,0x37,0x0,0x6f,0x0,0x7c,0x3c,0x2b,0xd0,0x5f,0x5a,0x27,0x6d,0xc3,0xda,0xb,0x4a,0x41,0x12,0x52,0x46,0xfb,0x47,0x83,0xde,0xd5,0xa2,0xcf,0x29,0x87,0xb3,0xda,0x3,0x3d,0xf0,0x16,0x52,0x83,0x1,0xa4,0x8c,0xda,0xcc,0x8c,0xb3,0x2,0xd,0x62,0xc6,0xd4,0x0,0xb4,0xec,0x6e,0xeb,0xb0,0x5a,0x18,0xd,0x2,0xd4,0x98,0xe9,0x0,0x6a,0xa6,0x85,0x51,0x33,0x35,0x8c,0xd6,0x21,0xa6,0xb2,0xbb,0xfd,0xaf,0x18,0xad,0x45,0x4c,0xc6,0x3f,0xce,0x9a,0xea,0xe8,0x14,0x84,0x9e,0x42,0x85,0xfe,0xe1,0xe3,0x7b,0x0,0x80,0xcf,0x9f,0xbe,0xe4,0xcf,0x4,0x5,0x0,0xe5,0xca,0xad,0x3b,0x71,0xca,0x28,0x7b,0xbd,0x86,0xed,0xd1,0xea,0x7d,0xb0,0x31,0xa7,0xae,0x22,0x46,0xe9,0x68,0x90,0xc8,0x50,0x8c,0x96,0x15,0x7f,0x55,0x90,0x12,0x97,0xa2,0x56,0xbc,0x18,0xaa,0x3c,0xfd,0xad,0x9,0x77,0xa0,0x4,0x40,0x30,0x9b,0x56,0x28,0x46,0x97,0x6e,0x2c,0xdf,0xec,0xfc,0xf8,0xd6,0x5,0x70,0xb8,0xf6,0xe4,0x81,0x6,0x0,0x22,0x82,0x10,0x2,0x33,0x33,0xb3,0x63,0x81,0xb6,0x0,0x5c,0x11,0x42,0xde,0x6,0x80,0x10,0x81,0x57,0x4a,0x2d,0x3,0x38,0xb2,0x97,0xce,0x8,0xd2,0xda,0xa0,0xd7,0xeb,0x15,0xe7,0x68,0xa6,0xfa,0xeb,0xd7,0x16,0xbc,0x3,0x95,0x42,0xe6,0x8a,0x9b,0xd2,0xba,0x93,0xb,0x94,0xec,0x17,0x62,0x22,0x5a,0x5c,0x7f,0xbd,0xbe,0x99,0x24,0xc9,0x8a,0x31,0x9e,0x56,0x11,0x21,0x11,0x45,0xd1,0xa6,0x10,0xf2,0x2e,0x80,0x5d,0x0,0xfb,0x96,0x55,0x4e,0x59,0x4d,0xc1,0x8a,0xc6,0x6c,0x99,0x44,0x62,0x38,0x8a,0xc3,0x8c,0x12,0xa8,0x39,0x40,0x6d,0x14,0x29,0x77,0xe1,0x24,0x9a,0x6,0x46,0x9,0x44,0xd4,0x9c,0xe5,0x6e,0x14,0x24,0xa5,0x2a,0x2,0x91,0x80,0x94,0xb2,0x2,0x50,0xe,0x9c,0x7,0x42,0xa4,0x20,0x85,0x44,0xab,0x15,0x39,0x0,0x65,0x6,0x98,0xfd,0xe1,0xb4,0xe7,0x8f,0x5a,0x1c,0xc7,0x0,0x4,0x94,0x54,0x88,0xe3,0xd9,0x62,0xa0,0x26,0x3b,0xc7,0x23,0xa5,0x6c,0x7d,0x8c,0x36,0xe9,0xb5,0xd5,0x67,0x13,0x3c,0x80,0x38,0x41,0xeb,0x87,0x51,0x87,0x54,0x53,0xe5,0xe7,0x64,0x7c,0xfa,0x4b,0xd2,0xbc,0x59,0x62,0xd4,0x9f,0x38,0x6f,0x1d,0xb9,0x9e,0xed,0x1c,0x7a,0xe,0x1c,0x7a,0xae,0x14,0x7a,0x9d,0x86,0xc0,0xbb,0x98,0xc0,0x76,0x5e,0x1a,0xcf,0x75,0x9,0xa3,0xda,0xe6,0x8f,0x47,0x31,0x81,0xad,0xf,0x7d,0x36,0x31,0x9d,0x88,0x9e,0x3,0x8b,0xbe,0xa2,0x98,0xd8,0x6,0xc7,0xa7,0x9c,0x5c,0x48,0x28,0x67,0xd4,0xd8,0xc8,0xfb,0x52,0x13,0xe3,0x74,0xb5,0xcf,0x29,0x59,0xa2,0x44,0x4b,0x36,0x3d,0xd9,0x2b,0x9f,0xb9,0x5a,0xaa,0x5e,0x9e,0xd8,0x3f,0xa3,0x39,0x44,0x54,0x62,0xd4,0xb7,0x90,0x8e,0x33,0xd4,0xe1,0x78,0x7,0x46,0x4d,0xb1,0x3c,0xeb,0x79,0xe4,0x50,0x5a,0xe,0x54,0xf9,0x11,0x69,0x9d,0xf3,0xd7,0x98,0x18,0x26,0x2f,0xf4,0x55,0x19,0xe5,0x0,0x1d,0x9f,0x1d,0xde,0x55,0x4e,0x5a,0xf2,0xd8,0xeb,0x79,0xcc,0x8,0xc9,0xfc,0x6f,0x32,0x6a,0x8e,0xc7,0x6,0x9f,0xbd,0x3e,0xb7,0xea,0x57,0x9d,0x9e,0xc0,0x1,0x7a,0x7d,0xee,0x4c,0x52,0x75,0x70,0x1e,0xb3,0x7c,0xf9,0x5e,0xee,0x26,0x1b,0x9c,0x7d,0xa6,0x28,0xb9,0xf9,0x53,0x4e,0x37,0xec,0x71,0x67,0xe2,0x31,0xbd,0x64,0x82,0x9d,0x29,0x40,0xe8,0x1d,0x48,0x10,0xe7,0x17,0xf3,0x6a,0x3e,0x94,0x7b,0x78,0x3c,0x85,0x9e,0xdc,0x56,0x68,0x51,0x50,0xd8,0x78,0x6b,0x7b,0xa3,0xd3,0x8a,0x62,0x6f,0xf,0x71,0x1,0xc0,0x18,0x8d,0x56,0x14,0xaf,0x6c,0x6d,0x6f,0x74,0x32,0xbf,0x6b,0xab,0x4f,0x79,0x82,0xd0,0x37,0xc3,0x44,0x3,0x12,0xd4,0xc9,0x97,0x28,0xd9,0x64,0x42,0x3,0x1d,0xeb,0xb3,0x8,0xa8,0x6,0xd0,0xa7,0xf2,0xbf,0x46,0xd5,0x50,0xf3,0x9,0x0,0xfa,0x27,0x4d,0xdb,0x1d,0xa8,0x6,0x90,0x0,0x38,0x90,0x52,0xee,0x29,0xe5,0xef,0xc1,0xb4,0x52,0xa,0x52,0xc9,0x3d,0x0,0x7,0xd6,0xa7,0xae,0x52,0x9e,0xc,0x80,0x43,0x0,0xdd,0x9d,0x9f,0x9d,0x77,0xb,0xb,0x4b,0x6f,0xf5,0x40,0xcf,0xd7,0xdd,0x9d,0x8,0x4,0x29,0xe5,0xee,0xce,0x4e,0xe7,0x3d,0x80,0xae,0xf5,0x69,0xda,0xed,0x39,0xe7,0x4e,0x2b,0x1,0xc4,0x0,0x2e,0x3,0x98,0x7,0x30,0x67,0x5f,0xc7,0x18,0xf7,0xcb,0xc5,0x64,0xb3,0x5d,0xdf,0x32,0xd9,0x5,0x90,0xb1,0xda,0xcf,0x63,0xb5,0x88,0xd1,0xc4,0xbe,0x1e,0x0,0xf8,0xd,0x20,0xb2,0x37,0x50,0x57,0x49,0x33,0x43,0x29,0x76,0x68,0x1,0x26,0xf9,0x9b,0x5e,0x31,0x33,0xd9,0x2f,0x78,0xd9,0x25,0x6b,0x62,0x73,0x94,0x55,0x6d,0xc1,0x99,0x73,0xa8,0x34,0xe1,0xa6,0xc1,0x63,0x7b,0xf9,0xe2,0x15,0xf6,0xba,0xbb,0x8d,0xef,0x4c,0x8d,0xb1,0x3f,0x4,0x3,0x19,0xf6,0x18,0xa6,0x30,0xaf,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -285,7 +325,7 @@ static const unsigned char reference_border_png[]={
static const unsigned char scroll_bg_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x8,0x8,0x6,0x0,0x0,0x0,0xc4,0xf,0xbe,0x8b,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x26,0x0,0x26,0x0,0x26,0x59,0xf,0xde,0x74,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x14,0x17,0x37,0x2c,0x8d,0x3d,0xc,0x64,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0x3f,0x49,0x44,0x41,0x54,0x18,0x95,0xad,0x8e,0x31,0xa,0x0,0x20,0xc,0x3,0xaf,0xda,0x47,0xf4,0xe5,0xf6,0xb3,0x4a,0x5d,0x1c,0x54,0x50,0x17,0xf,0x42,0x96,0x24,0x44,0xcc,0x8c,0x1b,0x69,0x78,0x1,0x62,0x53,0x1,0x90,0xb1,0x10,0xb5,0xb6,0xa5,0xa9,0x9a,0x1,0x24,0xf1,0xe0,0x5f,0xc0,0x55,0x33,0xb3,0x0,0x9f,0x4f,0x1e,0xe9,0xf,0x1d,0xb,0x68,0x95,0x6b,0x4f,0xeb,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0xc,0x0,0x0,0x0,0xc,0x8,0x6,0x0,0x0,0x0,0x56,0x75,0x5c,0xe7,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xb,0xd,0x15,0x25,0x28,0x6d,0xad,0xf4,0x10,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x1,0x3c,0x49,0x44,0x41,0x54,0x28,0xcf,0x95,0x92,0x31,0x6e,0x13,0x61,0x10,0x46,0xdf,0xcc,0x44,0xd8,0xff,0x2e,0xb,0x34,0xb,0x92,0x23,0x4b,0x14,0xc8,0x5b,0xa5,0xe2,0x18,0x88,0x3,0x20,0x25,0x7,0x40,0xb4,0xb9,0x49,0x44,0x4d,0x81,0x14,0xe,0x80,0x38,0x6,0x7,0x20,0xa1,0x0,0x59,0xa4,0x60,0x85,0x8,0x59,0xbc,0xb,0xb6,0xff,0x19,0x8a,0xc5,0xd,0x28,0x45,0x9e,0xf4,0x15,0xdf,0xa7,0x27,0x4d,0x33,0x2,0xf0,0xf4,0xc9,0xb3,0x3d,0xa0,0x6,0x1a,0x60,0xe,0x24,0x46,0x6,0x60,0x9,0x7c,0x0,0xda,0xb7,0xef,0xde,0x6c,0xe5,0xaf,0xfc,0xa8,0xeb,0x7e,0xbc,0xf8,0xda,0x7e,0x39,0xea,0x87,0xd5,0x6d,0xf7,0x30,0x0,0x55,0xc9,0x45,0x2a,0x7f,0xde,0xaf,0xf7,0x5f,0x57,0xd5,0xdd,0x97,0xc0,0x47,0x6b,0x16,0x7,0xf,0xae,0xba,0xcb,0xe3,0x4f,0x9f,0xcf,0x9f,0x6f,0xb7,0xdb,0xa4,0x6a,0x6a,0xa6,0x98,0x29,0x22,0xaa,0xeb,0xcd,0x7a,0xfa,0xfd,0xf2,0xdb,0xe3,0x94,0x4a,0x9d,0x4c,0xa6,0xef,0x15,0x68,0xda,0xf6,0xe2,0x50,0x44,0xcc,0xcc,0x30,0x33,0x54,0xc7,0xec,0xba,0x88,0x58,0xdb,0x5e,0x1c,0x2,0xcd,0x1e,0x30,0xef,0x87,0x55,0x35,0x4a,0xca,0xbf,0xa8,0x2a,0x11,0x41,0x3f,0xac,0x2a,0x60,0xae,0x40,0xe1,0x1e,0x2a,0xc2,0xb5,0x88,0x80,0x7b,0x28,0x50,0x28,0x37,0x44,0x81,0x5e,0x55,0x3c,0xe2,0x7a,0x29,0x2,0x54,0xc5,0x81,0x5e,0x81,0x65,0x91,0xca,0xce,0xdd,0x71,0xf7,0xff,0xe4,0xdd,0x5e,0xa4,0xb2,0x3,0x96,0xa,0x9c,0xd5,0xf5,0xec,0x34,0x22,0x72,0xce,0x99,0x9c,0x33,0xee,0x63,0x76,0x3d,0x22,0x72,0x5d,0xcf,0x4e,0x81,0x33,0x6b,0x16,0x7,0xc3,0x64,0x32,0x3d,0x4f,0xa9,0xb4,0xcd,0xfa,0xd7,0x62,0xbd,0xf9,0x7d,0x2b,0x67,0x97,0xf1,0x5a,0x78,0x91,0xca,0xab,0xfd,0xd9,0xc3,0x57,0x77,0xaa,0x7b,0x27,0xc0,0x52,0x6e,0xfa,0x1a,0x7f,0x0,0x2,0xd3,0x92,0x1e,0xd2,0x75,0x7c,0x7f,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -330,12 +370,12 @@ static const unsigned char scroll_button_up_hl_png[]={
static const unsigned char scroll_grabber_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x8,0x8,0x6,0x0,0x0,0x0,0xc4,0xf,0xbe,0x8b,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x26,0x0,0x26,0x0,0x26,0x59,0xf,0xde,0x74,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x14,0x17,0x25,0x29,0x85,0xa3,0x88,0x38,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0x72,0x49,0x44,0x41,0x54,0x18,0x95,0x7d,0xcd,0xb1,0x9,0xc3,0x30,0x0,0x44,0xd1,0x17,0x21,0x91,0x42,0x10,0xdc,0x4,0x34,0x80,0x77,0xc8,0x4,0x6e,0x32,0xb0,0x1b,0xf,0xe2,0x26,0x4d,0x6a,0x37,0xc2,0x5d,0x40,0x45,0x1a,0x1b,0x4c,0x20,0xfe,0xe5,0xbf,0x3b,0xee,0x52,0x4a,0x71,0x46,0x8c,0x31,0x1a,0x86,0x67,0x87,0x19,0x7b,0x7b,0x41,0x3f,0x4d,0xe3,0x1a,0x36,0x31,0xa3,0x3b,0xc,0x6f,0x78,0x41,0x6c,0xad,0x39,0x2c,0x77,0xae,0xb8,0xb7,0xd6,0x84,0x94,0xd2,0xdf,0xff,0x94,0x92,0x90,0x73,0x86,0xf7,0x4f,0xf6,0xc1,0x92,0x73,0x16,0x6a,0xad,0xf0,0xd8,0xe4,0xce,0x8a,0x7e,0xcb,0xce,0xf9,0x2,0x99,0xd9,0x19,0x5e,0xac,0x65,0x2e,0x22,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0xc,0x0,0x0,0x0,0xc,0x8,0x6,0x0,0x0,0x0,0x56,0x75,0x5c,0xe7,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xb,0xd,0x16,0x26,0x17,0xf2,0xa0,0x34,0xb7,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0xd4,0x49,0x44,0x41,0x54,0x28,0xcf,0xbd,0x8f,0x31,0x4a,0x3,0x61,0x10,0x85,0xdf,0xfb,0x67,0xb1,0x91,0x3d,0x80,0x6d,0xca,0x20,0x39,0xc1,0x7a,0xe,0x59,0x2c,0xc4,0x3b,0x8,0xb9,0x43,0xf0,0xe,0x62,0x11,0x82,0xa0,0x65,0x8a,0xd4,0xe6,0x4,0x31,0x24,0x67,0x48,0xbd,0xe5,0xbf,0x33,0x2f,0x8d,0xbf,0xae,0x6c,0xad,0xf,0x6,0x66,0x98,0xf7,0x31,0xf3,0x80,0xbf,0x16,0x87,0xc3,0x5d,0xfb,0x70,0xd,0xe0,0x49,0x52,0x3,0xe0,0x92,0xe4,0x6,0xc0,0xe3,0x72,0xf5,0xbc,0x1f,0x1,0xed,0xed,0xfd,0x8c,0xe4,0xb6,0xef,0xfb,0x3a,0x14,0x0,0x80,0xc4,0x84,0xaa,0xaa,0x3a,0x49,0xcd,0xea,0xf5,0x65,0x7,0x0,0xe9,0x9b,0x24,0x17,0x39,0xe7,0xda,0xdd,0xa1,0x10,0x14,0x82,0xbb,0x23,0xe7,0x5c,0x93,0x5c,0x14,0x5f,0x55,0x1a,0x8f,0x68,0x3c,0x2,0x90,0x7e,0xfd,0xec,0x11,0xb0,0x88,0x9b,0x11,0x20,0x9,0x92,0x46,0x40,0xd9,0x15,0xa5,0x41,0x98,0x2d,0x7,0x60,0xa9,0xaf,0x90,0x1f,0x23,0x20,0x22,0xe6,0x66,0xd6,0x91,0xfc,0xb9,0x46,0xc2,0xcc,0xba,0x88,0x98,0x17,0x9f,0x95,0xe6,0x70,0xfc,0x3c,0x4d,0xa7,0xb3,0xb5,0x99,0x4d,0x52,0x4a,0x57,0x66,0x76,0x61,0x66,0x1b,0x1,0xed,0xdb,0xfb,0x72,0x87,0x7f,0xd3,0x19,0xa9,0x1d,0x69,0xa0,0x52,0x76,0xa0,0x72,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char scroll_grabber_hl_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x8,0x8,0x6,0x0,0x0,0x0,0xc4,0xf,0xbe,0x8b,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x26,0x0,0x26,0x0,0x26,0x59,0xf,0xde,0x74,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x14,0x17,0x25,0x15,0xaa,0xcc,0xf4,0xbf,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0x86,0x49,0x44,0x41,0x54,0x18,0x95,0x7d,0x8e,0xb1,0xa,0x83,0x30,0x18,0x84,0xbf,0x36,0x81,0x6e,0xe5,0xf,0xad,0x6e,0xe,0x11,0x97,0x2e,0xfa,0xae,0x6e,0x7d,0x29,0xa1,0xce,0xa5,0xae,0x5,0x7,0x83,0x53,0xb,0xf9,0xa1,0x4b,0x94,0xe,0xe2,0x8d,0x77,0xdf,0x71,0x77,0x68,0xdb,0x3b,0x7b,0xb2,0x0,0xc3,0xf0,0xba,0x86,0x30,0x75,0x40,0x91,0xfc,0x51,0xc4,0x55,0xde,0x97,0xb3,0x5,0x8,0x61,0xea,0xea,0xba,0xb9,0x18,0x63,0x1,0x50,0x8d,0xe7,0xbe,0x7f,0x3c,0x81,0xdc,0xa6,0x46,0xb1,0x84,0x0,0xc6,0xd8,0x13,0x90,0x1,0x1c,0x77,0xf,0xfc,0x1,0xa3,0x6a,0xfc,0x2e,0xa6,0x6a,0xfc,0x0,0xef,0xf5,0xa4,0x88,0xab,0xd2,0x66,0x96,0x98,0x20,0xe2,0x6e,0x2b,0xe0,0x7d,0x39,0x3,0xf9,0xd6,0xc4,0xf,0x70,0x6e,0x25,0xf5,0x5c,0xbc,0xd7,0xd3,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0xc,0x0,0x0,0x0,0xc,0x8,0x6,0x0,0x0,0x0,0x56,0x75,0x5c,0xe7,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xb,0xd,0x16,0xe,0x1f,0xa1,0x26,0x12,0x2f,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x1,0x3,0x49,0x44,0x41,0x54,0x28,0xcf,0xbd,0x90,0x3f,0x4b,0xc3,0x50,0x14,0xc5,0x4f,0xf2,0xf2,0xca,0x33,0x12,0xf3,0x10,0x44,0x3a,0x74,0x10,0x91,0xae,0x75,0x13,0xe7,0xea,0x17,0xe8,0xa7,0x10,0x67,0x41,0xec,0x1e,0x4,0x67,0xf1,0x5b,0xf4,0x3,0x88,0xb3,0xb8,0xd9,0xb5,0x88,0xb8,0x28,0x5,0xb5,0x35,0xf4,0xc5,0x90,0xe6,0xbe,0x3f,0x4e,0x29,0xd,0x75,0xd5,0x3,0x7,0xee,0xb9,0xf0,0xe3,0x1e,0x2e,0xf0,0xd7,0xf2,0x96,0xc3,0xcd,0xf0,0x65,0x8f,0xc8,0x5c,0xce,0xd2,0xa2,0x6b,0x1d,0x36,0xa4,0x14,0x3,0xde,0x60,0xe7,0x27,0x9d,0x9d,0xa7,0x15,0xe0,0x7a,0xf8,0xdc,0x9e,0x7e,0xe4,0xf,0xe3,0xb1,0x92,0x45,0xa1,0xe1,0xe0,0xb0,0x26,0x38,0x9a,0xcd,0x28,0xdd,0xdc,0xa,0xf,0x4e,0x3b,0xbb,0x23,0x0,0x8,0x2a,0x20,0x2f,0xca,0xe4,0xed,0xf5,0x4b,0x7e,0xab,0xf9,0xe2,0xa2,0x2a,0x4a,0x58,0xa3,0xa5,0x88,0x82,0x4,0x40,0xaf,0x6,0x4c,0x27,0x59,0x37,0x53,0x39,0x34,0xd9,0x5a,0xe7,0x4c,0x19,0x4c,0x3e,0xd5,0x71,0x95,0x17,0x40,0x49,0x1a,0x46,0x13,0xac,0x36,0x35,0xc0,0x78,0xc,0xb4,0xb4,0xf3,0xab,0x41,0x48,0x71,0xc7,0x98,0x83,0xa1,0x79,0xcd,0x8c,0x39,0x8,0x29,0x6e,0x57,0x0,0xcb,0xfd,0x7e,0xdc,0x8a,0x53,0xbe,0xce,0xe1,0x39,0x82,0xe7,0x8,0x41,0x18,0x20,0x6e,0xc5,0xa9,0xe5,0x7e,0xff,0xd7,0xb7,0x9e,0xdd,0x3f,0xb6,0x29,0xa7,0x24,0x7b,0x9f,0x1d,0xc1,0xd9,0x28,0xda,0x8e,0x7,0x41,0xd8,0xb8,0xb8,0x3a,0xdc,0x1f,0xe1,0xdf,0xf4,0x3,0x35,0xb3,0x71,0xac,0x4,0x64,0x3e,0xbb,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -365,17 +405,22 @@ static const unsigned char tab_png[]={
static const unsigned char tab_behind_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x4c,0x0,0x4a,0x0,0x4e,0x88,0x29,0x6a,0xb6,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x10,0x13,0x3a,0x0,0x82,0x20,0x21,0x41,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0x92,0x49,0x44,0x41,0x54,0x38,0x8d,0xed,0x8f,0x3b,0xe,0xc2,0x30,0x10,0x5,0xc7,0x89,0xa5,0x80,0x45,0x81,0xb,0x6f,0x7,0x27,0xe0,0x73,0x36,0x4e,0xc2,0xd9,0xf8,0xd4,0x34,0x74,0xa1,0x30,0x5,0x12,0x34,0xab,0xa5,0x31,0xad,0x83,0x4,0x65,0xa6,0x7c,0xda,0x37,0x4f,0xb,0x3f,0xe2,0x80,0x0,0xcc,0x81,0x19,0xd0,0x96,0xac,0x86,0x1,0xa,0x3c,0x80,0xbb,0x2f,0xe5,0xd,0xb0,0x0,0x26,0x5f,0xa,0x5e,0xc0,0x15,0x38,0xfa,0xb2,0xbc,0x5c,0xaf,0xb6,0x7b,0x49,0x32,0x35,0xb5,0xaa,0xc0,0xb5,0xce,0xfa,0x5b,0xff,0x3c,0x9d,0xf,0x3b,0xe0,0xe2,0x1,0xf,0x74,0x92,0x24,0xa8,0x2a,0x39,0xe7,0xea,0x7c,0x8c,0xd1,0x49,0x92,0x0,0x74,0x80,0x6f,0x3e,0x62,0x53,0x1b,0x2c,0x3,0xe4,0x9c,0x31,0x35,0x28,0xaf,0x36,0xf5,0xf3,0x61,0x46,0xc1,0x28,0xf8,0x8b,0xe0,0xd,0xec,0x2e,0x27,0x7c,0x4,0xc2,0x7d,0x9a,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x35,0x0,0x32,0x0,0x3b,0x6,0x66,0x54,0x53,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xa,0x15,0x0,0x20,0xc,0x9e,0xf9,0xd3,0xdf,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0xf2,0x49,0x44,0x41,0x54,0x38,0xcb,0xe5,0x92,0x41,0x4a,0x3,0x41,0x10,0x45,0x5f,0xf7,0x4c,0xa6,0x3,0x19,0xc8,0x30,0x3,0xc9,0x2d,0xc4,0x95,0x7,0xf1,0x34,0x59,0xb8,0xf4,0x3c,0xde,0xc0,0xb,0x64,0x15,0xbc,0x85,0x48,0xa2,0x81,0x28,0x76,0xba,0x26,0xed,0xc2,0xea,0xd0,0x86,0x84,0x28,0xba,0xf3,0x43,0x51,0x45,0xf3,0xff,0xa7,0x7e,0x77,0x1b,0x3e,0x61,0x0,0xab,0x55,0x68,0x37,0x5a,0x0,0x51,0x6b,0x7,0xf4,0xda,0x77,0x40,0x4c,0xa4,0x2,0xa8,0x0,0x7,0xc,0x75,0x4e,0x46,0x64,0xc2,0x2d,0xf0,0xe,0x78,0x9d,0xfb,0x52,0x49,0x15,0x30,0x2,0x1a,0x60,0xac,0xb3,0x3b,0xd8,0xc0,0x3,0xaf,0xc0,0x1a,0x78,0xd1,0x73,0x9f,0xc,0x1c,0xd0,0x5c,0x5e,0x5c,0x5d,0x77,0xed,0xf4,0x26,0xc8,0xb6,0x26,0x46,0xbe,0xc0,0x18,0x6,0x65,0xb5,0x59,0xae,0x1e,0x6f,0x17,0xf,0xf3,0x3b,0x40,0x80,0x90,0xc,0x86,0xc0,0xb8,0x6b,0x27,0xb3,0xd5,0xf3,0x53,0x2d,0x12,0x38,0x86,0xb2,0x1c,0xd4,0x5d,0x3b,0x99,0x1,0xf7,0xc0,0x6,0x78,0xb3,0x59,0xfe,0x91,0x48,0x68,0x4e,0x89,0x1,0x44,0x2,0x22,0xa1,0xd1,0x88,0x15,0x50,0xd8,0xec,0x12,0x5d,0x3c,0x5c,0xfb,0x8,0x94,0xe3,0x54,0x63,0x6c,0xf6,0x84,0x86,0xef,0x63,0xaf,0xb1,0xfc,0x12,0x36,0xfb,0x20,0xf1,0x7,0xba,0xbd,0x26,0x19,0xf4,0x80,0x37,0xe6,0x7c,0xa,0xe5,0x78,0xd5,0xc4,0x3f,0x89,0xf0,0xdf,0xd,0x3e,0x0,0xbd,0x2e,0x4c,0x5c,0x6d,0xbf,0x37,0x8b,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+};
+
+
+static const unsigned char tab_close_png[]={
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x12,0x0,0x0,0xb,0x12,0x1,0xd2,0xdd,0x7e,0xfc,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x1,0x1b,0x49,0x44,0x41,0x54,0x38,0x8d,0xcd,0x52,0xbb,0x4e,0xc4,0x40,0xc,0x9c,0x73,0xd2,0x50,0x38,0xd1,0x8a,0x82,0x36,0x3d,0x8,0xc4,0x43,0x88,0x13,0x12,0x20,0xf8,0x67,0x8a,0xfb,0x1,0xe,0x89,0x13,0x3d,0x47,0xb1,0x7f,0xb0,0x85,0x53,0x41,0xce,0xa6,0xd9,0x45,0xbe,0x24,0x1f,0x70,0x96,0x56,0x96,0xed,0x9d,0x91,0x3d,0x36,0x70,0x50,0x96,0x52,0xaa,0xbd,0x1f,0xd5,0xaa,0xb9,0x1a,0x79,0xb0,0x99,0x9d,0xc4,0x18,0x4d,0x55,0x2f,0xfd,0xc7,0x94,0x12,0xa9,0xea,0x53,0x8c,0xd1,0xcc,0xac,0xf1,0xb5,0x85,0x67,0x8b,0x31,0x1a,0x0,0x5,0x40,0xcc,0x7c,0x4b,0x44,0x9f,0x0,0x54,0x55,0x5f,0x44,0x64,0x5,0x60,0x7,0xa0,0xea,0xba,0x6e,0x31,0x21,0x48,0x29,0xd5,0xaa,0x7a,0x25,0x22,0xef,0x25,0xc7,0xcc,0x4b,0x33,0xb,0x7d,0xdf,0xbf,0xba,0xdc,0x29,0x11,0x7d,0x85,0x10,0x86,0x49,0x7,0x99,0xe4,0x5a,0x44,0xd6,0x73,0x1a,0x65,0xf0,0x77,0x8,0xe1,0x67,0xa2,0x1,0x0,0x84,0x10,0x6,0x22,0xda,0x30,0xf3,0x7d,0x4e,0x59,0x7e,0x60,0xe6,0xb,0x22,0xda,0x7a,0xf0,0x84,0x20,0x9b,0x9a,0x59,0xeb,0xe2,0xd2,0x65,0x53,0xc8,0x30,0x53,0x2c,0x23,0x54,0xaa,0xfa,0x9c,0x5,0x9b,0x1b,0xe1,0x8e,0x88,0x36,0x65,0xfe,0xbd,0xe,0x32,0xf8,0xd1,0x83,0x99,0xf9,0x9c,0x99,0x1f,0x4a,0x2c,0x22,0xeb,0xf1,0x8a,0xe7,0xd6,0xb8,0x3,0x50,0x65,0xc1,0xb6,0x0,0x4c,0x55,0x6f,0x44,0xe4,0xd,0xc0,0x0,0xa0,0xf6,0x6b,0xdc,0x3b,0xa4,0xa6,0x69,0x8e,0x33,0xf8,0x2c,0xab,0xfd,0x9b,0x85,0xfd,0x60,0xe6,0x25,0x80,0xaa,0x6d,0xdb,0xa3,0xb9,0x4b,0xfd,0x27,0xf1,0x7e,0xac,0x8f,0xf7,0x87,0x63,0x7f,0xc3,0xca,0xa9,0x49,0x35,0x25,0x97,0x14,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char tab_container_bg_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x4c,0x0,0x4a,0x0,0x4e,0x88,0x29,0x6a,0xb6,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xd,0xd7,0x0,0x0,0xd,0xd7,0x1,0x42,0x28,0x9b,0x78,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x10,0x13,0x37,0x38,0x1f,0x8c,0xe7,0x92,0x0,0x0,0x0,0xba,0x49,0x44,0x41,0x54,0x38,0x8d,0xed,0xd3,0x3b,0x4e,0x3,0x41,0x10,0x84,0xe1,0x6f,0x4c,0x4b,0x1e,0xaf,0x36,0x20,0xde,0x11,0x9c,0x80,0xc7,0xd9,0x38,0x9,0x67,0x33,0x76,0x4c,0x82,0xd6,0x31,0x1,0x82,0xb1,0x34,0xc8,0x4,0x6c,0xbc,0x6b,0xc9,0x9,0x1,0x1d,0xb6,0xba,0xfe,0x52,0x4b,0x55,0x9,0x1d,0xae,0xd1,0xe3,0xa,0xc9,0xfc,0x9c,0xf0,0x8d,0xf,0xbc,0xc7,0x24,0x7e,0xc0,0xd,0xf2,0x99,0x80,0x8a,0x37,0xbc,0xc4,0xe4,0x7c,0x7b,0x7f,0xf7,0xf8,0x5c,0x86,0xb2,0x89,0x88,0x59,0x40,0x6b,0xed,0x34,0x1e,0xc6,0xaf,0xdd,0x7e,0xfb,0x84,0xd7,0x40,0x60,0x5d,0x86,0xd2,0xd5,0x5a,0xd5,0x5a,0x67,0xed,0x73,0xce,0xa9,0xc,0xa5,0xdb,0xed,0xb7,0x6b,0xc4,0x6a,0xda,0xa7,0x88,0x58,0x14,0x43,0xad,0x55,0x44,0x30,0xbd,0xba,0x9a,0x3f,0x5f,0x9e,0x7f,0xc0,0x5f,0x2,0x9c,0x5a,0x6b,0x72,0xce,0x8b,0x82,0x9c,0xb3,0xd6,0x1a,0xbf,0x91,0x16,0x68,0x38,0x8e,0x87,0xf1,0xb3,0xc,0x65,0xd3,0xf7,0xfd,0x59,0x51,0xc6,0x11,0x2d,0x61,0x70,0x41,0x99,0x92,0xb,0xeb,0xfc,0x3,0x18,0xa7,0x44,0x3f,0xdc,0xad,0xd9,0x96,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0xa,0x45,0x69,0x43,0x43,0x50,0x49,0x43,0x43,0x20,0x70,0x72,0x6f,0x66,0x69,0x6c,0x65,0x0,0x0,0x78,0xda,0x9d,0x53,0x67,0x54,0x53,0xe9,0x16,0x3d,0xf7,0xde,0xf4,0x42,0x4b,0x88,0x80,0x94,0x4b,0x6f,0x52,0x15,0x8,0x20,0x52,0x42,0x8b,0x80,0x14,0x91,0x26,0x2a,0x21,0x9,0x10,0x4a,0x88,0x21,0xa1,0xd9,0x15,0x51,0xc1,0x11,0x45,0x45,0x4,0x1b,0xc8,0xa0,0x88,0x3,0x8e,0x8e,0x80,0x8c,0x15,0x51,0x2c,0xc,0x8a,0xa,0xd8,0x7,0xe4,0x21,0xa2,0x8e,0x83,0xa3,0x88,0x8a,0xca,0xfb,0xe1,0x7b,0xa3,0x6b,0xd6,0xbc,0xf7,0xe6,0xcd,0xfe,0xb5,0xd7,0x3e,0xe7,0xac,0xf3,0x9d,0xb3,0xcf,0x7,0xc0,0x8,0xc,0x96,0x48,0x33,0x51,0x35,0x80,0xc,0xa9,0x42,0x1e,0x11,0xe0,0x83,0xc7,0xc4,0xc6,0xe1,0xe4,0x2e,0x40,0x81,0xa,0x24,0x70,0x0,0x10,0x8,0xb3,0x64,0x21,0x73,0xfd,0x23,0x1,0x0,0xf8,0x7e,0x3c,0x3c,0x2b,0x22,0xc0,0x7,0xbe,0x0,0x1,0x78,0xd3,0xb,0x8,0x0,0xc0,0x4d,0x9b,0xc0,0x30,0x1c,0x87,0xff,0xf,0xea,0x42,0x99,0x5c,0x1,0x80,0x84,0x1,0xc0,0x74,0x91,0x38,0x4b,0x8,0x80,0x14,0x0,0x40,0x7a,0x8e,0x42,0xa6,0x0,0x40,0x46,0x1,0x80,0x9d,0x98,0x26,0x53,0x0,0xa0,0x4,0x0,0x60,0xcb,0x63,0x62,0xe3,0x0,0x50,0x2d,0x0,0x60,0x27,0x7f,0xe6,0xd3,0x0,0x80,0x9d,0xf8,0x99,0x7b,0x1,0x0,0x5b,0x94,0x21,0x15,0x1,0xa0,0x91,0x0,0x20,0x13,0x65,0x88,0x44,0x0,0x68,0x3b,0x0,0xac,0xcf,0x56,0x8a,0x45,0x0,0x58,0x30,0x0,0x14,0x66,0x4b,0xc4,0x39,0x0,0xd8,0x2d,0x0,0x30,0x49,0x57,0x66,0x48,0x0,0xb0,0xb7,0x0,0xc0,0xce,0x10,0xb,0xb2,0x0,0x8,0xc,0x0,0x30,0x51,0x88,0x85,0x29,0x0,0x4,0x7b,0x0,0x60,0xc8,0x23,0x23,0x78,0x0,0x84,0x99,0x0,0x14,0x46,0xf2,0x57,0x3c,0xf1,0x2b,0xae,0x10,0xe7,0x2a,0x0,0x0,0x78,0x99,0xb2,0x3c,0xb9,0x24,0x39,0x45,0x81,0x5b,0x8,0x2d,0x71,0x7,0x57,0x57,0x2e,0x1e,0x28,0xce,0x49,0x17,0x2b,0x14,0x36,0x61,0x2,0x61,0x9a,0x40,0x2e,0xc2,0x79,0x99,0x19,0x32,0x81,0x34,0xf,0xe0,0xf3,0xcc,0x0,0x0,0xa0,0x91,0x15,0x11,0xe0,0x83,0xf3,0xfd,0x78,0xce,0xe,0xae,0xce,0xce,0x36,0x8e,0xb6,0xe,0x5f,0x2d,0xea,0xbf,0x6,0xff,0x22,0x62,0x62,0xe3,0xfe,0xe5,0xcf,0xab,0x70,0x40,0x0,0x0,0xe1,0x74,0x7e,0xd1,0xfe,0x2c,0x2f,0xb3,0x1a,0x80,0x3b,0x6,0x80,0x6d,0xfe,0xa2,0x25,0xee,0x4,0x68,0x5e,0xb,0xa0,0x75,0xf7,0x8b,0x66,0xb2,0xf,0x40,0xb5,0x0,0xa0,0xe9,0xda,0x57,0xf3,0x70,0xf8,0x7e,0x3c,0x3c,0x45,0xa1,0x90,0xb9,0xd9,0xd9,0xe5,0xe4,0xe4,0xd8,0x4a,0xc4,0x42,0x5b,0x61,0xca,0x57,0x7d,0xfe,0x67,0xc2,0x5f,0xc0,0x57,0xfd,0x6c,0xf9,0x7e,0x3c,0xfc,0xf7,0xf5,0xe0,0xbe,0xe2,0x24,0x81,0x32,0x5d,0x81,0x47,0x4,0xf8,0xe0,0xc2,0xcc,0xf4,0x4c,0xa5,0x1c,0xcf,0x92,0x9,0x84,0x62,0xdc,0xe6,0x8f,0x47,0xfc,0xb7,0xb,0xff,0xfc,0x1d,0xd3,0x22,0xc4,0x49,0x62,0xb9,0x58,0x2a,0x14,0xe3,0x51,0x12,0x71,0x8e,0x44,0x9a,0x8c,0xf3,0x32,0xa5,0x22,0x89,0x42,0x92,0x29,0xc5,0x25,0xd2,0xff,0x64,0xe2,0xdf,0x2c,0xfb,0x3,0x3e,0xdf,0x35,0x0,0xb0,0x6a,0x3e,0x1,0x7b,0x91,0x2d,0xa8,0x5d,0x63,0x3,0xf6,0x4b,0x27,0x10,0x58,0x74,0xc0,0xe2,0xf7,0x0,0x0,0xf2,0xbb,0x6f,0xc1,0xd4,0x28,0x8,0x3,0x80,0x68,0x83,0xe1,0xcf,0x77,0xff,0xef,0x3f,0xfd,0x47,0xa0,0x25,0x0,0x80,0x66,0x49,0x92,0x71,0x0,0x0,0x5e,0x44,0x24,0x2e,0x54,0xca,0xb3,0x3f,0xc7,0x8,0x0,0x0,0x44,0xa0,0x81,0x2a,0xb0,0x41,0x1b,0xf4,0xc1,0x18,0x2c,0xc0,0x6,0x1c,0xc1,0x5,0xdc,0xc1,0xb,0xfc,0x60,0x36,0x84,0x42,0x24,0xc4,0xc2,0x42,0x10,0x42,0xa,0x64,0x80,0x1c,0x72,0x60,0x29,0xac,0x82,0x42,0x28,0x86,0xcd,0xb0,0x1d,0x2a,0x60,0x2f,0xd4,0x40,0x1d,0x34,0xc0,0x51,0x68,0x86,0x93,0x70,0xe,0x2e,0xc2,0x55,0xb8,0xe,0x3d,0x70,0xf,0xfa,0x61,0x8,0x9e,0xc1,0x28,0xbc,0x81,0x9,0x4,0x41,0xc8,0x8,0x13,0x61,0x21,0xda,0x88,0x1,0x62,0x8a,0x58,0x23,0x8e,0x8,0x17,0x99,0x85,0xf8,0x21,0xc1,0x48,0x4,0x12,0x8b,0x24,0x20,0xc9,0x88,0x14,0x51,0x22,0x4b,0x91,0x35,0x48,0x31,0x52,0x8a,0x54,0x20,0x55,0x48,0x1d,0xf2,0x3d,0x72,0x2,0x39,0x87,0x5c,0x46,0xba,0x91,0x3b,0xc8,0x0,0x32,0x82,0xfc,0x86,0xbc,0x47,0x31,0x94,0x81,0xb2,0x51,0x3d,0xd4,0xc,0xb5,0x43,0xb9,0xa8,0x37,0x1a,0x84,0x46,0xa2,0xb,0xd0,0x64,0x74,0x31,0x9a,0x8f,0x16,0xa0,0x9b,0xd0,0x72,0xb4,0x1a,0x3d,0x8c,0x36,0xa1,0xe7,0xd0,0xab,0x68,0xf,0xda,0x8f,0x3e,0x43,0xc7,0x30,0xc0,0xe8,0x18,0x7,0x33,0xc4,0x6c,0x30,0x2e,0xc6,0xc3,0x42,0xb1,0x38,0x2c,0x9,0x93,0x63,0xcb,0xb1,0x22,0xac,0xc,0xab,0xc6,0x1a,0xb0,0x56,0xac,0x3,0xbb,0x89,0xf5,0x63,0xcf,0xb1,0x77,0x4,0x12,0x81,0x45,0xc0,0x9,0x36,0x4,0x77,0x42,0x20,0x61,0x1e,0x41,0x48,0x58,0x4c,0x58,0x4e,0xd8,0x48,0xa8,0x20,0x1c,0x24,0x34,0x11,0xda,0x9,0x37,0x9,0x3,0x84,0x51,0xc2,0x27,0x22,0x93,0xa8,0x4b,0xb4,0x26,0xba,0x11,0xf9,0xc4,0x18,0x62,0x32,0x31,0x87,0x58,0x48,0x2c,0x23,0xd6,0x12,0x8f,0x13,0x2f,0x10,0x7b,0x88,0x43,0xc4,0x37,0x24,0x12,0x89,0x43,0x32,0x27,0xb9,0x90,0x2,0x49,0xb1,0xa4,0x54,0xd2,0x12,0xd2,0x46,0xd2,0x6e,0x52,0x23,0xe9,0x2c,0xa9,0x9b,0x34,0x48,0x1a,0x23,0x93,0xc9,0xda,0x64,0x6b,0xb2,0x7,0x39,0x94,0x2c,0x20,0x2b,0xc8,0x85,0xe4,0x9d,0xe4,0xc3,0xe4,0x33,0xe4,0x1b,0xe4,0x21,0xf2,0x5b,0xa,0x9d,0x62,0x40,0x71,0xa4,0xf8,0x53,0xe2,0x28,0x52,0xca,0x6a,0x4a,0x19,0xe5,0x10,0xe5,0x34,0xe5,0x6,0x65,0x98,0x32,0x41,0x55,0xa3,0x9a,0x52,0xdd,0xa8,0xa1,0x54,0x11,0x35,0x8f,0x5a,0x42,0xad,0xa1,0xb6,0x52,0xaf,0x51,0x87,0xa8,0x13,0x34,0x75,0x9a,0x39,0xcd,0x83,0x16,0x49,0x4b,0xa5,0xad,0xa2,0x95,0xd3,0x1a,0x68,0x17,0x68,0xf7,0x69,0xaf,0xe8,0x74,0xba,0x11,0xdd,0x95,0x1e,0x4e,0x97,0xd0,0x57,0xd2,0xcb,0xe9,0x47,0xe8,0x97,0xe8,0x3,0xf4,0x77,0xc,0xd,0x86,0x15,0x83,0xc7,0x88,0x67,0x28,0x19,0x9b,0x18,0x7,0x18,0x67,0x19,0x77,0x18,0xaf,0x98,0x4c,0xa6,0x19,0xd3,0x8b,0x19,0xc7,0x54,0x30,0x37,0x31,0xeb,0x98,0xe7,0x99,0xf,0x99,0x6f,0x55,0x58,0x2a,0xb6,0x2a,0x7c,0x15,0x91,0xca,0xa,0x95,0x4a,0x95,0x26,0x95,0x1b,0x2a,0x2f,0x54,0xa9,0xaa,0xa6,0xaa,0xde,0xaa,0xb,0x55,0xf3,0x55,0xcb,0x54,0x8f,0xa9,0x5e,0x53,0x7d,0xae,0x46,0x55,0x33,0x53,0xe3,0xa9,0x9,0xd4,0x96,0xab,0x55,0xaa,0x9d,0x50,0xeb,0x53,0x1b,0x53,0x67,0xa9,0x3b,0xa8,0x87,0xaa,0x67,0xa8,0x6f,0x54,0x3f,0xa4,0x7e,0x59,0xfd,0x89,0x6,0x59,0xc3,0x4c,0xc3,0x4f,0x43,0xa4,0x51,0xa0,0xb1,0x5f,0xe3,0xbc,0xc6,0x20,0xb,0x63,0x19,0xb3,0x78,0x2c,0x21,0x6b,0xd,0xab,0x86,0x75,0x81,0x35,0xc4,0x26,0xb1,0xcd,0xd9,0x7c,0x76,0x2a,0xbb,0x98,0xfd,0x1d,0xbb,0x8b,0x3d,0xaa,0xa9,0xa1,0x39,0x43,0x33,0x4a,0x33,0x57,0xb3,0x52,0xf3,0x94,0x66,0x3f,0x7,0xe3,0x98,0x71,0xf8,0x9c,0x74,0x4e,0x9,0xe7,0x28,0xa7,0x97,0xf3,0x7e,0x8a,0xde,0x14,0xef,0x29,0xe2,0x29,0x1b,0xa6,0x34,0x4c,0xb9,0x31,0x65,0x5c,0x6b,0xaa,0x96,0x97,0x96,0x58,0xab,0x48,0xab,0x51,0xab,0x47,0xeb,0xbd,0x36,0xae,0xed,0xa7,0x9d,0xa6,0xbd,0x45,0xbb,0x59,0xfb,0x81,0xe,0x41,0xc7,0x4a,0x27,0x5c,0x27,0x47,0x67,0x8f,0xce,0x5,0x9d,0xe7,0x53,0xd9,0x53,0xdd,0xa7,0xa,0xa7,0x16,0x4d,0x3d,0x3a,0xf5,0xae,0x2e,0xaa,0x6b,0xa5,0x1b,0xa1,0xbb,0x44,0x77,0xbf,0x6e,0xa7,0xee,0x98,0x9e,0xbe,0x5e,0x80,0x9e,0x4c,0x6f,0xa7,0xde,0x79,0xbd,0xe7,0xfa,0x1c,0x7d,0x2f,0xfd,0x54,0xfd,0x6d,0xfa,0xa7,0xf5,0x47,0xc,0x58,0x6,0xb3,0xc,0x24,0x6,0xdb,0xc,0xce,0x18,0x3c,0xc5,0x35,0x71,0x6f,0x3c,0x1d,0x2f,0xc7,0xdb,0xf1,0x51,0x43,0x5d,0xc3,0x40,0x43,0xa5,0x61,0x95,0x61,0x97,0xe1,0x84,0x91,0xb9,0xd1,0x3c,0xa3,0xd5,0x46,0x8d,0x46,0xf,0x8c,0x69,0xc6,0x5c,0xe3,0x24,0xe3,0x6d,0xc6,0x6d,0xc6,0xa3,0x26,0x6,0x26,0x21,0x26,0x4b,0x4d,0xea,0x4d,0xee,0x9a,0x52,0x4d,0xb9,0xa6,0x29,0xa6,0x3b,0x4c,0x3b,0x4c,0xc7,0xcd,0xcc,0xcd,0xa2,0xcd,0xd6,0x99,0x35,0x9b,0x3d,0x31,0xd7,0x32,0xe7,0x9b,0xe7,0x9b,0xd7,0x9b,0xdf,0xb7,0x60,0x5a,0x78,0x5a,0x2c,0xb6,0xa8,0xb6,0xb8,0x65,0x49,0xb2,0xe4,0x5a,0xa6,0x59,0xee,0xb6,0xbc,0x6e,0x85,0x5a,0x39,0x59,0xa5,0x58,0x55,0x5a,0x5d,0xb3,0x46,0xad,0x9d,0xad,0x25,0xd6,0xbb,0xad,0xbb,0xa7,0x11,0xa7,0xb9,0x4e,0x93,0x4e,0xab,0x9e,0xd6,0x67,0xc3,0xb0,0xf1,0xb6,0xc9,0xb6,0xa9,0xb7,0x19,0xb0,0xe5,0xd8,0x6,0xdb,0xae,0xb6,0x6d,0xb6,0x7d,0x61,0x67,0x62,0x17,0x67,0xb7,0xc5,0xae,0xc3,0xee,0x93,0xbd,0x93,0x7d,0xba,0x7d,0x8d,0xfd,0x3d,0x7,0xd,0x87,0xd9,0xe,0xab,0x1d,0x5a,0x1d,0x7e,0x73,0xb4,0x72,0x14,0x3a,0x56,0x3a,0xde,0x9a,0xce,0x9c,0xee,0x3f,0x7d,0xc5,0xf4,0x96,0xe9,0x2f,0x67,0x58,0xcf,0x10,0xcf,0xd8,0x33,0xe3,0xb6,0x13,0xcb,0x29,0xc4,0x69,0x9d,0x53,0x9b,0xd3,0x47,0x67,0x17,0x67,0xb9,0x73,0x83,0xf3,0x88,0x8b,0x89,0x4b,0x82,0xcb,0x2e,0x97,0x3e,0x2e,0x9b,0x1b,0xc6,0xdd,0xc8,0xbd,0xe4,0x4a,0x74,0xf5,0x71,0x5d,0xe1,0x7a,0xd2,0xf5,0x9d,0x9b,0xb3,0x9b,0xc2,0xed,0xa8,0xdb,0xaf,0xee,0x36,0xee,0x69,0xee,0x87,0xdc,0x9f,0xcc,0x34,0x9f,0x29,0x9e,0x59,0x33,0x73,0xd0,0xc3,0xc8,0x43,0xe0,0x51,0xe5,0xd1,0x3f,0xb,0x9f,0x95,0x30,0x6b,0xdf,0xac,0x7e,0x4f,0x43,0x4f,0x81,0x67,0xb5,0xe7,0x23,0x2f,0x63,0x2f,0x91,0x57,0xad,0xd7,0xb0,0xb7,0xa5,0x77,0xaa,0xf7,0x61,0xef,0x17,0x3e,0xf6,0x3e,0x72,0x9f,0xe3,0x3e,0xe3,0x3c,0x37,0xde,0x32,0xde,0x59,0x5f,0xcc,0x37,0xc0,0xb7,0xc8,0xb7,0xcb,0x4f,0xc3,0x6f,0x9e,0x5f,0x85,0xdf,0x43,0x7f,0x23,0xff,0x64,0xff,0x7a,0xff,0xd1,0x0,0xa7,0x80,0x25,0x1,0x67,0x3,0x89,0x81,0x41,0x81,0x5b,0x2,0xfb,0xf8,0x7a,0x7c,0x21,0xbf,0x8e,0x3f,0x3a,0xdb,0x65,0xf6,0xb2,0xd9,0xed,0x41,0x8c,0xa0,0xb9,0x41,0x15,0x41,0x8f,0x82,0xad,0x82,0xe5,0xc1,0xad,0x21,0x68,0xc8,0xec,0x90,0xad,0x21,0xf7,0xe7,0x98,0xce,0x91,0xce,0x69,0xe,0x85,0x50,0x7e,0xe8,0xd6,0xd0,0x7,0x61,0xe6,0x61,0x8b,0xc3,0x7e,0xc,0x27,0x85,0x87,0x85,0x57,0x86,0x3f,0x8e,0x70,0x88,0x58,0x1a,0xd1,0x31,0x97,0x35,0x77,0xd1,0xdc,0x43,0x73,0xdf,0x44,0xfa,0x44,0x96,0x44,0xde,0x9b,0x67,0x31,0x4f,0x39,0xaf,0x2d,0x4a,0x35,0x2a,0x3e,0xaa,0x2e,0x6a,0x3c,0xda,0x37,0xba,0x34,0xba,0x3f,0xc6,0x2e,0x66,0x59,0xcc,0xd5,0x58,0x9d,0x58,0x49,0x6c,0x4b,0x1c,0x39,0x2e,0x2a,0xae,0x36,0x6e,0x6c,0xbe,0xdf,0xfc,0xed,0xf3,0x87,0xe2,0x9d,0xe2,0xb,0xe3,0x7b,0x17,0x98,0x2f,0xc8,0x5d,0x70,0x79,0xa1,0xce,0xc2,0xf4,0x85,0xa7,0x16,0xa9,0x2e,0x12,0x2c,0x3a,0x96,0x40,0x4c,0x88,0x4e,0x38,0x94,0xf0,0x41,0x10,0x2a,0xa8,0x16,0x8c,0x25,0xf2,0x13,0x77,0x25,0x8e,0xa,0x79,0xc2,0x1d,0xc2,0x67,0x22,0x2f,0xd1,0x36,0xd1,0x88,0xd8,0x43,0x5c,0x2a,0x1e,0x4e,0xf2,0x48,0x2a,0x4d,0x7a,0x92,0xec,0x91,0xbc,0x35,0x79,0x24,0xc5,0x33,0xa5,0x2c,0xe5,0xb9,0x84,0x27,0xa9,0x90,0xbc,0x4c,0xd,0x4c,0xdd,0x9b,0x3a,0x9e,0x16,0x9a,0x76,0x20,0x6d,0x32,0x3d,0x3a,0xbd,0x31,0x83,0x92,0x91,0x90,0x71,0x42,0xaa,0x21,0x4d,0x93,0xb6,0x67,0xea,0x67,0xe6,0x66,0x76,0xcb,0xac,0x65,0x85,0xb2,0xfe,0xc5,0x6e,0x8b,0xb7,0x2f,0x1e,0x95,0x7,0xc9,0x6b,0xb3,0x90,0xac,0x5,0x59,0x2d,0xa,0xb6,0x42,0xa6,0xe8,0x54,0x5a,0x28,0xd7,0x2a,0x7,0xb2,0x67,0x65,0x57,0x66,0xbf,0xcd,0x89,0xca,0x39,0x96,0xab,0x9e,0x2b,0xcd,0xed,0xcc,0xb3,0xca,0xdb,0x90,0x37,0x9c,0xef,0x9f,0xff,0xed,0x12,0xc2,0x12,0xe1,0x92,0xb6,0xa5,0x86,0x4b,0x57,0x2d,0x1d,0x58,0xe6,0xbd,0xac,0x6a,0x39,0xb2,0x3c,0x71,0x79,0xdb,0xa,0xe3,0x15,0x5,0x2b,0x86,0x56,0x6,0xac,0x3c,0xb8,0x8a,0xb6,0x2a,0x6d,0xd5,0x4f,0xab,0xed,0x57,0x97,0xae,0x7e,0xbd,0x26,0x7a,0x4d,0x6b,0x81,0x5e,0xc1,0xca,0x82,0xc1,0xb5,0x1,0x6b,0xeb,0xb,0x55,0xa,0xe5,0x85,0x7d,0xeb,0xdc,0xd7,0xed,0x5d,0x4f,0x58,0x2f,0x59,0xdf,0xb5,0x61,0xfa,0x86,0x9d,0x1b,0x3e,0x15,0x89,0x8a,0xae,0x14,0xdb,0x17,0x97,0x15,0x7f,0xd8,0x28,0xdc,0x78,0xe5,0x1b,0x87,0x6f,0xca,0xbf,0x99,0xdc,0x94,0xb4,0xa9,0xab,0xc4,0xb9,0x64,0xcf,0x66,0xd2,0x66,0xe9,0xe6,0xde,0x2d,0x9e,0x5b,0xe,0x96,0xaa,0x97,0xe6,0x97,0xe,0x6e,0xd,0xd9,0xda,0xb4,0xd,0xdf,0x56,0xb4,0xed,0xf5,0xf6,0x45,0xdb,0x2f,0x97,0xcd,0x28,0xdb,0xbb,0x83,0xb6,0x43,0xb9,0xa3,0xbf,0x3c,0xb8,0xbc,0x65,0xa7,0xc9,0xce,0xcd,0x3b,0x3f,0x54,0xa4,0x54,0xf4,0x54,0xfa,0x54,0x36,0xee,0xd2,0xdd,0xb5,0x61,0xd7,0xf8,0x6e,0xd1,0xee,0x1b,0x7b,0xbc,0xf6,0x34,0xec,0xd5,0xdb,0x5b,0xbc,0xf7,0xfd,0x3e,0xc9,0xbe,0xdb,0x55,0x1,0x55,0x4d,0xd5,0x66,0xd5,0x65,0xfb,0x49,0xfb,0xb3,0xf7,0x3f,0xae,0x89,0xaa,0xe9,0xf8,0x96,0xfb,0x6d,0x5d,0xad,0x4e,0x6d,0x71,0xed,0xc7,0x3,0xd2,0x3,0xfd,0x7,0x23,0xe,0xb6,0xd7,0xb9,0xd4,0xd5,0x1d,0xd2,0x3d,0x54,0x52,0x8f,0xd6,0x2b,0xeb,0x47,0xe,0xc7,0x1f,0xbe,0xfe,0x9d,0xef,0x77,0x2d,0xd,0x36,0xd,0x55,0x8d,0x9c,0xc6,0xe2,0x23,0x70,0x44,0x79,0xe4,0xe9,0xf7,0x9,0xdf,0xf7,0x1e,0xd,0x3a,0xda,0x76,0x8c,0x7b,0xac,0xe1,0x7,0xd3,0x1f,0x76,0x1d,0x67,0x1d,0x2f,0x6a,0x42,0x9a,0xf2,0x9a,0x46,0x9b,0x53,0x9a,0xfb,0x5b,0x62,0x5b,0xba,0x4f,0xcc,0x3e,0xd1,0xd6,0xea,0xde,0x7a,0xfc,0x47,0xdb,0x1f,0xf,0x9c,0x34,0x3c,0x59,0x79,0x4a,0xf3,0x54,0xc9,0x69,0xda,0xe9,0x82,0xd3,0x93,0x67,0xf2,0xcf,0x8c,0x9d,0x95,0x9d,0x7d,0x7e,0x2e,0xf9,0xdc,0x60,0xdb,0xa2,0xb6,0x7b,0xe7,0x63,0xce,0xdf,0x6a,0xf,0x6f,0xef,0xba,0x10,0x74,0xe1,0xd2,0x45,0xff,0x8b,0xe7,0x3b,0xbc,0x3b,0xce,0x5c,0xf2,0xb8,0x74,0xf2,0xb2,0xdb,0xe5,0x13,0x57,0xb8,0x57,0x9a,0xaf,0x3a,0x5f,0x6d,0xea,0x74,0xea,0x3c,0xfe,0x93,0xd3,0x4f,0xc7,0xbb,0x9c,0xbb,0x9a,0xae,0xb9,0x5c,0x6b,0xb9,0xee,0x7a,0xbd,0xb5,0x7b,0x66,0xf7,0xe9,0x1b,0x9e,0x37,0xce,0xdd,0xf4,0xbd,0x79,0xf1,0x16,0xff,0xd6,0xd5,0x9e,0x39,0x3d,0xdd,0xbd,0xf3,0x7a,0x6f,0xf7,0xc5,0xf7,0xf5,0xdf,0x16,0xdd,0x7e,0x72,0x27,0xfd,0xce,0xcb,0xbb,0xd9,0x77,0x27,0xee,0xad,0xbc,0x4f,0xbc,0x5f,0xf4,0x40,0xed,0x41,0xd9,0x43,0xdd,0x87,0xd5,0x3f,0x5b,0xfe,0xdc,0xd8,0xef,0xdc,0x7f,0x6a,0xc0,0x77,0xa0,0xf3,0xd1,0xdc,0x47,0xf7,0x6,0x85,0x83,0xcf,0xfe,0x91,0xf5,0x8f,0xf,0x43,0x5,0x8f,0x99,0x8f,0xcb,0x86,0xd,0x86,0xeb,0x9e,0x38,0x3e,0x39,0x39,0xe2,0x3f,0x72,0xfd,0xe9,0xfc,0xa7,0x43,0xcf,0x64,0xcf,0x26,0x9e,0x17,0xfe,0xa2,0xfe,0xcb,0xae,0x17,0x16,0x2f,0x7e,0xf8,0xd5,0xeb,0xd7,0xce,0xd1,0x98,0xd1,0xa1,0x97,0xf2,0x97,0x93,0xbf,0x6d,0x7c,0xa5,0xfd,0xea,0xc0,0xeb,0x19,0xaf,0xdb,0xc6,0xc2,0xc6,0x1e,0xbe,0xc9,0x78,0x33,0x31,0x5e,0xf4,0x56,0xfb,0xed,0xc1,0x77,0xdc,0x77,0x1d,0xef,0xa3,0xdf,0xf,0x4f,0xe4,0x7c,0x20,0x7f,0x28,0xff,0x68,0xf9,0xb1,0xf5,0x53,0xd0,0xa7,0xfb,0x93,0x19,0x93,0x93,0xff,0x4,0x3,0x98,0xf3,0xfc,0xef,0x35,0x94,0x82,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xa,0x15,0x0,0x5,0x21,0x33,0xd5,0x5f,0x4d,0x0,0x0,0x1,0x3a,0x49,0x44,0x41,0x54,0x38,0xcb,0xa5,0x93,0x41,0x4a,0x3,0x51,0xc,0x86,0xbf,0x37,0xef,0xd1,0x11,0x5d,0x74,0x40,0xc1,0x5a,0xea,0x45,0xc4,0xa5,0x27,0xf0,0x34,0x73,0x84,0xe2,0x61,0x3c,0x81,0xee,0xc4,0x8b,0x8,0x76,0xd3,0xea,0x14,0x5a,0xe8,0x74,0xde,0x4b,0x5c,0x4c,0x46,0x2a,0xd4,0x3a,0xc5,0x40,0x20,0x8b,0xe4,0x4f,0xfe,0xf0,0xff,0xe,0x8,0xc0,0x0,0xc8,0x81,0x13,0xab,0x3d,0x90,0xf1,0x33,0x4,0x48,0xc0,0x16,0xd8,0x0,0x35,0xb0,0xed,0x86,0xcf,0x80,0x2,0x18,0x5a,0x9d,0x3,0xce,0x12,0x40,0x2d,0x6b,0x60,0xd,0x2c,0x81,0xa,0xdb,0x9e,0x3,0xc5,0xed,0xcd,0xdd,0xfd,0xf8,0xea,0xba,0x8c,0x29,0x16,0xaa,0xec,0xd,0xe7,0x20,0xf8,0x50,0xbd,0xcf,0xde,0xa6,0x2f,0xaf,0x4f,0x8f,0x40,0xc,0x76,0xf6,0x70,0x3c,0x9a,0x94,0xd5,0xe7,0xa2,0x88,0x31,0xa2,0xec,0x47,0x70,0x38,0x42,0x8,0xc5,0x78,0x34,0x29,0x81,0x67,0x60,0xf5,0x4d,0xa1,0x89,0x4d,0xd1,0xc4,0xe6,0xd7,0xe1,0x96,0x87,0xd2,0xc4,0x86,0x26,0x36,0x85,0x51,0x1d,0x4,0x7b,0x58,0x2e,0x22,0x88,0xa,0x7f,0x85,0xa2,0x88,0x8,0x46,0xdd,0x7,0xfb,0xb6,0x53,0x51,0x54,0x94,0x3e,0x61,0x7d,0xe,0xc8,0x42,0x47,0x2f,0x69,0xea,0x75,0x1,0x40,0xd2,0xd4,0x1,0x10,0x76,0x51,0x55,0x8f,0xba,0x80,0x5d,0x0,0x55,0x3d,0x2,0xa0,0xed,0xd3,0xe,0x40,0x5a,0xd0,0x84,0xf6,0xa4,0x20,0x2d,0x5,0x5,0x24,0x98,0x3c,0x6b,0x84,0xde,0x4f,0xa4,0xdd,0x53,0x3,0x29,0x33,0x6d,0xaf,0x71,0x59,0x95,0x79,0x8f,0xa8,0x1e,0xcc,0xcc,0x7b,0x70,0x59,0x65,0x92,0xde,0x6,0x33,0xc6,0x72,0xbe,0x98,0x4d,0x2f,0xce,0x2f,0xcb,0x24,0xa9,0xe0,0x80,0x96,0x7d,0x16,0x3e,0xe6,0x8b,0xd9,0x83,0xf9,0x61,0xe3,0x80,0xd3,0x7f,0x98,0x69,0x1d,0x8c,0x2,0x40,0x4,0x56,0xc7,0xda,0xf9,0xb,0x57,0x2d,0xbb,0xf5,0x2d,0xe4,0x89,0x1b,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char tab_current_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x4c,0x0,0x4a,0x0,0x4e,0x88,0x29,0x6a,0xb6,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x10,0x13,0x39,0x1d,0xca,0xb,0x1e,0x5b,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0x8e,0x49,0x44,0x41,0x54,0x38,0x8d,0xed,0x8f,0x3d,0xe,0xc2,0x30,0x18,0x43,0x5f,0x8a,0xa5,0x86,0x88,0x81,0xb9,0x11,0x9c,0x80,0x9f,0xb3,0x71,0x12,0xce,0x56,0xda,0x99,0x5,0x95,0x99,0x1,0xa9,0xdf,0x10,0x54,0x96,0xcc,0x29,0x23,0x43,0x3d,0x5a,0xf6,0xb3,0xec,0x80,0x0,0x6c,0x81,0xd,0xb0,0x2,0x1c,0x65,0x4d,0xc0,0x7,0x78,0x3,0x2f,0xe5,0xf2,0x9,0xd8,0x1,0xfe,0x47,0x80,0x1,0xf,0xe0,0xa6,0xbc,0xbc,0x3f,0x1e,0xce,0xd7,0xd8,0xc4,0xb5,0xa4,0x22,0x20,0xa5,0x34,0xd,0xcf,0x61,0xec,0xfa,0xf6,0x2,0xdc,0x5,0x8,0xa8,0x63,0x13,0x83,0x99,0x61,0x66,0xc5,0x79,0xef,0xbd,0x8b,0x4d,0xc,0x5d,0xdf,0xd6,0x80,0xaa,0xec,0x3b,0x49,0xb3,0x65,0x0,0x33,0x43,0x12,0xe4,0xab,0x55,0x39,0x3e,0xaf,0x5,0xb0,0x0,0xfe,0x3,0xf0,0x5,0xd9,0x71,0x24,0x5d,0x58,0x1b,0x63,0x82,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0xa,0x45,0x69,0x43,0x43,0x50,0x49,0x43,0x43,0x20,0x70,0x72,0x6f,0x66,0x69,0x6c,0x65,0x0,0x0,0x78,0xda,0x9d,0x53,0x67,0x54,0x53,0xe9,0x16,0x3d,0xf7,0xde,0xf4,0x42,0x4b,0x88,0x80,0x94,0x4b,0x6f,0x52,0x15,0x8,0x20,0x52,0x42,0x8b,0x80,0x14,0x91,0x26,0x2a,0x21,0x9,0x10,0x4a,0x88,0x21,0xa1,0xd9,0x15,0x51,0xc1,0x11,0x45,0x45,0x4,0x1b,0xc8,0xa0,0x88,0x3,0x8e,0x8e,0x80,0x8c,0x15,0x51,0x2c,0xc,0x8a,0xa,0xd8,0x7,0xe4,0x21,0xa2,0x8e,0x83,0xa3,0x88,0x8a,0xca,0xfb,0xe1,0x7b,0xa3,0x6b,0xd6,0xbc,0xf7,0xe6,0xcd,0xfe,0xb5,0xd7,0x3e,0xe7,0xac,0xf3,0x9d,0xb3,0xcf,0x7,0xc0,0x8,0xc,0x96,0x48,0x33,0x51,0x35,0x80,0xc,0xa9,0x42,0x1e,0x11,0xe0,0x83,0xc7,0xc4,0xc6,0xe1,0xe4,0x2e,0x40,0x81,0xa,0x24,0x70,0x0,0x10,0x8,0xb3,0x64,0x21,0x73,0xfd,0x23,0x1,0x0,0xf8,0x7e,0x3c,0x3c,0x2b,0x22,0xc0,0x7,0xbe,0x0,0x1,0x78,0xd3,0xb,0x8,0x0,0xc0,0x4d,0x9b,0xc0,0x30,0x1c,0x87,0xff,0xf,0xea,0x42,0x99,0x5c,0x1,0x80,0x84,0x1,0xc0,0x74,0x91,0x38,0x4b,0x8,0x80,0x14,0x0,0x40,0x7a,0x8e,0x42,0xa6,0x0,0x40,0x46,0x1,0x80,0x9d,0x98,0x26,0x53,0x0,0xa0,0x4,0x0,0x60,0xcb,0x63,0x62,0xe3,0x0,0x50,0x2d,0x0,0x60,0x27,0x7f,0xe6,0xd3,0x0,0x80,0x9d,0xf8,0x99,0x7b,0x1,0x0,0x5b,0x94,0x21,0x15,0x1,0xa0,0x91,0x0,0x20,0x13,0x65,0x88,0x44,0x0,0x68,0x3b,0x0,0xac,0xcf,0x56,0x8a,0x45,0x0,0x58,0x30,0x0,0x14,0x66,0x4b,0xc4,0x39,0x0,0xd8,0x2d,0x0,0x30,0x49,0x57,0x66,0x48,0x0,0xb0,0xb7,0x0,0xc0,0xce,0x10,0xb,0xb2,0x0,0x8,0xc,0x0,0x30,0x51,0x88,0x85,0x29,0x0,0x4,0x7b,0x0,0x60,0xc8,0x23,0x23,0x78,0x0,0x84,0x99,0x0,0x14,0x46,0xf2,0x57,0x3c,0xf1,0x2b,0xae,0x10,0xe7,0x2a,0x0,0x0,0x78,0x99,0xb2,0x3c,0xb9,0x24,0x39,0x45,0x81,0x5b,0x8,0x2d,0x71,0x7,0x57,0x57,0x2e,0x1e,0x28,0xce,0x49,0x17,0x2b,0x14,0x36,0x61,0x2,0x61,0x9a,0x40,0x2e,0xc2,0x79,0x99,0x19,0x32,0x81,0x34,0xf,0xe0,0xf3,0xcc,0x0,0x0,0xa0,0x91,0x15,0x11,0xe0,0x83,0xf3,0xfd,0x78,0xce,0xe,0xae,0xce,0xce,0x36,0x8e,0xb6,0xe,0x5f,0x2d,0xea,0xbf,0x6,0xff,0x22,0x62,0x62,0xe3,0xfe,0xe5,0xcf,0xab,0x70,0x40,0x0,0x0,0xe1,0x74,0x7e,0xd1,0xfe,0x2c,0x2f,0xb3,0x1a,0x80,0x3b,0x6,0x80,0x6d,0xfe,0xa2,0x25,0xee,0x4,0x68,0x5e,0xb,0xa0,0x75,0xf7,0x8b,0x66,0xb2,0xf,0x40,0xb5,0x0,0xa0,0xe9,0xda,0x57,0xf3,0x70,0xf8,0x7e,0x3c,0x3c,0x45,0xa1,0x90,0xb9,0xd9,0xd9,0xe5,0xe4,0xe4,0xd8,0x4a,0xc4,0x42,0x5b,0x61,0xca,0x57,0x7d,0xfe,0x67,0xc2,0x5f,0xc0,0x57,0xfd,0x6c,0xf9,0x7e,0x3c,0xfc,0xf7,0xf5,0xe0,0xbe,0xe2,0x24,0x81,0x32,0x5d,0x81,0x47,0x4,0xf8,0xe0,0xc2,0xcc,0xf4,0x4c,0xa5,0x1c,0xcf,0x92,0x9,0x84,0x62,0xdc,0xe6,0x8f,0x47,0xfc,0xb7,0xb,0xff,0xfc,0x1d,0xd3,0x22,0xc4,0x49,0x62,0xb9,0x58,0x2a,0x14,0xe3,0x51,0x12,0x71,0x8e,0x44,0x9a,0x8c,0xf3,0x32,0xa5,0x22,0x89,0x42,0x92,0x29,0xc5,0x25,0xd2,0xff,0x64,0xe2,0xdf,0x2c,0xfb,0x3,0x3e,0xdf,0x35,0x0,0xb0,0x6a,0x3e,0x1,0x7b,0x91,0x2d,0xa8,0x5d,0x63,0x3,0xf6,0x4b,0x27,0x10,0x58,0x74,0xc0,0xe2,0xf7,0x0,0x0,0xf2,0xbb,0x6f,0xc1,0xd4,0x28,0x8,0x3,0x80,0x68,0x83,0xe1,0xcf,0x77,0xff,0xef,0x3f,0xfd,0x47,0xa0,0x25,0x0,0x80,0x66,0x49,0x92,0x71,0x0,0x0,0x5e,0x44,0x24,0x2e,0x54,0xca,0xb3,0x3f,0xc7,0x8,0x0,0x0,0x44,0xa0,0x81,0x2a,0xb0,0x41,0x1b,0xf4,0xc1,0x18,0x2c,0xc0,0x6,0x1c,0xc1,0x5,0xdc,0xc1,0xb,0xfc,0x60,0x36,0x84,0x42,0x24,0xc4,0xc2,0x42,0x10,0x42,0xa,0x64,0x80,0x1c,0x72,0x60,0x29,0xac,0x82,0x42,0x28,0x86,0xcd,0xb0,0x1d,0x2a,0x60,0x2f,0xd4,0x40,0x1d,0x34,0xc0,0x51,0x68,0x86,0x93,0x70,0xe,0x2e,0xc2,0x55,0xb8,0xe,0x3d,0x70,0xf,0xfa,0x61,0x8,0x9e,0xc1,0x28,0xbc,0x81,0x9,0x4,0x41,0xc8,0x8,0x13,0x61,0x21,0xda,0x88,0x1,0x62,0x8a,0x58,0x23,0x8e,0x8,0x17,0x99,0x85,0xf8,0x21,0xc1,0x48,0x4,0x12,0x8b,0x24,0x20,0xc9,0x88,0x14,0x51,0x22,0x4b,0x91,0x35,0x48,0x31,0x52,0x8a,0x54,0x20,0x55,0x48,0x1d,0xf2,0x3d,0x72,0x2,0x39,0x87,0x5c,0x46,0xba,0x91,0x3b,0xc8,0x0,0x32,0x82,0xfc,0x86,0xbc,0x47,0x31,0x94,0x81,0xb2,0x51,0x3d,0xd4,0xc,0xb5,0x43,0xb9,0xa8,0x37,0x1a,0x84,0x46,0xa2,0xb,0xd0,0x64,0x74,0x31,0x9a,0x8f,0x16,0xa0,0x9b,0xd0,0x72,0xb4,0x1a,0x3d,0x8c,0x36,0xa1,0xe7,0xd0,0xab,0x68,0xf,0xda,0x8f,0x3e,0x43,0xc7,0x30,0xc0,0xe8,0x18,0x7,0x33,0xc4,0x6c,0x30,0x2e,0xc6,0xc3,0x42,0xb1,0x38,0x2c,0x9,0x93,0x63,0xcb,0xb1,0x22,0xac,0xc,0xab,0xc6,0x1a,0xb0,0x56,0xac,0x3,0xbb,0x89,0xf5,0x63,0xcf,0xb1,0x77,0x4,0x12,0x81,0x45,0xc0,0x9,0x36,0x4,0x77,0x42,0x20,0x61,0x1e,0x41,0x48,0x58,0x4c,0x58,0x4e,0xd8,0x48,0xa8,0x20,0x1c,0x24,0x34,0x11,0xda,0x9,0x37,0x9,0x3,0x84,0x51,0xc2,0x27,0x22,0x93,0xa8,0x4b,0xb4,0x26,0xba,0x11,0xf9,0xc4,0x18,0x62,0x32,0x31,0x87,0x58,0x48,0x2c,0x23,0xd6,0x12,0x8f,0x13,0x2f,0x10,0x7b,0x88,0x43,0xc4,0x37,0x24,0x12,0x89,0x43,0x32,0x27,0xb9,0x90,0x2,0x49,0xb1,0xa4,0x54,0xd2,0x12,0xd2,0x46,0xd2,0x6e,0x52,0x23,0xe9,0x2c,0xa9,0x9b,0x34,0x48,0x1a,0x23,0x93,0xc9,0xda,0x64,0x6b,0xb2,0x7,0x39,0x94,0x2c,0x20,0x2b,0xc8,0x85,0xe4,0x9d,0xe4,0xc3,0xe4,0x33,0xe4,0x1b,0xe4,0x21,0xf2,0x5b,0xa,0x9d,0x62,0x40,0x71,0xa4,0xf8,0x53,0xe2,0x28,0x52,0xca,0x6a,0x4a,0x19,0xe5,0x10,0xe5,0x34,0xe5,0x6,0x65,0x98,0x32,0x41,0x55,0xa3,0x9a,0x52,0xdd,0xa8,0xa1,0x54,0x11,0x35,0x8f,0x5a,0x42,0xad,0xa1,0xb6,0x52,0xaf,0x51,0x87,0xa8,0x13,0x34,0x75,0x9a,0x39,0xcd,0x83,0x16,0x49,0x4b,0xa5,0xad,0xa2,0x95,0xd3,0x1a,0x68,0x17,0x68,0xf7,0x69,0xaf,0xe8,0x74,0xba,0x11,0xdd,0x95,0x1e,0x4e,0x97,0xd0,0x57,0xd2,0xcb,0xe9,0x47,0xe8,0x97,0xe8,0x3,0xf4,0x77,0xc,0xd,0x86,0x15,0x83,0xc7,0x88,0x67,0x28,0x19,0x9b,0x18,0x7,0x18,0x67,0x19,0x77,0x18,0xaf,0x98,0x4c,0xa6,0x19,0xd3,0x8b,0x19,0xc7,0x54,0x30,0x37,0x31,0xeb,0x98,0xe7,0x99,0xf,0x99,0x6f,0x55,0x58,0x2a,0xb6,0x2a,0x7c,0x15,0x91,0xca,0xa,0x95,0x4a,0x95,0x26,0x95,0x1b,0x2a,0x2f,0x54,0xa9,0xaa,0xa6,0xaa,0xde,0xaa,0xb,0x55,0xf3,0x55,0xcb,0x54,0x8f,0xa9,0x5e,0x53,0x7d,0xae,0x46,0x55,0x33,0x53,0xe3,0xa9,0x9,0xd4,0x96,0xab,0x55,0xaa,0x9d,0x50,0xeb,0x53,0x1b,0x53,0x67,0xa9,0x3b,0xa8,0x87,0xaa,0x67,0xa8,0x6f,0x54,0x3f,0xa4,0x7e,0x59,0xfd,0x89,0x6,0x59,0xc3,0x4c,0xc3,0x4f,0x43,0xa4,0x51,0xa0,0xb1,0x5f,0xe3,0xbc,0xc6,0x20,0xb,0x63,0x19,0xb3,0x78,0x2c,0x21,0x6b,0xd,0xab,0x86,0x75,0x81,0x35,0xc4,0x26,0xb1,0xcd,0xd9,0x7c,0x76,0x2a,0xbb,0x98,0xfd,0x1d,0xbb,0x8b,0x3d,0xaa,0xa9,0xa1,0x39,0x43,0x33,0x4a,0x33,0x57,0xb3,0x52,0xf3,0x94,0x66,0x3f,0x7,0xe3,0x98,0x71,0xf8,0x9c,0x74,0x4e,0x9,0xe7,0x28,0xa7,0x97,0xf3,0x7e,0x8a,0xde,0x14,0xef,0x29,0xe2,0x29,0x1b,0xa6,0x34,0x4c,0xb9,0x31,0x65,0x5c,0x6b,0xaa,0x96,0x97,0x96,0x58,0xab,0x48,0xab,0x51,0xab,0x47,0xeb,0xbd,0x36,0xae,0xed,0xa7,0x9d,0xa6,0xbd,0x45,0xbb,0x59,0xfb,0x81,0xe,0x41,0xc7,0x4a,0x27,0x5c,0x27,0x47,0x67,0x8f,0xce,0x5,0x9d,0xe7,0x53,0xd9,0x53,0xdd,0xa7,0xa,0xa7,0x16,0x4d,0x3d,0x3a,0xf5,0xae,0x2e,0xaa,0x6b,0xa5,0x1b,0xa1,0xbb,0x44,0x77,0xbf,0x6e,0xa7,0xee,0x98,0x9e,0xbe,0x5e,0x80,0x9e,0x4c,0x6f,0xa7,0xde,0x79,0xbd,0xe7,0xfa,0x1c,0x7d,0x2f,0xfd,0x54,0xfd,0x6d,0xfa,0xa7,0xf5,0x47,0xc,0x58,0x6,0xb3,0xc,0x24,0x6,0xdb,0xc,0xce,0x18,0x3c,0xc5,0x35,0x71,0x6f,0x3c,0x1d,0x2f,0xc7,0xdb,0xf1,0x51,0x43,0x5d,0xc3,0x40,0x43,0xa5,0x61,0x95,0x61,0x97,0xe1,0x84,0x91,0xb9,0xd1,0x3c,0xa3,0xd5,0x46,0x8d,0x46,0xf,0x8c,0x69,0xc6,0x5c,0xe3,0x24,0xe3,0x6d,0xc6,0x6d,0xc6,0xa3,0x26,0x6,0x26,0x21,0x26,0x4b,0x4d,0xea,0x4d,0xee,0x9a,0x52,0x4d,0xb9,0xa6,0x29,0xa6,0x3b,0x4c,0x3b,0x4c,0xc7,0xcd,0xcc,0xcd,0xa2,0xcd,0xd6,0x99,0x35,0x9b,0x3d,0x31,0xd7,0x32,0xe7,0x9b,0xe7,0x9b,0xd7,0x9b,0xdf,0xb7,0x60,0x5a,0x78,0x5a,0x2c,0xb6,0xa8,0xb6,0xb8,0x65,0x49,0xb2,0xe4,0x5a,0xa6,0x59,0xee,0xb6,0xbc,0x6e,0x85,0x5a,0x39,0x59,0xa5,0x58,0x55,0x5a,0x5d,0xb3,0x46,0xad,0x9d,0xad,0x25,0xd6,0xbb,0xad,0xbb,0xa7,0x11,0xa7,0xb9,0x4e,0x93,0x4e,0xab,0x9e,0xd6,0x67,0xc3,0xb0,0xf1,0xb6,0xc9,0xb6,0xa9,0xb7,0x19,0xb0,0xe5,0xd8,0x6,0xdb,0xae,0xb6,0x6d,0xb6,0x7d,0x61,0x67,0x62,0x17,0x67,0xb7,0xc5,0xae,0xc3,0xee,0x93,0xbd,0x93,0x7d,0xba,0x7d,0x8d,0xfd,0x3d,0x7,0xd,0x87,0xd9,0xe,0xab,0x1d,0x5a,0x1d,0x7e,0x73,0xb4,0x72,0x14,0x3a,0x56,0x3a,0xde,0x9a,0xce,0x9c,0xee,0x3f,0x7d,0xc5,0xf4,0x96,0xe9,0x2f,0x67,0x58,0xcf,0x10,0xcf,0xd8,0x33,0xe3,0xb6,0x13,0xcb,0x29,0xc4,0x69,0x9d,0x53,0x9b,0xd3,0x47,0x67,0x17,0x67,0xb9,0x73,0x83,0xf3,0x88,0x8b,0x89,0x4b,0x82,0xcb,0x2e,0x97,0x3e,0x2e,0x9b,0x1b,0xc6,0xdd,0xc8,0xbd,0xe4,0x4a,0x74,0xf5,0x71,0x5d,0xe1,0x7a,0xd2,0xf5,0x9d,0x9b,0xb3,0x9b,0xc2,0xed,0xa8,0xdb,0xaf,0xee,0x36,0xee,0x69,0xee,0x87,0xdc,0x9f,0xcc,0x34,0x9f,0x29,0x9e,0x59,0x33,0x73,0xd0,0xc3,0xc8,0x43,0xe0,0x51,0xe5,0xd1,0x3f,0xb,0x9f,0x95,0x30,0x6b,0xdf,0xac,0x7e,0x4f,0x43,0x4f,0x81,0x67,0xb5,0xe7,0x23,0x2f,0x63,0x2f,0x91,0x57,0xad,0xd7,0xb0,0xb7,0xa5,0x77,0xaa,0xf7,0x61,0xef,0x17,0x3e,0xf6,0x3e,0x72,0x9f,0xe3,0x3e,0xe3,0x3c,0x37,0xde,0x32,0xde,0x59,0x5f,0xcc,0x37,0xc0,0xb7,0xc8,0xb7,0xcb,0x4f,0xc3,0x6f,0x9e,0x5f,0x85,0xdf,0x43,0x7f,0x23,0xff,0x64,0xff,0x7a,0xff,0xd1,0x0,0xa7,0x80,0x25,0x1,0x67,0x3,0x89,0x81,0x41,0x81,0x5b,0x2,0xfb,0xf8,0x7a,0x7c,0x21,0xbf,0x8e,0x3f,0x3a,0xdb,0x65,0xf6,0xb2,0xd9,0xed,0x41,0x8c,0xa0,0xb9,0x41,0x15,0x41,0x8f,0x82,0xad,0x82,0xe5,0xc1,0xad,0x21,0x68,0xc8,0xec,0x90,0xad,0x21,0xf7,0xe7,0x98,0xce,0x91,0xce,0x69,0xe,0x85,0x50,0x7e,0xe8,0xd6,0xd0,0x7,0x61,0xe6,0x61,0x8b,0xc3,0x7e,0xc,0x27,0x85,0x87,0x85,0x57,0x86,0x3f,0x8e,0x70,0x88,0x58,0x1a,0xd1,0x31,0x97,0x35,0x77,0xd1,0xdc,0x43,0x73,0xdf,0x44,0xfa,0x44,0x96,0x44,0xde,0x9b,0x67,0x31,0x4f,0x39,0xaf,0x2d,0x4a,0x35,0x2a,0x3e,0xaa,0x2e,0x6a,0x3c,0xda,0x37,0xba,0x34,0xba,0x3f,0xc6,0x2e,0x66,0x59,0xcc,0xd5,0x58,0x9d,0x58,0x49,0x6c,0x4b,0x1c,0x39,0x2e,0x2a,0xae,0x36,0x6e,0x6c,0xbe,0xdf,0xfc,0xed,0xf3,0x87,0xe2,0x9d,0xe2,0xb,0xe3,0x7b,0x17,0x98,0x2f,0xc8,0x5d,0x70,0x79,0xa1,0xce,0xc2,0xf4,0x85,0xa7,0x16,0xa9,0x2e,0x12,0x2c,0x3a,0x96,0x40,0x4c,0x88,0x4e,0x38,0x94,0xf0,0x41,0x10,0x2a,0xa8,0x16,0x8c,0x25,0xf2,0x13,0x77,0x25,0x8e,0xa,0x79,0xc2,0x1d,0xc2,0x67,0x22,0x2f,0xd1,0x36,0xd1,0x88,0xd8,0x43,0x5c,0x2a,0x1e,0x4e,0xf2,0x48,0x2a,0x4d,0x7a,0x92,0xec,0x91,0xbc,0x35,0x79,0x24,0xc5,0x33,0xa5,0x2c,0xe5,0xb9,0x84,0x27,0xa9,0x90,0xbc,0x4c,0xd,0x4c,0xdd,0x9b,0x3a,0x9e,0x16,0x9a,0x76,0x20,0x6d,0x32,0x3d,0x3a,0xbd,0x31,0x83,0x92,0x91,0x90,0x71,0x42,0xaa,0x21,0x4d,0x93,0xb6,0x67,0xea,0x67,0xe6,0x66,0x76,0xcb,0xac,0x65,0x85,0xb2,0xfe,0xc5,0x6e,0x8b,0xb7,0x2f,0x1e,0x95,0x7,0xc9,0x6b,0xb3,0x90,0xac,0x5,0x59,0x2d,0xa,0xb6,0x42,0xa6,0xe8,0x54,0x5a,0x28,0xd7,0x2a,0x7,0xb2,0x67,0x65,0x57,0x66,0xbf,0xcd,0x89,0xca,0x39,0x96,0xab,0x9e,0x2b,0xcd,0xed,0xcc,0xb3,0xca,0xdb,0x90,0x37,0x9c,0xef,0x9f,0xff,0xed,0x12,0xc2,0x12,0xe1,0x92,0xb6,0xa5,0x86,0x4b,0x57,0x2d,0x1d,0x58,0xe6,0xbd,0xac,0x6a,0x39,0xb2,0x3c,0x71,0x79,0xdb,0xa,0xe3,0x15,0x5,0x2b,0x86,0x56,0x6,0xac,0x3c,0xb8,0x8a,0xb6,0x2a,0x6d,0xd5,0x4f,0xab,0xed,0x57,0x97,0xae,0x7e,0xbd,0x26,0x7a,0x4d,0x6b,0x81,0x5e,0xc1,0xca,0x82,0xc1,0xb5,0x1,0x6b,0xeb,0xb,0x55,0xa,0xe5,0x85,0x7d,0xeb,0xdc,0xd7,0xed,0x5d,0x4f,0x58,0x2f,0x59,0xdf,0xb5,0x61,0xfa,0x86,0x9d,0x1b,0x3e,0x15,0x89,0x8a,0xae,0x14,0xdb,0x17,0x97,0x15,0x7f,0xd8,0x28,0xdc,0x78,0xe5,0x1b,0x87,0x6f,0xca,0xbf,0x99,0xdc,0x94,0xb4,0xa9,0xab,0xc4,0xb9,0x64,0xcf,0x66,0xd2,0x66,0xe9,0xe6,0xde,0x2d,0x9e,0x5b,0xe,0x96,0xaa,0x97,0xe6,0x97,0xe,0x6e,0xd,0xd9,0xda,0xb4,0xd,0xdf,0x56,0xb4,0xed,0xf5,0xf6,0x45,0xdb,0x2f,0x97,0xcd,0x28,0xdb,0xbb,0x83,0xb6,0x43,0xb9,0xa3,0xbf,0x3c,0xb8,0xbc,0x65,0xa7,0xc9,0xce,0xcd,0x3b,0x3f,0x54,0xa4,0x54,0xf4,0x54,0xfa,0x54,0x36,0xee,0xd2,0xdd,0xb5,0x61,0xd7,0xf8,0x6e,0xd1,0xee,0x1b,0x7b,0xbc,0xf6,0x34,0xec,0xd5,0xdb,0x5b,0xbc,0xf7,0xfd,0x3e,0xc9,0xbe,0xdb,0x55,0x1,0x55,0x4d,0xd5,0x66,0xd5,0x65,0xfb,0x49,0xfb,0xb3,0xf7,0x3f,0xae,0x89,0xaa,0xe9,0xf8,0x96,0xfb,0x6d,0x5d,0xad,0x4e,0x6d,0x71,0xed,0xc7,0x3,0xd2,0x3,0xfd,0x7,0x23,0xe,0xb6,0xd7,0xb9,0xd4,0xd5,0x1d,0xd2,0x3d,0x54,0x52,0x8f,0xd6,0x2b,0xeb,0x47,0xe,0xc7,0x1f,0xbe,0xfe,0x9d,0xef,0x77,0x2d,0xd,0x36,0xd,0x55,0x8d,0x9c,0xc6,0xe2,0x23,0x70,0x44,0x79,0xe4,0xe9,0xf7,0x9,0xdf,0xf7,0x1e,0xd,0x3a,0xda,0x76,0x8c,0x7b,0xac,0xe1,0x7,0xd3,0x1f,0x76,0x1d,0x67,0x1d,0x2f,0x6a,0x42,0x9a,0xf2,0x9a,0x46,0x9b,0x53,0x9a,0xfb,0x5b,0x62,0x5b,0xba,0x4f,0xcc,0x3e,0xd1,0xd6,0xea,0xde,0x7a,0xfc,0x47,0xdb,0x1f,0xf,0x9c,0x34,0x3c,0x59,0x79,0x4a,0xf3,0x54,0xc9,0x69,0xda,0xe9,0x82,0xd3,0x93,0x67,0xf2,0xcf,0x8c,0x9d,0x95,0x9d,0x7d,0x7e,0x2e,0xf9,0xdc,0x60,0xdb,0xa2,0xb6,0x7b,0xe7,0x63,0xce,0xdf,0x6a,0xf,0x6f,0xef,0xba,0x10,0x74,0xe1,0xd2,0x45,0xff,0x8b,0xe7,0x3b,0xbc,0x3b,0xce,0x5c,0xf2,0xb8,0x74,0xf2,0xb2,0xdb,0xe5,0x13,0x57,0xb8,0x57,0x9a,0xaf,0x3a,0x5f,0x6d,0xea,0x74,0xea,0x3c,0xfe,0x93,0xd3,0x4f,0xc7,0xbb,0x9c,0xbb,0x9a,0xae,0xb9,0x5c,0x6b,0xb9,0xee,0x7a,0xbd,0xb5,0x7b,0x66,0xf7,0xe9,0x1b,0x9e,0x37,0xce,0xdd,0xf4,0xbd,0x79,0xf1,0x16,0xff,0xd6,0xd5,0x9e,0x39,0x3d,0xdd,0xbd,0xf3,0x7a,0x6f,0xf7,0xc5,0xf7,0xf5,0xdf,0x16,0xdd,0x7e,0x72,0x27,0xfd,0xce,0xcb,0xbb,0xd9,0x77,0x27,0xee,0xad,0xbc,0x4f,0xbc,0x5f,0xf4,0x40,0xed,0x41,0xd9,0x43,0xdd,0x87,0xd5,0x3f,0x5b,0xfe,0xdc,0xd8,0xef,0xdc,0x7f,0x6a,0xc0,0x77,0xa0,0xf3,0xd1,0xdc,0x47,0xf7,0x6,0x85,0x83,0xcf,0xfe,0x91,0xf5,0x8f,0xf,0x43,0x5,0x8f,0x99,0x8f,0xcb,0x86,0xd,0x86,0xeb,0x9e,0x38,0x3e,0x39,0x39,0xe2,0x3f,0x72,0xfd,0xe9,0xfc,0xa7,0x43,0xcf,0x64,0xcf,0x26,0x9e,0x17,0xfe,0xa2,0xfe,0xcb,0xae,0x17,0x16,0x2f,0x7e,0xf8,0xd5,0xeb,0xd7,0xce,0xd1,0x98,0xd1,0xa1,0x97,0xf2,0x97,0x93,0xbf,0x6d,0x7c,0xa5,0xfd,0xea,0xc0,0xeb,0x19,0xaf,0xdb,0xc6,0xc2,0xc6,0x1e,0xbe,0xc9,0x78,0x33,0x31,0x5e,0xf4,0x56,0xfb,0xed,0xc1,0x77,0xdc,0x77,0x1d,0xef,0xa3,0xdf,0xf,0x4f,0xe4,0x7c,0x20,0x7f,0x28,0xff,0x68,0xf9,0xb1,0xf5,0x53,0xd0,0xa7,0xfb,0x93,0x19,0x93,0x93,0xff,0x4,0x3,0x98,0xf3,0xfc,0xef,0x35,0x94,0x82,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x35,0x0,0x32,0x0,0x3b,0x6,0x66,0x54,0x53,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xa,0x15,0x0,0x1f,0x2d,0x8a,0x4e,0xe9,0xbd,0x0,0x0,0x1,0x2b,0x49,0x44,0x41,0x54,0x38,0xcb,0x95,0x92,0x31,0x4e,0x3,0x31,0x10,0x45,0x9f,0x37,0x26,0x8b,0x44,0x11,0xd7,0x21,0xe1,0x26,0x88,0x96,0x9a,0xd3,0xe4,0x8,0x9c,0x86,0x9a,0x86,0x2,0x71,0x13,0x4,0x1d,0x82,0x20,0x81,0x44,0xd6,0xde,0xf9,0x14,0xf6,0x26,0x59,0x48,0x60,0x33,0x92,0x25,0x6b,0xe4,0xff,0xfc,0xff,0x68,0x1c,0xe0,0x81,0x31,0x50,0x3,0xc7,0xe5,0x3e,0x2,0x2a,0xfa,0x65,0x40,0xb,0x34,0xc0,0x17,0xb0,0x2,0x9a,0x4e,0x7c,0x2,0x4,0x60,0x52,0xee,0x35,0xe0,0xca,0x1,0x50,0x39,0x2b,0xe0,0x13,0x78,0x7,0x96,0x94,0xdf,0x6b,0x20,0x5c,0x9c,0x5f,0x5e,0xcd,0x4e,0xcf,0x16,0x29,0xa5,0x60,0x62,0x67,0x55,0xe,0xbc,0xf7,0xcb,0xa7,0xe7,0xc7,0xeb,0xfb,0x87,0xdb,0x1b,0x20,0xf9,0x62,0x7b,0x32,0x9b,0xce,0x17,0x6f,0xaf,0x2f,0x21,0xc5,0x84,0xd8,0x4d,0x70,0x38,0xfc,0x91,0xf,0xb3,0xe9,0x7c,0x1,0xdc,0x1,0x1f,0xeb,0x8,0x4d,0x8c,0x21,0xc6,0xb8,0x57,0x9c,0x73,0x88,0x18,0x23,0x4d,0x8c,0xa1,0x44,0x1d,0xfb,0x32,0xb0,0xda,0xcc,0x30,0x19,0xff,0x95,0x10,0x66,0x46,0x89,0x3e,0xf2,0x65,0xda,0x4e,0x26,0xcc,0xc4,0x90,0x52,0x7e,0xe7,0x80,0xca,0x77,0xf1,0x5a,0xb5,0x83,0x1c,0x0,0xb4,0x6a,0x3b,0x0,0x7e,0x9b,0x2a,0x1d,0xe4,0x80,0x6d,0x80,0xa4,0x3,0x0,0xf9,0x9d,0x3a,0x80,0x65,0x68,0x42,0x3,0x23,0x98,0x52,0x7,0xb0,0xaa,0xac,0xe7,0x8a,0x61,0xda,0xcd,0x52,0xe7,0xad,0x6c,0xfd,0xe,0x6b,0x9d,0xbb,0xcd,0x26,0x77,0x8e,0x9d,0xfb,0xc5,0xea,0x3,0xcc,0x7a,0x52,0xa1,0xac,0x51,0x6e,0xc8,0x84,0xfb,0x13,0xb0,0x35,0x3,0x5b,0xf7,0xa,0x50,0xe,0x65,0xe4,0x7e,0x80,0x49,0xfc,0xb0,0xd0,0xdb,0x40,0x0,0xb9,0xfe,0xb0,0xbe,0x1,0x2c,0x3a,0x9d,0x31,0x64,0x70,0xaf,0x77,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -390,12 +435,12 @@ static const unsigned char tab_menu_hl_png[]={
static const unsigned char toggle_off_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x20,0x8,0x6,0x0,0x0,0x0,0xa2,0x9d,0x7e,0x84,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x26,0x0,0x26,0x0,0x26,0x59,0xf,0xde,0x74,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x14,0x17,0x2,0x16,0xe9,0x0,0x17,0x60,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x2,0x45,0x49,0x44,0x41,0x54,0x68,0x81,0xed,0x99,0x5f,0x4f,0xd3,0x50,0x18,0x87,0x9f,0xb3,0x96,0xb5,0xcc,0x3a,0xa6,0xac,0x6d,0xa,0x91,0x84,0x5b,0x8d,0x7e,0x21,0x60,0x2c,0x5c,0x1a,0x63,0xe2,0x27,0x31,0x31,0xc6,0x4b,0x32,0xa7,0x7e,0x20,0x84,0x6b,0x6f,0xc,0x90,0x6d,0x32,0xca,0x6c,0xb0,0x24,0x75,0xc7,0x8b,0xba,0xb9,0x35,0xdd,0x84,0xec,0xe0,0x26,0xed,0x73,0xd7,0xf7,0xed,0xce,0x7b,0x7e,0xbf,0xbe,0x67,0x7f,0xde,0x41,0x4e,0x4e,0xa6,0x11,0x89,0xeb,0x12,0x50,0x1,0x2c,0x40,0x4b,0xc9,0xff,0xaf,0x48,0xe0,0x27,0x10,0x0,0x3e,0x70,0x39,0x48,0xe8,0x89,0x1b,0x2b,0xc0,0x33,0xe0,0x11,0x60,0x72,0xb7,0xc,0x8,0x81,0xaf,0xc0,0x67,0xa6,0x18,0x60,0x1,0x1b,0x4f,0x1e,0x3f,0x7d,0x6d,0x57,0xed,0x65,0x40,0x48,0x64,0xfc,0x72,0x95,0x8,0x10,0x8,0x74,0x5d,0x67,0x69,0x49,0x47,0xd3,0x92,0xdb,0x50,0x4b,0x14,0x45,0xf2,0xf8,0xe4,0xf8,0xc7,0xe1,0xd1,0xc1,0x2b,0xe0,0xcb,0x68,0x2e,0x59,0x59,0x7,0xc,0xbb,0x6a,0x97,0xce,0xba,0x67,0x4,0x41,0x80,0xec,0xf7,0x91,0x8a,0x1d,0x10,0x8,0x44,0xa1,0x80,0x51,0x2c,0x52,0x2a,0xdd,0xa3,0x58,0x2c,0x2a,0x5d,0x3f,0x89,0x69,0x9a,0x62,0x7d,0x6d,0xbd,0x74,0x78,0x74,0x60,0x90,0xd0,0x9c,0x66,0xbd,0x0,0x8,0x82,0xef,0x54,0x2a,0xf,0x70,0x6c,0x7,0xa1,0xf8,0x24,0x48,0x24,0xed,0x4e,0x1b,0xdf,0x3f,0xc7,0x30,0x4c,0xa5,0x6b,0xa7,0x11,0x86,0x21,0x96,0x65,0x41,0xca,0x91,0x4e,0xed,0x3d,0x29,0x25,0xb2,0x2f,0x71,0x1d,0x97,0x30,0xc,0x39,0x6d,0x9d,0x2a,0xdd,0x90,0xe7,0x7a,0xb8,0x8e,0xcb,0x79,0xb7,0xab,0xbc,0xbb,0x6e,0x4a,0x61,0x52,0x62,0x70,0xf6,0x55,0x8b,0x87,0xdf,0x6b,0x4a,0xe6,0x2e,0x1e,0xa6,0x18,0x90,0x15,0x32,0x6f,0xc0,0xed,0x7e,0xfe,0xcc,0x80,0x65,0x59,0xd4,0xf7,0x6a,0x63,0xb1,0xc6,0x7e,0x93,0x20,0x8,0x78,0xf1,0xf2,0xf9,0x58,0xfc,0xed,0x9b,0x77,0xa9,0xb1,0xeb,0xb0,0xb0,0x6,0xc,0xc4,0x7f,0x78,0xff,0x9,0x80,0x9d,0xdd,0x2d,0xea,0x7b,0xb5,0xa1,0xb0,0x34,0x81,0xd7,0x15,0x3d,0xca,0xc2,0x1a,0x0,0xd0,0x6c,0x7c,0xa4,0xd7,0xeb,0x1,0xb1,0x11,0x3b,0xbb,0x5b,0xc3,0xdc,0xe8,0x13,0x1f,0x8,0x4f,0x8b,0xfd,0x8d,0x85,0x36,0x60,0x1a,0xaa,0x3a,0x60,0xa1,0xdf,0x4,0x6b,0xf5,0x6d,0xca,0xe5,0x32,0xe5,0x72,0x79,0xec,0xe9,0xab,0x24,0x69,0x80,0x9,0xac,0xdc,0x4a,0xa5,0x1b,0xd2,0xd8,0x6f,0x2,0xb1,0x9,0xb5,0xfa,0xf6,0x58,0x6c,0x6,0x56,0x88,0x35,0xe,0x49,0x1e,0x81,0x10,0xb8,0x98,0xb5,0x8a,0xa,0x82,0x20,0x98,0xd8,0xd2,0x33,0xb4,0xff,0x5,0xb1,0xc6,0x21,0xb,0x7d,0x4,0xfe,0x5,0xb9,0x1,0xf3,0xde,0xc0,0xbc,0x99,0x68,0x80,0x88,0xa7,0x16,0x78,0xae,0xa7,0xbc,0xa8,0xe7,0x7a,0xc3,0xa1,0xc8,0xbc,0x49,0xfd,0x1e,0x20,0x84,0x40,0x14,0x4,0xad,0x76,0xb,0xc7,0x76,0xd8,0xdc,0xd8,0x54,0x5a,0x54,0x22,0x69,0xb5,0x5b,0x88,0x82,0x98,0xbb,0x9,0x69,0x6,0x48,0x0,0xcb,0xba,0x8f,0xef,0xfb,0xb7,0xf2,0x9b,0xfd,0xcf,0x44,0xc8,0x40,0xd3,0x34,0xa5,0x6b,0xa7,0x61,0x9a,0x26,0x51,0x14,0x41,0xca,0x70,0x2f,0x69,0x40,0x4,0x5c,0x75,0xbe,0x75,0x2e,0xed,0xaa,0xbd,0xbc,0xfa,0x70,0xf5,0x4e,0xcd,0x4,0x81,0x2b,0x62,0x8d,0xa3,0x5b,0x19,0x63,0x8d,0x6c,0x4c,0x85,0x4f,0x6,0x89,0xcc,0xff,0x2f,0x90,0x93,0x93,0x93,0x6d,0x7e,0x1,0x6b,0xe,0xc1,0xdb,0xd6,0xe0,0xc4,0xba,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x20,0x8,0x6,0x0,0x0,0x0,0xa2,0x9d,0x7e,0x84,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xb,0xd,0x15,0x16,0x28,0x99,0xc6,0x91,0x20,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x5,0xb5,0x49,0x44,0x41,0x54,0x68,0xde,0xed,0x99,0xdb,0x6f,0x54,0x55,0x14,0xc6,0x7f,0xfb,0xdc,0xe6,0x72,0x66,0x3a,0x9d,0x76,0x5a,0xa0,0x3,0xe5,0xd2,0xc4,0xb4,0x21,0x26,0x46,0x2,0x31,0xbe,0x11,0xc0,0x17,0x62,0x14,0xe2,0xe5,0xc1,0xc4,0x77,0xc2,0xe5,0xf,0x30,0x31,0xd1,0x18,0x8,0xbc,0x5a,0x2,0xaf,0x3e,0x90,0x80,0xa8,0x28,0x1a,0x5f,0x4,0x9,0x8f,0x62,0x42,0x88,0x1a,0x9c,0x82,0x5c,0x14,0x68,0x11,0x5a,0x3a,0xed,0xdc,0x3b,0xe7,0xb2,0x7d,0x70,0x77,0x98,0xe,0x67,0x86,0x96,0xe,0x97,0x4,0x56,0xb2,0x33,0x33,0xeb,0x5c,0xe6,0xac,0x6f,0x7f,0x7b,0x9d,0xb5,0xbe,0xd,0x2f,0xec,0xf9,0x36,0xb1,0xc0,0x73,0x45,0xdd,0x35,0xe2,0x19,0x89,0x41,0xd6,0x7d,0xca,0xba,0xdf,0x6d,0x3,0x40,0x53,0xc3,0xac,0x1b,0xba,0xf2,0x89,0x67,0x20,0x78,0x1f,0xf0,0x0,0xa7,0x6e,0xf8,0x6a,0x2c,0xa,0x0,0xa1,0x2,0xb5,0x80,0x18,0xd0,0xa9,0x46,0x7,0x10,0x51,0x40,0x3c,0x4d,0x10,0x66,0x83,0x77,0x80,0x32,0x90,0x3,0xa6,0xd4,0x28,0x0,0x55,0x5,0x8c,0x7c,0x14,0x0,0x34,0xc0,0x50,0x81,0xf7,0x0,0xcb,0x53,0xa9,0x25,0xef,0xc6,0x62,0x1d,0x6f,0x1a,0x86,0xde,0x3,0xc2,0x0,0x84,0x10,0x4f,0x97,0x0,0x52,0x4a,0x5,0x84,0x74,0x5d,0xd7,0x1b,0x2f,0x14,0x72,0x3f,0x4c,0x4c,0xdc,0xf9,0xa,0xb8,0x5,0x8c,0x2b,0x20,0xdc,0x56,0x6c,0x10,0x4d,0x82,0xb7,0x80,0x4,0xd0,0xdf,0xd9,0xd9,0xbd,0xad,0xab,0x2b,0xb5,0x5b,0xd3,0x44,0xec,0x7e,0xbc,0x62,0x1e,0x18,0xca,0x26,0x3e,0xa1,0x9e,0xa7,0xfd,0xe4,0x91,0x52,0xe2,0xfb,0x7e,0x61,0x72,0x72,0x62,0x78,0x6a,0xea,0xde,0xb7,0xc0,0xd,0x60,0x5a,0xb1,0xc1,0x9f,0xf,0x0,0x42,0x5,0x9f,0x4,0xd6,0x2c,0x5b,0xb6,0xfc,0x23,0xdb,0x8e,0x6d,0x15,0x2,0xc2,0xc2,0x60,0x95,0x69,0xd3,0x6b,0x84,0xb1,0x35,0x3,0xbd,0xc5,0xec,0x3b,0xd2,0x67,0xd4,0x29,0x73,0xa5,0x9a,0xa7,0x22,0xfd,0x0,0x50,0x7c,0xf5,0x57,0xda,0x63,0x63,0x46,0xb1,0x98,0xff,0xf1,0xf6,0xed,0x5b,0xfb,0x80,0x6b,0x40,0x56,0x81,0x20,0x5b,0x1,0x30,0xbb,0xe6,0x13,0xc0,0x40,0x5f,0xdf,0x8a,0xcf,0xa2,0x51,0xfb,0xd,0x21,0x4,0x6b,0xcc,0x18,0x2b,0x2d,0x9b,0xdb,0x4e,0x85,0x51,0xa7,0x44,0x41,0xba,0x81,0xf3,0x2b,0x80,0x30,0x1a,0x1d,0xba,0x49,0xaf,0x11,0xa6,0xd7,0x8,0x71,0xbd,0x5a,0xe4,0x6f,0xa7,0x18,0x0,0xbf,0x7c,0xac,0xe9,0x43,0x4a,0x49,0xa9,0x54,0xf8,0x69,0x6c,0xec,0xe6,0xc7,0xc0,0x55,0xc5,0x84,0x7,0x72,0x82,0xde,0x40,0xfd,0x30,0xb0,0x2c,0x99,0x4c,0x7d,0x90,0x48,0x74,0x7e,0x28,0x84,0x60,0x6d,0x28,0x41,0x4a,0xf,0xf1,0x47,0x65,0x9a,0x5b,0x6e,0x99,0xea,0x43,0x92,0xab,0x8b,0xa4,0x28,0x3d,0xee,0x7a,0x33,0xe4,0x3c,0x87,0x95,0x96,0x4d,0x87,0x6e,0x72,0xcf,0x9b,0x69,0x0,0xed,0xf1,0xe6,0xf,0x21,0x4,0xa6,0x69,0xd,0x0,0xd3,0xe5,0x72,0xe9,0x12,0x50,0x54,0xf9,0x40,0x36,0xae,0xf7,0xfa,0xef,0x31,0x60,0x79,0x57,0x57,0xf7,0x2e,0x21,0xa0,0xdf,0xb4,0x49,0xe8,0x16,0x17,0xca,0x59,0xa6,0x7c,0x67,0xc1,0xf,0x71,0xcf,0xaf,0xf2,0x5b,0x39,0x4b,0x42,0xb7,0x58,0x61,0x46,0x9f,0xf8,0xeb,0x42,0x8,0x41,0x32,0xd9,0xbd,0x13,0x58,0xa1,0x62,0xd3,0x1b,0x91,0xd7,0xea,0xa6,0xc3,0x4,0x12,0x3d,0x3d,0x4b,0xdf,0xd7,0x34,0x11,0xb1,0x84,0xc1,0x6a,0xd3,0x26,0x53,0xc9,0x51,0x9e,0xdf,0x2b,0x35,0xd0,0x4a,0xf8,0x8c,0x54,0x72,0xac,0x31,0x63,0x58,0x42,0x7b,0xe2,0x6f,0xa,0x4d,0xd3,0x23,0x3d,0x3d,0x4b,0xdf,0x53,0x4b,0xdb,0x8,0xca,0xf8,0xf5,0x0,0x74,0xda,0x76,0x7c,0x2b,0x40,0xda,0x88,0x30,0xe9,0x55,0xc9,0xfa,0xd5,0x45,0x3f,0xc4,0xa4,0x5f,0xe5,0x9e,0x37,0x43,0x9f,0x11,0x69,0x79,0x5e,0x3a,0xdd,0xc7,0xfe,0xfd,0x7b,0xb9,0x7c,0xf9,0x22,0xe7,0xcf,0xff,0xc2,0xf6,0xed,0x6f,0x3,0xb0,0x61,0xc3,0x7a,0x2e,0x5f,0xbe,0x38,0x67,0x4,0xf9,0xe2,0xf1,0x78,0xe0,0x7d,0x6d,0x3b,0xb6,0x55,0x25,0x76,0xab,0x91,0x1,0x46,0x3,0x0,0x1d,0x86,0xa1,0xa7,0x40,0xb0,0xc4,0x8,0xf3,0x8f,0x53,0x6c,0xdb,0x4c,0x8c,0x7b,0x33,0xac,0x34,0x6d,0xae,0xb7,0xb8,0xe7,0x81,0x3,0xfb,0xc8,0xe5,0xf2,0x6c,0xdc,0xb8,0x85,0xa1,0xa1,0x41,0xe,0x1d,0x1a,0xe6,0xdc,0xb9,0x5f,0x6b,0xc7,0xd7,0xad,0x7b,0x8d,0x7c,0x3e,0x5f,0x3,0xa5,0xd1,0xd7,0xcc,0xc,0xc3,0xe8,0x51,0x5,0x9c,0xd1,0xc,0x80,0xd9,0x84,0x18,0x9e,0xf5,0xc5,0x34,0x83,0x69,0xcf,0x69,0x1b,0x0,0xd3,0x9e,0x43,0x2c,0x64,0xb4,0x9c,0xfd,0xd,0x1b,0xd6,0xd7,0x2,0x1a,0x1d,0x1d,0xe3,0xf4,0xe9,0x33,0x6c,0xde,0xbc,0x89,0x4c,0x66,0x84,0x4c,0x66,0xe4,0x81,0x6b,0x82,0x7c,0x4d,0xb2,0x81,0xa1,0xaa,0xd7,0xa6,0x39,0xa0,0xfe,0x35,0x28,0x0,0x4c,0xa1,0x51,0x96,0x5e,0xdb,0x0,0x28,0x4b,0xf,0xb3,0x45,0xe,0x48,0xa7,0xd3,0x64,0x32,0x23,0x73,0x66,0x33,0x93,0xc9,0x30,0x34,0x34,0x8,0x40,0x3e,0x9f,0xe7,0xf0,0xe1,0x61,0x8e,0x1c,0xf9,0xa2,0x46,0xf5,0x20,0x5f,0xb3,0x64,0xd8,0xac,0xf2,0x32,0x2,0x6a,0xeb,0x5a,0x31,0x13,0x11,0x3a,0xa5,0x36,0x81,0x10,0x11,0x3a,0x8e,0x6c,0x9e,0x4c,0x33,0x99,0x11,0x86,0x86,0x6,0x89,0xc7,0xe3,0x35,0x10,0xd2,0xe9,0xf4,0x1c,0x40,0x76,0xec,0xd8,0xfd,0x0,0xdd,0x83,0x7c,0x4d,0x4a,0x66,0x3f,0xa8,0x10,0xaa,0x9f,0x12,0xef,0xff,0xa6,0x42,0xba,0x20,0x29,0xf8,0x2e,0x9,0xdd,0x6c,0x1b,0x3,0x12,0xba,0x49,0xc1,0x77,0x9b,0x1e,0xcf,0xe7,0xf3,0x64,0x32,0x23,0xb5,0xc4,0x17,0x8f,0xc7,0xd9,0xb2,0x65,0xd3,0x2,0x68,0xde,0x12,0x2,0x57,0x35,0x4c,0x5e,0xb3,0x3a,0x40,0xaa,0xae,0x2a,0xef,0xba,0xfe,0x38,0xc0,0x1d,0xb7,0x42,0x4a,0xf,0xb5,0xd,0x80,0x1e,0x3d,0xc4,0x1d,0xb7,0xd2,0xf2,0x9c,0xbd,0x7b,0xf7,0xb3,0x67,0xcf,0x4e,0x4e,0x9e,0xfc,0x86,0xb3,0x67,0x4f,0x71,0xea,0xd4,0xcf,0x9c,0x38,0xf1,0xdd,0xa2,0xff,0xdb,0x75,0xdd,0x71,0xd5,0x2d,0xba,0xf,0xab,0x4,0x2d,0xd3,0xb4,0x7a,0xc3,0xe1,0xf0,0xab,0x25,0xe9,0xf3,0x92,0x15,0x27,0xe7,0xb9,0x54,0x16,0xb9,0xc,0xba,0x34,0x8b,0xd5,0x56,0x8c,0x3f,0xab,0x39,0xbc,0x16,0xdd,0xe9,0xe8,0xe8,0x18,0x47,0x8f,0x7e,0x9,0xc0,0xf0,0xf0,0x21,0x8e,0x1d,0x3b,0x3e,0x87,0x21,0xd7,0xae,0x5d,0xa7,0x5a,0xad,0xb6,0xf4,0x5,0xb3,0x6b,0xfa,0x78,0xa9,0x54,0x38,0x3,0x4c,0x2a,0x10,0x2,0xeb,0x51,0x3,0xe8,0x6,0x5e,0x1e,0x18,0x18,0xfc,0x5e,0xd3,0x44,0xa4,0xdf,0xb4,0x59,0x6e,0x46,0xb9,0x50,0x9a,0x7c,0xe4,0x62,0x28,0x8a,0xc6,0x2b,0xd1,0x2e,0x46,0x9d,0x12,0x37,0x9c,0xd2,0xc2,0xe4,0x9a,0x36,0x98,0xef,0x7b,0xe5,0xab,0x57,0x2f,0xbd,0x5,0xfc,0x5e,0x7,0x80,0xc,0x62,0x40,0xad,0x43,0x11,0x2,0x37,0x12,0x89,0xbe,0x9e,0xf3,0x1d,0x3a,0x34,0x93,0x55,0x96,0x4d,0xde,0x77,0x1b,0x3a,0xbb,0x87,0x5b,0xb7,0x66,0xb1,0x36,0x9c,0x20,0xe7,0x3b,0x5c,0xad,0x16,0x9e,0x78,0xf0,0x52,0x4a,0xb2,0xd9,0x89,0xcf,0xcb,0xe5,0xd2,0x59,0x60,0x22,0xa8,0x23,0x6c,0x4,0xc0,0x7,0xbc,0x72,0xb9,0x74,0x3b,0x1c,0x8e,0xac,0x34,0x4d,0x73,0x60,0xdc,0x9b,0xc1,0x14,0x1a,0x83,0xe1,0xe,0xc2,0x42,0x67,0xc6,0xf7,0x70,0x9a,0xb0,0x41,0x0,0x11,0x34,0xba,0x75,0x8b,0x35,0x56,0x8c,0x81,0x50,0x8c,0x51,0xb7,0xc2,0x5f,0xd5,0xfc,0x22,0x8a,0xe9,0xc5,0x75,0x83,0x77,0xef,0xfe,0x7b,0x50,0x9,0x24,0xc5,0x20,0x4d,0xa0,0x95,0x1e,0x30,0xd0,0xd7,0xd7,0xff,0x49,0x34,0x1a,0xdd,0x2c,0x4,0x84,0x84,0xce,0x6a,0x33,0xb6,0x48,0x3d,0xe0,0x49,0x6,0x5f,0x3c,0x3d,0x36,0x76,0xe3,0x53,0xe0,0xca,0x7c,0xf5,0x80,0x46,0x45,0xa8,0x13,0xe8,0x4f,0x26,0xbb,0xb7,0x25,0x93,0xdd,0xbb,0x74,0x5d,0x8b,0xdd,0xef,0xe1,0x9b,0x9,0xc3,0xf,0x23,0xf9,0xec,0xf5,0x8d,0xf7,0x69,0x9f,0x79,0x9e,0x57,0xc8,0x66,0x27,0xe,0x66,0xb3,0x35,0x45,0x68,0x6a,0x21,0x8a,0x50,0x3d,0x8,0xa6,0x6a,0x21,0x53,0xc0,0x8a,0x54,0x6a,0xc9,0x3b,0x4a,0x13,0xec,0x5,0x61,0x3c,0x6d,0x3d,0x70,0x6e,0x91,0x23,0x5d,0xd7,0xf5,0xee,0x2a,0x4d,0xf0,0x6b,0xe0,0xa6,0x5a,0xf3,0x85,0x3a,0x95,0xf8,0x91,0x55,0xe1,0x10,0x60,0x2b,0x46,0x24,0x3,0x54,0xe1,0xa7,0x69,0x8d,0xaa,0x70,0x56,0xcd,0x78,0x11,0x98,0x59,0x8c,0x2a,0x5c,0x7f,0x7c,0x16,0x8,0x43,0x2d,0xd,0xb3,0xae,0x67,0x78,0x16,0xf6,0x5,0x24,0xf7,0xf7,0x5,0xaa,0xea,0x35,0xe7,0x31,0xcf,0x4d,0x92,0x47,0xdd,0x19,0x7a,0x56,0x76,0x85,0x1a,0x81,0x58,0xf0,0xce,0xd0,0xb,0x7b,0x61,0xcf,0xb9,0xfd,0x7,0xde,0xc4,0x73,0xf5,0xe8,0x6c,0xed,0xda,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char toggle_on_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x20,0x8,0x6,0x0,0x0,0x0,0xa2,0x9d,0x7e,0x84,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x26,0x0,0x26,0x0,0x26,0x59,0xf,0xde,0x74,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x14,0x17,0x2,0x12,0xee,0x6d,0xd3,0x79,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x2,0xa7,0x49,0x44,0x41,0x54,0x68,0x81,0xed,0x99,0x4d,0x4f,0x13,0x51,0x14,0x86,0x9f,0x99,0x4e,0x6c,0x4b,0xc6,0x52,0xc5,0xb6,0x49,0x1b,0x5d,0xb1,0xf4,0x63,0x69,0x28,0x89,0xfc,0x7,0x63,0x42,0x8,0xff,0x40,0x11,0xc4,0x8d,0x51,0x2,0xb,0x5,0x56,0x86,0x8f,0xb8,0x51,0xff,0x0,0x69,0x20,0x24,0x6,0x24,0xfc,0x1,0x68,0x58,0x82,0x11,0x77,0x6e,0xc,0x24,0x2d,0x6,0x3a,0x49,0xad,0xd3,0x32,0xe5,0xba,0x18,0xdb,0x94,0x71,0x2,0xb1,0xb9,0x63,0x23,0x9d,0x67,0xd5,0xde,0x73,0xe6,0xcc,0x7b,0xde,0xe9,0x9d,0xcc,0x9c,0x82,0x8f,0x4f,0x5b,0xa3,0x38,0xbe,0x77,0x0,0x51,0x40,0x7,0x2,0x2e,0xf1,0xff,0x15,0x1,0x54,0x81,0x22,0x50,0x0,0x4a,0xb5,0x80,0xe6,0x48,0x8c,0x2,0xb7,0x81,0xeb,0x40,0x88,0x8b,0x65,0x80,0x9,0x7c,0x3,0x76,0x38,0xc3,0x0,0x1d,0xb8,0x71,0xeb,0xe6,0x9d,0xd9,0x54,0x32,0x15,0xd6,0x34,0xcd,0x53,0x3,0xaa,0x55,0x8b,0xe3,0x63,0xb,0xcb,0xb2,0x10,0x8,0x5b,0xa6,0x4c,0x14,0x50,0xec,0x6b,0x28,0xe,0xbe,0x1f,0xfc,0xfc,0xbc,0xfb,0x69,0x14,0xf8,0xda,0x98,0xe2,0x34,0x40,0x3,0x82,0xa9,0x64,0xaa,0xc3,0x34,0x4d,0x4c,0xd3,0x94,0xac,0xe8,0x34,0x95,0x4a,0x85,0x52,0xe9,0x7,0xe5,0x4a,0x5,0x71,0x72,0x62,0x9b,0x20,0x11,0x5,0x5,0x45,0x55,0xd1,0x75,0x5d,0x89,0x5d,0x8b,0x75,0x0,0x41,0x1c,0x3d,0x3b,0xd,0x0,0x50,0x34,0x4d,0xf3,0xbc,0x79,0x80,0x6a,0xb5,0x4a,0xb9,0x52,0x26,0x1a,0xbd,0x42,0x3c,0x16,0xaf,0x5d,0x2d,0x69,0x8,0x4,0xf9,0x83,0x3c,0x85,0xc2,0x11,0x5d,0x57,0xbb,0xc0,0x65,0x4b,0xbb,0x19,0xf0,0xcf,0x10,0x8,0xc4,0x89,0x20,0x11,0x4f,0x60,0x9a,0x26,0xf7,0x1f,0xf4,0x4b,0xad,0xbf,0xbc,0x94,0x21,0x11,0x4f,0x70,0x74,0x78,0x88,0x10,0xee,0xbf,0x2e,0x55,0xea,0x19,0x9b,0xa0,0xb6,0xf7,0x65,0x37,0xf,0xbf,0x6b,0xa,0xce,0xdc,0x5a,0x2d,0x37,0xa0,0xd5,0xf8,0x6,0x34,0x73,0x90,0xae,0xeb,0x8c,0x4f,0x8c,0xb1,0xb6,0xbe,0xca,0xda,0xfa,0x2a,0xe3,0x13,0x63,0xe8,0xba,0xe,0x40,0x76,0x6b,0x83,0xe7,0x2f,0x9e,0xd5,0x73,0xb3,0x5b,0x1b,0x72,0x94,0x7a,0x44,0x53,0x6,0x8c,0x3e,0x1d,0x1,0x60,0xa0,0x7f,0x90,0x81,0xfe,0x41,0x54,0x35,0x50,0x5f,0x3,0x48,0xf7,0xa6,0xe9,0xee,0xee,0x96,0xa3,0xd0,0x63,0x9a,0x32,0x20,0xdd,0x9b,0x66,0x7e,0xee,0xd,0x86,0x61,0x60,0x18,0x6,0x73,0xb3,0xf3,0xf4,0xa4,0x7b,0xea,0xf1,0x77,0x6f,0xdf,0xf3,0x64,0x74,0x58,0x9a,0x48,0x2f,0xf1,0xe4,0x1e,0xb0,0xba,0xf2,0x91,0x50,0x38,0x4c,0x5f,0xdf,0x3d,0x2f,0xca,0x4b,0xa5,0x29,0x3,0x36,0x37,0x36,0x79,0x3c,0x3c,0x44,0x24,0x12,0x21,0x12,0x89,0x30,0x3c,0x32,0x44,0x76,0x33,0x7b,0x2a,0x67,0xe6,0xf5,0xc,0x8f,0x86,0x1e,0x4a,0x11,0xe9,0x25,0x4e,0x3,0x42,0x40,0xe7,0x79,0x7,0xcd,0xce,0xcc,0xa3,0xaa,0xa,0x99,0xc5,0x5,0x32,0x8b,0xb,0xf5,0xb5,0x46,0x76,0x77,0xbf,0xb0,0xbd,0xbd,0x23,0x4b,0xa7,0x2c,0x3a,0xb1,0x7b,0xac,0xe3,0x7c,0x12,0x34,0x1,0xe3,0xbc,0x2a,0xc5,0x62,0x91,0x57,0x2f,0xa7,0x5c,0x63,0x3d,0x77,0x7b,0xeb,0x9f,0xa7,0x26,0xa7,0x99,0x9a,0x9c,0xfe,0x6b,0x95,0x1e,0x62,0x60,0xf7,0x58,0xc7,0x7f,0xe,0x68,0xb5,0x80,0x56,0xe3,0x1b,0xd0,0x6a,0x1,0x8a,0x3d,0xb5,0x60,0x79,0x29,0x23,0xbd,0xf6,0xf2,0x52,0xa6,0x71,0x28,0xe2,0x4a,0x4b,0x5f,0x87,0xed,0x81,0x85,0x42,0x2e,0x9f,0x23,0x1e,0x8b,0xb3,0xb6,0xf2,0x41,0x6a,0xfd,0x60,0x30,0x48,0x2e,0x9f,0x43,0x51,0x15,0x14,0xc5,0xdd,0x4,0x37,0x3,0x84,0x65,0x59,0x84,0x42,0x21,0xcf,0x87,0x22,0x81,0x40,0x80,0xe0,0xa5,0x20,0x85,0x42,0xc1,0x7e,0x67,0xf7,0x6c,0x22,0x74,0xb9,0xb6,0xf4,0xc7,0x9,0x9c,0x6,0x58,0x40,0x79,0x6f,0x7f,0xaf,0x94,0x4a,0xa6,0xc2,0xba,0xae,0x5f,0xa8,0x99,0x20,0x50,0xc6,0xee,0xb1,0x31,0xe5,0x14,0x49,0xda,0x63,0x2a,0xbc,0x5f,0xb,0xb4,0xfd,0xff,0x2,0x3e,0x3e,0x3e,0xed,0xcd,0x2f,0xbd,0x80,0xe4,0x2f,0x1f,0x1c,0x6a,0x6c,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x20,0x8,0x6,0x0,0x0,0x0,0xa2,0x9d,0x7e,0x84,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xb,0xd,0x15,0xc,0x32,0xd4,0x89,0x92,0x81,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x5,0xba,0x49,0x44,0x41,0x54,0x68,0xde,0xed,0x99,0x5d,0x6c,0x93,0x55,0x18,0xc7,0x7f,0xe7,0xbc,0xdd,0xdb,0x8e,0xf6,0xed,0xba,0x76,0x8d,0x8e,0x7d,0xf0,0x31,0x15,0x88,0x9a,0x11,0x95,0x85,0x18,0x24,0x12,0x21,0xde,0x1a,0xae,0x4d,0x8c,0xd1,0xe0,0x85,0x89,0x37,0x5e,0x68,0xe4,0xca,0xb,0xcc,0x48,0xbc,0x23,0x7a,0x41,0xd4,0xa0,0x21,0x41,0x4d,0x20,0x70,0x69,0xc0,0x8f,0xe0,0x47,0xc,0x86,0x44,0x8c,0xda,0x39,0x1,0x27,0x6c,0x40,0xe8,0xe7,0xf6,0xb6,0x5b,0xfb,0xb6,0xef,0x7b,0xbc,0xe8,0x59,0xa9,0xa5,0xd4,0x32,0x96,0x6d,0x6,0x4e,0x72,0xd2,0xf4,0xeb,0xbc,0xf9,0xff,0x9f,0xff,0x79,0xce,0xf3,0xfc,0xf,0xdc,0x1b,0x77,0xf7,0x10,0xb7,0xf9,0x5b,0x51,0xf7,0x1f,0xb1,0x42,0x30,0xa8,0xba,0x57,0x55,0xf7,0x7e,0xd1,0x8,0x90,0x7a,0x76,0xd4,0x4d,0x43,0x7f,0x26,0x56,0x0,0x78,0xf,0x70,0x81,0x72,0xdd,0xf4,0xf4,0xbc,0x23,0x2,0x84,0x6,0x6a,0x2,0x21,0x20,0xa2,0x67,0x18,0xe8,0xd4,0x44,0x2c,0x27,0x9,0xf3,0xe0,0xcb,0xc0,0x1c,0x30,0x3,0xe4,0xf4,0xcc,0x3,0x8e,0x26,0x46,0x2d,0x84,0x0,0x9,0xf8,0x34,0xf0,0x38,0xd0,0x6f,0x59,0x5d,0x4f,0x59,0x56,0xd7,0x2e,0xd3,0x34,0xd7,0x4b,0x69,0x84,0xa5,0x94,0x9d,0x42,0x88,0x65,0x55,0x80,0x52,0x4a,0x79,0x9e,0x37,0xe7,0x79,0xee,0x8c,0xe3,0x38,0x17,0x6d,0x7b,0xfa,0xa4,0x6d,0x4f,0x7f,0xb,0x4c,0x2,0x49,0x4d,0x44,0xa5,0x95,0x1a,0xc4,0x2d,0xc0,0x9b,0x40,0x17,0x30,0xb8,0x6a,0x55,0x68,0x7b,0x2c,0x16,0xdf,0xe3,0xf7,0x7,0x1e,0x5a,0x66,0xbc,0xed,0x10,0x42,0xa9,0x54,0x1c,0x4f,0xa7,0x93,0x7,0x67,0x67,0xf3,0xa7,0x81,0x4b,0xc0,0xb4,0x56,0x83,0xd7,0xe,0x1,0x42,0x83,0xef,0x6,0xd6,0x77,0x77,0xf7,0x3c,0x1f,0x8d,0xf6,0xbc,0x24,0xa5,0x34,0x97,0x1c,0x8d,0x3f,0x84,0x1c,0x18,0x46,0xf6,0xac,0x45,0x74,0x46,0x40,0xfa,0x6e,0xd,0xbc,0x52,0x42,0x5d,0xfb,0x3,0x77,0xe2,0x27,0x28,0xe5,0xf1,0x3c,0xcf,0xc9,0x64,0x52,0x1f,0x66,0xb3,0xa9,0xc3,0xc0,0x45,0x20,0xab,0x49,0x50,0xad,0x8,0x98,0xdf,0xf3,0x5d,0xc0,0x50,0x34,0x1a,0x7f,0x39,0x1a,0xed,0x79,0x79,0xc9,0x65,0x2e,0xd,0x64,0xff,0x30,0xb2,0xff,0x51,0xbc,0xeb,0x17,0xf0,0xae,0x8e,0xc1,0x6c,0x16,0x54,0x93,0x0,0xa,0x1,0xfe,0x10,0x58,0x3d,0xc8,0xd8,0x1a,0x64,0x6c,0x1d,0xde,0xe4,0xcf,0x78,0x97,0xcf,0xa1,0xdc,0x8a,0xca,0x64,0x52,0x1f,0x64,0x32,0xc9,0xf,0x80,0xb,0x5a,0x9,0x37,0xe5,0x4,0xa3,0x41,0xfa,0x1,0xa0,0x37,0x18,0xb4,0x9e,0x8d,0xc7,0xef,0x7b,0x5d,0x4a,0x69,0x2c,0x39,0xf8,0x7,0xb6,0x21,0xa2,0x3,0xb8,0x63,0x5f,0xa3,0xae,0xfe,0xe,0xe5,0xd9,0x16,0x79,0x4c,0x41,0xa5,0x4,0xb3,0x59,0x54,0x6a,0x2,0xcf,0xbe,0x8e,0xec,0x1f,0x46,0x84,0x62,0x90,0x9b,0x14,0x1,0xbf,0x7f,0xd8,0x71,0x4a,0x7f,0x95,0xcb,0xce,0x65,0xa0,0xa0,0xf3,0xc1,0x2d,0x9,0x30,0x74,0x96,0x7f,0xb0,0xb7,0xb7,0xff,0xed,0x8e,0x8e,0x8e,0xd8,0xd2,0x56,0x24,0x2,0xb9,0xfa,0x61,0x44,0xcf,0x1a,0xdc,0x5f,0xbf,0x80,0x42,0xfa,0xf6,0xd7,0x28,0xda,0xa8,0xec,0x24,0x72,0x60,0x18,0x21,0x4,0xe4,0x53,0xd2,0x34,0xcd,0xa1,0xe9,0xe9,0xec,0x69,0xbd,0xd,0x4a,0x8d,0x4,0xc8,0x3a,0xf9,0x77,0x0,0x5d,0xe1,0x70,0x64,0xbb,0xdf,0x1f,0x58,0xb7,0xe4,0x7b,0xde,0x17,0x40,0xe,0x6c,0xc6,0xfd,0xf3,0x7b,0x28,0xce,0x2c,0x7c,0x9d,0xe2,0xc,0xee,0xf9,0x1f,0x90,0x83,0x8f,0x41,0x47,0x27,0x7e,0x7f,0x60,0x5d,0x38,0x1c,0x79,0x4a,0x6f,0x6d,0x5f,0xb3,0x8c,0x5f,0x4f,0x40,0x24,0x14,0xa,0xef,0x6c,0xf7,0x59,0x7d,0x7d,0xab,0x19,0x1d,0xdd,0xc7,0xf8,0xf8,0x6f,0x9c,0x3d,0xfb,0x23,0xbb,0x77,0x3f,0x7,0xc0,0xc8,0xc8,0x16,0xc6,0xc7,0x7f,0x63,0xd3,0xa6,0x8d,0xb5,0xf7,0x87,0xf,0x1f,0x6a,0xad,0xfe,0xde,0x8d,0x78,0xb9,0x29,0x98,0xbe,0x72,0xe7,0x64,0xe6,0xa6,0xf0,0xb2,0x93,0xc8,0xfb,0x37,0x0,0x10,0xa,0x59,0x3b,0x75,0x62,0x37,0x1b,0x13,0x7f,0x23,0x1,0x61,0xd3,0x34,0xdb,0x8e,0xfe,0xfe,0xfd,0xef,0x10,0xe,0x87,0xd9,0xb1,0x63,0x17,0x6f,0xbc,0xf1,0x16,0xa3,0xa3,0xfb,0xe8,0xeb,0x5b,0x5d,0xfb,0x7e,0xef,0xde,0x37,0xdb,0xdf,0x1,0xb1,0xb5,0xa8,0xcc,0xa5,0xc5,0x3b,0x12,0x53,0x7f,0x23,0x62,0x6b,0x1,0x30,0x4d,0xff,0x90,0x2e,0xe0,0x7c,0x8d,0x4,0xf8,0x1a,0x72,0x40,0x40,0x4a,0x23,0xdc,0x6e,0xf4,0x47,0x46,0xb6,0xf0,0xf8,0xe3,0x5b,0xb1,0x6d,0x9b,0xa9,0xa9,0x2b,0x9c,0x3a,0xf5,0x15,0x3b,0x77,0x3e,0x43,0x22,0x31,0x46,0x22,0x31,0xc6,0xa6,0x4d,0x1b,0x19,0x19,0xd9,0xd2,0x1e,0x1,0xc1,0x28,0xca,0x4e,0x2e,0x1e,0x1,0xf9,0x24,0x22,0x18,0xad,0x2,0x33,0x7c,0x11,0x5d,0xbd,0x1a,0xb7,0x52,0x40,0xed,0x18,0x94,0x52,0x76,0xb6,0x47,0x40,0x1f,0x89,0xc4,0x18,0xb6,0x6d,0xd7,0x3e,0x4b,0x24,0x12,0x35,0xd9,0xdb,0xb6,0xcd,0xa1,0x43,0x9f,0xb4,0xad,0x2,0xd1,0x11,0x80,0x62,0x7e,0xf1,0x72,0x4a,0x31,0x5f,0x5d,0x13,0xd0,0x75,0x4c,0xd3,0xb2,0x5d,0x36,0xd6,0xd6,0x4a,0xa9,0x72,0x3b,0xeb,0xcf,0x47,0xd8,0xb2,0xac,0x7f,0x91,0x52,0x4f,0xc8,0x81,0x3,0xef,0x13,0xe,0x87,0x6b,0xb9,0xa1,0x65,0xc4,0xca,0x45,0x8,0x84,0x16,0x8f,0x80,0x40,0xa8,0xba,0x26,0xe0,0x79,0xde,0x7c,0x25,0xa8,0x5a,0x11,0xe0,0x2,0x73,0xae,0x5b,0xc9,0xb5,0xb3,0xbe,0x6d,0xdb,0x24,0x12,0x63,0x35,0x70,0x96,0x65,0xb1,0x6b,0x57,0x55,0xfe,0xf5,0xe3,0xc0,0x81,0xf7,0xda,0x23,0xa0,0x90,0x41,0x58,0xf1,0xc5,0x3b,0x55,0x43,0x71,0x54,0x21,0x53,0x5,0x56,0xc5,0x34,0xd7,0xac,0x10,0x92,0x75,0xd1,0x2f,0x3,0xb6,0xe3,0x38,0x17,0xda,0x7d,0xc8,0xbe,0x7d,0xa3,0xbc,0xf6,0xda,0xab,0x9c,0x38,0x71,0x94,0x6f,0xbe,0x39,0xc9,0xc9,0x93,0x5f,0x72,0xec,0xd8,0xf1,0x7f,0xfd,0xe6,0xd8,0xb1,0xe3,0x37,0x91,0xd2,0x94,0x80,0xf4,0x4,0x22,0x3a,0xb8,0x78,0x4,0xf4,0xac,0x41,0xa5,0x27,0x0,0x70,0x9c,0xd2,0x5,0xdd,0x2d,0x56,0xfe,0xab,0x12,0x34,0x85,0x10,0x56,0x28,0x64,0x6d,0x6f,0xe7,0x21,0x53,0x53,0x57,0x38,0x72,0xe4,0xb3,0x9a,0xdc,0x3f,0xfd,0xf4,0xf3,0x9b,0x14,0x2,0x70,0xee,0xdc,0x2f,0xa4,0x52,0xa9,0x96,0x44,0xa8,0xd9,0x69,0x8c,0xf5,0x5b,0xf1,0xec,0x14,0x94,0xec,0x3b,0x43,0x1f,0xe9,0xc3,0x18,0xdc,0x8c,0x3b,0x7e,0x1a,0xdc,0x32,0xd9,0x6c,0xfa,0xe3,0x52,0xa9,0x78,0x6,0xc8,0x68,0x12,0x9a,0xf6,0x2,0x3e,0x20,0x6,0x3c,0x3a,0x38,0xb8,0xfe,0xe0,0x92,0x17,0x43,0x42,0x20,0x57,0x3f,0x82,0xe8,0xdd,0x58,0xad,0x4,0x17,0x5a,0xc,0x5,0xc2,0x18,0x8f,0x3c,0x8b,0xba,0x36,0x86,0x37,0xf5,0x2b,0xa5,0xe2,0xdc,0x5f,0x97,0x2e,0x5d,0x7c,0x5,0xf8,0xa5,0x8e,0x0,0xd5,0x4c,0x1,0xf3,0x5b,0x41,0x54,0x2a,0x95,0x7c,0x30,0x68,0x3d,0x2d,0x84,0x90,0x4b,0xda,0xce,0x16,0xd2,0x88,0x60,0xc,0x39,0x30,0x8c,0x2a,0x64,0xa1,0x94,0xbf,0xfd,0xc8,0x6f,0xd8,0x81,0xb2,0xaf,0xe3,0xfd,0x7d,0x16,0xcf,0xad,0x54,0x92,0xc9,0x6b,0xef,0x96,0xcb,0xce,0x19,0x20,0xd5,0xac,0x23,0x6c,0x24,0xc0,0x3,0xdc,0x72,0xd9,0x99,0x16,0x42,0xc8,0xce,0xce,0x55,0x8f,0x2d,0x69,0x37,0xa8,0x14,0x2a,0x3b,0x89,0xf0,0x99,0x18,0x43,0x4f,0x82,0xdf,0x42,0x95,0x66,0xab,0xd,0xcf,0x4d,0xb6,0xa4,0x0,0x21,0x21,0x60,0x41,0x77,0x1f,0x72,0x70,0x33,0xc6,0x9a,0x27,0xaa,0x91,0x9f,0x38,0x83,0x72,0x2b,0x2a,0x9b,0x4d,0x7f,0x34,0x33,0x93,0x3d,0xaa,0xd,0x92,0x42,0x33,0x4f,0xa0,0x95,0x1f,0x30,0x14,0x8b,0xc5,0x5f,0x8c,0x44,0x62,0x2f,0x48,0xd9,0xa2,0x19,0x5f,0x99,0x7e,0x40,0x25,0x97,0x4b,0x7f,0x9c,0x4e,0x27,0xf,0x1,0xe7,0xdb,0xf5,0x3,0x1a,0x1d,0xa1,0x8,0x30,0x18,0xc,0x86,0xb6,0x47,0xa3,0xf1,0x3d,0x81,0x40,0xe7,0x83,0xff,0x7,0x9b,0xbb,0x58,0x9c,0xfb,0x33,0x93,0x49,0x1e,0x2c,0x14,0x6a,0x8e,0x50,0xee,0x76,0x1c,0xa1,0x7a,0x12,0x3a,0xb4,0x27,0xd8,0x3,0xc,0x58,0x56,0xd7,0x36,0xed,0x9,0x3e,0x60,0x18,0xbe,0xc8,0xb2,0xb8,0x44,0x4d,0x86,0xe7,0x79,0x8e,0xeb,0x56,0x72,0x8e,0xe3,0x9c,0xd7,0x9e,0xe0,0x77,0xc0,0x65,0xbd,0xe7,0xf3,0x75,0x2e,0xf1,0x82,0x5d,0x61,0x3f,0x10,0xd4,0x8a,0xe8,0x6e,0xe2,0xa,0x2f,0x2b,0xfe,0x6,0x57,0x38,0xab,0x23,0x5e,0xd0,0xbd,0xff,0x82,0x5d,0x61,0x1a,0xb2,0x8e,0xa1,0x8f,0x49,0x93,0x1b,0xf7,0x2,0x82,0x95,0x71,0x2f,0xa0,0xb8,0x71,0x2f,0xe0,0xe8,0x63,0xce,0xa5,0xcd,0x4b,0x92,0x85,0xde,0xc,0xad,0x34,0x7b,0x58,0xb1,0xc0,0x9b,0xa1,0x7b,0xe3,0xde,0xb8,0xcb,0xc7,0x3f,0xd2,0xdb,0x54,0x98,0x63,0x18,0x87,0x7d,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -410,7 +455,7 @@ static const unsigned char tooltip_bg_png[]={
static const unsigned char tree_bg_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x4c,0x0,0x4a,0x0,0x4e,0x88,0x29,0x6a,0xb6,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x10,0x12,0xb,0xd,0x3b,0xe,0x30,0x79,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0xbd,0x49,0x44,0x41,0x54,0x38,0x8d,0xdd,0x93,0x41,0x6a,0xc3,0x30,0x14,0x44,0xdf,0xa8,0x8a,0x97,0x26,0x27,0x48,0x9a,0x3,0xb4,0x90,0x1b,0xf4,0x66,0xf5,0x91,0x4b,0x16,0x9,0xd8,0x5f,0x9e,0x2e,0xac,0xa4,0x34,0xb8,0xb,0x6b,0xd9,0x1,0xa1,0x41,0x62,0x3e,0x33,0x1f,0x46,0xef,0x6f,0xe7,0xcf,0xcb,0xe5,0x6b,0x48,0x12,0x92,0x0,0xb0,0xbd,0xca,0xef,0xb0,0xcd,0x6c,0xd3,0xf7,0xfb,0x41,0xaf,0xc7,0x93,0xbb,0xdd,0x8e,0x9c,0xbb,0xe5,0x57,0x2,0x7b,0x9d,0x2f,0x6a,0x0,0x22,0x46,0xc6,0x69,0x22,0x27,0x89,0x9c,0x3b,0x72,0xce,0x6c,0x45,0x44,0x90,0x9e,0xed,0x6d,0x81,0x24,0xd2,0x2f,0x7b,0xdb,0xd4,0x0,0x75,0x40,0xb,0x6c,0x6c,0xd7,0x1,0xf7,0x45,0x6d,0x36,0x21,0x92,0x1b,0xc5,0x8f,0x8,0x92,0xda,0x76,0xf0,0xf,0x22,0x54,0xb4,0x47,0xa8,0x9a,0xf6,0x8,0x2c,0xa5,0xca,0xb3,0x4d,0xc4,0xf8,0xf3,0xfa,0x54,0x9a,0xbf,0xca,0x15,0x31,0x32,0xdb,0xbc,0x1c,0xe,0x27,0xae,0xb7,0xeb,0x47,0x29,0x41,0x29,0x41,0x89,0x69,0x39,0x25,0x88,0x7a,0xaf,0xf1,0x28,0x85,0xbe,0xdf,0xf,0xdf,0x7a,0xec,0x7c,0x19,0x53,0x3a,0x70,0xa,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0xa,0x0,0x0,0x0,0xa,0x8,0x6,0x0,0x0,0x0,0x8d,0x32,0xcf,0xbd,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xa,0x14,0x3,0x19,0x39,0x7c,0x34,0x43,0x7a,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0x9d,0x49,0x44,0x41,0x54,0x18,0xd3,0xb5,0x90,0x31,0xe,0xc2,0x40,0x10,0x3,0xed,0xbb,0xd5,0x25,0xa1,0xa1,0x3,0x9,0x41,0xc1,0x33,0x78,0x15,0x5f,0xc8,0x93,0x41,0x14,0x49,0x2e,0xbb,0xb7,0x29,0x2,0x52,0x20,0x14,0x34,0x58,0x72,0x63,0x4f,0x61,0x99,0xfb,0xdd,0xe1,0x9a,0x52,0xd5,0xc6,0x10,0x6b,0x92,0x58,0xca,0xdd,0x61,0xc5,0xfa,0x9c,0x87,0x96,0xa7,0xe3,0xf9,0x56,0xa5,0x7a,0x2b,0x22,0x0,0xde,0x41,0xc0,0xa1,0xaa,0x18,0x72,0x7f,0x97,0x18,0x62,0x23,0x22,0x88,0x22,0xe0,0x7,0xe8,0x70,0x0,0x80,0x6a,0x6c,0x2,0xc9,0x2,0x70,0x5,0x1,0x78,0x66,0x4,0xc9,0x12,0xf0,0xa3,0xfe,0x0,0xba,0x7b,0x98,0x67,0xfb,0xaa,0x9c,0x33,0x87,0xbb,0x7,0xb1,0x62,0x9d,0xaa,0xa6,0xd7,0xfc,0x6f,0xf7,0x58,0xb1,0x3e,0x36,0xf5,0xa6,0x3,0x70,0x29,0x66,0x30,0x53,0x5d,0x5a,0x75,0xd4,0x51,0xc7,0x47,0xce,0x43,0x3b,0x1,0xc,0x2e,0x55,0x5d,0x5f,0x72,0xb6,0x33,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -440,7 +485,7 @@ static const unsigned char tree_title_pressed_png[]={
static const unsigned char unchecked_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x0,0x0,0x0,0x0,0x0,0xf9,0x43,0xbb,0x7f,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x11,0x14,0x5,0x3b,0xd6,0x6,0x93,0xb9,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0xf2,0x49,0x44,0x41,0x54,0x38,0x8d,0xed,0x93,0xb1,0x4a,0xc4,0x50,0x10,0x45,0xcf,0x4b,0x26,0x71,0x2a,0xb7,0x58,0xc1,0xca,0x6f,0xb0,0xb4,0x74,0x75,0x59,0x11,0xbf,0xc1,0x1f,0xf0,0xaf,0xac,0xfc,0x1,0x61,0x11,0x45,0x85,0x5d,0xb6,0xb0,0xf4,0x1b,0xb4,0x10,0xd1,0x42,0xc1,0x65,0x30,0xb3,0x59,0x8b,0x24,0x10,0x10,0xf2,0x82,0xb5,0xb7,0x99,0xea,0xdc,0x79,0xf3,0xb8,0x37,0x50,0x29,0x0,0x9,0x20,0xf5,0xec,0x52,0x9,0x78,0x3d,0xd7,0xa1,0x86,0x33,0x60,0x8,0xec,0x0,0x9b,0x1d,0x26,0x25,0xf0,0x9,0x3c,0x1,0xef,0x40,0xd1,0x6c,0x1c,0x4a,0x2a,0xa3,0xf1,0xe1,0xe4,0x22,0xcb,0xb2,0xce,0xf5,0x45,0x51,0x70,0x7b,0x7f,0x73,0xea,0xee,0x77,0xc0,0x6b,0x0,0x36,0x80,0xdd,0xe3,0xa3,0x93,0x7,0x33,0xc3,0xcc,0x3a,0xd,0x54,0x15,0x55,0xe5,0xea,0x7a,0xba,0x7,0x3c,0x26,0xf5,0xb,0x6,0x22,0x12,0x85,0x1,0xcc,0xc,0x11,0x1,0x18,0x0,0x49,0x73,0x6b,0x88,0x92,0xbf,0x95,0x0,0x21,0xf6,0xe3,0xbd,0x5c,0xfe,0xd,0x2a,0xad,0xff,0xc0,0x96,0x8d,0x41,0x9,0x7c,0xb8,0x3b,0xaa,0x1a,0xa5,0x54,0x15,0x77,0x87,0x2a,0xd2,0xab,0x0,0xa4,0xc0,0x76,0x9e,0xe7,0x93,0x83,0xfd,0xf1,0x79,0x9f,0x28,0xcf,0x17,0xb3,0xb3,0xe5,0xf2,0xeb,0x12,0x78,0x69,0x97,0x69,0x8b,0xfe,0x65,0x7a,0x6,0xde,0x80,0xef,0x26,0x81,0xed,0x3a,0xa7,0x91,0x2b,0x56,0xb4,0xea,0xfc,0x3,0x6e,0x28,0x47,0x29,0x38,0xc5,0x49,0x7f,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xb,0xd,0x16,0x2f,0x23,0x2,0xd6,0x7b,0x4b,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0xe9,0x49,0x44,0x41,0x54,0x38,0xcb,0xed,0x93,0x4d,0x4e,0xc3,0x30,0x10,0x85,0x3f,0x4f,0x6c,0x71,0x1,0x1c,0x12,0x29,0x8b,0x6e,0x73,0x91,0x6e,0x10,0x7,0xe0,0x1c,0x3d,0x7,0x37,0x60,0xcf,0x1,0x10,0x8b,0xf6,0x22,0x15,0xbb,0x2e,0x2a,0xf5,0x7,0x2e,0x80,0xec,0x8e,0xd9,0x38,0x69,0x91,0x48,0x5a,0x4,0x4b,0x9e,0x34,0x2b,0xbf,0x19,0xbf,0x37,0x3f,0xf0,0x4b,0x18,0x80,0xbb,0xdb,0xfb,0x2b,0x60,0x2,0xb4,0x40,0x9,0xc8,0x0,0x5f,0x81,0x3d,0xb0,0x4,0x56,0xcf,0x2f,0x4f,0x1f,0x36,0x3f,0x4c,0xde,0xde,0x37,0xf,0xdb,0xdd,0x7a,0xaa,0xaa,0xce,0x18,0xf3,0x6d,0x76,0x4a,0x9,0x11,0x9,0xd5,0x4d,0xb3,0xf0,0xd7,0xf5,0xc,0x78,0xed,0x7e,0x6a,0xb7,0xbb,0xf5,0x14,0x70,0xd6,0x3a,0xc6,0x2,0x70,0x99,0xdb,0x2,0x74,0xa,0x4a,0x55,0x75,0xd6,0x3a,0x8a,0xa2,0x38,0xeb,0x3b,0xc6,0xe0,0xb2,0xd5,0xde,0xab,0x18,0x63,0x18,0x92,0xfe,0xa5,0x69,0x47,0x9e,0x30,0xd2,0xac,0x8b,0xf1,0x5f,0xe0,0x58,0x40,0x53,0x4a,0xa4,0x94,0xce,0x26,0x9c,0xf0,0xf4,0x74,0xf,0xf6,0x22,0x12,0x54,0xf,0xae,0x1b,0xd5,0x50,0xb2,0xea,0x1,0x11,0x89,0x79,0xa5,0x7b,0x5,0xcb,0xaa,0x6c,0x16,0x40,0x8c,0x31,0x30,0x16,0x60,0x42,0x55,0x36,0xf3,0x7c,0xf,0xbd,0x82,0x95,0xf7,0xf5,0xcc,0xfb,0xfa,0xf1,0x27,0xc7,0xc4,0x5f,0xe0,0x13,0xe5,0xc4,0x63,0x4f,0x20,0x8a,0x2e,0x80,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -455,17 +500,17 @@ static const unsigned char vseparator_png[]={
static const unsigned char vslider_bg_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xdd,0x0,0xdd,0x0,0xdd,0xf5,0x15,0x8,0x9d,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x14,0xf,0xc,0x18,0x82,0xe,0xe5,0x21,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0x4d,0x49,0x44,0x41,0x54,0x38,0x8d,0x63,0x60,0x18,0x68,0xc0,0x88,0x4d,0x50,0x42,0x42,0x62,0x1a,0x3,0x3,0x43,0x26,0x9a,0xf0,0xf4,0x17,0x2f,0x5e,0x64,0x11,0x6b,0xc0,0x7f,0x76,0x76,0x4e,0x14,0xb1,0x9f,0x3f,0xbf,0x33,0xbc,0x78,0xf1,0x2,0x43,0x3d,0x13,0xd1,0x6e,0xc5,0x1,0x46,0xd,0x18,0x35,0x0,0x9f,0x1,0xd3,0x7f,0xfe,0xfc,0xce,0x80,0x8c,0x19,0x18,0x18,0xa6,0x53,0x6a,0x19,0x6d,0x0,0x0,0x59,0x9c,0x18,0xe9,0x50,0xa4,0x59,0x7a,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xb,0xd,0x16,0x2c,0x30,0xad,0x45,0x69,0x56,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x1,0x87,0x49,0x44,0x41,0x54,0x38,0xcb,0xcd,0x93,0xcf,0x4e,0x13,0x51,0x14,0xc6,0x7f,0xf7,0xdc,0xc6,0x3b,0xd3,0xb1,0xc0,0x66,0x48,0x5b,0x42,0xea,0xc2,0xb4,0x2b,0x9f,0x81,0x7,0x30,0x3c,0x80,0x12,0x57,0x24,0xc6,0xc4,0xc8,0xd3,0xe0,0x12,0x37,0x68,0x7c,0x0,0xe3,0x3,0xf0,0xe,0x6e,0xb0,0x2c,0x68,0x50,0x20,0xce,0x6,0x3b,0x74,0xa6,0x3,0xce,0x3d,0x6c,0x4a,0x9d,0xd2,0x62,0xa2,0x2b,0xbf,0xe4,0x2c,0xee,0x9f,0xef,0x97,0x9c,0x2f,0xe7,0x18,0x2a,0xda,0x7c,0xfa,0xc,0xa0,0x6,0xac,0x2,0x5d,0x60,0x7d,0xf2,0x74,0x2,0x1c,0x2,0x9,0xf0,0xeb,0xd3,0xe7,0x8f,0x53,0x8f,0x59,0x60,0x7e,0x3c,0x4c,0x2f,0x76,0x92,0xe4,0xf4,0x79,0x96,0x8f,0x1a,0x0,0xf5,0x30,0x4a,0xe3,0xb8,0xfd,0x7e,0xa9,0xb1,0xb2,0xb,0x1c,0x55,0x21,0xc2,0xac,0xe2,0x61,0x7a,0xf1,0xe6,0x78,0xd0,0x7f,0x99,0xe5,0xd9,0xb2,0x88,0x15,0x11,0x2b,0x59,0x9e,0x2d,0x1f,0xf,0xfa,0xaf,0xd2,0xf4,0xe7,0x6b,0x20,0xae,0x1a,0xee,0x2,0x7a,0x49,0x72,0xba,0x65,0x8c,0xb1,0xd6,0x5a,0xaa,0x65,0x8c,0xb1,0x3f,0x92,0xef,0x2f,0x80,0x5e,0xd5,0x50,0xbb,0x3,0x58,0xcf,0xf2,0x51,0x43,0xc4,0x22,0xf2,0x9b,0x2d,0x22,0xa8,0x2a,0x59,0x3e,0x7a,0x58,0xc9,0x65,0x16,0x70,0x76,0x3e,0x0,0xd8,0xf6,0x5e,0xc5,0x5a,0xe6,0x64,0xc,0x78,0xaf,0xf6,0xec,0x7c,0xb0,0xd,0xec,0xcf,0x1,0x8a,0x62,0xc,0xb0,0x61,0xcc,0x4c,0xb6,0x55,0x4,0xc6,0x40,0x51,0x8c,0x37,0xfe,0x94,0xc1,0x5f,0xeb,0x3f,0x2,0x38,0x17,0xe0,0x5c,0x70,0xa0,0xa,0xa0,0xb,0xbe,0x2a,0xaa,0xe0,0x5c,0x70,0xe0,0x5c,0x30,0xf,0x68,0x35,0x3b,0xb4,0x9a,0x9d,0x3d,0x11,0xe3,0x75,0x81,0x5f,0x15,0x44,0x4c,0xd9,0x6a,0x76,0xf6,0x5a,0xcd,0xce,0xbd,0x2d,0x9c,0xd4,0xc3,0x28,0xf5,0xde,0xe3,0xbd,0x9f,0x5e,0xde,0x9e,0xeb,0x61,0x74,0x39,0xd9,0x8b,0x7b,0x1,0x87,0x71,0xdc,0xfe,0xa0,0xaa,0x65,0x59,0x96,0x54,0x4b,0x55,0xcb,0xd5,0x78,0x6d,0x7f,0xb2,0x54,0x53,0x4d,0x47,0xa6,0xd7,0x7d,0x2,0x30,0x76,0x2e,0x38,0xa,0xc3,0xa8,0x76,0x7d,0x35,0xee,0x5e,0x5d,0x17,0xf,0x54,0x55,0xeb,0x61,0x34,0x5c,0x6b,0x3f,0x7a,0xb7,0xd4,0x58,0x79,0xb,0x7c,0x3,0xfc,0xd7,0xfe,0x17,0xe6,0x26,0xe6,0x5f,0xd6,0xf9,0x6,0xaa,0x73,0x9f,0xf0,0x6d,0xf0,0x57,0x1b,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char vslider_grabber_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x92,0x0,0x92,0x0,0x99,0x25,0xc1,0x88,0x71,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x12,0x0,0x2,0x1f,0xac,0xde,0x45,0xed,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x1,0xa4,0x49,0x44,0x41,0x54,0x38,0x8d,0x9d,0x93,0xb1,0x6e,0x1a,0x41,0x14,0x45,0xcf,0xcc,0xce,0x9a,0x85,0x25,0x44,0x58,0x8a,0x15,0xc5,0x49,0x93,0x2,0xb2,0x2,0x51,0xf2,0x7,0x2e,0x68,0xf2,0x15,0xae,0x22,0xc1,0x77,0xa4,0xe,0x65,0x5c,0xe4,0x2f,0xf8,0xb,0x47,0xb6,0x2c,0x21,0xb0,0x44,0xb7,0x22,0x52,0x9a,0x0,0x82,0x9d,0xd9,0x1d,0x76,0xd3,0xec,0x22,0x40,0xb1,0x8d,0x72,0xa5,0x29,0xe6,0xcd,0xbd,0xf7,0xbd,0x79,0x33,0x4f,0x70,0x84,0x66,0xb3,0x79,0x1c,0x3a,0xc0,0x64,0x32,0x39,0xd8,0xcb,0x7f,0x88,0x2f,0x81,0xaf,0xc0,0x1d,0x10,0xe5,0xeb,0x2e,0x8f,0x5d,0x1e,0x27,0x10,0xdd,0x6e,0x17,0x80,0xc5,0x62,0x1,0x70,0xd,0x7c,0xb,0x82,0x76,0xb9,0x52,0xf1,0x71,0xdd,0x33,0x0,0x92,0x24,0x66,0xb3,0x59,0x33,0x1e,0x3f,0x44,0xc0,0xc0,0x5a,0x7b,0xb3,0x5e,0xaf,0x49,0xd3,0x14,0xe7,0xd3,0x87,0xe,0xbf,0xff,0xfc,0x2,0xb8,0xae,0xd7,0xcf,0xbf,0xb7,0x5a,0x1d,0xb7,0x5a,0xad,0xa1,0x94,0x42,0x8,0x81,0x10,0x2,0xa5,0x14,0xe5,0x72,0x85,0x8b,0x8b,0xb7,0xae,0xd6,0xd1,0xe7,0x38,0x36,0xa1,0xef,0xfb,0xb7,0x5a,0x6b,0x9c,0x33,0xdf,0x29,0xca,0x1e,0xb5,0x5a,0x1d,0xb7,0x54,0xf2,0x9e,0xbc,0xbf,0x52,0x8a,0x5a,0xed,0x35,0xf3,0x79,0x78,0x95,0x65,0xd9,0xf,0x6b,0xed,0xaa,0xe8,0x41,0x3f,0x8,0xda,0xe5,0xe7,0xc4,0x5,0x4a,0x25,0x8f,0x20,0x68,0x97,0x81,0xbe,0xeb,0xba,0xbb,0x26,0xf6,0x2a,0x15,0xff,0x45,0x71,0x81,0x9c,0xdb,0x53,0x4a,0x21,0xb3,0x2c,0x3,0x68,0x14,0xd,0x3b,0x5,0x39,0xb7,0x21,0xa5,0x3c,0x7c,0xc6,0xff,0x81,0x14,0x42,0x0,0x4c,0x93,0x24,0x3e,0x59,0x94,0x73,0xa7,0x69,0x9a,0xee,0x2a,0x18,0x6d,0x36,0xeb,0x93,0xd,0x72,0xee,0xc8,0x5a,0xbb,0x33,0x18,0x8e,0xc7,0xf,0x91,0x31,0xfa,0x45,0xb1,0x31,0xba,0xf8,0x50,0xc3,0x24,0x49,0x90,0xef,0xeb,0x1f,0x1,0x42,0x60,0x30,0x9b,0x3d,0xf2,0x9c,0x89,0x31,0x9a,0xd9,0xec,0x11,0x60,0xe0,0x38,0x4e,0xb8,0xdd,0x6e,0x71,0xde,0xbc,0x3b,0xc7,0xf3,0x3c,0x8c,0x31,0xb7,0x5a,0x47,0xe1,0x7c,0x1e,0x5e,0x55,0xab,0xaf,0x5c,0x29,0x25,0x52,0x4a,0xb2,0x2c,0x23,0x8e,0xd,0xab,0xd5,0x82,0xfb,0xfb,0x9f,0x91,0xd6,0xd1,0x17,0x6b,0xed,0xcd,0x72,0xb9,0x24,0x4d,0x53,0xc4,0x7e,0x86,0xbd,0x61,0xea,0x3,0x3d,0xa0,0x91,0x1f,0x4d,0x81,0x11,0x30,0x4,0xc2,0xfd,0x89,0x3c,0x30,0xd8,0x33,0x79,0x12,0xc7,0xe3,0xfc,0x17,0x9c,0xcc,0xa8,0xb2,0xd4,0xe8,0x7,0x23,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xb,0xd,0x15,0x1b,0x38,0x31,0xdf,0xff,0x9,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x1,0x7d,0x49,0x44,0x41,0x54,0x38,0xcb,0xdd,0x92,0x3d,0x6b,0x53,0x61,0x14,0x80,0x9f,0xf7,0x43,0xdf,0xfb,0x11,0x6f,0x9b,0x86,0x1a,0x84,0x3a,0x84,0x98,0x25,0x29,0xd,0x11,0x87,0x40,0x3b,0x64,0x70,0x89,0x6b,0x97,0x6c,0xa5,0x7b,0x6,0xc9,0x3f,0xe8,0xe2,0xe4,0x2f,0xb8,0x8b,0x6b,0x17,0x9d,0x1d,0xb2,0x25,0x43,0x29,0x4,0x41,0x42,0x21,0x43,0x20,0x1d,0x3b,0x8,0x49,0x24,0x2f,0x5c,0xc3,0xbd,0xaf,0x4b,0xb,0xb6,0xb6,0xe,0x6e,0xfa,0x2c,0x7,0xe,0x9c,0xf,0xce,0x73,0xe0,0x9f,0x47,0x3c,0x90,0x93,0x80,0x1,0x9e,0x0,0x21,0xf0,0x18,0x70,0xc0,0xa,0x58,0x0,0x16,0x48,0xef,0x6b,0xf0,0x8,0xd8,0x28,0x95,0x4a,0xcf,0x1b,0x8d,0xc6,0xab,0x7a,0xbd,0xfe,0x26,0x8a,0xa2,0x5d,0x63,0xcc,0xb6,0x94,0xd2,0x2d,0x16,0x8b,0xaf,0xd3,0xe9,0xf4,0x63,0x1c,0xc7,0xa7,0xc0,0x37,0x20,0x15,0xbf,0x4c,0xd,0x72,0xb9,0x5c,0xa9,0xdb,0xed,0xbe,0x2d,0x16,0x8b,0xaf,0x8d,0x31,0x3b,0x49,0x92,0xa8,0xf5,0x7a,0x4d,0x9a,0xa6,0x0,0x18,0x63,0xd0,0x5a,0x5f,0x8d,0xc7,0xe3,0x77,0x71,0x1c,0x7f,0x0,0xbe,0x6b,0x40,0x3,0x9b,0xcd,0x66,0x73,0xbf,0xd3,0xe9,0xbc,0x57,0x4a,0xbd,0xb0,0xd6,0x62,0xad,0x25,0xcb,0xb2,0x5b,0xeb,0xa5,0x69,0x4a,0x10,0x4,0xc5,0x72,0xb9,0x7c,0x8,0x7c,0xba,0x69,0x60,0x7a,0xbd,0xde,0x51,0xb5,0x5a,0x3d,0x99,0xcf,0xe7,0xe1,0x6a,0xb5,0xfa,0xad,0xf0,0x6,0xe7,0x1c,0x49,0x92,0x90,0xcf,0xe7,0xf7,0xae,0x6f,0x83,0x4,0x84,0xe7,0x79,0x1,0xa0,0xfe,0xc6,0x82,0x2,0xb2,0xc1,0x60,0x70,0xb1,0x5c,0x2e,0xbf,0xd4,0x6a,0xb5,0x97,0x9e,0xe7,0x6d,0x65,0x59,0x86,0x73,0xe,0xe7,0xdc,0x6d,0x3d,0x42,0xe0,0xfb,0x3e,0xd6,0xda,0xf3,0x7e,0xbf,0x7f,0xa,0x2c,0x15,0x90,0x1,0x76,0x36,0x9b,0x5d,0xe,0x87,0xc3,0xcf,0x95,0x4a,0x85,0x42,0xa1,0xf0,0x34,0xc,0xc3,0xd,0x21,0x84,0x0,0x90,0x52,0x22,0xa5,0xc4,0xf7,0x7d,0xb4,0xd6,0x57,0x93,0xc9,0x24,0x1e,0x8d,0x46,0x67,0xc0,0x8f,0xfb,0x34,0x46,0x5a,0xeb,0xed,0x76,0xbb,0x7d,0xd0,0x6a,0xb5,0x8e,0x85,0x10,0xcf,0x8c,0x31,0x5b,0x4a,0xa9,0x3f,0x6a,0xbc,0x8b,0x4,0x2,0x20,0xba,0x8e,0xfa,0xa1,0x47,0xfa,0xf,0xf8,0x9,0xc2,0x2d,0x88,0xfe,0x7,0xd8,0xc3,0x3a,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
static const unsigned char vslider_grabber_hl_png[]={
-0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x92,0x0,0x92,0x0,0x99,0x25,0xc1,0x88,0x71,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x12,0x0,0x2,0x21,0x6d,0xbf,0x58,0x46,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x1,0x30,0x49,0x44,0x41,0x54,0x38,0x8d,0xa5,0x93,0xb1,0x6a,0xc2,0x50,0x14,0x86,0xbf,0x63,0xe2,0x90,0xd0,0x2e,0xc1,0xad,0x8b,0xad,0x60,0x9e,0xc0,0xbe,0x41,0x7,0x33,0x38,0x7,0x1d,0xba,0x74,0x2a,0xe8,0xc3,0xe8,0x68,0xc1,0x49,0xc8,0xec,0x10,0x9f,0xa1,0x8,0xee,0x71,0xcf,0x52,0x4d,0x70,0x73,0x8a,0xb7,0x83,0x37,0x72,0x11,0xb4,0xa1,0xfe,0xe3,0xe5,0x7c,0xdf,0xbd,0x1c,0xfe,0xb,0x77,0x46,0x2e,0xf,0x7c,0xdf,0x7f,0x2,0x86,0x40,0x17,0x68,0xeb,0xe3,0xd,0xb0,0x4,0x26,0x49,0x92,0xa4,0x57,0x5,0xbe,0xef,0x7f,0x0,0xe3,0x30,0x1c,0x38,0x9e,0xd7,0x40,0xa4,0x6,0x80,0x52,0x47,0xf2,0x7c,0x47,0x14,0xcd,0xf,0xc0,0x28,0x49,0x92,0xaf,0x92,0xb1,0x4c,0xb8,0xd9,0x7c,0x9e,0xf6,0xfb,0xef,0x75,0xd7,0x7d,0xd4,0xb0,0x0,0x82,0x48,0xd,0xd7,0x7d,0xa0,0xd3,0x79,0xad,0x6f,0xb7,0x3f,0x3d,0xdb,0xb6,0xd2,0x2c,0xcb,0xd6,0x0,0x35,0xe3,0xd9,0xe3,0x20,0xe8,0x21,0x62,0x71,0x2d,0x22,0x16,0x41,0xd0,0x3,0x18,0x6b,0xe6,0x24,0x0,0x86,0x61,0x38,0x70,0x6e,0xc1,0xa6,0x24,0xc,0x7,0x8e,0xde,0xd3,0x59,0xd0,0xf5,0xbc,0xc6,0x9f,0x70,0x19,0x3d,0xdb,0x35,0x5,0xed,0x72,0x61,0x55,0xa2,0x67,0xdb,0xa6,0xe0,0xdf,0x29,0x5,0x1b,0xa5,0x8e,0x95,0x21,0x3d,0xbb,0x31,0x5,0xcb,0x3c,0xdf,0x55,0x16,0xe8,0xd9,0xa5,0x29,0x98,0x44,0xd1,0xfc,0xa0,0x54,0x51,0xe1,0xf6,0xa2,0x2c,0xd4,0xe4,0x2c,0xd0,0xf5,0x1c,0xc5,0xf1,0x82,0x5b,0x12,0xa5,0xa,0xe2,0x78,0x1,0xa7,0x36,0xa6,0x60,0x34,0x31,0xcb,0xb2,0xb5,0x6d,0x5b,0xe9,0x6a,0xf5,0xfd,0xd6,0x6a,0xbd,0xd4,0x1d,0xc7,0x41,0x44,0x34,0x78,0x24,0xcf,0xb7,0xcc,0x66,0xd3,0xc3,0x7e,0xbf,0xff,0x34,0xab,0x7c,0xf7,0x67,0xba,0x3b,0xbf,0x4d,0x78,0x75,0x34,0x1f,0x21,0x5d,0xa6,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
+0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0xb,0xd,0x15,0x1c,0x11,0x3c,0x2c,0xf1,0xa2,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x1,0x93,0x49,0x44,0x41,0x54,0x38,0xcb,0xdd,0x92,0x3f,0x4c,0x13,0x71,0x14,0xc7,0x3f,0xef,0x77,0x7f,0x5a,0xae,0xde,0x1d,0x57,0x3,0x47,0x13,0x19,0x1a,0x48,0x14,0x2,0xc,0xe2,0x62,0x80,0xc8,0x40,0x22,0x31,0x71,0x20,0xec,0x18,0x77,0x7,0x27,0xb6,0xe,0x2e,0x2e,0x32,0xe1,0xc6,0xc2,0x5a,0x7,0x9,0x21,0xe,0xdd,0x88,0x9b,0x61,0x91,0x34,0x6a,0x17,0x63,0xe2,0x60,0x28,0x10,0x4c,0x28,0x96,0x96,0xbb,0xde,0xfd,0x5c,0x20,0x51,0xfe,0x98,0x38,0xea,0x67,0x79,0xc9,0x4b,0xde,0xf7,0xbd,0x7c,0xbf,0xf,0xfe,0x79,0xe4,0x8a,0x9e,0x2,0x32,0x80,0xb,0xe4,0x0,0x1b,0xd0,0x40,0x13,0x38,0x4,0x8e,0x81,0xe4,0x32,0x1,0xb,0xf0,0xc3,0xe1,0xa1,0xfe,0x81,0x7b,0xd3,0x77,0x8a,0x53,0x93,0xf,0x6c,0x37,0x1c,0x51,0xe6,0xb5,0x1e,0x65,0x2a,0x1d,0xff,0xd8,0xa9,0xd6,0x3f,0x54,0x5f,0x57,0x4a,0xa5,0x32,0x70,0x0,0x24,0xf2,0xcb,0x56,0x27,0xeb,0xfb,0xc5,0x87,0x4b,0x2f,0x9e,0xe6,0xc2,0x81,0x99,0x54,0x77,0xdf,0x68,0x35,0x62,0x23,0x6a,0x76,0xe8,0xc4,0x29,0x22,0x90,0xf5,0x6c,0xdc,0x20,0xda,0xdd,0xd9,0x7e,0xfb,0xbc,0x52,0x2a,0xad,0x2,0x47,0x26,0x60,0x2,0xdd,0x37,0x67,0xef,0x4f,0x4c,0x3c,0x59,0x5c,0x6a,0xb7,0xbc,0xc1,0xef,0xdf,0x4e,0x88,0xdb,0x47,0xa4,0x89,0xfe,0xed,0xbc,0x4e,0xd4,0x6,0xb2,0x61,0xdf,0xc8,0xd8,0x3c,0xb0,0x76,0x26,0x90,0x99,0x7b,0xb9,0xfc,0x28,0x1c,0x9d,0x7a,0xb6,0xf7,0xa5,0x95,0x6b,0x1d,0x36,0x2f,0xc,0x9e,0xa1,0x53,0x4d,0xbb,0x11,0x11,0x14,0xa,0x63,0xa7,0xde,0xa0,0x0,0xb1,0x1c,0xc7,0x41,0x30,0xb4,0xfe,0xfb,0x14,0xc,0x20,0xfd,0xb8,0xb1,0xf1,0xe9,0xa4,0xb1,0xff,0x7e,0x70,0x7a,0xfc,0xb6,0xd9,0xe5,0xe6,0xd3,0x58,0xa3,0x53,0xcd,0x79,0x41,0x51,0x82,0x13,0x64,0x30,0xa5,0xbe,0xb5,0xfd,0xaa,0x5c,0x6,0x1a,0x6,0x90,0x2,0xc7,0x7b,0xb5,0xda,0xd7,0xda,0x9b,0xf5,0x4a,0xf1,0xee,0x2d,0xf2,0xfd,0xd7,0x7b,0xbb,0x7c,0xcf,0x17,0x11,0x41,0x40,0x44,0x30,0x2c,0x85,0x13,0x64,0x70,0x83,0x68,0xb7,0x5e,0xdd,0x5a,0xf9,0xbc,0xb9,0xf9,0xe,0x88,0x2e,0x8b,0xd1,0x33,0x2c,0xab,0x67,0x7c,0x61,0x61,0x72,0x74,0x6e,0xfe,0x71,0x92,0xd8,0x5,0xc3,0xce,0xe5,0x95,0x69,0xfc,0x31,0xc6,0xf3,0x28,0xc0,0x1,0xbc,0xd3,0x6a,0x5e,0xf5,0x48,0xff,0x1,0x3f,0x1,0xa3,0x8a,0x90,0x14,0xe9,0x66,0x95,0x43,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82
};
@@ -484,3 +529,42 @@ static const unsigned char vsplitter_png[]={
};
+
+
+
+static const char *uv_editor_shader_code=
+ "vec3 nd1sl2=vec3(UV,0);"
+ "uniform float H=0;"
+ "float nd4sl0=H;"
+ "float nd7sl0=nd1sl2.x;"
+ "float nd7sl1=nd1sl2.y;"
+ "float nd7sl2=nd1sl2.z;"
+ "float nd2sl1def=-1;"
+ "float nd2sl0=nd7sl1*nd2sl1def;"
+ "float nd6sl1def=1;"
+ "float nd6sl0=nd2sl0+nd6sl1def;"
+ "vec3 nd3sl0=vec3(nd4sl0,nd7sl0,nd6sl0);"
+ "vec3 nd5sl0;"
+ "{"
+ " vec3 c = nd3sl0;"
+ " vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);"
+ " vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);"
+ " nd5sl0=c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);"
+ "}"
+ "COLOR.rgb=nd5sl0;";
+
+
+static const char *w_editor_shader_code=
+ "vec3 nd1sl2=vec3(UV,0);"
+ "float nd2sl1=1-nd1sl2.y;"
+ "vec3 nd3sl0=vec3(nd2sl1,1,1);"
+ "vec3 nd6sl0;"
+ "{"
+ " vec3 c = nd3sl0;"
+ " vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);"
+ " vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);"
+ " nd6sl0=c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);"
+ "}"
+ "COLOR.rgb=nd6sl0;";
+
+
diff --git a/scene/resources/default_theme/toggle_off.png b/scene/resources/default_theme/toggle_off.png
index 3e92aa0ece..aa1c96e5a0 100644
--- a/scene/resources/default_theme/toggle_off.png
+++ b/scene/resources/default_theme/toggle_off.png
Binary files differ
diff --git a/scene/resources/default_theme/toggle_on.png b/scene/resources/default_theme/toggle_on.png
index a49c234f51..0a69d36ae8 100644
--- a/scene/resources/default_theme/toggle_on.png
+++ b/scene/resources/default_theme/toggle_on.png
Binary files differ
diff --git a/scene/resources/default_theme/tree_bg.png b/scene/resources/default_theme/tree_bg.png
index 6b9c9b4f8d..e1c42a39ec 100644
--- a/scene/resources/default_theme/tree_bg.png
+++ b/scene/resources/default_theme/tree_bg.png
Binary files differ
diff --git a/scene/resources/default_theme/unchecked.png b/scene/resources/default_theme/unchecked.png
index 39a70e6003..f8710d03df 100644
--- a/scene/resources/default_theme/unchecked.png
+++ b/scene/resources/default_theme/unchecked.png
Binary files differ
diff --git a/scene/resources/default_theme/uv_editor.gsl b/scene/resources/default_theme/uv_editor.gsl
new file mode 100644
index 0000000000..8c24e76dd5
--- /dev/null
+++ b/scene/resources/default_theme/uv_editor.gsl
@@ -0,0 +1,19 @@
+vec3 nd1sl2=vec3(UV,0);
+uniform float H=0;
+float nd4sl0=H;
+float nd7sl0=nd1sl2.x;
+float nd7sl1=nd1sl2.y;
+float nd7sl2=nd1sl2.z;
+float nd2sl1def=-1;
+float nd2sl0=nd7sl1*nd2sl1def;
+float nd6sl1def=1;
+float nd6sl0=nd2sl0+nd6sl1def;
+vec3 nd3sl0=vec3(nd4sl0,nd7sl0,nd6sl0);
+vec3 nd5sl0;
+{
+ vec3 c = nd3sl0;
+ vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
+ vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
+ nd5sl0=c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
+}
+COLOR.rgb=nd5sl0; \ No newline at end of file
diff --git a/scene/resources/default_theme/vslider_bg.png b/scene/resources/default_theme/vslider_bg.png
index 5472bb366f..d58d4b1659 100644
--- a/scene/resources/default_theme/vslider_bg.png
+++ b/scene/resources/default_theme/vslider_bg.png
Binary files differ
diff --git a/scene/resources/default_theme/vslider_grabber.png b/scene/resources/default_theme/vslider_grabber.png
index 988c25d9dd..50ef5680da 100644
--- a/scene/resources/default_theme/vslider_grabber.png
+++ b/scene/resources/default_theme/vslider_grabber.png
Binary files differ
diff --git a/scene/resources/default_theme/vslider_grabber_hl.png b/scene/resources/default_theme/vslider_grabber_hl.png
index f319df3319..93eba4b174 100644
--- a/scene/resources/default_theme/vslider_grabber_hl.png
+++ b/scene/resources/default_theme/vslider_grabber_hl.png
Binary files differ
diff --git a/scene/resources/default_theme/w_editor.gsl b/scene/resources/default_theme/w_editor.gsl
new file mode 100644
index 0000000000..6d2dd9a0bb
--- /dev/null
+++ b/scene/resources/default_theme/w_editor.gsl
@@ -0,0 +1,11 @@
+vec3 nd1sl2=vec3(UV,0);
+float nd2sl1=1-nd1sl2.y;
+vec3 nd3sl0=vec3(nd2sl1,1,1);
+vec3 nd6sl0;
+{
+ vec3 c = nd3sl0;
+ vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
+ vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
+ nd6sl0=c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
+}
+COLOR.rgb=nd6sl0; \ No newline at end of file
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index ffa02e819c..4551aff0ef 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/environment.h b/scene/resources/environment.h
index bee45b78cd..4620bf567a 100644
--- a/scene/resources/environment.h
+++ b/scene/resources/environment.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/event_stream.cpp b/scene/resources/event_stream.cpp
index e8cd08c064..8667bcc5db 100644
--- a/scene/resources/event_stream.cpp
+++ b/scene/resources/event_stream.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/event_stream.h b/scene/resources/event_stream.h
index f9a5e3785a..6ee9b76717 100644
--- a/scene/resources/event_stream.h
+++ b/scene/resources/event_stream.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 2d93113b40..0aae6fd978 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -462,31 +462,16 @@ void Font::draw_halign(RID p_canvas_item, const Point2& p_pos, HAlign p_align,fl
void Font::draw(RID p_canvas_item, const Point2& p_pos, const String& p_text, const Color& p_modulate,int p_clip_w) const {
- Point2 pos=p_pos;
- float ofs=0;
- VisualServer *vs = VisualServer::get_singleton();
+ Vector2 ofs;
for (int i=0;i<p_text.length();i++) {
- const Character * c = char_map.getptr(p_text[i]);
+ int width = get_char_size(p_text[i]).width;
- if (!c)
- continue;
-
-// if (p_clip_w>=0 && (ofs+c->rect.size.width)>(p_clip_w))
-// break; //width exceeded
-
- if (p_clip_w>=0 && (ofs+c->rect.size.width)>p_clip_w)
+ if (p_clip_w>=0 && (ofs.x+width)>p_clip_w)
break; //clip
- Point2 cpos=pos;
- cpos.x+=ofs+c->h_align;
- cpos.y-=ascent;
- cpos.y+=c->v_align;
- ERR_CONTINUE( c->texture_idx<-1 || c->texture_idx>=textures.size());
- if (c->texture_idx!=-1)
- textures[c->texture_idx]->draw_rect_region( p_canvas_item, Rect2( cpos, c->rect.size ), c->rect, p_modulate );
-
- ofs+=get_char_size(p_text[i],p_text[i+1]).width;
+
+ ofs.x+=draw_char(p_canvas_item,p_pos+ofs,p_text[i],p_text[i+1],p_modulate);
}
}
@@ -494,8 +479,11 @@ float Font::draw_char(RID p_canvas_item, const Point2& p_pos, const CharType& p_
const Character * c = char_map.getptr(p_char);
- if (!c)
+ if (!c) {
+ if (fallback.is_valid())
+ return fallback->draw_char(p_canvas_item,p_pos,p_char,p_next,p_modulate);
return 0;
+ }
Point2 cpos=p_pos;
cpos.x+=c->h_align;
@@ -508,6 +496,16 @@ float Font::draw_char(RID p_canvas_item, const Point2& p_pos, const CharType& p_
return get_char_size(p_char,p_next).width;
}
+void Font::set_fallback(const Ref<Font> &p_fallback) {
+
+ fallback=p_fallback;
+}
+
+Ref<Font> Font::get_fallback() const{
+
+ return fallback;
+}
+
void Font::_bind_methods() {
ObjectTypeDB::bind_method(_MD("create_from_fnt","path"),&Font::create_from_fnt);
@@ -519,7 +517,7 @@ void Font::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_descent"),&Font::get_descent);
ObjectTypeDB::bind_method(_MD("add_kerning_pair","char_a","char_b","kerning"),&Font::add_kerning_pair);
- ObjectTypeDB::bind_method(_MD("get_kerning_pair"),&Font::get_kerning_pair);
+ ObjectTypeDB::bind_method(_MD("get_kerning_pair","char_a","char_b"),&Font::get_kerning_pair);
ObjectTypeDB::bind_method(_MD("add_texture","texture:Texture"),&Font::add_texture);
ObjectTypeDB::bind_method(_MD("add_char","character","texture","rect","align","advance"),&Font::add_char,DEFVAL(Point2()),DEFVAL(-1));
@@ -548,6 +546,8 @@ void Font::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_set_textures"),&Font::_set_textures);
ObjectTypeDB::bind_method(_MD("_get_textures"),&Font::_get_textures);
+ ObjectTypeDB::bind_method(_MD("set_fallback","fallback"),&Font::set_fallback);
+ ObjectTypeDB::bind_method(_MD("get_fallback"),&Font::get_fallback);
ADD_PROPERTY( PropertyInfo( Variant::ARRAY, "textures", PROPERTY_HINT_NONE,"", PROPERTY_USAGE_NOEDITOR ), _SCS("_set_textures"), _SCS("_get_textures") );
ADD_PROPERTY( PropertyInfo( Variant::INT_ARRAY, "chars", PROPERTY_HINT_NONE,"", PROPERTY_USAGE_NOEDITOR ), _SCS("_set_chars"), _SCS("_get_chars") );
@@ -556,6 +556,7 @@ void Font::_bind_methods() {
ADD_PROPERTY( PropertyInfo( Variant::REAL, "height", PROPERTY_HINT_RANGE,"-1024,1024,1" ), _SCS("set_height"), _SCS("get_height") );
ADD_PROPERTY( PropertyInfo( Variant::REAL, "ascent", PROPERTY_HINT_RANGE,"-1024,1024,1" ), _SCS("set_ascent"), _SCS("get_ascent") );
ADD_PROPERTY( PropertyInfo( Variant::BOOL, "distance_field" ), _SCS("set_distance_field_hint"), _SCS("is_distance_field_hint") );
+ ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "fallback", PROPERTY_HINT_RESOURCE_TYPE,"Font" ), _SCS("set_fallback"), _SCS("get_fallback") );
}
diff --git a/scene/resources/font.h b/scene/resources/font.h
index 6728b59f8e..61f0352992 100644
--- a/scene/resources/font.h
+++ b/scene/resources/font.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -84,6 +84,7 @@ private:
void _set_textures(const Vector<Variant> & p_textures);
Vector<Variant> _get_textures() const;
+ Ref<Font> fallback;
protected:
static void _bind_methods();
@@ -113,9 +114,13 @@ public:
int get_kerning_pair(CharType p_A,CharType p_B) const;
Vector<KerningPairKey> get_kerning_pair_keys() const;
- _FORCE_INLINE_ Size2 get_char_size(CharType p_char,CharType p_next=0) const;
+ inline Size2 get_char_size(CharType p_char,CharType p_next=0) const;
Size2 get_string_size(const String& p_string) const;
+
+ void set_fallback(const Ref<Font> &p_fallback);
+ Ref<Font> get_fallback() const;
+
void clear();
void set_distance_field_hint(bool p_distance_field);
@@ -134,8 +139,11 @@ Size2 Font::get_char_size(CharType p_char,CharType p_next) const {
const Character * c = char_map.getptr(p_char);
- if (!c)
+ if (!c) {
+ if (fallback.is_valid())
+ return fallback->get_char_size(p_char,p_next);
return Size2();
+ }
Size2 ret(c->advance,c->rect.size.y);
diff --git a/scene/resources/gibberish_stream.cpp b/scene/resources/gibberish_stream.cpp
index 23b94c8f38..9d67069a6c 100644
--- a/scene/resources/gibberish_stream.cpp
+++ b/scene/resources/gibberish_stream.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,6 +29,8 @@
#include "gibberish_stream.h"
#include "servers/audio_server.h"
+#if 0
+
int AudioStreamGibberish::get_channel_count() const {
return 1;
@@ -328,3 +330,4 @@ AudioStreamGibberish::AudioStreamGibberish() {
paused=false;
active_voices=0;
}
+#endif
diff --git a/scene/resources/gibberish_stream.h b/scene/resources/gibberish_stream.h
index a52e629f83..e06dc5eff2 100644
--- a/scene/resources/gibberish_stream.h
+++ b/scene/resources/gibberish_stream.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,7 +29,7 @@
#ifndef GIBBERISH_STREAM_H
#define GIBBERISH_STREAM_H
-
+#if 0
#include "scene/resources/audio_stream.h"
#include "scene/resources/sample_library.h"
class AudioStreamGibberish : public AudioStream {
@@ -109,4 +109,6 @@ public:
AudioStreamGibberish();
};
+#endif
+
#endif // GIBBERISH_STREAM_H
diff --git a/scene/resources/height_map_shape.cpp b/scene/resources/height_map_shape.cpp
index 2c7c5384fa..e7b53c92c2 100644
--- a/scene/resources/height_map_shape.cpp
+++ b/scene/resources/height_map_shape.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/height_map_shape.h b/scene/resources/height_map_shape.h
index 46d49dab08..5494075107 100644
--- a/scene/resources/height_map_shape.h
+++ b/scene/resources/height_map_shape.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index bbb2a386f3..e56314c1f8 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -406,7 +406,6 @@ void FixedMaterial::_bind_methods() {
BIND_CONSTANT( PARAM_SHADE_PARAM );
BIND_CONSTANT( PARAM_MAX );
-
BIND_CONSTANT( TEXCOORD_SPHERE );
BIND_CONSTANT( TEXCOORD_UV );
BIND_CONSTANT( TEXCOORD_UV_TRANSFORM );
@@ -417,6 +416,11 @@ void FixedMaterial::_bind_methods() {
BIND_CONSTANT( FLAG_USE_POINT_SIZE );
BIND_CONSTANT( FLAG_DISCARD_ALPHA );
+ BIND_CONSTANT( LIGHT_SHADER_LAMBERT );
+ BIND_CONSTANT( LIGHT_SHADER_WRAP );
+ BIND_CONSTANT( LIGHT_SHADER_VELVET );
+ BIND_CONSTANT( LIGHT_SHADER_TOON );
+
}
@@ -531,6 +535,8 @@ void ShaderMaterial::_shader_changed() {
void ShaderMaterial::set_shader(const Ref<Shader>& p_shader) {
+ ERR_FAIL_COND(p_shader.is_valid() && p_shader->get_mode()!=Shader::MODE_MATERIAL);
+
if (shader.is_valid())
shader->disconnect(SceneStringNames::get_singleton()->changed,this,SceneStringNames::get_singleton()->_shader_changed);
shader=p_shader;
@@ -566,8 +572,8 @@ void ShaderMaterial::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_shader","shader:Shader"), &ShaderMaterial::set_shader );
ObjectTypeDB::bind_method(_MD("get_shader:Shader"), &ShaderMaterial::get_shader );
- ObjectTypeDB::bind_method(_MD("set_shader_param","param","value:var"), &ShaderMaterial::set_shader_param);
- ObjectTypeDB::bind_method(_MD("get_shader_param:var","param"), &ShaderMaterial::get_shader_param);
+ ObjectTypeDB::bind_method(_MD("set_shader_param","param","value:Variant"), &ShaderMaterial::set_shader_param);
+ ObjectTypeDB::bind_method(_MD("get_shader_param:Variant","param"), &ShaderMaterial::get_shader_param);
ObjectTypeDB::bind_method(_MD("_shader_changed"), &ShaderMaterial::_shader_changed );
}
diff --git a/scene/resources/material.h b/scene/resources/material.h
index 7b7bc50567..96b33ce129 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index 039a4788d5..9537fa269f 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -99,7 +99,7 @@ bool Mesh::_set(const StringName& p_name, const Variant& p_value) {
if (sl==-1)
return false;
int idx=sname.substr(8,sl-8).to_int()-1;
- String what = sname.get_slice("/",1);
+ String what = sname.get_slicec('/',1);
if (what=="material")
surface_set_material(idx,p_value);
else if (what=="name")
@@ -117,8 +117,8 @@ bool Mesh::_set(const StringName& p_name, const Variant& p_value) {
return false;
- int idx=sname.get_slice("/",1).to_int();
- String what=sname.get_slice("/",2);
+ int idx=sname.get_slicec('/',1).to_int();
+ String what=sname.get_slicec('/',2);
if (idx==surfaces.size()) {
@@ -180,7 +180,7 @@ bool Mesh::_get(const StringName& p_name,Variant &r_ret) const {
if (sl==-1)
return false;
int idx=sname.substr(8,sl-8).to_int()-1;
- String what = sname.get_slice("/",1);
+ String what = sname.get_slicec('/',1);
if (what=="material")
r_ret=surface_get_material(idx);
else if (what=="name")
@@ -195,7 +195,7 @@ bool Mesh::_get(const StringName& p_name,Variant &r_ret) const {
return false;
- int idx=sname.get_slice("/",1).to_int();
+ int idx=sname.get_slicec('/',1).to_int();
ERR_FAIL_INDEX_V(idx,surfaces.size(),false);
Dictionary d;
@@ -971,7 +971,7 @@ void Mesh::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_morph_target_mode","mode"),&Mesh::set_morph_target_mode);
ObjectTypeDB::bind_method(_MD("get_morph_target_mode"),&Mesh::get_morph_target_mode);
- ObjectTypeDB::bind_method(_MD("add_surface","primitive","arrays","morph_arrays"),&Mesh::add_surface,DEFVAL(Array()));
+ ObjectTypeDB::bind_method(_MD("add_surface","primitive","arrays","morph_arrays","alphasort"),&Mesh::add_surface,DEFVAL(Array()),DEFVAL(false));
ObjectTypeDB::bind_method(_MD("get_surface_count"),&Mesh::get_surface_count);
ObjectTypeDB::bind_method(_MD("surface_remove","surf_idx"),&Mesh::surface_remove);
ObjectTypeDB::bind_method(_MD("surface_get_array_len","surf_idx"),&Mesh::surface_get_array_len);
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index 50463ce80e..e0d9bdf7a8 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/mesh_data_tool.cpp b/scene/resources/mesh_data_tool.cpp
index 42aaed39e1..fb0fc2a247 100644
--- a/scene/resources/mesh_data_tool.cpp
+++ b/scene/resources/mesh_data_tool.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/mesh_data_tool.h b/scene/resources/mesh_data_tool.h
index e7e7924e98..4a26fc2628 100644
--- a/scene/resources/mesh_data_tool.h
+++ b/scene/resources/mesh_data_tool.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp
index ffa29572ff..8643e96303 100644
--- a/scene/resources/mesh_library.cpp
+++ b/scene/resources/mesh_library.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,8 +35,8 @@ bool MeshLibrary::_set(const StringName& p_name, const Variant& p_value) {
String name=p_name;
if (name.begins_with("item/")) {
- int idx = name.get_slice("/",1).to_int();
- String what = name.get_slice("/",2);
+ int idx = name.get_slicec('/',1).to_int();
+ String what = name.get_slicec('/',2);
if (!item_map.has(idx))
create_item(idx);
@@ -60,9 +60,9 @@ bool MeshLibrary::_set(const StringName& p_name, const Variant& p_value) {
bool MeshLibrary::_get(const StringName& p_name,Variant &r_ret) const {
String name=p_name;
- int idx = name.get_slice("/",1).to_int();
+ int idx = name.get_slicec('/',1).to_int();
ERR_FAIL_COND_V(!item_map.has(idx),false);
- String what = name.get_slice("/",2);
+ String what = name.get_slicec('/',2);
if(what=="name")
r_ret= get_item_name(idx);
diff --git a/scene/resources/mesh_library.h b/scene/resources/mesh_library.h
index a6a7b71669..9a468d5555 100644
--- a/scene/resources/mesh_library.h
+++ b/scene/resources/mesh_library.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/multimesh.cpp b/scene/resources/multimesh.cpp
index 0755d101b2..c5ade63124 100644
--- a/scene/resources/multimesh.cpp
+++ b/scene/resources/multimesh.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -224,13 +224,13 @@ void MultiMesh::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_mesh","mesh:Mesh"),&MultiMesh::set_mesh);
ObjectTypeDB::bind_method(_MD("get_mesh:Mesh"),&MultiMesh::get_mesh);
- ObjectTypeDB::bind_method(_MD("set_instance_count"),&MultiMesh::set_instance_count);
+ ObjectTypeDB::bind_method(_MD("set_instance_count","count"),&MultiMesh::set_instance_count);
ObjectTypeDB::bind_method(_MD("get_instance_count"),&MultiMesh::get_instance_count);
- ObjectTypeDB::bind_method(_MD("set_instance_transform"),&MultiMesh::set_instance_transform);
- ObjectTypeDB::bind_method(_MD("get_instance_transform"),&MultiMesh::get_instance_transform);
- ObjectTypeDB::bind_method(_MD("set_instance_color"),&MultiMesh::set_instance_color);
- ObjectTypeDB::bind_method(_MD("get_instance_color"),&MultiMesh::get_instance_color);
- ObjectTypeDB::bind_method(_MD("set_aabb"),&MultiMesh::set_aabb);
+ ObjectTypeDB::bind_method(_MD("set_instance_transform","instance","transform"),&MultiMesh::set_instance_transform);
+ ObjectTypeDB::bind_method(_MD("get_instance_transform","instance"),&MultiMesh::get_instance_transform);
+ ObjectTypeDB::bind_method(_MD("set_instance_color","instance","color"),&MultiMesh::set_instance_color);
+ ObjectTypeDB::bind_method(_MD("get_instance_color","instance"),&MultiMesh::get_instance_color);
+ ObjectTypeDB::bind_method(_MD("set_aabb","visibility_aabb"),&MultiMesh::set_aabb);
ObjectTypeDB::bind_method(_MD("get_aabb"),&MultiMesh::get_aabb);
ObjectTypeDB::bind_method(_MD("generate_aabb"),&MultiMesh::generate_aabb);
diff --git a/scene/resources/multimesh.h b/scene/resources/multimesh.h
index c2736e3070..0cf9e92def 100644
--- a/scene/resources/multimesh.h
+++ b/scene/resources/multimesh.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index a1cb1205e5..03127620f7 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,13 +32,30 @@
#include "scene/3d/spatial.h"
#include "scene/gui/control.h"
#include "scene/2d/node_2d.h"
+#include "scene/main/instance_placeholder.h"
-bool PackedScene::can_instance() const {
+#define PACK_VERSION 2
+
+bool SceneState::can_instance() const {
return nodes.size()>0;
}
-Node *PackedScene::instance(bool p_gen_edit_state) const {
+
+Node *SceneState::instance(bool p_gen_edit_state) const {
+
+ // nodes where instancing failed (because something is missing)
+ List<Node*> stray_instances;
+
+#define NODE_FROM_ID(p_name,p_id)\
+ Node *p_name;\
+ if (p_id&FLAG_ID_IS_PATH) {\
+ NodePath np=node_paths[p_id&FLAG_MASK];\
+ p_name=ret_nodes[0]->_get_node(np);\
+ } else {\
+ ERR_FAIL_INDEX_V(p_id&FLAG_MASK,nc,NULL);\
+ p_name=ret_nodes[p_id&FLAG_MASK];\
+ }
int nc = nodes.size();
ERR_FAIL_COND_V(nc==0,NULL);
@@ -53,35 +70,86 @@ Node *PackedScene::instance(bool p_gen_edit_state) const {
if (prop_count)
props=&variants[0];
- Vector<Variant> properties;
+ //Vector<Variant> properties;
const NodeData *nd = &nodes[0];
Node **ret_nodes=(Node**)alloca( sizeof(Node*)*nc );
+ bool gen_node_path_cache=p_gen_edit_state && node_path_cache.empty();
for(int i=0;i<nc;i++) {
const NodeData &n=nd[i];
- if (!ObjectTypeDB::is_type_enabled(snames[n.type])) {
- ret_nodes[i]=NULL;
- continue;
+ Node *parent=NULL;
+
+ if (i>0) {
+
+ NODE_FROM_ID(nparent,n.parent);
+#ifdef DEBUG_ENABLED
+ if (!nparent && n.parent&FLAG_ID_IS_PATH) {
+
+ WARN_PRINT(String("Parent path '"+String(node_paths[n.parent&FLAG_MASK])+"' for node '"+String(snames[n.name])+"' has vanished when instancing: '"+get_path()+"'.").ascii().get_data());
+
+ }
+#endif
+ parent=nparent;
}
Node *node=NULL;
- if (n.instance>=0) {
- //instance existing
- Ref<PackedScene> sdata = props[ n.instance ];
+ if (i==0 && base_scene_idx>=0) {
+ //scene inheritance on root node
+ //print_line("scene inherit");
+ Ref<PackedScene> sdata = props[ base_scene_idx ];
ERR_FAIL_COND_V( !sdata.is_valid(), NULL);
- node = sdata->instance();
+ node = sdata->instance(p_gen_edit_state);
ERR_FAIL_COND_V(!node,NULL);
- if (p_gen_edit_state)
- node->generate_instance_state();
+ if (p_gen_edit_state) {
+ node->set_scene_inherited_state(sdata->get_state());
+ }
- } else {
- //create anew
+ } else if (n.instance>=0) {
+ //instance a scene into this node
+ //print_line("instance");
+ if (n.instance&FLAG_INSTANCE_IS_PLACEHOLDER) {
+
+ String path = props[n.instance&FLAG_MASK];
+ if (disable_placeholders) {
+
+ Ref<PackedScene> sdata = ResourceLoader::load(path,"PackedScene");
+ ERR_FAIL_COND_V( !sdata.is_valid(), NULL);
+ node = sdata->instance(p_gen_edit_state);
+ ERR_FAIL_COND_V(!node,NULL);
+ } else {
+ InstancePlaceholder *ip = memnew( InstancePlaceholder );
+ ip->set_instance_path(path);
+ node=ip;
+ }
+ node->set_scene_instance_load_placeholder(true);
+ } else {
+ Ref<PackedScene> sdata = props[ n.instance&FLAG_MASK ];
+ ERR_FAIL_COND_V( !sdata.is_valid(), NULL);
+ node = sdata->instance(p_gen_edit_state);
+ ERR_FAIL_COND_V(!node,NULL);
+
+ }
+
+ } else if (n.type==TYPE_INSTANCED) {
+ //print_line("instanced");
+ //get the node from somewhere, it likely already exists from another instance
+ if (parent) {
+ node=parent->_get_child_by_name(snames[n.name]);
+#ifdef DEBUG_ENABLED
+ if (!node) {
+ WARN_PRINT(String("Node '"+String(ret_nodes[0]->get_path_to(parent))+"/"+String(snames[n.name])+"' was modified from inside a instance, but it has vanished.").ascii().get_data());
+ }
+#endif
+ }
+ } else if (ObjectTypeDB::is_type_enabled(snames[n.type])) {
+ //print_line("created");
+ //node belongs to this scene and must be created
Object * obj = ObjectTypeDB::instance(snames[ n.type ]);
if (!obj || !obj->cast_to<Node>()) {
if (obj) {
@@ -109,49 +177,68 @@ Node *PackedScene::instance(bool p_gen_edit_state) const {
}
- //properties
- int nprop_count=n.properties.size();
- if (nprop_count) {
+ if (node) {
+ // may not have found the node (part of instanced scene and removed)
+ // if found all is good, otherwise ignore
- const NodeData::Property* nprops=&n.properties[0];
+ //properties
+ int nprop_count=n.properties.size();
+ if (nprop_count) {
- for(int j=0;j<nprop_count;j++) {
+ const NodeData::Property* nprops=&n.properties[0];
- bool valid;
- ERR_FAIL_INDEX_V( nprops[j].name, sname_count, NULL );
- ERR_FAIL_INDEX_V( nprops[j].value, prop_count, NULL );
+ for(int j=0;j<nprop_count;j++) {
- node->set(snames[ nprops[j].name ],props[ nprops[j].value ],&valid);
+ bool valid;
+ ERR_FAIL_INDEX_V( nprops[j].name, sname_count, NULL );
+ ERR_FAIL_INDEX_V( nprops[j].value, prop_count, NULL );
+
+ node->set(snames[ nprops[j].name ],props[ nprops[j].value ],&valid);
+ }
}
- }
- //name
+ //name
- //groups
- for(int j=0;j<n.groups.size();j++) {
+ //groups
+ for(int j=0;j<n.groups.size();j++) {
- ERR_FAIL_INDEX_V( n.groups[j], sname_count, NULL );
- node->add_to_group( snames[ n.groups[j] ], true );
- }
+ ERR_FAIL_INDEX_V( n.groups[j], sname_count, NULL );
+ node->add_to_group( snames[ n.groups[j] ], true );
+ }
+
+ if (n.instance>=0 || n.type!=TYPE_INSTANCED) {
+ //if node was not part of instance, must set it's name, parenthood and ownership
+ if (i>0) {
+ if (parent) {
+ parent->_add_child_nocheck(node,snames[n.name]);
+ } else {
+ //it may be possible that an instanced scene has changed
+ //and the node has nowhere to go anymore
+ stray_instances.push_back(node); //can't be added, go to stray list
+ }
+ } else {
+ node->_set_name_nocheck( snames[ n.name ] );
+ }
+ }
+
+ if (n.owner>=0) {
+
+ NODE_FROM_ID(owner,n.owner);
+ if (owner)
+ node->_set_owner_nocheck(owner);
+ }
- ret_nodes[i]=node;
- if (i>0) {
- ERR_FAIL_INDEX_V(n.parent,i,NULL);
- ERR_FAIL_COND_V(!ret_nodes[n.parent],NULL);
- ret_nodes[n.parent]->_add_child_nocheck(node,snames[n.name]);
- } else {
- node->_set_name_nocheck( snames[ n.name ] );
}
- if (n.owner>=0) {
+ ret_nodes[i]=node;
- ERR_FAIL_INDEX_V(n.owner,i,NULL);
- node->_set_owner_nocheck(ret_nodes[n.owner]);
+ if (node && gen_node_path_cache && ret_nodes[0]) {
+ NodePath n = ret_nodes[0]->get_path_to(node);
+ node_path_cache[n]=i;
}
-
}
@@ -163,8 +250,14 @@ Node *PackedScene::instance(bool p_gen_edit_state) const {
for(int i=0;i<cc;i++) {
const ConnectionData &c=cdata[i];
- ERR_FAIL_INDEX_V( c.from, nc, NULL );
- ERR_FAIL_INDEX_V( c.to, nc, NULL );
+ //ERR_FAIL_INDEX_V( c.from, nc, NULL );
+ //ERR_FAIL_INDEX_V( c.to, nc, NULL );
+
+ NODE_FROM_ID(cfrom,c.from);
+ NODE_FROM_ID(cto,c.to);
+
+ if (!cfrom || !cto)
+ continue;
Vector<Variant> binds;
if (c.binds.size()) {
@@ -173,17 +266,25 @@ Node *PackedScene::instance(bool p_gen_edit_state) const {
binds[j]=props[ c.binds[j] ];
}
- if (!ret_nodes[c.from] || !ret_nodes[c.to])
- continue;
- ret_nodes[c.from]->connect( snames[ c.signal], ret_nodes[ c.to ], snames[ c.method], binds,CONNECT_PERSIST|c.flags );
+
+ cfrom->connect( snames[ c.signal], cto, snames[ c.method], binds,CONNECT_PERSIST|c.flags );
}
- Node *s = ret_nodes[0];
+ //Node *s = ret_nodes[0];
- if (get_path()!="" && get_path().find("::")==-1)
- s->set_filename(get_path());
+ //remove nodes that could not be added, likely as a result that
+ while(stray_instances.size()) {
+ memdelete(stray_instances.front()->get());
+ stray_instances.pop_front();;
+ }
+
+ for(int i=0;i<editable_instances.size();i++) {
+ Node *ei = ret_nodes[0]->_get_node(editable_instances[i]);
+ if (ei) {
+ ret_nodes[0]->set_editable_instance(ei,true);
+ }
+ }
- s->notification(Node::NOTIFICATION_INSTANCED);
return ret_nodes[0];
}
@@ -209,44 +310,157 @@ static int _vm_get_variant(const Variant& p_variant, HashMap<Variant,int,Variant
return idx;
}
-Error PackedScene::_parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map) {
+Error SceneState::_parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map,Map<Node*,int> &nodepath_map) {
- if (p_node!=p_owner && (p_node->get_owner()!=p_owner))
- return OK; //nothing to do with this node, may either belong to another scene or be onowned
+
+ // this function handles all the work related to properly packing scenes, be it
+ // instanced or inherited.
+ // given the complexity of this process, an attempt will be made to properly
+ // document it. if you fail to understand something, please ask!
+
+ //discard nodes that do not belong to be processed
+ if (p_node!=p_owner && p_node->get_owner()!=p_owner && !p_owner->is_editable_instance(p_node->get_owner()))
+ return OK;
+
+ // save the child instanced scenes that are chosen as editable, so they can be restored
+ // upon load back
+ if (p_node!=p_owner && p_node->get_filename()!=String() && p_owner->is_editable_instance(p_node))
+ editable_instances.push_back(p_owner->get_path_to(p_node));
NodeData nd;
nd.name=_nm_get_string(p_node->get_name(),name_map);
- nd.type=_nm_get_string(p_node->get_type(),name_map);
- nd.parent=p_parent_idx;
+ nd.instance=-1; //not instanced by default
+
+ // if this node is part of an instanced scene or sub-instanced scene
+ // we need to get the corresponding instance states.
+ // with the instance states, we can query for identical properties/groups
+ // and only save what has changed
+
+ List<PackState> pack_state_stack;
+
+ bool instanced_by_owner=true;
+
+ {
+ Node *n=p_node;
+ while(n) {
- Dictionary instance_state;
- Set<StringName> instance_groups;
+ if (n==p_owner) {
+ Ref<SceneState> state = n->get_scene_inherited_state();
+ if (state.is_valid()) {
+ int node = state->find_node_by_path(n->get_path_to(p_node));
+ if (node>=0) {
+ //this one has state for this node, save
+ PackState ps;
+ ps.node=node;
+ ps.state=state;
+ pack_state_stack.push_front(ps);
+ instanced_by_owner=false;
+ }
+ }
+
+ if (p_node->get_filename()!=String() && p_node->get_owner()==p_owner && instanced_by_owner) {
+
+ if (p_node->get_scene_instance_load_placeholder()) {
+ //it's a placeholder, use the placeholder path
+ nd.instance=_vm_get_variant(p_node->get_filename(),variant_map);
+ nd.instance|=FLAG_INSTANCE_IS_PLACEHOLDER;
+ } else {
+ //must instance ourselves
+ Ref<PackedScene> instance = ResourceLoader::load(p_node->get_filename());
+ if (!instance.is_valid()) {
+ return ERR_CANT_OPEN;
+ }
+
+ nd.instance=_vm_get_variant(instance,variant_map);
+ }
+ }
+ n=NULL;
+ } else {
+ if (n->get_filename()!=String()) {
+ //is an instance
+ Ref<SceneState> state = n->get_scene_instance_state();
+ if (state.is_valid()) {
+ int node = state->find_node_by_path(n->get_path_to(p_node));
+ if (node>=0) {
+ //this one has state for this node, save
+ PackState ps;
+ ps.node=node;
+ ps.state=state;
+ pack_state_stack.push_back(ps);
+ }
+ }
+
+ }
+ n=n->get_owner();
+ }
+ }
+ }
+
+#if 0
- if (p_node!=p_owner && p_node->get_filename()!="") {
- //instanced
+ Ref<SceneState> base_scene = p_node->get_scene_inherited_state(); //for inheritance
+ Ref<SceneState> instance_state;
+ int instance_state_node=-1;
+
+ if (base_scene.is_valid() && (p_node==p_owner || p_node->get_owner()==p_owner)) {
+ //scene inheritance in use, see if this node is actually inherited
+ NodePath path = p_owner->get_path_to(p_node);
+ instance_state_node = base_scene->find_node_by_path(path);
+ if (instance_state_node>=0) {
+ instance_state=base_scene;
+ }
+ }
+
+ // check that this is a directly instanced scene from the scene being packed, if so
+ // this information must be saved. Of course, if using scene instancing and this node
+ // does belong to base scene, ignore.
+
+ if (instance_state.is_null() && p_node!=p_owner && p_node->get_owner()==p_owner && p_node->get_filename()!="") {
+
+ //instanced, only direct sub-scnes are supported of course
Ref<PackedScene> instance = ResourceLoader::load(p_node->get_filename());
if (!instance.is_valid()) {
return ERR_CANT_OPEN;
}
nd.instance=_vm_get_variant(instance,variant_map);
- instance_state = p_node->get_instance_state();
- Vector<StringName> ig = p_node->get_instance_groups();
- for(int i=0;i<ig.size();i++)
- instance_groups.insert(ig[i]);
+
} else {
nd.instance=-1;
}
+ // finally, if this does not belong to scene inheritance, check
+ // if it belongs to scene instancing
- //instance state makes sure that only changes to instance are saved
+ if (instance_state.is_null() && p_node!=p_owner) {
+ //if not affected by scene inheritance, this may be
+ if (p_node->get_owner()==p_owner && p_node->get_filename()!=String()) {
+ instance_state=p_node->get_scene_instance_state();
+ if (instance_state.is_valid()) {
+ instance_state_node=instance_state->find_node_by_path(p_node->get_path_to(p_node));
+ }
+
+ } else if (p_node->get_owner()!=p_owner && p_owner->is_editable_instance(p_node->get_owner())) {
+ instance_state=p_node->get_owner()->get_scene_instance_state();
+ if (instance_state.is_valid()) {
+ instance_state_node=instance_state->find_node_by_path(p_node->get_owner()->get_path_to(p_node));
+ }
+ }
+ }
+#endif
+ int subscene_prop_search_from=0;
+
+ // all setup, we then proceed to check all properties for the node
+ // and save the ones that are worth saving
List<PropertyInfo> plist;
p_node->get_property_list(&plist);
+
+
for (List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) {
@@ -257,31 +471,76 @@ Error PackedScene::_parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<
String name = E->get().name;
Variant value = p_node->get( E->get().name );
- if (E->get().usage & PROPERTY_USAGE_STORE_IF_NONZERO && value.is_zero()) {
- continue;
- }
+ bool isdefault = ((E->get().usage & PROPERTY_USAGE_STORE_IF_NONZERO) && value.is_zero()) || ((E->get().usage & PROPERTY_USAGE_STORE_IF_NONONE) && value.is_one());
+
+// if (nd.instance<0 && ((E->get().usage & PROPERTY_USAGE_STORE_IF_NONZERO) && value.is_zero()) || ((E->get().usage & PROPERTY_USAGE_STORE_IF_NONONE) && value.is_one())) {
+// continue;
+// }
+
+
+
+ //print_line("PASSED!");
+ //print_line("at: "+String(p_node->get_name())+"::"+name+": - nz: "+itos(E->get().usage&PROPERTY_USAGE_STORE_IF_NONZERO)+" no: "+itos(E->get().usage&PROPERTY_USAGE_STORE_IF_NONONE));
+ //print_line("value: "+String(value)+" is zero: "+itos(value.is_zero())+" is one" +itos(value.is_one()));
- if (nd.instance>=0) {
- //only save changed properties in instance
- /*
- // this was commented because it would not save properties created from within script
- // done with _get_property_list, that are not in the original node.
- // if some property is not saved, check again
+ if (pack_state_stack.size()) {
+ // we are on part of an instanced subscene
+ // or part of instanced scene.
+ // only save what has been changed
+ // only save changed properties in instance
- if (!instance_state.has(name)) {
- print_line("skip not in instance");
+ if (E->get().usage & PROPERTY_USAGE_NO_INSTANCE_STATE || E->get().name=="__meta__") {
+ //property has requested that no instance state is saved, sorry
+ //also, meta won't be overriden or saved
continue;
- }*/
+ }
+
+ bool exists=false;
+ Variant original;
+
+ for (List<PackState>::Element *F=pack_state_stack.back();F;F=F->prev()) {
+ //check all levels of pack to see if the property exists somewhere
+ const PackState &ps=F->get();
+
+ original = ps.state->get_property_value(ps.node,E->get().name,exists);
+ if (exists) {
+ break;
+ }
+ }
+
+ if (exists && p_node->get_script_instance()) {
+ //if this is an overriden value by another script, save it anyway
+ //as the script change will erase it
+ //https://github.com/godotengine/godot/issues/2958
- if (E->get().usage & PROPERTY_USAGE_NO_INSTANCE_STATE) {
+ bool valid=false;
+ p_node->get_script_instance()->get_property_type(name,&valid);
+ if (valid) {
+ exists=false;
+ isdefault=false;
+ }
+ }
+
+
+ if (exists && bool(Variant::evaluate(Variant::OP_EQUAL,value,original))) {
+ //exists and did not change
continue;
}
- if (instance_state[name]==value) {
+ if (!exists && isdefault) {
+ //does not exist in original node, but it's the default value
+ //so safe to skip too.
continue;
}
+
+ } else {
+
+ if (isdefault) {
+ //it's the default value, no point in saving it
+ continue;
+ }
}
NodeData::Property prop;
@@ -292,6 +551,9 @@ Error PackedScene::_parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<
}
+ // save the groups this node is into
+ // discard groups that come from the original scene
+
List<Node::GroupInfo> groups;
p_node->get_groups(&groups);
for(List<Node::GroupInfo>::Element *E=groups.front();E;E=E->next()) {
@@ -299,27 +561,123 @@ Error PackedScene::_parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<
if (!gi.persistent)
continue;
- if (nd.instance>=0 && instance_groups.has(gi.name))
- continue; //group was instanced, don't add here
+// if (instance_state_node>=0 && instance_state->is_node_in_group(instance_state_node,gi.name))
+// continue; //group was instanced, don't add here
+
+ bool skip=false;
+ for (List<PackState>::Element *F=pack_state_stack.front();F;F=F->next()) {
+ //check all levels of pack to see if the group was added somewhere
+ const PackState &ps=F->get();
+ if (ps.state->is_node_in_group(ps.node,gi.name)) {
+ skip=true;
+ break;
+ }
+ }
+
+ if (skip)
+ continue;
nd.groups.push_back(_nm_get_string(gi.name,name_map));
}
- if (node_map.has(p_node->get_owner()))
- nd.owner=node_map[p_node->get_owner()];
- else
+
+ // save the right owner
+ // for the saved scene root this is -1
+ // for nodes of the saved scene this is 0
+ // for nodes of instanced scenes this is >0
+
+ if (p_node==p_owner) {
+ //saved scene root
+ nd.owner=-1;
+ } else if (p_node->get_owner()==p_owner) {
+ //part of saved scene
+ nd.owner=0;
+ } else {
+
nd.owner=-1;
+#if 0
+ // this is pointless, if this was instanced by something else,
+ // the owner will already be set.
+
+ if (node_map.has(p_node->get_owner())) {
+ //maybe an existing saved node
+ nd.owner=node_map[p_node->get_owner()];
+ } else {
+ //not saved, use nodepath map
+ int sidx;
+ if (nodepath_map.has(p_node->get_owner())) {
+ sidx=nodepath_map[p_node->get_owner()];
+ } else {
+ sidx=nodepath_map.size();
+ nodepath_map[p_node->get_owner()]=sidx;
+ }
+
+ nd.owner=FLAG_ID_IS_PATH|sidx;
+
+ }
+#endif
+
+
+ }
+
+ // Save the right type. If this node was created by an instance
+ // then flag that the node should not be created but reused
+ if (pack_state_stack.empty()) {
+ //this node is not part of an instancing process, so save the type
+ nd.type=_nm_get_string(p_node->get_type(),name_map);
+ } else {
+ // this node is part of an instanced process, so do not save the type.
+ // instead, save that it was instanced
+ nd.type=TYPE_INSTANCED;
+ }
+
+
+ // determine whether to save this node or not
+ // if this node is part of an instanced sub-scene, we can skip storing it if basically
+ // no properties changed and no groups were added to it.
+ // below condition is true for all nodes of the scene being saved, and ones in subscenes
+ // that hold changes
+
+ bool save_node = nd.properties.size() || nd.groups.size(); // some local properties or groups exist
+ save_node = save_node || p_node==p_owner; // owner is always saved
+ save_node = save_node || (p_node->get_owner()==p_owner && instanced_by_owner); //part of scene and not instanced
+
int idx = nodes.size();
- node_map[p_node]=idx;
- nodes.push_back(nd);
+ int parent_node=NO_PARENT_SAVED;
+
+ if (save_node) {
+
+ //don't save the node if nothing and subscene
+
+ node_map[p_node]=idx;
+
+ //ok validate parent node
+ if (p_parent_idx==NO_PARENT_SAVED) {
+
+ int sidx;
+ if (nodepath_map.has(p_node->get_parent())) {
+ sidx=nodepath_map[p_node->get_parent()];
+ } else {
+ sidx=nodepath_map.size();
+ nodepath_map[p_node->get_parent()]=sidx;
+ }
+
+ nd.parent=FLAG_ID_IS_PATH|sidx;
+ } else {
+ nd.parent=p_parent_idx;
+ }
+ parent_node=idx;
+ nodes.push_back(nd);
+
+ }
for(int i=0;i<p_node->get_child_count();i++) {
Node *c=p_node->get_child(i);
- Error err = _parse_node(p_owner,c,idx,name_map,variant_map,node_map);
+ Error err = _parse_node(p_owner,c,parent_node,name_map,variant_map,node_map,nodepath_map);
if (err)
return err;
}
@@ -328,53 +686,135 @@ Error PackedScene::_parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<
}
-Error PackedScene::_parse_connections(Node *p_owner,Node *p_node, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map) {
+Error SceneState::_parse_connections(Node *p_owner,Node *p_node, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map,Map<Node*,int> &nodepath_map) {
- if (p_node!=p_owner && (p_node->get_owner()!=p_owner))
- return OK; //nothing to do with this node, may either belong to another scene or be onowned
+ if (p_node!=p_owner && p_node->get_owner() && p_node->get_owner()!=p_owner && !p_owner->is_editable_instance(p_node->get_owner()))
+ return OK;
- List<MethodInfo> signals;
- p_node->get_signal_list(&signals);
- ERR_FAIL_COND_V( !node_map.has(p_node), ERR_BUG);
- NodeData &nd = nodes[node_map[p_node]];
- Set<Connection> instance_connections;
+ List<MethodInfo> _signals;
+ p_node->get_signal_list(&_signals);
- if (nd.instance>=0) {
-
- Vector<Connection> iconns = p_node->get_instance_connections();
- for(int i=0;i<iconns.size();i++) {
-
- instance_connections.insert(iconns[i]);
- }
- }
+ //ERR_FAIL_COND_V( !node_map.has(p_node), ERR_BUG);
+ //NodeData &nd = nodes[node_map[p_node]];
- for(List<MethodInfo>::Element *E=signals.front();E;E=E->next()) {
+ for(List<MethodInfo>::Element *E=_signals.front();E;E=E->next()) {
List<Node::Connection> conns;
p_node->get_signal_connection_list(E->get().name,&conns);
for(List<Node::Connection>::Element *F=conns.front();F;F=F->next()) {
const Node::Connection &c = F->get();
- if (!(c.flags&CONNECT_PERSIST))
+
+ if (!(c.flags&CONNECT_PERSIST)) //only persistent connections get saved
continue;
- if (nd.instance>=0 && instance_connections.has(c))
- continue; //came from instance, don't save!
+ // only connections that originate or end into main saved scene are saved
+ // everything else is discarded
Node *n=c.target->cast_to<Node>();
- if (!n)
+ if (!n) {
continue;
+ }
+
+ //source node is outside saved scene?
+ bool src_is_out = p_node!=p_owner && (p_node->get_filename()!=String() || p_node->get_owner()!=p_owner);
+ //target node is outside saved scene?
+ bool dst_is_out = n!=p_owner && (n->get_filename()!=String() || n->get_owner()!=p_owner);
- if (!node_map.has(n)) {
- WARN_PRINT("Connection to node outside scene??")
+ //if both are out, ignore connection
+ if (src_is_out && dst_is_out) {
continue;
}
+
+ {
+ Node *nl=p_node;
+
+ bool exists=false;
+
+ while(nl) {
+
+ if (nl==p_owner) {
+
+ Ref<SceneState> state = nl->get_scene_inherited_state();
+ if (state.is_valid()) {
+ int from_node = state->find_node_by_path(nl->get_path_to(p_node));
+ int to_node = state->find_node_by_path(nl->get_path_to(n));
+
+ if (from_node>=0 && to_node>=0) {
+ //this one has state for this node, save
+ if (state->is_connection(from_node,c.signal,to_node,c.method)) {
+ exists=true;
+ break;
+ }
+ }
+ }
+
+ nl=NULL;
+ } else {
+ if (nl->get_filename()!=String()) {
+ //is an instance
+ Ref<SceneState> state = nl->get_scene_instance_state();
+ if (state.is_valid()) {
+ int from_node = state->find_node_by_path(nl->get_path_to(p_node));
+ int to_node = state->find_node_by_path(nl->get_path_to(n));
+
+ if (from_node>=0 && to_node>=0) {
+ //this one has state for this node, save
+ if (state->is_connection(from_node,c.signal,to_node,c.method)) {
+ exists=true;
+ break;
+ }
+ }
+ }
+
+ }
+ nl=nl->get_owner();
+ }
+ }
+
+ if (exists) {
+ continue;
+ }
+
+ }
+
+
+ int src_id;
+
+ if (node_map.has(p_node)) {
+ src_id=node_map[p_node];
+ } else {
+ if (nodepath_map.has(p_node)) {
+ src_id=FLAG_ID_IS_PATH|nodepath_map[p_node];
+ } else {
+ int sidx=nodepath_map.size();
+ nodepath_map[p_node]=sidx;
+ src_id=FLAG_ID_IS_PATH|sidx;
+ }
+ }
+
+
+
+ int target_id;
+
+ if (node_map.has(n)) {
+ target_id=node_map[n];
+ } else {
+ if (nodepath_map.has(n)) {
+ target_id=FLAG_ID_IS_PATH|nodepath_map[n];
+ } else {
+ int sidx=nodepath_map.size();
+ nodepath_map[n]=sidx;
+ target_id=FLAG_ID_IS_PATH|sidx;
+ }
+ }
+
ConnectionData cd;
- cd.from=node_map[p_node];
- cd.to=node_map[n];
+ cd.from=src_id;
+ cd.to=target_id;
cd.method=_nm_get_string(c.method,name_map);
cd.signal=_nm_get_string(c.signal,name_map);
cd.flags=c.flags;
@@ -389,7 +829,7 @@ Error PackedScene::_parse_connections(Node *p_owner,Node *p_node, Map<StringName
for(int i=0;i<p_node->get_child_count();i++) {
Node *c=p_node->get_child(i);
- Error err = _parse_connections(p_owner,c,name_map,variant_map,node_map);
+ Error err = _parse_connections(p_owner,c,name_map,variant_map,node_map,nodepath_map);
if (err)
return err;
}
@@ -398,7 +838,7 @@ Error PackedScene::_parse_connections(Node *p_owner,Node *p_node, Map<StringName
}
-Error PackedScene::pack(Node *p_scene) {
+Error SceneState::pack(Node *p_scene) {
ERR_FAIL_NULL_V( p_scene, ERR_INVALID_PARAMETER );
@@ -409,14 +849,27 @@ Error PackedScene::pack(Node *p_scene) {
Map<StringName,int> name_map;
HashMap<Variant,int,VariantHasher> variant_map;
Map<Node*,int> node_map;
+ Map<Node*,int> nodepath_map;
+
+ //if using scene inheritance, pack the scene it inherits from
+ if (scene->get_scene_inherited_state().is_valid()) {
+ String path = scene->get_scene_inherited_state()->get_path();
+ Ref<PackedScene> instance = ResourceLoader::load(path);
+ if (instance.is_valid()) {
+
+ base_scene_idx=_vm_get_variant(instance,variant_map);
+ }
+ }
+ //instanced, only direct sub-scnes are supported of course
- Error err = _parse_node(scene,scene,-1,name_map,variant_map,node_map);
+
+ Error err = _parse_node(scene,scene,-1,name_map,variant_map,node_map,nodepath_map);
if (err) {
clear();
ERR_FAIL_V(err);
}
- err = _parse_connections(scene,scene,name_map,variant_map,node_map);
+ err = _parse_connections(scene,scene,name_map,variant_map,node_map,nodepath_map);
if (err) {
clear();
ERR_FAIL_V(err);
@@ -437,19 +890,177 @@ Error PackedScene::pack(Node *p_scene) {
variants[idx]=*K;
}
+ node_paths.resize(nodepath_map.size());
+ for(Map<Node*,int>::Element *E=nodepath_map.front();E;E=E->next()) {
+
+ node_paths[E->get()]=scene->get_path_to(E->key());
+ }
+
+
return OK;
}
-void PackedScene::clear() {
+void SceneState::set_path(const String &p_path) {
+
+ path=p_path;
+}
+
+String SceneState::get_path() const{
+
+ return path;
+}
+
+void SceneState::clear() {
names.clear();
variants.clear();
nodes.clear();
connections.clear();
+ node_path_cache.clear();
+ node_paths.clear();
+ editable_instances.clear();
+ base_scene_idx=-1;
}
-void PackedScene::_set_bundled_scene(const Dictionary& d) {
+Ref<SceneState> SceneState::_get_base_scene_state() const {
+
+ if (base_scene_idx>=0) {
+
+ Ref<PackedScene> ps = variants[base_scene_idx];
+ if (ps.is_valid()) {
+ return ps->get_state();
+ }
+ }
+
+ return Ref<SceneState>();
+}
+
+int SceneState::find_node_by_path(const NodePath& p_node) const {
+
+ if (!node_path_cache.has(p_node)) {
+ if (_get_base_scene_state().is_valid()) {
+ int idx = _get_base_scene_state()->find_node_by_path(p_node);
+ if (idx>=0) {
+ if (!base_scene_node_remap.has(idx)) {
+ int ridx = nodes.size() + base_scene_node_remap.size();
+ base_scene_node_remap[ridx]=idx;
+ }
+
+ return base_scene_node_remap[idx];
+ }
+ }
+ return -1;
+ }
+
+ int nid = node_path_cache[p_node];
+
+ if (_get_base_scene_state().is_valid() && !base_scene_node_remap.has(nid)) {
+ //for nodes that _do_ exist in current scene, still try to look for
+ //the node in the instanced scene, as a property may be missing
+ //from the local one
+ int idx = _get_base_scene_state()->find_node_by_path(p_node);
+ base_scene_node_remap[nid]=idx;
+
+ }
+
+ return nid;
+}
+Variant SceneState::get_property_value(int p_node, const StringName& p_property, bool &found) const {
+
+ found=false;
+
+ ERR_FAIL_COND_V(p_node<0,Variant());
+
+ if (p_node<nodes.size()) {
+ //find in built-in nodes
+ int pc = nodes[p_node].properties.size();
+ const StringName* namep = names.ptr();
+
+ const NodeData::Property *p=nodes[p_node].properties.ptr();
+ for(int i=0;i<pc;i++) {
+ if (p_property==namep[p[i].name]) {
+ found=true;
+ return variants[p[i].value];
+ }
+ }
+ }
+
+ //property not found, try on instance
+
+ if (base_scene_node_remap.has(p_node)) {
+ return _get_base_scene_state()->get_property_value(base_scene_node_remap[p_node],p_property,found);
+ }
+
+ return Variant();
+}
+
+bool SceneState::is_node_in_group(int p_node,const StringName& p_group) const {
+
+ ERR_FAIL_COND_V(p_node<0,false);
+
+ if (p_node<nodes.size()) {
+ const StringName* namep = names.ptr();
+ for(int i=0;i<nodes[p_node].groups.size();i++) {
+ if (namep[nodes[p_node].groups[i]]==p_group)
+ return true;
+ }
+ }
+
+ if (base_scene_node_remap.has(p_node)) {
+ return _get_base_scene_state()->is_node_in_group(base_scene_node_remap[p_node],p_group);
+ }
+
+ return false;
+}
+
+bool SceneState::disable_placeholders=false;
+
+void SceneState::set_disable_placeholders(bool p_disable) {
+
+ disable_placeholders=p_disable;
+}
+
+bool SceneState::is_connection(int p_node,const StringName& p_signal,int p_to_node,const StringName& p_to_method) const {
+
+ ERR_FAIL_COND_V(p_node<0,false);
+ ERR_FAIL_COND_V(p_to_node<0,false);
+
+ if (p_node<nodes.size() && p_to_node<nodes.size()) {
+
+ int signal_idx=-1;
+ int method_idx=-1;
+ for(int i=0;i<names.size();i++) {
+ if (names[i]==p_signal) {
+ signal_idx=i;
+ } else if (names[i]==p_to_method) {
+ method_idx=i;
+ }
+ }
+
+ if (signal_idx>=0 && method_idx>=0) {
+ //signal and method strings are stored..
+
+ for(int i=0;i<connections.size();i++) {
+
+ if (connections[i].from==p_node && connections[i].to==p_to_node && connections[i].signal==signal_idx && connections[i].method==method_idx) {
+
+ return true;
+ }
+ }
+ }
+ }
+
+ if (base_scene_node_remap.has(p_node) && base_scene_node_remap.has(p_to_node)) {
+ return _get_base_scene_state()->is_connection(base_scene_node_remap[p_node],p_signal,base_scene_node_remap[p_to_node],p_to_method);
+ }
+
+ return false;
+
+}
+
+
+void SceneState::set_bundled_scene(const Dictionary& d) {
ERR_FAIL_COND( !d.has("names"));
@@ -460,6 +1071,15 @@ void PackedScene::_set_bundled_scene(const Dictionary& d) {
ERR_FAIL_COND( !d.has("conns"));
// ERR_FAIL_COND( !d.has("path"));
+ int version=1;
+ if (d.has("version"))
+ version=d["version"];
+
+ if (version>PACK_VERSION) {
+ ERR_EXPLAIN("Save format version too new!");
+ ERR_FAIL();
+ }
+
DVector<String> snames = d["names"];
if (snames.size()) {
@@ -537,11 +1157,34 @@ void PackedScene::_set_bundled_scene(const Dictionary& d) {
}
+ Array np;
+ if (d.has("node_paths")) {
+ np=d["node_paths"];
+ }
+ node_paths.resize(np.size());
+ for(int i=0;i<np.size();i++) {
+ node_paths[i]=np[i];
+ }
+
+ Array ei;
+ if (d.has("editable_instances")) {
+ ei=d["editable_instances"];
+ }
+
+ if (d.has("base_scene")) {
+ base_scene_idx=d["base_scene"];
+ }
+
+ editable_instances.resize(ei.size());
+ for(int i=0;i<editable_instances.size();i++) {
+ editable_instances[i]=ei[i];
+ }
+
// path=d["path"];
}
-Dictionary PackedScene::_get_bundled_scene() const {
+Dictionary SceneState::get_bundled_scene() const {
DVector<String> rnames;
rnames.resize(names.size());
@@ -602,7 +1245,25 @@ Dictionary PackedScene::_get_bundled_scene() const {
}
d["conns"]=rconns;
- d["version"]=1;
+
+ Array rnode_paths;
+ rnode_paths.resize(node_paths.size());
+ for(int i=0;i<node_paths.size();i++) {
+ rnode_paths[i]=node_paths[i];
+ }
+ d["node_paths"]=rnode_paths;
+
+ Array reditable_instances;
+ reditable_instances.resize(editable_instances.size());
+ for(int i=0;i<editable_instances.size();i++) {
+ reditable_instances[i]=editable_instances[i];
+ }
+ d["editable_instances"]=reditable_instances;
+ if (base_scene_idx>=0) {
+ d["base_scene"]=base_scene_idx;
+ }
+
+ d["version"]=PACK_VERSION;
// d["path"]=path;
@@ -611,10 +1272,366 @@ Dictionary PackedScene::_get_bundled_scene() const {
}
+int SceneState::get_node_count() const {
+
+ return nodes.size();
+}
+
+StringName SceneState::get_node_type(int p_idx) const {
+
+ ERR_FAIL_INDEX_V(p_idx,nodes.size(),StringName());
+ if (nodes[p_idx].type==TYPE_INSTANCED)
+ return StringName();
+ return names[nodes[p_idx].type];
+}
+
+StringName SceneState::get_node_name(int p_idx) const {
+
+ ERR_FAIL_INDEX_V(p_idx,nodes.size(),StringName());
+ return names[nodes[p_idx].name];
+}
+
+Ref<PackedScene> SceneState::get_node_instance(int p_idx) const {
+ ERR_FAIL_INDEX_V(p_idx,nodes.size(),Ref<PackedScene>());
+
+ if (nodes[p_idx].instance>=0) {
+ return variants[nodes[p_idx].instance];
+ } else if (nodes[p_idx].parent<0 || nodes[p_idx].parent==NO_PARENT_SAVED) {
+
+ if (base_scene_idx>=0) {
+ return variants[base_scene_idx];
+ }
+ }
+
+
+
+ return Ref<PackedScene>();
+
+
+}
+Vector<StringName> SceneState::get_node_groups(int p_idx) const{
+ ERR_FAIL_INDEX_V(p_idx,nodes.size(),Vector<StringName>());
+ Vector<StringName> groups;
+ for(int i=0;i<nodes[p_idx].groups.size();i++) {
+ groups.push_back(names[nodes[p_idx].groups[i]]);
+ }
+ return groups;
+}
+
+
+NodePath SceneState::get_node_path(int p_idx,bool p_for_parent) const {
+
+ ERR_FAIL_INDEX_V(p_idx,nodes.size(),NodePath());
+
+ if (nodes[p_idx].parent<0 || nodes[p_idx].parent==NO_PARENT_SAVED) {
+ if (p_for_parent) {
+ return NodePath();
+ } else {
+ return NodePath(".");
+ }
+ }
+
+ Vector<StringName> sub_path;
+ NodePath base_path;
+ int nidx=p_idx;
+ while(true) {
+ if (nodes[nidx].parent==NO_PARENT_SAVED || nodes[nidx].parent<0) {
+
+ sub_path.insert(0,".");
+ break;
+ }
+
+ if (!p_for_parent || p_idx!=nidx) {
+ sub_path.insert(0,names[nodes[nidx].name]);
+ }
+
+ if (nodes[nidx].parent&FLAG_ID_IS_PATH) {
+ base_path=node_paths[nodes[nidx].parent&FLAG_MASK];
+ break;
+ } else {
+ nidx=nodes[nidx].parent&FLAG_MASK;
+ }
+ }
+
+ for(int i=0;i<base_path.get_name_count();i++) {
+ StringName sn = base_path.get_name(i);
+ sub_path.insert(0,base_path.get_name(i));
+ }
+
+ if (sub_path.empty()) {
+ return NodePath(".");
+ }
+
+ return NodePath(sub_path,false);
+
+}
+
+int SceneState::get_node_property_count(int p_idx) const {
+
+ ERR_FAIL_INDEX_V(p_idx,nodes.size(),-1);
+ return nodes[p_idx].properties.size();
+
+}
+StringName SceneState::get_node_property_name(int p_idx,int p_prop) const{
+ ERR_FAIL_INDEX_V(p_idx,nodes.size(),StringName());
+ ERR_FAIL_INDEX_V(p_prop,nodes[p_idx].properties.size(),StringName());
+ return names[nodes[p_idx].properties[p_prop].name];
+
+}
+Variant SceneState::get_node_property_value(int p_idx,int p_prop) const{
+ ERR_FAIL_INDEX_V(p_idx,nodes.size(),Variant());
+ ERR_FAIL_INDEX_V(p_prop,nodes[p_idx].properties.size(),Variant());
+
+ return variants[nodes[p_idx].properties[p_prop].value];
+}
+
+
+NodePath SceneState::get_node_owner_path(int p_idx) const {
+
+ ERR_FAIL_INDEX_V(p_idx,nodes.size(),NodePath());
+ if (nodes[p_idx].owner<0 || nodes[p_idx].owner==NO_PARENT_SAVED)
+ return NodePath(); //root likely
+ if (nodes[p_idx].owner&FLAG_ID_IS_PATH) {
+ return node_paths[nodes[p_idx].owner&FLAG_MASK];
+ } else {
+ return get_node_path(nodes[p_idx].owner&FLAG_MASK);
+ }
+}
+
+int SceneState::get_connection_count() const {
+
+ return connections.size();
+}
+NodePath SceneState::get_connection_source(int p_idx) const{
+
+ ERR_FAIL_INDEX_V(p_idx,connections.size(),NodePath());
+ if (connections[p_idx].from&FLAG_ID_IS_PATH) {
+ return node_paths[connections[p_idx].from&FLAG_MASK];
+ } else {
+ return get_node_path(connections[p_idx].from&FLAG_MASK);
+ }
+
+}
+
+StringName SceneState::get_connection_signal(int p_idx) const{
+
+ ERR_FAIL_INDEX_V(p_idx,connections.size(),StringName());
+ return names[connections[p_idx].signal];
+
+}
+NodePath SceneState::get_connection_target(int p_idx) const{
+
+ ERR_FAIL_INDEX_V(p_idx,connections.size(),NodePath());
+ if (connections[p_idx].to&FLAG_ID_IS_PATH) {
+ return node_paths[connections[p_idx].to&FLAG_MASK];
+ } else {
+ return get_node_path(connections[p_idx].to&FLAG_MASK);
+ }
+
+}
+StringName SceneState::get_connection_method(int p_idx) const{
+
+ ERR_FAIL_INDEX_V(p_idx,connections.size(),StringName());
+ return names[connections[p_idx].method];
+
+}
+int SceneState::get_connection_flags(int p_idx) const{
+
+ ERR_FAIL_INDEX_V(p_idx,connections.size(),-1);
+ return connections[p_idx].flags;
+}
+
+Array SceneState::get_connection_binds(int p_idx) const {
+
+ ERR_FAIL_INDEX_V(p_idx,connections.size(),-1);
+ Array binds;
+ for(int i=0;i<connections[p_idx].binds.size();i++) {
+ binds.push_back(variants[connections[p_idx].binds[i]]);
+ }
+ return binds;
+}
+
+Vector<NodePath> SceneState::get_editable_instances() const {
+ return editable_instances;
+}
+//add
+
+int SceneState::add_name(const StringName& p_name) {
+
+ names.push_back(p_name);
+ return names.size()-1;
+}
+
+int SceneState::add_value(const Variant& p_value) {
+
+ variants.push_back(p_value);
+ return variants.size()-1;
+}
+
+int SceneState::add_node_path(const NodePath& p_path){
+
+ node_paths.push_back(p_path);
+ return (node_paths.size()-1)|FLAG_ID_IS_PATH;
+}
+int SceneState::add_node(int p_parent,int p_owner,int p_type,int p_name, int p_instance){
+
+ NodeData nd;
+ nd.parent=p_parent;
+ nd.owner=p_owner;
+ nd.type=p_type;
+ nd.name=p_name;
+ nd.instance=p_instance;
+
+ nodes.push_back(nd);
+
+ return nodes.size()-1;
+}
+void SceneState::add_node_property(int p_node,int p_name,int p_value){
+
+ ERR_FAIL_INDEX(p_node,nodes.size());
+ ERR_FAIL_INDEX(p_name,names.size());
+ ERR_FAIL_INDEX(p_value,variants.size());
+
+ NodeData::Property prop;
+ prop.name=p_name;
+ prop.value=p_value;
+ nodes[p_node].properties.push_back(prop);
+}
+void SceneState::add_node_group(int p_node,int p_group){
+
+ ERR_FAIL_INDEX(p_node,nodes.size());
+ ERR_FAIL_INDEX(p_group,names.size());
+ nodes[p_node].groups.push_back(p_group);
+
+}
+void SceneState::set_base_scene(int p_idx){
+
+ ERR_FAIL_INDEX(p_idx,variants.size());
+ base_scene_idx=p_idx;
+}
+void SceneState::add_connection(int p_from,int p_to, int p_signal, int p_method, int p_flags,const Vector<int>& p_binds){
+
+ ERR_FAIL_INDEX(p_signal,names.size());
+ ERR_FAIL_INDEX(p_method,names.size());
+
+ for(int i=0;i<p_binds.size();i++) {
+ ERR_FAIL_INDEX(p_binds[i],variants.size());
+ }
+ ConnectionData c;
+ c.from=p_from;
+ c.to=p_to;
+ c.signal=p_signal;
+ c.method=p_method;
+ c.flags=p_flags;
+ c.binds=p_binds;
+ connections.push_back(c);
+
+}
+void SceneState::add_editable_instance(const NodePath& p_path){
+
+ editable_instances.push_back(p_path);
+}
+
+
+
+SceneState::SceneState() {
+
+ base_scene_idx=-1;
+ last_modified_time=0;
+}
+
+
+////////////////
+
+
+
+void PackedScene::_set_bundled_scene(const Dictionary& d) {
+
+ state->set_bundled_scene(d);
+}
+
+Dictionary PackedScene::_get_bundled_scene() const {
+
+ return state->get_bundled_scene();
+}
+
+
+Error PackedScene::pack(Node *p_scene) {
+
+ return state->pack(p_scene);
+}
+
+void PackedScene::clear() {
+
+ state->clear();
+}
+
+bool PackedScene::can_instance() const {
+
+ return state->can_instance();
+}
+
+Node *PackedScene::instance(bool p_gen_edit_state) const {
+
+#ifndef TOOLS_ENABLED
+ if (p_gen_edit_state) {
+ ERR_EXPLAIN("Edit state is only for editors, does not work without tools compiled");
+ ERR_FAIL_COND_V(p_gen_edit_state,NULL);
+ }
+#endif
+
+ Node *s = state->instance(p_gen_edit_state);
+ if (!s)
+ return NULL;
+
+ if (p_gen_edit_state) {
+ s->set_scene_instance_state(state);
+ }
+
+ if (get_path()!="" && get_path().find("::")==-1)
+ s->set_filename(get_path());
+
+
+ s->notification(Node::NOTIFICATION_INSTANCED);
+
+ return s;
+}
+
+void PackedScene::replace_state(Ref<SceneState> p_by) {
+
+ state=p_by;
+ state->set_path(get_path());
+#ifdef TOOLS_ENABLED
+ state->set_last_modified_time(get_last_modified_time());
+#endif
+
+}
+
+void PackedScene::recreate_state() {
+
+ state = Ref<SceneState>( memnew( SceneState ));
+ state->set_path(get_path());
+#ifdef TOOLS_ENABLED
+ state->set_last_modified_time(get_last_modified_time());
+#endif
+}
+
+Ref<SceneState> PackedScene::get_state() {
+
+ return state;
+}
+
+void PackedScene::set_path(const String& p_path,bool p_take_over) {
+
+ state->set_path(p_path);
+ Resource::set_path(p_path,p_take_over);
+}
+
+
void PackedScene::_bind_methods() {
ObjectTypeDB::bind_method(_MD("pack","path:Node"),&PackedScene::pack);
- ObjectTypeDB::bind_method(_MD("instance:Node"),&PackedScene::instance,DEFVAL(false));
+ ObjectTypeDB::bind_method(_MD("instance:Node","gen_edit_state"),&PackedScene::instance,DEFVAL(false));
ObjectTypeDB::bind_method(_MD("can_instance"),&PackedScene::can_instance);
ObjectTypeDB::bind_method(_MD("_set_bundled_scene"),&PackedScene::_set_bundled_scene);
ObjectTypeDB::bind_method(_MD("_get_bundled_scene"),&PackedScene::_get_bundled_scene);
@@ -625,5 +1642,6 @@ void PackedScene::_bind_methods() {
PackedScene::PackedScene() {
+ state = Ref<SceneState>( memnew( SceneState ));
}
diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h
index 6c7fa545d4..00a812f16a 100644
--- a/scene/resources/packed_scene.h
+++ b/scene/resources/packed_scene.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,17 +32,26 @@
#include "resource.h"
#include "scene/main/node.h"
-class PackedScene : public Resource {
- OBJ_TYPE( PackedScene, Resource );
- RES_BASE_EXTENSION("scn");
+class SceneState : public Reference {
+
+ OBJ_TYPE( SceneState, Reference );
Vector<StringName> names;
Vector<Variant> variants;
+ Vector<NodePath> node_paths;
+ Vector<NodePath> editable_instances;
+ mutable HashMap<NodePath,int> node_path_cache;
+ mutable Map<int,int> base_scene_node_remap;
+
+ int base_scene_idx;
- //missing - instances
- //missing groups
- //missing - owner
- //missing - override names and values
+ enum {
+ FLAG_ID_IS_PATH=(1<<30),
+ FLAG_INSTANCE_IS_PLACEHOLDER=(1<<30),
+ FLAG_MASK=(1<<24)-1,
+ NO_PARENT_SAVED=0x7FFFFFFF,
+
+ };
struct NodeData {
@@ -59,9 +68,15 @@ class PackedScene : public Resource {
};
Vector<Property> properties;
- Vector<int> groups;
+ Vector<int> groups;
+
};
+ struct PackState {
+ Ref<SceneState> state;
+ int node;
+ PackState() { node=-1; }
+ };
Vector<NodeData> nodes;
@@ -77,16 +92,100 @@ class PackedScene : public Resource {
Vector<ConnectionData> connections;
- Error _parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map);
- Error _parse_connections(Node *p_owner,Node *p_node, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map);
+ Error _parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map,Map<Node*,int> &nodepath_map);
+ Error _parse_connections(Node *p_owner,Node *p_node, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map,Map<Node*,int> &nodepath_map);
+
+ String path;
+
+ uint64_t last_modified_time;
+
+ _FORCE_INLINE_ Ref<SceneState> _get_base_scene_state() const;
+
+ static bool disable_placeholders;
+public:
+
+ enum {
+ TYPE_INSTANCED=0x7FFFFFFF
+ };
+
+ static void set_disable_placeholders(bool p_disable);
+
+ int find_node_by_path(const NodePath& p_node) const;
+ Variant get_property_value(int p_node,const StringName& p_property,bool &found) const;
+ bool is_node_in_group(int p_node,const StringName& p_group) const;
+ bool is_connection(int p_node,const StringName& p_signal,int p_to_node,const StringName& p_to_method) const;
+
+
+ void set_bundled_scene(const Dictionary& p_dictionary);
+ Dictionary get_bundled_scene() const;
+
+ Error pack(Node *p_scene);
+
+ void set_path(const String &p_path);
+ String get_path() const;
+
+ void clear();
+
+ bool can_instance() const;
+ Node *instance(bool p_gen_edit_state=false) const;
+
+
+ //unbuild API
+
+ int get_node_count() const;
+ StringName get_node_type(int p_idx) const;
+ StringName get_node_name(int p_idx) const;
+ NodePath get_node_path(int p_idx,bool p_for_parent=false) const;
+ NodePath get_node_owner_path(int p_idx) const;
+ Ref<PackedScene> get_node_instance(int p_idx) const;
+ Vector<StringName> get_node_groups(int p_idx) const;
+
+ int get_node_property_count(int p_idx) const;
+ StringName get_node_property_name(int p_idx,int p_prop) const;
+ Variant get_node_property_value(int p_idx,int p_prop) const;
+
+ int get_connection_count() const;
+ NodePath get_connection_source(int p_idx) const;
+ StringName get_connection_signal(int p_idx) const;
+ NodePath get_connection_target(int p_idx) const;
+ StringName get_connection_method(int p_idx) const;
+ int get_connection_flags(int p_idx) const;
+ Array get_connection_binds(int p_idx) const;
+
+ Vector<NodePath> get_editable_instances() const;
+
+ //build API
+
+ int add_name(const StringName& p_name);
+ int add_value(const Variant& p_value);
+ int add_node_path(const NodePath& p_path);
+ int add_node(int p_parent,int p_owner,int p_type,int p_name, int p_instance);
+ void add_node_property(int p_node,int p_name,int p_value);
+ void add_node_group(int p_node,int p_group);
+ void set_base_scene(int p_idx);
+ void add_connection(int p_from,int p_to, int p_signal, int p_method, int p_flags,const Vector<int>& p_binds);
+ void add_editable_instance(const NodePath& p_path);
+
+ virtual void set_last_modified_time(uint64_t p_time) { last_modified_time=p_time; }
+ uint64_t get_last_modified_time() const { return last_modified_time; }
+
+
+ SceneState();
+};
+
+class PackedScene : public Resource {
+
+ OBJ_TYPE(PackedScene, Resource );
+ RES_BASE_EXTENSION("scn");
+
+ Ref<SceneState> state;
void _set_bundled_scene(const Dictionary& p_scene);
Dictionary _get_bundled_scene() const;
protected:
-
static void _bind_methods();
public:
@@ -98,7 +197,18 @@ public:
bool can_instance() const;
Node *instance(bool p_gen_edit_state=false) const;
+ void recreate_state();
+ void replace_state(Ref<SceneState> p_by);
+
+ virtual void set_path(const String& p_path,bool p_take_over=false);
+#ifdef TOOLS_ENABLED
+ virtual void set_last_modified_time(uint64_t p_time) { state->set_last_modified_time(p_time); }
+
+#endif
+ Ref<SceneState> get_state();
+
PackedScene();
+
};
#endif // SCENE_PRELOADER_H
diff --git a/scene/resources/plane_shape.cpp b/scene/resources/plane_shape.cpp
index 150406ceff..f551414f61 100644
--- a/scene/resources/plane_shape.cpp
+++ b/scene/resources/plane_shape.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,7 +30,34 @@
#include "servers/physics_server.h"
-
+Vector<Vector3> PlaneShape::_gen_debug_mesh_lines() {
+
+ Plane p = get_plane();
+ Vector<Vector3> points;
+
+ Vector3 n1 = p.get_any_perpendicular_normal();
+ Vector3 n2 = p.normal.cross(n1).normalized();
+
+ Vector3 pface[4]={
+ p.normal*p.d+n1*10.0+n2*10.0,
+ p.normal*p.d+n1*10.0+n2*-10.0,
+ p.normal*p.d+n1*-10.0+n2*-10.0,
+ p.normal*p.d+n1*-10.0+n2*10.0,
+ };
+
+ points.push_back(pface[0]);
+ points.push_back(pface[1]);
+ points.push_back(pface[1]);
+ points.push_back(pface[2]);
+ points.push_back(pface[2]);
+ points.push_back(pface[3]);
+ points.push_back(pface[3]);
+ points.push_back(pface[0]);
+ points.push_back(p.normal*p.d);
+ points.push_back(p.normal*p.d+p.normal*3);
+
+ return points;
+}
void PlaneShape::_update_shape() {
diff --git a/scene/resources/plane_shape.h b/scene/resources/plane_shape.h
index 3bdf8f2bef..543c433965 100644
--- a/scene/resources/plane_shape.h
+++ b/scene/resources/plane_shape.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -39,9 +39,9 @@ class PlaneShape : public Shape {
protected:
static void _bind_methods();
-
virtual void _update_shape();
+ virtual Vector<Vector3> _gen_debug_mesh_lines();
public:
void set_plane(Plane p_plane);
diff --git a/scene/resources/ray_shape.cpp b/scene/resources/ray_shape.cpp
index e12ecf107b..73ce4de976 100644
--- a/scene/resources/ray_shape.cpp
+++ b/scene/resources/ray_shape.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,7 +30,14 @@
#include "servers/physics_server.h"
+Vector<Vector3> RayShape::_gen_debug_mesh_lines() {
+ Vector<Vector3> points;
+ points.push_back(Vector3());
+ points.push_back(Vector3(0,0,get_length()));
+
+ return points;
+}
void RayShape::_update_shape() {
diff --git a/scene/resources/ray_shape.h b/scene/resources/ray_shape.h
index 0b6156d343..0218045247 100644
--- a/scene/resources/ray_shape.h
+++ b/scene/resources/ray_shape.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -39,7 +39,7 @@ protected:
static void _bind_methods();
virtual void _update_shape();
-
+ virtual Vector<Vector3> _gen_debug_mesh_lines();
public:
void set_length(float p_length);
diff --git a/scene/resources/rectangle_shape_2d.cpp b/scene/resources/rectangle_shape_2d.cpp
index d3332f45a5..bc0f86f0a7 100644
--- a/scene/resources/rectangle_shape_2d.cpp
+++ b/scene/resources/rectangle_shape_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,7 +29,7 @@
#include "rectangle_shape_2d.h"
#include "servers/physics_2d_server.h"
-
+#include "servers/visual_server.h"
void RectangleShape2D::_update_shape() {
Physics2DServer::get_singleton()->shape_set_data(get_rid(),extents);
@@ -48,6 +48,19 @@ Vector2 RectangleShape2D::get_extents() const {
return extents;
}
+void RectangleShape2D::draw(const RID& p_to_rid,const Color& p_color) {
+
+
+ VisualServer::get_singleton()->canvas_item_add_rect(p_to_rid,Rect2(-extents,extents*2.0),p_color);
+
+}
+
+Rect2 RectangleShape2D::get_rect() const {
+
+ return Rect2(-extents,extents*2.0);
+
+}
+
void RectangleShape2D::_bind_methods() {
diff --git a/scene/resources/rectangle_shape_2d.h b/scene/resources/rectangle_shape_2d.h
index 0b89441d04..1ffbe1e356 100644
--- a/scene/resources/rectangle_shape_2d.h
+++ b/scene/resources/rectangle_shape_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -44,6 +44,9 @@ public:
void set_extents(const Vector2& p_extents);
Vector2 get_extents() const;
+ virtual void draw(const RID& p_to_rid,const Color& p_color);
+ virtual Rect2 get_rect() const ;
+
RectangleShape2D();
};
diff --git a/scene/resources/rich_text.cpp b/scene/resources/rich_text.cpp
index 7e58a19ac3..8acf5ff39b 100644
--- a/scene/resources/rich_text.cpp
+++ b/scene/resources/rich_text.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/rich_text.h b/scene/resources/rich_text.h
index 9dfffbfeb3..c74a391b10 100644
--- a/scene/resources/rich_text.h
+++ b/scene/resources/rich_text.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/room.cpp b/scene/resources/room.cpp
index 3673b18394..0f9eb85244 100644
--- a/scene/resources/room.cpp
+++ b/scene/resources/room.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/room.h b/scene/resources/room.h
index f621d8f1bf..c5aaea311e 100644
--- a/scene/resources/room.h
+++ b/scene/resources/room.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/sample.cpp b/scene/resources/sample.cpp
index 0a785e7bf6..4b25a2c490 100644
--- a/scene/resources/sample.cpp
+++ b/scene/resources/sample.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -210,11 +210,11 @@ void Sample::_bind_methods(){
ADD_PROPERTY( PropertyInfo( Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), _SCS("_set_data"), _SCS("_get_data") );
ADD_PROPERTY( PropertyInfo( Variant::BOOL, "stereo"), _SCS(""), _SCS("is_stereo") );
- ADD_PROPERTY( PropertyInfo( Variant::INT, "length"), _SCS(""), _SCS("get_length") );
+ ADD_PROPERTY( PropertyInfo( Variant::INT, "length",PROPERTY_HINT_RANGE,"0,999999999"), _SCS(""), _SCS("get_length") );
ADD_PROPERTY( PropertyInfo( Variant::INT, "mix_rate", PROPERTY_HINT_RANGE,"1,192000,1" ), _SCS("set_mix_rate"), _SCS("get_mix_rate") );
ADD_PROPERTY( PropertyInfo( Variant::INT, "loop_format", PROPERTY_HINT_ENUM,"None,Forward,PingPong" ), _SCS("set_loop_format"), _SCS("get_loop_format") );
- ADD_PROPERTY( PropertyInfo( Variant::INT, "loop_begin", PROPERTY_HINT_RANGE,"0,"+itos(99999999)+",1"), _SCS("set_loop_begin"), _SCS("get_loop_begin") );
- ADD_PROPERTY( PropertyInfo( Variant::INT, "loop_end", PROPERTY_HINT_RANGE,"0,"+itos(99999999)+",1"), _SCS("set_loop_end"), _SCS("get_loop_end") );
+ ADD_PROPERTY( PropertyInfo( Variant::INT, "loop_begin", PROPERTY_HINT_RANGE,"0,"+itos(999999999)+",1"), _SCS("set_loop_begin"), _SCS("get_loop_begin") );
+ ADD_PROPERTY( PropertyInfo( Variant::INT, "loop_end", PROPERTY_HINT_RANGE,"0,"+itos(999999999)+",1"), _SCS("set_loop_end"), _SCS("get_loop_end") );
BIND_CONSTANT( FORMAT_PCM8 );
BIND_CONSTANT( FORMAT_PCM16 );
diff --git a/scene/resources/sample.h b/scene/resources/sample.h
index 4877e0b841..0a88167233 100644
--- a/scene/resources/sample.h
+++ b/scene/resources/sample.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/sample_library.cpp b/scene/resources/sample_library.cpp
index 6bb9bc0d06..5b70ee0e11 100644
--- a/scene/resources/sample_library.cpp
+++ b/scene/resources/sample_library.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,7 +34,7 @@ bool SampleLibrary::_set(const StringName& p_name, const Variant& p_value) {
if (String(p_name).begins_with("samples/")) {
- String name=String(p_name).get_slice("/",1);
+ String name=String(p_name).get_slicec('/',1);
if (p_value.get_type()==Variant::NIL)
sample_map.erase(name);
else {
@@ -66,7 +66,7 @@ bool SampleLibrary::_get(const StringName& p_name,Variant &r_ret) const {
if (String(p_name).begins_with("samples/")) {
- String name=String(p_name).get_slice("/",1);
+ String name=String(p_name).get_slicec('/',1);
if(sample_map.has(name)) {
Dictionary d;
d["sample"]=sample_map[name].sample;
diff --git a/scene/resources/sample_library.h b/scene/resources/sample_library.h
index 88519e7035..8377967106 100644
--- a/scene/resources/sample_library.h
+++ b/scene/resources/sample_library.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/scene_format_text.cpp b/scene/resources/scene_format_text.cpp
new file mode 100644
index 0000000000..5450b9e2ac
--- /dev/null
+++ b/scene/resources/scene_format_text.cpp
@@ -0,0 +1,1438 @@
+#include "scene_format_text.h"
+
+#include "globals.h"
+#include "version.h"
+#include "os/dir_access.h"
+
+#define FORMAT_VERSION 1
+
+#include "version.h"
+#include "os/dir_access.h"
+
+#define _printerr() ERR_PRINT(String(res_path+":"+itos(lines)+" - Parse Error: "+error_text).utf8().get_data());
+
+
+
+
+///
+
+void ResourceInteractiveLoaderText::set_local_path(const String& p_local_path) {
+
+ res_path=p_local_path;
+}
+
+Ref<Resource> ResourceInteractiveLoaderText::get_resource() {
+
+ return resource;
+}
+
+Error ResourceInteractiveLoaderText::_parse_sub_resource(VariantParser::Stream* p_stream,Ref<Resource>& r_res,int &line,String &r_err_str) {
+
+ VariantParser::Token token;
+ VariantParser::get_token(p_stream,token,line,r_err_str);
+ if (token.type!=VariantParser::TK_NUMBER) {
+ r_err_str="Expected number (sub-resource index)";
+ return ERR_PARSE_ERROR;
+ }
+
+ int index = token.value;
+
+ String path = local_path+"::"+itos(index);
+
+ if (!ResourceCache::has(path)) {
+ r_err_str="Can't load cached sub-resource: "+path;
+ return ERR_PARSE_ERROR;
+ }
+
+ r_res=RES(ResourceCache::get(path));
+
+ VariantParser::get_token(p_stream,token,line,r_err_str);
+ if (token.type!=VariantParser::TK_PARENTHESIS_CLOSE) {
+ r_err_str="Expected ')'";
+ return ERR_PARSE_ERROR;
+ }
+
+
+ return OK;
+}
+
+Error ResourceInteractiveLoaderText::_parse_ext_resource(VariantParser::Stream* p_stream,Ref<Resource>& r_res,int &line,String &r_err_str){
+
+ VariantParser::Token token;
+ VariantParser::get_token(p_stream,token,line,r_err_str);
+ if (token.type!=VariantParser::TK_NUMBER) {
+ r_err_str="Expected number (sub-resource index)";
+ return ERR_PARSE_ERROR;
+ }
+
+ int id = token.value;
+
+
+ if (!ext_resources.has(id)) {
+ r_err_str="Can't load cached ext-resource #"+itos(id);
+ return ERR_PARSE_ERROR;
+ }
+
+ String path = ext_resources[id].path;
+ String type = ext_resources[id].type;
+
+ if (path.find("://")==-1 && path.is_rel_path()) {
+ // path is relative to file being loaded, so convert to a resource path
+ path=Globals::get_singleton()->localize_path(res_path.get_base_dir().plus_file(path));
+
+ }
+
+ r_res=ResourceLoader::load(path,type);
+
+ if (r_res.is_null()) {
+ r_err_str="Couldn't load external resource: "+path;
+ return ERR_PARSE_ERROR;
+ }
+
+ VariantParser::get_token(p_stream,token,line,r_err_str);
+ if (token.type!=VariantParser::TK_PARENTHESIS_CLOSE) {
+ r_err_str="Expected ')'";
+ return ERR_PARSE_ERROR;
+ }
+
+
+ return OK;
+}
+
+
+Error ResourceInteractiveLoaderText::poll() {
+
+ if (error!=OK)
+ return error;
+
+ if (next_tag.name=="ext_resource") {
+
+
+ if (!next_tag.fields.has("path")) {
+ error=ERR_FILE_CORRUPT;
+ error_text="Missing 'path' in external resource tag";
+ _printerr();
+ return error;
+ }
+
+ if (!next_tag.fields.has("type")) {
+ error=ERR_FILE_CORRUPT;
+ error_text="Missing 'type' in external resource tag";
+ _printerr();
+ return error;
+ }
+
+ if (!next_tag.fields.has("id")) {
+ error=ERR_FILE_CORRUPT;
+ error_text="Missing 'id' in external resource tag";
+ _printerr();
+ return error;
+ }
+
+ String path=next_tag.fields["path"];
+ String type=next_tag.fields["type"];
+ int index=next_tag.fields["id"];
+
+
+ if (path.find("://")==-1 && path.is_rel_path()) {
+ // path is relative to file being loaded, so convert to a resource path
+ path=Globals::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path));
+ }
+
+ if (remaps.has(path)) {
+ path=remaps[path];
+ }
+
+ RES res = ResourceLoader::load(path,type);
+
+ if (res.is_null()) {
+
+ if (ResourceLoader::get_abort_on_missing_resources()) {
+ error=ERR_FILE_CORRUPT;
+ error_text="[ext_resource] referenced nonexistent resource at: "+path;
+ _printerr();
+ return error;
+ } else {
+ ResourceLoader::notify_dependency_error(local_path,path,type);
+ }
+ } else {
+
+ resource_cache.push_back(res);
+ }
+
+ ExtResource er;
+ er.path=path;
+ er.type=type;
+ ext_resources[index]=er;
+
+ error = VariantParser::parse_tag(&stream,lines,error_text,next_tag,&rp);
+
+ if (error) {
+ _printerr();
+ }
+
+ return error;
+
+
+ } else if (next_tag.name=="sub_resource") {
+
+
+ if (!next_tag.fields.has("type")) {
+ error=ERR_FILE_CORRUPT;
+ error_text="Missing 'type' in external resource tag";
+ _printerr();
+ return error;
+ }
+
+ if (!next_tag.fields.has("id")) {
+ error=ERR_FILE_CORRUPT;
+ error_text="Missing 'index' in external resource tag";
+ _printerr();
+ return error;
+ }
+
+ String type=next_tag.fields["type"];
+ int id=next_tag.fields["id"];
+
+ String path = local_path+"::"+itos(id);
+
+
+ //bool exists=ResourceCache::has(path);
+
+ Ref<Resource> res;
+
+ if ( !ResourceCache::has(path)) { //only if it doesn't exist
+
+ Object *obj = ObjectTypeDB::instance(type);
+ if (!obj) {
+
+ error_text+="Can't create sub resource of type: "+type;
+ _printerr();
+ error=ERR_FILE_CORRUPT;
+ return error;
+ }
+
+
+ Resource *r = obj->cast_to<Resource>();
+ if (!r) {
+
+ error_text+="Can't create sub resource of type, because not a resource: "+type;
+ _printerr();
+ error=ERR_FILE_CORRUPT;
+ return error;
+ }
+
+ res=Ref<Resource>(r);
+ resource_cache.push_back(res);
+ res->set_path(path);
+
+ }
+
+ while(true) {
+
+ String assign;
+ Variant value;
+
+ error = VariantParser::parse_tag_assign_eof(&stream,lines,error_text,next_tag,assign,value,&rp);
+
+ if (error) {
+ _printerr();
+ return error;
+ }
+
+ if (assign!=String()) {
+ if (res.is_valid()) {
+ res->set(assign,value);
+ }
+ //it's assignment
+ } else if (next_tag.name!=String()) {
+
+ error=OK;
+ break;
+ } else {
+ error=ERR_FILE_CORRUPT;
+ error_text="Premature end of file while parsing [sub_resource]";
+ _printerr();
+ return error;
+ }
+
+
+ }
+
+ return OK;
+
+ } else if (next_tag.name=="resource") {
+
+ if (is_scene) {
+
+ error_text+="found the 'resource' tag on a scene file!";
+ _printerr();
+ error=ERR_FILE_CORRUPT;
+ return error;
+ }
+
+ Object *obj = ObjectTypeDB::instance(res_type);
+ if (!obj) {
+
+ error_text+="Can't create sub resource of type: "+res_type;
+ _printerr();
+ error=ERR_FILE_CORRUPT;
+ return error;
+ }
+
+
+ Resource *r = obj->cast_to<Resource>();
+ if (!r) {
+
+ error_text+="Can't create sub resource of type, because not a resource: "+res_type;
+ _printerr();
+ error=ERR_FILE_CORRUPT;
+ return error;
+ }
+
+ resource=Ref<Resource>(r);
+
+ while(true) {
+
+ String assign;
+ Variant value;
+
+ error = VariantParser::parse_tag_assign_eof(&stream,lines,error_text,next_tag,assign,value,&rp);
+
+ if (error) {
+ if (error!=ERR_FILE_EOF) {
+ _printerr();
+ } else {
+ if (!ResourceCache::has(res_path)) {
+ resource->set_path(res_path);
+ }
+ }
+ return error;
+ }
+
+ if (assign!=String()) {
+ resource->set(assign,value);
+ //it's assignment
+ } else if (next_tag.name!=String()) {
+
+ error=ERR_FILE_CORRUPT;
+ error_text="Extra tag found when parsing main resource file";
+ _printerr();
+ return error;
+ } else {
+ error=ERR_FILE_EOF;
+ return error;
+ }
+
+ }
+
+ return OK;
+
+ } else if (next_tag.name=="node") {
+
+ if (!is_scene) {
+
+ error_text+="found the 'node' tag on a resource file!";
+ _printerr();
+ error=ERR_FILE_CORRUPT;
+ return error;
+ }
+
+ /*
+ int add_name(const StringName& p_name);
+ int add_value(const Variant& p_value);
+ int add_node_path(const NodePath& p_path);
+ int add_node(int p_parent,int p_owner,int p_type,int p_name, int p_instance);
+ void add_node_property(int p_node,int p_name,int p_value);
+ void add_node_group(int p_node,int p_group);
+ void set_base_scene(int p_idx);
+ void add_connection(int p_from,int p_to, int p_signal, int p_method, int p_flags,const Vector<int>& p_binds);
+ void add_editable_instance(const NodePath& p_path);
+
+ */
+
+ int parent=-1;
+ int owner=-1;
+ int type=-1;
+ int name=-1;
+ int instance=-1;
+ int base_scene=-1;
+
+ if (next_tag.fields.has("name")) {
+ name=packed_scene->get_state()->add_name(next_tag.fields["name"]);
+ }
+
+ if (next_tag.fields.has("parent")) {
+ parent=packed_scene->get_state()->add_node_path(next_tag.fields["parent"]);
+ }
+
+
+
+ if (next_tag.fields.has("type")) {
+ type=packed_scene->get_state()->add_name(next_tag.fields["type"]);
+ } else {
+ type=SceneState::TYPE_INSTANCED; //no type? assume this was instanced
+ }
+
+
+ if (next_tag.fields.has("instance")) {
+
+ instance=packed_scene->get_state()->add_value(next_tag.fields["instance"]);
+
+ if (packed_scene->get_state()->get_node_count()==0 && parent==-1) {
+ packed_scene->get_state()->set_base_scene(instance);
+ instance=-1;
+ }
+ }
+
+ if (next_tag.fields.has("owner")) {
+ owner=packed_scene->get_state()->add_node_path(next_tag.fields["owner"]);
+ } else {
+ if (parent!=-1 && !(type==SceneState::TYPE_INSTANCED && instance==-1))
+ owner=0; //if no owner, owner is root
+ }
+
+ int node_id = packed_scene->get_state()->add_node(parent,owner,type,name,instance);
+
+
+ while(true) {
+
+ String assign;
+ Variant value;
+
+ error = VariantParser::parse_tag_assign_eof(&stream,lines,error_text,next_tag,assign,value,&rp);
+
+ if (error) {
+ if (error!=ERR_FILE_EOF) {
+ _printerr();
+ } else {
+ resource=packed_scene;
+ if (!ResourceCache::has(res_path)) {
+ packed_scene->set_path(res_path);
+ }
+ }
+ return error;
+ }
+
+ if (assign!=String()) {
+ int nameidx = packed_scene->get_state()->add_name(assign);
+ int valueidx = packed_scene->get_state()->add_value(value);
+ packed_scene->get_state()->add_node_property(node_id,nameidx,valueidx);
+ //it's assignment
+ } else if (next_tag.name!=String()) {
+
+ error=OK;
+ return error;
+ } else {
+
+ resource=packed_scene;
+ error=ERR_FILE_EOF;
+ return error;
+ }
+
+ }
+
+ return OK;
+
+ } else if (next_tag.name=="connection") {
+
+ if (!is_scene) {
+
+ error_text+="found the 'connection' tag on a resource file!";
+ _printerr();
+ error=ERR_FILE_CORRUPT;
+ return error;
+ }
+
+ if (!next_tag.fields.has("from")) {
+ error=ERR_FILE_CORRUPT;
+ error_text="missing 'from' field fron connection tag";
+ return error;
+ }
+
+ if (!next_tag.fields.has("to")) {
+ error=ERR_FILE_CORRUPT;
+ error_text="missing 'to' field fron connection tag";
+ return error;
+ }
+
+ if (!next_tag.fields.has("signal")) {
+ error=ERR_FILE_CORRUPT;
+ error_text="missing 'signal' field fron connection tag";
+ return error;
+ }
+
+ if (!next_tag.fields.has("method")) {
+ error=ERR_FILE_CORRUPT;
+ error_text="missing 'method' field fron connection tag";
+ return error;
+ }
+
+ NodePath from = next_tag.fields["from"];
+ NodePath to = next_tag.fields["to"];
+ StringName method = next_tag.fields["method"];
+ StringName signal = next_tag.fields["signal"];
+ int flags=CONNECT_PERSIST;
+ Array binds;
+
+ if (next_tag.fields.has("flags")) {
+ flags=next_tag.fields["flags"];
+ }
+
+ if (next_tag.fields.has("binds")) {
+ binds=next_tag.fields["binds"];
+ }
+
+ Vector<int> bind_ints;
+ for(int i=0;i<binds.size();i++) {
+ bind_ints.push_back( packed_scene->get_state()->add_value( binds[i] ) );
+ }
+
+ packed_scene->get_state()->add_connection(
+ packed_scene->get_state()->add_node_path(from.simplified()),
+ packed_scene->get_state()->add_node_path(to.simplified()),
+ packed_scene->get_state()->add_name(signal),
+ packed_scene->get_state()->add_name(method),
+ flags,
+ bind_ints
+ );
+
+ error = VariantParser::parse_tag(&stream,lines,error_text,next_tag,&rp);
+
+ if (error) {
+ if (error!=ERR_FILE_EOF) {
+ _printerr();
+ } else {
+ resource=packed_scene;
+ }
+ }
+
+ return error;
+ } else if (next_tag.name=="editable") {
+
+ if (!is_scene) {
+
+ error_text+="found the 'editable' tag on a resource file!";
+ _printerr();
+ error=ERR_FILE_CORRUPT;
+ return error;
+ }
+
+ if (!next_tag.fields.has("path")) {
+ error=ERR_FILE_CORRUPT;
+ error_text="missing 'path' field fron connection tag";
+ _printerr();
+ return error;
+ }
+
+ NodePath path = next_tag.fields["path"];
+
+ packed_scene->get_state()->add_editable_instance(path.simplified());
+
+ error = VariantParser::parse_tag(&stream,lines,error_text,next_tag,&rp);
+
+ if (error) {
+ if (error!=ERR_FILE_EOF) {
+ _printerr();
+ } else {
+ resource=packed_scene;
+ }
+ }
+
+ return error;
+
+ } else {
+
+ error_text+="Unknown tag in file: "+next_tag.name;
+ _printerr();
+ error=ERR_FILE_CORRUPT;
+ return error;
+ }
+
+ return OK;
+}
+
+int ResourceInteractiveLoaderText::get_stage() const {
+
+ return resource_current;
+}
+int ResourceInteractiveLoaderText::get_stage_count() const {
+
+ return resources_total;//+ext_resources;
+}
+
+ResourceInteractiveLoaderText::~ResourceInteractiveLoaderText() {
+
+ memdelete(f);
+}
+
+void ResourceInteractiveLoaderText::get_dependencies(FileAccess *f,List<String> *p_dependencies,bool p_add_types) {
+
+
+ open(f);
+ ERR_FAIL_COND(error!=OK);
+
+ while(next_tag.name=="ext_resource") {
+
+ if (!next_tag.fields.has("type")) {
+ error=ERR_FILE_CORRUPT;
+ error_text="Missing 'type' in external resource tag";
+ _printerr();
+ return;
+ }
+
+ if (!next_tag.fields.has("id")) {
+ error=ERR_FILE_CORRUPT;
+ error_text="Missing 'index' in external resource tag";
+ _printerr();
+ return;
+ }
+
+ String path=next_tag.fields["path"];
+ String type=next_tag.fields["type"];
+
+
+ if (path.find("://")==-1 && path.is_rel_path()) {
+ // path is relative to file being loaded, so convert to a resource path
+ path=Globals::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path));
+ }
+
+
+ if (p_add_types) {
+ path+="::"+type;
+ }
+
+ p_dependencies->push_back(path);
+
+ Error err = VariantParser::parse_tag(&stream,lines,error_text,next_tag,&rp);
+
+ if (err) {
+ error_text="Unexpected end of file";
+ _printerr();
+ error=ERR_FILE_CORRUPT;
+ }
+
+
+ }
+}
+
+Error ResourceInteractiveLoaderText::rename_dependencies(FileAccess *p_f, const String &p_path,const Map<String,String>& p_map) {
+
+
+
+
+#if 0
+ open(p_f);
+ ERR_FAIL_COND_V(error!=OK,error);
+
+ //FileAccess
+
+ bool old_format=false;
+
+ FileAccess *fw = NULL;
+
+ String base_path=local_path.get_base_dir();
+
+ while(true) {
+ bool exit;
+ List<String> order;
+
+ Tag *tag = parse_tag(&exit,true,&order);
+
+ bool done=false;
+
+ if (!tag) {
+ if (fw) {
+ memdelete(fw);
+ }
+ error=ERR_FILE_CORRUPT;
+ ERR_FAIL_COND_V(!exit,error);
+ error=ERR_FILE_EOF;
+
+ return error;
+ }
+
+ if (tag->name=="ext_resource") {
+
+ if (!tag->args.has("index") || !tag->args.has("path") || !tag->args.has("type")) {
+ old_format=true;
+ break;
+ }
+
+ if (!fw) {
+
+ fw=FileAccess::open(p_path+".depren",FileAccess::WRITE);
+ fw->store_line("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"); //no escape
+ fw->store_line("<resource_file type=\""+resource_type+"\" subresource_count=\""+itos(resources_total)+"\" version=\""+itos(VERSION_MAJOR)+"."+itos(VERSION_MINOR)+"\" version_name=\""+VERSION_FULL_NAME+"\">");
+
+ }
+
+ String path = tag->args["path"];
+ String index = tag->args["index"];
+ String type = tag->args["type"];
+
+
+ bool relative=false;
+ if (!path.begins_with("res://")) {
+ path=base_path.plus_file(path).simplify_path();
+ relative=true;
+ }
+
+
+ if (p_map.has(path)) {
+ String np=p_map[path];
+ path=np;
+ }
+
+ if (relative) {
+ //restore relative
+ path=base_path.path_to_file(path);
+ }
+
+ tag->args["path"]=path;
+ tag->args["index"]=index;
+ tag->args["type"]=type;
+
+ } else {
+
+ done=true;
+ }
+
+ String tagt="\t<";
+ if (exit)
+ tagt+="/";
+ tagt+=tag->name;
+
+ for(List<String>::Element *E=order.front();E;E=E->next()) {
+ tagt+=" "+E->get()+"=\""+tag->args[E->get()]+"\"";
+ }
+ tagt+=">";
+ fw->store_line(tagt);
+ if (done)
+ break;
+ close_tag("ext_resource");
+ fw->store_line("\t</ext_resource>");
+
+ }
+
+
+ if (old_format) {
+ if (fw)
+ memdelete(fw);
+
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ da->remove(p_path+".depren");
+ memdelete(da);
+ //fuck it, use the old approach;
+
+ WARN_PRINT(("This file is old, so it can't refactor dependencies, opening and resaving: "+p_path).utf8().get_data());
+
+ Error err;
+ FileAccess *f2 = FileAccess::open(p_path,FileAccess::READ,&err);
+ if (err!=OK) {
+ ERR_FAIL_COND_V(err!=OK,ERR_FILE_CANT_OPEN);
+ }
+
+ Ref<ResourceInteractiveLoaderText> ria = memnew( ResourceInteractiveLoaderText );
+ ria->local_path=Globals::get_singleton()->localize_path(p_path);
+ ria->res_path=ria->local_path;
+ ria->remaps=p_map;
+ // ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
+ ria->open(f2);
+
+ err = ria->poll();
+
+ while(err==OK) {
+ err=ria->poll();
+ }
+
+ ERR_FAIL_COND_V(err!=ERR_FILE_EOF,ERR_FILE_CORRUPT);
+ RES res = ria->get_resource();
+ ERR_FAIL_COND_V(!res.is_valid(),ERR_FILE_CORRUPT);
+
+ return ResourceFormatSaverText::singleton->save(p_path,res);
+ }
+
+ if (!fw) {
+
+ return OK; //nothing to rename, do nothing
+ }
+
+ uint8_t c=f->get_8();
+ while(!f->eof_reached()) {
+ fw->store_8(c);
+ c=f->get_8();
+ }
+
+ bool all_ok = fw->get_error()==OK;
+
+ memdelete(fw);
+
+ if (!all_ok) {
+ return ERR_CANT_CREATE;
+ }
+
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ da->remove(p_path);
+ da->rename(p_path+".depren",p_path);
+ memdelete(da);
+#endif
+ return OK;
+
+}
+
+
+void ResourceInteractiveLoaderText::open(FileAccess *p_f) {
+
+ error=OK;
+
+ lines=1;
+ f=p_f;
+
+
+ stream.f=f;
+ is_scene=false;
+
+
+ VariantParser::Tag tag;
+ Error err = VariantParser::parse_tag(&stream,lines,error_text,tag);
+
+ if (err) {
+
+ error=err;
+ _printerr();
+ return;
+ }
+
+ if (tag.fields.has("format")) {
+ int fmt = tag.fields["format"];
+ if (fmt>FORMAT_VERSION) {
+ error_text="Saved with newer format version";
+ _printerr();
+ error=ERR_PARSE_ERROR;
+ return;
+ }
+ }
+
+
+ if (tag.name=="gd_scene") {
+ is_scene=true;
+ packed_scene.instance();
+
+ } else if (tag.name=="gd_resource") {
+ if (!tag.fields.has("type")) {
+ error_text="Missing 'type' field in 'gd_resource' tag";
+ _printerr();
+ error=ERR_PARSE_ERROR;
+ return;
+ }
+
+ res_type=tag.fields["type"];
+
+ } else {
+ error_text="Unrecognized file type: "+tag.name;
+ _printerr();
+ error=ERR_PARSE_ERROR;
+ return;
+
+ }
+
+
+
+ if (tag.fields.has("load_steps")) {
+ resources_total=tag.fields["load_steps"];
+ } else {
+ resources_total=0;
+ }
+
+
+ err = VariantParser::parse_tag(&stream,lines,error_text,next_tag,&rp);
+
+ if (err) {
+ error_text="Unexpected end of file";
+ _printerr();
+ error=ERR_FILE_CORRUPT;
+ }
+
+ rp.ext_func=_parse_ext_resources;
+ rp.sub_func=_parse_sub_resources;
+ rp.func=NULL;
+ rp.userdata=this;
+
+}
+
+
+
+
+String ResourceInteractiveLoaderText::recognize(FileAccess *p_f) {
+
+ error=OK;
+
+ lines=1;
+ f=p_f;
+
+ stream.f=f;
+
+
+ VariantParser::Tag tag;
+ Error err = VariantParser::parse_tag(&stream,lines,error_text,tag);
+
+ if (err) {
+ _printerr();
+ return "";
+ }
+
+ if (tag.fields.has("format")) {
+ int fmt = tag.fields["format"];
+ if (fmt>FORMAT_VERSION) {
+ error_text="Saved with newer format version";
+ _printerr();
+ return "";
+ }
+ }
+
+ if (tag.name=="gd_scene")
+ return "PackedScene";
+
+ if (tag.name!="gd_resource")
+ return "";
+
+
+
+ if (!tag.fields.has("type")) {
+ error_text="Missing 'type' field in 'gd_resource' tag";
+ _printerr();
+ return "";
+ }
+
+ return tag.fields["type"];
+
+
+}
+
+/////////////////////
+
+Ref<ResourceInteractiveLoader> ResourceFormatLoaderText::load_interactive(const String &p_path, Error *r_error) {
+
+ if (r_error)
+ *r_error=ERR_CANT_OPEN;
+
+ Error err;
+ FileAccess *f = FileAccess::open(p_path,FileAccess::READ,&err);
+
+
+ if (err!=OK) {
+
+ ERR_FAIL_COND_V(err!=OK,Ref<ResourceInteractiveLoader>());
+ }
+
+ Ref<ResourceInteractiveLoaderText> ria = memnew( ResourceInteractiveLoaderText );
+ ria->local_path=Globals::get_singleton()->localize_path(p_path);
+ ria->res_path=ria->local_path;
+// ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
+ ria->open(f);
+
+ return ria;
+}
+
+void ResourceFormatLoaderText::get_recognized_extensions_for_type(const String& p_type,List<String> *p_extensions) const {
+
+ if (p_type=="") {
+ get_recognized_extensions(p_extensions);
+ return;
+ }
+
+ if (p_type=="PackedScene")
+ p_extensions->push_back("tscn");
+ else
+ p_extensions->push_back("tres");
+
+}
+
+void ResourceFormatLoaderText::get_recognized_extensions(List<String> *p_extensions) const{
+
+ p_extensions->push_back("tscn");
+ p_extensions->push_back("tres");
+}
+
+bool ResourceFormatLoaderText::handles_type(const String& p_type) const{
+
+ return true;
+}
+String ResourceFormatLoaderText::get_resource_type(const String &p_path) const{
+
+
+
+ String ext=p_path.extension().to_lower();
+ if (ext=="tscn")
+ return "PackedScene";
+ else if (ext!="tres")
+ return String();
+
+ //for anyhting else must test..
+
+ FileAccess *f = FileAccess::open(p_path,FileAccess::READ);
+ if (!f) {
+
+ return ""; //could not rwead
+ }
+
+ Ref<ResourceInteractiveLoaderText> ria = memnew( ResourceInteractiveLoaderText );
+ ria->local_path=Globals::get_singleton()->localize_path(p_path);
+ ria->res_path=ria->local_path;
+// ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
+ String r = ria->recognize(f);
+ return r;
+}
+
+
+void ResourceFormatLoaderText::get_dependencies(const String& p_path,List<String> *p_dependencies,bool p_add_types) {
+
+ FileAccess *f = FileAccess::open(p_path,FileAccess::READ);
+ if (!f) {
+
+ ERR_FAIL();
+ }
+
+ Ref<ResourceInteractiveLoaderText> ria = memnew( ResourceInteractiveLoaderText );
+ ria->local_path=Globals::get_singleton()->localize_path(p_path);
+ ria->res_path=ria->local_path;
+// ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
+ ria->get_dependencies(f,p_dependencies,p_add_types);
+
+
+}
+
+Error ResourceFormatLoaderText::rename_dependencies(const String &p_path,const Map<String,String>& p_map) {
+
+ FileAccess *f = FileAccess::open(p_path,FileAccess::READ);
+ if (!f) {
+
+ ERR_FAIL_V(ERR_CANT_OPEN);
+ }
+
+ Ref<ResourceInteractiveLoaderText> ria = memnew( ResourceInteractiveLoaderText );
+ ria->local_path=Globals::get_singleton()->localize_path(p_path);
+ ria->res_path=ria->local_path;
+// ria->set_local_path( Globals::get_singleton()->localize_path(p_path) );
+ return ria->rename_dependencies(f,p_path,p_map);
+}
+
+
+/*****************************************************************************************************/
+/*****************************************************************************************************/
+/*****************************************************************************************************/
+/*****************************************************************************************************/
+/*****************************************************************************************************/
+/*****************************************************************************************************/
+/*****************************************************************************************************/
+/*****************************************************************************************************/
+/*****************************************************************************************************/
+/*****************************************************************************************************/
+
+
+String ResourceFormatSaverTextInstance::_write_resources(void *ud,const RES& p_resource) {
+
+ ResourceFormatSaverTextInstance *rsi=(ResourceFormatSaverTextInstance*)ud;
+ return rsi->_write_resource(p_resource);
+
+}
+
+String ResourceFormatSaverTextInstance::_write_resource(const RES& res) {
+
+ if (external_resources.has(res)) {
+
+ return "ExtResource( "+itos(external_resources[res]+1)+" )";
+ } else {
+
+ if (internal_resources.has(res)) {
+ return "SubResource( "+itos(internal_resources[res])+" )";
+ } else if (res->get_path().length() && res->get_path().find("::")==-1) {
+
+ //external resource
+ String path=relative_paths?local_path.path_to_file(res->get_path()):res->get_path();
+ return "Resource( \""+path+"\" )";
+ } else {
+ ERR_EXPLAIN("Resource was not pre cached for the resource section, bug?");
+ ERR_FAIL_V("null");
+ //internal resource
+ }
+ }
+
+ return "null";
+}
+
+void ResourceFormatSaverTextInstance::_find_resources(const Variant& p_variant,bool p_main) {
+
+
+ switch(p_variant.get_type()) {
+ case Variant::OBJECT: {
+
+
+ RES res = p_variant.operator RefPtr();
+
+ if (res.is_null() || external_resources.has(res))
+ return;
+
+ if (!p_main && (!bundle_resources ) && res->get_path().length() && res->get_path().find("::") == -1 ) {
+ int index = external_resources.size();
+ external_resources[res]=index;
+ return;
+ }
+
+ if (resource_set.has(res))
+ return;
+
+ List<PropertyInfo> property_list;
+
+ res->get_property_list( &property_list );
+ property_list.sort();
+
+ List<PropertyInfo>::Element *I=property_list.front();
+
+ while(I) {
+
+ PropertyInfo pi=I->get();
+
+ if (pi.usage&PROPERTY_USAGE_STORAGE || (bundle_resources && pi.usage&PROPERTY_USAGE_BUNDLE)) {
+
+ Variant v=res->get(I->get().name);
+ _find_resources(v);
+ }
+
+ I=I->next();
+ }
+
+ resource_set.insert( res ); //saved after, so the childs it needs are available when loaded
+ saved_resources.push_back(res);
+
+ } break;
+ case Variant::ARRAY: {
+
+ Array varray=p_variant;
+ int len=varray.size();
+ for(int i=0;i<len;i++) {
+
+ Variant v=varray.get(i);
+ _find_resources(v);
+ }
+
+ } break;
+ case Variant::DICTIONARY: {
+
+ Dictionary d=p_variant;
+ List<Variant> keys;
+ d.get_key_list(&keys);
+ for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
+
+ Variant v = d[E->get()];
+ _find_resources(v);
+ }
+ } break;
+ default: {}
+ }
+
+}
+
+
+
+Error ResourceFormatSaverTextInstance::save(const String &p_path,const RES& p_resource,uint32_t p_flags) {
+
+ if (p_path.ends_with(".tscn")) {
+ packed_scene=p_resource;
+ }
+
+ Error err;
+ f = FileAccess::open(p_path, FileAccess::WRITE,&err);
+ ERR_FAIL_COND_V( err, ERR_CANT_OPEN );
+ FileAccessRef _fref(f);
+
+ local_path = Globals::get_singleton()->localize_path(p_path);
+
+ relative_paths=p_flags&ResourceSaver::FLAG_RELATIVE_PATHS;
+ skip_editor=p_flags&ResourceSaver::FLAG_OMIT_EDITOR_PROPERTIES;
+ bundle_resources=p_flags&ResourceSaver::FLAG_BUNDLE_RESOURCES;
+ takeover_paths=p_flags&ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS;
+ if (!p_path.begins_with("res://")) {
+ takeover_paths=false;
+ }
+
+ // save resources
+ _find_resources(p_resource,true);
+
+ if (packed_scene.is_valid()) {
+ //add instances to external resources if saving a packed scene
+ for(int i=0;i<packed_scene->get_state()->get_node_count();i++) {
+ Ref<PackedScene> instance=packed_scene->get_state()->get_node_instance(i);
+ if (instance.is_valid() && !external_resources.has(instance)) {
+ int index = external_resources.size();
+ external_resources[instance]=index;
+ }
+ }
+ }
+
+
+ ERR_FAIL_COND_V(err!=OK,err);
+
+ {
+ String title=packed_scene.is_valid()?"[gd_scene ":"[gd_resource ";
+ if (packed_scene.is_null())
+ title+="type=\""+p_resource->get_type()+"\" ";
+ int load_steps=saved_resources.size()+external_resources.size();
+ //if (packed_scene.is_valid()) {
+ // load_steps+=packed_scene->get_node_count();
+ //}
+ //no, better to not use load steps from nodes, no point to that
+
+ if (load_steps>1) {
+ title+="load_steps="+itos(load_steps)+" ";
+ }
+ title+="format="+itos(FORMAT_VERSION)+"";
+ //title+="engine_version=\""+itos(VERSION_MAJOR)+"."+itos(VERSION_MINOR)+"\"";
+
+ f->store_string(title);
+ f->store_line("]\n"); //one empty line
+ }
+
+
+ Vector<RES> sorted_er;
+ sorted_er.resize(external_resources.size());
+
+ for(Map<RES,int>::Element *E=external_resources.front();E;E=E->next()) {
+
+ sorted_er[E->get()]=E->key();
+ }
+
+ for(int i=0;i<sorted_er.size();i++) {
+ String p = sorted_er[i]->get_path();
+
+ f->store_string("[ext_resource path=\""+p+"\" type=\""+sorted_er[i]->get_save_type()+"\" id="+itos(i+1)+"]\n"); //bundled
+ }
+
+ if (external_resources.size())
+ f->store_line(String()); //separate
+
+ Set<int> used_indices;
+
+ for(List<RES>::Element *E=saved_resources.front();E;E=E->next()) {
+
+ RES res = E->get();
+ if (E->next() && (res->get_path()=="" || res->get_path().find("::") != -1 )) {
+
+ if (res->get_subindex()!=0) {
+ if (used_indices.has(res->get_subindex())) {
+ res->set_subindex(0); //repeated
+ } else {
+ used_indices.insert(res->get_subindex());
+ }
+ }
+ }
+ }
+
+ for(List<RES>::Element *E=saved_resources.front();E;E=E->next()) {
+
+ RES res = E->get();
+ ERR_CONTINUE(!resource_set.has(res));
+ bool main = (E->next()==NULL);
+
+ if (main && packed_scene.is_valid())
+ break; //save as a scene
+
+ if (main) {
+ f->store_line("[resource]\n");
+ } else {
+ String line="[sub_resource ";
+ if (res->get_subindex()==0) {
+ int new_subindex=1;
+ if (used_indices.size()) {
+ new_subindex=used_indices.back()->get()+1;
+ }
+
+ res->set_subindex(new_subindex);
+ used_indices.insert(new_subindex);
+ }
+
+ int idx = res->get_subindex();
+ line+="type=\""+res->get_type()+"\" id="+itos(idx);
+ f->store_line(line+"]\n");
+ if (takeover_paths) {
+ res->set_path(p_path+"::"+itos(idx),true);
+ }
+
+ internal_resources[res]=idx;
+
+ }
+
+
+ List<PropertyInfo> property_list;
+ res->get_property_list(&property_list);
+// property_list.sort();
+ for(List<PropertyInfo>::Element *PE = property_list.front();PE;PE=PE->next()) {
+
+
+ if (skip_editor && PE->get().name.begins_with("__editor"))
+ continue;
+
+ if (PE->get().usage&PROPERTY_USAGE_STORAGE || (bundle_resources && PE->get().usage&PROPERTY_USAGE_BUNDLE)) {
+
+ String name = PE->get().name;
+ Variant value = res->get(name);
+
+
+ if ((PE->get().usage&PROPERTY_USAGE_STORE_IF_NONZERO && value.is_zero())||(PE->get().usage&PROPERTY_USAGE_STORE_IF_NONONE && value.is_one()) )
+ continue;
+
+ if (PE->get().type==Variant::OBJECT && value.is_zero())
+ continue;
+
+ String vars;
+ VariantWriter::write_to_string(value,vars,_write_resources,this);
+ f->store_string(name+" = "+vars+"\n");
+ }
+
+
+ }
+
+ f->store_string("\n");
+
+ }
+
+ if (packed_scene.is_valid()) {
+ //if this is a scene, save nodes and connections!
+ Ref<SceneState> state = packed_scene->get_state();
+ for(int i=0;i<state->get_node_count();i++) {
+
+ StringName type = state->get_node_type(i);
+ StringName name = state->get_node_name(i);
+ NodePath path = state->get_node_path(i,true);
+ NodePath owner = state->get_node_owner_path(i);
+ Ref<PackedScene> instance = state->get_node_instance(i);
+ Vector<StringName> groups = state->get_node_groups(i);
+
+ if (instance.is_valid())
+ print_line("for path "+String(path)+" instance "+instance->get_path());
+
+ String header="[node";
+ header+=" name=\""+String(name)+"\"";
+ if (type!=StringName()) {
+ header+=" type=\""+String(type)+"\"";
+ }
+ if (path!=NodePath()) {
+ header+=" parent=\""+String(path.simplified())+"\"";
+ }
+ if (owner!=NodePath() && owner!=NodePath(".")) {
+ header+=" owner=\""+String(owner.simplified())+"\"";
+ }
+
+ if (groups.size()) {
+ String sgroups=" groups=[ ";
+ for(int j=0;j<groups.size();j++) {
+ if (j>0)
+ sgroups+=", ";
+ sgroups+="\""+groups[j].operator String().c_escape()+"\"";
+ }
+ sgroups+=" ]";
+ header+=sgroups;
+ }
+
+ f->store_string(header);
+
+ if (instance.is_valid()) {
+
+ String vars;
+ f->store_string(" instance=");
+ VariantWriter::write_to_string(instance,vars,_write_resources,this);
+ f->store_string(vars);
+
+ }
+
+ f->store_line("]\n");
+
+ for(int j=0;j<state->get_node_property_count(i);j++) {
+
+ String vars;
+ VariantWriter::write_to_string(state->get_node_property_value(i,j),vars,_write_resources,this);
+
+ f->store_string(String(state->get_node_property_name(i,j))+" = "+vars+"\n");
+ }
+
+ if (state->get_node_property_count(i)) {
+ //add space
+ f->store_line(String());
+ }
+
+ }
+
+ for(int i=0;i<state->get_connection_count();i++) {
+
+ String connstr="[connection";
+ connstr+=" signal=\""+String(state->get_connection_signal(i))+"\"";
+ connstr+=" from=\""+String(state->get_connection_source(i).simplified())+"\"";
+ connstr+=" to=\""+String(state->get_connection_target(i).simplified())+"\"";
+ connstr+=" method=\""+String(state->get_connection_method(i))+"\"";
+ int flags = state->get_connection_flags(i);
+ if (flags!=Object::CONNECT_PERSIST) {
+ connstr+=" flags="+itos(flags);
+ }
+
+ Array binds=state->get_connection_binds(i);
+ f->store_string(connstr);
+ if (binds.size()) {
+ String vars;
+ VariantWriter::write_to_string(binds,vars,_write_resources,this);
+ f->store_string(" binds= "+vars);
+
+ }
+
+ f->store_line("]\n");
+ }
+
+ f->store_line(String());
+
+ Vector<NodePath> editable_instances = state->get_editable_instances();
+ for(int i=0;i<editable_instances.size();i++) {
+ f->store_line("[editable path=\""+editable_instances[i].operator String()+"\"]");
+ }
+ }
+
+ if (f->get_error()!=OK && f->get_error()!=ERR_FILE_EOF) {
+ f->close();
+ return ERR_CANT_CREATE;
+ }
+
+ f->close();
+ //memdelete(f);
+
+ return OK;
+}
+
+
+
+Error ResourceFormatSaverText::save(const String &p_path,const RES& p_resource,uint32_t p_flags) {
+
+ if (p_path.ends_with(".sct") && p_resource->get_type()!="PackedScene") {
+ return ERR_FILE_UNRECOGNIZED;
+ }
+
+ ResourceFormatSaverTextInstance saver;
+ return saver.save(p_path,p_resource,p_flags);
+
+}
+
+bool ResourceFormatSaverText::recognize(const RES& p_resource) const {
+
+
+ return true; // all recognized!
+}
+void ResourceFormatSaverText::get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) const {
+
+ p_extensions->push_back("tres"); //text resource
+ if (p_resource->get_type()=="PackedScene")
+ p_extensions->push_back("tscn"); //text scene
+
+}
+
+ResourceFormatSaverText* ResourceFormatSaverText::singleton=NULL;
+ResourceFormatSaverText::ResourceFormatSaverText() {
+ singleton=this;
+}
diff --git a/scene/resources/scene_format_text.h b/scene/resources/scene_format_text.h
new file mode 100644
index 0000000000..0e844c9165
--- /dev/null
+++ b/scene/resources/scene_format_text.h
@@ -0,0 +1,142 @@
+#ifndef SCENE_FORMAT_TEXT_H
+#define SCENE_FORMAT_TEXT_H
+
+#include "io/resource_loader.h"
+#include "io/resource_saver.h"
+#include "os/file_access.h"
+#include "scene/resources/packed_scene.h"
+#include "variant_parser.h"
+
+
+
+class ResourceInteractiveLoaderText : public ResourceInteractiveLoader {
+
+ String local_path;
+ String res_path;
+ String error_text;
+
+ FileAccess *f;
+
+ VariantParser::StreamFile stream;
+
+ struct ExtResource {
+ String path;
+ String type;
+ };
+
+
+ bool is_scene;
+ String res_type;
+
+
+
+// Map<String,String> remaps;
+
+ Map<int,ExtResource> ext_resources;
+
+ int resources_total;
+ int resource_current;
+ String resource_type;
+
+ VariantParser::Tag next_tag;
+
+ mutable int lines;
+
+ Map<String,String> remaps;
+ //void _printerr();
+
+ static Error _parse_sub_resources(void* p_self, VariantParser::Stream* p_stream,Ref<Resource>& r_res,int &line,String &r_err_str) { return reinterpret_cast<ResourceInteractiveLoaderText*>(p_self)->_parse_sub_resource(p_stream,r_res,line,r_err_str); }
+ static Error _parse_ext_resources(void* p_self, VariantParser::Stream* p_stream,Ref<Resource>& r_res,int &line,String &r_err_str) { return reinterpret_cast<ResourceInteractiveLoaderText*>(p_self)->_parse_ext_resource(p_stream,r_res,line,r_err_str); }
+
+ Error _parse_sub_resource(VariantParser::Stream* p_stream,Ref<Resource>& r_res,int &line,String &r_err_str);
+ Error _parse_ext_resource(VariantParser::Stream* p_stream,Ref<Resource>& r_res,int &line,String &r_err_str);
+
+ VariantParser::ResourceParser rp;
+
+
+ Ref<PackedScene> packed_scene;
+
+
+friend class ResourceFormatLoaderText;
+
+ List<RES> resource_cache;
+ Error error;
+
+ RES resource;
+
+public:
+
+ virtual void set_local_path(const String& p_local_path);
+ virtual Ref<Resource> get_resource();
+ virtual Error poll();
+ virtual int get_stage() const;
+ virtual int get_stage_count() const;
+
+ void open(FileAccess *p_f);
+ String recognize(FileAccess *p_f);
+ void get_dependencies(FileAccess *p_f, List<String> *p_dependencies, bool p_add_types);
+ Error rename_dependencies(FileAccess *p_f, const String &p_path,const Map<String,String>& p_map);
+
+
+ ~ResourceInteractiveLoaderText();
+
+};
+
+
+
+class ResourceFormatLoaderText : public ResourceFormatLoader {
+public:
+
+ virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path,Error *r_error=NULL);
+ virtual void get_recognized_extensions_for_type(const String& p_type,List<String> *p_extensions) const;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual bool handles_type(const String& p_type) const;
+ virtual String get_resource_type(const String &p_path) const;
+ virtual void get_dependencies(const String& p_path, List<String> *p_dependencies, bool p_add_types=false);
+ virtual Error rename_dependencies(const String &p_path,const Map<String,String>& p_map);
+
+
+};
+
+
+class ResourceFormatSaverTextInstance {
+
+ String local_path;
+
+ Ref<PackedScene> packed_scene;
+
+ bool takeover_paths;
+ bool relative_paths;
+ bool bundle_resources;
+ bool skip_editor;
+ FileAccess *f;
+ Set<RES> resource_set;
+ List<RES> saved_resources;
+ Map<RES,int> external_resources;
+ Map<RES,int> internal_resources;
+
+ void _find_resources(const Variant& p_variant,bool p_main=false);
+
+ static String _write_resources(void *ud,const RES& p_resource);
+ String _write_resource(const RES& res);
+
+
+public:
+
+ Error save(const String &p_path,const RES& p_resource,uint32_t p_flags=0);
+
+
+};
+
+class ResourceFormatSaverText : public ResourceFormatSaver {
+public:
+ static ResourceFormatSaverText* singleton;
+ virtual Error save(const String &p_path,const RES& p_resource,uint32_t p_flags=0);
+ virtual bool recognize(const RES& p_resource) const;
+ virtual void get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) const;
+
+ ResourceFormatSaverText();
+};
+
+
+#endif // SCENE_FORMAT_TEXT_H
diff --git a/scene/resources/scene_preloader.cpp b/scene/resources/scene_preloader.cpp
index 09001c1a94..c031f3c721 100644
--- a/scene/resources/scene_preloader.cpp
+++ b/scene/resources/scene_preloader.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/scene_preloader.h b/scene/resources/scene_preloader.h
index d60d08afd4..2317c9e0bd 100644
--- a/scene/resources/scene_preloader.h
+++ b/scene/resources/scene_preloader.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/segment_shape_2d.cpp b/scene/resources/segment_shape_2d.cpp
index b8bd3de552..b8b14fd6fc 100644
--- a/scene/resources/segment_shape_2d.cpp
+++ b/scene/resources/segment_shape_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,6 +29,7 @@
#include "segment_shape_2d.h"
#include "servers/physics_2d_server.h"
+#include "servers/visual_server.h"
void SegmentShape2D::_update_shape() {
@@ -62,6 +63,23 @@ Vector2 SegmentShape2D::get_b() const {
return b;
}
+void SegmentShape2D::draw(const RID& p_to_rid,const Color& p_color) {
+
+ VisualServer::get_singleton()->canvas_item_add_line(p_to_rid,a,b,p_color,3);
+}
+
+Rect2 SegmentShape2D::get_rect() const{
+
+ Rect2 rect;
+ rect.pos=a;
+ rect.expand_to(b);
+ return rect;
+
+}
+
+
+
+
void SegmentShape2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_a","a"),&SegmentShape2D::set_a);
@@ -94,6 +112,37 @@ void RayShape2D::_update_shape() {
}
+
+void RayShape2D::draw(const RID& p_to_rid,const Color& p_color) {
+
+
+ Vector2 tip = Vector2(0,get_length());
+ VS::get_singleton()->canvas_item_add_line(p_to_rid,Vector2(),tip,p_color,3);
+ Vector<Vector2> pts;
+ float tsize=4;
+ pts.push_back(tip+Vector2(0,tsize));
+ pts.push_back(tip+Vector2(0.707*tsize,0));
+ pts.push_back(tip+Vector2(-0.707*tsize,0));
+ Vector<Color> cols;
+ for(int i=0;i<3;i++)
+ cols.push_back(p_color);
+
+ VS::get_singleton()->canvas_item_add_primitive(p_to_rid,pts,cols,Vector<Point2>(),RID());
+
+
+
+}
+
+Rect2 RayShape2D::get_rect() const {
+
+ Rect2 rect;
+ rect.pos=Vector2();
+ rect.expand_to(Vector2(0,length));
+ rect=rect.grow(0.707*4);
+ return rect;
+}
+
+
void RayShape2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_length","length"),&RayShape2D::set_length);
diff --git a/scene/resources/segment_shape_2d.h b/scene/resources/segment_shape_2d.h
index ec771cd2ed..6f7b2f2d38 100644
--- a/scene/resources/segment_shape_2d.h
+++ b/scene/resources/segment_shape_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -49,6 +49,9 @@ public:
Vector2 get_a() const;
Vector2 get_b() const;
+ virtual void draw(const RID& p_to_rid,const Color& p_color);
+ virtual Rect2 get_rect() const;
+
SegmentShape2D();
};
@@ -67,6 +70,8 @@ public:
void set_length(real_t p_length);
real_t get_length() const;
+ virtual void draw(const RID& p_to_rid,const Color& p_color);
+ virtual Rect2 get_rect() const;
RayShape2D();
};
diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp
index 90598ee789..ee9f23dd2a 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -219,7 +219,10 @@ Shader::~Shader() {
-RES ResourceFormatLoaderShader::load(const String &p_path,const String& p_original_path) {
+RES ResourceFormatLoaderShader::load(const String &p_path, const String& p_original_path, Error *r_error) {
+
+ if (r_error)
+ *r_error=ERR_FILE_CANT_OPEN;
String fragment_code;
String vertex_code;
@@ -235,6 +238,8 @@ RES ResourceFormatLoaderShader::load(const String &p_path,const String& p_origin
ERR_FAIL_COND_V(err,RES());
String base_path = p_path.get_base_dir();
+ if (r_error)
+ *r_error=ERR_FILE_CORRUPT;
Ref<Shader> shader;//( memnew( Shader ) );
@@ -435,37 +440,27 @@ RES ResourceFormatLoaderShader::load(const String &p_path,const String& p_origin
f->close();
memdelete(f);
+ if (r_error)
+ *r_error=OK;
return shader;
}
void ResourceFormatLoaderShader::get_recognized_extensions(List<String> *p_extensions) const {
- p_extensions->push_back("shader");
+ ObjectTypeDB::get_extensions_for_type("Shader", p_extensions);
}
+
bool ResourceFormatLoaderShader::handles_type(const String& p_type) const {
- return p_type=="Shader";
+ return ObjectTypeDB::is_type(p_type, "Shader");
}
String ResourceFormatLoaderShader::get_resource_type(const String &p_path) const {
- if (p_path.extension().to_lower()=="shader")
+ if (p_path.extension().to_lower()=="shd")
return "Shader";
return "";
}
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/scene/resources/shader.h b/scene/resources/shader.h
index b805cbec96..6ee8d4e793 100644
--- a/scene/resources/shader.h
+++ b/scene/resources/shader.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -126,7 +126,7 @@ public:
class ResourceFormatLoaderShader : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path,const String& p_original_path="");
+ virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String& p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/scene/resources/shader_graph.cpp b/scene/resources/shader_graph.cpp
index a0766ff317..eabc84c41e 100644
--- a/scene/resources/shader_graph.cpp
+++ b/scene/resources/shader_graph.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -80,12 +80,15 @@ void ShaderGraph::_set_data(const Dictionary &p_data) {
ERR_FAIL_COND((conns.size()%3)!=0);
for(int j=0;j<conns.size();j+=3) {
-
SourceSlot ss;
int ls=conns[j+0];
- ss.id=conns[j+1];
- ss.slot=conns[j+2];
- n.connections[ls]=ss;
+ if (ls == SLOT_DEFAULT_VALUE) {
+ n.defaults[conns[j+1]]=conns[j+2];
+ } else {
+ ss.id=conns[j+1];
+ ss.slot=conns[j+2];
+ n.connections[ls]=ss;
+ }
}
shader[t].node_map[n.id]=n;
@@ -114,7 +117,7 @@ Dictionary ShaderGraph::_get_data() const {
data[idx+4]=E->get().param2;
Array conns;
- conns.resize(E->get().connections.size()*3);
+ conns.resize(E->get().connections.size()*3+E->get().defaults.size()*3);
int idx2=0;
for(Map<int,SourceSlot>::Element*F=E->get().connections.front();F;F=F->next()) {
@@ -123,6 +126,14 @@ Dictionary ShaderGraph::_get_data() const {
conns[idx2+2]=F->get().slot;
idx2+=3;
}
+ for(Map<int,Variant>::Element*F=E->get().defaults.front();F;F=F->next()) {
+
+ conns[idx2+0]=SLOT_DEFAULT_VALUE;
+ conns[idx2+1]=F->key();
+ conns[idx2+2]=F->get();
+ idx2+=3;
+ }
+
data[idx+5]=conns;
idx+=6;
}
@@ -142,6 +153,15 @@ ShaderGraph::GraphError ShaderGraph::get_graph_error(ShaderType p_type) const {
return shader[p_type].error;
}
+int ShaderGraph::node_count(ShaderType p_which, int p_type)
+{
+ int count=0;
+ for (Map<int,Node>::Element *E=shader[p_which].node_map.front();E;E=E->next())
+ if (E->get().type==p_type)
+ count++;
+ return count;
+}
+
void ShaderGraph::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_update_shader"),&ShaderGraph::_update_shader);
@@ -155,26 +175,29 @@ void ShaderGraph::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_node_list","shader_type"),&ShaderGraph::_get_node_list);
+ ObjectTypeDB::bind_method(_MD("default_set_value","shader_type","id","param_id","value"), &ShaderGraph::default_set_value);
+ ObjectTypeDB::bind_method(_MD("default_get_value","shader_type","id","param_id"), &ShaderGraph::default_get_value);
+
ObjectTypeDB::bind_method(_MD("scalar_const_node_set_value","shader_type","id","value"),&ShaderGraph::scalar_const_node_set_value);
- ObjectTypeDB::bind_method(_MD("scalar_const_node_get_value","shader_type","id"),&ShaderGraph::scalar_const_node_set_value);
+ ObjectTypeDB::bind_method(_MD("scalar_const_node_get_value","shader_type","id"),&ShaderGraph::scalar_const_node_get_value);
ObjectTypeDB::bind_method(_MD("vec_const_node_set_value","shader_type","id","value"),&ShaderGraph::vec_const_node_set_value);
- ObjectTypeDB::bind_method(_MD("vec_const_node_get_value","shader_type","id"),&ShaderGraph::vec_const_node_set_value);
+ ObjectTypeDB::bind_method(_MD("vec_const_node_get_value","shader_type","id"),&ShaderGraph::vec_const_node_get_value);
ObjectTypeDB::bind_method(_MD("rgb_const_node_set_value","shader_type","id","value"),&ShaderGraph::rgb_const_node_set_value);
- ObjectTypeDB::bind_method(_MD("rgb_const_node_get_value","shader_type","id"),&ShaderGraph::rgb_const_node_set_value);
+ ObjectTypeDB::bind_method(_MD("rgb_const_node_get_value","shader_type","id"),&ShaderGraph::rgb_const_node_get_value);
ObjectTypeDB::bind_method(_MD("xform_const_node_set_value","shader_type","id","value"),&ShaderGraph::xform_const_node_set_value);
- ObjectTypeDB::bind_method(_MD("xform_const_node_get_value","shader_type","id"),&ShaderGraph::xform_const_node_set_value);
+ ObjectTypeDB::bind_method(_MD("xform_const_node_get_value","shader_type","id"),&ShaderGraph::xform_const_node_get_value);
// void get_node_list(ShaderType p_which,List<int> *p_node_list) const;
ObjectTypeDB::bind_method(_MD("texture_node_set_filter_size","shader_type","id","filter_size"),&ShaderGraph::texture_node_set_filter_size);
- ObjectTypeDB::bind_method(_MD("texture_node_get_filter_size","shader_type","id"),&ShaderGraph::texture_node_set_filter_size);
+ ObjectTypeDB::bind_method(_MD("texture_node_get_filter_size","shader_type","id"),&ShaderGraph::texture_node_get_filter_size);
ObjectTypeDB::bind_method(_MD("texture_node_set_filter_strength","shader_type","id","filter_strength"),&ShaderGraph::texture_node_set_filter_strength);
- ObjectTypeDB::bind_method(_MD("texture_node_get_filter_strength","shader_type","id"),&ShaderGraph::texture_node_set_filter_strength);
+ ObjectTypeDB::bind_method(_MD("texture_node_get_filter_strength","shader_type","id"),&ShaderGraph::texture_node_get_filter_strength);
ObjectTypeDB::bind_method(_MD("scalar_op_node_set_op","shader_type","id","op"),&ShaderGraph::scalar_op_node_set_op);
ObjectTypeDB::bind_method(_MD("scalar_op_node_get_op","shader_type","id"),&ShaderGraph::scalar_op_node_get_op);
@@ -237,7 +260,7 @@ void ShaderGraph::_bind_methods() {
ObjectTypeDB::bind_method(_MD("clear","shader_type"),&ShaderGraph::clear);
ObjectTypeDB::bind_method(_MD("node_set_state","shader_type","id","state"),&ShaderGraph::node_set_state);
- ObjectTypeDB::bind_method(_MD("node_get_state:var","shader_type","id"),&ShaderGraph::node_get_state);
+ ObjectTypeDB::bind_method(_MD("node_get_state:Variant","shader_type","id"),&ShaderGraph::node_get_state);
ObjectTypeDB::bind_method(_MD("_set_data"),&ShaderGraph::_set_data);
ObjectTypeDB::bind_method(_MD("_get_data"),&ShaderGraph::_get_data);
@@ -537,7 +560,7 @@ void ShaderGraph::node_add(ShaderType p_type, NodeType p_node_type,int p_id) {
case NODE_RGB_INPUT: {node.param1=_find_unique_name("Color");node.param2=Color();} break; // color uniform (assignable in material)
case NODE_XFORM_INPUT: {node.param1=_find_unique_name("XForm"); node.param2=Transform();} break; // mat4 uniform (assignable in material)
case NODE_TEXTURE_INPUT: {node.param1=_find_unique_name("Tex"); } break; // texture input (assignable in material)
- case NODE_CUBEMAP_INPUT: {node.param1=_find_unique_name("Cube"); } break; // cubemap input (assignable in material)
+ case NODE_CUBEMAP_INPUT: {node.param1=_find_unique_name("Cube"); } break; // cubemap input (assignable in material)
case NODE_DEFAULT_TEXTURE: {}; break;
case NODE_OUTPUT: {} break; // output (shader type dependent)
case NODE_COMMENT: {} break; // comment
@@ -683,6 +706,18 @@ void ShaderGraph::get_node_connections(ShaderType p_type,List<Connection> *p_con
}
}
+bool ShaderGraph::is_slot_connected(ShaderGraph::ShaderType p_type, int p_dst_id, int slot_id)
+{
+ for(const Map<int,Node>::Element *E=shader[p_type].node_map.front();E;E=E->next()) {
+ for (const Map<int,SourceSlot>::Element *F=E->get().connections.front();F;F=F->next()) {
+
+ if (p_dst_id == E->key() && slot_id==F->key())
+ return true;
+ }
+ }
+ return false;
+}
+
void ShaderGraph::clear(ShaderType p_type) {
@@ -824,6 +859,47 @@ float ShaderGraph::texture_node_get_filter_strength(ShaderType p_type,float p_id
return arr[1];
}
+void ShaderGraph::duplicate_nodes(ShaderType p_which, List<int> &p_nodes)
+{
+ //Create new node IDs
+ Map<int,int> duplicates = Map<int,int>();
+ int i=1;
+ for(List<int>::Element *E=p_nodes.front();E; E=E->next()) {
+ while (shader[p_which].node_map.has(i))
+ i++;
+ duplicates.insert(E->get(), i);
+ i++;
+ }
+
+ for(List<int>::Element *E = p_nodes.front();E; E=E->next()) {
+
+ const Node &n=shader[p_which].node_map[E->get()];
+ Node nn=n;
+ nn.id=duplicates.find(n.id)->get();
+ nn.pos += Vector2(0,100);
+ for (Map<int,SourceSlot>::Element *C=nn.connections.front();C;C=C->next()) {
+ SourceSlot &c=C->get();
+ if (p_nodes.find(c.id))
+ c.id=duplicates.find(c.id)->get();
+ }
+ shader[p_which].node_map[nn.id]=nn;
+ }
+ _request_update();
+}
+
+List<int> ShaderGraph::generate_ids(ShaderType p_type, int count)
+{
+ List<int> ids = List<int>();
+ int i=1;
+ while (ids.size() < count) {
+ while (shader[p_type].node_map.has(i))
+ i++;
+ ids.push_back(i);
+ i++;
+ }
+ return ids;
+}
+
void ShaderGraph::scalar_op_node_set_op(ShaderType p_type,float p_id,ScalarOp p_op){
@@ -955,6 +1031,33 @@ ShaderGraph::ScalarFunc ShaderGraph::scalar_func_node_get_function(ShaderType p_
return ScalarFunc(func);
}
+void ShaderGraph::default_set_value(ShaderGraph::ShaderType p_which, int p_id, int p_param, const Variant &p_value)
+{
+ ERR_FAIL_INDEX(p_which,3);
+ ERR_FAIL_COND(!shader[p_which].node_map.has(p_id));
+ Node& n = shader[p_which].node_map[p_id];
+ if(p_value.get_type()==Variant::NIL)
+ n.defaults.erase(n.defaults.find(p_param));
+ else
+ n.defaults[p_param]=p_value;
+
+ _request_update();
+
+}
+
+Variant ShaderGraph::default_get_value(ShaderGraph::ShaderType p_which, int p_id, int p_param)
+{
+ ERR_FAIL_INDEX_V(p_which,3,Variant());
+ ERR_FAIL_COND_V(!shader[p_which].node_map.has(p_id),Variant());
+ const Node& n = shader[p_which].node_map[p_id];
+
+ if (!n.defaults.has(p_param))
+ return Variant();
+ return n.defaults[p_param];
+}
+
+
+
void ShaderGraph::vec_func_node_set_function(ShaderType p_type,int p_id,VecFunc p_func){
ERR_FAIL_INDEX(p_type,3);
@@ -980,52 +1083,52 @@ ShaderGraph::VecFunc ShaderGraph::vec_func_node_get_function(ShaderType p_type,
void ShaderGraph::color_ramp_node_set_ramp(ShaderType p_type,int p_id,const DVector<Color>& p_colors, const DVector<real_t>& p_offsets){
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- ERR_FAIL_COND(p_colors.size()!=p_offsets.size());
- Node& n = shader[p_type].node_map[p_id];
- n.param1=p_colors;
- n.param2=p_offsets;
- _request_update();
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ ERR_FAIL_COND(p_colors.size()!=p_offsets.size());
+ Node& n = shader[p_type].node_map[p_id];
+ n.param1=p_colors;
+ n.param2=p_offsets;
+ _request_update();
}
DVector<Color> ShaderGraph::color_ramp_node_get_colors(ShaderType p_type,int p_id) const{
- ERR_FAIL_INDEX_V(p_type,3,DVector<Color>());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),DVector<Color>());
- const Node& n = shader[p_type].node_map[p_id];
- return n.param1;
+ ERR_FAIL_INDEX_V(p_type,3,DVector<Color>());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),DVector<Color>());
+ const Node& n = shader[p_type].node_map[p_id];
+ return n.param1;
}
DVector<real_t> ShaderGraph::color_ramp_node_get_offsets(ShaderType p_type,int p_id) const{
- ERR_FAIL_INDEX_V(p_type,3,DVector<real_t>());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),DVector<real_t>());
- const Node& n = shader[p_type].node_map[p_id];
- return n.param2;
+ ERR_FAIL_INDEX_V(p_type,3,DVector<real_t>());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),DVector<real_t>());
+ const Node& n = shader[p_type].node_map[p_id];
+ return n.param2;
}
void ShaderGraph::curve_map_node_set_points(ShaderType p_type,int p_id,const DVector<Vector2>& p_points) {
- ERR_FAIL_INDEX(p_type,3);
- ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
- Node& n = shader[p_type].node_map[p_id];
- n.param1=p_points;
- _request_update();
+ ERR_FAIL_INDEX(p_type,3);
+ ERR_FAIL_COND(!shader[p_type].node_map.has(p_id));
+ Node& n = shader[p_type].node_map[p_id];
+ n.param1=p_points;
+ _request_update();
}
DVector<Vector2> ShaderGraph::curve_map_node_get_points(ShaderType p_type,int p_id) const{
- ERR_FAIL_INDEX_V(p_type,3,DVector<Vector2>());
- ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),DVector<Vector2>());
- const Node& n = shader[p_type].node_map[p_id];
- return n.param1;
+ ERR_FAIL_INDEX_V(p_type,3,DVector<Vector2>());
+ ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),DVector<Vector2>());
+ const Node& n = shader[p_type].node_map[p_id];
+ return n.param1;
}
@@ -1215,6 +1318,12 @@ Variant ShaderGraph::node_get_state(ShaderType p_type,int p_id) const {
s["pos"]=n.pos;
s["param1"]=n.param1;
s["param2"]=n.param2;
+ Array keys;
+ for (Map<int,Variant>::Element *E=n.defaults.front();E;E=E->next()) {
+ keys.append(E->key());
+ s[E->key()]=E->get();
+ }
+ s["default_keys"]=keys;
return s;
}
@@ -1227,10 +1336,15 @@ void ShaderGraph::node_set_state(ShaderType p_type,int p_id,const Variant& p_sta
ERR_FAIL_COND(!d.has("pos"));
ERR_FAIL_COND(!d.has("param1"));
ERR_FAIL_COND(!d.has("param2"));
+ ERR_FAIL_COND(!d.has("default_keys"));
+
n.pos=d["pos"];
n.param1=d["param1"];
n.param2=d["param2"];
-
+ Array keys = d["default_keys"];
+ for(int i=0;i<keys.size();i++) {
+ n.defaults[keys[i]]=d[keys[i]];
+ }
}
ShaderGraph::ShaderGraph(Mode p_mode) : Shader(p_mode) {
@@ -1321,6 +1435,7 @@ const ShaderGraph::InOutParamInfo ShaderGraph::inout_param_info[]={
{MODE_MATERIAL,SHADER_TYPE_LIGHT,"ShadeParam","SHADE_PARAM","",SLOT_TYPE_SCALAR,SLOT_IN},
//light out
{MODE_MATERIAL,SHADER_TYPE_LIGHT,"Light","LIGHT","",SLOT_TYPE_VEC,SLOT_OUT},
+ {MODE_MATERIAL,SHADER_TYPE_LIGHT,"Shadow", "SHADOW", "",SLOT_TYPE_VEC, SLOT_OUT },
//canvas item vertex in
{MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"Vertex","vec3(SRC_VERTEX,0)","",SLOT_TYPE_VEC,SLOT_IN},
{MODE_CANVAS_ITEM,SHADER_TYPE_VERTEX,"UV","SRC_UV","",SLOT_TYPE_VEC,SLOT_IN},
@@ -1418,7 +1533,7 @@ const ShaderGraph::NodeSlotInfo ShaderGraph::node_slot_info[]= {
{NODE_CURVE_MAP,{SLOT_TYPE_SCALAR,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // vec3 interpolation (with optional curve)
{NODE_SCALAR_INPUT,{SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // scalar uniform (assignable in material)
{NODE_VEC_INPUT,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 uniform (assignable in material)
- {NODE_RGB_INPUT,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // color uniform (assignable in material)
+ {NODE_RGB_INPUT,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, // color uniform (assignable in material)
{NODE_XFORM_INPUT,{SLOT_MAX},{SLOT_TYPE_XFORM,SLOT_MAX}}, // mat4 uniform (assignable in material)
{NODE_TEXTURE_INPUT,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, // texture input (assignable in material)
{NODE_CUBEMAP_INPUT,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, // cubemap input (assignable in material)
@@ -1735,17 +1850,17 @@ void ShaderGraph::_update_shader() {
Vector<String> inputs;
int max = get_node_input_slot_count(get_mode(),ShaderType(i),n->type);
for(int k=0;k<max;k++) {
+ String iname;
if (!n->connections.has(k)) {
- shader[i].error=GRAPH_ERROR_MISSING_CONNECTIONS;
- failed=true;
- break;
+ iname="nd"+itos(n->id)+"sl"+itos(k)+"def";
+ } else {
+ iname="nd"+itos(n->connections[k].id)+"sl"+itos(n->connections[k].slot);
+ if (node_get_type(ShaderType(i),n->connections[k].id)==NODE_INPUT) {
+ inputs_used.insert(iname);
+ }
+
}
- String iname="nd"+itos(n->connections[k].id)+"sl"+itos(n->connections[k].slot);
inputs.push_back(iname);
- if (node_get_type(ShaderType(i),n->connections[k].id)==NODE_INPUT) {
- inputs_used.insert(iname);
- }
-
}
if (failed)
@@ -1874,27 +1989,27 @@ void ShaderGraph::_plot_curve(const Vector2& p_a,const Vector2& p_b,const Vector
};
for (i = 0; i < 4; i++)
- {
- for (j = 0; j < 4; j++)
+ {
+ for (j = 0; j < 4; j++)
{
tmp1[i][j] = (CR_basis[i][0] * geometry[0][j] +
- CR_basis[i][1] * geometry[1][j] +
- CR_basis[i][2] * geometry[2][j] +
- CR_basis[i][3] * geometry[3][j]);
+ CR_basis[i][1] * geometry[1][j] +
+ CR_basis[i][2] * geometry[2][j] +
+ CR_basis[i][3] * geometry[3][j]);
+ }
}
- }
/* compose the above results to get the deltas matrix */
for (i = 0; i < 4; i++)
- {
- for (j = 0; j < 4; j++)
+ {
+ for (j = 0; j < 4; j++)
{
deltas[i][j] = (tmp2[i][0] * tmp1[0][j] +
- tmp2[i][1] * tmp1[1][j] +
- tmp2[i][2] * tmp1[2][j] +
- tmp2[i][3] * tmp1[3][j]);
+ tmp2[i][1] * tmp1[1][j] +
+ tmp2[i][2] * tmp1[2][j] +
+ tmp2[i][3] * tmp1[3][j]);
+ }
}
- }
/* extract the x deltas */
@@ -1951,6 +2066,31 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
const char *typestr[4]={"float","vec3","mat4","texture"};
#define OUTNAME(id,slot) (String(typestr[get_node_output_slot_type(get_mode(),p_type,p_node->type,slot)])+" "+("nd"+itos(id)+"sl"+itos(slot)))
#define OUTVAR(id,slot) ("nd"+itos(id)+"sl"+itos(slot))
+#define DEF_VEC(slot)\
+ if (p_inputs[slot].ends_with("def")){\
+ Vector3 v = p_node->defaults[slot];\
+ code+=String(typestr[1])+" "+p_inputs[slot]+"=vec3("+v+");\n";\
+ }
+#define DEF_SCALAR(slot)\
+ if (p_inputs[slot].ends_with("def")){\
+ double v = p_node->defaults[slot];\
+ code+=String(typestr[0])+" "+p_inputs[slot]+"="+rtos(v)+";\n";\
+ }
+#define DEF_COLOR(slot)\
+ if (p_inputs[slot].ends_with("def")){\
+ Color col = p_node->defaults[slot];\
+ code+=String(typestr[1])+" "+p_inputs[slot]+"=vec3("+rtos(col.r)+","+rtos(col.g)+","+rtos(col.b)+");\n";\
+ }
+#define DEF_MATRIX(slot) \
+ if (p_inputs[slot].ends_with("def")){\
+ Transform xf = p_node->defaults[slot]; \
+ code+=String(typestr[2])+" "+p_inputs[slot]+"=mat4(\n";\
+ code+="\tvec4(vec3("+rtos(xf.basis.get_axis(0).x)+","+rtos(xf.basis.get_axis(0).y)+","+rtos(xf.basis.get_axis(0).z)+"),0),\n";\
+ code+="\tvec4(vec3("+rtos(xf.basis.get_axis(1).x)+","+rtos(xf.basis.get_axis(1).y)+","+rtos(xf.basis.get_axis(1).z)+"),0),\n";\
+ code+="\tvec4(vec3("+rtos(xf.basis.get_axis(2).x)+","+rtos(xf.basis.get_axis(2).y)+","+rtos(xf.basis.get_axis(2).z)+"),0),\n";\
+ code+="\tvec4(vec3("+rtos(xf.origin.x)+","+rtos(xf.origin.y)+","+rtos(xf.origin.z)+"),1)\n";\
+ code+=");\n";\
+ }
switch(p_node->type) {
@@ -1987,9 +2127,12 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
code+=OUTNAME(p_node->id,0)+"=TIME;\n";
}break;
case NODE_SCREEN_TEX: {
+ DEF_VEC(0);
code+=OUTNAME(p_node->id,0)+"=texscreen("+p_inputs[0]+".xy);\n";
}break;
case NODE_SCALAR_OP: {
+ DEF_SCALAR(0);
+ DEF_SCALAR(1);
int op = p_node->param1;
String optxt;
switch(op) {
@@ -2009,6 +2152,8 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
}break;
case NODE_VEC_OP: {
+ DEF_VEC(0);
+ DEF_VEC(1);
int op = p_node->param1;
String optxt;
switch(op) {
@@ -2026,6 +2171,8 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
}break;
case NODE_VEC_SCALAR_OP: {
+ DEF_VEC(0);
+ DEF_SCALAR(1);
int op = p_node->param1;
String optxt;
switch(op) {
@@ -2037,6 +2184,8 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
}break;
case NODE_RGB_OP: {
+ DEF_COLOR(0);
+ DEF_COLOR(1);
int op = p_node->param1;
static const char*axisn[3]={"x","y","z"};
@@ -2048,7 +2197,6 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
case RGB_OP_DIFFERENCE: {
code += OUTNAME(p_node->id,0)+"=abs("+p_inputs[0]+"-"+p_inputs[1]+");\n";
-
} break;
case RGB_OP_DARKEN: {
@@ -2119,11 +2267,15 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
}
}break;
case NODE_XFORM_MULT: {
+ DEF_MATRIX(0);
+ DEF_MATRIX(1);
code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+"*"+p_inputs[1]+";\n";
}break;
case NODE_XFORM_VEC_MULT: {
+ DEF_MATRIX(0);
+ DEF_VEC(1);
bool no_translation = p_node->param1;
if (no_translation) {
@@ -2134,6 +2286,8 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
}break;
case NODE_XFORM_VEC_INV_MULT: {
+ DEF_VEC(0);
+ DEF_MATRIX(1);
bool no_translation = p_node->param1;
if (no_translation) {
code += OUTNAME(p_node->id,0)+"=("+p_inputs[1]+"*vec4("+p_inputs[0]+",0)).xyz;\n";
@@ -2142,6 +2296,7 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
}
}break;
case NODE_SCALAR_FUNC: {
+ DEF_SCALAR(0);
static const char*scalar_func_id[SCALAR_MAX_FUNC]={
"sin($)",
"cos($)",
@@ -2171,6 +2326,7 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
} break;
case NODE_VEC_FUNC: {
+ DEF_VEC(0);
static const char*vec_func_id[VEC_MAX_FUNC]={
"normalize($)",
"max(min($,vec3(1,1,1)),vec3(0,0,0))",
@@ -2208,44 +2364,77 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
}
}break;
case NODE_VEC_LEN: {
+ DEF_VEC(0);
code += OUTNAME(p_node->id,0)+"=length("+p_inputs[0]+");\n";
}break;
case NODE_DOT_PROD: {
+ DEF_VEC(0);
+ DEF_VEC(1);
code += OUTNAME(p_node->id,0)+"=dot("+p_inputs[1]+","+p_inputs[0]+");\n";
}break;
case NODE_VEC_TO_SCALAR: {
+ DEF_VEC(0);
code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+".x;\n";
code += OUTNAME(p_node->id,1)+"="+p_inputs[0]+".y;\n";
code += OUTNAME(p_node->id,2)+"="+p_inputs[0]+".z;\n";
}break;
case NODE_SCALAR_TO_VEC: {
+ DEF_SCALAR(0);
+ DEF_SCALAR(1);
+ DEF_SCALAR(2);
code += OUTNAME(p_node->id,0)+"=vec3("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+""+");\n";
}break;
case NODE_VEC_TO_XFORM: {
- code += OUTNAME(p_node->id,0)+"=xform("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+","+","+p_inputs[3]+");\n";
+ DEF_VEC(0);
+ DEF_VEC(1);
+ DEF_VEC(2);
+ DEF_VEC(3);
+ code += OUTNAME(p_node->id, 0) + "=mat4(" +
+ "vec4(" + p_inputs[0] + ".x," + p_inputs[0] + ".y," + p_inputs[0] + ".z, 0.0),"
+ "vec4(" + p_inputs[1] + ".x," + p_inputs[1] + ".y," + p_inputs[1] + ".z, 0.0),"
+ "vec4(" + p_inputs[2] + ".x," + p_inputs[2] + ".y," + p_inputs[2] + ".z, 0.0),"
+ "vec4(" + p_inputs[3] + ".x," + p_inputs[3] + ".y," + p_inputs[3] + ".z, 1.0));\n";
}break;
case NODE_XFORM_TO_VEC: {
- code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+".x;\n";
- code += OUTNAME(p_node->id,1)+"="+p_inputs[0]+".y;\n";
- code += OUTNAME(p_node->id,2)+"="+p_inputs[0]+".z;\n";
- code += OUTNAME(p_node->id,3)+"="+p_inputs[0]+".o;\n";
+ DEF_MATRIX(0);
+ code += OUTNAME(p_node->id, 0) + ";\n";
+ code += OUTNAME(p_node->id, 1) + ";\n";
+ code += OUTNAME(p_node->id, 2) + ";\n";
+ code += OUTNAME(p_node->id, 3) + ";\n";
+ code += "{\n";
+ code += "\tvec4 xform_row_01=" + p_inputs[0] + ".x;\n";
+ code += "\tvec4 xform_row_02=" + p_inputs[0] + ".y;\n";
+ code += "\tvec4 xform_row_03=" + p_inputs[0] + ".z;\n";
+ code += "\tvec4 xform_row_04=" + p_inputs[0] + ".w;\n";
+ code += "\t" + OUTVAR(p_node->id, 0) + "=vec3(xform_row_01.x, xform_row_01.y, xform_row_01.z);\n";
+ code += "\t" + OUTVAR(p_node->id, 1) + "=vec3(xform_row_02.x, xform_row_02.y, xform_row_02.z);\n";
+ code += "\t" + OUTVAR(p_node->id, 2) + "=vec3(xform_row_03.x, xform_row_03.y, xform_row_03.z);\n";
+ code += "\t" + OUTVAR(p_node->id, 3) + "=vec3(xform_row_04.x, xform_row_04.y, xform_row_04.z);\n";
+ code += "}\n";
}break;
case NODE_SCALAR_INTERP: {
+ DEF_SCALAR(0);
+ DEF_SCALAR(1);
+ DEF_SCALAR(2);
code += OUTNAME(p_node->id,0)+"=mix("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+");\n";
}break;
case NODE_VEC_INTERP: {
+ DEF_VEC(0);
+ DEF_VEC(1);
+ DEF_SCALAR(2);
code += OUTNAME(p_node->id,0)+"=mix("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+");\n";
}break;
case NODE_COLOR_RAMP: {
+ DEF_SCALAR(0);
static const int color_ramp_len=512;
DVector<uint8_t> cramp;
@@ -2302,6 +2491,7 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
}break;
case NODE_CURVE_MAP: {
+ DEF_SCALAR(0);
static const int curve_map_len=256;
bool mapped[256];
zeromem(mapped,sizeof(mapped));
@@ -2386,8 +2576,9 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
String name = p_node->param1;
Color dv= p_node->param2;
- code +="uniform color "+name+"=vec4("+rtos(dv.r)+","+rtos(dv.g)+","+rtos(dv.g)+","+rtos(dv.a)+");\n";
+ code +="uniform color "+name+"=vec4("+rtos(dv.r)+","+rtos(dv.g)+","+rtos(dv.b)+","+rtos(dv.a)+");\n";
code += OUTNAME(p_node->id,0)+"="+name+".rgb;\n";
+ code += OUTNAME(p_node->id,1)+"="+name+".a;\n";
}break;
case NODE_XFORM_INPUT: {
@@ -2406,6 +2597,7 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
}break;
case NODE_TEXTURE_INPUT: {
+ DEF_VEC(0);
String name = p_node->param1;
String rname="rt_read_tex"+itos(p_node->id);
code +="uniform texture "+name+";";
@@ -2415,7 +2607,7 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
}break;
case NODE_CUBEMAP_INPUT: {
-
+ DEF_VEC(0);
String name = p_node->param1;
code +="uniform cubemap "+name+";";
String rname="rt_read_tex"+itos(p_node->id);
@@ -2424,6 +2616,7 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
code += OUTNAME(p_node->id,1)+"="+rname+".a;\n";
}break;
case NODE_DEFAULT_TEXTURE: {
+ DEF_VEC(0);
if (get_mode()==MODE_CANVAS_ITEM && p_type==SHADER_TYPE_FRAGMENT) {
@@ -2450,4 +2643,8 @@ void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<Str
}
}
+#undef DEF_SCALAR
+#undef DEF_COLOR
+#undef DEF_MATRIX
+#undef DEF_VEC
}
diff --git a/scene/resources/shader_graph.h b/scene/resources/shader_graph.h
index fd6540a747..1e6fc3507c 100644
--- a/scene/resources/shader_graph.h
+++ b/scene/resources/shader_graph.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -68,7 +68,7 @@ public:
NODE_VEC_INTERP, // vec3 interpolation (with optional curve)
NODE_COLOR_RAMP, //take scalar, output vec3
NODE_CURVE_MAP, //take scalar, otput scalar
- NODE_SCALAR_INPUT, // scalar uniform (assignable in material)
+ NODE_SCALAR_INPUT, // scalar uniform (assignable in material)
NODE_VEC_INPUT, // vec3 uniform (assignable in material)
NODE_RGB_INPUT, // color uniform (assignable in material)
NODE_XFORM_INPUT, // mat4 uniform (assignable in material)
@@ -120,6 +120,7 @@ private:
String _find_unique_name(const String& p_base);
+ enum {SLOT_DEFAULT_VALUE = 0x7FFFFFFF};
struct SourceSlot {
int id;
@@ -135,6 +136,7 @@ private:
NodeType type;
Variant param1;
Variant param2;
+ Map<int, Variant> defaults;
int id;
mutable int order; // used for sorting
int sort_order;
@@ -216,6 +218,10 @@ public:
void texture_node_set_filter_strength(ShaderType p_which,float p_id,float p_strength);
float texture_node_get_filter_strength(ShaderType p_which,float p_id) const;
+ void duplicate_nodes(ShaderType p_which, List<int> &p_nodes);
+
+ List<int> generate_ids(ShaderType p_type, int count);
+
enum ScalarOp {
SCALAR_OP_ADD,
SCALAR_OP_SUB,
@@ -314,6 +320,9 @@ public:
VEC_MAX_FUNC
};
+ void default_set_value(ShaderType p_which,int p_id,int p_param, const Variant& p_value);
+ Variant default_get_value(ShaderType p_which,int p_id,int p_param);
+
void vec_func_node_set_function(ShaderType p_which,int p_id,VecFunc p_func);
VecFunc vec_func_node_get_function(ShaderType p_which,int p_id) const;
@@ -354,6 +363,8 @@ public:
void get_node_connections(ShaderType p_which,List<Connection> *p_connections) const;
+ bool is_slot_connected(ShaderType p_which,int p_dst_id,int slot_id);
+
void clear(ShaderType p_which);
Variant node_get_state(ShaderType p_type, int p_node) const;
@@ -361,6 +372,8 @@ public:
GraphError get_graph_error(ShaderType p_type) const;
+ int node_count(ShaderType p_which, int p_type);
+
static int get_type_input_count(NodeType p_type);
static int get_type_output_count(NodeType p_type);
static SlotType get_type_input_type(NodeType p_type,int p_idx);
diff --git a/scene/resources/shape.cpp b/scene/resources/shape.cpp
index 1120a8d672..a71e414f61 100644
--- a/scene/resources/shape.cpp
+++ b/scene/resources/shape.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,9 +29,67 @@
#include "shape.h"
#include "servers/physics_server.h"
+#include "scene/resources/mesh.h"
+#include "os/os.h"
+#include "scene/main/scene_main_loop.h"
+void Shape::add_vertices_to_array(DVector<Vector3> &array, const Transform& p_xform) {
+ Vector<Vector3> toadd = _gen_debug_mesh_lines();
+
+ if (toadd.size()) {
+
+ int base=array.size();
+ array.resize(base+toadd.size());
+ DVector<Vector3>::Write w = array.write();
+ for(int i=0;i<toadd.size();i++) {
+ w[i+base]=p_xform.xform(toadd[i]);
+ }
+
+ }
+}
+
+Ref<Mesh> Shape::get_debug_mesh() {
+
+ if (debug_mesh_cache.is_valid())
+ return debug_mesh_cache;
+
+ Vector<Vector3> lines = _gen_debug_mesh_lines();
+
+ debug_mesh_cache = Ref<Mesh>(memnew(Mesh));
+
+ if (!lines.empty()) {
+ //make mesh
+ DVector<Vector3> array;
+ array.resize(lines.size());
+ {
+
+ DVector<Vector3>::Write w=array.write();
+ for(int i=0;i<lines.size();i++) {
+ w[i]=lines[i];
+ }
+ }
+
+ Array arr;
+ arr.resize(Mesh::ARRAY_MAX);
+ arr[Mesh::ARRAY_VERTEX]=array;
+
+ SceneTree *st=OS::get_singleton()->get_main_loop()->cast_to<SceneTree>();
+
+ debug_mesh_cache->add_surface(Mesh::PRIMITIVE_LINES,arr);
+
+ if (st) {
+ debug_mesh_cache->surface_set_material(0,st->get_debug_collision_material());
+ }
+
+ }
+
+
+
+ return debug_mesh_cache;
+
+}
Shape::Shape() {
@@ -49,3 +107,4 @@ Shape::~Shape() {
PhysicsServer::get_singleton()->free(shape);
}
+
diff --git a/scene/resources/shape.h b/scene/resources/shape.h
index 3cc806c7a3..bfd423a300 100644
--- a/scene/resources/shape.h
+++ b/scene/resources/shape.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,6 +30,7 @@
#define SHAPE_H
#include "resource.h"
+class Mesh;
class Shape : public Resource {
@@ -38,13 +39,22 @@ class Shape : public Resource {
RES_BASE_EXTENSION("shp");
RID shape;
+ Ref<Mesh> debug_mesh_cache;
+
protected:
_FORCE_INLINE_ RID get_shape() const { return shape; }
Shape(RID p_shape);
+
+ virtual Vector<Vector3> _gen_debug_mesh_lines()=0;// { return Vector<Vector3>(); }
public:
virtual RID get_rid() const { return shape; }
+
+ Ref<Mesh> get_debug_mesh();
+
+ void add_vertices_to_array(DVector<Vector3> &array, const Transform& p_xform);
+
Shape();
~Shape();
};
diff --git a/scene/resources/shape_2d.cpp b/scene/resources/shape_2d.cpp
index 31b28ee892..6a9773bf14 100644
--- a/scene/resources/shape_2d.cpp
+++ b/scene/resources/shape_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -108,8 +108,8 @@ void Shape2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_custom_solver_bias"),&Shape2D::get_custom_solver_bias);
ObjectTypeDB::bind_method(_MD("collide","local_xform","with_shape:Shape2D","shape_xform"),&Shape2D::collide);
ObjectTypeDB::bind_method(_MD("collide_with_motion","local_xform","local_motion","with_shape:Shape2D","shape_xform","shape_motion"),&Shape2D::collide_with_motion);
- ObjectTypeDB::bind_method(_MD("collide_and_get_contacts:var","local_xform","with_shape:Shape2D","shape_xform"),&Shape2D::collide_and_get_contacts);
- ObjectTypeDB::bind_method(_MD("collide_with_motion_and_get_contacts:var","local_xform","local_motion","with_shape:Shape2D","shape_xform","shape_motion"),&Shape2D::collide_with_motion_and_get_contacts);
+ ObjectTypeDB::bind_method(_MD("collide_and_get_contacts:Variant","local_xform","with_shape:Shape2D","shape_xform"),&Shape2D::collide_and_get_contacts);
+ ObjectTypeDB::bind_method(_MD("collide_with_motion_and_get_contacts:Variant","local_xform","local_motion","with_shape:Shape2D","shape_xform","shape_motion"),&Shape2D::collide_with_motion_and_get_contacts);
ADD_PROPERTY( PropertyInfo(Variant::REAL,"custom_solver_bias",PROPERTY_HINT_RANGE,"0,1,0.001"),_SCS("set_custom_solver_bias"),_SCS("get_custom_solver_bias"));
}
diff --git a/scene/resources/shape_2d.h b/scene/resources/shape_2d.h
index 55f3173db4..4059af62c6 100644
--- a/scene/resources/shape_2d.h
+++ b/scene/resources/shape_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -53,6 +53,8 @@ public:
Variant collide_with_motion_and_get_contacts(const Matrix32& p_local_xform, const Vector2& p_local_motion, const Ref<Shape2D>& p_shape, const Matrix32& p_shape_xform, const Vector2 &p_p_shape_motion);
Variant collide_and_get_contacts(const Matrix32& p_local_xform, const Ref<Shape2D>& p_shape, const Matrix32& p_shape_xform);
+ virtual void draw(const RID& p_to_rid,const Color& p_color) {}
+ virtual Rect2 get_rect() const { return Rect2(); }
virtual RID get_rid() const;
Shape2D();
~Shape2D();
diff --git a/scene/resources/shape_line_2d.cpp b/scene/resources/shape_line_2d.cpp
index d4dc46d64f..4133d2218f 100644
--- a/scene/resources/shape_line_2d.cpp
+++ b/scene/resources/shape_line_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -28,13 +28,14 @@
/*************************************************************************/
#include "shape_line_2d.h"
#include "servers/physics_2d_server.h"
-
+#include "servers/visual_server.h"
void LineShape2D::_update_shape() {
Array arr;
arr.push_back(normal);
arr.push_back(d);
Physics2DServer::get_singleton()->shape_set_data(get_rid(),arr);
+ emit_changed();
}
@@ -61,6 +62,32 @@ real_t LineShape2D::get_d() const {
return d;
}
+
+void LineShape2D::draw(const RID& p_to_rid,const Color& p_color) {
+
+ Vector2 point = get_d() * get_normal();
+
+ Vector2 l1[2]={point-get_normal().tangent()*100,point+get_normal().tangent()*100};
+ VS::get_singleton()->canvas_item_add_line(p_to_rid,l1[0],l1[1],p_color,3);
+ Vector2 l2[2]={point,point+get_normal()*30};
+ VS::get_singleton()->canvas_item_add_line(p_to_rid,l2[0],l2[1],p_color,3);
+
+}
+Rect2 LineShape2D::get_rect() const{
+
+ Vector2 point = get_d() * get_normal();
+
+ Vector2 l1[2]={point-get_normal().tangent()*100,point+get_normal().tangent()*100};
+ Vector2 l2[2]={point,point+get_normal()*30};
+ Rect2 rect;
+ rect.pos=l1[0];
+ rect.expand_to(l1[1]);
+ rect.expand_to(l2[0]);
+ rect.expand_to(l2[1]);
+ return rect;
+
+}
+
void LineShape2D::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_normal","normal"),&LineShape2D::set_normal);
diff --git a/scene/resources/shape_line_2d.h b/scene/resources/shape_line_2d.h
index 3ba8f57add..f6f75e7a95 100644
--- a/scene/resources/shape_line_2d.h
+++ b/scene/resources/shape_line_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -49,6 +49,9 @@ public:
Vector2 get_normal() const;
real_t get_d() const;
+ virtual void draw(const RID& p_to_rid,const Color& p_color);
+ virtual Rect2 get_rect() const;
+
LineShape2D();
};
diff --git a/scene/resources/space_2d.cpp b/scene/resources/space_2d.cpp
index 6dbf7c4a73..d328ee3de4 100644
--- a/scene/resources/space_2d.cpp
+++ b/scene/resources/space_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/space_2d.h b/scene/resources/space_2d.h
index eb3e13ee62..270f8de3ea 100644
--- a/scene/resources/space_2d.h
+++ b/scene/resources/space_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/sphere_shape.cpp b/scene/resources/sphere_shape.cpp
index e93d718efa..4764937371 100644
--- a/scene/resources/sphere_shape.cpp
+++ b/scene/resources/sphere_shape.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,6 +29,30 @@
#include "sphere_shape.h"
#include "servers/physics_server.h"
+Vector<Vector3> SphereShape::_gen_debug_mesh_lines() {
+
+ float r=get_radius();
+
+ Vector<Vector3> points;
+
+ for(int i=0;i<=360;i++) {
+
+ float ra=Math::deg2rad(i);
+ float rb=Math::deg2rad(i+1);
+ Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*r;
+ Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*r;
+
+ points.push_back(Vector3(a.x,0,a.y));
+ points.push_back(Vector3(b.x,0,b.y));
+ points.push_back(Vector3(0,a.x,a.y));
+ points.push_back(Vector3(0,b.x,b.y));
+ points.push_back(Vector3(a.x,a.y,0));
+ points.push_back(Vector3(b.x,b.y,0));
+
+ }
+
+ return points;
+}
void SphereShape::_update_shape() {
diff --git a/scene/resources/sphere_shape.h b/scene/resources/sphere_shape.h
index 1bbddb9fd9..50682f38bb 100644
--- a/scene/resources/sphere_shape.h
+++ b/scene/resources/sphere_shape.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -42,7 +42,7 @@ protected:
static void _bind_methods();
virtual void _update_shape();
-
+ virtual Vector<Vector3> _gen_debug_mesh_lines();
public:
void set_radius(float p_radius);
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index 527fae5946..71a775ee24 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -83,7 +83,7 @@ void StyleBox::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_center_size"),&StyleBox::get_center_size);
ObjectTypeDB::bind_method(_MD("get_offset"),&StyleBox::get_offset);
- ObjectTypeDB::bind_method(_MD("draw"),&StyleBox::draw);
+ ObjectTypeDB::bind_method(_MD("draw","canvas_item","rect"),&StyleBox::draw);
ADD_PROPERTYI( PropertyInfo( Variant::REAL, "content_margin/left", PROPERTY_HINT_RANGE,"-1,2048,1" ), _SCS("set_default_margin"),_SCS("get_default_margin"), MARGIN_LEFT );
ADD_PROPERTYI( PropertyInfo( Variant::REAL, "content_margin/right", PROPERTY_HINT_RANGE,"-1,2048,1" ), _SCS("set_default_margin"),_SCS("get_default_margin"), MARGIN_RIGHT );
@@ -182,10 +182,10 @@ void StyleBoxTexture::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_texture:Texture"),&StyleBoxTexture::get_texture);
ObjectTypeDB::bind_method(_MD("set_margin_size","margin","size"),&StyleBoxTexture::set_margin_size);
- ObjectTypeDB::bind_method(_MD("get_margin_size"),&StyleBoxTexture::get_margin_size);
+ ObjectTypeDB::bind_method(_MD("get_margin_size","margin"),&StyleBoxTexture::get_margin_size);
ObjectTypeDB::bind_method(_MD("set_expand_margin_size","margin","size"),&StyleBoxTexture::set_expand_margin_size);
- ObjectTypeDB::bind_method(_MD("get_expand_margin_size"),&StyleBoxTexture::get_expand_margin_size);
+ ObjectTypeDB::bind_method(_MD("get_expand_margin_size","margin"),&StyleBoxTexture::get_expand_margin_size);
ObjectTypeDB::bind_method(_MD("set_draw_center","enable"),&StyleBoxTexture::set_draw_center);
ObjectTypeDB::bind_method(_MD("get_draw_center"),&StyleBoxTexture::get_draw_center);
@@ -392,7 +392,7 @@ void StyleBoxImageMask::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_expand","expand"),&StyleBoxImageMask::set_expand);
ObjectTypeDB::bind_method(_MD("get_expand"),&StyleBoxImageMask::get_expand);
ObjectTypeDB::bind_method(_MD("set_expand_margin_size","margin","size"),&StyleBoxImageMask::set_expand_margin_size);
- ObjectTypeDB::bind_method(_MD("get_expand_margin_size"),&StyleBoxImageMask::get_expand_margin_size);
+ ObjectTypeDB::bind_method(_MD("get_expand_margin_size","margin"),&StyleBoxImageMask::get_expand_margin_size);
ADD_PROPERTY( PropertyInfo(Variant::IMAGE, "image"), _SCS("set_image"), _SCS("get_image"));
ADD_PROPERTY( PropertyInfo(Variant::BOOL, "expand"), _SCS("set_expand"), _SCS("get_expand"));
diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h
index 337bb54026..d0466ed5f1 100644
--- a/scene/resources/style_box.h
+++ b/scene/resources/style_box.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index 418df97f51..bf5070fd7d 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h
index ed91b4df61..1d329f23c0 100644
--- a/scene/resources/surface_tool.h
+++ b/scene/resources/surface_tool.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 018af0e5db..28754480f1 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -70,9 +70,9 @@ void Texture::_bind_methods() {
ObjectTypeDB::bind_method(_MD("has_alpha"),&Texture::has_alpha);
ObjectTypeDB::bind_method(_MD("set_flags","flags"),&Texture::set_flags);
ObjectTypeDB::bind_method(_MD("get_flags"),&Texture::get_flags);
- ObjectTypeDB::bind_method(_MD("draw","canvas_item","pos","modulate"),&Texture::draw,DEFVAL(Color(1,1,1)),DEFVAL(false));
- ObjectTypeDB::bind_method(_MD("draw_rect","canvas_item","rect","tile","modulate"),&Texture::draw_rect,DEFVAL(Color(1,1,1)),DEFVAL(false));
- ObjectTypeDB::bind_method(_MD("draw_rect_region","canvas_item","rect","src_rect","modulate"),&Texture::draw_rect_region,DEFVAL(Color(1,1,1)),DEFVAL(false));
+ ObjectTypeDB::bind_method(_MD("draw","canvas_item","pos","modulate","transpose"),&Texture::draw,DEFVAL(Color(1,1,1)),DEFVAL(false));
+ ObjectTypeDB::bind_method(_MD("draw_rect","canvas_item","rect","tile","modulate","transpose"),&Texture::draw_rect,DEFVAL(Color(1,1,1)),DEFVAL(false));
+ ObjectTypeDB::bind_method(_MD("draw_rect_region","canvas_item","rect","src_rect","modulate","transpose"),&Texture::draw_rect_region,DEFVAL(Color(1,1,1)),DEFVAL(false));
BIND_CONSTANT( FLAG_MIPMAPS );
BIND_CONSTANT( FLAG_REPEAT );
@@ -81,6 +81,7 @@ void Texture::_bind_methods() {
BIND_CONSTANT( FLAGS_DEFAULT );
BIND_CONSTANT( FLAG_ANISOTROPIC_FILTER );
BIND_CONSTANT( FLAG_CONVERT_TO_LINEAR );
+ BIND_CONSTANT( FLAG_MIRRORED_REPEAT );
}
@@ -181,7 +182,7 @@ void ImageTexture::_get_property_list( List<PropertyInfo> *p_list) const {
- p_list->push_back( PropertyInfo( Variant::INT, "flags", PROPERTY_HINT_FLAGS,"Mipmaps,Repeat,Filter,Anisotropic,sRGB") );
+ p_list->push_back( PropertyInfo( Variant::INT, "flags", PROPERTY_HINT_FLAGS,"Mipmaps,Repeat,Filter,Anisotropic,sRGB,Mirrored Repeat") );
p_list->push_back( PropertyInfo( Variant::IMAGE, "image", img_hint,String::num(lossy_storage_quality)) );
p_list->push_back( PropertyInfo( Variant::VECTOR2, "size",PROPERTY_HINT_NONE, ""));
p_list->push_back( PropertyInfo( Variant::INT, "storage", PROPERTY_HINT_ENUM,"Uncompressed,Compress Lossy,Compress Lossless"));
@@ -328,6 +329,16 @@ void ImageTexture::normal_to_xy() {
create_from_image(img,flags);
}
+void ImageTexture::shrink_x2_and_keep_size() {
+
+ Size2 sizeov=get_size();
+ Image img = get_data();
+ img.resize(img.get_width()/2,img.get_height()/2,Image::INTERPOLATE_BILINEAR);
+ create_from_image(img,flags);
+ set_size_override(sizeov);
+
+}
+
bool ImageTexture::has_alpha() const {
return ( format==Image::FORMAT_GRAYSCALE_ALPHA || format==Image::FORMAT_INDEXED_ALPHA || format==Image::FORMAT_RGBA );
@@ -365,6 +376,16 @@ void ImageTexture::set_size_override(const Size2& p_size) {
VisualServer::get_singleton()->texture_set_size_override(texture,w,h);
}
+void ImageTexture::set_path(const String& p_path,bool p_take_over) {
+
+ if (texture.is_valid()) {
+ VisualServer::get_singleton()->texture_set_path(texture,p_path);
+ }
+
+ Resource::set_path(p_path,p_take_over);
+}
+
+
void ImageTexture::set_storage(Storage p_storage) {
storage=p_storage;
@@ -413,10 +434,13 @@ void ImageTexture::_bind_methods() {
ObjectTypeDB::bind_method(_MD("fix_alpha_edges"),&ImageTexture::fix_alpha_edges);
ObjectTypeDB::bind_method(_MD("premultiply_alpha"),&ImageTexture::premultiply_alpha);
ObjectTypeDB::bind_method(_MD("normal_to_xy"),&ImageTexture::normal_to_xy);
+ ObjectTypeDB::bind_method(_MD("shrink_x2_and_keep_size"),&ImageTexture::shrink_x2_and_keep_size);
+
ObjectTypeDB::bind_method(_MD("set_size_override","size"),&ImageTexture::set_size_override);
ObjectTypeDB::set_method_flags(get_type_static(),_SCS("fix_alpha_edges"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
ObjectTypeDB::set_method_flags(get_type_static(),_SCS("premultiply_alpha"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
ObjectTypeDB::set_method_flags(get_type_static(),_SCS("normal_to_xy"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
+ ObjectTypeDB::set_method_flags(get_type_static(),_SCS("shrink_x2_and_keep_size"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR);
ObjectTypeDB::bind_method(_MD("_reload_hook","rid"),&ImageTexture::_reload_hook);
@@ -943,6 +967,16 @@ float CubeMap::get_lossy_storage_quality() const {
return lossy_storage_quality;
}
+void CubeMap::set_path(const String& p_path,bool p_take_over) {
+
+ if (cubemap.is_valid()) {
+ VisualServer::get_singleton()->texture_set_path(cubemap,p_path);
+ }
+
+ Resource::set_path(p_path,p_take_over);
+}
+
+
bool CubeMap::_set(const StringName& p_name, const Variant& p_value) {
if (p_name=="side/left") {
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index 9be8e24a83..2627b9480a 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -56,6 +56,7 @@ public:
FLAG_CONVERT_TO_LINEAR=VisualServer::TEXTURE_FLAG_CONVERT_TO_LINEAR,
FLAG_VIDEO_SURFACE=VisualServer::TEXTURE_FLAG_VIDEO_SURFACE,
FLAGS_DEFAULT=FLAG_MIPMAPS|FLAG_REPEAT|FLAG_FILTER,
+ FLAG_MIRRORED_REPEAT=VisualServer::TEXTURE_FLAG_MIRRORED_REPEAT
};
@@ -147,11 +148,13 @@ public:
void fix_alpha_edges();
void premultiply_alpha();
void normal_to_xy();
+ void shrink_x2_and_keep_size();
void set_size_override(const Size2& p_size);
-
+ virtual void set_path(const String& p_path,bool p_take_over=false);
+
ImageTexture();
~ImageTexture();
@@ -319,6 +322,8 @@ public:
void set_lossy_storage_quality(float p_lossy_storage_quality);
float get_lossy_storage_quality() const;
+ virtual void set_path(const String& p_path,bool p_take_over=false);
+
CubeMap();
~CubeMap();
diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp
index 21bdb6c0ab..685b2e07e1 100644
--- a/scene/resources/theme.cpp
+++ b/scene/resources/theme.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -40,9 +40,9 @@ bool Theme::_set(const StringName& p_name, const Variant& p_value) {
if (sname.find("/")!=-1) {
- String type=sname.get_slice("/",1);
- String node_type=sname.get_slice("/",0);
- String name=sname.get_slice("/",2);
+ String type=sname.get_slicec('/',1);
+ String node_type=sname.get_slicec('/',0);
+ String name=sname.get_slicec('/',2);
if (type=="icons") {
@@ -75,9 +75,9 @@ bool Theme::_get(const StringName& p_name,Variant &r_ret) const {
if (sname.find("/")!=-1) {
- String type=sname.get_slice("/",1);
- String node_type=sname.get_slice("/",0);
- String name=sname.get_slice("/",2);
+ String type=sname.get_slicec('/',1);
+ String node_type=sname.get_slicec('/',0);
+ String name=sname.get_slicec('/',2);
if (type=="icons") {
@@ -266,7 +266,52 @@ void Theme::get_icon_list(StringName p_type, List<StringName> *p_list) const {
p_list->push_back(*key);
}
+
+}
+
+void Theme::set_shader(const StringName &p_name,const StringName &p_type,const Ref<Shader>& p_shader) {
+ bool new_value=!shader_map.has(p_type) || !shader_map[p_type].has(p_name);
+
+ shader_map[p_type][p_name]=p_shader;
+
+ if (new_value) {
+ _change_notify();
+ emit_changed();;
+ }
+}
+
+Ref<Shader> Theme::get_shader(const StringName &p_name, const StringName &p_type) const {
+ if (shader_map.has(p_type) && shader_map[p_type].has(p_name) && shader_map[p_type][p_name].is_valid()) {
+ return shader_map[p_type][p_name];
+ } else {
+ return NULL;
+ }
+}
+
+bool Theme::has_shader(const StringName &p_name, const StringName &p_type) const {
+ return (shader_map.has(p_type) && shader_map[p_type].has(p_name) && shader_map[p_type][p_name].is_valid());
+}
+
+void Theme::clear_shader(const StringName &p_name, const StringName &p_type) {
+ ERR_FAIL_COND(!shader_map.has(p_type));
+ ERR_FAIL_COND(!shader_map[p_type].has(p_name));
+ shader_map[p_type].erase(p_name);
+ _change_notify();
+ emit_changed();;
+}
+
+void Theme::get_shader_list(const StringName &p_type, List<StringName> *p_list) const {
+ if (!shader_map.has(p_type))
+ return;
+
+ const StringName *key=NULL;
+
+ while((key=shader_map[p_type].next(key))) {
+
+ p_list->push_back(*key);
+ }
+
}
@@ -552,36 +597,36 @@ void Theme::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_icon:Texture","name","type"),&Theme::get_icon);
ObjectTypeDB::bind_method(_MD("has_icon","name","type"),&Theme::has_icon);
ObjectTypeDB::bind_method(_MD("clear_icon","name","type"),&Theme::clear_icon);
- ObjectTypeDB::bind_method(_MD("get_icon_list"),&Theme::_get_icon_list);
+ ObjectTypeDB::bind_method(_MD("get_icon_list","type"),&Theme::_get_icon_list);
ObjectTypeDB::bind_method(_MD("set_stylebox","name","type","texture:StyleBox"),&Theme::set_stylebox);
ObjectTypeDB::bind_method(_MD("get_stylebox:StyleBox","name","type"),&Theme::get_stylebox);
ObjectTypeDB::bind_method(_MD("has_stylebox","name","type"),&Theme::has_stylebox);
ObjectTypeDB::bind_method(_MD("clear_stylebox","name","type"),&Theme::clear_stylebox);
- ObjectTypeDB::bind_method(_MD("get_stylebox_list"),&Theme::_get_stylebox_list);
+ ObjectTypeDB::bind_method(_MD("get_stylebox_list","type"),&Theme::_get_stylebox_list);
ObjectTypeDB::bind_method(_MD("set_font","name","type","font:Font"),&Theme::set_font);
ObjectTypeDB::bind_method(_MD("get_font:Font","name","type"),&Theme::get_font);
ObjectTypeDB::bind_method(_MD("has_font","name","type"),&Theme::has_font);
ObjectTypeDB::bind_method(_MD("clear_font","name","type"),&Theme::clear_font);
- ObjectTypeDB::bind_method(_MD("get_font_list"),&Theme::_get_font_list);
+ ObjectTypeDB::bind_method(_MD("get_font_list","type"),&Theme::_get_font_list);
ObjectTypeDB::bind_method(_MD("set_color","name","type","color"),&Theme::set_color);
ObjectTypeDB::bind_method(_MD("get_color","name","type"),&Theme::get_color);
ObjectTypeDB::bind_method(_MD("has_color","name","type"),&Theme::has_color);
ObjectTypeDB::bind_method(_MD("clear_color","name","type"),&Theme::clear_color);
- ObjectTypeDB::bind_method(_MD("get_color_list"),&Theme::_get_color_list);
+ ObjectTypeDB::bind_method(_MD("get_color_list","type"),&Theme::_get_color_list);
ObjectTypeDB::bind_method(_MD("set_constant","name","type","constant"),&Theme::set_constant);
ObjectTypeDB::bind_method(_MD("get_constant","name","type"),&Theme::get_constant);
ObjectTypeDB::bind_method(_MD("has_constant","name","type"),&Theme::has_constant);
ObjectTypeDB::bind_method(_MD("clear_constant","name","type"),&Theme::clear_constant);
- ObjectTypeDB::bind_method(_MD("get_constant_list"),&Theme::_get_constant_list);
+ ObjectTypeDB::bind_method(_MD("get_constant_list","type"),&Theme::_get_constant_list);
ObjectTypeDB::bind_method(_MD("set_default_font","font"),&Theme::set_default_theme_font);
ObjectTypeDB::bind_method(_MD("get_default_font"),&Theme::get_default_theme_font);
- ObjectTypeDB::bind_method(_MD("get_type_list"),&Theme::_get_type_list);
+ ObjectTypeDB::bind_method(_MD("get_type_list","type"),&Theme::_get_type_list);
ObjectTypeDB::bind_method("copy_default_theme",&Theme::copy_default_theme);
@@ -601,7 +646,9 @@ Theme::~Theme()
-RES ResourceFormatLoaderTheme::load(const String &p_path,const String& p_original_path) {
+RES ResourceFormatLoaderTheme::load(const String &p_path, const String& p_original_path, Error *r_error) {
+ if (r_error)
+ *r_error=ERR_CANT_OPEN;
Error err;
FileAccess *f = FileAccess::open(p_path,FileAccess::READ,&err);
@@ -611,6 +658,8 @@ RES ResourceFormatLoaderTheme::load(const String &p_path,const String& p_origina
String base_path = p_path.get_base_dir();
Ref<Theme> theme( memnew( Theme ) );
Map<StringName,Variant> library;
+ if (r_error)
+ *r_error=ERR_FILE_CORRUPT;
bool reading_library=false;
int line=0;
@@ -1003,6 +1052,9 @@ RES ResourceFormatLoaderTheme::load(const String &p_path,const String& p_origina
f->close();
memdelete(f);
+ if (r_error)
+ *r_error=OK;
+
return theme;
}
diff --git a/scene/resources/theme.h b/scene/resources/theme.h
index 802dcb099c..180f55381d 100644
--- a/scene/resources/theme.h
+++ b/scene/resources/theme.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,6 +33,7 @@
#include "scene/resources/font.h"
#include "scene/resources/style_box.h"
#include "scene/resources/texture.h"
+#include "scene/resources/shader.h"
#include "io/resource_loader.h"
/**
@@ -48,6 +49,7 @@ class Theme : public Resource {
HashMap<StringName,HashMap<StringName,Ref<Texture>,StringNameHasher >, StringNameHasher > icon_map;
HashMap<StringName,HashMap<StringName,Ref<StyleBox>,StringNameHasher >,StringNameHasher > style_map;
HashMap<StringName,HashMap<StringName,Ref<Font>,StringNameHasher >,StringNameHasher > font_map;
+ HashMap<StringName,HashMap<StringName,Ref<Shader>,StringNameHasher >, StringNameHasher > shader_map;
HashMap<StringName,HashMap<StringName,Color,StringNameHasher >,StringNameHasher > color_map;
HashMap<StringName,HashMap<StringName,int,StringNameHasher>,StringNameHasher > constant_map;
protected:
@@ -86,7 +88,13 @@ public:
bool has_icon(const StringName& p_name,const StringName& p_type) const;
void clear_icon(const StringName& p_name,const StringName& p_type);
void get_icon_list(StringName p_type, List<StringName> *p_list) const;
-
+
+ void set_shader(const StringName& p_name,const StringName& p_type,const Ref<Shader>& p_shader);
+ Ref<Shader> get_shader(const StringName& p_name,const StringName& p_type) const;
+ bool has_shader(const StringName& p_name,const StringName& p_type) const;
+ void clear_shader(const StringName& p_name,const StringName& p_type);
+ void get_shader_list(const StringName& p_name, List<StringName> *p_list) const;
+
void set_stylebox(const StringName& p_name,const StringName& p_type,const Ref<StyleBox>& p_style);
Ref<StyleBox> get_stylebox(const StringName& p_name,const StringName& p_type) const;
bool has_stylebox(const StringName& p_name,const StringName& p_type) const;
@@ -124,7 +132,7 @@ public:
class ResourceFormatLoaderTheme : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path,const String& p_original_path="");
+ virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String& p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index 28e179b34c..6f71287750 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index 96048bf06b..fb0e832c1e 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/video_stream.cpp b/scene/resources/video_stream.cpp
index b27413bb68..8e16f2e024 100644
--- a/scene/resources/video_stream.cpp
+++ b/scene/resources/video_stream.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -28,16 +28,12 @@
/*************************************************************************/
#include "video_stream.h"
-void VideoStream::_bind_methods() {
+void VideoStreamPlayback::_bind_methods() {
- ObjectTypeDB::bind_method(_MD("get_pending_frame_count"),&VideoStream::get_pending_frame_count);
- ObjectTypeDB::bind_method(_MD("pop_frame"),&VideoStream::pop_frame);
- ObjectTypeDB::bind_method(_MD("peek_frame"),&VideoStream::peek_frame);
- ObjectTypeDB::bind_method(_MD("set_audio_track","idx"),&VideoStream::set_audio_track);
};
-VideoStream::VideoStream() {
+VideoStreamPlayback::VideoStreamPlayback() {
};
diff --git a/scene/resources/video_stream.h b/scene/resources/video_stream.h
index 2ad7457ec4..b05a7cf773 100644
--- a/scene/resources/video_stream.h
+++ b/scene/resources/video_stream.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,15 +33,17 @@
#include "scene/resources/texture.h"
-class VideoStream : public Resource {
+class VideoStreamPlayback : public Resource {
- OBJ_TYPE(VideoStream,Resource);
+ OBJ_TYPE(VideoStreamPlayback,Resource);
protected:
static void _bind_methods();
public:
+ typedef int (*AudioMixCallback)(void* p_udata,const int16_t *p_data,int p_frames);
+
virtual void stop()=0;
virtual void play()=0;
@@ -58,16 +60,34 @@ public:
virtual float get_pos() const=0;
virtual void seek_pos(float p_time)=0;
- virtual int get_pending_frame_count() const=0;
- virtual void pop_frame(Ref<ImageTexture> p_tex)=0;
- virtual Image peek_frame() const=0;
-
virtual void set_audio_track(int p_idx) =0;
- virtual void update(float p_time)=0;
+ //virtual int mix(int16_t* p_bufer,int p_frames)=0;
+
+ virtual Ref<Texture> get_texture()=0;
+ virtual void update(float p_delta)=0;
- VideoStream();
+ virtual void set_mix_callback(AudioMixCallback p_callback,void *p_userdata)=0;
+ virtual int get_channels() const=0;
+ virtual int get_mix_rate() const=0;
+
+ VideoStreamPlayback();
};
+
+class VideoStream : public Resource {
+
+ OBJ_TYPE( VideoStream, Resource );
+ OBJ_SAVE_TYPE( VideoStream ); //children are all saved as AudioStream, so they can be exchanged
+
+public:
+
+ virtual void set_audio_track(int p_track)=0;
+ virtual Ref<VideoStreamPlayback> instance_playback()=0;
+
+ VideoStream() {}
+};
+
+
#endif
diff --git a/scene/resources/volume.cpp b/scene/resources/volume.cpp
index a668a39c4f..8eb96cb4ad 100644
--- a/scene/resources/volume.cpp
+++ b/scene/resources/volume.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/volume.h b/scene/resources/volume.h
index f929792b74..be3cbddbbd 100644
--- a/scene/resources/volume.h
+++ b/scene/resources/volume.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/world.cpp b/scene/resources/world.cpp
index fb3469102c..0a88abf252 100644
--- a/scene/resources/world.cpp
+++ b/scene/resources/world.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/world.h b/scene/resources/world.h
index 165122124d..5a74f27235 100644
--- a/scene/resources/world.h
+++ b/scene/resources/world.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp
index d8d9c5b675..8cacc0fce7 100644
--- a/scene/resources/world_2d.cpp
+++ b/scene/resources/world_2d.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -374,7 +374,7 @@ World2D::World2D() {
Physics2DServer::get_singleton()->area_set_param(space,Physics2DServer::AREA_PARAM_GRAVITY,GLOBAL_DEF("physics_2d/default_gravity",98));
Physics2DServer::get_singleton()->area_set_param(space,Physics2DServer::AREA_PARAM_GRAVITY_VECTOR,GLOBAL_DEF("physics_2d/default_gravity_vector",Vector2(0,1)));
Physics2DServer::get_singleton()->area_set_param(space,Physics2DServer::AREA_PARAM_LINEAR_DAMP,GLOBAL_DEF("physics_2d/default_density",0.1));
- Physics2DServer::get_singleton()->area_set_param(space,Physics2DServer::AREA_PARAM_ANGULAR_DAMP,GLOBAL_DEF("physics_2d/default_density",1));
+ Physics2DServer::get_singleton()->area_set_param(space,Physics2DServer::AREA_PARAM_ANGULAR_DAMP,GLOBAL_DEF("physics_2d/default_angular_damp",1));
Physics2DServer::get_singleton()->space_set_param(space,Physics2DServer::SPACE_PARAM_CONTACT_RECYCLE_RADIUS,1.0);
Physics2DServer::get_singleton()->space_set_param(space,Physics2DServer::SPACE_PARAM_CONTACT_MAX_SEPARATION,1.5);
Physics2DServer::get_singleton()->space_set_param(space,Physics2DServer::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION,0.3);
diff --git a/scene/resources/world_2d.h b/scene/resources/world_2d.h
index a3a79dee09..a939d935c4 100644
--- a/scene/resources/world_2d.h
+++ b/scene/resources/world_2d.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp
index 2689c14718..57bde00de4 100644
--- a/scene/scene_string_names.cpp
+++ b/scene/scene_string_names.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -68,6 +68,8 @@ SceneStringNames::SceneStringNames() {
area_enter_shape = StaticCString::create("area_enter_shape");
area_exit_shape = StaticCString::create("area_exit_shape");
+ _body_inout = StaticCString::create("_body_inout");
+ _area_inout = StaticCString::create("_area_inout");
idle=StaticCString::create("idle");
iteration=StaticCString::create("iteration");
@@ -161,4 +163,11 @@ SceneStringNames::SceneStringNames() {
frame_changed=StaticCString::create("frame_changed");
+ playback_speed=StaticCString::create("playback/speed");
+ playback_active=StaticCString::create("playback/active");
+ autoplay=StaticCString::create("autoplay");
+ blend_times=StaticCString::create("blend_times");
+ speed=StaticCString::create("speed");
+
+ path_pp=NodePath("..");
}
diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h
index 83e817dbf7..b2c0e9abf0 100644
--- a/scene/scene_string_names.h
+++ b/scene/scene_string_names.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,7 +30,7 @@
#define SCENE_STRING_NAMES_H
#include "string_db.h"
-
+#include "path_db.h"
class SceneStringNames {
friend void register_scene_types();
@@ -87,6 +87,8 @@ public:
StringName area_enter_shape;
StringName area_exit_shape;
+ StringName _body_inout;
+ StringName _area_inout;
StringName _get_gizmo_geometry;
@@ -170,6 +172,14 @@ public:
StringName frame_changed;
+ StringName playback_speed;
+ StringName playback_active;
+ StringName autoplay;
+ StringName blend_times;
+ StringName speed;
+
+ NodePath path_pp;
+
};
diff --git a/servers/SCsub b/servers/SCsub
index 3871c30cfa..d861847101 100644
--- a/servers/SCsub
+++ b/servers/SCsub
@@ -15,5 +15,3 @@ SConscript('spatial_sound_2d/SCsub');
lib = env.Library("servers",env.servers_sources)
env.Prepend(LIBS=[lib])
-
-
diff --git a/servers/audio/SCsub b/servers/audio/SCsub
index 16fe3a59ac..d31af2c1c4 100644
--- a/servers/audio/SCsub
+++ b/servers/audio/SCsub
@@ -3,5 +3,3 @@ Import('env')
env.add_source_files(env.servers_sources,"*.cpp")
Export('env')
-
-
diff --git a/servers/audio/audio_driver_dummy.cpp b/servers/audio/audio_driver_dummy.cpp
index dd5243e467..d0695451b9 100644
--- a/servers/audio/audio_driver_dummy.cpp
+++ b/servers/audio/audio_driver_dummy.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/audio/audio_driver_dummy.h b/servers/audio/audio_driver_dummy.h
index 04926b89eb..9421574f93 100644
--- a/servers/audio/audio_driver_dummy.h
+++ b/servers/audio/audio_driver_dummy.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/audio/audio_filter_sw.cpp b/servers/audio/audio_filter_sw.cpp
index 032d93b617..3fb8e8f734 100644
--- a/servers/audio/audio_filter_sw.cpp
+++ b/servers/audio/audio_filter_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/audio/audio_filter_sw.h b/servers/audio/audio_filter_sw.h
index e8540adea6..d4d225ce29 100644
--- a/servers/audio/audio_filter_sw.h
+++ b/servers/audio/audio_filter_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/audio/audio_mixer_sw.cpp b/servers/audio/audio_mixer_sw.cpp
index 788eec0d4a..d1f36cb7b6 100644
--- a/servers/audio/audio_mixer_sw.cpp
+++ b/servers/audio/audio_mixer_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -45,14 +45,14 @@ void AudioMixerSW::do_resample(const Depth* p_src, int32_t *p_dst, ResamplerStat
while (p_state->amount--) {
int32_t pos=p_state->pos >> MIX_FRAC_BITS;
- if (is_stereo)
+ if (is_stereo && !is_ima_adpcm)
pos<<=1;
if (is_ima_adpcm) {
- int sample_pos = pos + p_state->ima_adpcm->window_ofs;
+ int sample_pos = pos + p_state->ima_adpcm[0].window_ofs;
- while(sample_pos>p_state->ima_adpcm->last_nibble) {
+ while(sample_pos>p_state->ima_adpcm[0].last_nibble) {
static const int16_t _ima_adpcm_step_table[89] = {
@@ -72,52 +72,64 @@ void AudioMixerSW::do_resample(const Depth* p_src, int32_t *p_dst, ResamplerStat
-1, -1, -1, -1, 2, 4, 6, 8
};
- int16_t nibble,signed_nibble,diff,step;
+ for(int i=0;i<(is_stereo?2:1);i++) {
- p_state->ima_adpcm->last_nibble++;
- const uint8_t *src_ptr=p_state->ima_adpcm->ptr;
- nibble = (p_state->ima_adpcm->last_nibble&1)?
- (src_ptr[p_state->ima_adpcm->last_nibble>>1]>>4):(src_ptr[p_state->ima_adpcm->last_nibble>>1]&0xF);
- step=_ima_adpcm_step_table[p_state->ima_adpcm->step_index];
+ int16_t nibble,signed_nibble,diff,step;
- p_state->ima_adpcm->step_index += _ima_adpcm_index_table[nibble];
- if (p_state->ima_adpcm->step_index<0)
- p_state->ima_adpcm->step_index=0;
- if (p_state->ima_adpcm->step_index>88)
- p_state->ima_adpcm->step_index=88;
+ p_state->ima_adpcm[i].last_nibble++;
+ const uint8_t *src_ptr=p_state->ima_adpcm[i].ptr;
- /*
- signed_nibble = (nibble&7) * ((nibble&8)?-1:1);
- diff = (2 * signed_nibble + 1) * step / 4; */
- diff = step >> 3 ;
- if (nibble & 1)
- diff += step >> 2 ;
- if (nibble & 2)
- diff += step >> 1 ;
- if (nibble & 4)
- diff += step ;
- if (nibble & 8)
- diff = -diff ;
+ uint8_t nbb = src_ptr[ (p_state->ima_adpcm[i].last_nibble>>1) * (is_stereo?2:1) + i ];
+ nibble = (p_state->ima_adpcm[i].last_nibble&1)?(nbb>>4):(nbb&0xF);
+ step=_ima_adpcm_step_table[p_state->ima_adpcm[i].step_index];
- p_state->ima_adpcm->predictor+=diff;
- if (p_state->ima_adpcm->predictor<-0x8000)
- p_state->ima_adpcm->predictor=-0x8000;
- else if (p_state->ima_adpcm->predictor>0x7FFF)
- p_state->ima_adpcm->predictor=0x7FFF;
+ p_state->ima_adpcm[i].step_index += _ima_adpcm_index_table[nibble];
+ if (p_state->ima_adpcm[i].step_index<0)
+ p_state->ima_adpcm[i].step_index=0;
+ if (p_state->ima_adpcm[i].step_index>88)
+ p_state->ima_adpcm[i].step_index=88;
- /* store loop if there */
- if (p_state->ima_adpcm->last_nibble==p_state->ima_adpcm->loop_pos) {
+ /*
+ signed_nibble = (nibble&7) * ((nibble&8)?-1:1);
+ diff = (2 * signed_nibble + 1) * step / 4; */
+
+ diff = step >> 3 ;
+ if (nibble & 1)
+ diff += step >> 2 ;
+ if (nibble & 2)
+ diff += step >> 1 ;
+ if (nibble & 4)
+ diff += step ;
+ if (nibble & 8)
+ diff = -diff ;
+
+ p_state->ima_adpcm[i].predictor+=diff;
+ if (p_state->ima_adpcm[i].predictor<-0x8000)
+ p_state->ima_adpcm[i].predictor=-0x8000;
+ else if (p_state->ima_adpcm[i].predictor>0x7FFF)
+ p_state->ima_adpcm[i].predictor=0x7FFF;
+
+
+ /* store loop if there */
+ if (p_state->ima_adpcm[i].last_nibble==p_state->ima_adpcm[i].loop_pos) {
+
+ p_state->ima_adpcm[i].loop_step_index = p_state->ima_adpcm[i].step_index;
+ p_state->ima_adpcm[i].loop_predictor = p_state->ima_adpcm[i].predictor;
+ }
+
+ //printf("%i - %i - pred %i\n",int(p_state->ima_adpcm[i].last_nibble),int(nibble),int(p_state->ima_adpcm[i].predictor));
- p_state->ima_adpcm->loop_step_index = p_state->ima_adpcm->step_index;
- p_state->ima_adpcm->loop_predictor = p_state->ima_adpcm->predictor;
}
}
- final=p_state->ima_adpcm->predictor;
+ final=p_state->ima_adpcm[0].predictor;
+ if (is_stereo) {
+ final_r=p_state->ima_adpcm[1].predictor;
+ }
} else {
final=p_src[pos];
@@ -399,9 +411,10 @@ void AudioMixerSW::mix_channel(Channel& c) {
if (format==AS::SAMPLE_FORMAT_IMA_ADPCM) {
- rstate.ima_adpcm=&c.mix.ima_adpcm;
+ rstate.ima_adpcm=c.mix.ima_adpcm;
if (loop_format!=AS::SAMPLE_LOOP_NONE) {
- c.mix.ima_adpcm.loop_pos=loop_begin_fp>>MIX_FRAC_BITS;
+ c.mix.ima_adpcm[0].loop_pos=loop_begin_fp>>MIX_FRAC_BITS;
+ c.mix.ima_adpcm[1].loop_pos=loop_begin_fp>>MIX_FRAC_BITS;
loop_format=AS::SAMPLE_LOOP_FORWARD;
}
}
@@ -447,9 +460,11 @@ void AudioMixerSW::mix_channel(Channel& c) {
/* go to loop-begin */
if (format==AS::SAMPLE_FORMAT_IMA_ADPCM) {
- c.mix.ima_adpcm.step_index=c.mix.ima_adpcm.loop_step_index;
- c.mix.ima_adpcm.predictor=c.mix.ima_adpcm.loop_predictor;
- c.mix.ima_adpcm.last_nibble=loop_begin_fp>>MIX_FRAC_BITS;
+ for(int i=0;i<2;i++) {
+ c.mix.ima_adpcm[i].step_index=c.mix.ima_adpcm[i].loop_step_index;
+ c.mix.ima_adpcm[i].predictor=c.mix.ima_adpcm[i].loop_predictor;
+ c.mix.ima_adpcm[i].last_nibble=loop_begin_fp>>MIX_FRAC_BITS;
+ }
c.mix.offset=loop_begin_fp;
} else {
c.mix.offset=loop_begin_fp+(c.mix.offset-loop_end_fp);
@@ -549,10 +564,12 @@ void AudioMixerSW::mix_channel(Channel& c) {
CALL_RESAMPLE_MODE(int16_t,is_stereo,false,use_filter,use_fx,interpolation_type,mix_channels);
} else if (format==AS::SAMPLE_FORMAT_IMA_ADPCM) {
- c.mix.ima_adpcm.window_ofs=c.mix.offset>>MIX_FRAC_BITS;
- c.mix.ima_adpcm.ptr=(const uint8_t*)data;
- int8_t *src_ptr = &((int8_t*)data)[(c.mix.offset >> MIX_FRAC_BITS)<<(is_stereo?1:0) ];
- CALL_RESAMPLE_MODE(int8_t,false,true,use_filter,use_fx,interpolation_type,mix_channels);
+ for(int i=0;i<2;i++) {
+ c.mix.ima_adpcm[i].window_ofs=c.mix.offset>>MIX_FRAC_BITS;
+ c.mix.ima_adpcm[i].ptr=(const uint8_t*)data;
+ }
+ int8_t *src_ptr = NULL;
+ CALL_RESAMPLE_MODE(int8_t,is_stereo,true,use_filter,use_fx,interpolation_type,mix_channels);
}
@@ -765,6 +782,10 @@ AudioMixer::ChannelID AudioMixerSW::channel_alloc(RID p_sample) {
c.mix.increment=1;
//zero everything when this errors
for(int i=0;i<4;i++) {
+ c.mix.vol[i]=0;
+ c.mix.reverb_vol[i]=0;
+ c.mix.chorus_vol[i]=0;
+
c.mix.old_vol[i]=0;
c.mix.old_reverb_vol[i]=0;
c.mix.old_chorus_vol[i]=0;
@@ -777,14 +798,16 @@ AudioMixer::ChannelID AudioMixerSW::channel_alloc(RID p_sample) {
if (sample_manager->sample_get_format(c.sample)==AudioServer::SAMPLE_FORMAT_IMA_ADPCM) {
- c.mix.ima_adpcm.step_index=0;
- c.mix.ima_adpcm.predictor=0;
- c.mix.ima_adpcm.loop_step_index=0;
- c.mix.ima_adpcm.loop_predictor=0;
- c.mix.ima_adpcm.last_nibble=-1;
- c.mix.ima_adpcm.loop_pos=0x7FFFFFFF;
- c.mix.ima_adpcm.window_ofs=0;
- c.mix.ima_adpcm.ptr=NULL;
+ for(int i=0;i<2;i++) {
+ c.mix.ima_adpcm[i].step_index=0;
+ c.mix.ima_adpcm[i].predictor=0;
+ c.mix.ima_adpcm[i].loop_step_index=0;
+ c.mix.ima_adpcm[i].loop_predictor=0;
+ c.mix.ima_adpcm[i].last_nibble=-1;
+ c.mix.ima_adpcm[i].loop_pos=0x7FFFFFFF;
+ c.mix.ima_adpcm[i].window_ofs=0;
+ c.mix.ima_adpcm[i].ptr=NULL;
+ }
}
ChannelID ret_id = index+c.check*MAX_CHANNELS;
diff --git a/servers/audio/audio_mixer_sw.h b/servers/audio/audio_mixer_sw.h
index cb38561c27..f5bd4cc5ba 100644
--- a/servers/audio/audio_mixer_sw.h
+++ b/servers/audio/audio_mixer_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -105,7 +105,7 @@ private:
int32_t loop_pos;
int32_t window_ofs;
const uint8_t *ptr;
- } ima_adpcm;
+ } ima_adpcm[2];
} mix;
diff --git a/servers/audio/audio_rb_resampler.cpp b/servers/audio/audio_rb_resampler.cpp
new file mode 100644
index 0000000000..d07d55f1b5
--- /dev/null
+++ b/servers/audio/audio_rb_resampler.cpp
@@ -0,0 +1,356 @@
+#include "audio_rb_resampler.h"
+
+
+int AudioRBResampler::get_channel_count() const {
+
+ if (!rb)
+ return 0;
+
+ return channels;
+}
+
+
+template<int C>
+uint32_t AudioRBResampler::_resample(int32_t *p_dest,int p_todo,int32_t p_increment) {
+
+ uint32_t read=offset&MIX_FRAC_MASK;
+
+ for (int i=0;i<p_todo;i++) {
+
+ offset = (offset + p_increment)&(((1<<(rb_bits+MIX_FRAC_BITS))-1));
+ read+=p_increment;
+ uint32_t pos = offset >> MIX_FRAC_BITS;
+ uint32_t frac = offset & MIX_FRAC_MASK;
+#ifndef FAST_AUDIO
+ ERR_FAIL_COND_V(pos>=rb_len,0);
+#endif
+ uint32_t pos_next = (pos+1)&rb_mask;
+ //printf("rb pos %i\n",pos);
+
+ // since this is a template with a known compile time value (C), conditionals go away when compiling.
+ if (C==1) {
+
+ int32_t v0 = rb[pos];
+ int32_t v0n=rb[pos_next];
+#ifndef FAST_AUDIO
+ v0+=(v0n-v0)*(int32_t)frac >> MIX_FRAC_BITS;
+#endif
+ v0<<=16;
+ p_dest[i]=v0;
+
+ }
+ if (C==2) {
+
+ int32_t v0 = rb[(pos<<1)+0];
+ int32_t v1 = rb[(pos<<1)+1];
+ int32_t v0n=rb[(pos_next<<1)+0];
+ int32_t v1n=rb[(pos_next<<1)+1];
+
+#ifndef FAST_AUDIO
+ v0+=(v0n-v0)*(int32_t)frac >> MIX_FRAC_BITS;
+ v1+=(v1n-v1)*(int32_t)frac >> MIX_FRAC_BITS;
+#endif
+ v0<<=16;
+ v1<<=16;
+ p_dest[(i<<1)+0]=v0;
+ p_dest[(i<<1)+1]=v1;
+
+ }
+
+ if (C==4) {
+
+ int32_t v0 = rb[(pos<<2)+0];
+ int32_t v1 = rb[(pos<<2)+1];
+ int32_t v2 = rb[(pos<<2)+2];
+ int32_t v3 = rb[(pos<<2)+3];
+ int32_t v0n = rb[(pos_next<<2)+0];
+ int32_t v1n=rb[(pos_next<<2)+1];
+ int32_t v2n=rb[(pos_next<<2)+2];
+ int32_t v3n=rb[(pos_next<<2)+3];
+
+#ifndef FAST_AUDIO
+ v0+=(v0n-v0)*(int32_t)frac >> MIX_FRAC_BITS;
+ v1+=(v1n-v1)*(int32_t)frac >> MIX_FRAC_BITS;
+ v2+=(v2n-v2)*(int32_t)frac >> MIX_FRAC_BITS;
+ v3+=(v3n-v3)*(int32_t)frac >> MIX_FRAC_BITS;
+#endif
+ v0<<=16;
+ v1<<=16;
+ v2<<=16;
+ v3<<=16;
+ p_dest[(i<<2)+0]=v0;
+ p_dest[(i<<2)+1]=v1;
+ p_dest[(i<<2)+2]=v2;
+ p_dest[(i<<2)+3]=v3;
+
+ }
+
+ if (C==6) {
+
+ int32_t v0 = rb[(pos*6)+0];
+ int32_t v1 = rb[(pos*6)+1];
+ int32_t v2 = rb[(pos*6)+2];
+ int32_t v3 = rb[(pos*6)+3];
+ int32_t v4 = rb[(pos*6)+4];
+ int32_t v5 = rb[(pos*6)+5];
+ int32_t v0n = rb[(pos_next*6)+0];
+ int32_t v1n=rb[(pos_next*6)+1];
+ int32_t v2n=rb[(pos_next*6)+2];
+ int32_t v3n=rb[(pos_next*6)+3];
+ int32_t v4n=rb[(pos_next*6)+4];
+ int32_t v5n=rb[(pos_next*6)+5];
+
+#ifndef FAST_AUDIO
+ v0+=(v0n-v0)*(int32_t)frac >> MIX_FRAC_BITS;
+ v1+=(v1n-v1)*(int32_t)frac >> MIX_FRAC_BITS;
+ v2+=(v2n-v2)*(int32_t)frac >> MIX_FRAC_BITS;
+ v3+=(v3n-v3)*(int32_t)frac >> MIX_FRAC_BITS;
+ v4+=(v4n-v4)*(int32_t)frac >> MIX_FRAC_BITS;
+ v5+=(v5n-v5)*(int32_t)frac >> MIX_FRAC_BITS;
+#endif
+ v0<<=16;
+ v1<<=16;
+ v2<<=16;
+ v3<<=16;
+ v4<<=16;
+ v5<<=16;
+ p_dest[(i*6)+0]=v0;
+ p_dest[(i*6)+1]=v1;
+ p_dest[(i*6)+2]=v2;
+ p_dest[(i*6)+3]=v3;
+ p_dest[(i*6)+4]=v4;
+ p_dest[(i*6)+5]=v5;
+
+ }
+
+
+ }
+
+
+ return read>>MIX_FRAC_BITS;//rb_read_pos=offset>>MIX_FRAC_BITS;
+
+}
+
+
+bool AudioRBResampler::mix(int32_t *p_dest, int p_frames) {
+
+
+ if (!rb)
+ return false;
+
+ int write_pos_cache=rb_write_pos;
+
+ int32_t increment=(src_mix_rate*MIX_FRAC_LEN)/target_mix_rate;
+
+ int rb_todo;
+
+ if (write_pos_cache==rb_read_pos) {
+ return false; //out of buffer
+
+ } else if (rb_read_pos<write_pos_cache) {
+
+ rb_todo=write_pos_cache-rb_read_pos; //-1?
+ } else {
+
+ rb_todo=(rb_len-rb_read_pos)+write_pos_cache; //-1?
+ }
+
+ int todo = MIN( ((int64_t(rb_todo)<<MIX_FRAC_BITS)/increment)+1, p_frames );
+#if 0
+ if (int(src_mix_rate)==target_mix_rate) {
+
+
+ if (channels==6) {
+
+ for(int i=0;i<p_frames;i++) {
+
+ int from = ((rb_read_pos+i)&rb_mask)*6;
+ int to = i*6;
+
+ p_dest[from+0]=int32_t(rb[to+0])<<16;
+ p_dest[from+1]=int32_t(rb[to+1])<<16;
+ p_dest[from+2]=int32_t(rb[to+2])<<16;
+ p_dest[from+3]=int32_t(rb[to+3])<<16;
+ p_dest[from+4]=int32_t(rb[to+4])<<16;
+ p_dest[from+5]=int32_t(rb[to+5])<<16;
+ }
+
+ } else {
+ int len=p_frames*channels;
+ int from=rb_read_pos*channels;
+ int mask=0;
+ switch(channels) {
+ case 1: mask=rb_len-1; break;
+ case 2: mask=(rb_len*2)-1; break;
+ case 4: mask=(rb_len*4)-1; break;
+ }
+
+ for(int i=0;i<len;i++) {
+
+ p_dest[i]=int32_t(rb[(from+i)&mask])<<16;
+ }
+ }
+
+ rb_read_pos = (rb_read_pos+p_frames)&rb_mask;
+ } else
+#endif
+ {
+
+ uint32_t read=0;
+ switch(channels) {
+ case 1: read=_resample<1>(p_dest,todo,increment); break;
+ case 2: read=_resample<2>(p_dest,todo,increment); break;
+ case 4: read=_resample<4>(p_dest,todo,increment); break;
+ case 6: read=_resample<6>(p_dest,todo,increment); break;
+ }
+#if 1
+ //end of stream, fadeout
+ int remaining = p_frames-todo;
+ if (remaining && todo>0) {
+
+ //print_line("fadeout");
+ for(int c=0;c<channels;c++) {
+
+ for(int i=0;i<todo;i++) {
+
+ int32_t samp = p_dest[i*channels+c]>>8;
+ uint32_t mul = (todo-i) * 256 /todo;
+ //print_line("mul: "+itos(i)+" "+itos(mul));
+ p_dest[i*channels+c]=samp*mul;
+ }
+
+ }
+
+ }
+
+#else
+ int remaining = p_frames-todo;
+ if (remaining && todo>0) {
+
+
+ for(int c=0;c<channels;c++) {
+
+ int32_t from = p_dest[(todo-1)*channels+c]>>8;
+
+ for(int i=0;i<remaining;i++) {
+
+ uint32_t mul = (remaining-i) * 256 /remaining;
+ p_dest[(todo+i)*channels+c]=from*mul;
+ }
+
+ }
+
+ }
+#endif
+
+ //zero out what remains there to avoid glitches
+ for(int i=todo*channels;i<int(p_frames)*channels;i++) {
+
+ p_dest[i]=0;
+ }
+
+ if (read>rb_todo)
+ read=rb_todo;
+
+ rb_read_pos = (rb_read_pos+read)&rb_mask;
+
+
+
+
+ }
+
+ return true;
+}
+
+
+Error AudioRBResampler::setup(int p_channels,int p_src_mix_rate,int p_target_mix_rate,int p_buffer_msec,int p_minbuff_needed) {
+
+ ERR_FAIL_COND_V(p_channels!=1 && p_channels!=2 && p_channels!=4 && p_channels!=6,ERR_INVALID_PARAMETER);
+
+
+ //float buffering_sec = int(GLOBAL_DEF("audio/stream_buffering_ms",500))/1000.0;
+ int desired_rb_bits =nearest_shift(MAX((p_buffer_msec/1000.0)*p_src_mix_rate,p_minbuff_needed));
+
+ bool recreate=!rb;
+
+ if (rb && (uint32_t(desired_rb_bits)!=rb_bits || channels!=uint32_t(p_channels))) {
+ //recreate
+
+ memdelete_arr(rb);
+ memdelete_arr(read_buf);
+ recreate=true;
+
+ }
+
+ if (recreate) {
+
+ channels=p_channels;
+ rb_bits=desired_rb_bits;
+ rb_len=(1<<rb_bits);
+ rb_mask=rb_len-1;
+ rb = memnew_arr( int16_t, rb_len * p_channels );
+ read_buf = memnew_arr( int16_t, rb_len * p_channels );
+
+ }
+
+ src_mix_rate=p_src_mix_rate;
+ target_mix_rate=p_target_mix_rate;
+ offset=0;
+ rb_read_pos=0;
+ rb_write_pos=0;
+
+ //avoid maybe strange noises upon load
+ for (int i=0;i<(rb_len*channels);i++) {
+
+ rb[i]=0;
+ read_buf[i]=0;
+ }
+
+ return OK;
+
+}
+
+void AudioRBResampler::clear() {
+
+ if (!rb)
+ return;
+
+ //should be stopped at this point but just in case
+ if (rb) {
+ memdelete_arr(rb);
+ memdelete_arr(read_buf);
+ }
+ rb=NULL;
+ offset=0;
+ rb_read_pos=0;
+ rb_write_pos=0;
+ read_buf=NULL;
+}
+
+AudioRBResampler::AudioRBResampler() {
+
+ rb=NULL;
+ offset=0;
+ read_buf=NULL;
+ rb_read_pos=0;
+ rb_write_pos=0;
+
+ rb_bits=0;
+ rb_len=0;
+ rb_mask=0;
+ read_buff_len=0;
+ channels=0;
+ src_mix_rate=0;
+ target_mix_rate=0;
+
+}
+
+AudioRBResampler::~AudioRBResampler() {
+
+ if (rb) {
+ memdelete_arr(rb);
+ memdelete_arr(read_buf);
+ }
+
+}
+
diff --git a/servers/audio/audio_rb_resampler.h b/servers/audio/audio_rb_resampler.h
new file mode 100644
index 0000000000..3c08c79797
--- /dev/null
+++ b/servers/audio/audio_rb_resampler.h
@@ -0,0 +1,138 @@
+#ifndef AUDIO_RB_RESAMPLER_H
+#define AUDIO_RB_RESAMPLER_H
+
+#include "typedefs.h"
+#include "os/memory.h"
+
+struct AudioRBResampler {
+
+ uint32_t rb_bits;
+ uint32_t rb_len;
+ uint32_t rb_mask;
+ uint32_t read_buff_len;
+ uint32_t channels;
+ uint32_t src_mix_rate;
+ uint32_t target_mix_rate;
+
+ volatile int rb_read_pos;
+ volatile int rb_write_pos;
+
+ int32_t offset; //contains the fractional remainder of the resampler
+ enum {
+ MIX_FRAC_BITS=13,
+ MIX_FRAC_LEN=(1<<MIX_FRAC_BITS),
+ MIX_FRAC_MASK=MIX_FRAC_LEN-1,
+ };
+
+ int16_t *read_buf;
+ int16_t *rb;
+
+
+ template<int C>
+ uint32_t _resample(int32_t *p_dest,int p_todo,int32_t p_increment);
+
+
+public:
+
+ _FORCE_INLINE_ void flush() {
+ rb_read_pos=0;
+ rb_write_pos=0;
+ }
+
+ _FORCE_INLINE_ bool is_ready() const{
+ return rb!=NULL;
+ }
+
+
+ _FORCE_INLINE_ int get_total() const {
+
+ return rb_len-1;
+ }
+
+ _FORCE_INLINE_ int get_todo() const { //return amount of frames to mix
+
+ int todo;
+ int read_pos_cache=rb_read_pos;
+
+ if (read_pos_cache==rb_write_pos) {
+ todo=rb_len-1;
+ } else if (read_pos_cache>rb_write_pos) {
+
+ todo=read_pos_cache-rb_write_pos-1;
+ } else {
+
+ todo=(rb_len-rb_write_pos)+read_pos_cache-1;
+ }
+
+ return todo;
+ }
+
+
+ _FORCE_INLINE_ bool has_data() const {
+ return rb && rb_read_pos!=rb_write_pos;
+ }
+
+ _FORCE_INLINE_ int16_t *get_write_buffer() { return read_buf; }
+ _FORCE_INLINE_ void write(uint32_t p_frames) {
+
+ ERR_FAIL_COND(p_frames >= rb_len);
+
+ switch(channels) {
+ case 1: {
+
+ for(uint32_t i=0;i<p_frames;i++) {
+
+ rb[ rb_write_pos ] = read_buf[i];
+ rb_write_pos=(rb_write_pos+1)&rb_mask;
+ }
+ } break;
+ case 2: {
+
+ for(uint32_t i=0;i<p_frames;i++) {
+
+ rb[ (rb_write_pos<<1)+0 ] = read_buf[(i<<1)+0];
+ rb[ (rb_write_pos<<1)+1 ] = read_buf[(i<<1)+1];
+ rb_write_pos=(rb_write_pos+1)&rb_mask;
+ }
+ } break;
+ case 4: {
+
+ for(uint32_t i=0;i<p_frames;i++) {
+
+ rb[ (rb_write_pos<<2)+0 ] = read_buf[(i<<2)+0];
+ rb[ (rb_write_pos<<2)+1 ] = read_buf[(i<<2)+1];
+ rb[ (rb_write_pos<<2)+2 ] = read_buf[(i<<2)+2];
+ rb[ (rb_write_pos<<2)+3 ] = read_buf[(i<<2)+3];
+ rb_write_pos=(rb_write_pos+1)&rb_mask;
+ }
+ } break;
+ case 6: {
+
+ for(uint32_t i=0;i<p_frames;i++) {
+
+ rb[ (rb_write_pos*6)+0 ] = read_buf[(i*6)+0];
+ rb[ (rb_write_pos*6)+1 ] = read_buf[(i*6)+1];
+ rb[ (rb_write_pos*6)+2 ] = read_buf[(i*6)+2];
+ rb[ (rb_write_pos*6)+3 ] = read_buf[(i*6)+3];
+ rb[ (rb_write_pos*6)+4 ] = read_buf[(i*6)+4];
+ rb[ (rb_write_pos*6)+5 ] = read_buf[(i*6)+5];
+ rb_write_pos=(rb_write_pos+1)&rb_mask;
+ }
+ } break;
+
+
+ }
+
+ }
+
+ int get_channel_count() const;
+
+ Error setup(int p_channels, int p_src_mix_rate, int p_target_mix_rate, int p_buffer_msec, int p_minbuff_needed=-1);
+ void clear();
+ bool mix(int32_t *p_dest, int p_frames);
+
+ AudioRBResampler();
+ ~AudioRBResampler();
+};
+
+#endif // AUDIO_RB_RESAMPLER_H
diff --git a/servers/audio/audio_server_sw.cpp b/servers/audio/audio_server_sw.cpp
index 8a3ab7ce70..d634c348dc 100644
--- a/servers/audio/audio_server_sw.cpp
+++ b/servers/audio/audio_server_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -360,7 +360,7 @@ void AudioServerSW::sample_set_description(RID p_sample, const String& p_descrip
AUDIO_LOCK
sample_manager->sample_set_description(p_sample,p_description);
}
-String AudioServerSW::sample_get_description(RID p_sample, const String& p_description) const {
+String AudioServerSW::sample_get_description(RID p_sample) const {
AUDIO_LOCK
return sample_manager->sample_get_description(p_sample);
@@ -455,12 +455,12 @@ void AudioServerSW::voice_play(RID p_voice, RID p_sample) {
}
-void AudioServerSW::voice_set_volume(RID p_voice, float p_db) {
+void AudioServerSW::voice_set_volume(RID p_voice, float p_volume) {
VoiceRBSW::Command cmd;
cmd.type=VoiceRBSW::Command::CMD_SET_VOLUME;
cmd.voice=p_voice;
- cmd.volume.volume=p_db;
+ cmd.volume.volume=p_volume;
voice_rb.push_command(cmd);
}
@@ -659,7 +659,7 @@ bool AudioServerSW::voice_is_active(RID p_voice) const {
RID AudioServerSW::audio_stream_create(AudioStream *p_stream) {
- AUDIO_LOCK
+ AUDIO_LOCK
Stream *s = memnew(Stream);
s->audio_stream=p_stream;
s->event_stream=NULL;
@@ -693,11 +693,11 @@ void AudioServerSW::stream_set_active(RID p_stream, bool p_active) {
Stream *s = stream_owner.get(p_stream);
ERR_FAIL_COND(!s);
+ _THREAD_SAFE_METHOD_
if (s->active==p_active)
return;
AUDIO_LOCK;
- _THREAD_SAFE_METHOD_
s->active=p_active;
if (p_active)
s->E=active_audio_streams.push_back(s);
@@ -705,6 +705,8 @@ void AudioServerSW::stream_set_active(RID p_stream, bool p_active) {
active_audio_streams.erase(s->E);
s->E=NULL;
}
+
+
}
bool AudioServerSW::stream_is_active(RID p_stream) const {
@@ -763,7 +765,6 @@ void AudioServerSW::free(RID p_id) {
void AudioServerSW::_thread_func(void *self) {
-
AudioServerSW *as=(AudioServerSW *)self;
while (!as->exit_update_thread) {
@@ -806,6 +807,7 @@ void AudioServerSW::init() {
#ifndef NO_THREADS
exit_update_thread=false;
thread = Thread::create(_thread_func,this);
+ thread->set_name("AudioServerSW");
#endif
}
@@ -830,10 +832,14 @@ void AudioServerSW::finish() {
void AudioServerSW::_update_streams(bool p_thread) {
_THREAD_SAFE_METHOD_
- for(List<Stream*>::Element *E=active_audio_streams.front();E;E=E->next()) {
+ for(List<Stream*>::Element *E=active_audio_streams.front();E;) { //stream might be removed durnig this callback
+
+ List<Stream*>::Element *N=E->next();
if (E->get()->audio_stream && p_thread == E->get()->audio_stream->can_update_mt())
E->get()->audio_stream->update();
+
+ E=N;
}
}
@@ -916,7 +922,7 @@ float AudioServerSW::get_event_voice_global_volume_scale() const {
double AudioServerSW::get_output_delay() const {
- return _output_delay;
+ return _output_delay+AudioDriverSW::get_singleton()->get_latency();
}
double AudioServerSW::get_mix_time() const {
diff --git a/servers/audio/audio_server_sw.h b/servers/audio/audio_server_sw.h
index 77d2f2e8dd..bc6191729c 100644
--- a/servers/audio/audio_server_sw.h
+++ b/servers/audio/audio_server_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -118,7 +118,7 @@ public:
virtual RID sample_create(SampleFormat p_format, bool p_stereo, int p_length);
virtual void sample_set_description(RID p_sample, const String& p_description);
- virtual String sample_get_description(RID p_sample, const String& p_description) const;
+ virtual String sample_get_description(RID p_sample) const;
virtual SampleFormat sample_get_format(RID p_sample) const;
virtual bool sample_is_stereo(RID p_sample) const;
@@ -146,7 +146,7 @@ public:
virtual void voice_play(RID p_voice, RID p_sample);
- virtual void voice_set_volume(RID p_voice, float p_db);
+ virtual void voice_set_volume(RID p_voice, float p_volume);
virtual void voice_set_pan(RID p_voice, float p_pan, float p_depth=0,float height=0); //pan and depth go from -1 to 1
virtual void voice_set_filter(RID p_voice, FilterType p_type, float p_cutoff, float p_resonance,float p_gain=0);
virtual void voice_set_chorus(RID p_voice, float p_chorus );
@@ -256,6 +256,8 @@ public:
virtual void unlock()=0;
virtual void finish()=0;
+ virtual float get_latency() { return 0; }
+
diff --git a/servers/audio/reverb_buffers_sw.cpp b/servers/audio/reverb_buffers_sw.cpp
index b840b9390b..04bc056313 100644
--- a/servers/audio/reverb_buffers_sw.cpp
+++ b/servers/audio/reverb_buffers_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/audio/reverb_buffers_sw.h b/servers/audio/reverb_buffers_sw.h
index 817122b65d..f5885e6ee8 100644
--- a/servers/audio/reverb_buffers_sw.h
+++ b/servers/audio/reverb_buffers_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/audio/reverb_sw.cpp b/servers/audio/reverb_sw.cpp
index cc4b4bd778..5721403ba3 100644
--- a/servers/audio/reverb_sw.cpp
+++ b/servers/audio/reverb_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/audio/reverb_sw.h b/servers/audio/reverb_sw.h
index 937824f907..b028a245c8 100644
--- a/servers/audio/reverb_sw.h
+++ b/servers/audio/reverb_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/audio/sample_manager_sw.cpp b/servers/audio/sample_manager_sw.cpp
index 9195136a5d..60f4d16659 100644
--- a/servers/audio/sample_manager_sw.cpp
+++ b/servers/audio/sample_manager_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -38,12 +38,8 @@ SampleManagerSW::~SampleManagerSW()
RID SampleManagerMallocSW::sample_create(AS::SampleFormat p_format, bool p_stereo, int p_length) {
- ERR_EXPLAIN("IMA-ADPCM and STEREO are not a valid combination for sample format.");
- ERR_FAIL_COND_V( p_format == AS::SAMPLE_FORMAT_IMA_ADPCM && p_stereo,RID());
Sample *s = memnew( Sample );
int datalen = p_length;
- if (p_stereo)
- datalen*=2;
if (p_format==AS::SAMPLE_FORMAT_PCM16)
datalen*=2;
else if (p_format==AS::SAMPLE_FORMAT_IMA_ADPCM) {
@@ -53,6 +49,10 @@ RID SampleManagerMallocSW::sample_create(AS::SampleFormat p_format, bool p_stere
datalen/=2;
datalen+=4;
}
+
+ if (p_stereo)
+ datalen*=2;
+
#define SAMPLE_EXTRA 16
s->data = memalloc(datalen+SAMPLE_EXTRA); //help the interpolator by allocating a little more..
diff --git a/servers/audio/sample_manager_sw.h b/servers/audio/sample_manager_sw.h
index 94254f99d5..bd7a11a3d2 100644
--- a/servers/audio/sample_manager_sw.h
+++ b/servers/audio/sample_manager_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/audio/voice_rb_sw.cpp b/servers/audio/voice_rb_sw.cpp
index a385e15283..8d12e5085d 100644
--- a/servers/audio/voice_rb_sw.cpp
+++ b/servers/audio/voice_rb_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/audio/voice_rb_sw.h b/servers/audio/voice_rb_sw.h
index cbebcdb86f..f785646577 100644
--- a/servers/audio/voice_rb_sw.h
+++ b/servers/audio/voice_rb_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp
index 7c4f8b185a..74f866afb7 100644
--- a/servers/audio_server.cpp
+++ b/servers/audio_server.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -88,7 +88,7 @@ void AudioServer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("sample_get_length","sample"), &AudioServer::sample_get_length );
ObjectTypeDB::bind_method(_MD("sample_set_signed_data","sample","data"), &AudioServer::sample_set_signed_data );
- ObjectTypeDB::bind_method(_MD("sample_set_data","sample"), &AudioServer::sample_set_data );
+ ObjectTypeDB::bind_method(_MD("sample_set_data","sample","data"), &AudioServer::sample_set_data );
ObjectTypeDB::bind_method(_MD("sample_get_data","sample"), &AudioServer::sample_get_data );
ObjectTypeDB::bind_method(_MD("sample_set_mix_rate","sample","mix_rate"), &AudioServer::sample_set_mix_rate );
@@ -132,7 +132,7 @@ void AudioServer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("voice_stop","voice"), &AudioServer::voice_stop );
- ObjectTypeDB::bind_method(_MD("free","rid"), &AudioServer::free );
+ ObjectTypeDB::bind_method(_MD("free_rid","rid"), &AudioServer::free );
ObjectTypeDB::bind_method(_MD("set_stream_global_volume_scale","scale"), &AudioServer::set_stream_global_volume_scale );
ObjectTypeDB::bind_method(_MD("get_stream_global_volume_scale"), &AudioServer::get_stream_global_volume_scale );
@@ -164,6 +164,7 @@ void AudioServer::_bind_methods() {
BIND_CONSTANT( REVERB_HALL );
GLOBAL_DEF("audio/stream_buffering_ms",500);
+ GLOBAL_DEF("audio/video_delay_compensation_ms",300);
}
diff --git a/servers/audio_server.h b/servers/audio_server.h
index f54698a1e3..c56820dcbb 100644
--- a/servers/audio_server.h
+++ b/servers/audio_server.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -160,7 +160,7 @@ public:
virtual RID sample_create(SampleFormat p_format, bool p_stereo, int p_length)=0;
virtual void sample_set_description(RID p_sample, const String& p_description)=0;
- virtual String sample_get_description(RID p_sample, const String& p_description) const=0;
+ virtual String sample_get_description(RID p_sample) const=0;
virtual SampleFormat sample_get_format(RID p_sample) const=0;
virtual bool sample_is_stereo(RID p_sample) const=0;
@@ -210,7 +210,7 @@ public:
virtual void voice_play(RID p_voice, RID p_sample)=0;
- virtual void voice_set_volume(RID p_voice, float p_gain)=0;
+ virtual void voice_set_volume(RID p_voice, float p_volume)=0;
virtual void voice_set_pan(RID p_voice, float p_pan, float p_depth=0,float height=0)=0; //pan and depth go from -1 to 1
virtual void voice_set_filter(RID p_voice, FilterType p_type, float p_cutoff, float p_resonance, float p_gain=0)=0;
virtual void voice_set_chorus(RID p_voice, float p_chorus )=0;
diff --git a/servers/physics/SCsub b/servers/physics/SCsub
index 3b84c5ef18..95296eadbe 100644
--- a/servers/physics/SCsub
+++ b/servers/physics/SCsub
@@ -5,5 +5,3 @@ env.add_source_files(env.servers_sources,"*.cpp")
Export('env')
SConscript("joints/SCsub")
-
-
diff --git a/servers/physics/area_pair_sw.cpp b/servers/physics/area_pair_sw.cpp
index 3eb96fb681..c6bf6114a0 100644
--- a/servers/physics/area_pair_sw.cpp
+++ b/servers/physics/area_pair_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics/area_pair_sw.h b/servers/physics/area_pair_sw.h
index 4f8087280a..09a2934467 100644
--- a/servers/physics/area_pair_sw.h
+++ b/servers/physics/area_pair_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics/area_sw.cpp b/servers/physics/area_sw.cpp
index 83be80f816..dbc82da316 100644
--- a/servers/physics/area_sw.cpp
+++ b/servers/physics/area_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -83,6 +83,10 @@ void AreaSW::set_monitor_callback(ObjectID p_id, const StringName& p_method) {
_shape_changed();
+ if (!moved_list.in_list() && get_space())
+ get_space()->area_add_to_moved_list(&moved_list);
+
+
}
void AreaSW::set_area_monitor_callback(ObjectID p_id, const StringName& p_method) {
@@ -103,6 +107,10 @@ void AreaSW::set_area_monitor_callback(ObjectID p_id, const StringName& p_method
_shape_changed();
+ if (!moved_list.in_list() && get_space())
+ get_space()->area_add_to_moved_list(&moved_list);
+
+
}
@@ -123,7 +131,8 @@ void AreaSW::set_param(PhysicsServer::AreaParameter p_param, const Variant& p_va
case PhysicsServer::AREA_PARAM_GRAVITY_IS_POINT: gravity_is_point=p_value; ; break;
case PhysicsServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE: gravity_distance_scale=p_value; ; break;
case PhysicsServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION: point_attenuation=p_value; ; break;
- case PhysicsServer::AREA_PARAM_DENSITY: density=p_value; ; break;
+ case PhysicsServer::AREA_PARAM_LINEAR_DAMP: linear_damp=p_value; ; break;
+ case PhysicsServer::AREA_PARAM_ANGULAR_DAMP: angular_damp=p_value; ; break;
case PhysicsServer::AREA_PARAM_PRIORITY: priority=p_value; ; break;
}
@@ -139,7 +148,8 @@ Variant AreaSW::get_param(PhysicsServer::AreaParameter p_param) const {
case PhysicsServer::AREA_PARAM_GRAVITY_IS_POINT: return gravity_is_point;
case PhysicsServer::AREA_PARAM_GRAVITY_DISTANCE_SCALE: return gravity_distance_scale;
case PhysicsServer::AREA_PARAM_GRAVITY_POINT_ATTENUATION: return point_attenuation;
- case PhysicsServer::AREA_PARAM_DENSITY: return density;
+ case PhysicsServer::AREA_PARAM_LINEAR_DAMP: return linear_damp;
+ case PhysicsServer::AREA_PARAM_ANGULAR_DAMP: return angular_damp;
case PhysicsServer::AREA_PARAM_PRIORITY: return priority;
}
@@ -248,7 +258,8 @@ AreaSW::AreaSW() : CollisionObjectSW(TYPE_AREA), monitor_query_list(this), move
gravity_is_point=false;
gravity_distance_scale=0;
point_attenuation=1;
- density=0.1;
+ angular_damp=1.0;
+ linear_damp=0.1;
priority=0;
set_ray_pickable(false);
monitor_callback_id=0;
diff --git a/servers/physics/area_sw.h b/servers/physics/area_sw.h
index 26d6a177db..622eeb5e23 100644
--- a/servers/physics/area_sw.h
+++ b/servers/physics/area_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -47,7 +47,8 @@ class AreaSW : public CollisionObjectSW{
bool gravity_is_point;
float gravity_distance_scale;
float point_attenuation;
- float density;
+ float linear_damp;
+ float angular_damp;
int priority;
bool monitorable;
@@ -145,8 +146,11 @@ public:
_FORCE_INLINE_ void set_point_attenuation(float p_point_attenuation) { point_attenuation=p_point_attenuation; }
_FORCE_INLINE_ float get_point_attenuation() const { return point_attenuation; }
- _FORCE_INLINE_ void set_density(float p_density) { density=p_density; }
- _FORCE_INLINE_ float get_density() const { return density; }
+ _FORCE_INLINE_ void set_linear_damp(float p_linear_damp) { linear_damp=p_linear_damp; }
+ _FORCE_INLINE_ float get_linear_damp() const { return linear_damp; }
+
+ _FORCE_INLINE_ void set_angular_damp(float p_angular_damp) { angular_damp=p_angular_damp; }
+ _FORCE_INLINE_ float get_angular_damp() const { return angular_damp; }
_FORCE_INLINE_ void set_priority(int p_priority) { priority=p_priority; }
_FORCE_INLINE_ int get_priority() const { return priority; }
@@ -202,6 +206,7 @@ void AreaSW::remove_area_from_query(AreaSW *p_area, uint32_t p_area_shape,uint32
monitored_areas[bk].dec();
if (!monitor_query_list.in_list())
_queue_monitor_update();
+
}
diff --git a/servers/physics/body_pair_sw.cpp b/servers/physics/body_pair_sw.cpp
index e2b2fa2051..a971cdaad8 100644
--- a/servers/physics/body_pair_sw.cpp
+++ b/servers/physics/body_pair_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -194,7 +194,6 @@ bool BodyPairSW::_test_ccd(float p_step,BodySW *p_A, int p_shape_A,const Transfo
//cast a segment from support in motion normal, in the same direction of motion by motion length
//support is the worst case collision point, so real collision happened before
- int a;
Vector3 s=p_A->get_shape(p_shape_A)->get_support(p_xform_A.basis.xform(mnormal).normalized());
Vector3 from = p_xform_A.xform(s);
Vector3 to = from + motion;
@@ -299,6 +298,16 @@ bool BodyPairSW::setup(float p_step) {
c.active=true;
+#ifdef DEBUG_ENABLED
+
+
+ if (space->is_debugging_contacts()) {
+ space->add_debug_contact(global_A+offset_A);
+ space->add_debug_contact(global_B+offset_A);
+ }
+#endif
+
+
int gather_A = A->can_report_contacts();
int gather_B = B->can_report_contacts();
diff --git a/servers/physics/body_pair_sw.h b/servers/physics/body_pair_sw.h
index 8ec7a9ccef..da637ade05 100644
--- a/servers/physics/body_pair_sw.h
+++ b/servers/physics/body_pair_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics/body_sw.cpp b/servers/physics/body_sw.cpp
index 5a528ecf94..b0ed99cb48 100644
--- a/servers/physics/body_sw.cpp
+++ b/servers/physics/body_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -159,6 +159,17 @@ void BodySW::set_param(PhysicsServer::BodyParameter p_param, float p_value) {
_update_inertia();
} break;
+ case PhysicsServer::BODY_PARAM_GRAVITY_SCALE: {
+ gravity_scale=p_value;
+ } break;
+ case PhysicsServer::BODY_PARAM_LINEAR_DAMP: {
+
+ linear_damp=p_value;
+ } break;
+ case PhysicsServer::BODY_PARAM_ANGULAR_DAMP: {
+
+ angular_damp=p_value;
+ } break;
default:{}
}
}
@@ -177,6 +188,18 @@ float BodySW::get_param(PhysicsServer::BodyParameter p_param) const {
case PhysicsServer::BODY_PARAM_MASS: {
return mass;
} break;
+ case PhysicsServer::BODY_PARAM_GRAVITY_SCALE: {
+ return gravity_scale;
+ } break;
+ case PhysicsServer::BODY_PARAM_LINEAR_DAMP: {
+
+ return linear_damp;
+ } break;
+ case PhysicsServer::BODY_PARAM_ANGULAR_DAMP: {
+
+ return angular_damp;
+ } break;
+
default:{}
}
@@ -357,9 +380,11 @@ void BodySW::set_space(SpaceSW *p_space){
}
+ first_integration=true;
+
}
-void BodySW::_compute_area_gravity(const AreaSW *p_area) {
+void BodySW::_compute_area_gravity_and_dampenings(const AreaSW *p_area) {
if (p_area->is_gravity_point()) {
if(p_area->get_gravity_distance_scale() > 0) {
@@ -371,6 +396,9 @@ void BodySW::_compute_area_gravity(const AreaSW *p_area) {
} else {
gravity += p_area->get_gravity_vector() * p_area->get_gravity();
}
+
+ area_linear_damp += p_area->get_linear_damp();
+ area_angular_damp += p_area->get_angular_damp();
}
void BodySW::integrate_forces(real_t p_step) {
@@ -380,29 +408,58 @@ void BodySW::integrate_forces(real_t p_step) {
return;
AreaSW *def_area = get_space()->get_default_area();
+ // AreaSW *damp_area = def_area;
+
ERR_FAIL_COND(!def_area);
int ac = areas.size();
- bool replace = false;
- gravity=Vector3(0,0,0);
+ bool stopped = false;
+ gravity = Vector3(0,0,0);
+ area_linear_damp = 0;
+ area_angular_damp = 0;
if (ac) {
areas.sort();
const AreaCMP *aa = &areas[0];
- density = aa[ac-1].area->get_density();
- for(int i=ac-1;i>=0;i--) {
- _compute_area_gravity(aa[i].area);
- if (aa[i].area->get_space_override_mode() == PhysicsServer::AREA_SPACE_OVERRIDE_REPLACE) {
- replace = true;
- break;
+ // damp_area = aa[ac-1].area;
+ for(int i=ac-1;i>=0 && !stopped;i--) {
+ PhysicsServer::AreaSpaceOverrideMode mode=aa[i].area->get_space_override_mode();
+ switch (mode) {
+ case PhysicsServer::AREA_SPACE_OVERRIDE_COMBINE:
+ case PhysicsServer::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: {
+ _compute_area_gravity_and_dampenings(aa[i].area);
+ stopped = mode==PhysicsServer::AREA_SPACE_OVERRIDE_COMBINE_REPLACE;
+ } break;
+ case PhysicsServer::AREA_SPACE_OVERRIDE_REPLACE:
+ case PhysicsServer::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: {
+ gravity = Vector3(0,0,0);
+ area_angular_damp = 0;
+ area_linear_damp = 0;
+ _compute_area_gravity_and_dampenings(aa[i].area);
+ stopped = mode==PhysicsServer::AREA_SPACE_OVERRIDE_REPLACE;
+ } break;
+ default: {}
}
}
- } else {
- density=def_area->get_density();
}
- if( !replace ) {
- _compute_area_gravity(def_area);
+
+ if( !stopped ) {
+ _compute_area_gravity_and_dampenings(def_area);
}
+ gravity*=gravity_scale;
+
+ // If less than 0, override dampenings with that of the Body
+ if (angular_damp>=0)
+ area_angular_damp=angular_damp;
+ //else
+ // area_angular_damp=damp_area->get_angular_damp();
+
+ if (linear_damp>=0)
+ area_linear_damp=linear_damp;
+ //else
+ // area_linear_damp=damp_area->get_linear_damp();
+
+
Vector3 motion;
bool do_motion=false;
@@ -424,19 +481,19 @@ void BodySW::integrate_forces(real_t p_step) {
do_motion=true;
} else {
- if (!omit_force_integration) {
+ if (!omit_force_integration && !first_integration) {
//overriden by direct state query
Vector3 force=gravity*mass;
force+=applied_force;
Vector3 torque=applied_torque;
- real_t damp = 1.0 - p_step * density;
+ real_t damp = 1.0 - p_step * area_linear_damp;
if (damp<0) // reached zero in the given time
damp=0;
- real_t angular_damp = 1.0 - p_step * density * get_space()->get_body_angular_velocity_damp_ratio();
+ real_t angular_damp = 1.0 - p_step * area_angular_damp;
if (angular_damp<0) // reached zero in the given time
angular_damp=0;
@@ -457,6 +514,7 @@ void BodySW::integrate_forces(real_t p_step) {
applied_force=Vector3();
applied_torque=Vector3();
+ first_integration=false;
//motion=linear_velocity*p_step;
@@ -694,9 +752,14 @@ BodySW::BodySW() : CollisionObjectSW(TYPE_BODY), active_list(this), inertia_upda
island_next=NULL;
island_list_next=NULL;
first_time_kinematic=false;
+ first_integration=false;
_set_static(false);
- density=0;
+
contact_count=0;
+ gravity_scale=1.0;
+
+ area_angular_damp=0;
+ area_linear_damp=0;
still_time=0;
continuous_cd=false;
diff --git a/servers/physics/body_sw.h b/servers/physics/body_sw.h
index 6491ba8f18..c958177a19 100644
--- a/servers/physics/body_sw.h
+++ b/servers/physics/body_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -50,6 +50,10 @@ class BodySW : public CollisionObjectSW {
real_t bounce;
real_t friction;
+ real_t linear_damp;
+ real_t angular_damp;
+ real_t gravity_scale;
+
PhysicsServer::BodyAxisLock axis_lock;
real_t _inv_mass;
@@ -57,13 +61,16 @@ class BodySW : public CollisionObjectSW {
Matrix3 _inv_inertia_tensor;
Vector3 gravity;
- real_t density;
real_t still_time;
Vector3 applied_force;
Vector3 applied_torque;
+ float area_angular_damp;
+ float area_linear_damp;
+
+
SelfList<BodySW> active_list;
SelfList<BodySW> inertia_update_list;
SelfList<BodySW> direct_state_query_list;
@@ -72,6 +79,8 @@ class BodySW : public CollisionObjectSW {
bool omit_force_integration;
bool active;
+ bool first_integration;
+
bool continuous_cd;
bool can_sleep;
bool first_time_kinematic;
@@ -123,7 +132,7 @@ class BodySW : public CollisionObjectSW {
BodySW *island_next;
BodySW *island_list_next;
- _FORCE_INLINE_ void _compute_area_gravity(const AreaSW *p_area);
+ _FORCE_INLINE_ void _compute_area_gravity_and_dampenings(const AreaSW *p_area);
_FORCE_INLINE_ void _update_inertia_tensor();
@@ -233,7 +242,6 @@ public:
_FORCE_INLINE_ Matrix3 get_inv_inertia_tensor() const { return _inv_inertia_tensor; }
_FORCE_INLINE_ real_t get_friction() const { return friction; }
_FORCE_INLINE_ Vector3 get_gravity() const { return gravity; }
- _FORCE_INLINE_ real_t get_density() const { return density; }
_FORCE_INLINE_ real_t get_bounce() const { return bounce; }
_FORCE_INLINE_ void set_axis_lock(PhysicsServer::BodyAxisLock p_lock) { axis_lock=p_lock; }
@@ -335,8 +343,9 @@ public:
BodySW *body;
real_t step;
- virtual Vector3 get_total_gravity() const { return body->get_gravity(); } // get gravity vector working on this body space/area
- virtual float get_total_density() const { return body->get_density(); } // get density of this body space/area
+ virtual Vector3 get_total_gravity() const { return body->gravity; } // get gravity vector working on this body space/area
+ virtual float get_total_angular_damp() const { return body->area_angular_damp; } // get density of this body space/area
+ virtual float get_total_linear_damp() const { return body->area_linear_damp; } // get density of this body space/area
virtual float get_inverse_mass() const { return body->get_inv_mass(); } // get the mass
virtual Vector3 get_inverse_inertia() const { return body->get_inv_inertia(); } // get density of this body space
diff --git a/servers/physics/broad_phase_basic.cpp b/servers/physics/broad_phase_basic.cpp
index c49caed795..0bed56d398 100644
--- a/servers/physics/broad_phase_basic.cpp
+++ b/servers/physics/broad_phase_basic.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics/broad_phase_basic.h b/servers/physics/broad_phase_basic.h
index 9848c4b16e..6bf024044e 100644
--- a/servers/physics/broad_phase_basic.h
+++ b/servers/physics/broad_phase_basic.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics/broad_phase_octree.cpp b/servers/physics/broad_phase_octree.cpp
index 874ae29755..bfe41f8423 100644
--- a/servers/physics/broad_phase_octree.cpp
+++ b/servers/physics/broad_phase_octree.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics/broad_phase_octree.h b/servers/physics/broad_phase_octree.h
index 200878f6df..b87996a58c 100644
--- a/servers/physics/broad_phase_octree.h
+++ b/servers/physics/broad_phase_octree.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics/broad_phase_sw.cpp b/servers/physics/broad_phase_sw.cpp
index 910be4e623..a382df6a46 100644
--- a/servers/physics/broad_phase_sw.cpp
+++ b/servers/physics/broad_phase_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics/broad_phase_sw.h b/servers/physics/broad_phase_sw.h
index 2bf9f202e2..409c249865 100644
--- a/servers/physics/broad_phase_sw.h
+++ b/servers/physics/broad_phase_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics/collision_object_sw.cpp b/servers/physics/collision_object_sw.cpp
index 19b3f28a2f..55c8c1b955 100644
--- a/servers/physics/collision_object_sw.cpp
+++ b/servers/physics/collision_object_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics/collision_object_sw.h b/servers/physics/collision_object_sw.h
index c018ab6224..592c84e667 100644
--- a/servers/physics/collision_object_sw.h
+++ b/servers/physics/collision_object_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics/collision_solver_sat.cpp b/servers/physics/collision_solver_sat.cpp
index 72e61f1456..8789663f63 100644
--- a/servers/physics/collision_solver_sat.cpp
+++ b/servers/physics/collision_solver_sat.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics/collision_solver_sat.h b/servers/physics/collision_solver_sat.h
index 686b587243..57f5bdbbc0 100644
--- a/servers/physics/collision_solver_sat.h
+++ b/servers/physics/collision_solver_sat.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics/collision_solver_sw.cpp b/servers/physics/collision_solver_sw.cpp
index b5a5c64660..716e724637 100644
--- a/servers/physics/collision_solver_sw.cpp
+++ b/servers/physics/collision_solver_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics/collision_solver_sw.h b/servers/physics/collision_solver_sw.h
index 5ed5260b7d..abc50cae2c 100644
--- a/servers/physics/collision_solver_sw.h
+++ b/servers/physics/collision_solver_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics/constraint_sw.cpp b/servers/physics/constraint_sw.cpp
index fb45485233..ce0e1e6963 100644
--- a/servers/physics/constraint_sw.cpp
+++ b/servers/physics/constraint_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics/constraint_sw.h b/servers/physics/constraint_sw.h
index 1ec237f9c5..d61701ac07 100644
--- a/servers/physics/constraint_sw.h
+++ b/servers/physics/constraint_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics/gjk_epa.cpp b/servers/physics/gjk_epa.cpp
index 9b5b3d4f67..229c6d3fb4 100644
--- a/servers/physics/gjk_epa.cpp
+++ b/servers/physics/gjk_epa.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/*************************************************/
/* Source code within this file is: */
-/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
/* All Rights Reserved. */
/*************************************************/
diff --git a/servers/physics/gjk_epa.h b/servers/physics/gjk_epa.h
index 08b0a65b15..23f51d66c4 100644
--- a/servers/physics/gjk_epa.h
+++ b/servers/physics/gjk_epa.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/*************************************************/
/* Source code within this file is: */
-/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
/* All Rights Reserved. */
/*************************************************/
diff --git a/servers/physics/joints/SCsub b/servers/physics/joints/SCsub
index 97d6edea21..d31af2c1c4 100644
--- a/servers/physics/joints/SCsub
+++ b/servers/physics/joints/SCsub
@@ -3,6 +3,3 @@ Import('env')
env.add_source_files(env.servers_sources,"*.cpp")
Export('env')
-
-
-
diff --git a/servers/physics/joints_sw.cpp b/servers/physics/joints_sw.cpp
index aa9d3265d2..7f7df31534 100644
--- a/servers/physics/joints_sw.cpp
+++ b/servers/physics/joints_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics/joints_sw.h b/servers/physics/joints_sw.h
index d7ba6ef925..c42baae961 100644
--- a/servers/physics/joints_sw.h
+++ b/servers/physics/joints_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics/physics_server_sw.cpp b/servers/physics/physics_server_sw.cpp
index 521ffae0ea..5eb14d80dc 100644
--- a/servers/physics/physics_server_sw.cpp
+++ b/servers/physics/physics_server_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -201,6 +201,30 @@ PhysicsDirectSpaceState* PhysicsServerSW::space_get_direct_state(RID p_space) {
return space->get_direct_state();
}
+void PhysicsServerSW::space_set_debug_contacts(RID p_space,int p_max_contacts) {
+
+ SpaceSW *space = space_owner.get(p_space);
+ ERR_FAIL_COND(!space);
+ space->set_debug_contacts(p_max_contacts);
+
+}
+
+Vector<Vector3> PhysicsServerSW::space_get_contacts(RID p_space) const {
+
+ SpaceSW *space = space_owner.get(p_space);
+ ERR_FAIL_COND_V(!space,Vector<Vector3>());
+ return space->get_debug_contacts();
+
+}
+
+int PhysicsServerSW::space_get_contact_count(RID p_space) const {
+
+ SpaceSW *space = space_owner.get(p_space);
+ ERR_FAIL_COND_V(!space,0);
+ return space->get_debug_contact_count();
+
+}
+
RID PhysicsServerSW::area_create() {
AreaSW *area = memnew( AreaSW );
@@ -493,7 +517,7 @@ void PhysicsServerSW::body_set_mode(RID p_body, BodyMode p_mode) {
body->set_mode(p_mode);
};
-PhysicsServer::BodyMode PhysicsServerSW::body_get_mode(RID p_body, BodyMode p_mode) const {
+PhysicsServer::BodyMode PhysicsServerSW::body_get_mode(RID p_body) const {
BodySW *body = body_owner.get(p_body);
ERR_FAIL_COND_V(!body,BODY_MODE_STATIC);
diff --git a/servers/physics/physics_server_sw.h b/servers/physics/physics_server_sw.h
index 80007b8499..2aadac2216 100644
--- a/servers/physics/physics_server_sw.h
+++ b/servers/physics/physics_server_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -94,6 +94,9 @@ public:
// this function only works on fixed process, errors and returns null otherwise
virtual PhysicsDirectSpaceState* space_get_direct_state(RID p_space);
+ virtual void space_set_debug_contacts(RID p_space,int p_max_contacts);
+ virtual Vector<Vector3> space_get_contacts(RID p_space) const;
+ virtual int space_get_contact_count(RID p_space) const;
/* AREA API */
@@ -143,7 +146,7 @@ public:
virtual RID body_get_space(RID p_body) const;
virtual void body_set_mode(RID p_body, BodyMode p_mode);
- virtual BodyMode body_get_mode(RID p_body, BodyMode p_mode) const;
+ virtual BodyMode body_get_mode(RID p_body) const;
virtual void body_add_shape(RID p_body, RID p_shape, const Transform& p_transform=Transform());
virtual void body_set_shape(RID p_body, int p_shape_idx,RID p_shape);
diff --git a/servers/physics/shape_sw.cpp b/servers/physics/shape_sw.cpp
index fabfa88ee5..5923f89120 100644
--- a/servers/physics/shape_sw.cpp
+++ b/servers/physics/shape_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -1354,6 +1354,10 @@ void ConcavePolygonShapeSW::_fill_bvh(_VolumeSW_BVH* p_bvh_tree,BVH* p_bvh_array
void ConcavePolygonShapeSW::_setup(DVector<Vector3> p_faces) {
int src_face_count=p_faces.size();
+ if (src_face_count==0) {
+ configure(AABB());
+ return;
+ }
ERR_FAIL_COND(src_face_count%3);
src_face_count/=3;
diff --git a/servers/physics/shape_sw.h b/servers/physics/shape_sw.h
index 4826eaea4f..39779bcda3 100644
--- a/servers/physics/shape_sw.h
+++ b/servers/physics/shape_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics/space_sw.cpp b/servers/physics/space_sw.cpp
index d329a10f04..08f280a976 100644
--- a/servers/physics/space_sw.cpp
+++ b/servers/physics/space_sw.cpp
@@ -1,744 +1,748 @@
-/*************************************************************************/
-/* space_sw.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* http://www.godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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. */
-/*************************************************************************/
-#include "globals.h"
-#include "space_sw.h"
-#include "collision_solver_sw.h"
-#include "physics_server_sw.h"
-
-
-_FORCE_INLINE_ static bool _match_object_type_query(CollisionObjectSW *p_object, uint32_t p_layer_mask, uint32_t p_type_mask) {
-
- if ((p_object->get_layer_mask()&p_layer_mask)==0)
- return false;
-
- if (p_object->get_type()==CollisionObjectSW::TYPE_AREA && !(p_type_mask&PhysicsDirectSpaceState::TYPE_MASK_AREA))
- return false;
-
- BodySW *body = static_cast<BodySW*>(p_object);
-
- return (1<<body->get_mode())&p_type_mask;
-
-}
-
-
-bool PhysicsDirectSpaceStateSW::intersect_ray(const Vector3& p_from, const Vector3& p_to,RayResult &r_result,const Set<RID>& p_exclude,uint32_t p_layer_mask,uint32_t p_object_type_mask) {
-
-
- ERR_FAIL_COND_V(space->locked,false);
-
- Vector3 begin,end;
- Vector3 normal;
- begin=p_from;
- end=p_to;
- normal=(end-begin).normalized();
-
-
- int amount = space->broadphase->cull_segment(begin,end,space->intersection_query_results,SpaceSW::INTERSECTION_QUERY_MAX,space->intersection_query_subindex_results);
-
-
- //todo, create another array tha references results, compute AABBs and check closest point to ray origin, sort, and stop evaluating results when beyond first collision
-
- bool collided=false;
- Vector3 res_point,res_normal;
- int res_shape;
- const CollisionObjectSW *res_obj;
- real_t min_d=1e10;
-
-
-
- for(int i=0;i<amount;i++) {
-
- if (!_match_object_type_query(space->intersection_query_results[i],p_layer_mask,p_object_type_mask))
- continue;
-
- if (!(static_cast<CollisionObjectSW*>(space->intersection_query_results[i])->is_ray_pickable()))
- continue;
-
- if (p_exclude.has( space->intersection_query_results[i]->get_self()))
- continue;
-
- const CollisionObjectSW *col_obj=space->intersection_query_results[i];
-
- int shape_idx=space->intersection_query_subindex_results[i];
- Transform inv_xform = col_obj->get_shape_inv_transform(shape_idx) * col_obj->get_inv_transform();
-
- Vector3 local_from = inv_xform.xform(begin);
- Vector3 local_to = inv_xform.xform(end);
-
- const ShapeSW *shape = col_obj->get_shape(shape_idx);
-
- Vector3 shape_point,shape_normal;
-
-
- if (shape->intersect_segment(local_from,local_to,shape_point,shape_normal)) {
-
-
-
- Transform xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
- shape_point=xform.xform(shape_point);
-
- real_t ld = normal.dot(shape_point);
-
-
- if (ld<min_d) {
-
- min_d=ld;
- res_point=shape_point;
- res_normal=inv_xform.basis.xform_inv(shape_normal).normalized();
- res_shape=shape_idx;
- res_obj=col_obj;
- collided=true;
- }
- }
-
- }
-
- if (!collided)
- return false;
-
-
- r_result.collider_id=res_obj->get_instance_id();
- if (r_result.collider_id!=0)
- r_result.collider=ObjectDB::get_instance(r_result.collider_id);
- else
- r_result.collider=NULL;
- r_result.normal=res_normal;
- r_result.position=res_point;
- r_result.rid=res_obj->get_self();
- r_result.shape=res_shape;
-
- return true;
-
-}
-
-
-int PhysicsDirectSpaceStateSW::intersect_shape(const RID& p_shape, const Transform& p_xform,float p_margin,ShapeResult *r_results,int p_result_max,const Set<RID>& p_exclude,uint32_t p_layer_mask,uint32_t p_object_type_mask) {
-
- if (p_result_max<=0)
- return 0;
-
- ShapeSW *shape = static_cast<PhysicsServerSW*>(PhysicsServer::get_singleton())->shape_owner.get(p_shape);
- ERR_FAIL_COND_V(!shape,0);
-
- AABB aabb = p_xform.xform(shape->get_aabb());
-
- int amount = space->broadphase->cull_aabb(aabb,space->intersection_query_results,SpaceSW::INTERSECTION_QUERY_MAX,space->intersection_query_subindex_results);
-
- bool collided=false;
- int cc=0;
-
- //Transform ai = p_xform.affine_inverse();
-
- for(int i=0;i<amount;i++) {
-
- if (cc>=p_result_max)
- break;
-
- if (!_match_object_type_query(space->intersection_query_results[i],p_layer_mask,p_object_type_mask))
- continue;
-
- //area cant be picked by ray (default)
-
- if (p_exclude.has( space->intersection_query_results[i]->get_self()))
- continue;
-
-
- const CollisionObjectSW *col_obj=space->intersection_query_results[i];
- int shape_idx=space->intersection_query_subindex_results[i];
-
- if (!CollisionSolverSW::solve_static(shape,p_xform,col_obj->get_shape(shape_idx),col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), NULL,NULL,NULL,p_margin,0))
- continue;
-
- r_results[cc].collider_id=col_obj->get_instance_id();
- if (r_results[cc].collider_id!=0)
- r_results[cc].collider=ObjectDB::get_instance(r_results[cc].collider_id);
- else
- r_results[cc].collider=NULL;
- r_results[cc].rid=col_obj->get_self();
- r_results[cc].shape=shape_idx;
-
- cc++;
-
- }
-
- return cc;
-
-}
-
-
-bool PhysicsDirectSpaceStateSW::cast_motion(const RID& p_shape, const Transform& p_xform,const Vector3& p_motion,float p_margin,float &p_closest_safe,float &p_closest_unsafe, const Set<RID>& p_exclude,uint32_t p_layer_mask,uint32_t p_object_type_mask,ShapeRestInfo *r_info) {
-
-
-
- ShapeSW *shape = static_cast<PhysicsServerSW*>(PhysicsServer::get_singleton())->shape_owner.get(p_shape);
- ERR_FAIL_COND_V(!shape,false);
-
- AABB aabb = p_xform.xform(shape->get_aabb());
- aabb=aabb.merge(AABB(aabb.pos+p_motion,aabb.size)); //motion
- aabb=aabb.grow(p_margin);
-
- //if (p_motion!=Vector3())
- // print_line(p_motion);
-
- int amount = space->broadphase->cull_aabb(aabb,space->intersection_query_results,SpaceSW::INTERSECTION_QUERY_MAX,space->intersection_query_subindex_results);
-
- float best_safe=1;
- float best_unsafe=1;
-
- Transform xform_inv = p_xform.affine_inverse();
- MotionShapeSW mshape;
- mshape.shape=shape;
- mshape.motion=xform_inv.basis.xform(p_motion);
-
- bool best_first=true;
-
- Vector3 closest_A,closest_B;
-
- for(int i=0;i<amount;i++) {
-
-
- if (!_match_object_type_query(space->intersection_query_results[i],p_layer_mask,p_object_type_mask))
- continue;
-
- if (p_exclude.has( space->intersection_query_results[i]->get_self()))
- continue; //ignore excluded
-
-
- const CollisionObjectSW *col_obj=space->intersection_query_results[i];
- int shape_idx=space->intersection_query_subindex_results[i];
-
- Vector3 point_A,point_B;
- Vector3 sep_axis=p_motion.normalized();
-
- Transform col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
- //test initial overlap, does it collide if going all the way?
- if (CollisionSolverSW::solve_distance(&mshape,p_xform,col_obj->get_shape(shape_idx),col_obj_xform,point_A,point_B,aabb,&sep_axis)) {
- //print_line("failed motion cast (no collision)");
- continue;
- }
-
-
- //test initial overlap
-#if 0
- if (CollisionSolverSW::solve_static(shape,p_xform,col_obj->get_shape(shape_idx),col_obj_xform,NULL,NULL,&sep_axis)) {
- print_line("failed initial cast (collision at begining)");
- return false;
- }
-#else
- sep_axis=p_motion.normalized();
-
- if (!CollisionSolverSW::solve_distance(shape,p_xform,col_obj->get_shape(shape_idx),col_obj_xform,point_A,point_B,aabb,&sep_axis)) {
- //print_line("failed motion cast (no collision)");
- return false;
- }
-#endif
-
-
- //just do kinematic solving
- float low=0;
- float hi=1;
- Vector3 mnormal=p_motion.normalized();
-
- for(int i=0;i<8;i++) { //steps should be customizable..
-
- Transform xfa = p_xform;
- float ofs = (low+hi)*0.5;
-
- Vector3 sep=mnormal; //important optimization for this to work fast enough
-
- mshape.motion=xform_inv.basis.xform(p_motion*ofs);
-
- Vector3 lA,lB;
-
- bool collided = !CollisionSolverSW::solve_distance(&mshape,p_xform,col_obj->get_shape(shape_idx),col_obj_xform,lA,lB,aabb,&sep);
-
- if (collided) {
-
- //print_line(itos(i)+": "+rtos(ofs));
- hi=ofs;
- } else {
-
- point_A=lA;
- point_B=lB;
- low=ofs;
- }
- }
-
- if (low<best_safe) {
- best_first=true; //force reset
- best_safe=low;
- best_unsafe=hi;
- }
-
- if (r_info && (best_first || (point_A.distance_squared_to(point_B) < closest_A.distance_squared_to(closest_B) && low<=best_safe))) {
- closest_A=point_A;
- closest_B=point_B;
- r_info->collider_id=col_obj->get_instance_id();
- r_info->rid=col_obj->get_self();
- r_info->shape=shape_idx;
- r_info->point=closest_B;
- r_info->normal=(closest_A-closest_B).normalized();
- best_first=false;
- if (col_obj->get_type()==CollisionObjectSW::TYPE_BODY) {
- const BodySW *body=static_cast<const BodySW*>(col_obj);
- r_info->linear_velocity= body->get_linear_velocity() + (body->get_angular_velocity()).cross(body->get_transform().origin - closest_B);
- }
-
- }
-
-
- }
-
- p_closest_safe=best_safe;
- p_closest_unsafe=best_unsafe;
-
- return true;
-}
-
-bool PhysicsDirectSpaceStateSW::collide_shape(RID p_shape, const Transform& p_shape_xform,float p_margin,Vector3 *r_results,int p_result_max,int &r_result_count, const Set<RID>& p_exclude,uint32_t p_layer_mask,uint32_t p_object_type_mask){
-
- if (p_result_max<=0)
- return 0;
-
- ShapeSW *shape = static_cast<PhysicsServerSW*>(PhysicsServer::get_singleton())->shape_owner.get(p_shape);
- ERR_FAIL_COND_V(!shape,0);
-
- AABB aabb = p_shape_xform.xform(shape->get_aabb());
- aabb=aabb.grow(p_margin);
-
- int amount = space->broadphase->cull_aabb(aabb,space->intersection_query_results,SpaceSW::INTERSECTION_QUERY_MAX,space->intersection_query_subindex_results);
-
- bool collided=false;
- int cc=0;
- r_result_count=0;
-
- PhysicsServerSW::CollCbkData cbk;
- cbk.max=p_result_max;
- cbk.amount=0;
- cbk.ptr=r_results;
- CollisionSolverSW::CallbackResult cbkres=NULL;
-
- PhysicsServerSW::CollCbkData *cbkptr=NULL;
- if (p_result_max>0) {
- cbkptr=&cbk;
- cbkres=PhysicsServerSW::_shape_col_cbk;
- }
-
-
- for(int i=0;i<amount;i++) {
-
- if (!_match_object_type_query(space->intersection_query_results[i],p_layer_mask,p_object_type_mask))
- continue;
-
- const CollisionObjectSW *col_obj=space->intersection_query_results[i];
- int shape_idx=space->intersection_query_subindex_results[i];
-
- if (p_exclude.has( col_obj->get_self() )) {
- continue;
- }
-
- //print_line("AGAINST: "+itos(col_obj->get_self().get_id())+":"+itos(shape_idx));
- //print_line("THE ABBB: "+(col_obj->get_transform() * col_obj->get_shape_transform(shape_idx)).xform(col_obj->get_shape(shape_idx)->get_aabb()));
-
- if (CollisionSolverSW::solve_static(shape,p_shape_xform,col_obj->get_shape(shape_idx),col_obj->get_transform() * col_obj->get_shape_transform(shape_idx),cbkres,cbkptr,NULL,p_margin)) {
- collided=true;
- }
-
- }
-
- r_result_count=cbk.amount;
-
- return collided;
-
-}
-
-
-struct _RestCallbackData {
-
- const CollisionObjectSW *object;
- const CollisionObjectSW *best_object;
- int shape;
- int best_shape;
- Vector3 best_contact;
- Vector3 best_normal;
- float best_len;
-};
-
-static void _rest_cbk_result(const Vector3& p_point_A,const Vector3& p_point_B,void *p_userdata) {
-
-
- _RestCallbackData *rd=(_RestCallbackData*)p_userdata;
-
- Vector3 contact_rel = p_point_B - p_point_A;
- float len = contact_rel.length();
- if (len <= rd->best_len)
- return;
-
- rd->best_len=len;
- rd->best_contact=p_point_B;
- rd->best_normal=contact_rel/len;
- rd->best_object=rd->object;
- rd->best_shape=rd->shape;
-
-}
-bool PhysicsDirectSpaceStateSW::rest_info(RID p_shape, const Transform& p_shape_xform,float p_margin,ShapeRestInfo *r_info, const Set<RID>& p_exclude,uint32_t p_layer_mask,uint32_t p_object_type_mask) {
-
-
- ShapeSW *shape = static_cast<PhysicsServerSW*>(PhysicsServer::get_singleton())->shape_owner.get(p_shape);
- ERR_FAIL_COND_V(!shape,0);
-
- AABB aabb = p_shape_xform.xform(shape->get_aabb());
- aabb=aabb.grow(p_margin);
-
- int amount = space->broadphase->cull_aabb(aabb,space->intersection_query_results,SpaceSW::INTERSECTION_QUERY_MAX,space->intersection_query_subindex_results);
-
- _RestCallbackData rcd;
- rcd.best_len=0;
- rcd.best_object=NULL;
- rcd.best_shape=0;
-
- for(int i=0;i<amount;i++) {
-
-
- if (!_match_object_type_query(space->intersection_query_results[i],p_layer_mask,p_object_type_mask))
- continue;
-
- const CollisionObjectSW *col_obj=space->intersection_query_results[i];
- int shape_idx=space->intersection_query_subindex_results[i];
-
- if (p_exclude.has( col_obj->get_self() ))
- continue;
-
- rcd.object=col_obj;
- rcd.shape=shape_idx;
- bool sc = CollisionSolverSW::solve_static(shape,p_shape_xform,col_obj->get_shape(shape_idx),col_obj->get_transform() * col_obj->get_shape_transform(shape_idx),_rest_cbk_result,&rcd,NULL,p_margin);
- if (!sc)
- continue;
-
-
- }
-
- if (rcd.best_len==0)
- return false;
-
- r_info->collider_id=rcd.best_object->get_instance_id();
- r_info->shape=rcd.best_shape;
- r_info->normal=rcd.best_normal;
- r_info->point=rcd.best_contact;
- r_info->rid=rcd.best_object->get_self();
- if (rcd.best_object->get_type()==CollisionObjectSW::TYPE_BODY) {
-
- const BodySW *body = static_cast<const BodySW*>(rcd.best_object);
- Vector3 rel_vec = r_info->point-body->get_transform().get_origin();
- r_info->linear_velocity = body->get_linear_velocity() +
- (body->get_angular_velocity()).cross(body->get_transform().origin-rcd.best_contact);// * mPos);
-
-
- } else {
- r_info->linear_velocity=Vector3();
- }
-
- return true;
-}
-
-
-PhysicsDirectSpaceStateSW::PhysicsDirectSpaceStateSW() {
-
-
- space=NULL;
-}
-
-
-////////////////////////////////////////////////////////////////////////////////////////////////////////////
-
-
-
-
-
-
-
-
-
-
-void* SpaceSW::_broadphase_pair(CollisionObjectSW *A,int p_subindex_A,CollisionObjectSW *B,int p_subindex_B,void *p_self) {
-
- CollisionObjectSW::Type type_A=A->get_type();
- CollisionObjectSW::Type type_B=B->get_type();
- if (type_A>type_B) {
-
- SWAP(A,B);
- SWAP(p_subindex_A,p_subindex_B);
- SWAP(type_A,type_B);
- }
-
- SpaceSW *self = (SpaceSW*)p_self;
-
- self->collision_pairs++;
-
- if (type_A==CollisionObjectSW::TYPE_AREA) {
-
- AreaSW *area=static_cast<AreaSW*>(A);
- if (type_B==CollisionObjectSW::TYPE_AREA) {
-
- AreaSW *area_b=static_cast<AreaSW*>(B);
- Area2PairSW *area2_pair = memnew(Area2PairSW(area_b,p_subindex_B,area,p_subindex_A) );
- return area2_pair;
- } else {
-
- BodySW *body=static_cast<BodySW*>(B);
- AreaPairSW *area_pair = memnew(AreaPairSW(body,p_subindex_B,area,p_subindex_A) );
- return area_pair;
- }
- } else {
-
-
- BodyPairSW *b = memnew( BodyPairSW((BodySW*)A,p_subindex_A,(BodySW*)B,p_subindex_B) );
- return b;
-
- }
-
- return NULL;
-}
-
-void SpaceSW::_broadphase_unpair(CollisionObjectSW *A,int p_subindex_A,CollisionObjectSW *B,int p_subindex_B,void *p_data,void *p_self) {
-
-
-
- SpaceSW *self = (SpaceSW*)p_self;
- self->collision_pairs--;
- ConstraintSW *c = (ConstraintSW*)p_data;
- memdelete(c);
-}
-
-
-const SelfList<BodySW>::List& SpaceSW::get_active_body_list() const {
-
- return active_list;
-}
-void SpaceSW::body_add_to_active_list(SelfList<BodySW>* p_body) {
-
- active_list.add(p_body);
-}
-void SpaceSW::body_remove_from_active_list(SelfList<BodySW>* p_body) {
-
- active_list.remove(p_body);
-
-}
-
-void SpaceSW::body_add_to_inertia_update_list(SelfList<BodySW>* p_body) {
-
-
- inertia_update_list.add(p_body);
-}
-
-void SpaceSW::body_remove_from_inertia_update_list(SelfList<BodySW>* p_body) {
-
- inertia_update_list.remove(p_body);
-}
-
-BroadPhaseSW *SpaceSW::get_broadphase() {
-
- return broadphase;
-}
-
-void SpaceSW::add_object(CollisionObjectSW *p_object) {
-
- ERR_FAIL_COND( objects.has(p_object) );
- objects.insert(p_object);
-}
-
-void SpaceSW::remove_object(CollisionObjectSW *p_object) {
-
- ERR_FAIL_COND( !objects.has(p_object) );
- objects.erase(p_object);
-}
-
-const Set<CollisionObjectSW*> &SpaceSW::get_objects() const {
-
- return objects;
-}
-
-void SpaceSW::body_add_to_state_query_list(SelfList<BodySW>* p_body) {
-
- state_query_list.add(p_body);
-}
-void SpaceSW::body_remove_from_state_query_list(SelfList<BodySW>* p_body) {
-
- state_query_list.remove(p_body);
-}
-
-void SpaceSW::area_add_to_monitor_query_list(SelfList<AreaSW>* p_area) {
-
- monitor_query_list.add(p_area);
-}
-void SpaceSW::area_remove_from_monitor_query_list(SelfList<AreaSW>* p_area) {
-
- monitor_query_list.remove(p_area);
-}
-
-void SpaceSW::area_add_to_moved_list(SelfList<AreaSW>* p_area) {
-
- area_moved_list.add(p_area);
-}
-
-void SpaceSW::area_remove_from_moved_list(SelfList<AreaSW>* p_area) {
-
- area_moved_list.remove(p_area);
-}
-
-const SelfList<AreaSW>::List& SpaceSW::get_moved_area_list() const {
-
- return area_moved_list;
-}
-
-
-
-
-void SpaceSW::call_queries() {
-
- while(state_query_list.first()) {
-
- BodySW * b = state_query_list.first()->self();
- b->call_queries();
- state_query_list.remove(state_query_list.first());
- }
-
- while(monitor_query_list.first()) {
-
- AreaSW * a = monitor_query_list.first()->self();
- a->call_queries();
- monitor_query_list.remove(monitor_query_list.first());
- }
-
-}
-
-void SpaceSW::setup() {
-
-
- while(inertia_update_list.first()) {
- inertia_update_list.first()->self()->update_inertias();
- inertia_update_list.remove(inertia_update_list.first());
- }
-
-
-}
-
-void SpaceSW::update() {
-
- broadphase->update();
-
-}
-
-
-void SpaceSW::set_param(PhysicsServer::SpaceParameter p_param, real_t p_value) {
-
- switch(p_param) {
-
- case PhysicsServer::SPACE_PARAM_CONTACT_RECYCLE_RADIUS: contact_recycle_radius=p_value; break;
- case PhysicsServer::SPACE_PARAM_CONTACT_MAX_SEPARATION: contact_max_separation=p_value; break;
- case PhysicsServer::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION: contact_max_allowed_penetration=p_value; break;
- case PhysicsServer::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_TRESHOLD: body_linear_velocity_sleep_threshold=p_value; break;
- case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_TRESHOLD: body_angular_velocity_sleep_threshold=p_value; break;
- case PhysicsServer::SPACE_PARAM_BODY_TIME_TO_SLEEP: body_time_to_sleep=p_value; break;
- case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO: body_angular_velocity_damp_ratio=p_value; break;
- case PhysicsServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: constraint_bias=p_value; break;
- }
-}
-
-real_t SpaceSW::get_param(PhysicsServer::SpaceParameter p_param) const {
-
- switch(p_param) {
-
- case PhysicsServer::SPACE_PARAM_CONTACT_RECYCLE_RADIUS: return contact_recycle_radius;
- case PhysicsServer::SPACE_PARAM_CONTACT_MAX_SEPARATION: return contact_max_separation;
- case PhysicsServer::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION: return contact_max_allowed_penetration;
- case PhysicsServer::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_TRESHOLD: return body_linear_velocity_sleep_threshold;
- case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_TRESHOLD: return body_angular_velocity_sleep_threshold;
- case PhysicsServer::SPACE_PARAM_BODY_TIME_TO_SLEEP: return body_time_to_sleep;
- case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO: return body_angular_velocity_damp_ratio;
- case PhysicsServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: return constraint_bias;
- }
- return 0;
-}
-
-void SpaceSW::lock() {
-
- locked=true;
-}
-
-void SpaceSW::unlock() {
-
- locked=false;
-}
-
-bool SpaceSW::is_locked() const {
-
- return locked;
-}
-
-PhysicsDirectSpaceStateSW *SpaceSW::get_direct_state() {
-
- return direct_access;
-}
-
-SpaceSW::SpaceSW() {
-
- collision_pairs=0;
- active_objects=0;
- island_count=0;
-
- locked=false;
- contact_recycle_radius=0.01;
- contact_max_separation=0.05;
- contact_max_allowed_penetration= 0.01;
-
- constraint_bias = 0.01;
- body_linear_velocity_sleep_threshold=GLOBAL_DEF("physics/sleep_threshold_linear",0.1);
- body_angular_velocity_sleep_threshold=GLOBAL_DEF("physics/sleep_threshold_angular", (8.0 / 180.0 * Math_PI) );
- body_time_to_sleep=0.5;
- body_angular_velocity_damp_ratio=10;
-
-
- broadphase = BroadPhaseSW::create_func();
- broadphase->set_pair_callback(_broadphase_pair,this);
- broadphase->set_unpair_callback(_broadphase_unpair,this);
- area=NULL;
-
- direct_access = memnew( PhysicsDirectSpaceStateSW );
- direct_access->space=this;
-}
-
-SpaceSW::~SpaceSW() {
-
- memdelete(broadphase);
- memdelete( direct_access );
-}
-
-
-
+/*************************************************************************/
+/* space_sw.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
+#include "globals.h"
+#include "space_sw.h"
+#include "collision_solver_sw.h"
+#include "physics_server_sw.h"
+
+
+_FORCE_INLINE_ static bool _match_object_type_query(CollisionObjectSW *p_object, uint32_t p_layer_mask, uint32_t p_type_mask) {
+
+ if (p_object->get_type()==CollisionObjectSW::TYPE_AREA)
+ return p_type_mask&PhysicsDirectSpaceState::TYPE_MASK_AREA;
+
+ if ((p_object->get_layer_mask()&p_layer_mask)==0)
+ return false;
+
+ BodySW *body = static_cast<BodySW*>(p_object);
+
+ return (1<<body->get_mode())&p_type_mask;
+
+}
+
+
+bool PhysicsDirectSpaceStateSW::intersect_ray(const Vector3& p_from, const Vector3& p_to, RayResult &r_result, const Set<RID>& p_exclude, uint32_t p_layer_mask, uint32_t p_object_type_mask, bool p_pick_ray) {
+
+
+ ERR_FAIL_COND_V(space->locked,false);
+
+ Vector3 begin,end;
+ Vector3 normal;
+ begin=p_from;
+ end=p_to;
+ normal=(end-begin).normalized();
+
+
+ int amount = space->broadphase->cull_segment(begin,end,space->intersection_query_results,SpaceSW::INTERSECTION_QUERY_MAX,space->intersection_query_subindex_results);
+
+
+ //todo, create another array tha references results, compute AABBs and check closest point to ray origin, sort, and stop evaluating results when beyond first collision
+
+ bool collided=false;
+ Vector3 res_point,res_normal;
+ int res_shape;
+ const CollisionObjectSW *res_obj;
+ real_t min_d=1e10;
+
+
+
+ for(int i=0;i<amount;i++) {
+
+ if (!_match_object_type_query(space->intersection_query_results[i],p_layer_mask,p_object_type_mask))
+ continue;
+
+ if (p_pick_ray && !(static_cast<CollisionObjectSW*>(space->intersection_query_results[i])->is_ray_pickable()))
+ continue;
+
+ if (p_exclude.has( space->intersection_query_results[i]->get_self()))
+ continue;
+
+ const CollisionObjectSW *col_obj=space->intersection_query_results[i];
+
+ int shape_idx=space->intersection_query_subindex_results[i];
+ Transform inv_xform = col_obj->get_shape_inv_transform(shape_idx) * col_obj->get_inv_transform();
+
+ Vector3 local_from = inv_xform.xform(begin);
+ Vector3 local_to = inv_xform.xform(end);
+
+ const ShapeSW *shape = col_obj->get_shape(shape_idx);
+
+ Vector3 shape_point,shape_normal;
+
+
+ if (shape->intersect_segment(local_from,local_to,shape_point,shape_normal)) {
+
+
+
+ Transform xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
+ shape_point=xform.xform(shape_point);
+
+ real_t ld = normal.dot(shape_point);
+
+
+ if (ld<min_d) {
+
+ min_d=ld;
+ res_point=shape_point;
+ res_normal=inv_xform.basis.xform_inv(shape_normal).normalized();
+ res_shape=shape_idx;
+ res_obj=col_obj;
+ collided=true;
+ }
+ }
+
+ }
+
+ if (!collided)
+ return false;
+
+
+ r_result.collider_id=res_obj->get_instance_id();
+ if (r_result.collider_id!=0)
+ r_result.collider=ObjectDB::get_instance(r_result.collider_id);
+ else
+ r_result.collider=NULL;
+ r_result.normal=res_normal;
+ r_result.position=res_point;
+ r_result.rid=res_obj->get_self();
+ r_result.shape=res_shape;
+
+ return true;
+
+}
+
+
+int PhysicsDirectSpaceStateSW::intersect_shape(const RID& p_shape, const Transform& p_xform,float p_margin,ShapeResult *r_results,int p_result_max,const Set<RID>& p_exclude,uint32_t p_layer_mask,uint32_t p_object_type_mask) {
+
+ if (p_result_max<=0)
+ return 0;
+
+ ShapeSW *shape = static_cast<PhysicsServerSW*>(PhysicsServer::get_singleton())->shape_owner.get(p_shape);
+ ERR_FAIL_COND_V(!shape,0);
+
+ AABB aabb = p_xform.xform(shape->get_aabb());
+
+ int amount = space->broadphase->cull_aabb(aabb,space->intersection_query_results,SpaceSW::INTERSECTION_QUERY_MAX,space->intersection_query_subindex_results);
+
+ bool collided=false;
+ int cc=0;
+
+ //Transform ai = p_xform.affine_inverse();
+
+ for(int i=0;i<amount;i++) {
+
+ if (cc>=p_result_max)
+ break;
+
+ if (!_match_object_type_query(space->intersection_query_results[i],p_layer_mask,p_object_type_mask))
+ continue;
+
+ //area cant be picked by ray (default)
+
+ if (p_exclude.has( space->intersection_query_results[i]->get_self()))
+ continue;
+
+
+ const CollisionObjectSW *col_obj=space->intersection_query_results[i];
+ int shape_idx=space->intersection_query_subindex_results[i];
+
+ if (!CollisionSolverSW::solve_static(shape,p_xform,col_obj->get_shape(shape_idx),col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), NULL,NULL,NULL,p_margin,0))
+ continue;
+
+ if (r_results) {
+ r_results[cc].collider_id=col_obj->get_instance_id();
+ if (r_results[cc].collider_id!=0)
+ r_results[cc].collider=ObjectDB::get_instance(r_results[cc].collider_id);
+ else
+ r_results[cc].collider=NULL;
+ r_results[cc].rid=col_obj->get_self();
+ r_results[cc].shape=shape_idx;
+ }
+
+ cc++;
+
+ }
+
+ return cc;
+
+}
+
+
+bool PhysicsDirectSpaceStateSW::cast_motion(const RID& p_shape, const Transform& p_xform,const Vector3& p_motion,float p_margin,float &p_closest_safe,float &p_closest_unsafe, const Set<RID>& p_exclude,uint32_t p_layer_mask,uint32_t p_object_type_mask,ShapeRestInfo *r_info) {
+
+
+
+ ShapeSW *shape = static_cast<PhysicsServerSW*>(PhysicsServer::get_singleton())->shape_owner.get(p_shape);
+ ERR_FAIL_COND_V(!shape,false);
+
+ AABB aabb = p_xform.xform(shape->get_aabb());
+ aabb=aabb.merge(AABB(aabb.pos+p_motion,aabb.size)); //motion
+ aabb=aabb.grow(p_margin);
+
+ //if (p_motion!=Vector3())
+ // print_line(p_motion);
+
+ int amount = space->broadphase->cull_aabb(aabb,space->intersection_query_results,SpaceSW::INTERSECTION_QUERY_MAX,space->intersection_query_subindex_results);
+
+ float best_safe=1;
+ float best_unsafe=1;
+
+ Transform xform_inv = p_xform.affine_inverse();
+ MotionShapeSW mshape;
+ mshape.shape=shape;
+ mshape.motion=xform_inv.basis.xform(p_motion);
+
+ bool best_first=true;
+
+ Vector3 closest_A,closest_B;
+
+ for(int i=0;i<amount;i++) {
+
+
+ if (!_match_object_type_query(space->intersection_query_results[i],p_layer_mask,p_object_type_mask))
+ continue;
+
+ if (p_exclude.has( space->intersection_query_results[i]->get_self()))
+ continue; //ignore excluded
+
+
+ const CollisionObjectSW *col_obj=space->intersection_query_results[i];
+ int shape_idx=space->intersection_query_subindex_results[i];
+
+ Vector3 point_A,point_B;
+ Vector3 sep_axis=p_motion.normalized();
+
+ Transform col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
+ //test initial overlap, does it collide if going all the way?
+ if (CollisionSolverSW::solve_distance(&mshape,p_xform,col_obj->get_shape(shape_idx),col_obj_xform,point_A,point_B,aabb,&sep_axis)) {
+ //print_line("failed motion cast (no collision)");
+ continue;
+ }
+
+
+ //test initial overlap
+#if 0
+ if (CollisionSolverSW::solve_static(shape,p_xform,col_obj->get_shape(shape_idx),col_obj_xform,NULL,NULL,&sep_axis)) {
+ print_line("failed initial cast (collision at begining)");
+ return false;
+ }
+#else
+ sep_axis=p_motion.normalized();
+
+ if (!CollisionSolverSW::solve_distance(shape,p_xform,col_obj->get_shape(shape_idx),col_obj_xform,point_A,point_B,aabb,&sep_axis)) {
+ //print_line("failed motion cast (no collision)");
+ return false;
+ }
+#endif
+
+
+ //just do kinematic solving
+ float low=0;
+ float hi=1;
+ Vector3 mnormal=p_motion.normalized();
+
+ for(int i=0;i<8;i++) { //steps should be customizable..
+
+ Transform xfa = p_xform;
+ float ofs = (low+hi)*0.5;
+
+ Vector3 sep=mnormal; //important optimization for this to work fast enough
+
+ mshape.motion=xform_inv.basis.xform(p_motion*ofs);
+
+ Vector3 lA,lB;
+
+ bool collided = !CollisionSolverSW::solve_distance(&mshape,p_xform,col_obj->get_shape(shape_idx),col_obj_xform,lA,lB,aabb,&sep);
+
+ if (collided) {
+
+ //print_line(itos(i)+": "+rtos(ofs));
+ hi=ofs;
+ } else {
+
+ point_A=lA;
+ point_B=lB;
+ low=ofs;
+ }
+ }
+
+ if (low<best_safe) {
+ best_first=true; //force reset
+ best_safe=low;
+ best_unsafe=hi;
+ }
+
+ if (r_info && (best_first || (point_A.distance_squared_to(point_B) < closest_A.distance_squared_to(closest_B) && low<=best_safe))) {
+ closest_A=point_A;
+ closest_B=point_B;
+ r_info->collider_id=col_obj->get_instance_id();
+ r_info->rid=col_obj->get_self();
+ r_info->shape=shape_idx;
+ r_info->point=closest_B;
+ r_info->normal=(closest_A-closest_B).normalized();
+ best_first=false;
+ if (col_obj->get_type()==CollisionObjectSW::TYPE_BODY) {
+ const BodySW *body=static_cast<const BodySW*>(col_obj);
+ r_info->linear_velocity= body->get_linear_velocity() + (body->get_angular_velocity()).cross(body->get_transform().origin - closest_B);
+ }
+
+ }
+
+
+ }
+
+ p_closest_safe=best_safe;
+ p_closest_unsafe=best_unsafe;
+
+ return true;
+}
+
+bool PhysicsDirectSpaceStateSW::collide_shape(RID p_shape, const Transform& p_shape_xform,float p_margin,Vector3 *r_results,int p_result_max,int &r_result_count, const Set<RID>& p_exclude,uint32_t p_layer_mask,uint32_t p_object_type_mask){
+
+ if (p_result_max<=0)
+ return 0;
+
+ ShapeSW *shape = static_cast<PhysicsServerSW*>(PhysicsServer::get_singleton())->shape_owner.get(p_shape);
+ ERR_FAIL_COND_V(!shape,0);
+
+ AABB aabb = p_shape_xform.xform(shape->get_aabb());
+ aabb=aabb.grow(p_margin);
+
+ int amount = space->broadphase->cull_aabb(aabb,space->intersection_query_results,SpaceSW::INTERSECTION_QUERY_MAX,space->intersection_query_subindex_results);
+
+ bool collided=false;
+ int cc=0;
+ r_result_count=0;
+
+ PhysicsServerSW::CollCbkData cbk;
+ cbk.max=p_result_max;
+ cbk.amount=0;
+ cbk.ptr=r_results;
+ CollisionSolverSW::CallbackResult cbkres=NULL;
+
+ PhysicsServerSW::CollCbkData *cbkptr=NULL;
+ if (p_result_max>0) {
+ cbkptr=&cbk;
+ cbkres=PhysicsServerSW::_shape_col_cbk;
+ }
+
+
+ for(int i=0;i<amount;i++) {
+
+ if (!_match_object_type_query(space->intersection_query_results[i],p_layer_mask,p_object_type_mask))
+ continue;
+
+ const CollisionObjectSW *col_obj=space->intersection_query_results[i];
+ int shape_idx=space->intersection_query_subindex_results[i];
+
+ if (p_exclude.has( col_obj->get_self() )) {
+ continue;
+ }
+
+ //print_line("AGAINST: "+itos(col_obj->get_self().get_id())+":"+itos(shape_idx));
+ //print_line("THE ABBB: "+(col_obj->get_transform() * col_obj->get_shape_transform(shape_idx)).xform(col_obj->get_shape(shape_idx)->get_aabb()));
+
+ if (CollisionSolverSW::solve_static(shape,p_shape_xform,col_obj->get_shape(shape_idx),col_obj->get_transform() * col_obj->get_shape_transform(shape_idx),cbkres,cbkptr,NULL,p_margin)) {
+ collided=true;
+ }
+
+ }
+
+ r_result_count=cbk.amount;
+
+ return collided;
+
+}
+
+
+struct _RestCallbackData {
+
+ const CollisionObjectSW *object;
+ const CollisionObjectSW *best_object;
+ int shape;
+ int best_shape;
+ Vector3 best_contact;
+ Vector3 best_normal;
+ float best_len;
+};
+
+static void _rest_cbk_result(const Vector3& p_point_A,const Vector3& p_point_B,void *p_userdata) {
+
+
+ _RestCallbackData *rd=(_RestCallbackData*)p_userdata;
+
+ Vector3 contact_rel = p_point_B - p_point_A;
+ float len = contact_rel.length();
+ if (len <= rd->best_len)
+ return;
+
+ rd->best_len=len;
+ rd->best_contact=p_point_B;
+ rd->best_normal=contact_rel/len;
+ rd->best_object=rd->object;
+ rd->best_shape=rd->shape;
+
+}
+bool PhysicsDirectSpaceStateSW::rest_info(RID p_shape, const Transform& p_shape_xform,float p_margin,ShapeRestInfo *r_info, const Set<RID>& p_exclude,uint32_t p_layer_mask,uint32_t p_object_type_mask) {
+
+
+ ShapeSW *shape = static_cast<PhysicsServerSW*>(PhysicsServer::get_singleton())->shape_owner.get(p_shape);
+ ERR_FAIL_COND_V(!shape,0);
+
+ AABB aabb = p_shape_xform.xform(shape->get_aabb());
+ aabb=aabb.grow(p_margin);
+
+ int amount = space->broadphase->cull_aabb(aabb,space->intersection_query_results,SpaceSW::INTERSECTION_QUERY_MAX,space->intersection_query_subindex_results);
+
+ _RestCallbackData rcd;
+ rcd.best_len=0;
+ rcd.best_object=NULL;
+ rcd.best_shape=0;
+
+ for(int i=0;i<amount;i++) {
+
+
+ if (!_match_object_type_query(space->intersection_query_results[i],p_layer_mask,p_object_type_mask))
+ continue;
+
+ const CollisionObjectSW *col_obj=space->intersection_query_results[i];
+ int shape_idx=space->intersection_query_subindex_results[i];
+
+ if (p_exclude.has( col_obj->get_self() ))
+ continue;
+
+ rcd.object=col_obj;
+ rcd.shape=shape_idx;
+ bool sc = CollisionSolverSW::solve_static(shape,p_shape_xform,col_obj->get_shape(shape_idx),col_obj->get_transform() * col_obj->get_shape_transform(shape_idx),_rest_cbk_result,&rcd,NULL,p_margin);
+ if (!sc)
+ continue;
+
+
+ }
+
+ if (rcd.best_len==0)
+ return false;
+
+ r_info->collider_id=rcd.best_object->get_instance_id();
+ r_info->shape=rcd.best_shape;
+ r_info->normal=rcd.best_normal;
+ r_info->point=rcd.best_contact;
+ r_info->rid=rcd.best_object->get_self();
+ if (rcd.best_object->get_type()==CollisionObjectSW::TYPE_BODY) {
+
+ const BodySW *body = static_cast<const BodySW*>(rcd.best_object);
+ Vector3 rel_vec = r_info->point-body->get_transform().get_origin();
+ r_info->linear_velocity = body->get_linear_velocity() +
+ (body->get_angular_velocity()).cross(body->get_transform().origin-rcd.best_contact);// * mPos);
+
+
+ } else {
+ r_info->linear_velocity=Vector3();
+ }
+
+ return true;
+}
+
+
+PhysicsDirectSpaceStateSW::PhysicsDirectSpaceStateSW() {
+
+
+ space=NULL;
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+
+
+
+
+void* SpaceSW::_broadphase_pair(CollisionObjectSW *A,int p_subindex_A,CollisionObjectSW *B,int p_subindex_B,void *p_self) {
+
+ CollisionObjectSW::Type type_A=A->get_type();
+ CollisionObjectSW::Type type_B=B->get_type();
+ if (type_A>type_B) {
+
+ SWAP(A,B);
+ SWAP(p_subindex_A,p_subindex_B);
+ SWAP(type_A,type_B);
+ }
+
+ SpaceSW *self = (SpaceSW*)p_self;
+
+ self->collision_pairs++;
+
+ if (type_A==CollisionObjectSW::TYPE_AREA) {
+
+ AreaSW *area=static_cast<AreaSW*>(A);
+ if (type_B==CollisionObjectSW::TYPE_AREA) {
+
+ AreaSW *area_b=static_cast<AreaSW*>(B);
+ Area2PairSW *area2_pair = memnew(Area2PairSW(area_b,p_subindex_B,area,p_subindex_A) );
+ return area2_pair;
+ } else {
+
+ BodySW *body=static_cast<BodySW*>(B);
+ AreaPairSW *area_pair = memnew(AreaPairSW(body,p_subindex_B,area,p_subindex_A) );
+ return area_pair;
+ }
+ } else {
+
+
+ BodyPairSW *b = memnew( BodyPairSW((BodySW*)A,p_subindex_A,(BodySW*)B,p_subindex_B) );
+ return b;
+
+ }
+
+ return NULL;
+}
+
+void SpaceSW::_broadphase_unpair(CollisionObjectSW *A,int p_subindex_A,CollisionObjectSW *B,int p_subindex_B,void *p_data,void *p_self) {
+
+
+
+ SpaceSW *self = (SpaceSW*)p_self;
+ self->collision_pairs--;
+ ConstraintSW *c = (ConstraintSW*)p_data;
+ memdelete(c);
+}
+
+
+const SelfList<BodySW>::List& SpaceSW::get_active_body_list() const {
+
+ return active_list;
+}
+void SpaceSW::body_add_to_active_list(SelfList<BodySW>* p_body) {
+
+ active_list.add(p_body);
+}
+void SpaceSW::body_remove_from_active_list(SelfList<BodySW>* p_body) {
+
+ active_list.remove(p_body);
+
+}
+
+void SpaceSW::body_add_to_inertia_update_list(SelfList<BodySW>* p_body) {
+
+
+ inertia_update_list.add(p_body);
+}
+
+void SpaceSW::body_remove_from_inertia_update_list(SelfList<BodySW>* p_body) {
+
+ inertia_update_list.remove(p_body);
+}
+
+BroadPhaseSW *SpaceSW::get_broadphase() {
+
+ return broadphase;
+}
+
+void SpaceSW::add_object(CollisionObjectSW *p_object) {
+
+ ERR_FAIL_COND( objects.has(p_object) );
+ objects.insert(p_object);
+}
+
+void SpaceSW::remove_object(CollisionObjectSW *p_object) {
+
+ ERR_FAIL_COND( !objects.has(p_object) );
+ objects.erase(p_object);
+}
+
+const Set<CollisionObjectSW*> &SpaceSW::get_objects() const {
+
+ return objects;
+}
+
+void SpaceSW::body_add_to_state_query_list(SelfList<BodySW>* p_body) {
+
+ state_query_list.add(p_body);
+}
+void SpaceSW::body_remove_from_state_query_list(SelfList<BodySW>* p_body) {
+
+ state_query_list.remove(p_body);
+}
+
+void SpaceSW::area_add_to_monitor_query_list(SelfList<AreaSW>* p_area) {
+
+ monitor_query_list.add(p_area);
+}
+void SpaceSW::area_remove_from_monitor_query_list(SelfList<AreaSW>* p_area) {
+
+ monitor_query_list.remove(p_area);
+}
+
+void SpaceSW::area_add_to_moved_list(SelfList<AreaSW>* p_area) {
+
+ area_moved_list.add(p_area);
+}
+
+void SpaceSW::area_remove_from_moved_list(SelfList<AreaSW>* p_area) {
+
+ area_moved_list.remove(p_area);
+}
+
+const SelfList<AreaSW>::List& SpaceSW::get_moved_area_list() const {
+
+ return area_moved_list;
+}
+
+
+
+
+void SpaceSW::call_queries() {
+
+ while(state_query_list.first()) {
+
+ BodySW * b = state_query_list.first()->self();
+ b->call_queries();
+ state_query_list.remove(state_query_list.first());
+ }
+
+ while(monitor_query_list.first()) {
+
+ AreaSW * a = monitor_query_list.first()->self();
+ a->call_queries();
+ monitor_query_list.remove(monitor_query_list.first());
+ }
+
+}
+
+void SpaceSW::setup() {
+
+ contact_debug_count=0;
+ while(inertia_update_list.first()) {
+ inertia_update_list.first()->self()->update_inertias();
+ inertia_update_list.remove(inertia_update_list.first());
+ }
+
+
+}
+
+void SpaceSW::update() {
+
+
+ broadphase->update();
+
+}
+
+
+void SpaceSW::set_param(PhysicsServer::SpaceParameter p_param, real_t p_value) {
+
+ switch(p_param) {
+
+ case PhysicsServer::SPACE_PARAM_CONTACT_RECYCLE_RADIUS: contact_recycle_radius=p_value; break;
+ case PhysicsServer::SPACE_PARAM_CONTACT_MAX_SEPARATION: contact_max_separation=p_value; break;
+ case PhysicsServer::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION: contact_max_allowed_penetration=p_value; break;
+ case PhysicsServer::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_TRESHOLD: body_linear_velocity_sleep_threshold=p_value; break;
+ case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_TRESHOLD: body_angular_velocity_sleep_threshold=p_value; break;
+ case PhysicsServer::SPACE_PARAM_BODY_TIME_TO_SLEEP: body_time_to_sleep=p_value; break;
+ case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO: body_angular_velocity_damp_ratio=p_value; break;
+ case PhysicsServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: constraint_bias=p_value; break;
+ }
+}
+
+real_t SpaceSW::get_param(PhysicsServer::SpaceParameter p_param) const {
+
+ switch(p_param) {
+
+ case PhysicsServer::SPACE_PARAM_CONTACT_RECYCLE_RADIUS: return contact_recycle_radius;
+ case PhysicsServer::SPACE_PARAM_CONTACT_MAX_SEPARATION: return contact_max_separation;
+ case PhysicsServer::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION: return contact_max_allowed_penetration;
+ case PhysicsServer::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_TRESHOLD: return body_linear_velocity_sleep_threshold;
+ case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_TRESHOLD: return body_angular_velocity_sleep_threshold;
+ case PhysicsServer::SPACE_PARAM_BODY_TIME_TO_SLEEP: return body_time_to_sleep;
+ case PhysicsServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO: return body_angular_velocity_damp_ratio;
+ case PhysicsServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: return constraint_bias;
+ }
+ return 0;
+}
+
+void SpaceSW::lock() {
+
+ locked=true;
+}
+
+void SpaceSW::unlock() {
+
+ locked=false;
+}
+
+bool SpaceSW::is_locked() const {
+
+ return locked;
+}
+
+PhysicsDirectSpaceStateSW *SpaceSW::get_direct_state() {
+
+ return direct_access;
+}
+
+SpaceSW::SpaceSW() {
+
+ collision_pairs=0;
+ active_objects=0;
+ island_count=0;
+ contact_debug_count=0;
+
+ locked=false;
+ contact_recycle_radius=0.01;
+ contact_max_separation=0.05;
+ contact_max_allowed_penetration= 0.01;
+
+ constraint_bias = 0.01;
+ body_linear_velocity_sleep_threshold=GLOBAL_DEF("physics/sleep_threshold_linear",0.1);
+ body_angular_velocity_sleep_threshold=GLOBAL_DEF("physics/sleep_threshold_angular", (8.0 / 180.0 * Math_PI) );
+ body_time_to_sleep=0.5;
+ body_angular_velocity_damp_ratio=10;
+
+
+ broadphase = BroadPhaseSW::create_func();
+ broadphase->set_pair_callback(_broadphase_pair,this);
+ broadphase->set_unpair_callback(_broadphase_unpair,this);
+ area=NULL;
+
+ direct_access = memnew( PhysicsDirectSpaceStateSW );
+ direct_access->space=this;
+}
+
+SpaceSW::~SpaceSW() {
+
+ memdelete(broadphase);
+ memdelete( direct_access );
+}
+
+
+
diff --git a/servers/physics/space_sw.h b/servers/physics/space_sw.h
index 16f5ad3c81..6300c206d8 100644
--- a/servers/physics/space_sw.h
+++ b/servers/physics/space_sw.h
@@ -1,179 +1,187 @@
-/*************************************************************************/
-/* space_sw.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* http://www.godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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. */
-/*************************************************************************/
-#ifndef SPACE_SW_H
-#define SPACE_SW_H
-
-#include "typedefs.h"
-#include "hash_map.h"
-#include "body_sw.h"
-#include "area_sw.h"
-#include "body_pair_sw.h"
-#include "area_pair_sw.h"
-#include "broad_phase_sw.h"
-#include "collision_object_sw.h"
-
-
-class PhysicsDirectSpaceStateSW : public PhysicsDirectSpaceState {
-
- OBJ_TYPE( PhysicsDirectSpaceStateSW, PhysicsDirectSpaceState );
-public:
-
- SpaceSW *space;
-
- virtual bool intersect_ray(const Vector3& p_from, const Vector3& p_to,RayResult &r_result,const Set<RID>& p_exclude=Set<RID>(),uint32_t p_layer_mask=0xFFFFFFFF,uint32_t p_object_type_mask=TYPE_MASK_COLLISION);
- virtual int intersect_shape(const RID& p_shape, const Transform& p_xform,float p_margin,ShapeResult *r_results,int p_result_max,const Set<RID>& p_exclude=Set<RID>(),uint32_t p_layer_mask=0xFFFFFFFF,uint32_t p_object_type_mask=TYPE_MASK_COLLISION);
- virtual bool cast_motion(const RID& p_shape, const Transform& p_xform,const Vector3& p_motion,float p_margin,float &p_closest_safe,float &p_closest_unsafe, const Set<RID>& p_exclude=Set<RID>(),uint32_t p_layer_mask=0xFFFFFFFF,uint32_t p_object_type_mask=TYPE_MASK_COLLISION,ShapeRestInfo *r_info=NULL);
- virtual bool collide_shape(RID p_shape, const Transform& p_shape_xform,float p_margin,Vector3 *r_results,int p_result_max,int &r_result_count, const Set<RID>& p_exclude=Set<RID>(),uint32_t p_layer_mask=0xFFFFFFFF,uint32_t p_object_type_mask=TYPE_MASK_COLLISION);
- virtual bool rest_info(RID p_shape, const Transform& p_shape_xform,float p_margin,ShapeRestInfo *r_info, const Set<RID>& p_exclude=Set<RID>(),uint32_t p_layer_mask=0xFFFFFFFF,uint32_t p_object_type_mask=TYPE_MASK_COLLISION);
-
- PhysicsDirectSpaceStateSW();
-};
-
-
-
-class SpaceSW {
-
-
- PhysicsDirectSpaceStateSW *direct_access;
- RID self;
-
- BroadPhaseSW *broadphase;
- SelfList<BodySW>::List active_list;
- SelfList<BodySW>::List inertia_update_list;
- SelfList<BodySW>::List state_query_list;
- SelfList<AreaSW>::List monitor_query_list;
- SelfList<AreaSW>::List area_moved_list;
-
- static void* _broadphase_pair(CollisionObjectSW *A,int p_subindex_A,CollisionObjectSW *B,int p_subindex_B,void *p_self);
- static void _broadphase_unpair(CollisionObjectSW *A,int p_subindex_A,CollisionObjectSW *B,int p_subindex_B,void *p_data,void *p_self);
-
- Set<CollisionObjectSW*> objects;
-
- AreaSW *area;
-
- real_t contact_recycle_radius;
- real_t contact_max_separation;
- real_t contact_max_allowed_penetration;
- real_t constraint_bias;
-
- enum {
-
- INTERSECTION_QUERY_MAX=2048
- };
-
- CollisionObjectSW *intersection_query_results[INTERSECTION_QUERY_MAX];
- int intersection_query_subindex_results[INTERSECTION_QUERY_MAX];
-
- float body_linear_velocity_sleep_threshold;
- float body_angular_velocity_sleep_threshold;
- float body_time_to_sleep;
- float body_angular_velocity_damp_ratio;
-
- bool locked;
-
- int island_count;
- int active_objects;
- int collision_pairs;
-
- RID static_global_body;
-
-friend class PhysicsDirectSpaceStateSW;
-
-public:
-
- _FORCE_INLINE_ void set_self(const RID& p_self) { self=p_self; }
- _FORCE_INLINE_ RID get_self() const { return self; }
-
- void set_default_area(AreaSW *p_area) { area=p_area; }
- AreaSW *get_default_area() const { return area; }
-
- const SelfList<BodySW>::List& get_active_body_list() const;
- void body_add_to_active_list(SelfList<BodySW>* p_body);
- void body_remove_from_active_list(SelfList<BodySW>* p_body);
- void body_add_to_inertia_update_list(SelfList<BodySW>* p_body);
- void body_remove_from_inertia_update_list(SelfList<BodySW>* p_body);
-
- void body_add_to_state_query_list(SelfList<BodySW>* p_body);
- void body_remove_from_state_query_list(SelfList<BodySW>* p_body);
-
- void area_add_to_monitor_query_list(SelfList<AreaSW>* p_area);
- void area_remove_from_monitor_query_list(SelfList<AreaSW>* p_area);
- void area_add_to_moved_list(SelfList<AreaSW>* p_area);
- void area_remove_from_moved_list(SelfList<AreaSW>* p_area);
- const SelfList<AreaSW>::List& get_moved_area_list() const;
-
- BroadPhaseSW *get_broadphase();
-
- void add_object(CollisionObjectSW *p_object);
- void remove_object(CollisionObjectSW *p_object);
- const Set<CollisionObjectSW*> &get_objects() const;
-
- _FORCE_INLINE_ real_t get_contact_recycle_radius() const { return contact_recycle_radius; }
- _FORCE_INLINE_ real_t get_contact_max_separation() const { return contact_max_separation; }
- _FORCE_INLINE_ real_t get_contact_max_allowed_penetration() const { return contact_max_allowed_penetration; }
- _FORCE_INLINE_ real_t get_constraint_bias() const { return constraint_bias; }
- _FORCE_INLINE_ real_t get_body_linear_velocity_sleep_treshold() const { return body_linear_velocity_sleep_threshold; }
- _FORCE_INLINE_ real_t get_body_angular_velocity_sleep_treshold() const { return body_angular_velocity_sleep_threshold; }
- _FORCE_INLINE_ real_t get_body_time_to_sleep() const { return body_time_to_sleep; }
- _FORCE_INLINE_ real_t get_body_angular_velocity_damp_ratio() const { return body_angular_velocity_damp_ratio; }
-
-
- void update();
- void setup();
- void call_queries();
-
-
- bool is_locked() const;
- void lock();
- void unlock();
-
- void set_param(PhysicsServer::SpaceParameter p_param, real_t p_value);
- real_t get_param(PhysicsServer::SpaceParameter p_param) const;
-
- void set_island_count(int p_island_count) { island_count=p_island_count; }
- int get_island_count() const { return island_count; }
-
- void set_active_objects(int p_active_objects) { active_objects=p_active_objects; }
- int get_active_objects() const { return active_objects; }
-
- int get_collision_pairs() const { return collision_pairs; }
-
- PhysicsDirectSpaceStateSW *get_direct_state();
-
-
- void set_static_global_body(RID p_body) { static_global_body=p_body; }
- RID get_static_global_body() { return static_global_body; }
-
-
- SpaceSW();
- ~SpaceSW();
-};
-
-
-#endif // SPACE__SW_H
+/*************************************************************************/
+/* space_sw.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
+#ifndef SPACE_SW_H
+#define SPACE_SW_H
+
+#include "typedefs.h"
+#include "hash_map.h"
+#include "body_sw.h"
+#include "area_sw.h"
+#include "body_pair_sw.h"
+#include "area_pair_sw.h"
+#include "broad_phase_sw.h"
+#include "collision_object_sw.h"
+
+
+class PhysicsDirectSpaceStateSW : public PhysicsDirectSpaceState {
+
+ OBJ_TYPE( PhysicsDirectSpaceStateSW, PhysicsDirectSpaceState );
+public:
+
+ SpaceSW *space;
+
+ virtual bool intersect_ray(const Vector3& p_from, const Vector3& p_to,RayResult &r_result,const Set<RID>& p_exclude=Set<RID>(),uint32_t p_layer_mask=0xFFFFFFFF,uint32_t p_object_type_mask=TYPE_MASK_COLLISION,bool p_pick_ray=false);
+ virtual int intersect_shape(const RID& p_shape, const Transform& p_xform,float p_margin,ShapeResult *r_results,int p_result_max,const Set<RID>& p_exclude=Set<RID>(),uint32_t p_layer_mask=0xFFFFFFFF,uint32_t p_object_type_mask=TYPE_MASK_COLLISION);
+ virtual bool cast_motion(const RID& p_shape, const Transform& p_xform,const Vector3& p_motion,float p_margin,float &p_closest_safe,float &p_closest_unsafe, const Set<RID>& p_exclude=Set<RID>(),uint32_t p_layer_mask=0xFFFFFFFF,uint32_t p_object_type_mask=TYPE_MASK_COLLISION,ShapeRestInfo *r_info=NULL);
+ virtual bool collide_shape(RID p_shape, const Transform& p_shape_xform,float p_margin,Vector3 *r_results,int p_result_max,int &r_result_count, const Set<RID>& p_exclude=Set<RID>(),uint32_t p_layer_mask=0xFFFFFFFF,uint32_t p_object_type_mask=TYPE_MASK_COLLISION);
+ virtual bool rest_info(RID p_shape, const Transform& p_shape_xform,float p_margin,ShapeRestInfo *r_info, const Set<RID>& p_exclude=Set<RID>(),uint32_t p_layer_mask=0xFFFFFFFF,uint32_t p_object_type_mask=TYPE_MASK_COLLISION);
+
+ PhysicsDirectSpaceStateSW();
+};
+
+
+
+class SpaceSW {
+
+
+ PhysicsDirectSpaceStateSW *direct_access;
+ RID self;
+
+ BroadPhaseSW *broadphase;
+ SelfList<BodySW>::List active_list;
+ SelfList<BodySW>::List inertia_update_list;
+ SelfList<BodySW>::List state_query_list;
+ SelfList<AreaSW>::List monitor_query_list;
+ SelfList<AreaSW>::List area_moved_list;
+
+ static void* _broadphase_pair(CollisionObjectSW *A,int p_subindex_A,CollisionObjectSW *B,int p_subindex_B,void *p_self);
+ static void _broadphase_unpair(CollisionObjectSW *A,int p_subindex_A,CollisionObjectSW *B,int p_subindex_B,void *p_data,void *p_self);
+
+ Set<CollisionObjectSW*> objects;
+
+ AreaSW *area;
+
+ real_t contact_recycle_radius;
+ real_t contact_max_separation;
+ real_t contact_max_allowed_penetration;
+ real_t constraint_bias;
+
+ enum {
+
+ INTERSECTION_QUERY_MAX=2048
+ };
+
+ CollisionObjectSW *intersection_query_results[INTERSECTION_QUERY_MAX];
+ int intersection_query_subindex_results[INTERSECTION_QUERY_MAX];
+
+ float body_linear_velocity_sleep_threshold;
+ float body_angular_velocity_sleep_threshold;
+ float body_time_to_sleep;
+ float body_angular_velocity_damp_ratio;
+
+ bool locked;
+
+ int island_count;
+ int active_objects;
+ int collision_pairs;
+
+ RID static_global_body;
+
+ Vector<Vector3> contact_debug;
+ int contact_debug_count;
+
+friend class PhysicsDirectSpaceStateSW;
+
+public:
+
+ _FORCE_INLINE_ void set_self(const RID& p_self) { self=p_self; }
+ _FORCE_INLINE_ RID get_self() const { return self; }
+
+ void set_default_area(AreaSW *p_area) { area=p_area; }
+ AreaSW *get_default_area() const { return area; }
+
+ const SelfList<BodySW>::List& get_active_body_list() const;
+ void body_add_to_active_list(SelfList<BodySW>* p_body);
+ void body_remove_from_active_list(SelfList<BodySW>* p_body);
+ void body_add_to_inertia_update_list(SelfList<BodySW>* p_body);
+ void body_remove_from_inertia_update_list(SelfList<BodySW>* p_body);
+
+ void body_add_to_state_query_list(SelfList<BodySW>* p_body);
+ void body_remove_from_state_query_list(SelfList<BodySW>* p_body);
+
+ void area_add_to_monitor_query_list(SelfList<AreaSW>* p_area);
+ void area_remove_from_monitor_query_list(SelfList<AreaSW>* p_area);
+ void area_add_to_moved_list(SelfList<AreaSW>* p_area);
+ void area_remove_from_moved_list(SelfList<AreaSW>* p_area);
+ const SelfList<AreaSW>::List& get_moved_area_list() const;
+
+ BroadPhaseSW *get_broadphase();
+
+ void add_object(CollisionObjectSW *p_object);
+ void remove_object(CollisionObjectSW *p_object);
+ const Set<CollisionObjectSW*> &get_objects() const;
+
+ _FORCE_INLINE_ real_t get_contact_recycle_radius() const { return contact_recycle_radius; }
+ _FORCE_INLINE_ real_t get_contact_max_separation() const { return contact_max_separation; }
+ _FORCE_INLINE_ real_t get_contact_max_allowed_penetration() const { return contact_max_allowed_penetration; }
+ _FORCE_INLINE_ real_t get_constraint_bias() const { return constraint_bias; }
+ _FORCE_INLINE_ real_t get_body_linear_velocity_sleep_treshold() const { return body_linear_velocity_sleep_threshold; }
+ _FORCE_INLINE_ real_t get_body_angular_velocity_sleep_treshold() const { return body_angular_velocity_sleep_threshold; }
+ _FORCE_INLINE_ real_t get_body_time_to_sleep() const { return body_time_to_sleep; }
+ _FORCE_INLINE_ real_t get_body_angular_velocity_damp_ratio() const { return body_angular_velocity_damp_ratio; }
+
+
+ void update();
+ void setup();
+ void call_queries();
+
+
+ bool is_locked() const;
+ void lock();
+ void unlock();
+
+ void set_param(PhysicsServer::SpaceParameter p_param, real_t p_value);
+ real_t get_param(PhysicsServer::SpaceParameter p_param) const;
+
+ void set_island_count(int p_island_count) { island_count=p_island_count; }
+ int get_island_count() const { return island_count; }
+
+ void set_active_objects(int p_active_objects) { active_objects=p_active_objects; }
+ int get_active_objects() const { return active_objects; }
+
+ int get_collision_pairs() const { return collision_pairs; }
+
+ PhysicsDirectSpaceStateSW *get_direct_state();
+
+ void set_debug_contacts(int p_amount) { contact_debug.resize(p_amount); }
+ _FORCE_INLINE_ bool is_debugging_contacts() const { return !contact_debug.empty(); }
+ _FORCE_INLINE_ void add_debug_contact(const Vector3& p_contact) { if (contact_debug_count<contact_debug.size()) contact_debug[contact_debug_count++]=p_contact; }
+ _FORCE_INLINE_ Vector<Vector3> get_debug_contacts() { return contact_debug; }
+ _FORCE_INLINE_ int get_debug_contact_count() { return contact_debug_count; }
+
+ void set_static_global_body(RID p_body) { static_global_body=p_body; }
+ RID get_static_global_body() { return static_global_body; }
+
+
+ SpaceSW();
+ ~SpaceSW();
+};
+
+
+#endif // SPACE__SW_H
diff --git a/servers/physics/step_sw.cpp b/servers/physics/step_sw.cpp
index 2424b36833..f10dadf81a 100644
--- a/servers/physics/step_sw.cpp
+++ b/servers/physics/step_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics/step_sw.h b/servers/physics/step_sw.h
index f089c041fc..f6362f3777 100644
--- a/servers/physics/step_sw.h
+++ b/servers/physics/step_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics_2d/SCsub b/servers/physics_2d/SCsub
index a2c2b51a61..ebb7f8be00 100644
--- a/servers/physics_2d/SCsub
+++ b/servers/physics_2d/SCsub
@@ -1,4 +1,3 @@
Import('env')
env.add_source_files(env.servers_sources,"*.cpp")
-
diff --git a/servers/physics_2d/area_2d_sw.cpp b/servers/physics_2d/area_2d_sw.cpp
index 1a41cda482..759a37e84f 100644
--- a/servers/physics_2d/area_2d_sw.cpp
+++ b/servers/physics_2d/area_2d_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -82,6 +82,10 @@ void Area2DSW::set_monitor_callback(ObjectID p_id, const StringName& p_method) {
_shape_changed();
+ if (!moved_list.in_list() && get_space())
+ get_space()->area_add_to_moved_list(&moved_list);
+
+
}
void Area2DSW::set_area_monitor_callback(ObjectID p_id, const StringName& p_method) {
@@ -102,6 +106,10 @@ void Area2DSW::set_area_monitor_callback(ObjectID p_id, const StringName& p_meth
_shape_changed();
+ if (!moved_list.in_list() && get_space())
+ get_space()->area_add_to_moved_list(&moved_list);
+
+
}
diff --git a/servers/physics_2d/area_2d_sw.h b/servers/physics_2d/area_2d_sw.h
index 6d99764c68..71192db1df 100644
--- a/servers/physics_2d/area_2d_sw.h
+++ b/servers/physics_2d/area_2d_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics_2d/area_pair_2d_sw.cpp b/servers/physics_2d/area_pair_2d_sw.cpp
index 3b1705bd56..0682d8abdd 100644
--- a/servers/physics_2d/area_pair_2d_sw.cpp
+++ b/servers/physics_2d/area_pair_2d_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics_2d/area_pair_2d_sw.h b/servers/physics_2d/area_pair_2d_sw.h
index 59113c9162..a03bdb572a 100644
--- a/servers/physics_2d/area_pair_2d_sw.h
+++ b/servers/physics_2d/area_pair_2d_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp
index 38835c9a82..f1f94f3485 100644
--- a/servers/physics_2d/body_2d_sw.cpp
+++ b/servers/physics_2d/body_2d_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,6 +29,7 @@
#include "body_2d_sw.h"
#include "space_2d_sw.h"
#include "area_2d_sw.h"
+#include "physics_2d_server_sw.h"
void Body2DSW::_update_inertia() {
@@ -378,9 +379,10 @@ void Body2DSW::set_space(Space2DSW *p_space){
}
+ first_integration=false;
}
-void Body2DSW::_compute_area_gravity(const Area2DSW *p_area) {
+void Body2DSW::_compute_area_gravity_and_dampenings(const Area2DSW *p_area) {
if (p_area->is_gravity_point()) {
if(p_area->get_gravity_distance_scale() > 0) {
@@ -393,6 +395,8 @@ void Body2DSW::_compute_area_gravity(const Area2DSW *p_area) {
gravity += p_area->get_gravity_vector() * p_area->get_gravity();
}
+ area_linear_damp += p_area->get_linear_damp();
+ area_angular_damp += p_area->get_angular_damp();
}
void Body2DSW::integrate_forces(real_t p_step) {
@@ -401,38 +405,53 @@ void Body2DSW::integrate_forces(real_t p_step) {
return;
Area2DSW *def_area = get_space()->get_default_area();
- Area2DSW *damp_area = def_area;
+ // Area2DSW *damp_area = def_area;
ERR_FAIL_COND(!def_area);
int ac = areas.size();
- bool replace = false;
- gravity=Vector2(0,0);
+ bool stopped = false;
+ gravity = Vector2(0,0);
+ area_angular_damp = 0;
+ area_linear_damp = 0;
if (ac) {
areas.sort();
const AreaCMP *aa = &areas[0];
- damp_area = aa[ac-1].area;
- for(int i=ac-1;i>=0;i--) {
- _compute_area_gravity(aa[i].area);
- if (aa[i].area->get_space_override_mode() == Physics2DServer::AREA_SPACE_OVERRIDE_REPLACE) {
- replace = true;
- break;
+ // damp_area = aa[ac-1].area;
+ for(int i=ac-1;i>=0 && !stopped;i--) {
+ Physics2DServer::AreaSpaceOverrideMode mode=aa[i].area->get_space_override_mode();
+ switch (mode) {
+ case Physics2DServer::AREA_SPACE_OVERRIDE_COMBINE:
+ case Physics2DServer::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: {
+ _compute_area_gravity_and_dampenings(aa[i].area);
+ stopped = mode==Physics2DServer::AREA_SPACE_OVERRIDE_COMBINE_REPLACE;
+ } break;
+ case Physics2DServer::AREA_SPACE_OVERRIDE_REPLACE:
+ case Physics2DServer::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: {
+ gravity = Vector2(0,0);
+ area_angular_damp = 0;
+ area_linear_damp = 0;
+ _compute_area_gravity_and_dampenings(aa[i].area);
+ stopped = mode==Physics2DServer::AREA_SPACE_OVERRIDE_REPLACE;
+ } break;
+ default: {}
}
}
}
- if( !replace ) {
- _compute_area_gravity(def_area);
+ if( !stopped ) {
+ _compute_area_gravity_and_dampenings(def_area);
}
gravity*=gravity_scale;
+ // If less than 0, override dampenings with that of the Body2D
if (angular_damp>=0)
- area_angular_damp=angular_damp;
- else
- area_angular_damp=damp_area->get_angular_damp();
+ area_angular_damp = angular_damp;
+ //else
+ // area_angular_damp=damp_area->get_angular_damp();
if (linear_damp>=0)
- area_linear_damp=linear_damp;
- else
- area_linear_damp=damp_area->get_linear_damp();
+ area_linear_damp = linear_damp;
+ //else
+ // area_linear_damp=damp_area->get_linear_damp();
Vector2 motion;
bool do_motion=false;
@@ -442,7 +461,7 @@ void Body2DSW::integrate_forces(real_t p_step) {
//compute motion, angular and etc. velocities from prev transform
linear_velocity = (new_transform.elements[2] - get_transform().elements[2])/p_step;
- real_t rot = new_transform.affine_inverse().basis_xform(get_transform().elements[1]).atan2();
+ real_t rot = new_transform.affine_inverse().basis_xform(get_transform().elements[1]).angle();
angular_velocity = rot / p_step;
motion = new_transform.elements[2] - get_transform().elements[2];
@@ -454,7 +473,7 @@ void Body2DSW::integrate_forces(real_t p_step) {
//}
} else {
- if (!omit_force_integration) {
+ if (!omit_force_integration && !first_integration) {
//overriden by direct state query
Vector2 force=gravity*mass;
@@ -489,6 +508,7 @@ void Body2DSW::integrate_forces(real_t p_step) {
//motion=linear_velocity*p_step;
+ first_integration=false;
biased_angular_velocity=0;
biased_linear_velocity=Vector2();
@@ -496,7 +516,7 @@ void Body2DSW::integrate_forces(real_t p_step) {
_update_shapes_with_motion(motion);
}
- damp_area=NULL; // clear the area, so it is set in the next frame
+ // damp_area=NULL; // clear the area, so it is set in the next frame
def_area=NULL; // clear the area, so it is set in the next frame
contact_count=0;
@@ -664,6 +684,7 @@ Body2DSW::Body2DSW() : CollisionObject2DSW(TYPE_BODY), active_list(this), inerti
gravity_scale=1.0;
using_one_way_cache=false;
one_way_collision_max_depth=0.1;
+ first_integration=false;
still_time=0;
continuous_cd_mode=Physics2DServer::CCD_MODE_DISABLED;
@@ -684,3 +705,24 @@ Physics2DDirectSpaceState* Physics2DDirectBodyStateSW::get_space_state() {
return body->get_space()->get_direct_state();
}
+
+
+Variant Physics2DDirectBodyStateSW::get_contact_collider_shape_metadata(int p_contact_idx) const {
+
+ ERR_FAIL_INDEX_V(p_contact_idx,body->contact_count,Variant());
+
+ if (!Physics2DServerSW::singletonsw->body_owner.owns(body->contacts[p_contact_idx].collider)) {
+
+ return Variant();
+ }
+ Body2DSW *other = Physics2DServerSW::singletonsw->body_owner.get(body->contacts[p_contact_idx].collider);
+
+ int sidx = body->contacts[p_contact_idx].collider_shape;
+ if (sidx<0 || sidx>=other->get_shape_count()) {
+
+ return Variant();
+ }
+
+
+ return other->get_shape_metadata(sidx);
+}
diff --git a/servers/physics_2d/body_2d_sw.h b/servers/physics_2d/body_2d_sw.h
index c86bb51f1d..4bd462ac00 100644
--- a/servers/physics_2d/body_2d_sw.h
+++ b/servers/physics_2d/body_2d_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -81,6 +81,7 @@ class Body2DSW : public CollisionObject2DSW {
bool active;
bool can_sleep;
bool first_time_kinematic;
+ bool first_integration;
bool using_one_way_cache;
void _update_inertia();
virtual void _shapes_changed();
@@ -132,7 +133,7 @@ class Body2DSW : public CollisionObject2DSW {
Body2DSW *island_next;
Body2DSW *island_list_next;
- _FORCE_INLINE_ void _compute_area_gravity(const Area2DSW *p_area);
+ _FORCE_INLINE_ void _compute_area_gravity_and_dampenings(const Area2DSW *p_area);
friend class Physics2DDirectBodyStateSW; // i give up, too many functions to expose
@@ -337,9 +338,9 @@ public:
Body2DSW *body;
real_t step;
- virtual Vector2 get_total_gravity() const { return body->get_gravity(); } // get gravity vector working on this body space/area
- virtual float get_total_angular_damp() const { return body->get_angular_damp(); } // get density of this body space/area
- virtual float get_total_linear_damp() const { return body->get_linear_damp(); } // get density of this body space/area
+ virtual Vector2 get_total_gravity() const { return body->gravity; } // get gravity vector working on this body space/area
+ virtual float get_total_angular_damp() const { return body->area_angular_damp; } // get density of this body space/area
+ virtual float get_total_linear_damp() const { return body->area_linear_damp; } // get density of this body space/area
virtual float get_inverse_mass() const { return body->get_inv_mass(); } // get the mass
virtual real_t get_inverse_inertia() const { return body->get_inv_inertia(); } // get density of this body space
@@ -369,7 +370,7 @@ public:
virtual Vector2 get_contact_collider_pos(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx,body->contact_count,Vector2()); return body->contacts[p_contact_idx].collider_pos; }
virtual ObjectID get_contact_collider_id(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx,body->contact_count,0); return body->contacts[p_contact_idx].collider_instance_id; }
virtual int get_contact_collider_shape(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx,body->contact_count,0); return body->contacts[p_contact_idx].collider_shape; }
- virtual Variant get_contact_collider_shape_metadata(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx,body->contact_count,Variant()); return body->get_shape_metadata(body->contacts[p_contact_idx].collider_shape); }
+ virtual Variant get_contact_collider_shape_metadata(int p_contact_idx) const;
virtual Vector2 get_contact_collider_velocity_at_pos(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx,body->contact_count,Vector2()); return body->contacts[p_contact_idx].collider_velocity_at_pos; }
diff --git a/servers/physics_2d/body_pair_2d_sw.cpp b/servers/physics_2d/body_pair_2d_sw.cpp
index 6bfed134e6..db7869c6a6 100644
--- a/servers/physics_2d/body_pair_2d_sw.cpp
+++ b/servers/physics_2d/body_pair_2d_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -364,6 +364,9 @@ bool BodyPair2DSW::setup(float p_step) {
real_t inv_dt = 1.0/p_step;
+
+ bool do_process=false;
+
for (int i = 0; i < contact_count; i++) {
Contact& c = contacts[i];
@@ -379,7 +382,12 @@ bool BodyPair2DSW::setup(float p_step) {
}
c.active=true;
-
+#ifdef DEBUG_ENABLED
+ if (space->is_debugging_contacts()) {
+ space->add_debug_contact(global_A+offset_A);
+ space->add_debug_contact(global_B+offset_A);
+ }
+#endif
int gather_A = A->can_report_contacts();
int gather_B = B->can_report_contacts();
@@ -454,10 +462,11 @@ bool BodyPair2DSW::setup(float p_step) {
c.bounce = c.bounce * dv.dot(c.normal);
}
+ do_process=true;
}
- return true;
+ return do_process;
}
void BodyPair2DSW::solve(float p_step) {
diff --git a/servers/physics_2d/body_pair_2d_sw.h b/servers/physics_2d/body_pair_2d_sw.h
index a7fa287be4..a16320585e 100644
--- a/servers/physics_2d/body_pair_2d_sw.h
+++ b/servers/physics_2d/body_pair_2d_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics_2d/broad_phase_2d_basic.cpp b/servers/physics_2d/broad_phase_2d_basic.cpp
index e61b4735b9..3a95bb2411 100644
--- a/servers/physics_2d/broad_phase_2d_basic.cpp
+++ b/servers/physics_2d/broad_phase_2d_basic.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics_2d/broad_phase_2d_basic.h b/servers/physics_2d/broad_phase_2d_basic.h
index cdee77ffd7..80aa423819 100644
--- a/servers/physics_2d/broad_phase_2d_basic.h
+++ b/servers/physics_2d/broad_phase_2d_basic.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics_2d/broad_phase_2d_hash_grid.cpp b/servers/physics_2d/broad_phase_2d_hash_grid.cpp
index 4651d485c2..6a52d5fe5b 100644
--- a/servers/physics_2d/broad_phase_2d_hash_grid.cpp
+++ b/servers/physics_2d/broad_phase_2d_hash_grid.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics_2d/broad_phase_2d_hash_grid.h b/servers/physics_2d/broad_phase_2d_hash_grid.h
index a2eecf7bbf..bda5ea21cf 100644
--- a/servers/physics_2d/broad_phase_2d_hash_grid.h
+++ b/servers/physics_2d/broad_phase_2d_hash_grid.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics_2d/broad_phase_2d_sw.cpp b/servers/physics_2d/broad_phase_2d_sw.cpp
index fd8e7254b6..0dead94ca1 100644
--- a/servers/physics_2d/broad_phase_2d_sw.cpp
+++ b/servers/physics_2d/broad_phase_2d_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics_2d/broad_phase_2d_sw.h b/servers/physics_2d/broad_phase_2d_sw.h
index 283d6941e1..056ef664fd 100644
--- a/servers/physics_2d/broad_phase_2d_sw.h
+++ b/servers/physics_2d/broad_phase_2d_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics_2d/collision_object_2d_sw.cpp b/servers/physics_2d/collision_object_2d_sw.cpp
index 7c8e223c57..7f9d3312b9 100644
--- a/servers/physics_2d/collision_object_2d_sw.cpp
+++ b/servers/physics_2d/collision_object_2d_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics_2d/collision_object_2d_sw.h b/servers/physics_2d/collision_object_2d_sw.h
index f3432060b9..1f213d8444 100644
--- a/servers/physics_2d/collision_object_2d_sw.h
+++ b/servers/physics_2d/collision_object_2d_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics_2d/collision_solver_2d_sat.cpp b/servers/physics_2d/collision_solver_2d_sat.cpp
index 2525c6e942..f22b676304 100644
--- a/servers/physics_2d/collision_solver_2d_sat.cpp
+++ b/servers/physics_2d/collision_solver_2d_sat.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics_2d/collision_solver_2d_sat.h b/servers/physics_2d/collision_solver_2d_sat.h
index 554f756738..91aeb53030 100644
--- a/servers/physics_2d/collision_solver_2d_sat.h
+++ b/servers/physics_2d/collision_solver_2d_sat.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics_2d/collision_solver_2d_sw.cpp b/servers/physics_2d/collision_solver_2d_sw.cpp
index 134ad04222..d9bf235c86 100644
--- a/servers/physics_2d/collision_solver_2d_sw.cpp
+++ b/servers/physics_2d/collision_solver_2d_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics_2d/collision_solver_2d_sw.h b/servers/physics_2d/collision_solver_2d_sw.h
index 0cdd54f8b6..7e3542805c 100644
--- a/servers/physics_2d/collision_solver_2d_sw.h
+++ b/servers/physics_2d/collision_solver_2d_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics_2d/constraint_2d_sw.cpp b/servers/physics_2d/constraint_2d_sw.cpp
index 24d56ce9fe..2f681e8590 100644
--- a/servers/physics_2d/constraint_2d_sw.cpp
+++ b/servers/physics_2d/constraint_2d_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics_2d/constraint_2d_sw.h b/servers/physics_2d/constraint_2d_sw.h
index a9145c382f..f776dbfe2c 100644
--- a/servers/physics_2d/constraint_2d_sw.h
+++ b/servers/physics_2d/constraint_2d_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics_2d/joints_2d_sw.cpp b/servers/physics_2d/joints_2d_sw.cpp
index b4c149e7e0..958780c2e6 100644
--- a/servers/physics_2d/joints_2d_sw.cpp
+++ b/servers/physics_2d/joints_2d_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -279,6 +279,18 @@ void PinJoint2DSW::solve(float p_step){
P += impulse;
}
+void PinJoint2DSW::set_param(Physics2DServer::PinJointParam p_param, real_t p_value) {
+
+ if(p_param == Physics2DServer::PIN_JOINT_SOFTNESS)
+ softness = p_value;
+}
+
+real_t PinJoint2DSW::get_param(Physics2DServer::PinJointParam p_param) const {
+
+ if(p_param == Physics2DServer::PIN_JOINT_SOFTNESS)
+ return softness;
+ ERR_FAIL_V(0);
+}
PinJoint2DSW::PinJoint2DSW(const Vector2& p_pos,Body2DSW* p_body_a,Body2DSW* p_body_b) : Joint2DSW(_arr,p_body_b?2:1) {
diff --git a/servers/physics_2d/joints_2d_sw.h b/servers/physics_2d/joints_2d_sw.h
index 2093be88c9..86a1397c53 100644
--- a/servers/physics_2d/joints_2d_sw.h
+++ b/servers/physics_2d/joints_2d_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -121,6 +121,8 @@ public:
virtual bool setup(float p_step);
virtual void solve(float p_step);
+ void set_param(Physics2DServer::PinJointParam p_param, real_t p_value);
+ real_t get_param(Physics2DServer::PinJointParam p_param) const;
PinJoint2DSW(const Vector2& p_pos,Body2DSW* p_body_a,Body2DSW* p_body_b=NULL);
~PinJoint2DSW();
diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp
index b446f4928a..c571331498 100644
--- a/servers/physics_2d/physics_2d_server_sw.cpp
+++ b/servers/physics_2d/physics_2d_server_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -257,6 +257,30 @@ real_t Physics2DServerSW::space_get_param(RID p_space,SpaceParameter p_param) co
return space->get_param(p_param);
}
+void Physics2DServerSW::space_set_debug_contacts(RID p_space,int p_max_contacts) {
+
+ Space2DSW *space = space_owner.get(p_space);
+ ERR_FAIL_COND(!space);
+ space->set_debug_contacts(p_max_contacts);
+
+}
+
+Vector<Vector2> Physics2DServerSW::space_get_contacts(RID p_space) const {
+
+ Space2DSW *space = space_owner.get(p_space);
+ ERR_FAIL_COND_V(!space,Vector<Vector2>());
+ return space->get_debug_contacts();
+
+}
+
+int Physics2DServerSW::space_get_contact_count(RID p_space) const {
+
+ Space2DSW *space = space_owner.get(p_space);
+ ERR_FAIL_COND_V(!space,0);
+ return space->get_debug_contact_count();
+
+}
+
Physics2DDirectSpaceState* Physics2DServerSW::space_get_direct_state(RID p_space) {
Space2DSW *space = space_owner.get(p_space);
@@ -1072,6 +1096,25 @@ RID Physics2DServerSW::damped_spring_joint_create(const Vector2& p_anchor_a,cons
}
+void Physics2DServerSW::pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) {
+
+ Joint2DSW *j = joint_owner.get(p_joint);
+ ERR_FAIL_COND(!j);
+ ERR_FAIL_COND(j->get_type()!=JOINT_PIN);
+
+ PinJoint2DSW *pin_joint = static_cast<PinJoint2DSW*>(j);
+ pin_joint->set_param(p_param, p_value);
+}
+
+real_t Physics2DServerSW::pin_joint_get_param(RID p_joint, PinJointParam p_param) const {
+ Joint2DSW *j = joint_owner.get(p_joint);
+ ERR_FAIL_COND_V(!j,0);
+ ERR_FAIL_COND_V(j->get_type()!=JOINT_PIN,0);
+
+ PinJoint2DSW *pin_joint = static_cast<PinJoint2DSW*>(j);
+ return pin_joint->get_param(p_param);
+}
+
void Physics2DServerSW::damped_string_joint_set_param(RID p_joint, DampedStringParam p_param, real_t p_value) {
@@ -1279,8 +1322,11 @@ int Physics2DServerSW::get_process_info(ProcessInfo p_info) {
}
+Physics2DServerSW *Physics2DServerSW::singletonsw=NULL;
+
Physics2DServerSW::Physics2DServerSW() {
+ singletonsw=this;
BroadPhase2DSW::create_func=BroadPhase2DHashGrid::_create;
// BroadPhase2DSW::create_func=BroadPhase2DBasic::_create;
diff --git a/servers/physics_2d/physics_2d_server_sw.h b/servers/physics_2d/physics_2d_server_sw.h
index 6e875701b8..28acf4e2d1 100644
--- a/servers/physics_2d/physics_2d_server_sw.h
+++ b/servers/physics_2d/physics_2d_server_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -42,6 +42,7 @@ class Physics2DServerSW : public Physics2DServer {
OBJ_TYPE( Physics2DServerSW, Physics2DServer );
friend class Physics2DDirectSpaceStateSW;
+friend class Physics2DDirectBodyStateSW;
bool active;
int iterations;
bool doing_sync;
@@ -65,7 +66,7 @@ friend class Physics2DDirectSpaceStateSW;
mutable RID_Owner<Body2DSW> body_owner;
mutable RID_Owner<Joint2DSW> joint_owner;
-
+ static Physics2DServerSW *singletonsw;
// void _clear_query(Query2DSW *p_query);
@@ -102,6 +103,11 @@ public:
virtual void space_set_param(RID p_space,SpaceParameter p_param, real_t p_value);
virtual real_t space_get_param(RID p_space,SpaceParameter p_param) const;
+ virtual void space_set_debug_contacts(RID p_space,int p_max_contacts);
+ virtual Vector<Vector2> space_get_contacts(RID p_space) const;
+ virtual int space_get_contact_count(RID p_space) const;
+
+
// this function only works on fixed process, errors and returns null otherwise
virtual Physics2DDirectSpaceState* space_get_direct_state(RID p_space);
@@ -238,6 +244,8 @@ public:
virtual RID pin_joint_create(const Vector2& p_pos,RID p_body_a,RID p_body_b=RID());
virtual RID groove_joint_create(const Vector2& p_a_groove1,const Vector2& p_a_groove2, const Vector2& p_b_anchor, RID p_body_a,RID p_body_b);
virtual RID damped_spring_joint_create(const Vector2& p_anchor_a,const Vector2& p_anchor_b,RID p_body_a,RID p_body_b=RID());
+ virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value);
+ virtual real_t pin_joint_get_param(RID p_joint, PinJointParam p_param) const;
virtual void damped_string_joint_set_param(RID p_joint, DampedStringParam p_param, real_t p_value);
virtual real_t damped_string_joint_get_param(RID p_joint, DampedStringParam p_param) const;
diff --git a/servers/physics_2d/physics_2d_server_wrap_mt.h b/servers/physics_2d/physics_2d_server_wrap_mt.h
index 0ddc8f16ec..60f8a4c879 100644
--- a/servers/physics_2d/physics_2d_server_wrap_mt.h
+++ b/servers/physics_2d/physics_2d_server_wrap_mt.h
@@ -94,6 +94,22 @@ public:
return physics_2d_server->space_get_direct_state(p_space);
}
+ FUNC2(space_set_debug_contacts,RID,int);
+ virtual Vector<Vector2> space_get_contacts(RID p_space) const {
+
+ ERR_FAIL_COND_V(main_thread!=Thread::get_caller_ID(),Vector<Vector2>());
+ return physics_2d_server->space_get_contacts(p_space);
+
+ }
+
+ virtual int space_get_contact_count(RID p_space) const {
+
+ ERR_FAIL_COND_V(main_thread!=Thread::get_caller_ID(),0);
+ return physics_2d_server->space_get_contact_count(p_space);
+
+ }
+
+
/* AREA API */
@@ -242,6 +258,9 @@ public:
FUNC5R(RID,groove_joint_create,const Vector2&,const Vector2&,const Vector2&,RID,RID);
FUNC4R(RID,damped_spring_joint_create,const Vector2&,const Vector2&,RID,RID);
+ FUNC3(pin_joint_set_param,RID,PinJointParam,real_t);
+ FUNC2RC(real_t,pin_joint_get_param,RID,PinJointParam);
+
FUNC3(damped_string_joint_set_param,RID,DampedStringParam,real_t);
FUNC2RC(real_t,damped_string_joint_get_param,RID,DampedStringParam);
diff --git a/servers/physics_2d/shape_2d_sw.cpp b/servers/physics_2d/shape_2d_sw.cpp
index d3591ec744..3054ba8d59 100644
--- a/servers/physics_2d/shape_2d_sw.cpp
+++ b/servers/physics_2d/shape_2d_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics_2d/shape_2d_sw.h b/servers/physics_2d/shape_2d_sw.h
index 6d5473aa17..4164896696 100644
--- a/servers/physics_2d/shape_2d_sw.h
+++ b/servers/physics_2d/shape_2d_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp
index 9b69ab299d..9ba6bdd5ba 100644
--- a/servers/physics_2d/space_2d_sw.cpp
+++ b/servers/physics_2d/space_2d_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -36,8 +36,8 @@ _FORCE_INLINE_ static bool _match_object_type_query(CollisionObject2DSW *p_objec
if ((p_object->get_layer_mask()&p_layer_mask)==0)
return false;
- if (p_object->get_type()==CollisionObject2DSW::TYPE_AREA && !(p_type_mask&Physics2DDirectSpaceState::TYPE_MASK_AREA))
- return false;
+ if (p_object->get_type()==CollisionObject2DSW::TYPE_AREA)
+ return p_type_mask&Physics2DDirectSpaceState::TYPE_MASK_AREA;
Body2DSW *body = static_cast<Body2DSW*>(p_object);
@@ -192,7 +192,7 @@ int Physics2DDirectSpaceStateSW::intersect_shape(const RID& p_shape, const Matri
if (p_result_max<=0)
return 0;
- Shape2DSW *shape = static_cast<Physics2DServerSW*>(Physics2DServer::get_singleton())->shape_owner.get(p_shape);
+ Shape2DSW *shape = Physics2DServerSW::singletonsw->shape_owner.get(p_shape);
ERR_FAIL_COND_V(!shape,0);
Rect2 aabb = p_xform.xform(shape->get_aabb());
@@ -239,7 +239,7 @@ bool Physics2DDirectSpaceStateSW::cast_motion(const RID& p_shape, const Matrix32
- Shape2DSW *shape = static_cast<Physics2DServerSW*>(Physics2DServer::get_singleton())->shape_owner.get(p_shape);
+ Shape2DSW *shape = Physics2DServerSW::singletonsw->shape_owner.get(p_shape);
ERR_FAIL_COND_V(!shape,false);
Rect2 aabb = p_xform.xform(shape->get_aabb());
@@ -367,7 +367,7 @@ bool Physics2DDirectSpaceStateSW::collide_shape(RID p_shape, const Matrix32& p_s
if (p_result_max<=0)
return 0;
- Shape2DSW *shape = static_cast<Physics2DServerSW*>(Physics2DServer::get_singleton())->shape_owner.get(p_shape);
+ Shape2DSW *shape = Physics2DServerSW::singletonsw->shape_owner.get(p_shape);
ERR_FAIL_COND_V(!shape,0);
Rect2 aabb = p_shape_xform.xform(shape->get_aabb());
@@ -474,7 +474,7 @@ static void _rest_cbk_result(const Vector2& p_point_A,const Vector2& p_point_B,v
bool Physics2DDirectSpaceStateSW::rest_info(RID p_shape, const Matrix32& p_shape_xform,const Vector2& p_motion,float p_margin,ShapeRestInfo *r_info, const Set<RID>& p_exclude,uint32_t p_layer_mask,uint32_t p_object_type_mask) {
- Shape2DSW *shape = static_cast<Physics2DServerSW*>(Physics2DServer::get_singleton())->shape_owner.get(p_shape);
+ Shape2DSW *shape = Physics2DServerSW::singletonsw->shape_owner.get(p_shape);
ERR_FAIL_COND_V(!shape,0);
Rect2 aabb = p_shape_xform.xform(shape->get_aabb());
@@ -657,8 +657,8 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body,const Vector2&p_motion,float p
const Body2DSW *body=static_cast<const Body2DSW*>(col_obj);
Vector2 cdir = body->get_one_way_collision_direction();
- if (cdir!=Vector2() && p_motion.dot(cdir)<0)
- continue;
+ //if (cdir!=Vector2() && p_motion.dot(cdir)<0)
+ // continue;
cbk.valid_dir=cdir;
cbk.valid_depth=body->get_one_way_collision_max_depth();
@@ -1230,6 +1230,7 @@ void Space2DSW::call_queries() {
void Space2DSW::setup() {
+ contact_debug_count=0;
while(inertia_update_list.first()) {
inertia_update_list.first()->self()->update_inertias();
@@ -1302,6 +1303,8 @@ Space2DSW::Space2DSW() {
active_objects=0;
island_count=0;
+ contact_debug_count=0;
+
locked=false;
contact_recycle_radius=0.01;
contact_max_separation=0.05;
@@ -1320,6 +1323,10 @@ Space2DSW::Space2DSW() {
direct_access = memnew( Physics2DDirectSpaceStateSW );
direct_access->space=this;
+
+
+
+
}
Space2DSW::~Space2DSW() {
diff --git a/servers/physics_2d/space_2d_sw.h b/servers/physics_2d/space_2d_sw.h
index abee8628fc..2bdbb8a881 100644
--- a/servers/physics_2d/space_2d_sw.h
+++ b/servers/physics_2d/space_2d_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -103,6 +103,9 @@ class Space2DSW {
int _cull_aabb_for_body(Body2DSW *p_body,const Rect2& p_aabb);
+ Vector<Vector2> contact_debug;
+ int contact_debug_count;
+
friend class Physics2DDirectSpaceStateSW;
public:
@@ -169,6 +172,14 @@ public:
bool test_body_motion(Body2DSW *p_body, const Vector2&p_motion, float p_margin, Physics2DServer::MotionResult *r_result);
+
+ void set_debug_contacts(int p_amount) { contact_debug.resize(p_amount); }
+ _FORCE_INLINE_ bool is_debugging_contacts() const { return !contact_debug.empty(); }
+ _FORCE_INLINE_ void add_debug_contact(const Vector2& p_contact) { if (contact_debug_count<contact_debug.size()) contact_debug[contact_debug_count++]=p_contact; }
+ _FORCE_INLINE_ Vector<Vector2> get_debug_contacts() { return contact_debug; }
+ _FORCE_INLINE_ int get_debug_contact_count() { return contact_debug_count; }
+
+
Physics2DDirectSpaceStateSW *get_direct_state();
Space2DSW();
diff --git a/servers/physics_2d/step_2d_sw.cpp b/servers/physics_2d/step_2d_sw.cpp
index bc87789937..94e1d26329 100644
--- a/servers/physics_2d/step_2d_sw.cpp
+++ b/servers/physics_2d/step_2d_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -56,14 +56,29 @@ void Step2DSW::_populate_island(Body2DSW* p_body,Body2DSW** p_island,Constraint2
}
}
-void Step2DSW::_setup_island(Constraint2DSW *p_island,float p_delta) {
+bool Step2DSW::_setup_island(Constraint2DSW *p_island,float p_delta) {
Constraint2DSW *ci=p_island;
+ Constraint2DSW *prev_ci=NULL;
+ bool removed_root=false;
while(ci) {
bool process = ci->setup(p_delta);
- //todo remove from island if process fails
+
+ if (!process) {
+ //remove from island if process fails
+ if (prev_ci) {
+ prev_ci->set_island_next(ci->get_island_next());
+ } else {
+ removed_root=true;
+ prev_ci=ci;
+ }
+ } else {
+ prev_ci=ci;
+ }
ci=ci->get_island_next();
}
+
+ return removed_root;
}
void Step2DSW::_solve_island(Constraint2DSW *p_island,int p_iterations,float p_delta){
@@ -195,9 +210,40 @@ void Step2DSW::step(Space2DSW* p_space,float p_delta,int p_iterations) {
{
Constraint2DSW *ci=constraint_island_list;
+ Constraint2DSW *prev_ci=NULL;
while(ci) {
- _setup_island(ci,p_delta);
+ if (_setup_island(ci,p_delta)==true) {
+
+ //removed the root from the island graph because it is not to be processed
+
+ Constraint2DSW *next = ci->get_island_next();
+
+ if (next) {
+ //root from list being deleted no longer exists, replace by next
+ next->set_island_list_next(ci->get_island_list_next());
+ if (prev_ci) {
+ prev_ci->set_island_list_next(next);
+ } else {
+ constraint_island_list=next;
+
+ }
+ prev_ci=next;
+ } else {
+
+ //list is empty, just skip
+ if (prev_ci) {
+ prev_ci->set_island_list_next(ci->get_island_list_next());
+
+ } else {
+ constraint_island_list=ci->get_island_list_next();
+ }
+
+ }
+ } else {
+ prev_ci=ci;
+ }
+
ci=ci->get_island_list_next();
}
}
diff --git a/servers/physics_2d/step_2d_sw.h b/servers/physics_2d/step_2d_sw.h
index d5e919836c..0c374d7e12 100644
--- a/servers/physics_2d/step_2d_sw.h
+++ b/servers/physics_2d/step_2d_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -36,7 +36,7 @@ class Step2DSW {
uint64_t _step;
void _populate_island(Body2DSW* p_body,Body2DSW** p_island,Constraint2DSW **p_constraint_island);
- void _setup_island(Constraint2DSW *p_island,float p_delta);
+ bool _setup_island(Constraint2DSW *p_island,float p_delta);
void _solve_island(Constraint2DSW *p_island,int p_iterations,float p_delta);
void _check_suspend(Body2DSW *p_island,float p_delta);
public:
diff --git a/servers/physics_2d_server.cpp b/servers/physics_2d_server.cpp
index b9d15d6e35..2d267a5749 100644
--- a/servers/physics_2d_server.cpp
+++ b/servers/physics_2d_server.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -102,7 +102,7 @@ void Physics2DDirectBodyState::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_contact_collider_id","contact_idx"),&Physics2DDirectBodyState::get_contact_collider_id);
ObjectTypeDB::bind_method(_MD("get_contact_collider_object","contact_idx"),&Physics2DDirectBodyState::get_contact_collider_object);
ObjectTypeDB::bind_method(_MD("get_contact_collider_shape","contact_idx"),&Physics2DDirectBodyState::get_contact_collider_shape);
- ObjectTypeDB::bind_method(_MD("get_contact_collider_shape_metadata:var","contact_idx"),&Physics2DDirectBodyState::get_contact_collider_shape_metadata);
+ ObjectTypeDB::bind_method(_MD("get_contact_collider_shape_metadata:Variant","contact_idx"),&Physics2DDirectBodyState::get_contact_collider_shape_metadata);
ObjectTypeDB::bind_method(_MD("get_contact_collider_velocity_at_pos","contact_idx"),&Physics2DDirectBodyState::get_contact_collider_velocity_at_pos);
ObjectTypeDB::bind_method(_MD("get_step"),&Physics2DDirectBodyState::get_step);
ObjectTypeDB::bind_method(_MD("integrate_forces"),&Physics2DDirectBodyState::integrate_forces);
@@ -548,7 +548,7 @@ void Physics2DServer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("area_attach_object_instance_ID","area","id"),&Physics2DServer::area_attach_object_instance_ID);
ObjectTypeDB::bind_method(_MD("area_get_object_instance_ID","area"),&Physics2DServer::area_get_object_instance_ID);
- ObjectTypeDB::bind_method(_MD("area_set_monitor_callback","receiver","method"),&Physics2DServer::area_set_monitor_callback);
+ ObjectTypeDB::bind_method(_MD("area_set_monitor_callback","area","receiver","method"),&Physics2DServer::area_set_monitor_callback);
ObjectTypeDB::bind_method(_MD("body_create","mode","init_sleeping"),&Physics2DServer::body_create,DEFVAL(BODY_MODE_RIGID),DEFVAL(false));
@@ -606,17 +606,17 @@ void Physics2DServer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("body_set_max_contacts_reported","body","amount"),&Physics2DServer::body_set_max_contacts_reported);
ObjectTypeDB::bind_method(_MD("body_get_max_contacts_reported","body"),&Physics2DServer::body_get_max_contacts_reported);
- ObjectTypeDB::bind_method(_MD("body_set_one_way_collision_direction","normal"),&Physics2DServer::body_set_one_way_collision_direction);
- ObjectTypeDB::bind_method(_MD("body_get_one_way_collision_direction"),&Physics2DServer::body_get_one_way_collision_direction);
+ ObjectTypeDB::bind_method(_MD("body_set_one_way_collision_direction","body","normal"),&Physics2DServer::body_set_one_way_collision_direction);
+ ObjectTypeDB::bind_method(_MD("body_get_one_way_collision_direction","body"),&Physics2DServer::body_get_one_way_collision_direction);
- ObjectTypeDB::bind_method(_MD("body_set_one_way_collision_max_depth","normal"),&Physics2DServer::body_set_one_way_collision_max_depth);
- ObjectTypeDB::bind_method(_MD("body_get_one_way_collision_max_depth"),&Physics2DServer::body_get_one_way_collision_max_depth);
+ ObjectTypeDB::bind_method(_MD("body_set_one_way_collision_max_depth","body","depth"),&Physics2DServer::body_set_one_way_collision_max_depth);
+ ObjectTypeDB::bind_method(_MD("body_get_one_way_collision_max_depth","body"),&Physics2DServer::body_get_one_way_collision_max_depth);
ObjectTypeDB::bind_method(_MD("body_set_omit_force_integration","body","enable"),&Physics2DServer::body_set_omit_force_integration);
ObjectTypeDB::bind_method(_MD("body_is_omitting_force_integration","body"),&Physics2DServer::body_is_omitting_force_integration);
- ObjectTypeDB::bind_method(_MD("body_set_force_integration_callback","body","receiver","method"),&Physics2DServer::body_set_force_integration_callback);
+ ObjectTypeDB::bind_method(_MD("body_set_force_integration_callback","body","receiver","method","userdata"),&Physics2DServer::body_set_force_integration_callback,DEFVAL(Variant()));
ObjectTypeDB::bind_method(_MD("body_test_motion","body","motion","margin","result:Physics2DTestMotionResult"),&Physics2DServer::_body_test_motion,DEFVAL(0.08),DEFVAL(Variant()));
@@ -638,7 +638,7 @@ void Physics2DServer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_active","active"),&Physics2DServer::set_active);
- ObjectTypeDB::bind_method(_MD("get_process_info"),&Physics2DServer::get_process_info);
+ ObjectTypeDB::bind_method(_MD("get_process_info","process_info"),&Physics2DServer::get_process_info);
// ObjectTypeDB::bind_method(_MD("init"),&Physics2DServer::init);
// ObjectTypeDB::bind_method(_MD("step"),&Physics2DServer::step);
@@ -663,9 +663,11 @@ void Physics2DServer::_bind_methods() {
BIND_CONSTANT( AREA_PARAM_ANGULAR_DAMP);
BIND_CONSTANT( AREA_PARAM_PRIORITY );
- BIND_CONSTANT( AREA_SPACE_OVERRIDE_COMBINE );
BIND_CONSTANT( AREA_SPACE_OVERRIDE_DISABLED );
+ BIND_CONSTANT( AREA_SPACE_OVERRIDE_COMBINE );
+ BIND_CONSTANT( AREA_SPACE_OVERRIDE_COMBINE_REPLACE );
BIND_CONSTANT( AREA_SPACE_OVERRIDE_REPLACE );
+ BIND_CONSTANT( AREA_SPACE_OVERRIDE_REPLACE_COMBINE );
BIND_CONSTANT( BODY_MODE_STATIC );
BIND_CONSTANT( BODY_MODE_KINEMATIC );
diff --git a/servers/physics_2d_server.h b/servers/physics_2d_server.h
index b24496880e..08f69f98b1 100644
--- a/servers/physics_2d_server.h
+++ b/servers/physics_2d_server.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -293,6 +293,9 @@ public:
// this function only works on fixed process, errors and returns null otherwise
virtual Physics2DDirectSpaceState* space_get_direct_state(RID p_space)=0;
+ virtual void space_set_debug_contacts(RID p_space,int p_max_contacts)=0;
+ virtual Vector<Vector2> space_get_contacts(RID p_space) const=0;
+ virtual int space_get_contact_count(RID p_space) const=0;
//missing space parameters
@@ -322,7 +325,9 @@ public:
enum AreaSpaceOverrideMode {
AREA_SPACE_OVERRIDE_DISABLED,
AREA_SPACE_OVERRIDE_COMBINE,
+ AREA_SPACE_OVERRIDE_COMBINE_REPLACE, // Combines, then discards all subsequent calculations
AREA_SPACE_OVERRIDE_REPLACE,
+ AREA_SPACE_OVERRIDE_REPLACE_COMBINE // Discards all previous calculations, then keeps combining
};
virtual void area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode)=0;
@@ -513,6 +518,13 @@ public:
virtual RID groove_joint_create(const Vector2& p_a_groove1,const Vector2& p_a_groove2, const Vector2& p_b_anchor, RID p_body_a,RID p_body_b)=0;
virtual RID damped_spring_joint_create(const Vector2& p_anchor_a,const Vector2& p_anchor_b,RID p_body_a,RID p_body_b=RID())=0;
+ enum PinJointParam {
+ PIN_JOINT_SOFTNESS
+ };
+
+ virtual void pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value)=0;
+ virtual real_t pin_joint_get_param(RID p_joint, PinJointParam p_param) const=0;
+
enum DampedStringParam {
DAMPED_STRING_REST_LENGTH,
DAMPED_STRING_STIFFNESS,
diff --git a/servers/physics_server.cpp b/servers/physics_server.cpp
index e02601af41..89fcffe7ed 100644
--- a/servers/physics_server.cpp
+++ b/servers/physics_server.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -39,13 +39,18 @@ void PhysicsDirectBodyState::integrate_forces() {
Vector3 av = get_angular_velocity();
- float damp = 1.0 - step * get_total_density();
+ float linear_damp = 1.0 - step * get_total_linear_damp();
- if (damp<0) // reached zero in the given time
- damp=0;
+ if (linear_damp<0) // reached zero in the given time
+ linear_damp=0;
- lv*=damp;
- av*=damp;
+ float angular_damp = 1.0 - step * get_total_angular_damp();
+
+ if (angular_damp<0) // reached zero in the given time
+ angular_damp=0;
+
+ lv*=linear_damp;
+ av*=angular_damp;
set_linear_velocity(lv);
set_angular_velocity(av);
@@ -70,7 +75,8 @@ PhysicsServer * PhysicsServer::get_singleton() {
void PhysicsDirectBodyState::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_total_gravity"),&PhysicsDirectBodyState::get_total_gravity);
- ObjectTypeDB::bind_method(_MD("get_total_density"),&PhysicsDirectBodyState::get_total_density);
+ ObjectTypeDB::bind_method(_MD("get_total_linear_damp"),&PhysicsDirectBodyState::get_total_linear_damp);
+ ObjectTypeDB::bind_method(_MD("get_total_angular_damp"),&PhysicsDirectBodyState::get_total_angular_damp);
ObjectTypeDB::bind_method(_MD("get_inverse_mass"),&PhysicsDirectBodyState::get_inverse_mass);
ObjectTypeDB::bind_method(_MD("get_inverse_inertia"),&PhysicsDirectBodyState::get_inverse_inertia);
@@ -461,7 +467,7 @@ void PhysicsServer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("area_attach_object_instance_ID","area","id"),&PhysicsServer::area_attach_object_instance_ID);
ObjectTypeDB::bind_method(_MD("area_get_object_instance_ID","area"),&PhysicsServer::area_get_object_instance_ID);
- ObjectTypeDB::bind_method(_MD("area_set_monitor_callback","receiver","method"),&PhysicsServer::area_set_monitor_callback);
+ ObjectTypeDB::bind_method(_MD("area_set_monitor_callback","area","receiver","method"),&PhysicsServer::area_set_monitor_callback);
ObjectTypeDB::bind_method(_MD("area_set_ray_pickable","area","enable"),&PhysicsServer::area_set_ray_pickable);
ObjectTypeDB::bind_method(_MD("area_is_ray_pickable","area"),&PhysicsServer::area_is_ray_pickable);
@@ -665,7 +671,7 @@ void PhysicsServer::_bind_methods() {
//ObjectTypeDB::bind_method(_MD("flush_queries"),&PhysicsServer::flush_queries);
- ObjectTypeDB::bind_method(_MD("get_process_info"),&PhysicsServer::get_process_info);
+ ObjectTypeDB::bind_method(_MD("get_process_info","process_info"),&PhysicsServer::get_process_info);
BIND_CONSTANT( SHAPE_PLANE );
BIND_CONSTANT( SHAPE_RAY );
@@ -683,12 +689,15 @@ void PhysicsServer::_bind_methods() {
BIND_CONSTANT( AREA_PARAM_GRAVITY_IS_POINT );
BIND_CONSTANT( AREA_PARAM_GRAVITY_DISTANCE_SCALE );
BIND_CONSTANT( AREA_PARAM_GRAVITY_POINT_ATTENUATION );
- BIND_CONSTANT( AREA_PARAM_DENSITY );
+ BIND_CONSTANT( AREA_PARAM_LINEAR_DAMP );
+ BIND_CONSTANT( AREA_PARAM_ANGULAR_DAMP );
BIND_CONSTANT( AREA_PARAM_PRIORITY );
- BIND_CONSTANT( AREA_SPACE_OVERRIDE_COMBINE );
BIND_CONSTANT( AREA_SPACE_OVERRIDE_DISABLED );
+ BIND_CONSTANT( AREA_SPACE_OVERRIDE_COMBINE );
+ BIND_CONSTANT( AREA_SPACE_OVERRIDE_COMBINE_REPLACE );
BIND_CONSTANT( AREA_SPACE_OVERRIDE_REPLACE );
+ BIND_CONSTANT( AREA_SPACE_OVERRIDE_REPLACE_COMBINE );
BIND_CONSTANT( BODY_MODE_STATIC );
BIND_CONSTANT( BODY_MODE_KINEMATIC );
@@ -698,6 +707,9 @@ void PhysicsServer::_bind_methods() {
BIND_CONSTANT( BODY_PARAM_BOUNCE );
BIND_CONSTANT( BODY_PARAM_FRICTION );
BIND_CONSTANT( BODY_PARAM_MASS );
+ BIND_CONSTANT( BODY_PARAM_GRAVITY_SCALE );
+ BIND_CONSTANT( BODY_PARAM_ANGULAR_DAMP );
+ BIND_CONSTANT( BODY_PARAM_LINEAR_DAMP );
BIND_CONSTANT( BODY_PARAM_MAX );
BIND_CONSTANT( BODY_STATE_TRANSFORM );
diff --git a/servers/physics_server.h b/servers/physics_server.h
index f66ea590b8..8e302bf363 100644
--- a/servers/physics_server.h
+++ b/servers/physics_server.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -41,8 +41,9 @@ protected:
static void _bind_methods();
public:
- virtual Vector3 get_total_gravity() const=0; // get gravity vector working on this body space/area
- virtual float get_total_density() const=0; // get density of this body space/area
+ virtual Vector3 get_total_gravity() const=0;
+ virtual float get_total_angular_damp() const=0;
+ virtual float get_total_linear_damp() const=0;
virtual float get_inverse_mass() const=0; // get the mass
virtual Vector3 get_inverse_inertia() const=0; // get density of this body space
@@ -169,7 +170,7 @@ public:
int shape;
};
- virtual bool intersect_ray(const Vector3& p_from, const Vector3& p_to,RayResult &r_result,const Set<RID>& p_exclude=Set<RID>(),uint32_t p_layer_mask=0xFFFFFFFF,uint32_t p_object_type_mask=TYPE_MASK_COLLISION)=0;
+ virtual bool intersect_ray(const Vector3& p_from, const Vector3& p_to,RayResult &r_result,const Set<RID>& p_exclude=Set<RID>(),uint32_t p_layer_mask=0xFFFFFFFF,uint32_t p_object_type_mask=TYPE_MASK_COLLISION,bool p_pick_ray=false)=0;
struct ShapeResult {
@@ -285,6 +286,9 @@ public:
// this function only works on fixed process, errors and returns null otherwise
virtual PhysicsDirectSpaceState* space_get_direct_state(RID p_space)=0;
+ virtual void space_set_debug_contacts(RID p_space,int p_max_contacts)=0;
+ virtual Vector<Vector3> space_get_contacts(RID p_space) const=0;
+ virtual int space_get_contact_count(RID p_space) const=0;
//missing space parameters
@@ -300,7 +304,8 @@ public:
AREA_PARAM_GRAVITY_IS_POINT,
AREA_PARAM_GRAVITY_DISTANCE_SCALE,
AREA_PARAM_GRAVITY_POINT_ATTENUATION,
- AREA_PARAM_DENSITY,
+ AREA_PARAM_LINEAR_DAMP,
+ AREA_PARAM_ANGULAR_DAMP,
AREA_PARAM_PRIORITY
};
@@ -313,7 +318,9 @@ public:
enum AreaSpaceOverrideMode {
AREA_SPACE_OVERRIDE_DISABLED,
AREA_SPACE_OVERRIDE_COMBINE,
+ AREA_SPACE_OVERRIDE_COMBINE_REPLACE,
AREA_SPACE_OVERRIDE_REPLACE,
+ AREA_SPACE_OVERRIDE_REPLACE_COMBINE
};
virtual void area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode)=0;
@@ -365,7 +372,7 @@ public:
virtual RID body_get_space(RID p_body) const=0;
virtual void body_set_mode(RID p_body, BodyMode p_mode)=0;
- virtual BodyMode body_get_mode(RID p_body, BodyMode p_mode) const=0;
+ virtual BodyMode body_get_mode(RID p_body) const=0;
virtual void body_add_shape(RID p_body, RID p_shape, const Transform& p_transform=Transform())=0;
virtual void body_set_shape(RID p_body, int p_shape_idx,RID p_shape)=0;
@@ -398,6 +405,9 @@ public:
BODY_PARAM_BOUNCE,
BODY_PARAM_FRICTION,
BODY_PARAM_MASS, ///< unused for static, always infinite
+ BODY_PARAM_GRAVITY_SCALE,
+ BODY_PARAM_LINEAR_DAMP,
+ BODY_PARAM_ANGULAR_DAMP,
BODY_PARAM_MAX,
};
@@ -411,7 +421,7 @@ public:
BODY_STATE_LINEAR_VELOCITY,
BODY_STATE_ANGULAR_VELOCITY,
BODY_STATE_SLEEPING,
- BODY_STATE_CAN_SLEEP
+ BODY_STATE_CAN_SLEEP
};
virtual void body_set_state(RID p_body, BodyState p_state, const Variant& p_variant)=0;
diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp
index 3634a03dbc..4752210b5f 100644
--- a/servers/register_server_types.cpp
+++ b/servers/register_server_types.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,6 +35,25 @@
#include "physics_2d_server.h"
#include "spatial_sound_server.h"
#include "spatial_sound_2d_server.h"
+#include "script_debugger_remote.h"
+
+static void _debugger_get_resource_usage(List<ScriptDebuggerRemote::ResourceUsage>* r_usage) {
+
+ List<VS::TextureInfo> tinfo;
+ VS::get_singleton()->texture_debug_usage(&tinfo);
+
+ for (List<VS::TextureInfo>::Element *E=tinfo.front();E;E=E->next()) {
+
+ ScriptDebuggerRemote::ResourceUsage usage;
+ usage.path=E->get().path;
+ usage.vram=E->get().bytes;
+ usage.id=E->get().texture;
+ usage.type="Texture";
+ usage.format=itos(E->get().size.width)+"x"+itos(E->get().size.height)+" "+Image::get_format_name(E->get().format);
+ r_usage->push_back(usage);
+ }
+
+}
void register_server_types() {
@@ -63,6 +82,7 @@ void register_server_types() {
ObjectTypeDB::register_virtual_type<PhysicsDirectSpaceState>();
ObjectTypeDB::register_virtual_type<PhysicsShapeQueryResult>();
+ ScriptDebuggerRemote::resource_usage_func=_debugger_get_resource_usage;
}
void unregister_server_types(){
diff --git a/servers/register_server_types.h b/servers/register_server_types.h
index d3d6c6b566..a62af905b3 100644
--- a/servers/register_server_types.h
+++ b/servers/register_server_types.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/spatial_sound/SCsub b/servers/spatial_sound/SCsub
index 16fe3a59ac..d31af2c1c4 100644
--- a/servers/spatial_sound/SCsub
+++ b/servers/spatial_sound/SCsub
@@ -3,5 +3,3 @@ Import('env')
env.add_source_files(env.servers_sources,"*.cpp")
Export('env')
-
-
diff --git a/servers/spatial_sound/spatial_sound_server_sw.cpp b/servers/spatial_sound/spatial_sound_server_sw.cpp
index d00deb3912..1ce56a5cdd 100644
--- a/servers/spatial_sound/spatial_sound_server_sw.cpp
+++ b/servers/spatial_sound/spatial_sound_server_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/*************************************************/
/* Source code within this file is: */
-/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
/* All Rights Reserved. */
/*************************************************/
diff --git a/servers/spatial_sound/spatial_sound_server_sw.h b/servers/spatial_sound/spatial_sound_server_sw.h
index 82b1b5fa8e..8a4dabdc3e 100644
--- a/servers/spatial_sound/spatial_sound_server_sw.h
+++ b/servers/spatial_sound/spatial_sound_server_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/*************************************************/
/* Source code within this file is: */
-/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
/* All Rights Reserved. */
/*************************************************/
diff --git a/servers/spatial_sound_2d/SCsub b/servers/spatial_sound_2d/SCsub
index 16fe3a59ac..d31af2c1c4 100644
--- a/servers/spatial_sound_2d/SCsub
+++ b/servers/spatial_sound_2d/SCsub
@@ -3,5 +3,3 @@ Import('env')
env.add_source_files(env.servers_sources,"*.cpp")
Export('env')
-
-
diff --git a/servers/spatial_sound_2d/spatial_sound_2d_server_sw.cpp b/servers/spatial_sound_2d/spatial_sound_2d_server_sw.cpp
index 439149b1a2..d27b322c21 100644
--- a/servers/spatial_sound_2d/spatial_sound_2d_server_sw.cpp
+++ b/servers/spatial_sound_2d/spatial_sound_2d_server_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/spatial_sound_2d/spatial_sound_2d_server_sw.h b/servers/spatial_sound_2d/spatial_sound_2d_server_sw.h
index ed305d25de..619b11f376 100644
--- a/servers/spatial_sound_2d/spatial_sound_2d_server_sw.h
+++ b/servers/spatial_sound_2d/spatial_sound_2d_server_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/spatial_sound_2d_server.cpp b/servers/spatial_sound_2d_server.cpp
index 574c3d761f..cfe40a0937 100644
--- a/servers/spatial_sound_2d_server.cpp
+++ b/servers/spatial_sound_2d_server.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/spatial_sound_2d_server.h b/servers/spatial_sound_2d_server.h
index 9917b36be1..2d388feb49 100644
--- a/servers/spatial_sound_2d_server.h
+++ b/servers/spatial_sound_2d_server.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/spatial_sound_server.cpp b/servers/spatial_sound_server.cpp
index f5f5925483..5f93c55a91 100644
--- a/servers/spatial_sound_server.cpp
+++ b/servers/spatial_sound_server.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/spatial_sound_server.h b/servers/spatial_sound_server.h
index 1cc323b370..5037ee6e2f 100644
--- a/servers/spatial_sound_server.h
+++ b/servers/spatial_sound_server.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/visual/SCsub b/servers/visual/SCsub
index 16fe3a59ac..d31af2c1c4 100644
--- a/servers/visual/SCsub
+++ b/servers/visual/SCsub
@@ -3,5 +3,3 @@ Import('env')
env.add_source_files(env.servers_sources,"*.cpp")
Export('env')
-
-
diff --git a/servers/visual/particle_system_sw.cpp b/servers/visual/particle_system_sw.cpp
index aa9b737459..00c06b9e3c 100644
--- a/servers/visual/particle_system_sw.cpp
+++ b/servers/visual/particle_system_sw.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/visual/particle_system_sw.h b/servers/visual/particle_system_sw.h
index b7ff5e9bb5..9a176ba0d4 100644
--- a/servers/visual/particle_system_sw.h
+++ b/servers/visual/particle_system_sw.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/visual/rasterizer.cpp b/servers/visual/rasterizer.cpp
index 5984e6e35c..26eca478fd 100644
--- a/servers/visual/rasterizer.cpp
+++ b/servers/visual/rasterizer.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h
index 50336e07f4..b84e83cb0c 100644
--- a/servers/visual/rasterizer.h
+++ b/servers/visual/rasterizer.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -190,9 +190,12 @@ public:
virtual bool texture_has_alpha(RID p_texture) const=0;
virtual void texture_set_size_override(RID p_texture,int p_width, int p_height)=0;
-
virtual void texture_set_reload_hook(RID p_texture,ObjectID p_owner,const StringName& p_function) const=0;
+ virtual void texture_set_path(RID p_texture,const String& p_path)=0;
+ virtual String texture_get_path(RID p_texture) const=0;
+ virtual void texture_debug_usage(List<VS::TextureInfo> *r_info)=0;
+
/* SHADER API */
virtual RID shader_create(VS::ShaderMode p_mode=VS::SHADER_MATERIAL)=0;
@@ -592,6 +595,7 @@ public:
RID shadow_buffer;
int shadow_buffer_size;
float shadow_esm_mult;
+ Color shadow_color;
void *texture_cache; // implementation dependent
@@ -606,10 +610,12 @@ public:
CanvasLight *shadows_next_ptr;
CanvasLight *filter_next_ptr;
CanvasLight *next_ptr;
+ CanvasLight *mask_next_ptr;
CanvasLight() {
enabled=true;
color=Color(1,1,1);
+ shadow_color=Color(0,0,0,0);
height=0;
z_min=-1024;
z_max=1024;
@@ -622,6 +628,7 @@ public:
mode=VS::CANVAS_LIGHT_MODE_ADD;
texture_cache=NULL;
next_ptr=NULL;
+ mask_next_ptr=NULL;
filter_next_ptr=NULL;
shadow_buffer_size=2048;
shadow_esm_mult=80;
@@ -688,7 +695,7 @@ public:
Rect2 rect;
RID texture;
float margin[4];
- float draw_center;
+ bool draw_center;
Color color;
CommandStyle() { draw_center=true; type = TYPE_STYLE; }
};
@@ -787,6 +794,7 @@ public:
CanvasItem* material_owner;
ViewportRender *vp_render;
bool distance_field;
+ bool light_masked;
Rect2 global_rect_cache;
@@ -913,8 +921,8 @@ public:
return rect;
}
- void clear() { for (int i=0;i<commands.size();i++) memdelete( commands[i] ); commands.clear(); clip=false; rect_dirty=true; final_clip_owner=NULL; material_owner=NULL;}
- CanvasItem() { light_mask=1; vp_render=NULL; next=NULL; final_clip_owner=NULL; clip=false; final_opacity=1; blend_mode=VS::MATERIAL_BLEND_MODE_MIX; visible=true; rect_dirty=true; custom_rect=false; ontop=true; material_owner=NULL; material=NULL; copy_back_buffer=NULL; distance_field=false; }
+ void clear() { for (int i=0;i<commands.size();i++) memdelete( commands[i] ); commands.clear(); clip=false; rect_dirty=true; final_clip_owner=NULL; material_owner=NULL; light_masked=false; }
+ CanvasItem() { light_mask=1; vp_render=NULL; next=NULL; final_clip_owner=NULL; clip=false; final_opacity=1; blend_mode=VS::MATERIAL_BLEND_MODE_MIX; visible=true; rect_dirty=true; custom_rect=false; ontop=true; material_owner=NULL; material=NULL; copy_back_buffer=NULL; distance_field=false; light_masked=false; }
virtual ~CanvasItem() { clear(); if (copy_back_buffer) memdelete(copy_back_buffer); }
};
@@ -1020,9 +1028,12 @@ public:
virtual bool has_feature(VS::Features p_feature) const=0;
+ virtual void restore_framebuffer()=0;
virtual int get_render_info(VS::RenderInfo p_info)=0;
+ virtual void set_force_16_bits_fbo(bool p_force) {}
+
Rasterizer();
virtual ~Rasterizer() {}
};
diff --git a/servers/visual/rasterizer_dummy.cpp b/servers/visual/rasterizer_dummy.cpp
index e32f47b3d8..3b12b503dd 100644
--- a/servers/visual/rasterizer_dummy.cpp
+++ b/servers/visual/rasterizer_dummy.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -1948,6 +1948,9 @@ bool RasterizerDummy::has_feature(VS::Features p_feature) const {
}
+void RasterizerDummy::restore_framebuffer() {
+
+}
RasterizerDummy::RasterizerDummy() {
diff --git a/servers/visual/rasterizer_dummy.h b/servers/visual/rasterizer_dummy.h
index cc3c1724a4..efa843839a 100644
--- a/servers/visual/rasterizer_dummy.h
+++ b/servers/visual/rasterizer_dummy.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -162,10 +162,6 @@ class RasterizerDummy : public Rasterizer {
uint32_t format;
uint32_t morph_format;
- RID material;
- bool material_owned;
-
-
Surface() {
packed=false;
@@ -415,6 +411,10 @@ public:
virtual void texture_set_size_override(RID p_texture,int p_width, int p_height);
virtual void texture_set_reload_hook(RID p_texture,ObjectID p_owner,const StringName& p_function) const;
+ virtual void texture_set_path(RID p_texture,const String& p_path) {}
+ virtual String texture_get_path(RID p_texture) const { return String(); }
+ virtual void texture_debug_usage(List<VS::TextureInfo> *r_info) {}
+
/* SHADER API */
virtual RID shader_create(VS::ShaderMode p_mode=VS::SHADER_MATERIAL);
@@ -779,6 +779,7 @@ public:
virtual bool has_feature(VS::Features p_feature) const;
+ virtual void restore_framebuffer();
RasterizerDummy();
virtual ~RasterizerDummy();
diff --git a/servers/visual/shader_compiler.cpp b/servers/visual/shader_compiler.cpp
index d7b171f5a7..ee5dae5ae2 100644
--- a/servers/visual/shader_compiler.cpp
+++ b/servers/visual/shader_compiler.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/visual/shader_compiler.h b/servers/visual/shader_compiler.h
index 69d9eedf9c..29561b2145 100644
--- a/servers/visual/shader_compiler.h
+++ b/servers/visual/shader_compiler.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/visual/shader_graph.cpp b/servers/visual/shader_graph.cpp
index 1346ec9253..07bbf9f7b4 100644
--- a/servers/visual/shader_graph.cpp
+++ b/servers/visual/shader_graph.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/visual/shader_graph.h b/servers/visual/shader_graph.h
index 807dbb3719..07e4bb3540 100644
--- a/servers/visual/shader_graph.h
+++ b/servers/visual/shader_graph.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp
index ea56306241..d0e8bfccd6 100644
--- a/servers/visual/shader_language.cpp
+++ b/servers/visual/shader_language.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -1043,6 +1043,7 @@ const ShaderLanguage::BuiltinsDef ShaderLanguage::vertex_builtins_defs[]={
{ "SRC_TANGENT", TYPE_VEC3},
{ "SRC_BINORMALF", TYPE_FLOAT},
+ { "POSITION", TYPE_VEC4 },
{ "VERTEX", TYPE_VEC3},
{ "NORMAL", TYPE_VEC3},
{ "TANGENT", TYPE_VEC3},
@@ -1112,7 +1113,8 @@ const ShaderLanguage::BuiltinsDef ShaderLanguage::light_builtins_defs[]={
{ "SPECULAR_EXP", TYPE_FLOAT},
{ "SHADE_PARAM", TYPE_FLOAT},
{ "LIGHT", TYPE_VEC3},
- { "POINT_COORD", TYPE_VEC2},
+ { "SHADOW", TYPE_VEC3 },
+ { "POINT_COORD", TYPE_VEC2 },
// { "SCREEN_POS", TYPE_VEC2},
// { "SCREEN_TEXEL_SIZE", TYPE_VEC2},
{ "TIME", TYPE_FLOAT},
@@ -1368,7 +1370,7 @@ ShaderLanguage::Node* ShaderLanguage::validate_function_call(Parser&parser, Oper
}
}
- if (!fail) {
+ if (!fail && name == program->functions[i].name) {
p_func->return_cache=pfunc->return_type;
return p_func;
}
@@ -2339,19 +2341,27 @@ Error ShaderLanguage::parse_flow_if(Parser& parser,Node *p_parent,Node **r_state
parser.advance();
+ if (parser.get_token_type()!=TK_CURLY_BRACKET_OPEN) {
+ parser.set_error("Expected statement block after 'if()'");
+ return ERR_PARSE_ERROR;
+ }
+
Node *substatement=NULL;
err = parse_statement(parser,cf,&substatement);
if (err)
return err;
-
cf->statements.push_back(substatement);
-
-
if (parser.get_token_type()==TK_CF_ELSE) {
parser.advance();
+
+ if (parser.get_token_type()!=TK_CURLY_BRACKET_OPEN) {
+ parser.set_error("Expected statement block after 'else'");
+ return ERR_PARSE_ERROR;
+ }
+
substatement=NULL;
err = parse_statement(parser,cf,&substatement);
if (err)
diff --git a/servers/visual/shader_language.h b/servers/visual/shader_language.h
index 9fd070ee2e..31e9fcda5b 100644
--- a/servers/visual/shader_language.h
+++ b/servers/visual/shader_language.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp
index 3fc90fd46d..3675194325 100644
--- a/servers/visual/visual_server_raster.cpp
+++ b/servers/visual/visual_server_raster.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -112,6 +112,21 @@ void VisualServerRaster::texture_set_reload_hook(RID p_texture,ObjectID p_owner,
rasterizer->texture_set_reload_hook(p_texture,p_owner,p_function);
}
+void VisualServerRaster::texture_set_path(RID p_texture,const String& p_path) {
+
+ rasterizer->texture_set_path(p_texture,p_path);
+}
+
+String VisualServerRaster::texture_get_path(RID p_texture) const{
+
+ return rasterizer->texture_get_path(p_texture);
+}
+
+void VisualServerRaster::texture_debug_usage(List<TextureInfo> *r_info){
+
+ rasterizer->texture_debug_usage(r_info);
+}
+
/* SHADER API */
RID VisualServerRaster::shader_create(ShaderMode p_mode) {
@@ -454,6 +469,14 @@ AABB VisualServerRaster::mesh_get_custom_aabb(RID p_mesh) const {
return rasterizer->mesh_get_custom_aabb(p_mesh);
}
+void VisualServerRaster::mesh_clear(RID p_mesh) {
+
+ ERR_FAIL_COND(!rasterizer->is_mesh(p_mesh));
+ while(rasterizer->mesh_get_surface_count(p_mesh)) {
+ rasterizer->mesh_remove_surface(p_mesh,0);
+ }
+}
+
/* MULTIMESH */
@@ -1367,7 +1390,7 @@ void VisualServerRaster::_update_baked_light_sampler_dp_cache(BakedLightSampler
void VisualServerRaster::baked_light_sampler_set_resolution(RID p_baked_light_sampler,int p_resolution){
- ERR_FAIL_COND(p_resolution<4 && p_resolution>64);
+ ERR_FAIL_COND(p_resolution<4 || p_resolution>64);
VS_CHANGED;
BakedLightSampler * blsamp = baked_light_sampler_owner.get(p_baked_light_sampler);
ERR_FAIL_COND(!blsamp);
@@ -4071,6 +4094,15 @@ void VisualServerRaster::canvas_light_set_shadow_esm_multiplier(RID p_light, flo
}
+void VisualServerRaster::canvas_light_set_shadow_color(RID p_light, const Color& p_color) {
+
+ Rasterizer::CanvasLight *clight = canvas_light_owner.get(p_light);
+ ERR_FAIL_COND(!clight);
+ clight->shadow_color=p_color;
+
+}
+
+
/****** CANVAS LIGHT OCCLUDER ******/
RID VisualServerRaster::canvas_light_occluder_create() {
@@ -5202,7 +5234,6 @@ void VisualServerRaster::_light_instance_update_lispsm_shadow(Instance *p_light,
AABB proj_space_aabb;
- float max_d,min_d;
{
@@ -6746,6 +6777,7 @@ void VisualServerRaster::_render_canvas_item_viewport(VisualServer* p_self,void
}
+
void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Matrix32& p_transform,const Rect2& p_clip_rect, float p_opacity,int p_z,Rasterizer::CanvasItem **z_list,Rasterizer::CanvasItem **z_last_list,CanvasItem *p_canvas_clip,CanvasItem *p_material_owner) {
CanvasItem *ci = p_canvas_item;
@@ -6807,7 +6839,11 @@ void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Mat
copymem(child_items,ci->child_items.ptr(),child_item_count*sizeof(CanvasItem*));
if (ci->clip) {
- ci->final_clip_rect=global_rect;
+ if (p_canvas_clip != NULL) {
+ ci->final_clip_rect=p_canvas_clip->final_clip_rect.clip(global_rect);
+ } else {
+ ci->final_clip_rect=global_rect;
+ }
ci->final_clip_owner=ci;
} else {
@@ -6843,6 +6879,7 @@ void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Mat
ci->final_opacity=opacity * ci->self_opacity;
ci->global_rect_cache=global_rect;
ci->global_rect_cache.pos-=p_clip_rect.pos;
+ ci->light_masked=false;
int zidx = p_z-CANVAS_ITEM_Z_MIN;
@@ -6870,7 +6907,34 @@ void VisualServerRaster::_render_canvas_item(CanvasItem *p_canvas_item,const Mat
}
-void VisualServerRaster::_render_canvas(Canvas *p_canvas,const Matrix32 &p_transform,Rasterizer::CanvasLight *p_lights) {
+void VisualServerRaster::_light_mask_canvas_items(int p_z,Rasterizer::CanvasItem *p_canvas_item,Rasterizer::CanvasLight *p_masked_lights) {
+
+ if (!p_masked_lights)
+ return;
+
+ Rasterizer::CanvasItem *ci=p_canvas_item;
+
+ while(ci) {
+
+ Rasterizer::CanvasLight *light=p_masked_lights;
+ while(light) {
+
+ if (ci->light_mask&light->item_mask && p_z>=light->z_min && p_z<=light->z_max && ci->global_rect_cache.intersects_transformed(light->xform_cache,light->rect_cache)) {
+ ci->light_masked=true;
+ }
+
+ light=light->mask_next_ptr;
+ }
+
+ ci=ci->next;
+ }
+
+
+
+
+}
+
+void VisualServerRaster::_render_canvas(Canvas *p_canvas,const Matrix32 &p_transform,Rasterizer::CanvasLight *p_lights,Rasterizer::CanvasLight *p_masked_lights) {
rasterizer->canvas_begin();
@@ -6903,6 +6967,11 @@ void VisualServerRaster::_render_canvas(Canvas *p_canvas,const Matrix32 &p_trans
for(int i=0;i<z_range;i++) {
if (!z_list[i])
continue;
+
+ if (p_masked_lights) {
+ _light_mask_canvas_items(CANVAS_ITEM_Z_MIN+i,z_list[i],p_masked_lights);
+ }
+
rasterizer->canvas_render_items(z_list[i],CANVAS_ITEM_Z_MIN+i,p_canvas->modulate,p_lights);
}
} else {
@@ -7037,6 +7106,7 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_
Rect2 clip_rect(0,0,viewport_rect.width,viewport_rect.height);
Rasterizer::CanvasLight *lights=NULL;
Rasterizer::CanvasLight *lights_with_shadow=NULL;
+ Rasterizer::CanvasLight *lights_with_mask=NULL;
Rect2 shadow_rect;
int light_count=0;
@@ -7084,9 +7154,14 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_
cl->radius_cache=cl->rect_cache.size.length();
}
+ if (cl->mode==CANVAS_LIGHT_MODE_MASK) {
+ cl->mask_next_ptr=lights_with_mask;
+ lights_with_mask=cl;
+ }
light_count++;
}
+
}
}
@@ -7107,6 +7182,8 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_
for(Set<Rasterizer::CanvasLightOccluderInstance*>::Element *F=E->get().canvas->occluders.front();F;F=F->next()) {
+ if (!F->get()->enabled)
+ continue;
F->get()->xform_cache = xf * F->get()->xform;
if (shadow_rect.intersects_transformed(F->get()->xform_cache,F->get()->aabb_cache)) {
@@ -7155,7 +7232,7 @@ void VisualServerRaster::_draw_viewport(Viewport *p_viewport,int p_ofs_x, int p_
ptr=ptr->filter_next_ptr;
}
- _render_canvas( E->get()->canvas,xform,canvas_lights );
+ _render_canvas( E->get()->canvas,xform,canvas_lights,lights_with_mask );
i++;
if (scenario_draw_canvas_bg && E->key().layer>=scenario_canvas_max_layer) {
@@ -7342,6 +7419,8 @@ void VisualServerRaster::_draw_cursors_and_margins() {
rasterizer->canvas_draw_rect(Rect2(cursors[i].pos, size), 0, Rect2(), tex, Color(1, 1, 1, 1));
};
+
+
if (black_image[MARGIN_LEFT].is_valid()) {
Size2 sz(rasterizer->texture_get_width(black_image[MARGIN_LEFT]),rasterizer->texture_get_height(black_image[MARGIN_LEFT]));
rasterizer->canvas_draw_rect(Rect2(0,0,black_margin[MARGIN_LEFT],window_h),0,Rect2(0,0,sz.x,sz.y),black_image[MARGIN_LEFT],Color(1,1,1));
@@ -7353,10 +7432,22 @@ void VisualServerRaster::_draw_cursors_and_margins() {
rasterizer->canvas_draw_rect(Rect2(window_w-black_margin[MARGIN_RIGHT],0,black_margin[MARGIN_RIGHT],window_h),0,Rect2(0,0,sz.x,sz.y),black_image[MARGIN_RIGHT],Color(1,1,1));
} else if (black_margin[MARGIN_RIGHT])
rasterizer->canvas_draw_rect(Rect2(window_w-black_margin[MARGIN_RIGHT],0,black_margin[MARGIN_RIGHT],window_h),0,Rect2(0,0,1,1),RID(),Color(0,0,0));
- if (black_margin[MARGIN_TOP])
+
+ if (black_image[MARGIN_TOP].is_valid()) {
+ Size2 sz(rasterizer->texture_get_width(black_image[MARGIN_TOP]),rasterizer->texture_get_height(black_image[MARGIN_TOP]));
+ rasterizer->canvas_draw_rect(Rect2(0,0,window_w,black_margin[MARGIN_TOP]),0,Rect2(0,0,sz.x,sz.y),black_image[MARGIN_TOP],Color(1,1,1));
+
+ } else if (black_margin[MARGIN_TOP]) {
rasterizer->canvas_draw_rect(Rect2(0,0,window_w,black_margin[MARGIN_TOP]),0,Rect2(0,0,1,1),RID(),Color(0,0,0));
- if (black_margin[MARGIN_BOTTOM])
+ }
+
+ if (black_image[MARGIN_BOTTOM].is_valid()) {
+
+ Size2 sz(rasterizer->texture_get_width(black_image[MARGIN_BOTTOM]),rasterizer->texture_get_height(black_image[MARGIN_BOTTOM]));
+ rasterizer->canvas_draw_rect(Rect2(0,window_h-black_margin[MARGIN_BOTTOM],window_w,black_margin[MARGIN_BOTTOM]),0,Rect2(0,0,sz.x,sz.y),black_image[MARGIN_BOTTOM],Color(1,1,1));
+ } else if (black_margin[MARGIN_BOTTOM]) {
rasterizer->canvas_draw_rect(Rect2(0,window_h-black_margin[MARGIN_BOTTOM],window_w,black_margin[MARGIN_BOTTOM]),0,Rect2(0,0,1,1),RID(),Color(0,0,0));
+ }
rasterizer->canvas_end_rect();
};
@@ -7404,6 +7495,8 @@ void VisualServerRaster::set_boot_image(const Image& p_image, const Color& p_col
if (p_image.empty())
return;
+ rasterizer->restore_framebuffer();
+
rasterizer->begin_frame();
int window_w = OS::get_singleton()->get_video_mode(0).width;
diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h
index e2940c216b..459dc60e81 100644
--- a/servers/visual/visual_server_raster.h
+++ b/servers/visual/visual_server_raster.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -633,7 +633,9 @@ class VisualServerRaster : public VisualServer {
static void _render_canvas_item_viewport(VisualServer* p_self,void *p_vp,const Rect2& p_rect);
void _render_canvas_item_tree(CanvasItem *p_canvas_item, const Matrix32& p_transform, const Rect2& p_clip_rect, const Color &p_modulate, Rasterizer::CanvasLight *p_lights);
void _render_canvas_item(CanvasItem *p_canvas_item, const Matrix32& p_transform, const Rect2& p_clip_rect, float p_opacity, int p_z, Rasterizer::CanvasItem **z_list, Rasterizer::CanvasItem **z_last_list, CanvasItem *p_canvas_clip, CanvasItem *p_material_owner);
- void _render_canvas(Canvas *p_canvas, const Matrix32 &p_transform, Rasterizer::CanvasLight *p_lights);
+ void _render_canvas(Canvas *p_canvas, const Matrix32 &p_transform, Rasterizer::CanvasLight *p_lights, Rasterizer::CanvasLight *p_masked_lights);
+ void _light_mask_canvas_items(int p_z,Rasterizer::CanvasItem *p_canvas_item,Rasterizer::CanvasLight *p_masked_lights);
+
Vector<Vector3> _camera_generate_endpoints(Instance *p_light,Camera *p_camera,float p_range_min, float p_range_max);
Vector<Plane> _camera_generate_orthogonal_planes(Instance *p_light,Camera *p_camera,float p_range_min, float p_range_max);
@@ -668,6 +670,11 @@ public:
virtual bool texture_can_stream(RID p_texture) const;
virtual void texture_set_reload_hook(RID p_texture,ObjectID p_owner,const StringName& p_function) const;
+ virtual void texture_set_path(RID p_texture,const String& p_path);
+ virtual String texture_get_path(RID p_texture) const;
+
+ virtual void texture_debug_usage(List<TextureInfo> *r_info);
+
/* SHADER API */
@@ -765,6 +772,7 @@ public:
virtual void mesh_set_custom_aabb(RID p_mesh,const AABB& p_aabb);
virtual AABB mesh_get_custom_aabb(RID p_mesh) const;
+ virtual void mesh_clear(RID p_mesh);
/* MULTIMESH API */
@@ -1180,6 +1188,8 @@ public:
virtual void canvas_light_set_shadow_enabled(RID p_light, bool p_enabled);
virtual void canvas_light_set_shadow_buffer_size(RID p_light, int p_size);
virtual void canvas_light_set_shadow_esm_multiplier(RID p_light, float p_multiplier);
+ virtual void canvas_light_set_shadow_color(RID p_light, const Color& p_color);
+
virtual RID canvas_light_occluder_create();
diff --git a/servers/visual/visual_server_wrap_mt.cpp b/servers/visual/visual_server_wrap_mt.cpp
index 19dff3d36c..478a31806c 100644
--- a/servers/visual/visual_server_wrap_mt.cpp
+++ b/servers/visual/visual_server_wrap_mt.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h
index 6719342a6a..fb502d8a6e 100644
--- a/servers/visual/visual_server_wrap_mt.h
+++ b/servers/visual/visual_server_wrap_mt.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -98,6 +98,15 @@ public:
FUNC1RC(bool,texture_can_stream,RID);
FUNC3C(texture_set_reload_hook,RID,ObjectID,const StringName&);
+ FUNC2(texture_set_path,RID,const String&);
+ FUNC1RC(String,texture_get_path,RID);
+
+ virtual void texture_debug_usage(List<TextureInfo> *r_info) {
+ //pass directly, should lock the server anyway
+ visual_server->texture_debug_usage(r_info);
+ }
+
+
/* SHADER API */
FUNC1R(RID,shader_create,ShaderMode);
@@ -199,6 +208,7 @@ public:
FUNC2(mesh_remove_surface,RID,int);
FUNC1RC(int,mesh_get_surface_count,RID);
+ FUNC1(mesh_clear,RID);
FUNC2(mesh_set_custom_aabb,RID,const AABB&);
@@ -626,6 +636,8 @@ public:
FUNC2(canvas_light_set_shadow_enabled,RID,bool);
FUNC2(canvas_light_set_shadow_buffer_size,RID,int);
FUNC2(canvas_light_set_shadow_esm_multiplier,RID,float);
+ FUNC2(canvas_light_set_shadow_color,RID,const Color&);
+
/* CANVAS OCCLUDER */
diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp
index 25e6a68469..fd2913cc7e 100644
--- a/servers/visual_server.cpp
+++ b/servers/visual_server.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -526,6 +526,7 @@ void VisualServer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("canvas_item_get_opacity"),&VisualServer::canvas_item_get_opacity);
ObjectTypeDB::bind_method(_MD("canvas_item_set_self_opacity"),&VisualServer::canvas_item_set_self_opacity);
ObjectTypeDB::bind_method(_MD("canvas_item_get_self_opacity"),&VisualServer::canvas_item_get_self_opacity);
+ ObjectTypeDB::bind_method(_MD("canvas_item_set_z"),&VisualServer::canvas_item_set_z);
ObjectTypeDB::bind_method(_MD("canvas_item_add_line"),&VisualServer::canvas_item_add_line, DEFVAL(1.0));
ObjectTypeDB::bind_method(_MD("canvas_item_add_rect"),&VisualServer::canvas_item_add_rect);
diff --git a/servers/visual_server.h b/servers/visual_server.h
index ef63907e34..4841720f41 100644
--- a/servers/visual_server.h
+++ b/servers/visual_server.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -104,6 +104,7 @@ public:
TEXTURE_FLAG_FILTER=4, /// Create texure with linear (or available) filter
TEXTURE_FLAG_ANISOTROPIC_FILTER=8,
TEXTURE_FLAG_CONVERT_TO_LINEAR=16,
+ TEXTURE_FLAG_MIRRORED_REPEAT=32, /// Repeat texture, with alternate sections mirrored
TEXTURE_FLAG_CUBEMAP=2048,
TEXTURE_FLAG_VIDEO_SURFACE=4096,
TEXTURE_FLAGS_DEFAULT=TEXTURE_FLAG_REPEAT|TEXTURE_FLAG_MIPMAPS|TEXTURE_FLAG_FILTER
@@ -134,6 +135,18 @@ public:
virtual bool texture_can_stream(RID p_texture) const=0;
virtual void texture_set_reload_hook(RID p_texture,ObjectID p_owner,const StringName& p_function) const=0;
+ virtual void texture_set_path(RID p_texture,const String& p_path)=0;
+ virtual String texture_get_path(RID p_texture) const=0;
+
+ struct TextureInfo {
+ RID texture;
+ Size2 size;
+ Image::Format format;
+ int bytes;
+ String path;
+ };
+
+ virtual void texture_debug_usage(List<TextureInfo> *r_info)=0;
/* SHADER API */
@@ -352,6 +365,8 @@ public:
virtual void mesh_set_custom_aabb(RID p_mesh,const AABB& p_aabb)=0;
virtual AABB mesh_get_custom_aabb(RID p_mesh) const=0;
+ virtual void mesh_clear(RID p_mesh)=0;
+
/* MULTIMESH API */
virtual RID multimesh_create()=0;
@@ -1026,12 +1041,14 @@ public:
CANVAS_LIGHT_MODE_ADD,
CANVAS_LIGHT_MODE_SUB,
CANVAS_LIGHT_MODE_MIX,
+ CANVAS_LIGHT_MODE_MASK,
};
virtual void canvas_light_set_mode(RID p_light, CanvasLightMode p_mode)=0;
virtual void canvas_light_set_shadow_enabled(RID p_light, bool p_enabled)=0;
virtual void canvas_light_set_shadow_buffer_size(RID p_light, int p_size)=0;
virtual void canvas_light_set_shadow_esm_multiplier(RID p_light, float p_multiplier)=0;
+ virtual void canvas_light_set_shadow_color(RID p_light, const Color& p_color)=0;
diff --git a/tools/Godot.app/Contents/Info.plist b/tools/Godot.app/Contents/Info.plist
index 3a4b51e2fe..cb2db17807 100755
--- a/tools/Godot.app/Contents/Info.plist
+++ b/tools/Godot.app/Contents/Info.plist
@@ -9,11 +9,11 @@
<key>CFBundleName</key>
<string>Godot</string>
<key>CFBundleGetInfoString</key>
- <string>(c) 2007-2014 Juan Linietsky, Ariel Manzur</string>
+ <string>(c) 2007-2016 Juan Linietsky, Ariel Manzur</string>
<key>CFBundleIconFile</key>
<string>Godot.icns</string>
<key>CFBundleIdentifier</key>
- <string>com.okamstudio.godot</string>
+ <string>org.godotengine.godot</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
@@ -25,7 +25,7 @@
<key>CFBundleVersion</key>
<string>1.0.0</string>
<key>NSHumanReadableCopyright</key>
- <string>© 2007-2014 Juan Linietsky, Ariel Manzur</string>
+ <string>© 2007-2016 Juan Linietsky, Ariel Manzur</string>
<key>LSMinimumSystemVersion</key>
<string>10.6.0</string>
<key>LSMinimumSystemVersionByArchitecture</key>
@@ -61,7 +61,7 @@
<true/>
<key>LSItemContentTypes</key>
<array>
- <string>com.okamstudio.scn</string>
+ <string>org.godotengine.scn</string>
</array>
</dict>
</array>
diff --git a/tools/Godot.app/Contents/Resources/Godot.icns b/tools/Godot.app/Contents/Resources/Godot.icns
index 18bc68d6ea..4a3dc0415a 100644
--- a/tools/Godot.app/Contents/Resources/Godot.icns
+++ b/tools/Godot.app/Contents/Resources/Godot.icns
Binary files differ
diff --git a/tools/SCsub b/tools/SCsub
index ce7df2c35b..f046e9ad08 100644
--- a/tools/SCsub
+++ b/tools/SCsub
@@ -11,11 +11,10 @@ if (env["tools"]!="no"):
SConscript('collada/SCsub');
SConscript('docdump/SCsub');
SConscript('freetype/SCsub');
+ SConscript('pe_bliss/SCsub');
SConscript('doc/SCsub')
SConscript('pck/SCsub')
lib = env.Library("tool",env.tool_sources)
env.Prepend(LIBS=[lib])
-
-
diff --git a/tools/addheader/addheader.py b/tools/addheader/addheader.py
index 038cec96d0..0252eb396d 100644
--- a/tools/addheader/addheader.py
+++ b/tools/addheader/addheader.py
@@ -6,7 +6,7 @@ header="""\
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/addheader/header.txt b/tools/addheader/header.txt
index 359949cc3b..e4efb2dcfc 100644
--- a/tools/addheader/header.txt
+++ b/tools/addheader/header.txt
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/*************************************************/
/* Source code within this file is: */
-/* (c) 2007-2010 Juan Linietsky, Ariel Manzur */
+/* (c) 2007-2016 Juan Linietsky, Ariel Manzur */
/* All Rights Reserved. */
/*************************************************/
diff --git a/tools/collada/SCsub b/tools/collada/SCsub
index c8eaa596d1..34524f10ef 100644
--- a/tools/collada/SCsub
+++ b/tools/collada/SCsub
@@ -3,5 +3,3 @@ Import('env')
env.add_source_files(env.tool_sources,"*.cpp")
Export('env')
-
-
diff --git a/tools/collada/collada.cpp b/tools/collada/collada.cpp
index b7ec5c9d04..07da72718e 100644
--- a/tools/collada/collada.cpp
+++ b/tools/collada/collada.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -1683,8 +1683,12 @@ Collada::Node* Collada::_parse_visual_scene_node(XMLParser& parser) {
if ( parser.has_attribute("sid") ) { //bones may not have sid
joint->sid=parser.get_attribute_value("sid");
// state.bone_map[joint->sid]=joint;
- } else if (state.idref_joints.has(name))
+ } else if (state.idref_joints.has(name)) {
joint->sid=name; //kind of a cheat but..
+ } else if (parser.has_attribute("name")) {
+ joint->sid=parser.get_attribute_value_safe("name");
+ }
+
if (joint->sid!="") {
state.sid_to_node_map[joint->sid]=id;
@@ -2054,8 +2058,8 @@ void Collada::_parse_animation(XMLParser& parser) {
}
if (target.find("/")!=-1) { //transform component
- track.target=target.get_slice("/",0);
- track.param=target.get_slice("/",1);
+ track.target=target.get_slicec('/',0);
+ track.param=target.get_slicec('/',1);
if (track.param.find(".")!=-1)
track.component=track.param.get_slice(".",1).to_upper();
track.param=track.param.get_slice(".",0);
diff --git a/tools/collada/collada.h b/tools/collada/collada.h
index 81f51a1f3d..8983b8faf0 100644
--- a/tools/collada/collada.h
+++ b/tools/collada/collada.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/doc/SCsub b/tools/doc/SCsub
index c8eaa596d1..34524f10ef 100644
--- a/tools/doc/SCsub
+++ b/tools/doc/SCsub
@@ -3,5 +3,3 @@ Import('env')
env.add_source_files(env.tool_sources,"*.cpp")
Export('env')
-
-
diff --git a/tools/doc/doc_data.cpp b/tools/doc/doc_data.cpp
index b3eb6b08f7..11e4797747 100644
--- a/tools/doc/doc_data.cpp
+++ b/tools/doc/doc_data.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -137,9 +137,9 @@ void DocData::merge_from(const DocData& p_data) {
void DocData::generate(bool p_basic_types) {
- List<String> classes;
+ List<StringName> classes;
ObjectTypeDB::get_type_list(&classes);
- classes.sort();
+ classes.sort_custom<StringName::AlphCompare>();
while(classes.size()) {
@@ -187,12 +187,13 @@ void DocData::generate(bool p_basic_types) {
arginfo=E->get().return_val;
- if (arginfo.type==Variant::NIL)
- continue;
+#ifdef DEBUG_METHODS_ENABLED
if (m && m->get_return_type()!=StringName())
method.return_type=m->get_return_type();
- else
+ else if (arginfo.type!=Variant::NIL) // {
+#endif
method.return_type=(arginfo.hint==PROPERTY_HINT_RESOURCE_TYPE)?arginfo.hint_string:Variant::get_type_name(arginfo.type);
+// }
} else {
@@ -547,7 +548,7 @@ void DocData::generate(bool p_basic_types) {
Globals::Singleton &s=E->get();
pd.name=s.name;
pd.type=s.ptr->get_type();
- while (ObjectTypeDB::type_inherits_from(pd.type)!="Object")
+ while (String(ObjectTypeDB::type_inherits_from(pd.type))!="Object")
pd.type=ObjectTypeDB::type_inherits_from(pd.type);
if (pd.type.begins_with("_"))
pd.type=pd.type.substr(1,pd.type.length());
@@ -583,7 +584,10 @@ void DocData::generate(bool p_basic_types) {
md.name=mi.name;
if (mi.return_val.name!="")
md.return_type=mi.return_val.name;
- else
+ else if (mi.name.find(":")!=-1) {
+ md.return_type=mi.name.get_slice(":",1);
+ md.name=mi.name.get_slice(":",0);
+ } else
md.return_type=Variant::get_type_name(mi.return_val.type);
for(int i=0;i<mi.arguments.size();i++) {
@@ -593,8 +597,9 @@ void DocData::generate(bool p_basic_types) {
ArgumentDoc ad;
ad.name=pi.name;
+
if (pi.type==Variant::NIL)
- ad.type="var";
+ ad.type="Variant";
else
ad.type=Variant::get_type_name( pi.type );
@@ -917,9 +922,9 @@ Error DocData::save(const String& p_path) {
String qualifiers;
if (m.qualifiers!="")
- qualifiers+="qualifiers=\""+m.qualifiers.xml_escape()+"\"";
+ qualifiers+=" qualifiers=\""+m.qualifiers.xml_escape()+"\"";
- _write_string(f,2,"<method name=\""+m.name+"\" "+qualifiers+" >");
+ _write_string(f,2,"<method name=\""+m.name+"\""+qualifiers+">");
if (m.return_type!="") {
diff --git a/tools/doc/doc_data.h b/tools/doc/doc_data.h
index b62eb21b4a..877f30defb 100644
--- a/tools/doc/doc_data.h
+++ b/tools/doc/doc_data.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/docdump/SCsub b/tools/docdump/SCsub
index c8eaa596d1..34524f10ef 100644
--- a/tools/docdump/SCsub
+++ b/tools/docdump/SCsub
@@ -3,5 +3,3 @@ Import('env')
env.add_source_files(env.tool_sources,"*.cpp")
Export('env')
-
-
diff --git a/tools/docdump/class_list.xml b/tools/docdump/class_list.xml
deleted file mode 100644
index 3d07f84177..0000000000
--- a/tools/docdump/class_list.xml
+++ /dev/null
@@ -1,13625 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<doc version="0.99.1384-pre-beta" name="Engine Types">
-<class name="Animation" inherits="Resource" category="Resources">
- <brief_description>
- Contains data used to animate everything in the engine.
- </brief_description>
- <description>
- An Animation resource contains data used to animate everything in the engine. Animations are divided into tracks, and each track must be linked to a node. The state of that node can be changed through time, by adding timed keys (signals) to the track. [html br/] Animations are just data containers, and must be added to odes such as an [AnimationPlayer] or [AnimationTreePlayer] to be played back.
- </description>
- <methods>
- <method name="add_track" >
- <argument index="0" name="type" type="int">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- Add a track to the Animation. The track type must be specified as any of the values in te TYPE_* enumeration.
- </description>
- </method>
- <method name="remove_track" >
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Remove a track by specifying the track index.
- </description>
- </method>
- <method name="get_track_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- Return the amount of tracks in the animation.
- </description>
- </method>
- <method name="track_get_type" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Get the type of a track.
- </description>
- </method>
- <method name="track_get_path" qualifiers="const" >
- <return type="NodePath">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Get the path of a track. for more information on the path format, see [method track_set_path]
- </description>
- </method>
- <method name="track_set_path" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="path" type="NodePath">
- </argument>
- <description>
- Set the path of a track. Paths must be valid scene-tree paths to a node, and must be specified starting from the parent node of the node that will reproduce the animation. Tracks that control properties or bones must append their name after the path, separated by &quot;:&quot;. Example: &quot;character/skeleton:ankle&quot; or &quot;character/mesh:transform/local:&quot;
- </description>
- </method>
- <method name="track_move_up" >
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="track_move_down" >
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="transform_track_insert_key" >
- <return type="int">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="time" type="real">
- </argument>
- <argument index="2" name="loc" type="Vector3">
- </argument>
- <argument index="3" name="rot" type="Quat">
- </argument>
- <argument index="4" name="scale" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="track_insert_key" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="key" type="real">
- </argument>
- <argument index="2" name="arg2" type="var">
- </argument>
- <argument index="3" name="arg3" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="track_remove_key" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="key_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="track_get_key_count" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Return the amount of keys in a given track.
- </description>
- </method>
- <method name="track_get_key_value" qualifiers="const" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="track_get_key_time" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- Return the time at which the key is located.
- </description>
- </method>
- <method name="track_find_key" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="time" type="real">
- </argument>
- <argument index="2" name="exact" type="bool" default="false">
- </argument>
- <description>
- </description>
- </method>
- <method name="track_set_interpolation_type" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="interpolation" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="track_get_interpolation_type" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="transform_track_interpolate" qualifiers="const" >
- <return type="Array">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="time_sec" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="value_track_interpolate" qualifiers="const" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="time_sec" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="blend_track_interpolate" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="time_sec" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="property_track_get_key_indices" qualifiers="const" >
- <return type="IntArray">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="time_sec" type="real">
- </argument>
- <argument index="2" name="delta" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="property_track_get_key_value" qualifiers="const" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="key_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="property_track_get_name" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="key_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="method_track_get_key_indices" qualifiers="const" >
- <return type="IntArray">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="time_sec" type="real">
- </argument>
- <argument index="2" name="delta" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="method_track_get_name" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="key_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="method_track_get_params" qualifiers="const" >
- <return type="Array">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="key_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_length" >
- <argument index="0" name="time_sec" type="real">
- </argument>
- <description>
- Set the total length of the animation (in seconds). Note that length is not delimited by the last key, as this one may be before or after the end to ensure correct interpolation and looping.
- </description>
- </method>
- <method name="get_length" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- Return the total length of the animation (in seconds).
- </description>
- </method>
- <method name="set_loop" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- Set a flag indicating that the animation must loop. This is uses for correct interpolation of animation cycles, and for hinting the player that it must restart the animation once it&apos;s over.
- </description>
- </method>
- <method name="has_loop" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- Return wether the animation has the loop flag set.
- </description>
- </method>
- </methods>
- <constants>
- <constant name="INTERPOLATION_CUBIC" value="2">
- </constant>
- <constant name="TYPE_TRANSFORM" value="0">
- Transform tracks are used to change node local transforms or skeleton pose bones. Transitions are Interpolated.
- </constant>
- <constant name="TYPE_BLEND" value="4">
- </constant>
- <constant name="TYPE_PROPERTY" value="2">
- TODO will be changed and bleh
- </constant>
- <constant name="TYPE_VALUE" value="1">
- Value tracks set values in node properties, but only those which can be Interpolated.
- </constant>
- <constant name="INTERPOLATION_NEAREST" value="0">
- </constant>
- <constant name="INTERPOLATION_LINEAR" value="1">
- </constant>
- <constant name="TYPE_METHOD" value="3">
- </constant>
- </constants>
-</class>
-<class name="AnimationPlayer" inherits="Misc" category="Nodes/Animation Nodes">
- <brief_description>
- Container and player of [Animaton] resources.
- </brief_description>
- <description>
- An animation player is used for general purpose playback of [Animation] resources. It contains a dictionary of animations (referenced by name) and custom blend times between their transitions. Additionally, animations can be played and blended in diferent channels.
- </description>
- <methods>
- <method name="add_animation" >
- <return type="int">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="animation" type="Object">
- </argument>
- <description>
- Add an animation resource to the player, which will be later referenced by the &quot;name&quot; argument.
- </description>
- </method>
- <method name="remove_animation" >
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- Remove an animation from the player (by supplying the same name used to add it).
- </description>
- </method>
- <method name="rename_animation" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="newname" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_animation" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- Request wether an [Animation] name exist within the player.
- </description>
- </method>
- <method name="get_animation" qualifiers="const" >
- <return type="Object">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- Get an [Animation] resource by requesting a name.
- </description>
- </method>
- <method name="get_animation_list" qualifiers="const" >
- <return type="StringArray">
- </return>
- <description>
- Get the list of names of the animations stored in the player.
- </description>
- </method>
- <method name="set_blend_time" >
- <argument index="0" name="anim_from" type="String">
- </argument>
- <argument index="1" name="anim_to" type="String">
- </argument>
- <argument index="2" name="sec" type="real">
- </argument>
- <description>
- Specify a blend time (in seconds) between two animations, referemced by their names.
- </description>
- </method>
- <method name="get_blend_time" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="anim_from" type="String">
- </argument>
- <argument index="1" name="anim_to" type="String">
- </argument>
- <description>
- Get the blend time between two animations, referemced by their names.
- </description>
- </method>
- <method name="play" >
- <argument index="0" name="name" type="String" default="&quot;&quot;">
- </argument>
- <argument index="1" name="channel" type="int" default="0">
- </argument>
- <description>
- Start playback of an animation (referenced by &quot;name&quot;). Optionally a channel can be specified.
- </description>
- </method>
- <method name="stop" >
- <argument index="0" name="channel" type="int" default="0">
- </argument>
- <description>
- Start playback of an animation channel. (or channel 0 if none is provided).
- </description>
- </method>
- <method name="stop_all" >
- <description>
- Stop playback on all animation channels.
- </description>
- </method>
- <method name="is_playing" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="channel" type="int" default="0">
- </argument>
- <description>
- Return wether an animation chanel is playing (or channel 0 if none is provided).
- </description>
- </method>
- <method name="get_current_animation" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="channel" type="int" default="0">
- </argument>
- <description>
- Return the name of the animation being played in a channel (or channel 0 if none is provided).
- </description>
- </method>
- <method name="set_pause" >
- <argument index="0" name="paused" type="bool">
- </argument>
- <description>
- Pause the playback in all animation channels.
- </description>
- </method>
- <method name="is_paused" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- Return [html i]true[html /i] if all playback is paused.
- </description>
- </method>
- <method name="set_speed" >
- <argument index="0" name="speed" type="real">
- </argument>
- <argument index="1" name="channel" type="int" default="0">
- </argument>
- <description>
- Set a speed scaling ratio in a given animation channel (or channel 0 if none is provided). Default ratio is [html i]1[html /i] (no scaling).
- </description>
- </method>
- <method name="get_speed" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="channel" type="int" default="0">
- </argument>
- <description>
- Get the speed scaling ratio in a given animation channel (or channel 0 if none is provided). Default ratio is [html i]1[html /i] (no scaling).
- </description>
- </method>
- <method name="seek" >
- <argument index="0" name="pos_sec" type="real">
- </argument>
- <argument index="1" name="channel" type="int" default="0">
- </argument>
- <description>
- Seek the animation in an animation channel (or channel 0 if none is provided) to a specific position (in seconds).
- </description>
- </method>
- <method name="get_pos" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="channel" type="int" default="0">
- </argument>
- <description>
- Return the playback position (in seconds) in an animation channel (or channel 0 if none is provided)
- </description>
- </method>
- <method name="find_animation" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="animation" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear_caches" >
- <description>
- The animation player creates caches for faster access to the nodes it will animate. However, if a specific node is removed, it may not notice it, so clear_caches will force the player to search for the nodes again.
- </description>
- </method>
- </methods>
- <constants>
- <constant name="MAX_CHANNELS" value="8">
- Maximum amount of animation channels.
- </constant>
- </constants>
-</class>
-<class name="AnimationTreePlayer" inherits="Node" category="Nodes/Animation Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="add_node" >
- <argument index="0" name="type" type="int">
- </argument>
- <argument index="1" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_node_id" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="node_set_name" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="node_get_name" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="node_get_input_count" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="animation_node_set_animation" >
- <argument index="0" name="arg0" type="int">
- </argument>
- <argument index="1" name="arg1" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="animation_node_get_animation" qualifiers="const" >
- <return type="Object">
- </return>
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="oneshot_node_set_fadein_time" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="time_sec" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="oneshot_node_get_fadein_time" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="oneshot_node_set_fadeout_time" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="time_sec" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="oneshot_node_get_fadeout_time" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="oneshot_node_set_autorestart" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="oneshot_node_set_autorestart_delay" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="delay_sec" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="oneshot_node_set_autorestart_random_delay" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="rand_sec" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="oneshot_node_has_autorestart" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="oneshot_node_get_autorestart_delay" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="oneshot_node_get_autorestart_random_delay" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="oneshot_node_start" >
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="oneshot_node_stop" >
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="oneshot_node_is_active" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="mix_node_set_amount" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="ratio" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="mix_node_get_amount" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="blend2_node_set_amount" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="blend" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="blend2_node_get_amount" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="blend3_node_set_amount" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="blend" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="blend3_node_get_amount" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="blend4_node_set_amount" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="blend" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="blend4_node_get_amount" qualifiers="const" >
- <return type="Vector2">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="timescale_node_set_scale" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="scale" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="timescale_node_get_scale" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="timeseek_node_seek" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="pos_sec" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="transition_node_set_input_count" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="count" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="transition_node_get_input_count" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="transition_node_delete_input" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="input_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="transition_node_set_input_auto_advance" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="input_idx" type="int">
- </argument>
- <argument index="2" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="transition_node_has_input_auto_advance" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="input_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="transition_node_set_xfade_time" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="time_sec" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="transition_node_get_xfade_time" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="transition_node_set_current" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="input_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="transition_node_get_current" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="node_set_pos" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="screen_pos" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="node_get_pos" qualifiers="const" >
- <return type="Vector2">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="remove_node" >
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="connect" >
- <return type="int">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="dst_id" type="int">
- </argument>
- <argument index="2" name="dst_input_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_connected" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="dst_id" type="int">
- </argument>
- <argument index="2" name="dst_input_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="disconnect" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="dst_input_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_active" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_active" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_base_path" >
- <argument index="0" name="path" type="NodePath">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_base_path" qualifiers="const" >
- <return type="NodePath">
- </return>
- <description>
- </description>
- </method>
- <method name="reset" >
- <description>
- </description>
- </method>
- <method name="recompute_caches" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="AudioServer" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="sample_create" >
- <return type="RID">
- </return>
- <argument index="0" name="format" type="int">
- </argument>
- <argument index="1" name="stereo" type="bool">
- </argument>
- <argument index="2" name="length" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_set_description" >
- <argument index="0" name="sample" type="RID">
- </argument>
- <argument index="1" name="description" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_get_description" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="sample" type="RID">
- </argument>
- <argument index="1" name="arg1" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_get_format" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="sample" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_is_stereo" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="sample" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_get_length" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="sample" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_set_signed_data" >
- <argument index="0" name="sample" type="RID">
- </argument>
- <argument index="1" name="data" type="RealArray">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_set_data" >
- <argument index="0" name="sample" type="RID">
- </argument>
- <argument index="1" name="arg1" type="RawArray">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_get_data" qualifiers="const" >
- <return type="RawArray">
- </return>
- <argument index="0" name="sample" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_set_mix_rate" >
- <argument index="0" name="sample" type="RID">
- </argument>
- <argument index="1" name="mix_rate" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_get_mix_rate" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="sample" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_set_loop_format" >
- <argument index="0" name="sample" type="RID">
- </argument>
- <argument index="1" name="loop_format" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_get_loop_format" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="sample" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_set_loop_begin" >
- <argument index="0" name="sample" type="RID">
- </argument>
- <argument index="1" name="pos" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_get_loop_begin" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="sample" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_set_loop_end" >
- <argument index="0" name="sample" type="RID">
- </argument>
- <argument index="1" name="pos" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="sample_get_loop_end" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="sample" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="voice_play" >
- <argument index="0" name="voice" type="RID">
- </argument>
- <argument index="1" name="sample" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_set_volume" >
- <argument index="0" name="voice" type="RID">
- </argument>
- <argument index="1" name="volume" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_set_pan" >
- <argument index="0" name="voice" type="RID">
- </argument>
- <argument index="1" name="pan" type="real">
- </argument>
- <argument index="2" name="depth" type="real" default="0">
- </argument>
- <argument index="3" name="height" type="real" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_set_filter" >
- <argument index="0" name="voice" type="RID">
- </argument>
- <argument index="1" name="type" type="int">
- </argument>
- <argument index="2" name="cutoff" type="real">
- </argument>
- <argument index="3" name="resonance" type="real">
- </argument>
- <argument index="4" name="gain" type="real" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_set_chorus" >
- <argument index="0" name="voice" type="RID">
- </argument>
- <argument index="1" name="chorus" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_set_reverb" >
- <argument index="0" name="voice" type="RID">
- </argument>
- <argument index="1" name="room" type="int">
- </argument>
- <argument index="2" name="reverb" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_set_mix_rate" >
- <argument index="0" name="voice" type="RID">
- </argument>
- <argument index="1" name="rate" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_set_positional" >
- <argument index="0" name="voice" type="RID">
- </argument>
- <argument index="1" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_get_volume" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_get_pan" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_get_pan_height" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_get_pan_depth" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_get_filter_type" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="voice" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_get_filter_cutoff" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_get_filter_resonance" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_get_chorus" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_get_reverb_type" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="voice" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_get_reverb" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_get_mix_rate" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="voice" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_is_positional" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="voice" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_stop" >
- <argument index="0" name="voice" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="free" >
- <argument index="0" name="rid" type="RID">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="SAMPLE_LOOP_PING_PONG" value="2">
- </constant>
- <constant name="SAMPLE_FORMAT_IMA_ADPCM" value="2">
- </constant>
- <constant name="FILTER_HIPASS" value="3">
- </constant>
- <constant name="FILTER_NONE" value="0">
- </constant>
- <constant name="REVERB_HALL" value="3">
- </constant>
- <constant name="REVERB_MEDIUM" value="1">
- </constant>
- <constant name="REVERB_SMALL" value="0">
- </constant>
- <constant name="FILTER_LOWPASS" value="1">
- </constant>
- <constant name="SAMPLE_LOOP_FORWARD" value="1">
- </constant>
- <constant name="REVERB_LARGE" value="2">
- </constant>
- <constant name="SAMPLE_FORMAT_PCM16" value="1">
- </constant>
- <constant name="FILTER_BANDLIMIT" value="6">
- </constant>
- <constant name="FILTER_NOTCH" value="4">
- </constant>
- <constant name="FILTER_BANDPASS" value="2">
- </constant>
- <constant name="SAMPLE_FORMAT_PCM8" value="0">
- </constant>
- <constant name="SAMPLE_LOOP_NONE" value="0">
- </constant>
- </constants>
-</class>
-<class name="AudioServerSW" inherits="AudioServer" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="AudioStream" inherits="Resource" category="Resources">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="play" >
- <description>
- </description>
- </method>
- <method name="stop" >
- <description>
- </description>
- </method>
- <method name="is_playing" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_loop" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_loop" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_stream_name" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="get_loop_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="seek_pos" >
- <argument index="0" name="pos" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_pos" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_update_mode" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="update" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="UPDATE_IDLE" value="1">
- </constant>
- <constant name="UPDATE_THREAD" value="2">
- </constant>
- <constant name="UPDATE_NONE" value="0">
- </constant>
- </constants>
-</class>
-<class name="AudioStreamOGG" inherits="AudioStream" category="Resources">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="BCSFX" inherits="ScenarioFX" category="Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="BGColorFX" inherits="ScenarioFX" category="Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="BGImageFX" inherits="ScenarioFX" category="Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="BaseButton" inherits="Control" category="Nodes/GUI Nodes">
- <brief_description>
- Provides a base class for different kinds of buttons.
- </brief_description>
- <description>
- BaseButton is the abstract base class for buttons, so it shouldn&apos;t be used directly (It doesnt display anything). Other types of buttons inherit from it.
- </description>
- <methods>
- <method name="set_pressed" >
- <argument index="0" name="pressed" type="bool">
- </argument>
- <description>
- Set the button to pressed state (only if toggle_mode is active).
- </description>
- </method>
- <method name="is_pressed" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- Return when the button is pressed (only if toggle_mode is active).
- </description>
- </method>
- <method name="set_toggle_mode" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- Set the button toggle_mode property. Toggle mode makes the button flip state between pressed and unpressed each time its area is clicked.
- </description>
- </method>
- <method name="is_toggle_mode" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- Return the toggle_mode property (see [method set_toggle_mode]).
- </description>
- </method>
- <method name="set_disabled" >
- <argument index="0" name="disabled" type="bool">
- </argument>
- <description>
- Set the button into disabled state. When a button is disabled, it can&apos;t be clicked or toggled.
- </description>
- </method>
- <method name="is_disabled" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- Return wether the button is in disabled state (see [method set_disabled]).
- </description>
- </method>
- <method name="set_click_on_press" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- Set the button click_on_press mode. This mode generates click signals when a mousebutton or key is just pressed (by default signals are generated when the button/keys are released and both press and release occur in the visual area of the Button).
- </description>
- </method>
- <method name="get_click_on_press" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- Return the state of the click_on_press property (see [method set_click_on_press]).
- </description>
- </method>
- </methods>
- <signals>
- <signal name="toggled">
- <argument index="0" name="pressed" type="bool">
- </argument>
- <description>
- This signal is emitted when the button was just toggled between pressed and normal states (only if toggle_mode is active). The new state is contained in the [html i]pressed[html /i] argument.
- </description>
- </signal>
- <signal name="pressed">
- <description>
- This signal is emitted every time the button is pressed or toggled.
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="BodyShape" inherits="Spatial" category="Nodes/3D/3D Physics Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="BoxShape" inherits="Shape" category="Resources">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_extents" >
- <argument index="0" name="extents" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_extents" qualifiers="const" >
- <return type="Vector3">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Button" inherits="BaseButton" category="Nodes/GUI Nodes">
- <brief_description>
- Standard themed Button.
- </brief_description>
- <description>
- Button is just the standard themed button: [html image src=&quot;images/button_example.png&quot;/] It can contain a text and an icon, and will display them according to the current theme.
- </description>
- <methods>
- <method name="set_text" >
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- Set the button text, which will be displayed inside the button area.
- </description>
- </method>
- <method name="get_text" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- Return the button text.
- </description>
- </method>
- <method name="set_icon" >
- <argument index="0" name="texture" type="Object">
- </argument>
- <description>
- Set the button icon, which will be displayed to the left of the text.
- </description>
- </method>
- <method name="get_icon" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- Return the button icon.
- </description>
- </method>
- <method name="set_flat" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- Set the [html i]flat[html /i] property of a Button. Flat buttons don&apos;t display decoration unless hoevered or pressed.
- </description>
- </method>
- <method name="set_clip_text" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- Set the [html i]clip_text[html /i] property of a Button. When this property is enabled, text that is too large to fit the button is clipped, when disabled (default) the Button will always be wide enough to hold the text.
- </description>
- </method>
- <method name="get_clip_text" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- Return the state of the [html i]clip_text[html /i] property (see [method set_clip_text])
- </description>
- </method>
- <method name="is_flat" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- Return the state of the [html i]flat[html /i] property (see [method set_flat])
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Camera" inherits="Spatial" category="Nodes/3D">
- <brief_description>
- Camera node, displays from a point of view.
- </brief_description>
- <description>
- Camera is a special node that displays what is visible from its current location. Cameras register themselves in the nearest [Viewport] node (when ascending the tree). Only one camera can be active per viewport. If no viewport is available ascending the tree, the Camera will register in the global viewport. In other words, a Camera just provides [html i]3D[html /i] display capabilities to a [Viewport], and, without one, a [Scene] registered in that [Viewport] (or higher viewports) can&apos;t be displayed.
- </description>
- <methods>
- <method name="project_ray_normal" qualifiers="const" >
- <return type="Vector3">
- </return>
- <argument index="0" name="screen_point" type="Vector2">
- </argument>
- <description>
- Return a normal vector in worldspace, that is the result of projecting a point on the [Viewport] rectangle by the camera proyection. This is useful for casting rays in the form of (origin,normal) for object intersection or picking.
- </description>
- </method>
- <method name="project_ray_origin" qualifiers="const" >
- <return type="Vector3">
- </return>
- <argument index="0" name="screen_point" type="Vector2">
- </argument>
- <description>
- Return a 3D position in worldspace, that is the result of projecting a point on the [Viewport] rectangle by the camera proyection. This is useful for casting rays in the form of (origin,normal) for object intersection or picking.
- </description>
- </method>
- <method name="unproject_position" qualifiers="const" >
- <return type="Vector2">
- </return>
- <argument index="0" name="world_point" type="Vector3">
- </argument>
- <description>
- Return how a 3D point in worldpsace maps to a 2D coordinate in the [Viewport] rectangle.
- </description>
- </method>
- <method name="set_perspective" >
- <argument index="0" name="fov" type="real">
- </argument>
- <argument index="1" name="z_near" type="real">
- </argument>
- <argument index="2" name="z_far" type="real">
- </argument>
- <description>
- Set the camera projection to perspective mode, by specifying a [html i]FOV[html /i] angle in degrees (FOV means Field of View), and the [html i]near[html /i] and [html i]far[html /i] clip planes in worldspace units.
- </description>
- </method>
- <method name="set_orthogonal" >
- <argument index="0" name="size" type="real">
- </argument>
- <argument index="1" name="z_near" type="real">
- </argument>
- <argument index="2" name="z_far" type="real">
- </argument>
- <description>
- Set the camera projection to orthogonal mode, by specifying a rectangle and the [html i]near[html /i] and [html i]far[html /i] clip planes in worldspace units. (As a hint, 2D games often use this projection, with values specified in pixels)
- </description>
- </method>
- <method name="make_current" >
- <description>
- Make this camera the current Camera for the [Viewport] (see class description). If the Camera Node is outside the scene tree, it will attempt to become current once it&apos;s added.
- </description>
- </method>
- <method name="clear_current" >
- <description>
- </description>
- </method>
- <method name="is_current" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- Return wether the Camera is the current one in the [Viewport], or plans to become current (if outside the scene tree).
- </description>
- </method>
- <method name="get_camera_transform" qualifiers="const" >
- <return type="Transform">
- </return>
- <description>
- Get the camera transform. Subclassed cameras (such as CharacterCamera) may provide different transforms than the [Node] transform.
- </description>
- </method>
- <method name="get_fov" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="PROJECTION_PERSPECTIVE" value="0">
- Perspective Projection (object&apos;s size on the screen becomes smaller when far away).
- </constant>
- <constant name="PROJECTION_ORTHOGONAL" value="1">
- Orthogonal Projection (objects remain the same size on the screen no matter how far away they are).
- </constant>
- </constants>
-</class>
-<class name="CanvasItem" inherits="Node" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="edit_set_state" >
- <argument index="0" name="state" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="edit_get" qualifiers="const" >
- <description>
- </description>
- </method>
- <method name="edit_set_rect" >
- <argument index="0" name="rect" type="Rect2">
- </argument>
- <description>
- </description>
- </method>
- <method name="edit_rotate" >
- <argument index="0" name="degrees" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_item_rect" qualifiers="const" >
- <return type="Rect2">
- </return>
- <description>
- </description>
- </method>
- <method name="get_canvas_item" qualifiers="const" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="is_visible" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="is_hidden" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="show" >
- <description>
- </description>
- </method>
- <method name="hide" >
- <description>
- </description>
- </method>
- <method name="update" >
- <description>
- </description>
- </method>
- <method name="set_as_toplevel" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_set_as_toplevel" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_blend_mode" >
- <argument index="0" name="blend_mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_blend_mode" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_opacity" >
- <argument index="0" name="opacity" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_opacity" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_self_opacity" >
- <argument index="0" name="self_opacity" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_self_opacity" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="item_rect_changed">
- <description>
- </description>
- </signal>
- <signal name="draw">
- <description>
- </description>
- </signal>
- <signal name="visibility_changed">
- <description>
- </description>
- </signal>
- <signal name="hide">
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- <constant name="NOTIFICATION_EXIT_CANVAS" value="33">
- </constant>
- <constant name="NOTIFICATION_DRAW" value="30">
- </constant>
- <constant name="BLEND_MODE_MUL" value="3">
- </constant>
- <constant name="BLEND_MODE_MIX" value="0">
- </constant>
- <constant name="NOTIFICATION_ENTER_CANVAS" value="32">
- </constant>
- <constant name="NOTIFICATION_VISIBILITY_CHANGED" value="31">
- </constant>
- <constant name="BLEND_MODE_ADD" value="1">
- </constant>
- <constant name="BLEND_MODE_SUB" value="2">
- </constant>
- </constants>
-</class>
-<class name="CapsuleShape" inherits="Shape" category="Resources">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_radius" >
- <argument index="0" name="radius" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_radius" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_height" >
- <argument index="0" name="height" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_height" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="CheckButton" inherits="BaseButton" category="Nodes/GUI Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_text" >
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_text" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="ColorPicker" inherits="Control" category="Nodes/GUI Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_color" >
- <argument index="0" name="arg0" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_color" qualifiers="const" >
- <return type="Color">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="color_changed">
- <argument index="0" name="color" type="Color">
- </argument>
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="ConcavePolygonShape" inherits="Shape" category="Resources">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_faces" >
- <argument index="0" name="faces" type="Vector3Array">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_faces" qualifiers="const" >
- <return type="Vector3Array">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="ConfirmationDialog" inherits="Popup" category="Nodes/GUI Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="get_ok" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="get_cancel" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="set_text" >
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_hide_on_ok" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_hide_on_ok" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="register_text_enter" >
- <argument index="0" name="line_edit" type="Object">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="confirmed">
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="Control" inherits="CanvasItem" category="Core">
- <brief_description>
- Control is the base class Node for all the GUI components.
- </brief_description>
- <description>
- Control is the base class Node for all the GUI components. Every GUI component inherits from it, directly or indirectly. Control Nodes contain positions relative to their parent control nodes. In this way, sections of the scene tree made of contiguous Control Nodes, become user interfaces.[html br/]&#10;&#9;Controls contain a [html i]canvas item[html /i] RID from the visual server, and can draw to it when receiving a NOTIFICATION_DRAW.[html br/]&#10;&#9;TODO: Explain margins and anchors[html br/]&#10;&#9;TODO: explain focus[html br/]
- </description>
- <methods>
- <method name="accept_event" >
- <description>
- </description>
- </method>
- <method name="get_minimum_size" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- Return the minimum size this Control can shrink to. A control will never be displayed or resized smaller than its minimum size.
- </description>
- </method>
- <method name="is_window" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- Return wether this control is a [html i]window[html /i]. Controls are considered windows when their parent [Node] is not a Control.
- </description>
- </method>
- <method name="get_window" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- Return the [html i]window[html /i] for this control, ascending the scene tree (see [method is_window]).
- </description>
- </method>
- <method name="set_anchor" >
- <argument index="0" name="margin" type="int">
- </argument>
- <argument index="1" name="anchor_mode" type="int">
- </argument>
- <description>
- Change the anchor (ANCHOR_BEGIN, ANCHOR_END, ANCHOR_RATIO) type for a margin (MARGIN_LEFT, MARGIN_TOP, MARGIN_RIGHT, MARGIN_BOTTOM). Changing the anchor mode converts the current margin offset from the previos anchor mode to the new one, so margin offsets ([method set_margin]) must be done after setting anchors, or at the same time ([method set_anchor_and_margin]).
- </description>
- </method>
- <method name="get_anchor" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="margin" type="int">
- </argument>
- <description>
- Return the anchor type (ANCHOR_BEGIN, ANCHOR_END, ANCHOR_RATIO) for a given margin (MARGIN_LEFT, MARGIN_TOP, MARGIN_RIGHT, MARGIN_BOTTOM).
- </description>
- </method>
- <method name="set_margin" >
- <argument index="0" name="margin" type="int">
- </argument>
- <argument index="1" name="offset" type="real">
- </argument>
- <description>
- Set a margin offset. Margin can be one of (MARGIN_LEFT, MARGIN_TOP, MARGIN_RIGHT, MARGIN_BOTTOM). Offset value being set depends on the anchor mode.
- </description>
- </method>
- <method name="set_anchor_and_margin" >
- <argument index="0" name="margin" type="int">
- </argument>
- <argument index="1" name="anchor_mode" type="int">
- </argument>
- <argument index="2" name="offset" type="real">
- </argument>
- <description>
- Change the anchor (ANCHOR_BEGIN, ANCHOR_END, ANCHOR_RATIO) type for a margin (MARGIN_LEFT, MARGIN_TOP, MARGIN_RIGHT, MARGIN_BOTTOM), and also set its offset. This is a helper (see [method set_anchor] and [method set_margin]).
- </description>
- </method>
- <method name="set_begin" >
- <argument index="0" name="pos" type="Vector2">
- </argument>
- <description>
- Sets MARGIN_LEFT and MARGIN_TOP at the same time. This is a helper (see [method set_margin]).
- </description>
- </method>
- <method name="set_end" >
- <argument index="0" name="pos" type="Vector2">
- </argument>
- <description>
- Sets MARGIN_RIGHT and MARGIN_BOTTOM at the same time. This is a helper (see [method set_margin]).
- </description>
- </method>
- <method name="set_pos" >
- <argument index="0" name="pos" type="Vector2">
- </argument>
- <description>
- Move the Control to a new position, relative to the top-left corner of the parent Control, changing all margins if needed and without changing current anchor mode. This is a helper (see [method set_margin]).
- </description>
- </method>
- <method name="set_size" >
- <argument index="0" name="size" type="Vector2">
- </argument>
- <description>
- Changes MARGIN_RIGHT and MARGIN_BOTTOM to fit a given size. This is a helper (see [method set_margin]).
- </description>
- </method>
- <method name="set_global_pos" >
- <argument index="0" name="pos" type="Vector2">
- </argument>
- <description>
- Move the Control to a new position, relative to the top-left corner of the [html i]window[html /i] Control, and without changing current anchor mode. (see [method set_margin]).
- </description>
- </method>
- <method name="get_margin" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="margin" type="int">
- </argument>
- <description>
- Return a margin offset. Margin can be one of (MARGIN_LEFT, MARGIN_TOP, MARGIN_RIGHT, MARGIN_BOTTOM). Offset value being returned depends on the anchor mode.
- </description>
- </method>
- <method name="get_begin" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="get_end" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- Returns MARGIN_LEFT and MARGIN_TOP at the same time. This is a helper (see [method set_margin]).
- </description>
- </method>
- <method name="get_pos" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- Returns the Control position, relative to the top-left corner of the parent Control and independly of the anchor mode.
- </description>
- </method>
- <method name="get_size" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- Returns the size of the Control, computed from all margins, however the size returned will [html b]never be smaller than the minimum size reported by [method get_minimum_size][html /b]. This means that even if end position of the Control rectangle is smaller than the begin position, the Control will still display and interact correctly. (see description, [method get_minimum_size], [method set_margin], [method set_anchor]).
- </description>
- </method>
- <method name="get_global_pos" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- Returns the Control position, relative to the top-left corner of the parent Control and independent of the anchor mode.
- </description>
- </method>
- <method name="get_rect" qualifiers="const" >
- <return type="Rect2">
- </return>
- <description>
- Return position and size of the Control, relative to the top-left corner of the parent Control. This is a helper (see [method get_pos],[method get_size]).
- </description>
- </method>
- <method name="get_global_rect" qualifiers="const" >
- <return type="Rect2">
- </return>
- <description>
- Return position and size of the Control, relative to the top-left corner of the [html i]window[html /i] Control. This is a helper (see [method get_global_pos],[method get_size]).
- </description>
- </method>
- <method name="set_area_as_parent_rect" >
- <description>
- Change all margins and anchors, so this Control always takes up the same area as the parent Control. This is a helper (see [method set_anchor],[method set_margin]).
- </description>
- </method>
- <method name="show_modal" >
- <argument index="0" name="exclusive" type="bool" default="false">
- </argument>
- <description>
- Display a Control as modal. Control must be a subwindow (see [method set_as_subwindow]). Modal controls capture the input signals until closed or the area outside them is accessed. When a modal control loses focus, or the ESC key is pressed, they automatically hide. Modal controls are used extensively for popup dialogs and menus.
- </description>
- </method>
- <method name="set_focus_mode" >
- <argument index="0" name="mode" type="int">
- </argument>
- <description>
- Set the focus access mode for the control (FOCUS_NONE, FOCUS_CLICK, FOCUS_ALL). Only one Control can be focused at the same time, and it will receive keyboard signals.
- </description>
- </method>
- <method name="has_focus" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- Return wether the Control is the current focused control (see [method set_focus_mode]).
- </description>
- </method>
- <method name="grab_focus" >
- <description>
- Steal the focus from another control and become the focused control (see [method set_focus_mode]).
- </description>
- </method>
- <method name="set_theme" >
- <argument index="0" name="theme" type="Object">
- </argument>
- <description>
- Override whole the [Theme] for this Control and all its children controls.
- </description>
- </method>
- <method name="get_theme" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- Return a [Theme] override, if one exists (see [method set_theme]).
- </description>
- </method>
- <method name="add_icon_override" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="texture" type="Object">
- </argument>
- <description>
- Override a single icon ([Texture]) in the theme of this Control. If texture is empty, override is cleared.
- </description>
- </method>
- <method name="add_style_override" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="stylebox" type="Object">
- </argument>
- <description>
- Override a single stylebox ([Stylebox]) in the theme of this Control. If stylebox is empty, override is cleared.
- </description>
- </method>
- <method name="add_font_override" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="font" type="Object">
- </argument>
- <description>
- Override a single font (font) in the theme of this Control. If font is empty, override is cleared.
- </description>
- </method>
- <method name="add_color_override" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_constant_override" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="constant" type="int">
- </argument>
- <description>
- Override a single constant (integer) in the theme of this Control. If constant equals Theme.INVALID_CONSTANT, override is cleared.
- </description>
- </method>
- <method name="get_parent_control" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- Return the parent Control. Unlike get_parent() in [Node], only returns a valid object if the parent is a Control.
- </description>
- </method>
- <method name="set_tooltip" >
- <argument index="0" name="tooltip" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_tooltip" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="atpos" type="Vector2" default="Vector2(0,0)">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_default_cursor_shape" >
- <argument index="0" name="shape" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_default_cursor_shape" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_cursor_shape" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="pos" type="Vector2" default="Vector2(0,0)">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_focus_neighbour" >
- <argument index="0" name="margin" type="int">
- </argument>
- <argument index="1" name="neighbour" type="NodePath">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_focus_neighbour" qualifiers="const" >
- <return type="NodePath">
- </return>
- <argument index="0" name="margin" type="int">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="focus_enter">
- <description>
- </description>
- </signal>
- <signal name="mouse_enter">
- <description>
- </description>
- </signal>
- <signal name="resized">
- <description>
- </description>
- </signal>
- <signal name="focus_exit">
- <description>
- </description>
- </signal>
- <signal name="input_event">
- <description>
- </description>
- </signal>
- <signal name="mouse_exit">
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- <constant name="CURSOR_FDIAGSIZE" value="12">
- </constant>
- <constant name="CURSOR_CAN_DROP" value="7">
- </constant>
- <constant name="CURSOR_DRAG" value="6">
- </constant>
- <constant name="CURSOR_IBEAM" value="1">
- </constant>
- <constant name="NOTIFICATION_FOCUS_ENTER" value="37">
- Control gained focus.
- </constant>
- <constant name="CURSOR_MOVE" value="13">
- </constant>
- <constant name="NOTIFICATION_MOUSE_ENTER" value="35">
- Mouse pointer entered the area of the Control.
- </constant>
- <constant name="NOTIFICATION_RESIZED" value="34">
- Control changed size (get_size() reports the new size).
- </constant>
- <constant name="FOCUS_CLICK" value="1">
- Control can acquire focus only if clicked.
- </constant>
- <constant name="CURSOR_HELP" value="16">
- </constant>
- <constant name="CURSOR_VSIZE" value="9">
- </constant>
- <constant name="CURSOR_VSPLIT" value="14">
- </constant>
- <constant name="CURSOR_BDIAGSIZE" value="11">
- </constant>
- <constant name="CURSOR_CROSS" value="3">
- </constant>
- <constant name="CURSOR_POINTING_HAND" value="2">
- </constant>
- <constant name="NOTIFICATION_FOCUS_EXIT" value="38">
- Control lost focus.
- </constant>
- <constant name="FOCUS_NONE" value="0">
- Control can&apos;t acquire focus.
- </constant>
- <constant name="ANCHOR_BEGIN" value="0">
- X is relative to MARGIN_LEFT, Y is relative to MARGIN_TOP,
- </constant>
- <constant name="CURSOR_HSIZE" value="10">
- </constant>
- <constant name="CURSOR_BUSY" value="5">
- </constant>
- <constant name="CURSOR_ARROW" value="0">
- </constant>
- <constant name="NOTIFICATION_MODAL_CLOSE" value="40">
- </constant>
- <constant name="NOTIFICATION_MOUSE_EXIT" value="36">
- Mouse pointer exited the area of the Control.
- </constant>
- <constant name="FOCUS_ALL" value="2">
- Control can acquire focus if clicked, or by pressing TAB/Directionals in the keyboard from another Control.
- </constant>
- <constant name="CURSOR_HSPLIT" value="15">
- </constant>
- <constant name="ANCHOR_RATIO" value="2">
- X and Y are a ratio (0 to 1) relative to the parent size 0 is left/top, 1 is right/bottom.
- </constant>
- <constant name="ANCHOR_END" value="1">
- X is relative to -MARGIN_RIGHT, Y is relative to -MARGIN_BOTTOM,
- </constant>
- <constant name="CURSOR_FORBIDDEN" value="8">
- </constant>
- <constant name="CURSOR_WAIT" value="4">
- </constant>
- <constant name="NOTIFICATION_THEME_CHANGED" value="39">
- </constant>
- </constants>
-</class>
-<class name="ConvexPolygonShape" inherits="Shape" category="Resources">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_planes" >
- <argument index="0" name="planes" type="Array">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_planes" qualifiers="const" >
- <return type="Array">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="GridMap" inherits="Spatial" category="Nodes/3D">
- <brief_description>
- GridMap is like a tile map, but in 3D.
- </brief_description>
- <description>
- GridMap is a 3D Tile map, using [html i]3D Cells[html /i] instead of tiles. On each cell, a mesh and a collision volume can be placed from a [MeshLibrary]. GridMap is used for designing worlds quickly. Despite that GridMaps can contain up to hundreds millions of cells, they are very optimized, and only use resources for the cells that contain items.
- </description>
- <methods>
- <method name="set_theme" >
- <argument index="0" name="theme" type="Object">
- </argument>
- <description>
- Set a MeshLibrary. Cell indices refer to items in the theme.
- </description>
- </method>
- <method name="get_theme" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- Get the current MeshLibrary (if exists).
- </description>
- </method>
- <method name="set_cell_size" >
- <argument index="0" name="size" type="real">
- </argument>
- <description>
- Set the size of a cell, in worldpsace units. All cells in a GridMap are the same size.
- </description>
- </method>
- <method name="get_cell_size" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- Return the current cell size.
- </description>
- </method>
- <method name="set_octant_size" >
- <argument index="0" name="size" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_octant_size" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_width" >
- <argument index="0" name="width" type="int">
- </argument>
- <description>
- Set the width of the GridMap. Width is the amount of cells i the direction of the X coordinate.
- </description>
- </method>
- <method name="get_width" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- Get the width of the GridMap. Width is the amount of cells i the direction of the X coordinate.
- </description>
- </method>
- <method name="set_height" >
- <argument index="0" name="height" type="int">
- </argument>
- <description>
- Set the height of the GridMap. Height is the amount of cells i the direction of the Y coordinate.
- </description>
- </method>
- <method name="get_height" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- Get the height of the GridMap. Height is the amount of cells i the direction of the Y coordinate.
- </description>
- </method>
- <method name="set_depth" >
- <argument index="0" name="depth" type="int">
- </argument>
- <description>
- Set the depth of the GridMap. Depth is the amount of cells i the direction of the Z coordinate.
- </description>
- </method>
- <method name="get_depth" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- Get the depth of the GridMap. Depth is the amount of cells i the direction of the Z coordinate.
- </description>
- </method>
- <method name="set_cell_item" >
- <argument index="0" name="x" type="int">
- </argument>
- <argument index="1" name="y" type="int">
- </argument>
- <argument index="2" name="z" type="int">
- </argument>
- <argument index="3" name="item" type="int">
- </argument>
- <argument index="4" name="orientation" type="int" default="0">
- </argument>
- <description>
- Set a cell item (x,y,z pos). Cell items are indices to items in the [MeshLibrary].
- </description>
- </method>
- <method name="get_cell_item" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="x" type="int">
- </argument>
- <argument index="1" name="y" type="int">
- </argument>
- <argument index="2" name="z" type="int">
- </argument>
- <description>
- Get a cell item (x,y,z pos). Cell items are indices to items in the [MeshLibrary].
- </description>
- </method>
- <method name="get_cell_item_orientation" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="x" type="int">
- </argument>
- <argument index="1" name="y" type="int">
- </argument>
- <argument index="2" name="z" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="resource_changed" >
- <argument index="0" name="arg0" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_center_x" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_center_x" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_center_y" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_center_y" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_center_z" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_center_z" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_clip" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <argument index="1" name="clipabove" type="bool" default="true">
- </argument>
- <argument index="2" name="floor" type="int" default="0">
- </argument>
- <argument index="3" name="axis" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="crate_area" >
- <return type="int">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="area" type="AABB">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_get_bounds" qualifiers="const" >
- <return type="AABB">
- </return>
- <argument index="0" name="area" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_set_exterior_portal" >
- <argument index="0" name="area" type="int">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_set_name" >
- <argument index="0" name="area" type="int">
- </argument>
- <argument index="1" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_get_name" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="area" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_is_exterior_portal" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="area" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_set_portal_disable_distance" >
- <argument index="0" name="area" type="int">
- </argument>
- <argument index="1" name="distance" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_get_portal_disable_distance" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="area" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_set_portal_disable_color" >
- <argument index="0" name="area" type="int">
- </argument>
- <argument index="1" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_get_portal_disable_color" qualifiers="const" >
- <return type="Color">
- </return>
- <argument index="0" name="area" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="erase_area" >
- <argument index="0" name="area" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_unused_area_id" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="INVALID_CELL_ITEM" value="-1">
- Value indicating that a cell item is not used or invalid.
- </constant>
- </constants>
-</class>
-<class name="MeshLibrary" inherits="Resource" category="Resources">
- <brief_description>
- Theme for a [GridMap].
- </brief_description>
- <description>
- MeshLibrary is [Resource] containing the data used in a [GridMap]. It&apos;s filled with items, each containing a mesh and a collision shape.
- </description>
- <methods>
- <method name="create_item" >
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- Create a new item, and assign it a given id.
- </description>
- </method>
- <method name="set_item_name" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="name" type="String">
- </argument>
- <description>
- Set the name of an item, referenced by id.
- </description>
- </method>
- <method name="set_item_mesh" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="mesh" type="Object">
- </argument>
- <description>
- Set the [Mesh] of an item, referenced by id.
- </description>
- </method>
- <method name="set_item_shape" >
- <argument index="0" name="id" type="int">
- </argument>
- <argument index="1" name="shape" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_item_name" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- Get the name of an item, referenced by id.
- </description>
- </method>
- <method name="get_item_mesh" qualifiers="const" >
- <return type="Object">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- Get the [Mesh] of an item, referenced by id.
- </description>
- </method>
- <method name="get_item_shape" qualifiers="const" >
- <return type="Object">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="remove_item" >
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- Remove an item, referenced by id.
- </description>
- </method>
- <method name="clear" >
- <description>
- Clear all items contained in this resource.
- </description>
- </method>
- <method name="get_item_list" qualifiers="const" >
- <return type="IntArray">
- </return>
- <description>
- Get the list of item IDs contained in this theme.
- </description>
- </method>
- <method name="get_last_unused_item_id" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- Get the last unused item id. This is useful for creating new item IDs.
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="CylinderShape" inherits="Shape" category="Resources">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_radius" >
- <argument index="0" name="radius" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_radius" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_height" >
- <argument index="0" name="height" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_height" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="DOFBlurFX" inherits="ScenarioFX" category="Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="DirectionalLight" inherits="Light" category="Nodes/3D/3D Visual Nodes/3D Light Nodes">
- <brief_description>
- Directional Light, such as the Sun or the Moon.
- </brief_description>
- <description>
- A DirectionalLight is a type of [Light] node that emits light constantly in one direction (the negative z axis of the node). It is used lights with strong intensity that are located far away from the scene to model sunlight or moonlight. The worldpace location of the DirectionalLight transform (origin) is ignored, only the basis is used do determine light direction.
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="DynamicBody" inherits="PhysicsBody" category="Nodes/3D">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_mass" >
- <argument index="0" name="mass" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_friction" >
- <argument index="0" name="friction" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_bounce" >
- <argument index="0" name="bounce" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_mass" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_friction" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_bounce" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_linear_velocity" >
- <argument index="0" name="linear_velocity" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_linear_velocity" qualifiers="const" >
- <return type="Vector3">
- </return>
- <description>
- </description>
- </method>
- <method name="set_angular_velocity" >
- <argument index="0" name="angular_velocity" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_angular_velocity" qualifiers="const" >
- <return type="Vector3">
- </return>
- <description>
- </description>
- </method>
- <method name="set_sleeping" >
- <argument index="0" name="sleeping" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_sleeping" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_applied_force" >
- <argument index="0" name="applied_force" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_applied_force" qualifiers="const" >
- <return type="Vector3">
- </return>
- <description>
- </description>
- </method>
- <method name="set_applied_torque" >
- <argument index="0" name="applied_torque" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_applied_torque" qualifiers="const" >
- <return type="Vector3">
- </return>
- <description>
- </description>
- </method>
- <method name="apply_local_impulse" >
- <argument index="0" name="pos" type="Vector3">
- </argument>
- <argument index="1" name="impulse" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_axis_velocity" >
- <argument index="0" name="axis_velocity" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_direct_state_control" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_direct_state_control_enabled" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_omit_force_integration" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_omitting_force_integration" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="DynamicCharacterBody" inherits="DynamicBody" category="Nodes/3D">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="DynamicCustomBody" inherits="DynamicBody" category="Nodes/3D">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_mode" >
- <argument index="0" name="mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="DynamicRigidBody" inherits="DynamicBody" category="Nodes/3D">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="FileDialog" inherits="Popup" category="Nodes/GUI Nodes">
- <brief_description>
- Dialog for selecting files or directories in the filesystem.
- </brief_description>
- <description>
- FileDialog is a preset dialog used to choose files and directories in the filesystem. It supports filter masks.
- </description>
- <methods>
- <method name="clear_filters" >
- <description>
- Clear all the added filters in the dialog.
- </description>
- </method>
- <method name="add_filter" >
- <argument index="0" name="filter" type="String">
- </argument>
- <description>
- Add a custom filter. Filter format is: &quot;mask ; description.
- </description>
- </method>
- <method name="get_current_dir" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- Get the current working directory of the file dialog.
- </description>
- </method>
- <method name="get_current_file" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- Get the current selected file of the file dialog (empty if none).
- </description>
- </method>
- <method name="get_current_path" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- Get the current selected path (directory and file) of the file dialog (empty if none).
- </description>
- </method>
- <method name="set_current_dir" >
- <argument index="0" name="dir" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_current_file" >
- <argument index="0" name="file" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_current_path" >
- <argument index="0" name="path" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_mode" >
- <argument index="0" name="mode" type="int">
- </argument>
- <description>
- Set the file dialog mode from the MODE_* enum.
- </description>
- </method>
- <method name="get_mode" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- Get the file dialog mode from the MODE_* enum.
- </description>
- </method>
- </methods>
- <signals>
- <signal name="dir_selected">
- <argument index="0" name="dir" type="String">
- </argument>
- <description>
- </description>
- </signal>
- <signal name="file_selected">
- <argument index="0" name="path" type="String">
- </argument>
- <description>
- Event emitted when the user selects a file (double clicks it or presses the OK button).
- </description>
- </signal>
- </signals>
- <constants>
- <constant name="MODE_OPEN_DIR" value="1">
- </constant>
- <constant name="MODE_OPEN_FILE" value="0">
- Editor will not allow to select nonexistent files.
- </constant>
- <constant name="MODE_SAVE_FILE" value="2">
- Editor will warn when a file exists.
- </constant>
- </constants>
-</class>
-<class name="FixedMaterial" inherits="Material" category="Resources">
- <brief_description>
- Simple Material with a fixed parameter set.
- </brief_description>
- <description>
- FixedMaterial is a simple type of material [Resource], which contains a fixed amount of paramters. It is the only type of material supported in fixed-pipeline devices and APIs. It is also an often a better alternative to [ShaderMaterial] for most simple use cases.
- </description>
- <methods>
- <method name="set_shader" >
- <argument index="0" name="shader" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_shader" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="set_parameter" >
- <argument index="0" name="param" type="int">
- </argument>
- <argument index="1" name="value" type="var">
- </argument>
- <description>
- Set a parameter, parameters are defined in the PARAM_* enum. The type of each parameter may change, so it&apos;s best to check the enum.
- </description>
- </method>
- <method name="get_parameter" qualifiers="const" >
- <argument index="0" name="param" type="int">
- </argument>
- <description>
- Return a parameter, parameters are defined in the PARAM_* enum. The type of each parameter may change, so it&apos;s best to check the enum.
- </description>
- </method>
- <method name="set_texture" >
- <argument index="0" name="param" type="int">
- </argument>
- <argument index="1" name="texture" type="Object">
- </argument>
- <description>
- Set a texture. Textures change parameters per texel and are mapped to the model depending on the texcoord mode (see [method set_texcoord_mode]).
- </description>
- </method>
- <method name="get_texture" qualifiers="const" >
- <return type="Object">
- </return>
- <argument index="0" name="param" type="int">
- </argument>
- <description>
- Return a texture. Textures change parameters per texel and are mapped to the model depending on the texcoord mode (see [method set_texcoord_mode]).
- </description>
- </method>
- <method name="set_texgen_mode" >
- <argument index="0" name="mode" type="int">
- </argument>
- <description>
- Set the texture coordinate generation mode. Materials have a unique, texgen mode which can generate texture coordinates on the fly. Texgen mode must be one of the values from the TEXGEN_* enum. TEXGEN can be selected as a texture coordinate mode (see [method set_texcoord_mode]).
- </description>
- </method>
- <method name="get_texgen_mode" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- Return the texture coordinate generation mode. Materials have a unique, texgen mode which can generate texture coordinates on the fly. Texgen mode must be one of the values from the TEXGEN_* enum. TEXGEN can be selected as a texture coordinate mode (see [method set_texcoord_mode]).
- </description>
- </method>
- <method name="set_texcoord_mode" >
- <argument index="0" name="param" type="int">
- </argument>
- <argument index="1" name="mode" type="int">
- </argument>
- <description>
- Set the texture coordinate mode. Each texture param (from the PARAM_* enum) has one. It defines how the textures are mapped to the object.
- </description>
- </method>
- <method name="get_texcoord_mode" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="param" type="int">
- </argument>
- <description>
- Return the texture coordinate mode. Each texture param (from the PARAM_* enum) has one. It defines how the textures are mapped to the object.
- </description>
- </method>
- <method name="set_uv_transform" >
- <argument index="0" name="transform" type="Transform">
- </argument>
- <description>
- Sets a special transform used to post-transform UV coordinates of the uv_xfrom tecoord mode: TEXCOORD_UV_TRANSFORM
- </description>
- </method>
- <method name="get_uv_transform" qualifiers="const" >
- <return type="Transform">
- </return>
- <description>
- Returns the special transform used to post-transform UV coordinates of the uv_xfrom tecoord mode: TEXCOORD_UV_TRANSFORM
- </description>
- </method>
- </methods>
- <constants>
- <constant name="PARAM_SPECULAR_EXP" value="4">
- Specular Exponent (size of the specular dot)
- </constant>
- <constant name="PARAM_DETAIL" value="1">
- Detail Layer for diffuse lighting.
- </constant>
- <constant name="TEXCOORD_UV2" value="2">
- Read texture coordinates from the UV2 array.
- </constant>
- <constant name="TEXGEN_SCREENZ" value="3">
- Use the screen coordinates as UV, scaled by depth and the screenz coefficient.
- </constant>
- <constant name="TEXCOORD_UV_TRANSFORM" value="1">
- Read texture coordinates from the UV array and transform them by uv_xform.
- </constant>
- <constant name="TEXGEN_LOCAL_XY" value="0">
- Use object local X and Y coordinates as UV.
- </constant>
- <constant name="PARAM_SHADE_PARAM" value="8">
- </constant>
- <constant name="PARAM_MAX" value="9">
- Maximum amount of parameters
- </constant>
- <constant name="PARAM_DIFFUSE" value="0">
- Diffuse Lighting (light scattered from surface).
- </constant>
- <constant name="PARAM_EMISSION" value="3">
- Emission Lighting (light emitted from the surface)
- </constant>
- <constant name="PARAM_SPECULAR" value="2">
- Specular Lighting (light reflected from the surface).
- </constant>
- <constant name="PARAM_DETAIL_MIX" value="6">
- Mix coefficient for the detail layer.
- </constant>
- <constant name="TEXGEN_SPHERE" value="1">
- Use view normal reflected by object normal as UV.
- </constant>
- <constant name="PARAM_NORMAL" value="7">
- Normal Map (irregularity map).
- </constant>
- <constant name="PARAM_GLOW" value="5">
- Glow (Visible emitted scattered light).
- </constant>
- <constant name="TEXCOORD_UV" value="0">
- Read texture coordinates from the UV array.
- </constant>
- <constant name="TEXCOORD_TEXGEN" value="3">
- Use texture coordinates from the texgen.
- </constant>
- <constant name="TEXGEN_SCREEN" value="2">
- Use the screen coordinates as UV.
- </constant>
- </constants>
-</class>
-<class name="FogFX" inherits="ScenarioFX" category="Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="FollowCamera" inherits="Camera" category="Nodes/3D">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_orbit" >
- <argument index="0" name="orbit" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_orbit" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="set_orbit_x" >
- <argument index="0" name="x" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_orbit_y" >
- <argument index="0" name="y" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_min_orbit_x" >
- <argument index="0" name="x" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_min_orbit_x" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_max_orbit_x" >
- <argument index="0" name="x" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_max_orbit_x" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_height" >
- <argument index="0" name="height" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_height" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_inclination" >
- <argument index="0" name="inclination" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_inclination" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="rotate_orbit" >
- <argument index="0" name="arg0" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_distance" >
- <argument index="0" name="distance" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_distance" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_max_distance" >
- <argument index="0" name="max_distance" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_max_distance" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_min_distance" >
- <argument index="0" name="min_distance" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_min_distance" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_clip" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_clip" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_autoturn" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_autoturn" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_autoturn_tolerance" >
- <argument index="0" name="degrees" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_autoturn_tolerance" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_autoturn_speed" >
- <argument index="0" name="speed" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_autoturn_speed" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_smoothing" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_smoothing" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_rotation_smoothing" >
- <argument index="0" name="amount" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_rotation_smoothing" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_translation_smoothing" >
- <argument index="0" name="amount" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_translation_smoothing" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_use_lookat_target" >
- <argument index="0" name="use" type="bool">
- </argument>
- <argument index="1" name="lookat" type="Vector3" default="Vector3(0, 0, 0)">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Font" inherits="Resource" category="Resources">
- <brief_description>
- Internationalized font and text drawing support.
- </brief_description>
- <description>
- Font contains an unicode compatible character set, as well as the ability to draw it with variable width, ascent, descent and kerning. For creating fonts from TTF files (or other font formats), see the editor support for fonts. TODO check wikipedia for graph of ascent/baseline/descent/height/etc.
- </description>
- <methods>
- <method name="set_height" >
- <argument index="0" name="px" type="real">
- </argument>
- <description>
- Set the total font height (ascent plus descent) in pixels.
- </description>
- </method>
- <method name="get_height" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- Return the total font height (ascent plus descent) in pixels.
- </description>
- </method>
- <method name="set_ascent" >
- <argument index="0" name="px" type="real">
- </argument>
- <description>
- Set the font ascent (number of pixels above the baseline).
- </description>
- </method>
- <method name="get_ascent" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- Return the font ascent (number of pixels above the baseline).
- </description>
- </method>
- <method name="get_descent" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- Return the font descent (number of pixels below the baseline).
- </description>
- </method>
- <method name="add_kerning_pair" >
- <argument index="0" name="char_a" type="int">
- </argument>
- <argument index="1" name="char_b" type="int">
- </argument>
- <argument index="2" name="kerning" type="int">
- </argument>
- <description>
- Add a kerning pair to the [Font] as a difference. Kerning pairs are special cases where a typeface advance is determined by the next character.
- </description>
- </method>
- <method name="get_kerning_pair" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="int">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- Return a kerning pair as a difference. Kerning pairs are special cases where a typeface advance is determined by the next character.
- </description>
- </method>
- <method name="add_texture" >
- <argument index="0" name="texture" type="Object">
- </argument>
- <description>
- Add a texture to the [Font].
- </description>
- </method>
- <method name="add_char" >
- <argument index="0" name="character" type="int">
- </argument>
- <argument index="1" name="texture" type="int">
- </argument>
- <argument index="2" name="rect" type="Rect2">
- </argument>
- <argument index="3" name="align" type="Vector2" default="Vector2(0,0)">
- </argument>
- <argument index="4" name="advance" type="real" default="-1">
- </argument>
- <description>
- Add a character to the font, where &quot;character&quot; is the unicode value, &quot;texture&quot; is the texture index, &quot;rect&quot; is the region in the texture (in pixels!), &quot;align&quot; is the (optional) alignment for the character and &quot;advance&quot; is the (optional) advance.
- </description>
- </method>
- <method name="get_char_size" qualifiers="const" >
- <return type="Vector2">
- </return>
- <argument index="0" name="char" type="int">
- </argument>
- <argument index="1" name="next" type="int" default="0">
- </argument>
- <description>
- Return the size of a character, optionally taking kerning into account if the next character is provided.
- </description>
- </method>
- <method name="get_string_size" qualifiers="const" >
- <return type="Vector2">
- </return>
- <argument index="0" name="string" type="String">
- </argument>
- <description>
- Return the size of a string, taking kerning and advance into account.
- </description>
- </method>
- <method name="clear" >
- <description>
- Clear all the font data.
- </description>
- </method>
- <method name="draw" qualifiers="const" >
- <argument index="0" name="canvas_item" type="RID">
- </argument>
- <argument index="1" name="pos" type="Vector2">
- </argument>
- <argument index="2" name="string" type="String">
- </argument>
- <argument index="3" name="modulate" type="Color" default="Color(1,1,1,1)">
- </argument>
- <argument index="4" name="clip_w" type="int" default="-1">
- </argument>
- <description>
- Draw &quot;string&quot; into a canvas item using the font at a given &quot;pos&quot; position, with &quot;modulate&quot; color, and optionally clipping the width. &quot;pos&quot; specifies te baseline, not the top. To draw from the top, [html i]ascent[html /i] must be added to the Y axis.
- </description>
- </method>
- <method name="draw_char" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="canvas_item" type="RID">
- </argument>
- <argument index="1" name="pos" type="Vector2">
- </argument>
- <argument index="2" name="char" type="int">
- </argument>
- <argument index="3" name="next" type="int" default="-1">
- </argument>
- <argument index="4" name="modulate" type="Color" default="Color(1,1,1,1)">
- </argument>
- <description>
- Draw character &quot;char&quot; into a canvas item using the font at a given &quot;pos&quot; position, with &quot;modulate&quot; color, and optionally kerning if &quot;next&quot; is apassed. clipping the width. &quot;pos&quot; specifies te baseline, not the top. To draw from the top, [html i]ascent[html /i] must be added to the Y axis. The width used by the character is returned, making this function useful for drawing strings character by character.
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="GammaFX" inherits="ScenarioFX" category="Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="_Geometry" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="build_box_planes" >
- <return type="Array">
- </return>
- <argument index="0" name="extents" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="build_cylinder_planes" >
- <return type="Array">
- </return>
- <argument index="0" name="radius" type="real">
- </argument>
- <argument index="1" name="height" type="real">
- </argument>
- <argument index="2" name="sides" type="int">
- </argument>
- <argument index="3" name="axis" type="int" default="2">
- </argument>
- <description>
- </description>
- </method>
- <method name="build_capsule_planes" >
- <return type="Array">
- </return>
- <argument index="0" name="radius" type="real">
- </argument>
- <argument index="1" name="height" type="real">
- </argument>
- <argument index="2" name="sides" type="int">
- </argument>
- <argument index="3" name="lats" type="int">
- </argument>
- <argument index="4" name="axis" type="int" default="2">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Globals" inherits="Object" category="Core">
- <brief_description>
- Contains global variables accessible from everywhere.
- </brief_description>
- <description>
- Contains global variables accessible from everywhere. Use the normal [Object] API, such as &quot;Globals.get(variable)&quot;, &quot;Globals.set(variable,value)&quot; or &quot;Globals.has(variable)&quot; to access them. Variables stored in engine.cfg are also loaded into globals, making this object very useful for reading custom game configuration options.
- </description>
- <methods>
- <method name="has" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_order" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="pos" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_order" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_persisting" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_persisting" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear" >
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="localize_path" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="path" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="globalize_path" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="path" type="String">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="GlowFX" inherits="ScenarioFX" category="Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="HDRFX" inherits="ScenarioFX" category="Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="HScrollBar" inherits="ScrollBar" category="Nodes/GUI Nodes">
- <brief_description>
- Horizontal version of [ScrollBar], which goes from top (min) to bottom (max).
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="HSeparator" inherits="Separator" category="Nodes/GUI Nodes">
- <brief_description>
- Horizontal version of [Separator].
- </brief_description>
- <description>
- Horizontal version of [Separator]. It is used to separate objects vertiacally, though (but it looks horizontal!).
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="HSlider" inherits="Slider" category="Nodes/GUI Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="IP" inherits="Object" category="Networking">
- <brief_description>
- IP Protocol support functions.
- </brief_description>
- <description>
- IP contains some support functions for the IPv4 protocol. TCP/IP support is in different classes (see [TCP_Client], [TCP_Server]). IP provides hostname resolution support, both blocking and threaded.
- </description>
- <methods>
- <method name="resolve_hostname" >
- <return type="String">
- </return>
- <argument index="0" name="host" type="String">
- </argument>
- <description>
- Resolve a given hostname, blocking. Resolved hostname is returned as an IP.
- </description>
- </method>
- <method name="resolve_hostname_queue_item" >
- <return type="int">
- </return>
- <argument index="0" name="host" type="String">
- </argument>
- <description>
- Create a queue item for resolving a given hostname. The queue ID is returned, or RESOLVER_INVALID_ID on error.
- </description>
- </method>
- <method name="get_resolve_item_status" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- Return the status of hostname queued for resolving, given it&apos;s queue ID. Returned status can be any of the RESOLVER_STATUS_* enumeration.
- </description>
- </method>
- <method name="get_resolve_item_address" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- Return a resolved item address, or an empty string if an error happened or resolution didn&apos;t happen yet (see [method get_resolve_item_status]).
- </description>
- </method>
- <method name="erase_resolve_item" >
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- Erase a queue ID, removing it from the queue if needed. This should be used after a queue is completed to free it and enable more queries to happen.
- </description>
- </method>
- </methods>
- <constants>
- <constant name="RESOLVER_INVALID_ID" value="-1">
- </constant>
- <constant name="RESOLVER_MAX_QUERIES" value="32">
- </constant>
- <constant name="RESOLVER_STATUS_NONE" value="0">
- </constant>
- <constant name="RESOLVER_STATUS_ERROR" value="3">
- </constant>
- <constant name="RESOLVER_STATUS_WAITING" value="1">
- </constant>
- <constant name="RESOLVER_STATUS_DONE" value="2">
- </constant>
- </constants>
-</class>
-<class name="IP_Unix" inherits="IP" category="Networking">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="InputMap" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Label" inherits="Range" category="Nodes/GUI Nodes">
- <brief_description>
- Control that displays formatted text.
- </brief_description>
- <description>
- Label is a control that displays formatted text, optionally autowrapping it to the [Control] area. It inherits from range to be able to scroll wrapped text vertically.
- </description>
- <methods>
- <method name="set_align" >
- <argument index="0" name="align" type="int">
- </argument>
- <description>
- Set the alignmend mode to any of the ALIGN_* enumeration values.
- </description>
- </method>
- <method name="get_align" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- Return the alignmend mode (any of the ALIGN_* enumeration values).
- </description>
- </method>
- <method name="set_text" >
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- Set the label text. Text can contain newlines.
- </description>
- </method>
- <method name="get_text" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- Return the label text. Text can contain newlines.
- </description>
- </method>
- <method name="set_autowrap" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- Set [html i]autowrap[html /i] mode. When enabled, autowrap will fit text to the control width, breaking sentences when they exceed the available horizontal space. When disabled, the label minimum width becomes the width of the longest row, and the minimum height large enough to fit all rows.
- </description>
- </method>
- <method name="has_autowrap" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- Return the state of the [html i]autowrap[html /i] mode (see [method set_autowrap]).
- </description>
- </method>
- </methods>
- <constants>
- <constant name="ALIGN_CENTER" value="1">
- Align rows centered.
- </constant>
- <constant name="ALIGN_LEFT" value="0">
- Align rows to the left (default).
- </constant>
- <constant name="ALIGN_RIGHT" value="2">
- Align rows to the right (default).
- </constant>
- <constant name="ALIGN_FILL" value="3">
- Expand row whitespaces to fit the width.
- </constant>
- </constants>
-</class>
-<class name="Light" inherits="VisualInstance" category="Nodes/3D/3D Visual Nodes/3D Light Nodes">
- <brief_description>
- Provides a base class for different kinds of light nodes.
- </brief_description>
- <description>
- Light is the abstract base class for light nodes, so it shouldn&apos;t be used directly (It can&apos;t be instanced). Other types of light nodes inherit from it. Light contains the common variables and parameters used for lighting.
- </description>
- <methods>
- <method name="set_parameter" >
- <argument index="0" name="variable" type="int">
- </argument>
- <argument index="1" name="value" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_parameter" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_color" >
- <argument index="0" name="color" type="int">
- </argument>
- <argument index="1" name="value" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_color" qualifiers="const" >
- <return type="Color">
- </return>
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_project_shadows" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_project_shadows" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_projector" >
- <argument index="0" name="projector" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_projector" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="set_operator" >
- <argument index="0" name="operator" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_operator" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="COLOR_DIFFUSE" value="1">
- </constant>
- <constant name="PARAM_SPOT_ANGLE" value="1">
- </constant>
- <constant name="PARAM_ATTENUATION" value="4">
- </constant>
- <constant name="COLOR_SPECULAR" value="2">
- </constant>
- <constant name="COLOR_AMBIENT" value="0">
- </constant>
- <constant name="PARAM_SHADOW_DARKENING" value="5">
- </constant>
- <constant name="PARAM_RADIUS" value="2">
- </constant>
- <constant name="PARAM_SPOT_ATTENUATION" value="4">
- </constant>
- <constant name="PARAM_ENERGY" value="3">
- </constant>
- </constants>
-</class>
-<class name="LineEdit" inherits="Control" category="Nodes/GUI Nodes">
- <brief_description>
- Control that provides single line string editing.
- </brief_description>
- <description>
- LineEdit provides a single line string editor, used for text fields.
- </description>
- <methods>
- <method name="clear" >
- <description>
- Clear the [LineEdit] text.
- </description>
- </method>
- <method name="select_all" >
- <description>
- Select the whole string.
- </description>
- </method>
- <method name="set_text" >
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- Set the text in the [LineEdit], clearing the existing one and the selection.
- </description>
- </method>
- <method name="get_text" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- Return the text in the [LineEdit].
- </description>
- </method>
- <method name="set_cursor_pos" >
- <argument index="0" name="pos" type="int">
- </argument>
- <description>
- Set the cursor position inside the [LineEdit], causing it to scroll if needed.
- </description>
- </method>
- <method name="get_cursor_pos" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- Return the cursor position inside the [LineEdit].
- </description>
- </method>
- <method name="set_max_length" >
- <argument index="0" name="chars" type="int">
- </argument>
- <description>
- Set the maximum amount of characters the [LineEdit] can edit, and cropping existing text in case it exceeds that limit. Setting 0 removes the limit.
- </description>
- </method>
- <method name="get_max_length" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- Return the maximum amount of characters the [LineEdit] can edit. If 0 is returned, no limit exists.
- </description>
- </method>
- <method name="append_at_cursor" >
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- Append text at cursor, scrolling the [LineEdit] when needed.
- </description>
- </method>
- <method name="set_editable" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- Set the [html i]editable[html /i] status of the [LineEdit]. When disabled, existing text can&apos;t be modified and new text can&apos;t be added.
- </description>
- </method>
- <method name="is_editable" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- Return the [html i]editable[html /i] status of the [LineEdit] (see [method set_editable]).
- </description>
- </method>
- <method name="set_secret" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- Set the [html i]secret[html /i] status of the [LineEdit]. When enabled, every character is displayed as &quot;*&quot;.
- </description>
- </method>
- <method name="is_secret" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- Return the [html i]secret[html /i] status of the [LineEdit] (see [method set_secret]).
- </description>
- </method>
- <method name="select" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="text_entered">
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- This signal is emitted when the user presses KEY_ENTER on the [LineEdit]. This signal is often used as an alternate confirmation mechanism in dialogs.
- </description>
- </signal>
- <signal name="text_changed">
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- When the text changes, this signal is emitted.
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="MainLoop" inherits="Object" category="Main Loop">
- <brief_description>
- Main loop is the abstract main loop base class.
- </brief_description>
- <description>
- Main loop is the abstract main loop base class. All other main loop classes are derived from it. Upon application start, a [MainLoop] has to be provided to OS, else the application will exit. This happens automatically (and a [SceneMainLoop] is created), unless a main [Script] is supplied, which may or not create and return a [MainLoop].
- </description>
- <methods>
- </methods>
- <constants>
- <constant name="NOTIFICATION_WM_QUIT_REQUEST" value="7">
- </constant>
- <constant name="NOTIFICATION_WM_FOCUS_IN" value="5">
- </constant>
- <constant name="NOTIFICATION_WM_FOCUS_OUT" value="6">
- </constant>
- </constants>
-</class>
-<class name="Material" inherits="Resource" category="Resources">
- <brief_description>
- Abstract base [Resource] for coloring and shading geometry.
- </brief_description>
- <description>
- Material is a base [Resource] used for coloring and shading geometry. All materials inherit from it and almost all [VisualInstance] derived nodes carry a Material. A few flags and parameters are shared between all material types and are configured here.
- </description>
- <methods>
- <method name="set_flag" >
- <argument index="0" name="flag" type="int">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- Set a [Material] flag, which toggles on or off a behavior when rendering. See enumeration FLAG_* for a list.
- </description>
- </method>
- <method name="get_flag" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="flag" type="int">
- </argument>
- <description>
- Return a [Material] flag, which toggles on or off a behavior when rendering. See enumeration FLAG_* for a list.
- </description>
- </method>
- <method name="set_hint" >
- <argument index="0" name="hint" type="int">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_hint" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="hint" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_blend_mode" >
- <argument index="0" name="mode" type="int">
- </argument>
- <description>
- Set blend mode for the material, which can be one of BLEND_MODE_MIX (default), BLEND_MODE_ADD, BLEND_MODE_SUB. Keep in mind that only BLEND_MODE_MIX ensures that the material [html i]may[html /i] be opaque, any other blend mode will render with alpha blending enabled in raster-based [VisualServer] implementations.
- </description>
- </method>
- <method name="get_blend_mode" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- Return blend mode for the material, which can be one of BLEND_MODE_MIX (default), BLEND_MODE_ADD, BLEND_MODE_SUB. Keep in mind that only BLEND_MODE_MIX ensures that the material [html i]may[html /i] be opaque, any other blend mode will render with alpha blending enabled in raster-based [VisualServer] implementations.
- </description>
- </method>
- <method name="set_shade_model" >
- <argument index="0" name="model" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_shade_model" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_line_width" >
- <argument index="0" name="width" type="real">
- </argument>
- <description>
- Set the line width for geometry drawn with FLAG_WIREFRAME enabled, or LINE primitives. Note that not all hardware or VisualServer backends support this (like DirectX).
- </description>
- </method>
- <method name="get_line_width" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- Return the line width for geometry drawn with FLAG_WIREFRAME enabled, or LINE primitives. Note that not all hardware or VisualServer backends support this (like DirectX).
- </description>
- </method>
- <method name="set_shader_param" >
- <argument index="0" name="param" type="String">
- </argument>
- <argument index="1" name="arg1" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_shader_param" qualifiers="const" >
- <argument index="0" name="arg0" type="String">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="SHADE_MODEL_FRESNEL" value="2">
- </constant>
- <constant name="SHADE_MODEL_LAMBERT" value="0">
- </constant>
- <constant name="HINT_DECAL" value="0">
- </constant>
- <constant name="FLAG_WIREFRAME" value="5">
- Triangle geometry is drawn as lines if this flag is enabled.
- </constant>
- <constant name="SHADE_MODEL_TOON" value="3">
- </constant>
- <constant name="SHADE_MODEL_LAMBERT_WRAP" value="1">
- </constant>
- <constant name="HINT_NO_SHADOW" value="2">
- </constant>
- <constant name="FLAG_DOUBLE_SIDED" value="1">
- Both front facing and back facing triangles are rendered when this flag is enabled.
- </constant>
- <constant name="FLAG_BILLBOARD_TOGGLE" value="6">
- Geometry world transform is computed as billboard if this flag is enabled, often used for impostors.
- </constant>
- <constant name="FLAG_UNSHADED" value="3">
- Shading (lighting) is disabled when this flag is enabled.
- </constant>
- <constant name="BLEND_MODE_MIX" value="0">
- Use the regular alpha blending equation (source and dest colors are faded) (default).
- </constant>
- <constant name="SHADE_MODEL_CUSTOM_0" value="4">
- </constant>
- <constant name="SHADE_MODEL_CUSTOM_1" value="5">
- </constant>
- <constant name="FLAG_MAX" value="7">
- Maximum amount of flags
- </constant>
- <constant name="FLAG_VISIBLE" value="0">
- Geometry is visible when this flag is enabled (default).
- </constant>
- <constant name="SHADE_MODEL_CUSTOM_2" value="6">
- </constant>
- <constant name="HINT_MAX" value="4">
- </constant>
- <constant name="HINT_NO_DEPTH_DRAW" value="3">
- </constant>
- <constant name="BLEND_MODE_ADD" value="1">
- Use additive blending equation, often used for particle effects such as fire or light decals.
- </constant>
- <constant name="SHADE_MODEL_CUSTOM_3" value="7">
- </constant>
- <constant name="HINT_OPAQUE_PRE_PASS" value="1">
- </constant>
- <constant name="FLAG_ONTOP" value="4">
- </constant>
- <constant name="BLEND_MODE_SUB" value="2">
- Use substractive blending equation, often used for some smoke effects or types of glass.
- </constant>
- <constant name="FLAG_INVERT_FACES" value="2">
- Front facing and back facing order is swapped when this flag is enabled.
- </constant>
- </constants>
-</class>
-<class name="MenuButton" inherits="Button" category="Nodes/GUI Nodes">
- <brief_description>
- Special button that brings up a [PopupMenu] when clicked.
- </brief_description>
- <description>
- Special button that brings up a [PopupMenu] when clicked. That&apos;s pretty much all it does, as it&apos;s just a helper class when bulding GUIs.
- </description>
- <methods>
- <method name="get_popup" >
- <return type="Object">
- </return>
- <description>
- Return the [PopupMenu] contained in this button.
- </description>
- </method>
- </methods>
- <signals>
- <signal name="about_to_show">
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="Mesh" inherits="Resource" category="Resources">
- <brief_description>
- A [Resource] that contains vertex-array based geometry.
- </brief_description>
- <description>
- Mesh is a type of [Resource] that contains vertex-array based geometry, divided in [html i]surfaces[html /i]. Each surface contains a completely separate array and a material used to draw it. Design wise, a mesh with multiple surfaces is prefered to a single surface, because objects created in 3D editing software commonly contain multiple materials.
- </description>
- <methods>
- <method name="add_morph_target" >
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_morph_target_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_morph_target" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="index" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear_morph_targets" >
- <description>
- </description>
- </method>
- <method name="add_surface" >
- <argument index="0" name="primitive" type="int">
- </argument>
- <argument index="1" name="format" type="int">
- </argument>
- <argument index="2" name="array_len" type="int">
- </argument>
- <argument index="3" name="index_array_len" type="int">
- </argument>
- <description>
- Create a new surface ([method get_surface_count] will become surf_idx for this.[html br/]&#10;&#9;&#9;&#9;Surfaces are created to be rendered using a &quot;primitive&quot;, which may be PRIMITIVE_POINTS, PRIMITIVE_LINES, PRIMITIVE_LINE_STRIP, PRIMITIVE_LINE_LOOP, PRIMITIVE_TRIANGLES, PRIMITIVE_TRIANGLE_STRIP, PRIMITIVE_TRIANGLE_FAN. (As a note, when using indices, it is recommended to only use just points, lines or triangles).[html br/]&#10;&#9;&#9;&#9;The format of a surface determines which arrays it will allocate and hold, so &quot;format&quot; is a combination of ARRAY_FORMAT_* mask constants ORed together. ARRAY_FORMAT_VERTEX must be always present. &quot;array_len&quot; determines the amount of vertices in the array (not primitives!). if ARRAY_FORMAT_INDEX is in the format mask, then it means that an index array will be allocated and &quot;index_array_len&quot; must be passed.
- </description>
- </method>
- <method name="get_surface_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- Return the amount of surfaces that the [Mesh] holds.
- </description>
- </method>
- <method name="surface_remove" >
- <argument index="0" name="surf_idx" type="int">
- </argument>
- <description>
- Remove a surface at position surf_idx, shifting greater surfaces one surf_idx slot down.
- </description>
- </method>
- <method name="surface_set_array" >
- <return type="int">
- </return>
- <argument index="0" name="surf_idx" type="int">
- </argument>
- <argument index="1" name="array" type="int">
- </argument>
- <argument index="2" name="data" type="var">
- </argument>
- <description>
- Set a surface array, array must be defined in the format (see [method add_surface]), and which array being set in &quot;data&quot; must be indicated passing a value from the ARRAY_* enum (NOT THE ARRAY_FORMAT_ enum!!). A Mesh can&apos;t be displayed (error will be reported) if an array that is present in the format was not set.
- </description>
- </method>
- <method name="surface_get_array" qualifiers="const" >
- <argument index="0" name="surf_idx" type="int">
- </argument>
- <argument index="1" name="array" type="int">
- </argument>
- <description>
- Return a surface array, array must be defined in the format (see [method add_surface]), and which array being returned must be indicated passing a value from the ARRAY_* enum (NOT THE ARRAY_FORMAT_ enum!!) (see [method add_surface]).
- </description>
- </method>
- <method name="surface_get_array_len" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="surf_idx" type="int">
- </argument>
- <description>
- Return the length in vertices of the vertex array in the requested surface (see [method add_surface]).
- </description>
- </method>
- <method name="surface_get_array_index_len" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="surf_idx" type="int">
- </argument>
- <description>
- Return the length in indices of the index array in the requested surface (see [method add_surface]).
- </description>
- </method>
- <method name="surface_get_format" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="surf_idx" type="int">
- </argument>
- <description>
- Return the format mask of the requested surface (see [method add_surface]).
- </description>
- </method>
- <method name="surface_get_primitive_type" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="surf_idx" type="int">
- </argument>
- <description>
- Return the primitive type of the requested surface (see [method add_surface]).
- </description>
- </method>
- <method name="surface_set_material" >
- <argument index="0" name="surf_idx" type="int">
- </argument>
- <argument index="1" name="arg1" type="Object">
- </argument>
- <description>
- Set a [Material] for a given surface. Surface will be rendered using this material.
- </description>
- </method>
- <method name="surface_get_material" qualifiers="const" >
- <return type="Object">
- </return>
- <argument index="0" name="surf_idx" type="int">
- </argument>
- <description>
- Return a [Material] in a given surface. Surface is rendered using this material.
- </description>
- </method>
- </methods>
- <constants>
- <constant name="PRIMITIVE_LINES" value="1">
- Render array as lines (every two vertices a line is created).
- </constant>
- <constant name="ARRAY_FORMAT_TEX_UV2" value="32">
- </constant>
- <constant name="ARRAY_TEX_UV2" value="5">
- </constant>
- <constant name="ARRAY_WEIGHTS_SIZE" value="4">
- Amount of weights/bone indices per vertex (always 4).
- </constant>
- <constant name="ARRAY_FORMAT_VERTEX" value="1">
- Array format will include vertices (mandatory).
- </constant>
- <constant name="ARRAY_VERTEX" value="0">
- Vertex array (array of [Vector3]() vertices).
- </constant>
- <constant name="PRIMITIVE_POINTS" value="0">
- Render array as points (one vertex equals one point).
- </constant>
- <constant name="ARRAY_FORMAT_BONES" value="64">
- Array format will include bone indices.
- </constant>
- <constant name="ARRAY_FORMAT_COLOR" value="8">
- Array format will include a color array.
- </constant>
- <constant name="ARRAY_BONES" value="6">
- Array of bone indices, as a float array. Each element in groups of 4 floats.
- </constant>
- <constant name="ARRAY_COLOR" value="3">
- Vertex array (array of [Color]() colors).
- </constant>
- <constant name="ARRAY_FORMAT_INDEX" value="256">
- Index array will be used.
- </constant>
- <constant name="ARRAY_INDEX" value="8">
- Array of integers, used as indices referencing vertices. No index can be beyond the vertex array size.
- </constant>
- <constant name="PRIMITIVE_TRIANGLE_STRIP" value="5">
- Render array as triangle strips.
- </constant>
- <constant name="ARRAY_FORMAT_TANGENT" value="4">
- Array format will include tangents
- </constant>
- <constant name="ARRAY_FORMAT_NORMAL" value="2">
- Array format will include normals
- </constant>
- <constant name="ARRAY_TANGENT" value="2">
- Tangent array, array of groups of 4 floats. first 3 floats determine the tangent, and the last the binormal direction as -1 or 1.
- </constant>
- <constant name="ARRAY_NORMAL" value="1">
- Normal array (array of [Vector3]() normals).
- </constant>
- <constant name="PRIMITIVE_TRIANGLES" value="4">
- Render array as triangles (every three vertices a triangle is created).
- </constant>
- <constant name="PRIMITIVE_LINE_LOOP" value="3">
- Render array as line loop (like line strip, but closed).
- </constant>
- <constant name="PRIMITIVE_LINE_STRIP" value="2">
- Render array as line strip.
- </constant>
- <constant name="ARRAY_FORMAT_WEIGHTS" value="128">
- Array format will include bone weights.
- </constant>
- <constant name="ARRAY_FORMAT_TEX_UV" value="16">
- Array format will include UVs.
- </constant>
- <constant name="ARRAY_WEIGHTS" value="7">
- Array of bone weights, as a float array. Each element in groups of 4 floats.
- </constant>
- <constant name="ARRAY_TEX_UV" value="4">
- UV array (array of [Vector3]() UVs or float array of groups of 2 floats (u,v)).
- </constant>
- <constant name="PRIMITIVE_TRIANGLE_FAN" value="6">
- Render array as triangle fans.
- </constant>
- <constant name="NO_INDEX_ARRAY" value="-1">
- Default value used for index_array_len when no indices are present.
- </constant>
- </constants>
-</class>
-<class name="MeshInstance" inherits="VisualInstance" category="Nodes/3D/3D Visual Nodes">
- <brief_description>
- Node that instances meshes into a [Scenario].
- </brief_description>
- <description>
- MeshInstance is a [Node] that takes a [Mesh] resource and adds it to the current [Scenario] by creating an instance of it. This is the class most often used to get 3D geometry rendered and can be used to instance a sigle [Mesh] in many places. This allows to reuse geometry and save on resources. When a [Mesh] has to be instanced more than thousands of times at close proximity, consider using a [MultiMesh] in a [MultiMeshInstance] instead.
- </description>
- <methods>
- <method name="set_mesh" >
- <argument index="0" name="mesh" type="Object">
- </argument>
- <description>
- Set the [Mesh] resource for the instance.
- </description>
- </method>
- <method name="get_mesh" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- Return the current [Mesh] resource for the instance.
- </description>
- </method>
- <method name="get_aabb" qualifiers="const" >
- <return type="AABB">
- </return>
- <description>
- Return the AABB of the mesh, in local coordinates.
- </description>
- </method>
- <method name="create_trimesh_collision" >
- <description>
- This helper creates a [StaticBody] child [Node] using the mesh geometry as collision. It&apos;s mainly used for testing.
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Misc" inherits="Node" category="Core">
- <brief_description>
- Soon to be removed, bye bye.
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="MultiMesh" inherits="Resource" category="Resources">
- <brief_description>
- Provides high perfomance mesh instancing.
- </brief_description>
- <description>
- MultiMesh provides low level mesh instancing. If the amount of [Mesh] instances needed goes from hundreds to thousands (and most need to be visible at close proximity) creating such a large amount of [MeshInstance] nodes may affect performance by using too much CPU or video memory. [html br/]For this case a MultiMesh becomes very useful, as it can draw thousands of instances with little API overhead.[html br/] As a drawback, if the instances are too far away of each other, performance may be reduced as every sigle instance will always rendered (they are spatially indexed as one, for the whole object).[html br/] Since instances may have any behavior, the AABB used for visibility must be provided by the user, or generated with [method generate_aabb].
- </description>
- <methods>
- <method name="set_mesh" >
- <argument index="0" name="arg0" type="Object">
- </argument>
- <description>
- Set the [Mesh] resource to be drawn in multiple instances.
- </description>
- </method>
- <method name="get_mesh" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- Return the [Mesh] resource drawn as multiple instances.
- </description>
- </method>
- <method name="set_instance_count" >
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- Set the amount of instnces that is going to be drawn. Changing this number will erase all the existing instance transform and color data.
- </description>
- </method>
- <method name="get_instance_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- Return the amount of instnces that is going to be drawn.
- </description>
- </method>
- <method name="set_instance_transform" >
- <argument index="0" name="arg0" type="int">
- </argument>
- <argument index="1" name="arg1" type="Transform">
- </argument>
- <description>
- Set the transform for a specific instance.
- </description>
- </method>
- <method name="get_instance_transform" qualifiers="const" >
- <return type="Transform">
- </return>
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- Return the transform of a specific instance.
- </description>
- </method>
- <method name="set_instance_color" >
- <argument index="0" name="arg0" type="int">
- </argument>
- <argument index="1" name="arg1" type="Color">
- </argument>
- <description>
- Set the color of a specific instance.
- </description>
- </method>
- <method name="get_instance_color" qualifiers="const" >
- <return type="Color">
- </return>
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- Get the color of a specific instance.
- </description>
- </method>
- <method name="set_aabb" >
- <argument index="0" name="arg0" type="AABB">
- </argument>
- <description>
- Set the visibility AABB. If not provided, MultiMesh will not be visible.
- </description>
- </method>
- <method name="get_aabb" qualifiers="const" >
- <return type="AABB">
- </return>
- <description>
- Return the visibility AABB.
- </description>
- </method>
- <method name="generate_aabb" >
- <description>
- Generate a new visibility AABB, using mesh AABB and instance transforms. Since instance information is stored in the [VisualServer], this function is VERY SLOW and must NOT be used often.
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="MultiMeshInstance" inherits="VisualInstance" category="Nodes/3D/3D Visual Nodes">
- <brief_description>
- Node that instances a [MultiMesh].
- </brief_description>
- <description>
- MultiMeshInstance is a [Node] that takes a [MultiMesh] resource and adds it to the current [Scenario] by creating an instance of it (yes, this is an instance of instances).
- </description>
- <methods>
- <method name="set_multimesh" >
- <argument index="0" name="multimesh" type="Object">
- </argument>
- <description>
- Set the [MultiMesh] to be instance.
- </description>
- </method>
- <method name="get_multimesh" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- Return the [MultiMesh] that is used for instancing.
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Node" inherits="Object" category="Nodes">
- <brief_description>
- Base class for all the &quot;Scene&quot; elements.
- </brief_description>
- <description>
- Nodes can be set as children of other nodes, resulting in a tree arrangement. Any tree of nodes is called a &quot;Scene&quot;.[html br/] Scenes can be saved to disk, and then instanced into other scenes. This allows for very high flexibility in the architecture and data model of the projects. Scenes become &quot;active&quot; and part of the &quot;Scene Tree&quot; once they are added as children of a [RootNode].[html br/][html br/]&#10;&#9;As an illustrative example, a Scene (tree of nodes):&#10;&#9;[html div align=&quot;center&quot;][html img src=&quot;images/scene.png&quot;/][html /div]&#10;&#9;This scene will was edited separatedly, then is added as part of a game (by instancing it), becoming part of a &quot;Scene Tree&quot;:&#10;&#9;[html div align=&quot;center&quot;][html img src=&quot;images/scene_tree.png&quot;/][html /div]&#10;&#9;In short, nodes are an effective all-in-one way to create and organize assets, gameplay and game data.&#10;&#9;When a Node is freed (deleted), it will delete all its children&#10;&#9;nodes.&#10;&#9;TODO: explain better process/signal/group call ordering
- </description>
- <methods>
- <method name="set_name" >
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- Set the name of the [Node]. Name must be unique within parent, and setting an already existing name will cause for the node to be automatically renamed.
- </description>
- </method>
- <method name="get_name" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- Return the name of the [Node]. Name is be unique within parent.
- </description>
- </method>
- <method name="add_child" >
- <argument index="0" name="node" type="Node">
- </argument>
- <description>
- Add a child [Node]. Nodes can have as many children as they want, but every child must have a unique name. Children nodes are automatically deleted when the parent node is deleted, so deleting a whole scene is performed by deleting its topmost node.
- </description>
- </method>
- <method name="remove_child" >
- <argument index="0" name="node" type="Node">
- </argument>
- <description>
- Remove a child [Node]. Node is NOT deleted and will have to be deleted manually.
- </description>
- </method>
- <method name="get_child_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- Return the amount of children nodes.
- </description>
- </method>
- <method name="get_child" qualifiers="const" >
- <return type="Object">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Return a children node by it&apos;s index (see [method get_child_count]). This method is often used for iterating all children of a node.
- </description>
- </method>
- <method name="has_node" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="path" type="NodePath">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_node" qualifiers="const" >
- <return type="Object">
- </return>
- <argument index="0" name="path" type="NodePath">
- </argument>
- <description>
- Fetch a node. &quot;path&quot; must be valid (or else error will occur) and can be either the name of a child node, a relative path (from the current node to another node), or an absolute path to a node.[html br/] Examples ofa paths are: get_node(&quot;Sword&quot;) , get_node(&quot;../Swamp/Alligator&quot;) , get_node(&quot;/MyGame&quot;). [html br/]Note: fetching absolute paths only works when the node is inside the scene tree (see [method is_inside_tree]).
- </description>
- </method>
- <method name="get_parent" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- Return the parent [Node] of the current [Node], or an empty Object if the node lacks a parent.
- </description>
- </method>
- <method name="is_inside_scene" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="is_a_parent_of" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="node" type="Node">
- </argument>
- <description>
- Return [html i]true[html /i] if the &quot;node&quot; argument is a direct or indirect child of the current node, otherwise return [html i]false[html /i].
- </description>
- </method>
- <method name="is_greater_than" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="node" type="Node">
- </argument>
- <description>
- Return [html i]true[html /i] if &quot;node&quot; occurs later in the scene hierarchy than the current node, otherwise return [html i]false[html /i].
- </description>
- </method>
- <method name="get_path" qualifiers="const" >
- <return type="NodePath">
- </return>
- <description>
- Return the absolute path of the current node. This only works if the curent node is inside the scene tree (see [method is_inside_tree]).
- </description>
- </method>
- <method name="get_path_to" qualifiers="const" >
- <return type="NodePath">
- </return>
- <argument index="0" name="node" type="Node">
- </argument>
- <description>
- Return the relative path from the current node to the specified node in &quot;node&quot; argument. Both nodes must be in the same scene, or else the function will fail.
- </description>
- </method>
- <method name="add_to_group" >
- <argument index="0" name="group" type="String">
- </argument>
- <argument index="1" name="arg1" type="bool">
- </argument>
- <description>
- Add a node to a group. Groups are helpers to name and organize group of nodes, like for example: &quot;Enemies&quot; &quot;Collectables&quot;, etc. A [Node] can be in any number of groups. Nodes can be assigned a group at any time, but will not be added to it until they are inside the scene tree (see [method is_inside_tree]).
- </description>
- </method>
- <method name="remove_from_group" >
- <argument index="0" name="group" type="String">
- </argument>
- <description>
- Remove a node from a group.
- </description>
- </method>
- <method name="move_child" >
- <argument index="0" name="child_node" type="Node">
- </argument>
- <argument index="1" name="to_pos" type="int">
- </argument>
- <description>
- Move a child node to a different position (order) amongst the other children. Since calls, signals, etc are performed by tree order, changing the order of chilren nodes may be useful.
- </description>
- </method>
- <method name="raise" >
- <description>
- Move this node to the top of the array of nodes of the parent node. This is often useful on GUIs ([Control]), because their order of drawing fully depends on their order in the tree.
- </description>
- </method>
- <method name="set_owner" >
- <argument index="0" name="arg0" type="Object">
- </argument>
- <description>
- Set the node owner. A node can have any other node as owner (as long as a valid parent, grandparent, etc ascending in the tree). When saving a node (using SceneSaver) all the nodes it owns will be saved with it. This allows to create complex SceneTrees, with instancing and subinstancing.
- </description>
- </method>
- <method name="get_owner" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- Get the node owner (see [method set_node_owner]).
- </description>
- </method>
- <method name="remove_and_skip" >
- <description>
- Remove a node and set all its children as childrens of the parent node (if exists). All even subscriptions that pass by the removed node will be unsubscribed.
- </description>
- </method>
- <method name="get_index" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- Get the node index in the parent (assuming it has a parent).
- </description>
- </method>
- <method name="print_tree" >
- <description>
- Print the screne to stdout. Used mainly for debugging purposes.
- </description>
- </method>
- <method name="set_filename" >
- <argument index="0" name="filename" type="String">
- </argument>
- <description>
- A node can contain a filename. This filename should not be changed by the user, unless writing editors and tools. When a scene is instanced from a file, it topmost node contains the filename from where it was loaded.
- </description>
- </method>
- <method name="get_filename" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- Return a filename that may be containedA node can contained by the node. When a scene is instanced from a file, it topmost node contains the filename from where it was loaded (see [method set_filename]).
- </description>
- </method>
- <method name="propagate_notification" >
- <argument index="0" name="what" type="int">
- </argument>
- <description>
- Notify the current node and all its chldren recursively by calling notification() in all of them.
- </description>
- </method>
- <method name="set_process" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- Enables or disables node processing. When a node is being processed, it will receive a NOTIFICATION_PROCESS on every frame. It is common to check how much time was elapsed since the previous frame by calling [method get_process_time]. If the application is set to run at 60 fps, NOTIFICATION_PROCESS will be received 60 times per second (even if the visuals are running at faster or lower fps). Because of this, nodes that wish to do processing are recommended to use [method set_idle_process] instead, unless strong syncronization is requiered (for example, to modify the behavior of physics objects).
- </description>
- </method>
- <method name="get_process_time" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- Return the amount of time elapsed (in seconds) between two succesive NOTIFICATION_PROCESS notifications.
- </description>
- </method>
- <method name="is_processing" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- Return wether processing is enabled in the current node.
- </description>
- </method>
- <method name="set_idle_process" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- Enables or disables node idle processing. When a node is being idle-processed, it will receive a NOTIFICATION_IDLE_PROCESS when idle. It is common to check how much time was elapsed since the previous idle time by calling [method get_idle_process_time]. Idle processing is commonly syncronized to [VisualServer] being done rendering a frame, so this type of processing is syncronized to the visible frames per second. To syncronize with the desired frames per second, see [method set_process] instead.
- </description>
- </method>
- <method name="get_idle_process_time" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- Return the amount of time elapsed (in seconds) between two succesive NOTIFICATION_IDLE_PROCESS notifications.
- </description>
- </method>
- <method name="is_idle_processing" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- Return wether idle processing is enabled in the current node.
- </description>
- </method>
- <method name="set_process_input" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_processing_input" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_process_unhandled_input" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_processing_unhandled_input" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_process_mode" >
- <argument index="0" name="mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_process_mode" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_world" >
- <argument index="0" name="world" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_world" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="get_current_world" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="get_scene" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="duplicate" qualifiers="const" >
- <return type="Object">
- </return>
- <argument index="0" name="arg0" type="Object">
- </argument>
- <argument index="1" name="arg1" type="bool" default="NULL">
- </argument>
- <description>
- Return a duplicate of the scene, with all nodes and parameters copied. Subscriptions will not be duplicated.
- </description>
- </method>
- <method name="replace_by" >
- <argument index="0" name="node" type="Node">
- </argument>
- <argument index="1" name="keep_data" type="bool" default="false">
- </argument>
- <description>
- Replace a node in a scene by a given one. Subscriptions that pass through this node will be lost.
- </description>
- </method>
- </methods>
- <signals>
- <signal name="enter_scene">
- <description>
- </description>
- </signal>
- <signal name="renamed">
- <description>
- </description>
- </signal>
- <signal name="exit_scene">
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- <constant name="NOTIFICATION_ENTER_WORLD" value="20">
- </constant>
- <constant name="PROCESS_PAUSE" value="1">
- </constant>
- <constant name="NOTIFICATION_UNPARENTED" value="19">
- Notification received when a node is unparented (parent removed it from the list of children).
- </constant>
- <constant name="NOTIFICATION_CHILDREN_CONFIGURED" value="14">
- </constant>
- <constant name="NOTIFICATION_PROCESS" value="16">
- Notification received every frame when the process flag is set (see [method set_process]).
- </constant>
- <constant name="NOTIFICATION_EXIT_SCENE" value="11">
- </constant>
- <constant name="PROCESS_ALWAYS" value="2">
- </constant>
- <constant name="PROCESS_NORMAL" value="0">
- </constant>
- <constant name="NOTIFICATION_EXIT_WORLD" value="21">
- </constant>
- <constant name="NOTIFICATION_MOVED_IN_PARENT" value="12">
- </constant>
- <constant name="NOTIFICATION_PARENTED" value="18">
- Notification received when a node is set as a child of another node. Note that this doesn&apos;t mean that a node entered the Scene Tree.
- </constant>
- <constant name="NOTIFICATION_ENTER_SCENE" value="10">
- </constant>
- <constant name="NOTIFICATION_IDLE_PROCESS" value="17">
- Notification received every time the application enters idle when the idle process flag is set (see [method set_process]).
- </constant>
- </constants>
-</class>
-<class name="Node2D" inherits="CanvasItem" category="Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_pos" >
- <argument index="0" name="pos" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_rot" >
- <argument index="0" name="rot" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_scale" >
- <argument index="0" name="scale" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_pos" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="get_rot" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_scale" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="NOTIFICATION_DRAW" value="30">
- </constant>
- </constants>
-</class>
-<class name="_OS" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_mouse_show" >
- <argument index="0" name="show" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_mouse_grab" >
- <argument index="0" name="grab" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_mouse_grab_enabled" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_mouse_pos" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="set_clipboard" >
- <argument index="0" name="clipboard" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_clipboard" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="set_video_mode" >
- <argument index="0" name="size" type="Vector2">
- </argument>
- <argument index="1" name="fullscreen" type="bool">
- </argument>
- <argument index="2" name="resizable" type="bool">
- </argument>
- <argument index="3" name="screen" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_video_mode_size" qualifiers="const" >
- <return type="Vector2">
- </return>
- <argument index="0" name="screen" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_video_mode_fullscreen" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="screen" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_video_mode_resizable" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="screen" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_fullscreen_mode_list" qualifiers="const" >
- <return type="Array">
- </return>
- <argument index="0" name="screen" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_iterations_per_second" >
- <argument index="0" name="iterations_per_second" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_iterations_per_second" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_low_processor_usage_mode" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_in_low_processor_usage_mode" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_executable_path" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="execute" >
- <return type="int">
- </return>
- <argument index="0" name="path" type="String">
- </argument>
- <argument index="1" name="arguments" type="StringArray">
- </argument>
- <argument index="2" name="blocking" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="kill" >
- <return type="int">
- </return>
- <argument index="0" name="pid" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_environment" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="environment" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_environment" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="environment" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_name" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="get_cmdline_args" >
- <return type="StringArray">
- </return>
- <description>
- </description>
- </method>
- <method name="get_main_loop" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="get_date" qualifiers="const" >
- <return type="Dictionary">
- </return>
- <description>
- </description>
- </method>
- <method name="get_time" qualifiers="const" >
- <return type="Dictionary">
- </return>
- <description>
- </description>
- </method>
- <method name="delay_usec" qualifiers="const" >
- <argument index="0" name="usec" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_ticks_msec" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="can_draw" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_frames_drawn" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="is_stdout_verbose" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="MONTH_NOVEMBER" value="10">
- </constant>
- <constant name="MONTH_OCTOBER" value="9">
- </constant>
- <constant name="MONTH_DECEMBER" value="11">
- </constant>
- <constant name="MONTH_SEPTEMBER" value="8">
- </constant>
- <constant name="MONTH_MAY" value="4">
- </constant>
- <constant name="DAY_FRIDAY" value="5">
- </constant>
- <constant name="DAY_TUESDAY" value="2">
- </constant>
- <constant name="MONTH_APRIL" value="3">
- </constant>
- <constant name="MONTH_FEBRUARY" value="1">
- </constant>
- <constant name="DAY_MONDAY" value="1">
- </constant>
- <constant name="MONTH_AUGUST" value="7">
- </constant>
- <constant name="MONTH_JUNE" value="5">
- </constant>
- <constant name="MONTH_JANUARY" value="0">
- </constant>
- <constant name="MONTH_MARCH" value="2">
- </constant>
- <constant name="MONTH_JULY" value="6">
- </constant>
- <constant name="DAY_THURSDAY" value="4">
- </constant>
- <constant name="DAY_WEDNESDAY" value="3">
- </constant>
- <constant name="DAY_SUNDAY" value="0">
- </constant>
- <constant name="DAY_SATURDAY" value="6">
- </constant>
- </constants>
-</class>
-<class name="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="get_type" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="is_type" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set" >
- <argument index="0" name="property" type="String">
- </argument>
- <argument index="1" name="value" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="get" qualifiers="const" >
- <argument index="0" name="property" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_property_list" qualifiers="const" >
- <return type="Array">
- </return>
- <description>
- </description>
- </method>
- <method name="notification" >
- <argument index="0" name="what" type="int">
- </argument>
- <argument index="1" name="arg1" type="bool" default="false">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_instance_ID" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_script" >
- <argument index="0" name="script" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_script" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="set_meta" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="value" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_meta" qualifiers="const" >
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_meta" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_meta_list" qualifiers="const" >
- <return type="StringArray">
- </return>
- <description>
- </description>
- </method>
- <method name="call" >
- <argument index="0" name="method" type="String">
- </argument>
- <argument index="1" name="arg1" type="var" default="NULL">
- </argument>
- <argument index="2" name="arg2" type="var" default="NULL">
- </argument>
- <argument index="3" name="arg3" type="var" default="NULL">
- </argument>
- <argument index="4" name="arg4" type="var" default="NULL">
- </argument>
- <description>
- </description>
- </method>
- <method name="call_deferred" >
- <argument index="0" name="method" type="String">
- </argument>
- <argument index="1" name="arg1" type="var" default="NULL">
- </argument>
- <argument index="2" name="arg2" type="var" default="NULL">
- </argument>
- <argument index="3" name="arg3" type="var" default="NULL">
- </argument>
- <argument index="4" name="arg4" type="var" default="NULL">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_user_signal" >
- <argument index="0" name="signal" type="String">
- </argument>
- <argument index="1" name="arguments" type="Array" default="Array()">
- </argument>
- <description>
- </description>
- </method>
- <method name="emit_signal" >
- <argument index="0" name="signal" type="String">
- </argument>
- <argument index="1" name="arguments" type="Array" default="Array()">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_signal_list" qualifiers="const" >
- <return type="Array">
- </return>
- <description>
- </description>
- </method>
- <method name="connect" >
- <argument index="0" name="signal" type="String">
- </argument>
- <argument index="1" name="target" type="Object">
- </argument>
- <argument index="2" name="method" type="String">
- </argument>
- <argument index="3" name="binds" type="Array" default="Array()">
- </argument>
- <argument index="4" name="flags" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="disconnect" >
- <argument index="0" name="signal" type="String">
- </argument>
- <argument index="1" name="target" type="Object">
- </argument>
- <argument index="2" name="method" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_block_signals" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_blocking_signals" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="NOTIFICATION_POSTINITIALIZE" value="0">
- </constant>
- <constant name="NOTIFICATION_PREDELETE" value="1">
- </constant>
- </constants>
-</class>
-<class name="OmniLight" inherits="Light" category="Nodes/3D/3D Visual Nodes/3D Light Nodes">
- <brief_description>
- OmniDirectional Light, such as a lightbulb or a candle.
- </brief_description>
- <description>
- An OmniDirectional light is a type of [Light] node that emits lights in all directions. The light is attenuated through the distance and this attenuation can be configured by changing the energy, radius and attenuation parameters of [Light]. TODO: Image of an omnilight.
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="OptionButton" inherits="Button" category="Nodes/GUI Nodes">
- <brief_description>
- Button control that provides selectable options when pressed.
- </brief_description>
- <description>
- OptionButton is a type button that provides a selectable list of items when pressed. The item selected becomes the &quot;current&quot; item and is displayed as the button text.
- </description>
- <methods>
- <method name="add_item" >
- <argument index="0" name="label" type="String">
- </argument>
- <argument index="1" name="id" type="int" default="-1">
- </argument>
- <description>
- Add an item, with text &quot;label&quot; and (optionally) id. If no &quot;id&quot; is passed, &quot;id&quot; becomes the item index. New items are appended at the end.
- </description>
- </method>
- <method name="add_icon_item" >
- <argument index="0" name="texture" type="Object">
- </argument>
- <argument index="1" name="label" type="String">
- </argument>
- <argument index="2" name="id" type="int">
- </argument>
- <description>
- Add an item, with a &quot;texture&quot; icon, text &quot;label&quot; and (optionally) id. If no &quot;id&quot; is passed, &quot;id&quot; becomes the item index. New items are appended at the end.
- </description>
- </method>
- <method name="set_item_text" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="text" type="String">
- </argument>
- <description>
- Set the text of an item at index &quot;idx&quot;.
- </description>
- </method>
- <method name="set_item_icon" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="texture" type="Object">
- </argument>
- <description>
- Set the icon of an item at index &quot;idx&quot;.
- </description>
- </method>
- <method name="set_item_disabled" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="disabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_item_ID" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="id" type="int">
- </argument>
- <description>
- Set the ID of an item at index &quot;idx&quot;.
- </description>
- </method>
- <method name="set_item_metadata" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="metadata" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_item_text" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Return the text of the item at index &quot;idx&quot;.
- </description>
- </method>
- <method name="get_item_icon" qualifiers="const" >
- <return type="Object">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Return the icon of the item at index &quot;idx&quot;.
- </description>
- </method>
- <method name="get_item_ID" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Return the ID of the item at index &quot;idx&quot;.
- </description>
- </method>
- <method name="get_item_metadata" qualifiers="const" >
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_item_disabled" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_item_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- Return the amount of items in the OptionButton.
- </description>
- </method>
- <method name="add_separator" >
- <description>
- Add a separator to the list of items. Separators help to group items. Separator also takes up an index and is appended at the end.
- </description>
- </method>
- <method name="clear" >
- <description>
- Clear all the items in the [OptionButton].
- </description>
- </method>
- <method name="select" >
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- Select an item by index and make it the current item.
- </description>
- </method>
- <method name="get_selected" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- Return the current item index
- </description>
- </method>
- <method name="get_selected_ID" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_selected_metadata" qualifiers="const" >
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="item_selected">
- <argument index="0" name="ID" type="int">
- </argument>
- <description>
- This signal is emitted when the current item was changed by the user. ID of the item selected is passed as argument (if no IDs were added, ID will be just the item index).
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="PacketPeer" inherits="Object" category="Core">
- <brief_description>
- Abstraction and base class for packet-based protocols.
- </brief_description>
- <description>
- PacketPeer is an abstration and base class for packet-based protocols (such as UDP). It provides an API for sending and receiving packets both as raw data or variables. This makes it easy to transfer data over a protocol, without having to encode data as low level bytes or having to worry about network ordering.
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="PacketPeerStream" inherits="PacketPeer" category="Core">
- <brief_description>
- Wrapper to use a PacketPeer over a StreamPeer.
- </brief_description>
- <description>
- PacketStreamPeer provides a wrapper for working using packets over a stream. This allows for using packet based code with StreamPeers. PacketPeerStream implements a custom protocol over the StreamPeer, so the user should not read or write to the wrapped StreamPeer directly.
- </description>
- <methods>
- <method name="set_stream_peer" >
- <argument index="0" name="peer" type="Object">
- </argument>
- <description>
- Set the StreamPeer object to be wrapped
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Panel" inherits="Control" category="Nodes/GUI Nodes">
- <brief_description>
- Provides an opaque background for [Control] children.
- </brief_description>
- <description>
- Panel is a [Control] that displays an opaque background. It&apos;s commoly used as a parent and container for other types of [Control] nodes.&#10;&#9;[html div align=&quot;center&quot;][html img src=&quot;images/panel_example.png&quot;/][html /div]
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Particles" inherits="VisualInstance" category="Nodes/3D/3D Visual Nodes">
- <brief_description>
- Particle system 3D Node
- </brief_description>
- <description>
- Particles is a particle system 3D [Node] that is used to simulate several types of particle effects, such as explosions, rain, snow, fireflies, or other magical-like shinny sparkles. Particles are drawn using impostors, and given their dynamic behavior, the user must provide a visibility AABB (although helpers to create one automatically exist).
- </description>
- <methods>
- <method name="set_amount" >
- <argument index="0" name="amount" type="int">
- </argument>
- <description>
- Set total amount of particles in the system.
- </description>
- </method>
- <method name="get_amount" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- Return the total amount of particles in the system.
- </description>
- </method>
- <method name="set_emitting" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- Set the &quot;emitting&quot; property state. When emitting, the particle system generates new particles at constant rate.
- </description>
- </method>
- <method name="is_emitting" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- Return the &quot;emitting&quot; property state (see [method set_emitting]).
- </description>
- </method>
- <method name="set_visibility_aabb" >
- <argument index="0" name="aabb" type="AABB">
- </argument>
- <description>
- Set the visibility AABB for the particle system, since the default one will not work properly most of the time.
- </description>
- </method>
- <method name="get_visibility_aabb" qualifiers="const" >
- <return type="AABB">
- </return>
- <description>
- Return the current visibility AABB.
- </description>
- </method>
- <method name="set_emission_half_extents" >
- <argument index="0" name="half_extents" type="Vector3">
- </argument>
- <description>
- Set the half extents for the emission box.
- </description>
- </method>
- <method name="get_emission_half_extents" qualifiers="const" >
- <return type="Vector3">
- </return>
- <description>
- Return the half extents for the emission box.
- </description>
- </method>
- <method name="set_emission_points" >
- <argument index="0" name="points" type="Vector3Array">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_emission_points" qualifiers="const" >
- <return type="Vector3Array">
- </return>
- <description>
- </description>
- </method>
- <method name="set_gravity_normal" >
- <argument index="0" name="normal" type="Vector3">
- </argument>
- <description>
- Set the normal vector towards where gravity is pulling (by default, negative Y).
- </description>
- </method>
- <method name="get_gravity_normal" qualifiers="const" >
- <return type="Vector3">
- </return>
- <description>
- Return the normal vector towards where gravity is pulling (by default, negative Y).
- </description>
- </method>
- <method name="set_variable" >
- <argument index="0" name="variable" type="int">
- </argument>
- <argument index="1" name="value" type="real">
- </argument>
- <description>
- Set a specific variable for the particle system (see VAR_* enum).
- </description>
- </method>
- <method name="get_variable" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="variable" type="int">
- </argument>
- <description>
- Return a specific variable for the particle system (see VAR_* enum).
- </description>
- </method>
- <method name="set_randomness" >
- <argument index="0" name="variable" type="int">
- </argument>
- <argument index="1" name="randomness" type="real">
- </argument>
- <description>
- Set the randomness for a specific variable of the particle system. Randomness produces small changes from the default each time a particle is emitted.
- </description>
- </method>
- <method name="get_randomness" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- Return the randomness for a specific variable of the particle system. Randomness produces small changes from the default each time a particle is emitted.
- </description>
- </method>
- <method name="set_color_phase_pos" >
- <argument index="0" name="phase" type="int">
- </argument>
- <argument index="1" name="pos" type="real">
- </argument>
- <description>
- Set the position of a color phase (0 to 1)
- </description>
- </method>
- <method name="get_color_phase_pos" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="phase" type="int">
- </argument>
- <description>
- Return the position of a color phase (0 to 1)
- </description>
- </method>
- <method name="set_color_phase_color" >
- <argument index="0" name="phase" type="int">
- </argument>
- <argument index="1" name="color" type="Color">
- </argument>
- <description>
- Set the color of a color phase.
- </description>
- </method>
- <method name="get_color_phase_color" qualifiers="const" >
- <return type="Color">
- </return>
- <argument index="0" name="phase" type="int">
- </argument>
- <description>
- Return the color of a color phase.
- </description>
- </method>
- <method name="set_material" >
- <argument index="0" name="material" type="Object">
- </argument>
- <description>
- Set the material used to draw particles
- </description>
- </method>
- <method name="get_material" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- Return the material used to draw particles
- </description>
- </method>
- <method name="set_emit_timeout" >
- <argument index="0" name="arg0" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_emit_timeout" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_height_from_velocity" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_height_from_velocity" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_color_phases" >
- <argument index="0" name="count" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_color_phases" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="VAR_FINAL_SIZE" value="9">
- </constant>
- <constant name="VAR_INITIAL_SIZE" value="8">
- </constant>
- <constant name="VAR_LINEAR_ACCELERATION" value="5">
- </constant>
- <constant name="VAR_MAX" value="13">
- </constant>
- <constant name="VAR_DRAG" value="6">
- </constant>
- <constant name="VAR_GRAVITY" value="2">
- </constant>
- <constant name="VAR_SPREAD" value="1">
- </constant>
- <constant name="VAR_LIFETIME" value="0">
- </constant>
- <constant name="VAR_HEIGHT_SPEED_SCALE" value="12">
- </constant>
- <constant name="VAR_INITIAL_ANGLE" value="10">
- </constant>
- <constant name="VAR_TANGENTIAL_ACCELERATION" value="7">
- </constant>
- <constant name="VAR_ANGULAR_VELOCITY" value="4">
- </constant>
- <constant name="VAR_HEIGHT" value="11">
- </constant>
- <constant name="VAR_LINEAR_VELOCITY" value="3">
- </constant>
- </constants>
-</class>
-<class name="Particles2D" inherits="Node2D" category="Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_emitting" >
- <argument index="0" name="active" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_emitting" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_amount" >
- <argument index="0" name="amount" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_amount" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_lifetime" >
- <argument index="0" name="lifetime" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_lifetime" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_param" >
- <argument index="0" name="param" type="int">
- </argument>
- <argument index="1" name="value" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_param" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="param" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_randomness" >
- <argument index="0" name="param" type="int">
- </argument>
- <argument index="1" name="value" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_randomness" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="param" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_texture" >
- <argument index="0" name="texture" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_texture" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="set_emissor_offset" >
- <argument index="0" name="offset" type="Vector2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_emissor_offset" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="set_initial_color" >
- <argument index="0" name="initial_color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_initial_color" qualifiers="const" >
- <return type="Color">
- </return>
- <description>
- </description>
- </method>
- <method name="set_final_color" >
- <argument index="0" name="final_color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_final_color" qualifiers="const" >
- <return type="Color">
- </return>
- <description>
- </description>
- </method>
- <method name="set_use_parent_space" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_using_parent_space" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="PARAM_FINAL_SIZE" value="9">
- </constant>
- <constant name="PARAM_INITIAL_SIZE" value="8">
- </constant>
- <constant name="PARAM_RADIAL_ACCEL" value="6">
- </constant>
- <constant name="PARAM_GRAVITY_STRENGTH" value="5">
- </constant>
- <constant name="PARAM_MAX" value="11">
- </constant>
- <constant name="PARAM_HUE_VARIATION" value="10">
- </constant>
- <constant name="PARAM_TANGENTIAL_ACCEL" value="7">
- </constant>
- <constant name="PARAM_GRAVITY_DIRECTION" value="4">
- </constant>
- <constant name="PARAM_SPREAD" value="1">
- </constant>
- <constant name="PARAM_SPIN_VELOCITY" value="3">
- </constant>
- <constant name="PARAM_LINEAR_VELOCITY" value="2">
- </constant>
- <constant name="PARAM_DIRECTION" value="0">
- </constant>
- </constants>
-</class>
-<class name="PhysicsBody" inherits="Spatial" category="Nodes/3D">
- <brief_description>
- Base class for differnt types of Physics bodies.
- </brief_description>
- <description>
- PhysicsBody is an abstract base class for implementing a physics body. All PhysicsBody types inherit from it.
- </description>
- <methods>
- <method name="add_shape" >
- <argument index="0" name="shape" type="Object">
- </argument>
- <argument index="1" name="transform" type="Transform" default="Transform()">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_shape_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_shape" >
- <argument index="0" name="shape_idx" type="int">
- </argument>
- <argument index="1" name="shape" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_shape_transform" >
- <argument index="0" name="shape_idx" type="int">
- </argument>
- <argument index="1" name="transform" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_shape" qualifiers="const" >
- <return type="Object">
- </return>
- <argument index="0" name="shape_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_shape_transform" qualifiers="const" >
- <return type="Transform">
- </return>
- <argument index="0" name="shape_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="remove_shape" >
- <argument index="0" name="shape_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear_shapes" >
- <description>
- </description>
- </method>
- <method name="get_body" qualifiers="const" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="set_max_contacts_reported" >
- <argument index="0" name="contacts" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_max_contacts_reported" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_contacts_reported_depth_treshold" >
- <argument index="0" name="depth" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_contacts_reported_depth_treshold" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="PhysicsDirectBodyState" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="get_total_gravity" qualifiers="const" >
- <return type="Vector3">
- </return>
- <description>
- </description>
- </method>
- <method name="get_total_density" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_inverse_mass" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_inverse_inertia_tensor" qualifiers="const" >
- <return type="Matrix3">
- </return>
- <description>
- </description>
- </method>
- <method name="set_linear_velocity" >
- <argument index="0" name="velocity" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_linear_velocity" qualifiers="const" >
- <return type="Vector3">
- </return>
- <description>
- </description>
- </method>
- <method name="set_angular_velocity" >
- <argument index="0" name="velocity" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_angular_velocity" qualifiers="const" >
- <return type="Vector3">
- </return>
- <description>
- </description>
- </method>
- <method name="set_transform" >
- <argument index="0" name="transform" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_transform" qualifiers="const" >
- <return type="Transform">
- </return>
- <description>
- </description>
- </method>
- <method name="set_sleep_state" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_sleeping" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_contact_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_contact_local_pos" qualifiers="const" >
- <return type="Vector3">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_contact_local_normal" qualifiers="const" >
- <return type="Vector3">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_contact_local_shape" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_contact_collider" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_contact_collider_pos" qualifiers="const" >
- <return type="Vector3">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_contact_collider_id" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_contact_collider_shape" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_contact_collider_velocity_at_pos" qualifiers="const" >
- <return type="Vector3">
- </return>
- <argument index="0" name="contact_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="PhysicsDirectBodyStateSW" inherits="PhysicsDirectBodyState" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="PhysicsServer" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="shape_create" >
- <return type="RID">
- </return>
- <argument index="0" name="shape_type" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="shape_set_data" >
- <argument index="0" name="shape" type="RID">
- </argument>
- <argument index="1" name="data" type="var">
- </argument>
- <argument index="2" name="margin" type="real" default="-1">
- </argument>
- <description>
- </description>
- </method>
- <method name="shape_get_type" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="shape" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="shape_get_data" qualifiers="const" >
- <argument index="0" name="shape" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="space_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="area_create" >
- <return type="RID">
- </return>
- <argument index="0" name="space" type="int">
- </argument>
- <argument index="1" name="arg1" type="bool" default="RID()">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_set_param" >
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="param" type="int">
- </argument>
- <argument index="2" name="value" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_set_shape" >
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="shape" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_set_bounds" >
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="bounds" type="Dictionary">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_set_transform" >
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="transform" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_get_param" qualifiers="const" >
- <argument index="0" name="area" type="RID">
- </argument>
- <argument index="1" name="param" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_get_shape" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_get_bounds" qualifiers="const" >
- <return type="Dictionary">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="area_get_transform" qualifiers="const" >
- <return type="Transform">
- </return>
- <argument index="0" name="area" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_create" >
- <return type="RID">
- </return>
- <argument index="0" name="space" type="int">
- </argument>
- <argument index="1" name="arg1" type="bool" default="RID()">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_mode" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_mode" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_add_shape" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape" type="RID">
- </argument>
- <argument index="2" name="transform" type="Transform" default="Transform()">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_shape" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <argument index="2" name="shape" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_shape_transform" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <argument index="2" name="transform" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_shape_count" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_shape" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_shape_transform" qualifiers="const" >
- <return type="Transform">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="shape_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_attach_object_instance_ID" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="ID" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_object_instance_ID" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_user_flags" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="user_flags" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_user_flags" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_param" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="param" type="int">
- </argument>
- <argument index="2" name="value" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_param" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="param" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_static_simulate_motion" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="motion" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_state" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="state" type="int">
- </argument>
- <argument index="2" name="value" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_state" qualifiers="const" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="state" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_applied_force" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="applied_force" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_applied_force" qualifiers="const" >
- <return type="Vector3">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_applied_torque" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="applied_torque" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_get_applied_torque" qualifiers="const" >
- <return type="Vector3">
- </return>
- <argument index="0" name="body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_set_axis_velocity" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="axis_velocity" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_apply_impulse" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="pos" type="Vector3">
- </argument>
- <argument index="2" name="impulse" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_add_collision_exception" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="against_body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="body_remove_collision_exception" >
- <argument index="0" name="body" type="RID">
- </argument>
- <argument index="1" name="against_body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_create" >
- <return type="RID">
- </return>
- <argument index="0" name="receiver" type="Object">
- </argument>
- <argument index="1" name="callback" type="String">
- </argument>
- <argument index="2" name="userdata" type="var">
- </argument>
- <argument index="3" name="persist" type="bool" default="true">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_body_state" >
- <argument index="0" name="query" type="RID">
- </argument>
- <argument index="1" name="body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_body_direct_state" >
- <argument index="0" name="query" type="RID">
- </argument>
- <argument index="1" name="body" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_area" >
- <argument index="0" name="query" type="RID">
- </argument>
- <argument index="1" name="area" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_intersection" >
- <argument index="0" name="query" type="RID">
- </argument>
- <argument index="1" name="space" type="RID">
- </argument>
- <argument index="2" name="exclude" type="Array" default="Array()">
- </argument>
- <argument index="3" name="usermask" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_intersection_ray" >
- <argument index="0" name="query" type="RID">
- </argument>
- <argument index="1" name="origin" type="Vector3">
- </argument>
- <argument index="2" name="dir" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_intersection_segment" >
- <argument index="0" name="query" type="RID">
- </argument>
- <argument index="1" name="from" type="Vector3">
- </argument>
- <argument index="2" name="to" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_intersection_shape" >
- <argument index="0" name="query" type="RID">
- </argument>
- <argument index="1" name="shape" type="RID">
- </argument>
- <argument index="2" name="arg2" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_intersection_bounds" >
- <argument index="0" name="query" type="RID">
- </argument>
- <argument index="1" name="bounds" type="Dictionary">
- </argument>
- <argument index="2" name="arg2" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_clear" >
- <argument index="0" name="query" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_get_type" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="query" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="query_get_target" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="query" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="free" >
- <argument index="0" name="rid" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_active" >
- <argument index="0" name="active" type="bool">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="QUERY_BODY_STATE" value="1">
- </constant>
- <constant name="BODY_PARAM_FRICTION" value="1">
- </constant>
- <constant name="AREA_PARAM_OVERRIDE_PARAMS" value="0">
- </constant>
- <constant name="SHAPE_CUSTOM" value="9">
- </constant>
- <constant name="QUERY_INTERSECTION" value="4">
- </constant>
- <constant name="BODY_STATE_SLEEPING" value="3">
- </constant>
- <constant name="QUERY_AREA_MONITOR" value="3">
- </constant>
- <constant name="QUERY_BODY_DIRECT_STATE" value="2">
- </constant>
- <constant name="QUERY_NONE" value="0">
- </constant>
- <constant name="CONE_TWIST_VAR_RELAXATION" value="4">
- </constant>
- <constant name="CONE_TWIST_VAR_BIAS" value="3">
- </constant>
- <constant name="CONE_TWIST_VAR_SWING_SPAN_LIMIT_1" value="0">
- </constant>
- <constant name="HINGE_VAR_MOTOR_ENABLED" value="5">
- </constant>
- <constant name="HINGE_VAR_LIMIT_SOFTNESS" value="3">
- </constant>
- <constant name="HINGE_VAR_ANGULAR_ONLY" value="0">
- </constant>
- <constant name="BODY_STATE_ANGULAR_VELOCITY" value="2">
- </constant>
- <constant name="SHAPE_CAPSULE" value="5">
- </constant>
- <constant name="CONE_TWIST_VAR_SWING_SPAN_LIMIT_2" value="1">
- </constant>
- <constant name="BODY_STATE_LINEAR_VELOCITY" value="1">
- </constant>
- <constant name="BODY_MODE_CHARACTER" value="2">
- </constant>
- <constant name="AREA_PARAM_GRAVITY" value="1">
- </constant>
- <constant name="SHAPE_CONCAVE_POLYGON" value="7">
- </constant>
- <constant name="TYPE_BODY" value="0">
- </constant>
- <constant name="HINGE_VAR_MOTOR_TARGET_VELOCITY" value="6">
- </constant>
- <constant name="HINGE_VAR_HIGHER_LIMIT" value="2">
- </constant>
- <constant name="SHAPE_HEIGHTMAP" value="8">
- </constant>
- <constant name="SHAPE_SPHERE" value="2">
- </constant>
- <constant name="CONE_TWIST_VAR_TWIST_SPAN_LIMIT" value="2">
- </constant>
- <constant name="BODY_MODE_RIGID" value="1">
- </constant>
- <constant name="AREA_PARAM_DENSITY" value="5">
- </constant>
- <constant name="AREA_PARAM_GRAVITY_VECTOR" value="2">
- </constant>
- <constant name="SHAPE_PLANE" value="0">
- </constant>
- <constant name="HINGE_VAR_MOTOR_IMPULSE" value="7">
- </constant>
- <constant name="HINGE_VAR_RELAXATION" value="4">
- </constant>
- <constant name="HINGE_VAR_LOWER_LIMIT" value="1">
- </constant>
- <constant name="BODY_STATE_TRANSFORM" value="0">
- </constant>
- <constant name="BODY_PARAM_MASS" value="2">
- </constant>
- <constant name="BODY_PARAM_BOUNCE" value="0">
- </constant>
- <constant name="BODY_MODE_STATIC" value="0">
- </constant>
- <constant name="SHAPE_BOX" value="3">
- </constant>
- <constant name="TYPE_AREA" value="1">
- </constant>
- <constant name="AREA_PARAM_PRIORITY" value="6">
- </constant>
- <constant name="AREA_PARAM_GRAVITY_POINT_ATTENUATION" value="4">
- </constant>
- <constant name="AREA_PARAM_GRAVITY_IS_POINT" value="3">
- </constant>
- <constant name="SHAPE_CONVEX_POLYGON" value="6">
- </constant>
- <constant name="SHAPE_CYLINDER" value="4">
- </constant>
- </constants>
-</class>
-<class name="PhysicsServerSW" inherits="PhysicsServer" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="PlaneShape" inherits="Shape" category="Resources">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_plane" >
- <argument index="0" name="plane" type="Plane">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_plane" qualifiers="const" >
- <return type="Plane">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Popup" inherits="Control" category="Core">
- <brief_description>
- Base container control for popups and dialogs.
- </brief_description>
- <description>
- PopUp is a base [Control] used to show dialogs and popups. It&apos;s a subwindow and modal by default (see [Control]) and has helpers for custom popup behavior.
- </description>
- <methods>
- <method name="popup_centered" >
- <argument index="0" name="size" type="Vector2" default="Vector2(0,0)">
- </argument>
- <description>
- Popup (show the control in modal form) in the center of the screen, at the curent size, or at a size determined by &quot;size&quot;.
- </description>
- </method>
- <method name="popup_centered_ratio" >
- <argument index="0" name="ratio" type="real" default="0.75">
- </argument>
- <description>
- Popup (show the control in modal form) in the center of the screen, scalled at a ratio of size of the screen.
- </description>
- </method>
- <method name="popup" >
- <description>
- Popup (show the control in modal form).
- </description>
- </method>
- <method name="set_exclusive" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_exclusive" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="about_to_show">
- <description>
- This signal is emitted when a popup is about to be shown. (often used in [PopupMenu] for clearing the list of options and creating a new one according to the current context).
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="PopupDialog" inherits="Popup" category="Nodes/GUI Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="PopupMenu" inherits="Popup" category="Nodes/GUI Nodes">
- <brief_description>
- PopupMenu displays a list of options.
- </brief_description>
- <description>
- PopupMenu is the typical Control that displays a list of options. They are popular in toolbars or context menus.
- </description>
- <methods>
- <method name="add_icon_item" >
- <argument index="0" name="texture" type="Object">
- </argument>
- <argument index="1" name="label" type="String">
- </argument>
- <argument index="2" name="id" type="int" default="-1">
- </argument>
- <argument index="3" name="accel" type="int" default="0">
- </argument>
- <description>
- Add a new item with text &quot;label&quot; and icon &quot;texture. An id can optonally be provided, as well as an accelerator. If no id is provided, one will be created from the index.
- </description>
- </method>
- <method name="add_item" >
- <argument index="0" name="label" type="String">
- </argument>
- <argument index="1" name="id" type="int" default="-1">
- </argument>
- <argument index="2" name="accel" type="int" default="0">
- </argument>
- <description>
- Add a new item with text &quot;label&quot;. An id can optonally be provided, as well as an accelerator. If no id is provided, one will be created from the index.
- </description>
- </method>
- <method name="add_icon_check_item" >
- <argument index="0" name="texture" type="Object">
- </argument>
- <argument index="1" name="label" type="String">
- </argument>
- <argument index="2" name="id" type="int" default="-1">
- </argument>
- <argument index="3" name="accel" type="int" default="0">
- </argument>
- <description>
- Add a new checkable item with text &quot;label&quot; and icon &quot;texture. An id can optonally be provided, as well as an accelerator. If no id is provided, one will be created from the index. Note that checkable items just display a checkmark, but don&apos;t have any built-in checking behavior and must be checked/unchecked manually.
- </description>
- </method>
- <method name="add_check_item" >
- <argument index="0" name="label" type="String">
- </argument>
- <argument index="1" name="id" type="int" default="-1">
- </argument>
- <argument index="2" name="accel" type="int" default="0">
- </argument>
- <description>
- Add a new checkable item with text &quot;label&quot;. An id can optonally be provided, as well as an accelerator. If no id is provided, one will be created from the index. Note that checkable items just display a checkmark, but don&apos;t have any built-in checking behavior and must be checked/unchecked manually.
- </description>
- </method>
- <method name="set_item_text" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="text" type="String">
- </argument>
- <description>
- Set the text of the item at index &quot;idx&quot;.
- </description>
- </method>
- <method name="set_item_icon" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="icon" type="Object">
- </argument>
- <description>
- Set the icon of the item at index &quot;idx&quot;.
- </description>
- </method>
- <method name="set_item_accelerator" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="accel" type="int">
- </argument>
- <description>
- Set the accelerator of the item at index &quot;idx&quot;. Accelerators are special combinations of keys that activate the item, no matter which control is fucused.
- </description>
- </method>
- <method name="set_item_metadata" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="metadata" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_item_checked" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="arg1" type="bool">
- </argument>
- <description>
- Set the checkstate status of the item at index &quot;idx&quot;.
- </description>
- </method>
- <method name="set_item_disabled" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="arg1" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_item_ID" >
- <argument index="0" name="idx" type="int">
- </argument>
- <argument index="1" name="id" type="int">
- </argument>
- <description>
- Set the id of the item at index &quot;idx&quot;.
- </description>
- </method>
- <method name="get_item_text" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Return the text of the item at index &quot;idx&quot;.
- </description>
- </method>
- <method name="get_item_icon" qualifiers="const" >
- <return type="Object">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Return the icon of the item at index &quot;idx&quot;.
- </description>
- </method>
- <method name="get_item_metadata" qualifiers="const" >
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_item_accelerator" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Return the accelerator of the item at index &quot;idx&quot;. Accelerators are special combinations of keys that activate the item, no matter which control is fucused.
- </description>
- </method>
- <method name="is_item_checked" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Return the checkstate status of the item at index &quot;idx&quot;.
- </description>
- </method>
- <method name="is_item_disabled" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_item_ID" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="idx" type="int">
- </argument>
- <description>
- Return the id of the item at index &quot;idx&quot;.
- </description>
- </method>
- <method name="get_item_index" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="id" type="int">
- </argument>
- <description>
- Find and return the index of the item containing a given id.
- </description>
- </method>
- <method name="get_item_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- Return the amount of items.
- </description>
- </method>
- <method name="add_separator" >
- <description>
- Add a separator between items. Separators also occupy an index.
- </description>
- </method>
- <method name="clear" >
- <description>
- Clear the popup menu.
- </description>
- </method>
- </methods>
- <signals>
- <signal name="item_pressed">
- <argument index="0" name="ID" type="int">
- </argument>
- <description>
- This even is emitted when an item is pressed or its accelerator is activated. The id of the item is returned if it exists, else the index.
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="PopupPanel" inherits="Popup" category="Nodes/GUI Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Portal" inherits="VisualInstance" category="Nodes/3D/3D Visual Nodes">
- <brief_description>
- Portals provide virtual openings to rooms.
- </brief_description>
- <description>
- Portals provide virtual openings to [RoomInstance] nodes, so cameras can look at them from the outside. Note that portals are a visibility optimization technique, and are in no way related to the game of the same name (as in, they are not used for teleportation). For more information on how rooms and portals work, see [RoomInstance]. Portals are represented as 2D convex polygon shapes (in the X,Y local plane), and are placed on the surface of the areas occupied by a [RoomInstance], to indicate that the room can be accessed or looked-at through them. If two rooms are next to each other, and two similar portals in each of them share the same world position (and are parallel and opposed to each other), they will automatically &quot;connect&quot; and form &quot;doors&quot; (for example, the portals that connect a kitchen to a living room are placed in the door they share). Portals must always have a [RoomInstance] node as a parent, grandparent or far parent, or else they will not be active.
- </description>
- <methods>
- <method name="set_shape" >
- <argument index="0" name="points" type="Array">
- </argument>
- <description>
- Set the portal shape. The shape is an array of [Point2] points, representing a convex polygon in the X,Y plane.
- </description>
- </method>
- <method name="get_shape" qualifiers="const" >
- <return type="Array">
- </return>
- <description>
- Return the portal shape. The shape is an array of [Point2] points, representing a convex polygon in the X,Y plane.
- </description>
- </method>
- <method name="set_enabled" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- Enable the portal (it is enabled by defaul though), disabling it will cause the parent [RoomInstance] to not be visible any longer when looking through the portal.
- </description>
- </method>
- <method name="is_enabled" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- Return wether the portal is active. When disabled it causes the parent [RoomInstance] to not be visible any longer when looking through the portal.
- </description>
- </method>
- <method name="set_disable_distance" >
- <argument index="0" name="distance" type="real">
- </argument>
- <description>
- Set the distance threshold for disabling the portal. Every time that the portal goes beyond &quot;distance&quot;, it disables itself, becoming the opaque color (see [method set_disabled_color]).
- </description>
- </method>
- <method name="get_disable_distance" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- Return the distance threshold for disabling the portal. Every time that the portal goes beyond &quot;distance&quot;, it disables itself, becoming the opaque color (see [method set_disabled_color]).
- </description>
- </method>
- <method name="set_disabled_color" >
- <argument index="0" name="color" type="Color">
- </argument>
- <description>
- When the portal goes beyond the disable distance (see [method set_disable_distance]), it becomes opaque and displayed with color &quot;color&quot;.
- </description>
- </method>
- <method name="get_disabled_color" qualifiers="const" >
- <return type="Color">
- </return>
- <description>
- Return the color for when the portal goes beyond the disable distance (see [method set_disable_distance]) and becomes disabled.
- </description>
- </method>
- <method name="set_connect_range" >
- <argument index="0" name="range" type="real">
- </argument>
- <description>
- Set the range for auto-connecting two portals from different rooms sharing the same space.
- </description>
- </method>
- <method name="get_connect_range" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- Return the range for auto-connecting two portals from different rooms sharing the same space.
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Range" inherits="Control" category="Core">
- <brief_description>
- Abstract base class for range-based controls.
- </brief_description>
- <description>
- Range is a base class for [Control] nodes that change a floating point [html i]value[html /i] between a need a [html i]minimum[html /i], [html i]maximum[html /i], using [html i]step[html /i] and [html i]page[html /i], for example a [ScrollBar].
- </description>
- <methods>
- <method name="get_val" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- Return the current value.
- </description>
- </method>
- <method name="get_min" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- Return the minimum value.
- </description>
- </method>
- <method name="get_max" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- Return the maximum value.
- </description>
- </method>
- <method name="get_step" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- Return the stepping, if step is 0, stepping is disabled.
- </description>
- </method>
- <method name="get_page" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- Return the page size, if page is 0, paging is disabled.
- </description>
- </method>
- <method name="get_unit_value" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- Return value mapped to 0 to 1 (unit) range.
- </description>
- </method>
- <method name="set_val" >
- <argument index="0" name="value" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_min" >
- <argument index="0" name="minimum" type="real">
- </argument>
- <description>
- Set minimum value, clamped range value to it if it&apos;s less.
- </description>
- </method>
- <method name="set_max" >
- <argument index="0" name="maximum" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_step" >
- <argument index="0" name="step" type="real">
- </argument>
- <description>
- Set step value. If step is 0, stepping will be disabled.
- </description>
- </method>
- <method name="set_page" >
- <argument index="0" name="pagesize" type="real">
- </argument>
- <description>
- Set page size. Page is mainly used for scrollbars or anything that controls text scrolling.
- </description>
- </method>
- <method name="set_unit_value" >
- <argument index="0" name="value" type="real">
- </argument>
- <description>
- Set value mapped to 0 to 1 (unit) range, it will then be converted to the actual value within min and max.
- </description>
- </method>
- <method name="share" >
- <argument index="0" name="with" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="unshare" >
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="value_changed">
- <argument index="0" name="value" type="real">
- </argument>
- <description>
- This signal is emitted when value changes.
- </description>
- </signal>
- <signal name="changed">
- <description>
- This signal is emitted when min, max, range or step change.
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="RayShape" inherits="Shape" category="Resources">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_length" >
- <argument index="0" name="length" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_length" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Reference" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Resource" inherits="Reference" category="Resources">
- <brief_description>
- Base class for all resources.
- </brief_description>
- <description>
- Resource is the base class for all resource types. Resources are primarily data containers. They are reference counted and freed when no longer in use. They are also loaded only once from disk, and further attempts to load the resource will return the same reference (all this in contrast to a [Node], which is not reference counted and can be instanced from disk as many times as desred). Resources can be saved externally on disk or bundled into another object, such as a [Node] or another resource.
- </description>
- <methods>
- <method name="set_path" >
- <argument index="0" name="path" type="String">
- </argument>
- <description>
- Set the path of the resource. This is useful mainly for editors when saving/loading, and shouldn&apos;t be changed by anything else.
- </description>
- </method>
- <method name="get_path" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- Return the path of the resource. This is useful mainly for editors when saving/loading, and shouldn&apos;t be changed by anything else.
- </description>
- </method>
- <method name="set_name" >
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- Set the name of the resources, any name is ok (it doesn&apos;t have to be unique). Name is for descriptive purposes only.
- </description>
- </method>
- <method name="get_name" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- Return the name of the resources, any name is ok (it doesn&apos;t have to be unique). Name is for descriptive purposes only.
- </description>
- </method>
- <method name="get_rid" qualifiers="const" >
- <return type="RID">
- </return>
- <description>
- Return the RID of the resource (or an empty RID). Many resources (such as [Texture], [Mesh], etc) are high level abstractions of resources stored in a server, so this function will return the original RID.
- </description>
- </method>
- </methods>
- <signals>
- <signal name="changed">
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="_ResourceLoader" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="load" >
- <return type="Object">
- </return>
- <argument index="0" name="path" type="String">
- </argument>
- <argument index="1" name="type_hint" type="String" default="&quot;&quot;">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_recognized_extensions_for_type" >
- <return type="StringArray">
- </return>
- <argument index="0" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="_ResourceSaver" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="save" >
- <return type="int">
- </return>
- <argument index="0" name="path" type="String">
- </argument>
- <argument index="1" name="resource" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_recognized_extensions" >
- <return type="StringArray">
- </return>
- <argument index="0" name="type" type="Object">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="RichTextLabel" inherits="Control" category="Nodes/GUI Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="add_text" >
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_image" >
- <argument index="0" name="image" type="Texture">
- </argument>
- <description>
- </description>
- </method>
- <method name="newline" >
- <description>
- </description>
- </method>
- <method name="push_font" >
- <argument index="0" name="font" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="push_color" >
- <argument index="0" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="push_align" >
- <argument index="0" name="align" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="push_indent" >
- <argument index="0" name="level" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="push_list" >
- <argument index="0" name="type" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="push_meta" >
- <argument index="0" name="data" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="push_underline" >
- <description>
- </description>
- </method>
- <method name="pop" >
- <description>
- </description>
- </method>
- <method name="clear" >
- <description>
- </description>
- </method>
- <method name="set_meta_underline" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_meta_underlined" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_scroll_active" >
- <argument index="0" name="active" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_scroll_active" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_scroll_follow" >
- <argument index="0" name="follow" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_scroll_following" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_tab_size" >
- <argument index="0" name="spaces" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_tab_size" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="meta_clicked">
- <argument index="0" name="meta" type="Nil">
- </argument>
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- <constant name="ITEM_TEXT" value="1">
- </constant>
- <constant name="ITEM_MAIN" value="0">
- </constant>
- <constant name="ALIGN_CENTER" value="1">
- </constant>
- <constant name="ITEM_UNDERLINE" value="6">
- </constant>
- <constant name="ITEM_META" value="10">
- </constant>
- <constant name="ITEM_COLOR" value="5">
- </constant>
- <constant name="ITEM_FONT" value="4">
- </constant>
- <constant name="LIST_DOTS" value="2">
- </constant>
- <constant name="ALIGN_LEFT" value="0">
- </constant>
- <constant name="LIST_LETTERS" value="1">
- </constant>
- <constant name="LIST_NUMBERS" value="0">
- </constant>
- <constant name="ITEM_INDENT" value="8">
- </constant>
- <constant name="ITEM_NEWLINE" value="3">
- </constant>
- <constant name="ALIGN_RIGHT" value="2">
- </constant>
- <constant name="ITEM_ALIGN" value="7">
- </constant>
- <constant name="ITEM_IMAGE" value="2">
- </constant>
- <constant name="ALIGN_FILL" value="3">
- </constant>
- <constant name="ITEM_LIST" value="9">
- </constant>
- </constants>
-</class>
-<class name="Room" inherits="Resource" category="Resources">
- <brief_description>
- Room data resource.
- </brief_description>
- <description>
- Room contains the data to define the bounds of a scene (using a BSP Tree). It is instanced by a [RoomInstance] node to create rooms. See that class documentation for more information about rooms.
- </description>
- <methods>
- <method name="set_bounds" >
- <argument index="0" name="bsp_tree" type="Dictionary">
- </argument>
- <description>
- Set the bounds of the room as a BSP tree. a BSP Tree is defined a Dictionary: (TODO - see source code on how to create a BSP tree from a dictionary).
- </description>
- </method>
- <method name="get_bounds" qualifiers="const" >
- <return type="Dictionary">
- </return>
- <description>
- Return the bounds of the room as a BSP tree. a BSP Tree is defined a Dictionary: (TODO - see source code on how to create a BSP tree from a dictionary).
- </description>
- </method>
- <method name="set_geometry_hint" >
- <argument index="0" name="triangles" type="Vector3Array">
- </argument>
- <description>
- Set the &quot;geometry&quot; hint of the room. This means, how the room actually looks (an array of [Vector3]s, forming triangles).
- </description>
- </method>
- <method name="get_geometry_hint" qualifiers="const" >
- <return type="Vector3Array">
- </return>
- <description>
- Return the &quot;geometry&quot; hint of the room. This means, how the room actually looks (an array of [Vector3]s, forming triangles).
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="RoomInstance" inherits="VisualInstance" category="Nodes/3D/3D Visual Nodes">
- <brief_description>
- Node that instances a Room.
- </brief_description>
- <description>
- RoomInstance is a [Node] that instances a [Room] resource and places it on the world. Rooms are used for defining the areas taken up by [html i]interiors[html /i]. An [html i]interior[html /i] is any closed space that has an entrance/exit (or not) to the outside world, for example the inside of a house, a room in a house, a cave.[html br/]So why is this used? Rooms and Portals ([Portal]) are a common visualization optimization technique, it is used to make interiors invisible (not rendered) when the camera is at the exterior (such as an open field), and also the exterior invisible when inside an interior (such as a house). It is also used to make interior rooms invisible from other interior rooms.&#10;[html div align=&quot;center&quot;][html img src=&quot;images/portals_example.png&quot;/][html /div]
- </description>
- <methods>
- <method name="set_room" >
- <argument index="0" name="room" type="Object">
- </argument>
- <description>
- Set the [Room] resource, containing the room bounds.
- </description>
- </method>
- <method name="get_room" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- Return the [Room] resource, containing the room bounds.
- </description>
- </method>
- <method name="compute_room_from_subtree" >
- <description>
- This helper function computes a [Room] from the shapes of all the children [VisualInstance] nodes, and sets it to the node.
- </description>
- </method>
- <method name="set_simulate_acoustics" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_simulating_acoustics" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="SSAOFX" inherits="ScenarioFX" category="Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Sample" inherits="Resource" category="Resources">
- <brief_description>
- Audio Sample (sound) class.
- </brief_description>
- <description>
- Sample provides an audio sample class, containing audio data, together with some information for playback, such as format, mix rate and loop. It is used by sound playback routines.
- </description>
- <methods>
- <method name="create" >
- <argument index="0" name="format" type="int">
- </argument>
- <argument index="1" name="stereo" type="bool">
- </argument>
- <argument index="2" name="length" type="int">
- </argument>
- <description>
- Create new data for the sample, with format &quot;format&quot; (see FORMAT_* enum), stereo hint, and length in frames (not samples or bytes!) &quot;frame&quot;. Calling create overrides previous existing data if it exists. Stereo samples are interleaved pairs of left and right (in that order) points
- </description>
- </method>
- <method name="get_format" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- Return the sample format (see FORMAT_* enum).
- </description>
- </method>
- <method name="is_stereo" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- Return true if the sample was created stereo.
- </description>
- </method>
- <method name="get_length" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- Return the sample length in frames.
- </description>
- </method>
- <method name="set_data" >
- <argument index="0" name="data" type="RawArray">
- </argument>
- <description>
- Set sample data. Data must be little endian, no matter the host platform, and exactly as long to fit all frames. Example, if data is Stereo, 16 bits, 256 frames, it will be 1024 bytes long.
- </description>
- </method>
- <method name="get_data" qualifiers="const" >
- <return type="RawArray">
- </return>
- <description>
- Return sample data. Data will be endian, no matter with the host platform, and exactly as long to fit all frames. Example, if data is Stereo, 16 bits, 256 frames, it will be 1024 bytes long.
- </description>
- </method>
- <method name="set_mix_rate" >
- <argument index="0" name="hz" type="int">
- </argument>
- <description>
- Set the mix rate for the sample (expected playback frequency).
- </description>
- </method>
- <method name="get_mix_rate" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- Return the mix rate for the sample (expected playback frequency).
- </description>
- </method>
- <method name="set_loop_format" >
- <argument index="0" name="format" type="int">
- </argument>
- <description>
- Set the loop format, see LOOP_* enum
- </description>
- </method>
- <method name="get_loop_format" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- Return the loop format, see LOOP_* enum.
- </description>
- </method>
- <method name="set_loop_begin" >
- <argument index="0" name="pos" type="int">
- </argument>
- <description>
- Set the loop begin position, it must be a valid frame and less than the loop end position.
- </description>
- </method>
- <method name="get_loop_begin" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- Return the loop begin position.
- </description>
- </method>
- <method name="set_loop_end" >
- <argument index="0" name="pos" type="int">
- </argument>
- <description>
- Set the loop end position, it must be a valid frame and greater than the loop begin position.
- </description>
- </method>
- <method name="get_loop_end" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- Return the loop begin position.
- </description>
- </method>
- </methods>
- <constants>
- <constant name="FORMAT_IMA_ADPCM" value="2">
- Ima-ADPCM Audio.
- </constant>
- <constant name="LOOP_FORWARD" value="1">
- Forward looping (when playback reaches loop end, goes back to loop begin)
- </constant>
- <constant name="FORMAT_PCM16" value="1">
- 16-Bits signed little endian PCM audio.
- </constant>
- <constant name="FORMAT_PCM8" value="0">
- 8-Bits signed little endian PCM audio.
- </constant>
- <constant name="LOOP_NONE" value="0">
- No loop enabled.
- </constant>
- <constant name="LOOP_PING_PONG" value="2">
- Ping-Pong looping (when playback reaches loop end, plays backward untilloop begin). Not available in all platforms.
- </constant>
- </constants>
-</class>
-<class name="SampleLibrary" inherits="Resource" category="Resources">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="add_sample" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="sample" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_sample" qualifiers="const" >
- <return type="Object">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_sample" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="remove_sample" >
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="SamplePlayer" inherits="Node" category="Nodes/Audio Nodes">
- <brief_description>
- Sample Player node.
- </brief_description>
- <description>
- SamplePlayer is a [Node] meant for simple sample playback. A library of samples is loaded and played back &quot;as is&quot;, without positioning or anything.
- </description>
- <methods>
- <method name="set_sample_library" >
- <argument index="0" name="library" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_sample_library" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="set_voice_count" >
- <argument index="0" name="max_voices" type="int">
- </argument>
- <description>
- Set the amount of simultaneous voices that will be used for playback.
- </description>
- </method>
- <method name="get_voice_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- Return the amount of simultaneous voices that will be used for playback.
- </description>
- </method>
- <method name="play" >
- <return type="int">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="unique" type="bool" default="false">
- </argument>
- <description>
- Play back sample, given it&apos;s identifier &quot;name&quot;. if &quot;unique&quot; is true, all othere previous samples will be stopped. The voice allocated for playback will be returned.
- </description>
- </method>
- <method name="stop" >
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- Stop a voice &quot;voice&quot;. (see [method play]).
- </description>
- </method>
- <method name="stop_all" >
- <description>
- </description>
- </method>
- <method name="set_mix_rate" >
- <argument index="0" name="voice" type="int">
- </argument>
- <argument index="1" name="hz" type="int">
- </argument>
- <description>
- Change the mix rate of a voice &quot;voice&quot; to given &quot;hz&quot;.
- </description>
- </method>
- <method name="set_pitch_scale" >
- <argument index="0" name="voice" type="int">
- </argument>
- <argument index="1" name="ratio" type="real">
- </argument>
- <description>
- Scale the pitch (mix rate) of a voice by a ratio value &quot;ratio&quot;. A ratio of 1.0 means the voice is unscaled.
- </description>
- </method>
- <method name="set_volume" >
- <argument index="0" name="voice" type="int">
- </argument>
- <argument index="1" name="nrg" type="real">
- </argument>
- <description>
- Set the volume of a voice, 0db is maximum volume (every about -6db, volume is reduced in half). &quot;db&quot; does in fact go from zero to negative.
- </description>
- </method>
- <method name="set_volume_db" >
- <argument index="0" name="voice" type="int">
- </argument>
- <argument index="1" name="nrg" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_pan" >
- <argument index="0" name="voice" type="int">
- </argument>
- <argument index="1" name="pan" type="real">
- </argument>
- <argument index="2" name="depth" type="real" default="0">
- </argument>
- <argument index="3" name="height" type="real" default="0">
- </argument>
- <description>
- Set the panning of a voice. Panning goes from -1 (left) to +1 (right). Optionally, if the hardware supports 3D sound, also set depth and height (also in range -1 to +1).
- </description>
- </method>
- <method name="set_filter" >
- <argument index="0" name="voice" type="int">
- </argument>
- <argument index="1" name="type" type="int">
- </argument>
- <argument index="2" name="cutoff_hz" type="real">
- </argument>
- <argument index="3" name="resonance" type="real">
- </argument>
- <argument index="4" name="gain" type="real" default="0">
- </argument>
- <description>
- Set and enable a filter of a voice, with type &quot;type&quot; (see FILTER_* enum), cutoff (0 to 22khz) frequency and resonance (0+).
- </description>
- </method>
- <method name="set_chorus" >
- <argument index="0" name="voice" type="int">
- </argument>
- <argument index="1" name="send" type="real">
- </argument>
- <description>
- Set the chorus send level of a voice (0 to 1). For setting chorus parameters, see [AudioServer].
- </description>
- </method>
- <method name="set_reverb" >
- <argument index="0" name="voice" type="int">
- </argument>
- <argument index="1" name="room_type" type="int">
- </argument>
- <argument index="2" name="send" type="real">
- </argument>
- <description>
- Set the reverb send level and type of a voice (0 to 1). (see REVERB_* enum for type).
- </description>
- </method>
- <method name="get_mix_rate" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- Return the current mix rate for a given voice.
- </description>
- </method>
- <method name="get_pitch_scale" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- Return the current pitch scale for a given voice.
- </description>
- </method>
- <method name="get_volume" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- Return the current volume (in db) for a given voice. 0db is maximum volume (every about -6db, volume is reduced in half). &quot;db&quot; does in fact go from zero to negative.
- </description>
- </method>
- <method name="get_volume_db" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_pan" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- Return the current panning for a given voice. Panning goes from -1 (left) to +1 (right).
- </description>
- </method>
- <method name="get_pan_depth" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- Return the current pan depth for a given voice (not used unless the hardware supports 3D sound)
- </description>
- </method>
- <method name="get_pan_height" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- Return the current pan height for a given voice (not used unless the hardware supports 3D sound)
- </description>
- </method>
- <method name="get_filter_type" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- Return the current filter type in use (see FILTER_* enum) for a given voice.
- </description>
- </method>
- <method name="get_filter_cutoff" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- Return the current filter cutoff for a given voice. Cutoff goes from 0 to 22khz.
- </description>
- </method>
- <method name="get_filter_resonance" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- Return the current filter resonance for a given voice. Resonance goes from 0 up.
- </description>
- </method>
- <method name="get_filter_gain" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_chorus" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- Return the current chorus send level for a given voice. (0 to 1).
- </description>
- </method>
- <method name="get_reverb_room" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- Return the current reverb room type for a given voice (see REVERB_* enum).
- </description>
- </method>
- <method name="get_reverb" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- Return the current reverb send level for a given voice. (0 to 1).
- </description>
- </method>
- <method name="set_default_pitch_scale" >
- <argument index="0" name="ratio" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_default_volume" >
- <argument index="0" name="nrg" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_default_volume_db" >
- <argument index="0" name="db" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_default_pan" >
- <argument index="0" name="pan" type="real">
- </argument>
- <argument index="1" name="depth" type="real" default="0">
- </argument>
- <argument index="2" name="height" type="real" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_default_filter" >
- <argument index="0" name="type" type="int">
- </argument>
- <argument index="1" name="cutoff_hz" type="real">
- </argument>
- <argument index="2" name="resonance" type="real">
- </argument>
- <argument index="3" name="gain" type="real" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_default_chorus" >
- <argument index="0" name="send" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_default_reverb" >
- <argument index="0" name="room_type" type="int">
- </argument>
- <argument index="1" name="send" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_default_pitch_scale" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_volume" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_volume_db" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_pan" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_pan_depth" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_pan_height" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_filter_type" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_filter_cutoff" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_filter_resonance" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_filter_gain" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_chorus" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_reverb_room" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_default_reverb" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="FILTER_HIPASS" value="3">
- HighPass filter is used for voice.
- </constant>
- <constant name="FILTER_NONE" value="0">
- Filter is disabled for voice.
- </constant>
- <constant name="REVERB_HALL" value="3">
- Huge reverb room (cathedral, warehouse).
- </constant>
- <constant name="REVERB_MEDIUM" value="1">
- Medium reverb room (street)
- </constant>
- <constant name="REVERB_SMALL" value="0">
- Small reverb room (house room).
- </constant>
- <constant name="FILTER_HIGH_SHELF" value="8">
- </constant>
- <constant name="FILTER_PEAK" value="5">
- </constant>
- <constant name="FILTER_LOWPASS" value="1">
- Lowpass filter is used for voice.
- </constant>
- <constant name="REVERB_LARGE" value="2">
- Large reverb room (Theather)
- </constant>
- <constant name="FILTER_LOW_SHELF" value="7">
- </constant>
- <constant name="FILTER_BANDLIMIT" value="6">
- Band-Limit filter is used for voice, in this case resonance is the highpass cutoff.
- </constant>
- <constant name="FILTER_NOTCH" value="4">
- Notch filter is used for voice.
- </constant>
- <constant name="FILTER_BANDPASS" value="2">
- Bandpass filter is used for voice.
- </constant>
- </constants>
-</class>
-<class name="ScenarioFX" inherits="Node" category="Nodes">
- <brief_description>
- </brief_description>
- <description>
- Deprecated, will go away.
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="SceneMainLoop" inherits="MainLoop" category="Main Loop">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_editor_hint" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_editor_hint" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_pause" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_paused" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="quit" >
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="screen_resized">
- <description>
- </description>
- </signal>
- <signal name="node_removed">
- <argument index="0" name="node" type="Object">
- </argument>
- <description>
- </description>
- </signal>
- <signal name="tree_changed">
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="Script" inherits="Resource" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="ScrollBar" inherits="Range" category="Core">
- <brief_description>
- Base class for scroll bars.
- </brief_description>
- <description>
- Scrollbars are a [Range] based [Control], that display a draggable area (the size of the page). Horizontal ([HScrollBar]) and Vertical ([VScrollBar]) versions are available.
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Separator" inherits="Control" category="Nodes/GUI Nodes">
- <brief_description>
- Base class for separators.
- </brief_description>
- <description>
- Separator is a [Control] used for sepataring other controls. It&apos;s purely a visual decoration. Horizontal ([HSeparator]) and Vertical ([VSeparator]) versions are available.
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Shader" inherits="Resource" category="Resources">
- <brief_description>
- To be changed, ignore.
- </brief_description>
- <description>
- To be changed, ignore.
- </description>
- <methods>
- <method name="set_mode" >
- <argument index="0" name="mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_mode" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_vertex_code" >
- <argument index="0" name="code" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_vertex_code" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="set_fragment_code" >
- <argument index="0" name="code" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_fragment_code" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="set_use_world_transform" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_using_world_transform" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_param" >
- <argument index="0" name="param" type="String">
- </argument>
- <argument index="1" name="value" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_param" qualifiers="const" >
- <argument index="0" name="param" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_param_list" qualifiers="const" >
- <return type="StringArray">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="MODE_MATERIAL" value="0">
- </constant>
- <constant name="MODE_POST_PROCESS" value="1">
- </constant>
- </constants>
-</class>
-<class name="ShaderMaterial" inherits="Material" category="Resources">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_shader" >
- <argument index="0" name="shader" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_shader" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Shape" inherits="Resource" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Skeleton" inherits="Spatial" category="Nodes/3D">
- <brief_description>
- Skeleton for characters and animated objects.
- </brief_description>
- <description>
- Skeleton provides a hierachial interface for managing bones, including pose, rest and animation (see [Animation]). Skeleton will support rag doll dynamics in the future.
- </description>
- <methods>
- <method name="add_bone" >
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- Add a bone, with name &quot;name&quot;. [method get_bone_count] will become the bone index.
- </description>
- </method>
- <method name="find_bone" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <description>
- Return the bone index that matches &quot;name&quot; as its name.
- </description>
- </method>
- <method name="get_bone_name" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <description>
- Return the name of the bone at index &quot;index&quot;
- </description>
- </method>
- <method name="get_bone_parent" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <description>
- Return the bone index which is the parent of the bone at &quot;bone_idx&quot;. If -1, then bone has no parent. Note that the parent bone returned will always be less than &quot;bone_idx&quot;.
- </description>
- </method>
- <method name="set_bone_parent" >
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <argument index="1" name="parent_idx" type="int">
- </argument>
- <description>
- Set the bone index &quot;parent_idx&quot; as the parent of the bone at &quot;bone_idx&quot;. If -1, then bone has no parent. Note: &quot;parent_idx&quot; must be less than &quot;bone_idx&quot;.
- </description>
- </method>
- <method name="get_bone_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- Return the amount of bones in the skeleton.
- </description>
- </method>
- <method name="get_bone_rest" qualifiers="const" >
- <return type="Transform">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <description>
- Return the rest transform for a bone &quot;bone_idx&quot;.
- </description>
- </method>
- <method name="set_bone_rest" >
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <argument index="1" name="rest" type="Transform">
- </argument>
- <description>
- Set the rest transform for bone &quot;bone_idx&quot;
- </description>
- </method>
- <method name="bind_child_node_to_bone" >
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <argument index="1" name="node" type="Object">
- </argument>
- <description>
- Deprecated soon
- </description>
- </method>
- <method name="unbind_child_node_from_bone" >
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <argument index="1" name="node" type="Object">
- </argument>
- <description>
- Deprecated soon
- </description>
- </method>
- <method name="get_bound_child_nodes_to_bone" qualifiers="const" >
- <return type="Array">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <description>
- Deprecated Soon
- </description>
- </method>
- <method name="clear_bones" >
- <description>
- Clear all the bones in this skeleton.
- </description>
- </method>
- <method name="get_bone_pose" qualifiers="const" >
- <return type="Transform">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <description>
- Return the pose transform for bone &quot;bone_idx&quot;.
- </description>
- </method>
- <method name="set_bone_pose" >
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <argument index="1" name="pose" type="Transform">
- </argument>
- <description>
- Return the pose transform for bone &quot;bone_idx&quot;.
- </description>
- </method>
- <method name="get_bone_custom_pose" qualifiers="const" >
- <return type="Transform">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_bone_custom_pose" >
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <argument index="1" name="custom_pose" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_bone_transform" qualifiers="const" >
- <return type="Transform">
- </return>
- <argument index="0" name="bone_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="NOTIFICATION_UPDATE_SKELETON" value="50">
- </constant>
- </constants>
-</class>
-<class name="SkyBoxFX" inherits="ScenarioFX" category="Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Slider" inherits="Range" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="SoundRoomParams" inherits="Node" category="Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_param" >
- <argument index="0" name="param" type="int">
- </argument>
- <argument index="1" name="value" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_param" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="param" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_reverb_mode" >
- <argument index="0" name="reverb_mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_reverb_mode" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_force_params_to_all_sources" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_forcing_params_to_all_sources" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Spatial" inherits="Node" category="Nodes/3D">
- <brief_description>
- Base class for all 3D nodes.
- </brief_description>
- <description>
- Spatial is the base for every type of 3D [Node]. It contains a 3D [Transform] which can be set or get as local or global. If a Spatial [Node] has Spatial children, their transforms will be relative to the parent.
- </description>
- <methods>
- <method name="set_transform" >
- <argument index="0" name="local" type="Transform">
- </argument>
- <description>
- Set the transform locally, relative to the parent spatial node.
- </description>
- </method>
- <method name="get_transform" qualifiers="const" >
- <return type="Transform">
- </return>
- <description>
- Return the local transform, relative to the bone parent.
- </description>
- </method>
- <method name="set_global_transform" >
- <argument index="0" name="global" type="Transform">
- </argument>
- <description>
- Set the transform globally, relative to worldspace.
- </description>
- </method>
- <method name="get_global_transform" qualifiers="const" >
- <return type="Transform">
- </return>
- <description>
- Return the gloal transform, relative to worldspace.
- </description>
- </method>
- <method name="get_parent_spatial" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- Return the parent [Spatial], or an empty [Object] if no parent exists or parent is not of type [Spatial.
- </description>
- </method>
- <method name="update_gizmo" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="NOTIFICATION_SCENARIO_CHANGED" value="41">
- Spatial nodes receive this notification when the viewport next to it in ascending hierarchy changed the [Scenario].
- </constant>
- <constant name="NOTIFICATION_TRANSFORM_CHANGED" value="40">
- Spatial nodes receive this notifacation with their global transform changes. This means that either the current or a parent node changed it&apos;s transform.
- </constant>
- </constants>
-</class>
-<class name="SpatialPlayer" inherits="Spatial" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="SpatialSamplePlayer" inherits="SpatialPlayer" category="Nodes/3D">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_sample_library" >
- <argument index="0" name="library" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_sample_library" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="set_polyphony" >
- <argument index="0" name="voices" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_polyphony" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="play" >
- <return type="int">
- </return>
- <argument index="0" name="sample" type="String">
- </argument>
- <argument index="1" name="voice" type="int" default="-2">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_set_pitch_scale" >
- <argument index="0" name="voice" type="int">
- </argument>
- <argument index="1" name="ratio" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="voice_set_volume_scale_db" >
- <argument index="0" name="voice" type="int">
- </argument>
- <argument index="1" name="db" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_voice_active" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="stop_voice" >
- <argument index="0" name="voice" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="stop_all" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="NEXT_VOICE" value="-2">
- </constant>
- <constant name="INVALID_VOICE" value="-1">
- </constant>
- </constants>
-</class>
-<class name="SpatialSoundServer" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="SpatialSoundServerSW" inherits="SpatialSoundServer" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="SpatialStreamPlayer" inherits="SpatialPlayer" category="Nodes/3D">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_stream" >
- <argument index="0" name="stream" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_stream" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="play" >
- <description>
- </description>
- </method>
- <method name="stop" >
- <description>
- </description>
- </method>
- <method name="is_playing" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_loop" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_loop" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_stream_name" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="get_loop_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_pos" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="seek_pos" >
- <argument index="0" name="time" type="real">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="SphereShape" inherits="Shape" category="Resources">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_radius" >
- <argument index="0" name="radius" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_radius" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="SpinBox" inherits="Range" category="Nodes/GUI Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_suffix" >
- <argument index="0" name="suffix" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_suffix" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="set_prefix" >
- <argument index="0" name="prefix" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_prefix" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="set_editable" >
- <argument index="0" name="editable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_editable" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="SpotLight" inherits="Light" category="Nodes/3D/3D Visual Nodes/3D Light Nodes">
- <brief_description>
- Spotlight Light, such as a reflector spotlight or a latern.
- </brief_description>
- <description>
- A SpotLight light is a type of [Light] node that emits lights in a specific direction, in the shape of a cone. The light is attenuated through the distance and this attenuation can be configured by changing the energy, radius and attenuation parameters of [Light]. TODO: Image of a spotlight.
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Sprite" inherits="Node2D" category="Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_texture" >
- <argument index="0" name="texture" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_texture" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="set_centered" >
- <argument index="0" name="centered" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_centered" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_flip_h" >
- <argument index="0" name="flip_h" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_flipped_h" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_flip_v" >
- <argument index="0" name="flip_v" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_flipped_v" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_frame" >
- <argument index="0" name="frame" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_frame" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_vframes" >
- <argument index="0" name="vframes" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_vframes" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_hframes" >
- <argument index="0" name="hframes" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_hframes" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_modulate" >
- <argument index="0" name="modulate" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_modulate" qualifiers="const" >
- <return type="Color">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="SquirrelScript" inherits="Script" category="Resources">
- <brief_description>
- Squirrel script language support.
- </brief_description>
- <description>
- [html a href=&quot;http://squirrel-lang.org/&quot;]Squirrel Language[html /a] support for the engine. Allows to load a [Script] from a .sq or .nut source or compiled file, or bundled it into scenes.
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="StaticBody" inherits="PhysicsBody" category="Nodes/3D">
- <brief_description>
- PhysicsBody for static collision objects.
- </brief_description>
- <description>
- StaticBody implements a static collision [Node], by utilizing a rigid body in the [PhysicsServer]. Static bodies are used for static collision. For more information on physics body nodes, see [PhysicsBody].
- </description>
- <methods>
- <method name="set_simulated_motion" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_simulating_motion" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="simulate_motion" >
- <argument index="0" name="new_transform" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="create_shapes_from_child_meshes" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="StreamPeer" inherits="Object" category="Networking">
- <brief_description>
- Abstraction and base class for stream-based protocols.
- </brief_description>
- <description>
- StreamPeer is an abstration and base class for stream-based protocols (such as TCP or Unix Sockets). It provides an API for sending and receiving data through streams as raw data or strings.
- </description>
- <methods>
- <method name="put_data" >
- <return type="int">
- </return>
- <argument index="0" name="data" type="RawArray">
- </argument>
- <description>
- Send a chunk of data through the connection, blocking if necesary until the data is done sending. This function returns an [Error] code.
- </description>
- </method>
- <method name="put_partial_data" >
- <return type="Array">
- </return>
- <argument index="0" name="data" type="RawArray">
- </argument>
- <description>
- Send a chunk of data through the connection, if all the data could not be sent at once, only part of it will. This function returns two values, an [Error] code and an integer, describing how much data was actually sent.
- </description>
- </method>
- <method name="get_data" >
- <return type="Array">
- </return>
- <argument index="0" name="bytes" type="int">
- </argument>
- <description>
- Return a chunk data with the received bytes. The amount of bytes to be received can be requested in the &quot;bytes&quot; argument. If not enough bytes are available, the function will block until the desired amount is received. This function returns two values, an [Error] code and a data array.
- </description>
- </method>
- <method name="get_partial_data" >
- <return type="Array">
- </return>
- <argument index="0" name="bytes" type="int">
- </argument>
- <description>
- Return a chunk data with the received bytes. The amount of bytes to be received can be requested in the &quot;bytes&quot; argument. If not enough bytes are available, the function will return how many were actually received. This function returns two values, an [Error] code, and a data array.
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="StreamPeerTCP" inherits="StreamPeer" category="Networking/Networking">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="connect" >
- <return type="int">
- </return>
- <argument index="0" name="host" type="String">
- </argument>
- <argument index="1" name="ip" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_connected" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_connected_host" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="get_connected_port" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="disconnect" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="StreamPlayer" inherits="Node" category="Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_stream" >
- <argument index="0" name="stream" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_stream" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="play" >
- <description>
- </description>
- </method>
- <method name="stop" >
- <description>
- </description>
- </method>
- <method name="is_playing" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_loop" >
- <argument index="0" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_loop" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_volume" >
- <argument index="0" name="volume" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_volume" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_volume_db" >
- <argument index="0" name="db" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_volume_db" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="get_stream_name" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="get_loop_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_pos" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="seek_pos" >
- <argument index="0" name="time" type="real">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="StyleBox" inherits="Resource" category="Core">
- <brief_description>
- Base class for dawing stylized boxes for the UI.
- </brief_description>
- <description>
- StyleBox is [Resource] that provides an abstract base class for dawing stylized boxes for the UI. StyleBoxes are used for dawing the styles of buttons, line edit backgrounds, tree backgrounds, etc. and also for testing a transparency mask for pointer signals. If mask test fails on a StyleBox assigned as mask to a control, clicks and motion signals will go through it to the one below.
- </description>
- <methods>
- <method name="test_mask" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="point" type="Vector2">
- </argument>
- <argument index="1" name="rect" type="Rect2">
- </argument>
- <description>
- Test a position in a rectangle, return wether it pases the mask test.
- </description>
- </method>
- <method name="set_default_margin" >
- <argument index="0" name="margin" type="int">
- </argument>
- <argument index="1" name="offset" type="real">
- </argument>
- <description>
- Set the default offset &quot;offset&quot; of the margin &quot;margin&quot; (see MARGIN_* enum) for a StyleBox, Controls that draw styleboxes with context inside need to know the margin, so the border of the stylebox is not occluded.
- </description>
- </method>
- <method name="get_default_margin" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="margin" type="int">
- </argument>
- <description>
- Return the default offset of the margin &quot;margin&quot; (see MARGIN_* enum) of a StyleBox, Controls that draw styleboxes with context inside need to know the margin, so the border of the stylebox is not occluded.
- </description>
- </method>
- <method name="get_margin" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="margin" type="int">
- </argument>
- <description>
- Return the offset of margin &quot;margin&quot; (see MARGIN_* enum).
- </description>
- </method>
- <method name="get_minimum_size" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- Return the minimum size that this stylebox can be shrunk to.
- </description>
- </method>
- <method name="get_offset" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- Return the &quot;offset&quot; of a stylebox, this is a helper function, like writing Point2( style.get_margin(MARGIN_LEFT), style.get_margin(MARGIN_TOP) )
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="StyleBoxEmpty" inherits="StyleBox" category="Resources">
- <brief_description>
- Empty stylebox (does not display anything).
- </brief_description>
- <description>
- Empty stylebox (really does not display anything).
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="StyleBoxFlat" inherits="StyleBox" category="Resources">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_bg_color" >
- <argument index="0" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_bg_color" qualifiers="const" >
- <return type="Color">
- </return>
- <description>
- </description>
- </method>
- <method name="set_light_color" >
- <argument index="0" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_light_color" qualifiers="const" >
- <return type="Color">
- </return>
- <description>
- </description>
- </method>
- <method name="set_dark_color" >
- <argument index="0" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_dark_color" qualifiers="const" >
- <return type="Color">
- </return>
- <description>
- </description>
- </method>
- <method name="set_border_size" >
- <argument index="0" name="size" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_border_size" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_border_blend" >
- <argument index="0" name="blend" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_border_blend" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_draw_center" >
- <argument index="0" name="size" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_draw_center" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="StyleBoxImageMask" inherits="StyleBox" category="Resources">
- <brief_description>
- Image mask based StyleBox, for mask test.
- </brief_description>
- <description>
- This StyleBox is similar to [StyleBoxTexture], but only meant to be used for mask testing. It takes an image and applies stretch rules to determine if the poit clicked is masked or not.
- </description>
- <methods>
- <method name="set_image" >
- <argument index="0" name="image" type="Image">
- </argument>
- <description>
- Set the image used for mask testing. Pixels (converted to grey) that have a value, less than 0.5 will fail the test.
- </description>
- </method>
- <method name="get_image" qualifiers="const" >
- <return type="Image">
- </return>
- <description>
- Return the image used for mask testing. (see [method set_imag]).
- </description>
- </method>
- <method name="set_expand" >
- <argument index="0" name="expand" type="bool">
- </argument>
- <description>
- Set the expand property (default). When expanding, the image will use the same rules as [StyleBoxTexture] for expand. If not expanding, the image will always be tested at its original size.
- </description>
- </method>
- <method name="get_expand" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- Return wether the expand property is set(default). When expanding, the image will use the same rules as [StyleBoxTexture] for expand. If not expanding, the image will always be tested at its original size.
- </description>
- </method>
- <method name="set_expand_margin_size" >
- <argument index="0" name="margin" type="int">
- </argument>
- <argument index="1" name="size" type="real">
- </argument>
- <description>
- Set an expand margin size (from enum MARGIN_*). Parts of the image below the size of the margin (and in the direction of the margin) will not expand.
- </description>
- </method>
- <method name="get_expand_margin_size" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- Return the expand margin size (from enum MARGIN_*). Parts of the image below the size of the margin (and in the direction of the margin) will not expand.
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="StyleBoxTexture" inherits="StyleBox" category="Resources">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_texture" >
- <argument index="0" name="texture" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_texture" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="set_margin_size" >
- <argument index="0" name="margin" type="int">
- </argument>
- <argument index="1" name="size" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_margin_size" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_expand_margin_size" >
- <argument index="0" name="margin" type="int">
- </argument>
- <argument index="1" name="size" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_expand_margin_size" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_draw_center" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_draw_center" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_center_size" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="draw" qualifiers="const" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Rect2">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="SurfaceTool" inherits="Reference" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="begin" >
- <argument index="0" name="primitive" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_vertex" >
- <argument index="0" name="vertex" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_color" >
- <argument index="0" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_normal" >
- <argument index="0" name="normal" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_tangent" >
- <argument index="0" name="tangent" type="Plane">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_uv" >
- <argument index="0" name="uv" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_uv2" >
- <argument index="0" name="uv2" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_bones" >
- <argument index="0" name="bones" type="IntArray">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_weights" >
- <argument index="0" name="weights" type="RealArray">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_material" >
- <argument index="0" name="material" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="index" >
- <description>
- </description>
- </method>
- <method name="deindex" >
- <description>
- </description>
- </method>
- <method name="generate_flat_normals" >
- <description>
- </description>
- </method>
- <method name="generate_smooth_normals" >
- <description>
- </description>
- </method>
- <method name="generate_tangents" >
- <description>
- </description>
- </method>
- <method name="commit" >
- <return type="Object">
- </return>
- <argument index="0" name="existing" type="Object" default="Object()">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="TCP_Server" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="listen" >
- <return type="int">
- </return>
- <argument index="0" name="port" type="int">
- </argument>
- <argument index="1" name="accepted_hosts" type="StringArray" default="StringArray()">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_connection_available" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="take_connection" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="stop" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="TabContainer" inherits="Control" category="Nodes/GUI Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="get_tab_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_current_tab" >
- <argument index="0" name="tab_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_current_tab" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_tab_align" >
- <argument index="0" name="align" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_tab_align" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_tabs_visible" >
- <argument index="0" name="visible" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="are_tabs_visible" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_tab_title" >
- <argument index="0" name="tab_idx" type="int">
- </argument>
- <argument index="1" name="title" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_tab_title" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="tab_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_tab_icon" >
- <argument index="0" name="tab_idx" type="int">
- </argument>
- <argument index="1" name="icon" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_tab_icon" qualifiers="const" >
- <return type="Object">
- </return>
- <argument index="0" name="tab_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="tab_changed">
- <argument index="0" name="tab" type="int">
- </argument>
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="TestCube" inherits="VisualInstance" category="Nodes/3D/3D Visual Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="TextEdit" inherits="Control" category="Nodes/GUI Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_text" >
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="insert_text_at_cursor" >
- <argument index="0" name="text" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_line_count" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_text" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="get_line" >
- <return type="String">
- </return>
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="cursor_set_column" >
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="cursor_set_line" >
- <argument index="0" name="line" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="cursor_get_column" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="cursor_get_line" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_readonly" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_wrap" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_max_chars" >
- <argument index="0" name="amount" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="cut" >
- <description>
- </description>
- </method>
- <method name="copy" >
- <description>
- </description>
- </method>
- <method name="paste" >
- <description>
- </description>
- </method>
- <method name="select_all" >
- <description>
- </description>
- </method>
- <method name="select" >
- <argument index="0" name="from_line" type="int">
- </argument>
- <argument index="1" name="from_column" type="int">
- </argument>
- <argument index="2" name="to_line" type="int">
- </argument>
- <argument index="3" name="to_column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_selection_active" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_selection_from_line" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_selection_from_column" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_selection_to_line" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_selection_to_column" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_selection_text" qualifiers="const" >
- <return type="String">
- </return>
- <description>
- </description>
- </method>
- <method name="search" qualifiers="const" >
- <return type="IntArray">
- </return>
- <argument index="0" name="flags" type="String">
- </argument>
- <argument index="1" name="from_line" type="int">
- </argument>
- <argument index="2" name="from_column" type="int">
- </argument>
- <argument index="3" name="to_line" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="undo" >
- <description>
- </description>
- </method>
- <method name="redo" >
- <description>
- </description>
- </method>
- <method name="clear_undo_history" >
- <description>
- </description>
- </method>
- <method name="set_syntax_coloring" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_syntax_coloring_enabled" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="add_keyword_color" >
- <argument index="0" name="keyword" type="String">
- </argument>
- <argument index="1" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_color_region" >
- <argument index="0" name="begin_key" type="String">
- </argument>
- <argument index="1" name="end_key" type="String">
- </argument>
- <argument index="2" name="color" type="Color">
- </argument>
- <argument index="3" name="line_only" type="bool" default="false">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_symbol_color" >
- <argument index="0" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_custom_bg_color" >
- <argument index="0" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear_colors" >
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="text_changed">
- <description>
- </description>
- </signal>
- <signal name="cursor_changed">
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- <constant name="SEARCH_MATCH_CASE" value="1">
- </constant>
- <constant name="SEARCH_BACKWARDS" value="4">
- </constant>
- <constant name="SEARCH_WHOLE_WORDS" value="2">
- </constant>
- </constants>
-</class>
-<class name="Texture" inherits="Resource" category="Resources">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="create" >
- <argument index="0" name="width" type="int">
- </argument>
- <argument index="1" name="height" type="int">
- </argument>
- <argument index="2" name="format" type="int">
- </argument>
- <argument index="3" name="flags" type="int" default="7">
- </argument>
- <description>
- </description>
- </method>
- <method name="create_from_image" >
- <argument index="0" name="image" type="Image">
- </argument>
- <argument index="1" name="flags" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_flags" >
- <argument index="0" name="flags" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_flags" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_format" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="load" >
- <argument index="0" name="path" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="blit_rect" >
- <argument index="0" name="x" type="int">
- </argument>
- <argument index="1" name="y" type="int">
- </argument>
- <argument index="2" name="image" type="Image">
- </argument>
- <argument index="3" name="cube_side" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_rect" qualifiers="const" >
- <return type="Image">
- </return>
- <argument index="0" name="x" type="int">
- </argument>
- <argument index="1" name="y" type="int">
- </argument>
- <argument index="2" name="width" type="int">
- </argument>
- <argument index="3" name="height" type="int">
- </argument>
- <argument index="4" name="cube_side" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_width" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_height" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_size" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- <method name="get_rid" qualifiers="const" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="has_alpha" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="draw" qualifiers="const" >
- <argument index="0" name="canvas_item" type="RID">
- </argument>
- <argument index="1" name="pos" type="Vector2">
- </argument>
- <argument index="2" name="modulate" type="Color" default="Color(1,1,1,1)">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="CUBEMAP_BACK" value="5">
- </constant>
- <constant name="CUBEMAP_FRONT" value="4">
- </constant>
- <constant name="FLAG_CUBEMAP" value="8">
- </constant>
- <constant name="CUBEMAP_TOP" value="3">
- </constant>
- <constant name="CUBEMAP_LEFT" value="0">
- </constant>
- <constant name="FLAG_FILTER" value="4">
- </constant>
- <constant name="FLAG_MIPMAPS" value="1">
- </constant>
- <constant name="CUBEMAP_BOTTOM" value="2">
- </constant>
- <constant name="FLAGS_DEFAULT" value="7">
- </constant>
- <constant name="CUBEMAP_RIGHT" value="1">
- </constant>
- <constant name="FLAG_REPEAT" value="2">
- </constant>
- </constants>
-</class>
-<class name="TextureButton" inherits="BaseButton" category="Nodes/GUI Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_normal_texture" >
- <argument index="0" name="texture" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_pressed_texture" >
- <argument index="0" name="texture" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_hover_texture" >
- <argument index="0" name="texture" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_disabled_texture" >
- <argument index="0" name="texture" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_focused_texture" >
- <argument index="0" name="texture" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_click_mask" >
- <argument index="0" name="texture" type="Image">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_normal_texture" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="get_pressed_texture" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="get_hover_texture" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="get_disabled_texture" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="get_focused_texture" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="get_click_mask" qualifiers="const" >
- <return type="Image">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="TextureFrame" inherits="Control" category="Nodes/GUI Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_texture" >
- <argument index="0" name="texture" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_texture" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="set_expand" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_expand" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Theme" inherits="Resource" category="Resources">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_icon" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <argument index="2" name="texture" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_icon" qualifiers="const" >
- <return type="Object">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_icon" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear_icon" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_icon_list" qualifiers="const" >
- <return type="StringArray">
- </return>
- <argument index="0" name="arg0" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_stylebox" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <argument index="2" name="texture" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_stylebox" qualifiers="const" >
- <return type="Object">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_stylebox" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear_stylebox" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_stylebox_list" qualifiers="const" >
- <return type="StringArray">
- </return>
- <argument index="0" name="arg0" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_font" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <argument index="2" name="font" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_font" qualifiers="const" >
- <return type="Object">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_font" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear_font" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_font_list" qualifiers="const" >
- <return type="StringArray">
- </return>
- <argument index="0" name="arg0" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_color" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <argument index="2" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_color" qualifiers="const" >
- <return type="Color">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_color" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear_color" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_color_list" qualifiers="const" >
- <return type="StringArray">
- </return>
- <argument index="0" name="arg0" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_constant" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <argument index="2" name="constant" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_constant" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_constant" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear_constant" >
- <argument index="0" name="name" type="String">
- </argument>
- <argument index="1" name="type" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_constant_list" qualifiers="const" >
- <return type="StringArray">
- </return>
- <argument index="0" name="arg0" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_type_list" qualifiers="const" >
- <return type="StringArray">
- </return>
- <argument index="0" name="arg0" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="copy_default_theme" >
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Timer" inherits="Node" category="Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_wait_time" >
- <argument index="0" name="time_sec" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_wait_time" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- <method name="set_one_shot" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_one_shot" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_autostart" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="has_autostart" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="start" >
- <description>
- </description>
- </method>
- <method name="stop" >
- <description>
- </description>
- </method>
- <method name="get_time_left" qualifiers="const" >
- <return type="real">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="timeout">
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- </constants>
-</class>
-<class name="Tree" inherits="Control" category="Nodes/GUI Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="clear" >
- <description>
- </description>
- </method>
- <method name="create_item" >
- <return type="Object">
- </return>
- <argument index="0" name="arg0" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_root" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="set_column_min_width" >
- <argument index="0" name="arg0" type="int">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_column_expand" >
- <argument index="0" name="arg0" type="int">
- </argument>
- <argument index="1" name="arg1" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_column_width" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_hide_root" >
- <argument index="0" name="arg0" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_next_selected" >
- <return type="Object">
- </return>
- <argument index="0" name="arg0" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_selected" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="get_selected_column" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_pressed_button" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="set_select_mode" >
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_columns" >
- <argument index="0" name="amount" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_columns" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_edited" qualifiers="const" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="get_edited_column" qualifiers="const" >
- <return type="int">
- </return>
- <description>
- </description>
- </method>
- <method name="get_custom_popup_rect" qualifiers="const" >
- <return type="Rect2">
- </return>
- <description>
- </description>
- </method>
- <method name="get_item_rect" qualifiers="const" >
- <return type="Rect2">
- </return>
- <argument index="0" name="item" type="Object">
- </argument>
- <argument index="1" name="column" type="int" default="-1">
- </argument>
- <description>
- </description>
- </method>
- <method name="ensure_cursor_is_visible" >
- <description>
- </description>
- </method>
- <method name="set_column_titles_visible" >
- <argument index="0" name="visible" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="are_column_titles_visible" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_column_title" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="title" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_column_title" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_scroll" qualifiers="const" >
- <return type="Vector2">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <signals>
- <signal name="multi_selected">
- <description>
- </description>
- </signal>
- <signal name="custom_popup_edited">
- <argument index="0" name="arrow_clicked" type="bool">
- </argument>
- <description>
- </description>
- </signal>
- <signal name="item_edited">
- <description>
- </description>
- </signal>
- <signal name="item_selected">
- <description>
- </description>
- </signal>
- <signal name="item_doubleclicked">
- <description>
- </description>
- </signal>
- <signal name="cell_selected">
- <description>
- </description>
- </signal>
- <signal name="button_pressed">
- <argument index="0" name="item" type="Object">
- </argument>
- <argument index="1" name="column" type="int">
- </argument>
- <argument index="2" name="id" type="int">
- </argument>
- <description>
- </description>
- </signal>
- </signals>
- <constants>
- <constant name="SELECT_ROW" value="1">
- </constant>
- <constant name="SELECT_SINGLE" value="0">
- </constant>
- <constant name="SELECT_MULTI" value="2">
- </constant>
- </constants>
-</class>
-<class name="TreeItem" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_cell_mode" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_cell_mode" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_checked" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="checked" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_checked" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_text" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="text" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_text" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_icon" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="texture" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_icon" qualifiers="const" >
- <return type="Object">
- </return>
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_range" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="value" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_range" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_range_config" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="min" type="real">
- </argument>
- <argument index="2" name="max" type="real">
- </argument>
- <argument index="3" name="step" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_range_config" >
- <return type="Dictionary">
- </return>
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_metadata" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="meta" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_metadata" qualifiers="const" >
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_collapsed" >
- <argument index="0" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_collapsed" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="get_next" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="get_prev" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="get_parent" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="get_children" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="get_next_visible" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="get_prev_visible" >
- <return type="Object">
- </return>
- <description>
- </description>
- </method>
- <method name="remove_child" >
- <argument index="0" name="child" type="Object">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_selectable" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="selectable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_selected" >
- <return type="bool">
- </return>
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="select" >
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="deselect" >
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_editable" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="enabled" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_editable" >
- <return type="bool">
- </return>
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_custom_color" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear_custom_color" >
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_custom_bg_color" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="color" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="clear_custom_bg_color" >
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="add_button" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="button" type="Object">
- </argument>
- <argument index="2" name="arg2" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_button_count" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="column" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_button" qualifiers="const" >
- <return type="Object">
- </return>
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="button_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="erase_button" >
- <argument index="0" name="column" type="int">
- </argument>
- <argument index="1" name="button_idx" type="int">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="CELL_MODE_ICON" value="3">
- </constant>
- <constant name="CELL_MODE_CUSTOM" value="4">
- </constant>
- <constant name="CELL_MODE_RANGE" value="2">
- </constant>
- <constant name="CELL_MODE_CHECK" value="1">
- </constant>
- <constant name="CELL_MODE_STRING" value="0">
- </constant>
- </constants>
-</class>
-<class name="VScrollBar" inherits="ScrollBar" category="Nodes/GUI Nodes">
- <brief_description>
- Vertical version of [ScrollBar], which goes from left (min) to right (max).
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="VSeparator" inherits="Separator" category="Nodes/GUI Nodes">
- <brief_description>
- Vertical version of [Separator].
- </brief_description>
- <description>
- Vertical version of [Separator]. It is used to separate objects horizontally, though (but it looks vertical!).
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="VSlider" inherits="Slider" category="Nodes/GUI Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="Viewport" inherits="Node" category="Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="set_rect" >
- <argument index="0" name="rect" type="Rect2">
- </argument>
- <description>
- </description>
- </method>
- <method name="get_rect" qualifiers="const" >
- <return type="Rect2">
- </return>
- <description>
- </description>
- </method>
- <method name="get_visible_rect" qualifiers="const" >
- <return type="Rect2">
- </return>
- <description>
- </description>
- </method>
- <method name="get_viewport" qualifiers="const" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="VisualInstance" inherits="Spatial" category="Nodes/3D/3D Visual Nodes">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="override_material_param" >
- <argument index="0" name="param" type="String">
- </argument>
- <argument index="1" name="value" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="set_visible" >
- <argument index="0" name="visible" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="is_visible" qualifiers="const" >
- <return type="bool">
- </return>
- <description>
- </description>
- </method>
- <method name="set_base" >
- <argument index="0" name="base" type="RID">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- </constants>
-</class>
-<class name="VisualServer" inherits="Object" category="Core">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- <method name="texture_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="texture_create_from_image" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="Image">
- </argument>
- <argument index="1" name="arg1" type="int" default="7">
- </argument>
- <description>
- </description>
- </method>
- <method name="texture_allocate" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="int">
- </argument>
- <argument index="3" name="arg3" type="int">
- </argument>
- <argument index="4" name="arg4" type="int" default="7">
- </argument>
- <description>
- </description>
- </method>
- <method name="texture_blit_rect" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="int">
- </argument>
- <argument index="3" name="arg3" type="Image">
- </argument>
- <argument index="4" name="arg4" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="texture_set_flags" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="texture_get_flags" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="texture_get_width" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="texture_get_height" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="shader_create" >
- <return type="RID">
- </return>
- <argument index="0" name="mode" type="int" default="0">
- </argument>
- <description>
- </description>
- </method>
- <method name="shader_set_mode" >
- <argument index="0" name="shader" type="RID">
- </argument>
- <argument index="1" name="mode" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="shader_get_mode" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="shader" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="shader_set_vertex_code" >
- <argument index="0" name="shader" type="RID">
- </argument>
- <argument index="1" name="code" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="shader_get_vertex_code" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="shader" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="shader_set_fragment_code" >
- <argument index="0" name="shader" type="RID">
- </argument>
- <argument index="1" name="code" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="shader_get_fragment_code" qualifiers="const" >
- <return type="String">
- </return>
- <argument index="0" name="shader" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="shader_set_param" >
- <argument index="0" name="shader" type="RID">
- </argument>
- <argument index="1" name="param" type="String">
- </argument>
- <argument index="2" name="value" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="shader_get_param" qualifiers="const" >
- <argument index="0" name="shader" type="RID">
- </argument>
- <argument index="1" name="param" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="shader_get_param_list" qualifiers="const" >
- <return type="StringArray">
- </return>
- <argument index="0" name="shader" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="shader_set_use_world_transform" >
- <argument index="0" name="shader" type="RID">
- </argument>
- <argument index="1" name="enable" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="shader_is_using_world_transform" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="shader" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="material_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="material_set_shader" >
- <argument index="0" name="shader" type="RID">
- </argument>
- <argument index="1" name="arg1" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="material_get_shader" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="material_set_param" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="String">
- </argument>
- <argument index="2" name="arg2" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="material_get_param" qualifiers="const" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="material_set_flag" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="material_get_flag" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="material_set_blend_mode" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="material_get_blend_mode" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="material_set_line_width" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="material_get_line_width" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="fixed_material_set_parameter" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="fixed_material_get_parameter" qualifiers="const" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="fixed_material_set_texture" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="fixed_material_get_texture" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="fixed_material_set_texgen_mode" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="fixed_material_get_texgen_mode" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="fixed_material_set_texcoord_mode" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="fixed_material_get_texcoord_mode" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="fixed_material_set_uv_transform" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="fixed_material_get_uv_transform" qualifiers="const" >
- <return type="Transform">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="mesh_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="mesh_surface_set_array" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="int">
- </argument>
- <argument index="3" name="arg3" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="mesh_surface_get_array" qualifiers="const" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="mesh_surface_set_material" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="RID">
- </argument>
- <argument index="3" name="arg3" type="bool" default="false">
- </argument>
- <description>
- </description>
- </method>
- <method name="mesh_surface_get_material" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="mesh_surface_get_array_len" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="mesh_surface_get_array_index_len" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="mesh_surface_get_format" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="mesh_surface_get_primitive_type" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="mesh_erase_surface" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="mesh_get_surface_count" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="multimesh_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="multimesh_set_mesh" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="multimesh_set_aabb" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="AABB">
- </argument>
- <description>
- </description>
- </method>
- <method name="multimesh_instance_set_transform" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="multimesh_instance_set_color" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="multimesh_get_mesh" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="multimesh_get_aabb" qualifiers="const" >
- <return type="AABB">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="AABB">
- </argument>
- <description>
- </description>
- </method>
- <method name="multimesh_instance_get_transform" qualifiers="const" >
- <return type="Transform">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="multimesh_instance_get_color" qualifiers="const" >
- <return type="Color">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="poly_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="poly_set_material" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="RID">
- </argument>
- <argument index="2" name="arg2" type="bool" default="false">
- </argument>
- <description>
- </description>
- </method>
- <method name="poly_add_primitive" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Vector3Array">
- </argument>
- <argument index="2" name="arg2" type="Vector3Array">
- </argument>
- <argument index="3" name="arg3" type="ColorArray">
- </argument>
- <argument index="4" name="arg4" type="Vector3Array">
- </argument>
- <description>
- </description>
- </method>
- <method name="poly_clear" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="particles_set_amount" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_get_amount" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_set_emitting" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_is_emitting" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_set_visibility_aabb" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="AABB">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_get_visibility_aabb" qualifiers="const" >
- <return type="AABB">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_set_variable" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_get_variable" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_set_randomness" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_get_randomness" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_set_color_phases" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_get_color_phases" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_set_color_phase_pos" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_get_color_phase_pos" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_set_color_phase_color" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_get_color_phase_color" qualifiers="const" >
- <return type="Color">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_set_attractors" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_get_attractors" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_set_attractor_pos" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="Vector3">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_get_attractor_pos" qualifiers="const" >
- <return type="Vector3">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_set_attractor_strength" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_get_attractor_strength" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_set_material" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="RID">
- </argument>
- <argument index="2" name="arg2" type="bool" default="false">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_set_height_from_velocity" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="particles_has_height_from_velocity" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="light_create" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="light_get_type" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="light_set_color" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="light_get_color" qualifiers="const" >
- <return type="Color">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="light_set_shadow" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="light_has_shadow" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="light_set_volumetric" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="light_is_volumetric" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="light_set_projector" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="light_get_projector" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="light_set_var" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="light_get_var" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="skeleton_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="skeleton_resize" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="skeleton_get_bone_count" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="skeleton_bone_set_transform" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="skeleton_bone_get_transform" >
- <return type="Transform">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="room_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="room_set_bounds" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Dictionary">
- </argument>
- <description>
- </description>
- </method>
- <method name="room_get_bounds" qualifiers="const" >
- <return type="Dictionary">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="portal_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="portal_set_shape" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Array">
- </argument>
- <description>
- </description>
- </method>
- <method name="portal_get_shape" qualifiers="const" >
- <return type="Array">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="portal_set_enabled" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="portal_is_enabled" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="portal_set_disable_distance" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="portal_get_disable_distance" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="portal_set_disabled_color" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="portal_get_disabled_color" qualifiers="const" >
- <return type="Color">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="camera_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="camera_set_perspective" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="real">
- </argument>
- <argument index="2" name="arg2" type="real">
- </argument>
- <argument index="3" name="arg3" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="camera_set_orthogonal" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="real">
- </argument>
- <argument index="2" name="arg2" type="real">
- </argument>
- <argument index="3" name="arg3" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="camera_set_transform" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="viewport_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="viewport_set_rect" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Rect2">
- </argument>
- <description>
- </description>
- </method>
- <method name="viewport_get_rect" qualifiers="const" >
- <return type="Rect2">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="viewport_attach_camera" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="RID" default="RID()">
- </argument>
- <description>
- </description>
- </method>
- <method name="viewport_get_attached_camera" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="viewport_get_scenario" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="viewport_attach_canvas" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="viewport_remove_canvas" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="viewport_move_canvas_to_top" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="viewport_move_canvas_to_bottom" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="scenario_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="scenario_set_debug" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="scenario_fx_get_effects" qualifiers="const" >
- <return type="StringArray">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="scenario_fx_set_active" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="String">
- </argument>
- <argument index="2" name="arg2" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="scenario_fx_is_active" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="scenario_fx_get_effect_params" qualifiers="const" >
- <return type="Array">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="scenario_fx_get_effect_param" qualifiers="const" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="String">
- </argument>
- <argument index="2" name="arg2" type="String">
- </argument>
- <description>
- </description>
- </method>
- <method name="scenario_fx_set_effect_param" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="String">
- </argument>
- <argument index="2" name="arg2" type="String">
- </argument>
- <argument index="3" name="arg3" type="var">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="instance_get_base" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_get_base_aabb" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_set_transform" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Transform">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_get_transform" qualifiers="const" >
- <return type="Transform">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_attach_object_instance_ID" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_get_object_instance_ID" qualifiers="const" >
- <return type="int">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_attach_skeleton" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_get_skeleton" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_set_room" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_get_room" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_set_exterior" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_is_exterior" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instances_cull_aabb" qualifiers="const" >
- <return type="Array">
- </return>
- <argument index="0" name="arg0" type="AABB">
- </argument>
- <argument index="1" name="arg1" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instances_cull_ray" qualifiers="const" >
- <return type="Array">
- </return>
- <argument index="0" name="arg0" type="Vector3">
- </argument>
- <argument index="1" name="arg1" type="Vector3">
- </argument>
- <argument index="2" name="arg2" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instances_cull_convex" qualifiers="const" >
- <return type="Array">
- </return>
- <argument index="0" name="arg0" type="Vector3">
- </argument>
- <argument index="1" name="arg1" type="Vector3">
- </argument>
- <argument index="2" name="arg2" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_geometry_set_visible" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_geometry_is_visible" qualifiers="const" >
- <return type="bool">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_geometry_override_material_param" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="instance_geometry_get_material_param" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="canvas_item_create" >
- <return type="RID">
- </return>
- <description>
- </description>
- </method>
- <method name="canvas_item_set_parent" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_get_parent" qualifiers="const" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_set_custom_rect" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="bool">
- </argument>
- <argument index="2" name="arg2" type="Rect2">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_set_clip" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="bool">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_set_opacity" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_get_opacity" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_set_self_opacity" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_get_self_opacity" qualifiers="const" >
- <return type="real">
- </return>
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_add_line" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Vector2">
- </argument>
- <argument index="2" name="arg2" type="Vector2">
- </argument>
- <argument index="3" name="arg3" type="Color">
- </argument>
- <argument index="4" name="arg4" type="real" default="1">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_add_rect" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Rect2">
- </argument>
- <argument index="2" name="arg2" type="Color">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_add_texture_rect" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Rect2">
- </argument>
- <argument index="2" name="arg2" type="RID">
- </argument>
- <argument index="3" name="arg3" type="bool">
- </argument>
- <argument index="4" name="arg4" type="Color" default="Color(1,1,1,1)">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_add_texture_rect_region" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Rect2">
- </argument>
- <argument index="2" name="arg2" type="RID">
- </argument>
- <argument index="3" name="arg3" type="Rect2">
- </argument>
- <argument index="4" name="arg4" type="Color" default="Color(1,1,1,1)">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_add_style_box" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Rect2">
- </argument>
- <argument index="2" name="arg2" type="RID">
- </argument>
- <argument index="3" name="arg3" type="RealArray">
- </argument>
- <argument index="4" name="arg4" type="Color" default="Color(1,1,1,1)">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_add_primitive" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Array">
- </argument>
- <argument index="2" name="arg2" type="ColorArray">
- </argument>
- <argument index="3" name="arg3" type="Array" default="Array()">
- </argument>
- <argument index="4" name="arg4" type="RID" default="RID()">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_clear" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="canvas_item_raise" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- <method name="cursor_set_rotation" >
- <argument index="0" name="arg0" type="real">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="cursor_set_texture" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Vector2">
- </argument>
- <argument index="2" name="arg2" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="cursor_set_visible" >
- <argument index="0" name="arg0" type="bool">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="cursor_set_pos" >
- <argument index="0" name="arg0" type="Vector2">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <description>
- </description>
- </method>
- <method name="make_sphere_mesh" >
- <return type="RID">
- </return>
- <argument index="0" name="arg0" type="int">
- </argument>
- <argument index="1" name="arg1" type="int">
- </argument>
- <argument index="2" name="arg2" type="real">
- </argument>
- <description>
- </description>
- </method>
- <method name="mesh_add_surface_from_planes" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <argument index="1" name="arg1" type="Array">
- </argument>
- <description>
- </description>
- </method>
- <method name="free" >
- <argument index="0" name="arg0" type="RID">
- </argument>
- <description>
- </description>
- </method>
- </methods>
- <constants>
- <constant name="INSTANCE_GEOMETRY_MASK" value="30">
- </constant>
- <constant name="INSTANCE_PARTICLES" value="4">
- </constant>
- <constant name="SCENARIO_DEBUG_WIREFRAME" value="1">
- </constant>
- <constant name="LIGHT_VAR_ATTENUATION" value="4">
- </constant>
- <constant name="LIGHT_VAR_SPOT_ANGLE" value="1">
- </constant>
- <constant name="LIGHT_COLOR_DIFFUSE" value="1">
- </constant>
- <constant name="PARTICLE_ANGULAR_VELOCITY" value="4">
- </constant>
- <constant name="INSTANCE_LIGHT" value="5">
- </constant>
- <constant name="INSTANCE_MULTIMESH" value="2">
- </constant>
- <constant name="PARTICLE_HEIGHT" value="11">
- </constant>
- <constant name="PARTICLE_LINEAR_VELOCITY" value="3">
- </constant>
- <constant name="FIXED_MATERIAL_PARAM_SPECULAR" value="2">
- </constant>
- <constant name="ARRAY_VERTEX" value="0">
- </constant>
- <constant name="LIGHT_SPOT" value="2">
- </constant>
- <constant name="CUBEMAP_BACK" value="5">
- </constant>
- <constant name="MATERIAL_FLAG_MAX" value="7">
- </constant>
- <constant name="FIXED_MATERIAL_PARAM_DETAIL_MIX" value="6">
- </constant>
- <constant name="ARRAY_COLOR" value="3">
- </constant>
- <constant name="ARRAY_FORMAT_BONES" value="64">
- </constant>
- <constant name="PRIMITIVE_MAX" value="7">
- </constant>
- <constant name="FIXED_MATERIAL_TEXGEN_SPHERE" value="1">
- </constant>
- <constant name="ARRAY_FORMAT_INDEX" value="256">
- </constant>
- <constant name="PRIMITIVE_TRIANGLE_STRIP" value="5">
- </constant>
- <constant name="MAX_PARTICLE_ATTRACTORS" value="4">
- </constant>
- <constant name="TEXTURE_FLAG_FILTER" value="4">
- </constant>
- <constant name="CUBEMAP_TOP" value="3">
- </constant>
- <constant name="MATERIAL_BLEND_MODE_ADD" value="1">
- </constant>
- <constant name="FIXED_MATERIAL_TEXCOORD_TEXGEN" value="3">
- </constant>
- <constant name="FIXED_MATERIAL_TEXCOORD_UV" value="0">
- </constant>
- <constant name="ARRAY_TANGENT" value="2">
- </constant>
- <constant name="ARRAY_FORMAT_NORMAL" value="2">
- </constant>
- <constant name="INFO_VIDEO_MEM_USED" value="3">
- </constant>
- <constant name="LIGHT_VAR_SPOT_ATTENUATION" value="0">
- </constant>
- <constant name="TEXTURE_FLAG_MIPMAPS" value="1">
- </constant>
- <constant name="MATERIAL_FLAG_INVERT_FACES" value="2">
- </constant>
- <constant name="MATERIAL_BLEND_MODE_SUB" value="2">
- </constant>
- <constant name="FIXED_MATERIAL_PARAM_DETAIL" value="1">
- </constant>
- <constant name="INSTANCE_ROOM" value="6">
- </constant>
- <constant name="INSTANCE_MESH" value="1">
- </constant>
- <constant name="SCENARIO_DEBUG_DISABLED" value="0">
- </constant>
- <constant name="PARTICLE_VAR_MAX" value="13">
- </constant>
- <constant name="PRIMITIVE_TRIANGLES" value="4">
- </constant>
- <constant name="PRIMITIVE_LINE_STRIP" value="2">
- </constant>
- <constant name="TEXTURE_FLAGS_DEFAULT" value="7">
- </constant>
- <constant name="CUBEMAP_BOTTOM" value="2">
- </constant>
- <constant name="FIXED_MATERIAL_TEXGEN_SCREENZ" value="3">
- </constant>
- <constant name="FIXED_MATERIAL_TEXCOORD_UV2" value="2">
- </constant>
- <constant name="ARRAY_FORMAT_TEX_UV" value="16">
- </constant>
- <constant name="ARRAY_FORMAT_WEIGHTS" value="128">
- </constant>
- <constant name="INFO_MATERIAL_CHANGES_IN_FRAME" value="1">
- </constant>
- <constant name="PARTICLE_SPREAD" value="1">
- </constant>
- <constant name="PARTICLE_LIFETIME" value="0">
- </constant>
- <constant name="PRIMITIVE_TRIANGLE_FAN" value="6">
- </constant>
- <constant name="NO_INDEX_ARRAY" value="-1">
- </constant>
- <constant name="MATERIAL_FLAG_BILLBOARD" value="6">
- </constant>
- <constant name="FIXED_MATERIAL_TEXGEN_LOCAL_XY" value="0">
- </constant>
- <constant name="SCENARIO_DEBUG_OVERDRAW" value="2">
- </constant>
- <constant name="PARTICLE_HEIGHT_SPEED_SCALE" value="12">
- </constant>
- <constant name="PARTICLE_INITIAL_ANGLE" value="10">
- </constant>
- <constant name="PARTICLE_TANGENTIAL_ACCELERATION" value="7">
- </constant>
- <constant name="PRIMITIVE_LINES" value="1">
- </constant>
- <constant name="CUSTOM_ARRAY_SIZE" value="8">
- </constant>
- <constant name="ARRAY_WEIGHTS_SIZE" value="4">
- </constant>
- <constant name="MATERIAL_FLAG_UNSHADED" value="3">
- </constant>
- <constant name="FIXED_MATERIAL_PARAM_DIFFUSE" value="0">
- </constant>
- <constant name="FIXED_MATERIAL_PARAM_MAX" value="9">
- </constant>
- <constant name="LIGHT_COLOR_SPECULAR" value="2">
- </constant>
- <constant name="MATERIAL_BLEND_MODE_MIX" value="0">
- </constant>
- <constant name="MATERIAL_BLEND_MODE_MUL" value="3">
- </constant>
- <constant name="FIXED_MATERIAL_PARAM_EMISSION" value="3">
- </constant>
- <constant name="ARRAY_MAX" value="9">
- </constant>
- <constant name="ARRAY_FORMAT_VERTEX" value="1">
- </constant>
- <constant name="INFO_OBJECTS_IN_FRAME" value="0">
- </constant>
- <constant name="LIGHT_VAR_MAX" value="6">
- </constant>
- <constant name="LIGHT_COLOR_AMBIENT" value="0">
- </constant>
- <constant name="LIGHT_DIRECTIONAL" value="0">
- </constant>
- <constant name="PRIMITIVE_POINTS" value="0">
- </constant>
- <constant name="CUBEMAP_FRONT" value="4">
- </constant>
- <constant name="SHADER_MATERIAL" value="0">
- </constant>
- <constant name="MATERIAL_FLAG_VISIBLE" value="0">
- </constant>
- <constant name="ARRAY_BONES" value="6">
- </constant>
- <constant name="ARRAY_FORMAT_COLOR" value="8">
- </constant>
- <constant name="INSTANCE_PORTAL" value="7">
- </constant>
- <constant name="MAX_CURSORS" value="8">
- </constant>
- <constant name="TEXTURE_FLAG_CUBEMAP" value="8">
- </constant>
- <constant name="FIXED_MATERIAL_PARAM_GLOW" value="5">
- </constant>
- <constant name="FIXED_MATERIAL_PARAM_NORMAL" value="7">
- </constant>
- <constant name="ARRAY_INDEX" value="8">
- </constant>
- <constant name="INFO_VERTEX_MEM_USED" value="5">
- </constant>
- <constant name="INFO_USAGE_VIDEO_MEM_TOTAL" value="2">
- </constant>
- <constant name="LIGHT_VAR_RADIUS" value="2">
- </constant>
- <constant name="PARTICLE_FINAL_SIZE" value="9">
- </constant>
- <constant name="PARTICLE_INITIAL_SIZE" value="8">
- </constant>
- <constant name="PARTICLE_LINEAR_ACCELERATION" value="5">
- </constant>
- <constant name="CUBEMAP_LEFT" value="0">
- </constant>
- <constant name="MATERIAL_FLAG_ONTOP" value="4">
- </constant>
- <constant name="FIXED_MATERIAL_TEXGEN_SCREEN" value="2">
- </constant>
- <constant name="ARRAY_NORMAL" value="1">
- </constant>
- <constant name="ARRAY_FORMAT_TANGENT" value="4">
- </constant>
- <constant name="INSTANCE_POLY" value="3">
- </constant>
- <constant name="FIXED_MATERIAL_PARAM_SPECULAR_EXP" value="4">
- </constant>
- <constant name="LIGHT_VAR_ENERGY" value="3">
- </constant>
- <constant name="PARTICLE_RADIAL_ACCELERATION" value="6">
- </constant>
- <constant name="PARTICLE_GRAVITY" value="2">
- </constant>
- <constant name="PRIMITIVE_LINE_LOOP" value="3">
- </constant>
- <constant name="MATERIAL_FLAG_WIREFRAME" value="5">
- </constant>
- <constant name="ARRAY_TEX_UV" value="4">
- </constant>
- <constant name="ARRAY_WEIGHTS" value="7">
- </constant>
- <constant name="INFO_TEXTURE_MEM_USED" value="4">
- </constant>
- <constant name="LIGHT_OMNI" value="1">
- </constant>
- <constant name="MAX_PARTICLE_COLOR_PHASES" value="4">
- </constant>
- <constant name="TEXTURE_FLAG_REPEAT" value="2">
- </constant>
- <constant name="CUBEMAP_RIGHT" value="1">
- </constant>
- <constant name="SHADER_POST_PROCESS" value="1">
- </constant>
- <constant name="MATERIAL_FLAG_DOUBLE_SIDED" value="1">
- </constant>
- <constant name="FIXED_MATERIAL_TEXCOORD_UV_TRANSFORM" value="1">
- </constant>
- </constants>
-</class>
-<class name="World" inherits="Resource" category="Resources">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
-</doc>
diff --git a/tools/docdump/doc_dump.cpp b/tools/docdump/doc_dump.cpp
index 17aff3dc74..f8e035e3fa 100644
--- a/tools/docdump/doc_dump.cpp
+++ b/tools/docdump/doc_dump.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -76,10 +76,10 @@ static String _escape_string(const String& p_str) {
void DocDump::dump(const String& p_file) {
- List<String> class_list;
+ List<StringName> class_list;
ObjectTypeDB::get_type_list(&class_list);
- class_list.sort();
+ class_list.sort_custom<StringName::AlphCompare>();
FileAccess *f = FileAccess::open(p_file,FileAccess::WRITE);
diff --git a/tools/docdump/doc_dump.h b/tools/docdump/doc_dump.h
index cb18289e31..372f5e0969 100644
--- a/tools/docdump/doc_dump.h
+++ b/tools/docdump/doc_dump.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/docdump/doc_merge.py b/tools/docdump/doc_merge.py
deleted file mode 100644
index 872f38ed87..0000000000
--- a/tools/docdump/doc_merge.py
+++ /dev/null
@@ -1,208 +0,0 @@
-import sys
-import xml.etree.ElementTree as ET
-
-
-tree = ET.parse(sys.argv[1])
-old_doc=tree.getroot()
-
-tree = ET.parse(sys.argv[2])
-new_doc=tree.getroot()
-
-f = file(sys.argv[3],"wb")
-tab=0
-
-old_classes={}
-
-def write_string(_f, text,newline=True):
- for t in range(tab):
- _f.write("\t")
- _f.write(text)
- if (newline):
- _f.write("\n")
-
-def escape(ret):
- ret=ret.replace("&","&amp;");
- ret=ret.replace("<","&gt;");
- ret=ret.replace(">","&lt;");
- ret=ret.replace("'","&apos;");
- ret=ret.replace("\"","&quot;");
- return ret
-
-
-def inc_tab():
- global tab
- tab+=1
-
-def dec_tab():
- global tab
- tab-=1
-
-write_string(f,'<?xml version="1.0" encoding="UTF-8" ?>')
-write_string(f,'<doc version="'+new_doc.attrib["version"]+'">')
-
-def get_tag(node,name):
- tag=""
- if (name in node.attrib):
- tag=' '+name+'="'+escape(node.attrib[name])+'" '
- return tag
-
-def find_method_descr(old_class,name):
-
- methods = old_class.find("methods")
- if(methods!=None and len(list(methods))>0):
- for m in list(methods):
- if (m.attrib["name"]==name):
- description=m.find("description")
- if (description!=None and description.text.strip()!=""):
- return description.text
-
- return None
-
-def find_signal_descr(old_class,name):
-
- signals = old_class.find("signals")
- if(signals!=None and len(list(signals))>0):
- for m in list(signals):
- if (m.attrib["name"]==name):
- description=m.find("description")
- if (description!=None and description.text.strip()!=""):
- return description.text
-
- return None
-
-def find_constant_descr(old_class,name):
-
- if (old_class==None):
- return None
- constants = old_class.find("constants")
- if(constants!=None and len(list(constants))>0):
- for m in list(constants):
- if (m.attrib["name"]==name):
- if (m.text.strip()!=""):
- return m.text
- return None
-
-def write_class(c):
- class_name = c.attrib["name"]
- print("Parsing Class: "+class_name)
- if (class_name in old_classes):
- old_class=old_classes[class_name]
- else:
- old_class=None
-
-
- category=get_tag(c,"category")
- inherits=get_tag(c,"inherits")
- write_string(f,'<class name="'+class_name+'" '+category+inherits+'>')
- inc_tab()
-
- write_string(f,"<brief_description>")
-
- if (old_class!=None):
- old_brief_descr=old_class.find("brief_description")
- if (old_brief_descr!=None):
- write_string(f,escape(old_brief_descr.text.strip()))
-
-
- write_string(f,"</brief_description>")
-
- write_string(f,"<description>")
- if (old_class!=None):
- old_descr=old_class.find("description")
- if (old_descr!=None):
- write_string(f,escape(old_descr.text.strip()))
-
- write_string(f,"</description>")
-
- methods = c.find("methods")
- if(methods!=None and len(list(methods))>0):
-
- write_string(f,"<methods>")
- inc_tab()
-
- for m in list(methods):
- qualifiers=get_tag(m,"qualifiers")
-
- write_string(f,'<method name="'+escape(m.attrib["name"])+'" ' +qualifiers+'>')
- inc_tab()
-
- for a in list(m):
- if (a.tag=="return"):
- typ=get_tag(a,"type")
- write_string(f,'<return'+typ+'>');
- write_string(f,'</return>');
- elif (a.tag=="argument"):
-
- default=get_tag(a,"default")
-
- write_string(f,'<argument index="'+a.attrib["index"]+'" name="'+escape(a.attrib["name"])+'" type="'+a.attrib["type"]+'"' +default+'>');
- write_string(f,'</argument>');
-
- write_string(f,'<description>');
- if (old_class!=None):
- old_method_descr=find_method_descr(old_class,m.attrib["name"])
- if (old_method_descr):
- write_string(f,escape(escape(old_method_descr.strip())))
-
- write_string(f,'</description>');
- dec_tab()
- write_string(f,"</method>")
- dec_tab()
- write_string(f,"</methods>")
-
- signals = c.find("signals")
- if(signals!=None and len(list(signals))>0):
-
- write_string(f,"<signals>")
- inc_tab()
-
- for m in list(signals):
-
- write_string(f,'<signal name="'+escape(m.attrib["name"])+'">')
- inc_tab()
-
- for a in list(m):
- if (a.tag=="argument"):
-
- write_string(f,'<argument index="'+a.attrib["index"]+'" name="'+escape(a.attrib["name"])+'" type="'+a.attrib["type"]+'">');
- write_string(f,'</argument>');
-
- write_string(f,'<description>');
- if (old_class!=None):
- old_signal_descr=find_signal_descr(old_class,m.attrib["name"])
- if (old_signal_descr):
- write_string(f,escape(old_signal_descr.strip()))
- write_string(f,'</description>');
- dec_tab()
- write_string(f,"</signal>")
- dec_tab()
- write_string(f,"</signals>")
-
- constants = c.find("constants")
- if(constants!=None and len(list(constants))>0):
-
- write_string(f,"<constants>")
- inc_tab()
-
- for m in list(constants):
-
- write_string(f,'<constant name="'+escape(m.attrib["name"])+'" value="'+m.attrib["value"]+'">')
- old_constant_descr=find_constant_descr(old_class,m.attrib["name"])
- if (old_constant_descr):
- write_string(f,escape(old_constant_descr.strip()))
- write_string(f,"</constant>")
-
- dec_tab()
- write_string(f,"</constants>")
-
- dec_tab()
- write_string(f,"</class>")
-
-for c in list(old_doc):
- old_classes[c.attrib["name"]]=c
-
-for c in list(new_doc):
- write_class(c)
-write_string(f,'</doc>\n')
-
-
diff --git a/tools/docdump/main.css b/tools/docdump/main.css
deleted file mode 100644
index a76e6bbed8..0000000000
--- a/tools/docdump/main.css
+++ /dev/null
@@ -1,146 +0,0 @@
-BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV, SPAN {
- font-family: Arial, Geneva, Helvetica, sans-serif;
-}
-
-a {
-
- text-decoration: none;
-
-}
-
-a:hover {
-
- text-decoration: underline;
-}
-
-td.top_table {
-
- padding: 5px;
-}
-
-div.method_doc {
-
- padding-bottom: 30px;
-}
-
-div.method_description {
- margin-left: 30px;
-}
-
-list.inh_class_list {
- margin-left: 30px;
-
-}
-
-div.inh_class_list {
- margin-left: 30px;
-
-}
-
-div.method_doc div.method {
-
- font-size: 12pt;
- font-weight: bold;
-}
-
-span.funcdecl {
-
- color: #202060;
-}
-
-span.funcdef {
-
- color: #202060;
-}
-
-
-span.qualifier {
-
- font-weight: bold;
-}
-
-
-span.symbol {
-
- /*font-weight: bold;*/
- color: #471870;
-}
-
-
-span.datatype {
-
- color: #6a1533;
-}
-
-tr.category_title {
-
- background-color: #333333;
-}
-a.category_title {
- font-weight: bold;
- color: #FFFFFF;
-}
-
-div.method_list {
-
- margin-left: 30px;
-}
-
-div.constant_list {
-
- margin-left: 30px;
-}
-
-div.member_list {
-
- margin-left: 30px;
-}
-
-div.description {
-
- margin-left: 30px;
-}
-
-div.class_description {
-
- margin-left: 30px;
-}
-
-div.method_list li div {
-
- display: inline;
-}
-
-div.member_list li div.member {
-
- display: inline;
-}
-
-div.constant_list li div.constant {
-
- display: inline;
-}
-
-span.member_description {
-
- font-style: italic;
- color: grey;
-}
-
-span.constant_description {
-
- font-style: italic;
- color: grey;
-}
-
-span.identifier {
-
- font-weight: bold;
-}
-
-
-table.class_table td {
-
- vertical-align: top;
-}
-
diff --git a/tools/docdump/makedoku.py b/tools/docdump/makedoku.py
deleted file mode 100644
index e8207715fe..0000000000
--- a/tools/docdump/makedoku.py
+++ /dev/null
@@ -1,511 +0,0 @@
-import sys
-import xml.etree.ElementTree as ET
-
-input_list = []
-
-
-for arg in sys.argv[1:]:
- input_list.append(arg)
-
-if len(input_list) < 1:
- print("usage: makedoku.py <class_list.xml>")
- sys.exit(0)
-
-
-def validate_tag(elem,tag):
- if (elem.tag != tag):
- print("Tag mismatch, expected '"+tag+"', got "+elem.tag);
- sys.exit(255)
-
-
-class_names=[]
-classes={}
-
-
-def make_class_list(class_list,columns):
-
- f=open("class_list.txt","wb")
- prev=0
- col_max = len(class_list) / columns + 1
- print("col max is ", col_max)
- col_count = 0
- row_count = 0
- last_initial = ""
- fit_columns=[]
-
- for n in range(0,columns):
- fit_columns+=[[]]
-
- indexers=[]
- last_initial=""
-
- idx=0
- for n in class_list:
- col = idx/col_max
- if (col>=columns):
- col=columns-1
- fit_columns[col]+=[n]
- idx+=1
- if (n[:1]!=last_initial):
- indexers+=[n]
- last_initial=n[:1]
-
-
- row_max=0
-
- for n in range(0,columns):
- if (len(fit_columns[n])>row_max):
- row_max=len(fit_columns[n])
-
-
- for r in range(0,row_max):
- s="|"
- for c in range(0,columns):
- if (r>=len(fit_columns[c])):
- continue
-
- classname = fit_columns[c][r]
- initial=classname[0]
- if (classname in indexers):
- s+="**"+initial+"**|"
- else:
- s+=" |"
-
- s+="[["+classname.lower()+"|"+classname+"]]|"
-
- s+="\n"
- f.write(s)
-
-
-def dokuize_text(txt):
-
- return txt
-
-
-def dokuize_text(text):
- pos=0
- while(True):
- pos = text.find("[",pos)
- if (pos==-1):
- break
-
- endq_pos=text.find("]",pos+1)
- if (endq_pos==-1):
- break
-
- pre_text=text[:pos]
- post_text=text[endq_pos+1:]
- tag_text=text[pos+1:endq_pos]
-
- if (tag_text in class_names):
- tag_text="[["+tag_text.lower()+"|"+tag_text+"]]"
- else: #command
- cmd=tag_text
- space_pos=tag_text.find(" ")
- if (cmd.find("html")==0):
- cmd=tag_text[:space_pos]
- param=tag_text[space_pos+1:]
- tag_text="<"+param+">"
- elif(cmd.find("method")==0):
- cmd=tag_text[:space_pos]
- param=tag_text[space_pos+1:]
-
- if (param.find(".")!=-1):
- class_param,method_param=param.split(".")
- tag_text="[["+class_param.lower()+"#"+method_param+"|"+class_param+'.'+method_param+"]]"
- else:
- tag_text="[[#"+param+"|"+param+"]]"
- elif (cmd.find("image=")==0):
- tag_text="{{"+cmd[6:]+"}}"
- elif (cmd.find("url=")==0):
- tag_text="[["+cmd[4:]+"|"
- elif (cmd=="/url"):
- tag_text="]]>"
- elif (cmd=="center"):
- tag_text=""
- elif (cmd=="/center"):
- tag_text=""
- elif (cmd=="br"):
- tag_text="\\\\\n"
- elif (cmd=="i" or cmd=="/i"):
- tag_text="//"
- elif (cmd=="b" or cmd=="/b"):
- tag_text="**"
- elif (cmd=="u" or cmd=="/u"):
- tag_text="__"
- else:
- tag_text="["+tag_text+"]"
-
-
- text=pre_text+tag_text+post_text
- pos=len(pre_text)+len(tag_text)
-
- #tnode = ET.SubElement(parent,"div")
- #tnode.text=text
- return text
-
-
-def make_type(t):
- global class_names
- if (t in class_names):
- return "[["+t.lower()+"|"+t+"]]"
- return t
-
-
-def make_method(f,name,m,declare,event=False):
-
- s=" * "
- ret_type="void"
- args=list(m)
- mdata={}
- mdata["argidx"]=[]
- for a in args:
- if (a.tag=="return"):
- idx=-1
- elif (a.tag=="argument"):
- idx=int(a.attrib["index"])
- else:
- continue
-
- mdata["argidx"].append(idx)
- mdata[idx]=a
-
-
-
- if (not event):
- if (-1 in mdata["argidx"]):
- s+=make_type(mdata[-1].attrib["type"])
- else:
- s+="void"
- s+=" "
-
- if (declare):
-
- #span.attrib["class"]="funcdecl"
- #a=ET.SubElement(span,"a")
- #a.attrib["name"]=name+"_"+m.attrib["name"]
- #a.text=name+"::"+m.attrib["name"]
- s+="**"+m.attrib["name"]+"**"
- else:
- s+="[[#"+m.attrib["name"]+"|"+m.attrib["name"]+"]]"
-
- s+="**(**"
- argfound=False
- for a in mdata["argidx"]:
- arg=mdata[a]
- if (a<0):
- continue
- if (a>0):
- s+=", "
- else:
- s+=" "
-
- s+=make_type(arg.attrib["type"])
- if ("name" in arg.attrib):
- s+=" "+arg.attrib["name"]
- else:
- s+=" arg"+str(a)
-
- if ("default" in arg.attrib):
- s+="="+arg.attrib["default"]
-
-
- argfound=True
-
- if (argfound):
- s+=" "
- s+="**)**"
-
- if ("qualifiers" in m.attrib):
- s+=" "+m.attrib["qualifiers"]
-
- f.write(s+"\n")
-
-
-def make_doku_class(node):
-
- name = node.attrib["name"]
-
- f=open(name.lower()+".txt","wb")
-
- f.write("====== "+name+" ======\n")
-
- if ("inherits" in node.attrib):
- inh=node.attrib["inherits"].strip()
- f.write("**Inherits:** [["+inh.lower()+"|"+inh+"]]\\\\\n")
- if ("category" in node.attrib):
- f.write("**Category:** "+node.attrib["category"].strip()+"\\\\\n")
-
- briefd = node.find("brief_description")
- if (briefd!=None):
- f.write("===== Brief Description ======\n")
- f.write( dokuize_text(briefd.text.strip())+"\n" )
-
- methods = node.find("methods")
-
- if(methods!=None and len(list(methods))>0):
- f.write("===== Member Functions ======\n")
- for m in list(methods):
- make_method(f,node.attrib["name"],m,False)
-
- events = node.find("signals")
- if(events!=None and len(list(events))>0):
- f.write("===== Signals ======\n")
- for m in list(events):
- make_method(f,node.attrib["name"],m,True,True)
-
- members = node.find("members")
-
- if(members!=None and len(list(members))>0):
- f.write("===== Member Variables ======\n")
-
- for c in list(members):
- s = " * "
- s+=make_type(c.attrib["type"])+" "
- s+="**"+c.attrib["name"]+"**"
- if (c.text.strip()!=""):
- s+=" - "+c.text.strip()
- f.write(s+"\n")
-
-
-
- constants = node.find("constants")
- if(constants!=None and len(list(constants))>0):
- f.write("===== Numeric Constants ======\n")
- for c in list(constants):
- s = " * "
- s+="**"+c.attrib["name"]+"**"
- if ("value" in c.attrib):
- s+=" = **"+c.attrib["value"]+"**"
- if (c.text.strip()!=""):
- s+=" - "+c.text.strip()
- f.write(s+"\n")
-
-
- descr=node.find("description")
- if (descr!=None and descr.text.strip()!=""):
- f.write("===== Description ======\n")
- f.write(dokuize_text(descr.text.strip())+"\n")
-
- methods = node.find("methods")
-
- if(methods!=None and len(list(methods))>0):
- f.write("===== Member Function Description ======\n")
- for m in list(methods):
-
- d=m.find("description")
- if (d==None or d.text.strip()==""):
- continue
- f.write("== "+m.attrib["name"]+" ==\n")
- make_method(f,node.attrib["name"],m,False)
- f.write("\\\\\n")
- f.write(dokuize_text(d.text.strip()))
- f.write("\n")
-
-
-
-
-
- """
- div=ET.Element("div")
- div.attrib["class"]="class";
-
- a=ET.SubElement(div,"a")
- a.attrib["name"]=node.attrib["name"]
-
- h3=ET.SubElement(a,"h3")
- h3.attrib["class"]="title class_title"
- h3.text=node.attrib["name"]
-
- briefd = node.find("brief_description")
- if (briefd!=None):
- div2=ET.SubElement(div,"div")
- div2.attrib["class"]="description class_description"
- div2.text=briefd.text
-
- if ("inherits" in node.attrib):
- ET.SubElement(div,"br")
-
- div2=ET.SubElement(div,"div")
- div2.attrib["class"]="inheritance";
-
- span=ET.SubElement(div2,"span")
- span.text="Inherits: "
-
- make_type(node.attrib["inherits"],div2)
-
- if ("category" in node.attrib):
- ET.SubElement(div,"br")
-
- div3=ET.SubElement(div,"div")
- div3.attrib["class"]="category";
-
- span=ET.SubElement(div3,"span")
- span.attrib["class"]="category"
- span.text="Category: "
-
- a = ET.SubElement(div3,"a")
- a.attrib["class"]="category_ref"
- a.text=node.attrib["category"]
- catname=a.text
- if (catname.rfind("/")!=-1):
- catname=catname[catname.rfind("/"):]
- catname="CATEGORY_"+catname
-
- if (single_page):
- a.attrib["href"]="#"+catname
- else:
- a.attrib["href"]="category.html#"+catname
-
-
- methods = node.find("methods")
-
- if(methods!=None and len(list(methods))>0):
-
- h4=ET.SubElement(div,"h4")
- h4.text="Public Methods:"
-
- method_table=ET.SubElement(div,"table")
- method_table.attrib["class"]="method_list";
-
- for m in list(methods):
-# li = ET.SubElement(div2, "li")
- method_table.append( make_method_def(node.attrib["name"],m,False) )
-
- events = node.find("signals")
-
- if(events!=None and len(list(events))>0):
- h4=ET.SubElement(div,"h4")
- h4.text="Events:"
-
- event_table=ET.SubElement(div,"table")
- event_table.attrib["class"]="method_list";
-
- for m in list(events):
-# li = ET.SubElement(div2, "li")
- event_table.append( make_method_def(node.attrib["name"],m,False,True) )
-
-
- members = node.find("members")
- if(members!=None and len(list(members))>0):
-
- h4=ET.SubElement(div,"h4")
- h4.text="Public Variables:"
- div2=ET.SubElement(div,"div")
- div2.attrib["class"]="member_list";
-
- for c in list(members):
-
- li = ET.SubElement(div2, "li")
- div3=ET.SubElement(li,"div")
- div3.attrib["class"]="member";
- make_type(c.attrib["type"],div3)
- span=ET.SubElement(div3,"span")
- span.attrib["class"]="identifier member_name"
- span.text=" "+c.attrib["name"]+" "
- span=ET.SubElement(div3,"span")
- span.attrib["class"]="member_description"
- span.text=c.text
-
-
- constants = node.find("constants")
- if(constants!=None and len(list(constants))>0):
-
- h4=ET.SubElement(div,"h4")
- h4.text="Constants:"
- div2=ET.SubElement(div,"div")
- div2.attrib["class"]="constant_list";
-
- for c in list(constants):
- li = ET.SubElement(div2, "li")
- div3=ET.SubElement(li,"div")
- div3.attrib["class"]="constant";
-
- span=ET.SubElement(div3,"span")
- span.attrib["class"]="identifier constant_name"
- span.text=c.attrib["name"]+" "
- if ("value" in c.attrib):
- span=ET.SubElement(div3,"span")
- span.attrib["class"]="symbol"
- span.text="= "
- span=ET.SubElement(div3,"span")
- span.attrib["class"]="constant_value"
- span.text=c.attrib["value"]+" "
- span=ET.SubElement(div3,"span")
- span.attrib["class"]="constant_description"
- span.text=c.text
-
-# ET.SubElement(div,"br")
-
-
- descr=node.find("description")
- if (descr!=None and descr.text.strip()!=""):
-
- h4=ET.SubElement(div,"h4")
- h4.text="Description:"
-
- make_text_def(node.attrib["name"],div,descr.text)
-# div2=ET.SubElement(div,"div")
-# div2.attrib["class"]="description";
-# div2.text=descr.text
-
-
-
- if(methods!=None or events!=None):
-
- h4=ET.SubElement(div,"h4")
- h4.text="Method Documentation:"
- iter_list = []
- if (methods!=None):
- iter_list+=list(methods)
- if (events!=None):
- iter_list+=list(events)
-
- for m in iter_list:
-
- descr=m.find("description")
-
- if (descr==None or descr.text.strip()==""):
- continue;
-
- div2=ET.SubElement(div,"div")
- div2.attrib["class"]="method_doc";
-
-
- div2.append( make_method_def(node.attrib["name"],m,True) )
- #anchor = ET.SubElement(div2, "a")
- #anchor.attrib["name"] =
- make_text_def(node.attrib["name"],div2,descr.text)
- #div3=ET.SubElement(div2,"div")
- #div3.attrib["class"]="description";
- #div3.text=descr.text
-
-
- return div
-"""
-for file in input_list:
- tree = ET.parse(file)
- doc=tree.getroot()
-
- if ("version" not in doc.attrib):
- print("Version missing from 'doc'")
- sys.exit(255)
-
- version=doc.attrib["version"]
-
- for c in list(doc):
- if (c.attrib["name"] in class_names):
- continue
- class_names.append(c.attrib["name"])
- classes[c.attrib["name"]]=c
-
-
-class_names.sort()
-
-make_class_list(class_names,4)
-
-for cn in class_names:
- c=classes[cn]
- make_doku_class(c)
-
-
diff --git a/tools/docdump/makehtml.py b/tools/docdump/makehtml.py
deleted file mode 100644
index d533ca1b8b..0000000000
--- a/tools/docdump/makehtml.py
+++ /dev/null
@@ -1,704 +0,0 @@
-import sys
-import xml.etree.ElementTree as ET
-
-input_list = []
-
-single_page=True
-
-for arg in sys.argv[1:]:
- if arg[:1] == "-":
- if arg[1:] == "multipage":
- single_page = False
- if arg[1:] == "singlepage":
- single_page = True
- else:
- input_list.append(arg)
-
-if len(input_list) < 1:
- print("usage: makehtml.py <class_list.xml>")
- sys.exit(0)
-
-
-def validate_tag(elem,tag):
- if (elem.tag != tag):
- print("Tag mismatch, expected '"+tag+"', got "+elem.tag);
- sys.exit(255)
-
-def make_html_bottom(body):
- #make_html_top(body,True)
- ET.SubElement(body,"hr")
- copyright = ET.SubElement(body,"span")
- copyright.text = "Copyright 2008-2010 Codenix SRL"
-
-def make_html_top(body,bottom=False):
-
- if (bottom):
- ET.SubElement(body,"hr")
-
- table = ET.SubElement(body,"table")
- table.attrib["class"]="top_table"
- tr = ET.SubElement(table,"tr")
- td = ET.SubElement(tr,"td")
- td.attrib["class"]="top_table"
-
- img = ET.SubElement(td,"image")
- img.attrib["src"]="images/logo.png"
- td = ET.SubElement(tr,"td")
- td.attrib["class"]="top_table"
- a = ET.SubElement(td,"a")
- a.attrib["href"]="index.html"
- a.text="Index"
- td = ET.SubElement(tr,"td")
- td.attrib["class"]="top_table"
- a = ET.SubElement(td,"a")
- a.attrib["href"]="alphabetical.html"
- a.text="Classes"
- td = ET.SubElement(tr,"td")
- td.attrib["class"]="top_table"
- a = ET.SubElement(td,"a")
- a.attrib["href"]="category.html"
- a.text="Categories"
- td = ET.SubElement(tr,"td")
- a = ET.SubElement(td,"a")
- a.attrib["href"]="inheritance.html"
- a.text="Inheritance"
- if (not bottom):
- ET.SubElement(body,"hr")
-
-
-
-
-def make_html_class_list(class_list,columns):
-
- div=ET.Element("div")
- div.attrib["class"]="ClassList";
-
- h1=ET.SubElement(div,"h2")
- h1.text="Alphabetical Class List"
-
- table=ET.SubElement(div,"table")
- table.attrib["class"]="class_table"
- table.attrib["width"]="100%"
- prev=0
-
- col_max = len(class_list) / columns + 1
- print("col max is ", col_max)
- col_count = 0
- row_count = 0
- last_initial = ""
- fit_columns=[]
-
- for n in range(0,columns):
- fit_columns+=[[]]
-
- indexers=[]
- last_initial=""
-
- idx=0
- for n in class_list:
- col = idx/col_max
- if (col>=columns):
- col=columns-1
- fit_columns[col]+=[n]
- idx+=1
- if (n[:1]!=last_initial):
- indexers+=[n]
- last_initial=n[:1]
-
- row_max=0
-
- for n in range(0,columns):
- if (len(fit_columns[n])>row_max):
- row_max=len(fit_columns[n])
-
-
- for r in range(0,row_max):
- tr = ET.SubElement(table,"tr")
- for c in range(0,columns):
- tdi = ET.SubElement(tr,"td")
- tdi.attrib["align"]="right"
- td = ET.SubElement(tr,"td")
- if (r>=len(fit_columns[c])):
- continue
-
- classname = fit_columns[c][r]
- print(classname)
- if (classname in indexers):
-
- span = ET.SubElement(tdi, "span")
- span.attrib["class"] = "class_index_letter"
- span.text = classname[:1].upper()
-
- if (single_page):
- link="#"+classname
- else:
- link=classname+".html"
-
- a=ET.SubElement(td,"a")
- a.attrib["href"]=link
- a.text=classname
-
-
- if (not single_page):
- cat_class_list=ET.Element("html")
- csscc = ET.SubElement(cat_class_list, "link")
- csscc.attrib["href"] = "main.css"
- csscc.attrib["rel"] = "stylesheet"
- csscc.attrib["type"] = "text/css"
- bodycc = ET.SubElement(cat_class_list, "body")
- make_html_top(bodycc)
-
- cat_class_parent=bodycc
- else:
- cat_class_parent=div
-
-
-
-
- h1=ET.SubElement(cat_class_parent,"h2")
- h1.text="Class List By Category"
-
- class_cat_table={}
- class_cat_list=[]
-
- for c in class_list:
- clss = classes[c]
- if ("category" in clss.attrib):
- class_cat=clss.attrib["category"]
- else:
- class_cat="Core"
- if (class_cat.find("/")!=-1):
- class_cat=class_cat[class_cat.rfind("/")+1:]
- if (not class_cat in class_cat_list):
- class_cat_list.append(class_cat)
- class_cat_table[class_cat]=[]
- class_cat_table[class_cat].append(c)
-
- class_cat_list.sort()
-
- ct = ET.SubElement(cat_class_parent,"table")
- for cl in class_cat_list:
- l = class_cat_table[cl]
- l.sort()
- tr = ET.SubElement(ct,"tr")
- tr.attrib["class"]="category_title"
- td = ET.SubElement(ct,"td")
- td.attrib["class"]="category_title"
-
- a = ET.SubElement(td,"a")
- a.attrib["class"]="category_title"
- a.text=cl
- a.attrib["name"]="CATEGORY_"+cl
-
- td = ET.SubElement(ct,"td")
- td.attrib["class"]="category_title"
-
- for clt in l:
- tr = ET.SubElement(ct,"tr")
- td = ET.SubElement(ct,"td")
- make_type(clt,td)
- clss=classes[clt]
- bd = clss.find("brief_description")
- bdtext=""
- if (bd!=None):
- bdtext=bd.text
- td = ET.SubElement(ct,"td")
- td.text=bdtext
-
- if (not single_page):
- make_html_bottom(bodycc)
- catet_out = ET.ElementTree(cat_class_list)
- catet_out.write("category.html")
-
-
- if (not single_page):
- inh_class_list=ET.Element("html")
- cssic = ET.SubElement(inh_class_list, "link")
- cssic.attrib["href"] = "main.css"
- cssic.attrib["rel"] = "stylesheet"
- cssic.attrib["type"] = "text/css"
- bodyic = ET.SubElement(inh_class_list, "body")
- make_html_top(bodyic)
- inh_class_parent=bodyic
- else:
- inh_class_parent=div
-
-
-
-
- h1=ET.SubElement(inh_class_parent,"h2")
- h1.text="Class List By Inheritance"
-
- itemlist = ET.SubElement(inh_class_parent,"list")
-
- class_inh_table={}
-
- def add_class(clss):
- if (clss.attrib["name"] in class_inh_table):
- return #already added
- parent_list=None
-
- if ("inherits" in clss.attrib):
- inhc = clss.attrib["inherits"]
- if (not (inhc in class_inh_table)):
- add_class(classes[inhc])
-
- parent_list = class_inh_table[inhc].find("div")
- if (parent_list == None):
- parent_div = ET.SubElement(class_inh_table[inhc],"div")
- parent_list = ET.SubElement(parent_div,"list")
- parent_div.attrib["class"]="inh_class_list"
- else:
- parent_list = parent_list.find("list")
-
-
- else:
- parent_list=itemlist
-
- item = ET.SubElement(parent_list,"li")
-# item.attrib["class"]="inh_class_list"
- class_inh_table[clss.attrib["name"]]=item
- make_type(clss.attrib["name"],item)
-
-
- for c in class_list:
- add_class(classes[c])
-
- if (not single_page):
- make_html_bottom(bodyic)
- catet_out = ET.ElementTree(inh_class_list)
- catet_out.write("inheritance.html")
-
-
-
-
-
- #h1=ET.SubElement(div,"h2")
- #h1.text="Class List By Inheritance"
-
- return div
-
-
-def make_type(p_type,p_parent):
- if (p_type=="RefPtr"):
- p_type="Resource"
-
- if (p_type in class_names):
- a=ET.SubElement(p_parent,"a")
- a.attrib["class"]="datatype_existing"
- a.text=p_type+" "
- if (single_page):
- a.attrib["href"]="#"+p_type
- else:
- a.attrib["href"]=p_type+".html"
- else:
- span=ET.SubElement(p_parent,"span")
- span.attrib["class"]="datatype"
- span.text=p_type+" "
-
-
-
-def make_text_def(class_name,parent,text):
- pos=0
- while(True):
- pos = text.find("[",pos)
- if (pos==-1):
- break
-
- endq_pos=text.find("]",pos+1)
- if (endq_pos==-1):
- break
-
- pre_text=text[:pos]
- post_text=text[endq_pos+1:]
- tag_text=text[pos+1:endq_pos]
-
- if (tag_text in class_names):
- if (single_page):
- tag_text='<a href="#'+tag_text+'">'+tag_text+'</a>'
- else:
- tag_text='<a href="'+tag_text+'.html">'+tag_text+'</a>'
- else: #command
- cmd=tag_text
- space_pos=tag_text.find(" ")
- if (cmd.find("html")==0):
- cmd=tag_text[:space_pos]
- param=tag_text[space_pos+1:]
- tag_text="<"+param+">"
- elif(cmd.find("method")==0):
- cmd=tag_text[:space_pos]
- param=tag_text[space_pos+1:]
-
- if (not single_page and param.find(".")!=-1):
- class_param,method_param=param.split(".")
- tag_text=tag_text='<a href="'+class_param+'.html#'+class_param+"_"+method_param+'">'+class_param+'.'+method_param+'()</a>'
- else:
- tag_text=tag_text='<a href="#'+class_name+"_"+param+'">'+class_name+'.'+param+'()</a>'
- elif (cmd.find("image=")==0):
- print("found image: "+cmd)
- tag_text="<img src="+cmd[6:]+"/>"
- elif (cmd.find("url=")==0):
- tag_text="<a href="+cmd[4:]+">"
- elif (cmd=="/url"):
- tag_text="</a>"
- elif (cmd=="center"):
- tag_text="<div align=\"center\">"
- elif (cmd=="/center"):
- tag_text="</div>"
- elif (cmd=="br"):
- tag_text="<br/>"
- elif (cmd=="i" or cmd=="/i" or cmd=="b" or cmd=="/b" or cmd=="u" or cmd=="/u"):
- tag_text="<"+tag_text+">" #html direct mapping
- else:
- tag_text="["+tag_text+"]"
-
-
- text=pre_text+tag_text+post_text
- pos=len(pre_text)+len(tag_text)
-
- #tnode = ET.SubElement(parent,"div")
- #tnode.text=text
- text="<div class=\"description\">"+text+"</div>"
- try:
- tnode=ET.XML(text)
- parent.append(tnode)
- except:
- print("Error parsing description text: '"+text+"'")
- sys.exit(255)
-
-
- return tnode
-
-
-
-
-def make_method_def(name,m,declare,event=False):
-
- mdata={}
-
-
- if (not declare):
- div=ET.Element("tr")
- div.attrib["class"]="method"
- ret_parent=ET.SubElement(div,"td")
- ret_parent.attrib["align"]="right"
- func_parent=ET.SubElement(div,"td")
- else:
- div=ET.Element("div")
- div.attrib["class"]="method"
- ret_parent=div
- func_parent=div
-
- mdata["argidx"]=[]
- mdata["name"]=m.attrib["name"]
- qualifiers=""
- if ("qualifiers" in m.attrib):
- qualifiers=m.attrib["qualifiers"]
-
- args=list(m)
- for a in args:
- if (a.tag=="return"):
- idx=-1
- elif (a.tag=="argument"):
- idx=int(a.attrib["index"])
- else:
- continue
-
- mdata["argidx"].append(idx)
- mdata[idx]=a
-
- if (not event):
- if (-1 in mdata["argidx"]):
- make_type(mdata[-1].attrib["type"],ret_parent)
- mdata["argidx"].remove(-1)
- else:
- make_type("void",ret_parent)
-
- span=ET.SubElement(func_parent,"span")
- if (declare):
- span.attrib["class"]="funcdecl"
- a=ET.SubElement(span,"a")
- a.attrib["name"]=name+"_"+m.attrib["name"]
- a.text=name+"::"+m.attrib["name"]
- else:
- span.attrib["class"]="identifier funcdef"
- a=ET.SubElement(span,"a")
- a.attrib["href"]="#"+name+"_"+m.attrib["name"]
- a.text=m.attrib["name"]
-
- span=ET.SubElement(func_parent,"span")
- span.attrib["class"]="symbol"
- span.text=" ("
-
- for a in mdata["argidx"]:
- arg=mdata[a]
- if (a>0):
- span=ET.SubElement(func_parent,"span")
- span.text=", "
- else:
- span=ET.SubElement(func_parent,"span")
- span.text=" "
-
-
- make_type(arg.attrib["type"],func_parent)
-
- span=ET.SubElement(func_parent,"span")
- span.text=arg.attrib["name"]
- if ("default" in arg.attrib):
- span.text=span.text+"="+arg.attrib["default"]
-
-
- span=ET.SubElement(func_parent,"span")
- span.attrib["class"]="symbol"
- if (len(mdata["argidx"])):
- span.text=" )"
- else:
- span.text=")"
-
- if (qualifiers):
- span=ET.SubElement(func_parent,"span")
- span.attrib["class"]="qualifier"
- span.text=" "+qualifiers
-
- return div
-
-
-def make_html_class(node):
-
- div=ET.Element("div")
- div.attrib["class"]="class";
-
- a=ET.SubElement(div,"a")
- a.attrib["name"]=node.attrib["name"]
-
- h3=ET.SubElement(a,"h3")
- h3.attrib["class"]="title class_title"
- h3.text=node.attrib["name"]
-
- briefd = node.find("brief_description")
- if (briefd!=None):
- div2=ET.SubElement(div,"div")
- div2.attrib["class"]="description class_description"
- div2.text=briefd.text
-
- if ("inherits" in node.attrib):
- ET.SubElement(div,"br")
-
- div2=ET.SubElement(div,"div")
- div2.attrib["class"]="inheritance";
-
- span=ET.SubElement(div2,"span")
- span.text="Inherits: "
-
- make_type(node.attrib["inherits"],div2)
-
- if ("category" in node.attrib):
- ET.SubElement(div,"br")
-
- div3=ET.SubElement(div,"div")
- div3.attrib["class"]="category";
-
- span=ET.SubElement(div3,"span")
- span.attrib["class"]="category"
- span.text="Category: "
-
- a = ET.SubElement(div3,"a")
- a.attrib["class"]="category_ref"
- a.text=node.attrib["category"]
- catname=a.text
- if (catname.rfind("/")!=-1):
- catname=catname[catname.rfind("/"):]
- catname="CATEGORY_"+catname
-
- if (single_page):
- a.attrib["href"]="#"+catname
- else:
- a.attrib["href"]="category.html#"+catname
-
-
- methods = node.find("methods")
-
- if(methods!=None and len(list(methods))>0):
-
- h4=ET.SubElement(div,"h4")
- h4.text="Public Methods:"
-
- method_table=ET.SubElement(div,"table")
- method_table.attrib["class"]="method_list";
-
- for m in list(methods):
-# li = ET.SubElement(div2, "li")
- method_table.append( make_method_def(node.attrib["name"],m,False) )
-
- events = node.find("signals")
-
- if(events!=None and len(list(events))>0):
- h4=ET.SubElement(div,"h4")
- h4.text="Events:"
-
- event_table=ET.SubElement(div,"table")
- event_table.attrib["class"]="method_list";
-
- for m in list(events):
-# li = ET.SubElement(div2, "li")
- event_table.append( make_method_def(node.attrib["name"],m,False,True) )
-
-
- members = node.find("members")
- if(members!=None and len(list(members))>0):
-
- h4=ET.SubElement(div,"h4")
- h4.text="Public Variables:"
- div2=ET.SubElement(div,"div")
- div2.attrib["class"]="member_list";
-
- for c in list(members):
-
- li = ET.SubElement(div2, "li")
- div3=ET.SubElement(li,"div")
- div3.attrib["class"]="member";
- make_type(c.attrib["type"],div3)
- span=ET.SubElement(div3,"span")
- span.attrib["class"]="identifier member_name"
- span.text=" "+c.attrib["name"]+" "
- span=ET.SubElement(div3,"span")
- span.attrib["class"]="member_description"
- span.text=c.text
-
-
- constants = node.find("constants")
- if(constants!=None and len(list(constants))>0):
-
- h4=ET.SubElement(div,"h4")
- h4.text="Constants:"
- div2=ET.SubElement(div,"div")
- div2.attrib["class"]="constant_list";
-
- for c in list(constants):
- li = ET.SubElement(div2, "li")
- div3=ET.SubElement(li,"div")
- div3.attrib["class"]="constant";
-
- span=ET.SubElement(div3,"span")
- span.attrib["class"]="identifier constant_name"
- span.text=c.attrib["name"]+" "
- if ("value" in c.attrib):
- span=ET.SubElement(div3,"span")
- span.attrib["class"]="symbol"
- span.text="= "
- span=ET.SubElement(div3,"span")
- span.attrib["class"]="constant_value"
- span.text=c.attrib["value"]+" "
- span=ET.SubElement(div3,"span")
- span.attrib["class"]="constant_description"
- span.text=c.text
-
-# ET.SubElement(div,"br")
-
-
- descr=node.find("description")
- if (descr!=None and descr.text.strip()!=""):
-
- h4=ET.SubElement(div,"h4")
- h4.text="Description:"
-
- make_text_def(node.attrib["name"],div,descr.text)
-# div2=ET.SubElement(div,"div")
-# div2.attrib["class"]="description";
-# div2.text=descr.text
-
-
-
- if(methods!=None or events!=None):
-
- h4=ET.SubElement(div,"h4")
- h4.text="Method Documentation:"
- iter_list = []
- if (methods!=None):
- iter_list+=list(methods)
- if (events!=None):
- iter_list+=list(events)
-
- for m in iter_list:
-
- descr=m.find("description")
-
- if (descr==None or descr.text.strip()==""):
- continue;
-
- div2=ET.SubElement(div,"div")
- div2.attrib["class"]="method_doc";
-
-
- div2.append( make_method_def(node.attrib["name"],m,True) )
- #anchor = ET.SubElement(div2, "a")
- #anchor.attrib["name"] =
- make_text_def(node.attrib["name"],div2,descr.text)
- #div3=ET.SubElement(div2,"div")
- #div3.attrib["class"]="description";
- #div3.text=descr.text
-
-
- return div
-
-class_names=[]
-classes={}
-
-
-for file in input_list:
- tree = ET.parse(file)
- doc=tree.getroot()
-
- if ("version" not in doc.attrib):
- print("Version missing from 'doc'")
- sys.exit(255)
-
- version=doc.attrib["version"]
-
- for c in list(doc):
- if (c.attrib["name"] in class_names):
- continue
- class_names.append(c.attrib["name"])
- classes[c.attrib["name"]]=c
-
-html = ET.Element("html")
-css = ET.SubElement(html, "link")
-css.attrib["href"] = "main.css"
-css.attrib["rel"] = "stylesheet"
-css.attrib["type"] = "text/css"
-
-body = ET.SubElement(html, "body")
-if (not single_page):
- make_html_top(body)
-
-
-
-class_names.sort()
-
-body.append( make_html_class_list(class_names,5) )
-
-for cn in class_names:
- c=classes[cn]
- if (single_page):
- body.append( make_html_class(c))
- else:
- html2 = ET.Element("html")
- css = ET.SubElement(html2, "link")
- css.attrib["href"] = "main.css"
- css.attrib["rel"] = "stylesheet"
- css.attrib["type"] = "text/css"
- body2 = ET.SubElement(html2, "body" )
- make_html_top(body2)
- body2.append( make_html_class(c) );
- make_html_bottom(body2)
- et_out = ET.ElementTree(html2)
- et_out.write(c.attrib["name"]+".html")
-
-
-et_out = ET.ElementTree(html)
-if (single_page):
- et_out.write("singlepage.html")
-else:
- make_html_bottom(body)
- et_out.write("alphabetical.html")
-
diff --git a/tools/docdump/makemd.py b/tools/docdump/makemd.py
deleted file mode 100644
index f85d145d5e..0000000000
--- a/tools/docdump/makemd.py
+++ /dev/null
@@ -1,345 +0,0 @@
-#!/usr/bin/python
-# -*- coding: utf-8 -*-
-import sys
-import xml.etree.ElementTree as ET
-
-input_list = []
-
-for arg in sys.argv[1:]:
- input_list.append(arg)
-
-if len(input_list) < 1:
- print 'usage: makedoku.py <class_list.xml>'
- sys.exit(0)
-
-
-def validate_tag(elem, tag):
- if elem.tag != tag:
- print "Tag mismatch, expected '" + tag + "', got " + elem.tag
- sys.exit(255)
-
-
-class_names = []
-classes = {}
-
-
-def make_class_list(class_list, columns):
-
- f = open('class_list.md', 'wb')
- prev = 0
- col_max = len(class_list) / columns + 1
- print ('col max is ', col_max)
- col_count = 0
- row_count = 0
- last_initial = ''
- fit_columns = []
-
- for n in range(0, columns):
- fit_columns += [[]]
-
- indexers = []
- last_initial = ''
-
- idx = 0
- for n in class_list:
- col = idx / col_max
- if col >= columns:
- col = columns - 1
- fit_columns[col] += [n]
- idx += 1
- if n[:1] != last_initial:
- indexers += [n]
- last_initial = n[:1]
-
- row_max = 0
- f.write("\n")
-
- for n in range(0, columns):
- if len(fit_columns[n]) > row_max:
- row_max = len(fit_columns[n])
-
- f.write("| ")
- for n in range(0, columns):
- f.write(" | |")
-
- f.write("\n")
- f.write("| ")
- for n in range(0, columns):
- f.write(" --- | ------- |")
- f.write("\n")
-
- for r in range(0, row_max):
- s = '| '
- for c in range(0, columns):
- if r >= len(fit_columns[c]):
- continue
-
- classname = fit_columns[c][r]
- initial = classname[0]
- if classname in indexers:
- s += '**' + initial + '** | '
- else:
- s += ' | '
-
- s += '[' + classname + '](class_'+ classname.lower()+') | '
-
- s += '\n'
- f.write(s)
-
-
-def dokuize_text(txt):
-
- return txt
-
-
-def dokuize_text(text):
- pos = 0
- while True:
- pos = text.find('[', pos)
- if pos == -1:
- break
-
- endq_pos = text.find(']', pos + 1)
- if endq_pos == -1:
- break
-
- pre_text = text[:pos]
- post_text = text[endq_pos + 1:]
- tag_text = text[pos + 1:endq_pos]
-
- if tag_text in class_names:
- tag_text = make_type(tag_text)
- else:
-
- # command
-
- cmd = tag_text
- space_pos = tag_text.find(' ')
- if cmd.find('html') == 0:
- cmd = tag_text[:space_pos]
- param = tag_text[space_pos + 1:]
- tag_text = '<' + param + '>'
- elif cmd.find('method') == 0:
- cmd = tag_text[:space_pos]
- param = tag_text[space_pos + 1:]
-
- if param.find('.') != -1:
- (class_param, method_param) = param.split('.')
- tag_text = '['+class_param+'.'+method_param.replace("_","&#95;")+'](' + class_param.lower() + '#' \
- + method_param + ')'
- else:
- tag_text = '[' + param.replace("_","&#95;") + '](#' + param + ')'
- elif cmd.find('image=') == 0:
- tag_text = '![](' + cmd[6:] + ')'
- elif cmd.find('url=') == 0:
- tag_text = '[' + cmd[4:] + ']('+cmd[4:]
- elif cmd == '/url':
- tag_text = ')'
- elif cmd == 'center':
- tag_text = ''
- elif cmd == '/center':
- tag_text = ''
- elif cmd == 'br':
- tag_text = '\n'
- elif cmd == 'i' or cmd == '/i':
- tag_text = '_'
- elif cmd == 'b' or cmd == '/b':
- tag_text = '**'
- elif cmd == 'u' or cmd == '/u':
- tag_text = '__'
- else:
- tag_text = '[' + tag_text + ']'
-
- text = pre_text + tag_text + post_text
- pos = len(pre_text) + len(tag_text)
-
- # tnode = ET.SubElement(parent,"div")
- # tnode.text=text
-
- return text
-
-
-def make_type(t):
- global class_names
- if t in class_names:
- return '[' + t + '](class_' + t.lower() + ')'
- return t
-
-
-def make_method(
- f,
- name,
- m,
- declare,
- event=False,
- ):
-
- s = ' * '
- ret_type = 'void'
- args = list(m)
- mdata = {}
- mdata['argidx'] = []
- for a in args:
- if a.tag == 'return':
- idx = -1
- elif a.tag == 'argument':
- idx = int(a.attrib['index'])
- else:
- continue
-
- mdata['argidx'].append(idx)
- mdata[idx] = a
-
- if not event:
- if -1 in mdata['argidx']:
- s += make_type(mdata[-1].attrib['type'])
- else:
- s += 'void'
- s += ' '
-
- if declare:
-
- # span.attrib["class"]="funcdecl"
- # a=ET.SubElement(span,"a")
- # a.attrib["name"]=name+"_"+m.attrib["name"]
- # a.text=name+"::"+m.attrib["name"]
-
- s += ' **'+m.attrib['name'].replace("_","&#95;")+'** '
- else:
- s += ' **['+ m.attrib['name'].replace("_","&#95;")+'](#' + m.attrib['name'] + ')** '
-
- s += ' **(**'
- argfound = False
- for a in mdata['argidx']:
- arg = mdata[a]
- if a < 0:
- continue
- if a > 0:
- s += ', '
- else:
- s += ' '
-
- s += make_type(arg.attrib['type'])
- if 'name' in arg.attrib:
- s += ' ' + arg.attrib['name']
- else:
- s += ' arg' + str(a)
-
- if 'default' in arg.attrib:
- s += '=' + arg.attrib['default']
-
- argfound = True
-
- if argfound:
- s += ' '
- s += ' **)**'
-
- if 'qualifiers' in m.attrib:
- s += ' ' + m.attrib['qualifiers']
-
- f.write(s + '\n')
-
-
-def make_doku_class(node):
-
- name = node.attrib['name']
-
- f = open("class_"+name.lower() + '.md', 'wb')
-
- f.write('# ' + name + ' \n')
-
- if 'inherits' in node.attrib:
- inh = node.attrib['inherits'].strip()
- f.write('####**Inherits:** '+make_type(inh)+'\n')
- if 'category' in node.attrib:
- f.write('####**Category:** ' + node.attrib['category'].strip()
- + '\n')
-
- briefd = node.find('brief_description')
- if briefd != None:
- f.write('\n### Brief Description \n')
- f.write(dokuize_text(briefd.text.strip()) + '\n')
-
- methods = node.find('methods')
-
- if methods != None and len(list(methods)) > 0:
- f.write('\n### Member Functions \n')
- for m in list(methods):
- make_method(f, node.attrib['name'], m, False)
-
- events = node.find('signals')
- if events != None and len(list(events)) > 0:
- f.write('\n### Signals \n')
- for m in list(events):
- make_method(f, node.attrib['name'], m, True, True)
-
- members = node.find('members')
-
- if members != None and len(list(members)) > 0:
- f.write('\n### Member Variables \n')
-
- for c in list(members):
- s = ' * '
- s += make_type(c.attrib['type']) + ' '
- s += '**' + c.attrib['name'] + '**'
- if c.text.strip() != '':
- s += ' - ' + c.text.strip()
- f.write(s + '\n')
-
- constants = node.find('constants')
- if constants != None and len(list(constants)) > 0:
- f.write('\n### Numeric Constants \n')
- for c in list(constants):
- s = ' * '
- s += '**' + c.attrib['name'] + '**'
- if 'value' in c.attrib:
- s += ' = **' + c.attrib['value'] + '**'
- if c.text.strip() != '':
- s += ' - ' + c.text.strip()
- f.write(s + '\n')
-
- descr = node.find('description')
- if descr != None and descr.text.strip() != '':
- f.write('\n### Description \n')
- f.write(dokuize_text(descr.text.strip()) + '\n')
-
- methods = node.find('methods')
-
- if methods != None and len(list(methods)) > 0:
- f.write('\n### Member Function Description \n')
- for m in list(methods):
-
- d = m.find('description')
- if d == None or d.text.strip() == '':
- continue
- f.write('\n#### <a name="'+m.attrib['name']+'">' + m.attrib['name'] + '</a>\n')
- make_method(f, node.attrib['name'], m, True)
- f.write('\n')
- f.write(dokuize_text(d.text.strip()))
- f.write('\n')
-
-
-for file in input_list:
- tree = ET.parse(file)
- doc = tree.getroot()
-
- if 'version' not in doc.attrib:
- print "Version missing from 'doc'"
- sys.exit(255)
-
- version = doc.attrib['version']
-
- for c in list(doc):
- if c.attrib['name'] in class_names:
- continue
- class_names.append(c.attrib['name'])
- classes[c.attrib['name']] = c
-
-class_names.sort()
-
-make_class_list(class_names, 2)
-
-for cn in class_names:
- c = classes[cn]
- make_doku_class(c)
-
diff --git a/tools/editor/SCsub b/tools/editor/SCsub
index 73ec530177..cd46ff8353 100644
--- a/tools/editor/SCsub
+++ b/tools/editor/SCsub
@@ -28,7 +28,7 @@ def make_doc_header(target,source,env):
-
+
if (env["tools"]=="yes"):
@@ -43,17 +43,16 @@ if (env["tools"]=="yes"):
f.write(reg_exporters_inc)
f.write(reg_exporters)
f.close()
-
+
env.Depends("#tools/editor/doc_data_compressed.h","#doc/base/classes.xml")
env.Command("#tools/editor/doc_data_compressed.h","#doc/base/classes.xml",make_doc_header)
#make_doc_header(env.File("#tools/editor/doc_data_raw.h").srcnode().abspath,env.File("#doc/base/classes.xml").srcnode().abspath,env)
-
+
env.add_source_files(env.tool_sources,"*.cpp")
-
+
Export('env')
- SConscript('icons/SCsub');
+ SConscript('icons/SCsub');
SConscript('plugins/SCsub');
SConscript('fileserver/SCsub');
SConscript('io_plugins/SCsub');
-
diff --git a/tools/editor/animation_editor.cpp b/tools/editor/animation_editor.cpp
index d431af6c8d..fbe50d6d96 100644
--- a/tools/editor/animation_editor.cpp
+++ b/tools/editor/animation_editor.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,6 +33,8 @@
#include "io/resource_saver.h"
#include "pair.h"
#include "scene/gui/separator.h"
+#include "editor_node.h"
+#include "tools/editor/plugins/animation_player_editor_plugin.h"
/* Missing to fix:
*Set
@@ -626,26 +628,41 @@ public:
};
-void AnimationKeyEditor::_menu_track(int p_type) {
+void AnimationKeyEditor::_menu_add_track(int p_type) {
ERR_FAIL_COND(!animation.is_valid());
- last_menu_track_opt=p_type;
switch(p_type) {
- case TRACK_MENU_ADD_VALUE_TRACK:
- case TRACK_MENU_ADD_TRANSFORM_TRACK:
- case TRACK_MENU_ADD_CALL_TRACK: {
+ case ADD_TRACK_MENU_ADD_CALL_TRACK: {
+ if (root) {
+ call_select->popup_centered_ratio();
+ break;
+ }
+ } break;
+ case ADD_TRACK_MENU_ADD_VALUE_TRACK:
+ case ADD_TRACK_MENU_ADD_TRANSFORM_TRACK: {
undo_redo->create_action("Anim Add Track");
- undo_redo->add_do_method(animation.ptr(),"add_track",p_type);
+ undo_redo->add_do_method(animation.ptr(),"add_track",p_type);
undo_redo->add_do_method(animation.ptr(),"track_set_path",animation->get_track_count(),".");
undo_redo->add_undo_method(animation.ptr(),"remove_track",animation->get_track_count());
undo_redo->commit_action();
} break;
+ }
+}
+
+void AnimationKeyEditor::_menu_track(int p_type) {
+
+ ERR_FAIL_COND(!animation.is_valid());
+
+
+ last_menu_track_opt=p_type;
+ switch(p_type) {
+
case TRACK_MENU_SCALE:
case TRACK_MENU_SCALE_PIVOT: {
@@ -887,6 +904,23 @@ void AnimationKeyEditor::_menu_track(int p_type) {
optimize_dialog->popup_centered(Size2(250,180));
} break;
+ case TRACK_MENU_CLEAN_UP: {
+
+ cleanup_dialog->popup_centered_minsize(Size2(300,0));
+ } break;
+ case TRACK_MENU_CLEAN_UP_CONFIRM: {
+
+ if (cleanup_all->is_pressed()) {
+ List<StringName> names;
+ AnimationPlayerEditor::singleton->get_player()->get_animation_list(&names);
+ for (List<StringName>::Element *E=names.front();E;E=E->next()) {
+ _cleanup_animation(AnimationPlayerEditor::singleton->get_player()->get_animation(E->get()));
+ }
+ } else {
+ _cleanup_animation(animation);
+
+ }
+ } break;
case CURVE_SET_LINEAR: {
curve_edit->force_transition(1.0);
@@ -917,6 +951,57 @@ void AnimationKeyEditor::_menu_track(int p_type) {
}
+void AnimationKeyEditor::_cleanup_animation(Ref<Animation> p_animation) {
+
+
+ for(int i=0;i<p_animation->get_track_count();i++) {
+
+ bool prop_exists=false;
+ Variant::Type valid_type=Variant::NIL;
+ Object *obj=NULL;
+
+ RES res;
+ Node *node = root->get_node_and_resource(p_animation->track_get_path(i),res);
+
+ if (res.is_valid()) {
+ obj=res.ptr();
+ } else if (node) {
+ obj=node;
+ }
+
+ if (obj && p_animation->track_get_type(i)==Animation::TYPE_VALUE) {
+ valid_type=obj->get_static_property_type(p_animation->track_get_path(i).get_property(),&prop_exists);
+ }
+
+ if (!obj && cleanup_tracks->is_pressed()) {
+
+ p_animation->remove_track(i);
+ i--;
+ continue;
+ }
+
+ if (!prop_exists || p_animation->track_get_type(i)!=Animation::TYPE_VALUE || cleanup_keys->is_pressed()==false)
+ continue;
+
+ for(int j=0;j<p_animation->track_get_key_count(i);j++) {
+
+ Variant v = p_animation->track_get_key_value(i,j);
+
+ if (!Variant::can_convert(v.get_type(),valid_type)) {
+ p_animation->track_remove_key(i,j);
+ j--;
+ }
+ }
+
+ if (p_animation->track_get_key_count(i)==0 && cleanup_tracks->is_pressed()) {
+ p_animation->remove_track(i);
+ i--;
+ }
+ }
+
+ undo_redo->clear_history();
+ _update_paths();
+}
void AnimationKeyEditor::_animation_optimize() {
@@ -993,15 +1078,18 @@ void AnimationKeyEditor::_track_editor_draw() {
if (!animation.is_valid()) {
v_scroll->hide();
h_scroll->hide();
+ menu_add_track->set_disabled(true);
menu_track->set_disabled(true);
edit_button->set_disabled(true);
key_editor_tab->hide();
move_up_button->set_disabled(true);
move_down_button->set_disabled(true);
remove_button->set_disabled(true);
+
return;
}
+ menu_add_track->set_disabled(false);
menu_track->set_disabled(false);
edit_button->set_disabled(false);
move_up_button->set_disabled(false);
@@ -1024,6 +1112,7 @@ void AnimationKeyEditor::_track_editor_draw() {
timecolor = Color::html("ff4a414f");
Color hover_color = Color(1,1,1,0.05);
Color select_color = Color(1,1,1,0.1);
+ Color invalid_path_color = Color(1,0.6,0.4,0.5);
Color track_select_color =Color::html("ffbd8e8e");
Ref<Texture> remove_icon = get_icon("Remove","EditorIcons");
@@ -1050,6 +1139,9 @@ void AnimationKeyEditor::_track_editor_draw() {
get_icon("KeyCall","EditorIcons")
};
+ Ref<Texture> invalid_icon = get_icon("KeyInvalid","EditorIcons");
+ Ref<Texture> invalid_icon_hover = get_icon("KeyInvalidHover","EditorIcons");
+
Ref<Texture> hsize_icon = get_icon("Hsize","EditorIcons");
Ref<Texture> type_hover=get_icon("KeyHover","EditorIcons");
@@ -1236,6 +1328,23 @@ void AnimationKeyEditor::_track_editor_draw() {
break;
int y = h+i*h+sep;
+ bool prop_exists=false;
+ Variant::Type valid_type=Variant::NIL;
+ Object *obj=NULL;
+
+ RES res;
+ Node *node = root->get_node_and_resource(animation->track_get_path(idx),res);
+
+ if (res.is_valid()) {
+ obj=res.ptr();
+ } else if (node) {
+ obj=node;
+ }
+
+ if (obj && animation->track_get_type(idx)==Animation::TYPE_VALUE) {
+ valid_type=obj->get_static_property_type(animation->track_get_path(idx).get_property(),&prop_exists);
+ }
+
if (/*mouse_over.over!=MouseOver::OVER_NONE &&*/ idx==mouse_over.track) {
Color sepc=hover_color;
@@ -1256,6 +1365,8 @@ void AnimationKeyEditor::_track_editor_draw() {
ncol=track_select_color;
te->draw_string(font,Point2(ofs+Point2(type_icon[0]->get_width()+sep,y+font->get_ascent()+(sep/2))).floor(),np,ncol,name_limit-(type_icon[0]->get_width()+sep)-5);
+ if (!obj)
+ te->draw_line(ofs+Point2(0,y+h/2),ofs+Point2(name_limit,y+h/2),invalid_path_color);
te->draw_line(ofs+Point2(0,y+h),ofs+Point2(size.width,y+h),sepcolor);
@@ -1321,6 +1432,8 @@ void AnimationKeyEditor::_track_editor_draw() {
int kc=animation->track_get_key_count(idx);
bool first=true;
+
+
for(int i=0;i<kc;i++) {
@@ -1368,7 +1481,21 @@ void AnimationKeyEditor::_track_editor_draw() {
}
- te->draw_texture(tex,ofs+Point2(x,y+key_vofs).floor());
+ if (prop_exists && !Variant::can_convert(value.get_type(),valid_type)) {
+ te->draw_texture(invalid_icon,ofs+Point2(x,y+key_vofs).floor());
+ }
+
+ if (prop_exists && !Variant::can_convert(value.get_type(),valid_type)) {
+ if (tex==type_hover)
+ te->draw_texture(invalid_icon_hover,ofs+Point2(x,y+key_vofs).floor());
+ else
+ te->draw_texture(invalid_icon,ofs+Point2(x,y+key_vofs).floor());
+ } else {
+
+ te->draw_texture(tex,ofs+Point2(x,y+key_vofs).floor());
+ }
+
+
first=false;
}
@@ -1576,7 +1703,7 @@ bool AnimationKeyEditor::_edit_if_single_selection() {
if (selection.size()==0) {
curve_edit->set_mode(AnimationCurveEdit::MODE_DISABLED);
- print_line("disable");
+ //print_line("disable");
} else {
curve_edit->set_mode(AnimationCurveEdit::MODE_MULTIPLE);
@@ -1587,13 +1714,13 @@ bool AnimationKeyEditor::_edit_if_single_selection() {
curve_edit->set_multiple(animation->track_get_key_transition(E->key().track,E->key().key));
}
- print_line("multiple");
+ //print_line("multiple");
}
return false;
}
curve_edit->set_mode(AnimationCurveEdit::MODE_SINGLE);
- print_line("regular");
+ //print_line("regular");
int idx = selection.front()->key().track;
int key = selection.front()->key().key;
@@ -2363,7 +2490,7 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
te->update();
track_editor->set_tooltip("");
- if (!track_editor->has_focus() && (!get_focus_owner() || !get_focus_owner()->cast_to<LineEdit>()))
+ if (!track_editor->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field()))
track_editor->call_deferred("grab_focus");
@@ -2537,6 +2664,8 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
String text;
text="time: "+rtos(animation->track_get_key_time(idx,mouse_over.over_key))+"\n";
+
+
switch(animation->track_get_type(idx)) {
case Animation::TYPE_TRANSFORM: {
@@ -2551,8 +2680,33 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
} break;
case Animation::TYPE_VALUE: {
- Variant v = animation->track_get_key_value(idx,mouse_over.over_key);
- text+="value: "+String(v)+"\n";
+ Variant v = animation->track_get_key_value(idx,mouse_over.over_key);;
+ //text+="value: "+String(v)+"\n";
+
+ bool prop_exists=false;
+ Variant::Type valid_type=Variant::NIL;
+ Object *obj=NULL;
+
+ RES res;
+ Node *node = root->get_node_and_resource(animation->track_get_path(idx),res);
+
+ if (res.is_valid()) {
+ obj=res.ptr();
+ } else if (node) {
+ obj=node;
+ }
+
+ if (obj) {
+ valid_type=obj->get_static_property_type(animation->track_get_path(idx).get_property(),&prop_exists);
+ }
+
+ text+="type: "+Variant::get_type_name(v.get_type())+"\n";
+ if (prop_exists && !Variant::can_convert(v.get_type(),valid_type)) {
+ text+="value: "+String(v)+" (Invalid, expected type: "+Variant::get_type_name(valid_type)+")\n";
+ } else {
+ text+="value: "+String(v)+"\n";
+ }
+
} break;
case Animation::TYPE_METHOD: {
@@ -2575,6 +2729,9 @@ void AnimationKeyEditor::_track_editor_input_event(const InputEvent& p_input) {
} break;
}
text+="easing: "+rtos(animation->track_get_key_transition(idx,mouse_over.over_key));
+
+
+
track_editor->set_tooltip(text);
return;
@@ -2650,15 +2807,21 @@ void AnimationKeyEditor::_notification(int p_what) {
switch(p_what) {
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+
+ EditorNode::get_singleton()->update_keying();
+ } break;
case NOTIFICATION_ENTER_TREE: {
- zoomicon->set_texture( get_icon("Zoom","EditorIcons") );
- //menu_track->set_icon(get_icon("AddTrack","EditorIcons"));
- menu_track->get_popup()->add_icon_item(get_icon("KeyValue","EditorIcons"),"Add Normal Track",TRACK_MENU_ADD_VALUE_TRACK);
- menu_track->get_popup()->add_icon_item(get_icon("KeyXform","EditorIcons"),"Add Transform Track",TRACK_MENU_ADD_TRANSFORM_TRACK);
- menu_track->get_popup()->add_icon_item(get_icon("KeyCall","EditorIcons"),"Add Call Func Track",TRACK_MENU_ADD_CALL_TRACK);
- menu_track->get_popup()->add_separator();
+ zoomicon->set_texture( get_icon("Zoom","EditorIcons") );
+
+ menu_add_track->set_icon(get_icon("AddTrack","EditorIcons"));
+ menu_add_track->get_popup()->add_icon_item(get_icon("KeyValue","EditorIcons"),"Add Normal Track",ADD_TRACK_MENU_ADD_VALUE_TRACK);
+ menu_add_track->get_popup()->add_icon_item(get_icon("KeyXform","EditorIcons"),"Add Transform Track",ADD_TRACK_MENU_ADD_TRANSFORM_TRACK);
+ menu_add_track->get_popup()->add_icon_item(get_icon("KeyCall","EditorIcons"),"Add Call Func Track",ADD_TRACK_MENU_ADD_CALL_TRACK);
+
+ menu_track->set_icon(get_icon("Tools","EditorIcons"));
menu_track->get_popup()->add_item("Scale Selection",TRACK_MENU_SCALE);
menu_track->get_popup()->add_item("Scale From Cursor",TRACK_MENU_SCALE_PIVOT);
menu_track->get_popup()->add_separator();
@@ -2683,6 +2846,7 @@ void AnimationKeyEditor::_notification(int p_what) {
//menu_track->get_popup()->add_submenu_item("Set Transitions..","Transitions");
//menu_track->get_popup()->add_separator();
menu_track->get_popup()->add_item("Optimize Animation",TRACK_MENU_OPTIMIZE);
+ menu_track->get_popup()->add_item("Clean-Up Animation",TRACK_MENU_CLEAN_UP);
curve_linear->set_icon(get_icon("CurveLinear","EditorIcons"));
curve_in->set_icon(get_icon("CurveIn","EditorIcons"));
@@ -2735,6 +2899,7 @@ void AnimationKeyEditor::_notification(int p_what) {
}
+ call_select->connect("selected",this,"_add_call_track");
// rename_anim->set_icon( get_icon("Rename","EditorIcons") );
/*
edit_anim->set_icon( get_icon("Edit","EditorIcons") );
@@ -2828,6 +2993,8 @@ void AnimationKeyEditor::set_animation(const Ref<Animation>& p_anim) {
_update_menu();
selected_track=-1;
_edit_if_single_selection();
+
+ EditorNode::get_singleton()->update_keying();
}
void AnimationKeyEditor::set_root(Node *p_root) {
@@ -2857,13 +3024,13 @@ void AnimationKeyEditor::set_keying(bool p_enabled) {
keying=p_enabled;
_update_menu();
- emit_signal("keying_changed",p_enabled);
+ emit_signal("keying_changed");
}
bool AnimationKeyEditor::has_keying() const {
- return keying;
+ return is_visible() && animation.is_valid();
}
void AnimationKeyEditor::_query_insert(const InsertData& p_id) {
@@ -3192,6 +3359,7 @@ Ref<Animation> AnimationKeyEditor::get_current_animation() const {
void AnimationKeyEditor::_animation_len_changed(float p_len) {
+
if (updating)
return;
@@ -3319,8 +3487,10 @@ void AnimationKeyEditor::_insert_delay() {
void AnimationKeyEditor::_step_changed(float p_len) {
updating=true;
- if (!animation.is_null())
+ if (!animation.is_null()) {
animation->set_step(p_len);
+ emit_signal("animation_step_changed",animation->get_step());
+ }
updating=false;
}
@@ -3456,6 +3626,26 @@ void AnimationKeyEditor::_scale() {
}
+void AnimationKeyEditor::_add_call_track(const NodePath& p_base) {
+
+ print_line("BASE IS "+String(p_base));
+ Node* base = EditorNode::get_singleton()->get_edited_scene();
+ if (!base)
+ return;
+ Node* from=base->get_node(p_base);
+ if (!from || !root)
+ return;
+
+ NodePath path = root->get_path_to(from);
+
+ undo_redo->create_action("Anim Add Call Track");
+ undo_redo->add_do_method(animation.ptr(),"add_track",Animation::TYPE_METHOD);
+ undo_redo->add_do_method(animation.ptr(),"track_set_path",animation->get_track_count(),path);
+ undo_redo->add_undo_method(animation.ptr(),"remove_track",animation->get_track_count());
+ undo_redo->commit_action();
+
+}
+
void AnimationKeyEditor::cleanup() {
set_animation(Ref<Animation>());
@@ -3484,6 +3674,7 @@ void AnimationKeyEditor::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_track_editor_input_event"),&AnimationKeyEditor::_track_editor_input_event);
ObjectTypeDB::bind_method(_MD("_track_name_changed"),&AnimationKeyEditor::_track_name_changed);
ObjectTypeDB::bind_method(_MD("_track_menu_selected"),&AnimationKeyEditor::_track_menu_selected);
+ ObjectTypeDB::bind_method(_MD("_menu_add_track"),&AnimationKeyEditor::_menu_add_track);
ObjectTypeDB::bind_method(_MD("_menu_track"),&AnimationKeyEditor::_menu_track);
ObjectTypeDB::bind_method(_MD("_clear_selection_for_anim"),&AnimationKeyEditor::_clear_selection_for_anim);
ObjectTypeDB::bind_method(_MD("_select_at_anim"),&AnimationKeyEditor::_select_at_anim);
@@ -3503,27 +3694,40 @@ void AnimationKeyEditor::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_animation_optimize"),&AnimationKeyEditor::_animation_optimize);
ObjectTypeDB::bind_method(_MD("_curve_transition_changed"),&AnimationKeyEditor::_curve_transition_changed);
ObjectTypeDB::bind_method(_MD("_toggle_edit_curves"),&AnimationKeyEditor::_toggle_edit_curves);
+ ObjectTypeDB::bind_method(_MD("_add_call_track"),&AnimationKeyEditor::_add_call_track);
ADD_SIGNAL( MethodInfo("resource_selected", PropertyInfo( Variant::OBJECT, "res"),PropertyInfo( Variant::STRING, "prop") ) );
ADD_SIGNAL( MethodInfo("keying_changed" ) );
ADD_SIGNAL( MethodInfo("timeline_changed", PropertyInfo(Variant::REAL,"pos") ) );
ADD_SIGNAL( MethodInfo("animation_len_changed", PropertyInfo(Variant::REAL,"len") ) );
+ ADD_SIGNAL( MethodInfo("animation_step_changed", PropertyInfo(Variant::REAL,"step") ) );
ADD_SIGNAL( MethodInfo("key_edited", PropertyInfo(Variant::INT,"track"), PropertyInfo(Variant::INT,"key") ) );
}
-AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_history,EditorSelection *p_selection) {
+AnimationKeyEditor::AnimationKeyEditor() {
alc="animation_len_changed";
- editor_selection=p_selection;
+ editor_selection=EditorNode::get_singleton()->get_editor_selection();
selected_track=-1;
updating=false;
te_drawing=false;
- undo_redo=p_undo_redo;
- history=p_history;
+ undo_redo=EditorNode::get_singleton()->get_undo_redo();
+ history=EditorNode::get_singleton()->get_editor_history();
+
+ ec = memnew (Control);
+ ec->set_custom_minimum_size(Size2(0,150));
+ add_child(ec);
+ ec->set_v_size_flags(SIZE_EXPAND_FILL);
+
+ h_scroll = memnew( HScrollBar );
+ h_scroll->connect("value_changed",this,"_scroll_changed");
+ add_child(h_scroll);
+ h_scroll->set_val(0);
+
HBoxContainer *hb = memnew( HBoxContainer );
add_child(hb);
@@ -3535,15 +3739,6 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h
//menu->set_pos(Point2());
//add_child(menu);
- menu_track = memnew( MenuButton );
- menu_track->set_text("Tracks");
- hb->add_child(menu_track);
- menu_track->get_popup()->connect("item_pressed",this,"_menu_track");
-
-
-
- hb->add_child( memnew( VSeparator ) );
-
zoomicon = memnew( TextureFrame );
hb->add_child(zoomicon);
zoomicon->set_tooltip("Animation zoom.");
@@ -3601,6 +3796,10 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h
hb->add_child( memnew( VSeparator ) );
+ menu_add_track = memnew( MenuButton );
+ hb->add_child(menu_add_track);
+ menu_add_track->get_popup()->connect("item_pressed",this,"_menu_add_track");
+ menu_add_track->set_tooltip("Add new tracks.");
move_up_button = memnew( ToolButton );
hb->add_child(move_up_button);
@@ -3625,6 +3824,11 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h
hb->add_child(memnew( VSeparator ));
+ menu_track = memnew( MenuButton );
+ hb->add_child(menu_track);
+ menu_track->get_popup()->connect("item_pressed",this,"_menu_track");
+ menu_track->set_tooltip("Track tools");
+
edit_button = memnew( ToolButton );
edit_button->set_toggle_mode(true);
edit_button->set_focus_mode(FOCUS_NONE);
@@ -3681,10 +3885,6 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h
// menu->get_popup()->connect("item_pressed",this,"_menu_callback");
- ec = memnew (Control);
- ec->set_custom_minimum_size(Size2(0,150));
- add_child(ec);
- ec->set_v_size_flags(SIZE_EXPAND_FILL);
hb = memnew( HBoxContainer);
hb->set_area_as_parent_rect();
@@ -3761,12 +3961,6 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h
curve_edit->set_v_size_flags(SIZE_EXPAND_FILL);
key_editor_tab->add_child(curve_vb);
- h_scroll = memnew( HScrollBar );
- h_scroll->connect("value_changed",this,"_scroll_changed");
- add_child(h_scroll);
- h_scroll->set_val(0);
-
-
track_name = memnew( LineEdit );
track_name->set_as_toplevel(true);
track_name->hide();
@@ -3815,6 +4009,35 @@ AnimationKeyEditor::AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_h
scale_dialog->connect("confirmed",this,"_scale");
add_child(scale_dialog);
+ call_select = memnew( SceneTreeDialog );
+ add_child(call_select);
+ call_select->set_title("Call Functions in Which Node?");
+
+ cleanup_dialog = memnew( ConfirmationDialog );
+ add_child(cleanup_dialog);
+ VBoxContainer *cleanup_vb = memnew( VBoxContainer );
+ cleanup_dialog->add_child(cleanup_vb);
+ cleanup_dialog->set_child_rect(cleanup_vb);
+ cleanup_keys = memnew( CheckButton );
+ cleanup_keys->set_text("Remove invalid keys");
+ cleanup_keys->set_pressed(true);
+ cleanup_vb->add_child(cleanup_keys);
+
+ cleanup_tracks = memnew( CheckButton );
+ cleanup_tracks->set_text("Remove unresolved and empty tracks");
+ cleanup_tracks->set_pressed(true);
+ cleanup_vb->add_child(cleanup_tracks);
+
+ cleanup_all = memnew( CheckButton );
+ cleanup_all->set_text("Clean-Up all animations");
+ cleanup_vb->add_child(cleanup_all);
+
+ cleanup_dialog->set_title("Clean up Animation(s) (NO UNDO!)");
+ cleanup_dialog->get_ok()->set_text("Clean-Up");
+
+ cleanup_dialog->connect("confirmed",this,"_menu_track",varray(TRACK_MENU_CLEAN_UP_CONFIRM));
+
+ add_constant_override("separation",get_constant("separation","VBoxContainer"));
}
diff --git a/tools/editor/animation_editor.h b/tools/editor/animation_editor.h
index 35053fb6a3..c8a539179e 100644
--- a/tools/editor/animation_editor.h
+++ b/tools/editor/animation_editor.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -44,7 +44,7 @@
#include "scene_tree_editor.h"
#include "editor_data.h"
#include "property_editor.h"
-
+#include "scene_tree_editor.h"
class AnimationKeyEdit;
class AnimationCurveEdit;
@@ -70,9 +70,9 @@ class AnimationKeyEditor : public VBoxContainer {
enum {
- TRACK_MENU_ADD_VALUE_TRACK,
- TRACK_MENU_ADD_TRANSFORM_TRACK,
- TRACK_MENU_ADD_CALL_TRACK,
+ ADD_TRACK_MENU_ADD_VALUE_TRACK,
+ ADD_TRACK_MENU_ADD_TRANSFORM_TRACK,
+ ADD_TRACK_MENU_ADD_CALL_TRACK,
TRACK_MENU_SCALE,
TRACK_MENU_SCALE_PIVOT,
TRACK_MENU_MOVE_UP,
@@ -89,6 +89,8 @@ class AnimationKeyEditor : public VBoxContainer {
TRACK_MENU_NEXT_STEP,
TRACK_MENU_PREV_STEP,
TRACK_MENU_OPTIMIZE,
+ TRACK_MENU_CLEAN_UP,
+ TRACK_MENU_CLEAN_UP_CONFIRM,
CURVE_SET_LINEAR,
CURVE_SET_IN,
CURVE_SET_OUT,
@@ -190,8 +192,14 @@ class AnimationKeyEditor : public VBoxContainer {
SpinBox *optimize_angular_error;
SpinBox *optimize_max_angle;
+ ConfirmationDialog *cleanup_dialog;
+ CheckButton *cleanup_keys;
+ CheckButton *cleanup_tracks;
+ CheckButton *cleanup_all;
+
SpinBox *step;
+ MenuButton *menu_add_track;
MenuButton *menu_track;
HScrollBar *h_scroll;
@@ -206,6 +214,8 @@ class AnimationKeyEditor : public VBoxContainer {
PropertyEditor *key_editor;
+ SceneTreeDialog *call_select;
+
Ref<Animation> animation;
void _update_paths();
@@ -252,7 +262,7 @@ class AnimationKeyEditor : public VBoxContainer {
EditorSelection *editor_selection;
- AnimationKeyEditor();
+
float _get_zoom_scale() const;
@@ -281,9 +291,11 @@ class AnimationKeyEditor : public VBoxContainer {
void _animation_changed();
void _animation_optimize();
+ void _cleanup_animation(Ref<Animation> p_animation);
void _scroll_changed(double);
+ void _menu_add_track(int p_type);
void _menu_track(int p_type);
void _clear_selection_for_anim(const Ref<Animation>& p_anim);
@@ -299,6 +311,8 @@ class AnimationKeyEditor : public VBoxContainer {
void _toggle_edit_curves();
void _animation_len_update();
+ void _add_call_track(const NodePath& p_base);
+
void _root_removed();
protected:
@@ -320,7 +334,7 @@ public:
void insert_value_key(const String& p_property, const Variant& p_value, bool p_advance);
void insert_transform_key(Spatial *p_node,const String& p_sub,const Transform& p_xform);
- AnimationKeyEditor(UndoRedo *p_undo_redo, EditorHistory *p_history, EditorSelection *p_selection);
+ AnimationKeyEditor();
~AnimationKeyEditor();
};
diff --git a/tools/editor/array_property_edit.cpp b/tools/editor/array_property_edit.cpp
new file mode 100644
index 0000000000..66c2782da5
--- /dev/null
+++ b/tools/editor/array_property_edit.cpp
@@ -0,0 +1,250 @@
+#include "array_property_edit.h"
+
+#include "editor_node.h"
+
+#define ITEMS_PER_PAGE 100
+
+Variant ArrayPropertyEdit::get_array() const{
+
+ Object*o = ObjectDB::get_instance(obj);
+ if (!o)
+ return Array();
+ Variant arr=o->get(property);
+ if (!arr.is_array()) {
+ Variant::CallError ce;
+ arr=Variant::construct(default_type,NULL,0,ce);
+ }
+ return arr;
+}
+
+void ArrayPropertyEdit::_notif_change() {
+ _change_notify();
+}
+void ArrayPropertyEdit::_notif_changev(const String& p_v) {
+
+ _change_notify(p_v.utf8().get_data());
+}
+
+void ArrayPropertyEdit::_set_size(int p_size) {
+
+ Variant arr = get_array();
+ arr.call("resize",p_size);
+ Object*o = ObjectDB::get_instance(obj);
+ if (!o)
+ return;
+
+ o->set(property,arr);
+
+}
+
+void ArrayPropertyEdit::_set_value(int p_idx,const Variant& p_value) {
+
+ Variant arr = get_array();
+ arr.set(p_idx,p_value);
+ Object*o = ObjectDB::get_instance(obj);
+ if (!o)
+ return;
+
+ o->set(property,arr);
+}
+
+bool ArrayPropertyEdit::_set(const StringName& p_name, const Variant& p_value){
+
+ String pn=p_name;
+
+ if (pn.begins_with("array/")) {
+
+ if (pn=="array/size") {
+
+ Variant arr = get_array();
+ int size = arr.call("size");
+
+ int newsize=p_value;
+ if (newsize==size)
+ return true;
+
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Resize Array");
+ ur->add_do_method(this,"_set_size",newsize);
+ ur->add_undo_method(this,"_set_size",size);
+ if (newsize<size) {
+ for(int i=newsize;i<size;i++) {
+ ur->add_undo_method(this,"_set_value",i,arr.get(i));
+
+ }
+ } else if (newsize>size && size) {
+
+ Variant init;
+ Variant::CallError ce;
+ init = Variant::construct(arr.get(size-1).get_type(),NULL,0,ce);
+ for(int i=size;i<newsize;i++) {
+ ur->add_do_method(this,"_set_value",i,init);
+ }
+
+ }
+ ur->add_do_method(this,"_notif_change");
+ ur->add_undo_method(this,"_notif_change");
+ ur->commit_action();
+ return true;
+ }
+ if (pn=="array/page") {
+ page=p_value;
+ _change_notify();
+ return true;
+ }
+
+ } else if (pn.begins_with("indices")) {
+
+ if (pn.find("_")!=-1) {
+ //type
+ int idx=pn.get_slicec('/',1).get_slicec('_',0).to_int();
+
+ int type = p_value;
+
+ Variant arr = get_array();
+
+ Variant value = arr.get(idx);
+ if (value.get_type()!=type && type>=0 && type<Variant::VARIANT_MAX) {
+ Variant::CallError ce;
+ Variant new_value=Variant::construct(Variant::Type(type),NULL,0,ce);
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+
+ ur->create_action("Change Array Value Type");
+ ur->add_do_method(this,"_set_value",idx,new_value);
+ ur->add_undo_method(this,"_set_value",idx,value);
+ ur->add_do_method(this,"_notif_change");
+ ur->add_undo_method(this,"_notif_change");
+ ur->commit_action();
+
+ }
+ return true;
+
+ } else {
+ int idx=pn.get_slicec('/',1).to_int();
+ Variant arr = get_array();
+
+ Variant value = arr.get(idx);
+ UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
+
+ ur->create_action("Change Array Value");
+ ur->add_do_method(this,"_set_value",idx,p_value);
+ ur->add_undo_method(this,"_set_value",idx,value);
+ ur->add_do_method(this,"_notif_changev",p_name);
+ ur->add_undo_method(this,"_notif_changev",p_name);
+ ur->commit_action();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ArrayPropertyEdit::_get(const StringName& p_name,Variant &r_ret) const {
+
+ Variant arr = get_array();
+ //int size = arr.call("size");
+
+ String pn=p_name;
+ if (pn.begins_with("array/")) {
+
+ if (pn=="array/size") {
+ r_ret=arr.call("size");
+ return true;
+ }
+ if (pn=="array/page") {
+ r_ret=page;
+ return true;
+ }
+ } else if (pn.begins_with("indices")) {
+
+ if (pn.find("_")!=-1) {
+ //type
+ int idx=pn.get_slicec('/',1).get_slicec('_',0).to_int();
+ bool valid;
+ r_ret=arr.get(idx,&valid);
+ if (valid)
+ r_ret=r_ret.get_type();
+ return valid;
+
+ } else {
+ int idx=pn.get_slicec('/',1).to_int();
+ bool valid;
+ r_ret=arr.get(idx,&valid);
+ return valid;
+ }
+ }
+
+ return false;
+}
+
+void ArrayPropertyEdit::_get_property_list( List<PropertyInfo> *p_list) const{
+
+ Variant arr = get_array();
+ int size = arr.call("size");
+
+ p_list->push_back( PropertyInfo(Variant::INT,"array/size",PROPERTY_HINT_RANGE,"0,100000,1") );
+ int pages = size/ITEMS_PER_PAGE;
+ if (pages>0)
+ p_list->push_back( PropertyInfo(Variant::INT,"array/page",PROPERTY_HINT_RANGE,"0,"+itos(pages)+",1") );
+
+ int offset=page*ITEMS_PER_PAGE;
+
+ int items=MIN(size-offset,ITEMS_PER_PAGE);
+
+
+ for(int i=0;i<items;i++) {
+
+ Variant v=arr.get(i+offset);
+ if (arr.get_type()==Variant::ARRAY) {
+ p_list->push_back(PropertyInfo(Variant::INT,"indices/"+itos(i+offset)+"_type",PROPERTY_HINT_ENUM,vtypes));
+ }
+ if (arr.get_type()!=Variant::ARRAY || v.get_type()!=Variant::NIL) {
+ PropertyInfo pi(v.get_type(),"indices/"+itos(i+offset));
+ if (v.get_type()==Variant::OBJECT) {
+ pi.hint=PROPERTY_HINT_RESOURCE_TYPE;
+ pi.hint_string="Resource";
+ }
+ p_list->push_back(pi);
+ }
+ }
+
+}
+
+void ArrayPropertyEdit::edit(Object* p_obj,const StringName& p_prop,Variant::Type p_deftype) {
+
+ page=0;
+ property=p_prop;
+ obj=p_obj->get_instance_ID();
+ default_type=p_deftype;
+
+}
+
+Node *ArrayPropertyEdit::get_node() {
+
+ Object *o = ObjectDB::get_instance(obj);
+ if (!o)
+ return NULL;
+
+ return o->cast_to<Node>();
+}
+
+void ArrayPropertyEdit::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("_set_size"),&ArrayPropertyEdit::_set_size);
+ ObjectTypeDB::bind_method(_MD("_set_value"),&ArrayPropertyEdit::_set_value);
+ ObjectTypeDB::bind_method(_MD("_notif_change"),&ArrayPropertyEdit::_notif_change);
+ ObjectTypeDB::bind_method(_MD("_notif_changev"),&ArrayPropertyEdit::_notif_changev);
+}
+
+ArrayPropertyEdit::ArrayPropertyEdit()
+{
+ page=0;
+ for(int i=0;i<Variant::VARIANT_MAX;i++) {
+
+ if (i>0)
+ vtypes+=",";
+ vtypes+=Variant::get_type_name( Variant::Type(i) );
+ }
+ default_type=Variant::NIL;
+
+}
diff --git a/tools/editor/array_property_edit.h b/tools/editor/array_property_edit.h
new file mode 100644
index 0000000000..948b2a71a3
--- /dev/null
+++ b/tools/editor/array_property_edit.h
@@ -0,0 +1,38 @@
+#ifndef ARRAY_PROPERTY_EDIT_H
+#define ARRAY_PROPERTY_EDIT_H
+
+#include "scene/main/node.h"
+
+class ArrayPropertyEdit : public Reference {
+
+ OBJ_TYPE(ArrayPropertyEdit,Reference);
+
+ int page;
+ ObjectID obj;
+ StringName property;
+ String vtypes;
+ Variant get_array() const;
+ Variant::Type default_type;
+
+ void _notif_change();
+ void _notif_changev(const String& p_v);
+ void _set_size(int p_size);
+ void _set_value(int p_idx,const Variant& p_value);
+
+protected:
+
+ static void _bind_methods();
+ bool _set(const StringName& p_name, const Variant& p_value);
+ bool _get(const StringName& p_name,Variant &r_ret) const;
+ void _get_property_list( List<PropertyInfo> *p_list) const;
+
+public:
+
+ void edit(Object* p_obj, const StringName& p_prop, Variant::Type p_deftype);
+
+ Node *get_node();
+
+ ArrayPropertyEdit();
+};
+
+#endif // ARRAY_PROPERTY_EDIT_H
diff --git a/tools/editor/call_dialog.cpp b/tools/editor/call_dialog.cpp
index 0e3abcf4ef..edcd7371f2 100644
--- a/tools/editor/call_dialog.cpp
+++ b/tools/editor/call_dialog.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/call_dialog.h b/tools/editor/call_dialog.h
index fe69847796..2d04e7b6cd 100644
--- a/tools/editor/call_dialog.h
+++ b/tools/editor/call_dialog.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/code_editor.cpp b/tools/editor/code_editor.cpp
index 2ed03a1858..fe863bfebc 100644
--- a/tools/editor/code_editor.cpp
+++ b/tools/editor/code_editor.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -612,13 +612,15 @@ CodeTextEditor::CodeTextEditor() {
if (!font_overrode)
text_editor->add_font_override("font",get_font("source","Fonts"));
+
text_editor->set_show_line_numbers(true);
text_editor->set_brace_matching(true);
+ text_editor->set_auto_indent(true);
line_col = memnew( Label );
add_child(line_col);
line_col->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_END,135);
- line_col->set_anchor_and_margin(MARGIN_TOP,ANCHOR_END,20);
+ line_col->set_anchor_and_margin(MARGIN_TOP,ANCHOR_END,15);
line_col->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_END,1);
line_col->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,5);
//line_col->set_align(Label::ALIGN_RIGHT);
@@ -637,7 +639,7 @@ CodeTextEditor::CodeTextEditor() {
error = memnew( Label );
add_child(error);
error->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_BEGIN,5);
- error->set_anchor_and_margin(MARGIN_TOP,ANCHOR_END,20);
+ error->set_anchor_and_margin(MARGIN_TOP,ANCHOR_END,15);
error->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_END,1);
error->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,130);
error->hide();
diff --git a/tools/editor/code_editor.h b/tools/editor/code_editor.h
index 0c32aeb68f..5ed7ce9052 100644
--- a/tools/editor/code_editor.h
+++ b/tools/editor/code_editor.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/connections_dialog.cpp b/tools/editor/connections_dialog.cpp
index 13612c8e7a..e94bc78f5d 100644
--- a/tools/editor/connections_dialog.cpp
+++ b/tools/editor/connections_dialog.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -163,6 +163,7 @@ void ConnectDialog::edit(Node *p_node) {
dst_path->set_text("");
dst_method->set_text("");
deferred->set_pressed(false);
+ oneshot->set_pressed(false);
cdbinds->params.clear();
cdbinds->notify_changed();
}
@@ -196,6 +197,11 @@ bool ConnectDialog::get_deferred() const {
return deferred->is_pressed();
}
+bool ConnectDialog::get_oneshot() const {
+
+ return oneshot->is_pressed();
+}
+
StringName ConnectDialog::get_dst_method() const {
String txt=dst_method->get_text();
@@ -423,12 +429,13 @@ ConnectDialog::ConnectDialog() {
dstm_hb->add_child(make_callback);
deferred = memnew( CheckButton );
- deferred->set_toggle_mode(true);
- deferred->set_pressed(true);
deferred->set_text("Deferred");
dstm_hb->add_child(deferred);
-
+ oneshot = memnew( CheckButton );
+ oneshot->set_text("Oneshot");
+ dstm_hb->add_child(oneshot);
+
/*
realtime = memnew( CheckButton );
realtime->set_anchor( MARGIN_TOP, ANCHOR_END );
@@ -496,11 +503,13 @@ void ConnectionsDialog::_connect() {
StringName dst_method=connect_dialog->get_dst_method();
bool defer=connect_dialog->get_deferred();
+ bool oshot=connect_dialog->get_oneshot();
Vector<Variant> binds = connect_dialog->get_binds();
StringArray args = it->get_metadata(0).operator Dictionary()["args"];
+ int flags = CONNECT_PERSIST | (defer?CONNECT_DEFERRED:0) | (oshot?CONNECT_ONESHOT:0);
undo_redo->create_action("Connect '"+signal+"' to '"+String(dst_method)+"'");
- undo_redo->add_do_method(node,"connect",signal,target,dst_method,binds,CONNECT_PERSIST | (defer?CONNECT_DEFERRED:0));
+ undo_redo->add_do_method(node,"connect",signal,target,dst_method,binds,flags);
undo_redo->add_undo_method(node,"disconnect",signal,target,dst_method);
undo_redo->add_do_method(this,"update_tree");
undo_redo->add_undo_method(this,"update_tree");
@@ -530,7 +539,7 @@ void ConnectionsDialog::ok_pressed() {
get_ok()->set_disabled(true);
return;
}
- if (item->get_parent()==tree->get_root()) {
+ if (item->get_parent()==tree->get_root() || item->get_parent()->get_parent()==tree->get_root()) {
//a signal - connect
String signal=item->get_metadata(0).operator Dictionary()["name"];
String signalname=signal;
@@ -731,6 +740,8 @@ void ConnectionsDialog::update_tree() {
String path = String(node->get_path_to(target))+" :: "+c.method+"()";
if (c.flags&CONNECT_DEFERRED)
path+=" (deferred)";
+ if (c.flags&CONNECT_ONESHOT)
+ path+=" (oneshot)";
if (c.binds.size()) {
path+=" binds( ";
@@ -778,7 +789,7 @@ void ConnectionsDialog::_something_selected() {
get_ok()->set_text("Connect..");
get_ok()->set_disabled(true);
- } else if (item->get_parent()==tree->get_root()) {
+ } else if (item->get_parent()==tree->get_root() || item->get_parent()->get_parent()==tree->get_root()) {
//a signal - connect
get_ok()->set_text("Connect..");
get_ok()->set_disabled(false);
diff --git a/tools/editor/connections_dialog.h b/tools/editor/connections_dialog.h
index 68b13bf07a..d5e228e799 100644
--- a/tools/editor/connections_dialog.h
+++ b/tools/editor/connections_dialog.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -58,6 +58,7 @@ class ConnectDialog : public ConfirmationDialog {
//MenuButton *dst_method_list;
OptionButton *type_list;
CheckButton *deferred;
+ CheckButton *oneshot;
CheckButton *make_callback;
PropertyEditor *bind_editor;
Node *node;
@@ -80,6 +81,7 @@ public:
NodePath get_dst_path() const;
StringName get_dst_method() const;
bool get_deferred() const;
+ bool get_oneshot() const;
Vector<Variant> get_binds() const;
void set_dst_method(const StringName& p_method);
void set_dst_node(Node* p_node);
diff --git a/tools/editor/console.cpp b/tools/editor/console.cpp
deleted file mode 100644
index 0c98f05706..0000000000
--- a/tools/editor/console.cpp
+++ /dev/null
@@ -1,386 +0,0 @@
-/*************************************************************************/
-/* console.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* http://www.godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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. */
-/*************************************************************************/
-#include "console.h"
-#include "os/os.h"
-#include "os/keyboard.h"
-
-#include "editor_icons.h"
-#include "scene/gui/label.h"
-#include "globals.h"
-
-
-void Console::_stats_update_timer_callback() {
-
- if (!status->is_visible())
- return;
-
- VisualServer *vs = VisualServer::get_singleton();
-
- stats.render_objects_in_frame->set_text(1,String::num(vs->get_render_info( VisualServer::INFO_OBJECTS_IN_FRAME ) ) );
- stats.material_changes_in_frame->set_text(1,String::num(vs->get_render_info( VisualServer::INFO_MATERIAL_CHANGES_IN_FRAME ) ) );
-
- int64_t total_vmem = vs->get_render_info( VisualServer::INFO_USAGE_VIDEO_MEM_TOTAL );
- if (total_vmem<0)
- stats.usage_video_mem_total->set_text(1, "Unknown");
- else
- stats.usage_video_mem_total->set_text(1,String::humanize_size( total_vmem ) );
-
- stats.usage_video_mem_used->set_text(1,String::humanize_size( vs->get_render_info( VisualServer::INFO_VIDEO_MEM_USED ) ) );
- stats.usage_texture_mem_used->set_text(1,String::humanize_size( vs->get_render_info( VisualServer::INFO_TEXTURE_MEM_USED ) ) );
- stats.usage_vertex_mem_used->set_text(1,String::humanize_size( vs->get_render_info( VisualServer::INFO_VERTEX_MEM_USED ) ) );
-
-
- stats.usage_static_memory_total->set_text(1,String::humanize_size( Memory::get_static_mem_available() ) );
- stats.usage_static_memory->set_text(1,String::humanize_size( Memory::get_static_mem_usage() ) );
- stats.usage_dynamic_memory_total->set_text(1,String::humanize_size( Memory::get_dynamic_mem_available() ) );
- stats.usage_dynamic_memory->set_text(1,String::humanize_size( Memory::get_dynamic_mem_usage() ) );
- stats.usage_objects_instanced->set_text(1,String::num( ObjectDB::get_object_count()) );
-
-
-}
-
-void Console::_print_handle(void *p_this,const String& p_string) {
-
-
- return;
- Console *self = (Console*)p_this;
-
- OutputQueue oq;
- oq.text=p_string;
- oq.type=OutputStrings::LINE_NORMAL;
-
-
- if (self->output_queue_mutex)
- self->output_queue_mutex->lock();
-
- self->output_queue.push_back(oq);
-
- if (self->output_queue_mutex)
- self->output_queue_mutex->unlock();
-
-}
-void Console::_error_handle(void *p_this,const char*p_function,const char* p_file,int p_line,const char *p_error, const char *p_explanation,ErrorHandlerType p_type) {
-
-
- Console *self = (Console*)p_this;
-
- OutputQueue oq;
- oq.text="ERROR: "+String(p_file)+":"+itos(p_line)+", in function: "+String(p_function);
- oq.text+="\n "+String(p_error)+".";
- if (p_explanation && p_explanation[0])
- oq.text+="\n Reason: "+String(p_explanation);
- oq.text+="\n";
- oq.type=OutputStrings::LINE_ERROR;
-
-
- if (self->output_queue_mutex)
- self->output_queue_mutex->lock();
-
- self->output_queue.push_back(oq);
-
- if (self->output_queue_mutex)
- self->output_queue_mutex->unlock();
-
-
-}
-
-void Console::_window_input_event(InputEvent p_event) {
-
- Control::_window_input_event(p_event);
-
- if (p_event.type==InputEvent::KEY && p_event.key.pressed) {
-
- if (p_event.key.scancode==KEY_QUOTELEFT && p_event.key.mod.control) {
-
- if (is_visible())
- hide();
- else {
- globals_property_editor->edit( NULL );
- globals_property_editor->edit( Globals::get_singleton() );
- show();
- };
- }
-
- if (p_event.key.scancode==KEY_ESCAPE && !window_has_modal_stack() && is_visible()) {
- hide();
- get_tree()->call_group(0,"windows","_cancel_input_ID",p_event.ID);
- }
-
-
- }
-}
-
-void Console::_window_resize_event() {
-
-// Control::_window_resize_event();
- _resized();
-}
-
-
-void Console::_resized() {
-
- set_pos( Point2( 0, OS::get_singleton()->get_video_mode().height-height) );
- set_size( Size2( OS::get_singleton()->get_video_mode().width, height) );
-}
-
-void Console::_notification(int p_what) {
-
- switch(p_what) {
-
- case NOTIFICATION_ENTER_TREE: {
-
- _resized();
- show();
- globals_property_editor->edit( Globals::get_singleton() );
-
- } break;
-
- case NOTIFICATION_PROCESS: {
- //pop messies
-
- if (output_queue_mutex)
- output_queue_mutex->lock();
-
- while(output_queue.size()) {
-
- OutputQueue q = output_queue.front()->get();
- if (q.type==OutputStrings::LINE_ERROR || q.type==OutputStrings::LINE_WARNING)
- errors->add_line(q.text,q.meta,q.type);
- output->add_line(q.text,q.meta,q.type);
- output_queue.pop_front();
- }
-
- if (output_queue_mutex)
- output_queue_mutex->unlock();
-
- } break;
- case NOTIFICATION_DRAW: {
-
- RID ci = get_canvas_item();
- get_stylebox("panel","Panel")->draw(ci,Rect2(Point2(),get_size()));
-
- } break;
- }
-}
-
-
-void Console::_close_pressed() {
-
- hide();
-}
-
-void Console::_inspector_node_selected() {
-
-
- Node *node = inspect_tree_editor->get_selected();
-
- if (!node)
- inspect_property_editor->edit(NULL);
- else {
-
- inspect_history.add_object(node->get_instance_ID());
-
- inspect_property_editor->edit(node);
- }
-
-}
-
-void Console::_bind_methods() {
-
- ObjectTypeDB::bind_method("_stats_update_timer_callback",&Console::_stats_update_timer_callback);
- ObjectTypeDB::bind_method("_close_pressed",&Console::_close_pressed);
- ObjectTypeDB::bind_method("_inspector_node_selected",&Console::_inspector_node_selected);
-}
-
-
-Console::Console() {
-
- Ref<Theme> theme( memnew( Theme ) );
- set_theme( theme );
- editor_register_icons(theme);
-
- height=300;
- tabs = memnew( TabContainer );
- tabs->set_tab_align(TabContainer::ALIGN_LEFT);
- add_child(tabs);
- tabs->set_area_as_parent_rect();
-
- output = memnew( OutputStrings );
- output->set_name("Output");
- tabs->add_child(output);
- errors = memnew( OutputStrings );
- errors->set_name("Errors");
- tabs->add_child(errors);
- status = memnew( Control );
- status->set_name("Stats");
- tabs->add_child(status);
- inspect = memnew( Control );
- inspect->set_name("Inspect");
- tabs->add_child(inspect);
- globals = memnew( Control );
- globals->set_name("Globals");
- tabs->add_child(globals);
-
- // stats
-
- stats_tree = memnew( Tree );
- stats_tree->set_hide_root(true);
- stats_tree->set_columns(2);
- status->add_child(stats_tree);
- stats_tree->set_anchor( MARGIN_BOTTOM, ANCHOR_END );
- stats_tree->set_anchor( MARGIN_RIGHT, ANCHOR_RATIO );
- stats_tree->set_margin( MARGIN_RIGHT, 0.5 );
- stats_tree->set_begin( Point2( 20,25 ) );
- stats_tree->set_end( Point2( 0.5,5 ) );
-
- Label *stats_label = memnew( Label );
- stats_label->set_text("Engine Statistics:");
- stats_label->set_pos( Point2( 5,5 ) );
- status->add_child(stats_label);
-
- TreeItem *stats_tree_root = stats_tree->create_item(NULL);
-
- {
- //system items
- TreeItem *system_item = stats_tree->create_item(stats_tree_root);
- system_item->set_text(0,"System");
-
- stats.usage_static_memory_total = stats_tree->create_item(system_item);
- stats.usage_static_memory_total->set_text(0,"Total Static Mem");;
- stats.usage_static_memory = stats_tree->create_item(system_item);
- stats.usage_static_memory->set_text(0,"Static Mem Usage");;
- stats.usage_dynamic_memory_total = stats_tree->create_item(system_item);
- stats.usage_dynamic_memory_total->set_text(0,"Total Dynamic Mem");;
- stats.usage_dynamic_memory = stats_tree->create_item(system_item);
- stats.usage_dynamic_memory->set_text(0,"Dynamic Mem Usage");
- stats.usage_objects_instanced = stats_tree->create_item(system_item);
- stats.usage_objects_instanced->set_text(0,"Instanced Objects");
-
- //render items
- TreeItem *render_item = stats_tree->create_item(stats_tree_root);
- render_item->set_text(0,"Render");
- stats.render_objects_in_frame = stats_tree->create_item(render_item);
- stats.render_objects_in_frame->set_text(0,"Visible Objects");
- stats.material_changes_in_frame = stats_tree->create_item(render_item);
- stats.material_changes_in_frame->set_text(0,"Material Changes");
- stats.usage_video_mem_total = stats_tree->create_item(render_item);
- stats.usage_video_mem_total->set_text(0,"Total Video Mem");
- stats.usage_texture_mem_used = stats_tree->create_item(render_item);
- stats.usage_texture_mem_used->set_text(0,"Texture Mem Usage");
- stats.usage_vertex_mem_used = stats_tree->create_item(render_item);
- stats.usage_vertex_mem_used->set_text(0,"Vertex Mem Usage");
- stats.usage_video_mem_used = stats_tree->create_item(render_item);
- stats.usage_video_mem_used->set_text(0,"Combined Mem Usage");
- }
-
- {
-
- inspect_tree_editor = memnew( SceneTreeEditor );
- inspect_tree_editor->set_anchor( MARGIN_RIGHT, ANCHOR_RATIO );
- inspect_tree_editor->set_anchor( MARGIN_BOTTOM, ANCHOR_END );
- inspect_tree_editor->set_begin( Point2( 20, 5 ) );
- inspect_tree_editor->set_end( Point2( 0.49, 5 ) );
- inspect->add_child(inspect_tree_editor);
-
- inspect_property_editor = memnew( PropertyEditor );
- inspect_property_editor->set_anchor( MARGIN_LEFT, ANCHOR_RATIO );
- inspect_property_editor->set_anchor( MARGIN_RIGHT, ANCHOR_END );
- inspect_property_editor->set_anchor( MARGIN_BOTTOM, ANCHOR_END );
- inspect_property_editor->set_begin( Point2( 0.51, 5 ) );
- inspect_property_editor->set_end( Point2( 5, 5 ) );
- inspect->add_child(inspect_property_editor);
- }
-
-
- { //globals
-
- globals_property_editor = memnew( PropertyEditor );
- globals_property_editor->set_anchor( MARGIN_RIGHT, ANCHOR_END );
- globals_property_editor->set_anchor( MARGIN_BOTTOM, ANCHOR_END );
- globals_property_editor->set_begin( Point2( 15, 5 ) );
- globals_property_editor->set_end( Point2( 5, 5 ) );
- globals_property_editor->get_top_label()->set_text("Globals Editor:");
- globals->add_child(globals_property_editor);
-
- }
-
-
-#ifndef NO_THREADS
- output_queue_mutex = Mutex::create();
-#else
- output_queue_mutex = NULL;
-#endif
-
-
- hide();
- set_process(true);
-
- close = memnew( Button );
- add_child(close);
- close->set_anchor( MARGIN_LEFT, ANCHOR_END);
- close->set_anchor( MARGIN_RIGHT, ANCHOR_END);
- close->set_begin( Point2( 25, 3 ) );
- close->set_end( Point2( 5, 3 ) );
- close->set_flat(true);
- close->connect("pressed", this,"_close_pressed");
-
-
- close->set_icon( get_icon("close","Icons") );
-// force_top_viewport(true);
-
-
- err_handler.userdata=this;
- err_handler.errfunc=_error_handle;
- add_error_handler(&err_handler);
-
- print_handler.userdata=this;
- print_handler.printfunc=_print_handle;
- add_print_handler(&print_handler);
-
- Timer *timer = memnew( Timer );
- add_child(timer);
- timer->set_wait_time(1);
- timer->start();
- timer->connect("timeout", this,"_stats_update_timer_callback");
- inspect_tree_editor->connect("node_selected", this,"_inspector_node_selected");
-
-
-
-}
-
-
-Console::~Console() {
-
- if (output_queue_mutex)
- memdelete(output_queue_mutex);
-
- remove_error_handler(&err_handler);
- remove_print_handler(&print_handler);
-
-}
diff --git a/tools/editor/console.h b/tools/editor/console.h
deleted file mode 100644
index aff425fcde..0000000000
--- a/tools/editor/console.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*************************************************************************/
-/* console.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* http://www.godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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. */
-/*************************************************************************/
-#ifndef CONSOLE_H
-#define CONSOLE_H
-
-#include "scene/gui/popup.h"
-#include "scene/gui/button.h"
-#include "scene/gui/tab_container.h"
-#include "scene/gui/tree.h"
-#include "scene/main/timer.h"
-#include "output_strings.h"
-#include "property_editor.h"
-#include "scene_tree_editor.h"
-#include "editor_data.h"
-
-class Console : public Popup {
-
- OBJ_TYPE( Console, Popup );
-
- TabContainer *tabs;
- OutputStrings *output;
- OutputStrings *errors;
- Control *status;
- Control *inspect;
- Control *globals;
- Button *close;
- int height;
-
- EditorHistory inspect_history;
- SceneTreeEditor *inspect_tree_editor;
- PropertyEditor *inspect_property_editor;
- PropertyEditor *globals_property_editor;
-
- Tree *stats_tree;
-
- struct StatsItems {
-
- TreeItem *render_objects_in_frame;
- TreeItem *material_changes_in_frame;
-
- TreeItem *usage_video_mem_total;
- TreeItem *usage_video_mem_used;
- TreeItem *usage_texture_mem_used;
- TreeItem *usage_vertex_mem_used;
-
- TreeItem *usage_static_memory_total;
- TreeItem *usage_static_memory;
- TreeItem *usage_dynamic_memory_total;
- TreeItem *usage_dynamic_memory;
- TreeItem *usage_objects_instanced;
-
- } stats;
-
- struct OutputQueue {
-
- OutputStrings::LineType type;
- Variant meta;
- String text;
- };
-
- Mutex *output_queue_mutex;
- List<OutputQueue> output_queue;
-
-
- ErrorHandlerList err_handler;
- PrintHandlerList print_handler;
-
- void _inspector_node_selected();
-
- static void _error_handle(void *p_this,const char*p_function,const char* p_file,int p_line,const char *p_error, const char *p_explanation,ErrorHandlerType p_type);
- static void _print_handle(void *p_this,const String& p_string);
-
-protected:
-
- virtual void _window_input_event(InputEvent p_event);
- virtual void _window_resize_event();
-
- void _stats_update_timer_callback();
- void _resized();
- void _close_pressed();
-
- void _notification(int p_what);
-
- static void _bind_methods();
-public:
- Console();
- ~Console();
-};
-
-#endif // CONSOLE_H
diff --git a/tools/editor/create_dialog.cpp b/tools/editor/create_dialog.cpp
index c0f35a4ac2..0f39d72308 100644
--- a/tools/editor/create_dialog.cpp
+++ b/tools/editor/create_dialog.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -128,7 +128,7 @@ void CreateDialog::_update_search() {
_parse_fs(EditorFileSystem::get_singleton()->get_filesystem());
*/
- List<String> type_list;
+ List<StringName> type_list;
ObjectTypeDB::get_type_list(&type_list);
HashMap<String,TreeItem*> types;
@@ -137,7 +137,7 @@ void CreateDialog::_update_search() {
root->set_text(0,base_type);
- List<String>::Element *I=type_list.front();
+ List<StringName>::Element *I=type_list.front();
TreeItem *to_select=NULL;
for(;I;I=I->next()) {
diff --git a/tools/editor/create_dialog.h b/tools/editor/create_dialog.h
index f200e1caf5..6f959fd467 100644
--- a/tools/editor/create_dialog.h
+++ b/tools/editor/create_dialog.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/default_saver.cpp b/tools/editor/default_saver.cpp
index c865adb1eb..611232e04b 100644
--- a/tools/editor/default_saver.cpp
+++ b/tools/editor/default_saver.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/default_saver.h b/tools/editor/default_saver.h
index 4e11ff5592..2b1a1edb23 100644
--- a/tools/editor/default_saver.h
+++ b/tools/editor/default_saver.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/dependency_editor.cpp b/tools/editor/dependency_editor.cpp
new file mode 100644
index 0000000000..7e63cfb1b4
--- /dev/null
+++ b/tools/editor/dependency_editor.cpp
@@ -0,0 +1,693 @@
+#include "dependency_editor.h"
+#include "os/file_access.h"
+#include "scene/gui/margin_container.h"
+#include "io/resource_loader.h"
+#include "editor_node.h"
+
+void DependencyEditor::_notification(int p_what){
+
+
+}
+
+void DependencyEditor::_searched(const String& p_path) {
+
+ Map<String,String> dep_rename;
+ dep_rename[replacing]=p_path;
+
+
+ ResourceLoader::rename_dependencies(editing,dep_rename);
+
+ _update_list();
+ _update_file();
+}
+
+void DependencyEditor::_load_pressed(Object* p_item,int p_cell,int p_button){
+
+ TreeItem *ti=p_item->cast_to<TreeItem>();
+ String fname = ti->get_text(0);
+ replacing = ti->get_text(1);
+
+ search->set_title("Search Replacement For: "+replacing.get_file());
+
+ search->clear_filters();
+ List<String> ext;
+ ResourceLoader::get_recognized_extensions_for_type(ti->get_metadata(0),&ext);
+ for (List<String>::Element *E=ext.front();E;E=E->next()) {
+ search->add_filter("*"+E->get());
+ }
+ search->popup_centered_ratio();
+
+}
+
+void DependencyEditor::_fix_and_find(EditorFileSystemDirectory *efsd, Map<String,Map<String,String> >& candidates){
+
+ for(int i=0;i<efsd->get_subdir_count();i++) {
+ _fix_and_find(efsd->get_subdir(i),candidates);
+ }
+
+ for(int i=0;i<efsd->get_file_count();i++) {
+
+ String file = efsd->get_file(i);
+ if (!candidates.has(file))
+ continue;
+
+ String path = efsd->get_file_path(i);
+ Map<String,String> &ss = candidates[file];
+
+
+ for(Map<String,String>::Element *E=candidates[file].front();E;E=E->next()) {
+
+ if (E->get()==String()) {
+ E->get()=path;
+ continue;
+ }
+
+ //must match the best, using subdirs
+ String existing=E->get().replace_first("res://","");
+ String current=path.replace_first("res://","");
+ String lost=E->key().replace_first("res://","");
+
+ Vector<String> existingv=existing.split("/");
+ existingv.invert();
+ Vector<String> currentv=current.split("/");
+ currentv.invert();
+ Vector<String> lostv=lost.split("/");
+ lostv.invert();
+
+ int existing_score=0;
+ int current_score=0;
+
+ for(int j=0;j<lostv.size();j++) {
+
+ if (j<existingv.size() && lostv[j]==existingv[j]) {
+ existing_score++;
+ }
+ if (j<currentv.size() && lostv[j]==currentv[j]) {
+ current_score++;
+ }
+ }
+
+ if (current_score > existing_score) {
+
+ //if it was the same, could track distance to new path but..
+
+ E->get()=path; //replace by more accurate
+ }
+
+ }
+
+ }
+
+}
+
+
+void DependencyEditor::_fix_all(){
+
+ if (!EditorFileSystem::get_singleton()->get_filesystem())
+ return;
+
+ Map<String,Map<String,String> > candidates;
+
+ for (List<String>::Element *E=missing.front();E;E=E->next()) {
+
+ String base = E->get().get_file();
+ if (!candidates.has(base)) {
+ candidates[base]=Map<String,String>();
+ }
+
+ candidates[base][E->get()]="";
+ }
+
+ _fix_and_find(EditorFileSystem::get_singleton()->get_filesystem(),candidates);
+
+ Map<String,String> remaps;
+
+ for (Map<String,Map<String,String> >::Element *E=candidates.front();E;E=E->next()) {
+
+ for (Map<String,String>::Element *F=E->get().front();F;F=F->next()) {
+
+ if (F->get()!=String()) {
+ remaps[F->key()]=F->get();
+ }
+ }
+
+ }
+
+ if (remaps.size()) {
+
+ ResourceLoader::rename_dependencies(editing,remaps);
+
+ _update_list();
+ _update_file();
+ }
+}
+
+void DependencyEditor::_update_file() {
+
+ EditorFileSystem::get_singleton()->update_file(editing);
+
+}
+
+void DependencyEditor::_update_list() {
+
+ List<String> deps;
+ ResourceLoader::get_dependencies(editing,&deps,true);
+
+ tree->clear();
+ missing.clear();
+
+ TreeItem *root = tree->create_item();
+
+ Ref<Texture> folder = get_icon("folder","FileDialog");
+
+ bool broken=false;
+
+ for(List<String>::Element *E=deps.front();E;E=E->next()) {
+
+ TreeItem *item = tree->create_item(root);
+
+ String n = E->get();
+ String path;
+ String type;
+
+ if (n.find("::")!=-1) {
+ path = n.get_slice("::",0);
+ type = n.get_slice("::",1);
+ } else {
+ path=n;
+ type="Resource";
+ }
+ String name = path.get_file();
+
+ Ref<Texture> icon;
+ if (has_icon(type,"EditorIcons")) {
+ icon=get_icon(type,"EditorIcons");
+ } else {
+ icon=get_icon("Object","EditorIcons");
+ }
+ item->set_text(0,name);
+ item->set_icon(0,icon);
+ item->set_metadata(0,type);
+ item->set_text(1,path);
+
+ if (!FileAccess::exists(path)) {
+ item->set_custom_color(1,Color(1,0.4,0.3));
+ missing.push_back(path);
+ broken=true;
+ }
+
+ item->add_button(1,folder,0);
+ }
+
+ fixdeps->set_disabled(!broken);
+
+}
+
+
+
+void DependencyEditor::edit(const String& p_path) {
+
+
+ editing=p_path;
+ set_title("Dependencies For: "+p_path.get_file());
+
+ _update_list();
+ popup_centered_ratio();
+
+ if (EditorNode::get_singleton()->is_scene_open(p_path)) {
+ EditorNode::get_singleton()->show_warning("Scene '"+p_path.get_file()+"' is currently being edited.\nChanges will not take effect unless reloaded.");
+ } else if (ResourceCache::has(p_path)) {
+ EditorNode::get_singleton()->show_warning("Resource '"+p_path.get_file()+"' is in use.\nChanges will take effect when reloaded.");
+ }
+}
+
+
+void DependencyEditor::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("_searched"),&DependencyEditor::_searched);
+ ObjectTypeDB::bind_method(_MD("_load_pressed"),&DependencyEditor::_load_pressed);
+ ObjectTypeDB::bind_method(_MD("_fix_all"),&DependencyEditor::_fix_all);
+
+}
+
+DependencyEditor::DependencyEditor() {
+
+ VBoxContainer *vb = memnew( VBoxContainer );
+ vb->set_name("Dependencies");
+ add_child(vb);
+ set_child_rect(vb);
+
+ tree = memnew( Tree );
+ tree->set_columns(2);
+ tree->set_column_titles_visible(true);
+ tree->set_column_title(0,"Resource");
+ tree->set_column_title(1,"Path");
+ tree->set_hide_root(true);
+ tree->connect("button_pressed",this,"_load_pressed");
+
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ Label *label = memnew( Label("Dependencies:"));
+ hbc->add_child(label);
+ hbc->add_spacer();
+ fixdeps = memnew( Button("Fix Broken"));
+ hbc->add_child(fixdeps);
+ fixdeps->connect("pressed",this,"_fix_all");
+
+ vb->add_child(hbc);
+
+ MarginContainer *mc = memnew( MarginContainer );
+ mc->set_v_size_flags(SIZE_EXPAND_FILL);
+
+ mc->add_child(tree);
+ vb->add_child(mc);
+
+ set_title("Dependency Editor");
+ search = memnew( EditorFileDialog );
+ search->connect("file_selected",this,"_searched");
+ search->set_mode(EditorFileDialog::MODE_OPEN_FILE);
+ search->set_title("Search Replacement Resource:");
+ add_child(search);
+
+}
+
+/////////////////////////////////////
+
+
+
+void DependencyEditorOwners::_fill_owners(EditorFileSystemDirectory *efsd) {
+
+ if (!efsd)
+ return;
+
+ for(int i=0;i<efsd->get_subdir_count();i++) {
+ _fill_owners(efsd->get_subdir(i));
+ }
+
+ for(int i=0;i<efsd->get_file_count();i++) {
+
+ Vector<String> deps = efsd->get_file_deps(i);
+ //print_line(":::"+efsd->get_file_path(i));
+ bool found=false;
+ for(int j=0;j<deps.size();j++) {
+ //print_line("\t"+deps[j]+" vs "+editing);
+ if (deps[j]==editing) {
+ //print_line("found");
+ found=true;
+ break;
+ }
+ }
+ if (!found)
+ continue;
+
+ Ref<Texture> icon;
+ String type=efsd->get_file_type(i);
+ if (!has_icon(type,"EditorIcons")) {
+ icon=get_icon("Object","EditorIcons");
+ } else {
+ icon=get_icon(type,"EditorIcons");
+ }
+
+ owners->add_item(efsd->get_file_path(i),icon);
+ }
+
+}
+
+void DependencyEditorOwners::show(const String& p_path) {
+
+ editing=p_path;
+ owners->clear();
+ _fill_owners(EditorFileSystem::get_singleton()->get_filesystem());
+ popup_centered_ratio();
+
+ set_title("Owners Of: "+p_path.get_file());
+
+}
+
+DependencyEditorOwners::DependencyEditorOwners() {
+
+
+ owners = memnew( ItemList );
+ add_child(owners);
+ set_child_rect(owners);
+
+
+}
+
+///////////////////////
+
+
+void DependencyRemoveDialog::_fill_owners(EditorFileSystemDirectory *efsd) {
+
+ if (!efsd)
+ return;
+
+ for(int i=0;i<efsd->get_subdir_count();i++) {
+ _fill_owners(efsd->get_subdir(i));
+ }
+
+ for(int i=0;i<efsd->get_file_count();i++) {
+
+ Vector<String> deps = efsd->get_file_deps(i);
+ //print_line(":::"+efsd->get_file_path(i));
+ Set<String> met;
+ for(int j=0;j<deps.size();j++) {
+ if (files.has(deps[j])) {
+ met.insert(deps[j]);
+ }
+ }
+ if (!met.size())
+ continue;
+
+ exist=true;
+
+ Ref<Texture> icon;
+ String type=efsd->get_file_type(i);
+ if (!has_icon(type,"EditorIcons")) {
+ icon=get_icon("Object","EditorIcons");
+ } else {
+ icon=get_icon(type,"EditorIcons");
+ }
+
+
+ for(Set<String>::Element *E=met.front();E;E=E->next()) {
+
+ String which = E->get();
+ if (!files[which]) {
+ TreeItem *ti=owners->create_item(owners->get_root());
+ ti->set_text(0,which.get_file());
+ files[which]=ti;
+
+ }
+ TreeItem *ti=owners->create_item(files[which]);
+ ti->set_text(0,efsd->get_file_path(i));
+ ti->set_icon(0,icon);
+ }
+
+ }
+
+}
+
+void DependencyRemoveDialog::show(const Vector<String> &to_erase) {
+
+ exist=false;
+ owners->clear();
+ files.clear();
+ TreeItem *root=owners->create_item();
+ for(int i=0;i<to_erase.size();i++) {
+ files[to_erase[i]]=NULL;
+ }
+
+ _fill_owners(EditorFileSystem::get_singleton()->get_filesystem());
+
+ if (exist) {
+ owners->show();
+ text->set_text("The files being removed are required by other resources in order for them to work.\nRemove them anyway? (no undo)");
+ popup_centered_minsize(Size2(500,220));
+ } else {
+ owners->hide();
+ text->set_text("Remove selected files from the project? (no undo)");
+ popup_centered_minsize(Size2(400,100));
+ }
+
+}
+
+void DependencyRemoveDialog::ok_pressed() {
+
+
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ for (Map<String,TreeItem*>::Element *E=files.front();E;E=E->next()) {
+
+ da->remove(E->key());
+ EditorFileSystem::get_singleton()->update_file(E->key());
+ }
+ memdelete(da);
+
+}
+
+DependencyRemoveDialog::DependencyRemoveDialog() {
+
+ VBoxContainer *vb = memnew( VBoxContainer );
+ add_child(vb);
+ set_child_rect(vb);
+
+ text = memnew( Label );
+ vb->add_child(text);
+
+ owners = memnew( Tree );
+ owners->set_hide_root(true);
+ vb->add_child(owners);
+ owners->set_v_size_flags(SIZE_EXPAND_FILL);
+ get_ok()->set_text("Remove");
+}
+
+
+//////////////
+
+
+void DependencyErrorDialog::show(const String& p_for_file,const Vector<String> &report) {
+
+
+ for_file=p_for_file;
+ set_title("Error loading: "+p_for_file.get_file());
+ files->clear();
+
+ TreeItem *root = files->create_item(NULL);
+ for(int i=0;i<report.size();i++) {
+
+ String dep;
+ String type="Object";
+ dep=report[i].get_slice("::",0);
+ if (report[i].get_slice_count("::")>0)
+ type=report[i].get_slice("::",1);
+
+ Ref<Texture> icon;
+ if (!has_icon(type,"EditorIcons")) {
+ icon=get_icon("Object","EditorIcons");
+ } else {
+ icon=get_icon(type,"EditorIcons");
+ }
+
+ TreeItem *ti=files->create_item(root);
+ ti->set_text(0,dep);
+ ti->set_icon(0,icon);
+
+ }
+
+ popup_centered_minsize(Size2(500,220));
+
+}
+
+void DependencyErrorDialog::ok_pressed() {
+
+ EditorNode::get_singleton()->load_scene(for_file,true);
+}
+
+void DependencyErrorDialog::custom_action(const String&) {
+
+ EditorNode::get_singleton()->fix_dependencies(for_file);
+}
+
+DependencyErrorDialog::DependencyErrorDialog() {
+
+ VBoxContainer *vb = memnew( VBoxContainer );
+ add_child(vb);
+ set_child_rect(vb);
+
+
+ files = memnew( Tree );
+ files->set_hide_root(true);
+ vb->add_margin_child("Scene failed to load due to missing dependencies:",files,true);
+ files->set_v_size_flags(SIZE_EXPAND_FILL);
+ get_ok()->set_text("Open Anyway");
+
+ text = memnew( Label );
+ vb->add_child(text);
+ text->set_text("Which action should be taken?");
+
+
+ fdep=add_button("Fix Dependencies",true,"fixdeps");
+
+ set_title("Errors loading!");
+
+}
+
+//////////////////////////////////////////////////////////////////////
+
+
+
+void OrphanResourcesDialog::ok_pressed() {
+
+ paths.clear();
+
+ _find_to_delete(files->get_root(),paths);
+ if (paths.empty())
+ return;
+
+ delete_confirm->set_text("Permanently Delete "+itos(paths.size())+" Item(s) ? (No Undo!!)");
+ delete_confirm->popup_centered_minsize();
+}
+
+bool OrphanResourcesDialog::_fill_owners(EditorFileSystemDirectory *efsd,HashMap<String,int>& refs,TreeItem* p_parent){
+
+
+ if (!efsd)
+ return false;
+
+ bool has_childs=false;
+
+ for(int i=0;i<efsd->get_subdir_count();i++) {
+
+ TreeItem *dir_item=NULL;
+ if (p_parent) {
+ dir_item = files->create_item(p_parent);
+ dir_item->set_text(0,efsd->get_subdir(i)->get_name());
+ dir_item->set_icon(0,get_icon("folder","FileDialog"));
+
+ }
+ bool children = _fill_owners(efsd->get_subdir(i),refs,dir_item);
+
+ if (p_parent) {
+ if (!children) {
+ memdelete(dir_item);
+ } else {
+ has_childs=true;
+ }
+ }
+
+ }
+
+
+ for(int i=0;i<efsd->get_file_count();i++) {
+
+ if (!p_parent) {
+ Vector<String> deps = efsd->get_file_deps(i);
+ //print_line(":::"+efsd->get_file_path(i));
+ for(int j=0;j<deps.size();j++) {
+
+ if (!refs.has(deps[j])) {
+ refs[deps[j]]=1;
+ }
+ }
+ } else {
+
+ String path = efsd->get_file_path(i);
+ if (!refs.has(path)) {
+ TreeItem *ti=files->create_item(p_parent);
+ ti->set_cell_mode(0,TreeItem::CELL_MODE_CHECK);
+ ti->set_text(0,efsd->get_file(i));
+ ti->set_editable(0,true);
+
+ String type=efsd->get_file_type(i);
+
+ Ref<Texture> icon;
+ if (has_icon(type,"EditorIcons")) {
+ icon=get_icon(type,"EditorIcons");
+ } else {
+ icon=get_icon("Object","EditorIcons");
+ }
+ ti->set_icon(0,icon);
+ int ds = efsd->get_file_deps(i).size();
+ ti->set_text(1,itos(ds));
+ if (ds) {
+ ti->add_button(1,get_icon("Visible","EditorIcons"));
+ }
+ ti->set_metadata(0,path);
+ has_childs=true;
+ }
+ }
+
+ }
+
+ return has_childs;
+}
+
+
+void OrphanResourcesDialog::refresh() {
+ HashMap<String,int> refs;
+ _fill_owners(EditorFileSystem::get_singleton()->get_filesystem(),refs,NULL);
+ files->clear();
+ TreeItem *root=files->create_item();
+ _fill_owners(EditorFileSystem::get_singleton()->get_filesystem(),refs,root);
+}
+
+
+void OrphanResourcesDialog::show(){
+
+ refresh();
+ popup_centered_ratio();
+}
+
+
+void OrphanResourcesDialog::_find_to_delete(TreeItem* p_item,List<String>& paths) {
+
+ while(p_item) {
+
+ if (p_item->get_cell_mode(0)==TreeItem::CELL_MODE_CHECK && p_item->is_checked(0)) {
+ paths.push_back(p_item->get_metadata(0));
+ }
+
+ if (p_item->get_children()) {
+ _find_to_delete(p_item->get_children(),paths);
+ }
+
+ p_item=p_item->get_next();
+ }
+
+
+}
+
+void OrphanResourcesDialog::_delete_confirm() {
+
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ for (List<String>::Element *E=paths.front();E;E=E->next()) {
+
+ da->remove(E->get());
+ EditorFileSystem::get_singleton()->update_file(E->get());
+ }
+ memdelete(da);
+ refresh();
+}
+
+void OrphanResourcesDialog::_button_pressed(Object *p_item,int p_column, int p_id) {
+
+ TreeItem *ti=p_item->cast_to<TreeItem>();
+
+ String path = ti->get_metadata(0);
+ dep_edit->edit(path);
+
+}
+
+void OrphanResourcesDialog::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("_delete_confirm"),&OrphanResourcesDialog::_delete_confirm);
+ ObjectTypeDB::bind_method(_MD("_button_pressed"),&OrphanResourcesDialog::_button_pressed);
+
+}
+
+OrphanResourcesDialog::OrphanResourcesDialog(){
+
+ VBoxContainer *vbc = memnew( VBoxContainer );
+ add_child(vbc);
+ set_child_rect(vbc);
+ files = memnew( Tree );
+ files->set_columns(2);
+ files->set_column_titles_visible(true);
+ files->set_column_min_width(1,100);
+ files->set_column_expand(0,true);
+ files->set_column_expand(1,false);
+ files->set_column_title(0,"Resource");
+ files->set_column_title(1,"Owns");
+ files->set_hide_root(true);
+ vbc->add_margin_child("Resources Without Explicit Ownership:",files,true);
+ set_title("Orphan Resource Explorer");
+ delete_confirm = memnew( ConfirmationDialog );
+ delete_confirm->set_text("Delete selected files?");
+ get_ok()->set_text("Delete");
+ add_child(delete_confirm);
+ dep_edit = memnew( DependencyEditor );
+ add_child(dep_edit);
+ files->connect("button_pressed",this,"_button_pressed");
+ delete_confirm->connect("confirmed",this,"_delete_confirm");
+ set_hide_on_ok(false);
+
+}
diff --git a/tools/editor/dependency_editor.h b/tools/editor/dependency_editor.h
new file mode 100644
index 0000000000..c372025ca0
--- /dev/null
+++ b/tools/editor/dependency_editor.h
@@ -0,0 +1,119 @@
+#ifndef DEPENDENCY_EDITOR_H
+#define DEPENDENCY_EDITOR_H
+
+#include "scene/gui/dialogs.h"
+#include "scene/gui/tree.h"
+#include "scene/gui/tab_container.h"
+#include "editor_file_dialog.h"
+
+class EditorFileSystemDirectory;
+
+class DependencyEditor : public AcceptDialog {
+ OBJ_TYPE(DependencyEditor,AcceptDialog);
+
+
+ Tree *tree;
+ Button *fixdeps;
+
+ EditorFileDialog *search;
+
+ String replacing;
+ String editing;
+ List<String> missing;
+
+
+ void _fix_and_find(EditorFileSystemDirectory *efsd, Map<String,Map<String,String> >& candidates);
+
+ void _searched(const String& p_path);
+ void _load_pressed(Object* p_item,int p_cell,int p_button);
+ void _fix_all();
+ void _update_list();
+
+ void _update_file();
+
+protected:
+
+ static void _bind_methods();
+ void _notification(int p_what);
+public:
+
+
+ void edit(const String& p_path);
+ DependencyEditor();
+};
+
+class DependencyEditorOwners : public AcceptDialog {
+ OBJ_TYPE(DependencyEditorOwners,AcceptDialog);
+
+ ItemList *owners;
+ String editing;
+ void _fill_owners(EditorFileSystemDirectory *efsd);
+
+public:
+
+ void show(const String& p_path);
+ DependencyEditorOwners();
+};
+
+class DependencyRemoveDialog : public ConfirmationDialog {
+ OBJ_TYPE(DependencyRemoveDialog,ConfirmationDialog);
+
+
+ Label *text;
+ Tree *owners;
+ bool exist;
+ Map<String,TreeItem*> files;
+ void _fill_owners(EditorFileSystemDirectory *efsd);
+
+ void ok_pressed();
+
+public:
+
+ void show(const Vector<String> &to_erase);
+ DependencyRemoveDialog();
+};
+
+
+class DependencyErrorDialog : public ConfirmationDialog {
+ OBJ_TYPE(DependencyErrorDialog,ConfirmationDialog);
+
+
+ String for_file;
+ Button *fdep;
+ Label *text;
+ Tree *files;
+ void ok_pressed();
+ void custom_action(const String&);
+
+public:
+
+ void show(const String& p_for,const Vector<String> &report);
+ DependencyErrorDialog();
+};
+
+
+
+class OrphanResourcesDialog : public ConfirmationDialog {
+ OBJ_TYPE(OrphanResourcesDialog,ConfirmationDialog);
+
+ DependencyEditor *dep_edit;
+ Tree *files;
+ ConfirmationDialog *delete_confirm;
+ void ok_pressed();
+
+ bool _fill_owners(EditorFileSystemDirectory *efsd, HashMap<String,int>& refs, TreeItem *p_parent);
+
+ List<String> paths;
+ void _find_to_delete(TreeItem* p_item,List<String>& paths);
+ void _delete_confirm();
+ void _button_pressed(Object *p_item,int p_column, int p_id);
+
+ void refresh();
+ static void _bind_methods();
+public:
+
+ void show();
+ OrphanResourcesDialog();
+};
+
+#endif // DEPENDENCY_EDITOR_H
diff --git a/tools/editor/doc_code_font.h b/tools/editor/doc_code_font.h
index 91f67c4a41..879c873ea1 100644
--- a/tools/editor/doc_code_font.h
+++ b/tools/editor/doc_code_font.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/doc_font.h b/tools/editor/doc_font.h
index f2e5e7950b..a3c3b58b21 100644
--- a/tools/editor/doc_font.h
+++ b/tools/editor/doc_font.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/doc_title_font.h b/tools/editor/doc_title_font.h
index fb6b4eaf5b..75a3f049f0 100644
--- a/tools/editor/doc_title_font.h
+++ b/tools/editor/doc_title_font.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/editor_data.cpp b/tools/editor/editor_data.cpp
index c4808d0cad..5e613c658b 100644
--- a/tools/editor/editor_data.cpp
+++ b/tools/editor/editor_data.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,6 +31,9 @@
#include "editor_settings.h"
#include "os/dir_access.h"
#include "io/resource_loader.h"
+#include "scene/resources/packed_scene.h"
+#include "os/file_access.h"
+#include "editor_node.h"
void EditorHistory::_cleanup_history() {
@@ -39,7 +42,7 @@ void EditorHistory::_cleanup_history() {
bool fail=false;
for(int j=0;j<history[i].path.size();j++) {
- if (!history[i].path[j].res.is_null())
+ if (!history[i].path[j].ref.is_null())
continue;
if (ObjectDB::get_instance(history[i].path[j].object))
@@ -70,10 +73,10 @@ void EditorHistory::_add_object(ObjectID p_object,const String& p_property,int p
Object *obj = ObjectDB::get_instance(p_object);
ERR_FAIL_COND(!obj);
- Resource *r = obj->cast_to<Resource>();
+ Reference *r = obj->cast_to<Reference>();
Obj o;
if (r)
- o.res=RES(r);
+ o.ref=REF(r);
o.object=p_object;
o.property=p_property;
@@ -123,6 +126,27 @@ void EditorHistory::add_object(ObjectID p_object,int p_relevel){
_add_object(p_object,"",p_relevel);
}
+int EditorHistory::get_history_len() {
+ return history.size();
+}
+int EditorHistory::get_history_pos() {
+ return current;
+}
+
+ObjectID EditorHistory::get_history_obj(int p_obj) const {
+ ERR_FAIL_INDEX_V(p_obj,history.size(),0);
+ ERR_FAIL_INDEX_V(history[p_obj].level,history[p_obj].path.size(),0);
+ return history[p_obj].path[history[p_obj].level].object;
+}
+
+bool EditorHistory::is_at_begining() const {
+ return current<=0;
+}
+bool EditorHistory::is_at_end() const {
+
+ return ((current+1)>=history.size());
+}
+
bool EditorHistory::next() {
@@ -317,6 +341,14 @@ void EditorData::set_editor_states(const Dictionary& p_states) {
}
+void EditorData::notify_edited_scene_changed() {
+
+ for(int i=0;i<editor_plugins.size();i++) {
+
+ editor_plugins[i]->edited_scene_changed();
+ }
+}
+
void EditorData::clear_editor_states() {
for(int i=0;i<editor_plugins.size();i++) {
@@ -432,6 +464,7 @@ int EditorData::add_edited_scene(int p_at_pos) {
es.root=NULL;
es.history_current=-1;
es.version=0;
+ es.live_edit_root=NodePath(String("/root"));
if (p_at_pos==edited_scene.size())
edited_scene.push_back(es);
@@ -463,6 +496,93 @@ void EditorData::remove_scene(int p_idx){
edited_scene.remove(p_idx);
}
+
+bool EditorData::_find_updated_instances(Node* p_root,Node *p_node,Set<String> &checked_paths) {
+
+// if (p_root!=p_node && p_node->get_owner()!=p_root && !p_root->is_editable_instance(p_node->get_owner()))
+// return false;
+
+ Ref<SceneState> ss;
+
+ if (p_node==p_root) {
+ ss=p_node->get_scene_inherited_state();
+ } else if (p_node->get_filename()!=String()){
+ ss=p_node->get_scene_instance_state();
+ }
+
+ if (ss.is_valid()) {
+ String path = ss->get_path();
+
+ if (!checked_paths.has(path)) {
+
+ uint64_t modified_time = FileAccess::get_modified_time(path);
+ if (modified_time!=ss->get_last_modified_time()) {
+ return true; //external scene changed
+ }
+
+ checked_paths.insert(path);
+ }
+
+ }
+
+ for(int i=0;i<p_node->get_child_count();i++) {
+
+ bool found = _find_updated_instances(p_root,p_node->get_child(i),checked_paths);
+ if (found)
+ return true;
+ }
+
+ return false;
+}
+
+
+bool EditorData::check_and_update_scene(int p_idx) {
+
+ ERR_FAIL_INDEX_V(p_idx,edited_scene.size(),false);
+ if (!edited_scene[p_idx].root)
+ return false;
+
+ Set<String> checked_scenes;
+
+
+ bool must_reload = _find_updated_instances(edited_scene[p_idx].root,edited_scene[p_idx].root,checked_scenes);
+
+ if (must_reload) {
+ Ref<PackedScene> pscene;
+ pscene.instance();
+
+ EditorProgress ep("update_scene","Updating Scene",2);
+ ep.step("Storing local changes..",0);
+ //pack first, so it stores diffs to previous version of saved scene
+ Error err = pscene->pack(edited_scene[p_idx].root);
+ ERR_FAIL_COND_V(err!=OK,false);
+ ep.step("Updating scene..",1);
+ Node *new_scene = pscene->instance(true);
+ ERR_FAIL_COND_V(!new_scene,false);
+
+ //transfer selection
+ List<Node*> new_selection;
+ for (List<Node*>::Element *E=edited_scene[p_idx].selection.front();E;E=E->next()) {
+ NodePath p = edited_scene[p_idx].root->get_path_to(E->get());
+ Node *new_node = new_scene->get_node(p);
+ if (new_node)
+ new_selection.push_back(new_node);
+ }
+
+ new_scene->set_filename( edited_scene[p_idx].root->get_filename() );
+
+ memdelete(edited_scene[p_idx].root);
+ edited_scene[p_idx].root=new_scene;
+ edited_scene[p_idx].selection=new_selection;
+
+ return true;
+
+ }
+
+ return false;
+
+}
+
int EditorData::get_edited_scene() const {
return current_edited_scene;
@@ -507,6 +627,31 @@ uint64_t EditorData::get_scene_version(int p_idx) const{
return edited_scene[p_idx].version;
}
+String EditorData::get_scene_type(int p_idx) const {
+
+ ERR_FAIL_INDEX_V(p_idx,edited_scene.size(),String());
+ if (!edited_scene[p_idx].root)
+ return "";
+ return edited_scene[p_idx].root->get_type();
+
+}
+
+Ref<Script> EditorData::get_scene_root_script(int p_idx) const {
+
+ ERR_FAIL_INDEX_V(p_idx,edited_scene.size(),Ref<Script>());
+ if (!edited_scene[p_idx].root)
+ return Ref<Script>();
+ Ref<Script> s=edited_scene[p_idx].root->get_script();
+ if (!s.is_valid() && edited_scene[p_idx].root->get_child_count()) {
+ Node *n = edited_scene[p_idx].root->get_child(0);
+ while(!s.is_valid() && n && n->get_filename()==String()) {
+ s=n->get_script();
+ n=n->get_parent();
+ }
+ }
+ return s;
+}
+
String EditorData::get_scene_title(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx,edited_scene.size(),String());
if (!edited_scene[p_idx].root)
@@ -527,6 +672,23 @@ String EditorData::get_scene_path(int p_idx) const {
}
+void EditorData::set_edited_scene_live_edit_root(const NodePath& p_root) {
+ ERR_FAIL_INDEX(current_edited_scene,edited_scene.size());
+
+ edited_scene[current_edited_scene].live_edit_root=p_root;
+
+}
+NodePath EditorData::get_edited_scene_live_edit_root() {
+
+ ERR_FAIL_INDEX_V(current_edited_scene,edited_scene.size(),String());
+
+ return edited_scene[current_edited_scene].live_edit_root;
+
+
+
+}
+
+
void EditorData::save_edited_scene_state(EditorSelection *p_selection, EditorHistory *p_history, const Dictionary& p_custom) {
ERR_FAIL_INDEX(current_edited_scene,edited_scene.size());
diff --git a/tools/editor/editor_data.h b/tools/editor/editor_data.h
index e3fdd52d01..7dafeeea04 100644
--- a/tools/editor/editor_data.h
+++ b/tools/editor/editor_data.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -45,7 +45,7 @@ class EditorHistory {
struct Obj {
- RES res;
+ REF ref;
ObjectID object;
String property;
};
@@ -75,10 +75,17 @@ friend class EditorData;
public:
+ bool is_at_begining() const;
+ bool is_at_end() const;
+
void add_object(ObjectID p_object);
void add_object(ObjectID p_object,const String& p_subprop);
void add_object(ObjectID p_object,int p_relevel);
+ int get_history_len();
+ int get_history_pos();
+ ObjectID get_history_obj(int p_obj) const;
+
bool next();
bool previous();
ObjectID get_current();
@@ -129,6 +136,7 @@ private:
int history_current;
Dictionary custom_state;
uint64_t version;
+ NodePath live_edit_root;
};
@@ -136,6 +144,8 @@ private:
Vector<EditedScene> edited_scene;
int current_edited_scene;
+ bool _find_updated_instances(Node* p_root,Node *p_node,Set<String> &checked_paths);
+
public:
EditorPlugin* get_editor(Object *p_object);
@@ -177,10 +187,15 @@ public:
int get_edited_scene_count() const;
String get_scene_title(int p_idx) const;
String get_scene_path(int p_idx) const;
+ String get_scene_type(int p_idx) const;
+ Ref<Script> get_scene_root_script(int p_idx) const;
void set_edited_scene_version(uint64_t version);
uint64_t get_edited_scene_version() const;
uint64_t get_scene_version(int p_idx) const;
void clear_edited_scenes();
+ void set_edited_scene_live_edit_root(const NodePath& p_root);
+ NodePath get_edited_scene_live_edit_root();
+ bool check_and_update_scene(int p_idx);
void set_plugin_window_layout(Ref<ConfigFile> p_layout);
@@ -188,6 +203,7 @@ public:
void save_edited_scene_state(EditorSelection *p_selection,EditorHistory *p_history,const Dictionary& p_custom);
Dictionary restore_edited_scene_state(EditorSelection *p_selection, EditorHistory *p_history);
+ void notify_edited_scene_changed();
EditorData();
diff --git a/tools/editor/editor_dir_dialog.cpp b/tools/editor/editor_dir_dialog.cpp
index a8421acff8..8512154485 100644
--- a/tools/editor/editor_dir_dialog.cpp
+++ b/tools/editor/editor_dir_dialog.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -205,31 +205,36 @@ void EditorDirDialog::_bind_methods() {
EditorDirDialog::EditorDirDialog() {
+ updating=false;
+
set_title("Choose a Directory");
+ set_hide_on_ok(false);
+
tree = memnew( Tree );
add_child(tree);
set_child_rect(tree);
- updating=false;
- get_ok()->set_text("Choose");
- set_hide_on_ok(false);
-
-
+ tree->connect("item_activated",this,"_ok");
makedir = add_button("Create Folder",OS::get_singleton()->get_swap_ok_cancel()?true:false,"makedir");
makedir->connect("pressed",this,"_make_dir");
makedialog = memnew( ConfirmationDialog );
makedialog->set_title("Create Folder");
+ add_child(makedialog);
+
VBoxContainer *makevb= memnew( VBoxContainer );
makedialog->add_child(makevb);
makedialog->set_child_rect(makevb);
+
makedirname = memnew( LineEdit );
makevb->add_margin_child("Name:",makedirname);
- add_child(makedialog);
makedialog->register_text_enter(makedirname);
makedialog->connect("confirmed",this,"_make_dir_confirm");
+
mkdirerr = memnew( AcceptDialog );
mkdirerr->set_text("Could not create folder.");
add_child(mkdirerr);
+ get_ok()->set_text("Choose");
+
}
diff --git a/tools/editor/editor_dir_dialog.h b/tools/editor/editor_dir_dialog.h
index 8ac83b86e8..1c2593219c 100644
--- a/tools/editor/editor_dir_dialog.h
+++ b/tools/editor/editor_dir_dialog.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/editor_file_dialog.cpp b/tools/editor/editor_file_dialog.cpp
index b1bbd71f7b..a9b23767f1 100644
--- a/tools/editor/editor_file_dialog.cpp
+++ b/tools/editor/editor_file_dialog.cpp
@@ -6,6 +6,8 @@
#include "editor_resource_preview.h"
#include "editor_settings.h"
#include "scene/gui/margin_container.h"
+#include "os/file_access.h"
+
EditorFileDialog::GetIconFunc EditorFileDialog::get_icon_func=NULL;
EditorFileDialog::GetIconFunc EditorFileDialog::get_large_icon_func=NULL;
@@ -27,14 +29,14 @@ void EditorFileDialog::_notification(int p_what) {
dir_prev->set_icon(get_icon("ArrowLeft","EditorIcons"));
dir_next->set_icon(get_icon("ArrowRight","EditorIcons"));
dir_up->set_icon(get_icon("ArrowUp","EditorIcons"));
+ refresh->set_icon(get_icon("Reload","EditorIcons"));
favorite->set_icon(get_icon("Favorites","EditorIcons"));
fav_up->set_icon(get_icon("MoveUp","EditorIcons"));
fav_down->set_icon(get_icon("MoveDown","EditorIcons"));
fav_rm->set_icon(get_icon("RemoveSmall","EditorIcons"));
- }
- if (p_what==NOTIFICATION_PROCESS) {
+ } else if (p_what==NOTIFICATION_PROCESS) {
if (preview_waiting) {
preview_wheel_timeout-=get_process_delta_time();
@@ -47,12 +49,57 @@ void EditorFileDialog::_notification(int p_what) {
preview_wheel_timeout=0.1;
}
}
- }
-
- if (p_what==NOTIFICATION_DRAW) {
+ } else if (p_what==NOTIFICATION_DRAW) {
//RID ci = get_canvas_item();
//get_stylebox("panel","PopupMenu")->draw(ci,Rect2(Point2(),get_size()));
+ } else if (p_what==NOTIFICATION_POPUP_HIDE) {
+
+ set_process_unhandled_input(false);
+
+ } else if (p_what==EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
+
+ bool show_hidden=EditorSettings::get_singleton()->get("file_dialog/show_hidden_files");
+ if (show_hidden_files!=show_hidden)
+ set_show_hidden_files(show_hidden);
+ set_display_mode((DisplayMode)EditorSettings::get_singleton()->get("file_dialog/display_mode").operator int());
+ }
+}
+
+void EditorFileDialog::_unhandled_input(const InputEvent& p_event) {
+
+ if (p_event.type==InputEvent::KEY && is_window_modal_on_top()) {
+
+ const InputEventKey &k=p_event.key;
+
+ if (k.pressed) {
+
+ bool handled=true;
+
+ switch (k.scancode) {
+
+ case KEY_H: {
+
+ if (k.mod.command) {
+
+ bool show=!show_hidden_files;
+ set_show_hidden_files(show);
+ EditorSettings::get_singleton()->set("file_dialog/show_hidden_files",show);
+ } else {
+ handled=false;
+ }
+
+ } break;
+ case KEY_F5: {
+
+ invalidate();
+ } break;
+ default: { handled=false; }
+ }
+
+ if (handled)
+ accept_event();
+ }
}
}
@@ -147,6 +194,8 @@ void EditorFileDialog::_post_popup() {
_update_favorites();
}
+ set_process_unhandled_input(true);
+
}
void EditorFileDialog::_thumbnail_result(const String& p_path,const Ref<Texture>& p_preview, const Variant& p_udata) {
@@ -189,8 +238,11 @@ void EditorFileDialog::_thumbnail_done(const String& p_path,const Ref<Texture>&
void EditorFileDialog::_request_single_thumbnail(const String& p_path) {
+ if (!FileAccess::exists(p_path))
+ return;
+
EditorResourcePreview::get_singleton()->queue_resource_preview(p_path,this,"_thumbnail_done",p_path);
- print_line("want file "+p_path);
+ //print_line("want file "+p_path);
set_process(true);
preview_waiting=true;
preview_wheel_timeout=0;
@@ -359,7 +411,7 @@ void EditorFileDialog::_item_dc_selected(int p_item) {
if (d["dir"]) {
- print_line("change dir: "+String(d["name"]));
+ //print_line("change dir: "+String(d["name"]));
dir_access->change_dir(d["name"]);
if (mode==MODE_OPEN_FILE || mode==MODE_OPEN_FILES || mode==MODE_OPEN_DIR)
file->set_text("");
@@ -430,6 +482,8 @@ void EditorFileDialog::update_file_list() {
}
+ String cdir = dir_access->get_current_dir();
+ bool skip_pp = access==ACCESS_RESOURCES && cdir=="res://";
dir_access->list_dir_begin();
@@ -450,7 +504,7 @@ void EditorFileDialog::update_file_list() {
if (show_hidden || !ishidden) {
if (!isdir)
files.push_back(item);
- else
+ else if (item!=".." || !skip_pp)
dirs.push_back(item);
}
}
@@ -536,6 +590,7 @@ void EditorFileDialog::update_file_list() {
if (get_icon_func) {
+
Ref<Texture> icon = get_icon_func(base_dir.plus_file(files.front()->get()));
//ti->set_icon(0,icon);
if (display_mode==DISPLAY_THUMBNAILS) {
@@ -1011,7 +1066,9 @@ void EditorFileDialog::_go_forward(){
}
-bool EditorFileDialog::default_show_hidden_files=true;
+bool EditorFileDialog::default_show_hidden_files=false;
+
+EditorFileDialog::DisplayMode EditorFileDialog::default_display_mode=DISPLAY_THUMBNAILS;
void EditorFileDialog::set_display_mode(DisplayMode p_mode) {
@@ -1037,6 +1094,8 @@ EditorFileDialog::DisplayMode EditorFileDialog::get_display_mode() const{
void EditorFileDialog::_bind_methods() {
+ ObjectTypeDB::bind_method(_MD("_unhandled_input"),&EditorFileDialog::_unhandled_input);
+
ObjectTypeDB::bind_method(_MD("_item_selected"),&EditorFileDialog::_item_selected);
ObjectTypeDB::bind_method(_MD("_item_db_selected"),&EditorFileDialog::_item_dc_selected);
ObjectTypeDB::bind_method(_MD("_dir_entered"),&EditorFileDialog::_dir_entered);
@@ -1059,7 +1118,7 @@ void EditorFileDialog::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_vbox:VBoxContainer"),&EditorFileDialog::get_vbox);
ObjectTypeDB::bind_method(_MD("set_access","access"),&EditorFileDialog::set_access);
ObjectTypeDB::bind_method(_MD("get_access"),&EditorFileDialog::get_access);
- ObjectTypeDB::bind_method(_MD("set_show_hidden_files"),&EditorFileDialog::set_show_hidden_files);
+ ObjectTypeDB::bind_method(_MD("set_show_hidden_files","show"),&EditorFileDialog::set_show_hidden_files);
ObjectTypeDB::bind_method(_MD("is_showing_hidden_files"),&EditorFileDialog::is_showing_hidden_files);
ObjectTypeDB::bind_method(_MD("_select_drive"),&EditorFileDialog::_select_drive);
ObjectTypeDB::bind_method(_MD("_make_dir"),&EditorFileDialog::_make_dir);
@@ -1112,6 +1171,10 @@ void EditorFileDialog::set_default_show_hidden_files(bool p_show) {
default_show_hidden_files=p_show;
}
+void EditorFileDialog::set_default_display_mode(DisplayMode p_mode) {
+ default_display_mode=p_mode;
+}
+
void EditorFileDialog::_save_to_recent() {
String dir = get_current_dir();
@@ -1140,8 +1203,8 @@ void EditorFileDialog::_save_to_recent() {
EditorFileDialog::EditorFileDialog() {
- show_hidden_files=true;
- display_mode=DISPLAY_THUMBNAILS;
+ show_hidden_files=default_show_hidden_files;
+ display_mode=default_display_mode;
local_history_pos=0;
VBoxContainer *vbc = memnew( VBoxContainer );
@@ -1169,6 +1232,10 @@ EditorFileDialog::EditorFileDialog() {
pathhb->add_child(dir);
dir->set_h_size_flags(SIZE_EXPAND_FILL);
+ refresh = memnew( ToolButton );
+ refresh->connect("pressed",this,"_update_file_list");
+ pathhb->add_child(refresh);
+
favorite = memnew( ToolButton );
favorite->set_toggle_mode(true);
favorite->connect("toggled",this,"_favorite_toggled");
@@ -1177,11 +1244,13 @@ EditorFileDialog::EditorFileDialog() {
mode_thumbnails = memnew( ToolButton );
mode_thumbnails->connect("pressed",this,"set_display_mode",varray(DISPLAY_THUMBNAILS));
mode_thumbnails->set_toggle_mode(true);
- mode_thumbnails->set_pressed(true);
+ mode_thumbnails->set_pressed(display_mode==DISPLAY_THUMBNAILS);
pathhb->add_child(mode_thumbnails);
+
mode_list = memnew( ToolButton );
mode_list->connect("pressed",this,"set_display_mode",varray(DISPLAY_LIST));
mode_list->set_toggle_mode(true);
+ mode_list->set_pressed(display_mode==DISPLAY_LIST);
pathhb->add_child(mode_list);
drives = memnew( OptionButton );
diff --git a/tools/editor/editor_file_dialog.h b/tools/editor/editor_file_dialog.h
index 6cfd970516..3590964a51 100644
--- a/tools/editor/editor_file_dialog.h
+++ b/tools/editor/editor_file_dialog.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -108,6 +108,7 @@ private:
ToolButton *mode_list;
+ ToolButton *refresh;
ToolButton *favorite;
ToolButton *fav_up;
@@ -127,6 +128,7 @@ private:
int preview_wheel_index;
float preview_wheel_timeout;
static bool default_show_hidden_files;
+ static DisplayMode default_display_mode;
bool show_hidden_files;
DisplayMode display_mode;
@@ -174,6 +176,8 @@ private:
void _thumbnail_done(const String& p_path,const Ref<Texture>& p_preview, const Variant& p_udata);
void _request_single_thumbnail(const String& p_path);
+ void _unhandled_input(const InputEvent& p_event);
+
protected:
void _notification(int p_what);
@@ -210,6 +214,7 @@ public:
bool is_showing_hidden_files() const;
static void set_default_show_hidden_files(bool p_show);
+ static void set_default_display_mode(DisplayMode p_mode);
void invalidate();
diff --git a/tools/editor/editor_file_system.cpp b/tools/editor/editor_file_system.cpp
index d741087a9f..c7c1a48e34 100644
--- a/tools/editor/editor_file_system.cpp
+++ b/tools/editor/editor_file_system.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -37,6 +37,31 @@
EditorFileSystem *EditorFileSystem::singleton=NULL;
+void EditorFileSystemDirectory::sort_files() {
+
+ files.sort_custom<FileInfoSort>();
+}
+
+int EditorFileSystemDirectory::find_file_index(const String& p_file) const {
+
+ for(int i=0;i<files.size();i++) {
+ if (files[i]->file==p_file)
+ return i;
+ }
+ return -1;
+
+}
+int EditorFileSystemDirectory::find_dir_index(const String& p_dir) const{
+
+
+ for(int i=0;i<subdirs.size();i++) {
+ if (subdirs[i]->name==p_dir)
+ return i;
+ }
+
+ return -1;
+}
+
int EditorFileSystemDirectory::get_subdir_count() const {
@@ -59,7 +84,7 @@ String EditorFileSystemDirectory::get_file(int p_idx) const{
ERR_FAIL_INDEX_V(p_idx,files.size(),"");
- return files[p_idx].file;
+ return files[p_idx]->file;
}
String EditorFileSystemDirectory::get_path() const {
@@ -91,16 +116,22 @@ String EditorFileSystemDirectory::get_file_path(int p_idx) const {
bool EditorFileSystemDirectory::get_file_meta(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx,files.size(),"");
- return files[p_idx].meta.enabled;
+ return files[p_idx]->meta.enabled;
}
+Vector<String> EditorFileSystemDirectory::get_file_deps(int p_idx) const {
+
+ ERR_FAIL_INDEX_V(p_idx,files.size(),Vector<String>());
+ return files[p_idx]->meta.deps;
+
+}
Vector<String> EditorFileSystemDirectory::get_missing_sources(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx,files.size(),Vector<String>());
Vector<String> missing;
- for(int i=0;i<files[p_idx].meta.sources.size();i++) {
- if (files[p_idx].meta.sources[i].missing)
- missing.push_back(files[p_idx].meta.sources[i].path);
+ for(int i=0;i<files[p_idx]->meta.sources.size();i++) {
+ if (files[p_idx]->meta.sources[i].missing)
+ missing.push_back(files[p_idx]->meta.sources[i].path);
}
return missing;
@@ -110,18 +141,18 @@ Vector<String> EditorFileSystemDirectory::get_missing_sources(int p_idx) const {
bool EditorFileSystemDirectory::is_missing_sources(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx,files.size(),false);
- for(int i=0;i<files[p_idx].meta.sources.size();i++) {
- if (files[p_idx].meta.sources[i].missing)
+ for(int i=0;i<files[p_idx]->meta.sources.size();i++) {
+ if (files[p_idx]->meta.sources[i].missing)
return true;
}
return false;
}
-String EditorFileSystemDirectory::get_file_type(int p_idx) const {
+StringName EditorFileSystemDirectory::get_file_type(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx,files.size(),"");
- return files[p_idx].type;
+ return files[p_idx]->type;
}
String EditorFileSystemDirectory::get_name() {
@@ -151,11 +182,17 @@ void EditorFileSystemDirectory::_bind_methods() {
EditorFileSystemDirectory::EditorFileSystemDirectory() {
+ modified_time=0;
parent=NULL;
}
EditorFileSystemDirectory::~EditorFileSystemDirectory() {
+ for(int i=0;i<files.size();i++) {
+
+ memdelete(files[i]);
+ }
+
for(int i=0;i<subdirs.size();i++) {
memdelete(subdirs[i]);
@@ -167,19 +204,6 @@ EditorFileSystemDirectory::~EditorFileSystemDirectory() {
-
-
-EditorFileSystem::DirItem::~DirItem() {
-
- for(int i=0;i<dirs.size();i++) {
- memdelete(dirs[i]);
- }
-
- for(int i=0;i<files.size();i++) {
- memdelete(files[i]);
- }
-}
-
EditorFileSystemDirectory::ImportMeta EditorFileSystem::_get_meta(const String& p_path) {
Ref<ResourceImportMetadata> imd = ResourceLoader::load_import_metadata(p_path);
@@ -198,167 +222,30 @@ EditorFileSystemDirectory::ImportMeta EditorFileSystem::_get_meta(const String&
}
m.import_editor=imd->get_editor();
}
- return m;
-}
-
-EditorFileSystem::DirItem* EditorFileSystem::_scan_dir(DirAccess *da,Set<String> &extensions,String p_name,float p_from,float p_range,const String& p_path,HashMap<String,FileCache> &file_cache,HashMap<String,DirCache> &dir_cache,EditorProgressBG& p_prog) {
-
- if (abort_scan)
- return NULL;
-
- if (p_path!=String()) {
- if (FileAccess::exists(("res://"+p_path).plus_file("engine.cfg"))) {
- return NULL;
- }
- }
-
- List<String> dirs;
- List<String> files;
- Set<String> pngs;
-
- String path=p_path;
- if (path.ends_with("/"))
- path=path.substr(0,path.length()-1);
- String global_path = Globals::get_singleton()->get_resource_path().plus_file(path);
-
- path="res://"+path;
- uint64_t mtime = FileAccess::get_modified_time(global_path);
-
- DirCache *dc = dir_cache.getptr(path);
-
-
- if (false && dc && dc->modification_time==mtime) {
- //use the cached files, since directory did not change
- for (Set<String>::Element *E=dc->subdirs.front();E;E=E->next()) {
- dirs.push_back(E->get());
- }
- for (Set<String>::Element *E=dc->files.front();E;E=E->next()) {
- files.push_back(E->get());
- }
-
- } else {
- //use the filesystem, some files may have changed
- Error err = da->change_dir(global_path);
- if (err!=OK) {
- print_line("Can't change to: "+path);
- ERR_FAIL_COND_V(err!=OK,NULL);
- }
-
-
- da->list_dir_begin();
- while (true) {
-
- bool isdir;
- String f = da->get_next(&isdir);
- if (f=="")
- break;
- if (isdir) {
- dirs.push_back(f);
- } else {
- String ext = f.extension().to_lower();
- if (extensions.has(ext))
- files.push_back(f);
-
- }
-
- }
-
- da->list_dir_end();
- files.sort();
- dirs.sort();
-
- }
-
-
-
- //print_line(da->get_current_dir()+": dirs: "+itos(dirs.size())+" files:"+itos(files.size()) );
- //find subdirs
- Vector<DirItem*> subdirs;
-
- //String current = da->get_current_dir();
- float idx=0;
- for (List<String>::Element *E=dirs.front();E;E=E->next(),idx+=1.0) {
-
- String d = E->get();
- if (d.begins_with(".")) //ignore hidden and . / ..
- continue;
-
- //ERR_CONTINUE( da->change_dir(d)!= OK );
- DirItem *sdi = _scan_dir(da,extensions,d,p_from+(idx/dirs.size())*p_range,p_range/dirs.size(),p_path+d+"/",file_cache,dir_cache,p_prog);
- if (sdi) {
- subdirs.push_back(sdi);
- }
- //da->change_dir(current);
+ List<String> deps;
+ ResourceLoader::get_dependencies(p_path,&deps);
+ for(List<String>::Element *E=deps.front();E;E=E->next()) {
+ m.deps.push_back(E->get());
}
-
- if (subdirs.empty() && files.empty()) {
- total=p_from+p_range;
- p_prog.step(total*100);
- return NULL; //give up, nothing to do here
- }
-
- DirItem *di = memnew( DirItem );
- di->path=path;
- di->name=p_name;
- di->dirs=subdirs;
- di->modified_time=mtime;
-
- //add files
- for (List<String>::Element *E=files.front();E;E=E->next()) {
-
- SceneItem * si = memnew( SceneItem );
- si->file=E->get();
- si->path="res://"+p_path+si->file;
- FileCache *fc = file_cache.getptr(si->path);
- uint64_t mt = FileAccess::get_modified_time(si->path);
-
- if (fc && fc->modification_time == mt) {
-
- si->meta=fc->meta;
- si->type=fc->type;
- si->modified_time=fc->modification_time;
- } else {
- si->meta=_get_meta(si->path);
- si->type=ResourceLoader::get_resource_type(si->path);
- si->modified_time=mt;
-
- }
-
- if (si->meta.enabled) {
- md_count++;
- if (_check_meta_sources(si->meta)) {
- sources_changed.push_back(si->path);
- }
- }
- di->files.push_back(si);
- }
-
- total=p_from+p_range;
- p_prog.step(total*100);
-
- return di;
+ return m;
}
-void EditorFileSystem::_scan_scenes() {
+void EditorFileSystem::_scan_filesystem() {
- ERR_FAIL_COND(!scanning || scandir);
+ ERR_FAIL_COND(!scanning || new_filesystem);
//read .fscache
- HashMap<String,FileCache> file_cache;
- HashMap<String,DirCache> dir_cache;
- DirCache *dc=NULL;
String cpath;
sources_changed.clear();
-
-
+ file_cache.clear();
String project=Globals::get_singleton()->get_resource_path();
- String fscache = EditorSettings::get_singleton()->get_project_settings_path().plus_file("file_cache");
+ String fscache = EditorSettings::get_singleton()->get_project_settings_path().plus_file("filesystem_cache");
FileAccess *f =FileAccess::open(fscache,FileAccess::READ);
if (f) {
@@ -374,39 +261,16 @@ void EditorFileSystem::_scan_scenes() {
ERR_CONTINUE( split.size() != 3);
String name = split[1];
- dir_cache[name]=DirCache();
- dc=&dir_cache[name];
- dc->modification_time=split[2].to_int64();
-
- if (name!="res://") {
-
- cpath=name+"/";
-
- int sp=name.find_last("/");
- if (sp==5)
- sp=6;
- String pd = name.substr(0,sp);
- DirCache *dcp = dir_cache.getptr(pd);
- ERR_CONTINUE(!dcp);
- dcp->subdirs.insert(name.get_file());
- } else {
-
- cpath=name;
- }
-
+ cpath=name;
} else {
Vector<String> split = l.split("::");
- ERR_CONTINUE( split.size() != 4);
+ ERR_CONTINUE( split.size() != 5);
String name = split[0];
String file;
- if (!name.begins_with("res://")) {
- file=name;
- name=cpath+name;
- } else {
- file=name.get_file();
- }
+ file=name;
+ name=cpath.plus_file(name);
FileCache fc;
fc.type=split[1];
@@ -429,10 +293,17 @@ void EditorFileSystem::_scan_scenes() {
}
}
+ String deps = split[4].strip_edges();
+ if (deps.length()) {
+ Vector<String> dp = deps.split("<>");
+ for(int i=0;i<dp.size();i++) {
+ String path=dp[i];
+ fc.meta.deps.push_back(path);
+ }
+ }
+
file_cache[name]=fc;
- ERR_CONTINUE(!dc);
- dc->files.insert(file);
}
}
@@ -443,39 +314,31 @@ void EditorFileSystem::_scan_scenes() {
+ EditorProgressBG scan_progress("efs","ScanFS",1000);
+ ScanProgress sp;
+ sp.low=0;
+ sp.hi=1;
+ sp.progress=&scan_progress;
- total=0;
- DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- //da->change_dir( Globals::get_singleton()->get_resource_path() );
+ new_filesystem = memnew( EditorFileSystemDirectory );
+ new_filesystem->parent=NULL;
+ DirAccess *d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ d->change_dir("res://");
+ _scan_new_dir(new_filesystem,d,sp);
- List<String> extensionsl;
- ResourceLoader::get_recognized_extensions_for_type("",&extensionsl);
- Set<String> extensions;
- for(List<String>::Element *E = extensionsl.front();E;E=E->next()) {
+ file_cache.clear(); //clear caches, no longer needed
- extensions.insert(E->get());
- }
-
- EditorProgressBG scan_progress("efs","ScanFS",100);
-
- md_count=0;
- scandir=_scan_dir(da,extensions,"",0,1,"",file_cache,dir_cache,scan_progress);
- memdelete(da);
- if (abort_scan && scandir) {
- memdelete(scandir);
- scandir=NULL;
-
- }
+ memdelete(d);
//save back the findings
// String fscache = EditorSettings::get_singleton()->get_project_settings_path().plus_file("file_cache");
f=FileAccess::open(fscache,FileAccess::WRITE);
- _save_type_cache_fs(scandir,f);
+ _save_filesystem_cache(new_filesystem,f);
f->close();
memdelete(f);
@@ -488,7 +351,95 @@ void EditorFileSystem::_scan_scenes() {
void EditorFileSystem::_thread_func(void *_userdata) {
EditorFileSystem *sd = (EditorFileSystem*)_userdata;
- sd->_scan_scenes();
+ sd->_scan_filesystem();
+
+}
+
+bool EditorFileSystem::_update_scan_actions() {
+
+ sources_changed.clear();
+
+ bool fs_changed=false;
+
+ for (List<ItemAction>::Element *E=scan_actions.front();E;E=E->next()) {
+
+ ItemAction&ia = E->get();
+
+ switch(ia.action) {
+ case ItemAction::ACTION_NONE: {
+
+ } break;
+ case ItemAction::ACTION_DIR_ADD: {
+
+ //print_line("*ACTION ADD DIR: "+ia.new_dir->get_name());
+ int idx=0;
+ for(int i=0;i<ia.dir->subdirs.size();i++) {
+
+ if (ia.new_dir->name<ia.dir->subdirs[i]->name)
+ break;
+ idx++;
+ }
+ if (idx==ia.dir->subdirs.size()) {
+ ia.dir->subdirs.push_back(ia.new_dir);
+ } else {
+ ia.dir->subdirs.insert(idx,ia.new_dir);
+ }
+
+ fs_changed=true;
+ } break;
+ case ItemAction::ACTION_DIR_REMOVE: {
+
+ ERR_CONTINUE(!ia.dir->parent);
+ //print_line("*ACTION REMOVE DIR: "+ia.dir->get_name());
+ ia.dir->parent->subdirs.erase(ia.dir);
+ memdelete( ia.dir );
+ fs_changed=true;
+ } break;
+ case ItemAction::ACTION_FILE_ADD: {
+
+ int idx=0;
+ for(int i=0;i<ia.dir->files.size();i++) {
+
+ if (ia.new_file->file<ia.dir->files[i]->file)
+ break;
+ idx++;
+ }
+ if (idx==ia.dir->files.size()) {
+ ia.dir->files.push_back(ia.new_file);
+ } else {
+ ia.dir->files.insert(idx,ia.new_file);
+ }
+
+ fs_changed=true;
+ //print_line("*ACTION ADD FILE: "+ia.new_file->file);
+
+ } break;
+ case ItemAction::ACTION_FILE_REMOVE: {
+
+ int idx = ia.dir->find_file_index(ia.file);
+ ERR_CONTINUE(idx==-1);
+ memdelete( ia.dir->files[idx] );
+ ia.dir->files.remove(idx);
+
+ fs_changed=true;
+ //print_line("*ACTION REMOVE FILE: "+ia.file);
+
+ } break;
+ case ItemAction::ACTION_FILE_SOURCES_CHANGED: {
+
+ int idx = ia.dir->find_file_index(ia.file);
+ ERR_CONTINUE(idx==-1);
+ String full_path = ia.dir->get_file_path(idx);
+ sources_changed.push_back(full_path);
+
+ } break;
+
+ }
+ }
+
+ scan_actions.clear();
+
+ return fs_changed;
}
@@ -504,19 +455,15 @@ void EditorFileSystem::scan() {
abort_scan=false;
if (!use_threads) {
scanning=true;
- _scan_scenes();
- if (rootdir)
- memdelete(rootdir);
- rootdir=scandir;
+ scan_total=0;
+ _scan_filesystem();
if (filesystem)
memdelete(filesystem);
// file_type_cache.clear();
- filesystem=_update_tree(rootdir);
-
- if (rootdir)
- memdelete(rootdir);
- rootdir=NULL;
- scanning=false;
+ filesystem=new_filesystem;
+ new_filesystem=NULL;
+ _update_scan_actions();
+ scanning=false;
emit_signal("filesystem_changed");
emit_signal("sources_changed",sources_changed.size()>0);
@@ -526,24 +473,22 @@ void EditorFileSystem::scan() {
set_process(true);
Thread::Settings s;
scanning=true;
+ scan_total=0;
s.priority=Thread::PRIORITY_LOW;
thread = Thread::create(_thread_func,this,s);
//tree->hide();
//progress->show();
+
}
}
-bool EditorFileSystem::_check_meta_sources(EditorFileSystemDirectory::ImportMeta & p_meta,EditorProgressBG *ep) {
+bool EditorFileSystem::_check_meta_sources(EditorFileSystemDirectory::ImportMeta & p_meta) {
if (p_meta.enabled) {
- if (ep) {
- ep->step(ss_amount++);
- }
-
for(int j=0;j<p_meta.sources.size();j++) {
@@ -561,9 +506,9 @@ bool EditorFileSystem::_check_meta_sources(EditorFileSystemDirectory::ImportMeta
if (mt!=p_meta.sources[j].modified_time) {
//scan
String md5 = FileAccess::get_md5(src);
- print_line("checking: "+src);
- print_line("md5: "+md5);
- print_line("vs: "+p_meta.sources[j].md5);
+ //print_line("checking: "+src);
+ //print_line("md5: "+md5);
+ //print_line("vs: "+p_meta.sources[j].md5);
if (md5!=p_meta.sources[j].md5) {
//really changed
return true;
@@ -576,18 +521,300 @@ bool EditorFileSystem::_check_meta_sources(EditorFileSystemDirectory::ImportMeta
return false;
}
-void EditorFileSystem::_scan_sources(EditorFileSystemDirectory *p_dir,EditorProgressBG *ep) {
+void EditorFileSystem::ScanProgress::update(int p_current,int p_total) const {
+
+ float ratio = low + ((hi-low)/p_total)*p_current;
+ progress->step(ratio*1000);
+ EditorFileSystem::singleton->scan_total=ratio;
+}
+
+EditorFileSystem::ScanProgress EditorFileSystem::ScanProgress::get_sub(int p_current,int p_total) const{
+
+ ScanProgress sp=*this;
+ float slice = (sp.hi-sp.low)/p_total;
+ sp.low+=slice*p_current;
+ sp.hi=slice;
+ return sp;
+
+
+}
+
+
+void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir,DirAccess *da,const ScanProgress& p_progress) {
+
+ List<String> dirs;
+ List<String> files;
+
+ String cd = da->get_current_dir();
+
+ p_dir->modified_time = FileAccess::get_modified_time(cd);
+
+
+ da->list_dir_begin();
+ while (true) {
+
+ bool isdir;
+ String f = da->get_next(&isdir);
+ if (f=="")
+ break;
+
+ if (isdir) {
+
+ if (f.begins_with(".")) //ignore hidden and . / ..
+ continue;
+
+ if (FileAccess::exists(cd.plus_file(f).plus_file("engine.cfg"))) // skip if another project inside this
+ continue;
+
+ dirs.push_back(f);
+
+ } else {
+
+ files.push_back(f);
+ }
+
+ }
+
+ da->list_dir_end();
+
+ dirs.sort();
+ files.sort();
+
+ int total = dirs.size()+files.size();
+ int idx=0;
+
+ for (List<String>::Element *E=dirs.front();E;E=E->next(),idx++) {
+
+ if (da->change_dir(E->get())==OK) {
+
+ EditorFileSystemDirectory *efd = memnew( EditorFileSystemDirectory );
+
+ efd->parent=p_dir;
+ efd->name=E->get();
+
+ _scan_new_dir(efd,da,p_progress.get_sub(idx,total));
+
+ int idx=0;
+ for(int i=0;i<p_dir->subdirs.size();i++) {
+
+ if (efd->name<p_dir->subdirs[i]->name)
+ break;
+ idx++;
+ }
+ if (idx==p_dir->subdirs.size()) {
+ p_dir->subdirs.push_back(efd);
+ } else {
+ p_dir->subdirs.insert(idx,efd);
+ }
+
+ da->change_dir("..");
+ } else {
+ ERR_PRINTS("Can't go into subdir: "+E->get());
+ }
+
+ p_progress.update(idx,total);
+
+ }
+
+ for (List<String>::Element*E=files.front();E;E=E->next(),idx++) {
+
+ String ext = E->get().extension().to_lower();
+ if (!valid_extensions.has(ext))
+ continue; //invalid
+
+ EditorFileSystemDirectory::FileInfo *fi = memnew( EditorFileSystemDirectory::FileInfo );
+ fi->file=E->get();
+
+ String path = cd.plus_file(fi->file);
+
+ FileCache *fc = file_cache.getptr(path);
+ uint64_t mt = FileAccess::get_modified_time(path);
+
+ if (fc && fc->modification_time == mt) {
+
+ fi->meta=fc->meta;
+ fi->type=fc->type;
+ fi->modified_time=fc->modification_time;
+ } else {
+ fi->meta=_get_meta(path);
+ fi->type=ResourceLoader::get_resource_type(path);
+ fi->modified_time=mt;
+
+ }
+
+ if (fi->meta.enabled) {
+ if (_check_meta_sources(fi->meta)) {
+ ItemAction ia;
+ ia.action=ItemAction::ACTION_FILE_SOURCES_CHANGED;
+ ia.dir=p_dir;
+ ia.file=E->get();
+ scan_actions.push_back(ia);
+ }
+ }
+
+ p_dir->files.push_back(fi);
+ p_progress.update(idx,total);
+ }
+
+}
+
+
+void EditorFileSystem::_scan_fs_changes(EditorFileSystemDirectory *p_dir,const ScanProgress& p_progress) {
+
+ uint64_t current_mtime = FileAccess::get_modified_time(p_dir->get_path());
+
+ bool updated_dir=false;
+
+ //print_line("dir: "+p_dir->get_path()+" MODTIME: "+itos(p_dir->modified_time)+" CTIME: "+itos(current_mtime));
+
+ if (current_mtime!=p_dir->modified_time) {
+
+ updated_dir=true;
+ p_dir->modified_time=current_mtime;
+ //ooooops, dir changed, see what's going on
+
+ //first mark everything as veryfied
+
+ for(int i=0;i<p_dir->files.size();i++) {
+
+ p_dir->files[i]->verified=false;
+ }
+
+ for(int i=0;i<p_dir->subdirs.size();i++) {
+
+ p_dir->get_subdir(i)->verified=false;
+ }
+
+ //then scan files and directories and check what's different
+
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ String cd = p_dir->get_path();
+ da->change_dir(cd);
+ da->list_dir_begin();
+ while (true) {
+
+ bool isdir;
+ String f = da->get_next(&isdir);
+ if (f=="")
+ break;
+
+ if (isdir) {
+
+ if (f.begins_with(".")) //ignore hidden and . / ..
+ continue;
+
+ int idx = p_dir->find_dir_index(f);
+ if (idx==-1) {
+
+ if (FileAccess::exists(cd.plus_file(f).plus_file("engine.cfg"))) // skip if another project inside this
+ continue;
+
+ EditorFileSystemDirectory *efd = memnew( EditorFileSystemDirectory );
+
+ efd->parent=p_dir;
+ efd->name=f;
+ DirAccess *d = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ d->change_dir(cd.plus_file(f));
+ _scan_new_dir(efd,d,p_progress.get_sub(1,1));
+ memdelete(d);
+
+
+ ItemAction ia;
+ ia.action=ItemAction::ACTION_DIR_ADD;
+ ia.dir=p_dir;
+ ia.file=f;
+ ia.new_dir=efd;
+ scan_actions.push_back(ia);
+ } else {
+ p_dir->subdirs[idx]->verified=true;
+ }
+
+
+ } else {
+ String ext = f.extension().to_lower();
+ if (!valid_extensions.has(ext))
+ continue; //invalid
+
+ int idx = p_dir->find_file_index(f);
+
+ if (idx==-1) {
+ //never seen this file, add actition to add it
+ EditorFileSystemDirectory::FileInfo *fi = memnew( EditorFileSystemDirectory::FileInfo );
+ fi->file=f;
+
+ String path = cd.plus_file(fi->file);
+ fi->modified_time=FileAccess::get_modified_time(path);
+ fi->meta=_get_meta(path);
+ fi->type=ResourceLoader::get_resource_type(path);
+
+ {
+ ItemAction ia;
+ ia.action=ItemAction::ACTION_FILE_ADD;
+ ia.dir=p_dir;
+ ia.file=f;
+ ia.new_file=fi;
+ scan_actions.push_back(ia);
+ }
+
+ //take the chance and scan sources
+ if (_check_meta_sources(fi->meta)) {
+
+ ItemAction ia;
+ ia.action=ItemAction::ACTION_FILE_SOURCES_CHANGED;
+ ia.dir=p_dir;
+ ia.file=f;
+ scan_actions.push_back(ia);
+ }
+
+ } else {
+ p_dir->files[idx]->verified=true;
+ }
+
+
+ }
+
+ }
+ da->list_dir_end();
+ memdelete(da);
+
+
+
+
+ }
for(int i=0;i<p_dir->files.size();i++) {
- if (_check_meta_sources(p_dir->files[i].meta,ep)) {
- sources_changed.push_back(p_dir->get_file_path(i));
+ if (updated_dir && !p_dir->files[i]->verified) {
+ //this file was removed, add action to remove it
+ ItemAction ia;
+ ia.action=ItemAction::ACTION_FILE_REMOVE;
+ ia.dir=p_dir;
+ ia.file=p_dir->files[i]->file;
+ scan_actions.push_back(ia);
+ continue;
+
+ }
+ if (_check_meta_sources(p_dir->files[i]->meta)) {
+ ItemAction ia;
+ ia.action=ItemAction::ACTION_FILE_SOURCES_CHANGED;
+ ia.dir=p_dir;
+ ia.file=p_dir->files[i]->file;
+ scan_actions.push_back(ia);
}
}
for(int i=0;i<p_dir->subdirs.size();i++) {
- _scan_sources(p_dir->get_subdir(i),ep);
+ if (updated_dir && !p_dir->subdirs[i]->verified) {
+ //this directory was removed, add action to remove it
+ ItemAction ia;
+ ia.action=ItemAction::ACTION_DIR_REMOVE;
+ ia.dir=p_dir->subdirs[i];
+ scan_actions.push_back(ia);
+ continue;
+
+ }
+ _scan_fs_changes(p_dir->get_subdir(i),p_progress);
}
}
@@ -596,9 +823,12 @@ void EditorFileSystem::_thread_func_sources(void *_userdata) {
EditorFileSystem *efs = (EditorFileSystem*)_userdata;
if (efs->filesystem) {
- EditorProgressBG pr("sources","ScanSources",efs->md_count);
- efs->ss_amount=0;
- efs->_scan_sources(efs->filesystem,&pr);
+ EditorProgressBG pr("sources","ScanSources",1000);
+ ScanProgress sp;
+ sp.progress=&pr;
+ sp.hi=1;
+ sp.low=0;
+ efs->_scan_fs_changes(efs->filesystem,sp);
}
efs->scanning_sources_done=true;
}
@@ -620,8 +850,17 @@ void EditorFileSystem::scan_sources() {
abort_scan=false;
if (!use_threads) {
- if (filesystem)
- _scan_sources(filesystem,NULL);
+ if (filesystem) {
+ EditorProgressBG pr("sources","ScanSources",1000);
+ ScanProgress sp;
+ sp.progress=&pr;
+ sp.hi=1;
+ sp.low=0;
+ scan_total=0;
+ _scan_fs_changes(filesystem,sp);
+ if (_update_scan_actions())
+ emit_signal("filesystem_changed");
+ }
scanning_sources=false;
scanning_sources_done=true;
emit_signal("sources_changed",sources_changed.size()>0);
@@ -629,8 +868,8 @@ void EditorFileSystem::scan_sources() {
ERR_FAIL_COND(thread_sources);
set_process(true);
+ scan_total=0;
Thread::Settings s;
- ss_amount=0;
s.priority=Thread::PRIORITY_LOW;
thread_sources = Thread::create(_thread_func_sources,this,s);
//tree->hide();
@@ -642,53 +881,14 @@ void EditorFileSystem::scan_sources() {
}
-EditorFileSystemDirectory* EditorFileSystem::_update_tree(DirItem *p_item) {
-
- EditorFileSystemDirectory *efd = memnew( EditorFileSystemDirectory );
-
- if (!p_item)
- return efd; //empty likely
- efd->name=p_item->name;
-
- for(int i=0;i<p_item->files.size();i++) {
-
- String s = p_item->files[i]->type;
- //if (p_item->files[i]->meta)
- // s="*"+s;
-
-// file_type_cache[p_item->files[i]->path]=s;
- if (p_item->files[i]->type=="")
- continue; //ignore because it's invalid
- EditorFileSystemDirectory::FileInfo fi;
- fi.file=p_item->files[i]->file;
- fi.type=p_item->files[i]->type;
- fi.meta=p_item->files[i]->meta;
- fi.modified_time=p_item->files[i]->modified_time;
-
- efd->files.push_back(fi);
-
- }
-
- for(int i=0;i<p_item->dirs.size();i++) {
-
- EditorFileSystemDirectory *efsd =_update_tree(p_item->dirs[i]);
- efsd->parent=efd;
- efd->subdirs.push_back( efsd );
-
- }
-
-
- return efd;
-}
-
void EditorFileSystem::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_ENTER_TREE: {
- _load_type_cache();
- scan();
+
+ scan();
} break;
case NOTIFICATION_EXIT_TREE: {
if (use_threads && thread) {
@@ -704,13 +904,13 @@ void EditorFileSystem::_notification(int p_what) {
set_process(false);
}
- if (rootdir)
- memdelete(rootdir);
- rootdir=NULL;
if (filesystem)
memdelete(filesystem);
+ if (new_filesystem)
+ memdelete(new_filesystem);
filesystem=NULL;
+ new_filesystem=NULL;
} break;
case NOTIFICATION_PROCESS: {
@@ -728,6 +928,8 @@ void EditorFileSystem::_notification(int p_what) {
Thread::wait_to_finish(thread_sources);
memdelete(thread_sources);
thread_sources=NULL;
+ if (_update_scan_actions())
+ emit_signal("filesystem_changed");
//print_line("sources changed: "+itos(sources_changed.size()));
emit_signal("sources_changed",sources_changed.size()>0);
}
@@ -735,21 +937,14 @@ void EditorFileSystem::_notification(int p_what) {
set_process(false);
- if (rootdir)
- memdelete(rootdir);
if (filesystem)
memdelete(filesystem);
- rootdir=scandir;
- scandir=NULL;
-// file_type_cache.clear();
- filesystem=_update_tree(rootdir);
-
- if (rootdir)
- memdelete(rootdir);
- rootdir=NULL;
+ filesystem=new_filesystem;
+ new_filesystem=NULL;
Thread::wait_to_finish(thread);
memdelete(thread);
thread=NULL;
+ _update_scan_actions();
emit_signal("filesystem_changed");
emit_signal("sources_changed",sources_changed.size()>0);
//print_line("initial sources changed: "+itos(sources_changed.size()));
@@ -771,7 +966,7 @@ bool EditorFileSystem::is_scanning() const {
}
float EditorFileSystem::get_scanning_progress() const {
- return total;
+ return scan_total;
}
EditorFileSystemDirectory *EditorFileSystem::get_filesystem() {
@@ -779,12 +974,12 @@ EditorFileSystemDirectory *EditorFileSystem::get_filesystem() {
return filesystem;
}
-void EditorFileSystem::_save_type_cache_fs(DirItem *p_dir,FileAccess *p_file) {
+void EditorFileSystem::_save_filesystem_cache(EditorFileSystemDirectory*p_dir,FileAccess *p_file) {
if (!p_dir)
return; //none
- p_file->store_line("::"+p_dir->path+"::"+String::num(p_dir->modified_time));
+ p_file->store_line("::"+p_dir->get_path()+"::"+String::num(p_dir->modified_time));
for(int i=0;i<p_dir->files.size();i++) {
@@ -798,129 +993,107 @@ void EditorFileSystem::_save_type_cache_fs(DirItem *p_dir,FileAccess *p_file) {
}
}
+ s+="::";
+ for(int j=0;j<p_dir->files[i]->meta.deps.size();j++) {
+
+ if (j>0)
+ s+="<>";
+ s+=p_dir->files[i]->meta.deps[j];
+ }
+
p_file->store_line(s);
}
- for(int i=0;i<p_dir->dirs.size();i++) {
+ for(int i=0;i<p_dir->subdirs.size();i++) {
- _save_type_cache_fs(p_dir->dirs[i],p_file);
+ _save_filesystem_cache(p_dir->subdirs[i],p_file);
}
}
-void EditorFileSystem::_load_type_cache(){
-
- GLOBAL_LOCK_FUNCTION
-
-
-#if 0
- //this is not good, removed for now as it interferes with metadata stored in files
-
- String project=Globals::get_singleton()->get_resource_path();
- FileAccess *f =FileAccess::open(project+"/types.cache",FileAccess::READ);
-
- if (!f) {
-
- WARN_PRINT("Can't open types.cache.");
- return;
- }
-
- file_type_cache.clear();
- while(!f->eof_reached()) {
-
- String path=f->get_line();
- if (f->eof_reached())
- break;
- String type=f->get_line();
- file_type_cache[path]=type;
- }
-
- memdelete(f);
-#endif
-}
bool EditorFileSystem::_find_file(const String& p_file,EditorFileSystemDirectory ** r_d, int &r_file_pos) const {
//todo make faster
- if (!filesystem || scanning)
- return false;
+ if (!filesystem || scanning)
+ return false;
- String f = Globals::get_singleton()->localize_path(p_file);
+ String f = Globals::get_singleton()->localize_path(p_file);
- if (!f.begins_with("res://"))
- return false;
- f=f.substr(6,f.length());
- f=f.replace("\\","/");
+ if (!f.begins_with("res://"))
+ return false;
+ f=f.substr(6,f.length());
+ f=f.replace("\\","/");
- Vector<String> path = f.split("/");
+ Vector<String> path = f.split("/");
- if (path.size()==0)
- return false;
- String file=path[path.size()-1];
- path.resize(path.size()-1);
+ if (path.size()==0)
+ return false;
+ String file=path[path.size()-1];
+ path.resize(path.size()-1);
- EditorFileSystemDirectory *fs=filesystem;
+ EditorFileSystemDirectory *fs=filesystem;
- for(int i=0;i<path.size();i++) {
+ for(int i=0;i<path.size();i++) {
- int idx=-1;
- for(int j=0;j<fs->get_subdir_count();j++) {
+ int idx=-1;
+ for(int j=0;j<fs->get_subdir_count();j++) {
- if (fs->get_subdir(j)->get_name()==path[i]) {
- idx=j;
- break;
- }
- }
+ if (fs->get_subdir(j)->get_name()==path[i]) {
+ idx=j;
+ break;
+ }
+ }
- if (idx==-1) {
- //does not exist, create i guess?
- EditorFileSystemDirectory *efsd = memnew( EditorFileSystemDirectory );
- efsd->name=path[i];
- int idx2=0;
- for(int j=0;j<fs->get_subdir_count();j++) {
+ if (idx==-1) {
+ //does not exist, create i guess?
+ EditorFileSystemDirectory *efsd = memnew( EditorFileSystemDirectory );
+ efsd->name=path[i];
+ int idx2=0;
+ for(int j=0;j<fs->get_subdir_count();j++) {
- if (efsd->name<fs->get_subdir(j)->get_name())
- break;
- idx2++;
- }
+ if (efsd->name<fs->get_subdir(j)->get_name())
+ break;
+ idx2++;
+ }
- if (idx2==fs->get_subdir_count())
- fs->subdirs.push_back(efsd);
- else
- fs->subdirs.insert(idx2,efsd);
- fs=efsd;
- } else {
+ if (idx2==fs->get_subdir_count())
+ fs->subdirs.push_back(efsd);
+ else
+ fs->subdirs.insert(idx2,efsd);
+ fs=efsd;
+ } else {
- fs=fs->get_subdir(idx);
+ fs=fs->get_subdir(idx);
+ }
}
- }
- int cpos=-1;
- for(int i=0;i<fs->files.size();i++) {
+ int cpos=-1;
+ for(int i=0;i<fs->files.size();i++) {
- if (fs->files[i].file==file) {
- cpos=i;
- break;
+ if (fs->files[i]->file==file) {
+ cpos=i;
+ break;
+ }
}
- }
r_file_pos=cpos;
*r_d=fs;
- if (cpos!=-1) {
+ if (cpos!=-1) {
- return true;
- } else {
+ return true;
+ } else {
- return false;
- }
+ return false;
+ }
}
@@ -936,7 +1109,7 @@ String EditorFileSystem::get_file_type(const String& p_file) const {
}
- return fs->files[cpos].type;
+ return fs->files[cpos]->type;
}
@@ -993,16 +1166,16 @@ EditorFileSystemDirectory *EditorFileSystem::get_path(const String& p_path) {
void EditorFileSystem::_resource_saved(const String& p_path){
- print_line("resource saved: "+p_path);
+ //print_line("resource saved: "+p_path);
EditorFileSystem::get_singleton()->update_file(p_path);
}
String EditorFileSystem::_find_first_from_source(EditorFileSystemDirectory* p_dir,const String &p_src) const {
for(int i=0;i<p_dir->files.size();i++) {
- for(int j=0;j<p_dir->files[i].meta.sources.size();j++) {
+ for(int j=0;j<p_dir->files[i]->meta.sources.size();j++) {
- if (p_dir->files[i].meta.sources[j].path==p_src)
+ if (p_dir->files[i]->meta.sources[j].path==p_src)
return p_dir->get_file_path(i);
}
}
@@ -1037,6 +1210,14 @@ void EditorFileSystem::update_file(const String& p_file) {
return;
}
+ if (!FileAccess::exists(p_file)) {
+ //was removed
+ memdelete( fs->files[cpos] );
+ fs->files.remove(cpos);
+ call_deferred("emit_signal","filesystem_changed"); //update later
+ return;
+
+ }
String type = ResourceLoader::get_resource_type(p_file);
@@ -1045,13 +1226,13 @@ void EditorFileSystem::update_file(const String& p_file) {
int idx=0;
for(int i=0;i<fs->files.size();i++) {
- if (p_file<fs->files[i].file)
+ if (p_file<fs->files[i]->file)
break;
idx++;
}
- EditorFileSystemDirectory::FileInfo fi;
- fi.file=p_file.get_file();
+ EditorFileSystemDirectory::FileInfo *fi = memnew( EditorFileSystemDirectory::FileInfo );
+ fi->file=p_file.get_file();
if (idx==fs->files.size()) {
fs->files.push_back(fi);
@@ -1064,10 +1245,10 @@ void EditorFileSystem::update_file(const String& p_file) {
}
- print_line("UPDATING: "+p_file);
- fs->files[cpos].type=type;
- fs->files[cpos].modified_time=FileAccess::get_modified_time(p_file);
- fs->files[cpos].meta=_get_meta(p_file);
+ //print_line("UPDATING: "+p_file);
+ fs->files[cpos]->type=type;
+ fs->files[cpos]->modified_time=FileAccess::get_modified_time(p_file);
+ fs->files[cpos]->meta=_get_meta(p_file);
call_deferred("emit_signal","filesystem_changed"); //update later
@@ -1090,15 +1271,22 @@ EditorFileSystem::EditorFileSystem() {
thread = NULL;
scanning=false;
- scandir=NULL;
- rootdir=NULL;
use_threads=true;
thread_sources=NULL;
+ new_filesystem=NULL;
scanning_sources=false;
ResourceSaver::set_save_callback(_resource_saved);
+ List<String> extensionsl;
+ ResourceLoader::get_recognized_extensions_for_type("",&extensionsl);
+ for(List<String>::Element *E = extensionsl.front();E;E=E->next()) {
+
+ valid_extensions.insert(E->get());
+ }
+
+ scan_total=0;
}
EditorFileSystem::~EditorFileSystem() {
diff --git a/tools/editor/editor_file_system.h b/tools/editor/editor_file_system.h
index 3f413292fe..d11fa0cfb1 100644
--- a/tools/editor/editor_file_system.h
+++ b/tools/editor/editor_file_system.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -42,6 +42,8 @@ class EditorFileSystemDirectory : public Object {
OBJ_TYPE( EditorFileSystemDirectory,Object );
String name;
+ uint64_t modified_time;
+ bool verified; //used for checking changes
EditorFileSystemDirectory *parent;
Vector<EditorFileSystemDirectory*> subdirs;
@@ -59,19 +61,29 @@ class EditorFileSystemDirectory : public Object {
Vector<Source> sources;
String import_editor;
+ Vector<String> deps;
bool enabled;
};
struct FileInfo {
String file;
- String type;
+ StringName type;
uint64_t modified_time;
-
ImportMeta meta;
+ bool verified; //used for checking changes
+
};
- Vector<FileInfo> files;
+ struct FileInfoSort {
+ bool operator()(const FileInfo *p_a,const FileInfo *p_b) const {
+ return p_a->file<p_b->file;
+ }
+ };
+
+ void sort_files();
+
+ Vector<FileInfo*> files;
static void _bind_methods();
@@ -87,13 +99,17 @@ public:
int get_file_count() const;
String get_file(int p_idx) const;
String get_file_path(int p_idx) const;
- String get_file_type(int p_idx) const;
+ StringName get_file_type(int p_idx) const;
bool get_file_meta(int p_idx) const;
bool is_missing_sources(int p_idx) const;
Vector<String> get_missing_sources(int p_idx) const;
+ Vector<String> get_file_deps(int p_idx) const;
EditorFileSystemDirectory *get_parent();
+ int find_file_index(const String& p_file) const;
+ int find_dir_index(const String& p_dir) const;
+
EditorFileSystemDirectory();
~EditorFileSystemDirectory();
@@ -105,80 +121,92 @@ class EditorFileSystem : public Node {
_THREAD_SAFE_CLASS_
- struct SceneItem {
+
+ struct ItemAction {
+
+ enum Action {
+ ACTION_NONE,
+ ACTION_DIR_ADD,
+ ACTION_DIR_REMOVE,
+ ACTION_FILE_ADD,
+ ACTION_FILE_REMOVE,
+ ACTION_FILE_SOURCES_CHANGED
+ };
+
+ Action action;
+ EditorFileSystemDirectory *dir;
String file;
- String path;
- String type;
- uint64_t modified_time;
- EditorFileSystemDirectory::ImportMeta meta;
- };
+ EditorFileSystemDirectory *new_dir;
+ EditorFileSystemDirectory::FileInfo *new_file;
- struct DirItem {
+ ItemAction() { action=ACTION_NONE; dir=NULL; new_dir=NULL; new_file=NULL; }
- uint64_t modified_time;
- String path;
- String name;
- Vector<DirItem*> dirs;
- Vector<SceneItem*> files;
- ~DirItem();
};
- float total;
bool use_threads;
Thread *thread;
static void _thread_func(void *_userdata);
- DirItem *scandir;
- DirItem *rootdir;
+ EditorFileSystemDirectory *new_filesystem;
bool abort_scan;
bool scanning;
+ float scan_total;
- EditorFileSystemDirectory* _update_tree(DirItem *p_item);
- void _scan_scenes();
- void _load_type_cache();
+ void _scan_filesystem();
EditorFileSystemDirectory *filesystem;
static EditorFileSystem *singleton;
+ /* Used for reading the filesystem cache file */
struct FileCache {
String type;
uint64_t modification_time;
EditorFileSystemDirectory::ImportMeta meta;
+ Vector<String> deps;
};
- struct DirCache {
+ HashMap<String,FileCache> file_cache;
- uint64_t modification_time;
- Set<String> files;
- Set<String> subdirs;
- };
+ struct ScanProgress {
+ float low;
+ float hi;
+ mutable EditorProgressBG *progress;
+ void update(int p_current,int p_total) const;
+ ScanProgress get_sub(int p_current,int p_total) const;
+ };
static EditorFileSystemDirectory::ImportMeta _get_meta(const String& p_path);
- bool _check_meta_sources(EditorFileSystemDirectory::ImportMeta & p_meta,EditorProgressBG *ep=NULL);
+ bool _check_meta_sources(EditorFileSystemDirectory::ImportMeta & p_meta);
- DirItem* _scan_dir(DirAccess *da,Set<String> &extensions,String p_name,float p_from,float p_range,const String& p_path,HashMap<String,FileCache> &file_cache,HashMap<String,DirCache> &dir_cache,EditorProgressBG& p_prog);
- void _save_type_cache_fs(DirItem *p_dir,FileAccess *p_file);
+ void _save_filesystem_cache(EditorFileSystemDirectory *p_dir,FileAccess *p_file);
bool _find_file(const String& p_file,EditorFileSystemDirectory ** r_d, int &r_file_pos) const;
- void _scan_sources(EditorFileSystemDirectory *p_dir,EditorProgressBG *ep);
+ void _scan_fs_changes(EditorFileSystemDirectory *p_dir, const ScanProgress &p_progress);
int md_count;
+ Set<String> valid_extensions;
+
+ void _scan_new_dir(EditorFileSystemDirectory *p_dir,DirAccess *da,const ScanProgress& p_progress);
Thread *thread_sources;
bool scanning_sources;
bool scanning_sources_done;
- int ss_amount;
+
static void _thread_func_sources(void *_userdata);
+
List<String> sources_changed;
+ List<ItemAction> scan_actions;
+
+ bool _update_scan_actions();
static void _resource_saved(const String& p_path);
String _find_first_from_source(EditorFileSystemDirectory* p_dir,const String &p_src) const;
diff --git a/tools/editor/editor_fonts.cpp b/tools/editor/editor_fonts.cpp
index f145f1ddef..b12b041f16 100644
--- a/tools/editor/editor_fonts.cpp
+++ b/tools/editor/editor_fonts.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/editor_fonts.h b/tools/editor/editor_fonts.h
index cc990a560c..3b2422c3e3 100644
--- a/tools/editor/editor_fonts.h
+++ b/tools/editor/editor_fonts.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/editor_help.cpp b/tools/editor/editor_help.cpp
index 25fc526bf9..2ece518f8d 100644
--- a/tools/editor/editor_help.cpp
+++ b/tools/editor/editor_help.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -36,6 +36,14 @@
#include "os/keyboard.h"
+void EditorHelpSearch::popup() {
+ popup_centered_ratio(0.6);
+ if (search_box->get_text()!="") {
+ search_box->select_all();
+ _update_search();
+ }
+ search_box->grab_focus();
+}
void EditorHelpSearch::popup(const String& p_term) {
@@ -79,7 +87,7 @@ void EditorHelpSearch::_update_search() {
_parse_fs(EditorFileSystem::get_singleton()->get_filesystem());
*/
- List<String> type_list;
+ List<StringName> type_list;
ObjectTypeDB::get_type_list(&type_list);
DocData *doc=EditorHelp::get_doc_data();
@@ -263,7 +271,7 @@ void EditorHelpSearch::_confirmed() {
String mdata=ti->get_metadata(0);
emit_signal("go_to_help",mdata);
- editor->call("_editor_select",3); // in case EditorHelpSearch beeen invoked on top of other editor window
+ editor->call("_editor_select",EditorNode::EDITOR_SCRIPT); // in case EditorHelpSearch beeen invoked on top of other editor window
// go to that
hide();
}
@@ -300,9 +308,9 @@ void EditorHelpSearch::_bind_methods() {
}
-EditorHelpSearch::EditorHelpSearch(EditorNode *p_editor) {
+EditorHelpSearch::EditorHelpSearch() {
- editor=p_editor;
+ editor=EditorNode::get_singleton();
VBoxContainer *vbc = memnew( VBoxContainer );
add_child(vbc);
set_child_rect(vbc);
@@ -318,17 +326,138 @@ EditorHelpSearch::EditorHelpSearch(EditorNode *p_editor) {
search_box->connect("input_event",this,"_sbox_input");
search_options = memnew( Tree );
vbc->add_margin_child("Matches:",search_options,true);
- get_ok()->set_text("View");
+ get_ok()->set_text("Open");
get_ok()->set_disabled(true);
register_text_enter(search_box);
set_hide_on_ok(false);
search_options->connect("item_activated",this,"_confirmed");
set_title("Search Classes");
+
// search_options->set_hide_root(true);
}
+/////////////////////////////////
+
+////////////////////////////////////
+/// /////////////////////////////////
+
+
+
+void EditorHelpIndex::add_type(const String& p_type,HashMap<String,TreeItem*>& p_types,TreeItem *p_root) {
+
+ if (p_types.has(p_type))
+ return;
+// if (!ObjectTypeDB::is_type(p_type,base) || p_type==base)
+// return;
+
+ String inherits=EditorHelp::get_doc_data()->class_list[p_type].inherits;
+
+ TreeItem *parent=p_root;
+
+
+ if (inherits.length()) {
+
+ if (!p_types.has(inherits)) {
+
+ add_type(inherits,p_types,p_root);
+ }
+
+ if (p_types.has(inherits) )
+ parent=p_types[inherits];
+ }
+
+ TreeItem *item = class_list->create_item(parent);
+ item->set_metadata(0,p_type);
+ item->set_tooltip(0,EditorHelp::get_doc_data()->class_list[p_type].brief_description);
+ item->set_text(0,p_type);
+
+
+ if (has_icon(p_type,"EditorIcons")) {
+
+ item->set_icon(0, get_icon(p_type,"EditorIcons"));
+ }
+
+ p_types[p_type]=item;
+}
+
+
+void EditorHelpIndex::_tree_item_selected() {
+
+
+ TreeItem *s=class_list->get_selected();
+ if (!s)
+ return;
+
+ emit_signal("open_class",s->get_text(0));
+
+ hide();
+
+ //_goto_desc(s->get_text(0));
+
+}
+
+void EditorHelpIndex::select_class(const String& p_class) {
+
+ if (!tree_item_map.has(p_class))
+ return;
+ tree_item_map[p_class]->select(0);
+ class_list->ensure_cursor_is_visible();
+}
+
+void EditorHelpIndex::_notification(int p_what) {
+
+ if (p_what==NOTIFICATION_ENTER_TREE) {
+
+ class_list->clear();
+ tree_item_map.clear();
+ TreeItem *root = class_list->create_item();
+ class_list->set_hide_root(true);
+ connect("confirmed",this,"_tree_item_selected");
+
+
+ for(Map<String,DocData::ClassDoc>::Element *E=EditorHelp::get_doc_data()->class_list.front();E;E=E->next()) {
+
+
+ add_type(E->key(),tree_item_map,root);
+ }
+
+ }
+}
+
+void EditorHelpIndex::_bind_methods() {
+
+ ObjectTypeDB::bind_method("_tree_item_selected",&EditorHelpIndex::_tree_item_selected);
+ ObjectTypeDB::bind_method("select_class",&EditorHelpIndex::select_class);
+ ADD_SIGNAL( MethodInfo("open_class"));
+}
+
+
+
+EditorHelpIndex::EditorHelpIndex() {
+
+
+ VBoxContainer *vbc = memnew( VBoxContainer );
+ add_child(vbc);
+ set_child_rect(vbc);
+
+ class_list = memnew( Tree );
+ vbc->add_margin_child("Class List: ",class_list,true);
+ class_list->set_v_size_flags(SIZE_EXPAND_FILL);
+
+
+ class_list->connect("item_activated",this,"_tree_item_selected");
+
+ get_ok()->set_text("Open");
+}
+
+
+
+/////////////////////////////////
+
+////////////////////////////////////
+/// /////////////////////////////////
DocData *EditorHelp::doc=NULL;
void EditorHelp::_unhandled_key_input(const InputEvent& p_ev) {
@@ -339,8 +468,6 @@ void EditorHelp::_unhandled_key_input(const InputEvent& p_ev) {
search->grab_focus();
search->select_all();
- } else if (p_ev.key.mod.shift && p_ev.key.scancode==KEY_F1) {
- class_search->popup();
}
}
@@ -351,17 +478,19 @@ void EditorHelp::_search(const String&) {
String stext=search->get_text();
- bool keep = prev_search==stext && class_list->get_selected() && prev_search_page==class_list->get_selected()->get_text(0);
+ bool keep = prev_search==stext;
- class_desc->search(stext, keep);
+ bool ret = class_desc->search(stext, keep);
+ if (!ret) {
+ class_desc->search(stext, false);
+ }
prev_search=stext;
- if (class_list->get_selected())
- prev_search_page=class_list->get_selected()->get_text(0);
}
+#if 0
void EditorHelp::_button_pressed(int p_idx) {
if (p_idx==PAGE_CLASS_LIST) {
@@ -399,16 +528,11 @@ void EditorHelp::_button_pressed(int p_idx) {
} else if (p_idx==PAGE_SEARCH) {
_search("");
- } else if (p_idx==CLASS_SEARCH) {
-
- class_search->popup();
}
-
-
}
-
+#endif
void EditorHelp::_class_list_select(const String& p_select) {
@@ -417,16 +541,28 @@ void EditorHelp::_class_list_select(const String& p_select) {
void EditorHelp::_class_desc_select(const String& p_select) {
+
+
+// print_line("LINK: "+p_select);
if (p_select.begins_with("#")) {
- _goto_desc(p_select.substr(1,p_select.length()));
+ //_goto_desc(p_select.substr(1,p_select.length()));
+ emit_signal("go_to_help","class_name:"+p_select.substr(1,p_select.length()));
return;
} else if (p_select.begins_with("@")) {
String m = p_select.substr(1,p_select.length());
- if (!method_line.has(m))
- return;
- class_desc->scroll_to_line(method_line[m]);
- return;
+
+ if (m.find(".")!=-1) {
+ //must go somewhere else
+
+ emit_signal("go_to_help","class_method:"+m.get_slice(".",0)+":"+m.get_slice(".",0));
+ } else {
+
+ if (!method_line.has(m))
+ return;
+ class_desc->scroll_to_line(method_line[m]);
+ }
+
}
@@ -449,68 +585,40 @@ void EditorHelp::_add_type(const String& p_type) {
}
-void EditorHelp::_update_history_buttons() {
-
- back->set_disabled(history_pos<2);
- forward->set_disabled(history_pos>=history.size());
-
-}
-
-
void EditorHelp::_scroll_changed(double p_scroll) {
if (scroll_locked)
return;
- int p = history_pos -1;
- if (p<0 || p>=history.size())
- return;
-
if (class_desc->get_v_scroll()->is_hidden())
p_scroll=0;
- history[p].scroll=p_scroll;
+ //history[p].scroll=p_scroll;
}
-Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_vscr) {
+Error EditorHelp::_goto_desc(const String& p_class,int p_vscr) {
//ERR_FAIL_COND(!doc->class_list.has(p_class));
if (!doc->class_list.has(p_class))
return ERR_DOES_NOT_EXIST;
- if (tree_item_map.has(p_class)) {
+ //if (tree_item_map.has(p_class)) {
select_locked = true;
- tree_item_map[p_class]->select(0);
- class_list->ensure_cursor_is_visible();
- }
+ //}
class_desc->show();
//tabs->set_current_tab(PAGE_CLASS_DESC);
- edited_class->set_pressed(true);
- class_list_button->set_pressed(false);
description_line=0;
- if (p_class==edited_class->get_text())
+ if (p_class==edited_class)
return OK; //already there
scroll_locked=true;
- if (p_update_history) {
-
- history.resize(history_pos);
- history_pos++;
- History h;
- h.c=p_class;
- h.scroll=0;
- history.push_back(h);
- _update_history_buttons();
- class_desc->get_v_scroll()->set_val(0);
- }
-
class_desc->clear();
method_line.clear();
- edited_class->set_text(p_class);
+ edited_class=p_class;
//edited_class->show();
@@ -529,7 +637,7 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/keyword_color"));
class_desc->add_text("Class: ");
class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/base_type_color"));
- class_desc->add_text(p_class);
+ _add_text(p_class);
class_desc->pop();
class_desc->pop();
class_desc->pop();
@@ -560,7 +668,13 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
//class_desc->add_newline();
class_desc->add_newline();
+ class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/text_color"));
+ class_desc->push_font( get_font("normal","Fonts") );
+ class_desc->push_indent(1);
_add_text(cd.brief_description);
+ class_desc->pop();
+ class_desc->pop();
+ class_desc->pop();
class_desc->add_newline();
class_desc->add_newline();
}
@@ -576,22 +690,34 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
class_desc->pop();
//class_desc->add_newline();
- class_desc->add_newline();
+// class_desc->add_newline();
class_desc->push_indent(1);
+ class_desc->push_table(2);
+ class_desc->set_table_column_expand(1,1);
for(int i=0;i<cd.methods.size();i++) {
+ class_desc->push_cell();
+
+
method_line[cd.methods[i].name]=class_desc->get_line_count()-2; //gets overriden if description
+ class_desc->push_align(RichTextLabel::ALIGN_RIGHT);
class_desc->push_font(doc_code_font);
_add_type(cd.methods[i].return_type);
- class_desc->add_text(" ");
+ //class_desc->add_text(" ");
+ class_desc->pop(); //align
+ class_desc->pop(); //font
+ class_desc->pop(); //cell
+ class_desc->push_cell();
+ class_desc->push_font(doc_code_font);
+
if (cd.methods[i].description!="") {
method_descr=true;
class_desc->push_meta("@"+cd.methods[i].name);
}
class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/text_color"));
- class_desc->add_text(cd.methods[i].name);
+ _add_text(cd.methods[i].name);
class_desc->pop();
if (cd.methods[i].description!="")
class_desc->pop();
@@ -603,13 +729,14 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
if (j>0)
class_desc->add_text(", ");
_add_type(cd.methods[i].arguments[j].type);
- class_desc->add_text(" "+cd.methods[i].arguments[j].name);
+ class_desc->add_text(" ");
+ _add_text(cd.methods[i].arguments[j].name);
if (cd.methods[i].arguments[j].default_value!="") {
class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/symbol_color"));
class_desc->add_text("=");
class_desc->pop();
- class_desc->add_text(cd.methods[i].arguments[j].default_value);
+ _add_text(cd.methods[i].arguments[j].default_value);
}
class_desc->pop();
@@ -621,17 +748,20 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
if (cd.methods[i].qualifiers!="") {
class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/keyword_color"));
- class_desc->add_text(" "+cd.methods[i].qualifiers);
+ class_desc->add_text(" ");
+ _add_text(cd.methods[i].qualifiers);
class_desc->pop();
}
class_desc->pop();//monofont
- class_desc->add_newline();
+// class_desc->add_newline();
+ class_desc->pop(); //cell
}
-
+ class_desc->pop(); //table
class_desc->pop();
class_desc->add_newline();
+ class_desc->add_newline();
}
@@ -655,7 +785,8 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
class_desc->push_font(doc_code_font);
_add_type(cd.properties[i].type);
class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/text_color"));
- class_desc->add_text(" "+cd.properties[i].name);
+ class_desc->add_text(" ");
+ _add_text(cd.properties[i].name);
class_desc->pop();
class_desc->pop();
@@ -663,7 +794,7 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
class_desc->push_font(doc_font);
class_desc->add_text(" ");
class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/comment_color"));
- class_desc->add_text(cd.properties[i].description);
+ _add_text(cd.properties[i].description);
class_desc->pop();
class_desc->pop();
@@ -698,7 +829,8 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
class_desc->push_font(doc_code_font);
_add_type(cd.theme_properties[i].type);
class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/text_color"));
- class_desc->add_text(" "+cd.theme_properties[i].name);
+ class_desc->add_text(" ");
+ _add_text(cd.theme_properties[i].name);
class_desc->pop();
class_desc->pop();
@@ -706,7 +838,7 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
class_desc->push_font(doc_font);
class_desc->add_text(" ");
class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/comment_color"));
- class_desc->add_text(cd.theme_properties[i].description);
+ _add_text(cd.theme_properties[i].description);
class_desc->pop();
class_desc->pop();
@@ -736,11 +868,11 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
for(int i=0;i<cd.signals.size();i++) {
signal_line[cd.signals[i].name]=class_desc->get_line_count()-2; //gets overriden if description
- class_desc->push_font(doc_code_font);
+ class_desc->push_font(doc_code_font); // monofont
//_add_type("void");
//class_desc->add_text(" ");
class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/text_color"));
- class_desc->add_text(cd.signals[i].name);
+ _add_text(cd.signals[i].name);
class_desc->pop();
class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/symbol_color"));
class_desc->add_text(cd.signals[i].arguments.size()?"( ":"(");
@@ -750,13 +882,14 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
if (j>0)
class_desc->add_text(", ");
_add_type(cd.signals[i].arguments[j].type);
- class_desc->add_text(" "+cd.signals[i].arguments[j].name);
+ class_desc->add_text(" ");
+ _add_text(cd.signals[i].arguments[j].name);
if (cd.signals[i].arguments[j].default_value!="") {
class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/symbol_color"));
class_desc->add_text("=");
class_desc->pop();
- class_desc->add_text(cd.signals[i].arguments[j].default_value);
+ _add_text(cd.signals[i].arguments[j].default_value);
}
class_desc->pop();
@@ -765,14 +898,15 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/symbol_color"));
class_desc->add_text(cd.signals[i].arguments.size()?" )":")");
class_desc->pop();
+ class_desc->pop(); // end monofont
if (cd.signals[i].description!="") {
class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/comment_color"));
- class_desc->add_text(" "+cd.signals[i].description);
+ class_desc->add_text(" ");
+ _add_text(cd.signals[i].description);
class_desc->pop();
}
- class_desc->pop();//monofont
class_desc->add_newline();
}
@@ -800,20 +934,20 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
constant_line[cd.constants[i].name]=class_desc->get_line_count()-2;
class_desc->push_font(doc_code_font);
class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/base_type_color"));
- class_desc->add_text(cd.constants[i].name);
+ _add_text(cd.constants[i].name);
class_desc->pop();
class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/symbol_color"));
class_desc->add_text(" = ");
class_desc->pop();
class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/keyword_color"));
- class_desc->add_text(cd.constants[i].value);
+ _add_text(cd.constants[i].value);
class_desc->pop();
class_desc->pop();
if (cd.constants[i].description!="") {
class_desc->push_font(doc_font);
class_desc->add_text(" ");
class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/comment_color"));
- class_desc->add_text(cd.constants[i].description);
+ _add_text(cd.constants[i].description);
class_desc->pop();
class_desc->pop();
}
@@ -838,7 +972,13 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
class_desc->add_newline();
class_desc->add_newline();
+ class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/text_color"));
+ class_desc->push_font( get_font("normal","Fonts") );
+ class_desc->push_indent(1);
_add_text(cd.description);
+ class_desc->pop();
+ class_desc->pop();
+ class_desc->pop();
class_desc->add_newline();
class_desc->add_newline();
}
@@ -864,7 +1004,7 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
class_desc->add_text(" ");
class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/text_color"));
- class_desc->add_text(cd.methods[i].name);
+ _add_text(cd.methods[i].name);
class_desc->pop();
class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/symbol_color"));
class_desc->add_text(cd.methods[i].arguments.size()?"( ":"(");
@@ -874,13 +1014,14 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
if (j>0)
class_desc->add_text(", ");
_add_type(cd.methods[i].arguments[j].type);
- class_desc->add_text(" "+cd.methods[i].arguments[j].name);
+ class_desc->add_text(" ");
+ _add_text(cd.methods[i].arguments[j].name);
if (cd.methods[i].arguments[j].default_value!="") {
class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/symbol_color"));
class_desc->add_text("=");
class_desc->pop();
- class_desc->add_text(cd.methods[i].arguments[j].default_value);
+ _add_text(cd.methods[i].arguments[j].default_value);
}
class_desc->pop();
@@ -892,7 +1033,8 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
if (cd.methods[i].qualifiers!="") {
class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/keyword_color"));
- class_desc->add_text(" "+cd.methods[i].qualifiers);
+ class_desc->add_text(" ");
+ _add_text(cd.methods[i].qualifiers);
class_desc->pop();
}
@@ -900,8 +1042,14 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
class_desc->pop();
class_desc->add_newline();
- class_desc->add_newline();
+ class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/text_color"));
+ class_desc->push_font( get_font("normal","Fonts") );
+ class_desc->push_indent(1);
_add_text(cd.methods[i].description);
+ class_desc->pop();
+ class_desc->pop();
+ class_desc->pop();
+ class_desc->add_newline();
class_desc->add_newline();
class_desc->add_newline();
@@ -913,10 +1061,7 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
}
- if (!p_update_history) {
- class_desc->get_v_scroll()->set_val(history[history_pos-1].scroll);
- }
scroll_locked=false;
@@ -926,9 +1071,7 @@ Error EditorHelp::_goto_desc(const String& p_class,bool p_update_history,int p_v
void EditorHelp::_request_help(const String& p_string) {
Error err = _goto_desc(p_string);
if (err==OK) {
- editor->call("_editor_select",3);
- } else {
- class_search->popup(p_string);
+ editor->call("_editor_select",EditorNode::EDITOR_SCRIPT);
}
//100 palabras
}
@@ -968,16 +1111,16 @@ void EditorHelp::_help_callback(const String& p_topic) {
line=constant_line[name];
}
- class_desc->scroll_to_line(line);
+ class_desc->call_deferred("scroll_to_line", line);
}
void EditorHelp::_add_text(const String& p_bbcode) {
- class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/text_color"));
+ /*class_desc->push_color(EditorSettings::get_singleton()->get("text_editor/text_color"));
class_desc->push_font( get_font("normal","Fonts") );
- class_desc->push_indent(1);
+ class_desc->push_indent(1);*/
int pos = 0;
List<String> tag_stack;
@@ -1055,7 +1198,7 @@ void EditorHelp::_add_text(const String& p_bbcode) {
} else if (tag=="i") {
//use italics font
- //class_desc->push_font(get_font("italic","Fonts"));
+ class_desc->push_font(get_font("italic","Fonts"));
pos=brk_end+1;
tag_stack.push_front(tag);
} else if (tag=="code") {
@@ -1191,319 +1334,160 @@ void EditorHelp::_add_text(const String& p_bbcode) {
}
}
+ /*class_desc->pop();
class_desc->pop();
- class_desc->pop();
+ class_desc->pop();*/
}
-void EditorHelp::add_type(const String& p_type,HashMap<String,TreeItem*>& p_types,TreeItem *p_root) {
-
- if (p_types.has(p_type))
- return;
-// if (!ObjectTypeDB::is_type(p_type,base) || p_type==base)
-// return;
- String inherits=doc->class_list[p_type].inherits;
- TreeItem *parent=p_root;
+void EditorHelp::_update_doc() {
- if (inherits.length()) {
-
- if (!p_types.has(inherits)) {
- add_type(inherits,p_types,p_root);
- }
-
- if (p_types.has(inherits) )
- parent=p_types[inherits];
- }
+}
- TreeItem *item = class_list->create_item(parent);
- item->set_metadata(0,p_type);
- item->set_tooltip(0,doc->class_list[p_type].brief_description);
- item->set_text(0,p_type);
+void EditorHelp::generate_doc() {
- if (has_icon(p_type,"EditorIcons")) {
+ doc = memnew( DocData );
+ doc->generate(true);
+ DocData compdoc;
+ compdoc.load_compressed(_doc_data_compressed,_doc_data_compressed_size,_doc_data_uncompressed_size);
+ doc->merge_from(compdoc); //ensure all is up to date
- item->set_icon(0, get_icon(p_type,"EditorIcons"));
- }
- p_types[p_type]=item;
}
+void EditorHelp::_notification(int p_what) {
-void EditorHelp::_update_doc() {
-
-
- class_list->clear();
-
- List<String> type_list;
-
- tree_item_map.clear();
+ switch(p_what) {
- TreeItem *root = class_list->create_item();
- class_list->set_hide_root(true);
- List<String>::Element *I=type_list.front();
+ case NOTIFICATION_READY: {
- for(Map<String,DocData::ClassDoc>::Element *E=doc->class_list.front();E;E=E->next()) {
+// forward->set_icon(get_icon("Forward","EditorIcons"));
+// back->set_icon(get_icon("Back","EditorIcons"));
+ _update_doc();
- add_type(E->key(),tree_item_map,root);
+ } break;
}
+}
+
+void EditorHelp::go_to_help(const String& p_help) {
+ _help_callback(p_help);
}
+void EditorHelp::go_to_class(const String& p_class,int p_scroll) {
-void EditorHelp::generate_doc() {
+ _goto_desc(p_class,p_scroll);
+}
- doc = memnew( DocData );
- doc->generate(true);
- DocData compdoc;
- compdoc.load_compressed(_doc_data_compressed,_doc_data_compressed_size,_doc_data_uncompressed_size);
- doc->merge_from(compdoc); //ensure all is up to date
+void EditorHelp::popup_search() {
+ search_dialog->popup_centered(Size2(250,80));
+ search->grab_focus();
}
-void EditorHelp::_notification(int p_what) {
+void EditorHelp::_search_cbk() {
+ _search(search->get_text());
+}
- switch(p_what) {
+String EditorHelp::get_class_name() {
- case NOTIFICATION_READY: {
+ return edited_class;
+}
+void EditorHelp::search_again() {
+ _search(prev_search);
+}
- forward->set_icon(get_icon("Forward","EditorIcons"));
- back->set_icon(get_icon("Back","EditorIcons"));
- _update_doc();
- editor->connect("request_help",this,"_request_help");
+int EditorHelp::get_scroll() const {
- } break;
- }
+ return class_desc->get_v_scroll()->get_val();
}
+void EditorHelp::set_scroll(int p_scroll) {
-void EditorHelp::_tree_item_selected() {
- if (select_locked) {
- select_locked = false;
- return;
- }
- TreeItem *s=class_list->get_selected();
- if (!s)
- return;
- select_locked=true;
- _goto_desc(s->get_text(0));
- select_locked=false;
+ class_desc->get_v_scroll()->set_val(p_scroll);
+
}
void EditorHelp::_bind_methods() {
ObjectTypeDB::bind_method("_class_list_select",&EditorHelp::_class_list_select);
ObjectTypeDB::bind_method("_class_desc_select",&EditorHelp::_class_desc_select);
- ObjectTypeDB::bind_method("_button_pressed",&EditorHelp::_button_pressed);
+// ObjectTypeDB::bind_method("_button_pressed",&EditorHelp::_button_pressed);
ObjectTypeDB::bind_method("_scroll_changed",&EditorHelp::_scroll_changed);
ObjectTypeDB::bind_method("_request_help",&EditorHelp::_request_help);
ObjectTypeDB::bind_method("_unhandled_key_input",&EditorHelp::_unhandled_key_input);
ObjectTypeDB::bind_method("_search",&EditorHelp::_search);
- ObjectTypeDB::bind_method("_tree_item_selected",&EditorHelp::_tree_item_selected);
+ ObjectTypeDB::bind_method("_search_cbk",&EditorHelp::_search_cbk);
ObjectTypeDB::bind_method("_help_callback",&EditorHelp::_help_callback);
+ ADD_SIGNAL(MethodInfo("go_to_help"));
+
}
-EditorHelp::EditorHelp(EditorNode *p_editor) {
+EditorHelp::EditorHelp() {
- editor=p_editor;
+ editor=EditorNode::get_singleton();
VBoxContainer *vbc = this;
- HBoxContainer *panel_hb = memnew( HBoxContainer );
-
- Button *b = memnew( Button );
- b->set_text("Class List");
- panel_hb->add_child(b);
- vbc->add_child(panel_hb);
- b->set_toggle_mode(true);
- b->set_pressed(true);
- b->connect("pressed",this,"_button_pressed",make_binds(PAGE_CLASS_LIST));
- class_list_button=b;
- class_list_button->hide();
-
- b = memnew( Button );
- b->set_text("Class");
- panel_hb->add_child(b);
- edited_class=b;
- edited_class->hide();
- b->set_toggle_mode(true);
- b->connect("pressed",this,"_button_pressed",make_binds(PAGE_CLASS_DESC));
-
- b = memnew( Button );
- b->set_text("Search in Classes");
- panel_hb->add_child(b);
- b->connect("pressed",this,"_button_pressed",make_binds(CLASS_SEARCH));
-
- Control *expand = memnew( Control );
- expand->set_h_size_flags(SIZE_EXPAND_FILL);
- panel_hb->add_child(expand);
-
- b = memnew( Button );
- panel_hb->add_child(b);
- back=b;
- b->connect("pressed",this,"_button_pressed",make_binds(PAGE_CLASS_PREV));
-
- b = memnew( Button );
- panel_hb->add_child(b);
- forward=b;
- b->connect("pressed",this,"_button_pressed",make_binds(PAGE_CLASS_NEXT));
-
- Separator *hs = memnew( VSeparator );
- panel_hb->add_child(hs);
- Control *ec = memnew( Control );
- ec->set_custom_minimum_size(Size2(200,1));
- panel_hb->add_child(ec);
- search = memnew( LineEdit );
- ec->add_child(search);
- search->set_area_as_parent_rect();
- search->connect("text_entered",this,"_search");
-
- b = memnew( Button );
- b->set_text("Find");
- panel_hb->add_child(b);
- b->connect("pressed",this,"_button_pressed",make_binds(PAGE_SEARCH));
-
- hs = memnew( VSeparator );
- panel_hb->add_child(hs);
-
- h_split = memnew( HSplitContainer );
- h_split->set_v_size_flags(SIZE_EXPAND_FILL);
-
- vbc->add_child(h_split);
-
- class_list = memnew( Tree );
- h_split->add_child(class_list);
//class_list->connect("meta_clicked",this,"_class_list_select");
//class_list->set_selection_enabled(true);
{
- PanelContainer *pc = memnew( PanelContainer );
+ Panel *pc = memnew( Panel );
Ref<StyleBoxFlat> style( memnew( StyleBoxFlat ) );
- style->set_bg_color( EditorSettings::get_singleton()->get("text_editor/background_color") );
+ style->set_bg_color( EditorSettings::get_singleton()->get("text_editor/background_color") );
+ pc->set_v_size_flags(SIZE_EXPAND_FILL);
pc->add_style_override("panel", style); //get_stylebox("normal","TextEdit"));
- h_split->add_child(pc);
+ vbc->add_child(pc);
class_desc = memnew( RichTextLabel );
pc->add_child(class_desc);
+ class_desc->set_area_as_parent_rect(8);
class_desc->connect("meta_clicked",this,"_class_desc_select");
}
class_desc->get_v_scroll()->connect("value_changed",this,"_scroll_changed");
class_desc->set_selection_enabled(true);
- editor=p_editor;
- history_pos=0;
+
scroll_locked=false;
select_locked=false;
set_process_unhandled_key_input(true);
- h_split->set_split_offset(200);
- class_list->connect("cell_selected",this,"_tree_item_selected");
class_desc->hide();
- class_search = memnew( EditorHelpSearch(editor) );
- editor->get_gui_base()->add_child(class_search);
- class_search->connect("go_to_help",this,"_help_callback");
-// prev_search_page=-1;
-}
-
-EditorHelp::~EditorHelp() {
- if (doc)
- memdelete(doc);
-}
-
-
-void EditorHelpPlugin::edit(Object *p_object) {
-
- if (!p_object->cast_to<Script>())
- return;
-
- //editor_help->edit(p_object->cast_to<Script>());
-}
-
-bool EditorHelpPlugin::handles(Object *p_object) const {
-
- return false;
-}
-
-void EditorHelpPlugin::make_visible(bool p_visible) {
-
- if (p_visible) {
- editor_help->show();
- } else {
-
- editor_help->hide();
- }
-
-}
-
-void EditorHelpPlugin::selected_notify() {
-
- //editor_help->ensure_select_current();
-}
-
-Dictionary EditorHelpPlugin::get_state() const {
-
- return Dictionary();
-}
-
-void EditorHelpPlugin::set_state(const Dictionary& p_state) {
-
- //editor_help->set_state(p_state);
-}
-void EditorHelpPlugin::clear() {
-
- //editor_help->clear();
-}
-
-void EditorHelpPlugin::save_external_data() {
-
- //editor_help->save_external_data();
-}
-
-void EditorHelpPlugin::apply_changes() {
-
- //editor_help->apply_helps();
-}
-
-void EditorHelpPlugin::restore_global_state() {
-
- //if (bool(EDITOR_DEF("text_editor/restore_helps_on_load",true))) {
-// editor_help->_load_files_state();
- //}
-
-}
+ search_dialog = memnew( ConfirmationDialog );
+ add_child(search_dialog);
+ VBoxContainer *search_vb = memnew( VBoxContainer );
+ search_dialog->add_child(search_vb);
+ search_dialog->set_child_rect(search_vb);
+ search = memnew( LineEdit );
+ search_dialog->register_text_enter(search);
+ search_vb->add_margin_child("Search Text",search);
+ search_dialog->get_ok()->set_text("Find");
+ search_dialog->connect("confirmed",this,"_search_cbk");
+ search_dialog->set_hide_on_ok(false);
+ search_dialog->set_self_opacity(0.8);
-void EditorHelpPlugin::save_global_state() {
- //if (bool(EDITOR_DEF("text_editor/restore_helps_on_load",true))) {
-// editor_help->_save_files_state();
-// }
+ /*class_search = memnew( EditorHelpSearch(editor) );
+ editor->get_gui_base()->add_child(class_search);
+ class_search->connect("go_to_help",this,"_help_callback");*/
+// prev_search_page=-1;
}
-
-EditorHelpPlugin::EditorHelpPlugin(EditorNode *p_node) {
-
- editor=p_node;
- editor_help = memnew( EditorHelp(p_node) );
- editor->get_viewport()->add_child(editor_help);
- editor_help->set_area_as_parent_rect();
- editor_help->hide();
-
+EditorHelp::~EditorHelp() {
}
-
-EditorHelpPlugin::~EditorHelpPlugin()
-{
-}
diff --git a/tools/editor/editor_help.h b/tools/editor/editor_help.h
index d4066d076a..059a7ae11d 100644
--- a/tools/editor/editor_help.h
+++ b/tools/editor/editor_help.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -68,11 +68,32 @@ protected:
static void _bind_methods();
public:
- void popup(const String& p_term="");
+ void popup();
+ void popup(const String& p_term);
- EditorHelpSearch(EditorNode *p_editor);
+ EditorHelpSearch();
};
+class EditorHelpIndex : public ConfirmationDialog {
+ OBJ_TYPE( EditorHelpIndex, ConfirmationDialog );
+
+
+ Tree *class_list;
+ HashMap<String,TreeItem*> tree_item_map;
+
+ void _tree_item_selected();
+ void add_type(const String& p_type,HashMap<String,TreeItem*>& p_types,TreeItem *p_root);
+protected:
+
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+
+ void select_class(const String& p_class);
+
+ EditorHelpIndex();
+};
class EditorHelp : public VBoxContainer {
@@ -91,17 +112,11 @@ class EditorHelp : public VBoxContainer {
};
- struct History {
- String c;
- int scroll;
- };
-
- Vector<History> history;
- int history_pos;
bool select_locked;
String prev_search;
- String prev_search_page;
+
+ String edited_class;
EditorNode *editor;
Map<String,int> method_line;
@@ -111,21 +126,17 @@ class EditorHelp : public VBoxContainer {
Map<String,int> constant_line;
int description_line;
- Tree *class_list;
RichTextLabel *class_desc;
HSplitContainer *h_split;
static DocData *doc;
- Button *class_list_button;
- Button *edited_class;
- Button *back;
- Button *forward;
+
+ ConfirmationDialog *search_dialog;
LineEdit *search;
- String base_path;
- HashMap<String,TreeItem*> tree_item_map;
+ String base_path;
void _help_callback(const String& p_topic);
@@ -133,25 +144,24 @@ class EditorHelp : public VBoxContainer {
void _add_text(const String& p_text);
bool scroll_locked;
- void _button_pressed(int p_idx);
+ //void _button_pressed(int p_idx);
void _add_type(const String& p_type);
void _scroll_changed(double p_scroll);
void _class_list_select(const String& p_select);
void _class_desc_select(const String& p_select);
- Error _goto_desc(const String& p_class,bool p_update_history=true,int p_vscr=-1);
- void _update_history_buttons();
+ Error _goto_desc(const String& p_class, int p_vscr=-1);
+ //void _update_history_buttons();
void _update_doc();
void _request_help(const String& p_string);
void _search(const String& p_str);
+ void _search_cbk();
void _unhandled_key_input(const InputEvent& p_ev);
- void add_type(const String& p_type,HashMap<String,TreeItem*>& p_types,TreeItem *p_root);
- void _tree_item_selected();
- EditorHelpSearch *class_search;
+
protected:
@@ -163,41 +173,25 @@ public:
static void generate_doc();
static DocData *get_doc_data() { return doc; }
- EditorHelp(EditorNode *p_editor=NULL);
- ~EditorHelp();
-};
-
-
+ void go_to_help(const String& p_help);
+ void go_to_class(const String& p_class,int p_scroll=0);
-class EditorHelpPlugin : public EditorPlugin {
+ void popup_search();
+ void search_again();
- OBJ_TYPE( EditorHelpPlugin, EditorPlugin );
+ String get_class_name();
- EditorHelp *editor_help;
- EditorNode *editor;
-public:
+ void set_focused() { class_desc->grab_focus(); }
- virtual String get_name() const { return "Help"; }
- bool has_main_screen() const { return true; }
- virtual void edit(Object *p_node);
- virtual bool handles(Object *p_node) const;
- virtual void make_visible(bool p_visible);
- virtual void selected_notify();
+ int get_scroll() const;
+ void set_scroll(int p_scroll);
- Dictionary get_state() const;
- virtual void set_state(const Dictionary& p_state);
- virtual void clear();
-
- virtual void save_external_data();
- virtual void apply_changes();
+ EditorHelp();
+ ~EditorHelp();
+};
- virtual void restore_global_state();
- virtual void save_global_state();
- EditorHelpPlugin(EditorNode *p_node);
- ~EditorHelpPlugin();
-};
#endif // EDITOR_HELP_H
diff --git a/tools/editor/editor_icons.h b/tools/editor/editor_icons.h
index 910febc895..191b908682 100644
--- a/tools/editor/editor_icons.h
+++ b/tools/editor/editor_icons.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/editor_import_export.cpp b/tools/editor/editor_import_export.cpp
index 4e6435b22e..5203ace125 100644
--- a/tools/editor/editor_import_export.cpp
+++ b/tools/editor/editor_import_export.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -40,6 +40,9 @@
#include "io/resource_saver.h"
#include "io/md5.h"
#include "io_plugins/editor_texture_import_plugin.h"
+#include "tools/editor/plugins/script_editor_plugin.h"
+#include "io/zip_io.h"
+
String EditorImportPlugin::validate_source_path(const String& p_path) {
@@ -254,7 +257,16 @@ static void _add_filter_to_list(Set<StringName>& r_list,const String& p_filter)
}
+Vector<uint8_t> EditorExportPlatform::get_exported_file_default(String& p_fname) const {
+ FileAccess *f = FileAccess::open(p_fname,FileAccess::READ);
+ ERR_FAIL_COND_V(!f,Vector<uint8_t>());
+ Vector<uint8_t> ret;
+ ret.resize(f->get_len());
+ int rbs = f->get_buffer(ret.ptr(),ret.size());
+ memdelete(f);
+ return ret;
+}
Vector<uint8_t> EditorExportPlatform::get_exported_file(String& p_fname) const {
@@ -269,13 +281,9 @@ Vector<uint8_t> EditorExportPlatform::get_exported_file(String& p_fname) const {
}
- FileAccess *f = FileAccess::open(p_fname,FileAccess::READ);
- ERR_FAIL_COND_V(!f,Vector<uint8_t>());
- Vector<uint8_t> ret;
- ret.resize(f->get_len());
- int rbs = f->get_buffer(ret.ptr(),ret.size());
- memdelete(f);
- return ret;
+ return get_exported_file_default(p_fname);
+
+
}
Vector<StringName> EditorExportPlatform::get_dependencies(bool p_bundles) const {
@@ -393,6 +401,40 @@ Vector<StringName> EditorExportPlatform::get_dependencies(bool p_bundles) const
}
+String EditorExportPlatform::find_export_template(String template_file_name, String *err) const {
+ String user_file = EditorSettings::get_singleton()->get_settings_path()
+ +"/templates/"+template_file_name;
+ String system_file=OS::get_singleton()->get_installed_templates_path();
+ bool has_system_path=(system_file!="");
+ system_file+=template_file_name;
+
+ // Prefer user file
+ if (FileAccess::exists(user_file)) {
+ return user_file;
+ }
+
+ // Now check system file
+ if (has_system_path) {
+ if (FileAccess::exists(system_file)) {
+ return system_file;
+ }
+ }
+
+ // Not found
+ if (err) {
+ *err+="No export template found at \""+user_file+"\"";
+ if (has_system_path)
+ *err+="\n or \""+system_file+"\".";
+ else
+ *err+=".";
+ }
+ return "";
+}
+
+bool EditorExportPlatform::exists_export_template(String template_file_name, String *err) const {
+ return find_export_template(template_file_name,err)!="";
+}
+
///////////////////////////////////////
@@ -413,6 +455,9 @@ bool EditorExportPlatformPC::_set(const StringName& p_name, const Variant& p_val
} else if (n=="resources/pack_mode") {
export_mode=ExportMode(int(p_value));
+ } else if (n=="resources/bundle_dependencies_(for_optical_disc)") {
+
+ bundle=p_value;
} else if (n=="binary/64_bits") {
use64=p_value;
@@ -436,6 +481,9 @@ bool EditorExportPlatformPC::_get(const StringName& p_name,Variant &r_ret) const
} else if (n=="resources/pack_mode") {
r_ret=export_mode;
+ } else if (n=="resources/bundle_dependencies_(for_optical_disc)") {
+
+ r_ret=bundle;
} else if (n=="binary/64_bits") {
r_ret=use64;
@@ -450,7 +498,8 @@ void EditorExportPlatformPC::_get_property_list( List<PropertyInfo> *p_list) con
p_list->push_back( PropertyInfo( Variant::STRING, "custom_binary/debug", PROPERTY_HINT_GLOBAL_FILE,binary_extension));
p_list->push_back( PropertyInfo( Variant::STRING, "custom_binary/release", PROPERTY_HINT_GLOBAL_FILE,binary_extension));
- p_list->push_back( PropertyInfo( Variant::INT, "resources/pack_mode", PROPERTY_HINT_ENUM,"Single Exec.,Exec+Pack (.pck),Copy,Bundles (Optical)"));
+ p_list->push_back( PropertyInfo( Variant::INT, "resources/pack_mode", PROPERTY_HINT_ENUM,"Pack into executable,Pack into binary file (.pck),Pack into archive file (.zip)"));
+ p_list->push_back( PropertyInfo( Variant::BOOL, "resources/bundle_dependencies_(for_optical_disc)"));
p_list->push_back( PropertyInfo( Variant::BOOL, "binary/64_bits"));
}
@@ -556,6 +605,7 @@ Error EditorExportPlatform::export_project_files(EditorExportSaveFunction p_func
group_shrink*=EditorImportExport::get_singleton()->get_export_image_shrink();
switch(EditorImportExport::get_singleton()->image_export_group_get_image_action(E->get())) {
+ case EditorImportExport::IMAGE_ACTION_KEEP:
case EditorImportExport::IMAGE_ACTION_NONE: {
switch(EditorImportExport::get_singleton()->get_export_image_action()) {
@@ -580,7 +630,7 @@ Error EditorExportPlatform::export_project_files(EditorExportSaveFunction p_func
} break; //use default
case EditorImportExport::IMAGE_ACTION_COMPRESS_RAM: {
group_format=EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_RAM;
- } break; //use default
+ } break; //use default
}
String image_list_md5;
@@ -824,13 +874,43 @@ Error EditorExportPlatform::export_project_files(EditorExportSaveFunction p_func
StringName engine_cfg="res://engine.cfg";
+ StringName boot_splash;
+ {
+ String splash=Globals::get_singleton()->get("application/boot_splash"); //avoid splash from being converted
+ splash=splash.strip_edges();
+ if (splash!=String()) {
+ if (!splash.begins_with("res://"))
+ splash="res://"+splash;
+ splash=splash.simplify_path();
+ boot_splash=splash;
+ }
+ }
+ StringName custom_cursor;
+ {
+ String splash=Globals::get_singleton()->get("display/custom_mouse_cursor"); //avoid splash from being converted
+ splash=splash.strip_edges();
+ if (splash!=String()) {
+ if (!splash.begins_with("res://"))
+ splash="res://"+splash;
+ splash=splash.simplify_path();
+ custom_cursor=splash;
+ }
+ }
+
+
+
for(int i=0;i<files.size();i++) {
if (remap_files.has(files[i]) || files[i]==engine_cfg) //gonna be remapped (happened before!)
continue; //from atlas?
String src=files[i];
- Vector<uint8_t> buf = get_exported_file(src);
+ Vector<uint8_t> buf;
+
+ if (src==boot_splash || src==custom_cursor)
+ buf = get_exported_file_default(src); //bootsplash must be kept if used
+ else
+ buf = get_exported_file(src);
ERR_CONTINUE( saved.has(src) );
@@ -916,6 +996,59 @@ static int _get_pad(int p_alignment, int p_n) {
return pad;
};
+void EditorExportPlatform::gen_export_flags(Vector<String> &r_flags, int p_flags) {
+
+ String host = EditorSettings::get_singleton()->get("network/debug_host");
+
+ if (p_flags&EXPORT_DUMB_CLIENT) {
+ int port = EditorSettings::get_singleton()->get("file_server/port");
+ String passwd = EditorSettings::get_singleton()->get("file_server/password");
+ r_flags.push_back("-rfs");
+ r_flags.push_back(host+":"+itos(port));
+ if (passwd!="") {
+ r_flags.push_back("-rfs_pass");
+ r_flags.push_back(passwd);
+ }
+ }
+
+ if (p_flags&EXPORT_REMOTE_DEBUG) {
+
+ r_flags.push_back("-rdebug");
+ r_flags.push_back(host+":"+String::num(GLOBAL_DEF("debug/debug_port", 6007)));
+
+ List<String> breakpoints;
+ ScriptEditor::get_singleton()->get_breakpoints(&breakpoints);
+
+
+ if (breakpoints.size()) {
+
+ r_flags.push_back("-bp");
+ String bpoints;
+ for(const List<String>::Element *E=breakpoints.front();E;E=E->next()) {
+
+ bpoints+=E->get().replace(" ","%20");
+ if (E->next())
+ bpoints+=",";
+ }
+
+ r_flags.push_back(bpoints);
+ }
+
+ }
+
+ if (p_flags&EXPORT_VIEW_COLLISONS) {
+
+ r_flags.push_back("-debugcol");
+ }
+
+ if (p_flags&EXPORT_VIEW_NAVIGATION) {
+
+ r_flags.push_back("-debugnav");
+ }
+
+
+}
+
Error EditorExportPlatform::save_pack_file(void *p_userdata,const String& p_path, const Vector<uint8_t>& p_data,int p_file,int p_total) {
@@ -938,7 +1071,7 @@ Error EditorExportPlatform::save_pack_file(void *p_userdata,const String& p_path
MD5Final(&ctx);
pd->f->store_buffer(ctx.digest,16);
}
- pd->ep->step("Storing File: "+p_path,2+p_file*100/p_total);
+ pd->ep->step("Storing File: "+p_path,2+p_file*100/p_total,false);
pd->count++;
pd->ftmp->store_buffer(p_data.ptr(),p_data.size());
if (pd->alignment > 1) {
@@ -953,6 +1086,58 @@ Error EditorExportPlatform::save_pack_file(void *p_userdata,const String& p_path
}
+Error EditorExportPlatform::save_zip_file(void *p_userdata,const String& p_path, const Vector<uint8_t>& p_data,int p_file,int p_total) {
+
+
+ String path=p_path.replace_first("res://","");
+
+ ZipData *zd = (ZipData*)p_userdata;
+
+ zipFile zip=(zipFile)zd->zip;
+
+ zipOpenNewFileInZip(zip,
+ path.utf8().get_data(),
+ NULL,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ NULL,
+ Z_DEFLATED,
+ Z_DEFAULT_COMPRESSION);
+
+ zipWriteInFileInZip(zip,p_data.ptr(),p_data.size());
+ zipCloseFileInZip(zip);
+
+ zd->ep->step("Storing File: "+p_path,2+p_file*100/p_total,false);
+ zd->count++;
+ return OK;
+
+}
+
+Error EditorExportPlatform::save_zip(const String& p_path, bool p_make_bundles) {
+
+ EditorProgress ep("savezip","Packing",102);
+
+ //FileAccess *tmp = FileAccess::open(tmppath,FileAccess::WRITE);
+
+ FileAccess *src_f;
+ zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
+ zipFile zip=zipOpen2(p_path.utf8().get_data(),APPEND_STATUS_CREATE,NULL,&io);
+
+ ZipData zd;
+ zd.count=0;
+ zd.ep=&ep;
+ zd.zip=zip;
+
+
+ Error err = export_project_files(save_zip_file,&zd,p_make_bundles);
+
+ zipClose(zip,NULL);
+
+ return err;
+}
+
Error EditorExportPlatform::save_pack(FileAccess *dst,bool p_make_bundles, int p_alignment) {
EditorProgress ep("savepack","Packing",102);
@@ -1029,7 +1214,7 @@ Error EditorExportPlatform::save_pack(FileAccess *dst,bool p_make_bundles, int p
return OK;
}
-Error EditorExportPlatformPC::export_project(const String& p_path, bool p_debug, bool p_dumb) {
+Error EditorExportPlatformPC::export_project(const String& p_path, bool p_debug, int p_flags) {
@@ -1041,19 +1226,32 @@ Error EditorExportPlatformPC::export_project(const String& p_path, bool p_debug,
ep.step("Setting Up..",0);
- String exe_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/";
- if (use64) {
- if (p_debug)
- exe_path=custom_debug_binary!=""?custom_debug_binary:exe_path+debug_binary64;
- else
- exe_path=custom_release_binary!=""?custom_release_binary:exe_path+release_binary64;
- } else {
+ String exe_path="";
- if (p_debug)
- exe_path=custom_debug_binary!=""?custom_debug_binary:exe_path+debug_binary32;
- else
- exe_path=custom_release_binary!=""?custom_release_binary:exe_path+release_binary32;
+ if (p_debug)
+ exe_path=custom_debug_binary;
+ else
+ exe_path=custom_release_binary;
+ if (exe_path=="") {
+ String fname;
+ if (use64) {
+ if (p_debug)
+ fname=debug_binary64;
+ else
+ fname=release_binary64;
+ } else {
+ if (p_debug)
+ fname=debug_binary32;
+ else
+ fname=release_binary32;
+ }
+ String err="";
+ exe_path=find_export_template(fname,&err);
+ if (exe_path=="") {
+ EditorNode::add_io_error(err);
+ return ERR_FILE_CANT_READ;
+ }
}
FileAccess *src_exe=FileAccess::open(exe_path,FileAccess::READ);
@@ -1083,26 +1281,32 @@ Error EditorExportPlatformPC::export_project(const String& p_path, bool p_debug,
}
}
+ String dstfile = p_path.replace_first("res://","").replace("\\","/");
if (export_mode!=EXPORT_EXE) {
- String dstfile=p_path.replace_first("res://","").replace("\\","/");
+ String dstfile_extension=export_mode==EXPORT_ZIP?".zip":".pck";
if (dstfile.find("/")!=-1)
- dstfile=dstfile.get_base_dir()+"/data.pck";
+ dstfile=dstfile.get_base_dir()+"/data"+dstfile_extension;
else
- dstfile="data.pck";
+ dstfile="data"+dstfile_extension;
+ if (export_mode==EXPORT_PACK) {
+
+ memdelete(dst);
- memdelete(dst);
- dst=FileAccess::open(dstfile,FileAccess::WRITE);
- if (!dst) {
+ dst=FileAccess::open(dstfile,FileAccess::WRITE);
+ if (!dst) {
- EditorNode::add_io_error("Can't write data pack to:\n "+p_path);
- return ERR_FILE_CANT_WRITE;
+ EditorNode::add_io_error("Can't write data pack to:\n "+p_path);
+ return ERR_FILE_CANT_WRITE;
+ }
}
}
+
+
memdelete(src_exe);
- Error err = save_pack(dst,export_mode==EXPORT_BUNDLES);
+ Error err = export_mode==EXPORT_ZIP?save_zip(dstfile,bundle):save_pack(dst,bundle);
memdelete(dst);
return err;
}
@@ -1117,32 +1321,42 @@ bool EditorExportPlatformPC::can_export(String *r_error) const {
String err;
bool valid=true;
- String exe_path = EditorSettings::get_singleton()->get_settings_path()+"/templates/";
+ if (use64 && (!exists_export_template(debug_binary64)) || !exists_export_template(release_binary64)) {
+ valid=false;
+ err="No 64 bits export templates found.\nDownload and install export templates.\n";
+ }
- if (!FileAccess::exists(exe_path+debug_binary32) || !FileAccess::exists(exe_path+release_binary32)) {
+ if (!use64 && (!exists_export_template(debug_binary32) || !exists_export_template(release_binary32))) {
valid=false;
err="No 32 bits export templates found.\nDownload and install export templates.\n";
}
- if (!FileAccess::exists(exe_path+debug_binary64) || !FileAccess::exists(exe_path+release_binary64)) {
- valid=false;
- err="No 64 bits export templates found.\nDownload and install export templates.\n";
+
+ if(custom_debug_binary=="" && custom_release_binary=="") {
+ if (r_error) *r_error=err;
+ return valid;
}
+ bool dvalid = true;
+ bool rvalid = true;
- if (custom_debug_binary!="" && !FileAccess::exists(custom_debug_binary)) {
- valid=false;
- err+="Custom debug binary not found.\n";
+ if(!FileAccess::exists(custom_debug_binary)) {
+ dvalid = false;
+ err = "Custom debug binary not found.\n";
}
- if (custom_release_binary!="" && !FileAccess::exists(custom_release_binary)) {
- valid=false;
- err+="Custom release binary not found.\n";
+ if(!FileAccess::exists(custom_release_binary)) {
+ rvalid = false;
+ err = "Custom release binary not found.\n";
}
+ if (dvalid || rvalid)
+ valid = true;
+ else
+ valid = false;
+
if (r_error)
*r_error=err;
return valid;
-
}
@@ -1330,12 +1544,12 @@ EditorImportExport::ImageAction EditorImportExport::get_export_image_action() co
return image_action;
}
-void EditorImportExport::set_export_image_shrink(int p_shrink) {
+void EditorImportExport::set_export_image_shrink(float p_shrink) {
image_shrink=p_shrink;
}
-int EditorImportExport::get_export_image_shrink() const{
+float EditorImportExport::get_export_image_shrink() const{
return image_shrink;
}
@@ -1406,12 +1620,12 @@ bool EditorImportExport::image_export_group_get_make_atlas(const StringName& p_e
return image_groups[p_export_group].make_atlas;
}
-void EditorImportExport::image_export_group_set_shrink(const StringName& p_export_group,int p_amount){
+void EditorImportExport::image_export_group_set_shrink(const StringName& p_export_group,float p_amount){
ERR_FAIL_COND(!image_groups.has(p_export_group));
image_groups[p_export_group].shrink=p_amount;
}
-int EditorImportExport::image_export_group_get_shrink(const StringName& p_export_group) const{
+float EditorImportExport::image_export_group_get_shrink(const StringName& p_export_group) const{
ERR_FAIL_COND_V(!image_groups.has(p_export_group),1);
return image_groups[p_export_group].shrink;
@@ -1460,6 +1674,17 @@ void EditorImportExport::image_export_get_images_in_group(const StringName& p_gr
}
}
+void EditorImportExport::set_convert_text_scenes(bool p_convert) {
+
+ convert_text_scenes=p_convert;
+}
+
+bool EditorImportExport::get_convert_text_scenes() const{
+
+ return convert_text_scenes;
+}
+
+
void EditorImportExport::load_config() {
Ref<ConfigFile> cf = memnew( ConfigFile );
@@ -1502,6 +1727,12 @@ void EditorImportExport::load_config() {
}
}
+ if (cf->has_section("convert_scenes")) {
+
+ convert_text_scenes = cf->get_value("convert_scenes","convert_text_scenes");
+ }
+
+
if (cf->has_section("export_filter_files")) {
@@ -1565,6 +1796,8 @@ void EditorImportExport::load_config() {
g.action=IMAGE_ACTION_COMPRESS_RAM;
else if (action=="compress_disk")
g.action=IMAGE_ACTION_COMPRESS_DISK;
+ else if (action=="keep")
+ g.action=IMAGE_ACTION_KEEP;
}
if (d.has("atlas"))
@@ -1614,6 +1847,26 @@ void EditorImportExport::load_config() {
}
}
+ if (cf->has_section("convert_samples")) {
+
+ if (cf->has_section_key("convert_samples","action")) {
+ String action = cf->get_value("convert_samples","action");
+ if (action=="none") {
+ sample_action=SAMPLE_ACTION_NONE;
+ } else if (action=="compress_ram") {
+ sample_action=SAMPLE_ACTION_COMPRESS_RAM;
+ }
+ }
+
+ if (cf->has_section_key("convert_samples","max_hz"))
+ sample_action_max_hz=cf->get_value("convert_samples","max_hz");
+
+ if (cf->has_section_key("convert_samples","trim"))
+ sample_action_trim=cf->get_value("convert_samples","trim");
+ }
+
+
+
}
@@ -1692,6 +1945,7 @@ void EditorImportExport::save_config() {
case IMAGE_ACTION_NONE: d["action"]="default"; break;
case IMAGE_ACTION_COMPRESS_RAM: d["action"]="compress_ram"; break;
case IMAGE_ACTION_COMPRESS_DISK: d["action"]="compress_disk"; break;
+ case IMAGE_ACTION_KEEP: d["action"]="keep"; break;
}
@@ -1721,8 +1975,18 @@ void EditorImportExport::save_config() {
case SCRIPT_ACTION_ENCRYPT: cf->set_value("script","action","encrypt"); break;
}
+ cf->set_value("convert_scenes","convert_text_scenes",convert_text_scenes);
+
cf->set_value("script","encrypt_key",script_key);
+ switch(sample_action) {
+ case SAMPLE_ACTION_NONE: cf->set_value("convert_samples","action","none"); break;
+ case SAMPLE_ACTION_COMPRESS_RAM: cf->set_value("convert_samples","action","compress_ram"); break;
+ }
+
+ cf->set_value("convert_samples","max_hz",sample_action_max_hz);
+ cf->set_value("convert_samples","trim",sample_action_trim);
+
cf->save("res://export.cfg");
}
@@ -1748,6 +2012,35 @@ String EditorImportExport::script_get_encryption_key() const{
}
+void EditorImportExport::sample_set_action(SampleAction p_action) {
+
+ sample_action=p_action;
+}
+
+EditorImportExport::SampleAction EditorImportExport::sample_get_action() const{
+
+ return sample_action;
+}
+
+void EditorImportExport::sample_set_max_hz(int p_hz){
+
+ sample_action_max_hz=p_hz;
+}
+int EditorImportExport::sample_get_max_hz() const{
+
+ return sample_action_max_hz;
+}
+
+void EditorImportExport::sample_set_trim(bool p_trim){
+
+ sample_action_trim=p_trim;
+}
+bool EditorImportExport::sample_get_trim() const{
+
+ return sample_action_trim;
+}
+
+
void EditorImportExport::_bind_methods() {
ObjectTypeDB::bind_method(_MD("image_export_group_create"),&EditorImportExport::image_export_group_create);
@@ -1775,8 +2068,15 @@ EditorImportExport::EditorImportExport() {
image_formats.insert("png");
image_shrink=1;
+
script_action=SCRIPT_ACTION_COMPILE;
+ sample_action=SAMPLE_ACTION_NONE;
+ sample_action_max_hz=44100;
+ sample_action_trim=false;
+
+ convert_text_scenes=true;
+
}
diff --git a/tools/editor/editor_import_export.h b/tools/editor/editor_import_export.h
index 9704d4a695..1a0686fb50 100644
--- a/tools/editor/editor_import_export.h
+++ b/tools/editor/editor_import_export.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,6 +33,7 @@
#include "scene/main/node.h"
#include "scene/resources/texture.h"
+
class EditorExportPlatform;
class FileAccess;
class EditorProgress;
@@ -83,8 +84,11 @@ public:
typedef Error (*EditorExportSaveFunction)(void *p_userdata,const String& p_path, const Vector<uint8_t>& p_data,int p_file,int p_total);
protected:
+ Vector<uint8_t> get_exported_file_default(String& p_fname) const;
virtual Vector<uint8_t> get_exported_file(String& p_fname) const;
virtual Vector<StringName> get_dependencies(bool p_bundles) const;
+ virtual String find_export_template(String template_file_name, String *err=NULL) const;
+ virtual bool exists_export_template(String template_file_name, String *err=NULL) const;
struct TempData {
@@ -104,7 +108,17 @@ protected:
};
+ struct ZipData {
+
+ void* zip;
+ EditorProgress *ep;
+ int count;
+
+ };
+
+ void gen_export_flags(Vector<String> &r_flags, int p_flags);
static Error save_pack_file(void *p_userdata,const String& p_path, const Vector<uint8_t>& p_data,int p_file,int p_total);
+ static Error save_zip_file(void *p_userdata,const String& p_path, const Vector<uint8_t>& p_data,int p_file,int p_total);
public:
@@ -119,10 +133,19 @@ public:
IMAGE_COMPRESSION_ETC2, // ericsson new compression format (can handle alpha)
};
+ enum ExportFlags {
+ EXPORT_DUMB_CLIENT=1,
+ EXPORT_REMOTE_DEBUG=2,
+ EXPORT_VIEW_COLLISONS=4,
+ EXPORT_VIEW_NAVIGATION=8
+ };
+
Error export_project_files(EditorExportSaveFunction p_func, void* p_udata,bool p_make_bundles);
Error save_pack(FileAccess *p_where, bool p_make_bundles=false, int p_alignment = 1);
+ Error save_zip(const String& p_path, bool p_make_bundles=false);
+
virtual String get_name() const =0;
virtual ImageCompression get_image_compression() const=0;
virtual Ref<Texture> get_logo() const =0;
@@ -131,14 +154,14 @@ public:
virtual int get_device_count() const { return 0; }
virtual String get_device_name(int p_device) const { return ""; }
virtual String get_device_info(int p_device) const { return ""; }
- virtual Error run(int p_device,bool p_dumb=false) { return OK; }
+ virtual Error run(int p_device,int p_flags) { return OK; }
virtual bool can_export(String *r_error=NULL) const=0;
virtual bool requieres_password(bool p_debug) const { return false; }
virtual String get_binary_extension() const=0;
- virtual Error export_project(const String& p_path,bool p_debug,bool p_dumb=false)=0;
+ virtual Error export_project(const String& p_path,bool p_debug,int p_flags=0)=0;
EditorExportPlatform() {};
};
@@ -152,8 +175,7 @@ public:
enum ExportMode {
EXPORT_EXE,
EXPORT_PACK,
- EXPORT_COPY,
- EXPORT_BUNDLES
+ EXPORT_ZIP
};
@@ -175,6 +197,7 @@ private:
Ref<Texture> logo;
ExportMode export_mode;
+ bool bundle;
protected:
bool _set(const StringName& p_name, const Variant& p_value);
@@ -188,7 +211,7 @@ public:
virtual ImageCompression get_image_compression() const { return IMAGE_COMPRESSION_BC; }
virtual String get_binary_extension() const { return binary_extension; }
- virtual Error export_project(const String& p_path,bool p_debug,bool p_dumb=false);
+ virtual Error export_project(const String& p_path, bool p_debug, int p_flags=0);
virtual void set_release_binary32(const String& p_binary) { release_binary32=p_binary; }
virtual void set_debug_binary32(const String& p_binary) { debug_binary32=p_binary; }
virtual void set_release_binary64(const String& p_binary) { release_binary64=p_binary; }
@@ -226,6 +249,8 @@ public:
IMAGE_ACTION_NONE,
IMAGE_ACTION_COMPRESS_DISK,
IMAGE_ACTION_COMPRESS_RAM,
+ IMAGE_ACTION_KEEP //for group
+
};
enum ScriptAction {
@@ -234,6 +259,12 @@ public:
SCRIPT_ACTION_ENCRYPT
};
+ enum SampleAction {
+
+ SAMPLE_ACTION_NONE,
+ SAMPLE_ACTION_COMPRESS_RAM,
+ };
+
protected:
struct ImageGroup {
@@ -241,7 +272,7 @@ protected:
ImageAction action;
bool make_atlas;
float lossy_quality;
- int shrink;
+ float shrink;
};
Vector<Ref<EditorExportPlugin> > export_plugins;
@@ -249,7 +280,7 @@ protected:
Map<String,int> by_idx;
ImageAction image_action;
float image_action_compress_quality;
- int image_shrink;
+ float image_shrink;
Set<String> image_formats;
ExportFilter export_filter;
@@ -263,6 +294,12 @@ protected:
ScriptAction script_action;
String script_key;
+ SampleAction sample_action;
+ int sample_action_max_hz;
+ bool sample_action_trim;
+
+ bool convert_text_scenes;
+
static EditorImportExport* singleton;
static void _bind_methods();
@@ -299,8 +336,8 @@ public:
void set_export_image_action(ImageAction p_action);
ImageAction get_export_image_action() const;
- void set_export_image_shrink(int p_shrink);
- int get_export_image_shrink() const;
+ void set_export_image_shrink(float p_shrink);
+ float get_export_image_shrink() const;
void set_export_image_quality(float p_quality);
float get_export_image_quality() const;
@@ -315,8 +352,8 @@ public:
ImageAction image_export_group_get_image_action(const StringName& p_export_group) const;
void image_export_group_set_make_atlas(const StringName& p_export_group,bool p_make);
bool image_export_group_get_make_atlas(const StringName& p_export_group) const;
- void image_export_group_set_shrink(const StringName& p_export_group,int p_amount);
- int image_export_group_get_shrink(const StringName& p_export_group) const;
+ void image_export_group_set_shrink(const StringName& p_export_group,float p_amount);
+ float image_export_group_get_shrink(const StringName& p_export_group) const;
void image_export_group_set_lossy_quality(const StringName& p_export_group,float p_quality);
float image_export_group_get_lossy_quality(const StringName& p_export_group) const;
@@ -332,6 +369,18 @@ public:
void script_set_encryption_key(const String& p_key);
String script_get_encryption_key() const;
+ void sample_set_action(SampleAction p_action);
+ SampleAction sample_get_action() const;
+
+ void sample_set_max_hz(int p_hz);
+ int sample_get_max_hz() const;
+
+ void sample_set_trim(bool p_trim);
+ bool sample_get_trim() const;
+
+ void set_convert_text_scenes(bool p_convert);
+ bool get_convert_text_scenes() const;
+
void load_config();
void save_config();
diff --git a/tools/editor/editor_log.cpp b/tools/editor/editor_log.cpp
index 8d49655960..bcdafbb06a 100644
--- a/tools/editor/editor_log.cpp
+++ b/tools/editor/editor_log.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -79,8 +79,7 @@ void EditorLog::_notification(int p_what) {
if (p_what==NOTIFICATION_ENTER_TREE) {
log->add_color_override("default_color",get_color("font_color","Tree"));
- tb->set_normal_texture( get_icon("Collapse","EditorIcons"));
- tb->set_hover_texture( get_icon("CollapseHl","EditorIcons"));
+ //button->set_icon(get_icon("Console","EditorIcons"));
}
@@ -97,10 +96,16 @@ void EditorLog::_notification(int p_what) {
}
-void EditorLog::_close_request() {
- _flip_request();
+void EditorLog::_clear_request() {
+
+ log->clear();
+
+}
+
+void EditorLog::clear() {
+ _clear_request();
}
@@ -110,16 +115,17 @@ void EditorLog::add_message(const String& p_msg,bool p_error) {
if (p_error) {
Ref<Texture> icon = get_icon("Error","EditorIcons");
log->add_image( icon );
- button->set_icon(icon);
+ //button->set_icon(icon);
log->push_color(get_color("fg_error","Editor"));
} else {
- button->set_icon(Ref<Texture>());
+ //button->set_icon(Ref<Texture>());
+
}
log->add_newline();
log->add_text(p_msg);
- button->set_text(p_msg);
+// button->set_text(p_msg);
if (p_error)
log->pop();
@@ -143,18 +149,7 @@ void EditorLog::_dragged(const Point2& p_ofs) {
*/
-ToolButton *EditorLog::get_button() {
-
- return button;
-}
-void EditorLog::_flip_request() {
-
- if (is_visible())
- hide();
- else
- show();
-}
void EditorLog::_undo_redo_cbk(void *p_self,const String& p_name) {
@@ -165,18 +160,16 @@ void EditorLog::_undo_redo_cbk(void *p_self,const String& p_name) {
void EditorLog::_bind_methods() {
- ObjectTypeDB::bind_method(_MD("_close_request"),&EditorLog::_close_request );
- ObjectTypeDB::bind_method(_MD("_flip_request"),&EditorLog::_flip_request );
+ ObjectTypeDB::bind_method(_MD("_clear_request"),&EditorLog::_clear_request );
+
//ObjectTypeDB::bind_method(_MD("_dragged"),&EditorLog::_dragged );
- ADD_SIGNAL( MethodInfo("close_request"));
- ADD_SIGNAL( MethodInfo("show_request"));
+ ADD_SIGNAL( MethodInfo("clear_request"));
}
EditorLog::EditorLog() {
- VBoxContainer *vb = memnew( VBoxContainer);
- add_child(vb);
- vb->set_v_size_flags(SIZE_EXPAND_FILL);
+ VBoxContainer *vb = this;
+ add_constant_override("separation",get_constant("separation","VBoxContainer"));
HBoxContainer *hb = memnew( HBoxContainer );
vb->add_child(hb);
@@ -185,27 +178,19 @@ EditorLog::EditorLog() {
title->set_h_size_flags(SIZE_EXPAND_FILL);
hb->add_child(title);
-
- button = memnew( ToolButton );
- button->set_text_align(Button::ALIGN_LEFT);
- button->connect("pressed",this,"_flip_request");
- button->set_focus_mode(FOCUS_NONE);
- button->set_clip_text(true);
- button->set_tooltip("Open/Close output panel.");
-
//pd = memnew( PaneDrag );
//hb->add_child(pd);
//pd->connect("dragged",this,"_dragged");
//pd->set_default_cursor_shape(Control::CURSOR_MOVE);
- tb = memnew( TextureButton );
- hb->add_child(tb);
- tb->connect("pressed",this,"_close_request");
-
+ clearbutton = memnew( Button );
+ hb->add_child(clearbutton);
+ clearbutton->set_text("Clear");
+ clearbutton->connect("pressed", this,"_clear_request");
ec = memnew( Control);
vb->add_child(ec);
- ec->set_custom_minimum_size(Size2(0,100));
+ ec->set_custom_minimum_size(Size2(0,180));
ec->set_v_size_flags(SIZE_EXPAND_FILL);
@@ -219,9 +204,8 @@ EditorLog::EditorLog() {
log->set_selection_enabled(true);
log->set_focus_mode(FOCUS_CLICK);
pc->add_child(log);
- add_message(VERSION_FULL_NAME" (c) 2008-2015 Juan Linietsky, Ariel Manzur.");
+ add_message(VERSION_FULL_NAME" (c) 2008-2016 Juan Linietsky, Ariel Manzur.");
//log->add_text("Initialization Complete.\n"); //because it looks cool.
- add_style_override("panel",get_stylebox("panelf","Panel"));
eh.errfunc=_error_handler;
eh.userdata=this;
@@ -231,7 +215,6 @@ EditorLog::EditorLog() {
EditorNode::get_undo_redo()->set_commit_notify_callback(_undo_redo_cbk,this);
- hide();
}
@@ -241,8 +224,8 @@ void EditorLog::deinit() {
}
+
EditorLog::~EditorLog() {
}
-
diff --git a/tools/editor/editor_log.h b/tools/editor/editor_log.h
index 1141d03911..699be710d8 100644
--- a/tools/editor/editor_log.h
+++ b/tools/editor/editor_log.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -40,14 +40,13 @@
#include "scene/gui/tool_button.h"
#include "pane_drag.h"
#include "os/thread.h"
-class EditorLog : public PanelContainer {
+class EditorLog : public VBoxContainer {
- OBJ_TYPE( EditorLog, PanelContainer );
+ OBJ_TYPE( EditorLog, VBoxContainer );
- ToolButton *button;
+ Button *clearbutton;
Label *title;
RichTextLabel *log;
- TextureButton *tb;
HBoxContainer *title_hb;
// PaneDrag *pd;
Control *ec;
@@ -58,10 +57,8 @@ class EditorLog : public PanelContainer {
Thread::ID current;
-
// void _dragged(const Point2& p_ofs);
- void _close_request();
- void _flip_request();
+ void _clear_request();
static void _undo_redo_cbk(void *p_self,const String& p_name);
protected:
@@ -72,7 +69,8 @@ public:
void add_message(const String& p_msg, bool p_error=false);
void deinit();
- ToolButton *get_button();
+
+ void clear();
EditorLog();
~EditorLog();
};
diff --git a/tools/editor/editor_name_dialog.cpp b/tools/editor/editor_name_dialog.cpp
new file mode 100644
index 0000000000..c221b908e0
--- /dev/null
+++ b/tools/editor/editor_name_dialog.cpp
@@ -0,0 +1,89 @@
+/*************************************************************************/
+/* editor_name_dialog.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
+
+#include "editor_name_dialog.h"
+#include "object_type_db.h"
+#include "os/keyboard.h"
+
+void EditorNameDialog::_line_input_event(const InputEvent& p_event) {
+
+ if (p_event.type == InputEvent::KEY) {
+
+ if (!p_event.key.pressed)
+ return;
+
+ switch (p_event.key.scancode) {
+ case KEY_ENTER:
+ case KEY_RETURN: {
+
+ if (get_hide_on_ok())
+ hide();
+ ok_pressed();
+ accept_event();
+ } break;
+ case KEY_ESCAPE: {
+
+ hide();
+ accept_event();
+ } break;
+ }
+ }
+}
+
+void EditorNameDialog::_post_popup() {
+
+ ConfirmationDialog::_post_popup();
+ name->clear();
+ name->grab_focus();
+}
+
+void EditorNameDialog::ok_pressed() {
+
+ if (name->get_text()!="") {
+ emit_signal("name_confirmed", name->get_text());
+ }
+}
+
+void EditorNameDialog::_bind_methods() {
+
+ ObjectTypeDB::bind_method("_line_input_event",&EditorNameDialog::_line_input_event);
+
+ ADD_SIGNAL(MethodInfo("name_confirmed",PropertyInfo( Variant::STRING,"name")));
+}
+
+EditorNameDialog::EditorNameDialog()
+{
+ name = memnew( LineEdit );
+ add_child(name);
+ move_child(name, get_label()->get_index()+1);
+ name->set_margin(MARGIN_TOP,5);
+ name->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_BEGIN,5);
+ name->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,5);
+ name->connect("input_event", this, "_line_input_event");
+}
diff --git a/tools/editor/editor_name_dialog.h b/tools/editor/editor_name_dialog.h
new file mode 100644
index 0000000000..9e66908899
--- /dev/null
+++ b/tools/editor/editor_name_dialog.h
@@ -0,0 +1,57 @@
+/*************************************************************************/
+/* editor_name_dialog.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
+
+#ifndef EDITOR_NAME_DIALOG_H
+#define EDITOR_NAME_DIALOG_H
+
+#include "scene/gui/dialogs.h"
+#include "scene/gui/line_edit.h"
+
+class EditorNameDialog : public ConfirmationDialog {
+
+ OBJ_TYPE( EditorNameDialog, ConfirmationDialog );
+
+ LineEdit *name;
+
+ void _line_input_event(const InputEvent& p_event);
+
+protected:
+
+ static void _bind_methods();
+ virtual void ok_pressed();
+ virtual void _post_popup();
+
+public:
+
+ LineEdit* get_line_edit() { return name; }
+
+ EditorNameDialog();
+};
+
+#endif // EDITOR_NAME_DIALOG_H
diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp
index a513451b48..3888ed23a6 100644
--- a/tools/editor/editor_node.cpp
+++ b/tools/editor/editor_node.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -55,9 +55,11 @@
#include "bind/core_bind.h"
#include "io/zip_io.h"
#include "io/config_file.h"
+#include "animation_editor.h"
// plugins
#include "plugins/sprite_frames_editor_plugin.h"
+#include "plugins/sprite_region_editor_plugin.h"
#include "plugins/canvas_item_editor_plugin.h"
#include "plugins/spatial_editor_plugin.h"
#include "plugins/sample_editor_plugin.h"
@@ -93,6 +95,7 @@
#include "plugins/light_occluder_2d_editor_plugin.h"
#include "plugins/color_ramp_editor_plugin.h"
#include "plugins/collision_shape_2d_editor_plugin.h"
+#include "main/input_default.h"
// end
#include "tools/editor/io_plugins/editor_texture_import_plugin.h"
#include "tools/editor/io_plugins/editor_scene_import_plugin.h"
@@ -100,22 +103,48 @@
#include "tools/editor/io_plugins/editor_sample_import_plugin.h"
#include "tools/editor/io_plugins/editor_translation_import_plugin.h"
#include "tools/editor/io_plugins/editor_mesh_import_plugin.h"
+#include "tools/editor/io_plugins/editor_export_scene.h"
#include "plugins/editor_preview_plugins.h"
+#include "script_editor_debugger.h"
EditorNode *EditorNode::singleton=NULL;
void EditorNode::_update_scene_tabs() {
+ bool show_rb = EditorSettings::get_singleton()->get("global/show_script_in_scene_tabs");
+
scene_tabs->clear_tabs();
+ Ref<Texture> script_icon = gui_base->get_icon("Script","EditorIcons");
for(int i=0;i<editor_data.get_edited_scene_count();i++) {
+
+ String type=editor_data.get_scene_type(i);
+ Ref<Texture> icon;
+ if (type!=String()) {
+
+ if (!gui_base->has_icon(type,"EditorIcons")) {
+ type="Node";
+ }
+
+ icon=gui_base->get_icon(type,"EditorIcons");
+
+ }
+
+
+
int current = editor_data.get_edited_scene();
bool unsaved = (i==current)?saved_version!=editor_data.get_undo_redo().get_version():editor_data.get_scene_version(i)!=0;
- scene_tabs->add_tab(editor_data.get_scene_title(i)+(unsaved?"(*)":""));
+ scene_tabs->add_tab(editor_data.get_scene_title(i)+(unsaved?"(*)":""),icon);
+
+ if (show_rb && editor_data.get_scene_root_script(i).is_valid()) {
+ scene_tabs->set_tab_right_button(i,script_icon);
+ }
+
}
scene_tabs->set_current_tab(editor_data.get_edited_scene());
+ scene_tabs->ensure_tab_visible(editor_data.get_edited_scene());
}
@@ -139,13 +168,22 @@ void EditorNode::_unhandled_input(const InputEvent& p_event) {
switch(p_event.key.scancode) {
+ /*case KEY_F1:
+ if (!p_event.key.mod.shift && !p_event.key.mod.command)
+ _editor_select(EDITOR_SCRIPT);
+ break;*/
case KEY_F1:
if (!p_event.key.mod.shift && !p_event.key.mod.command)
- _editor_select(3);
+ _editor_select(EDITOR_2D);
+ break;
+ case KEY_F2:
+ if (!p_event.key.mod.shift && !p_event.key.mod.command)
+ _editor_select(EDITOR_3D);
+ break;
+ case KEY_F3:
+ if (!p_event.key.mod.shift && !p_event.key.mod.command)
+ _editor_select(EDITOR_SCRIPT);
break;
- case KEY_F2: _editor_select(0); break;
- case KEY_F3: _editor_select(1); break;
- case KEY_F4: _editor_select(2); break;
case KEY_F5: _menu_option_confirm((p_event.key.mod.control&&p_event.key.mod.shift)?RUN_PLAY_CUSTOM_SCENE:RUN_PLAY,true); break;
case KEY_F6: _menu_option_confirm(RUN_PLAY_SCENE,true); break;
case KEY_F7: _menu_option_confirm(RUN_PAUSE,true); break;
@@ -206,7 +244,7 @@ void EditorNode::_notification(int p_what) {
circle_step=0;
circle_step_msec=tick;
- circle_step_frame=frame+1;
+ circle_step_frame=frame+1;
update_menu->set_icon(gui_base->get_icon("Progress"+itos(circle_step+1),"EditorIcons"));
@@ -263,7 +301,7 @@ void EditorNode::_notification(int p_what) {
VisualServer::get_singleton()->viewport_set_hide_canvas(get_scene_root()->get_viewport(),true);
VisualServer::get_singleton()->viewport_set_disable_environment(get_viewport()->get_viewport_rid(),true);
- _editor_select(1);
+ _editor_select(EDITOR_3D);
if (defer_load_scene!="") {
@@ -379,7 +417,7 @@ void EditorNode::_rebuild_import_menu()
{
PopupMenu* p = import_menu->get_popup();
p->clear();
- p->add_item("Sub-Scene", FILE_IMPORT_SUBSCENE);
+ p->add_item("Node from scene", FILE_IMPORT_SUBSCENE);
p->add_separator();
for (int i = 0; i < editor_import_export->get_import_plugin_count(); i++) {
p->add_item(editor_import_export->get_import_plugin(i)->get_visible_name(), IMPORT_PLUGIN_BASE + i);
@@ -436,19 +474,83 @@ void EditorNode::open_resource(const String& p_type) {
current_option=RESOURCE_LOAD;
}
-void EditorNode::save_resource(const Ref<Resource>& p_resource) {
+void EditorNode::save_resource_in_path(const Ref<Resource>& p_resource,const String& p_path) {
+
+ editor_data.apply_changes_in_editors();
+ int flg=0;
+ if (EditorSettings::get_singleton()->get("on_save/compress_binary_resources"))
+ flg|=ResourceSaver::FLAG_COMPRESS;
+ if (EditorSettings::get_singleton()->get("on_save/save_paths_as_relative"))
+ flg|=ResourceSaver::FLAG_RELATIVE_PATHS;
+
+ String path = Globals::get_singleton()->localize_path(p_path);
+ Error err = ResourceSaver::save(path,p_resource,flg|ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS);
- ERR_FAIL_COND(p_resource.is_null() || p_resource->get_path()=="" || p_resource->get_path().find("::")!=-1);
- resources_dock->save_resource(p_resource->get_path(),p_resource);
+ if (err!=OK) {
+ accept->set_text("Error saving resource!");
+ accept->popup_centered_minsize();
+ return;
+ }
+// EditorFileSystem::get_singleton()->update_file(path,p_resource->get_type());
+
+ ((Resource*)p_resource.ptr())->set_path(path);
+ emit_signal("resource_saved",p_resource);
+
+}
+
+void EditorNode::save_resource(const Ref<Resource>& p_resource) {
+
+ if (p_resource->get_path().is_resource_file()) {
+ save_resource_in_path(p_resource,p_resource->get_path());
+ } else {
+ save_resource_as(p_resource);
+ }
}
void EditorNode::save_resource_as(const Ref<Resource>& p_resource) {
- resources_dock->save_resource_as(p_resource);
+ file->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ bool relpaths = (p_resource->has_meta("__editor_relpaths__") && p_resource->get_meta("__editor_relpaths__").operator bool());
-}
+ current_option=RESOURCE_SAVE_AS;
+ List<String> extensions;
+ Ref<PackedScene> sd = memnew( PackedScene );
+ ResourceSaver::get_recognized_extensions(p_resource,&extensions);
+ file->clear_filters();
+
+ List<String> preferred;
+ for(int i=0;i<extensions.size();i++) {
+
+ if (p_resource->is_type("Script") && (extensions[i]=="tres" || extensions[i]=="res" || extensions[i]=="xml")) {
+ //this serves no purpose and confused people
+ continue;
+ }
+ file->add_filter("*."+extensions[i]+" ; "+extensions[i].to_upper());
+ preferred.push_back(extensions[i]);
+ }
+
+ //file->set_current_path(current_path);
+ if (p_resource->get_path()!="") {
+ file->set_current_path(p_resource->get_path());
+ if (extensions.size()) {
+ String ext=p_resource->get_path().extension().to_lower();
+ if (extensions.find(ext)==NULL) {
+ file->set_current_path(p_resource->get_path().replacen("."+ext,"."+extensions.front()->get()));
+ }
+ }
+ } else if (preferred.size()) {
+
+ String existing;
+ if (extensions.size()) {
+ existing="new_"+p_resource->get_type().to_lower()+"."+preferred.front()->get().to_lower();
+ }
+ file->set_current_path(existing);
+ }
+ file->popup_centered_ratio();
+ file->set_title("Save Resource As..");
+}
void EditorNode::_menu_option(int p_option) {
@@ -492,59 +594,66 @@ void EditorNode::_dialog_display_file_error(String p_file,Error p_error) {
}
-void EditorNode::_get_scene_metadata() {
+void EditorNode::_get_scene_metadata(const String& p_file) {
Node *scene = editor_data.get_edited_scene_root();
if (!scene)
return;
+ String path = EditorSettings::get_singleton()->get_project_settings_path().plus_file(p_file.get_file()+"-editstate-"+p_file.md5_text()+".cfg");
- if (scene->has_meta("__editor_plugin_states__")) {
+ Ref<ConfigFile> cf;
+ cf.instance();
- Dictionary md = scene->get_meta("__editor_plugin_states__");
- editor_data.set_editor_states(md);
+ Error err = cf->load(path);
+ if (err!=OK)
+ return; //must not exist
- }
+ List<String> esl;
+ cf->get_section_keys("editor_states",&esl);
- if (scene->has_meta("__editor_run_settings__")) {
+ Dictionary md;
+ for (List<String>::Element *E=esl.front();E;E=E->next()) {
- Dictionary md = scene->get_meta("__editor_run_settings__");
- if (md.has("run_mode"))
- run_settings_dialog->set_run_mode(md["run_mode"]);
- if (md.has("custom_args"))
- run_settings_dialog->set_custom_arguments(md["custom_args"]);
+ Variant st=cf->get_value("editor_states",E->get());
+ if (st.get_type()) {
+ md[E->get()]=st;
+ }
}
+
+ editor_data.set_editor_states(md);
+
}
-void EditorNode::_set_scene_metadata() {
+void EditorNode::_set_scene_metadata(const String& p_file) {
Node *scene = editor_data.get_edited_scene_root();
if (!scene)
return;
- { /* Editor States */
- Dictionary md = editor_data.get_editor_states();
+ scene->set_meta("__editor_run_settings__",Variant()); //clear it (no point in keeping it)
+ scene->set_meta("__editor_plugin_states__",Variant());
- if (!md.empty()) {
- scene->set_meta("__editor_plugin_states__",md);
- }
- }
+ String path = EditorSettings::get_singleton()->get_project_settings_path().plus_file(p_file.get_file()+"-editstate-"+p_file.md5_text()+".cfg");
- { /* Run Settings */
+ Ref<ConfigFile> cf;
+ cf.instance();
+ Dictionary md = editor_data.get_editor_states();
+ List<Variant> keys;
+ md.get_key_list(&keys);
- Dictionary md;
- md["run_mode"]=run_settings_dialog->get_run_mode();
- md["custom_args"]=run_settings_dialog->get_custom_arguments();
- scene->set_meta("__editor_run_settings__",md);
- }
-
+ for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
+ cf->set_value("editor_states",E->get(),md[E->get()]);
+ }
+ Error err = cf->save(path);
+ ERR_FAIL_COND(err!=OK);
}
@@ -796,7 +905,7 @@ void EditorNode::_save_scene_with_preview(String p_file) {
}
}
- _editor_select(is2d?0:1);
+ _editor_select(is2d?EDITOR_2D:EDITOR_3D);
VS::get_singleton()->viewport_queue_screen_capture(viewport);
save.step("Creating Thumbnail",2);
@@ -862,8 +971,24 @@ void EditorNode::_save_scene(String p_file) {
}
- _set_scene_metadata();
- Ref<PackedScene> sdata = memnew( PackedScene );
+ _set_scene_metadata(p_file);
+
+
+ Ref<PackedScene> sdata;
+
+ if (ResourceCache::has(p_file)) {
+ // something may be referencing this resource and we are good with that.
+ // we must update it, but also let the previous scene state go, as
+ // old version still work for referencing changes in instanced or inherited scenes
+
+ sdata = Ref<PackedScene>( ResourceCache::get(p_file)->cast_to<PackedScene>() );
+ if (sdata.is_valid())
+ sdata->recreate_state();
+ else
+ sdata.instance();
+ } else {
+ sdata.instance();
+ }
Error err = sdata->pack(scene);
@@ -895,6 +1020,7 @@ void EditorNode::_save_scene(String p_file) {
//EditorFileSystem::get_singleton()->update_file(p_file,sdata->get_type());
set_current_version(editor_data.get_undo_redo().get_version());
_update_title();
+ _update_scene_tabs();
} else {
_dialog_display_file_error(p_file,err);
@@ -1026,6 +1152,11 @@ void EditorNode::_dialog_action(String p_file) {
push_item(res.operator->() );
+ } break;
+ case FILE_NEW_INHERITED_SCENE: {
+
+
+ load_scene(p_file,false,true);
} break;
case FILE_OPEN_SCENE: {
@@ -1064,75 +1195,6 @@ void EditorNode::_dialog_action(String p_file) {
save_translatable_strings(p_file);
} break;
- case FILE_SAVE_SUBSCENE: {
-
- List<Node*> selection = editor_selection->get_selected_node_list();
-
- if (selection.size()!=1) {
-
- current_option=-1;
- //confirmation->get_cancel()->hide();
- accept->get_ok()->set_text("I see..");
- accept->set_text("This operation requieres a single selected node.");
- accept->popup_centered_minsize();
- break;
- }
-
- Node *base = selection.front()->get();
-
- Map<Node*,Node*> reown;
- reown[editor_data.get_edited_scene_root()]=base;
- Node *copy = base->duplicate_and_reown(reown);
- if (copy) {
-
- Ref<PackedScene> sdata = memnew( PackedScene );
- Error err = sdata->pack(copy);
- memdelete(copy);
-
- if (err!=OK) {
-
-
- current_option=-1;
- //accept->get_cancel()->hide();
- accept->get_ok()->set_text("I see..");
- accept->set_text("Couldn't save subscene. Likely dependencies (instances) couldn't be satisfied.");
- accept->popup_centered_minsize();
- return;
- }
-
- int flg=0;
- if (EditorSettings::get_singleton()->get("on_save/compress_binary_resources"))
- flg|=ResourceSaver::FLAG_COMPRESS;
- if (EditorSettings::get_singleton()->get("on_save/save_paths_as_relative"))
- flg|=ResourceSaver::FLAG_RELATIVE_PATHS;
-
-
- err = ResourceSaver::save(p_file,sdata,flg);
- if (err!=OK) {
-
- current_option=-1;
- //confirmation->get_cancel()->hide();
- accept->get_ok()->set_text("I see..");
- accept->set_text("Error saving scene.");
- accept->popup_centered_minsize();
- break;
- }
- //EditorFileSystem::get_singleton()->update_file(p_file,sdata->get_type());
-
- } else {
-
- current_option=-1;
- //confirmation->get_cancel()->hide();
- accept->get_ok()->set_text("I see..");
- accept->set_text("Error duplicating scene to save it.");
- accept->popup_centered_minsize();
- break;
-
- }
-
-
- } break;
-
case FILE_SAVE_SCENE:
case FILE_SAVE_AS_SCENE: {
@@ -1192,10 +1254,18 @@ void EditorNode::_dialog_action(String p_file) {
case FILE_EXPORT_TILESET: {
Ref<TileSet> ml;
- if (file_export_lib_merge->is_pressed() && FileAccess::exists(p_file)) {
+ if (FileAccess::exists(p_file)) {
ml=ResourceLoader::load(p_file,"TileSet");
- if (ml.is_null()) {
+ if (!file_export_lib_merge->is_pressed()) {
+ ml->clear();
+ }
+
+ }
+
+ if (ml.is_null()) {
+
+ if (file_export_lib_merge->is_pressed()) {
current_option=-1;
//accept->get_cancel()->hide();
accept->get_ok()->set_text("I see..");
@@ -1204,9 +1274,6 @@ void EditorNode::_dialog_action(String p_file) {
return;
}
- }
-
- if (ml.is_null()) {
ml = Ref<TileSet>( memnew( TileSet ));
}
@@ -1297,10 +1364,81 @@ void EditorNode::_dialog_action(String p_file) {
unzClose(pkg);
} break;
+ case RESOURCE_SAVE:
+ case RESOURCE_SAVE_AS: {
+
+
+ uint32_t current = editor_history.get_current();
+ Object *current_obj = current>0 ? ObjectDB::get_instance(current) : NULL;
+
+ ERR_FAIL_COND(!current_obj->cast_to<Resource>())
+
+ RES current_res = RES(current_obj->cast_to<Resource>());
+
+ save_resource_in_path(current_res,p_file);
+
+ } break;
+ case SETTINGS_LAYOUT_SAVE: {
+
+ if (p_file.empty())
+ return;
+
+ Ref<ConfigFile> config;
+ config.instance();
+ Error err = config->load(EditorSettings::get_singleton()->get_settings_path().plus_file("editor_layouts.cfg"));
+
+ if (err==ERR_CANT_OPEN) {
+ config.instance(); // new config
+ } else if (err!=OK) {
+ show_warning("Error trying to save layout!");
+ return;
+ }
+
+ _save_docks_to_config(config, p_file);
+
+ config->save(EditorSettings::get_singleton()->get_settings_path().plus_file("editor_layouts.cfg"));
+
+ layout_dialog->hide();
+ _update_layouts_menu();
+
+ if (p_file=="Default") {
+ show_warning("Default editor layout overridden.");
+ }
+
+ } break;
+ case SETTINGS_LAYOUT_DELETE: {
+
+ if (p_file.empty())
+ return;
+
+ Ref<ConfigFile> config;
+ config.instance();
+ Error err = config->load(EditorSettings::get_singleton()->get_settings_path().plus_file("editor_layouts.cfg"));
+
+ if (err!=OK || !config->has_section(p_file)) {
+ show_warning("Layout name not found!");
+ return;
+ }
+
+ // erase
+ List<String> keys;
+ config->get_section_keys(p_file, &keys);
+ for (List<String>::Element *E=keys.front();E;E=E->next()) {
+ config->set_value(p_file, E->get(), Variant());
+ }
+
+ config->save(EditorSettings::get_singleton()->get_settings_path().plus_file("editor_layouts.cfg"));
+ layout_dialog->hide();
+ _update_layouts_menu();
+
+ if (p_file=="Default") {
+ show_warning("Restored Default layout to base settings.");
+ }
+
+ } break;
default: { //save scene?
-
if (file->get_mode()==FileDialog::MODE_SAVE_FILE) {
//_save_scene(p_file);
@@ -1335,6 +1473,67 @@ void EditorNode::push_item(Object *p_object,const String& p_property) {
}
+void EditorNode::_select_history(int p_idx) {
+
+ //push it to the top, it is not correct, but it's more useful
+ ObjectID id=editor_history.get_history_obj(p_idx);
+ Object* obj=ObjectDB::get_instance(id);
+ if (!obj)
+ return;
+ push_item(obj);
+}
+
+void EditorNode::_prepare_history() {
+
+ int history_to = MAX(0,editor_history.get_history_len()-25);
+
+ editor_history_menu->get_popup()->clear();
+
+ Ref<Texture> base_icon = gui_base->get_icon("Object","EditorIcons");
+ Set<ObjectID> already;
+ for(int i=editor_history.get_history_len()-1;i>=history_to;i--) {
+
+
+ ObjectID id=editor_history.get_history_obj(i);
+ Object* obj=ObjectDB::get_instance(id);
+ if (!obj || already.has(id)) {
+ if (history_to>0) {
+ history_to--;
+ }
+ continue;
+ }
+
+ already.insert(id);
+
+ Ref<Texture> icon = gui_base->get_icon("Object","EditorIcons");
+ if (gui_base->has_icon(obj->get_type(),"EditorIcons"))
+ icon=gui_base->get_icon(obj->get_type(),"EditorIcons");
+ else
+ icon=base_icon;
+
+ String text;
+ if (obj->cast_to<Resource>()) {
+ Resource *r=obj->cast_to<Resource>();
+ if (r->get_path().is_resource_file())
+ text=r->get_path().get_file();
+ else if (r->get_name()!=String()) {
+ text=r->get_name();
+ } else {
+ text=r->get_type();
+ }
+ } else if (obj->cast_to<Node>()) {
+ text=obj->cast_to<Node>()->get_name();
+ } else {
+ text=obj->get_type();
+ }
+
+ if (i==editor_history.get_history_pos()) {
+ text="["+text+"]";
+ }
+ editor_history_menu->get_popup()->add_icon_item(icon,text,i);
+ }
+}
+
void EditorNode::_property_editor_forward() {
if (editor_history.next())
@@ -1379,6 +1578,9 @@ void EditorNode::_edit_current() {
uint32_t current = editor_history.get_current();
Object *current_obj = current>0 ? ObjectDB::get_instance(current) : NULL;
+ property_back->set_disabled( editor_history.is_at_begining() );
+ property_forward->set_disabled( editor_history.is_at_end() );
+
this->current=current_obj;
editor_path->update_path();
@@ -1388,12 +1590,19 @@ void EditorNode::_edit_current() {
scene_tree_dock->set_selected(NULL);
property_editor->edit( NULL );
object_menu->set_disabled(true);
+
+ if (editor_plugin_over)
+ editor_plugin_over->make_visible(false);
+
return;
}
object_menu->set_disabled(true);
- if (current_obj->is_type("Resource")) {
+ bool is_resource = current_obj->is_type("Resource");
+ resource_save_button->set_disabled(!is_resource);
+
+ if (is_resource) {
Resource *current_res = current_obj->cast_to<Resource>();
@@ -1402,12 +1611,11 @@ void EditorNode::_edit_current() {
property_editor->edit( current_res );
object_menu->set_disabled(false);
- resources_dock->add_resource(Ref<Resource>(current_res));
- //top_pallete->set_current_tab(1);
- }
+ //resources_dock->add_resource(Ref<Resource>(current_res));
- if (current_obj->is_type("Node")) {
+ //top_pallete->set_current_tab(1);
+ } else if (current_obj->is_type("Node")) {
Node * current_node = current_obj->cast_to<Node>();
ERR_FAIL_COND(!current_node);
@@ -1422,6 +1630,12 @@ void EditorNode::_edit_current() {
//top_pallete->set_current_tab(0);
+ } else {
+
+ property_editor->edit( current_obj );
+ //scene_tree_dock->set_selected(current_node);
+ //object_menu->get_popup()->clear();
+
}
/* Take care of PLUGIN EDITOR */
@@ -1446,10 +1660,8 @@ void EditorNode::_edit_current() {
for(int i=0;i<editor_table.size();i++) {
- if (editor_table[i]==main_plugin) {
- main_editor_tabs->set_current_tab(i);
- break;
- }
+
+ main_editor_buttons[i]->set_pressed(editor_table[i]==main_plugin);
}
}
@@ -1494,7 +1706,13 @@ void EditorNode::_edit_current() {
p->add_item("Copy Params",OBJECT_COPY_PARAMS);
p->add_item("Set Params",OBJECT_PASTE_PARAMS);
p->add_separator();
- p->add_item("Make Resources Unique",OBJECT_UNIQUE_RESOURCES);
+ p->add_item("Paste Resource",RESOURCE_PASTE);
+ if (is_resource) {
+ p->add_item("Copy Resource",RESOURCE_COPY);
+ p->add_item("Make Built-In",RESOURCE_UNREF);
+ }
+ p->add_separator();
+ p->add_item("Make Sub-Resources Unique",OBJECT_UNIQUE_RESOURCES);
p->add_separator();
p->add_icon_item(gui_base->get_icon("Help","EditorIcons"),"Class Reference",OBJECT_REQUEST_HELP);
List<MethodInfo> methods;
@@ -1524,7 +1742,21 @@ void EditorNode::_edit_current() {
//p->add_item("All Methods",OBJECT_CALL_METHOD);
- _update_keying();
+ update_keying();
+}
+
+void EditorNode::_resource_created() {
+
+ Object *c = create_dialog->instance_selected();
+
+ ERR_FAIL_COND(!c);
+ Resource *r = c->cast_to<Resource>();
+ ERR_FAIL_COND(!r);
+
+ REF res( r );
+
+ push_item(c);
+
}
void EditorNode::_resource_selected(const RES& p_res,const String& p_property) {
@@ -1549,8 +1781,10 @@ void EditorNode::_run(bool p_current,const String& p_custom) {
}
play_button->set_pressed(false);
+ play_button->set_icon(gui_base->get_icon("MainPlay","EditorIcons"));
//pause_button->set_pressed(false);
play_scene_button->set_pressed(false);
+ play_scene_button->set_icon(gui_base->get_icon("PlayScene","EditorIcons"));
String current_filename;
String run_filename;
@@ -1564,7 +1798,6 @@ void EditorNode::_run(bool p_current,const String& p_custom) {
Node *scene = editor_data.get_edited_scene_root();
if (!scene) {
-
current_option=-1;
//accept->get_cancel()->hide();
accept->get_ok()->set_text("I see..");
@@ -1645,6 +1878,10 @@ void EditorNode::_run(bool p_current,const String& p_custom) {
editor_data.save_editor_external_data();
}
+ if (bool(EDITOR_DEF("run/always_clear_output_on_play", true))) {
+ log->clear();
+ }
+
List<String> breakpoints;
editor_data.get_editor_breakpoints(&breakpoints);
@@ -1665,8 +1902,10 @@ void EditorNode::_run(bool p_current,const String& p_custom) {
emit_signal("play_pressed");
if (p_current) {
play_scene_button->set_pressed(true);
+ play_scene_button->set_icon(gui_base->get_icon("Reload","EditorIcons"));
} else {
play_button->set_pressed(true);
+ play_button->set_icon(gui_base->get_icon("Reload","EditorIcons"));
}
_playing_edited=p_current;
@@ -1736,11 +1975,13 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
int idx = editor_data.add_edited_scene(-1);
_scene_tab_changed(idx);
+ editor_data.clear_editor_states();
//_cleanup_scene();
} break;
+ case FILE_NEW_INHERITED_SCENE:
case FILE_OPEN_SCENE: {
@@ -1761,23 +2002,30 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
if (scene) {
file->set_current_path(scene->get_filename());
};
- file->set_title("Open Scene");
+ file->set_title(p_option==FILE_OPEN_SCENE?"Open Scene":"Open Base Scene");
file->popup_centered_ratio();
} break;
case FILE_QUICK_OPEN_SCENE: {
- quick_open->popup("PackedScene");
+ quick_open->popup("PackedScene", true);
quick_open->set_title("Quick Open Scene..");
} break;
case FILE_QUICK_OPEN_SCRIPT: {
- quick_open->popup("Script");
+ quick_open->popup("Script", true);
quick_open->set_title("Quick Open Script..");
} break;
+ case FILE_QUICK_OPEN_FILE: {
+
+
+ quick_open->popup("Resource", false, true);
+ quick_open->set_title("Quick Search File..");
+
+ } break;
case FILE_RUN_SCRIPT: {
file_script->popup_centered_ratio();
@@ -1792,7 +2040,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
} break;
case FILE_CLOSE: {
- if (!p_confirmed) {
+ if (!p_confirmed && unsaved_cache) {
confirmation->get_ok()->set_text("Yes");
//confirmation->get_cancel()->show();
confirmation->set_text("Close scene? (Unsaved changes will be lost)");
@@ -1805,6 +2053,11 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
} break;
+ case SCENE_TAB_CLOSE: {
+ _remove_scene(tab_closing);
+ _update_scene_tabs();
+ current_option = -1;
+ } break;
case FILE_SAVE_SCENE: {
@@ -1920,70 +2173,6 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
file->set_title("Save Translatable Strings");
file->popup_centered_ratio();
-
- } break;
-
- case FILE_SAVE_SUBSCENE: {
-
- Node *scene = editor_data.get_edited_scene_root();
-
- if (!scene) {
-
- current_option=-1;
- //confirmation->get_cancel()->hide();
- accept->get_ok()->set_text("I see..");
- accept->set_text("This operation can't be done without a scene.");
- accept->popup_centered_minsize();
- break;
- }
-
-
- List<Node*> selection = editor_selection->get_selected_node_list();
-
- if (selection.size()!=1) {
-
- current_option=-1;
- //confirmation->get_cancel()->hide();
- accept->get_ok()->set_text("I see..");
- accept->set_text("This operation requieres a single selected node.");
- accept->popup_centered_minsize();
- break;
- }
-
- Node *tocopy = selection.front()->get();
-
- if (tocopy!=editor_data.get_edited_scene_root() && tocopy->get_filename()!="") {
-
-
- current_option=-1;
- //confirmation->get_cancel()->hide();
- accept->get_ok()->set_text("I see..");
- accept->set_text("This operation can't be done on instanced scenes.");
- accept->popup_centered_minsize();
- break;
- }
-
- file->set_mode(EditorFileDialog::MODE_SAVE_FILE);
-
- List<String> extensions;
- Ref<PackedScene> sd = memnew( PackedScene );
- ResourceSaver::get_recognized_extensions(sd,&extensions);
- file->clear_filters();
- for(int i=0;i<extensions.size();i++) {
-
- file->add_filter("*."+extensions[i]+" ; "+extensions[i].to_upper());
- }
-
-
- String existing;
- if (extensions.size()) {
- existing="new_scene."+extensions.front()->get().to_lower();
- }
- file->set_current_path(existing);
-
-
- file->popup_centered_ratio();
- file->set_title("Save Sub-Scene As..");
} break;
case FILE_SAVE_OPTIMIZED: {
Node *scene = editor_data.get_edited_scene_root();
@@ -2167,6 +2356,10 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
log->add_message("REDO: "+action);
} break;
+ case TOOLS_ORPHAN_RESOURCES: {
+
+ orphan_resources->show();
+ } break;
case EDIT_REVERT: {
@@ -2240,11 +2433,74 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
} break;
#endif
-
+ case RESOURCE_NEW: {
+
+ create_dialog->popup_centered_ratio();
+ } break;
+ case RESOURCE_LOAD: {
+
+ open_resource();
+ } break;
+ case RESOURCE_SAVE: {
+
+
+ uint32_t current = editor_history.get_current();
+ Object *current_obj = current>0 ? ObjectDB::get_instance(current) : NULL;
+
+ ERR_FAIL_COND(!current_obj->cast_to<Resource>())
+
+ RES current_res = RES(current_obj->cast_to<Resource>());
+
+ save_resource(current_res);
+
+ } break;
+ case RESOURCE_SAVE_AS: {
+
+ uint32_t current = editor_history.get_current();
+ Object *current_obj = current>0 ? ObjectDB::get_instance(current) : NULL;
+
+ ERR_FAIL_COND(!current_obj->cast_to<Resource>())
+
+ RES current_res = RES(current_obj->cast_to<Resource>());
+
+ save_resource_as(current_res);
+
+ } break;
+ case RESOURCE_UNREF: {
+
+ uint32_t current = editor_history.get_current();
+ Object *current_obj = current>0 ? ObjectDB::get_instance(current) : NULL;
+
+ ERR_FAIL_COND(!current_obj->cast_to<Resource>())
+
+ RES current_res = RES(current_obj->cast_to<Resource>());
+ current_res->set_path("");
+ _edit_current();
+ } break;
+ case RESOURCE_COPY: {
+
+ uint32_t current = editor_history.get_current();
+ Object *current_obj = current>0 ? ObjectDB::get_instance(current) : NULL;
+
+ ERR_FAIL_COND(!current_obj->cast_to<Resource>())
+
+ RES current_res = RES(current_obj->cast_to<Resource>());
+
+ EditorSettings::get_singleton()->set_resource_clipboard(current_res);
+
+ } break;
+ case RESOURCE_PASTE: {
+
+ RES r = EditorSettings::get_singleton()->get_resource_clipboard();
+ if (r.is_valid()) {
+ push_item(EditorSettings::get_singleton()->get_resource_clipboard().ptr(),String());
+ }
+
+ } break;
case OBJECT_REQUEST_HELP: {
if (current) {
- _editor_select(3);
+ _editor_select(EDITOR_SCRIPT);
emit_signal("request_help",current->get_type());
}
@@ -2311,12 +2567,12 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
call_dialog->popup_centered_ratio();
} break;
case RUN_PLAY: {
-
+ _menu_option_confirm(RUN_STOP,true);
_run(false);
} break;
case RUN_PLAY_CUSTOM_SCENE: {
-
+ _menu_option_confirm(RUN_STOP,true);
quick_run->popup("PackedScene",true);
quick_run->set_title("Quick Run Scene..");
@@ -2333,16 +2589,25 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
editor_run.stop();
play_button->set_pressed(false);
+ play_button->set_icon(gui_base->get_icon("MainPlay","EditorIcons"));
play_scene_button->set_pressed(false);
+ play_scene_button->set_icon(gui_base->get_icon("PlayScene","EditorIcons"));
//pause_button->set_pressed(false);
emit_signal("stop_pressed");
} break;
case RUN_PLAY_SCENE: {
-
+ _menu_option_confirm(RUN_STOP,true);
_run(true);
} break;
+ case RUN_PLAY_NATIVE: {
+ _menu_option_confirm(RUN_STOP,true);
+ emit_signal("play_pressed");
+ editor_run.run_native_notify();
+
+
+ } break;
case RUN_SCENE_SETTINGS: {
run_settings_dialog->popup_run_settings();
@@ -2374,28 +2639,57 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
case RUN_FILE_SERVER: {
//file_server
- bool ischecked = fileserver_menu->get_popup()->is_item_checked( fileserver_menu->get_popup()->get_item_index(RUN_FILE_SERVER));
+ bool ischecked = debug_button->get_popup()->is_item_checked( debug_button->get_popup()->get_item_index(RUN_FILE_SERVER));
if (ischecked) {
file_server->stop();
- fileserver_menu->set_icon(gui_base->get_icon("FileServer","EditorIcons"));
- fileserver_menu->get_popup()->set_item_text( fileserver_menu->get_popup()->get_item_index(RUN_FILE_SERVER),"Enable File Server");
+ //debug_button->set_icon(gui_base->get_icon("FileServer","EditorIcons"));
+ //debug_button->get_popup()->set_item_text( debug_button->get_popup()->get_item_index(RUN_FILE_SERVER),"Enable File Server");
} else {
file_server->start();
- fileserver_menu->set_icon(gui_base->get_icon("FileServerActive","EditorIcons"));
- fileserver_menu->get_popup()->set_item_text( fileserver_menu->get_popup()->get_item_index(RUN_FILE_SERVER),"Disable File Server");
+ //debug_button->set_icon(gui_base->get_icon("FileServerActive","EditorIcons"));
+ //debug_button->get_popup()->set_item_text( debug_button->get_popup()->get_item_index(RUN_FILE_SERVER),"Disable File Server");
}
- fileserver_menu->get_popup()->set_item_checked( fileserver_menu->get_popup()->get_item_index(RUN_FILE_SERVER),!ischecked);
+ debug_button->get_popup()->set_item_checked( debug_button->get_popup()->get_item_index(RUN_FILE_SERVER),!ischecked);
} break;
+ case RUN_LIVE_DEBUG: {
+
+ bool ischecked = debug_button->get_popup()->is_item_checked( debug_button->get_popup()->get_item_index(RUN_LIVE_DEBUG));
+
+ debug_button->get_popup()->set_item_checked( debug_button->get_popup()->get_item_index(RUN_LIVE_DEBUG),!ischecked);
+ ScriptEditor::get_singleton()->get_debugger()->set_live_debugging(!ischecked);
+ } break;
+
case RUN_DEPLOY_DUMB_CLIENTS: {
- bool ischecked = fileserver_menu->get_popup()->is_item_checked( fileserver_menu->get_popup()->get_item_index(RUN_DEPLOY_DUMB_CLIENTS));
- fileserver_menu->get_popup()->set_item_checked( fileserver_menu->get_popup()->get_item_index(RUN_DEPLOY_DUMB_CLIENTS),!ischecked);
+ bool ischecked = debug_button->get_popup()->is_item_checked( debug_button->get_popup()->get_item_index(RUN_DEPLOY_DUMB_CLIENTS));
+ debug_button->get_popup()->set_item_checked( debug_button->get_popup()->get_item_index(RUN_DEPLOY_DUMB_CLIENTS),!ischecked);
run_native->set_deploy_dumb(!ischecked);
} break;
+ case RUN_DEPLOY_REMOTE_DEBUG: {
+
+ bool ischecked = debug_button->get_popup()->is_item_checked( debug_button->get_popup()->get_item_index(RUN_DEPLOY_REMOTE_DEBUG));
+ debug_button->get_popup()->set_item_checked( debug_button->get_popup()->get_item_index(RUN_DEPLOY_REMOTE_DEBUG),!ischecked);
+ run_native->set_deploy_debug_remote(!ischecked);
+
+ } break;
+ case RUN_DEBUG_COLLISONS: {
+
+ bool ischecked = debug_button->get_popup()->is_item_checked( debug_button->get_popup()->get_item_index(RUN_DEBUG_COLLISONS));
+ debug_button->get_popup()->set_item_checked( debug_button->get_popup()->get_item_index(RUN_DEBUG_COLLISONS),!ischecked);
+ run_native->set_debug_collisions(!ischecked);
+ editor_run.set_debug_collisions(!ischecked);
+ } break;
+ case RUN_DEBUG_NAVIGATION: {
+
+ bool ischecked = debug_button->get_popup()->is_item_checked( debug_button->get_popup()->get_item_index(RUN_DEBUG_NAVIGATION));
+ debug_button->get_popup()->set_item_checked( debug_button->get_popup()->get_item_index(RUN_DEBUG_NAVIGATION),!ischecked);
+ run_native->set_debug_navigation(!ischecked);
+ editor_run.set_debug_navigation(!ischecked);
+ } break;
case SETTINGS_UPDATE_ALWAYS: {
update_menu->get_popup()->set_item_checked(0,true);
@@ -2420,11 +2714,6 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
//optimized_presets->popup_centered_ratio();
} break;
- case SETTINGS_SHOW_ANIMATION: {
-
- animation_panel_make_visible( ! animation_panel->is_visible() );
-
- } break;
case SETTINGS_LOAD_EXPORT_TEMPLATES: {
@@ -2544,7 +2833,7 @@ Control* EditorNode::get_viewport() {
void EditorNode::_editor_select(int p_which) {
static bool selecting=false;
- if (selecting)
+ if (selecting || changing_scene)
return;
selecting=true;
@@ -2552,7 +2841,9 @@ void EditorNode::_editor_select(int p_which) {
ERR_FAIL_INDEX(p_which,editor_table.size());
- main_editor_tabs->set_current_tab(p_which);
+ for(int i=0;i<main_editor_buttons.size();i++) {
+ main_editor_buttons[i]->set_pressed(i==p_which);
+ }
selecting=false;
@@ -2570,6 +2861,8 @@ void EditorNode::_editor_select(int p_which) {
editor_plugin_screen=new_editor;
editor_plugin_screen->make_visible(true);
editor_plugin_screen->selected_notify();
+
+
}
void EditorNode::add_editor_plugin(EditorPlugin *p_editor) {
@@ -2577,7 +2870,12 @@ void EditorNode::add_editor_plugin(EditorPlugin *p_editor) {
if (p_editor->has_main_screen()) {
- singleton->main_editor_tabs->add_tab(p_editor->get_name());
+ ToolButton *tb = memnew( ToolButton );
+ tb->set_toggle_mode(true);
+ tb->connect("pressed",singleton,"_editor_select",varray(singleton->main_editor_buttons.size()));
+ tb->set_text(p_editor->get_name());
+ singleton->main_editor_buttons.push_back(tb);
+ singleton->main_editor_button_vb->add_child(tb);
singleton->editor_table.push_back(p_editor);
}
singleton->editor_data.add_editor_plugin( p_editor );
@@ -2589,16 +2887,18 @@ void EditorNode::remove_editor_plugin(EditorPlugin *p_editor) {
if (p_editor->has_main_screen()) {
- for(int i=0;i<singleton->main_editor_tabs->get_tab_count();i++) {
+ for(int i=0;i<singleton->main_editor_buttons.size();i++) {
+
+ if (p_editor->get_name()==singleton->main_editor_buttons[i]->get_name()) {
- if (p_editor->get_name()==singleton->main_editor_tabs->get_tab_title(i)) {
+ memdelete( singleton->main_editor_buttons[i] );
+ singleton->main_editor_buttons.remove(i);
- singleton->main_editor_tabs->remove_tab(i);
break;
}
}
- singleton->main_editor_tabs->add_tab(p_editor->get_name());
+ //singleton->main_editor_tabs->add_tab(p_editor->get_name());
singleton->editor_table.erase(p_editor);
}
singleton->remove_child(p_editor);
@@ -2638,18 +2938,32 @@ void EditorNode::_remove_edited_scene() {
_update_title();
_update_scene_tabs();
- if (editor_data.get_edited_scene_count()==1) {
- //make new scene appear saved
- set_current_version(editor_data.get_undo_redo().get_version());
- unsaved_cache=false;
+// if (editor_data.get_edited_scene_count()==1) {
+// //make new scene appear saved
+// set_current_version(editor_data.get_undo_redo().get_version());
+// unsaved_cache=false;
+// }
+}
+
+void EditorNode::_remove_scene(int index) {
+// printf("Attempting to remove scene %d (current is %d)\n", index, editor_data.get_edited_scene());
+
+ if (editor_data.get_edited_scene() == index) {
+ //Scene to remove is current scene
+ _remove_edited_scene();
+ }
+ else {
+ // Scene to remove is not active scene
+ editor_data.remove_scene(index);
}
}
+
void EditorNode::set_edited_scene(Node *p_scene) {
if (get_editor_data().get_edited_scene_root()) {
if (get_editor_data().get_edited_scene_root()->get_parent()==scene_root)
scene_root->remove_child(get_editor_data().get_edited_scene_root());
- animation_editor->set_root(NULL);
+
}
get_editor_data().set_edited_scene_root(p_scene);
@@ -2662,7 +2976,7 @@ void EditorNode::set_edited_scene(Node *p_scene) {
if (p_scene) {
if (p_scene->get_parent()!=scene_root)
scene_root->add_child(p_scene);
- animation_editor->set_root(p_scene);
+
}
}
@@ -2718,7 +3032,7 @@ Error EditorNode::save_translatable_strings(const String& p_to_file) {
OS::Time time = OS::get_singleton()->get_time();
f->store_line("# Translation Strings Dump.");
f->store_line("# Created By.");
- f->store_line("# \t"VERSION_FULL_NAME" (c) 2008-2015 Juan Linietsky, Ariel Manzur.");
+ f->store_line("# \t" VERSION_FULL_NAME " (c) 2008-2016 Juan Linietsky, Ariel Manzur.");
f->store_line("# From Scene: ");
f->store_line("# \t"+get_edited_scene()->get_filename());
f->store_line("");
@@ -2893,10 +3207,20 @@ Error EditorNode::save_optimized_copy(const String& p_scene,const String& p_pres
}
+int EditorNode::_get_current_main_editor() {
+
+ for(int i=0;i<editor_table.size();i++) {
+ if (editor_table[i]==editor_plugin_screen)
+ return i;
+ }
+
+ return 0;
+}
+
Dictionary EditorNode::_get_main_scene_state() {
Dictionary state;
- state["main_tab"]=main_editor_tabs->get_current_tab();
+ state["main_tab"]=_get_current_main_editor();
state["scene_tree_offset"]=scene_tree_dock->get_tree_editor()->get_scene_tree()->get_vscroll_bar()->get_val();
state["property_edit_offset"]=get_property_editor()->get_scene_tree()->get_vscroll_bar()->get_val();
state["saved_version"]=saved_version;
@@ -2907,9 +3231,14 @@ Dictionary EditorNode::_get_main_scene_state() {
void EditorNode::_set_main_scene_state(Dictionary p_state) {
//print_line("set current 7 ");
+ changing_scene=false;
+#if 0
if (p_state.has("main_tab")) {
int idx = p_state["main_tab"];
+
+
+ print_line("comes with tab: "+itos(idx));
int current=-1;
for(int i=0;i<editor_table.size();i++) {
if (editor_plugin_screen==editor_table[i]) {
@@ -2918,12 +3247,41 @@ void EditorNode::_set_main_scene_state(Dictionary p_state) {
}
}
+
if (idx<2 && current<2) {
//only set tab for 2D and 3D
- _editor_select(p_state["main_tab"]);
+ _editor_select(idx);
//print_line(" setting main tab: "+itos(p_state["main_tab"]));
}
}
+#else
+
+ if (get_edited_scene()) {
+
+ int current=-1;
+ for(int i=0;i<editor_table.size();i++) {
+ if (editor_plugin_screen==editor_table[i]) {
+ current=i;
+ break;
+ }
+ }
+
+ if (current<2) {
+ //use heuristic instead
+
+ int n2d=0,n3d=0;
+ _find_node_types(get_edited_scene(),n2d,n3d);
+ if (n2d>n3d) {
+ _editor_select(EDITOR_2D);
+ } else if (n3d>n2d) {
+ _editor_select(EDITOR_3D);
+
+ }
+ }
+
+ }
+#endif
+
if (p_state.has("scene_tree_offset"))
scene_tree_dock->get_tree_editor()->get_scene_tree()->get_vscroll_bar()->set_val(p_state["scene_tree_offset"]);
@@ -2932,6 +3290,14 @@ void EditorNode::_set_main_scene_state(Dictionary p_state) {
//print_line("set current 8 ");
+ //this should only happen at the very end
+
+ //changing_scene=true; //avoid script change from opening editor
+ ScriptEditor::get_singleton()->get_debugger()->update_live_edit_root();
+ ScriptEditor::get_singleton()->set_scene_root_script( editor_data.get_scene_root_script(editor_data.get_edited_scene()) );
+ editor_data.notify_edited_scene_changed();
+
+ //changing_scene=false;
}
@@ -2944,15 +3310,25 @@ void EditorNode::set_current_version(uint64_t p_version) {
bool EditorNode::is_changing_scene() const {
return changing_scene;
}
+
+void EditorNode::_clear_undo_history() {
+
+ get_undo_redo()->clear_history();
+}
+
void EditorNode::set_current_scene(int p_idx) {
+ if (editor_data.check_and_update_scene(p_idx)) {
+ call_deferred("_clear_undo_history");
+ }
+
changing_scene=true;
editor_data.save_edited_scene_state(editor_selection,&editor_history,_get_main_scene_state());
if (get_editor_data().get_edited_scene_root()) {
if (get_editor_data().get_edited_scene_root()->get_parent()==scene_root)
scene_root->remove_child(get_editor_data().get_edited_scene_root());
- animation_editor->set_root(NULL);
+
}
//print_line("set current 2 ");
@@ -2974,7 +3350,7 @@ void EditorNode::set_current_scene(int p_idx) {
if (new_scene) {
if (new_scene->get_parent()!=scene_root)
scene_root->add_child(new_scene);
- animation_editor->set_root(new_scene);
+
}
//print_line("set current 4 ");
@@ -2996,12 +3372,25 @@ void EditorNode::set_current_scene(int p_idx) {
call_deferred("_set_main_scene_state",state); //do after everything else is done setting up
//print_line("set current 6 ");
- changing_scene=false;
}
-Error EditorNode::load_scene(const String& p_scene) {
+bool EditorNode::is_scene_open(const String& p_path) {
+
+ for(int i=0;i<editor_data.get_edited_scene_count();i++) {
+ if (editor_data.get_scene_path(i)==p_path)
+ return true;
+ }
+
+ return false;
+}
+
+void EditorNode::fix_dependencies(const String& p_for_file) {
+ dependency_fixer->edit(p_for_file);
+}
+
+Error EditorNode::load_scene(const String& p_scene, bool p_ignore_broken_deps,bool p_set_inherited) {
if (!is_inside_tree()) {
defer_load_scene = p_scene;
@@ -3009,11 +3398,13 @@ Error EditorNode::load_scene(const String& p_scene) {
}
- for(int i=0;i<editor_data.get_edited_scene_count();i++) {
+ if(!p_set_inherited) {
+ for(int i=0;i<editor_data.get_edited_scene_count();i++) {
- if (editor_data.get_scene_path(i)==p_scene) {
- _scene_tab_changed(i);
- return OK;
+ if (editor_data.get_scene_path(i)==p_scene) {
+ _scene_tab_changed(i);
+ return OK;
+ }
}
}
@@ -3047,7 +3438,9 @@ Error EditorNode::load_scene(const String& p_scene) {
//_cleanup_scene(); // i'm sorry but this MUST happen to avoid modified resources to not be reloaded.
- Ref<PackedScene> sdata = ResourceLoader::load(lpath);
+ dependency_errors.clear();
+
+ Ref<PackedScene> sdata = ResourceLoader::load(lpath,"",true);
if (!sdata.is_valid()) {
current_option=-1;
@@ -3064,6 +3457,48 @@ Error EditorNode::load_scene(const String& p_scene) {
return ERR_FILE_NOT_FOUND;
}
+ if (!p_ignore_broken_deps && dependency_errors.has(lpath)) {
+
+ current_option=-1;
+ Vector<String> errors;
+ for(Set<String>::Element *E=dependency_errors[lpath].front();E;E=E->next()) {
+
+ errors.push_back(E->get());
+ }
+ dependency_error->show(lpath,errors);
+ opening_prev=false;
+
+ if (prev!=-1) {
+ set_current_scene(prev);
+ editor_data.remove_scene(idx);
+ }
+ return ERR_FILE_MISSING_DEPENDENCIES;
+ }
+
+ dependency_errors.erase(lpath); //at least not self path
+
+ for (Map<String,Set<String> >::Element *E=dependency_errors.front();E;E=E->next()) {
+
+ String txt="Scene '"+E->key()+"' has broken dependencies:\n";
+ for(Set<String>::Element *F=E->get().front();F;F=F->next()) {
+ txt+="\t"+F->get()+"\n";
+ }
+ add_io_error(txt);
+ }
+
+ if (ResourceCache::has(lpath)) {
+ //used from somewhere else? no problem! update state and replace sdata
+ Ref<PackedScene> ps = Ref<PackedScene>( ResourceCache::get(lpath)->cast_to<PackedScene>() );
+ if (ps.is_valid()) {
+ ps->replace_state( sdata->get_state() );
+ ps->set_last_modified_time( sdata->get_last_modified_time() );
+ sdata=ps;
+ }
+
+ } else {
+ sdata->set_path(lpath,true); //take over path
+ }
+
Node*new_scene=sdata->instance(true);
if (!new_scene) {
@@ -3098,8 +3533,19 @@ Error EditorNode::load_scene(const String& p_scene) {
}
*/
+ if (p_set_inherited) {
+ Ref<SceneState> state = sdata->get_state();
+ state->set_path(lpath);
+ new_scene->set_scene_inherited_state(state);
+ new_scene->set_filename(String());
+ //if (new_scene->get_scene_instance_state().is_valid())
+ // new_scene->get_scene_instance_state()->set_path(String());
+ }
+
+ new_scene->set_scene_instance_state(Ref<SceneState>());
+
set_edited_scene(new_scene);
- _get_scene_metadata();
+ _get_scene_metadata(p_scene);
/*
editor_data.set_edited_scene_root(new_scene);
@@ -3132,6 +3578,8 @@ Error EditorNode::load_scene(const String& p_scene) {
prev_scene->set_disabled(previous_scenes.size()==0);
opening_prev=false;
+ ScriptEditor::get_singleton()->get_debugger()->update_live_edit_root();
+
//top_pallete->set_current_tab(0); //always go to scene
push_item(new_scene);
@@ -3168,7 +3616,7 @@ void EditorNode::_instance_request(const String& p_path){
void EditorNode::_property_keyed(const String& p_keyed,const Variant& p_value,bool p_advance) {
- animation_editor->insert_value_key(p_keyed,p_value,p_advance);
+ AnimationPlayerEditor::singleton->get_key_editor()->insert_value_key(p_keyed,p_value,p_advance);
}
void EditorNode::_transform_keyed(Object *sp,const String& p_sub,const Transform& p_key) {
@@ -3176,16 +3624,16 @@ void EditorNode::_transform_keyed(Object *sp,const String& p_sub,const Transform
Spatial *s=sp->cast_to<Spatial>();
if (!s)
return;
- animation_editor->insert_transform_key(s,p_sub,p_key);
+ AnimationPlayerEditor::singleton->get_key_editor()->insert_transform_key(s,p_sub,p_key);
}
-void EditorNode::_update_keying() {
+void EditorNode::update_keying() {
//print_line("KR: "+itos(p_enabled));
bool valid=false;
- if (animation_editor->has_keying()) {
+ if (AnimationPlayerEditor::singleton->get_key_editor()->has_keying()) {
if (editor_history.get_path_size()>=1) {
@@ -3219,6 +3667,7 @@ void EditorNode::_show_messages() {
}
+#if 0
void EditorNode::animation_panel_make_visible(bool p_visible) {
if (!p_visible) {
@@ -3231,6 +3680,7 @@ void EditorNode::animation_panel_make_visible(bool p_visible) {
settings_menu->get_popup()->set_item_checked(idx,p_visible);
}
+
void EditorNode::animation_editor_make_visible(bool p_visible) {
if (p_visible) {
@@ -3252,10 +3702,9 @@ void EditorNode::animation_editor_make_visible(bool p_visible) {
}
animation_editor->set_keying(p_visible);
- _update_keying();
}
-
+#endif
void EditorNode::_add_to_recent_scenes(const String& p_scene) {
String base="_"+Globals::get_singleton()->get_resource_path().replace("\\","::").replace("/","::");
@@ -3348,21 +3797,26 @@ void EditorNode::_update_recent_scenes() {
}
-void EditorNode::hide_animation_player_editors() {
+void EditorNode::_quick_opened() {
- emit_signal("hide_animation_player_editors");
-}
+ if (current_option==FILE_QUICK_OPEN_FILE) {
+ String res_path = quick_open->get_selected();
-void EditorNode::_quick_opened(const String& p_resource) {
+ scenes_dock->open(res_path);
+ return;
+ }
- print_line("quick_opened");
- if (quick_open->get_base_type()=="PackedScene") {
+ Vector<String> files = quick_open->get_selected_files();
- open_request(p_resource);
- } else {
- load_resource(p_resource);
- }
+ for (int i = 0; i < files.size(); i++) {
+ String res_path = files[i];
+ if (quick_open->get_base_type()=="PackedScene") {
+ open_request(res_path);
+ } else {
+ load_resource(res_path);
+ }
+ }
}
void EditorNode::_quick_run(const String& p_resource) {
@@ -3373,9 +3827,7 @@ void EditorNode::_quick_run(const String& p_resource) {
void EditorNode::notify_child_process_exited() {
- play_button->set_pressed(false);
- play_scene_button->set_pressed(false);
- //pause_button->set_pressed(false);
+ _menu_option_confirm(RUN_STOP,false);
stop_button->set_pressed(false);
editor_run.stop();
@@ -3410,7 +3862,8 @@ bool EditorNode::_find_editing_changed_scene(Node *p_from) {
void EditorNode::add_io_error(const String& p_error) {
-
+ CharString err_ut = p_error.utf8();
+ ERR_PRINT(err_ut.get_data());
_load_error_notify(singleton,p_error);
}
@@ -3483,9 +3936,9 @@ void EditorNode::progress_add_task(const String& p_task,const String& p_label, i
singleton->progress_dialog->add_task(p_task,p_label,p_steps);
}
-void EditorNode::progress_task_step(const String& p_task, const String& p_state, int p_step) {
+void EditorNode::progress_task_step(const String& p_task, const String& p_state, int p_step,bool p_force_redraw) {
- singleton->progress_dialog->task_step(p_task,p_state,p_step);
+ singleton->progress_dialog->task_step(p_task,p_state,p_step,p_force_redraw);
}
@@ -3514,79 +3967,6 @@ void EditorNode::progress_end_task_bg(const String& p_task) {
}
-void EditorNode::_bind_methods() {
-
-
- ObjectTypeDB::bind_method("_menu_option",&EditorNode::_menu_option);
- ObjectTypeDB::bind_method("_menu_confirm_current",&EditorNode::_menu_confirm_current);
- ObjectTypeDB::bind_method("_dialog_action",&EditorNode::_dialog_action);
- ObjectTypeDB::bind_method("_resource_selected",&EditorNode::_resource_selected,DEFVAL(""));
- ObjectTypeDB::bind_method("_property_editor_forward",&EditorNode::_property_editor_forward);
- ObjectTypeDB::bind_method("_property_editor_back",&EditorNode::_property_editor_back);
- ObjectTypeDB::bind_method("_editor_select",&EditorNode::_editor_select);
- ObjectTypeDB::bind_method("_node_renamed",&EditorNode::_node_renamed);
- ObjectTypeDB::bind_method("edit_node",&EditorNode::edit_node);
- ObjectTypeDB::bind_method("_imported",&EditorNode::_imported);
- ObjectTypeDB::bind_method("_unhandled_input",&EditorNode::_unhandled_input);
-
- ObjectTypeDB::bind_method("_get_scene_metadata",&EditorNode::_get_scene_metadata);
- ObjectTypeDB::bind_method("set_edited_scene",&EditorNode::set_edited_scene);
- ObjectTypeDB::bind_method("open_request",&EditorNode::open_request);
- ObjectTypeDB::bind_method("_instance_request",&EditorNode::_instance_request);
- ObjectTypeDB::bind_method("_update_keying",&EditorNode::_update_keying);
- ObjectTypeDB::bind_method("_property_keyed",&EditorNode::_property_keyed);
- ObjectTypeDB::bind_method("_transform_keyed",&EditorNode::_transform_keyed);
- ObjectTypeDB::bind_method("_close_messages",&EditorNode::_close_messages);
- ObjectTypeDB::bind_method("_show_messages",&EditorNode::_show_messages);
- ObjectTypeDB::bind_method("_vp_resized",&EditorNode::_vp_resized);
- ObjectTypeDB::bind_method("_quick_opened",&EditorNode::_quick_opened);
- ObjectTypeDB::bind_method("_quick_run",&EditorNode::_quick_run);
-
- ObjectTypeDB::bind_method("_import_action",&EditorNode::_import_action);
- //ObjectTypeDB::bind_method("_import",&EditorNode::_import);
-// ObjectTypeDB::bind_method("_import_conflicts_solved",&EditorNode::_import_conflicts_solved);
- ObjectTypeDB::bind_method("_open_recent_scene",&EditorNode::_open_recent_scene);
-// ObjectTypeDB::bind_method("_open_recent_scene_confirm",&EditorNode::_open_recent_scene_confirm);
-
- ObjectTypeDB::bind_method("_save_optimized",&EditorNode::_save_optimized);
- ObjectTypeDB::bind_method(_MD("animation_panel_make_visible","enable"),&EditorNode::animation_panel_make_visible);
-
- ObjectTypeDB::bind_method("stop_child_process",&EditorNode::stop_child_process);
-
- ObjectTypeDB::bind_method("_sources_changed",&EditorNode::_sources_changed);
- ObjectTypeDB::bind_method("_fs_changed",&EditorNode::_fs_changed);
- ObjectTypeDB::bind_method("_dock_select_draw",&EditorNode::_dock_select_draw);
- ObjectTypeDB::bind_method("_dock_select_input",&EditorNode::_dock_select_input);
- ObjectTypeDB::bind_method("_dock_pre_popup",&EditorNode::_dock_pre_popup);
- ObjectTypeDB::bind_method("_dock_split_dragged",&EditorNode::_dock_split_dragged);
- ObjectTypeDB::bind_method("_save_docks",&EditorNode::_save_docks);
- ObjectTypeDB::bind_method("_dock_popup_exit",&EditorNode::_dock_popup_exit);
- ObjectTypeDB::bind_method("_dock_move_left",&EditorNode::_dock_move_left);
- ObjectTypeDB::bind_method("_dock_move_right",&EditorNode::_dock_move_right);
-
- ObjectTypeDB::bind_method("set_current_scene",&EditorNode::set_current_scene);
- ObjectTypeDB::bind_method("set_current_version",&EditorNode::set_current_version);
- ObjectTypeDB::bind_method("_scene_tab_changed",&EditorNode::_scene_tab_changed);
- ObjectTypeDB::bind_method("_set_main_scene_state",&EditorNode::_set_main_scene_state);
- ObjectTypeDB::bind_method("_update_scene_tabs",&EditorNode::_update_scene_tabs);
-
-
-
- ObjectTypeDB::bind_method(_MD("add_editor_import_plugin", "plugin"), &EditorNode::add_editor_import_plugin);
- ObjectTypeDB::bind_method(_MD("remove_editor_import_plugin", "plugin"), &EditorNode::remove_editor_import_plugin);
- ObjectTypeDB::bind_method(_MD("get_gui_base"), &EditorNode::get_gui_base);
-
- ADD_SIGNAL( MethodInfo("play_pressed") );
- ADD_SIGNAL( MethodInfo("pause_pressed") );
- ADD_SIGNAL( MethodInfo("stop_pressed") );
- ADD_SIGNAL( MethodInfo("hide_animation_player_editors") );
- ADD_SIGNAL( MethodInfo("request_help") );
- ADD_SIGNAL( MethodInfo("script_add_function_request",PropertyInfo(Variant::OBJECT,"obj"),PropertyInfo(Variant::STRING,"function"),PropertyInfo(Variant::STRING_ARRAY,"args")) );
- ADD_SIGNAL( MethodInfo("resource_saved",PropertyInfo(Variant::OBJECT,"obj")) );
-
-
-
-}
Ref<Texture> EditorNode::_file_dialog_get_icon(const String& p_path) {
@@ -3852,6 +4232,15 @@ void EditorNode::_save_docks() {
Ref<ConfigFile> config;
config.instance();
+ _save_docks_to_config(config, "docks");
+ editor_data.get_plugin_window_layout(config);
+
+ config->save(EditorSettings::get_singleton()->get_project_settings_path().plus_file("editor_layout.cfg"));
+
+}
+
+void EditorNode::_save_docks_to_config(Ref<ConfigFile> p_layout, const String& p_section) {
+
for(int i=0;i<DOCK_SLOT_MAX;i++) {
String names;
for(int j=0;j<dock_slot[i]->get_tab_count();j++) {
@@ -3862,7 +4251,7 @@ void EditorNode::_save_docks() {
}
if (names!="") {
- config->set_value("docks","dock_"+itos(i+1),names);
+ p_layout->set_value(p_section,"dock_"+itos(i+1),names);
}
}
@@ -3876,7 +4265,7 @@ void EditorNode::_save_docks() {
for(int i=0;i<DOCK_SLOT_MAX/2;i++) {
if (splits[i]->is_visible()) {
- config->set_value("docks","dock_split_"+itos(i+1),splits[i]->get_split_offset());
+ p_layout->set_value(p_section,"dock_split_"+itos(i+1),splits[i]->get_split_offset());
}
}
@@ -3890,13 +4279,9 @@ void EditorNode::_save_docks() {
for(int i=0;i<4;i++) {
- config->set_value("docks","dock_hsplit_"+itos(i+1),h_splits[i]->get_split_offset());
+ p_layout->set_value(p_section,"dock_hsplit_"+itos(i+1),h_splits[i]->get_split_offset());
}
- editor_data.get_plugin_window_layout(config);
-
- config->save(EditorSettings::get_singleton()->get_project_settings_path().plus_file("editor_layout.cfg"));
-
}
void EditorNode::save_layout() {
@@ -3915,15 +4300,26 @@ void EditorNode::_load_docks() {
config.instance();
Error err = config->load(EditorSettings::get_singleton()->get_project_settings_path().plus_file("editor_layout.cfg"));
if (err!=OK) {
- return; //no config
+ //no config
+ if (overridden_default_layout>=0) {
+ _layout_menu_option(overridden_default_layout);
+ }
+ return;
}
+ _load_docks_from_config(config, "docks");
+ editor_data.set_plugin_window_layout(config);
+
+}
+
+void EditorNode::_load_docks_from_config(Ref<ConfigFile> p_layout, const String& p_section) {
+
for(int i=0;i<DOCK_SLOT_MAX;i++) {
- if (!config->has_section_key("docks","dock_"+itos(i+1)))
+ if (!p_layout->has_section_key(p_section,"dock_"+itos(i+1)))
continue;
- Vector<String> names = String(config->get_value("docks","dock_"+itos(i+1))).split(",");
+ Vector<String> names = String(p_layout->get_value(p_section,"dock_"+itos(i+1))).split(",");
for(int j=0;j<names.size();j++) {
@@ -3943,7 +4339,7 @@ void EditorNode::_load_docks() {
if (atidx==-1) //well, it's not anywhere
continue;
- if (atidx==j) {
+ if (atidx==i) {
node->raise();
continue;
}
@@ -3958,7 +4354,6 @@ void EditorNode::_load_docks() {
dock_slot[i]->add_child(node);
dock_slot[i]->show();
}
-
}
VSplitContainer*splits[DOCK_SLOT_MAX/2]={
@@ -3970,14 +4365,14 @@ void EditorNode::_load_docks() {
for(int i=0;i<DOCK_SLOT_MAX/2;i++) {
- if (!config->has_section_key("docks","dock_split_"+itos(i+1)))
+ if (!p_layout->has_section_key(p_section,"dock_split_"+itos(i+1)))
continue;
- int ofs = config->get_value("docks","dock_split_"+itos(i+1));
+ int ofs = p_layout->get_value(p_section,"dock_split_"+itos(i+1));
splits[i]->set_split_offset(ofs);
}
- HSplitContainer *h_splits[4]={
+ HSplitContainer*h_splits[4]={
left_l_hsplit,
left_r_hsplit,
main_hsplit,
@@ -3985,9 +4380,9 @@ void EditorNode::_load_docks() {
};
for(int i=0;i<4;i++) {
- if (!config->has_section_key("docks","dock_hsplit_"+itos(i+1)))
+ if (!p_layout->has_section_key(p_section,"dock_hsplit_"+itos(i+1)))
continue;
- int ofs = config->get_value("docks","dock_hsplit_"+itos(i+1));
+ int ofs = p_layout->get_value(p_section,"dock_hsplit_"+itos(i+1));
h_splits[i]->set_split_offset(ofs);
}
@@ -4005,8 +4400,104 @@ void EditorNode::_load_docks() {
dock_slot[i]->set_current_tab(0);
}
}
+}
- editor_data.set_plugin_window_layout(config);
+
+void EditorNode::_update_layouts_menu() {
+
+ editor_layouts->clear();
+ overridden_default_layout=-1;
+
+ editor_layouts->set_size(Vector2());
+ editor_layouts->add_item("Save Layout", SETTINGS_LAYOUT_SAVE);
+ editor_layouts->add_item("Delete Layout", SETTINGS_LAYOUT_DELETE);
+ editor_layouts->add_separator();
+ editor_layouts->add_item("Default", SETTINGS_LAYOUT_DEFAULT);
+
+ Ref<ConfigFile> config;
+ config.instance();
+ Error err = config->load(EditorSettings::get_singleton()->get_settings_path().plus_file("editor_layouts.cfg"));
+ if (err!=OK) {
+ return; //no config
+ }
+
+ List<String> layouts;
+ config.ptr()->get_sections(&layouts);
+
+ for (List<String>::Element *E=layouts.front();E;E=E->next()) {
+
+ String layout=E->get();
+
+ if (layout=="Default") {
+ editor_layouts->remove_item(editor_layouts->get_item_index(SETTINGS_LAYOUT_DEFAULT));
+ overridden_default_layout=editor_layouts->get_item_count();
+ }
+
+ editor_layouts->add_item(layout);
+ }
+
+}
+
+void EditorNode::_layout_menu_option(int p_id) {
+
+ switch (p_id) {
+
+ case SETTINGS_LAYOUT_SAVE: {
+
+ current_option=p_id;
+ layout_dialog->set_title("Save Layout");
+ layout_dialog->get_ok()->set_text("Save");
+ layout_dialog->popup_centered();
+ } break;
+ case SETTINGS_LAYOUT_DELETE: {
+
+ current_option=p_id;
+ layout_dialog->set_title("Delete Layout");
+ layout_dialog->get_ok()->set_text("Delete");
+ layout_dialog->popup_centered();
+ } break;
+ case SETTINGS_LAYOUT_DEFAULT: {
+
+ _load_docks_from_config(default_layout, "docks");
+ _save_docks();
+ } break;
+ default: {
+
+ Ref<ConfigFile> config;
+ config.instance();
+ Error err = config->load(EditorSettings::get_singleton()->get_settings_path().plus_file("editor_layouts.cfg"));
+ if (err!=OK) {
+ return; //no config
+ }
+
+ _load_docks_from_config(config, editor_layouts->get_item_text(p_id));
+ _save_docks();
+ }
+ }
+
+}
+
+
+void EditorNode::_scene_tab_script_edited(int p_tab) {
+
+ Ref<Script> script = editor_data.get_scene_root_script(p_tab);
+ if (script.is_valid())
+ edit_resource(script);
+}
+
+void EditorNode::_scene_tab_closed(int p_tab) {
+ current_option = SCENE_TAB_CLOSE;
+ tab_closing = p_tab;
+ if (unsaved_cache) {
+ confirmation->get_ok()->set_text("Yes");
+ //confirmation->get_cancel()->show();
+ confirmation->set_text("Close scene? (Unsaved changes will be lost)");
+ confirmation->popup_centered_minsize();
+ }
+ else {
+ _remove_scene(p_tab);
+ //_update_scene_tabs();
+ }
}
@@ -4030,19 +4521,225 @@ void EditorNode::_scene_tab_changed(int p_tab) {
editor_data.get_undo_redo().add_do_method(this,"set_current_version",unsaved?saved_version:0);
editor_data.get_undo_redo().add_do_method(this,"set_current_scene",p_tab);
editor_data.get_undo_redo().add_do_method(scene_tabs,"set_current_tab",p_tab);
+ editor_data.get_undo_redo().add_do_method(scene_tabs,"ensure_tab_visible",p_tab);
editor_data.get_undo_redo().add_do_method(this,"set_current_version",next_scene_version==0?editor_data.get_undo_redo().get_version()+1:next_scene_version);
editor_data.get_undo_redo().add_undo_method(this,"set_current_version",next_scene_version);
editor_data.get_undo_redo().add_undo_method(this,"set_current_scene",editor_data.get_edited_scene());
editor_data.get_undo_redo().add_undo_method(scene_tabs,"set_current_tab",editor_data.get_edited_scene());
+ editor_data.get_undo_redo().add_undo_method(scene_tabs,"ensure_tab_visible",p_tab,editor_data.get_edited_scene());
editor_data.get_undo_redo().add_undo_method(this,"set_current_version",saved_version);
editor_data.get_undo_redo().commit_action();
}
+void EditorNode::_toggle_search_bar(bool p_pressed) {
+
+ property_editor->set_use_filter(p_pressed);
+
+ if (p_pressed) {
+
+ search_bar->show();
+ search_box->grab_focus();
+ search_box->select_all();
+ } else {
+
+ search_bar->hide();
+ }
+}
+
+void EditorNode::_clear_search_box() {
+
+ if (search_box->get_text()=="")
+ return;
+
+ search_box->clear();
+ property_editor->update_tree();
+}
+
+ToolButton *EditorNode::add_bottom_panel_item(String p_text,Control *p_item) {
+
+ ToolButton *tb = memnew( ToolButton );
+ tb->connect("toggled",this,"_bottom_panel_switch",varray(bottom_panel_items.size()));
+ tb->set_text(p_text);
+ tb->set_toggle_mode(true);
+ tb->set_focus_mode(Control::FOCUS_NONE);
+ bottom_panel_vb->add_child(p_item);
+ bottom_panel_hb->raise();
+ bottom_panel_hb->add_child(tb);
+ p_item->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ p_item->hide();
+ BottomPanelItem bpi;
+ bpi.button=tb;
+ bpi.control=p_item;
+ bpi.name=p_text;
+ bottom_panel_items.push_back(bpi);
+
+ return tb;
+
+}
+
+void EditorNode::hide_bottom_panel() {
+
+ _bottom_panel_switch(false,0);
+
+}
+
+void EditorNode::make_bottom_panel_item_visible(Control *p_item) {
+
+ for(int i=0;i<bottom_panel_items.size();i++) {
+
+ if (bottom_panel_items[i].control==p_item) {
+ _bottom_panel_switch(true,i);
+ break;
+ }
+ }
+}
+
+void EditorNode::raise_bottom_panel_item(Control *p_item) {
+
+ for(int i=0;i<bottom_panel_items.size();i++) {
+
+ if (bottom_panel_items[i].control==p_item) {
+ bottom_panel_items[i].button->raise();
+ SWAP( bottom_panel_items[i], bottom_panel_items[bottom_panel_items.size()-1]);
+ break;
+ }
+ }
+
+ for(int i=0;i<bottom_panel_items.size();i++) {
+ bottom_panel_items[i].button->disconnect("toggled",this,"_bottom_panel_switch");
+ bottom_panel_items[i].button->connect("toggled",this,"_bottom_panel_switch",varray(i));
+ }
+
+}
+
+void EditorNode::_bottom_panel_switch(bool p_enable,int p_idx) {
+
+ ERR_FAIL_INDEX(p_idx,bottom_panel_items.size());
+
+
+
+ if (p_enable) {
+ for(int i=0;i<bottom_panel_items.size();i++) {
+
+ bottom_panel_items[i].button->set_pressed(i==p_idx);
+ bottom_panel_items[i].control->set_hidden(i!=p_idx);
+ }
+ center_split->set_dragger_visibility(SplitContainer::DRAGGER_VISIBLE);
+ center_split->set_collapsed(false);
+ } else {
+ for(int i=0;i<bottom_panel_items.size();i++) {
+
+ bottom_panel_items[i].button->set_pressed(false);
+ bottom_panel_items[i].control->set_hidden(true);
+ }
+ center_split->set_dragger_visibility(SplitContainer::DRAGGER_HIDDEN);
+ center_split->set_collapsed(true);
+ }
+}
+
+void EditorNode::_bind_methods() {
+
+
+ ObjectTypeDB::bind_method("_menu_option",&EditorNode::_menu_option);
+ ObjectTypeDB::bind_method("_menu_confirm_current",&EditorNode::_menu_confirm_current);
+ ObjectTypeDB::bind_method("_dialog_action",&EditorNode::_dialog_action);
+ ObjectTypeDB::bind_method("_resource_selected",&EditorNode::_resource_selected,DEFVAL(""));
+ ObjectTypeDB::bind_method("_property_editor_forward",&EditorNode::_property_editor_forward);
+ ObjectTypeDB::bind_method("_property_editor_back",&EditorNode::_property_editor_back);
+ ObjectTypeDB::bind_method("_editor_select",&EditorNode::_editor_select);
+ ObjectTypeDB::bind_method("_node_renamed",&EditorNode::_node_renamed);
+ ObjectTypeDB::bind_method("edit_node",&EditorNode::edit_node);
+ ObjectTypeDB::bind_method("_imported",&EditorNode::_imported);
+ ObjectTypeDB::bind_method("_unhandled_input",&EditorNode::_unhandled_input);
+
+ ObjectTypeDB::bind_method("_get_scene_metadata",&EditorNode::_get_scene_metadata);
+ ObjectTypeDB::bind_method("set_edited_scene",&EditorNode::set_edited_scene);
+ ObjectTypeDB::bind_method("open_request",&EditorNode::open_request);
+ ObjectTypeDB::bind_method("_instance_request",&EditorNode::_instance_request);
+ ObjectTypeDB::bind_method("update_keying",&EditorNode::update_keying);
+ ObjectTypeDB::bind_method("_property_keyed",&EditorNode::_property_keyed);
+ ObjectTypeDB::bind_method("_transform_keyed",&EditorNode::_transform_keyed);
+ ObjectTypeDB::bind_method("_close_messages",&EditorNode::_close_messages);
+ ObjectTypeDB::bind_method("_show_messages",&EditorNode::_show_messages);
+ ObjectTypeDB::bind_method("_vp_resized",&EditorNode::_vp_resized);
+ ObjectTypeDB::bind_method("_quick_opened",&EditorNode::_quick_opened);
+ ObjectTypeDB::bind_method("_quick_run",&EditorNode::_quick_run);
+
+ ObjectTypeDB::bind_method("_resource_created",&EditorNode::_resource_created);
+
+ ObjectTypeDB::bind_method("_import_action",&EditorNode::_import_action);
+ //ObjectTypeDB::bind_method("_import",&EditorNode::_import);
+// ObjectTypeDB::bind_method("_import_conflicts_solved",&EditorNode::_import_conflicts_solved);
+ ObjectTypeDB::bind_method("_open_recent_scene",&EditorNode::_open_recent_scene);
+// ObjectTypeDB::bind_method("_open_recent_scene_confirm",&EditorNode::_open_recent_scene_confirm);
+
+ ObjectTypeDB::bind_method("_save_optimized",&EditorNode::_save_optimized);
+
+ ObjectTypeDB::bind_method("stop_child_process",&EditorNode::stop_child_process);
+
+ ObjectTypeDB::bind_method("_sources_changed",&EditorNode::_sources_changed);
+ ObjectTypeDB::bind_method("_fs_changed",&EditorNode::_fs_changed);
+ ObjectTypeDB::bind_method("_dock_select_draw",&EditorNode::_dock_select_draw);
+ ObjectTypeDB::bind_method("_dock_select_input",&EditorNode::_dock_select_input);
+ ObjectTypeDB::bind_method("_dock_pre_popup",&EditorNode::_dock_pre_popup);
+ ObjectTypeDB::bind_method("_dock_split_dragged",&EditorNode::_dock_split_dragged);
+ ObjectTypeDB::bind_method("_save_docks",&EditorNode::_save_docks);
+ ObjectTypeDB::bind_method("_dock_popup_exit",&EditorNode::_dock_popup_exit);
+ ObjectTypeDB::bind_method("_dock_move_left",&EditorNode::_dock_move_left);
+ ObjectTypeDB::bind_method("_dock_move_right",&EditorNode::_dock_move_right);
+
+ ObjectTypeDB::bind_method("_layout_menu_option",&EditorNode::_layout_menu_option);
+
+ ObjectTypeDB::bind_method("set_current_scene",&EditorNode::set_current_scene);
+ ObjectTypeDB::bind_method("set_current_version",&EditorNode::set_current_version);
+ ObjectTypeDB::bind_method("_scene_tab_changed",&EditorNode::_scene_tab_changed);
+ ObjectTypeDB::bind_method("_scene_tab_closed",&EditorNode::_scene_tab_closed);
+ ObjectTypeDB::bind_method("_scene_tab_script_edited",&EditorNode::_scene_tab_script_edited);
+ ObjectTypeDB::bind_method("_set_main_scene_state",&EditorNode::_set_main_scene_state);
+ ObjectTypeDB::bind_method("_update_scene_tabs",&EditorNode::_update_scene_tabs);
+
+ ObjectTypeDB::bind_method("_prepare_history",&EditorNode::_prepare_history);
+ ObjectTypeDB::bind_method("_select_history",&EditorNode::_select_history);
+
+ ObjectTypeDB::bind_method("_toggle_search_bar",&EditorNode::_toggle_search_bar);
+ ObjectTypeDB::bind_method("_clear_search_box",&EditorNode::_clear_search_box);
+ ObjectTypeDB::bind_method("_clear_undo_history",&EditorNode::_clear_undo_history);
+
+ ObjectTypeDB::bind_method(_MD("add_editor_import_plugin", "plugin"), &EditorNode::add_editor_import_plugin);
+ ObjectTypeDB::bind_method(_MD("remove_editor_import_plugin", "plugin"), &EditorNode::remove_editor_import_plugin);
+ ObjectTypeDB::bind_method(_MD("get_gui_base"), &EditorNode::get_gui_base);
+ ObjectTypeDB::bind_method(_MD("_bottom_panel_switch"), &EditorNode::_bottom_panel_switch);
+
+
+ ADD_SIGNAL( MethodInfo("play_pressed") );
+ ADD_SIGNAL( MethodInfo("pause_pressed") );
+ ADD_SIGNAL( MethodInfo("stop_pressed") );
+ ADD_SIGNAL( MethodInfo("request_help") );
+ ADD_SIGNAL( MethodInfo("script_add_function_request",PropertyInfo(Variant::OBJECT,"obj"),PropertyInfo(Variant::STRING,"function"),PropertyInfo(Variant::STRING_ARRAY,"args")) );
+ ADD_SIGNAL( MethodInfo("resource_saved",PropertyInfo(Variant::OBJECT,"obj")) );
+
+
+
+}
+
EditorNode::EditorNode() {
EditorHelp::generate_doc(); //before any editor classes are crated
+ SceneState::set_disable_placeholders(true);
+
+ InputDefault *id = Input::get_singleton()->cast_to<InputDefault>();
+
+ if (id) {
+
+ if (!OS::get_singleton()->has_touchscreen_ui_hint() && Input::get_singleton()) {
+ //only if no touchscreen ui hint, set emulation
+ id->set_emulate_touch(false); //just disable just in case
+ }
+ id->set_custom_mouse_cursor(RES());
+ }
+
singleton=this;
last_checked_version=0;
@@ -4058,7 +4755,10 @@ EditorNode::EditorNode() {
ResourceLoader::set_abort_on_missing_resources(false);
FileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("file_dialog/show_hidden_files"));
+ EditorFileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("file_dialog/show_hidden_files"));
+ EditorFileDialog::set_default_display_mode((EditorFileDialog::DisplayMode)EditorSettings::get_singleton()->get("file_dialog/display_mode").operator int());
ResourceLoader::set_error_notify_func(this,_load_error_notify);
+ ResourceLoader::set_dependency_error_notify_func(this,_dependency_error_report);
ResourceLoader::set_timestamp_on_load(true);
ResourceSaver::set_timestamp_on_save(true);
@@ -4139,6 +4839,7 @@ EditorNode::EditorNode() {
gui_base->add_child(main_vbox);
main_vbox->set_area_as_parent_rect(8);
+#if 0
PanelContainer *top_dark_panel = memnew( PanelContainer );
Ref<StyleBoxTexture> top_dark_sb;
top_dark_sb.instance();;
@@ -4154,18 +4855,14 @@ EditorNode::EditorNode() {
VBoxContainer *top_dark_vb = memnew( VBoxContainer );
main_vbox->add_child(top_dark_panel);
top_dark_panel->add_child(top_dark_vb);
-
+#endif
menu_hb = memnew( HBoxContainer );
- top_dark_vb->add_child(menu_hb);
+ main_vbox->add_child(menu_hb);
- scene_tabs=memnew( Tabs );
- scene_tabs->add_tab("unsaved");
- scene_tabs->set_tab_align(Tabs::ALIGN_CENTER);
- scene_tabs->connect("tab_changed",this,"_scene_tab_changed");
- top_dark_vb->add_child(scene_tabs);
+// top_dark_vb->add_child(scene_tabs);
//left
left_l_hsplit = memnew( HSplitContainer );
main_vbox->add_child(left_l_hsplit);
@@ -4198,11 +4895,15 @@ EditorNode::EditorNode() {
main_hsplit = memnew( HSplitContainer );
left_r_hsplit->add_child(main_hsplit);
//main_split->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ VBoxContainer * center_vb = memnew( VBoxContainer);
+ main_hsplit->add_child(center_vb);
+ center_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
center_split = memnew( VSplitContainer );
- main_hsplit->add_child(center_split);
- center_split->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ //main_hsplit->add_child(center_split);
+ center_split->set_v_size_flags(Control::SIZE_EXPAND_FILL);
center_split->set_collapsed(false);
+ center_vb->add_child(center_split);
right_hsplit = memnew( HSplitContainer );
main_hsplit->add_child(right_hsplit);
@@ -4213,6 +4914,9 @@ EditorNode::EditorNode() {
right_l_vsplit->add_child(dock_slot[DOCK_SLOT_RIGHT_UL]);
dock_slot[DOCK_SLOT_RIGHT_BL]=memnew( TabContainer );
right_l_vsplit->add_child(dock_slot[DOCK_SLOT_RIGHT_BL]);
+ //right_l_vsplit->hide();
+ //dock_slot[DOCK_SLOT_RIGHT_UL]->hide();
+ //dock_slot[DOCK_SLOT_RIGHT_BL]->hide();
right_r_vsplit = memnew( VSplitContainer );
right_hsplit->add_child(right_r_vsplit);
@@ -4221,8 +4925,8 @@ EditorNode::EditorNode() {
dock_slot[DOCK_SLOT_RIGHT_BR]=memnew( TabContainer );
right_r_vsplit->add_child(dock_slot[DOCK_SLOT_RIGHT_BR]);
right_r_vsplit->hide();
- //dock_slot[DOCK_SLOT_RIGHT_UL]->hide();
- //dock_slot[DOCK_SLOT_RIGHT_BL]->hide();
+ dock_slot[DOCK_SLOT_RIGHT_UR]->hide();
+ dock_slot[DOCK_SLOT_RIGHT_BR]->hide();
left_l_vsplit->connect("dragged",this,"_dock_split_dragged");
left_r_vsplit->connect("dragged",this,"_dock_split_dragged");
@@ -4274,7 +4978,7 @@ EditorNode::EditorNode() {
//dock_select_popoup->set_(Size2(20,20));
for(int i=0;i<DOCK_SLOT_MAX;i++) {
- dock_slot[i]->set_custom_minimum_size(Size2(250,250));
+ dock_slot[i]->set_custom_minimum_size(Size2(230,220));
dock_slot[i]->set_v_size_flags(Control::SIZE_EXPAND_FILL);
dock_slot[i]->set_popup(dock_select_popoup);
dock_slot[i]->connect("pre_popup_pressed",this,"_dock_pre_popup",varray(i));
@@ -4299,19 +5003,19 @@ EditorNode::EditorNode() {
srt->add_constant_override("separation",0);
- main_editor_tabs = memnew( Tabs );
+/* main_editor_tabs = memnew( Tabs );
main_editor_tabs->connect("tab_changed",this,"_editor_select");
- HBoxContainer *srth = memnew( HBoxContainer );
- srt->add_child( srth );
- Control *tec = memnew( Control );
- tec->set_custom_minimum_size(Size2(100,0));
- tec->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- srth->add_child(tec);
- srth->add_child(main_editor_tabs);
- tec = memnew( Control );
- tec->set_custom_minimum_size(Size2(100,0));
- srth->add_child(tec);
- tec->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ main_editor_tabs->set_tab_close_display_policy(Tabs::SHOW_NEVER);
+*/
+ scene_tabs=memnew( Tabs );
+ scene_tabs->add_tab("unsaved");
+ scene_tabs->set_tab_align(Tabs::ALIGN_CENTER);
+ scene_tabs->set_tab_close_display_policy(Tabs::CLOSE_BUTTON_SHOW_ACTIVE_ONLY);
+ scene_tabs->connect("tab_changed",this,"_scene_tab_changed");
+ scene_tabs->connect("right_button_pressed",this,"_scene_tab_script_edited");
+ scene_tabs->connect("tab_close", this, "_scene_tab_closed");
+
+ srt->add_child(scene_tabs);
scene_root_parent = memnew( Panel );
@@ -4336,8 +5040,9 @@ EditorNode::EditorNode() {
//scene_root_base->add_child(scene_root);
- scene_root->set_meta("_editor_disable_input",true);
+ //scene_root->set_meta("_editor_disable_input",true);
VisualServer::get_singleton()->viewport_set_hide_scenario(scene_root->get_viewport(),true);
+ scene_root->set_disable_input(true);
scene_root->set_as_audio_listener_2d(true);
scene_root->set_size_override(true,Size2(Globals::get_singleton()->get("display/width"),Globals::get_singleton()->get("display/height")));
@@ -4352,42 +5057,6 @@ EditorNode::EditorNode() {
scene_root_parent->add_child(viewport);
- PanelContainer *pc = memnew( PanelContainer );
- top_split->add_child(pc);
- animation_vb = memnew( VBoxContainer );
- animation_vb->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- pc->add_child(animation_vb);
- animation_panel=pc;
- animation_panel->hide();
-
-
- HBoxContainer *animation_hb = memnew( HBoxContainer);
- animation_vb->add_child(animation_hb);
-
- Label *l= memnew( Label );
- l->set_text("Animation:");
- //l->set_h_size_flags(Control::SIZE_);
- animation_hb->add_child(l);
-
- animation_panel_hb = memnew( HBoxContainer );
- animation_hb->add_child(animation_panel_hb);
- animation_panel_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
-
-
- /*pd_anim = memnew( PaneDrag );
- animation_hb->add_child(pd_anim);
- pd_anim->connect("dragged",this,"_dragged");
- pd_anim->set_default_cursor_shape(Control::CURSOR_MOVE);
- pd_anim->hide();*/
-
- anim_close = memnew( TextureButton );
- animation_hb->add_child(anim_close);
- anim_close->connect("pressed",this,"animation_panel_make_visible",make_binds(false));
- anim_close->set_normal_texture( anim_close->get_icon("Close","EditorIcons"));
- anim_close->set_hover_texture( anim_close->get_icon("CloseHover","EditorIcons"));
- anim_close->set_pressed_texture( anim_close->get_icon("Close","EditorIcons"));
-
-
PanelContainer *top_region = memnew( PanelContainer );
top_region->add_style_override("panel",gui_base->get_stylebox("hover","Button"));
HBoxContainer *left_menu_hb = memnew( HBoxContainer );
@@ -4419,6 +5088,7 @@ EditorNode::EditorNode() {
file_menu->set_tooltip("Operations with scene files.");
p=file_menu->get_popup();
p->add_item("New Scene",FILE_NEW_SCENE);
+ p->add_item("New Inherited Scene..",FILE_NEW_INHERITED_SCENE);
p->add_item("Open Scene..",FILE_OPEN_SCENE,KEY_MASK_CMD+KEY_O);
p->add_separator();
p->add_item("Save Scene",FILE_SAVE_SCENE,KEY_MASK_CMD+KEY_S);
@@ -4431,13 +5101,13 @@ EditorNode::EditorNode() {
p->add_separator();
p->add_item("Quick Open Scene..",FILE_QUICK_OPEN_SCENE,KEY_MASK_SHIFT+KEY_MASK_CMD+KEY_O);
p->add_item("Quick Open Script..",FILE_QUICK_OPEN_SCRIPT,KEY_MASK_ALT+KEY_MASK_CMD+KEY_O);
+ p->add_item("Quick Search File..",FILE_QUICK_OPEN_FILE,KEY_MASK_ALT+KEY_MASK_CMD+KEY_P);
p->add_separator();
PopupMenu *pm_export = memnew(PopupMenu );
pm_export->set_name("Export");
p->add_child(pm_export);
p->add_submenu_item("Convert To..","Export");
- pm_export->add_item("Subscene..",FILE_SAVE_SUBSCENE);
pm_export->add_item("Translatable Strings..",FILE_DUMP_STRINGS);
pm_export->add_separator();
pm_export->add_item("MeshLibrary..",FILE_EXPORT_MESH_LIBRARY);
@@ -4454,7 +5124,11 @@ EditorNode::EditorNode() {
p->add_separator();
p->add_item("Revert Scene",EDIT_REVERT);
p->add_separator();
- p->add_item("Quit to Project List",RUN_PROJECT_MANAGER,KEY_MASK_SHIFT+KEY_MASK_CMD+KEY_Q);
+#ifdef OSX_ENABLED
+ p->add_item("Quit to Project List",RUN_PROJECT_MANAGER,KEY_MASK_SHIFT+KEY_MASK_ALT+KEY_Q);
+#else
+ p->add_item("Quit to Project List",RUN_PROJECT_MANAGER,KEY_MASK_SHIFT+KEY_MASK_CTRL+KEY_Q);
+#endif
p->add_item("Quit",FILE_QUIT,KEY_MASK_CMD+KEY_Q);
recent_scenes = memnew( PopupMenu );
@@ -4462,6 +5136,18 @@ EditorNode::EditorNode() {
p->add_child(recent_scenes);
recent_scenes->connect("item_pressed",this,"_open_recent_scene");
+ {
+ Control *sp = memnew( Control );
+ sp->set_custom_minimum_size(Size2(30,0));
+ menu_hb->add_child(sp);
+ }
+
+ PanelContainer *editor_region = memnew( PanelContainer );
+ editor_region->add_style_override("panel",gui_base->get_stylebox("hover","Button"));
+ main_editor_button_vb = memnew( HBoxContainer );
+ editor_region->add_child(main_editor_button_vb);
+ menu_hb->add_child(editor_region);
+
//menu_hb->add_spacer();
#if 0
node_menu = memnew( MenuButton );
@@ -4500,6 +5186,17 @@ EditorNode::EditorNode() {
p=import_menu->get_popup();
p->connect("item_pressed",this,"_menu_option");
+ tool_menu = memnew( MenuButton );
+ tool_menu->set_tooltip("Miscelaneous project or scene wide tools.");
+ tool_menu->set_text("Tools");
+
+ //tool_menu->set_icon(gui_base->get_icon("Save","EditorIcons"));
+ left_menu_hb->add_child( tool_menu );
+
+ p=tool_menu->get_popup();
+ p->connect("item_pressed",this,"_menu_option");
+ p->add_item("Orphan Resource Explorer",TOOLS_ORPHAN_RESOURCES);
+
export_button = memnew( ToolButton );
export_button->set_tooltip("Export the project to many platforms.");
export_button->set_text("Export");
@@ -4562,6 +5259,7 @@ EditorNode::EditorNode() {
menu_hb->add_child(native_play_button);
native_play_button->hide();
native_play_button->get_popup()->connect("item_pressed",this,"_run_in_device");
+ run_native->connect("native_run",this,"_menu_option",varray(RUN_PLAY_NATIVE));
// VSeparator *s1 = memnew( VSeparator );
// play_hb->add_child(s1);
@@ -4582,21 +5280,24 @@ EditorNode::EditorNode() {
play_custom_scene_button->connect("pressed", this,"_menu_option",make_binds(RUN_PLAY_CUSTOM_SCENE));
play_custom_scene_button->set_tooltip("Play custom scene ("+keycode_get_string(KEY_MASK_CMD|KEY_MASK_SHIFT|KEY_F5)+").");
- fileserver_menu = memnew( MenuButton );
- play_hb->add_child(fileserver_menu);
- fileserver_menu->set_flat(true);
- fileserver_menu->set_focus_mode(Control::FOCUS_NONE);
- fileserver_menu->set_icon(gui_base->get_icon("FileServer","EditorIcons"));
- //fileserver_menu->connect("pressed", this,"_menu_option",make_binds(RUN_PLAY_CUSTOM_SCENE));
- fileserver_menu->set_tooltip("Serve the project filesystem to remote clients.");
-
- p=fileserver_menu->get_popup();
- p->add_check_item("Enable File Server",RUN_FILE_SERVER);
- p->set_item_tooltip(p->get_item_index(RUN_FILE_SERVER),"Enable/Disable the File Server.");
+ debug_button = memnew( MenuButton );
+ debug_button->set_flat(true);
+ play_hb->add_child(debug_button);
+ //debug_button->set_toggle_mode(true);
+ debug_button->set_focus_mode(Control::FOCUS_NONE);
+ debug_button->set_icon(gui_base->get_icon("Remote","EditorIcons"));
+ //debug_button->connect("pressed", this,"_menu_option",make_binds(RUN_LIVE_DEBUG));
+ debug_button->set_tooltip("Debug Options");
+
+ p=debug_button->get_popup();
+ p->add_check_item("Live Editing",RUN_LIVE_DEBUG);
+ p->add_check_item("File Server",RUN_FILE_SERVER);
+ p->add_separator();
+ p->add_check_item("Deploy Remote Debug",RUN_DEPLOY_REMOTE_DEBUG);
+ p->add_check_item("Deploy File Server Clients",RUN_DEPLOY_DUMB_CLIENTS);
p->add_separator();
- p->add_check_item("Deploy Dumb Clients",RUN_DEPLOY_DUMB_CLIENTS);
- //p->set_item_checked( p->get_item_index(RUN_DEPLOY_DUMB_CLIENTS),true );
- p->set_item_tooltip(p->get_item_index(RUN_DEPLOY_DUMB_CLIENTS),"Deploy dumb clients when the File Server is active.");
+ p->add_check_item("Visible Collision Shapes",RUN_DEBUG_COLLISONS);
+ p->add_check_item("Visible Navigation",RUN_DEBUG_NAVIGATION);
p->connect("item_pressed",this,"_menu_option");
/*
@@ -4618,6 +5319,39 @@ EditorNode::EditorNode() {
*/
+ progress_hb = memnew( BackgroundProgress );
+ menu_hb->add_child(progress_hb);
+
+ {
+ Control *sp = memnew( Control );
+ sp->set_custom_minimum_size(Size2(30,0));
+ menu_hb->add_child(sp);
+ }
+
+
+ PanelContainer *vu_cont = memnew( PanelContainer );
+ vu_cont->add_style_override("panel",gui_base->get_stylebox("hover","Button"));
+ menu_hb->add_child(vu_cont);
+
+ audio_vu = memnew( TextureProgress );
+ CenterContainer *vu_cc = memnew( CenterContainer );
+ vu_cc->add_child(audio_vu);
+ vu_cont->add_child(vu_cc);
+ audio_vu->set_under_texture(gui_base->get_icon("VuEmpty","EditorIcons"));
+ audio_vu->set_progress_texture(gui_base->get_icon("VuFull","EditorIcons"));
+ audio_vu->set_max(24);
+ audio_vu->set_min(-80);
+ audio_vu->set_step(0.01);
+ audio_vu->set_val(0);
+
+ {
+ Control *sp = memnew( Control );
+ sp->set_custom_minimum_size(Size2(30,0));
+ menu_hb->add_child(sp);
+ }
+
+
+
top_region = memnew( PanelContainer );
top_region->add_style_override("panel",gui_base->get_stylebox("hover","Button"));
HBoxContainer *right_menu_hb = memnew( HBoxContainer );
@@ -4631,17 +5365,25 @@ EditorNode::EditorNode() {
right_menu_hb->add_child( settings_menu );
p=settings_menu->get_popup();
-
//p->add_item("Export Settings",SETTINGS_EXPORT_PREFERENCES);
p->add_item("Editor Settings",SETTINGS_PREFERENCES);
//p->add_item("Optimization Presets",SETTINGS_OPTIMIZED_PRESETS);
p->add_separator();
- p->add_check_item("Show Animation",SETTINGS_SHOW_ANIMATION,KEY_MASK_CMD+KEY_N);
+ editor_layouts = memnew( PopupMenu );
+ editor_layouts->set_name("Layouts");
+ p->add_child(editor_layouts);
+ editor_layouts->connect("item_pressed",this,"_layout_menu_option");
+ p->add_submenu_item("Editor Layout", "Layouts");
p->add_separator();
p->add_item("Install Export Templates",SETTINGS_LOAD_EXPORT_TEMPLATES);
p->add_separator();
p->add_item("About",SETTINGS_ABOUT);
+ layout_dialog = memnew( EditorNameDialog );
+ gui_base->add_child(layout_dialog);
+ layout_dialog->set_hide_on_ok(false);
+ layout_dialog->set_size(Size2(175, 70));
+ layout_dialog->connect("name_confirmed", this,"_dialog_action");
sources_button = memnew( ToolButton );
right_menu_hb->add_child(sources_button);
@@ -4649,6 +5391,15 @@ EditorNode::EditorNode() {
sources_button->connect("pressed",this,"_menu_option",varray(SOURCES_REIMPORT));
sources_button->set_tooltip("Alerts when an external resource has changed.");
+ update_menu = memnew( MenuButton );
+ update_menu->set_tooltip("Spins when the editor window repaints!");
+ right_menu_hb->add_child(update_menu);
+ update_menu->set_icon(gui_base->get_icon("Progress1","EditorIcons"));
+ p=update_menu->get_popup();
+ p->add_check_item("Update Always",SETTINGS_UPDATE_ALWAYS);
+ p->add_check_item("Update Changes",SETTINGS_UPDATE_CHANGES);
+ p->set_item_checked(1,true);
+
//sources_button->connect();
/*
@@ -4672,13 +5423,14 @@ EditorNode::EditorNode() {
scene_tree_dock->set_name("Scene");
//top_pallete->add_child(scene_tree_dock);
dock_slot[DOCK_SLOT_LEFT_UR]->add_child(scene_tree_dock);
-
+#if 0
resources_dock = memnew( ResourcesDock(this) );
resources_dock->set_name("Resources");
//top_pallete->add_child(resources_dock);
dock_slot[DOCK_SLOT_RIGHT_BL]->add_child(resources_dock);
//top_pallete->set_v_size_flags(Control::SIZE_EXPAND_FILL);
-
+#endif
+ dock_slot[DOCK_SLOT_RIGHT_BL]->hide();
/*Control *editor_spacer = memnew( Control );
editor_spacer->set_custom_minimum_size(Size2(260,200));
editor_spacer->set_v_size_flags(Control::SIZE_EXPAND_FILL);
@@ -4703,27 +5455,40 @@ EditorNode::EditorNode() {
dock_slot[DOCK_SLOT_RIGHT_UL]->add_child(prop_editor_base);
HBoxContainer *prop_editor_hb = memnew( HBoxContainer );
- prop_editor_base->add_child(prop_editor_hb);
- editor_path = memnew( EditorPath(&editor_history) );
- editor_path->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- prop_editor_hb->add_child(editor_path);
-
- property_editor = memnew( PropertyEditor );
- property_editor->set_autoclear(true);
- property_editor->set_show_categories(true);
- property_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
-
- property_editor->hide_top_label();
- prop_editor_base->add_child( property_editor );
- property_editor->set_undo_redo(&editor_data.get_undo_redo());
+ prop_editor_base->add_child(prop_editor_hb);
+ resource_new_button = memnew( ToolButton );
+ resource_new_button->set_tooltip("Create a new resource in memory and edit it");
+ resource_new_button->set_icon(gui_base->get_icon("New","EditorIcons"));
+ prop_editor_hb->add_child(resource_new_button);
+ resource_new_button->connect("pressed",this,"_menu_option",varray(RESOURCE_NEW));
+ resource_new_button->set_focus_mode(Control::FOCUS_NONE);
+
+ resource_load_button = memnew( ToolButton );
+ resource_load_button->set_tooltip("Load an existing resource from disk and edit it");
+ resource_load_button->set_icon(gui_base->get_icon("Load","EditorIcons"));
+ prop_editor_hb->add_child(resource_load_button);
+ resource_load_button->connect("pressed",this,"_menu_option",varray(RESOURCE_LOAD));
+ resource_load_button->set_focus_mode(Control::FOCUS_NONE);
+
+ resource_save_button = memnew( MenuButton );
+ resource_save_button->set_tooltip("Save the currently edited resource");
+ resource_save_button->set_icon(gui_base->get_icon("Save","EditorIcons"));
+ prop_editor_hb->add_child(resource_save_button);
+ resource_save_button->get_popup()->add_item("Save",RESOURCE_SAVE);
+ resource_save_button->get_popup()->add_item("Save As..",RESOURCE_SAVE_AS);
+ resource_save_button->get_popup()->connect("item_pressed",this,"_menu_option");
+ resource_save_button->set_focus_mode(Control::FOCUS_NONE);
+ resource_save_button->set_disabled(true);
+
+ prop_editor_hb->add_spacer();
-
property_back = memnew( ToolButton );
property_back->set_icon( gui_base->get_icon("Back","EditorIcons") );
property_back->set_flat(true);
property_back->set_tooltip("Go to the previous edited object in history.");
+ property_back->set_disabled(true);
prop_editor_hb->add_child( property_back );
@@ -4731,77 +5496,135 @@ EditorNode::EditorNode() {
property_forward->set_icon( gui_base->get_icon("Forward","EditorIcons") );
property_forward->set_flat(true);
property_forward->set_tooltip("Go to the next edited object in history.");
+ property_forward->set_disabled(true);
prop_editor_hb->add_child( property_forward );
+
+ editor_history_menu = memnew( MenuButton );
+ editor_history_menu->set_tooltip("History of recently edited objects");
+ editor_history_menu->set_icon( gui_base->get_icon("History","EditorIcons"));
+ prop_editor_hb->add_child(editor_history_menu);
+ editor_history_menu->connect("about_to_show",this,"_prepare_history");
+ editor_history_menu->get_popup()->connect("item_pressed",this,"_select_history");
+
+
+ prop_editor_hb = memnew( HBoxContainer ); //again...
+
+ prop_editor_base->add_child(prop_editor_hb);
+ editor_path = memnew( EditorPath(&editor_history) );
+ editor_path->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ prop_editor_hb->add_child(editor_path);
+
+ search_button = memnew( ToolButton );
+ search_button->set_toggle_mode(true);
+ search_button->set_pressed(false);
+ search_button->set_icon(gui_base->get_icon("Zoom","EditorIcons"));
+ prop_editor_hb->add_child(search_button);
+ search_button->connect("toggled",this,"_toggle_search_bar");
+
object_menu = memnew( MenuButton );
object_menu->set_icon(gui_base->get_icon("Tools","EditorIcons"));
prop_editor_hb->add_child( object_menu );
object_menu->set_tooltip("Object properties.");
+ create_dialog = memnew( CreateDialog );
+ gui_base->add_child(create_dialog);
+ create_dialog->set_base_type("Resource");
+ create_dialog->connect("create",this,"_resource_created");
+
+ search_bar = memnew( HBoxContainer );
+ search_bar->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ prop_editor_base->add_child(search_bar);
+ search_bar->hide();
+
+ Label *l = memnew( Label("Search: ") );
+ search_bar->add_child(l);
+
+ search_box = memnew( LineEdit );
+ search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ search_bar->add_child(search_box);
+
+ ToolButton *clear_button = memnew( ToolButton );
+ clear_button->set_icon(gui_base->get_icon("Close","EditorIcons"));
+ search_bar->add_child(clear_button);
+ clear_button->connect("pressed",this,"_clear_search_box");
+
+ property_editor = memnew( PropertyEditor );
+ property_editor->set_autoclear(true);
+ property_editor->set_show_categories(true);
+ property_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ property_editor->set_use_doc_hints(true);
+
+ property_editor->hide_top_label();
+ property_editor->register_text_enter(search_box);
+
+ prop_editor_base->add_child( property_editor );
+ property_editor->set_undo_redo(&editor_data.get_undo_redo());
+
scenes_dock = memnew( ScenesDock(this) );
scenes_dock->set_name("FileSystem");
+ scenes_dock->set_use_thumbnails(int(EditorSettings::get_singleton()->get("file_dialog/display_mode"))==EditorFileDialog::DISPLAY_THUMBNAILS);
dock_slot[DOCK_SLOT_LEFT_BR]->add_child(scenes_dock);
//prop_pallete->add_child(scenes_dock);
scenes_dock->connect("open",this,"open_request");
scenes_dock->connect("instance",this,"_instance_request");
+ const String docks_section = "docks";
+
+ overridden_default_layout=-1;
+ default_layout.instance();
+ default_layout->set_value(docks_section, "dock_3", "Scene");
+ default_layout->set_value(docks_section, "dock_4", "FileSystem");
+ default_layout->set_value(docks_section, "dock_5", "Inspector");
+
+ for(int i=0;i<DOCK_SLOT_MAX/2;i++)
+ default_layout->set_value(docks_section, "dock_hsplit_"+itos(i+1), 0);
+ for(int i=0;i<DOCK_SLOT_MAX/2;i++)
+ default_layout->set_value(docks_section, "dock_split_"+itos(i+1), 0);
+
+ _update_layouts_menu();
+
+ bottom_panel = memnew( PanelContainer );
+ bottom_panel->add_style_override("panel",gui_base->get_stylebox("panelf","Panel"));
+ center_split->add_child(bottom_panel);
+ center_split->set_dragger_visibility(SplitContainer::DRAGGER_HIDDEN);
+
+ bottom_panel_vb = memnew( VBoxContainer );
+ bottom_panel->add_child(bottom_panel_vb);
+ //bottom_panel_vb->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+
+ bottom_panel_hb = memnew( HBoxContainer );
+ bottom_panel_vb->add_child(bottom_panel_hb);
+
log = memnew( EditorLog );
- center_split->add_child(log);
- log->connect("close_request",this,"_close_messages");
- log->connect("show_request",this,"_show_messages");
- //left_split->set_dragger_visible(false);
- old_split_ofs=0;
+ add_bottom_panel_item("Output",log);
- animation_editor = memnew( AnimationKeyEditor(get_undo_redo(),&editor_history,editor_selection) );
- animation_editor->set_anchor_and_margin(MARGIN_RIGHT,Control::ANCHOR_END,0);
- animation_editor->set_margin(MARGIN_BOTTOM,200);
- animation_editor->connect("keying_changed",this,"_update_keying");
+ //left_split->set_dragger_visible(false);
- animation_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ old_split_ofs=0;
- animation_vb->add_child(animation_editor);
center_split->connect("resized",this,"_vp_resized");
- animation_editor->hide();
-
- PanelContainer *bottom_pc = memnew( PanelContainer );
- main_vbox->add_child(bottom_pc);
+ /*PanelContainer *bottom_pc = memnew( PanelContainer );
+ srt->add_child(bottom_pc);
bottom_hb = memnew( HBoxContainer );
- bottom_pc->add_child(bottom_hb);
+ bottom_pc->add_child(bottom_hb);*/
+
+
+// center_vb->add_child( log->get_button() );
+// log->get_button()->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- bottom_hb->add_child( log->get_button() );
- log->get_button()->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- progress_hb = memnew( BackgroundProgress );
- bottom_hb->add_child(progress_hb);
//progress_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- audio_vu = memnew( TextureProgress );
- CenterContainer *vu_cc = memnew( CenterContainer );
- vu_cc->add_child(audio_vu);
- bottom_hb->add_child(vu_cc);
- audio_vu->set_under_texture(gui_base->get_icon("VuEmpty","EditorIcons"));
- audio_vu->set_progress_texture(gui_base->get_icon("VuFull","EditorIcons"));
- audio_vu->set_max(24);
- audio_vu->set_min(-80);
- audio_vu->set_step(0.01);
- audio_vu->set_val(0);
- update_menu = memnew( MenuButton );
- update_menu->set_tooltip("Spins when the editor window repaints!");
- bottom_hb->add_child(update_menu);
- update_menu->set_icon(gui_base->get_icon("Progress1","EditorIcons"));
- p=update_menu->get_popup();
- p->add_check_item("Update Always",SETTINGS_UPDATE_ALWAYS);
- p->add_check_item("Update Changes",SETTINGS_UPDATE_CHANGES);
- p->set_item_checked(1,true);
/*
animation_menu = memnew( ToolButton );
@@ -4827,7 +5650,8 @@ EditorNode::EditorNode() {
-
+ orphan_resources = memnew( OrphanResourcesDialog );
+ gui_base->add_child(orphan_resources);
@@ -4866,7 +5690,11 @@ EditorNode::EditorNode() {
+ dependency_error = memnew( DependencyErrorDialog );
+ gui_base->add_child(dependency_error);
+ dependency_fixer = memnew( DependencyEditor );
+ gui_base->add_child( dependency_fixer );
settings_config_dialog = memnew( EditorSettingsDialog );
gui_base->add_child(settings_config_dialog);
@@ -4900,7 +5728,7 @@ EditorNode::EditorNode() {
about->get_ok()->set_text("Thanks!");
about->set_hide_on_ok(true);
Label *about_text = memnew( Label );
- about_text->set_text(VERSION_FULL_NAME"\n(c) 2008-2015 Juan Linietsky, Ariel Manzur.\n");
+ about_text->set_text(VERSION_FULL_NAME"\n(c) 2008-2016 Juan Linietsky, Ariel Manzur.\n");
about_text->set_pos(Point2(gui_base->get_icon("Logo","EditorIcons")->get_size().width+30,20));
gui_base->add_child(about);
about->add_child(about_text);
@@ -4991,7 +5819,7 @@ EditorNode::EditorNode() {
file_templates->connect("file_selected", this,"_dialog_action");
property_editor->connect("resource_selected", this,"_resource_selected");
property_editor->connect("property_keyed", this,"_property_keyed");
- animation_editor->connect("resource_selected", this,"_resource_selected");
+
//plugin stuff
file_server = memnew( EditorFileServer );
@@ -5014,12 +5842,18 @@ EditorNode::EditorNode() {
editor_import_export->add_import_plugin( Ref<EditorTranslationImportPlugin>( memnew(EditorTranslationImportPlugin(this))));
editor_import_export->add_export_plugin( Ref<EditorTextureExportPlugin>( memnew(EditorTextureExportPlugin)));
+ editor_import_export->add_export_plugin( Ref<EditorSampleExportPlugin>( memnew(EditorSampleExportPlugin)));
+ editor_import_export->add_export_plugin( Ref<EditorSceneExportPlugin>( memnew(EditorSceneExportPlugin)));
+
+ add_editor_plugin( memnew( AnimationPlayerEditorPlugin(this) ) );
add_editor_plugin( memnew( CanvasItemEditorPlugin(this) ) );
add_editor_plugin( memnew( SpatialEditorPlugin(this) ) );
add_editor_plugin( memnew( ScriptEditorPlugin(this) ) );
- add_editor_plugin( memnew( EditorHelpPlugin(this) ) );
- add_editor_plugin( memnew( AnimationPlayerEditorPlugin(this) ) );
+
+ //more visually meaningful to have this later
+ raise_bottom_panel_item(AnimationPlayerEditor::singleton);
+
add_editor_plugin( memnew( ShaderGraphEditorPlugin(this,true) ) );
add_editor_plugin( memnew( ShaderGraphEditorPlugin(this,false) ) );
add_editor_plugin( memnew( ShaderEditorPlugin(this,true) ) );
@@ -5044,6 +5878,7 @@ EditorNode::EditorNode() {
add_editor_plugin( memnew( TileSetEditorPlugin(this) ) );
add_editor_plugin( memnew( TileMapEditorPlugin(this) ) );
add_editor_plugin( memnew( SpriteFramesEditorPlugin(this) ) );
+ add_editor_plugin( memnew( SpriteRegionEditorPlugin(this) ) );
add_editor_plugin( memnew( Particles2DEditorPlugin(this) ) );
add_editor_plugin( memnew( Path2DEditorPlugin(this) ) );
add_editor_plugin( memnew( PathEditorPlugin(this) ) );
@@ -5051,7 +5886,8 @@ EditorNode::EditorNode() {
add_editor_plugin( memnew( Polygon2DEditorPlugin(this) ) );
add_editor_plugin( memnew( LightOccluder2DEditorPlugin(this) ) );
add_editor_plugin( memnew( NavigationPolygonEditorPlugin(this) ) );
- add_editor_plugin( memnew( ColorRampEditorPlugin(this) ) );
+ add_editor_plugin( memnew( ColorRampEditorPlugin(this,true) ) );
+ add_editor_plugin( memnew( ColorRampEditorPlugin(this,false) ) );
add_editor_plugin( memnew( CollisionShape2DEditorPlugin(this) ) );
for(int i=0;i<EditorPlugins::get_plugin_count();i++)
@@ -5064,9 +5900,10 @@ EditorNode::EditorNode() {
resource_preview->add_preview_generator( Ref<EditorScriptPreviewPlugin>( memnew(EditorScriptPreviewPlugin )));
resource_preview->add_preview_generator( Ref<EditorSamplePreviewPlugin>( memnew(EditorSamplePreviewPlugin )));
resource_preview->add_preview_generator( Ref<EditorMeshPreviewPlugin>( memnew(EditorMeshPreviewPlugin )));
+ resource_preview->add_preview_generator( Ref<EditorBitmapPreviewPlugin>( memnew(EditorBitmapPreviewPlugin )));
circle_step_msec=OS::get_singleton()->get_ticks_msec();
- circle_step_frame=OS::get_singleton()->get_frames_drawn();;
+ circle_step_frame=OS::get_singleton()->get_frames_drawn();
circle_step=0;
_rebuild_import_menu();
@@ -5084,9 +5921,9 @@ EditorNode::EditorNode() {
Globals::get_singleton()->set("debug/indicators_enabled",true);
Globals::get_singleton()->set("render/room_cull_enabled",false);
- theme->set_color("prop_category","Editor",Color::hex(0x403d41ff));
- theme->set_color("prop_section","Editor",Color::hex(0x383539ff));
- theme->set_color("prop_subsection","Editor",Color::hex(0x343135ff));
+ theme->set_color("prop_category","Editor",Color::hex(0x3f3a44ff));
+ theme->set_color("prop_section","Editor",Color::hex(0x35313aff));
+ theme->set_color("prop_subsection","Editor",Color::hex(0x312e37ff));
theme->set_color("fg_selected","Editor",Color::html("ffbd8e8e"));
theme->set_color("fg_error","Editor",Color::html("ffbd8e8e"));
@@ -5193,6 +6030,7 @@ EditorNode::EditorNode() {
EditorNode::~EditorNode() {
+ memdelete( EditorHelp::get_doc_data() );
memdelete(editor_selection);
memdelete(file_server);
EditorSettings::destroy();
diff --git a/tools/editor/editor_node.h b/tools/editor/editor_node.h
index 293da2031d..4dc942c023 100644
--- a/tools/editor/editor_node.h
+++ b/tools/editor/editor_node.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -56,7 +56,7 @@
#include "tools/editor/editor_run.h"
#include "tools/editor/pane_drag.h"
-#include "tools/editor/animation_editor.h"
+
#include "tools/editor/script_create_dialog.h"
#include "tools/editor/run_settings_dialog.h"
#include "tools/editor/project_settings.h"
@@ -76,6 +76,7 @@
#include "editor_reimport_dialog.h"
#include "import_settings.h"
#include "tools/editor/editor_plugin.h"
+#include "tools/editor/editor_name_dialog.h"
#include "fileserver/editor_file_server.h"
#include "editor_resource_preview.h"
@@ -99,14 +100,14 @@ typedef void (*EditorNodeInitCallback)();
class EditorNode : public Node {
OBJ_TYPE( EditorNode, Node );
-
+
enum {
-
- HISTORY_SIZE=64
+ HISTORY_SIZE=64
};
+
enum MenuOptions {
-
FILE_NEW_SCENE,
+ FILE_NEW_INHERITED_SCENE,
FILE_OPEN_SCENE,
FILE_SAVE_SCENE,
FILE_SAVE_AS_SCENE,
@@ -117,12 +118,12 @@ class EditorNode : public Node {
FILE_EXPORT_MESH_LIBRARY,
FILE_EXPORT_TILESET,
FILE_SAVE_OPTIMIZED,
- FILE_SAVE_SUBSCENE,
FILE_DUMP_STRINGS,
FILE_OPEN_RECENT,
FILE_OPEN_OLD_SCENE,
FILE_QUICK_OPEN_SCENE,
FILE_QUICK_OPEN_SCRIPT,
+ FILE_QUICK_OPEN_FILE,
FILE_RUN_SCRIPT,
FILE_OPEN_PREV,
FILE_CLOSE,
@@ -131,12 +132,14 @@ class EditorNode : public Node {
EDIT_UNDO,
EDIT_REDO,
EDIT_REVERT,
+ TOOLS_ORPHAN_RESOURCES,
RESOURCE_NEW,
RESOURCE_LOAD,
RESOURCE_SAVE,
RESOURCE_SAVE_AS,
RESOURCE_UNREF,
RESOURCE_COPY,
+ RESOURCE_PASTE,
OBJECT_COPY_PARAMS,
OBJECT_PASTE_PARAMS,
OBJECT_UNIQUE_RESOURCES,
@@ -146,25 +149,33 @@ class EditorNode : public Node {
RUN_PAUSE,
RUN_STOP,
RUN_PLAY_SCENE,
+ RUN_PLAY_NATIVE,
RUN_PLAY_CUSTOM_SCENE,
RUN_SCENE_SETTINGS,
RUN_SETTINGS,
RUN_PROJECT_MANAGER,
RUN_FILE_SERVER,
RUN_DEPLOY_DUMB_CLIENTS,
+ RUN_LIVE_DEBUG,
+ RUN_DEBUG_COLLISONS,
+ RUN_DEBUG_NAVIGATION,
+ RUN_DEPLOY_REMOTE_DEBUG,
SETTINGS_UPDATE_ALWAYS,
SETTINGS_UPDATE_CHANGES,
SETTINGS_IMPORT,
SETTINGS_EXPORT_PREFERENCES,
SETTINGS_PREFERENCES,
SETTINGS_OPTIMIZED_PRESETS,
- SETTINGS_SHOW_ANIMATION,
+ SETTINGS_LAYOUT_SAVE,
+ SETTINGS_LAYOUT_DELETE,
+ SETTINGS_LAYOUT_DEFAULT,
SETTINGS_LOAD_EXPORT_TEMPLATES,
SETTINGS_HELP,
SETTINGS_ABOUT,
SOURCES_REIMPORT,
DEPENDENCY_LOAD_CHANGED_IMAGES,
DEPENDENCY_UPDATE_IMPORTED,
+ SCENE_TAB_CLOSE,
IMPORT_PLUGIN_BASE=100,
@@ -209,6 +220,7 @@ class EditorNode : public Node {
//main tabs
Tabs *scene_tabs;
+ int tab_closing;
int old_split_ofs;
@@ -217,7 +229,6 @@ class EditorNode : public Node {
Control *vp_base;
PaneDrag *pd;
//PaneDrag *pd_anim;
- TextureButton *anim_close;
Panel *menu_panel;
@@ -227,6 +238,7 @@ class EditorNode : public Node {
Control *viewport;
MenuButton *file_menu;
MenuButton *import_menu;
+ MenuButton *tool_menu;
ToolButton *export_button;
ToolButton *prev_scene;
MenuButton *object_menu;
@@ -236,11 +248,12 @@ class EditorNode : public Node {
ToolButton *pause_button;
ToolButton *stop_button;
ToolButton *run_settings_button;
- ToolButton *animation_menu;
ToolButton *play_scene_button;
ToolButton *play_custom_scene_button;
+ MenuButton *debug_button;
+ ToolButton *search_button;
TextureProgress *audio_vu;
- MenuButton *fileserver_menu;
+ //MenuButton *fileserver_menu;
TextEdit *load_errors;
AcceptDialog *load_error_dialog;
@@ -252,11 +265,16 @@ class EditorNode : public Node {
Button *property_back;
Button *property_forward;
SceneTreeDock *scene_tree_dock;
- ResourcesDock *resources_dock;
+ //ResourcesDock *resources_dock;
PropertyEditor *property_editor;
ScenesDock *scenes_dock;
EditorRunNative *run_native;
+ HBoxContainer *search_bar;
+ LineEdit *search_box;
+
+ CreateDialog *create_dialog;
+
CallDialog *call_dialog;
ConfirmationDialog *confirmation;
ConfirmationDialog *import_confirmation;
@@ -265,6 +283,11 @@ class EditorNode : public Node {
AcceptDialog *about;
AcceptDialog *warning;
+ int overridden_default_layout;
+ Ref<ConfigFile> default_layout;
+ PopupMenu *editor_layouts;
+ EditorNameDialog *layout_dialog;
+
//OptimizedPresetsDialog *optimized_presets;
EditorSettingsDialog *settings_config_dialog;
RunSettingsDialog *run_settings_dialog;
@@ -290,16 +313,19 @@ class EditorNode : public Node {
String defer_export_platform;
bool defer_export_debug;
Node *_last_instanced_scene;
- PanelContainer *animation_panel;
- HBoxContainer *animation_panel_hb;
- VBoxContainer *animation_vb;
EditorPath *editor_path;
- AnimationKeyEditor *animation_editor;
+ ToolButton *resource_new_button;
+ ToolButton *resource_load_button;
+ MenuButton *resource_save_button;
+ MenuButton *editor_history_menu;
+
EditorLog *log;
CenterContainer *tabs_center;
EditorQuickOpen *quick_open;
EditorQuickOpen *quick_run;
- Tabs *main_editor_tabs;
+
+ HBoxContainer *main_editor_button_vb;
+ Vector<ToolButton*> main_editor_buttons;
Vector<EditorPlugin*> editor_table;
EditorReImportDialog *reimport_dialog;
@@ -308,6 +334,10 @@ class EditorNode : public Node {
ProgressDialog *progress_dialog;
BackgroundProgress *progress_hb;
+ DependencyErrorDialog *dependency_error;
+ DependencyEditor *dependency_fixer;
+ OrphanResourcesDialog *orphan_resources;
+
TabContainer *dock_slot[DOCK_SLOT_MAX];
Rect2 dock_select_rect[DOCK_SLOT_MAX];
int dock_select_rect_over;
@@ -351,6 +381,21 @@ class EditorNode : public Node {
EditorFileServer *file_server;
+
+ struct BottomPanelItem {
+ String name;
+ Control *control;
+ ToolButton *button;
+ };
+
+ Vector<BottomPanelItem> bottom_panel_items;
+
+ PanelContainer *bottom_panel;
+ HBoxContainer *bottom_panel_hb;
+ VBoxContainer *bottom_panel_vb;
+
+ void _bottom_panel_switch(bool p_enable, int p_idx);
+
String external_file;
List<String> previous_scenes;
bool opening_prev;
@@ -363,6 +408,7 @@ class EditorNode : public Node {
int current_option;
//void _animation_visibility_toggle();
+ void _resource_created();
void _resource_selected(const RES& p_res,const String& p_property="");
void _menu_option(int p_option);
void _menu_confirm_current();
@@ -371,6 +417,9 @@ class EditorNode : public Node {
void _property_editor_forward();
void _property_editor_back();
+ void _select_history(int p_idx);
+ void _prepare_history();
+
void _fs_changed();
void _sources_changed(bool p_exist);
@@ -378,8 +427,8 @@ class EditorNode : public Node {
void _node_renamed();
void _editor_select(int p_which);
- void _set_scene_metadata();
- void _get_scene_metadata();
+ void _set_scene_metadata(const String &p_file);
+ void _get_scene_metadata(const String& p_file);
void _update_title();
void _update_scene_tabs();
void _close_messages();
@@ -396,9 +445,8 @@ class EditorNode : public Node {
void _property_keyed(const String& p_keyed, const Variant& p_value, bool p_advance);
void _transform_keyed(Object *sp,const String& p_sub,const Transform& p_key);
- void _update_keying();
void _hide_top_editors();
- void _quick_opened(const String& p_resource);
+ void _quick_opened();
void _quick_run(const String& p_resource);
void _run(bool p_current=false, const String &p_custom="");
@@ -439,6 +487,7 @@ class EditorNode : public Node {
void _cleanup_scene();
void _remove_edited_scene();
+ void _remove_scene(int index);
bool _find_and_save_resource(RES p_res,Map<RES,bool>& processed,int32_t flags);
bool _find_and_save_edited_subresources(Object *obj,Map<RES,bool>& processed,int32_t flags);
void _save_edited_subresources(Node* scene,Map<RES,bool>& processed,int32_t flags);
@@ -447,6 +496,16 @@ class EditorNode : public Node {
void _save_scene_with_preview(String p_file);
+ Map<String,Set<String> > dependency_errors;
+
+ static void _dependency_error_report(void *ud,const String& p_path,const String& p_dep,const String& p_type) {
+ EditorNode*en=(EditorNode*)ud;
+ if (!en->dependency_errors.has(p_path))
+ en->dependency_errors[p_path]=Set<String>();
+ en->dependency_errors[p_path].insert(p_dep+"::"+p_type);
+
+ }
+
struct ExportDefer {
String platform;
String path;
@@ -469,18 +528,37 @@ class EditorNode : public Node {
void _dock_split_dragged(int ofs);
void _dock_popup_exit();
void _scene_tab_changed(int p_tab);
+ void _scene_tab_closed(int p_tab);
+ void _scene_tab_script_edited(int p_tab);
Dictionary _get_main_scene_state();
void _set_main_scene_state(Dictionary p_state);
+ int _get_current_main_editor();
+
void _save_docks();
void _load_docks();
+ void _save_docks_to_config(Ref<ConfigFile> p_layout, const String& p_section);
+ void _load_docks_from_config(Ref<ConfigFile> p_layout, const String& p_section);
+
+ void _update_layouts_menu();
+ void _layout_menu_option(int p_idx);
+
+ void _toggle_search_bar(bool p_pressed);
+ void _clear_search_box();
+ void _clear_undo_history();
protected:
void _notification(int p_what);
- static void _bind_methods();
+ static void _bind_methods();
public:
+ enum EditorTable {
+ EDITOR_2D = 0,
+ EDITOR_3D,
+ EDITOR_SCRIPT
+ };
+
static EditorNode* get_singleton() { return singleton; }
@@ -498,6 +576,8 @@ public:
void edit_node(Node *p_node);
void edit_resource(const Ref<Resource>& p_resource);
void open_resource(const String& p_type="");
+
+ void save_resource_in_path(const Ref<Resource>& p_resource,const String& p_path);
void save_resource(const Ref<Resource>& p_resource);
void save_resource_as(const Ref<Resource>& p_resource);
@@ -514,13 +594,10 @@ public:
static EditorLog *get_log() { return singleton->log; }
Control* get_viewport();
- AnimationKeyEditor *get_animation_editor() const { return animation_editor; }
- Control *get_animation_panel() { return animation_vb; }
- HBoxContainer *get_animation_panel_hb() { return animation_panel_hb; }
- void animation_editor_make_visible(bool p_visible);
- void hide_animation_player_editors();
- void animation_panel_make_visible(bool p_visible);
+ //void animation_editor_make_visible(bool p_visible);
+ //void hide_animation_player_editors();
+ //void animation_panel_make_visible(bool p_visible);
void set_edited_scene(Node *p_scene);
@@ -529,14 +606,18 @@ public:
Viewport *get_scene_root() { return scene_root; } //root of the scene being edited
Error save_optimized_copy(const String& p_scene,const String& p_preset);
+ void fix_dependencies(const String& p_for_file);
void clear_scene() { _cleanup_scene(); }
- Error load_scene(const String& p_scene);
+ Error load_scene(const String& p_scene, bool p_ignore_broken_deps=false, bool p_set_inherited=false);
Error load_resource(const String& p_scene);
+ bool is_scene_open(const String& p_path);
+
void set_current_version(uint64_t p_version);
void set_current_scene(int p_idx);
static EditorData& get_editor_data() { return singleton->editor_data; }
+ EditorHistory * get_editor_history() { return &editor_history; }
static VSplitContainer *get_top_split() { return singleton->top_split; }
@@ -570,7 +651,7 @@ public:
static void add_io_error(const String& p_error);
static void progress_add_task(const String& p_task,const String& p_label, int p_steps);
- static void progress_task_step(const String& p_task,const String& p_state, int p_step=-1);
+ static void progress_task_step(const String& p_task,const String& p_state, int p_step=-1,bool p_force_refresh=true);
static void progress_end_task(const String& p_task);
static void progress_add_task_bg(const String& p_task,const String& p_label, int p_steps);
@@ -585,6 +666,14 @@ public:
void save_layout();
+ void update_keying();
+
+
+ ToolButton* add_bottom_panel_item(String p_text,Control *p_item);
+ void make_bottom_panel_item_visible(Control *p_item);
+ void raise_bottom_panel_item(Control *p_item);
+ void hide_bottom_panel();
+
EditorNode();
~EditorNode();
void get_singleton(const char* arg1, bool arg2);
@@ -597,7 +686,7 @@ public:
struct EditorProgress {
String task;
- void step(const String& p_state, int p_step=-1) { EditorNode::progress_task_step(task,p_state,p_step); }
+ void step(const String& p_state, int p_step=-1,bool p_force_refresh=true) { EditorNode::progress_task_step(task,p_state,p_step,p_force_refresh); }
EditorProgress(const String& p_task,const String& p_label,int p_amount) { EditorNode::progress_add_task(p_task,p_label,p_amount); task=p_task; }
~EditorProgress() { EditorNode::progress_end_task(task); }
};
diff --git a/tools/editor/editor_path.cpp b/tools/editor/editor_path.cpp
index 86fd79d014..4cf98e832c 100644
--- a/tools/editor/editor_path.cpp
+++ b/tools/editor/editor_path.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -73,7 +73,11 @@ void EditorPath::_notification(int p_what) {
if (obj->cast_to<Resource>()) {
Resource *r = obj->cast_to<Resource>();
- name=r->get_name();
+ if (r->get_path().is_resource_file())
+ name=r->get_path().get_file();
+ else
+ name=r->get_name();
+
if (name=="")
name=r->get_type();
} else if (obj->cast_to<Node>()) {
diff --git a/tools/editor/editor_path.h b/tools/editor/editor_path.h
index 2edaeb92a3..11e1005ba3 100644
--- a/tools/editor/editor_path.h
+++ b/tools/editor/editor_path.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/editor_plugin.cpp b/tools/editor/editor_plugin.cpp
index 04c34d9a88..b7ccb452e9 100644
--- a/tools/editor/editor_plugin.cpp
+++ b/tools/editor/editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -74,6 +74,7 @@ void EditorPlugin::add_custom_control(CustomControlContainer p_location,Control
case CONTAINER_CANVAS_EDITOR_SIDE: {
CanvasItemEditor::get_singleton()->get_palette_split()->add_child(p_control);
+ CanvasItemEditor::get_singleton()->get_palette_split()->move_child(p_control,0);
} break;
case CONTAINER_CANVAS_EDITOR_BOTTOM: {
diff --git a/tools/editor/editor_plugin.h b/tools/editor/editor_plugin.h
index 0f3a1e2e3c..bf1e185a37 100644
--- a/tools/editor/editor_plugin.h
+++ b/tools/editor/editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -92,6 +92,7 @@ public:
virtual bool get_remove_list(List<Node*> *p_list);
virtual void set_window_layout(Ref<ConfigFile> p_layout);
virtual void get_window_layout(Ref<ConfigFile> p_layout);
+ virtual void edited_scene_changed(){}; // if changes are pending in editor, apply them
virtual void restore_global_state();
virtual void save_global_state();
diff --git a/tools/editor/editor_reimport_dialog.cpp b/tools/editor/editor_reimport_dialog.cpp
index 8842a485b3..eab5a5e32d 100644
--- a/tools/editor/editor_reimport_dialog.cpp
+++ b/tools/editor/editor_reimport_dialog.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/editor_reimport_dialog.h b/tools/editor/editor_reimport_dialog.h
index 9726bac805..0c2d0eb52c 100644
--- a/tools/editor/editor_reimport_dialog.h
+++ b/tools/editor/editor_reimport_dialog.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/editor_run.cpp b/tools/editor/editor_run.cpp
index 77c5f419b1..fb0f24c084 100644
--- a/tools/editor/editor_run.cpp
+++ b/tools/editor/editor_run.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -28,7 +28,7 @@
/*************************************************************************/
#include "editor_run.h"
#include "globals.h"
-
+#include "editor_settings.h"
EditorRun::Status EditorRun::get_status() const {
@@ -61,6 +61,77 @@ Error EditorRun::run(const String& p_scene,const String p_custom_args,const List
}
}
+ if (debug_collisions) {
+ args.push_back("-debugcol");
+ }
+
+ if (debug_navigation) {
+ args.push_back("-debugnav");
+ }
+
+ int screen = EditorSettings::get_singleton()->get("game_window_placement/screen");
+
+ if (screen==0) {
+ screen=OS::get_singleton()->get_current_screen();
+ } else {
+ screen--;
+ }
+
+ Rect2 screen_rect;
+ screen_rect.pos=OS::get_singleton()->get_screen_position(screen);
+ screen_rect.size=OS::get_singleton()->get_screen_size(screen);
+
+
+ Size2 desired_size;
+
+ desired_size.x=Globals::get_singleton()->get("display/width");
+ desired_size.y=Globals::get_singleton()->get("display/height");
+
+ Size2 test_size;
+ test_size.x=Globals::get_singleton()->get("display/test_width");
+ test_size.y=Globals::get_singleton()->get("display/test_height");
+ if (test_size.x>0 && test_size.y>0) {
+
+ desired_size=test_size;
+ }
+
+
+ int window_placement=EditorSettings::get_singleton()->get("game_window_placement/rect");
+
+ switch(window_placement) {
+ case 0: { // default
+
+ args.push_back("-p");
+ args.push_back(itos(screen_rect.pos.x)+"x"+itos(screen_rect.pos.y));
+ } break;
+ case 1: { // centered
+ Vector2 pos=screen_rect.pos+((screen_rect.size-desired_size)/2).floor();
+ args.push_back("-p");
+ args.push_back(itos(pos.x)+"x"+itos(pos.y));
+ } break;
+ case 2: { // custom pos
+ Vector2 pos = EditorSettings::get_singleton()->get("game_window_placement/rect_custom_position");
+ pos+=screen_rect.pos;
+ args.push_back("-p");
+ args.push_back(itos(pos.x)+"x"+itos(pos.y));
+ } break;
+ case 3: { // force maximized
+ Vector2 pos=screen_rect.pos;
+ args.push_back("-p");
+ args.push_back(itos(pos.x)+"x"+itos(pos.y));
+ args.push_back("-mx");
+
+ } break;
+ case 4: { // force fullscreen
+
+ Vector2 pos=screen_rect.pos;
+ args.push_back("-p");
+ args.push_back(itos(pos.x)+"x"+itos(pos.y));
+ args.push_back("-f");
+ } break;
+ }
+
+
if (p_breakpoints.size()) {
args.push_back("-bp");
@@ -105,7 +176,31 @@ void EditorRun::stop() {
status=STATUS_STOP;
}
+void EditorRun::set_debug_collisions(bool p_debug) {
+
+ debug_collisions=p_debug;
+}
+
+bool EditorRun::get_debug_collisions() const{
+
+ return debug_collisions;
+}
+
+void EditorRun::set_debug_navigation(bool p_debug) {
+
+ debug_navigation=p_debug;
+}
+
+bool EditorRun::get_debug_navigation() const{
+
+ return debug_navigation;
+}
+
+
EditorRun::EditorRun() {
status=STATUS_STOP;
+ debug_collisions=false;
+ debug_navigation=false;
+
}
diff --git a/tools/editor/editor_run.h b/tools/editor/editor_run.h
index 5541cc84fa..0b96a2c91c 100644
--- a/tools/editor/editor_run.h
+++ b/tools/editor/editor_run.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -43,12 +43,22 @@ public:
OS::ProcessID pid;
private:
+ bool debug_collisions;
+ bool debug_navigation;
Status status;
public:
Status get_status() const;
Error run(const String& p_scene,const String p_custom_args,const List<String>& p_breakpoints,const String& p_edited_scene);
+ void run_native_notify() { status=STATUS_PLAY; }
void stop();
+
+ void set_debug_collisions(bool p_debug);
+ bool get_debug_collisions() const;
+
+ void set_debug_navigation(bool p_debug);
+ bool get_debug_navigation() const;
+
EditorRun();
};
diff --git a/tools/editor/editor_run_native.cpp b/tools/editor/editor_run_native.cpp
index 83b1753ea2..234dd03087 100644
--- a/tools/editor/editor_run_native.cpp
+++ b/tools/editor/editor_run_native.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -101,12 +101,28 @@ void EditorRunNative::_run_native(int p_idx,const String& p_platform) {
Ref<EditorExportPlatform> eep = EditorImportExport::get_singleton()->get_export_platform(p_platform);
ERR_FAIL_COND(eep.is_null());
- eep->run(p_idx,deploy_dumb);
+ if (deploy_debug_remote) {
+ emit_signal("native_run");
+
+ }
+ int flags=0;
+ if (deploy_debug_remote)
+ flags|=EditorExportPlatform::EXPORT_REMOTE_DEBUG;
+ if (deploy_dumb)
+ flags|=EditorExportPlatform::EXPORT_DUMB_CLIENT;
+ if (debug_collisions)
+ flags|=EditorExportPlatform::EXPORT_VIEW_COLLISONS;
+ if (debug_navigation)
+ flags|=EditorExportPlatform::EXPORT_VIEW_NAVIGATION;
+
+ eep->run(p_idx,flags);
}
void EditorRunNative::_bind_methods() {
ObjectTypeDB::bind_method("_run_native",&EditorRunNative::_run_native);
+
+ ADD_SIGNAL(MethodInfo("native_run"));
}
void EditorRunNative::set_deploy_dumb(bool p_enabled) {
@@ -119,10 +135,43 @@ bool EditorRunNative::is_deploy_dumb_enabled() const{
return deploy_dumb;
}
+void EditorRunNative::set_deploy_debug_remote(bool p_enabled) {
+
+ deploy_debug_remote=p_enabled;
+}
+
+bool EditorRunNative::is_deploy_debug_remote_enabled() const{
+
+ return deploy_debug_remote;
+}
+
+void EditorRunNative::set_debug_collisions(bool p_debug) {
+
+ debug_collisions=p_debug;
+}
+
+bool EditorRunNative::get_debug_collisions() const{
+
+ return debug_collisions;
+}
+
+void EditorRunNative::set_debug_navigation(bool p_debug) {
+
+ debug_navigation=p_debug;
+}
+
+bool EditorRunNative::get_debug_navigation() const{
+
+ return debug_navigation;
+}
EditorRunNative::EditorRunNative()
{
set_process(true);
first=true;
deploy_dumb=false;
+ deploy_debug_remote=false;
+ debug_collisions=false;
+ debug_navigation=false;
+
}
diff --git a/tools/editor/editor_run_native.h b/tools/editor/editor_run_native.h
index 1512dc5dd9..04dad6b6aa 100644
--- a/tools/editor/editor_run_native.h
+++ b/tools/editor/editor_run_native.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -39,6 +39,9 @@ class EditorRunNative : public HBoxContainer {
Map<StringName,MenuButton*> menus;
bool first;
bool deploy_dumb;
+ bool deploy_debug_remote;
+ bool debug_collisions;
+ bool debug_navigation;
void _run_native(int p_idx,const String& p_platform);
@@ -50,6 +53,16 @@ public:
void set_deploy_dumb(bool p_enabled);
bool is_deploy_dumb_enabled() const;
+
+ void set_deploy_debug_remote(bool p_enabled);
+ bool is_deploy_debug_remote_enabled() const;
+
+ void set_debug_collisions(bool p_debug);
+ bool get_debug_collisions() const;
+
+ void set_debug_navigation(bool p_debug);
+ bool get_debug_navigation() const;
+
EditorRunNative();
};
diff --git a/tools/editor/editor_selection.cpp b/tools/editor/editor_selection.cpp
index d8fd8735fc..f3fbdba907 100644
--- a/tools/editor/editor_selection.cpp
+++ b/tools/editor/editor_selection.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/editor_selection.h b/tools/editor/editor_selection.h
index f10f313a4e..d238d86567 100644
--- a/tools/editor/editor_selection.h
+++ b/tools/editor/editor_selection.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/editor_settings.cpp b/tools/editor/editor_settings.cpp
index 0df9fcadef..4195ba97e6 100644
--- a/tools/editor/editor_settings.cpp
+++ b/tools/editor/editor_settings.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -274,6 +274,7 @@ void EditorSettings::create() {
print_line("EditorSettings: Load OK!");
}
+ singleton->setup_network();
singleton->load_favorites();
singleton->scan_plugins();
@@ -289,6 +290,7 @@ void EditorSettings::create() {
singleton->config_file_path=config_file_path;
singleton->settings_path=config_path+"/"+config_dir;
singleton->_load_defaults();
+ singleton->setup_network();
singleton->scan_plugins();
@@ -330,6 +332,35 @@ Error EditorSettings::_load_plugin(const String& p_path, Plugin &plugin) {
return OK;
}
+void EditorSettings::setup_network() {
+
+ List<IP_Address> local_ip;
+ IP::get_singleton()->get_local_addresses(&local_ip);
+ String lip;
+ String hint;
+ String current=get("network/debug_host");
+
+ for(List<IP_Address>::Element *E=local_ip.front();E;E=E->next()) {
+
+ String ip = E->get();
+ if (ip=="127.0.0.1")
+ continue;
+
+ if (lip!="")
+ lip=ip;
+ if (ip==current)
+ lip=current; //so it saves
+ if (hint!="")
+ hint+=",";
+ hint+=ip;
+
+ }
+
+ set("network/debug_host",lip);
+ add_property_hint(PropertyInfo(Variant::STRING,"network/debug_host",PROPERTY_HINT_ENUM,hint));
+
+}
+
void EditorSettings::scan_plugins() {
Map<String,Plugin> new_plugins;
@@ -416,7 +447,7 @@ void EditorSettings::_load_defaults() {
hints["global/default_project_path"]=PropertyInfo(Variant::STRING,"global/default_project_path",PROPERTY_HINT_GLOBAL_DIR);
set("global/default_project_export_path","");
hints["global/default_project_export_path"]=PropertyInfo(Variant::STRING,"global/default_project_export_path",PROPERTY_HINT_GLOBAL_DIR);
-
+ set("global/show_script_in_scene_tabs",false);
set("text_editor/background_color",Color::html("3b000000"));
set("text_editor/text_color",Color::html("aaaaaa"));
set("text_editor/text_selected_color",Color::html("000000"));
@@ -443,6 +474,7 @@ void EditorSettings::_load_defaults() {
set("scenetree_editor/duplicate_node_name_num_separator",0);
hints["scenetree_editor/duplicate_node_name_num_separator"]=PropertyInfo(Variant::INT,"scenetree_editor/duplicate_node_name_num_separator",PROPERTY_HINT_ENUM, "None,Space,Underscore,Dash");
+ set("gridmap_editor/pick_distance", 5000.0);
set("3d_editor/default_fov",45.0);
set("3d_editor/default_z_near",0.1);
@@ -465,6 +497,16 @@ void EditorSettings::_load_defaults() {
set("2d_editor/bone_selected_color",Color(0.9,0.45,0.45,0.9));
set("2d_editor/bone_ik_color",Color(0.9,0.9,0.45,0.9));
+ set("game_window_placement/rect",0);
+ hints["game_window_placement/rect"]=PropertyInfo(Variant::INT,"game_window_placement/rect",PROPERTY_HINT_ENUM,"Default,Centered,Custom Position,Force Maximized,Force Full Screen");
+ String screen_hints="Default (Same as Editor)";
+ for(int i=0;i<OS::get_singleton()->get_screen_count();i++) {
+ screen_hints+=",Monitor "+itos(i+1);
+ }
+ set("game_window_placement/rect_custom_position",Vector2());
+ set("game_window_placement/screen",0);
+ hints["game_window_placement/screen"]=PropertyInfo(Variant::INT,"game_window_placement/screen",PROPERTY_HINT_ENUM,screen_hints);
+
set("on_save/compress_binary_resources",true);
set("on_save/save_modified_external_resources",true);
set("on_save/save_paths_as_relative",false);
@@ -473,6 +515,8 @@ void EditorSettings::_load_defaults() {
set("text_editor/create_signal_callbacks",true);
set("file_dialog/show_hidden_files", false);
+ set("file_dialog/display_mode", 0);
+ hints["file_dialog/display_mode"]=PropertyInfo(Variant::INT,"file_dialog/display_mode",PROPERTY_HINT_ENUM,"Thumbnails,List");
set("file_dialog/thumbnail_size", 64);
hints["file_dialog/thumbnail_size"]=PropertyInfo(Variant::INT,"file_dialog/thumbnail_size",PROPERTY_HINT_RANGE,"32,128,16");
diff --git a/tools/editor/editor_settings.h b/tools/editor/editor_settings.h
index 6b7e6eb989..d1a11360af 100644
--- a/tools/editor/editor_settings.h
+++ b/tools/editor/editor_settings.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -107,12 +107,14 @@ public:
static EditorSettings *get_singleton();
void erase(String p_var);
String get_settings_path() const;
+ String get_global_settings_path() const;
String get_project_settings_path() const;
const Map<String,Plugin>& get_plugins() const { return plugins; }
void scan_plugins();
void enable_plugins();
+ void setup_network();
void raise_order(const String& p_name);
static void create();
diff --git a/tools/editor/editor_sub_scene.cpp b/tools/editor/editor_sub_scene.cpp
index 2a6eba2554..e58e2c1351 100644
--- a/tools/editor/editor_sub_scene.cpp
+++ b/tools/editor/editor_sub_scene.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -196,7 +196,11 @@ void EditorSubScene::_bind_methods() {
EditorSubScene::EditorSubScene() {
+ scene=NULL;
+
set_title("Select Sub-Scene..");
+ set_hide_on_ok(false);
+
VBoxContainer *vb = memnew( VBoxContainer );
add_child(vb);
set_child_rect(vb);
@@ -211,9 +215,11 @@ EditorSubScene::EditorSubScene() {
hb->add_child(b);
b->connect("pressed",this,"_path_browse");
vb->add_margin_child("Scene Path:",hb);
+
tree = memnew( Tree );
tree->set_v_size_flags(SIZE_EXPAND_FILL);
- vb->add_margin_child("Import From Node:",tree)->set_v_size_flags(SIZE_EXPAND_FILL);
+ vb->add_margin_child("Import From Node:",tree,true);
+ tree->connect("item_activated",this,"_ok");
file_dialog = memnew( EditorFileDialog );
List<String> extensions;
@@ -228,8 +234,4 @@ EditorSubScene::EditorSubScene() {
add_child(file_dialog);
file_dialog->connect("file_selected",this,"_path_selected");
- scene=NULL;
-
- set_hide_on_ok(false);
-
}
diff --git a/tools/editor/editor_sub_scene.h b/tools/editor/editor_sub_scene.h
index dfd6c531e2..3dd86eefda 100644
--- a/tools/editor/editor_sub_scene.h
+++ b/tools/editor/editor_sub_scene.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/editor_vu.cpp b/tools/editor/editor_vu.cpp
index ac11aceb21..7a133c9736 100644
--- a/tools/editor/editor_vu.cpp
+++ b/tools/editor/editor_vu.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/editor_vu.h b/tools/editor/editor_vu.h
index 4c51ac31c0..78fe3eda86 100644
--- a/tools/editor/editor_vu.h
+++ b/tools/editor/editor_vu.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/file_type_cache.cpp b/tools/editor/file_type_cache.cpp
index a86400a560..7044a9900c 100644
--- a/tools/editor/file_type_cache.cpp
+++ b/tools/editor/file_type_cache.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/file_type_cache.h b/tools/editor/file_type_cache.h
index efc6d22b25..18451cbe19 100644
--- a/tools/editor/file_type_cache.h
+++ b/tools/editor/file_type_cache.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/fileserver/SCsub b/tools/editor/fileserver/SCsub
index b525fb3f75..363a2ce4c0 100644
--- a/tools/editor/fileserver/SCsub
+++ b/tools/editor/fileserver/SCsub
@@ -1,7 +1,3 @@
Import('env')
Export('env')
env.add_source_files(env.tool_sources,"*.cpp")
-
-
-
-
diff --git a/tools/editor/fileserver/editor_file_server.cpp b/tools/editor/fileserver/editor_file_server.cpp
index b66a1d522b..ea95e4da1c 100644
--- a/tools/editor/fileserver/editor_file_server.cpp
+++ b/tools/editor/fileserver/editor_file_server.cpp
@@ -318,27 +318,7 @@ EditorFileServer::EditorFileServer() {
cmd=CMD_NONE;
thread=Thread::create(_thread_start,this);
- List<IP_Address> local_ip;
- IP::get_singleton()->get_local_addresses(&local_ip);
EDITOR_DEF("file_server/port",6010);
- String lip;
- String hint;
- for(List<IP_Address>::Element *E=local_ip.front();E;E=E->next()) {
-
- String ip = E->get();
- if (ip=="127.0.0.1")
- continue;
-
- if (lip!="")
- lip=ip;
- if (hint!="")
- hint+=",";
- hint+=ip;
-
- }
-
- EDITOR_DEF("file_server/host",lip);
- EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,"file_server/host",PROPERTY_HINT_ENUM,hint));
EDITOR_DEF("file_server/password","");
}
diff --git a/tools/editor/groups_editor.cpp b/tools/editor/groups_editor.cpp
index 2e82854014..6840a8b205 100644
--- a/tools/editor/groups_editor.cpp
+++ b/tools/editor/groups_editor.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,151 +27,130 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "groups_editor.h"
-#include "scene/gui/box_container.h"
+#include "scene/gui/box_container.h"
#include "scene/gui/label.h"
+void GroupsEditor::_add_group(const String& p_group) {
-#include "print_string.h"
+ if (!node)
+ return;
-void GroupsEditor::_notification(int p_what) {
-
- if (p_what==NOTIFICATION_ENTER_TREE) {
- connect("confirmed", this,"_close");
- }
- if (p_what==NOTIFICATION_EXIT_TREE) {
- disconnect("confirmed", this,"_close");
- }
-}
+ String name = group_name->get_text();
+ if (name.strip_edges()=="")
+ return;
-void GroupsEditor::_close() {
-
- hide();
-
-}
-void GroupsEditor::_add() {
-
- if (!node)
+ if (node->is_in_group(name))
return;
-
- undo_redo->create_action("Add To Group");
- undo_redo->add_do_method(node,"add_to_group",group_name->get_text(),true);
- undo_redo->add_undo_method(node,"remove_from_group",group_name->get_text());
+ undo_redo->create_action("Add to Group");
+
+ undo_redo->add_do_method(node,"add_to_group",name,true);
undo_redo->add_do_method(this,"update_tree");
+ undo_redo->add_undo_method(node,"remove_from_group",name,get_text());
undo_redo->add_undo_method(this,"update_tree");
undo_redo->commit_action();
}
+void GroupsEditor::_remove_group(Object *p_item, int p_column, int p_id) {
-void GroupsEditor::_remove() {
-
- if (!tree->get_selected())
- return;
if (!node)
return;
- TreeItem *sel = tree->get_selected();
- if (!sel)
+ TreeItem *ti = p_item->cast_to<TreeItem>();
+ if (!ti)
return;
-
- node->remove_from_group( sel->get_text(0) );
- update_tree();
+
+ String name = ti->get_text(0);
+
+ undo_redo->create_action("Remove from Group");
+
+ undo_redo->add_do_method(node,"remove_from_group",name);
+ undo_redo->add_do_method(this,"update_tree");
+ undo_redo->add_undo_method(node,"add_to_group",name,true);
+ undo_redo->add_undo_method(this,"update_tree");
+
+ undo_redo->commit_action();
}
+struct _GroupInfoComparator {
+
+ bool operator()(const Node::GroupInfo& p_a, const Node::GroupInfo& p_b) const {
+ return p_a.name.operator String() < p_b.name.operator String();
+ }
+};
+
void GroupsEditor::update_tree() {
-
tree->clear();
-
+
if (!node)
return;
-
- List<GroupInfo> groups;
+
+ List<Node::GroupInfo> groups;
node->get_groups(&groups);
-
+ groups.sort_custom<_GroupInfoComparator>();
+
TreeItem *root=tree->create_item();
-
+
for(List<GroupInfo>::Element *E=groups.front();E;E=E->next()) {
-
- if (!E->get().persistent)
+
+ Node::GroupInfo gi = E->get();
+ if (!gi.persistent)
continue;
+
TreeItem *item=tree->create_item(root);
- item->set_text(0, E->get().name);
-
+ item->set_text(0, gi.name);
+ item->add_button(0, get_icon("Remove", "EditorIcons"), 0);
}
-
}
void GroupsEditor::set_current(Node* p_node) {
-
+
node=p_node;
update_tree();
-
}
void GroupsEditor::_bind_methods() {
-
- ObjectTypeDB::bind_method("_add",&GroupsEditor::_add);
- ObjectTypeDB::bind_method("_close",&GroupsEditor::_close);
- ObjectTypeDB::bind_method("_remove",&GroupsEditor::_remove);
+
+ ObjectTypeDB::bind_method("_add_group",&GroupsEditor::_add_group);
+ ObjectTypeDB::bind_method("_remove_group",&GroupsEditor::_remove_group);
ObjectTypeDB::bind_method("update_tree",&GroupsEditor::update_tree);
}
GroupsEditor::GroupsEditor() {
+ node=NULL;
+
set_title("Group Editor");
-
- Label * label = memnew( Label );
- label->set_pos( Point2( 8,11) );
- label->set_text("Groups:");
-
- add_child(label);
-
- group_name = memnew(LineEdit);
- group_name->set_anchor( MARGIN_RIGHT, ANCHOR_END );
- group_name->set_begin( Point2( 15,28) );
- group_name->set_end( Point2( 94,48 ) );
-
- add_child(group_name);
-
- tree = memnew( Tree );
- tree->set_anchor( MARGIN_RIGHT, ANCHOR_END );
- tree->set_anchor( MARGIN_BOTTOM, ANCHOR_END );
- tree->set_begin( Point2( 15,52) );
- tree->set_end( Point2( 94,42 ) );
- tree->set_hide_root(true);
- add_child(tree);
-
+
+ VBoxContainer *vbc = memnew( VBoxContainer );
+ add_child(vbc);
+ set_child_rect(vbc);
+
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ vbc->add_margin_child("Group", hbc);
+
+ group_name = memnew( LineEdit );
+ group_name->set_h_size_flags(SIZE_EXPAND_FILL);
+ hbc->add_child(group_name);
+ group_name->connect("text_entered",this,"_add_group");
+
add = memnew( Button );
- add->set_anchor( MARGIN_LEFT, ANCHOR_END );
- add->set_anchor( MARGIN_RIGHT, ANCHOR_END );
- add->set_begin( Point2( 90, 28 ) );
- add->set_end( Point2( 15, 48 ) );
add->set_text("Add");
-
- add_child(add);
-
- remove = memnew( Button );
- remove->set_anchor( MARGIN_LEFT, ANCHOR_END );
- remove->set_anchor( MARGIN_RIGHT, ANCHOR_END );
- remove->set_begin( Point2( 90, 52 ) );
- remove->set_end( Point2( 15, 72 ) );
- remove->set_text("Remove");
-
- add_child(remove);
+ hbc->add_child(add);
+ add->connect("pressed", this,"_add_group", varray(String()));
- get_ok()->set_text("Close");
-
- add->connect("pressed", this,"_add");
- remove->connect("pressed", this,"_remove");
+ tree = memnew( Tree );
+ tree->set_hide_root(true);
+ tree->set_v_size_flags(SIZE_EXPAND_FILL);
+ vbc->add_margin_child("Node Group(s)", tree, true);
+ tree->connect("button_pressed",this,"_remove_group");
-
- node=NULL;
+ get_ok()->set_text("Close");
}
-
GroupsEditor::~GroupsEditor()
{
}
diff --git a/tools/editor/groups_editor.h b/tools/editor/groups_editor.h
index 09883a150f..b5bccb2766 100644
--- a/tools/editor/groups_editor.h
+++ b/tools/editor/groups_editor.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,42 +29,42 @@
#ifndef GROUPS_EDITOR_H
#define GROUPS_EDITOR_H
-
#include "scene/gui/dialogs.h"
#include "scene/gui/button.h"
#include "scene/gui/tree.h"
#include "scene/gui/line_edit.h"
#include "undo_redo.h"
+
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
-class GroupsEditor : public ConfirmationDialog {
-
- OBJ_TYPE( GroupsEditor, ConfirmationDialog );
-
+
+class GroupsEditor : public AcceptDialog {
+
+ OBJ_TYPE(GroupsEditor,AcceptDialog);
+
+ Node *node;
+
LineEdit *group_name;
- Tree *tree;
Button *add;
- Button *remove;
- Node *node;
+ Tree *tree;
+
UndoRedo *undo_redo;
-
+
void update_tree();
- void _add();
- void _remove();
+ void _add_group(const String& p_group="");
+ void _remove_group(Object *p_item, int p_column, int p_id);
void _close();
-
protected:
-
- void _notification(int p_what);
- static void _bind_methods();
+
+ static void _bind_methods();
public:
-
+
void set_undo_redo(UndoRedo *p_undoredo) { undo_redo=p_undoredo; }
void set_current(Node* p_node);
-
+
GroupsEditor();
~GroupsEditor();
-
};
+
#endif
diff --git a/tools/editor/icons/SCsub b/tools/editor/icons/SCsub
index aea053d22b..addf6879a2 100644
--- a/tools/editor/icons/SCsub
+++ b/tools/editor/icons/SCsub
@@ -9,30 +9,30 @@ def make_editor_icons_action(target, source, env):
pixmaps = source
s = cStringIO.StringIO()
-
+
s.write("#include \"editor_icons.h\"\n\n")
s.write("#include \"scene/resources/theme.h\"\n\n")
for x in pixmaps:
-
+
x=str(x)
var_str=os.path.basename(x)[:-4]+"_png";
#print(var_str)
-
+
s.write("static const unsigned char "+ var_str +"[]={\n");
-
+
pngf=open(x,"rb");
-
+
b=pngf.read(1);
while(len(b)==1):
s.write(hex(ord(b)))
b=pngf.read(1);
if (len(b)==1):
s.write(",")
-
+
s.write("\n};\n\n\n");
pngf.close();
-
+
s.write("static Ref<ImageTexture> make_icon(const uint8_t* p_png) {\n")
s.write("\tRef<ImageTexture> texture( memnew( ImageTexture ) );\n")
s.write("\ttexture->create_from_image( Image(p_png),ImageTexture::FLAG_FILTER );\n")
@@ -42,14 +42,14 @@ def make_editor_icons_action(target, source, env):
s.write("void editor_register_icons(Ref<Theme> p_theme) {\n\n")
for x in pixmaps:
-
+
x=os.path.basename(str(x))
type=x[5:-4].title().replace("_","");
var_str=x[:-4]+"_png";
s.write("\tp_theme->set_icon(\""+type+"\",\"EditorIcons\",make_icon("+var_str+"));\n");
s.write("\n\n}\n\n");
-
+
f = open(dst,"wb")
f.write(s.getvalue())
f.close()
@@ -63,4 +63,3 @@ env.Alias('editor_icons',[env.MakeEditorIconsBuilder('#tools/editor/editor_icons
env.tool_sources.append("#tools/editor/editor_icons.cpp")
Export('env')
-
diff --git a/tools/editor/icons/icon_add_track.png b/tools/editor/icons/icon_add_track.png
index 3862597828..6a90950173 100644
--- a/tools/editor/icons/icon_add_track.png
+++ b/tools/editor/icons/icon_add_track.png
Binary files differ
diff --git a/tools/editor/icons/icon_anchor.png b/tools/editor/icons/icon_anchor.png
new file mode 100644
index 0000000000..1f9f9fa139
--- /dev/null
+++ b/tools/editor/icons/icon_anchor.png
Binary files differ
diff --git a/tools/editor/icons/icon_audio_stream_opus.png b/tools/editor/icons/icon_audio_stream_opus.png
new file mode 100644
index 0000000000..69b0c83b4d
--- /dev/null
+++ b/tools/editor/icons/icon_audio_stream_opus.png
Binary files differ
diff --git a/tools/editor/icons/icon_back.png b/tools/editor/icons/icon_back.png
index d60e3b2640..f7e507d92b 100644
--- a/tools/editor/icons/icon_back.png
+++ b/tools/editor/icons/icon_back.png
Binary files differ
diff --git a/tools/editor/icons/icon_class_list.png b/tools/editor/icons/icon_class_list.png
new file mode 100644
index 0000000000..fb756c0fe1
--- /dev/null
+++ b/tools/editor/icons/icon_class_list.png
Binary files differ
diff --git a/tools/editor/icons/icon_console.png b/tools/editor/icons/icon_console.png
new file mode 100644
index 0000000000..7dc7407ef7
--- /dev/null
+++ b/tools/editor/icons/icon_console.png
Binary files differ
diff --git a/tools/editor/icons/icon_control_align_bottom_center.png b/tools/editor/icons/icon_control_align_bottom_center.png
new file mode 100644
index 0000000000..5ce9fe5c1c
--- /dev/null
+++ b/tools/editor/icons/icon_control_align_bottom_center.png
Binary files differ
diff --git a/tools/editor/icons/icon_control_align_bottom_left.png b/tools/editor/icons/icon_control_align_bottom_left.png
new file mode 100644
index 0000000000..6c5129bf95
--- /dev/null
+++ b/tools/editor/icons/icon_control_align_bottom_left.png
Binary files differ
diff --git a/tools/editor/icons/icon_control_align_bottom_right.png b/tools/editor/icons/icon_control_align_bottom_right.png
new file mode 100644
index 0000000000..8857f4e940
--- /dev/null
+++ b/tools/editor/icons/icon_control_align_bottom_right.png
Binary files differ
diff --git a/tools/editor/icons/icon_control_align_bottom_wide.png b/tools/editor/icons/icon_control_align_bottom_wide.png
new file mode 100644
index 0000000000..56f009b8e4
--- /dev/null
+++ b/tools/editor/icons/icon_control_align_bottom_wide.png
Binary files differ
diff --git a/tools/editor/icons/icon_control_align_center.png b/tools/editor/icons/icon_control_align_center.png
new file mode 100644
index 0000000000..acd42525fa
--- /dev/null
+++ b/tools/editor/icons/icon_control_align_center.png
Binary files differ
diff --git a/tools/editor/icons/icon_control_align_center_left.png b/tools/editor/icons/icon_control_align_center_left.png
new file mode 100644
index 0000000000..997074b097
--- /dev/null
+++ b/tools/editor/icons/icon_control_align_center_left.png
Binary files differ
diff --git a/tools/editor/icons/icon_control_align_center_right.png b/tools/editor/icons/icon_control_align_center_right.png
new file mode 100644
index 0000000000..b5cae63f7a
--- /dev/null
+++ b/tools/editor/icons/icon_control_align_center_right.png
Binary files differ
diff --git a/tools/editor/icons/icon_control_align_left_center.png b/tools/editor/icons/icon_control_align_left_center.png
new file mode 100644
index 0000000000..7bb4dfb567
--- /dev/null
+++ b/tools/editor/icons/icon_control_align_left_center.png
Binary files differ
diff --git a/tools/editor/icons/icon_control_align_left_wide.png b/tools/editor/icons/icon_control_align_left_wide.png
new file mode 100644
index 0000000000..1b0a6cff95
--- /dev/null
+++ b/tools/editor/icons/icon_control_align_left_wide.png
Binary files differ
diff --git a/tools/editor/icons/icon_control_align_right_center.png b/tools/editor/icons/icon_control_align_right_center.png
new file mode 100644
index 0000000000..cf12d44c6a
--- /dev/null
+++ b/tools/editor/icons/icon_control_align_right_center.png
Binary files differ
diff --git a/tools/editor/icons/icon_control_align_right_wide.png b/tools/editor/icons/icon_control_align_right_wide.png
new file mode 100644
index 0000000000..406ed25aed
--- /dev/null
+++ b/tools/editor/icons/icon_control_align_right_wide.png
Binary files differ
diff --git a/tools/editor/icons/icon_control_align_top_center.png b/tools/editor/icons/icon_control_align_top_center.png
new file mode 100644
index 0000000000..da7ede984a
--- /dev/null
+++ b/tools/editor/icons/icon_control_align_top_center.png
Binary files differ
diff --git a/tools/editor/icons/icon_control_align_top_left.png b/tools/editor/icons/icon_control_align_top_left.png
new file mode 100644
index 0000000000..84a224fbbe
--- /dev/null
+++ b/tools/editor/icons/icon_control_align_top_left.png
Binary files differ
diff --git a/tools/editor/icons/icon_control_align_top_right.png b/tools/editor/icons/icon_control_align_top_right.png
new file mode 100644
index 0000000000..3b58eead9c
--- /dev/null
+++ b/tools/editor/icons/icon_control_align_top_right.png
Binary files differ
diff --git a/tools/editor/icons/icon_control_align_top_wide.png b/tools/editor/icons/icon_control_align_top_wide.png
new file mode 100644
index 0000000000..869ae26134
--- /dev/null
+++ b/tools/editor/icons/icon_control_align_top_wide.png
Binary files differ
diff --git a/tools/editor/icons/icon_control_align_wide.png b/tools/editor/icons/icon_control_align_wide.png
new file mode 100644
index 0000000000..57a2933b25
--- /dev/null
+++ b/tools/editor/icons/icon_control_align_wide.png
Binary files differ
diff --git a/tools/editor/icons/icon_control_hcenter_wide.png b/tools/editor/icons/icon_control_hcenter_wide.png
new file mode 100644
index 0000000000..739ea5baeb
--- /dev/null
+++ b/tools/editor/icons/icon_control_hcenter_wide.png
Binary files differ
diff --git a/tools/editor/icons/icon_control_vcenter_wide.png b/tools/editor/icons/icon_control_vcenter_wide.png
new file mode 100644
index 0000000000..44cbb8f344
--- /dev/null
+++ b/tools/editor/icons/icon_control_vcenter_wide.png
Binary files differ
diff --git a/tools/editor/icons/icon_create_new_scene_from.png b/tools/editor/icons/icon_create_new_scene_from.png
new file mode 100644
index 0000000000..e747c4f59f
--- /dev/null
+++ b/tools/editor/icons/icon_create_new_scene_from.png
Binary files differ
diff --git a/tools/editor/icons/icon_debug.png b/tools/editor/icons/icon_debug.png
new file mode 100644
index 0000000000..03b98aa9e4
--- /dev/null
+++ b/tools/editor/icons/icon_debug.png
Binary files differ
diff --git a/tools/editor/icons/icon_edit_pivot.png b/tools/editor/icons/icon_edit_pivot.png
new file mode 100644
index 0000000000..d68f7bbf25
--- /dev/null
+++ b/tools/editor/icons/icon_edit_pivot.png
Binary files differ
diff --git a/tools/editor/icons/icon_file_list.png b/tools/editor/icons/icon_file_list.png
index e5e9213e61..ab790a85a5 100644
--- a/tools/editor/icons/icon_file_list.png
+++ b/tools/editor/icons/icon_file_list.png
Binary files differ
diff --git a/tools/editor/icons/icon_filesystem.png b/tools/editor/icons/icon_filesystem.png
new file mode 100644
index 0000000000..6841f9a792
--- /dev/null
+++ b/tools/editor/icons/icon_filesystem.png
Binary files differ
diff --git a/tools/editor/icons/icon_forward.png b/tools/editor/icons/icon_forward.png
index ca6838ae9e..14e8bc9a5a 100644
--- a/tools/editor/icons/icon_forward.png
+++ b/tools/editor/icons/icon_forward.png
Binary files differ
diff --git a/tools/editor/icons/icon_godot.png b/tools/editor/icons/icon_godot.png
new file mode 100644
index 0000000000..e80820fc10
--- /dev/null
+++ b/tools/editor/icons/icon_godot.png
Binary files differ
diff --git a/tools/editor/icons/icon_grid.png b/tools/editor/icons/icon_grid.png
new file mode 100644
index 0000000000..dcdd86c9b5
--- /dev/null
+++ b/tools/editor/icons/icon_grid.png
Binary files differ
diff --git a/tools/editor/icons/icon_help.png b/tools/editor/icons/icon_help.png
index 3f4f8453a7..d2085589ae 100644
--- a/tools/editor/icons/icon_help.png
+++ b/tools/editor/icons/icon_help.png
Binary files differ
diff --git a/tools/editor/icons/icon_history.png b/tools/editor/icons/icon_history.png
new file mode 100644
index 0000000000..5c306c3ac9
--- /dev/null
+++ b/tools/editor/icons/icon_history.png
Binary files differ
diff --git a/tools/editor/icons/icon_key_invalid.png b/tools/editor/icons/icon_key_invalid.png
new file mode 100644
index 0000000000..e8e6c87180
--- /dev/null
+++ b/tools/editor/icons/icon_key_invalid.png
Binary files differ
diff --git a/tools/editor/icons/icon_key_invalid_hover.png b/tools/editor/icons/icon_key_invalid_hover.png
new file mode 100644
index 0000000000..6f0396d96a
--- /dev/null
+++ b/tools/editor/icons/icon_key_invalid_hover.png
Binary files differ
diff --git a/tools/editor/icons/icon_list_select.png b/tools/editor/icons/icon_list_select.png
new file mode 100644
index 0000000000..cbe81d4328
--- /dev/null
+++ b/tools/editor/icons/icon_list_select.png
Binary files differ
diff --git a/tools/editor/icons/icon_live_debug.png b/tools/editor/icons/icon_live_debug.png
new file mode 100644
index 0000000000..ad55646b9a
--- /dev/null
+++ b/tools/editor/icons/icon_live_debug.png
Binary files differ
diff --git a/tools/editor/icons/icon_multi_edit.png b/tools/editor/icons/icon_multi_edit.png
new file mode 100644
index 0000000000..70faee3d6a
--- /dev/null
+++ b/tools/editor/icons/icon_multi_edit.png
Binary files differ
diff --git a/tools/editor/icons/icon_multi_node_edit.png b/tools/editor/icons/icon_multi_node_edit.png
new file mode 100644
index 0000000000..357c062cbd
--- /dev/null
+++ b/tools/editor/icons/icon_multi_node_edit.png
Binary files differ
diff --git a/tools/editor/icons/icon_non_favorite.png b/tools/editor/icons/icon_non_favorite.png
new file mode 100644
index 0000000000..edd806fbe8
--- /dev/null
+++ b/tools/editor/icons/icon_non_favorite.png
Binary files differ
diff --git a/tools/editor/icons/icon_patch_9_frame.png b/tools/editor/icons/icon_patch_9_frame.png
new file mode 100644
index 0000000000..c8f38fa61a
--- /dev/null
+++ b/tools/editor/icons/icon_patch_9_frame.png
Binary files differ
diff --git a/tools/editor/icons/icon_pin.png b/tools/editor/icons/icon_pin.png
index 037352137d..4862ee8f71 100644
--- a/tools/editor/icons/icon_pin.png
+++ b/tools/editor/icons/icon_pin.png
Binary files differ
diff --git a/tools/editor/icons/icon_region_edit.png b/tools/editor/icons/icon_region_edit.png
new file mode 100644
index 0000000000..824607f2cc
--- /dev/null
+++ b/tools/editor/icons/icon_region_edit.png
Binary files differ
diff --git a/tools/editor/icons/icon_remote.png b/tools/editor/icons/icon_remote.png
new file mode 100644
index 0000000000..792d958a46
--- /dev/null
+++ b/tools/editor/icons/icon_remote.png
Binary files differ
diff --git a/tools/editor/icons/icon_script_list.png b/tools/editor/icons/icon_script_list.png
new file mode 100644
index 0000000000..cdea1e161e
--- /dev/null
+++ b/tools/editor/icons/icon_script_list.png
Binary files differ
diff --git a/tools/editor/import_settings.cpp b/tools/editor/import_settings.cpp
index 36d7828be0..2bbd1e3805 100644
--- a/tools/editor/import_settings.cpp
+++ b/tools/editor/import_settings.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/import_settings.h b/tools/editor/import_settings.h
index 31237dd8cf..5a383a1a1a 100644
--- a/tools/editor/import_settings.h
+++ b/tools/editor/import_settings.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/inspector_dock.cpp b/tools/editor/inspector_dock.cpp
new file mode 100644
index 0000000000..57d19c3ec8
--- /dev/null
+++ b/tools/editor/inspector_dock.cpp
@@ -0,0 +1,22 @@
+#include "inspector_dock.h"
+
+#if 0
+void InspectorDock::_go_next() {
+
+
+}
+
+void InspectorDock::_go_prev() {
+
+
+}
+
+void InspectorDock::_bind_methods() {
+
+}
+
+InspectorDock::InspectorDock() {
+
+
+}
+#endif
diff --git a/tools/editor/inspector_dock.h b/tools/editor/inspector_dock.h
new file mode 100644
index 0000000000..90f043aba8
--- /dev/null
+++ b/tools/editor/inspector_dock.h
@@ -0,0 +1,35 @@
+#ifndef INSPECTOR_DOCK_H
+#define INSPECTOR_DOCK_H
+
+#include "scene/gui/box_container.h"
+#include "property_editor.h"
+
+
+//this is for now bundled in EditorNode, will be moved away here eventually
+
+#if 0
+class InspectorDock : public VBoxContainer
+{
+ OBJ_TYPE(InspectorDock,VBoxContainer);
+
+ PropertyEditor *property_editor;
+
+ EditorHistory editor_history;
+
+ void _go_next();
+ void _go_prev();
+
+protected:
+
+ static void _bind_methods();
+public:
+
+ EditorHistory &get_editor_history();
+
+ PropertyEditor *get_property_editor();
+
+ InspectorDock();
+};
+
+#endif
+#endif // INSPECTOR_DOCK_H
diff --git a/tools/editor/io_plugins/SCsub b/tools/editor/io_plugins/SCsub
index b525fb3f75..363a2ce4c0 100644
--- a/tools/editor/io_plugins/SCsub
+++ b/tools/editor/io_plugins/SCsub
@@ -1,7 +1,3 @@
Import('env')
Export('env')
env.add_source_files(env.tool_sources,"*.cpp")
-
-
-
-
diff --git a/tools/editor/io_plugins/editor_atlas.cpp b/tools/editor/io_plugins/editor_atlas.cpp
index 4a260a9a6f..f894e7e8b2 100644
--- a/tools/editor/io_plugins/editor_atlas.cpp
+++ b/tools/editor/io_plugins/editor_atlas.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,7 +27,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "editor_atlas.h"
-
+#include "print_string.h"
struct _EditorAtlasWorkRect {
@@ -83,6 +83,7 @@ void EditorAtlas::fit(const Vector<Size2i>& p_rects,Vector<Point2i>& r_result, S
//place them
int ofs=0;
int limit_h=0;
+
for(int j=0;j<wrects.size();j++) {
@@ -100,6 +101,9 @@ void EditorAtlas::fit(const Vector<Size2i>& p_rects,Vector<Point2i>& r_result, S
wrects[j].p.x=ofs;
wrects[j].p.y=from_y;
+
+
+
int end_h = from_y+wrects[j].s.height;
int end_w = ofs+wrects[j].s.width;
if (ofs==0)
@@ -116,7 +120,7 @@ void EditorAtlas::fit(const Vector<Size2i>& p_rects,Vector<Point2i>& r_result, S
if (end_w > max_w)
max_w=end_w;
- if (ofs==0 || end_h>limit_h ) //while h limit not reched, keep stacking
+ //if (ofs==0 || end_h>limit_h ) //while h limit not reched, keep stacking
ofs+=wrects[j].s.width;
}
@@ -136,8 +140,8 @@ void EditorAtlas::fit(const Vector<Size2i>& p_rects,Vector<Point2i>& r_result, S
for(int i=0;i<results.size();i++) {
- float h = nearest_power_of_2(results[i].max_h);
- float w = nearest_power_of_2(results[i].max_w);
+ float h = results[i].max_h;
+ float w = results[i].max_w;
float aspect = h>w ? h/w : w/h;
if (aspect < best_aspect) {
best=i;
diff --git a/tools/editor/io_plugins/editor_atlas.h b/tools/editor/io_plugins/editor_atlas.h
index 716faff0c6..0135e76622 100644
--- a/tools/editor/io_plugins/editor_atlas.h
+++ b/tools/editor/io_plugins/editor_atlas.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/io_plugins/editor_export_scene.cpp b/tools/editor/io_plugins/editor_export_scene.cpp
new file mode 100644
index 0000000000..dff41a59ed
--- /dev/null
+++ b/tools/editor/io_plugins/editor_export_scene.cpp
@@ -0,0 +1,112 @@
+#include "editor_export_scene.h"
+#include "io/resource_loader.h"
+#include "io/resource_saver.h"
+#include "os/dir_access.h"
+#include "os/file_access.h"
+#include "tools/editor/editor_settings.h"
+#include "scene/resources/packed_scene.h"
+#include "globals.h"
+
+Vector<uint8_t> EditorSceneExportPlugin::custom_export(String& p_path,const Ref<EditorExportPlatform> &p_platform) {
+
+ if (!EditorImportExport::get_singleton()->get_convert_text_scenes()) {
+ return Vector<uint8_t>();
+ }
+
+
+ String extension = p_path.extension();
+
+ //step 1 check if scene
+
+ if (extension=="xml" || extension=="xres") {
+
+ String type = ResourceLoader::get_resource_type(p_path);
+
+ if (type!="PackedScene")
+ return Vector<uint8_t>();
+
+ } else if (extension!="tscn" && extension!="xscn") {
+ return Vector<uint8_t>();
+ }
+
+ //step 2 check if cached
+
+ uint64_t sd=0;
+ String smd5;
+ String gp = Globals::get_singleton()->globalize_path(p_path);
+ String md5=gp.md5_text();
+ String tmp_path = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp/");
+
+ bool valid=false;
+ {
+ //if existing, make sure it's valid
+ FileAccessRef f = FileAccess::open(tmp_path+"scnexp-"+md5+".txt",FileAccess::READ);
+ if (f) {
+
+ uint64_t d = f->get_line().strip_edges().to_int64();
+ sd = FileAccess::get_modified_time(p_path);
+
+ if (d==sd) {
+ valid=true;
+ } else {
+ String cmd5 = f->get_line().strip_edges();
+ smd5 = FileAccess::get_md5(p_path);
+ if (cmd5==smd5) {
+ valid=true;
+ }
+ }
+
+
+ }
+ }
+
+ if (!valid) {
+ //cache failed, convert
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+
+ String copy = p_path+".convert."+extension;
+
+ // a copy will allow loading the internal resources without conflicting with opened scenes
+ da->copy(p_path,copy);
+
+ //@todo for tscn use something more efficient
+
+ Ref<PackedScene> copyres = ResourceLoader::load(copy,"PackedScene");
+
+ da->remove(copy);
+
+ memdelete(da);
+
+ ERR_FAIL_COND_V(!copyres.is_valid(),Vector<uint8_t>());
+
+ Error err = ResourceSaver::save(tmp_path+"scnexp-"+md5+".scn",copyres);
+
+ copyres=Ref<PackedScene>();
+
+ ERR_FAIL_COND_V(err!=OK,Vector<uint8_t>());
+
+ FileAccessRef f = FileAccess::open(tmp_path+"scnexp-"+md5+".txt",FileAccess::WRITE);
+
+ if (sd==0)
+ sd = FileAccess::get_modified_time(p_path);
+ if (smd5==String())
+ smd5 = FileAccess::get_md5(p_path);
+
+ f->store_line(String::num(sd));
+ f->store_line(smd5);
+ f->store_line(gp); //source path for reference
+ }
+
+
+ Vector<uint8_t> ret = FileAccess::get_file_as_array(tmp_path+"scnexp-"+md5+".scn");
+
+ p_path+=".converted.scn";
+
+ return ret;
+
+}
+
+
+EditorSceneExportPlugin::EditorSceneExportPlugin()
+{
+}
diff --git a/tools/editor/io_plugins/editor_export_scene.h b/tools/editor/io_plugins/editor_export_scene.h
new file mode 100644
index 0000000000..134da6c234
--- /dev/null
+++ b/tools/editor/io_plugins/editor_export_scene.h
@@ -0,0 +1,16 @@
+#ifndef EDITOR_EXPORT_SCENE_H
+#define EDITOR_EXPORT_SCENE_H
+
+#include "tools/editor/editor_import_export.h"
+
+
+class EditorSceneExportPlugin : public EditorExportPlugin {
+ OBJ_TYPE( EditorSceneExportPlugin, EditorExportPlugin );
+public:
+
+ virtual Vector<uint8_t> custom_export(String& p_path,const Ref<EditorExportPlatform> &p_platform);
+
+ EditorSceneExportPlugin();
+};
+
+#endif // EDITOR_EXPORT_SCENE_H
diff --git a/tools/editor/io_plugins/editor_font_import_plugin.cpp b/tools/editor/io_plugins/editor_font_import_plugin.cpp
index 10a3877529..9b4ca246e7 100644
--- a/tools/editor/io_plugins/editor_font_import_plugin.cpp
+++ b/tools/editor/io_plugins/editor_font_import_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -520,6 +520,10 @@ class EditorFontImportDialog : public ConfirmationDialog {
return;
}
+ if (dest->get_line_edit()->get_text().get_file()==".fnt") {
+ dest->get_line_edit()->set_text(dest->get_line_edit()->get_text().get_base_dir() + "/" + source->get_line_edit()->get_text().get_file().basename() + ".fnt" );
+ }
+
Ref<ResourceImportMetadata> rimd = get_rimd();
if (rimd.is_null()) {
@@ -617,6 +621,7 @@ public:
source->get_file_dialog()->set_mode(EditorFileDialog::MODE_OPEN_FILE);
source->get_file_dialog()->add_filter("*.ttf;TrueType");
source->get_file_dialog()->add_filter("*.otf;OpenType");
+ source->get_file_dialog()->add_filter("*.fnt;BMFont");
source->get_line_edit()->connect("text_entered",this,"_src_changed");
vbl->add_margin_child("Source Font:",source);
@@ -872,10 +877,31 @@ static unsigned char get_SDF_radial(
Ref<Font> EditorFontImportPlugin::generate_font(const Ref<ResourceImportMetadata>& p_from, const String &p_existing) {
+
+
Ref<ResourceImportMetadata> from = p_from;
ERR_FAIL_COND_V(from->get_source_count()!=1,Ref<Font>());
String src_path = EditorImportPlugin::expand_source_path(from->get_source_path(0));
+
+ if (src_path.extension().to_lower()=="fnt") {
+
+ if (ResourceLoader::load(src_path).is_valid()) {
+ EditorNode::get_singleton()->show_warning("Path: "+src_path+"\nIs a Godot font file, please supply a BMFont type file instead.");
+ return Ref<Font>();
+ }
+
+ Ref<Font> font;
+ font.instance();
+ Error err = font->create_from_fnt(src_path);
+ if (err) {
+ EditorNode::get_singleton()->show_warning("Path: "+src_path+"\nFailed opening as BMFont file.");
+ return Ref<Font>();
+ }
+
+ return font;
+ }
+
int size = from->get_option("font/size");
#ifdef FREETYPE_ENABLED
diff --git a/tools/editor/io_plugins/editor_font_import_plugin.h b/tools/editor/io_plugins/editor_font_import_plugin.h
index 451f01080e..814897c5f0 100644
--- a/tools/editor/io_plugins/editor_font_import_plugin.h
+++ b/tools/editor/io_plugins/editor_font_import_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/io_plugins/editor_import_collada.cpp b/tools/editor/io_plugins/editor_import_collada.cpp
index d510333a32..7de9d978f2 100644
--- a/tools/editor/io_plugins/editor_import_collada.cpp
+++ b/tools/editor/io_plugins/editor_import_collada.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -68,6 +68,7 @@ struct ColladaImport {
Map<String,NodeMap> node_map; //map from collada node to engine node
+ Map<String,String> node_name_map; //map from collada node to engine node
Map<String, Ref<Mesh> > mesh_cache;
Map<String, Ref<Curve3D> > curve_cache;
Map<String, Ref<Material> > material_cache;
@@ -124,6 +125,7 @@ Error ColladaImport::_populate_skeleton(Skeleton *p_skeleton,Collada::Node *p_no
nm.node=p_skeleton;
nm.bone = r_bone;
node_map[p_node->id]=nm;
+ node_name_map[p_node->name]=p_node->id;
skeleton_bone_map[p_skeleton][joint->sid]=r_bone;
@@ -345,6 +347,7 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Spatial *p_parent) {
NodeMap nm;
nm.node=node;
node_map[p_node->id]=nm;
+ node_name_map[p_node->name]=p_node->id;
Transform xf = p_node->default_transform;
xf = collada.fix_transform( xf ) * p_node->post_transform;
@@ -710,10 +713,126 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref<Mesh>& p_mesh,con
//find largest source..
+ /************************/
+ /* ADD WEIGHTS IF EXIST */
+ /************************/
+
+ Map<int,Vector<Collada::Vertex::Weight> > pre_weights;
+
+ bool has_weights=false;
+
+ if (skin_controller) {
+
+ const Collada::SkinControllerData::Source *weight_src=NULL;
+ int weight_ofs=0;
+
+ if (skin_controller->weights.sources.has("WEIGHT")) {
+
+ String weight_id = skin_controller->weights.sources["WEIGHT"].source;
+ weight_ofs = skin_controller->weights.sources["WEIGHT"].offset;
+ if (skin_controller->sources.has(weight_id)) {
+
+ weight_src = &skin_controller->sources[weight_id];
+
+ }
+ }
+
+ int joint_ofs=0;
+
+ if (skin_controller->weights.sources.has("JOINT")) {
+
+ joint_ofs = skin_controller->weights.sources["JOINT"].offset;
+ }
+
+ //should be OK, given this was pre-checked.
+
+ int index_ofs=0;
+ int wstride = skin_controller->weights.sources.size();
+ for(int w_i=0;w_i<skin_controller->weights.sets.size();w_i++) {
+
+ int amount = skin_controller->weights.sets[w_i];
+
+ Vector<Collada::Vertex::Weight> weights;
+
+ for (int a_i=0;a_i<amount;a_i++) {
+
+ Collada::Vertex::Weight w;
+
+ int read_from = index_ofs+a_i*wstride;
+ ERR_FAIL_INDEX_V(read_from+wstride-1,skin_controller->weights.indices.size(),ERR_INVALID_DATA);
+ int weight_index = skin_controller->weights.indices[read_from+weight_ofs];
+ ERR_FAIL_INDEX_V(weight_index,weight_src->array.size(),ERR_INVALID_DATA);
+
+ w.weight = weight_src->array[weight_index];
+
+ int bone_index = skin_controller->weights.indices[read_from+joint_ofs];
+ if (bone_index==-1)
+ continue; //ignore this weight (refers to bind shape)
+ ERR_FAIL_INDEX_V(bone_index,bone_remap.size(),ERR_INVALID_DATA);
+
+ w.bone_idx=bone_remap[bone_index];
+
+
+ weights.push_back(w);
+ }
+
+ /* FIX WEIGHTS */
+
+
+
+ weights.sort();
+
+ if (weights.size()>4) {
+ //cap to 4 and make weights add up 1
+ weights.resize(4);
+
+ }
+
+ //make sure weights allways add up to 1
+ float total=0;
+ for(int i=0;i<weights.size();i++)
+ total+=weights[i].weight;
+ if (total)
+ for(int i=0;i<weights.size();i++)
+ weights[i].weight/=total;
+
+ if (weights.size()==0 || total==0) { //if nothing, add a weight to bone 0
+ //no weights assigned
+ Collada::Vertex::Weight w;
+ w.bone_idx=0;
+ w.weight=1.0;
+ weights.clear();
+ weights.push_back(w);
+
+ }
+
+ pre_weights[w_i]=weights;
+
+ /*
+ for(Set<int>::Element *E=vertex_map[w_i].front();E;E=E->next()) {
+
+ int dst = E->get();
+ ERR_EXPLAIN("invalid vertex index in array");
+ ERR_FAIL_INDEX_V(dst,vertex_array.size(),ERR_INVALID_DATA);
+ vertex_array[dst].weights=weights;
+
+ }*/
+
+
+
+
+ index_ofs+=wstride*amount;
+
+ }
+
+ //vertices need to be localized
+ has_weights=true;
+
+ }
Set<Collada::Vertex> vertex_set; //vertex set will be the vertices
List<int> indices_list; //indices will be the indices
- Map<int,Set<int> > vertex_map; //map vertices (for setting skinning/morph)
+ //Map<int,Set<int> > vertex_map; //map vertices (for setting skinning/morph)
/**************************/
/* CREATE PRIMITIVE ARRAY */
@@ -753,11 +872,16 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref<Mesh>& p_mesh,con
if (!p_optimize)
vertex.uid=vertidx++;
+
+
int vertex_index=p.indices[src+vertex_ofs]; //used for index field (later used by controllers)
int vertex_pos = (vertex_src->stride?vertex_src->stride:3) * vertex_index;
ERR_FAIL_INDEX_V(vertex_pos,vertex_src->array.size(),ERR_INVALID_DATA);
vertex.vertex=Vector3(vertex_src->array[vertex_pos+0],vertex_src->array[vertex_pos+1],vertex_src->array[vertex_pos+2]);
+ if (pre_weights.has(vertex_index)) {
+ vertex.weights=pre_weights[vertex_index];
+ }
if (normal_src) {
@@ -836,9 +960,9 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref<Mesh>& p_mesh,con
vertex_set.insert(vertex);
}
- if (!vertex_map.has(vertex_index))
+ /* if (!vertex_map.has(vertex_index))
vertex_map[vertex_index]=Set<int>();
- vertex_map[vertex_index].insert(index); //should be outside..
+ vertex_map[vertex_index].insert(index); //should be outside..*/
//build triangles if needed
if (j==0)
prev2[0]=index;
@@ -874,120 +998,10 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref<Mesh>& p_mesh,con
vertex_array[F->get().idx]=F->get();
}
- /************************/
- /* ADD WEIGHTS IF EXIST */
- /************************/
-
-
- bool has_weights=false;
-
- if (skin_controller) {
-
- const Collada::SkinControllerData::Source *weight_src=NULL;
- int weight_ofs=0;
-
- if (skin_controller->weights.sources.has("WEIGHT")) {
-
- String weight_id = skin_controller->weights.sources["WEIGHT"].source;
- weight_ofs = skin_controller->weights.sources["WEIGHT"].offset;
- if (skin_controller->sources.has(weight_id)) {
-
- weight_src = &skin_controller->sources[weight_id];
-
- }
- }
- int joint_ofs=0;
-
- if (skin_controller->weights.sources.has("JOINT")) {
-
- joint_ofs = skin_controller->weights.sources["JOINT"].offset;
- }
-
- //should be OK, given this was pre-checked.
-
- int index_ofs=0;
- int wstride = skin_controller->weights.sources.size();
- for(int w_i=0;w_i<skin_controller->weights.sets.size();w_i++) {
-
- int amount = skin_controller->weights.sets[w_i];
-
- if (vertex_map.has(w_i)) { //vertex may no longer be here, don't bother converting
-
- Vector<Collada::Vertex::Weight> weights;
-
- for (int a_i=0;a_i<amount;a_i++) {
-
- Collada::Vertex::Weight w;
-
- int read_from = index_ofs+a_i*wstride;
- ERR_FAIL_INDEX_V(read_from+wstride-1,skin_controller->weights.indices.size(),ERR_INVALID_DATA);
- int weight_index = skin_controller->weights.indices[read_from+weight_ofs];
- ERR_FAIL_INDEX_V(weight_index,weight_src->array.size(),ERR_INVALID_DATA);
-
- w.weight = weight_src->array[weight_index];
-
- int bone_index = skin_controller->weights.indices[read_from+joint_ofs];
- if (bone_index==-1)
- continue; //ignore this weight (refers to bind shape)
- ERR_FAIL_INDEX_V(bone_index,bone_remap.size(),ERR_INVALID_DATA);
-
- w.bone_idx=bone_remap[bone_index];
-
-
- weights.push_back(w);
- }
-
- /* FIX WEIGHTS */
-
-
-
- weights.sort();
-
- if (weights.size()>4) {
- //cap to 4 and make weights add up 1
- weights.resize(4);
-
- }
-
- //make sure weights allways add up to 1
- float total=0;
- for(int i=0;i<weights.size();i++)
- total+=weights[i].weight;
- if (total)
- for(int i=0;i<weights.size();i++)
- weights[i].weight/=total;
-
- if (weights.size()==0 || total==0) { //if nothing, add a weight to bone 0
- //no weights assigned
- Collada::Vertex::Weight w;
- w.bone_idx=0;
- w.weight=1.0;
- weights.clear();
- weights.push_back(w);
-
- }
-
-
- for(Set<int>::Element *E=vertex_map[w_i].front();E;E=E->next()) {
-
- int dst = E->get();
- ERR_EXPLAIN("invalid vertex index in array");
- ERR_FAIL_INDEX_V(dst,vertex_array.size(),ERR_INVALID_DATA);
- vertex_array[dst].weights=weights;
-
- }
-
- } else {
- //zzprint_line("no vertex found for index "+itos(w_i));
- }
-
- index_ofs+=wstride*amount;
-
- }
-
- //vertices need to be localized
+ if (has_weights) {
+ //if skeleton, localize
Transform local_xform = p_local_xform;
for(int i=0;i<vertex_array.size();i++) {
@@ -1000,11 +1014,9 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize,Ref<Mesh>& p_mesh,con
//vertex_array[i].tangent.normal*=-1.0;
}
}
-
- has_weights=true;
-
}
+
DVector<int> index_array;
index_array.resize(indices_list.size());
DVector<int>::Write index_arrayw = index_array.write();
@@ -1897,9 +1909,20 @@ void ColladaImport::create_animations(bool p_make_tracks_in_all_bones) {
Collada::AnimationTrack &at = collada.state.animation_tracks[i];
//print_line("CHANNEL: "+at.target+" PARAM: "+at.param);
+
+ String node;
+
if (!node_map.has(at.target)) {
- print_line("Coudlnt find node: "+at.target);
- continue;
+
+ if (node_name_map.has(at.target)) {
+
+ node=node_name_map[at.target];
+ } else {
+ print_line("Coudlnt find node: "+at.target);
+ continue;
+ }
+ } else {
+ node=at.target;
}
@@ -1908,8 +1931,9 @@ void ColladaImport::create_animations(bool p_make_tracks_in_all_bones) {
valid_animated_properties.push_back(i);
} else {
- node_map[at.target].anim_tracks.push_back(i);
- valid_animated_nodes.insert(at.target);
+
+ node_map[node].anim_tracks.push_back(i);
+ valid_animated_nodes.insert(node);
}
}
@@ -1925,6 +1949,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
Ref<Animation> animation = Ref<Animation>( memnew( Animation ));
+
if (p_clip==-1) {
//print_line("default");
@@ -1998,10 +2023,12 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
while(f<anim_length) {
base_snapshots.push_back(f);
+
f+=snapshot_interval;
if (f>=anim_length) {
base_snapshots.push_back(anim_length);
+
}
}
@@ -2010,11 +2037,17 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
bool tracks_found=false;
+
+
for(Set<String>::Element* E=valid_animated_nodes.front();E;E=E->next()) {
// take snapshots
- if (!collada.state.scene_map.has(E->get()))
+
+
+ if (!collada.state.scene_map.has(E->get())) {
+
continue;
+ }
NodeMap &nm = node_map[E->get()];
String path = scene->get_path_to(nm.node);
@@ -2030,7 +2063,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
Collada::Node *cn = collada.state.scene_map[E->get()];
if (cn->ignore_anim) {
- //print_line("warning, ignoring animation on node: "+path);
+
continue;
}
@@ -2049,20 +2082,23 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones
for(int i=0;i<at.keys.size();i++)
snapshots.push_back(at.keys[i].time);
- print_line("using anim snapshots");
}
for(int i=0;i<snapshots.size();i++) {
+
for(List<int>::Element *ET=nm.anim_tracks.front();ET;ET=ET->next()) {
//apply tracks
+
if (p_clip==-1) {
- if (track_filter.has(ET->get()))
+ if (track_filter.has(ET->get())) {
+
continue;
+ }
} else {
if (!track_filter.has(ET->get()))
diff --git a/tools/editor/io_plugins/editor_import_collada.h b/tools/editor/io_plugins/editor_import_collada.h
index 243cd043a0..de45dc38f4 100644
--- a/tools/editor/io_plugins/editor_import_collada.h
+++ b/tools/editor/io_plugins/editor_import_collada.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/io_plugins/editor_mesh_import_plugin.cpp b/tools/editor/io_plugins/editor_mesh_import_plugin.cpp
index 2139513025..b32ab8cb0b 100644
--- a/tools/editor/io_plugins/editor_mesh_import_plugin.cpp
+++ b/tools/editor/io_plugins/editor_mesh_import_plugin.cpp
@@ -128,7 +128,7 @@ class EditorMeshImportDialog : public ConfirmationDialog {
LineEdit *save_path;
EditorFileDialog *file_select;
EditorDirDialog *save_select;
- ConfirmationDialog *error_dialog;
+ AcceptDialog *error_dialog;
PropertyEditor *option_editor;
_EditorMeshImportOptions *options;
@@ -169,13 +169,12 @@ public:
void _browse_target() {
save_select->popup_centered_ratio();
-
}
-
void popup_import(const String& p_path) {
popup_centered(Size2(400,400));
+
if (p_path!="") {
Ref<ResourceImportMetadata> rimd = ResourceLoader::load_import_metadata(p_path);
@@ -199,14 +198,13 @@ public:
}
}
-
void _import() {
Vector<String> meshes = import_path->get_text().split(",");
-
if (meshes.size()==0) {
error_dialog->set_text("No meshes to import!");
- error_dialog->popup_centered(Size2(200,100));
+ error_dialog->popup_centered_minsize();
+ return;
}
for(int i=0;i<meshes.size();i++) {
@@ -229,19 +227,18 @@ public:
String dst = save_path->get_text();
if (dst=="") {
error_dialog->set_text("Save path is empty!");
- error_dialog->popup_centered(Size2(200,100));
+ error_dialog->popup_centered_minsize();
+ return;
}
dst = dst.plus_file(meshes[i].get_file().basename()+".msh");
- Error err = plugin->import(dst,imd);
+ plugin->import(dst,imd);
}
hide();
-
}
-
void _notification(int p_what) {
@@ -253,27 +250,24 @@ public:
static void _bind_methods() {
-
ObjectTypeDB::bind_method("_choose_files",&EditorMeshImportDialog::_choose_files);
ObjectTypeDB::bind_method("_choose_save_dir",&EditorMeshImportDialog::_choose_save_dir);
ObjectTypeDB::bind_method("_import",&EditorMeshImportDialog::_import);
ObjectTypeDB::bind_method("_browse",&EditorMeshImportDialog::_browse);
ObjectTypeDB::bind_method("_browse_target",&EditorMeshImportDialog::_browse_target);
- // ADD_SIGNAL( MethodInfo("imported",PropertyInfo(Variant::OBJECT,"scene")) );
}
EditorMeshImportDialog(EditorMeshImportPlugin *p_plugin) {
plugin=p_plugin;
-
set_title("Single Mesh Import");
+ set_hide_on_ok(false);
VBoxContainer *vbc = memnew( VBoxContainer );
add_child(vbc);
set_child_rect(vbc);
-
HBoxContainer *hbc = memnew( HBoxContainer );
vbc->add_margin_child("Source Mesh(es):",hbc);
@@ -300,28 +294,23 @@ public:
save_choose->connect("pressed", this,"_browse_target");
- file_select = memnew(EditorFileDialog);
+ file_select = memnew( EditorFileDialog );
file_select->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
- add_child(file_select);
file_select->set_mode(EditorFileDialog::MODE_OPEN_FILES);
- file_select->connect("files_selected", this,"_choose_files");
file_select->add_filter("*.obj ; Wavefront OBJ");
- save_select = memnew( EditorDirDialog );
- add_child(save_select);
+ add_child(file_select);
+ file_select->connect("files_selected", this,"_choose_files");
- // save_select->set_mode(EditorFileDialog::MODE_OPEN_DIR);
+ save_select = memnew( EditorDirDialog );
+ add_child(save_select);
save_select->connect("dir_selected", this,"_choose_save_dir");
get_ok()->connect("pressed", this,"_import");
get_ok()->set_text("Import");
-
- error_dialog = memnew ( ConfirmationDialog );
+ error_dialog = memnew( AcceptDialog );
add_child(error_dialog);
- error_dialog->get_ok()->set_text("Accept");
- // error_dialog->get_cancel()->hide();
- set_hide_on_ok(false);
options = memnew( _EditorMeshImportOptions );
option_editor = memnew( PropertyEditor );
diff --git a/tools/editor/io_plugins/editor_sample_import_plugin.cpp b/tools/editor/io_plugins/editor_sample_import_plugin.cpp
index 9491f957c3..b81c88c817 100644
--- a/tools/editor/io_plugins/editor_sample_import_plugin.cpp
+++ b/tools/editor/io_plugins/editor_sample_import_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,6 +35,7 @@
#include "io/resource_saver.h"
#include "os/file_access.h"
#include "io/marshalls.h"
+#include "tools/editor/editor_settings.h"
class _EditorSampleImportOptions : public Object {
@@ -156,7 +157,7 @@ public:
edit_normalize=true;
edit_loop=false;
- compress_mode=COMPRESS_MODE_DISABLED;
+ compress_mode=COMPRESS_MODE_RAM;
compress_bitrate=COMPRESS_128;
}
@@ -580,8 +581,7 @@ Error EditorSampleImportPlugin::import(const String& p_path, const Ref<ResourceI
int compression = from->get_option("compress/mode");
bool force_mono = from->get_option("force/mono");
- if (compression==_EditorSampleImportOptions::COMPRESS_MODE_RAM)
- force_mono=true;
+
if (force_mono && chans==2) {
@@ -608,9 +608,47 @@ Error EditorSampleImportPlugin::import(const String& p_path, const Ref<ResourceI
if ( compression == _EditorSampleImportOptions::COMPRESS_MODE_RAM) {
dst_format=Sample::FORMAT_IMA_ADPCM;
+ if (chans==1) {
+ _compress_ima_adpcm(data,dst_data);
+ } else {
+
+ print_line("INTERLEAAVE!");
+
+
+
+ //byte interleave
+ Vector<float> left;
+ Vector<float> right;
+
+ int tlen = data.size()/2;
+ left.resize(tlen);
+ right.resize(tlen);
+
+ for(int i=0;i<tlen;i++) {
+ left[i]=data[i*2+0];
+ right[i]=data[i*2+1];
+ }
+
+ DVector<uint8_t> bleft;
+ DVector<uint8_t> bright;
- _compress_ima_adpcm(data,dst_data);
- print_line("compressing ima-adpcm, resulting buffersize is "+itos(dst_data.size())+" from "+itos(data.size()));
+ _compress_ima_adpcm(left,bleft);
+ _compress_ima_adpcm(right,bright);
+
+ int dl = bleft.size();
+ dst_data.resize( dl *2 );
+
+ DVector<uint8_t>::Write w=dst_data.write();
+ DVector<uint8_t>::Read rl=bleft.read();
+ DVector<uint8_t>::Read rr=bright.read();
+
+ for(int i=0;i<dl;i++) {
+ w[i*2+0]=rl[i];
+ w[i*2+1]=rr[i];
+ }
+ }
+
+// print_line("compressing ima-adpcm, resulting buffersize is "+itos(dst_data.size())+" from "+itos(data.size()));
} else {
@@ -710,7 +748,7 @@ void EditorSampleImportPlugin::_compress_ima_adpcm(const Vector<float>& p_data,D
*(out++) =0;
for (i=0;i<datalen;i++) {
- int step,diff,vpdiff,signed_nibble,p,mask;
+ int step,diff,vpdiff,mask;
uint8_t nibble;
int16_t xm_sample;
@@ -781,9 +819,54 @@ void EditorSampleImportPlugin::_compress_ima_adpcm(const Vector<float>& p_data,D
}
+
+EditorSampleImportPlugin* EditorSampleImportPlugin::singleton=NULL;
+
+
+
EditorSampleImportPlugin::EditorSampleImportPlugin(EditorNode* p_editor) {
+ singleton=this;
dialog = memnew( EditorSampleImportDialog(this));
p_editor->get_gui_base()->add_child(dialog);
}
+Vector<uint8_t> EditorSampleExportPlugin::custom_export(String& p_path,const Ref<EditorExportPlatform> &p_platform) {
+
+
+
+ if (EditorImportExport::get_singleton()->sample_get_action()==EditorImportExport::SAMPLE_ACTION_NONE || p_path.extension().to_lower()!="wav") {
+
+ return Vector<uint8_t>();
+ }
+
+ Ref<ResourceImportMetadata> imd = memnew( ResourceImportMetadata );
+
+ imd->add_source(EditorImportPlugin::validate_source_path(p_path));
+
+ imd->set_option("force/8_bit",false);
+ imd->set_option("force/mono",false);
+ imd->set_option("force/max_rate",true);
+ imd->set_option("force/max_rate_hz",EditorImportExport::get_singleton()->sample_get_max_hz());
+ imd->set_option("edit/trim",EditorImportExport::get_singleton()->sample_get_trim());
+ imd->set_option("edit/normalize",false);
+ imd->set_option("edit/loop",false);
+ imd->set_option("compress/mode",1);
+
+ String savepath = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp/smpconv.smp");
+ Error err = EditorSampleImportPlugin::singleton->import(savepath,imd);
+
+
+ ERR_FAIL_COND_V(err!=OK,Vector<uint8_t>());
+
+ p_path=p_path.basename()+".converted.smp";
+ return FileAccess::get_file_as_array(savepath);
+
+}
+
+
+EditorSampleExportPlugin::EditorSampleExportPlugin() {
+
+}
+
+
diff --git a/tools/editor/io_plugins/editor_sample_import_plugin.h b/tools/editor/io_plugins/editor_sample_import_plugin.h
index 03a4d38ab3..b31562af76 100644
--- a/tools/editor/io_plugins/editor_sample_import_plugin.h
+++ b/tools/editor/io_plugins/editor_sample_import_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -43,6 +43,8 @@ class EditorSampleImportPlugin : public EditorImportPlugin {
void _compress_ima_adpcm(const Vector<float>& p_data,DVector<uint8_t>& dst_data);
public:
+ static EditorSampleImportPlugin *singleton;
+
virtual String get_name() const;
virtual String get_visible_name() const;
virtual void import_dialog(const String& p_from="");
@@ -52,4 +54,16 @@ public:
EditorSampleImportPlugin(EditorNode* p_editor);
};
+class EditorSampleExportPlugin : public EditorExportPlugin {
+
+ OBJ_TYPE( EditorSampleExportPlugin, EditorExportPlugin);
+
+
+public:
+
+ virtual Vector<uint8_t> custom_export(String& p_path,const Ref<EditorExportPlatform> &p_platform);
+
+ EditorSampleExportPlugin();
+};
+
#endif // EDITOR_SAMPLE_IMPORT_PLUGIN_H
diff --git a/tools/editor/io_plugins/editor_scene_import_plugin.cpp b/tools/editor/io_plugins/editor_scene_import_plugin.cpp
index 99dcf4ed28..a3b6827cd4 100644
--- a/tools/editor/io_plugins/editor_scene_import_plugin.cpp
+++ b/tools/editor/io_plugins/editor_scene_import_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -1814,8 +1814,8 @@ Node* EditorSceneImportPlugin::_fix_node(Node *p_node,Node *p_root,Map<Ref<Mesh>
for(int i=0;i<portal_points.size()-1;i++) {
- float a = portal_points[i].atan2();
- float b = portal_points[i+1].atan2();
+ float a = portal_points[i].angle();
+ float b = portal_points[i+1].angle();
if (a>b) {
SWAP( portal_points[i], portal_points[i+1] );
diff --git a/tools/editor/io_plugins/editor_scene_import_plugin.h b/tools/editor/io_plugins/editor_scene_import_plugin.h
index 71efab9503..1f3b73fe7f 100644
--- a/tools/editor/io_plugins/editor_scene_import_plugin.h
+++ b/tools/editor/io_plugins/editor_scene_import_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/io_plugins/editor_texture_import_plugin.cpp b/tools/editor/io_plugins/editor_texture_import_plugin.cpp
index 4f7ec1839a..29273ebd06 100644
--- a/tools/editor/io_plugins/editor_texture_import_plugin.cpp
+++ b/tools/editor/io_plugins/editor_texture_import_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -828,7 +828,7 @@ Error EditorTextureImportPlugin::import(const String& p_path, const Ref<Resource
}
-Error EditorTextureImportPlugin::_process_texture_data(Ref<ImageTexture> &texture,int format, float quality,int flags,EditorExportPlatform::ImageCompression p_compr,int tex_flags,int shrink) {
+Error EditorTextureImportPlugin::_process_texture_data(Ref<ImageTexture> &texture,int format, float quality,int flags,EditorExportPlatform::ImageCompression p_compr,int tex_flags,float shrink) {
if (format==IMAGE_FORMAT_COMPRESS_DISK_LOSSLESS || format==IMAGE_FORMAT_COMPRESS_DISK_LOSSY) {
@@ -866,7 +866,7 @@ Error EditorTextureImportPlugin::_process_texture_data(Ref<ImageTexture> &textur
int orig_w=image.get_width();
int orig_h=image.get_height();
- image.resize(orig_w/shrink,orig_h/shrink);
+ image.resize(orig_w/shrink,orig_h/shrink,Image::INTERPOLATE_CUBIC);
texture->create_from_image(image,tex_flags);
texture->set_size_override(Size2(orig_w,orig_h));
@@ -926,7 +926,7 @@ Error EditorTextureImportPlugin::_process_texture_data(Ref<ImageTexture> &textur
int orig_h=image.get_height();
if (shrink>1) {
- image.resize(orig_w/shrink,orig_h/shrink);
+ image.resize(orig_w/shrink,orig_h/shrink,Image::INTERPOLATE_CUBIC);
texture->create_from_image(image,tex_flags);
texture->set_size_override(Size2(orig_w,orig_h));
}
@@ -987,7 +987,7 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
tex_flags|=Texture::FLAG_ANISOTROPIC_FILTER;
print_line("path: "+p_path+" flags: "+itos(tex_flags));
- int shrink=1;
+ float shrink=1;
if (from->has_option("shrink"))
shrink=from->get_option("shrink");
@@ -1068,12 +1068,14 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
//prepare atlas!
Vector< Image > sources;
+ Vector< Image > tsources;
bool alpha=false;
bool crop = from->get_option("crop");
EditorProgress ep("make_atlas","Build Atlas For: "+p_path.get_file(),from->get_source_count()+3);
print_line("sources: "+itos(from->get_source_count()));
+
for(int i=0;i<from->get_source_count();i++) {
String path = EditorImportPlugin::expand_source_path(from->get_source_path(i));
@@ -1091,17 +1093,57 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
if (src.detect_alpha())
alpha=true;
- sources.push_back(src);
+ tsources.push_back(src);
}
ep.step("Converting Images",sources.size());
- for(int i=0;i<sources.size();i++) {
+ int base_index=0;
+
+
+ Map<uint64_t,int> source_md5;
+ Map<int,List<int> > source_map;
+
+ for(int i=0;i<tsources.size();i++) {
+
+ Image src = tsources[i];
if (alpha) {
- sources[i].convert(Image::FORMAT_RGBA);
+ src.convert(Image::FORMAT_RGBA);
} else {
- sources[i].convert(Image::FORMAT_RGB);
+ src.convert(Image::FORMAT_RGB);
+ }
+
+ DVector<uint8_t> data = src.get_data();
+ MD5_CTX md5;
+ DVector<uint8_t>::Read r=data.read();
+ MD5Init(&md5);
+ int len=data.size();
+ for(int j=0;j<len;j++) {
+ uint8_t b = r[j];
+ b>>=2; //to aid in comparing
+ MD5Update(&md5,(unsigned char*)&b,1);
+ }
+ MD5Final(&md5);
+ uint64_t *cmp = (uint64_t*)md5.digest; //less bits, but still useful for this
+
+ tsources[i]=Image(); //clear
+
+ if (source_md5.has(*cmp)) {
+ int sidx=source_md5[*cmp];
+ source_map[sidx].push_back(i);
+ print_line("REUSING "+from->get_source_path(i));
+
+ } else {
+ int sidx=sources.size();
+ source_md5[*cmp]=sidx;
+ sources.push_back(src);
+ List<int> sm;
+ sm.push_back(i);
+ source_map[sidx]=sm;
+
}
+
+
}
//texturepacker is not really good for optimizing, so..
@@ -1138,31 +1180,59 @@ Error EditorTextureImportPlugin::import2(const String& p_path, const Ref<Resourc
ep.step("Blitting Images",sources.size()+2);
+ bool blit_to_po2=tex_flags&Texture::FLAG_MIPMAPS;
+ int atlas_w=dst_size.width;
+ int atlas_h=dst_size.height;
+ if (blit_to_po2) {
+ atlas_w=nearest_power_of_2(dst_size.width);
+ atlas_h=nearest_power_of_2(dst_size.height);
+ }
Image atlas;
- atlas.create(nearest_power_of_2(dst_size.width),nearest_power_of_2(dst_size.height),0,alpha?Image::FORMAT_RGBA:Image::FORMAT_RGB);
+ atlas.create(atlas_w,atlas_h,0,alpha?Image::FORMAT_RGBA:Image::FORMAT_RGB);
+
+
+ atlases.resize(from->get_source_count());
for(int i=0;i<sources.size();i++) {
int x=dst_positions[i].x;
int y=dst_positions[i].y;
- Ref<AtlasTexture> at = memnew( AtlasTexture );
Size2 sz = Size2(sources[i].get_width(),sources[i].get_height());
+
+ Rect2 region;
+ Rect2 margin;
+
if (crop && sz!=crops[i].size) {
Rect2 rect = crops[i];
rect.size=sz-rect.size;
- at->set_region(Rect2(x+border,y+border,crops[i].size.width,crops[i].size.height));
- at->set_margin(rect);
+ region=Rect2(x+border,y+border,crops[i].size.width,crops[i].size.height);
+ margin=rect;
atlas.blit_rect(sources[i],crops[i],Point2(x+border,y+border));
} else {
- at->set_region(Rect2(x+border,y+border,sz.x,sz.y));
+ region=Rect2(x+border,y+border,sz.x,sz.y);
atlas.blit_rect(sources[i],Rect2(0,0,sources[i].get_width(),sources[i].get_height()),Point2(x+border,y+border));
}
- String apath = p_path.get_base_dir().plus_file(from->get_source_path(i).get_file().basename()+".atex");
- print_line("Atlas Tex: "+apath);
- at->set_path(apath);
- atlases.push_back(at);
+ ERR_CONTINUE( !source_map.has(i) );
+ for (List<int>::Element *E=source_map[i].front();E;E=E->next()) {
+
+ String apath = p_path.get_base_dir().plus_file(from->get_source_path(E->get()).get_file().basename()+".atex");
+
+ Ref<AtlasTexture> at;
+
+ if (ResourceCache::has(apath)) {
+ at = Ref<AtlasTexture>( ResourceCache::get(apath)->cast_to<AtlasTexture>() );
+ } else {
+
+ at = Ref<AtlasTexture>( memnew( AtlasTexture ) );
+ }
+ at->set_region(region);
+ at->set_margin(margin);
+ at->set_path(apath);
+ atlases[E->get()]=at;
+ print_line("Atlas Tex: "+apath);
+ }
}
if (ResourceCache::has(p_path)) {
texture = Ref<ImageTexture> ( ResourceCache::get(p_path)->cast_to<ImageTexture>() );
@@ -1414,6 +1484,9 @@ Vector<uint8_t> EditorTextureImportPlugin::custom_export(const String& p_path, c
case EditorImportExport::IMAGE_ACTION_COMPRESS_RAM: {
group_format=EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_RAM;
} break; //use default
+ case EditorImportExport::IMAGE_ACTION_KEEP: {
+ return Vector<uint8_t>();
+ } break; //use default
}
@@ -1593,7 +1666,7 @@ EditorTextureImportPlugin::EditorTextureImportPlugin(EditorNode *p_editor, Mode
if (pl.is_valid()) {
Vector<uint8_t> ce = pl->custom_export(p_path,p_platform);
if (ce.size()) {
- p_path=p_path.basename()+".tex";
+ p_path=p_path.basename()+".converted.tex";
return ce;
}
}
@@ -1607,7 +1680,7 @@ EditorTextureImportPlugin::EditorTextureImportPlugin(EditorNode *p_editor, Mode
if (pl.is_valid()) {
Vector<uint8_t> ce = pl->custom_export(p_path,p_platform);
if (ce.size()) {
- p_path=p_path.basename()+".tex";
+ p_path=p_path.basename()+".converted.tex";
return ce;
}
}
diff --git a/tools/editor/io_plugins/editor_texture_import_plugin.h b/tools/editor/io_plugins/editor_texture_import_plugin.h
index 02d09d9e17..cb63ba98c8 100644
--- a/tools/editor/io_plugins/editor_texture_import_plugin.h
+++ b/tools/editor/io_plugins/editor_texture_import_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -70,7 +70,7 @@ private:
static EditorTextureImportPlugin *singleton[MODE_MAX];
//used by other importers such as mesh
- Error _process_texture_data(Ref<ImageTexture> &texture, int format, float quality, int flags,EditorExportPlatform::ImageCompression p_compr,int tex_flags,int shrink);
+ Error _process_texture_data(Ref<ImageTexture> &texture, int format, float quality, int flags,EditorExportPlatform::ImageCompression p_compr,int tex_flags,float shrink);
void compress_image(EditorExportPlatform::ImageCompression p_mode,Image& image,bool p_smaller);
public:
@@ -123,6 +123,7 @@ public:
virtual Vector<uint8_t> custom_export(String& p_path,const Ref<EditorExportPlatform> &p_platform);
EditorTextureExportPlugin();
};
+
class EditorImportTextureOptions : public VBoxContainer {
OBJ_TYPE( EditorImportTextureOptions, VBoxContainer );
diff --git a/tools/editor/io_plugins/editor_translation_import_plugin.cpp b/tools/editor/io_plugins/editor_translation_import_plugin.cpp
index d152d71af4..1edfe697b6 100644
--- a/tools/editor/io_plugins/editor_translation_import_plugin.cpp
+++ b/tools/editor/io_plugins/editor_translation_import_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/io_plugins/editor_translation_import_plugin.h b/tools/editor/io_plugins/editor_translation_import_plugin.h
index f3c2884534..cadcdc03b3 100644
--- a/tools/editor/io_plugins/editor_translation_import_plugin.h
+++ b/tools/editor/io_plugins/editor_translation_import_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/multi_node_edit.cpp b/tools/editor/multi_node_edit.cpp
new file mode 100644
index 0000000000..cfa998bee9
--- /dev/null
+++ b/tools/editor/multi_node_edit.cpp
@@ -0,0 +1,118 @@
+#include "multi_node_edit.h"
+#include "editor_node.h"
+
+bool MultiNodeEdit::_set(const StringName& p_name, const Variant& p_value){
+
+ Node *es = EditorNode::get_singleton()->get_edited_scene();
+ if (!es)
+ return false;
+
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+
+ ur->create_action("MultiNode Set "+String(p_name));
+ for (const List<NodePath>::Element *E=nodes.front();E;E=E->next()) {
+
+ if (!es->has_node(E->get()))
+ continue;
+
+ Node*n=es->get_node(E->get());
+ if (!n)
+ continue;
+
+ ur->add_do_property(n,p_name,p_value);
+ ur->add_undo_property(n,p_name,n->get(p_name));
+
+ }
+
+ ur->commit_action();
+ return true;
+}
+
+bool MultiNodeEdit::_get(const StringName& p_name,Variant &r_ret) const {
+
+ Node *es = EditorNode::get_singleton()->get_edited_scene();
+ if (!es)
+ return false;
+
+ for (const List<NodePath>::Element *E=nodes.front();E;E=E->next()) {
+
+ if (!es->has_node(E->get()))
+ continue;
+
+ const Node*n=es->get_node(E->get());
+ if (!n)
+ continue;
+
+ bool found;
+ r_ret=n->get(p_name,&found);
+ if (found)
+ return true;
+
+ }
+
+ return false;
+}
+
+void MultiNodeEdit::_get_property_list( List<PropertyInfo> *p_list) const{
+
+ HashMap<String,PLData> usage;
+
+ Node *es = EditorNode::get_singleton()->get_edited_scene();
+ if (!es)
+ return;
+
+ int nc=0;
+
+ List<PLData*> datas;
+
+ for (const List<NodePath>::Element *E=nodes.front();E;E=E->next()) {
+
+ if (!es->has_node(E->get()))
+ continue;
+
+ Node*n=es->get_node(E->get());
+ if (!n)
+ continue;
+
+ List<PropertyInfo> plist;
+ n->get_property_list(&plist,true);
+
+ for(List<PropertyInfo>::Element *F=plist.front();F;F=F->next()) {
+
+ if (!usage.has(F->get().name)) {
+ PLData pld;
+ pld.uses=0;
+ pld.info=F->get();
+ usage[F->get().name]=pld;
+ datas.push_back(usage.getptr(F->get().name));
+ }
+
+ usage[F->get().name].uses++;
+ }
+
+ nc++;
+ }
+
+ for (List<PLData*>::Element *E=datas.front();E;E=E->next()) {
+
+ if (nc==E->get()->uses) {
+ p_list->push_back(E->get()->info);
+ }
+ }
+
+
+}
+
+void MultiNodeEdit::clear_nodes() {
+
+ nodes.clear();
+}
+
+void MultiNodeEdit::add_node(const NodePath& p_node){
+
+ nodes.push_back(p_node);
+}
+
+MultiNodeEdit::MultiNodeEdit()
+{
+}
diff --git a/tools/editor/multi_node_edit.h b/tools/editor/multi_node_edit.h
new file mode 100644
index 0000000000..5a0cabf4be
--- /dev/null
+++ b/tools/editor/multi_node_edit.h
@@ -0,0 +1,32 @@
+#ifndef MULTI_NODE_EDIT_H
+#define MULTI_NODE_EDIT_H
+
+#include "scene/main/node.h"
+
+class MultiNodeEdit : public Reference {
+
+ OBJ_TYPE(MultiNodeEdit,Reference);
+
+ List<NodePath> nodes;
+ struct PLData {
+ int uses;
+ PropertyInfo info;
+ };
+
+protected:
+
+ bool _set(const StringName& p_name, const Variant& p_value);
+ bool _get(const StringName& p_name,Variant &r_ret) const;
+ void _get_property_list( List<PropertyInfo> *p_list) const;
+
+public:
+
+
+
+ void clear_nodes();
+ void add_node(const NodePath& p_node);
+
+ MultiNodeEdit();
+};
+
+#endif // MULTI_NODE_EDIT_H
diff --git a/tools/editor/optimized_save_dialog.cpp b/tools/editor/optimized_save_dialog.cpp
index 687d3675fc..4814b3b021 100644
--- a/tools/editor/optimized_save_dialog.cpp
+++ b/tools/editor/optimized_save_dialog.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/optimized_save_dialog.h b/tools/editor/optimized_save_dialog.h
index 739d0e1506..bdc36eddc1 100644
--- a/tools/editor/optimized_save_dialog.h
+++ b/tools/editor/optimized_save_dialog.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/output_strings.cpp b/tools/editor/output_strings.cpp
index 30569d11b0..a19352f4ec 100644
--- a/tools/editor/output_strings.cpp
+++ b/tools/editor/output_strings.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/output_strings.h b/tools/editor/output_strings.h
index ad893534fa..3d5deb1646 100644
--- a/tools/editor/output_strings.h
+++ b/tools/editor/output_strings.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/pane_drag.cpp b/tools/editor/pane_drag.cpp
index fb137de5ce..8e8c2941ec 100644
--- a/tools/editor/pane_drag.cpp
+++ b/tools/editor/pane_drag.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/pane_drag.h b/tools/editor/pane_drag.h
index a6cd9b6662..24f2ef7ed8 100644
--- a/tools/editor/pane_drag.h
+++ b/tools/editor/pane_drag.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/plugins/SCsub b/tools/editor/plugins/SCsub
index b525fb3f75..363a2ce4c0 100644
--- a/tools/editor/plugins/SCsub
+++ b/tools/editor/plugins/SCsub
@@ -1,7 +1,3 @@
Import('env')
Export('env')
env.add_source_files(env.tool_sources,"*.cpp")
-
-
-
-
diff --git a/tools/editor/plugins/animation_data_editor_plugin.cpp b/tools/editor/plugins/animation_data_editor_plugin.cpp
index d8d65b875a..a73c75056b 100644
--- a/tools/editor/plugins/animation_data_editor_plugin.cpp
+++ b/tools/editor/plugins/animation_data_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/plugins/animation_data_editor_plugin.h b/tools/editor/plugins/animation_data_editor_plugin.h
index 0daa67d0a5..0a12638474 100644
--- a/tools/editor/plugins/animation_data_editor_plugin.h
+++ b/tools/editor/plugins/animation_data_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/plugins/animation_player_editor_plugin.cpp b/tools/editor/plugins/animation_player_editor_plugin.cpp
index 05b12543d2..b56140b32d 100644
--- a/tools/editor/plugins/animation_player_editor_plugin.cpp
+++ b/tools/editor/plugins/animation_player_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,23 +27,25 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "animation_player_editor_plugin.h"
+#include "globals.h"
#include "io/resource_loader.h"
+#include "io/resource_saver.h"
#include "os/keyboard.h"
#include "tools/editor/editor_settings.h"
+#include "tools/editor/animation_editor.h"
void AnimationPlayerEditor::_node_removed(Node *p_node) {
if (player && player == p_node) {
player=NULL;
- hide();
+
set_process(false);
- if (edit_anim->is_pressed()) {
- editor->get_animation_editor()->set_animation(Ref<Animation>());
- editor->get_animation_editor()->set_root(NULL);
- editor->animation_editor_make_visible(false);
- edit_anim->set_pressed(false);
- }
+ key_editor->set_animation(Ref<Animation>());
+ key_editor->set_root(NULL);
+ _update_player();
+ //editor->animation_editor_make_visible(false);
+
}
}
@@ -70,19 +72,18 @@ void AnimationPlayerEditor::_notification(int p_what) {
Ref<Animation> anim = player->get_animation(animname);
if (!anim.is_null()) {
- seek->set_max(anim->get_length());
+ frame->set_max(anim->get_length());
}
}
}
- seek->set_val(player->get_current_animation_pos());
- if (edit_anim->is_pressed())
- editor->get_animation_editor()->set_anim_pos(player->get_current_animation_pos());
+ frame->set_val(player->get_current_animation_pos());
+ key_editor->set_anim_pos(player->get_current_animation_pos());
EditorNode::get_singleton()->get_property_editor()->refresh();
} else if (last_active) {
//need the last frame after it stopped
- seek->set_val(player->get_current_animation_pos());
+ frame->set_val(player->get_current_animation_pos());
}
last_active=player->is_playing();
@@ -98,8 +99,10 @@ void AnimationPlayerEditor::_notification(int p_what) {
duplicate_anim->set_icon( get_icon("Duplicate","EditorIcons") );
autoplay->set_icon( get_icon("AutoPlay","EditorIcons") );
load_anim->set_icon( get_icon("Folder","EditorIcons") );
+ save_anim->set_icon(get_icon("Save", "EditorIcons"));
+ save_anim->get_popup()->connect("item_pressed", this, "_animation_save_menu");
remove_anim->set_icon( get_icon("Remove","EditorIcons") );
- edit_anim->set_icon( get_icon("Edit","EditorIcons") );
+
blend_anim->set_icon( get_icon("Blend","EditorIcons") );
play->set_icon( get_icon("PlayStart","EditorIcons") );
play_from->set_icon( get_icon("Play","EditorIcons") );
@@ -109,13 +112,14 @@ void AnimationPlayerEditor::_notification(int p_what) {
autoplay_icon=get_icon("AutoPlay","EditorIcons");
stop->set_icon( get_icon("Stop","EditorIcons") );
resource_edit_anim->set_icon( get_icon("EditResource","EditorIcons") );
- pin->set_normal_texture(get_icon("Pin","EditorIcons") );
- pin->set_pressed_texture( get_icon("PinPressed","EditorIcons") );
+ pin->set_icon(get_icon("Pin","EditorIcons") );
tool_anim->set_icon(get_icon("Tools","EditorIcons"));
tool_anim->get_popup()->connect("item_pressed",this,"_animation_tool_menu");
blend_editor.next->connect("text_changed",this,"_blend_editor_next_changed");
+ nodename->set_icon(get_icon("AnimationPlayer","EditorIcons"));
+
/*
anim_editor_load->set_normal_texture( get_icon("AnimGet","EditorIcons"));
anim_editor_store->set_normal_texture( get_icon("AnimSet","EditorIcons"));
@@ -291,22 +295,25 @@ void AnimationPlayerEditor::_animation_selected(int p_which) {
player->set_current_animation( current );
Ref<Animation> anim = player->get_animation(current);
- if (edit_anim->is_pressed()) {
- Ref<Animation> anim = player->get_animation(current);
- editor->get_animation_editor()->set_animation(anim);
+ {
+
+ key_editor->set_animation(anim);
Node *root = player->get_node(player->get_root());
if (root) {
- editor->get_animation_editor()->set_root(root);
+ key_editor->set_root(root);
}
}
- seek->set_max(anim->get_length());
+ frame->set_max(anim->get_length());
+ if (anim->get_step())
+ frame->set_step(anim->get_step());
+ else
+ frame->set_step(0.00001);
+
} else {
- if (edit_anim->is_pressed()) {
- editor->get_animation_editor()->set_animation(Ref<Animation>());
- editor->get_animation_editor()->set_root(NULL);
- }
+ key_editor->set_animation(Ref<Animation>());
+ key_editor->set_root(NULL);
}
@@ -367,8 +374,78 @@ void AnimationPlayerEditor::_animation_load() {
}
file->popup_centered_ratio();
+ current_option = RESOURCE_LOAD;
+}
+
+
+void AnimationPlayerEditor::_animation_save_in_path(const Ref<Resource>& p_resource, const String& p_path) {
+
+ int flg = 0;
+ if (EditorSettings::get_singleton()->get("on_save/compress_binary_resources"))
+ flg |= ResourceSaver::FLAG_COMPRESS;
+ if (EditorSettings::get_singleton()->get("on_save/save_paths_as_relative"))
+ flg |= ResourceSaver::FLAG_RELATIVE_PATHS;
+
+ String path = Globals::get_singleton()->localize_path(p_path);
+ Error err = ResourceSaver::save(path, p_resource, flg | ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS);
+
+ if (err != OK) {
+ accept->set_text("Error saving resource!");
+ accept->popup_centered_minsize();
+ return;
+ }
+ // EditorFileSystem::get_singleton()->update_file(path,p_resource->get_type());
+
+ ((Resource*)p_resource.ptr())->set_path(path);
+ editor->emit_signal("resource_saved", p_resource);
+
+}
+
+void AnimationPlayerEditor::_animation_save(const Ref<Resource>& p_resource) {
+
+ if (p_resource->get_path().is_resource_file()) {
+ _animation_save_in_path(p_resource, p_resource->get_path());
+ }
+ else {
+ _animation_save_as(p_resource);
+ }
+}
+void AnimationPlayerEditor::_animation_save_as(const Ref<Resource>& p_resource) {
+ file->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ bool relpaths = (p_resource->has_meta("__editor_relpaths__") && p_resource->get_meta("__editor_relpaths__").operator bool());
+
+ List<String> extensions;
+ ResourceSaver::get_recognized_extensions(p_resource, &extensions);
+ file->clear_filters();
+ for (int i = 0; i<extensions.size(); i++) {
+
+ file->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper());
+ }
+
+ //file->set_current_path(current_path);
+ if (p_resource->get_path() != "") {
+ file->set_current_path(p_resource->get_path());
+ if (extensions.size()) {
+ String ext = p_resource->get_path().extension().to_lower();
+ if (extensions.find(ext) == NULL) {
+ file->set_current_path(p_resource->get_path().replacen("." + ext, "." + extensions.front()->get()));
+ }
+ }
+ }
+ else {
+
+ String existing;
+ if (extensions.size()) {
+ existing = "new_" + p_resource->get_type().to_lower() + "." + extensions.front()->get().to_lower();
+ }
+ file->set_current_path(existing);
+
+ }
+ file->popup_centered_ratio();
+ file->set_title("Save Resource As..");
+ current_option = RESOURCE_SAVE;
}
void AnimationPlayerEditor::_animation_remove() {
@@ -549,6 +626,45 @@ void AnimationPlayerEditor::ensure_visibility() {
_animation_edit();
}
+Dictionary AnimationPlayerEditor::get_state() const {
+
+ Dictionary d;
+
+ d["visible"]=is_visible();
+ if (is_visible() && player) {
+ d["player"]=EditorNode::get_singleton()->get_edited_scene()->get_path_to(player);
+ d["animation"]=player->get_current_animation();
+
+ }
+
+ return d;
+
+}
+void AnimationPlayerEditor::set_state(const Dictionary& p_state) {
+
+ if (p_state.has("visible") && p_state["visible"]) {
+
+ Node *n = EditorNode::get_singleton()->get_edited_scene()->get_node(p_state["player"]);
+ if (n && n->cast_to<AnimationPlayer>()) {
+ player=n->cast_to<AnimationPlayer>();
+ _update_player();
+ show();
+ set_process(true);
+ ensure_visibility();
+// EditorNode::get_singleton()->animation_panel_make_visible(true);
+
+ if (p_state.has("animation")) {
+ String anim = p_state["animation"];
+ _select_anim_by_name(anim);
+ _animation_edit();
+ }
+
+ }
+ }
+
+}
+
+
void AnimationPlayerEditor::_animation_resource_edit() {
if (animation->get_item_count()) {
@@ -561,69 +677,72 @@ void AnimationPlayerEditor::_animation_resource_edit() {
void AnimationPlayerEditor::_animation_edit() {
-// if (animation->get_item_count()==0)
-// return;
+ if (animation->get_item_count()) {
+ String current = animation->get_item_text(animation->get_selected());
+ Ref<Animation> anim = player->get_animation(current);
+ key_editor->set_animation(anim);
+ Node *root = player->get_node(player->get_root());
+ if (root) {
+ key_editor->set_root(root);
+ }
- if (edit_anim->is_pressed()) {
- editor->animation_editor_make_visible(true);
+ } else {
- //editor->get_animation_editor()->set_root(player->get_roo); - get root pending
- if (animation->get_item_count()) {
- String current = animation->get_item_text(animation->get_selected());
- Ref<Animation> anim = player->get_animation(current);
- editor->get_animation_editor()->set_animation(anim);
- Node *root = player->get_node(player->get_root());
- if (root) {
- editor->get_animation_editor()->set_root(root);
- }
+ key_editor->set_animation(Ref<Animation>());
+ key_editor->set_root(NULL);
- } else {
+ }
- editor->get_animation_editor()->set_animation(Ref<Animation>());
- editor->get_animation_editor()->set_root(NULL);
+}
+void AnimationPlayerEditor::_dialog_action(String p_file) {
- }
- } else {
- editor->animation_editor_make_visible(false);
- editor->get_animation_editor()->set_animation(Ref<Animation>());
- editor->get_animation_editor()->set_root(NULL);
- }
+ switch (current_option) {
+ case RESOURCE_LOAD: {
+ ERR_FAIL_COND(!player);
- //get_scene()->get_root_node()->call("_resource_selected",anim,"");
+ Ref<Resource> res = ResourceLoader::load(p_file, "Animation");
+ ERR_FAIL_COND(res.is_null());
+ ERR_FAIL_COND(!res->is_type("Animation"));
+ if (p_file.find_last("/") != -1) {
-}
-void AnimationPlayerEditor::_file_selected(String p_file) {
+ p_file = p_file.substr(p_file.find_last("/") + 1, p_file.length());
- ERR_FAIL_COND(!player);
+ }
+ if (p_file.find_last("\\") != -1) {
- Ref<Resource> res = ResourceLoader::load(p_file,"Animation");
- ERR_FAIL_COND(res.is_null());
- ERR_FAIL_COND( !res->is_type("Animation") );
- if (p_file.find_last("/")!=-1) {
+ p_file = p_file.substr(p_file.find_last("\\") + 1, p_file.length());
- p_file=p_file.substr( p_file.find_last("/")+1, p_file.length() );
+ }
- }
- if (p_file.find_last("\\")!=-1) {
+ if (p_file.find(".") != -1)
+ p_file = p_file.substr(0, p_file.find("."));
- p_file=p_file.substr( p_file.find_last("\\")+1, p_file.length() );
+ undo_redo->create_action("Load Animation");
+ undo_redo->add_do_method(player, "add_animation", p_file, res);
+ undo_redo->add_undo_method(player, "remove_animation", p_file);
+ if (player->has_animation(p_file)) {
+ undo_redo->add_undo_method(player, "add_animation", p_file, player->get_animation(p_file));
- }
+ }
+ undo_redo->add_do_method(this, "_animation_player_changed", player);
+ undo_redo->add_undo_method(this, "_animation_player_changed", player);
+ undo_redo->commit_action();
+ break;
+ }
+ case RESOURCE_SAVE: {
- if (p_file.find(".")!=-1)
- p_file=p_file.substr(0,p_file.find("."));
+ String current = animation->get_item_text(animation->get_selected());
+ if (current != "") {
+ Ref<Animation> anim = player->get_animation(current);
+
+ ERR_FAIL_COND(!anim->cast_to<Resource>())
- undo_redo->create_action("Load Animation");
- undo_redo->add_do_method(player,"add_animation",p_file,res);
- undo_redo->add_undo_method(player,"remove_animation",p_file);
- if (player->has_animation(p_file)) {
- undo_redo->add_undo_method(player,"add_animation",p_file,player->get_animation(p_file));
+ RES current_res = RES(anim->cast_to<Resource>());
+ _animation_save_in_path(current_res, p_file);
+ }
+ }
}
- undo_redo->add_do_method(this,"_animation_player_changed",player);
- undo_redo->add_undo_method(this,"_animation_player_changed",player);
- undo_redo->commit_action();
-
}
void AnimationPlayerEditor::_scale_changed(const String& p_scale) {
@@ -666,16 +785,21 @@ void AnimationPlayerEditor::_update_animation() {
void AnimationPlayerEditor::_update_player() {
- if (!player)
- return;
updating=true;
List<StringName> animlist;
- player->get_animation_list(&animlist);
+ if (player)
+ player->get_animation_list(&animlist);
animation->clear();
- nodename->set_text(player->get_name());
+ if (player)
+ nodename->set_text(player->get_name());
+ else
+ nodename->set_text("<empty>");
+
+ add_anim->set_disabled(player==NULL);
+ load_anim->set_disabled(player==NULL);
stop->set_disabled(animlist.size()==0);
play->set_disabled(animlist.size()==0);
play_bw->set_disabled(animlist.size()==0);
@@ -687,6 +811,8 @@ void AnimationPlayerEditor::_update_player() {
blend_anim->set_disabled(animlist.size()==0);
remove_anim->set_disabled(animlist.size()==0);
resource_edit_anim->set_disabled(animlist.size()==0);
+ save_anim->set_disabled(animlist.size() == 0);
+
int active_idx=-1;
for (List<StringName>::Element *E=animlist.front();E;E=E->next()) {
@@ -701,6 +827,9 @@ void AnimationPlayerEditor::_update_player() {
}
+ if (!player)
+ return;
+
updating=false;
if (active_idx!=-1) {
animation->select(active_idx);
@@ -716,17 +845,14 @@ void AnimationPlayerEditor::_update_player() {
//pause->set_pressed(player->is_paused());
- if (edit_anim->is_pressed()) {
-
- if (animation->get_item_count()) {
- String current = animation->get_item_text(animation->get_selected());
- Ref<Animation> anim = player->get_animation(current);
- editor->get_animation_editor()->set_animation(anim);
- Node *root = player->get_node(player->get_root());
- if (root) {
- editor->get_animation_editor()->set_root(root);
- }
+ if (animation->get_item_count()) {
+ String current = animation->get_item_text(animation->get_selected());
+ Ref<Animation> anim = player->get_animation(current);
+ key_editor->set_animation(anim);
+ Node *root = player->get_node(player->get_root());
+ if (root) {
+ key_editor->set_root(root);
}
}
@@ -822,7 +948,7 @@ void AnimationPlayerEditor::_seek_value_changed(float p_value) {
Ref<Animation> anim;
anim=player->get_animation(current);
- float pos = anim->get_length() * (p_value / seek->get_max());
+ float pos = anim->get_length() * (p_value / frame->get_max());
if (player->is_valid()) {
float cpos = player->get_current_animation_pos();
@@ -832,8 +958,7 @@ void AnimationPlayerEditor::_seek_value_changed(float p_value) {
player->seek(pos,true);
}
- if (edit_anim->is_pressed())
- editor->get_animation_editor()->set_anim_pos(pos);
+ key_editor->set_anim_pos(pos);
updating=true;
};
@@ -863,19 +988,19 @@ void AnimationPlayerEditor::_editor_store() {
String current = animation->get_item_text(animation->get_selected());
Ref<Animation> anim = player->get_animation(current);
- if (editor->get_animation_editor()->get_current_animation()==anim)
+ if (key_editor->get_current_animation()==anim)
return; //already there
undo_redo->create_action("Store anim in editor");
- undo_redo->add_do_method(editor->get_animation_editor(),"set_animation",anim);
- undo_redo->add_undo_method(editor->get_animation_editor(),"remove_animation",anim);
+ undo_redo->add_do_method(key_editor,"set_animation",anim);
+ undo_redo->add_undo_method(key_editor,"remove_animation",anim);
undo_redo->commit_action();
}
void AnimationPlayerEditor::_editor_load(){
- Ref<Animation> anim = editor->get_animation_editor()->get_current_animation();
+ Ref<Animation> anim = key_editor->get_current_animation();
if (anim.is_null())
return;
@@ -923,7 +1048,16 @@ void AnimationPlayerEditor::_editor_load(){
void AnimationPlayerEditor::_animation_key_editor_anim_len_changed(float p_len) {
- seek->set_max(p_len);
+ frame->set_max(p_len);
+
+}
+
+void AnimationPlayerEditor::_animation_key_editor_anim_step_changed(float p_len) {
+
+ if (p_len)
+ frame->set_step(p_len);
+ else
+ frame->set_step(0.00001);
}
@@ -938,7 +1072,7 @@ void AnimationPlayerEditor::_animation_key_editor_seek(float p_pos) {
if (player->is_playing() )
return;
- seek->set_val(p_pos);
+ frame->set_val(p_pos);
EditorNode::get_singleton()->get_property_editor()->refresh();
@@ -951,13 +1085,11 @@ void AnimationPlayerEditor::_hide_anim_editors() {
player=NULL;
hide();
set_process(false);
- if (edit_anim->is_pressed()) {
- editor->get_animation_editor()->set_animation(Ref<Animation>());
- editor->get_animation_editor()->set_root(NULL);
- editor->animation_editor_make_visible(false);
- edit_anim->set_pressed(false);
- }
+ key_editor->set_animation(Ref<Animation>());
+ key_editor->set_root(NULL);
+// editor->animation_editor_make_visible(false);
+
}
@@ -1029,6 +1161,23 @@ void AnimationPlayerEditor::_animation_tool_menu(int p_option) {
}
}
+void AnimationPlayerEditor::_animation_save_menu(int p_option) {
+
+ String current = animation->get_item_text(animation->get_selected());
+ if (current != "") {
+ Ref<Animation> anim = player->get_animation(current);
+
+ switch (p_option) {
+ case ANIM_SAVE:
+ _animation_save(anim);
+ break;
+ case ANIM_SAVE_AS:
+ _animation_save_as(anim);
+ break;
+ }
+ }
+}
+
void AnimationPlayerEditor::_unhandled_key_input(const InputEvent& p_ev) {
if (is_visible() && p_ev.type==InputEvent::KEY && p_ev.key.pressed && !p_ev.key.echo && !p_ev.key.mod.alt && !p_ev.key.mod.control && !p_ev.key.mod.meta) {
@@ -1074,7 +1223,7 @@ void AnimationPlayerEditor::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_animation_blend"),&AnimationPlayerEditor::_animation_blend);
ObjectTypeDB::bind_method(_MD("_animation_edit"),&AnimationPlayerEditor::_animation_edit);
ObjectTypeDB::bind_method(_MD("_animation_resource_edit"),&AnimationPlayerEditor::_animation_resource_edit);
- ObjectTypeDB::bind_method(_MD("_file_selected"),&AnimationPlayerEditor::_file_selected);
+ ObjectTypeDB::bind_method(_MD("_dialog_action"),&AnimationPlayerEditor::_dialog_action);
ObjectTypeDB::bind_method(_MD("_seek_value_changed"),&AnimationPlayerEditor::_seek_value_changed);
ObjectTypeDB::bind_method(_MD("_animation_player_changed"),&AnimationPlayerEditor::_animation_player_changed);
ObjectTypeDB::bind_method(_MD("_blend_edited"),&AnimationPlayerEditor::_blend_edited);
@@ -1085,19 +1234,28 @@ void AnimationPlayerEditor::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_list_changed"),&AnimationPlayerEditor::_list_changed);
ObjectTypeDB::bind_method(_MD("_animation_key_editor_seek"),&AnimationPlayerEditor::_animation_key_editor_seek);
ObjectTypeDB::bind_method(_MD("_animation_key_editor_anim_len_changed"),&AnimationPlayerEditor::_animation_key_editor_anim_len_changed);
+ ObjectTypeDB::bind_method(_MD("_animation_key_editor_anim_step_changed"),&AnimationPlayerEditor::_animation_key_editor_anim_step_changed);
ObjectTypeDB::bind_method(_MD("_hide_anim_editors"),&AnimationPlayerEditor::_hide_anim_editors);
ObjectTypeDB::bind_method(_MD("_animation_duplicate"),&AnimationPlayerEditor::_animation_duplicate);
ObjectTypeDB::bind_method(_MD("_blend_editor_next_changed"),&AnimationPlayerEditor::_blend_editor_next_changed);
ObjectTypeDB::bind_method(_MD("_unhandled_key_input"),&AnimationPlayerEditor::_unhandled_key_input);
ObjectTypeDB::bind_method(_MD("_animation_tool_menu"),&AnimationPlayerEditor::_animation_tool_menu);
+ ObjectTypeDB::bind_method(_MD("_animation_save_menu"), &AnimationPlayerEditor::_animation_save_menu);
}
+AnimationPlayerEditor *AnimationPlayerEditor::singleton=NULL;
+
+AnimationPlayer *AnimationPlayerEditor::get_player() const {
+
+ return player;
+}
AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) {
editor=p_editor;
+ singleton=this;
updating=false;
@@ -1117,6 +1275,50 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) {
add_child(hb);
+ play_bw_from = memnew( ToolButton );
+ play_bw_from->set_tooltip("Play backwards selected animation from current pos. (A)");
+ hb->add_child(play_bw_from);
+
+ play_bw = memnew( ToolButton );
+ play_bw->set_tooltip("Play backwards selected animation from end. (Shift+A)");
+ hb->add_child(play_bw);
+
+ stop = memnew( ToolButton );
+ stop->set_toggle_mode(true);
+ hb->add_child(stop);
+ stop->set_tooltip("Stop animation playback. (S)");
+
+ play = memnew( ToolButton );
+ play->set_tooltip("Play selected animation from start. (Shift+D)");
+ hb->add_child(play);
+
+
+ play_from = memnew( ToolButton );
+ play_from->set_tooltip("Play selected animation from current pos. (D)");
+ hb->add_child(play_from);
+
+
+
+ //pause = memnew( Button );
+ //pause->set_toggle_mode(true);
+ //hb->add_child(pause);
+
+ frame = memnew( SpinBox );
+ hb->add_child(frame);
+ frame->set_custom_minimum_size(Size2(80,0));
+ frame->set_stretch_ratio(2);
+ frame->set_tooltip("Animation position (in seconds).");
+
+ hb->add_child( memnew( VSeparator));
+
+ scale = memnew( LineEdit );
+ hb->add_child(scale);
+ scale->set_h_size_flags(SIZE_EXPAND_FILL);
+ scale->set_stretch_ratio(1);
+ scale->set_tooltip("Scale animation playback globally for the node.");
+ scale->hide();
+
+
add_anim = memnew( ToolButton );
add_anim->set_tooltip("Create new animation in player.");
@@ -1127,6 +1329,17 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) {
load_anim->set_tooltip("Load an animation from disk.");
hb->add_child(load_anim);
+ save_anim = memnew(MenuButton);
+ save_anim->set_tooltip("Save the current animation");
+ save_anim->get_popup()->add_item("Save", ANIM_SAVE);
+ save_anim->get_popup()->add_item("Save As..", ANIM_SAVE_AS);
+ save_anim->set_focus_mode(Control::FOCUS_NONE);
+ hb->add_child(save_anim);
+
+ accept = memnew(AcceptDialog);
+ add_child(accept);
+ accept->connect("confirmed", this, "_menu_confirm_current");
+
duplicate_anim = memnew( ToolButton );
hb->add_child(duplicate_anim);
duplicate_anim->set_tooltip("Duplicate Animation");
@@ -1165,67 +1378,13 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) {
//tool_anim->get_popup()->add_item("Edit Anim Resource",TOOL_PASTE_ANIM);
hb->add_child(tool_anim);
-
- edit_anim = memnew( ToolButton );
- edit_anim->set_toggle_mode(true);
- hb->add_child(edit_anim);
- edit_anim->set_tooltip("Open animation editor.\nProperty editor will displays all editable keys too.");
-
-
- hb = memnew (HBoxContainer);
- add_child(hb);
-
- play_bw_from = memnew( ToolButton );
- play_bw_from->set_tooltip("Play backwards selected animation from current pos. (A)");
- hb->add_child(play_bw_from);
-
- play_bw = memnew( ToolButton );
- play_bw->set_tooltip("Play backwards selected animation from end. (Shift+A)");
- hb->add_child(play_bw);
-
- stop = memnew( ToolButton );
- stop->set_toggle_mode(true);
- hb->add_child(stop);
- stop->set_tooltip("Stop animation playback. (S)");
-
- play = memnew( ToolButton );
- play->set_tooltip("Play selected animation from start. (Shift+D)");
- hb->add_child(play);
+ nodename = memnew( Button );
+ hb->add_child(nodename);
+ pin = memnew( ToolButton );
+ pin->set_toggle_mode(true);
+ hb->add_child(pin);
- play_from = memnew( ToolButton );
- play_from->set_tooltip("Play selected animation from current pos. (D)");
- hb->add_child(play_from);
-
-
-
- //pause = memnew( Button );
- //pause->set_toggle_mode(true);
- //hb->add_child(pause);
-
- seek = memnew( HSlider );
- seek->set_val(0);
- seek->set_step(0.01);
- hb->add_child(seek);
- seek->set_h_size_flags(SIZE_EXPAND_FILL);
- seek->set_stretch_ratio(8);
- seek->set_tooltip("Seek animation (when stopped).");
-
- frame = memnew( SpinBox );
- hb->add_child(frame);
- frame->set_h_size_flags(SIZE_EXPAND_FILL);
- frame->set_stretch_ratio(2);
- frame->set_tooltip("Animation position (in seconds).");
- seek->share(frame);
-
-
-
- scale = memnew( LineEdit );
- hb->add_child(scale);
- scale->set_h_size_flags(SIZE_EXPAND_FILL);
- scale->set_stretch_ratio(1);
- scale->set_tooltip("Scale animation playback globally for the node.");
- scale->hide();
resource_edit_anim= memnew( Button );
hb->add_child(resource_edit_anim);
@@ -1236,6 +1395,7 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) {
add_child(file);
name_dialog = memnew( ConfirmationDialog );
+ name_dialog->set_title("Create New Animation");
name_dialog->set_hide_on_ok(false);
add_child(name_dialog);
name = memnew( LineEdit );
@@ -1291,30 +1451,31 @@ AnimationPlayerEditor::AnimationPlayerEditor(EditorNode *p_editor) {
load_anim->connect("pressed", this,"_animation_load");
duplicate_anim->connect("pressed", this,"_animation_duplicate");
//frame->connect("text_entered", this,"_seek_frame_changed");
- edit_anim->connect("pressed", this,"_animation_edit");
+
blend_anim->connect("pressed", this,"_animation_blend");
remove_anim->connect("pressed", this,"_animation_remove");
animation->connect("item_selected", this,"_animation_selected",Vector<Variant>(),true);
resource_edit_anim->connect("pressed", this,"_animation_resource_edit");
- file->connect("file_selected", this,"_file_selected");
- seek->connect("value_changed", this, "_seek_value_changed",Vector<Variant>(),true);
+ file->connect("file_selected", this,"_dialog_action");
+ frame->connect("value_changed", this, "_seek_value_changed",Vector<Variant>(),true);
scale->connect("text_entered", this, "_scale_changed",Vector<Variant>(),true);
- editor->get_animation_editor()->connect("timeline_changed",this,"_animation_key_editor_seek");
- editor->get_animation_editor()->connect("animation_len_changed",this,"_animation_key_editor_anim_len_changed");
-
- HBoxContainer *ahb = editor->get_animation_panel_hb();
- nodename = memnew( Label );
- ahb->add_child(nodename);
- nodename->set_h_size_flags(SIZE_EXPAND_FILL);
- nodename->set_opacity(0.5);
- pin = memnew( TextureButton );
- pin->set_toggle_mode(true);
- ahb->add_child(pin);
+
+
renaming=false;
last_active=false;
set_process_unhandled_key_input(true);
+
+ key_editor = memnew( AnimationKeyEditor);
+ add_child(key_editor);
+ add_constant_override("separation",get_constant("separation","VBoxContainer"));
+ key_editor->set_v_size_flags(SIZE_EXPAND_FILL);
+ key_editor->connect("timeline_changed",this,"_animation_key_editor_seek");
+ key_editor->connect("animation_len_changed",this,"_animation_key_editor_anim_len_changed");
+ key_editor->connect("animation_step_changed",this,"_animation_key_editor_anim_step_changed");
+
+ _update_player();
}
@@ -1337,7 +1498,7 @@ void AnimationPlayerEditorPlugin::make_visible(bool p_visible) {
anim_editor->show();
anim_editor->set_process(true);
anim_editor->ensure_visibility();
- editor->animation_panel_make_visible(true);
+// editor->animation_panel_make_visible(true);
} else {
// anim_editor->hide();
@@ -1350,7 +1511,9 @@ AnimationPlayerEditorPlugin::AnimationPlayerEditorPlugin(EditorNode *p_node) {
editor=p_node;
anim_editor = memnew( AnimationPlayerEditor(editor) );
- editor->get_animation_panel()->add_child(anim_editor);
+ anim_editor->set_undo_redo(editor->get_undo_redo());
+
+ editor->add_bottom_panel_item("Animation",anim_editor);
/*
editor->get_viewport()->add_child(anim_editor);
anim_editor->set_area_as_parent_rect();
diff --git a/tools/editor/plugins/animation_player_editor_plugin.h b/tools/editor/plugins/animation_player_editor_plugin.h
index 9f0413088d..0ad849c2f9 100644
--- a/tools/editor/plugins/animation_player_editor_plugin.h
+++ b/tools/editor/plugins/animation_player_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -41,7 +41,7 @@
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
-
+class AnimationKeyEditor;
class AnimationPlayerEditor : public VBoxContainer {
OBJ_TYPE(AnimationPlayerEditor, VBoxContainer );
@@ -55,6 +55,17 @@ class AnimationPlayerEditor : public VBoxContainer {
TOOL_EDIT_RESOURCE
};
+ enum {
+ ANIM_SAVE,
+ ANIM_SAVE_AS
+ };
+
+ enum {
+ RESOURCE_LOAD,
+ RESOURCE_SAVE
+ };
+
+
OptionButton *animation;
Button *stop;
Button *play;
@@ -67,16 +78,16 @@ class AnimationPlayerEditor : public VBoxContainer {
Button *autoplay;
Button *rename_anim;
Button *duplicate_anim;
- Button *edit_anim;
+
Button *resource_edit_anim;
Button *load_anim;
+ MenuButton *save_anim;
Button *blend_anim;
Button *remove_anim;
MenuButton *tool_anim;
- TextureButton *pin;
- Label *nodename;
+ ToolButton *pin;
+ Button *nodename;
SpinBox *frame;
- HSlider *seek;
LineEdit *scale;
LineEdit *name;
Label *name_title;
@@ -85,6 +96,8 @@ class AnimationPlayerEditor : public VBoxContainer {
bool last_active;
EditorFileDialog *file;
+ AcceptDialog *accept;
+ int current_option;
struct BlendEditor {
@@ -103,6 +116,9 @@ class AnimationPlayerEditor : public VBoxContainer {
bool updating;
bool updating_blends;
+ AnimationKeyEditor *key_editor;
+
+
void _select_anim_by_name(const String& p_anim);
void _play_pressed();
void _play_from_pressed();
@@ -116,13 +132,18 @@ class AnimationPlayerEditor : public VBoxContainer {
void _animation_rename();
void _animation_name_edited();
void _animation_load();
+
+ void _animation_save_in_path(const Ref<Resource>& p_resource, const String& p_path);
+ void _animation_save(const Ref<Resource>& p_resource);
+ void _animation_save_as(const Ref<Resource>& p_resource);
+
void _animation_remove();
void _animation_blend();
void _animation_edit();
void _animation_duplicate();
void _animation_resource_edit();
void _scale_changed(const String& p_scale);
- void _file_selected(String p_file);
+ void _dialog_action(String p_file);
void _seek_frame_changed(const String& p_frame);
void _seek_value_changed(float p_value);
void _blend_editor_next_changed(const String& p_string);
@@ -139,8 +160,12 @@ class AnimationPlayerEditor : public VBoxContainer {
void _animation_key_editor_seek(float p_pos);
void _animation_key_editor_anim_len_changed(float p_new);
+ void _animation_key_editor_anim_step_changed(float p_len);
+
void _unhandled_key_input(const InputEvent& p_ev);
void _animation_tool_menu(int p_option);
+ void _animation_save_menu(int p_option);
+
AnimationPlayerEditor();
protected:
@@ -151,6 +176,14 @@ protected:
static void _bind_methods();
public:
+ AnimationPlayer *get_player() const;
+ static AnimationPlayerEditor *singleton;
+
+ AnimationKeyEditor* get_key_editor() { return key_editor; }
+ Dictionary get_state() const;
+ void set_state(const Dictionary& p_state);
+
+
void ensure_visibility();
void set_undo_redo(UndoRedo *p_undo_redo) { undo_redo=p_undo_redo; }
@@ -167,6 +200,9 @@ class AnimationPlayerEditorPlugin : public EditorPlugin {
public:
+ virtual Dictionary get_state() const { return anim_editor->get_state(); }
+ virtual void set_state(const Dictionary& p_state) { anim_editor->set_state(p_state); }
+
virtual String get_name() const { return "Anim"; }
bool has_main_screen() const { return false; }
virtual void edit(Object *p_node);
diff --git a/tools/editor/plugins/animation_tree_editor_plugin.cpp b/tools/editor/plugins/animation_tree_editor_plugin.cpp
index 382bc44726..d85553b4db 100644
--- a/tools/editor/plugins/animation_tree_editor_plugin.cpp
+++ b/tools/editor/plugins/animation_tree_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -1498,18 +1498,17 @@ bool AnimationTreeEditorPlugin::handles(Object *p_object) const {
void AnimationTreeEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
- editor->hide_animation_player_editors();
- editor->animation_panel_make_visible(true);
- anim_tree_editor->show();
+// editor->hide_animation_player_editors();
+// editor->animation_panel_make_visible(true);
+ button->show();
+ editor->make_bottom_panel_item_visible(anim_tree_editor);
anim_tree_editor->set_fixed_process(true);
- EditorNode::get_top_split()->set_collapsed(false);
-
} else {
- anim_tree_editor->hide();
+ if (anim_tree_editor->is_visible())
+ editor->hide_bottom_panel();
+ button->hide();
anim_tree_editor->set_fixed_process(false);
- editor->animation_panel_make_visible(false);
- EditorNode::get_top_split()->set_collapsed(true);
}
}
@@ -1517,12 +1516,10 @@ AnimationTreeEditorPlugin::AnimationTreeEditorPlugin(EditorNode *p_node) {
editor=p_node;
anim_tree_editor = memnew( AnimationTreeEditor );
- //editor->get_viewport()->add_child(anim_tree_editor);
- //anim_tree_editor->set_area_as_parent_rect();
- editor->get_animation_panel()->add_child(anim_tree_editor);
- anim_tree_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- anim_tree_editor->hide();
+ anim_tree_editor->set_custom_minimum_size(Size2(0,300));
+ button=editor->add_bottom_panel_item("AnimationTree",anim_tree_editor);
+ button->hide();
diff --git a/tools/editor/plugins/animation_tree_editor_plugin.h b/tools/editor/plugins/animation_tree_editor_plugin.h
index bd29530c7a..4884a22d90 100644
--- a/tools/editor/plugins/animation_tree_editor_plugin.h
+++ b/tools/editor/plugins/animation_tree_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -176,6 +176,7 @@ class AnimationTreeEditorPlugin : public EditorPlugin {
AnimationTreeEditor *anim_tree_editor;
EditorNode *editor;
+ Button *button;
public:
diff --git a/tools/editor/plugins/camera_editor_plugin.cpp b/tools/editor/plugins/camera_editor_plugin.cpp
index 08ed2c745d..7433264b16 100644
--- a/tools/editor/plugins/camera_editor_plugin.cpp
+++ b/tools/editor/plugins/camera_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/plugins/camera_editor_plugin.h b/tools/editor/plugins/camera_editor_plugin.h
index afb8f9415d..ea016ecb4d 100644
--- a/tools/editor/plugins/camera_editor_plugin.h
+++ b/tools/editor/plugins/camera_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/plugins/canvas_item_editor_plugin.cpp b/tools/editor/plugins/canvas_item_editor_plugin.cpp
index f2738f0a62..a259fa0fcc 100644
--- a/tools/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/tools/editor/plugins/canvas_item_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -37,13 +37,15 @@
#include "os/input.h"
#include "tools/editor/editor_settings.h"
#include "scene/gui/grid_container.h"
+#include "tools/editor/animation_editor.h"
+#include "tools/editor/plugins/animation_player_editor_plugin.h"
class SnapDialog : public ConfirmationDialog {
OBJ_TYPE(SnapDialog,ConfirmationDialog);
-
-protected:
- friend class CanvasItemEditor;
+
+friend class CanvasItemEditor;
+
SpinBox *grid_offset_x;
SpinBox *grid_offset_y;
SpinBox *grid_step_x;
@@ -58,63 +60,75 @@ public:
Label *label;
VBoxContainer *container;
GridContainer *child_container;
-
+
set_title("Configure Snap");
get_ok()->set_text("Close");
- container = memnew(VBoxContainer);
+
+ container = memnew( VBoxContainer );
add_child(container);
-
- child_container = memnew(GridContainer);
+ set_child_rect(container);
+
+ child_container = memnew( GridContainer );
child_container->set_columns(3);
container->add_child(child_container);
-
- label = memnew(Label);
+
+ label = memnew( Label );
label->set_text("Grid Offset:");
child_container->add_child(label);
- grid_offset_x=memnew(SpinBox);
+ label->set_h_size_flags(SIZE_EXPAND_FILL);
+
+ grid_offset_x = memnew( SpinBox );
grid_offset_x->set_min(-SPIN_BOX_GRID_RANGE);
grid_offset_x->set_max(SPIN_BOX_GRID_RANGE);
grid_offset_x->set_suffix("px");
child_container->add_child(grid_offset_x);
- grid_offset_y=memnew(SpinBox);
+
+ grid_offset_y = memnew( SpinBox );
grid_offset_y->set_min(-SPIN_BOX_GRID_RANGE);
grid_offset_y->set_max(SPIN_BOX_GRID_RANGE);
grid_offset_y->set_suffix("px");
child_container->add_child(grid_offset_y);
- label = memnew(Label);
+ label = memnew( Label );
label->set_text("Grid Step:");
child_container->add_child(label);
- grid_step_x=memnew(SpinBox);
+ label->set_h_size_flags(SIZE_EXPAND_FILL);
+
+ grid_step_x = memnew( SpinBox );
grid_step_x->set_min(-SPIN_BOX_GRID_RANGE);
grid_step_x->set_max(SPIN_BOX_GRID_RANGE);
grid_step_x->set_suffix("px");
child_container->add_child(grid_step_x);
- grid_step_y=memnew(SpinBox);
+
+ grid_step_y = memnew( SpinBox );
grid_step_y->set_min(-SPIN_BOX_GRID_RANGE);
grid_step_y->set_max(SPIN_BOX_GRID_RANGE);
grid_step_y->set_suffix("px");
child_container->add_child(grid_step_y);
-
- container->add_child(memnew(HSeparator));
- child_container = memnew(GridContainer);
+ container->add_child( memnew( HSeparator ) );
+
+ child_container = memnew( GridContainer );
child_container->set_columns(2);
container->add_child(child_container);
- label = memnew(Label);
+ label = memnew( Label );
label->set_text("Rotation Offset:");
child_container->add_child(label);
- rotation_offset=memnew(SpinBox);
+ label->set_h_size_flags(SIZE_EXPAND_FILL);
+
+ rotation_offset = memnew( SpinBox );
rotation_offset->set_min(-SPIN_BOX_ROTATION_RANGE);
rotation_offset->set_max(SPIN_BOX_ROTATION_RANGE);
rotation_offset->set_suffix("deg");
child_container->add_child(rotation_offset);
-
- label = memnew(Label);
+
+ label = memnew( Label );
label->set_text("Rotation Step:");
child_container->add_child(label);
- rotation_step=memnew(SpinBox);
+ label->set_h_size_flags(SIZE_EXPAND_FILL);
+
+ rotation_step = memnew( SpinBox );
rotation_step->set_min(-SPIN_BOX_ROTATION_RANGE);
rotation_step->set_max(SPIN_BOX_ROTATION_RANGE);
rotation_step->set_suffix("deg");
@@ -140,9 +154,52 @@ public:
}
};
+void CanvasItemEditor::_edit_set_pivot(const Vector2& mouse_pos) {
+ List<Node*> &selection = editor_selection->get_selected_node_list();
+
+ undo_redo->create_action("Move Pivot");
+
+ for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
+
+ Node2D *n2d = E->get()->cast_to<Node2D>();
+
+ if (n2d && n2d->edit_has_pivot()) {
+
+ Vector2 offset = n2d->edit_get_pivot();
+ Vector2 gpos = n2d->get_global_pos();
+
+ Vector2 local_mouse_pos = n2d->get_canvas_transform().affine_inverse().xform(mouse_pos);
+
+ Vector2 motion_ofs = gpos-local_mouse_pos;
+
+ undo_redo->add_do_method(n2d,"set_global_pos",local_mouse_pos);
+ undo_redo->add_do_method(n2d,"edit_set_pivot",offset+n2d->get_global_transform().affine_inverse().basis_xform(motion_ofs));
+ undo_redo->add_undo_method(n2d,"set_global_pos",gpos);
+ undo_redo->add_undo_method(n2d,"edit_set_pivot",offset);
+ for(int i=0;i<n2d->get_child_count();i++) {
+ Node2D *n2dc = n2d->get_child(i)->cast_to<Node2D>();
+ if (!n2dc)
+ continue;
+
+ undo_redo->add_do_method(n2dc,"set_global_pos",n2dc->get_global_pos());
+ undo_redo->add_undo_method(n2dc,"set_global_pos",n2dc->get_global_pos());
+
+ }
+
+ }
+
+ }
+
+ undo_redo->commit_action();
+
+}
+
void CanvasItemEditor::_unhandled_key_input(const InputEvent& p_ev) {
- if (!is_visible())
+ if (!is_visible() || get_viewport()->gui_has_modal_stack())
+ return;
+ if (p_ev.key.mod.control)
+ // prevent to change tool mode when control key is pressed
return;
if (p_ev.key.pressed && !p_ev.key.echo && p_ev.key.scancode==KEY_Q)
_tool_select(TOOL_SELECT);
@@ -164,38 +221,7 @@ void CanvasItemEditor::_unhandled_key_input(const InputEvent& p_ev) {
mouse_pos=transform.affine_inverse().xform(mouse_pos);
mouse_pos=snap_point(mouse_pos);
- undo_redo->create_action("Move Pivot");
-
- for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
-
- Node2D *n2d = E->get()->cast_to<Node2D>();
-
- if (n2d && n2d->edit_has_pivot()) {
-
- Vector2 offset = n2d->edit_get_pivot();
- Vector2 gpos = n2d->get_global_pos();
-
- Vector2 motion_ofs = gpos-mouse_pos;
-
- undo_redo->add_do_method(n2d,"set_global_pos",mouse_pos);
- undo_redo->add_do_method(n2d,"edit_set_pivot",offset+n2d->get_global_transform().affine_inverse().basis_xform(motion_ofs));
- undo_redo->add_undo_method(n2d,"set_global_pos",gpos);
- undo_redo->add_undo_method(n2d,"edit_set_pivot",offset);
- for(int i=0;i<n2d->get_child_count();i++) {
- Node2D *n2dc = n2d->get_child(i)->cast_to<Node2D>();
- if (!n2dc)
- continue;
-
- undo_redo->add_do_method(n2dc,"set_global_pos",n2dc->get_global_pos());
- undo_redo->add_undo_method(n2dc,"set_global_pos",n2dc->get_global_pos());
-
- }
-
- }
-
- }
-
- undo_redo->commit_action();
+ _edit_set_pivot(mouse_pos);
}
}
@@ -206,7 +232,7 @@ void CanvasItemEditor::_unhandled_key_input(const InputEvent& p_ev) {
void CanvasItemEditor::_tool_select(int p_index) {
- ToolButton *tb[TOOL_MAX]={select_button,move_button,rotate_button,pan_button};
+ ToolButton *tb[TOOL_MAX]={select_button,list_select_button,move_button,rotate_button,pivot_button,pan_button};
for(int i=0;i<TOOL_MAX;i++) {
tb[i]->set_pressed(i==p_index);
@@ -381,9 +407,9 @@ void CanvasItemEditor::_node_removed(Node *p_node) {
#endif
}
-void CanvasItemEditor::_keying_changed(bool p_changed) {
+void CanvasItemEditor::_keying_changed() {
- if (p_changed)
+ if (AnimationPlayerEditor::singleton->get_key_editor()->has_keying())
animation_hb->show();
else
animation_hb->hide();
@@ -408,8 +434,6 @@ CanvasItem* CanvasItemEditor::_select_canvas_item_at_pos(const Point2& p_pos,Nod
r=_select_canvas_item_at_pos(p_pos,p_node->get_child(i),p_parent_xform * c->get_transform(),p_canvas_xform);
else {
CanvasLayer *cl = p_node->cast_to<CanvasLayer>();
- if (cl)
- return NULL;
r=_select_canvas_item_at_pos(p_pos,p_node->get_child(i),transform ,cl ? cl->get_transform() : p_canvas_xform); //use base transform
}
@@ -418,7 +442,7 @@ CanvasItem* CanvasItemEditor::_select_canvas_item_at_pos(const Point2& p_pos,Nod
}
- if (c && c->is_visible() && !c->has_meta("_edit_lock_")) {
+ if (c && c->is_visible() && !c->has_meta("_edit_lock_") && !c->cast_to<CanvasLayer>()) {
Rect2 rect = c->get_item_rect();
Point2 local_pos = (p_parent_xform * p_canvas_xform * c->get_transform()).affine_inverse().xform(p_pos);
@@ -432,6 +456,45 @@ CanvasItem* CanvasItemEditor::_select_canvas_item_at_pos(const Point2& p_pos,Nod
return NULL;
}
+void CanvasItemEditor::_find_canvas_items_at_pos(const Point2 &p_pos,Node* p_node,const Matrix32& p_parent_xform,const Matrix32& p_canvas_xform, Vector<_SelectResult> &r_items) {
+ if (!p_node)
+ return;
+ if (p_node->cast_to<Viewport>())
+ return;
+
+ CanvasItem *c=p_node->cast_to<CanvasItem>();
+
+ for (int i=p_node->get_child_count()-1;i>=0;i--) {
+
+ if (c && !c->is_set_as_toplevel())
+ _find_canvas_items_at_pos(p_pos,p_node->get_child(i),p_parent_xform * c->get_transform(),p_canvas_xform, r_items);
+ else {
+ CanvasLayer *cl = p_node->cast_to<CanvasLayer>();
+ _find_canvas_items_at_pos(p_pos,p_node->get_child(i),transform ,cl ? cl->get_transform() : p_canvas_xform, r_items); //use base transform
+ }
+ }
+
+
+ if (c && c->is_visible() && !c->has_meta("_edit_lock_") && !c->cast_to<CanvasLayer>()) {
+
+ Rect2 rect = c->get_item_rect();
+ Point2 local_pos = (p_parent_xform * p_canvas_xform * c->get_transform()).affine_inverse().xform(p_pos);
+
+
+ if (rect.has_point(local_pos)) {
+ Node2D *node=c->cast_to<Node2D>();
+
+ _SelectResult res;
+ res.item=c;
+ res.z=node?node->get_z():0;
+ res.has_z=node;
+ r_items.push_back(res);
+ }
+
+ }
+
+ return;
+}
void CanvasItemEditor::_find_canvas_items_at_rect(const Rect2& p_rect,Node* p_node,const Matrix32& p_parent_xform,const Matrix32& p_canvas_xform,List<CanvasItem*> *r_items) {
@@ -449,14 +512,12 @@ void CanvasItemEditor::_find_canvas_items_at_rect(const Rect2& p_rect,Node* p_no
_find_canvas_items_at_rect(p_rect,p_node->get_child(i),p_parent_xform * c->get_transform(),p_canvas_xform,r_items);
else {
CanvasLayer *cl = p_node->cast_to<CanvasLayer>();
- if (cl)
- return;
_find_canvas_items_at_rect(p_rect,p_node->get_child(i),transform,cl?cl->get_transform():p_canvas_xform,r_items);
}
}
- if (c && c->is_visible() && !c->has_meta("_edit_lock_")) {
+ if (c && c->is_visible() && !c->has_meta("_edit_lock_") && !c->cast_to<CanvasLayer>()) {
Rect2 rect = c->get_item_rect();
Matrix32 xform = p_parent_xform * p_canvas_xform * c->get_transform();
@@ -474,6 +535,96 @@ void CanvasItemEditor::_find_canvas_items_at_rect(const Rect2& p_rect,Node* p_no
}
+bool CanvasItemEditor::_select(CanvasItem *item, Point2 p_click_pos, bool p_append, bool p_drag) {
+
+ if (p_append) {
+ //additive selection
+
+ if (!item) {
+
+ if (p_drag) {
+ drag_from=transform.affine_inverse().xform(p_click_pos);
+
+ box_selecting=true;
+ box_selecting_to=drag_from;
+ }
+
+ return false; //nothing to add
+ }
+
+ if (editor_selection->is_selected(item)) {
+ //already in here, erase it
+ editor_selection->remove_node(item);
+ //_remove_canvas_item(c);
+
+ viewport->update();
+ return false;
+
+ }
+ _append_canvas_item(item);
+ viewport->update();
+
+ } else {
+ //regular selection
+
+ if (!item) {
+ //clear because nothing clicked
+ editor_selection->clear();;
+
+ if (p_drag) {
+ drag_from=transform.affine_inverse().xform(p_click_pos);
+
+ box_selecting=true;
+ box_selecting_to=drag_from;
+ }
+
+ viewport->update();
+ return false;
+ }
+
+ if (!editor_selection->is_selected(item)) {
+ //select a new one and clear previous selection
+ editor_selection->clear();
+ editor_selection->add_node(item);
+ //reselect
+ if (get_tree()->is_editor_hint()) {
+ editor->call("edit_node",item);
+ }
+
+ }
+
+ if (p_drag) {
+ //prepare to move!
+
+ List<Node*> &selection = editor_selection->get_selected_node_list();
+
+ for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
+
+ CanvasItem *canvas_item = E->get()->cast_to<CanvasItem>();
+ if (!canvas_item || !canvas_item->is_visible())
+ continue;
+ CanvasItemEditorSelectedItem *se=editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
+ if (!se)
+ continue;
+
+ se->undo_state=canvas_item->edit_get_state();
+ if (canvas_item->cast_to<Node2D>())
+ se->undo_pivot=canvas_item->cast_to<Node2D>()->edit_get_pivot();
+
+ }
+
+ drag=DRAG_ALL;
+ drag_from=transform.affine_inverse().xform(p_click_pos);
+ drag_point_from=_find_topleftmost_point();
+ }
+
+ viewport->update();
+
+ return true;
+
+ }
+}
+
void CanvasItemEditor::_key_move(const Vector2& p_dir, bool p_snap, KeyMoveMODE p_move_mode) {
@@ -773,6 +924,24 @@ void CanvasItemEditor::_dialog_value_changed(double) {
}
}
+void CanvasItemEditor::_selection_result_pressed(int p_result) {
+
+ if (selection_results.size() <= p_result)
+ return;
+
+ CanvasItem *item=selection_results[p_result].item;
+
+ if (item)
+ _select(item, Point2(), additive_selection, false);
+}
+
+void CanvasItemEditor::_selection_menu_hide() {
+
+ selection_results.clear();
+ selection_menu->clear();
+ selection_menu->set_size(Vector2(0, 0));
+}
+
bool CanvasItemEditor::get_remove_list(List<Node*> *p_list) {
@@ -780,6 +949,75 @@ bool CanvasItemEditor::get_remove_list(List<Node*> *p_list) {
}
+void CanvasItemEditor::_list_select(const InputEventMouseButton& b) {
+
+ Point2 click=Point2(b.x,b.y);
+
+ Node* scene = editor->get_edited_scene();
+ if (!scene)
+ return;
+
+ _find_canvas_items_at_pos(click, scene,transform,Matrix32(), selection_results);
+
+ for(int i=0;i<selection_results.size();i++) {
+ CanvasItem *item=selection_results[i].item;
+ if (item!=scene && item->get_owner()!=scene && !scene->is_editable_instance(item->get_owner())) {
+ //invalid result
+ selection_results.remove(i);
+ i--;
+ }
+
+ }
+
+ if (selection_results.size() == 1) {
+
+ CanvasItem *item = selection_results[0].item;
+ selection_results.clear();
+
+ additive_selection=b.mod.shift;
+ if (!_select(item, click, additive_selection, false))
+ return;
+
+ } else if (!selection_results.empty()) {
+
+ selection_results.sort();
+
+ NodePath root_path = get_tree()->get_edited_scene_root()->get_path();
+ StringName root_name = root_path.get_name(root_path.get_name_count()-1);
+
+ for (int i = 0; i < selection_results.size(); i++) {
+
+ CanvasItem *item=selection_results[i].item;
+
+
+ Ref<Texture> icon;
+ if (item->has_meta("_editor_icon"))
+ icon=item->get_meta("_editor_icon");
+ else
+ icon=get_icon( has_icon(item->get_type(),"EditorIcons")?item->get_type():String("Object"),"EditorIcons");
+
+ String node_path="/"+root_name+"/"+root_path.rel_path_to(item->get_path());
+
+ selection_menu->add_item(item->get_name());
+ selection_menu->set_item_icon(i, icon );
+ selection_menu->set_item_metadata(i, node_path);
+ selection_menu->set_item_tooltip(i,String(item->get_name())+
+ "\nType: "+item->get_type()+"\nPath: "+node_path);
+ }
+
+ additive_selection=b.mod.shift;
+
+ selection_menu->set_global_pos(Vector2( b.global_x, b.global_y ));
+ selection_menu->popup();
+ selection_menu->call_deferred("grab_click_focus");
+ selection_menu->set_invalidate_click_until_motion();
+
+
+ return;
+ }
+
+}
+
void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
{
@@ -836,6 +1074,11 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
if (b.button_index==BUTTON_RIGHT) {
+ if (b.pressed && (tool==TOOL_SELECT && b.mod.alt)) {
+
+ _list_select(b);
+ return;
+ }
if (get_item_count() > 0 && drag!=DRAG_NONE) {
//cancel drag
@@ -892,6 +1135,26 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
//if (!canvas_items.size())
// return;
+ if (b.button_index==BUTTON_LEFT && tool==TOOL_LIST_SELECT) {
+ if (b.pressed)
+ _list_select(b);
+ return;
+ }
+
+
+ if (b.button_index==BUTTON_LEFT && tool==TOOL_EDIT_PIVOT) {
+ if (b.pressed) {
+
+ Point2 mouse_pos(b.x,b.y);
+ mouse_pos=transform.affine_inverse().xform(mouse_pos);
+ mouse_pos=snap_point(mouse_pos);
+ _edit_set_pivot(mouse_pos);
+ }
+ return;
+ }
+
+
+
if (tool==TOOL_PAN || b.button_index!=BUTTON_LEFT || Input::get_singleton()->is_key_pressed(KEY_SPACE))
return;
@@ -1200,88 +1463,16 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
#if 0
if ( b.pressed ) box_selection_start( click );
#endif
- if (b.mod.shift) { //additive selection
-
- if (!c) {
- drag_from=transform.affine_inverse().xform(click);
-
- box_selecting=true;
- box_selecting_to=drag_from;
-
- return; //nothing to add
- }
-
- if (editor_selection->is_selected(c)) {
- //already in here, erase it
- editor_selection->remove_node(c);
- //_remove_canvas_item(c);
-
- viewport->update();
- return;
-
- }
- _append_canvas_item(c);
- viewport->update();
- } else {
- //regular selection
-
-
-
- if (!c) {
- //clear because nothing clicked
- editor_selection->clear();;
-
- drag_from=transform.affine_inverse().xform(click);
-
- box_selecting=true;
- box_selecting_to=drag_from;
- viewport->update();
- return;
- }
-
- if (!editor_selection->is_selected(c)) {
- //select a new one and clear previous selection
- editor_selection->clear();
- editor_selection->add_node(c);
- //reselect
- if (get_tree()->is_editor_hint()) {
- editor->call("edit_node",c);
- }
-
- }
-
- //prepare to move!
-
- List<Node*> &selection = editor_selection->get_selected_node_list();
-
- for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
-
- CanvasItem *canvas_item = E->get()->cast_to<CanvasItem>();
- if (!canvas_item || !canvas_item->is_visible())
- continue;
- CanvasItemEditorSelectedItem *se=editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
- if (!se)
- continue;
-
- se->undo_state=canvas_item->edit_get_state();
- if (canvas_item->cast_to<Node2D>())
- se->undo_pivot=canvas_item->cast_to<Node2D>()->edit_get_pivot();
-
- }
-
- drag=DRAG_ALL;
- drag_from=transform.affine_inverse().xform(click);
- drag_point_from=_find_topleftmost_point();
- viewport->update();
-
- }
+ additive_selection=b.mod.shift;
+ if (!_select(c, click, additive_selection))
+ return;
}
if (p_event.type==InputEvent::MOUSE_MOTION) {
- if (!viewport->has_focus())
+ if (!viewport->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field()))
viewport->call_deferred("grab_focus");
const InputEventMouseMotion &m=p_event.mouse_motion;
@@ -1343,7 +1534,7 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
Matrix32 rot;
rot.elements[1] = (dfrom - center).normalized();
rot.elements[0] = rot.elements[1].tangent();
- node->set_rot(snap_angle(rot.xform_inv(dto-center).atan2(), node->get_rot()));
+ node->set_rot(snap_angle(rot.xform_inv(dto-center).angle(), node->get_rot()));
display_rotate_to = dto;
display_rotate_from = center;
viewport->update();
@@ -1352,6 +1543,7 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
continue;
}
+
dfrom = drag_point_from;
dto = snap_point(dto - (drag == DRAG_ALL ? drag_from - drag_point_from : Vector2(0, 0)), drag_point_from);
@@ -1359,30 +1551,35 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
canvas_item->get_global_transform_with_canvas().affine_inverse().xform(dto) -
canvas_item->get_global_transform_with_canvas().affine_inverse().xform(dfrom);
-
Rect2 local_rect = canvas_item->get_item_rect();
-
- if (false && drag!=DRAG_ALL && m.mod.alt) {
- float aspect = local_rect.size.get_aspect();
- if (aspect!=0) {
- if (ABS(drag_vector.x) > ABS(drag_vector.y)) {
-
- drag_vector.y = ABS(drag_vector.x)/aspect * SGN(drag_vector.y);
- } else {
-
- drag_vector.x = ABS(drag_vector.y)*aspect * SGN(drag_vector.x);
- }
- }
- }
-
-
-
Vector2 begin=local_rect.pos;
Vector2 end=local_rect.pos+local_rect.size;
Vector2 minsize = canvas_item->edit_get_minimum_size();
bool uniform = m.mod.shift;
bool symmetric=m.mod.alt;
+ if (uniform) {
+ float aspect = local_rect.size.get_aspect();
+ switch(drag) {
+ case DRAG_BOTTOM_LEFT:
+ case DRAG_TOP_RIGHT: {
+ if (aspect > 1.0) { // width > height, take x as reference
+ drag_vector.y = -drag_vector.x/aspect;
+ } else { // height > width, take y as reference
+ drag_vector.x = -drag_vector.y*aspect;
+ }
+ } break;
+ case DRAG_BOTTOM_RIGHT:
+ case DRAG_TOP_LEFT: {
+ if (aspect > 1.0) { // width > height, take x as reference
+ drag_vector.y = drag_vector.x/aspect;
+ } else { // height > width, take y as reference
+ drag_vector.x = drag_vector.y*aspect;
+ }
+ } break;
+ default: {}
+ }
+ }
switch(drag) {
case DRAG_ALL: {
@@ -1401,19 +1598,11 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
} break;
case DRAG_BOTTOM_RIGHT: {
- if (uniform) {
- drag_vector.y=drag_vector.x;
- minsize.y=minsize.x;
- }
incend(begin.x,end.x,drag_vector.x,minsize.x,symmetric);
incend(begin.y,end.y,drag_vector.y,minsize.y,symmetric);
- } break;
+ } break;
case DRAG_TOP_LEFT: {
- if (uniform) {
- drag_vector.y=drag_vector.x;
- minsize.y=minsize.x;
- }
incbeg(begin.x,end.x,drag_vector.x,minsize.x,symmetric);
incbeg(begin.y,end.y,drag_vector.y,minsize.y,symmetric);
} break;
@@ -1429,20 +1618,12 @@ void CanvasItemEditor::_viewport_input_event(const InputEvent& p_event) {
} break;
case DRAG_TOP_RIGHT: {
- if (uniform) {
- drag_vector.x=-drag_vector.y;
- minsize.x=minsize.y;
- }
incbeg(begin.y,end.y,drag_vector.y,minsize.y,symmetric);
incend(begin.x,end.x,drag_vector.x,minsize.x,symmetric);
} break;
case DRAG_BOTTOM_LEFT: {
- if (uniform) {
- drag_vector.x=-drag_vector.y;
- minsize.x=minsize.y;
- }
incbeg(begin.x,end.x,drag_vector.x,minsize.x,symmetric);
incend(begin.y,end.y,drag_vector.y,minsize.y,symmetric);
} break;
@@ -1692,6 +1873,8 @@ void CanvasItemEditor::_viewport_draw() {
CanvasItem *single_item=NULL;
+ bool pivot_found=false;
+
for(Map<Node*,Object*>::Element *E=selection.front();E;E=E->next()) {
@@ -1733,7 +1916,7 @@ void CanvasItemEditor::_viewport_draw() {
viewport->draw_line(endpoints[i],endpoints[(i+1)%4],c,2);
}
- if (single && (tool==TOOL_SELECT || tool == TOOL_MOVE || tool == TOOL_ROTATE)) { //kind of sucks
+ if (single && (tool==TOOL_SELECT || tool == TOOL_MOVE || tool == TOOL_ROTATE || tool==TOOL_EDIT_PIVOT)) { //kind of sucks
if (canvas_item->cast_to<Node2D>()) {
@@ -1741,6 +1924,7 @@ void CanvasItemEditor::_viewport_draw() {
if (canvas_item->cast_to<Node2D>()->edit_has_pivot()) {
viewport->draw_texture(pivot,xform.get_origin()+(-pivot->get_size()/2).floor());
can_move_pivot=true;
+ pivot_found=true;
}
}
@@ -1775,6 +1959,7 @@ void CanvasItemEditor::_viewport_draw() {
//E->get().last_rect = rect;
}
+ pivot_button->set_disabled(!pivot_found);
VisualServer::get_singleton()->canvas_item_add_set_transform(ci,Matrix32());
@@ -1910,12 +2095,20 @@ void CanvasItemEditor::_notification(int p_what) {
List<Node*> &selection = editor_selection->get_selected_node_list();
+ bool all_control=true;
+ bool has_control=false;
+
for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
CanvasItem *canvas_item = E->get()->cast_to<CanvasItem>();
if (!canvas_item || !canvas_item->is_visible())
continue;
+ if (canvas_item->cast_to<Control>())
+ has_control=true;
+ else
+ all_control=false;
+
CanvasItemEditorSelectedItem *se=editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(canvas_item);
if (!se)
continue;
@@ -1932,6 +2125,13 @@ void CanvasItemEditor::_notification(int p_what) {
}
+ bool show_anchor = all_control && has_control;
+ if (show_anchor != !anchor_menu->is_hidden()) {
+ if (show_anchor)
+ anchor_menu->show();
+ else
+ anchor_menu->hide();
+ }
for(Map<ObjectID,BoneList>::Element *E=bone_list.front();E;E=E->next()) {
@@ -1964,9 +2164,11 @@ void CanvasItemEditor::_notification(int p_what) {
}
select_button->set_icon( get_icon("ToolSelect","EditorIcons"));
+ list_select_button->set_icon( get_icon("ListSelect","EditorIcons"));
move_button->set_icon( get_icon("ToolMove","EditorIcons"));
rotate_button->set_icon( get_icon("ToolRotate","EditorIcons"));
pan_button->set_icon( get_icon("ToolPan", "EditorIcons"));
+ pivot_button->set_icon( get_icon("EditPivot", "EditorIcons"));
select_handle=get_icon("EditorHandle","EditorIcons");
lock_button->set_icon(get_icon("Lock","EditorIcons"));
unlock_button->set_icon(get_icon("Unlock","EditorIcons"));
@@ -1974,6 +2176,32 @@ void CanvasItemEditor::_notification(int p_what) {
ungroup_button->set_icon(get_icon("Ungroup","EditorIcons"));
key_insert_button->set_icon(get_icon("Key","EditorIcons"));
+
+ //anchor_menu->add_icon_override("Align Top Left");
+ anchor_menu->set_icon(get_icon("Anchor","EditorIcons"));
+ PopupMenu *p=anchor_menu->get_popup();
+
+ p->add_icon_item(get_icon("ControlAlignTopLeft","EditorIcons"),"Top Left",ANCHOR_ALIGN_TOP_LEFT);
+ p->add_icon_item(get_icon("ControlAlignTopRight","EditorIcons"),"Top Right",ANCHOR_ALIGN_TOP_RIGHT);
+ p->add_icon_item(get_icon("ControlAlignBottomRight","EditorIcons"),"Bottom Right",ANCHOR_ALIGN_BOTTOM_RIGHT);
+ p->add_icon_item(get_icon("ControlAlignBottomLeft","EditorIcons"),"Bottom Left",ANCHOR_ALIGN_BOTTOM_LEFT);
+ p->add_separator();
+ p->add_icon_item(get_icon("ControlAlignLeftCenter","EditorIcons"),"Center Left",ANCHOR_ALIGN_CENTER_LEFT);
+ p->add_icon_item(get_icon("ControlAlignTopCenter","EditorIcons"),"Center Top",ANCHOR_ALIGN_CENTER_TOP);
+ p->add_icon_item(get_icon("ControlAlignRightCenter","EditorIcons"),"Center Right",ANCHOR_ALIGN_CENTER_RIGHT);
+ p->add_icon_item(get_icon("ControlAlignBottomCenter","EditorIcons"),"Center Bottom",ANCHOR_ALIGN_CENTER_BOTTOM);
+ p->add_icon_item(get_icon("ControlAlignCenter","EditorIcons"),"Center",ANCHOR_ALIGN_CENTER);
+ p->add_separator();
+ p->add_icon_item(get_icon("ControlAlignLeftWide","EditorIcons"),"Left Wide",ANCHOR_ALIGN_LEFT_WIDE);
+ p->add_icon_item(get_icon("ControlAlignTopWide","EditorIcons"),"Top Wide",ANCHOR_ALIGN_TOP_WIDE);
+ p->add_icon_item(get_icon("ControlAlignRightWide","EditorIcons"),"Right Wide",ANCHOR_ALIGN_RIGHT_WIDE);
+ p->add_icon_item(get_icon("ControlAlignBottomWide","EditorIcons"),"Bottom Wide",ANCHOR_ALIGN_BOTTOM_WIDE);
+ p->add_icon_item(get_icon("ControlVcenterWide","EditorIcons"),"VCenter Wide ",ANCHOR_ALIGN_VCENTER_WIDE);
+ p->add_icon_item(get_icon("ControlHcenterWide","EditorIcons"),"HCenter Wide ",ANCHOR_ALIGN_HCENTER_WIDE);
+ p->add_separator();
+ p->add_icon_item(get_icon("ControlAlignWide","EditorIcons"),"Full Rect",ANCHOR_ALIGN_WIDE);
+
+
}
if (p_what==NOTIFICATION_READY) {
@@ -2179,6 +2407,27 @@ void CanvasItemEditor::_update_scroll(float) {
}
+void CanvasItemEditor::_set_anchor(Control::AnchorType p_left,Control::AnchorType p_top,Control::AnchorType p_right,Control::AnchorType p_bottom) {
+ List<Node*> &selection = editor_selection->get_selected_node_list();
+
+ undo_redo->create_action("Change Anchors");
+ for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
+
+ Control *c = E->get()->cast_to<Control>();
+
+ undo_redo->add_do_method(c,"set_anchor",MARGIN_LEFT,p_left);
+ undo_redo->add_do_method(c,"set_anchor",MARGIN_TOP,p_top);
+ undo_redo->add_do_method(c,"set_anchor",MARGIN_RIGHT,p_right);
+ undo_redo->add_do_method(c,"set_anchor",MARGIN_BOTTOM,p_bottom);
+ undo_redo->add_undo_method(c,"set_anchor",MARGIN_LEFT,c->get_anchor(MARGIN_LEFT));
+ undo_redo->add_undo_method(c,"set_anchor",MARGIN_TOP,c->get_anchor(MARGIN_TOP));
+ undo_redo->add_undo_method(c,"set_anchor",MARGIN_RIGHT,c->get_anchor(MARGIN_RIGHT));
+ undo_redo->add_undo_method(c,"set_anchor",MARGIN_BOTTOM,c->get_anchor(MARGIN_BOTTOM));
+ }
+
+ undo_redo->commit_action();
+
+}
void CanvasItemEditor::_popup_callback(int p_op) {
@@ -2213,7 +2462,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
} break;
case SNAP_CONFIGURE: {
((SnapDialog *)snap_dialog)->set_fields(snap_offset, snap_step, snap_rotation_offset, snap_rotation_step);
- snap_dialog->popup_centered(Size2(200,160));
+ snap_dialog->popup_centered(Size2(220,160));
} break;
case ZOOM_IN: {
zoom=zoom*(1.0/0.5);
@@ -2381,6 +2630,56 @@ void CanvasItemEditor::_popup_callback(int p_op) {
case SPACE_VERTICAL: {
//space_selected_items< proj_vector2_y, compare_items_y >();
} break;
+ case ANCHOR_ALIGN_TOP_LEFT: {
+ _set_anchor(ANCHOR_BEGIN,ANCHOR_BEGIN,ANCHOR_BEGIN,ANCHOR_BEGIN);
+ } break;
+ case ANCHOR_ALIGN_TOP_RIGHT: {
+ _set_anchor(ANCHOR_END,ANCHOR_BEGIN,ANCHOR_END,ANCHOR_BEGIN);
+ } break;
+ case ANCHOR_ALIGN_BOTTOM_LEFT: {
+ _set_anchor(ANCHOR_BEGIN,ANCHOR_END,ANCHOR_BEGIN,ANCHOR_END);
+ } break;
+ case ANCHOR_ALIGN_BOTTOM_RIGHT: {
+ _set_anchor(ANCHOR_END,ANCHOR_END,ANCHOR_END,ANCHOR_END);
+ } break;
+ case ANCHOR_ALIGN_CENTER_LEFT: {
+ _set_anchor(ANCHOR_BEGIN,ANCHOR_CENTER,ANCHOR_BEGIN,ANCHOR_CENTER);
+ } break;
+ case ANCHOR_ALIGN_CENTER_RIGHT: {
+
+ _set_anchor(ANCHOR_END,ANCHOR_CENTER,ANCHOR_END,ANCHOR_CENTER);
+ } break;
+ case ANCHOR_ALIGN_CENTER_TOP: {
+ _set_anchor(ANCHOR_CENTER,ANCHOR_BEGIN,ANCHOR_CENTER,ANCHOR_BEGIN);
+ } break;
+ case ANCHOR_ALIGN_CENTER_BOTTOM: {
+ _set_anchor(ANCHOR_CENTER,ANCHOR_END,ANCHOR_CENTER,ANCHOR_END);
+ } break;
+ case ANCHOR_ALIGN_CENTER: {
+ _set_anchor(ANCHOR_CENTER,ANCHOR_CENTER,ANCHOR_CENTER,ANCHOR_CENTER);
+ } break;
+ case ANCHOR_ALIGN_TOP_WIDE: {
+ _set_anchor(ANCHOR_BEGIN,ANCHOR_BEGIN,ANCHOR_END,ANCHOR_BEGIN);
+ } break;
+ case ANCHOR_ALIGN_LEFT_WIDE: {
+ _set_anchor(ANCHOR_BEGIN,ANCHOR_BEGIN,ANCHOR_BEGIN,ANCHOR_END);
+ } break;
+ case ANCHOR_ALIGN_RIGHT_WIDE: {
+ _set_anchor(ANCHOR_END,ANCHOR_BEGIN,ANCHOR_END,ANCHOR_END);
+ } break;
+ case ANCHOR_ALIGN_BOTTOM_WIDE: {
+ _set_anchor(ANCHOR_BEGIN,ANCHOR_END,ANCHOR_END,ANCHOR_END);
+ } break;
+ case ANCHOR_ALIGN_VCENTER_WIDE: {
+ _set_anchor(ANCHOR_CENTER,ANCHOR_BEGIN,ANCHOR_CENTER,ANCHOR_END);
+ } break;
+ case ANCHOR_ALIGN_HCENTER_WIDE: {
+ _set_anchor(ANCHOR_BEGIN,ANCHOR_CENTER,ANCHOR_END,ANCHOR_CENTER);
+ } break;
+ case ANCHOR_ALIGN_WIDE: {
+ _set_anchor(ANCHOR_BEGIN,ANCHOR_BEGIN,ANCHOR_END,ANCHOR_END);
+ } break;
+
case ANIM_INSERT_KEY:
case ANIM_INSERT_KEY_EXISTING: {
@@ -2398,11 +2697,11 @@ void CanvasItemEditor::_popup_callback(int p_op) {
Node2D *n2d = canvas_item->cast_to<Node2D>();
if (key_pos)
- editor->get_animation_editor()->insert_node_value_key(n2d,"transform/pos",n2d->get_pos(),existing);
+ AnimationPlayerEditor::singleton->get_key_editor()->insert_node_value_key(n2d,"transform/pos",n2d->get_pos(),existing);
if (key_rot)
- editor->get_animation_editor()->insert_node_value_key(n2d,"transform/rot",Math::rad2deg(n2d->get_rot()),existing);
+ AnimationPlayerEditor::singleton->get_key_editor()->insert_node_value_key(n2d,"transform/rot",Math::rad2deg(n2d->get_rot()),existing);
if (key_scale)
- editor->get_animation_editor()->insert_node_value_key(n2d,"transform/scale",n2d->get_scale(),existing);
+ AnimationPlayerEditor::singleton->get_key_editor()->insert_node_value_key(n2d,"transform/scale",n2d->get_scale(),existing);
if (n2d->has_meta("_edit_bone_") && n2d->get_parent_item()) {
@@ -2430,11 +2729,11 @@ void CanvasItemEditor::_popup_callback(int p_op) {
for(List<Node2D*>::Element *F=ik_chain.front();F;F=F->next()) {
if (key_pos)
- editor->get_animation_editor()->insert_node_value_key(F->get(),"transform/pos",F->get()->get_pos(),existing);
+ AnimationPlayerEditor::singleton->get_key_editor()->insert_node_value_key(F->get(),"transform/pos",F->get()->get_pos(),existing);
if (key_rot)
- editor->get_animation_editor()->insert_node_value_key(F->get(),"transform/rot",Math::rad2deg(F->get()->get_rot()),existing);
+ AnimationPlayerEditor::singleton->get_key_editor()->insert_node_value_key(F->get(),"transform/rot",Math::rad2deg(F->get()->get_rot()),existing);
if (key_scale)
- editor->get_animation_editor()->insert_node_value_key(F->get(),"transform/scale",F->get()->get_scale(),existing);
+ AnimationPlayerEditor::singleton->get_key_editor()->insert_node_value_key(F->get(),"transform/scale",F->get()->get_scale(),existing);
}
@@ -2446,9 +2745,9 @@ void CanvasItemEditor::_popup_callback(int p_op) {
Control *ctrl = canvas_item->cast_to<Control>();
if (key_pos)
- editor->get_animation_editor()->insert_node_value_key(ctrl,"rect/pos",ctrl->get_pos(),existing);
+ AnimationPlayerEditor::singleton->get_key_editor()->insert_node_value_key(ctrl,"rect/pos",ctrl->get_pos(),existing);
if (key_scale)
- editor->get_animation_editor()->insert_node_value_key(ctrl,"rect/size",ctrl->get_size(),existing);
+ AnimationPlayerEditor::singleton->get_key_editor()->insert_node_value_key(ctrl,"rect/size",ctrl->get_size(),existing);
}
}
@@ -2570,7 +2869,7 @@ void CanvasItemEditor::_popup_callback(int p_op) {
if (key_pos)
ctrl->set_pos(Point2());
//if (key_scale)
- // editor->get_animation_editor()->insert_node_value_key(ctrl,"rect/size",ctrl->get_size());
+ // AnimationPlayerEditor::singleton->get_key_editor()->insert_node_value_key(ctrl,"rect/size",ctrl->get_size());
}
}
@@ -2752,6 +3051,8 @@ void CanvasItemEditor::_bind_methods() {
ObjectTypeDB::bind_method("_viewport_draw",&CanvasItemEditor::_viewport_draw);
ObjectTypeDB::bind_method("_viewport_input_event",&CanvasItemEditor::_viewport_input_event);
ObjectTypeDB::bind_method("_snap_changed",&CanvasItemEditor::_snap_changed);
+ ObjectTypeDB::bind_method(_MD("_selection_result_pressed"),&CanvasItemEditor::_selection_result_pressed);
+ ObjectTypeDB::bind_method(_MD("_selection_menu_hide"),&CanvasItemEditor::_selection_menu_hide);
ADD_SIGNAL( MethodInfo("item_lock_status_changed") );
ADD_SIGNAL( MethodInfo("item_group_status_changed") );
@@ -2902,7 +3203,8 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
hb->add_child(select_button);
select_button->connect("pressed",this,"_tool_select",make_binds(TOOL_SELECT));
select_button->set_pressed(true);
- select_button->set_tooltip("Select Mode (Q)\n"+keycode_get_string(KEY_MASK_CMD)+"Drag: Rotate\nAlt+Drag: Move\nPress 'v' to Change Pivot, 'Shift+v' to Drag Pivot (while moving).");
+ select_button->set_tooltip("Select Mode (Q)\n"+keycode_get_string(KEY_MASK_CMD)+"Drag: Rotate\nAlt+Drag: Move\nPress 'v' to Change Pivot, 'Shift+v' to Drag Pivot (while moving).\nAlt+RMB: Depth list selection");
+
move_button = memnew( ToolButton );
move_button->set_toggle_mode(true);
@@ -2918,6 +3220,18 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
hb->add_child(memnew(VSeparator));
+ list_select_button = memnew( ToolButton );
+ list_select_button->set_toggle_mode(true);
+ hb->add_child(list_select_button);
+ list_select_button->connect("pressed",this,"_tool_select",make_binds(TOOL_LIST_SELECT));
+ list_select_button->set_tooltip("Show a list of all objects at the position clicked\n(same as Alt+RMB in selet mode).");
+
+ pivot_button = memnew( ToolButton );
+ pivot_button->set_toggle_mode(true);
+ hb->add_child(pivot_button);
+ pivot_button->connect("pressed",this,"_tool_select",make_binds(TOOL_EDIT_PIVOT));
+ pivot_button->set_tooltip("Click to change object's rotation pivot");
+
pan_button = memnew( ToolButton );
pan_button->set_toggle_mode(true);
hb->add_child(pan_button);
@@ -2999,6 +3313,14 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
p->add_item("Center Selection", VIEW_CENTER_TO_SELECTION, KEY_F);
p->add_item("Frame Selection", VIEW_FRAME_TO_SELECTION, KEY_MASK_CMD|KEY_F);
+ anchor_menu = memnew( MenuButton );
+ anchor_menu->set_text("Anchor");
+ hb->add_child(anchor_menu);
+ anchor_menu->get_popup()->connect("item_pressed", this,"_popup_callback");
+ anchor_menu->hide();
+
+ //p = anchor_menu->get_popup();
+
animation_hb = memnew( HBoxContainer );
@@ -3050,7 +3372,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
p->add_item("Paste Pose",ANIM_PASTE_POSE);
p->add_item("Clear Pose",ANIM_CLEAR_POSE,KEY_MASK_SHIFT|KEY_K);
- snap_dialog = memnew(SnapDialog);
+ snap_dialog = memnew( SnapDialog );
snap_dialog->connect("confirmed",this,"_snap_changed");
add_child(snap_dialog);
@@ -3073,6 +3395,12 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
dialog_val->connect("value_changed",this,"_dialog_value_changed");
select_sb = Ref<StyleBoxTexture>( memnew( StyleBoxTexture) );
+ selection_menu = memnew( PopupMenu );
+ add_child(selection_menu);
+ selection_menu->set_custom_minimum_size(Vector2(100, 0));
+ selection_menu->connect("item_pressed", this, "_selection_result_pressed");
+ selection_menu->connect("popup_hide", this, "_selection_menu_hide");
+
key_pos=true;
key_rot=true;
key_scale=false;
@@ -3090,11 +3418,12 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
box_selecting=false;
//zoom=0.5;
singleton=this;
- editor->get_animation_editor()->connect("keying_changed",this,"_keying_changed");
+ AnimationPlayerEditor::singleton->get_key_editor()->connect("keying_changed",this,"_keying_changed");
set_process_unhandled_key_input(true);
can_move_pivot=false;
drag=DRAG_NONE;
bone_last_frame=0;
+ additive_selection=false;
}
CanvasItemEditor *CanvasItemEditor::singleton=NULL;
diff --git a/tools/editor/plugins/canvas_item_editor_plugin.h b/tools/editor/plugins/canvas_item_editor_plugin.h
index 48a34e2d07..df24734fd7 100644
--- a/tools/editor/plugins/canvas_item_editor_plugin.h
+++ b/tools/editor/plugins/canvas_item_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -67,8 +67,10 @@ class CanvasItemEditor : public VBoxContainer {
enum Tool {
TOOL_SELECT,
+ TOOL_LIST_SELECT,
TOOL_MOVE,
TOOL_ROTATE,
+ TOOL_EDIT_PIVOT,
TOOL_PAN,
TOOL_MAX
};
@@ -90,6 +92,23 @@ class CanvasItemEditor : public VBoxContainer {
UNGROUP_SELECTED,
ALIGN_HORIZONTAL,
ALIGN_VERTICAL,
+ ANCHOR_ALIGN_TOP_LEFT,
+ ANCHOR_ALIGN_TOP_RIGHT,
+ ANCHOR_ALIGN_BOTTOM_LEFT,
+ ANCHOR_ALIGN_BOTTOM_RIGHT,
+ ANCHOR_ALIGN_CENTER_LEFT,
+ ANCHOR_ALIGN_CENTER_RIGHT,
+ ANCHOR_ALIGN_CENTER_TOP,
+ ANCHOR_ALIGN_CENTER_BOTTOM,
+ ANCHOR_ALIGN_CENTER,
+ ANCHOR_ALIGN_TOP_WIDE,
+ ANCHOR_ALIGN_LEFT_WIDE,
+ ANCHOR_ALIGN_RIGHT_WIDE,
+ ANCHOR_ALIGN_BOTTOM_WIDE,
+ ANCHOR_ALIGN_VCENTER_WIDE,
+ ANCHOR_ALIGN_HCENTER_WIDE,
+ ANCHOR_ALIGN_WIDE,
+
SPACE_HORIZONTAL,
SPACE_VERTICAL,
EXPAND_TO_PARENT,
@@ -133,6 +152,7 @@ class CanvasItemEditor : public VBoxContainer {
};
EditorSelection *editor_selection;
+ bool additive_selection;
Tool tool;
bool first_update;
@@ -166,6 +186,18 @@ class CanvasItemEditor : public VBoxContainer {
MenuOption last_option;
+ struct _SelectResult {
+
+ CanvasItem* item;
+ float z;
+ bool has_z;
+ _FORCE_INLINE_ bool operator<(const _SelectResult& p_rr) const {
+ return has_z && p_rr.has_z ? p_rr.z < z : p_rr.has_z;
+ }
+ };
+
+ Vector<_SelectResult> selection_results;
+
struct LockList {
Point2 pos;
bool lock;
@@ -210,9 +242,11 @@ class CanvasItemEditor : public VBoxContainer {
List<PoseClipboard> pose_clipboard;
ToolButton *select_button;
+ ToolButton *list_select_button;
ToolButton *move_button;
ToolButton *rotate_button;
+ ToolButton *pivot_button;
ToolButton *pan_button;
ToolButton *lock_button;
@@ -225,12 +259,16 @@ class CanvasItemEditor : public VBoxContainer {
MenuButton *view_menu;
HBoxContainer *animation_hb;
MenuButton *animation_menu;
+ MenuButton *anchor_menu;
Button *key_loc_button;
Button *key_rot_button;
Button *key_scale_button;
Button *key_insert_button;
+ PopupMenu *selection_menu;
+
+
//PopupMenu *popup;
DragType drag;
Point2 drag_from;
@@ -258,8 +296,11 @@ class CanvasItemEditor : public VBoxContainer {
int handle_len;
CanvasItem* _select_canvas_item_at_pos(const Point2 &p_pos,Node* p_node,const Matrix32& p_parent_xform,const Matrix32& p_canvas_xform);
+ void _find_canvas_items_at_pos(const Point2 &p_pos,Node* p_node,const Matrix32& p_parent_xform,const Matrix32& p_canvas_xform, Vector<_SelectResult> &r_items);
void _find_canvas_items_at_rect(const Rect2& p_rect,Node* p_node,const Matrix32& p_parent_xform,const Matrix32& p_canvas_xform,List<CanvasItem*> *r_items);
+ bool _select(CanvasItem *item, Point2 p_click_pos, bool p_append, bool p_drag=true);
+
ConfirmationDialog *snap_dialog;
AcceptDialog *value_dialog;
@@ -268,11 +309,13 @@ class CanvasItemEditor : public VBoxContainer {
CanvasItem *ref_item;
+ void _edit_set_pivot(const Vector2& mouse_pos);
void _add_canvas_item(CanvasItem *p_canvas_item);
void _remove_canvas_item(CanvasItem *p_canvas_item);
void _clear_canvas_items();
void _visibility_changed(ObjectID p_canvas_item);
void _key_move(const Vector2& p_dir, bool p_snap, KeyMoveMODE p_move_mode);
+ void _list_select(const InputEventMouseButton& b);
DragType _find_drag_type(const Matrix32& p_xform, const Rect2& p_local_rect, const Point2& p_click, Vector2& r_point);
@@ -286,6 +329,9 @@ class CanvasItemEditor : public VBoxContainer {
void _append_canvas_item(CanvasItem *p_item);
void _dialog_value_changed(double);
void _snap_changed();
+ void _selection_result_pressed(int);
+ void _selection_menu_hide();
+
UndoRedo *undo_redo;
Point2 _find_topleftmost_point();
@@ -298,13 +344,15 @@ class CanvasItemEditor : public VBoxContainer {
CanvasItem *get_single_item();
int get_item_count();
- void _keying_changed(bool p_changed);
+ void _keying_changed();
void _unhandled_key_input(const InputEvent& p_ev);
void _viewport_input_event(const InputEvent& p_event);
void _viewport_draw();
+ void _set_anchor(Control::AnchorType p_left,Control::AnchorType p_top,Control::AnchorType p_right,Control::AnchorType p_bottom);
+
HSplitContainer *palette_split;
VSplitContainer *bottom_split;
diff --git a/tools/editor/plugins/collision_polygon_editor_plugin.cpp b/tools/editor/plugins/collision_polygon_editor_plugin.cpp
index 381cfd74ab..d4198f3166 100644
--- a/tools/editor/plugins/collision_polygon_editor_plugin.cpp
+++ b/tools/editor/plugins/collision_polygon_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -113,6 +113,7 @@ bool CollisionPolygonEditor::forward_spatial_input_event(Camera* p_camera,const
return false;
Transform gt = node->get_global_transform();
+ Transform gi = gt.affine_inverse();
float depth = node->get_depth()*0.5;
Vector3 n = gt.basis.get_axis(2).normalized();
Plane p(gt.origin+n*depth,n);
@@ -135,6 +136,8 @@ bool CollisionPolygonEditor::forward_spatial_input_event(Camera* p_camera,const
if (!p.intersects_ray(ray_from,ray_dir,&spoint))
break;
+ spoint = gi.xform(spoint);
+
Vector2 cpoint(spoint.x,spoint.y);
cpoint=CanvasItemEditor::get_singleton()->snap_point(cpoint);
@@ -349,6 +352,8 @@ bool CollisionPolygonEditor::forward_spatial_input_event(Camera* p_camera,const
if (!p.intersects_ray(ray_from,ray_dir,&spoint))
break;
+ spoint = gi.xform(spoint);
+
Vector2 cpoint(spoint.x,spoint.y);
cpoint=CanvasItemEditor::get_singleton()->snap_point(cpoint);
diff --git a/tools/editor/plugins/collision_polygon_editor_plugin.h b/tools/editor/plugins/collision_polygon_editor_plugin.h
index 20a0b3c3f6..45e287ef00 100644
--- a/tools/editor/plugins/collision_polygon_editor_plugin.h
+++ b/tools/editor/plugins/collision_polygon_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/plugins/collision_shape_2d_editor_plugin.cpp b/tools/editor/plugins/collision_shape_2d_editor_plugin.cpp
index 62cf1b4acb..7e5d52d17d 100644
--- a/tools/editor/plugins/collision_shape_2d_editor_plugin.cpp
+++ b/tools/editor/plugins/collision_shape_2d_editor_plugin.cpp
@@ -42,6 +42,13 @@ Variant CollisionShape2DEditor::get_handle_value(int idx) const {
} break;
case LINE_SHAPE: {
+ Ref<LineShape2D> line = node->get_shape();
+
+ if (idx==0) {
+ return line->get_d();
+ } else {
+ return line->get_normal();
+ }
} break;
@@ -115,6 +122,18 @@ void CollisionShape2DEditor::set_handle(int idx, Point2& p_point) {
} break;
case LINE_SHAPE: {
+ if (idx<2) {
+ Ref<LineShape2D> line = node->get_shape();
+
+ if (idx==0){
+ line->set_d(p_point.length());
+ }else{
+ line->set_normal(p_point.normalized());
+ }
+
+ canvas_item_editor->get_viewport_control()->update();
+ }
+
} break;
@@ -200,6 +219,19 @@ void CollisionShape2DEditor::commit_handle(int idx, Variant& p_org) {
} break;
case LINE_SHAPE: {
+ Ref<LineShape2D> line = node->get_shape();
+
+ if (idx==0) {
+ undo_redo->add_do_method(line.ptr(),"set_d",line->get_d());
+ undo_redo->add_do_method(c,"update");
+ undo_redo->add_undo_method(line.ptr(),"set_d",p_org);
+ undo_redo->add_undo_method(c,"update");
+ } else {
+ undo_redo->add_do_method(line.ptr(),"set_normal",line->get_normal());
+ undo_redo->add_do_method(c,"update");
+ undo_redo->add_undo_method(line.ptr(),"set_normal",p_org);
+ undo_redo->add_undo_method(c,"update");
+ }
} break;
@@ -418,6 +450,14 @@ void CollisionShape2DEditor::_canvas_draw() {
} break;
case LINE_SHAPE: {
+ Ref<LineShape2D> shape = node->get_shape();
+
+ handles.resize(2);
+ handles[0] = shape->get_normal() * shape->get_d();
+ handles[1] = shape->get_normal() * (shape->get_d() + 30.0);
+
+ c->draw_texture(h,gt.xform(handles[0])-size);
+ c->draw_texture(h,gt.xform(handles[1])-size);
} break;
diff --git a/tools/editor/plugins/color_ramp_editor_plugin.cpp b/tools/editor/plugins/color_ramp_editor_plugin.cpp
index df50535402..42ff1b1de9 100644
--- a/tools/editor/plugins/color_ramp_editor_plugin.cpp
+++ b/tools/editor/plugins/color_ramp_editor_plugin.cpp
@@ -3,14 +3,20 @@
*/
#include "color_ramp_editor_plugin.h"
+#include "spatial_editor_plugin.h"
+#include "canvas_item_editor_plugin.h"
-ColorRampEditorPlugin::ColorRampEditorPlugin(EditorNode *p_node) {
+ColorRampEditorPlugin::ColorRampEditorPlugin(EditorNode *p_node, bool p_2d) {
editor=p_node;
ramp_editor = memnew( ColorRampEdit );
- add_custom_control(CONTAINER_CANVAS_EDITOR_BOTTOM,ramp_editor);
- //add_custom_control(CONTAINER_SPATIAL_EDITOR_BOTTOM,ramp_editor);
+ _2d=p_2d;
+ if (p_2d)
+ add_custom_control(CONTAINER_CANVAS_EDITOR_BOTTOM,ramp_editor);
+ else
+ add_custom_control(CONTAINER_SPATIAL_EDITOR_BOTTOM,ramp_editor);
+
ramp_editor->set_custom_minimum_size(Size2(100, 48));
ramp_editor->hide();
ramp_editor->connect("ramp_changed", this, "ramp_changed");
@@ -27,7 +33,10 @@ void ColorRampEditorPlugin::edit(Object *p_object) {
bool ColorRampEditorPlugin::handles(Object *p_object) const {
- return p_object->is_type("ColorRamp");
+ if (_2d)
+ return p_object->is_type("ColorRamp") && CanvasItemEditor::get_singleton()->is_visible() == true;
+ else
+ return p_object->is_type("ColorRamp") && SpatialEditor::get_singleton()->is_visible() == true;
}
void ColorRampEditorPlugin::make_visible(bool p_visible) {
diff --git a/tools/editor/plugins/color_ramp_editor_plugin.h b/tools/editor/plugins/color_ramp_editor_plugin.h
index e39a5d65fe..f07dbabeb3 100644
--- a/tools/editor/plugins/color_ramp_editor_plugin.h
+++ b/tools/editor/plugins/color_ramp_editor_plugin.h
@@ -13,6 +13,7 @@ class ColorRampEditorPlugin : public EditorPlugin {
OBJ_TYPE( ColorRampEditorPlugin, EditorPlugin );
+ bool _2d;
Ref<ColorRamp> color_ramp_ref;
ColorRampEdit *ramp_editor;
EditorNode *editor;
@@ -29,7 +30,7 @@ public:
virtual bool handles(Object *p_node) const;
virtual void make_visible(bool p_visible);
- ColorRampEditorPlugin(EditorNode *p_node);
+ ColorRampEditorPlugin(EditorNode *p_node, bool p_2d);
~ColorRampEditorPlugin();
};
diff --git a/tools/editor/plugins/control_editor_plugin.cpp b/tools/editor/plugins/control_editor_plugin.cpp
index 7348a69665..375622a89c 100644
--- a/tools/editor/plugins/control_editor_plugin.cpp
+++ b/tools/editor/plugins/control_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/plugins/control_editor_plugin.h b/tools/editor/plugins/control_editor_plugin.h
index 074298d0df..94cffc8d8d 100644
--- a/tools/editor/plugins/control_editor_plugin.h
+++ b/tools/editor/plugins/control_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/plugins/cube_grid_theme_editor_plugin.cpp b/tools/editor/plugins/cube_grid_theme_editor_plugin.cpp
index c118485083..c861a5841a 100644
--- a/tools/editor/plugins/cube_grid_theme_editor_plugin.cpp
+++ b/tools/editor/plugins/cube_grid_theme_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/plugins/cube_grid_theme_editor_plugin.h b/tools/editor/plugins/cube_grid_theme_editor_plugin.h
index 583ddf6e14..72ee171e19 100644
--- a/tools/editor/plugins/cube_grid_theme_editor_plugin.h
+++ b/tools/editor/plugins/cube_grid_theme_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/plugins/editor_preview_plugins.cpp b/tools/editor/plugins/editor_preview_plugins.cpp
index a77ba9a605..f3b5272571 100644
--- a/tools/editor/plugins/editor_preview_plugins.cpp
+++ b/tools/editor/plugins/editor_preview_plugins.cpp
@@ -6,16 +6,30 @@
#include "scene/resources/material.h"
#include "scene/resources/sample.h"
#include "scene/resources/mesh.h"
+#include "scene/resources/bit_mask.h"
bool EditorTexturePreviewPlugin::handles(const String& p_type) const {
- return ObjectTypeDB::is_type(p_type,"ImageTexture");
+ return (ObjectTypeDB::is_type(p_type,"ImageTexture") || ObjectTypeDB::is_type(p_type, "AtlasTexture"));
}
Ref<Texture> EditorTexturePreviewPlugin::generate(const RES& p_from) {
- Ref<ImageTexture> tex =p_from;
- Image img = tex->get_data();
+ Image img;
+ Ref<AtlasTexture> atex = p_from;
+ if (atex.is_valid()) {
+ Ref<ImageTexture> tex = atex->get_atlas();
+ if (!tex.is_valid()) {
+ return Ref<Texture>();
+ }
+ Image atlas = tex->get_data();
+ img = atlas.get_rect(atex->get_region());
+ }
+ else {
+ Ref<ImageTexture> tex = p_from;
+ img = tex->get_data();
+ }
+
if (img.empty())
return Ref<Texture>();
@@ -25,7 +39,7 @@ Ref<Texture> EditorTexturePreviewPlugin::generate(const RES& p_from) {
if (img.is_compressed()) {
if (img.decompress()!=OK)
return Ref<Texture>();
- } else if (img.get_format()!=Image::FORMAT_RGB && img.get_format()!=Image::FORMAT_RGB) {
+ } else if (img.get_format()!=Image::FORMAT_RGB && img.get_format()!=Image::FORMAT_RGBA) {
img.convert(Image::FORMAT_RGBA);
}
@@ -58,6 +72,81 @@ EditorTexturePreviewPlugin::EditorTexturePreviewPlugin() {
}
+////////////////////////////////////////////////////////////////////////////
+
+bool EditorBitmapPreviewPlugin::handles(const String& p_type) const {
+
+ return ObjectTypeDB::is_type(p_type,"BitMap");
+}
+
+Ref<Texture> EditorBitmapPreviewPlugin::generate(const RES& p_from) {
+
+ Ref<BitMap> bm =p_from;
+
+ if (bm->get_size()==Size2()) {
+ return Ref<Texture>();
+ }
+
+ DVector<uint8_t> data;
+
+ data.resize(bm->get_size().width*bm->get_size().height);
+
+ {
+ DVector<uint8_t>::Write w=data.write();
+
+ for(int i=0;i<bm->get_size().width;i++) {
+ for(int j=0;j<bm->get_size().height;j++) {
+ if (bm->get_bit(Point2i(i,j))) {
+ w[j*bm->get_size().width+i]=255;
+ } else {
+ w[j*bm->get_size().width+i]=0;
+
+ }
+ }
+
+ }
+ }
+
+
+ Image img(bm->get_size().width,bm->get_size().height,0,Image::FORMAT_GRAYSCALE,data);
+
+ int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
+ if (img.is_compressed()) {
+ if (img.decompress()!=OK)
+ return Ref<Texture>();
+ } else if (img.get_format()!=Image::FORMAT_RGB && img.get_format()!=Image::FORMAT_RGBA) {
+ img.convert(Image::FORMAT_RGBA);
+ }
+
+ int width,height;
+ if (img.get_width() > thumbnail_size && img.get_width() >= img.get_height()) {
+
+ width=thumbnail_size;
+ height = img.get_height() * thumbnail_size / img.get_width();
+ } else if (img.get_height() > thumbnail_size && img.get_height() >= img.get_width()) {
+
+ height=thumbnail_size;
+ width = img.get_width() * thumbnail_size / img.get_height();
+ } else {
+
+ width=img.get_width();
+ height=img.get_height();
+ }
+
+ img.resize(width,height);
+
+ Ref<ImageTexture> ptex = Ref<ImageTexture>( memnew( ImageTexture ));
+
+ ptex->create_from_image(img,0);
+ return ptex;
+
+}
+
+EditorBitmapPreviewPlugin::EditorBitmapPreviewPlugin() {
+
+
+}
+
///////////////////////////////////////////////////////////////////////////
@@ -491,8 +580,14 @@ Ref<Texture> EditorSamplePreviewPlugin::generate(const RES& p_from) {
ima_adpcm.last_nibble++;
const uint8_t *src_ptr=sdata;
+ int ofs = ima_adpcm.last_nibble>>1;
+
+ if (stereo)
+ ofs*=2;
+
+
nibble = (ima_adpcm.last_nibble&1)?
- (src_ptr[ima_adpcm.last_nibble>>1]>>4):(src_ptr[ima_adpcm.last_nibble>>1]&0xF);
+ (src_ptr[ofs]>>4):(src_ptr[ofs]&0xF);
step=_ima_adpcm_step_table[ima_adpcm.step_index];
ima_adpcm.step_index += _ima_adpcm_index_table[nibble];
diff --git a/tools/editor/plugins/editor_preview_plugins.h b/tools/editor/plugins/editor_preview_plugins.h
index 98071e2a0e..b3bfda8045 100644
--- a/tools/editor/plugins/editor_preview_plugins.h
+++ b/tools/editor/plugins/editor_preview_plugins.h
@@ -13,6 +13,17 @@ public:
};
+class EditorBitmapPreviewPlugin : public EditorResourcePreviewGenerator {
+public:
+
+ virtual bool handles(const String& p_type) const;
+ virtual Ref<Texture> generate(const RES& p_from);
+
+ EditorBitmapPreviewPlugin();
+};
+
+
+
class EditorPackedScenePreviewPlugin : public EditorResourcePreviewGenerator {
Ref<Texture> _gen_from_imd(Ref<ResourceImportMetadata> p_imd);
diff --git a/tools/editor/plugins/item_list_editor_plugin.cpp b/tools/editor/plugins/item_list_editor_plugin.cpp
index fa261edea3..6f0db959ba 100644
--- a/tools/editor/plugins/item_list_editor_plugin.cpp
+++ b/tools/editor/plugins/item_list_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,7 +30,6 @@
#include "io/resource_loader.h"
-
bool ItemListPlugin::_set(const StringName& p_name, const Variant& p_value) {
String name = p_name;
@@ -45,12 +44,10 @@ bool ItemListPlugin::_set(const StringName& p_name, const Variant& p_value) {
set_item_checkable(idx,p_value);
else if (what=="checked")
set_item_checked(idx,p_value);
- else if (what=="enabled")
- set_item_enabled(idx,p_value);
- else if (what=="accel")
- set_item_accel(idx,p_value);
else if (what=="id")
set_item_id(idx,p_value);
+ else if (what=="enabled")
+ set_item_enabled(idx,p_value);
else if (what=="separator")
set_item_separator(idx,p_value);
else
@@ -60,6 +57,7 @@ bool ItemListPlugin::_set(const StringName& p_name, const Variant& p_value) {
}
bool ItemListPlugin::_get(const StringName& p_name,Variant &r_ret) const {
+
String name = p_name;
int idx = name.get_slice("/",0).to_int();
String what=name.get_slice("/",1);
@@ -72,12 +70,10 @@ bool ItemListPlugin::_get(const StringName& p_name,Variant &r_ret) const {
r_ret=is_item_checkable(idx);
else if (what=="checked")
r_ret=is_item_checked(idx);
- else if (what=="enabled")
- r_ret=is_item_enabled(idx);
- else if (what=="accel")
- r_ret=get_item_accel(idx);
else if (what=="id")
r_ret=get_item_id(idx);
+ else if (what=="enabled")
+ r_ret=is_item_enabled(idx);
else if (what=="separator")
r_ret=is_item_separator(idx);
else
@@ -93,66 +89,119 @@ void ItemListPlugin::_get_property_list( List<PropertyInfo> *p_list) const {
p_list->push_back( PropertyInfo(Variant::STRING,base+"text") );
p_list->push_back( PropertyInfo(Variant::OBJECT,base+"icon",PROPERTY_HINT_RESOURCE_TYPE,"Texture") );
- if (get_flags()&FLAG_CHECKABLE) {
+ int flags = get_flags();
+
+ if (flags&FLAG_CHECKABLE) {
p_list->push_back( PropertyInfo(Variant::BOOL,base+"checkable") );
p_list->push_back( PropertyInfo(Variant::BOOL,base+"checked") );
-
}
- if (get_flags()&FLAG_ENABLE) {
+ if (flags&FLAG_ID)
+ p_list->push_back( PropertyInfo(Variant::INT,base+"id",PROPERTY_HINT_RANGE,"-1,4096") );
+
+ if (flags&FLAG_ENABLE)
p_list->push_back( PropertyInfo(Variant::BOOL,base+"enabled") );
- }
- if (get_flags()&FLAG_ACCEL) {
+ if (flags&FLAG_SEPARATOR)
+ p_list->push_back( PropertyInfo(Variant::BOOL,base+"separator") );
+ }
+}
- p_list->push_back( PropertyInfo(Variant::INT,base+"accel",PROPERTY_HINT_KEY_ACCEL) );
+///////////////////////////////////////////////////////////////
+///////////////////////// PLUGINS /////////////////////////////
+///////////////////////////////////////////////////////////////
- }
- if (get_flags()&FLAG_ID) {
+void ItemListOptionButtonPlugin::set_object(Object *p_object) {
- p_list->push_back( PropertyInfo(Variant::INT,base+"id",PROPERTY_HINT_RANGE,"-1,4096") );
+ ob = p_object->cast_to<OptionButton>();
+}
- }
- if (get_flags()&FLAG_SEPARATOR) {
+bool ItemListOptionButtonPlugin::handles(Object *p_object) const {
- p_list->push_back( PropertyInfo(Variant::BOOL,base+"separator") );
+ return p_object->is_type("OptionButton");
+}
- }
- }
+int ItemListOptionButtonPlugin::get_flags() const {
+
+ return FLAG_ICON|FLAG_ID|FLAG_ENABLE;
}
-void ItemListEditor::_node_removed(Node *p_node) {
+void ItemListOptionButtonPlugin::add_item() {
- if(p_node==item_list) {
- item_list=NULL;
- hide();
- dialog->hide();
- }
+ ob->add_item( "Item "+itos(ob->get_item_count()));
+ _change_notify();
+}
+int ItemListOptionButtonPlugin::get_item_count() const {
+ return ob->get_item_count();
}
-void ItemListEditor::_delete_pressed() {
+void ItemListOptionButtonPlugin::erase(int p_idx) {
- String p = prop_editor->get_selected_path();
+ ob->remove_item(p_idx);
+ _change_notify();
+}
- if (p.find("/")!=-1) {
+ItemListOptionButtonPlugin::ItemListOptionButtonPlugin() {
- if (selected_idx<0 || selected_idx>=item_plugins.size())
- return;
+ ob=NULL;
+}
- item_plugins[selected_idx]->erase(p.get_slice("/",0).to_int());;
- }
+///////////////////////////////////////////////////////////////
+
+void ItemListPopupMenuPlugin::set_object(Object *p_object) {
+ if (p_object->is_type("MenuButton"))
+ pp = p_object->cast_to<MenuButton>()->get_popup();
+ else
+ pp = p_object->cast_to<PopupMenu>();
}
-void ItemListEditor::_add_pressed() {
+bool ItemListPopupMenuPlugin::handles(Object *p_object) const {
- if (selected_idx<0 || selected_idx>=item_plugins.size())
- return;
+ return p_object->is_type("PopupMenu") || p_object->is_type("MenuButton");
+}
- item_plugins[selected_idx]->add_item();
+int ItemListPopupMenuPlugin::get_flags() const {
+
+ return FLAG_ICON|FLAG_CHECKABLE|FLAG_ID|FLAG_ENABLE|FLAG_SEPARATOR;
+}
+
+void ItemListPopupMenuPlugin::add_item() {
+
+ pp->add_item( "Item "+itos(pp->get_item_count()));
+ _change_notify();
+}
+
+int ItemListPopupMenuPlugin::get_item_count() const {
+
+ return pp->get_item_count();
+}
+
+void ItemListPopupMenuPlugin::erase(int p_idx) {
+
+ pp->remove_item(p_idx);
+ _change_notify();
+}
+
+ItemListPopupMenuPlugin::ItemListPopupMenuPlugin() {
+
+ pp=NULL;
+}
+
+///////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////
+
+void ItemListEditor::_node_removed(Node *p_node) {
+
+ if(p_node==item_list) {
+ item_list=NULL;
+ hide();
+ dialog->hide();
+ }
}
void ItemListEditor::_notification(int p_notification) {
@@ -160,57 +209,73 @@ void ItemListEditor::_notification(int p_notification) {
if (p_notification==NOTIFICATION_ENTER_TREE) {
add_button->set_icon(get_icon("Add","EditorIcons"));
- del_button->set_icon(get_icon("Del","EditorIcons"));
+ del_button->set_icon(get_icon("Remove","EditorIcons"));
}
}
+void ItemListEditor::_add_pressed() {
-void ItemListEditor::_menu_option(int p_option) {
+ if (selected_idx==-1)
+ return;
+ item_plugins[selected_idx]->add_item();
+}
- switch(p_option) {
+void ItemListEditor::_delete_pressed() {
- case MENU_EDIT_ITEMS: {
+ TreeItem *ti = tree->get_selected();
- dialog->popup_centered_ratio();
- } break;
- }
+ if (!ti)
+ return;
+
+ if (ti->get_parent()!=tree->get_root())
+ return;
+
+ int idx = ti->get_text(0).to_int();
+
+ if (selected_idx==-1)
+ return;
+
+ item_plugins[selected_idx]->erase(idx);
}
+void ItemListEditor::_edit_items() {
+
+ dialog->popup_centered(Vector2(300, 400));
+}
void ItemListEditor::edit(Node *p_item_list) {
item_list=p_item_list;
+ if (!item_list) {
+ selected_idx=-1;
+ property_editor->edit(NULL);
+ return;
+ }
+
for(int i=0;i<item_plugins.size();i++) {
if (item_plugins[i]->handles(p_item_list)) {
item_plugins[i]->set_object(p_item_list);
- prop_editor->edit(item_plugins[i]);
+ property_editor->edit(item_plugins[i]);
+
+ if (has_icon(item_list->get_type(), "EditorIcons"))
+ toolbar_button->set_icon(get_icon(item_list->get_type(), "EditorIcons"));
+ else
+ toolbar_button->set_icon(Ref<Texture>());
+
selected_idx=i;
return;
}
}
selected_idx=-1;
-
- prop_editor->edit(NULL);
-
-}
-
-
-void ItemListEditor::_bind_methods() {
-
- ObjectTypeDB::bind_method("_menu_option",&ItemListEditor::_menu_option);
- ObjectTypeDB::bind_method("_add_button",&ItemListEditor::_add_pressed);
- ObjectTypeDB::bind_method("_delete_button",&ItemListEditor::_delete_pressed);
-
- //ObjectTypeDB::bind_method("_populate",&ItemListEditor::_populate);
-
+ property_editor->edit(NULL);
}
bool ItemListEditor::handles(Object *p_object) const {
- return false;
+
for(int i=0;i<item_plugins.size();i++) {
if (item_plugins[i]->handles(p_object)) {
return true;
@@ -218,57 +283,65 @@ bool ItemListEditor::handles(Object *p_object) const {
}
return false;
+}
+void ItemListEditor::_bind_methods() {
+
+ ObjectTypeDB::bind_method("_edit_items",&ItemListEditor::_edit_items);
+ ObjectTypeDB::bind_method("_add_button",&ItemListEditor::_add_pressed);
+ ObjectTypeDB::bind_method("_delete_button",&ItemListEditor::_delete_pressed);
}
+
ItemListEditor::ItemListEditor() {
selected_idx=-1;
- options = memnew( MenuButton );
- add_child(options);
- options->set_area_as_parent_rect();
- options->set_text("Items");
- options->get_popup()->add_item("Edit Items",MENU_EDIT_ITEMS);
- //options->get_popup()->add_item("Clear",MENU_CLEAR);
+ add_child( memnew( VSeparator ) );
- options->get_popup()->connect("item_pressed", this,"_menu_option");
+ toolbar_button = memnew( ToolButton );
+ toolbar_button->set_text("Items");
+ add_child(toolbar_button);
+ toolbar_button->connect("pressed",this,"_edit_items");
dialog = memnew( AcceptDialog );
+ dialog->set_title("Item List Editor");
add_child( dialog );
-
+ VBoxContainer *vbc = memnew( VBoxContainer );
+ dialog->add_child(vbc);
+ dialog->set_child_rect(vbc);
HBoxContainer *hbc = memnew( HBoxContainer );
-
- dialog->add_child(hbc);
- dialog->set_child_rect(hbc);
-
- prop_editor = memnew( PropertyEditor );
-
- hbc->add_child(prop_editor);
- prop_editor->set_h_size_flags(SIZE_EXPAND_FILL);
-
- VBoxContainer *vbc = memnew( VBoxContainer );
- hbc->add_child(vbc);
+ hbc->set_h_size_flags(SIZE_EXPAND_FILL);
+ vbc->add_child(hbc);
add_button = memnew( Button );
- //add_button->set_text("Add");
+ add_button->set_text("Add");
+ hbc->add_child(add_button);
add_button->connect("pressed",this,"_add_button");
- vbc->add_child(add_button);
+
+ hbc->add_spacer();
del_button = memnew( Button );
- //del_button->set_text("Del");
+ del_button->set_text("Delete");
+ hbc->add_child(del_button);
del_button->connect("pressed",this,"_delete_button");
- vbc->add_child(del_button);
- dialog->set_title("Item List");
- prop_editor->hide_top_label();
+ property_editor = memnew( PropertyEditor );
+ property_editor->hide_top_label();
+ property_editor->set_subsection_selectable(true);
+ vbc->add_child(property_editor);
+ property_editor->set_v_size_flags(SIZE_EXPAND_FILL);
+ tree = property_editor->get_scene_tree();
+}
+ItemListEditor::~ItemListEditor() {
+ for(int i=0;i<item_plugins.size();i++)
+ memdelete( item_plugins[i] );
}
-
void ItemListEditorPlugin::edit(Object *p_object) {
item_list_editor->edit(p_object->cast_to<Node>());
@@ -288,127 +361,19 @@ void ItemListEditorPlugin::make_visible(bool p_visible) {
item_list_editor->hide();
item_list_editor->edit(NULL);
}
-
-}
-
-
-ItemListEditor::~ItemListEditor() {
-
- for(int i=0;i<item_plugins.size();i++)
- memdelete( item_plugins[i] );
}
-///////////////////////// PLUGINS /////////////////////////////
-///////////////////////// PLUGINS /////////////////////////////
-///////////////////////// PLUGINS /////////////////////////////
-///////////////////////// PLUGINS /////////////////////////////
-///////////////////////// PLUGINS /////////////////////////////
-
-
-class ItemListOptionButtonPlugin : public ItemListPlugin {
-
- OBJ_TYPE(ItemListOptionButtonPlugin,ItemListPlugin);
-
- OptionButton *ob;
-public:
-
- virtual void set_object(Object *p_object) { ob = p_object->cast_to<OptionButton>(); }
-
- virtual bool handles(Object *p_object) const { return p_object->cast_to<OptionButton>()!=NULL; }
-
- virtual int get_flags() const { return FLAG_ICON|FLAG_ID|FLAG_ENABLE; }
-
- virtual void set_item_text(int p_idx,const String& p_text){ ob->set_item_text(p_idx,p_text);}
- virtual void set_item_icon(int p_idx,const Ref<Texture>& p_tex){ ob->set_item_icon(p_idx,p_tex);}
- virtual void set_item_enabled(int p_idx,int p_enabled){ ob->set_item_disabled(p_idx,!p_enabled);}
- virtual void set_item_id(int p_idx,int p_id){ ob->set_item_ID(p_idx,p_id);}
-
-
- virtual String get_item_text(int p_idx) const{ return ob->get_item_text(p_idx); };
- virtual Ref<Texture> get_item_icon(int p_idx) const{ return ob->get_item_icon(p_idx); };
- virtual bool is_item_enabled(int p_idx) const{ return !ob->is_item_disabled(p_idx); };
- virtual int get_item_id(int p_idx) const{ return ob->get_item_ID(p_idx); };
-
- virtual void add_item() { ob->add_item( "New Item "+itos(ob->get_item_count())); _change_notify();}
- virtual int get_item_count() const { return ob->get_item_count(); }
- virtual void erase(int p_idx) { ob->remove_item(p_idx); _change_notify();}
-
-
- ItemListOptionButtonPlugin() { ob=NULL; }
-};
-
-class ItemListPopupMenuPlugin : public ItemListPlugin {
-
- OBJ_TYPE(ItemListPopupMenuPlugin,ItemListPlugin);
-
- PopupMenu *pp;
-public:
-
- virtual void set_object(Object *p_object) {
- if (p_object->cast_to<MenuButton>())
- pp = p_object->cast_to<MenuButton>()->get_popup();
- else
- pp = p_object->cast_to<PopupMenu>();
- }
-
- virtual bool handles(Object *p_object) const { return p_object->cast_to<PopupMenu>()!=NULL || p_object->cast_to<MenuButton>()!=NULL; }
-
- virtual int get_flags() const { return FLAG_ICON|FLAG_ID|FLAG_ENABLE|FLAG_CHECKABLE|FLAG_SEPARATOR|FLAG_ACCEL; }
-
- virtual void set_item_text(int p_idx,const String& p_text){ pp->set_item_text(p_idx,p_text); }
- virtual void set_item_icon(int p_idx,const Ref<Texture>& p_tex){ pp->set_item_icon(p_idx,p_tex);}
- virtual void set_item_checkable(int p_idx,bool p_check){ pp->set_item_as_checkable(p_idx,p_check);}
- virtual void set_item_checked(int p_idx,bool p_checked){ pp->set_item_checked(p_idx,p_checked);}
- virtual void set_item_accel(int p_idx,int p_accel){ pp->set_item_accelerator(p_idx,p_accel);}
- virtual void set_item_enabled(int p_idx,int p_enabled){ pp->set_item_disabled(p_idx,!p_enabled);}
- virtual void set_item_id(int p_idx,int p_id){ pp->set_item_ID(p_idx,p_idx);}
- virtual void set_item_separator(int p_idx,bool p_separator){ pp->set_item_as_separator(p_idx,p_separator);}
-
-
- virtual String get_item_text(int p_idx) const{ return pp->get_item_text(p_idx); };
- virtual Ref<Texture> get_item_icon(int p_idx) const{ return pp->get_item_icon(p_idx); };
- virtual bool is_item_checkable(int p_idx) const{ return pp->is_item_checkable(p_idx); };
- virtual bool is_item_checked(int p_idx) const{ return pp->is_item_checked(p_idx); };
- virtual int get_item_accel(int p_idx) const{ return pp->get_item_accelerator(p_idx); };
- virtual bool is_item_enabled(int p_idx) const{ return !pp->is_item_disabled(p_idx); };
- virtual int get_item_id(int p_idx) const{ return pp->get_item_ID(p_idx); };
- virtual bool is_item_separator(int p_idx) const{ return pp->is_item_separator(p_idx); };
-
-
-
- virtual void add_item() { pp->add_item( "New Item "+itos(pp->get_item_count())); _change_notify();}
- virtual int get_item_count() const { return pp->get_item_count(); }
- virtual void erase(int p_idx) { pp->remove_item(p_idx); _change_notify();}
-
-
- ItemListPopupMenuPlugin() { pp=NULL; }
-};
-
-
-
-
-
-
ItemListEditorPlugin::ItemListEditorPlugin(EditorNode *p_node) {
editor=p_node;
item_list_editor = memnew( ItemListEditor );
- editor->get_viewport()->add_child(item_list_editor);
-
-// item_list_editor->set_anchor(MARGIN_LEFT,Control::ANCHOR_END);
-// item_list_editor->set_anchor(MARGIN_RIGHT,Control::ANCHOR_END);
- item_list_editor->set_margin(MARGIN_LEFT,180);
- item_list_editor->set_margin(MARGIN_RIGHT,230);
- item_list_editor->set_margin(MARGIN_TOP,0);
- item_list_editor->set_margin(MARGIN_BOTTOM,10);
-
+ CanvasItemEditor::get_singleton()->add_control_to_menu_panel(item_list_editor);
item_list_editor->hide();
- item_list_editor->add_plugin( memnew( ItemListOptionButtonPlugin) );
- item_list_editor->add_plugin( memnew( ItemListPopupMenuPlugin) );
+ item_list_editor->add_plugin( memnew( ItemListOptionButtonPlugin ) );
+ item_list_editor->add_plugin( memnew( ItemListPopupMenuPlugin ) );
}
-
ItemListEditorPlugin::~ItemListEditorPlugin()
{
}
diff --git a/tools/editor/plugins/item_list_editor_plugin.h b/tools/editor/plugins/item_list_editor_plugin.h
index 351dbb800d..95d316b199 100644
--- a/tools/editor/plugins/item_list_editor_plugin.h
+++ b/tools/editor/plugins/item_list_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -31,10 +31,11 @@
#include "tools/editor/editor_plugin.h"
#include "tools/editor/editor_node.h"
+#include "canvas_item_editor_plugin.h"
+
#include "scene/gui/option_button.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/popup_menu.h"
-#include "scene/gui/spin_box.h"
/**
@author Juan Linietsky <reduzio@gmail.com>
@@ -51,43 +52,42 @@ protected:
bool _get(const StringName& p_name,Variant &r_ret) const;
void _get_property_list( List<PropertyInfo> *p_list) const;
-
public:
enum Flags {
FLAG_ICON=1,
FLAG_CHECKABLE=2,
- FLAG_ACCEL=4,
- FLAG_ID=8,
- FLAG_ENABLE=16,
- FLAG_SEPARATOR=32
+ FLAG_ID=4,
+ FLAG_ENABLE=8,
+ FLAG_SEPARATOR=16
};
virtual void set_object(Object *p_object)=0;
-
virtual bool handles(Object *p_object) const=0;
virtual int get_flags() const=0;
- virtual void set_item_text(int p_idx,const String& p_text){}
- virtual void set_item_icon(int p_idx,const Ref<Texture>& p_tex){}
- virtual void set_item_checkable(int p_idx,bool p_check){}
- virtual void set_item_checked(int p_idx,bool p_checked){}
- virtual void set_item_accel(int p_idx,int p_accel){}
- virtual void set_item_enabled(int p_idx,int p_enabled){}
- virtual void set_item_id(int p_idx,int p_id){}
- virtual void set_item_separator(int p_idx,bool p_separator){}
-
-
+ virtual void set_item_text(int p_idx, const String& p_text) {}
virtual String get_item_text(int p_idx) const{ return ""; };
+
+ virtual void set_item_icon(int p_idx, const Ref<Texture>& p_tex) {}
virtual Ref<Texture> get_item_icon(int p_idx) const{ return Ref<Texture>(); };
+
+ virtual void set_item_checkable(int p_idx, bool p_check) {}
virtual bool is_item_checkable(int p_idx) const{ return false; };
+
+ virtual void set_item_checked(int p_idx, bool p_checked) {}
virtual bool is_item_checked(int p_idx) const{ return false; };
- virtual int get_item_accel(int p_idx) const{ return 0; };
+
+ virtual void set_item_enabled(int p_idx, int p_enabled) {}
virtual bool is_item_enabled(int p_idx) const{ return false; };
+
+ virtual void set_item_id(int p_idx, int p_id) {}
virtual int get_item_id(int p_idx) const{ return -1; };
- virtual bool is_item_separator(int p_idx) const{ return false; };
+
+ virtual void set_item_separator(int p_idx, bool p_separator) {}
+ virtual bool is_item_separator(int p_idx) const { return false; };
virtual void add_item()=0;
virtual int get_item_count() const=0;
@@ -96,41 +96,107 @@ public:
ItemListPlugin() {}
};
-class ItemListEditor : public Control {
+///////////////////////////////////////////////////////////////
- OBJ_TYPE(ItemListEditor, Control );
+class ItemListOptionButtonPlugin : public ItemListPlugin {
- Node *item_list;
+ OBJ_TYPE(ItemListOptionButtonPlugin,ItemListPlugin);
- enum {
+ OptionButton *ob;
+public:
- MENU_EDIT_ITEMS,
- MENU_CLEAR
- };
+ virtual void set_object(Object *p_object);
+ virtual bool handles(Object *p_object) const;
+ virtual int get_flags() const;
- AcceptDialog *dialog;
+ virtual void set_item_text(int p_idx, const String& p_text) { ob->set_item_text(p_idx,p_text); }
+ virtual String get_item_text(int p_idx) const { return ob->get_item_text(p_idx); }
- PropertyEditor *prop_editor;
+ virtual void set_item_icon(int p_idx, const Ref<Texture>& p_tex) { ob->set_item_icon(p_idx, p_tex); }
+ virtual Ref<Texture> get_item_icon(int p_idx) const { return ob->get_item_icon(p_idx); }
- MenuButton * options;
- int selected_idx;
+ virtual void set_item_enabled(int p_idx, int p_enabled) { ob->set_item_disabled(p_idx, !p_enabled); }
+ virtual bool is_item_enabled(int p_idx) const { return !ob->is_item_disabled(p_idx); }
+
+ virtual void set_item_id(int p_idx, int p_id) { ob->set_item_ID(p_idx,p_id); }
+ virtual int get_item_id(int p_idx) const { return ob->get_item_ID(p_idx); }
+
+ virtual void add_item();
+ virtual int get_item_count() const;
+ virtual void erase(int p_idx);
+
+ ItemListOptionButtonPlugin();
+};
+
+class ItemListPopupMenuPlugin : public ItemListPlugin {
+
+ OBJ_TYPE(ItemListPopupMenuPlugin,ItemListPlugin);
+
+ PopupMenu *pp;
+public:
+
+ virtual void set_object(Object *p_object);
+ virtual bool handles(Object *p_object) const;
+ virtual int get_flags() const;
+ virtual void set_item_text(int p_idx, const String& p_text) { pp->set_item_text(p_idx,p_text); }
+ virtual String get_item_text(int p_idx) const { return pp->get_item_text(p_idx); }
+
+ virtual void set_item_icon(int p_idx, const Ref<Texture>& p_tex) { pp->set_item_icon(p_idx,p_tex); }
+ virtual Ref<Texture> get_item_icon(int p_idx) const { return pp->get_item_icon(p_idx); }
+
+ virtual void set_item_checkable(int p_idx, bool p_check) { pp->set_item_as_checkable(p_idx,p_check); }
+ virtual bool is_item_checkable(int p_idx) const { return pp->is_item_checkable(p_idx); }
+
+ virtual void set_item_checked(int p_idx, bool p_checked) { pp->set_item_checked(p_idx,p_checked); }
+ virtual bool is_item_checked(int p_idx) const { return pp->is_item_checked(p_idx); }
+
+ virtual void set_item_enabled(int p_idx, int p_enabled) { pp->set_item_disabled(p_idx,!p_enabled); }
+ virtual bool is_item_enabled(int p_idx) const { return !pp->is_item_disabled(p_idx); }
+
+ virtual void set_item_id(int p_idx, int p_id) { pp->set_item_ID(p_idx,p_idx); }
+ virtual int get_item_id(int p_idx) const { return pp->get_item_ID(p_idx); }
+
+ virtual void set_item_separator(int p_idx, bool p_separator) { pp->set_item_as_separator(p_idx,p_separator); }
+ virtual bool is_item_separator(int p_idx) const { return pp->is_item_separator(p_idx); }
+
+ virtual void add_item();
+ virtual int get_item_count() const;
+ virtual void erase(int p_idx);
+
+ ItemListPopupMenuPlugin();
+};
+
+///////////////////////////////////////////////////////////////
+
+class ItemListEditor : public HBoxContainer {
+
+ OBJ_TYPE(ItemListEditor,HBoxContainer);
+
+ Node *item_list;
+
+ ToolButton *toolbar_button;
+
+ AcceptDialog *dialog;
+ PropertyEditor *property_editor;
+ Tree *tree;
Button *add_button;
Button *del_button;
-
-// FileDialog *emission_file_dialog;
- void _menu_option(int);
+ int selected_idx;
Vector<ItemListPlugin*> item_plugins;
- void _node_removed(Node *p_node);
+ void _edit_items();
+
void _add_pressed();
void _delete_pressed();
+
+ void _node_removed(Node *p_node);
+
protected:
void _notification(int p_notification);
-
static void _bind_methods();
public:
@@ -143,7 +209,7 @@ public:
class ItemListEditorPlugin : public EditorPlugin {
- OBJ_TYPE( ItemListEditorPlugin, EditorPlugin );
+ OBJ_TYPE(ItemListEditorPlugin,EditorPlugin);
ItemListEditor *item_list_editor;
EditorNode *editor;
diff --git a/tools/editor/plugins/mesh_editor_plugin.cpp b/tools/editor/plugins/mesh_editor_plugin.cpp
index 2c64b2eb6b..5314529a23 100644
--- a/tools/editor/plugins/mesh_editor_plugin.cpp
+++ b/tools/editor/plugins/mesh_editor_plugin.cpp
@@ -1,13 +1,8 @@
#include "mesh_editor_plugin.h"
-#include "tools/editor/editor_plugin.h"
-#include "tools/editor/editor_node.h"
-#include "scene/3d/mesh_instance.h"
#include "scene/3d/physics_body.h"
#include "scene/3d/body_shape.h"
-#include "scene/gui/spin_box.h"
#include "scene/gui/box_container.h"
-#include "scene/3d/mesh_instance.h"
#include "scene/3d/navigation_mesh.h"
#include "spatial_editor_plugin.h"
@@ -38,92 +33,106 @@ void MeshInstanceEditor::_menu_option(int p_option) {
}
switch(p_option) {
- case MENU_OPTION_CREATE_STATIC_TRIMESH_BODY: {
+ case MENU_OPTION_CREATE_STATIC_TRIMESH_BODY:
+ case MENU_OPTION_CREATE_STATIC_CONVEX_BODY: {
- Ref<Shape> shape = mesh->create_trimesh_shape();
- if (shape.is_null())
- return;
- StaticBody *body = memnew( StaticBody );
- CollisionShape *cshape = memnew( CollisionShape );
- cshape->set_shape(shape);
- body->add_child(cshape);
- Node *owner = node==get_tree()->get_edited_scene_root() ? node : node->get_owner();
+ bool trimesh_shape = (p_option==MENU_OPTION_CREATE_STATIC_TRIMESH_BODY);
+ EditorSelection *editor_selection = EditorNode::get_singleton()->get_editor_selection();
UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
- ur->create_action("Create Static Trimesh");
- ur->add_do_method(node,"add_child",body);
- ur->add_do_method(body,"set_owner",owner);
- ur->add_do_method(cshape,"set_owner",owner);
- ur->add_do_reference(body);
- ur->add_undo_method(node,"remove_child",body);
- ur->commit_action();
- } break;
- case MENU_OPTION_CREATE_STATIC_CONVEX_BODY: {
+ List<Node*> selection = editor_selection->get_selected_node_list();
- Ref<Shape> shape = mesh->create_convex_shape();
- if (shape.is_null())
- return;
- StaticBody *body = memnew( StaticBody );
- CollisionShape *cshape = memnew( CollisionShape );
- cshape->set_shape(shape);
- body->add_child(cshape);
- Node *owner = node==get_tree()->get_edited_scene_root() ? node : node->get_owner();
+ if (selection.empty()) {
+ Ref<Shape> shape = trimesh_shape ? mesh->create_trimesh_shape() : mesh->create_convex_shape();
+ if (shape.is_null())
+ return;
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
- ur->create_action("Create Static Trimesh");
- ur->add_do_method(node,"add_child",body);
- ur->add_do_method(body,"set_owner",owner);
- ur->add_do_method(cshape,"set_owner",owner);
- ur->add_do_reference(body);
- ur->add_undo_method(node,"remove_child",body);
- ur->commit_action();
+ CollisionShape *cshape = memnew( CollisionShape );
+ cshape->set_shape(shape);
+ StaticBody *body = memnew( StaticBody );
+ body->add_child(cshape);
- } break;
- case MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE: {
+ Node *owner = node==get_tree()->get_edited_scene_root() ? node : node->get_owner();
+ if (trimesh_shape)
+ ur->create_action("Create Static Trimesh Body");
+ else
+ ur->create_action("Create Static Convex Body");
- if (node==get_tree()->get_edited_scene_root()) {
- err_dialog->set_text("This doesn't work on scene root!");
- err_dialog->popup_centered_minsize();
+ ur->add_do_method(node,"add_child",body);
+ ur->add_do_method(body,"set_owner",owner);
+ ur->add_do_method(cshape,"set_owner",owner);
+ ur->add_do_reference(body);
+ ur->add_undo_method(node,"remove_child",body);
+ ur->commit_action();
return;
}
- Ref<Shape> shape = mesh->create_trimesh_shape();
- if (shape.is_null())
- return;
- CollisionShape *cshape = memnew( CollisionShape );
- cshape->set_shape(shape);
- Node *owner = node->get_owner();
+ if (trimesh_shape)
+ ur->create_action("Create Static Trimesh Body");
+ else
+ ur->create_action("Create Static Convex Body");
+
+ for (List<Node*>::Element *E=selection.front();E;E=E->next()) {
+
+ MeshInstance *instance = E->get()->cast_to<MeshInstance>();
+ if (!instance)
+ continue;
+
+ Ref<Mesh> m = instance->get_mesh();
+ if (m.is_null())
+ continue;
+
+ Ref<Shape> shape = trimesh_shape ? m->create_trimesh_shape() : m->create_convex_shape();
+ if (shape.is_null())
+ continue;
+
+ CollisionShape *cshape = memnew( CollisionShape );
+ cshape->set_shape(shape);
+ StaticBody *body = memnew( StaticBody );
+ body->add_child(cshape);
+
+ Node *owner = instance==get_tree()->get_edited_scene_root() ? instance : instance->get_owner();
+
+ ur->add_do_method(instance,"add_child",body);
+ ur->add_do_method(body,"set_owner",owner);
+ ur->add_do_method(cshape,"set_owner",owner);
+ ur->add_do_reference(body);
+ ur->add_undo_method(instance,"remove_child",body);
+ }
- UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
- ur->create_action("Create Static Trimesh");
- ur->add_do_method(node->get_parent(),"add_child",cshape);
- ur->add_do_method(node->get_parent(),"move_child",cshape,node->get_index()+1);
- ur->add_do_method(cshape,"set_owner",owner);
- ur->add_do_reference(cshape);
- ur->add_undo_method(node->get_parent(),"remove_child",cshape);
ur->commit_action();
} break;
- case MENU_OPTION_CREATE_CONVEX_COLLISION_SHAPE: {
+ case MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE:
+ case MENU_OPTION_CREATE_CONVEX_COLLISION_SHAPE: {
if (node==get_tree()->get_edited_scene_root()) {
err_dialog->set_text("This doesn't work on scene root!");
err_dialog->popup_centered_minsize();
return;
}
- Ref<Shape> shape = mesh->create_convex_shape();
+
+ bool trimesh_shape = (p_option==MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE);
+
+ Ref<Shape> shape = trimesh_shape ? mesh->create_trimesh_shape() : mesh->create_convex_shape();
if (shape.is_null())
return;
+
CollisionShape *cshape = memnew( CollisionShape );
cshape->set_shape(shape);
Node *owner = node->get_owner();
UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
- ur->create_action("Create Static Trimesh");
+
+ if (trimesh_shape)
+ ur->create_action("Create Trimesh Shape");
+ else
+ ur->create_action("Create Convex Shape");
+
ur->add_do_method(node->get_parent(),"add_child",cshape);
ur->add_do_method(node->get_parent(),"move_child",cshape,node->get_index()+1);
ur->add_do_method(cshape,"set_owner",owner);
@@ -132,10 +141,8 @@ void MeshInstanceEditor::_menu_option(int p_option) {
ur->commit_action();
} break;
- case MENU_OPTION_CREATE_NAVMESH: {
-
-
+ case MENU_OPTION_CREATE_NAVMESH: {
Ref<NavigationMesh> nmesh = memnew( NavigationMesh );
@@ -158,9 +165,10 @@ void MeshInstanceEditor::_menu_option(int p_option) {
ur->add_undo_method(node,"remove_child",nmi);
ur->commit_action();
} break;
+
case MENU_OPTION_CREATE_OUTLINE_MESH: {
- outline_dialog->popup_centered_minsize();
+ outline_dialog->popup_centered(Vector2(200, 90));
} break;
}
@@ -212,10 +220,11 @@ MeshInstanceEditor::MeshInstanceEditor() {
options = memnew( MenuButton );
- //add_child(options);
SpatialEditor::get_singleton()->add_control_to_menu_panel(options);
options->set_text("Mesh");
+ options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("MeshInstance","EditorIcons"));
+
options->get_popup()->add_item("Create Trimesh Static Body",MENU_OPTION_CREATE_STATIC_TRIMESH_BODY);
options->get_popup()->add_item("Create Convex Static Body",MENU_OPTION_CREATE_STATIC_CONVEX_BODY);
options->get_popup()->add_separator();
@@ -229,14 +238,20 @@ MeshInstanceEditor::MeshInstanceEditor() {
options->get_popup()->connect("item_pressed", this,"_menu_option");
outline_dialog = memnew( ConfirmationDialog );
- outline_dialog->set_title("Outline Size: ");
+ outline_dialog->set_title("Create Outline Mesh");
+ outline_dialog->get_ok()->set_text("Create");
+
+ VBoxContainer *outline_dialog_vbc = memnew( VBoxContainer );
+ outline_dialog->add_child(outline_dialog_vbc);
+ outline_dialog->set_child_rect(outline_dialog_vbc);
+
outline_size = memnew( SpinBox );
outline_size->set_min(0.001);
outline_size->set_max(1024);
outline_size->set_step(0.001);
outline_size->set_val(0.05);
- outline_dialog->add_child(outline_size);
- outline_dialog->set_child_rect(outline_size);
+ outline_dialog_vbc->add_margin_child("Outline Size:",outline_size);
+
add_child(outline_dialog);
outline_dialog->connect("confirmed",this,"_create_outline_mesh");
diff --git a/tools/editor/plugins/mesh_editor_plugin.h b/tools/editor/plugins/mesh_editor_plugin.h
index e502b5dc2b..6b3e23f31f 100644
--- a/tools/editor/plugins/mesh_editor_plugin.h
+++ b/tools/editor/plugins/mesh_editor_plugin.h
@@ -23,24 +23,19 @@ class MeshInstanceEditor : public Node {
MENU_OPTION_CREATE_OUTLINE_MESH,
};
+ MeshInstance *node;
+
+ MenuButton *options;
+
ConfirmationDialog *outline_dialog;
SpinBox *outline_size;
AcceptDialog *err_dialog;
-
- Panel *panel;
- MeshInstance *node;
-
- LineEdit *surface_source;
- LineEdit *mesh_source;
-
-
void _menu_option(int p_option);
void _create_outline_mesh();
friend class MeshInstanceEditorPlugin;
- MenuButton * options;
protected:
void _node_removed(Node *p_node);
diff --git a/tools/editor/plugins/multimesh_editor_plugin.cpp b/tools/editor/plugins/multimesh_editor_plugin.cpp
index 0df906117e..3f63ef706b 100644
--- a/tools/editor/plugins/multimesh_editor_plugin.cpp
+++ b/tools/editor/plugins/multimesh_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -289,7 +289,7 @@ void MultiMeshEditor::_menu_option(int p_option) {
_last_pp_node=node;
}
- populate_dialog->popup_centered(Size2(250,395));
+ populate_dialog->popup_centered(Size2(250,380));
} break;
}
@@ -325,11 +325,11 @@ MultiMeshEditor::MultiMeshEditor() {
options = memnew( MenuButton );
- //add_child(options);
SpatialEditor::get_singleton()->add_control_to_menu_panel(options);
- options->set_area_as_parent_rect();
-
+
options->set_text("MultiMesh");
+ options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("MultiMeshInstance","EditorIcons"));
+
options->get_popup()->add_item("Populate Surface");
options->get_popup()->connect("item_pressed", this,"_menu_option");
@@ -371,12 +371,12 @@ MultiMeshEditor::MultiMeshEditor() {
populate_axis->select(2);
vbc->add_margin_child("Mesh Up Axis:",populate_axis);
- populate_rotate_random = memnew( HScrollBar );
+ populate_rotate_random = memnew( HSlider );
populate_rotate_random->set_max(1);
populate_rotate_random->set_step(0.01);
vbc->add_margin_child("Random Rotation:",populate_rotate_random);
- populate_tilt_random = memnew( HScrollBar );
+ populate_tilt_random = memnew( HSlider );
populate_tilt_random->set_max(1);
populate_tilt_random->set_step(0.01);
vbc->add_margin_child("Random Tilt:",populate_tilt_random);
@@ -414,8 +414,7 @@ MultiMeshEditor::MultiMeshEditor() {
std->connect("selected",this,"_browsed");
_last_pp_node=NULL;
- //options->set_anchor(MARGIN_LEFT,Control::ANCHOR_END);
- //options->set_anchor(MARGIN_RIGHT,Control::ANCHOR_END);
+
err_dialog = memnew( AcceptDialog );
add_child(err_dialog);
}
@@ -449,13 +448,6 @@ MultiMeshEditorPlugin::MultiMeshEditorPlugin(EditorNode *p_node) {
multimesh_editor = memnew( MultiMeshEditor );
editor->get_viewport()->add_child(multimesh_editor);
-// multimesh_editor->set_anchor(MARGIN_LEFT,Control::ANCHOR_END);
-// multimesh_editor->set_anchor(MARGIN_RIGHT,Control::ANCHOR_END);
- multimesh_editor->set_margin(MARGIN_LEFT,253);
- multimesh_editor->set_margin(MARGIN_RIGHT,310);
- multimesh_editor->set_margin(MARGIN_TOP,0);
- multimesh_editor->set_margin(MARGIN_BOTTOM,10);
-
multimesh_editor->options->hide();
}
diff --git a/tools/editor/plugins/multimesh_editor_plugin.h b/tools/editor/plugins/multimesh_editor_plugin.h
index 4f0c0d008b..245da1eeb7 100644
--- a/tools/editor/plugins/multimesh_editor_plugin.h
+++ b/tools/editor/plugins/multimesh_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -42,10 +42,10 @@ class MultiMeshEditor : public Control {
OBJ_TYPE(MultiMeshEditor, Control );
- friend class MultiMeshEditorPlugin;
+friend class MultiMeshEditorPlugin;
AcceptDialog *err_dialog;
- MenuButton * options;
+ MenuButton * options;
MultiMeshInstance *_last_pp_node;
bool browsing_source;
@@ -59,8 +59,8 @@ class MultiMeshEditor : public Control {
ConfirmationDialog *populate_dialog;
OptionButton *populate_axis;
- HScrollBar *populate_rotate_random;
- HScrollBar *populate_tilt_random;
+ HSlider *populate_rotate_random;
+ HSlider *populate_tilt_random;
SpinBox *populate_scale_random;
SpinBox *populate_scale;
SpinBox *populate_amount;
diff --git a/tools/editor/plugins/particles_2d_editor_plugin.cpp b/tools/editor/plugins/particles_2d_editor_plugin.cpp
index fdf534a3a8..2488c4cdd9 100644
--- a/tools/editor/plugins/particles_2d_editor_plugin.cpp
+++ b/tools/editor/plugins/particles_2d_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -146,6 +146,7 @@ void Particles2DEditorPlugin::_notification(int p_what) {
if (p_what==NOTIFICATION_ENTER_TREE) {
menu->get_popup()->connect("item_pressed",this,"_menu_callback");
+ menu->set_icon(menu->get_popup()->get_icon("Particles2D","EditorIcons"));
file->connect("file_selected",this,"_file_selected");
}
}
diff --git a/tools/editor/plugins/particles_2d_editor_plugin.h b/tools/editor/plugins/particles_2d_editor_plugin.h
index dba0bb4dae..f70a0e7b76 100644
--- a/tools/editor/plugins/particles_2d_editor_plugin.h
+++ b/tools/editor/plugins/particles_2d_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/plugins/particles_editor_plugin.cpp b/tools/editor/plugins/particles_editor_plugin.cpp
index f6f01d82ca..2df6d3ea90 100644
--- a/tools/editor/plugins/particles_editor_plugin.cpp
+++ b/tools/editor/plugins/particles_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -111,6 +111,7 @@ void ParticlesEditor::_populate() {
void ParticlesEditor::_notification(int p_notification) {
if (p_notification==NOTIFICATION_ENTER_TREE) {
+ options->set_icon(options->get_popup()->get_icon("Particles","EditorIcons"));
}
}
diff --git a/tools/editor/plugins/particles_editor_plugin.h b/tools/editor/plugins/particles_editor_plugin.h
index 92756af1f6..ff80bffc29 100644
--- a/tools/editor/plugins/particles_editor_plugin.h
+++ b/tools/editor/plugins/particles_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/plugins/path_2d_editor_plugin.cpp b/tools/editor/plugins/path_2d_editor_plugin.cpp
index d037adc555..509edbe5f8 100644
--- a/tools/editor/plugins/path_2d_editor_plugin.cpp
+++ b/tools/editor/plugins/path_2d_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -534,6 +534,7 @@ void Path2DEditor::edit(Node *p_path2d) {
if (!node->is_connected("visibility_changed", this, "_node_visibility_changed"))
node->connect("visibility_changed", this, "_node_visibility_changed");
+
} else {
if (canvas_item_editor->get_viewport_control()->is_connected("draw",this,"_canvas_draw"))
@@ -614,6 +615,7 @@ Path2DEditor::Path2DEditor(EditorNode *p_editor) {
editor=p_editor;
undo_redo = editor->get_undo_redo();
+ mode=MODE_EDIT;
action=ACTION_NONE;
#if 0
diff --git a/tools/editor/plugins/path_2d_editor_plugin.h b/tools/editor/plugins/path_2d_editor_plugin.h
index 9f15c0669f..973c17464e 100644
--- a/tools/editor/plugins/path_2d_editor_plugin.h
+++ b/tools/editor/plugins/path_2d_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/plugins/path_editor_plugin.cpp b/tools/editor/plugins/path_editor_plugin.cpp
index 4af22e956f..b99e632604 100644
--- a/tools/editor/plugins/path_editor_plugin.cpp
+++ b/tools/editor/plugins/path_editor_plugin.cpp
@@ -1,597 +1,597 @@
-/*************************************************************************/
-/* path_editor_plugin.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* http://www.godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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. */
-/*************************************************************************/
-#include "path_editor_plugin.h"
-#include "spatial_editor_plugin.h"
-#include "scene/resources/curve.h"
-#include "os/keyboard.h"
-
-String PathSpatialGizmo::get_handle_name(int p_idx) const {
-
- Ref<Curve3D> c = path->get_curve();
- if (c.is_null())
- return "";
-
- if (p_idx<c->get_point_count()) {
-
- return "Curve Point #"+itos(p_idx);
- }
-
- p_idx=p_idx-c->get_point_count()+1;
-
- int idx=p_idx/2;
- int t=p_idx%2;
- String n = "Curve Point #"+itos(idx);
- if (t==0)
- n+=" In";
- else
- n+=" Out";
-
- return n;
-
-
-}
-Variant PathSpatialGizmo::get_handle_value(int p_idx) const{
-
- Ref<Curve3D> c = path->get_curve();
- if (c.is_null())
- return Variant();
-
- if (p_idx<c->get_point_count()) {
-
- original=c->get_point_pos(p_idx);
- return original;
- }
-
- p_idx=p_idx-c->get_point_count()+1;
-
- int idx=p_idx/2;
- int t=p_idx%2;
-
- Vector3 ofs;
- if (t==0)
- ofs=c->get_point_in(idx);
- else
- ofs= c->get_point_out(idx);
-
- original=ofs+c->get_point_pos(idx);
-
- return ofs;
-
-}
-void PathSpatialGizmo::set_handle(int p_idx,Camera *p_camera, const Point2& p_point){
-
- Ref<Curve3D> c = path->get_curve();
- if (c.is_null())
- return;
-
- Transform gt = path->get_global_transform();
- Transform gi = gt.affine_inverse();
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
-
- if (p_idx<c->get_point_count()) {
-
- Plane p(gt.xform(original),p_camera->get_transform().basis.get_axis(2));
-
- Vector3 inters;
-
- if (p.intersects_ray(ray_from,ray_dir,&inters)) {
-
- Vector3 local = gi.xform(inters);
- c->set_point_pos(p_idx,local);
- }
-
- return;
- }
-
- p_idx=p_idx-c->get_point_count()+1;
-
- int idx=p_idx/2;
- int t=p_idx%2;
-
- Vector3 base = c->get_point_pos(idx);
-
- Plane p(gt.xform(original),p_camera->get_transform().basis.get_axis(2));
-
- Vector3 inters;
-
- if (p.intersects_ray(ray_from,ray_dir,&inters)) {
-
- Vector3 local = gi.xform(inters)-base;
- if (t==0) {
- c->set_point_in(idx,local);
- } else {
- c->set_point_out(idx,local);
- }
- }
-
-}
-
-void PathSpatialGizmo::commit_handle(int p_idx,const Variant& p_restore,bool p_cancel){
-
- Ref<Curve3D> c = path->get_curve();
- if (c.is_null())
- return;
-
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
-
- if (p_idx<c->get_point_count()) {
-
- if (p_cancel) {
-
- c->set_point_pos(p_idx,p_restore);
- return;
- }
- ur->create_action("Set Curve Point Pos");
- ur->add_do_method(c.ptr(),"set_point_pos",p_idx,c->get_point_pos(p_idx));
- ur->add_undo_method(c.ptr(),"set_point_pos",p_idx,p_restore);
- ur->commit_action();
-
- return;
- }
-
- p_idx=p_idx-c->get_point_count()+1;
-
- int idx=p_idx/2;
- int t=p_idx%2;
-
- Vector3 ofs;
-
- if (p_cancel) {
-
-
-
- return;
- }
-
-
-
- if (t==0) {
-
- if (p_cancel) {
-
- c->set_point_in(p_idx,p_restore);
- return;
- }
- ur->create_action("Set Curve In Pos");
- ur->add_do_method(c.ptr(),"set_point_in",idx,c->get_point_in(idx));
- ur->add_undo_method(c.ptr(),"set_point_in",idx,p_restore);
- ur->commit_action();
-
-
- } else {
- if (p_cancel) {
-
- c->set_point_out(idx,p_restore);
- return;
- }
- ur->create_action("Set Curve Out Pos");
- ur->add_do_method(c.ptr(),"set_point_out",idx,c->get_point_out(idx));
- ur->add_undo_method(c.ptr(),"set_point_out",idx,p_restore);
- ur->commit_action();
-
- }
-
-}
-
-
-void PathSpatialGizmo::redraw(){
-
- clear();
-
- Ref<Curve3D> c = path->get_curve();
- if (c.is_null())
- return;
-
- Vector3Array v3a=c->tesselate();
- //Vector3Array v3a=c->get_baked_points();
-
- int v3s = v3a.size();
- if (v3s==0)
- return;
- Vector<Vector3> v3p;
- Vector3Array::Read r = v3a.read();
-
- for(int i=0;i<v3s-1;i++) {
-
- v3p.push_back(r[i]);
- v3p.push_back(r[i+1]);
- //v3p.push_back(r[i]);
- //v3p.push_back(r[i]+Vector3(0,0.2,0));
- }
-
- add_lines(v3p,PathEditorPlugin::singleton->path_material);
- add_collision_segments(v3p);
-
- if (PathEditorPlugin::singleton->get_edited_path()==path) {
- v3p.clear();
- Vector<Vector3> handles;
- Vector<Vector3> sec_handles;
-
- for(int i=0;i<c->get_point_count();i++) {
-
- Vector3 p = c->get_point_pos(i);
- handles.push_back(p);
- if (i>0) {
- v3p.push_back(p);
- v3p.push_back(p+c->get_point_in(i));
- sec_handles.push_back(p+c->get_point_in(i));
- }
-
- if (i<c->get_point_count()-1) {
- v3p.push_back(p);
- v3p.push_back(p+c->get_point_out(i));
- sec_handles.push_back(p+c->get_point_out(i));
- }
- }
-
- add_lines(v3p,PathEditorPlugin::singleton->path_thin_material);
- add_handles(handles);
- add_handles(sec_handles,false,true);
- }
-
-}
-
-PathSpatialGizmo::PathSpatialGizmo(Path* p_path){
-
- path=p_path;
- set_spatial_node(p_path);
-
-
-
-}
-
-bool PathEditorPlugin::create_spatial_gizmo(Spatial* p_spatial) {
-
- if (p_spatial->cast_to<Path>()) {
-
-
- Ref<PathSpatialGizmo> psg = memnew( PathSpatialGizmo(p_spatial->cast_to<Path>()));
- p_spatial->set_gizmo(psg);
- return true;
- }
-
- return false;
-}
-
-bool PathEditorPlugin::forward_spatial_input_event(Camera* p_camera,const InputEvent& p_event) {
-
- if (!path)
- return false;
- Ref<Curve3D> c=path->get_curve();
- if (c.is_null())
- return false;
- Transform gt = path->get_global_transform();
- Transform it = gt.affine_inverse();
-
- static const int click_dist = 10; //should make global
-
-
- if (p_event.type==InputEvent::MOUSE_BUTTON) {
-
- const InputEventMouseButton &mb=p_event.mouse_button;
- Point2 mbpos(mb.x,mb.y);
-
- if (mb.pressed && mb.button_index==BUTTON_LEFT && (curve_create->is_pressed() || (curve_edit->is_pressed() && mb.mod.control))) {
- //click into curve, break it down
- Vector3Array v3a = c->tesselate();
- int idx=0;
- int rc=v3a.size();
- int closest_seg=-1;
- Vector3 closest_seg_point;
- float closest_d=1e20;
-
- if (rc>=2) {
- Vector3Array::Read r = v3a.read();
-
- if (p_camera->unproject_position(gt.xform(c->get_point_pos(0))).distance_to(mbpos)<click_dist)
- return false; //nope, existing
-
-
- for(int i=0;i<c->get_point_count()-1;i++) {
- //find the offset and point index of the place to break up
- int j=idx;
- if (p_camera->unproject_position(gt.xform(c->get_point_pos(i+1))).distance_to(mbpos)<click_dist)
- return false; //nope, existing
-
-
- while(j<rc && c->get_point_pos(i+1)!=r[j]) {
-
- Vector3 from =r[j];
- Vector3 to =r[j+1];
- real_t cdist = from.distance_to(to);
- from=gt.xform(from);
- to=gt.xform(to);
- if (cdist>0) {
- Vector2 s[2];
- s[0] = p_camera->unproject_position(from);
- s[1] = p_camera->unproject_position(to);
- Vector2 inters = Geometry::get_closest_point_to_segment_2d(mbpos,s);
- float d = inters.distance_to(mbpos);
-
- if (d<10 && d<closest_d) {
-
-
- closest_d=d;
- closest_seg=i;
- Vector3 ray_from=p_camera->project_ray_origin(mbpos);
- Vector3 ray_dir=p_camera->project_ray_normal(mbpos);
-
- Vector3 ra,rb;
- Geometry::get_closest_points_between_segments(ray_from,ray_from+ray_dir*4096,from,to,ra,rb);
-
- closest_seg_point=it.xform(rb);
- }
-
- }
- j++;
-
- }
- if (idx==j)
- idx++; //force next
- else
- idx=j; //swap
-
-
- if (j==rc)
- break;
- }
- }
-
- UndoRedo *ur = editor->get_undo_redo();
- if (closest_seg!=-1) {
- //subdivide
-
- ur->create_action("Split Path");
- ur->add_do_method(c.ptr(),"add_point",closest_seg_point,Vector3(),Vector3(),closest_seg+1);
- ur->add_undo_method(c.ptr(),"remove_point",closest_seg+1);
- ur->commit_action();;
- return true;
-
- } else {
-
- Vector3 org;
- if (c->get_point_count()==0)
- org=path->get_transform().get_origin();
- else
- org=gt.xform(c->get_point_pos(c->get_point_count()));
- Plane p(org,p_camera->get_transform().basis.get_axis(2));
- Vector3 ray_from=p_camera->project_ray_origin(mbpos);
- Vector3 ray_dir=p_camera->project_ray_normal(mbpos);
-
- Vector3 inters;
- if (p.intersects_ray(ray_from,ray_dir,&inters)) {
-
- ur->create_action("Add Point to Curve");
- ur->add_do_method(c.ptr(),"add_point",it.xform(inters),Vector3(),Vector3(),-1);
- ur->add_undo_method(c.ptr(),"remove_point",c->get_point_count());
- ur->commit_action();;
- return true;
- }
-
- //add new at pos
- }
-
- } else if (mb.pressed && ((mb.button_index==BUTTON_LEFT && curve_del->is_pressed()) || (mb.button_index==BUTTON_RIGHT && curve_edit->is_pressed()))) {
-
- int erase_idx=-1;
- for(int i=0;i<c->get_point_count();i++) {
- //find the offset and point index of the place to break up
- if (p_camera->unproject_position(gt.xform(c->get_point_pos(i))).distance_to(mbpos)<click_dist) {
-
- erase_idx=i;
- break;
- }
- }
-
- if (erase_idx!=-1) {
-
- UndoRedo *ur = editor->get_undo_redo();
- ur->create_action("Remove Path Point");
- ur->add_do_method(c.ptr(),"remove_point",erase_idx);
- ur->add_undo_method(c.ptr(),"add_point",c->get_point_pos(erase_idx),c->get_point_in(erase_idx),c->get_point_out(erase_idx),erase_idx);
- ur->commit_action();
- return true;
- }
- }
-
- }
-
- return false;
-}
-
-
-void PathEditorPlugin::edit(Object *p_object) {
-
- if (p_object) {
- path=p_object->cast_to<Path>();
- if (path) {
-
- if (path->get_curve().is_valid()) {
- path->get_curve()->emit_signal("changed");
- }
- }
- } else {
- Path *pre=path;
- path=NULL;
- if (pre) {
- pre->get_curve()->emit_signal("changed");
- }
- }
-// collision_polygon_editor->edit(p_object->cast_to<Node>());
-}
-
-bool PathEditorPlugin::handles(Object *p_object) const {
-
- return p_object->is_type("Path");
-}
-
-void PathEditorPlugin::make_visible(bool p_visible) {
-
- if (p_visible) {
-
- curve_create->show();
- curve_edit->show();
- curve_del->show();
- curve_close->show();
- sep->show();
- } else {
-
- curve_create->hide();
- curve_edit->hide();
- curve_del->hide();
- curve_close->hide();
- sep->hide();
-
- {
- Path *pre=path;
- path=NULL;
- if (pre && pre->get_curve().is_valid()) {
- pre->get_curve()->emit_signal("changed");
- }
- }
- }
-
-}
-
-void PathEditorPlugin::_mode_changed(int p_idx) {
-
- curve_create->set_pressed(p_idx==0);
- curve_edit->set_pressed(p_idx==1);
- curve_del->set_pressed(p_idx==2);
-}
-
-void PathEditorPlugin::_close_curve() {
-
- Ref<Curve3D> c = path->get_curve();
- if (c.is_null())
- return ;
- if (c->get_point_count()<2)
- return;
- c->add_point(c->get_point_pos(0),c->get_point_in(0),c->get_point_out(0));
-
-}
-
-void PathEditorPlugin::_notification(int p_what) {
-
- if (p_what==NOTIFICATION_ENTER_TREE) {
-
- curve_create->connect("pressed",this,"_mode_changed",make_binds(0));
- curve_edit->connect("pressed",this,"_mode_changed",make_binds(1));
- curve_del->connect("pressed",this,"_mode_changed",make_binds(2));
- curve_close->connect("pressed",this,"_close_curve");
- }
-}
-
-void PathEditorPlugin::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("_mode_changed"),&PathEditorPlugin::_mode_changed);
- ObjectTypeDB::bind_method(_MD("_close_curve"),&PathEditorPlugin::_close_curve);
-}
-
-PathEditorPlugin* PathEditorPlugin::singleton=NULL;
-
-
-PathEditorPlugin::PathEditorPlugin(EditorNode *p_node) {
-
- path=NULL;
- editor=p_node;
- singleton=this;
-
- path_material = Ref<FixedMaterial>( memnew( FixedMaterial ));
- path_material->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(0.5,0.5,1.0,0.8) );
- path_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
- path_material->set_line_width(3);
- path_material->set_flag(Material::FLAG_DOUBLE_SIDED,true);
- path_material->set_flag(Material::FLAG_UNSHADED,true);
-
- path_thin_material = Ref<FixedMaterial>( memnew( FixedMaterial ));
- path_thin_material->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(0.5,0.5,1.0,0.4) );
- path_thin_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
- path_thin_material->set_line_width(1);
- path_thin_material->set_flag(Material::FLAG_DOUBLE_SIDED,true);
- path_thin_material->set_flag(Material::FLAG_UNSHADED,true);
-
- SpatialEditor::get_singleton()->add_gizmo_plugin(this);
-
- sep = memnew( VSeparator);
- sep->hide();
- SpatialEditor::get_singleton()->add_control_to_menu_panel(sep);
- curve_edit = memnew( ToolButton );
- curve_edit->set_icon(SpatialEditor::get_singleton()->get_icon("CurveEdit","EditorIcons"));
- curve_edit->set_toggle_mode(true);
- curve_edit->hide();
- curve_edit->set_focus_mode(Control::FOCUS_NONE);
- curve_edit->set_tooltip("Select Points\nShift+Drag: Select Control Points\n"+keycode_get_string(KEY_MASK_CMD)+"Click: Add Point\nRight Click: Delete Point.");
- SpatialEditor::get_singleton()->add_control_to_menu_panel(curve_edit);
- curve_create = memnew( ToolButton );
- curve_create->set_icon(SpatialEditor::get_singleton()->get_icon("CurveCreate","EditorIcons"));
- curve_create->set_toggle_mode(true);
- curve_create->hide();
- curve_create->set_focus_mode(Control::FOCUS_NONE);
- curve_create->set_tooltip("Add Point (in empty space)\nSplit Segment (in curve).");
- SpatialEditor::get_singleton()->add_control_to_menu_panel(curve_create);
- curve_del = memnew( ToolButton );
- curve_del->set_icon(SpatialEditor::get_singleton()->get_icon("CurveDelete","EditorIcons"));
- curve_del->set_toggle_mode(true);
- curve_del->hide();
- curve_del->set_focus_mode(Control::FOCUS_NONE);
- curve_del->set_tooltip("Delete Point.");
- SpatialEditor::get_singleton()->add_control_to_menu_panel(curve_del);
- curve_close = memnew( ToolButton );
- curve_close->set_icon(SpatialEditor::get_singleton()->get_icon("CurveClose","EditorIcons"));
- curve_close->hide();
- curve_close->set_focus_mode(Control::FOCUS_NONE);
- curve_close->set_tooltip("Close Curve");
- SpatialEditor::get_singleton()->add_control_to_menu_panel(curve_close);
-
-
-
- curve_edit->set_pressed(true);
- /*
- collision_polygon_editor = memnew( PathEditor(p_node) );
- editor->get_viewport()->add_child(collision_polygon_editor);
-
- collision_polygon_editor->set_margin(MARGIN_LEFT,200);
- collision_polygon_editor->set_margin(MARGIN_RIGHT,230);
- collision_polygon_editor->set_margin(MARGIN_TOP,0);
- collision_polygon_editor->set_margin(MARGIN_BOTTOM,10);
-
-
- collision_polygon_editor->hide();
- */
-
-
-}
-
-
-PathEditorPlugin::~PathEditorPlugin()
-{
-}
-
+/*************************************************************************/
+/* path_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
+#include "path_editor_plugin.h"
+#include "spatial_editor_plugin.h"
+#include "scene/resources/curve.h"
+#include "os/keyboard.h"
+
+String PathSpatialGizmo::get_handle_name(int p_idx) const {
+
+ Ref<Curve3D> c = path->get_curve();
+ if (c.is_null())
+ return "";
+
+ if (p_idx<c->get_point_count()) {
+
+ return "Curve Point #"+itos(p_idx);
+ }
+
+ p_idx=p_idx-c->get_point_count()+1;
+
+ int idx=p_idx/2;
+ int t=p_idx%2;
+ String n = "Curve Point #"+itos(idx);
+ if (t==0)
+ n+=" In";
+ else
+ n+=" Out";
+
+ return n;
+
+
+}
+Variant PathSpatialGizmo::get_handle_value(int p_idx) const{
+
+ Ref<Curve3D> c = path->get_curve();
+ if (c.is_null())
+ return Variant();
+
+ if (p_idx<c->get_point_count()) {
+
+ original=c->get_point_pos(p_idx);
+ return original;
+ }
+
+ p_idx=p_idx-c->get_point_count()+1;
+
+ int idx=p_idx/2;
+ int t=p_idx%2;
+
+ Vector3 ofs;
+ if (t==0)
+ ofs=c->get_point_in(idx);
+ else
+ ofs= c->get_point_out(idx);
+
+ original=ofs+c->get_point_pos(idx);
+
+ return ofs;
+
+}
+void PathSpatialGizmo::set_handle(int p_idx,Camera *p_camera, const Point2& p_point){
+
+ Ref<Curve3D> c = path->get_curve();
+ if (c.is_null())
+ return;
+
+ Transform gt = path->get_global_transform();
+ Transform gi = gt.affine_inverse();
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+ if (p_idx<c->get_point_count()) {
+
+ Plane p(gt.xform(original),p_camera->get_transform().basis.get_axis(2));
+
+ Vector3 inters;
+
+ if (p.intersects_ray(ray_from,ray_dir,&inters)) {
+
+ Vector3 local = gi.xform(inters);
+ c->set_point_pos(p_idx,local);
+ }
+
+ return;
+ }
+
+ p_idx=p_idx-c->get_point_count()+1;
+
+ int idx=p_idx/2;
+ int t=p_idx%2;
+
+ Vector3 base = c->get_point_pos(idx);
+
+ Plane p(gt.xform(original),p_camera->get_transform().basis.get_axis(2));
+
+ Vector3 inters;
+
+ if (p.intersects_ray(ray_from,ray_dir,&inters)) {
+
+ Vector3 local = gi.xform(inters)-base;
+ if (t==0) {
+ c->set_point_in(idx,local);
+ } else {
+ c->set_point_out(idx,local);
+ }
+ }
+
+}
+
+void PathSpatialGizmo::commit_handle(int p_idx,const Variant& p_restore,bool p_cancel){
+
+ Ref<Curve3D> c = path->get_curve();
+ if (c.is_null())
+ return;
+
+ UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
+
+ if (p_idx<c->get_point_count()) {
+
+ if (p_cancel) {
+
+ c->set_point_pos(p_idx,p_restore);
+ return;
+ }
+ ur->create_action("Set Curve Point Pos");
+ ur->add_do_method(c.ptr(),"set_point_pos",p_idx,c->get_point_pos(p_idx));
+ ur->add_undo_method(c.ptr(),"set_point_pos",p_idx,p_restore);
+ ur->commit_action();
+
+ return;
+ }
+
+ p_idx=p_idx-c->get_point_count()+1;
+
+ int idx=p_idx/2;
+ int t=p_idx%2;
+
+ Vector3 ofs;
+
+ if (p_cancel) {
+
+
+
+ return;
+ }
+
+
+
+ if (t==0) {
+
+ if (p_cancel) {
+
+ c->set_point_in(p_idx,p_restore);
+ return;
+ }
+ ur->create_action("Set Curve In Pos");
+ ur->add_do_method(c.ptr(),"set_point_in",idx,c->get_point_in(idx));
+ ur->add_undo_method(c.ptr(),"set_point_in",idx,p_restore);
+ ur->commit_action();
+
+
+ } else {
+ if (p_cancel) {
+
+ c->set_point_out(idx,p_restore);
+ return;
+ }
+ ur->create_action("Set Curve Out Pos");
+ ur->add_do_method(c.ptr(),"set_point_out",idx,c->get_point_out(idx));
+ ur->add_undo_method(c.ptr(),"set_point_out",idx,p_restore);
+ ur->commit_action();
+
+ }
+
+}
+
+
+void PathSpatialGizmo::redraw(){
+
+ clear();
+
+ Ref<Curve3D> c = path->get_curve();
+ if (c.is_null())
+ return;
+
+ Vector3Array v3a=c->tesselate();
+ //Vector3Array v3a=c->get_baked_points();
+
+ int v3s = v3a.size();
+ if (v3s==0)
+ return;
+ Vector<Vector3> v3p;
+ Vector3Array::Read r = v3a.read();
+
+ for(int i=0;i<v3s-1;i++) {
+
+ v3p.push_back(r[i]);
+ v3p.push_back(r[i+1]);
+ //v3p.push_back(r[i]);
+ //v3p.push_back(r[i]+Vector3(0,0.2,0));
+ }
+
+ add_lines(v3p,PathEditorPlugin::singleton->path_material);
+ add_collision_segments(v3p);
+
+ if (PathEditorPlugin::singleton->get_edited_path()==path) {
+ v3p.clear();
+ Vector<Vector3> handles;
+ Vector<Vector3> sec_handles;
+
+ for(int i=0;i<c->get_point_count();i++) {
+
+ Vector3 p = c->get_point_pos(i);
+ handles.push_back(p);
+ if (i>0) {
+ v3p.push_back(p);
+ v3p.push_back(p+c->get_point_in(i));
+ sec_handles.push_back(p+c->get_point_in(i));
+ }
+
+ if (i<c->get_point_count()-1) {
+ v3p.push_back(p);
+ v3p.push_back(p+c->get_point_out(i));
+ sec_handles.push_back(p+c->get_point_out(i));
+ }
+ }
+
+ add_lines(v3p,PathEditorPlugin::singleton->path_thin_material);
+ add_handles(handles);
+ add_handles(sec_handles,false,true);
+ }
+
+}
+
+PathSpatialGizmo::PathSpatialGizmo(Path* p_path){
+
+ path=p_path;
+ set_spatial_node(p_path);
+
+
+
+}
+
+bool PathEditorPlugin::create_spatial_gizmo(Spatial* p_spatial) {
+
+ if (p_spatial->cast_to<Path>()) {
+
+
+ Ref<PathSpatialGizmo> psg = memnew( PathSpatialGizmo(p_spatial->cast_to<Path>()));
+ p_spatial->set_gizmo(psg);
+ return true;
+ }
+
+ return false;
+}
+
+bool PathEditorPlugin::forward_spatial_input_event(Camera* p_camera,const InputEvent& p_event) {
+
+ if (!path)
+ return false;
+ Ref<Curve3D> c=path->get_curve();
+ if (c.is_null())
+ return false;
+ Transform gt = path->get_global_transform();
+ Transform it = gt.affine_inverse();
+
+ static const int click_dist = 10; //should make global
+
+
+ if (p_event.type==InputEvent::MOUSE_BUTTON) {
+
+ const InputEventMouseButton &mb=p_event.mouse_button;
+ Point2 mbpos(mb.x,mb.y);
+
+ if (mb.pressed && mb.button_index==BUTTON_LEFT && (curve_create->is_pressed() || (curve_edit->is_pressed() && mb.mod.control))) {
+ //click into curve, break it down
+ Vector3Array v3a = c->tesselate();
+ int idx=0;
+ int rc=v3a.size();
+ int closest_seg=-1;
+ Vector3 closest_seg_point;
+ float closest_d=1e20;
+
+ if (rc>=2) {
+ Vector3Array::Read r = v3a.read();
+
+ if (p_camera->unproject_position(gt.xform(c->get_point_pos(0))).distance_to(mbpos)<click_dist)
+ return false; //nope, existing
+
+
+ for(int i=0;i<c->get_point_count()-1;i++) {
+ //find the offset and point index of the place to break up
+ int j=idx;
+ if (p_camera->unproject_position(gt.xform(c->get_point_pos(i+1))).distance_to(mbpos)<click_dist)
+ return false; //nope, existing
+
+
+ while(j<rc && c->get_point_pos(i+1)!=r[j]) {
+
+ Vector3 from =r[j];
+ Vector3 to =r[j+1];
+ real_t cdist = from.distance_to(to);
+ from=gt.xform(from);
+ to=gt.xform(to);
+ if (cdist>0) {
+ Vector2 s[2];
+ s[0] = p_camera->unproject_position(from);
+ s[1] = p_camera->unproject_position(to);
+ Vector2 inters = Geometry::get_closest_point_to_segment_2d(mbpos,s);
+ float d = inters.distance_to(mbpos);
+
+ if (d<10 && d<closest_d) {
+
+
+ closest_d=d;
+ closest_seg=i;
+ Vector3 ray_from=p_camera->project_ray_origin(mbpos);
+ Vector3 ray_dir=p_camera->project_ray_normal(mbpos);
+
+ Vector3 ra,rb;
+ Geometry::get_closest_points_between_segments(ray_from,ray_from+ray_dir*4096,from,to,ra,rb);
+
+ closest_seg_point=it.xform(rb);
+ }
+
+ }
+ j++;
+
+ }
+ if (idx==j)
+ idx++; //force next
+ else
+ idx=j; //swap
+
+
+ if (j==rc)
+ break;
+ }
+ }
+
+ UndoRedo *ur = editor->get_undo_redo();
+ if (closest_seg!=-1) {
+ //subdivide
+
+ ur->create_action("Split Path");
+ ur->add_do_method(c.ptr(),"add_point",closest_seg_point,Vector3(),Vector3(),closest_seg+1);
+ ur->add_undo_method(c.ptr(),"remove_point",closest_seg+1);
+ ur->commit_action();;
+ return true;
+
+ } else {
+
+ Vector3 org;
+ if (c->get_point_count()==0)
+ org=path->get_transform().get_origin();
+ else
+ org=gt.xform(c->get_point_pos(c->get_point_count()));
+ Plane p(org,p_camera->get_transform().basis.get_axis(2));
+ Vector3 ray_from=p_camera->project_ray_origin(mbpos);
+ Vector3 ray_dir=p_camera->project_ray_normal(mbpos);
+
+ Vector3 inters;
+ if (p.intersects_ray(ray_from,ray_dir,&inters)) {
+
+ ur->create_action("Add Point to Curve");
+ ur->add_do_method(c.ptr(),"add_point",it.xform(inters),Vector3(),Vector3(),-1);
+ ur->add_undo_method(c.ptr(),"remove_point",c->get_point_count());
+ ur->commit_action();;
+ return true;
+ }
+
+ //add new at pos
+ }
+
+ } else if (mb.pressed && ((mb.button_index==BUTTON_LEFT && curve_del->is_pressed()) || (mb.button_index==BUTTON_RIGHT && curve_edit->is_pressed()))) {
+
+ int erase_idx=-1;
+ for(int i=0;i<c->get_point_count();i++) {
+ //find the offset and point index of the place to break up
+ if (p_camera->unproject_position(gt.xform(c->get_point_pos(i))).distance_to(mbpos)<click_dist) {
+
+ erase_idx=i;
+ break;
+ }
+ }
+
+ if (erase_idx!=-1) {
+
+ UndoRedo *ur = editor->get_undo_redo();
+ ur->create_action("Remove Path Point");
+ ur->add_do_method(c.ptr(),"remove_point",erase_idx);
+ ur->add_undo_method(c.ptr(),"add_point",c->get_point_pos(erase_idx),c->get_point_in(erase_idx),c->get_point_out(erase_idx),erase_idx);
+ ur->commit_action();
+ return true;
+ }
+ }
+
+ }
+
+ return false;
+}
+
+
+void PathEditorPlugin::edit(Object *p_object) {
+
+ if (p_object) {
+ path=p_object->cast_to<Path>();
+ if (path) {
+
+ if (path->get_curve().is_valid()) {
+ path->get_curve()->emit_signal("changed");
+ }
+ }
+ } else {
+ Path *pre=path;
+ path=NULL;
+ if (pre) {
+ pre->get_curve()->emit_signal("changed");
+ }
+ }
+// collision_polygon_editor->edit(p_object->cast_to<Node>());
+}
+
+bool PathEditorPlugin::handles(Object *p_object) const {
+
+ return p_object->is_type("Path");
+}
+
+void PathEditorPlugin::make_visible(bool p_visible) {
+
+ if (p_visible) {
+
+ curve_create->show();
+ curve_edit->show();
+ curve_del->show();
+ curve_close->show();
+ sep->show();
+ } else {
+
+ curve_create->hide();
+ curve_edit->hide();
+ curve_del->hide();
+ curve_close->hide();
+ sep->hide();
+
+ {
+ Path *pre=path;
+ path=NULL;
+ if (pre && pre->get_curve().is_valid()) {
+ pre->get_curve()->emit_signal("changed");
+ }
+ }
+ }
+
+}
+
+void PathEditorPlugin::_mode_changed(int p_idx) {
+
+ curve_create->set_pressed(p_idx==0);
+ curve_edit->set_pressed(p_idx==1);
+ curve_del->set_pressed(p_idx==2);
+}
+
+void PathEditorPlugin::_close_curve() {
+
+ Ref<Curve3D> c = path->get_curve();
+ if (c.is_null())
+ return ;
+ if (c->get_point_count()<2)
+ return;
+ c->add_point(c->get_point_pos(0),c->get_point_in(0),c->get_point_out(0));
+
+}
+
+void PathEditorPlugin::_notification(int p_what) {
+
+ if (p_what==NOTIFICATION_ENTER_TREE) {
+
+ curve_create->connect("pressed",this,"_mode_changed",make_binds(0));
+ curve_edit->connect("pressed",this,"_mode_changed",make_binds(1));
+ curve_del->connect("pressed",this,"_mode_changed",make_binds(2));
+ curve_close->connect("pressed",this,"_close_curve");
+ }
+}
+
+void PathEditorPlugin::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("_mode_changed"),&PathEditorPlugin::_mode_changed);
+ ObjectTypeDB::bind_method(_MD("_close_curve"),&PathEditorPlugin::_close_curve);
+}
+
+PathEditorPlugin* PathEditorPlugin::singleton=NULL;
+
+
+PathEditorPlugin::PathEditorPlugin(EditorNode *p_node) {
+
+ path=NULL;
+ editor=p_node;
+ singleton=this;
+
+ path_material = Ref<FixedMaterial>( memnew( FixedMaterial ));
+ path_material->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(0.5,0.5,1.0,0.8) );
+ path_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
+ path_material->set_line_width(3);
+ path_material->set_flag(Material::FLAG_DOUBLE_SIDED,true);
+ path_material->set_flag(Material::FLAG_UNSHADED,true);
+
+ path_thin_material = Ref<FixedMaterial>( memnew( FixedMaterial ));
+ path_thin_material->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(0.5,0.5,1.0,0.4) );
+ path_thin_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
+ path_thin_material->set_line_width(1);
+ path_thin_material->set_flag(Material::FLAG_DOUBLE_SIDED,true);
+ path_thin_material->set_flag(Material::FLAG_UNSHADED,true);
+
+ SpatialEditor::get_singleton()->add_gizmo_plugin(this);
+
+ sep = memnew( VSeparator);
+ sep->hide();
+ SpatialEditor::get_singleton()->add_control_to_menu_panel(sep);
+ curve_edit = memnew( ToolButton );
+ curve_edit->set_icon(SpatialEditor::get_singleton()->get_icon("CurveEdit","EditorIcons"));
+ curve_edit->set_toggle_mode(true);
+ curve_edit->hide();
+ curve_edit->set_focus_mode(Control::FOCUS_NONE);
+ curve_edit->set_tooltip("Select Points\nShift+Drag: Select Control Points\n"+keycode_get_string(KEY_MASK_CMD)+"Click: Add Point\nRight Click: Delete Point.");
+ SpatialEditor::get_singleton()->add_control_to_menu_panel(curve_edit);
+ curve_create = memnew( ToolButton );
+ curve_create->set_icon(SpatialEditor::get_singleton()->get_icon("CurveCreate","EditorIcons"));
+ curve_create->set_toggle_mode(true);
+ curve_create->hide();
+ curve_create->set_focus_mode(Control::FOCUS_NONE);
+ curve_create->set_tooltip("Add Point (in empty space)\nSplit Segment (in curve).");
+ SpatialEditor::get_singleton()->add_control_to_menu_panel(curve_create);
+ curve_del = memnew( ToolButton );
+ curve_del->set_icon(SpatialEditor::get_singleton()->get_icon("CurveDelete","EditorIcons"));
+ curve_del->set_toggle_mode(true);
+ curve_del->hide();
+ curve_del->set_focus_mode(Control::FOCUS_NONE);
+ curve_del->set_tooltip("Delete Point.");
+ SpatialEditor::get_singleton()->add_control_to_menu_panel(curve_del);
+ curve_close = memnew( ToolButton );
+ curve_close->set_icon(SpatialEditor::get_singleton()->get_icon("CurveClose","EditorIcons"));
+ curve_close->hide();
+ curve_close->set_focus_mode(Control::FOCUS_NONE);
+ curve_close->set_tooltip("Close Curve");
+ SpatialEditor::get_singleton()->add_control_to_menu_panel(curve_close);
+
+
+
+ curve_edit->set_pressed(true);
+ /*
+ collision_polygon_editor = memnew( PathEditor(p_node) );
+ editor->get_viewport()->add_child(collision_polygon_editor);
+
+ collision_polygon_editor->set_margin(MARGIN_LEFT,200);
+ collision_polygon_editor->set_margin(MARGIN_RIGHT,230);
+ collision_polygon_editor->set_margin(MARGIN_TOP,0);
+ collision_polygon_editor->set_margin(MARGIN_BOTTOM,10);
+
+
+ collision_polygon_editor->hide();
+ */
+
+
+}
+
+
+PathEditorPlugin::~PathEditorPlugin()
+{
+}
+
diff --git a/tools/editor/plugins/path_editor_plugin.h b/tools/editor/plugins/path_editor_plugin.h
index fcd4241e59..18bad23bd1 100644
--- a/tools/editor/plugins/path_editor_plugin.h
+++ b/tools/editor/plugins/path_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/plugins/polygon_2d_editor_plugin.cpp b/tools/editor/plugins/polygon_2d_editor_plugin.cpp
index d25880fdff..3e9c58d604 100644
--- a/tools/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/tools/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -50,6 +50,11 @@ void Polygon2DEditor::_notification(int p_what) {
uv_button[UV_MODE_ROTATE]->set_icon(get_icon("ToolRotate","EditorIcons"));
uv_button[UV_MODE_SCALE]->set_icon(get_icon("ToolScale","EditorIcons"));
+ b_snap_grid->set_icon( get_icon("Grid", "EditorIcons"));
+ b_snap_enable->set_icon( get_icon("Snap", "EditorIcons"));
+ uv_icon_zoom->set_texture( get_icon("Zoom", "EditorIcons"));
+
+ get_tree()->connect("node_removed", this, "_node_removed");
} break;
case NOTIFICATION_FIXED_PROCESS: {
@@ -62,8 +67,10 @@ void Polygon2DEditor::_notification(int p_what) {
void Polygon2DEditor::_node_removed(Node *p_node) {
if(p_node==node) {
- node=NULL;
+ edit(NULL);
hide();
+
+ canvas_item_editor->get_viewport_control()->update();
}
}
@@ -158,6 +165,41 @@ void Polygon2DEditor::_menu_option(int p_option) {
}
}
+void Polygon2DEditor::_set_use_snap(bool p_use)
+{
+ use_snap=p_use;
+}
+
+void Polygon2DEditor::_set_show_grid(bool p_show)
+{
+ snap_show_grid=p_show;
+ uv_edit_draw->update();
+}
+
+void Polygon2DEditor::_set_snap_off_x(float p_val)
+{
+ snap_offset.x=p_val;
+ uv_edit_draw->update();
+}
+
+void Polygon2DEditor::_set_snap_off_y(float p_val)
+{
+ snap_offset.y=p_val;
+ uv_edit_draw->update();
+}
+
+void Polygon2DEditor::_set_snap_step_x(float p_val)
+{
+ snap_step.x=p_val;
+ uv_edit_draw->update();
+}
+
+void Polygon2DEditor::_set_snap_step_y(float p_val)
+{
+ snap_step.y=p_val;
+ uv_edit_draw->update();
+}
+
void Polygon2DEditor::_wip_close() {
undo_redo->create_action("Create Poly");
@@ -494,7 +536,7 @@ void Polygon2DEditor::_uv_input(const InputEvent& p_input) {
Vector2 tuv=mtx.xform(uv_prev[i]);
if (tuv.distance_to(Vector2(mb.x,mb.y))<8) {
-
+ uv_drag_from=tuv;
uv_drag_index=i;
}
}
@@ -545,7 +587,7 @@ void Polygon2DEditor::_uv_input(const InputEvent& p_input) {
} else if (uv_drag) {
- Vector2 uv_drag_to(mm.x,mm.y);
+ Vector2 uv_drag_to=snap_point(Vector2(mm.x,mm.y));
Vector2 drag = mtx.affine_inverse().xform(uv_drag_to) - mtx.affine_inverse().xform(uv_drag_from);
@@ -649,6 +691,33 @@ void Polygon2DEditor::_uv_draw() {
uv_edit_draw->draw_texture(base_tex,Point2());
VS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(),Matrix32());
+ if (snap_show_grid) {
+ Size2 s = uv_edit_draw->get_size();
+ int last_cell;
+
+ if (snap_step.x!=0) {
+ for(int i=0;i<s.width;i++) {
+ int cell = Math::fast_ftoi(Math::floor((mtx.affine_inverse().xform(Vector2(i,0)).x-snap_offset.x)/snap_step.x));
+ if (i==0)
+ last_cell=cell;
+ if (last_cell!=cell)
+ uv_edit_draw->draw_line(Point2(i,0),Point2(i,s.height),Color(0.3,0.7,1,0.3));
+ last_cell=cell;
+ }
+ }
+
+ if (snap_step.y!=0) {
+ for(int i=0;i<s.height;i++) {
+ int cell = Math::fast_ftoi(Math::floor((mtx.affine_inverse().xform(Vector2(0,i)).y-snap_offset.y)/snap_step.y));
+ if (i==0)
+ last_cell=cell;
+ if (last_cell!=cell)
+ uv_edit_draw->draw_line(Point2(0,i),Point2(s.width,i),Color(0.3,0.7,1,0.3));
+ last_cell=cell;
+ }
+ }
+ }
+
DVector<Vector2> uvs = node->get_uv();
Ref<Texture> handle = get_icon("EditorHandle","EditorIcons");
@@ -686,22 +755,18 @@ void Polygon2DEditor::edit(Node *p_collision_polygon) {
canvas_item_editor=CanvasItemEditor::get_singleton();
}
-
if (p_collision_polygon) {
node=p_collision_polygon->cast_to<Polygon2D>();
if (!canvas_item_editor->get_viewport_control()->is_connected("draw",this,"_canvas_draw"))
canvas_item_editor->get_viewport_control()->connect("draw",this,"_canvas_draw");
- node->connect("exit_tree",this,"_node_removed",varray(),CONNECT_ONESHOT);
+
wip.clear();
wip_active=false;
edited_point=-1;
} else {
- if (node)
- node->disconnect("exit_tree",this,"_node_removed");
-
node=NULL;
if (canvas_item_editor->get_viewport_control()->is_connected("draw",this,"_canvas_draw"))
@@ -720,10 +785,29 @@ void Polygon2DEditor::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_uv_input"),&Polygon2DEditor::_uv_input);
ObjectTypeDB::bind_method(_MD("_uv_scroll_changed"),&Polygon2DEditor::_uv_scroll_changed);
ObjectTypeDB::bind_method(_MD("_node_removed"),&Polygon2DEditor::_node_removed);
+ ObjectTypeDB::bind_method(_MD("_set_use_snap"),&Polygon2DEditor::_set_use_snap);
+ ObjectTypeDB::bind_method(_MD("_set_show_grid"),&Polygon2DEditor::_set_show_grid);
+ ObjectTypeDB::bind_method(_MD("_set_snap_off_x"),&Polygon2DEditor::_set_snap_off_x);
+ ObjectTypeDB::bind_method(_MD("_set_snap_off_y"),&Polygon2DEditor::_set_snap_off_y);
+ ObjectTypeDB::bind_method(_MD("_set_snap_step_x"),&Polygon2DEditor::_set_snap_step_x);
+ ObjectTypeDB::bind_method(_MD("_set_snap_step_y"),&Polygon2DEditor::_set_snap_step_y);
}
+inline float _snap_scalar(float p_offset, float p_step, float p_target) {
+ return p_step != 0 ? Math::stepify(p_target - p_offset, p_step) + p_offset : p_target;
+}
+
+Vector2 Polygon2DEditor::snap_point(Vector2 p_target) const {
+ if (use_snap) {
+ p_target.x = _snap_scalar(snap_offset.x*uv_draw_zoom-uv_draw_ofs.x, snap_step.x*uv_draw_zoom, p_target.x);
+ p_target.y = _snap_scalar(snap_offset.y*uv_draw_zoom-uv_draw_ofs.y, snap_step.y*uv_draw_zoom, p_target.y);
+ }
+
+ return p_target;
+}
+
Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) {
node=NULL;
@@ -731,6 +815,10 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) {
editor=p_editor;
undo_redo = editor->get_undo_redo();
+ snap_step=Vector2(10,10);
+ use_snap=false;
+ snap_show_grid=false;
+
add_child( memnew( VSeparator ));
button_create = memnew( ToolButton );
add_child(button_create);
@@ -800,9 +888,72 @@ Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) {
uv_menu->get_popup()->add_separator();
uv_menu->get_popup()->add_item("Clear UV",UVEDIT_UV_CLEAR);
uv_menu->get_popup()->connect("item_pressed",this,"_menu_option");
+
+ uv_mode_hb->add_child( memnew( VSeparator ));
+
+ b_snap_enable = memnew( ToolButton );
+ uv_mode_hb->add_child(b_snap_enable);
+ b_snap_enable->set_text("Snap");
+ b_snap_enable->set_focus_mode(FOCUS_NONE);
+ b_snap_enable->set_toggle_mode(true);
+ b_snap_enable->set_pressed(use_snap);
+ b_snap_enable->set_tooltip("Enable Snap");
+ b_snap_enable->connect("toggled",this,"_set_use_snap");
+
+ b_snap_grid = memnew( ToolButton );
+ uv_mode_hb->add_child(b_snap_grid);
+ b_snap_grid->set_text("Grid");
+ b_snap_grid->set_focus_mode(FOCUS_NONE);
+ b_snap_grid->set_toggle_mode(true);
+ b_snap_grid->set_pressed(snap_show_grid);
+ b_snap_grid->set_tooltip("Show Grid");
+ b_snap_grid->connect("toggled",this,"_set_show_grid");
+
+ uv_mode_hb->add_child( memnew( VSeparator ));
+ uv_mode_hb->add_child( memnew( Label("Grid Offset:") ) );
+
+ SpinBox *sb_off_x = memnew( SpinBox );
+ sb_off_x->set_min(-256);
+ sb_off_x->set_max(256);
+ sb_off_x->set_step(1);
+ sb_off_x->set_val(snap_offset.x);
+ sb_off_x->set_suffix("px");
+ sb_off_x->connect("value_changed", this, "_set_snap_off_x");
+ uv_mode_hb->add_child(sb_off_x);
+
+ SpinBox *sb_off_y = memnew( SpinBox );
+ sb_off_y->set_min(-256);
+ sb_off_y->set_max(256);
+ sb_off_y->set_step(1);
+ sb_off_y->set_val(snap_offset.y);
+ sb_off_y->set_suffix("px");
+ sb_off_y->connect("value_changed", this, "_set_snap_off_y");
+ uv_mode_hb->add_child(sb_off_y);
+
+ uv_mode_hb->add_child( memnew( VSeparator ));
+ uv_mode_hb->add_child( memnew( Label("Grid Step:") ) );
+
+ SpinBox *sb_step_x = memnew( SpinBox );
+ sb_step_x->set_min(-256);
+ sb_step_x->set_max(256);
+ sb_step_x->set_step(1);
+ sb_step_x->set_val(snap_step.x);
+ sb_step_x->set_suffix("px");
+ sb_step_x->connect("value_changed", this, "_set_snap_step_x");
+ uv_mode_hb->add_child(sb_step_x);
+
+ SpinBox *sb_step_y = memnew( SpinBox );
+ sb_step_y->set_min(-256);
+ sb_step_y->set_max(256);
+ sb_step_y->set_step(1);
+ sb_step_y->set_val(snap_step.y);
+ sb_step_y->set_suffix("px");
+ sb_step_y->connect("value_changed", this, "_set_snap_step_y");
+ uv_mode_hb->add_child(sb_step_y);
+
uv_mode_hb->add_child( memnew( VSeparator ));
uv_icon_zoom = memnew( TextureFrame );
- uv_main_hb->add_child( uv_icon_zoom );
+ uv_mode_hb->add_child( uv_icon_zoom );
uv_zoom = memnew( HSlider );
uv_zoom->set_min(0.01);
uv_zoom->set_max(4);
diff --git a/tools/editor/plugins/polygon_2d_editor_plugin.h b/tools/editor/plugins/polygon_2d_editor_plugin.h
index 8f807cb7e8..0939c44264 100644
--- a/tools/editor/plugins/polygon_2d_editor_plugin.h
+++ b/tools/editor/plugins/polygon_2d_editor_plugin.h
@@ -41,6 +41,8 @@ class Polygon2DEditor : public HBoxContainer {
UVMode uv_mode;
AcceptDialog *uv_edit;
ToolButton *uv_button[4];
+ ToolButton *b_snap_enable;
+ ToolButton *b_snap_grid;
Control *uv_edit_draw;
HSlider *uv_zoom;
SpinBox *uv_zoom_value;
@@ -78,6 +80,11 @@ class Polygon2DEditor : public HBoxContainer {
Vector<Vector2> wip;
bool wip_active;
+ bool use_snap;
+ bool snap_show_grid;
+ Vector2 snap_offset;
+ Vector2 snap_step;
+
void _uv_scroll_changed(float);
void _uv_input(const InputEvent& p_input);
void _uv_draw();
@@ -86,10 +93,20 @@ class Polygon2DEditor : public HBoxContainer {
void _canvas_draw();
void _menu_option(int p_option);
+ void _set_use_snap(bool p_use);
+ void _set_show_grid(bool p_show);
+ void _set_snap_off_x(float p_val);
+ void _set_snap_off_y(float p_val);
+ void _set_snap_step_x(float p_val);
+ void _set_snap_step_y(float p_val);
+
protected:
void _notification(int p_what);
void _node_removed(Node *p_node);
static void _bind_methods();
+
+ Vector2 snap_point(Vector2 p_target) const;
+
public:
bool forward_input_event(const InputEvent& p_event);
diff --git a/tools/editor/plugins/resource_preloader_editor_plugin.cpp b/tools/editor/plugins/resource_preloader_editor_plugin.cpp
index 9cd20ac53a..8490f63ff0 100644
--- a/tools/editor/plugins/resource_preloader_editor_plugin.cpp
+++ b/tools/editor/plugins/resource_preloader_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -356,11 +356,16 @@ bool ResourcePreloaderEditorPlugin::handles(Object *p_object) const {
void ResourcePreloaderEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
- preloader_editor->show();
+ //preloader_editor->show();
+ button->show();
+ editor->make_bottom_panel_item_visible(preloader_editor);
// preloader_editor->set_process(true);
} else {
- preloader_editor->hide();
+ if (preloader_editor->is_visible())
+ editor->hide_bottom_panel();
+ button->hide();
+ //preloader_editor->hide();
// preloader_editor->set_process(false);
}
@@ -370,11 +375,14 @@ ResourcePreloaderEditorPlugin::ResourcePreloaderEditorPlugin(EditorNode *p_node)
editor=p_node;
preloader_editor = memnew( ResourcePreloaderEditor );
- editor->get_viewport()->add_child(preloader_editor);
- preloader_editor->set_area_as_parent_rect();
+ preloader_editor->set_custom_minimum_size(Size2(0,250));
+
+ button=editor->add_bottom_panel_item("ResourcePreloader",preloader_editor);
+ button->hide();
+
// preloader_editor->set_anchor( MARGIN_TOP, Control::ANCHOR_END);
// preloader_editor->set_margin( MARGIN_TOP, 120 );
- preloader_editor->hide();
+
diff --git a/tools/editor/plugins/resource_preloader_editor_plugin.h b/tools/editor/plugins/resource_preloader_editor_plugin.h
index 88272bc603..53436797a9 100644
--- a/tools/editor/plugins/resource_preloader_editor_plugin.h
+++ b/tools/editor/plugins/resource_preloader_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -85,6 +85,7 @@ class ResourcePreloaderEditorPlugin : public EditorPlugin {
ResourcePreloaderEditor *preloader_editor;
EditorNode *editor;
+ Button *button;
public:
diff --git a/tools/editor/plugins/rich_text_editor_plugin.cpp b/tools/editor/plugins/rich_text_editor_plugin.cpp
index a0daad854f..08374d6624 100644
--- a/tools/editor/plugins/rich_text_editor_plugin.cpp
+++ b/tools/editor/plugins/rich_text_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/plugins/rich_text_editor_plugin.h b/tools/editor/plugins/rich_text_editor_plugin.h
index 478dc0d308..ae1d04be01 100644
--- a/tools/editor/plugins/rich_text_editor_plugin.h
+++ b/tools/editor/plugins/rich_text_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/plugins/sample_editor_plugin.cpp b/tools/editor/plugins/sample_editor_plugin.cpp
index 31fa7246ae..ffa39bd010 100644
--- a/tools/editor/plugins/sample_editor_plugin.cpp
+++ b/tools/editor/plugins/sample_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -156,8 +156,14 @@ void SampleEditor::generate_preview_texture(const Ref<Sample>& p_sample,Ref<Imag
ima_adpcm.last_nibble++;
const uint8_t *src_ptr=sdata;
+ int ofs = ima_adpcm.last_nibble>>1;
+
+ if (stereo)
+ ofs*=2;
+
nibble = (ima_adpcm.last_nibble&1)?
- (src_ptr[ima_adpcm.last_nibble>>1]>>4):(src_ptr[ima_adpcm.last_nibble>>1]&0xF);
+ (src_ptr[ofs]>>4):(src_ptr[ofs]&0xF);
+
step=_ima_adpcm_step_table[ima_adpcm.step_index];
ima_adpcm.step_index += _ima_adpcm_index_table[nibble];
diff --git a/tools/editor/plugins/sample_editor_plugin.h b/tools/editor/plugins/sample_editor_plugin.h
index e615667914..22dc75b53b 100644
--- a/tools/editor/plugins/sample_editor_plugin.h
+++ b/tools/editor/plugins/sample_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/plugins/sample_library_editor_plugin.cpp b/tools/editor/plugins/sample_library_editor_plugin.cpp
index cf9a6c41a4..a28fbb2ec8 100644
--- a/tools/editor/plugins/sample_library_editor_plugin.cpp
+++ b/tools/editor/plugins/sample_library_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -49,9 +49,13 @@ void SampleLibraryEditor::_notification(int p_what) {
if (p_what==NOTIFICATION_ENTER_TREE) {
play->set_icon( get_icon("Play","EditorIcons") );
+ play->set_tooltip("Play Sample");
stop->set_icon( get_icon("Stop","EditorIcons") );
+ stop->set_tooltip("Stop Sample");
load->set_icon( get_icon("Folder","EditorIcons") );
+ load->set_tooltip("Open Sample File(s)");
_delete->set_icon( get_icon("Del","EditorIcons") );
+ _delete->set_tooltip("Remove Sample");
}
if (p_what==NOTIFICATION_READY) {
@@ -419,11 +423,16 @@ bool SampleLibraryEditorPlugin::handles(Object *p_object) const {
void SampleLibraryEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
- sample_library_editor->show();
+ //sample_library_editor->show();
+ button->show();
+ editor->make_bottom_panel_item_visible(sample_library_editor);
// sample_library_editor->set_process(true);
} else {
- sample_library_editor->hide();
+ if (sample_library_editor->is_visible())
+ editor->hide_bottom_panel();
+ button->hide();
+
// sample_library_editor->set_process(false);
}
@@ -433,11 +442,16 @@ SampleLibraryEditorPlugin::SampleLibraryEditorPlugin(EditorNode *p_node) {
editor=p_node;
sample_library_editor = memnew( SampleLibraryEditor );
- editor->get_viewport()->add_child(sample_library_editor);
- sample_library_editor->set_area_as_parent_rect();
+
+ //editor->get_viewport()->add_child(sample_library_editor);
+ sample_library_editor->set_custom_minimum_size(Size2(0,250));
+ button=p_node->add_bottom_panel_item("SampleLibrary",sample_library_editor);
+ button->hide();
+
+ //sample_library_editor->set_area_as_parent_rect();
// sample_library_editor->set_anchor( MARGIN_TOP, Control::ANCHOR_END);
// sample_library_editor->set_margin( MARGIN_TOP, 120 );
- sample_library_editor->hide();
+ //sample_library_editor->hide();
diff --git a/tools/editor/plugins/sample_library_editor_plugin.h b/tools/editor/plugins/sample_library_editor_plugin.h
index 2770ca2d9a..cbdcf5fc3f 100644
--- a/tools/editor/plugins/sample_library_editor_plugin.h
+++ b/tools/editor/plugins/sample_library_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -90,6 +90,7 @@ class SampleLibraryEditorPlugin : public EditorPlugin {
SampleLibraryEditor *sample_library_editor;
EditorNode *editor;
+ Button *button;
public:
diff --git a/tools/editor/plugins/sample_player_editor_plugin.cpp b/tools/editor/plugins/sample_player_editor_plugin.cpp
index f1c7ca8c98..3085ad87d8 100644
--- a/tools/editor/plugins/sample_player_editor_plugin.cpp
+++ b/tools/editor/plugins/sample_player_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/plugins/sample_player_editor_plugin.h b/tools/editor/plugins/sample_player_editor_plugin.h
index cdd1a99c17..013b042487 100644
--- a/tools/editor/plugins/sample_player_editor_plugin.h
+++ b/tools/editor/plugins/sample_player_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/plugins/script_editor_plugin.cpp b/tools/editor/plugins/script_editor_plugin.cpp
index 71ce040b05..1e16f32e6e 100644
--- a/tools/editor/plugins/script_editor_plugin.cpp
+++ b/tools/editor/plugins/script_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -43,6 +43,83 @@
/*** SCRIPT EDITOR ****/
+class EditorScriptCodeCompletionCache : public ScriptCodeCompletionCache {
+
+
+ struct Cache {
+ uint64_t time_loaded;
+ RES cache;
+ };
+
+ Map<String,Cache> cached;
+
+
+public:
+
+ uint64_t max_time_cache;
+ int max_cache_size;
+
+ void cleanup() {
+
+ List< Map<String,Cache>::Element * > to_clean;
+
+
+ Map<String,Cache>::Element *I=cached.front();
+ while(I) {
+ if ((OS::get_singleton()->get_ticks_msec()-I->get().time_loaded)>max_time_cache) {
+ to_clean.push_back(I);
+ }
+ I=I->next();
+ }
+
+ while(to_clean.front()) {
+ cached.erase(to_clean.front()->get());
+ to_clean.pop_front();
+ }
+ }
+
+ RES get_cached_resource(const String& p_path) {
+
+ Map<String,Cache>::Element *E=cached.find(p_path);
+ if (!E) {
+
+ Cache c;
+ c.cache=ResourceLoader::load(p_path);
+ E=cached.insert(p_path,c);
+ }
+
+ E->get().time_loaded=OS::get_singleton()->get_ticks_msec();
+
+ if (cached.size()>max_cache_size) {
+ uint64_t older;
+ Map<String,Cache>::Element *O=cached.front();
+ older=O->get().time_loaded;
+ Map<String,Cache>::Element *I=O;
+ while(I) {
+ if (I->get().time_loaded<older) {
+ older = I->get().time_loaded;
+ O=I;
+ }
+ I=I->next();
+ }
+
+ if (O!=E) {//should never heppane..
+ cached.erase(O);
+ }
+ }
+
+ return E->get().cache;
+ }
+
+
+ EditorScriptCodeCompletionCache() {
+
+ max_cache_size=128;
+ max_time_cache=5*60*1000; //minutes, five
+ }
+
+};
+
#define SORT_SCRIPT_LIST
void ScriptEditorQuickOpen::popup(const Vector<String>& p_functions, bool p_dontclear) {
@@ -134,7 +211,6 @@ void ScriptEditorQuickOpen::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_confirmed"),&ScriptEditorQuickOpen::_confirmed);
ObjectTypeDB::bind_method(_MD("_sbox_input"),&ScriptEditorQuickOpen::_sbox_input);
-
ADD_SIGNAL(MethodInfo("goto_line",PropertyInfo(Variant::INT,"line")));
}
@@ -240,16 +316,22 @@ void ScriptTextEditor::_load_theme_settings() {
get_text_edit()->add_keyword_color("Color",basetype_color);
get_text_edit()->add_keyword_color("Image",basetype_color);
get_text_edit()->add_keyword_color("InputEvent",basetype_color);
+ get_text_edit()->add_keyword_color("Rect2",basetype_color);
+ get_text_edit()->add_keyword_color("NodePath",basetype_color);
//colorize engine types
Color type_color= EDITOR_DEF("text_editor/engine_type_color",Color(0.0,0.2,0.4));
- List<String> types;
+ List<StringName> types;
ObjectTypeDB::get_type_list(&types);
- for(List<String>::Element *E=types.front();E;E=E->next()) {
+ for(List<StringName>::Element *E=types.front();E;E=E->next()) {
+
+ String n = E->get();
+ if (n.begins_with("_"))
+ n = n.substr(1, n.length());
- get_text_edit()->add_keyword_color(E->get(),type_color);
+ get_text_edit()->add_keyword_color(n,type_color);
}
//colorize comments
@@ -303,6 +385,8 @@ void ScriptTextEditor::reload_text() {
te->set_h_scroll(h);
te->set_v_scroll(v);
+ te->tag_saved_version();
+
_line_col_changed();
}
@@ -315,6 +399,12 @@ void ScriptTextEditor::_notification(int p_what) {
}
}
+
+bool ScriptTextEditor::is_unsaved() {
+
+ return get_text_edit()->get_version()!=get_text_edit()->get_saved_version();
+}
+
String ScriptTextEditor::get_name() {
String name;
@@ -416,6 +506,59 @@ static Node* _find_node_for_script(Node* p_base, Node*p_current, const Ref<Scrip
return NULL;
}
+static void _find_changed_scripts_for_external_editor(Node* p_base, Node*p_current, Set<Ref<Script> > &r_scripts) {
+
+ if (p_current->get_owner()!=p_base && p_base!=p_current)
+ return;
+ Ref<Script> c = p_current->get_script();
+
+ if (c.is_valid())
+ r_scripts.insert(c);
+
+ for(int i=0;i<p_current->get_child_count();i++) {
+ _find_changed_scripts_for_external_editor(p_base,p_current->get_child(i),r_scripts);
+ }
+
+}
+
+void ScriptEditor::_update_modified_scripts_for_external_editor() {
+
+ if (!bool(EditorSettings::get_singleton()->get("external_editor/use_external_editor")))
+ return;
+
+ Set<Ref<Script> > scripts;
+
+ Node *base = get_tree()->get_edited_scene_root();
+ if (base) {
+ _find_changed_scripts_for_external_editor(base,base,scripts);
+ }
+
+ for (Set<Ref<Script> >::Element *E=scripts.front();E;E=E->next()) {
+
+ Ref<Script> script = E->get();
+
+ if (script->get_path()=="" || script->get_path().find("local://")!=-1 || script->get_path().find("::")!=-1) {
+
+ continue; //internal script, who cares, though weird
+ }
+
+ uint64_t last_date = script->get_last_modified_time();
+ uint64_t date = FileAccess::get_modified_time(script->get_path());
+
+ if (last_date!=date) {
+
+ Ref<Script> rel_script = ResourceLoader::load(script->get_path(),script->get_type(),true);
+ ERR_CONTINUE(!rel_script.is_valid());
+ script->set_source_code( rel_script->get_source_code() );
+ script->set_last_modified_time( rel_script->get_last_modified_time() );
+ script->update_exports();
+ }
+
+ }
+}
+
+
+
void ScriptTextEditor::_code_complete_script(const String& p_code, List<String>* r_options) {
Node *base = get_tree()->get_edited_scene_root();
@@ -467,7 +610,10 @@ void ScriptEditor::_breaked(bool p_breaked,bool p_can_debug) {
void ScriptEditor::_show_debugger(bool p_show) {
debug_menu->get_popup()->set_item_checked( debug_menu->get_popup()->get_item_index(DEBUG_SHOW), p_show);
+}
+void ScriptEditor::_script_created(Ref<Script> p_script) {
+ editor->push_item(p_script.operator->());
}
void ScriptEditor::_goto_script_line2(int p_line) {
@@ -492,28 +638,119 @@ void ScriptEditor::_goto_script_line(REF p_script,int p_line) {
}
+
+void ScriptEditor::_update_history_arrows() {
+
+ script_back->set_disabled( history_pos<=0 );
+ script_forward->set_disabled( history_pos>=history.size()-1 );
+}
+
+
+void ScriptEditor::_go_to_tab(int p_idx) {
+
+ Node *cn = tab_container->get_child(p_idx);
+ if (!cn)
+ return;
+ Control *c = cn->cast_to<Control>();
+ if (!c)
+ return;
+
+ if (history_pos>=0 && history_pos<history.size() && history[history_pos].control==tab_container->get_current_tab_control()) {
+
+ Node *n = tab_container->get_current_tab_control();
+
+ if (n->cast_to<ScriptTextEditor>()) {
+
+ history[history_pos].scroll_pos=n->cast_to<ScriptTextEditor>()->get_text_edit()->get_v_scroll();
+ history[history_pos].cursor_column=n->cast_to<ScriptTextEditor>()->get_text_edit()->cursor_get_column();
+ history[history_pos].cursor_row=n->cast_to<ScriptTextEditor>()->get_text_edit()->cursor_get_line();
+ }
+ if (n->cast_to<EditorHelp>()) {
+
+ history[history_pos].scroll_pos=n->cast_to<EditorHelp>()->get_scroll();
+ }
+ }
+
+ history.resize(history_pos+1);
+ ScriptHistory sh;
+ sh.control=c;
+ sh.scroll_pos=0;
+
+ history.push_back(sh);
+ history_pos++;
+
+
+ tab_container->set_current_tab(p_idx);
+
+ c = tab_container->get_current_tab_control();
+
+ if (c->cast_to<ScriptTextEditor>()) {
+
+ script_name_label->set_text(c->cast_to<ScriptTextEditor>()->get_name());
+ script_icon->set_texture(c->cast_to<ScriptTextEditor>()->get_icon());
+ if (is_visible())
+ c->cast_to<ScriptTextEditor>()->get_text_edit()->grab_focus();
+ }
+ if (c->cast_to<EditorHelp>()) {
+
+ script_name_label->set_text(c->cast_to<EditorHelp>()->get_class_name());
+ script_icon->set_texture(get_icon("Help","EditorIcons"));
+ if (is_visible())
+ c->cast_to<EditorHelp>()->set_focused();
+ }
+
+
+
+ c->set_meta("__editor_pass",++edit_pass);
+ _update_history_arrows();
+ _update_script_colors();
+}
+
void ScriptEditor::_close_current_tab() {
int selected = tab_container->get_current_tab();
if (selected<0 || selected>=tab_container->get_child_count())
return;
-
+
+ Node *tselected = tab_container->get_child(selected);
ScriptTextEditor *current = tab_container->get_child(selected)->cast_to<ScriptTextEditor>();
- if (!current)
- return;
+ if (current) {
+ apply_scripts();
+ }
- apply_scripts();
+ //remove from history
+ history.resize(history_pos+1);
+
+ for(int i=0;i<history.size();i++) {
+ if (history[i].control==tselected) {
+ history.remove(i);
+ i--;
+ history_pos--;
+ }
+ }
+
+ if (history_pos>=history.size()) {
+ history_pos=history.size()-1;
+ }
int idx = tab_container->get_current_tab();
- memdelete(current);
+ memdelete(tselected);
if (idx>=tab_container->get_child_count())
idx=tab_container->get_child_count()-1;
if (idx>=0) {
+
+ if (history_pos>=0) {
+ idx = history[history_pos].control->get_index();
+ }
tab_container->set_current_tab(idx);
+
//script_list->select(idx);
}
+ _update_history_arrows();
+
+
_update_script_names();
EditorNode::get_singleton()->save_layout();
@@ -578,6 +815,7 @@ void ScriptEditor::_reload_scripts(){
}
disk_changed->hide();
+ _update_script_names();
}
@@ -620,46 +858,53 @@ bool ScriptEditor::_test_script_times_on_disk() {
TreeItem *r = disk_changed_list->create_item();
disk_changed_list->set_hide_root(true);
- bool all_ok=true;
+ bool need_ask=false;
+ bool need_reload=false;
+ bool use_autoreload=bool(EDITOR_DEF("text_editor/auto_reload_scripts_on_external_change",false));
+
for(int i=0;i<tab_container->get_child_count();i++) {
ScriptTextEditor *ste = tab_container->get_child(i)->cast_to<ScriptTextEditor>();
- if (!ste)
- continue;
+ if (ste) {
+ Ref<Script> script = ste->get_edited_script();
- Ref<Script> script = ste->get_edited_script();
+ if (script->get_path()=="" || script->get_path().find("local://")!=-1 || script->get_path().find("::")!=-1)
+ continue; //internal script, who cares
- if (script->get_path()=="" || script->get_path().find("local://")!=-1 || script->get_path().find("::")!=-1)
- continue; //internal script, who cares
+ uint64_t last_date = script->get_last_modified_time();
+ uint64_t date = FileAccess::get_modified_time(script->get_path());
- uint64_t last_date = script->get_last_modified_time();
- uint64_t date = FileAccess::get_modified_time(script->get_path());
+ //printf("last date: %lli vs date: %lli\n",last_date,date);
+ if (last_date!=date) {
- //printf("last date: %lli vs date: %lli\n",last_date,date);
- if (last_date!=date) {
+ TreeItem *ti = disk_changed_list->create_item(r);
+ ti->set_text(0,script->get_path().get_file());
- TreeItem *ti = disk_changed_list->create_item(r);
- ti->set_text(0,script->get_path().get_file());
- all_ok=false;
- //r->set_metadata(0,);
+ if (!use_autoreload || ste->is_unsaved()) {
+ need_ask=true;
+ }
+ need_reload=true;
+ //r->set_metadata(0,);
+ }
}
}
- if (!all_ok) {
- if (bool(EDITOR_DEF("text_editor/auto_reload_changed_scripts",false))) {
+ if (need_reload) {
+ if (!need_ask) {
script_editor->_reload_scripts();
+ need_reload=false;
} else {
disk_changed->call_deferred("popup_centered_ratio",0.5);
}
}
- return all_ok;
+ return need_reload;
}
void ScriptEditor::swap_lines(TextEdit *tx, int line1, int line2)
@@ -675,31 +920,15 @@ void ScriptEditor::swap_lines(TextEdit *tx, int line1, int line2)
void ScriptEditor::_menu_option(int p_option) {
- if (p_option==FILE_OPEN) {
-
- editor->open_resource("Script");
- return;
- }
- int selected = tab_container->get_current_tab();
- if (selected<0 || selected>=tab_container->get_child_count())
- return;
-
- ScriptTextEditor *current = tab_container->get_child(selected)->cast_to<ScriptTextEditor>();
- if (!current)
- return;
-
switch(p_option) {
- case FILE_SAVE: {
-
- if (!_test_script_times_on_disk())
- return;
- editor->save_resource( current->get_edited_script() );
-
+ case FILE_NEW: {
+ script_create_dialog->config("Node", ".gd");
+ script_create_dialog->popup_centered(Size2(300, 300));
} break;
- case FILE_SAVE_AS: {
-
- editor->save_resource_as( current->get_edited_script() );
+ case FILE_OPEN: {
+ editor->open_resource("Script");
+ return;
} break;
case FILE_SAVE_ALL: {
@@ -724,329 +953,38 @@ void ScriptEditor::_menu_option(int p_option) {
} break;
- case EDIT_UNDO: {
- current->get_text_edit()->undo();
- current->get_text_edit()->call_deferred("grab_focus");
- } break;
- case EDIT_REDO: {
- current->get_text_edit()->redo();
- current->get_text_edit()->call_deferred("grab_focus");
- } break;
- case EDIT_CUT: {
-
- current->get_text_edit()->cut();
- current->get_text_edit()->call_deferred("grab_focus");
- } break;
- case EDIT_COPY: {
- current->get_text_edit()->copy();
- current->get_text_edit()->call_deferred("grab_focus");
-
- } break;
- case EDIT_PASTE: {
- current->get_text_edit()->paste();
- current->get_text_edit()->call_deferred("grab_focus");
+ case SEARCH_HELP: {
+ help_search_dialog->popup();
} break;
- case EDIT_SELECT_ALL: {
+ case SEARCH_CLASSES: {
- current->get_text_edit()->select_all();
- current->get_text_edit()->call_deferred("grab_focus");
+ String current;
- } break;
- case EDIT_MOVE_LINE_UP: {
-
- TextEdit *tx = current->get_text_edit();
- Ref<Script> scr = current->get_edited_script();
- if (scr.is_null())
- return;
-
- if (tx->is_selection_active())
- {
- int from_line = tx->get_selection_from_line();
- int from_col = tx->get_selection_from_column();
- int to_line = tx->get_selection_to_line();
- int to_column = tx->get_selection_to_column();
-
- for (int i = from_line; i <= to_line; i++)
- {
- int line_id = i;
- int next_id = i - 1;
-
- if (line_id == 0 || next_id < 0)
- return;
-
- swap_lines(tx, line_id, next_id);
- }
- int from_line_up = from_line > 0 ? from_line-1 : from_line;
- int to_line_up = to_line > 0 ? to_line-1 : to_line;
- tx->select(from_line_up, from_col, to_line_up, to_column);
- }
- else
- {
- int line_id = tx->cursor_get_line();
- int next_id = line_id - 1;
-
- if (line_id == 0 || next_id < 0)
- return;
-
- swap_lines(tx, line_id, next_id);
- }
- tx->update();
-
- } break;
- case EDIT_MOVE_LINE_DOWN: {
-
- TextEdit *tx = current->get_text_edit();
- Ref<Script> scr = current->get_edited_script();
- if (scr.is_null())
- return;
-
- if (tx->is_selection_active())
- {
- int from_line = tx->get_selection_from_line();
- int from_col = tx->get_selection_from_column();
- int to_line = tx->get_selection_to_line();
- int to_column = tx->get_selection_to_column();
-
- for (int i = to_line; i >= from_line; i--)
- {
- int line_id = i;
- int next_id = i + 1;
-
- if (line_id == tx->get_line_count()-1 || next_id > tx->get_line_count())
- return;
-
- swap_lines(tx, line_id, next_id);
- }
- int from_line_down = from_line < tx->get_line_count() ? from_line+1 : from_line;
- int to_line_down = to_line < tx->get_line_count() ? to_line+1 : to_line;
- tx->select(from_line_down, from_col, to_line_down, to_column);
- }
- else
- {
- int line_id = tx->cursor_get_line();
- int next_id = line_id + 1;
-
- if (line_id == tx->get_line_count()-1 || next_id > tx->get_line_count())
- return;
-
- swap_lines(tx, line_id, next_id);
- }
- tx->update();
-
- } break;
- case EDIT_INDENT_LEFT: {
-
- TextEdit *tx = current->get_text_edit();
- Ref<Script> scr = current->get_edited_script();
- if (scr.is_null())
- return;
-
-
- if (tx->is_selection_active())
- {
- int begin = tx->get_selection_from_line();
- int end = tx->get_selection_to_line();
- for (int i = begin; i <= end; i++)
- {
- String line_text = tx->get_line(i);
- // begins with tab
- if (line_text.begins_with("\t"))
- {
- line_text = line_text.substr(1, line_text.length());
- tx->set_line(i, line_text);
- }
- // begins with 4 spaces
- else if (line_text.begins_with(" "))
- {
- line_text = line_text.substr(4, line_text.length());
- tx->set_line(i, line_text);
- }
- }
- }
- else
- {
- int begin = tx->cursor_get_line();
- String line_text = tx->get_line(begin);
- // begins with tab
- if (line_text.begins_with("\t"))
- {
- line_text = line_text.substr(1, line_text.length());
- tx->set_line(begin, line_text);
- }
- // begins with 4 spaces
- else if (line_text.begins_with(" "))
- {
- line_text = line_text.substr(4, line_text.length());
- tx->set_line(begin, line_text);
- }
- }
- tx->update();
- //tx->deselect();
-
- } break;
- case EDIT_INDENT_RIGHT: {
-
- TextEdit *tx = current->get_text_edit();
- Ref<Script> scr = current->get_edited_script();
- if (scr.is_null())
- return;
-
- if (tx->is_selection_active())
- {
- int begin = tx->get_selection_from_line();
- int end = tx->get_selection_to_line();
- for (int i = begin; i <= end; i++)
- {
- String line_text = tx->get_line(i);
- line_text = '\t' + line_text;
- tx->set_line(i, line_text);
- }
- }
- else
- {
- int begin = tx->cursor_get_line();
- String line_text = tx->get_line(begin);
- line_text = '\t' + line_text;
- tx->set_line(begin, line_text);
- }
- tx->update();
- //tx->deselect();
-
- } break;
- case EDIT_CLONE_DOWN: {
-
- TextEdit *tx = current->get_text_edit();
- Ref<Script> scr = current->get_edited_script();
- if (scr.is_null())
- return;
- int line = tx->cursor_get_line();
- int next_line = line + 1;
-
- if (line == tx->get_line_count() || next_line > tx->get_line_count())
- return;
-
- String line_clone = tx->get_line(line);
- tx->insert_at(line_clone, next_line);
- tx->update();
-
- } break;
- case EDIT_TOGGLE_COMMENT: {
-
- TextEdit *tx = current->get_text_edit();
- Ref<Script> scr = current->get_edited_script();
- if (scr.is_null())
- return;
-
-
-
- if (tx->is_selection_active())
- {
- int begin = tx->get_selection_from_line();
- int end = tx->get_selection_to_line();
- for (int i = begin; i <= end; i++)
- {
- String line_text = tx->get_line(i);
-
- if (line_text.begins_with("#"))
- line_text = line_text.substr(1, line_text.length());
- else
- line_text = "#" + line_text;
- tx->set_line(i, line_text);
- }
- }
- else
- {
- int begin = tx->cursor_get_line();
- String line_text = tx->get_line(begin);
-
- if (line_text.begins_with("#"))
- line_text = line_text.substr(1, line_text.length());
- else
- line_text = "#" + line_text;
- tx->set_line(begin, line_text);
- }
- tx->update();
- //tx->deselect();
-
- } break;
- case EDIT_COMPLETE: {
-
- current->get_text_edit()->query_code_comple();
-
- } break;
- case EDIT_AUTO_INDENT: {
-
- TextEdit *te = current->get_text_edit();
- String text = te->get_text();
- Ref<Script> scr = current->get_edited_script();
- if (scr.is_null())
- return;
- int begin,end;
- if (te->is_selection_active()) {
- begin=te->get_selection_from_line();
- end=te->get_selection_to_line();
- } else {
- begin=0;
- end=te->get_line_count()-1;
+ if (tab_container->get_tab_count()>0) {
+ EditorHelp *eh = tab_container->get_child( tab_container->get_current_tab() )->cast_to<EditorHelp>();
+ if (eh) {
+ current=eh->get_class_name();
+ }
}
- scr->get_language()->auto_indent_code(text,begin,end);
- te->set_text(text);
+ help_index->popup_centered_ratio(0.6);
+ if (current!="") {
+ help_index->call_deferred("select_class",current);
+ }
} break;
- case SEARCH_FIND: {
-
- find_replace_dialog->set_text_edit(current->get_text_edit());
- find_replace_dialog->popup_search();
- } break;
- case SEARCH_FIND_NEXT: {
-
- find_replace_dialog->set_text_edit(current->get_text_edit());
- find_replace_dialog->search_next();
- } break;
- case SEARCH_REPLACE: {
-
- find_replace_dialog->set_text_edit(current->get_text_edit());
- find_replace_dialog->popup_replace();
- } break;
- case SEARCH_LOCATE_FUNCTION: {
-
- if (!current)
- return;
- quick_open->popup(current->get_functions());
- } break;
- case SEARCH_GOTO_LINE: {
-
- goto_line_dialog->popup_find_line(current->get_text_edit());
- } break;
- case DEBUG_TOGGLE_BREAKPOINT: {
- int line=current->get_text_edit()->cursor_get_line();
- bool dobreak = !current->get_text_edit()->is_line_set_as_breakpoint(line);
- current->get_text_edit()->set_line_as_breakpoint(line,dobreak);
- } break;
- case DEBUG_NEXT: {
-
- if (debugger)
- debugger->debug_next();
- } break;
- case DEBUG_STEP: {
-
- if (debugger)
- debugger->debug_step();
+ case SEARCH_WEBSITE: {
+ OS::get_singleton()->shell_open("http://www.godotengine.org/projects/godot-engine/wiki/Documentation#Tutorials");
} break;
- case DEBUG_BREAK: {
- if (debugger)
- debugger->debug_break();
+ case WINDOW_NEXT: {
+ _history_forward();
} break;
- case DEBUG_CONTINUE: {
-
- if (debugger)
- debugger->debug_continue();
-
+ case WINDOW_PREV: {
+ _history_back();
} break;
case DEBUG_SHOW: {
if (debugger) {
@@ -1058,52 +996,433 @@ void ScriptEditor::_menu_option(int p_option) {
debugger->show();
}
} break;
- case HELP_CONTEXTUAL: {
- String text = current->get_text_edit()->get_selection_text();
- if (text == "")
- text = current->get_text_edit()->get_word_under_cursor();
- if (text != "")
- editor->emit_signal("request_help", text);
- } break;
- case FILE_CLOSE: {
- if (current->get_text_edit()->get_version()!=current->get_text_edit()->get_saved_version()) {
- erase_tab_confirm->set_text("Close and save changes?\n\""+current->get_name()+"\"");
- erase_tab_confirm->popup_centered_minsize();
- } else {
- _close_current_tab();
- }
+ case DEBUG_SHOW_KEEP_OPEN: {
+ bool visible = debug_menu->get_popup()->is_item_checked( debug_menu->get_popup()->get_item_index(DEBUG_SHOW_KEEP_OPEN) );
+ if (debugger)
+ debugger->set_hide_on_stop(visible);
+ debug_menu->get_popup()->set_item_checked( debug_menu->get_popup()->get_item_index(DEBUG_SHOW_KEEP_OPEN), !visible);
} break;
- case WINDOW_MOVE_LEFT: {
+ }
- if (tab_container->get_current_tab()>0) {
- tab_container->call_deferred("set_current_tab",tab_container->get_current_tab()-1);
- script_list->call_deferred("select",tab_container->get_current_tab()-1);
- tab_container->move_child(current,tab_container->get_current_tab()-1);
- _update_script_names();
- }
- } break;
- case WINDOW_MOVE_RIGHT: {
- if (tab_container->get_current_tab()<tab_container->get_child_count()-1) {
- tab_container->call_deferred("set_current_tab",tab_container->get_current_tab()+1);
- script_list->call_deferred("select",tab_container->get_current_tab()+1);
- tab_container->move_child(current,tab_container->get_current_tab()+1);
- _update_script_names();
- }
+ int selected = tab_container->get_current_tab();
+ if (selected<0 || selected>=tab_container->get_child_count())
+ return;
+ ScriptTextEditor *current = tab_container->get_child(selected)->cast_to<ScriptTextEditor>();
+ if (current) {
+
+ switch(p_option) {
+ case FILE_NEW: {
+ script_create_dialog->config("Node", ".gd");
+ script_create_dialog->popup_centered(Size2(300, 300));
+ } break;
+ case FILE_SAVE: {
+ if (!_test_script_times_on_disk())
+ return;
+ editor->save_resource( current->get_edited_script() );
+
+ } break;
+ case FILE_SAVE_AS: {
+
+ editor->save_resource_as( current->get_edited_script() );
+
+ } break;
+ case EDIT_UNDO: {
+ current->get_text_edit()->undo();
+ current->get_text_edit()->call_deferred("grab_focus");
+ } break;
+ case EDIT_REDO: {
+ current->get_text_edit()->redo();
+ current->get_text_edit()->call_deferred("grab_focus");
+ } break;
+ case EDIT_CUT: {
+
+ current->get_text_edit()->cut();
+ current->get_text_edit()->call_deferred("grab_focus");
+ } break;
+ case EDIT_COPY: {
+ current->get_text_edit()->copy();
+ current->get_text_edit()->call_deferred("grab_focus");
+
+ } break;
+ case EDIT_PASTE: {
+ current->get_text_edit()->paste();
+ current->get_text_edit()->call_deferred("grab_focus");
+
+ } break;
+ case EDIT_SELECT_ALL: {
+
+ current->get_text_edit()->select_all();
+ current->get_text_edit()->call_deferred("grab_focus");
+
+ } break;
+ case EDIT_MOVE_LINE_UP: {
+
+ TextEdit *tx = current->get_text_edit();
+ Ref<Script> scr = current->get_edited_script();
+ if (scr.is_null())
+ return;
+
+ if (tx->is_selection_active())
+ {
+ int from_line = tx->get_selection_from_line();
+ int from_col = tx->get_selection_from_column();
+ int to_line = tx->get_selection_to_line();
+ int to_column = tx->get_selection_to_column();
+
+ for (int i = from_line; i <= to_line; i++)
+ {
+ int line_id = i;
+ int next_id = i - 1;
+
+ if (line_id == 0 || next_id < 0)
+ return;
+
+ swap_lines(tx, line_id, next_id);
+ }
+ int from_line_up = from_line > 0 ? from_line-1 : from_line;
+ int to_line_up = to_line > 0 ? to_line-1 : to_line;
+ tx->select(from_line_up, from_col, to_line_up, to_column);
+ }
+ else
+ {
+ int line_id = tx->cursor_get_line();
+ int next_id = line_id - 1;
- } break;
- default: {
+ if (line_id == 0 || next_id < 0)
+ return;
- if (p_option>=WINDOW_SELECT_BASE) {
+ swap_lines(tx, line_id, next_id);
+ }
+ tx->update();
+
+ } break;
+ case EDIT_MOVE_LINE_DOWN: {
+
+ TextEdit *tx = current->get_text_edit();
+ Ref<Script> scr = current->get_edited_script();
+ if (scr.is_null())
+ return;
+
+ if (tx->is_selection_active())
+ {
+ int from_line = tx->get_selection_from_line();
+ int from_col = tx->get_selection_from_column();
+ int to_line = tx->get_selection_to_line();
+ int to_column = tx->get_selection_to_column();
+
+ for (int i = to_line; i >= from_line; i--)
+ {
+ int line_id = i;
+ int next_id = i + 1;
+
+ if (line_id == tx->get_line_count()-1 || next_id > tx->get_line_count())
+ return;
+
+ swap_lines(tx, line_id, next_id);
+ }
+ int from_line_down = from_line < tx->get_line_count() ? from_line+1 : from_line;
+ int to_line_down = to_line < tx->get_line_count() ? to_line+1 : to_line;
+ tx->select(from_line_down, from_col, to_line_down, to_column);
+ }
+ else
+ {
+ int line_id = tx->cursor_get_line();
+ int next_id = line_id + 1;
- tab_container->set_current_tab(p_option-WINDOW_SELECT_BASE);
- script_list->select(p_option-WINDOW_SELECT_BASE);
+ if (line_id == tx->get_line_count()-1 || next_id > tx->get_line_count())
+ return;
+ swap_lines(tx, line_id, next_id);
+ }
+ tx->update();
+
+ } break;
+ case EDIT_INDENT_LEFT: {
+
+ TextEdit *tx = current->get_text_edit();
+ Ref<Script> scr = current->get_edited_script();
+ if (scr.is_null())
+ return;
+
+
+ if (tx->is_selection_active())
+ {
+ int begin = tx->get_selection_from_line();
+ int end = tx->get_selection_to_line();
+ for (int i = begin; i <= end; i++)
+ {
+ String line_text = tx->get_line(i);
+ // begins with tab
+ if (line_text.begins_with("\t"))
+ {
+ line_text = line_text.substr(1, line_text.length());
+ tx->set_line(i, line_text);
+ }
+ // begins with 4 spaces
+ else if (line_text.begins_with(" "))
+ {
+ line_text = line_text.substr(4, line_text.length());
+ tx->set_line(i, line_text);
+ }
+ }
+ }
+ else
+ {
+ int begin = tx->cursor_get_line();
+ String line_text = tx->get_line(begin);
+ // begins with tab
+ if (line_text.begins_with("\t"))
+ {
+ line_text = line_text.substr(1, line_text.length());
+ tx->set_line(begin, line_text);
+ }
+ // begins with 4 spaces
+ else if (line_text.begins_with(" "))
+ {
+ line_text = line_text.substr(4, line_text.length());
+ tx->set_line(begin, line_text);
+ }
+ }
+ tx->update();
+ //tx->deselect();
+
+ } break;
+ case EDIT_INDENT_RIGHT: {
+
+ TextEdit *tx = current->get_text_edit();
+ Ref<Script> scr = current->get_edited_script();
+ if (scr.is_null())
+ return;
+
+ if (tx->is_selection_active())
+ {
+ int begin = tx->get_selection_from_line();
+ int end = tx->get_selection_to_line();
+ for (int i = begin; i <= end; i++)
+ {
+ String line_text = tx->get_line(i);
+ line_text = '\t' + line_text;
+ tx->set_line(i, line_text);
+ }
+ }
+ else
+ {
+ int begin = tx->cursor_get_line();
+ String line_text = tx->get_line(begin);
+ line_text = '\t' + line_text;
+ tx->set_line(begin, line_text);
+ }
+ tx->update();
+ //tx->deselect();
+
+ } break;
+ case EDIT_CLONE_DOWN: {
+
+ TextEdit *tx = current->get_text_edit();
+ Ref<Script> scr = current->get_edited_script();
+ if (scr.is_null())
+ return;
+ int line = tx->cursor_get_line();
+ int next_line = line + 1;
+ int column = tx->cursor_get_column();
+
+ if (line >= tx->get_line_count() - 1)
+ tx->set_line(line, tx->get_line(line) + "\n");
+
+ String line_clone = tx->get_line(line);
+ tx->insert_at(line_clone, next_line);
+ tx->cursor_set_column(column);
+ tx->update();
+
+ } break;
+ case EDIT_TOGGLE_COMMENT: {
+
+ TextEdit *tx = current->get_text_edit();
+ Ref<Script> scr = current->get_edited_script();
+ if (scr.is_null())
+ return;
+
+
+
+ if (tx->is_selection_active())
+ {
+ int begin = tx->get_selection_from_line();
+ int end = tx->get_selection_to_line();
+ for (int i = begin; i <= end; i++)
+ {
+ String line_text = tx->get_line(i);
+
+ if (line_text.begins_with("#"))
+ line_text = line_text.substr(1, line_text.length());
+ else
+ line_text = "#" + line_text;
+ tx->set_line(i, line_text);
+ }
+ }
+ else
+ {
+ int begin = tx->cursor_get_line();
+ String line_text = tx->get_line(begin);
+
+ if (line_text.begins_with("#"))
+ line_text = line_text.substr(1, line_text.length());
+ else
+ line_text = "#" + line_text;
+ tx->set_line(begin, line_text);
+ }
+ tx->update();
+ //tx->deselect();
+
+ } break;
+ case EDIT_COMPLETE: {
+
+ current->get_text_edit()->query_code_comple();
+
+ } break;
+ case EDIT_AUTO_INDENT: {
+
+ TextEdit *te = current->get_text_edit();
+ String text = te->get_text();
+ Ref<Script> scr = current->get_edited_script();
+ if (scr.is_null())
+ return;
+ int begin,end;
+ if (te->is_selection_active()) {
+ begin=te->get_selection_from_line();
+ end=te->get_selection_to_line();
+ } else {
+ begin=0;
+ end=te->get_line_count()-1;
+ }
+ scr->get_language()->auto_indent_code(text,begin,end);
+ te->set_text(text);
+
+
+ } break;
+ case SEARCH_FIND: {
+
+ find_replace_dialog->set_text_edit(current->get_text_edit());
+ find_replace_dialog->popup_search();
+ } break;
+ case SEARCH_FIND_NEXT: {
+
+ find_replace_dialog->set_text_edit(current->get_text_edit());
+ find_replace_dialog->search_next();
+ } break;
+ case SEARCH_REPLACE: {
+
+ find_replace_dialog->set_text_edit(current->get_text_edit());
+ find_replace_dialog->popup_replace();
+ } break;
+ case SEARCH_LOCATE_FUNCTION: {
+
+ if (!current)
+ return;
+ quick_open->popup(current->get_functions());
+ } break;
+ case SEARCH_GOTO_LINE: {
+
+ goto_line_dialog->popup_find_line(current->get_text_edit());
+ } break;
+ case DEBUG_TOGGLE_BREAKPOINT: {
+ int line=current->get_text_edit()->cursor_get_line();
+ bool dobreak = !current->get_text_edit()->is_line_set_as_breakpoint(line);
+ current->get_text_edit()->set_line_as_breakpoint(line,dobreak);
+ get_debugger()->set_breakpoint(current->get_edited_script()->get_path(),line+1,dobreak);
+ } break;
+ case DEBUG_NEXT: {
+
+ if (debugger)
+ debugger->debug_next();
+ } break;
+ case DEBUG_STEP: {
+
+ if (debugger)
+ debugger->debug_step();
+
+ } break;
+ case DEBUG_BREAK: {
+
+ if (debugger)
+ debugger->debug_break();
+
+ } break;
+ case DEBUG_CONTINUE: {
+
+ if (debugger)
+ debugger->debug_continue();
+
+ } break;
+ case HELP_CONTEXTUAL: {
+ String text = current->get_text_edit()->get_selection_text();
+ if (text == "")
+ text = current->get_text_edit()->get_word_under_cursor();
+ if (text != "")
+ help_search_dialog->popup(text);
+ } break;
+ case FILE_CLOSE: {
+ if (current->get_text_edit()->get_version()!=current->get_text_edit()->get_saved_version()) {
+ erase_tab_confirm->set_text("Close and save changes?\n\""+current->get_name()+"\"");
+ erase_tab_confirm->popup_centered_minsize();
+ } else {
+ _close_current_tab();
+ }
+ } break;
+ case WINDOW_MOVE_LEFT: {
+
+ if (tab_container->get_current_tab()>0) {
+ tab_container->call_deferred("set_current_tab",tab_container->get_current_tab()-1);
+ script_list->call_deferred("select",tab_container->get_current_tab()-1);
+ tab_container->move_child(current,tab_container->get_current_tab()-1);
+ _update_script_names();
+ }
+ } break;
+ case WINDOW_MOVE_RIGHT: {
+
+ if (tab_container->get_current_tab()<tab_container->get_child_count()-1) {
+ tab_container->call_deferred("set_current_tab",tab_container->get_current_tab()+1);
+ script_list->call_deferred("select",tab_container->get_current_tab()+1);
+ tab_container->move_child(current,tab_container->get_current_tab()+1);
+ _update_script_names();
+ }
+
+
+ } break;
+
+ default: {
+
+ if (p_option>=WINDOW_SELECT_BASE) {
+
+ tab_container->set_current_tab(p_option-WINDOW_SELECT_BASE);
+ script_list->select(p_option-WINDOW_SELECT_BASE);
+
+ }
}
}
}
+ EditorHelp *help = tab_container->get_child(selected)->cast_to<EditorHelp>();
+ if (help) {
+
+ switch(p_option) {
+
+ case SEARCH_FIND: {
+ help->popup_search();
+ } break;
+ case SEARCH_FIND_NEXT: {
+ help->search_again();
+ } break;
+ case FILE_CLOSE: {
+ _close_current_tab();
+ } break;
+
+
+ }
+ }
+
+
}
void ScriptEditor::_tab_changed(int p_which) {
@@ -1134,6 +1453,14 @@ void ScriptEditor::_notification(int p_what) {
}
EditorSettings::get_singleton()->connect("settings_changed",this,"_editor_settings_changed");
+ help_search->set_icon(get_icon("Help","EditorIcons"));
+ site_search->set_icon(get_icon("Godot","EditorIcons"));
+ class_search->set_icon(get_icon("ClassList","EditorIcons"));
+
+ script_forward->set_icon(get_icon("Forward","EditorIcons"));
+ script_back->set_icon(get_icon("Back","EditorIcons"));
+
+
}
@@ -1141,6 +1468,7 @@ void ScriptEditor::_notification(int p_what) {
if (p_what==NOTIFICATION_READY) {
get_tree()->connect("tree_changed",this,"_tree_changed");
+ editor->connect("request_help",this,"_request_help");
}
if (p_what==NOTIFICATION_EXIT_TREE) {
@@ -1154,6 +1482,7 @@ void ScriptEditor::_notification(int p_what) {
if (p_what==MainLoop::NOTIFICATION_WM_FOCUS_IN) {
_test_script_times_on_disk();
+ _update_modified_scripts_for_external_editor();
}
if (p_what==NOTIFICATION_PROCESS) {
@@ -1162,6 +1491,11 @@ void ScriptEditor::_notification(int p_what) {
}
+void ScriptEditor::edited_scene_changed() {
+
+ _update_modified_scripts_for_external_editor();
+
+}
static const Node * _find_node_with_script(const Node* p_node, const RefPtr & p_script) {
@@ -1263,7 +1597,7 @@ void ScriptEditor::set_state(const Dictionary& p_state) {
}
void ScriptEditor::clear() {
-
+#if 0
List<ScriptTextEditor*> stes;
for(int i=0;i<tab_container->get_child_count();i++) {
@@ -1288,7 +1622,7 @@ void ScriptEditor::clear() {
script_list->select( script_list->find_metadata(idx) );
}
-
+#endif
}
@@ -1319,30 +1653,6 @@ void ScriptEditor::get_breakpoints(List<String> *p_breakpoints) {
-void ScriptEditor::_bind_methods() {
-
- ObjectTypeDB::bind_method("_tab_changed",&ScriptEditor::_tab_changed);
- ObjectTypeDB::bind_method("_menu_option",&ScriptEditor::_menu_option);
- ObjectTypeDB::bind_method("_close_current_tab",&ScriptEditor::_close_current_tab);
- ObjectTypeDB::bind_method("_editor_play",&ScriptEditor::_editor_play);
- ObjectTypeDB::bind_method("_editor_pause",&ScriptEditor::_editor_pause);
- ObjectTypeDB::bind_method("_editor_stop",&ScriptEditor::_editor_stop);
- ObjectTypeDB::bind_method("_add_callback",&ScriptEditor::_add_callback);
- ObjectTypeDB::bind_method("_reload_scripts",&ScriptEditor::_reload_scripts);
- ObjectTypeDB::bind_method("_resave_scripts",&ScriptEditor::_resave_scripts);
- ObjectTypeDB::bind_method("_res_saved_callback",&ScriptEditor::_res_saved_callback);
- ObjectTypeDB::bind_method("_goto_script_line",&ScriptEditor::_goto_script_line);
- ObjectTypeDB::bind_method("_goto_script_line2",&ScriptEditor::_goto_script_line2);
- ObjectTypeDB::bind_method("_breaked",&ScriptEditor::_breaked);
- ObjectTypeDB::bind_method("_show_debugger",&ScriptEditor::_show_debugger);
- ObjectTypeDB::bind_method("_get_debug_tooltip",&ScriptEditor::_get_debug_tooltip);
- ObjectTypeDB::bind_method("_autosave_scripts",&ScriptEditor::_autosave_scripts);
- ObjectTypeDB::bind_method("_editor_settings_changed",&ScriptEditor::_editor_settings_changed);
- ObjectTypeDB::bind_method("_update_script_names",&ScriptEditor::_update_script_names);
- ObjectTypeDB::bind_method("_tree_changed",&ScriptEditor::_tree_changed);
- ObjectTypeDB::bind_method("_script_selected",&ScriptEditor::_script_selected);
- ObjectTypeDB::bind_method("_script_split_dragged",&ScriptEditor::_script_split_dragged);
-}
void ScriptEditor::ensure_focus_current() {
@@ -1364,7 +1674,8 @@ void ScriptEditor::ensure_focus_current() {
void ScriptEditor::_script_selected(int p_idx) {
grab_focus_block = !Input::get_singleton()->is_mouse_button_pressed(1); //amazing hack, simply amazing
- tab_container->set_current_tab(script_list->get_item_metadata(p_idx));
+
+ _go_to_tab(script_list->get_item_metadata(p_idx));
grab_focus_block=false;
}
@@ -1373,16 +1684,38 @@ void ScriptEditor::ensure_select_current() {
if (tab_container->get_child_count() && tab_container->get_current_tab()>=0) {
- ScriptTextEditor *ste = tab_container->get_child(tab_container->get_current_tab())->cast_to<ScriptTextEditor>();
- if (!ste)
- return;
- Ref<Script> script = ste->get_edited_script();
+ Node *current = tab_container->get_child(tab_container->get_current_tab());
+
+
+ ScriptTextEditor *ste = current->cast_to<ScriptTextEditor>();
+ if (ste) {
+
+ Ref<Script> script = ste->get_edited_script();
+
+ if (!grab_focus_block && is_inside_tree())
+ ste->get_text_edit()->grab_focus();
+
+ edit_menu->show();
+ search_menu->show();
+ script_search_menu->hide();
- if (!grab_focus_block && is_inside_tree())
- ste->get_text_edit()->grab_focus();
+
+ }
+
+ EditorHelp *eh = current->cast_to<EditorHelp>();
+
+ if (eh) {
+ edit_menu->hide();
+ search_menu->hide();
+ script_search_menu->show();
+
+ }
}
+
+
+
}
void ScriptEditor::_find_scripts(Node* p_base, Node* p_current, Set<Ref<Script> > &used) {
@@ -1401,6 +1734,57 @@ void ScriptEditor::_find_scripts(Node* p_base, Node* p_current, Set<Ref<Script>
}
+struct _ScriptEditorItemData {
+
+ String name;
+ Ref<Texture> icon;
+ int index;
+ String tooltip;
+ bool used;
+ int category;
+
+
+ bool operator<(const _ScriptEditorItemData& id) const {
+
+ return category==id.category?name.nocasecmp_to(id.name)<0:category<id.category;
+ }
+
+};
+
+
+void ScriptEditor::_update_script_colors() {
+
+ bool enabled = EditorSettings::get_singleton()->get("text_editor/script_temperature_enabled");
+ if (!enabled)
+ return;
+
+ int hist_size = EditorSettings::get_singleton()->get("text_editor/script_temperature_history_size");
+ Color hot_color=EditorSettings::get_singleton()->get("text_editor/script_temperature_hot_color");
+ Color cold_color=EditorSettings::get_singleton()->get("text_editor/script_temperature_cold_color");
+
+ for(int i=0;i<script_list->get_item_count();i++) {
+
+ int c = script_list->get_item_metadata(i);
+ Node *n = tab_container->get_child(c);
+ if (!n)
+ continue;
+
+ script_list->set_item_custom_bg_color(i,Color(0,0,0,0));
+ if (!n->has_meta("__editor_pass")) {
+ continue;
+ }
+
+ int pass=n->get_meta("__editor_pass");
+ int h = edit_pass - pass;
+ if (h>hist_size) {
+ continue;
+ }
+ float v = Math::ease((edit_pass-pass)/float(hist_size),0.4);
+
+
+ script_list->set_item_custom_bg_color(i,hot_color.linear_interpolate(cold_color,v));
+ }
+}
void ScriptEditor::_update_script_names() {
@@ -1412,31 +1796,75 @@ void ScriptEditor::_update_script_names() {
}
script_list->clear();
+ bool split_script_help = EditorSettings::get_singleton()->get("text_editor/group_help_pages");
+
+ Vector<_ScriptEditorItemData> sedata;
+
for(int i=0;i<tab_container->get_child_count();i++) {
+
ScriptTextEditor *ste = tab_container->get_child(i)->cast_to<ScriptTextEditor>();
- if (!ste)
- continue;
+ if (ste) {
- String script = ste->get_name();
- Ref<Texture> icon = ste->get_icon();
- String path = ste->get_edited_script()->get_path();
- script_list->add_item(script,icon);
+ String name = ste->get_name();
+ Ref<Texture> icon = ste->get_icon();
+ String tooltip = ste->get_edited_script()->get_path();
- int index = script_list->get_item_count()-1;
+ _ScriptEditorItemData sd;
+ sd.icon=icon;
+ sd.name=name;
+ sd.tooltip=tooltip;
+ sd.index=i;
+ sd.used=used.has(ste->get_edited_script());
+ sd.category=0;
+
+ sedata.push_back(sd);
+ }
- script_list->set_item_tooltip(index,path);
- script_list->set_item_metadata(index,i);
- if (used.has(ste->get_edited_script())) {
+ EditorHelp *eh = tab_container->get_child(i)->cast_to<EditorHelp>();
+ if (eh) {
+
+ String name = eh->get_class_name();
+ Ref<Texture> icon = get_icon("Help","EditorIcons");
+ String tooltip = name+" Class Reference";
+
+ _ScriptEditorItemData sd;
+ sd.icon=icon;
+ sd.name=name;
+ sd.tooltip=tooltip;
+ sd.index=i;
+ sd.used=false;
+ sd.category=split_script_help?1:0;
+ sedata.push_back(sd);
+
+ }
+
+ }
+
+ sedata.sort();
+
+ for(int i=0;i<sedata.size();i++) {
+
+ script_list->add_item(sedata[i].name,sedata[i].icon);
+ int index = script_list->get_item_count()-1;
+ script_list->set_item_tooltip(index,sedata[i].tooltip);
+ script_list->set_item_metadata(index,sedata[i].index);
+ if (sedata[i].used) {
script_list->set_item_custom_bg_color(index,Color(88/255.0,88/255.0,60/255.0));
}
- if (tab_container->get_current_tab()==index) {
+ if (tab_container->get_current_tab()==sedata[i].index) {
script_list->select(index);
+ script_name_label->set_text(sedata[i].name);
+ script_icon->set_texture(sedata[i].icon);
+
}
}
- script_list->sort_items_by_text();
+ _update_script_colors();
+
+
+
}
@@ -1447,6 +1875,8 @@ void ScriptEditor::edit(const Ref<Script>& p_script) {
// see if already has it
+ bool open_dominant = EditorSettings::get_singleton()->get("text_editor/open_dominant_script_on_scene_change");
+
if (p_script->get_path().is_resource_file() && bool(EditorSettings::get_singleton()->get("external_editor/use_external_editor"))) {
String path = EditorSettings::get_singleton()->get("external_editor/exec_path");
@@ -1475,12 +1905,13 @@ void ScriptEditor::edit(const Ref<Script>& p_script) {
if (ste->get_edited_script()==p_script) {
- if (!EditorNode::get_singleton()->is_changing_scene()) {
+ if (open_dominant || !EditorNode::get_singleton()->is_changing_scene()) {
if (tab_container->get_current_tab()!=i) {
- tab_container->set_current_tab(i);
+ _go_to_tab(i);
script_list->select( script_list->find_metadata(i) );
}
- ste->get_text_edit()->grab_focus();
+ if (is_visible())
+ ste->get_text_edit()->grab_focus();
}
return;
}
@@ -1491,8 +1922,10 @@ void ScriptEditor::edit(const Ref<Script>& p_script) {
ScriptTextEditor *ste = memnew( ScriptTextEditor );
ste->set_edited_script(p_script);
ste->get_text_edit()->set_tooltip_request_func(this,"_get_debug_tooltip",ste);
+ ste->get_text_edit()->set_auto_brace_completion(EditorSettings::get_singleton()->get("text_editor/auto_brace_complete"));
tab_container->add_child(ste);
- tab_container->set_current_tab(tab_container->get_tab_count()-1);
+ _go_to_tab(tab_container->get_tab_count()-1);
+
@@ -1591,7 +2024,7 @@ void ScriptEditor::_add_callback(Object *p_obj, const String& p_function, const
ste->get_text_edit()->insert_text_at_cursor("\n\n"+func);
}
- tab_container->set_current_tab(i);
+ _go_to_tab(i);
ste->get_text_edit()->cursor_set_line(pos);
ste->get_text_edit()->cursor_set_column(1);
@@ -1614,6 +2047,15 @@ void ScriptEditor::_editor_settings_changed() {
autosave_timer->stop();
}
+ for(int i=0;i<tab_container->get_child_count();i++) {
+
+ ScriptTextEditor *ste = tab_container->get_child(i)->cast_to<ScriptTextEditor>();
+ if (!ste)
+ continue;
+
+ ste->get_text_edit()->set_auto_brace_completion(EditorSettings::get_singleton()->get("text_editor/auto_brace_complete"));
+ }
+
}
void ScriptEditor::_autosave_scripts() {
@@ -1642,10 +2084,13 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) {
return;
}
- if (!p_layout->has_section_key("ScriptEditor","open_scripts"))
+ if (!p_layout->has_section_key("ScriptEditor","open_scripts") && !p_layout->has_section_key("ScriptEditor","open_help"))
return;
Array scripts = p_layout->get_value("ScriptEditor","open_scripts");
+ Array helps;
+ if (p_layout->has_section_key("ScriptEditor","open_help"))
+ helps=p_layout->get_value("ScriptEditor","open_help");
restoring_layout=true;
@@ -1658,6 +2103,18 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) {
}
}
+
+ for(int i=0;i<helps.size();i++) {
+
+ String path = helps[i];
+ _help_class_open(path);
+ }
+
+ for(int i=0;i<tab_container->get_child_count();i++) {
+ tab_container->get_child(i)->set_meta("__editor_pass",Variant());
+ }
+
+
if (p_layout->has_section_key("ScriptEditor","split_offset")) {
script_split->set_split_offset(p_layout->get_value("ScriptEditor","split_offset"));
}
@@ -1670,30 +2127,193 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) {
void ScriptEditor::get_window_layout(Ref<ConfigFile> p_layout) {
Array scripts;
+ Array helps;
for(int i=0;i<tab_container->get_child_count();i++) {
ScriptTextEditor *ste = tab_container->get_child(i)->cast_to<ScriptTextEditor>();
- if (!ste)
- continue;
+ if (ste) {
- String path = ste->get_edited_script()->get_path();
- if (!path.is_resource_file())
- continue;
+ String path = ste->get_edited_script()->get_path();
+ if (!path.is_resource_file())
+ continue;
+
+ scripts.push_back(path);
+ }
+
+ EditorHelp *eh = tab_container->get_child(i)->cast_to<EditorHelp>();
+
+ if (eh) {
+
+ helps.push_back(eh->get_class_name());
+ }
- scripts.push_back(path);
}
p_layout->set_value("ScriptEditor","open_scripts",scripts);
+ p_layout->set_value("ScriptEditor","open_help",helps);
p_layout->set_value("ScriptEditor","split_offset",script_split->get_split_offset());
}
+void ScriptEditor::_help_class_open(const String& p_class) {
+
+
+ for(int i=0;i<tab_container->get_child_count();i++) {
+
+ EditorHelp *eh = tab_container->get_child(i)->cast_to<EditorHelp>();
+
+ if (eh && eh->get_class_name()==p_class) {
+
+ _go_to_tab(i);
+ _update_script_names();
+ return;
+ }
+ }
+
+ EditorHelp * eh = memnew( EditorHelp );
+
+
+ eh->set_name(p_class);
+ tab_container->add_child(eh);
+ _go_to_tab(tab_container->get_tab_count()-1);
+ eh->go_to_class(p_class,0);
+ eh->connect("go_to_help",this,"_help_class_goto");
+ _update_script_names();
+
+}
+
+void ScriptEditor::_help_class_goto(const String& p_desc) {
+
+
+ String cname=p_desc.get_slice(":",1);
+
+ for(int i=0;i<tab_container->get_child_count();i++) {
+
+ EditorHelp *eh = tab_container->get_child(i)->cast_to<EditorHelp>();
+
+ if (eh && eh->get_class_name()==cname) {
+
+ _go_to_tab(i);
+ eh->go_to_help(p_desc);
+ _update_script_names();
+ return;
+ }
+ }
+
+ EditorHelp * eh = memnew( EditorHelp );
+
+ eh->set_name(cname);
+ tab_container->add_child(eh);
+ _go_to_tab(tab_container->get_tab_count()-1);
+ eh->go_to_help(p_desc);
+ eh->connect("go_to_help",this,"_help_class_goto");
+ _update_script_names();
+
+}
+
+void ScriptEditor::_update_history_pos(int p_new_pos) {
+
+ Node *n = tab_container->get_current_tab_control();
+
+ if (n->cast_to<ScriptTextEditor>()) {
+
+ history[history_pos].scroll_pos=n->cast_to<ScriptTextEditor>()->get_text_edit()->get_v_scroll();
+ history[history_pos].cursor_column=n->cast_to<ScriptTextEditor>()->get_text_edit()->cursor_get_column();
+ history[history_pos].cursor_row=n->cast_to<ScriptTextEditor>()->get_text_edit()->cursor_get_line();
+ }
+ if (n->cast_to<EditorHelp>()) {
+
+ history[history_pos].scroll_pos=n->cast_to<EditorHelp>()->get_scroll();
+ }
+
+ history_pos=p_new_pos;
+ tab_container->set_current_tab(history[history_pos].control->get_index());
+
+ n = history[history_pos].control;
+
+ if (n->cast_to<ScriptTextEditor>()) {
+
+ n->cast_to<ScriptTextEditor>()->get_text_edit()->set_v_scroll(history[history_pos].scroll_pos);
+ n->cast_to<ScriptTextEditor>()->get_text_edit()->cursor_set_column( history[history_pos].cursor_column );
+ n->cast_to<ScriptTextEditor>()->get_text_edit()->cursor_set_line( history[history_pos].cursor_row );
+ n->cast_to<ScriptTextEditor>()->get_text_edit()->grab_focus();
+ }
+
+ if (n->cast_to<EditorHelp>()) {
+
+ n->cast_to<EditorHelp>()->set_scroll(history[history_pos].scroll_pos);
+ n->cast_to<EditorHelp>()->set_focused();
+ }
+
+ n->set_meta("__editor_pass",++edit_pass);
+ _update_script_names();
+ _update_history_arrows();
+
+}
+
+void ScriptEditor::_history_forward() {
+
+ if (history_pos<history.size()-1) {
+ _update_history_pos(history_pos+1);
+ }
+}
+
+void ScriptEditor::_history_back(){
+
+ if (history_pos>0) {
+ _update_history_pos(history_pos-1);
+ }
+
+}
+void ScriptEditor::set_scene_root_script( Ref<Script> p_script ) {
+
+ bool open_dominant = EditorSettings::get_singleton()->get("text_editor/open_dominant_script_on_scene_change");
+
+ if (bool(EditorSettings::get_singleton()->get("external_editor/use_external_editor")))
+ return;
+
+ if (open_dominant && p_script.is_valid()) {
+ edit(p_script);
+ }
+}
+
+void ScriptEditor::_bind_methods() {
+
+ ObjectTypeDB::bind_method("_tab_changed",&ScriptEditor::_tab_changed);
+ ObjectTypeDB::bind_method("_menu_option",&ScriptEditor::_menu_option);
+ ObjectTypeDB::bind_method("_close_current_tab",&ScriptEditor::_close_current_tab);
+ ObjectTypeDB::bind_method("_editor_play",&ScriptEditor::_editor_play);
+ ObjectTypeDB::bind_method("_editor_pause",&ScriptEditor::_editor_pause);
+ ObjectTypeDB::bind_method("_editor_stop",&ScriptEditor::_editor_stop);
+ ObjectTypeDB::bind_method("_add_callback",&ScriptEditor::_add_callback);
+ ObjectTypeDB::bind_method("_reload_scripts",&ScriptEditor::_reload_scripts);
+ ObjectTypeDB::bind_method("_resave_scripts",&ScriptEditor::_resave_scripts);
+ ObjectTypeDB::bind_method("_res_saved_callback",&ScriptEditor::_res_saved_callback);
+ ObjectTypeDB::bind_method("_goto_script_line",&ScriptEditor::_goto_script_line);
+ ObjectTypeDB::bind_method("_goto_script_line2",&ScriptEditor::_goto_script_line2);
+ ObjectTypeDB::bind_method("_breaked",&ScriptEditor::_breaked);
+ ObjectTypeDB::bind_method("_show_debugger",&ScriptEditor::_show_debugger);
+ ObjectTypeDB::bind_method("_get_debug_tooltip",&ScriptEditor::_get_debug_tooltip);
+ ObjectTypeDB::bind_method("_autosave_scripts",&ScriptEditor::_autosave_scripts);
+ ObjectTypeDB::bind_method("_editor_settings_changed",&ScriptEditor::_editor_settings_changed);
+ ObjectTypeDB::bind_method("_update_script_names",&ScriptEditor::_update_script_names);
+ ObjectTypeDB::bind_method("_tree_changed",&ScriptEditor::_tree_changed);
+ ObjectTypeDB::bind_method("_script_selected",&ScriptEditor::_script_selected);
+ ObjectTypeDB::bind_method("_script_created",&ScriptEditor::_script_created);
+ ObjectTypeDB::bind_method("_script_split_dragged",&ScriptEditor::_script_split_dragged);
+ ObjectTypeDB::bind_method("_help_class_open",&ScriptEditor::_help_class_open);
+ ObjectTypeDB::bind_method("_help_class_goto",&ScriptEditor::_help_class_goto);
+ ObjectTypeDB::bind_method("_request_help",&ScriptEditor::_help_class_open);
+ ObjectTypeDB::bind_method("_history_forward",&ScriptEditor::_history_forward);
+ ObjectTypeDB::bind_method("_history_back",&ScriptEditor::_history_back);
+}
ScriptEditor::ScriptEditor(EditorNode *p_editor) {
+ completion_cache = memnew( EditorScriptCodeCompletionCache );
restoring_layout=false;
waiting_update_names=false;
editor=p_editor;
@@ -1701,17 +2321,15 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
menu_hb = memnew( HBoxContainer );
add_child(menu_hb);
- v_split = memnew( VSplitContainer );
- add_child(v_split);
- v_split->set_v_size_flags(SIZE_EXPAND_FILL);
script_split = memnew( HSplitContainer );
- v_split->add_child(script_split);
+ add_child(script_split);
script_split->set_v_size_flags(SIZE_EXPAND_FILL);
script_list = memnew( ItemList );
script_split->add_child(script_list);
- script_list->set_custom_minimum_size(Size2(140,0));
+ script_list->set_custom_minimum_size(Size2(0,0));
+ script_split->set_split_offset(70);
tab_container = memnew( TabContainer );
tab_container->set_tabs_visible(false);
@@ -1723,12 +2341,16 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
file_menu = memnew( MenuButton );
menu_hb->add_child(file_menu);
file_menu->set_text("File");
+ file_menu->get_popup()->add_item("New",FILE_NEW);
file_menu->get_popup()->add_item("Open",FILE_OPEN);
file_menu->get_popup()->add_separator();
file_menu->get_popup()->add_item("Save",FILE_SAVE,KEY_MASK_ALT|KEY_MASK_CMD|KEY_S);
file_menu->get_popup()->add_item("Save As..",FILE_SAVE_AS);
file_menu->get_popup()->add_item("Save All",FILE_SAVE_ALL,KEY_MASK_CMD|KEY_MASK_SHIFT|KEY_S);
file_menu->get_popup()->add_separator();
+ file_menu->get_popup()->add_item("History Prev",WINDOW_PREV,KEY_MASK_CTRL|KEY_MASK_ALT|KEY_LEFT);
+ file_menu->get_popup()->add_item("History Next",WINDOW_NEXT,KEY_MASK_CTRL|KEY_MASK_ALT|KEY_RIGHT);
+ file_menu->get_popup()->add_separator();
file_menu->get_popup()->add_item("Close",FILE_CLOSE,KEY_MASK_CMD|KEY_W);
file_menu->get_popup()->connect("item_pressed", this,"_menu_option");
@@ -1764,13 +2386,22 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
menu_hb->add_child(search_menu);
search_menu->set_text("Search");
search_menu->get_popup()->add_item("Find..",SEARCH_FIND,KEY_MASK_CMD|KEY_F);
- search_menu->get_popup()->add_item("Find Next",SEARCH_FIND_NEXT,KEY_MASK_CMD|KEY_G);
+ search_menu->get_popup()->add_item("Find Next",SEARCH_FIND_NEXT,KEY_F3);
search_menu->get_popup()->add_item("Replace..",SEARCH_REPLACE,KEY_MASK_CMD|KEY_R);
search_menu->get_popup()->add_separator();
search_menu->get_popup()->add_item("Goto Function..",SEARCH_LOCATE_FUNCTION,KEY_MASK_SHIFT|KEY_MASK_CMD|KEY_F);
search_menu->get_popup()->add_item("Goto Line..",SEARCH_GOTO_LINE,KEY_MASK_CMD|KEY_L);
search_menu->get_popup()->connect("item_pressed", this,"_menu_option");
+ script_search_menu = memnew( MenuButton );
+ menu_hb->add_child(script_search_menu);
+ script_search_menu->set_text("Search");
+ script_search_menu->get_popup()->add_item("Find..",SEARCH_FIND,KEY_MASK_CMD|KEY_F);
+ script_search_menu->get_popup()->add_item("Find Next",SEARCH_FIND_NEXT,KEY_F3);
+ script_search_menu->get_popup()->connect("item_pressed", this,"_menu_option");
+ script_search_menu->hide();
+
+
debug_menu = memnew( MenuButton );
menu_hb->add_child(debug_menu);
debug_menu->set_text("Debug");
@@ -1782,7 +2413,8 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
debug_menu->get_popup()->add_item("Break",DEBUG_BREAK);
debug_menu->get_popup()->add_item("Continue",DEBUG_CONTINUE);
debug_menu->get_popup()->add_separator();
- debug_menu->get_popup()->add_check_item("Show Debugger",DEBUG_SHOW);
+ //debug_menu->get_popup()->add_check_item("Show Debugger",DEBUG_SHOW);
+ debug_menu->get_popup()->add_check_item("Keep Debugger Open",DEBUG_SHOW_KEEP_OPEN);
debug_menu->get_popup()->connect("item_pressed", this,"_menu_option");
debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_NEXT), true);
@@ -1810,6 +2442,53 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
help_menu->get_popup()->add_item("Contextual", HELP_CONTEXTUAL, KEY_MASK_SHIFT|KEY_F1);
help_menu->get_popup()->connect("item_pressed", this,"_menu_option");
+ menu_hb->add_spacer();
+
+
+ script_icon = memnew( TextureFrame );
+ menu_hb->add_child(script_icon);
+ script_name_label = memnew( Label );
+ menu_hb->add_child(script_name_label);
+
+ script_icon->hide();
+ script_name_label->hide();
+
+ menu_hb->add_spacer();
+
+ site_search = memnew( ToolButton );
+ site_search->set_text("Tutorials");
+ site_search->connect("pressed",this,"_menu_option",varray(SEARCH_WEBSITE));
+ menu_hb->add_child(site_search);
+ site_search->set_tooltip("Open http://www.godotengine.org at tutorials section.");
+
+ class_search = memnew( ToolButton );
+ class_search->set_text("Classes");
+ class_search->connect("pressed",this,"_menu_option",varray(SEARCH_CLASSES));
+ menu_hb->add_child(class_search);
+ class_search->set_tooltip("Search the class hierarchy.");
+
+ help_search = memnew( ToolButton );
+ help_search->set_text("Search Help");
+ help_search->connect("pressed",this,"_menu_option",varray(SEARCH_HELP));
+ menu_hb->add_child(help_search);
+ help_search->set_tooltip("Search the reference documentation.");
+
+ menu_hb->add_child( memnew( VSeparator) );
+
+ script_back = memnew( ToolButton );
+ script_back->connect("pressed",this,"_history_back");
+ menu_hb->add_child(script_back);
+ script_back->set_disabled(true);
+ help_search->set_tooltip("Go to previous edited document.");
+
+ script_forward = memnew( ToolButton );
+ script_forward->connect("pressed",this,"_history_forward");
+ menu_hb->add_child(script_forward);
+ script_forward->set_disabled(true);
+ help_search->set_tooltip("Go to next edited document.");
+
+
+
tab_container->connect("tab_changed", this,"_tab_changed");
find_replace_dialog = memnew(FindReplaceDialog);
@@ -1819,6 +2498,10 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
add_child(erase_tab_confirm);
erase_tab_confirm->connect("confirmed", this,"_close_current_tab");
+ script_create_dialog = memnew(ScriptCreateDialog);
+ script_create_dialog->set_title("Create Script");
+ add_child(script_create_dialog);
+ script_create_dialog->connect("script_created", this, "_script_created");
goto_line_dialog = memnew(GotoLineDialog);
add_child(goto_line_dialog);
@@ -1859,7 +2542,11 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
quick_open->connect("goto_line",this,"_goto_script_line2");
- v_split->add_child(debugger);
+
+ Button *db = EditorNode::get_singleton()->add_bottom_panel_item("Debugger",debugger);
+ debugger->set_tool_button(db);
+
+
debugger->connect("breaked",this,"_breaked");
autosave_timer = memnew( Timer );
@@ -1868,11 +2555,28 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
grab_focus_block=false;
+ help_search_dialog = memnew( EditorHelpSearch );
+ add_child(help_search_dialog);
+ help_search_dialog->connect("go_to_help",this,"_help_class_goto");
+
+
+ help_index = memnew( EditorHelpIndex );
+ add_child(help_index);
+ help_index->connect("open_class",this,"_help_class_open");
+
+ history_pos=-1;
// debugger_gui->hide();
+ edit_pass=0;
+
}
+ScriptEditor::~ScriptEditor() {
+
+ memdelete(completion_cache);
+}
+
void ScriptEditorPlugin::edit(Object *p_object) {
if (!p_object->cast_to<Script>())
@@ -1956,6 +2660,11 @@ void ScriptEditorPlugin::get_breakpoints(List<String> *p_breakpoints) {
return script_editor->get_breakpoints(p_breakpoints);
}
+void ScriptEditorPlugin::edited_scene_changed() {
+
+ script_editor->edited_scene_changed();
+}
+
ScriptEditorPlugin::ScriptEditorPlugin(EditorNode *p_node) {
editor=p_node;
@@ -1965,9 +2674,15 @@ ScriptEditorPlugin::ScriptEditorPlugin(EditorNode *p_node) {
script_editor->hide();
- EDITOR_DEF("text_editor/auto_reload_changed_scripts",false);
+ EDITOR_DEF("text_editor/auto_reload_scripts_on_external_change",true);
+ EDITOR_DEF("text_editor/open_dominant_script_on_scene_change",true);
EDITOR_DEF("external_editor/use_external_editor",false);
EDITOR_DEF("external_editor/exec_path","");
+ EDITOR_DEF("text_editor/script_temperature_enabled",true);
+ EDITOR_DEF("text_editor/script_temperature_history_size",15);
+ EDITOR_DEF("text_editor/script_temperature_hot_color",Color(1,0,0,0.3));
+ EDITOR_DEF("text_editor/script_temperature_cold_color",Color(0,0,1,0.3));
+ EDITOR_DEF("text_editor/group_help_pages",false);
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,"external_editor/exec_path",PROPERTY_HINT_GLOBAL_FILE));
EDITOR_DEF("external_editor/exec_flags","");
diff --git a/tools/editor/plugins/script_editor_plugin.h b/tools/editor/plugins/script_editor_plugin.h
index 635db40c2f..c52da41a43 100644
--- a/tools/editor/plugins/script_editor_plugin.h
+++ b/tools/editor/plugins/script_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,15 +30,18 @@
#define SCRIPT_EDITOR_PLUGIN_H
#include "tools/editor/editor_plugin.h"
+#include "tools/editor/script_create_dialog.h"
#include "scene/gui/tab_container.h"
#include "scene/gui/text_edit.h"
#include "scene/gui/menu_button.h"
+#include "scene/gui/tool_button.h"
#include "scene/gui/tree.h"
#include "scene/main/timer.h"
#include "script_language.h"
#include "tools/editor/code_editor.h"
#include "scene/gui/split_container.h"
#include "scene/gui/item_list.h"
+#include "tools/editor/editor_help.h"
class ScriptEditorQuickOpen : public ConfirmationDialog {
@@ -100,11 +103,13 @@ public:
void reload_text();
String get_name() ;
Ref<Texture> get_icon() ;
-
+ bool is_unsaved();
ScriptTextEditor();
};
+class EditorScriptCodeCompletionCache;
+
class ScriptEditor : public VBoxContainer {
OBJ_TYPE(ScriptEditor, VBoxContainer );
@@ -112,7 +117,7 @@ class ScriptEditor : public VBoxContainer {
EditorNode *editor;
enum {
-
+ FILE_NEW,
FILE_OPEN,
FILE_SAVE,
FILE_SAVE_AS,
@@ -137,15 +142,21 @@ class ScriptEditor : public VBoxContainer {
SEARCH_REPLACE,
SEARCH_LOCATE_FUNCTION,
SEARCH_GOTO_LINE,
+ SEARCH_HELP,
+ SEARCH_CLASSES,
+ SEARCH_WEBSITE,
DEBUG_TOGGLE_BREAKPOINT,
DEBUG_NEXT,
DEBUG_STEP,
DEBUG_BREAK,
DEBUG_CONTINUE,
DEBUG_SHOW,
- HELP_CONTEXTUAL,
+ DEBUG_SHOW_KEEP_OPEN,
+ HELP_CONTEXTUAL,
WINDOW_MOVE_LEFT,
WINDOW_MOVE_RIGHT,
+ WINDOW_NEXT,
+ WINDOW_PREV,
WINDOW_SELECT_BASE=100
};
@@ -153,18 +164,47 @@ class ScriptEditor : public VBoxContainer {
MenuButton *file_menu;
MenuButton *edit_menu;
MenuButton *search_menu;
+ MenuButton *script_search_menu;
MenuButton *debug_menu;
MenuButton *help_menu;
Timer *autosave_timer;
uint64_t idle;
+ Button *help_search;
+ Button *site_search;
+ Button *class_search;
+ EditorHelpSearch *help_search_dialog;
+
ItemList *script_list;
HSplitContainer *script_split;
TabContainer *tab_container;
FindReplaceDialog *find_replace_dialog;
GotoLineDialog *goto_line_dialog;
ConfirmationDialog *erase_tab_confirm;
+ ScriptCreateDialog *script_create_dialog;
ScriptEditorDebugger* debugger;
+ ToolButton *scripts_visible;
+
+ TextureFrame *script_icon;
+ Label *script_name_label;
+
+ ToolButton *script_back;
+ ToolButton *script_forward;
+
+
+ struct ScriptHistory {
+
+ Control *control;
+ int scroll_pos;
+ int cursor_column;
+ int cursor_row;
+ };
+
+ Vector<ScriptHistory> history;
+ int history_pos;
+
+
+ EditorHelpIndex *help_index;
void _tab_changed(int p_which);
void _menu_option(int p_optin);
@@ -172,8 +212,6 @@ class ScriptEditor : public VBoxContainer {
Tree *disk_changed_list;
ConfirmationDialog *disk_changed;
- VSplitContainer *v_split;
-
bool restoring_layout;
String _get_debug_tooltip(const String&p_text,Node *_ste);
@@ -189,11 +227,14 @@ class ScriptEditor : public VBoxContainer {
ScriptEditorQuickOpen *quick_open;
+ EditorScriptCodeCompletionCache *completion_cache;
void _editor_play();
void _editor_pause();
void _editor_stop();
+ int edit_pass;
+
void _add_callback(Object *p_obj, const String& p_function, const StringArray& p_args);
void _res_saved_callback(const Ref<Resource>& p_res);
@@ -202,6 +243,7 @@ class ScriptEditor : public VBoxContainer {
void _breaked(bool p_breaked,bool p_can_debug);
void _show_debugger(bool p_show);
void _update_window_menu();
+ void _script_created(Ref<Script> p_script);
void _editor_settings_changed();
void _autosave_scripts();
@@ -216,8 +258,21 @@ class ScriptEditor : public VBoxContainer {
void _script_split_dragged(float);
+
+ void _history_forward();
+ void _history_back();
+
bool waiting_update_names;
+ void _help_class_open(const String& p_class);
+ void _help_class_goto(const String& p_desc);
+ void _update_history_arrows();
+ void _go_to_tab(int p_idx);
+ void _update_history_pos(int p_new_pos);
+ void _update_script_colors();
+ void _update_modified_scripts_for_external_editor();
+
+
static ScriptEditor *script_editor;
protected:
void _notification(int p_what);
@@ -245,7 +300,14 @@ public:
void set_window_layout(Ref<ConfigFile> p_layout);
void get_window_layout(Ref<ConfigFile> p_layout);
+ void set_scene_root_script( Ref<Script> p_script );
+
+ virtual void edited_scene_changed();
+
+ ScriptEditorDebugger *get_debugger() { return debugger; }
+
ScriptEditor(EditorNode *p_editor);
+ ~ScriptEditor();
};
class ScriptEditorPlugin : public EditorPlugin {
@@ -278,6 +340,7 @@ public:
virtual void get_breakpoints(List<String> *p_breakpoints);
+ virtual void edited_scene_changed();
ScriptEditorPlugin(EditorNode *p_node);
~ScriptEditorPlugin();
diff --git a/tools/editor/plugins/shader_editor_plugin.cpp b/tools/editor/plugins/shader_editor_plugin.cpp
index a182d57742..65b5365b50 100644
--- a/tools/editor/plugins/shader_editor_plugin.cpp
+++ b/tools/editor/plugins/shader_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -172,11 +172,8 @@ ShaderTextEditor::ShaderTextEditor() {
void ShaderEditor::_menu_option(int p_option) {
- int selected = tab_container->get_current_tab();
- if (selected<0 || selected>=tab_container->get_child_count())
- return;
- ShaderTextEditor *current = tab_container->get_child(selected)->cast_to<ShaderTextEditor>();
+ ShaderTextEditor *current = tab_container->get_current_tab_control()->cast_to<ShaderTextEditor>();
if (!current)
return;
@@ -235,6 +232,11 @@ void ShaderEditor::_menu_option(int p_option) {
void ShaderEditor::_tab_changed(int p_which) {
+ ShaderTextEditor *shader_editor = tab_container->get_tab_control(p_which)->cast_to<ShaderTextEditor>();
+
+ if (shader_editor)
+ shader_editor->get_text_edit()->grab_focus();
+
ensure_select_current();
}
diff --git a/tools/editor/plugins/shader_editor_plugin.h b/tools/editor/plugins/shader_editor_plugin.h
index 4ead2ba94e..26d20b80b4 100644
--- a/tools/editor/plugins/shader_editor_plugin.h
+++ b/tools/editor/plugins/shader_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/plugins/shader_graph_editor_plugin.cpp b/tools/editor/plugins/shader_graph_editor_plugin.cpp
index 03fcbffa24..36a8c79b84 100644
--- a/tools/editor/plugins/shader_graph_editor_plugin.cpp
+++ b/tools/editor/plugins/shader_graph_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,6 +29,7 @@
#include "shader_graph_editor_plugin.h"
+#include "scene/gui/check_box.h"
#include "scene/gui/menu_button.h"
#include "scene/gui/panel.h"
#include "spatial_editor_plugin.h"
@@ -454,43 +455,43 @@ void GraphCurveMapEdit::_plot_curve(const Vector2& p_a,const Vector2& p_b,const
d3 = d * d * d;
/* construct a temporary matrix for determining the forward differencing deltas */
- tmp2[0][0] = 0; tmp2[0][1] = 0; tmp2[0][2] = 0; tmp2[0][3] = 1;
- tmp2[1][0] = d3; tmp2[1][1] = d2; tmp2[1][2] = d; tmp2[1][3] = 0;
- tmp2[2][0] = 6*d3; tmp2[2][1] = 2*d2; tmp2[2][2] = 0; tmp2[2][3] = 0;
- tmp2[3][0] = 6*d3; tmp2[3][1] = 0; tmp2[3][2] = 0; tmp2[3][3] = 0;
+ tmp2[0][0] = 0; tmp2[0][1] = 0; tmp2[0][2] = 0; tmp2[0][3] = 1;
+ tmp2[1][0] = d3; tmp2[1][1] = d2; tmp2[1][2] = d; tmp2[1][3] = 0;
+ tmp2[2][0] = 6*d3; tmp2[2][1] = 2*d2; tmp2[2][2] = 0; tmp2[2][3] = 0;
+ tmp2[3][0] = 6*d3; tmp2[3][1] = 0; tmp2[3][2] = 0; tmp2[3][3] = 0;
/* compose the basis and geometry matrices */
static const float CR_basis[4][4] =
{
- { -0.5, 1.5, -1.5, 0.5 },
- { 1.0, -2.5, 2.0, -0.5 },
- { -0.5, 0.0, 0.5, 0.0 },
- { 0.0, 1.0, 0.0, 0.0 },
+ { -0.5, 1.5, -1.5, 0.5 },
+ { 1.0, -2.5, 2.0, -0.5 },
+ { -0.5, 0.0, 0.5, 0.0 },
+ { 0.0, 1.0, 0.0, 0.0 },
};
for (i = 0; i < 4; i++)
- {
- for (j = 0; j < 4; j++)
+ {
+ for (j = 0; j < 4; j++)
{
- tmp1[i][j] = (CR_basis[i][0] * geometry[0][j] +
- CR_basis[i][1] * geometry[1][j] +
- CR_basis[i][2] * geometry[2][j] +
- CR_basis[i][3] * geometry[3][j]);
+ tmp1[i][j] = (CR_basis[i][0] * geometry[0][j] +
+ CR_basis[i][1] * geometry[1][j] +
+ CR_basis[i][2] * geometry[2][j] +
+ CR_basis[i][3] * geometry[3][j]);
}
- }
+ }
/* compose the above results to get the deltas matrix */
for (i = 0; i < 4; i++)
- {
- for (j = 0; j < 4; j++)
+ {
+ for (j = 0; j < 4; j++)
{
- deltas[i][j] = (tmp2[i][0] * tmp1[0][j] +
- tmp2[i][1] * tmp1[1][j] +
- tmp2[i][2] * tmp1[2][j] +
- tmp2[i][3] * tmp1[3][j]);
+ deltas[i][j] = (tmp2[i][0] * tmp1[0][j] +
+ tmp2[i][1] * tmp1[1][j] +
+ tmp2[i][2] * tmp1[2][j] +
+ tmp2[i][3] * tmp1[3][j]);
}
- }
+ }
/* extract the x deltas */
@@ -509,15 +510,15 @@ void GraphCurveMapEdit::_plot_curve(const Vector2& p_a,const Vector2& p_b,const
lastx = CLAMP (x, 0, xmax);
lasty = CLAMP (y, 0, ymax);
-/* if (fix255)
- {
- cd->curve[cd->outline][lastx] = lasty;
- }
- else
- {
- cd->curve_ptr[cd->outline][lastx] = lasty;
- if(gb_debug) printf("bender_plot_curve xmax:%d ymax:%d\n", (int)xmax, (int)ymax);
- }
+ /* if (fix255)
+ {
+ cd->curve[cd->outline][lastx] = lasty;
+ }
+ else
+ {
+ cd->curve_ptr[cd->outline][lastx] = lasty;
+ if(gb_debug) printf("bender_plot_curve xmax:%d ymax:%d\n", (int)xmax, (int)ymax);
+ }
*/
/* loop over the curve */
for (i = 0; i < ntimes; i++)
@@ -590,9 +591,9 @@ void GraphCurveMapEdit::_notification(int p_what){
}
/*if (i==-1 && prev.offset==next.offset) {
- prev=next;
- continue;
- }*/
+ prev=next;
+ continue;
+ }*/
_plot_curve(prev2,prev,next,next2);
@@ -608,10 +609,10 @@ void GraphCurveMapEdit::_notification(int p_what){
draw_rect(Rect2( Vector2(points[i].offset,1.0-points[i].height)*get_size()-Vector2(2,2),Vector2(5,5)),col);
}
-/* if (grabbed!=-1) {
+ /* if (grabbed!=-1) {
- draw_rect(Rect2(total_w+3,0,h,h),points[grabbed].color);
- }
+ draw_rect(Rect2(total_w+3,0,h,h),points[grabbed].color);
+ }
*/
if (has_focus()) {
@@ -840,6 +841,7 @@ void ShaderGraphView::_xform_input_changed(int p_id, Node *p_button){
ped_popup->set_pos(tb->get_global_pos()+Vector2(0,tb->get_size().height));
ped_popup->set_size(tb->get_size());
edited_id=p_id;
+ edited_def=-1;
ped_popup->edit(NULL,"",Variant::TRANSFORM,graph->xform_input_node_get_value(type,p_id),PROPERTY_HINT_NONE,"");
ped_popup->popup();
@@ -850,6 +852,7 @@ void ShaderGraphView::_xform_const_changed(int p_id, Node *p_button){
ped_popup->set_pos(tb->get_global_pos()+Vector2(0,tb->get_size().height));
ped_popup->set_size(tb->get_size());
edited_id=p_id;
+ edited_def=-1;
ped_popup->edit(NULL,"",Variant::TRANSFORM,graph->xform_const_node_get_value(type,p_id),PROPERTY_HINT_NONE,"");
ped_popup->popup();
@@ -879,6 +882,35 @@ void ShaderGraphView::_cube_input_change(int p_id){
void ShaderGraphView::_variant_edited() {
+ if (edited_def != -1) {
+
+ Variant v = ped_popup->get_variant();
+ Variant v2 = graph->default_get_value(type,edited_id,edited_def);
+ if (v2.get_type() == Variant::NIL)
+ switch (v.get_type()) {
+ case Variant::VECTOR3:
+ v2=Vector3();
+ break;
+ case Variant::REAL:
+ v2=0.0;
+ break;
+ case Variant::TRANSFORM:
+ v2=Transform();
+ break;
+ case Variant::COLOR:
+ v2=Color();
+ break;
+ }
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Change default value");
+ ur->add_do_method(graph.ptr(),"default_set_value",type,edited_id,edited_def, v);
+ ur->add_undo_method(graph.ptr(),"default_set_value",type,edited_id,edited_def, v2);
+ ur->add_do_method(this,"_update_graph");
+ ur->add_undo_method(this,"_update_graph");
+ ur->commit_action();
+ return;
+ }
+
if (graph->node_get_type(type,edited_id)==ShaderGraph::NODE_XFORM_CONST) {
UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
@@ -1043,6 +1075,7 @@ void ShaderGraphView::_tex_edited(int p_id,Node* p_button) {
ped_popup->set_pos(tb->get_global_pos()+Vector2(0,tb->get_size().height));
ped_popup->set_size(tb->get_size());
edited_id=p_id;
+ edited_def=-1;
ped_popup->edit(NULL,"",Variant::OBJECT,graph->texture_input_node_get_value(type,p_id),PROPERTY_HINT_RESOURCE_TYPE,"Texture");
}
@@ -1052,6 +1085,7 @@ void ShaderGraphView::_cube_edited(int p_id,Node* p_button) {
ped_popup->set_pos(tb->get_global_pos()+Vector2(0,tb->get_size().height));
ped_popup->set_size(tb->get_size());
edited_id=p_id;
+ edited_def=-1;
ped_popup->edit(NULL,"",Variant::OBJECT,graph->cubemap_input_node_get_value(type,p_id),PROPERTY_HINT_RESOURCE_TYPE,"CubeMap");
}
@@ -1156,14 +1190,24 @@ void ShaderGraphView::_node_removed(int p_id) {
}
+void ShaderGraphView::_begin_node_move()
+{
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Move Shader Graph Node");
+}
+
void ShaderGraphView::_node_moved(const Vector2& p_from, const Vector2& p_to,int p_id) {
ERR_FAIL_COND(!node_map.has(p_id));
UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
- ur->create_action("Move Shader Graph Node");
ur->add_do_method(this,"_move_node",p_id,p_to);
ur->add_undo_method(this,"_move_node",p_id,p_from);
+}
+
+void ShaderGraphView::_end_node_move()
+{
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
ur->commit_action();
}
@@ -1174,860 +1218,1244 @@ void ShaderGraphView::_move_node(int p_id,const Vector2& p_to) {
graph->node_set_pos(type,p_id,p_to);
}
+void ShaderGraphView::_duplicate_nodes_request()
+{
+ Array s_id;
+
+ for(Map<int,GraphNode*>::Element *E=node_map.front();E;E=E->next()) {
+ ShaderGraph::NodeType t=graph->node_get_type(type, E->key());
+ if (t==ShaderGraph::NODE_OUTPUT || t==ShaderGraph::NODE_INPUT)
+ continue;
+ GraphNode *gn = E->get();
+ if (gn && gn->is_selected())
+ s_id.push_back(E->key());
+ }
-void ShaderGraphView::_create_node(int p_id) {
-
-
- GraphNode *gn = memnew( GraphNode );
- gn->set_show_close_button(true);
- Color typecol[4]={
- Color(0.9,0.4,1),
- Color(0.8,1,0.2),
- Color(1,0.2,0.2),
- Color(0,1,1)
- };
-
-
- switch(graph->node_get_type(type,p_id)) {
-
- case ShaderGraph::NODE_INPUT: {
+ if (s_id.size()==0)
+ return;
- gn->set_title("Input");
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Duplicate Graph Node(s)");
+ ur->add_do_method(this,"_duplicate_nodes",s_id);
+ List<int> n_ids = graph->generate_ids(type, s_id.size());
+ for (List<int>::Element *E=n_ids.front();E;E=E->next())
+ ur->add_undo_method(graph.ptr(),"node_remove",type,E->get());
+ ur->add_do_method(this,"_update_graph");
+ ur->add_undo_method(this,"_update_graph");
+ ur->commit_action();
- List<ShaderGraph::SlotInfo> si;
- ShaderGraph::get_input_output_node_slot_info(graph->get_mode(),type,&si);
+}
- int idx=0;
- for (List<ShaderGraph::SlotInfo>::Element *E=si.front();E;E=E->next()) {
- ShaderGraph::SlotInfo& s=E->get();
- if (s.dir==ShaderGraph::SLOT_IN) {
+void ShaderGraphView::_duplicate_nodes(const Array &p_nodes)
+{
+ List<int> n = List<int>();
+ for (int i=0; i<p_nodes.size();i++)
+ n.push_back(p_nodes.get(i));
+ graph->duplicate_nodes(type, n);
+ call_deferred("_update_graph");
+}
- Label *l= memnew( Label );
- l->set_text(s.name);
- l->set_align(Label::ALIGN_RIGHT);
- gn->add_child(l);
- gn->set_slot(idx,false,0,Color(),true,s.type,typecol[s.type]);
- idx++;
- }
- }
+void ShaderGraphView::_delete_nodes_request()
+{
+ List<int> s_id=List<int>();
+
+ for(Map<int,GraphNode*>::Element *E=node_map.front();E;E=E->next()) {
+ ShaderGraph::NodeType t=graph->node_get_type(type, E->key());
+ if (t==ShaderGraph::NODE_OUTPUT)
+ continue;
+ GraphNode *gn = E->get();
+ if (gn && gn->is_selected())
+ s_id.push_back(E->key());
+ }
- } break; // all inputs (case Shader type dependent)
- case ShaderGraph::NODE_SCALAR_CONST: {
- gn->set_title("Scalar");
- SpinBox *sb = memnew( SpinBox );
- sb->set_min(-100000);
- sb->set_max(100000);
- sb->set_step(0.001);
- sb->set_val(graph->scalar_const_node_get_value(type,p_id));
- sb->connect("value_changed",this,"_scalar_const_changed",varray(p_id));
- gn->add_child(sb);
- gn->set_slot(0,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
-
- } break; //scalar constant
- case ShaderGraph::NODE_VEC_CONST: {
-
- gn->set_title("Vector");
- Array v3p(true);
- for(int i=0;i<3;i++) {
- HBoxContainer *hbc = memnew( HBoxContainer );
- Label *l = memnew( Label );
- l->set_text(String::chr('X'+i));
- hbc->add_child(l);
- SpinBox *sb = memnew( SpinBox );
- sb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- sb->set_min(-100000);
- sb->set_max(100000);
- sb->set_step(0.001);
- sb->set_val(graph->vec_const_node_get_value(type,p_id)[i]);
- sb->connect("value_changed",this,"_vec_const_changed",varray(p_id,v3p));
- v3p.push_back(sb);
- hbc->add_child(sb);
- gn->add_child(hbc);
- }
- gn->set_slot(0,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+ if (s_id.size()==0)
+ return;
- } break; //vec3 constant
- case ShaderGraph::NODE_RGB_CONST: {
+ UndoRedo *ur=EditorNode::get_singleton()->get_undo_redo();
+ ur->create_action("Delete Shader Graph Node(s)");
- gn->set_title("Color");
- ColorPickerButton *cpb = memnew( ColorPickerButton );
- cpb->set_color(graph->rgb_const_node_get_value(type,p_id));
- cpb->connect("color_changed",this,"_rgb_const_changed",varray(p_id));
- gn->add_child(cpb);
- Label *l = memnew( Label );
- l->set_text("RGB");
- l->set_align(Label::ALIGN_RIGHT);
- gn->add_child(l);
- l = memnew( Label );
- l->set_text("Alpha");
- l->set_align(Label::ALIGN_RIGHT);
- gn->add_child(l);
-
- gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
- gn->set_slot(2,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
-
- } break; //rgb constant (shows a color picker instead)
- case ShaderGraph::NODE_XFORM_CONST: {
- gn->set_title("XForm");
- ToolButton *edit = memnew( ToolButton );
- edit->set_text("edit..");
- edit->connect("pressed",this,"_xform_const_changed",varray(p_id,edit));
- gn->add_child(edit);
- gn->set_slot(0,false,0,Color(),true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM]);
-
- } break; // 4x4 matrix constant
- case ShaderGraph::NODE_TIME: {
-
- gn->set_title("Time");
- Label *l = memnew( Label );
- l->set_text("(s)");
- l->set_align(Label::ALIGN_RIGHT);
- gn->add_child(l);
- gn->set_slot(0,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+ for (List<int>::Element *N=s_id.front();N;N=N->next()) {
+ ur->add_do_method(graph.ptr(),"node_remove",type,N->get());
+ ur->add_undo_method(graph.ptr(),"node_add",type,graph->node_get_type(type,N->get()),N->get());
+ ur->add_undo_method(graph.ptr(),"node_set_state",type,N->get(),graph->node_get_state(type,N->get()));
+ List<ShaderGraph::Connection> conns;
- } break; // time in seconds
- case ShaderGraph::NODE_SCREEN_TEX: {
+ graph->get_node_connections(type,&conns);
+ for(List<ShaderGraph::Connection>::Element *E=conns.front();E;E=E->next()) {
- gn->set_title("ScreenTex");
- HBoxContainer *hbc = memnew( HBoxContainer );
- hbc->add_constant_override("separation",0);
- hbc->add_child( memnew(Label("UV")));
- hbc->add_spacer();
- hbc->add_child( memnew(Label("RGB")));
- gn->add_child(hbc);
- gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
-
- } break; // screen texture sampler (takes UV) (only usable in fragment case Shader)
- case ShaderGraph::NODE_SCALAR_OP: {
-
- gn->set_title("ScalarOp");
- static const char* op_name[ShaderGraph::SCALAR_MAX_OP]={
- "Add",
- "Sub",
- "Mul",
- "Div",
- "Mod",
- "Pow",
- "Max",
- "Min",
- "Atan2"
- };
-
- OptionButton *ob = memnew( OptionButton );
- for(int i=0;i<ShaderGraph::SCALAR_MAX_OP;i++) {
-
- ob->add_item(op_name[i],i);
+ if (E->get().dst_id==N->get() || E->get().src_id==N->get()) {
+ ur->add_undo_method(graph.ptr(),"connect_node",type,E->get().src_id,E->get().src_slot,E->get().dst_id,E->get().dst_slot);
}
+ }
+ }
+ ur->add_do_method(this,"_update_graph");
+ ur->add_undo_method(this,"_update_graph");
+ ur->commit_action();
- ob->select(graph->scalar_op_node_get_op(type,p_id));
- ob->connect("item_selected",this,"_scalar_op_changed",varray(p_id));
- gn->add_child(ob);
-
- HBoxContainer *hbc = memnew( HBoxContainer );
- hbc->add_constant_override("separation",0);
- hbc->add_child( memnew(Label("a")));
- hbc->add_spacer();
- hbc->add_child( memnew(Label("out")));
- gn->add_child(hbc);
- gn->add_child( memnew(Label("b")));
-
- gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
- gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color());
-
-
- } break; // scalar vs scalar op (mul: { } break; add: { } break; div: { } break; etc)
- case ShaderGraph::NODE_VEC_OP: {
-
- gn->set_title("VecOp");
- static const char* op_name[ShaderGraph::VEC_MAX_OP]={
- "Add",
- "Sub",
- "Mul",
- "Div",
- "Mod",
- "Pow",
- "Max",
- "Min",
- "Cross"
- };
-
- OptionButton *ob = memnew( OptionButton );
- for(int i=0;i<ShaderGraph::VEC_MAX_OP;i++) {
-
- ob->add_item(op_name[i],i);
- }
+}
- ob->select(graph->vec_op_node_get_op(type,p_id));
- ob->connect("item_selected",this,"_vec_op_changed",varray(p_id));
- gn->add_child(ob);
+void ShaderGraphView::_default_changed(int p_id, Node *p_button, int p_param, int v_type, String p_hint)
+{
+ ToolButton *tb = p_button->cast_to<ToolButton>();
+ ped_popup->set_pos(tb->get_global_pos()+Vector2(0,tb->get_size().height));
+ ped_popup->set_size(tb->get_size());
+ edited_id=p_id;
+ edited_def=p_param;
+ Variant::Type vt = (Variant::Type)v_type;
+ Variant v = graph->default_get_value(type,p_id,edited_def);
+ int h=PROPERTY_HINT_NONE;
+ if (v.get_type() == Variant::NIL)
+ switch (vt) {
+ case Variant::VECTOR3:
+ v=Vector3();
+ break;
+ case Variant::REAL:
+ h=PROPERTY_HINT_RANGE;
+ v=0.0;
+ break;
+ case Variant::TRANSFORM:
+ v=Transform();
+ break;
+ case Variant::COLOR:
+ h=PROPERTY_HINT_COLOR_NO_ALPHA;
+ v=Color();
+ break;
+ }
- HBoxContainer *hbc = memnew( HBoxContainer );
- hbc->add_constant_override("separation",0);
- hbc->add_child( memnew(Label("a")));
- hbc->add_spacer();
- hbc->add_child( memnew(Label("out")));
- gn->add_child(hbc);
- gn->add_child( memnew(Label("b")));
+ ped_popup->edit(NULL,"",vt,v,h,p_hint);
- gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
- gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
+ ped_popup->popup();
+}
+ToolButton *ShaderGraphView::make_label(String text, Variant::Type v_type) {
+ ToolButton *l = memnew( ToolButton );
+ l->set_text(text);
+ l->set_text_align(ToolButton::ALIGN_LEFT);
+ l->add_style_override("hover", l->get_stylebox("normal", "ToolButton"));
+ l->add_style_override("pressed", l->get_stylebox("normal", "ToolButton"));
+ l->add_style_override("focus", l->get_stylebox("normal", "ToolButton"));
+ switch (v_type) {
+ case Variant::REAL:
+ l->set_icon(ped_popup->get_icon("Real", "EditorIcons"));
+ break;
+ case Variant::VECTOR3:
+ l->set_icon(ped_popup->get_icon("Vector", "EditorIcons"));
+ break;
+ case Variant::TRANSFORM:
+ l->set_icon(ped_popup->get_icon("Matrix", "EditorIcons"));
+ break;
+ case Variant::COLOR:
+ l->set_icon(ped_popup->get_icon("Color", "EditorIcons"));
+ }
+ return l;
+}
- } break; // vec3 vs vec3 op (mul: { } break;ad: { } break;div: { } break;crossprod: { } break;etc)
- case ShaderGraph::NODE_VEC_SCALAR_OP: {
+ToolButton *ShaderGraphView::make_editor(String text,GraphNode* gn,int p_id,int param,Variant::Type v_type, String p_hint) {
+ ToolButton *edit = memnew( ToolButton );
+ edit->set_text(text);
+ edit->set_text_align(ToolButton::ALIGN_LEFT);
+ edit->set_flat(false);
+ edit->add_style_override("normal", gn->get_stylebox("defaultframe", "GraphNode"));
+ edit->add_style_override("hover", gn->get_stylebox("defaultframe", "GraphNode"));
+ edit->add_style_override("pressed", gn->get_stylebox("defaultframe", "GraphNode"));
+ edit->add_style_override("focus", gn->get_stylebox("defaultfocus", "GraphNode"));
+ edit->connect("pressed",this,"_default_changed",varray(p_id,edit,param,v_type,p_hint));
+
+ switch (v_type) {
+ case Variant::REAL:
+ edit->set_icon(ped_popup->get_icon("Real", "EditorIcons"));
+ break;
+ case Variant::VECTOR3:
+ edit->set_icon(ped_popup->get_icon("Vector", "EditorIcons"));
+ break;
+ case Variant::TRANSFORM:
+ edit->set_icon(ped_popup->get_icon("Matrix", "EditorIcons"));
+ break;
+ case Variant::COLOR:
+ Image icon_color = Image(15,15,false,Image::FORMAT_RGB);
+ Color c = graph->default_get_value(type,p_id,param);
+ for (int x=1;x<14;x++)
+ for (int y=1;y<14;y++)
+ icon_color.put_pixel(x,y,c);
+ Ref<ImageTexture> t;
+ t.instance();
+ t->create_from_image(icon_color);
+ edit->set_icon(t);
+ break;
+ }
+ return edit;
+}
- gn->set_title("VecScalarOp");
- static const char* op_name[ShaderGraph::VEC_SCALAR_MAX_OP]={
- "Mul",
- "Div",
- "Pow",
- };
+void ShaderGraphView::_create_node(int p_id) {
- OptionButton *ob = memnew( OptionButton );
- for(int i=0;i<ShaderGraph::VEC_SCALAR_MAX_OP;i++) {
- ob->add_item(op_name[i],i);
- }
+ GraphNode *gn = memnew( GraphNode );
+ gn->set_show_close_button(true);
+ Color typecol[4]={
+ Color(0.9,0.4,1),
+ Color(0.8,1,0.2),
+ Color(1,0.2,0.2),
+ Color(0,1,1)
+ };
- ob->select(graph->vec_scalar_op_node_get_op(type,p_id));
- ob->connect("item_selected",this,"_vec_scalar_op_changed",varray(p_id));
- gn->add_child(ob);
+ const String hint_spin = "-65536,65535,0.001";
+ const String hint_slider = "0.0,1.0,0.01,slider";
- HBoxContainer *hbc = memnew( HBoxContainer );
- hbc->add_constant_override("separation",0);
- hbc->add_child( memnew(Label("a")));
- hbc->add_spacer();
- hbc->add_child( memnew(Label("out")));
- gn->add_child(hbc);
- gn->add_child( memnew(Label("b")));
- gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
- gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color());
+ switch(graph->node_get_type(type,p_id)) {
+ case ShaderGraph::NODE_INPUT: {
- } break; // vec3 vs scalar op (mul: { } break; add: { } break; div: { } break; etc)
- case ShaderGraph::NODE_RGB_OP: {
+ gn->set_title("Input");
- gn->set_title("RGB Op");
- static const char* op_name[ShaderGraph::RGB_MAX_OP]={
- "Screen",
- "Difference",
- "Darken",
- "Lighten",
- "Overlay",
- "Dodge",
- "Burn",
- "SoftLight",
- "HardLight"
- };
+ List<ShaderGraph::SlotInfo> si;
+ ShaderGraph::get_input_output_node_slot_info(graph->get_mode(),type,&si);
- OptionButton *ob = memnew( OptionButton );
- for(int i=0;i<ShaderGraph::RGB_MAX_OP;i++) {
+ int idx=0;
+ for (List<ShaderGraph::SlotInfo>::Element *E=si.front();E;E=E->next()) {
+ ShaderGraph::SlotInfo& s=E->get();
+ if (s.dir==ShaderGraph::SLOT_IN) {
- ob->add_item(op_name[i],i);
+ Label *l= memnew( Label );
+ l->set_text(s.name);
+ l->set_align(Label::ALIGN_RIGHT);
+ gn->add_child(l);
+ gn->set_slot(idx,false,0,Color(),true,s.type,typecol[s.type]);
+ idx++;
}
+ }
- ob->select(graph->rgb_op_node_get_op(type,p_id));
- ob->connect("item_selected",this,"_rgb_op_changed",varray(p_id));
- gn->add_child(ob);
-
+ } break; // all inputs (case Shader type dependent)
+ case ShaderGraph::NODE_SCALAR_CONST: {
+ gn->set_title("Scalar");
+ SpinBox *sb = memnew( SpinBox );
+ sb->set_min(-100000);
+ sb->set_max(100000);
+ sb->set_step(0.001);
+ sb->set_val(graph->scalar_const_node_get_value(type,p_id));
+ sb->connect("value_changed",this,"_scalar_const_changed",varray(p_id));
+ gn->add_child(sb);
+ gn->set_slot(0,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+
+ } break; //scalar constant
+ case ShaderGraph::NODE_VEC_CONST: {
+
+ gn->set_title("Vector");
+ Array v3p(true);
+ for(int i=0;i<3;i++) {
HBoxContainer *hbc = memnew( HBoxContainer );
- hbc->add_constant_override("separation",0);
- hbc->add_child( memnew(Label("a")));
- hbc->add_spacer();
- hbc->add_child( memnew(Label("out")));
+ Label *l = memnew( Label );
+ l->set_text(String::chr('X'+i));
+ hbc->add_child(l);
+ SpinBox *sb = memnew( SpinBox );
+ sb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ sb->set_min(-100000);
+ sb->set_max(100000);
+ sb->set_step(0.001);
+ sb->set_val(graph->vec_const_node_get_value(type,p_id)[i]);
+ sb->connect("value_changed",this,"_vec_const_changed",varray(p_id,v3p));
+ v3p.push_back(sb);
+ hbc->add_child(sb);
gn->add_child(hbc);
- gn->add_child( memnew(Label("b")));
+ }
+ gn->set_slot(0,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+
+ } break; //vec3 constant
+ case ShaderGraph::NODE_RGB_CONST: {
+
+ gn->set_title("Color");
+ ColorPickerButton *cpb = memnew( ColorPickerButton );
+ cpb->set_color(graph->rgb_const_node_get_value(type,p_id));
+ cpb->connect("color_changed",this,"_rgb_const_changed",varray(p_id));
+ gn->add_child(cpb);
+ Label *l = memnew( Label );
+ l->set_text("RGB");
+ l->set_align(Label::ALIGN_RIGHT);
+ gn->add_child(l);
+ l = memnew( Label );
+ l->set_text("Alpha");
+ l->set_align(Label::ALIGN_RIGHT);
+ gn->add_child(l);
+
+ gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+ gn->set_slot(2,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+
+ } break; //rgb constant (shows a color picker instead)
+ case ShaderGraph::NODE_XFORM_CONST: {
+ gn->set_title("XForm");
+ ToolButton *edit = memnew( ToolButton );
+ edit->set_text("edit..");
+ edit->connect("pressed",this,"_xform_const_changed",varray(p_id,edit));
+ gn->add_child(edit);
+ gn->set_slot(0,false,0,Color(),true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM]);
+
+ } break; // 4x4 matrix constant
+ case ShaderGraph::NODE_TIME: {
+
+ gn->set_title("Time");
+ Label *l = memnew( Label );
+ l->set_text("(s)");
+ l->set_align(Label::ALIGN_RIGHT);
+ gn->add_child(l);
+ gn->set_slot(0,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+
+ } break; // time in seconds
+ case ShaderGraph::NODE_SCREEN_TEX: {
+
+ gn->set_title("ScreenTex");
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ hbc->add_constant_override("separation",0);
+ if (!graph->is_slot_connected(type,p_id,0)) {
+ Vector3 v = graph->default_get_value(type, p_id, 0);
+ hbc->add_child(make_editor("UV: " + v,gn,p_id,0,Variant::VECTOR3));
+ } else {
+ hbc->add_child(make_label("UV",Variant::VECTOR3));
+ }
+ hbc->add_spacer();
+ hbc->add_child( memnew(Label("RGB")));
+ gn->add_child(hbc);
+ gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+
+ } break; // screen texture sampler (takes UV) (only usable in fragment case Shader)
+ case ShaderGraph::NODE_SCALAR_OP: {
+
+ gn->set_title("ScalarOp");
+ static const char* op_name[ShaderGraph::SCALAR_MAX_OP]={
+ "Add",
+ "Sub",
+ "Mul",
+ "Div",
+ "Mod",
+ "Pow",
+ "Max",
+ "Min",
+ "Atan2"
+ };
+
+ OptionButton *ob = memnew( OptionButton );
+ for(int i=0;i<ShaderGraph::SCALAR_MAX_OP;i++) {
+
+ ob->add_item(op_name[i],i);
+ }
- gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
- gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
+ ob->select(graph->scalar_op_node_get_op(type,p_id));
+ ob->connect("item_selected",this,"_scalar_op_changed",varray(p_id));
+ gn->add_child(ob);
+
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ hbc->add_constant_override("separation",0);
+ if (graph->is_slot_connected(type, p_id, 0)) {
+ hbc->add_child(make_label("a",Variant::REAL));
+ } else {
+ float v = graph->default_get_value(type,p_id,0);
+ hbc->add_child(make_editor(String("a: ")+Variant(v),gn,p_id,0,Variant::REAL,hint_spin));
+ }
+ hbc->add_spacer();
+ hbc->add_child( memnew(Label("out")));
+ gn->add_child(hbc);
+ if (graph->is_slot_connected(type, p_id, 1)) {
+ gn->add_child(make_label("b",Variant::REAL));
+ } else {
+ float v = graph->default_get_value(type,p_id,1);
+ gn->add_child(make_editor(String("b: ")+Variant(v),gn,p_id,1,Variant::REAL,hint_spin));
+ }
- } break; // vec3 vs vec3 rgb op (with scalar amount): { } break; like brighten: { } break; darken: { } break; burn: { } break; dodge: { } break; multiply: { } break; etc.
- case ShaderGraph::NODE_XFORM_MULT: {
+ gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+ gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color());
- gn->set_title("XFMult");
- HBoxContainer *hbc = memnew( HBoxContainer );
- hbc->add_child( memnew(Label("a")));
- hbc->add_spacer();
- hbc->add_child( memnew(Label("out")));
- gn->add_child(hbc);
- gn->add_child( memnew(Label("b")));
- gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM],true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM]);
- gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM],false,0,Color());
+ } break; // scalar vs scalar op (mul: { } break; add: { } break; div: { } break; etc)
+ case ShaderGraph::NODE_VEC_OP: {
+ gn->set_title("VecOp");
+ static const char* op_name[ShaderGraph::VEC_MAX_OP]={
+ "Add",
+ "Sub",
+ "Mul",
+ "Div",
+ "Mod",
+ "Pow",
+ "Max",
+ "Min",
+ "Cross"
+ };
- } break; // mat4 x mat4
- case ShaderGraph::NODE_XFORM_VEC_MULT: {
+ OptionButton *ob = memnew( OptionButton );
+ for(int i=0;i<ShaderGraph::VEC_MAX_OP;i++) {
- gn->set_title("XFVecMult");
+ ob->add_item(op_name[i],i);
+ }
- Button *button = memnew( Button("RotOnly"));
- button->set_toggle_mode(true);
- button->set_pressed(graph->xform_vec_mult_node_get_no_translation(type,p_id));
- button->connect("toggled",this,"_xform_inv_rev_changed",varray(p_id));
+ ob->select(graph->vec_op_node_get_op(type,p_id));
+ ob->connect("item_selected",this,"_vec_op_changed",varray(p_id));
+ gn->add_child(ob);
+
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ hbc->add_constant_override("separation",0);
+ if (graph->is_slot_connected(type, p_id, 0)) {
+ hbc->add_child(make_label("a",Variant::VECTOR3));
+ } else {
+ Vector3 v = graph->default_get_value(type,p_id,0);
+ hbc->add_child(make_editor(String("a: ")+v,gn,p_id,0,Variant::VECTOR3));
+ }
+ hbc->add_spacer();
+ hbc->add_child( memnew(Label("out")));
+ gn->add_child(hbc);
+ if (graph->is_slot_connected(type, p_id, 1)) {
+ gn->add_child(make_label("b",Variant::VECTOR3));
+ } else {
+ Vector3 v = graph->default_get_value(type,p_id,1);
+ gn->add_child(make_editor(String("b: ")+v,gn,p_id,1,Variant::VECTOR3));
+ }
- gn->add_child(button);
+ gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+ gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
- HBoxContainer *hbc = memnew( HBoxContainer );
- hbc->add_constant_override("separation",0);
- hbc->add_child( memnew(Label("xf")));
- hbc->add_spacer();
- Label *l = memnew(Label("out"));
- l->set_align(Label::ALIGN_RIGHT);
- hbc->add_child( l);
- gn->add_child(hbc);
- gn->add_child( memnew(Label("vec")));
- gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
- gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
+ } break; // vec3 vs vec3 op (mul: { } break;ad: { } break;div: { } break;crossprod: { } break;etc)
+ case ShaderGraph::NODE_VEC_SCALAR_OP: {
- } break;
- case ShaderGraph::NODE_XFORM_VEC_INV_MULT: {
+ gn->set_title("VecScalarOp");
+ static const char* op_name[ShaderGraph::VEC_SCALAR_MAX_OP]={
+ "Mul",
+ "Div",
+ "Pow",
+ };
- gn->set_title("XFVecInvMult");
+ OptionButton *ob = memnew( OptionButton );
+ for(int i=0;i<ShaderGraph::VEC_SCALAR_MAX_OP;i++) {
+ ob->add_item(op_name[i],i);
+ }
- Button *button = memnew( Button("RotOnly"));
- button->set_toggle_mode(true);
- button->set_pressed(graph->xform_vec_mult_node_get_no_translation(type,p_id));
- button->connect("toggled",this,"_xform_inv_rev_changed",varray(p_id));
+ ob->select(graph->vec_scalar_op_node_get_op(type,p_id));
+ ob->connect("item_selected",this,"_vec_scalar_op_changed",varray(p_id));
+ gn->add_child(ob);
+
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ hbc->add_constant_override("separation",0);
+ if (graph->is_slot_connected(type, p_id, 0)) {
+ hbc->add_child(make_label("a",Variant::VECTOR3));
+ } else {
+ Vector3 v = graph->default_get_value(type,p_id,0);
+ hbc->add_child(make_editor(String("a: ")+v,gn,p_id,0,Variant::VECTOR3));
+ }
+ hbc->add_spacer();
+ hbc->add_child( memnew(Label("out")));
+ gn->add_child(hbc);
+
+ if (graph->is_slot_connected(type, p_id, 1)) {
+ gn->add_child(make_label("b",Variant::REAL));
+ } else {
+ float v = graph->default_get_value(type,p_id,1);
+ gn->add_child(make_editor(String("b: ")+Variant(v),gn,p_id,1,Variant::REAL,hint_spin));
+ }
+ gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+ gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color());
+
+
+ } break; // vec3 vs scalar op (mul: { } break; add: { } break; div: { } break; etc)
+ case ShaderGraph::NODE_RGB_OP: {
+
+ gn->set_title("RGB Op");
+ static const char* op_name[ShaderGraph::RGB_MAX_OP]={
+ "Screen",
+ "Difference",
+ "Darken",
+ "Lighten",
+ "Overlay",
+ "Dodge",
+ "Burn",
+ "SoftLight",
+ "HardLight"
+ };
+
+ OptionButton *ob = memnew( OptionButton );
+ for(int i=0;i<ShaderGraph::RGB_MAX_OP;i++) {
+
+ ob->add_item(op_name[i],i);
+ }
- gn->add_child(button);
+ ob->select(graph->rgb_op_node_get_op(type,p_id));
+ ob->connect("item_selected",this,"_rgb_op_changed",varray(p_id));
+ gn->add_child(ob);
- gn->add_child( memnew(Label("vec")));
- HBoxContainer *hbc = memnew( HBoxContainer );
- hbc->add_constant_override("separation",0);
- hbc->add_child( memnew(Label("xf")));
- hbc->add_spacer();
- Label *l = memnew(Label("out"));
- l->set_align(Label::ALIGN_RIGHT);
- hbc->add_child( l);
- gn->add_child(hbc);
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ hbc->add_constant_override("separation",0);
+ if (graph->is_slot_connected(type, p_id, 0)) {
+ hbc->add_child(make_label("a",Variant::COLOR));
+ } else {
+ hbc->add_child(make_editor(String("a: "),gn,p_id,0,Variant::COLOR));
+ }
+ hbc->add_spacer();
+ hbc->add_child( memnew(Label("out")));
+ gn->add_child(hbc);
+ if (graph->is_slot_connected(type, p_id, 1)) {
+ gn->add_child(make_label("b",Variant::COLOR));
+ } else {
+ gn->add_child(make_editor(String("b: "),gn,p_id,1,Variant::COLOR));
+ }
- gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
- gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
-
-
- } break; // mat4 x vec3 inverse mult (with no-translation option)
- case ShaderGraph::NODE_SCALAR_FUNC: {
-
- gn->set_title("ScalarFunc");
- static const char* func_name[ShaderGraph::SCALAR_MAX_FUNC]={
- "Sin",
- "Cos",
- "Tan",
- "ASin",
- "ACos",
- "ATan",
- "SinH",
- "CosH",
- "TanH",
- "Log",
- "Exp",
- "Sqrt",
- "Abs",
- "Sign",
- "Floor",
- "Round",
- "Ceil",
- "Frac",
- "Satr",
- "Neg"
- };
-
- OptionButton *ob = memnew( OptionButton );
- for(int i=0;i<ShaderGraph::SCALAR_MAX_FUNC;i++) {
-
- ob->add_item(func_name[i],i);
- }
+ gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+ gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
- ob->select(graph->scalar_func_node_get_function(type,p_id));
- ob->connect("item_selected",this,"_scalar_func_changed",varray(p_id));
- gn->add_child(ob);
+ } break; // vec3 vs vec3 rgb op (with scalar amount): { } break; like brighten: { } break; darken: { } break; burn: { } break; dodge: { } break; multiply: { } break; etc.
+ case ShaderGraph::NODE_XFORM_MULT: {
- HBoxContainer *hbc = memnew( HBoxContainer );
- hbc->add_child( memnew(Label("in")));
- hbc->add_spacer();
- hbc->add_child( memnew(Label("out")));
- gn->add_child(hbc);
+ gn->set_title("XFMult");
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ if (graph->is_slot_connected(type, p_id, 0)) {
+ hbc->add_child(make_label("a",Variant::TRANSFORM));
+ } else {
+ hbc->add_child(make_editor(String("a: edit..."),gn,p_id,0,Variant::TRANSFORM));
+ }
+ hbc->add_spacer();
+ hbc->add_child( memnew(Label("out")));
+ gn->add_child(hbc);
+ if (graph->is_slot_connected(type, p_id, 1)) {
+ gn->add_child(make_label("b",Variant::TRANSFORM));
+ } else {
+ gn->add_child(make_editor(String("b: edit..."),gn,p_id,1,Variant::TRANSFORM));
+ }
- gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+ gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM],true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM]);
+ gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM],false,0,Color());
- } break; // scalar function (sin: { } break; cos: { } break; etc)
- case ShaderGraph::NODE_VEC_FUNC: {
+ } break; // mat4 x mat4
+ case ShaderGraph::NODE_XFORM_VEC_MULT: {
+ gn->set_title("XFVecMult");
+ CheckBox *button = memnew (CheckBox("RotOnly"));
+ button->set_pressed(graph->xform_vec_mult_node_get_no_translation(type,p_id));
+ button->connect("toggled",this,"_xform_inv_rev_changed",varray(p_id));
- gn->set_title("VecFunc");
- static const char* func_name[ShaderGraph::VEC_MAX_FUNC]={
- "Normalize",
- "Saturate",
- "Negate",
- "Reciprocal",
- "RGB to HSV",
- "HSV to RGB",
- };
+ gn->add_child(button);
- OptionButton *ob = memnew( OptionButton );
- for(int i=0;i<ShaderGraph::VEC_MAX_FUNC;i++) {
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ hbc->add_constant_override("separation",0);
+ if (graph->is_slot_connected(type, p_id, 0)) {
+ hbc->add_child(make_label("xf",Variant::TRANSFORM));
+ } else {
+ hbc->add_child(make_editor(String("xf: edit..."),gn,p_id,0,Variant::TRANSFORM));
+ }
+ hbc->add_spacer();
+ Label *l = memnew(Label("out"));
+ l->set_align(Label::ALIGN_RIGHT);
+ hbc->add_child( l);
+ gn->add_child(hbc);
+ if (graph->is_slot_connected(type, p_id, 1)) {
+ gn->add_child(make_label("a",Variant::VECTOR3));
+ } else {
+ Vector3 v = graph->default_get_value(type,p_id,1);
+ gn->add_child(make_editor(String("a: ")+v,gn,p_id,1,Variant::VECTOR3));
+ }
- ob->add_item(func_name[i],i);
- }
+ gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+ gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
- ob->select(graph->vec_func_node_get_function(type,p_id));
- ob->connect("item_selected",this,"_vec_func_changed",varray(p_id));
- gn->add_child(ob);
+ } break;
+ case ShaderGraph::NODE_XFORM_VEC_INV_MULT: {
- HBoxContainer *hbc = memnew( HBoxContainer );
- hbc->add_constant_override("separation",0);
- hbc->add_child( memnew(Label("in")));
- hbc->add_spacer();
- hbc->add_child( memnew(Label("out")));
- gn->add_child(hbc);
+ gn->set_title("XFVecInvMult");
- gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
- } break; // vector function (normalize: { } break; negate: { } break; reciprocal: { } break; rgb2hsv: { } break; hsv2rgb: { } break; etc: { } break; etc)
- case ShaderGraph::NODE_VEC_LEN: {
- gn->set_title("VecLength");
- HBoxContainer *hbc = memnew( HBoxContainer );
- hbc->add_child( memnew(Label("in")));
- hbc->add_spacer();
- hbc->add_child( memnew(Label("len")));
- gn->add_child(hbc);
+ CheckBox *button = memnew( CheckBox("RotOnly"));
+ button->set_pressed(graph->xform_vec_mult_node_get_no_translation(type,p_id));
+ button->connect("toggled",this,"_xform_inv_rev_changed",varray(p_id));
- gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+ gn->add_child(button);
- } break; // vec3 length
- case ShaderGraph::NODE_DOT_PROD: {
+ if (graph->is_slot_connected(type, p_id, 0)) {
+ gn->add_child(make_label("a",Variant::VECTOR3));
+ } else {
+ Vector3 v = graph->default_get_value(type,p_id,0);
+ gn->add_child(make_editor(String("a: ")+v,gn,p_id,0,Variant::VECTOR3));
+ }
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ hbc->add_constant_override("separation",0);
+ if (graph->is_slot_connected(type, p_id, 1)) {
+ hbc->add_child(make_label("xf", Variant::TRANSFORM));
+ } else {
+ hbc->add_child(make_editor(String("xf: edit..."),gn,p_id,1,Variant::TRANSFORM));
+ }
+ hbc->add_spacer();
+ Label *l = memnew(Label("out"));
+ l->set_align(Label::ALIGN_RIGHT);
+ hbc->add_child( l);
+ gn->add_child(hbc);
+
+ gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
+ gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+
+
+ } break; // mat4 x vec3 inverse mult (with no-translation option)
+ case ShaderGraph::NODE_SCALAR_FUNC: {
+
+ gn->set_title("ScalarFunc");
+ static const char* func_name[ShaderGraph::SCALAR_MAX_FUNC]={
+ "Sin",
+ "Cos",
+ "Tan",
+ "ASin",
+ "ACos",
+ "ATan",
+ "SinH",
+ "CosH",
+ "TanH",
+ "Log",
+ "Exp",
+ "Sqrt",
+ "Abs",
+ "Sign",
+ "Floor",
+ "Round",
+ "Ceil",
+ "Frac",
+ "Satr",
+ "Neg"
+ };
+
+ OptionButton *ob = memnew( OptionButton );
+ for(int i=0;i<ShaderGraph::SCALAR_MAX_FUNC;i++) {
+
+ ob->add_item(func_name[i],i);
+ }
- gn->set_title("DotProduct");
- HBoxContainer *hbc = memnew( HBoxContainer );
- hbc->add_constant_override("separation",0);
- hbc->add_child( memnew(Label("a")));
- hbc->add_spacer();
- hbc->add_child( memnew(Label("dp")));
- gn->add_child(hbc);
- gn->add_child( memnew(Label("b")));
+ ob->select(graph->scalar_func_node_get_function(type,p_id));
+ ob->connect("item_selected",this,"_scalar_func_changed",varray(p_id));
+ gn->add_child(ob);
- gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
- gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ if (graph->is_slot_connected(type, p_id, 0)) {
+ hbc->add_child(make_label("in", Variant::REAL));
+ } else {
+ float v = graph->default_get_value(type,p_id,0);
+ hbc->add_child(make_editor(String("in: ")+Variant(v),gn,p_id,0,Variant::REAL,hint_spin));
+ }
+ hbc->add_spacer();
+ hbc->add_child( memnew(Label("out")));
+ gn->add_child(hbc);
- } break; // vec3 . vec3 (dot product -> scalar output)
- case ShaderGraph::NODE_VEC_TO_SCALAR: {
+ gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
- gn->set_title("Vec2Scalar");
- HBoxContainer *hbc = memnew( HBoxContainer );
- hbc->add_constant_override("separation",0);
- hbc->add_child( memnew(Label("vec")));
- hbc->add_spacer();
- Label *l=memnew(Label("x"));
- l->set_align(Label::ALIGN_RIGHT);
- hbc->add_child( l);
- gn->add_child(hbc);
- l=memnew(Label("y"));
- l->set_align(Label::ALIGN_RIGHT);
- gn->add_child( l );
- l=memnew(Label("z"));
- l->set_align(Label::ALIGN_RIGHT);
- gn->add_child( l);
- gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
- gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
- gn->set_slot(2,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+ } break; // scalar function (sin: { } break; cos: { } break; etc)
+ case ShaderGraph::NODE_VEC_FUNC: {
+ gn->set_title("VecFunc");
+ static const char* func_name[ShaderGraph::VEC_MAX_FUNC]={
+ "Normalize",
+ "Saturate",
+ "Negate",
+ "Reciprocal",
+ "RGB to HSV",
+ "HSV to RGB",
+ };
- } break; // 1 vec3 input: { } break; 3 scalar outputs
- case ShaderGraph::NODE_SCALAR_TO_VEC: {
+ OptionButton *ob = memnew( OptionButton );
+ for(int i=0;i<ShaderGraph::VEC_MAX_FUNC;i++) {
- gn->set_title("Scalar2Vec");
- HBoxContainer *hbc = memnew( HBoxContainer );
- hbc->add_child( memnew(Label("x")));
- hbc->add_spacer();
- hbc->add_child( memnew(Label("vec")));
- gn->add_child(hbc);
- gn->add_child( memnew(Label("y")));
- gn->add_child( memnew(Label("z")));
+ ob->add_item(func_name[i],i);
+ }
- gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
- gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color());
- gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color());
+ ob->select(graph->vec_func_node_get_function(type,p_id));
+ ob->connect("item_selected",this,"_vec_func_changed",varray(p_id));
+ gn->add_child(ob);
+
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ hbc->add_constant_override("separation",0);
+ if (graph->is_slot_connected(type, p_id, 0)) {
+ hbc->add_child(make_label("in", Variant::VECTOR3));
+ } else {
+ Vector3 v = graph->default_get_value(type,p_id,0);
+ hbc->add_child(make_editor(String("in: ")+v,gn,p_id,0,Variant::VECTOR3));
+ }
+ hbc->add_spacer();
+ hbc->add_child( memnew(Label("out")));
+ gn->add_child(hbc);
+
+ gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+
+ } break; // vector function (normalize: { } break; negate: { } break; reciprocal: { } break; rgb2hsv: { } break; hsv2rgb: { } break; etc: { } break; etc)
+ case ShaderGraph::NODE_VEC_LEN: {
+ gn->set_title("VecLength");
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ if (graph->is_slot_connected(type, p_id, 0)) {
+ hbc->add_child(make_label("in", Variant::VECTOR3));
+ } else {
+ Vector3 v = graph->default_get_value(type,p_id,0);
+ hbc->add_child(make_editor(String("in: ")+v,gn,p_id,0,Variant::VECTOR3));
+ }
+ hbc->add_spacer();
+ hbc->add_child( memnew(Label("len")));
+ gn->add_child(hbc);
+
+ gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+
+ } break; // vec3 length
+ case ShaderGraph::NODE_DOT_PROD: {
+
+ gn->set_title("DotProduct");
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ hbc->add_constant_override("separation",0);
+ if (graph->is_slot_connected(type, p_id, 0)) {
+ hbc->add_child(make_label("a", Variant::VECTOR3));
+ } else {
+ Vector3 v = graph->default_get_value(type,p_id,0);
+ hbc->add_child(make_editor(String("a: ")+v,gn,p_id,0,Variant::VECTOR3));
+ }
+ hbc->add_spacer();
+ hbc->add_child( memnew(Label("dp")));
+ gn->add_child(hbc);
+ if (graph->is_slot_connected(type, p_id, 1)) {
+ gn->add_child(make_label("b", Variant::VECTOR3));
+ } else {
+ Vector3 v = graph->default_get_value(type,p_id,1);
+ gn->add_child(make_editor(String("b: ")+v,gn,p_id,1,Variant::VECTOR3));
+ }
- } break; // 3 scalar input: { } break; 1 vec3 output
- case ShaderGraph::NODE_VEC_TO_XFORM: {
+ gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+ gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
- gn->set_title("Vec2XForm");
- HBoxContainer *hbc = memnew( HBoxContainer );
- hbc->add_constant_override("separation",0);
- hbc->add_child( memnew(Label("x")));
- hbc->add_spacer();
- hbc->add_child( memnew(Label("xf")));
- gn->add_child(hbc);
- gn->add_child( memnew(Label("y")));
- gn->add_child( memnew(Label("z")));
- gn->add_child( memnew(Label("ofs")));
+ } break; // vec3 . vec3 (dot product -> scalar output)
+ case ShaderGraph::NODE_VEC_TO_SCALAR: {
- gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM]);
- gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
- gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
- gn->set_slot(3,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
+ gn->set_title("Vec2Scalar");
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ hbc->add_constant_override("separation",0);
+ if (graph->is_slot_connected(type, p_id, 0)) {
+ hbc->add_child(make_label("vec", Variant::VECTOR3));
+ } else {
+ Vector3 v = graph->default_get_value(type,p_id,0);
+ hbc->add_child(make_editor(String("vec: ")+v,gn,p_id,0,Variant::VECTOR3));
+ }
+ hbc->add_spacer();
+ Label *l=memnew(Label("x"));
+ l->set_align(Label::ALIGN_RIGHT);
+ hbc->add_child( l);
+ gn->add_child(hbc);
+ l=memnew(Label("y"));
+ l->set_align(Label::ALIGN_RIGHT);
+ gn->add_child( l );
+ l=memnew(Label("z"));
+ l->set_align(Label::ALIGN_RIGHT);
+ gn->add_child( l);
+
+ gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+ gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+ gn->set_slot(2,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+
+
+
+
+ } break; // 1 vec3 input: { } break; 3 scalar outputs
+ case ShaderGraph::NODE_SCALAR_TO_VEC: {
+
+ gn->set_title("Scalar2Vec");
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ if (graph->is_slot_connected(type, p_id, 0)) {
+ hbc->add_child(make_label("x", Variant::REAL));
+ } else {
+ float v = graph->default_get_value(type,p_id,0);
+ hbc->add_child(make_editor(String("x: ")+Variant(v),gn,p_id,0,Variant::REAL));
+ }
+ hbc->add_spacer();
+ hbc->add_child( memnew(Label("vec")));
+ gn->add_child(hbc);
+ if (graph->is_slot_connected(type, p_id, 1)) {
+ gn->add_child(make_label("y", Variant::REAL));
+ } else {
+ float v = graph->default_get_value(type,p_id,1);
+ gn->add_child(make_editor(String("y: ")+Variant(v),gn,p_id,1,Variant::REAL));
+ }
+ if (graph->is_slot_connected(type, p_id, 2)) {
+ gn->add_child(make_label("in", Variant::REAL));
+ } else {
+ float v = graph->default_get_value(type,p_id,2);
+ gn->add_child(make_editor(String("in: ")+Variant(v),gn,p_id,2,Variant::REAL));
+ }
- } break; // 3 vec input: { } break; 1 xform output
- case ShaderGraph::NODE_XFORM_TO_VEC: {
+ gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+ gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color());
+ gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color());
+
+ } break; // 3 scalar input: { } break; 1 vec3 output
+ case ShaderGraph::NODE_VEC_TO_XFORM: {
+
+ gn->set_title("Vec2XForm");
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ hbc->add_constant_override("separation",0);
+ if (graph->is_slot_connected(type, p_id, 0)) {
+ hbc->add_child(make_label("x", Variant::VECTOR3));
+ } else {
+ Vector3 v = graph->default_get_value(type,p_id,0);
+ hbc->add_child(make_editor(String("x: ")+v,gn,p_id,0,Variant::VECTOR3));
+ }
+ hbc->add_spacer();
+ hbc->add_child( memnew(Label("xf")));
+ gn->add_child(hbc);
+ if (graph->is_slot_connected(type, p_id, 1)) {
+ gn->add_child(make_label("y", Variant::VECTOR3));
+ } else {
+ Vector3 v = graph->default_get_value(type,p_id,1);
+ gn->add_child(make_editor(String("y: ")+v,gn,p_id,1,Variant::VECTOR3));
+ }
+ if (graph->is_slot_connected(type, p_id, 2)) {
+ gn->add_child(make_label("z", Variant::VECTOR3));
+ } else {
+ Vector3 v = graph->default_get_value(type,p_id,2);
+ gn->add_child(make_editor(String("z: ")+v,gn,p_id,2,Variant::VECTOR3));
+ }
+ if (graph->is_slot_connected(type, p_id, 3)) {
+ gn->add_child(make_label("ofs", Variant::VECTOR3));
+ } else {
+ Vector3 v = graph->default_get_value(type,p_id,3);
+ gn->add_child(make_editor(String("ofs: ")+v,gn,p_id,3,Variant::VECTOR3));
+ }
- gn->set_title("XForm2Vec");
+ gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM]);
+ gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
+ gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
+ gn->set_slot(3,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
- HBoxContainer *hbc = memnew( HBoxContainer );
- hbc->add_constant_override("separation",0);
- hbc->add_child( memnew(Label("xf")));
- hbc->add_spacer();
- Label *l=memnew(Label("x"));
- l->set_align(Label::ALIGN_RIGHT);
- hbc->add_child( l);
- gn->add_child(hbc);
- l=memnew(Label("y"));
- l->set_align(Label::ALIGN_RIGHT);
- gn->add_child( l );
- l=memnew(Label("z"));
- l->set_align(Label::ALIGN_RIGHT);
- gn->add_child( l);
- l=memnew(Label("ofs"));
- l->set_align(Label::ALIGN_RIGHT);
- gn->add_child( l);
-
- gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
- gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
- gn->set_slot(2,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
- gn->set_slot(3,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
-
- } break; // 3 vec input: { } break; 1 xform output
- case ShaderGraph::NODE_SCALAR_INTERP: {
-
- gn->set_title("ScalarInterp");
- HBoxContainer *hbc = memnew( HBoxContainer );
- hbc->add_constant_override("separation",0);
- hbc->add_child( memnew(Label("a")));
- hbc->add_spacer();
- hbc->add_child( memnew(Label("interp")));
- gn->add_child(hbc);
- gn->add_child( memnew(Label("b")));
- gn->add_child( memnew(Label("c")));
+ } break; // 3 vec input: { } break; 1 xform output
+ case ShaderGraph::NODE_XFORM_TO_VEC: {
- gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
- gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color());
- gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color());
+ gn->set_title("XForm2Vec");
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ hbc->add_constant_override("separation",0);
+ if (graph->is_slot_connected(type, p_id, 0)) {
+ hbc->add_child(make_label("fx", Variant::TRANSFORM));
+ } else {
+ hbc->add_child(make_editor(String("fx: edit..."),gn,p_id,0,Variant::TRANSFORM));
+ }
+ hbc->add_spacer();
+ Label *l=memnew(Label("x"));
+ l->set_align(Label::ALIGN_RIGHT);
+ hbc->add_child( l);
+ gn->add_child(hbc);
+ l=memnew(Label("y"));
+ l->set_align(Label::ALIGN_RIGHT);
+ gn->add_child( l );
+ l=memnew(Label("z"));
+ l->set_align(Label::ALIGN_RIGHT);
+ gn->add_child( l);
+ l=memnew(Label("ofs"));
+ l->set_align(Label::ALIGN_RIGHT);
+ gn->add_child( l);
+
+ gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+ gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+ gn->set_slot(2,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+ gn->set_slot(3,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+
+ } break; // 3 vec input: { } break; 1 xform output
+ case ShaderGraph::NODE_SCALAR_INTERP: {
+
+ gn->set_title("ScalarInterp");
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ hbc->add_constant_override("separation",0);
+ if (graph->is_slot_connected(type, p_id, 0)) {
+ hbc->add_child(make_label("a", Variant::REAL));
+ } else {
+ float v = graph->default_get_value(type,p_id,0);
+ hbc->add_child(make_editor(String("a: ")+Variant(v),gn,p_id,0,Variant::REAL,hint_spin));
+ }
+ hbc->add_spacer();
+ hbc->add_child( memnew(Label("interp")));
+ gn->add_child(hbc);
+ if (graph->is_slot_connected(type, p_id, 1)) {
+ gn->add_child(make_label("b", Variant::REAL));
+ } else {
+ float v = graph->default_get_value(type,p_id,1);
+ gn->add_child(make_editor(String("b: ")+Variant(v),gn,p_id,1,Variant::REAL,hint_spin));
+ }
+ if (graph->is_slot_connected(type, p_id, 2)) {
+ gn->add_child(make_label("c", Variant::REAL));
+ } else {
+ float v = graph->default_get_value(type,p_id,2);
+ gn->add_child(make_editor(String("c: ")+Variant(v),gn,p_id,2,Variant::REAL,hint_slider));
+ }
- } break; // scalar interpolation (with optional curve)
- case ShaderGraph::NODE_VEC_INTERP: {
+ gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+ gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color());
+ gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color());
- gn->set_title("VecInterp");
- HBoxContainer *hbc = memnew( HBoxContainer );
- hbc->add_child( memnew(Label("a")));
- hbc->add_spacer();
- hbc->add_child( memnew(Label("interp")));
- gn->add_child(hbc);
- gn->add_child( memnew(Label("b")));
- gn->add_child( memnew(Label("c")));
- gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
- gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
- gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color());
+ } break; // scalar interpolation (with optional curve)
+ case ShaderGraph::NODE_VEC_INTERP: {
- } break; // vec3 interpolation (with optional curve)
- case ShaderGraph::NODE_COLOR_RAMP: {
+ gn->set_title("VecInterp");
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ if (graph->is_slot_connected(type, p_id, 0)) {
+ hbc->add_child(make_label("a", Variant::VECTOR3));
+ } else {
+ Vector3 v = graph->default_get_value(type,p_id,0);
+ hbc->add_child(make_editor(String("a: ")+v,gn,p_id,0,Variant::VECTOR3));
+ }
+ hbc->add_spacer();
+ hbc->add_child( memnew(Label("interp")));
+ gn->add_child(hbc);
+ if (graph->is_slot_connected(type, p_id, 1)) {
+ gn->add_child(make_label("b", Variant::VECTOR3));
+ } else {
+ Vector3 v = graph->default_get_value(type,p_id,1);
+ gn->add_child(make_editor(String("b: ")+v,gn,p_id,1,Variant::VECTOR3));
+ }
+ if (graph->is_slot_connected(type, p_id, 2)) {
+ gn->add_child(make_label("c", Variant::REAL));
+ } else {
+ float v = graph->default_get_value(type,p_id,2);
+ gn->add_child(make_editor(String("c: ")+Variant(v),gn,p_id,2,Variant::REAL,hint_slider));
+ }
- gn->set_title("ColorRamp");
- GraphColorRampEdit * ramp = memnew( GraphColorRampEdit );
+ gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+ gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],false,0,Color());
+ gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],false,0,Color());
- DVector<real_t> offsets = graph->color_ramp_node_get_offsets(type,p_id);
- DVector<Color> colors = graph->color_ramp_node_get_colors(type,p_id);
+ } break; // vec3 interpolation (with optional curve)
+ case ShaderGraph::NODE_COLOR_RAMP: {
- int oc = offsets.size();
+ gn->set_title("ColorRamp");
+ GraphColorRampEdit * ramp = memnew( GraphColorRampEdit );
- if (oc) {
- DVector<real_t>::Read rofs = offsets.read();
- DVector<Color>::Read rcol = colors.read();
+ DVector<real_t> offsets = graph->color_ramp_node_get_offsets(type,p_id);
+ DVector<Color> colors = graph->color_ramp_node_get_colors(type,p_id);
- Vector<float> ofsv;
- Vector<Color> colorv;
- for(int i=0;i<oc;i++) {
- ofsv.push_back(rofs[i]);
- colorv.push_back(rcol[i]);
- }
+ int oc = offsets.size();
- ramp->set_ramp(ofsv,colorv);
+ if (oc) {
+ DVector<real_t>::Read rofs = offsets.read();
+ DVector<Color>::Read rcol = colors.read();
+ Vector<float> ofsv;
+ Vector<Color> colorv;
+ for(int i=0;i<oc;i++) {
+ ofsv.push_back(rofs[i]);
+ colorv.push_back(rcol[i]);
}
- ramp->connect("ramp_changed",this,"_color_ramp_changed",varray(p_id,ramp));
- ramp->set_custom_minimum_size(Size2(128,1));
- gn->add_child(ramp);
+ ramp->set_ramp(ofsv,colorv);
+ }
- HBoxContainer *hbc = memnew( HBoxContainer );
- hbc->add_constant_override("separation",0);
- hbc->add_child( memnew(Label("c")));
- hbc->add_spacer();
- Label *l=memnew(Label("rgb"));
- l->set_align(Label::ALIGN_RIGHT);
- hbc->add_child( l);
- gn->add_child(hbc);
- l=memnew(Label("alpha"));
- l->set_align(Label::ALIGN_RIGHT);
- gn->add_child( l);
+ ramp->connect("ramp_changed",this,"_color_ramp_changed",varray(p_id,ramp));
+ ramp->set_custom_minimum_size(Size2(128,1));
+ gn->add_child(ramp);
- gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
- gn->set_slot(2,false,ShaderGraph::SLOT_MAX,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ hbc->add_constant_override("separation",0);
+ if (graph->is_slot_connected(type, p_id, 0)) {
+ hbc->add_child(make_label("c", Variant::REAL));
+ } else {
+ float v = graph->default_get_value(type,p_id,0);
+ hbc->add_child(make_editor(String("c: ")+Variant(v),gn,p_id,0,Variant::REAL,hint_slider));
+ }
+ hbc->add_spacer();
+ Label *l=memnew(Label("rgb"));
+ l->set_align(Label::ALIGN_RIGHT);
+ hbc->add_child( l);
+ gn->add_child(hbc);
+ l=memnew(Label("alpha"));
+ l->set_align(Label::ALIGN_RIGHT);
+ gn->add_child( l);
- } break; // scalar interpolation (with optional curve)
- case ShaderGraph::NODE_CURVE_MAP: {
+ gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+ gn->set_slot(2,false,ShaderGraph::SLOT_MAX,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
- gn->set_title("CurveMap");
- GraphCurveMapEdit * map = memnew( GraphCurveMapEdit );
- DVector<Vector2> points = graph->curve_map_node_get_points(type,p_id);
+ } break; // scalar interpolation (with optional curve)
+ case ShaderGraph::NODE_CURVE_MAP: {
- int oc = points.size();
+ gn->set_title("CurveMap");
+ GraphCurveMapEdit * map = memnew( GraphCurveMapEdit );
- if (oc) {
- DVector<Vector2>::Read rofs = points.read();
+ DVector<Vector2> points = graph->curve_map_node_get_points(type,p_id);
+ int oc = points.size();
- Vector<Vector2> ofsv;
- for(int i=0;i<oc;i++) {
- ofsv.push_back(rofs[i]);
- }
+ if (oc) {
+ DVector<Vector2>::Read rofs = points.read();
- map->set_points(ofsv);
+ Vector<Vector2> ofsv;
+ for(int i=0;i<oc;i++) {
+ ofsv.push_back(rofs[i]);
}
- map->connect("curve_changed",this,"_curve_changed",varray(p_id,map));
- //map->connect("map_changed",this,"_curve_map_changed",varray(p_id,map));
- map->set_custom_minimum_size(Size2(128,64));
- gn->add_child(map);
+ map->set_points(ofsv);
+ }
+ map->connect("curve_changed",this,"_curve_changed",varray(p_id,map));
+
+ //map->connect("map_changed",this,"_curve_map_changed",varray(p_id,map));
+ map->set_custom_minimum_size(Size2(128,64));
+ gn->add_child(map);
+
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ hbc->add_constant_override("separation",0);
+ if (graph->is_slot_connected(type, p_id, 0)) {
+ hbc->add_child(make_label("c", Variant::REAL));
+ } else {
+ float v = graph->default_get_value(type,p_id,0);
+ hbc->add_child(make_editor(String("c: ")+Variant(v),gn,p_id,0,Variant::REAL,hint_slider));
+ }
+ hbc->add_spacer();
+ Label *l=memnew(Label("cmap"));
+ l->set_align(Label::ALIGN_RIGHT);
+ hbc->add_child( l);
+ gn->add_child(hbc);
+
+
+ gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+
+
+ } break; // scalar interpolation (with optional curve)
+
+ case ShaderGraph::NODE_SCALAR_INPUT: {
+
+ gn->set_title("ScalarUniform");
+ LineEdit *le = memnew( LineEdit );
+ gn->add_child(le);
+ le->set_text(graph->input_node_get_name(type,p_id));
+ le->connect("text_entered",this,"_input_name_changed",varray(p_id,le));
+ SpinBox *sb = memnew( SpinBox );
+ sb->set_min(-100000);
+ sb->set_max(100000);
+ sb->set_step(0.001);
+ sb->set_val(graph->scalar_input_node_get_value(type,p_id));
+ sb->connect("value_changed",this,"_scalar_input_changed",varray(p_id));
+ gn->add_child(sb);
+ gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+
+ } break; // scalar uniform (assignable in material)
+ case ShaderGraph::NODE_VEC_INPUT: {
+
+ gn->set_title("VectorUniform");
+ LineEdit *le = memnew( LineEdit );
+ gn->add_child(le);
+ le->set_text(graph->input_node_get_name(type,p_id));
+ le->connect("text_entered",this,"_input_name_changed",varray(p_id,le));
+ Array v3p(true);
+ for(int i=0;i<3;i++) {
HBoxContainer *hbc = memnew( HBoxContainer );
- hbc->add_constant_override("separation",0);
- hbc->add_child( memnew(Label("c")));
- hbc->add_spacer();
- Label *l=memnew(Label("cmap"));
- l->set_align(Label::ALIGN_RIGHT);
- hbc->add_child( l);
- gn->add_child(hbc);
-
-
- gn->set_slot(1,true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR],true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
-
-
- } break; // scalar interpolation (with optional curve)
-
- case ShaderGraph::NODE_SCALAR_INPUT: {
-
- gn->set_title("ScalarUniform");
- LineEdit *le = memnew( LineEdit );
- gn->add_child(le);
- le->set_text(graph->input_node_get_name(type,p_id));
- le->connect("text_entered",this,"_input_name_changed",varray(p_id,le));
+ Label *l = memnew( Label );
+ l->set_text(String::chr('X'+i));
+ hbc->add_child(l);
SpinBox *sb = memnew( SpinBox );
+ sb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
sb->set_min(-100000);
sb->set_max(100000);
sb->set_step(0.001);
- sb->set_val(graph->scalar_input_node_get_value(type,p_id));
- sb->connect("value_changed",this,"_scalar_input_changed",varray(p_id));
- gn->add_child(sb);
- gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
-
- } break; // scalar uniform (assignable in material)
- case ShaderGraph::NODE_VEC_INPUT: {
-
- gn->set_title("VectorUniform");
- LineEdit *le = memnew( LineEdit );
- gn->add_child(le);
- le->set_text(graph->input_node_get_name(type,p_id));
- le->connect("text_entered",this,"_input_name_changed",varray(p_id,le));
- Array v3p(true);
- for(int i=0;i<3;i++) {
- HBoxContainer *hbc = memnew( HBoxContainer );
- Label *l = memnew( Label );
- l->set_text(String::chr('X'+i));
- hbc->add_child(l);
- SpinBox *sb = memnew( SpinBox );
- sb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- sb->set_min(-100000);
- sb->set_max(100000);
- sb->set_step(0.001);
- sb->set_val(graph->vec_input_node_get_value(type,p_id)[i]);
- sb->connect("value_changed",this,"_vec_input_changed",varray(p_id,v3p));
- v3p.push_back(sb);
- hbc->add_child(sb);
- gn->add_child(hbc);
- }
- gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
-
- } break; // vec3 uniform (assignable in material)
- case ShaderGraph::NODE_RGB_INPUT: {
-
- gn->set_title("ColorUniform");
- LineEdit *le = memnew( LineEdit );
- gn->add_child(le);
- le->set_text(graph->input_node_get_name(type,p_id));
- le->connect("text_entered",this,"_input_name_changed",varray(p_id,le));
- ColorPickerButton *cpb = memnew( ColorPickerButton );
- cpb->set_color(graph->rgb_input_node_get_value(type,p_id));
- cpb->connect("color_changed",this,"_rgb_input_changed",varray(p_id));
- gn->add_child(cpb);
- Label *l = memnew( Label );
- l->set_text("RGB");
- l->set_align(Label::ALIGN_RIGHT);
- gn->add_child(l);
- l = memnew( Label );
- l->set_text("Alpha");
- l->set_align(Label::ALIGN_RIGHT);
- gn->add_child(l);
-
- gn->set_slot(2,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
- gn->set_slot(3,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
-
-
- } break; // color uniform (assignable in material)
- case ShaderGraph::NODE_XFORM_INPUT: {
- gn->set_title("XFUniform");
- LineEdit *le = memnew( LineEdit );
- gn->add_child(le);
- le->set_text(graph->input_node_get_name(type,p_id));
- le->connect("text_entered",this,"_input_name_changed",varray(p_id,le));
- ToolButton *edit = memnew( ToolButton );
- edit->set_text("edit..");
- edit->connect("pressed",this,"_xform_input_changed",varray(p_id,edit));
- gn->add_child(edit);
- gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM]);
-
- } break; // mat4 uniform (assignable in material)
- case ShaderGraph::NODE_TEXTURE_INPUT: {
-
- gn->set_title("TexUniform");
- LineEdit *le = memnew( LineEdit );
- gn->add_child(le);
- le->set_text(graph->input_node_get_name(type,p_id));
- le->connect("text_entered",this,"_input_name_changed",varray(p_id,le));
- TextureFrame *tex = memnew( TextureFrame );
- tex->set_expand(true);
- tex->set_custom_minimum_size(Size2(80,80));
- gn->add_child(tex);
- tex->set_texture(graph->texture_input_node_get_value(type,p_id));
- ToolButton *edit = memnew( ToolButton );
- edit->set_text("edit..");
- edit->connect("pressed",this,"_tex_edited",varray(p_id,edit));
- gn->add_child(edit);
-
- HBoxContainer *hbc = memnew( HBoxContainer );
- hbc->add_constant_override("separation",0);
- hbc->add_child( memnew(Label("UV")));
- hbc->add_spacer();
- Label *l=memnew(Label("RGB"));
- l->set_align(Label::ALIGN_RIGHT);
- hbc->add_child(l);
- gn->add_child(hbc);
- l = memnew( Label );
- l->set_text("Alpha");
- l->set_align(Label::ALIGN_RIGHT);
- gn->add_child(l);
-
- gn->set_slot(3,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
- gn->set_slot(4,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
-
- } break; // texture input (assignable in material)
- case ShaderGraph::NODE_CUBEMAP_INPUT: {
-
- gn->set_title("TexUniform");
- LineEdit *le = memnew( LineEdit );
- gn->add_child(le);
- le->set_text(graph->input_node_get_name(type,p_id));
- le->connect("text_entered",this,"_input_name_changed",varray(p_id,le));
-
- ToolButton *edit = memnew( ToolButton );
- edit->set_text("edit..");
- edit->connect("pressed",this,"_cube_edited",varray(p_id,edit));
- gn->add_child(edit);
-
-
- HBoxContainer *hbc = memnew( HBoxContainer );
- hbc->add_constant_override("separation",0);
- hbc->add_child( memnew(Label("UV")));
- hbc->add_spacer();
- Label *l=memnew(Label("RGB"));
- l->set_align(Label::ALIGN_RIGHT);
- hbc->add_child(l);
- gn->add_child(hbc);
- l = memnew( Label );
- l->set_text("Alpha");
- l->set_align(Label::ALIGN_RIGHT);
- gn->add_child(l);
-
- gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
- gn->set_slot(3,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
-
- } break; // cubemap input (assignable in material)
- case ShaderGraph::NODE_DEFAULT_TEXTURE: {
-
- gn->set_title("CanvasItemTex");
- HBoxContainer *hbc = memnew( HBoxContainer );
- hbc->add_constant_override("separation",0);
- hbc->add_child( memnew(Label("UV")));
- hbc->add_spacer();
- Label *l=memnew(Label("RGB"));
- l->set_align(Label::ALIGN_RIGHT);
- hbc->add_child(l);
+ sb->set_val(graph->vec_input_node_get_value(type,p_id)[i]);
+ sb->connect("value_changed",this,"_vec_input_changed",varray(p_id,v3p));
+ v3p.push_back(sb);
+ hbc->add_child(sb);
gn->add_child(hbc);
- l = memnew( Label );
- l->set_text("Alpha");
- l->set_align(Label::ALIGN_RIGHT);
- gn->add_child(l);
-
- gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
- gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
-
-
- } break; // screen texture sampler (takes UV) (only usable in fragment case Shader)
-
- case ShaderGraph::NODE_OUTPUT: {
- gn->set_title("Output");
-
- List<ShaderGraph::SlotInfo> si;
- ShaderGraph::get_input_output_node_slot_info(graph->get_mode(),type,&si);
-
- int idx=0;
- for (List<ShaderGraph::SlotInfo>::Element *E=si.front();E;E=E->next()) {
- ShaderGraph::SlotInfo& s=E->get();
- if (s.dir==ShaderGraph::SLOT_OUT) {
-
- Label *l= memnew( Label );
- l->set_text(s.name);
- l->set_align(Label::ALIGN_LEFT);
- gn->add_child(l);
- gn->set_slot(idx,true,s.type,typecol[s.type],false,0,Color());
- idx++;
- }
+ }
+ gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+
+ } break; // vec3 uniform (assignable in material)
+ case ShaderGraph::NODE_RGB_INPUT: {
+
+ gn->set_title("ColorUniform");
+ LineEdit *le = memnew( LineEdit );
+ gn->add_child(le);
+ le->set_text(graph->input_node_get_name(type,p_id));
+ le->connect("text_entered",this,"_input_name_changed",varray(p_id,le));
+ ColorPickerButton *cpb = memnew( ColorPickerButton );
+ cpb->set_color(graph->rgb_input_node_get_value(type,p_id));
+ cpb->connect("color_changed",this,"_rgb_input_changed",varray(p_id));
+ gn->add_child(cpb);
+ Label *l = memnew( Label );
+ l->set_text("RGB");
+ l->set_align(Label::ALIGN_RIGHT);
+ gn->add_child(l);
+ l = memnew( Label );
+ l->set_text("Alpha");
+ l->set_align(Label::ALIGN_RIGHT);
+ gn->add_child(l);
+
+ gn->set_slot(2,false,0,Color(),true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+ gn->set_slot(3,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+
+
+ } break; // color uniform (assignable in material)
+ case ShaderGraph::NODE_XFORM_INPUT: {
+ gn->set_title("XFUniform");
+ LineEdit *le = memnew( LineEdit );
+ gn->add_child(le);
+ le->set_text(graph->input_node_get_name(type,p_id));
+ le->connect("text_entered",this,"_input_name_changed",varray(p_id,le));
+ ToolButton *edit = memnew( ToolButton );
+ edit->set_text("edit..");
+ edit->connect("pressed",this,"_xform_input_changed",varray(p_id,edit));
+ gn->add_child(edit);
+ gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_XFORM,typecol[ShaderGraph::SLOT_TYPE_XFORM]);
+
+ } break; // mat4 uniform (assignable in material)
+ case ShaderGraph::NODE_TEXTURE_INPUT: {
+
+ gn->set_title("TexUniform");
+ LineEdit *le = memnew( LineEdit );
+ gn->add_child(le);
+ le->set_text(graph->input_node_get_name(type,p_id));
+ le->connect("text_entered",this,"_input_name_changed",varray(p_id,le));
+ TextureFrame *tex = memnew( TextureFrame );
+ tex->set_expand(true);
+ tex->set_custom_minimum_size(Size2(80,80));
+ gn->add_child(tex);
+ tex->set_texture(graph->texture_input_node_get_value(type,p_id));
+ ToolButton *edit = memnew( ToolButton );
+ edit->set_text("edit..");
+ edit->connect("pressed",this,"_tex_edited",varray(p_id,edit));
+ gn->add_child(edit);
+
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ hbc->add_constant_override("separation",0);
+ if (graph->is_slot_connected(type, p_id, 0)) {
+ hbc->add_child(make_label("UV", Variant::VECTOR3));
+ } else {
+ Vector3 v = graph->default_get_value(type,p_id,0);
+ hbc->add_child(make_editor(String("UV: ")+v,gn,p_id,0,Variant::VECTOR3));
+ }
+ hbc->add_spacer();
+ Label *l=memnew(Label("RGB"));
+ l->set_align(Label::ALIGN_RIGHT);
+ hbc->add_child(l);
+ gn->add_child(hbc);
+ l = memnew( Label );
+ l->set_text("Alpha");
+ l->set_align(Label::ALIGN_RIGHT);
+ gn->add_child(l);
+
+ gn->set_slot(3,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+ gn->set_slot(4,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+
+ } break; // texture input (assignable in material)
+ case ShaderGraph::NODE_CUBEMAP_INPUT: {
+
+ gn->set_title("TexUniform");
+ LineEdit *le = memnew( LineEdit );
+ gn->add_child(le);
+ le->set_text(graph->input_node_get_name(type,p_id));
+ le->connect("text_entered",this,"_input_name_changed",varray(p_id,le));
+
+ ToolButton *edit = memnew( ToolButton );
+ edit->set_text("edit..");
+ edit->connect("pressed",this,"_cube_edited",varray(p_id,edit));
+ gn->add_child(edit);
+
+
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ hbc->add_constant_override("separation",0);
+ if (graph->is_slot_connected(type, p_id, 0)) {
+ hbc->add_child(make_label("UV", Variant::VECTOR3));
+ } else {
+ Vector3 v = graph->default_get_value(type,p_id,0);
+ hbc->add_child(make_editor(String("UV: ")+v,gn,p_id,0,Variant::VECTOR3));
+ }
+ hbc->add_spacer();
+ Label *l=memnew(Label("RGB"));
+ l->set_align(Label::ALIGN_RIGHT);
+ hbc->add_child(l);
+ gn->add_child(hbc);
+ l = memnew( Label );
+ l->set_text("Alpha");
+ l->set_align(Label::ALIGN_RIGHT);
+ gn->add_child(l);
+
+ gn->set_slot(2,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+ gn->set_slot(3,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+
+ } break; // cubemap input (assignable in material)
+ case ShaderGraph::NODE_DEFAULT_TEXTURE: {
+
+ gn->set_title("CanvasItemTex");
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ hbc->add_constant_override("separation",0);
+ if (graph->is_slot_connected(type, p_id, 0)) {
+ hbc->add_child(make_label("UV", Variant::VECTOR3));
+ } else {
+ Vector3 v = graph->default_get_value(type,p_id,0);
+ hbc->add_child(make_editor(String("UV: ")+v,gn,p_id,0,Variant::VECTOR3));
+ }
+ hbc->add_spacer();
+ Label *l=memnew(Label("RGB"));
+ l->set_align(Label::ALIGN_RIGHT);
+ hbc->add_child(l);
+ gn->add_child(hbc);
+ l = memnew( Label );
+ l->set_text("Alpha");
+ l->set_align(Label::ALIGN_RIGHT);
+ gn->add_child(l);
+
+ gn->set_slot(0,true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC],true,ShaderGraph::SLOT_TYPE_VEC,typecol[ShaderGraph::SLOT_TYPE_VEC]);
+ gn->set_slot(1,false,0,Color(),true,ShaderGraph::SLOT_TYPE_SCALAR,typecol[ShaderGraph::SLOT_TYPE_SCALAR]);
+
+
+ } break; // screen texture sampler (takes UV) (only usable in fragment case Shader)
+
+ case ShaderGraph::NODE_OUTPUT: {
+ gn->set_title("Output");
+ gn->set_show_close_button(false);
+
+ List<ShaderGraph::SlotInfo> si;
+ ShaderGraph::get_input_output_node_slot_info(graph->get_mode(),type,&si);
+
+ Array colors;
+ colors.push_back("Color");
+ colors.push_back("LightColor");
+ colors.push_back("Light");
+ colors.push_back("Diffuse");
+ colors.push_back("Specular");
+ colors.push_back("Emmision");
+ Array reals;
+ reals.push_back("Alpha");
+ reals.push_back("DiffuseAlpha");
+ reals.push_back("NormalMapDepth");
+ reals.push_back("SpecExp");
+ reals.push_back("Glow");
+ reals.push_back("ShadeParam");
+ reals.push_back("SpecularExp");
+ reals.push_back("LightAlpha");
+ reals.push_back("PointSize");
+ reals.push_back("Discard");
+
+ int idx=0;
+ for (List<ShaderGraph::SlotInfo>::Element *E=si.front();E;E=E->next()) {
+ ShaderGraph::SlotInfo& s=E->get();
+ if (s.dir==ShaderGraph::SLOT_OUT) {
+ Variant::Type v;
+ if (colors.find(s.name)>=0)
+ v=Variant::COLOR;
+ else if (reals.find(s.name)>=0)
+ v=Variant::REAL;
+ else
+ v=Variant::VECTOR3;
+ gn->add_child(make_label(s.name, v));
+ gn->set_slot(idx,true,s.type,typecol[s.type],false,0,Color());
+ idx++;
}
+ }
- } break; // output (case Shader type dependent)
- case ShaderGraph::NODE_COMMENT: {
- gn->set_title("Comment");
- TextEdit *te = memnew(TextEdit);
- te->set_custom_minimum_size(Size2(100,100));
- gn->add_child(te);
- te->set_text(graph->comment_node_get_text(type,p_id));
- te->connect("text_changed",this,"_comment_edited",varray(p_id,te));
+ } break; // output (case Shader type dependent)
+ case ShaderGraph::NODE_COMMENT: {
+ gn->set_title("Comment");
+ TextEdit *te = memnew(TextEdit);
+ te->set_custom_minimum_size(Size2(100,100));
+ gn->add_child(te);
+ te->set_text(graph->comment_node_get_text(type,p_id));
+ te->connect("text_changed",this,"_comment_edited",varray(p_id,te));
- } break; // comment
+ } break; // comment
@@ -2076,8 +2504,6 @@ void ShaderGraphView::_update_graph() {
graph_edit->connect_node(node_map[E->get().src_id]->get_name(),E->get().src_slot,node_map[E->get().dst_id]->get_name(),E->get().dst_slot);
}
-
-
}
void ShaderGraphView::_sg_updated() {
@@ -2085,9 +2511,9 @@ void ShaderGraphView::_sg_updated() {
if (!graph.is_valid())
return;
switch(graph->get_graph_error(type)) {
- case ShaderGraph::GRAPH_OK: status->set_text(""); break;
- case ShaderGraph::GRAPH_ERROR_CYCLIC: status->set_text("Error: Cyclic Connection Link"); break;
- case ShaderGraph::GRAPH_ERROR_MISSING_CONNECTIONS: status->set_text("Error: Missing Input Connections"); break;
+ case ShaderGraph::GRAPH_OK: status->set_text(""); break;
+ case ShaderGraph::GRAPH_ERROR_CYCLIC: status->set_text("Error: Cyclic Connection Link"); break;
+ case ShaderGraph::GRAPH_ERROR_MISSING_CONNECTIONS: status->set_text("Error: Missing Input Connections"); break;
}
}
@@ -2112,9 +2538,12 @@ void ShaderGraphView::_notification(int p_what) {
ped_popup->connect("variant_changed",this,"_variant_edited");
}
- }
+}
-void ShaderGraphView::add_node(int p_type) {
+void ShaderGraphView::add_node(int p_type, const Vector2 &location) {
+
+ if (p_type==ShaderGraph::NODE_INPUT && graph->node_count(type, p_type)>0)
+ return;
List<int> existing;
graph->get_node_list(type,&existing);
@@ -2127,7 +2556,7 @@ void ShaderGraphView::add_node(int p_type) {
}
}
- Vector2 init_ofs(20,20);
+ Vector2 init_ofs = location;
while(true) {
bool valid=true;
for(List<int>::Element *E=existing.front();E;E=E->next()) {
@@ -2157,12 +2586,18 @@ void ShaderGraphView::add_node(int p_type) {
void ShaderGraphView::_bind_methods() {
ObjectTypeDB::bind_method("_update_graph",&ShaderGraphView::_update_graph);
+ ObjectTypeDB::bind_method("_begin_node_move", &ShaderGraphView::_begin_node_move);
ObjectTypeDB::bind_method("_node_moved",&ShaderGraphView::_node_moved);
+ ObjectTypeDB::bind_method("_end_node_move", &ShaderGraphView::_end_node_move);
ObjectTypeDB::bind_method("_move_node",&ShaderGraphView::_move_node);
ObjectTypeDB::bind_method("_node_removed",&ShaderGraphView::_node_removed);
ObjectTypeDB::bind_method("_connection_request",&ShaderGraphView::_connection_request);
ObjectTypeDB::bind_method("_disconnection_request",&ShaderGraphView::_disconnection_request);
+ ObjectTypeDB::bind_method("_duplicate_nodes_request", &ShaderGraphView::_duplicate_nodes_request);
+ ObjectTypeDB::bind_method("_duplicate_nodes", &ShaderGraphView::_duplicate_nodes);
+ ObjectTypeDB::bind_method("_delete_nodes_request", &ShaderGraphView::_delete_nodes_request);
+ ObjectTypeDB::bind_method("_default_changed",&ShaderGraphView::_default_changed);
ObjectTypeDB::bind_method("_scalar_const_changed",&ShaderGraphView::_scalar_const_changed);
ObjectTypeDB::bind_method("_vec_const_changed",&ShaderGraphView::_vec_const_changed);
ObjectTypeDB::bind_method("_rgb_const_changed",&ShaderGraphView::_rgb_const_changed);
@@ -2200,6 +2635,8 @@ ShaderGraphView::ShaderGraphView(ShaderGraph::ShaderType p_type) {
graph_edit->add_child(ped_popup);
status = memnew( Label );
graph_edit->get_top_layer()->add_child(status);
+ graph_edit->connect("_begin_node_move", this, "_begin_node_move");
+ graph_edit->connect("_end_node_move", this, "_end_node_move");
status->set_pos(Vector2(5,5));
status->add_color_override("font_color_shadow",Color(0,0,0));
status->add_color_override("font_color",Color(1,0.4,0.3));
@@ -2221,10 +2658,19 @@ void ShaderGraphEditor::edit(Ref<ShaderGraph> p_shader) {
void ShaderGraphEditor::_add_node(int p_type) {
ShaderGraph::ShaderType shader_type=ShaderGraph::ShaderType(tabs->get_current_tab());
-
- graph_edits[shader_type]->add_node(p_type);
+ graph_edits[shader_type]->add_node(p_type, next_location);
}
+void ShaderGraphEditor::_popup_requested(const Vector2 &p_position)
+{
+ Vector2 scroll_ofs=graph_edits[tabs->get_current_tab()]->get_graph_edit()->get_scroll_ofs();
+ next_location = get_local_mouse_pos() + scroll_ofs;
+ popup->set_global_pos(p_position);
+ popup->set_size( Size2( 200, 0) );
+ popup->popup();
+ popup->call_deferred("grab_click_focus");
+ popup->set_invalidate_click_until_motion();
+}
void ShaderGraphEditor::_notification(int p_what) {
if (p_what==NOTIFICATION_ENTER_TREE) {
@@ -2243,11 +2689,11 @@ void ShaderGraphEditor::_notification(int p_what) {
if (nn.ends_with(":")) {
addsep=true;
}
- menu->get_popup()->add_icon_item(get_icon(ic,"EditorIcons"),v,i);
+ popup->add_icon_item(get_icon(ic,"EditorIcons"),v,i);
if (addsep)
- menu->get_popup()->add_separator();
+ popup->add_separator();
}
- menu->get_popup()->connect("item_pressed",this,"_add_node");
+ popup->connect("item_pressed",this,"_add_node");
}
@@ -2256,7 +2702,7 @@ void ShaderGraphEditor::_notification(int p_what) {
void ShaderGraphEditor::_bind_methods() {
ObjectTypeDB::bind_method("_add_node",&ShaderGraphEditor::_add_node);
-
+ ObjectTypeDB::bind_method("_popup_requested",&ShaderGraphEditor::_popup_requested);
}
@@ -2285,16 +2731,16 @@ const char* ShaderGraphEditor::node_names[ShaderGraph::NODE_TYPE_MAX]={
"GraphVecsToXform:Vectors -> XForm:", // 3 vec input", 1 xform output
"GraphScalarInterp:Scalar Interpolate", // scalar interpolation (with optional curve)
"GraphVecInterp:Vector Interpolate:", // vec3 interpolation (with optional curve)
- "GraphColorRamp:Color Ramp", // vec3 interpolation (with optional curve)
- "GraphCurveMap:Curve Remap:", // vec3 interpolation (with optional curve)
- "GraphScalarUniform:Scalar Uniform", // scalar uniform (assignable in material)
+ "GraphColorRamp:Color Ramp", // vec3 interpolation (with optional curve)
+ "GraphCurveMap:Curve Remap:", // vec3 interpolation (with optional curve)
+ "GraphScalarUniform:Scalar Uniform", // scalar uniform (assignable in material)
"GraphVectorUniform:Vector Uniform", // vec3 uniform (assignable in material)
"GraphRgbUniform:RGB Uniform", // color uniform (assignable in material)
"GraphXformUniform:XForm Uniform", // mat4 uniform (assignable in material)
"GraphTextureUniform:Texture Uniform", // texture input (assignable in material)
"GraphCubeUniform:CubeMap Uniform:", // cubemap input (assignable in material)
- "GraphDefaultTexture:CanvasItem Texture:", // cubemap input (assignable in material)
- "Output", // output (shader type dependent)
+ "GraphDefaultTexture:CanvasItem Texture:", // cubemap input (assignable in material)
+ "Output", // output (shader type dependent)
"GraphComment:Comment", // comment
@@ -2302,11 +2748,8 @@ const char* ShaderGraphEditor::node_names[ShaderGraph::NODE_TYPE_MAX]={
ShaderGraphEditor::ShaderGraphEditor(bool p_2d) {
_2d=p_2d;
- HBoxContainer *hbc = memnew( HBoxContainer );
- menu = memnew( MenuButton );
- menu->set_text("Add Node..");
- hbc->add_child(menu);
- add_child(hbc);
+ popup = memnew( PopupMenu );
+ add_child(popup);
tabs = memnew(TabContainer);
@@ -2325,8 +2768,10 @@ ShaderGraphEditor::ShaderGraphEditor(bool p_2d) {
tabs->add_child(graph_edits[i]->get_graph_edit());
graph_edits[i]->get_graph_edit()->connect("connection_request",graph_edits[i],"_connection_request");
graph_edits[i]->get_graph_edit()->connect("disconnection_request",graph_edits[i],"_disconnection_request");
+ graph_edits[i]->get_graph_edit()->connect("duplicate_nodes_request", graph_edits[i], "_duplicate_nodes_request");
+ graph_edits[i]->get_graph_edit()->connect("popup_request",this,"_popup_requested");
+ graph_edits[i]->get_graph_edit()->connect("delete_nodes_request",graph_edits[i],"_delete_nodes_request");
graph_edits[i]->get_graph_edit()->set_right_disconnects(true);
-
}
tabs->set_current_tab(1);
@@ -2374,9 +2819,9 @@ ShaderGraphEditorPlugin::ShaderGraphEditorPlugin(EditorNode *p_node, bool p_2d)
SpatialEditor::get_singleton()->get_shader_split()->add_child(shader_editor);
-// editor->get_viewport()->add_child(shader_editor);
-// shader_editor->set_area_as_parent_rect();
-// shader_editor->hide();
+ // editor->get_viewport()->add_child(shader_editor);
+ // shader_editor->set_area_as_parent_rect();
+ // shader_editor->hide();
}
diff --git a/tools/editor/plugins/shader_graph_editor_plugin.h b/tools/editor/plugins/shader_graph_editor_plugin.h
index 0051fbfd74..0336696911 100644
--- a/tools/editor/plugins/shader_graph_editor_plugin.h
+++ b/tools/editor/plugins/shader_graph_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -129,6 +129,7 @@ class ShaderGraphView : public Node {
GraphEdit *graph_edit;
Ref<ShaderGraph> graph;
int edited_id;
+ int edited_def;
ShaderGraph::ShaderType type;
@@ -136,13 +137,23 @@ class ShaderGraphView : public Node {
void _create_node(int p_id);
+ ToolButton *make_label(String text, Variant::Type v_type = Variant::NIL);
+ ToolButton *make_editor(String text, GraphNode* gn, int p_id, int param, Variant::Type type, String p_hint="");
void _connection_request(const String& p_from, int p_from_slot,const String& p_to,int p_to_slot);
void _disconnection_request(const String& p_from, int p_from_slot,const String& p_to,int p_to_slot);
void _node_removed(int p_id);
+ void _begin_node_move();
void _node_moved(const Vector2& p_from, const Vector2& p_to,int p_id);
+ void _end_node_move();
void _move_node(int p_id,const Vector2& p_to);
+ void _duplicate_nodes_request();
+ void _duplicate_nodes(const Array &p_nodes);
+ void _delete_nodes_request();
+
+
+ void _default_changed(int p_id, Node* p_button, int p_param, int v_type, String p_hint);
void _scalar_const_changed(double p_value,int p_id);
void _vec_const_changed(double p_value, int p_id, Array p_arr);
@@ -175,7 +186,7 @@ protected:
static void _bind_methods();
public:
- void add_node(int p_type);
+ void add_node(int p_type, const Vector2 &location);
GraphEdit *get_graph_edit() { return graph_edit; }
void set_graph(Ref<ShaderGraph> p_graph);
@@ -186,13 +197,15 @@ class ShaderGraphEditor : public VBoxContainer {
OBJ_TYPE(ShaderGraphEditor,VBoxContainer);
- MenuButton *menu;
+ PopupMenu *popup;
TabContainer *tabs;
ShaderGraphView *graph_edits[ShaderGraph::SHADER_TYPE_MAX];
static const char* node_names[ShaderGraph::NODE_TYPE_MAX];
+ Vector2 next_location;
bool _2d;
void _add_node(int p_type);
+ void _popup_requested(const Vector2 &p_position);
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/tools/editor/plugins/spatial_editor_plugin.cpp b/tools/editor/plugins/spatial_editor_plugin.cpp
index 77663f39c0..236d69dfb3 100644
--- a/tools/editor/plugins/spatial_editor_plugin.cpp
+++ b/tools/editor/plugins/spatial_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -39,6 +39,9 @@
#include "scene/resources/surface_tool.h"
#include "tools/editor/spatial_editor_gizmos.h"
#include "globals.h"
+#include "tools/editor/plugins/animation_player_editor_plugin.h"
+#include "tools/editor/animation_editor.h"
+
#define DISTANCE_DEFAULT 4
@@ -232,15 +235,6 @@ void SpatialEditorViewport::_select(Spatial *p_node, bool p_append,bool p_single
}
-
-struct _RayResult {
-
- Spatial* item;
- float depth;
- int handle;
- _FORCE_INLINE_ bool operator<(const _RayResult& p_rr) const { return depth<p_rr.depth; }
-};
-
ObjectID SpatialEditorViewport::_select_ray(const Point2& p_pos, bool p_append,bool &r_includes_current,int *r_gizmo_handle,bool p_alt_select) {
if (r_gizmo_handle)
@@ -379,6 +373,70 @@ ObjectID SpatialEditorViewport::_select_ray(const Point2& p_pos, bool p_append,b
}
+void SpatialEditorViewport::_find_items_at_pos(const Point2& p_pos,bool &r_includes_current,Vector<_RayResult> &results,bool p_alt_select) {
+
+ Vector3 ray=_get_ray(p_pos);
+ Vector3 pos=_get_ray_pos(p_pos);
+
+ Vector<RID> instances=VisualServer::get_singleton()->instances_cull_ray(pos,ray,get_tree()->get_root()->get_world()->get_scenario() );
+ Set<Ref<SpatialEditorGizmo> > found_gizmos;
+
+ r_includes_current=false;
+
+ for (int i=0;i<instances.size();i++) {
+
+ uint32_t id=VisualServer::get_singleton()->instance_get_object_instance_ID(instances[i]);
+ Object *obj=ObjectDB::get_instance(id);
+ if (!obj)
+ continue;
+
+ Spatial *spat=obj->cast_to<Spatial>();
+
+ if (!spat)
+ continue;
+
+ Ref<SpatialEditorGizmo> seg = spat->get_gizmo();
+
+ if (!seg.is_valid())
+ continue;
+
+ if (found_gizmos.has(seg))
+ continue;
+
+ found_gizmos.insert(seg);
+ Vector3 point;
+ Vector3 normal;
+
+ int handle=-1;
+ bool inters = seg->intersect_ray(camera,p_pos,point,normal,NULL,p_alt_select);
+
+ if (!inters)
+ continue;
+
+ float dist = pos.distance_to(point);
+
+ if (dist<0)
+ continue;
+
+
+
+ if (editor_selection->is_selected(spat))
+ r_includes_current=true;
+
+ _RayResult res;
+ res.item=spat;
+ res.depth=dist;
+ res.handle=handle;
+ results.push_back(res);
+ }
+
+
+ if (results.empty())
+ return;
+
+ results.sort();
+}
+
Vector3 SpatialEditorViewport::_get_screen_to_space(const Vector3& p_pos) {
@@ -677,9 +735,72 @@ bool SpatialEditorViewport::_gizmo_select(const Vector2& p_screenpos,bool p_hili
void SpatialEditorViewport::_smouseenter() {
- surface->grab_focus();
+ if (!surface->has_focus() && (!get_focus_owner() || !get_focus_owner()->is_text_field()))
+ surface->grab_focus();
}
+void SpatialEditorViewport::_list_select(InputEventMouseButton b) {
+
+ _find_items_at_pos(Vector2( b.x, b.y ),clicked_includes_current,selection_results,b.mod.shift);
+
+ Node *scene=editor->get_edited_scene();
+
+ for(int i=0;i<selection_results.size();i++) {
+ Spatial *item=selection_results[i].item;
+ if (item!=scene && item->get_owner()!=scene && !scene->is_editable_instance(item->get_owner())) {
+ //invalid result
+ selection_results.remove(i);
+ i--;
+ }
+
+ }
+
+
+ clicked_wants_append=b.mod.shift;
+
+ if (selection_results.size() == 1) {
+
+ clicked=selection_results[0].item->get_instance_ID();
+ selection_results.clear();
+
+ if (clicked) {
+ _select_clicked(clicked_wants_append,true);
+ clicked=0;
+ }
+
+ } else if (!selection_results.empty()) {
+
+ NodePath root_path = get_tree()->get_edited_scene_root()->get_path();
+ StringName root_name = root_path.get_name(root_path.get_name_count()-1);
+
+ for (int i = 0; i < selection_results.size(); i++) {
+
+ Spatial *spat=selection_results[i].item;
+
+ Ref<Texture> icon;
+ if (spat->has_meta("_editor_icon"))
+ icon=spat->get_meta("_editor_icon");
+ else
+ icon=get_icon( has_icon(spat->get_type(),"EditorIcons")?spat->get_type():String("Object"),"EditorIcons");
+
+ String node_path="/"+root_name+"/"+root_path.rel_path_to(spat->get_path());
+
+ selection_menu->add_item(spat->get_name());
+ selection_menu->set_item_icon(i, icon );
+ selection_menu->set_item_metadata(i, node_path);
+ selection_menu->set_item_tooltip(i,String(spat->get_name())+
+ "\nType: "+spat->get_type()+"\nPath: "+node_path);
+ }
+
+ selection_menu->set_global_pos(Vector2( b.global_x, b.global_y ));
+ selection_menu->popup();
+ selection_menu->call_deferred("grab_click_focus");
+ selection_menu->set_invalidate_click_until_motion();
+
+
+
+ }
+}
void SpatialEditorViewport::_sinput(const InputEvent &p_event) {
if (previewing)
@@ -723,6 +844,7 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) {
} break;
case BUTTON_RIGHT: {
+ NavigationScheme nav_scheme = _get_navigation_schema("3d_editor/navigation_scheme");
if (b.pressed && _edit.gizmo.is_valid()) {
//restore
@@ -805,6 +927,16 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) {
//VisualServer::get_singleton()->instance_set_transform(cursor_instance,Transform(Matrix3(),cursor.cursor_pos));
}
}
+
+ if (b.mod.alt) {
+
+ if (nav_scheme == NAVIGATION_MAYA)
+ break;
+
+ _list_select(b);
+ return;
+
+ }
}
if (_edit.mode!=TRANSFORM_NONE && b.pressed) {
@@ -876,6 +1008,11 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) {
break;
}
+ if (spatial_editor->get_tool_mode()==SpatialEditor::TOOL_MODE_LIST_SELECT) {
+ _list_select(b);
+ break;
+ }
+
_edit.mouse_pos=Point2(b.x,b.y);
_edit.snap=false;
_edit.mode=TRANSFORM_NONE;
@@ -1483,6 +1620,8 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) {
case InputEvent::KEY: {
const InputEventKey &k = p_event.key;
+ if (!k.pressed)
+ break;
switch(k.scancode) {
case KEY_S: {
@@ -1543,7 +1682,8 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) {
} break;
case KEY_KP_5: {
- orthogonal = !orthogonal;
+
+ //orthogonal = !orthogonal;
_menu_option(orthogonal?VIEW_PERSPECTIVE:VIEW_ORTHOGONAL);
_update_name();
@@ -1554,7 +1694,7 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) {
if (!get_selected_count() || _edit.mode!=TRANSFORM_NONE)
break;
- if (!editor->get_animation_editor()->has_keying()) {
+ if (!AnimationPlayerEditor::singleton->get_key_editor()->has_keying()) {
set_message("Keying is disabled (no key inserted).");
break;
}
@@ -1956,11 +2096,11 @@ void SpatialEditorViewport::_menu_option(int p_option) {
if (!se)
continue;
- Vector3 original_scale = sp->get_scale();
- sp->set_global_transform(camera_transform);
- sp->set_scale(original_scale);
- undo_redo->add_do_method(sp,"set_global_transform",sp->get_global_transform());
- undo_redo->add_undo_method(sp,"set_global_transform",se->original);
+ Transform xform = camera_transform;
+ xform.scale_basis(sp->get_scale());
+
+ undo_redo->add_do_method(sp,"set_global_transform",xform);
+ undo_redo->add_undo_method(sp,"set_global_transform",sp->get_global_transform());
}
undo_redo->commit_action();
} break;
@@ -2095,6 +2235,26 @@ void SpatialEditorViewport::_toggle_camera_preview(bool p_activate) {
}
}
+void SpatialEditorViewport::_selection_result_pressed(int p_result) {
+
+ if (selection_results.size() <= p_result)
+ return;
+
+ clicked=selection_results[p_result].item->get_instance_ID();
+
+ if (clicked) {
+ _select_clicked(clicked_wants_append,true);
+ clicked=0;
+ }
+}
+
+void SpatialEditorViewport::_selection_menu_hide() {
+
+ selection_results.clear();
+ selection_menu->clear();
+ selection_menu->set_size(Vector2(0, 0));
+}
+
void SpatialEditorViewport::set_can_preview(Camera* p_preview) {
preview=p_preview;
@@ -2168,7 +2328,18 @@ void SpatialEditorViewport::set_state(const Dictionary& p_state) {
view_menu->get_popup()->set_item_checked( idx, listener );
}
-
+ if (p_state.has("previewing")) {
+ Node *pv = EditorNode::get_singleton()->get_edited_scene()->get_node(p_state["previewing"]);
+ if (pv && pv->cast_to<Camera>()) {
+ previewing=pv->cast_to<Camera>();
+ previewing->connect("exit_tree",this,"_preview_exited_scene");
+ VS::get_singleton()->viewport_attach_camera( viewport->get_viewport(), previewing->get_camera() ); //replace
+ view_menu->hide();
+ surface->update();
+ preview_camera->set_pressed(true);
+ preview_camera->show();
+ }
+ }
}
Dictionary SpatialEditorViewport::get_state() const {
@@ -2181,6 +2352,10 @@ Dictionary SpatialEditorViewport::get_state() const {
d["use_environment"]=camera->get_environment().is_valid();
d["use_orthogonal"]=camera->get_projection()==Camera::PROJECTION_ORTHOGONAL;
d["listener"]=viewport->is_audio_listener();
+ if (previewing) {
+ d["previewing"]=EditorNode::get_singleton()->get_edited_scene()->get_path_to(previewing);
+ }
+
return d;
}
@@ -2194,6 +2369,8 @@ void SpatialEditorViewport::_bind_methods(){
ObjectTypeDB::bind_method(_MD("_toggle_camera_preview"),&SpatialEditorViewport::_toggle_camera_preview);
ObjectTypeDB::bind_method(_MD("_preview_exited_scene"),&SpatialEditorViewport::_preview_exited_scene);
ObjectTypeDB::bind_method(_MD("update_transform_gizmo_view"),&SpatialEditorViewport::update_transform_gizmo_view);
+ ObjectTypeDB::bind_method(_MD("_selection_result_pressed"),&SpatialEditorViewport::_selection_result_pressed);
+ ObjectTypeDB::bind_method(_MD("_selection_menu_hide"),&SpatialEditorViewport::_selection_menu_hide);
ADD_SIGNAL( MethodInfo("toggle_maximize_view", PropertyInfo(Variant::OBJECT, "viewport")) );
}
@@ -2238,6 +2415,7 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
add_child(c);
c->set_area_as_parent_rect();
viewport = memnew( Viewport );
+ viewport->set_disable_input(true);
c->add_child(viewport);
surface = memnew( Control );
add_child(surface);
@@ -2291,6 +2469,12 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed
preview=NULL;
gizmo_scale=1.0;
+ selection_menu = memnew( PopupMenu );
+ add_child(selection_menu);
+ selection_menu->set_custom_minimum_size(Vector2(100, 0));
+ selection_menu->connect("item_pressed", this, "_selection_result_pressed");
+ selection_menu->connect("popup_hide", this, "_selection_menu_hide");
+
if (p_index==0) {
view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_AUDIO_LISTENER),true);
viewport->set_as_audio_listener(true);
@@ -2449,6 +2633,13 @@ Dictionary SpatialEditor::get_state() const {
Dictionary d;
+ d["snap_enabled"]=snap_enabled;
+ d["translate_snap"]=get_translate_snap();
+ d["rotate_snap"]=get_rotate_snap();
+ d["scale_snap"]=get_scale_snap();
+
+ int local_coords_index=transform_menu->get_popup()->get_item_index(MENU_TRANSFORM_LOCAL_COORDS);
+ d["local_coords"]=transform_menu->get_popup()->is_item_checked( local_coords_index );
int vc=0;
if (view_menu->get_popup()->is_item_checked( view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT) ))
@@ -2490,37 +2681,52 @@ void SpatialEditor::set_state(const Dictionary& p_state) {
Dictionary d = p_state;
- ERR_FAIL_COND(!d.has("viewport_mode"));
- ERR_FAIL_COND(!d.has("viewports"));
- ERR_FAIL_COND(!d.has("default_light"));
- ERR_FAIL_COND(!d.has("show_grid"));
- ERR_FAIL_COND(!d.has("show_origin"));
- ERR_FAIL_COND(!d.has("fov"));
- ERR_FAIL_COND(!d.has("znear"));
- ERR_FAIL_COND(!d.has("zfar"));
+ if (d.has("snap_enabled")) {
+ snap_enabled=d["snap_enabled"];
+ int snap_enabled_idx=transform_menu->get_popup()->get_item_index(MENU_TRANSFORM_USE_SNAP);
+ transform_menu->get_popup()->set_item_checked( snap_enabled_idx, snap_enabled );
+ }
- int vc = d["viewport_mode"];
+ if (d.has("translate_snap"))
+ snap_translate->set_text(d["translate_snap"]);
- if (vc==1)
- _menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT);
- else if (vc==2)
- _menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS);
- else if (vc==3)
- _menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS);
- else if (vc==4)
- _menu_item_pressed(MENU_VIEW_USE_4_VIEWPORTS);
- else if (vc==5)
- _menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS_ALT);
- else if (vc==6)
- _menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS_ALT);
-
- Array vp = d["viewports"];
- ERR_FAIL_COND(vp.size()>4);
+ if (d.has("rotate_snap"))
+ snap_rotate->set_text(d["rotate_snap"]);
- for(int i=0;i<4;i++) {
- viewports[i]->set_state(vp[i]);
+ if (d.has("scale_snap"))
+ snap_scale->set_text(d["scale_snap"]);
+
+ if (d.has("local_coords")) {
+ int local_coords_idx=transform_menu->get_popup()->get_item_index(MENU_TRANSFORM_LOCAL_COORDS);
+ transform_menu->get_popup()->set_item_checked( local_coords_idx, d["local_coords"] );
+ update_transform_gizmo();
}
+ if (d.has("viewport_mode")) {
+ int vc = d["viewport_mode"];
+
+ if (vc==1)
+ _menu_item_pressed(MENU_VIEW_USE_1_VIEWPORT);
+ else if (vc==2)
+ _menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS);
+ else if (vc==3)
+ _menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS);
+ else if (vc==4)
+ _menu_item_pressed(MENU_VIEW_USE_4_VIEWPORTS);
+ else if (vc==5)
+ _menu_item_pressed(MENU_VIEW_USE_2_VIEWPORTS_ALT);
+ else if (vc==6)
+ _menu_item_pressed(MENU_VIEW_USE_3_VIEWPORTS_ALT);
+ }
+
+ if (d.has("viewports")) {
+ Array vp = d["viewports"];
+ ERR_FAIL_COND(vp.size()>4);
+
+ for(int i=0;i<4;i++) {
+ viewports[i]->set_state(vp[i]);
+ }
+ }
if (d.has("zfar"))
settings_zfar->set_val(float(d["zfar"]));
@@ -2690,13 +2896,14 @@ void SpatialEditor::_menu_item_pressed(int p_option) {
case MENU_TOOL_SELECT:
case MENU_TOOL_MOVE:
case MENU_TOOL_ROTATE:
- case MENU_TOOL_SCALE: {
+ case MENU_TOOL_SCALE:
+ case MENU_TOOL_LIST_SELECT: {
- for(int i=0;i<4;i++)
+ for(int i=0;i<TOOL_MAX;i++)
tool_button[i]->set_pressed(i==p_option);
tool_mode=(ToolMode)p_option;
- static const char *_mode[]={"Selection Mode.","Translation Mode.","Rotation Mode.","Scale Mode."};
+ static const char *_mode[]={"Selection Mode.","Translation Mode.","Rotation Mode.","Scale Mode.","List Selection Mode."};
// set_message(_mode[p_option],3);
update_transform_gizmo();
@@ -2709,7 +2916,7 @@ void SpatialEditor::_menu_item_pressed(int p_option) {
} break;
case MENU_TRANSFORM_CONFIGURE_SNAP: {
- snap_dialog->popup_centered(Size2(200,160));
+ snap_dialog->popup_centered(Size2(200,180));
} break;
case MENU_TRANSFORM_LOCAL_COORDS: {
@@ -3323,19 +3530,13 @@ void SpatialEditor::_instance_scene() {
undo_redo->commit_action();
#endif
}
-/*
-void SpatialEditor::_update_selection() {
-
-
-}
-*/
void SpatialEditor::_unhandled_key_input(InputEvent p_event) {
- if (!is_visible())
+ if (!is_visible() || get_viewport()->gui_has_modal_stack())
return;
- {
+ {
EditorNode *en = editor;
EditorPlugin *over_plugin = en->get_editor_plugin_over();
@@ -3379,6 +3580,7 @@ void SpatialEditor::_notification(int p_what) {
tool_button[SpatialEditor::TOOL_MODE_MOVE]->set_icon( get_icon("ToolMove","EditorIcons") );
tool_button[SpatialEditor::TOOL_MODE_ROTATE]->set_icon( get_icon("ToolRotate","EditorIcons") );
tool_button[SpatialEditor::TOOL_MODE_SCALE]->set_icon( get_icon("ToolScale","EditorIcons") );
+ tool_button[SpatialEditor::TOOL_MODE_LIST_SELECT]->set_icon( get_icon("ListSelect","EditorIcons") );
instance_button->set_icon( get_icon("SpatialAdd","EditorIcons") );
instance_button->hide();
@@ -3533,7 +3735,6 @@ void SpatialEditor::_bind_methods() {
ObjectTypeDB::bind_method("_menu_item_pressed",&SpatialEditor::_menu_item_pressed);
ObjectTypeDB::bind_method("_xform_dialog_action",&SpatialEditor::_xform_dialog_action);
ObjectTypeDB::bind_method("_instance_scene",&SpatialEditor::_instance_scene);
-// ObjectTypeDB::bind_method("_update_selection",&SpatialEditor::_update_selection);
ObjectTypeDB::bind_method("_get_editor_data",&SpatialEditor::_get_editor_data);
ObjectTypeDB::bind_method("_request_gizmo",&SpatialEditor::_request_gizmo);
ObjectTypeDB::bind_method("_default_light_angle_input",&SpatialEditor::_default_light_angle_input);
@@ -3635,7 +3836,6 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
editor=p_editor;
editor_selection=editor->get_editor_selection();
editor_selection->add_editor_plugin(this);
- editor_selection->connect("selection_changed",this,"_update_selection");
snap_enabled=false;
tool_mode = TOOL_MODE_SELECT;
@@ -3656,7 +3856,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
tool_button[TOOL_MODE_SELECT]->set_pressed(true);
button_binds[0]=MENU_TOOL_SELECT;
tool_button[TOOL_MODE_SELECT]->connect("pressed", this,"_menu_item_pressed",button_binds);
- tool_button[TOOL_MODE_SELECT]->set_tooltip("Select Mode (Q)");
+ tool_button[TOOL_MODE_SELECT]->set_tooltip("Select Mode (Q)\n"+keycode_get_string(KEY_MASK_CMD)+"Drag: Rotate\nAlt+Drag: Move\nAlt+RMB: Depth list selection");
tool_button[TOOL_MODE_MOVE] = memnew( ToolButton );
@@ -3688,10 +3888,22 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
hbc_menu->add_child( instance_button );
instance_button->set_flat(true);
instance_button->connect("pressed",this,"_instance_scene");
+ instance_button->hide();
VSeparator *vs = memnew( VSeparator );
hbc_menu->add_child(vs);
+ tool_button[TOOL_MODE_LIST_SELECT] = memnew( ToolButton );
+ hbc_menu->add_child( tool_button[TOOL_MODE_LIST_SELECT] );
+ tool_button[TOOL_MODE_LIST_SELECT]->set_toggle_mode(true);
+ tool_button[TOOL_MODE_LIST_SELECT]->set_flat(true);
+ button_binds[0]=MENU_TOOL_LIST_SELECT;
+ tool_button[TOOL_MODE_LIST_SELECT]->connect("pressed", this,"_menu_item_pressed",button_binds);
+ tool_button[TOOL_MODE_LIST_SELECT]->set_tooltip("Show a list of all objects at the position clicked\n(same as Alt+RMB in selet mode).");
+
+ vs = memnew( VSeparator );
+ hbc_menu->add_child(vs);
+
PopupMenu *p;
@@ -3777,46 +3989,24 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
snap_dialog = memnew( ConfirmationDialog );
snap_dialog->set_title("Snap Settings");
add_child(snap_dialog);
- Label *l = memnew(Label);
- l->set_text("Translate Snap:");
- l->set_pos(Point2(5,5));
- snap_dialog->add_child(l);
+
+ VBoxContainer *snap_dialog_vbc = memnew( VBoxContainer );
+ snap_dialog->add_child(snap_dialog_vbc);
+ snap_dialog->set_child_rect(snap_dialog_vbc);
snap_translate = memnew( LineEdit );
- snap_translate->set_anchor( MARGIN_RIGHT, ANCHOR_END );
- snap_translate->set_begin( Point2(15,22) );
- snap_translate->set_end( Point2(15,35) );
snap_translate->set_text("1");
- snap_dialog->add_child(snap_translate);
-
- l = memnew(Label);
- l->set_text("Rotate Snap (deg.):");
- l->set_pos(Point2(5,45));
- snap_dialog->add_child(l);
+ snap_dialog_vbc->add_margin_child("Translate Snap:",snap_translate);
snap_rotate = memnew( LineEdit );
- snap_rotate->set_anchor( MARGIN_RIGHT, ANCHOR_END );
- snap_rotate->set_begin( Point2(15,62) );
- snap_rotate->set_end( Point2(15,75) );
snap_rotate->set_text("5");
- snap_dialog->add_child(snap_rotate);
-
-
- l = memnew(Label);
- l->set_text("Scale Snap (%):");
- l->set_pos(Point2(5,85));
- snap_dialog->add_child(l);
+ snap_dialog_vbc->add_margin_child("Rotate Snap (deg.):",snap_rotate);
snap_scale = memnew( LineEdit );
- snap_scale->set_anchor( MARGIN_RIGHT, ANCHOR_END );
- snap_scale->set_begin( Point2(15,102) );
- snap_scale->set_end( Point2(15,115) );
snap_scale->set_text("5");
- snap_dialog->add_child(snap_scale);
-
- //snap_dialog->get_cancel()->hide();
+ snap_dialog_vbc->add_margin_child("Scale Snap (%):",snap_scale);
- /* SNAP DIALOG */
+ /* SETTINGS DIALOG */
settings_dialog = memnew( ConfirmationDialog );
settings_dialog->set_title("Viewport Settings");
@@ -3833,6 +4023,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
settings_light_base->connect("input_event",this,"_default_light_angle_input");
settings_vbc->add_margin_child("Default Light Normal:",settings_light_base);
settings_light_vp = memnew( Viewport );
+ settings_light_vp->set_disable_input(true);
settings_light_vp->set_use_own_world(true);
settings_light_base->add_child(settings_light_vp);
@@ -3890,7 +4081,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) {
xform_dialog = memnew( ConfirmationDialog );
xform_dialog->set_title("Transform Change");
add_child(xform_dialog);
- l = memnew(Label);
+ Label *l = memnew(Label);
l->set_text("Translate:");
l->set_pos(Point2(5,5));
xform_dialog->add_child(l);
diff --git a/tools/editor/plugins/spatial_editor_plugin.h b/tools/editor/plugins/spatial_editor_plugin.h
index ff8912fca8..b0e366b140 100644
--- a/tools/editor/plugins/spatial_editor_plugin.h
+++ b/tools/editor/plugins/spatial_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -111,12 +111,21 @@ private:
bool orthogonal;
float gizmo_scale;
+ struct _RayResult {
+
+ Spatial* item;
+ float depth;
+ int handle;
+ _FORCE_INLINE_ bool operator<(const _RayResult& p_rr) const { return depth<p_rr.depth; }
+ };
+
void _update_name();
void _compute_edit(const Point2& p_point);
void _clear_selected();
void _select_clicked(bool p_append,bool p_single);
void _select(Spatial *p_node, bool p_append,bool p_single);
ObjectID _select_ray(const Point2& p_pos, bool p_append,bool &r_includes_current,int *r_gizmo_handle=NULL,bool p_alt_select=false);
+ void _find_items_at_pos(const Point2& p_pos,bool &r_includes_current,Vector<_RayResult> &results,bool p_alt_select=false);
Vector3 _get_ray_pos(const Vector2& p_pos) const;
Vector3 _get_ray(const Vector2& p_pos);
Point2 _point_to_screen(const Vector3& p_point);
@@ -128,7 +137,6 @@ private:
Vector3 _get_screen_to_space(const Vector3& p_vector3);
void _select_region();
- void _update_selection();
bool _gizmo_select(const Vector2& p_screenpos,bool p_hilite_only=false);
float get_znear() const;
@@ -136,9 +144,12 @@ private:
float get_fov() const;
ObjectID clicked;
+ Vector<_RayResult> selection_results;
bool clicked_includes_current;
bool clicked_wants_append;
+ PopupMenu *selection_menu;
+
enum NavigationScheme {
NAVIGATION_GODOT,
NAVIGATION_MAYA,
@@ -225,6 +236,9 @@ private:
void _toggle_camera_preview(bool);
void _init_gizmo_instance(int p_idx);
void _finish_gizmo_instances();
+ void _selection_result_pressed(int);
+ void _selection_menu_hide();
+ void _list_select(InputEventMouseButton b);
protected:
@@ -273,7 +287,9 @@ public:
TOOL_MODE_SELECT,
TOOL_MODE_MOVE,
TOOL_MODE_ROTATE,
- TOOL_MODE_SCALE
+ TOOL_MODE_SCALE,
+ TOOL_MODE_LIST_SELECT,
+ TOOL_MAX
};
@@ -355,6 +371,7 @@ private:
MENU_TOOL_MOVE,
MENU_TOOL_ROTATE,
MENU_TOOL_SCALE,
+ MENU_TOOL_LIST_SELECT,
MENU_TRANSFORM_USE_SNAP,
MENU_TRANSFORM_CONFIGURE_SNAP,
MENU_TRANSFORM_LOCAL_COORDS,
@@ -378,7 +395,7 @@ private:
};
- Button *tool_button[4];
+ Button *tool_button[TOOL_MAX];
Button *instance_button;
diff --git a/tools/editor/plugins/sprite_frames_editor_plugin.cpp b/tools/editor/plugins/sprite_frames_editor_plugin.cpp
index e90087efda..af73828b61 100644
--- a/tools/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/tools/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -338,7 +338,6 @@ void SpriteFramesEditor::_update_library() {
TreeItem *ti = tree->create_item(root);
ti->set_cell_mode(0,TreeItem::CELL_MODE_STRING);
- ti->set_editable(0,true);
ti->set_selectable(0,true);
if (frames->get_frame(i).is_null()) {
@@ -346,7 +345,7 @@ void SpriteFramesEditor::_update_library() {
ti->set_text(0,"Frame "+itos(i)+" (empty)");
} else {
- ti->set_text(0,"Frame "+itos(i));
+ ti->set_text(0,"Frame "+itos(i)+" ("+frames->get_frame(i)->get_name()+")");
ti->set_icon(0,frames->get_frame(i));
}
if (frames->get_frame(i).is_valid())
@@ -486,11 +485,15 @@ bool SpriteFramesEditorPlugin::handles(Object *p_object) const {
void SpriteFramesEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
- frames_editor->show();
+ button->show();
+ editor->make_bottom_panel_item_visible(frames_editor);
// frames_editor->set_process(true);
} else {
- frames_editor->hide();
+ button->hide();
+ if (frames_editor->is_visible())
+ editor->hide_bottom_panel();
+
// frames_editor->set_process(false);
}
@@ -500,11 +503,9 @@ SpriteFramesEditorPlugin::SpriteFramesEditorPlugin(EditorNode *p_node) {
editor=p_node;
frames_editor = memnew( SpriteFramesEditor );
- editor->get_viewport()->add_child(frames_editor);
- frames_editor->set_area_as_parent_rect();
-// frames_editor->set_anchor( MARGIN_TOP, Control::ANCHOR_END);
-// frames_editor->set_margin( MARGIN_TOP, 120 );
- frames_editor->hide();
+ frames_editor->set_custom_minimum_size(Size2(0,300));
+ button=editor->add_bottom_panel_item("SpriteFrames",frames_editor);
+ button->hide();
diff --git a/tools/editor/plugins/sprite_frames_editor_plugin.h b/tools/editor/plugins/sprite_frames_editor_plugin.h
index 969d7b1ce3..5d0a6cb035 100644
--- a/tools/editor/plugins/sprite_frames_editor_plugin.h
+++ b/tools/editor/plugins/sprite_frames_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -94,6 +94,7 @@ class SpriteFramesEditorPlugin : public EditorPlugin {
SpriteFramesEditor *frames_editor;
EditorNode *editor;
+ Button *button;
public:
diff --git a/tools/editor/plugins/sprite_region_editor_plugin.cpp b/tools/editor/plugins/sprite_region_editor_plugin.cpp
new file mode 100644
index 0000000000..725de19dd7
--- /dev/null
+++ b/tools/editor/plugins/sprite_region_editor_plugin.cpp
@@ -0,0 +1,608 @@
+/*************************************************************************/
+/* sprite_region_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Author: Mariano Suligoy */
+/* */
+/* 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. */
+/*************************************************************************/
+
+#include "sprite_region_editor_plugin.h"
+#include "scene/gui/check_box.h"
+#include "os/input.h"
+#include "os/keyboard.h"
+
+void SpriteRegionEditor::_region_draw()
+{
+ Ref<Texture> base_tex = node->get_texture();
+ if (base_tex.is_null())
+ return;
+
+ Matrix32 mtx;
+ mtx.elements[2]=-draw_ofs;
+ mtx.scale_basis(Vector2(draw_zoom,draw_zoom));
+
+ VS::get_singleton()->canvas_item_set_clip(edit_draw->get_canvas_item(),true);
+ VS::get_singleton()->canvas_item_add_set_transform(edit_draw->get_canvas_item(),mtx);
+ edit_draw->draw_texture(base_tex,Point2());
+ VS::get_singleton()->canvas_item_add_set_transform(edit_draw->get_canvas_item(),Matrix32());
+
+ if (snap_show_grid) {
+ Size2 s = edit_draw->get_size();
+ int last_cell;
+
+ if (snap_step.x!=0) {
+ for(int i=0;i<s.width;i++) {
+ int cell = Math::fast_ftoi(Math::floor((mtx.affine_inverse().xform(Vector2(i,0)).x-snap_offset.x)/snap_step.x));
+ if (i==0)
+ last_cell=cell;
+ if (last_cell!=cell)
+ edit_draw->draw_line(Point2(i,0),Point2(i,s.height),Color(0.3,0.7,1,0.3));
+ last_cell=cell;
+ }
+ }
+
+ if (snap_step.y!=0) {
+ for(int i=0;i<s.height;i++) {
+ int cell = Math::fast_ftoi(Math::floor((mtx.affine_inverse().xform(Vector2(0,i)).y-snap_offset.y)/snap_step.y));
+ if (i==0)
+ last_cell=cell;
+ if (last_cell!=cell)
+ edit_draw->draw_line(Point2(0,i),Point2(s.width,i),Color(0.3,0.7,1,0.3));
+ last_cell=cell;
+ }
+ }
+ }
+
+ Ref<Texture> select_handle = get_icon("EditorHandle","EditorIcons");
+
+ Rect2 scroll_rect(Point2(),mtx.basis_xform(base_tex->get_size()));
+ scroll_rect.expand_to(mtx.basis_xform(edit_draw->get_size()));
+
+ Vector2 endpoints[4]={
+ mtx.basis_xform(rect.pos),
+ mtx.basis_xform(rect.pos+Vector2(rect.size.x,0)),
+ mtx.basis_xform(rect.pos+rect.size),
+ mtx.basis_xform(rect.pos+Vector2(0,rect.size.y))
+ };
+
+ for(int i=0;i<4;i++) {
+
+ int prev = (i+3)%4;
+ int next = (i+1)%4;
+
+ Vector2 ofs = ((endpoints[i] - endpoints[prev]).normalized() + ((endpoints[i] - endpoints[next]).normalized())).normalized();
+ ofs*=1.4144*(select_handle->get_size().width/2);
+
+ edit_draw->draw_line(endpoints[i]-draw_ofs, endpoints[next]-draw_ofs, Color(0.9,0.5,0.5), 2);
+
+ edit_draw->draw_texture(select_handle,(endpoints[i]+ofs-(select_handle->get_size()/2)).floor()-draw_ofs);
+
+ ofs = (endpoints[next]-endpoints[i])/2;
+ ofs += (endpoints[next]-endpoints[i]).tangent().normalized()*(select_handle->get_size().width/2);
+
+ edit_draw->draw_texture(select_handle,(endpoints[i]+ofs-(select_handle->get_size()/2)).floor()-draw_ofs);
+
+ scroll_rect.expand_to(endpoints[i]);
+ }
+
+ scroll_rect=scroll_rect.grow(200);
+ updating_scroll=true;
+ hscroll->set_min(scroll_rect.pos.x);
+ hscroll->set_max(scroll_rect.pos.x+scroll_rect.size.x);
+ hscroll->set_page(edit_draw->get_size().x);
+ hscroll->set_val(draw_ofs.x);
+ hscroll->set_step(0.001);
+
+ vscroll->set_min(scroll_rect.pos.y);
+ vscroll->set_max(scroll_rect.pos.y+scroll_rect.size.y);
+ vscroll->set_page(edit_draw->get_size().y);
+ vscroll->set_val(draw_ofs.y);
+ vscroll->set_step(0.001);
+ updating_scroll=false;
+}
+
+void SpriteRegionEditor::_region_input(const InputEvent& p_input)
+{
+ Matrix32 mtx;
+ mtx.elements[2]=-draw_ofs;
+ mtx.scale_basis(Vector2(draw_zoom,draw_zoom));
+
+ Vector2 endpoints[8]={
+ mtx.xform(rect.pos)+Vector2(-4,-4),
+ mtx.xform(rect.pos+Vector2(rect.size.x/2,0))+Vector2(0,-4),
+ mtx.xform(rect.pos+Vector2(rect.size.x,0))+Vector2(4,-4),
+ mtx.xform(rect.pos+Vector2(rect.size.x,rect.size.y/2))+Vector2(4,0),
+ mtx.xform(rect.pos+rect.size)+Vector2(4,4),
+ mtx.xform(rect.pos+Vector2(rect.size.x/2,rect.size.y))+Vector2(0,4),
+ mtx.xform(rect.pos+Vector2(0,rect.size.y))+Vector2(-4,4),
+ mtx.xform(rect.pos+Vector2(0,rect.size.y/2))+Vector2(-4,0)
+ };
+
+ if (p_input.type==InputEvent::MOUSE_BUTTON) {
+
+
+ const InputEventMouseButton &mb=p_input.mouse_button;
+
+ if (mb.button_index==BUTTON_LEFT) {
+
+
+ if (mb.pressed) {
+
+ drag_from=mtx.affine_inverse().xform(Vector2(mb.x,mb.y));
+ drag_from=snap_point(drag_from);
+ drag=true;
+ rect_prev=node->get_region_rect();
+
+ drag_index=-1;
+ for(int i=0;i<8;i++) {
+
+ Vector2 tuv=endpoints[i];
+ if (tuv.distance_to(Vector2(mb.x,mb.y))<8) {
+ drag_index=i;
+ creating = false;
+ }
+ }
+
+ if (drag_index==-1) {
+ creating = true;
+ rect = Rect2(drag_from,Size2());
+ }
+
+ } else if (drag) {
+
+ undo_redo->create_action("Set region_rect");
+ undo_redo->add_do_method(node,"set_region_rect",node->get_region_rect());
+ undo_redo->add_undo_method(node,"set_region_rect",rect_prev);
+ undo_redo->add_do_method(edit_draw,"update");
+ undo_redo->add_undo_method(edit_draw,"update");
+ undo_redo->commit_action();
+
+ drag=false;
+ }
+
+ } else if (mb.button_index==BUTTON_RIGHT && mb.pressed) {
+
+ if (drag) {
+ drag=false;
+ node->set_region_rect(rect_prev);
+ rect=rect_prev;
+ edit_draw->update();
+ }
+
+ } else if (mb.button_index==BUTTON_WHEEL_UP && mb.pressed) {
+
+ zoom->set_val( zoom->get_val()/0.9 );
+ } else if (mb.button_index==BUTTON_WHEEL_DOWN && mb.pressed) {
+
+ zoom->set_val( zoom->get_val()*0.9);
+ }
+
+ } else if (p_input.type==InputEvent::MOUSE_MOTION) {
+
+ const InputEventMouseMotion &mm=p_input.mouse_motion;
+
+ if (mm.button_mask&BUTTON_MASK_MIDDLE || Input::get_singleton()->is_key_pressed(KEY_SPACE)) {
+
+ Vector2 draged(mm.relative_x,mm.relative_y);
+ hscroll->set_val( hscroll->get_val()-draged.x );
+ vscroll->set_val( vscroll->get_val()-draged.y );
+
+ } else if (drag) {
+
+ Vector2 new_pos = mtx.affine_inverse().xform(Vector2(mm.x,mm.y));
+ new_pos = snap_point(new_pos);
+
+ if (creating) {
+ rect = Rect2(drag_from,Size2());
+ rect.expand_to(new_pos);
+ node->set_region_rect(rect);
+ edit_draw->update();
+ return;
+ }
+
+ switch(drag_index) {
+ case 0: {
+ Vector2 p=rect_prev.pos+rect_prev.size;
+ rect = Rect2(p,Size2());
+ rect.expand_to(new_pos);
+ node->set_region_rect(rect);
+ } break;
+ case 1: {
+ Vector2 p=rect_prev.pos+Vector2(0,rect_prev.size.y);
+ rect = Rect2(p,Size2(rect_prev.size.x,0));
+ rect.expand_to(new_pos);
+ node->set_region_rect(rect);
+ } break;
+ case 2: {
+ Vector2 p=rect_prev.pos+Vector2(0,rect_prev.size.y);
+ rect = Rect2(p,Size2());
+ rect.expand_to(new_pos);
+ node->set_region_rect(rect);
+ } break;
+ case 3: {
+ Vector2 p=rect_prev.pos;
+ rect = Rect2(p,Size2(0,rect_prev.size.y));
+ rect.expand_to(new_pos);
+ node->set_region_rect(rect);
+ } break;
+ case 4: {
+ Vector2 p=rect_prev.pos;
+ rect = Rect2(p,Size2());
+ rect.expand_to(new_pos);
+ node->set_region_rect(rect);
+ } break;
+ case 5: {
+ Vector2 p=rect_prev.pos;
+ rect = Rect2(p,Size2(rect_prev.size.x,0));
+ rect.expand_to(new_pos);
+ node->set_region_rect(rect);
+ } break;
+ case 6: {
+ Vector2 p=rect_prev.pos+Vector2(rect_prev.size.x,0);
+ rect = Rect2(p,Size2());
+ rect.expand_to(new_pos);
+ node->set_region_rect(rect);
+ } break;
+ case 7: {
+ Vector2 p=rect_prev.pos+Vector2(rect_prev.size.x,0);
+ rect = Rect2(p,Size2(0,rect_prev.size.y));
+ rect.expand_to(new_pos);
+ node->set_region_rect(rect);
+ } break;
+
+ }
+ edit_draw->update();
+ }
+
+ }
+}
+
+void SpriteRegionEditor::_scroll_changed(float)
+{
+ if (updating_scroll)
+ return;
+
+ draw_ofs.x=hscroll->get_val();
+ draw_ofs.y=vscroll->get_val();
+ draw_zoom=zoom->get_val();
+ print_line("_scroll_changed");
+ edit_draw->update();
+}
+
+void SpriteRegionEditor::_set_use_snap(bool p_use)
+{
+ use_snap=p_use;
+}
+
+void SpriteRegionEditor::_set_show_grid(bool p_show)
+{
+ snap_show_grid=p_show;
+ edit_draw->update();
+}
+
+void SpriteRegionEditor::_set_snap_off_x(float p_val)
+{
+ snap_offset.x=p_val;
+ edit_draw->update();
+}
+
+void SpriteRegionEditor::_set_snap_off_y(float p_val)
+{
+ snap_offset.y=p_val;
+ edit_draw->update();
+}
+
+void SpriteRegionEditor::_set_snap_step_x(float p_val)
+{
+ snap_step.x=p_val;
+ edit_draw->update();
+}
+
+void SpriteRegionEditor::_set_snap_step_y(float p_val)
+{
+ snap_step.y=p_val;
+ edit_draw->update();
+}
+
+void SpriteRegionEditor::_notification(int p_what)
+{
+ switch(p_what) {
+
+ case NOTIFICATION_READY: {
+ edit_node->set_icon( get_icon("RegionEdit","EditorIcons"));
+ b_snap_grid->set_icon( get_icon("Grid", "EditorIcons"));
+ b_snap_enable->set_icon( get_icon("Snap", "EditorIcons"));
+ icon_zoom->set_texture( get_icon("Zoom", "EditorIcons"));
+ } break;
+ }
+}
+
+void SpriteRegionEditor::_node_removed(Node *p_node)
+{
+ if(p_node==node) {
+ node=NULL;
+ hide();
+ }
+}
+
+void SpriteRegionEditor::_bind_methods()
+{
+ ObjectTypeDB::bind_method(_MD("_edit_node"),&SpriteRegionEditor::_edit_node);
+ ObjectTypeDB::bind_method(_MD("_region_draw"),&SpriteRegionEditor::_region_draw);
+ ObjectTypeDB::bind_method(_MD("_region_input"),&SpriteRegionEditor::_region_input);
+ ObjectTypeDB::bind_method(_MD("_scroll_changed"),&SpriteRegionEditor::_scroll_changed);
+ ObjectTypeDB::bind_method(_MD("_node_removed"),&SpriteRegionEditor::_node_removed);
+ ObjectTypeDB::bind_method(_MD("_set_use_snap"),&SpriteRegionEditor::_set_use_snap);
+ ObjectTypeDB::bind_method(_MD("_set_show_grid"),&SpriteRegionEditor::_set_show_grid);
+ ObjectTypeDB::bind_method(_MD("_set_snap_off_x"),&SpriteRegionEditor::_set_snap_off_x);
+ ObjectTypeDB::bind_method(_MD("_set_snap_off_y"),&SpriteRegionEditor::_set_snap_off_y);
+ ObjectTypeDB::bind_method(_MD("_set_snap_step_x"),&SpriteRegionEditor::_set_snap_step_x);
+ ObjectTypeDB::bind_method(_MD("_set_snap_step_y"),&SpriteRegionEditor::_set_snap_step_y);
+}
+
+void SpriteRegionEditor::edit(Node *p_sprite)
+{
+ if (p_sprite) {
+ node=p_sprite->cast_to<Sprite>();
+ node->connect("exit_tree",this,"_node_removed",varray(),CONNECT_ONESHOT);
+ } else {
+ if (node)
+ node->disconnect("exit_tree",this,"_node_removed");
+ node=NULL;
+ }
+
+}
+void SpriteRegionEditor::_edit_node()
+{
+ if (node->get_texture().is_null()) {
+
+ error->set_text("No texture in this sprite.\nSet a texture to be able to edit Region.");
+ error->popup_centered_minsize();
+ return;
+ }
+
+ rect=node->get_region_rect();
+ dlg_editor->popup_centered_ratio(0.85);
+}
+
+inline float _snap_scalar(float p_offset, float p_step, float p_target) {
+ return p_step != 0 ? Math::stepify(p_target - p_offset, p_step) + p_offset : p_target;
+}
+
+Vector2 SpriteRegionEditor::snap_point(Vector2 p_target) const {
+ if (use_snap) {
+ p_target.x = _snap_scalar(snap_offset.x, snap_step.x, p_target.x);
+ p_target.y = _snap_scalar(snap_offset.y, snap_step.y, p_target.y);
+ }
+ p_target = p_target.snapped(Size2(1, 1));
+
+ return p_target;
+}
+
+SpriteRegionEditor::SpriteRegionEditor(EditorNode* p_editor)
+{
+ node=NULL;
+ editor=p_editor;
+ undo_redo = editor->get_undo_redo();
+
+ snap_step=Vector2(10,10);
+ use_snap=false;
+ snap_show_grid=false;
+ drag=false;
+
+ add_child( memnew( VSeparator ));
+ edit_node = memnew( ToolButton );
+ add_child(edit_node);
+ edit_node->connect("pressed",this,"_edit_node");
+
+ dlg_editor = memnew( AcceptDialog );
+ add_child(dlg_editor);
+ dlg_editor->set_title("Sprite Region Editor");
+ dlg_editor->set_self_opacity(0.9);
+
+ VBoxContainer *main_vb = memnew( VBoxContainer );
+ dlg_editor->add_child(main_vb);
+ dlg_editor->set_child_rect(main_vb);
+ HBoxContainer *hb_tools = memnew( HBoxContainer );
+ main_vb->add_child(hb_tools);
+
+ b_snap_enable = memnew( ToolButton );
+ hb_tools->add_child(b_snap_enable);
+ b_snap_enable->set_text("Snap");
+ b_snap_enable->set_focus_mode(FOCUS_NONE);
+ b_snap_enable->set_toggle_mode(true);
+ b_snap_enable->set_pressed(use_snap);
+ b_snap_enable->set_tooltip("Enable Snap");
+ b_snap_enable->connect("toggled",this,"_set_use_snap");
+
+ b_snap_grid = memnew( ToolButton );
+ hb_tools->add_child(b_snap_grid);
+ b_snap_grid->set_text("Grid");
+ b_snap_grid->set_focus_mode(FOCUS_NONE);
+ b_snap_grid->set_toggle_mode(true);
+ b_snap_grid->set_pressed(snap_show_grid);
+ b_snap_grid->set_tooltip("Show Grid");
+ b_snap_grid->connect("toggled",this,"_set_show_grid");
+
+ hb_tools->add_child( memnew( VSeparator ));
+ hb_tools->add_child( memnew( Label("Grid Offset:") ) );
+
+ sb_off_x = memnew( SpinBox );
+ sb_off_x->set_min(-256);
+ sb_off_x->set_max(256);
+ sb_off_x->set_step(1);
+ sb_off_x->set_val(snap_offset.x);
+ sb_off_x->set_suffix("px");
+ sb_off_x->connect("value_changed", this, "_set_snap_off_x");
+ hb_tools->add_child(sb_off_x);
+
+ sb_off_y = memnew( SpinBox );
+ sb_off_y->set_min(-256);
+ sb_off_y->set_max(256);
+ sb_off_y->set_step(1);
+ sb_off_y->set_val(snap_offset.y);
+ sb_off_y->set_suffix("px");
+ sb_off_y->connect("value_changed", this, "_set_snap_off_y");
+ hb_tools->add_child(sb_off_y);
+
+ hb_tools->add_child( memnew( VSeparator ));
+ hb_tools->add_child( memnew( Label("Grid Step:") ) );
+
+ sb_step_x = memnew( SpinBox );
+ sb_step_x->set_min(-256);
+ sb_step_x->set_max(256);
+ sb_step_x->set_step(1);
+ sb_step_x->set_val(snap_step.x);
+ sb_step_x->set_suffix("px");
+ sb_step_x->connect("value_changed", this, "_set_snap_step_x");
+ hb_tools->add_child(sb_step_x);
+
+ sb_step_y = memnew( SpinBox );
+ sb_step_y->set_min(-256);
+ sb_step_y->set_max(256);
+ sb_step_y->set_step(1);
+ sb_step_y->set_val(snap_step.y);
+ sb_step_y->set_suffix("px");
+ sb_step_y->connect("value_changed", this, "_set_snap_step_y");
+ hb_tools->add_child(sb_step_y);
+
+ HBoxContainer *main_hb = memnew( HBoxContainer );
+ main_vb->add_child(main_hb);
+ edit_draw = memnew( Control );
+ main_hb->add_child(edit_draw);
+ main_hb->set_v_size_flags(SIZE_EXPAND_FILL);
+ edit_draw->set_h_size_flags(SIZE_EXPAND_FILL);
+
+
+ hb_tools->add_child( memnew( VSeparator ));
+ icon_zoom = memnew( TextureFrame );
+ hb_tools->add_child(icon_zoom);
+
+ zoom = memnew( HSlider );
+ zoom->set_min(0.01);
+ zoom->set_max(4);
+ zoom->set_val(1);
+ zoom->set_step(0.01);
+ hb_tools->add_child(zoom);
+ zoom->set_custom_minimum_size(Size2(200,0));
+ zoom_value = memnew( SpinBox );
+ zoom->share(zoom_value);
+ zoom_value->set_custom_minimum_size(Size2(50,0));
+ hb_tools->add_child(zoom_value);
+ zoom->connect("value_changed",this,"_scroll_changed");
+
+
+
+ vscroll = memnew( VScrollBar);
+ main_hb->add_child(vscroll);
+ vscroll->connect("value_changed",this,"_scroll_changed");
+ hscroll = memnew( HScrollBar );
+ main_vb->add_child(hscroll);
+ hscroll->connect("value_changed",this,"_scroll_changed");
+
+ edit_draw->connect("draw",this,"_region_draw");
+ edit_draw->connect("input_event",this,"_region_input");
+ draw_zoom=1.0;
+ updating_scroll=false;
+
+ error = memnew( AcceptDialog);
+ add_child(error);
+
+}
+
+void SpriteRegionEditorPlugin::edit(Object *p_node)
+{
+ region_editor->edit(p_node->cast_to<Node>());
+}
+
+bool SpriteRegionEditorPlugin::handles(Object *p_node) const
+{
+ return p_node->is_type("Sprite");
+}
+
+void SpriteRegionEditorPlugin::make_visible(bool p_visible)
+{
+ if (p_visible) {
+ region_editor->show();
+ } else {
+ region_editor->hide();
+ region_editor->edit(NULL);
+ }
+}
+
+
+Dictionary SpriteRegionEditorPlugin::get_state() const {
+
+ Dictionary state;
+ state["zoom"]=region_editor->zoom->get_val();
+ state["snap_offset"]=region_editor->snap_offset;
+ state["snap_step"]=region_editor->snap_step;
+ state["use_snap"]=region_editor->use_snap;
+ state["snap_show_grid"]=region_editor->snap_show_grid;
+ return state;
+}
+
+void SpriteRegionEditorPlugin::set_state(const Dictionary& p_state){
+
+ Dictionary state=p_state;
+ if (state.has("zoom")) {
+ region_editor->zoom->set_val(p_state["zoom"]);
+ }
+
+ if (state.has("snap_step")) {
+ Vector2 s = state["snap_step"];
+ region_editor->sb_step_x->set_val(s.x);
+ region_editor->sb_step_y->set_val(s.y);
+ region_editor->snap_step = s;
+ }
+
+ if (state.has("snap_offset")) {
+ Vector2 ofs = state["snap_offset"];
+ region_editor->sb_off_x->set_val(ofs.x);
+ region_editor->sb_off_y->set_val(ofs.y);
+ region_editor->snap_offset = ofs;
+ }
+
+ if (state.has("use_snap")) {
+ region_editor->use_snap=state["use_snap"];
+ region_editor->b_snap_enable->set_pressed(state["use_snap"]);
+ }
+
+ if (state.has("snap_show_grid")) {
+ region_editor->snap_show_grid=state["snap_show_grid"];
+ region_editor->b_snap_grid->set_pressed(state["snap_show_grid"]);
+ }
+}
+
+SpriteRegionEditorPlugin::SpriteRegionEditorPlugin(EditorNode *p_node)
+{
+ editor = p_node;
+ region_editor= memnew ( SpriteRegionEditor(p_node) );
+ CanvasItemEditor::get_singleton()->add_control_to_menu_panel(region_editor);
+
+ region_editor->hide();
+}
+
diff --git a/tools/editor/plugins/sprite_region_editor_plugin.h b/tools/editor/plugins/sprite_region_editor_plugin.h
new file mode 100644
index 0000000000..47cb210863
--- /dev/null
+++ b/tools/editor/plugins/sprite_region_editor_plugin.h
@@ -0,0 +1,133 @@
+/*************************************************************************/
+/* sprite_region_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Author: Mariano Suligoy */
+/* */
+/* 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. */
+/*************************************************************************/
+
+#ifndef SPRITE_REGION_EDITOR_PLUGIN_H
+#define SPRITE_REGION_EDITOR_PLUGIN_H
+
+#include "canvas_item_editor_plugin.h"
+#include "tools/editor/editor_plugin.h"
+#include "tools/editor/editor_node.h"
+#include "scene/2d/sprite.h"
+
+class SpriteRegionEditor : public HBoxContainer {
+
+ OBJ_TYPE(SpriteRegionEditor, HBoxContainer );
+
+ friend class SpriteRegionEditorPlugin;
+
+ ToolButton *edit_node;
+// Button *use_region;
+ ToolButton *b_snap_enable;
+ ToolButton *b_snap_grid;
+ TextureFrame *icon_zoom;
+ HSlider *zoom;
+ SpinBox *zoom_value;
+ SpinBox *sb_step_y;
+ SpinBox *sb_step_x;
+ SpinBox *sb_off_y;
+ SpinBox *sb_off_x;
+ Control *edit_draw;
+
+ VScrollBar *vscroll;
+ HScrollBar *hscroll;
+
+ Sprite *node;
+ EditorNode *editor;
+ AcceptDialog *dlg_editor;
+ UndoRedo* undo_redo;
+
+ Vector2 draw_ofs;
+ float draw_zoom;
+ bool updating_scroll;
+
+ bool use_snap;
+ bool snap_show_grid;
+ Vector2 snap_offset;
+ Vector2 snap_step;
+
+ Rect2 rect;
+ Rect2 rect_prev;
+ bool drag;
+ bool creating;
+ Vector2 drag_from;
+ int drag_index;
+
+ AcceptDialog *error;
+
+ void _set_use_snap(bool p_use);
+ void _set_show_grid(bool p_show);
+ void _set_snap_off_x(float p_val);
+ void _set_snap_off_y(float p_val);
+ void _set_snap_step_x(float p_val);
+ void _set_snap_step_y(float p_val);
+
+protected:
+
+ void _notification(int p_what);
+ void _node_removed(Node *p_node);
+ static void _bind_methods();
+
+ Vector2 snap_point(Vector2 p_target) const;
+
+public:
+
+ void edit();
+ void _edit_node();
+ void _region_draw();
+ void _region_input(const InputEvent &p_input);
+ void _scroll_changed(float);
+
+ void edit(Node *p_sprite);
+ SpriteRegionEditor(EditorNode* p_editor);
+
+};
+
+class SpriteRegionEditorPlugin : public EditorPlugin
+{
+
+ OBJ_TYPE( SpriteRegionEditorPlugin, EditorPlugin );
+
+ SpriteRegionEditor *region_editor;
+ EditorNode *editor;
+public:
+
+ virtual String get_name() const { return "SpriteRegion"; }
+ bool has_main_screen() const { return false; }
+ virtual void edit(Object *p_node);
+ virtual bool handles(Object *p_node) const;
+ virtual void make_visible(bool p_visible);
+ void set_state(const Dictionary &p_state);
+ Dictionary get_state() const;
+
+ SpriteRegionEditorPlugin(EditorNode *p_node);
+};
+
+#endif // SPRITE_REGION_EDITOR_PLUGIN_H
diff --git a/tools/editor/plugins/stream_editor_plugin.cpp b/tools/editor/plugins/stream_editor_plugin.cpp
index 81db7f2846..d896784074 100644
--- a/tools/editor/plugins/stream_editor_plugin.cpp
+++ b/tools/editor/plugins/stream_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/plugins/stream_editor_plugin.h b/tools/editor/plugins/stream_editor_plugin.h
index 7378bfad0c..5730612d61 100644
--- a/tools/editor/plugins/stream_editor_plugin.h
+++ b/tools/editor/plugins/stream_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/plugins/style_box_editor_plugin.cpp b/tools/editor/plugins/style_box_editor_plugin.cpp
index 898c69e1e0..3d7cf4135d 100644
--- a/tools/editor/plugins/style_box_editor_plugin.cpp
+++ b/tools/editor/plugins/style_box_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -90,19 +90,24 @@ bool StyleBoxEditorPlugin::handles(Object *p_node) const{
void StyleBoxEditorPlugin::make_visible(bool p_visible){
- if (p_visible)
- stylebox_editor->show();
- else
- stylebox_editor->hide();
+ if (p_visible) {
+ button->show();
+
+ } else {
+ if (stylebox_editor->is_visible())
+ EditorNode::get_singleton()->hide_bottom_panel();
+ button->hide();
+ }
}
StyleBoxEditorPlugin::StyleBoxEditorPlugin(EditorNode *p_node) {
stylebox_editor = memnew( StyleBoxEditor );
+ stylebox_editor->set_custom_minimum_size(Size2(0,250));
- p_node->get_viewport()->add_child(stylebox_editor);
- stylebox_editor->set_area_as_parent_rect();
- stylebox_editor->hide();
+ //p_node->get_viewport()->add_child(stylebox_editor);
+ button = p_node->add_bottom_panel_item("StyleBox",stylebox_editor);
+ button->hide();
}
diff --git a/tools/editor/plugins/style_box_editor_plugin.h b/tools/editor/plugins/style_box_editor_plugin.h
index 00b0871572..737f830bbb 100644
--- a/tools/editor/plugins/style_box_editor_plugin.h
+++ b/tools/editor/plugins/style_box_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -65,6 +65,7 @@ class StyleBoxEditorPlugin : public EditorPlugin {
StyleBoxEditor *stylebox_editor;
EditorNode *editor;
+ Button *button;
public:
diff --git a/tools/editor/plugins/theme_editor_plugin.cpp b/tools/editor/plugins/theme_editor_plugin.cpp
index 55e8f164d6..ef7b3b17c3 100644
--- a/tools/editor/plugins/theme_editor_plugin.cpp
+++ b/tools/editor/plugins/theme_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -568,26 +568,24 @@ ThemeEditor::ThemeEditor() {
CheckButton *cb = memnew( CheckButton );
cb->set_text("CheckButton");
first_vb->add_child(cb );
- CheckBox *cbx = memnew( CheckBox );
- cbx->set_text("CheckBox");
- first_vb->add_child(cbx );
-
- /* TODO: This is not working properly, controls are overlapping*/
- /*
- ButtonGroup *bg = memnew( ButtonGroup );
- bg->set_v_size_flags(SIZE_EXPAND_FILL);
- VBoxContainer *gbvb = memnew( VBoxContainer );
- gbvb->set_v_size_flags(SIZE_EXPAND_FILL);
- CheckBox *rbx1 = memnew( CheckBox );
- rbx1->set_text("CheckBox Radio1");
- rbx1->set_pressed(true);
- gbvb->add_child(rbx1);
- CheckBox *rbx2 = memnew( CheckBox );
- rbx2->set_text("CheckBox Radio2");
- gbvb->add_child(rbx2);
- bg->add_child(gbvb);
- first_vb->add_child(bg);
- */
+ CheckBox *cbx = memnew( CheckBox );
+ cbx->set_text("CheckBox");
+ first_vb->add_child(cbx );
+
+
+ ButtonGroup *bg = memnew( ButtonGroup );
+ bg->set_v_size_flags(SIZE_EXPAND_FILL);
+ VBoxContainer *gbvb = memnew( VBoxContainer );
+ gbvb->set_v_size_flags(SIZE_EXPAND_FILL);
+ CheckBox *rbx1 = memnew( CheckBox );
+ rbx1->set_text("CheckBox Radio1");
+ rbx1->set_pressed(true);
+ gbvb->add_child(rbx1);
+ CheckBox *rbx2 = memnew( CheckBox );
+ rbx2->set_text("CheckBox Radio2");
+ gbvb->add_child(rbx2);
+ bg->add_child(gbvb);
+ first_vb->add_child(bg);
MenuButton* test_menu_button = memnew( MenuButton );
test_menu_button->set_text("MenuButton");
@@ -833,21 +831,26 @@ bool ThemeEditorPlugin::handles(Object *p_node) const{
void ThemeEditorPlugin::make_visible(bool p_visible){
if (p_visible) {
- theme_editor->show();
theme_editor->set_process(true);
+ button->show();
} else {
- theme_editor->hide();
theme_editor->set_process(false);
+ if (theme_editor->is_visible())
+ EditorNode::get_singleton()->hide_bottom_panel();
+ button->hide();
}
}
ThemeEditorPlugin::ThemeEditorPlugin(EditorNode *p_node) {
+ editor=p_node;
theme_editor = memnew( ThemeEditor );
+ theme_editor->set_custom_minimum_size(Size2(0,500));
+
+// p_node->get_viewport()->add_child(theme_editor);
+ button=EditorNode::get_singleton()->add_bottom_panel_item("Theme",theme_editor);
+ button->hide();
- p_node->get_viewport()->add_child(theme_editor);
- theme_editor->set_area_as_parent_rect();
- theme_editor->hide();
}
diff --git a/tools/editor/plugins/theme_editor_plugin.h b/tools/editor/plugins/theme_editor_plugin.h
index 40c7ad8186..52c4aed839 100644
--- a/tools/editor/plugins/theme_editor_plugin.h
+++ b/tools/editor/plugins/theme_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -102,6 +102,7 @@ class ThemeEditorPlugin : public EditorPlugin {
ThemeEditor *theme_editor;
EditorNode *editor;
+ Button *button;
public:
diff --git a/tools/editor/plugins/tile_map_editor_plugin.cpp b/tools/editor/plugins/tile_map_editor_plugin.cpp
index 017a26441d..29326a2222 100644
--- a/tools/editor/plugins/tile_map_editor_plugin.cpp
+++ b/tools/editor/plugins/tile_map_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -107,8 +107,8 @@ void TileMapEditor::_set_cell(const Point2i& p_pos,int p_value,bool p_flip_h, bo
if (p_with_undo) {
- undo_redo->add_do_method(this,"_set_cell_shortened",Point2(p_pos),p_value,p_flip_h,p_flip_v,p_transpose);
- undo_redo->add_undo_method(this,"_set_cell_shortened",Point2(p_pos),prev_val,prev_flip_h,prev_flip_v,prev_transpose);
+ undo_redo->add_do_method(node,"set_cellv",Point2(p_pos),p_value,p_flip_h,p_flip_v,p_transpose);
+ undo_redo->add_undo_method(node,"set_cellv",Point2(p_pos),prev_val,prev_flip_h,prev_flip_v,prev_transpose);
} else {
node->set_cell(p_pos.x,p_pos.y,p_value,p_flip_h,p_flip_v,p_transpose);
@@ -218,7 +218,8 @@ struct _TileMapEditorCopyData {
bool TileMapEditor::forward_input_event(const InputEvent& p_event) {
- if (!node || !node->get_tileset().is_valid())
+
+ if (!node || !node->get_tileset().is_valid() || !node->is_visible())
return false;
Matrix32 xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * node->get_global_transform();
@@ -314,8 +315,8 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {
for(Map<Point2i,CellOp>::Element *E=paint_undo.front();E;E=E->next()) {
Point2i p=E->key();
- undo_redo->add_do_method(this,"_set_cell_shortened",Point2(p),node->get_cell(p.x,p.y),node->is_cell_x_flipped(p.x,p.y),node->is_cell_y_flipped(p.x,p.y),node->is_cell_transposed(p.x,p.y));
- undo_redo->add_undo_method(this,"_set_cell_shortened",Point2(p),E->get().idx,E->get().xf,E->get().yf,E->get().tr);
+ undo_redo->add_do_method(node,"set_cellv",Point2(p),node->get_cell(p.x,p.y),node->is_cell_x_flipped(p.x,p.y),node->is_cell_y_flipped(p.x,p.y),node->is_cell_transposed(p.x,p.y));
+ undo_redo->add_undo_method(node,"set_cellv",Point2(p),E->get().idx,E->get().xf,E->get().yf,E->get().tr);
}
undo_redo->commit_action();
@@ -344,7 +345,7 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {
//return true;
_set_cell(local,TileMap::INVALID_CELL);
return true;
- } else {
+ } else if (!mb.pressed) {
if (tool==TOOL_ERASING) {
@@ -353,9 +354,10 @@ bool TileMapEditor::forward_input_event(const InputEvent& p_event) {
for(Map<Point2i,CellOp>::Element *E=paint_undo.front();E;E=E->next()) {
Point2i p=E->key();
- //undo_redo->add_do_method(node,"set_cell",p.x,p.y,node->get_cell(p.x,p.y),node->is_cell_x_flipped(p.x,p.y),node->is_cell_y_flipped(p.x,p.y),node->is_cell_transposed(p.x,p.y));
- _set_cell(p,TileMap::INVALID_CELL,false,false,false,true);
- undo_redo->add_undo_method(this,"_set_cell_shortened",Point2(p),E->get().idx,E->get().xf,E->get().yf,E->get().tr);
+ //undo_redo->add_do_method(node,"set_cell",p,node->get_cell(p.x,p.y),node->is_cell_x_flipped(p.x,p.y),node->is_cell_y_flipped(p.x,p.y),node->is_cell_transposed(p.x,p.y));
+ //_set_cell(p,TileMap::INVALID_CELL,false,false,false,true);
+ undo_redo->add_do_method(node,"set_cellv",Point2(p),TileMap::INVALID_CELL,false,false,false);
+ undo_redo->add_undo_method(node,"set_cellv",Point2(p),E->get().idx,E->get().xf,E->get().yf,E->get().tr);
}
undo_redo->commit_action();
@@ -674,12 +676,9 @@ void TileMapEditor::_canvas_draw() {
Ref<Texture> t = ts->tile_get_texture(st);
if (t.is_valid()) {
Vector2 from = node->map_to_world(over_tile)+node->get_cell_draw_offset();
+ Vector2 tile_ofs = ts->tile_get_texture_offset(st);
Rect2 r = ts->tile_get_region(st);
Size2 sc = xform.get_scale();
- if (mirror_x->is_pressed())
- sc.x*=-1.0;
- if (mirror_y->is_pressed())
- sc.y*=-1.0;
Rect2 rect;
if (r==Rect2()) {
@@ -689,23 +688,47 @@ void TileMapEditor::_canvas_draw() {
rect=Rect2(from,r.get_size());
}
+ bool transp = transpose->is_pressed();
+ bool flip_h = mirror_x->is_pressed();
+ bool flip_v = mirror_y->is_pressed();
+
+ if (rect.size.y > rect.size.x) {
+ if ((flip_h && (flip_v || transp)) || (flip_v && !transp))
+ tile_ofs.y += rect.size.y - rect.size.x;
+ } else if (rect.size.y < rect.size.x) {
+ if ((flip_v && (flip_h || transp)) || (flip_h && !transp))
+ tile_ofs.x += rect.size.x - rect.size.y;
+ }
+
+ if (transp) {
+ SWAP(tile_ofs.x, tile_ofs.y);
+ }
+
+ if (flip_h) {
+ sc.x*=-1.0;
+ tile_ofs.x*=-1.0;
+ }
+ if (flip_v) {
+ sc.y*=-1.0;
+ tile_ofs.y*=-1.0;
+ }
if (node->get_tile_origin()==TileMap::TILE_ORIGIN_TOP_LEFT) {
- rect.pos+=ts->tile_get_texture_offset(st);
+ rect.pos+=tile_ofs;
} else if (node->get_tile_origin()==TileMap::TILE_ORIGIN_CENTER) {
rect.pos+=node->get_cell_size()/2;
Vector2 s = r.size;
- Vector2 center = (s/2) - ts->tile_get_texture_offset(st);
+ Vector2 center = (s/2) - tile_ofs;
- if (mirror_x->is_pressed())
+ if (flip_h)
rect.pos.x-=s.x-center.x;
else
rect.pos.x-=center.x;
- if (mirror_y->is_pressed())
+ if (flip_v)
rect.pos.y-=s.y-center.y;
else
rect.pos.y-=center.y;
@@ -716,10 +739,10 @@ void TileMapEditor::_canvas_draw() {
if (r==Rect2()) {
- canvas_item_editor->draw_texture_rect(t,rect,false,Color(1,1,1,0.5),transpose->is_pressed());
+ canvas_item_editor->draw_texture_rect(t,rect,false,Color(1,1,1,0.5),transp);
} else {
- canvas_item_editor->draw_texture_rect_region(t,rect,r,Color(1,1,1,0.5),transpose->is_pressed());
+ canvas_item_editor->draw_texture_rect_region(t,rect,r,Color(1,1,1,0.5),transp);
}
}
}
diff --git a/tools/editor/plugins/tile_map_editor_plugin.h b/tools/editor/plugins/tile_map_editor_plugin.h
index 74d1573d0f..3cbf5ff68d 100644
--- a/tools/editor/plugins/tile_map_editor_plugin.h
+++ b/tools/editor/plugins/tile_map_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/plugins/tile_set_editor_plugin.cpp b/tools/editor/plugins/tile_set_editor_plugin.cpp
index 39b0ef3c75..06046b226a 100644
--- a/tools/editor/plugins/tile_set_editor_plugin.cpp
+++ b/tools/editor/plugins/tile_set_editor_plugin.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -110,11 +110,15 @@ void TileSetEditor::_import_scene(Node *scene, Ref<TileSet> p_library, bool p_me
if (!child2->cast_to<StaticBody2D>())
continue;
StaticBody2D *sb = child2->cast_to<StaticBody2D>();
- if (sb->get_shape_count()==0)
+ int shape_count = sb->get_shape_count();
+ if (shape_count==0)
continue;
- Ref<Shape2D> collision=sb->get_shape(0);
- if (collision.is_valid()) {
- collisions.push_back(collision);
+ for (int shape_index=0; shape_index<shape_count; ++shape_index)
+ {
+ Ref<Shape2D> collision=sb->get_shape(shape_index);
+ if (collision.is_valid()) {
+ collisions.push_back(collision);
+ }
}
}
@@ -141,10 +145,6 @@ void TileSetEditor::_menu_confirm() {
switch(option) {
- case MENU_OPTION_REMOVE_ITEM: {
-
- tileset->remove_tile(to_erase);
- } break;
case MENU_OPTION_MERGE_FROM_SCENE:
case MENU_OPTION_CREATE_FROM_SCENE: {
@@ -161,6 +161,27 @@ void TileSetEditor::_menu_confirm() {
}
}
+void TileSetEditor::_name_dialog_confirm(const String& name) {
+
+ switch (option) {
+
+ case MENU_OPTION_REMOVE_ITEM: {
+
+ int id=tileset->find_tile_by_name(name);
+
+ if (id<0 && name.is_valid_integer())
+ id=name.to_int();
+
+ if (tileset->has_tile(id)) {
+ tileset->remove_tile(id);
+ } else {
+ err_dialog->set_text("Could not find tile: " + name);
+ err_dialog->popup_centered(Size2(300, 60));
+ }
+ } break;
+ }
+}
+
void TileSetEditor::_menu_cbk(int p_option) {
option=p_option;
@@ -172,13 +193,9 @@ void TileSetEditor::_menu_cbk(int p_option) {
} break;
case MENU_OPTION_REMOVE_ITEM: {
- String p = editor->get_property_editor()->get_selected_path();
- if (p.begins_with("/TileSet") && p.get_slice_count("/")>=2) {
-
- to_erase = p.get_slice("/",2).to_int();
- cd->set_text("Remove Item "+itos(to_erase)+"?");
- cd->popup_centered(Size2(300,60));
- }
+ nd->set_title("Remove Item");
+ nd->set_text("Item name or ID:");
+ nd->popup_centered(Size2(300, 95));
} break;
case MENU_OPTION_CREATE_FROM_SCENE: {
@@ -206,6 +223,7 @@ void TileSetEditor::_bind_methods() {
ObjectTypeDB::bind_method("_menu_cbk",&TileSetEditor::_menu_cbk);
ObjectTypeDB::bind_method("_menu_confirm",&TileSetEditor::_menu_confirm);
+ ObjectTypeDB::bind_method("_name_dialog_confirm",&TileSetEditor::_name_dialog_confirm);
}
TileSetEditor::TileSetEditor(EditorNode *p_editor) {
@@ -218,7 +236,7 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
options->set_pos(Point2(1,1));
options->set_text("Theme");
options->get_popup()->add_item("Add Item",MENU_OPTION_ADD_ITEM);
- options->get_popup()->add_item("Remove Selected Item",MENU_OPTION_REMOVE_ITEM);
+ options->get_popup()->add_item("Remove Item",MENU_OPTION_REMOVE_ITEM);
options->get_popup()->add_separator();
options->get_popup()->add_item("Create from Scene",MENU_OPTION_CREATE_FROM_SCENE);
options->get_popup()->add_item("Merge from Scene",MENU_OPTION_MERGE_FROM_SCENE);
@@ -228,6 +246,15 @@ TileSetEditor::TileSetEditor(EditorNode *p_editor) {
add_child(cd);
cd->get_ok()->connect("pressed", this,"_menu_confirm");
+ nd = memnew(EditorNameDialog);
+ add_child(nd);
+ nd->set_hide_on_ok(true);
+ nd->get_line_edit()->set_margin(MARGIN_TOP,28);
+ nd->connect("name_confirmed", this,"_name_dialog_confirm");
+
+ err_dialog = memnew(AcceptDialog);
+ add_child(err_dialog);
+ err_dialog->set_title("Error");
}
void TileSetEditorPlugin::edit(Object *p_node) {
diff --git a/tools/editor/plugins/tile_set_editor_plugin.h b/tools/editor/plugins/tile_set_editor_plugin.h
index df82df6993..3f47520e2a 100644
--- a/tools/editor/plugins/tile_set_editor_plugin.h
+++ b/tools/editor/plugins/tile_set_editor_plugin.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,6 +33,7 @@
#include "scene/resources/tile_set.h"
#include "tools/editor/editor_node.h"
+#include "tools/editor/editor_name_dialog.h"
class TileSetEditor : public Control {
@@ -44,7 +45,8 @@ class TileSetEditor : public Control {
EditorNode *editor;
MenuButton *menu;
ConfirmationDialog *cd;
- int to_erase;
+ EditorNameDialog *nd;
+ AcceptDialog *err_dialog;
enum {
@@ -56,7 +58,8 @@ class TileSetEditor : public Control {
int option;
void _menu_cbk(int p_option);
- void _menu_confirm();
+ void _menu_confirm();
+ void _name_dialog_confirm(const String& name);
static void _import_scene(Node *p_scene, Ref<TileSet> p_library, bool p_merge);
diff --git a/tools/editor/progress_dialog.cpp b/tools/editor/progress_dialog.cpp
index c8b87486c0..d072ce7f83 100644
--- a/tools/editor/progress_dialog.cpp
+++ b/tools/editor/progress_dialog.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,7 +29,7 @@
#include "progress_dialog.h"
#include "main/main.h"
#include "message_queue.h"
-
+#include "os/os.h"
void BackgroundProgress::_add_task(const String& p_task,const String& p_label, int p_steps) {
@@ -191,10 +191,16 @@ void ProgressDialog::add_task(const String& p_task,const String& p_label,int p_s
}
-void ProgressDialog::task_step(const String& p_task, const String& p_state, int p_step){
+void ProgressDialog::task_step(const String& p_task, const String& p_state, int p_step,bool p_force_redraw){
ERR_FAIL_COND(!tasks.has(p_task));
+ if (!p_force_redraw) {
+ uint64_t tus = OS::get_singleton()->get_ticks_usec();
+ if (tus-last_progress_tick < 50000) //50ms
+ return;
+ }
+
Task &t=tasks[p_task];
if (p_step<0)
t.progress->set_val(t.progress->get_val()+1);
@@ -202,6 +208,7 @@ void ProgressDialog::task_step(const String& p_task, const String& p_state, int
t.progress->set_val(p_step);
t.state->set_text(p_state);
+ last_progress_tick=OS::get_singleton()->get_ticks_usec();
Main::iteration(); // this will not work on a lot of platforms, so it's only meant for the editor
}
@@ -229,4 +236,5 @@ ProgressDialog::ProgressDialog() {
add_child(main);
main->set_area_as_parent_rect();
set_exclusive(true);
+ last_progress_tick=0;
}
diff --git a/tools/editor/progress_dialog.h b/tools/editor/progress_dialog.h
index 7f1cc4cb2d..539eaa8737 100644
--- a/tools/editor/progress_dialog.h
+++ b/tools/editor/progress_dialog.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -84,6 +84,7 @@ class ProgressDialog : public Popup {
Map<String,Task> tasks;
VBoxContainer *main;
+ uint64_t last_progress_tick;
void _popup();
protected:
@@ -92,7 +93,7 @@ protected:
public:
void add_task(const String& p_task,const String& p_label, int p_steps);
- void task_step(const String& p_task,const String& p_state, int p_step=-1);
+ void task_step(const String& p_task, const String& p_state, int p_step=-1, bool p_force_redraw=true);
void end_task(const String& p_task);
diff --git a/tools/editor/project_export.cpp b/tools/editor/project_export.cpp
index e38c672a3e..7690d31e7b 100644
--- a/tools/editor/project_export.cpp
+++ b/tools/editor/project_export.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -80,7 +80,7 @@ bool ProjectExportDialog::_create_tree(TreeItem *p_parent,EditorFileSystemDirect
String path = p_dir->get_file_path(i);
fitem->set_tooltip(0,path);
fitem->set_metadata(0,path);
- Ref<Texture> icon = get_icon( (has_icon(p_dir->get_file_type(i),"EditorIcons")?p_dir->get_file_type(i):String("Object")),"EditorIcons");
+ Ref<Texture> icon = get_icon( (has_icon(p_dir->get_file_type(i),ei)?p_dir->get_file_type(i):ot),ei);
fitem->set_icon(0,icon);
fitem->set_cell_mode(1,TreeItem::CELL_MODE_RANGE);
@@ -193,6 +193,8 @@ void ProjectExportDialog::_prop_edited(String what) {
_save_export_cfg();
+ _validate_platform();
+
}
void ProjectExportDialog::_filters_edited(String what) {
@@ -252,6 +254,14 @@ void ProjectExportDialog::_script_edited(Variant v) {
}
+void ProjectExportDialog::_sample_convert_edited(int what) {
+ EditorImportExport::get_singleton()->sample_set_action( EditorImportExport::SampleAction(sample_mode->get_selected()));
+ EditorImportExport::get_singleton()->sample_set_max_hz( sample_max_hz->get_val() );
+ EditorImportExport::get_singleton()->sample_set_trim( sample_trim->is_pressed() );
+ _save_export_cfg();
+
+}
+
void ProjectExportDialog::_notification(int p_what) {
switch(p_what) {
@@ -288,6 +298,7 @@ void ProjectExportDialog::_notification(int p_what) {
// _rescan();
_update_platform();
export_mode->select( EditorImportExport::get_singleton()->get_export_filter() );
+ convert_text_scenes->set_pressed( EditorImportExport::get_singleton()->get_convert_text_scenes() );
filters->set_text( EditorImportExport::get_singleton()->get_export_custom_filter() );
if (EditorImportExport::get_singleton()->get_export_filter()!=EditorImportExport::EXPORT_SELECTED)
tree_vb->hide();
@@ -319,6 +330,15 @@ void ProjectExportDialog::_notification(int p_what) {
_update_group();
_update_group_tree();
+ sample_mode->select( EditorImportExport::get_singleton()->sample_get_action() );
+ sample_max_hz->set_val( EditorImportExport::get_singleton()->sample_get_max_hz() );
+ sample_trim->set_pressed( EditorImportExport::get_singleton()->sample_get_trim() );
+
+ sample_mode->connect("item_selected",this,"_sample_convert_edited");
+ sample_max_hz->connect("value_changed",this,"_sample_convert_edited");
+ sample_trim->connect("toggled",this,"_sample_convert_edited");
+
+
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -402,6 +422,8 @@ void ProjectExportDialog::_export_mode_changed(int p_idx) {
else
tree_vb->show();
+ EditorImportExport::get_singleton()->set_convert_text_scenes( convert_text_scenes->is_pressed() );
+
_save_export_cfg();
}
@@ -450,20 +472,32 @@ void ProjectExportDialog::_export_action_pck(const String& p_file) {
ERR_PRINT("Invalid platform for export of PCK");
return;
}
- FileAccess *f = FileAccess::open(p_file,FileAccess::WRITE);
- if (!f) {
- error->set_text("Error exporting project PCK! Can't write");
- error->popup_centered_minsize();
- }
- ERR_FAIL_COND(!f);
- Error err = exporter->save_pack(f,false);
- memdelete(f);
+ if (p_file.ends_with(".pck")) {
+ FileAccess *f = FileAccess::open(p_file,FileAccess::WRITE);
+ if (!f) {
+ error->set_text("Error exporting project PCK! Can't write");
+ error->popup_centered_minsize();
+ }
+ ERR_FAIL_COND(!f);
- if (err!=OK) {
- error->set_text("Error exporting project!");
- error->popup_centered_minsize();
- return;
+ Error err = exporter->save_pack(f,false);
+ memdelete(f);
+
+ if (err!=OK) {
+ error->set_text("Error exporting project!");
+ error->popup_centered_minsize();
+ return;
+ }
+ } else if (p_file.ends_with(".zip")) {
+
+ Error err = exporter->save_zip(p_file,false);
+
+ if (err!=OK) {
+ error->set_text("Error exporting project!");
+ error->popup_centered_minsize();
+ return;
+ }
}
}
@@ -473,6 +507,18 @@ Error ProjectExportDialog::export_platform(const String& p_platform, const Strin
Ref<EditorExportPlatform> exporter = EditorImportExport::get_singleton()->get_export_platform(p_platform);
if (exporter.is_null()) {
ERR_PRINT("Invalid platform for export");
+
+ List<StringName> platforms;
+ EditorImportExport::get_singleton()->get_export_platforms(&platforms);
+ print_line("Valid export plaftorms are:");
+ for (List<StringName>::Element *E=platforms.front();E;E=E->next())
+ print_line(" \""+E->get()+"\"");
+
+ if (p_quit_after) {
+ OS::get_singleton()->set_exit_code(255);
+ get_tree()->quit();
+ }
+
return ERR_INVALID_PARAMETER;
}
Error err = exporter->export_project(p_path,p_debug);
@@ -1045,6 +1091,7 @@ void ProjectExportDialog::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_group_select_none"),&ProjectExportDialog::_group_select_none);
ObjectTypeDB::bind_method(_MD("_script_edited"),&ProjectExportDialog::_script_edited);
ObjectTypeDB::bind_method(_MD("_update_script"),&ProjectExportDialog::_update_script);
+ ObjectTypeDB::bind_method(_MD("_sample_convert_edited"),&ProjectExportDialog::_sample_convert_edited);
ObjectTypeDB::bind_method(_MD("export_platform"),&ProjectExportDialog::export_platform);
@@ -1106,6 +1153,7 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) {
vb = memnew( VBoxContainer );
vb->set_name("Resources");
sections->add_child(vb);
+
export_mode = memnew( OptionButton );
export_mode->add_item("Export selected resources (including dependencies).");
export_mode->add_item("Export all resources in the project.");
@@ -1114,6 +1162,8 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) {
vb->add_margin_child("Export Mode:",export_mode);
+
+
tree_vb = memnew( VBoxContainer );
vb->add_child(tree_vb);
tree_vb->set_v_size_flags(SIZE_EXPAND_FILL);
@@ -1131,9 +1181,13 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) {
tree->set_column_min_width(1,90);
filters = memnew( LineEdit );
- vb->add_margin_child("Filters for Non-Resources (Comma Separated):",filters);
+ vb->add_margin_child("Filters to export non-resource files (Comma Separated, ie: *.json, *.txt):",filters);
filters->connect("text_changed",this,"_filters_edited");
+ convert_text_scenes = memnew( CheckButton );
+ convert_text_scenes->set_text("Convert text scenes to binary on export");
+ vb->add_child(convert_text_scenes);
+ convert_text_scenes->connect("toggled",this,"_export_mode_changed");
image_vb = memnew( VBoxContainer );
image_vb->set_name("Images");
@@ -1156,7 +1210,7 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) {
image_shrink = memnew( SpinBox );
image_shrink->set_min(1);
image_shrink->set_max(8);
- image_shrink->set_step(1);
+ image_shrink->set_step(0.1);
image_vb->add_margin_child("Shrink All Images:",image_shrink);
sections->add_child(image_vb);
@@ -1216,6 +1270,7 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) {
group_image_action->add_item("Default");
group_image_action->add_item("Compress Disk");
group_image_action->add_item("Compress RAM");
+ group_image_action->add_item("Keep Original");
group_options->add_margin_child("Compress Mode:",group_image_action);
group_image_action->connect("item_selected",this,"_group_changed");
@@ -1236,7 +1291,7 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) {
group_shrink->set_min(1);
group_shrink->set_max(8);
group_shrink->set_val(1);
- group_shrink->set_step(1);
+ group_shrink->set_step(0.001);
group_options->add_margin_child("Shrink By:",group_shrink);
group_shrink->connect("value_changed",this,"_group_changed");
@@ -1315,6 +1370,22 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) {
hbc->add_child(button_reload);
*/
+
+ sample_vbox = memnew( VBoxContainer );
+ sample_vbox->set_name("Samples");
+ sections->add_child(sample_vbox);
+ sample_mode = memnew( OptionButton );
+ sample_vbox->add_margin_child("Sample Conversion Mode: (.wav files):",sample_mode);
+ sample_mode->add_item("Keep");
+ sample_mode->add_item("Compress (RAM - IMA-ADPCM)");
+ sample_max_hz = memnew( SpinBox );
+ sample_max_hz->set_max(192000);
+ sample_max_hz->set_min(8000);
+ sample_vbox->add_margin_child("Sampling Rate Limit: (hz)",sample_max_hz);
+ sample_trim = memnew( CheckButton );
+ sample_trim->set_text("Trim");
+ sample_vbox->add_margin_child("Trailing Silence:",sample_trim);
+
script_vbox = memnew( VBoxContainer );
script_vbox->set_name("Script");
sections->add_child(script_vbox);
@@ -1337,7 +1408,7 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) {
add_child(confirm);
confirm->connect("confirmed",this,"_confirmed");
- get_ok()->set_text("Export PCK");
+ get_ok()->set_text("Export PCK/Zip");
expopt="--,Export,Bundle";
@@ -1367,11 +1438,14 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) {
pck_export->set_title("Export Project PCK");
pck_export->connect("file_selected", this,"_export_action_pck");
pck_export->add_filter("*.pck ; Data Pack");
+ pck_export->add_filter("*.zip ; Zip");
add_child(pck_export);
button_export = add_button("Export..",!OS::get_singleton()->get_swap_ok_cancel(),"export_pck");
updating_script=false;
+ ei="EditorIcons";
+ ot="Object";
}
diff --git a/tools/editor/project_export.h b/tools/editor/project_export.h
index c88233ae01..5a42a58e58 100644
--- a/tools/editor/project_export.h
+++ b/tools/editor/project_export.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -78,6 +78,9 @@ private:
HBoxContainer *plat_errors;
Label *platform_error_string;
+ StringName ei;
+ StringName ot;
+
Tree * tree;
EditorFileDialog *pck_export;
@@ -105,6 +108,7 @@ private:
PropertyEditor *platform_options;
OptionButton *export_mode;
+ CheckButton *convert_text_scenes;
VBoxContainer *tree_vb;
VBoxContainer *image_vb;
@@ -136,6 +140,10 @@ private:
OptionButton *script_mode;
LineEdit *script_key;
+ VBoxContainer *sample_vbox;
+ OptionButton *sample_mode;
+ SpinBox *sample_max_hz;
+ CheckButton *sample_trim;
void _export_mode_changed(int p_idx);
@@ -159,6 +167,8 @@ private:
void _image_export_edited(int what);
void _shrink_edited(float what);
+ void _sample_convert_edited(int what);
+
void _update_group_list();
void _select_group(const String& p_by_name);
diff --git a/tools/editor/project_manager.cpp b/tools/editor/project_manager.cpp
index f1eecd53b0..589d9d3d99 100644
--- a/tools/editor/project_manager.cpp
+++ b/tools/editor/project_manager.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -144,7 +144,7 @@ class NewProjectDialog : public ConfirmationDialog {
fdialog->set_mode(FileDialog::MODE_OPEN_FILE);
fdialog->clear_filters();
- fdialog->add_filter("engine.cfg ; "_MKSTR(VERSION_NAME)" Project");
+ fdialog->add_filter("engine.cfg ; " _MKSTR(VERSION_NAME) " Project");
} else {
fdialog->set_mode(FileDialog::MODE_OPEN_DIR);
}
@@ -193,7 +193,7 @@ class NewProjectDialog : public ConfirmationDialog {
f->store_line("\n");
f->store_line("[application]");
f->store_line("name=\""+project_name->get_text()+"\"");
- f->store_line("icon=\"icon.png\"");
+ f->store_line("icon=\"res://icon.png\"");
memdelete(f);
@@ -245,7 +245,8 @@ public:
project_name->clear();
if (import_mode) {
- set_title("Import Existing Project:");
+ set_title("Import Existing Project");
+ get_ok()->set_text("Import");
pp->set_text("Project Path: (Must exist)");
pn->set_text("Project Name:");
pn->hide();
@@ -254,7 +255,8 @@ public:
popup_centered(Size2(500,125));
} else {
- set_title("Create New Project:");
+ set_title("Create New Project");
+ get_ok()->set_text("Create");
pp->set_text("Project Path:");
pn->set_text("Project Name:");
pn->show();
@@ -313,7 +315,6 @@ public:
l->add_color_override("font_color",Color(1,0.4,0.3,0.8));
l->set_align(Label::ALIGN_CENTER);
- get_ok()->set_text("Create");
DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
project_path->set_text(d->get_current_dir());
memdelete(d);
@@ -347,6 +348,13 @@ struct ProjectItem {
_FORCE_INLINE_ bool operator ==(const ProjectItem& l) const { return project==l.project; }
};
+void ProjectManager::_notification(int p_what) {
+
+ if (p_what==NOTIFICATION_ENTER_TREE) {
+
+ get_tree()->set_editor_hint(true);
+ }
+}
void ProjectManager::_panel_draw(Node *p_hb) {
@@ -479,20 +487,25 @@ void ProjectManager::_load_recent_projects() {
bool favorite = (_name.begins_with("favorite_projects/"))?true:false;
uint64_t last_modified = 0;
- if (FileAccess::exists(conf))
+ if (FileAccess::exists(conf)) {
last_modified = FileAccess::get_modified_time(conf);
- String fscache = path.plus_file(".fscache");
- if (FileAccess::exists(fscache)) {
- uint64_t cache_modified = FileAccess::get_modified_time(fscache);
- if ( cache_modified > last_modified )
- last_modified = cache_modified;
- }
- ProjectItem item(project, path, conf, last_modified, favorite);
- if (favorite)
- favorite_projects.push_back(item);
- else
- projects.push_back(item);
+ String fscache = path.plus_file(".fscache");
+ if (FileAccess::exists(fscache)) {
+ uint64_t cache_modified = FileAccess::get_modified_time(fscache);
+ if ( cache_modified > last_modified )
+ last_modified = cache_modified;
+ }
+
+ ProjectItem item(project, path, conf, last_modified, favorite);
+ if (favorite)
+ favorite_projects.push_back(item);
+ else
+ projects.push_back(item);
+ } else {
+ //project doesn't exist on disk but it's in the XML settings file
+ EditorSettings::get_singleton()->erase(_name); //remove it
+ }
}
projects.sort();
@@ -600,6 +613,8 @@ void ProjectManager::_load_recent_projects() {
erase_btn->set_disabled(selected_list.size()<1);
open_btn->set_disabled(selected_list.size()<1);
run_btn->set_disabled(selected_list.size()<1 || (selected_list.size()==1 && single_selected_main==""));
+
+ EditorSettings::get_singleton()->save();
}
void ProjectManager::_open_project_confirm() {
@@ -616,11 +631,6 @@ void ProjectManager::_open_project_confirm() {
args.push_back("-editor");
- const String &selected_main = E->get();
- if (selected_main!="") {
- args.push_back(selected_main);
- }
-
String exec = OS::get_singleton()->get_executable_path();
OS::ProcessID pid=0;
@@ -822,6 +832,19 @@ ProjectManager::ProjectManager() {
FileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("file_dialog/show_hidden_files"));
set_area_as_parent_rect();
+
+ Ref<Theme> theme = Ref<Theme>( memnew( Theme ) );
+ set_theme(theme);
+ editor_register_icons(theme);
+
+ String global_font = EditorSettings::get_singleton()->get("global/font");
+ if (global_font!="") {
+ Ref<Font> fnt = ResourceLoader::load(global_font);
+ if (fnt.is_valid()) {
+ theme->set_default_theme_font(fnt);
+ }
+ }
+
Panel *panel = memnew( Panel );
add_child(panel);
panel->set_area_as_parent_rect();
@@ -838,7 +861,7 @@ ProjectManager::ProjectManager() {
l->set_align(Label::ALIGN_CENTER);
vb->add_child(l);
l = memnew( Label );
- l->set_text("v"VERSION_MKSTRING);
+ l->set_text("v" VERSION_MKSTRING);
//l->add_font_override("font",get_font("bold","Fonts"));
l->set_align(Label::ALIGN_CENTER);
vb->add_child(l);
@@ -941,7 +964,7 @@ ProjectManager::ProjectManager() {
String cp;
cp.push_back(0xA9);
cp.push_back(0);
- l->set_text(cp+" 2008-2015 Juan Linietsky, Ariel Manzur.");
+ l->set_text(cp+" 2008-2016 Juan Linietsky, Ariel Manzur.");
l->set_align(Label::ALIGN_CENTER);
vb->add_child(l);
@@ -969,10 +992,6 @@ ProjectManager::ProjectManager() {
npdialog = memnew( NewProjectDialog );
add_child(npdialog);
- Ref<Theme> theme = memnew( Theme );
- editor_register_icons(theme);
- set_theme(theme);
-
npdialog->connect("project_created", this,"_load_recent_projects");
_load_recent_projects();
diff --git a/tools/editor/project_manager.h b/tools/editor/project_manager.h
index 1e6ea9c1c9..80c34690f8 100644
--- a/tools/editor/project_manager.h
+++ b/tools/editor/project_manager.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -85,6 +85,7 @@ class ProjectManager : public Control {
protected:
+ void _notification(int p_what);
static void _bind_methods();
public:
ProjectManager();
diff --git a/tools/editor/project_settings.cpp b/tools/editor/project_settings.cpp
index fea9c705ef..26e8919375 100644
--- a/tools/editor/project_settings.cpp
+++ b/tools/editor/project_settings.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,6 +33,7 @@
#include "editor_node.h"
#include "scene/gui/margin_container.h"
#include "translation.h"
+#include "global_constants.h"
ProjectSettings *ProjectSettings::singleton=NULL;
@@ -89,7 +90,9 @@ void ProjectSettings::_notification(int p_what) {
autoload_file_open->add_filter("*."+E->get());
}
+ } else if (p_what==NOTIFICATION_POST_POPUP) {
+ globals_editor->clear_search_box();
}
}
@@ -103,6 +106,8 @@ void ProjectSettings::_action_persist_toggle() {
String name="input/"+ti->get_text(0);
bool prev = Globals::get_singleton()->is_persisting(name);
+ print_line("prev persist: "+itos(prev));
+ print_line("new persist: "+itos(ti->is_checked(0)));
if (prev==ti->is_checked(0))
return;
@@ -152,12 +157,14 @@ void ProjectSettings::_device_input_add() {
} break;
case InputEvent::JOYSTICK_MOTION: {
- ie.joy_motion.axis = device_index->get_selected();
+ ie.joy_motion.axis = device_index->get_selected()>>1;
+ ie.joy_motion.axis_value = device_index->get_selected()&1?1:-1;
+
for(int i=0;i<arr.size();i++) {
InputEvent aie=arr[i];
- if (aie.device == ie.device && aie.type==InputEvent::JOYSTICK_MOTION && aie.joy_motion.axis==ie.joy_motion.axis) {
+ if (aie.device == ie.device && aie.type==InputEvent::JOYSTICK_MOTION && aie.joy_motion.axis==ie.joy_motion.axis && aie.joy_motion.axis_value==ie.joy_motion.axis_value) {
return;
}
}
@@ -291,9 +298,10 @@ void ProjectSettings::_add_item(int p_item){
device_id->set_val(0);
device_index_label->set_text("Joy Button Axis:");
device_index->clear();
- for(int i=0;i<8;i++) {
+ for(int i=0;i<24;i++) {
+
- device_index->add_item("Axis "+itos(i));
+ device_index->add_item("Axis "+itos(i/2)+" "+(i&1?"+":"-"));
}
device_input->popup_centered(Size2(350,95));
@@ -335,6 +343,15 @@ void ProjectSettings::_action_button_pressed(Object* p_obj, int p_column,int p_i
add_at="input/"+ti->get_text(0);
} else if (p_id==2) {
+ //rename
+
+ add_at="input/"+ti->get_text(0);
+ rename_action->popup_centered();
+ rename_action->get_line_edit()->set_text(ti->get_text(0));
+ rename_action->get_line_edit()->set_cursor_pos(ti->get_text(0).length());
+ rename_action->get_line_edit()->select_all();
+
+ } else if (p_id==3) {
//remove
if (ti->get_parent()==input_editor->get_root()) {
@@ -412,13 +429,16 @@ void ProjectSettings::_update_actions() {
continue;
TreeItem *item=input_editor->create_item(root);
- item->set_cell_mode(0,TreeItem::CELL_MODE_CHECK);
+ //item->set_cell_mode(0,TreeItem::CELL_MODE_CHECK);
item->set_text(0,name);
item->add_button(0,get_icon("Add","EditorIcons"),1);
- item->add_button(0,get_icon("Remove","EditorIcons"),2);
+ if (!Globals::get_singleton()->get_input_presets().find(pi.name)) {
+ item->add_button(0,get_icon("Rename","EditorIcons"),2);
+ item->add_button(0,get_icon("Remove","EditorIcons"),3);
+ }
item->set_custom_bg_color(0,get_color("prop_subsection","Editor"));
item->set_editable(0,true);
- item->set_checked(0,pi.usage&PROPERTY_USAGE_CHECKED);
+ //item->set_checked(0,pi.usage&PROPERTY_USAGE_CHECKED);
@@ -478,12 +498,12 @@ void ProjectSettings::_update_actions() {
} break;
case InputEvent::JOYSTICK_MOTION: {
- String str = "Device "+itos(ie.device)+", Axis "+itos(ie.joy_motion.axis)+".";
+ String str = "Device "+itos(ie.device)+", Axis "+itos(ie.joy_motion.axis)+" "+(ie.joy_motion.axis_value<0?"-.":"+.");
action->set_text(0,str);
action->set_icon(0,get_icon("JoyAxis","EditorIcons"));
} break;
}
- action->add_button(0,get_icon("Remove","EditorIcons"),2);
+ action->add_button(0,get_icon("Remove","EditorIcons"),3);
action->set_metadata(0,i);
}
}
@@ -504,12 +524,12 @@ void ProjectSettings::popup_project_settings() {
void ProjectSettings::_item_selected() {
- TreeItem *ti = globals_editor->get_scene_tree()->get_selected();
+ TreeItem *ti = globals_editor->get_property_editor()->get_scene_tree()->get_selected();
if (!ti)
return;
if (!ti->get_parent())
return;
- category->set_text(ti->get_parent()->get_text(0));
+ category->set_text(globals_editor->get_current_section());
property->set_text(ti->get_text(0));
popup_platform->set_disabled(false);
@@ -548,7 +568,8 @@ void ProjectSettings::_item_add() {
String name = catname+"/"+propname;
Globals::get_singleton()->set(name,value);
- globals_editor->update_tree();
+ globals_editor->edit(NULL);
+ globals_editor->edit(Globals::get_singleton());
}
void ProjectSettings::_item_del() {
@@ -560,7 +581,7 @@ void ProjectSettings::_item_del() {
String name = catname+"/"+propname;
Globals::get_singleton()->set(name,Variant());
- globals_editor->update_tree();
+ globals_editor->get_property_editor()->update_tree();
}
@@ -613,14 +634,57 @@ void ProjectSettings::_action_add() {
}
+void ProjectSettings::_action_rename(const String &p_name) {
+
+
+ if (p_name.find("/")!=-1 || p_name.find(":")!=-1 || p_name=="") {
+ message->set_text("Invalid Action (Anything goes but / or :).");
+ message->popup_centered(Size2(300,100));
+ return;
+ }
+
+ String new_name = "input/"+p_name;
+
+ if (Globals::get_singleton()->has(new_name)) {
+ message->set_text("Action '"+p_name+"' already exists!.");
+ message->popup_centered(Size2(300,100));
+ return;
+ }
+
+ int order = Globals::get_singleton()->get_order(add_at);
+ Array va = Globals::get_singleton()->get(add_at);
+ bool persisting = Globals::get_singleton()->is_persisting(add_at);
+
+ undo_redo->create_action("Rename Input Action Event");
+ undo_redo->add_do_method(Globals::get_singleton(),"clear",add_at);
+ undo_redo->add_do_method(Globals::get_singleton(),"set",new_name,va);
+ undo_redo->add_do_method(Globals::get_singleton(),"set_persisting",new_name,persisting);
+ undo_redo->add_do_method(Globals::get_singleton(),"set_order",new_name,order);
+ undo_redo->add_undo_method(Globals::get_singleton(),"clear",new_name);
+ undo_redo->add_undo_method(Globals::get_singleton(),"set",add_at,va);
+ undo_redo->add_undo_method(Globals::get_singleton(),"set_persisting",add_at,persisting);
+ undo_redo->add_undo_method(Globals::get_singleton(),"set_order",add_at,order);
+ undo_redo->add_do_method(this,"_update_actions");
+ undo_redo->add_undo_method(this,"_update_actions");
+ undo_redo->add_do_method(this,"_settings_changed");
+ undo_redo->add_undo_method(this,"_settings_changed");
+ undo_redo->commit_action();
+
+ rename_action->hide();
+}
+
void ProjectSettings::_item_checked(const String& p_item, bool p_check) {
undo_redo->create_action("Toggle Persisting");
- undo_redo->add_do_method(Globals::get_singleton(),"set_persisting",p_item,p_check);
- undo_redo->add_undo_method(Globals::get_singleton(),"set_persisting",p_item,!p_check);
+ String full_item = globals_editor->get_full_item_path(p_item);
+
+ undo_redo->add_do_method(Globals::get_singleton(),"set_persisting",full_item,p_check);
+ undo_redo->add_undo_method(Globals::get_singleton(),"set_persisting",full_item,!p_check);
undo_redo->add_do_method(this,"_settings_changed");
undo_redo->add_undo_method(this,"_settings_changed");
+ undo_redo->add_do_method(globals_editor->get_property_editor(),"update_tree");
+ undo_redo->add_undo_method(globals_editor->get_property_editor(),"update_tree");
undo_redo->commit_action();
}
@@ -637,11 +701,22 @@ void ProjectSettings::_save() {
void ProjectSettings::_settings_prop_edited(const String& p_name) {
- if (!Globals::get_singleton()->is_persisting(p_name)) {
+ String full_item = globals_editor->get_full_item_path(p_name);
+
+ if (!Globals::get_singleton()->is_persisting(full_item)) {
+ Globals::get_singleton()->set_persisting(full_item,true);
+
+ {
+ //small usability workaround, if anything related to resolution scaling or size is modified, change all of them together
+ if (full_item=="display/width" || full_item=="display/height" || full_item=="display/stretch_mode") {
+ Globals::get_singleton()->set_persisting("display/height",true);
+ Globals::get_singleton()->set_persisting("display/width",true);
+ }
+ }
+
- Globals::get_singleton()->set_persisting(p_name,true);
// globals_editor->update_property(p_name);
- globals_editor->update_tree();
+ globals_editor->get_property_editor()->update_tree();
}
_settings_changed();
}
@@ -676,7 +751,7 @@ void ProjectSettings::_copy_to_platform(int p_which) {
name = catname+"/"+propname;
Globals::get_singleton()->set(name,value);
- globals_editor->update_tree();
+ globals_editor->get_property_editor()->update_tree();
}
@@ -719,6 +794,11 @@ void ProjectSettings::_translation_file_open() {
void ProjectSettings::_autoload_file_callback(const String& p_path) {
autoload_add_path->set_text(p_path);
+ //if (autoload_add_name->get_text().strip_edges()==String()) {
+
+ autoload_add_name->set_text( p_path.get_file().basename() );
+ //}
+
//_translation_add(p_translation);
}
@@ -727,6 +807,40 @@ void ProjectSettings::_autoload_file_open() {
autoload_file_open->popup_centered_ratio();
}
+void ProjectSettings::_autoload_edited() {
+
+ if (updating_autoload)
+ return;
+
+ TreeItem *ti = autoload_list->get_edited();
+ if (!ti || autoload_list->get_edited_column()!=2)
+ return;
+
+ updating_autoload=true;
+ bool checked=ti->is_checked(2);
+
+ String base="autoload/"+ti->get_text(0);
+
+ String path = Globals::get_singleton()->get(base);
+
+ if (path.begins_with("*"))
+ path=path.substr(1,path.length());
+
+ if (checked)
+ path="*"+path;
+
+ undo_redo->create_action("Toggle Autoload GlobalVar");
+ undo_redo->add_do_property(Globals::get_singleton(),base,path);
+ undo_redo->add_undo_property(Globals::get_singleton(),base,Globals::get_singleton()->get(base));
+ undo_redo->add_do_method(this,"_update_autoload");
+ undo_redo->add_undo_method(this,"_update_autoload");
+ undo_redo->add_do_method(this,"_settings_changed");
+ undo_redo->add_undo_method(this,"_settings_changed");
+ undo_redo->commit_action();
+ updating_autoload=false;
+
+}
+
void ProjectSettings::_autoload_add() {
String name = autoload_add_name->get_text();
@@ -737,6 +851,35 @@ void ProjectSettings::_autoload_add() {
}
+ if (ObjectTypeDB::type_exists(name)) {
+
+ message->set_text("Invalid Name.Must not collide with an existing engine class name.");
+ message->popup_centered(Size2(300,100));
+ return;
+
+ }
+
+ for(int i=0;i<Variant::VARIANT_MAX;i++) {
+ if (Variant::get_type_name(Variant::Type(i))==name) {
+
+ message->set_text("Invalid Name.Must not collide with an existing buit-in type name.");
+ message->popup_centered(Size2(300,100));
+ return;
+
+ }
+ }
+
+ for(int i=0;i<GlobalConstants::get_global_constant_count();i++) {
+
+ if (GlobalConstants::get_global_constant_name(i)==name) {
+
+ message->set_text("Invalid Name.Must not collide with an existing global constant name.");
+ message->popup_centered(Size2(300,100));
+ return;
+ }
+
+ }
+
String path = autoload_add_path->get_text();
if (!FileAccess::exists(path)) {
message->set_text("Invalid Path.\nFile does not exist.");
@@ -753,7 +896,7 @@ void ProjectSettings::_autoload_add() {
undo_redo->create_action("Add Autoload");
name = "autoload/"+name;
- undo_redo->add_do_property(Globals::get_singleton(),name,path);
+ undo_redo->add_do_property(Globals::get_singleton(),name,"*"+path);
if (Globals::get_singleton()->has(name))
undo_redo->add_undo_property(Globals::get_singleton(),name,Globals::get_singleton()->get(name));
else
@@ -766,23 +909,58 @@ void ProjectSettings::_autoload_add() {
undo_redo->add_undo_method(this,"_settings_changed");
undo_redo->commit_action();
+ autoload_add_path->set_text("");
+ autoload_add_name->set_text("");
+
//autoload_file_open->popup_centered_ratio();
}
void ProjectSettings::_autoload_delete(Object *p_item,int p_column, int p_button) {
+
TreeItem *ti=p_item->cast_to<TreeItem>();
String name = "autoload/"+ti->get_text(0);
- undo_redo->create_action("Remove Autoload");
- undo_redo->add_do_property(Globals::get_singleton(),name,Variant());
- undo_redo->add_undo_property(Globals::get_singleton(),name,Globals::get_singleton()->get(name));
- undo_redo->add_undo_method(Globals::get_singleton(),"set_persisting",name,true);
- undo_redo->add_do_method(this,"_update_autoload");
- undo_redo->add_undo_method(this,"_update_autoload");
- undo_redo->add_do_method(this,"_settings_changed");
- undo_redo->add_undo_method(this,"_settings_changed");
- undo_redo->commit_action();
+ if (p_button==0) {
+ //delete
+ undo_redo->create_action("Remove Autoload");
+ undo_redo->add_do_property(Globals::get_singleton(),name,Variant());
+ undo_redo->add_undo_property(Globals::get_singleton(),name,Globals::get_singleton()->get(name));
+ undo_redo->add_undo_method(Globals::get_singleton(),"set_persisting",name,true);
+ undo_redo->add_do_method(this,"_update_autoload");
+ undo_redo->add_undo_method(this,"_update_autoload");
+ undo_redo->add_do_method(this,"_settings_changed");
+ undo_redo->add_undo_method(this,"_settings_changed");
+ undo_redo->commit_action();
+ } else {
+
+ TreeItem *swap;
+
+ if (p_button==1) {
+ swap=ti->get_prev();
+ } else if (p_button==2) {
+ swap=ti->get_next();
+ }
+ if (!swap)
+ return;
+
+ String swap_name= "autoload/"+swap->get_text(0);
+
+ int order = Globals::get_singleton()->get_order(name);
+ int swap_order = Globals::get_singleton()->get_order(swap_name);
+
+ undo_redo->create_action("Move Autoload");
+ undo_redo->add_do_method(Globals::get_singleton(),"set_order",swap_name,order);
+ undo_redo->add_do_method(Globals::get_singleton(),"set_order",name,swap_order);
+ undo_redo->add_undo_method(Globals::get_singleton(),"set_order",swap_name,swap_order);
+ undo_redo->add_undo_method(Globals::get_singleton(),"set_order",name,order);
+ undo_redo->add_do_method(this,"_update_autoload");
+ undo_redo->add_undo_method(this,"_update_autoload");
+ undo_redo->add_do_method(this,"_settings_changed");
+ undo_redo->add_undo_method(this,"_settings_changed");
+ undo_redo->commit_action();
+
+ }
}
@@ -1114,6 +1292,11 @@ void ProjectSettings::_update_translations() {
void ProjectSettings::_update_autoload() {
+ if (updating_autoload)
+ return;
+
+ updating_autoload=true;
+
autoload_list->clear();
TreeItem *root = autoload_list->create_item();
autoload_list->set_hide_root(true);
@@ -1128,18 +1311,32 @@ void ProjectSettings::_update_autoload() {
continue;
String name = pi.name.get_slice("/",1);
+ String path = Globals::get_singleton()->get(pi.name);
+
if (name=="")
continue;
-
+ bool global=false;
+ if (path.begins_with("*")) {
+ path=path.substr(1,path.length());
+ global=true;
+ }
TreeItem *t = autoload_list->create_item(root);
t->set_text(0,name);
- t->set_text(1,Globals::get_singleton()->get(pi.name));
- t->add_button(1,get_icon("Del","EditorIcons"),0);
+ t->set_text(1,path);
+ t->set_cell_mode(2,TreeItem::CELL_MODE_CHECK);
+ t->set_editable(2,true);
+ t->set_text(2,"Enable");
+ t->set_checked(2,global);
+ t->add_button(3,get_icon("MoveUp","EditorIcons"),1);
+ t->add_button(3,get_icon("MoveDown","EditorIcons"),2);
+ t->add_button(3,get_icon("Del","EditorIcons"),0);
+
}
-}
+ updating_autoload=false;
+}
void ProjectSettings::_bind_methods() {
@@ -1153,6 +1350,7 @@ void ProjectSettings::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_action_adds"),&ProjectSettings::_action_adds);
ObjectTypeDB::bind_method(_MD("_action_persist_toggle"),&ProjectSettings::_action_persist_toggle);
ObjectTypeDB::bind_method(_MD("_action_button_pressed"),&ProjectSettings::_action_button_pressed);
+ ObjectTypeDB::bind_method(_MD("_action_rename"),&ProjectSettings::_action_rename);
ObjectTypeDB::bind_method(_MD("_update_actions"),&ProjectSettings::_update_actions);
ObjectTypeDB::bind_method(_MD("_wait_for_key"),&ProjectSettings::_wait_for_key);
ObjectTypeDB::bind_method(_MD("_add_item"),&ProjectSettings::_add_item);
@@ -1180,6 +1378,7 @@ void ProjectSettings::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_autoload_file_callback"),&ProjectSettings::_autoload_file_callback);
ObjectTypeDB::bind_method(_MD("_update_autoload"),&ProjectSettings::_update_autoload);
ObjectTypeDB::bind_method(_MD("_autoload_delete"),&ProjectSettings::_autoload_delete);
+ ObjectTypeDB::bind_method(_MD("_autoload_edited"),&ProjectSettings::_autoload_edited);
}
@@ -1201,87 +1400,66 @@ ProjectSettings::ProjectSettings(EditorData *p_data) {
//tab_container->set_anchor_and_margin(MARGIN_TOP,ANCHOR_BEGIN, 15 );
//tab_container->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_END, 35 );
- Control *props_base = memnew( Control );
+ VBoxContainer *props_base = memnew( VBoxContainer );
+ props_base->set_alignment(BoxContainer::ALIGN_BEGIN);
+ props_base->set_v_size_flags(Control::SIZE_EXPAND_FILL);
tab_container->add_child(props_base);
props_base->set_name("General");
- globals_editor = memnew( PropertyEditor );
- props_base->add_child(globals_editor);
- globals_editor->set_area_as_parent_rect();
- globals_editor->hide_top_label();
- globals_editor->set_anchor_and_margin(MARGIN_TOP,ANCHOR_BEGIN, 55 );
- globals_editor->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_END, 35 );
- globals_editor->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_BEGIN, 5 );
- globals_editor->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END, 5 );
- globals_editor->set_capitalize_paths(false);
- globals_editor->get_scene_tree()->connect("cell_selected",this,"_item_selected");
- globals_editor->connect("property_toggled",this,"_item_checked");
- globals_editor->connect("property_edited",this,"_settings_prop_edited");
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ props_base->add_child(hbc);
Label *l = memnew( Label );
- props_base->add_child(l);
- l->set_pos(Point2(6,5));
+ hbc->add_child(l);
l->set_text("Category:");
+ category = memnew( LineEdit );
+ category->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ hbc->add_child(category);
+ category->connect("text_entered",this,"_item_adds");
l = memnew( Label );
- l->set_anchor(MARGIN_LEFT,ANCHOR_RATIO);
- props_base->add_child(l);
- l->set_begin(Point2(0.21,5));
+ hbc->add_child(l);
l->set_text("Property:");
- l = memnew( Label );
- l->set_anchor(MARGIN_LEFT,ANCHOR_RATIO);
- props_base->add_child(l);
- l->set_begin(Point2(0.51,5));
- l->set_text("Type:");
-
- category = memnew( LineEdit );
- props_base->add_child(category);
- category->set_anchor(MARGIN_RIGHT,ANCHOR_RATIO);
- category->set_begin( Point2(5,25) );
- category->set_end( Point2(0.20,26) );
- category->connect("text_entered",this,"_item_adds");
-
property = memnew( LineEdit );
- props_base->add_child(property);
- property->set_anchor(MARGIN_LEFT,ANCHOR_RATIO);
- property->set_anchor(MARGIN_RIGHT,ANCHOR_RATIO);
- property->set_begin( Point2(0.21,25) );
- property->set_end( Point2(0.50,26) );
+ property->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ hbc->add_child(property);
property->connect("text_entered",this,"_item_adds");
+ l = memnew( Label );
+ hbc->add_child(l);
+ l->set_text("Type:");
type = memnew( OptionButton );
- props_base->add_child(type);
- type->set_anchor(MARGIN_LEFT,ANCHOR_RATIO);
- type->set_anchor(MARGIN_RIGHT,ANCHOR_RATIO);
- type->set_begin( Point2(0.51,25) );
- type->set_end( Point2(0.70,26) );
+ type->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ hbc->add_child(type);
type->add_item("bool");
type->add_item("int");
type->add_item("float");
type->add_item("string");
Button *add = memnew( Button );
- props_base->add_child(add);
- add->set_anchor(MARGIN_LEFT,ANCHOR_RATIO);
- add->set_anchor(MARGIN_RIGHT,ANCHOR_RATIO);
- add->set_begin( Point2(0.71,25) );
- add->set_end( Point2(0.85,26) );
+ hbc->add_child(add);
add->set_text("Add");
add->connect("pressed",this,"_item_add");
Button *del = memnew( Button );
- props_base->add_child(del);
- del->set_anchor(MARGIN_LEFT,ANCHOR_RATIO);
- del->set_anchor(MARGIN_RIGHT,ANCHOR_END);
- del->set_begin( Point2(0.86,25) );
- del->set_end( Point2(5,26) );
+ hbc->add_child(del);
del->set_text("Del");
del->connect("pressed",this,"_item_del");
- /*
+ globals_editor = memnew( SectionedPropertyEditor );
+ props_base->add_child(globals_editor);
+ //globals_editor->hide_top_label();
+ globals_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ globals_editor->get_property_editor()->set_capitalize_paths(false);
+ globals_editor->get_property_editor()->get_scene_tree()->connect("cell_selected",this,"_item_selected");
+ globals_editor->get_property_editor()->connect("property_toggled",this,"_item_checked",varray(),CONNECT_DEFERRED);
+ globals_editor->get_property_editor()->connect("property_edited",this,"_settings_prop_edited");
+
+/*
Button *save = memnew( Button );
props_base->add_child(save);
@@ -1294,17 +1472,16 @@ ProjectSettings::ProjectSettings(EditorData *p_data) {
save->set_text("Save");
save->connect("pressed",this,"_save");
*/
+
+ hbc = memnew( HBoxContainer );
+ props_base->add_child(hbc);
+
popup_platform = memnew( MenuButton );
popup_platform->set_text("Copy To Platform..");
popup_platform->set_disabled(true);
- props_base->add_child(popup_platform);
+ hbc->add_child(popup_platform);
- popup_platform->set_anchor(MARGIN_LEFT,ANCHOR_BEGIN);
- popup_platform->set_anchor(MARGIN_RIGHT,ANCHOR_BEGIN);
- popup_platform->set_anchor(MARGIN_TOP,ANCHOR_END);
- popup_platform->set_anchor(MARGIN_BOTTOM,ANCHOR_END);
- popup_platform->set_begin( Point2(10,28) );
- popup_platform->set_end( Point2(150,20) );
+ hbc->add_spacer();
List<StringName> ep;
EditorImportExport::get_singleton()->get_export_platforms(&ep);
@@ -1364,12 +1541,17 @@ ProjectSettings::ProjectSettings(EditorData *p_data) {
add_child(popup_add);
popup_add->connect("item_pressed",this,"_add_item");
+ rename_action = memnew( EditorNameDialog );
+ add_child(rename_action);
+ rename_action->set_hide_on_ok(false);
+ rename_action->set_size(Size2(200, 70));
+ rename_action->set_title("Rename Input Action");
+ rename_action->connect("name_confirmed", this,"_action_rename");
+
press_a_key = memnew( ConfirmationDialog );
press_a_key->set_focus_mode(FOCUS_ALL);
add_child(press_a_key);
-
-
l = memnew( Label );
l->set_text("Press a Key..");
l->set_area_as_parent_rect();
@@ -1522,11 +1704,6 @@ ProjectSettings::ProjectSettings(EditorData *p_data) {
HBoxContainer *ahb = memnew( HBoxContainer);
avb->add_child(ahb);
- VBoxContainer *avb_name = memnew( VBoxContainer );
- avb_name->set_h_size_flags(SIZE_EXPAND_FILL);
- autoload_add_name = memnew(LineEdit);
- avb_name->add_margin_child("Node Name:",autoload_add_name);
- ahb->add_child(avb_name);
VBoxContainer *avb_path = memnew( VBoxContainer );
avb_path->set_h_size_flags(SIZE_EXPAND_FILL);
@@ -1537,13 +1714,24 @@ ProjectSettings::ProjectSettings(EditorData *p_data) {
Button *browseaa = memnew( Button("..") );
ahb_path->add_child(browseaa);
browseaa->connect("pressed",this,"_autoload_file_open");
- Button *addaa = memnew( Button("Add") );
- ahb_path->add_child(addaa);
- addaa->connect("pressed",this,"_autoload_add");
avb_path->add_margin_child("Path:",ahb_path);
ahb->add_child(avb_path);
+ VBoxContainer *avb_name = memnew( VBoxContainer );
+ avb_name->set_h_size_flags(SIZE_EXPAND_FILL);
+
+ HBoxContainer *ahb_name = memnew( HBoxContainer );
+ autoload_add_name = memnew(LineEdit);
+ autoload_add_name->set_h_size_flags(SIZE_EXPAND_FILL);
+ ahb_name->add_child(autoload_add_name);
+ avb_name->add_margin_child("Node Name:",ahb_name);
+ Button *addaa = memnew( Button("Add") );
+ ahb_name->add_child(addaa);
+ addaa->connect("pressed",this,"_autoload_add");
+
+ ahb->add_child(avb_name);
+
autoload_list = memnew( Tree );
autoload_list->set_v_size_flags(SIZE_EXPAND_FILL);
avb->add_margin_child("List:",autoload_list,true);
@@ -1553,11 +1741,24 @@ ProjectSettings::ProjectSettings(EditorData *p_data) {
autoload_file_open->set_mode(EditorFileDialog::MODE_OPEN_FILE);
autoload_file_open->connect("file_selected",this,"_autoload_file_callback");
- autoload_list->set_columns(2);
+ autoload_list->set_columns(4);
autoload_list->set_column_titles_visible(true);
- autoload_list->set_column_title(0,"name");
- autoload_list->set_column_title(1,"path");
+ autoload_list->set_column_title(0,"Name");
+ autoload_list->set_column_expand(0,true);
+ autoload_list->set_column_min_width(0,100);
+ autoload_list->set_column_title(1,"Path");
+ autoload_list->set_column_expand(1,true);
+ autoload_list->set_column_min_width(1,100);
+ autoload_list->set_column_title(2,"Singleton");
+ autoload_list->set_column_expand(2,false);
+ autoload_list->set_column_min_width(2,80);
+ autoload_list->set_column_expand(3,false);
+ autoload_list->set_column_min_width(3,80);
+
autoload_list->connect("button_pressed",this,"_autoload_delete");
+ autoload_list->connect("item_edited",this,"_autoload_edited");
+
+ updating_autoload=false;
}
diff --git a/tools/editor/project_settings.h b/tools/editor/project_settings.h
index 7c91254764..cbf24e7bfd 100644
--- a/tools/editor/project_settings.h
+++ b/tools/editor/project_settings.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,6 +34,7 @@
#include "optimized_save_dialog.h"
#include "undo_redo.h"
#include "editor_data.h"
+#include "editor_name_dialog.h"
//#include "project_export_settings.h"
class ProjectSettings : public AcceptDialog {
@@ -45,7 +46,7 @@ class ProjectSettings : public AcceptDialog {
EditorData *data;
UndoRedo *undo_redo;
- PropertyEditor *globals_editor;
+ SectionedPropertyEditor *globals_editor;
ConfirmationDialog *message;
LineEdit *category;
@@ -60,6 +61,8 @@ class ProjectSettings : public AcceptDialog {
Label *device_index_label;
MenuButton *popup_platform;
+ EditorNameDialog *rename_action;
+
LineEdit *action_name;
Tree *input_editor;
bool setting;
@@ -86,8 +89,10 @@ class ProjectSettings : public AcceptDialog {
void _update_autoload();
void _autoload_file_callback(const String& p_path);
void _autoload_add();
+ void _autoload_edited();
void _autoload_file_open();
void _autoload_delete(Object *p_item,int p_column, int p_button);
+ bool updating_autoload;
void _item_selected();
@@ -100,6 +105,7 @@ class ProjectSettings : public AcceptDialog {
void _action_adds(String);
void _action_add();
+ void _action_rename(const String& p_name);
void _device_input_add();
void _item_checked(const String& p_item, bool p_check);
diff --git a/tools/editor/property_editor.cpp b/tools/editor/property_editor.cpp
index 2fa8b98ff1..286a8f25b1 100644
--- a/tools/editor/property_editor.cpp
+++ b/tools/editor/property_editor.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -39,17 +39,22 @@
#include "editor_settings.h"
#include "editor_import_export.h"
#include "editor_node.h"
+#include "multi_node_edit.h"
+#include "array_property_edit.h"
+#include "editor_help.h"
+#include "scene/resources/packed_scene.h"
+
void CustomPropertyEditor::_notification(int p_what) {
-
+
if (p_what==NOTIFICATION_DRAW) {
-
+
RID ci = get_canvas_item();
- get_stylebox("panel","PopupMenu")->draw(ci,Rect2(Point2(),get_size()));
+ get_stylebox("panel","PopupMenu")->draw(ci,Rect2(Point2(),get_size()));
/*
if (v.get_type()==Variant::COLOR) {
-
+
VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2( 10,10,60, get_size().height-20 ), v );
}*/
}
@@ -84,13 +89,23 @@ void CustomPropertyEditor::_menu_option(int p_which) {
case OBJ_MENU_LOAD: {
file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
- List<String> extensions;
String type=(hint==PROPERTY_HINT_RESOURCE_TYPE)?hint_text:String();
- ResourceLoader::get_recognized_extensions_for_type(type,&extensions);
- file->clear_filters();
+ List<String> extensions;
+ for (int i=0;i<type.get_slice_count(",");i++) {
+
+ ResourceLoader::get_recognized_extensions_for_type(type.get_slice(",",i),&extensions);
+ }
+
+ Set<String> valid_extensions;
for (List<String>::Element *E=extensions.front();E;E=E->next()) {
+ valid_extensions.insert(E->get());
+ }
+
+ file->clear_filters();
+ for (Set<String>::Element *E=valid_extensions.front();E;E=E->next()) {
+
file->add_filter("*."+E->get()+" ; "+E->get().to_upper() );
}
@@ -210,11 +225,11 @@ void CustomPropertyEditor::_menu_option(int p_which) {
}
Variant CustomPropertyEditor::get_variant() const {
-
- return v;
+
+ return v;
}
String CustomPropertyEditor::get_name() const {
-
+
return name;
}
@@ -232,9 +247,11 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty
inheritors_array.clear();
text_edit->hide();
easing_draw->hide();
-
+ spinbox->hide();
+ slider->hide();
+
for (int i=0;i<MAX_VALUE_EDITORS;i++) {
-
+
value_editor[i]->hide();
value_label[i]->hide();
if (i<4)
@@ -242,8 +259,8 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty
}
for (int i=0;i<MAX_ACTION_BUTTONS;i++) {
-
- action_buttons[i]->hide();
+
+ action_buttons[i]->hide();
}
for(int i=0;i<20;i++)
@@ -253,11 +270,49 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty
switch(type) {
-
+
case Variant::INT:
case Variant::REAL: {
- if (hint==PROPERTY_HINT_ALL_FLAGS) {
+ if (hint==PROPERTY_HINT_RANGE) {
+
+ int c = hint_text.get_slice_count(",");
+ float min=0,max=100,step=1;
+ if (c>=1) {
+
+ if (!hint_text.get_slice(",",0).empty())
+ min=hint_text.get_slice(",",0).to_double();
+ }
+ if (c>=2) {
+
+ if (!hint_text.get_slice(",",1).empty())
+ max=hint_text.get_slice(",",1).to_double();
+ }
+
+ if (type==Variant::REAL && c>=3) {
+
+ if (!hint_text.get_slice(",",2).empty())
+ step= hint_text.get_slice(",",2).to_double();
+ }
+
+ if (c>=4 && hint_text.get_slice(",",3)=="slider") {
+ slider->set_min(min);
+ slider->set_max(max);
+ slider->set_step((type==Variant::REAL) ? step : 1);
+ slider->set_val(v);
+ slider->show();
+ set_size(Size2(110,30));
+ } else {
+ spinbox->set_min(min);
+ spinbox->set_max(max);
+ spinbox->set_step((type==Variant::REAL) ? step : 1);
+ spinbox->set_val(v);
+ spinbox->show();
+ set_size(Size2(70,35));
+ }
+
+
+ } else if (hint==PROPERTY_HINT_ALL_FLAGS) {
uint32_t flgs = v;
for(int i=0;i<2;i++) {
@@ -405,7 +460,7 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty
value_editor[3]->set_text( String::num( r.size.y) );
} break;
case Variant::VECTOR3: {
-
+
List<String> names;
names.push_back("x");
names.push_back("y");
@@ -417,7 +472,7 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty
value_editor[2]->set_text( String::num( vec.z) );
} break;
case Variant::PLANE: {
-
+
List<String> names;
names.push_back("x");
names.push_back("y");
@@ -429,10 +484,10 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty
value_editor[1]->set_text( String::num( plane.normal.y ) );
value_editor[2]->set_text( String::num( plane.normal.z ) );
value_editor[3]->set_text( String::num( plane.d ) );
-
+
} break;
case Variant::QUAT: {
-
+
List<String> names;
names.push_back("x");
names.push_back("y");
@@ -447,7 +502,7 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty
} break;
case Variant::_AABB: {
-
+
List<String> names;
names.push_back("px");
names.push_back("py");
@@ -456,7 +511,7 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty
names.push_back("sy");
names.push_back("sz");
config_value_editors(6,3,16,names);
-
+
AABB aabb=v;
value_editor[0]->set_text( String::num( aabb.pos.x ) );
value_editor[1]->set_text( String::num( aabb.pos.y ) );
@@ -464,7 +519,7 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty
value_editor[3]->set_text( String::num( aabb.size.x ) );
value_editor[4]->set_text( String::num( aabb.size.y ) );
value_editor[5]->set_text( String::num( aabb.size.z ) );
-
+
} break;
case Variant::MATRIX32: {
@@ -485,7 +540,7 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty
} break;
case Variant::MATRIX3: {
-
+
List<String> names;
names.push_back("xx");
names.push_back("xy");
@@ -497,17 +552,17 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty
names.push_back("zy");
names.push_back("zz");
config_value_editors(9,3,16,names);
-
+
Matrix3 basis=v;
for(int i=0;i<9;i++) {
-
+
value_editor[i]->set_text( String::num( basis.elements[i/3][i%3] ) );
}
-
+
} break;
case Variant::TRANSFORM: {
-
-
+
+
List<String> names;
names.push_back("xx");
names.push_back("xy");
@@ -522,25 +577,25 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty
names.push_back("zz");
names.push_back("zo");
config_value_editors(12,4,16,names);
-
+
Transform tr=v;
for(int i=0;i<9;i++) {
-
+
value_editor[(i/3)*4+i%3]->set_text( String::num( tr.basis.elements[i/3][i%3] ) );
}
-
+
value_editor[3]->set_text( String::num( tr.origin.x ) );
value_editor[7]->set_text( String::num( tr.origin.y ) );
value_editor[11]->set_text( String::num( tr.origin.z ) );
-
+
} break;
case Variant::COLOR: {
-
+
color_picker->show();
color_picker->set_edit_alpha(hint!=PROPERTY_HINT_COLOR_NO_ALPHA);
color_picker->set_color(v);
- set_size( Size2(350, color_picker->get_combined_minimum_size().height+10));
+ set_size( Size2(300, color_picker->get_combined_minimum_size().height+10));
/*
int ofs=80;
int m=10;
@@ -549,13 +604,13 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty
float values[4]={c.r,c.g,c.b,c.a};
for (int i=0;i<4;i++) {
int y=m+i*h;
-
+
value_editor[i]->show();
- value_label[i]->show();
+ value_label[i]->show();
value_label[i]->set_pos(Point2(ofs,y));
scroll[i]->set_min(0);
scroll[i]->set_max(1.0);
- scroll[i]->set_page(0);
+ scroll[i]->set_page(0);
scroll[i]->set_pos(Point2(ofs+15,y+Math::floor((h-scroll[i]->get_minimum_size().height)/2.0)));
scroll[i]->set_val(values[i]);
scroll[i]->set_size(Size2(120,1));
@@ -563,30 +618,30 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty
value_editor[i]->set_pos(Point2(ofs+140,y));
value_editor[i]->set_size(Size2(40,h));
value_editor[i]->set_text( String::num(values[i],2 ));
-
+
}
-
+
value_label[0]->set_text("R");
value_label[1]->set_text("G");
value_label[2]->set_text("B");
value_label[3]->set_text("A");
-
+
Size2 new_size = value_editor[3]->get_pos() + value_editor[3]->get_size() + Point2(10,10);
set_size( new_size );
*/
-
+
} break;
case Variant::IMAGE: {
-
+
List<String> names;
names.push_back("New");
names.push_back("Load");
names.push_back("Clear");
config_action_buttons(names);
-
+
} break;
case Variant::NODE_PATH: {
-
+
List<String> names;
names.push_back("Assign");
names.push_back("Clear");
@@ -594,7 +649,7 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty
} break;
case Variant::OBJECT: {
-
+
if (hint!=PROPERTY_HINT_RESOURCE_TYPE)
break;
@@ -614,9 +669,9 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty
Set<String> valid_inheritors;
valid_inheritors.insert(base);
- List<String> inheritors;
+ List<StringName> inheritors;
ObjectTypeDB::get_inheriters_from(base.strip_edges(),&inheritors);
- List<String>::Element *E=inheritors.front();
+ List<StringName>::Element *E=inheritors.front();
while(E) {
valid_inheritors.insert(E->get());
E=E->next();
@@ -672,7 +727,17 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty
RES cb=EditorSettings::get_singleton()->get_resource_clipboard();
- bool paste_valid=cb.is_valid() && (hint_text=="" || ObjectTypeDB::is_type(cb->get_type(),hint_text));
+ bool paste_valid=false;
+ if (cb.is_valid()) {
+ if (hint_text=="")
+ paste_valid=true;
+ else
+ for (int i = 0; i < hint_text.get_slice_count(",");i++)
+ if (ObjectTypeDB::is_type(cb->get_type(),hint_text.get_slice(",",i))) {
+ paste_valid=true;
+ break;
+ }
+ }
if (!RES(v).is_null() || paste_valid) {
menu->add_separator();
@@ -700,40 +765,40 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty
} break;
case Variant::INPUT_EVENT: {
-
-
+
+
} break;
case Variant::DICTIONARY: {
-
-
+
+
} break;
case Variant::RAW_ARRAY: {
-
-
+
+
} break;
case Variant::INT_ARRAY: {
-
-
+
+
} break;
case Variant::REAL_ARRAY: {
-
-
+
+
} break;
case Variant::STRING_ARRAY: {
-
-
+
+
} break;
case Variant::VECTOR3_ARRAY: {
-
-
+
+
} break;
case Variant::COLOR_ARRAY: {
-
-
+
+
} break;
default: {}
- }
-
+ }
+
updating=false;
return true;
}
@@ -741,7 +806,7 @@ bool CustomPropertyEditor::edit(Object* p_owner,const String& p_name,Variant::Ty
void CustomPropertyEditor::_file_selected(String p_file) {
switch(type) {
-
+
case Variant::STRING: {
if (hint==PROPERTY_HINT_FILE || hint==PROPERTY_HINT_DIR) {
@@ -860,28 +925,40 @@ void CustomPropertyEditor::_color_changed(const Color& p_color) {
void CustomPropertyEditor::_node_path_selected(NodePath p_path) {
- if (owner && owner->is_type("Node")) {
+ if (owner) {
+
+ Node *node=NULL;
+
+ if (owner->is_type("Node"))
+ node = owner->cast_to<Node>();
+ else if (owner->is_type("ArrayPropertyEdit"))
+ node = owner->cast_to<ArrayPropertyEdit>()->get_node();
+
+ if (!node) {
+ v=p_path;
+ emit_signal("variant_changed");
+ call_deferred("hide"); //to not mess with dialogs
+ return;
+ }
- Node *node = owner->cast_to<Node>();
Node *tonode=node->get_node(p_path);
if (tonode) {
-
p_path=node->get_path_to(tonode);
}
-
}
v=p_path;
emit_signal("variant_changed");
+ call_deferred("hide"); //to not mess with dialogs
}
void CustomPropertyEditor::_action_pressed(int p_which) {
- if (updating)
+ if (updating)
return;
-
+
switch(type) {
case Variant::INT: {
@@ -964,7 +1041,7 @@ void CustomPropertyEditor::_action_pressed(int p_which) {
} break;
case Variant::NODE_PATH: {
-
+
if (p_which==0) {
@@ -975,60 +1052,61 @@ void CustomPropertyEditor::_action_pressed(int p_which) {
v=NodePath();
emit_signal("variant_changed");
- }
+ hide();
+ }
} break;
case Variant::OBJECT: {
-
+
if (p_which==0) {
-
+
ERR_FAIL_COND( inheritors_array.empty() );
String intype=inheritors_array[0];
-
+
if (hint==PROPERTY_HINT_RESOURCE_TYPE) {
-
+
Object *obj = ObjectTypeDB::instance(intype);
ERR_BREAK( !obj );
Resource *res=obj->cast_to<Resource>();
ERR_BREAK( !res );
-
+
v=Ref<Resource>(res).get_ref_ptr();
emit_signal("variant_changed");
hide();
-
+
}
} else if (p_which==1) {
-
+
file->set_access(EditorFileDialog::ACCESS_RESOURCES);
file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
List<String> extensions;
String type=(hint==PROPERTY_HINT_RESOURCE_TYPE)?hint_text:String();
-
+
ResourceLoader::get_recognized_extensions_for_type(type,&extensions);
file->clear_filters();
for (List<String>::Element *E=extensions.front();E;E=E->next()) {
-
+
file->add_filter("*."+E->get()+" ; "+E->get().to_upper() );
-
+
}
-
+
file->popup_centered_ratio();
-
+
} else if (p_which==2) {
-
+
RefPtr RefPtr=v;
if (!RefPtr.is_null()) {
emit_signal("resource_edit_request");
- hide();
+ hide();
}
-
+
} else if (p_which==3) {
-
-
+
+
v=Variant();
emit_signal("variant_changed");
hide();
@@ -1071,7 +1149,7 @@ void CustomPropertyEditor::_action_pressed(int p_which) {
emit_signal("variant_changed");
hide();
}
-
+
} break;
case Variant::IMAGE: {
@@ -1110,16 +1188,16 @@ void CustomPropertyEditor::_action_pressed(int p_which) {
}
void CustomPropertyEditor::_scroll_modified(double p_value) {
-
- if (updating)
+
+ if (updating)
return;
/*
switch(type) {
-
+
case Variant::COLOR: {
-
+
for (int i=0;i<4;i++) {
-
+
value_editor[i]->set_text( String::num(scroll[i]->get_val(),2) );
}
Color c;
@@ -1144,7 +1222,7 @@ void CustomPropertyEditor::_drag_easing(const InputEvent& p_ev) {
float rel = p_ev.mouse_motion.relative_x;
if (rel==0)
- return;
+ return;
bool flip=hint_text=="attenuation";
@@ -1227,7 +1305,7 @@ void CustomPropertyEditor::_text_edit_changed() {
}
void CustomPropertyEditor::_modified(String p_string) {
-
+
if (updating)
return;
updating=true;
@@ -1268,17 +1346,17 @@ void CustomPropertyEditor::_modified(String p_string) {
} break;
case Variant::VECTOR3: {
-
+
Vector3 vec;
vec.x=value_editor[0]->get_text().to_double();
vec.y=value_editor[1]->get_text().to_double();
vec.z=value_editor[2]->get_text().to_double();
v=vec;
emit_signal("variant_changed");
-
+
} break;
case Variant::PLANE: {
-
+
Plane pl;
pl.normal.x=value_editor[0]->get_text().to_double();
pl.normal.y=value_editor[1]->get_text().to_double();
@@ -1286,10 +1364,10 @@ void CustomPropertyEditor::_modified(String p_string) {
pl.d=value_editor[3]->get_text().to_double();
v=pl;
emit_signal("variant_changed");
-
+
} break;
case Variant::QUAT: {
-
+
Quat q;
q.x=value_editor[0]->get_text().to_double();
q.y=value_editor[1]->get_text().to_double();
@@ -1297,10 +1375,10 @@ void CustomPropertyEditor::_modified(String p_string) {
q.w=value_editor[3]->get_text().to_double();
v=q;
emit_signal("variant_changed");
-
+
} break;
case Variant::_AABB: {
-
+
Vector3 pos;
pos.x=value_editor[0]->get_text().to_double();
pos.y=value_editor[1]->get_text().to_double();
@@ -1309,14 +1387,14 @@ void CustomPropertyEditor::_modified(String p_string) {
size.x=value_editor[3]->get_text().to_double();
size.y=value_editor[4]->get_text().to_double();
size.z=value_editor[5]->get_text().to_double();
-
+
v=AABB(pos,size);
emit_signal("variant_changed");
-
+
} break;
case Variant::MATRIX32: {
- Matrix3 m;
+ Matrix32 m;
for(int i=0;i<6;i++) {
m.elements[i/2][i%2]=value_editor[i]->get_text().to_double();
@@ -1327,39 +1405,39 @@ void CustomPropertyEditor::_modified(String p_string) {
} break;
case Variant::MATRIX3: {
-
+
Matrix3 m;
for(int i=0;i<9;i++) {
-
+
m.elements[i/3][i%3]=value_editor[i]->get_text().to_double();
}
-
+
v=m;
emit_signal("variant_changed");
-
+
} break;
case Variant::TRANSFORM: {
-
+
Matrix3 basis;
for(int i=0;i<9;i++) {
-
+
basis.elements[i/3][i%3]=value_editor[(i/3)*4+i%3]->get_text().to_double();
}
-
+
Vector3 origin;
origin.x=value_editor[3]->get_text().to_double();
origin.y=value_editor[7]->get_text().to_double();
origin.z=value_editor[11]->get_text().to_double();
-
+
v=Transform(basis,origin);
emit_signal("variant_changed");
-
-
+
+
} break;
case Variant::COLOR: {
/*
for (int i=0;i<4;i++) {
-
+
scroll[i]->set_val( value_editor[i]->get_text().to_double() );
}
Color c;
@@ -1373,51 +1451,57 @@ void CustomPropertyEditor::_modified(String p_string) {
*/
} break;
case Variant::IMAGE: {
-
-
+
+
} break;
case Variant::NODE_PATH: {
-
-
- } break;
+
+
+ } break;
case Variant::INPUT_EVENT: {
-
-
+
+
} break;
case Variant::DICTIONARY: {
-
-
+
+
} break;
case Variant::RAW_ARRAY: {
-
-
+
+
} break;
case Variant::INT_ARRAY: {
-
-
+
+
} break;
case Variant::REAL_ARRAY: {
-
-
+
+
} break;
case Variant::STRING_ARRAY: {
-
-
+
+
} break;
case Variant::VECTOR3_ARRAY: {
-
-
+
+
} break;
case Variant::COLOR_ARRAY: {
-
-
+
+
} break;
default: {}
- }
-
+ }
+
updating=false;
}
+void CustomPropertyEditor::_range_modified(double p_value)
+{
+ v=p_value;
+ emit_signal("variant_changed");
+}
+
void CustomPropertyEditor::_focus_enter() {
switch(type) {
case Variant::REAL:
@@ -1474,10 +1558,10 @@ void CustomPropertyEditor::config_action_buttons(const List<String>& p_strings)
set_size( Size2( w, m*2+(h+m)*p_strings.size() ) );
for (int i=0;i<MAX_ACTION_BUTTONS;i++) {
-
+
if (i<p_strings.size()) {
action_buttons[i]->show();
- action_buttons[i]->set_text(p_strings[i]);
+ action_buttons[i]->set_text(p_strings[i]);
action_buttons[i]->set_pos( Point2( m, m+i*(h+m) ));
action_buttons[i]->set_size( Size2( w-m*2, h ) );
action_buttons[i]->set_flat(true);
@@ -1485,29 +1569,29 @@ void CustomPropertyEditor::config_action_buttons(const List<String>& p_strings)
action_buttons[i]->hide();
}
}
-
-
+
+
}
void CustomPropertyEditor::config_value_editors(int p_amount, int p_columns,int p_label_w,const List<String>& p_strings) {
-
+
int w=80;
int h=20;
int m=10;
-
+
int rows=((p_amount-1)/p_columns)+1;
-
+
set_size( Size2( m*(1+p_columns)+(w+p_label_w)*p_columns, m*(1+rows)+h*rows ) );
-
+
for (int i=0;i<MAX_VALUE_EDITORS;i++) {
-
+
int c=i%p_columns;
int r=i/p_columns;
-
+
if (i<p_amount) {
value_editor[i]->show();
value_label[i]->show();
- value_label[i]->set_text(i<p_strings.size()?p_strings[i]:String(""));
+ value_label[i]->set_text(i<p_strings.size()?p_strings[i]:String(""));
value_editor[i]->set_pos( Point2( m+p_label_w+c*(w+m+p_label_w), m+r*(h+m) ));
value_editor[i]->set_size( Size2( w, h ) );
value_label[i]->set_pos( Point2( m+c*(w+m+p_label_w), m+r*(h+m) ) );
@@ -1517,16 +1601,17 @@ void CustomPropertyEditor::config_value_editors(int p_amount, int p_columns,int
value_label[i]->hide();
}
}
-
-
-
+
+
+
}
void CustomPropertyEditor::_bind_methods() {
-
+
ObjectTypeDB::bind_method("_focus_enter", &CustomPropertyEditor::_focus_enter);
ObjectTypeDB::bind_method("_focus_exit", &CustomPropertyEditor::_focus_exit);
ObjectTypeDB::bind_method("_modified",&CustomPropertyEditor::_modified);
+ ObjectTypeDB::bind_method("_range_modified", &CustomPropertyEditor::_range_modified);
ObjectTypeDB::bind_method("_scroll_modified",&CustomPropertyEditor::_scroll_modified);
ObjectTypeDB::bind_method("_action_pressed",&CustomPropertyEditor::_action_pressed);
ObjectTypeDB::bind_method("_file_selected",&CustomPropertyEditor::_file_selected);
@@ -1543,13 +1628,13 @@ void CustomPropertyEditor::_bind_methods() {
ADD_SIGNAL( MethodInfo("resource_edit_request") );
}
CustomPropertyEditor::CustomPropertyEditor() {
-
-
+
+
read_only=false;
updating=false;
-
+
for (int i=0;i<MAX_VALUE_EDITORS;i++) {
-
+
value_editor[i]=memnew( LineEdit );
add_child( value_editor[i] );
value_label[i]=memnew( Label );
@@ -1560,17 +1645,17 @@ CustomPropertyEditor::CustomPropertyEditor() {
value_editor[i]->connect("focus_enter", this, "_focus_enter");
value_editor[i]->connect("focus_exit", this, "_focus_exit");
}
-
+
for(int i=0;i<4;i++) {
-
+
scroll[i] = memnew( HScrollBar );
scroll[i]->hide();
scroll[i]->set_min(0);
scroll[i]->set_max(1.0);
- scroll[i]->set_step(0.01);
+ scroll[i]->set_step(0.01);
add_child(scroll[i]);
scroll[i]->connect("value_changed", this,"_scroll_modified");
-
+
}
for(int i=0;i<20;i++) {
@@ -1594,15 +1679,15 @@ CustomPropertyEditor::CustomPropertyEditor() {
text_edit->connect("text_changed",this,"_text_edit_changed");
for (int i=0;i<MAX_ACTION_BUTTONS;i++) {
-
+
action_buttons[i]=memnew(Button);
- action_buttons[i]->hide();
+ action_buttons[i]->hide();
add_child(action_buttons[i]);
Vector<Variant> binds;
binds.push_back(i);
action_buttons[i]->connect("pressed", this,"_action_pressed",binds);
}
-
+
color_picker = memnew( ColorPicker );
add_child(color_picker);
color_picker->hide();
@@ -1615,7 +1700,7 @@ CustomPropertyEditor::CustomPropertyEditor() {
file = memnew ( EditorFileDialog );
add_child(file);
file->hide();
-
+
file->connect("file_selected", this,"_file_selected");
file->connect("dir_selected", this,"_file_selected");
@@ -1623,12 +1708,12 @@ CustomPropertyEditor::CustomPropertyEditor() {
error->set_title("Error!");
add_child(error);
//error->get_cancel()->hide();
-
+
type_button = memnew( MenuButton );
add_child(type_button);
type_button->hide();
type_button->get_popup()->connect("item_pressed", this,"_type_create_selected");
-
+
scene_tree = memnew( SceneTreeDialog );
add_child(scene_tree);
@@ -1650,52 +1735,182 @@ CustomPropertyEditor::CustomPropertyEditor() {
menu = memnew(PopupMenu);
add_child(menu);
menu->connect("item_pressed",this,"_menu_option");
-}
+ spinbox = memnew ( SpinBox );
+ add_child(spinbox);
+ spinbox->set_area_as_parent_rect(5);
+ spinbox->connect("value_changed",this,"_range_modified");
+ slider = memnew ( HSlider );
+ add_child(slider);
+ slider->set_area_as_parent_rect(5);
+ slider->connect("value_changed",this,"_range_modified");
+}
-Node *PropertyEditor::get_instanced_node() {
+bool PropertyEditor::_might_be_in_instance() {
- //this sucks badly
if (!obj)
return NULL;
Node *node = obj->cast_to<Node>();
+
+ Node* edited_scene =EditorNode::get_singleton()->get_edited_scene();
+
+ bool might_be=false;
+
+ while(node) {
+
+ if (node->get_scene_instance_state().is_valid()) {
+ might_be=true;
+ break;
+ }
+ if (node==edited_scene) {
+ if (node->get_scene_inherited_state().is_valid()) {
+ might_be=true;
+ break;
+ }
+ might_be=false;
+ break;
+ }
+ node=node->get_owner();
+ }
+
+ return might_be;
+
+}
+
+bool PropertyEditor::_get_instanced_node_original_property(const StringName& p_prop, Variant& value) {
+
+ Node *node = obj->cast_to<Node>();
+
if (!node)
- return NULL;
+ return false;
+
+ Node *orig=node;
+
+ Node* edited_scene =EditorNode::get_singleton()->get_edited_scene();
+
+ bool found=false;
+
+// print_line("for prop - "+String(p_prop));
+
+
+ while(node) {
+
+ Ref<SceneState> ss;
+
+ if (node==edited_scene) {
+ ss=node->get_scene_inherited_state();
+
+ } else {
+ ss=node->get_scene_instance_state();
+ }
+ // print_line("at - "+String(edited_scene->get_path_to(node)));
+
+ if (ss.is_valid()) {
+
+ NodePath np = node->get_path_to(orig);
+ int node_idx = ss->find_node_by_path(np);
+ // print_line("\t valid, nodeidx "+itos(node_idx));
+ if (node_idx>=0) {
+ bool lfound=false;
+ Variant lvar;
+ lvar=ss->get_property_value(node_idx,p_prop,lfound);
+ if (lfound) {
+
+ found=true;
+ value=lvar;
+ // print_line("\t found value "+String(value));
+ }
+ }
+ }
+ if (node==edited_scene) {
+ //just in case
+ break;
+ }
+ node=node->get_owner();
+
+ }
+
+ return found;
+}
+
+bool PropertyEditor::_is_property_different(const Variant& p_current, const Variant& p_orig,int p_usage) {
+
+
+ {
+ Node *node = obj->cast_to<Node>();
+ if (!node)
+ return false;
+
+ Node* edited_scene =EditorNode::get_singleton()->get_edited_scene();
+ bool found_state=false;
+
+ // print_line("for prop - "+String(p_prop));
+
+
+ while(node) {
+
+ Ref<SceneState> ss;
+
+ if (node==edited_scene) {
+ ss=node->get_scene_inherited_state();
+
+ } else {
+ ss=node->get_scene_instance_state();
+ }
+
+ if (ss.is_valid()) {
+ found_state=true;
+ }
+ if (node==edited_scene) {
+ //just in case
+ break;
+ }
+ node=node->get_owner();
+ }
+
+ if (!found_state)
+ return false; //pointless to check if we are not comparing against anything.
+ }
+
+ if (p_orig.get_type()==Variant::NIL) {
+
- if (node->get_filename()=="")
- return NULL;
- if (!node->get_owner())
- return NULL; //scene root i guess
+ //special cases
+ if (p_current.is_zero() && p_usage&PROPERTY_USAGE_STORE_IF_NONZERO)
+ return false;
+ if (p_current.is_one() && p_usage&PROPERTY_USAGE_STORE_IF_NONONE)
+ return false;
+ }
- return node;
+ return bool(Variant::evaluate(Variant::OP_NOT_EQUAL,p_current,p_orig));
}
TreeItem *PropertyEditor::find_item(TreeItem *p_item,const String& p_name) {
-
-
+
+
if (!p_item)
return NULL;
-
+
String name = p_item->get_metadata(1);
-
+
if (name==p_name) {
-
+
return p_item;
}
-
+
TreeItem *c=p_item->get_children();
-
+
while (c) {
-
+
TreeItem *found = find_item(c,p_name);
if (found)
return found;
c=c->get_next();
}
-
+
return NULL;
}
@@ -1718,9 +1933,9 @@ void PropertyEditor::_changed_callbacks(Object *p_changed,const String& p_prop)
if (p_prop==String())
update_tree_pending=true;
else {
-
+
pending[p_prop]=p_prop;
-
+
}
}
@@ -1732,7 +1947,7 @@ void PropertyEditor::update_property(const String& p_prop) {
void PropertyEditor::set_item_text(TreeItem *p_item, int p_type, const String& p_name, int p_hint, const String& p_hint_text) {
-
+
switch( p_type ) {
case Variant::BOOL: {
@@ -1825,7 +2040,7 @@ void PropertyEditor::set_item_text(TreeItem *p_item, int p_type, const String& p
} break;
case Variant::IMAGE: {
-
+
Image img = obj->get( p_name );
if (img.empty())
p_item->set_text(1,"[Image (empty)]");
@@ -1904,7 +2119,68 @@ void PropertyEditor::set_item_text(TreeItem *p_item, int p_type, const String& p
} break;
default: {};
}
-
+
+}
+
+
+void PropertyEditor::_check_reload_status(const String&p_name, TreeItem* item) {
+
+ bool has_reload=false;
+ int found=-1;
+
+ for(int i=0;i<item->get_button_count(1);i++) {
+
+ if (item->get_button_id(1,i)==3) {
+ found=i;
+ break;
+ }
+ }
+
+ if (_might_be_in_instance()) {
+
+
+ Variant vorig;
+ Dictionary d=item->get_metadata(0);
+ int usage = d.has("usage")?int(int(d["usage"])&(PROPERTY_USAGE_STORE_IF_NONONE|PROPERTY_USAGE_STORE_IF_NONZERO)):0;
+
+
+ if (_get_instanced_node_original_property(p_name,vorig) || usage) {
+ Variant v = obj->get(p_name);
+
+ bool changed = _is_property_different(v,vorig,usage);
+
+ if ((found!=-1)!=changed) {
+
+ if (changed) {
+
+ has_reload=true;
+ } else {
+
+ }
+
+ }
+
+ }
+
+
+
+ }
+
+ if (!has_reload && !obj->get_script().is_null()) {
+ Ref<Script> scr = obj->get_script();
+ Variant orig_value;
+ if (scr->get_property_default_value(p_name,orig_value)) {
+ if (orig_value!=obj->get(p_name)) {
+ has_reload=true;
+ }
+ }
+ }
+
+ if (found!=-1 && !has_reload) {
+ item->erase_button(1,found);
+ } else if (found==-1 && has_reload) {
+ item->add_button(1,get_icon("Reload","EditorIcons"),3);
+ }
}
void PropertyEditor::_notification(int p_what) {
@@ -1919,10 +2195,10 @@ void PropertyEditor::_notification(int p_what) {
edit(NULL);
}
-
+
if (p_what==NOTIFICATION_FIXED_PROCESS) {
-
-
+
+
if (refresh_countdown>0) {
refresh_countdown-=get_fixed_process_delta_time();
if (refresh_countdown<=0) {
@@ -1932,63 +2208,32 @@ void PropertyEditor::_notification(int p_what) {
}
changing=true;
-
+
if (update_tree_pending) {
update_tree();
update_tree_pending=false;
-
+
} else {
-
- const String *k=NULL;
+
+ const String *k=NULL;
while ((k=pending.next(k))) {
-
+
TreeItem * item = find_item(tree->get_root(),*k);
if (!item)
continue;
-
- if (get_instanced_node()) {
-
- Dictionary d = get_instanced_node()->get_instance_state();
- if (d.has(*k)) {
- Variant v = obj->get(*k);
- Variant vorig = d[*k];
-
- int found=-1;
- for(int i=0;i<item->get_button_count(1);i++) {
-
- if (item->get_button_id(1,i)==3) {
- found=i;
- break;
- }
- }
- bool changed = ! (v==vorig);
+ _check_reload_status(*k,item);
- if ((found!=-1)!=changed) {
-
- if (changed) {
-
- item->add_button(1,get_icon("Reload","EditorIcons"),3);
- } else {
-
- item->erase_button(1,found);
- }
-
- }
-
- }
-
- }
- Dictionary d=item->get_metadata(0);
+ Dictionary d=item->get_metadata(0);
set_item_text(item,d["type"],d["name"],d["hint"],d["hint_text"]);
- }
+ }
}
-
+
pending.clear();
-
+
changing=false;
-
+
}
}
@@ -2019,9 +2264,9 @@ TreeItem *PropertyEditor::get_parent_node(String p_path,HashMap<String,TreeItem*
}
item->set_editable(0,false);
- item->set_selectable(0,false);
+ item->set_selectable(0,subsection_selectable);
item->set_editable(1,false);
- item->set_selectable(1,false);
+ item->set_selectable(1,subsection_selectable);
if (item->get_parent()==root) {
@@ -2046,32 +2291,42 @@ void PropertyEditor::_refresh_item(TreeItem *p_item) {
if (name!=String()) {
- if (get_instanced_node()) {
- Dictionary d = get_instanced_node()->get_instance_state();
- if (d.has(name)) {
- Variant v = obj->get(name);
- Variant vorig = d[name];
+ _check_reload_status(name,p_item);
+#if 0
+ bool has_reload=false;
- int found=-1;
- for(int i=0;i<p_item->get_button_count(1);i++) {
+ int found=-1;
+ for(int i=0;i<p_item->get_button_count(1);i++) {
- if (p_item->get_button_id(1,i)==3) {
- found=i;
- break;
- }
- }
+ if (p_item->get_button_id(1,i)==3) {
+ found=i;
+ break;
+ }
+ }
+
+ if (_might_be_in_instance()) {
+
+ Variant vorig;
+ Dictionary d=p_item->get_metadata(0);
+ int usage = d.has("usage")?int(int(d["usage"])&(PROPERTY_USAGE_STORE_IF_NONONE|PROPERTY_USAGE_STORE_IF_NONZERO)):0;
+
+
+ if (_get_instanced_node_original_property(name,vorig) || usage) {
+ Variant v = obj->get(name);
- bool changed = ! (v==vorig);
+
+ bool changed = _is_property_different(v,vorig,usage);
if ((found!=-1)!=changed) {
if (changed) {
- p_item->add_button(1,get_icon("Reload","EditorIcons"),3);
+ has_reload=true;
+
} else {
- p_item->erase_button(1,found);
+ //p_item->erase_button(1,found);
}
}
@@ -2080,6 +2335,22 @@ void PropertyEditor::_refresh_item(TreeItem *p_item) {
}
+ if (!has_reload && !obj->get_script().is_null()) {
+ Ref<Script> scr = obj->get_script();
+ Variant orig_value;
+ if (scr->get_property_default_value(name,orig_value)) {
+ if (orig_value!=obj->get(name)) {
+ has_reload=true;
+ }
+ }
+ }
+
+ if (!has_reload && found!=-1) {
+ p_item->erase_button(1,found);
+ } else if (has_reload && found==-1) {
+ p_item->add_button(1,get_icon("Reload","EditorIcons"),3);
+ }
+#endif
Dictionary d=p_item->get_metadata(0);
set_item_text(p_item,d["type"],d["name"],d["hint"],d["hint_text"]);
}
@@ -2173,6 +2444,8 @@ void PropertyEditor::update_tree() {
TreeItem * current_category=NULL;
+ String filter = search_box ? search_box->get_text() : "";
+
for (List<PropertyInfo>::Element *I=plist.front() ; I ; I=I->next()) {
PropertyInfo& p = I->get();
@@ -2212,6 +2485,23 @@ void PropertyEditor::update_tree() {
sep->set_selectable(1,false);
sep->set_custom_bg_color(0,get_color("prop_category","Editor"));
sep->set_custom_bg_color(1,get_color("prop_category","Editor"));
+
+ if (use_doc_hints) {
+ StringName type=p.name;
+ if (!class_descr_cache.has(type)) {
+
+ String descr;
+ DocData *dd=EditorHelp::get_doc_data();
+ Map<String,DocData::ClassDoc>::Element *E=dd->class_list.find(type);
+ if (E) {
+ descr=E->get().brief_description;
+ }
+ class_descr_cache[type]=descr.world_wrap(80);
+
+ }
+
+ sep->set_tooltip(0,"Class: "+p.name+":\n\n"+class_descr_cache[type]);
+ }
//sep->set_custom_color(0,Color(1,1,1));
@@ -2219,7 +2509,24 @@ void PropertyEditor::update_tree() {
} else if ( ! (p.usage&PROPERTY_USAGE_EDITOR ) )
continue;
+ String name = (p.name.find("/")!=-1)?p.name.right( p.name.find_last("/")+1 ):p.name;
+
+ if (capitalize_paths)
+ name = name.camelcase_to_underscore().capitalize();
+
String path=p.name.left( p.name.find_last("/") ) ;
+
+ if (use_filter && filter!="") {
+
+ String cat = path;
+
+ if (capitalize_paths)
+ cat = cat.capitalize();
+
+ if (cat.findn(filter)==-1 && name.findn(filter)==-1)
+ continue;
+ }
+
//printf("property %s\n",p.name.ascii().get_data());
TreeItem * parent = get_parent_node(path,item_path,current_category?current_category:root );
//if (parent->get_parent()==root)
@@ -2241,8 +2548,6 @@ void PropertyEditor::update_tree() {
TreeItem * item = tree->create_item( parent );
- String name = (p.name.find("/")!=-1)?p.name.right( p.name.find_last("/")+1 ):p.name;
-
if (level>0) {
item->set_custom_bg_color(0,col);
//item->set_custom_bg_color(1,col);
@@ -2258,32 +2563,65 @@ void PropertyEditor::update_tree() {
item->set_checked(0,p.usage&PROPERTY_USAGE_CHECKED);
}
- if (capitalize_paths)
- item->set_text( 0, name.camelcase_to_underscore().capitalize() );
- else
- item->set_text( 0, name );
-
+ item->set_text(0, name);
item->set_tooltip(0, p.name);
+ if (use_doc_hints) {
+ StringName setter;
+ StringName type;
+ if (ObjectTypeDB::get_setter_and_type_for_property(obj->get_type_name(),p.name,type,setter)) {
+
+ String descr;
+ bool found=false;
+ Map<StringName,Map<StringName,String> >::Element *E=descr_cache.find(type);
+ if (E) {
+
+ Map<StringName,String>::Element *F=E->get().find(setter);
+ if (F) {
+ found=true;
+ descr=F->get();
+ }
+ }
+ if (!found) {
+
+ DocData *dd=EditorHelp::get_doc_data();
+ Map<String,DocData::ClassDoc>::Element *E=dd->class_list.find(type);
+ if (E) {
+ for(int i=0;i<E->get().methods.size();i++) {
+ if (E->get().methods[i].name==setter.operator String()) {
+ descr=E->get().methods[i].description.strip_edges().world_wrap(80);
+ }
+ }
+ }
+
+ descr_cache[type][setter]=descr;
+ }
+
+ item->set_tooltip(0, "Property: "+p.name+"\n\n"+descr);
+ }
+ }
+ //EditorHelp::get_doc_data();
+
Dictionary d;
d["name"]=p.name;
d["type"]=(int)p.type;
d["hint"]=(int)p.hint;
d["hint_text"]=p.hint_string;
-
+ d["usage"]=(int)p.usage;
+
item->set_metadata( 0, d );
item->set_metadata( 1, p.name );
if (draw_red)
item->set_custom_color(0,Color(0.8,0.4,0.20));
-
+
if (p.name==selected_property) {
item->select(1);
}
-
+
//printf("property %s type %i\n",p.name.ascii().get_data(),p.type);
switch( p.type ) {
@@ -2292,7 +2630,8 @@ void PropertyEditor::update_tree() {
item->set_cell_mode( 1, TreeItem::CELL_MODE_CHECK );
item->set_text(1,"On");
item->set_checked( 1, obj->get( p.name ) );
- item->set_icon( 0, get_icon("Bool","EditorIcons") );
+ if (show_type_icons)
+ item->set_icon( 0, get_icon("Bool","EditorIcons") );
item->set_editable(1,!read_only);
} break;
@@ -2304,7 +2643,8 @@ void PropertyEditor::update_tree() {
item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM );
item->set_text(1, String::num(obj->get( p.name ),2) );
item->set_editable(1,!read_only);
- item->set_icon( 0, get_icon("Curve","EditorIcons"));
+ if (show_type_icons)
+ item->set_icon( 0, get_icon("Curve","EditorIcons"));
break;
@@ -2347,8 +2687,10 @@ void PropertyEditor::update_tree() {
item->set_cell_mode( 1, TreeItem::CELL_MODE_RANGE );
+ if (p.hint==PROPERTY_HINT_SPRITE_FRAME) {
+ item->set_range_config(1,0,99999,1);
- if (p.hint==PROPERTY_HINT_RANGE || p.hint==PROPERTY_HINT_EXP_RANGE) {
+ } else if (p.hint==PROPERTY_HINT_RANGE || p.hint==PROPERTY_HINT_EXP_RANGE) {
int c = p.hint_string.get_slice_count(",");
float min=0,max=100,step=1;
@@ -2364,15 +2706,16 @@ void PropertyEditor::update_tree() {
if (p.type==Variant::REAL && c>=3) {
step= p.hint_string.get_slice(",",2).to_double();
- }
-
+ }
+
item->set_range_config(1,min,max,step,p.hint==PROPERTY_HINT_EXP_RANGE);
} else if (p.hint==PROPERTY_HINT_ENUM) {
// int c = p.hint_string.get_slice_count(",");
item->set_text(1,p.hint_string);
- item->set_icon( 0,get_icon("Enum","EditorIcons") );
+ if (show_type_icons)
+ item->set_icon( 0,get_icon("Enum","EditorIcons") );
item->set_range(1, obj->get( p.name ) );
item->set_editable(1,!read_only);
break;
@@ -2388,11 +2731,13 @@ void PropertyEditor::update_tree() {
};
if (p.type==Variant::REAL) {
- item->set_icon( 0, get_icon("Real","EditorIcons"));
+ if (show_type_icons)
+ item->set_icon( 0, get_icon("Real","EditorIcons"));
item->set_range(1, obj->get( p.name ) );
} else {
- item->set_icon( 0,get_icon("Integer","EditorIcons") );
+ if (show_type_icons)
+ item->set_icon( 0,get_icon("Integer","EditorIcons") );
item->set_range(1, obj->get( p.name ) );
}
@@ -2412,7 +2757,8 @@ void PropertyEditor::update_tree() {
item->set_cell_mode( 1, TreeItem::CELL_MODE_STRING );
item->set_editable(1,!read_only);
- item->set_icon( 0, get_icon("File","EditorIcons") );
+ if (show_type_icons)
+ item->set_icon( 0, get_icon("File","EditorIcons") );
item->set_text(1,obj->get(p.name));
item->add_button(1,get_icon("Folder","EditorIcons"));
@@ -2432,7 +2778,8 @@ void PropertyEditor::update_tree() {
item->set_text(1, p.hint_string);
item->set_range(1,idx);
item->set_editable( 1, !read_only );
- item->set_icon( 0,get_icon("Enum","EditorIcons") );
+ if (show_type_icons)
+ item->set_icon( 0,get_icon("Enum","EditorIcons") );
} break;
@@ -2440,7 +2787,8 @@ void PropertyEditor::update_tree() {
item->set_cell_mode( 1, TreeItem::CELL_MODE_STRING );
item->set_editable(1,!read_only);
- item->set_icon( 0, get_icon("String","EditorIcons") );
+ if (show_type_icons)
+ item->set_icon( 0, get_icon("String","EditorIcons") );
item->set_text(1,obj->get(p.name));
if (p.hint==PROPERTY_HINT_MULTILINE_TEXT)
item->add_button(1,get_icon("MultiLine","EditorIcons") );
@@ -2449,37 +2797,126 @@ void PropertyEditor::update_tree() {
}
} break;
+ case Variant::ARRAY: {
+
+ item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM );
+ item->add_button(1,get_icon("EditResource","EditorIcons"));
+
+
+ Variant v = obj->get(p.name);
+ if (v.is_array())
+ item->set_text(1,"Array["+itos(v.call("size"))+"]");
+ else
+ item->set_text(1,"Array[]");
+ if (show_type_icons)
+ item->set_icon( 0, get_icon("ArrayData","EditorIcons") );
+
+
+ } break;
+
case Variant::INT_ARRAY: {
item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM );
- item->set_editable( 1, !read_only );
- item->set_text(1,"[IntArray]");
- item->set_icon( 0, get_icon("ArrayInt","EditorIcons") );
+ item->add_button(1,get_icon("EditResource","EditorIcons"));
+
+ Variant v = obj->get(p.name);
+ if (v.is_array())
+ item->set_text(1,"IntArray["+itos(v.call("size"))+"]");
+ else
+ item->set_text(1,"IntArray[]");
+ if (show_type_icons)
+ item->set_icon( 0, get_icon("ArrayInt","EditorIcons") );
} break;
case Variant::REAL_ARRAY: {
item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM );
- item->set_editable( 1, !read_only );
- item->set_text(1,"[RealArray]");
- item->set_icon( 0, get_icon("ArrayReal","EditorIcons") );
+ item->add_button(1,get_icon("EditResource","EditorIcons"));
+
+ Variant v = obj->get(p.name);
+ if (v.is_array())
+ item->set_text(1,"FloatArray["+itos(v.call("size"))+"]");
+ else
+ item->set_text(1,"FloatArray[]");
+ if (show_type_icons)
+ item->set_icon( 0, get_icon("ArrayReal","EditorIcons") );
+
} break;
case Variant::STRING_ARRAY: {
item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM );
- item->set_editable( 1, !read_only );
- item->set_text(1,"[StringArray]");
- item->set_icon( 0, get_icon("ArrayString","EditorIcons") );
+ item->add_button(1,get_icon("EditResource","EditorIcons"));
+
+ Variant v = obj->get(p.name);
+ if (v.is_array())
+ item->set_text(1,"String["+itos(v.call("size"))+"]");
+ else
+ item->set_text(1,"String[]");
+ if (show_type_icons)
+ item->set_icon( 0, get_icon("ArrayString","EditorIcons") );
+
} break;
case Variant::RAW_ARRAY: {
item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM );
- item->set_editable( 1, !read_only );
- item->set_text(1,"[Raw Data]");
- item->set_icon( 0, get_icon("ArrayData","EditorIcons") );
+ item->add_button(1,get_icon("EditResource","EditorIcons"));
+
+ Variant v = obj->get(p.name);
+ if (v.is_array())
+ item->set_text(1,"Byte["+itos(v.call("size"))+"]");
+ else
+ item->set_text(1,"Byte[]");
+ if (show_type_icons)
+ item->set_icon( 0, get_icon("ArrayData","EditorIcons") );
+
+
+ } break;
+ case Variant::VECTOR2_ARRAY: {
+
+ item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM );
+ item->add_button(1,get_icon("EditResource","EditorIcons"));
+
+ Variant v = obj->get(p.name);
+ if (v.is_array())
+ item->set_text(1,"Vector2["+itos(v.call("size"))+"]");
+ else
+ item->set_text(1,"Vector2[]");
+ if (show_type_icons)
+ item->set_icon( 0, get_icon("Vector2","EditorIcons") );
+
+
+ } break;
+ case Variant::VECTOR3_ARRAY: {
+
+ item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM );
+ item->add_button(1,get_icon("EditResource","EditorIcons"));
+
+ Variant v = obj->get(p.name);
+ if (v.is_array())
+ item->set_text(1,"Vector3["+itos(v.call("size"))+"]");
+ else
+ item->set_text(1,"Vector3[]");
+ if (show_type_icons)
+ item->set_icon( 0, get_icon("Vector","EditorIcons") );
+
+
+ } break;
+ case Variant::COLOR_ARRAY: {
+
+ item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM );
+ item->add_button(1,get_icon("EditResource","EditorIcons"));
+
+ Variant v = obj->get(p.name);
+ if (v.is_array())
+ item->set_text(1,"Color["+itos(v.call("size"))+"]");
+ else
+ item->set_text(1,"Color[]");
+ if (show_type_icons)
+ item->set_icon( 0, get_icon("Color","EditorIcons") );
+
} break;
case Variant::VECTOR2: {
@@ -2487,7 +2924,8 @@ void PropertyEditor::update_tree() {
item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM );
item->set_editable( 1, true );
item->set_text(1,obj->get(p.name));
- item->set_icon( 0,get_icon("Vector2","EditorIcons") );
+ if (show_type_icons)
+ item->set_icon( 0,get_icon("Vector2","EditorIcons") );
} break;
case Variant::RECT2: {
@@ -2495,7 +2933,8 @@ void PropertyEditor::update_tree() {
item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM );
item->set_editable( 1, true );
item->set_text(1,obj->get(p.name));
- item->set_icon( 0,get_icon("Rect2","EditorIcons") );
+ if (show_type_icons)
+ item->set_icon( 0,get_icon("Rect2","EditorIcons") );
} break;
case Variant::VECTOR3: {
@@ -2503,15 +2942,24 @@ void PropertyEditor::update_tree() {
item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM );
item->set_editable( 1, true );
item->set_text(1,obj->get(p.name));
- item->set_icon( 0,get_icon("Vector","EditorIcons") );
+ if (show_type_icons)
+ item->set_icon( 0,get_icon("Vector","EditorIcons") );
} break;
+ case Variant::MATRIX32:
+ case Variant::MATRIX3: {
+
+ item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM );
+ item->set_editable( 1, true );
+ item->set_text(1, obj->get(p.name));
+ } break;
case Variant::TRANSFORM: {
item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM );
item->set_editable( 1, true );
item->set_text(1,obj->get(p.name));
- item->set_icon( 0,get_icon("Matrix","EditorIcons") );
+ if (show_type_icons)
+ item->set_icon( 0,get_icon("Matrix","EditorIcons") );
} break;
case Variant::PLANE: {
@@ -2519,7 +2967,8 @@ void PropertyEditor::update_tree() {
item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM );
item->set_editable( 1, true );
item->set_text(1,obj->get(p.name));
- item->set_icon( 0,get_icon("Plane","EditorIcons") );
+ if (show_type_icons)
+ item->set_icon( 0,get_icon("Plane","EditorIcons") );
} break;
case Variant::_AABB: {
@@ -2527,7 +2976,8 @@ void PropertyEditor::update_tree() {
item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM );
item->set_editable( 1, true );
item->set_text(1,"AABB");
- item->set_icon( 0,get_icon("Rect3","EditorIcons") );
+ if (show_type_icons)
+ item->set_icon( 0,get_icon("Rect3","EditorIcons") );
} break;
case Variant::QUAT: {
@@ -2535,7 +2985,8 @@ void PropertyEditor::update_tree() {
item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM );
item->set_editable( 1, true );
item->set_text(1,obj->get(p.name));
- item->set_icon( 0,get_icon("Quat","EditorIcons") );
+ if (show_type_icons)
+ item->set_icon( 0,get_icon("Quat","EditorIcons") );
} break;
case Variant::COLOR: {
@@ -2544,11 +2995,12 @@ void PropertyEditor::update_tree() {
item->set_editable( 1, !read_only );
// item->set_text(1,obj->get(p.name));
item->set_custom_bg_color(1,obj->get(p.name));
- item->set_icon( 0,get_icon("Color","EditorIcons") );
+ if (show_type_icons)
+ item->set_icon( 0,get_icon("Color","EditorIcons") );
} break;
case Variant::IMAGE: {
-
+
item->set_cell_mode( 1, TreeItem::CELL_MODE_CUSTOM );
item->set_editable( 1, !read_only );
Image img = obj->get( p.name );
@@ -2556,8 +3008,9 @@ void PropertyEditor::update_tree() {
item->set_text(1,"[Image (empty)]");
else
item->set_text(1,"[Image "+itos(img.get_width())+"x"+itos(img.get_height())+"]");
- item->set_icon( 0,get_icon("Image","EditorIcons") );
-
+ if (show_type_icons)
+ item->set_icon( 0,get_icon("Image","EditorIcons") );
+
} break;
case Variant::NODE_PATH: {
@@ -2638,20 +3091,37 @@ void PropertyEditor::update_tree() {
}
}
- if (get_instanced_node()) {
+ bool has_reload=false;
+ if (_might_be_in_instance()) {
- Dictionary d = get_instanced_node()->get_instance_state();
- if (d.has(p.name)) {
+ Variant vorig;
+ Dictionary d=item->get_metadata(0);
+ int usage = d.has("usage")?int(int(d["usage"])&(PROPERTY_USAGE_STORE_IF_NONONE|PROPERTY_USAGE_STORE_IF_NONZERO)):0;
+ if (_get_instanced_node_original_property(p.name,vorig) || usage) {
Variant v = obj->get(p.name);
- Variant vorig = d[p.name];
- if (! (v==vorig)) {
+
+ if (_is_property_different(v,vorig,usage)) {
+ //print_line("FOR "+String(p.name)+" RELOAD WITH: "+String(v)+"("+Variant::get_type_name(v.get_type())+")=="+String(vorig)+"("+Variant::get_type_name(vorig.get_type())+")");
item->add_button(1,get_icon("Reload","EditorIcons"),3);
+ has_reload=true;
}
}
}
+ if (!has_reload && !obj->get_script().is_null()) {
+ Ref<Script> scr = obj->get_script();
+ Variant orig_value;
+ if (scr->get_property_default_value(p.name,orig_value)) {
+ if (orig_value!=obj->get(p.name)) {
+ item->add_button(1,get_icon("Reload","EditorIcons"),3);
+ }
+ }
+ }
+
+
+
}
}
@@ -2676,7 +3146,7 @@ void PropertyEditor::_edit_set(const String& p_name, const Variant& p_value) {
}
}
- if (!undo_redo) {
+ if (!undo_redo || obj->cast_to<MultiNodeEdit>() || obj->cast_to<ArrayPropertyEdit>()) { //kind of hacky
obj->set(p_name,p_value);
_changed_callbacks(obj,p_name);
@@ -2708,10 +3178,10 @@ void PropertyEditor::_edit_set(const String& p_name, const Variant& p_value) {
void PropertyEditor::_item_edited() {
-
- TreeItem * item = tree->get_edited();
+
+ TreeItem * item = tree->get_edited();
Dictionary d = item->get_metadata(0);
-
+
String name=d["name"];
if (tree->get_edited_column()==0) {
@@ -2740,12 +3210,12 @@ void PropertyEditor::_item_edited() {
int hint= d["hint"];
String hint_text=d["hint_text"];
switch(type) {
-
+
case Variant::NIL: {
-
- } break;
+
+ } break;
case Variant::BOOL: {
-
+
_edit_set(name,item->is_checked(1));
} break;
case Variant::INT:
@@ -2764,7 +3234,7 @@ void PropertyEditor::_item_edited() {
_edit_set(name,item->get_range(1));
} break;
case Variant::STRING: {
-
+
if (hint==PROPERTY_HINT_ENUM) {
int idx= item->get_range(1);
@@ -2782,64 +3252,64 @@ void PropertyEditor::_item_edited() {
}
} break;
// math types
-
+
case Variant::VECTOR3: {
-
+
} break;
case Variant::PLANE: {
-
+
} break;
case Variant::QUAT: {
-
+
} break;
case Variant::_AABB: {
-
+
} break;
case Variant::MATRIX3: {
-
+
} break;
case Variant::TRANSFORM: {
-
+
} break;
-
+
case Variant::COLOR: {
//_edit_set(name,item->get_custom_bg_color(0));
} break;
case Variant::IMAGE: {
-
+
} break;
case Variant::NODE_PATH: {
-
+
} break;
case Variant::INPUT_EVENT: {
-
+
} break;
case Variant::DICTIONARY: {
-
+
} break;
-
+
// arrays
case Variant::RAW_ARRAY: {
-
+
} break;
case Variant::INT_ARRAY: {
-
+
} break;
case Variant::REAL_ARRAY: {
-
+
} break;
case Variant::STRING_ARRAY: {
-
+
} break;
case Variant::VECTOR3_ARRAY: {
-
+
} break;
case Variant::COLOR_ARRAY: {
-
+
} break;
-
-
+
+
};
}
@@ -2890,24 +3360,24 @@ void PropertyEditor::_custom_editor_request(bool p_arrow) {
}
void PropertyEditor::edit(Object* p_object) {
-
+
if (obj==p_object)
return;
if (obj) {
-
+
obj->remove_change_receptor(this);
}
obj=p_object;
update_tree();
-
+
if (obj) {
-
+
obj->add_change_receptor(this);
}
-
-
+
+
}
void PropertyEditor::_set_range_def(Object *p_item, String prop,float p_frame) {
@@ -2942,19 +3412,28 @@ void PropertyEditor::_edit_button(Object *p_item, int p_column, int p_button) {
call_deferred("_set_range_def",ti,prop,ti->get_range(p_column)+1.0);
} else if (p_button==3) {
- if (!get_instanced_node())
- return;
if (!d.has("name"))
return;
String prop=d["name"];
- Dictionary d2 = get_instanced_node()->get_instance_state();
- if (d2.has(prop)) {
+ Variant vorig;
+
+ if (_might_be_in_instance() && _get_instanced_node_original_property(prop,vorig)) {
- _edit_set(prop,d2[prop]);
+ _edit_set(prop,vorig);
+ return;
}
+ if (!obj->get_script().is_null()) {
+ Ref<Script> scr = obj->get_script();
+ Variant orig_value;
+ if (scr->get_property_default_value(prop,orig_value)) {
+ _edit_set(prop,orig_value);
+ }
+ }
+
+
} else {
Dictionary d = ti->get_metadata(0);
@@ -2996,15 +3475,28 @@ void PropertyEditor::_edit_button(Object *p_item, int p_column, int p_button) {
emit_signal("resource_selected",r,n);
}
+ } else if (t==Variant::ARRAY || t==Variant::INT_ARRAY || t==Variant::REAL_ARRAY || t==Variant::STRING_ARRAY || t==Variant::VECTOR2_ARRAY || t==Variant::VECTOR3_ARRAY || t==Variant::COLOR_ARRAY || t==Variant::RAW_ARRAY) {
+
+ Variant v = obj->get(n);
+
+ if (v.get_type()!=t) {
+ Variant::CallError ce;
+ v=Variant::construct(Variant::Type(t),NULL,0,ce);
+ }
+
+ Ref<ArrayPropertyEdit> ape = memnew( ArrayPropertyEdit );
+ ape->edit(obj,n,Variant::Type(t));
+
+ EditorNode::get_singleton()->push_item(ape.ptr());
}
}
}
void PropertyEditor::_node_removed(Node *p_node) {
-
+
if (p_node==obj) {
-
+
edit(NULL);
}
}
@@ -3059,18 +3551,25 @@ void PropertyEditor::_draw_flags(Object *t,const Rect2& p_rect) {
}
+void PropertyEditor::_filter_changed(const String& p_text) {
+
+ update_tree();
+}
+
void PropertyEditor::_bind_methods() {
ObjectTypeDB::bind_method( "_item_edited",&PropertyEditor::_item_edited);
ObjectTypeDB::bind_method( "_item_selected",&PropertyEditor::_item_selected);
ObjectTypeDB::bind_method( "_custom_editor_request",&PropertyEditor::_custom_editor_request);
- ObjectTypeDB::bind_method( "_custom_editor_edited",&PropertyEditor::_custom_editor_edited);
- ObjectTypeDB::bind_method( "_resource_edit_request",&PropertyEditor::_resource_edit_request);
- ObjectTypeDB::bind_method( "_node_removed",&PropertyEditor::_node_removed);
+ ObjectTypeDB::bind_method( "_custom_editor_edited",&PropertyEditor::_custom_editor_edited);
+ ObjectTypeDB::bind_method( "_resource_edit_request",&PropertyEditor::_resource_edit_request);
+ ObjectTypeDB::bind_method( "_node_removed",&PropertyEditor::_node_removed);
ObjectTypeDB::bind_method( "_edit_button",&PropertyEditor::_edit_button);
ObjectTypeDB::bind_method( "_changed_callback",&PropertyEditor::_changed_callbacks);
ObjectTypeDB::bind_method( "_draw_flags",&PropertyEditor::_draw_flags);
ObjectTypeDB::bind_method( "_set_range_def",&PropertyEditor::_set_range_def);
+ ObjectTypeDB::bind_method( "_filter_changed",&PropertyEditor::_filter_changed);
+ ObjectTypeDB::bind_method( "update_tree",&PropertyEditor::update_tree);
ADD_SIGNAL( MethodInfo("property_toggled",PropertyInfo( Variant::STRING, "property"),PropertyInfo( Variant::BOOL, "value")));
ADD_SIGNAL( MethodInfo("resource_selected", PropertyInfo( Variant::OBJECT, "res"),PropertyInfo( Variant::STRING, "prop") ) );
@@ -3125,30 +3624,58 @@ void PropertyEditor::set_show_categories(bool p_show) {
update_tree();
}
+void PropertyEditor::set_use_filter(bool p_use) {
+
+ if (p_use==use_filter)
+ return;
+
+ use_filter=p_use;
+ update_tree();
+}
+
+void PropertyEditor::register_text_enter(Node* p_line_edit) {
+
+ ERR_FAIL_NULL(p_line_edit);
+ search_box=p_line_edit->cast_to<LineEdit>();
+
+ if (search_box)
+ search_box->connect("text_changed",this,"_filter_changed");
+}
+
+void PropertyEditor::set_subsection_selectable(bool p_selectable) {
+
+ if (p_selectable==subsection_selectable)
+ return;
+
+ subsection_selectable=p_selectable;
+ update_tree();
+}
+
PropertyEditor::PropertyEditor() {
-
+
_prop_edited="property_edited";
_prop_edited_name.push_back(String());
undo_redo=NULL;
obj=NULL;
+ search_box=NULL;
changing=false;
update_tree_pending=false;
-
+
top_label = memnew( Label );
top_label->set_text("Properties:");
top_label->set_anchor( MARGIN_RIGHT, ANCHOR_END );
top_label->set_begin( Point2( 10,0) );
- top_label->set_end( Point2( 0,12) );
-
- add_child(top_label);
+ top_label->set_end( Point2( 0,12) );
+
+ add_child(top_label);
+
-
tree = memnew( Tree );
tree->set_anchor( MARGIN_RIGHT, ANCHOR_END );
- tree->set_anchor( MARGIN_BOTTOM, ANCHOR_END );
+ tree->set_anchor( MARGIN_BOTTOM, ANCHOR_END );
tree->set_begin( Point2(0,19 ));
tree->set_end( Point2(0,0 ));
-
+
tree->set_columns(2);
tree->set_column_expand(0,true);
tree->set_column_min_width(0,30);
@@ -3156,21 +3683,22 @@ PropertyEditor::PropertyEditor() {
tree->set_column_min_width(1,18);
//tree->set_hide_root(true);
- add_child( tree );
-
+ add_child( tree );
+
tree->connect("item_edited", this,"_item_edited",varray(),CONNECT_DEFERRED);
tree->connect("cell_selected", this,"_item_selected");
-
+
set_fixed_process(true);
-
+
custom_editor = memnew( CustomPropertyEditor );
add_child(custom_editor);
-
+
tree->connect("custom_popup_edited", this,"_custom_editor_request");
tree->connect("button_pressed", this,"_edit_button");
custom_editor->connect("variant_changed", this,"_custom_editor_edited");
custom_editor->connect("resource_edit_request", this,"_resource_edit_request",make_binds(),CONNECT_DEFERRED);
-
+ tree->set_hide_folding(true);
+
capitalize_paths=true;
autoclear=false;
tree->set_column_title(0,"Property");
@@ -3181,7 +3709,11 @@ PropertyEditor::PropertyEditor() {
read_only=false;
show_categories=false;
refresh_countdown=0;
-
+ use_doc_hints=false;
+ use_filter=false;
+ subsection_selectable=false;
+ show_type_icons=EDITOR_DEF("inspector/show_type_icons",false);
+
}
@@ -3190,3 +3722,259 @@ PropertyEditor::~PropertyEditor()
}
+/////////////////////////////
+
+
+
+
+
+class SectionedPropertyEditorFilter : public Object {
+
+ OBJ_TYPE( SectionedPropertyEditorFilter, Object );
+
+ Object *edited;
+ String section;
+
+ bool _set(const StringName& p_name, const Variant& p_value) {
+
+ if (!edited)
+ return false;
+
+ String name=p_name;
+ if (section!="") {
+ name=section+"/"+name;
+ }
+
+ bool valid;
+ edited->set(name,p_value,&valid);
+ return valid;
+ }
+
+ bool _get(const StringName& p_name,Variant &r_ret) const{
+
+ if (!edited)
+ return false;
+
+ String name=p_name;
+ if (section!="") {
+ name=section+"/"+name;
+ }
+
+ bool valid=false;
+
+ r_ret=edited->get(name,&valid);
+ return valid;
+
+
+ }
+ void _get_property_list(List<PropertyInfo> *p_list) const{
+
+ if (!edited)
+ return;
+
+ List<PropertyInfo> pinfo;
+ edited->get_property_list(&pinfo);
+ for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+
+ PropertyInfo pi=E->get();
+
+ if (section=="")
+ p_list->push_back(pi);
+
+ int sp = pi.name.find("/");
+ if (sp!=-1) {
+ String ss = pi.name.substr(0,sp);
+
+ if (ss==section) {
+ pi.name=pi.name.substr(sp+1,pi.name.length());
+ p_list->push_back(pi);
+ }
+ } else {
+ if (section=="global")
+ p_list->push_back(pi);
+ }
+ }
+
+ }
+public:
+
+ void set_section(const String& p_section) {
+
+ section=p_section;
+ _change_notify();
+ }
+
+ void set_edited(Object* p_edited) {
+ edited=p_edited;
+ _change_notify();
+ }
+
+ SectionedPropertyEditorFilter() {
+ edited=NULL;
+ }
+
+};
+
+void SectionedPropertyEditor::_notification(int p_what) {
+
+ if (p_what==NOTIFICATION_ENTER_TREE) {
+
+ clear_button->set_icon(get_icon("Close", "EditorIcons"));
+ }
+}
+
+void SectionedPropertyEditor::_bind_methods() {
+
+ ObjectTypeDB::bind_method("_section_selected",&SectionedPropertyEditor::_section_selected);
+ ObjectTypeDB::bind_method("_clear_search_box",&SectionedPropertyEditor::clear_search_box);
+}
+
+void SectionedPropertyEditor::_section_selected(int p_which) {
+
+ filter->set_section( sections->get_item_metadata(p_which) );
+}
+
+void SectionedPropertyEditor::clear_search_box() {
+
+ if (search_box->get_text().strip_edges()=="")
+ return;
+
+ search_box->clear();
+ editor->update_tree();
+}
+
+
+String SectionedPropertyEditor::get_current_section() const {
+
+ String section = sections->get_item_metadata( sections->get_current() );
+
+ if (section=="") {
+ String name = editor->get_selected_path();
+
+ int sp = name.find("/");
+ if (sp!=-1)
+ section = name.substr(0, sp);
+
+ }
+
+ return section;
+}
+
+String SectionedPropertyEditor::get_full_item_path(const String& p_item) {
+
+ String base = sections->get_item_metadata( sections->get_current() );
+ if (base!="")
+ return base+"/"+p_item;
+ else
+ return p_item;
+}
+
+void SectionedPropertyEditor::edit(Object* p_object) {
+
+ List<PropertyInfo> pinfo;
+ if (p_object)
+ p_object->get_property_list(&pinfo);
+ sections->clear();
+
+ Set<String> existing_sections;
+
+ existing_sections.insert("");
+ sections->add_item("All");
+ sections->set_item_metadata(0, "");
+
+ for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+
+ PropertyInfo pi=E->get();
+
+ if (pi.usage&PROPERTY_USAGE_CATEGORY)
+ continue;
+ if ( !(pi.usage&PROPERTY_USAGE_EDITOR) )
+ continue;
+
+ if (pi.name.find(":")!=-1 || pi.name=="script/script")
+ continue;
+ int sp = pi.name.find("/");
+ if (sp!=-1) {
+ String sname=pi.name.substr(0,sp);
+ if (!existing_sections.has(sname)) {
+ existing_sections.insert(sname);
+ sections->add_item(sname.capitalize());
+ sections->set_item_metadata(sections->get_item_count()-1,sname);
+ }
+
+ } else {
+ if (!existing_sections.has("global")) {
+ existing_sections.insert("global");
+ sections->add_item("Global");
+ sections->set_item_metadata(sections->get_item_count()-1,"global");
+ }
+ }
+
+
+ }
+
+ //sections->sort_items_by_text();
+
+
+ filter->set_edited(p_object);
+ editor->edit(filter);
+
+ sections->select(0);
+ _section_selected(0);
+
+}
+
+PropertyEditor *SectionedPropertyEditor::get_property_editor() {
+
+ return editor;
+}
+
+SectionedPropertyEditor::SectionedPropertyEditor() {
+
+ add_constant_override("separation", 8);
+
+ VBoxContainer *left_vb = memnew( VBoxContainer);
+ left_vb->set_custom_minimum_size(Size2(160,0));
+ add_child(left_vb);
+
+ sections = memnew( ItemList );
+ sections->set_v_size_flags(SIZE_EXPAND_FILL);
+
+ left_vb->add_margin_child("Sections:",sections,true);
+
+ VBoxContainer *right_vb = memnew( VBoxContainer);
+ right_vb->set_h_size_flags(SIZE_EXPAND_FILL);
+ add_child(right_vb);
+
+ filter = memnew( SectionedPropertyEditorFilter );
+
+ HBoxContainer *hbc = memnew( HBoxContainer );
+ right_vb->add_margin_child("Search:",hbc);
+
+ search_box = memnew( LineEdit );
+ search_box->set_h_size_flags(SIZE_EXPAND_FILL);
+ hbc->add_child(search_box);
+
+ clear_button = memnew( ToolButton );
+ hbc->add_child(clear_button);
+ clear_button->connect("pressed", this, "_clear_search_box");
+
+ editor = memnew( PropertyEditor );
+ editor->register_text_enter(search_box);
+ editor->set_use_filter(true);
+ editor->set_v_size_flags(SIZE_EXPAND_FILL);
+ right_vb->add_margin_child("Properties:",editor,true);
+
+ editor->get_scene_tree()->set_column_titles_visible(false);
+ add_child(editor);
+
+ editor->hide_top_label();
+
+ sections->connect("item_selected",this,"_section_selected");
+
+}
+
+SectionedPropertyEditor::~SectionedPropertyEditor() {
+
+ memdelete(filter);
+}
diff --git a/tools/editor/property_editor.h b/tools/editor/property_editor.h
index de5cac8711..5dc2f6d154 100644
--- a/tools/editor/property_editor.h
+++ b/tools/editor/property_editor.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -39,6 +39,7 @@
#include "scene/gui/texture_frame.h"
#include "scene/gui/text_edit.h"
#include "scene/gui/check_button.h"
+#include "scene/gui/split_container.h"
#include "scene_tree_editor.h"
/**
@@ -46,9 +47,9 @@
*/
class CustomPropertyEditor : public Popup {
-
+
OBJ_TYPE( CustomPropertyEditor, Popup );
-
+
enum {
MAX_VALUE_EDITORS=12,
MAX_ACTION_BUTTONS=5,
@@ -93,6 +94,8 @@ class CustomPropertyEditor : public Popup {
TextEdit *text_edit;
bool read_only;
Button *checks20[20];
+ SpinBox *spinbox;
+ HSlider *slider;
Control *easing_draw;
@@ -105,44 +108,48 @@ class CustomPropertyEditor : public Popup {
void _file_selected(String p_file);
void _scroll_modified(double p_value);
void _modified(String p_string);
+ void _range_modified(double p_value);
void _focus_enter();
void _focus_exit();
void _action_pressed(int p_which);
void _type_create_selected(int p_idx);
+
void _color_changed(const Color& p_color);
void _draw_easing();
void _menu_option(int p_which);
-
+
void _drag_easing(const InputEvent& p_ev);
void _node_path_selected(NodePath p_path);
void show_value_editors(int p_amount);
void config_value_editors(int p_amount, int p_columns,int p_label_w,const List<String>& p_strings);
void config_action_buttons(const List<String>& p_strings);
+
protected:
void _notification(int p_what);
- static void _bind_methods();
-
-public:
+ static void _bind_methods();
+
+public:
Variant get_variant() const;
String get_name() const;
-
+
void set_read_only(bool p_read_only) { read_only=p_read_only; }
bool edit(Object* p_owner,const String& p_name,Variant::Type p_type, const Variant& p_variant,int p_hint,String p_hint_text);
-
+
CustomPropertyEditor();
};
class PropertyEditor : public Control {
-
+
OBJ_TYPE( PropertyEditor, Control );
-
+
Tree *tree;
Label *top_label;
//Object *object;
+ LineEdit *search_box;
Object* obj;
@@ -156,42 +163,56 @@ class PropertyEditor : public Control {
bool keying;
bool read_only;
bool show_categories;
+ bool show_type_icons;
float refresh_countdown;
+ bool use_doc_hints;
+ bool use_filter;
+ bool subsection_selectable;
HashMap<String,String> pending;
String selected_property;
+
+ Map<StringName,Map<StringName,String> > descr_cache;
+ Map<StringName,String > class_descr_cache;
CustomPropertyEditor *custom_editor;
-
+
void _resource_edit_request();
void _custom_editor_edited();
void _custom_editor_request(bool p_arrow);
-
+
void _item_selected();
void _item_edited();
TreeItem *get_parent_node(String p_path,HashMap<String,TreeItem*>& item_paths,TreeItem *root);
-
+
void set_item_text(TreeItem *p_item, int p_type, const String& p_name, int p_hint=PROPERTY_HINT_NONE, const String& p_hint_text="");
-
+
TreeItem *find_item(TreeItem *p_item,const String& p_name);
-
-
+
+
virtual void _changed_callback(Object *p_changed,const char * p_what);
virtual void _changed_callbacks(Object *p_changed,const String& p_callback);
+ void _check_reload_status(const String&p_name,TreeItem* item);
+
void _edit_button(Object *p_item, int p_column, int p_button);
-
+
void _node_removed(Node *p_node);
void _edit_set(const String& p_name, const Variant& p_value);
void _draw_flags(Object *ti,const Rect2& p_rect);
- Node *get_instanced_node();
+ bool _might_be_in_instance();
+ bool _get_instanced_node_original_property(const StringName& p_prop,Variant& value);
+ bool _is_property_different(const Variant& p_current, const Variant& p_orig,int p_usage=0);
+
void _refresh_item(TreeItem *p_item);
void _set_range_def(Object *p_item, String prop, float p_frame);
+ void _filter_changed(const String& p_text);
+
UndoRedo *undo_redo;
protected:
-
+
void _notification(int p_what);
static void _bind_methods();
public:
@@ -217,10 +238,48 @@ public:
void set_autoclear(bool p_enable);
void set_show_categories(bool p_show);
-
+ void set_use_doc_hints(bool p_enable) { use_doc_hints=p_enable; }
+
+ void set_use_filter(bool p_use);
+ void register_text_enter(Node *p_line_edit);
+
+ void set_subsection_selectable(bool p_selectable);
+
PropertyEditor();
~PropertyEditor();
};
+
+class SectionedPropertyEditorFilter;
+
+class SectionedPropertyEditor : public HBoxContainer {
+
+
+ OBJ_TYPE(SectionedPropertyEditor,HBoxContainer);
+ ItemList *sections;
+ SectionedPropertyEditorFilter *filter;
+ LineEdit *search_box;
+ ToolButton *clear_button;
+ PropertyEditor *editor;
+
+ void _section_selected(int p_which);
+
+protected:
+
+ void _notification(int p_what);
+ static void _bind_methods();
+public:
+
+ PropertyEditor *get_property_editor();
+ void edit(Object* p_object);
+ String get_full_item_path(const String& p_item);
+ String get_current_section() const;
+
+ void clear_search_box();
+
+ SectionedPropertyEditor();
+ ~SectionedPropertyEditor();
+};
+
#endif
diff --git a/tools/editor/pvrtc_compress.cpp b/tools/editor/pvrtc_compress.cpp
index a2f98adbe0..c30aedc1dc 100644
--- a/tools/editor/pvrtc_compress.cpp
+++ b/tools/editor/pvrtc_compress.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/pvrtc_compress.h b/tools/editor/pvrtc_compress.h
index c4fb0bacb5..129faee080 100644
--- a/tools/editor/pvrtc_compress.h
+++ b/tools/editor/pvrtc_compress.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/quick_open.cpp b/tools/editor/quick_open.cpp
index 749318386c..828275340b 100644
--- a/tools/editor/quick_open.cpp
+++ b/tools/editor/quick_open.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,20 +30,46 @@
#include "os/keyboard.h"
-void EditorQuickOpen::popup(const String& p_base, bool p_dontclear) {
+void EditorQuickOpen::popup(const StringName &p_base, bool p_enable_multi, bool p_add_dirs, bool p_dontclear) {
+ add_directories=p_add_dirs;
popup_centered_ratio(0.6);
if (p_dontclear)
search_box->select_all();
else
search_box->clear();
+ if (p_enable_multi)
+ search_options->set_select_mode(Tree::SELECT_MULTI);
+ else
+ search_options->set_select_mode(Tree::SELECT_SINGLE);
search_box->grab_focus();
base_type=p_base;
_update_search();
+}
+String EditorQuickOpen::get_selected() const {
+
+ TreeItem *ti = search_options->get_selected();
+ if (!ti)
+ return String();
+ return "res://" + ti->get_text(0);
}
+Vector<String> EditorQuickOpen::get_selected_files() const {
+
+ Vector<String> files;
+
+ TreeItem* item = search_options->get_next_selected(search_options->get_root());
+ while (item) {
+
+ files.push_back("res://"+item->get_text(0));
+
+ item = search_options->get_next_selected(item);
+ }
+
+ return files;
+}
void EditorQuickOpen::_text_changed(const String& p_newtext) {
@@ -52,41 +78,83 @@ void EditorQuickOpen::_text_changed(const String& p_newtext) {
void EditorQuickOpen::_sbox_input(const InputEvent& p_ie) {
- if (p_ie.type==InputEvent::KEY && (
- p_ie.key.scancode == KEY_UP ||
- p_ie.key.scancode == KEY_DOWN ||
- p_ie.key.scancode == KEY_PAGEUP ||
- p_ie.key.scancode == KEY_PAGEDOWN ) ) {
+ if (p_ie.type==InputEvent::KEY) {
+
+ switch(p_ie.key.scancode) {
+ case KEY_UP:
+ case KEY_DOWN:
+ case KEY_PAGEUP:
+ case KEY_PAGEDOWN: {
+
+ search_options->call("_input_event", p_ie);
+ search_box->accept_event();
+
+ TreeItem *root = search_options->get_root();
+ if (!root->get_children())
+ break;
- search_options->call("_input_event",p_ie);
- search_box->accept_event();
+ TreeItem *current = search_options->get_selected();
+
+ TreeItem *item = search_options->get_next_selected(root);
+ while (item) {
+ item->deselect(0);
+ item = search_options->get_next_selected(item);
+ }
+
+ current->select(0);
+
+ } break;
+ }
}
}
void EditorQuickOpen::_parse_fs(EditorFileSystemDirectory *efsd) {
- for(int i=0;i<efsd->get_subdir_count();i++) {
+ if (!add_directories) {
+ for(int i=0;i<efsd->get_subdir_count();i++) {
- _parse_fs(efsd->get_subdir(i));
+ _parse_fs(efsd->get_subdir(i));
+ }
}
+ TreeItem *root = search_options->get_root();
+
+ if (add_directories) {
+ String path = efsd->get_path();
+ if (!path.ends_with("/"))
+ path+="/";
+ if (path!="res://") {
+ path=path.substr(6,path.length());
+ if (path.findn(search_box->get_text())!=-1) {
+ TreeItem *ti = search_options->create_item(root);
+ ti->set_text(0,path);
+ Ref<Texture> icon = get_icon("folder","FileDialog");
+ ti->set_icon(0,icon);
+ }
+ }
+ }
for(int i=0;i<efsd->get_file_count();i++) {
String file = efsd->get_file_path(i);
file=file.substr(6,file.length());
if (ObjectTypeDB::is_type(efsd->get_file_type(i),base_type) && (search_box->get_text()=="" || file.findn(search_box->get_text())!=-1)) {
- TreeItem *root = search_options->get_root();
TreeItem *ti = search_options->create_item(root);
ti->set_text(0,file);
- Ref<Texture> icon = get_icon( (has_icon(efsd->get_file_type(i),"EditorIcons")?efsd->get_file_type(i):String("Object")),"EditorIcons");
+ Ref<Texture> icon = get_icon( (has_icon(efsd->get_file_type(i),ei)?efsd->get_file_type(i):ot),ei);
ti->set_icon(0,icon);
- if (root->get_children()==ti)
- ti->select(0);
+ }
+ }
+
+ if (add_directories) {
+ for(int i=0;i<efsd->get_subdir_count();i++) {
+
+ _parse_fs(efsd->get_subdir(i));
}
}
+
}
void EditorQuickOpen::_update_search() {
@@ -96,6 +164,13 @@ void EditorQuickOpen::_update_search() {
TreeItem *root = search_options->create_item();
_parse_fs(EditorFileSystem::get_singleton()->get_filesystem());
+ if (root->get_children()) {
+ TreeItem *ti = root->get_children();
+
+ ti->select(0);
+ ti->set_as_cursor(0);
+ }
+
get_ok()->set_disabled(root->get_children()==NULL);
}
@@ -105,7 +180,7 @@ void EditorQuickOpen::_confirmed() {
TreeItem *ti = search_options->get_selected();
if (!ti)
return;
- emit_signal("quick_open","res://"+ti->get_text(0));
+ emit_signal("quick_open");
hide();
}
@@ -118,7 +193,7 @@ void EditorQuickOpen::_notification(int p_what) {
}
-String EditorQuickOpen::get_base_type() const {
+StringName EditorQuickOpen::get_base_type() const {
return base_type;
}
@@ -129,7 +204,7 @@ void EditorQuickOpen::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_confirmed"),&EditorQuickOpen::_confirmed);
ObjectTypeDB::bind_method(_MD("_sbox_input"),&EditorQuickOpen::_sbox_input);
- ADD_SIGNAL(MethodInfo("quick_open",PropertyInfo(Variant::STRING,"respath")));
+ ADD_SIGNAL(MethodInfo("quick_open"));
}
@@ -152,4 +227,7 @@ EditorQuickOpen::EditorQuickOpen() {
set_hide_on_ok(false);
search_options->connect("item_activated",this,"_confirmed");
search_options->set_hide_root(true);
+ ei="EditorIcons";
+ ot="Object";
+ add_directories=false;
}
diff --git a/tools/editor/quick_open.h b/tools/editor/quick_open.h
index 63652a442a..520f7e569d 100644
--- a/tools/editor/quick_open.h
+++ b/tools/editor/quick_open.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -38,7 +38,11 @@ class EditorQuickOpen : public ConfirmationDialog {
LineEdit *search_box;
Tree *search_options;
- String base_type;
+ StringName base_type;
+ StringName ei;
+ StringName ot;
+ bool add_directories;
+
void _update_search();
@@ -55,9 +59,12 @@ protected:
static void _bind_methods();
public:
- String get_base_type() const;
+ StringName get_base_type() const;
+
+ String get_selected() const;
+ Vector<String> get_selected_files() const;
- void popup(const String& p_base,bool p_dontclear=false);
+ void popup(const StringName& p_base,bool p_enable_multi=false,bool p_add_dirs=false,bool p_dontclear=false);
EditorQuickOpen();
};
diff --git a/tools/editor/register_exporters.h b/tools/editor/register_exporters.h
index 0e1ad2ca46..364ad5efc9 100644
--- a/tools/editor/register_exporters.h
+++ b/tools/editor/register_exporters.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/reparent_dialog.cpp b/tools/editor/reparent_dialog.cpp
index 6d0c5b867e..97b27603b2 100644
--- a/tools/editor/reparent_dialog.cpp
+++ b/tools/editor/reparent_dialog.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -36,12 +36,12 @@
void ReparentDialog::_notification(int p_what) {
- if (p_what==NOTIFICATION_ENTER_TREE) {
+ if (p_what==NOTIFICATION_ENTER_TREE) {
connect("confirmed", this,"_reparent");
}
- if (p_what==NOTIFICATION_EXIT_TREE) {
+ if (p_what==NOTIFICATION_EXIT_TREE) {
disconnect("confirmed", this,"_reparent");
}
@@ -62,7 +62,7 @@ void ReparentDialog::_reparent() {
if (tree->get_selected()) {
- emit_signal("reparent",tree->get_selected()->get_path(),node_only->is_pressed());
+ emit_signal("reparent",tree->get_selected()->get_path(),keep_transform->is_pressed());
hide();
}
}
@@ -78,37 +78,41 @@ void ReparentDialog::_bind_methods() {
ObjectTypeDB::bind_method("_reparent",&ReparentDialog::_reparent);
ObjectTypeDB::bind_method("_cancel",&ReparentDialog::_cancel);
- ADD_SIGNAL( MethodInfo("reparent",PropertyInfo(Variant::NODE_PATH,"path"),PropertyInfo(Variant::BOOL,"only_node")));
+ ADD_SIGNAL( MethodInfo("reparent",PropertyInfo(Variant::NODE_PATH,"path"),PropertyInfo(Variant::BOOL,"keep_global_xform")));
}
ReparentDialog::ReparentDialog() {
-
set_title("Reparent Node");
+
VBoxContainer *vbc = memnew( VBoxContainer );
add_child(vbc);
set_child_rect(vbc);
tree = memnew( SceneTreeEditor(false) );
-
+ tree->set_show_enabled_subscene(true);
vbc->add_margin_child("Reparent Location (Select new Parent):",tree,true);
-
+
+ tree->get_scene_tree()->connect("item_activated",this,"_reparent");
+
//Label *label = memnew( Label );
//label->set_pos( Point2( 15,8) );
//label->set_text("Reparent Location (Select new Parent):");
-
- node_only = memnew( CheckButton );
- add_child(node_only);
- node_only->hide();
+
+ keep_transform = memnew( CheckBox );
+ keep_transform->set_text("Keep Global Transform");
+ keep_transform->set_pressed(true);
+ vbc->add_child(keep_transform);
+
//vbc->add_margin_child("Options:",node_only);;
-
//cancel->connect("pressed", this,"_cancel");
get_ok()->set_text("Reparent");
+
}
diff --git a/tools/editor/reparent_dialog.h b/tools/editor/reparent_dialog.h
index 78c0df9285..296102e4b9 100644
--- a/tools/editor/reparent_dialog.h
+++ b/tools/editor/reparent_dialog.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -32,6 +32,7 @@
#include "scene/gui/dialogs.h"
#include "scene/gui/button.h"
#include "scene/gui/check_button.h"
+#include "scene/gui/check_box.h"
#include "tools/editor/scene_tree_editor.h"
#include "scene/gui/line_edit.h"
/**
@@ -42,12 +43,14 @@ class ReparentDialog : public ConfirmationDialog {
OBJ_TYPE( ReparentDialog, ConfirmationDialog );
SceneTreeEditor *tree;
- CheckButton *node_only;
+ CheckBox *keep_transform;
+
void update_tree();
void _reparent();
void _cancel();
-
+
+
protected:
void _notification(int p_what);
diff --git a/tools/editor/resources_dock.cpp b/tools/editor/resources_dock.cpp
index b69eec4a51..5e44162c93 100644
--- a/tools/editor/resources_dock.cpp
+++ b/tools/editor/resources_dock.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/resources_dock.h b/tools/editor/resources_dock.h
index 933b457b29..978291fc3f 100644
--- a/tools/editor/resources_dock.h
+++ b/tools/editor/resources_dock.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/run_settings_dialog.cpp b/tools/editor/run_settings_dialog.cpp
index e883c69939..e8c509d79d 100644
--- a/tools/editor/run_settings_dialog.cpp
+++ b/tools/editor/run_settings_dialog.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/run_settings_dialog.h b/tools/editor/run_settings_dialog.h
index fdb8857f6b..09319702f3 100644
--- a/tools/editor/run_settings_dialog.h
+++ b/tools/editor/run_settings_dialog.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/scene_tree_dock.cpp b/tools/editor/scene_tree_dock.cpp
index 49cbebdb43..5877ce1a43 100644
--- a/tools/editor/scene_tree_dock.cpp
+++ b/tools/editor/scene_tree_dock.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,11 +33,15 @@
#include "scene/resources/packed_scene.h"
#include "editor_settings.h"
#include "tools/editor/plugins/canvas_item_editor_plugin.h"
-
+#include "script_editor_debugger.h"
+#include "tools/editor/plugins/script_editor_plugin.h"
+#include "core/io/resource_saver.h"
+#include "multi_node_edit.h"
+#include "tools/editor/plugins/animation_player_editor_plugin.h"
+#include "animation_editor.h"
void SceneTreeDock::_unhandled_key_input(InputEvent p_event) {
-
uint32_t sc = p_event.key.get_scancode_with_modifiers();
if (!p_event.key.pressed || p_event.key.echo)
return;
@@ -70,7 +74,7 @@ Node* SceneTreeDock::instance(const String& p_file) {
Node*instanced_scene=NULL;
Ref<PackedScene> sdata = ResourceLoader::load(p_file);
if (sdata.is_valid())
- instanced_scene=sdata->instance();
+ instanced_scene=sdata->instance(true);
if (!instanced_scene) {
@@ -95,7 +99,7 @@ Node* SceneTreeDock::instance(const String& p_file) {
}
}
- instanced_scene->generate_instance_state();
+ //instanced_scene->generate_instance_state();
instanced_scene->set_filename( Globals::get_singleton()->localize_path(p_file) );
editor_data->get_undo_redo().create_action("Instance Scene");
@@ -105,6 +109,13 @@ Node* SceneTreeDock::instance(const String& p_file) {
editor_data->get_undo_redo().add_do_method(editor_selection,"add_node",instanced_scene);
editor_data->get_undo_redo().add_do_reference(instanced_scene);
editor_data->get_undo_redo().add_undo_method(parent,"remove_child",instanced_scene);
+
+
+ String new_name = parent->validate_child_name(instanced_scene->get_name());
+ ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger();
+ editor_data->get_undo_redo().add_do_method(sed,"live_debug_instance_node",edited_scene->get_path_to(parent),p_file,new_name);
+ editor_data->get_undo_redo().add_undo_method(sed,"live_debug_remove_node",NodePath(String(edited_scene->get_path_to(parent))+"/"+new_name));
+
editor_data->get_undo_redo().commit_action();
@@ -150,8 +161,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
case TOOL_NEW: {
- if (!_validate_no_foreign())
- break;
+ //if (!_validate_no_foreign())
+ // break;
create_dialog->popup_centered_ratio();
} break;
case TOOL_INSTANCE: {
@@ -168,8 +179,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
break;
}
- if (!_validate_no_foreign())
- break;
+ //if (!_validate_no_foreign())
+ // break;
file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
List<String> extensions;
@@ -194,8 +205,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (!current)
break;
- if (!_validate_no_foreign())
- break;
+ //if (!_validate_no_foreign())
+ // break;
connect_dialog->popup_centered_ratio();
connect_dialog->set_node(current);
@@ -205,8 +216,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
Node *current = scene_tree->get_selected();
if (!current)
break;
- if (!_validate_no_foreign())
- break;
+ //if (!_validate_no_foreign())
+ // break;
groups_editor->set_current(current);
groups_editor->popup_centered_ratio();
} break;
@@ -216,8 +227,8 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
if (!selected)
break;
- if (!_validate_no_foreign())
- break;
+ //if (!_validate_no_foreign())
+ // break;
Ref<Script> existing = selected->get_script();
if (existing.is_valid())
@@ -283,7 +294,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
for (int i = 0; i < selection.size(); i++) {
Node *top_node = selection[i];
Node *bottom_node = selection[selection.size() - 1 - i];
-
+
ERR_FAIL_COND(!top_node->get_parent());
ERR_FAIL_COND(!bottom_node->get_parent());
@@ -392,6 +403,11 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
editor_data->get_undo_redo().add_undo_method(parent,"remove_child",dup);
editor_data->get_undo_redo().add_do_reference(dup);
+ ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger();
+
+ editor_data->get_undo_redo().add_do_method(sed,"live_debug_duplicate_node",edited_scene->get_path_to(node),attempt);
+ editor_data->get_undo_redo().add_undo_method(sed,"live_debug_remove_node",NodePath(String(edited_scene->get_path_to(parent))+"/"+attempt));
+
//parent->add_child(dup);
//reselect.push_back(dup);
}
@@ -437,6 +453,19 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
reparent_dialog->set_current( nodeset );
} break;
+ case TOOL_MULTI_EDIT: {
+
+ Node*root=EditorNode::get_singleton()->get_edited_scene();
+ if (!root)
+ break;
+ Ref<MultiNodeEdit> mne = memnew( MultiNodeEdit );
+ for (const Map<Node*,Object*>::Element *E=EditorNode::get_singleton()->get_editor_selection()->get_selection().front();E;E=E->next()) {
+ mne->add_node(root->get_path_to(E->key()));
+ }
+
+ EditorNode::get_singleton()->push_item(mne.ptr());
+
+ } break;
case TOOL_ERASE: {
List<Node*> remove_list = editor_selection->get_selected_node_list();
@@ -459,7 +488,54 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
delete_dialog->popup_centered_minsize();
}
+ } break;
+ case TOOL_NEW_SCENE_FROM: {
+
+ Node *scene = editor_data->get_edited_scene_root();
+
+ if (!scene) {
+ accept->get_ok()->set_text("I see..");
+ accept->set_text("This operation can't be done without a scene.");
+ accept->popup_centered_minsize();
+ break;
+ }
+
+ List<Node*> selection = editor_selection->get_selected_node_list();
+
+ if (selection.size()!=1) {
+ accept->get_ok()->set_text("I see..");
+ accept->set_text("This operation requires a single selected node.");
+ accept->popup_centered_minsize();
+ break;
+ }
+
+ Node *tocopy = selection.front()->get();
+
+ if (tocopy!=editor_data->get_edited_scene_root() && tocopy->get_filename()!="") {
+ accept->get_ok()->set_text("I see..");
+ accept->set_text("This operation can't be done on instanced scenes.");
+ accept->popup_centered_minsize();
+ break;
+ }
+
+ new_scene_from_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+
+ List<String> extensions;
+ Ref<PackedScene> sd = memnew( PackedScene );
+ ResourceSaver::get_recognized_extensions(sd,&extensions);
+ new_scene_from_dialog->clear_filters();
+ for(int i=0;i<extensions.size();i++) {
+ new_scene_from_dialog->add_filter("*."+extensions[i]+" ; "+extensions[i].to_upper());
+ }
+
+ String existing;
+ if (extensions.size()) {
+ existing="new_scene."+extensions.front()->get().to_lower();
+ }
+ new_scene_from_dialog->set_current_path(existing);
+ new_scene_from_dialog->popup_centered_ratio();
+ new_scene_from_dialog->set_title("Save New Scene As..");
} break;
@@ -494,6 +570,8 @@ void SceneTreeDock::_notification(int p_what) {
"MoveDown",
"Duplicate",
"Reparent",
+ "CreateNewSceneFrom",
+ "MultiNodeEdit",
"Remove",
};
@@ -502,6 +580,8 @@ void SceneTreeDock::_notification(int p_what) {
for(int i=0;i<TOOL_BUTTON_MAX;i++)
tool_buttons[i]->set_icon(get_icon(button_names[i],"EditorIcons"));
+ EditorNode::get_singleton()->get_editor_selection()->connect("selection_changed",this,"_selection_changed");
+
} break;
}
}
@@ -544,9 +624,9 @@ Node *SceneTreeDock::_duplicate(Node *p_node, Map<Node*,Node*> &duplimap) {
Ref<PackedScene> sd = ResourceLoader::load( p_node->get_filename() );
ERR_FAIL_COND_V(!sd.is_valid(),NULL);
- node = sd->instance();
+ node = sd->instance(true);
ERR_FAIL_COND_V(!node,NULL);
- node->generate_instance_state();
+ //node->generate_instance_state();
} else {
Object *obj = ObjectTypeDB::instance(p_node->get_type());
ERR_FAIL_COND_V(!obj,NULL);
@@ -845,12 +925,22 @@ bool SceneTreeDock::_validate_no_foreign() {
return false;
}
+
+ if (edited_scene->get_scene_inherited_state().is_valid() && edited_scene->get_scene_inherited_state()->find_node_by_path(edited_scene->get_path_to(E->get()))>=0) {
+
+ accept->get_ok()->set_text("Makes Sense!");
+ accept->set_text("Can't operate on nodes the current scene inherits from!");
+ accept->popup_centered_minsize();
+ return false;
+
+ }
+
}
return true;
}
-void SceneTreeDock::_node_reparent(NodePath p_path,bool p_node_only) {
+void SceneTreeDock::_node_reparent(NodePath p_path,bool p_keep_global_xform) {
Node *node = scene_tree->get_selected();
@@ -903,10 +993,34 @@ void SceneTreeDock::_node_reparent(NodePath p_path,bool p_node_only) {
editor_data->get_undo_redo().add_do_method(node->get_parent(),"remove_child",node);
editor_data->get_undo_redo().add_do_method(new_parent,"add_child",node);
+
+ ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger();
+ String new_name = new_parent->validate_child_name(node->get_name());
+ editor_data->get_undo_redo().add_do_method(sed,"live_debug_reparent_node",edited_scene->get_path_to(node),edited_scene->get_path_to(new_parent),new_name,-1);
+ editor_data->get_undo_redo().add_undo_method(sed,"live_debug_reparent_node",NodePath(String(edited_scene->get_path_to(new_parent))+"/"+new_name),edited_scene->get_path_to(node->get_parent()),node->get_name(),node->get_index());
+
+ if (p_keep_global_xform) {
+ if (node->cast_to<Node2D>())
+ editor_data->get_undo_redo().add_do_method(node,"set_global_transform",node->cast_to<Node2D>()->get_global_transform());
+ if (node->cast_to<Spatial>())
+ editor_data->get_undo_redo().add_do_method(node,"set_global_transform",node->cast_to<Spatial>()->get_global_transform());
+ if (node->cast_to<Control>()) {
+ bool can_do_it=false;
+ Control *c=node->cast_to<Control>();
+ if (c->get_parent()->cast_to<Container>())
+ can_do_it=false;
+ for(int i=0;i<4;i++) {
+ if (c->get_anchor(Margin(i))!=ANCHOR_BEGIN)
+ can_do_it=false;
+ }
+ editor_data->get_undo_redo().add_do_method(node,"set_global_pos",node->cast_to<Control>()->get_global_pos());
+ }
+ }
+
editor_data->get_undo_redo().add_do_method(this,"_set_owners",edited_scene,owners);
- if (editor->get_animation_editor()->get_root()==node)
- editor_data->get_undo_redo().add_do_method(editor->get_animation_editor(),"set_root",node);
+ if (AnimationPlayerEditor::singleton->get_key_editor()->get_root()==node)
+ editor_data->get_undo_redo().add_do_method(AnimationPlayerEditor::singleton->get_key_editor(),"set_root",node);
editor_data->get_undo_redo().add_undo_method(new_parent,"remove_child",node);
@@ -933,8 +1047,28 @@ void SceneTreeDock::_node_reparent(NodePath p_path,bool p_node_only) {
editor_data->get_undo_redo().add_undo_method(node->get_parent(),"add_child",node);
editor_data->get_undo_redo().add_undo_method(node->get_parent(),"move_child",node,child_pos);
editor_data->get_undo_redo().add_undo_method(this,"_set_owners",edited_scene,owners);
- if (editor->get_animation_editor()->get_root()==node)
- editor_data->get_undo_redo().add_undo_method(editor->get_animation_editor(),"set_root",node);
+ if (AnimationPlayerEditor::singleton->get_key_editor()->get_root()==node)
+ editor_data->get_undo_redo().add_undo_method(AnimationPlayerEditor::singleton->get_key_editor(),"set_root",node);
+
+ if (p_keep_global_xform) {
+ if (node->cast_to<Node2D>())
+ editor_data->get_undo_redo().add_undo_method(node,"set_transform",node->cast_to<Node2D>()->get_transform());
+ if (node->cast_to<Spatial>())
+ editor_data->get_undo_redo().add_undo_method(node,"set_transform",node->cast_to<Spatial>()->get_transform());
+ if (node->cast_to<Control>()) {
+ bool can_do_it=false;
+ Control *c=node->cast_to<Control>();
+ if (c->get_parent()->cast_to<Container>())
+ can_do_it=false;
+ for(int i=0;i<4;i++) {
+ if (c->get_anchor(Margin(i))!=ANCHOR_BEGIN)
+ can_do_it=false;
+ }
+ editor_data->get_undo_redo().add_undo_method(node,"set_pos",node->cast_to<Control>()->get_pos());
+ }
+ }
+
+
}
@@ -1020,11 +1154,16 @@ void SceneTreeDock::_delete_confirm() {
editor_data->get_undo_redo().add_do_method(n->get_parent(),"remove_child",n);
editor_data->get_undo_redo().add_undo_method(n->get_parent(),"add_child",n);
editor_data->get_undo_redo().add_undo_method(n->get_parent(),"move_child",n,n->get_index());
- if (editor->get_animation_editor()->get_root()==n)
- editor_data->get_undo_redo().add_undo_method(editor->get_animation_editor(),"set_root",n);
+ if (AnimationPlayerEditor::singleton->get_key_editor()->get_root()==n)
+ editor_data->get_undo_redo().add_undo_method(AnimationPlayerEditor::singleton->get_key_editor(),"set_root",n);
editor_data->get_undo_redo().add_undo_method(this,"_set_owners",edited_scene,owners);
//editor_data->get_undo_redo().add_undo_method(n,"set_owner",n->get_owner());
editor_data->get_undo_redo().add_undo_reference(n);
+
+ ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger();
+ editor_data->get_undo_redo().add_do_method(sed,"live_debug_remove_and_keep_node",edited_scene->get_path_to(n),n->get_instance_ID());
+ editor_data->get_undo_redo().add_undo_method(sed,"live_debug_restore_node",n->get_instance_ID(),edited_scene->get_path_to(n->get_parent()),n->get_index());
+
}
@@ -1038,21 +1177,34 @@ void SceneTreeDock::_update_tool_buttons() {
Node *sel = scene_tree->get_selected();
bool disable = !sel || (sel!=edited_scene && sel->get_owner()!=edited_scene);
+ disable = disable || (edited_scene->get_scene_inherited_state().is_valid() && edited_scene->get_scene_inherited_state()->find_node_by_path(edited_scene->get_path_to(sel))>=0);
bool disable_root = disable || sel->get_parent()==scene_root;
+ bool disable_edit = !sel;
- tool_buttons[TOOL_INSTANCE]->set_disabled(disable);
+ tool_buttons[TOOL_INSTANCE]->set_disabled(disable_edit);
tool_buttons[TOOL_REPLACE]->set_disabled(disable);
- tool_buttons[TOOL_CONNECT]->set_disabled(disable);
- tool_buttons[TOOL_GROUP]->set_disabled(disable);
- tool_buttons[TOOL_SCRIPT]->set_disabled(disable);
+ tool_buttons[TOOL_CONNECT]->set_disabled(disable_edit);
+ tool_buttons[TOOL_GROUP]->set_disabled(disable_edit);
+ tool_buttons[TOOL_SCRIPT]->set_disabled(disable_edit);
tool_buttons[TOOL_MOVE_UP]->set_disabled(disable_root);
tool_buttons[TOOL_MOVE_DOWN]->set_disabled(disable_root);
tool_buttons[TOOL_DUPLICATE]->set_disabled(disable_root);
tool_buttons[TOOL_REPARENT]->set_disabled(disable_root);
tool_buttons[TOOL_ERASE]->set_disabled(disable);
+ tool_buttons[TOOL_NEW_SCENE_FROM]->set_disabled(disable_root);
+ tool_buttons[TOOL_MULTI_EDIT]->set_disabled(EditorNode::get_singleton()->get_editor_selection()->get_selection().size()<2);
+
}
+
+void SceneTreeDock::_selection_changed() {
+
+ tool_buttons[TOOL_MULTI_EDIT]->set_disabled(EditorNode::get_singleton()->get_editor_selection()->get_selection().size()<2);
+
+}
+
+
void SceneTreeDock::_create() {
@@ -1082,12 +1234,20 @@ void SceneTreeDock::_create() {
editor_data->get_undo_redo().create_action("Create Node");
if (edited_scene) {
+
editor_data->get_undo_redo().add_do_method(parent,"add_child",child);
editor_data->get_undo_redo().add_do_method(child,"set_owner",edited_scene);
editor_data->get_undo_redo().add_do_method(editor_selection,"clear");
editor_data->get_undo_redo().add_do_method(editor_selection,"add_node",child);
editor_data->get_undo_redo().add_do_reference(child);
editor_data->get_undo_redo().add_undo_method(parent,"remove_child",child);
+
+
+ String new_name = parent->validate_child_name(child->get_type());
+ ScriptEditorDebugger *sed = ScriptEditor::get_singleton()->get_debugger();
+ editor_data->get_undo_redo().add_do_method(sed,"live_debug_create_node",edited_scene->get_path_to(parent),child->get_type(),new_name);
+ editor_data->get_undo_redo().add_undo_method(sed,"live_debug_remove_node",NodePath(String(edited_scene->get_path_to(parent))+"/"+new_name));
+
} else {
editor_data->get_undo_redo().add_do_method(editor,"set_edited_scene",child);
@@ -1152,24 +1312,26 @@ void SceneTreeDock::_create() {
}
-
String newname=n->get_name();
n->replace_by(newnode,true);
-
if (n==edited_scene) {
edited_scene=newnode;
editor->set_edited_scene(newnode);
}
-
-
-
+ //small hack to make collisionshapes and other kind of nodes to work
+ for(int i=0;i<newnode->get_child_count();i++) {
+ Node *c=newnode->get_child(i);
+ c->call("set_transform", c->call("get_transform") );
+ }
editor_data->get_undo_redo().clear_history();
- memdelete(n);
newnode->set_name(newname);
+
editor->push_item(newnode);
+ memdelete(n);
+
_update_tool_buttons();
}
@@ -1196,7 +1358,10 @@ void SceneTreeDock::import_subscene() {
void SceneTreeDock::_import_subscene() {
Node* parent = scene_tree->get_selected();
- ERR_FAIL_COND(!parent);
+ if (!parent) {
+ parent = editor_data->get_edited_scene_root();
+ ERR_FAIL_COND(!parent);
+ }
import_subscene_dialog->move(parent,edited_scene);
editor_data->get_undo_redo().clear_history(); //no undo for now..
@@ -1213,6 +1378,59 @@ void SceneTreeDock::_import_subscene() {
*/
}
+void SceneTreeDock::_new_scene_from(String p_file) {
+
+ List<Node*> selection = editor_selection->get_selected_node_list();
+
+ if (selection.size()!=1) {
+ accept->get_ok()->set_text("I see..");
+ accept->set_text("This operation requires a single selected node.");
+ accept->popup_centered_minsize();
+ return;
+ }
+
+ Node *base = selection.front()->get();
+
+ Map<Node*,Node*> reown;
+ reown[editor_data->get_edited_scene_root()]=base;
+ Node *copy = base->duplicate_and_reown(reown);
+ if (copy) {
+
+ Ref<PackedScene> sdata = memnew( PackedScene );
+ Error err = sdata->pack(copy);
+ memdelete(copy);
+
+ if (err!=OK) {
+ accept->get_ok()->set_text("I see..");
+ accept->set_text("Couldn't save new scene. Likely dependencies (instances) couldn't be satisfied.");
+ accept->popup_centered_minsize();
+ return;
+ }
+
+ int flg=0;
+ if (EditorSettings::get_singleton()->get("on_save/compress_binary_resources"))
+ flg|=ResourceSaver::FLAG_COMPRESS;
+ if (EditorSettings::get_singleton()->get("on_save/save_paths_as_relative"))
+ flg|=ResourceSaver::FLAG_RELATIVE_PATHS;
+
+
+ err = ResourceSaver::save(p_file,sdata,flg);
+ if (err!=OK) {
+ accept->get_ok()->set_text("I see..");
+ accept->set_text("Error saving scene.");
+ accept->popup_centered_minsize();
+ return;
+ }
+
+ } else {
+ accept->get_ok()->set_text("I see..");
+ accept->set_text("Error duplicating scene to save it.");
+ accept->popup_centered_minsize();
+ return;
+ }
+
+}
+
void SceneTreeDock::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_tool_selected"),&SceneTreeDock::_tool_selected);
@@ -1229,6 +1447,8 @@ void SceneTreeDock::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_delete_confirm"),&SceneTreeDock::_delete_confirm);
ObjectTypeDB::bind_method(_MD("_node_prerenamed"),&SceneTreeDock::_node_prerenamed);
ObjectTypeDB::bind_method(_MD("_import_subscene"),&SceneTreeDock::_import_subscene);
+ ObjectTypeDB::bind_method(_MD("_selection_changed"),&SceneTreeDock::_selection_changed);
+ ObjectTypeDB::bind_method(_MD("_new_scene_from"),&SceneTreeDock::_new_scene_from);
ObjectTypeDB::bind_method(_MD("instance"),&SceneTreeDock::instance);
}
@@ -1301,9 +1521,10 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor,Node *p_scene_root,EditorSelec
scene_tree->set_undo_redo(&editor_data->get_undo_redo());
scene_tree->set_editor_selection(editor_selection);
+
HBoxContainer *hbc_bottom = memnew( HBoxContainer );
vbc->add_child(hbc_bottom);
-
+ hbc_bottom->add_constant_override("separation", 0);
tb = memnew( ToolButton );
tb->connect("pressed",this,"_tool_selected",make_binds(TOOL_MOVE_UP, false));
@@ -1332,6 +1553,18 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor,Node *p_scene_root,EditorSelec
hbc_bottom->add_spacer();
tb = memnew( ToolButton );
+ tb->connect("pressed",this,"_tool_selected",make_binds(TOOL_NEW_SCENE_FROM, false));
+ tb->set_tooltip("Create New Scene From Node(s)");
+ hbc_bottom->add_child(tb);
+ tool_buttons[TOOL_NEW_SCENE_FROM]=tb;
+
+ tb = memnew( ToolButton );
+ tb->connect("pressed",this,"_tool_selected",make_binds(TOOL_MULTI_EDIT, false));
+ tb->set_tooltip("Multi-Edit Selected Nodes");
+ hbc_bottom->add_child(tb);
+ tool_buttons[TOOL_MULTI_EDIT]=tb;
+
+ tb = memnew( ToolButton );
tb->connect("pressed",this,"_tool_selected",make_binds(TOOL_ERASE, false));
tb->set_tooltip("Erase Selected Node(s)");
hbc_bottom->add_child(tb);
@@ -1345,12 +1578,15 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor,Node *p_scene_root,EditorSelec
groups_editor = memnew( GroupsEditor );
add_child(groups_editor);
groups_editor->set_undo_redo(&editor_data->get_undo_redo());
+
connect_dialog = memnew( ConnectionsDialog(p_editor) );
add_child(connect_dialog);
connect_dialog->set_undoredo(&editor_data->get_undo_redo());
+
script_create_dialog = memnew( ScriptCreateDialog );
add_child(script_create_dialog);
script_create_dialog->connect("script_created",this,"_script_created");
+
reparent_dialog = memnew( ReparentDialog );
add_child(reparent_dialog);
reparent_dialog->connect("reparent",this,"_node_reparent");
@@ -1366,10 +1602,16 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor,Node *p_scene_root,EditorSelec
delete_dialog = memnew( ConfirmationDialog );
add_child(delete_dialog);
delete_dialog->connect("confirmed",this,"_delete_confirm");
+
import_subscene_dialog = memnew( EditorSubScene );
add_child(import_subscene_dialog);
import_subscene_dialog->connect("subscene_selected",this,"_import_subscene");
+ new_scene_from_dialog = memnew( EditorFileDialog );
+ new_scene_from_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ add_child(new_scene_from_dialog);
+ new_scene_from_dialog->connect("file_selected",this,"_new_scene_from");
+
first_enter=true;
diff --git a/tools/editor/scene_tree_dock.h b/tools/editor/scene_tree_dock.h
index f0bbbad6be..114e2c5c97 100644
--- a/tools/editor/scene_tree_dock.h
+++ b/tools/editor/scene_tree_dock.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -62,6 +62,8 @@ class SceneTreeDock : public VBoxContainer {
TOOL_MOVE_DOWN,
TOOL_DUPLICATE,
TOOL_REPARENT,
+ TOOL_NEW_SCENE_FROM,
+ TOOL_MULTI_EDIT,
TOOL_ERASE,
TOOL_BUTTON_MAX
};
@@ -89,6 +91,7 @@ class SceneTreeDock : public VBoxContainer {
ReparentDialog *reparent_dialog;
EditorFileDialog *file;
EditorSubScene *import_subscene_dialog;
+ EditorFileDialog *new_scene_from_dialog;
bool first_enter;
@@ -98,7 +101,7 @@ class SceneTreeDock : public VBoxContainer {
EditorNode *editor;
Node *_duplicate(Node *p_node, Map<Node*,Node*> &duplimap);
- void _node_reparent(NodePath p_path,bool p_node_only);
+ void _node_reparent(NodePath p_path, bool p_keep_global_xform);
void _set_owners(Node *p_owner, const Array& p_nodes);
void _load_request(const String& p_path);
void _script_open_request(const Ref<Script>& p_script);
@@ -118,7 +121,10 @@ class SceneTreeDock : public VBoxContainer {
void _import_subscene();
+ void _new_scene_from(String p_file);
+
bool _validate_no_foreign();
+ void _selection_changed();
void _fill_path_renames(Vector<StringName> base_path,Vector<StringName> new_base_path,Node * p_node, List<Pair<NodePath,NodePath> > *p_renames);
diff --git a/tools/editor/scene_tree_editor.cpp b/tools/editor/scene_tree_editor.cpp
index fd841028a2..ea7d760133 100644
--- a/tools/editor/scene_tree_editor.cpp
+++ b/tools/editor/scene_tree_editor.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,15 +34,13 @@
#include "scene/main/viewport.h"
#include "tools/editor/plugins/canvas_item_editor_plugin.h"
+#include "scene/resources/packed_scene.h"
+
Node *SceneTreeEditor::get_scene_node() {
ERR_FAIL_COND_V(!is_inside_tree(),NULL);
- if (get_tree()->get_root()->get_child_count() && get_tree()->get_root()->get_child(0)->cast_to<EditorNode>())
- return get_tree()->get_root()->get_child(0)->cast_to<EditorNode>()->get_edited_scene();
- else
- return get_tree()->get_root();
- return NULL;
+ return get_tree()->get_edited_scene_root();
}
@@ -57,22 +55,58 @@ void SceneTreeEditor::_subscene_option(int p_idx) {
switch(p_idx) {
- case SCENE_MENU_SHOW_CHILDREN: {
+ case SCENE_MENU_EDITABLE_CHILDREN: {
- if (node->has_meta("__editor_show_subtree")) {
- instance_menu->set_item_checked(0,true);
- node->set_meta("__editor_show_subtree",Variant());
- _update_tree();
- } else {
- node->set_meta("__editor_show_subtree",true);
- _update_tree();
+ bool editable = EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(node);
+ editable = !editable;
+
+ //node->set_instance_children_editable(editable);
+ EditorNode::get_singleton()->get_edited_scene()->set_editable_instance(node,editable);
+ instance_menu->set_item_checked(0,editable);
+ if (editable) {
+ node->set_scene_instance_load_placeholder(false);
+ instance_menu->set_item_checked(1,false);
}
+ _update_tree();
+
+ } break;
+ case SCENE_MENU_USE_PLACEHOLDER: {
+
+ bool placeholder = node->get_scene_instance_load_placeholder();
+ placeholder = !placeholder;
+
+ //node->set_instance_children_editable(editable);
+ if (placeholder) {
+ EditorNode::get_singleton()->get_edited_scene()->set_editable_instance(node,false);
+ }
+ node->set_scene_instance_load_placeholder(placeholder);
+ instance_menu->set_item_checked(0,false);
+ instance_menu->set_item_checked(1,placeholder);
+
+ _update_tree();
+
} break;
case SCENE_MENU_OPEN: {
emit_signal("open",node->get_filename());
} break;
+ case SCENE_MENU_CLEAR_INHERITANCE: {
+ clear_inherit_confirm->popup_centered_minsize();
+ } break;
+ case SCENE_MENU_OPEN_INHERITED: {
+ if (node && node->get_scene_inherited_state().is_valid()) {
+ emit_signal("open",node->get_scene_inherited_state()->get_path());
+ }
+ } break;
+ case SCENE_MENU_CLEAR_INHERITANCE_CONFIRM: {
+ if (node && node->get_scene_inherited_state().is_valid()) {
+ node->set_scene_inherited_state(Ref<SceneState>());
+ update_tree();
+ EditorNode::get_singleton()->get_property_editor()->update_tree();
+ }
+
+ } break;
}
@@ -94,15 +128,33 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item,int p_column,int p_id)
Rect2 item_rect = tree->get_item_rect(item,0);
item_rect.pos.y-=tree->get_scroll().y;
item_rect.pos+=tree->get_global_pos();
- instance_menu->set_pos(item_rect.pos+Vector2(0,item_rect.size.y));
- instance_menu->set_size(Vector2(item_rect.size.x,0));
- if (n->has_meta("__editor_show_subtree"))
- instance_menu->set_item_checked(0,true);
- else
- instance_menu->set_item_checked(0,false);
- instance_menu->popup();
- instance_node=n->get_instance_ID();
+ if (n==get_scene_node()) {
+ inheritance_menu->set_pos(item_rect.pos+Vector2(0,item_rect.size.y));
+ inheritance_menu->set_size(Vector2(item_rect.size.x,0));
+ inheritance_menu->popup();
+ instance_node=n->get_instance_ID();
+
+ } else {
+ instance_menu->set_pos(item_rect.pos+Vector2(0,item_rect.size.y));
+ instance_menu->set_size(Vector2(item_rect.size.x,0));
+ if (EditorNode::get_singleton()->get_edited_scene()->is_editable_instance(n))
+ instance_menu->set_item_checked(0,true);
+ else
+ instance_menu->set_item_checked(0,false);
+
+ if (n->get_owner()==get_scene_node()) {
+ instance_menu->set_item_checked(1,n->get_scene_instance_load_placeholder());
+ instance_menu->set_item_disabled(1,false);
+ } else {
+
+ instance_menu->set_item_checked(1,false);
+ instance_menu->set_item_disabled(1,true);
+ }
+
+ instance_menu->popup();
+ instance_node=n->get_instance_ID();
+ }
//emit_signal("open",n->get_filename());
} else if (p_id==BUTTON_SCRIPT) {
RefPtr script=n->get_script();
@@ -168,20 +220,22 @@ void SceneTreeEditor::_add_nodes(Node *p_node,TreeItem *p_parent) {
bool part_of_subscene=false;
- if (!display_foreign && p_node->get_owner()!=get_scene_node() && p_node!=get_scene_node()) {
+ if (!display_foreign && p_node->get_owner()!=get_scene_node() && p_node!=get_scene_node()) {
- if ((show_enabled_subscene || can_open_instance) && p_node->get_owner() && p_node->get_owner()->get_owner()==get_scene_node() && p_node->get_owner()->has_meta("__editor_show_subtree")) {
+ if ((show_enabled_subscene || can_open_instance) && p_node->get_owner() && (get_scene_node()->is_editable_instance(p_node->get_owner()))) {
part_of_subscene=true;
//allow
} else {
return;
}
+ } else {
+ part_of_subscene = get_scene_node()->get_scene_inherited_state().is_valid() && get_scene_node()->get_scene_inherited_state()->find_node_by_path(get_scene_node()->get_path_to(p_node))>=0;
}
TreeItem *item = tree->create_item(p_parent);
item->set_text(0, p_node->get_name() );
- if (can_rename && (p_node->get_owner() == get_scene_node() || p_node==get_scene_node()))
+ if (can_rename && !part_of_subscene /*(p_node->get_owner() == get_scene_node() || p_node==get_scene_node())*/)
item->set_editable(0, true);
item->set_selectable(0,true);
@@ -199,6 +253,7 @@ void SceneTreeEditor::_add_nodes(Node *p_node,TreeItem *p_parent) {
icon=get_icon( (has_icon(p_node->get_type(),"EditorIcons")?p_node->get_type():String("Object")),"EditorIcons");
item->set_icon(0, icon );
item->set_metadata( 0,p_node->get_path() );
+
if (part_of_subscene) {
//item->set_selectable(0,marked_selectable);
@@ -221,7 +276,10 @@ void SceneTreeEditor::_add_nodes(Node *p_node,TreeItem *p_parent) {
}
}
- if (p_node!=get_scene_node() && p_node->get_filename()!="" && can_open_instance) {
+ if (p_node==get_scene_node() && p_node->get_scene_inherited_state().is_valid()) {
+ item->add_button(0,get_icon("InstanceOptions","EditorIcons"),BUTTON_SUBSCENE);
+ item->set_tooltip(0,"Inherits: "+p_node->get_scene_inherited_state()->get_path()+"\nType: "+p_node->get_type());
+ } else if (p_node!=get_scene_node() && p_node->get_filename()!="" && can_open_instance) {
item->add_button(0,get_icon("InstanceOptions","EditorIcons"),BUTTON_SUBSCENE);
item->set_tooltip(0,"Instance: "+p_node->get_filename()+"\nType: "+p_node->get_type());
@@ -487,8 +545,11 @@ void SceneTreeEditor::_notification(int p_what) {
get_tree()->connect("tree_changed",this,"_tree_changed");
get_tree()->connect("node_removed",this,"_node_removed");
- instance_menu->set_item_icon(2,get_icon("Load","EditorIcons"));
+ instance_menu->set_item_icon(3,get_icon("Load","EditorIcons"));
tree->connect("item_collapsed",this,"_cell_collapsed");
+ inheritance_menu->set_item_icon(2,get_icon("Load","EditorIcons"));
+ clear_inherit_confirm->connect("confirmed",this,"_subscene_option",varray(SCENE_MENU_CLEAR_INHERITANCE_CONFIRM));
+
// get_scene()->connect("tree_changed",this,"_tree_changed",Vector<Variant>(),CONNECT_DEFERRED);
// get_scene()->connect("node_removed",this,"_node_removed",Vector<Variant>(),CONNECT_DEFERRED);
@@ -499,7 +560,7 @@ void SceneTreeEditor::_notification(int p_what) {
get_tree()->disconnect("tree_changed",this,"_tree_changed");
get_tree()->disconnect("node_removed",this,"_node_removed");
tree->disconnect("item_collapsed",this,"_cell_collapsed");
- _update_tree();
+ clear_inherit_confirm->disconnect("confirmed",this,"_subscene_option");
}
}
@@ -583,20 +644,28 @@ void SceneTreeEditor::_rename_node(ObjectID p_node,const String& p_name) {
void SceneTreeEditor::_renamed() {
TreeItem *which=tree->get_edited();
-
+
ERR_FAIL_COND(!which);
NodePath np = which->get_metadata(0);
Node *n=get_node(np);
ERR_FAIL_COND(!n);
+ String new_name=which->get_text(0);
+ if (new_name.find(".") != -1 || new_name.find("/") != -1) {
+
+ error->set_text("Invalid node name, the following characters are not allowed:\n \".\", \"/\"");
+ error->popup_centered_minsize();
+ new_name=n->get_name();
+ }
+
if (!undo_redo) {
- n->set_name( which->get_text(0) );
+ n->set_name( new_name );
which->set_metadata(0,n->get_path());
emit_signal("node_renamed");
} else {
undo_redo->create_action("Rename Node");
- emit_signal("node_prerename",n,which->get_text(0));
- undo_redo->add_do_method(this,"_rename_node",n->get_instance_ID(),which->get_text(0));
+ emit_signal("node_prerename",n,new_name);
+ undo_redo->add_do_method(this,"_rename_node",n->get_instance_ID(),new_name);
undo_redo->add_undo_method(this,"_rename_node",n->get_instance_ID(),n->get_name());
undo_redo->commit_action();
}
@@ -788,12 +857,27 @@ SceneTreeEditor::SceneTreeEditor(bool p_label,bool p_can_rename, bool p_can_open
blocked=0;
instance_menu = memnew( PopupMenu );
- instance_menu->add_check_item("Show Children",SCENE_MENU_SHOW_CHILDREN);
+ instance_menu->add_check_item("Editable Children",SCENE_MENU_EDITABLE_CHILDREN);
+ instance_menu->add_check_item("Load As Placeholder",SCENE_MENU_USE_PLACEHOLDER);
instance_menu->add_separator();
instance_menu->add_item("Open in Editor",SCENE_MENU_OPEN);
instance_menu->connect("item_pressed",this,"_subscene_option");
add_child(instance_menu);
+ inheritance_menu = memnew( PopupMenu );
+ inheritance_menu->add_item("Clear Inheritance",SCENE_MENU_CLEAR_INHERITANCE);
+ inheritance_menu->add_separator();
+ inheritance_menu->add_item("Open in Editor",SCENE_MENU_OPEN_INHERITED);
+ inheritance_menu->connect("item_pressed",this,"_subscene_option");
+
+ add_child(inheritance_menu);
+
+ clear_inherit_confirm = memnew( ConfirmationDialog );
+ clear_inherit_confirm->set_text("Clear Inheritance? (No Undo!)");
+ clear_inherit_confirm->get_ok()->set_text("Clear!");
+ add_child(clear_inherit_confirm);
+
+
}
@@ -840,7 +924,7 @@ void SceneTreeDialog::_cancel() {
void SceneTreeDialog::_select() {
if (tree->get_selected()) {
- emit_signal("selected",tree->get_selected()->get_path());
+ emit_signal("selected",tree->get_selected()->get_path());
hide();
}
}
@@ -851,7 +935,6 @@ void SceneTreeDialog::_bind_methods() {
ObjectTypeDB::bind_method("_cancel",&SceneTreeDialog::_cancel);
ADD_SIGNAL( MethodInfo("selected",PropertyInfo(Variant::NODE_PATH,"path")));
-
}
@@ -863,7 +946,7 @@ SceneTreeDialog::SceneTreeDialog() {
add_child(tree);
set_child_rect(tree);
-
+ tree->get_scene_tree()->connect("item_activated",this,"_select");
}
diff --git a/tools/editor/scene_tree_editor.h b/tools/editor/scene_tree_editor.h
index b05a52a2da..334debc148 100644
--- a/tools/editor/scene_tree_editor.h
+++ b/tools/editor/scene_tree_editor.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -52,16 +52,22 @@ class SceneTreeEditor : public Control {
};
enum {
- SCENE_MENU_SHOW_CHILDREN,
+ SCENE_MENU_EDITABLE_CHILDREN,
+ SCENE_MENU_USE_PLACEHOLDER,
SCENE_MENU_OPEN,
+ SCENE_MENU_CLEAR_INHERITANCE,
+ SCENE_MENU_OPEN_INHERITED,
+ SCENE_MENU_CLEAR_INHERITANCE_CONFIRM,
};
Tree *tree;
Node *selected;
PopupMenu *instance_menu;
+ PopupMenu *inheritance_menu;
ObjectID instance_node;
AcceptDialog *error;
+ ConfirmationDialog *clear_inherit_confirm;
int blocked;
diff --git a/tools/editor/scenes.cpp b/tools/editor/scenes.cpp
index ada5751b5a..e6569c98a9 100644
--- a/tools/editor/scenes.cpp
+++ b/tools/editor/scenes.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/scenes.h b/tools/editor/scenes.h
index 463c3b5e18..bae9ef65f0 100644
--- a/tools/editor/scenes.h
+++ b/tools/editor/scenes.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/scenes_dock.cpp b/tools/editor/scenes_dock.cpp
index 9153616775..5abc4992df 100644
--- a/tools/editor/scenes_dock.cpp
+++ b/tools/editor/scenes_dock.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -35,15 +35,30 @@
#include "os/os.h"
#include "editor_node.h"
+#include "editor_settings.h"
+
bool ScenesDock::_create_tree(TreeItem *p_parent,EditorFileSystemDirectory *p_dir) {
- String search_term = tree_filter->get_search_term();
- ScenesDockFilter::FilterOption file_filter = tree_filter->get_file_filter();
TreeItem *item = tree->create_item(p_parent);
- item->set_text(0,p_dir->get_name()+"/");
+ String dname=p_dir->get_name();
+ if (dname=="")
+ dname="res://";
+
+ item->set_text(0,dname);
item->set_icon(0,get_icon("Folder","EditorIcons"));
- item->set_custom_bg_color(0,get_color("prop_subsection","Editor"));
+ item->set_selectable(0,true);
+ String lpath = p_dir->get_path();
+ if (lpath!="res://" && lpath.ends_with("/")) {
+ lpath=lpath.substr(0,lpath.length()-1);
+ }
+ item->set_metadata(0,lpath);
+ if (lpath==path) {
+ item->select(0);
+ }
+
+
+ //item->set_custom_bg_color(0,get_color("prop_subsection","Editor"));
bool has_items=false;
@@ -52,7 +67,7 @@ bool ScenesDock::_create_tree(TreeItem *p_parent,EditorFileSystemDirectory *p_di
if (_create_tree(item,p_dir->get_subdir(i)))
has_items=true;
}
-
+#if 0
for (int i=0;i<p_dir->get_file_count();i++) {
String file_name = p_dir->get_file(i);
@@ -89,13 +104,13 @@ bool ScenesDock::_create_tree(TreeItem *p_parent,EditorFileSystemDirectory *p_di
has_items=true;
}
-
- if (!has_items) {
+#endif
+ /*if (!has_items) {
memdelete(item);
return false;
- }
+ }*/
return true;
}
@@ -105,7 +120,28 @@ void ScenesDock::_update_tree() {
tree->clear();
updating_tree=true;
- _create_tree(NULL,EditorFileSystem::get_singleton()->get_filesystem());
+ TreeItem *root = tree->create_item();
+ TreeItem *favorites = tree->create_item(root);
+ favorites->set_icon(0, get_icon("Favorites","EditorIcons") );
+ favorites->set_text(0,"Favorites:");
+ favorites->set_selectable(0,false);
+ Vector<String> faves = EditorSettings::get_singleton()->get_favorite_dirs();
+ for(int i=0;i<faves.size();i++) {
+ if (!faves[i].begins_with("res://"))
+ continue;
+
+ TreeItem *ti = tree->create_item(favorites);
+ String fv = faves[i];
+ if (fv=="res://")
+ ti->set_text(0,"/");
+ else
+ ti->set_text(0,faves[i].get_file());
+ ti->set_icon(0,get_icon("Folder","EditorIcons"));
+ ti->set_selectable(0,true);
+ ti->set_metadata(0,faves[i]);
+ }
+
+ _create_tree(root,EditorFileSystem::get_singleton()->get_filesystem());
updating_tree=false;
}
@@ -117,68 +153,197 @@ void ScenesDock::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
+ if (initialized)
+ return;
+ initialized=true;
- EditorFileSystem::get_singleton()->connect("filesystem_changed",this,"_update_tree");
+ EditorFileSystem::get_singleton()->connect("filesystem_changed",this,"_fs_changed");
button_reload->set_icon( get_icon("Reload","EditorIcons"));
button_favorite->set_icon( get_icon("Favorites","EditorIcons"));
+ button_fav_up->set_icon( get_icon("MoveUp","EditorIcons"));
+ button_fav_down->set_icon( get_icon("MoveDown","EditorIcons"));
button_instance->set_icon( get_icon("Add","EditorIcons"));
button_open->set_icon( get_icon("Folder","EditorIcons"));
+ button_back->set_icon( get_icon("Filesystem","EditorIcons"));
+ display_mode->set_icon( get_icon("FileList","EditorIcons"));
+ display_mode->connect("pressed",this,"_change_file_display");
+ file_options->set_icon( get_icon("Tools","EditorIcons"));
+ files->connect("item_activated",this,"_select_file");
+ button_hist_next->connect("pressed",this,"_fw_history");
+ button_hist_prev->connect("pressed",this,"_bw_history");
- String path = Globals::get_singleton()->get_resource_path()+"/favorites.cfg";
- FileAccess *f=FileAccess::open(path,FileAccess::READ);
- if (f) {
-
- String l = f->get_line();
+ button_hist_next->set_icon( get_icon("Forward","EditorIcons"));
+ button_hist_prev->set_icon( get_icon("Back","EditorIcons"));
+ file_options->get_popup()->connect("item_pressed",this,"_file_option");
- while(l!="") {
- favorites.insert(l);
- l = f->get_line();
- }
+ button_back->connect("pressed",this,"_go_to_tree",varray(),CONNECT_DEFERRED);
+ current_path->connect("text_entered",this,"_go_to_dir");
+ _update_tree(); //maybe it finished already
- f->close();
- memdelete(f);
+ if (EditorFileSystem::get_singleton()->is_scanning()) {
+ _set_scannig_mode();
}
-
-
- _update_tree(); //maybe it finished already
+ } break;
+ case NOTIFICATION_PROCESS: {
+ if (EditorFileSystem::get_singleton()->is_scanning()) {
+ scanning_progress->set_val(EditorFileSystem::get_singleton()->get_scanning_progress()*100);
+ }
} break;
case NOTIFICATION_EXIT_TREE: {
} break;
- case NOTIFICATION_PROCESS: {
+ case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
+ display_mode->set_pressed(int(EditorSettings::get_singleton()->get("file_dialog/display_mode"))==EditorFileDialog::DISPLAY_LIST);
+
+ _change_file_display();
} break;
}
}
-void ScenesDock::_favorite_toggled() {
- if (updating_tree)
+
+
+void ScenesDock::_dir_selected() {
+
+ TreeItem *ti = tree->get_selected();
+ if (!ti)
return;
+ String dir = ti->get_metadata(0);
+ bool found=false;
+ Vector<String> favorites = EditorSettings::get_singleton()->get_favorite_dirs();
+ for(int i=0;i<favorites.size();i++) {
+
+ if (favorites[i]==dir) {
+ found=true;
+ break;
+ }
+ }
+
+
+ button_favorite->set_pressed(found);
+ if (ti->get_parent() && ti->get_parent()->get_parent()==tree->get_root() && !ti->get_parent()->get_prev()) {
+
+ //a favorite!!!
+ button_fav_up->set_disabled(!ti->get_prev());
+ button_fav_down->set_disabled(!ti->get_next());
+ } else {
+ button_fav_up->set_disabled(true);
+ button_fav_down->set_disabled(true);
+
+ }
+
+}
+void ScenesDock::_fav_up_pressed() {
TreeItem *sel = tree->get_selected();
if (!sel)
- return; //?
+ return ;
- bool faved = sel->is_checked(0);
- String path = sel->get_metadata(0);
- if (faved)
- favorites.insert(path);
- else
- favorites.erase(path);
+ if (!sel->get_prev())
+ return;
+
+ String sw = sel->get_prev()->get_metadata(0);
+ String txt = sel->get_metadata(0);
+
+ Vector<String> favorited = EditorSettings::get_singleton()->get_favorite_dirs();
+
+ int a_idx=favorited.find(sw);
+ int b_idx=favorited.find(txt);
- timer->start();
+ if (a_idx==-1 || b_idx==-1)
+ return;
+ SWAP(favorited[a_idx],favorited[b_idx]);
+
+ EditorSettings::get_singleton()->set_favorite_dirs(favorited);
+
+ _update_tree();
+
+ if (!tree->get_root() || !tree->get_root()->get_children() || !tree->get_root()->get_children()->get_children())
+ return;
+ sel = tree->get_root()->get_children()->get_children();
+ while(sel) {
+ String t = sel->get_metadata(0);
+ if (t==txt) {
+ sel->select(0);
+ return;
+ }
+ sel=sel->get_next();
+ }
}
-void ScenesDock::_favorites_toggled(bool p_toggled) {
+void ScenesDock::_fav_down_pressed() {
+
+ TreeItem *sel = tree->get_selected();
+ if (!sel)
+ return ;
+
+ if (!sel->get_next())
+ return;
+
+ String sw = sel->get_next()->get_metadata(0);
+ String txt = sel->get_metadata(0);
+
+ Vector<String> favorited = EditorSettings::get_singleton()->get_favorite_dirs();
+
+ int a_idx=favorited.find(sw);
+ int b_idx=favorited.find(txt);
+
+ if (a_idx==-1 || b_idx==-1)
+ return;
+ SWAP(favorited[a_idx],favorited[b_idx]);
+
+ EditorSettings::get_singleton()->set_favorite_dirs(favorited);
_update_tree();
+
+ if (!tree->get_root() || !tree->get_root()->get_children() || !tree->get_root()->get_children()->get_children())
+ return;
+ sel = tree->get_root()->get_children()->get_children();
+ while(sel) {
+
+ String t = sel->get_metadata(0);
+ if (t==txt) {
+ sel->select(0);
+ return;
+ }
+ sel=sel->get_next();
+ }
+}
+
+void ScenesDock::_favorites_pressed() {
+
+ TreeItem *sel = tree->get_selected();
+ if (!sel)
+ return ;
+ String dir = sel->get_metadata(0);
+
+ int idx = -1;
+ Vector<String> favorites = EditorSettings::get_singleton()->get_favorite_dirs();
+ for(int i=0;i<favorites.size();i++) {
+
+ if (favorites[i]==dir) {
+ idx=i;
+ break;
+ }
+ }
+
+ if (button_favorite->is_pressed() && idx==-1) {
+ favorites.push_back(dir);
+ EditorSettings::get_singleton()->set_favorite_dirs(favorites);
+ _update_tree();
+ } else if (!button_favorite->is_pressed() && idx!=-1) {
+ favorites.remove(idx);
+ EditorSettings::get_singleton()->set_favorite_dirs(favorites);
+ _update_tree();
+ }
+
}
String ScenesDock::get_selected_path() const {
@@ -192,72 +357,744 @@ String ScenesDock::get_selected_path() const {
void ScenesDock::_instance_pressed() {
- TreeItem *sel = tree->get_selected();
- if (!sel)
- return;
- String path = sel->get_metadata(0);
+ if (tree_mode)
+ {
+ TreeItem *sel = tree->get_selected();
+ if (!sel)
+ return;
+ String path = sel->get_metadata(0);
+ }
+ else
+ {
+ int idx = -1;
+ for (int i = 0; i<files->get_item_count(); i++) {
+ if (files->is_selected(i))
+ {
+ idx = i;
+ break;
+ }
+ }
+
+ if (idx<0)
+ return;
+
+ path = files->get_item_metadata(idx);
+ }
+
emit_signal("instance",path);
}
-void ScenesDock::_open_pressed(){
+void ScenesDock::_thumbnail_done(const String& p_path,const Ref<Texture>& p_preview, const Variant& p_udata) {
- TreeItem *sel = tree->get_selected();
- if (!sel) {
+ if (p_preview.is_valid() && path==p_path.get_base_dir()) {
+
+ int idx=p_udata;
+ if (idx>=files->get_item_count())
+ return;
+ String fpath = files->get_item_metadata(idx);
+ if (fpath!=p_path)
+ return;
+ files->set_item_icon(idx,p_preview);
+
+ }
+
+}
+
+void ScenesDock::_change_file_display() {
+
+ if (display_mode->is_pressed()) {
+ display_mode->set_icon( get_icon("FileThumbnail","EditorIcons"));
+
+ } else {
+ display_mode->set_icon( get_icon("FileList","EditorIcons"));
+ }
+
+ _update_files(true);
+}
+
+void ScenesDock::_update_files(bool p_keep_selection) {
+
+ Set<String> cselection;
+
+ if (p_keep_selection) {
+
+ for(int i=0;i<files->get_item_count();i++) {
+
+ if (files->is_selected(i))
+ cselection.insert(files->get_item_text(i));
+ }
+ }
+
+ files->clear();
+
+ EditorFileSystemDirectory *efd = EditorFileSystem::get_singleton()->get_path(path);
+ if (!efd)
return;
+
+ int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
+ Ref<Texture> folder_thumbnail;
+ Ref<Texture> file_thumbnail;
+
+ bool use_thumbnails=!display_mode->is_pressed();
+
+ if (use_thumbnails) { //thumbnails
+
+ files->set_max_columns(0);
+ files->set_icon_mode(ItemList::ICON_MODE_TOP);
+ files->set_fixed_column_width(thumbnail_size*3/2);
+ files->set_max_text_lines(2);
+ files->set_min_icon_size(Size2(thumbnail_size,thumbnail_size));
+
+ if (!has_icon("ResizedFolder","EditorIcons")) {
+ Ref<ImageTexture> folder = get_icon("FolderBig","EditorIcons");
+ Image img = folder->get_data();
+ img.resize(thumbnail_size,thumbnail_size);
+ Ref<ImageTexture> resized_folder = Ref<ImageTexture>( memnew( ImageTexture));
+ resized_folder->create_from_image(img,0);
+ Theme::get_default()->set_icon("ResizedFolder","EditorIcons",resized_folder);
+ }
+
+ folder_thumbnail = get_icon("ResizedFolder","EditorIcons");
+
+ if (!has_icon("ResizedFile","EditorIcons")) {
+ Ref<ImageTexture> file = get_icon("FileBig","EditorIcons");
+ Image img = file->get_data();
+ img.resize(thumbnail_size,thumbnail_size);
+ Ref<ImageTexture> resized_file = Ref<ImageTexture>( memnew( ImageTexture));
+ resized_file->create_from_image(img,0);
+ Theme::get_default()->set_icon("ResizedFile","EditorIcons",resized_file);
+ }
+
+ file_thumbnail = get_icon("ResizedFile","EditorIcons");
+
+ } else {
+
+ files->set_icon_mode(ItemList::ICON_MODE_LEFT);
+ files->set_max_columns(1);
+ files->set_max_text_lines(1);
+ files->set_fixed_column_width(0);
+ files->set_min_icon_size(Size2());
+
+ }
+
+
+ if (path!="res://") {
+
+ if (use_thumbnails) {
+ files->add_item("..",folder_thumbnail,true);
+ } else {
+ files->add_item("..",get_icon("folder","FileDialog"),true);
+ }
+
+ String bd = path.get_base_dir();
+ if (bd!="res://" && !bd.ends_with("/"))
+ bd+="/";
+
+ files->set_item_metadata(files->get_item_count()-1,bd);
+ }
+
+ for(int i=0;i<efd->get_subdir_count();i++) {
+
+ String dname=efd->get_subdir(i)->get_name();
+
+
+ if (use_thumbnails) {
+ files->add_item(dname,folder_thumbnail,true);
+ } else {
+ files->add_item(dname,get_icon("folder","FileDialog"),true);
+ }
+
+ files->set_item_metadata(files->get_item_count()-1,path.plus_file(dname)+"/");
+
+ if (cselection.has(dname))
+ files->select(files->get_item_count()-1,false);
+ }
+
+ for(int i=0;i<efd->get_file_count();i++) {
+
+ String fname=efd->get_file(i);
+ String fp = path.plus_file(fname);
+
+
+ String type = efd->get_file_type(i);
+ Ref<Texture> type_icon;
+
+ if (has_icon(type,"EditorIcons")) {
+ type_icon=get_icon(type,"EditorIcons");
+ } else {
+ type_icon=get_icon("Object","EditorIcons");
+ }
+
+ if (use_thumbnails) {
+ files->add_item(fname,file_thumbnail,true);
+ files->set_item_metadata(files->get_item_count()-1,fp);
+ files->set_item_tag_icon(files->get_item_count()-1,type_icon);
+ EditorResourcePreview::get_singleton()->queue_resource_preview(fp,this,"_thumbnail_done",files->get_item_count()-1);
+ } else {
+ files->add_item(fname,type_icon,true);
+ files->set_item_metadata(files->get_item_count()-1,fp);
+
+ }
+
+ if (cselection.has(fname))
+ files->select(files->get_item_count()-1,false);
+
}
- String path = sel->get_metadata(0);
- if (ResourceLoader::get_resource_type(path)=="PackedScene") {
- editor->open_request(path);
+}
+
+void ScenesDock::_select_file(int p_idx) {
+
+ files->select(p_idx,true);
+ _open_pressed();
+}
+
+void ScenesDock::_go_to_tree() {
+
+ tree->show();
+ files->hide();
+ path_hb->hide();
+ _update_tree();
+ tree->grab_focus();
+ tree->ensure_cursor_is_visible();
+ button_favorite->show();
+ button_fav_up->show();
+ button_fav_down->show();
+ button_open->hide();
+ button_instance->hide();
+ button_open->hide();
+ file_options->hide();
+ tree_mode=true;
+}
+
+void ScenesDock::_go_to_dir(const String& p_dir){
+
+ DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ if (da->change_dir(p_dir)==OK) {
+ path=da->get_current_dir();
+ _update_files(false);
+ }
+ current_path->set_text(path);
+ memdelete(da);
+
+
+}
+void ScenesDock::_fs_changed() {
+
+ button_hist_prev->set_disabled(history_pos==0);
+ button_hist_next->set_disabled(history_pos+1==history.size());
+ scanning_vb->hide();
+
+ if (tree_mode) {
+
+ tree->show();
+ button_favorite->show();
+ button_fav_up->show();
+ button_fav_down->show();
+ _update_tree();
+ } else {
+ files->show();
+ path_hb->show();
+ button_instance->show();
+ button_open->show();
+ file_options->show();
+ _update_files(true);
+ }
+
+ set_process(false);
+}
+
+void ScenesDock::_set_scannig_mode() {
+
+ tree->hide();
+ button_favorite->hide();
+ button_fav_up->hide();
+ button_fav_down->hide();
+ button_instance->hide();
+ button_open->hide();
+ file_options->hide();
+ button_hist_prev->set_disabled(true);
+ button_hist_next->set_disabled(true);
+ scanning_vb->show();
+ path_hb->hide();
+ files->hide();
+ set_process(true);
+ if (EditorFileSystem::get_singleton()->is_scanning()) {
+ scanning_progress->set_val(EditorFileSystem::get_singleton()->get_scanning_progress()*100);
+ } else {
+ scanning_progress->set_val(0);
+ }
+
+}
+
+void ScenesDock::_fw_history() {
+
+ if (history_pos<history.size()-1)
+ history_pos++;
+
+ path=history[history_pos];
+
+ if (tree_mode) {
+ _update_tree();
+ tree->grab_focus();
+ tree->ensure_cursor_is_visible();
} else {
+ _update_files(false);
+ current_path->set_text(path);
+ }
- /*
+ button_hist_prev->set_disabled(history_pos==0);
+ button_hist_next->set_disabled(history_pos+1==history.size());
- RES res = ResourceLoader::load(path);
- if (res.is_null()) {
+}
+
+void ScenesDock::_bw_history() {
+
+ if (history_pos>0)
+ history_pos--;
+
+ path=history[history_pos];
+
+ if (tree_mode) {
+ _update_tree();
+ tree->grab_focus();
+ tree->ensure_cursor_is_visible();
+ } else {
+ _update_files(false);
+ current_path->set_text(path);
+ }
+ button_hist_prev->set_disabled(history_pos==0);
+ button_hist_next->set_disabled(history_pos+1==history.size());
+}
+
+void ScenesDock::_push_to_history() {
+
+ history.resize(history_pos+1);
+ if (history[history_pos]!=path) {
+ history.push_back(path);
+ history_pos++;
+ }
+
+ button_hist_prev->set_disabled(history_pos==0);
+ button_hist_next->set_disabled(history_pos+1==history.size());
+
+}
+
+
+void ScenesDock::_find_inside_move_files(EditorFileSystemDirectory *efsd,Vector<String>& files) {
+
+ for(int i=0;i<efsd->get_subdir_count();i++) {
+ _find_inside_move_files(efsd->get_subdir(i),files);
+ }
+ for(int i=0;i<efsd->get_file_count();i++) {
+ files.push_back(efsd->get_file_path(i));
+ }
+
+}
+
+void ScenesDock::_find_remaps(EditorFileSystemDirectory *efsd,Map<String,String> &renames,List<String>& to_remaps) {
+
+ for(int i=0;i<efsd->get_subdir_count();i++) {
+ _find_remaps(efsd->get_subdir(i),renames,to_remaps);
+ }
+ for(int i=0;i<efsd->get_file_count();i++) {
+ Vector<String> deps=efsd->get_file_deps(i);
+ for(int j=0;j<deps.size();j++) {
+ if (renames.has(deps[j])) {
+ to_remaps.push_back(efsd->get_file_path(i));
+ break;
+ }
+ }
+ }
+}
+
+
+void ScenesDock::_rename_operation(const String& p_to_path) {
+
+ if (move_files[0]==p_to_path) {
+ EditorNode::get_singleton()->show_warning("Same source and destination files, doing nothing.");
+ return;
+ }
+ if (FileAccess::exists(p_to_path)) {
+ EditorNode::get_singleton()->show_warning("Target file exists, can't overwrite. Delete first.");
+ return;
+ }
+
+ Map<String,String> renames;
+ renames[move_files[0]]=p_to_path;
+
+ List<String> remap;
+
+ _find_remaps(EditorFileSystem::get_singleton()->get_filesystem(),renames,remap);
+ print_line("found files to remap: "+itos(remap.size()));
+
+ //perform remaps
+ for(List<String>::Element *E=remap.front();E;E=E->next()) {
+
+ Error err = ResourceLoader::rename_dependencies(E->get(),renames);
+ print_line("remapping: "+E->get());
+
+ if (err!=OK) {
+ EditorNode::get_singleton()->add_io_error("Can't rename deps for:\n"+E->get()+"\n");
+ }
+ }
+
+ //finally, perform moves
+
+ DirAccess *da=DirAccess::create(DirAccess::ACCESS_RESOURCES);
+
+ Error err = da->rename(move_files[0],p_to_path);
+ print_line("moving file "+move_files[0]+" to "+p_to_path);
+ if (err!=OK) {
+ EditorNode::get_singleton()->add_io_error("Error moving file:\n"+move_files[0]+"\n");
+ }
+
+ //rescan everything
+ memdelete(da);
+ print_line("call rescan!");
+ _rescan();
+}
+
+
+void ScenesDock::_move_operation(const String& p_to_path) {
+
+ if (p_to_path==path) {
+ EditorNode::get_singleton()->show_warning("Same source and destination paths, doing nothing.");
+ return;
+ }
+
+ //find files inside dirs to be moved
+
+ Vector<String> inside_files;
+
+ for(int i=0;i<move_dirs.size();i++) {
+ if (p_to_path.begins_with(move_dirs[i])) {
+ EditorNode::get_singleton()->show_warning("Can't move directories to within themselves");
return;
- }*/
+ }
- editor->load_resource(path);
+ EditorFileSystemDirectory *efsd=EditorFileSystem::get_singleton()->get_path(move_dirs[i]);
+ if (!efsd)
+ continue;
+ _find_inside_move_files(efsd,inside_files);
}
-// emit_signal("open",path);
+ //make list of remaps
+ Map<String,String> renames;
+ String repfrom=path=="res://"?path:String(path+"/");
+ String repto=p_to_path=="res://"?p_to_path:String(p_to_path+"/");
+
+ for(int i=0;i<move_files.size();i++) {
+ renames[move_files[i]]=move_files[i].replace_first(repfrom,repto);
+ print_line("move file "+move_files[i]+" -> "+renames[move_files[i]]);
+ }
+ for(int i=0;i<inside_files.size();i++) {
+ renames[inside_files[i]]=inside_files[i].replace_first(repfrom,repto);
+ print_line("inside file "+inside_files[i]+" -> "+renames[inside_files[i]]);
+ }
+
+ //make list of files that will be run the remapping
+ List<String> remap;
+
+ _find_remaps(EditorFileSystem::get_singleton()->get_filesystem(),renames,remap);
+ print_line("found files to remap: "+itos(remap.size()));
+
+ //perform remaps
+ for(List<String>::Element *E=remap.front();E;E=E->next()) {
+
+ Error err = ResourceLoader::rename_dependencies(E->get(),renames);
+ print_line("remapping: "+E->get());
+
+ if (err!=OK) {
+ EditorNode::get_singleton()->add_io_error("Can't rename deps for:\n"+E->get()+"\n");
+ }
+ }
+
+ //finally, perform moves
+
+ DirAccess *da=DirAccess::create(DirAccess::ACCESS_RESOURCES);
+
+ for(int i=0;i<move_files.size();i++) {
+ String to = move_files[i].replace_first(repfrom,repto);
+ Error err = da->rename(move_files[i],to);
+ print_line("moving file "+move_files[i]+" to "+to);
+ if (err!=OK) {
+ EditorNode::get_singleton()->add_io_error("Error moving file:\n"+move_files[i]+"\n");
+ }
+ }
+
+ for(int i=0;i<move_dirs.size();i++) {
+
+ String to = p_to_path.plus_file(move_dirs[i].get_file());
+ Error err = da->rename(move_dirs[i],to);
+ print_line("moving dir "+move_dirs[i]+" to "+to);
+ if (err!=OK) {
+ EditorNode::get_singleton()->add_io_error("Error moving dir:\n"+move_dirs[i]+"\n");
+ }
+ }
+
+ memdelete(da);
+ //rescan everything
+ print_line("call rescan!");
+ _rescan();
+
+}
+
+void ScenesDock::_file_option(int p_option) {
+
+ switch(p_option) {
+
+ case FILE_DEPENDENCIES: {
+
+ int idx = files->get_current();
+ if (idx<0 || idx>=files->get_item_count())
+ break;
+ String path = files->get_item_metadata(idx);
+ deps_editor->edit(path);
+ } break;
+ case FILE_OWNERS: {
+
+ int idx = files->get_current();
+ if (idx<0 || idx>=files->get_item_count())
+ break;
+ String path = files->get_item_metadata(idx);
+ owners_editor->show(path);
+ } break;
+ case FILE_MOVE: {
+
+ move_dirs.clear();;
+ move_files.clear();
+
+ for(int i=0;i<files->get_item_count();i++) {
+
+ String path = files->get_item_metadata(i);
+ if (!files->is_selected(i))
+ continue;
+
+ if (files->get_item_text(i)=="..") {
+ EditorNode::get_singleton()->show_warning("Can't operate on '..'");
+ return;
+ }
+
+ if (path.ends_with("/")) {
+ move_dirs.push_back(path.substr(0,path.length()-1));
+ } else {
+ move_files.push_back(path);
+ }
+ }
+
+
+ if (move_dirs.empty() && move_files.size()==1) {
+
+ rename_dialog->clear_filters();
+ rename_dialog->add_filter("*."+move_files[0].extension());
+ rename_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ rename_dialog->set_current_path(move_files[0]);
+ rename_dialog->popup_centered_ratio();
+ rename_dialog->set_title("Pick New Name and Location For: "+move_files[0].get_file());
+
+
+ } else {
+ //just move
+ move_dialog->popup_centered_ratio();
+ }
+
+
+ } break;
+ case FILE_REMOVE: {
+
+ Vector<String> torem;
+
+ for(int i=0;i<files->get_item_count();i++) {
+
+ String path = files->get_item_metadata(i);
+ if (path.ends_with("/") || !files->is_selected(i))
+ continue;
+ torem.push_back(path);
+ }
+
+ if (torem.empty()) {
+ EditorNode::get_singleton()->show_warning("No files selected!");
+ break;
+ }
+
+ remove_dialog->show(torem);
+ //1) find if used
+ //2) warn
+
+ } break;
+ case FILE_INFO: {
+
+ } break;
+
+ }
}
-void ScenesDock::_save_favorites() {
+void ScenesDock::_open_pressed(){
+
+
+ if (tree_mode) {
+
+ TreeItem *sel = tree->get_selected();
+ if (!sel) {
+ return;
+ }
+ path = sel->get_metadata(0);
+ /*if (path!="res://" && path.ends_with("/")) {
+ path=path.substr(0,path.length()-1);
+ }*/
+
+ tree_mode=false;
- String path = Globals::get_singleton()->get_resource_path()+"/favorites.cfg";
- FileAccess *f=FileAccess::open(path,FileAccess::WRITE);
- ERR_FAIL_COND(!f);
- for(Set<String>::Element *E=favorites.front();E;E=E->next() ) {
+ tree->hide();
+ files->show();
+ path_hb->show();
+ button_favorite->hide();
+ button_fav_up->hide();
+ button_fav_down->hide();
+ button_instance->show();
+ button_open->show();
+ file_options->show();
- CharString utf8f = E->get().utf8();
- f->store_buffer((const uint8_t*)utf8f.get_data(),utf8f.length());
- f->store_8('\n');
+ _update_files(false);
+
+ current_path->set_text(path);
+
+ _push_to_history();
+
+
+ } else {
+
+ int idx=-1;
+ for(int i=0;i<files->get_item_count();i++) {
+ if (files->is_selected(i)) {
+ idx=i;
+ break;
+ }
+ }
+
+ if (idx<0)
+ return;
+
+
+
+ String path = files->get_item_metadata(idx);
+
+ if (path.ends_with("/")) {
+ if (path!="res://") {
+ path=path.substr(0,path.length()-1);
+ }
+ this->path=path;
+ _update_files(false);
+ current_path->set_text(path);
+ _push_to_history();
+ } else {
+
+ if (ResourceLoader::get_resource_type(path)=="PackedScene") {
+
+ editor->open_request(path);
+ } else {
+
+ editor->load_resource(path);
+ }
+ }
}
- f->close();
- memdelete(f);
+// emit_signal("open",path);
+
}
+
void ScenesDock::_rescan() {
+ _set_scannig_mode();
EditorFileSystem::get_singleton()->scan();
+
+}
+
+void ScenesDock::fix_dependencies(const String& p_for_file) {
+ deps_editor->edit(p_for_file);
+}
+
+void ScenesDock::open(const String& p_path) {
+
+
+ String npath;
+ String nfile;
+
+ if (p_path.ends_with("/")) {
+
+ if (p_path!="res://")
+ npath=p_path.substr(0,p_path.length()-1);
+ else
+ npath="res://";
+ } else {
+ nfile=p_path.get_file();
+ npath=p_path.get_base_dir();
+ }
+
+ path=npath;
+
+ if (tree_mode && nfile=="") {
+ _update_tree();
+ tree->grab_focus();
+ tree->call_deferred("ensure_cursor_is_visible");
+ _push_to_history();
+ return;
+ } else if (tree_mode){
+ _update_tree();
+ tree->grab_focus();
+ tree->ensure_cursor_is_visible();
+ _open_pressed();
+ current_path->set_text(path);
+ } else {
+ _update_files(false);
+ _push_to_history();
+ }
+
+ for(int i=0;i<files->get_item_count();i++) {
+
+ String md = files->get_item_metadata(i);
+ if (md==p_path) {
+ files->select(i,true);
+ files->ensure_current_is_visible();
+ break;
+ }
+ }
+
+}
+
+void ScenesDock::set_use_thumbnails(bool p_use) {
+
+ display_mode->set_pressed(!p_use);
}
void ScenesDock::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_update_tree"),&ScenesDock::_update_tree);
ObjectTypeDB::bind_method(_MD("_rescan"),&ScenesDock::_rescan);
- ObjectTypeDB::bind_method(_MD("_favorites_toggled"),&ScenesDock::_favorites_toggled);
- ObjectTypeDB::bind_method(_MD("_favorite_toggled"),&ScenesDock::_favorite_toggled);
+ ObjectTypeDB::bind_method(_MD("_favorites_pressed"),&ScenesDock::_favorites_pressed);
ObjectTypeDB::bind_method(_MD("_instance_pressed"),&ScenesDock::_instance_pressed);
ObjectTypeDB::bind_method(_MD("_open_pressed"),&ScenesDock::_open_pressed);
- ObjectTypeDB::bind_method(_MD("_save_favorites"),&ScenesDock::_save_favorites);
+
+ ObjectTypeDB::bind_method(_MD("_thumbnail_done"),&ScenesDock::_thumbnail_done);
+ ObjectTypeDB::bind_method(_MD("_select_file"), &ScenesDock::_select_file);
+ ObjectTypeDB::bind_method(_MD("_go_to_tree"), &ScenesDock::_go_to_tree);
+ ObjectTypeDB::bind_method(_MD("_go_to_dir"), &ScenesDock::_go_to_dir);
+ ObjectTypeDB::bind_method(_MD("_change_file_display"), &ScenesDock::_change_file_display);
+ ObjectTypeDB::bind_method(_MD("_fw_history"), &ScenesDock::_fw_history);
+ ObjectTypeDB::bind_method(_MD("_bw_history"), &ScenesDock::_bw_history);
+ ObjectTypeDB::bind_method(_MD("_fs_changed"), &ScenesDock::_fs_changed);
+ ObjectTypeDB::bind_method(_MD("_dir_selected"), &ScenesDock::_dir_selected);
+ ObjectTypeDB::bind_method(_MD("_fav_up_pressed"), &ScenesDock::_fav_up_pressed);
+ ObjectTypeDB::bind_method(_MD("_fav_down_pressed"), &ScenesDock::_fav_down_pressed);
+ ObjectTypeDB::bind_method(_MD("_file_option"), &ScenesDock::_file_option);
+ ObjectTypeDB::bind_method(_MD("_move_operation"), &ScenesDock::_move_operation);
+ ObjectTypeDB::bind_method(_MD("_rename_operation"), &ScenesDock::_rename_operation);
ADD_SIGNAL(MethodInfo("instance"));
ADD_SIGNAL(MethodInfo("open"));
@@ -271,153 +1108,158 @@ ScenesDock::ScenesDock(EditorNode *p_editor) {
HBoxContainer *toolbar_hbc = memnew( HBoxContainer );
add_child(toolbar_hbc);
+ button_hist_prev = memnew( ToolButton );
+ toolbar_hbc->add_child(button_hist_prev);
+ button_hist_prev->set_disabled(true);
+ button_hist_prev->set_tooltip("Previous Directory");
+
+ button_hist_next = memnew( ToolButton );
+ toolbar_hbc->add_child(button_hist_next);
+ button_hist_next->set_disabled(true);
+ button_hist_prev->set_focus_mode(FOCUS_NONE);
+ button_hist_next->set_focus_mode(FOCUS_NONE);
+ button_hist_next->set_tooltip("Next Directory");
+
button_reload = memnew( Button );
button_reload->set_flat(true);
button_reload->connect("pressed",this,"_rescan");
toolbar_hbc->add_child(button_reload);
+ button_reload->set_focus_mode(FOCUS_NONE);
+ button_reload->set_tooltip("Re-Scan Filesystem");
+
+ toolbar_hbc->add_spacer();
+
+ button_fav_up = memnew( ToolButton );
+ button_fav_up->set_flat(true);
+ toolbar_hbc->add_child(button_fav_up);
+ button_fav_up->set_disabled(true);
+ button_fav_up->connect("pressed",this,"_fav_up_pressed");
+ button_fav_up->set_tooltip("Move Favorite Up");
+
+ button_fav_down = memnew( ToolButton );
+ button_fav_down->set_flat(true);
+ toolbar_hbc->add_child(button_fav_down);
+ button_fav_down->set_disabled(true);
+ button_fav_down->connect("pressed",this,"_fav_down_pressed");
+ button_fav_down->set_tooltip("Move Favorite Down");
button_favorite = memnew( Button );
button_favorite->set_flat(true);
button_favorite->set_toggle_mode(true);
- button_favorite->connect("toggled",this,"_favorites_toggled");
+ button_favorite->connect("pressed",this,"_favorites_pressed");
toolbar_hbc->add_child(button_favorite);
+ button_favorite->set_tooltip("Toggle folder status as Favorite");
+
+ button_favorite->set_focus_mode(FOCUS_NONE);
+ button_fav_up->set_focus_mode(FOCUS_NONE);
+ button_fav_down->set_focus_mode(FOCUS_NONE);
- toolbar_hbc->add_spacer();
button_open = memnew( Button );
button_open->set_flat(true);
button_open->connect("pressed",this,"_open_pressed");
toolbar_hbc->add_child(button_open);
+ button_open->hide();
+ button_open->set_focus_mode(FOCUS_NONE);
+ button_open->set_tooltip("Open the selected file.\nOpen as scene if a scene, or as resource otherwise.");
+
button_instance = memnew( Button );
button_instance->set_flat(true);
button_instance->connect("pressed",this,"_instance_pressed");
toolbar_hbc->add_child(button_instance);
+ button_instance->hide();
+ button_instance->set_focus_mode(FOCUS_NONE);
+ button_instance->set_tooltip("Instance the selected scene(s) as child of the selected node.");
+
+
+ file_options = memnew( MenuButton );
+ toolbar_hbc->add_child(file_options);
+ file_options->get_popup()->add_item("Rename or Move",FILE_MOVE);
+ file_options->get_popup()->add_item("Delete",FILE_REMOVE);
+ file_options->get_popup()->add_separator();
+ file_options->get_popup()->add_item("Edit Dependencies",FILE_DEPENDENCIES);
+ file_options->get_popup()->add_item("View Owners",FILE_OWNERS);
+ //file_options->get_popup()->add_item("Info",FILE_INFO);
+ file_options->hide();
+ file_options->set_focus_mode(FOCUS_NONE);
+ file_options->set_tooltip("Miscenaneous options related to resources on disk.");
tree = memnew( Tree );
- tree_filter=memnew( ScenesDockFilter() );
- tree_filter->connect("filter_changed", this, "_update_tree");
- add_child(tree_filter);
+
+ tree->set_hide_root(true);
add_child(tree);
+
tree->set_v_size_flags(SIZE_EXPAND_FILL);
tree->connect("item_edited",this,"_favorite_toggled");
tree->connect("item_activated",this,"_open_pressed");
-
- timer = memnew( Timer );
- timer->set_one_shot(true);
- timer->set_wait_time(2);
- timer->connect("timeout",this,"_save_favorites");
- add_child(timer);
-
+ tree->connect("cell_selected",this,"_dir_selected");
+
+ files = memnew( ItemList );
+ files->set_v_size_flags(SIZE_EXPAND_FILL);
+ files->set_select_mode(ItemList::SELECT_MULTI);
+
+ path_hb = memnew( HBoxContainer );
+ button_back = memnew( ToolButton );
+ path_hb->add_child(button_back);
+ current_path=memnew( LineEdit );
+ current_path->set_h_size_flags(SIZE_EXPAND_FILL);
+ path_hb->add_child(current_path);
+ display_mode = memnew( ToolButton );
+ path_hb->add_child(display_mode);
+ display_mode->set_toggle_mode(true);
+ add_child(path_hb);
+ path_hb->hide();
+
+
+ add_child(files);
+ files->hide();
+
+ scanning_vb = memnew( VBoxContainer );
+ Label *slabel = memnew( Label );
+ slabel->set_text("Scanning Files,\nPlease Wait..");
+ slabel->set_align(Label::ALIGN_CENTER);
+ scanning_vb->add_child(slabel);
+ scanning_progress = memnew( ProgressBar );
+ scanning_vb->add_child(scanning_progress);
+ add_child(scanning_vb);
+ scanning_vb->hide();
+
+
+
+ deps_editor = memnew( DependencyEditor );
+ add_child(deps_editor);
+
+ owners_editor = memnew( DependencyEditorOwners);
+ add_child(owners_editor);
+
+ remove_dialog = memnew( DependencyRemoveDialog);
+ add_child(remove_dialog);
+
+ move_dialog = memnew( EditorDirDialog );
+ add_child(move_dialog);
+ move_dialog->connect("dir_selected",this,"_move_operation");
+ move_dialog->get_ok()->set_text("Move");
+
+ rename_dialog = memnew( EditorFileDialog );
+ rename_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE);
+ rename_dialog->connect("file_selected",this,"_rename_operation");
+ add_child(rename_dialog);
updating_tree=false;
+ initialized=false;
-}
-
-ScenesDock::~ScenesDock() {
-
-}
-
-void ScenesDockFilter::_setup_filters() {
-
- filter_option->clear();
- filter_option->add_item("Path");
- filter_option->add_item("Name");
- filter_option->add_item("Folder");
-#if 0
- List<String> extensions;
- ResourceLoader::get_recognized_extensions_for_type("",&extensions);
-
- file_filter->add_item("All Files (*)");
- filters.push_back("*");
-
- List<String> filter_texts;
- for(int i=0;i<extensions.size();i++) {
- filter_texts.push_back("*."+extensions[i]+" ; "+extensions[i].to_upper());
- filters.push_back(extensions[i]);
- }
- for(int i=0;i<filter_texts.size();i++) {
-
- String flt=filter_texts[i].get_slice(";",0).strip_edges();
- String desc=filter_texts[i].get_slice(";",1).strip_edges();
- if (desc.length())
- file_filter->add_item(desc+" ( "+flt+" )");
- else
- file_filter->add_item("( "+flt+" )");
- }
-#endif
-}
-
-void ScenesDockFilter::_command(int p_command) {
- switch (p_command) {
+ history.push_back("res://");
+ history_pos=0;
+ tree_mode=true;
- case CMD_CLEAR_FILTER: {
- if (search_box->get_text()!="") {
- search_box->clear();
- emit_signal("filter_changed");
- }
- }break;
- }
-}
+ path="res://";
-void ScenesDockFilter::_search_text_changed(const String &p_newtext) {
- emit_signal("filter_changed");
-}
-String ScenesDockFilter::get_search_term() {
- return search_box->get_text().strip_edges();
}
-ScenesDockFilter::FilterOption ScenesDockFilter::get_file_filter() {
- return _current_filter;
-}
-
-void ScenesDockFilter::_file_filter_selected(int p_idx) {
- FilterOption selected = (FilterOption)(filter_option->get_selected());
- if (_current_filter != selected ) {
- _current_filter = selected;
- emit_signal("filter_changed");
- }
-}
-
-void ScenesDockFilter::_notification(int p_what) {
- switch(p_what) {
- case NOTIFICATION_ENTER_TREE: {
- clear_search_button->set_icon(get_icon("CloseHover","EditorIcons"));
- } break;
- }
-}
-
-void ScenesDockFilter::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("_command"),&ScenesDockFilter::_command);
- ObjectTypeDB::bind_method(_MD("_search_text_changed"), &ScenesDockFilter::_search_text_changed);
- ObjectTypeDB::bind_method(_MD("_file_filter_selected"), &ScenesDockFilter::_file_filter_selected);
-
- ADD_SIGNAL( MethodInfo("filter_changed") );
-}
-
-ScenesDockFilter::ScenesDockFilter() {
-
- _current_filter = FILTER_PATH;
-
- filter_option = memnew( OptionButton );
- filter_option->set_custom_minimum_size(Size2(60,10));
- filter_option->set_clip_text(true);
- filter_option->connect("item_selected", this, "_file_filter_selected");
- add_child(filter_option);
-
- _setup_filters();
-
- search_box = memnew( LineEdit );
- search_box->connect("text_changed",this,"_search_text_changed");
- search_box->set_h_size_flags(SIZE_EXPAND_FILL);
- add_child(search_box);
-
- clear_search_button = memnew( ToolButton );
- clear_search_button->connect("pressed",this,"_command",make_binds(CMD_CLEAR_FILTER));
- add_child(clear_search_button);
+ScenesDock::~ScenesDock() {
}
diff --git a/tools/editor/scenes_dock.h b/tools/editor/scenes_dock.h
index de7ab51edc..a1978a3ca4 100644
--- a/tools/editor/scenes_dock.h
+++ b/tools/editor/scenes_dock.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -36,40 +36,112 @@
#include "scene/gui/tool_button.h"
#include "scene/gui/option_button.h"
#include "scene/gui/box_container.h"
+#include "scene/gui/menu_button.h"
+#include "scene/gui/item_list.h"
+#include "scene/gui/progress_bar.h"
+
#include "os/dir_access.h"
#include "os/thread.h"
#include "editor_file_system.h"
-
+#include "editor_dir_dialog.h"
+#include "dependency_editor.h"
class EditorNode;
-class ScenesDockFilter;
+
class ScenesDock : public VBoxContainer {
OBJ_TYPE( ScenesDock, VBoxContainer );
+ enum FileMenu {
+ FILE_DEPENDENCIES,
+ FILE_OWNERS,
+ FILE_MOVE,
+ FILE_REMOVE,
+ FILE_REIMPORT,
+ FILE_INFO
+ };
+
+
+ VBoxContainer *scanning_vb;
+ ProgressBar *scanning_progress;
+
EditorNode *editor;
Set<String> favorites;
Button *button_reload;
Button *button_instance;
Button *button_favorite;
+ Button *button_fav_up;
+ Button *button_fav_down;
Button *button_open;
- Timer *timer;
+ Button *button_back;
+ Button *display_mode;
+ Button *button_hist_next;
+ Button *button_hist_prev;
+ LineEdit *current_path;
+ HBoxContainer *path_hb;
+
+ MenuButton *file_options;
+
+
+ DependencyEditor *deps_editor;
+ DependencyEditorOwners *owners_editor;
+ DependencyRemoveDialog *remove_dialog;
+
+ EditorDirDialog *move_dialog;
+ EditorFileDialog *rename_dialog;
- ScenesDockFilter *tree_filter;
+ Vector<String> move_dirs;
+ Vector<String> move_files;
+
+
+ Vector<String> history;
+ int history_pos;
+
+ String path;
+
+ bool initialized;
bool updating_tree;
- Tree * tree;
+ Tree * tree; //directories
+ ItemList *files;
+
+ bool tree_mode;
+
+ void _go_to_tree();
+ void _go_to_dir(const String& p_dir);
+ void _select_file(int p_idx);
+
bool _create_tree(TreeItem *p_parent,EditorFileSystemDirectory *p_dir);
+ void _thumbnail_done(const String& p_path,const Ref<Texture>& p_preview, const Variant& p_udata);
+ void _find_inside_move_files(EditorFileSystemDirectory *efsd,Vector<String>& files);
+ void _find_remaps(EditorFileSystemDirectory *efsd,Map<String,String> &renames,List<String>& to_remaps);
+
+ void _rename_operation(const String& p_to_path);
+ void _move_operation(const String& p_to_path);
+
+
+ void _file_option(int p_option);
+ void _update_files(bool p_keep_selection);
+ void _change_file_display();
+ void _fs_changed();
+ void _fw_history();
+ void _bw_history();
+ void _push_to_history();
+
+ void _fav_up_pressed();
+ void _fav_down_pressed();
+ void _dir_selected();
void _update_tree();
void _rescan();
- void _favorites_toggled(bool);
- void _favorite_toggled();
+ void _set_scannig_mode();
+
+ void _favorites_pressed();
void _instance_pressed();
void _open_pressed();
- void _save_favorites();
+
protected:
void _notification(int p_what);
@@ -77,48 +149,15 @@ protected:
public:
String get_selected_path() const;
+ void open(const String& p_path);
+
+ void fix_dependencies(const String& p_for_file);
+
+ void set_use_thumbnails(bool p_use);
ScenesDock(EditorNode *p_editor);
~ScenesDock();
};
-class ScenesDockFilter : public HBoxContainer {
-
- OBJ_TYPE( ScenesDockFilter, HBoxContainer );
-
-private:
- friend class ScenesDock;
-
- enum Command {
- CMD_CLEAR_FILTER,
- };
-
- Tree *tree;
- OptionButton *filter_option;
- LineEdit *search_box;
- ToolButton *clear_search_button;
-
- enum FilterOption {
- FILTER_PATH, // NAME or Folder
- FILTER_NAME,
- FILTER_FOLDER,
- };
- FilterOption _current_filter;
- //Vector<String> filters;
-
- void _command(int p_command);
- void _search_text_changed(const String& p_newtext);
- void _setup_filters();
- void _file_filter_selected(int p_idx);
-
-protected:
- void _notification(int p_what);
- static void _bind_methods();
-
-public:
- String get_search_term();
- FilterOption get_file_filter();
- ScenesDockFilter();
-};
#endif // SCENES_DOCK_H
diff --git a/tools/editor/script_create_dialog.cpp b/tools/editor/script_create_dialog.cpp
index bdfb66f0f2..409e8be870 100644
--- a/tools/editor/script_create_dialog.cpp
+++ b/tools/editor/script_create_dialog.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -74,17 +74,17 @@ bool ScriptCreateDialog::_validate(const String& p_string) {
void ScriptCreateDialog::_class_name_changed(const String& p_name) {
if (!_validate(parent_name->get_text())) {
- error_label->set_text("INVALID PARENT CLASS NAME");
+ error_label->set_text("Invaild parent class name");
error_label->add_color_override("font_color",Color(1,0.4,0.0,0.8));
} else if (class_name->is_editable()) {
if (class_name->get_text()=="") {
error_label->set_text("Valid Chars: a-z A-Z 0-9 _");
error_label->add_color_override("font_color",Color(1,1,1,0.6));
} else if (!_validate(class_name->get_text())) {
- error_label->set_text("INVALID CLASS NAME");
+ error_label->set_text("Invalid class name");
error_label->add_color_override("font_color",Color(1,0.2,0.2,0.8));
} else {
- error_label->set_text("Name is Valid");
+ error_label->set_text("Valid Name");
error_label->add_color_override("font_color",Color(0,1.0,0.8,0.8));
}
} else {
@@ -363,7 +363,7 @@ ScriptCreateDialog::ScriptCreateDialog() {
set_size(Size2(200,150));
set_hide_on_ok(false);
- set_title("Create Script for Node..");;
+ set_title("Create Script for Node");
file_browse = memnew( EditorFileDialog );
file_browse->connect("file_selected",this,"_file_selected");
diff --git a/tools/editor/script_create_dialog.h b/tools/editor/script_create_dialog.h
index 59fde8fbd5..181989402e 100644
--- a/tools/editor/script_create_dialog.h
+++ b/tools/editor/script_create_dialog.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/tools/editor/script_editor_debugger.cpp b/tools/editor/script_editor_debugger.cpp
index 13734f2c4b..297f10a1c8 100644
--- a/tools/editor/script_editor_debugger.cpp
+++ b/tools/editor/script_editor_debugger.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -169,6 +169,17 @@ void ScriptEditorDebugger::_scene_tree_request() {
}
+void ScriptEditorDebugger::_video_mem_request() {
+
+ ERR_FAIL_COND(connection.is_null());
+ ERR_FAIL_COND(!connection->is_connected());
+
+ Array msg;
+ msg.push_back("request_video_mem");
+ ppeer->put_var(msg);
+
+}
+
Size2 ScriptEditorDebugger::get_minimum_size() const {
Size2 ms = Control::get_minimum_size();
@@ -199,6 +210,8 @@ void ScriptEditorDebugger::_parse_message(const String& p_msg,const Array& p_dat
OS::get_singleton()->move_window_to_foreground();
tabs->set_current_tab(0);
+ EditorNode::get_singleton()->make_bottom_panel_item_visible(this);
+
} else if (p_msg=="debug_exit") {
breaked=false;
@@ -241,6 +254,33 @@ void ScriptEditorDebugger::_parse_message(const String& p_msg,const Array& p_dat
lv[level]=it;
}
+ le_clear->set_disabled(false);
+ le_set->set_disabled(false);
+
+ } else if (p_msg=="message:video_mem") {
+
+ vmem_tree->clear();
+ TreeItem* root=vmem_tree->create_item();
+
+ int total=0;
+
+ for(int i=0;i<p_data.size();i+=4) {
+
+ TreeItem *it = vmem_tree->create_item(root);
+ String type=p_data[i+1];
+ int bytes=p_data[i+3].operator int();
+ it->set_text(0,p_data[i+0]); //path
+ it->set_text(1,type); //type
+ it->set_text(2,p_data[i+2]); //type
+ it->set_text(3,String::humanize_size(bytes)); //type
+ total+=bytes;
+
+ if (has_icon(type,"EditorIcons"))
+ it->set_icon(0,get_icon(type,"EditorIcons"));
+ }
+
+ vmem_total->set_tooltip("Bytes: "+itos(total));
+ vmem_total->set_text(String::humanize_size(total));
} else if (p_msg=="stack_dump") {
@@ -320,7 +360,7 @@ void ScriptEditorDebugger::_parse_message(const String& p_msg,const Array& p_dat
if (EditorNode::get_log()->is_hidden()) {
log_forced_visible=true;
- EditorNode::get_log()->show();
+ EditorNode::get_singleton()->make_bottom_panel_item_visible(EditorNode::get_log());
}
EditorNode::get_log()->add_message(t);
@@ -342,6 +382,63 @@ void ScriptEditorDebugger::_parse_message(const String& p_msg,const Array& p_dat
perf_history.push_front(p);
perf_draw->update();
+ } else if (p_msg=="error") {
+
+ Array err = p_data[0];
+
+ Array vals;
+ vals.push_back(err[0]);
+ vals.push_back(err[1]);
+ vals.push_back(err[2]);
+ vals.push_back(err[3]);
+
+ bool warning = err[9];
+ bool e;
+ String time = String("%d:%02d:%02d:%04d").sprintf(vals,&e);
+ String txt=time+" - "+String(err[8]);
+
+ String tooltip="Type:"+String(warning?"Warning":"Error");
+ tooltip+="\nDescription: "+String(err[8]);
+ tooltip+="\nTime: "+time;
+ tooltip+="\nC Error: "+String(err[7]);
+ tooltip+="\nC Source: "+String(err[5])+":"+String(err[6]);
+ tooltip+="\nC Function: "+String(err[4]);
+
+
+
+ error_list->add_item(txt,EditorNode::get_singleton()->get_gui_base()->get_icon(warning?"Warning":"Error","EditorIcons"));
+ error_list->set_item_tooltip( error_list->get_item_count() -1,tooltip );
+
+ int scc = p_data[1];
+
+ Array stack;
+ stack.resize(scc);
+ for(int i=0;i<scc;i++) {
+ stack[i]=p_data[2+i];
+ }
+
+ error_list->set_item_metadata( error_list->get_item_count() -1,stack );
+
+ error_count++;
+ /*
+ int count = p_data[1];
+
+ Array cstack;
+
+ OutputError oe = errors.front()->get();
+
+ packet_peer_stream->put_var(oe.hr);
+ packet_peer_stream->put_var(oe.min);
+ packet_peer_stream->put_var(oe.sec);
+ packet_peer_stream->put_var(oe.msec);
+ packet_peer_stream->put_var(oe.source_func);
+ packet_peer_stream->put_var(oe.source_file);
+ packet_peer_stream->put_var(oe.source_line);
+ packet_peer_stream->put_var(oe.error);
+ packet_peer_stream->put_var(oe.error_descr);
+ packet_peer_stream->put_var(oe.warning);
+ packet_peer_stream->put_var(oe.callstack);
+ */
} else if (p_msg=="kill_me") {
editor->call_deferred("stop_child_process");
@@ -443,10 +540,30 @@ void ScriptEditorDebugger::_notification(int p_what) {
tb->set_hover_texture( get_icon("CloseHover","EditorIcons"));
tb->set_pressed_texture( get_icon("Close","EditorIcons"));
scene_tree_refresh->set_icon( get_icon("Reload","EditorIcons"));
+ le_set->connect("pressed",this,"_live_edit_set");
+ le_clear->connect("pressed",this,"_live_edit_clear");
+ error_list->connect("item_selected",this,"_error_selected");
+ error_stack->connect("item_selected",this,"_error_stack_selected");
+ vmem_refresh->set_icon( get_icon("Reload","EditorIcons"));
} break;
case NOTIFICATION_PROCESS: {
+ if (error_count!=last_error_count) {
+
+ if (error_count==0) {
+ error_split->set_name("Errors");
+ debugger_button->set_text("Debugger");
+ debugger_button->set_icon(Ref<Texture>());
+ tabs->set_tab_icon(error_split->get_index(),Ref<Texture>());
+ } else {
+ error_split->set_name("Errors ("+itos(error_count)+")");
+ debugger_button->set_text("Debugger ("+itos(error_count)+")");
+ debugger_button->set_icon(get_icon("Error","EditorIcons"));
+ tabs->set_tab_icon(error_split->get_index(),get_icon("Error","EditorIcons"));
+ }
+ last_error_count=error_count;
+ }
if (connection.is_null()) {
if (server->is_connection_available()) {
@@ -460,14 +577,23 @@ void ScriptEditorDebugger::_notification(int p_what) {
ppeer->set_stream_peer(connection);
+ //EditorNode::get_singleton()->make_bottom_panel_item_visible(this);
+ //emit_signal("show_debugger",true);
- show();
dobreak->set_disabled(false);
tabs->set_current_tab(0);
- emit_signal("show_debugger",true);
reason->set_text("Child Process Connected");
reason->set_tooltip("Child Process Connected");
+ scene_tree->clear();
+ le_set->set_disabled(true);
+ le_clear->set_disabled(false);
+ error_list->clear();
+ error_stack->clear();
+ error_count=0;
+ //live_edit_root->set_text("/root");
+
+ update_live_edit_root();
} else {
@@ -609,14 +735,23 @@ void ScriptEditorDebugger::stop(){
message.clear();
if (log_forced_visible) {
- EditorNode::get_log()->hide();
+ //EditorNode::get_singleton()->make_bottom_panel_item_visible(this);
+ if (EditorNode::get_log()->is_visible())
+ EditorNode::get_singleton()->hide_bottom_panel();
log_forced_visible=false;
}
+ node_path_cache.clear();
+ res_path_cache.clear();
+ le_clear->set_disabled(false);
+ le_set->set_disabled(true);
- hide();
- emit_signal("show_debugger",false);
+ if (hide_on_stop) {
+ if (is_visible())
+ EditorNode::get_singleton()->hide_bottom_panel();
+ emit_signal("show_debugger",false);
+ }
}
@@ -646,9 +781,9 @@ void ScriptEditorDebugger::_stack_dump_frame_selected() {
void ScriptEditorDebugger::_hide_request() {
- hide();
+ if (EditorNode::get_log()->is_visible())
+ EditorNode::get_singleton()->hide_bottom_panel();
emit_signal("show_debugger",false);
-
}
void ScriptEditorDebugger::_output_clear() {
@@ -664,6 +799,385 @@ String ScriptEditorDebugger::get_var_value(const String& p_var) const {
return variables->get_var_value(p_var);
}
+int ScriptEditorDebugger::_get_node_path_cache(const NodePath& p_path) {
+
+ const int *r = node_path_cache.getptr(p_path);
+ if (r)
+ return *r;
+
+ last_path_id++;
+
+ node_path_cache[p_path]=last_path_id;
+ Array msg;
+ msg.push_back("live_node_path");
+ msg.push_back(p_path);
+ msg.push_back(last_path_id);
+ ppeer->put_var(msg);
+
+
+ return last_path_id;
+}
+
+int ScriptEditorDebugger::_get_res_path_cache(const String& p_path) {
+
+ Map<String,int>::Element *E=res_path_cache.find(p_path);
+
+ if (E)
+ return E->get();
+
+ last_path_id++;
+
+ res_path_cache[p_path]=last_path_id;
+ Array msg;
+ msg.push_back("live_res_path");
+ msg.push_back(p_path);
+ msg.push_back(last_path_id);
+ ppeer->put_var(msg);
+
+
+ return last_path_id;
+}
+
+void ScriptEditorDebugger::_method_changed(Object*p_base,const StringName& p_name,VARIANT_ARG_DECLARE) {
+
+ if (!p_base || !live_debug || !connection.is_valid() || !editor->get_edited_scene())
+ return;
+
+ Node *node = p_base->cast_to<Node>();
+
+ VARIANT_ARGPTRS
+
+ for(int i=0;i<VARIANT_ARG_MAX;i++) {
+ //no pointers, sorry
+ if (argptr[i] && (argptr[i]->get_type()==Variant::OBJECT || argptr[i]->get_type()==Variant::_RID))
+ return;
+ }
+
+ if (node) {
+
+ NodePath path = editor->get_edited_scene()->get_path_to(node);
+ int pathid = _get_node_path_cache(path);
+
+
+
+ Array msg;
+ msg.push_back("live_node_call");
+ msg.push_back(pathid);
+ msg.push_back(p_name);
+ for(int i=0;i<VARIANT_ARG_MAX;i++) {
+ //no pointers, sorry
+ msg.push_back(*argptr[i]);
+ }
+ ppeer->put_var(msg);
+
+ return;
+
+ }
+
+ Resource *res = p_base->cast_to<Resource>();
+
+ if (res && res->get_path()!=String()) {
+
+ String respath = res->get_path();
+ int pathid = _get_res_path_cache(respath);
+
+ Array msg;
+ msg.push_back("live_res_call");
+ msg.push_back(pathid);
+ msg.push_back(p_name);
+ for(int i=0;i<VARIANT_ARG_MAX;i++) {
+ //no pointers, sorry
+ msg.push_back(*argptr[i]);
+ }
+ ppeer->put_var(msg);
+
+ return;
+ }
+
+ //print_line("method");
+}
+
+void ScriptEditorDebugger::_property_changed(Object*p_base,const StringName& p_property,const Variant& p_value){
+
+ if (!p_base || !live_debug || !connection.is_valid() || !editor->get_edited_scene())
+ return;
+
+ Node *node = p_base->cast_to<Node>();
+
+ if (node) {
+
+ NodePath path = editor->get_edited_scene()->get_path_to(node);
+ int pathid = _get_node_path_cache(path);
+
+
+ if (p_value.is_ref()) {
+ Ref<Resource> res = p_value;
+ if (res.is_valid() && res->get_path()!=String()) {
+
+ Array msg;
+ msg.push_back("live_node_prop_res");
+ msg.push_back(pathid);
+ msg.push_back(p_property);
+ msg.push_back(res->get_path());
+ ppeer->put_var(msg);
+ }
+ } else {
+
+ Array msg;
+ msg.push_back("live_node_prop");
+ msg.push_back(pathid);
+ msg.push_back(p_property);
+ msg.push_back(p_value);
+ ppeer->put_var(msg);
+ }
+
+
+ return;
+
+ }
+
+ Resource *res = p_base->cast_to<Resource>();
+
+ if (res && res->get_path()!=String()) {
+
+ String respath = res->get_path();
+ int pathid = _get_res_path_cache(respath);
+
+
+ if (p_value.is_ref()) {
+ Ref<Resource> res = p_value;
+ if (res.is_valid() && res->get_path()!=String()) {
+
+ Array msg;
+ msg.push_back("live_res_prop_res");
+ msg.push_back(pathid);
+ msg.push_back(p_property);
+ msg.push_back(res->get_path());
+ ppeer->put_var(msg);
+ }
+ } else {
+
+ Array msg;
+ msg.push_back("live_res_prop");
+ msg.push_back(pathid);
+ msg.push_back(p_property);
+ msg.push_back(p_value);
+ ppeer->put_var(msg);
+ }
+
+
+ return;
+ }
+
+
+ //print_line("prop");
+}
+
+void ScriptEditorDebugger::_method_changeds(void *p_ud,Object*p_base,const StringName& p_name,VARIANT_ARG_DECLARE) {
+
+ ScriptEditorDebugger *sed = (ScriptEditorDebugger*)p_ud;
+ sed->_method_changed(p_base,p_name,VARIANT_ARG_PASS);
+
+
+}
+
+void ScriptEditorDebugger::_property_changeds(void *p_ud,Object*p_base,const StringName& p_property,const Variant& p_value){
+
+ ScriptEditorDebugger *sed = (ScriptEditorDebugger*)p_ud;
+ sed->_property_changed(p_base,p_property,p_value);
+
+}
+
+void ScriptEditorDebugger::set_live_debugging(bool p_enable) {
+
+ live_debug=p_enable;
+}
+
+void ScriptEditorDebugger::_live_edit_set() {
+
+ if (!connection.is_valid())
+ return;
+
+ TreeItem* ti = scene_tree->get_selected();
+ if (!ti)
+ return;
+ String path;
+
+ while(ti) {
+ String lp=ti->get_text(0);
+ path="/"+lp+path;
+ ti=ti->get_parent();
+
+ }
+
+ NodePath np = path;
+
+ editor->get_editor_data().set_edited_scene_live_edit_root(np);
+
+ update_live_edit_root();
+
+
+}
+
+void ScriptEditorDebugger::_live_edit_clear() {
+
+ NodePath np = NodePath("/root");
+ editor->get_editor_data().set_edited_scene_live_edit_root(np);
+
+ update_live_edit_root();
+
+}
+
+void ScriptEditorDebugger::update_live_edit_root() {
+
+ NodePath np = editor->get_editor_data().get_edited_scene_live_edit_root();
+
+ if (connection.is_valid()) {
+ Array msg;
+ msg.push_back("live_set_root");
+ msg.push_back(np);
+ if (editor->get_edited_scene())
+ msg.push_back(editor->get_edited_scene()->get_filename());
+ else
+ msg.push_back("");
+ ppeer->put_var(msg);
+ }
+ live_edit_root->set_text(np);
+
+}
+
+void ScriptEditorDebugger::live_debug_create_node(const NodePath& p_parent,const String& p_type,const String& p_name) {
+
+ if (live_debug && connection.is_valid()) {
+ Array msg;
+ msg.push_back("live_create_node");
+ msg.push_back(p_parent);
+ msg.push_back(p_type);
+ msg.push_back(p_name);
+ ppeer->put_var(msg);
+ }
+}
+
+void ScriptEditorDebugger::live_debug_instance_node(const NodePath& p_parent,const String& p_path,const String& p_name){
+
+ if (live_debug && connection.is_valid()) {
+ Array msg;
+ msg.push_back("live_instance_node");
+ msg.push_back(p_parent);
+ msg.push_back(p_path);
+ msg.push_back(p_name);
+ ppeer->put_var(msg);
+ }
+
+}
+void ScriptEditorDebugger::live_debug_remove_node(const NodePath& p_at){
+
+ if (live_debug && connection.is_valid()) {
+ Array msg;
+ msg.push_back("live_remove_node");
+ msg.push_back(p_at);
+ ppeer->put_var(msg);
+ }
+
+}
+void ScriptEditorDebugger::live_debug_remove_and_keep_node(const NodePath& p_at,ObjectID p_keep_id) {
+
+ if (live_debug && connection.is_valid()) {
+ Array msg;
+ msg.push_back("live_remove_and_keep_node");
+ msg.push_back(p_at);
+ msg.push_back(p_keep_id);
+ ppeer->put_var(msg);
+ }
+
+}
+void ScriptEditorDebugger::live_debug_restore_node(ObjectID p_id, const NodePath& p_at, int p_at_pos){
+
+ if (live_debug && connection.is_valid()) {
+ Array msg;
+ msg.push_back("live_restore_node");
+ msg.push_back(p_id);
+ msg.push_back(p_at);
+ msg.push_back(p_at_pos);
+ ppeer->put_var(msg);
+ }
+
+}
+void ScriptEditorDebugger::live_debug_duplicate_node(const NodePath& p_at,const String& p_new_name){
+
+ if (live_debug && connection.is_valid()) {
+ Array msg;
+ msg.push_back("live_duplicate_node");
+ msg.push_back(p_at);
+ msg.push_back(p_new_name);
+ ppeer->put_var(msg);
+ }
+
+}
+void ScriptEditorDebugger::live_debug_reparent_node(const NodePath& p_at, const NodePath& p_new_place, const String &p_new_name, int p_at_pos){
+
+ if (live_debug && connection.is_valid()) {
+ Array msg;
+ msg.push_back("live_reparent_node");
+ msg.push_back(p_at);
+ msg.push_back(p_new_place);
+ msg.push_back(p_new_name);
+ msg.push_back(p_at_pos);
+ ppeer->put_var(msg);
+ }
+
+}
+
+void ScriptEditorDebugger::set_breakpoint(const String& p_path,int p_line,bool p_enabled) {
+
+ if (connection.is_valid()) {
+ Array msg;
+ msg.push_back("breakpoint");
+ msg.push_back(p_path);
+ msg.push_back(p_line);
+ msg.push_back(p_enabled);
+ ppeer->put_var(msg);
+ }
+}
+
+
+void ScriptEditorDebugger::_error_selected(int p_idx) {
+
+ error_stack->clear();
+ Array st=error_list->get_item_metadata(p_idx);
+ for(int i=0;i<st.size();i+=2) {
+
+ String script=st[i];
+ int line=st[i+1];
+ Array md;
+ md.push_back(st[i]);
+ md.push_back(st[i+1]);
+
+ String str = script.get_file()+":"+itos(line);
+
+ error_stack->add_item(str);
+ error_stack->set_item_metadata(error_stack->get_item_count()-1,md);
+ error_stack->set_item_tooltip(error_stack->get_item_count()-1,"File: "+String(st[i])+"\nLine: "+itos(line));
+ }
+}
+
+void ScriptEditorDebugger:: _error_stack_selected(int p_idx){
+
+ Array arr = error_stack->get_item_metadata(p_idx);
+ if (arr.size()!=2)
+ return;
+
+
+ Ref<Script> s = ResourceLoader::load(arr[0]);
+ emit_signal("goto_script_line",s,int(arr[1])-1);
+
+}
+
+void ScriptEditorDebugger::set_hide_on_stop(bool p_hide) {
+
+ hide_on_stop=p_hide;
+}
+
void ScriptEditorDebugger::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_stack_dump_frame_selected"),&ScriptEditorDebugger::_stack_dump_frame_selected);
@@ -676,6 +1190,20 @@ void ScriptEditorDebugger::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_performance_draw"),&ScriptEditorDebugger::_performance_draw);
ObjectTypeDB::bind_method(_MD("_performance_select"),&ScriptEditorDebugger::_performance_select);
ObjectTypeDB::bind_method(_MD("_scene_tree_request"),&ScriptEditorDebugger::_scene_tree_request);
+ ObjectTypeDB::bind_method(_MD("_video_mem_request"),&ScriptEditorDebugger::_video_mem_request);
+ ObjectTypeDB::bind_method(_MD("_live_edit_set"),&ScriptEditorDebugger::_live_edit_set);
+ ObjectTypeDB::bind_method(_MD("_live_edit_clear"),&ScriptEditorDebugger::_live_edit_clear);
+
+ ObjectTypeDB::bind_method(_MD("_error_selected"),&ScriptEditorDebugger::_error_selected);
+ ObjectTypeDB::bind_method(_MD("_error_stack_selected"),&ScriptEditorDebugger::_error_stack_selected);
+
+ ObjectTypeDB::bind_method(_MD("live_debug_create_node"),&ScriptEditorDebugger::live_debug_create_node);
+ ObjectTypeDB::bind_method(_MD("live_debug_instance_node"),&ScriptEditorDebugger::live_debug_instance_node);
+ ObjectTypeDB::bind_method(_MD("live_debug_remove_node"),&ScriptEditorDebugger::live_debug_remove_node);
+ ObjectTypeDB::bind_method(_MD("live_debug_remove_and_keep_node"),&ScriptEditorDebugger::live_debug_remove_and_keep_node);
+ ObjectTypeDB::bind_method(_MD("live_debug_restore_node"),&ScriptEditorDebugger::live_debug_restore_node);
+ ObjectTypeDB::bind_method(_MD("live_debug_duplicate_node"),&ScriptEditorDebugger::live_debug_duplicate_node);
+ ObjectTypeDB::bind_method(_MD("live_debug_reparent_node"),&ScriptEditorDebugger::live_debug_reparent_node);
ADD_SIGNAL(MethodInfo("goto_script_line"));
ADD_SIGNAL(MethodInfo("breaked",PropertyInfo(Variant::BOOL,"reallydid")));
@@ -711,12 +1239,13 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor){
vbc->add_child(hbc);
- reason = memnew( Label );
+ reason = memnew( LineEdit );
reason->set_text("");
+ reason->set_editable(false);
hbc->add_child(reason);
reason->add_color_override("font_color",Color(1,0.4,0.0,0.8));
reason->set_h_size_flags(SIZE_EXPAND_FILL);
- reason->set_clip_text(true);
+ //reason->set_clip_text(true);
hbc->add_child( memnew( VSeparator) );
@@ -789,6 +1318,23 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor){
vbc->add_child(hbc);
+ error_split = memnew( HSplitContainer );
+ VBoxContainer *errvb = memnew( VBoxContainer );
+ errvb->set_h_size_flags(SIZE_EXPAND_FILL);
+ error_list = memnew( ItemList );
+ errvb->add_margin_child("Errors:",error_list,true);
+ error_split->add_child(errvb);
+
+ errvb = memnew( VBoxContainer );
+ errvb->set_h_size_flags(SIZE_EXPAND_FILL);
+ error_stack = memnew( ItemList );
+ errvb->add_margin_child("Stack Trace (if applies):",error_stack,true);
+ error_split->add_child(errvb);
+
+ error_split->set_name("Errors");
+ tabs->add_child(error_split);
+
+
HSplitContainer *hsp = memnew( HSplitContainer );
perf_monitors = memnew(Tree);
@@ -832,6 +1378,47 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor){
}
+ VBoxContainer *vmem_vb = memnew( VBoxContainer );
+ HBoxContainer *vmem_hb = memnew( HBoxContainer );
+ Label *vmlb = memnew(Label("List of Video Memory Usage by Resource: ") );
+ vmlb->set_h_size_flags(SIZE_EXPAND_FILL);
+ vmem_hb->add_child( vmlb );
+ vmem_hb->add_child( memnew(Label("Total: ")) );
+ vmem_total = memnew( LineEdit );
+ vmem_total->set_editable(false);
+ vmem_total->set_custom_minimum_size(Size2(100,1));
+ vmem_hb->add_child(vmem_total);
+ vmem_refresh = memnew( Button );
+ vmem_hb->add_child(vmem_refresh);
+ vmem_vb->add_child(vmem_hb);
+ vmem_refresh->connect("pressed",this,"_video_mem_request");
+
+ MarginContainer *vmmc = memnew( MarginContainer );
+ vmem_tree = memnew( Tree );
+ vmem_tree->set_v_size_flags(SIZE_EXPAND_FILL);
+ vmem_tree->set_h_size_flags(SIZE_EXPAND_FILL);
+ vmmc->add_child(vmem_tree);
+ vmmc->set_v_size_flags(SIZE_EXPAND_FILL);
+ vmem_vb->add_child(vmmc);
+
+ vmem_vb->set_name("Video Mem");
+ vmem_tree->set_columns(4);
+ vmem_tree->set_column_titles_visible(true);
+ vmem_tree->set_column_title(0,"Resource Path");
+ vmem_tree->set_column_expand(0,true);
+ vmem_tree->set_column_expand(1,false);
+ vmem_tree->set_column_title(1,"Type");
+ vmem_tree->set_column_min_width(1,100);
+ vmem_tree->set_column_expand(2,false);
+ vmem_tree->set_column_title(2,"Format");
+ vmem_tree->set_column_min_width(2,150);
+ vmem_tree->set_column_expand(3,false);
+ vmem_tree->set_column_title(3,"Usage");
+ vmem_tree->set_column_min_width(3,80);
+ vmem_tree->set_hide_root(true);
+
+ tabs->add_child(vmem_vb);
+
info = memnew( HSplitContainer );
info->set_name("Info");
tabs->add_child(info);
@@ -843,6 +1430,26 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor){
info_left->add_margin_child("Clicked Control:",clicked_ctrl);
clicked_ctrl_type = memnew( LineEdit );
info_left->add_margin_child("Clicked Control Type:",clicked_ctrl_type);
+
+ live_edit_root = memnew( LineEdit );
+
+ {
+ HBoxContainer *lehb = memnew( HBoxContainer );
+ Label *l = memnew( Label("Live Edit Root:") );
+ lehb->add_child(l);
+ l->set_h_size_flags(SIZE_EXPAND_FILL);
+ le_set = memnew( Button("Set From Tree") );
+ lehb->add_child(le_set);
+ le_clear = memnew( Button("Clear") );
+ lehb->add_child(le_clear);
+ info_left->add_child(lehb);
+ MarginContainer *mc = memnew( MarginContainer );
+ mc->add_child(live_edit_root);
+ info_left->add_child(mc);
+ le_set->set_disabled(true);
+ le_clear->set_disabled(true);
+ }
+
VBoxContainer *info_right = memnew(VBoxContainer);
info_right->set_h_size_flags(SIZE_EXPAND_FILL);
info->add_child(info_right);
@@ -865,9 +1472,17 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor){
msgdialog = memnew( AcceptDialog );
add_child(msgdialog);
- hide();
log_forced_visible=false;
+ p_editor->get_undo_redo()->set_method_notify_callback(_method_changeds,this);
+ p_editor->get_undo_redo()->set_property_notify_callback(_property_changeds,this);
+ live_debug=false;
+ last_path_id=false;
+ error_count=0;
+ hide_on_stop=true;
+ last_error_count=0;
+
+
}
ScriptEditorDebugger::~ScriptEditorDebugger() {
diff --git a/tools/editor/script_editor_debugger.h b/tools/editor/script_editor_debugger.h
index c59cc1cf9d..0be311a990 100644
--- a/tools/editor/script_editor_debugger.h
+++ b/tools/editor/script_editor_debugger.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -45,6 +45,7 @@ class TextureButton;
class AcceptDialog;
class TreeItem;
class HSplitContainer;
+class ItemList;
class ScriptEditorDebugger : public Control {
@@ -53,19 +54,34 @@ class ScriptEditorDebugger : public Control {
AcceptDialog *msgdialog;
+ Button *debugger_button;
LineEdit *clicked_ctrl;
LineEdit *clicked_ctrl_type;
+ LineEdit *live_edit_root;
Tree *scene_tree;
HSplitContainer *info;
Button *scene_tree_refresh;
+ Button *le_set;
+ Button *le_clear;
+
+ HSplitContainer *error_split;
+ ItemList *error_list;
+ ItemList *error_stack;
+
+ int error_count;
+ int last_error_count;
+
+ bool hide_on_stop;
+
+
TextureButton *tb;
TabContainer *tabs;
- Label *reason;
+ LineEdit *reason;
bool log_forced_visible;
ScriptEditorDebuggerVariables *variables;
@@ -83,6 +99,10 @@ class ScriptEditorDebugger : public Control {
Tree *perf_monitors;
Control *perf_draw;
+ Tree *vmem_tree;
+ Button *vmem_refresh;
+ LineEdit *vmem_total;
+
Tree *stack_dump;
PropertyEditor *inspector;
@@ -94,11 +114,17 @@ class ScriptEditorDebugger : public Control {
Array message;
int pending_in_queue;
+ HashMap<NodePath,int> node_path_cache;
+ int last_path_id;
+ Map<String,int> res_path_cache;
+
EditorNode *editor;
bool breaked;
+ bool live_debug;
+
void _performance_draw();
void _performance_select(Object *, int, bool);
void _stack_dump_frame_selected();
@@ -108,6 +134,24 @@ class ScriptEditorDebugger : public Control {
void _scene_tree_request();
void _parse_message(const String& p_msg,const Array& p_data);
+ void _video_mem_request();
+
+ int _get_node_path_cache(const NodePath& p_path);
+
+ int _get_res_path_cache(const String& p_path);
+
+ void _live_edit_set();
+ void _live_edit_clear();
+
+ void _method_changed(Object*p_base,const StringName& p_name,VARIANT_ARG_DECLARE);
+ void _property_changed(Object*p_base,const StringName& p_property,const Variant& p_value);
+
+ static void _method_changeds(void *p_ud,Object*p_base,const StringName& p_name,VARIANT_ARG_DECLARE);
+ static void _property_changeds(void *p_ud,Object*p_base,const StringName& p_property,const Variant& p_value);
+
+ void _error_selected(int p_idx);
+ void _error_stack_selected(int p_idx);
+
protected:
void _notification(int p_what);
@@ -127,6 +171,24 @@ public:
String get_var_value(const String& p_var) const;
+ void set_live_debugging(bool p_enable);
+
+ void live_debug_create_node(const NodePath& p_parent,const String& p_type,const String& p_name);
+ void live_debug_instance_node(const NodePath& p_parent,const String& p_path,const String& p_name);
+ void live_debug_remove_node(const NodePath& p_at);
+ void live_debug_remove_and_keep_node(const NodePath& p_at,ObjectID p_keep_id);
+ void live_debug_restore_node(ObjectID p_id,const NodePath& p_at,int p_at_pos);
+ void live_debug_duplicate_node(const NodePath& p_at,const String& p_new_name);
+ void live_debug_reparent_node(const NodePath& p_at,const NodePath& p_new_place,const String& p_new_name,int p_at_pos);
+
+ void set_breakpoint(const String& p_path,int p_line,bool p_enabled);
+
+ void update_live_edit_root();
+
+ void set_hide_on_stop(bool p_hide);
+
+ void set_tool_button(Button *p_tb) { debugger_button=p_tb; }
+
virtual Size2 get_minimum_size() const;
ScriptEditorDebugger(EditorNode *p_editor=NULL);
~ScriptEditorDebugger();
diff --git a/tools/editor/settings_config_dialog.cpp b/tools/editor/settings_config_dialog.cpp
index f73de26eec..3d30b3882d 100644
--- a/tools/editor/settings_config_dialog.cpp
+++ b/tools/editor/settings_config_dialog.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -71,7 +71,8 @@ void EditorSettingsDialog::popup_edit_settings() {
return;
property_editor->edit(EditorSettings::get_singleton());
- property_editor->update_tree();
+ property_editor->get_property_editor()->update_tree();
+
popup_centered_ratio(0.7);
}
@@ -250,6 +251,9 @@ void EditorSettingsDialog::_notification(int p_what) {
rescan_plugins->set_icon(get_icon("Reload","EditorIcons"));
_update_plugins();
+ } else if (p_what==NOTIFICATION_POST_POPUP) {
+
+ property_editor->clear_search_box();
}
}
@@ -271,10 +275,11 @@ EditorSettingsDialog::EditorSettingsDialog() {
add_child(tabs);
set_child_rect(tabs);
- property_editor = memnew( PropertyEditor );
- property_editor->hide_top_label();
- tabs->add_child(property_editor);
+ property_editor = memnew( SectionedPropertyEditor );
+ //property_editor->hide_top_label();
property_editor->set_name("General");
+ property_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ tabs->add_child(property_editor);
VBoxContainer *vbc = memnew( VBoxContainer );
tabs->add_child(vbc);
diff --git a/tools/editor/settings_config_dialog.h b/tools/editor/settings_config_dialog.h
index cca1ef33d5..119b4035ca 100644
--- a/tools/editor/settings_config_dialog.h
+++ b/tools/editor/settings_config_dialog.h
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -51,7 +51,7 @@ class EditorSettingsDialog : public AcceptDialog {
Button *rescan_plugins;
Tree *plugins;
- PropertyEditor *property_editor;
+ SectionedPropertyEditor *property_editor;
Timer *timer;
@@ -71,6 +71,8 @@ class EditorSettingsDialog : public AcceptDialog {
void _rescan_plugins();
void _update_plugins();
+ void _clear_search_box();
+
protected:
static void _bind_methods();
diff --git a/tools/editor/spatial_editor_gizmos.cpp b/tools/editor/spatial_editor_gizmos.cpp
index 521a10bbd0..320b0c3a70 100644
--- a/tools/editor/spatial_editor_gizmos.cpp
+++ b/tools/editor/spatial_editor_gizmos.cpp
@@ -1,3191 +1,3193 @@
-/*************************************************************************/
-/* spatial_editor_gizmos.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* http://www.godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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. */
-/*************************************************************************/
-#include "spatial_editor_gizmos.h"
-#include "geometry.h"
-#include "scene/3d/camera.h"
-#include "scene/resources/surface_tool.h"
-#include "scene/resources/sphere_shape.h"
-#include "scene/resources/box_shape.h"
-#include "scene/resources/capsule_shape.h"
-#include "scene/resources/ray_shape.h"
-#include "scene/resources/convex_polygon_shape.h"
-#include "scene/resources/plane_shape.h"
-#include "quick_hull.h"
-
-// Keep small children away from this file.
-// It's so ugly it will eat them alive
-
-#define HANDLE_HALF_SIZE 0.05
-
-void SpatialGizmoTool::clear() {
-
- for(int i=0;i<instances.size();i++) {
-
- if (instances[i].instance.is_valid())
- VS::get_singleton()->free(instances[i].instance);
-
-
- }
-
- billboard_handle=false;
- collision_segments.clear();
- collision_mesh=Ref<TriangleMesh>();
- instances.clear();
- handles.clear();
- secondary_handles.clear();
-}
-
-void SpatialGizmoTool::Instance::create_instance(Spatial *p_base) {
-
- instance = VS::get_singleton()->instance_create2(mesh->get_rid(),p_base->get_world()->get_scenario());
- VS::get_singleton()->instance_attach_object_instance_ID(instance,p_base->get_instance_ID());
- if (billboard)
- VS::get_singleton()->instance_geometry_set_flag(instance,VS::INSTANCE_FLAG_BILLBOARD,true);
- if (unscaled)
- VS::get_singleton()->instance_geometry_set_flag(instance,VS::INSTANCE_FLAG_DEPH_SCALE,true);
- if (skeleton.is_valid())
- VS::get_singleton()->instance_attach_skeleton(instance,skeleton);
- if (extra_margin)
- VS::get_singleton()->instance_set_extra_visibility_margin(instance,1);
- VS::get_singleton()->instance_geometry_set_flag(instance,VS::INSTANCE_FLAG_CAST_SHADOW,false);
- VS::get_singleton()->instance_geometry_set_flag(instance,VS::INSTANCE_FLAG_RECEIVE_SHADOWS,false);
- VS::get_singleton()->instance_set_layer_mask(instance,1<<SpatialEditorViewport::GIZMO_EDIT_LAYER); //gizmos are 26
-}
-
-
-
-void SpatialGizmoTool::add_mesh(const Ref<Mesh>& p_mesh,bool p_billboard, const RID &p_skeleton) {
-
- ERR_FAIL_COND(!spatial_node);
- Instance ins;
-
- ins.billboard=p_billboard;
- ins.mesh=p_mesh;
- ins.skeleton=p_skeleton;
- if (valid) {
- ins.create_instance(spatial_node);
- VS::get_singleton()->instance_set_transform(ins.instance,spatial_node->get_global_transform());
- }
-
- instances.push_back(ins);
-
-}
-
-void SpatialGizmoTool::add_lines(const Vector<Vector3> &p_lines, const Ref<Material> &p_material,bool p_billboard){
-
- ERR_FAIL_COND(!spatial_node);
- Instance ins;
-
- Ref<Mesh> mesh = memnew( Mesh );
- Array a;
- a.resize(Mesh::ARRAY_MAX);
-
- a[Mesh::ARRAY_VERTEX]=p_lines;
-
- DVector<Color> color;
- color.resize(p_lines.size());
- {
- DVector<Color>::Write w = color.write();
- for(int i=0;i<p_lines.size();i++) {
- if (is_selected())
- w[i]=Color(1,1,1,0.6);
- else
- w[i]=Color(1,1,1,0.25);
- }
-
- }
-
- a[Mesh::ARRAY_COLOR]=color;
-
-
- mesh->add_surface(Mesh::PRIMITIVE_LINES,a);
- mesh->surface_set_material(0,p_material);
-
- if (p_billboard) {
- float md=0;
- for(int i=0;i<p_lines.size();i++) {
-
- md=MAX(0,p_lines[i].length());
-
- }
- if (md) {
- mesh->set_custom_aabb(AABB(Vector3(-md,-md,-md),Vector3(md,md,md)*2.0));
- }
- }
-
- ins.billboard=p_billboard;
- ins.mesh=mesh;
- if (valid) {
- ins.create_instance(spatial_node);
- VS::get_singleton()->instance_set_transform(ins.instance,spatial_node->get_global_transform());
- }
-
- instances.push_back(ins);
-
-}
-
-void SpatialGizmoTool::add_unscaled_billboard(const Ref<Material>& p_material,float p_scale) {
-
- ERR_FAIL_COND(!spatial_node);
- Instance ins;
-
- Vector<Vector3 > vs;
- Vector<Vector2 > uv;
-
- vs.push_back(Vector3(-p_scale,p_scale,0));
- vs.push_back(Vector3(p_scale,p_scale,0));
- vs.push_back(Vector3(p_scale,-p_scale,0));
- vs.push_back(Vector3(-p_scale,-p_scale,0));
-
- uv.push_back(Vector2(1,0));
- uv.push_back(Vector2(0,0));
- uv.push_back(Vector2(0,1));
- uv.push_back(Vector2(1,1));
-
- Ref<Mesh> mesh = memnew( Mesh );
- Array a;
- a.resize(Mesh::ARRAY_MAX);
- a[Mesh::ARRAY_VERTEX]=vs;
- a[Mesh::ARRAY_TEX_UV]=uv;
- mesh->add_surface(Mesh::PRIMITIVE_TRIANGLE_FAN,a);
- mesh->surface_set_material(0,p_material);
-
- if (true) {
- float md=0;
- for(int i=0;i<vs.size();i++) {
-
- md=MAX(0,vs[i].length());
-
- }
- if (md) {
- mesh->set_custom_aabb(AABB(Vector3(-md,-md,-md),Vector3(md,md,md)*2.0));
- }
- }
-
- ins.mesh=mesh;
- ins.unscaled=true;
- ins.billboard=true;
- if (valid) {
- ins.create_instance(spatial_node);
- VS::get_singleton()->instance_set_transform(ins.instance,spatial_node->get_global_transform());
- }
-
- instances.push_back(ins);
-
-
-}
-
-void SpatialGizmoTool::add_collision_triangles(const Ref<TriangleMesh>& p_tmesh) {
-
- collision_mesh=p_tmesh;
-}
-
-void SpatialGizmoTool::add_collision_segments(const Vector<Vector3> &p_lines) {
-
- int from=collision_segments.size();
- collision_segments.resize(from+p_lines.size());
- for(int i=0;i<p_lines.size();i++) {
-
- collision_segments[from+i]=p_lines[i];
- }
-}
-
-
-void SpatialGizmoTool::add_handles(const Vector<Vector3> &p_handles, bool p_billboard,bool p_secondary){
-
- billboard_handle=p_billboard;
-
- if (!is_selected())
- return;
-
- ERR_FAIL_COND(!spatial_node);
-
- ERR_FAIL_COND(!spatial_node);
- Instance ins;
-
-
- Ref<Mesh> mesh = memnew( Mesh );
-#if 1
-
- Array a;
- a.resize(VS::ARRAY_MAX);
- a[VS::ARRAY_VERTEX]=p_handles;
- DVector<Color> colors;
- {
- colors.resize(p_handles.size());
- DVector<Color>::Write w=colors.write();
- for(int i=0;i<p_handles.size();i++) {
-
- Color col(1,1,1,1);
- if (SpatialEditor::get_singleton()->get_over_gizmo_handle()!=i)
- col=Color(0.9,0.9,0.9,0.9);
- w[i]=col;
- }
-
- }
- a[VS::ARRAY_COLOR]=colors;
- mesh->add_surface(Mesh::PRIMITIVE_POINTS,a);
- mesh->surface_set_material(0,SpatialEditorGizmos::singleton->handle2_material);
-
- if (p_billboard) {
- float md=0;
- for(int i=0;i<p_handles.size();i++) {
-
- md=MAX(0,p_handles[i].length());
-
- }
- if (md) {
- mesh->set_custom_aabb(AABB(Vector3(-md,-md,-md),Vector3(md,md,md)*2.0));
- }
- }
-
-
-
-#else
- for(int ih=0;ih<p_handles.size();ih++) {
-
-
- Vector<Vector3> vertices;
- Vector<Vector3> normals;
-
- int vtx_idx=0;
-#define ADD_VTX(m_idx);\
- vertices.push_back( (face_points[m_idx]*HANDLE_HALF_SIZE+p_handles[ih]) );\
- normals.push_back( normal_points[m_idx] );\
- vtx_idx++;\
-
- for (int i=0;i<6;i++) {
-
-
- Vector3 face_points[4];
- Vector3 normal_points[4];
- float uv_points[8]={0,0,0,1,1,1,1,0};
-
- for (int j=0;j<4;j++) {
-
- float v[3];
- v[0]=1.0;
- v[1]=1-2*((j>>1)&1);
- v[2]=v[1]*(1-2*(j&1));
-
- for (int k=0;k<3;k++) {
-
- if (i<3)
- face_points[j][(i+k)%3]=v[k]*(i>=3?-1:1);
- else
- face_points[3-j][(i+k)%3]=v[k]*(i>=3?-1:1);
- }
- normal_points[j]=Vector3();
- normal_points[j][i%3]=(i>=3?-1:1);
- }
- //tri 1
- ADD_VTX(0);
- ADD_VTX(1);
- ADD_VTX(2);
- //tri 2
- ADD_VTX(2);
- ADD_VTX(3);
- ADD_VTX(0);
-
- }
-
-
- Array d;
- d.resize(VS::ARRAY_MAX);
- d[VisualServer::ARRAY_NORMAL]= normals ;
- d[VisualServer::ARRAY_VERTEX]= vertices ;
-
- mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES,d);
- mesh->surface_set_material(ih,SpatialEditorGizmos::singleton->handle_material);
-
-
- }
-#endif
- ins.mesh=mesh;
- ins.billboard=p_billboard;
- ins.extra_margin=true;
- if (valid) {
- ins.create_instance(spatial_node);
- VS::get_singleton()->instance_set_transform(ins.instance,spatial_node->get_global_transform());
- }
- instances.push_back(ins);
- if (!p_secondary) {
- int chs=handles.size();
- handles.resize(chs+p_handles.size());
- for(int i=0;i<p_handles.size();i++) {
- handles[i+chs]=p_handles[i];
- }
- } else {
-
- int chs=secondary_handles.size();
- secondary_handles.resize(chs+p_handles.size());
- for(int i=0;i<p_handles.size();i++) {
- secondary_handles[i+chs]=p_handles[i];
- }
-
- }
-
-}
-
-
-void SpatialGizmoTool::set_spatial_node(Spatial *p_node){
-
- spatial_node=p_node;
-
-}
-
-bool SpatialGizmoTool::intersect_frustum(const Camera *p_camera,const Vector<Plane> &p_frustum) {
-
- ERR_FAIL_COND_V(!spatial_node,false);
- ERR_FAIL_COND_V(!valid,false);
-
- if (collision_segments.size()) {
-
- const Plane *p=p_frustum.ptr();
- int fc=p_frustum.size();
-
- int vc=collision_segments.size();
- const Vector3* vptr=collision_segments.ptr();
- Transform t = spatial_node->get_global_transform();
-
- for(int i=0;i<vc/2;i++) {
-
-
- Vector3 a=t.xform(vptr[i*2+0]);
- Vector3 b=t.xform(vptr[i*2+1]);
-
- bool any_out=false;
- for(int j=0;j<fc;j++) {
-
- if (p[j].distance_to(a) > 0 && p[j].distance_to(b) >0) {
-
- any_out=true;
- break;
- }
- }
-
- if (!any_out)
- return true;
- }
-
- return false;
- }
-
- return false;
-}
-
-
-bool SpatialGizmoTool::intersect_ray(const Camera *p_camera,const Point2& p_point, Vector3& r_pos, Vector3& r_normal,int *r_gizmo_handle,bool p_sec_first) {
-
- ERR_FAIL_COND_V(!spatial_node,false);
- ERR_FAIL_COND_V(!valid,false);
-
- if (r_gizmo_handle) {
-
- Transform t = spatial_node->get_global_transform();
- t.orthonormalize();
- if (billboard_handle) {
- t.set_look_at(t.origin,t.origin+p_camera->get_transform().basis.get_axis(2),p_camera->get_transform().basis.get_axis(1));
- }
- Transform ti=t.affine_inverse();
-
- Vector3 ray_from=ti.xform(p_camera->project_ray_origin(p_point));
- Vector3 ray_dir=t.basis.xform_inv(p_camera->project_ray_normal(p_point)).normalized();
- Vector3 ray_to = ray_from+ray_dir*4096;
-
- float min_d=1e20;
- int idx=-1;
-
- for(int i=0;i<secondary_handles.size();i++) {
-#if 1
-
-
- Vector3 hpos = t.xform(secondary_handles[i]);
- Vector2 p = p_camera->unproject_position(hpos);
- if (p.distance_to(p_point)<SpatialEditorGizmos::singleton->handle_t->get_width()*0.6) {
-
-
- real_t dp = p_camera->get_transform().origin.distance_to(hpos);
- if (dp<min_d) {
-
- r_pos=t.xform(hpos);
- r_normal=p_camera->get_transform().basis.get_axis(2);
- min_d=dp;
- idx=i+handles.size();
-
- }
-
- }
-
-#else
- AABB aabb;
- aabb.pos=Vector3(-1,-1,-1)*HANDLE_HALF_SIZE;
- aabb.size=aabb.pos*-2;
- aabb.pos+=secondary_handles[i];
-
-
- Vector3 rpos,rnorm;
-
- if (aabb.intersects_segment(ray_from,ray_to,&rpos,&rnorm)) {
-
- real_t dp = ray_dir.dot(rpos);
- if (dp<min_d) {
-
- r_pos=t.xform(rpos);
- r_normal=ti.basis.xform_inv(rnorm).normalized();
- min_d=dp;
- idx=i+handles.size();
-
- }
- }
-#endif
- }
-
- if (p_sec_first && idx!=-1) {
-
- *r_gizmo_handle=idx;
- return true;
- }
-
- min_d=1e20;
-
- for(int i=0;i<handles.size();i++) {
-
-#if 1
-
-
- Vector3 hpos = t.xform(handles[i]);
- Vector2 p = p_camera->unproject_position(hpos);
- if (p.distance_to(p_point)<SpatialEditorGizmos::singleton->handle_t->get_width()*0.6) {
-
-
- real_t dp = p_camera->get_transform().origin.distance_to(hpos);
- if (dp<min_d) {
-
- r_pos=t.xform(hpos);
- r_normal=p_camera->get_transform().basis.get_axis(2);
- min_d=dp;
- idx=i;
-
- }
-
- }
-
-#else
-
- AABB aabb;
- aabb.pos=Vector3(-1,-1,-1)*HANDLE_HALF_SIZE;
- aabb.size=aabb.pos*-2;
- aabb.pos+=handles[i];
-
-
- Vector3 rpos,rnorm;
-
- if (aabb.intersects_segment(ray_from,ray_to,&rpos,&rnorm)) {
-
- real_t dp = ray_dir.dot(rpos);
- if (dp<min_d) {
-
- r_pos=t.xform(rpos);
- r_normal=ti.basis.xform_inv(rnorm).normalized();
- min_d=dp;
- idx=i;
-
- }
- }
-#endif
- }
-
- if (idx>=0) {
- *r_gizmo_handle=idx;
- return true;
- }
-
-
- }
-
- if (collision_segments.size()) {
-
- Plane camp(p_camera->get_transform().origin,(-p_camera->get_transform().basis.get_axis(2)).normalized());
-
- int vc=collision_segments.size();
- const Vector3* vptr=collision_segments.ptr();
- Transform t = spatial_node->get_global_transform();
- if (billboard_handle) {
- t.set_look_at(t.origin,t.origin+p_camera->get_transform().basis.get_axis(2),p_camera->get_transform().basis.get_axis(1));
- }
-
- Vector3 cp;
- float cpd=1e20;
-
- for(int i=0;i<vc/2;i++) {
-
-
- Vector3 a=t.xform(vptr[i*2+0]);
- Vector3 b=t.xform(vptr[i*2+1]);
- Vector2 s[2];
- s[0] = p_camera->unproject_position(a);
- s[1] = p_camera->unproject_position(b);
-
-
- Vector2 p = Geometry::get_closest_point_to_segment_2d(p_point,s);
-
- float pd = p.distance_to(p_point);
-
- if (pd<cpd) {
-
-
- float d = s[0].distance_to(s[1]);
- Vector3 tcp;
- if (d>0) {
-
- float d2=s[0].distance_to(p)/d;
- tcp = a+(b-a)*d2;
-
- } else {
- tcp=a;
-
- }
-
- if (camp.distance_to(tcp)<p_camera->get_znear())
- continue;
- cp=tcp;
- cpd=pd;
- }
- }
-
- if (cpd<8) {
-
- r_pos=cp;
- r_normal=-p_camera->project_ray_normal(p_point);
- return true;
- }
-
- return false;
- }
-
-
- if (collision_mesh.is_valid()) {
- Transform gt = spatial_node->get_global_transform();
-
- if (billboard_handle) {
- gt.set_look_at(gt.origin,gt.origin+p_camera->get_transform().basis.get_axis(2),p_camera->get_transform().basis.get_axis(1));
- }
-
- Transform ai=gt.affine_inverse();
- Vector3 ray_from = ai.xform(p_camera->project_ray_origin(p_point));
- Vector3 ray_dir=ai.basis.xform(p_camera->project_ray_normal(p_point)).normalized();
- Vector3 rpos,rnorm;
-
-#if 1
-
-
-
- if (collision_mesh->intersect_ray(ray_from,ray_dir,rpos,rnorm)) {
-
- r_pos=gt.xform(rpos);
- r_normal=gt.basis.xform(rnorm).normalized();
- return true;
- }
-#else
-
- if (collision_mesh->intersect_segment(ray_from,ray_from+ray_dir*4906.0,rpos,rnorm)) {
-
- r_pos=gt.xform(rpos);
- r_normal=gt.basis.xform(rnorm).normalized();
- return true;
- }
-
-#endif
- }
-
- return false;
-
-}
-
-
-
-void SpatialGizmoTool::create() {
-
- ERR_FAIL_COND(!spatial_node);
- ERR_FAIL_COND(valid);
- valid=true;
-
- for(int i=0;i<instances.size();i++) {
-
- instances[i].create_instance(spatial_node);
- }
-
- transform();
-
-}
-
-void SpatialGizmoTool::transform(){
-
- ERR_FAIL_COND(!spatial_node);
- ERR_FAIL_COND(!valid);
- for(int i=0;i<instances.size();i++) {
- VS::get_singleton()->instance_set_transform(instances[i].instance,spatial_node->get_global_transform());
- }
-
-}
-
-
-void SpatialGizmoTool::free(){
-
- ERR_FAIL_COND(!spatial_node);
- ERR_FAIL_COND(!valid);
-
- for(int i=0;i<instances.size();i++) {
-
- if (instances[i].instance.is_valid())
- VS::get_singleton()->free(instances[i].instance);
- instances[i].instance=RID();
- }
-
- valid=false;
-
-
-}
-
-
-
-SpatialGizmoTool::SpatialGizmoTool() {
- valid=false;
- billboard_handle=false;
-
-}
-
-SpatialGizmoTool::~SpatialGizmoTool(){
-
- clear();
-}
-
-Vector3 SpatialGizmoTool::get_handle_pos(int p_idx) const {
-
- ERR_FAIL_INDEX_V(p_idx,handles.size(),Vector3());
-
- return handles[p_idx];
-
-}
-
-//// light gizmo
-
-
-String LightSpatialGizmo::get_handle_name(int p_idx) const {
-
- if (p_idx==0)
- return "Radius";
- else
- return "Aperture";
-}
-
-
-Variant LightSpatialGizmo::get_handle_value(int p_idx) const{
-
- if (p_idx==0)
- return light->get_parameter(Light::PARAM_RADIUS);
- if (p_idx==1)
- return light->get_parameter(Light::PARAM_SPOT_ANGLE);
-
- return Variant();
-}
-
-
-static float _find_closest_angle_to_half_pi_arc(const Vector3& p_from, const Vector3& p_to, float p_arc_radius,const Transform& p_arc_xform) {
-
- //bleh, discrete is simpler
- static const int arc_test_points=64;
- float min_d = 1e20;
- Vector3 min_p;
-
-
- for(int i=0;i<arc_test_points;i++) {
-
- float a = i*Math_PI*0.5/arc_test_points;
- float an = (i+1)*Math_PI*0.5/arc_test_points;
- Vector3 p=Vector3( Math::cos(a), 0, -Math::sin(a) )*p_arc_radius;
- Vector3 n=Vector3( Math::cos(an), 0,- Math::sin(an) )*p_arc_radius;
-
- Vector3 ra,rb;
- Geometry::get_closest_points_between_segments(p,n,p_from,p_to,ra,rb);
-
- float d = ra.distance_to(rb);
- if (d<min_d) {
- min_d=d;
- min_p=ra;
- }
-
- }
-
- //min_p = p_arc_xform.affine_inverse().xform(min_p);
- float a = Vector2(min_p.x,-min_p.z).atan2();
- return a*180.0/Math_PI;
-}
-
-
-void LightSpatialGizmo::set_handle(int p_idx,Camera *p_camera, const Point2& p_point) {
-
- Transform gt = light->get_global_transform();
- gt.orthonormalize();
- Transform gi = gt.affine_inverse();
-
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
-
- Vector3 s[2]={gi.xform(ray_from),gi.xform(ray_from+ray_dir*4096)};
- if (p_idx==0) {
-
- if (light->cast_to<SpotLight>()) {
- Vector3 ra,rb;
- Geometry::get_closest_points_between_segments(Vector3(),Vector3(0,0,-4096),s[0],s[1],ra,rb);
-
- float d = -ra.z;
- if (d<0)
- d=0;
-
- light->set_parameter(Light::PARAM_RADIUS,d);
- } else if (light->cast_to<OmniLight>()) {
-
- Plane cp=Plane( gt.origin, p_camera->get_transform().basis.get_axis(2));
-
- Vector3 inters;
- if (cp.intersects_ray(ray_from,ray_dir,&inters)) {
-
- float r = inters.distance_to(gt.origin);
- light->set_parameter(Light::PARAM_RADIUS,r);
- }
-
- }
-
- } else if (p_idx==1) {
-
- float a = _find_closest_angle_to_half_pi_arc(s[0],s[1],light->get_parameter(Light::PARAM_RADIUS),gt);
- light->set_parameter(Light::PARAM_SPOT_ANGLE,CLAMP(a,0.01,89.99));
- }
-}
-
-void LightSpatialGizmo::commit_handle(int p_idx,const Variant& p_restore,bool p_cancel){
-
- if (p_cancel) {
-
- light->set_parameter(p_idx==0?Light::PARAM_RADIUS:Light::PARAM_SPOT_ANGLE,p_restore);
-
- } else if (p_idx==0) {
-
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- ur->create_action("Change Light Radius");
- ur->add_do_method(light,"set_parameter",Light::PARAM_RADIUS,light->get_parameter(Light::PARAM_RADIUS));
- ur->add_undo_method(light,"set_parameter",Light::PARAM_RADIUS,p_restore);
- ur->commit_action();
- } else if (p_idx==1) {
-
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- ur->create_action("Change Light Radius");
- ur->add_do_method(light,"set_parameter",Light::PARAM_SPOT_ANGLE,light->get_parameter(Light::PARAM_SPOT_ANGLE));
- ur->add_undo_method(light,"set_parameter",Light::PARAM_SPOT_ANGLE,p_restore);
- ur->commit_action();
-
- }
-}
-
-
-
-void LightSpatialGizmo::redraw() {
-
-
- if (light->cast_to<DirectionalLight>()) {
-
-
-
- const int arrow_points=5;
- Vector3 arrow[arrow_points]={
- Vector3(0,0,2),
- Vector3(1,1,2),
- Vector3(1,1,-1),
- Vector3(2,2,-1),
- Vector3(0,0,-3)
- };
-
- int arrow_sides=4;
-
- Vector<Vector3> lines;
-
-
- for(int i = 0; i < arrow_sides ; i++) {
-
-
- Matrix3 ma(Vector3(0,0,1),Math_PI*2*float(i)/arrow_sides);
- Matrix3 mb(Vector3(0,0,1),Math_PI*2*float(i+1)/arrow_sides);
-
-
- for(int j=1;j<arrow_points-1;j++) {
-
- if (j!=2) {
- lines.push_back(ma.xform(arrow[j]));
- lines.push_back(ma.xform(arrow[j+1]));
- }
- if (j<arrow_points-1) {
- lines.push_back(ma.xform(arrow[j]));
- lines.push_back(mb.xform(arrow[j]));
- }
-
- }
- }
-
- add_lines(lines,SpatialEditorGizmos::singleton->light_material);
- add_collision_segments(lines);
- add_unscaled_billboard(SpatialEditorGizmos::singleton->light_material_directional_icon,0.05);
-
- }
-
- if (light->cast_to<OmniLight>()) {
-
- clear();
-
-
- OmniLight *on = light->cast_to<OmniLight>();
-
- float r = on->get_parameter(Light::PARAM_RADIUS);
-
- Vector<Vector3> points;
-
- for(int i=0;i<=360;i++) {
-
- float ra=Math::deg2rad(i);
- float rb=Math::deg2rad(i+1);
- Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*r;
- Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*r;
-
- /*points.push_back(Vector3(a.x,0,a.y));
- points.push_back(Vector3(b.x,0,b.y));
- points.push_back(Vector3(0,a.x,a.y));
- points.push_back(Vector3(0,b.x,b.y));*/
- points.push_back(Vector3(a.x,a.y,0));
- points.push_back(Vector3(b.x,b.y,0));
-
- }
-
- add_lines(points,SpatialEditorGizmos::singleton->light_material,true);
- add_collision_segments(points);
-
- add_unscaled_billboard(SpatialEditorGizmos::singleton->light_material_omni_icon,0.05);
-
- Vector<Vector3> handles;
- handles.push_back(Vector3(r,0,0));
- add_handles(handles,true);
-
-
- }
-
-
- if (light->cast_to<SpotLight>()) {
-
- clear();
-
- Vector<Vector3> points;
- SpotLight *on = light->cast_to<SpotLight>();
-
- float r = on->get_parameter(Light::PARAM_RADIUS);
- float w = r*Math::sin(Math::deg2rad(on->get_parameter(Light::PARAM_SPOT_ANGLE)));
- float d = r*Math::cos(Math::deg2rad(on->get_parameter(Light::PARAM_SPOT_ANGLE)));
-
-
-
- for(int i=0;i<360;i++) {
-
- float ra=Math::deg2rad(i);
- float rb=Math::deg2rad(i+1);
- Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*w;
- Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*w;
-
- /*points.push_back(Vector3(a.x,0,a.y));
- points.push_back(Vector3(b.x,0,b.y));
- points.push_back(Vector3(0,a.x,a.y));
- points.push_back(Vector3(0,b.x,b.y));*/
- points.push_back(Vector3(a.x,a.y,-d));
- points.push_back(Vector3(b.x,b.y,-d));
-
- if (i%90==0) {
-
- points.push_back(Vector3(a.x,a.y,-d));
- points.push_back(Vector3());
-
- }
-
-
- }
-
- points.push_back(Vector3(0,0,-r));
- points.push_back(Vector3());
-
- add_lines(points,SpatialEditorGizmos::singleton->light_material);
-
- Vector<Vector3> handles;
- handles.push_back(Vector3(0,0,-r));
-
- Vector<Vector3> collision_segments;
-
- for(int i=0;i<64;i++) {
-
- float ra=i*Math_PI*2.0/64.0;
- float rb=(i+1)*Math_PI*2.0/64.0;
- Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*w;
- Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*w;
-
- collision_segments.push_back(Vector3(a.x,a.y,-d));
- collision_segments.push_back(Vector3(b.x,b.y,-d));
-
- if (i%16==0) {
-
- collision_segments.push_back(Vector3(a.x,a.y,-d));
- collision_segments.push_back(Vector3());
-
- }
-
- if (i==16) {
-
- handles.push_back(Vector3(a.x,a.y,-d));
- }
-
- }
-
- collision_segments.push_back(Vector3(0,0,-r));
- collision_segments.push_back(Vector3());
-
-
- add_handles(handles);
- add_collision_segments(collision_segments);
- add_unscaled_billboard(SpatialEditorGizmos::singleton->light_material_omni_icon,0.05);
-
- }
-
-}
-
-LightSpatialGizmo::LightSpatialGizmo(Light* p_light){
-
- light=p_light;
- set_spatial_node(p_light);
-
-}
-
-//////
-
-String CameraSpatialGizmo::get_handle_name(int p_idx) const {
-
- if (camera->get_projection()==Camera::PROJECTION_PERSPECTIVE) {
- return "FOV";
- } else {
- return "Size";
- }
-}
-Variant CameraSpatialGizmo::get_handle_value(int p_idx) const{
-
- if (camera->get_projection()==Camera::PROJECTION_PERSPECTIVE) {
- return camera->get_fov();
- } else {
-
- return camera->get_size();
- }
-}
-void CameraSpatialGizmo::set_handle(int p_idx,Camera *p_camera, const Point2& p_point){
-
- Transform gt = camera->get_global_transform();
- gt.orthonormalize();
- Transform gi = gt.affine_inverse();
-
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
-
- Vector3 s[2]={gi.xform(ray_from),gi.xform(ray_from+ray_dir*4096)};
-
- if (camera->get_projection()==Camera::PROJECTION_PERSPECTIVE) {
- Transform gt=camera->get_global_transform();
- float a = _find_closest_angle_to_half_pi_arc(s[0],s[1],1.0,gt);
- camera->set("fov",a);
- } else {
-
- Vector3 ra,rb;
- Geometry::get_closest_points_between_segments(Vector3(0,0,-1),Vector3(4096,0,-1),s[0],s[1],ra,rb);
- float d = ra.x * 2.0;
- if (d<0)
- d=0;
-
- camera->set("size",d);
- }
-
-}
-void CameraSpatialGizmo::commit_handle(int p_idx,const Variant& p_restore,bool p_cancel){
-
- if (camera->get_projection()==Camera::PROJECTION_PERSPECTIVE) {
-
- if (p_cancel) {
-
- camera->set("fov",p_restore);
- } else {
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- ur->create_action("Change Camera FOV");
- ur->add_do_property(camera,"fov",camera->get_fov());
- ur->add_undo_property(camera,"fov",p_restore);
- ur->commit_action();
- }
-
- } else {
-
- if (p_cancel) {
-
- camera->set("size",p_restore);
- } else {
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- ur->create_action("Change Camera Size");
- ur->add_do_property(camera,"size",camera->get_size());
- ur->add_undo_property(camera,"size",p_restore);
- ur->commit_action();
- }
-
- }
-
-}
-
-void CameraSpatialGizmo::redraw(){
-
- clear();
-
- Vector<Vector3> lines;
- Vector<Vector3> handles;
-
-
- switch(camera->get_projection()) {
-
- case Camera::PROJECTION_PERSPECTIVE: {
-
- float fov = camera->get_fov();
-
- Vector3 side=Vector3( Math::sin(Math::deg2rad(fov)), 0, -Math::cos(Math::deg2rad(fov)) );
- Vector3 nside=side;
- nside.x=-nside.x;
- Vector3 up=Vector3(0,side.x,0);
-
-
-#define ADD_TRIANGLE( m_a, m_b, m_c)\
-{\
- lines.push_back(m_a);\
- lines.push_back(m_b);\
- lines.push_back(m_b);\
- lines.push_back(m_c);\
- lines.push_back(m_c);\
- lines.push_back(m_a);\
-}
-
- ADD_TRIANGLE( Vector3(), side+up, side-up );
- ADD_TRIANGLE( Vector3(), nside+up, nside-up );
- ADD_TRIANGLE( Vector3(), side+up, nside+up );
- ADD_TRIANGLE( Vector3(), side-up, nside-up );
-
- handles.push_back(side);
- side.x*=0.25;
- nside.x*=0.25;
- Vector3 tup( 0, up.y*3/2,side.z);
- ADD_TRIANGLE( tup, side+up, nside+up );
-
- } break;
- case Camera::PROJECTION_ORTHOGONAL: {
-
-#define ADD_QUAD( m_a, m_b, m_c, m_d)\
-{\
- lines.push_back(m_a);\
- lines.push_back(m_b);\
- lines.push_back(m_b);\
- lines.push_back(m_c);\
- lines.push_back(m_c);\
- lines.push_back(m_d);\
- lines.push_back(m_d);\
- lines.push_back(m_a);\
-}
- float size = camera->get_size();
-
- float hsize=size*0.5;
- Vector3 right(hsize,0,0);
- Vector3 up(0,hsize,0);
- Vector3 back(0,0,-1.0);
- Vector3 front(0,0,0);
-
- ADD_QUAD( -up-right,-up+right,up+right,up-right);
- ADD_QUAD( -up-right+back,-up+right+back,up+right+back,up-right+back);
- ADD_QUAD( up+right,up+right+back,up-right+back,up-right);
- ADD_QUAD( -up+right,-up+right+back,-up-right+back,-up-right);
- handles.push_back(right+back);
-
- right.x*=0.25;
- Vector3 tup( 0, up.y*3/2,back.z );
- ADD_TRIANGLE( tup, right+up+back, -right+up+back );
-
- } break;
-
- }
-
- add_lines(lines,SpatialEditorGizmos::singleton->camera_material);
- add_collision_segments(lines);
- add_handles(handles);
-}
-
-
-CameraSpatialGizmo::CameraSpatialGizmo(Camera* p_camera){
-
- camera=p_camera;
- set_spatial_node(camera);
-}
-
-
-
-
-//////
-
-void MeshInstanceSpatialGizmo::redraw() {
-
- Ref<Mesh> m = mesh->get_mesh();
- if (!m.is_valid())
- return; //none
-
- Ref<TriangleMesh> tm = m->generate_triangle_mesh();
- if (tm.is_valid())
- add_collision_triangles(tm);
-}
-
-MeshInstanceSpatialGizmo::MeshInstanceSpatialGizmo(MeshInstance* p_mesh) {
-
- mesh=p_mesh;
- set_spatial_node(p_mesh);
-}
-
-/////
-
-
-void Position3DSpatialGizmo::redraw() {
-
- clear();
- add_mesh(SpatialEditorGizmos::singleton->pos3d_mesh);
- Vector<Vector3> cursor_points;
- float cs = 0.25;
- cursor_points.push_back(Vector3(+cs,0,0));
- cursor_points.push_back(Vector3(-cs,0,0));
- cursor_points.push_back(Vector3(0,+cs,0));
- cursor_points.push_back(Vector3(0,-cs,0));
- cursor_points.push_back(Vector3(0,0,+cs));
- cursor_points.push_back(Vector3(0,0,-cs));
- add_collision_segments(cursor_points);
-
-}
-
-
-Position3DSpatialGizmo::Position3DSpatialGizmo(Position3D* p_p3d) {
-
- p3d=p_p3d;
- set_spatial_node(p3d);
-}
-
-
-/////
-
-void SkeletonSpatialGizmo::redraw() {
-
- clear();
-
- Ref<SurfaceTool> surface_tool( memnew( SurfaceTool ));
-
-
- surface_tool->begin(Mesh::PRIMITIVE_LINES);
- surface_tool->set_material(SpatialEditorGizmos::singleton->skeleton_material);
- Vector<Transform> grests;
- grests.resize(skel->get_bone_count());
-
- Vector<int> bones;
- Vector<float> weights;
- bones.resize(4);
- weights.resize(4);
-
- for(int i=0;i<4;i++) {
- bones[i]=0;
- weights[i]=0;
- }
-
- weights[0]=1;
-
-
- AABB aabb;
-
- Color bonecolor = Color(1.0,0.4,0.4,0.3);
- Color rootcolor = Color(0.4,1.0,0.4,0.1);
-
- for (int i=0;i<skel->get_bone_count();i++) {
-
- int parent = skel->get_bone_parent(i);
-
- if (parent>=0) {
- grests[i]=grests[parent] * skel->get_bone_rest(i);
-
- Vector3 v0 = grests[parent].origin;
- Vector3 v1 = grests[i].origin;
- Vector3 d = (v1-v0).normalized();
- float dist = v0.distance_to(v1);
-
- //find closest axis
- int closest=-1;
- float closest_d = 0.0;
-
- for(int j=0;j<3;j++) {
- float dp = Math::abs(grests[parent].basis[j].normalized().dot(d));
- if (j==0 || dp>closest_d)
- closest=j;
- }
-
- //find closest other
- Vector3 first;
- Vector3 points[4];
- int pointidx=0;
- for(int j=0;j<3;j++) {
-
- bones[0]=parent;
- surface_tool->add_bones(bones);
- surface_tool->add_weights(weights);
- surface_tool->add_color(rootcolor);
- surface_tool->add_vertex(v0-grests[parent].basis[j].normalized()*dist*0.05);
- surface_tool->add_bones(bones);
- surface_tool->add_weights(weights);
- surface_tool->add_color(rootcolor);
- surface_tool->add_vertex(v0+grests[parent].basis[j].normalized()*dist*0.05);
-
- if (j==closest)
- continue;
-
- Vector3 axis;
- if (first==Vector3()) {
- axis = d.cross(d.cross(grests[parent].basis[j])).normalized();
- first=axis;
- } else {
- axis = d.cross(first).normalized();
- }
-
- for(int k=0;k<2;k++) {
-
- if (k==1)
- axis=-axis;
- Vector3 point = v0+d*dist*0.2;
- point+=axis*dist*0.1;
-
-
- bones[0]=parent;
- surface_tool->add_bones(bones);
- surface_tool->add_weights(weights);
- surface_tool->add_color(bonecolor);
- surface_tool->add_vertex(v0);
- surface_tool->add_bones(bones);
- surface_tool->add_weights(weights);
- surface_tool->add_color(bonecolor);
- surface_tool->add_vertex(point);
-
- bones[0]=parent;
- surface_tool->add_bones(bones);
- surface_tool->add_weights(weights);
- surface_tool->add_color(bonecolor);
- surface_tool->add_vertex(point);
- bones[0]=i;
- surface_tool->add_bones(bones);
- surface_tool->add_weights(weights);
- surface_tool->add_color(bonecolor);
- surface_tool->add_vertex(v1);
- points[pointidx++]=point;
-
- }
-
- }
-
- SWAP( points[1],points[2] );
- for(int j=0;j<4;j++) {
-
-
- bones[0]=parent;
- surface_tool->add_bones(bones);
- surface_tool->add_weights(weights);
- surface_tool->add_color(bonecolor);
- surface_tool->add_vertex(points[j]);
- surface_tool->add_bones(bones);
- surface_tool->add_weights(weights);
- surface_tool->add_color(bonecolor);
- surface_tool->add_vertex(points[(j+1)%4]);
- }
-
-
-/*
- bones[0]=parent;
- surface_tool->add_bones(bones);
- surface_tool->add_weights(weights);
- surface_tool->add_color(Color(0.4,1,0.4,0.4));
- surface_tool->add_vertex(v0);
- bones[0]=i;
- surface_tool->add_bones(bones);
- surface_tool->add_weights(weights);
- surface_tool->add_color(Color(0.4,1,0.4,0.4));
- surface_tool->add_vertex(v1);
-*/
- } else {
-
- grests[i]=skel->get_bone_rest(i);
- bones[0]=i;
- }
-/*
- Transform t = grests[i];
- t.orthonormalize();
-
- for (int i=0;i<6;i++) {
-
-
- Vector3 face_points[4];
-
- for (int j=0;j<4;j++) {
-
- float v[3];
- v[0]=1.0;
- v[1]=1-2*((j>>1)&1);
- v[2]=v[1]*(1-2*(j&1));
-
- for (int k=0;k<3;k++) {
-
- if (i<3)
- face_points[j][(i+k)%3]=v[k]*(i>=3?-1:1);
- else
- face_points[3-j][(i+k)%3]=v[k]*(i>=3?-1:1);
- }
- }
-
- for(int j=0;j<4;j++) {
- surface_tool->add_bones(bones);
- surface_tool->add_weights(weights);
- surface_tool->add_color(Color(1.0,0.4,0.4,0.4));
- surface_tool->add_vertex(t.xform(face_points[j]*0.04));
- surface_tool->add_bones(bones);
- surface_tool->add_weights(weights);
- surface_tool->add_color(Color(1.0,0.4,0.4,0.4));
- surface_tool->add_vertex(t.xform(face_points[(j+1)%4]*0.04));
- }
-
- }
- */
- }
-
- Ref<Mesh> m = surface_tool->commit();
- add_mesh(m,false,skel->get_skeleton());
-
-}
-
-SkeletonSpatialGizmo::SkeletonSpatialGizmo(Skeleton* p_skel) {
-
- skel=p_skel;
- set_spatial_node(p_skel);
-}
-
-/////
-
-
-void SpatialPlayerSpatialGizmo::redraw() {
-
- clear();
- if (splayer->cast_to<SpatialStreamPlayer>()) {
-
- add_unscaled_billboard(SpatialEditorGizmos::singleton->stream_player_icon,0.05);
-
- } else if (splayer->cast_to<SpatialSamplePlayer>()) {
-
- add_unscaled_billboard(SpatialEditorGizmos::singleton->sample_player_icon,0.05);
-
- }
-
-}
-
-SpatialPlayerSpatialGizmo::SpatialPlayerSpatialGizmo(SpatialPlayer* p_splayer){
-
- set_spatial_node(p_splayer);
- splayer=p_splayer;
-}
-
-
-/////
-
-
-void RoomSpatialGizmo::redraw() {
-
- clear();
- Ref<RoomBounds> roomie = room->get_room();
- if (roomie.is_null())
- return;
- DVector<Face3> faces = roomie->get_geometry_hint();
-
- Vector<Vector3> lines;
- int fc=faces.size();
- DVector<Face3>::Read r =faces.read();
-
- Map<_EdgeKey,Vector3> edge_map;
-
- for(int i=0;i<fc;i++) {
-
- Vector3 fn = r[i].get_plane().normal;
-
- for(int j=0;j<3;j++) {
-
- _EdgeKey ek;
- ek.from=r[i].vertex[j].snapped(CMP_EPSILON);
- ek.to=r[i].vertex[(j+1)%3].snapped(CMP_EPSILON);
- if (ek.from<ek.to)
- SWAP(ek.from,ek.to);
-
- Map<_EdgeKey,Vector3>::Element *E=edge_map.find(ek);
-
- if (E) {
-
- if (E->get().dot(fn) >0.9) {
-
- E->get()=Vector3();
- }
-
- } else {
-
- edge_map[ek]=fn;
- }
-
- }
- }
-
- for(Map<_EdgeKey,Vector3>::Element *E=edge_map.front();E;E=E->next()) {
-
- if (E->get()!=Vector3()) {
- lines.push_back(E->key().from);
- lines.push_back(E->key().to);
- }
- }
-
- add_lines(lines,SpatialEditorGizmos::singleton->room_material);
- add_collision_segments(lines);
-
-}
-
-RoomSpatialGizmo::RoomSpatialGizmo(Room* p_room){
-
- set_spatial_node(p_room);
- room=p_room;
-}
-
-/////
-
-
-void PortalSpatialGizmo::redraw() {
-
- clear();
-
- Vector<Point2> points = portal->get_shape();
- if (points.size()==0) {
- return;
- }
-
- Vector<Vector3> lines;
-
- Vector3 center;
- for(int i=0;i<points.size();i++) {
-
- Vector3 f;
- f.x=points[i].x;
- f.y=points[i].y;
- Vector3 fn;
- fn.x=points[(i+1)%points.size()].x;
- fn.y=points[(i+1)%points.size()].y;
- center+=f;
-
- lines.push_back(f);
- lines.push_back(fn);
- }
-
- center/=points.size();
- lines.push_back(center);
- lines.push_back(center+Vector3(0,0,1));
-
- add_lines(lines,SpatialEditorGizmos::singleton->portal_material);
- add_collision_segments(lines);
-
-}
-
-PortalSpatialGizmo::PortalSpatialGizmo(Portal* p_portal){
-
- set_spatial_node(p_portal);
- portal=p_portal;
-}
-
-/////
-
-
-void RayCastSpatialGizmo::redraw() {
-
- clear();
-
-
- Vector<Vector3> lines;
-
- lines.push_back(Vector3());
- lines.push_back(raycast->get_cast_to());
-
- add_lines(lines,SpatialEditorGizmos::singleton->raycast_material);
- add_collision_segments(lines);
-
-}
-
-RayCastSpatialGizmo::RayCastSpatialGizmo(RayCast* p_raycast){
-
- set_spatial_node(p_raycast);
- raycast=p_raycast;
-}
-
-
-
-/////
-
-
-void VehicleWheelSpatialGizmo::redraw() {
-
- clear();
-
-
- Vector<Vector3> points;
-
- float r = car_wheel->get_radius();
- const int skip=10;
- for(int i=0;i<=360;i+=skip) {
-
- float ra=Math::deg2rad(i);
- float rb=Math::deg2rad(i+skip);
- Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*r;
- Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*r;
-
- points.push_back(Vector3(0,a.x,a.y));
- points.push_back(Vector3(0,b.x,b.y));
-
- const int springsec=4;
-
- for(int j=0;j<springsec;j++) {
- float t = car_wheel->get_suspension_rest_length()*5;
- points.push_back(Vector3(a.x,i/360.0*t/springsec+j*(t/springsec),a.y)*0.2);
- points.push_back(Vector3(b.x,(i+skip)/360.0*t/springsec+j*(t/springsec),b.y)*0.2);
- }
-
-
- }
-
- //travel
- points.push_back(Vector3(0,0,0));
- points.push_back(Vector3(0,car_wheel->get_suspension_rest_length(),0));
-
- //axis
- points.push_back(Vector3(r*0.2,car_wheel->get_suspension_rest_length(),0));
- points.push_back(Vector3(-r*0.2,car_wheel->get_suspension_rest_length(),0));
- //axis
- points.push_back(Vector3(r*0.2,0,0));
- points.push_back(Vector3(-r*0.2,0,0));
-
- //forward line
- points.push_back(Vector3(0,-r,0));
- points.push_back(Vector3(0,-r,r*2));
- points.push_back(Vector3(0,-r,r*2));
- points.push_back(Vector3(r*2*0.2,-r,r*2*0.8));
- points.push_back(Vector3(0,-r,r*2));
- points.push_back(Vector3(-r*2*0.2,-r,r*2*0.8));
-
- add_lines(points,SpatialEditorGizmos::singleton->car_wheel_material);
- add_collision_segments(points);
-
-}
-
-VehicleWheelSpatialGizmo::VehicleWheelSpatialGizmo(VehicleWheel* p_car_wheel){
-
- set_spatial_node(p_car_wheel);
- car_wheel=p_car_wheel;
-}
-
-
-
-///
-
-void TestCubeSpatialGizmo::redraw() {
-
- clear();
- add_collision_triangles(SpatialEditorGizmos::singleton->test_cube_tm);
-}
-
-TestCubeSpatialGizmo::TestCubeSpatialGizmo(TestCube* p_tc) {
-
- tc=p_tc;
- set_spatial_node(p_tc);
-}
-
-
-///////////
-
-
-
-
-
-
-String CollisionShapeSpatialGizmo::get_handle_name(int p_idx) const {
-
- Ref<Shape> s = cs->get_shape();
- if (s.is_null())
- return "";
-
- if (s->cast_to<SphereShape>()) {
-
- return "Radius";
- }
-
- if (s->cast_to<BoxShape>()) {
-
- return "Extents";
- }
-
- if (s->cast_to<CapsuleShape>()) {
-
- return p_idx==0?"Radius":"Height";
- }
-
- if (s->cast_to<RayShape>()) {
-
- return "Length";
- }
-
- return "";
-}
-Variant CollisionShapeSpatialGizmo::get_handle_value(int p_idx) const{
-
- Ref<Shape> s = cs->get_shape();
- if (s.is_null())
- return Variant();
-
- if (s->cast_to<SphereShape>()) {
-
- Ref<SphereShape> ss = s;
- return ss->get_radius();
- }
-
- if (s->cast_to<BoxShape>()) {
-
- Ref<BoxShape> bs = s;
- return bs->get_extents();
- }
-
- if (s->cast_to<CapsuleShape>()) {
-
- Ref<CapsuleShape> cs = s;
- return p_idx==0?cs->get_radius():cs->get_height();
- }
-
- if (s->cast_to<RayShape>()) {
-
- Ref<RayShape> cs = s;
- return cs->get_length();
- }
-
- return Variant();
-}
-void CollisionShapeSpatialGizmo::set_handle(int p_idx,Camera *p_camera, const Point2& p_point){
- Ref<Shape> s = cs->get_shape();
- if (s.is_null())
- return;
-
- Transform gt = cs->get_global_transform();
- gt.orthonormalize();
- Transform gi = gt.affine_inverse();
-
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
-
- Vector3 sg[2]={gi.xform(ray_from),gi.xform(ray_from+ray_dir*4096)};
-
- if (s->cast_to<SphereShape>()) {
-
- Ref<SphereShape> ss = s;
- Vector3 ra,rb;
- Geometry::get_closest_points_between_segments(Vector3(),Vector3(4096,0,0),sg[0],sg[1],ra,rb);
- float d = ra.x;
- if (d<0.001)
- d=0.001;
-
- ss->set_radius(d);
- }
-
- if (s->cast_to<RayShape>()) {
-
- Ref<RayShape> rs = s;
- Vector3 ra,rb;
- Geometry::get_closest_points_between_segments(Vector3(),Vector3(0,0,4096),sg[0],sg[1],ra,rb);
- float d = ra.z;
- if (d<0.001)
- d=0.001;
-
- rs->set_length(d);
- }
-
-
- if (s->cast_to<BoxShape>()) {
-
- Vector3 axis;
- axis[p_idx]=1.0;
- Ref<BoxShape> bs = s;
- Vector3 ra,rb;
- Geometry::get_closest_points_between_segments(Vector3(),axis*4096,sg[0],sg[1],ra,rb);
- float d = ra[p_idx];
- if (d<0.001)
- d=0.001;
-
- Vector3 he = bs->get_extents();
- he[p_idx]=d;
- bs->set_extents(he);
-
- }
-
- if (s->cast_to<CapsuleShape>()) {
-
- Vector3 axis;
- axis[p_idx==0?0:2]=1.0;
- Ref<CapsuleShape> cs = s;
- Vector3 ra,rb;
- Geometry::get_closest_points_between_segments(Vector3(),axis*4096,sg[0],sg[1],ra,rb);
- float d = axis.dot(ra);
- if (p_idx==1)
- d-=cs->get_radius();
- if (d<0.001)
- d=0.001;
-
- if (p_idx==0)
- cs->set_radius(d);
- else if (p_idx==1)
- cs->set_height(d*2.0);
-
- }
-
-}
-void CollisionShapeSpatialGizmo::commit_handle(int p_idx,const Variant& p_restore,bool p_cancel){
- Ref<Shape> s = cs->get_shape();
- if (s.is_null())
- return;
-
- if (s->cast_to<SphereShape>()) {
-
- Ref<SphereShape> ss=s;
- if (p_cancel) {
- ss->set_radius(p_restore);
- return;
- }
-
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- ur->create_action("Change Sphere Shape Radius");
- ur->add_do_method(ss.ptr(),"set_radius",ss->get_radius());
- ur->add_undo_method(ss.ptr(),"set_radius",p_restore);
- ur->commit_action();
-
- }
-
- if (s->cast_to<BoxShape>()) {
-
- Ref<BoxShape> ss=s;
- if (p_cancel) {
- ss->set_extents(p_restore);
- return;
- }
-
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- ur->create_action("Change Box Shape Extents");
- ur->add_do_method(ss.ptr(),"set_extents",ss->get_extents());
- ur->add_undo_method(ss.ptr(),"set_extents",p_restore);
- ur->commit_action();
- }
-
- if (s->cast_to<CapsuleShape>()) {
-
- Ref<CapsuleShape> ss=s;
- if (p_cancel) {
- if (p_idx==0)
- ss->set_radius(p_restore);
- else
- ss->set_height(p_restore);
- return;
- }
-
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- if (p_idx==0) {
- ur->create_action("Change Capsule Shape Radius");
- ur->add_do_method(ss.ptr(),"set_radius",ss->get_radius());
- ur->add_undo_method(ss.ptr(),"set_radius",p_restore);
- } else {
- ur->create_action("Change Capsule Shape Height");
- ur->add_do_method(ss.ptr(),"set_height",ss->get_height());
- ur->add_undo_method(ss.ptr(),"set_height",p_restore);
-
- }
-
- ur->commit_action();
-
- }
-
- if (s->cast_to<RayShape>()) {
-
- Ref<RayShape> ss=s;
- if (p_cancel) {
- ss->set_length(p_restore);
- return;
- }
-
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- ur->create_action("Change Ray Shape Length");
- ur->add_do_method(ss.ptr(),"set_length",ss->get_length());
- ur->add_undo_method(ss.ptr(),"set_length",p_restore);
- ur->commit_action();
-
- }
-
-}
-void CollisionShapeSpatialGizmo::redraw(){
-
- clear();
-
- Ref<Shape> s = cs->get_shape();
- if (s.is_null())
- return;
-
- if (s->cast_to<SphereShape>()) {
-
- Ref<SphereShape> sp= s;
- float r=sp->get_radius();
-
- Vector<Vector3> points;
-
- for(int i=0;i<=360;i++) {
-
- float ra=Math::deg2rad(i);
- float rb=Math::deg2rad(i+1);
- Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*r;
- Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*r;
-
- points.push_back(Vector3(a.x,0,a.y));
- points.push_back(Vector3(b.x,0,b.y));
- points.push_back(Vector3(0,a.x,a.y));
- points.push_back(Vector3(0,b.x,b.y));
- points.push_back(Vector3(a.x,a.y,0));
- points.push_back(Vector3(b.x,b.y,0));
-
- }
-
- Vector<Vector3> collision_segments;
-
- for(int i=0;i<64;i++) {
-
- float ra=i*Math_PI*2.0/64.0;
- float rb=(i+1)*Math_PI*2.0/64.0;
- Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*r;
- Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*r;
-
- collision_segments.push_back(Vector3(a.x,0,a.y));
- collision_segments.push_back(Vector3(b.x,0,b.y));
- collision_segments.push_back(Vector3(0,a.x,a.y));
- collision_segments.push_back(Vector3(0,b.x,b.y));
- collision_segments.push_back(Vector3(a.x,a.y,0));
- collision_segments.push_back(Vector3(b.x,b.y,0));
- }
-
- add_lines(points,SpatialEditorGizmos::singleton->shape_material);
- add_collision_segments(collision_segments);
- Vector<Vector3> handles;
- handles.push_back(Vector3(r,0,0));
- add_handles(handles);
-
- }
-
- if (s->cast_to<BoxShape>()) {
-
- Ref<BoxShape> bs=s;
- Vector<Vector3> lines;
- AABB aabb;
- aabb.pos=-bs->get_extents();
- aabb.size=aabb.pos*-2;
-
- for(int i=0;i<12;i++) {
- Vector3 a,b;
- aabb.get_edge(i,a,b);
- lines.push_back(a);
- lines.push_back(b);
- }
-
- Vector<Vector3> handles;
-
- for(int i=0;i<3;i++) {
-
- Vector3 ax;
- ax[i]=bs->get_extents()[i];
- handles.push_back(ax);
- }
-
- add_lines(lines,SpatialEditorGizmos::singleton->shape_material);
- add_collision_segments(lines);
- add_handles(handles);
-
- }
-
- if (s->cast_to<CapsuleShape>()) {
-
- Ref<CapsuleShape> cs=s;
- float radius = cs->get_radius();
- float height = cs->get_height();
-
-
- Vector<Vector3> points;
-
- Vector3 d(0,0,height*0.5);
- for(int i=0;i<360;i++) {
-
- float ra=Math::deg2rad(i);
- float rb=Math::deg2rad(i+1);
- Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*radius;
- Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*radius;
-
- points.push_back(Vector3(a.x,a.y,0)+d);
- points.push_back(Vector3(b.x,b.y,0)+d);
-
- points.push_back(Vector3(a.x,a.y,0)-d);
- points.push_back(Vector3(b.x,b.y,0)-d);
-
- if (i%90==0) {
-
- points.push_back(Vector3(a.x,a.y,0)+d);
- points.push_back(Vector3(a.x,a.y,0)-d);
- }
-
- Vector3 dud = i<180?d:-d;
-
- points.push_back(Vector3(0,a.y,a.x)+dud);
- points.push_back(Vector3(0,b.y,b.x)+dud);
- points.push_back(Vector3(a.y,0,a.x)+dud);
- points.push_back(Vector3(b.y,0,b.x)+dud);
-
- }
-
- add_lines(points,SpatialEditorGizmos::singleton->shape_material);
-
- Vector<Vector3> collision_segments;
-
- for(int i=0;i<64;i++) {
-
- float ra=i*Math_PI*2.0/64.0;
- float rb=(i+1)*Math_PI*2.0/64.0;
- Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*radius;
- Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*radius;
-
- collision_segments.push_back(Vector3(a.x,a.y,0)+d);
- collision_segments.push_back(Vector3(b.x,b.y,0)+d);
-
- collision_segments.push_back(Vector3(a.x,a.y,0)-d);
- collision_segments.push_back(Vector3(b.x,b.y,0)-d);
-
- if (i%16==0) {
-
- collision_segments.push_back(Vector3(a.x,a.y,0)+d);
- collision_segments.push_back(Vector3(a.x,a.y,0)-d);
- }
-
- Vector3 dud = i<32?d:-d;
-
- collision_segments.push_back(Vector3(0,a.y,a.x)+dud);
- collision_segments.push_back(Vector3(0,b.y,b.x)+dud);
- collision_segments.push_back(Vector3(a.y,0,a.x)+dud);
- collision_segments.push_back(Vector3(b.y,0,b.x)+dud);
-
- }
-
- add_collision_segments(collision_segments);
-
- Vector<Vector3> handles;
- handles.push_back(Vector3(cs->get_radius(),0,0));
- handles.push_back(Vector3(0,0,cs->get_height()*0.5+cs->get_radius()));
- add_handles(handles);
-
-
- }
-
- if (s->cast_to<PlaneShape>()) {
-
- Ref<PlaneShape> ps=s;
- Plane p = ps->get_plane();
- Vector<Vector3> points;
-
- Vector3 n1 = p.get_any_perpendicular_normal();
- Vector3 n2 = p.normal.cross(n1).normalized();
-
- Vector3 pface[4]={
- p.normal*p.d+n1*10.0+n2*10.0,
- p.normal*p.d+n1*10.0+n2*-10.0,
- p.normal*p.d+n1*-10.0+n2*-10.0,
- p.normal*p.d+n1*-10.0+n2*10.0,
- };
-
- points.push_back(pface[0]);
- points.push_back(pface[1]);
- points.push_back(pface[1]);
- points.push_back(pface[2]);
- points.push_back(pface[2]);
- points.push_back(pface[3]);
- points.push_back(pface[3]);
- points.push_back(pface[0]);
- points.push_back(p.normal*p.d);
- points.push_back(p.normal*p.d+p.normal*3);
-
- add_lines(points,SpatialEditorGizmos::singleton->shape_material);
- add_collision_segments(points);
-
- }
-
-
- if (s->cast_to<ConvexPolygonShape>()) {
-
- DVector<Vector3> points = s->cast_to<ConvexPolygonShape>()->get_points();
-
- if (points.size()>3) {
-
- QuickHull qh;
- Vector<Vector3> varr = Variant(points);
- Geometry::MeshData md;
- Error err = qh.build(varr,md);
- if (err==OK) {
- Vector<Vector3> points;
- points.resize(md.edges.size()*2);
- for(int i=0;i<md.edges.size();i++) {
- points[i*2+0]=md.vertices[md.edges[i].a];
- points[i*2+1]=md.vertices[md.edges[i].b];
- }
-
-
- add_lines(points,SpatialEditorGizmos::singleton->shape_material);
- add_collision_segments(points);
-
- }
- }
-
- }
-
-
- if (s->cast_to<RayShape>()) {
-
- Ref<RayShape> rs=s;
-
- Vector<Vector3> points;
- points.push_back(Vector3());
- points.push_back(Vector3(0,0,rs->get_length()));
- add_lines(points,SpatialEditorGizmos::singleton->shape_material);
- add_collision_segments(points);
- Vector<Vector3> handles;
- handles.push_back(Vector3(0,0,rs->get_length()));
- add_handles(handles);
-
-
- }
-
-}
-CollisionShapeSpatialGizmo::CollisionShapeSpatialGizmo(CollisionShape* p_cs) {
-
- cs=p_cs;
- set_spatial_node(p_cs);
-}
-
-
-
-/////
-
-
-void CollisionPolygonSpatialGizmo::redraw() {
-
- clear();
-
- Vector<Vector2> points = polygon->get_polygon();
- float depth = polygon->get_depth()*0.5;
-
- Vector<Vector3> lines;
- for(int i=0;i<points.size();i++) {
-
- int n = (i+1)%points.size();
- lines.push_back(Vector3(points[i].x,points[i].y,depth));
- lines.push_back(Vector3(points[n].x,points[n].y,depth));
- lines.push_back(Vector3(points[i].x,points[i].y,-depth));
- lines.push_back(Vector3(points[n].x,points[n].y,-depth));
- lines.push_back(Vector3(points[i].x,points[i].y,depth));
- lines.push_back(Vector3(points[i].x,points[i].y,-depth));
-
- }
-
- add_lines(lines,SpatialEditorGizmos::singleton->shape_material);
- add_collision_segments(lines);
-}
-
-CollisionPolygonSpatialGizmo::CollisionPolygonSpatialGizmo(CollisionPolygon* p_polygon){
-
- set_spatial_node(p_polygon);
- polygon=p_polygon;
-}
-///
-
-
-String VisibilityNotifierGizmo::get_handle_name(int p_idx) const {
-
- switch(p_idx) {
- case 0: return "X";
- case 1: return "Y";
- case 2: return "Z";
- }
-
- return "";
-}
-Variant VisibilityNotifierGizmo::get_handle_value(int p_idx) const{
-
- return notifier->get_aabb();
-}
-void VisibilityNotifierGizmo::set_handle(int p_idx,Camera *p_camera, const Point2& p_point){
-
-
- Transform gt = notifier->get_global_transform();
- //gt.orthonormalize();
- Transform gi = gt.affine_inverse();
-
- AABB aabb = notifier->get_aabb();
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
-
- Vector3 sg[2]={gi.xform(ray_from),gi.xform(ray_from+ray_dir*4096)};
- Vector3 ofs = aabb.pos+aabb.size*0.5;;
-
- Vector3 axis;
- axis[p_idx]=1.0;
-
- Vector3 ra,rb;
- Geometry::get_closest_points_between_segments(ofs,ofs+axis*4096,sg[0],sg[1],ra,rb);
- float d = ra[p_idx];
- if (d<0.001)
- d=0.001;
-
- Vector3 he = aabb.size;
- aabb.pos[p_idx]=(aabb.pos[p_idx]+aabb.size[p_idx]*0.5)-d;
- aabb.size[p_idx]=d*2;
- notifier->set_aabb(aabb);
-}
-
-void VisibilityNotifierGizmo::commit_handle(int p_idx,const Variant& p_restore,bool p_cancel){
-
-
- if (p_cancel) {
- notifier->set_aabb(p_restore);
- return;
- }
-
- UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
- ur->create_action("Change Notifier Extents");
- ur->add_do_method(notifier,"set_aabb",notifier->get_aabb());
- ur->add_undo_method(notifier,"set_aabb",p_restore);
- ur->commit_action();
-
-}
-
-void VisibilityNotifierGizmo::redraw(){
-
- clear();
-
- Vector<Vector3> lines;
- AABB aabb = notifier->get_aabb();
-
- for(int i=0;i<12;i++) {
- Vector3 a,b;
- aabb.get_edge(i,a,b);
- lines.push_back(a);
- lines.push_back(b);
- }
-
- Vector<Vector3> handles;
-
-
- for(int i=0;i<3;i++) {
-
- Vector3 ax;
- ax[i]=aabb.pos[i]+aabb.size[i];
- handles.push_back(ax);
- }
-
- add_lines(lines,SpatialEditorGizmos::singleton->visibility_notifier_material);
- //add_unscaled_billboard(SpatialEditorGizmos::singleton->visi,0.05);
- add_collision_segments(lines);
- add_handles(handles);
-
-}
-VisibilityNotifierGizmo::VisibilityNotifierGizmo(VisibilityNotifier* p_notifier){
-
- notifier=p_notifier;
- set_spatial_node(p_notifier);
-}
-
-////////
-
-
-
-void NavigationMeshSpatialGizmo::redraw() {
-
- clear();
- Ref<NavigationMesh> navmeshie = navmesh->get_navigation_mesh();
- if (navmeshie.is_null())
- return;
-
- DVector<Vector3> vertices = navmeshie->get_vertices();
- DVector<Vector3>::Read vr=vertices.read();
- List<Face3> faces;
- for(int i=0;i<navmeshie->get_polygon_count();i++) {
- Vector<int> p = navmeshie->get_polygon(i);
-
- for(int j=2;j<p.size();j++) {
- Face3 f;
- f.vertex[0]=vr[p[0]];
- f.vertex[1]=vr[p[j-1]];
- f.vertex[2]=vr[p[j]];
-
- faces.push_back(f);
- }
- }
-
-
- Map<_EdgeKey,bool> edge_map;
- DVector<Vector3> tmeshfaces;
- tmeshfaces.resize(faces.size()*3);
-
- {
- DVector<Vector3>::Write tw=tmeshfaces.write();
- int tidx=0;
-
-
- for(List<Face3>::Element *E=faces.front();E;E=E->next()) {
-
- const Face3 &f = E->get();
-
- for(int j=0;j<3;j++) {
-
- tw[tidx++]=f.vertex[j];
- _EdgeKey ek;
- ek.from=f.vertex[j].snapped(CMP_EPSILON);
- ek.to=f.vertex[(j+1)%3].snapped(CMP_EPSILON);
- if (ek.from<ek.to)
- SWAP(ek.from,ek.to);
-
- Map<_EdgeKey,bool>::Element *E=edge_map.find(ek);
-
- if (E) {
-
- E->get()=false;
-
- } else {
-
- edge_map[ek]=true;
- }
-
- }
- }
- }
- Vector<Vector3> lines;
-
- for(Map<_EdgeKey,bool>::Element *E=edge_map.front();E;E=E->next()) {
-
- if (E->get()) {
- lines.push_back(E->key().from);
- lines.push_back(E->key().to);
- }
- }
-
- Ref<TriangleMesh> tmesh = memnew( TriangleMesh);
- tmesh->create(tmeshfaces);
-
- if (lines.size())
- add_lines(lines,navmesh->is_enabled()?SpatialEditorGizmos::singleton->navmesh_edge_material:SpatialEditorGizmos::singleton->navmesh_edge_material_disabled);
- add_collision_triangles(tmesh);
- Ref<Mesh> m = memnew( Mesh );
- Array a;
- a.resize(Mesh::ARRAY_MAX);
- a[0]=tmeshfaces;
- m->add_surface(Mesh::PRIMITIVE_TRIANGLES,a);
- m->surface_set_material(0,navmesh->is_enabled()?SpatialEditorGizmos::singleton->navmesh_solid_material:SpatialEditorGizmos::singleton->navmesh_solid_material_disabled);
- add_mesh(m);
- add_collision_segments(lines);
-
-}
-
-NavigationMeshSpatialGizmo::NavigationMeshSpatialGizmo(NavigationMeshInstance *p_navmesh){
-
- set_spatial_node(p_navmesh);
- navmesh=p_navmesh;
-}
-
-//////
-///
-///
-
-
-
-void PinJointSpatialGizmo::redraw() {
-
- clear();
- Vector<Vector3> cursor_points;
- float cs = 0.25;
- cursor_points.push_back(Vector3(+cs,0,0));
- cursor_points.push_back(Vector3(-cs,0,0));
- cursor_points.push_back(Vector3(0,+cs,0));
- cursor_points.push_back(Vector3(0,-cs,0));
- cursor_points.push_back(Vector3(0,0,+cs));
- cursor_points.push_back(Vector3(0,0,-cs));
- add_collision_segments(cursor_points);
- add_lines(cursor_points,SpatialEditorGizmos::singleton->joint_material);
-
-}
-
-
-PinJointSpatialGizmo::PinJointSpatialGizmo(PinJoint* p_p3d) {
-
- p3d=p_p3d;
- set_spatial_node(p3d);
-}
-
-////
-
-void HingeJointSpatialGizmo::redraw() {
-
- clear();
- Vector<Vector3> cursor_points;
- float cs = 0.25;
- /*cursor_points.push_back(Vector3(+cs,0,0));
- cursor_points.push_back(Vector3(-cs,0,0));
- cursor_points.push_back(Vector3(0,+cs,0));
- cursor_points.push_back(Vector3(0,-cs,0));*/
- cursor_points.push_back(Vector3(0,0,+cs*2));
- cursor_points.push_back(Vector3(0,0,-cs*2));
-
- float ll = p3d->get_param(HingeJoint::PARAM_LIMIT_LOWER);
- float ul = p3d->get_param(HingeJoint::PARAM_LIMIT_UPPER);
-
- if (p3d->get_flag(HingeJoint::FLAG_USE_LIMIT) && ll<ul) {
-
- const int points = 32;
- float step = (ul-ll)/points;
-
-
- for(int i=0;i<points;i++) {
-
- float s = ll+i*(ul-ll)/points;
- float n = ll+(i+1)*(ul-ll)/points;
-
- Vector3 from=Vector3( -Math::sin(s),Math::cos(s), 0 )*cs;
- Vector3 to=Vector3( -Math::sin(n),Math::cos(n), 0 )*cs;
-
- if (i==points-1) {
- cursor_points.push_back(to);
- cursor_points.push_back(Vector3());
- }
- if (i==0) {
- cursor_points.push_back(from);
- cursor_points.push_back(Vector3());
- }
-
-
- cursor_points.push_back(from);
- cursor_points.push_back(to);
-
-
- }
-
- cursor_points.push_back(Vector3(0,cs*1.5,0));
- cursor_points.push_back(Vector3());
-
- } else {
-
-
- const int points = 32;
-
- for(int i=0;i<points;i++) {
-
- float s = ll+i*(Math_PI*2.0)/points;
- float n = ll+(i+1)*(Math_PI*2.0)/points;
-
- Vector3 from=Vector3( -Math::sin(s),Math::cos(s), 0 )*cs;
- Vector3 to=Vector3( -Math::sin(n),Math::cos(n), 0 )*cs;
-
- cursor_points.push_back(from);
- cursor_points.push_back(to);
-
- }
-
- }
- add_collision_segments(cursor_points);
- add_lines(cursor_points,SpatialEditorGizmos::singleton->joint_material);
-
-}
-
-
-HingeJointSpatialGizmo::HingeJointSpatialGizmo(HingeJoint* p_p3d) {
-
- p3d=p_p3d;
- set_spatial_node(p3d);
-}
-
-///////
-///
-////
-
-void SliderJointSpatialGizmo::redraw() {
-
- clear();
- Vector<Vector3> cursor_points;
- float cs = 0.25;
- /*cursor_points.push_back(Vector3(+cs,0,0));
- cursor_points.push_back(Vector3(-cs,0,0));
- cursor_points.push_back(Vector3(0,+cs,0));
- cursor_points.push_back(Vector3(0,-cs,0));*/
- cursor_points.push_back(Vector3(0,0,+cs*2));
- cursor_points.push_back(Vector3(0,0,-cs*2));
-
- float ll = p3d->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_LOWER);
- float ul = p3d->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_UPPER);
- float lll = -p3d->get_param(SliderJoint::PARAM_LINEAR_LIMIT_LOWER);
- float lul = -p3d->get_param(SliderJoint::PARAM_LINEAR_LIMIT_UPPER);
-
- if (lll>lul) {
-
- cursor_points.push_back(Vector3(lul,0,0));
- cursor_points.push_back(Vector3(lll,0,0));
-
- cursor_points.push_back(Vector3(lul,-cs,-cs));
- cursor_points.push_back(Vector3(lul,-cs,cs));
- cursor_points.push_back(Vector3(lul,-cs,cs));
- cursor_points.push_back(Vector3(lul,cs,cs));
- cursor_points.push_back(Vector3(lul,cs,cs));
- cursor_points.push_back(Vector3(lul,cs,-cs));
- cursor_points.push_back(Vector3(lul,cs,-cs));
- cursor_points.push_back(Vector3(lul,-cs,-cs));
-
-
- cursor_points.push_back(Vector3(lll,-cs,-cs));
- cursor_points.push_back(Vector3(lll,-cs,cs));
- cursor_points.push_back(Vector3(lll,-cs,cs));
- cursor_points.push_back(Vector3(lll,cs,cs));
- cursor_points.push_back(Vector3(lll,cs,cs));
- cursor_points.push_back(Vector3(lll,cs,-cs));
- cursor_points.push_back(Vector3(lll,cs,-cs));
- cursor_points.push_back(Vector3(lll,-cs,-cs));
-
-
- } else {
-
- cursor_points.push_back(Vector3(+cs*2,0,0));
- cursor_points.push_back(Vector3(-cs*2,0,0));
-
- }
-
- if (ll<ul) {
-
- const int points = 32;
- float step = (ul-ll)/points;
-
-
- for(int i=0;i<points;i++) {
-
- float s = ll+i*(ul-ll)/points;
- float n = ll+(i+1)*(ul-ll)/points;
-
- Vector3 from=Vector3(0, Math::cos(s), -Math::sin(s) )*cs;
- Vector3 to=Vector3(0,Math::cos(n), -Math::sin(n) )*cs;
-
- if (i==points-1) {
- cursor_points.push_back(to);
- cursor_points.push_back(Vector3());
- }
- if (i==0) {
- cursor_points.push_back(from);
- cursor_points.push_back(Vector3());
- }
-
-
- cursor_points.push_back(from);
- cursor_points.push_back(to);
-
-
- }
-
- cursor_points.push_back(Vector3(0,cs*1.5,0));
- cursor_points.push_back(Vector3());
-
- } else {
-
-
- const int points = 32;
-
- for(int i=0;i<points;i++) {
-
- float s = ll+i*(Math_PI*2.0)/points;
- float n = ll+(i+1)*(Math_PI*2.0)/points;
-
- Vector3 from=Vector3(0,Math::cos(s),-Math::sin(s) )*cs;
- Vector3 to=Vector3( 0,Math::cos(n),-Math::sin(n) )*cs;
-
- cursor_points.push_back(from);
- cursor_points.push_back(to);
-
- }
-
- }
- add_collision_segments(cursor_points);
- add_lines(cursor_points,SpatialEditorGizmos::singleton->joint_material);
-
-}
-
-
-SliderJointSpatialGizmo::SliderJointSpatialGizmo(SliderJoint* p_p3d) {
-
- p3d=p_p3d;
- set_spatial_node(p3d);
-}
-
-///////
-///
-////
-
-void ConeTwistJointSpatialGizmo::redraw() {
-
- clear();
- float cs = 0.25;
- Vector<Vector3> points;
-
- float r = 1.0;
- float w = r*Math::sin(p3d->get_param(ConeTwistJoint::PARAM_SWING_SPAN));
- float d = r*Math::cos(p3d->get_param(ConeTwistJoint::PARAM_SWING_SPAN));
-
-
- //swing
- for(int i=0;i<360;i+=10) {
-
- float ra=Math::deg2rad(i);
- float rb=Math::deg2rad(i+10);
- Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*w;
- Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*w;
-
- /*points.push_back(Vector3(a.x,0,a.y));
- points.push_back(Vector3(b.x,0,b.y));
- points.push_back(Vector3(0,a.x,a.y));
- points.push_back(Vector3(0,b.x,b.y));*/
- points.push_back(Vector3(d,a.x,a.y));
- points.push_back(Vector3(d,b.x,b.y));
-
- if (i%90==0) {
-
- points.push_back(Vector3(d,a.x,a.y));
- points.push_back(Vector3());
-
- }
- }
-
- points.push_back(Vector3());
- points.push_back(Vector3(1,0,0));
-
- //twist
- /*
- */
- float ts=Math::rad2deg(p3d->get_param(ConeTwistJoint::PARAM_TWIST_SPAN));
- ts=MIN(ts,720);
-
-
- for(int i=0;i<int(ts);i+=5) {
-
- float ra=Math::deg2rad(i);
- float rb=Math::deg2rad(i+5);
- float c = i/720.0;
- float cn = (i+5)/720.0;
- Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*w*c;
- Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*w*cn;
-
- /*points.push_back(Vector3(a.x,0,a.y));
- points.push_back(Vector3(b.x,0,b.y));
- points.push_back(Vector3(0,a.x,a.y));
- points.push_back(Vector3(0,b.x,b.y));*/
-
- points.push_back(Vector3(c,a.x,a.y));
- points.push_back(Vector3(cn,b.x,b.y));
-
- }
-
-
- add_collision_segments(points);
- add_lines(points,SpatialEditorGizmos::singleton->joint_material);
-
-}
-
-
-ConeTwistJointSpatialGizmo::ConeTwistJointSpatialGizmo(ConeTwistJoint* p_p3d) {
-
- p3d=p_p3d;
- set_spatial_node(p3d);
-}
-
-////////
-/// \brief SpatialEditorGizmos::singleton
-///
-///////
-///
-////
-
-void Generic6DOFJointSpatialGizmo::redraw() {
-
- clear();
- Vector<Vector3> cursor_points;
- float cs = 0.25;
-
- for(int ax=0;ax<3;ax++) {
- /*cursor_points.push_back(Vector3(+cs,0,0));
- cursor_points.push_back(Vector3(-cs,0,0));
- cursor_points.push_back(Vector3(0,+cs,0));
- cursor_points.push_back(Vector3(0,-cs,0));
- cursor_points.push_back(Vector3(0,0,+cs*2));
- cursor_points.push_back(Vector3(0,0,-cs*2)); */
-
- float ll;
- float ul;
- float lll;
- float lul;
-
- int a1,a2,a3;
- bool enable_ang;
- bool enable_lin;
-
- switch(ax) {
- case 0:
- ll = p3d->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT);
- ul = p3d->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT);
- lll = -p3d->get_param_x(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT);
- lul = -p3d->get_param_x(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT);
- enable_ang = p3d->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT);
- enable_lin = p3d->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT);
- a1=0;
- a2=1;
- a3=2;
- break;
- case 1:
- ll = p3d->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT);
- ul = p3d->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT);
- lll = -p3d->get_param_y(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT);
- lul = -p3d->get_param_y(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT);
- enable_ang = p3d->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT);
- enable_lin = p3d->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT);
- a1=2;
- a2=0;
- a3=1;
- break;
- case 2:
- ll = p3d->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT);
- ul = p3d->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT);
- lll = -p3d->get_param_z(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT);
- lul = -p3d->get_param_z(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT);
- enable_ang = p3d->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT);
- enable_lin = p3d->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT);
-
- a1=1;
- a2=2;
- a3=0;
- break;
- }
-
-#define ADD_VTX(x,y,z)\
- {\
- Vector3 v;\
- v[a1]=(x);\
- v[a2]=(y);\
- v[a3]=(z);\
- cursor_points.push_back(v);\
- }
-
-#define SET_VTX(what,x,y,z)\
- {\
- Vector3 v;\
- v[a1]=(x);\
- v[a2]=(y);\
- v[a3]=(z);\
- what=v;\
- }
-
-
-
-
- if (enable_lin && lll>=lul) {
-
- ADD_VTX(lul,0,0);
- ADD_VTX(lll,0,0);
-
- ADD_VTX(lul,-cs,-cs);
- ADD_VTX(lul,-cs,cs);
- ADD_VTX(lul,-cs,cs);
- ADD_VTX(lul,cs,cs);
- ADD_VTX(lul,cs,cs);
- ADD_VTX(lul,cs,-cs);
- ADD_VTX(lul,cs,-cs);
- ADD_VTX(lul,-cs,-cs);
-
-
- ADD_VTX(lll,-cs,-cs);
- ADD_VTX(lll,-cs,cs);
- ADD_VTX(lll,-cs,cs);
- ADD_VTX(lll,cs,cs);
- ADD_VTX(lll,cs,cs);
- ADD_VTX(lll,cs,-cs);
- ADD_VTX(lll,cs,-cs);
- ADD_VTX(lll,-cs,-cs);
-
-
- } else {
-
- ADD_VTX(+cs*2,0,0);
- ADD_VTX(-cs*2,0,0);
-
- }
-
- if (enable_ang && ll<=ul) {
-
- const int points = 32;
- float step = (ul-ll)/points;
-
-
- for(int i=0;i<points;i++) {
-
- float s = ll+i*(ul-ll)/points;
- float n = ll+(i+1)*(ul-ll)/points;
-
- Vector3 from;
- SET_VTX(from,0, Math::cos(s), -Math::sin(s) );
- from*=cs;
- Vector3 to;
- SET_VTX(to,0,Math::cos(n), -Math::sin(n));
- to*=cs;
-
- if (i==points-1) {
- cursor_points.push_back(to);
- cursor_points.push_back(Vector3());
- }
- if (i==0) {
- cursor_points.push_back(from);
- cursor_points.push_back(Vector3());
- }
-
-
- cursor_points.push_back(from);
- cursor_points.push_back(to);
-
-
- }
-
- ADD_VTX(0,cs*1.5,0);
- cursor_points.push_back(Vector3());
-
- } else {
-
-
- const int points = 32;
-
- for(int i=0;i<points;i++) {
-
- float s = ll+i*(Math_PI*2.0)/points;
- float n = ll+(i+1)*(Math_PI*2.0)/points;
-
-// Vector3 from=Vector3(0,Math::cos(s),-Math::sin(s) )*cs;
-// Vector3 to=Vector3( 0,Math::cos(n),-Math::sin(n) )*cs;
-
- Vector3 from;
- SET_VTX(from,0, Math::cos(s), -Math::sin(s) );
- from*=cs;
- Vector3 to;
- SET_VTX(to,0,Math::cos(n), -Math::sin(n));
- to*=cs;
-
- cursor_points.push_back(from);
- cursor_points.push_back(to);
-
- }
-
- }
- }
-
-#undef ADD_VTX
-#undef SET_VTX
-
- add_collision_segments(cursor_points);
- add_lines(cursor_points,SpatialEditorGizmos::singleton->joint_material);
-
-}
-
-
-Generic6DOFJointSpatialGizmo::Generic6DOFJointSpatialGizmo(Generic6DOFJoint* p_p3d) {
-
- p3d=p_p3d;
- set_spatial_node(p3d);
-}
-
-///////
-///
-////
-
-
-SpatialEditorGizmos *SpatialEditorGizmos::singleton=NULL;
-
-Ref<SpatialEditorGizmo> SpatialEditorGizmos::get_gizmo(Spatial *p_spatial) {
-
- if (p_spatial->cast_to<Light>()) {
-
- Ref<LightSpatialGizmo> lsg = memnew( LightSpatialGizmo(p_spatial->cast_to<Light>()) );
- return lsg;
- }
-
- if (p_spatial->cast_to<Camera>()) {
-
- Ref<CameraSpatialGizmo> lsg = memnew( CameraSpatialGizmo(p_spatial->cast_to<Camera>()) );
- return lsg;
- }
-
- if (p_spatial->cast_to<Skeleton>()) {
-
- Ref<SkeletonSpatialGizmo> lsg = memnew( SkeletonSpatialGizmo(p_spatial->cast_to<Skeleton>()) );
- return lsg;
- }
-
-
- if (p_spatial->cast_to<Position3D>()) {
-
- Ref<Position3DSpatialGizmo> lsg = memnew( Position3DSpatialGizmo(p_spatial->cast_to<Position3D>()) );
- return lsg;
- }
-
- if (p_spatial->cast_to<MeshInstance>()) {
-
- Ref<MeshInstanceSpatialGizmo> misg = memnew( MeshInstanceSpatialGizmo(p_spatial->cast_to<MeshInstance>()) );
- return misg;
- }
-
- if (p_spatial->cast_to<Room>()) {
-
- Ref<RoomSpatialGizmo> misg = memnew( RoomSpatialGizmo(p_spatial->cast_to<Room>()) );
- return misg;
- }
-
- if (p_spatial->cast_to<NavigationMeshInstance>()) {
-
- Ref<NavigationMeshSpatialGizmo> misg = memnew( NavigationMeshSpatialGizmo(p_spatial->cast_to<NavigationMeshInstance>()) );
- return misg;
- }
-
- if (p_spatial->cast_to<RayCast>()) {
-
- Ref<RayCastSpatialGizmo> misg = memnew( RayCastSpatialGizmo(p_spatial->cast_to<RayCast>()) );
- return misg;
- }
-
- if (p_spatial->cast_to<Portal>()) {
-
- Ref<PortalSpatialGizmo> misg = memnew( PortalSpatialGizmo(p_spatial->cast_to<Portal>()) );
- return misg;
- }
-
-
- if (p_spatial->cast_to<TestCube>()) {
-
- Ref<TestCubeSpatialGizmo> misg = memnew( TestCubeSpatialGizmo(p_spatial->cast_to<TestCube>()) );
- return misg;
- }
-
- if (p_spatial->cast_to<SpatialPlayer>()) {
-
- Ref<SpatialPlayerSpatialGizmo> misg = memnew( SpatialPlayerSpatialGizmo(p_spatial->cast_to<SpatialPlayer>()) );
- return misg;
- }
-
- if (p_spatial->cast_to<CollisionShape>()) {
-
- Ref<CollisionShapeSpatialGizmo> misg = memnew( CollisionShapeSpatialGizmo(p_spatial->cast_to<CollisionShape>()) );
- return misg;
- }
-
- if (p_spatial->cast_to<VisibilityNotifier>()) {
-
- Ref<VisibilityNotifierGizmo> misg = memnew( VisibilityNotifierGizmo(p_spatial->cast_to<VisibilityNotifier>()) );
- return misg;
- }
-
- if (p_spatial->cast_to<VehicleWheel>()) {
-
- Ref<VehicleWheelSpatialGizmo> misg = memnew( VehicleWheelSpatialGizmo(p_spatial->cast_to<VehicleWheel>()) );
- return misg;
- }
- if (p_spatial->cast_to<PinJoint>()) {
-
- Ref<PinJointSpatialGizmo> misg = memnew( PinJointSpatialGizmo(p_spatial->cast_to<PinJoint>()) );
- return misg;
- }
-
- if (p_spatial->cast_to<HingeJoint>()) {
-
- Ref<HingeJointSpatialGizmo> misg = memnew( HingeJointSpatialGizmo(p_spatial->cast_to<HingeJoint>()) );
- return misg;
- }
-
- if (p_spatial->cast_to<SliderJoint>()) {
-
- Ref<SliderJointSpatialGizmo> misg = memnew( SliderJointSpatialGizmo(p_spatial->cast_to<SliderJoint>()) );
- return misg;
- }
-
- if (p_spatial->cast_to<ConeTwistJoint>()) {
-
- Ref<ConeTwistJointSpatialGizmo> misg = memnew( ConeTwistJointSpatialGizmo(p_spatial->cast_to<ConeTwistJoint>()) );
- return misg;
- }
-
- if (p_spatial->cast_to<Generic6DOFJoint>()) {
-
- Ref<Generic6DOFJointSpatialGizmo> misg = memnew( Generic6DOFJointSpatialGizmo(p_spatial->cast_to<Generic6DOFJoint>()) );
- return misg;
- }
-
- if (p_spatial->cast_to<CollisionPolygon>()) {
-
- Ref<CollisionPolygonSpatialGizmo> misg = memnew( CollisionPolygonSpatialGizmo(p_spatial->cast_to<CollisionPolygon>()) );
- return misg;
- }
-
-
- return Ref<SpatialEditorGizmo>();
-}
-
-
-Ref<FixedMaterial> SpatialEditorGizmos::create_line_material(const Color& p_base_color) {
-
- Ref<FixedMaterial> line_material = Ref<FixedMaterial>( memnew( FixedMaterial ));
- line_material->set_flag(Material::FLAG_UNSHADED, true);
- line_material->set_line_width(3.0);
- line_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
- line_material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, true);
- line_material->set_parameter(FixedMaterial::PARAM_DIFFUSE,p_base_color);
-
- return line_material;
-
-}
-
-Ref<FixedMaterial> SpatialEditorGizmos::create_solid_material(const Color& p_base_color) {
-
- Ref<FixedMaterial> line_material = Ref<FixedMaterial>( memnew( FixedMaterial ));
- line_material->set_flag(Material::FLAG_UNSHADED, true);
- line_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
- line_material->set_parameter(FixedMaterial::PARAM_DIFFUSE,p_base_color);
-
- return line_material;
-
-}
-
-SpatialEditorGizmos::SpatialEditorGizmos() {
-
- singleton=this;
-
- handle_material = Ref<FixedMaterial>( memnew( FixedMaterial ));
- handle_material->set_flag(Material::FLAG_UNSHADED, true);
- handle_material->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(0.8,0.8,0.8));
-
- handle2_material = Ref<FixedMaterial>( memnew( FixedMaterial ));
- handle2_material->set_flag(Material::FLAG_UNSHADED, true);
- handle2_material->set_fixed_flag(FixedMaterial::FLAG_USE_POINT_SIZE, true);
- handle_t = SpatialEditor::get_singleton()->get_icon("Editor3DHandle","EditorIcons");
- handle2_material->set_point_size(handle_t->get_width());
- handle2_material->set_texture(FixedMaterial::PARAM_DIFFUSE,handle_t);
- handle2_material->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1));
- handle2_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
- handle2_material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, true);
-
- light_material = create_line_material(Color(1,1,0.2));
-
- light_material_omni_icon = Ref<FixedMaterial>( memnew( FixedMaterial ));
- light_material_omni_icon->set_flag(Material::FLAG_UNSHADED, true);
- light_material_omni_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true);
- light_material_omni_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER);
- light_material_omni_icon->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
- light_material_omni_icon->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1,0.9));
- light_material_omni_icon->set_texture(FixedMaterial::PARAM_DIFFUSE,SpatialEditor::get_singleton()->get_icon("GizmoLight","EditorIcons"));
-
-
- light_material_directional_icon = Ref<FixedMaterial>( memnew( FixedMaterial ));
- light_material_directional_icon->set_flag(Material::FLAG_UNSHADED, true);
- light_material_directional_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true);
- light_material_directional_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER);
- light_material_directional_icon->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
- light_material_directional_icon->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1,0.9));
- light_material_directional_icon->set_texture(FixedMaterial::PARAM_DIFFUSE,SpatialEditor::get_singleton()->get_icon("GizmoDirectionalLight","EditorIcons"));
-
- camera_material = create_line_material(Color(1.0,0.5,1.0));
-
-
- navmesh_edge_material = create_line_material(Color(0.1,0.8,1.0));
- navmesh_solid_material = create_solid_material(Color(0.1,0.8,1.0,0.4));
- navmesh_edge_material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, false);
- navmesh_solid_material->set_flag(Material::FLAG_DOUBLE_SIDED,true);
-
- navmesh_edge_material_disabled = create_line_material(Color(1.0,0.8,0.1));
- navmesh_solid_material_disabled = create_solid_material(Color(1.0,0.8,0.1,0.4));
- navmesh_edge_material_disabled->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, false);
- navmesh_solid_material_disabled->set_flag(Material::FLAG_DOUBLE_SIDED,true);
-
- skeleton_material = create_line_material(Color(0.6,1.0,0.3));
- skeleton_material->set_flag(Material::FLAG_DOUBLE_SIDED,true);
- skeleton_material->set_flag(Material::FLAG_UNSHADED,true);
- skeleton_material->set_flag(Material::FLAG_ONTOP,true);
- skeleton_material->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER);
-
- //position 3D Shared mesh
-
- pos3d_mesh = Ref<Mesh>( memnew( Mesh ) );
- {
-
- DVector<Vector3> cursor_points;
- DVector<Color> cursor_colors;
- float cs = 0.25;
- cursor_points.push_back(Vector3(+cs,0,0));
- cursor_points.push_back(Vector3(-cs,0,0));
- cursor_points.push_back(Vector3(0,+cs,0));
- cursor_points.push_back(Vector3(0,-cs,0));
- cursor_points.push_back(Vector3(0,0,+cs));
- cursor_points.push_back(Vector3(0,0,-cs));
- cursor_colors.push_back(Color(1,0.5,0.5,0.7));
- cursor_colors.push_back(Color(1,0.5,0.5,0.7));
- cursor_colors.push_back(Color(0.5,1,0.5,0.7));
- cursor_colors.push_back(Color(0.5,1,0.5,0.7));
- cursor_colors.push_back(Color(0.5,0.5,1,0.7));
- cursor_colors.push_back(Color(0.5,0.5,1,0.7));
-
- Ref<FixedMaterial> mat = memnew( FixedMaterial );
- mat->set_flag(Material::FLAG_UNSHADED,true);
- mat->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY,true);
- mat->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA,true);
- mat->set_line_width(3);
- Array d;
- d.resize(VS::ARRAY_MAX);
- d[Mesh::ARRAY_VERTEX]=cursor_points;
- d[Mesh::ARRAY_COLOR]=cursor_colors;
- pos3d_mesh->add_surface(Mesh::PRIMITIVE_LINES,d);
- pos3d_mesh->surface_set_material(0,mat);
- }
-
-
- sample_player_icon = Ref<FixedMaterial>( memnew( FixedMaterial ));
- sample_player_icon->set_flag(Material::FLAG_UNSHADED, true);
- sample_player_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true);
- sample_player_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER);
- sample_player_icon->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
- sample_player_icon->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1,0.9));
- sample_player_icon->set_texture(FixedMaterial::PARAM_DIFFUSE,SpatialEditor::get_singleton()->get_icon("GizmoSpatialSamplePlayer","EditorIcons"));
-
- room_material = create_line_material(Color(1.0,0.6,0.9));
- portal_material = create_line_material(Color(1.0,0.8,0.6));
- raycast_material = create_line_material(Color(1.0,0.8,0.6));
- car_wheel_material = create_line_material(Color(0.6,0.8,1.0));
- visibility_notifier_material = create_line_material(Color(1.0,0.5,1.0));
- joint_material = create_line_material(Color(0.6,0.8,1.0));
-
- stream_player_icon = Ref<FixedMaterial>( memnew( FixedMaterial ));
- stream_player_icon->set_flag(Material::FLAG_UNSHADED, true);
- stream_player_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true);
- stream_player_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER);
- stream_player_icon->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
- stream_player_icon->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1,0.9));
- stream_player_icon->set_texture(FixedMaterial::PARAM_DIFFUSE,SpatialEditor::get_singleton()->get_icon("GizmoSpatialStreamPlayer","EditorIcons"));
-
- visibility_notifier_icon = Ref<FixedMaterial>( memnew( FixedMaterial ));
- visibility_notifier_icon->set_flag(Material::FLAG_UNSHADED, true);
- visibility_notifier_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true);
- visibility_notifier_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER);
- visibility_notifier_icon->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
- visibility_notifier_icon->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1,0.9));
- visibility_notifier_icon->set_texture(FixedMaterial::PARAM_DIFFUSE,SpatialEditor::get_singleton()->get_icon("Visible","EditorIcons"));
-
- {
-
- DVector<Vector3> vertices;
-
-#undef ADD_VTX
-#define ADD_VTX(m_idx);\
- vertices.push_back( face_points[m_idx] );
-
- for (int i=0;i<6;i++) {
-
-
- Vector3 face_points[4];
-
- for (int j=0;j<4;j++) {
-
- float v[3];
- v[0]=1.0;
- v[1]=1-2*((j>>1)&1);
- v[2]=v[1]*(1-2*(j&1));
-
- for (int k=0;k<3;k++) {
-
- if (i<3)
- face_points[j][(i+k)%3]=v[k]*(i>=3?-1:1);
- else
- face_points[3-j][(i+k)%3]=v[k]*(i>=3?-1:1);
- }
- }
- //tri 1
- ADD_VTX(0);
- ADD_VTX(1);
- ADD_VTX(2);
- //tri 2
- ADD_VTX(2);
- ADD_VTX(3);
- ADD_VTX(0);
-
- }
-
- test_cube_tm = Ref<TriangleMesh>( memnew( TriangleMesh ) );
- test_cube_tm->create(vertices);
- }
-
- shape_material = create_line_material(Color(0.2,1,1.0));
-
-
-}
-
+/*************************************************************************/
+/* spatial_editor_gizmos.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
+#include "spatial_editor_gizmos.h"
+#include "geometry.h"
+#include "scene/3d/camera.h"
+#include "scene/resources/surface_tool.h"
+#include "scene/resources/sphere_shape.h"
+#include "scene/resources/box_shape.h"
+#include "scene/resources/capsule_shape.h"
+#include "scene/resources/ray_shape.h"
+#include "scene/resources/convex_polygon_shape.h"
+#include "scene/resources/plane_shape.h"
+#include "quick_hull.h"
+
+// Keep small children away from this file.
+// It's so ugly it will eat them alive
+
+#define HANDLE_HALF_SIZE 0.05
+
+void SpatialGizmoTool::clear() {
+
+ for(int i=0;i<instances.size();i++) {
+
+ if (instances[i].instance.is_valid())
+ VS::get_singleton()->free(instances[i].instance);
+
+
+ }
+
+ billboard_handle=false;
+ collision_segments.clear();
+ collision_mesh=Ref<TriangleMesh>();
+ instances.clear();
+ handles.clear();
+ secondary_handles.clear();
+}
+
+void SpatialGizmoTool::Instance::create_instance(Spatial *p_base) {
+
+ instance = VS::get_singleton()->instance_create2(mesh->get_rid(),p_base->get_world()->get_scenario());
+ VS::get_singleton()->instance_attach_object_instance_ID(instance,p_base->get_instance_ID());
+ if (billboard)
+ VS::get_singleton()->instance_geometry_set_flag(instance,VS::INSTANCE_FLAG_BILLBOARD,true);
+ if (unscaled)
+ VS::get_singleton()->instance_geometry_set_flag(instance,VS::INSTANCE_FLAG_DEPH_SCALE,true);
+ if (skeleton.is_valid())
+ VS::get_singleton()->instance_attach_skeleton(instance,skeleton);
+ if (extra_margin)
+ VS::get_singleton()->instance_set_extra_visibility_margin(instance,1);
+ VS::get_singleton()->instance_geometry_set_flag(instance,VS::INSTANCE_FLAG_CAST_SHADOW,false);
+ VS::get_singleton()->instance_geometry_set_flag(instance,VS::INSTANCE_FLAG_RECEIVE_SHADOWS,false);
+ VS::get_singleton()->instance_set_layer_mask(instance,1<<SpatialEditorViewport::GIZMO_EDIT_LAYER); //gizmos are 26
+}
+
+
+
+void SpatialGizmoTool::add_mesh(const Ref<Mesh>& p_mesh,bool p_billboard, const RID &p_skeleton) {
+
+ ERR_FAIL_COND(!spatial_node);
+ Instance ins;
+
+ ins.billboard=p_billboard;
+ ins.mesh=p_mesh;
+ ins.skeleton=p_skeleton;
+ if (valid) {
+ ins.create_instance(spatial_node);
+ VS::get_singleton()->instance_set_transform(ins.instance,spatial_node->get_global_transform());
+ }
+
+ instances.push_back(ins);
+
+}
+
+void SpatialGizmoTool::add_lines(const Vector<Vector3> &p_lines, const Ref<Material> &p_material,bool p_billboard){
+
+ ERR_FAIL_COND(!spatial_node);
+ Instance ins;
+
+ Ref<Mesh> mesh = memnew( Mesh );
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+
+ a[Mesh::ARRAY_VERTEX]=p_lines;
+
+ DVector<Color> color;
+ color.resize(p_lines.size());
+ {
+ DVector<Color>::Write w = color.write();
+ for(int i=0;i<p_lines.size();i++) {
+ if (is_selected())
+ w[i]=Color(1,1,1,0.6);
+ else
+ w[i]=Color(1,1,1,0.25);
+ }
+
+ }
+
+ a[Mesh::ARRAY_COLOR]=color;
+
+
+ mesh->add_surface(Mesh::PRIMITIVE_LINES,a);
+ mesh->surface_set_material(0,p_material);
+
+ if (p_billboard) {
+ float md=0;
+ for(int i=0;i<p_lines.size();i++) {
+
+ md=MAX(0,p_lines[i].length());
+
+ }
+ if (md) {
+ mesh->set_custom_aabb(AABB(Vector3(-md,-md,-md),Vector3(md,md,md)*2.0));
+ }
+ }
+
+ ins.billboard=p_billboard;
+ ins.mesh=mesh;
+ if (valid) {
+ ins.create_instance(spatial_node);
+ VS::get_singleton()->instance_set_transform(ins.instance,spatial_node->get_global_transform());
+ }
+
+ instances.push_back(ins);
+
+}
+
+void SpatialGizmoTool::add_unscaled_billboard(const Ref<Material>& p_material,float p_scale) {
+
+ ERR_FAIL_COND(!spatial_node);
+ Instance ins;
+
+ Vector<Vector3 > vs;
+ Vector<Vector2 > uv;
+
+ vs.push_back(Vector3(-p_scale,p_scale,0));
+ vs.push_back(Vector3(p_scale,p_scale,0));
+ vs.push_back(Vector3(p_scale,-p_scale,0));
+ vs.push_back(Vector3(-p_scale,-p_scale,0));
+
+ uv.push_back(Vector2(1,0));
+ uv.push_back(Vector2(0,0));
+ uv.push_back(Vector2(0,1));
+ uv.push_back(Vector2(1,1));
+
+ Ref<Mesh> mesh = memnew( Mesh );
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+ a[Mesh::ARRAY_VERTEX]=vs;
+ a[Mesh::ARRAY_TEX_UV]=uv;
+ mesh->add_surface(Mesh::PRIMITIVE_TRIANGLE_FAN,a);
+ mesh->surface_set_material(0,p_material);
+
+ if (true) {
+ float md=0;
+ for(int i=0;i<vs.size();i++) {
+
+ md=MAX(0,vs[i].length());
+
+ }
+ if (md) {
+ mesh->set_custom_aabb(AABB(Vector3(-md,-md,-md),Vector3(md,md,md)*2.0));
+ }
+ }
+
+ ins.mesh=mesh;
+ ins.unscaled=true;
+ ins.billboard=true;
+ if (valid) {
+ ins.create_instance(spatial_node);
+ VS::get_singleton()->instance_set_transform(ins.instance,spatial_node->get_global_transform());
+ }
+
+ instances.push_back(ins);
+
+
+}
+
+void SpatialGizmoTool::add_collision_triangles(const Ref<TriangleMesh>& p_tmesh) {
+
+ collision_mesh=p_tmesh;
+}
+
+void SpatialGizmoTool::add_collision_segments(const Vector<Vector3> &p_lines) {
+
+ int from=collision_segments.size();
+ collision_segments.resize(from+p_lines.size());
+ for(int i=0;i<p_lines.size();i++) {
+
+ collision_segments[from+i]=p_lines[i];
+ }
+}
+
+
+void SpatialGizmoTool::add_handles(const Vector<Vector3> &p_handles, bool p_billboard,bool p_secondary){
+
+ billboard_handle=p_billboard;
+
+ if (!is_selected())
+ return;
+
+ ERR_FAIL_COND(!spatial_node);
+
+ ERR_FAIL_COND(!spatial_node);
+ Instance ins;
+
+
+ Ref<Mesh> mesh = memnew( Mesh );
+#if 1
+
+ Array a;
+ a.resize(VS::ARRAY_MAX);
+ a[VS::ARRAY_VERTEX]=p_handles;
+ DVector<Color> colors;
+ {
+ colors.resize(p_handles.size());
+ DVector<Color>::Write w=colors.write();
+ for(int i=0;i<p_handles.size();i++) {
+
+ Color col(1,1,1,1);
+ if (SpatialEditor::get_singleton()->get_over_gizmo_handle()!=i)
+ col=Color(0.9,0.9,0.9,0.9);
+ w[i]=col;
+ }
+
+ }
+ a[VS::ARRAY_COLOR]=colors;
+ mesh->add_surface(Mesh::PRIMITIVE_POINTS,a);
+ mesh->surface_set_material(0,SpatialEditorGizmos::singleton->handle2_material);
+
+ if (p_billboard) {
+ float md=0;
+ for(int i=0;i<p_handles.size();i++) {
+
+ md=MAX(0,p_handles[i].length());
+
+ }
+ if (md) {
+ mesh->set_custom_aabb(AABB(Vector3(-md,-md,-md),Vector3(md,md,md)*2.0));
+ }
+ }
+
+
+
+#else
+ for(int ih=0;ih<p_handles.size();ih++) {
+
+
+ Vector<Vector3> vertices;
+ Vector<Vector3> normals;
+
+ int vtx_idx=0;
+#define ADD_VTX(m_idx);\
+ vertices.push_back( (face_points[m_idx]*HANDLE_HALF_SIZE+p_handles[ih]) );\
+ normals.push_back( normal_points[m_idx] );\
+ vtx_idx++;\
+
+ for (int i=0;i<6;i++) {
+
+
+ Vector3 face_points[4];
+ Vector3 normal_points[4];
+ float uv_points[8]={0,0,0,1,1,1,1,0};
+
+ for (int j=0;j<4;j++) {
+
+ float v[3];
+ v[0]=1.0;
+ v[1]=1-2*((j>>1)&1);
+ v[2]=v[1]*(1-2*(j&1));
+
+ for (int k=0;k<3;k++) {
+
+ if (i<3)
+ face_points[j][(i+k)%3]=v[k]*(i>=3?-1:1);
+ else
+ face_points[3-j][(i+k)%3]=v[k]*(i>=3?-1:1);
+ }
+ normal_points[j]=Vector3();
+ normal_points[j][i%3]=(i>=3?-1:1);
+ }
+ //tri 1
+ ADD_VTX(0);
+ ADD_VTX(1);
+ ADD_VTX(2);
+ //tri 2
+ ADD_VTX(2);
+ ADD_VTX(3);
+ ADD_VTX(0);
+
+ }
+
+
+ Array d;
+ d.resize(VS::ARRAY_MAX);
+ d[VisualServer::ARRAY_NORMAL]= normals ;
+ d[VisualServer::ARRAY_VERTEX]= vertices ;
+
+ mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES,d);
+ mesh->surface_set_material(ih,SpatialEditorGizmos::singleton->handle_material);
+
+
+ }
+#endif
+ ins.mesh=mesh;
+ ins.billboard=p_billboard;
+ ins.extra_margin=true;
+ if (valid) {
+ ins.create_instance(spatial_node);
+ VS::get_singleton()->instance_set_transform(ins.instance,spatial_node->get_global_transform());
+ }
+ instances.push_back(ins);
+ if (!p_secondary) {
+ int chs=handles.size();
+ handles.resize(chs+p_handles.size());
+ for(int i=0;i<p_handles.size();i++) {
+ handles[i+chs]=p_handles[i];
+ }
+ } else {
+
+ int chs=secondary_handles.size();
+ secondary_handles.resize(chs+p_handles.size());
+ for(int i=0;i<p_handles.size();i++) {
+ secondary_handles[i+chs]=p_handles[i];
+ }
+
+ }
+
+}
+
+
+void SpatialGizmoTool::set_spatial_node(Spatial *p_node){
+
+ spatial_node=p_node;
+
+}
+
+bool SpatialGizmoTool::intersect_frustum(const Camera *p_camera,const Vector<Plane> &p_frustum) {
+
+ ERR_FAIL_COND_V(!spatial_node,false);
+ ERR_FAIL_COND_V(!valid,false);
+
+ if (collision_segments.size()) {
+
+ const Plane *p=p_frustum.ptr();
+ int fc=p_frustum.size();
+
+ int vc=collision_segments.size();
+ const Vector3* vptr=collision_segments.ptr();
+ Transform t = spatial_node->get_global_transform();
+
+ for(int i=0;i<vc/2;i++) {
+
+
+ Vector3 a=t.xform(vptr[i*2+0]);
+ Vector3 b=t.xform(vptr[i*2+1]);
+
+ bool any_out=false;
+ for(int j=0;j<fc;j++) {
+
+ if (p[j].distance_to(a) > 0 && p[j].distance_to(b) >0) {
+
+ any_out=true;
+ break;
+ }
+ }
+
+ if (!any_out)
+ return true;
+ }
+
+ return false;
+ }
+
+ return false;
+}
+
+
+bool SpatialGizmoTool::intersect_ray(const Camera *p_camera,const Point2& p_point, Vector3& r_pos, Vector3& r_normal,int *r_gizmo_handle,bool p_sec_first) {
+
+ ERR_FAIL_COND_V(!spatial_node,false);
+ ERR_FAIL_COND_V(!valid,false);
+
+ if (r_gizmo_handle) {
+
+ Transform t = spatial_node->get_global_transform();
+ t.orthonormalize();
+ if (billboard_handle) {
+ t.set_look_at(t.origin,t.origin+p_camera->get_transform().basis.get_axis(2),p_camera->get_transform().basis.get_axis(1));
+ }
+ Transform ti=t.affine_inverse();
+
+ Vector3 ray_from=ti.xform(p_camera->project_ray_origin(p_point));
+ Vector3 ray_dir=t.basis.xform_inv(p_camera->project_ray_normal(p_point)).normalized();
+ Vector3 ray_to = ray_from+ray_dir*4096;
+
+ float min_d=1e20;
+ int idx=-1;
+
+ for(int i=0;i<secondary_handles.size();i++) {
+#if 1
+
+
+ Vector3 hpos = t.xform(secondary_handles[i]);
+ Vector2 p = p_camera->unproject_position(hpos);
+ if (p.distance_to(p_point)<SpatialEditorGizmos::singleton->handle_t->get_width()*0.6) {
+
+
+ real_t dp = p_camera->get_transform().origin.distance_to(hpos);
+ if (dp<min_d) {
+
+ r_pos=t.xform(hpos);
+ r_normal=p_camera->get_transform().basis.get_axis(2);
+ min_d=dp;
+ idx=i+handles.size();
+
+ }
+
+ }
+
+#else
+ AABB aabb;
+ aabb.pos=Vector3(-1,-1,-1)*HANDLE_HALF_SIZE;
+ aabb.size=aabb.pos*-2;
+ aabb.pos+=secondary_handles[i];
+
+
+ Vector3 rpos,rnorm;
+
+ if (aabb.intersects_segment(ray_from,ray_to,&rpos,&rnorm)) {
+
+ real_t dp = ray_dir.dot(rpos);
+ if (dp<min_d) {
+
+ r_pos=t.xform(rpos);
+ r_normal=ti.basis.xform_inv(rnorm).normalized();
+ min_d=dp;
+ idx=i+handles.size();
+
+ }
+ }
+#endif
+ }
+
+ if (p_sec_first && idx!=-1) {
+
+ *r_gizmo_handle=idx;
+ return true;
+ }
+
+ min_d=1e20;
+
+ for(int i=0;i<handles.size();i++) {
+
+#if 1
+
+
+ Vector3 hpos = t.xform(handles[i]);
+ Vector2 p = p_camera->unproject_position(hpos);
+ if (p.distance_to(p_point)<SpatialEditorGizmos::singleton->handle_t->get_width()*0.6) {
+
+
+ real_t dp = p_camera->get_transform().origin.distance_to(hpos);
+ if (dp<min_d) {
+
+ r_pos=t.xform(hpos);
+ r_normal=p_camera->get_transform().basis.get_axis(2);
+ min_d=dp;
+ idx=i;
+
+ }
+
+ }
+
+#else
+
+ AABB aabb;
+ aabb.pos=Vector3(-1,-1,-1)*HANDLE_HALF_SIZE;
+ aabb.size=aabb.pos*-2;
+ aabb.pos+=handles[i];
+
+
+ Vector3 rpos,rnorm;
+
+ if (aabb.intersects_segment(ray_from,ray_to,&rpos,&rnorm)) {
+
+ real_t dp = ray_dir.dot(rpos);
+ if (dp<min_d) {
+
+ r_pos=t.xform(rpos);
+ r_normal=ti.basis.xform_inv(rnorm).normalized();
+ min_d=dp;
+ idx=i;
+
+ }
+ }
+#endif
+ }
+
+ if (idx>=0) {
+ *r_gizmo_handle=idx;
+ return true;
+ }
+
+
+ }
+
+ if (collision_segments.size()) {
+
+ Plane camp(p_camera->get_transform().origin,(-p_camera->get_transform().basis.get_axis(2)).normalized());
+
+ int vc=collision_segments.size();
+ const Vector3* vptr=collision_segments.ptr();
+ Transform t = spatial_node->get_global_transform();
+ if (billboard_handle) {
+ t.set_look_at(t.origin,t.origin+p_camera->get_transform().basis.get_axis(2),p_camera->get_transform().basis.get_axis(1));
+ }
+
+ Vector3 cp;
+ float cpd=1e20;
+
+ for(int i=0;i<vc/2;i++) {
+
+
+ Vector3 a=t.xform(vptr[i*2+0]);
+ Vector3 b=t.xform(vptr[i*2+1]);
+ Vector2 s[2];
+ s[0] = p_camera->unproject_position(a);
+ s[1] = p_camera->unproject_position(b);
+
+
+ Vector2 p = Geometry::get_closest_point_to_segment_2d(p_point,s);
+
+ float pd = p.distance_to(p_point);
+
+ if (pd<cpd) {
+
+
+ float d = s[0].distance_to(s[1]);
+ Vector3 tcp;
+ if (d>0) {
+
+ float d2=s[0].distance_to(p)/d;
+ tcp = a+(b-a)*d2;
+
+ } else {
+ tcp=a;
+
+ }
+
+ if (camp.distance_to(tcp)<p_camera->get_znear())
+ continue;
+ cp=tcp;
+ cpd=pd;
+ }
+ }
+
+ if (cpd<8) {
+
+ r_pos=cp;
+ r_normal=-p_camera->project_ray_normal(p_point);
+ return true;
+ }
+
+ return false;
+ }
+
+
+ if (collision_mesh.is_valid()) {
+ Transform gt = spatial_node->get_global_transform();
+
+ if (billboard_handle) {
+ gt.set_look_at(gt.origin,gt.origin+p_camera->get_transform().basis.get_axis(2),p_camera->get_transform().basis.get_axis(1));
+ }
+
+ Transform ai=gt.affine_inverse();
+ Vector3 ray_from = ai.xform(p_camera->project_ray_origin(p_point));
+ Vector3 ray_dir=ai.basis.xform(p_camera->project_ray_normal(p_point)).normalized();
+ Vector3 rpos,rnorm;
+
+#if 1
+
+
+
+ if (collision_mesh->intersect_ray(ray_from,ray_dir,rpos,rnorm)) {
+
+ r_pos=gt.xform(rpos);
+ r_normal=gt.basis.xform(rnorm).normalized();
+ return true;
+ }
+#else
+
+ if (collision_mesh->intersect_segment(ray_from,ray_from+ray_dir*4906.0,rpos,rnorm)) {
+
+ r_pos=gt.xform(rpos);
+ r_normal=gt.basis.xform(rnorm).normalized();
+ return true;
+ }
+
+#endif
+ }
+
+ return false;
+
+}
+
+
+
+void SpatialGizmoTool::create() {
+
+ ERR_FAIL_COND(!spatial_node);
+ ERR_FAIL_COND(valid);
+ valid=true;
+
+ for(int i=0;i<instances.size();i++) {
+
+ instances[i].create_instance(spatial_node);
+ }
+
+ transform();
+
+}
+
+void SpatialGizmoTool::transform(){
+
+ ERR_FAIL_COND(!spatial_node);
+ ERR_FAIL_COND(!valid);
+ for(int i=0;i<instances.size();i++) {
+ VS::get_singleton()->instance_set_transform(instances[i].instance,spatial_node->get_global_transform());
+ }
+
+}
+
+
+void SpatialGizmoTool::free(){
+
+ ERR_FAIL_COND(!spatial_node);
+ ERR_FAIL_COND(!valid);
+
+ for(int i=0;i<instances.size();i++) {
+
+ if (instances[i].instance.is_valid())
+ VS::get_singleton()->free(instances[i].instance);
+ instances[i].instance=RID();
+ }
+
+ valid=false;
+
+
+}
+
+
+
+SpatialGizmoTool::SpatialGizmoTool() {
+ valid=false;
+ billboard_handle=false;
+
+}
+
+SpatialGizmoTool::~SpatialGizmoTool(){
+
+ clear();
+}
+
+Vector3 SpatialGizmoTool::get_handle_pos(int p_idx) const {
+
+ ERR_FAIL_INDEX_V(p_idx,handles.size(),Vector3());
+
+ return handles[p_idx];
+
+}
+
+//// light gizmo
+
+
+String LightSpatialGizmo::get_handle_name(int p_idx) const {
+
+ if (p_idx==0)
+ return "Radius";
+ else
+ return "Aperture";
+}
+
+
+Variant LightSpatialGizmo::get_handle_value(int p_idx) const{
+
+ if (p_idx==0)
+ return light->get_parameter(Light::PARAM_RADIUS);
+ if (p_idx==1)
+ return light->get_parameter(Light::PARAM_SPOT_ANGLE);
+
+ return Variant();
+}
+
+
+static float _find_closest_angle_to_half_pi_arc(const Vector3& p_from, const Vector3& p_to, float p_arc_radius,const Transform& p_arc_xform) {
+
+ //bleh, discrete is simpler
+ static const int arc_test_points=64;
+ float min_d = 1e20;
+ Vector3 min_p;
+
+
+ for(int i=0;i<arc_test_points;i++) {
+
+ float a = i*Math_PI*0.5/arc_test_points;
+ float an = (i+1)*Math_PI*0.5/arc_test_points;
+ Vector3 p=Vector3( Math::cos(a), 0, -Math::sin(a) )*p_arc_radius;
+ Vector3 n=Vector3( Math::cos(an), 0,- Math::sin(an) )*p_arc_radius;
+
+ Vector3 ra,rb;
+ Geometry::get_closest_points_between_segments(p,n,p_from,p_to,ra,rb);
+
+ float d = ra.distance_to(rb);
+ if (d<min_d) {
+ min_d=d;
+ min_p=ra;
+ }
+
+ }
+
+ //min_p = p_arc_xform.affine_inverse().xform(min_p);
+ float a = Vector2(min_p.x,-min_p.z).angle();
+ return a*180.0/Math_PI;
+}
+
+
+void LightSpatialGizmo::set_handle(int p_idx,Camera *p_camera, const Point2& p_point) {
+
+ Transform gt = light->get_global_transform();
+ gt.orthonormalize();
+ Transform gi = gt.affine_inverse();
+
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+ Vector3 s[2]={gi.xform(ray_from),gi.xform(ray_from+ray_dir*4096)};
+ if (p_idx==0) {
+
+ if (light->cast_to<SpotLight>()) {
+ Vector3 ra,rb;
+ Geometry::get_closest_points_between_segments(Vector3(),Vector3(0,0,-4096),s[0],s[1],ra,rb);
+
+ float d = -ra.z;
+ if (d<0)
+ d=0;
+
+ light->set_parameter(Light::PARAM_RADIUS,d);
+ } else if (light->cast_to<OmniLight>()) {
+
+ Plane cp=Plane( gt.origin, p_camera->get_transform().basis.get_axis(2));
+
+ Vector3 inters;
+ if (cp.intersects_ray(ray_from,ray_dir,&inters)) {
+
+ float r = inters.distance_to(gt.origin);
+ light->set_parameter(Light::PARAM_RADIUS,r);
+ }
+
+ }
+
+ } else if (p_idx==1) {
+
+ float a = _find_closest_angle_to_half_pi_arc(s[0],s[1],light->get_parameter(Light::PARAM_RADIUS),gt);
+ light->set_parameter(Light::PARAM_SPOT_ANGLE,CLAMP(a,0.01,89.99));
+ }
+}
+
+void LightSpatialGizmo::commit_handle(int p_idx,const Variant& p_restore,bool p_cancel){
+
+ if (p_cancel) {
+
+ light->set_parameter(p_idx==0?Light::PARAM_RADIUS:Light::PARAM_SPOT_ANGLE,p_restore);
+
+ } else if (p_idx==0) {
+
+ UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
+ ur->create_action("Change Light Radius");
+ ur->add_do_method(light,"set_parameter",Light::PARAM_RADIUS,light->get_parameter(Light::PARAM_RADIUS));
+ ur->add_undo_method(light,"set_parameter",Light::PARAM_RADIUS,p_restore);
+ ur->commit_action();
+ } else if (p_idx==1) {
+
+ UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
+ ur->create_action("Change Light Radius");
+ ur->add_do_method(light,"set_parameter",Light::PARAM_SPOT_ANGLE,light->get_parameter(Light::PARAM_SPOT_ANGLE));
+ ur->add_undo_method(light,"set_parameter",Light::PARAM_SPOT_ANGLE,p_restore);
+ ur->commit_action();
+
+ }
+}
+
+
+
+void LightSpatialGizmo::redraw() {
+
+
+ if (light->cast_to<DirectionalLight>()) {
+
+
+
+ const int arrow_points=5;
+ Vector3 arrow[arrow_points]={
+ Vector3(0,0,2),
+ Vector3(1,1,2),
+ Vector3(1,1,-1),
+ Vector3(2,2,-1),
+ Vector3(0,0,-3)
+ };
+
+ int arrow_sides=4;
+
+ Vector<Vector3> lines;
+
+
+ for(int i = 0; i < arrow_sides ; i++) {
+
+
+ Matrix3 ma(Vector3(0,0,1),Math_PI*2*float(i)/arrow_sides);
+ Matrix3 mb(Vector3(0,0,1),Math_PI*2*float(i+1)/arrow_sides);
+
+
+ for(int j=1;j<arrow_points-1;j++) {
+
+ if (j!=2) {
+ lines.push_back(ma.xform(arrow[j]));
+ lines.push_back(ma.xform(arrow[j+1]));
+ }
+ if (j<arrow_points-1) {
+ lines.push_back(ma.xform(arrow[j]));
+ lines.push_back(mb.xform(arrow[j]));
+ }
+
+ }
+ }
+
+ add_lines(lines,SpatialEditorGizmos::singleton->light_material);
+ add_collision_segments(lines);
+ add_unscaled_billboard(SpatialEditorGizmos::singleton->light_material_directional_icon,0.05);
+
+ }
+
+ if (light->cast_to<OmniLight>()) {
+
+ clear();
+
+
+ OmniLight *on = light->cast_to<OmniLight>();
+
+ float r = on->get_parameter(Light::PARAM_RADIUS);
+
+ Vector<Vector3> points;
+
+ for(int i=0;i<=360;i++) {
+
+ float ra=Math::deg2rad(i);
+ float rb=Math::deg2rad(i+1);
+ Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*r;
+ Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*r;
+
+ /*points.push_back(Vector3(a.x,0,a.y));
+ points.push_back(Vector3(b.x,0,b.y));
+ points.push_back(Vector3(0,a.x,a.y));
+ points.push_back(Vector3(0,b.x,b.y));*/
+ points.push_back(Vector3(a.x,a.y,0));
+ points.push_back(Vector3(b.x,b.y,0));
+
+ }
+
+ add_lines(points,SpatialEditorGizmos::singleton->light_material,true);
+ add_collision_segments(points);
+
+ add_unscaled_billboard(SpatialEditorGizmos::singleton->light_material_omni_icon,0.05);
+
+ Vector<Vector3> handles;
+ handles.push_back(Vector3(r,0,0));
+ add_handles(handles,true);
+
+
+ }
+
+
+ if (light->cast_to<SpotLight>()) {
+
+ clear();
+
+ Vector<Vector3> points;
+ SpotLight *on = light->cast_to<SpotLight>();
+
+ float r = on->get_parameter(Light::PARAM_RADIUS);
+ float w = r*Math::sin(Math::deg2rad(on->get_parameter(Light::PARAM_SPOT_ANGLE)));
+ float d = r*Math::cos(Math::deg2rad(on->get_parameter(Light::PARAM_SPOT_ANGLE)));
+
+
+
+ for(int i=0;i<360;i++) {
+
+ float ra=Math::deg2rad(i);
+ float rb=Math::deg2rad(i+1);
+ Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*w;
+ Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*w;
+
+ /*points.push_back(Vector3(a.x,0,a.y));
+ points.push_back(Vector3(b.x,0,b.y));
+ points.push_back(Vector3(0,a.x,a.y));
+ points.push_back(Vector3(0,b.x,b.y));*/
+ points.push_back(Vector3(a.x,a.y,-d));
+ points.push_back(Vector3(b.x,b.y,-d));
+
+ if (i%90==0) {
+
+ points.push_back(Vector3(a.x,a.y,-d));
+ points.push_back(Vector3());
+
+ }
+
+
+ }
+
+ points.push_back(Vector3(0,0,-r));
+ points.push_back(Vector3());
+
+ add_lines(points,SpatialEditorGizmos::singleton->light_material);
+
+ Vector<Vector3> handles;
+ handles.push_back(Vector3(0,0,-r));
+
+ Vector<Vector3> collision_segments;
+
+ for(int i=0;i<64;i++) {
+
+ float ra=i*Math_PI*2.0/64.0;
+ float rb=(i+1)*Math_PI*2.0/64.0;
+ Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*w;
+ Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*w;
+
+ collision_segments.push_back(Vector3(a.x,a.y,-d));
+ collision_segments.push_back(Vector3(b.x,b.y,-d));
+
+ if (i%16==0) {
+
+ collision_segments.push_back(Vector3(a.x,a.y,-d));
+ collision_segments.push_back(Vector3());
+
+ }
+
+ if (i==16) {
+
+ handles.push_back(Vector3(a.x,a.y,-d));
+ }
+
+ }
+
+ collision_segments.push_back(Vector3(0,0,-r));
+ collision_segments.push_back(Vector3());
+
+
+ add_handles(handles);
+ add_collision_segments(collision_segments);
+ add_unscaled_billboard(SpatialEditorGizmos::singleton->light_material_omni_icon,0.05);
+
+ }
+
+}
+
+LightSpatialGizmo::LightSpatialGizmo(Light* p_light){
+
+ light=p_light;
+ set_spatial_node(p_light);
+
+}
+
+//////
+
+String CameraSpatialGizmo::get_handle_name(int p_idx) const {
+
+ if (camera->get_projection()==Camera::PROJECTION_PERSPECTIVE) {
+ return "FOV";
+ } else {
+ return "Size";
+ }
+}
+Variant CameraSpatialGizmo::get_handle_value(int p_idx) const{
+
+ if (camera->get_projection()==Camera::PROJECTION_PERSPECTIVE) {
+ return camera->get_fov();
+ } else {
+
+ return camera->get_size();
+ }
+}
+void CameraSpatialGizmo::set_handle(int p_idx,Camera *p_camera, const Point2& p_point){
+
+ Transform gt = camera->get_global_transform();
+ gt.orthonormalize();
+ Transform gi = gt.affine_inverse();
+
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+ Vector3 s[2]={gi.xform(ray_from),gi.xform(ray_from+ray_dir*4096)};
+
+ if (camera->get_projection()==Camera::PROJECTION_PERSPECTIVE) {
+ Transform gt=camera->get_global_transform();
+ float a = _find_closest_angle_to_half_pi_arc(s[0],s[1],1.0,gt);
+ camera->set("fov",a);
+ } else {
+
+ Vector3 ra,rb;
+ Geometry::get_closest_points_between_segments(Vector3(0,0,-1),Vector3(4096,0,-1),s[0],s[1],ra,rb);
+ float d = ra.x * 2.0;
+ if (d<0)
+ d=0;
+
+ camera->set("size",d);
+ }
+
+}
+void CameraSpatialGizmo::commit_handle(int p_idx,const Variant& p_restore,bool p_cancel){
+
+ if (camera->get_projection()==Camera::PROJECTION_PERSPECTIVE) {
+
+ if (p_cancel) {
+
+ camera->set("fov",p_restore);
+ } else {
+ UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
+ ur->create_action("Change Camera FOV");
+ ur->add_do_property(camera,"fov",camera->get_fov());
+ ur->add_undo_property(camera,"fov",p_restore);
+ ur->commit_action();
+ }
+
+ } else {
+
+ if (p_cancel) {
+
+ camera->set("size",p_restore);
+ } else {
+ UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
+ ur->create_action("Change Camera Size");
+ ur->add_do_property(camera,"size",camera->get_size());
+ ur->add_undo_property(camera,"size",p_restore);
+ ur->commit_action();
+ }
+
+ }
+
+}
+
+void CameraSpatialGizmo::redraw(){
+
+ clear();
+
+ Vector<Vector3> lines;
+ Vector<Vector3> handles;
+
+
+ switch(camera->get_projection()) {
+
+ case Camera::PROJECTION_PERSPECTIVE: {
+
+ float fov = camera->get_fov();
+
+ Vector3 side=Vector3( Math::sin(Math::deg2rad(fov)), 0, -Math::cos(Math::deg2rad(fov)) );
+ Vector3 nside=side;
+ nside.x=-nside.x;
+ Vector3 up=Vector3(0,side.x,0);
+
+
+#define ADD_TRIANGLE( m_a, m_b, m_c)\
+{\
+ lines.push_back(m_a);\
+ lines.push_back(m_b);\
+ lines.push_back(m_b);\
+ lines.push_back(m_c);\
+ lines.push_back(m_c);\
+ lines.push_back(m_a);\
+}
+
+ ADD_TRIANGLE( Vector3(), side+up, side-up );
+ ADD_TRIANGLE( Vector3(), nside+up, nside-up );
+ ADD_TRIANGLE( Vector3(), side+up, nside+up );
+ ADD_TRIANGLE( Vector3(), side-up, nside-up );
+
+ handles.push_back(side);
+ side.x*=0.25;
+ nside.x*=0.25;
+ Vector3 tup( 0, up.y*3/2,side.z);
+ ADD_TRIANGLE( tup, side+up, nside+up );
+
+ } break;
+ case Camera::PROJECTION_ORTHOGONAL: {
+
+#define ADD_QUAD( m_a, m_b, m_c, m_d)\
+{\
+ lines.push_back(m_a);\
+ lines.push_back(m_b);\
+ lines.push_back(m_b);\
+ lines.push_back(m_c);\
+ lines.push_back(m_c);\
+ lines.push_back(m_d);\
+ lines.push_back(m_d);\
+ lines.push_back(m_a);\
+}
+ float size = camera->get_size();
+
+ float hsize=size*0.5;
+ Vector3 right(hsize,0,0);
+ Vector3 up(0,hsize,0);
+ Vector3 back(0,0,-1.0);
+ Vector3 front(0,0,0);
+
+ ADD_QUAD( -up-right,-up+right,up+right,up-right);
+ ADD_QUAD( -up-right+back,-up+right+back,up+right+back,up-right+back);
+ ADD_QUAD( up+right,up+right+back,up-right+back,up-right);
+ ADD_QUAD( -up+right,-up+right+back,-up-right+back,-up-right);
+ handles.push_back(right+back);
+
+ right.x*=0.25;
+ Vector3 tup( 0, up.y*3/2,back.z );
+ ADD_TRIANGLE( tup, right+up+back, -right+up+back );
+
+ } break;
+
+ }
+
+ add_lines(lines,SpatialEditorGizmos::singleton->camera_material);
+ add_collision_segments(lines);
+ add_handles(handles);
+}
+
+
+CameraSpatialGizmo::CameraSpatialGizmo(Camera* p_camera){
+
+ camera=p_camera;
+ set_spatial_node(camera);
+}
+
+
+
+
+//////
+
+void MeshInstanceSpatialGizmo::redraw() {
+
+ Ref<Mesh> m = mesh->get_mesh();
+ if (!m.is_valid())
+ return; //none
+
+ Ref<TriangleMesh> tm = m->generate_triangle_mesh();
+ if (tm.is_valid())
+ add_collision_triangles(tm);
+}
+
+MeshInstanceSpatialGizmo::MeshInstanceSpatialGizmo(MeshInstance* p_mesh) {
+
+ mesh=p_mesh;
+ set_spatial_node(p_mesh);
+}
+
+/////
+
+
+void Position3DSpatialGizmo::redraw() {
+
+ clear();
+ add_mesh(SpatialEditorGizmos::singleton->pos3d_mesh);
+ Vector<Vector3> cursor_points;
+ float cs = 0.25;
+ cursor_points.push_back(Vector3(+cs,0,0));
+ cursor_points.push_back(Vector3(-cs,0,0));
+ cursor_points.push_back(Vector3(0,+cs,0));
+ cursor_points.push_back(Vector3(0,-cs,0));
+ cursor_points.push_back(Vector3(0,0,+cs));
+ cursor_points.push_back(Vector3(0,0,-cs));
+ add_collision_segments(cursor_points);
+
+}
+
+
+Position3DSpatialGizmo::Position3DSpatialGizmo(Position3D* p_p3d) {
+
+ p3d=p_p3d;
+ set_spatial_node(p3d);
+}
+
+
+/////
+
+void SkeletonSpatialGizmo::redraw() {
+
+ clear();
+
+ Ref<SurfaceTool> surface_tool( memnew( SurfaceTool ));
+
+
+ surface_tool->begin(Mesh::PRIMITIVE_LINES);
+ surface_tool->set_material(SpatialEditorGizmos::singleton->skeleton_material);
+ Vector<Transform> grests;
+ grests.resize(skel->get_bone_count());
+
+ Vector<int> bones;
+ Vector<float> weights;
+ bones.resize(4);
+ weights.resize(4);
+
+ for(int i=0;i<4;i++) {
+ bones[i]=0;
+ weights[i]=0;
+ }
+
+ weights[0]=1;
+
+
+ AABB aabb;
+
+ Color bonecolor = Color(1.0,0.4,0.4,0.3);
+ Color rootcolor = Color(0.4,1.0,0.4,0.1);
+
+ for (int i=0;i<skel->get_bone_count();i++) {
+
+ int parent = skel->get_bone_parent(i);
+
+ if (parent>=0) {
+ grests[i]=grests[parent] * skel->get_bone_rest(i);
+
+ Vector3 v0 = grests[parent].origin;
+ Vector3 v1 = grests[i].origin;
+ Vector3 d = (v1-v0).normalized();
+ float dist = v0.distance_to(v1);
+
+ //find closest axis
+ int closest=-1;
+ float closest_d = 0.0;
+
+ for(int j=0;j<3;j++) {
+ float dp = Math::abs(grests[parent].basis[j].normalized().dot(d));
+ if (j==0 || dp>closest_d)
+ closest=j;
+ }
+
+ //find closest other
+ Vector3 first;
+ Vector3 points[4];
+ int pointidx=0;
+ for(int j=0;j<3;j++) {
+
+ bones[0]=parent;
+ surface_tool->add_bones(bones);
+ surface_tool->add_weights(weights);
+ surface_tool->add_color(rootcolor);
+ surface_tool->add_vertex(v0-grests[parent].basis[j].normalized()*dist*0.05);
+ surface_tool->add_bones(bones);
+ surface_tool->add_weights(weights);
+ surface_tool->add_color(rootcolor);
+ surface_tool->add_vertex(v0+grests[parent].basis[j].normalized()*dist*0.05);
+
+ if (j==closest)
+ continue;
+
+ Vector3 axis;
+ if (first==Vector3()) {
+ axis = d.cross(d.cross(grests[parent].basis[j])).normalized();
+ first=axis;
+ } else {
+ axis = d.cross(first).normalized();
+ }
+
+ for(int k=0;k<2;k++) {
+
+ if (k==1)
+ axis=-axis;
+ Vector3 point = v0+d*dist*0.2;
+ point+=axis*dist*0.1;
+
+
+ bones[0]=parent;
+ surface_tool->add_bones(bones);
+ surface_tool->add_weights(weights);
+ surface_tool->add_color(bonecolor);
+ surface_tool->add_vertex(v0);
+ surface_tool->add_bones(bones);
+ surface_tool->add_weights(weights);
+ surface_tool->add_color(bonecolor);
+ surface_tool->add_vertex(point);
+
+ bones[0]=parent;
+ surface_tool->add_bones(bones);
+ surface_tool->add_weights(weights);
+ surface_tool->add_color(bonecolor);
+ surface_tool->add_vertex(point);
+ bones[0]=i;
+ surface_tool->add_bones(bones);
+ surface_tool->add_weights(weights);
+ surface_tool->add_color(bonecolor);
+ surface_tool->add_vertex(v1);
+ points[pointidx++]=point;
+
+ }
+
+ }
+
+ SWAP( points[1],points[2] );
+ for(int j=0;j<4;j++) {
+
+
+ bones[0]=parent;
+ surface_tool->add_bones(bones);
+ surface_tool->add_weights(weights);
+ surface_tool->add_color(bonecolor);
+ surface_tool->add_vertex(points[j]);
+ surface_tool->add_bones(bones);
+ surface_tool->add_weights(weights);
+ surface_tool->add_color(bonecolor);
+ surface_tool->add_vertex(points[(j+1)%4]);
+ }
+
+
+/*
+ bones[0]=parent;
+ surface_tool->add_bones(bones);
+ surface_tool->add_weights(weights);
+ surface_tool->add_color(Color(0.4,1,0.4,0.4));
+ surface_tool->add_vertex(v0);
+ bones[0]=i;
+ surface_tool->add_bones(bones);
+ surface_tool->add_weights(weights);
+ surface_tool->add_color(Color(0.4,1,0.4,0.4));
+ surface_tool->add_vertex(v1);
+*/
+ } else {
+
+ grests[i]=skel->get_bone_rest(i);
+ bones[0]=i;
+ }
+/*
+ Transform t = grests[i];
+ t.orthonormalize();
+
+ for (int i=0;i<6;i++) {
+
+
+ Vector3 face_points[4];
+
+ for (int j=0;j<4;j++) {
+
+ float v[3];
+ v[0]=1.0;
+ v[1]=1-2*((j>>1)&1);
+ v[2]=v[1]*(1-2*(j&1));
+
+ for (int k=0;k<3;k++) {
+
+ if (i<3)
+ face_points[j][(i+k)%3]=v[k]*(i>=3?-1:1);
+ else
+ face_points[3-j][(i+k)%3]=v[k]*(i>=3?-1:1);
+ }
+ }
+
+ for(int j=0;j<4;j++) {
+ surface_tool->add_bones(bones);
+ surface_tool->add_weights(weights);
+ surface_tool->add_color(Color(1.0,0.4,0.4,0.4));
+ surface_tool->add_vertex(t.xform(face_points[j]*0.04));
+ surface_tool->add_bones(bones);
+ surface_tool->add_weights(weights);
+ surface_tool->add_color(Color(1.0,0.4,0.4,0.4));
+ surface_tool->add_vertex(t.xform(face_points[(j+1)%4]*0.04));
+ }
+
+ }
+ */
+ }
+
+ Ref<Mesh> m = surface_tool->commit();
+ add_mesh(m,false,skel->get_skeleton());
+
+}
+
+SkeletonSpatialGizmo::SkeletonSpatialGizmo(Skeleton* p_skel) {
+
+ skel=p_skel;
+ set_spatial_node(p_skel);
+}
+
+/////
+
+
+void SpatialPlayerSpatialGizmo::redraw() {
+
+ clear();
+ if (splayer->cast_to<SpatialStreamPlayer>()) {
+
+ add_unscaled_billboard(SpatialEditorGizmos::singleton->stream_player_icon,0.05);
+
+ } else if (splayer->cast_to<SpatialSamplePlayer>()) {
+
+ add_unscaled_billboard(SpatialEditorGizmos::singleton->sample_player_icon,0.05);
+
+ }
+
+}
+
+SpatialPlayerSpatialGizmo::SpatialPlayerSpatialGizmo(SpatialPlayer* p_splayer){
+
+ set_spatial_node(p_splayer);
+ splayer=p_splayer;
+}
+
+
+/////
+
+
+void RoomSpatialGizmo::redraw() {
+
+ clear();
+ Ref<RoomBounds> roomie = room->get_room();
+ if (roomie.is_null())
+ return;
+ DVector<Face3> faces = roomie->get_geometry_hint();
+
+ Vector<Vector3> lines;
+ int fc=faces.size();
+ DVector<Face3>::Read r =faces.read();
+
+ Map<_EdgeKey,Vector3> edge_map;
+
+ for(int i=0;i<fc;i++) {
+
+ Vector3 fn = r[i].get_plane().normal;
+
+ for(int j=0;j<3;j++) {
+
+ _EdgeKey ek;
+ ek.from=r[i].vertex[j].snapped(CMP_EPSILON);
+ ek.to=r[i].vertex[(j+1)%3].snapped(CMP_EPSILON);
+ if (ek.from<ek.to)
+ SWAP(ek.from,ek.to);
+
+ Map<_EdgeKey,Vector3>::Element *E=edge_map.find(ek);
+
+ if (E) {
+
+ if (E->get().dot(fn) >0.9) {
+
+ E->get()=Vector3();
+ }
+
+ } else {
+
+ edge_map[ek]=fn;
+ }
+
+ }
+ }
+
+ for(Map<_EdgeKey,Vector3>::Element *E=edge_map.front();E;E=E->next()) {
+
+ if (E->get()!=Vector3()) {
+ lines.push_back(E->key().from);
+ lines.push_back(E->key().to);
+ }
+ }
+
+ add_lines(lines,SpatialEditorGizmos::singleton->room_material);
+ add_collision_segments(lines);
+
+}
+
+RoomSpatialGizmo::RoomSpatialGizmo(Room* p_room){
+
+ set_spatial_node(p_room);
+ room=p_room;
+}
+
+/////
+
+
+void PortalSpatialGizmo::redraw() {
+
+ clear();
+
+ Vector<Point2> points = portal->get_shape();
+ if (points.size()==0) {
+ return;
+ }
+
+ Vector<Vector3> lines;
+
+ Vector3 center;
+ for(int i=0;i<points.size();i++) {
+
+ Vector3 f;
+ f.x=points[i].x;
+ f.y=points[i].y;
+ Vector3 fn;
+ fn.x=points[(i+1)%points.size()].x;
+ fn.y=points[(i+1)%points.size()].y;
+ center+=f;
+
+ lines.push_back(f);
+ lines.push_back(fn);
+ }
+
+ center/=points.size();
+ lines.push_back(center);
+ lines.push_back(center+Vector3(0,0,1));
+
+ add_lines(lines,SpatialEditorGizmos::singleton->portal_material);
+ add_collision_segments(lines);
+
+}
+
+PortalSpatialGizmo::PortalSpatialGizmo(Portal* p_portal){
+
+ set_spatial_node(p_portal);
+ portal=p_portal;
+}
+
+/////
+
+
+void RayCastSpatialGizmo::redraw() {
+
+ clear();
+
+
+ Vector<Vector3> lines;
+
+ lines.push_back(Vector3());
+ lines.push_back(raycast->get_cast_to());
+
+ add_lines(lines,SpatialEditorGizmos::singleton->raycast_material);
+ add_collision_segments(lines);
+
+}
+
+RayCastSpatialGizmo::RayCastSpatialGizmo(RayCast* p_raycast){
+
+ set_spatial_node(p_raycast);
+ raycast=p_raycast;
+}
+
+
+
+/////
+
+
+void VehicleWheelSpatialGizmo::redraw() {
+
+ clear();
+
+
+ Vector<Vector3> points;
+
+ float r = car_wheel->get_radius();
+ const int skip=10;
+ for(int i=0;i<=360;i+=skip) {
+
+ float ra=Math::deg2rad(i);
+ float rb=Math::deg2rad(i+skip);
+ Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*r;
+ Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*r;
+
+ points.push_back(Vector3(0,a.x,a.y));
+ points.push_back(Vector3(0,b.x,b.y));
+
+ const int springsec=4;
+
+ for(int j=0;j<springsec;j++) {
+ float t = car_wheel->get_suspension_rest_length()*5;
+ points.push_back(Vector3(a.x,i/360.0*t/springsec+j*(t/springsec),a.y)*0.2);
+ points.push_back(Vector3(b.x,(i+skip)/360.0*t/springsec+j*(t/springsec),b.y)*0.2);
+ }
+
+
+ }
+
+ //travel
+ points.push_back(Vector3(0,0,0));
+ points.push_back(Vector3(0,car_wheel->get_suspension_rest_length(),0));
+
+ //axis
+ points.push_back(Vector3(r*0.2,car_wheel->get_suspension_rest_length(),0));
+ points.push_back(Vector3(-r*0.2,car_wheel->get_suspension_rest_length(),0));
+ //axis
+ points.push_back(Vector3(r*0.2,0,0));
+ points.push_back(Vector3(-r*0.2,0,0));
+
+ //forward line
+ points.push_back(Vector3(0,-r,0));
+ points.push_back(Vector3(0,-r,r*2));
+ points.push_back(Vector3(0,-r,r*2));
+ points.push_back(Vector3(r*2*0.2,-r,r*2*0.8));
+ points.push_back(Vector3(0,-r,r*2));
+ points.push_back(Vector3(-r*2*0.2,-r,r*2*0.8));
+
+ add_lines(points,SpatialEditorGizmos::singleton->car_wheel_material);
+ add_collision_segments(points);
+
+}
+
+VehicleWheelSpatialGizmo::VehicleWheelSpatialGizmo(VehicleWheel* p_car_wheel){
+
+ set_spatial_node(p_car_wheel);
+ car_wheel=p_car_wheel;
+}
+
+
+
+///
+
+void TestCubeSpatialGizmo::redraw() {
+
+ clear();
+ add_collision_triangles(SpatialEditorGizmos::singleton->test_cube_tm);
+}
+
+TestCubeSpatialGizmo::TestCubeSpatialGizmo(TestCube* p_tc) {
+
+ tc=p_tc;
+ set_spatial_node(p_tc);
+}
+
+
+///////////
+
+
+
+
+
+
+String CollisionShapeSpatialGizmo::get_handle_name(int p_idx) const {
+
+ Ref<Shape> s = cs->get_shape();
+ if (s.is_null())
+ return "";
+
+ if (s->cast_to<SphereShape>()) {
+
+ return "Radius";
+ }
+
+ if (s->cast_to<BoxShape>()) {
+
+ return "Extents";
+ }
+
+ if (s->cast_to<CapsuleShape>()) {
+
+ return p_idx==0?"Radius":"Height";
+ }
+
+ if (s->cast_to<RayShape>()) {
+
+ return "Length";
+ }
+
+ return "";
+}
+Variant CollisionShapeSpatialGizmo::get_handle_value(int p_idx) const{
+
+ Ref<Shape> s = cs->get_shape();
+ if (s.is_null())
+ return Variant();
+
+ if (s->cast_to<SphereShape>()) {
+
+ Ref<SphereShape> ss = s;
+ return ss->get_radius();
+ }
+
+ if (s->cast_to<BoxShape>()) {
+
+ Ref<BoxShape> bs = s;
+ return bs->get_extents();
+ }
+
+ if (s->cast_to<CapsuleShape>()) {
+
+ Ref<CapsuleShape> cs = s;
+ return p_idx==0?cs->get_radius():cs->get_height();
+ }
+
+ if (s->cast_to<RayShape>()) {
+
+ Ref<RayShape> cs = s;
+ return cs->get_length();
+ }
+
+ return Variant();
+}
+void CollisionShapeSpatialGizmo::set_handle(int p_idx,Camera *p_camera, const Point2& p_point){
+ Ref<Shape> s = cs->get_shape();
+ if (s.is_null())
+ return;
+
+ Transform gt = cs->get_global_transform();
+ gt.orthonormalize();
+ Transform gi = gt.affine_inverse();
+
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+ Vector3 sg[2]={gi.xform(ray_from),gi.xform(ray_from+ray_dir*4096)};
+
+ if (s->cast_to<SphereShape>()) {
+
+ Ref<SphereShape> ss = s;
+ Vector3 ra,rb;
+ Geometry::get_closest_points_between_segments(Vector3(),Vector3(4096,0,0),sg[0],sg[1],ra,rb);
+ float d = ra.x;
+ if (d<0.001)
+ d=0.001;
+
+ ss->set_radius(d);
+ }
+
+ if (s->cast_to<RayShape>()) {
+
+ Ref<RayShape> rs = s;
+ Vector3 ra,rb;
+ Geometry::get_closest_points_between_segments(Vector3(),Vector3(0,0,4096),sg[0],sg[1],ra,rb);
+ float d = ra.z;
+ if (d<0.001)
+ d=0.001;
+
+ rs->set_length(d);
+ }
+
+
+ if (s->cast_to<BoxShape>()) {
+
+ Vector3 axis;
+ axis[p_idx]=1.0;
+ Ref<BoxShape> bs = s;
+ Vector3 ra,rb;
+ Geometry::get_closest_points_between_segments(Vector3(),axis*4096,sg[0],sg[1],ra,rb);
+ float d = ra[p_idx];
+ if (d<0.001)
+ d=0.001;
+
+ Vector3 he = bs->get_extents();
+ he[p_idx]=d;
+ bs->set_extents(he);
+
+ }
+
+ if (s->cast_to<CapsuleShape>()) {
+
+ Vector3 axis;
+ axis[p_idx==0?0:2]=1.0;
+ Ref<CapsuleShape> cs = s;
+ Vector3 ra,rb;
+ Geometry::get_closest_points_between_segments(Vector3(),axis*4096,sg[0],sg[1],ra,rb);
+ float d = axis.dot(ra);
+ if (p_idx==1)
+ d-=cs->get_radius();
+ if (d<0.001)
+ d=0.001;
+
+ if (p_idx==0)
+ cs->set_radius(d);
+ else if (p_idx==1)
+ cs->set_height(d*2.0);
+
+ }
+
+}
+void CollisionShapeSpatialGizmo::commit_handle(int p_idx,const Variant& p_restore,bool p_cancel){
+ Ref<Shape> s = cs->get_shape();
+ if (s.is_null())
+ return;
+
+ if (s->cast_to<SphereShape>()) {
+
+ Ref<SphereShape> ss=s;
+ if (p_cancel) {
+ ss->set_radius(p_restore);
+ return;
+ }
+
+ UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
+ ur->create_action("Change Sphere Shape Radius");
+ ur->add_do_method(ss.ptr(),"set_radius",ss->get_radius());
+ ur->add_undo_method(ss.ptr(),"set_radius",p_restore);
+ ur->commit_action();
+
+ }
+
+ if (s->cast_to<BoxShape>()) {
+
+ Ref<BoxShape> ss=s;
+ if (p_cancel) {
+ ss->set_extents(p_restore);
+ return;
+ }
+
+ UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
+ ur->create_action("Change Box Shape Extents");
+ ur->add_do_method(ss.ptr(),"set_extents",ss->get_extents());
+ ur->add_undo_method(ss.ptr(),"set_extents",p_restore);
+ ur->commit_action();
+ }
+
+ if (s->cast_to<CapsuleShape>()) {
+
+ Ref<CapsuleShape> ss=s;
+ if (p_cancel) {
+ if (p_idx==0)
+ ss->set_radius(p_restore);
+ else
+ ss->set_height(p_restore);
+ return;
+ }
+
+ UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
+ if (p_idx==0) {
+ ur->create_action("Change Capsule Shape Radius");
+ ur->add_do_method(ss.ptr(),"set_radius",ss->get_radius());
+ ur->add_undo_method(ss.ptr(),"set_radius",p_restore);
+ } else {
+ ur->create_action("Change Capsule Shape Height");
+ ur->add_do_method(ss.ptr(),"set_height",ss->get_height());
+ ur->add_undo_method(ss.ptr(),"set_height",p_restore);
+
+ }
+
+ ur->commit_action();
+
+ }
+
+ if (s->cast_to<RayShape>()) {
+
+ Ref<RayShape> ss=s;
+ if (p_cancel) {
+ ss->set_length(p_restore);
+ return;
+ }
+
+ UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
+ ur->create_action("Change Ray Shape Length");
+ ur->add_do_method(ss.ptr(),"set_length",ss->get_length());
+ ur->add_undo_method(ss.ptr(),"set_length",p_restore);
+ ur->commit_action();
+
+ }
+
+}
+void CollisionShapeSpatialGizmo::redraw(){
+
+ clear();
+
+ Ref<Shape> s = cs->get_shape();
+ if (s.is_null())
+ return;
+
+ if (s->cast_to<SphereShape>()) {
+
+ Ref<SphereShape> sp= s;
+ float r=sp->get_radius();
+
+ Vector<Vector3> points;
+
+ for(int i=0;i<=360;i++) {
+
+ float ra=Math::deg2rad(i);
+ float rb=Math::deg2rad(i+1);
+ Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*r;
+ Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*r;
+
+ points.push_back(Vector3(a.x,0,a.y));
+ points.push_back(Vector3(b.x,0,b.y));
+ points.push_back(Vector3(0,a.x,a.y));
+ points.push_back(Vector3(0,b.x,b.y));
+ points.push_back(Vector3(a.x,a.y,0));
+ points.push_back(Vector3(b.x,b.y,0));
+
+ }
+
+ Vector<Vector3> collision_segments;
+
+ for(int i=0;i<64;i++) {
+
+ float ra=i*Math_PI*2.0/64.0;
+ float rb=(i+1)*Math_PI*2.0/64.0;
+ Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*r;
+ Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*r;
+
+ collision_segments.push_back(Vector3(a.x,0,a.y));
+ collision_segments.push_back(Vector3(b.x,0,b.y));
+ collision_segments.push_back(Vector3(0,a.x,a.y));
+ collision_segments.push_back(Vector3(0,b.x,b.y));
+ collision_segments.push_back(Vector3(a.x,a.y,0));
+ collision_segments.push_back(Vector3(b.x,b.y,0));
+ }
+
+ add_lines(points,SpatialEditorGizmos::singleton->shape_material);
+ add_collision_segments(collision_segments);
+ Vector<Vector3> handles;
+ handles.push_back(Vector3(r,0,0));
+ add_handles(handles);
+
+ }
+
+ if (s->cast_to<BoxShape>()) {
+
+ Ref<BoxShape> bs=s;
+ Vector<Vector3> lines;
+ AABB aabb;
+ aabb.pos=-bs->get_extents();
+ aabb.size=aabb.pos*-2;
+
+ for(int i=0;i<12;i++) {
+ Vector3 a,b;
+ aabb.get_edge(i,a,b);
+ lines.push_back(a);
+ lines.push_back(b);
+ }
+
+ Vector<Vector3> handles;
+
+ for(int i=0;i<3;i++) {
+
+ Vector3 ax;
+ ax[i]=bs->get_extents()[i];
+ handles.push_back(ax);
+ }
+
+ add_lines(lines,SpatialEditorGizmos::singleton->shape_material);
+ add_collision_segments(lines);
+ add_handles(handles);
+
+ }
+
+ if (s->cast_to<CapsuleShape>()) {
+
+ Ref<CapsuleShape> cs=s;
+ float radius = cs->get_radius();
+ float height = cs->get_height();
+
+
+ Vector<Vector3> points;
+
+ Vector3 d(0,0,height*0.5);
+ for(int i=0;i<360;i++) {
+
+ float ra=Math::deg2rad(i);
+ float rb=Math::deg2rad(i+1);
+ Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*radius;
+ Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*radius;
+
+ points.push_back(Vector3(a.x,a.y,0)+d);
+ points.push_back(Vector3(b.x,b.y,0)+d);
+
+ points.push_back(Vector3(a.x,a.y,0)-d);
+ points.push_back(Vector3(b.x,b.y,0)-d);
+
+ if (i%90==0) {
+
+ points.push_back(Vector3(a.x,a.y,0)+d);
+ points.push_back(Vector3(a.x,a.y,0)-d);
+ }
+
+ Vector3 dud = i<180?d:-d;
+
+ points.push_back(Vector3(0,a.y,a.x)+dud);
+ points.push_back(Vector3(0,b.y,b.x)+dud);
+ points.push_back(Vector3(a.y,0,a.x)+dud);
+ points.push_back(Vector3(b.y,0,b.x)+dud);
+
+ }
+
+ add_lines(points,SpatialEditorGizmos::singleton->shape_material);
+
+ Vector<Vector3> collision_segments;
+
+ for(int i=0;i<64;i++) {
+
+ float ra=i*Math_PI*2.0/64.0;
+ float rb=(i+1)*Math_PI*2.0/64.0;
+ Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*radius;
+ Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*radius;
+
+ collision_segments.push_back(Vector3(a.x,a.y,0)+d);
+ collision_segments.push_back(Vector3(b.x,b.y,0)+d);
+
+ collision_segments.push_back(Vector3(a.x,a.y,0)-d);
+ collision_segments.push_back(Vector3(b.x,b.y,0)-d);
+
+ if (i%16==0) {
+
+ collision_segments.push_back(Vector3(a.x,a.y,0)+d);
+ collision_segments.push_back(Vector3(a.x,a.y,0)-d);
+ }
+
+ Vector3 dud = i<32?d:-d;
+
+ collision_segments.push_back(Vector3(0,a.y,a.x)+dud);
+ collision_segments.push_back(Vector3(0,b.y,b.x)+dud);
+ collision_segments.push_back(Vector3(a.y,0,a.x)+dud);
+ collision_segments.push_back(Vector3(b.y,0,b.x)+dud);
+
+ }
+
+ add_collision_segments(collision_segments);
+
+ Vector<Vector3> handles;
+ handles.push_back(Vector3(cs->get_radius(),0,0));
+ handles.push_back(Vector3(0,0,cs->get_height()*0.5+cs->get_radius()));
+ add_handles(handles);
+
+
+ }
+
+ if (s->cast_to<PlaneShape>()) {
+
+ Ref<PlaneShape> ps=s;
+ Plane p = ps->get_plane();
+ Vector<Vector3> points;
+
+ Vector3 n1 = p.get_any_perpendicular_normal();
+ Vector3 n2 = p.normal.cross(n1).normalized();
+
+ Vector3 pface[4]={
+ p.normal*p.d+n1*10.0+n2*10.0,
+ p.normal*p.d+n1*10.0+n2*-10.0,
+ p.normal*p.d+n1*-10.0+n2*-10.0,
+ p.normal*p.d+n1*-10.0+n2*10.0,
+ };
+
+ points.push_back(pface[0]);
+ points.push_back(pface[1]);
+ points.push_back(pface[1]);
+ points.push_back(pface[2]);
+ points.push_back(pface[2]);
+ points.push_back(pface[3]);
+ points.push_back(pface[3]);
+ points.push_back(pface[0]);
+ points.push_back(p.normal*p.d);
+ points.push_back(p.normal*p.d+p.normal*3);
+
+ add_lines(points,SpatialEditorGizmos::singleton->shape_material);
+ add_collision_segments(points);
+
+ }
+
+
+ if (s->cast_to<ConvexPolygonShape>()) {
+
+ DVector<Vector3> points = s->cast_to<ConvexPolygonShape>()->get_points();
+
+ if (points.size()>3) {
+
+ QuickHull qh;
+ Vector<Vector3> varr = Variant(points);
+ Geometry::MeshData md;
+ Error err = qh.build(varr,md);
+ if (err==OK) {
+ Vector<Vector3> points;
+ points.resize(md.edges.size()*2);
+ for(int i=0;i<md.edges.size();i++) {
+ points[i*2+0]=md.vertices[md.edges[i].a];
+ points[i*2+1]=md.vertices[md.edges[i].b];
+ }
+
+
+ add_lines(points,SpatialEditorGizmos::singleton->shape_material);
+ add_collision_segments(points);
+
+ }
+ }
+
+ }
+
+
+ if (s->cast_to<RayShape>()) {
+
+ Ref<RayShape> rs=s;
+
+ Vector<Vector3> points;
+ points.push_back(Vector3());
+ points.push_back(Vector3(0,0,rs->get_length()));
+ add_lines(points,SpatialEditorGizmos::singleton->shape_material);
+ add_collision_segments(points);
+ Vector<Vector3> handles;
+ handles.push_back(Vector3(0,0,rs->get_length()));
+ add_handles(handles);
+
+
+ }
+
+}
+CollisionShapeSpatialGizmo::CollisionShapeSpatialGizmo(CollisionShape* p_cs) {
+
+ cs=p_cs;
+ set_spatial_node(p_cs);
+}
+
+
+
+/////
+
+
+void CollisionPolygonSpatialGizmo::redraw() {
+
+ clear();
+
+ Vector<Vector2> points = polygon->get_polygon();
+ float depth = polygon->get_depth()*0.5;
+
+ Vector<Vector3> lines;
+ for(int i=0;i<points.size();i++) {
+
+ int n = (i+1)%points.size();
+ lines.push_back(Vector3(points[i].x,points[i].y,depth));
+ lines.push_back(Vector3(points[n].x,points[n].y,depth));
+ lines.push_back(Vector3(points[i].x,points[i].y,-depth));
+ lines.push_back(Vector3(points[n].x,points[n].y,-depth));
+ lines.push_back(Vector3(points[i].x,points[i].y,depth));
+ lines.push_back(Vector3(points[i].x,points[i].y,-depth));
+
+ }
+
+ add_lines(lines,SpatialEditorGizmos::singleton->shape_material);
+ add_collision_segments(lines);
+}
+
+CollisionPolygonSpatialGizmo::CollisionPolygonSpatialGizmo(CollisionPolygon* p_polygon){
+
+ set_spatial_node(p_polygon);
+ polygon=p_polygon;
+}
+///
+
+
+String VisibilityNotifierGizmo::get_handle_name(int p_idx) const {
+
+ switch(p_idx) {
+ case 0: return "X";
+ case 1: return "Y";
+ case 2: return "Z";
+ }
+
+ return "";
+}
+Variant VisibilityNotifierGizmo::get_handle_value(int p_idx) const{
+
+ return notifier->get_aabb();
+}
+void VisibilityNotifierGizmo::set_handle(int p_idx,Camera *p_camera, const Point2& p_point){
+
+
+ Transform gt = notifier->get_global_transform();
+ //gt.orthonormalize();
+ Transform gi = gt.affine_inverse();
+
+ AABB aabb = notifier->get_aabb();
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+ Vector3 sg[2]={gi.xform(ray_from),gi.xform(ray_from+ray_dir*4096)};
+ Vector3 ofs = aabb.pos+aabb.size*0.5;;
+
+ Vector3 axis;
+ axis[p_idx]=1.0;
+
+ Vector3 ra,rb;
+ Geometry::get_closest_points_between_segments(ofs,ofs+axis*4096,sg[0],sg[1],ra,rb);
+ float d = ra[p_idx];
+ if (d<0.001)
+ d=0.001;
+
+ Vector3 he = aabb.size;
+ aabb.pos[p_idx]=(aabb.pos[p_idx]+aabb.size[p_idx]*0.5)-d;
+ aabb.size[p_idx]=d*2;
+ notifier->set_aabb(aabb);
+}
+
+void VisibilityNotifierGizmo::commit_handle(int p_idx,const Variant& p_restore,bool p_cancel){
+
+
+ if (p_cancel) {
+ notifier->set_aabb(p_restore);
+ return;
+ }
+
+ UndoRedo *ur = SpatialEditor::get_singleton()->get_undo_redo();
+ ur->create_action("Change Notifier Extents");
+ ur->add_do_method(notifier,"set_aabb",notifier->get_aabb());
+ ur->add_undo_method(notifier,"set_aabb",p_restore);
+ ur->commit_action();
+
+}
+
+void VisibilityNotifierGizmo::redraw(){
+
+ clear();
+
+ Vector<Vector3> lines;
+ AABB aabb = notifier->get_aabb();
+
+ for(int i=0;i<12;i++) {
+ Vector3 a,b;
+ aabb.get_edge(i,a,b);
+ lines.push_back(a);
+ lines.push_back(b);
+ }
+
+ Vector<Vector3> handles;
+
+
+ for(int i=0;i<3;i++) {
+
+ Vector3 ax;
+ ax[i]=aabb.pos[i]+aabb.size[i];
+ handles.push_back(ax);
+ }
+
+ add_lines(lines,SpatialEditorGizmos::singleton->visibility_notifier_material);
+ //add_unscaled_billboard(SpatialEditorGizmos::singleton->visi,0.05);
+ add_collision_segments(lines);
+ add_handles(handles);
+
+}
+VisibilityNotifierGizmo::VisibilityNotifierGizmo(VisibilityNotifier* p_notifier){
+
+ notifier=p_notifier;
+ set_spatial_node(p_notifier);
+}
+
+////////
+
+
+
+void NavigationMeshSpatialGizmo::redraw() {
+
+ clear();
+ Ref<NavigationMesh> navmeshie = navmesh->get_navigation_mesh();
+ if (navmeshie.is_null())
+ return;
+
+ DVector<Vector3> vertices = navmeshie->get_vertices();
+ DVector<Vector3>::Read vr=vertices.read();
+ List<Face3> faces;
+ for(int i=0;i<navmeshie->get_polygon_count();i++) {
+ Vector<int> p = navmeshie->get_polygon(i);
+
+ for(int j=2;j<p.size();j++) {
+ Face3 f;
+ f.vertex[0]=vr[p[0]];
+ f.vertex[1]=vr[p[j-1]];
+ f.vertex[2]=vr[p[j]];
+
+ faces.push_back(f);
+ }
+ }
+
+ if (faces.empty())
+ return;
+
+ Map<_EdgeKey,bool> edge_map;
+ DVector<Vector3> tmeshfaces;
+ tmeshfaces.resize(faces.size()*3);
+
+ {
+ DVector<Vector3>::Write tw=tmeshfaces.write();
+ int tidx=0;
+
+
+ for(List<Face3>::Element *E=faces.front();E;E=E->next()) {
+
+ const Face3 &f = E->get();
+
+ for(int j=0;j<3;j++) {
+
+ tw[tidx++]=f.vertex[j];
+ _EdgeKey ek;
+ ek.from=f.vertex[j].snapped(CMP_EPSILON);
+ ek.to=f.vertex[(j+1)%3].snapped(CMP_EPSILON);
+ if (ek.from<ek.to)
+ SWAP(ek.from,ek.to);
+
+ Map<_EdgeKey,bool>::Element *E=edge_map.find(ek);
+
+ if (E) {
+
+ E->get()=false;
+
+ } else {
+
+ edge_map[ek]=true;
+ }
+
+ }
+ }
+ }
+ Vector<Vector3> lines;
+
+ for(Map<_EdgeKey,bool>::Element *E=edge_map.front();E;E=E->next()) {
+
+ if (E->get()) {
+ lines.push_back(E->key().from);
+ lines.push_back(E->key().to);
+ }
+ }
+
+ Ref<TriangleMesh> tmesh = memnew( TriangleMesh );
+ tmesh->create(tmeshfaces);
+
+ if (lines.size())
+ add_lines(lines,navmesh->is_enabled()?SpatialEditorGizmos::singleton->navmesh_edge_material:SpatialEditorGizmos::singleton->navmesh_edge_material_disabled);
+ add_collision_triangles(tmesh);
+ Ref<Mesh> m = memnew( Mesh );
+ Array a;
+ a.resize(Mesh::ARRAY_MAX);
+ a[0]=tmeshfaces;
+ m->add_surface(Mesh::PRIMITIVE_TRIANGLES,a);
+ m->surface_set_material(0,navmesh->is_enabled()?SpatialEditorGizmos::singleton->navmesh_solid_material:SpatialEditorGizmos::singleton->navmesh_solid_material_disabled);
+ add_mesh(m);
+ add_collision_segments(lines);
+
+}
+
+NavigationMeshSpatialGizmo::NavigationMeshSpatialGizmo(NavigationMeshInstance *p_navmesh){
+
+ set_spatial_node(p_navmesh);
+ navmesh=p_navmesh;
+}
+
+//////
+///
+///
+
+
+
+void PinJointSpatialGizmo::redraw() {
+
+ clear();
+ Vector<Vector3> cursor_points;
+ float cs = 0.25;
+ cursor_points.push_back(Vector3(+cs,0,0));
+ cursor_points.push_back(Vector3(-cs,0,0));
+ cursor_points.push_back(Vector3(0,+cs,0));
+ cursor_points.push_back(Vector3(0,-cs,0));
+ cursor_points.push_back(Vector3(0,0,+cs));
+ cursor_points.push_back(Vector3(0,0,-cs));
+ add_collision_segments(cursor_points);
+ add_lines(cursor_points,SpatialEditorGizmos::singleton->joint_material);
+
+}
+
+
+PinJointSpatialGizmo::PinJointSpatialGizmo(PinJoint* p_p3d) {
+
+ p3d=p_p3d;
+ set_spatial_node(p3d);
+}
+
+////
+
+void HingeJointSpatialGizmo::redraw() {
+
+ clear();
+ Vector<Vector3> cursor_points;
+ float cs = 0.25;
+ /*cursor_points.push_back(Vector3(+cs,0,0));
+ cursor_points.push_back(Vector3(-cs,0,0));
+ cursor_points.push_back(Vector3(0,+cs,0));
+ cursor_points.push_back(Vector3(0,-cs,0));*/
+ cursor_points.push_back(Vector3(0,0,+cs*2));
+ cursor_points.push_back(Vector3(0,0,-cs*2));
+
+ float ll = p3d->get_param(HingeJoint::PARAM_LIMIT_LOWER);
+ float ul = p3d->get_param(HingeJoint::PARAM_LIMIT_UPPER);
+
+ if (p3d->get_flag(HingeJoint::FLAG_USE_LIMIT) && ll<ul) {
+
+ const int points = 32;
+ float step = (ul-ll)/points;
+
+
+ for(int i=0;i<points;i++) {
+
+ float s = ll+i*(ul-ll)/points;
+ float n = ll+(i+1)*(ul-ll)/points;
+
+ Vector3 from=Vector3( -Math::sin(s),Math::cos(s), 0 )*cs;
+ Vector3 to=Vector3( -Math::sin(n),Math::cos(n), 0 )*cs;
+
+ if (i==points-1) {
+ cursor_points.push_back(to);
+ cursor_points.push_back(Vector3());
+ }
+ if (i==0) {
+ cursor_points.push_back(from);
+ cursor_points.push_back(Vector3());
+ }
+
+
+ cursor_points.push_back(from);
+ cursor_points.push_back(to);
+
+
+ }
+
+ cursor_points.push_back(Vector3(0,cs*1.5,0));
+ cursor_points.push_back(Vector3());
+
+ } else {
+
+
+ const int points = 32;
+
+ for(int i=0;i<points;i++) {
+
+ float s = ll+i*(Math_PI*2.0)/points;
+ float n = ll+(i+1)*(Math_PI*2.0)/points;
+
+ Vector3 from=Vector3( -Math::sin(s),Math::cos(s), 0 )*cs;
+ Vector3 to=Vector3( -Math::sin(n),Math::cos(n), 0 )*cs;
+
+ cursor_points.push_back(from);
+ cursor_points.push_back(to);
+
+ }
+
+ }
+ add_collision_segments(cursor_points);
+ add_lines(cursor_points,SpatialEditorGizmos::singleton->joint_material);
+
+}
+
+
+HingeJointSpatialGizmo::HingeJointSpatialGizmo(HingeJoint* p_p3d) {
+
+ p3d=p_p3d;
+ set_spatial_node(p3d);
+}
+
+///////
+///
+////
+
+void SliderJointSpatialGizmo::redraw() {
+
+ clear();
+ Vector<Vector3> cursor_points;
+ float cs = 0.25;
+ /*cursor_points.push_back(Vector3(+cs,0,0));
+ cursor_points.push_back(Vector3(-cs,0,0));
+ cursor_points.push_back(Vector3(0,+cs,0));
+ cursor_points.push_back(Vector3(0,-cs,0));*/
+ cursor_points.push_back(Vector3(0,0,+cs*2));
+ cursor_points.push_back(Vector3(0,0,-cs*2));
+
+ float ll = p3d->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_LOWER);
+ float ul = p3d->get_param(SliderJoint::PARAM_ANGULAR_LIMIT_UPPER);
+ float lll = -p3d->get_param(SliderJoint::PARAM_LINEAR_LIMIT_LOWER);
+ float lul = -p3d->get_param(SliderJoint::PARAM_LINEAR_LIMIT_UPPER);
+
+ if (lll>lul) {
+
+ cursor_points.push_back(Vector3(lul,0,0));
+ cursor_points.push_back(Vector3(lll,0,0));
+
+ cursor_points.push_back(Vector3(lul,-cs,-cs));
+ cursor_points.push_back(Vector3(lul,-cs,cs));
+ cursor_points.push_back(Vector3(lul,-cs,cs));
+ cursor_points.push_back(Vector3(lul,cs,cs));
+ cursor_points.push_back(Vector3(lul,cs,cs));
+ cursor_points.push_back(Vector3(lul,cs,-cs));
+ cursor_points.push_back(Vector3(lul,cs,-cs));
+ cursor_points.push_back(Vector3(lul,-cs,-cs));
+
+
+ cursor_points.push_back(Vector3(lll,-cs,-cs));
+ cursor_points.push_back(Vector3(lll,-cs,cs));
+ cursor_points.push_back(Vector3(lll,-cs,cs));
+ cursor_points.push_back(Vector3(lll,cs,cs));
+ cursor_points.push_back(Vector3(lll,cs,cs));
+ cursor_points.push_back(Vector3(lll,cs,-cs));
+ cursor_points.push_back(Vector3(lll,cs,-cs));
+ cursor_points.push_back(Vector3(lll,-cs,-cs));
+
+
+ } else {
+
+ cursor_points.push_back(Vector3(+cs*2,0,0));
+ cursor_points.push_back(Vector3(-cs*2,0,0));
+
+ }
+
+ if (ll<ul) {
+
+ const int points = 32;
+ float step = (ul-ll)/points;
+
+
+ for(int i=0;i<points;i++) {
+
+ float s = ll+i*(ul-ll)/points;
+ float n = ll+(i+1)*(ul-ll)/points;
+
+ Vector3 from=Vector3(0, Math::cos(s), -Math::sin(s) )*cs;
+ Vector3 to=Vector3(0,Math::cos(n), -Math::sin(n) )*cs;
+
+ if (i==points-1) {
+ cursor_points.push_back(to);
+ cursor_points.push_back(Vector3());
+ }
+ if (i==0) {
+ cursor_points.push_back(from);
+ cursor_points.push_back(Vector3());
+ }
+
+
+ cursor_points.push_back(from);
+ cursor_points.push_back(to);
+
+
+ }
+
+ cursor_points.push_back(Vector3(0,cs*1.5,0));
+ cursor_points.push_back(Vector3());
+
+ } else {
+
+
+ const int points = 32;
+
+ for(int i=0;i<points;i++) {
+
+ float s = ll+i*(Math_PI*2.0)/points;
+ float n = ll+(i+1)*(Math_PI*2.0)/points;
+
+ Vector3 from=Vector3(0,Math::cos(s),-Math::sin(s) )*cs;
+ Vector3 to=Vector3( 0,Math::cos(n),-Math::sin(n) )*cs;
+
+ cursor_points.push_back(from);
+ cursor_points.push_back(to);
+
+ }
+
+ }
+ add_collision_segments(cursor_points);
+ add_lines(cursor_points,SpatialEditorGizmos::singleton->joint_material);
+
+}
+
+
+SliderJointSpatialGizmo::SliderJointSpatialGizmo(SliderJoint* p_p3d) {
+
+ p3d=p_p3d;
+ set_spatial_node(p3d);
+}
+
+///////
+///
+////
+
+void ConeTwistJointSpatialGizmo::redraw() {
+
+ clear();
+ float cs = 0.25;
+ Vector<Vector3> points;
+
+ float r = 1.0;
+ float w = r*Math::sin(p3d->get_param(ConeTwistJoint::PARAM_SWING_SPAN));
+ float d = r*Math::cos(p3d->get_param(ConeTwistJoint::PARAM_SWING_SPAN));
+
+
+ //swing
+ for(int i=0;i<360;i+=10) {
+
+ float ra=Math::deg2rad(i);
+ float rb=Math::deg2rad(i+10);
+ Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*w;
+ Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*w;
+
+ /*points.push_back(Vector3(a.x,0,a.y));
+ points.push_back(Vector3(b.x,0,b.y));
+ points.push_back(Vector3(0,a.x,a.y));
+ points.push_back(Vector3(0,b.x,b.y));*/
+ points.push_back(Vector3(d,a.x,a.y));
+ points.push_back(Vector3(d,b.x,b.y));
+
+ if (i%90==0) {
+
+ points.push_back(Vector3(d,a.x,a.y));
+ points.push_back(Vector3());
+
+ }
+ }
+
+ points.push_back(Vector3());
+ points.push_back(Vector3(1,0,0));
+
+ //twist
+ /*
+ */
+ float ts=Math::rad2deg(p3d->get_param(ConeTwistJoint::PARAM_TWIST_SPAN));
+ ts=MIN(ts,720);
+
+
+ for(int i=0;i<int(ts);i+=5) {
+
+ float ra=Math::deg2rad(i);
+ float rb=Math::deg2rad(i+5);
+ float c = i/720.0;
+ float cn = (i+5)/720.0;
+ Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*w*c;
+ Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*w*cn;
+
+ /*points.push_back(Vector3(a.x,0,a.y));
+ points.push_back(Vector3(b.x,0,b.y));
+ points.push_back(Vector3(0,a.x,a.y));
+ points.push_back(Vector3(0,b.x,b.y));*/
+
+ points.push_back(Vector3(c,a.x,a.y));
+ points.push_back(Vector3(cn,b.x,b.y));
+
+ }
+
+
+ add_collision_segments(points);
+ add_lines(points,SpatialEditorGizmos::singleton->joint_material);
+
+}
+
+
+ConeTwistJointSpatialGizmo::ConeTwistJointSpatialGizmo(ConeTwistJoint* p_p3d) {
+
+ p3d=p_p3d;
+ set_spatial_node(p3d);
+}
+
+////////
+/// \brief SpatialEditorGizmos::singleton
+///
+///////
+///
+////
+
+void Generic6DOFJointSpatialGizmo::redraw() {
+
+ clear();
+ Vector<Vector3> cursor_points;
+ float cs = 0.25;
+
+ for(int ax=0;ax<3;ax++) {
+ /*cursor_points.push_back(Vector3(+cs,0,0));
+ cursor_points.push_back(Vector3(-cs,0,0));
+ cursor_points.push_back(Vector3(0,+cs,0));
+ cursor_points.push_back(Vector3(0,-cs,0));
+ cursor_points.push_back(Vector3(0,0,+cs*2));
+ cursor_points.push_back(Vector3(0,0,-cs*2)); */
+
+ float ll;
+ float ul;
+ float lll;
+ float lul;
+
+ int a1,a2,a3;
+ bool enable_ang;
+ bool enable_lin;
+
+ switch(ax) {
+ case 0:
+ ll = p3d->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT);
+ ul = p3d->get_param_x(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT);
+ lll = -p3d->get_param_x(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT);
+ lul = -p3d->get_param_x(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT);
+ enable_ang = p3d->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT);
+ enable_lin = p3d->get_flag_x(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT);
+ a1=0;
+ a2=1;
+ a3=2;
+ break;
+ case 1:
+ ll = p3d->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT);
+ ul = p3d->get_param_y(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT);
+ lll = -p3d->get_param_y(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT);
+ lul = -p3d->get_param_y(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT);
+ enable_ang = p3d->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT);
+ enable_lin = p3d->get_flag_y(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT);
+ a1=2;
+ a2=0;
+ a3=1;
+ break;
+ case 2:
+ ll = p3d->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_LOWER_LIMIT);
+ ul = p3d->get_param_z(Generic6DOFJoint::PARAM_ANGULAR_UPPER_LIMIT);
+ lll = -p3d->get_param_z(Generic6DOFJoint::PARAM_LINEAR_LOWER_LIMIT);
+ lul = -p3d->get_param_z(Generic6DOFJoint::PARAM_LINEAR_UPPER_LIMIT);
+ enable_ang = p3d->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_ANGULAR_LIMIT);
+ enable_lin = p3d->get_flag_z(Generic6DOFJoint::FLAG_ENABLE_LINEAR_LIMIT);
+
+ a1=1;
+ a2=2;
+ a3=0;
+ break;
+ }
+
+#define ADD_VTX(x,y,z)\
+ {\
+ Vector3 v;\
+ v[a1]=(x);\
+ v[a2]=(y);\
+ v[a3]=(z);\
+ cursor_points.push_back(v);\
+ }
+
+#define SET_VTX(what,x,y,z)\
+ {\
+ Vector3 v;\
+ v[a1]=(x);\
+ v[a2]=(y);\
+ v[a3]=(z);\
+ what=v;\
+ }
+
+
+
+
+ if (enable_lin && lll>=lul) {
+
+ ADD_VTX(lul,0,0);
+ ADD_VTX(lll,0,0);
+
+ ADD_VTX(lul,-cs,-cs);
+ ADD_VTX(lul,-cs,cs);
+ ADD_VTX(lul,-cs,cs);
+ ADD_VTX(lul,cs,cs);
+ ADD_VTX(lul,cs,cs);
+ ADD_VTX(lul,cs,-cs);
+ ADD_VTX(lul,cs,-cs);
+ ADD_VTX(lul,-cs,-cs);
+
+
+ ADD_VTX(lll,-cs,-cs);
+ ADD_VTX(lll,-cs,cs);
+ ADD_VTX(lll,-cs,cs);
+ ADD_VTX(lll,cs,cs);
+ ADD_VTX(lll,cs,cs);
+ ADD_VTX(lll,cs,-cs);
+ ADD_VTX(lll,cs,-cs);
+ ADD_VTX(lll,-cs,-cs);
+
+
+ } else {
+
+ ADD_VTX(+cs*2,0,0);
+ ADD_VTX(-cs*2,0,0);
+
+ }
+
+ if (enable_ang && ll<=ul) {
+
+ const int points = 32;
+ float step = (ul-ll)/points;
+
+
+ for(int i=0;i<points;i++) {
+
+ float s = ll+i*(ul-ll)/points;
+ float n = ll+(i+1)*(ul-ll)/points;
+
+ Vector3 from;
+ SET_VTX(from,0, Math::cos(s), -Math::sin(s) );
+ from*=cs;
+ Vector3 to;
+ SET_VTX(to,0,Math::cos(n), -Math::sin(n));
+ to*=cs;
+
+ if (i==points-1) {
+ cursor_points.push_back(to);
+ cursor_points.push_back(Vector3());
+ }
+ if (i==0) {
+ cursor_points.push_back(from);
+ cursor_points.push_back(Vector3());
+ }
+
+
+ cursor_points.push_back(from);
+ cursor_points.push_back(to);
+
+
+ }
+
+ ADD_VTX(0,cs*1.5,0);
+ cursor_points.push_back(Vector3());
+
+ } else {
+
+
+ const int points = 32;
+
+ for(int i=0;i<points;i++) {
+
+ float s = ll+i*(Math_PI*2.0)/points;
+ float n = ll+(i+1)*(Math_PI*2.0)/points;
+
+// Vector3 from=Vector3(0,Math::cos(s),-Math::sin(s) )*cs;
+// Vector3 to=Vector3( 0,Math::cos(n),-Math::sin(n) )*cs;
+
+ Vector3 from;
+ SET_VTX(from,0, Math::cos(s), -Math::sin(s) );
+ from*=cs;
+ Vector3 to;
+ SET_VTX(to,0,Math::cos(n), -Math::sin(n));
+ to*=cs;
+
+ cursor_points.push_back(from);
+ cursor_points.push_back(to);
+
+ }
+
+ }
+ }
+
+#undef ADD_VTX
+#undef SET_VTX
+
+ add_collision_segments(cursor_points);
+ add_lines(cursor_points,SpatialEditorGizmos::singleton->joint_material);
+
+}
+
+
+Generic6DOFJointSpatialGizmo::Generic6DOFJointSpatialGizmo(Generic6DOFJoint* p_p3d) {
+
+ p3d=p_p3d;
+ set_spatial_node(p3d);
+}
+
+///////
+///
+////
+
+
+SpatialEditorGizmos *SpatialEditorGizmos::singleton=NULL;
+
+Ref<SpatialEditorGizmo> SpatialEditorGizmos::get_gizmo(Spatial *p_spatial) {
+
+ if (p_spatial->cast_to<Light>()) {
+
+ Ref<LightSpatialGizmo> lsg = memnew( LightSpatialGizmo(p_spatial->cast_to<Light>()) );
+ return lsg;
+ }
+
+ if (p_spatial->cast_to<Camera>()) {
+
+ Ref<CameraSpatialGizmo> lsg = memnew( CameraSpatialGizmo(p_spatial->cast_to<Camera>()) );
+ return lsg;
+ }
+
+ if (p_spatial->cast_to<Skeleton>()) {
+
+ Ref<SkeletonSpatialGizmo> lsg = memnew( SkeletonSpatialGizmo(p_spatial->cast_to<Skeleton>()) );
+ return lsg;
+ }
+
+
+ if (p_spatial->cast_to<Position3D>()) {
+
+ Ref<Position3DSpatialGizmo> lsg = memnew( Position3DSpatialGizmo(p_spatial->cast_to<Position3D>()) );
+ return lsg;
+ }
+
+ if (p_spatial->cast_to<MeshInstance>()) {
+
+ Ref<MeshInstanceSpatialGizmo> misg = memnew( MeshInstanceSpatialGizmo(p_spatial->cast_to<MeshInstance>()) );
+ return misg;
+ }
+
+ if (p_spatial->cast_to<Room>()) {
+
+ Ref<RoomSpatialGizmo> misg = memnew( RoomSpatialGizmo(p_spatial->cast_to<Room>()) );
+ return misg;
+ }
+
+ if (p_spatial->cast_to<NavigationMeshInstance>()) {
+
+ Ref<NavigationMeshSpatialGizmo> misg = memnew( NavigationMeshSpatialGizmo(p_spatial->cast_to<NavigationMeshInstance>()) );
+ return misg;
+ }
+
+ if (p_spatial->cast_to<RayCast>()) {
+
+ Ref<RayCastSpatialGizmo> misg = memnew( RayCastSpatialGizmo(p_spatial->cast_to<RayCast>()) );
+ return misg;
+ }
+
+ if (p_spatial->cast_to<Portal>()) {
+
+ Ref<PortalSpatialGizmo> misg = memnew( PortalSpatialGizmo(p_spatial->cast_to<Portal>()) );
+ return misg;
+ }
+
+
+ if (p_spatial->cast_to<TestCube>()) {
+
+ Ref<TestCubeSpatialGizmo> misg = memnew( TestCubeSpatialGizmo(p_spatial->cast_to<TestCube>()) );
+ return misg;
+ }
+
+ if (p_spatial->cast_to<SpatialPlayer>()) {
+
+ Ref<SpatialPlayerSpatialGizmo> misg = memnew( SpatialPlayerSpatialGizmo(p_spatial->cast_to<SpatialPlayer>()) );
+ return misg;
+ }
+
+ if (p_spatial->cast_to<CollisionShape>()) {
+
+ Ref<CollisionShapeSpatialGizmo> misg = memnew( CollisionShapeSpatialGizmo(p_spatial->cast_to<CollisionShape>()) );
+ return misg;
+ }
+
+ if (p_spatial->cast_to<VisibilityNotifier>()) {
+
+ Ref<VisibilityNotifierGizmo> misg = memnew( VisibilityNotifierGizmo(p_spatial->cast_to<VisibilityNotifier>()) );
+ return misg;
+ }
+
+ if (p_spatial->cast_to<VehicleWheel>()) {
+
+ Ref<VehicleWheelSpatialGizmo> misg = memnew( VehicleWheelSpatialGizmo(p_spatial->cast_to<VehicleWheel>()) );
+ return misg;
+ }
+ if (p_spatial->cast_to<PinJoint>()) {
+
+ Ref<PinJointSpatialGizmo> misg = memnew( PinJointSpatialGizmo(p_spatial->cast_to<PinJoint>()) );
+ return misg;
+ }
+
+ if (p_spatial->cast_to<HingeJoint>()) {
+
+ Ref<HingeJointSpatialGizmo> misg = memnew( HingeJointSpatialGizmo(p_spatial->cast_to<HingeJoint>()) );
+ return misg;
+ }
+
+ if (p_spatial->cast_to<SliderJoint>()) {
+
+ Ref<SliderJointSpatialGizmo> misg = memnew( SliderJointSpatialGizmo(p_spatial->cast_to<SliderJoint>()) );
+ return misg;
+ }
+
+ if (p_spatial->cast_to<ConeTwistJoint>()) {
+
+ Ref<ConeTwistJointSpatialGizmo> misg = memnew( ConeTwistJointSpatialGizmo(p_spatial->cast_to<ConeTwistJoint>()) );
+ return misg;
+ }
+
+ if (p_spatial->cast_to<Generic6DOFJoint>()) {
+
+ Ref<Generic6DOFJointSpatialGizmo> misg = memnew( Generic6DOFJointSpatialGizmo(p_spatial->cast_to<Generic6DOFJoint>()) );
+ return misg;
+ }
+
+ if (p_spatial->cast_to<CollisionPolygon>()) {
+
+ Ref<CollisionPolygonSpatialGizmo> misg = memnew( CollisionPolygonSpatialGizmo(p_spatial->cast_to<CollisionPolygon>()) );
+ return misg;
+ }
+
+
+ return Ref<SpatialEditorGizmo>();
+}
+
+
+Ref<FixedMaterial> SpatialEditorGizmos::create_line_material(const Color& p_base_color) {
+
+ Ref<FixedMaterial> line_material = Ref<FixedMaterial>( memnew( FixedMaterial ));
+ line_material->set_flag(Material::FLAG_UNSHADED, true);
+ line_material->set_line_width(3.0);
+ line_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
+ line_material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, true);
+ line_material->set_parameter(FixedMaterial::PARAM_DIFFUSE,p_base_color);
+
+ return line_material;
+
+}
+
+Ref<FixedMaterial> SpatialEditorGizmos::create_solid_material(const Color& p_base_color) {
+
+ Ref<FixedMaterial> line_material = Ref<FixedMaterial>( memnew( FixedMaterial ));
+ line_material->set_flag(Material::FLAG_UNSHADED, true);
+ line_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
+ line_material->set_parameter(FixedMaterial::PARAM_DIFFUSE,p_base_color);
+
+ return line_material;
+
+}
+
+SpatialEditorGizmos::SpatialEditorGizmos() {
+
+ singleton=this;
+
+ handle_material = Ref<FixedMaterial>( memnew( FixedMaterial ));
+ handle_material->set_flag(Material::FLAG_UNSHADED, true);
+ handle_material->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(0.8,0.8,0.8));
+
+ handle2_material = Ref<FixedMaterial>( memnew( FixedMaterial ));
+ handle2_material->set_flag(Material::FLAG_UNSHADED, true);
+ handle2_material->set_fixed_flag(FixedMaterial::FLAG_USE_POINT_SIZE, true);
+ handle_t = SpatialEditor::get_singleton()->get_icon("Editor3DHandle","EditorIcons");
+ handle2_material->set_point_size(handle_t->get_width());
+ handle2_material->set_texture(FixedMaterial::PARAM_DIFFUSE,handle_t);
+ handle2_material->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1));
+ handle2_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
+ handle2_material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, true);
+
+ light_material = create_line_material(Color(1,1,0.2));
+
+ light_material_omni_icon = Ref<FixedMaterial>( memnew( FixedMaterial ));
+ light_material_omni_icon->set_flag(Material::FLAG_UNSHADED, true);
+ light_material_omni_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true);
+ light_material_omni_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER);
+ light_material_omni_icon->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
+ light_material_omni_icon->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1,0.9));
+ light_material_omni_icon->set_texture(FixedMaterial::PARAM_DIFFUSE,SpatialEditor::get_singleton()->get_icon("GizmoLight","EditorIcons"));
+
+
+ light_material_directional_icon = Ref<FixedMaterial>( memnew( FixedMaterial ));
+ light_material_directional_icon->set_flag(Material::FLAG_UNSHADED, true);
+ light_material_directional_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true);
+ light_material_directional_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER);
+ light_material_directional_icon->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
+ light_material_directional_icon->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1,0.9));
+ light_material_directional_icon->set_texture(FixedMaterial::PARAM_DIFFUSE,SpatialEditor::get_singleton()->get_icon("GizmoDirectionalLight","EditorIcons"));
+
+ camera_material = create_line_material(Color(1.0,0.5,1.0));
+
+
+ navmesh_edge_material = create_line_material(Color(0.1,0.8,1.0));
+ navmesh_solid_material = create_solid_material(Color(0.1,0.8,1.0,0.4));
+ navmesh_edge_material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, false);
+ navmesh_solid_material->set_flag(Material::FLAG_DOUBLE_SIDED,true);
+
+ navmesh_edge_material_disabled = create_line_material(Color(1.0,0.8,0.1));
+ navmesh_solid_material_disabled = create_solid_material(Color(1.0,0.8,0.1,0.4));
+ navmesh_edge_material_disabled->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, false);
+ navmesh_solid_material_disabled->set_flag(Material::FLAG_DOUBLE_SIDED,true);
+
+ skeleton_material = create_line_material(Color(0.6,1.0,0.3));
+ skeleton_material->set_flag(Material::FLAG_DOUBLE_SIDED,true);
+ skeleton_material->set_flag(Material::FLAG_UNSHADED,true);
+ skeleton_material->set_flag(Material::FLAG_ONTOP,true);
+ skeleton_material->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER);
+
+ //position 3D Shared mesh
+
+ pos3d_mesh = Ref<Mesh>( memnew( Mesh ) );
+ {
+
+ DVector<Vector3> cursor_points;
+ DVector<Color> cursor_colors;
+ float cs = 0.25;
+ cursor_points.push_back(Vector3(+cs,0,0));
+ cursor_points.push_back(Vector3(-cs,0,0));
+ cursor_points.push_back(Vector3(0,+cs,0));
+ cursor_points.push_back(Vector3(0,-cs,0));
+ cursor_points.push_back(Vector3(0,0,+cs));
+ cursor_points.push_back(Vector3(0,0,-cs));
+ cursor_colors.push_back(Color(1,0.5,0.5,0.7));
+ cursor_colors.push_back(Color(1,0.5,0.5,0.7));
+ cursor_colors.push_back(Color(0.5,1,0.5,0.7));
+ cursor_colors.push_back(Color(0.5,1,0.5,0.7));
+ cursor_colors.push_back(Color(0.5,0.5,1,0.7));
+ cursor_colors.push_back(Color(0.5,0.5,1,0.7));
+
+ Ref<FixedMaterial> mat = memnew( FixedMaterial );
+ mat->set_flag(Material::FLAG_UNSHADED,true);
+ mat->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY,true);
+ mat->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA,true);
+ mat->set_line_width(3);
+ Array d;
+ d.resize(VS::ARRAY_MAX);
+ d[Mesh::ARRAY_VERTEX]=cursor_points;
+ d[Mesh::ARRAY_COLOR]=cursor_colors;
+ pos3d_mesh->add_surface(Mesh::PRIMITIVE_LINES,d);
+ pos3d_mesh->surface_set_material(0,mat);
+ }
+
+
+ sample_player_icon = Ref<FixedMaterial>( memnew( FixedMaterial ));
+ sample_player_icon->set_flag(Material::FLAG_UNSHADED, true);
+ sample_player_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true);
+ sample_player_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER);
+ sample_player_icon->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
+ sample_player_icon->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1,0.9));
+ sample_player_icon->set_texture(FixedMaterial::PARAM_DIFFUSE,SpatialEditor::get_singleton()->get_icon("GizmoSpatialSamplePlayer","EditorIcons"));
+
+ room_material = create_line_material(Color(1.0,0.6,0.9));
+ portal_material = create_line_material(Color(1.0,0.8,0.6));
+ raycast_material = create_line_material(Color(1.0,0.8,0.6));
+ car_wheel_material = create_line_material(Color(0.6,0.8,1.0));
+ visibility_notifier_material = create_line_material(Color(1.0,0.5,1.0));
+ joint_material = create_line_material(Color(0.6,0.8,1.0));
+
+ stream_player_icon = Ref<FixedMaterial>( memnew( FixedMaterial ));
+ stream_player_icon->set_flag(Material::FLAG_UNSHADED, true);
+ stream_player_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true);
+ stream_player_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER);
+ stream_player_icon->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
+ stream_player_icon->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1,0.9));
+ stream_player_icon->set_texture(FixedMaterial::PARAM_DIFFUSE,SpatialEditor::get_singleton()->get_icon("GizmoSpatialStreamPlayer","EditorIcons"));
+
+ visibility_notifier_icon = Ref<FixedMaterial>( memnew( FixedMaterial ));
+ visibility_notifier_icon->set_flag(Material::FLAG_UNSHADED, true);
+ visibility_notifier_icon->set_flag(Material::FLAG_DOUBLE_SIDED, true);
+ visibility_notifier_icon->set_depth_draw_mode(Material::DEPTH_DRAW_NEVER);
+ visibility_notifier_icon->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true);
+ visibility_notifier_icon->set_parameter(FixedMaterial::PARAM_DIFFUSE,Color(1,1,1,0.9));
+ visibility_notifier_icon->set_texture(FixedMaterial::PARAM_DIFFUSE,SpatialEditor::get_singleton()->get_icon("Visible","EditorIcons"));
+
+ {
+
+ DVector<Vector3> vertices;
+
+#undef ADD_VTX
+#define ADD_VTX(m_idx);\
+ vertices.push_back( face_points[m_idx] );
+
+ for (int i=0;i<6;i++) {
+
+
+ Vector3 face_points[4];
+
+ for (int j=0;j<4;j++) {
+
+ float v[3];
+ v[0]=1.0;
+ v[1]=1-2*((j>>1)&1);
+ v[2]=v[1]*(1-2*(j&1));
+
+ for (int k=0;k<3;k++) {
+
+ if (i<3)
+ face_points[j][(i+k)%3]=v[k]*(i>=3?-1:1);
+ else
+ face_points[3-j][(i+k)%3]=v[k]*(i>=3?-1:1);
+ }
+ }
+ //tri 1
+ ADD_VTX(0);
+ ADD_VTX(1);
+ ADD_VTX(2);
+ //tri 2
+ ADD_VTX(2);
+ ADD_VTX(3);
+ ADD_VTX(0);
+
+ }
+
+ test_cube_tm = Ref<TriangleMesh>( memnew( TriangleMesh ) );
+ test_cube_tm->create(vertices);
+ }
+
+ shape_material = create_line_material(Color(0.2,1,1.0));
+
+
+}
+
diff --git a/tools/editor/spatial_editor_gizmos.h b/tools/editor/spatial_editor_gizmos.h
index 8d6730e2f1..669d3e2380 100644
--- a/tools/editor/spatial_editor_gizmos.h
+++ b/tools/editor/spatial_editor_gizmos.h
@@ -1,487 +1,491 @@
-/*************************************************************************/
-/* spatial_editor_gizmos.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* http://www.godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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. */
-/*************************************************************************/
-#ifndef SPATIAL_EDITOR_GIZMOS_H
-#define SPATIAL_EDITOR_GIZMOS_H
-
-
-#include "tools/editor/plugins/spatial_editor_plugin.h"
-#include "scene/3d/light.h"
-#include "scene/3d/camera.h"
-#include "scene/3d/position_3d.h"
-#include "scene/3d/spatial_sample_player.h"
-#include "scene/3d/spatial_stream_player.h"
-#include "scene/3d/test_cube.h"
-#include "scene/3d/mesh_instance.h"
-#include "scene/3d/body_shape.h"
-#include "scene/3d/room_instance.h"
-#include "scene/3d/visibility_notifier.h"
-#include "scene/3d/portal.h"
-#include "scene/3d/ray_cast.h"
-#include "scene/3d/navigation_mesh.h"
-
-#include "scene/3d/vehicle_body.h"
-#include "scene/3d/collision_polygon.h"
-#include "scene/3d/physics_joint.h"
-
-
-class Camera;
-
-class SpatialGizmoTool : public SpatialEditorGizmo {
-
- OBJ_TYPE(SpatialGizmoTool,SpatialGizmo);
-
- struct Instance{
-
- RID instance;
- Ref<Mesh> mesh;
- RID skeleton;
- bool billboard;
- bool unscaled;
- bool can_intersect;
- bool extra_margin;
- Instance() {
-
- billboard=false;
- unscaled=false;
- can_intersect=false;
- extra_margin=false;
- }
-
- void create_instance(Spatial *p_base);
-
- };
-
- Vector<Vector3> collision_segments;
- Ref<TriangleMesh> collision_mesh;
-
- struct Handle {
- Vector3 pos;
- bool billboard;
- };
-
- Vector<Vector3> handles;
- Vector<Vector3> secondary_handles;
- bool billboard_handle;
-
- bool valid;
- Spatial *base;
- Vector<Instance> instances;
- Spatial *spatial_node;
-protected:
- void add_lines(const Vector<Vector3> &p_lines,const Ref<Material>& p_material,bool p_billboard=false);
- void add_mesh(const Ref<Mesh>& p_mesh,bool p_billboard=false,const RID& p_skeleton=RID());
- void add_collision_segments(const Vector<Vector3> &p_lines);
- void add_collision_triangles(const Ref<TriangleMesh>& p_tmesh);
- void add_unscaled_billboard(const Ref<Material>& p_material,float p_scale=1);
- void add_handles(const Vector<Vector3> &p_handles,bool p_billboard=false,bool p_secondary=false);
-
- void set_spatial_node(Spatial *p_node);
-
-public:
-
- virtual Vector3 get_handle_pos(int p_idx) const;
- virtual bool intersect_frustum(const Camera *p_camera,const Vector<Plane> &p_frustum);
- virtual bool intersect_ray(const Camera *p_camera,const Point2& p_point, Vector3& r_pos, Vector3& r_normal,int *r_gizmo_handle=NULL,bool p_sec_first=false);
-
- void clear();
- void create();
- void transform();
- //void redraw();
- void free();
-
- SpatialGizmoTool();
- ~SpatialGizmoTool();
-};
-
-
-
-class LightSpatialGizmo : public SpatialGizmoTool {
-
- OBJ_TYPE(LightSpatialGizmo,SpatialGizmoTool);
-
- Light* light;
-
-public:
-
-
- virtual String get_handle_name(int p_idx) const;
- virtual Variant get_handle_value(int p_idx) const;
- virtual void set_handle(int p_idx,Camera *p_camera, const Point2& p_point);
- virtual void commit_handle(int p_idx,const Variant& p_restore,bool p_cancel=false);
-
- void redraw();
- LightSpatialGizmo(Light* p_light=NULL);
-
-};
-
-class CameraSpatialGizmo : public SpatialGizmoTool {
-
- OBJ_TYPE(CameraSpatialGizmo,SpatialGizmoTool);
-
- Camera* camera;
-
-public:
-
-
- virtual String get_handle_name(int p_idx) const;
- virtual Variant get_handle_value(int p_idx) const;
- virtual void set_handle(int p_idx,Camera *p_camera, const Point2& p_point);
- virtual void commit_handle(int p_idx,const Variant& p_restore,bool p_cancel=false);
-
- void redraw();
- CameraSpatialGizmo(Camera* p_camera=NULL);
-
-};
-
-
-
-class MeshInstanceSpatialGizmo : public SpatialGizmoTool {
-
- OBJ_TYPE(MeshInstanceSpatialGizmo,SpatialGizmoTool);
-
- MeshInstance* mesh;
-
-public:
-
- void redraw();
- MeshInstanceSpatialGizmo(MeshInstance* p_mesh=NULL);
-
-};
-
-class Position3DSpatialGizmo : public SpatialGizmoTool {
-
- OBJ_TYPE(Position3DSpatialGizmo,SpatialGizmoTool);
-
- Position3D* p3d;
-
-public:
-
- void redraw();
- Position3DSpatialGizmo(Position3D* p_p3d=NULL);
-
-};
-
-class SkeletonSpatialGizmo : public SpatialGizmoTool {
-
- OBJ_TYPE(SkeletonSpatialGizmo,SpatialGizmoTool);
-
- Skeleton* skel;
-
-public:
-
- void redraw();
- SkeletonSpatialGizmo(Skeleton* p_skel=NULL);
-
-};
-
-
-class SpatialPlayerSpatialGizmo : public SpatialGizmoTool {
-
- OBJ_TYPE(SpatialPlayerSpatialGizmo,SpatialGizmoTool);
-
- SpatialPlayer* splayer;
-
-public:
-
- void redraw();
- SpatialPlayerSpatialGizmo(SpatialPlayer* p_splayer=NULL);
-
-};
-
-class TestCubeSpatialGizmo : public SpatialGizmoTool {
-
- OBJ_TYPE(TestCubeSpatialGizmo,SpatialGizmoTool);
-
- TestCube* tc;
-
-public:
- void redraw();
- TestCubeSpatialGizmo(TestCube* p_tc=NULL);
-
-};
-
-
-class RoomSpatialGizmo : public SpatialGizmoTool {
-
- OBJ_TYPE(RoomSpatialGizmo,SpatialGizmoTool);
-
-
- struct _EdgeKey {
-
- Vector3 from;
- Vector3 to;
-
- bool operator<(const _EdgeKey& p_with) const { return from==p_with.from ? to < p_with.to : from < p_with.from; }
- };
-
-
-
- Room* room;
-
-public:
-
- void redraw();
- RoomSpatialGizmo(Room* p_room=NULL);
-
-};
-
-
-class PortalSpatialGizmo : public SpatialGizmoTool {
-
- OBJ_TYPE(PortalSpatialGizmo,SpatialGizmoTool);
-
- Portal* portal;
-
-public:
-
- void redraw();
- PortalSpatialGizmo(Portal* p_portal=NULL);
-
-};
-
-
-class VisibilityNotifierGizmo : public SpatialGizmoTool {
-
- OBJ_TYPE(VisibilityNotifierGizmo ,SpatialGizmoTool);
-
-
- VisibilityNotifier* notifier;
-
-public:
-
- virtual String get_handle_name(int p_idx) const;
- virtual Variant get_handle_value(int p_idx) const;
- virtual void set_handle(int p_idx,Camera *p_camera, const Point2& p_point);
- virtual void commit_handle(int p_idx,const Variant& p_restore,bool p_cancel=false);
-
- void redraw();
- VisibilityNotifierGizmo(VisibilityNotifier* p_notifier=NULL);
-
-};
-
-
-
-class CollisionShapeSpatialGizmo : public SpatialGizmoTool {
-
- OBJ_TYPE(CollisionShapeSpatialGizmo,SpatialGizmoTool);
-
- CollisionShape* cs;
-
-public:
- virtual String get_handle_name(int p_idx) const;
- virtual Variant get_handle_value(int p_idx) const;
- virtual void set_handle(int p_idx,Camera *p_camera, const Point2& p_point);
- virtual void commit_handle(int p_idx,const Variant& p_restore,bool p_cancel=false);
- void redraw();
- CollisionShapeSpatialGizmo(CollisionShape* p_cs=NULL);
-
-};
-
-
-class CollisionPolygonSpatialGizmo : public SpatialGizmoTool {
-
- OBJ_TYPE(CollisionPolygonSpatialGizmo,SpatialGizmoTool);
-
- CollisionPolygon* polygon;
-
-public:
-
- void redraw();
- CollisionPolygonSpatialGizmo(CollisionPolygon* p_polygon=NULL);
-
-};
-
-
-class RayCastSpatialGizmo : public SpatialGizmoTool {
-
- OBJ_TYPE(RayCastSpatialGizmo,SpatialGizmoTool);
-
- RayCast* raycast;
-
-public:
-
- void redraw();
- RayCastSpatialGizmo(RayCast* p_raycast=NULL);
-
-};
-
-
-
-class VehicleWheelSpatialGizmo : public SpatialGizmoTool {
-
- OBJ_TYPE(VehicleWheelSpatialGizmo,SpatialGizmoTool);
-
- VehicleWheel* car_wheel;
-
-public:
-
- void redraw();
- VehicleWheelSpatialGizmo(VehicleWheel* p_car_wheel=NULL);
-
-};
-
-
-class NavigationMeshSpatialGizmo : public SpatialGizmoTool {
-
- OBJ_TYPE(NavigationMeshSpatialGizmo,SpatialGizmoTool);
-
-
- struct _EdgeKey {
-
- Vector3 from;
- Vector3 to;
-
- bool operator<(const _EdgeKey& p_with) const { return from==p_with.from ? to < p_with.to : from < p_with.from; }
- };
-
-
-
- NavigationMeshInstance* navmesh;
-
-public:
-
- void redraw();
- NavigationMeshSpatialGizmo(NavigationMeshInstance* p_navmesh=NULL);
-
-};
-
-
-class PinJointSpatialGizmo : public SpatialGizmoTool {
-
- OBJ_TYPE(PinJointSpatialGizmo,SpatialGizmoTool);
-
- PinJoint* p3d;
-
-public:
-
- void redraw();
- PinJointSpatialGizmo(PinJoint* p_p3d=NULL);
-
-};
-
-
-class HingeJointSpatialGizmo : public SpatialGizmoTool {
-
- OBJ_TYPE(HingeJointSpatialGizmo,SpatialGizmoTool);
-
- HingeJoint* p3d;
-
-public:
-
- void redraw();
- HingeJointSpatialGizmo(HingeJoint* p_p3d=NULL);
-
-};
-
-class SliderJointSpatialGizmo : public SpatialGizmoTool {
-
- OBJ_TYPE(SliderJointSpatialGizmo,SpatialGizmoTool);
-
- SliderJoint* p3d;
-
-public:
-
- void redraw();
- SliderJointSpatialGizmo(SliderJoint* p_p3d=NULL);
-
-};
-
-class ConeTwistJointSpatialGizmo : public SpatialGizmoTool {
-
- OBJ_TYPE(ConeTwistJointSpatialGizmo,SpatialGizmoTool);
-
- ConeTwistJoint* p3d;
-
-public:
-
- void redraw();
- ConeTwistJointSpatialGizmo(ConeTwistJoint* p_p3d=NULL);
-
-};
-
-
-class Generic6DOFJointSpatialGizmo : public SpatialGizmoTool {
-
- OBJ_TYPE(Generic6DOFJointSpatialGizmo,SpatialGizmoTool);
-
- Generic6DOFJoint* p3d;
-
-public:
-
- void redraw();
- Generic6DOFJointSpatialGizmo(Generic6DOFJoint* p_p3d=NULL);
-
-};
-
-
-class SpatialEditorGizmos {
-public:
-
- Ref<FixedMaterial> create_line_material(const Color& p_base_color);
- Ref<FixedMaterial> create_solid_material(const Color& p_base_color);
- Ref<FixedMaterial> handle2_material;
- Ref<FixedMaterial> handle_material;
- Ref<FixedMaterial> light_material;
- Ref<FixedMaterial> light_material_omni_icon;
- Ref<FixedMaterial> light_material_directional_icon;
- Ref<FixedMaterial> camera_material;
- Ref<FixedMaterial> skeleton_material;
- Ref<FixedMaterial> room_material;
- Ref<FixedMaterial> portal_material;
- Ref<FixedMaterial> raycast_material;
- Ref<FixedMaterial> visibility_notifier_material;
- Ref<FixedMaterial> car_wheel_material;
- Ref<FixedMaterial> joint_material;
-
- Ref<FixedMaterial> navmesh_edge_material;
- Ref<FixedMaterial> navmesh_solid_material;
- Ref<FixedMaterial> navmesh_edge_material_disabled;
- Ref<FixedMaterial> navmesh_solid_material_disabled;
-
-
- Ref<FixedMaterial> sample_player_icon;
- Ref<FixedMaterial> stream_player_icon;
- Ref<FixedMaterial> visibility_notifier_icon;
-
- Ref<FixedMaterial> shape_material;
- Ref<Texture> handle_t;
-
- Ref<Mesh> pos3d_mesh;
- static SpatialEditorGizmos *singleton;
-
- Ref<TriangleMesh> test_cube_tm;
-
-
- Ref<SpatialEditorGizmo> get_gizmo(Spatial *p_spatial);
-
- SpatialEditorGizmos();
-};
-
-#endif // SPATIAL_EDITOR_GIZMOS_H
-
+/*************************************************************************/
+/* spatial_editor_gizmos.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
+#ifndef SPATIAL_EDITOR_GIZMOS_H
+#define SPATIAL_EDITOR_GIZMOS_H
+
+
+#include "tools/editor/plugins/spatial_editor_plugin.h"
+#include "scene/3d/light.h"
+#include "scene/3d/camera.h"
+#include "scene/3d/position_3d.h"
+#include "scene/3d/spatial_sample_player.h"
+#include "scene/3d/spatial_stream_player.h"
+#include "scene/3d/test_cube.h"
+#include "scene/3d/mesh_instance.h"
+#include "scene/3d/body_shape.h"
+#include "scene/3d/room_instance.h"
+#include "scene/3d/visibility_notifier.h"
+#include "scene/3d/portal.h"
+#include "scene/3d/ray_cast.h"
+#include "scene/3d/navigation_mesh.h"
+
+#include "scene/3d/vehicle_body.h"
+#include "scene/3d/collision_polygon.h"
+#include "scene/3d/physics_joint.h"
+
+
+class Camera;
+
+class SpatialGizmoTool : public SpatialEditorGizmo {
+
+ OBJ_TYPE(SpatialGizmoTool,SpatialGizmo);
+
+ struct Instance{
+
+ RID instance;
+ Ref<Mesh> mesh;
+ RID skeleton;
+ bool billboard;
+ bool unscaled;
+ bool can_intersect;
+ bool extra_margin;
+ Instance() {
+
+ billboard=false;
+ unscaled=false;
+ can_intersect=false;
+ extra_margin=false;
+ }
+
+ void create_instance(Spatial *p_base);
+
+ };
+
+ Vector<Vector3> collision_segments;
+ Ref<TriangleMesh> collision_mesh;
+
+ struct Handle {
+ Vector3 pos;
+ bool billboard;
+ };
+
+ Vector<Vector3> handles;
+ Vector<Vector3> secondary_handles;
+ bool billboard_handle;
+
+ bool valid;
+ Spatial *base;
+ Vector<Instance> instances;
+ Spatial *spatial_node;
+protected:
+ void add_lines(const Vector<Vector3> &p_lines,const Ref<Material>& p_material,bool p_billboard=false);
+ void add_mesh(const Ref<Mesh>& p_mesh,bool p_billboard=false,const RID& p_skeleton=RID());
+ void add_collision_segments(const Vector<Vector3> &p_lines);
+ void add_collision_triangles(const Ref<TriangleMesh>& p_tmesh);
+ void add_unscaled_billboard(const Ref<Material>& p_material,float p_scale=1);
+ void add_handles(const Vector<Vector3> &p_handles,bool p_billboard=false,bool p_secondary=false);
+
+ void set_spatial_node(Spatial *p_node);
+
+public:
+
+ virtual Vector3 get_handle_pos(int p_idx) const;
+ virtual bool intersect_frustum(const Camera *p_camera,const Vector<Plane> &p_frustum);
+ virtual bool intersect_ray(const Camera *p_camera,const Point2& p_point, Vector3& r_pos, Vector3& r_normal,int *r_gizmo_handle=NULL,bool p_sec_first=false);
+
+ void clear();
+ void create();
+ void transform();
+ //void redraw();
+ void free();
+
+ SpatialGizmoTool();
+ ~SpatialGizmoTool();
+};
+
+
+
+class LightSpatialGizmo : public SpatialGizmoTool {
+
+ OBJ_TYPE(LightSpatialGizmo,SpatialGizmoTool);
+
+ Light* light;
+
+public:
+
+
+ virtual String get_handle_name(int p_idx) const;
+ virtual Variant get_handle_value(int p_idx) const;
+ virtual void set_handle(int p_idx,Camera *p_camera, const Point2& p_point);
+ virtual void commit_handle(int p_idx,const Variant& p_restore,bool p_cancel=false);
+
+ void redraw();
+ LightSpatialGizmo(Light* p_light=NULL);
+
+};
+
+class CameraSpatialGizmo : public SpatialGizmoTool {
+
+ OBJ_TYPE(CameraSpatialGizmo,SpatialGizmoTool);
+
+ Camera* camera;
+
+public:
+
+
+ virtual String get_handle_name(int p_idx) const;
+ virtual Variant get_handle_value(int p_idx) const;
+ virtual void set_handle(int p_idx,Camera *p_camera, const Point2& p_point);
+ virtual void commit_handle(int p_idx,const Variant& p_restore,bool p_cancel=false);
+
+ void redraw();
+ CameraSpatialGizmo(Camera* p_camera=NULL);
+
+};
+
+
+
+class MeshInstanceSpatialGizmo : public SpatialGizmoTool {
+
+ OBJ_TYPE(MeshInstanceSpatialGizmo,SpatialGizmoTool);
+
+ MeshInstance* mesh;
+
+public:
+
+ void redraw();
+ MeshInstanceSpatialGizmo(MeshInstance* p_mesh=NULL);
+
+};
+
+class Position3DSpatialGizmo : public SpatialGizmoTool {
+
+ OBJ_TYPE(Position3DSpatialGizmo,SpatialGizmoTool);
+
+ Position3D* p3d;
+
+public:
+
+ void redraw();
+ Position3DSpatialGizmo(Position3D* p_p3d=NULL);
+
+};
+
+class SkeletonSpatialGizmo : public SpatialGizmoTool {
+
+ OBJ_TYPE(SkeletonSpatialGizmo,SpatialGizmoTool);
+
+ Skeleton* skel;
+
+public:
+
+ void redraw();
+ SkeletonSpatialGizmo(Skeleton* p_skel=NULL);
+
+};
+
+
+
+
+class SpatialPlayerSpatialGizmo : public SpatialGizmoTool {
+
+ OBJ_TYPE(SpatialPlayerSpatialGizmo,SpatialGizmoTool);
+
+ SpatialPlayer* splayer;
+
+public:
+
+ void redraw();
+ SpatialPlayerSpatialGizmo(SpatialPlayer* p_splayer=NULL);
+
+};
+
+
+
+class TestCubeSpatialGizmo : public SpatialGizmoTool {
+
+ OBJ_TYPE(TestCubeSpatialGizmo,SpatialGizmoTool);
+
+ TestCube* tc;
+
+public:
+ void redraw();
+ TestCubeSpatialGizmo(TestCube* p_tc=NULL);
+
+};
+
+
+class RoomSpatialGizmo : public SpatialGizmoTool {
+
+ OBJ_TYPE(RoomSpatialGizmo,SpatialGizmoTool);
+
+
+ struct _EdgeKey {
+
+ Vector3 from;
+ Vector3 to;
+
+ bool operator<(const _EdgeKey& p_with) const { return from==p_with.from ? to < p_with.to : from < p_with.from; }
+ };
+
+
+
+ Room* room;
+
+public:
+
+ void redraw();
+ RoomSpatialGizmo(Room* p_room=NULL);
+
+};
+
+
+class PortalSpatialGizmo : public SpatialGizmoTool {
+
+ OBJ_TYPE(PortalSpatialGizmo,SpatialGizmoTool);
+
+ Portal* portal;
+
+public:
+
+ void redraw();
+ PortalSpatialGizmo(Portal* p_portal=NULL);
+
+};
+
+
+class VisibilityNotifierGizmo : public SpatialGizmoTool {
+
+ OBJ_TYPE(VisibilityNotifierGizmo ,SpatialGizmoTool);
+
+
+ VisibilityNotifier* notifier;
+
+public:
+
+ virtual String get_handle_name(int p_idx) const;
+ virtual Variant get_handle_value(int p_idx) const;
+ virtual void set_handle(int p_idx,Camera *p_camera, const Point2& p_point);
+ virtual void commit_handle(int p_idx,const Variant& p_restore,bool p_cancel=false);
+
+ void redraw();
+ VisibilityNotifierGizmo(VisibilityNotifier* p_notifier=NULL);
+
+};
+
+
+
+class CollisionShapeSpatialGizmo : public SpatialGizmoTool {
+
+ OBJ_TYPE(CollisionShapeSpatialGizmo,SpatialGizmoTool);
+
+ CollisionShape* cs;
+
+public:
+ virtual String get_handle_name(int p_idx) const;
+ virtual Variant get_handle_value(int p_idx) const;
+ virtual void set_handle(int p_idx,Camera *p_camera, const Point2& p_point);
+ virtual void commit_handle(int p_idx,const Variant& p_restore,bool p_cancel=false);
+ void redraw();
+ CollisionShapeSpatialGizmo(CollisionShape* p_cs=NULL);
+
+};
+
+
+class CollisionPolygonSpatialGizmo : public SpatialGizmoTool {
+
+ OBJ_TYPE(CollisionPolygonSpatialGizmo,SpatialGizmoTool);
+
+ CollisionPolygon* polygon;
+
+public:
+
+ void redraw();
+ CollisionPolygonSpatialGizmo(CollisionPolygon* p_polygon=NULL);
+
+};
+
+
+class RayCastSpatialGizmo : public SpatialGizmoTool {
+
+ OBJ_TYPE(RayCastSpatialGizmo,SpatialGizmoTool);
+
+ RayCast* raycast;
+
+public:
+
+ void redraw();
+ RayCastSpatialGizmo(RayCast* p_raycast=NULL);
+
+};
+
+
+
+class VehicleWheelSpatialGizmo : public SpatialGizmoTool {
+
+ OBJ_TYPE(VehicleWheelSpatialGizmo,SpatialGizmoTool);
+
+ VehicleWheel* car_wheel;
+
+public:
+
+ void redraw();
+ VehicleWheelSpatialGizmo(VehicleWheel* p_car_wheel=NULL);
+
+};
+
+
+class NavigationMeshSpatialGizmo : public SpatialGizmoTool {
+
+ OBJ_TYPE(NavigationMeshSpatialGizmo,SpatialGizmoTool);
+
+
+ struct _EdgeKey {
+
+ Vector3 from;
+ Vector3 to;
+
+ bool operator<(const _EdgeKey& p_with) const { return from==p_with.from ? to < p_with.to : from < p_with.from; }
+ };
+
+
+
+ NavigationMeshInstance* navmesh;
+
+public:
+
+ void redraw();
+ NavigationMeshSpatialGizmo(NavigationMeshInstance* p_navmesh=NULL);
+
+};
+
+
+class PinJointSpatialGizmo : public SpatialGizmoTool {
+
+ OBJ_TYPE(PinJointSpatialGizmo,SpatialGizmoTool);
+
+ PinJoint* p3d;
+
+public:
+
+ void redraw();
+ PinJointSpatialGizmo(PinJoint* p_p3d=NULL);
+
+};
+
+
+class HingeJointSpatialGizmo : public SpatialGizmoTool {
+
+ OBJ_TYPE(HingeJointSpatialGizmo,SpatialGizmoTool);
+
+ HingeJoint* p3d;
+
+public:
+
+ void redraw();
+ HingeJointSpatialGizmo(HingeJoint* p_p3d=NULL);
+
+};
+
+class SliderJointSpatialGizmo : public SpatialGizmoTool {
+
+ OBJ_TYPE(SliderJointSpatialGizmo,SpatialGizmoTool);
+
+ SliderJoint* p3d;
+
+public:
+
+ void redraw();
+ SliderJointSpatialGizmo(SliderJoint* p_p3d=NULL);
+
+};
+
+class ConeTwistJointSpatialGizmo : public SpatialGizmoTool {
+
+ OBJ_TYPE(ConeTwistJointSpatialGizmo,SpatialGizmoTool);
+
+ ConeTwistJoint* p3d;
+
+public:
+
+ void redraw();
+ ConeTwistJointSpatialGizmo(ConeTwistJoint* p_p3d=NULL);
+
+};
+
+
+class Generic6DOFJointSpatialGizmo : public SpatialGizmoTool {
+
+ OBJ_TYPE(Generic6DOFJointSpatialGizmo,SpatialGizmoTool);
+
+ Generic6DOFJoint* p3d;
+
+public:
+
+ void redraw();
+ Generic6DOFJointSpatialGizmo(Generic6DOFJoint* p_p3d=NULL);
+
+};
+
+
+class SpatialEditorGizmos {
+public:
+
+ Ref<FixedMaterial> create_line_material(const Color& p_base_color);
+ Ref<FixedMaterial> create_solid_material(const Color& p_base_color);
+ Ref<FixedMaterial> handle2_material;
+ Ref<FixedMaterial> handle_material;
+ Ref<FixedMaterial> light_material;
+ Ref<FixedMaterial> light_material_omni_icon;
+ Ref<FixedMaterial> light_material_directional_icon;
+ Ref<FixedMaterial> camera_material;
+ Ref<FixedMaterial> skeleton_material;
+ Ref<FixedMaterial> room_material;
+ Ref<FixedMaterial> portal_material;
+ Ref<FixedMaterial> raycast_material;
+ Ref<FixedMaterial> visibility_notifier_material;
+ Ref<FixedMaterial> car_wheel_material;
+ Ref<FixedMaterial> joint_material;
+
+ Ref<FixedMaterial> navmesh_edge_material;
+ Ref<FixedMaterial> navmesh_solid_material;
+ Ref<FixedMaterial> navmesh_edge_material_disabled;
+ Ref<FixedMaterial> navmesh_solid_material_disabled;
+
+
+ Ref<FixedMaterial> sample_player_icon;
+ Ref<FixedMaterial> stream_player_icon;
+ Ref<FixedMaterial> visibility_notifier_icon;
+
+ Ref<FixedMaterial> shape_material;
+ Ref<Texture> handle_t;
+
+ Ref<Mesh> pos3d_mesh;
+ static SpatialEditorGizmos *singleton;
+
+ Ref<TriangleMesh> test_cube_tm;
+
+
+ Ref<SpatialEditorGizmo> get_gizmo(Spatial *p_spatial);
+
+ SpatialEditorGizmos();
+};
+
+#endif // SPATIAL_EDITOR_GIZMOS_H
+
diff --git a/tools/export/blender25/godot_export_manager.py b/tools/export/blender25/godot_export_manager.py
index 31db2c9e94..582d76f94f 100644
--- a/tools/export/blender25/godot_export_manager.py
+++ b/tools/export/blender25/godot_export_manager.py
@@ -1,474 +1,472 @@
-# ##### BEGIN GPL LICENSE BLOCK #####
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; either version 2
-# of the License, or (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-#
-# ##### END GPL LICENSE BLOCK #####
-
-# Script copyright (c) Andreas Esau
-
-bl_info = {
- "name": "Godot Export Manager",
- "author": "Andreas Esau",
- "version": (1, 0),
- "blender": (2, 7, 0),
- "location": "Scene Properties > Godot Export Manager",
- "description": "Godot Export Manager uses the Better Collada Exporter to manage Export Groups and automatically export the objects groups to Collada Files.",
- "warning": "",
- "wiki_url": ("http://www.godotengine.org"),
- "tracker_url": "",
- "category": "Import-Export"}
-
-import bpy
-from bpy.props import StringProperty, BoolProperty, EnumProperty, FloatProperty, FloatVectorProperty, IntProperty, CollectionProperty, PointerProperty
-import os
-from bpy.app.handlers import persistent
-from mathutils import Vector, Matrix
-
-class godot_export_manager(bpy.types.Panel):
- bl_label = "Godot Export Manager"
- bl_space_type = 'PROPERTIES'
- bl_region_type = 'WINDOW'
- bl_context = "scene"
-
- bpy.types.Scene.godot_export_on_save = BoolProperty(default=False)
-
- ### draw function for all ui elements
- def draw(self, context):
- layout = self.layout
- split = self.layout.split()
- scene = bpy.data.scenes[0]
- ob = context.object
- scene = context.scene
-
- row = layout.row()
- col = row.column()
- col.prop(scene,"godot_export_on_save",text="Export Groups on save")
-
- row = layout.row()
- col = row.column(align=True)
- op = col.operator("scene.godot_add_objects_to_group",text="Add selected objects to Group",icon="COPYDOWN")
-
- op = col.operator("scene.godot_delete_objects_from_group",text="Delete selected objects from Group",icon="PASTEDOWN")
-
-
-
- row = layout.row()
- col = row.column()
- col.label(text="Export Groups:")
-
-
- row = layout.row()
- col = row.column()
-
- col.template_list("UI_List_Godot","dummy",scene, "godot_export_groups", scene, "godot_export_groups_index",rows=1,maxrows=10,type='DEFAULT')
-
- col = row.column(align=True)
- col.operator("scene.godot_add_export_group",text="",icon="ZOOMIN")
- col.operator("scene.godot_delete_export_group",text="",icon="ZOOMOUT")
- col.operator("scene.godot_export_all_groups",text="",icon="EXPORT")
-
- if len(scene.godot_export_groups) > 0:
- row = layout.row()
- col = row.column()
- group = scene.godot_export_groups[scene.godot_export_groups_index]
- col.prop(group,"name",text="Group Name")
- col.prop(group,"export_name",text="Export Name")
- col.prop(group,"export_path",text="Export Filepath")
-
- row = layout.row()
- col = row.column()
- row = layout.row()
- col = row.column()
- col.label(text="Export Settings:")
-
- col = col.row(align=True)
- col.prop(group,"apply_loc",toggle=True,icon="MAN_TRANS")
- col.prop(group,"apply_rot",toggle=True,icon="MAN_ROT")
- col.prop(group,"apply_scale",toggle=True,icon="MAN_SCALE")
-
- row = layout.row()
- col = row.column()
-
- col.prop(group,"use_include_particle_duplicates")
- col.prop(group,"use_mesh_modifiers")
- col.prop(group,"use_tangent_arrays")
- col.prop(group,"use_triangles")
- col.prop(group,"use_copy_images")
- col.prop(group,"use_active_layers")
- col.prop(group,"use_exclude_ctrl_bones")
- col.prop(group,"use_anim")
- col.prop(group,"use_anim_action_all")
- col.prop(group,"use_anim_skip_noexp")
- col.prop(group,"use_anim_optimize")
- col.prop(group,"anim_optimize_precision")
- col.prop(group,"use_metadata")
-
-### Custom template_list look
-class UI_List_Godot(bpy.types.UIList):
- def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
- ob = data
- slot = item
- col = layout.row(align=True)
-
- col.label(text=item.name,icon="GROUP")
- col.prop(item,"active",text="")
-
- op = col.operator("scene.godot_select_group_objects",text="",emboss=False,icon="RESTRICT_SELECT_OFF")
- op.idx = index
- op = col.operator("scene.godot_export_group",text="",emboss=False,icon="EXPORT")
- op.idx = index
-
-class add_objects_to_group(bpy.types.Operator):
- bl_idname = "scene.godot_add_objects_to_group"
- bl_label = "Add Objects to Group"
- bl_description = "Adds the selected Objects to the active group below."
-
- undo = BoolProperty(default=True)
-
- def execute(self,context):
- scene = context.scene
-
- objects_str = ""
- if len(scene.godot_export_groups) > 0:
- for i,object in enumerate(context.selected_objects):
- if object.name not in scene.godot_export_groups[scene.godot_export_groups_index].nodes:
- node = scene.godot_export_groups[scene.godot_export_groups_index].nodes.add()
- node.name = object.name
- if i == 0:
- objects_str += object.name
- else:
- objects_str += ", "+object.name
-
-
- self.report({'INFO'}, objects_str + " added to group." )
- if self.undo:
- bpy.ops.ed.undo_push(message="Objects added to group")
- else:
- self.report({'WARNING'}, "Create a group first." )
- return{'FINISHED'}
-
-class del_objects_from_group(bpy.types.Operator):
- bl_idname = "scene.godot_delete_objects_from_group"
- bl_label = "Delete Objects from Group"
- bl_description = "Delets the selected Objects from the active group below."
-
- def execute(self,context):
- scene = context.scene
-
- if len(scene.godot_export_groups) > 0:
-
- selected_objects = []
- for object in context.selected_objects:
- selected_objects.append(object.name)
-
- objects_str = ""
- j = 0
- for i,node in enumerate(scene.godot_export_groups[scene.godot_export_groups_index].nodes):
- if node.name in selected_objects:
- scene.godot_export_groups[scene.godot_export_groups_index].nodes.remove(i)
-
-
- if j == 0:
- objects_str += object.name
- else:
- objects_str += ", "+object.name
- j+=1
-
-
- self.report({'INFO'}, objects_str + " deleted from group." )
- bpy.ops.ed.undo_push(message="Objects deleted from group")
- else:
- self.report({'WARNING'}, "There is no group to delete from." )
- return{'FINISHED'}
-
-class select_group_objects(bpy.types.Operator):
- bl_idname = "scene.godot_select_group_objects"
- bl_label = "Select Group Objects"
- bl_description = "Will select all group Objects in the scene."
-
- idx = IntProperty()
-
- def execute(self,context):
- scene = context.scene
- for object in context.scene.objects:
- object.select = False
- for node in scene.godot_export_groups[self.idx].nodes:
- if node.name in bpy.data.objects:
- bpy.data.objects[node.name].select = True
- context.scene.objects.active = bpy.data.objects[node.name]
- return{'FINISHED'}
-
-class export_groups_autosave(bpy.types.Operator):
- bl_idname = "scene.godot_export_groups_autosave"
- bl_label = "Export All Groups"
- bl_description = "Exports all groups to Collada."
-
- def execute(self,context):
- scene = context.scene
- if scene.godot_export_on_save:
- for i in range(len(scene.godot_export_groups)):
- if scene.godot_export_groups[i].active:
- bpy.ops.scene.godot_export_group(idx=i)
- self.report({'INFO'}, "All Groups exported." )
- bpy.ops.ed.undo_push(message="Export all Groups")
- return{'FINISHED'}
-
-class export_all_groups(bpy.types.Operator):
- bl_idname = "scene.godot_export_all_groups"
- bl_label = "Export All Groups"
- bl_description = "Exports all groups to Collada."
-
- def execute(self,context):
- scene = context.scene
-
- for i in range(0,len(scene.godot_export_groups)):
- bpy.ops.scene.godot_export_group(idx=i,export_all=True)
-
- self.report({'INFO'}, "All Groups exported." )
- return{'FINISHED'}
-
-
-class export_group(bpy.types.Operator):
- bl_idname = "scene.godot_export_group"
- bl_label = "Export Group"
- bl_description = "Exports the active group to destination folder as Collada file."
-
- idx = IntProperty(default=0)
- export_all = BoolProperty(default=False)
-
-
- def copy_object_recursive(self,ob,parent,single_user = True):
- new_ob = bpy.data.objects[ob.name].copy()
- if single_user or ob.type=="ARMATURE":
- new_mesh_data = new_ob.data.copy()
- new_ob.data = new_mesh_data
- bpy.context.scene.objects.link(new_ob)
-
- if ob != parent:
- new_ob.parent = parent
- else:
- new_ob.parent = None
-
- for child in ob.children:
- self.copy_object_recursive(child,new_ob,single_user)
- new_ob.select = True
- return new_ob
-
- def delete_object(self,ob):
- if ob != None:
- for child in ob.children:
- self.delete_object(child)
- bpy.context.scene.objects.unlink(ob)
- bpy.data.objects.remove(ob)
-
- def convert_group_to_node(self,group):
- if group.dupli_group != None:
- for object in group.dupli_group.objects:
- if object.parent == None:
- object = self.copy_object_recursive(object,object,True)
- matrix = Matrix(object.matrix_local)
- object.matrix_local = Matrix()
- object.matrix_local *= group.matrix_local
- object.matrix_local *= matrix
-
- self.delete_object(group)
-
- def execute(self,context):
-
- scene = context.scene
- group = context.scene.godot_export_groups
-
- if not group[self.idx].active and self.export_all:
- return{'FINISHED'}
-
- for i,object in enumerate(group[self.idx].nodes):
- if object.name in bpy.data.objects:
- pass
- else:
- group[self.idx].nodes.remove(i)
- bpy.ops.ed.undo_push(message="Clear not existent Group Nodes.")
-
- path = group[self.idx].export_path
- if (path.find("//")==0 or path.find("\\\\")==0):
- #if relative, convert to absolute
- path = bpy.path.abspath(path)
- path = path.replace("\\","/")
-
- ### if path exists and group export name is set the group will be exported
- if os.path.exists(path) and group[self.idx].export_name != "":
-
- context.scene.layers = [True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True]
-
-
- if group[self.idx].export_name.endswith(".dae"):
- path = os.path.join(path,group[self.idx].export_name)
- else:
- path = os.path.join(path,group[self.idx].export_name+".dae")
-
- hide_select = []
- for object in context.scene.objects:
- hide_select.append(object.hide_select)
- object.hide_select = False
- object.select = False
- context.scene.objects.active = None
-
- ### make particle duplicates, parent and select them
- nodes_to_be_added = []
- if group[self.idx].use_include_particle_duplicates:
- for i,object in enumerate(group[self.idx].nodes):
- if bpy.data.objects[object.name].type != "EMPTY":
- context.scene.objects.active = bpy.data.objects[object.name]
- bpy.data.objects[object.name].select = True
- bpy.ops.object.duplicates_make_real()
- for object in context.selected_objects:
- nodes_to_be_added.append(object)
- bpy.ops.object.parent_set(type="OBJECT", keep_transform=False)
-
- for object in context.selected_objects:
- object.select = False
- bpy.data.objects[object.name].select = False
- context.scene.objects.active = None
- for object in nodes_to_be_added:
- object.select = True
-
- ### select all other nodes from the group
- for i,object in enumerate(group[self.idx].nodes):
- if bpy.data.objects[object.name].type == "EMPTY":
- self.convert_group_to_node(bpy.data.objects[object.name])
- else:
- bpy.data.objects[object.name].select = True
-
- bpy.ops.object.transform_apply(location=group[self.idx].apply_loc, rotation=group[self.idx].apply_rot, scale=group[self.idx].apply_scale)
- bpy.ops.export_scene.dae(check_existing=True, filepath=path, filter_glob="*.dae", object_types=group[self.idx].object_types, use_export_selected=group[self.idx].use_export_selected, use_mesh_modifiers=group[self.idx].use_mesh_modifiers, use_tangent_arrays=group[self.idx].use_tangent_arrays, use_triangles=group[self.idx].use_triangles, use_copy_images=group[self.idx].use_copy_images, use_active_layers=group[self.idx].use_active_layers, use_exclude_ctrl_bones=group[self.idx].use_exclude_ctrl_bones, use_anim=group[self.idx].use_anim, use_anim_action_all=group[self.idx].use_anim_action_all, use_anim_skip_noexp=group[self.idx].use_anim_skip_noexp, use_anim_optimize=group[self.idx].use_anim_optimize, anim_optimize_precision=group[self.idx].anim_optimize_precision, use_metadata=group[self.idx].use_metadata)
-
- self.report({'INFO'}, '"'+group[self.idx].name+'"' + " Group exported." )
- msg = "Export Group "+group[self.idx].name
-
- bpy.ops.ed.undo_push(message="")
- bpy.ops.ed.undo()
- bpy.ops.ed.undo_push(message=msg)
-
- else:
- self.report({'INFO'}, "Define Export Name and Export Path." )
- return{'FINISHED'}
-
-class add_export_group(bpy.types.Operator):
- bl_idname = "scene.godot_add_export_group"
- bl_label = "Adds a new export Group"
- bl_description = "Creates a new Export Group with the selected Objects assigned to it."
-
- def execute(self,context):
- scene = context.scene
-
- item = scene.godot_export_groups.add()
- item.name = "New Group"
- for object in context.selected_objects:
- node = item.nodes.add()
- node.name = object.name
- scene.godot_export_groups_index = len(scene.godot_export_groups)-1
- bpy.ops.ed.undo_push(message="Create New Export Group")
- return{'FINISHED'}
-
-class del_export_group(bpy.types.Operator):
- bl_idname = "scene.godot_delete_export_group"
- bl_label = "Delets the selected export Group"
- bl_description = "Delets the active Export Group."
-
- def invoke(self, context, event):
- wm = context.window_manager
- return wm.invoke_confirm(self,event)
-
- def execute(self,context):
- scene = context.scene
-
- scene.godot_export_groups.remove(scene.godot_export_groups_index)
- if scene.godot_export_groups_index > 0:
- scene.godot_export_groups_index -= 1
- bpy.ops.ed.undo_push(message="Delete Export Group")
- return{'FINISHED'}
-
-class godot_node_list(bpy.types.PropertyGroup):
- name = StringProperty()
-
-class godot_export_groups(bpy.types.PropertyGroup):
- name = StringProperty(name="Group Name")
- export_name = StringProperty(name="scene_name")
- nodes = CollectionProperty(type=godot_node_list)
- export_path = StringProperty(subtype="DIR_PATH")
- active = BoolProperty(default=True,description="Export Group")
-
- object_types = EnumProperty(name="Object Types",options={'ENUM_FLAG'},items=(('EMPTY', "Empty", ""),('CAMERA', "Camera", ""),('LAMP', "Lamp", ""),('ARMATURE', "Armature", ""),('MESH', "Mesh", ""),('CURVE', "Curve", ""),),default={'EMPTY', 'CAMERA', 'LAMP', 'ARMATURE', 'MESH','CURVE'})
-
- apply_scale = BoolProperty(name="Apply Scale",description="Apply Scale before export.",default=False)
- apply_rot = BoolProperty(name="Apply Rotation",description="Apply Rotation before export.",default=False)
- apply_loc = BoolProperty(name="Apply Location",description="Apply Location before export.",default=False)
-
- use_export_selected = BoolProperty(name="Selected Objects",description="Export only selected objects (and visible in active layers if that applies).",default=True)
- use_mesh_modifiers = BoolProperty(name="Apply Modifiers",description="Apply modifiers to mesh objects (on a copy!).",default=True)
- use_tangent_arrays = BoolProperty(name="Tangent Arrays",description="Export Tangent and Binormal arrays (for normalmapping).",default=False)
- use_triangles = BoolProperty(name="Triangulate",description="Export Triangles instead of Polygons.",default=False)
-
- use_copy_images = BoolProperty(name="Copy Images",description="Copy Images (create images/ subfolder)",default=False)
- use_active_layers = BoolProperty(name="Active Layers",description="Export only objects on the active layers.",default=True)
- use_exclude_ctrl_bones = BoolProperty(name="Exclude Control Bones",description="Exclude skeleton bones with names that begin with 'ctrl'.",default=True)
- use_anim = BoolProperty(name="Export Animation",description="Export keyframe animation",default=False)
- use_anim_action_all = BoolProperty(name="All Actions",description=("Export all actions for the first armature found in separate DAE files"),default=False)
- use_anim_skip_noexp = BoolProperty(name="Skip (-noexp) Actions",description="Skip exporting of actions whose name end in (-noexp). Useful to skip control animations.",default=True)
- use_anim_optimize = BoolProperty(name="Optimize Keyframes",description="Remove double keyframes",default=True)
-
- anim_optimize_precision = FloatProperty(name="Precision",description=("Tolerence for comparing double keyframes (higher for greater accuracy)"),min=1, max=16,soft_min=1, soft_max=16,default=6.0)
-
- use_metadata = BoolProperty(name="Use Metadata",default=True,options={'HIDDEN'})
- use_include_particle_duplicates = BoolProperty(name="Include Particle Duplicates",default=True)
-
-def register():
- bpy.utils.register_class(godot_export_manager)
- bpy.utils.register_class(godot_node_list)
- bpy.utils.register_class(godot_export_groups)
- bpy.utils.register_class(add_export_group)
- bpy.utils.register_class(del_export_group)
- bpy.utils.register_class(export_all_groups)
- bpy.utils.register_class(export_groups_autosave)
- bpy.utils.register_class(export_group)
- bpy.utils.register_class(add_objects_to_group)
- bpy.utils.register_class(del_objects_from_group)
- bpy.utils.register_class(select_group_objects)
- bpy.utils.register_class(UI_List_Godot)
-
- bpy.types.Scene.godot_export_groups = CollectionProperty(type=godot_export_groups)
- bpy.types.Scene.godot_export_groups_index = IntProperty(default=0,min=0)
-
-def unregister():
- bpy.utils.unregister_class(godot_export_manager)
- bpy.utils.unregister_class(godot_node_list)
- bpy.utils.unregister_class(godot_export_groups)
- bpy.utils.unregister_class(export_groups_autosave)
- bpy.utils.unregister_class(add_export_group)
- bpy.utils.unregister_class(del_export_group)
- bpy.utils.unregister_class(export_all_groups)
- bpy.utils.unregister_class(export_group)
- bpy.utils.unregister_class(add_objects_to_group)
- bpy.utils.unregister_class(del_objects_from_group)
- bpy.utils.unregister_class(select_group_objects)
- bpy.utils.unregister_class(UI_List_Godot)
-
-@persistent
-def auto_export(dummy):
- bpy.ops.scene.godot_export_groups_autosave()
-
-bpy.app.handlers.save_post.append(auto_export)
-
-if __name__ == "__main__":
- register()
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# Script copyright (c) Andreas Esau
+
+bl_info = {
+ "name": "Godot Export Manager",
+ "author": "Andreas Esau",
+ "version": (1, 0),
+ "blender": (2, 7, 0),
+ "location": "Scene Properties > Godot Export Manager",
+ "description": "Godot Export Manager uses the Better Collada Exporter to manage Export Groups and automatically export the objects groups to Collada Files.",
+ "warning": "",
+ "wiki_url": ("http://www.godotengine.org"),
+ "tracker_url": "",
+ "category": "Import-Export"}
+
+import bpy
+from bpy.props import StringProperty, BoolProperty, EnumProperty, FloatProperty, FloatVectorProperty, IntProperty, CollectionProperty, PointerProperty
+import os
+from bpy.app.handlers import persistent
+from mathutils import Vector, Matrix
+
+class godot_export_manager(bpy.types.Panel):
+ bl_label = "Godot Export Manager"
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_context = "scene"
+
+ bpy.types.Scene.godot_export_on_save = BoolProperty(default=False)
+
+ ### draw function for all ui elements
+ def draw(self, context):
+ layout = self.layout
+ split = self.layout.split()
+ scene = bpy.data.scenes[0]
+ ob = context.object
+ scene = context.scene
+
+ row = layout.row()
+ col = row.column()
+ col.prop(scene,"godot_export_on_save",text="Export Groups on save")
+
+ row = layout.row()
+ col = row.column(align=True)
+ op = col.operator("scene.godot_add_objects_to_group",text="Add selected objects to Group",icon="COPYDOWN")
+
+ op = col.operator("scene.godot_delete_objects_from_group",text="Delete selected objects from Group",icon="PASTEDOWN")
+
+
+
+ row = layout.row()
+ col = row.column()
+ col.label(text="Export Groups:")
+
+
+ row = layout.row()
+ col = row.column()
+
+ col.template_list("UI_List_Godot","dummy",scene, "godot_export_groups", scene, "godot_export_groups_index",rows=1,maxrows=10,type='DEFAULT')
+
+ col = row.column(align=True)
+ col.operator("scene.godot_add_export_group",text="",icon="ZOOMIN")
+ col.operator("scene.godot_delete_export_group",text="",icon="ZOOMOUT")
+ col.operator("scene.godot_export_all_groups",text="",icon="EXPORT")
+
+ if len(scene.godot_export_groups) > 0:
+ row = layout.row()
+ col = row.column()
+ group = scene.godot_export_groups[scene.godot_export_groups_index]
+ col.prop(group,"name",text="Group Name")
+ col.prop(group,"export_name",text="Export Name")
+ col.prop(group,"export_path",text="Export Filepath")
+
+ row = layout.row()
+ col = row.column()
+ row = layout.row()
+ col = row.column()
+ col.label(text="Export Settings:")
+
+ col = col.row(align=True)
+ col.prop(group,"apply_loc",toggle=True,icon="MAN_TRANS")
+ col.prop(group,"apply_rot",toggle=True,icon="MAN_ROT")
+ col.prop(group,"apply_scale",toggle=True,icon="MAN_SCALE")
+
+ row = layout.row()
+ col = row.column()
+
+ col.prop(group,"use_include_particle_duplicates")
+ col.prop(group,"use_mesh_modifiers")
+ col.prop(group,"use_tangent_arrays")
+ col.prop(group,"use_triangles")
+ col.prop(group,"use_copy_images")
+ col.prop(group,"use_active_layers")
+ col.prop(group,"use_anim")
+ col.prop(group,"use_anim_action_all")
+ col.prop(group,"use_anim_skip_noexp")
+ col.prop(group,"use_anim_optimize")
+ col.prop(group,"anim_optimize_precision")
+ col.prop(group,"use_metadata")
+
+### Custom template_list look
+class UI_List_Godot(bpy.types.UIList):
+ def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
+ ob = data
+ slot = item
+ col = layout.row(align=True)
+
+ col.label(text=item.name,icon="GROUP")
+ col.prop(item,"active",text="")
+
+ op = col.operator("scene.godot_select_group_objects",text="",emboss=False,icon="RESTRICT_SELECT_OFF")
+ op.idx = index
+ op = col.operator("scene.godot_export_group",text="",emboss=False,icon="EXPORT")
+ op.idx = index
+
+class add_objects_to_group(bpy.types.Operator):
+ bl_idname = "scene.godot_add_objects_to_group"
+ bl_label = "Add Objects to Group"
+ bl_description = "Adds the selected Objects to the active group below."
+
+ undo = BoolProperty(default=True)
+
+ def execute(self,context):
+ scene = context.scene
+
+ objects_str = ""
+ if len(scene.godot_export_groups) > 0:
+ for i,object in enumerate(context.selected_objects):
+ if object.name not in scene.godot_export_groups[scene.godot_export_groups_index].nodes:
+ node = scene.godot_export_groups[scene.godot_export_groups_index].nodes.add()
+ node.name = object.name
+ if i == 0:
+ objects_str += object.name
+ else:
+ objects_str += ", "+object.name
+
+
+ self.report({'INFO'}, objects_str + " added to group." )
+ if self.undo:
+ bpy.ops.ed.undo_push(message="Objects added to group")
+ else:
+ self.report({'WARNING'}, "Create a group first." )
+ return{'FINISHED'}
+
+class del_objects_from_group(bpy.types.Operator):
+ bl_idname = "scene.godot_delete_objects_from_group"
+ bl_label = "Delete Objects from Group"
+ bl_description = "Delets the selected Objects from the active group below."
+
+ def execute(self,context):
+ scene = context.scene
+
+ if len(scene.godot_export_groups) > 0:
+
+ selected_objects = []
+ for object in context.selected_objects:
+ selected_objects.append(object.name)
+
+ objects_str = ""
+ j = 0
+ for i,node in enumerate(scene.godot_export_groups[scene.godot_export_groups_index].nodes):
+ if node.name in selected_objects:
+ scene.godot_export_groups[scene.godot_export_groups_index].nodes.remove(i)
+
+
+ if j == 0:
+ objects_str += object.name
+ else:
+ objects_str += ", "+object.name
+ j+=1
+
+
+ self.report({'INFO'}, objects_str + " deleted from group." )
+ bpy.ops.ed.undo_push(message="Objects deleted from group")
+ else:
+ self.report({'WARNING'}, "There is no group to delete from." )
+ return{'FINISHED'}
+
+class select_group_objects(bpy.types.Operator):
+ bl_idname = "scene.godot_select_group_objects"
+ bl_label = "Select Group Objects"
+ bl_description = "Will select all group Objects in the scene."
+
+ idx = IntProperty()
+
+ def execute(self,context):
+ scene = context.scene
+ for object in context.scene.objects:
+ object.select = False
+ for node in scene.godot_export_groups[self.idx].nodes:
+ if node.name in bpy.data.objects:
+ bpy.data.objects[node.name].select = True
+ context.scene.objects.active = bpy.data.objects[node.name]
+ return{'FINISHED'}
+
+class export_groups_autosave(bpy.types.Operator):
+ bl_idname = "scene.godot_export_groups_autosave"
+ bl_label = "Export All Groups"
+ bl_description = "Exports all groups to Collada."
+
+ def execute(self,context):
+ scene = context.scene
+ if scene.godot_export_on_save:
+ for i in range(len(scene.godot_export_groups)):
+ if scene.godot_export_groups[i].active:
+ bpy.ops.scene.godot_export_group(idx=i)
+ self.report({'INFO'}, "All Groups exported." )
+ bpy.ops.ed.undo_push(message="Export all Groups")
+ return{'FINISHED'}
+
+class export_all_groups(bpy.types.Operator):
+ bl_idname = "scene.godot_export_all_groups"
+ bl_label = "Export All Groups"
+ bl_description = "Exports all groups to Collada."
+
+ def execute(self,context):
+ scene = context.scene
+
+ for i in range(0,len(scene.godot_export_groups)):
+ bpy.ops.scene.godot_export_group(idx=i,export_all=True)
+
+ self.report({'INFO'}, "All Groups exported." )
+ return{'FINISHED'}
+
+
+class export_group(bpy.types.Operator):
+ bl_idname = "scene.godot_export_group"
+ bl_label = "Export Group"
+ bl_description = "Exports the active group to destination folder as Collada file."
+
+ idx = IntProperty(default=0)
+ export_all = BoolProperty(default=False)
+
+
+ def copy_object_recursive(self,ob,parent,single_user = True):
+ new_ob = bpy.data.objects[ob.name].copy()
+ if single_user or ob.type=="ARMATURE":
+ new_mesh_data = new_ob.data.copy()
+ new_ob.data = new_mesh_data
+ bpy.context.scene.objects.link(new_ob)
+
+ if ob != parent:
+ new_ob.parent = parent
+ else:
+ new_ob.parent = None
+
+ for child in ob.children:
+ self.copy_object_recursive(child,new_ob,single_user)
+ new_ob.select = True
+ return new_ob
+
+ def delete_object(self,ob):
+ if ob != None:
+ for child in ob.children:
+ self.delete_object(child)
+ bpy.context.scene.objects.unlink(ob)
+ bpy.data.objects.remove(ob)
+
+ def convert_group_to_node(self,group):
+ if group.dupli_group != None:
+ for object in group.dupli_group.objects:
+ if object.parent == None:
+ object = self.copy_object_recursive(object,object,True)
+ matrix = Matrix(object.matrix_local)
+ object.matrix_local = Matrix()
+ object.matrix_local *= group.matrix_local
+ object.matrix_local *= matrix
+
+ self.delete_object(group)
+
+ def execute(self,context):
+
+ scene = context.scene
+ group = context.scene.godot_export_groups
+
+ if not group[self.idx].active and self.export_all:
+ return{'FINISHED'}
+
+ for i,object in enumerate(group[self.idx].nodes):
+ if object.name in bpy.data.objects:
+ pass
+ else:
+ group[self.idx].nodes.remove(i)
+ bpy.ops.ed.undo_push(message="Clear not existent Group Nodes.")
+
+ path = group[self.idx].export_path
+ if (path.find("//")==0 or path.find("\\\\")==0):
+ #if relative, convert to absolute
+ path = bpy.path.abspath(path)
+ path = path.replace("\\","/")
+
+ ### if path exists and group export name is set the group will be exported
+ if os.path.exists(path) and group[self.idx].export_name != "":
+
+ context.scene.layers = [True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True,True]
+
+
+ if group[self.idx].export_name.endswith(".dae"):
+ path = os.path.join(path,group[self.idx].export_name)
+ else:
+ path = os.path.join(path,group[self.idx].export_name+".dae")
+
+ hide_select = []
+ for object in context.scene.objects:
+ hide_select.append(object.hide_select)
+ object.hide_select = False
+ object.select = False
+ context.scene.objects.active = None
+
+ ### make particle duplicates, parent and select them
+ nodes_to_be_added = []
+ if group[self.idx].use_include_particle_duplicates:
+ for i,object in enumerate(group[self.idx].nodes):
+ if bpy.data.objects[object.name].type != "EMPTY":
+ context.scene.objects.active = bpy.data.objects[object.name]
+ bpy.data.objects[object.name].select = True
+ bpy.ops.object.duplicates_make_real()
+ for object in context.selected_objects:
+ nodes_to_be_added.append(object)
+ bpy.ops.object.parent_set(type="OBJECT", keep_transform=False)
+
+ for object in context.selected_objects:
+ object.select = False
+ bpy.data.objects[object.name].select = False
+ context.scene.objects.active = None
+ for object in nodes_to_be_added:
+ object.select = True
+
+ ### select all other nodes from the group
+ for i,object in enumerate(group[self.idx].nodes):
+ if bpy.data.objects[object.name].type == "EMPTY":
+ self.convert_group_to_node(bpy.data.objects[object.name])
+ else:
+ bpy.data.objects[object.name].select = True
+
+ bpy.ops.object.transform_apply(location=group[self.idx].apply_loc, rotation=group[self.idx].apply_rot, scale=group[self.idx].apply_scale)
+ bpy.ops.export_scene.dae(check_existing=True, filepath=path, filter_glob="*.dae", object_types=group[self.idx].object_types, use_export_selected=group[self.idx].use_export_selected, use_mesh_modifiers=group[self.idx].use_mesh_modifiers, use_tangent_arrays=group[self.idx].use_tangent_arrays, use_triangles=group[self.idx].use_triangles, use_copy_images=group[self.idx].use_copy_images, use_active_layers=group[self.idx].use_active_layers, use_anim=group[self.idx].use_anim, use_anim_action_all=group[self.idx].use_anim_action_all, use_anim_skip_noexp=group[self.idx].use_anim_skip_noexp, use_anim_optimize=group[self.idx].use_anim_optimize, anim_optimize_precision=group[self.idx].anim_optimize_precision, use_metadata=group[self.idx].use_metadata)
+
+ self.report({'INFO'}, '"'+group[self.idx].name+'"' + " Group exported." )
+ msg = "Export Group "+group[self.idx].name
+
+ bpy.ops.ed.undo_push(message="")
+ bpy.ops.ed.undo()
+ bpy.ops.ed.undo_push(message=msg)
+
+ else:
+ self.report({'INFO'}, "Define Export Name and Export Path." )
+ return{'FINISHED'}
+
+class add_export_group(bpy.types.Operator):
+ bl_idname = "scene.godot_add_export_group"
+ bl_label = "Adds a new export Group"
+ bl_description = "Creates a new Export Group with the selected Objects assigned to it."
+
+ def execute(self,context):
+ scene = context.scene
+
+ item = scene.godot_export_groups.add()
+ item.name = "New Group"
+ for object in context.selected_objects:
+ node = item.nodes.add()
+ node.name = object.name
+ scene.godot_export_groups_index = len(scene.godot_export_groups)-1
+ bpy.ops.ed.undo_push(message="Create New Export Group")
+ return{'FINISHED'}
+
+class del_export_group(bpy.types.Operator):
+ bl_idname = "scene.godot_delete_export_group"
+ bl_label = "Delets the selected export Group"
+ bl_description = "Delets the active Export Group."
+
+ def invoke(self, context, event):
+ wm = context.window_manager
+ return wm.invoke_confirm(self,event)
+
+ def execute(self,context):
+ scene = context.scene
+
+ scene.godot_export_groups.remove(scene.godot_export_groups_index)
+ if scene.godot_export_groups_index > 0:
+ scene.godot_export_groups_index -= 1
+ bpy.ops.ed.undo_push(message="Delete Export Group")
+ return{'FINISHED'}
+
+class godot_node_list(bpy.types.PropertyGroup):
+ name = StringProperty()
+
+class godot_export_groups(bpy.types.PropertyGroup):
+ name = StringProperty(name="Group Name")
+ export_name = StringProperty(name="scene_name")
+ nodes = CollectionProperty(type=godot_node_list)
+ export_path = StringProperty(subtype="DIR_PATH")
+ active = BoolProperty(default=True,description="Export Group")
+
+ object_types = EnumProperty(name="Object Types",options={'ENUM_FLAG'},items=(('EMPTY', "Empty", ""),('CAMERA', "Camera", ""),('LAMP', "Lamp", ""),('ARMATURE', "Armature", ""),('MESH', "Mesh", ""),('CURVE', "Curve", ""),),default={'EMPTY', 'CAMERA', 'LAMP', 'ARMATURE', 'MESH','CURVE'})
+
+ apply_scale = BoolProperty(name="Apply Scale",description="Apply Scale before export.",default=False)
+ apply_rot = BoolProperty(name="Apply Rotation",description="Apply Rotation before export.",default=False)
+ apply_loc = BoolProperty(name="Apply Location",description="Apply Location before export.",default=False)
+
+ use_export_selected = BoolProperty(name="Selected Objects",description="Export only selected objects (and visible in active layers if that applies).",default=True)
+ use_mesh_modifiers = BoolProperty(name="Apply Modifiers",description="Apply modifiers to mesh objects (on a copy!).",default=True)
+ use_tangent_arrays = BoolProperty(name="Tangent Arrays",description="Export Tangent and Binormal arrays (for normalmapping).",default=False)
+ use_triangles = BoolProperty(name="Triangulate",description="Export Triangles instead of Polygons.",default=False)
+
+ use_copy_images = BoolProperty(name="Copy Images",description="Copy Images (create images/ subfolder)",default=False)
+ use_active_layers = BoolProperty(name="Active Layers",description="Export only objects on the active layers.",default=True)
+ use_anim = BoolProperty(name="Export Animation",description="Export keyframe animation",default=False)
+ use_anim_action_all = BoolProperty(name="All Actions",description=("Export all actions for the first armature found in separate DAE files"),default=False)
+ use_anim_skip_noexp = BoolProperty(name="Skip (-noexp) Actions",description="Skip exporting of actions whose name end in (-noexp). Useful to skip control animations.",default=True)
+ use_anim_optimize = BoolProperty(name="Optimize Keyframes",description="Remove double keyframes",default=True)
+
+ anim_optimize_precision = FloatProperty(name="Precision",description=("Tolerence for comparing double keyframes (higher for greater accuracy)"),min=1, max=16,soft_min=1, soft_max=16,default=6.0)
+
+ use_metadata = BoolProperty(name="Use Metadata",default=True,options={'HIDDEN'})
+ use_include_particle_duplicates = BoolProperty(name="Include Particle Duplicates",default=True)
+
+def register():
+ bpy.utils.register_class(godot_export_manager)
+ bpy.utils.register_class(godot_node_list)
+ bpy.utils.register_class(godot_export_groups)
+ bpy.utils.register_class(add_export_group)
+ bpy.utils.register_class(del_export_group)
+ bpy.utils.register_class(export_all_groups)
+ bpy.utils.register_class(export_groups_autosave)
+ bpy.utils.register_class(export_group)
+ bpy.utils.register_class(add_objects_to_group)
+ bpy.utils.register_class(del_objects_from_group)
+ bpy.utils.register_class(select_group_objects)
+ bpy.utils.register_class(UI_List_Godot)
+
+ bpy.types.Scene.godot_export_groups = CollectionProperty(type=godot_export_groups)
+ bpy.types.Scene.godot_export_groups_index = IntProperty(default=0,min=0)
+
+def unregister():
+ bpy.utils.unregister_class(godot_export_manager)
+ bpy.utils.unregister_class(godot_node_list)
+ bpy.utils.unregister_class(godot_export_groups)
+ bpy.utils.unregister_class(export_groups_autosave)
+ bpy.utils.unregister_class(add_export_group)
+ bpy.utils.unregister_class(del_export_group)
+ bpy.utils.unregister_class(export_all_groups)
+ bpy.utils.unregister_class(export_group)
+ bpy.utils.unregister_class(add_objects_to_group)
+ bpy.utils.unregister_class(del_objects_from_group)
+ bpy.utils.unregister_class(select_group_objects)
+ bpy.utils.unregister_class(UI_List_Godot)
+
+@persistent
+def auto_export(dummy):
+ bpy.ops.scene.godot_export_groups_autosave()
+
+bpy.app.handlers.save_post.append(auto_export)
+
+if __name__ == "__main__":
+ register()
diff --git a/tools/export/blender25/io_scene_dae/__init__.py b/tools/export/blender25/io_scene_dae/__init__.py
index 5b561673c5..182ec21e63 100644
--- a/tools/export/blender25/io_scene_dae/__init__.py
+++ b/tools/export/blender25/io_scene_dae/__init__.py
@@ -104,11 +104,6 @@ class ExportDAE(bpy.types.Operator, ExportHelper):
description="Export only objects on the active layers.",
default=True,
)
- use_exclude_ctrl_bones = BoolProperty(
- name="Exclude Control Bones",
- description="Exclude skeleton bones with names that begin with 'ctrl'.",
- default=True,
- )
use_anim = BoolProperty(
name="Export Animation",
description="Export keyframe animation",
diff --git a/tools/export/blender25/io_scene_dae/export_dae.py b/tools/export/blender25/io_scene_dae/export_dae.py
index 5245f32b82..7ee0e179b8 100644
--- a/tools/export/blender25/io_scene_dae/export_dae.py
+++ b/tools/export/blender25/io_scene_dae/export_dae.py
@@ -190,7 +190,7 @@ class DaeExporter:
if (not os.path.isfile(dstfile)):
shutil.copy(imgpath,dstfile)
- imgpath="images/"+os.path.basename(imgpath)
+ imgpath="images/"+os.path.basename(imgpath)
else:
### if file is not found save it as png file in the destination folder
img_tmp_path = image.filepath
@@ -204,7 +204,7 @@ class DaeExporter:
if (not os.path.isfile(dstfile)):
image.save()
- imgpath="images/"+os.path.basename(image.filepath)
+ imgpath="images/"+os.path.basename(image.filepath)
image.filepath = img_tmp_path
else:
@@ -921,7 +921,7 @@ class DaeExporter:
if (node.parent.type=="ARMATURE"):
armature=node.parent
if (armcount>1):
- self.operator.report({'WARNING'},'Object "'+node.name+'" refers to more than one armature! This is unsopported.')
+ self.operator.report({'WARNING'},'Object "'+node.name+'" refers to more than one armature! This is unsupported.')
if (armcount==0):
self.operator.report({'WARNING'},'Object "'+node.name+'" is child of an armature, but has no armature modifier.')
diff --git a/tools/freetype/SCsub b/tools/freetype/SCsub
index a31b8c4602..65b4827f9c 100644
--- a/tools/freetype/SCsub
+++ b/tools/freetype/SCsub
@@ -65,7 +65,5 @@ if (env["freetype"]=="builtin"):
# lib = env.Library("freetype_builtin",ft_sources)
# env.Prepend(LIBS=[lib])
-
-Export('env')
-
+Export('env')
diff --git a/tools/html_fs/godot.html b/tools/html_fs/godot.html
new file mode 100644
index 0000000000..36761deb90
--- /dev/null
+++ b/tools/html_fs/godot.html
@@ -0,0 +1,1317 @@
+<!doctype html>
+<html lang="en-us">
+ <head>
+ <meta charset="utf-8">
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+ <title>Emscripten-Generated Code</title>
+ <style>
+ body {
+ font-family: arial;
+ margin: 0;
+ padding: none;
+ }
+
+ .emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; }
+ div.emscripten { text-align: center; }
+ div.emscripten_border { border: 1px solid black; }
+ /* the canvas *must not* have any border or padding, or mouse coords will be wrong */
+ canvas.emscripten { border: 0px none; }
+
+ #emscripten_logo {
+ display: inline-block;
+ margin: 0;
+ }
+
+ .spinner {
+ height: 30px;
+ width: 30px;
+ margin: 0;
+ margin-top: 20px;
+ margin-left: 20px;
+ display: inline-block;
+ vertical-align: top;
+
+ -webkit-animation: rotation .8s linear infinite;
+ -moz-animation: rotation .8s linear infinite;
+ -o-animation: rotation .8s linear infinite;
+ animation: rotation 0.8s linear infinite;
+
+ border-left: 5px solid rgb(235, 235, 235);
+ border-right: 5px solid rgb(235, 235, 235);
+ border-bottom: 5px solid rgb(235, 235, 235);
+ border-top: 5px solid rgb(120, 120, 120);
+
+ border-radius: 100%;
+ background-color: rgb(189, 215, 46);
+ }
+
+ @-webkit-keyframes rotation {
+ from {-webkit-transform: rotate(0deg);}
+ to {-webkit-transform: rotate(360deg);}
+ }
+ @-moz-keyframes rotation {
+ from {-moz-transform: rotate(0deg);}
+ to {-moz-transform: rotate(360deg);}
+ }
+ @-o-keyframes rotation {
+ from {-o-transform: rotate(0deg);}
+ to {-o-transform: rotate(360deg);}
+ }
+ @keyframes rotation {
+ from {transform: rotate(0deg);}
+ to {transform: rotate(360deg);}
+ }
+
+ #status {
+ display: inline-block;
+ vertical-align: top;
+ margin-top: 30px;
+ margin-left: 20px;
+ font-weight: bold;
+ color: rgb(120, 120, 120);
+ }
+
+ #progress {
+ height: 20px;
+ width: 30px;
+ }
+
+ #controls {
+ display: inline-block;
+ float: right;
+ vertical-align: top;
+ margin-top: 30px;
+ margin-right: 20px;
+ }
+
+ #output {
+ width: 100%;
+ height: 200px;
+ margin: 0 auto;
+ margin-top: 10px;
+ display: block;
+ background-color: black;
+ color: white;
+ font-family: 'Lucida Console', Monaco, monospace;
+ outline: none;
+ }
+ </style>
+ </head>
+ <body>
+ <a href="http://emscripten.org">
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?><svg
+ version="1.1"
+ id="Layer_1"
+ x="0px"
+ y="0px"
+ width="296px"
+ height="78px"
+ viewBox="420 120 100 170"
+ enable-background="new 0 0 900 400"
+ xml:space="preserve"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="emscripten_powered_by_logo.svg"><metadata
+ id="metadata345"><rdf:RDF><cc:Work
+ rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
+ id="defs343"><linearGradient
+ y2="247.6265"
+ x2="225.1929"
+ y1="152.499"
+ x1="225.1929"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient5104"><stop
+ id="stop5106"
+ style="stop-color:#C1D72F"
+ offset="0.3227531" /><stop
+ id="stop5108"
+ style="stop-color:#BCD631"
+ offset="0.45119295" /><stop
+ id="stop5110"
+ style="stop-color:#AFD136"
+ offset="0.64491969" /><stop
+ id="stop5112"
+ style="stop-color:#ABD037"
+ offset="1" /><a:midPointStop
+ style="stop-color:#C1D72F"
+ offset="0.0123" /><a:midPointStop
+ style="stop-color:#C1D72F"
+ offset="0.3086" /><a:midPointStop
+ style="stop-color:#ABD037"
+ offset="1" /></linearGradient><linearGradient
+ inkscape:collect="always"
+ xlink:href="#SVGID_2_"
+ id="linearGradient5120"
+ x1="397.56918"
+ y1="128.12726"
+ x2="397.56918"
+ y2="166.25996"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.103059,0,0,1.103059,-38.997823,3.1312145)" /><filter
+ inkscape:collect="always"
+ id="filter5126"><feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="0.56377237"
+ id="feGaussianBlur5128" /></filter><linearGradient
+ inkscape:collect="always"
+ xlink:href="#SVGID_2_"
+ id="linearGradient5134"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.103059,0,0,1.103059,-38.997823,3.1312145)"
+ x1="397.56918"
+ y1="128.12726"
+ x2="397.56918"
+ y2="166.25996" /></defs><sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1440"
+ inkscape:window-height="838"
+ id="namedview341"
+ showgrid="false"
+ inkscape:zoom="0.63555556"
+ inkscape:cx="224.82424"
+ inkscape:cy="-52.085109"
+ inkscape:window-x="-8"
+ inkscape:window-y="-8"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="Layer_1" /><g
+ id="g5130"
+ transform="matrix(0.91591318,0,0,0.91591318,28.176953,14.143571)"><path
+ transform="matrix(1.103059,0,0,1.103059,-35.073492,-16.03923)"
+ id="path5122"
+ style="fill:#383838;fill-opacity:0.34705882;stroke:none;filter:url(#filter5126)"
+ d="m 494.39333,173.6323 c 0.57407,0.28703 1.87073,1.00226 2.89426,1.02855 0.55732,0.0143 1.14006,-0.1672 1.60262,-0.4784 1.20466,-0.81046 2.23561,-2.03031 2.72683,-3.39661 0.19424,-0.54027 0.0238,-1.72222 0.0238,-1.72222 l -3.82713,-14.06478 -1.98533,0 0.50231,-2.67891 6.36261,0 2.55939,12.22285 4.78392,-9.68746 -2.00924,0 0,-2.65498 7.19979,0 -11.00301,22.38875 -1.69829,1.91358 -2.29628,1.3395 -2.46371,0.26312 -2.29628,-0.21528 -2.79859,-1.36342 z m -12.0637,-14.56445 c -0.93698,1.88565 -1.70261,4.35262 -0.81842,6.26333 0.36549,0.78976 1.35098,1.19428 2.192,1.41737 0.60934,0.16133 1.29167,0.0999 1.88775,-0.10468 0.48126,-0.1655 0.8829,-0.5224 1.255,-0.8697 0.40341,-0.3768 0.77723,-0.80461 1.03505,-1.29262 0.21864,-0.41395 0.40236,-0.84786 0.49325,-1.30698 0.20667,-1.0485 0.35879,-2.1079 0.33583,-3.17631 -0.0184,-0.87403 -0.0789,-1.87107 -0.47711,-2.64959 -0.26344,-0.51379 -0.77017,-0.71849 -1.33113,-0.85633 -0.42395,-0.10479 -0.81432,-0.0626 -1.21773,0.10517 -0.65479,0.27273 -1.2544,0.5311 -1.82112,0.95764 -0.57331,0.4317 -1.21403,0.86959 -1.53337,1.5127 z m 0.65588,-4.31208 c 0,0 2.19341,-1.80738 3.45549,-2.27082 0.71718,-0.26365 3.45363,-0.65258 4.15,-0.3378 1.47292,0.66633 2.26103,1.57529 2.7222,2.60001 0.46118,1.02472 0.69944,2.59956 0.79701,3.73627 0.13278,1.55027 -0.13682,3.77629 -0.53404,5.74843 -0.30079,1.49256 -1.01883,2.74423 -1.83478,3.92156 -1.06526,1.5373 -1.82382,2.15116 -3.66756,2.46594 -0.98864,0.16889 -1.93845,0.46787 -3.25466,0.0928 -1.4384,-0.40963 -2.35273,-0.81244 -3.39599,-1.63337 -0.72524,-0.57054 -1.16043,-1.54043 -1.16043,-1.54043 l 0,2.82636 -4.8903,0 3.39872,-23.01602 -1.92242,-0.85888 0.0403,-2.38127 7.25847,0.0534 z m -23.77803,2.20447 c 0.29175,1.49273 0.0813,4.83252 -0.86111,6.69751 -0.3062,0.60617 -0.94813,1.32967 -1.55479,1.6983 -1.01515,0.61713 -2.21688,1.21322 -3.3966,1.07639 -0.47944,-0.0541 -0.97036,-0.34348 -1.24383,-0.74151 -0.47686,-0.69328 -0.43621,-1.55032 -0.45448,-2.39198 -0.024,-1.06873 0.13137,-2.23775 0.38272,-3.277 0.18705,-0.7744 0.4229,-1.58254 0.86111,-2.24844 0.39037,-0.59323 0.92628,-1.12617 1.55478,-1.45909 0.54854,-0.29014 1.19695,-0.38467 1.81791,-0.40664 0.63637,-0.0231 1.3031,0.0385 1.88966,0.28704 0.3875,0.16453 0.92361,0.3524 1.00463,0.76542 z m 1.29312,-9.69052 -0.64254,6.12262 c 0,0 -1.68393,-0.96858 -2.605,-1.25148 -0.73032,-0.22434 -1.50312,-0.36654 -2.26624,-0.33838 -0.97069,0.0345 -1.91182,0.22099 -2.81751,0.57088 -0.9185,0.35497 -1.78344,0.94565 -2.49338,1.62792 -0.88025,0.84538 -1.51404,1.90455 -2.02977,3.0106 -0.39653,0.84993 -0.69517,1.75284 -0.87975,2.67232 -0.22875,1.14241 -0.44415,2.38719 -0.43937,3.55197 0.01,1.44865 0.0623,2.89489 0.54092,4.26214 0.25525,0.72907 0.71643,1.40578 1.28572,1.9283 0.56835,0.52207 1.29566,0.87604 2.02935,1.11621 0.41072,0.13491 0.85346,0.17274 1.28579,0.16935 1.00285,-0.01 2.03715,-0.0883 2.97671,-0.43999 0.66497,-0.2489 1.21759,-0.73399 1.79298,-1.1502 0.75304,-0.54475 2.16476,-1.86006 2.16476,-1.86006 l 0,1.62374 -0.5751,0 0,1.48807 6.86709,0 0,-2.84135 -1.92841,0 3.21374,-23.57782 -7.37422,0 0,2.33412 z m -93.60062,7.55781 2.33363,15.57933 6.23084,0 4.04243,-11.34169 1.62654,11.34169 5.88425,0 7.05633,-16.38872 0,-2.0141 -6.1713,0 0,2.82349 1.88966,0 -4.04243,10.16973 -0.74151,0 -1.29167,-12.55773 -5.38194,0 -4.7361,12.50989 -1.55478,-12.94538 -6.86496,0 0,2.82349 z m -12.15,0.72146 c -0.56264,0.0892 -1.03524,0.17358 -1.53086,0.45447 -0.737,0.41808 -1.46132,0.95771 -1.91357,1.67437 -0.44123,0.70048 -0.53204,1.57581 -0.66975,2.39196 -0.1751,1.04003 -0.20064,2.10306 -0.19136,3.15741 0.01,0.81614 -0.0138,1.66577 0.35879,2.39197 0.1904,0.37315 0.52874,0.80945 0.88503,1.02855 0.56015,0.34453 1.06632,0.55494 1.72222,0.598 0.72597,0.0483 1.48801,-0.18852 2.10493,-0.57408 0.59422,-0.37072 1.03334,-0.97401 1.38735,-1.5787 0.46117,-0.78744 0.70905,-1.69257 0.90895,-2.58334 0.20377,-0.90704 0.33579,-1.84565 0.28703,-2.77468 -0.0491,-0.92714 -0.18211,-1.88434 -0.57407,-2.72684 -0.2728,-0.58681 -0.70954,-1.00753 -1.29166,-1.29165 -0.44403,-0.21628 -0.99455,-0.24402 -1.48303,-0.16744 z m -6.62442,-0.73581 c 0.65404,-0.6664 1.4072,-1.25479 2.23273,-1.69161 1.0305,-0.54505 2.16429,-0.92749 3.31518,-1.11604 1.51307,-0.24806 3.09342,-0.2847 4.60036,0 0.88055,0.16632 1.78322,0.44742 2.50307,0.98113 0.77409,0.57312 1.35279,1.40936 1.79291,2.26639 0.42901,0.83457 0.6828,1.77223 0.77798,2.70605 0.16564,1.61985 0.024,3.29135 -0.37201,4.87103 -0.33328,1.33759 -0.88436,2.64754 -1.65745,3.78889 -0.67549,0.99679 -1.52894,1.91262 -2.53721,2.5709 -0.89957,0.58746 -1.9718,0.87641 -3.01035,1.15006 -0.87153,0.22963 -1.77166,0.4095 -2.67235,0.40576 -1.21068,-0.01 -2.47998,-0.0817 -3.58589,-0.57511 -1.09854,-0.48896 -1.89728,-1.32739 -2.60455,-2.30013 -0.61123,-0.83995 -1.02561,-1.59975 -1.31932,-2.87516 -0.2125,-0.9233 -0.40006,-2.19912 -0.37215,-3.14592 0.0335,-1.16537 0.3568,-2.74121 0.83416,-3.80434 0.52547,-1.17098 1.17609,-2.3161 2.07489,-3.2319 z m 94.95184,13.82318 c -2.20516,1.01761 -4.61429,1.69636 -7.02343,1.69636 -5.32726,0 -7.22678,-3.12145 -7.22678,-7.22678 0,-7.1251 4.54685,-11.19645 10.0772,-11.19645 3.7324,0 5.56453,1.69625 5.56453,4.47856 0,4.85189 -5.12329,6.27735 -10.41633,6.82001 0.10168,1.73076 0.81446,3.32485 3.3592,3.32485 1.2218,0 2.88401,-0.37315 4.91982,-1.22099 z m -3.22292,-11.77374 c 0,-0.81423 -0.57695,-1.28891 -1.62876,-1.28891 -1.89988,0 -3.46041,1.66212 -3.96978,4.34287 1.45897,-0.20368 5.59854,-0.91613 5.59854,-3.05396 z m -30.33408,11.77374 c -2.2054,1.01761 -4.61457,1.69636 -7.02371,1.69636 -5.32653,0 -7.22671,-3.12145 -7.22671,-7.22678 0,-7.1251 4.54679,-11.19645 10.07785,-11.19645 3.73175,0 5.56382,1.69625 5.56382,4.47856 0,4.85189 -5.12273,6.27735 -10.41568,6.82001 0.10142,1.73076 0.81422,3.32485 3.35884,3.32485 1.22158,0 2.8842,-0.37315 4.91994,-1.22099 z m -3.22305,-11.77374 c 0,-0.81423 -0.57638,-1.28891 -1.62883,-1.28891 -1.89959,0 -3.46023,1.66212 -3.96971,4.34287 1.4591,-0.20368 5.59854,-0.91613 5.59854,-3.05396 z m -82.36051,20.5268 -0.0679,-0.13571 0.98406,-5.66614 2.10303,-15.16698 c 0.0687,-0.40664 -0.0332,-0.61046 -0.30522,-0.71214 l -1.66259,-0.61111 0.37379,-2.57855 6.78556,0 -0.40663,2.71427 0.10142,0.0335 c 2.0016,-1.86631 4.10566,-3.08743 6.24306,-3.08743 2.91821,0 4.95366,1.86577 4.95366,6.78561 0,4.68241 -1.83206,11.6379 -8.14271,11.6379 -2.20534,0 -3.42694,-0.84825 -4.68256,-1.73039 l -0.74621,5.08917 c -0.0341,0.37361 0.0326,0.50898 0.47457,0.54273 l 3.42697,0.33969 -0.37385,2.5447 -9.0589,0 z m 6.78613,-12.04485 c 0.84787,0.71258 1.96788,1.32305 3.22348,1.32305 2.74798,0 3.76601,-3.86811 3.76601,-6.85368 0,-2.002 -0.47476,-3.32542 -1.76432,-3.32542 -1.35696,0 -3.08763,1.4591 -4.30913,2.54506 z m 81.08934,4.85147 0.33969,-2.54464 1.56064,-0.2038 c 0.47498,-0.0683 0.5429,-0.1695 0.61084,-0.67837 l 1.42466,-10.34864 c 0.0335,-0.37315 -0.0335,-0.61046 -0.33914,-0.71214 l -1.69691,-0.61111 0.37365,-2.57855 6.71797,0 -0.44097,3.05395 0.10191,0.0679 c 1.32326,-1.89982 3.22359,-3.46042 5.39485,-3.46042 0.7463,0 2.0359,0.13582 2.61295,0.30538 l -0.84863,6.17508 -3.96972,-0.13582 -0.10157,-1.76443 c -0.0335,-0.30537 -0.10223,-0.40701 -0.37391,-0.40701 -0.64452,0 -1.69636,0.78027 -2.64651,1.76455 l -1.18674,8.61817 c -0.0687,0.54303 -0.0334,0.64474 0.47477,0.67874 l 3.22351,0.27142 -0.37384,2.51081 -10.8575,0 z"
+ inkscape:connector-curvature="0"
+ sodipodi:nodetypes="cssscccccccccccccccccssssssssccssscssssscsssccccccccsssssssssccsccsssssssssscsscccccccccccccccccccccccccccccccsssscsssssscscsssssssscsssssssssscsssscsccsscscsssscsccsscsccccccccccsssccccccccssscccccccccccccsccccsccccccc" /><path
+ sodipodi:nodetypes="cssscccccccccccccccccssssssssccssscssssscsssccccccccsssssssssccsccsssssssssscsscccccccccccccccccccccccccccccccsssscsssssscscsssssssscsssssssssscsssscsccsscscsssscsccsscsccccccccccsssccccccccssscccccccccccccsccccsccccccc"
+ inkscape:connector-curvature="0"
+ d="m 509.55935,174.26011 c 0.63327,0.31663 2.06355,1.10555 3.19256,1.13455 0.61476,0.0158 1.25757,-0.18443 1.76781,-0.5277 1.3288,-0.89397 2.46618,-2.23946 3.00784,-3.74661 0.21419,-0.59598 0.0258,-1.89972 0.0258,-1.89972 l -4.22153,-15.51428 -2.18993,0 0.55406,-2.95501 7.01835,0 2.82313,13.48255 5.27696,-10.68586 -2.21631,0 0,-2.92858 7.94179,0 -12.13698,24.69605 -1.87332,2.11078 -2.5329,1.4776 -2.71762,0.29022 -2.53295,-0.23748 -3.08699,-1.50392 z m -13.30698,-16.06545 c -1.0335,2.08005 -1.87803,4.80122 -0.90274,6.90883 0.4032,0.87116 1.49018,1.31738 2.4179,1.56347 0.67214,0.17793 1.42477,0.1102 2.08233,-0.11548 0.53084,-0.1826 0.97383,-0.5762 1.38432,-0.9593 0.44502,-0.4157 0.85733,-0.8875 1.14176,-1.42582 0.24113,-0.45665 0.44375,-0.93526 0.54404,-1.44168 0.22797,-1.1566 0.3958,-2.3252 0.37043,-3.50371 -0.0204,-0.96413 -0.0869,-2.06387 -0.52631,-2.92259 -0.29054,-0.56679 -0.84946,-0.79259 -1.46826,-0.94463 -0.46761,-0.11559 -0.89829,-0.0686 -1.34322,0.11597 -0.72226,0.30083 -1.38368,0.5859 -2.00879,1.05634 -0.63242,0.4762 -1.33915,0.9593 -1.69146,1.6686 z m 0.72346,-4.75648 c 0,0 2.41951,-1.99358 3.81169,-2.50482 0.79109,-0.29085 3.80953,-0.71977 4.57766,-0.3726 1.6247,0.73503 2.49408,1.73759 3.00274,2.86791 0.50868,1.13043 0.77154,2.86756 0.87911,4.12137 0.14648,1.71007 -0.15092,4.16549 -0.58904,6.34083 -0.33179,1.64636 -1.12383,3.02703 -2.02388,4.32576 -1.17506,1.6957 -2.01178,2.37286 -4.04556,2.72004 -1.09051,0.18629 -2.13814,0.51607 -3.59006,0.10268 -1.5866,-0.45183 -2.59522,-0.89615 -3.74599,-1.8017 -0.79994,-0.62933 -1.28003,-1.6992 -1.28003,-1.6992 l 0,3.11766 -5.39426,0 3.74898,-25.38802 -2.12052,-0.94738 0.0443,-2.62669 8.00657,0.0587 z m -26.22853,2.43167 c 0.32185,1.64663 0.0893,5.33062 -0.9498,7.38781 -0.33781,0.66857 -1.04588,1.46667 -1.7151,1.8733 -1.11975,0.68073 -2.44527,1.33822 -3.7466,1.18729 -0.52883,-0.0601 -1.07036,-0.37888 -1.37203,-0.81791 -0.52601,-0.76478 -0.48121,-1.71012 -0.50128,-2.63848 -0.0263,-1.17893 0.14487,-2.46835 0.42212,-3.6147 0.20635,-0.8543 0.4665,-1.74564 0.94981,-2.48024 0.43067,-0.65433 1.02178,-1.24217 1.71508,-1.60939 0.60504,-0.32004 1.32025,-0.42437 2.00521,-0.44854 0.70197,-0.0251 1.4374,0.0425 2.08446,0.31654 0.4274,0.18153 1.01882,0.3888 1.10813,0.84432 z m 1.42642,-10.68922 -0.70874,6.75362 c 0,0 -1.85753,-1.06838 -2.8735,-1.38048 -0.80562,-0.24744 -1.65802,-0.40424 -2.49984,-0.37318 -1.07069,0.0382 -2.10882,0.24369 -3.1078,0.62968 -1.01321,0.39157 -1.96724,1.04315 -2.75039,1.79572 -0.97095,0.93248 -1.67003,2.10085 -2.23897,3.3208 -0.43738,0.93753 -0.76677,1.93354 -0.9704,2.94777 -0.2523,1.26016 -0.4899,2.63324 -0.48461,3.91802 0.011,1.59795 0.0683,3.19329 0.59661,4.70144 0.28155,0.80417 0.79028,1.55058 1.41822,2.127 0.62695,0.57587 1.4292,0.96634 2.23856,1.23121 0.45301,0.14881 0.94135,0.19054 1.41828,0.18685 1.10615,-0.011 2.24705,-0.0973 3.28346,-0.48539 0.73352,-0.2745 1.34304,-0.80959 1.97773,-1.2687 0.83064,-0.60085 2.38786,-2.05176 2.38786,-2.05176 l 0,1.79104 -0.63429,0 0,1.64147 7.57478,0 0,-3.13415 -2.12721,0 3.54494,-26.00772 -8.13411,0 0,2.57462 z m -103.24702,8.33671 2.57413,17.18493 6.87304,0 4.45903,-12.51049 1.79414,12.51049 6.49065,0 7.78353,-18.07772 0,-2.2217 -6.8073,0 0,3.11449 2.08446,0 -4.45903,11.21783 -0.8179,0 -1.42488,-13.85193 -5.93654,0 -5.2242,13.79919 -1.71497,-14.27958 -7.57246,0 0,3.11449 z m -13.4021,0.79586 c -0.62064,0.0982 -1.14194,0.19148 -1.68866,0.50127 -0.813,0.46118 -1.61192,1.05641 -2.11077,1.84697 -0.48673,0.77268 -0.58683,1.73821 -0.73875,2.63846 -0.1932,1.14723 -0.22134,2.31976 -0.21116,3.48281 0.011,0.90024 -0.0148,1.83747 0.39579,2.63847 0.21,0.41165 0.58324,0.89285 0.97623,1.13455 0.61796,0.38003 1.17622,0.61214 1.89972,0.6596 0.80077,0.0533 1.64141,-0.20792 2.32189,-0.63318 0.65546,-0.40892 1.13978,-1.07441 1.53029,-1.7414 0.50878,-0.86864 0.78215,-1.86707 1.00265,-2.84964 0.22477,-1.00044 0.37039,-2.03585 0.31663,-3.06058 -0.0541,-1.02274 -0.20091,-2.07854 -0.63327,-3.00784 -0.3009,-0.64731 -0.78264,-1.11143 -1.42476,-1.42485 -0.48983,-0.23858 -1.09705,-0.26912 -1.63583,-0.18464 z m -7.30711,-0.81171 c 0.72143,-0.735 1.55219,-1.38409 2.46282,-1.86591 1.1367,-0.60125 2.38729,-1.02309 3.65678,-1.23104 1.66908,-0.27366 3.41222,-0.314 5.07446,0 0.97135,0.18342 1.96702,0.49352 2.76107,1.08223 0.85389,0.63222 1.49219,1.55466 1.97771,2.49999 0.47321,0.92057 0.7531,1.95483 0.85808,2.98495 0.18274,1.78675 0.0263,3.63055 -0.41031,5.37303 -0.36757,1.47539 -0.97545,2.92034 -1.82825,4.17929 -0.74509,1.09959 -1.68654,2.10982 -2.79871,2.8359 -0.99227,0.64796 -2.175,0.96671 -3.32055,1.26856 -0.96139,0.25333 -1.95426,0.4517 -2.94774,0.44756 -1.33549,-0.011 -2.73559,-0.0897 -3.9555,-0.63431 -1.21174,-0.53936 -2.09278,-1.46419 -2.87295,-2.53723 -0.67423,-0.92645 -1.13131,-1.76457 -1.45532,-3.17146 -0.2344,-1.0184 -0.44126,-2.42572 -0.41044,-3.47012 0.0365,-1.28547 0.39349,-3.02371 0.92005,-4.19644 0.57967,-1.29168 1.29729,-2.5548 2.2888,-3.565 z m 104.73744,15.24778 c -2.43247,1.12251 -5.0899,1.87126 -7.74734,1.87126 -5.87626,0 -7.97147,-3.44315 -7.97147,-7.97158 0,-7.8594 5.0154,-12.35035 11.11569,-12.35035 4.11711,0 6.13803,1.87105 6.13803,4.94016 0,5.35189 -5.65129,6.92425 -11.48983,7.52281 0.11219,1.90916 0.89836,3.66755 3.7054,3.66755 1.3477,0 3.18121,-0.41165 5.42682,-1.34689 z m -3.55513,-12.98704 c 0,-0.89823 -0.63635,-1.42181 -1.79655,-1.42181 -2.09568,0 -3.81712,1.83342 -4.37899,4.79047 1.60937,-0.22468 6.17554,-1.01053 6.17554,-3.36866 z m -33.46028,12.98704 c -2.4327,1.12251 -5.09006,1.87126 -7.74751,1.87126 -5.87553,0 -7.97151,-3.44315 -7.97151,-7.97158 0,-7.8594 5.01539,-12.35035 11.11645,-12.35035 4.11635,0 6.13722,1.87105 6.13722,4.94016 0,5.35189 -5.65062,6.92425 -11.48908,7.52281 0.11182,1.90916 0.89812,3.66755 3.70494,3.66755 1.34748,0 3.1815,-0.41165 5.42704,-1.34689 z m -3.55514,-12.98704 c 0,-0.89823 -0.63578,-1.42181 -1.79674,-1.42181 -2.09539,0 -3.81683,1.83342 -4.37881,4.79047 1.60951,-0.22468 6.17555,-1.01053 6.17555,-3.36866 z m -90.84852,22.6422 -0.0749,-0.14971 1.08546,-6.25004 2.31984,-16.73008 c 0.0757,-0.44854 -0.0367,-0.67336 -0.33673,-0.78554 l -1.83388,-0.67411 0.41228,-2.84425 7.48486,0 -0.44853,2.99397 0.11182,0.0371 c 2.2079,-2.05871 4.52887,-3.40563 6.88646,-3.40563 3.21901,0 5.46427,2.05807 5.46427,7.48491 0,5.16501 -2.02094,12.8373 -8.98192,12.8373 -2.43264,0 -3.78014,-0.93565 -5.16516,-1.90869 l -0.82311,5.61357 c -0.0376,0.41212 0.0356,0.56148 0.52347,0.59873 l 3.78017,0.37469 -0.41234,2.8069 -9.9925,0 z m 7.48553,-13.28615 c 0.93528,0.78598 2.17068,1.45946 3.55568,1.45946 3.03118,0 4.15411,-4.26682 4.15411,-7.56009 0,-2.2083 -0.52366,-3.66812 -1.94612,-3.66812 -1.49686,0 -3.40583,1.6095 -4.75323,2.80736 z m 89.44624,5.35147 0.37469,-2.80694 1.72154,-0.2248 c 0.52388,-0.0753 0.5988,-0.1869 0.67374,-0.74827 l 1.57152,-11.41514 c 0.0365,-0.41155 -0.0368,-0.67336 -0.3741,-0.78554 l -1.87181,-0.67411 0.41215,-2.84425 7.41037,0 -0.48647,3.36865 0.11241,0.0749 c 1.45966,-2.09562 3.55581,-3.81702 5.95085,-3.81702 0.8232,0 2.2457,0.14982 2.88225,0.33688 l -0.93613,6.81148 -4.37882,-0.14982 -0.11196,-1.94633 c -0.0371,-0.33677 -0.11284,-0.44891 -0.41252,-0.44891 -0.71092,0 -1.87116,0.86067 -2.91921,1.94635 l -1.30904,9.50637 c -0.0757,0.59903 -0.0368,0.71124 0.52367,0.74874 l 3.55571,0.29932 -0.41234,2.76961 -11.9765,0 z"
+ style="fill:url(#linearGradient5134);fill-opacity:1;stroke:none"
+ id="path5080" /></g><path
+ fill="#E2E2E2"
+ d="M256.023,135.437H196.36c-16.432,0-29.8,13.368-29.8,29.8v73.527c0,16.432,13.368,29.8,29.8,29.8h59.663 c16.433,0,29.801-13.368,29.801-29.8v-73.527C285.824,148.805,272.456,135.437,256.023,135.437z M191.561,165.236 c0-2.646,2.153-4.8,4.8-4.8h59.663c2.647,0,4.801,2.153,4.801,4.8v73.527c0,2.646-2.153,4.8-4.801,4.8H196.36 c-2.646,0-4.8-2.153-4.8-4.8V165.236z"
+ id="path3" /><path
+ d="m 531.664,250.155 h 18.498 l -2.809,18.064 h 5.59 37.586 l 2.6,-17.718 c 4.98,-1.091 9.133,-3.455 12.512,-6.693 3.084,4.075 8.566,7.37 18.252,7.37 6.338,0 12.775,-1.807 17.174,-3.687 4.254,2.399 9.463,3.687 15.459,3.687 3.088,0 6.236,-0.355 9.426,-1.023 h 67.135 l 3.354,-24.827 -5.445,-0.764 1.879,-13.356 c 0.371,-2.386 0.449,-4.66 0.449,-6.156 l -0.008,-0.375 c -0.457,-12.191 -8.139,-19.765 -20.045,-19.765 -2.404,0 -4.623,0.314 -6.676,0.852 h -34.189 l -0.035,0.244 c -2.527,-0.701 -5.41,-1.096 -8.686,-1.096 -3.801,0 -7.406,0.555 -10.76,1.598 l 0.105,-0.746 h -12.467 l 1.826,-12.951 H 615.08 l -1.846,7.658 c -1.373,5.704 -2.213,5.793 -4.453,6.03 l -4.508,0.477 c -3.049,-1.424 -6.357,-2.065 -9.602,-2.065 -2.135,0 -4.275,0.284 -6.416,0.852 h -19.291 c 0.502,-1.772 0.775,-3.674 0.775,-5.678 0,-9.601 -6.846,-16.305 -16.646,-16.305 -11.055,0 -18.775,7.721 -18.775,18.776 0,0.951 0.082,1.869 0.219,2.764 -2.135,-0.288 -4.277,-0.409 -5.553,-0.409 -2.053,0 -4.072,0.288 -6.045,0.852 h -31.342 c -2.74,-0.553 -5.641,-0.852 -8.537,-0.852 -7.138,0 -13.492,1.674 -18.808,4.723 l -3.451,-1.461 c -3.711,-1.571 -11.232,-3.262 -18.979,-3.262 -8.933,0 -16.383,2.56 -21.576,7.016 -3.265,-4.473 -8.523,-7.016 -15.228,-7.016 -4.822,0 -9.021,1.477 -12.572,3.44 -2.996,-2.204 -6.796,-3.44 -11.115,-3.44 -2.327,0 -4.48,0.315 -6.476,0.852 h -33.963 l -0.035,0.245 c -2.526,-0.702 -5.41,-1.097 -8.687,-1.097 -20.458,0 -35.307,16.031 -35.307,38.117 0,17.363 10.785,28.149 28.148,28.149 3.087,0 6.236,-0.356 9.426,-1.023 h 88.816 c 3.706,0.676 7.669,1.023 11.154,1.023 8.907,0 16.278,-2.375 21.51,-6.593 4.872,4.252 11.585,6.593 19.728,6.593 3.053,0 6.206,-0.368 9.286,-1.023 h 44.664 2.069 z"
+ id="path5"
+ inkscape:connector-curvature="0"
+ style="fill:#e2e2e2" /><path
+ fill="#F5F5F5"
+ d="M255.023,133.437H195.36c-16.432,0-29.8,13.368-29.8,29.8v73.527c0,16.432,13.368,29.8,29.8,29.8h59.663 c16.433,0,29.801-13.368,29.801-29.8v-73.527C284.824,146.805,271.456,133.437,255.023,133.437z M190.561,163.236 c0-2.646,2.153-4.8,4.8-4.8h59.663c2.647,0,4.801,2.153,4.801,4.8v73.527c0,2.646-2.153,4.8-4.801,4.8H195.36 c-2.646,0-4.8-2.153-4.8-4.8V163.236z"
+ id="path7" /><g
+ id="g9"><g
+ id="g11"><path
+ fill="#FBFDF8"
+ d="M195.361,251.626c-8.161,0-14.8-6.64-14.8-14.8v-73.527c0-8.161,6.639-14.8,14.8-14.8h59.663 c8.161,0,14.8,6.639,14.8,14.8v73.527c0,8.16-6.639,14.8-14.8,14.8H195.361z"
+ id="path13" /><path
+ fill="#F0F4E1"
+ d="M255.024,152.499c5.964,0,10.8,4.835,10.8,10.8v73.527c0,5.965-4.835,10.8-10.8,10.8h-59.663 c-5.964,0-10.8-4.835-10.8-10.8v-73.527c0-5.964,4.835-10.8,10.8-10.8H255.024 M255.024,144.499h-59.663 c-10.366,0-18.8,8.434-18.8,18.8v73.527c0,10.366,8.434,18.8,18.8,18.8h59.663c10.366,0,18.8-8.434,18.8-18.8v-73.527 C273.824,152.933,265.391,144.499,255.024,144.499L255.024,144.499z"
+ id="path15" /></g><defs
+ id="defs17"><filter
+ id="Adobe_OpacityMaskFilter"
+ filterUnits="userSpaceOnUse"
+ x="176.562"
+ y="144.499"
+ width="97.263"
+ height="111.127"><feColorMatrix
+ type="matrix"
+ values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"
+ color-interpolation-filters="sRGB"
+ result="source"
+ id="feColorMatrix20" /></filter></defs><mask
+ maskUnits="userSpaceOnUse"
+ x="176.562"
+ y="144.499"
+ width="97.263"
+ height="111.127"
+ id="SVGID_1_"><g
+ filter="url(#Adobe_OpacityMaskFilter)"
+ id="g23"><image
+ overflow="visible"
+ width="422"
+ height="480"
+ xlink:href="data:image/jpeg;base64,/9j/4AAQSkZJRgABAgEBLAEsAAD/7AARRHVja3kAAQAEAAAAHgAA/+4AIUFkb2JlAGTAAAAAAQMA EAMCAwYAAAg2AAAQ4QAAF1b/2wCEABALCwsMCxAMDBAXDw0PFxsUEBAUGx8XFxcXFx8eFxoaGhoX Hh4jJSclIx4vLzMzLy9AQEBAQEBAQEBAQEBAQEABEQ8PERMRFRISFRQRFBEUGhQWFhQaJhoaHBoa JjAjHh4eHiMwKy4nJycuKzU1MDA1NUBAP0BAQEBAQEBAQEBAQP/CABEIAeMBqQMBIgACEQEDEQH/ xACjAAEAAgMBAQAAAAAAAAAAAAAABQYBAwQHAgEBAQAAAAAAAAAAAAAAAAAAAAEQAAEDAQQKAwAC AwEAAAAAAAABAwQCMRMUBRBQEjMVJQYWNgcgESEwI5AiMkARAAEBAwsEAQIFAwUBAAAAAAABMQID EFAycqOz0wQ0RaURIXGRIEFRMGEiExRAgRKh0SMzQxUSAQAAAAAAAAAAAAAAAAAAAJD/2gAMAwEA AhEDEQAAANUJsrZYFfFgV8WBXxYEL0ki5fo6GjJuaRuaRuaRuaRuaRuaRuaRuaRuaRuaRuaRuaRu aRuaMHQ5dR3ojnJ9XxYFfFgV8WD0jxf2AodbslbAD6mDhlpLvI/qkuiovZL7CGzNfRCJwQacEGnB Bp0QSdEEnRBJ0QSdEEnRBJ3BBpwQacEHidwQXzPfBA6bBqK5w2nlKVH3iJitt+gAeweP+wFDrdkr Y+vmaN02k6+e3d2Gjo6N0c2zoyaM7xozuGluGluGluGluGluGluGluGluGluGluGluGnG8c/z1YO PVIfJF80xoIGPsfBVVrl6hIrD7+B7B4/7AUOt2StnXaYyxHTJ6ZKvrqb4x9MgAAAAAAAAAAAAAAA DGR8692Dh4pbkIKJscTVNiLdVY1+weP+wFDgJ+JLJORs3XbIc3dGz6ZAAAAAAAAAAAAAAAAAAAPn R0ayMi5uLqv1S51eIT2Dx/2AofB38Ra5uIm6kOzm6o+gAAAAAAAAAAAAAAAAAAAPj7+TkjJWNIOt 2et1WfYPH/YIofH2cZcJyEnKkenn6IyAAAAAAAAAAAAAAAAAAABjODmjZONIWt2WtVWPYPH/AGCK Hx9nIXGcg5ypLfo3xkAAAAAAAAAAAAAAAAAAADGcHPGyUaQ1astaqseweP8AsEUPk6+QuM7BTtSW 7TujIAAAAAAAAAAAAAAAAAAAGM4OeOkY4hqzZqzVY9g8f9gih8nXyFxnYKdqS3ad0ZAAAAAAAAAA AAAAAAAAAAxnBzx0jHENWbNWarHsHj/sEUPk6+QuM7BTtSW7TujIAAAAAAAAAAAAAAAAAAAGM4Oe OkY4hqzZqzVY9g8f9gih8nXyFxnYKdqS3ad0ZAAAAAAAAAAAAAAAAAAAAxnBzx0jHENWbNWarHsH j/sEUPk6+QuM7BTtSW7TujIAAAAAAAAAAAAAAAAAAAGM4OeOkY4hqzZqzVY9g8f9gih8nXyFxnYK dqS3ad0ZAAAAAAAAAAAAAAAAAAAAxnBzx0jHENWbNWarHsHj/sEUPk6+QuM7BTtSW7TujIAAAAAA AAAAAAAAAAAAAGM4OeOkY4hqzZqzVY9g8f8AYIofJ18hcZ2Cnakt2ndGQAAAAAAAAAAAAAAAAAAA MZwc8dIxxDVmzVmqx7B4/wCwRQ+Tr5C4zsFO1JbtO6MgAAAAAAAAAAAAAAAAAAAYzg546RjiGrNm rNVj2Dx/2CKHydfIXGdgp2pLdp3RkAAAAAAAAAAAAAAAAAAADGcHPHSMcQ1Zs1ZqseweP+wRQ+Tr 5C4zsFO1JbtO6MgAAAAAAAAAAAAAAAAAAAYzg546RjiGrNmrNVj2Dx/2CKHydfIXGdgp2pLdp3Rk AAAAAAAAAAAAAAAAAAADGcHPHSMcQ1Zs1ZqseweP+wRQ+Tr5C4zsFO1JbtO6MgAAAAAAAAAAAAAA AAAAAYzg546RjiGrNmrNVj2Dx/2CKHydfIXGdgp2pLdp3RkAAAAAAAAAAAAAAAAAAADGcHPHSMcQ 1Zs1ZqseweP+wRQ+Tr4y5TkHOVJb9G+MgAAAAAAAAAAAAAAAAAAAYzg542SjSGrVlrVVj2Dx/wBg ih8fZxlxnIKcqT6ObpjIAAAAAAAAAAAAAAAAAAAGM4OeNkY0h61Za1VY9g8f9gih8Xbwlxm4GbqW 6uLrj7AAAAAAAAAAAAAAAAAAAA+fr5OaNkI0ia1Y61Vb9g8f9gihxknCl1m65N1OdsZ3x0ZxkAAA AAAAAAAAAAAAAAAAx8fek5ozui6jazYKsRPsHj/sEUOu2Ktlqn6XZ6scjBSRLbOPpjYxkAAAAAAA AAAAAAAAAAYfJjm+uM0xXVE1xVOZr0Y9g8f9gKHW7JWz7s1W6i9SdYlasXXB9pLbI7fHY5/s3NeT 7fGT6fI+nyPp8j6fI+nyPp8j6fI+nyPp8j6fI+nyPp8D7x8fJtxp1m7Tp5jbw/MfWIjbXTk5SHsH j/sBQ63ZK2AdthqO8vXbUZWrJ0V/oJ7ZB7Sa+ofJMIkS6IySyJRLIkSyJEsiRLIkSyJEsiRLIkSy JVLYiRLYicEr8xfwSemN0kjy8PIdkfxQp0xWEAPYPH/YCh1uyVsAAz08ome2si37qZkumaULspIu 2aRkuyki7KSLspIuyki7KSLspIuyki7KSLtilC6qSLtilC6fNNFu5qz8k7wcI+vkAAHsHj/sBWoQ AAAAAAAAAAAAAAAAAAAAAAAAAHpAf//aAAgBAgABBQD/ACi//9oACAEDAAEFAP8AKL//2gAIAQEA AQUA6w6rz/LM+776rO++qzvvqs776rO++qzvvqs776rO++qzvvqs776rO++qzvvqs776rO++qzvv qs776rO++qzvvqs776rO++qzvvqs776rO++qzvvqs776rO++qzvvqs776rO++qzvvqs776rO++qz vvqs776rO++qzvvqs776rO++qzvvqs776rO++qzvvqs776rO++qzvvqs776rO++qzvvqs776rO++ qzvvqs776rMfLPYHlHyRFUbivuDeUv1FOSVKJkRwE4CcAOAHADgBwA4AcAOAHADgBwA4AcAOAHAD gBwA4AcAOAHADgBwA4AcAOAnARciFyRUK8ndQcgyGxaaqf4fYHlHwRFUjZe68RsqbpGoKIUQkKYY kISEYJDAmBMCYEwJgTAmBMCYEwJgTAmBMCYEwJgTAmBMCYEwJgTAmCQWELCKoSFcNByEhIyxusk5 VVQV0VUL8vYHlGltupyqDlaIMREQaijcUoilMUSKgkZDDIYZDDIYZDDIYZDDIYZDDIYZDDIYZDDI YZDDIYZDDIYZDDIYZDDIYZDDIYZDDIYZDDILGQWKVRSuKORR2KPRCZltDiSYrjFXx9geUaG26nKs vy9KEjxhmONRxuOUMFLAjIjJdF0XRdIXSF0hdF0XRdF0XRdF0XRdF0XRdF0XRdIXSF0hdIXRdCsi sisFTBXHHY49GH4xMhU10y4tTFfw9geUCJ9rlcL6SNHGGBlgbZKGilsShDZQ+kPr/wBX0fSGygtC CtoVNDjI6wPsElgzCGjlLrdTden2B5QZfGvnYbCIkdkYZGmihsSn61ItJXQOtD7JIZJTBm0X6+Hs DyhP1cpjbLcVojtDLY3QIn1qZU+yugebJDRKaJ7CVUvtq27o9geURaLx6C19JFbI7Y1QU0/WqFQd oH6CS2TG/wAzZrZd0ewPKMqo2n4VH5FoGKBunVTifj9JJpJdBnVH+mj2B5RkqfdcOki0jFJQn5qm pPx5CTSS6TOKf6tHsDyjI0/2hIRU/GUKbNU1DyfklCWhm6f06PYHlGRf9QkIqfjKCWapWx4kkszj daPYHlGQ2wrItjImqlseJJMM43Wj2B5RkNsEjWNarUeJJMM43Oj2B5RkNsEjWNarUeJJMM43Oj2B 5RkNsGyLY1qtR6ySTDONzo9geUZDbBsi2NarUesk2TDON1o9geUZDbBsjWNarUesk2TDON1o9geU ZDbBsjWNarUeskkwzjdaPYHlGQ2wbI1jWq1HrJJMM43Wj2B5RkNsGyNY1qtR6ySTDON1o9geUZDb BsjWNarUeskkwzjdaPYHlGQ2wbI1jWq1HrJJMM43Wj2B5RkNsGyNY1qtR6ySTDON1o9geUZDbBsj WNarUeskkwzjdaPYHlGQ2wbI1jWq1HrJJMM43Wj2B5RkNsGyNY1qtR6ySTDON1o9geUZDbBsjWNa rUeskkwzjdaPYHlGQ2wbI1jWq1HrJJMM43Wj2B5RkNsGyNY1qtR6ySTDON1o9geUZDbBsjWNarUe skkwzjdaPYHlGQ2wbI1jWq1HrJJMM43Wj2B5RkNsGyNY1qtR6ySTDON1o9geUZDbBsjWNarUeskk wzjdaPYHlGQ2wbI1jWq1HrJJMM43Wj2B5RkNsGyNY1qtR6ySTDON1o9geUZDbBsjWNarUeskkwzj daPYHlGQ2wbI1jWq1HrJJMM43Wj2B5RkNsGyNY1qtR6ySTDON1o9geUZDbBsjWNarUeskkwzjdaP YHlGQ2wbI1jWq1HrJNkwzjdaPYHlGQ2wbItjWq1HrJNkwzjdaPYHlGQ2wbItjWq1HrJJMM43Oj2B 5RkNsGyNY1qtR4kkwzjc6PYHlGQ2wSNY1qtR4kkwzjc6PYHlGQ2wrItjImqlseJJMM43Wj2B5RkV sJSKv4yolmqVseJJLM43Wj2B5Rkf/UJSKv4ypTZqmoeX8kqS1M43Oj2B5Rki/wC0Koi1DKlC/mqa h5SSpLUzdf6tHsDyjJ6/p2HURaxiobX81TWv4/USaiXUZy59N6PYHlGXubEiE5+RaxisaqEXVCjl Q/WSayXX+Zy59ro9geUUVbNeXPpVRFdI7gzWUVfeqK6h2skOElwmu/ST3bx/R7A8oMpk/SxHiM8M OjThTX9iLqWqr6HHB50kOkp4zSVsUVKqro9geUDLit15fLSumM+MPjTw26UuCVH2moPsWoqcK3R1 4feJD5MkIiTpKvO6fYHlGiFLViuHLSpGJAzIGnyh8peKXRHEEcQ20NtDbQ2kNpDaQ2kNpDaQ2kNp DaQ2kNpDaQ2kNpDaQ2kNpDaQ2kNpDaQ20NtDbQVxBXEFdKnit8cfHpA/IJMn6TMp+0vw9geUaYU+ pmqJNprRmUNSRuSUSSmQgkgSQI+X5fl+X5fl+X5fl+X5fl+X5fl+X5fl+X5fl+X5fl+X4r4sgWQV SCuSOSR2SPSiRLREzDMlUVVVfh7A8o+EeW4wsTNKKxmYijcsollMspliSxJZjDGIYxDGIYxDGIYx DGIYxDGIYxDGIYxDGIYxDGIYxDGIYxDGIYxDGIYxDGIYxBZYssqllUsrljksdmISsxooSVmLjyqq r8vYHlHxRVRWZ77QznNI3mzSlGZUKU5hSJmKHEUOIocRQ4jScRQ4ihxFDiKHEUOIocRQ4ihxFDiK HEUOIocRQ4ihxFDiKHEUOIocRpOIocRQ4ihxFBcxQXMEKsxpHM1aQezmhB/M3nCquqtfn7A8o/hS utC9dL50vnS/eL94v3i/eL94v3i/eL94v3i/eL94v3i/eL94v3i/eL94v3i/eL94v3i/eL94v3i/ eL50vnS9dLytT7X+PrDhvHuTHJjkxyY5McmOTHJjkxyY5McmOTHJjkxyY5McmOTHJjkxyY5McmOT HJjkxyY5McmOTHJjkxyY5McmOTHJjkxyY5McmOTHJjkxyY5McmOTHJjkxyY/pP/aAAgBAgIGPwBR f//aAAgBAwIGPwBRf//aAAgBAQEGPwCPk8jmv2su47DV1z9uE90V5xHl7vuKrTXWMHDNdYwcM11j BwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHD NdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11 jBwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMH DNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHDNdYwcM11jBwzXWMHDP+z/AEd/2MzUhXbvz7H6XVO/ Y7vFJSkpSUpKUlKSlJSkpSUpKUlKSlJSkpSUpKUlKSlJSkpSUpKUlKSlJSkpSUpKUlKSlJSkp+le p3d6ndOn4OZqQrt349EOqp0QT9PVfzGDBgwYMGDBgwYMGDBgwYMGDBgwYMGDBgwYMGDBgwYMGC9X RVh9/wAjo8nRfnmakK7d+H+LqdVEefTqonYYMGDBgwYMGDBgwYMGDBgwYMGDBgwYMGDBgwYMGDBg wYMGDBeqd/uKip2+/wAszUhXbsqOutURVT9SidhgwYMlZ/XsGDBgvYVFQVOnb6fHM1IV27J0QR95 O6idhOwyaWC9hU6d/oK6v0+GZqQrt2RFVOyCdhBJrUU/cRO6N+GZqQrt06CL07qIJNiijydGjzsu ZqQrt0dd/MRBBJsUUU/y+8uZqQrt06/YQQSbFFFOv2WXM1IV26KIJNyij0uZqQrt0e8iCTcoo/Lm akK7dHvIggk2KKKPy5mpCu3R7yIJNyij8uZqQrt0e8iCTcoo/LmakK7dHvIgk3KKPy5mpCu3R7yI JNyij8uZqQrt0e8iCTaooo/LmakK7dHvIgk3KKPy5mpCu3R7yIJNyij8uZqQrt0e8iCCTaoo/Lma kK7dHvIggk2qKPy5mpCu3R7yIIJNqij8uZqQrt0e8iCCTaoo/LmakK7dHvIggk2qKPy5mpCu3R7y IIJNqij8uZqQrt0e8iCCTaoo/LmakK7dHvIggk2qKPy5mpCu3R7yIIJNqij8uZqQrt0e8iCCTaoo /LmakK7dHvIggk2qKPy5mpCu3R7yIIJNqij8uZqQrt0e8iCCTaoo/LmakK7dHvIggk2qKPy5mpCu 3R7yIIJNqij8uZqQrt0e8iCCTaoo/LmakK7dHvIggk2qKPy5mpCu3R7yIIJNqij8uZqQrt0e8iCC Taoo/LmakK7dHvIggk2qKPy5mpCu3R7yIIJNqij8uZqQrt0e8iCTcoo/LmakK7dHvIgk2qKKPy5m pCu3R7yIJNyij8uZqQrt0e8iCTcoo/LmakK7dHvIgk3KKPy5mpCu3R7yIJNyij8uZqQrt0e8iCCT aoo/LmakK7dHvIgk3KKPy5mpCu3R4QSblFHpczUhXboqfcQQSbVFFT7y5mpCu3RPzEEEmxRRRHZc zUhXbojyfRR1RBJsUUUX7JLmakK7dk/bVfAgk2KKL37qwVV+suZqQrt2RHk+giook2L3F7i9GJ8M zUhXbsqItFRFRRO40aNmVo0aL3FhuL5+OZqQrt34I69REVFGjRo0aNGjf6po0aNGjRo0XuK5DXv9 zqrV+OZqQrt349UXt9hEVeijRo0aNGjRo0aNGjRo0aNGjRo0aNGjRo0aNGjRo0aNGjRo0Xq9/YVH V6OnVflmakK7d+XVOw3qh0e7FM7PJ7KQ0aNGjRo0aNGjRo0aNGjRo0aNGjRo0aNGjRpSKaH6V6nR 3sh1eXr+BmakK7d/C7KqFJfZTX2U19lNfZTX2U19lN72U3vZTe9lN72U3vZTe9lN72U3vZTe9lN7 2U3vZTe9lN72U3vZTe9lN72U3vZTe9lN72U19lNfZTX2U19lNfZSX2d3l/Ej/wAj/wCf+7/jD6/y f5/7tBOnX+L/AMfr+5tPKm08qbTyptPKm08qbTyptPKm08qbTyptPKm08qbTyptPKm08qbTyptPK m08qbTyptPKm08qbTyptPKm08qbTyptPKm08qbTyptPKm08qbTyptPKm08qbTyptPKm08qbTyptP Km08qbTyptPKm08qbTyptPKm08qbTyptPKm08qbTyptPKm08qbTyptPKn/jan//Z"
+ transform="matrix(0.24 0 0 0.24 174.5615 142.499)"
+ id="image25"></image></g></mask><g
+ opacity="0.09"
+ mask="url(#SVGID_1_)"
+ a:adobe-blending-mode="multiply"
+ a:adobe-opacity-share="1"
+ id="g27"><path
+ fill="#1D2915"
+ a:adobe-blending-mode="normal"
+ a:adobe-opacity-share="0"
+ d="M195.361,251.626 c-8.161,0-14.8-6.64-14.8-14.8v-73.527c0-8.161,6.639-14.8,14.8-14.8h59.663c8.161,0,14.8,6.639,14.8,14.8v73.527 c0,8.16-6.639,14.8-14.8,14.8H195.361z"
+ id="path29" /><path
+ fill="#1D2915"
+ a:adobe-blending-mode="normal"
+ a:adobe-opacity-share="0"
+ d="M255.024,152.499 c5.964,0,10.8,4.835,10.8,10.8v73.527c0,5.965-4.835,10.8-10.8,10.8h-59.663c-5.964,0-10.8-4.835-10.8-10.8v-73.527 c0-5.964,4.835-10.8,10.8-10.8H255.024 M255.024,144.499h-59.663c-10.366,0-18.8,8.434-18.8,18.8v73.527 c0,10.366,8.434,18.8,18.8,18.8h59.663c10.366,0,18.8-8.434,18.8-18.8v-73.527C273.824,152.933,265.391,144.499,255.024,144.499 L255.024,144.499z"
+ id="path31" /></g></g><g
+ id="g33"><g
+ id="g35"><linearGradient
+ id="SVGID_2_"
+ gradientUnits="userSpaceOnUse"
+ x1="225.1929"
+ y1="152.499"
+ x2="225.1929"
+ y2="247.6265"><stop
+ offset="0.0123"
+ style="stop-color:#C1D72F"
+ id="stop38" /><stop
+ offset="0.1394"
+ style="stop-color:#BCD631"
+ id="stop40" /><stop
+ offset="0.5859"
+ style="stop-color:#AFD136"
+ id="stop42" /><stop
+ offset="1"
+ style="stop-color:#ABD037"
+ id="stop44" /><a:midPointStop
+ offset="0.0123"
+ style="stop-color:#C1D72F" /><a:midPointStop
+ offset="0.3086"
+ style="stop-color:#C1D72F" /><a:midPointStop
+ offset="1"
+ style="stop-color:#ABD037" /></linearGradient><path
+ d="M184.562,236.826c0,5.965,4.835,10.8,10.8,10.8h59.663c5.964,0,10.8-4.835,10.8-10.8v-73.527 c0-5.964-4.835-10.8-10.8-10.8h-59.663c-5.964,0-10.8,4.835-10.8,10.8V236.826z"
+ id="path46"
+ fill="url(#SVGID_2_)" /></g><defs
+ id="defs48"><filter
+ id="Adobe_OpacityMaskFilter_1_"
+ filterUnits="userSpaceOnUse"
+ x="184.562"
+ y="152.499"
+ width="81.263"
+ height="95.127"><feColorMatrix
+ type="matrix"
+ values="-1 0 0 0 1 0 -1 0 0 1 0 0 -1 0 1 0 0 0 1 0"
+ color-interpolation-filters="sRGB"
+ result="source"
+ id="feColorMatrix51" /></filter></defs><mask
+ maskUnits="userSpaceOnUse"
+ x="184.562"
+ y="152.499"
+ width="81.263"
+ height="95.127"
+ id="SVGID_3_"><g
+ filter="url(#Adobe_OpacityMaskFilter_1_)"
+ id="g54"><image
+ overflow="visible"
+ width="356"
+ height="414"
+ xlink:href="data:image/jpeg;base64,/9j/4AAQSkZJRgABAgEBLAEsAAD/7AARRHVja3kAAQAEAAAAHgAA/+4AIUFkb2JlAGTAAAAAAQMA EAMCAwYAAAXBAAALIQAAEOP/2wCEABALCwsMCxAMDBAXDw0PFxsUEBAUGx8XFxcXFx8eFxoaGhoX Hh4jJSclIx4vLzMzLy9AQEBAQEBAQEBAQEBAQEABEQ8PERMRFRISFRQRFBEUGhQWFhQaJhoaHBoa JjAjHh4eHiMwKy4nJycuKzU1MDA1NUBAP0BAQEBAQEBAQEBAQP/CABEIAaEBawMBIgACEQEDEQH/ xACYAAEAAgMBAQAAAAAAAAAAAAAABAcBBQYDAgEBAAAAAAAAAAAAAAAAAAAAABAAAAMIAwEAAgMB AAAAAAAAAAIGATIDBBQFFjZQMwcRECKQMRMSEQABAgQEBgEBBwQDAQAAAAAAAQIxcgMEEFCRsyGC M6PTNBFBIGFxEiIyE1GB0UKhscFiEgEAAAAAAAAAAAAAAAAAAACQ/9oADAMBAAIRAxEAAADy0npz Z0Dnx0DS7Q9kr0IKcIKeICeICeICeICeICeICeICeICeICeICeICeICfggp2CElQD1aXxOgc+O1s um7kKj5vpObG6d2Q9zspRA9JmSGmCHmWIiWIiWIiWIiWIiWIiWIiWIiWIiWIiWIiWIaYIeJo1sPe 4OK5C2tCVS3OmN5clN3IVHod9EOv6zWb0zkAAAAAAAAAAAAAAAAAMRJnwcVXltVuetyU3chUfp5+ 5YexhTgAAAAAAAAAAAAAAAAABjODUVxZNbnjclN3IVHIjyCx5sKaAAAAAAAAAAAAAAAAAAMZwaut rJrY8bkpu5Co5EeQWPNhTQAAAAAAAAAAAAAAAAABjODV1tZNbHjclN3IVHIjyCx5sKaAAAAAAAAA AAAAAAAAAMZwautrJrY8bkpu5Co5EeQWPNhTQAAAAAAAAAAAAAAAAABjODV1tZNbHjclN3IVHIjy Cx5sKaAAAAAAAAAAAAAAAAAAMZwautrJrY8bkpu5Co5EeQWPNhTQAAAAAAAAAAAAAAAAABjODV1t ZNbHjclN3IVHIjyCx5sKaAAAAAAAAAAAAAAAAAAMZwautrJrY8bkpu5Co5EeQWPNhTQAAAAAAAAA AAAAAAAABjODV1tZNbHjclN3IVHIjyCx5sKaAAAAAAAAAAAAAAAAAAMZwautrJrY8bkpu5Co5EeQ WPNhTQAAAAAAAAAAAAAAAAABjODV1tZNbHjclN3IVHIjyCx5sKaAAAAAAAAAAAAAAAAAAMZwautr JrY8bkpu5Co5EeQWPNhTQAAAAAAAAAAAAAAAAABjODV1tZNbHjclN3IVHIjyCx5sKaAAAAAAAAAA AAAAAAAAMZwautrJrY8bkpu5Co5EeQWPNhTQAAAAAAAAAAAAAAAAABjODV1tZNbHjclN3IVHIjyC x5sKaAAAAAAAAAAAAAAAAAAMZwautrJrY8bkpu5Co5EeQWPNhTQAAAAAAAAAAAAAAAAABjODV1tZ NbHjclN3IVHIjyCx5sKaAAAAAAAAAAAAAAAAAAMZwautrJrY8bkpu5Co5EeQWPNhTQAAAAAAAAAA AAAAAAABjODV1tZNbHjclN3IVH7+HqWTO1uxMgAAAAAAAAAAAAAAAAAYzg1Vb2NXB5XJTdyFRx5G jLc3XG9SS2MgAAAAAAAAAAAAAAAAD4+ohqq47GvTa3JTdyFR830nNm/7qp+gLVk8fuDcZgehLRBL RBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBLRBKQohP0MbkT40OcG8uSm7kKj5vpObAJm45sd n98SO3cQO3cQO3cQO3cQO3cQO3cQO3cQO3cQO3cQO3cQO3cQO3cQO3cQO3cQO3xxI7PX84JcQAN5 clN3IAAAAAAAAAAAAAAAAAAAAAAAf//aAAgBAgABBQD+G3//2gAIAQMAAQUA/ht//9oACAEBAAEF AFgq7/bL9narGdqsZ2qxnarGdqsZ2qxnarGdqsZ2qxnarGdqsZ2qxnarGdqsZ2qxnarGdqsZ2qxn arGdqsZ2qxnarGdqsZ2qxnarGdqsZ2qxnarGdqsZ2qxnarGdqsZ2qxnarGdqsZ2qxnarGdqsZ2qx narGdqsZ2qxnarCYVyhn78PQNo/MCUmJhssm48QEScNrGJGEMQgjEIIxCCMQgjEIIxCCMQgjEIIx CCMQgjEIIxCCMQgjEIIxCCMQgjEIIxCCMQgjEIIxCCMQgjEIIxCCMQgjEIIxCCMQgjEIQakYQOlI bGTCajw2R5SPLm/KK2gegbR+LVYzzDZGzFKyBaysYS3FYGSBBQkFCQUJBQkFCQUJBQkFCQUJBQkF CQUJBQkFCQUJBQkFCQUJBQkFCQUJBQkFCQUJBQkFCQUJBQkFCQNkCA9uK0R7WVrJ+ykMy6WI8BrW NY0IraB6BtAsdqbMHtttYxkvKFKxhCs4JpCtExKFMy5W5jWX22NgRAitoHoG0SsBsePZZFhSSkuw peFm5dhi3qRKYk1BbAjoraB6BtCcl/8ASYtUBjCkL8Lwp2fS3WCxpVDA/wA5lFbQPQNoShGNLbif CcM3+roX9VQz4ZFbQPQNoSLP0t7P04e5uql5FbQPQNoSPXIOcPc3VU8itoHoG0JHrkHOHubqqeRW 0D0DaEj1yDnD3N1VPIraB6BtCR65Bzh7m6qnkVtA9A2hI9cg5w9zdVTyK2gegbQkeuQc4e5uqp5F bQPQNoSPXIOcPc3VU8itoHoG0JHrkHOHubqqeRW0D0DaEj1yDnD3N1VPIraB6BtCR65Bzh7m6qnk VtA9A2hI9cg5w9zdVTyK2gegbQkeuQc4e5uqp5FbQPQNoSPXIOcPc3VU8itoHoG0JHrkHOHubqqe RW0D0DaEj1yDnD3N1VPIraB6BtCR65Bzh7m6qnkVtA9A2hI9cg5w9zdVTyK2gegbQkeuQc4e5uqp 5FbQPQNoSPXIOcPc3VU8itoHoG0JHrkHOHubqqeRW0D0DaEj1yDnD3N1VPIraB6BtCR65Bzh7m6q nkVtA9A2hI9cg5w9zdVTyK2gegbQkeuQc4e5uqp5FbQPQNoSPXIOcPc3VU8itoHoG0JHrkHOHubq qeRW0D0DaEj1yDnD3N1VPIraB6BtCR65Bzh7m6qnkVtA9A2hI9cg5w9zdVTyK2gegbQkeuQc4e5u qp5FbQPQNoSPXIOcPc3VU8itoHoG0JHrkHOHubqqeRW0D0DaEj1yDnD3N1VPIraB6BtCR65Bzh7m 6qnkVtA9A2hI9cg5w9zdVTyK2gegbQkeuQc4e5uqp5FbQPQNoSLlvb+nD3N1UvIraB6BtCTN8Jbj /ScM3+rob9VQ36ZFbQPQNoTUx/xGtcdjSlb9ZwsRvwt1jMYVRR/+5hFbQPQNokZinmbPOsaWVjsM XhZuOwpbxOsYWcjtjzCK2gegbQLDdv8ANtuuDGsgTJTMYZjeCaZjBHmSlZcbgxjL9dGxDBFbQPQN oDGtK2z31pBJXYrWQLmVrCz5Whk8QVpBWkFaQVpBWkFaQVpBWkFaQVpBWkFaQVpBWkFaQVpBWkFa QVpBWkFaQVpBWkFaQVpBWkFaQVpBWkDZ4gNPkYI9zKxk7dysZdr80zTGaZoRW0D0DaPzK3Oalmyy oYwEVEv8yqXGVS4yqXGVS4yqXGVS4yqXGVS4yqXGVS4yqXGVS4yqXGVS4yqXGVS4yqXGVS4yqXGV S4yqXGVS4yqXGVS4yqXGVS4yqXGVS4yqXGVS4yqXB1RL/JlUMMyauU1Mt/KK2gegbRxaK2jj/wD/ 2gAIAQICBj8AG3//2gAIAQMCBj8AG3//2gAIAQEBBj8Ar2djdfxW7G01az+Ok74VzEcvF7FWJ73Z o+M97s0fGe92aPjPe7NHxnvdmj4z3uzR8Z73Zo+M97s0fGe92aPjPe7NHxnvdmj4z3uzR8Z73Zo+ M97s0fGe92aPjPe7NHxnvdmj4z3uzR8Z73Zo+M97s0fGe92aPjPe7NHxnvdmj4z3uzR8Z73Zo+M9 7s0fGe92aPjPe7NHxnvdmj4z3uzR8Z73Zo+M97s0fGe92aPjPe7NHxnvdmj4z3uzR8Z73Zo+M97s 0fGe92aPjPe7NHxnvdmj4z3uzR8Z73Zo+Ms7O7u/5Leq5yVGfx0m/KIxzotYixTC5kpbbfsfFJir 9/0EWo74+5qHH8y/3IO1Ug7VSDtVIO1Ug7VSDtVIO1Ug7VSDtVIO1Ug7VSDtVIO1Ug7VSDtVIO1U g7VSDtVIO1Ug7VSDtVIO1Ug7VSDtVIO1Ug7VSDtVIO1Ug7VSDtVIO1U4fmT+5803fP3Kn+D4qsVP v+n2LCd22/C5kpbbcUqVkX4+jf8AIiI34QTgQIECBAgQIECBAgQIECBAgQIECBAgQIECBAgQIEBe AqK1FRfuFqUE/SkWf4PhY4WE7tt+FzJS224JWqJw+f0ov/YnATgcMi4i8BeAtdifpX9yf+4WE7tt +FzJS22jKSfVeP4DUROCCcMmXgORU4KPpL/qvD8CwndtvwuZKW20dUVIcEE4Hxkyi8BHon7uC/2L Cd22/C5kpbbT5/8AoTKFG/iWE7tt+FzJS22nMomUKNmLCd22/C5kpbbTmUTKFGzFhO7bfhcyUttp zKJlCjZiwndtvwuZKW205lEyhRsxYTu234XMlLbacyiZQo2YsJ3bb8LmSlttOZRMoUbMWE7tt+Fz JS22nMomUKNmLCd22/C5kpbbTmUTKFGzFhO7bfhcyUttpzKJlCjZiwndtvwuZKW205lEyhRsxYTu 234XMlLbacyiZQo2YsJ3bb8LmSlttOZRMoUbMWE7tt+FzJS22nMomUKNmLCd22/C5kpbbTmUTKFG zFhO7bfhcyUttpzKJlCjZiwndtvwuZKW205lEyhRsxYTu234XMlLbacyiZQo2YsJ3bb8LmSlttOZ RMoUbMWE7tt+FzJS22nMomUKNmLCd22/C5kpbbTmUTKFGzFhO7bfhcyUttpzKJlCjZiwndtvwuZK W205lEyhRsxYTu234XMlLbacyiZQo2YsJ3bb8LmSlttOZRMoUbMWE7tt+FzJS22nMomUKNmLCd22 /C5kpbbTmUTKFGzFhO7bfhcyUttpzKJlCjZiwndtvwuZKW205lEyhRsxYTu234XMlLbacyiZQo2Y sJ3bb8LmSlttOZRMoUbMWE7tt+FzJS22nMomUKNmLCd22/C5kpbbTmUTKFGzFhO7bfhcyUttpzKJ lCjZiwndtvwuZKW205lEyhRsxYTu234XMlLbacyiZQo2YsJ3bb8LmSlttOZRMoUbMWE7tt+FzJS2 2nMomUKNmLCd22/C5kpbbTmUTKFGzFhO7bfhcyUttpzCZQo38SwndtvwuZKW20dTVfvQQ+cmUXiI xFhxUsJ3bb8LmSlttGVPp8/C/go1fkTjky8RyqsB9T6KvD8CwndtvwuZKW23BKNR3wqftX+qCcRO JwyLiLxF4i0Ka8V/cuFhO7bfhcyUttuCKi/CpBRtOs74cnBF/qJ+oiRIkSJEiRIkSJEiRIkSJEiR IkSJEiRIkSJEiRIkReIv6hadFfl31d9EFc5flViuFhO7bfhcyUttv2ERrvzNT/VT4qIrf+TqIdVD qodVDqpqdVNTqpqdVNTqpqdVNTqpqdVNTqpqdVNTqpqdVNTqpqdVNTqpqdVNTqpqdVNTqpqdVNTq pqdVNTqpqdVNTqpqdVDqodVDqC/xorl0F/O74av+qfYsJ3bb8LmSlttyywndtvzD/9k="
+ transform="matrix(0.24 0 0 0.24 182.5615 150.499)"
+ id="image56"></image></g></mask><g
+ opacity="0.35"
+ mask="url(#SVGID_3_)"
+ a:adobe-opacity-share="1"
+ id="g58"><path
+ a:adobe-opacity-share="0"
+ d="M184.562,236.826c0,5.965,4.835,10.8,10.8,10.8h59.663 c5.964,0,10.8-4.835,10.8-10.8v-73.527c0-5.964-4.835-10.8-10.8-10.8h-59.663c-5.964,0-10.8,4.835-10.8,10.8V236.826z"
+ id="path60"
+ fill="#1D2915" /></g></g><linearGradient
+ id="SVGID_4_"
+ gradientUnits="userSpaceOnUse"
+ x1="226.1924"
+ y1="159.7139"
+ x2="226.1924"
+ y2="200"><stop
+ offset="0.0123"
+ style="stop-color:#FFFFFF"
+ id="stop63" /><stop
+ offset="0.3788"
+ style="stop-color:#F8FBF3"
+ id="stop65" /><stop
+ offset="1"
+ style="stop-color:#F2F7E8"
+ id="stop67" /><a:midPointStop
+ offset="0.0123"
+ style="stop-color:#FFFFFF" /><a:midPointStop
+ offset="0.4383"
+ style="stop-color:#FFFFFF" /><a:midPointStop
+ offset="1"
+ style="stop-color:#F2F7E8" /></linearGradient><polygon
+ fill="url(#SVGID_4_)"
+ points="221.189,159.714 214.142,180.951 224.048,180.951 214.142,200 238.243,173.61 227.655,173.61 236.978,159.714 "
+ id="polygon69" /><g
+ id="g71"><g
+ id="g73"><g
+ id="g75"><image
+ overflow="visible"
+ opacity="0.75"
+ a:adobe-blending-mode="multiply"
+ a:adobe-opacity-share="1"
+ width="392"
+ height="242"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAYwAAAD2CAYAAADF97BZAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAHohJREFUeNrsnYlu40gSBZMU5Z75 /4+dbUsiFwtY2JrqvIqHSEoRACFZPtqk3BV8WVcvAAAACXouAQAAIAwAAEAYAADwWgYuwSp0XAKA wzJxCRAGIgCANf8fIxaE8RIxIBaA8yeMDokgjLkNfLfyzwOAfWTRNX49EkEY5h9N6+sIAuC8/++n mXKZjJ/5UfIYPuyPRXut9WOEAXDuxOGJYEqKZPpEebyjMOYKoTO+BmEAfIYwSjG0JJFaHm8rjncS RkYE2uutwkAgAO8liezzTPqY3jl1vIMwooa+fi0SRvQzshIBgHMKYwpez5Su3jJ1nFUYLWWlznne KpHW5AEAx5fF5Aijfi0jDy91nFocZxRGJgnUMvDkkf3arDiQCMD+YshIwxKE93xy5CGJ1HFqcZxJ GEsE4b0WHa3JA2EAHEcYU8PjlJREdESp47TiOIMwIlG0yqEPPl4iDmQBcCxpZMtOmWNs+Fy2n6M7 kzSOLIy5oogk0SsfZwWCNADeSxhZMYzGYy2I8uslIY5TpY2jCiMzsikjCO2xDz4fiaNFGggDYD9h LJGF9uh9rq8+7hxxWLI4vDiOJozsKCdPFJoc5ry2JG0gDYDzJouxOrTXLJHUsuiKz4uROurS1GHL VEcShpcqNGFoZSZLBBfla6zXO0MeGXGQMgCOkyyyopgCMfzveDifs44yRdQlLKtEdei0cRRhaLKI UkXZoFtCeH7uUn3dJfF9UV8HwgA4tzDG6nktjYfy/OF8zhJLZ0hjEns01SHTxt7C8EpQmdKTlhQu lSguxmu1TLSfNac8hTQAji+MMZEsahHUx6g8743v1aQxOudzSGnsKYyoBOUlCk0StQQGRRrW4aUO bWRVpj8DYQDsI4xaFJEwPFk8FGHcDYGUR1/Jon7uzf84bIlqL2FkS1BWP8XFSRKDIozBEclgiMPq CJ8rDSQCsI0cWmWRTRaWDO7BYy2OXhFH2SE+BudymLSxhzAsWbSkCk8S3vNBkUdGGJE06pTUIgTE AbCOKLRylCYNqxyVTRV347gYX9sr4nhUotDKVPXw292l8WphtMrCSxWeEOrjqghDE0hUlrKkYaUL ZACwj1S8lBGli1oYWpL433Eznl8qWdxFL2trfRsiev/GIaTxSmFkJ99po5+0RBHJoXy8Bt+j9WmU /743qU/E7vxGGgD7JBBrCRCvs9sqRd2NZHErRDEY4iiTxV1p72ppiPx/IqDVr7GbNF4ljBZZaKnC E0UtBu3jq5E0PGFcgpJUH8gCcQDsJworXWQTRiSMWyWM5/Oheu3ZltzFLmk/lPbhkCOoXiEMreHM 9FVYsrhWz8vjS3lNE8dglKiyHd9ewqAsBbB/KcoThjbvwhpCG6WL8vgu2pRb0XbdnGpFKY26vbCG 3u4mja2Fkemz8EpQZWOulZq+gkdNIlFZaq4wBGkAHFYWIm2d3lG6uFeiKNPFt9Ku3ESfEOyJY3TS xi7S2FIYc2ThpQpLFF/Bx6U4auFckiWpFlkgCoBjiCPb8T01Jow6WVx/JHEtZPEt+oCaaD6XRUYa b1OSapXFEJSdsodVporKUZlRUpEsEAbAcaWhpYx6WK02lPamSKOWxVBIo1UY3QJpbC6PrYTROhLK SxW1LH5VUvhlvG5JQ0sXWv/FReYNp0UaAPvKYq4wxoQwvIQRlbojYayRNDaVxhbCaFmKXJNFPcrp q5LFL0UUGWlE6UJ7Y7MT9hAGwDmFEaUMb/5F3X/hjb70hulnZVFL4/Sd3l2iLNUHsrBKUL+M48v4 2EoX0ZvqlaIEYQCcWhalNKwNkrz5GPeftuRWtCk30ed8aUsYzU0WdZoo25ZaHJsJZMuSVMs8i6iv opbEX4FAnt+jdXZnZaEtby6IAuBtUsac/oxaGoPy6A2mWZoupiJldK8uTa0pjLmlKK2DOxLFX8br WllKG5Lbsn4UO+0BII1B/uzLqG9Av+XPKQHZNsU7H22IcF2e0qRx2ISRkYU1g3sISlB/KY9/OUlD 67vIyOKSKEO1JAzEAbCfKFqF4c0CL1PGUKSNm9hr1LXchHYJWYjoy4RYZSnZQhxbz8OIRDEYwvhl SOIvQxh/KenC6+hu7eSOpIEwAM4hjCXSuBRp47lW1F1p16wtoFvShSYLa++MUV7Un7GGMFpKUV66 qPssaln8bUijFoY1u9vbOGnp8NkucX0A4LWyEGmbCT6KvnzIWMjiUcgjsyGbdQOa+V0nyW/p2r2i NLVmSWqJLLR0Ycnib6ck5U3S85JFy8KCSzq5kQfA9pJokUX52AdJo6/EkVmwdM6ci2nG0TmyWE0c S4URDaPN9ltkZPG3U5bS5l1kFhecu2w55SeAfcl0FncJgXh9G30hivqxXIE2Gl3ZO6KIymPZo0xI m/VjrFWSmjsqanBkYfVd/K2kC6uj25JFZ7yxraJAEADHF8pUvTYFjbZUd+5T0UY8hfEQfapAZnRl lCpG0eeHaB/XKcOS5CriGFZ6Qyx5aPMuhiBZ/FJkoaUMTRblMNpoFvfS3fOQBcB55DEp/3e9DuJa GE9ZWO1bpvRkNeZWp7u1Z0emNDUp579YGsOCNyBKF9HIqEFp7K1U4Q2lteZcWOu4tM6xoAQF8H7S EKN0Uz9qd/B90Xh3ku+r6IxUMTpHuWWsdvRGacrr09g9YWTnW7RM0rPKU9oyIN7CgpYs1twxD3EA HJcp+f9UuxPvFGnMFUUXpANLGJ5Qyu+t/+1Ddnp3iXKUNu/iy0gYvyQ/Qa8cGaUt+5FJFiJtI5+Q A8D50kVGIpNy0zgtkIYY/0b5PLOnuHZcqpTRK0nIK0+9TBjZLVfnzOrOJI0vQxbafAuvzyJbfmK4 LMB7JAzv/+zU8H+9lEZL2zApopgMcURHVJrqRO+72a0Pw0oX0YZIVsKIylDWkuVav0UpK2upj7mi QA4A504YnkCmoLpQfm/r3hbWarmRHJ5rV3kpwytNaalqljiGhRc+U4qKNkb6ctJFnSa0uRaaLC7J ZEEZCgCBRCOoLHFMxd19JuVEndyeMLIpo98yZcwtSWWXL5/bf/El9kioL7H3tYhmW1rpYm4pCgDe RyCt4pCigRaxZ297w2fHIFWU6aJ8HOTf61uVbd5mKWOYcVFb08Wc/bm1RQTrVFH3WViy6INUgSgA oEUcWn9HL7kFEOtS1BiIojy+5P97cdSlqUfVDnspYzZLh9Vq+3Rn5mBcE6KwtlgtReEli16YiAcA 64vDayt65XszQ2ejhFFu3FTuxfFQksYo+kitXfowOrFHSnmlqGgLVi9daEt9ZCbmibAzHgBsK46u kIFUlY3pp416CmNIlqNulShuRVtYbuB0r26aR6MsNYm/d8aqwpi7DEhm74urU36K9rTQ1p23Fg9E FgCwpjjqmeFdlTK8ctS1eNT2DP+qZPFVSOMm+grcUV/G4s7v1j6MOcuYe3MwNGl8KV8b7cFd/w4i /pR8RAEAc8QRSUOqlPH8+jpljEVJqZbGl5Iq6qPc7e9eScPry5AlKWONeRjeUNpLUI7SEsUg9sxt bwZ3L/RVAMBr04bXCT5Wpam6XF+WpK7y7z6Ka5EqynQxiL2DaC/xaKnNJ+5Fayi1jpQagtKTNXN7 SKSLaClhZAEAa6cNSxrlXX5fpYyxaNdqadyVdnBuyli187ufeaG0foJMyhgMMdSlp0wZykoXIu3b qAIAzE0b2nNtBGl2YdbBaRsHJ2W0rMg9q23sGy5My2S9PnExhsTFyG6BmHkDAQBeLRFNGpeqNOXt RJppG7Wb6i6Qxiz6hpP3RNIHCSNj0swF6WaUopAFALwyZWRvri1xXIL2sWVqQbR67qrCaEkaLUNr 6wtxCWRh7ZVryQFJAMAe0ojazWe7dWlsI6/JhKG1l6KUoma1lf3Ci2RdiGyyuIg+CspbRLA3TD7n jQQA2EIe0Y21Nw1hUB6z0sgkDC8dLRZGNlVkR0hZpSdLFpfkBVhkTgCADVJGZoM5qyLjyaN1o7hV +jH6mTHL2gcjugjWBfHKUN1WJw8AsFG6iGSRLeNn2spoFOlqbWXfeDG6IHK1ysI76cyOeaQLADhr maqfIY2L5Pt5rQ7vzYfVZspUfXC0CsLq5LbGEgMAnC1laP0Z1giqls7ubBl/k07vaOiYtp6TdjKa JKJJJ9n5FqQLADhj2vCG20Y33NlSVNfwu62SMLqkNb2E0SviyMzgXrUOBwDw4pThrY6R6QPOVmo2 7fvNTNzrgs9F9bhIHH3ihC07C+kCAE4mE00ctUCiakymhN+vfZPdz4gm2fHFXSALK0V409pFWPID AM6XNrwUklnANSpZzRlS29x+zllLqiVpZBKHNwoqE6OQBgAcXRTeIoCd0x564siW8K2RUs0MMy9E 9tBOwNv4KFtjQxwA8C5C8drOLlmlya4h5a21Fy513q948llbdo48okglQn8FAJxLCt68Ma1Bt9pD 7fW1O7q7LYQRxausLaPaGivPAsC7yyTbZnZiTznIyENk4UipfuZJtp68VXLyxJGZoEfaAIAzSaJl TtuaCWOVdrJ18UHrJCNZRFErU3ZCCgDwjglDa+u6GQkjszjr5sLIJI2oA8dLGtKYMBAHAJxVDJ4s Mmv1ZWURlaNeKgxJnmBmT9kueZFFKEEBwGdJJjui9CU7j/YrnJTX6Gcn3m1SbwMAOEnyyDT4SxNF tGrtLGF4nc3euN7MbMKsGDIlKMQCAO8kjeyNdIs0Vm0vt+jDiGQS2TVbtgIAOKMkoopMa5uaEc4q 9C+8EF4UmyMpAIB3Tx4tfcGb32T3G52sVzN7iQkBAA4ogJYbbetjbxe9zFp8s8v8/Y4XCQAAkeiN uwSJQiQ3qbn1Jn/zhNHNuDCR5RAKAHyKLDKfjxJG9t/YpdNbpH1/7ZY4BgDw6TKJSvWtW0Espt/g ROes/eQtxYtQAAAOsJFc/6KTmxPJAADAF8RL29F+5xMHAEAGfz5fvHfFFu1tf8ILCgDwbrLIrAi+ xs/+CGEAACCX/FpTm9x4IwwAgPMkka2+/jDCoJwEAPAGbSoJAwDgwxr+owuDlAEAcHJIGAAAgDAA AD6At5jpDQAAJAwAAPikdIEwAAAAYQAAAMIAAACEAQAACAMAABAGAAAgDAAAAIQBAAAIAwAAEAYA ACAMAABAGAAAgDAAAABhAAAAIAwAAEAYAACAMAAAAGEAAADCAAAAhAEAAAgDAAAAYQAAAMIAAACE AQAACAMAABAGAAAgDAAAQBgAAAAIAwAAEAYAACAMAABAGAAAgDAAAABhAAAAwgAAAEAYAACAMAAA AGEAAADCAAAAhAEAAAgDAAAQBgAAAMIAAACEAQDwMUwIAwAASBgAAHDOlIEwAADgUMKYuNQAAOdu F0kYAABwGGGQLgAA1mtHd2tTSRgAAOeThvX58vhYYZBSAOBTJDAl0sXU0EauJhESBgDA/tKoG/U1 GvnVk0a/08UhNQAArJtENqff4KQydbTpyBcFAODA0titA7xf+MtPM09YuwDT1nEKAOCEaSLqw5he 1Wb2K51c5hedErYkUQDAJ0ohalen4KZ9esXN9h4zvefIBQDgE6QxSVyJmSRXllq9xN9vdBEiM2ai FwDAp0hjMm6sWxKGN9oqandTbW+/0clnkkXr8DFkAgBnl8KcG+dJ/AFFU9DGZqUQ3uT3G1yUKGJ5 1pyEkVIA8BkCySSOKHVMiTZ2tfazn3liU/IEopPPXBhkAQDvKIu5N9JTcGx2o903xpLopDIXyJNB JIgp+XsCAJxBHNkb6czN+ZT8Ppl7Q96vcNItJxHZUoKTRBAA8K4CiYbIPp+PDW1t5qb+ZcKQwIxZ C3oJA2kAwLumi0w7OiqSGKWtI3yV9rNPntyc2KQdkRk9cQAAvIscJidZWG3mqHy89IZ804SR6Zix RDFWJzlK23Axz4zIBQDOJBCRuDQ/OqLItKOrDx5asw/DkoRmxFH5mlH8OhzDbQHg3WQRtZuZhDE6 clky9201YURlqDFIGGODGT0rAwCcVRxRKX9MtJ8tJarF7WffcIJZY3mmtKJVFK+s+AYAcBYxRJ+L Sk5jcMzp12iq2myVMFpO0CpXtdoRgQDAGSQSdW5bCePRII1R8h3tL1lLaq4kyhN/SNwhHtkaUQDA UdOFVRXxkoUmh0fQfmZK/SILy/t94mS9dUsiI3on6J209jNF4o5w5AEAZxFHNM/iURxLZbFKGT+7 ltSUSBjRCKjoRB/BBaQjHADOKAmvKqP1UTyM9jFqQz2BaL/D6sJoPenROdHoKC+EVdfLCAJ5AMCR xJGpzHg32I9EW9pSltosYXiiECNWRXW4R0PUmrOoFgDAEdOFJpEoSTyPe/U4VxpzfvdFCSNKGi1W fF6Au7T1a7SsagsAsHe6EMmVo7yb63tSFF5ZalHq6Gc2utnRUZEkshdgSpw8ogCAI6YLWUEUd+fj pQkj3W6uMXEvEkdWEnfR63abxSsAgBeki7k32Hfj0BJH3W5uMlqqbzh5TyCtUSpzEVpKU6QMADhi uvCE8VBuqj1R3IMb72iY7WLmrlabnXuRsWXGng/xZ4KTMgDgiOlCGiowLdKIOr6jzetm7ZGx1bDa TN/F87glLkhLR44IczQAYL90kZnYbI2EqtvEW4M8Mqt/L2of+4YLEfVfaOb0TvJWXIybcWE8e86Z owEAsJUsrOkGmVLUXZFG1D5mb7BXm4vRz7worQkjEsVNsanVqROtzLjYogAAM2URdXA/GtrIW0Ic L524Nyy4UJm+jEdwEerj+vM4/DxeiuN/P6P7kdz487z7ed4rF6P7ea0rfueOv3EA2KAMJZLbEygr iqjNbE0X2u/YfEM9JC9MV/3gLlGWsmpz1vH98/uUx70QRl8cXXFIJY5IGoI4AGBFWbR0cFtTDeo2 8ltpH7W+jUyHt7fH92YJY3JEkZFFfVG+fxLFd5EsbkXCGKqEEQmjThmlLOp0QdoAgLVkUYujbrSt AUC3QBLWa9mEYW0V8fKSVH1xygbbGjJWlppuijQG5Yhk0SmJoa+k4EmDtAEAS0RRPnorz1ojoer2 sD40aUQDgzJbts5KGUPDxeoco0bjiy9KuhgUWVyLz1+MhOEJoyt+v1H5Gk0SpA0AyIoiksUYVFse jizqR00ac6YeTMnzWj1haHfpVsdOb0SwoUgadbK4FsmiTBnZhNFVKUNDEwdpAwCyohCZtyzSwyhD 1cdvI2lEKcOTxSpTEJb0YZSNb1mailLGUxpRGWqoRKHJonMa+k7aO8ERBwCiiEShVVesEaLlTbM1 2Oe3IwpLGLdkyvDKaZsnDE0cXSGLTMrISKNMFhdHFpYwpkIWnZM4InEgDwBEYcnCWnVWW+LDE0Ut jUgcmc7uVdeQWiIMcS5iJmXcqpLTt/w5IqpFFlGjXs/b6BrEQeoAQBTRpLxphiwsUXji8EpSWv+F yEqd3XOFMTl34V7KuFelpUtwaGWovlEW5UXqg5SRKU1NhmQA4NyCyIpCjGShDZ3V5lV8B3L4bXzu OyhFeSOkWs5/s4RhDVEt7+QfRUNfSqNMGV6qqKXRBymjlsTFKFPV3zsVH7eUpqagzAUAxxRDNmFk k8XDSBfaCKhaCv/5OTxpRB3eXt/FquvtrdGHUd+p18t2PIqGXytNXZTk4U3Sy7zxtTiespjEHmk1 JctVmWQDAOcSibXQamYDJGvobCmL34njP+L3YWRLUasOpS25zPy+srPZKhFpX+Md3pDZqA+j5Y9k 6UXrFn4eAPZPGNnyU3borCaLm1KG+k+VLLzDG17rSWOTdLFEGCJ+B7IllEgCEryWbaCjWZlrxVlE AXA+cSyRxST6sFlNFjdHFnU5yhPGb0cW1gipTSofwwpvRl3S0dZ+19JEn0waljCiIW7Px6EqS12K z2n9IyL+pEBGTQGcUxaZ5T2iDm5v8yNtUp7VZ/FPQ7Lw9gpqWdJ8t+XNPVlIUhqZklSXSBGj2JNn roU0xh9ZjIU4ns9HRxzWo9dBjlAAjlOGmgJJiCzbz8KSxbfofRSRLH47Zaho7oXIhpvKrTUPo1N+ wbFoOLPSyAgjMw66vJClLMpjlD9HYdXikMSjJocu+SYhFYBlMmhJFa2y0EZCZWRxE33IbC2Hf6rH WhatI6M230RurZKUNcy2FkerNLw33lvw6/mmXos3tlyj6iH6aKw+WRaLZIEgAPYTSKs0rEUEvdFQ 1uZH2qQ8r5/iH4k7uVtGRmlltdVYM2FYb9RYNbgZaXiNq/amWtseatJ4iD9JcKk0WjrnAWB7aXhr QXk3oJP4o6G0mdzakh9WZ/c/Ys/DiFanrTdM8q7BoUpSUWmqbOSz0rB+flSGeiSkcRF7rw1vhrlI bhgx0gDYVxhT0GjWd+FjsmJxF31TuGg2dzSk9rdRjlpj7+7DJYxsaapMG1oDG02Es5ZR90RRvsHP pdOfW79mpZFdUh1hABxfGN5EvKws6r6Let8Kq/8imt3tLWWe2fNis1LUFgnDeyNHpeF8JGThJYxo 8kx5J3AtJHFVUoa1LIkmjH6mMJAFwPbCyHZyjzOqFlay0Pa1aJnR7Y2KinbV82SxujS2Kklpo4Qm RRwtPzsShZUqvooL/0wX9QZN1gq5njhE2kZSIQ2A7WQxNT5qZai6P3SU3G559RIgVsqwEoW1wGA0 jFacEtQpEoYnjXLOQ7bxzAyh9UYtfBXiuMq/d/UbnKShiWOuNJAFwHGkYQnj0ZAublU5yts5L1qy /DuQRVSCispzpyhJlfLwImGLLKw+DC8yluIYKnFo0uiN8hTSAHgfYYwSz+HKlqIyW61qaULbqzsq Q2X7LTaTx7DRm9gF4sjKQpKi8IRx/XkjalnUfRmeNCxhRP0ZCAPgGMLwZDGJP4imlsXdKEdF+3Pf xO+rqDu4DyWLLRNG1J8RScMaAjc69UUrXVyrhOGVpYbGlIEwAM6TLsZkwshULW4N0rgpj9oM7nr4 bKss3qIkNVcaIvl16LWRUc9SVJkwhiphWH0ZLSlj7dngANAuCi1R1M+z6WIUe85FnTK+FWnclBRR J4rspLwWWWwujuGFb3KLNDL9F1Z0/DJKUbUwWstSnjSQBcDxpRHJIprRHaWMmyEIL1FEqSLb0X36 Tu9SFFlpTOKvSZ8dVntVRKEJo+78tvYWvyQSBsIAOFZJKhKG1p6MTtXCGimlPY9E8RB9BvdDkdok L1qN9ggJo0Ua2T0vvIRxlT/7MKwSVDS8NprINzdlIA6AdUQRJYy6HOUtLGi1KZnSlCWSjChaS1C7 yGKPklQkDS1teEnjUr3JQ/H4nKh3q4RxUaRxCRJGZngtHd8Ax0oYmXJUZq+LaB0p77WHxP0UD4nX htqlz2IvYWSkMUnbHhhjII5aCjcjTXjlqOxcjEgaiAJge3FkN0NqmYORKU9ZcmhJFNYM7sPI4tXC mFue0t703hFH+ca2pIkoXWRkkU0ZHogFoK1BbNk9L+rH8OZ5ZYRgPc+Iwis/7S6LPYThSUOTxyh/ 7hNei6N+oy/y7z0v7skk4fVdZIWxRBaIAmC+OLKyyHZ+eyth3wOpRENkWzc/OoQs9hJGNmlMSmNc v+F9lTZ6+fduehdFHPXn+oQoMsIQsffKQAwA24ukRRqZlOF1hkevWf0To1IWkzPIYk9hlCffGc8l SBudkjaejXmdNHrjMRLEnHSBMAD2k4WIP2CmRRqePEbxl/Cw0kRUftp1nsWRhdFaotI6xbW00RWl qmfi0NJDS5pAGADnF4ZIbk0pSxjWx1lJjOL3URwyVRxNGFrasGRRp43668dKFmVD/0gKwtqiNdrn m/kXAPsJQyS3rPmkNN7185bDks00s/R0WFkcSRiiJAxLIJNxh1+nkzFICr3zemY01JzlzZEGwD7C kERpKtv4j4mUUm9L3ZImpqNe+OHAfwzRwoWROLoqcXTiL1MepYmlu+0hCoDXlaZapZFJHlMghslJ FJnf7dCyOKoworSREYcYAukqeWTkQKoAeO+kIQl5eK+PkptDccpUcRZhiPgjqTKd4p2TRGSGIJYI A2kAbC+LrDBE8qOpWo45SWI6y0UfTvbHEZWp6mSSafQzH4vkJ+chDIB9hRHdxWdGKUWL/0Wd2G8l irMJQ5OBKOnDk4bX6GdSw1qLCyINgNcKo0UakUhE5o1yOrUozioMcWTRkjqyKSGbJOjgBjiuSLyG u6V/YU5fxFuI4szC0N6MOaljmiGDTOkJUQAcM31MM59PC37GW4jiXYShiUMkP7JK+16SBMBnp45s w9/6McI48B9GlDrq2eNTQjgIA+D9hLH11yCME6cOCdJHy89AGADnFEbm89PCr0UYb5A6ZIFAsn8o SATguIJo+fppxX8HYZz8D6n75DcfAGE0ff3HtxEDf1ipdNDyh9LxhwVwOmkgB4Sx6h9Kxx8aAGJB GLDmHxb9FwCIAGEAf6gA8Ln0XAIAAEAYAACAMAAAAGEAAADCAACAs/JfAQYAL3iXmIlSiu4AAAAA SUVORK5CYII="
+ transform="matrix(0.24 0 0 0.24 179.2061 198.1514)"
+ id="image77"></image><g
+ id="g79"><radialGradient
+ id="SVGID_5_"
+ cx="225.1929"
+ cy="226.1387"
+ r="30.8299"
+ gradientTransform="matrix(1 0 0 0.75 0 56.5347)"
+ gradientUnits="userSpaceOnUse"><stop
+ offset="0.0123"
+ style="stop-color:#FFFFFF"
+ id="stop82" /><stop
+ offset="0.4828"
+ style="stop-color:#FDFEFB"
+ id="stop84" /><stop
+ offset="0.7611"
+ style="stop-color:#F8FBF3"
+ id="stop86" /><stop
+ offset="0.989"
+ style="stop-color:#F2F8E8"
+ id="stop88" /><stop
+ offset="1"
+ style="stop-color:#F2F7E8"
+ id="stop90" /><a:midPointStop
+ offset="0.0123"
+ style="stop-color:#FFFFFF" /><a:midPointStop
+ offset="0.8025"
+ style="stop-color:#FFFFFF" /><a:midPointStop
+ offset="1"
+ style="stop-color:#F2F7E8" /></radialGradient><path
+ fill="url(#SVGID_5_)"
+ d="M186.706,235.825c0,5.965,4.835,10.801,10.799,10.801h55.374c5.965,0,10.801-4.836,10.801-10.801 v-19.373c0-5.965-4.836-10.801-10.801-10.801h-55.374c-5.964,0-10.799,4.836-10.799,10.801V235.825z"
+ id="path92" /><path
+ fill="none"
+ stroke="#EDF5E5"
+ stroke-width="5"
+ stroke-miterlimit="10"
+ d="M186.706,235.825 c0,5.965,4.835,10.801,10.799,10.801h55.374c5.965,0,10.801-4.836,10.801-10.801v-19.373c0-5.965-4.836-10.801-10.801-10.801 h-55.374c-5.964,0-10.799,4.836-10.799,10.801V235.825z"
+ id="path94" /></g></g><path
+ opacity="0.74"
+ fill="#FFFFFF"
+ a:adobe-blending-mode="lighten"
+ d="M263.623,229.595c0.037-0.364,0.057-0.734,0.057-1.107 v-13.375c0-5.965-4.836-10.799-10.801-10.799h-55.374c-5.964,0-10.799,4.834-10.799,10.799v7.324 c7.545-1.012,15.699-1.566,24.213-1.566C231.959,220.87,250.812,224.252,263.623,229.595z"
+ id="path96" /><linearGradient
+ id="SVGID_6_"
+ gradientUnits="userSpaceOnUse"
+ x1="225.1929"
+ y1="204.3135"
+ x2="225.1929"
+ y2="246.626"><stop
+ offset="0.0123"
+ style="stop-color:#FFFFFF;stop-opacity:0"
+ id="stop99" /><stop
+ offset="0.0141"
+ style="stop-color:#FDFDFC;stop-opacity:2.231669e-04"
+ id="stop101" /><stop
+ offset="0.1344"
+ style="stop-color:#BEBEAF;stop-opacity:0.0148"
+ id="stop103" /><stop
+ offset="0.2565"
+ style="stop-color:#94957C;stop-opacity:0.0297"
+ id="stop105" /><stop
+ offset="0.3796"
+ style="stop-color:#747759;stop-opacity:0.0446"
+ id="stop107" /><stop
+ offset="0.5029"
+ style="stop-color:#5D633F;stop-opacity:0.0596"
+ id="stop109" /><stop
+ offset="0.6263"
+ style="stop-color:#4D552E;stop-opacity:0.0746"
+ id="stop111" /><stop
+ offset="0.75"
+ style="stop-color:#414B23;stop-opacity:0.0896"
+ id="stop113" /><stop
+ offset="0.8742"
+ style="stop-color:#3B461E;stop-opacity:0.1047"
+ id="stop115" /><stop
+ offset="1"
+ style="stop-color:#38441C;stop-opacity:0.12"
+ id="stop117" /><a:midPointStop
+ offset="0.0123"
+ style="stop-color:#FFFFFF;stop-opacity:0" /><a:midPointStop
+ offset="0.2901"
+ style="stop-color:#FFFFFF;stop-opacity:0" /><a:midPointStop
+ offset="1"
+ style="stop-color:#38441C;stop-opacity:0.12" /></linearGradient><path
+ fill="url(#SVGID_6_)"
+ a:adobe-blending-mode="darken"
+ d="M263.68,221.954v13.871c0,5.965-4.836,10.801-10.801,10.801 h-55.374c-5.964,0-10.799-4.836-10.799-10.801v-13.871l0.038-7.704c0,0,0.923-9.937,11.173-9.937h54.962 c0,0,10.063,0.328,10.801,10.799V221.954z"
+ id="path119" /></g><g
+ id="g121"><g
+ id="g123"><image
+ overflow="visible"
+ opacity="0.25"
+ a:adobe-blending-mode="multiply"
+ a:adobe-opacity-share="1"
+ width="30"
+ height="30"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAhCAYAAABX5MJvAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAuJJREFUeNrsl9trE0EUxjO7m5vW tKFN1RqLCmqlIvjgkz5I/cOFIqLggw9KsRHxUo1IdEtactG9+A1+A8dxNrsxK/rgwI9lt5ueb875 ZuZspfJ//Bhqjvc0AfCIHClIQEzSMkUoBqyCJbAKWrxXQoBmBL6AQzChmGQREWbmNQY/DS6Aa6AL mtZvdcDPoEcOQEgxUV5mVMYzH5wCZ8FFcJ0CLoN1UHeIGII34AV4BvbBW4qbzsqKctzruq+ALXAL 3ABXwAafNyjS9sQ3cAwG4BXYA0/AU/AejLOE+I4MtME22AH3wE2wyedNivSFQT3eB/y79kwHnGE2 v4IjinCaNrBEtJiBu2SLs686VkRWGRt8/wTL5jFwxIxMbSGB+Ac1qtcluEMBbWslFDV7QBFdlmBE bwxZtthVDn1dpgF3WIIOhakF9iCf2ajQK32W5hcRJgvnmYHb9ECzQAnyhif8o7PxkWImsiQeRSyJ fWCjJAGy5G2usKtgzc6wx5dWxT6wYhm2jKNBm/UcV90m/aLsdLVoonX+QJV8RvmcXNflNVOOKktQ Fz4p+6AMrBg/GUeeFWUHd51HyuXevz7+GRELNSRzjMwYnmhI5Laa/gEBYxEjskVE7Ih67AeOi3ZE BYc55j+xxzjgpBMpImZL1mNDMuDxm5aYBT2x1+wx+vZJ6lt94kl2Ux1uWl4JWZhy9g/AQ/DOPjt8 q0ULuLebhiRYYO8wPUTIdm+X1zDrKE/FKjH95TL3eP83MiIF7FHAY2ZkYpfadxhoRE80WJ66EKIK BE9YAiPgPkW8dPUSFUfDGnMpHVmKvQJCEoofcsamBLs0fOgSUMnomo2QQ66UAbMTi4+hmOk2mGZW B39OE+rgj5iBcNb3h5qxk9boDb1SLrEh2c75+NlnCfT1A4OP8nZiVeAT0IhZY0Ni+gHP8oEpQ59Z HHP2uRtfkeUnxTj7AWHqMU0ZiRVX2ld5kZ4jnSewHN8FGACSOOKkAlOGAAAAAABJRU5ErkJggg=="
+ transform="matrix(0.24 0 0 0.24 199.0298 216.5547)"
+ id="image125"></image><g
+ id="g127"><radialGradient
+ id="SVGID_7_"
+ cx="202.6289"
+ cy="219.7041"
+ r="2.9995"
+ gradientTransform="matrix(1 0 0 0.75 0 54.926)"
+ gradientUnits="userSpaceOnUse"><stop
+ offset="0.0123"
+ style="stop-color:#FFFFFF"
+ id="stop130" /><stop
+ offset="0.4235"
+ style="stop-color:#FAFCF6"
+ id="stop132" /><stop
+ offset="1"
+ style="stop-color:#F2F7E8"
+ id="stop134" /><a:midPointStop
+ offset="0.0123"
+ style="stop-color:#FFFFFF" /><a:midPointStop
+ offset="0.6235"
+ style="stop-color:#FFFFFF" /><a:midPointStop
+ offset="1"
+ style="stop-color:#F2F7E8" /></radialGradient><circle
+ fill="url(#SVGID_7_)"
+ cx="202.629"
+ cy="219.704"
+ r="2.999"
+ id="circle136" /></g></g><g
+ id="g138"><image
+ overflow="visible"
+ opacity="0.25"
+ a:adobe-blending-mode="multiply"
+ a:adobe-opacity-share="1"
+ width="30"
+ height="30"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAhCAYAAAC1ONkWAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAtFJREFUeNrsmP1LFEEYx292Ts3V 9ujFrCiwFyPShH4I+imoiPqbhYKIoKigN0W8SulNIrOU63S921u/A9+BYdm9mbndg4IGPiynuzOf eea52WeuVvvf/Joo8VwA6rxm+0lBD3R5TYctpu6XYBRE4DiYzMhpqRbYBDtgHyQ+gsIzQmMUOg3O gzkwzciZTUXqO1gCH8E3CsauERSOUiOgAc6AC2ABXAYXwZECsV/gPVgBb8AH8AVsg45NTjhKTYGr 4Aa4AmYZqYjLmpdj+4ySilwTLIOn4C34YZOTjlLXwH1wC8xzKSMureQym0g+O85ITxP1uU3hPS6r t5j63zFK3QM3uYwNQ0g45KUSPMSJNLjsLS71blHUZJ9Ox5lDSuo2k32SHYsBvslKcAIc5jJvUK7r I1ZntK6Du8yryBJhW9P73hi3jg2ym7ek0hKtO0z4E5xx2RYYOany7DPYyotaUPCwyoVL3KemKpLS TX+h5jhGI88jT0x9/U9yrzoHwoL7ykQtZN8LHGvURUxy05xhntWH8I7WOTzDsaSLmOAMQl6DIYgF mTGEi5iWEyWqD9dtpHCMoPaXtn9KrHSR59CsYxSJ6SKv1e9FW6L1MmM4iXWMIu8ri7u04mjF7HuJ Y3VcxLqciaqfVlnYJRWKJexzlWNs5r2SZMGMNOp1cRYc5atEVBCtPVazD8AzHzHdQUKZUyzywoIT kY9Uh9XrC4o1WTimPmI9ouv9iAXfIHKm1GtKvSyKlq2C1Una5sMTLBRHPN4MOvIxpV6BRfCEJU/s W8Ganf4xzoaCf5dGaS36JHnMKnWNUg/BY35uD1rza7ku5bY4658cMDHkEt6nUZP4TQG1dI/Ic/CJ /SVVHHglS2J94pnluXLecuB9x3Nlk5+3jUlV9hOBMAQjCpn1lMikgFrCdQrtGEKp62CDlCtaMLQc eNu+QmV/7XGp2cyN2rsdCDAAoyXZx8WJpTUAAAAASUVORK5CYII="
+ transform="matrix(0.24 0 0 0.24 213.9448 216.5547)"
+ id="image140"></image><g
+ id="g142"><radialGradient
+ id="SVGID_8_"
+ cx="217.5439"
+ cy="219.7041"
+ r="2.9995"
+ gradientTransform="matrix(1 0 0 0.75 0 54.926)"
+ gradientUnits="userSpaceOnUse"><stop
+ offset="0.0123"
+ style="stop-color:#FFFFFF"
+ id="stop145" /><stop
+ offset="0.4235"
+ style="stop-color:#FAFCF6"
+ id="stop147" /><stop
+ offset="1"
+ style="stop-color:#F2F7E8"
+ id="stop149" /><a:midPointStop
+ offset="0.0123"
+ style="stop-color:#FFFFFF" /><a:midPointStop
+ offset="0.6235"
+ style="stop-color:#FFFFFF" /><a:midPointStop
+ offset="1"
+ style="stop-color:#F2F7E8" /></radialGradient><circle
+ fill="url(#SVGID_8_)"
+ cx="217.544"
+ cy="219.704"
+ r="2.999"
+ id="circle151" /></g></g><g
+ id="g153"><image
+ overflow="visible"
+ opacity="0.25"
+ a:adobe-blending-mode="multiply"
+ a:adobe-opacity-share="1"
+ width="30"
+ height="30"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAhCAYAAAC1ONkWAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAttJREFUeNrsmO9r00Acxptc1m6d Fn9M125sU4RVpyjiSwXB/9wXulciiE4dhpUMpwzFUa02XdP4HDwHR7hcLk0mCh58WOnI9548973k uTYa/0e54c15nQ8E8TJ1UpKQ2Z8QJgUtgDa4CC6AliZOiYrBCfgGfoLTsgK9OQStgE2wDa6DDv+v hhQwBAdgH0TgS1mBLsIEBV0F18BNcJvC1sCyQdgIHFHYG/AODMAxBSZVhQXgHJ15AO5T2Aa4TMHC 0GMJBXwFhxT2Erygkz/AtGhim1NS1A3wCDwGO+AKBS3QKS+nrlp6eQProKe5G4LvNucCS0+1uXQP wRNwj6JaFkH6SgitNxeJ0BwNueSzMsIC3ulduiX/roJmpp9cWkVQ1CrrqB17ws+TPGdM3y3Rftnk fTpVVlS2ZpN1+qy7znl8V2HSrUvcdbKnutryVRk+63RZd5vzBC7ClFvyMXALbHEDiJreNGpDbbH+ Wp5rJmEd7sQ+n13NCq8uU881WbfPeTquwtq0u1ezW1nXepyn7SJM9dgSCc4oPBTO4Rus9jKJwatZ lGeZy+rYXzH+GWEpXxEq5Kl8VecwBcnURVjMgCcZn5GwsTZH7CJMD3khL5zWLGzKuiHnGZpe5CZh I6bO9wx7v+bN7YYxY70j1o/yEoZpKSdMmntMoMq1tIYlVG7ts/4x50tddmXCEDfgxRETZ1JRWMI6 EesObGFRWCyfaa+oDl8jQd4DscApJUr21S54Dj7wu1JBUW2Ct1rybDDRntditUtPnWor8Aw8Zd2h rXdFQdGYd6WfbPTYnOeeEiSv/cTDyC5FvbL1luspSSXPFUYUmaHu8KS0yfjdMpySYp6QIop6TZdC njEnRTvdpVc8Lt0yBW4wS+04HHj3+Fg4pKARnUxdJnVNBL7hSNal4OxPBFLAZ/CRzumn8NR1wrKR xdfy1KLlwDvmw3RaRlDVX3s8h8dGWiUE/BZgAMf82R9IYLF+AAAAAElFTkSuQmCC"
+ transform="matrix(0.24 0 0 0.24 228.8599 216.5547)"
+ id="image155"></image><g
+ id="g157"><radialGradient
+ id="SVGID_9_"
+ cx="232.459"
+ cy="219.7041"
+ r="2.9995"
+ gradientTransform="matrix(1 0 0 0.75 0 54.926)"
+ gradientUnits="userSpaceOnUse"><stop
+ offset="0.0123"
+ style="stop-color:#FFFFFF"
+ id="stop160" /><stop
+ offset="0.4235"
+ style="stop-color:#FAFCF6"
+ id="stop162" /><stop
+ offset="1"
+ style="stop-color:#F2F7E8"
+ id="stop164" /><a:midPointStop
+ offset="0.0123"
+ style="stop-color:#FFFFFF" /><a:midPointStop
+ offset="0.6235"
+ style="stop-color:#FFFFFF" /><a:midPointStop
+ offset="1"
+ style="stop-color:#F2F7E8" /></radialGradient><circle
+ fill="url(#SVGID_9_)"
+ cx="232.459"
+ cy="219.704"
+ r="2.999"
+ id="circle166" /></g></g><g
+ id="g168"><image
+ overflow="visible"
+ opacity="0.25"
+ a:adobe-blending-mode="multiply"
+ a:adobe-opacity-share="1"
+ width="30"
+ height="30"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAhCAYAAABX5MJvAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAt9JREFUeNrsl91rE0EUxTOzm69a 05YmVWsUFdRKRfDBJ32Q+ocLRUTBBx+UYiOitlqRaEos2UT3w3P1jIzrbHZNVuiDAz9CNru5Z+69 M3O2Uvk/fg414zOCDzSxRwJiEJGkTBGKAatgEayCFr8rS4AwAp/BIRhTTDyPCDPzGoOfAhfANdAF zdT/SMBPoEf2wYBiQldmVAEBHjgJzoCL4DoFXAZroO4QMQRvwAvwDOyCtxQ3SWdF5QiQui+DDXAL 3ABXwDqvNygy3RPfwBHog1dgBzwBT8E7ENhCvJwMrIBNsAXugZvgPK83KdKzGlTzu8/fpWc64DSz +RV8oYhfTetPEdFiBu6SDc6+6lgRWZNo8P4Flk0zcMiMSGkSP+MPalQvJbhDASuplVB0RfkU0WUJ RuyNIcsWucoh15bYgFssQYfC1Bz7kcdsVNgrByzNHyJMFs4xA7fZA80CJcgb2uofycYHihlrh4hF ax9YL0mAGT7LKivsKmjLpLXjplVrH1ie0ryzlkWa9SxXnWR5QTv6ocUmWuMDqlLu8Di5ruk1Vzmq LEGdD5QtQln7yI8YespZUXbwzBi6cgzGsRTx14ZkxvFbDJeI9Laa/AMBgRUjTIsI6Yh69ANH0xzR DMMc8x/pMcTwjNIiIlqyHg1Jn8dvUmIWZGKv6THk/Jh4GWqFE3RTHW5auoQsTDj7B+Ah2JOzI8vU RNxQ2pYh8efYO4yHGNDubfNzkHWUJ9YqMf5yiZ7AmyEjtoAdCnjMjIj5TbycBhqxJxosT90SogoE j1kCI+A+Rbw0XmKaxzQlCXjz2GpOXUBITPFDztiUYJsNPzAC8kQklpBDrpQ+sxNZL0MR020wZlaC P2cTSvBHzMAg/f6hCu6qNfaGrJRLNCSbOS8/uyyBfL5n8JFrJy7a7Solpk1DYrynTvWBKcMBsxhw 9nEZL8S2GNtzuJo6YFOG1oor7a28iOdI8gLb47sAAwCDFN6m03jgxgAAAABJRU5ErkJggg=="
+ transform="matrix(0.24 0 0 0.24 243.7749 216.5547)"
+ id="image170"></image><g
+ id="g172"><radialGradient
+ id="SVGID_10_"
+ cx="247.374"
+ cy="219.7041"
+ r="2.9995"
+ gradientTransform="matrix(1 0 0 0.75 0 54.926)"
+ gradientUnits="userSpaceOnUse"><stop
+ offset="0.0123"
+ style="stop-color:#FFFFFF"
+ id="stop175" /><stop
+ offset="0.4235"
+ style="stop-color:#FAFCF6"
+ id="stop177" /><stop
+ offset="1"
+ style="stop-color:#F2F7E8"
+ id="stop179" /><a:midPointStop
+ offset="0.0123"
+ style="stop-color:#FFFFFF" /><a:midPointStop
+ offset="0.6235"
+ style="stop-color:#FFFFFF" /><a:midPointStop
+ offset="1"
+ style="stop-color:#F2F7E8" /></radialGradient><circle
+ fill="url(#SVGID_10_)"
+ cx="247.374"
+ cy="219.704"
+ r="2.999"
+ id="circle181" /></g></g><g
+ id="g183"><image
+ overflow="visible"
+ opacity="0.25"
+ a:adobe-blending-mode="multiply"
+ a:adobe-opacity-share="1"
+ width="30"
+ height="30"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAhCAYAAABX5MJvAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAn9JREFUeNrsl+lrE0EYxvdKjSZW YxEPxBsVrNdHQTxA/KMFBRGPDwoVVIpoq3jUeJUG25qk2fVZ+A28WTabxG4lHzrwgxw78z7zzMw7 73reBDR/jOcCUREhn21LRCy6osfn0kT4BN0h9oiDoiGmTN8Efoum+CHWEBRvRoSbeZXgR8QZcVEc F7syfTcI/kq8Fgviu1jlv3hcET627xXHxFlxWZwXJ8RMxgmPIKkTn8UbMSdeinfiq1hnmUYS4QTs F5fENQSc4rfUgahgT7TFivgk5sVj8VQs4kqukGiAgCviDiKOijr/BUOWL7t/9uGaVyTEighYggsI uI79NQYfdY9FPF8x/WL2xiJLk9hOoelcJehtcYslqI8hYNDGrvP9G5t1PbtRQ+NIg/W/KWaxNNpk DnK5JZ35TzbuCq70ibAu3BBXxWHW1i8hGbpc0+akNLNuBDAtTopz4kBJAuxEC8cPzIlI88BpOoQl Xw1TuDtLsqvZkxbwUA2FjZxEVJYbdROj4mWOpVuzCMoWYGPlxggm4SrfFmFFJOTzDUi2KFY8KIYT sUoSWRadLRDSM0XPMgVPn4guOT0tSN6KVtHd/w8tYWJfqDHeM+m+jBkTeIEaoEmKTUp0oXD80Kjt kU4PkVSqJWTOhIDpFf5APBFLOOPliYhxZgYR00MKmVEEuKWeQ8Q8ruRe5Xb3po7s5CqvDSjnxhVw XzzjFu3k5XTbuuziNYLvZolCk+KHBU8n8QcBL8Rd8VB8yCto8kTEDNBCTIdBg4wQvyD4L6rsdOb3 xKNhhW44IKm4wZaghSAnoIdrHWhz/m3wlOfiI86OXPJPzMvPxLwG/tcX4u3m2l8BBgBQ/dU5d1Za tAAAAABJRU5ErkJggg=="
+ transform="matrix(0.24 0 0 0.24 199.0298 230.2217)"
+ id="image185"></image><g
+ id="g187"><radialGradient
+ id="SVGID_11_"
+ cx="202.6289"
+ cy="233.3711"
+ r="2.999"
+ gradientTransform="matrix(1 0 0 0.75 0 58.3428)"
+ gradientUnits="userSpaceOnUse"><stop
+ offset="0.0123"
+ style="stop-color:#FFFFFF"
+ id="stop190" /><stop
+ offset="0.4235"
+ style="stop-color:#FAFCF6"
+ id="stop192" /><stop
+ offset="1"
+ style="stop-color:#F2F7E8"
+ id="stop194" /><a:midPointStop
+ offset="0.0123"
+ style="stop-color:#FFFFFF" /><a:midPointStop
+ offset="0.6235"
+ style="stop-color:#FFFFFF" /><a:midPointStop
+ offset="1"
+ style="stop-color:#F2F7E8" /></radialGradient><circle
+ fill="url(#SVGID_11_)"
+ cx="202.629"
+ cy="233.37"
+ r="2.999"
+ id="circle196" /></g></g><g
+ id="g198"><image
+ overflow="visible"
+ opacity="0.25"
+ a:adobe-blending-mode="multiply"
+ a:adobe-opacity-share="1"
+ width="30"
+ height="30"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAhCAYAAAC1ONkWAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAmlJREFUeNrsmM9r1EAUx3cz2XW1 il2wLLagIh5aeilUBC967EX/XA/1It5aUaiC2JNY/EWp0lZkG3c3id+Bz0AIaXayibKHDnzIJfPm s29eZl/Sas3paNeYZ0SHaz5OKmIx5pr+azF7fyh6oi+WxXURZGJZiUScim/iWERiUkWwXTFDlxG6 I1bFBnKd3P1jpPbEvviE4JlvBtueUl1xQ9wVa2ITsdtkzOTmxGTsALE34oP4KH6I0TS5tofUJXFT PBCPxToZ67OlZTUWkSmbsffipXglvos/ZXLGI1N2qx6Kp+KRuFcgVYRh/oJYEgNxle08EUNqsbJY SDAnZa8r1FlYoQzc02sFF5n/W/wskzMlAReopydkaoVtDWocL1bqGtv8Bblx0YSgJFt9xNbJXLfG uZctjQEx11gj9M2YDXCFiVviflmAGeQCYtlt/MxTOvbJmEFkFZqSyu9GNr7xEXNP4gbnVK/mFhZl rUdsd0B3fcQCDs3lcw7PJobJrRH4iE37g24qa6VrBK05HRdiTYjVbvI8xtQ1isSyTd4pE5secW6N xEdslGnyDmhd0oazFRF7j7VGPmIxPdQ+HNMWNzUmBfFj3+7C1YDtMG7RT3UaONMS+jErtC1e05tV EksyPdkAyToHbsqW2e51R7ygs42qNooJaU/oPF2TF8wgl2SkdsVz8Y5sJVXFUvryX6TfNXld5HwE U37cWUbqGdfDsto1njVxQjscQ8jc8+SckO25jqipHTK1i+Ro1peR7FM6pKH7StAhC7uam7CQI+J+ J7RNTb0lU7Vf3+b6hXeuPxH8948qF6Pq+CvAAGGezDColMK7AAAAAElFTkSuQmCC"
+ transform="matrix(0.24 0 0 0.24 213.9448 230.2217)"
+ id="image200"></image><g
+ id="g202"><radialGradient
+ id="SVGID_12_"
+ cx="217.5439"
+ cy="233.3711"
+ r="2.999"
+ gradientTransform="matrix(1 0 0 0.75 0 58.3428)"
+ gradientUnits="userSpaceOnUse"><stop
+ offset="0.0123"
+ style="stop-color:#FFFFFF"
+ id="stop205" /><stop
+ offset="0.4235"
+ style="stop-color:#FAFCF6"
+ id="stop207" /><stop
+ offset="1"
+ style="stop-color:#F2F7E8"
+ id="stop209" /><a:midPointStop
+ offset="0.0123"
+ style="stop-color:#FFFFFF" /><a:midPointStop
+ offset="0.6235"
+ style="stop-color:#FFFFFF" /><a:midPointStop
+ offset="1"
+ style="stop-color:#F2F7E8" /></radialGradient><circle
+ fill="url(#SVGID_12_)"
+ cx="217.544"
+ cy="233.37"
+ r="2.999"
+ id="circle211" /></g></g><g
+ id="g213"><image
+ overflow="visible"
+ opacity="0.25"
+ a:adobe-blending-mode="multiply"
+ a:adobe-opacity-share="1"
+ width="30"
+ height="30"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAhCAYAAAC1ONkWAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAlRJREFUeNrsmM9LG0EUx5PdjTTW otDYWmoOQm2M/YGXnrxI/3IvnnoRW7TagocotqjQtLYp5pffgc/CECc7u+uGpuDAB2Y32Tff9+bN 7Jstlaa0lXM+E4gIAsd/BqIHpj+cpLBY0Ix4JBbhwYg4I+SvOIdf4jqrwHIOQUvihXgtVsWCQ9gP 8UV8El/Ft6wCyyl+DxH0XLwUb8UbxD0V1RE7ZtCO+I6oj2JPHIlTBPZ94sqe3yIi0hCb4h1Reibm iOK4HDPRuRJnRO+D2BGHRLSXJC7yRGpeNMV7sYXAeQSFCU6FRHIGB56IGveMI/uIGxu5JGFzTN0W wpqIijIsmpDFYZ55hah4xRpxP7MIM4NWWHEbTGGDKY1ybi8VKyVM/l2wYjtM+S1xrvww9x6KulgX K0QqvOOeGafGCnbrjOPScOtmnPA1Hm7Sr+TcjF2Rq2F3nb4zNVzCZsWyWMOr2XFe5WgB9urYX+ba KywkF1bJh8d4WWSrYLdhbdBhmohVrddNtYApLOUZI0jxgp6EMO8YQWlK272wuwobFlHkeVqqMVzC OlaR15mQMO8Yo8L6VpFnypNL0S1YWBe7h4wTVxneiP0RJ+KzaHE9KEjUAHst7J9wnWoqe7z9TVly QL9bwJQOsXOB3X36vbTVhfHqN16Zh49F2xXujK2PnWPsthhnkLYeiz0ziblrVZ55CkV7Ftrk1Q52 z5NmIkowdsUBIrIqz7SltR2la0vUNhxhP3PNP7RCf4CouPIs4jDS9p2U/svj21QfeKf6E8E/+ahy 37K2GwEGAJb/2mQI89WQAAAAAElFTkSuQmCC"
+ transform="matrix(0.24 0 0 0.24 228.8599 230.2217)"
+ id="image215"></image><g
+ id="g217"><radialGradient
+ id="SVGID_13_"
+ cx="232.459"
+ cy="233.3711"
+ r="2.999"
+ gradientTransform="matrix(1 0 0 0.75 0 58.3428)"
+ gradientUnits="userSpaceOnUse"><stop
+ offset="0.0123"
+ style="stop-color:#FFFFFF"
+ id="stop220" /><stop
+ offset="0.4235"
+ style="stop-color:#FAFCF6"
+ id="stop222" /><stop
+ offset="1"
+ style="stop-color:#F2F7E8"
+ id="stop224" /><a:midPointStop
+ offset="0.0123"
+ style="stop-color:#FFFFFF" /><a:midPointStop
+ offset="0.6235"
+ style="stop-color:#FFFFFF" /><a:midPointStop
+ offset="1"
+ style="stop-color:#F2F7E8" /></radialGradient><circle
+ fill="url(#SVGID_13_)"
+ cx="232.459"
+ cy="233.37"
+ r="2.999"
+ id="circle226" /></g></g><g
+ id="g228"><image
+ overflow="visible"
+ opacity="0.25"
+ a:adobe-blending-mode="multiply"
+ a:adobe-opacity-share="1"
+ width="30"
+ height="30"
+ xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACEAAAAhCAYAAABX5MJvAAAACXBIWXMAAC4jAAAuIwF4pT92AAAA GXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAnpJREFUeNrsl2lrE1EUhmdLjSZ2 sYgL4lqsYN0+CuIC4o8WFERcPii0YEsQtYpL3cVgW7PMjO+F55ZhmMlMzATyoRceSDKZc957zplz zzjOBCz3P+/xRE34fE6uWESiJ0I+VybCxekeMSMOizkxlbATwx/xRXwXWwiKRhFhd17H+TFxVlwU J8W+lJ0+zlfFmngjvolNrkXDinAJ+6w4IRbFZXFenBLzqUg4ODGR+CheimXxQrwWn8U2aSolwgo4 KC6Jawg4w28mAsGAmuiI3+KDaInH4qlYJyo7QoISAq6IO4g4Lppc8wrSl66fA0TNSQvJE+GRggsI uE74GxgvW8gB/68l7ouojXVSE/s5N9dxelvcIgXNIQTkFXaT718pViMiyjIa8OiZ/N8US4Q0GLEf 2d5iauYHhWtqpu8PiMINcVUcJbduBY3R9poOT4rpJdteRi1Mi9PinDhUkQC7/Cz7aRH2iTB9YIEb /IqPiSmiu0Sza3gZf2qgcC6jEVUVjWbCR83LOR8CqFpAMu07PrxJOMp3ReSJiOnnfYjH5DdK+sgS sUkT+SW6YxASJoYe46OXFtGjp5uB5JVop8/+EVfMxj4xY7w1m/YywtRmGmqhtlNhNMIs+36O2pB2 fYSmUq+gc8ZsyBzhD8QTsWEikyciomjnETFdMMiUEWBTvYyIFlGJ/ILqNRHZy1HeyBnnhhVwXzzj FO06BSHuUcVbON9Piuy7hlvCudnEXwSsiLvioXhnB5oiEREG2ojpYtRLCXEHOP/JlG12fk88yhp0 /RJNxRrbgDaCrICQqHWhw/OfdG54Lt4T2dIj/8S8/EzMa+DYX4h3l13/BBgABM7SO70ZkkMAAAAA SUVORK5CYII="
+ transform="matrix(0.24 0 0 0.24 243.7749 230.2217)"
+ id="image230"></image><g
+ id="g232"><radialGradient
+ id="SVGID_14_"
+ cx="247.374"
+ cy="233.3711"
+ r="2.999"
+ gradientTransform="matrix(1 0 0 0.75 0 58.3428)"
+ gradientUnits="userSpaceOnUse"><stop
+ offset="0.0123"
+ style="stop-color:#FFFFFF"
+ id="stop235" /><stop
+ offset="0.4235"
+ style="stop-color:#FAFCF6"
+ id="stop237" /><stop
+ offset="1"
+ style="stop-color:#F2F7E8"
+ id="stop239" /><a:midPointStop
+ offset="0.0123"
+ style="stop-color:#FFFFFF" /><a:midPointStop
+ offset="0.6235"
+ style="stop-color:#FFFFFF" /><a:midPointStop
+ offset="1"
+ style="stop-color:#F2F7E8" /></radialGradient><circle
+ fill="url(#SVGID_14_)"
+ cx="247.374"
+ cy="233.37"
+ r="2.999"
+ id="circle241" /></g></g></g></g><path
+ d="m 529.664,248.155 h 18.498 l -2.809,18.064 h 5.59 37.586 l 2.6,-17.718 c 4.98,-1.091 9.133,-3.455 12.512,-6.693 3.084,4.075 8.566,7.37 18.252,7.37 6.338,0 12.775,-1.807 17.174,-3.687 4.254,2.399 9.463,3.687 15.459,3.687 3.088,0 6.236,-0.355 9.426,-1.023 h 67.135 l 3.354,-24.827 -5.445,-0.764 1.879,-13.356 c 0.371,-2.386 0.449,-4.66 0.449,-6.156 l -0.008,-0.375 c -0.457,-12.191 -8.139,-19.765 -20.045,-19.765 -2.404,0 -4.623,0.314 -6.676,0.852 h -34.189 l -0.035,0.244 c -2.527,-0.701 -5.41,-1.096 -8.686,-1.096 -3.801,0 -7.406,0.555 -10.76,1.598 l 0.105,-0.746 h -12.467 l 1.826,-12.951 H 613.08 l -1.846,7.658 c -1.373,5.704 -2.213,5.793 -4.453,6.03 l -4.508,0.477 c -3.049,-1.424 -6.357,-2.065 -9.602,-2.065 -2.135,0 -4.275,0.284 -6.416,0.852 h -19.291 c 0.502,-1.772 0.775,-3.674 0.775,-5.678 0,-9.601 -6.846,-16.305 -16.646,-16.305 -11.055,0 -18.775,7.721 -18.775,18.776 0,0.951 0.082,1.869 0.219,2.764 -2.135,-0.288 -4.277,-0.409 -5.553,-0.409 -2.053,0 -4.072,0.288 -6.045,0.852 h -31.342 c -2.74,-0.553 -5.641,-0.852 -8.537,-0.852 -7.138,0 -13.492,1.674 -18.808,4.723 l -3.451,-1.461 c -3.711,-1.571 -11.232,-3.262 -18.979,-3.262 -8.933,0 -16.383,2.56 -21.576,7.016 -3.265,-4.473 -8.523,-7.016 -15.228,-7.016 -4.822,0 -9.021,1.477 -12.572,3.44 -2.996,-2.204 -6.796,-3.44 -11.115,-3.44 -2.327,0 -4.48,0.315 -6.476,0.852 h -33.963 l -0.035,0.245 c -2.526,-0.702 -5.41,-1.097 -8.687,-1.097 -20.458,0 -35.307,16.031 -35.307,38.117 0,17.363 10.785,28.149 28.148,28.149 3.087,0 6.236,-0.356 9.426,-1.023 h 88.816 c 3.706,0.676 7.669,1.023 11.154,1.023 8.907,0 16.278,-2.375 21.51,-6.593 4.872,4.252 11.585,6.593 19.728,6.593 3.053,0 6.206,-0.368 9.286,-1.023 h 44.664 2.069 z"
+ id="path243"
+ inkscape:connector-curvature="0"
+ style="fill:#f5f5f5" /><g
+ id="g245"
+ transform="translate(0,16)"><g
+ id="g247"><path
+ d="m 340.308,218.463 c -5.538,2.556 -11.588,4.26 -17.638,4.26 -13.377,0 -18.148,-7.839 -18.148,-18.148 0,-17.893 11.418,-28.117 25.307,-28.117 9.372,0 13.973,4.26 13.973,11.247 0,12.184 -12.865,15.763 -26.157,17.126 0.255,4.346 2.045,8.35 8.435,8.35 3.068,0 7.243,-0.937 12.355,-3.067 l 1.873,8.349 z m -8.095,-29.567 c 0,-2.045 -1.448,-3.237 -4.09,-3.237 -4.771,0 -8.69,4.175 -9.969,10.906 3.664,-0.511 14.059,-2.3 14.059,-7.669 z"
+ id="path249"
+ inkscape:connector-curvature="0"
+ style="fill:#383838" /><path
+ d="m 394.07,221.7 -0.171,-0.255 1.789,-10.055 2.642,-18.063 c 0.512,-3.749 0.341,-5.623 -1.96,-5.623 -2.642,0 -5.794,2.727 -9.372,5.879 l -2.727,19.512 c -0.171,1.363 -0.171,1.534 1.022,1.704 l 4.26,0.597 -0.852,6.305 h -18.404 l -0.171,-0.341 1.875,-10.82 2.471,-17.212 c 0.512,-3.237 0.682,-5.453 -1.789,-5.453 -3.238,0 -7.413,3.664 -9.714,5.709 l -2.642,19.512 c -0.17,1.363 -0.17,1.534 1.108,1.704 l 4.26,0.597 -0.852,6.305 h -23.347 l 0.853,-6.39 3.749,-0.512 c 1.107,-0.17 1.363,-0.426 1.533,-1.704 l 3.579,-25.987 c 0.17,-0.938 0,-1.534 -0.767,-1.789 l -4.176,-1.534 0.938,-6.476 h 16.871 l -0.938,6.987 0.256,0.085 c 4.43,-3.749 9.116,-7.924 15.592,-7.924 4.687,0 7.839,2.641 8.18,7.753 l 0.256,0.086 c 4.175,-3.664 9.202,-7.839 15.252,-7.839 6.22,0 8.775,3.152 8.946,9.202 0,1.618 -0.171,3.493 -0.426,5.538 l -3.067,21.897 c -0.171,1.363 -0.171,1.534 1.107,1.704 l 4.175,0.597 -0.852,6.305 H 394.07 z"
+ id="path251"
+ inkscape:connector-curvature="0"
+ style="fill:#383838" /><path
+ d="m 443.995,190.771 -0.17,-4.431 c 0,-0.682 -0.085,-1.108 -1.022,-1.363 -1.022,-0.256 -2.642,-0.427 -4.771,-0.427 -3.579,0 -6.391,1.108 -6.391,4.09 0,2.727 2.982,3.749 6.731,5.027 6.05,2.045 13.888,4.431 13.888,13.463 0,11.076 -9.372,15.592 -20.193,15.592 -8.009,0 -14.91,-1.959 -16.273,-2.981 l 1.618,-12.355 8.691,0.512 0.255,4.941 c 0,0.597 0.171,1.108 0.938,1.363 1.278,0.427 3.238,0.768 6.05,0.768 4.687,0 7.327,-1.79 7.327,-4.687 0,-3.408 -3.152,-4.175 -8.009,-5.624 -6.135,-1.874 -12.78,-4.26 -12.78,-13.206 0,-10.48 9.116,-14.996 19.597,-14.996 6.646,0 12.866,1.533 15.081,2.471 l -1.704,12.354 -8.863,-0.511 z"
+ id="path253"
+ inkscape:connector-curvature="0"
+ style="fill:#383838" /><path
+ d="m 489.748,218.548 c -4.175,2.386 -10.395,4.175 -16.444,4.175 -13.036,0 -18.575,-7.583 -18.575,-18.574 0,-18.83 11.588,-27.691 25.988,-27.691 6.475,0 11.843,1.874 14.229,3.578 l -1.874,13.377 -8.691,-0.426 -0.255,-5.794 c 0,-0.597 -0.086,-0.938 -0.597,-1.192 -1.022,-0.427 -2.557,-0.597 -4.175,-0.597 -5.624,0 -11.418,4.601 -11.418,17.382 0,7.839 3.493,10.395 8.436,10.395 4.346,0 8.436,-1.448 11.247,-2.556 l 2.129,7.923 z"
+ id="path255"
+ inkscape:connector-curvature="0"
+ style="fill:#383838" /><path
+ d="m 491.364,221.7 0.853,-6.39 3.919,-0.512 c 1.193,-0.17 1.363,-0.426 1.534,-1.704 l 3.578,-25.987 c 0.086,-0.938 -0.085,-1.534 -0.852,-1.789 l -4.261,-1.534 0.938,-6.476 h 16.87 l -1.107,7.669 0.256,0.17 c 3.323,-4.771 8.095,-8.69 13.548,-8.69 1.874,0 5.112,0.341 6.561,0.767 l -2.13,15.507 -9.969,-0.341 -0.256,-4.431 c -0.086,-0.767 -0.256,-1.022 -0.938,-1.022 -1.619,0 -4.26,1.96 -6.646,4.431 l -2.981,21.643 c -0.171,1.363 -0.085,1.619 1.192,1.704 l 8.095,0.682 -0.938,6.305 h -27.266 z"
+ id="path257"
+ inkscape:connector-curvature="0"
+ style="fill:#383838" /><path
+ d="m 536.094,221.7 -0.17,-0.426 2.045,-11.503 3.152,-22.749 c 0.17,-0.938 -0.086,-1.534 -0.853,-1.79 l -4.175,-1.448 0.852,-6.476 h 18.149 l -5.027,35.786 c -0.171,1.363 -0.085,1.534 1.192,1.704 l 4.09,0.597 -0.852,6.305 h -18.403 z m 5.879,-57.598 c 0,-5.453 3.238,-8.775 8.776,-8.775 4.175,0 6.646,2.215 6.646,6.305 0,5.368 -3.322,8.861 -8.861,8.861 -4.176,-0.001 -6.561,-2.387 -6.561,-6.391 z"
+ id="path259"
+ inkscape:connector-curvature="0"
+ style="fill:#383838" /><path
+ d="m 556.796,239.764 -0.17,-0.341 2.471,-14.229 5.282,-38.087 c 0.171,-1.022 -0.085,-1.534 -0.767,-1.789 l -4.175,-1.534 0.938,-6.476 h 17.041 l -1.022,6.816 0.255,0.085 c 5.027,-4.686 10.311,-7.753 15.678,-7.753 7.328,0 12.44,4.686 12.44,17.041 0,11.758 -4.601,29.225 -20.449,29.225 -5.538,0 -8.605,-2.13 -11.759,-4.345 l -1.874,12.78 c -0.085,0.938 0.085,1.278 1.192,1.363 l 8.606,0.853 -0.938,6.39 h -22.749 z m 17.041,-30.247 c 2.13,1.789 4.942,3.322 8.095,3.322 6.901,0 9.458,-9.713 9.458,-17.211 0,-5.027 -1.193,-8.351 -4.431,-8.351 -3.408,0 -7.754,3.664 -10.821,6.391 l -2.301,15.849 z"
+ id="path261"
+ inkscape:connector-curvature="0"
+ style="fill:#383838" /><path
+ d="m 635.777,219.4 c -3.749,1.789 -9.458,3.322 -14.229,3.322 -8.521,0 -12.099,-2.981 -12.099,-9.969 0,-1.107 0.085,-2.386 0.256,-3.749 l 3.066,-22.323 c 0.086,-0.512 0.086,-0.853 -0.511,-0.853 h -5.879 l 1.107,-7.839 c 7.242,-0.767 10.906,-4.431 13.122,-13.633 h 7.924 l -1.704,12.1 c -0.085,0.596 -0.085,0.852 0.597,0.852 h 11.758 l -1.193,8.521 h -12.439 l -2.812,20.364 c -0.171,1.107 -0.256,1.96 -0.256,2.727 0,2.982 1.278,4.26 4.942,4.26 2.385,0 4.771,-0.596 6.816,-1.363 l 1.534,7.583 z"
+ id="path263"
+ inkscape:connector-curvature="0"
+ style="fill:#383838" /><path
+ d="m 671.817,218.463 c -5.538,2.556 -11.588,4.26 -17.638,4.26 -13.377,0 -18.148,-7.839 -18.148,-18.148 0,-17.893 11.418,-28.117 25.307,-28.117 9.372,0 13.973,4.26 13.973,11.247 0,12.184 -12.865,15.763 -26.157,17.126 0.255,4.346 2.045,8.35 8.435,8.35 3.068,0 7.243,-0.937 12.355,-3.067 l 1.873,8.349 z m -8.094,-29.567 c 0,-2.045 -1.448,-3.237 -4.09,-3.237 -4.771,0 -8.69,4.175 -9.969,10.906 3.664,-0.511 14.059,-2.3 14.059,-7.669 z"
+ id="path265"
+ inkscape:connector-curvature="0"
+ style="fill:#383838" /><path
+ d="m 703.596,221.7 -0.17,-0.255 1.874,-10.396 2.471,-17.723 c 0.512,-3.578 0.341,-5.879 -2.215,-5.879 -3.664,0 -8.18,3.578 -11.077,6.135 l -2.641,19.512 c -0.171,1.363 -0.171,1.534 1.107,1.704 l 4.26,0.597 -0.852,6.305 h -23.347 l 0.853,-6.39 3.749,-0.512 c 1.107,-0.17 1.363,-0.426 1.533,-1.704 l 3.579,-25.987 c 0.17,-0.938 0,-1.534 -0.768,-1.789 l -4.175,-1.534 0.938,-6.476 h 16.87 l -0.937,6.987 0.255,0.085 c 4.771,-4.09 9.373,-7.924 16.02,-7.924 6.475,0 9.798,3.322 10.054,10.139 0,1.363 -0.085,3.067 -0.341,4.687 l -3.067,21.812 c -0.171,1.363 -0.171,1.534 1.022,1.704 l 4.26,0.597 L 722,221.7 h -18.404 z"
+ id="path267"
+ inkscape:connector-curvature="0"
+ style="fill:#383838" /></g><g
+ id="g269"><linearGradient
+ id="SVGID_15_"
+ gradientUnits="userSpaceOnUse"
+ x1="324.1611"
+ y1="239.7637"
+ x2="324.1611"
+ y2="155.3275"><stop
+ offset="0"
+ style="stop-color:#000000"
+ id="stop272" /><stop
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0"
+ id="stop274" /><a:midPointStop
+ offset="0"
+ style="stop-color:#000000" /><a:midPointStop
+ offset="0.6933"
+ style="stop-color:#000000" /><a:midPointStop
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0" /></linearGradient><path
+ d="m 340.308,218.463 c -5.538,2.556 -11.588,4.26 -17.638,4.26 -13.377,0 -18.148,-7.839 -18.148,-18.148 0,-17.893 11.418,-28.117 25.307,-28.117 9.372,0 13.973,4.26 13.973,11.247 0,12.184 -12.865,15.763 -26.157,17.126 0.255,4.346 2.045,8.35 8.435,8.35 3.068,0 7.243,-0.937 12.355,-3.067 l 1.873,8.349 z m -8.095,-29.567 c 0,-2.045 -1.448,-3.237 -4.09,-3.237 -4.771,0 -8.69,4.175 -9.969,10.906 3.664,-0.511 14.059,-2.3 14.059,-7.669 z"
+ id="path276"
+ style="fill:url(#SVGID_15_)"
+ inkscape:connector-curvature="0" /><linearGradient
+ id="SVGID_16_"
+ gradientUnits="userSpaceOnUse"
+ x1="377.45459"
+ y1="239.7637"
+ x2="377.45459"
+ y2="155.3277"><stop
+ offset="0"
+ style="stop-color:#000000"
+ id="stop279" /><stop
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0"
+ id="stop281" /><a:midPointStop
+ offset="0"
+ style="stop-color:#000000" /><a:midPointStop
+ offset="0.6933"
+ style="stop-color:#000000" /><a:midPointStop
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0" /></linearGradient><path
+ d="m 394.07,221.7 -0.171,-0.255 1.789,-10.055 2.642,-18.063 c 0.512,-3.749 0.341,-5.623 -1.96,-5.623 -2.642,0 -5.794,2.727 -9.372,5.879 l -2.727,19.512 c -0.171,1.363 -0.171,1.534 1.022,1.704 l 4.26,0.597 -0.852,6.305 h -18.404 l -0.171,-0.341 1.875,-10.82 2.471,-17.212 c 0.512,-3.237 0.682,-5.453 -1.789,-5.453 -3.238,0 -7.413,3.664 -9.714,5.709 l -2.642,19.512 c -0.17,1.363 -0.17,1.534 1.108,1.704 l 4.26,0.597 -0.852,6.305 h -23.347 l 0.853,-6.39 3.749,-0.512 c 1.107,-0.17 1.363,-0.426 1.533,-1.704 l 3.579,-25.987 c 0.17,-0.938 0,-1.534 -0.767,-1.789 l -4.176,-1.534 0.938,-6.476 h 16.871 l -0.938,6.987 0.256,0.085 c 4.43,-3.749 9.116,-7.924 15.592,-7.924 4.687,0 7.839,2.641 8.18,7.753 l 0.256,0.086 c 4.175,-3.664 9.202,-7.839 15.252,-7.839 6.22,0 8.775,3.152 8.946,9.202 0,1.618 -0.171,3.493 -0.426,5.538 l -3.067,21.897 c -0.171,1.363 -0.171,1.534 1.107,1.704 l 4.175,0.597 -0.852,6.305 H 394.07 z"
+ id="path283"
+ style="fill:url(#SVGID_16_)"
+ inkscape:connector-curvature="0" /><linearGradient
+ id="SVGID_17_"
+ gradientUnits="userSpaceOnUse"
+ x1="435.17719"
+ y1="239.7637"
+ x2="435.17719"
+ y2="155.3275"><stop
+ offset="0"
+ style="stop-color:#000000"
+ id="stop286" /><stop
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0"
+ id="stop288" /><a:midPointStop
+ offset="0"
+ style="stop-color:#000000" /><a:midPointStop
+ offset="0.6933"
+ style="stop-color:#000000" /><a:midPointStop
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0" /></linearGradient><path
+ d="m 443.995,190.771 -0.17,-4.431 c 0,-0.682 -0.085,-1.108 -1.022,-1.363 -1.022,-0.256 -2.642,-0.427 -4.771,-0.427 -3.579,0 -6.391,1.108 -6.391,4.09 0,2.727 2.982,3.749 6.731,5.027 6.05,2.045 13.888,4.431 13.888,13.463 0,11.076 -9.372,15.592 -20.193,15.592 -8.009,0 -14.91,-1.959 -16.273,-2.981 l 1.618,-12.355 8.691,0.512 0.255,4.941 c 0,0.597 0.171,1.108 0.938,1.363 1.278,0.427 3.238,0.768 6.05,0.768 4.687,0 7.327,-1.79 7.327,-4.687 0,-3.408 -3.152,-4.175 -8.009,-5.624 -6.135,-1.874 -12.78,-4.26 -12.78,-13.206 0,-10.48 9.116,-14.996 19.597,-14.996 6.646,0 12.866,1.533 15.081,2.471 l -1.704,12.354 -8.863,-0.511 z"
+ id="path290"
+ style="fill:url(#SVGID_17_)"
+ inkscape:connector-curvature="0" /><linearGradient
+ id="SVGID_18_"
+ gradientUnits="userSpaceOnUse"
+ x1="474.83691"
+ y1="239.7637"
+ x2="474.83691"
+ y2="155.3275"><stop
+ offset="0"
+ style="stop-color:#000000"
+ id="stop293" /><stop
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0"
+ id="stop295" /><a:midPointStop
+ offset="0"
+ style="stop-color:#000000" /><a:midPointStop
+ offset="0.6933"
+ style="stop-color:#000000" /><a:midPointStop
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0" /></linearGradient><path
+ d="m 489.748,218.548 c -4.175,2.386 -10.395,4.175 -16.444,4.175 -13.036,0 -18.575,-7.583 -18.575,-18.574 0,-18.83 11.588,-27.691 25.988,-27.691 6.475,0 11.843,1.874 14.229,3.578 l -1.874,13.377 -8.691,-0.426 -0.255,-5.794 c 0,-0.597 -0.086,-0.938 -0.597,-1.192 -1.022,-0.427 -2.557,-0.597 -4.175,-0.597 -5.624,0 -11.418,4.601 -11.418,17.382 0,7.839 3.493,10.395 8.436,10.395 4.346,0 8.436,-1.448 11.247,-2.556 l 2.129,7.923 z"
+ id="path297"
+ style="fill:url(#SVGID_18_)"
+ inkscape:connector-curvature="0" /><linearGradient
+ id="SVGID_19_"
+ gradientUnits="userSpaceOnUse"
+ x1="512.28223"
+ y1="239.7637"
+ x2="512.28223"
+ y2="155.3277"><stop
+ offset="0"
+ style="stop-color:#000000"
+ id="stop300" /><stop
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0"
+ id="stop302" /><a:midPointStop
+ offset="0"
+ style="stop-color:#000000" /><a:midPointStop
+ offset="0.6933"
+ style="stop-color:#000000" /><a:midPointStop
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0" /></linearGradient><path
+ d="m 491.364,221.7 0.853,-6.39 3.919,-0.512 c 1.193,-0.17 1.363,-0.426 1.534,-1.704 l 3.578,-25.987 c 0.086,-0.938 -0.085,-1.534 -0.852,-1.789 l -4.261,-1.534 0.938,-6.476 h 16.87 l -1.107,7.669 0.256,0.17 c 3.323,-4.771 8.095,-8.69 13.548,-8.69 1.874,0 5.112,0.341 6.561,0.767 l -2.13,15.507 -9.969,-0.341 -0.256,-4.431 c -0.086,-0.767 -0.256,-1.022 -0.938,-1.022 -1.619,0 -4.26,1.96 -6.646,4.431 l -2.981,21.643 c -0.171,1.363 -0.085,1.619 1.192,1.704 l 8.095,0.682 -0.938,6.305 h -27.266 z"
+ id="path304"
+ style="fill:url(#SVGID_19_)"
+ inkscape:connector-curvature="0" /><linearGradient
+ id="SVGID_20_"
+ gradientUnits="userSpaceOnUse"
+ x1="546.65918"
+ y1="239.7637"
+ x2="546.65918"
+ y2="155.32719"><stop
+ offset="0"
+ style="stop-color:#000000"
+ id="stop307" /><stop
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0"
+ id="stop309" /><a:midPointStop
+ offset="0"
+ style="stop-color:#000000" /><a:midPointStop
+ offset="0.6933"
+ style="stop-color:#000000" /><a:midPointStop
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0" /></linearGradient><path
+ d="m 536.094,221.7 -0.17,-0.426 2.045,-11.503 3.152,-22.749 c 0.17,-0.938 -0.086,-1.534 -0.853,-1.79 l -4.175,-1.448 0.852,-6.476 h 18.149 l -5.027,35.786 c -0.171,1.363 -0.085,1.534 1.192,1.704 l 4.09,0.597 -0.852,6.305 h -18.403 z m 5.879,-57.598 c 0,-5.453 3.238,-8.775 8.776,-8.775 4.175,0 6.646,2.215 6.646,6.305 0,5.368 -3.322,8.861 -8.861,8.861 -4.176,-0.001 -6.561,-2.387 -6.561,-6.391 z"
+ id="path311"
+ style="fill:url(#SVGID_20_)"
+ inkscape:connector-curvature="0" /><linearGradient
+ id="SVGID_21_"
+ gradientUnits="userSpaceOnUse"
+ x1="580.69629"
+ y1="239.7637"
+ x2="580.69629"
+ y2="155.32719"><stop
+ offset="0"
+ style="stop-color:#000000"
+ id="stop314" /><stop
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0"
+ id="stop316" /><a:midPointStop
+ offset="0"
+ style="stop-color:#000000" /><a:midPointStop
+ offset="0.6933"
+ style="stop-color:#000000" /><a:midPointStop
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0" /></linearGradient><path
+ d="m 556.796,239.764 -0.17,-0.341 2.471,-14.229 5.282,-38.087 c 0.171,-1.022 -0.085,-1.534 -0.767,-1.789 l -4.175,-1.534 0.938,-6.476 h 17.041 l -1.022,6.816 0.255,0.085 c 5.027,-4.686 10.311,-7.753 15.678,-7.753 7.328,0 12.44,4.686 12.44,17.041 0,11.758 -4.601,29.225 -20.449,29.225 -5.538,0 -8.605,-2.13 -11.759,-4.345 l -1.874,12.78 c -0.085,0.938 0.085,1.278 1.192,1.363 l 8.606,0.853 -0.938,6.39 h -22.749 z m 17.041,-30.247 c 2.13,1.789 4.942,3.322 8.095,3.322 6.901,0 9.458,-9.713 9.458,-17.211 0,-5.027 -1.193,-8.351 -4.431,-8.351 -3.408,0 -7.754,3.664 -10.821,6.391 l -2.301,15.849 z"
+ id="path318"
+ style="fill:url(#SVGID_21_)"
+ inkscape:connector-curvature="0" /><linearGradient
+ id="SVGID_22_"
+ gradientUnits="userSpaceOnUse"
+ x1="622.7832"
+ y1="239.7637"
+ x2="622.7832"
+ y2="155.3268"><stop
+ offset="0"
+ style="stop-color:#000000"
+ id="stop321" /><stop
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0"
+ id="stop323" /><a:midPointStop
+ offset="0"
+ style="stop-color:#000000" /><a:midPointStop
+ offset="0.6933"
+ style="stop-color:#000000" /><a:midPointStop
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0" /></linearGradient><path
+ d="m 635.777,219.4 c -3.749,1.789 -9.458,3.322 -14.229,3.322 -8.521,0 -12.099,-2.981 -12.099,-9.969 0,-1.107 0.085,-2.386 0.256,-3.749 l 3.066,-22.323 c 0.086,-0.512 0.086,-0.853 -0.511,-0.853 h -5.879 l 1.107,-7.839 c 7.242,-0.767 10.906,-4.431 13.122,-13.633 h 7.924 l -1.704,12.1 c -0.085,0.596 -0.085,0.852 0.597,0.852 h 11.758 l -1.193,8.521 h -12.439 l -2.812,20.364 c -0.171,1.107 -0.256,1.96 -0.256,2.727 0,2.982 1.278,4.26 4.942,4.26 2.385,0 4.771,-0.596 6.816,-1.363 l 1.534,7.583 z"
+ id="path325"
+ style="fill:url(#SVGID_22_)"
+ inkscape:connector-curvature="0" /><linearGradient
+ id="SVGID_23_"
+ gradientUnits="userSpaceOnUse"
+ x1="655.6709"
+ y1="239.7637"
+ x2="655.6709"
+ y2="155.3275"><stop
+ offset="0"
+ style="stop-color:#000000"
+ id="stop328" /><stop
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0"
+ id="stop330" /><a:midPointStop
+ offset="0"
+ style="stop-color:#000000" /><a:midPointStop
+ offset="0.6933"
+ style="stop-color:#000000" /><a:midPointStop
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0" /></linearGradient><path
+ d="m 671.817,218.463 c -5.538,2.556 -11.588,4.26 -17.638,4.26 -13.377,0 -18.148,-7.839 -18.148,-18.148 0,-17.893 11.418,-28.117 25.307,-28.117 9.372,0 13.973,4.26 13.973,11.247 0,12.184 -12.865,15.763 -26.157,17.126 0.255,4.346 2.045,8.35 8.435,8.35 3.068,0 7.243,-0.937 12.355,-3.067 l 1.873,8.349 z m -8.094,-29.567 c 0,-2.045 -1.448,-3.237 -4.09,-3.237 -4.771,0 -8.69,4.175 -9.969,10.906 3.664,-0.511 14.059,-2.3 14.059,-7.669 z"
+ id="path332"
+ style="fill:url(#SVGID_23_)"
+ inkscape:connector-curvature="0" /><linearGradient
+ id="SVGID_24_"
+ gradientUnits="userSpaceOnUse"
+ x1="697.92969"
+ y1="239.7637"
+ x2="697.92969"
+ y2="155.3277"><stop
+ offset="0"
+ style="stop-color:#000000"
+ id="stop335" /><stop
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0"
+ id="stop337" /><a:midPointStop
+ offset="0"
+ style="stop-color:#000000" /><a:midPointStop
+ offset="0.6933"
+ style="stop-color:#000000" /><a:midPointStop
+ offset="1"
+ style="stop-color:#000000;stop-opacity:0" /></linearGradient><path
+ d="m 703.596,221.7 -0.17,-0.255 1.874,-10.396 2.471,-17.723 c 0.512,-3.578 0.341,-5.879 -2.215,-5.879 -3.664,0 -8.18,3.578 -11.077,6.135 l -2.641,19.512 c -0.171,1.363 -0.171,1.534 1.107,1.704 l 4.26,0.597 -0.852,6.305 h -23.347 l 0.853,-6.39 3.749,-0.512 c 1.107,-0.17 1.363,-0.426 1.533,-1.704 l 3.579,-25.987 c 0.17,-0.938 0,-1.534 -0.768,-1.789 l -4.175,-1.534 0.938,-6.476 h 16.87 l -0.937,6.987 0.255,0.085 c 4.771,-4.09 9.373,-7.924 16.02,-7.924 6.475,0 9.798,3.322 10.054,10.139 0,1.363 -0.085,3.067 -0.341,4.687 l -3.067,21.812 c -0.171,1.363 -0.171,1.534 1.022,1.704 l 4.26,0.597 L 722,221.7 h -18.404 z"
+ id="path339"
+ style="fill:url(#SVGID_24_)"
+ inkscape:connector-curvature="0" /></g></g><g
+ id="g4141"
+ transform="matrix(0.81856441,0,0,0.81856441,79.234731,-94.128741)"><g
+ id="g4143"></g><g
+ id="g4165"><linearGradient
+ y2="155.3275"
+ x2="324.1611"
+ y1="239.7637"
+ x1="324.1611"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4167"><stop
+ id="stop4169"
+ style="stop-color:#000000"
+ offset="0" /><stop
+ id="stop4171"
+ style="stop-color:#000000;stop-opacity:0"
+ offset="1" /><a:midPointStop
+ style="stop-color:#000000"
+ offset="0" /><a:midPointStop
+ style="stop-color:#000000"
+ offset="0.6933" /><a:midPointStop
+ style="stop-color:#000000;stop-opacity:0"
+ offset="1" /></linearGradient><linearGradient
+ y2="155.3277"
+ x2="377.45459"
+ y1="239.7637"
+ x1="377.45459"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4175"><stop
+ id="stop4177"
+ style="stop-color:#000000"
+ offset="0" /><stop
+ id="stop4179"
+ style="stop-color:#000000;stop-opacity:0"
+ offset="1" /><a:midPointStop
+ style="stop-color:#000000"
+ offset="0" /><a:midPointStop
+ style="stop-color:#000000"
+ offset="0.6933" /><a:midPointStop
+ style="stop-color:#000000;stop-opacity:0"
+ offset="1" /></linearGradient><linearGradient
+ y2="155.3275"
+ x2="435.17719"
+ y1="239.7637"
+ x1="435.17719"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4183"><stop
+ id="stop4185"
+ style="stop-color:#000000"
+ offset="0" /><stop
+ id="stop4187"
+ style="stop-color:#000000;stop-opacity:0"
+ offset="1" /><a:midPointStop
+ style="stop-color:#000000"
+ offset="0" /><a:midPointStop
+ style="stop-color:#000000"
+ offset="0.6933" /><a:midPointStop
+ style="stop-color:#000000;stop-opacity:0"
+ offset="1" /></linearGradient><linearGradient
+ y2="155.3275"
+ x2="474.83691"
+ y1="239.7637"
+ x1="474.83691"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4191"><stop
+ id="stop4193"
+ style="stop-color:#000000"
+ offset="0" /><stop
+ id="stop4195"
+ style="stop-color:#000000;stop-opacity:0"
+ offset="1" /><a:midPointStop
+ style="stop-color:#000000"
+ offset="0" /><a:midPointStop
+ style="stop-color:#000000"
+ offset="0.6933" /><a:midPointStop
+ style="stop-color:#000000;stop-opacity:0"
+ offset="1" /></linearGradient><linearGradient
+ y2="155.3277"
+ x2="512.28223"
+ y1="239.7637"
+ x1="512.28223"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4199"><stop
+ id="stop4201"
+ style="stop-color:#000000"
+ offset="0" /><stop
+ id="stop4203"
+ style="stop-color:#000000;stop-opacity:0"
+ offset="1" /><a:midPointStop
+ style="stop-color:#000000"
+ offset="0" /><a:midPointStop
+ style="stop-color:#000000"
+ offset="0.6933" /><a:midPointStop
+ style="stop-color:#000000;stop-opacity:0"
+ offset="1" /></linearGradient><linearGradient
+ y2="155.32719"
+ x2="546.65918"
+ y1="239.7637"
+ x1="546.65918"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4207"><stop
+ id="stop4209"
+ style="stop-color:#000000"
+ offset="0" /><stop
+ id="stop4211"
+ style="stop-color:#000000;stop-opacity:0"
+ offset="1" /><a:midPointStop
+ style="stop-color:#000000"
+ offset="0" /><a:midPointStop
+ style="stop-color:#000000"
+ offset="0.6933" /><a:midPointStop
+ style="stop-color:#000000;stop-opacity:0"
+ offset="1" /></linearGradient><linearGradient
+ y2="155.32719"
+ x2="580.69629"
+ y1="239.7637"
+ x1="580.69629"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4215"><stop
+ id="stop4217"
+ style="stop-color:#000000"
+ offset="0" /><stop
+ id="stop4219"
+ style="stop-color:#000000;stop-opacity:0"
+ offset="1" /><a:midPointStop
+ style="stop-color:#000000"
+ offset="0" /><a:midPointStop
+ style="stop-color:#000000"
+ offset="0.6933" /><a:midPointStop
+ style="stop-color:#000000;stop-opacity:0"
+ offset="1" /></linearGradient><linearGradient
+ y2="155.3268"
+ x2="622.7832"
+ y1="239.7637"
+ x1="622.7832"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4223"><stop
+ id="stop4225"
+ style="stop-color:#000000"
+ offset="0" /><stop
+ id="stop4227"
+ style="stop-color:#000000;stop-opacity:0"
+ offset="1" /><a:midPointStop
+ style="stop-color:#000000"
+ offset="0" /><a:midPointStop
+ style="stop-color:#000000"
+ offset="0.6933" /><a:midPointStop
+ style="stop-color:#000000;stop-opacity:0"
+ offset="1" /></linearGradient><linearGradient
+ y2="155.3275"
+ x2="655.6709"
+ y1="239.7637"
+ x1="655.6709"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4231"><stop
+ id="stop4233"
+ style="stop-color:#000000"
+ offset="0" /><stop
+ id="stop4235"
+ style="stop-color:#000000;stop-opacity:0"
+ offset="1" /><a:midPointStop
+ style="stop-color:#000000"
+ offset="0" /><a:midPointStop
+ style="stop-color:#000000"
+ offset="0.6933" /><a:midPointStop
+ style="stop-color:#000000;stop-opacity:0"
+ offset="1" /></linearGradient><linearGradient
+ y2="155.3277"
+ x2="697.92969"
+ y1="239.7637"
+ x1="697.92969"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4239"><stop
+ id="stop4241"
+ style="stop-color:#000000"
+ offset="0" /><stop
+ id="stop4243"
+ style="stop-color:#000000;stop-opacity:0"
+ offset="1" /><a:midPointStop
+ style="stop-color:#000000"
+ offset="0" /><a:midPointStop
+ style="stop-color:#000000"
+ offset="0.6933" /><a:midPointStop
+ style="stop-color:#000000;stop-opacity:0"
+ offset="1" /></linearGradient></g></g></svg>
+ </a>
+
+ <div class="spinner" id='spinner'></div>
+ <div class="emscripten" id="status">Downloading...</div>
+
+<span id='controls'>
+ <span><input type="checkbox" id="resize">Resize canvas</span>
+ <span><input type="checkbox" id="pointerLock" checked>Lock/hide mouse pointer &nbsp;&nbsp;&nbsp;</span>
+ <span><input type="button" value="Fullscreen" onclick="Module.requestFullScreen(document.getElementById('pointerLock').checked,
+ document.getElementById('resize').checked)">
+ </span>
+</span>
+
+ <div class="emscripten">
+ <progress value="0" max="100" id="progress" hidden=1></progress>
+ </div>
+
+
+ <div class="emscripten_border">
+ <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
+ </div>
+ <textarea id="output" rows="8"></textarea>
+
+ <script type='text/javascript'>
+ var statusElement = document.getElementById('status');
+ var progressElement = document.getElementById('progress');
+ var spinnerElement = document.getElementById('spinner');
+
+ var Module = {
+ TOTAL_MEMORY: $GODOTTMEM,
+ preRun: [],
+ postRun: [],
+ print: (function() {
+ var element = document.getElementById('output');
+ if (element) element.value = ''; // clear browser cache
+ return function(text) {
+ if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
+ // These replacements are necessary if you render to raw HTML
+ //text = text.replace(/&/g, "&amp;");
+ //text = text.replace(/</g, "&lt;");
+ //text = text.replace(/>/g, "&gt;");
+ //text = text.replace('\n', '<br>', 'g');
+ console.log(text);
+ if (element) {
+ element.value += text + "\n";
+ element.scrollTop = element.scrollHeight; // focus on bottom
+ }
+ };
+ })(),
+ printErr: function(text) {
+ if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
+ if (0) { // XXX disabled for safety typeof dump == 'function') {
+ dump(text + '\n'); // fast, straight to the real console
+ } else {
+ console.error(text);
+ }
+ },
+ canvas: (function() {
+ var canvas = document.getElementById('canvas');
+
+ // As a default initial behavior, pop up an alert when webgl context is lost. To make your
+ // application robust, you may want to override this behavior before shipping!
+ // See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
+ canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);
+
+ return canvas;
+ })(),
+ setStatus: function(text) {
+ if (!Module.setStatus.last) Module.setStatus.last = { time: Date.now(), text: '' };
+ if (text === Module.setStatus.text) return;
+ var m = text.match(/([^(]+)\((\d+(\.\d+)?)\/(\d+)\)/);
+ var now = Date.now();
+ if (m && now - Date.now() < 30) return; // if this is a progress update, skip it if too soon
+ if (m) {
+ text = m[1];
+ progressElement.value = parseInt(m[2])*100;
+ progressElement.max = parseInt(m[4])*100;
+ progressElement.hidden = false;
+ spinnerElement.hidden = false;
+ } else {
+ progressElement.value = null;
+ progressElement.max = null;
+ progressElement.hidden = true;
+ if (!text) spinnerElement.style.display = 'none';
+ }
+ statusElement.innerHTML = text;
+ },
+ totalDependencies: 0,
+ monitorRunDependencies: function(left) {
+ this.totalDependencies = Math.max(this.totalDependencies, left);
+ Module.setStatus(left ? 'Preparing... (' + (this.totalDependencies-left) + '/' + this.totalDependencies + ')' : 'All downloads complete.');
+ }
+ };
+ Module.setStatus('Downloading...');
+ window.onerror = function(event) {
+ // TODO: do not warn on ok events like simulating an infinite loop or exitStatus
+ Module.setStatus('Exception thrown, see JavaScript console');
+ spinnerElement.style.display = 'none';
+ Module.setStatus = function(text) {
+ if (text) Module.printErr('[post-exception status] ' + text);
+ };
+ };
+ </script>
+ <script type="text/javascript" src="$GODOTFS"></script>
+ <script>
+
+ (function() {
+ var memoryInitializer = '$GODOTMEM';
+ if (typeof Module['locateFile'] === 'function') {
+ memoryInitializer = Module['locateFile'](memoryInitializer);
+ } else if (Module['memoryInitializerPrefixURL']) {
+ memoryInitializer = Module['memoryInitializerPrefixURL'] + memoryInitializer;
+ }
+ var xhr = Module['memoryInitializerRequest'] = new XMLHttpRequest();
+ xhr.open('GET', memoryInitializer, true);
+ xhr.responseType = 'arraybuffer';
+ xhr.send(null);
+ })();
+
+ var script = document.createElement('script');
+ script.src = "$GODOTJS";
+ document.body.appendChild(script);
+
+</script>
+ </body>
+</html>
diff --git a/tools/html_fs/filesystem.js b/tools/html_fs/godotfs.js
index 93cc30556b..93cc30556b 100644
--- a/tools/html_fs/filesystem.js
+++ b/tools/html_fs/godotfs.js
diff --git a/tools/ios_xcode_template/godot_ios.xcodeproj/project.pbxproj b/tools/ios_xcode_template/godot_ios.xcodeproj/project.pbxproj
index 7cd4da0f4a..4ae1ec8a53 100644
--- a/tools/ios_xcode_template/godot_ios.xcodeproj/project.pbxproj
+++ b/tools/ios_xcode_template/godot_ios.xcodeproj/project.pbxproj
@@ -192,7 +192,7 @@
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0500;
- ORGANIZATIONNAME = Okam;
+ ORGANIZATIONNAME = GodotEngine;
TargetAttributes = {
D0BCFE5F18AEBDA3004A7AAE = {
TestTargetID = D0BCFE3318AEBDA2004A7AAE;
diff --git a/tools/ios_xcode_template/godot_ios/godot_ios-Info.plist b/tools/ios_xcode_template/godot_ios/godot_ios-Info.plist
index f34ebb97f0..357970920a 100644
--- a/tools/ios_xcode_template/godot_ios/godot_ios-Info.plist
+++ b/tools/ios_xcode_template/godot_ios/godot_ios-Info.plist
@@ -9,7 +9,7 @@
<key>CFBundleExecutable</key>
<string>godot_opt.iphone</string>
<key>CFBundleIdentifier</key>
- <string>com.okamstudios.${PRODUCT_NAME:rfc1034identifier}</string>
+ <string>org.godotengine.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
diff --git a/tools/ios_xcode_template/godot_ios/main.m b/tools/ios_xcode_template/godot_ios/main.m
index dca55f40ce..3e4ea5e129 100644
--- a/tools/ios_xcode_template/godot_ios/main.m
+++ b/tools/ios_xcode_template/godot_ios/main.m
@@ -1,10 +1,31 @@
-//
-// main.m
-// godot_ios
-//
-// Created by Ariel m on 2/14/14.
-// Copyright (c) 2014 Okam. All rights reserved.
-//
+/*************************************************************************/
+/* main.m */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
#import <UIKit/UIKit.h>
diff --git a/tools/ios_xcode_template/godot_iosTests/godot_iosTests-Info.plist b/tools/ios_xcode_template/godot_iosTests/godot_iosTests-Info.plist
index 3b3eec9a51..0f69aa80eb 100644
--- a/tools/ios_xcode_template/godot_iosTests/godot_iosTests-Info.plist
+++ b/tools/ios_xcode_template/godot_iosTests/godot_iosTests-Info.plist
@@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
- <string>com.okamstudios.${PRODUCT_NAME:rfc1034identifier}</string>
+ <string>org.godotengine.${PRODUCT_NAME:rfc1034identifier}</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
diff --git a/tools/ios_xcode_template/godot_iosTests/godot_iosTests.m b/tools/ios_xcode_template/godot_iosTests/godot_iosTests.m
index fce6288670..d9fac0a250 100644
--- a/tools/ios_xcode_template/godot_iosTests/godot_iosTests.m
+++ b/tools/ios_xcode_template/godot_iosTests/godot_iosTests.m
@@ -1,10 +1,31 @@
-//
-// godot_iosTests.m
-// godot_iosTests
-//
-// Created by Ariel m on 2/14/14.
-// Copyright (c) 2014 Okam. All rights reserved.
-//
+/*************************************************************************/
+/* godot_iosTests.m */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* http://www.godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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. */
+/*************************************************************************/
#import <XCTest/XCTest.h>
diff --git a/tools/osx_template.app/Contents/Resources/icon.icns b/tools/osx_template.app/Contents/Resources/icon.icns
index 18bc68d6ea..4a3dc0415a 100644
--- a/tools/osx_template.app/Contents/Resources/icon.icns
+++ b/tools/osx_template.app/Contents/Resources/icon.icns
Binary files differ
diff --git a/tools/pck/SCsub b/tools/pck/SCsub
index b1fed9a472..cf98ae145d 100644
--- a/tools/pck/SCsub
+++ b/tools/pck/SCsub
@@ -2,4 +2,3 @@ Import('env')
if env["tools"] == "yes":
env.add_source_files(env.tool_sources, "*.cpp")
-
diff --git a/tools/pck/pck_packer.cpp b/tools/pck/pck_packer.cpp
index d398fefb5f..228d37df7c 100644
--- a/tools/pck/pck_packer.cpp
+++ b/tools/pck/pck_packer.cpp
@@ -26,7 +26,7 @@ void PCKPacker::_bind_methods() {
ObjectTypeDB::bind_method(_MD("pck_start","pck_name","alignment"),&PCKPacker::pck_start);
ObjectTypeDB::bind_method(_MD("add_file","pck_path","source_path"),&PCKPacker::add_file);
- ObjectTypeDB::bind_method(_MD("flush"),&PCKPacker::flush);
+ ObjectTypeDB::bind_method(_MD("flush","verbose"),&PCKPacker::flush);
};
diff --git a/tools/pe_bliss/README b/tools/pe_bliss/README
new file mode 100644
index 0000000000..d5d1355444
--- /dev/null
+++ b/tools/pe_bliss/README
@@ -0,0 +1,84 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+
+
+Открытая бесплатная библиотека для работы с PE-файлами PE Bliss.
+Бесплатна к использованию, модификации и распространению.
+Автор: DX
+(c) DX 2011-2012, kaimi.ru
+
+Совместимость: Windows, Linux
+
+Возможности:
+[+] Создание PE или PE+ файла с нуля
+[+] Чтение 32-разрядных и 64-разрядных PE-файлов (PE, PE+) и единообразная работа с ними
+[+] Пересборка 32-разрядных и 64-разрядных PE-файлов
+[+] Работа с директориями и заголовками
+[+] Конвертирование адресов
+[+] Чтение и редактирование секций PE-файла
+[+] Чтение и редактирование таблицы импортов
+[+] Чтение и редактирование таблицы экспортов
+[+] Чтение и редактирование таблиц релокаций
+[+] Чтение и редактирование ресурсов
+[+] Чтение и редактирование TLS
+[+] Чтение и редактирование конфигурации образа (image config)
+[+] Чтение базовой информации .NET
+[+] Чтение и редактирование информации о привязанном импорте
+[+] Чтение директории исключений (только PE+)
+[+] Чтение отладочной директории с расширенной информацией
+[+] Вычисление энтропии
+[+] Изменение файлового выравнивания
+[+] Изменение базового адреса загрузки
+[+] Работа с DOS Stub'ом и Rich overlay
+[+] Высокоуровневое чтение ресурсов: картинки, иконки, курсоры, информация о версии, строковые таблицы, таблицы сообщений
+[+] Высокоуровневое редактирование ресурсов: картинки, иконки, курсоры, информация о версии
+
+[English]
+Open a free library for working with PE-file PE Bliss.
+Free to use, modify, and distribute.
+Author: DX
+(c) DX 2011-2012, kaimi.ru
+Compatibility: Windows, Linux
+
+### Capabilities:
+[+] Creation of PE or PE + file from scratch
+[+] Reading the 32-bit and 64-bit PE-file (PE, PE +) and uniform working with them
+[+] Rebuild 32-bit and 64-bit PE-files
+[+] Working with the directors and titles
+[+] Converting addresses
+[+] Reading and editing sections of PE-file
+[+] Reading and editing the import table
+[+] Reading and editing tables exports
+[+] Reading and editing tables relocations
+[+] Reading and editing resources
+[+] Reading and editing TLS
+[+] Reading and editing the configuration of the image (image config)
+[+] Reading data base .NET
+[+] Reading and editing information about tethered import
+[+] Read the directory exceptions (only PE +)
+[+] Read debug directories with extended information
+[+] The calculation of entropy
+[+] Changing file alignment
+[+] Change the base load address
+[+] Support of DOS Stub'om and Rich overlay
+[+] High-level reading resources: images, icons, cursors, version information, string tables, message table
+[+] High-level editing resources: images, icons, cursors, version information \ No newline at end of file
diff --git a/tools/pe_bliss/SCsub b/tools/pe_bliss/SCsub
new file mode 100644
index 0000000000..34524f10ef
--- /dev/null
+++ b/tools/pe_bliss/SCsub
@@ -0,0 +1,5 @@
+Import('env')
+
+env.add_source_files(env.tool_sources,"*.cpp")
+
+Export('env')
diff --git a/tools/pe_bliss/entropy.cpp b/tools/pe_bliss/entropy.cpp
new file mode 100644
index 0000000000..acefa63e83
--- /dev/null
+++ b/tools/pe_bliss/entropy.cpp
@@ -0,0 +1,111 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include <cmath>
+#include "entropy.h"
+#include "utils.h"
+
+namespace pe_bliss
+{
+//Calculates entropy for PE image section
+double entropy_calculator::calculate_entropy(const section& s)
+{
+ if(s.get_raw_data().empty()) //Don't count entropy for empty sections
+ throw pe_exception("Section is empty", pe_exception::section_is_empty);
+
+ return calculate_entropy(s.get_raw_data().data(), s.get_raw_data().length());
+}
+
+//Calculates entropy for istream (from current position of stream)
+double entropy_calculator::calculate_entropy(std::istream& file)
+{
+ uint32_t byte_count[256] = {0}; //Byte count for each of 255 bytes
+
+ if(file.bad())
+ throw pe_exception("Stream is bad", pe_exception::stream_is_bad);
+
+ std::streamoff pos = file.tellg();
+
+ std::streamoff length = pe_utils::get_file_size(file);
+ length -= file.tellg();
+
+ if(!length) //Don't calculate entropy for empty buffers
+ throw pe_exception("Data length is zero", pe_exception::data_is_empty);
+
+ //Count bytes
+ for(std::streamoff i = 0; i != length; ++i)
+ ++byte_count[static_cast<unsigned char>(file.get())];
+
+ file.seekg(pos);
+
+ return calculate_entropy(byte_count, length);
+}
+
+//Calculates entropy for data block
+double entropy_calculator::calculate_entropy(const char* data, size_t length)
+{
+ uint32_t byte_count[256] = {0}; //Byte count for each of 255 bytes
+
+ if(!length) //Don't calculate entropy for empty buffers
+ throw pe_exception("Data length is zero", pe_exception::data_is_empty);
+
+ //Count bytes
+ for(size_t i = 0; i != length; ++i)
+ ++byte_count[static_cast<unsigned char>(data[i])];
+
+ return calculate_entropy(byte_count, length);
+}
+
+//Calculates entropy for this PE file (only section data)
+double entropy_calculator::calculate_entropy(const pe_base& pe)
+{
+ uint32_t byte_count[256] = {0}; //Byte count for each of 255 bytes
+
+ size_t total_data_length = 0;
+
+ //Count bytes for each section
+ for(section_list::const_iterator it = pe.get_image_sections().begin(); it != pe.get_image_sections().end(); ++it)
+ {
+ const std::string& data = (*it).get_raw_data();
+ size_t length = data.length();
+ total_data_length += length;
+ for(size_t i = 0; i != length; ++i)
+ ++byte_count[static_cast<unsigned char>(data[i])];
+ }
+
+ return calculate_entropy(byte_count, total_data_length);
+}
+
+//Calculates entropy from bytes count
+double entropy_calculator::calculate_entropy(const uint32_t byte_count[256], std::streamoff total_length)
+{
+ double entropy = 0.; //Entropy result value
+ //Calculate entropy
+ for(uint32_t i = 0; i < 256; ++i)
+ {
+ double temp = static_cast<double>(byte_count[i]) / total_length;
+ if(temp > 0.)
+ entropy += std::abs(temp * (std::log(temp) * pe_utils::log_2));
+ }
+
+ return entropy;
+}
+}
diff --git a/tools/pe_bliss/entropy.h b/tools/pe_bliss/entropy.h
new file mode 100644
index 0000000000..7d225a3e32
--- /dev/null
+++ b/tools/pe_bliss/entropy.h
@@ -0,0 +1,51 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <istream>
+#include "pe_base.h"
+
+namespace pe_bliss
+{
+class entropy_calculator
+{
+public:
+ //Calculates entropy for PE image section
+ static double calculate_entropy(const section& s);
+
+ //Calculates entropy for istream (from current position of stream)
+ static double calculate_entropy(std::istream& file);
+
+ //Calculates entropy for data block
+ static double calculate_entropy(const char* data, size_t length);
+
+ //Calculates entropy for this PE file (only section data)
+ static double calculate_entropy(const pe_base& pe);
+
+private:
+ entropy_calculator();
+ entropy_calculator(const entropy_calculator&);
+ entropy_calculator& operator=(const entropy_calculator&);
+
+ //Calculates entropy from bytes count
+ static double calculate_entropy(const uint32_t byte_count[256], std::streamoff total_length);
+};
+}
diff --git a/tools/pe_bliss/file_version_info.cpp b/tools/pe_bliss/file_version_info.cpp
new file mode 100644
index 0000000000..3f2ba454b4
--- /dev/null
+++ b/tools/pe_bliss/file_version_info.cpp
@@ -0,0 +1,440 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include "file_version_info.h"
+#include "pe_structures.h"
+
+namespace pe_bliss
+{
+using namespace pe_win;
+
+//Default constructor
+file_version_info::file_version_info()
+ :file_version_ms_(0), file_version_ls_(0),
+ product_version_ms_(0), product_version_ls_(0),
+ file_flags_(0),
+ file_os_(0),
+ file_type_(0), file_subtype_(0),
+ file_date_ms_(0), file_date_ls_(0)
+{}
+
+//Constructor from Windows fixed version info structure
+file_version_info::file_version_info(const vs_fixedfileinfo& info)
+ :file_version_ms_(info.dwFileVersionMS), file_version_ls_(info.dwFileVersionLS),
+ product_version_ms_(info.dwProductVersionMS), product_version_ls_(info.dwProductVersionLS),
+ file_flags_(info.dwFileFlags),
+ file_os_(info.dwFileOS),
+ file_type_(info.dwFileType), file_subtype_(info.dwFileSubtype),
+ file_date_ms_(info.dwFileDateMS), file_date_ls_(info.dwFileDateLS)
+{}
+
+//Returns true if file is debug-built
+bool file_version_info::is_debug() const
+{
+ return file_flags_ & vs_ff_debug ? true : false;
+}
+
+//Returns true if file is release-built
+bool file_version_info::is_prerelease() const
+{
+ return file_flags_ & vs_ff_prerelease ? true : false;
+}
+
+//Returns true if file is patched
+bool file_version_info::is_patched() const
+{
+ return file_flags_ & vs_ff_patched ? true : false;
+}
+
+//Returns true if private build
+bool file_version_info::is_private_build() const
+{
+ return file_flags_ & vs_ff_privatebuild ? true : false;
+}
+
+//Returns true if special build
+bool file_version_info::is_special_build() const
+{
+ return file_flags_ & vs_ff_specialbuild ? true : false;
+}
+
+//Returns true if info inferred
+bool file_version_info::is_info_inferred() const
+{
+ return file_flags_ & vs_ff_infoinferred ? true : false;
+}
+
+//Retuens file flags (raw DWORD)
+uint32_t file_version_info::get_file_flags() const
+{
+ return file_flags_;
+}
+
+//Returns file version most significant DWORD
+uint32_t file_version_info::get_file_version_ms() const
+{
+ return file_version_ms_;
+}
+
+//Returns file version least significant DWORD
+uint32_t file_version_info::get_file_version_ls() const
+{
+ return file_version_ls_;
+}
+
+//Returns product version most significant DWORD
+uint32_t file_version_info::get_product_version_ms() const
+{
+ return product_version_ms_;
+}
+
+//Returns product version least significant DWORD
+uint32_t file_version_info::get_product_version_ls() const
+{
+ return product_version_ls_;
+}
+
+//Returns file OS type (raw DWORD)
+uint32_t file_version_info::get_file_os_raw() const
+{
+ return file_os_;
+}
+
+//Returns file OS type
+file_version_info::file_os_type file_version_info::get_file_os() const
+{
+ //Determine file operation system type
+ switch(file_os_)
+ {
+ case vos_dos:
+ return file_os_dos;
+
+ case vos_os216:
+ return file_os_os216;
+
+ case vos_os232:
+ return file_os_os232;
+
+ case vos_nt:
+ return file_os_nt;
+
+ case vos_wince:
+ return file_os_wince;
+
+ case vos__windows16:
+ return file_os_win16;
+
+ case vos__pm16:
+ return file_os_pm16;
+
+ case vos__pm32:
+ return file_os_pm32;
+
+ case vos__windows32:
+ return file_os_win32;
+
+ case vos_dos_windows16:
+ return file_os_dos_win16;
+
+ case vos_dos_windows32:
+ return file_os_dos_win32;
+
+ case vos_os216_pm16:
+ return file_os_os216_pm16;
+
+ case vos_os232_pm32:
+ return file_os_os232_pm32;
+
+ case vos_nt_windows32:
+ return file_os_nt_win32;
+ }
+
+ return file_os_unknown;
+}
+
+//Returns file type (raw DWORD)
+uint32_t file_version_info::get_file_type_raw() const
+{
+ return file_type_;
+}
+
+//Returns file type
+file_version_info::file_type file_version_info::get_file_type() const
+{
+ //Determine file type
+ switch(file_type_)
+ {
+ case vft_app:
+ return file_type_application;
+
+ case vft_dll:
+ return file_type_dll;
+
+ case vft_drv:
+ return file_type_driver;
+
+ case vft_font:
+ return file_type_font;
+
+ case vft_vxd:
+ return file_type_vxd;
+
+ case vft_static_lib:
+ return file_type_static_lib;
+ }
+
+ return file_type_unknown;
+}
+
+//Returns file subtype (usually non-zero for drivers and fonts)
+uint32_t file_version_info::get_file_subtype() const
+{
+ return file_subtype_;
+}
+
+//Returns file date most significant DWORD
+uint32_t file_version_info::get_file_date_ms() const
+{
+ return file_date_ms_;
+}
+
+//Returns file date least significant DWORD
+uint32_t file_version_info::get_file_date_ls() const
+{
+ return file_date_ls_;
+}
+
+//Helper to set file flag
+void file_version_info::set_file_flag(uint32_t flag)
+{
+ file_flags_ |= flag;
+}
+
+//Helper to clear file flag
+void file_version_info::clear_file_flag(uint32_t flag)
+{
+ file_flags_ &= ~flag;
+}
+
+//Helper to set or clear file flag
+void file_version_info::set_file_flag(uint32_t flag, bool set_flag)
+{
+ set_flag ? set_file_flag(flag) : clear_file_flag(flag);
+}
+
+//Sets if file is debug-built
+void file_version_info::set_debug(bool debug)
+{
+ set_file_flag(vs_ff_debug, debug);
+}
+
+//Sets if file is prerelease
+void file_version_info::set_prerelease(bool prerelease)
+{
+ set_file_flag(vs_ff_prerelease, prerelease);
+}
+
+//Sets if file is patched
+void file_version_info::set_patched(bool patched)
+{
+ set_file_flag(vs_ff_patched, patched);
+}
+
+//Sets if private build
+void file_version_info::set_private_build(bool private_build)
+{
+ set_file_flag(vs_ff_privatebuild, private_build);
+}
+
+//Sets if special build
+void file_version_info::set_special_build(bool special_build)
+{
+ set_file_flag(vs_ff_specialbuild, special_build);
+}
+
+//Sets if info inferred
+void file_version_info::set_info_inferred(bool info_inferred)
+{
+ set_file_flag(vs_ff_infoinferred, info_inferred);
+}
+
+//Sets flags (raw DWORD)
+void file_version_info::set_file_flags(uint32_t file_flags)
+{
+ file_flags_ = file_flags;
+}
+
+//Sets file version most significant DWORD
+void file_version_info::set_file_version_ms(uint32_t file_version_ms)
+{
+ file_version_ms_ = file_version_ms;
+}
+
+//Sets file version least significant DWORD
+void file_version_info::set_file_version_ls(uint32_t file_version_ls)
+{
+ file_version_ls_ = file_version_ls;
+}
+
+//Sets product version most significant DWORD
+void file_version_info::set_product_version_ms(uint32_t product_version_ms)
+{
+ product_version_ms_ = product_version_ms;
+}
+
+//Sets product version least significant DWORD
+void file_version_info::set_product_version_ls(uint32_t product_version_ls)
+{
+ product_version_ls_ = product_version_ls;
+}
+
+//Sets file OS type (raw DWORD)
+void file_version_info::set_file_os_raw(uint32_t file_os)
+{
+ file_os_ = file_os;
+}
+
+//Sets file OS type
+void file_version_info::set_file_os(file_os_type file_os)
+{
+ //Determine file operation system type
+ switch(file_os)
+ {
+ case file_os_dos:
+ file_os_ = vos_dos;
+ return;
+
+ case file_os_os216:
+ file_os_ = vos_os216;
+ return;
+
+ case file_os_os232:
+ file_os_ = vos_os232;
+ return;
+
+ case file_os_nt:
+ file_os_ = vos_nt;
+ return;
+
+ case file_os_wince:
+ file_os_ = vos_wince;
+ return;
+
+ case file_os_win16:
+ file_os_ = vos__windows16;
+ return;
+
+ case file_os_pm16:
+ file_os_ = vos__pm16;
+ return;
+
+ case file_os_pm32:
+ file_os_ = vos__pm32;
+ return;
+
+ case file_os_win32:
+ file_os_ = vos__windows32;
+ return;
+
+ case file_os_dos_win16:
+ file_os_ = vos_dos_windows16;
+ return;
+
+ case file_os_dos_win32:
+ file_os_ = vos_dos_windows32;
+ return;
+
+ case file_os_os216_pm16:
+ file_os_ = vos_os216_pm16;
+ return;
+
+ case file_os_os232_pm32:
+ file_os_ = vos_os232_pm32;
+ return;
+
+ case file_os_nt_win32:
+ file_os_ = vos_nt_windows32;
+ return;
+
+ default:
+ return;
+ }
+}
+
+//Sets file type (raw DWORD)
+void file_version_info::set_file_type_raw(uint32_t file_type)
+{
+ file_type_ = file_type;
+}
+
+//Sets file type
+void file_version_info::set_file_type(file_type file_type)
+{
+ //Determine file type
+ switch(file_type)
+ {
+ case file_type_application:
+ file_type_ = vft_app;
+ return;
+
+ case file_type_dll:
+ file_type_ = vft_dll;
+ return;
+
+ case file_type_driver:
+ file_type_ = vft_drv;
+ return;
+
+ case file_type_font:
+ file_type_ = vft_font;
+ return;
+
+ case file_type_vxd:
+ file_type_ = vft_vxd;
+ return;
+
+ case file_type_static_lib:
+ file_type_ = vft_static_lib;
+ return;
+
+ default:
+ return;
+ }
+}
+
+//Sets file subtype (usually non-zero for drivers and fonts)
+void file_version_info::set_file_subtype(uint32_t file_subtype)
+{
+ file_subtype_ = file_subtype;
+}
+
+//Sets file date most significant DWORD
+void file_version_info::set_file_date_ms(uint32_t file_date_ms)
+{
+ file_date_ms_ = file_date_ms;
+}
+
+//Sets file date least significant DWORD
+void file_version_info::set_file_date_ls(uint32_t file_date_ls)
+{
+ file_date_ls_ = file_date_ls;
+}
+}
diff --git a/tools/pe_bliss/file_version_info.h b/tools/pe_bliss/file_version_info.h
new file mode 100644
index 0000000000..d898351ba1
--- /dev/null
+++ b/tools/pe_bliss/file_version_info.h
@@ -0,0 +1,199 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <string>
+#include <map>
+#include "stdint_defs.h"
+#include "pe_structures.h"
+
+namespace pe_bliss
+{
+//Structure representing fixed file version info
+class file_version_info
+{
+public:
+ //Enumeration of file operating system types
+ enum file_os_type
+ {
+ file_os_unknown,
+ file_os_dos,
+ file_os_os216,
+ file_os_os232,
+ file_os_nt,
+ file_os_wince,
+ file_os_win16,
+ file_os_pm16,
+ file_os_pm32,
+ file_os_win32,
+ file_os_dos_win16,
+ file_os_dos_win32,
+ file_os_os216_pm16,
+ file_os_os232_pm32,
+ file_os_nt_win32
+ };
+
+ //Enumeration of file types
+ enum file_type
+ {
+ file_type_unknown,
+ file_type_application,
+ file_type_dll,
+ file_type_driver,
+ file_type_font,
+ file_type_vxd,
+ file_type_static_lib
+ };
+
+public:
+ //Default constructor
+ file_version_info();
+ //Constructor from Windows fixed version info structure
+ explicit file_version_info(const pe_win::vs_fixedfileinfo& info);
+
+public: //Getters
+ //Returns true if file is debug-built
+ bool is_debug() const;
+ //Returns true if file is prerelease
+ bool is_prerelease() const;
+ //Returns true if file is patched
+ bool is_patched() const;
+ //Returns true if private build
+ bool is_private_build() const;
+ //Returns true if special build
+ bool is_special_build() const;
+ //Returns true if info inferred
+ bool is_info_inferred() const;
+ //Retuens file flags (raw DWORD)
+ uint32_t get_file_flags() const;
+
+ //Returns file version most significant DWORD
+ uint32_t get_file_version_ms() const;
+ //Returns file version least significant DWORD
+ uint32_t get_file_version_ls() const;
+ //Returns product version most significant DWORD
+ uint32_t get_product_version_ms() const;
+ //Returns product version least significant DWORD
+ uint32_t get_product_version_ls() const;
+
+ //Returns file OS type (raw DWORD)
+ uint32_t get_file_os_raw() const;
+ //Returns file OS type
+ file_os_type get_file_os() const;
+
+ //Returns file type (raw DWORD)
+ uint32_t get_file_type_raw() const;
+ //Returns file type
+ file_type get_file_type() const;
+
+ //Returns file subtype (usually non-zero for drivers and fonts)
+ uint32_t get_file_subtype() const;
+
+ //Returns file date most significant DWORD
+ uint32_t get_file_date_ms() const;
+ //Returns file date least significant DWORD
+ uint32_t get_file_date_ls() const;
+
+ //Returns file version string
+ template<typename T>
+ const std::basic_string<T> get_file_version_string() const
+ {
+ return get_version_string<T>(file_version_ms_, file_version_ls_);
+ }
+
+ //Returns product version string
+ template<typename T>
+ const std::basic_string<T> get_product_version_string() const
+ {
+ return get_version_string<T>(product_version_ms_, product_version_ls_);
+ }
+
+public: //Setters
+ //Sets if file is debug-built
+ void set_debug(bool debug);
+ //Sets if file is prerelease
+ void set_prerelease(bool prerelease);
+ //Sets if file is patched
+ void set_patched(bool patched);
+ //Sets if private build
+ void set_private_build(bool private_build);
+ //Sets if special build
+ void set_special_build(bool special_build);
+ //Sets if info inferred
+ void set_info_inferred(bool info_inferred);
+ //Sets flags (raw DWORD)
+ void set_file_flags(uint32_t file_flags);
+
+ //Sets file version most significant DWORD
+ void set_file_version_ms(uint32_t file_version_ms);
+ //Sets file version least significant DWORD
+ void set_file_version_ls(uint32_t file_version_ls);
+ //Sets product version most significant DWORD
+ void set_product_version_ms(uint32_t product_version_ms);
+ //Sets product version least significant DWORD
+ void set_product_version_ls(uint32_t product_version_ls);
+
+ //Sets file OS type (raw DWORD)
+ void set_file_os_raw(uint32_t file_os);
+ //Sets file OS type
+ void set_file_os(file_os_type file_os);
+
+ //Sets file type (raw DWORD)
+ void set_file_type_raw(uint32_t file_type);
+ //Sets file type
+ void set_file_type(file_type file_type);
+
+ //Sets file subtype (usually non-zero for drivers and fonts)
+ void set_file_subtype(uint32_t file_subtype);
+
+ //Sets file date most significant DWORD
+ void set_file_date_ms(uint32_t file_date_ms);
+ //Sets file date least significant DWORD
+ void set_file_date_ls(uint32_t file_date_ls);
+
+private:
+ //Helper to convert version DWORDs to string
+ template<typename T>
+ static const std::basic_string<T> get_version_string(uint32_t ms, uint32_t ls)
+ {
+ std::basic_stringstream<T> ss;
+ ss << (ms >> 16) << static_cast<T>(L'.')
+ << (ms & 0xFFFF) << static_cast<T>(L'.')
+ << (ls >> 16) << static_cast<T>(L'.')
+ << (ls & 0xFFFF);
+ return ss.str();
+ }
+
+ //Helper to set file flag
+ void set_file_flag(uint32_t flag);
+ //Helper to clear file flag
+ void clear_file_flag(uint32_t flag);
+ //Helper to set or clear file flag
+ void set_file_flag(uint32_t flag, bool set_flag);
+
+ uint32_t file_version_ms_, file_version_ls_,
+ product_version_ms_, product_version_ls_;
+ uint32_t file_flags_;
+ uint32_t file_os_;
+ uint32_t file_type_, file_subtype_;
+ uint32_t file_date_ms_, file_date_ls_;
+};
+}
diff --git a/tools/pe_bliss/message_table.cpp b/tools/pe_bliss/message_table.cpp
new file mode 100644
index 0000000000..909be5d494
--- /dev/null
+++ b/tools/pe_bliss/message_table.cpp
@@ -0,0 +1,81 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include "message_table.h"
+#include "utils.h"
+
+namespace pe_bliss
+{
+//Default constructor
+message_table_item::message_table_item()
+ :unicode_(false)
+{}
+
+//Constructor from ANSI string
+message_table_item::message_table_item(const std::string& str)
+ :unicode_(false), ansi_str_(str)
+{
+ pe_utils::strip_nullbytes(ansi_str_);
+}
+
+//Constructor from UNICODE string
+message_table_item::message_table_item(const std::wstring& str)
+ :unicode_(true), unicode_str_(str)
+{
+ pe_utils::strip_nullbytes(unicode_str_);
+}
+
+//Returns true if contained string is unicode
+bool message_table_item::is_unicode() const
+{
+ return unicode_;
+}
+
+//Returns ANSI string
+const std::string& message_table_item::get_ansi_string() const
+{
+ return ansi_str_;
+}
+
+//Returns UNICODE string
+const std::wstring& message_table_item::get_unicode_string() const
+{
+ return unicode_str_;
+}
+
+//Sets ANSI string (clears UNICODE one)
+void message_table_item::set_string(const std::string& str)
+{
+ ansi_str_ = str;
+ pe_utils::strip_nullbytes(ansi_str_);
+ unicode_str_.clear();
+ unicode_ = false;
+}
+
+//Sets UNICODE string (clears ANSI one)
+void message_table_item::set_string(const std::wstring& str)
+{
+ unicode_str_ = str;
+ pe_utils::strip_nullbytes(unicode_str_);
+ ansi_str_.clear();
+ unicode_ = true;
+}
+}
diff --git a/tools/pe_bliss/message_table.h b/tools/pe_bliss/message_table.h
new file mode 100644
index 0000000000..5a3feb32c1
--- /dev/null
+++ b/tools/pe_bliss/message_table.h
@@ -0,0 +1,56 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <string>
+#include <map>
+#include "stdint_defs.h"
+
+namespace pe_bliss
+{
+//Structure representing message table string
+class message_table_item
+{
+public:
+ //Default constructor
+ message_table_item();
+ //Constructors from ANSI and UNICODE strings
+ explicit message_table_item(const std::string& str);
+ explicit message_table_item(const std::wstring& str);
+
+ //Returns true if string is UNICODE
+ bool is_unicode() const;
+ //Returns ANSI string
+ const std::string& get_ansi_string() const;
+ //Returns UNICODE string
+ const std::wstring& get_unicode_string() const;
+
+public:
+ //Sets ANSI or UNICODE string
+ void set_string(const std::string& str);
+ void set_string(const std::wstring& str);
+
+private:
+ bool unicode_;
+ std::string ansi_str_;
+ std::wstring unicode_str_;
+};
+}
diff --git a/tools/pe_bliss/pe_base.cpp b/tools/pe_bliss/pe_base.cpp
new file mode 100644
index 0000000000..97baa17cb3
--- /dev/null
+++ b/tools/pe_bliss/pe_base.cpp
@@ -0,0 +1,1680 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include <string>
+#include <vector>
+#include <istream>
+#include <ostream>
+#include <algorithm>
+#include <cmath>
+#include <set>
+#include <string.h>
+#include "pe_exception.h"
+#include "pe_base.h"
+
+namespace pe_bliss
+{
+using namespace pe_win;
+
+//Constructor
+pe_base::pe_base(std::istream& file, const pe_properties& props, bool read_debug_raw_data)
+{
+ props_ = props.duplicate().release();
+
+ //Save istream state
+ std::ios_base::iostate state = file.exceptions();
+ std::streamoff old_offset = file.tellg();
+
+ try
+ {
+ file.exceptions(std::ios::goodbit);
+ //Read DOS header, PE headers and section data
+ read_dos_header(file);
+ read_pe(file, read_debug_raw_data);
+ }
+ catch(const std::exception&)
+ {
+ //If something went wrong, restore istream state
+ file.seekg(old_offset);
+ file.exceptions(state);
+ file.clear();
+ //Rethrow
+ throw;
+ }
+
+ //Restore istream state
+ file.seekg(old_offset);
+ file.exceptions(state);
+ file.clear();
+}
+
+pe_base::pe_base(const pe_properties& props, uint32_t section_alignment, bool dll, uint16_t subsystem)
+{
+ props_ = props.duplicate().release();
+ props_->create_pe(section_alignment, subsystem);
+
+ has_overlay_ = false;
+ memset(&dos_header_, 0, sizeof(dos_header_));
+
+ dos_header_.e_magic = 0x5A4D; //"MZ"
+ //Magic numbers from MSVC++ build
+ dos_header_.e_maxalloc = 0xFFFF;
+ dos_header_.e_cblp = 0x90;
+ dos_header_.e_cp = 3;
+ dos_header_.e_cparhdr = 4;
+ dos_header_.e_sp = 0xB8;
+ dos_header_.e_lfarlc = 64;
+
+ set_characteristics(image_file_executable_image | image_file_relocs_stripped);
+
+ if(get_pe_type() == pe_type_32)
+ set_characteristics_flags(image_file_32bit_machine);
+
+ if(dll)
+ set_characteristics_flags(image_file_dll);
+
+ set_subsystem_version(5, 1); //WinXP
+ set_os_version(5, 1); //WinXP
+}
+
+pe_base::pe_base(const pe_base& pe)
+ :dos_header_(pe.dos_header_),
+ rich_overlay_(pe.rich_overlay_),
+ sections_(pe.sections_),
+ has_overlay_(pe.has_overlay_),
+ full_headers_data_(pe.full_headers_data_),
+ debug_data_(pe.debug_data_),
+ props_(0)
+{
+ props_ = pe.props_->duplicate().release();
+}
+
+pe_base& pe_base::operator=(const pe_base& pe)
+{
+ dos_header_ = pe.dos_header_;
+ rich_overlay_ = pe.rich_overlay_;
+ sections_ = pe.sections_;
+ has_overlay_ = pe.has_overlay_;
+ full_headers_data_ = pe.full_headers_data_;
+ debug_data_ = pe.debug_data_;
+ delete props_;
+ props_ = 0;
+ props_ = pe.props_->duplicate().release();
+
+ return *this;
+}
+
+pe_base::~pe_base()
+{
+ delete props_;
+}
+
+//Returns dos header
+const image_dos_header& pe_base::get_dos_header() const
+{
+ return dos_header_;
+}
+
+//Returns dos header
+image_dos_header& pe_base::get_dos_header()
+{
+ return dos_header_;
+}
+
+//Returns PE headers start position (e_lfanew)
+int32_t pe_base::get_pe_header_start() const
+{
+ return dos_header_.e_lfanew;
+}
+
+//Strips MSVC stub overlay
+void pe_base::strip_stub_overlay()
+{
+ rich_overlay_.clear();
+}
+
+//Fills MSVC stub overlay with character c
+void pe_base::fill_stub_overlay(char c)
+{
+ if(rich_overlay_.length())
+ rich_overlay_.assign(rich_overlay_.length(), c);
+}
+
+//Sets stub MSVS overlay
+void pe_base::set_stub_overlay(const std::string& data)
+{
+ rich_overlay_ = data;
+}
+
+//Returns stub overlay
+const std::string& pe_base::get_stub_overlay() const
+{
+ return rich_overlay_;
+}
+
+//Realigns all sections
+void pe_base::realign_all_sections()
+{
+ for(unsigned int i = 0; i < sections_.size(); i++)
+ realign_section(i);
+}
+
+//Returns number of sections from PE header
+uint16_t pe_base::get_number_of_sections() const
+{
+ return props_->get_number_of_sections();
+}
+
+//Updates number of sections in PE header
+uint16_t pe_base::update_number_of_sections()
+{
+ uint16_t new_number = static_cast<uint16_t>(sections_.size());
+ props_->set_number_of_sections(new_number);
+ return new_number;
+}
+
+//Returns section alignment
+uint32_t pe_base::get_section_alignment() const
+{
+ return props_->get_section_alignment();
+}
+
+//Returns image sections list
+section_list& pe_base::get_image_sections()
+{
+ return sections_;
+}
+
+//Returns image sections list
+const section_list& pe_base::get_image_sections() const
+{
+ return sections_;
+}
+
+//Realigns section by index
+void pe_base::realign_section(uint32_t index)
+{
+ //Check index
+ if(sections_.size() <= index)
+ throw pe_exception("Section not found", pe_exception::section_not_found);
+
+ //Get section iterator
+ section_list::iterator it = sections_.begin() + index;
+ section& s = *it;
+
+ //Calculate, how many null bytes we have in the end of raw section data
+ std::size_t strip = 0;
+ for(std::size_t i = (*it).get_raw_data().length(); i >= 1; --i)
+ {
+ if(s.get_raw_data()[i - 1] == 0)
+ strip++;
+ else
+ break;
+ }
+
+ if(it == sections_.end() - 1) //If we're realigning the last section
+ {
+ //We can strip ending null bytes
+ s.set_size_of_raw_data(static_cast<uint32_t>(s.get_raw_data().length() - strip));
+ s.get_raw_data().resize(s.get_raw_data().length() - strip, 0);
+ }
+ else
+ {
+ //Else just set size of raw data
+ uint32_t raw_size_aligned = s.get_aligned_raw_size(get_file_alignment());
+ s.set_size_of_raw_data(raw_size_aligned);
+ s.get_raw_data().resize(raw_size_aligned, 0);
+ }
+}
+
+//Returns file alignment
+uint32_t pe_base::get_file_alignment() const
+{
+ return props_->get_file_alignment();
+}
+
+//Sets file alignment
+void pe_base::set_file_alignment(uint32_t alignment)
+{
+ //Check alignment
+ if(alignment < minimum_file_alignment)
+ throw pe_exception("File alignment can't be less than 512", pe_exception::incorrect_file_alignment);
+
+ if(!pe_utils::is_power_of_2(alignment))
+ throw pe_exception("File alignment must be a power of 2", pe_exception::incorrect_file_alignment);
+
+ if(alignment > get_section_alignment())
+ throw pe_exception("File alignment must be <= section alignment", pe_exception::incorrect_file_alignment);
+
+ //Set file alignment without any additional checks
+ set_file_alignment_unchecked(alignment);
+}
+
+//Returns size of image
+uint32_t pe_base::get_size_of_image() const
+{
+ return props_->get_size_of_image();
+}
+
+//Returns image entry point
+uint32_t pe_base::get_ep() const
+{
+ return props_->get_ep();
+}
+
+//Sets image entry point (just a value of PE header)
+void pe_base::set_ep(uint32_t new_ep)
+{
+ props_->set_ep(new_ep);
+}
+
+//Returns number of RVA and sizes (number of DATA_DIRECTORY entries)
+uint32_t pe_base::get_number_of_rvas_and_sizes() const
+{
+ return props_->get_number_of_rvas_and_sizes();
+}
+
+//Sets number of RVA and sizes (number of DATA_DIRECTORY entries)
+void pe_base::set_number_of_rvas_and_sizes(uint32_t number)
+{
+ props_->set_number_of_rvas_and_sizes(number);
+}
+
+//Returns PE characteristics
+uint16_t pe_base::get_characteristics() const
+{
+ return props_->get_characteristics();
+}
+
+//Sets PE characteristics (a value inside header)
+void pe_base::set_characteristics(uint16_t ch)
+{
+ props_->set_characteristics(ch);
+}
+
+//Returns section from RVA
+section& pe_base::section_from_rva(uint32_t rva)
+{
+ //Search for section
+ for(section_list::iterator i = sections_.begin(); i != sections_.end(); ++i)
+ {
+ section& s = *i;
+ //Return section if found
+ if(rva >= s.get_virtual_address() && rva < s.get_virtual_address() + s.get_aligned_virtual_size(get_section_alignment()))
+ return s;
+ }
+
+ throw pe_exception("No section found by presented address", pe_exception::no_section_found);
+}
+
+//Returns section from RVA
+const section& pe_base::section_from_rva(uint32_t rva) const
+{
+ //Search for section
+ for(section_list::const_iterator i = sections_.begin(); i != sections_.end(); ++i)
+ {
+ const section& s = *i;
+ //Return section if found
+ if(rva >= s.get_virtual_address() && rva < s.get_virtual_address() + s.get_aligned_virtual_size(get_section_alignment()))
+ return s;
+ }
+
+ throw pe_exception("No section found by presented address", pe_exception::no_section_found);
+}
+
+//Returns section from directory ID
+section& pe_base::section_from_directory(uint32_t directory_id)
+{
+ return section_from_rva(get_directory_rva(directory_id));
+}
+
+//Returns section from directory ID
+const section& pe_base::section_from_directory(uint32_t directory_id) const
+{
+ return section_from_rva(get_directory_rva(directory_id));
+}
+
+//Sets section virtual size (actual for the last one of this PE or for unbound section)
+void pe_base::set_section_virtual_size(section& s, uint32_t vsize)
+{
+ //Check if we're changing virtual size of the last section
+ //Of course, we can change virtual size of section that's not bound to this PE file
+ if(sections_.empty() || std::find_if(sections_.begin(), sections_.end() - 1, section_ptr_finder(s)) != sections_.end() - 1)
+ throw pe_exception("Can't change virtual size of any section, except last one", pe_exception::error_changing_section_virtual_size);
+
+ //If we're setting virtual size to zero
+ if(vsize == 0)
+ {
+ //Check if section is empty
+ if(s.empty())
+ throw pe_exception("Cannot set virtual size of empty section to zero", pe_exception::error_changing_section_virtual_size);
+
+ //Set virtual size equal to aligned size of raw data
+ s.set_virtual_size(s.get_size_of_raw_data());
+ }
+ else
+ {
+ s.set_virtual_size(vsize);
+ }
+
+ //Update image size if we're changing virtual size for the last section of this PE
+ if(!sections_.empty() || &s == &(*(sections_.end() - 1)))
+ update_image_size();
+}
+
+//Expands section raw or virtual size to hold data from specified RVA with specified size
+//Section must be free (not bound to any image)
+//or the last section of this image
+bool pe_base::expand_section(section& s, uint32_t needed_rva, uint32_t needed_size, section_expand_type expand)
+{
+ //Check if we're changing the last section
+ //Of course, we can change the section that's not bound to this PE file
+ if(sections_.empty() || std::find_if(sections_.begin(), sections_.end() - 1, section_ptr_finder(s)) != sections_.end() - 1)
+ throw pe_exception("Can't expand any section, except last one", pe_exception::error_expanding_section);
+
+ //Check if we should expand our section
+ if(expand == expand_section_raw && section_data_length_from_rva(s, needed_rva, section_data_raw) < needed_size)
+ {
+ //Expand section raw data
+ s.get_raw_data().resize(needed_rva - s.get_virtual_address() + needed_size);
+ recalculate_section_sizes(s, false);
+ return true;
+ }
+ else if(expand == expand_section_virtual && section_data_length_from_rva(s, needed_rva, section_data_virtual) < needed_size)
+ {
+ //Expand section virtual data
+ set_section_virtual_size(s, needed_rva - s.get_virtual_address() + needed_size);
+ return true;
+ }
+
+ return false;
+}
+
+//Updates image virtual size
+void pe_base::update_image_size()
+{
+ //Write virtual size of image to headers
+ if(!sections_.empty())
+ set_size_of_image(sections_.back().get_virtual_address() + sections_.back().get_aligned_virtual_size(get_section_alignment()));
+ else
+ set_size_of_image(get_size_of_headers());
+}
+
+//Returns checksum of PE file from header
+uint32_t pe_base::get_checksum() const
+{
+ return props_->get_checksum();
+}
+
+//Sets checksum of PE file
+void pe_base::set_checksum(uint32_t checksum)
+{
+ props_->set_checksum(checksum);
+}
+
+//Returns timestamp of PE file from header
+uint32_t pe_base::get_time_date_stamp() const
+{
+ return props_->get_time_date_stamp();
+}
+
+//Sets timestamp of PE file
+void pe_base::set_time_date_stamp(uint32_t timestamp)
+{
+ props_->set_time_date_stamp(timestamp);
+}
+
+//Returns Machine field value of PE file from header
+uint16_t pe_base::get_machine() const
+{
+ return props_->get_machine();
+}
+
+//Sets Machine field value of PE file
+void pe_base::set_machine(uint16_t machine)
+{
+ props_->set_machine(machine);
+}
+
+//Prepares section before attaching it
+void pe_base::prepare_section(section& s)
+{
+ //Calculate its size of raw data
+ s.set_size_of_raw_data(static_cast<uint32_t>(pe_utils::align_up(s.get_raw_data().length(), get_file_alignment())));
+
+ //Check section virtual and raw size
+ if(!s.get_size_of_raw_data() && !s.get_virtual_size())
+ throw pe_exception("Virtual and Physical sizes of section can't be 0 at the same time", pe_exception::zero_section_sizes);
+
+ //If section virtual size is zero
+ if(!s.get_virtual_size())
+ {
+ s.set_virtual_size(s.get_size_of_raw_data());
+ }
+ else
+ {
+ //Else calculate its virtual size
+ s.set_virtual_size(
+ std::max<uint32_t>(pe_utils::align_up(s.get_size_of_raw_data(), get_file_alignment()),
+ pe_utils::align_up(s.get_virtual_size(), get_section_alignment())));
+ }
+}
+
+//Adds section to image
+section& pe_base::add_section(section s)
+{
+ if(sections_.size() >= maximum_number_of_sections)
+ throw pe_exception("Maximum number of sections has been reached", pe_exception::no_more_sections_can_be_added);
+
+ //Prepare section before adding it
+ prepare_section(s);
+
+ //Calculate section virtual address
+ if(!sections_.empty())
+ {
+ s.set_virtual_address(pe_utils::align_up(sections_.back().get_virtual_address() + sections_.back().get_aligned_virtual_size(get_section_alignment()), get_section_alignment()));
+
+ //We should align last section raw size, if it wasn't aligned
+ section& last = sections_.back();
+ last.set_size_of_raw_data(static_cast<uint32_t>(pe_utils::align_up(last.get_raw_data().length(), get_file_alignment())));
+ }
+ else
+ {
+ s.set_virtual_address(
+ s.get_virtual_address() == 0
+ ? pe_utils::align_up(get_size_of_headers(), get_section_alignment())
+ : pe_utils::align_up(s.get_virtual_address(), get_section_alignment()));
+ }
+
+ //Add section to the end of section list
+ sections_.push_back(s);
+ //Set number of sections in PE header
+ set_number_of_sections(static_cast<uint16_t>(sections_.size()));
+ //Recalculate virtual size of image
+ set_size_of_image(get_size_of_image() + s.get_aligned_virtual_size(get_section_alignment()));
+ //Return last section
+ return sections_.back();
+}
+
+//Returns true if sectios "s" is already attached to this PE file
+bool pe_base::section_attached(const section& s) const
+{
+ return sections_.end() != std::find_if(sections_.begin(), sections_.end(), section_ptr_finder(s));
+}
+
+//Returns true if directory exists
+bool pe_base::directory_exists(uint32_t id) const
+{
+ return props_->directory_exists(id);
+}
+
+//Removes directory
+void pe_base::remove_directory(uint32_t id)
+{
+ props_->remove_directory(id);
+}
+
+//Returns directory RVA
+uint32_t pe_base::get_directory_rva(uint32_t id) const
+{
+ return props_->get_directory_rva(id);
+}
+
+//Returns directory size
+uint32_t pe_base::get_directory_size(uint32_t id) const
+{
+ return props_->get_directory_size(id);
+}
+
+//Sets directory RVA (just a value of PE header, no moving occurs)
+void pe_base::set_directory_rva(uint32_t id, uint32_t rva)
+{
+ return props_->set_directory_rva(id, rva);
+}
+
+//Sets directory size (just a value of PE header, no moving occurs)
+void pe_base::set_directory_size(uint32_t id, uint32_t size)
+{
+ return props_->set_directory_size(id, size);
+}
+
+//Strips only zero DATA_DIRECTORY entries to count = min_count
+//Returns resulting number of data directories
+//strip_iat_directory - if true, even not empty IAT directory will be stripped
+uint32_t pe_base::strip_data_directories(uint32_t min_count, bool strip_iat_directory)
+{
+ return props_->strip_data_directories(min_count, strip_iat_directory);
+}
+
+//Returns true if image has import directory
+bool pe_base::has_imports() const
+{
+ return directory_exists(image_directory_entry_import);
+}
+
+//Returns true if image has export directory
+bool pe_base::has_exports() const
+{
+ return directory_exists(image_directory_entry_export);
+}
+
+//Returns true if image has resource directory
+bool pe_base::has_resources() const
+{
+ return directory_exists(image_directory_entry_resource);
+}
+
+//Returns true if image has security directory
+bool pe_base::has_security() const
+{
+ return directory_exists(image_directory_entry_security);
+}
+
+//Returns true if image has relocations
+bool pe_base::has_reloc() const
+{
+ return directory_exists(image_directory_entry_basereloc) && !(get_characteristics() & image_file_relocs_stripped);
+}
+
+//Returns true if image has TLS directory
+bool pe_base::has_tls() const
+{
+ return directory_exists(image_directory_entry_tls);
+}
+
+//Returns true if image has config directory
+bool pe_base::has_config() const
+{
+ return directory_exists(image_directory_entry_load_config);
+}
+
+//Returns true if image has bound import directory
+bool pe_base::has_bound_import() const
+{
+ return directory_exists(image_directory_entry_bound_import);
+}
+
+//Returns true if image has delay import directory
+bool pe_base::has_delay_import() const
+{
+ return directory_exists(image_directory_entry_delay_import);
+}
+
+//Returns true if image has COM directory
+bool pe_base::is_dotnet() const
+{
+ return directory_exists(image_directory_entry_com_descriptor);
+}
+
+//Returns true if image has exception directory
+bool pe_base::has_exception_directory() const
+{
+ return directory_exists(image_directory_entry_exception);
+}
+
+//Returns true if image has debug directory
+bool pe_base::has_debug() const
+{
+ return directory_exists(image_directory_entry_debug);
+}
+
+//Returns corresponding section data pointer from RVA inside section "s" (checks bounds)
+char* pe_base::section_data_from_rva(section& s, uint32_t rva)
+{
+ //Check if RVA is inside section "s"
+ if(rva >= s.get_virtual_address() && rva < s.get_virtual_address() + s.get_aligned_virtual_size(get_section_alignment()))
+ {
+ if(s.get_raw_data().empty())
+ throw pe_exception("Section raw data is empty and cannot be changed", pe_exception::section_is_empty);
+
+ return &s.get_raw_data()[rva - s.get_virtual_address()];
+ }
+
+ throw pe_exception("RVA not found inside section", pe_exception::rva_not_exists);
+}
+
+//Returns corresponding section data pointer from RVA inside section "s" (checks bounds)
+const char* pe_base::section_data_from_rva(const section& s, uint32_t rva, section_data_type datatype) const
+{
+ //Check if RVA is inside section "s"
+ if(rva >= s.get_virtual_address() && rva < s.get_virtual_address() + s.get_aligned_virtual_size(get_section_alignment()))
+ return (datatype == section_data_raw ? s.get_raw_data().data() : s.get_virtual_data(get_section_alignment()).c_str()) + rva - s.get_virtual_address();
+
+ throw pe_exception("RVA not found inside section", pe_exception::rva_not_exists);
+}
+
+//Returns section TOTAL RAW/VIRTUAL data length from RVA inside section
+uint32_t pe_base::section_data_length_from_rva(uint32_t rva, section_data_type datatype, bool include_headers) const
+{
+ //if RVA is inside of headers and we're searching them too...
+ if(include_headers && rva < full_headers_data_.length())
+ return static_cast<unsigned long>(full_headers_data_.length());
+
+ const section& s = section_from_rva(rva);
+ return static_cast<unsigned long>(datatype == section_data_raw ? s.get_raw_data().length() /* instead of SizeOfRawData */ : s.get_aligned_virtual_size(get_section_alignment()));
+}
+
+//Returns section TOTAL RAW/VIRTUAL data length from VA inside section for PE32
+uint32_t pe_base::section_data_length_from_va(uint32_t va, section_data_type datatype, bool include_headers) const
+{
+ return section_data_length_from_rva(va_to_rva(va), datatype, include_headers);
+}
+
+//Returns section TOTAL RAW/VIRTUAL data length from VA inside section for PE32/PE64
+uint32_t pe_base::section_data_length_from_va(uint64_t va, section_data_type datatype, bool include_headers) const
+{
+ return section_data_length_from_rva(va_to_rva(va), datatype, include_headers);
+}
+
+//Returns section remaining RAW/VIRTUAL data length from RVA "rva_inside" to the end of section containing RVA "rva"
+uint32_t pe_base::section_data_length_from_rva(uint32_t rva, uint32_t rva_inside, section_data_type datatype, bool include_headers) const
+{
+ //if RVAs are inside of headers and we're searching them too...
+ if(include_headers && rva < full_headers_data_.length() && rva_inside < full_headers_data_.length())
+ return static_cast<unsigned long>(full_headers_data_.length() - rva_inside);
+
+ const section& s = section_from_rva(rva);
+ if(rva_inside < s.get_virtual_address())
+ throw pe_exception("RVA not found inside section", pe_exception::rva_not_exists);
+
+ //Calculate remaining length of section data from "rva" address
+ long length = static_cast<long>(datatype == section_data_raw ? s.get_raw_data().length() /* instead of SizeOfRawData */ : s.get_aligned_virtual_size(get_section_alignment()))
+ + s.get_virtual_address() - rva_inside;
+
+ if(length < 0)
+ return 0;
+
+ return static_cast<unsigned long>(length);
+}
+
+//Returns section remaining RAW/VIRTUAL data length from VA "va_inside" to the end of section containing VA "va" for PE32
+uint32_t pe_base::section_data_length_from_va(uint32_t va, uint32_t va_inside, section_data_type datatype, bool include_headers) const
+{
+ return section_data_length_from_rva(va_to_rva(va), va_to_rva(va_inside), datatype, include_headers);
+}
+
+//Returns section remaining RAW/VIRTUAL data length from VA "va_inside" to the end of section containing VA "va" for PE32/PE64
+uint32_t pe_base::section_data_length_from_va(uint64_t va, uint64_t va_inside, section_data_type datatype, bool include_headers) const
+{
+ return section_data_length_from_rva(va_to_rva(va), va_to_rva(va_inside), datatype, include_headers);
+}
+
+//Returns section remaining RAW/VIRTUAL data length from RVA to the end of section "s" (checks bounds)
+uint32_t pe_base::section_data_length_from_rva(const section& s, uint32_t rva_inside, section_data_type datatype) const
+{
+ //Check rva_inside
+ if(rva_inside >= s.get_virtual_address() && rva_inside < s.get_virtual_address() + s.get_aligned_virtual_size(get_section_alignment()))
+ {
+ //Calculate remaining length of section data from "rva" address
+ int32_t length = static_cast<int32_t>(datatype == section_data_raw ? s.get_raw_data().length() /* instead of SizeOfRawData */ : s.get_aligned_virtual_size(get_section_alignment()))
+ + s.get_virtual_address() - rva_inside;
+
+ if(length < 0)
+ return 0;
+
+ return static_cast<uint32_t>(length);
+ }
+
+ throw pe_exception("RVA not found inside section", pe_exception::rva_not_exists);
+}
+
+//Returns section remaining RAW/VIRTUAL data length from VA to the end of section "s" for PE32 (checks bounds)
+uint32_t pe_base::section_data_length_from_va(const section& s, uint32_t va_inside, section_data_type datatype) const
+{
+ return section_data_length_from_rva(s, va_to_rva(va_inside), datatype);
+}
+
+//Returns section remaining RAW/VIRTUAL data length from VA to the end of section "s" for PE32/PE64 (checks bounds)
+uint32_t pe_base::section_data_length_from_va(const section& s, uint64_t va_inside, section_data_type datatype) const
+{
+ return section_data_length_from_rva(s, va_to_rva(va_inside), datatype);
+}
+
+//Returns corresponding section data pointer from RVA inside section
+char* pe_base::section_data_from_rva(uint32_t rva, bool include_headers)
+{
+ //if RVA is inside of headers and we're searching them too...
+ if(include_headers && rva < full_headers_data_.length())
+ return &full_headers_data_[rva];
+
+ section& s = section_from_rva(rva);
+
+ if(s.get_raw_data().empty())
+ throw pe_exception("Section raw data is empty and cannot be changed", pe_exception::section_is_empty);
+
+ return &s.get_raw_data()[rva - s.get_virtual_address()];
+}
+
+//Returns corresponding section data pointer from RVA inside section
+const char* pe_base::section_data_from_rva(uint32_t rva, section_data_type datatype, bool include_headers) const
+{
+ //if RVA is inside of headers and we're searching them too...
+ if(include_headers && rva < full_headers_data_.length())
+ return &full_headers_data_[rva];
+
+ const section& s = section_from_rva(rva);
+ return (datatype == section_data_raw ? s.get_raw_data().data() : s.get_virtual_data(get_section_alignment()).c_str()) + rva - s.get_virtual_address();
+}
+
+//Reads DOS headers from istream
+void pe_base::read_dos_header(std::istream& file, image_dos_header& header)
+{
+ //Check istream flags
+ if(file.bad() || file.eof())
+ throw pe_exception("PE file stream is bad or closed.", pe_exception::bad_pe_file);
+
+ //Read DOS header and check istream
+ file.read(reinterpret_cast<char*>(&header), sizeof(image_dos_header));
+ if(file.bad() || file.eof())
+ throw pe_exception("Unable to read IMAGE_DOS_HEADER", pe_exception::bad_dos_header);
+
+ //Check DOS header magic
+ if(header.e_magic != 0x5a4d) //"MZ"
+ throw pe_exception("IMAGE_DOS_HEADER signature is incorrect", pe_exception::bad_dos_header);
+}
+
+//Reads DOS headers from istream
+void pe_base::read_dos_header(std::istream& file)
+{
+ read_dos_header(file, dos_header_);
+}
+
+//Reads PE image from istream
+void pe_base::read_pe(std::istream& file, bool read_debug_raw_data)
+{
+ //Get istream size
+ std::streamoff filesize = pe_utils::get_file_size(file);
+
+ //Check if PE header is DWORD-aligned
+ if((dos_header_.e_lfanew % sizeof(uint32_t)) != 0)
+ throw pe_exception("PE header is not DWORD-aligned", pe_exception::bad_dos_header);
+
+ //Seek to NT headers
+ file.seekg(dos_header_.e_lfanew);
+ if(file.bad() || file.fail())
+ throw pe_exception("Cannot reach IMAGE_NT_HEADERS", pe_exception::image_nt_headers_not_found);
+
+ //Read NT headers
+ file.read(get_nt_headers_ptr(), get_sizeof_nt_header() - sizeof(image_data_directory) * image_numberof_directory_entries);
+ if(file.bad() || file.eof())
+ throw pe_exception("Error reading IMAGE_NT_HEADERS", pe_exception::error_reading_image_nt_headers);
+
+ //Check PE signature
+ if(get_pe_signature() != 0x4550) //"PE"
+ throw pe_exception("Incorrect PE signature", pe_exception::pe_signature_incorrect);
+
+ //Check number of directories
+ if(get_number_of_rvas_and_sizes() > image_numberof_directory_entries)
+ set_number_of_rvas_and_sizes(image_numberof_directory_entries);
+
+ if(get_number_of_rvas_and_sizes() > 0)
+ {
+ //Read data directory headers, if any
+ file.read(get_nt_headers_ptr() + (get_sizeof_nt_header() - sizeof(image_data_directory) * image_numberof_directory_entries), sizeof(image_data_directory) * get_number_of_rvas_and_sizes());
+ if(file.bad() || file.eof())
+ throw pe_exception("Error reading DATA_DIRECTORY headers", pe_exception::error_reading_data_directories);
+ }
+
+ //Check section number
+ //Images with zero section number accepted
+ if(get_number_of_sections() > maximum_number_of_sections)
+ throw pe_exception("Incorrect number of sections", pe_exception::section_number_incorrect);
+
+ //Check PE magic
+ if(get_magic() != get_needed_magic())
+ throw pe_exception("Incorrect PE signature", pe_exception::pe_signature_incorrect);
+
+ //Check section alignment
+ if(!pe_utils::is_power_of_2(get_section_alignment()))
+ throw pe_exception("Incorrect section alignment", pe_exception::incorrect_section_alignment);
+
+ //Check file alignment
+ if(!pe_utils::is_power_of_2(get_file_alignment()))
+ throw pe_exception("Incorrect file alignment", pe_exception::incorrect_file_alignment);
+
+ if(get_file_alignment() != get_section_alignment() && (get_file_alignment() < minimum_file_alignment || get_file_alignment() > get_section_alignment()))
+ throw pe_exception("Incorrect file alignment", pe_exception::incorrect_file_alignment);
+
+ //Check size of image
+ if(pe_utils::align_up(get_size_of_image(), get_section_alignment()) == 0)
+ throw pe_exception("Incorrect size of image", pe_exception::incorrect_size_of_image);
+
+ //Read rich data overlay / DOS stub (if any)
+ if(static_cast<uint32_t>(dos_header_.e_lfanew) > sizeof(image_dos_header))
+ {
+ rich_overlay_.resize(dos_header_.e_lfanew - sizeof(image_dos_header));
+ file.seekg(sizeof(image_dos_header));
+ file.read(&rich_overlay_[0], dos_header_.e_lfanew - sizeof(image_dos_header));
+ if(file.bad() || file.eof())
+ throw pe_exception("Error reading 'Rich' & 'DOS stub' overlay", pe_exception::error_reading_overlay);
+ }
+
+ //Calculate first section raw position
+ //Sum is safe here
+ uint32_t first_section = dos_header_.e_lfanew + get_size_of_optional_header() + sizeof(image_file_header) + sizeof(uint32_t) /* Signature */;
+
+ if(get_number_of_sections() > 0)
+ {
+ //Go to first section
+ file.seekg(first_section);
+ if(file.bad() || file.fail())
+ throw pe_exception("Cannot reach section headers", pe_exception::image_section_headers_not_found);
+ }
+
+ uint32_t last_raw_size = 0;
+
+ //Read all sections
+ for(int i = 0; i < get_number_of_sections(); i++)
+ {
+ section s;
+ //Read section header
+ file.read(reinterpret_cast<char*>(&s.get_raw_header()), sizeof(image_section_header));
+ if(file.bad() || file.eof())
+ throw pe_exception("Error reading section header", pe_exception::error_reading_section_header);
+
+ //Save next section header position
+ std::streamoff next_sect = file.tellg();
+
+ //Check section virtual and raw sizes
+ if(!s.get_size_of_raw_data() && !s.get_virtual_size())
+ throw pe_exception("Virtual and Physical sizes of section can't be 0 at the same time", pe_exception::zero_section_sizes);
+
+ //Check for adequate values of section fields
+ if(!pe_utils::is_sum_safe(s.get_virtual_address(), s.get_virtual_size()) || s.get_virtual_size() > pe_utils::two_gb
+ || !pe_utils::is_sum_safe(s.get_pointer_to_raw_data(), s.get_size_of_raw_data()) || s.get_size_of_raw_data() > pe_utils::two_gb)
+ throw pe_exception("Incorrect section address or size", pe_exception::section_incorrect_addr_or_size);
+
+ if(s.get_size_of_raw_data() != 0)
+ {
+ //If section has raw data
+
+ //If section raw data size is greater than virtual, fix it
+ last_raw_size = s.get_size_of_raw_data();
+ if(pe_utils::align_up(s.get_size_of_raw_data(), get_file_alignment()) > pe_utils::align_up(s.get_virtual_size(), get_section_alignment()))
+ s.set_size_of_raw_data(s.get_virtual_size());
+
+ //Check virtual and raw section sizes and addresses
+ if(s.get_virtual_address() + pe_utils::align_up(s.get_virtual_size(), get_section_alignment()) > pe_utils::align_up(get_size_of_image(), get_section_alignment())
+ ||
+ pe_utils::align_down(s.get_pointer_to_raw_data(), get_file_alignment()) + s.get_size_of_raw_data() > static_cast<uint32_t>(filesize))
+ throw pe_exception("Incorrect section address or size", pe_exception::section_incorrect_addr_or_size);
+
+ //Seek to section raw data
+ file.seekg(pe_utils::align_down(s.get_pointer_to_raw_data(), get_file_alignment()));
+ if(file.bad() || file.fail())
+ throw pe_exception("Cannot reach section data", pe_exception::image_section_data_not_found);
+
+ //Read section raw data
+ s.get_raw_data().resize(s.get_size_of_raw_data());
+ file.read(&s.get_raw_data()[0], s.get_size_of_raw_data());
+ if(file.bad() || file.fail())
+ throw pe_exception("Error reading section data", pe_exception::image_section_data_not_found);
+ }
+
+ //Check virtual address and size of section
+ if(s.get_virtual_address() + s.get_aligned_virtual_size(get_section_alignment()) > pe_utils::align_up(get_size_of_image(), get_section_alignment()))
+ throw pe_exception("Incorrect section address or size", pe_exception::section_incorrect_addr_or_size);
+
+ //Save section
+ sections_.push_back(s);
+
+ //Seek to the next section header
+ file.seekg(next_sect);
+ }
+
+ //Check size of headers: SizeOfHeaders can't be larger than first section VA
+ if(!sections_.empty() && get_size_of_headers() > sections_.front().get_virtual_address())
+ throw pe_exception("Incorrect size of headers", pe_exception::incorrect_size_of_headers);
+
+ //If image has more than two sections
+ if(sections_.size() >= 2)
+ {
+ //Check sections virtual sizes
+ for(section_list::const_iterator i = sections_.begin() + 1; i != sections_.end(); ++i)
+ {
+ if((*i).get_virtual_address() != (*(i - 1)).get_virtual_address() + (*(i - 1)).get_aligned_virtual_size(get_section_alignment()))
+ throw pe_exception("Section table is incorrect", pe_exception::image_section_table_incorrect);
+ }
+ }
+
+ //Check if image has overlay in the end of file
+ has_overlay_ = !sections_.empty() && filesize > static_cast<std::streamoff>(sections_.back().get_pointer_to_raw_data() + last_raw_size);
+
+ {
+ //Additionally, read data from the beginning of istream to size of headers
+ file.seekg(0);
+ uint32_t size_of_headers = std::min<uint32_t>(get_size_of_headers(), static_cast<uint32_t>(filesize));
+
+ if(!sections_.empty())
+ {
+ for(section_list::const_iterator i = sections_.begin(); i != sections_.end(); ++i)
+ {
+ if(!(*i).empty())
+ {
+ size_of_headers = std::min<uint32_t>(get_size_of_headers(), (*i).get_pointer_to_raw_data());
+ break;
+ }
+ }
+ }
+
+ full_headers_data_.resize(size_of_headers);
+ file.read(&full_headers_data_[0], size_of_headers);
+ if(file.bad() || file.eof())
+ throw pe_exception("Error reading file", pe_exception::error_reading_file);
+ }
+
+ //Moreover, if there's debug directory, read its raw data for some debug info types
+ while(read_debug_raw_data && has_debug())
+ {
+ try
+ {
+ //Check the length in bytes of the section containing debug directory
+ if(section_data_length_from_rva(get_directory_rva(image_directory_entry_debug), get_directory_rva(image_directory_entry_debug), section_data_virtual, true) < sizeof(image_debug_directory))
+ break;
+
+ unsigned long current_pos = get_directory_rva(image_directory_entry_debug);
+
+ //First IMAGE_DEBUG_DIRECTORY table
+ image_debug_directory directory = section_data_from_rva<image_debug_directory>(current_pos, section_data_virtual, true);
+
+ //Iterate over all IMAGE_DEBUG_DIRECTORY directories
+ while(directory.PointerToRawData
+ && current_pos < get_directory_rva(image_directory_entry_debug) + get_directory_size(image_directory_entry_debug))
+ {
+ //If we have something to read
+ if((directory.Type == image_debug_type_codeview
+ || directory.Type == image_debug_type_misc
+ || directory.Type == image_debug_type_coff)
+ && directory.SizeOfData)
+ {
+ std::string data;
+ data.resize(directory.SizeOfData);
+ file.seekg(directory.PointerToRawData);
+ file.read(&data[0], directory.SizeOfData);
+ if(file.bad() || file.eof())
+ throw pe_exception("Error reading file", pe_exception::error_reading_file);
+
+ debug_data_.insert(std::make_pair(directory.PointerToRawData, data));
+ }
+
+ //Go to next debug entry
+ current_pos += sizeof(image_debug_directory);
+ directory = section_data_from_rva<image_debug_directory>(current_pos, section_data_virtual, true);
+ }
+
+ break;
+ }
+ catch(const pe_exception&)
+ {
+ //Don't throw any exception here, if debug info is corrupted or incorrect
+ break;
+ }
+ catch(const std::bad_alloc&)
+ {
+ //Don't throw any exception here, if debug info is corrupted or incorrect
+ break;
+ }
+ }
+}
+
+//Returns PE type of this image
+pe_type pe_base::get_pe_type() const
+{
+ return props_->get_pe_type();
+}
+
+//Returns PE type (PE or PE+) from pe_type enumeration (minimal correctness checks)
+pe_type pe_base::get_pe_type(std::istream& file)
+{
+ //Save state of the istream
+ std::ios_base::iostate state = file.exceptions();
+ std::streamoff old_offset = file.tellg();
+ image_nt_headers32 nt_headers;
+ image_dos_header header;
+
+ try
+ {
+ //Read dos header
+ file.exceptions(std::ios::goodbit);
+ read_dos_header(file, header);
+
+ //Seek to the NT headers start
+ file.seekg(header.e_lfanew);
+ if(file.bad() || file.fail())
+ throw pe_exception("Cannot reach IMAGE_NT_HEADERS", pe_exception::image_nt_headers_not_found);
+
+ //Read NT headers (we're using 32-bit version, because there's no significant differencies between 32 and 64 bit version structures)
+ file.read(reinterpret_cast<char*>(&nt_headers), sizeof(image_nt_headers32) - sizeof(image_data_directory) * image_numberof_directory_entries);
+ if(file.bad() || file.eof())
+ throw pe_exception("Error reading IMAGE_NT_HEADERS", pe_exception::error_reading_image_nt_headers);
+
+ //Check NT headers signature
+ if(nt_headers.Signature != 0x4550) //"PE"
+ throw pe_exception("Incorrect PE signature", pe_exception::pe_signature_incorrect);
+
+ //Check NT headers magic
+ if(nt_headers.OptionalHeader.Magic != image_nt_optional_hdr32_magic && nt_headers.OptionalHeader.Magic != image_nt_optional_hdr64_magic)
+ throw pe_exception("Incorrect PE signature", pe_exception::pe_signature_incorrect);
+ }
+ catch(const std::exception&)
+ {
+ //If something went wrong, restore istream state
+ file.exceptions(state);
+ file.seekg(old_offset);
+ file.clear();
+ //Retrhow exception
+ throw;
+ }
+
+ //Restore stream state
+ file.exceptions(state);
+ file.seekg(old_offset);
+ file.clear();
+
+ //Determine PE type and return it
+ return nt_headers.OptionalHeader.Magic == image_nt_optional_hdr64_magic ? pe_type_64 : pe_type_32;
+}
+
+//Returns true if image has overlay data at the end of file
+bool pe_base::has_overlay() const
+{
+ return has_overlay_;
+}
+
+//Clears PE characteristics flag
+void pe_base::clear_characteristics_flags(uint16_t flags)
+{
+ set_characteristics(get_characteristics() & ~flags);
+}
+
+//Sets PE characteristics flag
+void pe_base::set_characteristics_flags(uint16_t flags)
+{
+ set_characteristics(get_characteristics() | flags);
+}
+
+//Returns true if PE characteristics flag set
+bool pe_base::check_characteristics_flag(uint16_t flag) const
+{
+ return (get_characteristics() & flag) ? true : false;
+}
+
+//Returns subsystem value
+uint16_t pe_base::get_subsystem() const
+{
+ return props_->get_subsystem();
+}
+
+//Sets subsystem value
+void pe_base::set_subsystem(uint16_t subsystem)
+{
+ props_->set_subsystem(subsystem);
+}
+
+//Returns true if image has console subsystem
+bool pe_base::is_console() const
+{
+ return get_subsystem() == image_subsystem_windows_cui;
+}
+
+//Returns true if image has Windows GUI subsystem
+bool pe_base::is_gui() const
+{
+ return get_subsystem() == image_subsystem_windows_gui;
+}
+
+//Sets required operation system version
+void pe_base::set_os_version(uint16_t major, uint16_t minor)
+{
+ props_->set_os_version(major, minor);
+}
+
+//Returns required operation system version (minor word)
+uint16_t pe_base::get_minor_os_version() const
+{
+ return props_->get_minor_os_version();
+}
+
+//Returns required operation system version (major word)
+uint16_t pe_base::get_major_os_version() const
+{
+ return props_->get_major_os_version();
+}
+
+//Sets required subsystem version
+void pe_base::set_subsystem_version(uint16_t major, uint16_t minor)
+{
+ props_->set_subsystem_version(major, minor);
+}
+
+//Returns required subsystem version (minor word)
+uint16_t pe_base::get_minor_subsystem_version() const
+{
+ return props_->get_minor_subsystem_version();
+}
+
+//Returns required subsystem version (major word)
+uint16_t pe_base::get_major_subsystem_version() const
+{
+ return props_->get_major_subsystem_version();
+}
+
+//Returns corresponding section data pointer from VA inside section "s" for PE32 (checks bounds)
+char* pe_base::section_data_from_va(section& s, uint32_t va) //Always returns raw data
+{
+ return section_data_from_rva(s, va_to_rva(va));
+}
+
+//Returns corresponding section data pointer from VA inside section "s" for PE32 (checks bounds)
+const char* pe_base::section_data_from_va(const section& s, uint32_t va, section_data_type datatype) const
+{
+ return section_data_from_rva(s, va_to_rva(va), datatype);
+}
+
+//Returns corresponding section data pointer from VA inside section for PE32
+char* pe_base::section_data_from_va(uint32_t va, bool include_headers) //Always returns raw data
+{
+ return section_data_from_rva(va_to_rva(va), include_headers);
+}
+
+//Returns corresponding section data pointer from VA inside section for PE32
+const char* pe_base::section_data_from_va(uint32_t va, section_data_type datatype, bool include_headers) const
+{
+ return section_data_from_rva(va_to_rva(va), datatype, include_headers);
+}
+
+//Returns corresponding section data pointer from VA inside section "s" for PE32/PE64 (checks bounds)
+char* pe_base::section_data_from_va(section& s, uint64_t va) //Always returns raw data
+{
+ return section_data_from_rva(s, va_to_rva(va));
+}
+
+//Returns corresponding section data pointer from VA inside section "s" for PE32/PE64 (checks bounds)
+const char* pe_base::section_data_from_va(const section& s, uint64_t va, section_data_type datatype) const
+{
+ return section_data_from_rva(s, va_to_rva(va), datatype);
+}
+
+//Returns corresponding section data pointer from VA inside section for PE32/PE64
+char* pe_base::section_data_from_va(uint64_t va, bool include_headers) //Always returns raw data
+{
+ return section_data_from_rva(va_to_rva(va), include_headers);
+}
+
+//Returns corresponding section data pointer from VA inside section for PE32/PE64
+const char* pe_base::section_data_from_va(uint64_t va, section_data_type datatype, bool include_headers) const
+{
+ return section_data_from_rva(va_to_rva(va), datatype, include_headers);
+}
+
+//Returns section from VA inside it for PE32
+section& pe_base::section_from_va(uint32_t va)
+{
+ return section_from_rva(va_to_rva(va));
+}
+
+//Returns section from VA inside it for PE32/PE64
+section& pe_base::section_from_va(uint64_t va)
+{
+ return section_from_rva(va_to_rva(va));
+}
+
+//Returns section from RVA inside it for PE32
+const section& pe_base::section_from_va(uint32_t va) const
+{
+ return section_from_rva(va_to_rva(va));
+}
+
+//Returns section from RVA inside it for PE32/PE64
+const section& pe_base::section_from_va(uint64_t va) const
+{
+ return section_from_rva(va_to_rva(va));
+}
+
+uint32_t pe_base::va_to_rva(uint32_t va, bool bound_check) const
+{
+ return props_->va_to_rva(va, bound_check);
+}
+
+uint32_t pe_base::va_to_rva(uint64_t va, bool bound_check) const
+{
+ return props_->va_to_rva(va, bound_check);
+}
+
+uint32_t pe_base::rva_to_va_32(uint32_t rva) const
+{
+ return props_->rva_to_va_32(rva);
+}
+
+uint64_t pe_base::rva_to_va_64(uint32_t rva) const
+{
+ return props_->rva_to_va_64(rva);
+}
+
+//Relative Virtual Address (RVA) to Virtual Address (VA) convertion for PE32
+void pe_base::rva_to_va(uint32_t rva, uint32_t& va) const
+{
+ va = rva_to_va_32(rva);
+}
+
+//Relative Virtual Address (RVA) to Virtual Address (VA) convertions for PE32/PE64
+void pe_base::rva_to_va(uint32_t rva, uint64_t& va) const
+{
+ va = rva_to_va_64(rva);
+}
+
+//Returns section from file offset (4gb max)
+section& pe_base::section_from_file_offset(uint32_t offset)
+{
+ return *file_offset_to_section(offset);
+}
+
+//Returns section from file offset (4gb max)
+const section& pe_base::section_from_file_offset(uint32_t offset) const
+{
+ return *file_offset_to_section(offset);
+}
+
+//Returns section and offset (raw data only) from its start from RVA
+const std::pair<uint32_t, const section*> pe_base::section_and_offset_from_rva(uint32_t rva) const
+{
+ const section& s = section_from_rva(rva);
+ return std::make_pair(rva - s.get_virtual_address(), &s);
+}
+
+//Returns DLL Characteristics
+uint16_t pe_base::get_dll_characteristics() const
+{
+ return props_->get_dll_characteristics();
+}
+
+//Sets DLL Characteristics
+void pe_base::set_dll_characteristics(uint16_t characteristics)
+{
+ props_->set_dll_characteristics(characteristics);
+}
+
+//Returns size of headers
+uint32_t pe_base::get_size_of_headers() const
+{
+ return props_->get_size_of_headers();
+}
+
+//Returns size of optional header
+uint16_t pe_base::get_size_of_optional_header() const
+{
+ return props_->get_size_of_optional_header();
+}
+
+//Returns PE signature
+uint32_t pe_base::get_pe_signature() const
+{
+ return props_->get_pe_signature();
+}
+
+//Returns magic value
+uint32_t pe_base::get_magic() const
+{
+ return props_->get_magic();
+}
+
+//Returns image base for PE32
+void pe_base::get_image_base(uint32_t& base) const
+{
+ base = get_image_base_32();
+}
+
+//Returns image base for PE32 and PE64 respectively
+uint32_t pe_base::get_image_base_32() const
+{
+ return props_->get_image_base_32();
+}
+
+//Sets image base for PE32 and PE64 respectively
+uint64_t pe_base::get_image_base_64() const
+{
+ return props_->get_image_base_64();
+}
+
+//RVA to RAW file offset convertion (4gb max)
+uint32_t pe_base::rva_to_file_offset(uint32_t rva) const
+{
+ //Maybe, RVA is inside PE headers
+ if(rva < get_size_of_headers())
+ return rva;
+
+ const section& s = section_from_rva(rva);
+ return s.get_pointer_to_raw_data() + rva - s.get_virtual_address();
+}
+
+//RAW file offset to RVA convertion (4gb max)
+uint32_t pe_base::file_offset_to_rva(uint32_t offset) const
+{
+ //Maybe, offset is inside PE headers
+ if(offset < get_size_of_headers())
+ return offset;
+
+ const section_list::const_iterator it = file_offset_to_section(offset);
+ return offset - (*it).get_pointer_to_raw_data() + (*it).get_virtual_address();
+}
+
+//RAW file offset to section convertion helper (4gb max)
+section_list::const_iterator pe_base::file_offset_to_section(uint32_t offset) const
+{
+ section_list::const_iterator it = std::find_if(sections_.begin(), sections_.end(), section_by_raw_offset(offset));
+ if(it == sections_.end())
+ throw pe_exception("No section found by presented file offset", pe_exception::no_section_found);
+
+ return it;
+}
+
+//RAW file offset to section convertion helper (4gb max)
+section_list::iterator pe_base::file_offset_to_section(uint32_t offset)
+{
+ section_list::iterator it = std::find_if(sections_.begin(), sections_.end(), section_by_raw_offset(offset));
+ if(it == sections_.end())
+ throw pe_exception("No section found by presented file offset", pe_exception::no_section_found);
+
+ return it;
+}
+
+//RVA from section raw data offset
+uint32_t pe_base::rva_from_section_offset(const section& s, uint32_t raw_offset_from_section_start)
+{
+ return s.get_virtual_address() + raw_offset_from_section_start;
+}
+
+//Returns image base for PE32/PE64
+void pe_base::get_image_base(uint64_t& base) const
+{
+ base = get_image_base_64();
+}
+
+//Sets new image base
+void pe_base::set_image_base(uint32_t base)
+{
+ props_->set_image_base(base);
+}
+
+void pe_base::set_image_base_64(uint64_t base)
+{
+ props_->set_image_base_64(base);
+}
+
+//Sets heap size commit for PE32 and PE64 respectively
+void pe_base::set_heap_size_commit(uint32_t size)
+{
+ props_->set_heap_size_commit(size);
+}
+
+void pe_base::set_heap_size_commit(uint64_t size)
+{
+ props_->set_heap_size_commit(size);
+}
+
+//Sets heap size reserve for PE32 and PE64 respectively
+void pe_base::set_heap_size_reserve(uint32_t size)
+{
+ props_->set_heap_size_reserve(size);
+}
+
+void pe_base::set_heap_size_reserve(uint64_t size)
+{
+ props_->set_heap_size_reserve(size);
+}
+
+//Sets stack size commit for PE32 and PE64 respectively
+void pe_base::set_stack_size_commit(uint32_t size)
+{
+ props_->set_stack_size_commit(size);
+}
+
+void pe_base::set_stack_size_commit(uint64_t size)
+{
+ props_->set_stack_size_commit(size);
+}
+
+//Sets stack size reserve for PE32 and PE64 respectively
+void pe_base::set_stack_size_reserve(uint32_t size)
+{
+ props_->set_stack_size_reserve(size);
+}
+
+void pe_base::set_stack_size_reserve(uint64_t size)
+{
+ props_->set_stack_size_reserve(size);
+}
+
+//Returns heap size commit for PE32 and PE64 respectively
+uint32_t pe_base::get_heap_size_commit_32() const
+{
+ return props_->get_heap_size_commit_32();
+}
+
+uint64_t pe_base::get_heap_size_commit_64() const
+{
+ return props_->get_heap_size_commit_64();
+}
+
+//Returns heap size reserve for PE32 and PE64 respectively
+uint32_t pe_base::get_heap_size_reserve_32() const
+{
+ return props_->get_heap_size_reserve_32();
+}
+
+uint64_t pe_base::get_heap_size_reserve_64() const
+{
+ return props_->get_heap_size_reserve_64();
+}
+
+//Returns stack size commit for PE32 and PE64 respectively
+uint32_t pe_base::get_stack_size_commit_32() const
+{
+ return props_->get_stack_size_commit_32();
+}
+
+uint64_t pe_base::get_stack_size_commit_64() const
+{
+ return props_->get_stack_size_commit_64();
+}
+
+//Returns stack size reserve for PE32 and PE64 respectively
+uint32_t pe_base::get_stack_size_reserve_32() const
+{
+ return props_->get_stack_size_reserve_32();
+}
+
+uint64_t pe_base::get_stack_size_reserve_64() const
+{
+ return props_->get_stack_size_reserve_64();
+}
+
+//Returns heap size commit for PE32
+void pe_base::get_heap_size_commit(uint32_t& size) const
+{
+ size = get_heap_size_commit_32();
+}
+
+//Returns heap size commit for PE32/PE64
+void pe_base::get_heap_size_commit(uint64_t& size) const
+{
+ size = get_heap_size_commit_64();
+}
+
+//Returns heap size reserve for PE32
+void pe_base::get_heap_size_reserve(uint32_t& size) const
+{
+ size = get_heap_size_reserve_32();
+}
+
+//Returns heap size reserve for PE32/PE64
+void pe_base::get_heap_size_reserve(uint64_t& size) const
+{
+ size = get_heap_size_reserve_64();
+}
+
+//Returns stack size commit for PE32
+void pe_base::get_stack_size_commit(uint32_t& size) const
+{
+ size = get_stack_size_commit_32();
+}
+
+//Returns stack size commit for PE32/PE64
+void pe_base::get_stack_size_commit(uint64_t& size) const
+{
+ size = get_stack_size_commit_64();
+}
+
+//Returns stack size reserve for PE32
+void pe_base::get_stack_size_reserve(uint32_t& size) const
+{
+ size = get_stack_size_reserve_32();
+}
+
+//Returns stack size reserve for PE32/PE64
+void pe_base::get_stack_size_reserve(uint64_t& size) const
+{
+ size = get_stack_size_reserve_64();
+}
+
+//Realigns file (changes file alignment)
+void pe_base::realign_file(uint32_t new_file_alignment)
+{
+ //Checks alignment for correctness
+ set_file_alignment(new_file_alignment);
+ realign_all_sections();
+}
+
+//Helper function to recalculate RAW and virtual section sizes and strip it, if necessary
+void pe_base::recalculate_section_sizes(section& s, bool auto_strip)
+{
+ prepare_section(s); //Recalculate section raw addresses
+
+ //Strip RAW size of section, if it is the last one
+ //For all others it must be file-aligned and calculated by prepare_section() call
+ if(auto_strip && !(sections_.empty() || &s == &*(sections_.end() - 1)))
+ {
+ //Strip ending raw data nullbytes to optimize size
+ std::string& raw_data = s.get_raw_data();
+ if(!raw_data.empty())
+ {
+ std::string::size_type i = raw_data.length();
+ for(; i != 1; --i)
+ {
+ if(raw_data[i - 1] != 0)
+ break;
+ }
+
+ raw_data.resize(i);
+ }
+
+ s.set_size_of_raw_data(static_cast<uint32_t>(raw_data.length()));
+ }
+
+ //Can occur only for last section
+ if(pe_utils::align_up(s.get_virtual_size(), get_section_alignment()) < pe_utils::align_up(s.get_size_of_raw_data(), get_file_alignment()))
+ set_section_virtual_size(s, pe_utils::align_up(s.get_size_of_raw_data(), get_section_alignment())); //Recalculate section virtual size
+}
+
+//Returns data from the beginning of image
+//Size = SizeOfHeaders
+const std::string& pe_base::get_full_headers_data() const
+{
+ return full_headers_data_;
+}
+
+const pe_base::debug_data_list& pe_base::get_raw_debug_data_list() const
+{
+ return debug_data_;
+}
+
+//Sets number of sections
+void pe_base::set_number_of_sections(uint16_t number)
+{
+ props_->set_number_of_sections(number);
+}
+
+//Sets size of image
+void pe_base::set_size_of_image(uint32_t size)
+{
+ props_->set_size_of_image(size);
+}
+
+//Sets size of headers
+void pe_base::set_size_of_headers(uint32_t size)
+{
+ props_->set_size_of_headers(size);
+}
+
+//Sets size of optional headers
+void pe_base::set_size_of_optional_header(uint16_t size)
+{
+ props_->set_size_of_optional_header(size);
+}
+
+//Returns nt headers data pointer
+char* pe_base::get_nt_headers_ptr()
+{
+ return props_->get_nt_headers_ptr();
+}
+
+//Returns nt headers data pointer
+const char* pe_base::get_nt_headers_ptr() const
+{
+ return props_->get_nt_headers_ptr();
+}
+
+//Returns sizeof() nt headers
+uint32_t pe_base::get_sizeof_nt_header() const
+{
+ return props_->get_sizeof_nt_header();
+}
+
+//Returns sizeof() optional headers
+uint32_t pe_base::get_sizeof_opt_headers() const
+{
+ return props_->get_sizeof_opt_headers();
+}
+
+//Sets file alignment (no checks)
+void pe_base::set_file_alignment_unchecked(uint32_t alignment)
+{
+ props_->set_file_alignment_unchecked(alignment);
+}
+
+//Sets base of code
+void pe_base::set_base_of_code(uint32_t base)
+{
+ props_->set_base_of_code(base);
+}
+
+//Returns base of code
+uint32_t pe_base::get_base_of_code() const
+{
+ return props_->get_base_of_code();
+}
+
+//Returns needed magic of image
+uint32_t pe_base::get_needed_magic() const
+{
+ return props_->get_needed_magic();
+}
+}
diff --git a/tools/pe_bliss/pe_base.h b/tools/pe_bliss/pe_base.h
new file mode 100644
index 0000000000..b5416cf1e2
--- /dev/null
+++ b/tools/pe_bliss/pe_base.h
@@ -0,0 +1,544 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <string>
+#include <vector>
+#include <istream>
+#include <ostream>
+#include <map>
+#include "pe_exception.h"
+#include "pe_structures.h"
+#include "utils.h"
+#include "pe_section.h"
+#include "pe_properties.h"
+
+//Please don't remove this information from header
+//PEBliss 1.0.0
+//(c) DX 2011 - 2012, http://kaimi.ru
+//Free to use for commertial and non-commertial purposes, modification and distribution
+
+// == more important ==
+//TODO: compact import rebuilder
+//TODO: remove sections in the middle
+//== less important ==
+//TODO: relocations that take more than one element (seems to be not possible in Windows PE, but anyway)
+//TODO: delay import directory
+//TODO: write message tables
+//TODO: write string tables
+//TODO: read security information
+//TODO: read full .NET information
+
+namespace pe_bliss
+{
+//Portable executable class
+class pe_base
+{
+public: //CONSTRUCTORS
+ //Constructor from stream
+ pe_base(std::istream& file, const pe_properties& props, bool read_debug_raw_data = true);
+
+ //Constructor of empty PE-file
+ explicit pe_base(const pe_properties& props, uint32_t section_alignment = 0x1000, bool dll = false, uint16_t subsystem = pe_win::image_subsystem_windows_gui);
+
+ pe_base(const pe_base& pe);
+ pe_base& operator=(const pe_base& pe);
+
+public:
+ ~pe_base();
+
+public: //STUB
+ //Strips stub MSVS overlay, if any
+ void strip_stub_overlay();
+ //Fills stub MSVS overlay with specified byte
+ void fill_stub_overlay(char c);
+ //Sets stub MSVS overlay
+ void set_stub_overlay(const std::string& data);
+ //Returns stub overlay contents
+ const std::string& get_stub_overlay() const;
+
+
+public: //DIRECTORIES
+ //Returns true if directory exists
+ bool directory_exists(uint32_t id) const;
+ //Removes directory
+ void remove_directory(uint32_t id);
+
+ //Returns directory RVA
+ uint32_t get_directory_rva(uint32_t id) const;
+ //Returns directory size
+ uint32_t get_directory_size(uint32_t id) const;
+
+ //Sets directory RVA (just a value of PE header, no moving occurs)
+ void set_directory_rva(uint32_t id, uint32_t rva);
+ //Sets directory size (just a value of PE header, no moving occurs)
+ void set_directory_size(uint32_t id, uint32_t size);
+
+ //Strips only zero DATA_DIRECTORY entries to count = min_count
+ //Returns resulting number of data directories
+ //strip_iat_directory - if true, even not empty IAT directory will be stripped
+ uint32_t strip_data_directories(uint32_t min_count = 1, bool strip_iat_directory = true);
+
+ //Returns true if image has import directory
+ bool has_imports() const;
+ //Returns true if image has export directory
+ bool has_exports() const;
+ //Returns true if image has resource directory
+ bool has_resources() const;
+ //Returns true if image has security directory
+ bool has_security() const;
+ //Returns true if image has relocations
+ bool has_reloc() const;
+ //Returns true if image has TLS directory
+ bool has_tls() const;
+ //Returns true if image has config directory
+ bool has_config() const;
+ //Returns true if image has bound import directory
+ bool has_bound_import() const;
+ //Returns true if image has delay import directory
+ bool has_delay_import() const;
+ //Returns true if image has COM directory
+ bool is_dotnet() const;
+ //Returns true if image has exception directory
+ bool has_exception_directory() const;
+ //Returns true if image has debug directory
+ bool has_debug() const;
+
+ //Returns subsystem value
+ uint16_t get_subsystem() const;
+ //Sets subsystem value
+ void set_subsystem(uint16_t subsystem);
+ //Returns true if image has console subsystem
+ bool is_console() const;
+ //Returns true if image has Windows GUI subsystem
+ bool is_gui() const;
+
+ //Sets required operation system version
+ void set_os_version(uint16_t major, uint16_t minor);
+ //Returns required operation system version (minor word)
+ uint16_t get_minor_os_version() const;
+ //Returns required operation system version (major word)
+ uint16_t get_major_os_version() const;
+
+ //Sets required subsystem version
+ void set_subsystem_version(uint16_t major, uint16_t minor);
+ //Returns required subsystem version (minor word)
+ uint16_t get_minor_subsystem_version() const;
+ //Returns required subsystem version (major word)
+ uint16_t get_major_subsystem_version() const;
+
+public: //PE HEADER
+ //Returns DOS header
+ const pe_win::image_dos_header& get_dos_header() const;
+ pe_win::image_dos_header& get_dos_header();
+
+ //Returns PE header start (e_lfanew)
+ int32_t get_pe_header_start() const;
+
+ //Returns file alignment
+ uint32_t get_file_alignment() const;
+ //Sets file alignment, checking the correctness of its value
+ void set_file_alignment(uint32_t alignment);
+
+ //Returns size of image
+ uint32_t get_size_of_image() const;
+
+ //Returns image entry point
+ uint32_t get_ep() const;
+ //Sets image entry point (just a value of PE header)
+ void set_ep(uint32_t new_ep);
+
+ //Returns number of RVA and sizes (number of DATA_DIRECTORY entries)
+ uint32_t get_number_of_rvas_and_sizes() const;
+ //Sets number of RVA and sizes (number of DATA_DIRECTORY entries)
+ void set_number_of_rvas_and_sizes(uint32_t number);
+
+ //Returns PE characteristics
+ uint16_t get_characteristics() const;
+ //Sets PE characteristics (a value inside header)
+ void set_characteristics(uint16_t ch);
+ //Clears PE characteristics flag
+ void clear_characteristics_flags(uint16_t flags);
+ //Sets PE characteristics flag
+ void set_characteristics_flags(uint16_t flags);
+ //Returns true if PE characteristics flag set
+ bool check_characteristics_flag(uint16_t flag) const;
+
+ //Returns DLL Characteristics
+ uint16_t get_dll_characteristics() const;
+ //Sets DLL Characteristics
+ void set_dll_characteristics(uint16_t characteristics);
+
+ //Returns size of headers
+ uint32_t get_size_of_headers() const;
+ //Returns size of optional header
+ uint16_t get_size_of_optional_header() const;
+
+ //Returns PE signature
+ uint32_t get_pe_signature() const;
+
+ //Returns magic value
+ uint32_t get_magic() const;
+
+ //Returns image base for PE32 and PE64 respectively
+ uint32_t get_image_base_32() const;
+ void get_image_base(uint32_t& base) const;
+ //Sets image base for PE32 and PE64 respectively
+ uint64_t get_image_base_64() const;
+ void get_image_base(uint64_t& base) const;
+
+ //Sets new image base
+ void set_image_base(uint32_t base);
+ void set_image_base_64(uint64_t base);
+
+ //Sets heap size commit for PE32 and PE64 respectively
+ void set_heap_size_commit(uint32_t size);
+ void set_heap_size_commit(uint64_t size);
+ //Sets heap size reserve for PE32 and PE64 respectively
+ void set_heap_size_reserve(uint32_t size);
+ void set_heap_size_reserve(uint64_t size);
+ //Sets stack size commit for PE32 and PE64 respectively
+ void set_stack_size_commit(uint32_t size);
+ void set_stack_size_commit(uint64_t size);
+ //Sets stack size reserve for PE32 and PE64 respectively
+ void set_stack_size_reserve(uint32_t size);
+ void set_stack_size_reserve(uint64_t size);
+
+ //Returns heap size commit for PE32 and PE64 respectively
+ uint32_t get_heap_size_commit_32() const;
+ void get_heap_size_commit(uint32_t& size) const;
+ uint64_t get_heap_size_commit_64() const;
+ void get_heap_size_commit(uint64_t& size) const;
+ //Returns heap size reserve for PE32 and PE64 respectively
+ uint32_t get_heap_size_reserve_32() const;
+ void get_heap_size_reserve(uint32_t& size) const;
+ uint64_t get_heap_size_reserve_64() const;
+ void get_heap_size_reserve(uint64_t& size) const;
+ //Returns stack size commit for PE32 and PE64 respectively
+ uint32_t get_stack_size_commit_32() const;
+ void get_stack_size_commit(uint32_t& size) const;
+ uint64_t get_stack_size_commit_64() const;
+ void get_stack_size_commit(uint64_t& size) const;
+ //Returns stack size reserve for PE32 and PE64 respectively
+ uint32_t get_stack_size_reserve_32() const;
+ void get_stack_size_reserve(uint32_t& size) const;
+ uint64_t get_stack_size_reserve_64() const;
+ void get_stack_size_reserve(uint64_t& size) const;
+
+ //Updates virtual size of image corresponding to section virtual sizes
+ void update_image_size();
+
+ //Returns checksum of PE file from header
+ uint32_t get_checksum() const;
+ //Sets checksum of PE file
+ void set_checksum(uint32_t checksum);
+
+ //Returns timestamp of PE file from header
+ uint32_t get_time_date_stamp() const;
+ //Sets timestamp of PE file
+ void set_time_date_stamp(uint32_t timestamp);
+
+ //Returns Machine field value of PE file from header
+ uint16_t get_machine() const;
+ //Sets Machine field value of PE file
+ void set_machine(uint16_t machine);
+
+ //Returns data from the beginning of image
+ //Size = SizeOfHeaders
+ const std::string& get_full_headers_data() const;
+
+ typedef std::multimap<uint32_t, std::string> debug_data_list;
+ //Returns raw list of debug data
+ const debug_data_list& get_raw_debug_data_list() const;
+
+ //Reads and checks DOS header
+ static void read_dos_header(std::istream& file, pe_win::image_dos_header& header);
+
+ //Returns sizeof() nt headers
+ uint32_t get_sizeof_nt_header() const;
+ //Returns sizeof() optional headers
+ uint32_t get_sizeof_opt_headers() const;
+ //Returns raw nt headers data pointer
+ const char* get_nt_headers_ptr() const;
+
+ //Sets size of headers (to NT headers)
+ void set_size_of_headers(uint32_t size);
+ //Sets size of optional headers (to NT headers)
+ void set_size_of_optional_header(uint16_t size);
+
+ //Sets base of code
+ void set_base_of_code(uint32_t base);
+ //Returns base of code
+ uint32_t get_base_of_code() const;
+
+public: //ADDRESS CONVERTIONS
+ //Virtual Address (VA) to Relative Virtual Address (RVA) convertions
+ //for PE32 and PE64 respectively
+ //bound_check checks integer overflow
+ uint32_t va_to_rva(uint32_t va, bool bound_check = true) const;
+ uint32_t va_to_rva(uint64_t va, bool bound_check = true) const;
+
+ //Relative Virtual Address (RVA) to Virtual Address (VA) convertions
+ //for PE32 and PE64 respectively
+ uint32_t rva_to_va_32(uint32_t rva) const;
+ void rva_to_va(uint32_t rva, uint32_t& va) const;
+ uint64_t rva_to_va_64(uint32_t rva) const;
+ void rva_to_va(uint32_t rva, uint64_t& va) const;
+
+ //RVA to RAW file offset convertion (4gb max)
+ uint32_t rva_to_file_offset(uint32_t rva) const;
+ //RAW file offset to RVA convertion (4gb max)
+ uint32_t file_offset_to_rva(uint32_t offset) const;
+
+ //RVA from section raw data offset
+ static uint32_t rva_from_section_offset(const section& s, uint32_t raw_offset_from_section_start);
+
+public: //IMAGE SECTIONS
+ //Returns number of sections from PE header
+ uint16_t get_number_of_sections() const;
+
+ //Updates number of sections in PE header
+ uint16_t update_number_of_sections();
+
+ //Returns section alignment
+ uint32_t get_section_alignment() const;
+
+ //Returns section list
+ section_list& get_image_sections();
+ const section_list& get_image_sections() const;
+
+ //Realigns all sections, if you made any changes to sections or alignments
+ void realign_all_sections();
+ //Resligns section with specified index
+ void realign_section(uint32_t index);
+
+ //Returns section from RVA inside it
+ section& section_from_rva(uint32_t rva);
+ const section& section_from_rva(uint32_t rva) const;
+ //Returns section from directory ID
+ section& section_from_directory(uint32_t directory_id);
+ const section& section_from_directory(uint32_t directory_id) const;
+ //Returns section from VA inside it for PE32 and PE64 respectively
+ section& section_from_va(uint32_t va);
+ const section& section_from_va(uint32_t va) const;
+ section& section_from_va(uint64_t va);
+ const section& section_from_va(uint64_t va) const;
+ //Returns section from file offset (4gb max)
+ section& section_from_file_offset(uint32_t offset);
+ const section& section_from_file_offset(uint32_t offset) const;
+
+ //Returns section TOTAL RAW/VIRTUAL data length from RVA inside section
+ //If include_headers = true, data from the beginning of PE file to SizeOfHeaders will be searched, too
+ uint32_t section_data_length_from_rva(uint32_t rva, section_data_type datatype = section_data_raw, bool include_headers = false) const;
+ //Returns section TOTAL RAW/VIRTUAL data length from VA inside section for PE32 and PE64 respectively
+ //If include_headers = true, data from the beginning of PE file to SizeOfHeaders will be searched, too
+ uint32_t section_data_length_from_va(uint32_t va, section_data_type datatype = section_data_raw, bool include_headers = false) const;
+ uint32_t section_data_length_from_va(uint64_t va, section_data_type datatype = section_data_raw, bool include_headers = false) const;
+
+ //Returns section remaining RAW/VIRTUAL data length from RVA to the end of section "s" (checks bounds)
+ uint32_t section_data_length_from_rva(const section& s, uint32_t rva_inside, section_data_type datatype = section_data_raw) const;
+ //Returns section remaining RAW/VIRTUAL data length from VA to the end of section "s" for PE32 and PE64 respectively (checks bounds)
+ uint32_t section_data_length_from_va(const section& s, uint64_t va_inside, section_data_type datatype = section_data_raw) const;
+ uint32_t section_data_length_from_va(const section& s, uint32_t va_inside, section_data_type datatype = section_data_raw) const;
+
+ //Returns section remaining RAW/VIRTUAL data length from RVA "rva_inside" to the end of section containing RVA "rva"
+ //If include_headers = true, data from the beginning of PE file to SizeOfHeaders will be searched, too
+ uint32_t section_data_length_from_rva(uint32_t rva, uint32_t rva_inside, section_data_type datatype = section_data_raw, bool include_headers = false) const;
+ //Returns section remaining RAW/VIRTUAL data length from VA "va_inside" to the end of section containing VA "va" for PE32 and PE64 respectively
+ //If include_headers = true, data from the beginning of PE file to SizeOfHeaders will be searched, too
+ uint32_t section_data_length_from_va(uint32_t va, uint32_t va_inside, section_data_type datatype = section_data_raw, bool include_headers = false) const;
+ uint32_t section_data_length_from_va(uint64_t va, uint64_t va_inside, section_data_type datatype = section_data_raw, bool include_headers = false) const;
+
+ //If include_headers = true, data from the beginning of PE file to SizeOfHeaders will be searched, too
+ //Returns corresponding section data pointer from RVA inside section
+ char* section_data_from_rva(uint32_t rva, bool include_headers = false);
+ const char* section_data_from_rva(uint32_t rva, section_data_type datatype = section_data_raw, bool include_headers = false) const;
+ //Returns corresponding section data pointer from VA inside section for PE32 and PE64 respectively
+ char* section_data_from_va(uint32_t va, bool include_headers = false);
+ const char* section_data_from_va(uint32_t va, section_data_type datatype = section_data_raw, bool include_headers = false) const;
+ char* section_data_from_va(uint64_t va, bool include_headers = false);
+ const char* section_data_from_va(uint64_t va, section_data_type datatype = section_data_raw, bool include_headers = false) const;
+
+ //Returns corresponding section data pointer from RVA inside section "s" (checks bounds)
+ char* section_data_from_rva(section& s, uint32_t rva);
+ const char* section_data_from_rva(const section& s, uint32_t rva, section_data_type datatype = section_data_raw) const;
+ //Returns corresponding section data pointer from VA inside section "s" for PE32 and PE64 respectively (checks bounds)
+ char* section_data_from_va(section& s, uint32_t va); //Always returns raw data
+ const char* section_data_from_va(const section& s, uint32_t va, section_data_type datatype = section_data_raw) const;
+ char* section_data_from_va(section& s, uint64_t va); //Always returns raw data
+ const char* section_data_from_va(const section& s, uint64_t va, section_data_type datatype = section_data_raw) const;
+
+ //Returns corresponding section data pointer from RVA inside section "s" (checks bounds, checks sizes, the most safe function)
+ template<typename T>
+ T section_data_from_rva(const section& s, uint32_t rva, section_data_type datatype = section_data_raw) const
+ {
+ if(rva >= s.get_virtual_address() && rva < s.get_virtual_address() + s.get_aligned_virtual_size(get_section_alignment()) && pe_utils::is_sum_safe(rva, sizeof(T)))
+ {
+ const std::string& data = datatype == section_data_raw ? s.get_raw_data() : s.get_virtual_data(get_section_alignment());
+ //Don't check for underflow here, comparsion is unsigned
+ if(data.size() < rva - s.get_virtual_address() + sizeof(T))
+ throw pe_exception("RVA and requested data size does not exist inside section", pe_exception::rva_not_exists);
+
+ return *reinterpret_cast<const T*>(data.data() + rva - s.get_virtual_address());
+ }
+
+ throw pe_exception("RVA not found inside section", pe_exception::rva_not_exists);
+ }
+
+ //Returns corresponding section data pointer from RVA inside section (checks rva, checks sizes, the most safe function)
+ //If include_headers = true, data from the beginning of PE file to SizeOfHeaders will be searched, too
+ template<typename T>
+ T section_data_from_rva(uint32_t rva, section_data_type datatype = section_data_raw, bool include_headers = false) const
+ {
+ //if RVA is inside of headers and we're searching them too...
+ if(include_headers && pe_utils::is_sum_safe(rva, sizeof(T)) && (rva + sizeof(T) < full_headers_data_.length()))
+ return *reinterpret_cast<const T*>(&full_headers_data_[rva]);
+
+ const section& s = section_from_rva(rva);
+ const std::string& data = datatype == section_data_raw ? s.get_raw_data() : s.get_virtual_data(get_section_alignment());
+ //Don't check for underflow here, comparsion is unsigned
+ if(data.size() < rva - s.get_virtual_address() + sizeof(T))
+ throw pe_exception("RVA and requested data size does not exist inside section", pe_exception::rva_not_exists);
+
+ return *reinterpret_cast<const T*>(data.data() + rva - s.get_virtual_address());
+ }
+
+ //Returns corresponding section data pointer from VA inside section "s" (checks bounds, checks sizes, the most safe function)
+ template<typename T>
+ T section_data_from_va(const section& s, uint32_t va, section_data_type datatype = section_data_raw) const
+ {
+ return section_data_from_rva<T>(s, va_to_rva(va), datatype);
+ }
+
+ template<typename T>
+ T section_data_from_va(const section& s, uint64_t va, section_data_type datatype = section_data_raw) const
+ {
+ return section_data_from_rva<T>(s, va_to_rva(va), datatype);
+ }
+
+ //Returns corresponding section data pointer from VA inside section (checks rva, checks sizes, the most safe function)
+ //If include_headers = true, data from the beginning of PE file to SizeOfHeaders will be searched, too
+ template<typename T>
+ T section_data_from_va(uint32_t va, section_data_type datatype = section_data_raw, bool include_headers = false) const
+ {
+ return section_data_from_rva<T>(va_to_rva(va), datatype, include_headers);
+ }
+
+ template<typename T>
+ T section_data_from_va(uint64_t va, section_data_type datatype = section_data_raw, bool include_headers = false) const
+ {
+ return section_data_from_rva<T>(va_to_rva(va), datatype, include_headers);
+ }
+
+ //Returns section and offset (raw data only) from its start from RVA
+ const std::pair<uint32_t, const section*> section_and_offset_from_rva(uint32_t rva) const;
+
+ //Sets virtual size of section "s"
+ //Section must be free (not bound to any image)
+ //or the last section of this image
+ //Function calls update_image_size automatically in second case
+ void set_section_virtual_size(section& s, uint32_t vsize);
+
+ //Represents section expand type for expand_section function
+ enum section_expand_type
+ {
+ expand_section_raw, //Section raw data size will be expanded
+ expand_section_virtual //Section virtual data size will be expanded
+ };
+
+ //Expands section raw or virtual size to hold data from specified RVA with specified size
+ //Section must be free (not bound to any image)
+ //or the last section of this image
+ //Returns true if section was expanded
+ bool expand_section(section& s, uint32_t needed_rva, uint32_t needed_size, section_expand_type expand);
+
+ //Adds section to image
+ //Returns last section
+ section& add_section(section s);
+ //Prepares section to later add it to image (checks and recalculates virtual and raw section size)
+ //Section must be prepared by this function before calling add_section
+ void prepare_section(section& s);
+
+ //Returns true if sectios "s" is already attached to this PE file
+ bool section_attached(const section& s) const;
+
+
+public: //IMAGE
+ //Returns PE type (PE or PE+) from pe_type enumeration (minimal correctness checks)
+ static pe_type get_pe_type(std::istream& file);
+ //Returns PE type of this image
+ pe_type get_pe_type() const;
+
+ //Returns true if image has overlay data at the end of file
+ bool has_overlay() const;
+
+ //Realigns file (changes file alignment)
+ void realign_file(uint32_t new_file_alignment);
+
+ //Helper function to recalculate RAW and virtual section sizes and strip it, if necessary
+ //auto_strip = strip section, if necessary
+ void recalculate_section_sizes(section& s, bool auto_strip);
+
+ // ========== END OF PUBLIC MEMBERS AND STRUCTURES ========== //
+private:
+ //Image DOS header
+ pe_win::image_dos_header dos_header_;
+ //Rich (stub) overlay data (for MSVS)
+ std::string rich_overlay_;
+ //List of image sections
+ section_list sections_;
+ //True if image has overlay
+ bool has_overlay_;
+ //Raw SizeOfHeaders-sized data from the beginning of image
+ std::string full_headers_data_;
+ //Raw debug data for all directories
+ //PointerToRawData; Data
+ debug_data_list debug_data_;
+ //PE or PE+ related properties
+ pe_properties* props_;
+
+ //Reads and checks DOS header
+ void read_dos_header(std::istream& file);
+
+ //Reads and checks PE headers and section headers, data
+ void read_pe(std::istream& file, bool read_debug_raw_data);
+
+ //Sets number of sections
+ void set_number_of_sections(uint16_t number);
+ //Sets size of image
+ void set_size_of_image(uint32_t size);
+ //Sets file alignment (no checks)
+ void set_file_alignment_unchecked(uint32_t alignment);
+ //Returns needed magic of image
+ uint32_t get_needed_magic() const;
+ //Returns nt headers data pointer
+ char* get_nt_headers_ptr();
+
+private:
+ static const uint16_t maximum_number_of_sections = 0x60;
+ static const uint32_t minimum_file_alignment = 512;
+
+private:
+ //RAW file offset to section convertion helpers (4gb max)
+ section_list::const_iterator file_offset_to_section(uint32_t offset) const;
+ section_list::iterator file_offset_to_section(uint32_t offset);
+};
+}
diff --git a/tools/pe_bliss/pe_bliss.h b/tools/pe_bliss/pe_bliss.h
new file mode 100644
index 0000000000..1a8b430284
--- /dev/null
+++ b/tools/pe_bliss/pe_bliss.h
@@ -0,0 +1,39 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include "pe_base.h"
+#include "pe_rebuilder.h"
+#include "pe_factory.h"
+#include "pe_bound_import.h"
+#include "pe_debug.h"
+#include "pe_dotnet.h"
+#include "pe_exception_directory.h"
+#include "pe_exports.h"
+#include "pe_imports.h"
+#include "pe_load_config.h"
+#include "pe_relocations.h"
+#include "pe_resources.h"
+#include "pe_rich_data.h"
+#include "pe_tls.h"
+#include "pe_properties_generic.h"
+#include "pe_checksum.h"
+#include "entropy.h"
diff --git a/tools/pe_bliss/pe_bliss_godot.cpp b/tools/pe_bliss/pe_bliss_godot.cpp
new file mode 100644
index 0000000000..8297aa1045
--- /dev/null
+++ b/tools/pe_bliss/pe_bliss_godot.cpp
@@ -0,0 +1,118 @@
+#include "pe_bliss/pe_bliss.h"
+#include "pe_bliss/pe_bliss_resources.h"
+#include "core/ustring.h"
+#include "core/dvector.h"
+#include "os/file_access.h"
+
+using namespace pe_bliss;
+
+String pe_bliss_add_resrc(const char* p_path, int version_major, int version_minor,
+ String& company_name, String& file_description,
+ String& legal_copyright, String& version_text,
+ String& product_name, String& godot_version,
+ DVector<uint8_t>& icon_content) {
+ try
+ {
+ pe_base image(pe_factory::create_pe(p_path));
+
+ const section_list& pe_sections = image.get_image_sections();
+ uint32_t end_of_pe = 0;
+ FileAccess *dst;
+ DVector<uint8_t> overlay_data;
+ if(image.has_overlay())
+ {
+ end_of_pe = pe_sections.back().get_pointer_to_raw_data() + pe_sections.back().get_size_of_raw_data();
+ dst=FileAccess::open(p_path,FileAccess::READ);
+ if (dst) {
+ overlay_data.resize(dst->get_len()-end_of_pe);
+ dst->seek(end_of_pe);
+ DVector<uint8_t>::Write overlay_data_write = overlay_data.write();
+ dst->get_buffer(overlay_data_write.ptr(),overlay_data.size());
+ dst->close();
+ memdelete(dst);
+ }
+ }
+ resource_directory root;
+ if(image.has_resources())
+ {
+ root = resource_directory(get_resources(image));
+ }
+ pe_resource_manager res(root);
+ if(image.has_resources())
+ {
+ if(icon_content.size()) {
+ if(res.resource_exists(pe_resource_viewer::resource_icon))
+ {
+ res.remove_resource_type(pe_resource_viewer::resource_icon);
+ }
+ if(res.resource_exists(pe_resource_viewer::resource_icon_group))
+ {
+ res.remove_resource_type(pe_resource_viewer::resource_icon_group);
+ }
+ }
+ if(res.resource_exists(pe_resource_viewer::resource_version))
+ {
+ res.remove_resource_type(pe_resource_viewer::resource_version);
+ }
+ }
+ file_version_info file_info;
+ file_info.set_file_os(file_version_info::file_os_nt_win32);
+ file_info.set_file_type(file_version_info::file_type_application);
+ unsigned int ver = version_major << 16;
+ ver = ver + version_minor;
+ file_info.set_file_version_ms(ver);
+ file_info.set_file_version_ls(0x00000000);
+ file_info.set_product_version_ms(ver);
+ file_info.set_product_version_ls(0x00000000);
+ lang_string_values_map strings;
+ translation_values_map translations;
+ version_info_editor version(strings, translations);
+ version.add_translation(version_info_editor::default_language_translation);
+ version.set_company_name(company_name.c_str());
+ version.set_file_description(file_description.c_str());
+ if (!product_name.empty()) {
+ version.set_internal_name((product_name+String(".exe")).c_str());
+ version.set_original_filename((product_name+String(".exe")).c_str());
+ version.set_product_name(product_name.c_str());
+ }
+ version.set_legal_copyright(legal_copyright.c_str());
+ version.set_product_version(version_text.c_str());
+ if(!godot_version.empty()) version.set_property(L"Godot Engine Version", godot_version.c_str() );
+ resource_version_info_writer(res).set_version_info(file_info, strings, translations, 1033, 1200);
+ if(icon_content.size()) {
+ std::string icon;
+ icon.resize(icon_content.size());
+ for(int i=0; i<icon_content.size(); i++)
+ {
+ icon[i] = icon_content[i];
+ }
+ resource_cursor_icon_writer(res).add_icon(icon, L"MAIN_ICON", 1033);
+ }
+ if(image.has_resources())
+ {
+ rebuild_resources(image, root, image.section_from_directory(pe_win::image_directory_entry_resource));
+ } else {
+ section new_resources;
+ new_resources.get_raw_data().resize(1);
+ new_resources.set_name(".rsrc");
+ new_resources.readable(true);
+ section& attached_section = image.add_section(new_resources);
+ rebuild_resources(image, root, attached_section);
+ }
+ rebuild_pe(image, p_path);
+ if(image.has_overlay() && end_of_pe) {
+ dst=FileAccess::open(p_path,FileAccess::READ_WRITE);
+ if (dst) {
+ dst->seek_end();
+ DVector<uint8_t>::Read overlay_data_read = overlay_data.read();
+ dst->store_buffer(overlay_data_read.ptr(),overlay_data.size());
+ dst->close();
+ memdelete(dst);
+ }
+ }
+ return String();
+ } catch(const pe_exception& e) {
+ String ret("Error In Add rsrc Section : ");
+ return ret + String(e.what());
+ }
+}
diff --git a/tools/pe_bliss/pe_bliss_godot.h b/tools/pe_bliss/pe_bliss_godot.h
new file mode 100644
index 0000000000..0365ca9eaf
--- /dev/null
+++ b/tools/pe_bliss/pe_bliss_godot.h
@@ -0,0 +1,7 @@
+
+
+String pe_bliss_add_resrc(const char* p_path, int version_major, int version_minor,
+ String& company_name, String& file_description,
+ String& legal_copyright, String& version_text,
+ String& product_name, String& godot_version,
+ DVector<uint8_t>& icon_content);
diff --git a/tools/pe_bliss/pe_bliss_resources.h b/tools/pe_bliss/pe_bliss_resources.h
new file mode 100644
index 0000000000..60369f8011
--- /dev/null
+++ b/tools/pe_bliss/pe_bliss_resources.h
@@ -0,0 +1,36 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include "file_version_info.h"
+#include "message_table.h"
+#include "pe_resource_manager.h"
+#include "pe_resource_viewer.h"
+#include "version_info_editor.h"
+#include "version_info_viewer.h"
+#include "resource_bitmap_reader.h"
+#include "resource_bitmap_writer.h"
+#include "resource_cursor_icon_reader.h"
+#include "resource_cursor_icon_writer.h"
+#include "resource_version_info_reader.h"
+#include "resource_version_info_writer.h"
+#include "resource_string_table_reader.h"
+#include "resource_message_list_reader.h"
diff --git a/tools/pe_bliss/pe_bound_import.cpp b/tools/pe_bliss/pe_bound_import.cpp
new file mode 100644
index 0000000000..4b54b36105
--- /dev/null
+++ b/tools/pe_bliss/pe_bound_import.cpp
@@ -0,0 +1,311 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include <string.h>
+#include "pe_bound_import.h"
+#include "utils.h"
+
+namespace pe_bliss
+{
+using namespace pe_win;
+
+//BOUND IMPORT
+//Default constructor
+bound_import_ref::bound_import_ref()
+ :timestamp_(0)
+{}
+
+//Constructor from data
+bound_import_ref::bound_import_ref(const std::string& module_name, uint32_t timestamp)
+ :module_name_(module_name), timestamp_(timestamp)
+{}
+
+//Returns imported module name
+const std::string& bound_import_ref::get_module_name() const
+{
+ return module_name_;
+}
+
+//Returns bound import date and time stamp
+uint32_t bound_import_ref::get_timestamp() const
+{
+ return timestamp_;
+}
+
+//Sets module name
+void bound_import_ref::set_module_name(const std::string& module_name)
+{
+ module_name_ = module_name;
+}
+
+//Sets timestamp
+void bound_import_ref::set_timestamp(uint32_t timestamp)
+{
+ timestamp_ = timestamp;
+}
+
+//Default constructor
+bound_import::bound_import()
+ :timestamp_(0)
+{}
+
+//Constructor from data
+bound_import::bound_import(const std::string& module_name, uint32_t timestamp)
+ :module_name_(module_name), timestamp_(timestamp)
+{}
+
+//Returns imported module name
+const std::string& bound_import::get_module_name() const
+{
+ return module_name_;
+}
+
+//Returns bound import date and time stamp
+uint32_t bound_import::get_timestamp() const
+{
+ return timestamp_;
+}
+
+//Returns bound references cound
+size_t bound_import::get_module_ref_count() const
+{
+ return refs_.size();
+}
+
+//Returns module references
+const bound_import::ref_list& bound_import::get_module_ref_list() const
+{
+ return refs_;
+}
+
+//Adds module reference
+void bound_import::add_module_ref(const bound_import_ref& ref)
+{
+ refs_.push_back(ref);
+}
+
+//Clears module references list
+void bound_import::clear_module_refs()
+{
+ refs_.clear();
+}
+
+//Returns module references
+bound_import::ref_list& bound_import::get_module_ref_list()
+{
+ return refs_;
+}
+
+//Sets module name
+void bound_import::set_module_name(const std::string& module_name)
+{
+ module_name_ = module_name;
+}
+
+//Sets timestamp
+void bound_import::set_timestamp(uint32_t timestamp)
+{
+ timestamp_ = timestamp;
+}
+
+const bound_import_module_list get_bound_import_module_list(const pe_base& pe)
+{
+ //Returned bound import modules list
+ bound_import_module_list ret;
+
+ //If image has no bound imports
+ if(!pe.has_bound_import())
+ return ret;
+
+ uint32_t bound_import_data_len =
+ pe.section_data_length_from_rva(pe.get_directory_rva(image_directory_entry_bound_import), pe.get_directory_rva(image_directory_entry_bound_import), section_data_raw, true);
+
+ if(bound_import_data_len < pe.get_directory_size(image_directory_entry_bound_import))
+ throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory);
+
+ const char* bound_import_data = pe.section_data_from_rva(pe.get_directory_rva(image_directory_entry_bound_import), section_data_raw, true);
+
+ //Check read in "read_pe" function raw bound import data size
+ if(bound_import_data_len < sizeof(image_bound_import_descriptor))
+ throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory);
+
+ //current bound_import_data_ in-string position
+ unsigned long current_pos = 0;
+ //first bound import descriptor
+ //so, we're working with raw data here, no section helpers available
+ const image_bound_import_descriptor* descriptor = reinterpret_cast<const image_bound_import_descriptor*>(&bound_import_data[current_pos]);
+
+ //Enumerate until zero
+ while(descriptor->OffsetModuleName)
+ {
+ //Check module name offset
+ if(descriptor->OffsetModuleName >= bound_import_data_len)
+ throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory);
+
+ //Check module name for null-termination
+ if(!pe_utils::is_null_terminated(&bound_import_data[descriptor->OffsetModuleName], bound_import_data_len - descriptor->OffsetModuleName))
+ throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory);
+
+ //Create bound import descriptor structure
+ bound_import elem(&bound_import_data[descriptor->OffsetModuleName], descriptor->TimeDateStamp);
+
+ //Check DWORDs
+ if(descriptor->NumberOfModuleForwarderRefs >= pe_utils::max_dword / sizeof(image_bound_forwarder_ref)
+ || !pe_utils::is_sum_safe(current_pos, 2 /* this descriptor and the next one */ * sizeof(image_bound_import_descriptor) + descriptor->NumberOfModuleForwarderRefs * sizeof(image_bound_forwarder_ref)))
+ throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory);
+
+ //Move after current descriptor
+ current_pos += sizeof(image_bound_import_descriptor);
+
+ //Enumerate referenced bound import descriptors
+ for(unsigned long i = 0; i != descriptor->NumberOfModuleForwarderRefs; ++i)
+ {
+ //They're just after parent descriptor
+ //Check size of structure
+ if(current_pos + sizeof(image_bound_forwarder_ref) > bound_import_data_len)
+ throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory);
+
+ //Get IMAGE_BOUND_FORWARDER_REF pointer
+ const image_bound_forwarder_ref* ref_descriptor = reinterpret_cast<const image_bound_forwarder_ref*>(&bound_import_data[current_pos]);
+
+ //Check referenced module name
+ if(ref_descriptor->OffsetModuleName >= bound_import_data_len)
+ throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory);
+
+ //And its null-termination
+ if(!pe_utils::is_null_terminated(&bound_import_data[ref_descriptor->OffsetModuleName], bound_import_data_len - ref_descriptor->OffsetModuleName))
+ throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory);
+
+ //Add referenced module to current bound import structure
+ elem.add_module_ref(bound_import_ref(&bound_import_data[ref_descriptor->OffsetModuleName], ref_descriptor->TimeDateStamp));
+
+ //Move after referenced bound import descriptor
+ current_pos += sizeof(image_bound_forwarder_ref);
+ }
+
+ //Check structure size
+ if(current_pos + sizeof(image_bound_import_descriptor) > bound_import_data_len)
+ throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory);
+
+ //Move to next bound import descriptor
+ descriptor = reinterpret_cast<const image_bound_import_descriptor*>(&bound_import_data[current_pos]);
+
+ //Save created descriptor structure and references
+ ret.push_back(elem);
+ }
+
+ //Return result
+ return ret;
+}
+
+//imports - bound imported modules list
+//imports_section - section where export directory will be placed (must be attached to PE image)
+//offset_from_section_start - offset from imports_section raw data start
+//save_to_pe_headers - if true, new bound import directory information will be saved to PE image headers
+//auto_strip_last_section - if true and bound imports are placed in the last section, it will be automatically stripped
+const image_directory rebuild_bound_imports(pe_base& pe, const bound_import_module_list& imports, section& imports_section, uint32_t offset_from_section_start, bool save_to_pe_header, bool auto_strip_last_section)
+{
+ //Check that exports_section is attached to this PE image
+ if(!pe.section_attached(imports_section))
+ throw pe_exception("Bound import section must be attached to PE file", pe_exception::section_is_not_attached);
+
+ uint32_t directory_pos = pe_utils::align_up(offset_from_section_start, sizeof(uint32_t));
+ uint32_t needed_size = sizeof(image_bound_import_descriptor) /* Ending null descriptor */;
+ uint32_t needed_size_for_strings = 0;
+
+ //Calculate needed size for bound import data
+ for(bound_import_module_list::const_iterator it = imports.begin(); it != imports.end(); ++it)
+ {
+ const bound_import& import = *it;
+ needed_size += sizeof(image_bound_import_descriptor);
+ needed_size_for_strings += static_cast<uint32_t>((*it).get_module_name().length()) + 1 /* nullbyte */;
+
+ const bound_import::ref_list& refs = import.get_module_ref_list();
+ for(bound_import::ref_list::const_iterator ref_it = refs.begin(); ref_it != refs.end(); ++ref_it)
+ {
+ needed_size_for_strings += static_cast<uint32_t>((*ref_it).get_module_name().length()) + 1 /* nullbyte */;
+ needed_size += sizeof(image_bound_forwarder_ref);
+ }
+ }
+
+ needed_size += needed_size_for_strings;
+
+ //Check if imports_section is last one. If it's not, check if there's enough place for bound import data
+ if(&imports_section != &*(pe.get_image_sections().end() - 1) &&
+ (imports_section.empty() || pe_utils::align_up(imports_section.get_size_of_raw_data(), pe.get_file_alignment()) < needed_size + directory_pos))
+ throw pe_exception("Insufficient space for bound import directory", pe_exception::insufficient_space);
+
+ std::string& raw_data = imports_section.get_raw_data();
+
+ //This will be done only if imports_section is the last section of image or for section with unaligned raw length of data
+ if(raw_data.length() < needed_size + directory_pos)
+ raw_data.resize(needed_size + directory_pos); //Expand section raw data
+
+ uint32_t current_pos_for_structures = directory_pos;
+ uint32_t current_pos_for_strings = current_pos_for_structures + needed_size - needed_size_for_strings;
+
+ for(bound_import_module_list::const_iterator it = imports.begin(); it != imports.end(); ++it)
+ {
+ const bound_import& import = *it;
+ image_bound_import_descriptor descriptor;
+ descriptor.NumberOfModuleForwarderRefs = static_cast<uint16_t>(import.get_module_ref_list().size());
+ descriptor.OffsetModuleName = static_cast<uint16_t>(current_pos_for_strings - directory_pos);
+ descriptor.TimeDateStamp = import.get_timestamp();
+
+ memcpy(&raw_data[current_pos_for_structures], &descriptor, sizeof(descriptor));
+ current_pos_for_structures += sizeof(descriptor);
+
+ size_t length = import.get_module_name().length() + 1 /* nullbyte */;
+ memcpy(&raw_data[current_pos_for_strings], import.get_module_name().c_str(), length);
+ current_pos_for_strings += static_cast<uint32_t>(length);
+
+ const bound_import::ref_list& refs = import.get_module_ref_list();
+ for(bound_import::ref_list::const_iterator ref_it = refs.begin(); ref_it != refs.end(); ++ref_it)
+ {
+ const bound_import_ref& ref = *ref_it;
+ image_bound_forwarder_ref ref_descriptor = {0};
+ ref_descriptor.OffsetModuleName = static_cast<uint16_t>(current_pos_for_strings - directory_pos);
+ ref_descriptor.TimeDateStamp = ref.get_timestamp();
+
+ memcpy(&raw_data[current_pos_for_structures], &ref_descriptor, sizeof(ref_descriptor));
+ current_pos_for_structures += sizeof(ref_descriptor);
+
+ length = ref.get_module_name().length() + 1 /* nullbyte */;
+ memcpy(&raw_data[current_pos_for_strings], ref.get_module_name().c_str(), length);
+ current_pos_for_strings += static_cast<uint32_t>(length);
+ }
+ }
+
+ //Adjust section raw and virtual sizes
+ pe.recalculate_section_sizes(imports_section, auto_strip_last_section);
+
+ image_directory ret(pe.rva_from_section_offset(imports_section, directory_pos), needed_size);
+
+ //If auto-rewrite of PE headers is required
+ if(save_to_pe_header)
+ {
+ pe.set_directory_rva(image_directory_entry_bound_import, ret.get_rva());
+ pe.set_directory_size(image_directory_entry_bound_import, ret.get_size());
+ }
+
+ return ret;
+}
+}
diff --git a/tools/pe_bliss/pe_bound_import.h b/tools/pe_bliss/pe_bound_import.h
new file mode 100644
index 0000000000..667e28792e
--- /dev/null
+++ b/tools/pe_bliss/pe_bound_import.h
@@ -0,0 +1,108 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <vector>
+#include <string>
+#include "pe_structures.h"
+#include "pe_base.h"
+#include "pe_directory.h"
+
+namespace pe_bliss
+{
+//Class representing bound import reference
+class bound_import_ref
+{
+public:
+ //Default constructor
+ bound_import_ref();
+ //Constructor from data
+ bound_import_ref(const std::string& module_name, uint32_t timestamp);
+
+ //Returns imported module name
+ const std::string& get_module_name() const;
+ //Returns bound import date and time stamp
+ uint32_t get_timestamp() const;
+
+public: //Setters
+ //Sets module name
+ void set_module_name(const std::string& module_name);
+ //Sets timestamp
+ void set_timestamp(uint32_t timestamp);
+
+private:
+ std::string module_name_; //Imported module name
+ uint32_t timestamp_; //Bound import timestamp
+};
+
+//Class representing image bound import information
+class bound_import
+{
+public:
+ typedef std::vector<bound_import_ref> ref_list;
+
+public:
+ //Default constructor
+ bound_import();
+ //Constructor from data
+ bound_import(const std::string& module_name, uint32_t timestamp);
+
+ //Returns imported module name
+ const std::string& get_module_name() const;
+ //Returns bound import date and time stamp
+ uint32_t get_timestamp() const;
+
+ //Returns bound references cound
+ size_t get_module_ref_count() const;
+ //Returns module references
+ const ref_list& get_module_ref_list() const;
+
+public: //Setters
+ //Sets module name
+ void set_module_name(const std::string& module_name);
+ //Sets timestamp
+ void set_timestamp(uint32_t timestamp);
+
+ //Adds module reference
+ void add_module_ref(const bound_import_ref& ref);
+ //Clears module references list
+ void clear_module_refs();
+ //Returns module references
+ ref_list& get_module_ref_list();
+
+private:
+ std::string module_name_; //Imported module name
+ uint32_t timestamp_; //Bound import timestamp
+ ref_list refs_; //Module references list
+};
+
+typedef std::vector<bound_import> bound_import_module_list;
+
+//Returns bound import information
+const bound_import_module_list get_bound_import_module_list(const pe_base& pe);//Export directory rebuilder
+
+//imports - bound imported modules list
+//imports_section - section where export directory will be placed (must be attached to PE image)
+//offset_from_section_start - offset from imports_section raw data start
+//save_to_pe_headers - if true, new bound import directory information will be saved to PE image headers
+//auto_strip_last_section - if true and bound imports are placed in the last section, it will be automatically stripped
+const image_directory rebuild_bound_imports(pe_base& pe, const bound_import_module_list& imports, section& imports_section, uint32_t offset_from_section_start = 0, bool save_to_pe_header = true, bool auto_strip_last_section = true);
+}
diff --git a/tools/pe_bliss/pe_checksum.cpp b/tools/pe_bliss/pe_checksum.cpp
new file mode 100644
index 0000000000..5971a33c90
--- /dev/null
+++ b/tools/pe_bliss/pe_checksum.cpp
@@ -0,0 +1,103 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include "pe_checksum.h"
+#include "pe_structures.h"
+#include "pe_base.h"
+
+namespace pe_bliss
+{
+using namespace pe_win;
+
+//Calculate checksum of image
+uint32_t calculate_checksum(std::istream& file)
+{
+ //Save istream state
+ std::ios_base::iostate state = file.exceptions();
+ std::streamoff old_offset = file.tellg();
+
+ //Checksum value
+ unsigned long long checksum = 0;
+
+ try
+ {
+ image_dos_header header;
+
+ file.exceptions(std::ios::goodbit);
+
+ //Read DOS header
+ pe_base::read_dos_header(file, header);
+
+ //Calculate PE checksum
+ file.seekg(0);
+ unsigned long long top = 0xFFFFFFFF;
+ top++;
+
+ //"CheckSum" field position in optional PE headers - it's always 64 for PE and PE+
+ static const unsigned long checksum_pos_in_optional_headers = 64;
+ //Calculate real PE headers "CheckSum" field position
+ //Sum is safe here
+ unsigned long pe_checksum_pos = header.e_lfanew + sizeof(image_file_header) + sizeof(uint32_t) + checksum_pos_in_optional_headers;
+
+ //Calculate checksum for each byte of file
+ std::streamoff filesize = pe_utils::get_file_size(file);
+ for(long long i = 0; i < filesize; i += 4)
+ {
+ unsigned long dw = 0;
+
+ //Read DWORD from file
+ file.read(reinterpret_cast<char*>(&dw), sizeof(unsigned long));
+ //Skip "CheckSum" DWORD
+ if(i == pe_checksum_pos)
+ continue;
+
+ //Calculate checksum
+ checksum = (checksum & 0xffffffff) + dw + (checksum >> 32);
+ if(checksum > top)
+ checksum = (checksum & 0xffffffff) + (checksum >> 32);
+ }
+
+ //Finish checksum
+ checksum = (checksum & 0xffff) + (checksum >> 16);
+ checksum = (checksum) + (checksum >> 16);
+ checksum = checksum & 0xffff;
+
+ checksum += static_cast<unsigned long>(filesize);
+ }
+ catch(const std::exception&)
+ {
+ //If something went wrong, restore istream state
+ file.exceptions(state);
+ file.seekg(old_offset);
+ file.clear();
+ //Rethrow
+ throw;
+ }
+
+ //Restore istream state
+ file.exceptions(state);
+ file.seekg(old_offset);
+ file.clear();
+
+ //Return checksum
+ return static_cast<uint32_t>(checksum);
+}
+}
diff --git a/tools/pe_bliss/pe_checksum.h b/tools/pe_bliss/pe_checksum.h
new file mode 100644
index 0000000000..a568d5d369
--- /dev/null
+++ b/tools/pe_bliss/pe_checksum.h
@@ -0,0 +1,30 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <istream>
+#include "stdint_defs.h"
+
+namespace pe_bliss
+{
+//Calculate checksum of image (performs no checks on PE structures)
+uint32_t calculate_checksum(std::istream& file);
+}
diff --git a/tools/pe_bliss/pe_debug.cpp b/tools/pe_bliss/pe_debug.cpp
new file mode 100644
index 0000000000..a0ed3f5af1
--- /dev/null
+++ b/tools/pe_bliss/pe_debug.cpp
@@ -0,0 +1,865 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include <string.h>
+#include "pe_debug.h"
+#include "utils.h"
+
+namespace pe_bliss
+{
+using namespace pe_win;
+//DEBUG
+//Default constructor
+debug_info::debug_info()
+ :characteristics_(0),
+ time_stamp_(0),
+ major_version_(0), minor_version_(0),
+ type_(0),
+ size_of_data_(0),
+ address_of_raw_data_(0),
+ pointer_to_raw_data_(0),
+ advanced_info_type_(advanced_info_none)
+{}
+
+//Constructor from data
+debug_info::debug_info(const image_debug_directory& debug)
+ :characteristics_(debug.Characteristics),
+ time_stamp_(debug.TimeDateStamp),
+ major_version_(debug.MajorVersion), minor_version_(debug.MinorVersion),
+ type_(debug.Type),
+ size_of_data_(debug.SizeOfData),
+ address_of_raw_data_(debug.AddressOfRawData),
+ pointer_to_raw_data_(debug.PointerToRawData),
+ advanced_info_type_(advanced_info_none)
+{}
+
+//Returns debug characteristics
+uint32_t debug_info::get_characteristics() const
+{
+ return characteristics_;
+}
+
+//Returns debug datetimestamp
+uint32_t debug_info::get_time_stamp() const
+{
+ return time_stamp_;
+}
+
+//Returns major version
+uint32_t debug_info::get_major_version() const
+{
+ return major_version_;
+}
+
+//Returns minor version
+uint32_t debug_info::get_minor_version() const
+{
+ return minor_version_;
+}
+
+//Returns type of debug info (unchecked)
+uint32_t debug_info::get_type_raw() const
+{
+ return type_;
+}
+
+//Returns type of debug info from debug_info_type enumeration
+debug_info::debug_info_type debug_info::get_type() const
+{
+ //Determine debug type
+ switch(type_)
+ {
+ case image_debug_type_coff:
+ return debug_type_coff;
+
+ case image_debug_type_codeview:
+ return debug_type_codeview;
+
+ case image_debug_type_fpo:
+ return debug_type_fpo;
+
+ case image_debug_type_misc:
+ return debug_type_misc;
+
+ case image_debug_type_exception:
+ return debug_type_exception;
+
+ case image_debug_type_fixup:
+ return debug_type_fixup;
+
+ case image_debug_type_omap_to_src:
+ return debug_type_omap_to_src;
+
+ case image_debug_type_omap_from_src:
+ return debug_type_omap_from_src;
+
+ case image_debug_type_borland:
+ return debug_type_borland;
+
+ case image_debug_type_clsid:
+ return debug_type_clsid;
+
+ case image_debug_type_reserved10:
+ return debug_type_reserved10;
+ }
+
+ return debug_type_unknown;
+}
+
+//Returns size of debug data (internal, .pdb or other file doesn't count)
+uint32_t debug_info::get_size_of_data() const
+{
+ return size_of_data_;
+}
+
+//Returns RVA of debug info when mapped to memory or zero, if info is not mapped
+uint32_t debug_info::get_rva_of_raw_data() const
+{
+ return address_of_raw_data_;
+}
+
+//Returns raw file pointer to raw data
+uint32_t debug_info::get_pointer_to_raw_data() const
+{
+ return pointer_to_raw_data_;
+}
+
+//Copy constructor
+debug_info::debug_info(const debug_info& info)
+ :characteristics_(info.characteristics_),
+ time_stamp_(info.time_stamp_),
+ major_version_(info.major_version_), minor_version_(info.minor_version_),
+ type_(info.type_),
+ size_of_data_(info.size_of_data_),
+ address_of_raw_data_(info.address_of_raw_data_),
+ pointer_to_raw_data_(info.pointer_to_raw_data_),
+ advanced_info_type_(info.advanced_info_type_)
+{
+ copy_advanced_info(info);
+}
+
+//Copy assignment operator
+debug_info& debug_info::operator=(const debug_info& info)
+{
+ copy_advanced_info(info);
+
+ characteristics_ = info.characteristics_;
+ time_stamp_ = info.time_stamp_;
+ major_version_ = info.major_version_;
+ minor_version_ = info.minor_version_;
+ type_ = info.type_;
+ size_of_data_ = info.size_of_data_;
+ address_of_raw_data_ = info.address_of_raw_data_;
+ pointer_to_raw_data_ = info.pointer_to_raw_data_;
+ advanced_info_type_ = info.advanced_info_type_;
+
+ return *this;
+}
+
+//Default constructor
+debug_info::advanced_info::advanced_info()
+ :adv_pdb_7_0_info(0) //Zero pointer to advanced data
+{}
+
+//Returns true if advanced debug info is present
+bool debug_info::advanced_info::is_present() const
+{
+ return adv_pdb_7_0_info != 0;
+}
+
+//Helper for advanced debug information copying
+void debug_info::copy_advanced_info(const debug_info& info)
+{
+ free_present_advanced_info();
+
+ switch(info.advanced_info_type_)
+ {
+ case advanced_info_pdb_7_0:
+ advanced_debug_info_.adv_pdb_7_0_info = new pdb_7_0_info(*info.advanced_debug_info_.adv_pdb_7_0_info);
+ break;
+ case advanced_info_pdb_2_0:
+ advanced_debug_info_.adv_pdb_2_0_info = new pdb_2_0_info(*info.advanced_debug_info_.adv_pdb_2_0_info);
+ break;
+ case advanced_info_misc:
+ advanced_debug_info_.adv_misc_info = new misc_debug_info(*info.advanced_debug_info_.adv_misc_info);
+ break;
+ case advanced_info_coff:
+ advanced_debug_info_.adv_coff_info = new coff_debug_info(*info.advanced_debug_info_.adv_coff_info);
+ break;
+ default:
+ break;
+ }
+
+ advanced_info_type_ = info.advanced_info_type_;
+}
+
+//Helper for clearing any present advanced debug information
+void debug_info::free_present_advanced_info()
+{
+ switch(advanced_info_type_)
+ {
+ case advanced_info_pdb_7_0:
+ delete advanced_debug_info_.adv_pdb_7_0_info;
+ break;
+ case advanced_info_pdb_2_0:
+ delete advanced_debug_info_.adv_pdb_2_0_info;
+ break;
+ case advanced_info_misc:
+ delete advanced_debug_info_.adv_misc_info;
+ break;
+ case advanced_info_coff:
+ delete advanced_debug_info_.adv_coff_info;
+ break;
+ default:
+ break;
+ }
+
+ advanced_debug_info_.adv_pdb_7_0_info = 0;
+ advanced_info_type_ = advanced_info_none;
+}
+
+//Destructor
+debug_info::~debug_info()
+{
+ free_present_advanced_info();
+}
+
+//Sets advanced debug information
+void debug_info::set_advanced_debug_info(const pdb_7_0_info& info)
+{
+ free_present_advanced_info();
+ advanced_debug_info_.adv_pdb_7_0_info = new pdb_7_0_info(info);
+ advanced_info_type_ = advanced_info_pdb_7_0;
+}
+
+void debug_info::set_advanced_debug_info(const pdb_2_0_info& info)
+{
+ free_present_advanced_info();
+ advanced_debug_info_.adv_pdb_2_0_info = new pdb_2_0_info(info);
+ advanced_info_type_ = advanced_info_pdb_2_0;
+}
+
+void debug_info::set_advanced_debug_info(const misc_debug_info& info)
+{
+ free_present_advanced_info();
+ advanced_debug_info_.adv_misc_info = new misc_debug_info(info);
+ advanced_info_type_ = advanced_info_misc;
+}
+
+void debug_info::set_advanced_debug_info(const coff_debug_info& info)
+{
+ free_present_advanced_info();
+ advanced_debug_info_.adv_coff_info = new coff_debug_info(info);
+ advanced_info_type_ = advanced_info_coff;
+}
+
+//Returns advanced debug information type
+debug_info::advanced_info_type debug_info::get_advanced_info_type() const
+{
+ return advanced_info_type_;
+}
+
+//Returns advanced debug information or throws an exception,
+//if requested information type is not contained by structure
+template<>
+const pdb_7_0_info debug_info::get_advanced_debug_info<pdb_7_0_info>() const
+{
+ if(advanced_info_type_ != advanced_info_pdb_7_0)
+ throw pe_exception("Debug info structure does not contain PDB 7.0 data", pe_exception::advanced_debug_information_request_error);
+
+ return *advanced_debug_info_.adv_pdb_7_0_info;
+}
+
+template<>
+const pdb_2_0_info debug_info::get_advanced_debug_info<pdb_2_0_info>() const
+{
+ if(advanced_info_type_ != advanced_info_pdb_2_0)
+ throw pe_exception("Debug info structure does not contain PDB 2.0 data", pe_exception::advanced_debug_information_request_error);
+
+ return *advanced_debug_info_.adv_pdb_2_0_info;
+}
+
+template<>
+const misc_debug_info debug_info::get_advanced_debug_info<misc_debug_info>() const
+{
+ if(advanced_info_type_ != advanced_info_misc)
+ throw pe_exception("Debug info structure does not contain MISC data", pe_exception::advanced_debug_information_request_error);
+
+ return *advanced_debug_info_.adv_misc_info;
+}
+
+template<>
+const coff_debug_info debug_info::get_advanced_debug_info<coff_debug_info>() const
+{
+ if(advanced_info_type_ != advanced_info_coff)
+ throw pe_exception("Debug info structure does not contain COFF data", pe_exception::advanced_debug_information_request_error);
+
+ return *advanced_debug_info_.adv_coff_info;
+}
+
+//Sets advanced debug information type, if no advanced info structure available
+void debug_info::set_advanced_info_type(advanced_info_type type)
+{
+ free_present_advanced_info();
+ if(advanced_info_type_ >= advanced_info_codeview_4_0) //Don't set info type for those types, which have advanced info structures
+ advanced_info_type_ = type;
+}
+
+//Default constructor
+pdb_7_0_info::pdb_7_0_info()
+ :age_(0)
+{
+ memset(&guid_, 0, sizeof(guid_));
+}
+
+//Constructor from data
+pdb_7_0_info::pdb_7_0_info(const CV_INFO_PDB70* info)
+ :age_(info->Age), guid_(info->Signature),
+ pdb_file_name_(reinterpret_cast<const char*>(info->PdbFileName)) //Must be checked before for null-termination
+{}
+
+//Returns debug PDB 7.0 structure GUID
+const guid pdb_7_0_info::get_guid() const
+{
+ return guid_;
+}
+
+//Returns age of build
+uint32_t pdb_7_0_info::get_age() const
+{
+ return age_;
+}
+
+//Returns PDB file name / path
+const std::string& pdb_7_0_info::get_pdb_file_name() const
+{
+ return pdb_file_name_;
+}
+
+//Default constructor
+pdb_2_0_info::pdb_2_0_info()
+ :age_(0), signature_(0)
+{}
+
+//Constructor from data
+pdb_2_0_info::pdb_2_0_info(const CV_INFO_PDB20* info)
+ :age_(info->Age), signature_(info->Signature),
+ pdb_file_name_(reinterpret_cast<const char*>(info->PdbFileName)) //Must be checked before for null-termination
+{}
+
+//Returns debug PDB 2.0 structure signature
+uint32_t pdb_2_0_info::get_signature() const
+{
+ return signature_;
+}
+
+//Returns age of build
+uint32_t pdb_2_0_info::get_age() const
+{
+ return age_;
+}
+
+//Returns PDB file name / path
+const std::string& pdb_2_0_info::get_pdb_file_name() const
+{
+ return pdb_file_name_;
+}
+
+//Default constructor
+misc_debug_info::misc_debug_info()
+ :data_type_(0), unicode_(false)
+{}
+
+//Constructor from data
+misc_debug_info::misc_debug_info(const image_debug_misc* info)
+ :data_type_(info->DataType), unicode_(info->Unicode ? true : false)
+{
+ //IMAGE_DEBUG_MISC::Data must be checked before!
+ if(info->Unicode)
+ {
+#ifdef PE_BLISS_WINDOWS
+ debug_data_unicode_ = std::wstring(reinterpret_cast<const wchar_t*>(info->Data), (info->Length - sizeof(image_debug_misc) + 1 /* BYTE[1] in the end of structure */) / 2);
+#else
+ debug_data_unicode_ = pe_utils::from_ucs2(u16string(reinterpret_cast<const unicode16_t*>(info->Data), (info->Length - sizeof(image_debug_misc) + 1 /* BYTE[1] in the end of structure */) / 2));
+#endif
+
+ pe_utils::strip_nullbytes(debug_data_unicode_); //Strip nullbytes in the end of string
+ }
+ else
+ {
+ debug_data_ansi_ = std::string(reinterpret_cast<const char*>(info->Data), info->Length - sizeof(image_debug_misc) + 1 /* BYTE[1] in the end of structure */);
+ pe_utils::strip_nullbytes(debug_data_ansi_); //Strip nullbytes in the end of string
+ }
+}
+
+//Returns debug data type
+uint32_t misc_debug_info::get_data_type() const
+{
+ return data_type_;
+}
+
+//Returns true if data type is exe name
+bool misc_debug_info::is_exe_name() const
+{
+ return data_type_ == image_debug_misc_exename;
+}
+
+//Returns true if debug data is UNICODE
+bool misc_debug_info::is_unicode() const
+{
+ return unicode_;
+}
+
+//Returns debug data (ANSI)
+const std::string& misc_debug_info::get_data_ansi() const
+{
+ return debug_data_ansi_;
+}
+
+//Returns debug data (UNICODE)
+const std::wstring& misc_debug_info::get_data_unicode() const
+{
+ return debug_data_unicode_;
+}
+
+//Default constructor
+coff_debug_info::coff_debug_info()
+ :number_of_symbols_(0),
+ lva_to_first_symbol_(0),
+ number_of_line_numbers_(0),
+ lva_to_first_line_number_(0),
+ rva_to_first_byte_of_code_(0),
+ rva_to_last_byte_of_code_(0),
+ rva_to_first_byte_of_data_(0),
+ rva_to_last_byte_of_data_(0)
+{}
+
+//Constructor from data
+coff_debug_info::coff_debug_info(const image_coff_symbols_header* info)
+ :number_of_symbols_(info->NumberOfSymbols),
+ lva_to_first_symbol_(info->LvaToFirstSymbol),
+ number_of_line_numbers_(info->NumberOfLinenumbers),
+ lva_to_first_line_number_(info->LvaToFirstLinenumber),
+ rva_to_first_byte_of_code_(info->RvaToFirstByteOfCode),
+ rva_to_last_byte_of_code_(info->RvaToLastByteOfCode),
+ rva_to_first_byte_of_data_(info->RvaToFirstByteOfData),
+ rva_to_last_byte_of_data_(info->RvaToLastByteOfData)
+{}
+
+//Returns number of symbols
+uint32_t coff_debug_info::get_number_of_symbols() const
+{
+ return number_of_symbols_;
+}
+
+//Returns virtual address of the first symbol
+uint32_t coff_debug_info::get_lva_to_first_symbol() const
+{
+ return lva_to_first_symbol_;
+}
+
+//Returns number of line-number entries
+uint32_t coff_debug_info::get_number_of_line_numbers() const
+{
+ return number_of_line_numbers_;
+}
+
+//Returns virtual address of the first line-number entry
+uint32_t coff_debug_info::get_lva_to_first_line_number() const
+{
+ return lva_to_first_line_number_;
+}
+
+//Returns relative virtual address of the first byte of code
+uint32_t coff_debug_info::get_rva_to_first_byte_of_code() const
+{
+ return rva_to_first_byte_of_code_;
+}
+
+//Returns relative virtual address of the last byte of code
+uint32_t coff_debug_info::get_rva_to_last_byte_of_code() const
+{
+ return rva_to_last_byte_of_code_;
+}
+
+//Returns relative virtual address of the first byte of data
+uint32_t coff_debug_info::get_rva_to_first_byte_of_data() const
+{
+ return rva_to_first_byte_of_data_;
+}
+
+//Returns relative virtual address of the last byte of data
+uint32_t coff_debug_info::get_rva_to_last_byte_of_data() const
+{
+ return rva_to_last_byte_of_data_;
+}
+
+//Returns COFF symbols list
+const coff_debug_info::coff_symbols_list& coff_debug_info::get_symbols() const
+{
+ return symbols_;
+}
+
+//Adds COFF symbol
+void coff_debug_info::add_symbol(const coff_symbol& sym)
+{
+ symbols_.push_back(sym);
+}
+
+//Default constructor
+coff_debug_info::coff_symbol::coff_symbol()
+ :storage_class_(0),
+ index_(0),
+ section_number_(0), rva_(0),
+ type_(0),
+ is_filename_(false)
+{}
+
+//Returns storage class
+uint32_t coff_debug_info::coff_symbol::get_storage_class() const
+{
+ return storage_class_;
+}
+
+//Returns symbol index
+uint32_t coff_debug_info::coff_symbol::get_index() const
+{
+ return index_;
+}
+
+//Returns section number
+uint32_t coff_debug_info::coff_symbol::get_section_number() const
+{
+ return section_number_;
+}
+
+//Returns RVA
+uint32_t coff_debug_info::coff_symbol::get_rva() const
+{
+ return rva_;
+}
+
+//Returns true if structure contains file name
+bool coff_debug_info::coff_symbol::is_file() const
+{
+ return is_filename_;
+}
+
+//Returns text data (symbol or file name)
+const std::string& coff_debug_info::coff_symbol::get_symbol() const
+{
+ return name_;
+}
+
+//Sets storage class
+void coff_debug_info::coff_symbol::set_storage_class(uint32_t storage_class)
+{
+ storage_class_ = storage_class;
+}
+
+//Sets symbol index
+void coff_debug_info::coff_symbol::set_index(uint32_t index)
+{
+ index_ = index;
+}
+
+//Sets section number
+void coff_debug_info::coff_symbol::set_section_number(uint32_t section_number)
+{
+ section_number_ = section_number;
+}
+
+//Sets RVA
+void coff_debug_info::coff_symbol::set_rva(uint32_t rva)
+{
+ rva_ = rva;
+}
+
+//Sets file name
+void coff_debug_info::coff_symbol::set_file_name(const std::string& file_name)
+{
+ name_ = file_name;
+ is_filename_ = true;
+}
+
+//Sets symbol name
+void coff_debug_info::coff_symbol::set_symbol_name(const std::string& symbol_name)
+{
+ name_ = symbol_name;
+ is_filename_ = false;
+}
+
+//Returns type
+uint16_t coff_debug_info::coff_symbol::get_type() const
+{
+ return type_;
+}
+
+//Sets type
+void coff_debug_info::coff_symbol::set_type(uint16_t type)
+{
+ type_ = type;
+}
+
+//Returns debug information list
+const debug_info_list get_debug_information(const pe_base& pe)
+{
+ debug_info_list ret;
+
+ //If there's no debug directory, return empty list
+ if(!pe.has_debug())
+ return ret;
+
+ //Check the length in bytes of the section containing debug directory
+ if(pe.section_data_length_from_rva(pe.get_directory_rva(image_directory_entry_debug), pe.get_directory_rva(image_directory_entry_debug), section_data_virtual, true)
+ < sizeof(image_debug_directory))
+ throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
+
+ unsigned long current_pos = pe.get_directory_rva(image_directory_entry_debug);
+
+ //First IMAGE_DEBUG_DIRECTORY table
+ image_debug_directory directory = pe.section_data_from_rva<image_debug_directory>(current_pos, section_data_virtual, true);
+
+ if(!pe_utils::is_sum_safe(pe.get_directory_rva(image_directory_entry_debug), pe.get_directory_size(image_directory_entry_debug)))
+ throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
+
+ //Iterate over all IMAGE_DEBUG_DIRECTORY directories
+ while(directory.PointerToRawData
+ && current_pos < pe.get_directory_rva(image_directory_entry_debug) + pe.get_directory_size(image_directory_entry_debug))
+ {
+ //Create debug information structure
+ debug_info info(directory);
+
+ //Find raw debug data
+ const pe_base::debug_data_list& debug_datas = pe.get_raw_debug_data_list();
+ pe_base::debug_data_list::const_iterator it = debug_datas.find(directory.PointerToRawData);
+ if(it != debug_datas.end()) //If it exists, we'll do some detailed debug info research
+ {
+ const std::string& debug_data = (*it).second;
+ switch(directory.Type)
+ {
+ case image_debug_type_coff:
+ {
+ //Check data length
+ if(debug_data.length() < sizeof(image_coff_symbols_header))
+ throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
+
+ //Get coff header structure pointer
+ const image_coff_symbols_header* coff = reinterpret_cast<const image_coff_symbols_header*>(debug_data.data());
+
+ //Check possible overflows
+ if(coff->NumberOfSymbols >= pe_utils::max_dword / sizeof(image_symbol)
+ || !pe_utils::is_sum_safe(coff->NumberOfSymbols * sizeof(image_symbol), coff->LvaToFirstSymbol))
+ throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
+
+ //Check data length again
+ if(debug_data.length() < coff->NumberOfSymbols * sizeof(image_symbol) + coff->LvaToFirstSymbol)
+ throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
+
+ //Create COFF debug info structure
+ coff_debug_info coff_info(coff);
+
+ //Enumerate debug symbols data
+ for(uint32_t i = 0; i < coff->NumberOfSymbols; ++i)
+ {
+ //Safe sum (checked above)
+ const image_symbol* sym = reinterpret_cast<const image_symbol*>(debug_data.data() + i * sizeof(image_symbol) + coff->LvaToFirstSymbol);
+
+ coff_debug_info::coff_symbol symbol;
+ symbol.set_index(i); //Save symbol index
+ symbol.set_storage_class(sym->StorageClass); //Save storage class
+ symbol.set_type(sym->Type); //Save storage class
+
+ //Check data length again
+ if(!pe_utils::is_sum_safe(i, sym->NumberOfAuxSymbols)
+ || (i + sym->NumberOfAuxSymbols) > coff->NumberOfSymbols
+ || debug_data.length() < (i + 1) * sizeof(image_symbol) + coff->LvaToFirstSymbol + sym->NumberOfAuxSymbols * sizeof(image_symbol))
+ throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
+
+ //If symbol is filename
+ if(sym->StorageClass == image_sym_class_file)
+ {
+ //Save file name, it is situated just after this IMAGE_SYMBOL structure
+ std::string file_name(reinterpret_cast<const char*>(debug_data.data() + (i + 1) * sizeof(image_symbol)), sym->NumberOfAuxSymbols * sizeof(image_symbol));
+ pe_utils::strip_nullbytes(file_name);
+ symbol.set_file_name(file_name);
+
+ //Save symbol info
+ coff_info.add_symbol(symbol);
+
+ //Move to next symbol
+ i += sym->NumberOfAuxSymbols;
+ continue;
+ }
+
+ //Dump some other symbols
+ if(((sym->StorageClass == image_sym_class_static)
+ && (sym->NumberOfAuxSymbols == 0)
+ && (sym->SectionNumber == 1))
+ ||
+ ((sym->StorageClass == image_sym_class_external)
+ && ISFCN(sym->Type)
+ && (sym->SectionNumber > 0))
+ )
+ {
+ //Save RVA and section number
+ symbol.set_section_number(sym->SectionNumber);
+ symbol.set_rva(sym->Value);
+
+ //If symbol has short name
+ if(sym->N.Name.Short)
+ {
+ //Copy and save symbol name
+ char name_buff[9];
+ memcpy(name_buff, sym->N.ShortName, 8);
+ name_buff[8] = '\0';
+ symbol.set_symbol_name(name_buff);
+ }
+ else
+ {
+ //Symbol has long name
+
+ //Check possible overflows
+ if(!pe_utils::is_sum_safe(coff->LvaToFirstSymbol + coff->NumberOfSymbols * sizeof(image_symbol), sym->N.Name.Long))
+ throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
+
+ //Here we have an offset to the string table
+ uint32_t symbol_offset = coff->LvaToFirstSymbol + coff->NumberOfSymbols * sizeof(image_symbol) + sym->N.Name.Long;
+
+ //Check data length
+ if(debug_data.length() < symbol_offset)
+ throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
+
+ //Check symbol name for null-termination
+ if(!pe_utils::is_null_terminated(debug_data.data() + symbol_offset, debug_data.length() - symbol_offset))
+ throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
+
+ //Save symbol name
+ symbol.set_symbol_name(debug_data.data() + symbol_offset);
+ }
+
+ //Save symbol info
+ coff_info.add_symbol(symbol);
+
+ //Move to next symbol
+ i += sym->NumberOfAuxSymbols;
+ continue;
+ }
+ }
+
+ info.set_advanced_debug_info(coff_info);
+ }
+ break;
+
+ case image_debug_type_codeview:
+ {
+ //Check data length
+ if(debug_data.length() < sizeof(OMFSignature*))
+ throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
+
+ //Get POMFSignature structure pointer from the very beginning of debug data
+ const OMFSignature* sig = reinterpret_cast<const OMFSignature*>(debug_data.data());
+ if(!memcmp(sig->Signature, "RSDS", 4))
+ {
+ //Signature is "RSDS" - PDB 7.0
+
+ //Check data length
+ if(debug_data.length() < sizeof(CV_INFO_PDB70))
+ throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
+
+ const CV_INFO_PDB70* pdb_data = reinterpret_cast<const CV_INFO_PDB70*>(debug_data.data());
+
+ //Check PDB file name null-termination
+ if(!pe_utils::is_null_terminated(pdb_data->PdbFileName, debug_data.length() - (sizeof(CV_INFO_PDB70) - 1 /* BYTE of filename in structure */)))
+ throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
+
+ info.set_advanced_debug_info(pdb_7_0_info(pdb_data));
+ }
+ else if(!memcmp(sig->Signature, "NB10", 4))
+ {
+ //Signature is "NB10" - PDB 2.0
+
+ //Check data length
+ if(debug_data.length() < sizeof(CV_INFO_PDB20))
+ throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
+
+ const CV_INFO_PDB20* pdb_data = reinterpret_cast<const CV_INFO_PDB20*>(debug_data.data());
+
+ //Check PDB file name null-termination
+ if(!pe_utils::is_null_terminated(pdb_data->PdbFileName, debug_data.length() - (sizeof(CV_INFO_PDB20) - 1 /* BYTE of filename in structure */)))
+ throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
+
+ info.set_advanced_debug_info(pdb_2_0_info(pdb_data));
+ }
+ else if(!memcmp(sig->Signature, "NB09", 4))
+ {
+ //CodeView 4.0, no structures available
+ info.set_advanced_info_type(debug_info::advanced_info_codeview_4_0);
+ }
+ else if(!memcmp(sig->Signature, "NB11", 4))
+ {
+ //CodeView 5.0, no structures available
+ info.set_advanced_info_type(debug_info::advanced_info_codeview_5_0);
+ }
+ else if(!memcmp(sig->Signature, "NB05", 4))
+ {
+ //Other CodeView, no structures available
+ info.set_advanced_info_type(debug_info::advanced_info_codeview);
+ }
+ }
+
+ break;
+
+ case image_debug_type_misc:
+ {
+ //Check data length
+ if(debug_data.length() < sizeof(image_debug_misc))
+ throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
+
+ //Get misc structure pointer
+ const image_debug_misc* misc_data = reinterpret_cast<const image_debug_misc*>(debug_data.data());
+
+ //Check misc data length
+ if(debug_data.length() < misc_data->Length /* Total length of record */)
+ throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
+
+ //Save advanced information
+ info.set_advanced_debug_info(misc_debug_info(misc_data));
+ }
+ break;
+ }
+ }
+
+ //Save debug information structure
+ ret.push_back(info);
+
+ //Check possible overflow
+ if(!pe_utils::is_sum_safe(current_pos, sizeof(image_debug_directory)))
+ throw pe_exception("Incorrect debug directory", pe_exception::incorrect_debug_directory);
+
+ //Go to next debug entry
+ current_pos += sizeof(image_debug_directory);
+ directory = pe.section_data_from_rva<image_debug_directory>(current_pos, section_data_virtual, true);
+ }
+
+ return ret;
+}
+}
diff --git a/tools/pe_bliss/pe_debug.h b/tools/pe_bliss/pe_debug.h
new file mode 100644
index 0000000000..73a7e6860d
--- /dev/null
+++ b/tools/pe_bliss/pe_debug.h
@@ -0,0 +1,324 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <vector>
+#include "pe_structures.h"
+#include "pe_base.h"
+
+namespace pe_bliss
+{
+//Class representing advanced RSDS (PDB 7.0) information
+class pdb_7_0_info
+{
+public:
+ //Default constructor
+ pdb_7_0_info();
+ //Constructor from data
+ explicit pdb_7_0_info(const pe_win::CV_INFO_PDB70* info);
+
+ //Returns debug PDB 7.0 structure GUID
+ const pe_win::guid get_guid() const;
+ //Returns age of build
+ uint32_t get_age() const;
+ //Returns PDB file name / path
+ const std::string& get_pdb_file_name() const;
+
+private:
+ uint32_t age_;
+ pe_win::guid guid_;
+ std::string pdb_file_name_;
+};
+
+//Class representing advanced NB10 (PDB 2.0) information
+class pdb_2_0_info
+{
+public:
+ //Default constructor
+ pdb_2_0_info();
+ //Constructor from data
+ explicit pdb_2_0_info(const pe_win::CV_INFO_PDB20* info);
+
+ //Returns debug PDB 2.0 structure signature
+ uint32_t get_signature() const;
+ //Returns age of build
+ uint32_t get_age() const;
+ //Returns PDB file name / path
+ const std::string& get_pdb_file_name() const;
+
+private:
+ uint32_t age_;
+ uint32_t signature_;
+ std::string pdb_file_name_;
+};
+
+//Class representing advanced misc (IMAGE_DEBUG_TYPE_MISC) info
+class misc_debug_info
+{
+public:
+ //Default constructor
+ misc_debug_info();
+ //Constructor from data
+ explicit misc_debug_info(const pe_win::image_debug_misc* info);
+
+ //Returns debug data type
+ uint32_t get_data_type() const;
+ //Returns true if data type is exe name
+ bool is_exe_name() const;
+
+ //Returns true if debug data is UNICODE
+ bool is_unicode() const;
+ //Returns debug data (ANSI or UNICODE)
+ const std::string& get_data_ansi() const;
+ const std::wstring& get_data_unicode() const;
+
+private:
+ uint32_t data_type_;
+ bool unicode_;
+ std::string debug_data_ansi_;
+ std::wstring debug_data_unicode_;
+};
+
+//Class representing COFF (IMAGE_DEBUG_TYPE_COFF) debug info
+class coff_debug_info
+{
+public:
+ //Structure representing COFF symbol
+ struct coff_symbol
+ {
+ public:
+ //Default constructor
+ coff_symbol();
+
+ //Returns storage class
+ uint32_t get_storage_class() const;
+ //Returns symbol index
+ uint32_t get_index() const;
+ //Returns section number
+ uint32_t get_section_number() const;
+ //Returns RVA
+ uint32_t get_rva() const;
+ //Returns type
+ uint16_t get_type() const;
+
+ //Returns true if structure contains file name
+ bool is_file() const;
+ //Returns text data (symbol or file name)
+ const std::string& get_symbol() const;
+
+ public: //These functions do not change everything inside image, they are used by PE class
+ //Sets storage class
+ void set_storage_class(uint32_t storage_class);
+ //Sets symbol index
+ void set_index(uint32_t index);
+ //Sets section number
+ void set_section_number(uint32_t section_number);
+ //Sets RVA
+ void set_rva(uint32_t rva);
+ //Sets type
+ void set_type(uint16_t type);
+
+ //Sets file name
+ void set_file_name(const std::string& file_name);
+ //Sets symbol name
+ void set_symbol_name(const std::string& symbol_name);
+
+ private:
+ uint32_t storage_class_;
+ uint32_t index_;
+ uint32_t section_number_, rva_;
+ uint16_t type_;
+ bool is_filename_;
+ std::string name_;
+ };
+
+public:
+ typedef std::vector<coff_symbol> coff_symbols_list;
+
+public:
+ //Default constructor
+ coff_debug_info();
+ //Constructor from data
+ explicit coff_debug_info(const pe_win::image_coff_symbols_header* info);
+
+ //Returns number of symbols
+ uint32_t get_number_of_symbols() const;
+ //Returns virtual address of the first symbol
+ uint32_t get_lva_to_first_symbol() const;
+ //Returns number of line-number entries
+ uint32_t get_number_of_line_numbers() const;
+ //Returns virtual address of the first line-number entry
+ uint32_t get_lva_to_first_line_number() const;
+ //Returns relative virtual address of the first byte of code
+ uint32_t get_rva_to_first_byte_of_code() const;
+ //Returns relative virtual address of the last byte of code
+ uint32_t get_rva_to_last_byte_of_code() const;
+ //Returns relative virtual address of the first byte of data
+ uint32_t get_rva_to_first_byte_of_data() const;
+ //Returns relative virtual address of the last byte of data
+ uint32_t get_rva_to_last_byte_of_data() const;
+
+ //Returns COFF symbols list
+ const coff_symbols_list& get_symbols() const;
+
+public: //These functions do not change everything inside image, they are used by PE class
+ //Adds COFF symbol
+ void add_symbol(const coff_symbol& sym);
+
+private:
+ uint32_t number_of_symbols_;
+ uint32_t lva_to_first_symbol_;
+ uint32_t number_of_line_numbers_;
+ uint32_t lva_to_first_line_number_;
+ uint32_t rva_to_first_byte_of_code_;
+ uint32_t rva_to_last_byte_of_code_;
+ uint32_t rva_to_first_byte_of_data_;
+ uint32_t rva_to_last_byte_of_data_;
+
+private:
+ coff_symbols_list symbols_;
+};
+
+//Class representing debug information
+class debug_info
+{
+public:
+ //Enumeration of debug information types
+ enum debug_info_type
+ {
+ debug_type_unknown,
+ debug_type_coff,
+ debug_type_codeview,
+ debug_type_fpo,
+ debug_type_misc,
+ debug_type_exception,
+ debug_type_fixup,
+ debug_type_omap_to_src,
+ debug_type_omap_from_src,
+ debug_type_borland,
+ debug_type_reserved10,
+ debug_type_clsid
+ };
+
+public:
+ //Enumeration of advanced debug information types
+ enum advanced_info_type
+ {
+ advanced_info_none, //No advanced info
+ advanced_info_pdb_7_0, //PDB 7.0
+ advanced_info_pdb_2_0, //PDB 2.0
+ advanced_info_misc, //MISC debug info
+ advanced_info_coff, //COFF debug info
+ //No advanced info structures available for types below
+ advanced_info_codeview_4_0, //CodeView 4.0
+ advanced_info_codeview_5_0, //CodeView 5.0
+ advanced_info_codeview //CodeView
+ };
+
+public:
+ //Default constructor
+ debug_info();
+ //Constructor from data
+ explicit debug_info(const pe_win::image_debug_directory& debug);
+ //Copy constructor
+ debug_info(const debug_info& info);
+ //Copy assignment operator
+ debug_info& operator=(const debug_info& info);
+ //Destructor
+ ~debug_info();
+
+ //Returns debug characteristics
+ uint32_t get_characteristics() const;
+ //Returns debug datetimestamp
+ uint32_t get_time_stamp() const;
+ //Returns major version
+ uint32_t get_major_version() const;
+ //Returns minor version
+ uint32_t get_minor_version() const;
+ //Returns type of debug info (unchecked)
+ uint32_t get_type_raw() const;
+ //Returns type of debug info from debug_info_type enumeration
+ debug_info_type get_type() const;
+ //Returns size of debug data (internal, .pdb or other file doesn't count)
+ uint32_t get_size_of_data() const;
+ //Returns RVA of debug info when mapped to memory or zero, if info is not mapped
+ uint32_t get_rva_of_raw_data() const;
+ //Returns raw file pointer to raw data
+ uint32_t get_pointer_to_raw_data() const;
+
+ //Returns advanced debug information type
+ advanced_info_type get_advanced_info_type() const;
+ //Returns advanced debug information or throws an exception,
+ //if requested information type is not contained by structure
+ template<typename AdvancedInfo>
+ const AdvancedInfo get_advanced_debug_info() const;
+
+public: //These functions do not change everything inside image, they are used by PE class
+ //Sets advanced debug information
+ void set_advanced_debug_info(const pdb_7_0_info& info);
+ void set_advanced_debug_info(const pdb_2_0_info& info);
+ void set_advanced_debug_info(const misc_debug_info& info);
+ void set_advanced_debug_info(const coff_debug_info& info);
+
+ //Sets advanced debug information type, if no advanced info structure available
+ void set_advanced_info_type(advanced_info_type type);
+
+private:
+ uint32_t characteristics_;
+ uint32_t time_stamp_;
+ uint32_t major_version_, minor_version_;
+ uint32_t type_;
+ uint32_t size_of_data_;
+ uint32_t address_of_raw_data_; //RVA when mapped or 0
+ uint32_t pointer_to_raw_data_; //RAW file offset
+
+ //Union containing advanced debug information pointer
+ union advanced_info
+ {
+ public:
+ //Default constructor
+ advanced_info();
+
+ //Returns true if advanced debug info is present
+ bool is_present() const;
+
+ public:
+ pdb_7_0_info* adv_pdb_7_0_info;
+ pdb_2_0_info* adv_pdb_2_0_info;
+ misc_debug_info* adv_misc_info;
+ coff_debug_info* adv_coff_info;
+ };
+
+ //Helper for advanced debug information copying
+ void copy_advanced_info(const debug_info& info);
+ //Helper for clearing any present advanced debug information
+ void free_present_advanced_info();
+
+ advanced_info advanced_debug_info_;
+ //Advanced information type
+ advanced_info_type advanced_info_type_;
+};
+
+typedef std::vector<debug_info> debug_info_list;
+
+//Returns debug information list
+const debug_info_list get_debug_information(const pe_base& pe);
+}
diff --git a/tools/pe_bliss/pe_directory.cpp b/tools/pe_bliss/pe_directory.cpp
new file mode 100644
index 0000000000..13ad2afc5d
--- /dev/null
+++ b/tools/pe_bliss/pe_directory.cpp
@@ -0,0 +1,59 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include "pe_directory.h"
+
+namespace pe_bliss
+{
+//Default constructor
+image_directory::image_directory()
+ :rva_(0), size_(0)
+{}
+
+//Constructor from data
+image_directory::image_directory(uint32_t rva, uint32_t size)
+ :rva_(rva), size_(size)
+{}
+
+//Returns RVA
+uint32_t image_directory::get_rva() const
+{
+ return rva_;
+}
+
+//Returns size
+uint32_t image_directory::get_size() const
+{
+ return size_;
+}
+
+//Sets RVA
+void image_directory::set_rva(uint32_t rva)
+{
+ rva_ = rva;
+}
+
+//Sets size
+void image_directory::set_size(uint32_t size)
+{
+ size_ = size;
+}
+}
diff --git a/tools/pe_bliss/pe_directory.h b/tools/pe_bliss/pe_directory.h
new file mode 100644
index 0000000000..a7b1ea7a5f
--- /dev/null
+++ b/tools/pe_bliss/pe_directory.h
@@ -0,0 +1,50 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include "stdint_defs.h"
+
+namespace pe_bliss
+{
+//Class representing image directory data
+class image_directory
+{
+public:
+ //Default constructor
+ image_directory();
+ //Constructor from data
+ image_directory(uint32_t rva, uint32_t size);
+
+ //Returns RVA
+ uint32_t get_rva() const;
+ //Returns size
+ uint32_t get_size() const;
+
+ //Sets RVA
+ void set_rva(uint32_t rva);
+ //Sets size
+ void set_size(uint32_t size);
+
+private:
+ uint32_t rva_;
+ uint32_t size_;
+};
+}
diff --git a/tools/pe_bliss/pe_dotnet.cpp b/tools/pe_bliss/pe_dotnet.cpp
new file mode 100644
index 0000000000..f34a76eae8
--- /dev/null
+++ b/tools/pe_bliss/pe_dotnet.cpp
@@ -0,0 +1,186 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include <string.h>
+#include "pe_dotnet.h"
+
+namespace pe_bliss
+{
+using namespace pe_win;
+
+//.NET
+basic_dotnet_info::basic_dotnet_info()
+{
+ memset(&header_, 0, sizeof(header_));
+}
+
+//Constructor from data
+basic_dotnet_info::basic_dotnet_info(const image_cor20_header& header)
+ :header_(header)
+{}
+
+//Returns major runtime version
+uint16_t basic_dotnet_info::get_major_runtime_version() const
+{
+ return header_.MajorRuntimeVersion;
+}
+
+//Returns minor runtime version
+uint16_t basic_dotnet_info::get_minor_runtime_version() const
+{
+ return header_.MinorRuntimeVersion;
+}
+
+//Returns RVA of metadata (symbol table and startup information)
+uint32_t basic_dotnet_info::get_rva_of_metadata() const
+{
+ return header_.MetaData.VirtualAddress;
+}
+
+//Returns size of metadata (symbol table and startup information)
+uint32_t basic_dotnet_info::get_size_of_metadata() const
+{
+ return header_.MetaData.Size;
+}
+
+//Returns flags
+uint32_t basic_dotnet_info::get_flags() const
+{
+ return header_.Flags;
+}
+
+//Returns true if entry point is native
+bool basic_dotnet_info::is_native_entry_point() const
+{
+ return (header_.Flags & comimage_flags_native_entrypoint) ? true : false;
+}
+
+//Returns true if 32 bit required
+bool basic_dotnet_info::is_32bit_required() const
+{
+ return (header_.Flags & comimage_flags_32bitrequired) ? true : false;
+}
+
+//Returns true if image is IL library
+bool basic_dotnet_info::is_il_library() const
+{
+ return (header_.Flags & comimage_flags_il_library) ? true : false;
+}
+
+//Returns true if image uses IL only
+bool basic_dotnet_info::is_il_only() const
+{
+ return (header_.Flags & comimage_flags_ilonly) ? true : false;
+}
+
+//Returns entry point RVA (if entry point is native)
+//Returns entry point managed token (if entry point is managed)
+uint32_t basic_dotnet_info::get_entry_point_rva_or_token() const
+{
+ return header_.EntryPointToken;
+}
+
+//Returns RVA of managed resources
+uint32_t basic_dotnet_info::get_rva_of_resources() const
+{
+ return header_.Resources.VirtualAddress;
+}
+
+//Returns size of managed resources
+uint32_t basic_dotnet_info::get_size_of_resources() const
+{
+ return header_.Resources.Size;
+}
+
+//Returns RVA of strong name signature
+uint32_t basic_dotnet_info::get_rva_of_strong_name_signature() const
+{
+ return header_.StrongNameSignature.VirtualAddress;
+}
+
+//Returns size of strong name signature
+uint32_t basic_dotnet_info::get_size_of_strong_name_signature() const
+{
+ return header_.StrongNameSignature.Size;
+}
+
+//Returns RVA of code manager table
+uint32_t basic_dotnet_info::get_rva_of_code_manager_table() const
+{
+ return header_.CodeManagerTable.VirtualAddress;
+}
+
+//Returns size of code manager table
+uint32_t basic_dotnet_info::get_size_of_code_manager_table() const
+{
+ return header_.CodeManagerTable.Size;
+}
+
+//Returns RVA of VTable fixups
+uint32_t basic_dotnet_info::get_rva_of_vtable_fixups() const
+{
+ return header_.VTableFixups.VirtualAddress;
+}
+
+//Returns size of VTable fixups
+uint32_t basic_dotnet_info::get_size_of_vtable_fixups() const
+{
+ return header_.VTableFixups.Size;
+}
+
+//Returns RVA of export address table jumps
+uint32_t basic_dotnet_info::get_rva_of_export_address_table_jumps() const
+{
+ return header_.ExportAddressTableJumps.VirtualAddress;
+}
+
+//Returns size of export address table jumps
+uint32_t basic_dotnet_info::get_size_of_export_address_table_jumps() const
+{
+ return header_.ExportAddressTableJumps.Size;
+}
+
+//Returns RVA of managed native header
+//(precompiled header info, usually set to zero, for internal use)
+uint32_t basic_dotnet_info::get_rva_of_managed_native_header() const
+{
+ return header_.ManagedNativeHeader.VirtualAddress;
+}
+
+//Returns size of managed native header
+//(precompiled header info, usually set to zero, for internal use)
+uint32_t basic_dotnet_info::get_size_of_managed_native_header() const
+{
+ return header_.ManagedNativeHeader.Size;
+}
+
+//Returns basic .NET information
+//If image is not native, throws an exception
+const basic_dotnet_info get_basic_dotnet_info(const pe_base& pe)
+{
+ //If there's no debug directory, return empty list
+ if(!pe.is_dotnet())
+ throw pe_exception("Image does not have managed code", pe_exception::image_does_not_have_managed_code);
+
+ //Return basic .NET information
+ return basic_dotnet_info(pe.section_data_from_rva<image_cor20_header>(pe.get_directory_rva(image_directory_entry_com_descriptor), section_data_virtual, true));
+}
+}
diff --git a/tools/pe_bliss/pe_dotnet.h b/tools/pe_bliss/pe_dotnet.h
new file mode 100644
index 0000000000..96b0ac7d0a
--- /dev/null
+++ b/tools/pe_bliss/pe_dotnet.h
@@ -0,0 +1,97 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include "pe_structures.h"
+#include "pe_base.h"
+
+namespace pe_bliss
+{
+//Class representing basic .NET header information
+class basic_dotnet_info
+{
+public:
+ //Default constructor
+ basic_dotnet_info();
+ //Constructor from data
+ explicit basic_dotnet_info(const pe_win::image_cor20_header& header);
+
+ //Returns major runtime version
+ uint16_t get_major_runtime_version() const;
+ //Returns minor runtime version
+ uint16_t get_minor_runtime_version() const;
+
+ //Returns RVA of metadata (symbol table and startup information)
+ uint32_t get_rva_of_metadata() const;
+ //Returns size of metadata (symbol table and startup information)
+ uint32_t get_size_of_metadata() const;
+
+ //Returns flags
+ uint32_t get_flags() const;
+
+ //Returns true if entry point is native
+ bool is_native_entry_point() const;
+ //Returns true if 32 bit required
+ bool is_32bit_required() const;
+ //Returns true if image is IL library
+ bool is_il_library() const;
+ //Returns true if image uses IL only
+ bool is_il_only() const;
+
+ //Returns entry point RVA (if entry point is native)
+ //Returns entry point managed token (if entry point is managed)
+ uint32_t get_entry_point_rva_or_token() const;
+
+ //Returns RVA of managed resources
+ uint32_t get_rva_of_resources() const;
+ //Returns size of managed resources
+ uint32_t get_size_of_resources() const;
+ //Returns RVA of strong name signature
+ uint32_t get_rva_of_strong_name_signature() const;
+ //Returns size of strong name signature
+ uint32_t get_size_of_strong_name_signature() const;
+ //Returns RVA of code manager table
+ uint32_t get_rva_of_code_manager_table() const;
+ //Returns size of code manager table
+ uint32_t get_size_of_code_manager_table() const;
+ //Returns RVA of VTable fixups
+ uint32_t get_rva_of_vtable_fixups() const;
+ //Returns size of VTable fixups
+ uint32_t get_size_of_vtable_fixups() const;
+ //Returns RVA of export address table jumps
+ uint32_t get_rva_of_export_address_table_jumps() const;
+ //Returns size of export address table jumps
+ uint32_t get_size_of_export_address_table_jumps() const;
+ //Returns RVA of managed native header
+ //(precompiled header info, usually set to zero, for internal use)
+ uint32_t get_rva_of_managed_native_header() const;
+ //Returns size of managed native header
+ //(precompiled header info, usually set to zero, for internal use)
+ uint32_t get_size_of_managed_native_header() const;
+
+private:
+ pe_win::image_cor20_header header_;
+};
+
+//Returns basic .NET information
+//If image is not native, throws an exception
+const basic_dotnet_info get_basic_dotnet_info(const pe_base& pe);
+}
diff --git a/tools/pe_bliss/pe_exception.cpp b/tools/pe_bliss/pe_exception.cpp
new file mode 100644
index 0000000000..3161f93599
--- /dev/null
+++ b/tools/pe_bliss/pe_exception.cpp
@@ -0,0 +1,40 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include "pe_exception.h"
+
+namespace pe_bliss
+{
+//PE exception class constructors
+pe_exception::pe_exception(const char* text, exception_id id)
+ :std::runtime_error(text), id_(id)
+{}
+
+pe_exception::pe_exception(const std::string& text, exception_id id)
+ :std::runtime_error(text), id_(id)
+{}
+
+//Returns exception ID
+pe_exception::exception_id pe_exception::get_id() const
+{
+ return id_;
+}
+}
diff --git a/tools/pe_bliss/pe_exception.h b/tools/pe_bliss/pe_exception.h
new file mode 100644
index 0000000000..2b58a95772
--- /dev/null
+++ b/tools/pe_bliss/pe_exception.h
@@ -0,0 +1,130 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <exception>
+#include <stdexcept>
+
+namespace pe_bliss
+{
+//PE exception class
+class pe_exception : public std::runtime_error
+{
+public:
+ //Exception IDs
+ enum exception_id
+ {
+ unknown_error,
+ bad_pe_file,
+ bad_dos_header,
+ image_nt_headers_not_found,
+ error_reading_image_nt_headers,
+ error_reading_data_directories,
+ error_reading_file,
+ pe_signature_incorrect,
+ incorrect_number_of_rva_and_sizes,
+ error_changing_section_virtual_size,
+ section_number_incorrect,
+ section_table_incorrect,
+ incorrect_section_alignment,
+ incorrect_file_alignment,
+ incorrect_size_of_image,
+ incorrect_size_of_headers,
+ image_section_headers_not_found,
+ zero_section_sizes,
+ section_incorrect_addr_or_size,
+ section_not_found,
+ image_section_data_not_found,
+ no_section_found,
+ image_section_table_incorrect,
+ directory_does_not_exist,
+ rva_not_exists,
+ error_reading_section_header,
+ error_reading_overlay,
+ incorrect_address_conversion,
+
+ incorrect_export_directory,
+ incorrect_import_directory,
+ incorrect_relocation_directory,
+ incorrect_tls_directory,
+ incorrect_config_directory,
+ incorrect_bound_import_directory,
+ incorrect_resource_directory,
+ incorrect_exception_directory,
+ incorrect_debug_directory,
+
+ resource_directory_entry_error,
+ resource_directory_entry_not_found,
+ resource_data_entry_not_found,
+ resource_incorrect_bitmap,
+ resource_incorrect_icon,
+ resource_incorrect_cursor,
+ resource_incorrect_string_table,
+ resource_string_not_found,
+ resource_incorrect_message_table,
+ resource_incorrect_version_info,
+
+ advanced_debug_information_request_error,
+ image_does_not_have_managed_code,
+
+ section_is_empty,
+ data_is_empty,
+ stream_is_bad,
+
+ section_is_not_attached,
+ insufficient_space,
+
+ cannot_rebase_relocations,
+
+ exports_list_is_empty,
+ duplicate_exported_function_ordinal,
+ duplicate_exported_function_name,
+
+ version_info_string_does_not_exist,
+
+ no_more_sections_can_be_added,
+
+ no_icon_group_found,
+ no_cursor_group_found,
+
+ encoding_convertion_error,
+
+ error_expanding_section,
+
+ cannot_rebuild_image
+ };
+
+public:
+ //Class constructors
+ explicit pe_exception(const char* text, exception_id id = unknown_error);
+ explicit pe_exception(const std::string& text, exception_id id = unknown_error);
+
+ //Returns exception ID from exception_id enumeration
+ exception_id get_id() const;
+
+ //Destructor
+ virtual ~pe_exception() throw()
+ {}
+
+private:
+ exception_id id_;
+};
+}
diff --git a/tools/pe_bliss/pe_exception_directory.cpp b/tools/pe_bliss/pe_exception_directory.cpp
new file mode 100644
index 0000000000..1813f02021
--- /dev/null
+++ b/tools/pe_bliss/pe_exception_directory.cpp
@@ -0,0 +1,177 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include "pe_exception_directory.h"
+
+namespace pe_bliss
+{
+using namespace pe_win;
+
+//EXCEPTION DIRECTORY (exists on PE+ only)
+//Default constructor
+exception_entry::exception_entry()
+ :begin_address_(0), end_address_(0), unwind_info_address_(0),
+ unwind_info_version_(0),
+ flags_(0),
+ size_of_prolog_(0),
+ count_of_codes_(0),
+ frame_register_(0),
+ frame_offset_(0)
+{}
+
+//Constructor from data
+exception_entry::exception_entry(const image_runtime_function_entry& entry, const unwind_info& unwind_info)
+ :begin_address_(entry.BeginAddress), end_address_(entry.EndAddress), unwind_info_address_(entry.UnwindInfoAddress),
+ unwind_info_version_(unwind_info.Version),
+ flags_(unwind_info.Flags),
+ size_of_prolog_(unwind_info.SizeOfProlog),
+ count_of_codes_(unwind_info.CountOfCodes),
+ frame_register_(unwind_info.FrameRegister),
+ frame_offset_(unwind_info.FrameOffset)
+{}
+
+//Returns starting address of function, affected by exception unwinding
+uint32_t exception_entry::get_begin_address() const
+{
+ return begin_address_;
+}
+
+//Returns ending address of function, affected by exception unwinding
+uint32_t exception_entry::get_end_address() const
+{
+ return end_address_;
+}
+
+//Returns unwind info address
+uint32_t exception_entry::get_unwind_info_address() const
+{
+ return unwind_info_address_;
+}
+
+//Returns UNWIND_INFO structure version
+uint8_t exception_entry::get_unwind_info_version() const
+{
+ return unwind_info_version_;
+}
+
+//Returns unwind info flags
+uint8_t exception_entry::get_flags() const
+{
+ return flags_;
+}
+
+//The function has an exception handler that should be called
+//when looking for functions that need to examine exceptions
+bool exception_entry::has_exception_handler() const
+{
+ return (flags_ & unw_flag_ehandler) ? true : false;
+}
+
+//The function has a termination handler that should be called
+//when unwinding an exception
+bool exception_entry::has_termination_handler() const
+{
+ return (flags_ & unw_flag_uhandler) ? true : false;
+}
+
+//The unwind info structure is not the primary one for the procedure
+bool exception_entry::is_chaininfo() const
+{
+ return (flags_ & unw_flag_chaininfo) ? true : false;
+}
+
+//Returns size of function prolog
+uint8_t exception_entry::get_size_of_prolog() const
+{
+ return size_of_prolog_;
+}
+
+//Returns number of unwind slots
+uint8_t exception_entry::get_number_of_unwind_slots() const
+{
+ return count_of_codes_;
+}
+
+//If the function uses frame pointer
+bool exception_entry::uses_frame_pointer() const
+{
+ return frame_register_ != 0;
+}
+
+//Number of the nonvolatile register used as the frame pointer,
+//using the same encoding for the operation info field of UNWIND_CODE nodes
+uint8_t exception_entry::get_frame_pointer_register_number() const
+{
+ return frame_register_;
+}
+
+//The scaled offset from RSP that is applied to the FP reg when it is established.
+//The actual FP reg is set to RSP + 16 * this number, allowing offsets from 0 to 240
+uint8_t exception_entry::get_scaled_rsp_offset() const
+{
+ return frame_offset_;
+}
+
+//Returns exception directory data (exists on PE+ only)
+//Unwind opcodes are not listed, because their format and list are subject to change
+const exception_entry_list get_exception_directory_data(const pe_base& pe)
+{
+ exception_entry_list ret;
+
+ //If image doesn't have exception directory, return empty list
+ if(!pe.has_exception_directory())
+ return ret;
+
+ //Check the length in bytes of the section containing exception directory
+ if(pe.section_data_length_from_rva(pe.get_directory_rva(image_directory_entry_exception), pe.get_directory_rva(image_directory_entry_exception), section_data_virtual, true)
+ < sizeof(image_runtime_function_entry))
+ throw pe_exception("Incorrect exception directory", pe_exception::incorrect_exception_directory);
+
+ unsigned long current_pos = pe.get_directory_rva(image_directory_entry_exception);
+
+ //Check if structures are DWORD-aligned
+ if(current_pos % sizeof(uint32_t))
+ throw pe_exception("Incorrect exception directory", pe_exception::incorrect_exception_directory);
+
+ //First IMAGE_RUNTIME_FUNCTION_ENTRY table
+ image_runtime_function_entry exception_table = pe.section_data_from_rva<image_runtime_function_entry>(current_pos, section_data_virtual, true);
+
+ //todo: virtual addresses BeginAddress and EndAddress are not checked to be inside image
+ while(exception_table.BeginAddress)
+ {
+ //Check addresses
+ if(exception_table.BeginAddress > exception_table.EndAddress)
+ throw pe_exception("Incorrect exception directory", pe_exception::incorrect_exception_directory);
+
+ //Get unwind information
+ unwind_info info = pe.section_data_from_rva<unwind_info>(exception_table.UnwindInfoAddress, section_data_virtual, true);
+
+ //Create exception entry and save it
+ ret.push_back(exception_entry(exception_table, info));
+
+ //Go to next exception entry
+ current_pos += sizeof(image_runtime_function_entry);
+ exception_table = pe.section_data_from_rva<image_runtime_function_entry>(current_pos, section_data_virtual, true);
+ }
+
+ return ret;
+}
+}
diff --git a/tools/pe_bliss/pe_exception_directory.h b/tools/pe_bliss/pe_exception_directory.h
new file mode 100644
index 0000000000..6f4fc2298b
--- /dev/null
+++ b/tools/pe_bliss/pe_exception_directory.h
@@ -0,0 +1,88 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <vector>
+#include "pe_structures.h"
+#include "pe_base.h"
+
+namespace pe_bliss
+{
+//Class representing exception directory entry
+class exception_entry
+{
+public:
+ //Default constructor
+ exception_entry();
+ //Constructor from data
+ exception_entry(const pe_win::image_runtime_function_entry& entry, const pe_win::unwind_info& unwind_info);
+
+ //Returns starting address of function, affected by exception unwinding
+ uint32_t get_begin_address() const;
+ //Returns ending address of function, affected by exception unwinding
+ uint32_t get_end_address() const;
+ //Returns unwind info address
+ uint32_t get_unwind_info_address() const;
+
+ //Returns UNWIND_INFO structure version
+ uint8_t get_unwind_info_version() const;
+
+ //Returns unwind info flags
+ uint8_t get_flags() const;
+ //The function has an exception handler that should be called
+ //when looking for functions that need to examine exceptions
+ bool has_exception_handler() const;
+ //The function has a termination handler that should be called
+ //when unwinding an exception
+ bool has_termination_handler() const;
+ //The unwind info structure is not the primary one for the procedure
+ bool is_chaininfo() const;
+
+ //Returns size of function prolog
+ uint8_t get_size_of_prolog() const;
+
+ //Returns number of unwind slots
+ uint8_t get_number_of_unwind_slots() const;
+
+ //If the function uses frame pointer
+ bool uses_frame_pointer() const;
+ //Number of the nonvolatile register used as the frame pointer,
+ //using the same encoding for the operation info field of UNWIND_CODE nodes
+ uint8_t get_frame_pointer_register_number() const;
+ //The scaled offset from RSP that is applied to the FP reg when it is established.
+ //The actual FP reg is set to RSP + 16 * this number, allowing offsets from 0 to 240
+ uint8_t get_scaled_rsp_offset() const;
+
+private:
+ uint32_t begin_address_, end_address_, unwind_info_address_;
+ uint8_t unwind_info_version_;
+ uint8_t flags_;
+ uint8_t size_of_prolog_;
+ uint8_t count_of_codes_;
+ uint8_t frame_register_, frame_offset_;
+};
+
+typedef std::vector<exception_entry> exception_entry_list;
+
+//Returns exception directory data (exists on PE+ only)
+//Unwind opcodes are not listed, because their format and list are subject to change
+const exception_entry_list get_exception_directory_data(const pe_base& pe);
+}
diff --git a/tools/pe_bliss/pe_exports.cpp b/tools/pe_bliss/pe_exports.cpp
new file mode 100644
index 0000000000..c2ad895554
--- /dev/null
+++ b/tools/pe_bliss/pe_exports.cpp
@@ -0,0 +1,700 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include <set>
+#include <algorithm>
+#include <string.h>
+#include "pe_exports.h"
+#include "utils.h"
+
+namespace pe_bliss
+{
+using namespace pe_win;
+
+//EXPORTS
+//Default constructor
+exported_function::exported_function()
+ :ordinal_(0), rva_(0), has_name_(false), name_ordinal_(0), forward_(false)
+{}
+
+//Returns ordinal of function (actually, ordinal = hint + ordinal base)
+uint16_t exported_function::get_ordinal() const
+{
+ return ordinal_;
+}
+
+//Returns RVA of function
+uint32_t exported_function::get_rva() const
+{
+ return rva_;
+}
+
+//Returns name of function
+const std::string& exported_function::get_name() const
+{
+ return name_;
+}
+
+//Returns true if function has name and name ordinal
+bool exported_function::has_name() const
+{
+ return has_name_;
+}
+
+//Returns name ordinal of function
+uint16_t exported_function::get_name_ordinal() const
+{
+ return name_ordinal_;
+}
+
+//Returns true if function is forwarded to other library
+bool exported_function::is_forwarded() const
+{
+ return forward_;
+}
+
+//Returns the name of forwarded function
+const std::string& exported_function::get_forwarded_name() const
+{
+ return forward_name_;
+}
+
+//Sets ordinal of function
+void exported_function::set_ordinal(uint16_t ordinal)
+{
+ ordinal_ = ordinal;
+}
+
+//Sets RVA of function
+void exported_function::set_rva(uint32_t rva)
+{
+ rva_ = rva;
+}
+
+//Sets name of function (or clears it, if empty name is passed)
+void exported_function::set_name(const std::string& name)
+{
+ name_ = name;
+ has_name_ = !name.empty();
+}
+
+//Sets name ordinal
+void exported_function::set_name_ordinal(uint16_t name_ordinal)
+{
+ name_ordinal_ = name_ordinal;
+}
+
+//Sets forwarded function name (or clears it, if empty name is passed)
+void exported_function::set_forwarded_name(const std::string& name)
+{
+ forward_name_ = name;
+ forward_ = !name.empty();
+}
+
+//Default constructor
+export_info::export_info()
+ :characteristics_(0),
+ timestamp_(0),
+ major_version_(0),
+ minor_version_(0),
+ ordinal_base_(0),
+ number_of_functions_(0),
+ number_of_names_(0),
+ address_of_functions_(0),
+ address_of_names_(0),
+ address_of_name_ordinals_(0)
+{}
+
+//Returns characteristics
+uint32_t export_info::get_characteristics() const
+{
+ return characteristics_;
+}
+
+//Returns timestamp
+uint32_t export_info::get_timestamp() const
+{
+ return timestamp_;
+}
+
+//Returns major version
+uint16_t export_info::get_major_version() const
+{
+ return major_version_;
+}
+
+//Returns minor version
+uint16_t export_info::get_minor_version() const
+{
+ return minor_version_;
+}
+
+//Returns DLL name
+const std::string& export_info::get_name() const
+{
+ return name_;
+}
+
+//Returns ordinal base
+uint32_t export_info::get_ordinal_base() const
+{
+ return ordinal_base_;
+}
+
+//Returns number of functions
+uint32_t export_info::get_number_of_functions() const
+{
+ return number_of_functions_;
+}
+
+//Returns number of function names
+uint32_t export_info::get_number_of_names() const
+{
+ return number_of_names_;
+}
+
+//Returns RVA of function address table
+uint32_t export_info::get_rva_of_functions() const
+{
+ return address_of_functions_;
+}
+
+//Returns RVA of function name address table
+uint32_t export_info::get_rva_of_names() const
+{
+ return address_of_names_;
+}
+
+//Returns RVA of name ordinals table
+uint32_t export_info::get_rva_of_name_ordinals() const
+{
+ return address_of_name_ordinals_;
+}
+
+//Sets characteristics
+void export_info::set_characteristics(uint32_t characteristics)
+{
+ characteristics_ = characteristics;
+}
+
+//Sets timestamp
+void export_info::set_timestamp(uint32_t timestamp)
+{
+ timestamp_ = timestamp;
+}
+
+//Sets major version
+void export_info::set_major_version(uint16_t major_version)
+{
+ major_version_ = major_version;
+}
+
+//Sets minor version
+void export_info::set_minor_version(uint16_t minor_version)
+{
+ minor_version_ = minor_version;
+}
+
+//Sets DLL name
+void export_info::set_name(const std::string& name)
+{
+ name_ = name;
+}
+
+//Sets ordinal base
+void export_info::set_ordinal_base(uint32_t ordinal_base)
+{
+ ordinal_base_ = ordinal_base;
+}
+
+//Sets number of functions
+void export_info::set_number_of_functions(uint32_t number_of_functions)
+{
+ number_of_functions_ = number_of_functions;
+}
+
+//Sets number of function names
+void export_info::set_number_of_names(uint32_t number_of_names)
+{
+ number_of_names_ = number_of_names;
+}
+
+//Sets RVA of function address table
+void export_info::set_rva_of_functions(uint32_t rva_of_functions)
+{
+ address_of_functions_ = rva_of_functions;
+}
+
+//Sets RVA of function name address table
+void export_info::set_rva_of_names(uint32_t rva_of_names)
+{
+ address_of_names_ = rva_of_names;
+}
+
+//Sets RVA of name ordinals table
+void export_info::set_rva_of_name_ordinals(uint32_t rva_of_name_ordinals)
+{
+ address_of_name_ordinals_ = rva_of_name_ordinals;
+}
+
+const exported_functions_list get_exported_functions(const pe_base& pe, export_info* info);
+
+//Returns array of exported functions
+const exported_functions_list get_exported_functions(const pe_base& pe)
+{
+ return get_exported_functions(pe, 0);
+}
+
+//Returns array of exported functions and information about export
+const exported_functions_list get_exported_functions(const pe_base& pe, export_info& info)
+{
+ return get_exported_functions(pe, &info);
+}
+
+//Helper: sorts exported function list by ordinals
+struct ordinal_sorter
+{
+public:
+ bool operator()(const exported_function& func1, const exported_function& func2) const;
+};
+
+//Returns array of exported functions and information about export (if info != 0)
+const exported_functions_list get_exported_functions(const pe_base& pe, export_info* info)
+{
+ //Returned exported functions info array
+ std::vector<exported_function> ret;
+
+ if(pe.has_exports())
+ {
+ //Check the length in bytes of the section containing export directory
+ if(pe.section_data_length_from_rva(pe.get_directory_rva(image_directory_entry_export),
+ pe.get_directory_rva(image_directory_entry_export), section_data_virtual, true)
+ < sizeof(image_export_directory))
+ throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory);
+
+ image_export_directory exports = pe.section_data_from_rva<image_export_directory>(pe.get_directory_rva(image_directory_entry_export), section_data_virtual, true);
+
+ unsigned long max_name_length;
+
+ if(info)
+ {
+ //Save some export info data
+ info->set_characteristics(exports.Characteristics);
+ info->set_major_version(exports.MajorVersion);
+ info->set_minor_version(exports.MinorVersion);
+
+ //Get byte count that we have for dll name
+ if((max_name_length = pe.section_data_length_from_rva(exports.Name, exports.Name, section_data_virtual, true)) < 2)
+ throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory);
+
+ //Get dll name pointer
+ const char* dll_name = pe.section_data_from_rva(exports.Name, section_data_virtual, true);
+
+ //Check for null-termination
+ if(!pe_utils::is_null_terminated(dll_name, max_name_length))
+ throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory);
+
+ //Save the rest of export information data
+ info->set_name(dll_name);
+ info->set_number_of_functions(exports.NumberOfFunctions);
+ info->set_number_of_names(exports.NumberOfNames);
+ info->set_ordinal_base(exports.Base);
+ info->set_rva_of_functions(exports.AddressOfFunctions);
+ info->set_rva_of_names(exports.AddressOfNames);
+ info->set_rva_of_name_ordinals(exports.AddressOfNameOrdinals);
+ info->set_timestamp(exports.TimeDateStamp);
+ }
+
+ if(!exports.NumberOfFunctions)
+ return ret;
+
+ //Check IMAGE_EXPORT_DIRECTORY fields
+ if(exports.NumberOfNames > exports.NumberOfFunctions)
+ throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory);
+
+ //Check some export directory fields
+ if((!exports.AddressOfNameOrdinals && exports.AddressOfNames) ||
+ (exports.AddressOfNameOrdinals && !exports.AddressOfNames) ||
+ !exports.AddressOfFunctions
+ || exports.NumberOfFunctions >= pe_utils::max_dword / sizeof(uint32_t)
+ || exports.NumberOfNames > pe_utils::max_dword / sizeof(uint32_t)
+ || !pe_utils::is_sum_safe(exports.AddressOfFunctions, exports.NumberOfFunctions * sizeof(uint32_t))
+ || !pe_utils::is_sum_safe(exports.AddressOfNames, exports.NumberOfNames * sizeof(uint32_t))
+ || !pe_utils::is_sum_safe(exports.AddressOfNameOrdinals, exports.NumberOfFunctions * sizeof(uint32_t))
+ || !pe_utils::is_sum_safe(pe.get_directory_rva(image_directory_entry_export), pe.get_directory_size(image_directory_entry_export)))
+ throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory);
+
+ //Check if it is enough bytes to hold AddressOfFunctions table
+ if(pe.section_data_length_from_rva(exports.AddressOfFunctions, exports.AddressOfFunctions, section_data_virtual, true)
+ < exports.NumberOfFunctions * sizeof(uint32_t))
+ throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory);
+
+ if(exports.AddressOfNames)
+ {
+ //Check if it is enough bytes to hold name and ordinal tables
+ if(pe.section_data_length_from_rva(exports.AddressOfNameOrdinals, exports.AddressOfNameOrdinals, section_data_virtual, true)
+ < exports.NumberOfNames * sizeof(uint16_t))
+ throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory);
+
+ if(pe.section_data_length_from_rva(exports.AddressOfNames, exports.AddressOfNames, section_data_virtual, true)
+ < exports.NumberOfNames * sizeof(uint32_t))
+ throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory);
+ }
+
+ for(uint32_t ordinal = 0; ordinal < exports.NumberOfFunctions; ordinal++)
+ {
+ //Get function address
+ //Sum and multiplication are safe (checked above)
+ uint32_t rva = pe.section_data_from_rva<uint32_t>(exports.AddressOfFunctions + ordinal * sizeof(uint32_t), section_data_virtual, true);
+
+ //If we have a skip
+ if(!rva)
+ continue;
+
+ exported_function func;
+ func.set_rva(rva);
+
+ if(!pe_utils::is_sum_safe(exports.Base, ordinal) || exports.Base + ordinal > pe_utils::max_word)
+ throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory);
+
+ func.set_ordinal(static_cast<uint16_t>(ordinal + exports.Base));
+
+ //Scan for function name ordinal
+ for(uint32_t i = 0; i < exports.NumberOfNames; i++)
+ {
+ uint16_t ordinal2 = pe.section_data_from_rva<uint16_t>(exports.AddressOfNameOrdinals + i * sizeof(uint16_t), section_data_virtual, true);
+
+ //If function has name (and name ordinal)
+ if(ordinal == ordinal2)
+ {
+ //Get function name
+ //Sum and multiplication are safe (checked above)
+ uint32_t function_name_rva = pe.section_data_from_rva<uint32_t>(exports.AddressOfNames + i * sizeof(uint32_t), section_data_virtual, true);
+
+ //Get byte count that we have for function name
+ if((max_name_length = pe.section_data_length_from_rva(function_name_rva, function_name_rva, section_data_virtual, true)) < 2)
+ throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory);
+
+ //Get function name pointer
+ const char* func_name = pe.section_data_from_rva(function_name_rva, section_data_virtual, true);
+
+ //Check for null-termination
+ if(!pe_utils::is_null_terminated(func_name, max_name_length))
+ throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory);
+
+ //Save function info
+ func.set_name(func_name);
+ func.set_name_ordinal(ordinal2);
+
+ //If the function is just a redirect, save its name
+ if(rva >= pe.get_directory_rva(image_directory_entry_export) + sizeof(image_directory_entry_export) &&
+ rva < pe.get_directory_rva(image_directory_entry_export) + pe.get_directory_size(image_directory_entry_export))
+ {
+ if((max_name_length = pe.section_data_length_from_rva(rva, rva, section_data_virtual, true)) < 2)
+ throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory);
+
+ //Get forwarded function name pointer
+ const char* forwarded_func_name = pe.section_data_from_rva(rva, section_data_virtual, true);
+
+ //Check for null-termination
+ if(!pe_utils::is_null_terminated(forwarded_func_name, max_name_length))
+ throw pe_exception("Incorrect export directory", pe_exception::incorrect_export_directory);
+
+ //Set the name of forwarded function
+ func.set_forwarded_name(forwarded_func_name);
+ }
+
+ break;
+ }
+ }
+
+ //Add function info to output array
+ ret.push_back(func);
+ }
+ }
+
+ return ret;
+}
+
+//Helper export functions
+//Returns pair: <ordinal base for supplied functions; maximum ordinal value for supplied functions>
+const std::pair<uint16_t, uint16_t> get_export_ordinal_limits(const exported_functions_list& exports)
+{
+ if(exports.empty())
+ return std::make_pair(0, 0);
+
+ uint16_t max_ordinal = 0; //Maximum ordinal number
+ uint16_t ordinal_base = pe_utils::max_word; //Minimum ordinal value
+ for(exported_functions_list::const_iterator it = exports.begin(); it != exports.end(); ++it)
+ {
+ const exported_function& func = (*it);
+
+ //Calculate maximum and minimum ordinal numbers
+ max_ordinal = std::max<uint16_t>(max_ordinal, func.get_ordinal());
+ ordinal_base = std::min<uint16_t>(ordinal_base, func.get_ordinal());
+ }
+
+ return std::make_pair(ordinal_base, max_ordinal);
+}
+
+//Checks if exported function name already exists
+bool exported_name_exists(const std::string& function_name, const exported_functions_list& exports)
+{
+ for(exported_functions_list::const_iterator it = exports.begin(); it != exports.end(); ++it)
+ {
+ if((*it).has_name() && (*it).get_name() == function_name)
+ return true;
+ }
+
+ return false;
+}
+
+//Checks if exported function name already exists
+bool exported_ordinal_exists(uint16_t ordinal, const exported_functions_list& exports)
+{
+ for(exported_functions_list::const_iterator it = exports.begin(); it != exports.end(); ++it)
+ {
+ if((*it).get_ordinal() == ordinal)
+ return true;
+ }
+
+ return false;
+}
+
+//Helper: sorts exported function list by ordinals
+bool ordinal_sorter::operator()(const exported_function& func1, const exported_function& func2) const
+{
+ return func1.get_ordinal() < func2.get_ordinal();
+}
+
+//Export directory rebuilder
+//info - export information
+//exported_functions_list - list of exported functions
+//exports_section - section where export directory will be placed (must be attached to PE image)
+//offset_from_section_start - offset from exports_section raw data start
+//save_to_pe_headers - if true, new export directory information will be saved to PE image headers
+//auto_strip_last_section - if true and exports are placed in the last section, it will be automatically stripped
+//number_of_functions and number_of_names parameters don't matter in "info" when rebuilding, they're calculated independently
+//characteristics, major_version, minor_version, timestamp and name are the only used members of "info" structure
+//Returns new export directory information
+//exported_functions_list is copied intentionally to be sorted by ordinal values later
+//Name ordinals in exported function don't matter, they will be recalculated
+const image_directory rebuild_exports(pe_base& pe, const export_info& info, exported_functions_list exports, section& exports_section, uint32_t offset_from_section_start, bool save_to_pe_header, bool auto_strip_last_section)
+{
+ //Check that exports_section is attached to this PE image
+ if(!pe.section_attached(exports_section))
+ throw pe_exception("Exports section must be attached to PE file", pe_exception::section_is_not_attached);
+
+ //Needed space for strings
+ uint32_t needed_size_for_strings = static_cast<uint32_t>(info.get_name().length() + 1);
+ uint32_t number_of_names = 0; //Number of named functions
+ uint32_t max_ordinal = 0; //Maximum ordinal number
+ uint32_t ordinal_base = static_cast<uint32_t>(-1); //Minimum ordinal value
+
+ if(exports.empty())
+ ordinal_base = info.get_ordinal_base();
+
+ uint32_t needed_size_for_function_names = 0; //Needed space for function name strings
+ uint32_t needed_size_for_function_forwards = 0; //Needed space for function forwards names
+
+ //List all exported functions
+ //Calculate needed size for function list
+ {
+ //Also check that there're no duplicate names and ordinals
+ std::set<std::string> used_function_names;
+ std::set<uint16_t> used_function_ordinals;
+
+ for(exported_functions_list::const_iterator it = exports.begin(); it != exports.end(); ++it)
+ {
+ const exported_function& func = (*it);
+ //Calculate maximum and minimum ordinal numbers
+ max_ordinal = std::max<uint32_t>(max_ordinal, func.get_ordinal());
+ ordinal_base = std::min<uint32_t>(ordinal_base, func.get_ordinal());
+
+ //Check if ordinal is unique
+ if(!used_function_ordinals.insert(func.get_ordinal()).second)
+ throw pe_exception("Duplicate exported function ordinal", pe_exception::duplicate_exported_function_ordinal);
+
+ if(func.has_name())
+ {
+ //If function is named
+ ++number_of_names;
+ needed_size_for_function_names += static_cast<uint32_t>(func.get_name().length() + 1);
+
+ //Check if it's name and name ordinal are unique
+ if(!used_function_names.insert(func.get_name()).second)
+ throw pe_exception("Duplicate exported function name", pe_exception::duplicate_exported_function_name);
+ }
+
+ //If function is forwarded to another DLL
+ if(func.is_forwarded())
+ needed_size_for_function_forwards += static_cast<uint32_t>(func.get_forwarded_name().length() + 1);
+ }
+ }
+
+ //Sort functions by ordinal value
+ std::sort(exports.begin(), exports.end(), ordinal_sorter());
+
+ //Calculate needed space for different things...
+ needed_size_for_strings += needed_size_for_function_names;
+ needed_size_for_strings += needed_size_for_function_forwards;
+ uint32_t needed_size_for_function_name_ordinals = number_of_names * sizeof(uint16_t);
+ uint32_t needed_size_for_function_name_rvas = number_of_names * sizeof(uint32_t);
+ uint32_t needed_size_for_function_addresses = (max_ordinal - ordinal_base + 1) * sizeof(uint32_t);
+
+ //Export directory header will be placed first
+ uint32_t directory_pos = pe_utils::align_up(offset_from_section_start, sizeof(uint32_t));
+
+ uint32_t needed_size = sizeof(image_export_directory); //Calculate needed size for export tables and strings
+ //sizeof(IMAGE_EXPORT_DIRECTORY) = export directory header
+
+ //Total needed space...
+ needed_size += needed_size_for_function_name_ordinals; //For list of names ordinals
+ needed_size += needed_size_for_function_addresses; //For function RVAs
+ needed_size += needed_size_for_strings; //For all strings
+ needed_size += needed_size_for_function_name_rvas; //For function name strings RVAs
+
+ //Check if exports_section is last one. If it's not, check if there's enough place for exports data
+ if(&exports_section != &*(pe.get_image_sections().end() - 1) &&
+ (exports_section.empty() || pe_utils::align_up(exports_section.get_size_of_raw_data(), pe.get_file_alignment()) < needed_size + directory_pos))
+ throw pe_exception("Insufficient space for export directory", pe_exception::insufficient_space);
+
+ std::string& raw_data = exports_section.get_raw_data();
+
+ //This will be done only if exports_section is the last section of image or for section with unaligned raw length of data
+ if(raw_data.length() < needed_size + directory_pos)
+ raw_data.resize(needed_size + directory_pos); //Expand section raw data
+
+ //Library name will be placed after it
+ uint32_t current_pos_of_function_names = static_cast<uint32_t>(info.get_name().length() + 1 + directory_pos + sizeof(image_export_directory));
+ //Next - function names
+ uint32_t current_pos_of_function_name_ordinals = current_pos_of_function_names + needed_size_for_function_names;
+ //Next - function name ordinals
+ uint32_t current_pos_of_function_forwards = current_pos_of_function_name_ordinals + needed_size_for_function_name_ordinals;
+ //Finally - function addresses
+ uint32_t current_pos_of_function_addresses = current_pos_of_function_forwards + needed_size_for_function_forwards;
+ //Next - function names RVAs
+ uint32_t current_pos_of_function_names_rvas = current_pos_of_function_addresses + needed_size_for_function_addresses;
+
+ {
+ //Create export directory and fill it
+ image_export_directory dir = {0};
+ dir.Characteristics = info.get_characteristics();
+ dir.MajorVersion = info.get_major_version();
+ dir.MinorVersion = info.get_minor_version();
+ dir.TimeDateStamp = info.get_timestamp();
+ dir.NumberOfFunctions = max_ordinal - ordinal_base + 1;
+ dir.NumberOfNames = number_of_names;
+ dir.Base = ordinal_base;
+ dir.AddressOfFunctions = pe.rva_from_section_offset(exports_section, current_pos_of_function_addresses);
+ dir.AddressOfNameOrdinals = pe.rva_from_section_offset(exports_section, current_pos_of_function_name_ordinals);
+ dir.AddressOfNames = pe.rva_from_section_offset(exports_section, current_pos_of_function_names_rvas);
+ dir.Name = pe.rva_from_section_offset(exports_section, directory_pos + sizeof(image_export_directory));
+
+ //Save it
+ memcpy(&raw_data[directory_pos], &dir, sizeof(dir));
+ }
+
+ //Sve library name
+ memcpy(&raw_data[directory_pos + sizeof(image_export_directory)], info.get_name().c_str(), info.get_name().length() + 1);
+
+ //A map to sort function names alphabetically
+ typedef std::map<std::string, uint16_t> funclist; //function name; function name ordinal
+ funclist funcs;
+
+ uint32_t last_ordinal = ordinal_base;
+ //Enumerate all exported functions
+ for(exported_functions_list::const_iterator it = exports.begin(); it != exports.end(); ++it)
+ {
+ const exported_function& func = (*it);
+
+ //If we're skipping some ordinals...
+ if(func.get_ordinal() > last_ordinal)
+ {
+ //Fill this function RVAs data with zeros
+ uint32_t len = sizeof(uint32_t) * (func.get_ordinal() - last_ordinal - 1);
+ if(len)
+ {
+ memset(&raw_data[current_pos_of_function_addresses], 0, len);
+ current_pos_of_function_addresses += len;
+ }
+
+ //Save last encountered ordinal
+ last_ordinal = func.get_ordinal();
+ }
+
+ //If function is named, save its name ordinal and name in sorted alphabetically order
+ if(func.has_name())
+ funcs.insert(std::make_pair(func.get_name(), static_cast<uint16_t>(func.get_ordinal() - ordinal_base))); //Calculate name ordinal
+
+ //If function is forwarded to another DLL
+ if(func.is_forwarded())
+ {
+ //Write its forwarded name and its RVA
+ uint32_t function_rva = pe.rva_from_section_offset(exports_section, current_pos_of_function_forwards);
+ memcpy(&raw_data[current_pos_of_function_addresses], &function_rva, sizeof(function_rva));
+ current_pos_of_function_addresses += sizeof(function_rva);
+
+ memcpy(&raw_data[current_pos_of_function_forwards], func.get_forwarded_name().c_str(), func.get_forwarded_name().length() + 1);
+ current_pos_of_function_forwards += static_cast<uint32_t>(func.get_forwarded_name().length() + 1);
+ }
+ else
+ {
+ //Write actual function RVA
+ uint32_t function_rva = func.get_rva();
+ memcpy(&raw_data[current_pos_of_function_addresses], &function_rva, sizeof(function_rva));
+ current_pos_of_function_addresses += sizeof(function_rva);
+ }
+ }
+
+ //Enumerate sorted function names
+ for(funclist::const_iterator it = funcs.begin(); it != funcs.end(); ++it)
+ {
+ //Save function name RVA
+ uint32_t function_name_rva = pe.rva_from_section_offset(exports_section, current_pos_of_function_names);
+ memcpy(&raw_data[current_pos_of_function_names_rvas], &function_name_rva, sizeof(function_name_rva));
+ current_pos_of_function_names_rvas += sizeof(function_name_rva);
+
+ //Save function name
+ memcpy(&raw_data[current_pos_of_function_names], (*it).first.c_str(), (*it).first.length() + 1);
+ current_pos_of_function_names += static_cast<uint32_t>((*it).first.length() + 1);
+
+ //Save function name ordinal
+ uint16_t name_ordinal = (*it).second;
+ memcpy(&raw_data[current_pos_of_function_name_ordinals], &name_ordinal, sizeof(name_ordinal));
+ current_pos_of_function_name_ordinals += sizeof(name_ordinal);
+ }
+
+ //Adjust section raw and virtual sizes
+ pe.recalculate_section_sizes(exports_section, auto_strip_last_section);
+
+ image_directory ret(pe.rva_from_section_offset(exports_section, directory_pos), needed_size);
+
+ //If auto-rewrite of PE headers is required
+ if(save_to_pe_header)
+ {
+ pe.set_directory_rva(image_directory_entry_export, ret.get_rva());
+ pe.set_directory_size(image_directory_entry_export, ret.get_size());
+ }
+
+ return ret;
+}
+}
diff --git a/tools/pe_bliss/pe_exports.h b/tools/pe_bliss/pe_exports.h
new file mode 100644
index 0000000000..127cf86ed6
--- /dev/null
+++ b/tools/pe_bliss/pe_exports.h
@@ -0,0 +1,184 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <vector>
+#include <string>
+#include "pe_structures.h"
+#include "pe_base.h"
+#include "pe_directory.h"
+
+namespace pe_bliss
+{
+//Class representing exported function
+class exported_function
+{
+public:
+ //Default constructor
+ exported_function();
+
+ //Returns ordinal of function (actually, ordinal = hint + ordinal base)
+ uint16_t get_ordinal() const;
+
+ //Returns RVA of function
+ uint32_t get_rva() const;
+
+ //Returns true if function has name and name ordinal
+ bool has_name() const;
+ //Returns name of function
+ const std::string& get_name() const;
+ //Returns name ordinal of function
+ uint16_t get_name_ordinal() const;
+
+ //Returns true if function is forwarded to other library
+ bool is_forwarded() const;
+ //Returns the name of forwarded function
+ const std::string& get_forwarded_name() const;
+
+public: //Setters do not change everything inside image, they are used by PE class
+ //You can also use them to rebuild export directory
+
+ //Sets ordinal of function
+ void set_ordinal(uint16_t ordinal);
+
+ //Sets RVA of function
+ void set_rva(uint32_t rva);
+
+ //Sets name of function (or clears it, if empty name is passed)
+ void set_name(const std::string& name);
+ //Sets name ordinal
+ void set_name_ordinal(uint16_t name_ordinal);
+
+ //Sets forwarded function name (or clears it, if empty name is passed)
+ void set_forwarded_name(const std::string& name);
+
+private:
+ uint16_t ordinal_; //Function ordinal
+ uint32_t rva_; //Function RVA
+ std::string name_; //Function name
+ bool has_name_; //true == function has name
+ uint16_t name_ordinal_; //Function name ordinal
+ bool forward_; //true == function is forwarded
+ std::string forward_name_; //Name of forwarded function
+};
+
+//Class representing export information
+class export_info
+{
+public:
+ //Default constructor
+ export_info();
+
+ //Returns characteristics
+ uint32_t get_characteristics() const;
+ //Returns timestamp
+ uint32_t get_timestamp() const;
+ //Returns major version
+ uint16_t get_major_version() const;
+ //Returns minor version
+ uint16_t get_minor_version() const;
+ //Returns DLL name
+ const std::string& get_name() const;
+ //Returns ordinal base
+ uint32_t get_ordinal_base() const;
+ //Returns number of functions
+ uint32_t get_number_of_functions() const;
+ //Returns number of function names
+ uint32_t get_number_of_names() const;
+ //Returns RVA of function address table
+ uint32_t get_rva_of_functions() const;
+ //Returns RVA of function name address table
+ uint32_t get_rva_of_names() const;
+ //Returns RVA of name ordinals table
+ uint32_t get_rva_of_name_ordinals() const;
+
+public: //Setters do not change everything inside image, they are used by PE class
+ //You can also use them to rebuild export directory using rebuild_exports
+
+ //Sets characteristics
+ void set_characteristics(uint32_t characteristics);
+ //Sets timestamp
+ void set_timestamp(uint32_t timestamp);
+ //Sets major version
+ void set_major_version(uint16_t major_version);
+ //Sets minor version
+ void set_minor_version(uint16_t minor_version);
+ //Sets DLL name
+ void set_name(const std::string& name);
+ //Sets ordinal base
+ void set_ordinal_base(uint32_t ordinal_base);
+ //Sets number of functions
+ void set_number_of_functions(uint32_t number_of_functions);
+ //Sets number of function names
+ void set_number_of_names(uint32_t number_of_names);
+ //Sets RVA of function address table
+ void set_rva_of_functions(uint32_t rva_of_functions);
+ //Sets RVA of function name address table
+ void set_rva_of_names(uint32_t rva_of_names);
+ //Sets RVA of name ordinals table
+ void set_rva_of_name_ordinals(uint32_t rva_of_name_ordinals);
+
+private:
+ uint32_t characteristics_;
+ uint32_t timestamp_;
+ uint16_t major_version_;
+ uint16_t minor_version_;
+ std::string name_;
+ uint32_t ordinal_base_;
+ uint32_t number_of_functions_;
+ uint32_t number_of_names_;
+ uint32_t address_of_functions_;
+ uint32_t address_of_names_;
+ uint32_t address_of_name_ordinals_;
+};
+
+//Exported functions list typedef
+typedef std::vector<exported_function> exported_functions_list;
+
+//Returns array of exported functions
+const exported_functions_list get_exported_functions(const pe_base& pe);
+//Returns array of exported functions and information about export
+const exported_functions_list get_exported_functions(const pe_base& pe, export_info& info);
+
+//Helper export functions
+//Returns pair: <ordinal base for supplied functions; maximum ordinal value for supplied functions>
+const std::pair<uint16_t, uint16_t> get_export_ordinal_limits(const exported_functions_list& exports);
+
+//Checks if exported function name already exists
+bool exported_name_exists(const std::string& function_name, const exported_functions_list& exports);
+
+//Checks if exported function ordinal already exists
+bool exported_ordinal_exists(uint16_t ordinal, const exported_functions_list& exports);
+
+//Export directory rebuilder
+//info - export information
+//exported_functions_list - list of exported functions
+//exports_section - section where export directory will be placed (must be attached to PE image)
+//offset_from_section_start - offset from exports_section raw data start
+//save_to_pe_headers - if true, new export directory information will be saved to PE image headers
+//auto_strip_last_section - if true and exports are placed in the last section, it will be automatically stripped
+//number_of_functions and number_of_names parameters don't matter in "info" when rebuilding, they're calculated independently
+//characteristics, major_version, minor_version, timestamp and name are the only used members of "info" structure
+//Returns new export directory information
+//exported_functions_list is copied intentionally to be sorted by ordinal values later
+//Name ordinals in exported function don't matter, they will be recalculated
+const image_directory rebuild_exports(pe_base& pe, const export_info& info, exported_functions_list exports, section& exports_section, uint32_t offset_from_section_start = 0, bool save_to_pe_header = true, bool auto_strip_last_section = true);
+}
diff --git a/tools/pe_bliss/pe_factory.cpp b/tools/pe_bliss/pe_factory.cpp
new file mode 100644
index 0000000000..f6d8a3e1ed
--- /dev/null
+++ b/tools/pe_bliss/pe_factory.cpp
@@ -0,0 +1,43 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include "pe_factory.h"
+#include "pe_properties_generic.h"
+
+namespace pe_bliss
+{
+pe_base pe_factory::create_pe(std::istream& file, bool read_debug_raw_data)
+{
+ return pe_base::get_pe_type(file) == pe_type_32
+ ? pe_base(file, pe_properties_32(), read_debug_raw_data)
+ : pe_base(file, pe_properties_64(), read_debug_raw_data);
+}
+
+pe_base pe_factory::create_pe(const char* file_path, bool read_debug_raw_data)
+{
+ std::ifstream pe_file(file_path, std::ios::in | std::ios::binary);
+ if(!pe_file)
+ {
+ throw pe_exception("Error in open file.", pe_exception::stream_is_bad);
+ }
+ return pe_factory::create_pe(pe_file,read_debug_raw_data);
+}
+}
diff --git a/tools/pe_bliss/pe_factory.h b/tools/pe_bliss/pe_factory.h
new file mode 100644
index 0000000000..60b42d9b71
--- /dev/null
+++ b/tools/pe_bliss/pe_factory.h
@@ -0,0 +1,39 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <memory>
+#include <istream>
+#include <fstream>
+#include "pe_base.h"
+
+namespace pe_bliss
+{
+class pe_factory
+{
+public:
+ //Creates pe_base class instance from PE or PE+ istream
+ //If read_bound_import_raw_data, raw bound import data will be read (used to get bound import info)
+ //If read_debug_raw_data, raw debug data will be read (used to get image debug info)
+ static pe_base create_pe(std::istream& file, bool read_debug_raw_data = true);
+ static pe_base create_pe(const char* file_path, bool read_debug_raw_data = true);
+};
+}
diff --git a/tools/pe_bliss/pe_imports.cpp b/tools/pe_bliss/pe_imports.cpp
new file mode 100644
index 0000000000..0a6c01d6c0
--- /dev/null
+++ b/tools/pe_bliss/pe_imports.cpp
@@ -0,0 +1,777 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include <string.h>
+#include "pe_imports.h"
+#include "pe_properties_generic.h"
+
+namespace pe_bliss
+{
+using namespace pe_win;
+
+//IMPORTS
+//Default constructor
+//If set_to_pe_headers = true, IMAGE_DIRECTORY_ENTRY_IMPORT entry will be reset
+//to new value after import rebuilding
+//If auto_zero_directory_entry_iat = true, IMAGE_DIRECTORY_ENTRY_IAT will be set to zero
+//IMAGE_DIRECTORY_ENTRY_IAT is used by loader to temporarily make section, where IMAGE_DIRECTORY_ENTRY_IAT RVA points, writeable
+//to be able to modify IAT thunks
+import_rebuilder_settings::import_rebuilder_settings(bool set_to_pe_headers, bool auto_zero_directory_entry_iat)
+ :offset_from_section_start_(0),
+ build_original_iat_(true),
+ save_iat_and_original_iat_rvas_(true),
+ fill_missing_original_iats_(false),
+ set_to_pe_headers_(set_to_pe_headers),
+ zero_directory_entry_iat_(auto_zero_directory_entry_iat),
+ rewrite_iat_and_original_iat_contents_(false),
+ auto_strip_last_section_(true)
+{}
+
+//Returns offset from section start where import directory data will be placed
+uint32_t import_rebuilder_settings::get_offset_from_section_start() const
+{
+ return offset_from_section_start_;
+}
+
+//Returns true if Original import address table (IAT) will be rebuilt
+bool import_rebuilder_settings::build_original_iat() const
+{
+ return build_original_iat_;
+}
+
+//Returns true if Original import address and import address tables will not be rebuilt,
+//works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero
+bool import_rebuilder_settings::save_iat_and_original_iat_rvas() const
+{
+ return save_iat_and_original_iat_rvas_;
+}
+
+//Returns true if Original import address and import address tables contents will be rewritten
+//works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero
+//and save_iat_and_original_iat_rvas is true
+bool import_rebuilder_settings::rewrite_iat_and_original_iat_contents() const
+{
+ return rewrite_iat_and_original_iat_contents_;
+}
+
+//Returns true if original missing IATs will be rebuilt
+//(only if IATs are saved)
+bool import_rebuilder_settings::fill_missing_original_iats() const
+{
+ return fill_missing_original_iats_;
+}
+
+//Returns true if PE headers should be updated automatically after rebuilding of imports
+bool import_rebuilder_settings::auto_set_to_pe_headers() const
+{
+ return set_to_pe_headers_;
+}
+
+//Returns true if IMAGE_DIRECTORY_ENTRY_IAT must be zeroed, works only if auto_set_to_pe_headers = true
+bool import_rebuilder_settings::zero_directory_entry_iat() const
+{
+ return zero_directory_entry_iat_;
+}
+
+//Returns true if the last section should be stripped automatically, if imports are inside it
+bool import_rebuilder_settings::auto_strip_last_section_enabled() const
+{
+ return auto_strip_last_section_;
+}
+
+//Sets offset from section start where import directory data will be placed
+void import_rebuilder_settings::set_offset_from_section_start(uint32_t offset)
+{
+ offset_from_section_start_ = offset;
+}
+
+//Sets if Original import address table (IAT) will be rebuilt
+void import_rebuilder_settings::build_original_iat(bool enable)
+{
+ build_original_iat_ = enable;
+}
+
+//Sets if Original import address and import address tables will not be rebuilt,
+//works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero
+void import_rebuilder_settings::save_iat_and_original_iat_rvas(bool enable, bool enable_rewrite_iat_and_original_iat_contents)
+{
+ save_iat_and_original_iat_rvas_ = enable;
+ if(save_iat_and_original_iat_rvas_)
+ rewrite_iat_and_original_iat_contents_ = enable_rewrite_iat_and_original_iat_contents;
+ else
+ rewrite_iat_and_original_iat_contents_ = false;
+}
+
+//Sets if original missing IATs will be rebuilt
+//(only if IATs are saved)
+void import_rebuilder_settings::fill_missing_original_iats(bool enable)
+{
+ fill_missing_original_iats_ = enable;
+}
+
+//Sets if PE headers should be updated automatically after rebuilding of imports
+void import_rebuilder_settings::auto_set_to_pe_headers(bool enable)
+{
+ set_to_pe_headers_ = enable;
+}
+
+//Sets if IMAGE_DIRECTORY_ENTRY_IAT must be zeroed, works only if auto_set_to_pe_headers = true
+void import_rebuilder_settings::zero_directory_entry_iat(bool enable)
+{
+ zero_directory_entry_iat_ = enable;
+}
+
+//Sets if the last section should be stripped automatically, if imports are inside it, default true
+void import_rebuilder_settings::enable_auto_strip_last_section(bool enable)
+{
+ auto_strip_last_section_ = enable;
+}
+
+//Default constructor
+imported_function::imported_function()
+ :hint_(0), ordinal_(0), iat_va_(0)
+{}
+
+//Returns name of function
+const std::string& imported_function::get_name() const
+{
+ return name_;
+}
+
+//Returns true if imported function has name (and hint)
+bool imported_function::has_name() const
+{
+ return !name_.empty();
+}
+
+//Returns hint
+uint16_t imported_function::get_hint() const
+{
+ return hint_;
+}
+
+//Returns ordinal of function
+uint16_t imported_function::get_ordinal() const
+{
+ return ordinal_;
+}
+
+//Returns IAT entry VA (usable if image has both IAT and original IAT and is bound)
+uint64_t imported_function::get_iat_va() const
+{
+ return iat_va_;
+}
+
+//Sets name of function
+void imported_function::set_name(const std::string& name)
+{
+ name_ = name;
+}
+
+//Sets hint
+void imported_function::set_hint(uint16_t hint)
+{
+ hint_ = hint;
+}
+
+//Sets ordinal
+void imported_function::set_ordinal(uint16_t ordinal)
+{
+ ordinal_ = ordinal;
+}
+
+//Sets IAT entry VA (usable if image has both IAT and original IAT and is bound)
+void imported_function::set_iat_va(uint64_t va)
+{
+ iat_va_ = va;
+}
+
+//Default constructor
+import_library::import_library()
+ :rva_to_iat_(0), rva_to_original_iat_(0), timestamp_(0)
+{}
+
+//Returns name of library
+const std::string& import_library::get_name() const
+{
+ return name_;
+}
+
+//Returns RVA to Import Address Table (IAT)
+uint32_t import_library::get_rva_to_iat() const
+{
+ return rva_to_iat_;
+}
+
+//Returns RVA to Original Import Address Table (Original IAT)
+uint32_t import_library::get_rva_to_original_iat() const
+{
+ return rva_to_original_iat_;
+}
+
+//Returns timestamp
+uint32_t import_library::get_timestamp() const
+{
+ return timestamp_;
+}
+
+//Sets name of library
+void import_library::set_name(const std::string& name)
+{
+ name_ = name;
+}
+
+//Sets RVA to Import Address Table (IAT)
+void import_library::set_rva_to_iat(uint32_t rva_to_iat)
+{
+ rva_to_iat_ = rva_to_iat;
+}
+
+//Sets RVA to Original Import Address Table (Original IAT)
+void import_library::set_rva_to_original_iat(uint32_t rva_to_original_iat)
+{
+ rva_to_original_iat_ = rva_to_original_iat;
+}
+
+//Sets timestamp
+void import_library::set_timestamp(uint32_t timestamp)
+{
+ timestamp_ = timestamp;
+}
+
+//Returns imported functions list
+const import_library::imported_list& import_library::get_imported_functions() const
+{
+ return imports_;
+}
+
+//Adds imported function
+void import_library::add_import(const imported_function& func)
+{
+ imports_.push_back(func);
+}
+
+//Clears imported functions list
+void import_library::clear_imports()
+{
+ imports_.clear();
+}
+
+const imported_functions_list get_imported_functions(const pe_base& pe)
+{
+ return (pe.get_pe_type() == pe_type_32 ?
+ get_imported_functions_base<pe_types_class_32>(pe)
+ : get_imported_functions_base<pe_types_class_64>(pe));
+}
+
+const image_directory rebuild_imports(pe_base& pe, const imported_functions_list& imports, section& import_section, const import_rebuilder_settings& import_settings)
+{
+ return (pe.get_pe_type() == pe_type_32 ?
+ rebuild_imports_base<pe_types_class_32>(pe, imports, import_section, import_settings)
+ : rebuild_imports_base<pe_types_class_64>(pe, imports, import_section, import_settings));
+}
+
+//Returns imported functions list with related libraries info
+template<typename PEClassType>
+const imported_functions_list get_imported_functions_base(const pe_base& pe)
+{
+ imported_functions_list ret;
+
+ //If image has no imports, return empty array
+ if(!pe.has_imports())
+ return ret;
+
+ unsigned long current_descriptor_pos = pe.get_directory_rva(image_directory_entry_import);
+ //Get first IMAGE_IMPORT_DESCRIPTOR
+ image_import_descriptor import_descriptor = pe.section_data_from_rva<image_import_descriptor>(current_descriptor_pos, section_data_virtual, true);
+
+ //Iterate them until we reach zero-element
+ //We don't need to check correctness of this, because exception will be thrown
+ //inside of loop if we go outsize of section
+ while(import_descriptor.Name)
+ {
+ //Get imported library information
+ import_library lib;
+
+ unsigned long max_name_length;
+ //Get byte count that we have for library name
+ if((max_name_length = pe.section_data_length_from_rva(import_descriptor.Name, import_descriptor.Name, section_data_virtual, true)) < 2)
+ throw pe_exception("Incorrect import directory", pe_exception::incorrect_import_directory);
+
+ //Get DLL name pointer
+ const char* dll_name = pe.section_data_from_rva(import_descriptor.Name, section_data_virtual, true);
+
+ //Check for null-termination
+ if(!pe_utils::is_null_terminated(dll_name, max_name_length))
+ throw pe_exception("Incorrect import directory", pe_exception::incorrect_import_directory);
+
+ //Set library name
+ lib.set_name(dll_name);
+ //Set library timestamp
+ lib.set_timestamp(import_descriptor.TimeDateStamp);
+ //Set library RVA to IAT and original IAT
+ lib.set_rva_to_iat(import_descriptor.FirstThunk);
+ lib.set_rva_to_original_iat(import_descriptor.OriginalFirstThunk);
+
+ //Get RVA to IAT (it must be filled by loader when loading PE)
+ uint32_t current_thunk_rva = import_descriptor.FirstThunk;
+ typename PEClassType::BaseSize import_address_table = pe.section_data_from_rva<typename PEClassType::BaseSize>(current_thunk_rva, section_data_virtual, true);
+
+ //Get RVA to original IAT (lookup table), which must handle imported functions names
+ //Some linkers leave this pointer zero-filled
+ //Such image is valid, but it is not possible to restore imported functions names
+ //afted image was loaded, because IAT becomes the only one table
+ //containing both function names and function RVAs after loading
+ uint32_t current_original_thunk_rva = import_descriptor.OriginalFirstThunk;
+ typename PEClassType::BaseSize import_lookup_table = current_original_thunk_rva == 0 ? import_address_table : pe.section_data_from_rva<typename PEClassType::BaseSize>(current_original_thunk_rva, section_data_virtual, true);
+ if(current_original_thunk_rva == 0)
+ current_original_thunk_rva = current_thunk_rva;
+
+ //List all imported functions for current DLL
+ if(import_lookup_table != 0 && import_address_table != 0)
+ {
+ while(true)
+ {
+ //Imported function description
+ imported_function func;
+
+ //Get VA from IAT
+ typename PEClassType::BaseSize address = pe.section_data_from_rva<typename PEClassType::BaseSize>(current_thunk_rva, section_data_virtual, true);
+ //Move pointer
+ current_thunk_rva += sizeof(typename PEClassType::BaseSize);
+
+ //Jump to next DLL if we finished with this one
+ if(!address)
+ break;
+
+ func.set_iat_va(address);
+
+ //Get VA from original IAT
+ typename PEClassType::BaseSize lookup = pe.section_data_from_rva<typename PEClassType::BaseSize>(current_original_thunk_rva, section_data_virtual, true);
+ //Move pointer
+ current_original_thunk_rva += sizeof(typename PEClassType::BaseSize);
+
+ //Check if function is imported by ordinal
+ if((lookup & PEClassType::ImportSnapFlag) != 0)
+ {
+ //Set function ordinal
+ func.set_ordinal(static_cast<uint16_t>(lookup & 0xffff));
+ }
+ else
+ {
+ //Get byte count that we have for function name
+ if(lookup > static_cast<uint32_t>(-1) - sizeof(uint16_t))
+ throw pe_exception("Incorrect import directory", pe_exception::incorrect_import_directory);
+
+ //Get maximum available length of function name
+ if((max_name_length = pe.section_data_length_from_rva(static_cast<uint32_t>(lookup + sizeof(uint16_t)), static_cast<uint32_t>(lookup + sizeof(uint16_t)), section_data_virtual, true)) < 2)
+ throw pe_exception("Incorrect import directory", pe_exception::incorrect_import_directory);
+
+ //Get imported function name
+ const char* func_name = pe.section_data_from_rva(static_cast<uint32_t>(lookup + sizeof(uint16_t)), section_data_virtual, true);
+
+ //Check for null-termination
+ if(!pe_utils::is_null_terminated(func_name, max_name_length))
+ throw pe_exception("Incorrect import directory", pe_exception::incorrect_import_directory);
+
+ //HINT in import table is ORDINAL in export table
+ uint16_t hint = pe.section_data_from_rva<uint16_t>(static_cast<uint32_t>(lookup), section_data_virtual, true);
+
+ //Save hint and name
+ func.set_name(func_name);
+ func.set_hint(hint);
+ }
+
+ //Add function to list
+ lib.add_import(func);
+ }
+ }
+
+ //Check possible overflow
+ if(!pe_utils::is_sum_safe(current_descriptor_pos, sizeof(image_import_descriptor)))
+ throw pe_exception("Incorrect import directory", pe_exception::incorrect_import_directory);
+
+ //Go to next library
+ current_descriptor_pos += sizeof(image_import_descriptor);
+ import_descriptor = pe.section_data_from_rva<image_import_descriptor>(current_descriptor_pos, section_data_virtual, true);
+
+ //Save import information
+ ret.push_back(lib);
+ }
+
+ //Return resulting list
+ return ret;
+}
+
+
+//Simple import directory rebuilder
+//You can get all image imports with get_imported_functions() function
+//You can use returned value to, for example, add new imported library with some functions
+//to the end of list of imported libraries
+//To keep PE file working, rebuild its imports with save_iat_and_original_iat_rvas = true (default)
+//Don't add new imported functions to existing imported library entries, because this can cause
+//rewriting of some used memory (or other IAT/orig.IAT fields) by system loader
+//The safest way is just adding import libraries with functions to the end of imported_functions_list array
+template<typename PEClassType>
+const image_directory rebuild_imports_base(pe_base& pe, const imported_functions_list& imports, section& import_section, const import_rebuilder_settings& import_settings)
+{
+ //Check that import_section is attached to this PE image
+ if(!pe.section_attached(import_section))
+ throw pe_exception("Import section must be attached to PE file", pe_exception::section_is_not_attached);
+
+ uint32_t needed_size = 0; //Calculate needed size for import structures and strings
+ uint32_t needed_size_for_strings = 0; //Calculate needed size for import strings (library and function names and hints)
+ uint32_t size_of_iat = 0; //Size of IAT structures
+
+ needed_size += static_cast<uint32_t>((1 /* ending null descriptor */ + imports.size()) * sizeof(image_import_descriptor));
+
+ //Enumerate imported functions
+ for(imported_functions_list::const_iterator it = imports.begin(); it != imports.end(); ++it)
+ {
+ needed_size_for_strings += static_cast<uint32_t>((*it).get_name().length() + 1 /* nullbyte */);
+
+ const import_library::imported_list& funcs = (*it).get_imported_functions();
+
+ //IMAGE_THUNK_DATA
+ size_of_iat += static_cast<uint32_t>(sizeof(typename PEClassType::BaseSize) * (1 /*ending null */ + funcs.size()));
+
+ //Enumerate all imported functions in library
+ for(import_library::imported_list::const_iterator f = funcs.begin(); f != funcs.end(); ++f)
+ {
+ if((*f).has_name())
+ needed_size_for_strings += static_cast<uint32_t>((*f).get_name().length() + 1 /* nullbyte */ + sizeof(uint16_t) /* hint */);
+ }
+ }
+
+ if(import_settings.build_original_iat() || import_settings.fill_missing_original_iats())
+ needed_size += size_of_iat * 2; //We'll have two similar-sized IATs if we're building original IAT
+ else
+ needed_size += size_of_iat;
+
+ needed_size += sizeof(typename PEClassType::BaseSize); //Maximum align for IAT and original IAT
+
+ //Total needed size for import structures and strings
+ needed_size += needed_size_for_strings;
+
+ //Check if import_section is last one. If it's not, check if there's enough place for import data
+ if(&import_section != &*(pe.get_image_sections().end() - 1) &&
+ (import_section.empty() || pe_utils::align_up(import_section.get_size_of_raw_data(), pe.get_file_alignment()) < needed_size + import_settings.get_offset_from_section_start()))
+ throw pe_exception("Insufficient space for import directory", pe_exception::insufficient_space);
+
+ std::string& raw_data = import_section.get_raw_data();
+
+ //This will be done only if image_section is the last section of image or for section with unaligned raw length of data
+ if(raw_data.length() < needed_size + import_settings.get_offset_from_section_start())
+ raw_data.resize(needed_size + import_settings.get_offset_from_section_start()); //Expand section raw data
+
+ uint32_t current_string_pointer = import_settings.get_offset_from_section_start();/* we will paste structures after strings */
+
+ //Position for IAT
+ uint32_t current_pos_for_iat = pe_utils::align_up(static_cast<uint32_t>(needed_size_for_strings + import_settings.get_offset_from_section_start() + (1 + imports.size()) * sizeof(image_import_descriptor)), sizeof(typename PEClassType::BaseSize));
+ //Position for original IAT
+ uint32_t current_pos_for_original_iat = current_pos_for_iat + size_of_iat;
+ //Position for import descriptors
+ uint32_t current_pos_for_descriptors = needed_size_for_strings + import_settings.get_offset_from_section_start();
+
+ //Build imports
+ for(imported_functions_list::const_iterator it = imports.begin(); it != imports.end(); ++it)
+ {
+ //Create import descriptor
+ image_import_descriptor descr;
+ memset(&descr, 0, sizeof(descr));
+ descr.TimeDateStamp = (*it).get_timestamp(); //Restore timestamp
+ descr.Name = pe.rva_from_section_offset(import_section, current_string_pointer); //Library name RVA
+
+ //If we should save IAT for current import descriptor
+ bool save_iats_for_this_descriptor = import_settings.save_iat_and_original_iat_rvas() && (*it).get_rva_to_iat() != 0;
+ //If we should write original IAT
+ bool write_original_iat = (!save_iats_for_this_descriptor && import_settings.build_original_iat()) || import_settings.fill_missing_original_iats();
+
+ //If we should rewrite saved original IAT for current import descriptor (without changing its position)
+ bool rewrite_saved_original_iat = save_iats_for_this_descriptor && import_settings.rewrite_iat_and_original_iat_contents() && import_settings.build_original_iat();
+ //If we should rewrite saved IAT for current import descriptor (without changing its position)
+ bool rewrite_saved_iat = save_iats_for_this_descriptor && import_settings.rewrite_iat_and_original_iat_contents() && (*it).get_rva_to_iat() != 0;
+
+ //Helper values if we're rewriting existing IAT or orig.IAT
+ uint32_t original_first_thunk = 0;
+ uint32_t first_thunk = 0;
+
+ if(save_iats_for_this_descriptor)
+ {
+ //If there's no original IAT and we're asked to rebuild missing original IATs
+ if(!(*it).get_rva_to_original_iat() && import_settings.fill_missing_original_iats())
+ descr.OriginalFirstThunk = import_settings.build_original_iat() ? pe.rva_from_section_offset(import_section, current_pos_for_original_iat) : 0;
+ else
+ descr.OriginalFirstThunk = import_settings.build_original_iat() ? (*it).get_rva_to_original_iat() : 0;
+
+ descr.FirstThunk = (*it).get_rva_to_iat();
+
+ original_first_thunk = descr.OriginalFirstThunk;
+ first_thunk = descr.FirstThunk;
+
+ if(rewrite_saved_original_iat)
+ {
+ if((*it).get_rva_to_original_iat())
+ write_original_iat = true;
+ else
+ rewrite_saved_original_iat = false;
+ }
+
+ if(rewrite_saved_iat)
+ save_iats_for_this_descriptor = false;
+ }
+ else
+ {
+ //We are creating new IAT and original IAT (if needed)
+ descr.OriginalFirstThunk = import_settings.build_original_iat() ? pe.rva_from_section_offset(import_section, current_pos_for_original_iat) : 0;
+ descr.FirstThunk = pe.rva_from_section_offset(import_section, current_pos_for_iat);
+ }
+
+ //Save import descriptor
+ memcpy(&raw_data[current_pos_for_descriptors], &descr, sizeof(descr));
+ current_pos_for_descriptors += sizeof(descr);
+
+ //Save library name
+ memcpy(&raw_data[current_string_pointer], (*it).get_name().c_str(), (*it).get_name().length() + 1 /* nullbyte */);
+ current_string_pointer += static_cast<uint32_t>((*it).get_name().length() + 1 /* nullbyte */);
+
+ //List all imported functions
+ const import_library::imported_list& funcs = (*it).get_imported_functions();
+ for(import_library::imported_list::const_iterator f = funcs.begin(); f != funcs.end(); ++f)
+ {
+ if((*f).has_name()) //If function is imported by name
+ {
+ //Get RVA of IMAGE_IMPORT_BY_NAME
+ typename PEClassType::BaseSize rva_of_named_import = pe.rva_from_section_offset(import_section, current_string_pointer);
+
+ if(!save_iats_for_this_descriptor)
+ {
+ if(write_original_iat)
+ {
+ //We're creating original IATs - so we can write to IAT saved VA (because IMAGE_IMPORT_BY_NAME will be read
+ //by PE loader from original IAT)
+ typename PEClassType::BaseSize iat_value = static_cast<typename PEClassType::BaseSize>((*f).get_iat_va());
+
+ if(rewrite_saved_iat)
+ {
+ if(pe.section_data_length_from_rva(first_thunk, first_thunk, section_data_raw, true) <= sizeof(iat_value))
+ throw pe_exception("Insufficient space inside initial IAT", pe_exception::insufficient_space);
+
+ memcpy(pe.section_data_from_rva(first_thunk, true), &iat_value, sizeof(iat_value));
+
+ first_thunk += sizeof(iat_value);
+ }
+ else
+ {
+ memcpy(&raw_data[current_pos_for_iat], &iat_value, sizeof(iat_value));
+ current_pos_for_iat += sizeof(rva_of_named_import);
+ }
+ }
+ else
+ {
+ //Else - write to IAT RVA of IMAGE_IMPORT_BY_NAME
+ if(rewrite_saved_iat)
+ {
+ if(pe.section_data_length_from_rva(first_thunk, first_thunk, section_data_raw, true) <= sizeof(rva_of_named_import))
+ throw pe_exception("Insufficient space inside initial IAT", pe_exception::insufficient_space);
+
+ memcpy(pe.section_data_from_rva(first_thunk, true), &rva_of_named_import, sizeof(rva_of_named_import));
+
+ first_thunk += sizeof(rva_of_named_import);
+ }
+ else
+ {
+ memcpy(&raw_data[current_pos_for_iat], &rva_of_named_import, sizeof(rva_of_named_import));
+ current_pos_for_iat += sizeof(rva_of_named_import);
+ }
+ }
+ }
+
+ if(write_original_iat)
+ {
+ if(rewrite_saved_original_iat)
+ {
+ if(pe.section_data_length_from_rva(original_first_thunk, original_first_thunk, section_data_raw, true) <= sizeof(rva_of_named_import))
+ throw pe_exception("Insufficient space inside initial original IAT", pe_exception::insufficient_space);
+
+ memcpy(pe.section_data_from_rva(original_first_thunk, true), &rva_of_named_import, sizeof(rva_of_named_import));
+
+ original_first_thunk += sizeof(rva_of_named_import);
+ }
+ else
+ {
+ //We're creating original IATs
+ memcpy(&raw_data[current_pos_for_original_iat], &rva_of_named_import, sizeof(rva_of_named_import));
+ current_pos_for_original_iat += sizeof(rva_of_named_import);
+ }
+ }
+
+ //Write IMAGE_IMPORT_BY_NAME (WORD hint + string function name)
+ uint16_t hint = (*f).get_hint();
+ memcpy(&raw_data[current_string_pointer], &hint, sizeof(hint));
+ memcpy(&raw_data[current_string_pointer + sizeof(uint16_t)], (*f).get_name().c_str(), (*f).get_name().length() + 1 /* nullbyte */);
+ current_string_pointer += static_cast<uint32_t>((*f).get_name().length() + 1 /* nullbyte */ + sizeof(uint16_t) /* hint */);
+ }
+ else //Function is imported by ordinal
+ {
+ uint16_t ordinal = (*f).get_ordinal();
+ typename PEClassType::BaseSize thunk_value = ordinal;
+ thunk_value |= PEClassType::ImportSnapFlag; //Imported by ordinal
+
+ if(!save_iats_for_this_descriptor)
+ {
+ if(write_original_iat)
+ {
+ //We're creating original IATs - so we can wtire to IAT saved VA (because ordinal will be read
+ //by PE loader from original IAT)
+ typename PEClassType::BaseSize iat_value = static_cast<typename PEClassType::BaseSize>((*f).get_iat_va());
+ if(rewrite_saved_iat)
+ {
+ if(pe.section_data_length_from_rva(first_thunk, first_thunk, section_data_raw, true) <= sizeof(iat_value))
+ throw pe_exception("Insufficient space inside initial IAT", pe_exception::insufficient_space);
+
+ memcpy(pe.section_data_from_rva(first_thunk, true), &iat_value, sizeof(iat_value));
+
+ first_thunk += sizeof(iat_value);
+ }
+ else
+ {
+ memcpy(&raw_data[current_pos_for_iat], &iat_value, sizeof(iat_value));
+ current_pos_for_iat += sizeof(thunk_value);
+ }
+ }
+ else
+ {
+ //Else - write ordinal to IAT
+ if(rewrite_saved_iat)
+ {
+ if(pe.section_data_length_from_rva(first_thunk, first_thunk, section_data_raw, true) <= sizeof(thunk_value))
+ throw pe_exception("Insufficient space inside initial IAT", pe_exception::insufficient_space);
+
+ memcpy(pe.section_data_from_rva(first_thunk, true), &thunk_value, sizeof(thunk_value));
+
+ first_thunk += sizeof(thunk_value);
+ }
+ else
+ {
+ memcpy(&raw_data[current_pos_for_iat], &thunk_value, sizeof(thunk_value));
+ }
+ }
+ }
+
+ //We're writing ordinal to original IAT slot
+ if(write_original_iat)
+ {
+ if(rewrite_saved_original_iat)
+ {
+ if(pe.section_data_length_from_rva(original_first_thunk, original_first_thunk, section_data_raw, true) <= sizeof(thunk_value))
+ throw pe_exception("Insufficient space inside initial original IAT", pe_exception::insufficient_space);
+
+ memcpy(pe.section_data_from_rva(original_first_thunk, true), &thunk_value, sizeof(thunk_value));
+
+ original_first_thunk += sizeof(thunk_value);
+ }
+ else
+ {
+ memcpy(&raw_data[current_pos_for_original_iat], &thunk_value, sizeof(thunk_value));
+ current_pos_for_original_iat += sizeof(thunk_value);
+ }
+ }
+ }
+ }
+
+ if(!save_iats_for_this_descriptor)
+ {
+ //Ending null thunks
+ typename PEClassType::BaseSize thunk_value = 0;
+
+ if(rewrite_saved_iat)
+ {
+ if(pe.section_data_length_from_rva(first_thunk, first_thunk, section_data_raw, true) <= sizeof(thunk_value))
+ throw pe_exception("Insufficient space inside initial IAT", pe_exception::insufficient_space);
+
+ memcpy(pe.section_data_from_rva(first_thunk, true), &thunk_value, sizeof(thunk_value));
+
+ first_thunk += sizeof(thunk_value);
+ }
+ else
+ {
+ memcpy(&raw_data[current_pos_for_iat], &thunk_value, sizeof(thunk_value));
+ current_pos_for_iat += sizeof(thunk_value);
+ }
+ }
+
+ if(write_original_iat)
+ {
+ //Ending null thunks
+ typename PEClassType::BaseSize thunk_value = 0;
+
+ if(rewrite_saved_original_iat)
+ {
+ if(pe.section_data_length_from_rva(original_first_thunk, original_first_thunk, section_data_raw, true) <= sizeof(thunk_value))
+ throw pe_exception("Insufficient space inside initial original IAT", pe_exception::insufficient_space);
+
+ memcpy(pe.section_data_from_rva(original_first_thunk, true), &thunk_value, sizeof(thunk_value));
+
+ original_first_thunk += sizeof(thunk_value);
+ }
+ else
+ {
+ memcpy(&raw_data[current_pos_for_original_iat], &thunk_value, sizeof(thunk_value));
+ current_pos_for_original_iat += sizeof(thunk_value);
+ }
+ }
+ }
+
+ {
+ //Null ending descriptor
+ image_import_descriptor descr;
+ memset(&descr, 0, sizeof(descr));
+ memcpy(&raw_data[current_pos_for_descriptors], &descr, sizeof(descr));
+ }
+
+ //Strip data a little, if we saved some place
+ //We're allocating more space than needed, if present original IAT and IAT are saved
+ raw_data.resize(current_pos_for_original_iat);
+
+ //Adjust section raw and virtual sizes
+ pe.recalculate_section_sizes(import_section, import_settings.auto_strip_last_section_enabled());
+
+ //Return information about rebuilt import directory
+ image_directory ret(pe.rva_from_section_offset(import_section, import_settings.get_offset_from_section_start() + needed_size_for_strings), needed_size - needed_size_for_strings);
+
+ //If auto-rewrite of PE headers is required
+ if(import_settings.auto_set_to_pe_headers())
+ {
+ pe.set_directory_rva(image_directory_entry_import, ret.get_rva());
+ pe.set_directory_size(image_directory_entry_import, ret.get_size());
+
+ //If we are requested to zero IMAGE_DIRECTORY_ENTRY_IAT also
+ if(import_settings.zero_directory_entry_iat())
+ {
+ pe.set_directory_rva(image_directory_entry_iat, 0);
+ pe.set_directory_size(image_directory_entry_iat, 0);
+ }
+ }
+
+ return ret;
+}
+}
diff --git a/tools/pe_bliss/pe_imports.h b/tools/pe_bliss/pe_imports.h
new file mode 100644
index 0000000000..681b5b59bd
--- /dev/null
+++ b/tools/pe_bliss/pe_imports.h
@@ -0,0 +1,208 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <vector>
+#include <string>
+#include "pe_structures.h"
+#include "pe_directory.h"
+#include "pe_base.h"
+
+namespace pe_bliss
+{
+//Class representing imported function
+class imported_function
+{
+public:
+ //Default constructor
+ imported_function();
+
+ //Returns true if imported function has name (and hint)
+ bool has_name() const;
+ //Returns name of function
+ const std::string& get_name() const;
+ //Returns hint
+ uint16_t get_hint() const;
+ //Returns ordinal of function
+ uint16_t get_ordinal() const;
+
+ //Returns IAT entry VA (usable if image has both IAT and original IAT and is bound)
+ uint64_t get_iat_va() const;
+
+public: //Setters do not change everything inside image, they are used by PE class
+ //You also can use them to rebuild image imports
+ //Sets name of function
+ void set_name(const std::string& name);
+ //Sets hint
+ void set_hint(uint16_t hint);
+ //Sets ordinal
+ void set_ordinal(uint16_t ordinal);
+
+ //Sets IAT entry VA (usable if image has both IAT and original IAT and is bound)
+ void set_iat_va(uint64_t rva);
+
+private:
+ std::string name_; //Function name
+ uint16_t hint_; //Hint
+ uint16_t ordinal_; //Ordinal
+ uint64_t iat_va_;
+};
+
+//Class representing imported library information
+class import_library
+{
+public:
+ typedef std::vector<imported_function> imported_list;
+
+public:
+ //Default constructor
+ import_library();
+
+ //Returns name of library
+ const std::string& get_name() const;
+ //Returns RVA to Import Address Table (IAT)
+ uint32_t get_rva_to_iat() const;
+ //Returns RVA to Original Import Address Table (Original IAT)
+ uint32_t get_rva_to_original_iat() const;
+ //Returns timestamp
+ uint32_t get_timestamp() const;
+
+ //Returns imported functions list
+ const imported_list& get_imported_functions() const;
+
+public: //Setters do not change everything inside image, they are used by PE class
+ //You also can use them to rebuild image imports
+ //Sets name of library
+ void set_name(const std::string& name);
+ //Sets RVA to Import Address Table (IAT)
+ void set_rva_to_iat(uint32_t rva_to_iat);
+ //Sets RVA to Original Import Address Table (Original IAT)
+ void set_rva_to_original_iat(uint32_t rva_to_original_iat);
+ //Sets timestamp
+ void set_timestamp(uint32_t timestamp);
+
+ //Adds imported function
+ void add_import(const imported_function& func);
+ //Clears imported functions list
+ void clear_imports();
+
+private:
+ std::string name_; //Library name
+ uint32_t rva_to_iat_; //RVA to IAT
+ uint32_t rva_to_original_iat_; //RVA to original IAT
+ uint32_t timestamp_; //DLL TimeStamp
+
+ imported_list imports_;
+};
+
+//Simple import directory rebuilder
+//Class representing import rebuilder advanced settings
+class import_rebuilder_settings
+{
+public:
+ //Default constructor
+ //Default constructor
+ //If set_to_pe_headers = true, IMAGE_DIRECTORY_ENTRY_IMPORT entry will be reset
+ //to new value after import rebuilding
+ //If auto_zero_directory_entry_iat = true, IMAGE_DIRECTORY_ENTRY_IAT will be set to zero
+ //IMAGE_DIRECTORY_ENTRY_IAT is used by loader to temporarily make section, where IMAGE_DIRECTORY_ENTRY_IAT RVA points, writeable
+ //to be able to modify IAT thunks
+ explicit import_rebuilder_settings(bool set_to_pe_headers = true, bool auto_zero_directory_entry_iat = false);
+
+ //Returns offset from section start where import directory data will be placed
+ uint32_t get_offset_from_section_start() const;
+ //Returns true if Original import address table (IAT) will be rebuilt
+ bool build_original_iat() const;
+
+ //Returns true if Original import address and import address tables will not be rebuilt,
+ //works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero
+ bool save_iat_and_original_iat_rvas() const;
+ //Returns true if Original import address and import address tables contents will be rewritten
+ //works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero
+ //and save_iat_and_original_iat_rvas is true
+ bool rewrite_iat_and_original_iat_contents() const;
+
+ //Returns true if original missing IATs will be rebuilt
+ //(only if IATs are saved)
+ bool fill_missing_original_iats() const;
+ //Returns true if PE headers should be updated automatically after rebuilding of imports
+ bool auto_set_to_pe_headers() const;
+ //Returns true if IMAGE_DIRECTORY_ENTRY_IAT must be zeroed, works only if auto_set_to_pe_headers = true
+ bool zero_directory_entry_iat() const;
+
+ //Returns true if the last section should be stripped automatically, if imports are inside it
+ bool auto_strip_last_section_enabled() const;
+
+public: //Setters
+ //Sets offset from section start where import directory data will be placed
+ void set_offset_from_section_start(uint32_t offset);
+ //Sets if Original import address table (IAT) will be rebuilt
+ void build_original_iat(bool enable);
+ //Sets if Original import address and import address tables will not be rebuilt,
+ //works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero
+ //enable_rewrite_iat_and_original_iat_contents sets if Original import address and import address tables contents will be rewritten
+ //works only if import descriptor IAT (and orig.IAT, if present) RVAs are not zero
+ //and save_iat_and_original_iat_rvas is true
+ void save_iat_and_original_iat_rvas(bool enable, bool enable_rewrite_iat_and_original_iat_contents = false);
+ //Sets if original missing IATs will be rebuilt
+ //(only if IATs are saved)
+ void fill_missing_original_iats(bool enable);
+ //Sets if PE headers should be updated automatically after rebuilding of imports
+ void auto_set_to_pe_headers(bool enable);
+ //Sets if IMAGE_DIRECTORY_ENTRY_IAT must be zeroed, works only if auto_set_to_pe_headers = true
+ void zero_directory_entry_iat(bool enable);
+
+ //Sets if the last section should be stripped automatically, if imports are inside it, default true
+ void enable_auto_strip_last_section(bool enable);
+
+private:
+ uint32_t offset_from_section_start_;
+ bool build_original_iat_;
+ bool save_iat_and_original_iat_rvas_;
+ bool fill_missing_original_iats_;
+ bool set_to_pe_headers_;
+ bool zero_directory_entry_iat_;
+ bool rewrite_iat_and_original_iat_contents_;
+ bool auto_strip_last_section_;
+};
+
+typedef std::vector<import_library> imported_functions_list;
+
+
+//Returns imported functions list with related libraries info
+const imported_functions_list get_imported_functions(const pe_base& pe);
+
+template<typename PEClassType>
+const imported_functions_list get_imported_functions_base(const pe_base& pe);
+
+
+//You can get all image imports with get_imported_functions() function
+//You can use returned value to, for example, add new imported library with some functions
+//to the end of list of imported libraries
+//To keep PE file working, rebuild its imports with save_iat_and_original_iat_rvas = true (default)
+//Don't add new imported functions to existing imported library entries, because this can cause
+//rewriting of some used memory (or other IAT/orig.IAT fields) by system loader
+//The safest way is just adding import libraries with functions to the end of imported_functions_list array
+const image_directory rebuild_imports(pe_base& pe, const imported_functions_list& imports, section& import_section, const import_rebuilder_settings& import_settings = import_rebuilder_settings());
+
+template<typename PEClassType>
+const image_directory rebuild_imports_base(pe_base& pe, const imported_functions_list& imports, section& import_section, const import_rebuilder_settings& import_settings = import_rebuilder_settings());
+}
diff --git a/tools/pe_bliss/pe_load_config.cpp b/tools/pe_bliss/pe_load_config.cpp
new file mode 100644
index 0000000000..c05895fecd
--- /dev/null
+++ b/tools/pe_bliss/pe_load_config.cpp
@@ -0,0 +1,557 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include <algorithm>
+#include <string.h>
+#include "pe_load_config.h"
+#include "pe_properties_generic.h"
+
+namespace pe_bliss
+{
+using namespace pe_win;
+
+//IMAGE CONFIG
+//Default constructor
+image_config_info::image_config_info()
+ :time_stamp_(0),
+ major_version_(0), minor_version_(0),
+ global_flags_clear_(0), global_flags_set_(0),
+ critical_section_default_timeout_(0),
+ decommit_free_block_threshold_(0), decommit_total_free_threshold_(0),
+ lock_prefix_table_va_(0),
+ max_allocation_size_(0),
+ virtual_memory_threshold_(0),
+ process_affinity_mask_(0),
+ process_heap_flags_(0),
+ service_pack_version_(0),
+ edit_list_va_(0),
+ security_cookie_va_(0),
+ se_handler_table_va_(0),
+ se_handler_count_(0)
+{}
+
+//Constructors from PE structures
+template<typename ConfigStructure>
+image_config_info::image_config_info(const ConfigStructure& info)
+ :time_stamp_(info.TimeDateStamp),
+ major_version_(info.MajorVersion), minor_version_(info.MinorVersion),
+ global_flags_clear_(info.GlobalFlagsClear), global_flags_set_(info.GlobalFlagsSet),
+ critical_section_default_timeout_(info.CriticalSectionDefaultTimeout),
+ decommit_free_block_threshold_(info.DeCommitFreeBlockThreshold), decommit_total_free_threshold_(info.DeCommitTotalFreeThreshold),
+ lock_prefix_table_va_(info.LockPrefixTable),
+ max_allocation_size_(info.MaximumAllocationSize),
+ virtual_memory_threshold_(info.VirtualMemoryThreshold),
+ process_affinity_mask_(info.ProcessAffinityMask),
+ process_heap_flags_(info.ProcessHeapFlags),
+ service_pack_version_(info.CSDVersion),
+ edit_list_va_(info.EditList),
+ security_cookie_va_(info.SecurityCookie),
+ se_handler_table_va_(info.SEHandlerTable),
+ se_handler_count_(info.SEHandlerCount)
+{}
+
+//Instantiate template constructor with needed structures
+template image_config_info::image_config_info(const image_load_config_directory32& info);
+template image_config_info::image_config_info(const image_load_config_directory64& info);
+
+//Returns the date and time stamp value
+uint32_t image_config_info::get_time_stamp() const
+{
+ return time_stamp_;
+}
+
+//Returns major version number
+uint16_t image_config_info::get_major_version() const
+{
+ return major_version_;
+}
+
+//Returns minor version number
+uint16_t image_config_info::get_minor_version() const
+{
+ return minor_version_;
+}
+
+//Returns clear global flags
+uint32_t image_config_info::get_global_flags_clear() const
+{
+ return global_flags_clear_;
+}
+
+//Returns set global flags
+uint32_t image_config_info::get_global_flags_set() const
+{
+ return global_flags_set_;
+}
+
+//Returns critical section default timeout
+uint32_t image_config_info::get_critical_section_default_timeout() const
+{
+ return critical_section_default_timeout_;
+}
+
+//Get the size of the minimum block that
+//must be freed before it is freed (de-committed), in bytes
+uint64_t image_config_info::get_decommit_free_block_threshold() const
+{
+ return decommit_free_block_threshold_;
+}
+
+//Returns the size of the minimum total memory
+//that must be freed in the process heap before it is freed (de-committed), in bytes
+uint64_t image_config_info::get_decommit_total_free_threshold() const
+{
+ return decommit_total_free_threshold_;
+}
+
+//Returns VA of a list of addresses where the LOCK prefix is used
+uint64_t image_config_info::get_lock_prefix_table_va() const
+{
+ return lock_prefix_table_va_;
+}
+
+//Returns the maximum allocation size, in bytes
+uint64_t image_config_info::get_max_allocation_size() const
+{
+ return max_allocation_size_;
+}
+
+//Returns the maximum block size that can be allocated from heap segments, in bytes
+uint64_t image_config_info::get_virtual_memory_threshold() const
+{
+ return virtual_memory_threshold_;
+}
+
+//Returns process affinity mask
+uint64_t image_config_info::get_process_affinity_mask() const
+{
+ return process_affinity_mask_;
+}
+
+//Returns process heap flags
+uint32_t image_config_info::get_process_heap_flags() const
+{
+ return process_heap_flags_;
+}
+
+//Returns service pack version (CSDVersion)
+uint16_t image_config_info::get_service_pack_version() const
+{
+ return service_pack_version_;
+}
+
+//Returns VA of edit list (reserved by system)
+uint64_t image_config_info::get_edit_list_va() const
+{
+ return edit_list_va_;
+}
+
+//Returns a pointer to a cookie that is used by Visual C++ or GS implementation
+uint64_t image_config_info::get_security_cookie_va() const
+{
+ return security_cookie_va_;
+}
+
+//Returns VA of the sorted table of RVAs of each valid, unique handler in the image
+uint64_t image_config_info::get_se_handler_table_va() const
+{
+ return se_handler_table_va_;
+}
+
+//Returns the count of unique handlers in the table
+uint64_t image_config_info::get_se_handler_count() const
+{
+ return se_handler_count_;
+}
+
+//Returns SE Handler RVA list
+const image_config_info::se_handler_list& image_config_info::get_se_handler_rvas() const
+{
+ return se_handlers_;
+}
+
+//Returns Lock Prefix RVA list
+const image_config_info::lock_prefix_rva_list& image_config_info::get_lock_prefix_rvas() const
+{
+ return lock_prefixes_;
+}
+
+//Adds SE Handler RVA to list
+void image_config_info::add_se_handler_rva(uint32_t rva)
+{
+ se_handlers_.push_back(rva);
+}
+
+//Clears SE Handler list
+void image_config_info::clear_se_handler_list()
+{
+ se_handlers_.clear();
+}
+
+//Adds Lock Prefix RVA to list
+void image_config_info::add_lock_prefix_rva(uint32_t rva)
+{
+ lock_prefixes_.push_back(rva);
+}
+
+//Clears Lock Prefix list
+void image_config_info::clear_lock_prefix_list()
+{
+ lock_prefixes_.clear();
+}
+
+//Sets the date and time stamp value
+void image_config_info::set_time_stamp(uint32_t time_stamp)
+{
+ time_stamp_ = time_stamp;
+}
+
+//Sets major version number
+void image_config_info::set_major_version(uint16_t major_version)
+{
+ major_version_ = major_version;
+}
+
+//Sets minor version number
+void image_config_info::set_minor_version(uint16_t minor_version)
+{
+ minor_version_ = minor_version;
+}
+
+//Sets clear global flags
+void image_config_info::set_global_flags_clear(uint32_t global_flags_clear)
+{
+ global_flags_clear_ = global_flags_clear;
+}
+
+//Sets set global flags
+void image_config_info::set_global_flags_set(uint32_t global_flags_set)
+{
+ global_flags_set_ = global_flags_set;
+}
+
+//Sets critical section default timeout
+void image_config_info::set_critical_section_default_timeout(uint32_t critical_section_default_timeout)
+{
+ critical_section_default_timeout_ = critical_section_default_timeout;
+}
+
+//Sets the size of the minimum block that
+//must be freed before it is freed (de-committed), in bytes
+void image_config_info::set_decommit_free_block_threshold(uint64_t decommit_free_block_threshold)
+{
+ decommit_free_block_threshold_ = decommit_free_block_threshold;
+}
+
+//Sets the size of the minimum total memory
+//that must be freed in the process heap before it is freed (de-committed), in bytes
+void image_config_info::set_decommit_total_free_threshold(uint64_t decommit_total_free_threshold)
+{
+ decommit_total_free_threshold_ = decommit_total_free_threshold;
+}
+
+//Sets VA of a list of addresses where the LOCK prefix is used
+//If you rebuild this list, VA will be re-assigned automatically
+void image_config_info::set_lock_prefix_table_va(uint64_t lock_prefix_table_va)
+{
+ lock_prefix_table_va_ = lock_prefix_table_va;
+}
+
+//Sets the maximum allocation size, in bytes
+void image_config_info::set_max_allocation_size(uint64_t max_allocation_size)
+{
+ max_allocation_size_ = max_allocation_size;
+}
+
+//Sets the maximum block size that can be allocated from heap segments, in bytes
+void image_config_info::set_virtual_memory_threshold(uint64_t virtual_memory_threshold)
+{
+ virtual_memory_threshold_ = virtual_memory_threshold;
+}
+
+//Sets process affinity mask
+void image_config_info::set_process_affinity_mask(uint64_t process_affinity_mask)
+{
+ process_affinity_mask_ = process_affinity_mask;
+}
+
+//Sets process heap flags
+void image_config_info::set_process_heap_flags(uint32_t process_heap_flags)
+{
+ process_heap_flags_ = process_heap_flags;
+}
+
+//Sets service pack version (CSDVersion)
+void image_config_info::set_service_pack_version(uint16_t service_pack_version)
+{
+ service_pack_version_ = service_pack_version;
+}
+
+//Sets VA of edit list (reserved by system)
+void image_config_info::set_edit_list_va(uint64_t edit_list_va)
+{
+ edit_list_va_ = edit_list_va;
+}
+
+//Sets a pointer to a cookie that is used by Visual C++ or GS implementation
+void image_config_info::set_security_cookie_va(uint64_t security_cookie_va)
+{
+ security_cookie_va_ = security_cookie_va;
+}
+
+//Sets VA of the sorted table of RVAs of each valid, unique handler in the image
+//If you rebuild this list, VA will be re-assigned automatically
+void image_config_info::set_se_handler_table_va(uint64_t se_handler_table_va)
+{
+ se_handler_table_va_ = se_handler_table_va;
+}
+
+//Returns SE Handler RVA list
+image_config_info::se_handler_list& image_config_info::get_se_handler_rvas()
+{
+ return se_handlers_;
+}
+
+//Returns Lock Prefix RVA list
+image_config_info::lock_prefix_rva_list& image_config_info::get_lock_prefix_rvas()
+{
+ return lock_prefixes_;
+}
+
+//Returns image config info
+//If image does not have config info, throws an exception
+const image_config_info get_image_config(const pe_base& pe)
+{
+ return pe.get_pe_type() == pe_type_32
+ ? get_image_config_base<pe_types_class_32>(pe)
+ : get_image_config_base<pe_types_class_64>(pe);
+}
+
+//Image config rebuilder
+const image_directory rebuild_image_config(pe_base& pe, const image_config_info& info, section& image_config_section, uint32_t offset_from_section_start, bool write_se_handlers, bool write_lock_prefixes, bool save_to_pe_header, bool auto_strip_last_section)
+{
+ return pe.get_pe_type() == pe_type_32
+ ? rebuild_image_config_base<pe_types_class_32>(pe, info, image_config_section, offset_from_section_start, write_se_handlers, write_lock_prefixes, save_to_pe_header, auto_strip_last_section)
+ : rebuild_image_config_base<pe_types_class_64>(pe, info, image_config_section, offset_from_section_start, write_se_handlers, write_lock_prefixes, save_to_pe_header, auto_strip_last_section);
+}
+
+
+//Returns image config info
+//If image does not have config info, throws an exception
+template<typename PEClassType>
+const image_config_info get_image_config_base(const pe_base& pe)
+{
+ //Check if image has config directory
+ if(!pe.has_config())
+ throw pe_exception("Image does not have load config directory", pe_exception::directory_does_not_exist);
+
+ //Get load config structure
+ typename PEClassType::ConfigStruct config_info = pe.section_data_from_rva<typename PEClassType::ConfigStruct>(pe.get_directory_rva(image_directory_entry_load_config), section_data_virtual);
+
+ //Check size of config directory
+ if(config_info.Size != sizeof(config_info))
+ throw pe_exception("Incorrect (or old) load config directory", pe_exception::incorrect_config_directory);
+
+ //Fill return structure
+ image_config_info ret(config_info);
+
+ //Check possible overflow
+ if(config_info.SEHandlerCount >= pe_utils::max_dword / sizeof(uint32_t)
+ || config_info.SEHandlerTable >= static_cast<typename PEClassType::BaseSize>(-1) - config_info.SEHandlerCount * sizeof(uint32_t))
+ throw pe_exception("Incorrect load config directory", pe_exception::incorrect_config_directory);
+
+ //Read sorted SE handler RVA list (if any)
+ for(typename PEClassType::BaseSize i = 0; i != config_info.SEHandlerCount; ++i)
+ ret.add_se_handler_rva(pe.section_data_from_va<uint32_t>(static_cast<typename PEClassType::BaseSize>(config_info.SEHandlerTable + i * sizeof(uint32_t))));
+
+ if(config_info.LockPrefixTable)
+ {
+ //Read Lock Prefix VA list (if any)
+ unsigned long current = 0;
+ while(true)
+ {
+ typename PEClassType::BaseSize lock_prefix_va = pe.section_data_from_va<typename PEClassType::BaseSize>(static_cast<typename PEClassType::BaseSize>(config_info.LockPrefixTable + current * sizeof(typename PEClassType::BaseSize)));
+ if(!lock_prefix_va)
+ break;
+
+ ret.add_lock_prefix_rva(pe.va_to_rva(lock_prefix_va));
+
+ ++current;
+ }
+ }
+
+ return ret;
+}
+
+//Image config directory rebuilder
+//auto_strip_last_section - if true and TLS are placed in the last section, it will be automatically stripped
+//If write_se_handlers = true, SE Handlers list will be written just after image config directory structure
+//If write_lock_prefixes = true, Lock Prefixes address list will be written just after image config directory structure
+template<typename PEClassType>
+const image_directory rebuild_image_config_base(pe_base& pe, const image_config_info& info, section& image_config_section, uint32_t offset_from_section_start, bool write_se_handlers, bool write_lock_prefixes, bool save_to_pe_header, bool auto_strip_last_section)
+{
+ //Check that image_config_section is attached to this PE image
+ if(!pe.section_attached(image_config_section))
+ throw pe_exception("Image Config section must be attached to PE file", pe_exception::section_is_not_attached);
+
+ uint32_t alignment = pe_utils::align_up(offset_from_section_start, sizeof(typename PEClassType::BaseSize)) - offset_from_section_start;
+
+ uint32_t needed_size = sizeof(typename PEClassType::ConfigStruct); //Calculate needed size for Image Config table
+
+ uint32_t image_config_data_pos = offset_from_section_start + alignment;
+
+ uint32_t current_pos_of_se_handlers = 0;
+ uint32_t current_pos_of_lock_prefixes = 0;
+
+ if(write_se_handlers)
+ {
+ current_pos_of_se_handlers = needed_size + image_config_data_pos;
+ needed_size += static_cast<uint32_t>(info.get_se_handler_rvas().size()) * sizeof(uint32_t); //RVAs of SE Handlers
+ }
+
+ if(write_lock_prefixes)
+ {
+ current_pos_of_lock_prefixes = needed_size + image_config_data_pos;
+ needed_size += static_cast<uint32_t>((info.get_lock_prefix_rvas().size() + 1) * sizeof(typename PEClassType::BaseSize)); //VAs of Lock Prefixes (and ending null element)
+ }
+
+ //Check if image_config_section is last one. If it's not, check if there's enough place for Image Config data
+ if(&image_config_section != &*(pe.get_image_sections().end() - 1) &&
+ (image_config_section.empty() || pe_utils::align_up(image_config_section.get_size_of_raw_data(), pe.get_file_alignment()) < needed_size + image_config_data_pos))
+ throw pe_exception("Insufficient space for TLS directory", pe_exception::insufficient_space);
+
+ std::string& raw_data = image_config_section.get_raw_data();
+
+ //This will be done only if image_config_section is the last section of image or for section with unaligned raw length of data
+ if(raw_data.length() < needed_size + image_config_data_pos)
+ raw_data.resize(needed_size + image_config_data_pos); //Expand section raw data
+
+ //Create and fill Image Config structure
+ typename PEClassType::ConfigStruct image_config_section_struct = {0};
+ image_config_section_struct.Size = sizeof(image_config_section_struct);
+ image_config_section_struct.TimeDateStamp = info.get_time_stamp();
+ image_config_section_struct.MajorVersion = info.get_major_version();
+ image_config_section_struct.MinorVersion = info.get_minor_version();
+ image_config_section_struct.GlobalFlagsClear = info.get_global_flags_clear();
+ image_config_section_struct.GlobalFlagsSet = info.get_global_flags_set();
+ image_config_section_struct.CriticalSectionDefaultTimeout = info.get_critical_section_default_timeout();
+ image_config_section_struct.DeCommitFreeBlockThreshold = static_cast<typename PEClassType::BaseSize>(info.get_decommit_free_block_threshold());
+ image_config_section_struct.DeCommitTotalFreeThreshold = static_cast<typename PEClassType::BaseSize>(info.get_decommit_total_free_threshold());
+ image_config_section_struct.MaximumAllocationSize = static_cast<typename PEClassType::BaseSize>(info.get_max_allocation_size());
+ image_config_section_struct.VirtualMemoryThreshold = static_cast<typename PEClassType::BaseSize>(info.get_virtual_memory_threshold());
+ image_config_section_struct.ProcessHeapFlags = info.get_process_heap_flags();
+ image_config_section_struct.ProcessAffinityMask = static_cast<typename PEClassType::BaseSize>(info.get_process_affinity_mask());
+ image_config_section_struct.CSDVersion = info.get_service_pack_version();
+ image_config_section_struct.EditList = static_cast<typename PEClassType::BaseSize>(info.get_edit_list_va());
+ image_config_section_struct.SecurityCookie = static_cast<typename PEClassType::BaseSize>(info.get_security_cookie_va());
+ image_config_section_struct.SEHandlerCount = static_cast<typename PEClassType::BaseSize>(info.get_se_handler_rvas().size());
+
+
+ if(write_se_handlers)
+ {
+ if(info.get_se_handler_rvas().empty())
+ {
+ write_se_handlers = false;
+ image_config_section_struct.SEHandlerTable = 0;
+ }
+ else
+ {
+ typename PEClassType::BaseSize va;
+ pe.rva_to_va(pe.rva_from_section_offset(image_config_section, current_pos_of_se_handlers), va);
+ image_config_section_struct.SEHandlerTable = va;
+ }
+ }
+ else
+ {
+ image_config_section_struct.SEHandlerTable = static_cast<typename PEClassType::BaseSize>(info.get_se_handler_table_va());
+ }
+
+ if(write_lock_prefixes)
+ {
+ if(info.get_lock_prefix_rvas().empty())
+ {
+ write_lock_prefixes = false;
+ image_config_section_struct.LockPrefixTable = 0;
+ }
+ else
+ {
+ typename PEClassType::BaseSize va;
+ pe.rva_to_va(pe.rva_from_section_offset(image_config_section, current_pos_of_lock_prefixes), va);
+ image_config_section_struct.LockPrefixTable = va;
+ }
+ }
+ else
+ {
+ image_config_section_struct.LockPrefixTable = static_cast<typename PEClassType::BaseSize>(info.get_lock_prefix_table_va());
+ }
+
+ //Write image config section
+ memcpy(&raw_data[image_config_data_pos], &image_config_section_struct, sizeof(image_config_section_struct));
+
+ if(write_se_handlers)
+ {
+ //Sort SE Handlers list
+ image_config_info::se_handler_list sorted_list = info.get_se_handler_rvas();
+ std::sort(sorted_list.begin(), sorted_list.end());
+
+ //Write SE Handlers table
+ for(image_config_info::se_handler_list::const_iterator it = sorted_list.begin(); it != sorted_list.end(); ++it)
+ {
+ uint32_t se_handler_rva = *it;
+ memcpy(&raw_data[current_pos_of_se_handlers], &se_handler_rva, sizeof(se_handler_rva));
+ current_pos_of_se_handlers += sizeof(se_handler_rva);
+ }
+ }
+
+ if(write_lock_prefixes)
+ {
+ //Write Lock Prefixes VA list
+ for(image_config_info::lock_prefix_rva_list::const_iterator it = info.get_lock_prefix_rvas().begin(); it != info.get_lock_prefix_rvas().end(); ++it)
+ {
+ typename PEClassType::BaseSize lock_prefix_va;
+ pe.rva_to_va(*it, lock_prefix_va);
+ memcpy(&raw_data[current_pos_of_lock_prefixes], &lock_prefix_va, sizeof(lock_prefix_va));
+ current_pos_of_lock_prefixes += sizeof(lock_prefix_va);
+ }
+
+ {
+ //Ending null VA
+ typename PEClassType::BaseSize lock_prefix_va = 0;
+ memcpy(&raw_data[current_pos_of_lock_prefixes], &lock_prefix_va, sizeof(lock_prefix_va));
+ }
+ }
+
+ //Adjust section raw and virtual sizes
+ pe.recalculate_section_sizes(image_config_section, auto_strip_last_section);
+
+ image_directory ret(pe.rva_from_section_offset(image_config_section, image_config_data_pos), sizeof(typename PEClassType::ConfigStruct));
+
+ //If auto-rewrite of PE headers is required
+ if(save_to_pe_header)
+ {
+ pe.set_directory_rva(image_directory_entry_load_config, ret.get_rva());
+ pe.set_directory_size(image_directory_entry_load_config, ret.get_size());
+ }
+
+ return ret;
+}
+
+}
diff --git a/tools/pe_bliss/pe_load_config.h b/tools/pe_bliss/pe_load_config.h
new file mode 100644
index 0000000000..cb24072de7
--- /dev/null
+++ b/tools/pe_bliss/pe_load_config.h
@@ -0,0 +1,184 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <vector>
+#include "pe_structures.h"
+#include "pe_base.h"
+#include "pe_directory.h"
+
+namespace pe_bliss
+{
+//Class representing image configuration information
+class image_config_info
+{
+public:
+ typedef std::vector<uint32_t> se_handler_list;
+ typedef std::vector<uint32_t> lock_prefix_rva_list;
+
+public:
+ //Default constructor
+ image_config_info();
+ //Constructors from PE structures (no checks)
+ template<typename ConfigStructure>
+ explicit image_config_info(const ConfigStructure& info);
+
+ //Returns the date and time stamp value
+ uint32_t get_time_stamp() const;
+ //Returns major version number
+ uint16_t get_major_version() const;
+ //Returns minor version number
+ uint16_t get_minor_version() const;
+ //Returns clear global flags
+ uint32_t get_global_flags_clear() const;
+ //Returns set global flags
+ uint32_t get_global_flags_set() const;
+ //Returns critical section default timeout
+ uint32_t get_critical_section_default_timeout() const;
+ //Get the size of the minimum block that
+ //must be freed before it is freed (de-committed), in bytes
+ uint64_t get_decommit_free_block_threshold() const;
+ //Returns the size of the minimum total memory
+ //that must be freed in the process heap before it is freed (de-committed), in bytes
+ uint64_t get_decommit_total_free_threshold() const;
+ //Returns VA of a list of addresses where the LOCK prefix is used
+ uint64_t get_lock_prefix_table_va() const;
+ //Returns the maximum allocation size, in bytes
+ uint64_t get_max_allocation_size() const;
+ //Returns the maximum block size that can be allocated from heap segments, in bytes
+ uint64_t get_virtual_memory_threshold() const;
+ //Returns process affinity mask
+ uint64_t get_process_affinity_mask() const;
+ //Returns process heap flags
+ uint32_t get_process_heap_flags() const;
+ //Returns service pack version (CSDVersion)
+ uint16_t get_service_pack_version() const;
+ //Returns VA of edit list (reserved by system)
+ uint64_t get_edit_list_va() const;
+ //Returns a pointer to a cookie that is used by Visual C++ or GS implementation
+ uint64_t get_security_cookie_va() const;
+ //Returns VA of the sorted table of RVAs of each valid, unique handler in the image
+ uint64_t get_se_handler_table_va() const;
+ //Returns the count of unique handlers in the table
+ uint64_t get_se_handler_count() const;
+
+ //Returns SE Handler RVA list
+ const se_handler_list& get_se_handler_rvas() const;
+
+ //Returns Lock Prefix RVA list
+ const lock_prefix_rva_list& get_lock_prefix_rvas() const;
+
+public: //These functions do not change everything inside image, they are used by PE class
+ //Also you can use these functions to rebuild image config directory
+
+ //Adds SE Handler RVA to list
+ void add_se_handler_rva(uint32_t rva);
+ //Clears SE Handler list
+ void clear_se_handler_list();
+
+ //Adds Lock Prefix RVA to list
+ void add_lock_prefix_rva(uint32_t rva);
+ //Clears Lock Prefix list
+ void clear_lock_prefix_list();
+
+ //Sets the date and time stamp value
+ void set_time_stamp(uint32_t time_stamp);
+ //Sets major version number
+ void set_major_version(uint16_t major_version);
+ //Sets minor version number
+ void set_minor_version(uint16_t minor_version);
+ //Sets clear global flags
+ void set_global_flags_clear(uint32_t global_flags_clear);
+ //Sets set global flags
+ void set_global_flags_set(uint32_t global_flags_set);
+ //Sets critical section default timeout
+ void set_critical_section_default_timeout(uint32_t critical_section_default_timeout);
+ //Sets the size of the minimum block that
+ //must be freed before it is freed (de-committed), in bytes
+ void set_decommit_free_block_threshold(uint64_t decommit_free_block_threshold);
+ //Sets the size of the minimum total memory
+ //that must be freed in the process heap before it is freed (de-committed), in bytes
+ void set_decommit_total_free_threshold(uint64_t decommit_total_free_threshold);
+ //Sets VA of a list of addresses where the LOCK prefix is used
+ //If you rebuild this list, VA will be re-assigned automatically
+ void set_lock_prefix_table_va(uint64_t lock_prefix_table_va);
+ //Sets the maximum allocation size, in bytes
+ void set_max_allocation_size(uint64_t max_allocation_size);
+ //Sets the maximum block size that can be allocated from heap segments, in bytes
+ void set_virtual_memory_threshold(uint64_t virtual_memory_threshold);
+ //Sets process affinity mask
+ void set_process_affinity_mask(uint64_t process_affinity_mask);
+ //Sets process heap flags
+ void set_process_heap_flags(uint32_t process_heap_flags);
+ //Sets service pack version (CSDVersion)
+ void set_service_pack_version(uint16_t service_pack_version);
+ //Sets VA of edit list (reserved by system)
+ void set_edit_list_va(uint64_t edit_list_va);
+ //Sets a pointer to a cookie that is used by Visual C++ or GS implementation
+ void set_security_cookie_va(uint64_t security_cookie_va);
+ //Sets VA of the sorted table of RVAs of each valid, unique handler in the image
+ //If you rebuild this list, VA will be re-assigned automatically
+ void set_se_handler_table_va(uint64_t se_handler_table_va);
+
+ //Returns SE Handler RVA list
+ se_handler_list& get_se_handler_rvas();
+
+ //Returns Lock Prefix RVA list
+ lock_prefix_rva_list& get_lock_prefix_rvas();
+
+private:
+ uint32_t time_stamp_;
+ uint16_t major_version_, minor_version_;
+ uint32_t global_flags_clear_, global_flags_set_;
+ uint32_t critical_section_default_timeout_;
+ uint64_t decommit_free_block_threshold_, decommit_total_free_threshold_;
+ uint64_t lock_prefix_table_va_;
+ uint64_t max_allocation_size_;
+ uint64_t virtual_memory_threshold_;
+ uint64_t process_affinity_mask_;
+ uint32_t process_heap_flags_;
+ uint16_t service_pack_version_;
+ uint64_t edit_list_va_;
+ uint64_t security_cookie_va_;
+ uint64_t se_handler_table_va_;
+ uint64_t se_handler_count_;
+
+ se_handler_list se_handlers_;
+ lock_prefix_rva_list lock_prefixes_;
+};
+
+//Returns image config info
+//If image does not have config info, throws an exception
+const image_config_info get_image_config(const pe_base& pe);
+
+template<typename PEClassType>
+const image_config_info get_image_config_base(const pe_base& pe);
+
+
+//Image config directory rebuilder
+//auto_strip_last_section - if true and TLS are placed in the last section, it will be automatically stripped
+//If write_se_handlers = true, SE Handlers list will be written just after image config directory structure
+//If write_lock_prefixes = true, Lock Prefixes address list will be written just after image config directory structure
+const image_directory rebuild_image_config(pe_base& pe, const image_config_info& info, section& image_config_section, uint32_t offset_from_section_start = 0, bool write_se_handlers = true, bool write_lock_prefixes = true, bool save_to_pe_header = true, bool auto_strip_last_section = true);
+
+template<typename PEClassType>
+const image_directory rebuild_image_config_base(pe_base& pe, const image_config_info& info, section& image_config_section, uint32_t offset_from_section_start = 0, bool write_se_handlers = true, bool write_lock_prefixes = true, bool save_to_pe_header = true, bool auto_strip_last_section = true);
+}
diff --git a/tools/pe_bliss/pe_properties.cpp b/tools/pe_bliss/pe_properties.cpp
new file mode 100644
index 0000000000..8d1c2eac43
--- /dev/null
+++ b/tools/pe_bliss/pe_properties.cpp
@@ -0,0 +1,41 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include "pe_properties.h"
+
+namespace pe_bliss
+{
+//Destructor
+pe_properties::~pe_properties()
+{}
+
+//Clears PE characteristics flag
+void pe_properties::clear_characteristics_flags(uint16_t flags)
+{
+ set_characteristics(get_characteristics() & ~flags);
+}
+
+//Sets PE characteristics flag
+void pe_properties::set_characteristics_flags(uint16_t flags)
+{
+ set_characteristics(get_characteristics() | flags);
+}
+}
diff --git a/tools/pe_bliss/pe_properties.h b/tools/pe_bliss/pe_properties.h
new file mode 100644
index 0000000000..1db163e8b1
--- /dev/null
+++ b/tools/pe_bliss/pe_properties.h
@@ -0,0 +1,236 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <memory>
+#include "pe_structures.h"
+
+namespace pe_bliss
+{
+class pe_properties
+{
+public: //Constructors
+ virtual std::auto_ptr<pe_properties> duplicate() const = 0;
+
+ //Fills properly PE structures
+ virtual void create_pe(uint32_t section_alignment, uint16_t subsystem) = 0;
+
+public:
+ //Destructor
+ virtual ~pe_properties();
+
+
+public: //DIRECTORIES
+ //Returns true if directory exists
+ virtual bool directory_exists(uint32_t id) const = 0;
+
+ //Removes directory
+ virtual void remove_directory(uint32_t id) = 0;
+
+ //Returns directory RVA
+ virtual uint32_t get_directory_rva(uint32_t id) const = 0;
+ //Returns directory size
+ virtual uint32_t get_directory_size(uint32_t id) const = 0;
+
+ //Sets directory RVA (just a value of PE header, no moving occurs)
+ virtual void set_directory_rva(uint32_t id, uint32_t rva) = 0;
+ //Sets directory size (just a value of PE header, no moving occurs)
+ virtual void set_directory_size(uint32_t id, uint32_t size) = 0;
+
+ //Strips only zero DATA_DIRECTORY entries to count = min_count
+ //Returns resulting number of data directories
+ //strip_iat_directory - if true, even not empty IAT directory will be stripped
+ virtual uint32_t strip_data_directories(uint32_t min_count = 1, bool strip_iat_directory = true) = 0;
+
+
+public: //IMAGE
+ //Returns PE type of this image
+ virtual pe_type get_pe_type() const = 0;
+
+
+public: //PE HEADER
+ //Returns image base for PE32 and PE64 respectively
+ virtual uint32_t get_image_base_32() const = 0;
+ virtual uint64_t get_image_base_64() const = 0;
+
+ //Sets new image base for PE32
+ virtual void set_image_base(uint32_t base) = 0;
+ //Sets new image base for PE32/PE+
+ virtual void set_image_base_64(uint64_t base) = 0;
+
+ //Returns image entry point
+ virtual uint32_t get_ep() const = 0;
+ //Sets image entry point
+ virtual void set_ep(uint32_t new_ep) = 0;
+
+ //Returns file alignment
+ virtual uint32_t get_file_alignment() const = 0;
+ //Returns section alignment
+ virtual uint32_t get_section_alignment() const = 0;
+
+ //Sets heap size commit for PE32 and PE64 respectively
+ virtual void set_heap_size_commit(uint32_t size) = 0;
+ virtual void set_heap_size_commit(uint64_t size) = 0;
+ //Sets heap size reserve for PE32 and PE64 respectively
+ virtual void set_heap_size_reserve(uint32_t size) = 0;
+ virtual void set_heap_size_reserve(uint64_t size) = 0;
+ //Sets stack size commit for PE32 and PE64 respectively
+ virtual void set_stack_size_commit(uint32_t size) = 0;
+ virtual void set_stack_size_commit(uint64_t size) = 0;
+ //Sets stack size reserve for PE32 and PE64 respectively
+ virtual void set_stack_size_reserve(uint32_t size) = 0;
+ virtual void set_stack_size_reserve(uint64_t size) = 0;
+
+ //Returns heap size commit for PE32 and PE64 respectively
+ virtual uint32_t get_heap_size_commit_32() const = 0;
+ virtual uint64_t get_heap_size_commit_64() const = 0;
+ //Returns heap size reserve for PE32 and PE64 respectively
+ virtual uint32_t get_heap_size_reserve_32() const = 0;
+ virtual uint64_t get_heap_size_reserve_64() const = 0;
+ //Returns stack size commit for PE32 and PE64 respectively
+ virtual uint32_t get_stack_size_commit_32() const = 0;
+ virtual uint64_t get_stack_size_commit_64() const = 0;
+ //Returns stack size reserve for PE32 and PE64 respectively
+ virtual uint32_t get_stack_size_reserve_32() const = 0;
+ virtual uint64_t get_stack_size_reserve_64() const = 0;
+
+ //Returns virtual size of image
+ virtual uint32_t get_size_of_image() const = 0;
+
+ //Returns number of RVA and sizes (number of DATA_DIRECTORY entries)
+ virtual uint32_t get_number_of_rvas_and_sizes() const = 0;
+ //Sets number of RVA and sizes (number of DATA_DIRECTORY entries)
+ virtual void set_number_of_rvas_and_sizes(uint32_t number) = 0;
+
+ //Returns PE characteristics
+ virtual uint16_t get_characteristics() const = 0;
+ //Sets PE characteristics
+ virtual void set_characteristics(uint16_t ch) = 0;
+
+ //Clears PE characteristics flag
+ void clear_characteristics_flags(uint16_t flags);
+ //Sets PE characteristics flag
+ void set_characteristics_flags(uint16_t flags);
+
+ //Returns size of headers
+ virtual uint32_t get_size_of_headers() const = 0;
+
+ //Returns subsystem
+ virtual uint16_t get_subsystem() const = 0;
+
+ //Sets subsystem
+ virtual void set_subsystem(uint16_t subsystem) = 0;
+
+ //Returns size of optional header
+ virtual uint16_t get_size_of_optional_header() const = 0;
+
+ //Returns PE signature
+ virtual uint32_t get_pe_signature() const = 0;
+
+ //Returns PE magic value
+ virtual uint32_t get_magic() const = 0;
+
+ //Returns checksum of PE file from header
+ virtual uint32_t get_checksum() const = 0;
+
+ //Sets checksum of PE file
+ virtual void set_checksum(uint32_t checksum) = 0;
+
+ //Returns timestamp of PE file from header
+ virtual uint32_t get_time_date_stamp() const = 0;
+
+ //Sets timestamp of PE file
+ virtual void set_time_date_stamp(uint32_t timestamp) = 0;
+
+ //Returns Machine field value of PE file from header
+ virtual uint16_t get_machine() const = 0;
+
+ //Sets Machine field value of PE file
+ virtual void set_machine(uint16_t machine) = 0;
+
+ //Returns DLL Characteristics
+ virtual uint16_t get_dll_characteristics() const = 0;
+
+ //Sets DLL Characteristics
+ virtual void set_dll_characteristics(uint16_t characteristics) = 0;
+
+ //Sets required operation system version
+ virtual void set_os_version(uint16_t major, uint16_t minor) = 0;
+
+ //Returns required operation system version (minor word)
+ virtual uint16_t get_minor_os_version() const = 0;
+
+ //Returns required operation system version (major word)
+ virtual uint16_t get_major_os_version() const = 0;
+
+ //Sets required subsystem version
+ virtual void set_subsystem_version(uint16_t major, uint16_t minor) = 0;
+
+ //Returns required subsystem version (minor word)
+ virtual uint16_t get_minor_subsystem_version() const = 0;
+
+ //Returns required subsystem version (major word)
+ virtual uint16_t get_major_subsystem_version() const = 0;
+
+public: //ADDRESS CONVERTIONS
+ //Virtual Address (VA) to Relative Virtual Address (RVA) convertions
+ //for PE32 and PE64 respectively
+ //bound_check checks integer overflow
+ virtual uint32_t va_to_rva(uint32_t va, bool bound_check = true) const = 0;
+ virtual uint32_t va_to_rva(uint64_t va, bool bound_check = true) const = 0;
+
+ //Relative Virtual Address (RVA) to Virtual Address (VA) convertions
+ //for PE32 and PE64 respectively
+ virtual uint32_t rva_to_va_32(uint32_t rva) const = 0;
+ virtual uint64_t rva_to_va_64(uint32_t rva) const = 0;
+
+
+public: //SECTIONS
+ //Returns number of sections
+ virtual uint16_t get_number_of_sections() const = 0;
+
+public:
+ //Sets number of sections
+ virtual void set_number_of_sections(uint16_t number) = 0;
+ //Sets virtual size of image
+ virtual void set_size_of_image(uint32_t size) = 0;
+ //Sets size of headers
+ virtual void set_size_of_headers(uint32_t size) = 0;
+ //Sets size of optional headers
+ virtual void set_size_of_optional_header(uint16_t size) = 0;
+ //Returns nt headers data pointer
+ virtual char* get_nt_headers_ptr() = 0;
+ //Returns nt headers data pointer
+ virtual const char* get_nt_headers_ptr() const = 0;
+ //Returns size of NT header
+ virtual uint32_t get_sizeof_nt_header() const = 0;
+ //Returns size of optional headers
+ virtual uint32_t get_sizeof_opt_headers() const = 0;
+ //Sets file alignment (no checks)
+ virtual void set_file_alignment_unchecked(uint32_t alignment) = 0;
+ //Sets base of code
+ virtual void set_base_of_code(uint32_t base) = 0;
+ //Returns base of code
+ virtual uint32_t get_base_of_code() const = 0;
+ //Returns needed PE magic for PE or PE+ (from template parameters)
+ virtual uint32_t get_needed_magic() const = 0;
+};
+}
diff --git a/tools/pe_bliss/pe_properties_generic.cpp b/tools/pe_bliss/pe_properties_generic.cpp
new file mode 100644
index 0000000000..bcf6f2047d
--- /dev/null
+++ b/tools/pe_bliss/pe_properties_generic.cpp
@@ -0,0 +1,645 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include <string.h>
+#include "pe_properties_generic.h"
+#include "pe_exception.h"
+#include "utils.h"
+
+namespace pe_bliss
+{
+using namespace pe_win;
+
+//Constructor
+template<typename PEClassType>
+std::auto_ptr<pe_properties> pe_properties_generic<PEClassType>::duplicate() const
+{
+ return std::auto_ptr<pe_properties>(new pe_properties_generic<PEClassType>(*this));
+}
+
+//Fills properly PE structures
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::create_pe(uint32_t section_alignment, uint16_t subsystem)
+{
+ memset(&nt_headers_, 0, sizeof(nt_headers_));
+ nt_headers_.Signature = 0x4550; //"PE"
+ nt_headers_.FileHeader.Machine = 0x14C; //i386
+ nt_headers_.FileHeader.SizeOfOptionalHeader = sizeof(nt_headers_.OptionalHeader);
+ nt_headers_.OptionalHeader.Magic = PEClassType::Id;
+ nt_headers_.OptionalHeader.ImageBase = 0x400000;
+ nt_headers_.OptionalHeader.SectionAlignment = section_alignment;
+ nt_headers_.OptionalHeader.FileAlignment = 0x200;
+ nt_headers_.OptionalHeader.SizeOfHeaders = 1024;
+ nt_headers_.OptionalHeader.Subsystem = subsystem;
+ nt_headers_.OptionalHeader.SizeOfHeapReserve = 0x100000;
+ nt_headers_.OptionalHeader.SizeOfHeapCommit = 0x1000;
+ nt_headers_.OptionalHeader.SizeOfStackReserve = 0x100000;
+ nt_headers_.OptionalHeader.SizeOfStackCommit = 0x1000;
+ nt_headers_.OptionalHeader.NumberOfRvaAndSizes = 0x10;
+}
+
+//Duplicate
+template<typename PEClassType>
+pe_properties_generic<PEClassType>::~pe_properties_generic()
+{}
+
+//Returns true if directory exists
+template<typename PEClassType>
+bool pe_properties_generic<PEClassType>::directory_exists(uint32_t id) const
+{
+ return (nt_headers_.OptionalHeader.NumberOfRvaAndSizes - 1) >= id &&
+ nt_headers_.OptionalHeader.DataDirectory[id].VirtualAddress;
+}
+
+//Removes directory
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::remove_directory(uint32_t id)
+{
+ if(directory_exists(id))
+ {
+ nt_headers_.OptionalHeader.DataDirectory[id].VirtualAddress = 0;
+ nt_headers_.OptionalHeader.DataDirectory[id].Size = 0;
+
+ if(id == image_directory_entry_basereloc)
+ {
+ set_characteristics_flags(image_file_relocs_stripped);
+ set_dll_characteristics(get_dll_characteristics() & ~image_dllcharacteristics_dynamic_base);
+ }
+ else if(id == image_directory_entry_export)
+ {
+ clear_characteristics_flags(image_file_dll);
+ }
+ }
+}
+
+//Returns directory RVA
+template<typename PEClassType>
+uint32_t pe_properties_generic<PEClassType>::get_directory_rva(uint32_t id) const
+{
+ //Check if directory exists
+ if(nt_headers_.OptionalHeader.NumberOfRvaAndSizes <= id)
+ throw pe_exception("Specified directory does not exist", pe_exception::directory_does_not_exist);
+
+ return nt_headers_.OptionalHeader.DataDirectory[id].VirtualAddress;
+}
+
+//Returns directory size
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_directory_rva(uint32_t id, uint32_t va)
+{
+ //Check if directory exists
+ if(nt_headers_.OptionalHeader.NumberOfRvaAndSizes <= id)
+ throw pe_exception("Specified directory does not exist", pe_exception::directory_does_not_exist);
+
+ nt_headers_.OptionalHeader.DataDirectory[id].VirtualAddress = va;
+}
+
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_directory_size(uint32_t id, uint32_t size)
+{
+ //Check if directory exists
+ if(nt_headers_.OptionalHeader.NumberOfRvaAndSizes <= id)
+ throw pe_exception("Specified directory does not exist", pe_exception::directory_does_not_exist);
+
+ nt_headers_.OptionalHeader.DataDirectory[id].Size = size;
+}
+
+//Returns directory size
+template<typename PEClassType>
+uint32_t pe_properties_generic<PEClassType>::get_directory_size(uint32_t id) const
+{
+ //Check if directory exists
+ if(nt_headers_.OptionalHeader.NumberOfRvaAndSizes <= id)
+ throw pe_exception("Specified directory does not exist", pe_exception::directory_does_not_exist);
+
+ return nt_headers_.OptionalHeader.DataDirectory[id].Size;
+}
+
+//Strips only zero DATA_DIRECTORY entries to count = min_count
+//Returns resulting number of data directories
+//strip_iat_directory - if true, even not empty IAT directory will be stripped
+template<typename PEClassType>
+uint32_t pe_properties_generic<PEClassType>::strip_data_directories(uint32_t min_count, bool strip_iat_directory)
+{
+ int i = nt_headers_.OptionalHeader.NumberOfRvaAndSizes - 1;
+
+ //Enumerate all data directories from the end
+ for(; i >= 0; i--)
+ {
+ //If directory exists, break
+ if(nt_headers_.OptionalHeader.DataDirectory[i].VirtualAddress && (static_cast<uint32_t>(i) != image_directory_entry_iat || !strip_iat_directory))
+ break;
+
+ if(i <= static_cast<int>(min_count) - 2)
+ break;
+ }
+
+ if(i == image_numberof_directory_entries - 1)
+ return image_numberof_directory_entries;
+
+ //Return new number of data directories
+ return nt_headers_.OptionalHeader.NumberOfRvaAndSizes = i + 1;
+}
+
+//Returns image base for PE32
+template<typename PEClassType>
+uint32_t pe_properties_generic<PEClassType>::get_image_base_32() const
+{
+ return static_cast<uint32_t>(nt_headers_.OptionalHeader.ImageBase);
+}
+
+//Returns image base for PE32/PE64
+template<typename PEClassType>
+uint64_t pe_properties_generic<PEClassType>::get_image_base_64() const
+{
+ return static_cast<uint64_t>(nt_headers_.OptionalHeader.ImageBase);
+}
+
+//Sets new image base
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_image_base(uint32_t base)
+{
+ nt_headers_.OptionalHeader.ImageBase = base;
+}
+
+//Sets new image base
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_image_base_64(uint64_t base)
+{
+ nt_headers_.OptionalHeader.ImageBase = static_cast<typename PEClassType::BaseSize>(base);
+}
+
+//Returns image entry point
+template<typename PEClassType>
+uint32_t pe_properties_generic<PEClassType>::get_ep() const
+{
+ return nt_headers_.OptionalHeader.AddressOfEntryPoint;
+}
+
+//Sets image entry point
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_ep(uint32_t new_ep)
+{
+ nt_headers_.OptionalHeader.AddressOfEntryPoint = new_ep;
+}
+
+//Returns file alignment
+template<typename PEClassType>
+uint32_t pe_properties_generic<PEClassType>::get_file_alignment() const
+{
+ return nt_headers_.OptionalHeader.FileAlignment;
+}
+
+//Returns section alignment
+template<typename PEClassType>
+uint32_t pe_properties_generic<PEClassType>::get_section_alignment() const
+{
+ return nt_headers_.OptionalHeader.SectionAlignment;
+}
+
+//Sets heap size commit for PE32
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_heap_size_commit(uint32_t size)
+{
+ nt_headers_.OptionalHeader.SizeOfHeapCommit = static_cast<typename PEClassType::BaseSize>(size);
+}
+
+//Sets heap size commit for PE32/PE64
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_heap_size_commit(uint64_t size)
+{
+ nt_headers_.OptionalHeader.SizeOfHeapCommit = static_cast<typename PEClassType::BaseSize>(size);
+}
+
+//Sets heap size reserve for PE32
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_heap_size_reserve(uint32_t size)
+{
+ nt_headers_.OptionalHeader.SizeOfHeapReserve = static_cast<typename PEClassType::BaseSize>(size);
+}
+
+//Sets heap size reserve for PE32/PE64
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_heap_size_reserve(uint64_t size)
+{
+ nt_headers_.OptionalHeader.SizeOfHeapReserve = static_cast<typename PEClassType::BaseSize>(size);
+}
+
+//Sets stack size commit for PE32
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_stack_size_commit(uint32_t size)
+{
+ nt_headers_.OptionalHeader.SizeOfStackCommit = static_cast<typename PEClassType::BaseSize>(size);
+}
+
+//Sets stack size commit for PE32/PE64
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_stack_size_commit(uint64_t size)
+{
+ nt_headers_.OptionalHeader.SizeOfStackCommit = static_cast<typename PEClassType::BaseSize>(size);
+}
+
+//Sets stack size reserve for PE32
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_stack_size_reserve(uint32_t size)
+{
+ nt_headers_.OptionalHeader.SizeOfStackReserve = static_cast<typename PEClassType::BaseSize>(size);
+}
+
+//Sets stack size reserve for PE32/PE64
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_stack_size_reserve(uint64_t size)
+{
+ nt_headers_.OptionalHeader.SizeOfStackReserve = static_cast<typename PEClassType::BaseSize>(size);
+}
+
+//Returns heap size commit for PE32
+template<typename PEClassType>
+uint32_t pe_properties_generic<PEClassType>::get_heap_size_commit_32() const
+{
+ return static_cast<uint32_t>(nt_headers_.OptionalHeader.SizeOfHeapCommit);
+}
+
+//Returns heap size commit for PE32/PE64
+template<typename PEClassType>
+uint64_t pe_properties_generic<PEClassType>::get_heap_size_commit_64() const
+{
+ return static_cast<uint64_t>(nt_headers_.OptionalHeader.SizeOfHeapCommit);
+}
+
+//Returns heap size reserve for PE32
+template<typename PEClassType>
+uint32_t pe_properties_generic<PEClassType>::get_heap_size_reserve_32() const
+{
+ return static_cast<uint32_t>(nt_headers_.OptionalHeader.SizeOfHeapReserve);
+}
+
+//Returns heap size reserve for PE32/PE64
+template<typename PEClassType>
+uint64_t pe_properties_generic<PEClassType>::get_heap_size_reserve_64() const
+{
+ return static_cast<uint64_t>(nt_headers_.OptionalHeader.SizeOfHeapReserve);
+}
+
+//Returns stack size commit for PE32
+template<typename PEClassType>
+uint32_t pe_properties_generic<PEClassType>::get_stack_size_commit_32() const
+{
+ return static_cast<uint32_t>(nt_headers_.OptionalHeader.SizeOfStackCommit);
+}
+
+//Returns stack size commit for PE32/PE64
+template<typename PEClassType>
+uint64_t pe_properties_generic<PEClassType>::get_stack_size_commit_64() const
+{
+ return static_cast<uint64_t>(nt_headers_.OptionalHeader.SizeOfStackCommit);
+}
+
+//Returns stack size reserve for PE32
+template<typename PEClassType>
+uint32_t pe_properties_generic<PEClassType>::get_stack_size_reserve_32() const
+{
+ return static_cast<uint32_t>(nt_headers_.OptionalHeader.SizeOfStackReserve);
+}
+
+//Returns stack size reserve for PE32/PE64
+template<typename PEClassType>
+uint64_t pe_properties_generic<PEClassType>::get_stack_size_reserve_64() const
+{
+ return static_cast<uint64_t>(nt_headers_.OptionalHeader.SizeOfStackReserve);
+}
+
+//Returns virtual size of image
+template<typename PEClassType>
+uint32_t pe_properties_generic<PEClassType>::get_size_of_image() const
+{
+ return nt_headers_.OptionalHeader.SizeOfImage;
+}
+
+//Returns number of RVA and sizes (number of DATA_DIRECTORY entries)
+template<typename PEClassType>
+uint32_t pe_properties_generic<PEClassType>::get_number_of_rvas_and_sizes() const
+{
+ return nt_headers_.OptionalHeader.NumberOfRvaAndSizes;
+}
+
+//Sets number of RVA and sizes (number of DATA_DIRECTORY entries)
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_number_of_rvas_and_sizes(uint32_t number)
+{
+ nt_headers_.OptionalHeader.NumberOfRvaAndSizes = number;
+}
+
+//Returns PE characteristics
+template<typename PEClassType>
+uint16_t pe_properties_generic<PEClassType>::get_characteristics() const
+{
+ return nt_headers_.FileHeader.Characteristics;
+}
+
+//Returns checksum of PE file from header
+template<typename PEClassType>
+uint32_t pe_properties_generic<PEClassType>::get_checksum() const
+{
+ return nt_headers_.OptionalHeader.CheckSum;
+}
+
+//Sets checksum of PE file
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_checksum(uint32_t checksum)
+{
+ nt_headers_.OptionalHeader.CheckSum = checksum;
+}
+
+//Returns DLL Characteristics
+template<typename PEClassType>
+uint16_t pe_properties_generic<PEClassType>::get_dll_characteristics() const
+{
+ return nt_headers_.OptionalHeader.DllCharacteristics;
+}
+
+//Returns timestamp of PE file from header
+template<typename PEClassType>
+uint32_t pe_properties_generic<PEClassType>::get_time_date_stamp() const
+{
+ return nt_headers_.FileHeader.TimeDateStamp;
+}
+
+//Sets timestamp of PE file
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_time_date_stamp(uint32_t timestamp)
+{
+ nt_headers_.FileHeader.TimeDateStamp = timestamp;
+}
+
+//Sets DLL Characteristics
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_dll_characteristics(uint16_t characteristics)
+{
+ nt_headers_.OptionalHeader.DllCharacteristics = characteristics;
+}
+
+//Returns Machine field value of PE file from header
+template<typename PEClassType>
+uint16_t pe_properties_generic<PEClassType>::get_machine() const
+{
+ return nt_headers_.FileHeader.Machine;
+}
+
+//Sets Machine field value of PE file
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_machine(uint16_t machine)
+{
+ nt_headers_.FileHeader.Machine = machine;
+}
+
+//Sets PE characteristics
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_characteristics(uint16_t ch)
+{
+ nt_headers_.FileHeader.Characteristics = ch;
+}
+
+//Returns size of headers
+template<typename PEClassType>
+uint32_t pe_properties_generic<PEClassType>::get_size_of_headers() const
+{
+ return nt_headers_.OptionalHeader.SizeOfHeaders;
+}
+
+//Returns subsystem
+template<typename PEClassType>
+uint16_t pe_properties_generic<PEClassType>::get_subsystem() const
+{
+ return nt_headers_.OptionalHeader.Subsystem;
+}
+
+//Sets subsystem
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_subsystem(uint16_t subsystem)
+{
+ nt_headers_.OptionalHeader.Subsystem = subsystem;
+}
+
+//Returns size of optional header
+template<typename PEClassType>
+uint16_t pe_properties_generic<PEClassType>::get_size_of_optional_header() const
+{
+ return nt_headers_.FileHeader.SizeOfOptionalHeader;
+}
+
+//Returns PE signature
+template<typename PEClassType>
+uint32_t pe_properties_generic<PEClassType>::get_pe_signature() const
+{
+ return nt_headers_.Signature;
+}
+
+//Returns PE magic value
+template<typename PEClassType>
+uint32_t pe_properties_generic<PEClassType>::get_magic() const
+{
+ return nt_headers_.OptionalHeader.Magic;
+}
+
+//Sets required operation system version
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_os_version(uint16_t major, uint16_t minor)
+{
+ nt_headers_.OptionalHeader.MinorOperatingSystemVersion = minor;
+ nt_headers_.OptionalHeader.MajorOperatingSystemVersion = major;
+}
+
+//Returns required operation system version (minor word)
+template<typename PEClassType>
+uint16_t pe_properties_generic<PEClassType>::get_minor_os_version() const
+{
+ return nt_headers_.OptionalHeader.MinorOperatingSystemVersion;
+}
+
+//Returns required operation system version (major word)
+template<typename PEClassType>
+uint16_t pe_properties_generic<PEClassType>::get_major_os_version() const
+{
+ return nt_headers_.OptionalHeader.MajorOperatingSystemVersion;
+}
+
+//Sets required subsystem version
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_subsystem_version(uint16_t major, uint16_t minor)
+{
+ nt_headers_.OptionalHeader.MinorSubsystemVersion = minor;
+ nt_headers_.OptionalHeader.MajorSubsystemVersion = major;
+}
+
+//Returns required subsystem version (minor word)
+template<typename PEClassType>
+uint16_t pe_properties_generic<PEClassType>::get_minor_subsystem_version() const
+{
+ return nt_headers_.OptionalHeader.MinorSubsystemVersion;
+}
+
+//Returns required subsystem version (major word)
+template<typename PEClassType>
+uint16_t pe_properties_generic<PEClassType>::get_major_subsystem_version() const
+{
+ return nt_headers_.OptionalHeader.MajorSubsystemVersion;
+}
+
+//Virtual Address (VA) to Relative Virtual Address (RVA) convertions for PE32
+template<typename PEClassType>
+uint32_t pe_properties_generic<PEClassType>::va_to_rva(uint32_t va, bool bound_check) const
+{
+ if(bound_check && static_cast<uint64_t>(va) - nt_headers_.OptionalHeader.ImageBase > pe_utils::max_dword)
+ throw pe_exception("Incorrect address conversion", pe_exception::incorrect_address_conversion);
+
+ return static_cast<uint32_t>(va - nt_headers_.OptionalHeader.ImageBase);
+}
+
+//Virtual Address (VA) to Relative Virtual Address (RVA) convertions for PE32/PE64
+template<typename PEClassType>
+uint32_t pe_properties_generic<PEClassType>::va_to_rva(uint64_t va, bool bound_check) const
+{
+ if(bound_check && va - nt_headers_.OptionalHeader.ImageBase > pe_utils::max_dword)
+ throw pe_exception("Incorrect address conversion", pe_exception::incorrect_address_conversion);
+
+ return static_cast<uint32_t>(va - nt_headers_.OptionalHeader.ImageBase);
+}
+
+//Relative Virtual Address (RVA) to Virtual Address (VA) convertions for PE32
+template<typename PEClassType>
+uint32_t pe_properties_generic<PEClassType>::rva_to_va_32(uint32_t rva) const
+{
+ if(!pe_utils::is_sum_safe(rva, static_cast<uint32_t>(nt_headers_.OptionalHeader.ImageBase)))
+ throw pe_exception("Incorrect address conversion", pe_exception::incorrect_address_conversion);
+
+ return static_cast<uint32_t>(rva + nt_headers_.OptionalHeader.ImageBase);
+}
+
+//Relative Virtual Address (RVA) to Virtual Address (VA) convertions for PE32/PE64
+template<typename PEClassType>
+uint64_t pe_properties_generic<PEClassType>::rva_to_va_64(uint32_t rva) const
+{
+ return static_cast<uint64_t>(rva) + nt_headers_.OptionalHeader.ImageBase;
+}
+
+//Returns number of sections
+template<typename PEClassType>
+uint16_t pe_properties_generic<PEClassType>::get_number_of_sections() const
+{
+ return nt_headers_.FileHeader.NumberOfSections;
+}
+
+//Sets number of sections
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_number_of_sections(uint16_t number)
+{
+ nt_headers_.FileHeader.NumberOfSections = number;
+}
+
+//Sets virtual size of image
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_size_of_image(uint32_t size)
+{
+ nt_headers_.OptionalHeader.SizeOfImage = size;
+}
+
+//Sets size of headers
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_size_of_headers(uint32_t size)
+{
+ nt_headers_.OptionalHeader.SizeOfHeaders = size;
+}
+
+//Sets size of optional headers
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_size_of_optional_header(uint16_t size)
+{
+ nt_headers_.FileHeader.SizeOfOptionalHeader = size;
+}
+
+//Returns nt headers data pointer
+template<typename PEClassType>
+char* pe_properties_generic<PEClassType>::get_nt_headers_ptr()
+{
+ return reinterpret_cast<char*>(&nt_headers_);
+}
+
+//Returns nt headers data pointer
+template<typename PEClassType>
+const char* pe_properties_generic<PEClassType>::get_nt_headers_ptr() const
+{
+ return reinterpret_cast<const char*>(&nt_headers_);
+}
+
+//Returns size of NT header
+template<typename PEClassType>
+uint32_t pe_properties_generic<PEClassType>::get_sizeof_nt_header() const
+{
+ return sizeof(typename PEClassType::NtHeaders);
+}
+
+//Returns size of optional headers
+template<typename PEClassType>
+uint32_t pe_properties_generic<PEClassType>::get_sizeof_opt_headers() const
+{
+ return sizeof(typename PEClassType::OptHeaders);
+}
+
+//Sets file alignment (no checks)
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_file_alignment_unchecked(uint32_t alignment)
+{
+ nt_headers_.OptionalHeader.FileAlignment = alignment;
+}
+
+//Sets base of code
+template<typename PEClassType>
+void pe_properties_generic<PEClassType>::set_base_of_code(uint32_t base)
+{
+ nt_headers_.OptionalHeader.BaseOfCode = base;
+}
+
+//Returns base of code
+template<typename PEClassType>
+uint32_t pe_properties_generic<PEClassType>::get_base_of_code() const
+{
+ return nt_headers_.OptionalHeader.BaseOfCode;
+}
+
+//Returns needed PE magic for PE or PE+ (from template parameters)
+template<typename PEClassType>
+uint32_t pe_properties_generic<PEClassType>::get_needed_magic() const
+{
+ return PEClassType::Id;
+}
+
+//Returns PE type of this image
+template<typename PEClassType>
+pe_type pe_properties_generic<PEClassType>::get_pe_type() const
+{
+ return PEClassType::Id == image_nt_optional_hdr32_magic ? pe_type_32 : pe_type_64;
+}
+
+//Two used instantiations for PE32 (PE) and PE64 (PE+)
+template class pe_properties_generic<pe_types_class_32>;
+template class pe_properties_generic<pe_types_class_64>;
+}
diff --git a/tools/pe_bliss/pe_properties_generic.h b/tools/pe_bliss/pe_properties_generic.h
new file mode 100644
index 0000000000..4ff906803c
--- /dev/null
+++ b/tools/pe_bliss/pe_properties_generic.h
@@ -0,0 +1,277 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include "pe_properties.h"
+
+namespace pe_bliss
+{
+//Helper class to reduce code size and ease its editing
+template<
+ typename NtHeadersType,
+ typename OptHeadersType,
+ uint16_t IdVal,
+ typename BaseSizeType,
+ BaseSizeType ImportSnapFlagVal,
+ typename TLSStructType,
+ typename ConfigStructType>
+class pe_types
+{
+public:
+ typedef NtHeadersType NtHeaders; //NT HEADERS type
+ typedef OptHeadersType OptHeaders; //NT OPTIONAL HEADER type
+ typedef BaseSizeType BaseSize; //Base size of different values: DWORD or ULONGLONG
+ typedef TLSStructType TLSStruct; //TLS structure type
+ typedef ConfigStructType ConfigStruct; //Configuration structure type
+
+ static const uint16_t Id = IdVal; //Magic of PE or PE+
+ static const BaseSize ImportSnapFlag = ImportSnapFlagVal; //Import snap flag value
+};
+
+//Portable Executable derived class for PE and PE+
+//Describes PE/PE+ dependent things
+template<typename PEClassType>
+class pe_properties_generic : public pe_properties
+{
+public: //Constructor
+ virtual std::auto_ptr<pe_properties> duplicate() const;
+
+ //Fills properly PE structures
+ virtual void create_pe(uint32_t section_alignment, uint16_t subsystem);
+
+public:
+ //Destructor
+ virtual ~pe_properties_generic();
+
+
+public: //DIRECTORIES
+ //Returns true if directory exists
+ virtual bool directory_exists(uint32_t id) const;
+
+ //Removes directory
+ virtual void remove_directory(uint32_t id);
+
+ //Returns directory RVA
+ virtual uint32_t get_directory_rva(uint32_t id) const;
+ //Returns directory size
+ virtual uint32_t get_directory_size(uint32_t id) const;
+
+ //Sets directory RVA (just a value of PE header, no moving occurs)
+ virtual void set_directory_rva(uint32_t id, uint32_t rva);
+ //Sets directory size (just a value of PE header, no moving occurs)
+ virtual void set_directory_size(uint32_t id, uint32_t size);
+
+ //Strips only zero DATA_DIRECTORY entries to count = min_count
+ //Returns resulting number of data directories
+ //strip_iat_directory - if true, even not empty IAT directory will be stripped
+ virtual uint32_t strip_data_directories(uint32_t min_count = 1, bool strip_iat_directory = true);
+
+
+public: //IMAGE
+ //Returns PE type of this image
+ virtual pe_type get_pe_type() const;
+
+
+public: //PE HEADER
+ //Returns image base for PE32 and PE64 respectively
+ virtual uint32_t get_image_base_32() const;
+ virtual uint64_t get_image_base_64() const;
+
+ //Sets new image base for PE32
+ virtual void set_image_base(uint32_t base);
+ //Sets new image base for PE32/PE+
+ virtual void set_image_base_64(uint64_t base);
+
+ //Returns image entry point
+ virtual uint32_t get_ep() const;
+ //Sets image entry point
+ virtual void set_ep(uint32_t new_ep);
+
+ //Returns file alignment
+ virtual uint32_t get_file_alignment() const;
+ //Returns section alignment
+ virtual uint32_t get_section_alignment() const;
+
+ //Sets heap size commit for PE32 and PE64 respectively
+ virtual void set_heap_size_commit(uint32_t size);
+ virtual void set_heap_size_commit(uint64_t size);
+ //Sets heap size reserve for PE32 and PE64 respectively
+ virtual void set_heap_size_reserve(uint32_t size);
+ virtual void set_heap_size_reserve(uint64_t size);
+ //Sets stack size commit for PE32 and PE64 respectively
+ virtual void set_stack_size_commit(uint32_t size);
+ virtual void set_stack_size_commit(uint64_t size);
+ //Sets stack size reserve for PE32 and PE64 respectively
+ virtual void set_stack_size_reserve(uint32_t size);
+ virtual void set_stack_size_reserve(uint64_t size);
+
+ //Returns heap size commit for PE32 and PE64 respectively
+ virtual uint32_t get_heap_size_commit_32() const;
+ virtual uint64_t get_heap_size_commit_64() const;
+ //Returns heap size reserve for PE32 and PE64 respectively
+ virtual uint32_t get_heap_size_reserve_32() const;
+ virtual uint64_t get_heap_size_reserve_64() const;
+ //Returns stack size commit for PE32 and PE64 respectively
+ virtual uint32_t get_stack_size_commit_32() const;
+ virtual uint64_t get_stack_size_commit_64() const;
+ //Returns stack size reserve for PE32 and PE64 respectively
+ virtual uint32_t get_stack_size_reserve_32() const;
+ virtual uint64_t get_stack_size_reserve_64() const;
+
+ //Returns virtual size of image
+ virtual uint32_t get_size_of_image() const;
+
+ //Returns number of RVA and sizes (number of DATA_DIRECTORY entries)
+ virtual uint32_t get_number_of_rvas_and_sizes() const;
+ //Sets number of RVA and sizes (number of DATA_DIRECTORY entries)
+ virtual void set_number_of_rvas_and_sizes(uint32_t number);
+
+ //Returns PE characteristics
+ virtual uint16_t get_characteristics() const;
+ //Sets PE characteristics
+ virtual void set_characteristics(uint16_t ch);
+
+ //Returns size of headers
+ virtual uint32_t get_size_of_headers() const;
+
+ //Returns subsystem
+ virtual uint16_t get_subsystem() const;
+
+ //Sets subsystem
+ virtual void set_subsystem(uint16_t subsystem);
+
+ //Returns size of optional header
+ virtual uint16_t get_size_of_optional_header() const;
+
+ //Returns PE signature
+ virtual uint32_t get_pe_signature() const;
+
+ //Returns PE magic value
+ virtual uint32_t get_magic() const;
+
+ //Returns checksum of PE file from header
+ virtual uint32_t get_checksum() const;
+
+ //Sets checksum of PE file
+ virtual void set_checksum(uint32_t checksum);
+
+ //Returns timestamp of PE file from header
+ virtual uint32_t get_time_date_stamp() const;
+
+ //Sets timestamp of PE file
+ virtual void set_time_date_stamp(uint32_t timestamp);
+
+ //Returns Machine field value of PE file from header
+ virtual uint16_t get_machine() const;
+
+ //Sets Machine field value of PE file
+ virtual void set_machine(uint16_t machine);
+
+ //Returns DLL Characteristics
+ virtual uint16_t get_dll_characteristics() const;
+
+ //Sets DLL Characteristics
+ virtual void set_dll_characteristics(uint16_t characteristics);
+
+ //Sets required operation system version
+ virtual void set_os_version(uint16_t major, uint16_t minor);
+
+ //Returns required operation system version (minor word)
+ virtual uint16_t get_minor_os_version() const;
+
+ //Returns required operation system version (major word)
+ virtual uint16_t get_major_os_version() const;
+
+ //Sets required subsystem version
+ virtual void set_subsystem_version(uint16_t major, uint16_t minor);
+
+ //Returns required subsystem version (minor word)
+ virtual uint16_t get_minor_subsystem_version() const;
+
+ //Returns required subsystem version (major word)
+ virtual uint16_t get_major_subsystem_version() const;
+
+public: //ADDRESS CONVERTIONS
+ //Virtual Address (VA) to Relative Virtual Address (RVA) convertions
+ //for PE32 and PE64 respectively
+ //bound_check checks integer overflow
+ virtual uint32_t va_to_rva(uint32_t va, bool bound_check = true) const;
+ virtual uint32_t va_to_rva(uint64_t va, bool bound_check = true) const;
+
+ //Relative Virtual Address (RVA) to Virtual Address (VA) convertions
+ //for PE32 and PE64 respectively
+ virtual uint32_t rva_to_va_32(uint32_t rva) const;
+ virtual uint64_t rva_to_va_64(uint32_t rva) const;
+
+
+public: //SECTIONS
+ //Returns number of sections
+ virtual uint16_t get_number_of_sections() const;
+
+protected:
+ typename PEClassType::NtHeaders nt_headers_; //NT headers (PE32 or PE64)
+
+public:
+ //Sets number of sections
+ virtual void set_number_of_sections(uint16_t number);
+ //Sets virtual size of image
+ virtual void set_size_of_image(uint32_t size);
+ //Sets size of headers
+ virtual void set_size_of_headers(uint32_t size);
+ //Sets size of optional headers
+ virtual void set_size_of_optional_header(uint16_t size);
+ //Returns nt headers data pointer
+ virtual char* get_nt_headers_ptr();
+ //Returns nt headers data pointer
+ virtual const char* get_nt_headers_ptr() const;
+ //Returns size of NT header
+ virtual uint32_t get_sizeof_nt_header() const;
+ //Returns size of optional headers
+ virtual uint32_t get_sizeof_opt_headers() const;
+ //Sets file alignment (no checks)
+ virtual void set_file_alignment_unchecked(uint32_t alignment);
+ //Sets base of code
+ virtual void set_base_of_code(uint32_t base);
+ //Returns base of code
+ virtual uint32_t get_base_of_code() const;
+ //Returns needed PE magic for PE or PE+ (from template parameters)
+ virtual uint32_t get_needed_magic() const;
+};
+
+//Two used typedefs for PE32 (PE) and PE64 (PE+)
+typedef pe_types<pe_win::image_nt_headers32,
+ pe_win::image_optional_header32,
+ pe_win::image_nt_optional_hdr32_magic,
+ uint32_t,
+ pe_win::image_ordinal_flag32,
+ pe_win::image_tls_directory32,
+ pe_win::image_load_config_directory32> pe_types_class_32;
+
+typedef pe_types<pe_win::image_nt_headers64,
+ pe_win::image_optional_header64,
+ pe_win::image_nt_optional_hdr64_magic,
+ uint64_t,
+ pe_win::image_ordinal_flag64,
+ pe_win::image_tls_directory64,
+ pe_win::image_load_config_directory64> pe_types_class_64;
+
+typedef pe_properties_generic<pe_types_class_32> pe_properties_32;
+typedef pe_properties_generic<pe_types_class_64> pe_properties_64;
+}
diff --git a/tools/pe_bliss/pe_rebuilder.cpp b/tools/pe_bliss/pe_rebuilder.cpp
new file mode 100644
index 0000000000..faf5803b8c
--- /dev/null
+++ b/tools/pe_bliss/pe_rebuilder.cpp
@@ -0,0 +1,214 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include "pe_rebuilder.h"
+#include "pe_base.h"
+#include "pe_structures.h"
+#include "pe_exception.h"
+
+namespace pe_bliss
+{
+using namespace pe_win;
+
+//Rebuilds PE image headers
+//If strip_dos_header is true, DOS headers partially will be used for PE headers
+//If change_size_of_headers == true, SizeOfHeaders will be recalculated automatically
+//If save_bound_import == true, existing bound import directory will be saved correctly (because some compilers and bind.exe put it to PE headers)
+void rebuild_pe(pe_base& pe, image_dos_header& dos_header, bool strip_dos_header, bool change_size_of_headers, bool save_bound_import)
+{
+ dos_header = pe.get_dos_header();
+
+ if(strip_dos_header)
+ {
+ //Strip stub overlay
+ pe.strip_stub_overlay();
+ //BaseOfCode NT Headers field now overlaps
+ //e_lfanew field, so we're acrually setting
+ //e_lfanew with this call
+ pe.set_base_of_code(8 * sizeof(uint16_t));
+ }
+ else
+ {
+ //Set start of PE headers
+ dos_header.e_lfanew = sizeof(image_dos_header)
+ + pe_utils::align_up(static_cast<uint32_t>(pe.get_stub_overlay().size()), sizeof(uint32_t));
+ }
+
+ section_list& sections = pe.get_image_sections();
+
+ //Calculate pointer to section data
+ size_t ptr_to_section_data = (strip_dos_header ? 8 * sizeof(uint16_t) : sizeof(image_dos_header)) + pe.get_sizeof_nt_header()
+ + pe_utils::align_up(pe.get_stub_overlay().size(), sizeof(uint32_t))
+ - sizeof(image_data_directory) * (image_numberof_directory_entries - pe.get_number_of_rvas_and_sizes())
+ + sections.size() * sizeof(image_section_header);
+
+ if(save_bound_import && pe.has_bound_import())
+ {
+ //It will be aligned to DWORD, because we're aligning to DWORD everything above it
+ pe.set_directory_rva(image_directory_entry_bound_import, static_cast<uint32_t>(ptr_to_section_data));
+ ptr_to_section_data += pe.get_directory_size(image_directory_entry_bound_import);
+ }
+
+ ptr_to_section_data = pe_utils::align_up(ptr_to_section_data, pe.get_file_alignment());
+
+ //Set size of headers and size of optional header
+ if(change_size_of_headers)
+ {
+ if(!pe.get_image_sections().empty())
+ {
+ if(static_cast<uint32_t>(ptr_to_section_data) > (*sections.begin()).get_virtual_address())
+ throw pe_exception("Headers of PE file are too long. Try to strip STUB or don't build bound import", pe_exception::cannot_rebuild_image);
+ }
+
+ pe.set_size_of_headers(static_cast<uint32_t>(ptr_to_section_data));
+ }
+
+ //Set number of sections in PE header
+ pe.update_number_of_sections();
+
+ pe.update_image_size();
+
+ pe.set_size_of_optional_header(static_cast<uint16_t>(pe.get_sizeof_opt_headers()
+ - sizeof(image_data_directory) * (image_numberof_directory_entries - pe.get_number_of_rvas_and_sizes())));
+
+ //Recalculate pointer to raw data according to section list
+ for(section_list::iterator it = sections.begin(); it != sections.end(); ++it)
+ {
+ //Save section headers PointerToRawData
+ (*it).set_pointer_to_raw_data(static_cast<uint32_t>(ptr_to_section_data));
+ ptr_to_section_data += (*it).get_aligned_raw_size(pe.get_file_alignment());
+ }
+}
+
+//Rebuild PE image and write it to "out" ostream
+//If strip_dos_header is true, DOS headers partially will be used for PE headers
+//If change_size_of_headers == true, SizeOfHeaders will be recalculated automatically
+//If save_bound_import == true, existing bound import directory will be saved correctly (because some compilers and bind.exe put it to PE headers)
+void rebuild_pe(pe_base& pe, std::ostream& out, bool strip_dos_header, bool change_size_of_headers, bool save_bound_import)
+{
+ if(out.bad())
+ throw pe_exception("Stream is bad", pe_exception::stream_is_bad);
+
+ if(save_bound_import && pe.has_bound_import())
+ {
+ if(pe.section_data_length_from_rva(pe.get_directory_rva(image_directory_entry_bound_import), pe.get_directory_rva(image_directory_entry_bound_import), section_data_raw, true)
+ < pe.get_directory_size(image_directory_entry_bound_import))
+ throw pe_exception("Incorrect bound import directory", pe_exception::incorrect_bound_import_directory);
+ }
+
+ //Change ostream state
+ out.exceptions(std::ios::goodbit);
+ out.clear();
+
+ uint32_t original_bound_import_rva = pe.has_bound_import() ? pe.get_directory_rva(image_directory_entry_bound_import) : 0;
+ if(original_bound_import_rva && original_bound_import_rva > pe.get_size_of_headers())
+ {
+ //No need to do anything with bound import directory
+ //if it is placed inside of any section, not headers
+ original_bound_import_rva = 0;
+ save_bound_import = false;
+ }
+
+ {
+ image_dos_header dos_header;
+
+ //Rebuild PE image headers
+ rebuild_pe(pe, dos_header, strip_dos_header, change_size_of_headers, save_bound_import);
+
+ //Write DOS header
+ out.write(reinterpret_cast<const char*>(&dos_header), strip_dos_header ? 8 * sizeof(uint16_t) : sizeof(image_dos_header));
+ }
+
+ //If we have stub overlay, write it too
+ {
+ const std::string& stub = pe.get_stub_overlay();
+ if(stub.size())
+ {
+ out.write(stub.data(), stub.size());
+ size_t aligned_size = pe_utils::align_up(stub.size(), sizeof(uint32_t));
+ //Align PE header, which is right after rich overlay
+ while(aligned_size > stub.size())
+ {
+ out.put('\0');
+ --aligned_size;
+ }
+ }
+ }
+
+ //Write NT headers
+ out.write(static_cast<const pe_base&>(pe).get_nt_headers_ptr(), pe.get_sizeof_nt_header()
+ - sizeof(image_data_directory) * (image_numberof_directory_entries - pe.get_number_of_rvas_and_sizes()));
+
+ //Write section headers
+ const section_list& sections = pe.get_image_sections();
+ for(section_list::const_iterator it = sections.begin(); it != sections.end(); ++it)
+ {
+ if(it == sections.end() - 1) //If last section encountered
+ {
+ image_section_header header((*it).get_raw_header());
+ header.SizeOfRawData = static_cast<uint32_t>((*it).get_raw_data().length()); //Set non-aligned actual data length for it
+ out.write(reinterpret_cast<const char*>(&header), sizeof(image_section_header));
+ }
+ else
+ {
+ out.write(reinterpret_cast<const char*>(&(*it).get_raw_header()), sizeof(image_section_header));
+ }
+ }
+
+ //Write bound import data if requested
+ if(save_bound_import && pe.has_bound_import())
+ {
+ out.write(pe.section_data_from_rva(original_bound_import_rva, section_data_raw, true),
+ pe.get_directory_size(image_directory_entry_bound_import));
+ }
+
+ //Write section data finally
+ for(section_list::const_iterator it = sections.begin(); it != sections.end(); ++it)
+ {
+ const section& s = *it;
+
+ std::streamoff wpos = out.tellp();
+
+ //Fill unused overlay data between sections with null bytes
+ for(unsigned int i = 0; i < s.get_pointer_to_raw_data() - wpos; i++)
+ out.put(0);
+
+ //Write raw section data
+ out.write(s.get_raw_data().data(), s.get_raw_data().length());
+ }
+}
+
+//Rebuild PE image and write it to "out" file
+//If strip_dos_header is true, DOS headers partially will be used for PE headers
+//If change_size_of_headers == true, SizeOfHeaders will be recalculated automatically
+//If save_bound_import == true, existing bound import directory will be saved correctly (because some compilers and bind.exe put it to PE headers)
+void rebuild_pe(pe_base& pe, const char* out, bool strip_dos_header, bool change_size_of_headers, bool save_bound_import)
+{
+ std::ofstream pe_file(out, std::ios::out | std::ios::binary | std::ios::trunc);
+ if(!pe_file)
+ {
+ throw pe_exception("Error in open file.", pe_exception::stream_is_bad);
+ }
+ rebuild_pe(pe, pe_file, strip_dos_header, change_size_of_headers, save_bound_import);
+}
+
+
+}
diff --git a/tools/pe_bliss/pe_rebuilder.h b/tools/pe_bliss/pe_rebuilder.h
new file mode 100644
index 0000000000..319807e5c9
--- /dev/null
+++ b/tools/pe_bliss/pe_rebuilder.h
@@ -0,0 +1,40 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <ostream>
+#include <fstream>
+
+namespace pe_bliss
+{
+class pe_base;
+//Rebuilds PE image, writes resulting image to ostream "out". If strip_dos_header == true, DOS header will be stripped a little
+//If change_size_of_headers == true, SizeOfHeaders will be recalculated automatically
+//If save_bound_import == true, existing bound import directory will be saved correctly (because some compilers and bind.exe put it to PE headers)
+void rebuild_pe(pe_base& pe, std::ostream& out, bool strip_dos_header = false, bool change_size_of_headers = true, bool save_bound_import = true);
+
+//Rebuild PE image and write it to "out" file
+//If strip_dos_header is true, DOS headers partially will be used for PE headers
+//If change_size_of_headers == true, SizeOfHeaders will be recalculated automatically
+//If save_bound_import == true, existing bound import directory will be saved correctly (because some compilers and bind.exe put it to PE headers)
+void rebuild_pe(pe_base& pe, const char* out, bool strip_dos_header = false, bool change_size_of_headers = true, bool save_bound_import = true);
+
+}
diff --git a/tools/pe_bliss/pe_relocations.cpp b/tools/pe_bliss/pe_relocations.cpp
new file mode 100644
index 0000000000..d5357dd219
--- /dev/null
+++ b/tools/pe_bliss/pe_relocations.cpp
@@ -0,0 +1,320 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include <string.h>
+#include "pe_relocations.h"
+#include "pe_properties_generic.h"
+
+namespace pe_bliss
+{
+using namespace pe_win;
+
+//RELOCATIONS
+//Default constructor
+relocation_entry::relocation_entry()
+ :rva_(0), type_(0)
+{}
+
+//Constructor from relocation item (WORD)
+relocation_entry::relocation_entry(uint16_t relocation_value)
+ :rva_(relocation_value & ((1 << 12) - 1)), type_(relocation_value >> 12)
+{}
+
+//Constructor from relative rva and relocation type
+relocation_entry::relocation_entry(uint16_t rrva, uint16_t type)
+ :rva_(rrva), type_(type)
+{}
+
+//Returns RVA of relocation
+uint16_t relocation_entry::get_rva() const
+{
+ return rva_;
+}
+
+//Returns type of relocation
+uint16_t relocation_entry::get_type() const
+{
+ return type_;
+}
+
+//Sets RVA of relocation
+void relocation_entry::set_rva(uint16_t rva)
+{
+ rva_ = rva;
+}
+
+//Sets type of relocation
+void relocation_entry::set_type(uint16_t type)
+{
+ type_ = type;
+}
+
+//Returns relocation item (rrva + type)
+uint16_t relocation_entry::get_item() const
+{
+ return rva_ | (type_ << 12);
+}
+
+//Sets relocation item (rrva + type)
+void relocation_entry::set_item(uint16_t item)
+{
+ rva_ = item & ((1 << 12) - 1);
+ type_ = item >> 12;
+}
+
+//Returns relocation list
+const relocation_table::relocation_list& relocation_table::get_relocations() const
+{
+ return relocations_;
+}
+
+//Adds relocation to table
+void relocation_table::add_relocation(const relocation_entry& entry)
+{
+ relocations_.push_back(entry);
+}
+
+//Default constructor
+relocation_table::relocation_table()
+ :rva_(0)
+{}
+
+//Constructor from RVA of relocation table
+relocation_table::relocation_table(uint32_t rva)
+ :rva_(rva)
+{}
+
+//Returns RVA of block
+uint32_t relocation_table::get_rva() const
+{
+ return rva_;
+}
+
+//Sets RVA of block
+void relocation_table::set_rva(uint32_t rva)
+{
+ rva_ = rva;
+}
+
+//Returns changeable relocation list
+relocation_table::relocation_list& relocation_table::get_relocations()
+{
+ return relocations_;
+}
+
+//Get relocation list of pe file, supports one-word sized relocations only
+//If list_absolute_entries = true, IMAGE_REL_BASED_ABSOLUTE will be listed
+const relocation_table_list get_relocations(const pe_base& pe, bool list_absolute_entries)
+{
+ relocation_table_list ret;
+
+ //If image does not have relocations
+ if(!pe.has_reloc())
+ return ret;
+
+ //Check the length in bytes of the section containing relocation directory
+ if(pe.section_data_length_from_rva(pe.get_directory_rva(image_directory_entry_basereloc),
+ pe.get_directory_rva(image_directory_entry_basereloc), section_data_virtual, true)
+ < sizeof(image_base_relocation))
+ throw pe_exception("Incorrect relocation directory", pe_exception::incorrect_relocation_directory);
+
+ unsigned long current_pos = pe.get_directory_rva(image_directory_entry_basereloc);
+ //First IMAGE_BASE_RELOCATION table
+ image_base_relocation reloc_table = pe.section_data_from_rva<image_base_relocation>(current_pos, section_data_virtual, true);
+
+ if(reloc_table.SizeOfBlock % 2)
+ throw pe_exception("Incorrect relocation directory", pe_exception::incorrect_relocation_directory);
+
+ unsigned long reloc_size = pe.get_directory_size(image_directory_entry_basereloc);
+ unsigned long read_size = 0;
+
+ //reloc_table.VirtualAddress is not checked (not so important)
+ while(reloc_table.SizeOfBlock && read_size < reloc_size)
+ {
+ //Create relocation table
+ relocation_table table;
+ //Save RVA
+ table.set_rva(reloc_table.VirtualAddress);
+
+ if(!pe_utils::is_sum_safe(current_pos, reloc_table.SizeOfBlock))
+ throw pe_exception("Incorrect relocation directory", pe_exception::incorrect_relocation_directory);
+
+ //List all relocations
+ for(unsigned long i = sizeof(image_base_relocation); i < reloc_table.SizeOfBlock; i += sizeof(uint16_t))
+ {
+ relocation_entry entry(pe.section_data_from_rva<uint16_t>(current_pos + i, section_data_virtual, true));
+ if(list_absolute_entries || entry.get_type() != image_rel_based_absolute)
+ table.add_relocation(entry);
+ }
+
+ //Save table
+ ret.push_back(table);
+
+ //Go to next relocation block
+ if(!pe_utils::is_sum_safe(current_pos, reloc_table.SizeOfBlock))
+ throw pe_exception("Incorrect relocation directory", pe_exception::incorrect_relocation_directory);
+
+ current_pos += reloc_table.SizeOfBlock;
+ read_size += reloc_table.SizeOfBlock;
+ reloc_table = pe.section_data_from_rva<image_base_relocation>(current_pos, section_data_virtual, true);
+ }
+
+ return ret;
+}
+
+//Simple relocations rebuilder
+//To keep PE file working, don't remove any of existing relocations in
+//relocation_table_list returned by a call to get_relocations() function
+//auto_strip_last_section - if true and relocations are placed in the last section, it will be automatically stripped
+//offset_from_section_start - offset from the beginning of reloc_section, where relocations data will be situated
+//If save_to_pe_header is true, PE header will be modified automatically
+const image_directory rebuild_relocations(pe_base& pe, const relocation_table_list& relocs, section& reloc_section, uint32_t offset_from_section_start, bool save_to_pe_header, bool auto_strip_last_section)
+{
+ //Check that reloc_section is attached to this PE image
+ if(!pe.section_attached(reloc_section))
+ throw pe_exception("Relocations section must be attached to PE file", pe_exception::section_is_not_attached);
+
+ uint32_t current_reloc_data_pos = pe_utils::align_up(offset_from_section_start, sizeof(uint32_t));
+
+ uint32_t needed_size = current_reloc_data_pos - offset_from_section_start; //Calculate needed size for relocation tables
+ uint32_t size_delta = needed_size;
+
+ uint32_t start_reloc_pos = current_reloc_data_pos;
+
+ //Enumerate relocation tables
+ for(relocation_table_list::const_iterator it = relocs.begin(); it != relocs.end(); ++it)
+ {
+ needed_size += static_cast<uint32_t>((*it).get_relocations().size() * sizeof(uint16_t) /* relocations */ + sizeof(image_base_relocation) /* table header */);
+ //End of each table will be DWORD-aligned
+ if((start_reloc_pos + needed_size - size_delta) % sizeof(uint32_t))
+ needed_size += sizeof(uint16_t); //Align it with IMAGE_REL_BASED_ABSOLUTE relocation
+ }
+
+ //Check if reloc_section is last one. If it's not, check if there's enough place for relocations data
+ if(&reloc_section != &*(pe.get_image_sections().end() - 1) &&
+ (reloc_section.empty() || pe_utils::align_up(reloc_section.get_size_of_raw_data(), pe.get_file_alignment()) < needed_size + current_reloc_data_pos))
+ throw pe_exception("Insufficient space for relocations directory", pe_exception::insufficient_space);
+
+ std::string& raw_data = reloc_section.get_raw_data();
+
+ //This will be done only if reloc_section is the last section of image or for section with unaligned raw length of data
+ if(raw_data.length() < needed_size + current_reloc_data_pos)
+ raw_data.resize(needed_size + current_reloc_data_pos); //Expand section raw data
+
+ //Enumerate relocation tables
+ for(relocation_table_list::const_iterator it = relocs.begin(); it != relocs.end(); ++it)
+ {
+ //Create relocation table header
+ image_base_relocation reloc;
+ reloc.VirtualAddress = (*it).get_rva();
+ const relocation_table::relocation_list& reloc_list = (*it).get_relocations();
+ reloc.SizeOfBlock = static_cast<uint32_t>(sizeof(image_base_relocation) + sizeof(uint16_t) * reloc_list.size());
+ if((reloc_list.size() * sizeof(uint16_t)) % sizeof(uint32_t)) //If we must align end of relocation table
+ reloc.SizeOfBlock += sizeof(uint16_t);
+
+ memcpy(&raw_data[current_reloc_data_pos], &reloc, sizeof(reloc));
+ current_reloc_data_pos += sizeof(reloc);
+
+ //Enumerate relocations in table
+ for(relocation_table::relocation_list::const_iterator r = reloc_list.begin(); r != reloc_list.end(); ++r)
+ {
+ //Save relocations
+ uint16_t reloc_value = (*r).get_item();
+ memcpy(&raw_data[current_reloc_data_pos], &reloc_value, sizeof(reloc_value));
+ current_reloc_data_pos += sizeof(reloc_value);
+ }
+
+ if(current_reloc_data_pos % sizeof(uint32_t)) //If end of table is not DWORD-aligned
+ {
+ memset(&raw_data[current_reloc_data_pos], 0, sizeof(uint16_t)); //Align it with IMAGE_REL_BASED_ABSOLUTE relocation
+ current_reloc_data_pos += sizeof(uint16_t);
+ }
+ }
+
+ image_directory ret(pe.rva_from_section_offset(reloc_section, start_reloc_pos), needed_size - size_delta);
+
+ //Adjust section raw and virtual sizes
+ pe.recalculate_section_sizes(reloc_section, auto_strip_last_section);
+
+ //If auto-rewrite of PE headers is required
+ if(save_to_pe_header)
+ {
+ pe.set_directory_rva(image_directory_entry_basereloc, ret.get_rva());
+ pe.set_directory_size(image_directory_entry_basereloc, ret.get_size());
+
+ pe.clear_characteristics_flags(image_file_relocs_stripped);
+ pe.set_dll_characteristics(pe.get_dll_characteristics() | image_dllcharacteristics_dynamic_base);
+ }
+
+ return ret;
+}
+
+//Recalculates image base with the help of relocation tables
+void rebase_image(pe_base& pe, const relocation_table_list& tables, uint64_t new_base)
+{
+ pe.get_pe_type() == pe_type_32
+ ? rebase_image_base<pe_types_class_32>(pe, tables, new_base)
+ : rebase_image_base<pe_types_class_64>(pe, tables, new_base);
+}
+
+//RELOCATIONS
+//Recalculates image base with the help of relocation tables
+//Recalculates VAs of DWORDS/QWORDS in image according to relocations
+//Notice: if you move some critical structures like TLS, image relocations will not fix new
+//positions of TLS VAs. Instead, some bytes that now doesn't belong to TLS will be fixed.
+//It is recommended to rebase image in the very beginning and move all structures afterwards.
+template<typename PEClassType>
+void rebase_image_base(pe_base& pe, const relocation_table_list& tables, uint64_t new_base)
+{
+ //Get current image base value
+ typename PEClassType::BaseSize image_base;
+ pe.get_image_base(image_base);
+
+ //ImageBase difference
+ typename PEClassType::BaseSize base_rel = static_cast<typename PEClassType::BaseSize>(static_cast<int64_t>(new_base) - image_base);
+
+ //We need to fix addresses from relocation tables
+ //Enumerate relocation tables
+ for(relocation_table_list::const_iterator it = tables.begin(); it != tables.end(); ++it)
+ {
+ const relocation_table::relocation_list& relocs = (*it).get_relocations();
+
+ uint32_t base_rva = (*it).get_rva();
+
+ //Enumerate relocations
+ for(relocation_table::relocation_list::const_iterator rel = relocs.begin(); rel != relocs.end(); ++rel)
+ {
+ //Skip ABSOLUTE entries
+ if((*rel).get_type() == pe_win::image_rel_based_absolute)
+ continue;
+
+ //Recalculate value by RVA and rewrite it
+ uint32_t current_rva = base_rva + (*rel).get_rva();
+ typename PEClassType::BaseSize value = pe.section_data_from_rva<typename PEClassType::BaseSize>(current_rva, section_data_raw, true);
+ value += base_rel;
+ memcpy(pe.section_data_from_rva(current_rva, true), &value, sizeof(value));
+ }
+ }
+
+ //Finally, save new image base
+ pe.set_image_base_64(new_base);
+}
+}
diff --git a/tools/pe_bliss/pe_relocations.h b/tools/pe_bliss/pe_relocations.h
new file mode 100644
index 0000000000..1bc8b2a405
--- /dev/null
+++ b/tools/pe_bliss/pe_relocations.h
@@ -0,0 +1,122 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <vector>
+#include "pe_structures.h"
+#include "pe_base.h"
+#include "pe_directory.h"
+
+namespace pe_bliss
+{
+//Class representing relocation entry
+//RVA of relocation is not actually RVA, but
+//(real RVA) - (RVA of table)
+class relocation_entry
+{
+public:
+ //Default constructor
+ relocation_entry();
+ //Constructor from relocation item (WORD)
+ explicit relocation_entry(uint16_t relocation_value);
+ //Constructor from relative rva and relocation type
+ relocation_entry(uint16_t rrva, uint16_t type);
+
+ //Returns RVA of relocation (actually, relative RVA from relocation table RVA)
+ uint16_t get_rva() const;
+ //Returns type of relocation
+ uint16_t get_type() const;
+
+ //Returns relocation item (rrva + type)
+ uint16_t get_item() const;
+
+public: //Setters do not change everything inside image, they are used by PE class
+ //You can also use them to rebuild relocations using rebuild_relocations()
+
+ //Sets RVA of relocation (actually, relative RVA from relocation table RVA)
+ void set_rva(uint16_t rva);
+ //Sets type of relocation
+ void set_type(uint16_t type);
+
+ //Sets relocation item (rrva + type)
+ void set_item(uint16_t item);
+
+private:
+ uint16_t rva_;
+ uint16_t type_;
+};
+
+//Class representing relocation table
+class relocation_table
+{
+public:
+ typedef std::vector<relocation_entry> relocation_list;
+
+public:
+ //Default constructor
+ relocation_table();
+ //Constructor from RVA of relocation table
+ explicit relocation_table(uint32_t rva);
+
+ //Returns relocation list
+ const relocation_list& get_relocations() const;
+ //Returns RVA of block
+ uint32_t get_rva() const;
+
+public: //These functions do not change everything inside image, they are used by PE class
+ //You can also use them to rebuild relocations using rebuild_relocations()
+
+ //Adds relocation to table
+ void add_relocation(const relocation_entry& entry);
+ //Returns changeable relocation list
+ relocation_list& get_relocations();
+ //Sets RVA of block
+ void set_rva(uint32_t rva);
+
+private:
+ uint32_t rva_;
+ relocation_list relocations_;
+};
+
+typedef std::vector<relocation_table> relocation_table_list;
+
+//Get relocation list of pe file, supports one-word sized relocations only
+//If list_absolute_entries = true, IMAGE_REL_BASED_ABSOLUTE will be listed
+const relocation_table_list get_relocations(const pe_base& pe, bool list_absolute_entries = false);
+
+//Simple relocations rebuilder
+//To keep PE file working, don't remove any of existing relocations in
+//relocation_table_list returned by a call to get_relocations() function
+//auto_strip_last_section - if true and relocations are placed in the last section, it will be automatically stripped
+//offset_from_section_start - offset from the beginning of reloc_section, where relocations data will be situated
+//If save_to_pe_header is true, PE header will be modified automatically
+const image_directory rebuild_relocations(pe_base& pe, const relocation_table_list& relocs, section& reloc_section, uint32_t offset_from_section_start = 0, bool save_to_pe_header = true, bool auto_strip_last_section = true);
+
+//Recalculates image base with the help of relocation tables
+//Recalculates VAs of DWORDS/QWORDS in image according to relocations
+//Notice: if you move some critical structures like TLS, image relocations will not fix new
+//positions of TLS VAs. Instead, some bytes that now doesn't belong to TLS will be fixed.
+//It is recommended to rebase image in the very beginning and move all structures afterwards.
+void rebase_image(pe_base& pe, const relocation_table_list& tables, uint64_t new_base);
+
+template<typename PEClassType>
+void rebase_image_base(pe_base& pe, const relocation_table_list& tables, uint64_t new_base);
+}
diff --git a/tools/pe_bliss/pe_resource_manager.cpp b/tools/pe_bliss/pe_resource_manager.cpp
new file mode 100644
index 0000000000..0ee7840ff0
--- /dev/null
+++ b/tools/pe_bliss/pe_resource_manager.cpp
@@ -0,0 +1,286 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include <algorithm>
+#include <sstream>
+#include <iomanip>
+#include <math.h>
+#include <string.h>
+#include "pe_resource_manager.h"
+#include "resource_internal.h"
+
+namespace pe_bliss
+{
+using namespace pe_win;
+
+//Constructor from root resource directory
+pe_resource_manager::pe_resource_manager(resource_directory& root_directory)
+ :pe_resource_viewer(root_directory), root_dir_edit_(root_directory)
+{}
+
+resource_directory& pe_resource_manager::get_root_directory()
+{
+ return root_dir_edit_;
+}
+
+//Removes all resources of given type or root name
+//If there's more than one directory entry of a given type, only the
+//first one will be deleted (that's an unusual situation)
+//Returns true if resource was deleted
+bool pe_resource_manager::remove_resource_type(resource_type type)
+{
+ //Search for resource type
+ resource_directory::entry_list& entries = root_dir_edit_.get_entry_list();
+ resource_directory::entry_list::iterator it = std::find_if(entries.begin(), entries.end(), resource_directory::id_entry_finder(type));
+ if(it != entries.end())
+ {
+ //Remove it, if found
+ entries.erase(it);
+ return true;
+ }
+
+ return false;
+}
+
+bool pe_resource_manager::remove_resource(const std::wstring& root_name)
+{
+ //Search for resource type
+ resource_directory::entry_list& entries = root_dir_edit_.get_entry_list();
+ resource_directory::entry_list::iterator it = std::find_if(entries.begin(), entries.end(), resource_directory::name_entry_finder(root_name));
+ if(it != entries.end())
+ {
+ //Remove it, if found
+ entries.erase(it);
+ return true;
+ }
+
+ return false;
+}
+
+//Helper to remove resource
+bool pe_resource_manager::remove_resource(const resource_directory::entry_finder& root_finder, const resource_directory::entry_finder& finder)
+{
+ //Search for resource type
+ resource_directory::entry_list& entries_type = root_dir_edit_.get_entry_list();
+ resource_directory::entry_list::iterator it_type = std::find_if(entries_type.begin(), entries_type.end(), root_finder);
+ if(it_type != entries_type.end())
+ {
+ //Search for resource name/ID with "finder"
+ resource_directory::entry_list& entries_name = (*it_type).get_resource_directory().get_entry_list();
+ resource_directory::entry_list::iterator it_name = std::find_if(entries_name.begin(), entries_name.end(), finder);
+ if(it_name != entries_name.end())
+ {
+ //Erase resource, if found
+ entries_name.erase(it_name);
+ if(entries_name.empty())
+ entries_type.erase(it_type);
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//Removes all resource languages by resource type/root name and name
+//Deletes only one entry of given type and name
+//Returns true if resource was deleted
+bool pe_resource_manager::remove_resource(resource_type type, const std::wstring& name)
+{
+ return remove_resource(resource_directory::entry_finder(type), resource_directory::entry_finder(name));
+}
+
+bool pe_resource_manager::remove_resource(const std::wstring& root_name, const std::wstring& name)
+{
+ return remove_resource(resource_directory::entry_finder(root_name), resource_directory::entry_finder(name));
+}
+
+//Removes all resource languages by resource type/root name and ID
+//Deletes only one entry of given type and ID
+//Returns true if resource was deleted
+bool pe_resource_manager::remove_resource(resource_type type, uint32_t id)
+{
+ return remove_resource(resource_directory::entry_finder(type), resource_directory::entry_finder(id));
+}
+
+bool pe_resource_manager::remove_resource(const std::wstring& root_name, uint32_t id)
+{
+ return remove_resource(resource_directory::entry_finder(root_name), resource_directory::entry_finder(id));
+}
+
+//Helper to remove resource
+bool pe_resource_manager::remove_resource(const resource_directory::entry_finder& root_finder, const resource_directory::entry_finder& finder, uint32_t language)
+{
+ //Search for resource type
+ resource_directory::entry_list& entries_type = root_dir_edit_.get_entry_list();
+ resource_directory::entry_list::iterator it_type = std::find_if(entries_type.begin(), entries_type.end(), root_finder);
+ if(it_type != entries_type.end())
+ {
+ //Search for resource name/ID with "finder"
+ resource_directory::entry_list& entries_name = (*it_type).get_resource_directory().get_entry_list();
+ resource_directory::entry_list::iterator it_name = std::find_if(entries_name.begin(), entries_name.end(), finder);
+ if(it_name != entries_name.end())
+ {
+ //Search for resource language
+ resource_directory::entry_list& entries_lang = (*it_name).get_resource_directory().get_entry_list();
+ resource_directory::entry_list::iterator it_lang = std::find_if(entries_lang.begin(), entries_lang.end(), resource_directory::id_entry_finder(language));
+ if(it_lang != entries_lang.end())
+ {
+ //Erase resource, if found
+ entries_lang.erase(it_lang);
+ if(entries_lang.empty())
+ {
+ entries_name.erase(it_name);
+ if(entries_name.empty())
+ entries_type.erase(it_type);
+ }
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+//Removes resource language by resource type/root name and name
+//Deletes only one entry of given type, name and language
+//Returns true if resource was deleted
+bool pe_resource_manager::remove_resource(resource_type type, const std::wstring& name, uint32_t language)
+{
+ return remove_resource(resource_directory::entry_finder(type), resource_directory::entry_finder(name), language);
+}
+
+bool pe_resource_manager::remove_resource(const std::wstring& root_name, const std::wstring& name, uint32_t language)
+{
+ return remove_resource(resource_directory::entry_finder(root_name), resource_directory::entry_finder(name), language);
+}
+
+//Removes recource language by resource type/root name and ID
+//Deletes only one entry of given type, ID and language
+//Returns true if resource was deleted
+bool pe_resource_manager::remove_resource(resource_type type, uint32_t id, uint32_t language)
+{
+ return remove_resource(resource_directory::entry_finder(type), resource_directory::entry_finder(id), language);
+}
+
+bool pe_resource_manager::remove_resource(const std::wstring& root_name, uint32_t id, uint32_t language)
+{
+ return remove_resource(resource_directory::entry_finder(root_name), resource_directory::entry_finder(id), language);
+}
+
+//Helper to add/replace resource
+void pe_resource_manager::add_resource(const std::string& data, resource_type type, resource_directory_entry& new_entry, const resource_directory::entry_finder& finder, uint32_t language, uint32_t codepage, uint32_t timestamp)
+{
+ resource_directory_entry new_type_entry;
+ new_type_entry.set_id(type);
+
+ add_resource(data, new_type_entry, resource_directory::entry_finder(type), new_entry, finder, language, codepage, timestamp);
+}
+
+//Helper to add/replace resource
+void pe_resource_manager::add_resource(const std::string& data, const std::wstring& root_name, resource_directory_entry& new_entry, const resource_directory::entry_finder& finder, uint32_t language, uint32_t codepage, uint32_t timestamp)
+{
+ resource_directory_entry new_type_entry;
+ new_type_entry.set_name(root_name);
+
+ add_resource(data, new_type_entry, resource_directory::entry_finder(root_name), new_entry, finder, language, codepage, timestamp);
+}
+
+//Helper to add/replace resource
+void pe_resource_manager::add_resource(const std::string& data, resource_directory_entry& new_root_entry, const resource_directory::entry_finder& root_finder, resource_directory_entry& new_entry, const resource_directory::entry_finder& finder, uint32_t language, uint32_t codepage, uint32_t timestamp)
+{
+ //Search for resource type
+ resource_directory::entry_list* entries = &root_dir_edit_.get_entry_list();
+ resource_directory::entry_list::iterator it = std::find_if(entries->begin(), entries->end(), root_finder);
+ if(it == entries->end())
+ {
+ //Add resource type directory, if it was not found
+ resource_directory dir;
+ dir.set_timestamp(timestamp);
+ new_root_entry.add_resource_directory(dir);
+ entries->push_back(new_root_entry);
+ it = entries->end() - 1;
+ }
+
+ //Search for resource name/ID directory with "finder"
+ entries = &(*it).get_resource_directory().get_entry_list();
+ it = std::find_if(entries->begin(), entries->end(), finder);
+ if(it == entries->end())
+ {
+ //Add resource name/ID directory, if it was not found
+ resource_directory dir;
+ dir.set_timestamp(timestamp);
+ new_entry.add_resource_directory(dir);
+ entries->push_back(new_entry);
+ it = entries->end() - 1;
+ }
+
+ //Search for data resource entry by language
+ entries = &(*it).get_resource_directory().get_entry_list();
+ it = std::find_if(entries->begin(), entries->end(), resource_directory::id_entry_finder(language));
+ if(it != entries->end())
+ entries->erase(it); //Erase it, if found
+
+ //Add new data entry
+ resource_directory_entry new_dir_data_entry;
+ resource_data_entry data_dir(data, codepage);
+ new_dir_data_entry.add_data_entry(data_dir);
+ new_dir_data_entry.set_id(language);
+ entries->push_back(new_dir_data_entry);
+}
+
+//Adds resource. If resource already exists, replaces it
+void pe_resource_manager::add_resource(const std::string& data, resource_type type, const std::wstring& name, uint32_t language, uint32_t codepage, uint32_t timestamp)
+{
+ resource_directory_entry new_entry;
+ new_entry.set_name(name);
+
+ add_resource(data, type, new_entry, resource_directory::entry_finder(name), language, codepage, timestamp);
+}
+
+//Adds resource. If resource already exists, replaces it
+void pe_resource_manager::add_resource(const std::string& data, const std::wstring& root_name, const std::wstring& name, uint32_t language, uint32_t codepage, uint32_t timestamp)
+{
+ resource_directory_entry new_entry;
+ new_entry.set_name(name);
+
+ add_resource(data, root_name, new_entry, resource_directory::entry_finder(name), language, codepage, timestamp);
+}
+
+//Adds resource. If resource already exists, replaces it
+void pe_resource_manager::add_resource(const std::string& data, resource_type type, uint32_t id, uint32_t language, uint32_t codepage, uint32_t timestamp)
+{
+ resource_directory_entry new_entry;
+ new_entry.set_id(id);
+
+ add_resource(data, type, new_entry, resource_directory::entry_finder(id), language, codepage, timestamp);
+}
+
+//Adds resource. If resource already exists, replaces it
+void pe_resource_manager::add_resource(const std::string& data, const std::wstring& root_name, uint32_t id, uint32_t language, uint32_t codepage, uint32_t timestamp)
+{
+ resource_directory_entry new_entry;
+ new_entry.set_id(id);
+
+ add_resource(data, root_name, new_entry, resource_directory::entry_finder(id), language, codepage, timestamp);
+}
+}
diff --git a/tools/pe_bliss/pe_resource_manager.h b/tools/pe_bliss/pe_resource_manager.h
new file mode 100644
index 0000000000..85d7f44a8a
--- /dev/null
+++ b/tools/pe_bliss/pe_resource_manager.h
@@ -0,0 +1,113 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <map>
+#include <sstream>
+#include <string>
+#include <memory>
+#include "pe_base.h"
+#include "pe_structures.h"
+#include "pe_resources.h"
+#include "message_table.h"
+#include "file_version_info.h"
+#include "pe_resource_viewer.h"
+#include "resource_data_info.h"
+
+namespace pe_bliss
+{
+//Derived class to edit PE resources
+class pe_resource_manager : public pe_resource_viewer
+{
+public:
+ //Constructor from root resource directory
+ explicit pe_resource_manager(resource_directory& root_directory);
+
+ resource_directory& get_root_directory();
+
+public: //Resource editing
+ //Removes all resources of given type or root name
+ //If there's more than one directory entry of a given type, only the
+ //first one will be deleted (that's an unusual situation)
+ //Returns true if resource was deleted
+ bool remove_resource_type(resource_type type);
+ bool remove_resource(const std::wstring& root_name);
+
+ //Removes all resource languages by resource type/root name and name
+ //Deletes only one entry of given type and name
+ //Returns true if resource was deleted
+ bool remove_resource(resource_type type, const std::wstring& name);
+ bool remove_resource(const std::wstring& root_name, const std::wstring& name);
+ //Removes all resource languages by resource type/root name and ID
+ //Deletes only one entry of given type and ID
+ //Returns true if resource was deleted
+ bool remove_resource(resource_type type, uint32_t id);
+ bool remove_resource(const std::wstring& root_name, uint32_t id);
+
+ //Removes resource language by resource type/root name and name
+ //Deletes only one entry of given type, name and language
+ //Returns true if resource was deleted
+ bool remove_resource(resource_type type, const std::wstring& name, uint32_t language);
+ bool remove_resource(const std::wstring& root_name, const std::wstring& name, uint32_t language);
+ //Removes recource language by resource type/root name and ID
+ //Deletes only one entry of given type, ID and language
+ //Returns true if resource was deleted
+ bool remove_resource(resource_type type, uint32_t id, uint32_t language);
+ bool remove_resource(const std::wstring& root_name, uint32_t id, uint32_t language);
+
+ //Adds resource. If resource already exists, replaces it
+ //timestamp will be used for directories that will be added
+ void add_resource(const std::string& data, resource_type type, const std::wstring& name, uint32_t language, uint32_t codepage = 0, uint32_t timestamp = 0);
+ void add_resource(const std::string& data, const std::wstring& root_name, const std::wstring& name, uint32_t language, uint32_t codepage = 0, uint32_t timestamp = 0);
+ //Adds resource. If resource already exists, replaces it
+ //timestamp will be used for directories that will be added
+ void add_resource(const std::string& data, resource_type type, uint32_t id, uint32_t language, uint32_t codepage = 0, uint32_t timestamp = 0);
+ void add_resource(const std::string& data, const std::wstring& root_name, uint32_t id, uint32_t language, uint32_t codepage = 0, uint32_t timestamp = 0);
+
+public:
+ //Helpers to add/replace resource
+ void add_resource(const std::string& data, resource_type type,
+ resource_directory_entry& new_entry,
+ const resource_directory::entry_finder& finder,
+ uint32_t language, uint32_t codepage, uint32_t timestamp);
+
+ void add_resource(const std::string& data, const std::wstring& root_name,
+ resource_directory_entry& new_entry,
+ const resource_directory::entry_finder& finder,
+ uint32_t language, uint32_t codepage, uint32_t timestamp);
+
+ void add_resource(const std::string& data, resource_directory_entry& new_root_entry,
+ const resource_directory::entry_finder& root_finder,
+ resource_directory_entry& new_entry,
+ const resource_directory::entry_finder& finder,
+ uint32_t language, uint32_t codepage, uint32_t timestamp);
+
+private:
+ //Root resource directory. We're not copying it, because it might be heavy
+ resource_directory& root_dir_edit_;
+
+ //Helper to remove resource
+ bool remove_resource(const resource_directory::entry_finder& root_finder, const resource_directory::entry_finder& finder);
+
+ //Helper to remove resource
+ bool remove_resource(const resource_directory::entry_finder& root_finder, const resource_directory::entry_finder& finder, uint32_t language);
+};
+}
diff --git a/tools/pe_bliss/pe_resource_viewer.cpp b/tools/pe_bliss/pe_resource_viewer.cpp
new file mode 100644
index 0000000000..712cc28d9b
--- /dev/null
+++ b/tools/pe_bliss/pe_resource_viewer.cpp
@@ -0,0 +1,382 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include <algorithm>
+#include <cmath>
+#include "pe_resource_viewer.h"
+#include "pe_structures.h"
+
+namespace pe_bliss
+{
+using namespace pe_win;
+
+//Constructor from root resource_directory
+pe_resource_viewer::pe_resource_viewer(const resource_directory& root_directory)
+ :root_dir_(root_directory)
+{}
+
+const resource_directory& pe_resource_viewer::get_root_directory() const
+{
+ return root_dir_;
+}
+
+//Finder helpers
+bool pe_resource_viewer::has_name::operator()(const resource_directory_entry& entry) const
+{
+ return entry.is_named();
+}
+
+bool pe_resource_viewer::has_id::operator()(const resource_directory_entry& entry) const
+{
+ return !entry.is_named();
+}
+
+//Lists resource types existing in PE file (non-named only)
+const pe_resource_viewer::resource_type_list pe_resource_viewer::list_resource_types() const
+{
+ resource_type_list ret;
+
+ //Get root directory entries list
+ const resource_directory::entry_list& entries = root_dir_.get_entry_list();
+ for(resource_directory::entry_list::const_iterator it = entries.begin(); it != entries.end(); ++it)
+ {
+ //List all non-named items
+ if(!(*it).is_named())
+ ret.push_back((*it).get_id());
+ }
+
+ return ret;
+}
+
+//Returns true if resource type exists
+bool pe_resource_viewer::resource_exists(resource_type type) const
+{
+ const resource_directory::entry_list& entries = root_dir_.get_entry_list();
+ return std::find_if(entries.begin(), entries.end(), resource_directory::id_entry_finder(type)) != entries.end();
+}
+
+//Returns true if resource name exists
+bool pe_resource_viewer::resource_exists(const std::wstring& root_name) const
+{
+ const resource_directory::entry_list& entries = root_dir_.get_entry_list();
+ return std::find_if(entries.begin(), entries.end(), resource_directory::name_entry_finder(root_name)) != entries.end();
+}
+
+//Helper function to get name list from entry list
+const pe_resource_viewer::resource_name_list pe_resource_viewer::get_name_list(const resource_directory::entry_list& entries)
+{
+ resource_name_list ret;
+
+ for(resource_directory::entry_list::const_iterator it = entries.begin(); it != entries.end(); ++it)
+ {
+ //List all named items
+ if((*it).is_named())
+ ret.push_back((*it).get_name());
+ }
+
+ return ret;
+}
+
+//Helper function to get ID list from entry list
+const pe_resource_viewer::resource_id_list pe_resource_viewer::get_id_list(const resource_directory::entry_list& entries)
+{
+ resource_id_list ret;
+
+ for(resource_directory::entry_list::const_iterator it = entries.begin(); it != entries.end(); ++it)
+ {
+ //List all non-named items
+ if(!(*it).is_named())
+ ret.push_back((*it).get_id());
+ }
+
+ return ret;
+}
+
+//Lists resource names existing in PE file by resource type
+const pe_resource_viewer::resource_name_list pe_resource_viewer::list_resource_names(resource_type type) const
+{
+ return get_name_list(root_dir_.entry_by_id(type).get_resource_directory().get_entry_list());
+}
+
+//Lists resource names existing in PE file by resource name
+const pe_resource_viewer::resource_name_list pe_resource_viewer::list_resource_names(const std::wstring& root_name) const
+{
+ return get_name_list(root_dir_.entry_by_name(root_name).get_resource_directory().get_entry_list());
+}
+
+//Lists resource IDs existing in PE file by resource type
+const pe_resource_viewer::resource_id_list pe_resource_viewer::list_resource_ids(resource_type type) const
+{
+ return get_id_list(root_dir_.entry_by_id(type).get_resource_directory().get_entry_list());
+}
+
+//Lists resource IDs existing in PE file by resource name
+const pe_resource_viewer::resource_id_list pe_resource_viewer::list_resource_ids(const std::wstring& root_name) const
+{
+ return get_id_list(root_dir_.entry_by_name(root_name).get_resource_directory().get_entry_list());
+}
+
+//Returns resource count by type
+unsigned long pe_resource_viewer::get_resource_count(resource_type type) const
+{
+ return static_cast<unsigned long>(
+ root_dir_ //Type directory
+ .entry_by_id(type)
+ .get_resource_directory() //Name/ID directory
+ .get_entry_list()
+ .size());
+}
+
+//Returns resource count by name
+unsigned long pe_resource_viewer::get_resource_count(const std::wstring& root_name) const
+{
+ return static_cast<unsigned long>(
+ root_dir_ //Type directory
+ .entry_by_name(root_name)
+ .get_resource_directory() //Name/ID directory
+ .get_entry_list()
+ .size());
+}
+
+//Returns language count of resource by resource type and name
+unsigned long pe_resource_viewer::get_language_count(resource_type type, const std::wstring& name) const
+{
+ const resource_directory::entry_list& entries =
+ root_dir_ //Type directory
+ .entry_by_id(type)
+ .get_resource_directory() //Name/ID directory
+ .entry_by_name(name)
+ .get_resource_directory() //Language directory
+ .get_entry_list();
+
+ return static_cast<unsigned long>(std::count_if(entries.begin(), entries.end(), has_id()));
+}
+
+//Returns language count of resource by resource names
+unsigned long pe_resource_viewer::get_language_count(const std::wstring& root_name, const std::wstring& name) const
+{
+ const resource_directory::entry_list& entries =
+ root_dir_ //Type directory
+ .entry_by_name(root_name)
+ .get_resource_directory() //Name/ID directory
+ .entry_by_name(name)
+ .get_resource_directory() //Language directory
+ .get_entry_list();
+
+ return static_cast<unsigned long>(std::count_if(entries.begin(), entries.end(), has_id()));
+}
+
+//Returns language count of resource by resource type and ID
+unsigned long pe_resource_viewer::get_language_count(resource_type type, uint32_t id) const
+{
+ const resource_directory::entry_list& entries =
+ root_dir_ //Type directory
+ .entry_by_id(type)
+ .get_resource_directory() //Name/ID directory
+ .entry_by_id(id)
+ .get_resource_directory() //Language directory
+ .get_entry_list();
+
+ return static_cast<unsigned long>(std::count_if(entries.begin(), entries.end(), has_id()));
+}
+
+//Returns language count of resource by resource name and ID
+unsigned long pe_resource_viewer::get_language_count(const std::wstring& root_name, uint32_t id) const
+{
+ const resource_directory::entry_list& entries =
+ root_dir_ //Type directory
+ .entry_by_name(root_name)
+ .get_resource_directory() //Name/ID directory
+ .entry_by_id(id)
+ .get_resource_directory() //Language directory
+ .get_entry_list();
+
+ return static_cast<unsigned long>(std::count_if(entries.begin(), entries.end(), has_id()));
+}
+
+//Lists resource languages by resource type and name
+const pe_resource_viewer::resource_language_list pe_resource_viewer::list_resource_languages(resource_type type, const std::wstring& name) const
+{
+ const resource_directory::entry_list& entries =
+ root_dir_ //Type directory
+ .entry_by_id(type)
+ .get_resource_directory() //Name/ID directory
+ .entry_by_name(name)
+ .get_resource_directory() //Language directory
+ .get_entry_list();
+
+ return get_id_list(entries);
+}
+
+//Lists resource languages by resource names
+const pe_resource_viewer::resource_language_list pe_resource_viewer::list_resource_languages(const std::wstring& root_name, const std::wstring& name) const
+{
+ const resource_directory::entry_list& entries =
+ root_dir_ //Type directory
+ .entry_by_name(root_name)
+ .get_resource_directory() //Name/ID directory
+ .entry_by_name(name)
+ .get_resource_directory() //Language directory
+ .get_entry_list();
+
+ return get_id_list(entries);
+}
+
+//Lists resource languages by resource type and ID
+const pe_resource_viewer::resource_language_list pe_resource_viewer::list_resource_languages(resource_type type, uint32_t id) const
+{
+ const resource_directory::entry_list& entries =
+ root_dir_ //Type directory
+ .entry_by_id(type)
+ .get_resource_directory() //Name/ID directory
+ .entry_by_id(id)
+ .get_resource_directory() //Language directory
+ .get_entry_list();
+
+ return get_id_list(entries);
+}
+
+//Lists resource languages by resource name and ID
+const pe_resource_viewer::resource_language_list pe_resource_viewer::list_resource_languages(const std::wstring& root_name, uint32_t id) const
+{
+ const resource_directory::entry_list& entries =
+ root_dir_ //Type directory
+ .entry_by_name(root_name)
+ .get_resource_directory() //Name/ID directory
+ .entry_by_id(id)
+ .get_resource_directory() //Language directory
+ .get_entry_list();
+
+ return get_id_list(entries);
+}
+
+//Returns raw resource data by type, name and language
+const resource_data_info pe_resource_viewer::get_resource_data_by_name(uint32_t language, resource_type type, const std::wstring& name) const
+{
+ return resource_data_info(root_dir_ //Type directory
+ .entry_by_id(type)
+ .get_resource_directory() //Name/ID directory
+ .entry_by_name(name)
+ .get_resource_directory() //Language directory
+ .entry_by_id(language)
+ .get_data_entry()); //Data directory
+}
+
+//Returns raw resource data by root name, name and language
+const resource_data_info pe_resource_viewer::get_resource_data_by_name(uint32_t language, const std::wstring& root_name, const std::wstring& name) const
+{
+ return resource_data_info(root_dir_ //Type directory
+ .entry_by_name(root_name)
+ .get_resource_directory() //Name/ID directory
+ .entry_by_name(name)
+ .get_resource_directory() //Language directory
+ .entry_by_id(language)
+ .get_data_entry()); //Data directory
+}
+
+//Returns raw resource data by type, ID and language
+const resource_data_info pe_resource_viewer::get_resource_data_by_id(uint32_t language, resource_type type, uint32_t id) const
+{
+ return resource_data_info(root_dir_ //Type directory
+ .entry_by_id(type)
+ .get_resource_directory() //Name/ID directory
+ .entry_by_id(id)
+ .get_resource_directory() //Language directory
+ .entry_by_id(language)
+ .get_data_entry()); //Data directory
+}
+
+//Returns raw resource data by root name, ID and language
+const resource_data_info pe_resource_viewer::get_resource_data_by_id(uint32_t language, const std::wstring& root_name, uint32_t id) const
+{
+ return resource_data_info(root_dir_ //Type directory
+ .entry_by_name(root_name)
+ .get_resource_directory() //Name/ID directory
+ .entry_by_id(id)
+ .get_resource_directory() //Language directory
+ .entry_by_id(language)
+ .get_data_entry()); //Data directory
+}
+
+//Returns raw resource data by type, name and index in language directory (instead of language)
+const resource_data_info pe_resource_viewer::get_resource_data_by_name(resource_type type, const std::wstring& name, uint32_t index) const
+{
+ const resource_directory::entry_list& entries = root_dir_ //Type directory
+ .entry_by_id(type)
+ .get_resource_directory() //Name/ID directory
+ .entry_by_name(name)
+ .get_resource_directory() //Language directory
+ .get_entry_list();
+
+ if(entries.size() <= index)
+ throw pe_exception("Resource data entry not found", pe_exception::resource_data_entry_not_found);
+
+ return resource_data_info(entries.at(index).get_data_entry()); //Data directory
+}
+
+//Returns raw resource data by root name, name and index in language directory (instead of language)
+const resource_data_info pe_resource_viewer::get_resource_data_by_name(const std::wstring& root_name, const std::wstring& name, uint32_t index) const
+{
+ const resource_directory::entry_list& entries = root_dir_ //Type directory
+ .entry_by_name(root_name)
+ .get_resource_directory() //Name/ID directory
+ .entry_by_name(name)
+ .get_resource_directory() //Language directory
+ .get_entry_list();
+
+ if(entries.size() <= index)
+ throw pe_exception("Resource data entry not found", pe_exception::resource_data_entry_not_found);
+
+ return resource_data_info(entries.at(index).get_data_entry()); //Data directory
+}
+
+//Returns raw resource data by type, ID and index in language directory (instead of language)
+const resource_data_info pe_resource_viewer::get_resource_data_by_id(resource_type type, uint32_t id, uint32_t index) const
+{
+ const resource_directory::entry_list& entries = root_dir_ //Type directory
+ .entry_by_id(type)
+ .get_resource_directory() //Name/ID directory
+ .entry_by_id(id)
+ .get_resource_directory() //Language directory
+ .get_entry_list();
+
+ if(entries.size() <= index)
+ throw pe_exception("Resource data entry not found", pe_exception::resource_data_entry_not_found);
+
+ return resource_data_info(entries.at(index).get_data_entry()); //Data directory
+}
+
+//Returns raw resource data by root name, ID and index in language directory (instead of language)
+const resource_data_info pe_resource_viewer::get_resource_data_by_id(const std::wstring& root_name, uint32_t id, uint32_t index) const
+{
+ const resource_directory::entry_list& entries = root_dir_ //Type directory
+ .entry_by_name(root_name)
+ .get_resource_directory() //Name/ID directory
+ .entry_by_id(id)
+ .get_resource_directory() //Language directory
+ .get_entry_list();
+
+ if(entries.size() <= index)
+ throw pe_exception("Resource data entry not found", pe_exception::resource_data_entry_not_found);
+
+ return resource_data_info(entries.at(index).get_data_entry()); //Data directory
+}
+}
diff --git a/tools/pe_bliss/pe_resource_viewer.h b/tools/pe_bliss/pe_resource_viewer.h
new file mode 100644
index 0000000000..e585da6a87
--- /dev/null
+++ b/tools/pe_bliss/pe_resource_viewer.h
@@ -0,0 +1,153 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <map>
+#include <string>
+#include "pe_structures.h"
+#include "pe_resources.h"
+#include "message_table.h"
+#include "resource_data_info.h"
+
+namespace pe_bliss
+{
+ //PE resource manager allows to read resources from PE files
+class pe_resource_viewer
+{
+public:
+ //Resource type enumeration
+ enum resource_type
+ {
+ resource_cursor = 1,
+ resource_bitmap = 2,
+ resource_icon = 3,
+ resource_menu = 4,
+ resource_dialog = 5,
+ resource_string = 6,
+ resource_fontdir = 7,
+ resource_font = 8,
+ resource_accelerator = 9,
+ resource_rcdata = 10,
+ resource_message_table = 11,
+ resource_cursor_group = 12,
+ resource_icon_group = 14,
+ resource_version = 16,
+ resource_dlginclude = 17,
+ resource_plugplay = 19,
+ resource_vxd = 20,
+ resource_anicursor = 21,
+ resource_aniicon = 22,
+ resource_html = 23,
+ resource_manifest = 24
+ };
+
+public:
+ //Some useful typedefs
+ typedef std::vector<uint32_t> resource_type_list;
+ typedef std::vector<uint32_t> resource_id_list;
+ typedef std::vector<std::wstring> resource_name_list;
+ typedef std::vector<uint32_t> resource_language_list;
+
+public:
+ //Constructor from root resource_directory from PE file
+ explicit pe_resource_viewer(const resource_directory& root_directory);
+
+ const resource_directory& get_root_directory() const;
+
+ //Lists resource types existing in PE file (non-named only)
+ const resource_type_list list_resource_types() const;
+ //Returns true if resource type exists
+ bool resource_exists(resource_type type) const;
+ //Returns true if resource name exists
+ bool resource_exists(const std::wstring& root_name) const;
+
+ //Lists resource names existing in PE file by resource type
+ const resource_name_list list_resource_names(resource_type type) const;
+ //Lists resource names existing in PE file by resource name
+ const resource_name_list list_resource_names(const std::wstring& root_name) const;
+ //Lists resource IDs existing in PE file by resource type
+ const resource_id_list list_resource_ids(resource_type type) const;
+ //Lists resource IDs existing in PE file by resource name
+ const resource_id_list list_resource_ids(const std::wstring& root_name) const;
+ //Returns resource count by type
+ unsigned long get_resource_count(resource_type type) const;
+ //Returns resource count by name
+ unsigned long get_resource_count(const std::wstring& root_name) const;
+
+ //Returns language count of resource by resource type and name
+ unsigned long get_language_count(resource_type type, const std::wstring& name) const;
+ //Returns language count of resource by resource names
+ unsigned long get_language_count(const std::wstring& root_name, const std::wstring& name) const;
+ //Returns language count of resource by resource type and ID
+ unsigned long get_language_count(resource_type type, uint32_t id) const;
+ //Returns language count of resource by resource name and ID
+ unsigned long get_language_count(const std::wstring& root_name, uint32_t id) const;
+ //Lists resource languages by resource type and name
+ const resource_language_list list_resource_languages(resource_type type, const std::wstring& name) const;
+ //Lists resource languages by resource names
+ const resource_language_list list_resource_languages(const std::wstring& root_name, const std::wstring& name) const;
+ //Lists resource languages by resource type and ID
+ const resource_language_list list_resource_languages(resource_type type, uint32_t id) const;
+ //Lists resource languages by resource name and ID
+ const resource_language_list list_resource_languages(const std::wstring& root_name, uint32_t id) const;
+
+ //Returns raw resource data by type, name and language
+ const resource_data_info get_resource_data_by_name(uint32_t language, resource_type type, const std::wstring& name) const;
+ //Returns raw resource data by root name, name and language
+ const resource_data_info get_resource_data_by_name(uint32_t language, const std::wstring& root_name, const std::wstring& name) const;
+ //Returns raw resource data by type, ID and language
+ const resource_data_info get_resource_data_by_id(uint32_t language, resource_type type, uint32_t id) const;
+ //Returns raw resource data by root name, ID and language
+ const resource_data_info get_resource_data_by_id(uint32_t language, const std::wstring& root_name, uint32_t id) const;
+ //Returns raw resource data by type, name and index in language directory (instead of language)
+ const resource_data_info get_resource_data_by_name(resource_type type, const std::wstring& name, uint32_t index = 0) const;
+ //Returns raw resource data by root name, name and index in language directory (instead of language)
+ const resource_data_info get_resource_data_by_name(const std::wstring& root_name, const std::wstring& name, uint32_t index = 0) const;
+ //Returns raw resource data by type, ID and index in language directory (instead of language)
+ const resource_data_info get_resource_data_by_id(resource_type type, uint32_t id, uint32_t index = 0) const;
+ //Returns raw resource data by root name, ID and index in language directory (instead of language)
+ const resource_data_info get_resource_data_by_id(const std::wstring& root_name, uint32_t id, uint32_t index = 0) const;
+
+protected:
+ //Root resource directory. We're not copying it, because it might be heavy
+ const resource_directory& root_dir_;
+
+ //Helper function to get ID list from entry list
+ static const resource_id_list get_id_list(const resource_directory::entry_list& entries);
+ //Helper function to get name list from entry list
+ static const resource_name_list get_name_list(const resource_directory::entry_list& entries);
+
+protected:
+ //Helper structure - finder of resource_directory_entry that is named
+ struct has_name
+ {
+ public:
+ bool operator()(const resource_directory_entry& entry) const;
+ };
+
+ //Helper structure - finder of resource_directory_entry that is not named (has id)
+ struct has_id
+ {
+ public:
+ bool operator()(const resource_directory_entry& entry) const;
+ };
+};
+}
diff --git a/tools/pe_bliss/pe_resources.cpp b/tools/pe_bliss/pe_resources.cpp
new file mode 100644
index 0000000000..189aba1f76
--- /dev/null
+++ b/tools/pe_bliss/pe_resources.cpp
@@ -0,0 +1,726 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include <algorithm>
+#include <string.h>
+#include "pe_resources.h"
+
+namespace pe_bliss
+{
+using namespace pe_win;
+
+//RESOURCES
+//Default constructor
+resource_data_entry::resource_data_entry()
+ :codepage_(0)
+{}
+
+//Constructor from data
+resource_data_entry::resource_data_entry(const std::string& data, uint32_t codepage)
+ :codepage_(codepage), data_(data)
+{}
+
+//Returns resource data codepage
+uint32_t resource_data_entry::get_codepage() const
+{
+ return codepage_;
+}
+
+//Returns resource data
+const std::string& resource_data_entry::get_data() const
+{
+ return data_;
+}
+
+//Sets resource data codepage
+void resource_data_entry::set_codepage(uint32_t codepage)
+{
+ codepage_ = codepage;
+}
+
+//Sets resource data
+void resource_data_entry::set_data(const std::string& data)
+{
+ data_ = data;
+}
+
+//Default constructor
+resource_directory_entry::includes::includes()
+ :data_(0)
+{}
+
+//Default constructor
+resource_directory_entry::resource_directory_entry()
+ :id_(0), includes_data_(false), named_(false)
+{}
+
+//Copy constructor
+resource_directory_entry::resource_directory_entry(const resource_directory_entry& other)
+ :id_(other.id_), name_(other.name_), includes_data_(other.includes_data_), named_(other.named_)
+{
+ //If union'ed pointer is not zero
+ if(other.ptr_.data_)
+ {
+ if(other.includes_data())
+ ptr_.data_ = new resource_data_entry(*other.ptr_.data_);
+ else
+ ptr_.dir_ = new resource_directory(*other.ptr_.dir_);
+ }
+}
+
+//Copy assignment operator
+resource_directory_entry& resource_directory_entry::operator=(const resource_directory_entry& other)
+{
+ release();
+
+ id_ = other.id_;
+ name_ = other.name_;
+ includes_data_ = other.includes_data_;
+ named_ = other.named_;
+
+ //If other union'ed pointer is not zero
+ if(other.ptr_.data_)
+ {
+ if(other.includes_data())
+ ptr_.data_ = new resource_data_entry(*other.ptr_.data_);
+ else
+ ptr_.dir_ = new resource_directory(*other.ptr_.dir_);
+ }
+
+ return *this;
+}
+
+//Destroys included data
+void resource_directory_entry::release()
+{
+ //If union'ed pointer is not zero
+ if(ptr_.data_)
+ {
+ if(includes_data())
+ delete ptr_.data_;
+ else
+ delete ptr_.dir_;
+
+ ptr_.data_ = 0;
+ }
+}
+
+//Destructor
+resource_directory_entry::~resource_directory_entry()
+{
+ release();
+}
+
+//Returns entry ID
+uint32_t resource_directory_entry::get_id() const
+{
+ return id_;
+}
+
+//Returns entry name
+const std::wstring& resource_directory_entry::get_name() const
+{
+ return name_;
+}
+
+//Returns true, if entry has name
+//Returns false, if entry has ID
+bool resource_directory_entry::is_named() const
+{
+ return named_;
+}
+
+//Returns true, if entry includes resource_data_entry
+//Returns false, if entry includes resource_directory
+bool resource_directory_entry::includes_data() const
+{
+ return includes_data_;
+}
+
+//Returns resource_directory if entry includes it, otherwise throws an exception
+const resource_directory& resource_directory_entry::get_resource_directory() const
+{
+ if(!ptr_.dir_ || includes_data_)
+ throw pe_exception("Resource directory entry does not contain resource directory", pe_exception::resource_directory_entry_error);
+
+ return *ptr_.dir_;
+}
+
+//Returns resource_data_entry if entry includes it, otherwise throws an exception
+const resource_data_entry& resource_directory_entry::get_data_entry() const
+{
+ if(!ptr_.data_ || !includes_data_)
+ throw pe_exception("Resource directory entry does not contain resource data entry", pe_exception::resource_directory_entry_error);
+
+ return *ptr_.data_;
+}
+
+//Returns resource_directory if entry includes it, otherwise throws an exception
+resource_directory& resource_directory_entry::get_resource_directory()
+{
+ if(!ptr_.dir_ || includes_data_)
+ throw pe_exception("Resource directory entry does not contain resource directory", pe_exception::resource_directory_entry_error);
+
+ return *ptr_.dir_;
+}
+
+//Returns resource_data_entry if entry includes it, otherwise throws an exception
+resource_data_entry& resource_directory_entry::get_data_entry()
+{
+ if(!ptr_.data_ || !includes_data_)
+ throw pe_exception("Resource directory entry does not contain resource data entry", pe_exception::resource_directory_entry_error);
+
+ return *ptr_.data_;
+}
+
+//Sets entry name
+void resource_directory_entry::set_name(const std::wstring& name)
+{
+ name_ = name;
+ named_ = true;
+ id_ = 0;
+}
+
+//Sets entry ID
+void resource_directory_entry::set_id(uint32_t id)
+{
+ id_ = id;
+ named_ = false;
+ name_.clear();
+}
+
+//Adds resource_data_entry
+void resource_directory_entry::add_data_entry(const resource_data_entry& entry)
+{
+ release();
+ ptr_.data_ = new resource_data_entry(entry);
+ includes_data_ = true;
+}
+
+//Adds resource_directory
+void resource_directory_entry::add_resource_directory(const resource_directory& dir)
+{
+ release();
+ ptr_.dir_ = new resource_directory(dir);
+ includes_data_ = false;
+}
+
+//Default constructor
+resource_directory::resource_directory()
+ :characteristics_(0),
+ timestamp_(0),
+ major_version_(0), minor_version_(0),
+ number_of_named_entries_(0), number_of_id_entries_(0)
+{}
+
+//Constructor from data
+resource_directory::resource_directory(const image_resource_directory& dir)
+ :characteristics_(dir.Characteristics),
+ timestamp_(dir.TimeDateStamp),
+ major_version_(dir.MajorVersion), minor_version_(dir.MinorVersion),
+ number_of_named_entries_(0), number_of_id_entries_(0) //Set to zero here, calculate on add
+{}
+
+//Returns characteristics of directory
+uint32_t resource_directory::get_characteristics() const
+{
+ return characteristics_;
+}
+
+//Returns date and time stamp of directory
+uint32_t resource_directory::get_timestamp() const
+{
+ return timestamp_;
+}
+
+//Returns major version of directory
+uint16_t resource_directory::get_major_version() const
+{
+ return major_version_;
+}
+
+//Returns minor version of directory
+uint16_t resource_directory::get_minor_version() const
+{
+ return minor_version_;
+}
+
+//Returns number of named entries
+uint32_t resource_directory::get_number_of_named_entries() const
+{
+ return number_of_named_entries_;
+}
+
+//Returns number of ID entries
+uint32_t resource_directory::get_number_of_id_entries() const
+{
+ return number_of_id_entries_;
+}
+
+//Returns resource_directory_entry array
+const resource_directory::entry_list& resource_directory::get_entry_list() const
+{
+ return entries_;
+}
+
+//Returns resource_directory_entry array
+resource_directory::entry_list& resource_directory::get_entry_list()
+{
+ return entries_;
+}
+
+//Adds resource_directory_entry
+void resource_directory::add_resource_directory_entry(const resource_directory_entry& entry)
+{
+ entries_.push_back(entry);
+ if(entry.is_named())
+ ++number_of_named_entries_;
+ else
+ ++number_of_id_entries_;
+}
+
+//Clears resource_directory_entry array
+void resource_directory::clear_resource_directory_entry_list()
+{
+ entries_.clear();
+ number_of_named_entries_ = 0;
+ number_of_id_entries_ = 0;
+}
+
+//Sets characteristics of directory
+void resource_directory::set_characteristics(uint32_t characteristics)
+{
+ characteristics_ = characteristics;
+}
+
+//Sets date and time stamp of directory
+void resource_directory::set_timestamp(uint32_t timestamp)
+{
+ timestamp_ = timestamp;
+}
+
+//Sets number of named entries
+void resource_directory::set_number_of_named_entries(uint32_t number)
+{
+ number_of_named_entries_ = number;
+}
+
+//Sets number of ID entries
+void resource_directory::set_number_of_id_entries(uint32_t number)
+{
+ number_of_id_entries_ = number;
+}
+
+//Sets major version of directory
+void resource_directory::set_major_version(uint16_t major_version)
+{
+ major_version_ = major_version;
+}
+
+//Sets minor version of directory
+void resource_directory::get_minor_version(uint16_t minor_version)
+{
+ minor_version_ = minor_version;
+}
+
+//Processes resource directory
+const resource_directory process_resource_directory(const pe_base& pe, uint32_t res_rva, uint32_t offset_to_directory, std::set<uint32_t>& processed)
+{
+ resource_directory ret;
+
+ //Check for resource loops
+ if(!processed.insert(offset_to_directory).second)
+ throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory);
+
+ if(!pe_utils::is_sum_safe(res_rva, offset_to_directory))
+ throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory);
+
+ //Get root IMAGE_RESOURCE_DIRECTORY
+ image_resource_directory directory = pe.section_data_from_rva<image_resource_directory>(res_rva + offset_to_directory, section_data_virtual, true);
+
+ ret = resource_directory(directory);
+
+ //Check DWORDs for possible overflows
+ if(!pe_utils::is_sum_safe(directory.NumberOfIdEntries, directory.NumberOfNamedEntries)
+ || directory.NumberOfIdEntries + directory.NumberOfNamedEntries >= pe_utils::max_dword / sizeof(image_resource_directory_entry) + sizeof(image_resource_directory))
+ throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory);
+
+ if(!pe_utils::is_sum_safe(offset_to_directory, sizeof(image_resource_directory) + (directory.NumberOfIdEntries + directory.NumberOfNamedEntries) * sizeof(image_resource_directory_entry))
+ || !pe_utils::is_sum_safe(res_rva, offset_to_directory + sizeof(image_resource_directory) + (directory.NumberOfIdEntries + directory.NumberOfNamedEntries) * sizeof(image_resource_directory_entry)))
+ throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory);
+
+ for(unsigned long i = 0; i != static_cast<unsigned long>(directory.NumberOfIdEntries) + directory.NumberOfNamedEntries; ++i)
+ {
+ //Read directory entries one by one
+ image_resource_directory_entry dir_entry = pe.section_data_from_rva<image_resource_directory_entry>(
+ res_rva + sizeof(image_resource_directory) + i * sizeof(image_resource_directory_entry) + offset_to_directory, section_data_virtual, true);
+
+ //Create directory entry structure
+ resource_directory_entry entry;
+
+ //If directory is named
+ if(dir_entry.NameIsString)
+ {
+ if(!pe_utils::is_sum_safe(res_rva + sizeof(uint16_t) /* safe */, dir_entry.NameOffset))
+ throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory);
+
+ //get directory name length
+ uint16_t directory_name_length = pe.section_data_from_rva<uint16_t>(res_rva + dir_entry.NameOffset, section_data_virtual, true);
+
+ //Check name length
+ if(pe.section_data_length_from_rva(res_rva + dir_entry.NameOffset + sizeof(uint16_t), res_rva + dir_entry.NameOffset + sizeof(uint16_t), section_data_virtual, true)
+ < directory_name_length)
+ throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory);
+
+#ifdef PE_BLISS_WINDOWS
+ //Set entry UNICODE name
+ entry.set_name(std::wstring(
+ reinterpret_cast<const wchar_t*>(pe.section_data_from_rva(res_rva + dir_entry.NameOffset + sizeof(uint16_t), section_data_virtual, true)),
+ directory_name_length));
+#else
+ //Set entry UNICODE name
+ entry.set_name(pe_utils::from_ucs2(u16string(
+ reinterpret_cast<const unicode16_t*>(pe.section_data_from_rva(res_rva + dir_entry.NameOffset + sizeof(uint16_t), section_data_virtual, true)),
+ directory_name_length)));
+#endif
+ }
+ else
+ {
+ //Else - set directory ID
+ entry.set_id(dir_entry.Id);
+ }
+
+ //If directory entry has another resource directory
+ if(dir_entry.DataIsDirectory)
+ {
+ entry.add_resource_directory(process_resource_directory(pe, res_rva, dir_entry.OffsetToDirectory, processed));
+ }
+ else
+ {
+ //If directory entry has data
+ image_resource_data_entry data_entry = pe.section_data_from_rva<image_resource_data_entry>(
+ res_rva + dir_entry.OffsetToData, section_data_virtual, true);
+
+ //Check byte count that stated by data entry
+ if(pe.section_data_length_from_rva(data_entry.OffsetToData, data_entry.OffsetToData, section_data_virtual, true) < data_entry.Size)
+ throw pe_exception("Incorrect resource directory", pe_exception::incorrect_resource_directory);
+
+ //Add data entry to directory entry
+ entry.add_data_entry(resource_data_entry(
+ std::string(pe.section_data_from_rva(data_entry.OffsetToData, section_data_virtual, true), data_entry.Size),
+ data_entry.CodePage));
+ }
+
+ //Save directory entry
+ ret.add_resource_directory_entry(entry);
+ }
+
+ //Return resource directory
+ return ret;
+}
+
+//Helper function to calculate needed space for resource data
+void calculate_resource_data_space(const resource_directory& root, uint32_t aligned_offset_from_section_start, uint32_t& needed_size_for_structures, uint32_t& needed_size_for_strings)
+{
+ needed_size_for_structures += sizeof(image_resource_directory);
+ for(resource_directory::entry_list::const_iterator it = root.get_entry_list().begin(); it != root.get_entry_list().end(); ++it)
+ {
+ needed_size_for_structures += sizeof(image_resource_directory_entry);
+
+ if((*it).is_named())
+ needed_size_for_strings += static_cast<uint32_t>(((*it).get_name().length() + 1) * 2 /* unicode */ + sizeof(uint16_t) /* for string length */);
+
+ if(!(*it).includes_data())
+ calculate_resource_data_space((*it).get_resource_directory(), aligned_offset_from_section_start, needed_size_for_structures, needed_size_for_strings);
+ }
+}
+
+//Helper function to calculate needed space for resource data
+void calculate_resource_data_space(const resource_directory& root, uint32_t needed_size_for_structures, uint32_t needed_size_for_strings, uint32_t& needed_size_for_data, uint32_t& current_data_pos)
+{
+ for(resource_directory::entry_list::const_iterator it = root.get_entry_list().begin(); it != root.get_entry_list().end(); ++it)
+ {
+ if((*it).includes_data())
+ {
+ uint32_t data_size = static_cast<uint32_t>((*it).get_data_entry().get_data().length()
+ + sizeof(image_resource_data_entry)
+ + (pe_utils::align_up(current_data_pos, sizeof(uint32_t)) - current_data_pos) /* alignment */);
+ needed_size_for_data += data_size;
+ current_data_pos += data_size;
+ }
+ else
+ {
+ calculate_resource_data_space((*it).get_resource_directory(), needed_size_for_structures, needed_size_for_strings, needed_size_for_data, current_data_pos);
+ }
+ }
+}
+
+//Helper: sorts resource directory entries
+struct entry_sorter
+{
+public:
+ bool operator()(const resource_directory_entry& entry1, const resource_directory_entry& entry2) const;
+};
+
+//Helper function to rebuild resource directory
+void rebuild_resource_directory(pe_base& pe, section& resource_section, resource_directory& root, uint32_t& current_structures_pos, uint32_t& current_data_pos, uint32_t& current_strings_pos, uint32_t offset_from_section_start)
+{
+ //Create resource directory
+ image_resource_directory dir = {0};
+ dir.Characteristics = root.get_characteristics();
+ dir.MajorVersion = root.get_major_version();
+ dir.MinorVersion = root.get_minor_version();
+ dir.TimeDateStamp = root.get_timestamp();
+
+ {
+ resource_directory::entry_list& entries = root.get_entry_list();
+ std::sort(entries.begin(), entries.end(), entry_sorter());
+ }
+
+ //Calculate number of named and ID entries
+ for(resource_directory::entry_list::const_iterator it = root.get_entry_list().begin(); it != root.get_entry_list().end(); ++it)
+ {
+ if((*it).is_named())
+ ++dir.NumberOfNamedEntries;
+ else
+ ++dir.NumberOfIdEntries;
+ }
+
+ std::string& raw_data = resource_section.get_raw_data();
+
+ //Save resource directory
+ memcpy(&raw_data[current_structures_pos], &dir, sizeof(dir));
+ current_structures_pos += sizeof(dir);
+
+ uint32_t this_current_structures_pos = current_structures_pos;
+
+ current_structures_pos += sizeof(image_resource_directory_entry) * (dir.NumberOfNamedEntries + dir.NumberOfIdEntries);
+
+ //Create all resource directory entries
+ for(resource_directory::entry_list::iterator it = root.get_entry_list().begin(); it != root.get_entry_list().end(); ++it)
+ {
+ image_resource_directory_entry entry;
+ if((*it).is_named())
+ {
+ entry.Name = 0x80000000 | (current_strings_pos - offset_from_section_start);
+ uint16_t unicode_length = static_cast<uint16_t>((*it).get_name().length());
+ memcpy(&raw_data[current_strings_pos], &unicode_length, sizeof(unicode_length));
+ current_strings_pos += sizeof(unicode_length);
+
+#ifdef PE_BLISS_WINDOWS
+ memcpy(&raw_data[current_strings_pos], (*it).get_name().c_str(), (*it).get_name().length() * sizeof(uint16_t) + sizeof(uint16_t) /* unicode */);
+#else
+ {
+ u16string str(pe_utils::to_ucs2((*it).get_name()));
+ memcpy(&raw_data[current_strings_pos], str.c_str(), (*it).get_name().length() * sizeof(uint16_t) + sizeof(uint16_t) /* unicode */);
+ }
+#endif
+
+ current_strings_pos += static_cast<unsigned long>((*it).get_name().length() * sizeof(uint16_t) + sizeof(uint16_t) /* unicode */);
+ }
+ else
+ {
+ entry.Name = (*it).get_id();
+ }
+
+ if((*it).includes_data())
+ {
+ current_data_pos = pe_utils::align_up(current_data_pos, sizeof(uint32_t));
+ image_resource_data_entry data_entry = {0};
+ data_entry.CodePage = (*it).get_data_entry().get_codepage();
+ data_entry.Size = static_cast<uint32_t>((*it).get_data_entry().get_data().length());
+ data_entry.OffsetToData = pe.rva_from_section_offset(resource_section, current_data_pos + sizeof(data_entry));
+
+ entry.OffsetToData = current_data_pos - offset_from_section_start;
+
+ memcpy(&raw_data[current_data_pos], &data_entry, sizeof(data_entry));
+ current_data_pos += sizeof(data_entry);
+
+ memcpy(&raw_data[current_data_pos], (*it).get_data_entry().get_data().data(), data_entry.Size);
+ current_data_pos += data_entry.Size;
+
+ memcpy(&raw_data[this_current_structures_pos], &entry, sizeof(entry));
+ this_current_structures_pos += sizeof(entry);
+ }
+ else
+ {
+ entry.OffsetToData = 0x80000000 | (current_structures_pos - offset_from_section_start);
+
+ memcpy(&raw_data[this_current_structures_pos], &entry, sizeof(entry));
+ this_current_structures_pos += sizeof(entry);
+
+ rebuild_resource_directory(pe, resource_section, (*it).get_resource_directory(), current_structures_pos, current_data_pos, current_strings_pos, offset_from_section_start);
+ }
+ }
+}
+
+//Helper function to rebuild resource directory
+bool entry_sorter::operator()(const resource_directory_entry& entry1, const resource_directory_entry& entry2) const
+{
+ if(entry1.is_named() && entry2.is_named())
+ return entry1.get_name() < entry2.get_name();
+ else if(!entry1.is_named() && !entry2.is_named())
+ return entry1.get_id() < entry2.get_id();
+ else
+ return entry1.is_named();
+}
+
+//Resources rebuilder
+//resource_directory - root resource directory
+//resources_section - section where resource directory will be placed (must be attached to PE image)
+//offset_from_section_start - offset from resources_section raw data start
+//resource_directory is non-constant, because it will be sorted
+//save_to_pe_headers - if true, new resource directory information will be saved to PE image headers
+//auto_strip_last_section - if true and resources are placed in the last section, it will be automatically stripped
+//number_of_id_entries and number_of_named_entries for resource directories are recalculated and not used
+const image_directory rebuild_resources(pe_base& pe, resource_directory& info, section& resources_section, uint32_t offset_from_section_start, bool save_to_pe_header, bool auto_strip_last_section)
+{
+ //Check that resources_section is attached to this PE image
+ if(!pe.section_attached(resources_section))
+ throw pe_exception("Resource section must be attached to PE file", pe_exception::section_is_not_attached);
+
+ //Check resource directory correctness
+ if(info.get_entry_list().empty())
+ throw pe_exception("Empty resource directory", pe_exception::incorrect_resource_directory);
+
+ uint32_t aligned_offset_from_section_start = pe_utils::align_up(offset_from_section_start, sizeof(uint32_t));
+ uint32_t needed_size_for_structures = aligned_offset_from_section_start - offset_from_section_start; //Calculate needed size for resource tables and data
+ uint32_t needed_size_for_strings = 0;
+ uint32_t needed_size_for_data = 0;
+
+ calculate_resource_data_space(info, aligned_offset_from_section_start, needed_size_for_structures, needed_size_for_strings);
+
+ {
+ uint32_t current_data_pos = aligned_offset_from_section_start + needed_size_for_structures + needed_size_for_strings;
+ calculate_resource_data_space(info, needed_size_for_structures, needed_size_for_strings, needed_size_for_data, current_data_pos);
+ }
+
+ uint32_t needed_size = needed_size_for_structures + needed_size_for_strings + needed_size_for_data;
+
+ //Check if resources_section is last one. If it's not, check if there's enough place for resource data
+ if(&resources_section != &*(pe.get_image_sections().end() - 1) &&
+ (resources_section.empty() || pe_utils::align_up(resources_section.get_size_of_raw_data(), pe.get_file_alignment())
+ < needed_size + aligned_offset_from_section_start))
+ throw pe_exception("Insufficient space for resource directory", pe_exception::insufficient_space);
+
+ std::string& raw_data = resources_section.get_raw_data();
+
+ //This will be done only if resources_section is the last section of image or for section with unaligned raw length of data
+ if(raw_data.length() < needed_size + aligned_offset_from_section_start)
+ raw_data.resize(needed_size + aligned_offset_from_section_start); //Expand section raw data
+
+ uint32_t current_structures_pos = aligned_offset_from_section_start;
+ uint32_t current_strings_pos = current_structures_pos + needed_size_for_structures;
+ uint32_t current_data_pos = current_strings_pos + needed_size_for_strings;
+ rebuild_resource_directory(pe, resources_section, info, current_structures_pos, current_data_pos, current_strings_pos, aligned_offset_from_section_start);
+
+ //Adjust section raw and virtual sizes
+ pe.recalculate_section_sizes(resources_section, auto_strip_last_section);
+
+ image_directory ret(pe.rva_from_section_offset(resources_section, aligned_offset_from_section_start), needed_size);
+
+ //If auto-rewrite of PE headers is required
+ if(save_to_pe_header)
+ {
+ pe.set_directory_rva(image_directory_entry_resource, ret.get_rva());
+ pe.set_directory_size(image_directory_entry_resource, ret.get_size());
+ }
+
+ return ret;
+}
+
+//Returns resources from PE file
+const resource_directory get_resources(const pe_base& pe)
+{
+ resource_directory ret;
+
+ if(!pe.has_resources())
+ return ret;
+
+ //Get resource directory RVA
+ uint32_t res_rva = pe.get_directory_rva(image_directory_entry_resource);
+
+ //Store already processed directories to avoid resource loops
+ std::set<uint32_t> processed;
+
+ //Process all directories (recursion)
+ ret = process_resource_directory(pe, res_rva, 0, processed);
+
+ return ret;
+}
+
+//Finds resource_directory_entry by ID
+resource_directory::id_entry_finder::id_entry_finder(uint32_t id)
+ :id_(id)
+{}
+
+bool resource_directory::id_entry_finder::operator()(const resource_directory_entry& entry) const
+{
+ return !entry.is_named() && entry.get_id() == id_;
+}
+
+//Finds resource_directory_entry by name
+resource_directory::name_entry_finder::name_entry_finder(const std::wstring& name)
+ :name_(name)
+{}
+
+bool resource_directory::name_entry_finder::operator()(const resource_directory_entry& entry) const
+{
+ return entry.is_named() && entry.get_name() == name_;
+}
+
+//Finds resource_directory_entry by name or ID (universal)
+resource_directory::entry_finder::entry_finder(const std::wstring& name)
+ :name_(name), named_(true)
+{}
+
+resource_directory::entry_finder::entry_finder(uint32_t id)
+ :id_(id), named_(false)
+{}
+
+bool resource_directory::entry_finder::operator()(const resource_directory_entry& entry) const
+{
+ if(named_)
+ return entry.is_named() && entry.get_name() == name_;
+ else
+ return !entry.is_named() && entry.get_id() == id_;
+}
+
+//Returns resource_directory_entry by ID. If not found - throws an exception
+const resource_directory_entry& resource_directory::entry_by_id(uint32_t id) const
+{
+ entry_list::const_iterator i = std::find_if(entries_.begin(), entries_.end(), id_entry_finder(id));
+ if(i == entries_.end())
+ throw pe_exception("Resource directory entry not found", pe_exception::resource_directory_entry_not_found);
+
+ return *i;
+}
+
+//Returns resource_directory_entry by name. If not found - throws an exception
+const resource_directory_entry& resource_directory::entry_by_name(const std::wstring& name) const
+{
+ entry_list::const_iterator i = std::find_if(entries_.begin(), entries_.end(), name_entry_finder(name));
+ if(i == entries_.end())
+ throw pe_exception("Resource directory entry not found", pe_exception::resource_directory_entry_not_found);
+
+ return *i;
+}
+}
diff --git a/tools/pe_bliss/pe_resources.h b/tools/pe_bliss/pe_resources.h
new file mode 100644
index 0000000000..1eb6437563
--- /dev/null
+++ b/tools/pe_bliss/pe_resources.h
@@ -0,0 +1,245 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <vector>
+#include <string>
+#include <set>
+#include "pe_structures.h"
+#include "pe_base.h"
+#include "pe_directory.h"
+
+namespace pe_bliss
+{
+//Class representing resource data entry
+class resource_data_entry
+{
+public:
+ //Default constructor
+ resource_data_entry();
+ //Constructor from data
+ resource_data_entry(const std::string& data, uint32_t codepage);
+
+ //Returns resource data codepage
+ uint32_t get_codepage() const;
+ //Returns resource data
+ const std::string& get_data() const;
+
+public: //These functions do not change everything inside image, they are used by PE class
+ //You can also use them to rebuild resource directory
+
+ //Sets resource data codepage
+ void set_codepage(uint32_t codepage);
+ //Sets resource data
+ void set_data(const std::string& data);
+
+private:
+ uint32_t codepage_; //Resource data codepage
+ std::string data_; //Resource data
+};
+
+//Forward declaration
+class resource_directory;
+
+//Class representing resource directory entry
+class resource_directory_entry
+{
+public:
+ //Default constructor
+ resource_directory_entry();
+ //Copy constructor
+ resource_directory_entry(const resource_directory_entry& other);
+ //Copy assignment operator
+ resource_directory_entry& operator=(const resource_directory_entry& other);
+
+ //Returns entry ID
+ uint32_t get_id() const;
+ //Returns entry name
+ const std::wstring& get_name() const;
+ //Returns true, if entry has name
+ //Returns false, if entry has ID
+ bool is_named() const;
+
+ //Returns true, if entry includes resource_data_entry
+ //Returns false, if entry includes resource_directory
+ bool includes_data() const;
+ //Returns resource_directory if entry includes it, otherwise throws an exception
+ const resource_directory& get_resource_directory() const;
+ //Returns resource_data_entry if entry includes it, otherwise throws an exception
+ const resource_data_entry& get_data_entry() const;
+
+ //Destructor
+ ~resource_directory_entry();
+
+public: //These functions do not change everything inside image, they are used by PE class
+ //You can also use them to rebuild resource directory
+
+ //Sets entry name
+ void set_name(const std::wstring& name);
+ //Sets entry ID
+ void set_id(uint32_t id);
+
+ //Returns resource_directory if entry includes it, otherwise throws an exception
+ resource_directory& get_resource_directory();
+ //Returns resource_data_entry if entry includes it, otherwise throws an exception
+ resource_data_entry& get_data_entry();
+
+ //Adds resource_data_entry
+ void add_data_entry(const resource_data_entry& entry);
+ //Adds resource_directory
+ void add_resource_directory(const resource_directory& dir);
+
+private:
+ //Destroys included data
+ void release();
+
+private:
+ uint32_t id_;
+ std::wstring name_;
+
+ union includes
+ {
+ //Default constructor
+ includes();
+
+ //We use pointers, we're doing manual copying here
+ class resource_data_entry* data_;
+ class resource_directory* dir_; //We use pointer, because structs include each other
+ };
+
+ includes ptr_;
+
+ bool includes_data_, named_;
+};
+
+//Class representing resource directory
+class resource_directory
+{
+public:
+ typedef std::vector<resource_directory_entry> entry_list;
+
+public:
+ //Default constructor
+ resource_directory();
+ //Constructor from data
+ explicit resource_directory(const pe_win::image_resource_directory& dir);
+
+ //Returns characteristics of directory
+ uint32_t get_characteristics() const;
+ //Returns date and time stamp of directory
+ uint32_t get_timestamp() const;
+ //Returns number of named entries
+ uint32_t get_number_of_named_entries() const;
+ //Returns number of ID entries
+ uint32_t get_number_of_id_entries() const;
+ //Returns major version of directory
+ uint16_t get_major_version() const;
+ //Returns minor version of directory
+ uint16_t get_minor_version() const;
+ //Returns resource_directory_entry array
+ const entry_list& get_entry_list() const;
+ //Returns resource_directory_entry by ID. If not found - throws an exception
+ const resource_directory_entry& entry_by_id(uint32_t id) const;
+ //Returns resource_directory_entry by name. If not found - throws an exception
+ const resource_directory_entry& entry_by_name(const std::wstring& name) const;
+
+public: //These functions do not change everything inside image, they are used by PE class
+ //You can also use them to rebuild resource directory
+
+ //Adds resource_directory_entry
+ void add_resource_directory_entry(const resource_directory_entry& entry);
+ //Clears resource_directory_entry array
+ void clear_resource_directory_entry_list();
+
+ //Sets characteristics of directory
+ void set_characteristics(uint32_t characteristics);
+ //Sets date and time stamp of directory
+ void set_timestamp(uint32_t timestamp);
+ //Sets number of named entries
+ void set_number_of_named_entries(uint32_t number);
+ //Sets number of ID entries
+ void set_number_of_id_entries(uint32_t number);
+ //Sets major version of directory
+ void set_major_version(uint16_t major_version);
+ //Sets minor version of directory
+ void get_minor_version(uint16_t minor_version);
+
+ //Returns resource_directory_entry array
+ entry_list& get_entry_list();
+
+private:
+ uint32_t characteristics_;
+ uint32_t timestamp_;
+ uint16_t major_version_, minor_version_;
+ uint32_t number_of_named_entries_, number_of_id_entries_;
+ entry_list entries_;
+
+public: //Finder helpers
+ //Finds resource_directory_entry by ID
+ struct id_entry_finder
+ {
+ public:
+ explicit id_entry_finder(uint32_t id);
+ bool operator()(const resource_directory_entry& entry) const;
+
+ private:
+ uint32_t id_;
+ };
+
+ //Finds resource_directory_entry by name
+ struct name_entry_finder
+ {
+ public:
+ explicit name_entry_finder(const std::wstring& name);
+ bool operator()(const resource_directory_entry& entry) const;
+
+ private:
+ std::wstring name_;
+ };
+
+ //Finds resource_directory_entry by name or ID (universal)
+ struct entry_finder
+ {
+ public:
+ explicit entry_finder(const std::wstring& name);
+ explicit entry_finder(uint32_t id);
+ bool operator()(const resource_directory_entry& entry) const;
+
+ private:
+ std::wstring name_;
+ uint32_t id_;
+ bool named_;
+ };
+};
+
+//Returns resources (root resource_directory) from PE file
+const resource_directory get_resources(const pe_base& pe);
+
+//Resources rebuilder
+//resource_directory - root resource directory
+//resources_section - section where resource directory will be placed (must be attached to PE image)
+//resource_directory is non-constant, because it will be sorted
+//offset_from_section_start - offset from resources_section raw data start
+//save_to_pe_headers - if true, new resource directory information will be saved to PE image headers
+//auto_strip_last_section - if true and resources are placed in the last section, it will be automatically stripped
+//number_of_id_entries and number_of_named_entries for resource directories are recalculated and not used
+const image_directory rebuild_resources(pe_base& pe, resource_directory& info, section& resources_section, uint32_t offset_from_section_start = 0, bool save_to_pe_header = true, bool auto_strip_last_section = true);
+}
diff --git a/tools/pe_bliss/pe_rich_data.cpp b/tools/pe_bliss/pe_rich_data.cpp
new file mode 100644
index 0000000000..e92f7ddc1b
--- /dev/null
+++ b/tools/pe_bliss/pe_rich_data.cpp
@@ -0,0 +1,152 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include "pe_rich_data.h"
+
+namespace pe_bliss
+{
+//STUB OVERLAY
+//Default constructor
+rich_data::rich_data()
+ :number_(0), version_(0), times_(0)
+{}
+
+//Who knows, what these fields mean...
+uint32_t rich_data::get_number() const
+{
+ return number_;
+}
+
+uint32_t rich_data::get_version() const
+{
+ return version_;
+}
+
+uint32_t rich_data::get_times() const
+{
+ return times_;
+}
+
+void rich_data::set_number(uint32_t number)
+{
+ number_ = number;
+}
+
+void rich_data::set_version(uint32_t version)
+{
+ version_ = version;
+}
+
+void rich_data::set_times(uint32_t times)
+{
+ times_ = times;
+}
+
+//Returns MSVC rich data
+const rich_data_list get_rich_data(const pe_base& pe)
+{
+ //Returned value
+ rich_data_list ret;
+
+ const std::string& rich_overlay = pe.get_stub_overlay();
+
+ //If there's no rich overlay, return empty vector
+ if(rich_overlay.size() < sizeof(uint32_t))
+ return ret;
+
+ //True if rich data was found
+ bool found = false;
+
+ //Rich overlay ID ("Rich" word)
+ static const uint32_t rich_overlay_id = 0x68636952;
+
+ //Search for rich data overlay ID
+ const char* begin = &rich_overlay[0];
+ const char* end = begin + rich_overlay.length();
+ for(; begin != end; ++begin)
+ {
+ if(*reinterpret_cast<const uint32_t*>(begin) == rich_overlay_id)
+ {
+ found = true; //We've found it!
+ break;
+ }
+ }
+
+ //If we found it
+ if(found)
+ {
+ //Check remaining length
+ if(static_cast<size_t>(end - begin) < sizeof(uint32_t))
+ return ret;
+
+ //The XOR key is after "Rich" word, we should get it
+ uint32_t xorkey = *reinterpret_cast<const uint32_t*>(begin + sizeof(uint32_t));
+
+ //True if rich data was found
+ found = false;
+
+ //Second search for signature "DanS"
+ begin = &rich_overlay[0];
+ for(; begin != end; ++begin)
+ {
+ if((*reinterpret_cast<const uint32_t*>(begin) ^ xorkey) == 0x536e6144) //"DanS"
+ {
+ found = true;
+ break;
+ }
+ }
+
+ //If second signature is found
+ if(found)
+ {
+ begin += sizeof(uint32_t) * 3;
+ //List all rich data structures
+ while(begin < end)
+ {
+ begin += sizeof(uint32_t);
+ if(begin >= end)
+ break;
+
+ //Check for rich overlay data end ("Rich" word reached)
+ if(*reinterpret_cast<const uint32_t*>(begin) == rich_overlay_id)
+ break;
+
+ //Create rich_data structure
+ rich_data data;
+ data.set_number((*reinterpret_cast<const uint32_t*>(begin) ^ xorkey) >> 16);
+ data.set_version((*reinterpret_cast<const uint32_t*>(begin) ^ xorkey) & 0xFFFF);
+
+ begin += sizeof(uint32_t);
+ if(begin >= end)
+ break;
+
+ data.set_times(*reinterpret_cast<const uint32_t*>(begin) ^ xorkey);
+
+ //Save rich data structure
+ ret.push_back(data);
+ }
+ }
+ }
+
+ //Return rich data structures list
+ return ret;
+}
+}
diff --git a/tools/pe_bliss/pe_rich_data.h b/tools/pe_bliss/pe_rich_data.h
new file mode 100644
index 0000000000..3e01d3c011
--- /dev/null
+++ b/tools/pe_bliss/pe_rich_data.h
@@ -0,0 +1,58 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <vector>
+#include "pe_structures.h"
+#include "pe_base.h"
+
+namespace pe_bliss
+{
+//Rich data overlay class of Microsoft Visual Studio
+class rich_data
+{
+public:
+ //Default constructor
+ rich_data();
+
+public: //Getters
+ //Who knows, what these fields mean...
+ uint32_t get_number() const;
+ uint32_t get_version() const;
+ uint32_t get_times() const;
+
+public: //Setters, used by PE library only
+ void set_number(uint32_t number);
+ void set_version(uint32_t version);
+ void set_times(uint32_t times);
+
+private:
+ uint32_t number_;
+ uint32_t version_;
+ uint32_t times_;
+};
+
+//Rich data list typedef
+typedef std::vector<rich_data> rich_data_list;
+
+//Returns a vector with rich data (stub overlay)
+const rich_data_list get_rich_data(const pe_base& pe);
+}
diff --git a/tools/pe_bliss/pe_section.cpp b/tools/pe_bliss/pe_section.cpp
new file mode 100644
index 0000000000..72127e22e2
--- /dev/null
+++ b/tools/pe_bliss/pe_section.cpp
@@ -0,0 +1,303 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include <algorithm>
+#include <string.h>
+#include "utils.h"
+#include "pe_section.h"
+
+namespace pe_bliss
+{
+using namespace pe_win;
+
+//Section structure default constructor
+section::section()
+ :old_size_(static_cast<size_t>(-1))
+{
+ memset(&header_, 0, sizeof(image_section_header));
+}
+
+//Sets the name of section (8 characters maximum)
+void section::set_name(const std::string& name)
+{
+ memset(header_.Name, 0, sizeof(header_.Name));
+ memcpy(header_.Name, name.c_str(), std::min<size_t>(name.length(), sizeof(header_.Name)));
+}
+
+//Returns section name
+const std::string section::get_name() const
+{
+ char buf[9] = {0};
+ memcpy(buf, header_.Name, 8);
+ return std::string(buf);
+}
+
+//Set flag (attribute) of section
+section& section::set_flag(uint32_t flag, bool setflag)
+{
+ if(setflag)
+ header_.Characteristics |= flag;
+ else
+ header_.Characteristics &= ~flag;
+
+ return *this;
+}
+
+//Sets "readable" attribute of section
+section& section::readable(bool readable)
+{
+ return set_flag(image_scn_mem_read, readable);
+}
+
+//Sets "writeable" attribute of section
+section& section::writeable(bool writeable)
+{
+ return set_flag(image_scn_mem_write, writeable);
+}
+
+//Sets "executable" attribute of section
+section& section::executable(bool executable)
+{
+ return set_flag(image_scn_mem_execute, executable);
+}
+
+//Sets "shared" attribute of section
+section& section::shared(bool shared)
+{
+ return set_flag(image_scn_mem_shared, shared);
+}
+
+//Sets "discardable" attribute of section
+section& section::discardable(bool discardable)
+{
+ return set_flag(image_scn_mem_discardable, discardable);
+}
+
+//Returns true if section is readable
+bool section::readable() const
+{
+ return (header_.Characteristics & image_scn_mem_read) != 0;
+}
+
+//Returns true if section is writeable
+bool section::writeable() const
+{
+ return (header_.Characteristics & image_scn_mem_write) != 0;
+}
+
+//Returns true if section is executable
+bool section::executable() const
+{
+ return (header_.Characteristics & image_scn_mem_execute) != 0;
+}
+
+bool section::shared() const
+{
+ return (header_.Characteristics & image_scn_mem_shared) != 0;
+}
+
+bool section::discardable() const
+{
+ return (header_.Characteristics & image_scn_mem_discardable) != 0;
+}
+
+//Returns true if section has no RAW data
+bool section::empty() const
+{
+ if(old_size_ != static_cast<size_t>(-1)) //If virtual memory is mapped, check raw data length (old_size_)
+ return old_size_ == 0;
+ else
+ return raw_data_.empty();
+}
+
+//Returns raw section data from file image
+std::string& section::get_raw_data()
+{
+ unmap_virtual();
+ return raw_data_;
+}
+
+//Sets raw section data from file image
+void section::set_raw_data(const std::string& data)
+{
+ old_size_ = static_cast<size_t>(-1);
+ raw_data_ = data;
+}
+
+//Returns raw section data from file image
+const std::string& section::get_raw_data() const
+{
+ unmap_virtual();
+ return raw_data_;
+}
+
+//Returns mapped virtual section data
+const std::string& section::get_virtual_data(uint32_t section_alignment) const
+{
+ map_virtual(section_alignment);
+ return raw_data_;
+}
+
+//Returns mapped virtual section data
+std::string& section::get_virtual_data(uint32_t section_alignment)
+{
+ map_virtual(section_alignment);
+ return raw_data_;
+}
+
+//Maps virtual section data
+void section::map_virtual(uint32_t section_alignment) const
+{
+ uint32_t aligned_virtual_size = get_aligned_virtual_size(section_alignment);
+ if(old_size_ == static_cast<size_t>(-1) && aligned_virtual_size && aligned_virtual_size > raw_data_.length())
+ {
+ old_size_ = raw_data_.length();
+ raw_data_.resize(aligned_virtual_size, 0);
+ }
+}
+
+//Unmaps virtual section data
+void section::unmap_virtual() const
+{
+ if(old_size_ != static_cast<size_t>(-1))
+ {
+ raw_data_.resize(old_size_, 0);
+ old_size_ = static_cast<size_t>(-1);
+ }
+}
+
+//Returns section virtual size
+uint32_t section::get_virtual_size() const
+{
+ return header_.Misc.VirtualSize;
+}
+
+//Returns section virtual address
+uint32_t section::get_virtual_address() const
+{
+ return header_.VirtualAddress;
+}
+
+//Returns size of section raw data
+uint32_t section::get_size_of_raw_data() const
+{
+ return header_.SizeOfRawData;
+}
+
+//Returns pointer to raw section data in PE file
+uint32_t section::get_pointer_to_raw_data() const
+{
+ return header_.PointerToRawData;
+}
+
+//Returns section characteristics
+uint32_t section::get_characteristics() const
+{
+ return header_.Characteristics;
+}
+
+//Returns raw image section header
+const pe_win::image_section_header& section::get_raw_header() const
+{
+ return header_;
+}
+
+//Returns raw image section header
+pe_win::image_section_header& section::get_raw_header()
+{
+ return header_;
+}
+
+//Calculates aligned virtual section size
+uint32_t section::get_aligned_virtual_size(uint32_t section_alignment) const
+{
+ if(get_size_of_raw_data())
+ {
+ if(!get_virtual_size())
+ {
+ //If section virtual size is zero
+ //Set aligned virtual size of section as aligned raw size
+ return pe_utils::align_up(get_size_of_raw_data(), section_alignment);
+ }
+ }
+
+ return pe_utils::align_up(get_virtual_size(), section_alignment);
+}
+
+//Calculates aligned raw section size
+uint32_t section::get_aligned_raw_size(uint32_t file_alignment) const
+{
+ if(get_size_of_raw_data())
+ return pe_utils::align_up(get_size_of_raw_data(), file_alignment);
+ else
+ return 0;
+}
+
+//Sets size of raw section data
+void section::set_size_of_raw_data(uint32_t size_of_raw_data)
+{
+ header_.SizeOfRawData = size_of_raw_data;
+}
+
+//Sets pointer to section raw data
+void section::set_pointer_to_raw_data(uint32_t pointer_to_raw_data)
+{
+ header_.PointerToRawData = pointer_to_raw_data;
+}
+
+//Sets section characteristics
+void section::set_characteristics(uint32_t characteristics)
+{
+ header_.Characteristics = characteristics;
+}
+
+//Sets section virtual size
+void section::set_virtual_size(uint32_t virtual_size)
+{
+ header_.Misc.VirtualSize = virtual_size;
+}
+
+//Sets section virtual address
+void section::set_virtual_address(uint32_t virtual_address)
+{
+ header_.VirtualAddress = virtual_address;
+}
+
+//Section by file offset finder helper (4gb max)
+section_by_raw_offset::section_by_raw_offset(uint32_t offset)
+ :offset_(offset)
+{}
+
+bool section_by_raw_offset::operator()(const section& s) const
+{
+ return (s.get_pointer_to_raw_data() <= offset_)
+ && (s.get_pointer_to_raw_data() + s.get_size_of_raw_data() > offset_);
+}
+
+section_ptr_finder::section_ptr_finder(const section& s)
+ :s_(s)
+{}
+
+bool section_ptr_finder::operator()(const section& s) const
+{
+ return &s == &s_;
+}
+}
diff --git a/tools/pe_bliss/pe_section.h b/tools/pe_bliss/pe_section.h
new file mode 100644
index 0000000000..617ecebe26
--- /dev/null
+++ b/tools/pe_bliss/pe_section.h
@@ -0,0 +1,158 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <string>
+#include <vector>
+#include "pe_structures.h"
+
+namespace pe_bliss
+{
+//Enumeration of section data types, used in functions below
+enum section_data_type
+{
+ section_data_raw,
+ section_data_virtual
+};
+
+//Class representing image section
+class section
+{
+public:
+ //Default constructor
+ section();
+
+ //Sets the name of section (stripped to 8 characters)
+ void set_name(const std::string& name);
+
+ //Returns the name of section
+ const std::string get_name() const;
+
+ //Changes attributes of section
+ section& readable(bool readable);
+ section& writeable(bool writeable);
+ section& executable(bool executable);
+ section& shared(bool shared);
+ section& discardable(bool discardable);
+
+ //Returns attributes of section
+ bool readable() const;
+ bool writeable() const;
+ bool executable() const;
+ bool shared() const;
+ bool discardable() const;
+
+ //Returns true if section has no RAW data
+ bool empty() const;
+
+ //Returns raw section data from file image
+ std::string& get_raw_data();
+ //Returns raw section data from file image
+ const std::string& get_raw_data() const;
+ //Returns mapped virtual section data
+ const std::string& get_virtual_data(uint32_t section_alignment) const;
+ //Returns mapped virtual section data
+ std::string& get_virtual_data(uint32_t section_alignment);
+
+public: //Header getters
+ //Returns section virtual size
+ uint32_t get_virtual_size() const;
+ //Returns section virtual address (RVA)
+ uint32_t get_virtual_address() const;
+ //Returns size of section raw data
+ uint32_t get_size_of_raw_data() const;
+ //Returns pointer to raw section data in PE file
+ uint32_t get_pointer_to_raw_data() const;
+ //Returns section characteristics
+ uint32_t get_characteristics() const;
+
+ //Returns raw image section header
+ const pe_win::image_section_header& get_raw_header() const;
+
+public: //Aligned sizes calculation
+ //Calculates aligned virtual section size
+ uint32_t get_aligned_virtual_size(uint32_t section_alignment) const;
+ //Calculates aligned raw section size
+ uint32_t get_aligned_raw_size(uint32_t file_alignment) const;
+
+public: //Setters
+ //Sets size of raw section data
+ void set_size_of_raw_data(uint32_t size_of_raw_data);
+ //Sets pointer to section raw data
+ void set_pointer_to_raw_data(uint32_t pointer_to_raw_data);
+ //Sets section characteristics
+ void set_characteristics(uint32_t characteristics);
+ //Sets raw section data from file image
+ void set_raw_data(const std::string& data);
+
+public: //Setters, be careful
+ //Sets section virtual size (doesn't set internal aligned virtual size, changes only header value)
+ //Better use pe_base::set_section_virtual_size
+ void set_virtual_size(uint32_t virtual_size);
+ //Sets section virtual address
+ void set_virtual_address(uint32_t virtual_address);
+ //Returns raw image section header
+ pe_win::image_section_header& get_raw_header();
+
+private:
+ //Section header
+ pe_win::image_section_header header_;
+
+ //Maps virtual section data
+ void map_virtual(uint32_t section_alignment) const;
+
+ //Unmaps virtual section data
+ void unmap_virtual() const;
+
+ //Set flag (attribute) of section
+ section& set_flag(uint32_t flag, bool setflag);
+
+ //Old size of section (stored after mapping of virtual section memory)
+ mutable std::size_t old_size_;
+
+ //Section raw/virtual data
+ mutable std::string raw_data_;
+};
+
+//Section by file offset finder helper (4gb max)
+struct section_by_raw_offset
+{
+public:
+ explicit section_by_raw_offset(uint32_t offset);
+ bool operator()(const section& s) const;
+
+private:
+ uint32_t offset_;
+};
+
+//Helper: finder of section* in sections list
+struct section_ptr_finder
+{
+public:
+ explicit section_ptr_finder(const section& s);
+ bool operator()(const section& s) const;
+
+private:
+ const section& s_;
+};
+
+typedef std::vector<section> section_list;
+}
diff --git a/tools/pe_bliss/pe_structures.h b/tools/pe_bliss/pe_structures.h
new file mode 100644
index 0000000000..efc99103b2
--- /dev/null
+++ b/tools/pe_bliss/pe_structures.h
@@ -0,0 +1,1028 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <string>
+#include <sstream>
+#include "stdint_defs.h"
+#if defined(_MSC_VER) or defined(__MINGW32__)
+#define PE_BLISS_WINDOWS
+#endif
+
+namespace pe_bliss
+{
+//Enumeration of PE types
+enum pe_type
+{
+ pe_type_32,
+ pe_type_64
+};
+
+namespace pe_win
+{
+const uint32_t image_numberof_directory_entries = 16;
+const uint32_t image_nt_optional_hdr32_magic = 0x10b;
+const uint32_t image_nt_optional_hdr64_magic = 0x20b;
+const uint32_t image_resource_name_is_string = 0x80000000;
+const uint32_t image_resource_data_is_directory = 0x80000000;
+
+const uint32_t image_dllcharacteristics_dynamic_base = 0x0040; // DLL can move.
+const uint32_t image_dllcharacteristics_force_integrity = 0x0080; // Code Integrity Image
+const uint32_t image_dllcharacteristics_nx_compat = 0x0100; // Image is NX compatible
+const uint32_t image_dllcharacteristics_no_isolation = 0x0200; // Image understands isolation and doesn't want it
+const uint32_t image_dllcharacteristics_no_seh = 0x0400; // Image does not use SEH. No SE handler may reside in this image
+const uint32_t image_dllcharacteristics_no_bind = 0x0800; // Do not bind this image.
+const uint32_t image_dllcharacteristics_wdm_driver = 0x2000; // Driver uses WDM model
+const uint32_t image_dllcharacteristics_terminal_server_aware = 0x8000;
+
+const uint32_t image_sizeof_file_header = 20;
+
+const uint32_t image_file_relocs_stripped = 0x0001; // Relocation info stripped from file.
+const uint32_t image_file_executable_image = 0x0002; // File is executable (i.e. no unresolved externel references).
+const uint32_t image_file_line_nums_stripped = 0x0004; // Line nunbers stripped from file.
+const uint32_t image_file_local_syms_stripped = 0x0008; // Local symbols stripped from file.
+const uint32_t image_file_aggresive_ws_trim = 0x0010; // Agressively trim working set
+const uint32_t image_file_large_address_aware = 0x0020; // App can handle >2gb addresses
+const uint32_t image_file_bytes_reversed_lo = 0x0080; // Bytes of machine word are reversed.
+const uint32_t image_file_32bit_machine = 0x0100; // 32 bit word machine.
+const uint32_t image_file_debug_stripped = 0x0200; // Debugging info stripped from file in .DBG file
+const uint32_t image_file_removable_run_from_swap = 0x0400; // If Image is on removable media, copy and run from the swap file.
+const uint32_t image_file_net_run_from_swap = 0x0800; // If Image is on Net, copy and run from the swap file.
+const uint32_t image_file_system = 0x1000; // System File.
+const uint32_t image_file_dll = 0x2000; // File is a DLL.
+const uint32_t image_file_up_system_only = 0x4000; // File should only be run on a UP machine
+const uint32_t image_file_bytes_reversed_hi = 0x8000; // Bytes of machine word are reversed.
+
+const uint32_t image_scn_lnk_nreloc_ovfl = 0x01000000; // Section contains extended relocations.
+const uint32_t image_scn_mem_discardable = 0x02000000; // Section can be discarded.
+const uint32_t image_scn_mem_not_cached = 0x04000000; // Section is not cachable.
+const uint32_t image_scn_mem_not_paged = 0x08000000; // Section is not pageable.
+const uint32_t image_scn_mem_shared = 0x10000000; // Section is shareable.
+const uint32_t image_scn_mem_execute = 0x20000000; // Section is executable.
+const uint32_t image_scn_mem_read = 0x40000000; // Section is readable.
+const uint32_t image_scn_mem_write = 0x80000000; // Section is writeable.
+
+const uint32_t image_scn_cnt_code = 0x00000020; // Section contains code.
+const uint32_t image_scn_cnt_initialized_data = 0x00000040; // Section contains initialized data.
+const uint32_t image_scn_cnt_uninitialized_data = 0x00000080; // Section contains uninitialized data.
+
+//Directory Entries
+const uint32_t image_directory_entry_export = 0; // Export Directory
+const uint32_t image_directory_entry_import = 1; // Import Directory
+const uint32_t image_directory_entry_resource = 2; // Resource Directory
+const uint32_t image_directory_entry_exception = 3; // Exception Directory
+const uint32_t image_directory_entry_security = 4; // Security Directory
+const uint32_t image_directory_entry_basereloc = 5; // Base Relocation Table
+const uint32_t image_directory_entry_debug = 6; // Debug Directory
+const uint32_t image_directory_entry_architecture = 7; // Architecture Specific Data
+const uint32_t image_directory_entry_globalptr = 8; // RVA of GP
+const uint32_t image_directory_entry_tls = 9; // TLS Directory
+const uint32_t image_directory_entry_load_config = 10; // Load Configuration Directory
+const uint32_t image_directory_entry_bound_import = 11; // Bound Import Directory in headers
+const uint32_t image_directory_entry_iat = 12; // Import Address Table
+const uint32_t image_directory_entry_delay_import = 13; // Delay Load Import Descriptors
+const uint32_t image_directory_entry_com_descriptor = 14; // COM Runtime descriptor
+
+//Subsystem Values
+const uint32_t image_subsystem_unknown = 0; // Unknown subsystem.
+const uint32_t image_subsystem_native = 1; // Image doesn't require a subsystem.
+const uint32_t image_subsystem_windows_gui = 2; // Image runs in the Windows GUI subsystem.
+const uint32_t image_subsystem_windows_cui = 3; // Image runs in the Windows character subsystem.
+const uint32_t image_subsystem_os2_cui = 5; // image runs in the OS/2 character subsystem.
+const uint32_t image_subsystem_posix_cui = 7; // image runs in the Posix character subsystem.
+const uint32_t image_subsystem_native_windows = 8; // image is a native Win9x driver.
+const uint32_t image_subsystem_windows_ce_gui = 9; // Image runs in the Windows CE subsystem.
+const uint32_t image_subsystem_efi_application = 10; //
+const uint32_t image_subsystem_efi_boot_service_driver = 11; //
+const uint32_t image_subsystem_efi_runtime_driver = 12; //
+const uint32_t image_subsystem_efi_rom = 13;
+const uint32_t image_subsystem_xbox = 14;
+const uint32_t image_subsystem_windows_boot_application = 16;
+
+//Imports
+const uint64_t image_ordinal_flag64 = 0x8000000000000000ull;
+const uint32_t image_ordinal_flag32 = 0x80000000;
+
+//Based relocation types
+const uint32_t image_rel_based_absolute = 0;
+const uint32_t image_rel_based_high = 1;
+const uint32_t image_rel_based_low = 2;
+const uint32_t image_rel_based_highlow = 3;
+const uint32_t image_rel_based_highadj = 4;
+const uint32_t image_rel_based_mips_jmpaddr = 5;
+const uint32_t image_rel_based_mips_jmpaddr16 = 9;
+const uint32_t image_rel_based_ia64_imm64 = 9;
+const uint32_t image_rel_based_dir64 = 10;
+
+//Exception directory
+//The function has an exception handler that should be called when looking for functions that need to examine exceptions
+const uint32_t unw_flag_ehandler = 0x01;
+//The function has a termination handler that should be called when unwinding an exception
+const uint32_t unw_flag_uhandler = 0x02;
+//This unwind info structure is not the primary one for the procedure.
+//Instead, the chained unwind info entry is the contents of a previous RUNTIME_FUNCTION entry.
+//If this flag is set, then the UNW_FLAG_EHANDLER and UNW_FLAG_UHANDLER flags must be cleared.
+//Also, the frame register and fixed-stack allocation fields must have the same values as in the primary unwind info
+const uint32_t unw_flag_chaininfo = 0x04;
+
+//Debug
+const uint32_t image_debug_misc_exename = 1;
+const uint32_t image_debug_type_unknown = 0;
+const uint32_t image_debug_type_coff = 1;
+const uint32_t image_debug_type_codeview = 2;
+const uint32_t image_debug_type_fpo = 3;
+const uint32_t image_debug_type_misc = 4;
+const uint32_t image_debug_type_exception = 5;
+const uint32_t image_debug_type_fixup = 6;
+const uint32_t image_debug_type_omap_to_src = 7;
+const uint32_t image_debug_type_omap_from_src = 8;
+const uint32_t image_debug_type_borland = 9;
+const uint32_t image_debug_type_reserved10 = 10;
+const uint32_t image_debug_type_clsid = 11;
+
+
+//Storage classes
+const uint32_t image_sym_class_end_of_function = static_cast<uint8_t>(-1);
+const uint32_t image_sym_class_null = 0x0000;
+const uint32_t image_sym_class_automatic = 0x0001;
+const uint32_t image_sym_class_external = 0x0002;
+const uint32_t image_sym_class_static = 0x0003;
+const uint32_t image_sym_class_register = 0x0004;
+const uint32_t image_sym_class_external_def = 0x0005;
+const uint32_t image_sym_class_label = 0x0006;
+const uint32_t image_sym_class_undefined_label = 0x0007;
+const uint32_t image_sym_class_member_of_struct = 0x0008;
+const uint32_t image_sym_class_argument = 0x0009;
+const uint32_t image_sym_class_struct_tag = 0x000a;
+const uint32_t image_sym_class_member_of_union = 0x000b;
+const uint32_t image_sym_class_union_tag = 0x000c;
+const uint32_t image_sym_class_type_definition = 0x000d;
+const uint32_t image_sym_class_undefined_static = 0x000e;
+const uint32_t image_sym_class_enum_tag = 0x000f;
+const uint32_t image_sym_class_member_of_enum = 0x0010;
+const uint32_t image_sym_class_register_param = 0x0011;
+const uint32_t image_sym_class_bit_field = 0x0012;
+
+const uint32_t image_sym_class_far_external = 0x0044;
+
+const uint32_t image_sym_class_block = 0x0064;
+const uint32_t image_sym_class_function = 0x0065;
+const uint32_t image_sym_class_end_of_struct = 0x0066;
+const uint32_t image_sym_class_file = 0x0067;
+
+const uint32_t image_sym_class_section = 0x0068;
+const uint32_t image_sym_class_weak_external = 0x0069;
+
+const uint32_t image_sym_class_clr_token = 0x006b;
+
+//type packing constants
+const uint32_t n_btmask = 0x000f;
+const uint32_t n_tmask = 0x0030;
+const uint32_t n_tmask1 = 0x00c0;
+const uint32_t n_tmask2 = 0x00f0;
+const uint32_t n_btshft = 4;
+const uint32_t n_tshift = 2;
+
+//Type (derived) values.
+const uint32_t image_sym_dtype_null = 0; // no derived type.
+const uint32_t image_sym_dtype_pointer = 1; // pointer.
+const uint32_t image_sym_dtype_function = 2; // function.
+const uint32_t image_sym_dtype_array = 3; // array.
+
+// Is x a function?
+//TODO
+#ifndef ISFCN
+#define ISFCN(x) (((x) & n_tmask) == (image_sym_dtype_function << n_btshft))
+#endif
+
+//Version info
+const uint32_t vs_ffi_fileflagsmask = 0x0000003FL;
+
+const uint32_t vs_ffi_signature = 0xFEEF04BDL;
+const uint32_t vs_ffi_strucversion = 0x00010000L;
+
+/* ----- VS_VERSION.dwFileFlags ----- */
+const uint32_t vs_ff_debug = 0x00000001L;
+const uint32_t vs_ff_prerelease = 0x00000002L;
+const uint32_t vs_ff_patched = 0x00000004L;
+const uint32_t vs_ff_privatebuild = 0x00000008L;
+const uint32_t vs_ff_infoinferred = 0x00000010L;
+const uint32_t vs_ff_specialbuild = 0x00000020L;
+
+/* ----- VS_VERSION.dwFileOS ----- */
+const uint32_t vos_unknown = 0x00000000L;
+const uint32_t vos_dos = 0x00010000L;
+const uint32_t vos_os216 = 0x00020000L;
+const uint32_t vos_os232 = 0x00030000L;
+const uint32_t vos_nt = 0x00040000L;
+const uint32_t vos_wince = 0x00050000L;
+
+const uint32_t vos__base = 0x00000000L;
+const uint32_t vos__windows16 = 0x00000001L;
+const uint32_t vos__pm16 = 0x00000002L;
+const uint32_t vos__pm32 = 0x00000003L;
+const uint32_t vos__windows32 = 0x00000004L;
+
+const uint32_t vos_dos_windows16 = 0x00010001L;
+const uint32_t vos_dos_windows32 = 0x00010004L;
+const uint32_t vos_os216_pm16 = 0x00020002L;
+const uint32_t vos_os232_pm32 = 0x00030003L;
+const uint32_t vos_nt_windows32 = 0x00040004L;
+
+/* ----- VS_VERSION.dwFileType ----- */
+const uint32_t vft_unknown = 0x00000000L;
+const uint32_t vft_app = 0x00000001L;
+const uint32_t vft_dll = 0x00000002L;
+const uint32_t vft_drv = 0x00000003L;
+const uint32_t vft_font = 0x00000004L;
+const uint32_t vft_vxd = 0x00000005L;
+const uint32_t vft_static_lib = 0x00000007L;
+
+const uint32_t message_resource_unicode = 0x0001;
+
+#pragma pack(push, 1)
+
+//Windows GUID structure
+struct guid
+{
+ uint32_t Data1;
+ uint16_t Data2;
+ uint16_t Data3;
+ uint8_t Data4[8];
+};
+
+//DOS .EXE header
+struct image_dos_header
+{
+ uint16_t e_magic; // Magic number
+ uint16_t e_cblp; // Bytes on last page of file
+ uint16_t e_cp; // Pages in file
+ uint16_t e_crlc; // Relocations
+ uint16_t e_cparhdr; // Size of header in paragraphs
+ uint16_t e_minalloc; // Minimum extra paragraphs needed
+ uint16_t e_maxalloc; // Maximum extra paragraphs needed
+ uint16_t e_ss; // Initial (relative) SS value
+ uint16_t e_sp; // Initial SP value
+ uint16_t e_csum; // Checksum
+ uint16_t e_ip; // Initial IP value
+ uint16_t e_cs; // Initial (relative) CS value
+ uint16_t e_lfarlc; // File address of relocation table
+ uint16_t e_ovno; // Overlay number
+ uint16_t e_res[4]; // Reserved words
+ uint16_t e_oemid; // OEM identifier (for e_oeminfo)
+ uint16_t e_oeminfo; // OEM information; e_oemid specific
+ uint16_t e_res2[10]; // Reserved words
+ int32_t e_lfanew; // File address of new exe header
+};
+
+//Directory format
+struct image_data_directory
+{
+ uint32_t VirtualAddress;
+ uint32_t Size;
+};
+
+//Optional header format
+struct image_optional_header32
+{
+ //Standard fields
+ uint16_t Magic;
+ uint8_t MajorLinkerVersion;
+ uint8_t MinorLinkerVersion;
+ uint32_t SizeOfCode;
+ uint32_t SizeOfInitializedData;
+ uint32_t SizeOfUninitializedData;
+ uint32_t AddressOfEntryPoint;
+ uint32_t BaseOfCode;
+ uint32_t BaseOfData;
+
+ //NT additional fields
+ uint32_t ImageBase;
+ uint32_t SectionAlignment;
+ uint32_t FileAlignment;
+ uint16_t MajorOperatingSystemVersion;
+ uint16_t MinorOperatingSystemVersion;
+ uint16_t MajorImageVersion;
+ uint16_t MinorImageVersion;
+ uint16_t MajorSubsystemVersion;
+ uint16_t MinorSubsystemVersion;
+ uint32_t Win32VersionValue;
+ uint32_t SizeOfImage;
+ uint32_t SizeOfHeaders;
+ uint32_t CheckSum;
+ uint16_t Subsystem;
+ uint16_t DllCharacteristics;
+ uint32_t SizeOfStackReserve;
+ uint32_t SizeOfStackCommit;
+ uint32_t SizeOfHeapReserve;
+ uint32_t SizeOfHeapCommit;
+ uint32_t LoaderFlags;
+ uint32_t NumberOfRvaAndSizes;
+ image_data_directory DataDirectory[image_numberof_directory_entries];
+};
+
+struct image_optional_header64
+{
+ uint16_t Magic;
+ uint8_t MajorLinkerVersion;
+ uint8_t MinorLinkerVersion;
+ uint32_t SizeOfCode;
+ uint32_t SizeOfInitializedData;
+ uint32_t SizeOfUninitializedData;
+ uint32_t AddressOfEntryPoint;
+ uint32_t BaseOfCode;
+ uint64_t ImageBase;
+ uint32_t SectionAlignment;
+ uint32_t FileAlignment;
+ uint16_t MajorOperatingSystemVersion;
+ uint16_t MinorOperatingSystemVersion;
+ uint16_t MajorImageVersion;
+ uint16_t MinorImageVersion;
+ uint16_t MajorSubsystemVersion;
+ uint16_t MinorSubsystemVersion;
+ uint32_t Win32VersionValue;
+ uint32_t SizeOfImage;
+ uint32_t SizeOfHeaders;
+ uint32_t CheckSum;
+ uint16_t Subsystem;
+ uint16_t DllCharacteristics;
+ uint64_t SizeOfStackReserve;
+ uint64_t SizeOfStackCommit;
+ uint64_t SizeOfHeapReserve;
+ uint64_t SizeOfHeapCommit;
+ uint32_t LoaderFlags;
+ uint32_t NumberOfRvaAndSizes;
+ image_data_directory DataDirectory[image_numberof_directory_entries];
+};
+
+struct image_file_header
+{
+ uint16_t Machine;
+ uint16_t NumberOfSections;
+ uint32_t TimeDateStamp;
+ uint32_t PointerToSymbolTable;
+ uint32_t NumberOfSymbols;
+ uint16_t SizeOfOptionalHeader;
+ uint16_t Characteristics;
+};
+
+struct image_nt_headers64
+{
+ uint32_t Signature;
+ image_file_header FileHeader;
+ image_optional_header64 OptionalHeader;
+};
+
+struct image_nt_headers32
+{
+ uint32_t Signature;
+ image_file_header FileHeader;
+ image_optional_header32 OptionalHeader;
+};
+
+//Section header format
+struct image_section_header
+{
+ uint8_t Name[8];
+ union
+ {
+ uint32_t PhysicalAddress;
+ uint32_t VirtualSize;
+ } Misc;
+
+ uint32_t VirtualAddress;
+ uint32_t SizeOfRawData;
+ uint32_t PointerToRawData;
+ uint32_t PointerToRelocations;
+ uint32_t PointerToLinenumbers;
+ uint16_t NumberOfRelocations;
+ uint16_t NumberOfLinenumbers;
+ uint32_t Characteristics;
+};
+
+
+/// RESOURCES ///
+struct image_resource_directory
+{
+ uint32_t Characteristics;
+ uint32_t TimeDateStamp;
+ uint16_t MajorVersion;
+ uint16_t MinorVersion;
+ uint16_t NumberOfNamedEntries;
+ uint16_t NumberOfIdEntries;
+ // IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[];
+};
+
+struct vs_fixedfileinfo
+{
+ uint32_t dwSignature; /* e.g. 0xfeef04bd */
+ uint32_t dwStrucVersion; /* e.g. 0x00000042 = "0.42" */
+ uint32_t dwFileVersionMS; /* e.g. 0x00030075 = "3.75" */
+ uint32_t dwFileVersionLS; /* e.g. 0x00000031 = "0.31" */
+ uint32_t dwProductVersionMS; /* e.g. 0x00030010 = "3.10" */
+ uint32_t dwProductVersionLS; /* e.g. 0x00000031 = "0.31" */
+ uint32_t dwFileFlagsMask; /* = 0x3F for version "0.42" */
+ uint32_t dwFileFlags; /* e.g. VFF_DEBUG | VFF_PRERELEASE */
+ uint32_t dwFileOS; /* e.g. VOS_DOS_WINDOWS16 */
+ uint32_t dwFileType; /* e.g. VFT_DRIVER */
+ uint32_t dwFileSubtype; /* e.g. VFT2_DRV_KEYBOARD */
+ uint32_t dwFileDateMS; /* e.g. 0 */
+ uint32_t dwFileDateLS; /* e.g. 0 */
+};
+
+struct bitmapinfoheader
+{
+ uint32_t biSize;
+ int32_t biWidth;
+ int32_t biHeight;
+ uint16_t biPlanes;
+ uint16_t biBitCount;
+ uint32_t biCompression;
+ uint32_t biSizeImage;
+ int32_t biXPelsPerMeter;
+ int32_t biYPelsPerMeter;
+ uint32_t biClrUsed;
+ uint32_t biClrImportant;
+};
+
+struct message_resource_entry
+{
+ uint16_t Length;
+ uint16_t Flags;
+ uint8_t Text[1];
+};
+
+struct message_resource_block
+{
+ uint32_t LowId;
+ uint32_t HighId;
+ uint32_t OffsetToEntries;
+};
+
+struct message_resource_data
+{
+ uint32_t NumberOfBlocks;
+ message_resource_block Blocks[1];
+};
+
+struct image_resource_directory_entry
+{
+ union
+ {
+ struct
+ {
+ uint32_t NameOffset:31;
+ uint32_t NameIsString:1;
+ };
+ uint32_t Name;
+ uint16_t Id;
+ };
+
+ union
+ {
+ uint32_t OffsetToData;
+ struct
+ {
+ uint32_t OffsetToDirectory:31;
+ uint32_t DataIsDirectory:1;
+ };
+ };
+};
+
+struct image_resource_data_entry
+{
+ uint32_t OffsetToData;
+ uint32_t Size;
+ uint32_t CodePage;
+ uint32_t Reserved;
+};
+
+#pragma pack(push, 2)
+struct bitmapfileheader
+{
+ uint16_t bfType;
+ uint32_t bfSize;
+ uint16_t bfReserved1;
+ uint16_t bfReserved2;
+ uint32_t bfOffBits;
+};
+#pragma pack(pop)
+
+
+
+//Structure representing ICON file header
+struct ico_header
+{
+ uint16_t Reserved;
+ uint16_t Type; //1
+ uint16_t Count; //Count of icons included in icon group
+};
+
+//Structure that is stored in icon group directory in PE resources
+struct icon_group
+{
+ uint8_t Width;
+ uint8_t Height;
+ uint8_t ColorCount;
+ uint8_t Reserved;
+ uint16_t Planes;
+ uint16_t BitCount;
+ uint32_t SizeInBytes;
+ uint16_t Number; //Represents resource ID in PE icon list
+};
+
+//Structure representing ICON directory entry inside ICON file
+struct icondirentry
+{
+ uint8_t Width;
+ uint8_t Height;
+ uint8_t ColorCount;
+ uint8_t Reserved;
+ uint16_t Planes;
+ uint16_t BitCount;
+ uint32_t SizeInBytes;
+ uint32_t ImageOffset; //Offset from start of header to the image
+};
+
+//Structure representing CURSOR file header
+struct cursor_header
+{
+ uint16_t Reserved;
+ uint16_t Type; //2
+ uint16_t Count; //Count of cursors included in cursor group
+};
+
+struct cursor_group
+{
+ uint16_t Width;
+ uint16_t Height; //Divide by 2 to get the actual height.
+ uint16_t Planes;
+ uint16_t BitCount;
+ uint32_t SizeInBytes;
+ uint16_t Number; //Represents resource ID in PE icon list
+};
+
+//Structure representing CURSOR directory entry inside CURSOR file
+struct cursordirentry
+{
+ uint8_t Width; //Set to CURSOR_GROUP::Height/2.
+ uint8_t Height;
+ uint8_t ColorCount;
+ uint8_t Reserved;
+ uint16_t HotspotX;
+ uint16_t HotspotY;
+ uint32_t SizeInBytes;
+ uint32_t ImageOffset; //Offset from start of header to the image
+};
+
+//Structure representing BLOCK in version info resource
+struct version_info_block //(always aligned on 32-bit (DWORD) boundary)
+{
+ uint16_t Length; //Length of this block (doesn't include padding)
+ uint16_t ValueLength; //Value length (if any)
+ uint16_t Type; //Value type (0 = binary, 1 = text)
+ uint16_t Key[1]; //Value name (block key) (always NULL terminated)
+
+ //////////
+ //WORD padding1[]; //Padding, if any (ALIGNMENT)
+ //xxxxx Value[]; //Value data, if any (*ALIGNED*)
+ //WORD padding2[]; //Padding, if any (ALIGNMENT)
+ //xxxxx Child[]; //Child block(s), if any (*ALIGNED*)
+ //////////
+};
+
+
+/// IMPORTS ///
+#pragma pack(push, 8)
+struct image_thunk_data64
+{
+ union
+ {
+ uint64_t ForwarderString; // PBYTE
+ uint64_t Function; // PDWORD
+ uint64_t Ordinal;
+ uint64_t AddressOfData; // PIMAGE_IMPORT_BY_NAME
+ } u1;
+};
+#pragma pack(pop)
+
+struct image_thunk_data32
+{
+ union
+ {
+ uint32_t ForwarderString; // PBYTE
+ uint32_t Function; // PDWORD
+ uint32_t Ordinal;
+ uint32_t AddressOfData; // PIMAGE_IMPORT_BY_NAME
+ } u1;
+};
+
+struct image_import_descriptor
+{
+ union
+ {
+ uint32_t Characteristics; // 0 for terminating null import descriptor
+ uint32_t OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
+ };
+
+ uint32_t TimeDateStamp; // 0 if not bound,
+ // -1 if bound, and real date\time stamp
+ // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
+ // O.W. date/time stamp of DLL bound to (Old BIND)
+
+ uint32_t ForwarderChain; // -1 if no forwarders
+ uint32_t Name;
+ uint32_t FirstThunk; // RVA to IAT (if bound this IAT has actual addresses)
+};
+
+
+/// TLS ///
+struct image_tls_directory64
+{
+ uint64_t StartAddressOfRawData;
+ uint64_t EndAddressOfRawData;
+ uint64_t AddressOfIndex; // PDWORD
+ uint64_t AddressOfCallBacks; // PIMAGE_TLS_CALLBACK *;
+ uint32_t SizeOfZeroFill;
+ uint32_t Characteristics;
+};
+
+struct image_tls_directory32
+{
+ uint32_t StartAddressOfRawData;
+ uint32_t EndAddressOfRawData;
+ uint32_t AddressOfIndex; // PDWORD
+ uint32_t AddressOfCallBacks; // PIMAGE_TLS_CALLBACK *
+ uint32_t SizeOfZeroFill;
+ uint32_t Characteristics;
+};
+
+
+/// Export Format ///
+struct image_export_directory
+{
+ uint32_t Characteristics;
+ uint32_t TimeDateStamp;
+ uint16_t MajorVersion;
+ uint16_t MinorVersion;
+ uint32_t Name;
+ uint32_t Base;
+ uint32_t NumberOfFunctions;
+ uint32_t NumberOfNames;
+ uint32_t AddressOfFunctions; // RVA from base of image
+ uint32_t AddressOfNames; // RVA from base of image
+ uint32_t AddressOfNameOrdinals; // RVA from base of image
+};
+
+
+/// Based relocation format ///
+struct image_base_relocation
+{
+ uint32_t VirtualAddress;
+ uint32_t SizeOfBlock;
+ // uint16_t TypeOffset[1];
+};
+
+
+/// New format import descriptors pointed to by DataDirectory[ IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ] ///
+struct image_bound_import_descriptor
+{
+ uint32_t TimeDateStamp;
+ uint16_t OffsetModuleName;
+ uint16_t NumberOfModuleForwarderRefs;
+ // Array of zero or more IMAGE_BOUND_FORWARDER_REF follows
+};
+
+struct image_bound_forwarder_ref
+{
+ uint32_t TimeDateStamp;
+ uint16_t OffsetModuleName;
+ uint16_t Reserved;
+};
+
+
+/// Exception directory ///
+struct image_runtime_function_entry
+{
+ uint32_t BeginAddress;
+ uint32_t EndAddress;
+ uint32_t UnwindInfoAddress;
+};
+
+enum unwind_op_codes
+{
+ uwop_push_nonvol = 0, /* info == register number */
+ uwop_alloc_large, /* no info, alloc size in next 2 slots */
+ uwop_alloc_small, /* info == size of allocation / 8 - 1 */
+ uwop_set_fpreg, /* no info, FP = RSP + UNWIND_INFO.FPRegOffset*16 */
+ uwop_save_nonvol, /* info == register number, offset in next slot */
+ uwop_save_nonvol_far, /* info == register number, offset in next 2 slots */
+ uwop_save_xmm128, /* info == XMM reg number, offset in next slot */
+ uwop_save_xmm128_far, /* info == XMM reg number, offset in next 2 slots */
+ uwop_push_machframe /* info == 0: no error-code, 1: error-code */
+};
+
+union unwind_code
+{
+ struct s
+ {
+ uint8_t CodeOffset;
+ uint8_t UnwindOp : 4;
+ uint8_t OpInfo : 4;
+ };
+
+ uint16_t FrameOffset;
+};
+
+struct unwind_info
+{
+ uint8_t Version : 3;
+ uint8_t Flags : 5;
+ uint8_t SizeOfProlog;
+ uint8_t CountOfCodes;
+ uint8_t FrameRegister : 4;
+ uint8_t FrameOffset : 4;
+ unwind_code UnwindCode[1];
+ /* unwind_code MoreUnwindCode[((CountOfCodes + 1) & ~1) - 1];
+ * union {
+ * OPTIONAL ULONG ExceptionHandler;
+ * OPTIONAL ULONG FunctionEntry;
+ * };
+ * OPTIONAL ULONG ExceptionData[]; */
+};
+
+
+
+/// Debug ///
+struct image_debug_misc
+{
+ uint32_t DataType; // type of misc data, see defines
+ uint32_t Length; // total length of record, rounded to four
+ // byte multiple.
+ uint8_t Unicode; // TRUE if data is unicode string
+ uint8_t Reserved[3];
+ uint8_t Data[1]; // Actual data
+};
+
+struct image_coff_symbols_header
+{
+ uint32_t NumberOfSymbols;
+ uint32_t LvaToFirstSymbol;
+ uint32_t NumberOfLinenumbers;
+ uint32_t LvaToFirstLinenumber;
+ uint32_t RvaToFirstByteOfCode;
+ uint32_t RvaToLastByteOfCode;
+ uint32_t RvaToFirstByteOfData;
+ uint32_t RvaToLastByteOfData;
+};
+
+struct image_debug_directory
+{
+ uint32_t Characteristics;
+ uint32_t TimeDateStamp;
+ uint16_t MajorVersion;
+ uint16_t MinorVersion;
+ uint32_t Type;
+ uint32_t SizeOfData;
+ uint32_t AddressOfRawData;
+ uint32_t PointerToRawData;
+};
+
+
+#pragma pack(push, 2)
+struct image_symbol
+{
+ union
+ {
+ uint8_t ShortName[8];
+ struct
+ {
+ uint32_t Short; // if 0, use LongName
+ uint32_t Long; // offset into string table
+ } Name;
+ uint32_t LongName[2]; // PBYTE [2]
+ } N;
+ uint32_t Value;
+ int16_t SectionNumber;
+ uint16_t Type;
+ uint8_t StorageClass;
+ uint8_t NumberOfAuxSymbols;
+};
+#pragma pack(pop)
+
+//CodeView Debug OMF signature. The signature at the end of the file is
+//a negative offset from the end of the file to another signature. At
+//the negative offset (base address) is another signature whose filepos
+//field points to the first OMFDirHeader in a chain of directories.
+//The NB05 signature is used by the link utility to indicated a completely
+//unpacked file. The NB06 signature is used by ilink to indicate that the
+//executable has had CodeView information from an incremental link appended
+//to the executable. The NB08 signature is used by cvpack to indicate that
+//the CodeView Debug OMF has been packed. CodeView will only process
+//executables with the NB08 signature.
+struct OMFSignature
+{
+ char Signature[4]; // "NBxx"
+ uint32_t filepos; // offset in file
+};
+
+struct CV_INFO_PDB20
+{
+ OMFSignature CvHeader;
+ uint32_t Signature;
+ uint32_t Age;
+ uint8_t PdbFileName[1];
+};
+
+struct CV_INFO_PDB70
+{
+ uint32_t CvSignature;
+ guid Signature;
+ uint32_t Age;
+ uint8_t PdbFileName[1];
+};
+
+// directory information structure
+// This structure contains the information describing the directory.
+// It is pointed to by the signature at the base address or the directory
+// link field of a preceeding directory. The directory entries immediately
+// follow this structure.
+struct OMFDirHeader
+{
+ uint16_t cbDirHeader; // length of this structure
+ uint16_t cbDirEntry; // number of bytes in each directory entry
+ uint32_t cDir; // number of directorie entries
+ int32_t lfoNextDir; // offset from base of next directory
+ uint32_t flags; // status flags
+};
+
+// directory structure
+// The data in this structure is used to reference the data for each
+// subsection of the CodeView Debug OMF information. Tables that are
+// not associated with a specific module will have a module index of
+// oxffff. These tables are the global types table, the global symbol
+// table, the global public table and the library table.
+struct OMFDirEntry
+{
+ uint16_t SubSection; // subsection type (sst...)
+ uint16_t iMod; // module index
+ int32_t lfo; // large file offset of subsection
+ uint32_t cb; // number of bytes in subsection
+};
+
+
+/// CLR 2.0 header structure ///
+struct image_cor20_header
+{
+ //Header versioning
+ uint32_t cb;
+ uint16_t MajorRuntimeVersion;
+ uint16_t MinorRuntimeVersion;
+
+ // Symbol table and startup information
+ image_data_directory MetaData;
+ uint32_t Flags;
+
+ // If COMIMAGE_FLAGS_NATIVE_ENTRYPOINT is not set, EntryPointToken represents a managed entrypoint.
+ // If COMIMAGE_FLAGS_NATIVE_ENTRYPOINT is set, EntryPointRVA represents an RVA to a native entrypoint.
+ union
+ {
+ uint32_t EntryPointToken;
+ uint32_t EntryPointRVA;
+ };
+
+ // Binding information
+ image_data_directory Resources;
+ image_data_directory StrongNameSignature;
+
+ // Regular fixup and binding information
+ image_data_directory CodeManagerTable;
+ image_data_directory VTableFixups;
+ image_data_directory ExportAddressTableJumps;
+
+ // Precompiled image info (internal use only - set to zero)
+ image_data_directory ManagedNativeHeader;
+};
+
+enum replaces_cor_hdr_numeric_defines
+{
+ // COM+ Header entry point flags.
+ comimage_flags_ilonly =0x00000001,
+ comimage_flags_32bitrequired =0x00000002,
+ comimage_flags_il_library =0x00000004,
+ comimage_flags_strongnamesigned =0x00000008,
+ comimage_flags_native_entrypoint =0x00000010,
+ comimage_flags_trackdebugdata =0x00010000,
+
+ // Version flags for image.
+ cor_version_major_v2 =2,
+ cor_version_major =cor_version_major_v2,
+ cor_version_minor =0,
+ cor_deleted_name_length =8,
+ cor_vtablegap_name_length =8,
+
+ // Maximum size of a NativeType descriptor.
+ native_type_max_cb =1,
+ cor_ilmethod_sect_small_max_datasize=0xff,
+
+ // #defines for the MIH FLAGS
+ image_cor_mih_methodrva =0x01,
+ image_cor_mih_ehrva =0x02,
+ image_cor_mih_basicblock =0x08,
+
+ // V-table constants
+ cor_vtable_32bit =0x01, // V-table slots are 32-bits in size.
+ cor_vtable_64bit =0x02, // V-table slots are 64-bits in size.
+ cor_vtable_from_unmanaged =0x04, // If set, transition from unmanaged.
+ cor_vtable_from_unmanaged_retain_appdomain =0x08, // If set, transition from unmanaged with keeping the current appdomain.
+ cor_vtable_call_most_derived =0x10, // Call most derived method described by
+
+ // EATJ constants
+ image_cor_eatj_thunk_size =32, // Size of a jump thunk reserved range.
+
+ // Max name lengths
+ //@todo: Change to unlimited name lengths.
+ max_class_name =1024,
+ max_package_name =1024
+};
+
+/// Load Configuration Directory Entry ///
+struct image_load_config_directory32
+{
+ uint32_t Size;
+ uint32_t TimeDateStamp;
+ uint16_t MajorVersion;
+ uint16_t MinorVersion;
+ uint32_t GlobalFlagsClear;
+ uint32_t GlobalFlagsSet;
+ uint32_t CriticalSectionDefaultTimeout;
+ uint32_t DeCommitFreeBlockThreshold;
+ uint32_t DeCommitTotalFreeThreshold;
+ uint32_t LockPrefixTable; // VA
+ uint32_t MaximumAllocationSize;
+ uint32_t VirtualMemoryThreshold;
+ uint32_t ProcessHeapFlags;
+ uint32_t ProcessAffinityMask;
+ uint16_t CSDVersion;
+ uint16_t Reserved1;
+ uint32_t EditList; // VA
+ uint32_t SecurityCookie; // VA
+ uint32_t SEHandlerTable; // VA
+ uint32_t SEHandlerCount;
+};
+
+struct image_load_config_directory64
+{
+ uint32_t Size;
+ uint32_t TimeDateStamp;
+ uint16_t MajorVersion;
+ uint16_t MinorVersion;
+ uint32_t GlobalFlagsClear;
+ uint32_t GlobalFlagsSet;
+ uint32_t CriticalSectionDefaultTimeout;
+ uint64_t DeCommitFreeBlockThreshold;
+ uint64_t DeCommitTotalFreeThreshold;
+ uint64_t LockPrefixTable; // VA
+ uint64_t MaximumAllocationSize;
+ uint64_t VirtualMemoryThreshold;
+ uint64_t ProcessAffinityMask;
+ uint32_t ProcessHeapFlags;
+ uint16_t CSDVersion;
+ uint16_t Reserved1;
+ uint64_t EditList; // VA
+ uint64_t SecurityCookie; // VA
+ uint64_t SEHandlerTable; // VA
+ uint64_t SEHandlerCount;
+};
+
+#pragma pack(pop)
+} //namespace pe_win
+
+#ifdef PE_BLISS_WINDOWS
+typedef wchar_t unicode16_t;
+typedef std::basic_string<unicode16_t> u16string;
+#else
+//Instead of wchar_t for windows
+typedef unsigned short unicode16_t;
+typedef std::basic_string<unicode16_t> u16string;
+#endif
+
+} //namespace pe_bliss
diff --git a/tools/pe_bliss/pe_tls.cpp b/tools/pe_bliss/pe_tls.cpp
new file mode 100644
index 0000000000..5ec68e3f10
--- /dev/null
+++ b/tools/pe_bliss/pe_tls.cpp
@@ -0,0 +1,396 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include <string.h>
+#include "pe_tls.h"
+#include "pe_properties_generic.h"
+
+namespace pe_bliss
+{
+using namespace pe_win;
+
+//TLS
+//Default constructor
+tls_info::tls_info()
+ :start_rva_(0), end_rva_(0), index_rva_(0), callbacks_rva_(0),
+ size_of_zero_fill_(0), characteristics_(0)
+{}
+
+//Returns start RVA of TLS raw data
+uint32_t tls_info::get_raw_data_start_rva() const
+{
+ return start_rva_;
+}
+
+//Returns end RVA of TLS raw data
+uint32_t tls_info::get_raw_data_end_rva() const
+{
+ return end_rva_;
+}
+
+//Returns TLS index RVA
+uint32_t tls_info::get_index_rva() const
+{
+ return index_rva_;
+}
+
+//Returns TLS callbacks RVA
+uint32_t tls_info::get_callbacks_rva() const
+{
+ return callbacks_rva_;
+}
+
+//Returns size of zero fill
+uint32_t tls_info::get_size_of_zero_fill() const
+{
+ return size_of_zero_fill_;
+}
+
+//Returns characteristics
+uint32_t tls_info::get_characteristics() const
+{
+ return characteristics_;
+}
+
+//Returns raw TLS data
+const std::string& tls_info::get_raw_data() const
+{
+ return raw_data_;
+}
+
+//Returns TLS callbacks addresses
+const tls_info::tls_callback_list& tls_info::get_tls_callbacks() const
+{
+ return callbacks_;
+}
+
+//Returns TLS callbacks addresses
+tls_info::tls_callback_list& tls_info::get_tls_callbacks()
+{
+ return callbacks_;
+}
+
+//Adds TLS callback
+void tls_info::add_tls_callback(uint32_t rva)
+{
+ callbacks_.push_back(rva);
+}
+
+//Clears TLS callbacks list
+void tls_info::clear_tls_callbacks()
+{
+ callbacks_.clear();
+}
+
+//Recalculates end address of raw TLS data
+void tls_info::recalc_raw_data_end_rva()
+{
+ end_rva_ = static_cast<uint32_t>(start_rva_ + raw_data_.length());
+}
+
+//Sets start RVA of TLS raw data
+void tls_info::set_raw_data_start_rva(uint32_t rva)
+{
+ start_rva_ = rva;
+}
+
+//Sets end RVA of TLS raw data
+void tls_info::set_raw_data_end_rva(uint32_t rva)
+{
+ end_rva_ = rva;
+}
+
+//Sets TLS index RVA
+void tls_info::set_index_rva(uint32_t rva)
+{
+ index_rva_ = rva;
+}
+
+//Sets TLS callbacks RVA
+void tls_info::set_callbacks_rva(uint32_t rva)
+{
+ callbacks_rva_ = rva;
+}
+
+//Sets size of zero fill
+void tls_info::set_size_of_zero_fill(uint32_t size)
+{
+ size_of_zero_fill_ = size;
+}
+
+//Sets characteristics
+void tls_info::set_characteristics(uint32_t characteristics)
+{
+ characteristics_ = characteristics;
+}
+
+//Sets raw TLS data
+void tls_info::set_raw_data(const std::string& data)
+{
+ raw_data_ = data;
+}
+
+//If image does not have TLS, throws an exception
+const tls_info get_tls_info(const pe_base& pe)
+{
+ return pe.get_pe_type() == pe_type_32
+ ? get_tls_info_base<pe_types_class_32>(pe)
+ : get_tls_info_base<pe_types_class_64>(pe);
+}
+
+//TLS Rebuilder
+const image_directory rebuild_tls(pe_base& pe, const tls_info& info, section& tls_section, uint32_t offset_from_section_start, bool write_tls_callbacks, bool write_tls_data, tls_data_expand_type expand, bool save_to_pe_header, bool auto_strip_last_section)
+{
+ return pe.get_pe_type() == pe_type_32
+ ? rebuild_tls_base<pe_types_class_32>(pe, info, tls_section, offset_from_section_start, write_tls_callbacks, write_tls_data, expand, save_to_pe_header, auto_strip_last_section)
+ : rebuild_tls_base<pe_types_class_64>(pe, info, tls_section, offset_from_section_start, write_tls_callbacks, write_tls_data, expand, save_to_pe_header, auto_strip_last_section);
+}
+
+//Get TLS info
+//If image does not have TLS, throws an exception
+template<typename PEClassType>
+const tls_info get_tls_info_base(const pe_base& pe)
+{
+ tls_info ret;
+
+ //If there's no TLS directory, throw an exception
+ if(!pe.has_tls())
+ throw pe_exception("Image does not have TLS directory", pe_exception::directory_does_not_exist);
+
+ //Get TLS directory data
+ typename PEClassType::TLSStruct tls_directory_data = pe.section_data_from_rva<typename PEClassType::TLSStruct>(pe.get_directory_rva(image_directory_entry_tls), section_data_virtual, true);
+
+ //Check data addresses
+ if(tls_directory_data.EndAddressOfRawData == tls_directory_data.StartAddressOfRawData)
+ {
+ try
+ {
+ pe.va_to_rva(static_cast<typename PEClassType::BaseSize>(tls_directory_data.EndAddressOfRawData));
+ }
+ catch(const pe_exception&)
+ {
+ //Fix addressess on incorrect conversion
+ tls_directory_data.EndAddressOfRawData = tls_directory_data.StartAddressOfRawData = 0;
+ }
+ }
+
+ if(tls_directory_data.StartAddressOfRawData &&
+ pe.section_data_length_from_va(static_cast<typename PEClassType::BaseSize>(tls_directory_data.StartAddressOfRawData),
+ static_cast<typename PEClassType::BaseSize>(tls_directory_data.StartAddressOfRawData), section_data_virtual, true)
+ < (tls_directory_data.EndAddressOfRawData - tls_directory_data.StartAddressOfRawData))
+ throw pe_exception("Incorrect TLS directory", pe_exception::incorrect_tls_directory);
+
+ //Fill TLS info
+ //VAs are not checked
+ ret.set_raw_data_start_rva(tls_directory_data.StartAddressOfRawData ? pe.va_to_rva(static_cast<typename PEClassType::BaseSize>(tls_directory_data.StartAddressOfRawData)) : 0);
+ ret.set_raw_data_end_rva(tls_directory_data.EndAddressOfRawData ? pe.va_to_rva(static_cast<typename PEClassType::BaseSize>(tls_directory_data.EndAddressOfRawData)) : 0);
+ ret.set_index_rva(tls_directory_data.AddressOfIndex ? pe.va_to_rva(static_cast<typename PEClassType::BaseSize>(tls_directory_data.AddressOfIndex)) : 0);
+ ret.set_callbacks_rva(tls_directory_data.AddressOfCallBacks ? pe.va_to_rva(static_cast<typename PEClassType::BaseSize>(tls_directory_data.AddressOfCallBacks)) : 0);
+ ret.set_size_of_zero_fill(tls_directory_data.SizeOfZeroFill);
+ ret.set_characteristics(tls_directory_data.Characteristics);
+
+ if(tls_directory_data.StartAddressOfRawData && tls_directory_data.StartAddressOfRawData != tls_directory_data.EndAddressOfRawData)
+ {
+ //Read and save TLS RAW data
+ ret.set_raw_data(std::string(
+ pe.section_data_from_va(static_cast<typename PEClassType::BaseSize>(tls_directory_data.StartAddressOfRawData), section_data_virtual, true),
+ static_cast<uint32_t>(tls_directory_data.EndAddressOfRawData - tls_directory_data.StartAddressOfRawData)));
+ }
+
+ //If file has TLS callbacks
+ if(ret.get_callbacks_rva())
+ {
+ //Read callbacks VAs
+ uint32_t current_tls_callback = 0;
+
+ while(true)
+ {
+ //Read TLS callback VA
+ typename PEClassType::BaseSize va = pe.section_data_from_va<typename PEClassType::BaseSize>(static_cast<typename PEClassType::BaseSize>(tls_directory_data.AddressOfCallBacks + current_tls_callback), section_data_virtual, true);
+ if(va == 0)
+ break;
+
+ //Save it
+ ret.add_tls_callback(pe.va_to_rva(va, false));
+
+ //Move to next callback VA
+ current_tls_callback += sizeof(va);
+ }
+ }
+
+ return ret;
+}
+
+//Rebuilder of TLS structures
+//If write_tls_callbacks = true, TLS callbacks VAs will be written to their place
+//If write_tls_data = true, TLS data will be written to its place
+//If you have chosen to rewrite raw data, only (EndAddressOfRawData - StartAddressOfRawData) bytes will be written, not the full length of string
+//representing raw data content
+//auto_strip_last_section - if true and TLS are placed in the last section, it will be automatically stripped
+//Note/TODO: TLS Callbacks array is not DWORD-aligned (seems to work on WinXP - Win7)
+template<typename PEClassType>
+const image_directory rebuild_tls_base(pe_base& pe, const tls_info& info, section& tls_section, uint32_t offset_from_section_start, bool write_tls_callbacks, bool write_tls_data, tls_data_expand_type expand, bool save_to_pe_header, bool auto_strip_last_section)
+{
+ //Check that tls_section is attached to this PE image
+ if(!pe.section_attached(tls_section))
+ throw pe_exception("TLS section must be attached to PE file", pe_exception::section_is_not_attached);
+
+ uint32_t tls_data_pos = pe_utils::align_up(offset_from_section_start, sizeof(typename PEClassType::BaseSize));
+ uint32_t needed_size = sizeof(typename PEClassType::TLSStruct); //Calculate needed size for TLS table
+
+ //Check if tls_section is last one. If it's not, check if there's enough place for TLS data
+ if(&tls_section != &*(pe.get_image_sections().end() - 1) &&
+ (tls_section.empty() || pe_utils::align_up(tls_section.get_size_of_raw_data(), pe.get_file_alignment()) < needed_size + tls_data_pos))
+ throw pe_exception("Insufficient space for TLS directory", pe_exception::insufficient_space);
+
+ //Check raw data positions
+ if(info.get_raw_data_end_rva() < info.get_raw_data_start_rva() || info.get_index_rva() == 0)
+ throw pe_exception("Incorrect TLS directory", pe_exception::incorrect_tls_directory);
+
+ std::string& raw_data = tls_section.get_raw_data();
+
+ //This will be done only if tls_section is the last section of image or for section with unaligned raw length of data
+ if(raw_data.length() < needed_size + tls_data_pos)
+ raw_data.resize(needed_size + tls_data_pos); //Expand section raw data
+
+ //Create and fill TLS structure
+ typename PEClassType::TLSStruct tls_struct = {0};
+
+ typename PEClassType::BaseSize va;
+ if(info.get_raw_data_start_rva())
+ {
+ pe.rva_to_va(info.get_raw_data_start_rva(), va);
+ tls_struct.StartAddressOfRawData = va;
+ tls_struct.SizeOfZeroFill = info.get_size_of_zero_fill();
+ }
+
+ if(info.get_raw_data_end_rva())
+ {
+ pe.rva_to_va(info.get_raw_data_end_rva(), va);
+ tls_struct.EndAddressOfRawData = va;
+ }
+
+ pe.rva_to_va(info.get_index_rva(), va);
+ tls_struct.AddressOfIndex = va;
+
+ if(info.get_callbacks_rva())
+ {
+ pe.rva_to_va(info.get_callbacks_rva(), va);
+ tls_struct.AddressOfCallBacks = va;
+ }
+
+ tls_struct.Characteristics = info.get_characteristics();
+
+ //Save TLS structure
+ memcpy(&raw_data[tls_data_pos], &tls_struct, sizeof(tls_struct));
+
+ //If we are asked to rewrite TLS raw data
+ if(write_tls_data && info.get_raw_data_start_rva() && info.get_raw_data_start_rva() != info.get_raw_data_end_rva())
+ {
+ try
+ {
+ //Check if we're going to write TLS raw data to an existing section (not to PE headers)
+ section& raw_data_section = pe.section_from_rva(info.get_raw_data_start_rva());
+ pe.expand_section(raw_data_section, info.get_raw_data_start_rva(), info.get_raw_data_end_rva() - info.get_raw_data_start_rva(), expand == tls_data_expand_raw ? pe_base::expand_section_raw : pe_base::expand_section_virtual);
+ }
+ catch(const pe_exception&)
+ {
+ //If no section is presented by StartAddressOfRawData, just go to next step
+ }
+
+ unsigned long write_raw_data_size = info.get_raw_data_end_rva() - info.get_raw_data_start_rva();
+ unsigned long available_raw_length = 0;
+
+ //Check if there's enough RAW space to write raw TLS data...
+ if((available_raw_length = pe.section_data_length_from_rva(info.get_raw_data_start_rva(), info.get_raw_data_start_rva(), section_data_raw, true))
+ < info.get_raw_data_end_rva() - info.get_raw_data_start_rva())
+ {
+ //Check if there's enough virtual space for it...
+ if(pe.section_data_length_from_rva(info.get_raw_data_start_rva(), info.get_raw_data_start_rva(), section_data_virtual, true)
+ < info.get_raw_data_end_rva() - info.get_raw_data_start_rva())
+ throw pe_exception("Insufficient space for TLS raw data", pe_exception::insufficient_space);
+ else
+ write_raw_data_size = available_raw_length; //We'll write just a part of full raw data
+ }
+
+ //Write raw TLS data, if any
+ if(write_raw_data_size != 0)
+ memcpy(pe.section_data_from_rva(info.get_raw_data_start_rva(), true), info.get_raw_data().data(), write_raw_data_size);
+ }
+
+ //If we are asked to rewrite TLS callbacks addresses
+ if(write_tls_callbacks && info.get_callbacks_rva())
+ {
+ unsigned long needed_callback_size = static_cast<unsigned long>((info.get_tls_callbacks().size() + 1 /* last null element */) * sizeof(typename PEClassType::BaseSize));
+
+ try
+ {
+ //Check if we're going to write TLS callbacks VAs to an existing section (not to PE headers)
+ section& raw_data_section = pe.section_from_rva(info.get_callbacks_rva());
+ pe.expand_section(raw_data_section, info.get_callbacks_rva(), needed_callback_size, pe_base::expand_section_raw);
+ }
+ catch(const pe_exception&)
+ {
+ //If no section is presented by RVA of callbacks, just go to next step
+ }
+
+ //Check if there's enough space to write callbacks TLS data...
+ if(pe.section_data_length_from_rva(info.get_callbacks_rva(), info.get_callbacks_rva(), section_data_raw, true)
+ < needed_callback_size - sizeof(typename PEClassType::BaseSize) /* last zero element can be virtual only */)
+ throw pe_exception("Insufficient space for TLS callbacks data", pe_exception::insufficient_space);
+
+ if(pe.section_data_length_from_rva(info.get_callbacks_rva(), info.get_callbacks_rva(), section_data_virtual, true)
+ < needed_callback_size /* check here full virtual data length available */)
+ throw pe_exception("Insufficient space for TLS callbacks data", pe_exception::insufficient_space);
+
+ std::vector<typename PEClassType::BaseSize> callbacks_virtual_addresses;
+ callbacks_virtual_addresses.reserve(info.get_tls_callbacks().size() + 1 /* last null element */);
+
+ //Convert TLS RVAs to VAs
+ for(tls_info::tls_callback_list::const_iterator it = info.get_tls_callbacks().begin(); it != info.get_tls_callbacks().end(); ++it)
+ {
+ typename PEClassType::BaseSize cb_va = 0;
+ pe.rva_to_va(*it, cb_va);
+ callbacks_virtual_addresses.push_back(cb_va);
+ }
+
+ //Ending null element
+ callbacks_virtual_addresses.push_back(0);
+
+ //Write callbacks TLS data
+ memcpy(pe.section_data_from_rva(info.get_callbacks_rva(), true), &callbacks_virtual_addresses[0], needed_callback_size);
+ }
+
+ //Adjust section raw and virtual sizes
+ pe.recalculate_section_sizes(tls_section, auto_strip_last_section);
+
+ image_directory ret(pe.rva_from_section_offset(tls_section, tls_data_pos), needed_size);
+
+ //If auto-rewrite of PE headers is required
+ if(save_to_pe_header)
+ {
+ pe.set_directory_rva(image_directory_entry_tls, ret.get_rva());
+ pe.set_directory_size(image_directory_entry_tls, ret.get_size());
+ }
+
+ return ret;
+}
+}
diff --git a/tools/pe_bliss/pe_tls.h b/tools/pe_bliss/pe_tls.h
new file mode 100644
index 0000000000..316e208147
--- /dev/null
+++ b/tools/pe_bliss/pe_tls.h
@@ -0,0 +1,122 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <memory>
+#include <istream>
+#include "pe_base.h"
+#include "pe_directory.h"
+
+namespace pe_bliss
+{
+//Class representing TLS info
+//We use "DWORD" type to represent RVAs, because RVA is
+//always 32bit even in PE+
+class tls_info
+{
+public:
+ typedef std::vector<uint32_t> tls_callback_list;
+
+public:
+ //Default constructor
+ tls_info();
+
+ //Returns start RVA of TLS raw data
+ uint32_t get_raw_data_start_rva() const;
+ //Returns end RVA of TLS raw data
+ uint32_t get_raw_data_end_rva() const;
+ //Returns TLS index RVA
+ uint32_t get_index_rva() const;
+ //Returns TLS callbacks RVA
+ uint32_t get_callbacks_rva() const;
+ //Returns size of zero fill
+ uint32_t get_size_of_zero_fill() const;
+ //Returns characteristics
+ uint32_t get_characteristics() const;
+ //Returns raw TLS data
+ const std::string& get_raw_data() const;
+ //Returns TLS callbacks addresses
+ const tls_callback_list& get_tls_callbacks() const;
+
+public: //These functions do not change everything inside image, they are used by PE class
+ //You can also use them to rebuild TLS directory
+
+ //Sets start RVA of TLS raw data
+ void set_raw_data_start_rva(uint32_t rva);
+ //Sets end RVA of TLS raw data
+ void set_raw_data_end_rva(uint32_t rva);
+ //Sets TLS index RVA
+ void set_index_rva(uint32_t rva);
+ //Sets TLS callbacks RVA
+ void set_callbacks_rva(uint32_t rva);
+ //Sets size of zero fill
+ void set_size_of_zero_fill(uint32_t size);
+ //Sets characteristics
+ void set_characteristics(uint32_t characteristics);
+ //Sets raw TLS data
+ void set_raw_data(const std::string& data);
+ //Returns TLS callbacks addresses
+ tls_callback_list& get_tls_callbacks();
+ //Adds TLS callback
+ void add_tls_callback(uint32_t rva);
+ //Clears TLS callbacks list
+ void clear_tls_callbacks();
+ //Recalculates end address of raw TLS data
+ void recalc_raw_data_end_rva();
+
+private:
+ uint32_t start_rva_, end_rva_, index_rva_, callbacks_rva_;
+ uint32_t size_of_zero_fill_, characteristics_;
+
+ //Raw TLS data
+ std::string raw_data_;
+
+ //TLS callback RVAs
+ tls_callback_list callbacks_;
+};
+
+//Represents type of expanding of TLS section containing raw data
+//(Works only if you are writing TLS raw data to tls_section and it is the last one in the PE image on the moment of TLS rebuild)
+enum tls_data_expand_type
+{
+ tls_data_expand_raw, //If there is not enough raw space for raw TLS data, it can be expanded
+ tls_data_expand_virtual //If there is not enough virtual place for raw TLS data, it can be expanded
+};
+
+
+//Get TLS info
+//If image does not have TLS, throws an exception
+const tls_info get_tls_info(const pe_base& pe);
+
+template<typename PEClassType>
+const tls_info get_tls_info_base(const pe_base& pe);
+
+//Rebuilder of TLS structures
+//If write_tls_callbacks = true, TLS callbacks VAs will be written to their place
+//If write_tls_data = true, TLS data will be written to its place
+//If you have chosen to rewrite raw data, only (EndAddressOfRawData - StartAddressOfRawData) bytes will be written, not the full length of string
+//representing raw data content
+//auto_strip_last_section - if true and TLS are placed in the last section, it will be automatically stripped
+const image_directory rebuild_tls(pe_base& pe, const tls_info& info, section& tls_section, uint32_t offset_from_section_start = 0, bool write_tls_callbacks = true, bool write_tls_data = true, tls_data_expand_type expand = tls_data_expand_raw, bool save_to_pe_header = true, bool auto_strip_last_section = true);
+
+template<typename PEClassType>
+const image_directory rebuild_tls_base(pe_base& pe, const tls_info& info, section& tls_section, uint32_t offset_from_section_start = 0, bool write_tls_callbacks = true, bool write_tls_data = true, tls_data_expand_type expand = tls_data_expand_raw, bool save_to_pe_header = true, bool auto_strip_last_section = true);
+}
diff --git a/tools/pe_bliss/resource_bitmap_reader.cpp b/tools/pe_bliss/resource_bitmap_reader.cpp
new file mode 100644
index 0000000000..3546461f53
--- /dev/null
+++ b/tools/pe_bliss/resource_bitmap_reader.cpp
@@ -0,0 +1,86 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include <cmath>
+#include "resource_bitmap_reader.h"
+#include "pe_resource_viewer.h"
+#include "pe_structures.h"
+
+namespace pe_bliss
+{
+using namespace pe_win;
+
+resource_bitmap_reader::resource_bitmap_reader(const pe_resource_viewer& res)
+ :res_(res)
+{}
+
+//Returns bitmap data by name and index in language directory (instead of language) (minimum checks of format correctness)
+const std::string resource_bitmap_reader::get_bitmap_by_name(const std::wstring& name, uint32_t index) const
+{
+ return create_bitmap(res_.get_resource_data_by_name(pe_resource_viewer::resource_bitmap, name, index).get_data());
+}
+
+//Returns bitmap data by name and language (minimum checks of format correctness)
+const std::string resource_bitmap_reader::get_bitmap_by_name(uint32_t language, const std::wstring& name) const
+{
+ return create_bitmap(res_.get_resource_data_by_name(language, pe_resource_viewer::resource_bitmap, name).get_data());
+}
+
+//Returns bitmap data by ID and language (minimum checks of format correctness)
+const std::string resource_bitmap_reader::get_bitmap_by_id_lang(uint32_t language, uint32_t id) const
+{
+ return create_bitmap(res_.get_resource_data_by_id(language, pe_resource_viewer::resource_bitmap, id).get_data());
+}
+
+//Returns bitmap data by ID and index in language directory (instead of language) (minimum checks of format correctness)
+const std::string resource_bitmap_reader::get_bitmap_by_id(uint32_t id, uint32_t index) const
+{
+ return create_bitmap(res_.get_resource_data_by_id(pe_resource_viewer::resource_bitmap, id, index).get_data());
+}
+
+//Helper function of creating bitmap header
+const std::string resource_bitmap_reader::create_bitmap(const std::string& resource_data)
+{
+ //Create bitmap file header
+ bitmapfileheader header = {0};
+ header.bfType = 0x4d42; //Signature "BM"
+ header.bfOffBits = sizeof(bitmapfileheader) + sizeof(bitmapinfoheader); //Offset to bitmap bits
+ header.bfSize = static_cast<uint32_t>(sizeof(bitmapfileheader) + resource_data.length()); //Size of bitmap
+
+ //Check size of resource data
+ if(resource_data.length() < sizeof(bitmapinfoheader))
+ throw pe_exception("Incorrect resource bitmap", pe_exception::resource_incorrect_bitmap);
+
+ {
+ //Get bitmap info header
+ const bitmapinfoheader* info = reinterpret_cast<const bitmapinfoheader*>(resource_data.data());
+
+ //If color table is present, skip it
+ if(info->biClrUsed != 0)
+ header.bfOffBits += 4 * info->biClrUsed; //Add this size to offset to bitmap bits
+ else if(info->biBitCount <= 8)
+ header.bfOffBits += 4 * static_cast<uint32_t>(std::pow(2.f, info->biBitCount)); //Add this size to offset to bitmap bits
+ }
+
+ //Return final bitmap data
+ return std::string(reinterpret_cast<const char*>(&header), sizeof(bitmapfileheader)) + resource_data;
+}
+}
diff --git a/tools/pe_bliss/resource_bitmap_reader.h b/tools/pe_bliss/resource_bitmap_reader.h
new file mode 100644
index 0000000000..f2b92bbde7
--- /dev/null
+++ b/tools/pe_bliss/resource_bitmap_reader.h
@@ -0,0 +1,50 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <string>
+#include "stdint_defs.h"
+
+namespace pe_bliss
+{
+class pe_resource_viewer;
+
+class resource_bitmap_reader
+{
+public:
+ resource_bitmap_reader(const pe_resource_viewer& res);
+
+ //Returns bitmap data by name and language (minimum checks of format correctness)
+ const std::string get_bitmap_by_name(uint32_t language, const std::wstring& name) const;
+ //Returns bitmap data by name and index in language directory (instead of language) (minimum checks of format correctness)
+ const std::string get_bitmap_by_name(const std::wstring& name, uint32_t index = 0) const;
+ //Returns bitmap data by ID and language (minimum checks of format correctness)
+ const std::string get_bitmap_by_id_lang(uint32_t language, uint32_t id) const;
+ //Returns bitmap data by ID and index in language directory (instead of language) (minimum checks of format correctness)
+ const std::string get_bitmap_by_id(uint32_t id, uint32_t index = 0) const;
+
+private:
+ //Helper function of creating bitmap header
+ static const std::string create_bitmap(const std::string& resource_data);
+
+ const pe_resource_viewer& res_;
+};
+}
diff --git a/tools/pe_bliss/resource_bitmap_writer.cpp b/tools/pe_bliss/resource_bitmap_writer.cpp
new file mode 100644
index 0000000000..3445a08445
--- /dev/null
+++ b/tools/pe_bliss/resource_bitmap_writer.cpp
@@ -0,0 +1,75 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include "resource_bitmap_writer.h"
+#include "pe_resource_manager.h"
+#include "pe_structures.h"
+
+namespace pe_bliss
+{
+using namespace pe_win;
+
+resource_bitmap_writer::resource_bitmap_writer(pe_resource_manager& res)
+ :res_(res)
+{}
+
+//Adds bitmap from bitmap file data. If bitmap already exists, replaces it
+//timestamp will be used for directories that will be added
+void resource_bitmap_writer::add_bitmap(const std::string& bitmap_file, uint32_t id, uint32_t language, uint32_t codepage, uint32_t timestamp)
+{
+ //Check bitmap data a little
+ if(bitmap_file.length() < sizeof(bitmapfileheader))
+ throw pe_exception("Incorrect resource bitmap", pe_exception::resource_incorrect_bitmap);
+
+ resource_directory_entry new_entry;
+ new_entry.set_id(id);
+
+ //Add bitmap
+ res_.add_resource(bitmap_file.substr(sizeof(bitmapfileheader)), pe_resource_viewer::resource_bitmap, new_entry, resource_directory::entry_finder(id), language, codepage, timestamp);
+}
+
+//Adds bitmap from bitmap file data. If bitmap already exists, replaces it
+//timestamp will be used for directories that will be added
+void resource_bitmap_writer::add_bitmap(const std::string& bitmap_file, const std::wstring& name, uint32_t language, uint32_t codepage, uint32_t timestamp)
+{
+ //Check bitmap data a little
+ if(bitmap_file.length() < sizeof(bitmapfileheader))
+ throw pe_exception("Incorrect resource bitmap", pe_exception::resource_incorrect_bitmap);
+
+ resource_directory_entry new_entry;
+ new_entry.set_name(name);
+
+ //Add bitmap
+ res_.add_resource(bitmap_file.substr(sizeof(bitmapfileheader)), pe_resource_viewer::resource_bitmap, new_entry, resource_directory::entry_finder(name), language, codepage, timestamp);
+}
+
+//Removes bitmap by name/ID and language
+bool resource_bitmap_writer::remove_bitmap(const std::wstring& name, uint32_t language)
+{
+ return res_.remove_resource(pe_resource_viewer::resource_bitmap, name, language);
+}
+
+//Removes bitmap by name/ID and language
+bool resource_bitmap_writer::remove_bitmap(uint32_t id, uint32_t language)
+{
+ return res_.remove_resource(pe_resource_viewer::resource_bitmap, id, language);
+}
+}
diff --git a/tools/pe_bliss/resource_bitmap_writer.h b/tools/pe_bliss/resource_bitmap_writer.h
new file mode 100644
index 0000000000..4b8ea72705
--- /dev/null
+++ b/tools/pe_bliss/resource_bitmap_writer.h
@@ -0,0 +1,47 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <string>
+#include "stdint_defs.h"
+
+namespace pe_bliss
+{
+class pe_resource_manager;
+
+class resource_bitmap_writer
+{
+public:
+ resource_bitmap_writer(pe_resource_manager& res);
+
+ //Adds bitmap from bitmap file data. If bitmap already exists, replaces it
+ //timestamp will be used for directories that will be added
+ void add_bitmap(const std::string& bitmap_file, uint32_t id, uint32_t language, uint32_t codepage = 0, uint32_t timestamp = 0);
+ void add_bitmap(const std::string& bitmap_file, const std::wstring& name, uint32_t language, uint32_t codepage = 0, uint32_t timestamp = 0);
+
+ //Removes bitmap by name/ID and language
+ bool remove_bitmap(const std::wstring& name, uint32_t language);
+ bool remove_bitmap(uint32_t id, uint32_t language);
+
+private:
+ pe_resource_manager& res_;
+};
+}
diff --git a/tools/pe_bliss/resource_cursor_icon_reader.cpp b/tools/pe_bliss/resource_cursor_icon_reader.cpp
new file mode 100644
index 0000000000..28a259163e
--- /dev/null
+++ b/tools/pe_bliss/resource_cursor_icon_reader.cpp
@@ -0,0 +1,521 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include <algorithm>
+#include "resource_cursor_icon_reader.h"
+#include "pe_structures.h"
+#include "pe_resource_viewer.h"
+
+namespace pe_bliss
+{
+using namespace pe_win;
+
+resource_cursor_icon_reader::resource_cursor_icon_reader(const pe_resource_viewer& res)
+ :res_(res)
+{}
+
+//Helper function of creating icon headers from ICON_GROUP resource data
+//Returns icon count
+uint16_t resource_cursor_icon_reader::format_icon_headers(std::string& ico_data, const std::string& resource_data)
+{
+ //Check resource data size
+ if(resource_data.length() < sizeof(ico_header))
+ throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon);
+
+ //Get icon header
+ const ico_header* info = reinterpret_cast<const ico_header*>(resource_data.data());
+
+ //Check resource data size
+ if(resource_data.length() < sizeof(ico_header) + info->Count * sizeof(icon_group))
+ throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon);
+
+ //Reserve memory to speed up a little
+ ico_data.reserve(sizeof(ico_header) + info->Count * sizeof(icondirentry));
+ ico_data.append(reinterpret_cast<const char*>(info), sizeof(ico_header));
+
+ //Iterate over all listed icons
+ uint32_t offset = sizeof(ico_header) + sizeof(icondirentry) * info->Count;
+ for(uint16_t i = 0; i != info->Count; ++i)
+ {
+ const icon_group* group = reinterpret_cast<const icon_group*>(resource_data.data() + sizeof(ico_header) + i * sizeof(icon_group));
+
+ //Fill icon data
+ icondirentry direntry;
+ direntry.BitCount = group->BitCount;
+ direntry.ColorCount = group->ColorCount;
+ direntry.Height = group->Height;
+ direntry.Planes = group->Planes;
+ direntry.Reserved = group->Reserved;
+ direntry.SizeInBytes = group->SizeInBytes;
+ direntry.Width = group->Width;
+ direntry.ImageOffset = offset;
+
+ //Add icon header to returned value
+ ico_data.append(reinterpret_cast<const char*>(&direntry), sizeof(icondirentry));
+
+ offset += group->SizeInBytes;
+ }
+
+ //Return icon count
+ return info->Count;
+}
+
+//Returns single icon data by ID and language (minimum checks of format correctness)
+const std::string resource_cursor_icon_reader::get_single_icon_by_id_lang(uint32_t language, uint32_t id) const
+{
+ //Get icon headers
+ std::string icon_data(lookup_icon_group_data_by_icon(id, language));
+ //Append icon data
+ icon_data.append(res_.get_resource_data_by_id(language, pe_resource_viewer::resource_icon, id).get_data());
+ return icon_data;
+}
+
+//Returns single icon data by ID and index in language directory (instead of language) (minimum checks of format correctness)
+const std::string resource_cursor_icon_reader::get_single_icon_by_id(uint32_t id, uint32_t index) const
+{
+ pe_resource_viewer::resource_language_list languages(res_.list_resource_languages(pe_resource_viewer::resource_icon, id));
+ if(languages.size() <= index)
+ throw pe_exception("Resource data entry not found", pe_exception::resource_data_entry_not_found);
+
+ //Get icon headers
+ std::string icon_data(lookup_icon_group_data_by_icon(id, languages.at(index)));
+ //Append icon data
+ icon_data.append(res_.get_resource_data_by_id(pe_resource_viewer::resource_icon, id, index).get_data());
+ return icon_data;
+}
+
+//Returns icon data by name and index in language directory (instead of language) (minimum checks of format correctness)
+const std::string resource_cursor_icon_reader::get_icon_by_name(const std::wstring& name, uint32_t index) const
+{
+ std::string ret;
+
+ //Get resource by name and index
+ const std::string data = res_.get_resource_data_by_name(pe_resource_viewer::resource_icon_group, name, index).get_data();
+
+ //Create icon headers
+ uint16_t icon_count = format_icon_headers(ret, data);
+
+ //Append icon data
+ for(uint16_t i = 0; i != icon_count; ++i)
+ {
+ const icon_group* group = reinterpret_cast<const icon_group*>(data.data() + sizeof(ico_header) + i * sizeof(icon_group));
+ ret += res_.get_resource_data_by_id(pe_resource_viewer::resource_icon, group->Number, index).get_data();
+ }
+
+ return ret;
+}
+
+//Returns icon data by name and language (minimum checks of format correctness)
+const std::string resource_cursor_icon_reader::get_icon_by_name(uint32_t language, const std::wstring& name) const
+{
+ std::string ret;
+
+ //Get resource by name and language
+ const std::string data = res_.get_resource_data_by_name(language, pe_resource_viewer::resource_icon_group, name).get_data();
+
+ //Create icon headers
+ uint16_t icon_count = format_icon_headers(ret, data);
+
+ //Append icon data
+ for(uint16_t i = 0; i != icon_count; ++i)
+ {
+ const icon_group* group = reinterpret_cast<const icon_group*>(data.data() + sizeof(ico_header) + i * sizeof(icon_group));
+ ret += res_.get_resource_data_by_id(language, pe_resource_viewer::resource_icon, group->Number).get_data();
+ }
+
+ return ret;
+}
+
+//Returns icon data by ID and language (minimum checks of format correctness)
+const std::string resource_cursor_icon_reader::get_icon_by_id_lang(uint32_t language, uint32_t id) const
+{
+ std::string ret;
+
+ //Get resource by language and id
+ const std::string data = res_.get_resource_data_by_id(language, pe_resource_viewer::resource_icon_group, id).get_data();
+
+ //Create icon headers
+ uint16_t icon_count = format_icon_headers(ret, data);
+
+ //Append icon data
+ for(uint16_t i = 0; i != icon_count; ++i)
+ {
+ const icon_group* group = reinterpret_cast<const icon_group*>(data.data() + sizeof(ico_header) + i * sizeof(icon_group));
+ ret += res_.get_resource_data_by_id(language, pe_resource_viewer::resource_icon, group->Number).get_data();
+ }
+
+ return ret;
+}
+
+//Returns icon data by ID and index in language directory (instead of language) (minimum checks of format correctness)
+const std::string resource_cursor_icon_reader::get_icon_by_id(uint32_t id, uint32_t index) const
+{
+ std::string ret;
+
+ //Get resource by id and index
+ const std::string data = res_.get_resource_data_by_id(pe_resource_viewer::resource_icon_group, id, index).get_data();
+
+ //Create icon headers
+ uint16_t icon_count = format_icon_headers(ret, data);
+
+ //Append icon data
+ for(uint16_t i = 0; i != icon_count; ++i)
+ {
+ const icon_group* group = reinterpret_cast<const icon_group*>(data.data() + sizeof(ico_header) + i * sizeof(icon_group));
+ ret += res_.get_resource_data_by_id(pe_resource_viewer::resource_icon, group->Number, index).get_data();
+ }
+
+ return ret;
+}
+
+//Checks for icon presence inside icon group, fills icon headers if found
+bool resource_cursor_icon_reader::check_icon_presence(const std::string& icon_group_resource_data, uint32_t icon_id, std::string& ico_data)
+{
+ //Check resource data size
+ if(icon_group_resource_data.length() < sizeof(ico_header))
+ throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon);
+
+ //Get icon header
+ const ico_header* info = reinterpret_cast<const ico_header*>(icon_group_resource_data.data());
+
+ //Check resource data size
+ if(icon_group_resource_data.length() < sizeof(ico_header) + info->Count * sizeof(icon_group))
+ throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon);
+
+ for(uint16_t i = 0; i != info->Count; ++i)
+ {
+ const icon_group* group = reinterpret_cast<const icon_group*>(icon_group_resource_data.data() + sizeof(ico_header) + i * sizeof(icon_group));
+ if(group->Number == icon_id)
+ {
+ //Reserve memory to speed up a little
+ ico_data.reserve(sizeof(ico_header) + sizeof(icondirentry));
+ //Write single-icon icon header
+ ico_header new_header = *info;
+ new_header.Count = 1;
+ ico_data.append(reinterpret_cast<const char*>(&new_header), sizeof(ico_header));
+
+ //Fill icon data
+ icondirentry direntry;
+ direntry.BitCount = group->BitCount;
+ direntry.ColorCount = group->ColorCount;
+ direntry.Height = group->Height;
+ direntry.Planes = group->Planes;
+ direntry.Reserved = group->Reserved;
+ direntry.SizeInBytes = group->SizeInBytes;
+ direntry.Width = group->Width;
+ direntry.ImageOffset = sizeof(ico_header) + sizeof(icondirentry);
+ ico_data.append(reinterpret_cast<const char*>(&direntry), sizeof(direntry));
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//Looks up icon group by icon id and returns full icon headers if found
+const std::string resource_cursor_icon_reader::lookup_icon_group_data_by_icon(uint32_t icon_id, uint32_t language) const
+{
+ std::string icon_header_data;
+
+ {
+ //List all ID-resources
+ pe_resource_viewer::resource_id_list ids(res_.list_resource_ids(pe_resource_viewer::resource_icon_group));
+
+ for(pe_resource_viewer::resource_id_list::const_iterator it = ids.begin(); it != ids.end(); ++it)
+ {
+ pe_resource_viewer::resource_language_list group_languages(res_.list_resource_languages(pe_resource_viewer::resource_icon_group, *it));
+ if(std::find(group_languages.begin(), group_languages.end(), language) != group_languages.end()
+ && check_icon_presence(res_.get_resource_data_by_id(language, pe_resource_viewer::resource_icon_group, *it).get_data(), icon_id, icon_header_data))
+ return icon_header_data;
+ }
+ }
+
+ {
+ //List all named resources
+ pe_resource_viewer::resource_name_list names(res_.list_resource_names(pe_resource_viewer::resource_icon_group));
+ for(pe_resource_viewer::resource_name_list::const_iterator it = names.begin(); it != names.end(); ++it)
+ {
+ pe_resource_viewer::resource_language_list group_languages(res_.list_resource_languages(pe_resource_viewer::resource_icon_group, *it));
+ if(std::find(group_languages.begin(), group_languages.end(), language) != group_languages.end()
+ && check_icon_presence(res_.get_resource_data_by_name(language, pe_resource_viewer::resource_icon_group, *it).get_data(), icon_id, icon_header_data))
+ return icon_header_data;
+ }
+ }
+
+ throw pe_exception("No icon group find for requested icon", pe_exception::no_icon_group_found);
+}
+
+//Returns single cursor data by ID and language (minimum checks of format correctness)
+const std::string resource_cursor_icon_reader::get_single_cursor_by_id_lang(uint32_t language, uint32_t id) const
+{
+ std::string raw_cursor_data(res_.get_resource_data_by_id(language, pe_resource_viewer::resource_cursor, id).get_data());
+ //Get cursor headers
+ std::string cursor_data(lookup_cursor_group_data_by_cursor(id, language, raw_cursor_data));
+ //Append cursor data
+ cursor_data.append(raw_cursor_data.substr(sizeof(uint16_t) * 2 /* hotspot position */));
+ return cursor_data;
+}
+
+//Returns single cursor data by ID and index in language directory (instead of language) (minimum checks of format correctness)
+const std::string resource_cursor_icon_reader::get_single_cursor_by_id(uint32_t id, uint32_t index) const
+{
+ pe_resource_viewer::resource_language_list languages(res_.list_resource_languages(pe_resource_viewer::resource_cursor, id));
+ if(languages.size() <= index)
+ throw pe_exception("Resource data entry not found", pe_exception::resource_data_entry_not_found);
+
+ std::string raw_cursor_data(res_.get_resource_data_by_id(pe_resource_viewer::resource_cursor, id, index).get_data());
+ //Get cursor headers
+ std::string cursor_data(lookup_cursor_group_data_by_cursor(id, languages.at(index), raw_cursor_data));
+ //Append cursor data
+ cursor_data.append(raw_cursor_data.substr(sizeof(uint16_t) * 2 /* hotspot position */));
+ return cursor_data;
+}
+
+//Helper function of creating cursor headers
+//Returns cursor count
+uint16_t resource_cursor_icon_reader::format_cursor_headers(std::string& cur_data, const std::string& resource_data, uint32_t language, uint32_t index) const
+{
+ //Check resource data length
+ if(resource_data.length() < sizeof(cursor_header))
+ throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor);
+
+ const cursor_header* info = reinterpret_cast<const cursor_header*>(resource_data.data());
+
+ //Check resource data length
+ if(resource_data.length() < sizeof(cursor_header) + sizeof(cursor_group) * info->Count)
+ throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor);
+
+ //Reserve needed space to speed up a little
+ cur_data.reserve(sizeof(cursor_header) + info->Count * sizeof(cursordirentry));
+ //Add cursor header
+ cur_data.append(reinterpret_cast<const char*>(info), sizeof(cursor_header));
+
+ //Iterate over all cursors listed in cursor group
+ uint32_t offset = sizeof(cursor_header) + sizeof(cursordirentry) * info->Count;
+ for(uint16_t i = 0; i != info->Count; ++i)
+ {
+ const cursor_group* group = reinterpret_cast<const cursor_group*>(resource_data.data() + sizeof(cursor_header) + i * sizeof(cursor_group));
+
+ //Fill cursor info
+ cursordirentry direntry;
+ direntry.ColorCount = 0; //OK
+ direntry.Width = static_cast<uint8_t>(group->Width);
+ direntry.Height = static_cast<uint8_t>(group->Height) / 2;
+ direntry.Reserved = 0;
+
+ //Now read hotspot data from cursor data directory
+ const std::string cursor = index == 0xFFFFFFFF
+ ? res_.get_resource_data_by_id(language, pe_resource_viewer::resource_cursor, group->Number).get_data()
+ : res_.get_resource_data_by_id(pe_resource_viewer::resource_cursor, group->Number, index).get_data();
+ if(cursor.length() < 2 * sizeof(uint16_t))
+ throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor);
+
+ //Here it is - two words in the very beginning of cursor data
+ direntry.HotspotX = *reinterpret_cast<const uint16_t*>(cursor.data());
+ direntry.HotspotY = *reinterpret_cast<const uint16_t*>(cursor.data() + sizeof(uint16_t));
+
+ //Fill the rest data
+ direntry.SizeInBytes = group->SizeInBytes - 2 * sizeof(uint16_t);
+ direntry.ImageOffset = offset;
+
+ //Add cursor header
+ cur_data.append(reinterpret_cast<const char*>(&direntry), sizeof(cursordirentry));
+
+ offset += direntry.SizeInBytes;
+ }
+
+ //Return cursor count
+ return info->Count;
+}
+
+//Returns cursor data by name and language (minimum checks of format correctness)
+const std::string resource_cursor_icon_reader::get_cursor_by_name(uint32_t language, const std::wstring& name) const
+{
+ std::string ret;
+
+ //Get resource by name and language
+ const std::string resource_data = res_.get_resource_data_by_name(language, pe_resource_viewer::resource_cursor_group, name).get_data();
+
+ //Create cursor headers
+ uint16_t cursor_count = format_cursor_headers(ret, resource_data, language);
+
+ //Add cursor data
+ for(uint16_t i = 0; i != cursor_count; ++i)
+ {
+ const cursor_group* group = reinterpret_cast<const cursor_group*>(resource_data.data() + sizeof(cursor_header) + i * sizeof(cursor_group));
+ ret += res_.get_resource_data_by_id(language, pe_resource_viewer::resource_cursor, group->Number).get_data().substr(2 * sizeof(uint16_t));
+ }
+
+ return ret;
+}
+
+//Returns cursor data by name and index in language directory (instead of language) (minimum checks of format correctness)
+const std::string resource_cursor_icon_reader::get_cursor_by_name(const std::wstring& name, uint32_t index) const
+{
+ std::string ret;
+
+ //Get resource by name and index
+ const std::string resource_data = res_.get_resource_data_by_name(pe_resource_viewer::resource_cursor_group, name, index).get_data();
+
+ //Create cursor headers
+ uint16_t cursor_count = format_cursor_headers(ret, resource_data, 0, index);
+
+ //Add cursor data
+ for(uint16_t i = 0; i != cursor_count; ++i)
+ {
+ const cursor_group* group = reinterpret_cast<const cursor_group*>(resource_data.data() + sizeof(cursor_header) + i * sizeof(cursor_group));
+ ret += res_.get_resource_data_by_id(pe_resource_viewer::resource_cursor, group->Number, index).get_data().substr(2 * sizeof(uint16_t));
+ }
+
+ return ret;
+}
+
+//Returns cursor data by ID and language (minimum checks of format correctness)
+const std::string resource_cursor_icon_reader::get_cursor_by_id_lang(uint32_t language, uint32_t id) const
+{
+ std::string ret;
+
+ //Get resource by ID and language
+ const std::string resource_data = res_.get_resource_data_by_id(language, pe_resource_viewer::resource_cursor_group, id).get_data();
+
+ //Create cursor headers
+ uint16_t cursor_count = format_cursor_headers(ret, resource_data, language);
+
+ //Add cursor data
+ for(uint16_t i = 0; i != cursor_count; ++i)
+ {
+ const cursor_group* group = reinterpret_cast<const cursor_group*>(resource_data.data() + sizeof(cursor_header) + i * sizeof(cursor_group));
+ ret += res_.get_resource_data_by_id(language, pe_resource_viewer::resource_cursor, group->Number).get_data().substr(2 * sizeof(uint16_t));
+ }
+
+ return ret;
+}
+
+//Returns cursor data by ID and index in language directory (instead of language) (minimum checks of format correctness)
+const std::string resource_cursor_icon_reader::get_cursor_by_id(uint32_t id, uint32_t index) const
+{
+ std::string ret;
+
+ //Get resource by ID and index
+ const std::string resource_data = res_.get_resource_data_by_id(pe_resource_viewer::resource_cursor_group, id, index).get_data();
+
+ //Create cursor headers
+ uint16_t cursor_count = format_cursor_headers(ret, resource_data, 0, index);
+
+ //Add cursor data
+ for(uint16_t i = 0; i != cursor_count; ++i)
+ {
+ const cursor_group* group = reinterpret_cast<const cursor_group*>(resource_data.data() + sizeof(cursor_header) + i * sizeof(cursor_group));
+ ret += res_.get_resource_data_by_id(pe_resource_viewer::resource_cursor, group->Number, index).get_data().substr(2 * sizeof(uint16_t));
+ }
+
+ return ret;
+}
+
+//Checks for cursor presence inside cursor group, fills cursor headers if found
+bool resource_cursor_icon_reader::check_cursor_presence(const std::string& cursor_group_resource_data, uint32_t cursor_id, std::string& cur_header_data, const std::string& raw_cursor_data)
+{
+ //Check resource data length
+ if(cursor_group_resource_data.length() < sizeof(cursor_header))
+ throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor);
+
+ const cursor_header* info = reinterpret_cast<const cursor_header*>(cursor_group_resource_data.data());
+
+ //Check resource data length
+ if(cursor_group_resource_data.length() < sizeof(cursor_header) + sizeof(cursor_group))
+ throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor);
+
+ //Iterate over all cursors listed in cursor group
+ for(uint16_t i = 0; i != info->Count; ++i)
+ {
+ const cursor_group* group = reinterpret_cast<const cursor_group*>(cursor_group_resource_data.data() + sizeof(cursor_header) + i * sizeof(cursor_group));
+
+ if(group->Number == cursor_id)
+ {
+ //Reserve needed space to speed up a little
+ cur_header_data.reserve(sizeof(cursor_header) + sizeof(cursordirentry));
+ //Write single-cursor cursor header
+ cursor_header new_header = *info;
+ new_header.Count = 1;
+ cur_header_data.append(reinterpret_cast<const char*>(&new_header), sizeof(cursor_header));
+
+ //Fill cursor info
+ cursordirentry direntry;
+ direntry.ColorCount = 0; //OK
+ direntry.Width = static_cast<uint8_t>(group->Width);
+ direntry.Height = static_cast<uint8_t>(group->Height) / 2;
+ direntry.Reserved = 0;
+
+ if(raw_cursor_data.length() < 2 * sizeof(uint16_t))
+ throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor);
+
+ //Here it is - two words in the very beginning of cursor data
+ direntry.HotspotX = *reinterpret_cast<const uint16_t*>(raw_cursor_data.data());
+ direntry.HotspotY = *reinterpret_cast<const uint16_t*>(raw_cursor_data.data() + sizeof(uint16_t));
+
+ //Fill the rest data
+ direntry.SizeInBytes = group->SizeInBytes - 2 * sizeof(uint16_t);
+ direntry.ImageOffset = sizeof(cursor_header) + sizeof(cursordirentry);
+
+ //Add cursor header
+ cur_header_data.append(reinterpret_cast<const char*>(&direntry), sizeof(cursordirentry));
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+//Looks up cursor group by cursor id and returns full cursor headers if found
+const std::string resource_cursor_icon_reader::lookup_cursor_group_data_by_cursor(uint32_t cursor_id, uint32_t language, const std::string& raw_cursor_data) const
+{
+ std::string cursor_header_data;
+
+ {
+ //List all ID-resources
+ pe_resource_viewer::resource_id_list ids(res_.list_resource_ids(pe_resource_viewer::resource_cursor_group));
+
+ for(pe_resource_viewer::resource_id_list::const_iterator it = ids.begin(); it != ids.end(); ++it)
+ {
+ pe_resource_viewer::resource_language_list group_languages(res_.list_resource_languages(pe_resource_viewer::resource_cursor_group, *it));
+ if(std::find(group_languages.begin(), group_languages.end(), language) != group_languages.end()
+ && check_cursor_presence(res_.get_resource_data_by_id(language, pe_resource_viewer::resource_cursor_group, *it).get_data(), cursor_id, cursor_header_data, raw_cursor_data))
+ return cursor_header_data;
+ }
+ }
+
+ {
+ //List all named resources
+ pe_resource_viewer::resource_name_list names(res_.list_resource_names(pe_resource_viewer::resource_cursor_group));
+ for(pe_resource_viewer::resource_name_list::const_iterator it = names.begin(); it != names.end(); ++it)
+ {
+ pe_resource_viewer::resource_language_list group_languages(res_.list_resource_languages(pe_resource_viewer::resource_cursor_group, *it));
+ if(std::find(group_languages.begin(), group_languages.end(), language) != group_languages.end()
+ && check_cursor_presence(res_.get_resource_data_by_name(language, pe_resource_viewer::resource_cursor_group, *it).get_data(), cursor_id, cursor_header_data, raw_cursor_data))
+ return cursor_header_data;
+ }
+ }
+
+ throw pe_exception("No cursor group find for requested icon", pe_exception::no_cursor_group_found);
+}
+}
diff --git a/tools/pe_bliss/resource_cursor_icon_reader.h b/tools/pe_bliss/resource_cursor_icon_reader.h
new file mode 100644
index 0000000000..e34fff419b
--- /dev/null
+++ b/tools/pe_bliss/resource_cursor_icon_reader.h
@@ -0,0 +1,84 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <string>
+#include "stdint_defs.h"
+
+namespace pe_bliss
+{
+class pe_resource_viewer;
+
+class resource_cursor_icon_reader
+{
+public:
+ resource_cursor_icon_reader(const pe_resource_viewer& res);
+
+ //Returns single icon data by ID and language (minimum checks of format correctness)
+ const std::string get_single_icon_by_id_lang(uint32_t language, uint32_t id) const;
+ //Returns single icon data by ID and index in language directory (instead of language) (minimum checks of format correctness)
+ const std::string get_single_icon_by_id(uint32_t id, uint32_t index = 0) const;
+
+ //Returns icon data of group of icons by name and language (minimum checks of format correctness)
+ const std::string get_icon_by_name(uint32_t language, const std::wstring& icon_group_name) const;
+ //Returns icon data of group of icons by name and index in language directory (instead of language) (minimum checks of format correctness)
+ const std::string get_icon_by_name(const std::wstring& icon_group_name, uint32_t index = 0) const;
+ //Returns icon data of group of icons by ID and language (minimum checks of format correctness)
+ const std::string get_icon_by_id_lang(uint32_t language, uint32_t icon_group_id) const;
+ //Returns icon data of group of icons by ID and index in language directory (instead of language) (minimum checks of format correctness)
+ const std::string get_icon_by_id(uint32_t icon_group_id, uint32_t index = 0) const;
+
+ //Returns single cursor data by ID and language (minimum checks of format correctness)
+ const std::string get_single_cursor_by_id_lang(uint32_t language, uint32_t id) const;
+ //Returns single cursor data by ID and index in language directory (instead of language) (minimum checks of format correctness)
+ const std::string get_single_cursor_by_id(uint32_t id, uint32_t index = 0) const;
+
+ //Returns cursor data by name and language (minimum checks of format correctness)
+ const std::string get_cursor_by_name(uint32_t language, const std::wstring& cursor_group_name) const;
+ //Returns cursor data by name and index in language directory (instead of language) (minimum checks of format correctness)
+ const std::string get_cursor_by_name(const std::wstring& cursor_group_name, uint32_t index = 0) const;
+ //Returns cursor data by ID and language (minimum checks of format correctness)
+ const std::string get_cursor_by_id_lang(uint32_t language, uint32_t cursor_group_id) const;
+ //Returns cursor data by ID and index in language directory (instead of language) (minimum checks of format correctness)
+ const std::string get_cursor_by_id(uint32_t cursor_group_id, uint32_t index = 0) const;
+
+private:
+ const pe_resource_viewer& res_;
+
+ //Helper function of creating icon headers from ICON_GROUP resource data
+ //Returns icon count
+ static uint16_t format_icon_headers(std::string& ico_data, const std::string& resource_data);
+
+ //Helper function of creating cursor headers from CURSOR_GROUP resource data
+ //Returns cursor count
+ uint16_t format_cursor_headers(std::string& cur_data, const std::string& resource_data, uint32_t language, uint32_t index = 0xFFFFFFFF) const;
+
+ //Looks up icon group by icon id and returns full icon headers if found
+ const std::string lookup_icon_group_data_by_icon(uint32_t icon_id, uint32_t language) const;
+ //Checks for icon presence inside icon group, fills icon headers if found
+ static bool check_icon_presence(const std::string& icon_group_resource_data, uint32_t icon_id, std::string& ico_data);
+
+ //Looks up cursor group by cursor id and returns full cursor headers if found
+ const std::string lookup_cursor_group_data_by_cursor(uint32_t cursor_id, uint32_t language, const std::string& raw_cursor_data) const;
+ //Checks for cursor presence inside cursor group, fills cursor headers if found
+ static bool check_cursor_presence(const std::string& icon_group_resource_data, uint32_t cursor_id, std::string& cur_header_data, const std::string& raw_cursor_data);
+};
+}
diff --git a/tools/pe_bliss/resource_cursor_icon_writer.cpp b/tools/pe_bliss/resource_cursor_icon_writer.cpp
new file mode 100644
index 0000000000..2f1c4363c4
--- /dev/null
+++ b/tools/pe_bliss/resource_cursor_icon_writer.cpp
@@ -0,0 +1,447 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include <algorithm>
+#include <string.h>
+#include "resource_cursor_icon_writer.h"
+
+namespace pe_bliss
+{
+using namespace pe_win;
+
+resource_cursor_icon_writer::resource_cursor_icon_writer(pe_resource_manager& res)
+ :res_(res)
+{}
+
+//Add icon helper
+void resource_cursor_icon_writer::add_icon(const std::string& icon_file, const resource_data_info* group_icon_info /* or zero */, resource_directory_entry& new_icon_group_entry, const resource_directory::entry_finder& finder, uint32_t language, icon_place_mode mode, uint32_t codepage, uint32_t timestamp)
+{
+ //Check icon for correctness
+ if(icon_file.length() < sizeof(ico_header))
+ throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon);
+
+ const ico_header* icon_header = reinterpret_cast<const ico_header*>(&icon_file[0]);
+
+ unsigned long size_of_headers = sizeof(ico_header) + icon_header->Count * sizeof(icondirentry);
+ if(icon_file.length() < size_of_headers || icon_header->Count == 0)
+ throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon);
+
+ //Enumerate all icons in file
+ for(uint16_t i = 0; i != icon_header->Count; ++i)
+ {
+ //Check icon entries
+ const icondirentry* icon_entry = reinterpret_cast<const icondirentry*>(&icon_file[sizeof(ico_header) + i * sizeof(icondirentry)]);
+ if(icon_entry->SizeInBytes == 0
+ || icon_entry->ImageOffset < size_of_headers
+ || !pe_utils::is_sum_safe(icon_entry->ImageOffset, icon_entry->SizeInBytes)
+ || icon_entry->ImageOffset + icon_entry->SizeInBytes > icon_file.length())
+ throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon);
+ }
+
+ std::string icon_group_data;
+ ico_header* info = 0;
+
+ if(group_icon_info)
+ {
+ //If icon group already exists
+ {
+ icon_group_data = group_icon_info->get_data();
+ codepage = group_icon_info->get_codepage(); //Don't change codepage of icon group entry
+ }
+
+ //Check resource data size
+ if(icon_group_data.length() < sizeof(ico_header))
+ throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon);
+
+ //Get icon header
+ info = reinterpret_cast<ico_header*>(&icon_group_data[0]);
+
+ //Check resource data size
+ if(icon_group_data.length() < sizeof(ico_header) + info->Count * sizeof(icon_group))
+ throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon);
+
+ icon_group_data.resize(sizeof(ico_header) + (info->Count + icon_header->Count) * sizeof(icon_group));
+ info = reinterpret_cast<ico_header*>(&icon_group_data[0]); //In case if memory was reallocated
+ }
+ else //Entry not found - icon group doesn't exist
+ {
+ icon_group_data.resize(sizeof(ico_header) + icon_header->Count * sizeof(icon_group));
+ memcpy(&icon_group_data[0], icon_header, sizeof(ico_header));
+ }
+
+ //Search for available icon IDs
+ std::vector<uint16_t> icon_id_list(get_icon_or_cursor_free_id_list(pe_resource_viewer::resource_icon, mode, icon_header->Count));
+
+ //Enumerate all icons in file
+ for(uint16_t i = 0; i != icon_header->Count; ++i)
+ {
+ const icondirentry* icon_entry = reinterpret_cast<const icondirentry*>(&icon_file[sizeof(ico_header) + i * sizeof(icondirentry)]);
+ icon_group group = {0};
+
+ //Fill icon resource header
+ group.BitCount = icon_entry->BitCount;
+ group.ColorCount = icon_entry->ColorCount;
+ group.Height = icon_entry->Height;
+ group.Planes = icon_entry->Planes;
+ group.Reserved = icon_entry->Reserved;
+ group.SizeInBytes = icon_entry->SizeInBytes;
+ group.Width = icon_entry->Width;
+ group.Number = icon_id_list.at(i);
+
+ memcpy(&icon_group_data[sizeof(ico_header) + ((info ? info->Count : 0) + i) * sizeof(icon_group)], &group, sizeof(group));
+
+ //Add icon to resources
+ resource_directory_entry new_entry;
+ new_entry.set_id(group.Number);
+ res_.add_resource(icon_file.substr(icon_entry->ImageOffset, icon_entry->SizeInBytes), pe_resource_viewer::resource_icon, new_entry, resource_directory::entry_finder(group.Number), language, codepage, timestamp);
+ }
+
+ if(info)
+ info->Count += icon_header->Count; //Increase icon count, if we're adding icon to existing group
+
+ {
+ //Add or replace icon group data entry
+ res_.add_resource(icon_group_data, pe_resource_viewer::resource_icon_group, new_icon_group_entry, finder, language, codepage, timestamp);
+ }
+}
+
+//Returns free icon or cursor ID list depending on icon_place_mode
+const std::vector<uint16_t> resource_cursor_icon_writer::get_icon_or_cursor_free_id_list(pe_resource_viewer::resource_type type, icon_place_mode mode, uint32_t count)
+{
+ //Search for available icon/cursor IDs
+ std::vector<uint16_t> icon_cursor_id_list;
+
+ try
+ {
+ //If any icon exists
+ //List icon IDs
+ std::vector<uint32_t> id_list(res_.list_resource_ids(type));
+ std::sort(id_list.begin(), id_list.end());
+
+ //If we are placing icon on free spaces
+ //I.e., icon IDs 1, 3, 4, 7, 8 already exist
+ //We'll place five icons on IDs 2, 5, 6, 9, 10
+ if(mode != icon_place_after_max_icon_id)
+ {
+ if(!id_list.empty())
+ {
+ //Determine and list free icon IDs
+ for(std::vector<uint32_t>::const_iterator it = id_list.begin(); it != id_list.end(); ++it)
+ {
+ if(it == id_list.begin())
+ {
+ if(*it > 1)
+ {
+ for(uint16_t i = 1; i != *it; ++i)
+ {
+ icon_cursor_id_list.push_back(i);
+ if(icon_cursor_id_list.size() == count)
+ break;
+ }
+ }
+ }
+ else if(*(it - 1) - *it > 1)
+ {
+ for(uint16_t i = static_cast<uint16_t>(*(it - 1) + 1); i != static_cast<uint16_t>(*it); ++i)
+ {
+ icon_cursor_id_list.push_back(i);
+ if(icon_cursor_id_list.size() == count)
+ break;
+ }
+ }
+
+ if(icon_cursor_id_list.size() == count)
+ break;
+ }
+ }
+ }
+
+ uint32_t max_id = id_list.empty() ? 0 : *std::max_element(id_list.begin(), id_list.end());
+ for(uint32_t i = static_cast<uint32_t>(icon_cursor_id_list.size()); i != count; ++i)
+ icon_cursor_id_list.push_back(static_cast<uint16_t>(++max_id));
+ }
+ catch(const pe_exception&) //Entry not found
+ {
+ for(uint16_t i = 1; i != count + 1; ++i)
+ icon_cursor_id_list.push_back(i);
+ }
+
+ return icon_cursor_id_list;
+}
+
+//Add cursor helper
+void resource_cursor_icon_writer::add_cursor(const std::string& cursor_file, const resource_data_info* group_cursor_info /* or zero */, resource_directory_entry& new_cursor_group_entry, const resource_directory::entry_finder& finder, uint32_t language, icon_place_mode mode, uint32_t codepage, uint32_t timestamp)
+{
+ //Check cursor for correctness
+ if(cursor_file.length() < sizeof(cursor_header))
+ throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor);
+
+ const cursor_header* cur_header = reinterpret_cast<const cursor_header*>(&cursor_file[0]);
+
+ unsigned long size_of_headers = sizeof(cursor_header) + cur_header->Count * sizeof(cursordirentry);
+ if(cursor_file.length() < size_of_headers || cur_header->Count == 0)
+ throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor);
+
+ //Enumerate all cursors in file
+ for(uint16_t i = 0; i != cur_header->Count; ++i)
+ {
+ //Check cursor entries
+ const cursordirentry* cursor_entry = reinterpret_cast<const cursordirentry*>(&cursor_file[sizeof(cursor_header) + i * sizeof(cursordirentry)]);
+ if(cursor_entry->SizeInBytes == 0
+ || cursor_entry->ImageOffset < size_of_headers
+ || !pe_utils::is_sum_safe(cursor_entry->ImageOffset, cursor_entry->SizeInBytes)
+ || cursor_entry->ImageOffset + cursor_entry->SizeInBytes > cursor_file.length())
+ throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor);
+ }
+
+ std::string cursor_group_data;
+ cursor_header* info = 0;
+
+ if(group_cursor_info)
+ {
+ //If cursor group already exists
+ {
+ cursor_group_data = group_cursor_info->get_data();
+ codepage = group_cursor_info->get_codepage(); //Don't change codepage of cursor group entry
+ }
+
+ //Check resource data size
+ if(cursor_group_data.length() < sizeof(cursor_header))
+ throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor);
+
+ //Get cursor header
+ info = reinterpret_cast<cursor_header*>(&cursor_group_data[0]);
+
+ //Check resource data size
+ if(cursor_group_data.length() < sizeof(cursor_header) + info->Count * sizeof(cursor_group))
+ throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor);
+
+ cursor_group_data.resize(sizeof(cursor_header) + (info->Count + cur_header->Count) * sizeof(cursor_group));
+ info = reinterpret_cast<cursor_header*>(&cursor_group_data[0]); //In case if memory was reallocated
+ }
+ else //Entry not found - cursor group doesn't exist
+ {
+ cursor_group_data.resize(sizeof(cursor_header) + cur_header->Count * sizeof(cursor_group));
+ memcpy(&cursor_group_data[0], cur_header, sizeof(cursor_header));
+ }
+
+ //Search for available cursor IDs
+ std::vector<uint16_t> cursor_id_list(get_icon_or_cursor_free_id_list(pe_resource_viewer::resource_cursor, mode, cur_header->Count));
+
+ //Enumerate all cursors in file
+ for(uint16_t i = 0; i != cur_header->Count; ++i)
+ {
+ const cursordirentry* cursor_entry = reinterpret_cast<const cursordirentry*>(&cursor_file[sizeof(cursor_header) + i * sizeof(cursordirentry)]);
+ cursor_group group = {0};
+
+ //Fill cursor resource header
+ group.Height = cursor_entry->Height * 2;
+ group.SizeInBytes = cursor_entry->SizeInBytes + 2 * sizeof(uint16_t) /* hotspot coordinates */;
+ group.Width = cursor_entry->Width;
+ group.Number = cursor_id_list.at(i);
+
+ memcpy(&cursor_group_data[sizeof(cursor_header) + ((info ? info->Count : 0) + i) * sizeof(cursor_group)], &group, sizeof(group));
+
+ //Add cursor to resources
+ resource_directory_entry new_entry;
+ new_entry.set_id(group.Number);
+
+ //Fill resource data (two WORDs for hotspot of cursor, and cursor bitmap data)
+ std::string cur_data;
+ cur_data.resize(sizeof(uint16_t) * 2);
+ memcpy(&cur_data[0], &cursor_entry->HotspotX, sizeof(uint16_t));
+ memcpy(&cur_data[sizeof(uint16_t)], &cursor_entry->HotspotY, sizeof(uint16_t));
+ cur_data.append(cursor_file.substr(cursor_entry->ImageOffset, cursor_entry->SizeInBytes));
+
+ res_.add_resource(cur_data, pe_resource_viewer::resource_cursor, new_entry, resource_directory::entry_finder(group.Number), language, codepage, timestamp);
+ }
+
+ if(info)
+ info->Count += cur_header->Count; //Increase cursor count, if we're adding cursor to existing group
+
+ {
+ //Add or replace cursor group data entry
+ res_.add_resource(cursor_group_data, pe_resource_viewer::resource_cursor_group, new_cursor_group_entry, finder, language, codepage, timestamp);
+ }
+}
+
+//Adds icon(s) from icon file data
+//timestamp will be used for directories that will be added
+//If icon group with name "icon_group_name" or ID "icon_group_id" already exists, it will be appended with new icon(s)
+//(Codepage of icon group and icons will not be changed in this case)
+//icon_place_mode determines, how new icon(s) will be placed
+void resource_cursor_icon_writer::add_icon(const std::string& icon_file, const std::wstring& icon_group_name, uint32_t language, icon_place_mode mode, uint32_t codepage, uint32_t timestamp)
+{
+ resource_directory_entry new_icon_group_entry;
+ new_icon_group_entry.set_name(icon_group_name);
+ std::auto_ptr<resource_data_info> data_info;
+
+ try
+ {
+ data_info.reset(new resource_data_info(res_.get_resource_data_by_name(language, pe_resource_viewer::resource_icon_group, icon_group_name)));
+ }
+ catch(const pe_exception&) //Entry not found
+ {
+ }
+
+ add_icon(icon_file, data_info.get(), new_icon_group_entry, resource_directory::entry_finder(icon_group_name), language, mode, codepage, timestamp);
+}
+
+void resource_cursor_icon_writer::add_icon(const std::string& icon_file, uint32_t icon_group_id, uint32_t language, icon_place_mode mode, uint32_t codepage, uint32_t timestamp)
+{
+ resource_directory_entry new_icon_group_entry;
+ new_icon_group_entry.set_id(icon_group_id);
+ std::auto_ptr<resource_data_info> data_info;
+
+ try
+ {
+ data_info.reset(new resource_data_info(res_.get_resource_data_by_id(language, pe_resource_viewer::resource_icon_group, icon_group_id)));
+ }
+ catch(const pe_exception&) //Entry not found
+ {
+ }
+
+ add_icon(icon_file, data_info.get(), new_icon_group_entry, resource_directory::entry_finder(icon_group_id), language, mode, codepage, timestamp);
+}
+
+//Adds cursor(s) from cursor file data
+//timestamp will be used for directories that will be added
+//If cursor group with name "cursor_group_name" or ID "cursor_group_id" already exists, it will be appended with new cursor(s)
+//(Codepage of cursor group and cursors will not be changed in this case)
+//icon_place_mode determines, how new cursor(s) will be placed
+void resource_cursor_icon_writer::add_cursor(const std::string& cursor_file, const std::wstring& cursor_group_name, uint32_t language, icon_place_mode mode, uint32_t codepage, uint32_t timestamp)
+{
+ resource_directory_entry new_cursor_group_entry;
+ new_cursor_group_entry.set_name(cursor_group_name);
+ std::auto_ptr<resource_data_info> data_info;
+
+ try
+ {
+ data_info.reset(new resource_data_info(res_.get_resource_data_by_name(language, pe_resource_viewer::resource_cursor_group, cursor_group_name)));
+ }
+ catch(const pe_exception&) //Entry not found
+ {
+ }
+
+ add_cursor(cursor_file, data_info.get(), new_cursor_group_entry, resource_directory::entry_finder(cursor_group_name), language, mode, codepage, timestamp);
+}
+
+void resource_cursor_icon_writer::add_cursor(const std::string& cursor_file, uint32_t cursor_group_id, uint32_t language, icon_place_mode mode, uint32_t codepage, uint32_t timestamp)
+{
+ resource_directory_entry new_cursor_group_entry;
+ new_cursor_group_entry.set_id(cursor_group_id);
+ std::auto_ptr<resource_data_info> data_info;
+
+ try
+ {
+ data_info.reset(new resource_data_info(res_.get_resource_data_by_id(language, pe_resource_viewer::resource_cursor_group, cursor_group_id)));
+ }
+ catch(const pe_exception&) //Entry not found
+ {
+ }
+
+ add_cursor(cursor_file, data_info.get(), new_cursor_group_entry, resource_directory::entry_finder(cursor_group_id), language, mode, codepage, timestamp);
+}
+
+//Remove icon group helper
+void resource_cursor_icon_writer::remove_icons_from_icon_group(const std::string& icon_group_data, uint32_t language)
+{
+ //Check resource data size
+ if(icon_group_data.length() < sizeof(ico_header))
+ throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon);
+
+ //Get icon header
+ const ico_header* info = reinterpret_cast<const ico_header*>(icon_group_data.data());
+
+ uint16_t icon_count = info->Count;
+
+ //Check resource data size
+ if(icon_group_data.length() < sizeof(ico_header) + icon_count * sizeof(icon_group))
+ throw pe_exception("Incorrect resource icon", pe_exception::resource_incorrect_icon);
+
+ //Remove icon data
+ for(uint16_t i = 0; i != icon_count; ++i)
+ {
+ const icon_group* group = reinterpret_cast<const icon_group*>(icon_group_data.data() + sizeof(ico_header) + i * sizeof(icon_group));
+ res_.remove_resource(pe_resource_viewer::resource_icon, group->Number, language);
+ }
+}
+
+//Remove cursor group helper
+void resource_cursor_icon_writer::remove_cursors_from_cursor_group(const std::string& cursor_group_data, uint32_t language)
+{
+ //Check resource data size
+ if(cursor_group_data.length() < sizeof(cursor_header))
+ throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor);
+
+ //Get icon header
+ const cursor_header* info = reinterpret_cast<const cursor_header*>(cursor_group_data.data());
+
+ uint16_t cursor_count = info->Count;
+
+ //Check resource data size
+ if(cursor_group_data.length() < sizeof(cursor_header) + cursor_count * sizeof(cursor_group))
+ throw pe_exception("Incorrect resource cursor", pe_exception::resource_incorrect_cursor);
+
+ //Remove icon data
+ for(uint16_t i = 0; i != cursor_count; ++i)
+ {
+ const icon_group* group = reinterpret_cast<const icon_group*>(cursor_group_data.data() + sizeof(cursor_header) + i * sizeof(cursor_group));
+ res_.remove_resource(pe_resource_viewer::resource_cursor, group->Number, language);
+ }
+}
+
+//Removes cursor group and all its cursors by name/ID and language
+bool resource_cursor_icon_writer::remove_cursor_group(const std::wstring& cursor_group_name, uint32_t language)
+{
+ //Get resource by name and language
+ const std::string data = res_.get_resource_data_by_name(language, pe_resource_viewer::resource_cursor_group, cursor_group_name).get_data();
+ remove_cursors_from_cursor_group(data, language);
+ return res_.remove_resource(pe_resource_viewer::resource_cursor_group, cursor_group_name, language);
+}
+
+//Removes cursor group and all its cursors by name/ID and language
+bool resource_cursor_icon_writer::remove_cursor_group(uint32_t cursor_group_id, uint32_t language)
+{
+ //Get resource by name and language
+ const std::string data = res_.get_resource_data_by_id(language, pe_resource_viewer::resource_cursor_group, cursor_group_id).get_data();
+ remove_cursors_from_cursor_group(data, language);
+ return res_.remove_resource(pe_resource_viewer::resource_cursor_group, cursor_group_id, language);
+}
+
+//Removes icon group and all its icons by name/ID and language
+bool resource_cursor_icon_writer::remove_icon_group(const std::wstring& icon_group_name, uint32_t language)
+{
+ //Get resource by name and language
+ const std::string data = res_.get_resource_data_by_name(language, pe_resource_viewer::resource_icon_group, icon_group_name).get_data();
+ remove_icons_from_icon_group(data, language);
+ return res_.remove_resource(pe_resource_viewer::resource_icon_group, icon_group_name, language);
+}
+
+//Removes icon group and all its icons by name/ID and language
+bool resource_cursor_icon_writer::remove_icon_group(uint32_t icon_group_id, uint32_t language)
+{
+ //Get resource by name and language
+ const std::string data = res_.get_resource_data_by_id(language, pe_resource_viewer::resource_icon_group, icon_group_id).get_data();
+ remove_icons_from_icon_group(data, language);
+ return res_.remove_resource(pe_resource_viewer::resource_icon_group, icon_group_id, language);
+}
+}
diff --git a/tools/pe_bliss/resource_cursor_icon_writer.h b/tools/pe_bliss/resource_cursor_icon_writer.h
new file mode 100644
index 0000000000..e73ac6a093
--- /dev/null
+++ b/tools/pe_bliss/resource_cursor_icon_writer.h
@@ -0,0 +1,94 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <string>
+#include <vector>
+#include "stdint_defs.h"
+#include "pe_resource_manager.h"
+
+namespace pe_bliss
+{
+class pe_resource_manager;
+
+class resource_cursor_icon_writer
+{
+public:
+ //Determines, how new icon(s) or cursor(s) will be placed
+ enum icon_place_mode
+ {
+ icon_place_after_max_icon_id, //Icon(s) will be placed after all existing
+ icon_place_free_ids //New icon(s) will take all free IDs between existing icons
+ };
+
+public:
+ resource_cursor_icon_writer(pe_resource_manager& res);
+
+ //Removes icon group and all its icons by name/ID and language
+ bool remove_icon_group(const std::wstring& icon_group_name, uint32_t language);
+ bool remove_icon_group(uint32_t icon_group_id, uint32_t language);
+
+ //Adds icon(s) from icon file data
+ //timestamp will be used for directories that will be added
+ //If icon group with name "icon_group_name" or ID "icon_group_id" already exists, it will be appended with new icon(s)
+ //(Codepage of icon group and icons will not be changed in this case)
+ //icon_place_mode determines, how new icon(s) will be placed
+ void add_icon(const std::string& icon_file,
+ const std::wstring& icon_group_name,
+ uint32_t language, icon_place_mode mode = icon_place_after_max_icon_id,
+ uint32_t codepage = 0, uint32_t timestamp = 0);
+
+ void add_icon(const std::string& icon_file,
+ uint32_t icon_group_id,
+ uint32_t language, icon_place_mode mode = icon_place_after_max_icon_id,
+ uint32_t codepage = 0, uint32_t timestamp = 0);
+
+ //Removes cursor group and all its cursors by name/ID and language
+ bool remove_cursor_group(const std::wstring& cursor_group_name, uint32_t language);
+ bool remove_cursor_group(uint32_t cursor_group_id, uint32_t language);
+
+ //Adds cursor(s) from cursor file data
+ //timestamp will be used for directories that will be added
+ //If cursor group with name "cursor_group_name" or ID "cursor_group_id" already exists, it will be appended with new cursor(s)
+ //(Codepage of cursor group and cursors will not be changed in this case)
+ //icon_place_mode determines, how new cursor(s) will be placed
+ void add_cursor(const std::string& cursor_file, const std::wstring& cursor_group_name, uint32_t language, icon_place_mode mode = icon_place_after_max_icon_id, uint32_t codepage = 0, uint32_t timestamp = 0);
+ void add_cursor(const std::string& cursor_file, uint32_t cursor_group_id, uint32_t language, icon_place_mode mode = icon_place_after_max_icon_id, uint32_t codepage = 0, uint32_t timestamp = 0);
+
+private:
+ pe_resource_manager& res_;
+
+ //Add icon helper
+ void add_icon(const std::string& icon_file, const resource_data_info* group_icon_info /* or zero */, resource_directory_entry& new_icon_group_entry, const resource_directory::entry_finder& finder, uint32_t language, icon_place_mode mode, uint32_t codepage, uint32_t timestamp);
+
+ //Remove icon group helper
+ void remove_icons_from_icon_group(const std::string& icon_group_data, uint32_t language);
+
+ //Add cursor helper
+ void add_cursor(const std::string& cursor_file, const resource_data_info* group_cursor_info /* or zero */, resource_directory_entry& new_cursor_group_entry, const resource_directory::entry_finder& finder, uint32_t language, icon_place_mode mode, uint32_t codepage, uint32_t timestamp);
+
+ //Remove cursor group helper
+ void remove_cursors_from_cursor_group(const std::string& cursor_group_data, uint32_t language);
+
+ //Returns free icon or cursor ID list depending on icon_place_mode
+ const std::vector<uint16_t> get_icon_or_cursor_free_id_list(pe_resource_manager::resource_type type, icon_place_mode mode, uint32_t count);
+};
+}
diff --git a/tools/pe_bliss/resource_data_info.cpp b/tools/pe_bliss/resource_data_info.cpp
new file mode 100644
index 0000000000..75bb060eae
--- /dev/null
+++ b/tools/pe_bliss/resource_data_info.cpp
@@ -0,0 +1,48 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include "resource_data_info.h"
+#include "pe_resource_viewer.h"
+
+namespace pe_bliss
+{
+//Default constructor
+resource_data_info::resource_data_info(const std::string& data, uint32_t codepage)
+ :data_(data), codepage_(codepage)
+{}
+
+//Constructor from data
+resource_data_info::resource_data_info(const resource_data_entry& data)
+ :data_(data.get_data()), codepage_(data.get_codepage())
+{}
+
+//Returns resource data
+const std::string& resource_data_info::get_data() const
+{
+ return data_;
+}
+
+//Returns resource codepage
+uint32_t resource_data_info::get_codepage() const
+{
+ return codepage_;
+}
+}
diff --git a/tools/pe_bliss/resource_data_info.h b/tools/pe_bliss/resource_data_info.h
new file mode 100644
index 0000000000..e2275ebbf5
--- /dev/null
+++ b/tools/pe_bliss/resource_data_info.h
@@ -0,0 +1,48 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <string>
+#include "stdint_defs.h"
+
+namespace pe_bliss
+{
+class resource_data_entry;
+
+//Class representing resource data
+class resource_data_info
+{
+public:
+ //Constructor from data
+ resource_data_info(const std::string& data, uint32_t codepage);
+ //Constructor from data
+ explicit resource_data_info(const resource_data_entry& data);
+
+ //Returns resource data
+ const std::string& get_data() const;
+ //Returns resource codepage
+ uint32_t get_codepage() const;
+
+private:
+ std::string data_;
+ uint32_t codepage_;
+};
+}
diff --git a/tools/pe_bliss/resource_internal.h b/tools/pe_bliss/resource_internal.h
new file mode 100644
index 0000000000..64a5bf3903
--- /dev/null
+++ b/tools/pe_bliss/resource_internal.h
@@ -0,0 +1,34 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+
+#define U16TEXT(t) reinterpret_cast<const unicode16_t*>( t )
+
+#define StringFileInfo U16TEXT("S\0t\0r\0i\0n\0g\0F\0i\0l\0e\0I\0n\0f\0o\0\0")
+#define SizeofStringFileInfo sizeof("S\0t\0r\0i\0n\0g\0F\0i\0l\0e\0I\0n\0f\0o\0\0")
+#define VarFileInfo U16TEXT("V\0a\0r\0F\0i\0l\0e\0I\0n\0f\0o\0\0")
+#define Translation U16TEXT("T\0r\0a\0n\0s\0l\0a\0t\0i\0o\0n\0\0")
+
+#define VarFileInfoAligned U16TEXT("V\0a\0r\0F\0i\0l\0e\0I\0n\0f\0o\0\0\0\0")
+#define TranslationAligned U16TEXT("T\0r\0a\0n\0s\0l\0a\0t\0i\0o\0n\0\0\0\0")
+#define SizeofVarFileInfoAligned sizeof("V\0a\0r\0F\0i\0l\0e\0I\0n\0f\0o\0\0\0\0")
+#define SizeofTranslationAligned sizeof("T\0r\0a\0n\0s\0l\0a\0t\0i\0o\0n\0\0\0\0")
diff --git a/tools/pe_bliss/resource_message_list_reader.cpp b/tools/pe_bliss/resource_message_list_reader.cpp
new file mode 100644
index 0000000000..f2ea142bee
--- /dev/null
+++ b/tools/pe_bliss/resource_message_list_reader.cpp
@@ -0,0 +1,131 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include "resource_message_list_reader.h"
+#include "pe_resource_viewer.h"
+
+namespace pe_bliss
+{
+using namespace pe_win;
+
+resource_message_list_reader::resource_message_list_reader(const pe_resource_viewer& res)
+ :res_(res)
+{}
+
+//Helper function of parsing message list table
+const resource_message_list resource_message_list_reader::parse_message_list(const std::string& resource_data)
+{
+ resource_message_list ret;
+
+ //Check resource data length
+ if(resource_data.length() < sizeof(message_resource_data))
+ throw pe_exception("Incorrect resource message table", pe_exception::resource_incorrect_message_table);
+
+ const message_resource_data* message_data = reinterpret_cast<const message_resource_data*>(resource_data.data());
+
+ //Check resource data length more carefully and some possible overflows
+ if(message_data->NumberOfBlocks >= pe_utils::max_dword / sizeof(message_resource_block)
+ || !pe_utils::is_sum_safe(message_data->NumberOfBlocks * sizeof(message_resource_block), sizeof(message_resource_data))
+ || resource_data.length() < message_data->NumberOfBlocks * sizeof(message_resource_block) + sizeof(message_resource_data))
+ throw pe_exception("Incorrect resource message table", pe_exception::resource_incorrect_message_table);
+
+ //Iterate over all message resource blocks
+ for(unsigned long i = 0; i != message_data->NumberOfBlocks; ++i)
+ {
+ //Get block
+ const message_resource_block* block =
+ reinterpret_cast<const message_resource_block*>(resource_data.data() + sizeof(message_resource_data) - sizeof(message_resource_block) + sizeof(message_resource_block) * i);
+
+ //Check resource data length and IDs
+ if(resource_data.length() < block->OffsetToEntries || block->LowId > block->HighId)
+ throw pe_exception("Incorrect resource message table", pe_exception::resource_incorrect_message_table);
+
+ unsigned long current_pos = 0;
+ static const unsigned long size_of_entry_headers = 4;
+ //List all message resource entries in block
+ for(uint32_t curr_id = block->LowId; curr_id <= block->HighId; curr_id++)
+ {
+ //Check resource data length and some possible overflows
+ if(!pe_utils::is_sum_safe(block->OffsetToEntries, current_pos)
+ || !pe_utils::is_sum_safe(block->OffsetToEntries + current_pos, size_of_entry_headers)
+ || resource_data.length() < block->OffsetToEntries + current_pos + size_of_entry_headers)
+ throw pe_exception("Incorrect resource message table", pe_exception::resource_incorrect_message_table);
+
+ //Get entry
+ const message_resource_entry* entry = reinterpret_cast<const message_resource_entry*>(resource_data.data() + block->OffsetToEntries + current_pos);
+
+ //Check resource data length and entry length and some possible overflows
+ if(entry->Length < size_of_entry_headers
+ || !pe_utils::is_sum_safe(block->OffsetToEntries + current_pos, entry->Length)
+ || resource_data.length() < block->OffsetToEntries + current_pos + entry->Length
+ || entry->Length < size_of_entry_headers)
+ throw pe_exception("Incorrect resource message table", pe_exception::resource_incorrect_message_table);
+
+ if(entry->Flags & message_resource_unicode)
+ {
+ //If string is UNICODE
+ //Check its length
+ if(entry->Length % 2)
+ throw pe_exception("Incorrect resource message table", pe_exception::resource_incorrect_message_table);
+
+ //Add ID and string to message table
+#ifdef PE_BLISS_WINDOWS
+ ret.insert(std::make_pair(curr_id, message_table_item(
+ std::wstring(reinterpret_cast<const wchar_t*>(resource_data.data() + block->OffsetToEntries + current_pos + size_of_entry_headers),
+ (entry->Length - size_of_entry_headers) / 2)
+ )));
+#else
+ ret.insert(std::make_pair(curr_id, message_table_item(
+ pe_utils::from_ucs2(u16string(reinterpret_cast<const unicode16_t*>(resource_data.data() + block->OffsetToEntries + current_pos + size_of_entry_headers),
+ (entry->Length - size_of_entry_headers) / 2))
+ )));
+#endif
+ }
+ else
+ {
+ //If string is ANSI
+ //Add ID and string to message table
+ ret.insert(std::make_pair(curr_id, message_table_item(
+ std::string(resource_data.data() + block->OffsetToEntries + current_pos + size_of_entry_headers,
+ entry->Length - size_of_entry_headers)
+ )));
+ }
+
+ //Go to next entry
+ current_pos += entry->Length;
+ }
+ }
+
+ return ret;
+}
+
+//Returns message table data by ID and index in language directory (instead of language)
+const resource_message_list resource_message_list_reader::get_message_table_by_id(uint32_t id, uint32_t index) const
+{
+ return parse_message_list(res_.get_resource_data_by_id(pe_resource_viewer::resource_message_table, id, index).get_data());
+}
+
+//Returns message table data by ID and language
+const resource_message_list resource_message_list_reader::get_message_table_by_id_lang(uint32_t language, uint32_t id) const
+{
+ return parse_message_list(res_.get_resource_data_by_id(language, pe_resource_viewer::resource_message_table, id).get_data());
+}
+}
diff --git a/tools/pe_bliss/resource_message_list_reader.h b/tools/pe_bliss/resource_message_list_reader.h
new file mode 100644
index 0000000000..a0ac96eb8c
--- /dev/null
+++ b/tools/pe_bliss/resource_message_list_reader.h
@@ -0,0 +1,49 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include "message_table.h"
+
+namespace pe_bliss
+{
+class pe_resource_viewer;
+
+//ID; message_table_item
+typedef std::map<uint32_t, message_table_item> resource_message_list;
+
+class resource_message_list_reader
+{
+public:
+ resource_message_list_reader(const pe_resource_viewer& res);
+
+ //Returns message table data by ID and language
+ const resource_message_list get_message_table_by_id_lang(uint32_t language, uint32_t id) const;
+ //Returns message table data by ID and index in language directory (instead of language)
+ const resource_message_list get_message_table_by_id(uint32_t id, uint32_t index = 0) const;
+
+ //Helper function of parsing message list table
+ //resource_data - raw message table resource data
+ static const resource_message_list parse_message_list(const std::string& resource_data);
+
+private:
+ const pe_resource_viewer& res_;
+};
+}
diff --git a/tools/pe_bliss/resource_string_table_reader.cpp b/tools/pe_bliss/resource_string_table_reader.cpp
new file mode 100644
index 0000000000..8a51720e6a
--- /dev/null
+++ b/tools/pe_bliss/resource_string_table_reader.cpp
@@ -0,0 +1,109 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include "resource_string_table_reader.h"
+#include "pe_resource_viewer.h"
+
+namespace pe_bliss
+{
+resource_string_table_reader::resource_string_table_reader(const pe_resource_viewer& res)
+ :res_(res)
+{}
+
+//Returns string table data by ID and index in language directory (instead of language)
+const resource_string_list resource_string_table_reader::get_string_table_by_id(uint32_t id, uint32_t index) const
+{
+ return parse_string_list(id, res_.get_resource_data_by_id(pe_resource_viewer::resource_string, id, index).get_data());
+}
+
+//Returns string table data by ID and language
+const resource_string_list resource_string_table_reader::get_string_table_by_id_lang(uint32_t language, uint32_t id) const
+{
+ return parse_string_list(id, res_.get_resource_data_by_id(language, pe_resource_viewer::resource_string, id).get_data());
+}
+
+//Helper function of parsing string list table
+const resource_string_list resource_string_table_reader::parse_string_list(uint32_t id, const std::string& resource_data)
+{
+ resource_string_list ret;
+
+ //16 is maximum count of strings in a string table
+ static const unsigned long max_string_list_entries = 16;
+ unsigned long passed_bytes = 0;
+ for(unsigned long i = 0; i != max_string_list_entries; ++i)
+ {
+ //Check resource data length
+ if(resource_data.length() < sizeof(uint16_t) + passed_bytes)
+ throw pe_exception("Incorrect resource string table", pe_exception::resource_incorrect_string_table);
+
+ //Get string length - the first WORD
+ uint16_t string_length = *reinterpret_cast<const uint16_t*>(resource_data.data() + passed_bytes);
+ passed_bytes += sizeof(uint16_t); //WORD containing string length
+
+ //Check resource data length again
+ if(resource_data.length() < string_length + passed_bytes)
+ throw pe_exception("Incorrect resource string table", pe_exception::resource_incorrect_string_table);
+
+ if(string_length)
+ {
+ //Create and save string (UNICODE)
+#ifdef PE_BLISS_WINDOWS
+ ret.insert(
+ std::make_pair(static_cast<uint16_t>(((id - 1) << 4) + i), //ID of string is calculated such way
+ std::wstring(reinterpret_cast<const wchar_t*>(resource_data.data() + passed_bytes), string_length)));
+#else
+ ret.insert(
+ std::make_pair(static_cast<uint16_t>(((id - 1) << 4) + i), //ID of string is calculated such way
+ pe_utils::from_ucs2(u16string(reinterpret_cast<const unicode16_t*>(resource_data.data() + passed_bytes), string_length))));
+#endif
+ }
+
+ //Go to next string
+ passed_bytes += string_length * 2;
+ }
+
+ return ret;
+}
+
+//Returns string from string table by ID and language
+const std::wstring resource_string_table_reader::get_string_by_id_lang(uint32_t language, uint16_t id) const
+{
+ //List strings by string table id and language
+ const resource_string_list strings(get_string_table_by_id_lang(language, (id >> 4) + 1));
+ resource_string_list::const_iterator it = strings.find(id); //Find string by id
+ if(it == strings.end())
+ throw pe_exception("Resource string not found", pe_exception::resource_string_not_found);
+
+ return (*it).second;
+}
+
+//Returns string from string table by ID and index in language directory (instead of language)
+const std::wstring resource_string_table_reader::get_string_by_id(uint16_t id, uint32_t index) const
+{
+ //List strings by string table id and index
+ const resource_string_list strings(get_string_table_by_id((id >> 4) + 1, index));
+ resource_string_list::const_iterator it = strings.find(id); //Find string by id
+ if(it == strings.end())
+ throw pe_exception("Resource string not found", pe_exception::resource_string_not_found);
+
+ return (*it).second;
+}
+}
diff --git a/tools/pe_bliss/resource_string_table_reader.h b/tools/pe_bliss/resource_string_table_reader.h
new file mode 100644
index 0000000000..e3ded1da85
--- /dev/null
+++ b/tools/pe_bliss/resource_string_table_reader.h
@@ -0,0 +1,57 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <string>
+#include <map>
+#include "stdint_defs.h"
+
+namespace pe_bliss
+{
+class pe_resource_viewer;
+
+//ID; string
+typedef std::map<uint16_t, std::wstring> resource_string_list;
+
+class resource_string_table_reader
+{
+public:
+ resource_string_table_reader(const pe_resource_viewer& res);
+
+public:
+ //Returns string table data by ID and language
+ const resource_string_list get_string_table_by_id_lang(uint32_t language, uint32_t id) const;
+ //Returns string table data by ID and index in language directory (instead of language)
+ const resource_string_list get_string_table_by_id(uint32_t id, uint32_t index = 0) const;
+ //Returns string from string table by ID and language
+ const std::wstring get_string_by_id_lang(uint32_t language, uint16_t id) const;
+ //Returns string from string table by ID and index in language directory (instead of language)
+ const std::wstring get_string_by_id(uint16_t id, uint32_t index = 0) const;
+
+private:
+ const pe_resource_viewer& res_;
+
+ //Helper function of parsing string list table
+ //Id of resource is needed to calculate string IDs correctly
+ //resource_data is raw string table resource data
+ static const resource_string_list parse_string_list(uint32_t id, const std::string& resource_data);
+};
+}
diff --git a/tools/pe_bliss/resource_version_info_reader.cpp b/tools/pe_bliss/resource_version_info_reader.cpp
new file mode 100644
index 0000000000..8ad44c6856
--- /dev/null
+++ b/tools/pe_bliss/resource_version_info_reader.cpp
@@ -0,0 +1,311 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include "resource_version_info_reader.h"
+#include "utils.h"
+#include "pe_exception.h"
+#include "resource_internal.h"
+#include "pe_resource_viewer.h"
+
+namespace pe_bliss
+{
+using namespace pe_win;
+
+//Root version info block key value
+const u16string resource_version_info_reader::version_info_key(U16TEXT("V\0S\0_\0V\0E\0R\0S\0I\0O\0N\0_\0I\0N\0F\0O\0\0"));
+
+resource_version_info_reader::resource_version_info_reader(const pe_resource_viewer& res)
+ :res_(res)
+{}
+
+//Returns aligned version block value position
+uint32_t resource_version_info_reader::get_version_block_value_pos(uint32_t base_pos, const unicode16_t* key)
+{
+ uint32_t string_length = static_cast<uint32_t>(u16string(key).length());
+ uint32_t ret = pe_utils::align_up(static_cast<uint32_t>(sizeof(uint16_t) * 3 /* headers before Key data */
+ + base_pos
+ + (string_length + 1 /* nullbyte */) * 2),
+ sizeof(uint32_t));
+
+ //Check possible overflows
+ if(ret < base_pos || ret < sizeof(uint16_t) * 3 || ret < (string_length + 1) * 2)
+ throw_incorrect_version_info();
+
+ return ret;
+}
+
+//Returns aligned version block first child position
+uint32_t resource_version_info_reader::get_version_block_first_child_pos(uint32_t base_pos, uint32_t value_length, const unicode16_t* key)
+{
+ uint32_t string_length = static_cast<uint32_t>(u16string(key).length());
+ uint32_t ret = pe_utils::align_up(static_cast<uint32_t>(sizeof(uint16_t) * 3 /* headers before Key data */
+ + base_pos
+ + (string_length + 1 /* nullbyte */) * 2),
+ sizeof(uint32_t))
+ + pe_utils::align_up(value_length, sizeof(uint32_t));
+
+ //Check possible overflows
+ if(ret < base_pos || ret < value_length || ret < sizeof(uint16_t) * 3 || ret < (string_length + 1) * 2)
+ throw_incorrect_version_info();
+
+ return ret;
+}
+
+//Throws an exception (id = resource_incorrect_version_info)
+void resource_version_info_reader::throw_incorrect_version_info()
+{
+ throw pe_exception("Incorrect resource version info", pe_exception::resource_incorrect_version_info);
+}
+
+//Returns full version information:
+//file_version_info: versions and file info
+//lang_string_values_map: map of version info strings with encodings
+//translation_values_map: map of translations
+const file_version_info resource_version_info_reader::get_version_info(lang_string_values_map& string_values, translation_values_map& translations, const std::string& resource_data) const
+{
+ //Fixed file version info
+ file_version_info ret;
+
+ //Check resource data length
+ if(resource_data.length() < sizeof(version_info_block))
+ throw_incorrect_version_info();
+
+ //Root version info block
+ const version_info_block* root_block = reinterpret_cast<const version_info_block*>(resource_data.data());
+
+ //Check root block key for null-termination and its name
+ if(!pe_utils::is_null_terminated(root_block->Key, resource_data.length() - sizeof(uint16_t) * 3 /* headers before Key data */)
+ || version_info_key != reinterpret_cast<const unicode16_t*>(root_block->Key))
+ throw_incorrect_version_info();
+
+ //If file has fixed version info
+ if(root_block->ValueLength)
+ {
+ //Get root block value position
+ uint32_t value_pos = get_version_block_value_pos(0, reinterpret_cast<const unicode16_t*>(root_block->Key));
+ //Check value length
+ if(resource_data.length() < value_pos + sizeof(vs_fixedfileinfo))
+ throw_incorrect_version_info();
+
+ //Get VS_FIXEDFILEINFO structure pointer
+ const vs_fixedfileinfo* file_info = reinterpret_cast<const vs_fixedfileinfo*>(resource_data.data() + value_pos);
+ //Check its signature and some other fields
+ if(file_info->dwSignature != vs_ffi_signature || file_info->dwStrucVersion != vs_ffi_strucversion) //Don't check if file_info->dwFileFlagsMask == VS_FFI_FILEFLAGSMASK
+ throw_incorrect_version_info();
+
+ //Save fixed version info
+ ret = file_version_info(*file_info);
+ }
+
+ //Iterate over child elements of VS_VERSIONINFO (StringFileInfo or VarFileInfo)
+ for(uint32_t child_pos = get_version_block_first_child_pos(0, root_block->ValueLength, reinterpret_cast<const unicode16_t*>(root_block->Key));
+ child_pos < root_block->Length;)
+ {
+ //Check block position
+ if(!pe_utils::is_sum_safe(child_pos, sizeof(version_info_block))
+ || resource_data.length() < child_pos + sizeof(version_info_block))
+ throw_incorrect_version_info();
+
+ //Get VERSION_INFO_BLOCK structure pointer
+ const version_info_block* block = reinterpret_cast<const version_info_block*>(resource_data.data() + child_pos);
+
+ //Check its length
+ if(block->Length == 0)
+ throw_incorrect_version_info();
+
+ //Check block key for null-termination
+ if(!pe_utils::is_null_terminated(block->Key, resource_data.length() - child_pos - sizeof(uint16_t) * 3 /* headers before Key data */))
+ throw_incorrect_version_info();
+
+ u16string info_type(reinterpret_cast<const unicode16_t*>(block->Key));
+ //If we encountered StringFileInfo...
+ if(info_type == StringFileInfo)
+ {
+ //Enumerate all string tables
+ for(uint32_t string_table_pos = get_version_block_first_child_pos(child_pos, block->ValueLength, reinterpret_cast<const unicode16_t*>(block->Key));
+ string_table_pos - child_pos < block->Length;)
+ {
+ //Check string table block position
+ if(resource_data.length() < string_table_pos + sizeof(version_info_block))
+ throw_incorrect_version_info();
+
+ //Get VERSION_INFO_BLOCK structure pointer for string table
+ const version_info_block* string_table = reinterpret_cast<const version_info_block*>(resource_data.data() + string_table_pos);
+
+ //Check its length
+ if(string_table->Length == 0)
+ throw_incorrect_version_info();
+
+ //Check string table key for null-termination
+ if(!pe_utils::is_null_terminated(string_table->Key, resource_data.length() - string_table_pos - sizeof(uint16_t) * 3 /* headers before Key data */))
+ throw_incorrect_version_info();
+
+ string_values_map new_values;
+
+ //Enumerate all strings in the string table
+ for(uint32_t string_pos = get_version_block_first_child_pos(string_table_pos, string_table->ValueLength, reinterpret_cast<const unicode16_t*>(string_table->Key));
+ string_pos - string_table_pos < string_table->Length;)
+ {
+ //Check string block position
+ if(resource_data.length() < string_pos + sizeof(version_info_block))
+ throw_incorrect_version_info();
+
+ //Get VERSION_INFO_BLOCK structure pointer for string block
+ const version_info_block* string_block = reinterpret_cast<const version_info_block*>(resource_data.data() + string_pos);
+
+ //Check its length
+ if(string_block->Length == 0)
+ throw_incorrect_version_info();
+
+ //Check string block key for null-termination
+ if(!pe_utils::is_null_terminated(string_block->Key, resource_data.length() - string_pos - sizeof(uint16_t) * 3 /* headers before Key data */))
+ throw_incorrect_version_info();
+
+ u16string data;
+ //If string block has value
+ if(string_block->ValueLength != 0)
+ {
+ //Get value position
+ uint32_t value_pos = get_version_block_value_pos(string_pos, reinterpret_cast<const unicode16_t*>(string_block->Key));
+ //Check it
+ if(resource_data.length() < value_pos + string_block->ValueLength)
+ throw pe_exception("Incorrect resource version info", pe_exception::resource_incorrect_version_info);
+
+ //Get UNICODE string value
+ data = u16string(reinterpret_cast<const unicode16_t*>(resource_data.data() + value_pos), string_block->ValueLength);
+ pe_utils::strip_nullbytes(data);
+ }
+
+ //Save name-value pair
+#ifdef PE_BLISS_WINDOWS
+ new_values.insert(std::make_pair(reinterpret_cast<const unicode16_t*>(string_block->Key), data));
+#else
+ new_values.insert(std::make_pair(pe_utils::from_ucs2(reinterpret_cast<const unicode16_t*>(string_block->Key)),
+ pe_utils::from_ucs2(data)));
+#endif
+
+ //Navigate to next string block
+ string_pos += pe_utils::align_up(string_block->Length, sizeof(uint32_t));
+ }
+
+#ifdef PE_BLISS_WINDOWS
+ string_values.insert(std::make_pair(reinterpret_cast<const unicode16_t*>(string_table->Key), new_values));
+#else
+ string_values.insert(std::make_pair(pe_utils::from_ucs2(reinterpret_cast<const unicode16_t*>(string_table->Key)), new_values));
+#endif
+
+ //Navigate to next string table block
+ string_table_pos += pe_utils::align_up(string_table->Length, sizeof(uint32_t));
+ }
+ }
+ else if(info_type == VarFileInfo) //If we encountered VarFileInfo
+ {
+ for(uint32_t var_table_pos = get_version_block_first_child_pos(child_pos, block->ValueLength, reinterpret_cast<const unicode16_t*>(block->Key));
+ var_table_pos - child_pos < block->Length;)
+ {
+ //Check var block position
+ if(resource_data.length() < var_table_pos + sizeof(version_info_block))
+ throw_incorrect_version_info();
+
+ //Get VERSION_INFO_BLOCK structure pointer for var block
+ const version_info_block* var_table = reinterpret_cast<const version_info_block*>(resource_data.data() + var_table_pos);
+
+ //Check its length
+ if(var_table->Length == 0)
+ throw_incorrect_version_info();
+
+ //Check its key for null-termination
+ if(!pe_utils::is_null_terminated(var_table->Key, resource_data.length() - var_table_pos - sizeof(uint16_t) * 3 /* headers before Key data */))
+ throw_incorrect_version_info();
+
+ //If block is "Translation" (actually, there's no other types possible in VarFileInfo) and it has value
+ if(u16string(reinterpret_cast<const unicode16_t*>(var_table->Key)) == Translation && var_table->ValueLength)
+ {
+ //Get its value position
+ uint32_t value_pos = get_version_block_value_pos(var_table_pos, reinterpret_cast<const unicode16_t*>(var_table->Key));
+ //Cherck value length
+ if(resource_data.length() < value_pos + var_table->ValueLength)
+ throw_incorrect_version_info();
+
+ //Get list of translations: pairs of LANGUAGE_ID - CODEPAGE_ID
+ for(unsigned long i = 0; i < var_table->ValueLength; i += sizeof(uint16_t) * 2)
+ {
+ //Pair of WORDs
+ uint16_t lang_id = *reinterpret_cast<const uint16_t*>(resource_data.data() + value_pos + i);
+ uint16_t codepage_id = *reinterpret_cast<const uint16_t*>(resource_data.data() + value_pos + sizeof(uint16_t) + i);
+ //Save translation
+ translations.insert(std::make_pair(lang_id, codepage_id));
+ }
+ }
+
+ //Navigate to next var block
+ var_table_pos += pe_utils::align_up(var_table->Length, sizeof(uint32_t));
+ }
+ }
+ else
+ {
+ throw_incorrect_version_info();
+ }
+
+ //Navigate to next element in root block
+ child_pos += pe_utils::align_up(block->Length, sizeof(uint32_t));
+ }
+
+ return ret;
+}
+
+//Returns full version information:
+//file_version info: versions and file info
+//lang_string_values_map: map of version info strings with encodings
+//translation_values_map: map of translations
+const file_version_info resource_version_info_reader::get_version_info_by_lang(lang_string_values_map& string_values, translation_values_map& translations, uint32_t language) const
+{
+ const std::string& resource_data = res_.get_root_directory() //Type directory
+ .entry_by_id(pe_resource_viewer::resource_version)
+ .get_resource_directory() //Name/ID directory
+ .entry_by_id(1)
+ .get_resource_directory() //Language directory
+ .entry_by_id(language)
+ .get_data_entry() //Data directory
+ .get_data();
+
+ return get_version_info(string_values, translations, resource_data);
+}
+
+//Returns full version information:
+//file_version_info: versions and file info
+//lang_string_values_map: map of version info strings with encodings
+//translation_values_map: map of translations
+const file_version_info resource_version_info_reader::get_version_info(lang_string_values_map& string_values, translation_values_map& translations, uint32_t index) const
+{
+ const resource_directory::entry_list& entries = res_.get_root_directory() //Type directory
+ .entry_by_id(pe_resource_viewer::resource_version)
+ .get_resource_directory() //Name/ID directory
+ .entry_by_id(1)
+ .get_resource_directory() //Language directory
+ .get_entry_list();
+
+ if(entries.size() <= index)
+ throw pe_exception("Resource data entry not found", pe_exception::resource_data_entry_not_found);
+
+ return get_version_info(string_values, translations, entries.at(index).get_data_entry().get_data()); //Data directory
+}
+}
diff --git a/tools/pe_bliss/resource_version_info_reader.h b/tools/pe_bliss/resource_version_info_reader.h
new file mode 100644
index 0000000000..c1dfbffdc2
--- /dev/null
+++ b/tools/pe_bliss/resource_version_info_reader.h
@@ -0,0 +1,67 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <map>
+#include "file_version_info.h"
+#include "pe_structures.h"
+#include "version_info_types.h"
+
+namespace pe_bliss
+{
+class pe_resource_viewer;
+
+class resource_version_info_reader
+{
+public: //VERSION INFO
+ resource_version_info_reader(const pe_resource_viewer& res);
+
+ //Returns full version information:
+ //file_version_info: versions and file info
+ //lang_lang_string_values_map: map of version info strings with encodings with encodings
+ //translation_values_map: map of translations
+ const file_version_info get_version_info(lang_string_values_map& string_values, translation_values_map& translations, uint32_t index = 0) const;
+ const file_version_info get_version_info_by_lang(lang_string_values_map& string_values, translation_values_map& translations, uint32_t language) const;
+
+public:
+ //L"VS_VERSION_INFO" key of root version info block
+ static const u16string version_info_key;
+
+private:
+ const pe_resource_viewer& res_;
+
+ //VERSION INFO helpers
+ //Returns aligned version block value position
+ static uint32_t get_version_block_value_pos(uint32_t base_pos, const unicode16_t* key);
+
+ //Returns aligned version block first child position
+ static uint32_t get_version_block_first_child_pos(uint32_t base_pos, uint32_t value_length, const unicode16_t* key);
+
+ //Returns full version information:
+ //file_version_info: versions and file info
+ //lang_string_values_map: map of version info strings with encodings
+ //translation_values_map: map of translations
+ const file_version_info get_version_info(lang_string_values_map& string_values, translation_values_map& translations, const std::string& resource_data) const;
+
+ //Throws an exception (id = resource_incorrect_version_info)
+ static void throw_incorrect_version_info();
+};
+}
diff --git a/tools/pe_bliss/resource_version_info_writer.cpp b/tools/pe_bliss/resource_version_info_writer.cpp
new file mode 100644
index 0000000000..ed95a0f7ea
--- /dev/null
+++ b/tools/pe_bliss/resource_version_info_writer.cpp
@@ -0,0 +1,283 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include <string.h>
+#include "resource_version_info_writer.h"
+#include "pe_structures.h"
+#include "resource_internal.h"
+#include "utils.h"
+#include "pe_resource_manager.h"
+#include "resource_version_info_reader.h"
+
+namespace pe_bliss
+{
+using namespace pe_win;
+
+resource_version_info_writer::resource_version_info_writer(pe_resource_manager& res)
+ :res_(res)
+{}
+
+//Sets/replaces full version information:
+//file_version_info: versions and file info
+//lang_string_values_map: map of version info strings with encodings
+//translation_values_map: map of translations
+void resource_version_info_writer::set_version_info(const file_version_info& file_info,
+ const lang_string_values_map& string_values,
+ const translation_values_map& translations,
+ uint32_t language,
+ uint32_t codepage,
+ uint32_t timestamp)
+{
+ std::string version_data;
+
+ //Calculate total size of version resource data
+ uint32_t total_version_info_length =
+ static_cast<uint32_t>(sizeof(version_info_block) - sizeof(uint16_t) + sizeof(uint16_t) /* pading */
+ + (resource_version_info_reader::version_info_key.length() + 1) * 2
+ + sizeof(vs_fixedfileinfo));
+
+ //If we have any strings values
+ if(!string_values.empty())
+ {
+ total_version_info_length += sizeof(version_info_block) - sizeof(uint16_t); //StringFileInfo block
+ total_version_info_length += SizeofStringFileInfo; //Name of block (key)
+
+ //Add required size for version strings
+ for(lang_string_values_map::const_iterator table_it = string_values.begin(); table_it != string_values.end(); ++table_it)
+ {
+ total_version_info_length += pe_utils::align_up(static_cast<uint32_t>(sizeof(uint16_t) * 3 + ((*table_it).first.length() + 1) * 2), sizeof(uint32_t)); //Name of child block and block size (key of string table block)
+
+ const string_values_map& values = (*table_it).second;
+ for(string_values_map::const_iterator it = values.begin(); it != values.end(); ++it)
+ {
+ total_version_info_length += pe_utils::align_up(static_cast<uint32_t>(sizeof(uint16_t) * 3 + ((*it).first.length() + 1) * 2), sizeof(uint32_t));
+ total_version_info_length += pe_utils::align_up(static_cast<uint32_t>(((*it).second.length() + 1) * 2), sizeof(uint32_t));
+ }
+ }
+ }
+
+ //If we have translations
+ if(!translations.empty())
+ {
+ total_version_info_length += (sizeof(version_info_block) - sizeof(uint16_t)) * 2; //VarFileInfo and Translation blocks
+ total_version_info_length += SizeofVarFileInfoAligned; //DWORD-aligned VarFileInfo block name
+ total_version_info_length += SizeofTranslationAligned; //DWORD-aligned Translation block name
+ total_version_info_length += static_cast<uint32_t>(translations.size() * sizeof(uint16_t) * 2);
+ }
+
+ //Resize version data buffer
+ version_data.resize(total_version_info_length);
+
+ //Create root version block
+ version_info_block root_block = {0};
+ root_block.ValueLength = sizeof(vs_fixedfileinfo);
+ root_block.Length = static_cast<uint16_t>(total_version_info_length);
+
+ //Fill fixed file info
+ vs_fixedfileinfo fixed_info = {0};
+ fixed_info.dwFileDateLS = file_info.get_file_date_ls();
+ fixed_info.dwFileDateMS = file_info.get_file_date_ms();
+ fixed_info.dwFileFlags = file_info.get_file_flags();
+ fixed_info.dwFileFlagsMask = vs_ffi_fileflagsmask;
+ fixed_info.dwFileOS = file_info.get_file_os_raw();
+ fixed_info.dwFileSubtype = file_info.get_file_subtype();
+ fixed_info.dwFileType = file_info.get_file_type_raw();
+ fixed_info.dwFileVersionLS = file_info.get_file_version_ls();
+ fixed_info.dwFileVersionMS = file_info.get_file_version_ms();
+ fixed_info.dwSignature = vs_ffi_signature;
+ fixed_info.dwStrucVersion = vs_ffi_strucversion;
+ fixed_info.dwProductVersionLS = file_info.get_product_version_ls();
+ fixed_info.dwProductVersionMS = file_info.get_product_version_ms();
+
+ //Write root block and fixed file info to buffer
+ uint32_t data_ptr = 0;
+ memcpy(&version_data[data_ptr], &root_block, sizeof(version_info_block) - sizeof(uint16_t));
+ data_ptr += sizeof(version_info_block) - sizeof(uint16_t);
+ memcpy(&version_data[data_ptr], resource_version_info_reader::version_info_key.c_str(), (resource_version_info_reader::version_info_key.length() + 1) * sizeof(uint16_t));
+ data_ptr += static_cast<uint32_t>((resource_version_info_reader::version_info_key.length() + 1) * sizeof(uint16_t));
+ memset(&version_data[data_ptr], 0, sizeof(uint16_t));
+ data_ptr += sizeof(uint16_t);
+ memcpy(&version_data[data_ptr], &fixed_info, sizeof(fixed_info));
+ data_ptr += sizeof(fixed_info);
+
+ //Write string values, if any
+ if(!string_values.empty())
+ {
+ //Create string file info root block
+ version_info_block string_file_info_block = {0};
+ string_file_info_block.Type = 1; //Block type is string
+ memcpy(&version_data[data_ptr], &string_file_info_block, sizeof(version_info_block) - sizeof(uint16_t));
+ //We will calculate its length later
+ version_info_block* string_file_info_block_ptr = reinterpret_cast<version_info_block*>(&version_data[data_ptr]);
+ data_ptr += sizeof(version_info_block) - sizeof(uint16_t);
+
+ uint32_t old_ptr1 = data_ptr; //Used to calculate string file info block length later
+ memcpy(&version_data[data_ptr], StringFileInfo, SizeofStringFileInfo); //Write block name
+ data_ptr += SizeofStringFileInfo;
+
+ //Create string table root block (child of string file info)
+ version_info_block string_table_block = {0};
+ string_table_block.Type = 1; //Block type is string
+
+ for(lang_string_values_map::const_iterator table_it = string_values.begin(); table_it != string_values.end(); ++table_it)
+ {
+ const string_values_map& values = (*table_it).second;
+
+ memcpy(&version_data[data_ptr], &string_table_block, sizeof(version_info_block) - sizeof(uint16_t));
+ //We will calculate its length later
+ version_info_block* string_table_block_ptr = reinterpret_cast<version_info_block*>(&version_data[data_ptr]);
+ data_ptr += sizeof(version_info_block) - sizeof(uint16_t);
+
+ uint32_t old_ptr2 = data_ptr; //Used to calculate string table block length later
+ uint32_t lang_key_length = static_cast<uint32_t>(((*table_it).first.length() + 1) * sizeof(uint16_t));
+
+#ifdef PE_BLISS_WINDOWS
+ memcpy(&version_data[data_ptr], (*table_it).first.c_str(), lang_key_length); //Write block key
+#else
+ {
+ u16string str(pe_utils::to_ucs2((*table_it).first));
+ memcpy(&version_data[data_ptr], str.c_str(), lang_key_length); //Write block key
+ }
+#endif
+
+ data_ptr += lang_key_length;
+ //Align key if necessary
+ if((sizeof(uint16_t) * 3 + lang_key_length) % sizeof(uint32_t))
+ {
+ memset(&version_data[data_ptr], 0, sizeof(uint16_t));
+ data_ptr += sizeof(uint16_t);
+ }
+
+ //Create string block (child of string table block)
+ version_info_block string_block = {0};
+ string_block.Type = 1; //Block type is string
+ for(string_values_map::const_iterator it = values.begin(); it != values.end(); ++it)
+ {
+ //Calculate value length and key length of string block
+ string_block.ValueLength = static_cast<uint16_t>((*it).second.length() + 1);
+ uint32_t key_length = static_cast<uint32_t>(((*it).first.length() + 1) * sizeof(uint16_t));
+ //Calculate length of block
+ string_block.Length = static_cast<uint16_t>(pe_utils::align_up(sizeof(uint16_t) * 3 + key_length, sizeof(uint32_t)) + string_block.ValueLength * sizeof(uint16_t));
+
+ //Write string block
+ memcpy(&version_data[data_ptr], &string_block, sizeof(version_info_block) - sizeof(uint16_t));
+ data_ptr += sizeof(version_info_block) - sizeof(uint16_t);
+
+#ifdef PE_BLISS_WINDOWS
+ memcpy(&version_data[data_ptr], (*it).first.c_str(), key_length); //Write block key
+#else
+ {
+ u16string str(pe_utils::to_ucs2((*it).first));
+ memcpy(&version_data[data_ptr], str.c_str(), key_length); //Write block key
+ }
+#endif
+
+ data_ptr += key_length;
+ //Align key if necessary
+ if((sizeof(uint16_t) * 3 + key_length) % sizeof(uint32_t))
+ {
+ memset(&version_data[data_ptr], 0, sizeof(uint16_t));
+ data_ptr += sizeof(uint16_t);
+ }
+
+ //Write block data (value)
+#ifdef PE_BLISS_WINDOWS
+ memcpy(&version_data[data_ptr], (*it).second.c_str(), string_block.ValueLength * sizeof(uint16_t));
+#else
+ {
+ u16string str(pe_utils::to_ucs2((*it).second));
+ memcpy(&version_data[data_ptr], str.c_str(), string_block.ValueLength * sizeof(uint16_t));
+ }
+#endif
+
+ data_ptr += string_block.ValueLength * 2;
+ //Align data if necessary
+ if((string_block.ValueLength * 2) % sizeof(uint32_t))
+ {
+ memset(&version_data[data_ptr], 0, sizeof(uint16_t));
+ data_ptr += sizeof(uint16_t);
+ }
+ }
+
+ //Calculate string table and string file info blocks lengths
+ string_table_block_ptr->Length = static_cast<uint16_t>(data_ptr - old_ptr2 + sizeof(uint16_t) * 3);
+ }
+
+ string_file_info_block_ptr->Length = static_cast<uint16_t>(data_ptr - old_ptr1 + sizeof(uint16_t) * 3);
+ }
+
+ //If we have transactions
+ if(!translations.empty())
+ {
+ //Create root var file info block
+ version_info_block var_file_info_block = {0};
+ var_file_info_block.Type = 1; //Type of block is string
+ //Write block header
+ memcpy(&version_data[data_ptr], &var_file_info_block, sizeof(version_info_block) - sizeof(uint16_t));
+ //We will calculate its length later
+ version_info_block* var_file_info_block_ptr = reinterpret_cast<version_info_block*>(&version_data[data_ptr]);
+ data_ptr += sizeof(version_info_block) - sizeof(uint16_t);
+
+ uint32_t old_ptr1 = data_ptr; //Used to calculate var file info block length later
+ memcpy(&version_data[data_ptr], VarFileInfoAligned, SizeofVarFileInfoAligned); //Write block key (aligned)
+ data_ptr += SizeofVarFileInfoAligned;
+
+ //Create root translation block (child of var file info block)
+ version_info_block translation_block = {0};
+ //Write block header
+ memcpy(&version_data[data_ptr], &translation_block, sizeof(version_info_block) - sizeof(uint16_t));
+ //We will calculate its length later
+ version_info_block* translation_block_ptr = reinterpret_cast<version_info_block*>(&version_data[data_ptr]);
+ data_ptr += sizeof(version_info_block) - sizeof(uint16_t);
+
+ uint32_t old_ptr2 = data_ptr; //Used to calculate var file info block length later
+ memcpy(&version_data[data_ptr], TranslationAligned, SizeofTranslationAligned); //Write block key (aligned)
+ data_ptr += SizeofTranslationAligned;
+
+ //Calculate translation block value length
+ translation_block_ptr->ValueLength = static_cast<uint16_t>(sizeof(uint16_t) * 2 * translations.size());
+
+ //Write translation values to block
+ for(translation_values_map::const_iterator it = translations.begin(); it != translations.end(); ++it)
+ {
+ uint16_t lang_id = (*it).first; //Language ID
+ uint16_t codepage_id = (*it).second; //Codepage ID
+ memcpy(&version_data[data_ptr], &lang_id, sizeof(lang_id));
+ data_ptr += sizeof(lang_id);
+ memcpy(&version_data[data_ptr], &codepage_id, sizeof(codepage_id));
+ data_ptr += sizeof(codepage_id);
+ }
+
+ //Calculate Translation and VarFileInfo blocks lengths
+ translation_block_ptr->Length = static_cast<uint16_t>(data_ptr - old_ptr2 + sizeof(uint16_t) * 3);
+ var_file_info_block_ptr->Length = static_cast<uint16_t>(data_ptr - old_ptr1 + sizeof(uint16_t) * 3);
+ }
+
+ //Add/replace version info resource
+ res_.add_resource(version_data, pe_resource_viewer::resource_version, 1, language, codepage, timestamp);
+}
+
+//Removes version info by language (ID = 1)
+bool resource_version_info_writer::remove_version_info(uint32_t language)
+{
+ return res_.remove_resource(pe_resource_viewer::resource_version, 1, language);
+}
+}
diff --git a/tools/pe_bliss/resource_version_info_writer.h b/tools/pe_bliss/resource_version_info_writer.h
new file mode 100644
index 0000000000..da279ddedb
--- /dev/null
+++ b/tools/pe_bliss/resource_version_info_writer.h
@@ -0,0 +1,52 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include "version_info_types.h"
+#include "file_version_info.h"
+
+namespace pe_bliss
+{
+class pe_resource_manager;
+
+class resource_version_info_writer
+{
+public:
+ resource_version_info_writer(pe_resource_manager& res);
+
+ //Sets/replaces full version information:
+ //file_version_info: versions and file info
+ //lang_string_values_map: map of version info strings with encodings
+ //translation_values_map: map of translations
+ void set_version_info(const file_version_info& file_info,
+ const lang_string_values_map& string_values,
+ const translation_values_map& translations,
+ uint32_t language,
+ uint32_t codepage = 0,
+ uint32_t timestamp = 0);
+
+ //Removes version info by language (ID = 1)
+ bool remove_version_info(uint32_t language);
+
+private:
+ pe_resource_manager& res_;
+};
+}
diff --git a/tools/pe_bliss/stdint_defs.h b/tools/pe_bliss/stdint_defs.h
new file mode 100644
index 0000000000..bbc003690a
--- /dev/null
+++ b/tools/pe_bliss/stdint_defs.h
@@ -0,0 +1,45 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#ifdef _MSC_VER
+#if _MSC_VER < 1600
+namespace pe_bliss
+{
+ //stdint.h definitions for MSVC 2008 and earlier, as
+ //it doesn't have them
+ typedef signed char int8_t;
+ typedef short int16_t;
+ typedef int int32_t;
+
+ typedef unsigned char uint8_t;
+ typedef unsigned short uint16_t;
+ typedef unsigned int uint32_t;
+
+ typedef long long int64_t;
+ typedef unsigned long long uint64_t;
+}
+#else
+#include <stdint.h>
+#endif
+#else
+#include <stdint.h>
+#endif
diff --git a/tools/pe_bliss/utils.cpp b/tools/pe_bliss/utils.cpp
new file mode 100644
index 0000000000..e6a75d5497
--- /dev/null
+++ b/tools/pe_bliss/utils.cpp
@@ -0,0 +1,85 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include <string.h>
+#include "utils.h"
+#include "pe_exception.h"
+
+
+namespace pe_bliss
+{
+const double pe_utils::log_2 = 1.44269504088896340736; //instead of using M_LOG2E
+
+//Returns stream size
+std::streamoff pe_utils::get_file_size(std::istream& file)
+{
+ //Get old istream offset
+ std::streamoff old_offset = file.tellg();
+ file.seekg(0, std::ios::end);
+ std::streamoff filesize = file.tellg();
+ //Set old istream offset
+ file.seekg(old_offset);
+ return filesize;
+}
+
+#ifndef PE_BLISS_WINDOWS
+const u16string pe_utils::to_ucs2(const std::wstring& str)
+{
+ u16string ret;
+ if(str.empty())
+ return ret;
+
+ int len = str.length();
+
+ ret.resize(len);
+
+ for(int i=0;i<len;i++) {
+ ret[i]=str[i]&0xFFFF;
+ }
+
+ return ret;
+}
+
+const std::wstring pe_utils::from_ucs2(const u16string& str)
+{
+ std::wstring ret;
+ if(str.empty())
+ return ret;
+
+ int len = str.length();
+ ret.resize(str.length());
+
+ for(int i=0;i<len;i++) {
+ ret[i]=str[i];
+ }
+
+ return ret;
+}
+#endif
+
+bool operator==(const pe_win::guid& guid1, const pe_win::guid& guid2)
+{
+ return guid1.Data1 == guid2.Data1
+ && guid1.Data2 == guid2.Data2
+ && guid1.Data3 == guid2.Data3
+ && !memcmp(guid1.Data4, guid2.Data4, sizeof(guid1.Data4));
+}
+}
diff --git a/tools/pe_bliss/utils.h b/tools/pe_bliss/utils.h
new file mode 100644
index 0000000000..29125f8dc1
--- /dev/null
+++ b/tools/pe_bliss/utils.h
@@ -0,0 +1,105 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <istream>
+#include <string>
+#include "stdint_defs.h"
+#include "pe_structures.h"
+
+namespace pe_bliss
+{
+class pe_utils
+{
+public:
+ //Returns true if string "data" with maximum length "raw_length" is null-terminated
+ template<typename T>
+ static bool is_null_terminated(const T* data, size_t raw_length)
+ {
+ raw_length /= sizeof(T);
+ for(size_t l = 0; l < raw_length; l++)
+ {
+ if(data[l] == static_cast<T>(L'\0'))
+ return true;
+ }
+
+ return false;
+ }
+
+ //Helper template function to strip nullbytes in the end of string
+ template<typename T>
+ static void strip_nullbytes(std::basic_string<T>& str)
+ {
+ while(!*(str.end() - 1) && !str.empty())
+ str.erase(str.length() - 1);
+ }
+
+ //Helper function to determine if number is power of 2
+ template<typename T>
+ static inline bool is_power_of_2(T x)
+ {
+ return !(x & (x - 1));
+ }
+
+ //Helper function to align number down
+ template<typename T>
+ static inline T align_down(T x, uint32_t align)
+ {
+ return x & ~(static_cast<T>(align) - 1);
+ }
+
+ //Helper function to align number up
+ template<typename T>
+ static inline T align_up(T x, uint32_t align)
+ {
+ return (x & static_cast<T>(align - 1)) ? align_down(x, align) + static_cast<T>(align) : x;
+ }
+
+ //Returns true if sum of two unsigned integers is safe (no overflow occurs)
+ static inline bool is_sum_safe(uint32_t a, uint32_t b)
+ {
+ return a <= static_cast<uint32_t>(-1) - b;
+ }
+
+ //Two gigabytes value in bytes
+ static const uint32_t two_gb = 0x80000000;
+ static const uint32_t max_dword = 0xFFFFFFFF;
+ static const uint32_t max_word = 0x0000FFFF;
+ static const double log_2; //instead of using M_LOG2E
+
+ //Returns stream size
+ static std::streamoff get_file_size(std::istream& file);
+
+#ifndef PE_BLISS_WINDOWS
+public:
+ static const u16string to_ucs2(const std::wstring& str);
+ static const std::wstring from_ucs2(const u16string& str);
+#endif
+
+private:
+ pe_utils();
+ pe_utils(pe_utils&);
+ pe_utils& operator=(const pe_utils&);
+};
+
+//Windows GUID comparison
+bool operator==(const pe_win::guid& guid1, const pe_win::guid& guid2);
+}
diff --git a/tools/pe_bliss/version_info_editor.cpp b/tools/pe_bliss/version_info_editor.cpp
new file mode 100644
index 0000000000..199eebfd54
--- /dev/null
+++ b/tools/pe_bliss/version_info_editor.cpp
@@ -0,0 +1,184 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include <sstream>
+#include <iomanip>
+#include "version_info_types.h"
+#include "version_info_editor.h"
+#include "version_info_viewer.h"
+
+namespace pe_bliss
+{
+//Default constructor
+//strings - version info strings with charsets
+//translations - version info translations map
+version_info_editor::version_info_editor(lang_string_values_map& strings, translation_values_map& translations)
+ :version_info_viewer(strings, translations),
+ strings_edit_(strings),
+ translations_edit_(translations)
+{}
+
+//Below functions have parameter translation
+//If it's empty, the default language translation will be taken
+//If there's no default language translation, the first one will be taken
+
+//Sets company name
+void version_info_editor::set_company_name(const std::wstring& value, const std::wstring& translation)
+{
+ set_property(L"CompanyName", value, translation);
+}
+
+//Sets file description
+void version_info_editor::set_file_description(const std::wstring& value, const std::wstring& translation)
+{
+ set_property(L"FileDescription", value, translation);
+}
+
+//Sets file version
+void version_info_editor::set_file_version(const std::wstring& value, const std::wstring& translation)
+{
+ set_property(L"FileVersion", value, translation);
+}
+
+//Sets internal file name
+void version_info_editor::set_internal_name(const std::wstring& value, const std::wstring& translation)
+{
+ set_property(L"InternalName", value, translation);
+}
+
+//Sets legal copyright
+void version_info_editor::set_legal_copyright(const std::wstring& value, const std::wstring& translation)
+{
+ set_property(L"LegalCopyright", value, translation);
+}
+
+//Sets original file name
+void version_info_editor::set_original_filename(const std::wstring& value, const std::wstring& translation)
+{
+ set_property(L"OriginalFilename", value, translation);
+}
+
+//Sets product name
+void version_info_editor::set_product_name(const std::wstring& value, const std::wstring& translation)
+{
+ set_property(L"ProductName", value, translation);
+}
+
+//Sets product version
+void version_info_editor::set_product_version(const std::wstring& value, const std::wstring& translation)
+{
+ set_property(L"ProductVersion", value, translation);
+}
+
+//Sets version info property value
+//property_name - property name
+//value - property value
+//If translation does not exist, it will be added
+//If property does not exist, it will be added
+void version_info_editor::set_property(const std::wstring& property_name, const std::wstring& value, const std::wstring& translation)
+{
+ lang_string_values_map::iterator it = strings_edit_.begin();
+
+ if(translation.empty())
+ {
+ //If no translation was specified
+ it = strings_edit_.find(default_language_translation); //Find default translation table
+ if(it == strings_edit_.end()) //If there's no default translation table, take the first one
+ {
+ it = strings_edit_.begin();
+ if(it == strings_edit_.end()) //If there's no any translation table, add default one
+ {
+ it = strings_edit_.insert(std::make_pair(default_language_translation, string_values_map())).first;
+ //Also add it to translations list
+ add_translation(default_language_translation);
+ }
+ }
+ }
+ else
+ {
+ it = strings_edit_.find(translation); //Find specified translation table
+ if(it == strings_edit_.end()) //If there's no translation, add it
+ {
+ it = strings_edit_.insert(std::make_pair(translation, string_values_map())).first;
+ //Also add it to translations list
+ add_translation(translation);
+ }
+ }
+
+ //Change value of the required property
+ ((*it).second)[property_name] = value;
+}
+
+//Adds translation to translation list
+void version_info_editor::add_translation(const std::wstring& translation)
+{
+ std::pair<uint16_t, uint16_t> translation_ids(translation_from_string(translation));
+ add_translation(translation_ids.first, translation_ids.second);
+}
+
+void version_info_editor::add_translation(uint16_t language_id, uint16_t codepage_id)
+{
+ std::pair<translation_values_map::const_iterator, translation_values_map::const_iterator>
+ range(translations_edit_.equal_range(language_id));
+
+ //If translation already exists
+ for(translation_values_map::const_iterator it = range.first; it != range.second; ++it)
+ {
+ if((*it).second == codepage_id)
+ return;
+ }
+
+ translations_edit_.insert(std::make_pair(language_id, codepage_id));
+}
+
+//Removes translation from translations and strings lists
+void version_info_editor::remove_translation(const std::wstring& translation)
+{
+ std::pair<uint16_t, uint16_t> translation_ids(translation_from_string(translation));
+ remove_translation(translation_ids.first, translation_ids.second);
+}
+
+void version_info_editor::remove_translation(uint16_t language_id, uint16_t codepage_id)
+{
+ {
+ //Erase string table (if exists)
+ std::wstringstream ss;
+ ss << std::hex
+ << std::setw(4) << std::setfill(L'0') << language_id
+ << std::setw(4) << std::setfill(L'0') << codepage_id;
+
+ strings_edit_.erase(ss.str());
+ }
+
+ //Find and erase translation from translations table
+ std::pair<translation_values_map::iterator, translation_values_map::iterator>
+ it_pair = translations_edit_.equal_range(language_id);
+
+ for(translation_values_map::iterator it = it_pair.first; it != it_pair.second; ++it)
+ {
+ if((*it).second == codepage_id)
+ {
+ translations_edit_.erase(it);
+ break;
+ }
+ }
+}
+}
diff --git a/tools/pe_bliss/version_info_editor.h b/tools/pe_bliss/version_info_editor.h
new file mode 100644
index 0000000000..53d3dc62c1
--- /dev/null
+++ b/tools/pe_bliss/version_info_editor.h
@@ -0,0 +1,79 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include "version_info_types.h"
+#include "version_info_viewer.h"
+
+namespace pe_bliss
+{
+ //Helper class to read and edit version information
+ //lang_string_values_map: map of version info strings with encodings
+ //translation_values_map: map of translations
+ class version_info_editor : public version_info_viewer
+ {
+ public:
+ //Default constructor
+ //strings - version info strings with charsets
+ //translations - version info translations map
+ version_info_editor(lang_string_values_map& strings, translation_values_map& translations);
+
+ //Below functions have parameter translation
+ //If it's empty, the default language translation will be taken
+ //If there's no default language translation, the first one will be taken
+
+ //Sets company name
+ void set_company_name(const std::wstring& value, const std::wstring& translation = std::wstring());
+ //Sets file description
+ void set_file_description(const std::wstring& value, const std::wstring& translation = std::wstring());
+ //Sets file version
+ void set_file_version(const std::wstring& value, const std::wstring& translation = std::wstring());
+ //Sets internal file name
+ void set_internal_name(const std::wstring& value, const std::wstring& translation = std::wstring());
+ //Sets legal copyright
+ void set_legal_copyright(const std::wstring& value, const std::wstring& translation = std::wstring());
+ //Sets original file name
+ void set_original_filename(const std::wstring& value, const std::wstring& translation = std::wstring());
+ //Sets product name
+ void set_product_name(const std::wstring& value, const std::wstring& translation = std::wstring());
+ //Sets product version
+ void set_product_version(const std::wstring& value, const std::wstring& translation = std::wstring());
+
+ //Sets version info property value
+ //property_name - property name
+ //value - property value
+ //If translation does not exist, it will be added to strings and translations lists
+ //If property does not exist, it will be added
+ void set_property(const std::wstring& property_name, const std::wstring& value, const std::wstring& translation = std::wstring());
+
+ //Adds translation to translation list
+ void add_translation(const std::wstring& translation);
+ void add_translation(uint16_t language_id, uint16_t codepage_id);
+
+ //Removes translation from translations and strings lists
+ void remove_translation(const std::wstring& translation);
+ void remove_translation(uint16_t language_id, uint16_t codepage_id);
+
+ private:
+ lang_string_values_map& strings_edit_;
+ translation_values_map& translations_edit_;
+ };
+}
diff --git a/tools/pe_bliss/version_info_types.h b/tools/pe_bliss/version_info_types.h
new file mode 100644
index 0000000000..6010c9691e
--- /dev/null
+++ b/tools/pe_bliss/version_info_types.h
@@ -0,0 +1,38 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <map>
+#include <string>
+#include "stdint_defs.h"
+
+namespace pe_bliss
+{
+ //Typedef for version info functions: Name - Value
+ typedef std::map<std::wstring, std::wstring> string_values_map;
+ //Typedef for version info functions: Language string - String Values Map
+ //Language String consists of LangID and CharsetID
+ //E.g. 041904b0 for Russian UNICODE, 040004b0 for Process Default Language UNICODE
+ typedef std::map<std::wstring, string_values_map> lang_string_values_map;
+
+ //Typedef for version info functions: Language - Character Set
+ typedef std::multimap<uint16_t, uint16_t> translation_values_map;
+}
diff --git a/tools/pe_bliss/version_info_viewer.cpp b/tools/pe_bliss/version_info_viewer.cpp
new file mode 100644
index 0000000000..6e2d0d5c5b
--- /dev/null
+++ b/tools/pe_bliss/version_info_viewer.cpp
@@ -0,0 +1,180 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#include <iomanip>
+#include <sstream>
+#include "pe_exception.h"
+#include "version_info_viewer.h"
+
+namespace pe_bliss
+{
+//Default process language, UNICODE
+const std::wstring version_info_viewer::default_language_translation(L"040904b0");
+
+//Default constructor
+//strings - version info strings with charsets
+//translations - version info translations map
+version_info_viewer::version_info_viewer(const lang_string_values_map& strings, const translation_values_map& translations)
+ :strings_(strings), translations_(translations)
+{}
+
+//Below functions have parameter translation
+//If it's empty, the default language translation will be taken
+//If there's no default language translation, the first one will be taken
+
+//Returns company name
+const std::wstring version_info_viewer::get_company_name(const std::wstring& translation) const
+{
+ return get_property(L"CompanyName", translation);
+}
+
+//Returns file description
+const std::wstring version_info_viewer::get_file_description(const std::wstring& translation) const
+{
+ return get_property(L"FileDescription", translation);
+}
+
+//Returns file version
+const std::wstring version_info_viewer::get_file_version(const std::wstring& translation) const
+{
+ return get_property(L"FileVersion", translation);
+}
+
+//Returns internal file name
+const std::wstring version_info_viewer::get_internal_name(const std::wstring& translation) const
+{
+ return get_property(L"InternalName", translation);
+}
+
+//Returns legal copyright
+const std::wstring version_info_viewer::get_legal_copyright(const std::wstring& translation) const
+{
+ return get_property(L"LegalCopyright", translation);
+}
+
+//Returns original file name
+const std::wstring version_info_viewer::get_original_filename(const std::wstring& translation) const
+{
+ return get_property(L"OriginalFilename", translation);
+}
+
+//Returns product name
+const std::wstring version_info_viewer::get_product_name(const std::wstring& translation) const
+{
+ return get_property(L"ProductName", translation);
+}
+
+//Returns product version
+const std::wstring version_info_viewer::get_product_version(const std::wstring& translation) const
+{
+ return get_property(L"ProductVersion", translation);
+}
+
+//Returns list of translations in string representation
+const version_info_viewer::translation_list version_info_viewer::get_translation_list() const
+{
+ translation_list ret;
+
+ //Enumerate all translations
+ for(translation_values_map::const_iterator it = translations_.begin(); it != translations_.end(); ++it)
+ {
+ //Create string representation of translation value
+ std::wstringstream ss;
+ ss << std::hex
+ << std::setw(4) << std::setfill(L'0') << (*it).first
+ << std::setw(4) << std::setfill(L'0') << (*it).second;
+
+ //Save it
+ ret.push_back(ss.str());
+ }
+
+ return ret;
+}
+
+//Returns version info property value
+//property_name - required property name
+//If throw_if_absent = true, will throw exception if property does not exist
+//If throw_if_absent = false, will return empty string if property does not exist
+const std::wstring version_info_viewer::get_property(const std::wstring& property_name, const std::wstring& translation, bool throw_if_absent) const
+{
+ std::wstring ret;
+
+ //If there're no strings
+ if(strings_.empty())
+ {
+ if(throw_if_absent)
+ throw pe_exception("Version info string does not exist", pe_exception::version_info_string_does_not_exist);
+
+ return ret;
+ }
+
+ lang_string_values_map::const_iterator it = strings_.begin();
+
+ if(translation.empty())
+ {
+ //If no translation was specified
+ it = strings_.find(default_language_translation); //Find default translation table
+ if(it == strings_.end()) //If there's no default translation table, take the first one
+ it = strings_.begin();
+ }
+ else
+ {
+ it = strings_.find(translation); //Find specified translation table
+ if(it == strings_.end())
+ {
+ if(throw_if_absent)
+ throw pe_exception("Version info string does not exist", pe_exception::version_info_string_does_not_exist);
+
+ return ret;
+ }
+ }
+
+ //Find value of the required property
+ string_values_map::const_iterator str_it = (*it).second.find(property_name);
+
+ if(str_it == (*it).second.end())
+ {
+ if(throw_if_absent)
+ throw pe_exception("Version info string does not exist", pe_exception::version_info_string_does_not_exist);
+
+ return ret;
+ }
+
+ ret = (*str_it).second;
+
+ return ret;
+}
+
+//Converts translation HEX-string to pair of language ID and codepage ID
+const version_info_viewer::translation_pair version_info_viewer::translation_from_string(const std::wstring& translation)
+{
+ uint32_t translation_id = 0;
+
+ {
+ //Convert string to DWORD
+ std::wstringstream ss;
+ ss << std::hex << translation;
+ ss >> translation_id;
+ }
+
+ return std::make_pair(static_cast<uint16_t>(translation_id >> 16), static_cast<uint16_t>(translation_id & 0xFFFF));
+}
+}
diff --git a/tools/pe_bliss/version_info_viewer.h b/tools/pe_bliss/version_info_viewer.h
new file mode 100644
index 0000000000..bc2f6f2ba7
--- /dev/null
+++ b/tools/pe_bliss/version_info_viewer.h
@@ -0,0 +1,89 @@
+/*************************************************************************/
+/* Copyright (c) 2015 dx, http://kaimi.ru */
+/* */
+/* 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. */
+/*************************************************************************/
+#pragma once
+#include <map>
+#include <vector>
+#include <string>
+#include "pe_resource_viewer.h"
+#include "pe_structures.h"
+#include "version_info_types.h"
+
+namespace pe_bliss
+{
+//Helper class to read version information
+//lang_string_values_map: map of version info strings with encodings
+//translation_values_map: map of translations
+class version_info_viewer
+{
+public:
+ //Useful typedefs
+ typedef std::pair<uint16_t, uint16_t> translation_pair;
+ typedef std::vector<std::wstring> translation_list;
+
+public:
+ //Default constructor
+ //strings - version info strings with charsets
+ //translations - version info translations map
+ version_info_viewer(const lang_string_values_map& strings, const translation_values_map& translations);
+
+ //Below functions have parameter translation
+ //If it's empty, the default language translation will be taken
+ //If there's no default language translation, the first one will be taken
+
+ //Returns company name
+ const std::wstring get_company_name(const std::wstring& translation = std::wstring()) const;
+ //Returns file description
+ const std::wstring get_file_description(const std::wstring& translation = std::wstring()) const;
+ //Returns file version
+ const std::wstring get_file_version(const std::wstring& translation = std::wstring()) const;
+ //Returns internal file name
+ const std::wstring get_internal_name(const std::wstring& translation = std::wstring()) const;
+ //Returns legal copyright
+ const std::wstring get_legal_copyright(const std::wstring& translation = std::wstring()) const;
+ //Returns original file name
+ const std::wstring get_original_filename(const std::wstring& translation = std::wstring()) const;
+ //Returns product name
+ const std::wstring get_product_name(const std::wstring& translation = std::wstring()) const;
+ //Returns product version
+ const std::wstring get_product_version(const std::wstring& translation = std::wstring()) const;
+
+ //Returns list of translations in string representation
+ const translation_list get_translation_list() const;
+
+ //Returns version info property value
+ //property_name - required property name
+ //If throw_if_absent = true, will throw exception if property does not exist
+ //If throw_if_absent = false, will return empty string if property does not exist
+ const std::wstring get_property(const std::wstring& property_name, const std::wstring& translation = std::wstring(), bool throw_if_absent = false) const;
+
+ //Converts translation HEX-string to pair of language ID and codepage ID
+ static const translation_pair translation_from_string(const std::wstring& translation);
+
+public:
+ //Default process language, UNICODE
+ static const std::wstring default_language_translation;
+
+private:
+ const lang_string_values_map& strings_;
+ const translation_values_map& translations_;
+};
+}
diff --git a/tools/scripts/file-hex-array.py b/tools/scripts/file-hex-array.py
new file mode 100755
index 0000000000..05352396f1
--- /dev/null
+++ b/tools/scripts/file-hex-array.py
@@ -0,0 +1,52 @@
+import binascii
+import os.path
+import sys
+
+def tof(filepath):
+ with open(filepath, 'r') as f:
+ content = f.read()
+ content = content.replace("0x","")
+ content = content.split(',')
+ for i in range(len(content)):
+ if len(content[i]) == 1: content[i] = "0" + content[i]
+ content = "".join(content)
+ with open(filepath+".file", 'wb') as f:
+ content = f.write(content.decode("hex"))
+ print(os.path.basename(filepath)+".file created.")
+ exit(0)
+
+def toa(filepath):
+ with open(filepath, 'rb') as f:
+ content = f.read()
+ content = binascii.hexlify(content)
+ content = [content[i:i+2] for i in range(0, len(content), 2)]
+ content = ",0x".join(content)
+ content = "0x" + content
+ content = content.replace("0x00","0x0")
+ with open(filepath+".array", 'w') as f:
+ content = f.write(content)
+ print(os.path.basename(filepath)+".array created.")
+ exit(0)
+
+def usage():
+ print("========================================================\n\
+#\n\
+# Usage: python file-hex-array.py [action] [option]\n\
+#\n\
+# Arguments:\n\
+# action ==> toa # convert file to array [option is file path]\n\
+# tof # convert array to file [option is array file path]\n\
+#\n\
+# Example : python file-hex-array.py toa 1.png\n\
+#\n\
+========================================================")
+ exit(1)
+
+if len(sys.argv) != 3:
+ usage()
+if sys.argv[1] == "toa" and os.path.isfile(sys.argv[2]):
+ toa(sys.argv[2])
+elif sys.argv[1] == "tof" and os.path.isfile(sys.argv[2]):
+ tof(sys.argv[2])
+else:
+ usage() \ No newline at end of file
diff --git a/version.py b/version.py
index c723dd2935..284bda9520 100644
--- a/version.py
+++ b/version.py
@@ -1,7 +1,8 @@
short_name="godot"
name="Godot Engine"
-major=1
-minor=1
-status="stable"
+major=2
+minor=0
+status="alpha"
+